From e05b65193f5e684c590a710180b0de813261ab75 Mon Sep 17 00:00:00 2001 From: zhong-wanfu Date: Wed, 6 Apr 2022 11:14:49 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=88=9D=E6=AC=A1=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../audio/Jasper_for_PyTorch/diff.patch | 176 +- .../audio/Jasper_for_PyTorch/pth2onnx.py | 88 +- .../audio/Jasper_for_PyTorch/requirements.txt | 30 +- ACL_PyTorch/built-in/audio/LSTM/LICENSE | 400 +- .../built-in/audio/LSTM/LSTM_get_info.py | 66 +- .../audio/LSTM/LSTM_postprocess_data.py | 228 +- .../audio/LSTM/LSTM_preprocess_data.py | 160 +- .../built-in/audio/LSTM/LSTM_pth2onnx.py | 462 +- ACL_PyTorch/built-in/audio/LSTM/ReadMe.md | 682 +- ACL_PyTorch/built-in/audio/LSTM/acl_net.py | 552 +- ACL_PyTorch/built-in/audio/LSTM/lstm_atc.sh | 10 +- .../built-in/audio/LSTM/lstm_onnx_infer.py | 310 +- .../built-in/audio/LSTM/prepare_data.sh | 62 +- .../built-in/audio/LSTM/pyacl_infer.py | 314 +- .../audio/RawNet2_for_Pytorch/LICENSE | 40 +- .../audio/RawNet2_for_Pytorch/README.md | 198 +- .../audio/RawNet2_for_Pytorch/acl_net.py | 518 +- .../RawNet2_for_Pytorch/modelzoo_level.txt | 4 +- .../audio/RawNet2_for_Pytorch/modify_onnx.py | 444 +- .../audio/RawNet2_for_Pytorch/om_infer.py | 318 +- .../audio/RawNet2_for_Pytorch/pth2onnx.py | 138 +- .../built-in/audio/TDNN_for_Pytorch/LICENSE | 56 +- .../built-in/audio/TDNN_for_Pytorch/ReadMe.md | 116 +- .../built-in/audio/TDNN_for_Pytorch/mo.py | 62 +- .../audio/TDNN_for_Pytorch/modelzoo_level.txt | 4 +- .../audio/TDNN_for_Pytorch/modify.patch | 16 +- .../audio/TDNN_for_Pytorch/modify_onnx.py | 100 +- .../audio/TDNN_for_Pytorch/requirements.txt | 16 +- .../TDNN_for_Pytorch/tdnn_postprocess.py | 104 +- .../audio/TDNN_for_Pytorch/tdnn_preprocess.py | 102 +- .../audio/TDNN_for_Pytorch/tdnn_pth2onnx.py | 92 +- .../TDNN_for_Pytorch/tdnn_pyacl_infer.py | 400 +- .../built-in/cv/CRNN_for_Pytorch/ReadMe.md | 74 +- .../cv/CRNN_for_Pytorch/lstm_revise.py | 572 +- .../cv/CRNN_for_Pytorch/parse_testdata.py | 158 +- .../postpossess_CRNN_pytorch.py | 276 +- .../built-in/cv/CRNN_for_Pytorch/pth2onnx.py | 44 +- .../built-in/cv/CenterNet_for_Pytorch/LICENSE | 56 +- .../cv/CenterNet_for_Pytorch/OXInterface.py | 2498 +++---- .../cv/CenterNet_for_Pytorch/ReadMe.md | 620 +- .../cv/CenterNet_for_Pytorch/export_onnx.py | 228 +- .../CenterNet_for_Pytorch/modelzoo_level.txt | 4 +- .../cv/CenterNet_for_Pytorch/modify_onnx.py | 114 +- .../cv/CenterNet_for_Pytorch/postprocess.py | 314 +- .../cv/CenterNet_for_Pytorch/preprocess.py | 254 +- .../cv/CenterNet_for_Pytorch/pth_eval.py | 230 +- .../built-in/cv/DB_for_PyTorch/LICENSE | 400 +- .../built-in/cv/DB_for_PyTorch/db.diff | 34 +- .../built-in/cv/DB_for_PyTorch/db_pth2onnx.py | 114 +- .../cv/DB_for_PyTorch/modelzoo_level.txt | 6 +- .../built-in/cv/DB_for_PyTorch/test/parse.py | 66 +- .../built-in/cv/Deepmar_for_Pytorch/ReadMe.md | 92 +- .../cv/Deepmar_for_Pytorch/export_onnx.py | 76 +- .../cv/Deepmar_for_Pytorch/get_info.py | 32 +- .../postprocess_deepmar_pytorch.py | 188 +- .../preprocess_deepmar_pytorch.py | 146 +- .../cv/Deepmar_for_Pytorch/remove_pad.py | 36 +- .../cv/Deepmar_for_Pytorch/split_test_data.py | 50 +- .../Deepsort_for_Pytorch/modelzoo_level.txt | 4 +- .../PytorchTransfer.py | 90 +- .../cv/EfficientNet_for_Pytorch/ReadMe.md | 96 +- .../EfficientNet_for_Pytorch/pthtar2onnx.py | 72 +- .../vision_metric_ImageNet.py | 346 +- .../built-in/cv/Flownet2_for_Pytorch/LICENSE | 400 +- .../cv/Flownet2_for_Pytorch/flownet2.patch | 98 +- .../cv/GoogleNet_for_Pytorch/ReadMe.md | 126 +- .../cv/GoogleNet_for_Pytorch/get_info.py | 90 +- .../preprocess_googlenet_pth.py | 170 +- .../cv/InceptionV3_for_Pytorch/ReadMe.md | 190 +- .../gen_dataset_info.py | 122 +- .../imagenet_torch_preprocess.py | 226 +- .../InceptionV3_for_Pytorch/requirements.txt | 10 +- .../cv/InceptionV4_for_Pytorch/ReadMe.md | 126 +- .../cv/InceptionV4_for_Pytorch/get_info.py | 90 +- .../preprocess_inceptionv4_pth.py | 170 +- .../PytorchTransfer.py | 94 +- .../cv/MobileNetV2_for_Pytorch/ReadMe.md | 96 +- .../cv/MobileNetV2_for_Pytorch/pth2onnx.py | 54 +- .../cv/MobileNetV2_for_Pytorch/pthtar2onnx.py | 82 +- .../vision_metric_ImageNet.py | 346 +- .../built-in/cv/PSENet_for_Pytorch/README.md | 18 +- .../cv/PSENet_for_Pytorch/export_onnx.py | 78 +- .../cv/PSENet_for_Pytorch/fpn_resnet.py | 682 +- .../PSENet_for_Pytorch/fpn_resnet_nearest.py | 1110 +-- .../preprocess_psenet_pytorch.py | 100 +- .../pth_bintotxt_bilinear.py | 210 +- .../pth_bintotxt_nearest.py | 210 +- .../built-in/cv/PSENet_for_Pytorch/pypse.py | 110 +- .../revise_PSENET_bilinear.py | 592 +- .../revise_PSENET_nearest2.py | 548 +- .../cv/Res2Net_v1b_101_for_PyTorch/ README.md | 164 +- .../ imagenet_torch_preprocess.py | 232 +- .../ requirements.txt | 10 +- .../cv/Res2Net_v1b_101_for_PyTorch/LICENSE | 402 +- .../cv/Res2Net_v1b_101_for_PyTorch/atc.sh | 32 +- .../cv/Res2Net_v1b_101_for_PyTorch/diff.patch | 64 +- .../cv/Res2Net_v1b_101_for_PyTorch/env.sh | 12 +- .../Res2Net_v1b_101_for_PyTorch/get_info.py | 120 +- .../modelzoo_level.txt | 4 +- .../Res2Net_v1b_101_for_PyTorch/pth2onnx.py | 152 +- .../vision_metric_ImageNet.py | 354 +- .../cv/ResNeXt50_for_Pytorch/ReadMe.md | 124 +- .../cv/ResNeXt50_for_Pytorch/get_info.py | 90 +- .../preprocess_resnext50_pth.py | 170 +- .../cv/Resnet101_Pytorch_Infer/ReadMe.md | 762 +-- .../gen_dataset_info.py | 122 +- .../imagenet_acc_eval.py | 368 +- .../imagenet_torch_preprocess.py | 226 +- .../Resnet101_Pytorch_Infer/requirements.txt | 10 +- .../resnet101_pth2onnx.py | 70 +- .../built-in/cv/Resnet18_for_PyTorch/LICENSE | 400 +- .../cv/Resnet18_for_PyTorch/README.md | 310 +- .../Resnet18_for_PyTorch/calibration_bin.py | 112 +- .../Resnet18_for_PyTorch/gen_dataset_info.py | 122 +- .../Resnet18_for_PyTorch/imagenet_acc_eval.py | 368 +- .../imagenet_torch_preprocess.py | 228 +- .../Resnet18_for_PyTorch/modelzoo_level.txt | 4 +- .../cv/Resnet18_for_PyTorch/requirements.txt | 10 +- .../Resnet18_for_PyTorch/resnet18_pth2onnx.py | 70 +- .../aipp_resnet50_710.aippconfig | 38 +- .../gen_dataset_info.py | 122 +- .../imagenet_torch_preprocess.py | 258 +- .../cv/SE_ResNet50_Pytorch_Infer/README.md | 466 +- .../SE_ResNet50_pth2onnx.py | 78 +- .../aipp_SE_ResNet50_pth.config | 42 +- .../gen_dataset_info.py | 122 +- .../imagenet_torch_preprocess.py | 116 +- .../vision_metric_ImageNet.py | 368 +- .../PytorchTransfer.py | 94 +- .../cv/Shufflenetv2_for_Pytorch/ReadMe.md | 96 +- .../Shufflenetv2_for_Pytorch/shufflenetv2.py | 426 +- .../shufflenetv2_wock_op_woct.py | 512 +- .../vision_metric_ImageNet.py | 346 +- .../cv/U2-Net_for_PyTorch/gen_dataset_info.py | 130 +- .../built-in/cv/Vgg16_for_Pytorch/ReadMe.md | 96 +- .../built-in/cv/Vgg16_for_Pytorch/get_info.py | 32 +- .../preprocess_vgg_pytorch.py | 166 +- .../vision_metric_ImageNet.py | 346 +- .../built-in/cv/Vgg19_for_Pytorch/ReadMe.md | 96 +- .../built-in/cv/Vgg19_for_Pytorch/get_info.py | 32 +- .../preprocess_vgg_pytorch.py | 166 +- .../vision_metric_ImageNet.py | 346 +- .../cv/YolactEdge_for_PyTorch/LICENSE | 404 +- .../cv/YolactEdge_for_PyTorch/README.md | 224 +- .../cv/YolactEdge_for_PyTorch/acl_net.py | 518 +- .../built-in/cv/YolactEdge_for_PyTorch/atc.sh | 10 +- .../built-in/cv/YolactEdge_for_PyTorch/env.sh | 10 +- .../YolactEdge_for_PyTorch/modelzoo_level.txt | 4 +- .../YolactEdge_for_PyTorch/requirements.txt | 12 +- .../YolactEdge_for_PyTorch/yolact_edge.diff | 342 +- .../built-in/cv/Yolov3_for_Pytorch/README.md | 146 +- .../bin_to_predict_yolo_pytorch.py | 510 +- .../cv/Yolov3_for_Pytorch/get_coco_info.py | 62 +- .../cv/Yolov3_for_Pytorch/parse_json.py | 154 +- .../preprocess_yolov3_pytorch.py | 158 +- .../built-in/cv/Yolov4_for_Pytorch/README.md | 212 +- .../bin_to_predict_yolov4_pytorch.py | 720 +- .../cv/Yolov4_for_Pytorch/get_coco_info.py | 92 +- .../cv/Yolov4_for_Pytorch/parse_json.py | 154 +- .../preprocess_yolov4_pytorch.py | 130 +- .../cv/Yolov4_for_Pytorch/requirements.txt | 8 +- .../cv/Yolov5_for_Pytorch/generate_data.py | 130 +- .../built-in/cv/Yolov5_for_Pytorch/img.png | Bin 71967 -> 0 bytes .../nlp/CNN_Transformer_for_Pytorch/LICENSE | 58 +- .../nlp/CNN_Transformer_for_Pytorch/ReadMe.md | 336 +- .../modelzoo_level.txt | 4 +- .../pyacl_infer.py | 276 +- ACL_PyTorch/built-in/nlp/textcnn/License | 400 +- ACL_PyTorch/built-in/nlp/textcnn/README.md | 124 +- .../nlp/textcnn/TextCNN_postprocess.py | 58 +- .../nlp/textcnn/TextCNN_preprocess.py | 214 +- .../built-in/nlp/textcnn/TextCNN_pth2onnx.py | 112 +- ACL_PyTorch/built-in/nlp/textcnn/env.sh | 16 +- ACL_PyTorch/built-in/nlp/textcnn/fix_onnx.py | 130 +- .../built-in/nlp/textcnn/gen_dataset_info.py | 52 +- .../built-in/nlp/textcnn/modelzoo_level.txt | 6 +- .../built-in/nlp/textcnn/onnx2mgonnx.sh | 22 +- ACL_PyTorch/built-in/nlp/textcnn/onnx2om.sh | 22 +- ACL_PyTorch/built-in/nlp/textcnn/onnxsim.sh | 22 +- .../built-in/nlp/textcnn/requirements.txt | 10 +- ACL_PyTorch/contrib/CONTRIBUTING.md | 628 +- ACL_PyTorch/contrib/audio/FastPitch/README.md | 450 +- .../FastPitch/fastpitch/loss_function.py | 216 +- ACL_PyTorch/contrib/audio/FastPitch/infer.py | 178 +- .../contrib/audio/FastPitch/infer_test.py | 178 +- ACL_PyTorch/contrib/audio/rawnet2/README.md | 100 +- .../audio/rawnet2/RawNet2_postprocess.py | 242 +- .../audio/rawnet2/RawNet2_preprocess.py | 168 +- .../contrib/audio/rawnet2/RawNet2_pth2onnx.py | 68 +- ACL_PyTorch/contrib/audio/rawnet2/env.sh | 12 +- .../contrib/audio/rawnet2/fusion_switch.cfg | 12 +- .../contrib/audio/rawnet2/modelzoo_level.txt | 4 +- ACL_PyTorch/contrib/audio/rawnet2/perf_t4.sh | 42 +- .../contrib/audio/rawnet2/requirements.txt | 16 +- .../contrib/audio/rawnet2/test/parse.py | 64 +- ACL_PyTorch/contrib/audio/tdnn/LICENSE | 400 +- ACL_PyTorch/contrib/audio/tdnn/ReadMe.md | 552 +- .../contrib/audio/tdnn/Tdnn_onnx_infer.py | 248 +- .../contrib/audio/tdnn/Tdnn_postprocess.py | 116 +- .../contrib/audio/tdnn/Tdnn_preprocess.py | 102 +- .../contrib/audio/tdnn/Tdnn_pth2onnx.py | 86 +- .../contrib/audio/tdnn/Tdnn_pyacl_infer.py | 352 +- ACL_PyTorch/contrib/audio/tdnn/acl_net.py | 552 +- ACL_PyTorch/contrib/audio/tdnn/atc.sh | 16 +- .../contrib/audio/tdnn/hyperparams.yaml | 134 +- ACL_PyTorch/contrib/audio/tdnn/interfaces.py | 1916 +++--- .../contrib/audio/tdnn/modelzoo_level.txt | 4 +- ACL_PyTorch/contrib/audio/tdnn/om_infer.sh | 46 +- .../contrib/audio/tdnn/requirements.txt | 22 +- .../3d_attention_net_pkl2onnx.py | 66 +- .../3d_attention_net_preprocess.py | 134 +- .../cv/classfication/3d_attention_net/LICENSE | 400 +- .../3d_attention_net/modelzoo_level.txt | 6 +- .../classfication/3d_attention_net/readme.md | 196 +- .../3d_attention_net/requirements.txt | 12 +- .../3d_attention_net/resize_optimize.py | 76 +- .../contrib/cv/classfication/AlexNet/LICENSE | 400 +- .../cv/classfication/C3D/C3D_postprocess.py | 136 +- .../cv/classfication/C3D/modelzoo_level.txt | 4 +- .../cv/classfication/CSPResneXt50/LICENSE | 400 +- .../cv/classfication/Deit_Small/LICENSE | 400 +- .../Deit_Small/gen_dataset_info.py | 120 +- .../Deit_Small/imagenet_acc_eval.py | 366 +- .../Deit_Small/imagenet_torch_preprocess.py | 208 +- .../cv/classfication/Deit_Small/parse.py | 62 +- .../classfication/Deit_Small/test/README.md | 48 +- .../classfication/Deit_Small/test/pth2om.sh | 0 .../Efficient-3DCNNs_postprocess.py | 226 +- .../Efficient-3DCNNs_preprocess.py | 184 +- .../cv/classfication/Efficient-3DCNNs/LICENSE | 406 +- .../classfication/Efficient-3DCNNs/README.md | 98 +- .../Efficient-3DCNNs/modelzoo_level.txt | 6 +- .../Efficient-3DCNNs/requirements.txt | 12 +- .../Efficient-B1_postprocess.py | 144 +- .../Efficient-B1_preprocess.py | 124 +- .../EfficientNet-B1/Efficient-B1_pth2onnx.py | 102 +- .../EfficientNet-B1/ImageNet_val_split.py | 124 +- .../cv/classfication/EfficientNet-B1/LICENSE | 402 +- .../classfication/EfficientNet-B1/README.md | 96 +- .../EfficientNet-B1/gen_dataset_info.py | 84 +- .../EfficientNet-B1/modelzoo_level.txt | 6 +- .../EfficientNet-B1/requirements.txt | 16 +- .../EfficientNet-B1/test/parse.py | 82 +- .../classfication/EfficientNet-B3/README.md | 0 .../contrib/cv/classfication/FixRes/README.md | 86 +- .../classfication/FixRes/modelzoo_level.txt | 6 +- .../contrib/cv/classfication/GENet/LICENSE | 400 +- .../classfication/GENet/cifar10_acc_eval.py | 372 +- .../cv/classfication/GENet/modelzoo_level.txt | 10 +- .../cv/classfication/GENet/test/infer_bin.sh | 2 +- .../cv/classfication/GhostNet1.0x/LICENSE | 400 +- .../GhostNet1.0x/ghostnet_pth2onnx.py | 66 +- .../GhostNet1.0x/imagenet_torch_preprocess.py | 242 +- .../GhostNet1.0x/requirements.txt | 10 +- .../classfication/GhostNet1.0x/test/README.md | 48 +- .../cv/classfication/GloRe/GloRe_pth2onnx.py | 66 +- .../contrib/cv/classfication/GloRe/LICENSE | 400 +- .../contrib/cv/classfication/GloRe/README.md | 86 +- .../contrib/cv/classfication/GloRe/env.sh | 10 +- .../cv/classfication/GloRe/modelzoo_level.txt | 4 +- .../cv/classfication/GloRe/requirements.txt | 10 +- .../cv/classfication/GloRe/test/parse.py | 62 +- .../HRNet-Image-Classification/LICENSE | 58 +- .../HRNet-Image-Classification/README.md | 540 +- .../HRNet-Image-Classification/get_info.py | 116 +- .../hrnet_pth2onnx.py | 184 +- .../imagenet_acc_eval.py | 374 +- .../imagenet_torch_preprocess.py | 206 +- .../requirements.txt | 20 +- .../HRNet-Image-Classification/test/README.md | 56 +- .../HRNet-Image-Classification/test/parse.py | 62 +- .../contrib/cv/classfication/LV-Vit/LICENSE | 400 +- .../LV-Vit/LV_Vit_postprocess.py | 94 +- .../classfication/LV-Vit/LV_Vit_pth2onnx.py | 156 +- .../contrib/cv/classfication/LV-Vit/README.md | 762 +-- .../classfication/LV-Vit/gen_dataset_info.py | 62 +- .../classfication/LV-Vit/modelzoo_level.txt | 6 +- .../cv/classfication/LV-Vit/test/README.md | 154 +- .../MobileNet-v1/mobilenet-v1_pth2onnx.py | 214 +- .../MobileNet-v1/test/eval_acc_perf.sh | 0 .../classfication/MobileNet-v1/test/pth2om.sh | 0 .../contrib/cv/classfication/OSNet/README.md | 496 +- .../cv/classfication/OSNet/test/README.md | 62 +- .../PAMTRI/PAMTRI_postprocess.py | 280 +- .../classfication/PAMTRI/PAMTRI_preprocess.py | 184 +- .../contrib/cv/classfication/PAMTRI/README.md | 140 +- .../classfication/PAMTRI/modelzoo_level.txt | 6 +- .../cv/classfication/PointNetCNN/LICENSE | 400 +- .../PointNetCNN/PointNetCNN_preprocess.py | 112 +- .../cv/classfication/PointNetCNN/README.md | 128 +- .../PointNetCNN/modelzoo_level.txt | 6 +- .../PointNetCNN/requirements.txt | 16 +- .../Pointnetplus/Pointnetplus/README.md | 138 +- .../Pointnetplus/modelzoo_level.txt | 4 +- .../Pointnetplus/pointnetplus_postprocess.py | 230 +- .../Pointnetplus/pointnetplus_preprocess.py | 314 +- .../Pointnetplus/pointnetplus_pth2onnx.py | 208 +- .../Pointnetplus/requirements.txt | 10 +- .../contrib/cv/classfication/R(2+1)D/ LICENSE | 406 +- .../classfication/R(2+1)D/ modelzoo_level.txt | 4 +- .../cv/classfication/R(2+1)D/ReadME.md | 152 +- .../cv/classfication/R(2+1)D/get_info.py | 118 +- .../r2plus1d_r34_8x8x1_180e_ucf101_rgb2.py | 192 +- .../cv/classfication/R(2+1)D/requirements.txt | 16 +- .../ReID_for_Pytorch/modelzoo_level.txt | 6 +- .../cv/classfication/RegNetX-1.6GF/LICENSE | 400 +- .../classfication/RegNetX-1.6GF/get_info.py | 122 +- .../RegNetX-1.6GF/vision_metric_ImageNet.py | 368 +- .../cv/classfication/RegNetY-1.6GF/LICENSE | 400 +- .../classfication/RegNetY-1.6GF/get_info.py | 122 +- .../RegNetY-1.6GF/vision_metric_ImageNet.py | 368 +- .../cv/classfication/Res2Net101_v1b/LICENSE | 400 +- .../cv/classfication/Res2Net101_v1b/README.md | 490 +- .../Res2Net101_v1b/gen_dataset_info.py | 122 +- .../Res2Net101_v1b/imagenet_acc_eval.py | 368 +- .../imagenet_torch_preprocess.py | 234 +- .../Res2Net101_v1b/requirements.txt | 10 +- .../Res2Net101_v1b/res2net101_v1b_pth2onnx.py | 72 +- .../Res2Net101_v1b/test/README.md | 48 +- .../cv/classfication/ResNet101/LICENSE | 400 +- .../cv/classfication/ResNet101/README.md | 500 +- .../ResNet101/gen_dataset_info.py | 122 +- .../ResNet101/imagenet_acc_eval.py | 368 +- .../ResNet101/imagenet_torch_preprocess.py | 234 +- .../classfication/ResNet101/requirements.txt | 10 +- .../ResNet101/resnet101_pth2onnx.py | 70 +- .../cv/classfication/ResNet101/test/README.md | 58 +- .../cv/classfication/ResNet101/test/parse.py | 62 +- .../contrib/cv/classfication/ResNet18/LICENSE | 58 +- .../cv/classfication/ResNet18/README.md | 498 +- .../ResNet18/gen_dataset_info.py | 122 +- .../ResNet18/imagenet_acc_eval.py | 368 +- .../ResNet18/imagenet_torch_preprocess.py | 234 +- .../classfication/ResNet18/requirements.txt | 10 +- .../ResNet18/resnet18_pth2onnx.py | 70 +- .../cv/classfication/ResNet18/test/README.md | 58 +- .../cv/classfication/ResNet18/test/parse.py | 62 +- .../contrib/cv/classfication/ResNet34/LICENSE | 400 +- .../cv/classfication/ResNet34/README.md | 500 +- .../ResNet34/gen_dataset_info.py | 122 +- .../ResNet34/imagenet_acc_eval.py | 368 +- .../ResNet34/imagenet_torch_preprocess.py | 234 +- .../classfication/ResNet34/requirements.txt | 10 +- .../ResNet34/resnet34_pth2onnx.py | 70 +- .../cv/classfication/ResNet34/test/README.md | 58 +- .../cv/classfication/ResNet34/test/parse.py | 62 +- .../classfication/ResNext101_32x8d/README.md | 576 +- .../cv/classfication/Shufflenetv1/LICENSE | 400 +- .../cv/classfication/Shufflenetv1/README.md | 540 +- .../Shufflenetv1/requirements.txt | 10 +- .../Shufflenetv1/shufflenetv1_pth2onnx_bs1.py | 76 +- .../shufflenetv1_pth2onnx_bs16.py | 74 +- .../shufflenetv1_torch_preprocess.py | 156 +- .../cv/classfication/Shufflenetv2+/LICENSE | 400 +- .../cv/classfication/Shufflenetv2+/README.md | 518 +- .../imagenet_torch_preprocess.py | 144 +- .../Shufflenetv2+/requirements.txt | 10 +- .../shufflenetv2_pth2onnx_bs1.py | 78 +- .../shufflenetv2_pth2onnx_bs16.py | 78 +- .../Shufflenetv2+/test/readme.md | 54 +- .../SimCLR_inference/Simclr_preprocess.py | 212 +- .../SimCLR_inference/Simclr_pth2onnx.py | 158 +- .../SimCLR_inference/test/parse.py | 60 +- .../contrib/cv/classfication/Sknet50/LICENSE | 400 +- .../cv/classfication/Sknet50/README.md | 538 +- .../cv/classfication/Sknet50/requirements.txt | 10 +- .../cv/classfication/Sknet50/test/README.md | 52 +- .../cv/classfication/Sknet50/test/parse.py | 62 +- .../contrib/cv/classfication/TNT/README.md | 88 +- .../cv/classfication/TNT/modelzoo_level.txt | 6 +- .../contrib/cv/classfication/TResNet/LICENSE | 48 +- .../cv/classfication/TResNet/README.md | 74 +- .../TResNet/TResNet_postprocess.py | 368 +- .../classfication/TResNet/modelzoo_level.txt | 6 +- .../cv/classfication/Wide_ResNet101_2/LICENSE | 400 +- .../classfication/Wide_ResNet101_2/README.md | 626 +- .../Wide_ResNet101_2/gen_dataset_info.py | 122 +- .../Wide_ResNet101_2/requirements.txt | 10 +- .../Wide_ResNet101_2/test/README.md | 96 +- .../Wide_ResNet101_2/test/parse.py | 62 +- .../Wide_ResNet101_2/wrn101_2_pth2onnx.py | 68 +- .../contrib/cv/classfication/X3D/LICENSE | 404 +- .../contrib/cv/classfication/X3D/README.md | 136 +- .../baseline_dino_resnet50/LICENSE | 400 +- .../baseline_dino_resnet50/README.md | 90 +- .../dino_resnet50_postprocess.py | 336 +- .../dino_resnet50_preprocess.py | 230 +- .../dino_resnet50_pth2onnx.py | 90 +- .../baseline_dino_resnet50/get_info.py | 116 +- .../baseline_dino_resnet50/modelzoo_level.txt | 6 +- .../baseline_dino_resnet50/test/parse.py | 60 +- .../cv/classfication/pnasnet5large/LICENSE | 400 +- .../classfication/pnasnet5large/get_info.py | 122 +- .../pnasnet5large/vision_metric_ImageNet.py | 368 +- .../cv/classfication/vit-small/README.md | 140 +- .../contrib/cv/classfication/vit-small/env.sh | 0 .../vit_base_patch32_224/LICENSE | 400 +- .../vit_base_patch32_224/gen_dataset_info.py | 128 +- .../vit_base_patch32_224/modelzoo_level.txt | 10 +- .../vit_base_patch32_224/requirements.txt | 8 +- .../vit_base_patch32_224_preprocess.py | 104 +- .../vit_base_patch32_224_pth2onnx.py | 80 +- .../contrib/cv/classfication/vovnet39/LICENSE | 400 +- .../cv/classfication/vovnet39/README.md | 508 +- .../classfication/vovnet39/requirements.txt | 10 +- .../cv/classfication/vovnet39/test/readme.md | 48 +- .../vovnet39/vovnet39_pth2onnx.py | 72 +- .../cv/classfication/xcit/modelzoo_level.txt | 12 +- .../contrib/cv/detection/3DUnet/LISCENSE | 400 +- .../cv/detection/3DUnet/UNet3D_pth2onnx.py | 96 +- .../contrib/cv/detection/3DUnet/modify.py | 226 +- .../cv/detection/3DUnet/postprocess.py | 260 +- .../cv/detection/AlphaPose/AlphaPose.patch | 20 +- .../contrib/cv/detection/AlphaPose/LICENSE | 400 +- .../detection/AlphaPose/gen_dataset_info.py | 130 +- .../cv/detection/AlphaPose/test/parse.py | 62 +- .../contrib/cv/detection/BSN/BSN_eval.py | 168 +- .../cv/detection/BSN/BSN_pem_postprocess.py | 378 +- .../cv/detection/BSN/BSN_pem_preprocess.py | 212 +- .../cv/detection/BSN/BSN_pem_pth2onnx.py | 130 +- .../cv/detection/BSN/BSN_tem_postprocess.py | 624 +- .../cv/detection/BSN/BSN_tem_preprocess.py | 148 +- .../cv/detection/BSN/BSN_tem_pth2onnx.py | 126 +- .../contrib/cv/detection/BSN/README.md | 900 +-- .../detection/BSN/TEM_onnx_conv1d2conv2d.py | 218 +- .../cv/detection/BSN/gen_dataset_info.py | 76 +- .../cv/detection/BSN/modelzoo_level.txt | 8 +- ACL_PyTorch/contrib/cv/detection/BSN/parse.py | 76 +- .../contrib/cv/detection/BSN/requirements.txt | 50 +- .../contrib/cv/detection/BSN/test/parse.py | 76 +- .../Cascade-RCNN-Resnet101-FPN-DCN/README.md | 312 +- .../coco_eval.py | 180 +- .../get_info.py | 118 +- .../mmdetection_coco_postprocess.py | 296 +- .../mmdetection_coco_preprocess.py | 136 +- .../requirements.txt | 10 +- .../txt_to_json.py | 226 +- .../cv/detection/Cascade_RCNN_R101/README.md | 114 +- .../detection/Cascade_RCNN_R101/get_info.py | 118 +- .../mmdetection_coco_postprocess.py | 550 +- .../mmdetection_coco_preprocess.py | 136 +- .../Cascade_RCNN_R101/requirements.txt | 20 +- .../contrib/cv/detection/CenterFace/README.md | 600 +- .../CenterFace/aipp_centerface.aippconfig | 30 +- .../detection/CenterFace/calibration_bin.py | 112 +- .../CenterFace/centerface_pth_postprocess.py | 306 +- .../CenterFace/centerface_pth_preprocess.py | 116 +- .../cv/detection/CenterFace/convert.py | 80 +- .../cv/detection/CenterFace/pth2onnx.py | 70 +- .../cv/detection/CenterFace/test/README.md | 54 +- .../CenterNet/CenterNet_postprocess.py | 208 +- .../CenterNet/CenterNet_preprocess.py | 196 +- .../detection/CenterNet/CenterNet_pth2onnx.py | 108 +- .../contrib/cv/detection/CenterNet/README.md | 206 +- .../contrib/cv/detection/DSFD/DSFD.patch | 3356 ++++----- .../contrib/cv/detection/DSFD/README.md | 206 +- .../contrib/cv/detection/DSFD/data/config.py | 180 +- .../cv/detection/DSFD/data/widerface.py | 264 +- .../cv/detection/DSFD/dsfd_preprocess.py | 126 +- .../DSFD/eval_tools/dsfd_acc_eval.py | 782 +-- .../cv/detection/DSFD/requirements.txt | 18 +- .../cv/detection/DSFD/test/dsfd_pth2onnx.py | 134 +- .../contrib/cv/detection/Deepspeech/README.md | 504 +- .../cv/detection/Deepspeech/ckpt2onnx.py | 96 +- .../Deepspeech/deepspeech_postprocess.py | 302 +- .../Deepspeech/deepspeech_preprocess.py | 224 +- .../cv/detection/Deepspeech/test/t4_perf.py | 170 +- ACL_PyTorch/contrib/cv/detection/Detr/FPS.py | 64 +- .../contrib/cv/detection/Detr/excute_omval.py | 120 +- .../contrib/cv/detection/Detr/onnx2om.py | 86 +- .../cv/detection/EfficientDetD0/get_info.py | 118 +- .../detection/EfficientDetD0/modify_onnx.py | 68 +- .../detection/EfficientDetD0/test/pth2om.sh | 0 .../cv/detection/EfficientDetD7/get_info.py | 118 +- .../detection/EfficientDetD7/modify_onnx.py | 68 +- .../cv/detection/FOTS/FOTS_pth2onnx_8.py | 72 +- ACL_PyTorch/contrib/cv/detection/FOTS/LICENSE | 408 +- .../cv/detection/FOTS/gen_dataset_info.py | 118 +- .../cv/detection/FOTS/modelzoo_level.txt | 6 +- .../contrib/cv/detection/FOTS/preprocess.py | 88 +- .../contrib/cv/detection/FOTS/readme.md | 284 +- .../contrib/cv/detection/FOTS/requirments.txt | 24 +- .../cv/detection/FasterRCNN_FPN_DCN/README.md | 158 +- .../cv/detection/Fsaf/Fsaf_preprocess.py | 144 +- .../contrib/cv/detection/Fsaf/README.md | 108 +- .../contrib/cv/detection/GFocalV2/LICENSE | 404 +- .../contrib/cv/detection/GFocalV2/README.md | 118 +- .../contrib/cv/detection/GFocalV2/get_info.py | 118 +- .../detection/GFocalV2/gfocal_postprocess.py | 178 +- .../detection/GFocalV2/gfocal_preprocess.py | 144 +- .../cv/detection/GFocalV2/modelzoo_level.txt | 4 +- .../cv/detection/GFocalV2/requirements.txt | 8 +- .../cv/detection/GFocalV2/test/parse.py | 62 +- .../contrib/cv/detection/M2Det/LICENSE | 400 +- .../contrib/cv/detection/M2Det/M2Det.patch | 16 +- .../cv/detection/M2Det/M2Det_preprocess.py | 116 +- .../cv/detection/M2Det/M2Det_pth2onnx.py | 174 +- .../cv/detection/M2Det/gen_dataset_info.py | 132 +- .../cv/detection/M2Det/modelzoo_level.txt | 6 +- .../cv/detection/M2Det/requirements.txt | 30 +- .../contrib/cv/detection/NAS_FPN/README.md | 114 +- .../contrib/cv/detection/NAS_FPN/coco_eval.py | 182 +- .../contrib/cv/detection/NAS_FPN/get_info.py | 116 +- .../NAS_FPN/mmdetection_coco_postprocess.py | 314 +- .../NAS_FPN/mmdetection_coco_preprocess.py | 136 +- .../cv/detection/NAS_FPN/requirements.txt | 20 +- .../cv/detection/NAS_FPN/txt_to_json.py | 226 +- .../contrib/cv/detection/Nasnetlarge/LICENSE | 402 +- .../OpenPose/OpenPose_postprocess.py | 238 +- .../detection/OpenPose/OpenPose_preprocess.py | 180 +- .../detection/OpenPose/OpenPose_pth2onnx.py | 126 +- .../contrib/cv/detection/OpenPose/README.md | 104 +- .../cv/detection/OpenPose/gen_dataset_info.py | 144 +- .../cv/detection/OpenPose/modelzoo_level.txt | 8 +- .../cv/detection/OpenPose/requirements.txt | 8 +- .../cv/detection/OpenPose/test/parse.py | 64 +- ACL_PyTorch/contrib/cv/detection/RFCN/env.sh | 12 +- .../cv/detection/RFCN/modelzoo_level.txt | 10 +- .../cv/detection/RFCN/rfcn_postprocess.py | 496 +- .../contrib/cv/detection/RefineDet/README.md | 132 +- .../contrib/cv/detection/RefineDet/env.sh | 10 +- .../cv/detection/RefineDet/get_prior_data.py | 54 +- .../cv/detection/RefineDet/modelzoo_level.txt | 4 +- .../contrib/cv/detection/Retinanet/LICENSE | 400 +- .../cv/detection/Retinanet/get_info.py | 118 +- .../cv/detection/Retinanet/requirements.txt | 8 +- .../retinanet_pth_postprocess_detectron2.py | 370 +- .../retinanet_pth_preprocess_detectron2.py | 158 +- .../cv/detection/Retinanet/test/README.md | 98 +- .../cv/detection/Retinanet/test/parse.py | 62 +- .../cv/detection/SSD-MobileNetV1/LICENSE | 400 +- .../SSD-MobileNetV1/SSD_MobileNet_pth2onnx.py | 92 +- .../cv/detection/SSD-MobileNetV1/get_info.py | 126 +- .../cv/detection/SSD-Resnet34/README.md | 900 +-- .../cv/detection/SSD-Resnet34/ssd_pth2onnx.py | 92 +- .../YOLOX-mmdetection/YOLOX_postprocess.py | 108 +- .../YOLOX-mmdetection/gen_dataset_info.py | 106 +- .../cv/detection/YOLOX-mmdetection/readme.md | 102 +- .../YOLOX-mmdetection/requirements.txt | 12 +- .../cv/detection/YOLOX/Yolox_postprocess.py | 278 +- .../contrib/cv/detection/YOLOX/readme.md | 100 +- .../contrib/cv/detection/pyramidbox/README.md | 582 +- .../cv/detection/pyramidbox/convert.py | 78 +- .../pyramidbox/pyramidbox_pth2onnx.py | 68 +- .../pyramidbox/pyramidbox_pth_postprocess.py | 452 +- .../pyramidbox/pyramidbox_pth_preprocess.py | 218 +- .../cv/face/AlignedReID/modelzoo_level.txt | 6 +- .../cv/face/FaceNet/FaceNet_postprocess.py | 462 +- .../cv/face/FaceNet/FaceNet_preprocess.py | 146 +- .../cv/face/FaceNet/FaceNet_pth2onnx.py | 92 +- ACL_PyTorch/contrib/cv/face/FaceNet/LICENSE | 110 +- .../cv/face/FaceNet/MTCNN_preprocess.py | 734 +- .../contrib/cv/face/FaceNet/MTCNN_pth2onnx.py | 114 +- .../cv/face/FaceNet/gen_dataset_info.py | 118 +- .../contrib/cv/face/FaceNet/models/acl_net.py | 566 +- .../cv/face/FaceNet/models/mtcnn.patch | 478 +- .../cv/face/FaceNet/modelzoo_level.txt | 2 +- .../contrib/cv/face/FaceNet/requirements.txt | 22 +- .../cv/face/FaceNet/utils/batch_utils.py | 96 +- .../cv/face/FaceNet/utils/fix_prelu.py | 70 +- .../cv/face/FaceNet/utils/gen_test_data.py | 60 +- .../contrib/cv/face/ReId-MGN-master/LICENSE | 400 +- .../face/ReId-MGN-master/postprocess_MGN.py | 324 +- .../cv/face/ReId-MGN-master/preprocess_MGN.py | 118 +- .../cv/face/ReId-MGN-master/pth2onnx.py | 78 +- .../cv/face/ReId-MGN-master/requirements.txt | 8 +- .../cv/face/ReId-MGN-master/test/README.md | 108 +- .../cv/face/ReId-MGN-master/test/parse.py | 62 +- .../contrib/cv/face/reid_PCB_baseline/LICENSE | 400 +- .../reid_PCB_baseline/PCB_pth_postprocess.py | 528 +- .../reid_PCB_baseline/PCB_pth_preprocess.py | 316 +- .../cv/face/reid_PCB_baseline/Readme.md | 570 +- .../contrib/cv/face/reid_PCB_baseline/env.sh | 12 +- .../cv/face/reid_PCB_baseline/get_info.py | 118 +- .../face/reid_PCB_baseline/modelzoo_level.txt | 2 +- .../cv/face/reid_PCB_baseline/pth2onnx.py | 74 +- .../face/reid_PCB_baseline/requirements.txt | 18 +- .../cv/face/reid_PCB_baseline/test/Readme.md | 138 +- .../reid_PCB_baseline/test/eval_acc_perf.sh | 106 +- .../cv/face/reid_PCB_baseline/test/parse.py | 62 +- .../cv/face/reid_PCB_baseline/test/pth2om.sh | 38 +- .../face/reid_PCB_baseline/test/resnet.diff | 22 +- .../test/scripts/split_reducelp.py | 102 +- ACL_PyTorch/contrib/cv/gan/BigGAN/LICENSE | 400 +- ACL_PyTorch/contrib/cv/gan/BigGAN/README.md | 448 +- .../contrib/cv/gan/BigGAN/biggan_pth2onnx.py | 126 +- .../contrib/cv/gan/BigGAN/requirements.txt | 8 +- .../contrib/cv/gan/CGAN/CGAN_postprocess.py | 152 +- .../contrib/cv/gan/CGAN/CGAN_preprocess.py | 124 +- .../contrib/cv/gan/CGAN/CGAN_pth2onnx.py | 130 +- ACL_PyTorch/contrib/cv/gan/CGAN/README.md | 530 +- .../contrib/cv/gan/CGAN/gen_dataset_info.py | 88 +- .../contrib/cv/gan/CGAN/modelzoo_level.txt | 4 +- ACL_PyTorch/contrib/cv/gan/CGAN/test/parse.py | 76 +- .../cv/gan/CycleGAN/CycleGAN_NetLoad.py | 180 +- .../gan/CycleGAN/CycleGAN_ReflectpadDeal.py | 132 +- .../cv/gan/CycleGAN/CycleGAN_onnx_export.py | 124 +- ACL_PyTorch/contrib/cv/gan/CycleGAN/LICENSE | 60 +- .../cv/gan/CycleGAN/PerformanceForGPU.py | 346 +- ACL_PyTorch/contrib/cv/gan/CycleGAN/Readme.md | 1236 ++-- .../contrib/cv/gan/CycleGAN/eval_acc.py | 220 +- .../cv/gan/CycleGAN/gen_dataset_info.py | 178 +- .../cv/gan/CycleGAN/maps_torch_preprocess.py | 216 +- ACL_PyTorch/contrib/cv/gan/CycleGAN/parse.py | 282 +- ACL_PyTorch/contrib/cv/gan/DCGAN/README.md | 116 +- .../contrib/cv/gan/DCGAN/modelzoo_level.txt | 6 +- .../contrib/cv/gan/GAN/GAN_pth2onnx.py | 108 +- .../contrib/cv/gan/GAN/GAN_testdata.py | 114 +- ACL_PyTorch/contrib/cv/gan/GAN/GAN_txt2jpg.py | 100 +- ACL_PyTorch/contrib/cv/gan/GAN/LICENSE | 402 +- ACL_PyTorch/contrib/cv/gan/GAN/README.md | 442 +- ACL_PyTorch/contrib/cv/gan/GAN/models.py | 134 +- .../contrib/cv/gan/GAN/modelzoo_level.txt | 4 +- .../contrib/cv/gan/GAN/requirements.txt | 8 +- ACL_PyTorch/contrib/cv/gan/GAN/test/README.md | 76 +- ACL_PyTorch/contrib/cv/gan/Pix2Pix/README.md | 70 +- .../contrib/cv/gan/Pix2Pix/modelzoo_level.txt | 4 +- .../contrib/cv/gan/Pix2Pix/precision.py | 396 +- .../contrib/cv/gan/Pix2Pix/pytorch_prof.py | 280 +- .../contrib/cv/gan/Pix2pixHD/datasets_deal.py | 86 +- ACL_PyTorch/contrib/cv/gan/StarGAN/LICENSE | 402 +- ACL_PyTorch/contrib/cv/gan/StarGAN/README.md | 320 +- .../contrib/cv/gan/StarGAN/modelzoo_level.txt | 4 +- .../contrib/cv/gan/StarGAN/requirements.txt | 8 +- .../CSNLN_postprocess.py | 328 +- .../CSNLN_preprocess.py | 210 +- .../CSNLN_pth2onnx.py | 74 +- .../Cross-Scale-Non-Local-Attention/LICENSE | 400 +- .../get_info.py | 114 +- .../modelzoo_level.txt | 4 +- .../perf_softmax_transpose.py | 44 +- .../requirements.txt | 16 +- .../test/parse.py | 58 +- .../contrib/cv/image_process/DnCNN/READEME.md | 532 +- .../cv/image_process/DnCNN/test/README.md | 62 +- .../3DMPPE-ROOTNET_postprocess.py | 98 +- .../3DMPPE-ROOTNET_preprocess.py | 120 +- .../3DMPPE-ROOTNET/3DMPPE-ROOTNET_pth2onnx.py | 94 +- .../cv/pose_estimation/3DMPPE-ROOTNET/LICENSE | 404 +- .../pose_estimation/3DMPPE-ROOTNET/README.md | 86 +- .../3DMPPE-ROOTNET/modelzoo_level.txt | 4 +- .../3DMPPE-ROOTNET/requirements.txt | 16 +- .../3DMPPE-ROOTNET/test/parse.py | 60 +- .../HigherHRNet/modelzoo_level.txt | 6 +- .../pose_estimation/MSPN/MSPN_postprocess.py | 386 +- .../pose_estimation/MSPN/MSPN_preprocess.py | 180 +- .../cv/pose_estimation/MSPN/MSPN_pth2onnx.py | 106 +- .../contrib/cv/pose_estimation/MSPN/README.md | 128 +- .../pose_estimation/MSPN/gen_dataset_info.py | 74 +- .../pose_estimation/MSPN/modelzoo_level.txt | 6 +- .../cv/pose_estimation/MSPN/test/perf_g.sh | 46 +- .../TransPose/fusion_switch.cfg | 2 +- .../TransPose/modelzoo_level.txt | 6 +- .../cv/pose_estimation/VideoPose3D/LISCENCE | 404 +- .../cv/pose_estimation/VideoPose3D/README.md | 76 +- .../VideoPose3D/modelzoo_level.txt | 6 +- .../ADNet/ADNet_postprocess.py | 180 +- .../ADNet/ADNet_preprocess.py | 130 +- .../ADNet/ADNet_pth2onnx.py | 96 +- .../cv/quality_enhancement/ADNet/README.md | 592 +- .../ADNet/gen_dataset_info.py | 78 +- .../ADNet/modelzoo_level.txt | 4 +- .../quality_enhancement/ADNet/test/parse.py | 76 +- .../3d_nested_unet_postprocess.py | 78 +- .../3d_nested_unet_preprocess.py | 78 +- .../3D_Nested_Unet/3d_nested_unet_pth2onnx.py | 114 +- .../cv/segmentation/3D_Nested_Unet/License | 400 +- .../3D_Nested_Unet/change_infer_path.py | 122 +- .../3D_Nested_Unet/gen_dataset_info.py | 158 +- .../cv/segmentation/3D_Nested_Unet/new.patch | 6018 ++++++++--------- .../contrib/cv/segmentation/DeeplabV3/LICENSE | 400 +- .../cv/segmentation/DeeplabV3/README.md | 164 +- .../DeeplabV3/deeplabv3_torch_postprocess.py | 460 +- .../DeeplabV3/deeplabv3_torch_preprocess.py | 176 +- .../DeeplabV3/gen_dataset_info.py | 148 +- .../segmentation/DeeplabV3/modelzoo_level.txt | 6 +- .../segmentation/DeeplabV3/requirements.txt | 12 +- .../cv/segmentation/DeeplabV3/test/parse.py | 64 +- .../cv/segmentation/ENet/ENet_postprocess.py | 184 +- .../cv/segmentation/ENet/ENet_preprocess.py | 214 +- .../cv/segmentation/ENet/ENet_pth2onnx.py | 164 +- .../cv/segmentation/ENet/test/parse.py | 62 +- .../contrib/cv/segmentation/FCN-8s/LICENSE | 400 +- .../contrib/cv/segmentation/FCN-8s/README.md | 712 +- .../cv/segmentation/FCN-8s/get_info.py | 118 +- .../mmsegmentation_voc2012_postprocess.py | 486 +- .../mmsegmentation_voc2012_preprocess.py | 190 +- .../cv/segmentation/FCN-8s/requirements.txt | 8 +- .../cv/segmentation/FCN-8s/test/README.md | 62 +- .../cv/segmentation/FCN-8s/test/parse.py | 62 +- .../FastSCNN/Fast_SCNN_pth2onnx.py | 90 +- .../cv/segmentation/FastSCNN/README.md | 738 +- .../segmentation/FastSCNN/gen_dataset_info.py | 94 +- .../cv/segmentation/FastSCNN/test/README.md | 240 +- .../cv/segmentation/FastSCNN/test/parse.py | 78 +- .../contrib/cv/segmentation/GCNet/README.md | 318 +- .../segmentation/IntraDA/gen_dataset_info.py | 196 +- .../IntraDA/intrada_postprocess.py | 354 +- .../IntraDA/intrada_preprocess.py | 134 +- .../segmentation/IntraDA/modelzoo_level.txt | 4 +- .../cv/segmentation/IntraDA/requirements.txt | 10 +- .../contrib/cv/segmentation/PSPnet/LICENSE | 400 +- .../contrib/cv/segmentation/PSPnet/README.md | 812 +-- .../cv/segmentation/PSPnet/get_info.py | 118 +- .../mmsegmentation_voc2012_preprocess.py | 190 +- .../cv/segmentation/PSPnet/requirements.txt | 8 +- .../cv/segmentation/PSPnet/test/README.md | 62 +- .../cv/segmentation/PSPnet/test/parse.py | 62 +- .../contrib/cv/segmentation/SOLOV1/README.md | 132 +- .../cv/segmentation/SOLOV1/get_info.py | 118 +- .../cv/segmentation/SOLOV1/modelzoo_level.txt | 4 +- .../cv/segmentation/SOLOV1/pth2onnx.py | 80 +- .../cv/segmentation/SOLOV1/requirements.txt | 10 +- .../segmentation/SOLOV1/solov1_postprocess.py | 208 +- .../segmentation/SOLOV1/solov1_preprocess.py | 172 +- .../cv/segmentation/SOLOV1/test/parse.py | 62 +- .../contrib/cv/segmentation/SOLOV2/README.md | 134 +- .../cv/segmentation/SOLOV2/get_info.py | 118 +- .../cv/segmentation/SOLOV2/modelzoo_level.txt | 4 +- .../cv/segmentation/SOLOV2/pth2onnx.py | 80 +- .../cv/segmentation/SOLOV2/requirements.txt | 10 +- .../segmentation/SOLOV2/solov2_postprocess.py | 208 +- .../segmentation/SOLOV2/solov2_preprocess.py | 172 +- .../cv/segmentation/SOLOV2/test/parse.py | 62 +- .../contrib/cv/segmentation/SiamMask/LICENSE | 402 +- .../Ultra-Fast-Lane-Detection/LICENSE | 402 +- .../modelzoo_level.txt | 10 +- .../cv/segmentation/VNet/modelzoo_level.txt | 4 +- .../contrib/cv/segmentation/Wseg/README.md | 130 +- .../cv/segmentation/Wseg/Wseg_postprocess.py | 748 +- .../cv/segmentation/Wseg/Wseg_preprocess.py | 252 +- .../Wseg/fix_softmax_transpose.py | 70 +- .../cv/segmentation/Wseg/get_dateset_info.py | 120 +- .../cv/segmentation/Wseg/modelzoo_level.txt | 4 +- .../cv/segmentation/Wseg/test/parse.py | 64 +- .../contrib/cv/segmentation/Wseg/val_voc.txt | 600 +- .../contrib/cv/segmentation/YOLACT/README.md | 310 +- .../segmentation/YOLACT/YOLACT_postprocess.py | 1128 +-- .../segmentation/YOLACT/YOLACT_preprocess.py | 348 +- .../segmentation/YOLACT/test/eval_acc_perf.sh | 0 .../cv/segmentation/YOLACT/test/parse.py | 62 +- .../cv/segmentation/YOLACT/test/perf_g.sh | 0 .../cv/segmentation/YOLACT/test/pth2om.sh | 0 .../cv/segmentation/YOLACT_plus/LICENSE | 400 +- .../cv/segmentation/YOLACT_plus/README.md | 318 +- .../YOLACT_plus/YOLACT_postprocess.py | 1132 ++-- .../YOLACT_plus/YOLACT_preprocess.py | 312 +- .../cv/segmentation/YOLACT_plus/dcnv2.diff | 212 +- .../segmentation/YOLACT_plus/deform_conv.py | 468 +- .../YOLACT_plus/modelzoo_level.txt | 4 +- .../cv/segmentation/YOLACT_plus/pth2onnx.py | 358 +- .../contrib/cv/super_resolution/EDSR/LICENSE | 400 +- .../cv/super_resolution/EDSR/requirements.txt | 10 +- .../contrib/cv/super_resolution/RCAN/LICENSE | 400 +- ...50\347\220\206\346\214\207\345\257\274.md" | 482 +- .../cv/super_resolution/RCAN/test/README.md | 52 +- .../cv/super_resolution/RCAN/test/parse.py | 64 +- .../super_resolution/RDN/modelzoo_level.txt | 4 +- .../cv/super_resolution/RDN/test/README.md | 102 +- .../cv/super_resolution/Real-ESRGAN/README.md | 98 +- .../Real-ESRGAN/Real-ESRGAN_postprocess.py | 24 +- .../Real-ESRGAN/Real-ESRGAN_preprocess.py | 28 +- .../Real-ESRGAN/get_dataset_info.py | 124 +- .../Real-ESRGAN/modelzoo_level.txt | 6 +- .../Real-ESRGAN/test/parse.py | 50 +- .../contrib/cv/super_resolution/SRCNN/LICENSE | 400 +- .../super_resolution/SRCNN/requirements.txt | 10 +- .../cv/super_resolution/SRCNN/test/parse.py | 62 +- .../contrib/cv/tracking/SiamFC/LICENSE | 400 +- .../contrib/cv/tracking/SiamFC/README.md | 100 +- .../cv/tracking/SiamFC/get_perf_data.py | 128 +- .../cv/tracking/SiamFC/modelzoo_level.txt | 10 +- .../cv/tracking/SiamFC/prepostprocess.py | 316 +- .../contrib/cv/tracking/SiamFC/pth2onnx.py | 236 +- .../cv/tracking/SiamFC/requirements.txt | 14 +- .../contrib/cv/tracking/SiamFC/test/parse.py | 50 +- .../cv/tracking/SiamFC/wholeprocess.py | 852 +-- .../contrib/cv/tracking/SiamRPN/LICENSE | 402 +- .../contrib/cv/tracking/SiamRPN/README.md | 194 +- .../contrib/cv/tracking/SiamRPN/acl_net.py | 478 +- .../cv/tracking/SiamRPN/modelzoo_level.txt | 4 +- .../cv/video_understanding/I3D/acl_net.py | 490 +- .../video_understanding/I3D/i3d_inference.py | 406 +- .../cv/video_understanding/TSN/LICENSE | 400 +- .../cv/video_understanding/TSN/README.md | 192 +- .../TSN/modelzoo_level.txt | 4 +- .../video_understanding/TSN/pytorch2onnx.py | 384 +- .../video_understanding/TSN/requirements.txt | 22 +- .../TSN/test/eval_acc_perf.sh | 146 +- .../cv/video_understanding/TSN/test/parse.py | 72 +- .../video_understanding/TSN/test/perf_gpu.sh | 60 +- .../cv/video_understanding/TSN/test/pth2om.sh | 24 +- .../TSN/tsn_ucf101_postprocess.py | 116 +- ACL_PyTorch/contrib/knowledge/RotatE/LICENSE | 406 +- .../contrib/knowledge/RotatE/ReadME.md | 82 +- .../contrib/knowledge/RotatE/get_info.py | 64 +- .../knowledge/RotatE/modelzoo_level.txt | 4 +- .../contrib/knowledge/RotatE/requirements.txt | 8 +- .../knowledge/RotatE/rotate_postprocess.py | 242 +- .../knowledge/RotatE/rotate_preprocess.py | 454 +- .../knowledge/RotatE/rotate_pth2onnx.py | 144 +- .../contrib/nlp/BertSum/BertSum-pth2onnx.py | 236 +- .../nlp/BertSum/BertSum_pth_postprocess.py | 548 +- .../nlp/BertSum/BertSum_pth_preprocess.py | 356 +- ACL_PyTorch/contrib/nlp/BertSum/README.md | 568 +- .../contrib/nlp/BertSum/modelzoo_level.txt | 10 +- .../contrib/nlp/BertSum/requirements.txt | 10 +- ACL_PyTorch/contrib/nlp/TextCNN/LICENSE | 402 +- ACL_PyTorch/contrib/nlp/TextCNN/TextCNN.patch | 1292 ++-- .../contrib/nlp/albert/0001-init.patch | 1506 ++--- .../contrib/nlp/tinybert/TinyBERT_get_info.py | 92 +- .../nlp/tinybert/TinyBERT_postprocess_data.py | 556 +- .../nlp/tinybert/TinyBERT_preprocess_data.py | 550 +- .../contrib/nlp/tinybert/modelzoo_level.txt | 10 +- ACL_PyTorch/contrib/nlp/tinybert/pth2onnx.py | 168 +- ACL_PyTorch/contrib/rl/DQN/env.sh | 14 +- ACL_PyTorch/contrib/rl/DQN/modelzoo_level.txt | 6 +- ACL_PyTorch/contrib/rl/DQN/test/parse.py | 68 +- .../test/train_full_8p.sh | 400 +- .../test/train_performance_8p.sh | 360 +- .../CRNN_for_PyTorch/modelzoo_level.txt | 4 +- .../DeepMar_for_PyTorch/test/train_full_1p.sh | 328 +- .../test/train_performance_1p.sh | 322 +- .../test/train_performance_8p.sh | 348 +- .../convert/densenet121_pt_aipp.config | 32 +- .../sdk_infer/mxbase_infer/CMakeLists.txt | 98 +- .../mxbase_infer/Densenet121Classify.cpp | 512 +- .../mxbase_infer/Densenet121Classify.h | 112 +- .../sdk_infer/mxbase_infer/main.cpp | 138 +- .../utils/classification_task_metric.py | 374 +- .../test/train_full_1p.sh | 304 +- .../test/train_full_8p.sh | 334 +- .../test/train_performance_1p.sh | 302 +- .../test/train_performance_8p.sh | 342 +- .../EfficientNet_for_PyTorch/LICENSE | 404 +- .../efficientnet_pytorch/__init__.py | 456 +- .../efficientnet_pytorch/auto_augment.py | 1624 ++--- .../efficientnet_pytorch/model.py | 852 +-- .../efficientnet_pytorch/rmsprop_tf.py | 270 +- .../efficientnet_pytorch/utils.py | 1272 ++-- .../examples/imagenet/README.md | 46 +- .../examples/imagenet/data/README.md | 10 +- .../examples/imagenet/main.py | 1090 +-- .../EfficientNet_for_PyTorch/hubconf.py | 116 +- .../EfficientNet_for_PyTorch/pthtar2onnx.py | 124 +- .../EfficientNet_for_PyTorch/run_to_onnx.sh | 6 +- .../EfficientNet_for_PyTorch/setup.py | 276 +- .../test/train_full_8p.sh | 346 +- .../test/train_performance_1p.sh | 318 +- .../test/train_performance_8p.sh | 344 +- .../tests/test_model.py | 278 +- .../test/train_full_1p.sh | 314 +- .../test/train_full_8p.sh | 312 +- .../test/train_performance_1p.sh | 326 +- .../infer/mxbase/CMakeLists.txt | 96 +- .../infer/mxbase/Resnet50Classify.cpp | 520 +- .../infer/mxbase/Resnet50Classify.h | 116 +- .../mxbase/classification_task_metric.py | 348 +- .../infer/mxbase/main.cpp | 136 +- .../infer/sdk/classification_task_metric.py | 350 +- .../modelarts/train_start.py | 1376 ++-- .../test/train_performance_1p.sh | 356 +- .../test/train_performance_8p.sh | 350 +- .../Faster_Mask_RCNN_for_PyTorch/LICENSE | 0 .../configs/Base-RCNN-C4.yaml | 0 .../configs/Base-RCNN-DilatedC5.yaml | 0 .../configs/Base-RCNN-FPN.yaml | 0 .../configs/Base-RetinaNet.yaml | 0 .../COCO-Detection/fast_rcnn_R_50_FPN_1x.yaml | 0 .../faster_rcnn_R_101_C4_3x.yaml | 0 .../faster_rcnn_R_101_DC5_3x.yaml | 0 .../faster_rcnn_R_101_FPN_3x.yaml | 0 .../faster_rcnn_R_50_C4_1x.yaml | 0 .../faster_rcnn_R_50_C4_3x.yaml | 0 .../faster_rcnn_R_50_DC5_1x.yaml | 0 .../faster_rcnn_R_50_DC5_3x.yaml | 0 .../faster_rcnn_R_50_FPN_1x.yaml | 0 .../faster_rcnn_R_50_FPN_3x.yaml | 0 .../faster_rcnn_X_101_32x8d_FPN_3x.yaml | 0 .../retinanet_R_101_FPN_3x.yaml | 0 .../COCO-Detection/retinanet_R_50_FPN_1x.yaml | 0 .../COCO-Detection/retinanet_R_50_FPN_3x.yaml | 0 .../COCO-Detection/rpn_R_50_C4_1x.yaml | 0 .../COCO-Detection/rpn_R_50_FPN_1x.yaml | 0 .../mask_rcnn_R_101_C4_3x.yaml | 0 .../mask_rcnn_R_101_DC5_3x.yaml | 0 .../mask_rcnn_R_101_FPN_3x.yaml | 0 .../mask_rcnn_R_50_C4_1x.yaml | 0 .../mask_rcnn_R_50_C4_3x.yaml | 0 .../mask_rcnn_R_50_DC5_1x.yaml | 0 .../mask_rcnn_R_50_DC5_3x.yaml | 0 .../mask_rcnn_R_50_FPN_1x.yaml | 0 .../mask_rcnn_R_50_FPN_1x_giou.yaml | 0 .../mask_rcnn_R_50_FPN_3x.yaml | 0 .../mask_rcnn_X_101_32x8d_FPN_3x.yaml | 0 .../Base-Keypoint-RCNN-FPN.yaml | 0 .../keypoint_rcnn_R_101_FPN_3x.yaml | 0 .../keypoint_rcnn_R_50_FPN_1x.yaml | 0 .../keypoint_rcnn_R_50_FPN_3x.yaml | 0 .../keypoint_rcnn_X_101_32x8d_FPN_3x.yaml | 0 .../Base-Panoptic-FPN.yaml | 0 .../panoptic_fpn_R_101_3x.yaml | 0 .../panoptic_fpn_R_50_1x.yaml | 0 .../panoptic_fpn_R_50_3x.yaml | 0 .../Cityscapes/mask_rcnn_R_50_FPN.yaml | 0 .../configs/Detectron1-Comparisons/README.md | 0 .../faster_rcnn_R_50_FPN_noaug_1x.yaml | 0 .../keypoint_rcnn_R_50_FPN_1x.yaml | 0 .../mask_rcnn_R_50_FPN_noaug_1x.yaml | 0 .../mask_rcnn_R_101_FPN_1x.yaml | 0 .../mask_rcnn_R_50_FPN_1x.yaml | 0 .../mask_rcnn_X_101_32x8d_FPN_1x.yaml | 0 .../mask_rcnn_R_101_FPN_1x.yaml | 0 .../mask_rcnn_R_50_FPN_1x.yaml | 0 .../mask_rcnn_X_101_32x8d_FPN_1x.yaml | 0 .../Misc/cascade_mask_rcnn_R_50_FPN_1x.yaml | 0 .../Misc/cascade_mask_rcnn_R_50_FPN_3x.yaml | 0 ...sk_rcnn_X_152_32x8d_FPN_IN5k_gn_dconv.yaml | 0 .../mask_rcnn_R_50_FPN_1x_cls_agnostic.yaml | 0 .../mask_rcnn_R_50_FPN_1x_dconv_c3-c5.yaml | 0 .../mask_rcnn_R_50_FPN_3x_dconv_c3-c5.yaml | 0 .../Misc/mask_rcnn_R_50_FPN_3x_gn.yaml | 0 .../Misc/mask_rcnn_R_50_FPN_3x_syncbn.yaml | 0 ...anoptic_fpn_R_101_dconv_cascade_gn_3x.yaml | 0 .../scratch_mask_rcnn_R_50_FPN_3x_gn.yaml | 0 .../scratch_mask_rcnn_R_50_FPN_9x_gn.yaml | 0 .../scratch_mask_rcnn_R_50_FPN_9x_syncbn.yaml | 0 .../configs/Misc/semantic_R_50_FPN_1x.yaml | 0 .../faster_rcnn_R_50_C4.yaml | 0 .../faster_rcnn_R_50_FPN.yaml | 0 .../configs/quick_schedules/README.md | 0 ...mask_rcnn_R_50_FPN_inference_acc_test.yaml | 0 ...scade_mask_rcnn_R_50_FPN_instant_test.yaml | 0 ...fast_rcnn_R_50_FPN_inference_acc_test.yaml | 0 .../fast_rcnn_R_50_FPN_instant_test.yaml | 0 ...oint_rcnn_R_50_FPN_inference_acc_test.yaml | 0 .../keypoint_rcnn_R_50_FPN_instant_test.yaml | 0 ...R_50_FPN_normalized_training_acc_test.yaml | 0 ...point_rcnn_R_50_FPN_training_acc_test.yaml | 0 .../mask_rcnn_R_50_C4_GCV_instant_test.yaml | 0 .../mask_rcnn_R_50_C4_inference_acc_test.yaml | 0 .../mask_rcnn_R_50_C4_instant_test.yaml | 0 .../mask_rcnn_R_50_C4_training_acc_test.yaml | 0 ...mask_rcnn_R_50_DC5_inference_acc_test.yaml | 0 ...mask_rcnn_R_50_FPN_inference_acc_test.yaml | 0 .../mask_rcnn_R_50_FPN_instant_test.yaml | 0 ...R_50_FPN_pred_boxes_training_acc_test.yaml | 0 .../mask_rcnn_R_50_FPN_training_acc_test.yaml | 0 .../panoptic_fpn_R_50_inference_acc_test.yaml | 0 .../panoptic_fpn_R_50_instant_test.yaml | 0 .../panoptic_fpn_R_50_training_acc_test.yaml | 0 ...retinanet_R_50_FPN_inference_acc_test.yaml | 0 .../retinanet_R_50_FPN_instant_test.yaml | 0 .../rpn_R_50_FPN_inference_acc_test.yaml | 0 .../rpn_R_50_FPN_instant_test.yaml | 0 .../semantic_R_50_FPN_inference_acc_test.yaml | 0 .../semantic_R_50_FPN_instant_test.yaml | 0 .../semantic_R_50_FPN_training_acc_test.yaml | 0 .../datasets/README.md | 0 .../datasets/prepare_cocofied_lvis.py | 0 .../datasets/prepare_for_tests.sh | 0 .../datasets/prepare_panoptic_fpn.py | 0 .../demo/README.md | 0 .../Faster_Mask_RCNN_for_PyTorch/demo/demo.py | 0 .../demo/predictor.py | 0 .../detectron2/__init__.py | 0 .../detectron2/checkpoint/__init__.py | 0 .../detectron2/checkpoint/c2_model_loading.py | 0 .../detectron2/checkpoint/catalog.py | 0 .../checkpoint/detection_checkpoint.py | 0 .../detectron2/config/__init__.py | 0 .../detectron2/config/compat.py | 0 .../detectron2/config/config.py | 0 .../detectron2/config/defaults.py | 0 .../detectron2/data/__init__.py | 0 .../detectron2/data/build.py | 0 .../detectron2/data/catalog.py | 0 .../detectron2/data/common.py | 0 .../detectron2/data/dataset_mapper.py | 0 .../detectron2/data/datasets/README.md | 0 .../detectron2/data/datasets/__init__.py | 0 .../detectron2/data/datasets/builtin.py | 0 .../detectron2/data/datasets/builtin_meta.py | 0 .../detectron2/data/datasets/cityscapes.py | 0 .../detectron2/data/datasets/coco.py | 0 .../detectron2/data/datasets/lvis.py | 0 .../data/datasets/lvis_v0_5_categories.py | 0 .../data/datasets/lvis_v1_categories.py | 0 .../detectron2/data/datasets/pascal_voc.py | 0 .../detectron2/data/datasets/register_coco.py | 0 .../detectron2/data/detection_utils.py | 0 .../detectron2/data/samplers/__init__.py | 0 .../data/samplers/distributed_sampler.py | 0 .../data/samplers/grouped_batch_sampler.py | 0 .../detectron2/data/transforms/__init__.py | 0 .../data/transforms/augmentation.py | 0 .../data/transforms/augmentation_impl.py | 0 .../detectron2/data/transforms/transform.py | 0 .../detectron2/engine/__init__.py | 0 .../detectron2/engine/defaults.py | 0 .../detectron2/engine/hooks.py | 0 .../detectron2/engine/launch.py | 0 .../detectron2/engine/train_loop.py | 0 .../detectron2/evaluation/__init__.py | 0 .../evaluation/cityscapes_evaluation.py | 0 .../detectron2/evaluation/coco_evaluation.py | 0 .../detectron2/evaluation/evaluator.py | 0 .../detectron2/evaluation/fast_eval_api.py | 0 .../detectron2/evaluation/lvis_evaluation.py | 0 .../evaluation/panoptic_evaluation.py | 0 .../evaluation/pascal_voc_evaluation.py | 0 .../evaluation/rotated_coco_evaluation.py | 0 .../evaluation/sem_seg_evaluation.py | 0 .../detectron2/evaluation/testing.py | 0 .../detectron2/export/README.md | 0 .../detectron2/export/__init__.py | 0 .../detectron2/export/api.py | 0 .../detectron2/export/c10.py | 0 .../detectron2/export/caffe2_export.py | 0 .../detectron2/export/caffe2_inference.py | 0 .../detectron2/export/caffe2_modeling.py | 0 .../detectron2/export/patcher.py | 0 .../detectron2/export/shared.py | 0 .../detectron2/export/torchscript.py | 0 .../detectron2/layers/__init__.py | 0 .../detectron2/layers/aspp.py | 0 .../detectron2/layers/batch_norm.py | 0 .../detectron2/layers/blocks.py | 0 .../detectron2/layers/csrc/README.md | 0 .../layers/csrc/ROIAlign/ROIAlign.h | 0 .../layers/csrc/ROIAlign/ROIAlign_cpu.cpp | 0 .../layers/csrc/ROIAlign/ROIAlign_cuda.cu | 0 .../csrc/ROIAlignRotated/ROIAlignRotated.h | 0 .../ROIAlignRotated/ROIAlignRotated_cpu.cpp | 0 .../ROIAlignRotated/ROIAlignRotated_cuda.cu | 0 .../csrc/box_iou_rotated/box_iou_rotated.h | 0 .../box_iou_rotated/box_iou_rotated_cpu.cpp | 0 .../box_iou_rotated/box_iou_rotated_cuda.cu | 0 .../box_iou_rotated/box_iou_rotated_utils.h | 0 .../layers/csrc/cocoeval/cocoeval.cpp | 0 .../layers/csrc/cocoeval/cocoeval.h | 0 .../detectron2/layers/csrc/cuda_version.cu | 0 .../layers/csrc/deformable/deform_conv.h | 0 .../csrc/deformable/deform_conv_cuda.cu | 0 .../deformable/deform_conv_cuda_kernel.cu | 0 .../layers/csrc/nms_rotated/nms_rotated.h | 0 .../csrc/nms_rotated/nms_rotated_cpu.cpp | 0 .../csrc/nms_rotated/nms_rotated_cuda.cu | 0 .../detectron2/layers/csrc/vision.cpp | 0 .../detectron2/layers/deform_conv.py | 0 .../detectron2/layers/mask_ops.py | 0 .../detectron2/layers/nms.py | 0 .../detectron2/layers/roi_align.py | 0 .../detectron2/layers/roi_align_rotated.py | 0 .../detectron2/layers/rotated_boxes.py | 0 .../detectron2/layers/shape_spec.py | 0 .../detectron2/layers/wrappers.py | 0 .../detectron2/model_zoo/__init__.py | 0 .../detectron2/model_zoo/model_zoo.py | 0 .../detectron2/modeling/__init__.py | 0 .../detectron2/modeling/anchor_generator.py | 0 .../detectron2/modeling/backbone/__init__.py | 0 .../detectron2/modeling/backbone/backbone.py | 0 .../detectron2/modeling/backbone/build.py | 0 .../detectron2/modeling/backbone/fpn.py | 0 .../detectron2/modeling/backbone/resnet.py | 0 .../detectron2/modeling/box_regression.py | 0 .../detectron2/modeling/matcher.py | 0 .../detectron2/modeling/meta_arch/__init__.py | 0 .../detectron2/modeling/meta_arch/build.py | 0 .../modeling/meta_arch/panoptic_fpn.py | 0 .../detectron2/modeling/meta_arch/rcnn.py | 0 .../modeling/meta_arch/retinanet.py | 0 .../modeling/meta_arch/semantic_seg.py | 0 .../detectron2/modeling/poolers.py | 0 .../detectron2/modeling/postprocessing.py | 0 .../modeling/proposal_generator/__init__.py | 0 .../modeling/proposal_generator/build.py | 0 .../proposal_generator/proposal_utils.py | 0 .../modeling/proposal_generator/rpn.py | 0 .../modeling/proposal_generator/rrpn.py | 0 .../detectron2/modeling/roi_heads/__init__.py | 0 .../detectron2/modeling/roi_heads/box_head.py | 0 .../modeling/roi_heads/cascade_rcnn.py | 0 .../modeling/roi_heads/fast_rcnn.py | 0 .../modeling/roi_heads/keypoint_head.py | 0 .../modeling/roi_heads/mask_head.py | 0 .../modeling/roi_heads/roi_heads.py | 0 .../modeling/roi_heads/rotated_fast_rcnn.py | 0 .../detectron2/modeling/sampling.py | 0 .../modeling/test_time_augmentation.py | 0 .../detectron2/solver/__init__.py | 0 .../detectron2/solver/build.py | 0 .../detectron2/solver/lr_scheduler.py | 0 .../detectron2/structures/__init__.py | 0 .../detectron2/structures/boxes.py | 0 .../detectron2/structures/image_list.py | 0 .../detectron2/structures/instances.py | 0 .../detectron2/structures/keypoints.py | 0 .../detectron2/structures/masks.py | 884 +-- .../detectron2/structures/rotated_boxes.py | 0 .../detectron2/utils/README.md | 0 .../detectron2/utils/__init__.py | 0 .../detectron2/utils/analysis.py | 0 .../detectron2/utils/collect_env.py | 0 .../detectron2/utils/colormap.py | 0 .../detectron2/utils/comm.py | 0 .../detectron2/utils/env.py | 0 .../detectron2/utils/events.py | 0 .../detectron2/utils/logger.py | 0 .../detectron2/utils/memory.py | 0 .../detectron2/utils/registry.py | 0 .../detectron2/utils/serialize.py | 0 .../detectron2/utils/video_visualizer.py | 0 .../detectron2/utils/visualizer.py | 0 .../dev/README.md | 0 .../dev/linter.sh | 0 .../dev/packaging/README.md | 0 .../dev/packaging/build_all_wheels.sh | 0 .../dev/packaging/build_wheel.sh | 0 .../dev/packaging/gen_install_table.py | 0 .../dev/packaging/gen_wheel_index.sh | 0 .../dev/packaging/pkg_helpers.bash | 0 .../dev/parse_results.sh | 0 .../dev/run_inference_tests.sh | 0 .../dev/run_instant_tests.sh | 0 .../docker/Dockerfile | 0 .../docker/Dockerfile-circleci | 0 .../docker/README.md | 0 .../docker/docker-compose.yml | 0 .../docs/.gitignore | 0 .../docs/Makefile | 0 .../docs/README.md | 0 .../docs/_static/css/custom.css | 0 .../Faster_Mask_RCNN_for_PyTorch/docs/conf.py | 0 .../docs/notes/benchmarks.md | 0 .../docs/notes/changelog.md | 0 .../docs/notes/compatibility.md | 0 .../docs/notes/contributing.md | 0 .../docs/tutorials/README.md | 0 .../docs/tutorials/builtin_datasets.md | 0 .../docs/tutorials/configs.md | 0 .../docs/tutorials/data_loading.md | 0 .../docs/tutorials/datasets.md | 0 .../docs/tutorials/deployment.md | 0 .../docs/tutorials/evaluation.md | 0 .../docs/tutorials/extend.md | 0 .../docs/tutorials/getting_started.md | 0 .../docs/tutorials/install.md | 0 .../docs/tutorials/models.md | 0 .../docs/tutorials/training.md | 0 .../docs/tutorials/write-models.md | 0 .../Faster_Mask_RCNN_for_PyTorch/eval.sh | 0 .../Faster_Mask_RCNN_for_PyTorch/run.sh | 0 .../Faster_Mask_RCNN_for_PyTorch/run8p.sh | 0 .../run8p_for_faster_rcnn.sh | 0 .../run_for_faster_rcnn.sh | 0 .../Faster_Mask_RCNN_for_PyTorch/setup.cfg | 0 .../Faster_Mask_RCNN_for_PyTorch/setup.py | 0 .../test/train_full_1p.sh | 362 +- .../test/train_performance_1p.sh | 340 +- .../test/train_performance_8p.sh | 338 +- .../tests/README.md | 0 .../tests/__init__.py | 0 .../tests/data/__init__.py | 0 .../tests/data/test_coco.py | 0 .../tests/data/test_coco_evaluation.py | 0 .../tests/data/test_detection_utils.py | 0 .../tests/data/test_rotation_transform.py | 0 .../tests/data/test_sampler.py | 0 .../tests/data/test_transforms.py | 0 .../tests/layers/__init__.py | 0 .../tests/layers/test_mask_ops.py | 0 .../tests/layers/test_nms.py | 0 .../tests/layers/test_nms_rotated.py | 0 .../tests/layers/test_roi_align.py | 0 .../tests/layers/test_roi_align_rotated.py | 0 .../tests/modeling/__init__.py | 0 .../tests/modeling/test_anchor_generator.py | 0 .../tests/modeling/test_box2box_transform.py | 0 .../tests/modeling/test_fast_rcnn.py | 0 .../tests/modeling/test_matcher.py | 0 .../tests/modeling/test_model_e2e.py | 0 .../tests/modeling/test_roi_heads.py | 0 .../tests/modeling/test_roi_pooler.py | 0 .../tests/modeling/test_rpn.py | 0 .../tests/structures/__init__.py | 0 .../tests/structures/test_boxes.py | 0 .../tests/structures/test_imagelist.py | 0 .../tests/structures/test_instances.py | 0 .../tests/structures/test_rotated_boxes.py | 0 .../tests/test_checkpoint.py | 0 .../tests/test_config.py | 0 .../tests/test_engine.py | 0 .../tests/test_export_caffe2.py | 0 .../tests/test_model_analysis.py | 0 .../tests/test_model_zoo.py | 0 .../tests/test_visualizer.py | 0 .../tools/README.md | 0 .../tools/analyze_model.py | 0 .../tools/benchmark.py | 0 .../tools/convert-torchvision-to-d2.py | 0 .../tools/plain_train_net.py | 0 .../tools/train_net.py | 0 .../tools/visualize_data.py | 0 .../tools/visualize_json_results.py | 0 .../cv/detection/PSENet_for_PyTorch/LICENSE | 56 +- .../PSENet_for_PyTorch/NPU/src/README.md | 122 +- .../NPU/src/requirements.txt | 4 +- .../PSENet_for_PyTorch/NPU/src/train_ic15.py | 898 +-- .../NPU/src/train_ic15_8p.py | 906 +-- .../cv/detection/PSENet_for_PyTorch/README.md | 44 +- .../PSENet_for_PyTorch/test/train_full_1p.sh | 320 +- .../PSENet_for_PyTorch/test/train_full_8p.sh | 316 +- .../test/train_performance_1p.sh | 320 +- .../test/train_performance_8p.sh | 316 +- .../mmcv_need/_functions.py | 184 +- .../mmcv_need/builder.py | 136 +- .../mmcv_need/data_parallel.py | 208 +- .../mmcv_need/dist_utils.py | 368 +- .../mmcv_need/distributed.py | 238 +- .../mmcv_need/optimizer.py | 324 +- .../RetinaNet_for_PyTorch/modelzoo_level.txt | 4 +- .../test/train_performance_8p.sh | 360 +- .../test/train_retinanet_1p.sh | 56 +- .../test/train_retinanet_8p.sh | 92 +- .../tools/dist_test.sh | 0 .../AttU_Net_for_PyTorch/pthtar2onx.py | 110 +- .../AttU_Net_for_PyTorch/run_to_onnx.sh | 6 +- .../Attention_R2U_Net_for_PyTorch/LICENSE | 56 +- .../Attention_R2U_Net_for_PyTorch/README.md | 78 +- .../data_loader.py | 292 +- .../Attention_R2U_Net_for_PyTorch/dataset.py | 282 +- .../evaluation.py | 210 +- .../Attention_R2U_Net_for_PyTorch/main_1p.py | 268 +- .../Attention_R2U_Net_for_PyTorch/main_8p.py | 220 +- .../Attention_R2U_Net_for_PyTorch/misc.py | 98 +- .../modelzoo_level.txt | 4 +- .../Attention_R2U_Net_for_PyTorch/network.py | 912 +-- .../pthtar2onx.py | 110 +- .../solver_1p.py | 710 +- .../solver_8p.py | 432 +- .../Attention_R2U_Net_for_PyTorch/train.py | 668 +- .../Attention_R2U_Net_for_PyTorch/train_1p.sh | 4 +- .../Attention_R2U_Net_for_PyTorch/train_8p.sh | 4 +- .../Attention_R2U_Net_for_PyTorch/utils.py | 524 +- .../R2U_Net_for_PyTorch/LICENSE | 56 +- .../R2U_Net_for_PyTorch/evaluation.py | 230 +- .../R2U_Net_for_PyTorch/modelzoo_level.txt | 4 +- .../R2U_Net_for_PyTorch/run_to_onnx.sh | 6 +- .../R2U_Net_for_PyTorch/utils.py | 524 +- .../bert_base_config.json | 24 +- .../test/run_squad.py | 2564 +++---- .../test/train_performance_bert_8p.sh | 376 +- .../bpe_3w_new/readme.md | 2 +- .../CPM_Finetune_for_PyTorch/test/eval_1p.sh | 230 +- .../nlp/GRU_for_PyTorch/test/train_full_8p.sh | 354 +- .../test/train_performance_1p.sh | 294 +- .../test/train_performance_8p.sh | 362 +- .../nlp/Transformer_for_PyTorch/LICENSE | 62 +- .../nlp/Transformer_for_PyTorch/PATENTS | 64 +- .../nlp/Transformer_for_PyTorch/README.md | 168 +- .../Transformer_for_PyTorch/docker_start.sh | 50 +- .../modelzoo_level.txt | 4 +- .../modules/multihead_attention.py | 750 +- .../optim/combined_adam_v3.py | 512 +- .../nlp/Transformer_for_PyTorch/preprocess.py | 400 +- .../test/train_full_1p.sh | 432 +- .../test/train_performance_1p.sh | 430 +- .../test/set_conda.sh | 2 +- .../built-in/others/WDL_for_PyTorch/LICENSE | 402 +- .../WDL_for_PyTorch/criteo_preprocess.py | 108 +- .../others/WDL_for_PyTorch/infer/Dockerfile | 60 +- .../WDL_for_PyTorch/infer/requirements.txt | 6 +- .../others/WDL_for_PyTorch/modelzoo_level.txt | 4 +- .../others/WDL_for_PyTorch/requirements.txt | 6 +- .../run_classification_criteo_wdl.py | 282 +- PyTorch/contrib/CONTRIBUTING.md | 628 +- .../FastPitch/fastpitch/loss_function.py | 216 +- .../contrib/audio/baseline-rawnet/README.md | 256 +- .../audio/baseline-rawnet/modelzoo_level.txt | 4 +- .../audio/baseline-rawnet/requirements.txt | 16 +- PyTorch/contrib/audio/deepspeech/README.md | 178 +- PyTorch/contrib/audio/tdnn/README.md | 286 +- PyTorch/contrib/audio/tdnn/modelzoo_level.txt | 4 +- .../speechbrain/lobes/models/MetricGAN.py | 344 +- .../tdnn/speechbrain/nnet/loss/stoi_loss.py | 390 +- .../speaker_id/mini_librispeech_prepare.py | 412 +- .../templates/speaker_id/modelzoo_level.txt | 10 +- .../speaker_id/test/train_full_8p.sh | 318 +- .../speaker_id/test/train_performance_8p.sh | 308 +- .../classification/3d_attention_net/train.py | 472 +- .../AlignedReID/modelzoo_level.txt | 6 +- .../cv/classification/Deit_Small/mixup.py | 660 +- .../Deit_Small/npu_fused_adamw.py | 514 +- PyTorch/contrib/cv/classification/DnCNN/.keep | 0 .../cv/classification/DnCNN/Dockerfile | 0 .../contrib/cv/classification/DnCNN/README.md | 0 .../cv/classification/DnCNN/dataset.py | 0 .../contrib/cv/classification/DnCNN/demo.py | 0 .../cv/classification/DnCNN/docker_start.sh | 0 .../cv/classification/DnCNN/evalOnePic.py | 0 .../contrib/cv/classification/DnCNN/models.py | 0 .../classification/DnCNN/modelzoo_level.txt | 0 .../cv/classification/DnCNN/pth2onnx.py | 0 .../cv/classification/DnCNN/requirements.txt | 0 .../cv/classification/DnCNN/scripts/demo.sh | 0 .../cv/classification/DnCNN/scripts/eval.sh | 0 .../classification/DnCNN/scripts/pth2onnx.sh | 0 .../DnCNN/scripts/set_npu_env.sh | 0 .../classification/DnCNN/scripts/train_1p.sh | 0 .../classification/DnCNN/scripts/train_8p.sh | 0 .../cv/classification/DnCNN/test/demo.sh | 0 .../cv/classification/DnCNN/test/pth2onnx.sh | 0 .../DnCNN/test/train_eval_8p.sh | 0 .../DnCNN/test/train_full_1p.sh | 0 .../DnCNN/test/train_full_8p.sh | 0 .../DnCNN/test/train_performance_1p.sh | 0 .../DnCNN/test/train_performance_8p.sh | 0 .../cv/classification/DnCNN/train_1p.py | 0 .../cv/classification/DnCNN/train_8p.py | 0 .../contrib/cv/classification/DnCNN/utils.py | 0 .../modelzoo_level.txt | 4 +- .../EfficientNet-B1/ImageNet_val_split.py | 120 +- .../classification/EfficientNet-B1/README.md | 158 +- .../archive/cifar/anynet/R-110_nds_1gpu.yaml | 72 +- .../archive/cifar/anynet/R-56_nds_1gpu.yaml | 72 +- .../archive/cifar/anynet/V-56_nds_1gpu.yaml | 72 +- .../archive/cifar/resnet/R-110_nds_1gpu.yaml | 64 +- .../archive/cifar/resnet/R-56_nds_1gpu.yaml | 64 +- .../anynet/R-101-1x64d_step_1gpu.yaml | 78 +- .../anynet/R-101-1x64d_step_2gpu.yaml | 78 +- .../anynet/R-101-1x64d_step_8gpu.yaml | 78 +- .../imagenet/anynet/R-50-1x64d_step_1gpu.yaml | 78 +- .../imagenet/anynet/R-50-1x64d_step_2gpu.yaml | 78 +- .../imagenet/anynet/R-50-1x64d_step_8gpu.yaml | 78 +- .../anynet/X-101-32x4d_step_1gpu.yaml | 78 +- .../anynet/X-101-32x4d_step_2gpu.yaml | 78 +- .../anynet/X-101-32x4d_step_8gpu.yaml | 78 +- .../imagenet/anynet/X-50-32x4d_step_1gpu.yaml | 78 +- .../imagenet/anynet/X-50-32x4d_step_2gpu.yaml | 78 +- .../imagenet/anynet/X-50-32x4d_step_8gpu.yaml | 78 +- .../resnet/R-101-1x64d_step_1gpu.yaml | 72 +- .../resnet/R-101-1x64d_step_2gpu.yaml | 72 +- .../resnet/R-101-1x64d_step_8gpu.yaml | 72 +- .../imagenet/resnet/R-50-1x64d_step_1gpu.yaml | 72 +- .../imagenet/resnet/R-50-1x64d_step_2gpu.yaml | 72 +- .../imagenet/resnet/R-50-1x64d_step_8gpu.yaml | 72 +- .../resnet/X-101-32x4d_step_1gpu.yaml | 72 +- .../resnet/X-101-32x4d_step_2gpu.yaml | 72 +- .../resnet/X-101-32x4d_step_8gpu.yaml | 72 +- .../imagenet/resnet/X-50-32x4d_step_1gpu.yaml | 72 +- .../imagenet/resnet/X-50-32x4d_step_2gpu.yaml | 72 +- .../imagenet/resnet/X-50-32x4d_step_8gpu.yaml | 72 +- .../effnet/EN-B1_dds_1npu_full.yaml | 54 +- .../effnet/EN-B1_dds_1npu_perf.yaml | 54 +- .../effnet/EN-B1_dds_8npu_full.yaml | 54 +- .../effnet/EN-B1_dds_8npu_perf.yaml | 54 +- .../cv/classification/EfficientNet-B1/demo.py | 126 +- .../EfficientNet-B1/pycls/core/benchmark.py | 334 +- .../EfficientNet-B1/pycls/core/builders.py | 136 +- .../EfficientNet-B1/pycls/core/distributed.py | 372 +- .../EfficientNet-B1/pycls/core/env.py | 112 +- .../EfficientNet-B1/pycls/core/io.py | 186 +- .../EfficientNet-B1/pycls/core/logging.py | 306 +- .../EfficientNet-B1/pycls/core/plotting.py | 292 +- .../EfficientNet-B1/pycls/core/sgd.py | 424 +- .../EfficientNet-B1/pycls/core/timer.py | 106 +- .../EfficientNet-B1/pycls/datasets/augment.py | 496 +- .../EfficientNet-B1/pycls/datasets/cifar10.py | 190 +- .../pycls/datasets/imagenet.py | 232 +- .../EfficientNet-B1/pycls/datasets/loader.py | 192 +- .../pycls/datasets/transforms.py | 188 +- .../EfficientNet-B1/pycls/models/__init__.py | 20 +- .../EfficientNet-B1/pycls/models/anynet.py | 750 +- .../EfficientNet-B1/pycls/models/blocks.py | 402 +- .../EfficientNet-B1/pycls/models/effnet.py | 422 +- .../EfficientNet-B1/pycls/models/model_zoo.py | 392 +- .../EfficientNet-B1/pycls/models/regnet.py | 166 +- .../EfficientNet-B1/pycls/models/resnet.py | 602 +- .../EfficientNet-B1/tools/test_net.py | 80 +- .../EfficientNet-B1/tools/time_net.py | 78 +- .../EfficientNet-B1/tools/train_net.py | 212 +- .../EfficientNet-B3/modelzoo_level.txt | 4 +- .../modelasrts/config.py | 858 +-- .../modelasrts/loader.py | 196 +- .../modelasrts/train_net.py | 212 +- .../modelasrts/trainer.py | 610 +- .../classification/GENet_for_Pytorch/LICENSE | 400 +- .../GENet_for_Pytorch/README.md | 116 +- .../GENet_for_Pytorch/modelzoo_level.txt | 12 +- .../cv/classification/GhostNet/LICENSE | 56 +- .../ghostnet/ghostnet_pytorch/ghostnet.py | 518 +- .../GhostNet/modelarts/train_start.py | 1556 ++--- .../cv/classification/GhostNet/pthtar2onx.py | 94 +- .../classification/GhostNet/requirements.txt | 6 +- .../cv/classification/GhostNet/setup.cfg | 10 +- .../cv/classification/GhostNet/setup.py | 96 +- .../GhostNet/timm/loss/asymmetric_loss.py | 194 +- .../modelzoo_level.txt | 4 +- .../infer/README.md | 762 +-- .../infer/sdk/classification_task_metric.py | 376 +- .../contrib/cv/classification/MGN/README.md | 116 +- .../MnasNet/infer/convert/aipp.aipconfig | 0 .../MnasNet/infer/convert/onnx2om.sh | 0 .../MnasNet/infer/mxbase/CMakeLists.txt | 0 .../MnasNet/infer/mxbase/Mnasnet.cpp | 0 .../MnasNet/infer/mxbase/Mnasnet.h | 0 .../MnasNet/infer/mxbase/build.sh | 0 .../MnasNet/infer/mxbase/main.cpp | 0 .../MnasNet/infer/mxbase/run.sh | 0 .../classification/MnasNet/infer/sdk/main.py | 0 .../MnasNet/infer/sdk/mnasnet_aipp.cfg | 0 .../MnasNet/infer/sdk/mnasnet_opencv.pipeline | 0 .../classification/MnasNet/infer/sdk/run.sh | 0 .../infer/util/classification_task_metric.py | 372 +- .../MnasNet/modelArts/pth2onnx.py | 194 +- .../MnasNet/modelArts/train-modelarts.py | 1470 ++-- .../cv/classification/MobileNet/Dockerfile | 0 .../cv/classification/MobileNet/LICENSE | 0 .../cv/classification/MobileNet/README.md | 0 .../cv/classification/MobileNet/demo.py | 0 .../classification/MobileNet/docker_start.sh | 0 .../cv/classification/MobileNet/mobilenet.py | 0 .../MobileNet/modelzoo_level.txt | 4 +- .../classification/MobileNet/pthtar2onnx.py | 0 .../classification/MobileNet/requirements.txt | 0 .../classification/MobileNet/scripts/eval.sh | 0 .../MobileNet/scripts/run_2onnx.sh | 0 .../MobileNet/scripts/run_demo.sh | 0 .../MobileNet/scripts/train_1p.sh | 0 .../MobileNet/scripts/train_8p.sh | 0 .../classification/MobileNet/test/env_npu.sh | 0 .../MobileNet/test/run_2onnx.sh | 0 .../classification/MobileNet/test/run_demo.sh | 0 .../MobileNet/test/train_eval_8p.sh | 0 .../MobileNet/test/train_full_1p.sh | 0 .../MobileNet/test/train_full_8p.sh | 0 .../MobileNet/test/train_performance_1p.sh | 0 .../MobileNet/test/train_performance_8p.sh | 0 .../contrib/cv/classification/OSNet/README.md | 144 +- .../contrib/cv/classification/OSNet/main.py | 0 .../torchreid/metrics/rank_cylib/__init__.py | 92 +- .../contrib/cv/classification/PCB/README.md | 122 +- .../cv/classification/PCB/README_raw.md | 102 +- .../RegNetY-1.6GF/utils/progress/setup.py | 0 .../utils/progress/test_progress.py | 0 .../contrib/cv/classification/RepVGG/arch.PNG | Bin 52779 -> 0 bytes .../cv/classification/RepVGG/speed_acc.PNG | Bin 113972 -> 0 bytes .../cv/classification/RepVGG/table.PNG | Bin 134445 -> 0 bytes .../modelzoo_level.txt | 4 +- .../ResNeXt101_32x8d_for_PyTorch/LICENSE | 56 +- .../ResNeXt101_32x8d_for_PyTorch/README.md | 100 +- .../ResNeXt101_32x8d_for_PyTorch/demo.py | 144 +- .../ResNeXt101_32x8d_for_PyTorch/main.py | 1344 ++-- .../modelzoo_level.txt | 4 +- .../pthtar2onnx.py | 98 +- .../requirements.txt | 8 +- .../modelzoo_level.txt | 4 +- .../modelzoo_level.txt | 4 +- .../modelzoo_level.txt | 4 +- .../cv/classification/SE-ResNet-50/main.py | 1310 ++-- .../classification/SE-ResNet-50/se_module.py | 66 +- .../cv/classification/SE-ResNet-50/senet.py | 598 +- .../cv/classification/SENet154/README.md | 140 +- .../cv/classification/SENet154/checkpoint.py | 0 .../cv/classification/SENet154/data.py | 0 .../cv/classification/SENet154/demo.py | 0 .../contrib/cv/classification/SENet154/lsr.py | 0 .../SENet154/modelzoo_level.txt | 4 +- .../cv/classification/SENet154/pth2onnx.py | 0 .../cv/classification/SENet154/senet.py | 0 .../classification/SENet154/test/env_npu.sh | 0 .../classification/SENet154/test/run_2onnx.sh | 0 .../classification/SENet154/test/run_demo.sh | 0 .../SENet154/test/train_eval_8p.sh | 0 .../SENet154/test/train_full_1p.sh | 0 .../SENet154/test/train_full_8p.sh | 0 .../SENet154/test/train_performance_1p.sh | 0 .../SENet154/test/train_performance_8p.sh | 0 .../cv/classification/SENet154/train.py | 0 .../cv/classification/SENet154/utils.py | 0 .../Se-ResNext-50-32x4d/Dockerfile | 0 .../Se-ResNext-50-32x4d/LICENSE | 0 .../Se-ResNext-50-32x4d/README.md | 0 .../Se-ResNext-50-32x4d/demo.py | 0 .../Se-ResNext-50-32x4d/docker_start.sh | 0 .../Se-ResNext-50-32x4d/main.py | 0 .../Se-ResNext-50-32x4d/modelzoo_level.txt | 0 .../Se-ResNext-50-32x4d/pthtar2onnx.py | 0 .../Se-ResNext-50-32x4d/requirements.txt | 0 .../Se-ResNext-50-32x4d/scripts/eval.sh | 0 .../scripts/npu_set_env.sh | 0 .../Se-ResNext-50-32x4d/scripts/train_1p.sh | 0 .../Se-ResNext-50-32x4d/scripts/train_8p.sh | 0 .../Se-ResNext-50-32x4d/senet.py | 0 .../Se-ResNext-50-32x4d/test/env_npu.sh | 0 .../Se-ResNext-50-32x4d/test/train_eval_8p.sh | 0 .../Se-ResNext-50-32x4d/test/train_full_1p.sh | 0 .../Se-ResNext-50-32x4d/test/train_full_8p.sh | 0 .../test/train_performance_1p.sh | 0 .../test/train_performance_8p.sh | 0 .../Dockerfile | 8 +- .../docker_start.sh | 48 +- .../modelzoo_level.txt | 4 +- .../README.md | 110 +- .../blocks.py | 498 +- .../channel_shuffle.py | 312 +- .../classification/SkresNet50/scripts/eval.sh | 0 .../SkresNet50/scripts/npu_setenv.sh | 0 .../SkresNet50/scripts/train_1p.sh | 0 .../SkresNet50/scripts/train_8p.sh | 0 .../SkresNet50/utils/progress/setup.py | 0 .../utils/progress/test_progress.py | 0 .../cv/classification/TNT/npu_fused_adamw.py | 514 +- .../contrib/cv/classification/VOLO/README.md | 128 +- .../contrib/cv/classification/VOLO/demo.py | 272 +- .../cv/classification/VOLO/loss/__init__.py | 92 +- .../cv/classification/VOLO/models/__init__.py | 94 +- .../cv/classification/VOLO/prof_demo.sh | 0 .../classification/VOLO/test/train_full_8p.sh | 0 .../VOLO/test/train_performance_8p.sh | 0 .../VOLO/timm/loss/asymmetric_loss.py | 286 +- .../cv/classification/VOLO/tlt/__init__.py | 92 +- .../VOLO/tlt/data/random_augment_label.py | 1212 ++-- .../classification/VOLO/tlt/loss/__init__.py | 92 +- .../classification/VOLO/tlt/utils/__init__.py | 92 +- .../cv/classification/VOLO/utils/__init__.py | 92 +- .../modelzoo_level.txt | 4 +- .../modelzoo_level.txt | 4 +- .../Vit_small_patch16_224/README.md | 110 +- .../Vit_small_patch16_224/demo.py | 168 +- .../distributed_train.sh | 0 .../distributed_train_npu.sh | 0 .../Vit_small_patch16_224/pthtar2onnx.py | 124 +- .../timm/loss/asymmetric_loss.py | 286 +- .../timm/optim/npu_fused_adamp.py | 596 +- .../timm/optim/npu_fused_adamw.py | 578 +- .../Vit_small_patch16_224/train.py | 0 .../VoVNet39/test/train_eval_8p.sh | 0 .../VoVNet39/test/train_finetune_1p.sh | 0 .../VoVNet39/test/train_full_8p.sh | 0 .../VoVNet39/test/train_performance_1p.sh | 0 .../VoVNet39/test/train_performance_8p.sh | 0 .../infer/Dockerfile | 42 +- .../infer/convert/xception_pt_aipp.config | 32 +- .../infer/models/xception_aipp.cfg | 4 +- .../infer/mxbase/CMakeLists.txt | 104 +- .../infer/mxbase/XceptionClassify.cpp | 500 +- .../infer/mxbase/XceptionClassify.h | 116 +- .../infer/mxbase/main.cpp | 138 +- .../infer/sdk/main_xception_opencv.py | 190 +- .../sdk/pipeline/xception_opencv.pipeline | 146 +- .../infer/utils/classification_task_metric.py | 324 +- .../modelarts/train_start_xception.py | 1192 ++-- .../csp_resnext50-mish/benchmark.py | 0 .../timm/loss/asymmetric_loss.py | 194 +- .../csp_resnext50-mish/train-1p.py | 0 .../csp_resnext50-mish/train-8p.py | 0 .../csp_resnext50-mish/validate.py | 0 .../cv/classification/pointnetCNN/LICENSE | 58 +- .../cv/classification/pointnetCNN/README.md | 96 +- .../pointnetCNN/modelzoo_level.txt | 4 +- .../pointnetCNN/requirements.txt | 8 +- .../vit_base_patch32_224/LICENSE | 56 +- .../vit_base_patch32_224/README.md | 60 +- .../vit_base_patch32_224/modelzoo_level.txt | 8 +- .../vit_base_patch32_224/requirements.txt | 8 +- .../vit_base_patch32_224/vit_train.py | 1806 ++--- .../detectron2/structures/masks.py | 884 +-- .../contrib/cv/detection/CenterFace/LICENSE | 56 +- .../detection/CenterFace/modelzoo_level.txt | 4 +- .../detection/CenterFace/src/8p_npu_main.py | 254 +- .../detection/CenterFace/src/test/env_npu.sh | 136 +- .../cv/detection/CenterNet/modelzoo_level.txt | 4 +- .../src/lib/detectors/base_detector.py | 0 .../CenterNet/src/lib/detectors/ctdet.py | 0 .../CenterNet/src/lib/detectors/ddd.py | 0 .../CenterNet/src/lib/detectors/exdet.py | 0 .../CenterNet/src/lib/detectors/multi_pose.py | 0 .../src/lib/models/networks/DCNv2/make.sh | 0 .../networks/dcn/modules/deform_conv.py | 470 +- .../cv/detection/CenterNet/src/lib/opts.py | 0 .../CenterNet/src/lib/trains/base_trainer.py | 0 .../CenterNet/src/lib/trains/ctdet.py | 0 .../detection/CenterNet/src/lib/trains/ddd.py | 0 .../CenterNet/src/lib/trains/exdet.py | 0 .../CenterNet/src/lib/trains/multi_pose.py | 0 .../CenterNet/src/lib/utils/__init__.py | 0 .../CenterNet/src/lib/utils/image.py | 0 .../cv/detection/CenterNet/src/main.py | 0 .../cv/detection/CenterNet/src/test.py | 0 .../cv/detection/CenterNet/src/tools/reval.py | 0 .../CenterNet/test/modelzoo_level.txt | 4 +- .../contrib/cv/detection/FCOS/README_raw.md | 260 +- .../FCOS/infer/convert/fcos_aipp.cfg | 32 +- .../FCOS/infer/docker_start_infer.sh | 94 +- .../FCOS/infer/mxbase/CMakeLists.txt | 102 +- .../detection/FCOS/infer/mxbase/src/fcos.cpp | 626 +- .../cv/detection/FCOS/infer/mxbase/src/fcos.h | 104 +- .../detection/FCOS/infer/mxbase/src/main.cpp | 90 +- .../FCOS/infer/sdk/fcos_opencv_all.py | 578 +- .../cv/detection/FCOS/infer/util/coco_eval.py | 190 +- .../detection/FCOS/infer/util/txt_to_json.py | 222 +- .../detection/FCOS/mmcv_need/base_runner.py | 948 +-- .../FCOS/mmcv_need/epoch_based_runner.py | 446 +- .../cv/detection/FCOS/mmcv_need/iter_timer.py | 112 +- .../fcos_r50_caffe_fpn_4x4_1x_coco_new.py | 276 +- .../cv/detection/FCOS/scripts/train_1p.sh | 0 .../cv/detection/FCOS/scripts/train_8p.sh | 0 .../cv/detection/FCOS/tools/dist_train.sh | 0 PyTorch/contrib/cv/detection/FOTS/LICENSE | 408 +- PyTorch/contrib/cv/detection/FOTS/README.md | 118 +- .../contrib/cv/detection/FOTS/requirments.txt | 8 +- .../infer/data/config/fsaf.pipeline | 0 .../infer/docker_start_infer.sh | 94 +- .../infer/mxbase/CMakeLists.txt | 114 +- .../FSAF_for_Pytorch/infer/mxbase/build.sh | 0 .../infer/mxbase/src/fsaf.cpp | 854 +-- .../FSAF_for_Pytorch/infer/mxbase/src/fsaf.h | 130 +- .../infer/mxbase/src/main.cpp | 106 +- .../FSAF_for_Pytorch/infer/sdk/run.sh | 0 .../FSAF_for_Pytorch/infer/util/coco_eval.py | 192 +- .../infer/util/txt_to_json.py | 224 +- .../mmdetection/tools/dist_train.sh | 0 .../mmdetection/tools/slurm_test.sh | 0 .../mmdetection/tools/slurm_train.sh | 0 .../FSAF_for_Pytorch/scripts/train_8p.sh | 0 .../contrib/cv/detection/FaceBoxes/README.md | 234 +- .../cv/detection/FaceBoxes/README_raw.md | 184 +- .../GFocalV2/test/train_finetune_1p.sh | 270 +- .../cv/detection/Pointnetplus/README.md | 96 +- .../cv/detection/Pointnetplus/finetune.py | 148 +- .../detection/Pointnetplus/modelzoo_level.txt | 8 +- .../Pointnetplus/pointnetplus_pth2onnx.py | 208 +- .../detection/Pointnetplus/requirements.txt | 10 +- .../contrib/cv/detection/Pyramidbox/README.md | 276 +- .../cv/detection/Pyramidbox/README_raw.md | 144 +- .../cv/detection/Pyramidbox/data/config.py | 174 +- .../cv/detection/Pyramidbox/data/widerface.py | 344 +- .../contrib/cv/detection/Pyramidbox/demo.py | 282 +- .../detection/Pyramidbox/layers/__init__.py | 18 +- .../detection/Pyramidbox/layers/bbox_utils.py | 678 +- .../Pyramidbox/layers/functions/__init__.py | 10 +- .../Pyramidbox/layers/functions/detection.py | 164 +- .../Pyramidbox/layers/functions/prior_box.py | 146 +- .../Pyramidbox/layers/modules/__init__.py | 24 +- .../Pyramidbox/layers/modules/l2norm.py | 94 +- .../layers/modules/multibox_loss.py | 318 +- .../detection/Pyramidbox/modelzoo_level.txt | 6 +- .../Pyramidbox/prepare_wider_data.py | 242 +- .../cv/detection/Pyramidbox/pyramidbox.py | 868 +-- .../cv/detection/Pyramidbox/requirements.txt | 50 +- .../cv/detection/Pyramidbox/tools/afw_test.py | 280 +- .../detection/Pyramidbox/tools/fddb_test.py | 312 +- .../detection/Pyramidbox/tools/pascal_test.py | 280 +- .../detection/Pyramidbox/tools/wider_test.py | 566 +- .../contrib/cv/detection/Pyramidbox/train.py | 722 +- .../Pyramidbox/utils/augmentations.py | 1740 ++--- .../contrib/cv/detection/RefineDet/README.md | 96 +- .../contrib/cv/detection/RefineDet/demo.py | 42 +- .../cv/detection/RefineDet/eval_refinedet.py | 932 +-- .../cv/detection/RefineDet/models/timeAcc.py | 84 +- .../cv/detection/RefineDet/modelzoo_level.txt | 4 +- .../cv/detection/RefineDet/requirements.txt | 18 +- .../cv/detection/RefineDet/train_1p.py | 568 +- .../cv/detection/RefineDet/train_8p.py | 588 +- .../RefineDet/utils/augmentations.py | 866 +-- .../cv/detection/RefineDet/utils/logging.py | 108 +- .../cv/detection/RefineDet/utils/osutils.py | 52 +- .../detection/Retinaface/modelzoo_level.txt | 4 +- .../cv/detection/SOLOv1/mmcv/README.rst | 54 - .../cv/detection/SOLOv2/mmcv/README.rst | 54 - .../cv/detection/SSD-MobilenetV2/Dockerfile | 8 +- .../cv/detection/SSD-MobilenetV2/LICENSE | 0 .../cv/detection/SSD-MobilenetV2/README.md | 176 +- .../detection/SSD-MobilenetV2/README_raw.md | 0 .../convert_to_caffe2_models.py | 0 .../cv/detection/SSD-MobilenetV2/demo.py | 206 +- .../detection/SSD-MobilenetV2/docker_start.sh | 0 .../SSD-MobilenetV2/draw_eval_results.py | 0 .../cv/detection/SSD-MobilenetV2/eval_ssd.py | 0 .../SSD-MobilenetV2/extract_tf_weights.py | 0 .../SSD-MobilenetV2/modelzoo_level.txt | 4 +- .../SSD-MobilenetV2/open_images_downloader.py | 0 .../SSD-MobilenetV2/prune_alexnet.py | 0 .../SSD-MobilenetV2/requirements.txt | 8 +- .../SSD-MobilenetV2/run_ssd_example.py | 0 .../SSD-MobilenetV2/run_ssd_live_caffe2.py | 0 .../SSD-MobilenetV2/run_ssd_live_demo.py | 0 .../detection/SSD-MobilenetV2/scripts/eval.sh | 0 .../SSD-MobilenetV2/scripts/set_npu_env.sh | 0 .../SSD-MobilenetV2/scripts/train_1p.sh | 0 .../SSD-MobilenetV2/scripts/train_8p.sh | 0 .../detection/SSD-MobilenetV2/test/env_npu.sh | 0 .../SSD-MobilenetV2/test/train_finetune_1p.sh | 0 .../SSD-MobilenetV2/test/train_full_1p.sh | 0 .../SSD-MobilenetV2/test/train_full_8p.sh | 0 .../test/train_performance_1p.sh | 0 .../test/train_performance_8p.sh | 0 .../cv/detection/SSD-MobilenetV2/train_ssd.py | 986 +-- .../translate_tf_mobilenetv1.py | 0 .../vision/datasets/collation.py | 0 .../vision/datasets/generate_vocdata.py | 0 .../vision/datasets/open_images.py | 0 .../vision/datasets/voc_dataset.py | 0 .../SSD-MobilenetV2/vision/nn/alexnet.py | 0 .../SSD-MobilenetV2/vision/nn/mobilenet.py | 0 .../SSD-MobilenetV2/vision/nn/mobilenet_v2.py | 0 .../SSD-MobilenetV2/vision/nn/mobilenetv3.py | 0 .../vision/nn/multibox_loss.py | 0 .../vision/nn/scaled_l2_norm.py | 0 .../SSD-MobilenetV2/vision/nn/squeezenet.py | 0 .../SSD-MobilenetV2/vision/nn/vgg.py | 0 .../vision/prunning/prunner.py | 0 .../ssd/config/mobilenetv1_ssd_config.py | 0 .../ssd/config/squeezenet_ssd_config.py | 0 .../vision/ssd/config/vgg_ssd_config.py | 0 .../vision/ssd/data_preprocessing.py | 0 .../vision/ssd/fpn_mobilenetv1_ssd.py | 0 .../SSD-MobilenetV2/vision/ssd/fpn_ssd.py | 0 .../vision/ssd/mobilenet_v2_ssd_lite.py | 0 .../vision/ssd/mobilenetv1_ssd.py | 0 .../vision/ssd/mobilenetv1_ssd_lite.py | 0 .../vision/ssd/mobilenetv3_ssd_lite.py | 0 .../SSD-MobilenetV2/vision/ssd/predictor.py | 0 .../vision/ssd/squeezenet_ssd_lite.py | 0 .../SSD-MobilenetV2/vision/ssd/ssd.py | 0 .../SSD-MobilenetV2/vision/ssd/vgg_ssd.py | 0 .../vision/test/test_vgg_ssd.py | 0 .../vision/transforms/transforms.py | 0 .../SSD-MobilenetV2/vision/utils/__init__.py | 0 .../SSD-MobilenetV2/vision/utils/box_utils.py | 0 .../vision/utils/box_utils_numpy.py | 0 .../vision/utils/measurements.py | 0 .../SSD-MobilenetV2/vision/utils/misc.py | 0 .../vision/utils/model_book.py | 0 .../SSD-MobilenetV2/visual_tf_models.py | 0 .../contrib/cv/detection/SSD-Resnet/README.md | 120 +- .../contrib/cv/detection/SSD-Resnet/demo.py | 978 +-- .../contrib/cv/detection/SSD-Resnet/new.py | 102 +- .../contrib/cv/detection/SSD-Resnet/nms.py | 292 +- .../contrib/cv/detection/SSD/scripts/eval.sh | 0 .../cv/detection/SSD/scripts/eval_1p.sh | 0 .../cv/detection/SSD/scripts/npu_set_env.sh | 0 .../cv/detection/SSD/scripts/train_1p.sh | 0 .../cv/detection/SSD/scripts/train_8p.sh | 0 PyTorch/contrib/cv/detection/SSD/setup.py | 0 .../cv/detection/SSD/tools/dist_test.sh | 0 .../cv/detection/SSD/tools/dist_train.sh | 0 .../cv/detection/SSD/tools/slurm_test.sh | 0 .../cv/detection/SSD/tools/slurm_train.sh | 0 .../SimCLR_for_Pytorch/README_raw.md | 104 +- .../detection/SimCLR_for_Pytorch/main_1p.py | 540 +- .../detection/SimCLR_for_Pytorch/main_8p.py | 660 +- .../SimCLR_for_Pytorch/modelzoo_level.txt | 14 +- .../multi_epochs_dataloader.py | 92 +- .../cv/detection/StyleGAN2-ADA/README.md | 128 +- .../cv/detection/StyleGAN2-ADA/perf_gpu.py | 244 +- .../detection/StyleGAN2-ADA/requirements.txt | 8 +- .../stylegan2-ada-pytorch_postprocess.py | 156 +- .../stylegan2-ada-pytorch_preprocess.py | 162 +- .../contrib/cv/detection/TextSnake/Dockerfile | 8 +- .../cv/detection/TextSnake/dataset/ctw.py | 60 +- .../ComputePrecisionRecall.m | 322 +- .../cv/detection/TextSnake/modelzoo_level.txt | 4 +- .../YOLACT/layers/modules/multibox_loss.py | 1474 ++-- .../cv/detection/YOLACT/modelzoo_level.txt | 4 +- PyTorch/contrib/cv/detection/YOLACT/yolact.py | 1508 ++--- .../contrib/cv/detection/YOLACT_plus/LICENSE | 400 +- .../cv/detection/YOLACT_plus/README.md | 98 +- .../cv/detection/YOLACT_plus/backbone.py | 948 +-- .../cv/detection/YOLACT_plus/data/__init__.py | 12 +- .../cv/detection/YOLACT_plus/data/coco.py | 622 +- .../cv/detection/YOLACT_plus/data/config.py | 1684 ++--- .../YOLACT_plus/data/scripts/COCO.sh | 140 +- .../YOLACT_plus/data/scripts/COCO_test.sh | 124 +- .../YOLACT_plus/data/scripts/mix_sets.py | 148 +- .../cv/detection/YOLACT_plus/deform_conv.py | 470 +- .../contrib/cv/detection/YOLACT_plus/eval.py | 2316 +++---- .../detection/YOLACT_plus/layers/__init__.py | 4 +- .../detection/YOLACT_plus/layers/box_utils.py | 806 +-- .../YOLACT_plus/layers/functions/__init__.py | 8 +- .../YOLACT_plus/layers/functions/detection.py | 484 +- .../YOLACT_plus/layers/interpolate.py | 62 +- .../YOLACT_plus/layers/modules/__init__.py | 6 +- .../layers/modules/multibox_loss.py | 1442 ++-- .../YOLACT_plus/layers/output_utils.py | 400 +- .../detection/YOLACT_plus/modelzoo_level.txt | 10 +- .../YOLACT_plus/scripts/augment_bbox.py | 368 +- .../YOLACT_plus/scripts/bbox_recall.py | 390 +- .../YOLACT_plus/scripts/cluster_bbox_sizes.py | 166 +- .../YOLACT_plus/scripts/compute_masks.py | 216 +- .../YOLACT_plus/scripts/convert_darknet.py | 126 +- .../YOLACT_plus/scripts/convert_sbd.py | 176 +- .../cv/detection/YOLACT_plus/scripts/eval.sh | 28 +- .../YOLACT_plus/scripts/make_grid.py | 436 +- .../YOLACT_plus/scripts/optimize_bboxes.py | 436 +- .../YOLACT_plus/scripts/parse_eval.py | 126 +- .../YOLACT_plus/scripts/plot_loss.py | 184 +- .../detection/YOLACT_plus/scripts/resume.sh | 28 +- .../YOLACT_plus/scripts/save_bboxes.py | 94 +- .../cv/detection/YOLACT_plus/scripts/train.sh | 28 +- .../YOLACT_plus/scripts/unpack_statedict.py | 60 +- .../cv/detection/YOLACT_plus/test/env_npu.sh | 150 +- .../YOLACT_plus/test/train_eval_1p.sh | 280 +- .../YOLACT_plus/test/train_full_1p.sh | 302 +- .../YOLACT_plus/test/train_full_8p.sh | 344 +- .../YOLACT_plus/test/train_performance_1p.sh | 296 +- .../contrib/cv/detection/YOLACT_plus/train.py | 1320 ++-- .../YOLACT_plus/utils/augmentations.py | 1404 ++-- .../YOLACT_plus/utils/cython_nms.pyx | 148 +- .../detection/YOLACT_plus/utils/functions.py | 452 +- .../cv/detection/YOLACT_plus/utils/logger.py | 1006 +-- .../cv/detection/YOLACT_plus/utils/nvinfo.py | 152 +- .../cv/detection/YOLACT_plus/utils/timer.py | 290 +- .../cv/detection/YOLACT_plus/yolact.py | 1478 ++-- PyTorch/contrib/cv/detection/YOLOR/README.md | 256 +- .../cv/detection/YOLOR/cfg/yolor_csp.cfg | 2752 ++++---- .../cv/detection/YOLOR/cfg/yolor_csp_x.cfg | 3152 ++++----- .../cv/detection/YOLOR/cfg/yolor_p6.cfg | 3522 +++++----- .../detection/YOLOR/cfg/yolor_p6_finetune.cfg | 3518 +++++----- .../cv/detection/YOLOR/cfg/yolor_w6.cfg | 3520 +++++----- .../cv/detection/YOLOR/cfg/yolov4_csp.cfg | 2668 ++++---- .../cv/detection/YOLOR/cfg/yolov4_csp_x.cfg | 3068 ++++----- .../cv/detection/YOLOR/cfg/yolov4_p6.cfg | 4520 ++++++------- .../cv/detection/YOLOR/cfg/yolov4_p7.cfg | 5428 +++++++-------- .../cv/detection/YOLOR/cfg/yolov5x.cfg | 86 +- .../cv/detection/YOLOR/darknet/README.md | 126 +- .../YOLOR/darknet/cfg/yolov4-csp-x.cfg | 3110 ++++----- .../YOLOR/darknet/cfg/yolov4-csp.cfg | 2708 ++++---- .../cv/detection/YOLOR/darknet/new_layers.md | 658 +- .../cv/detection/YOLOR/data/coco.names | 160 +- .../contrib/cv/detection/YOLOR/data/coco.yaml | 36 +- .../YOLOR/data/hyp.finetune.1280.yaml | 56 +- .../YOLOR/data/hyp.scratch.1280.yaml | 56 +- .../detection/YOLOR/data/hyp.scratch.640.yaml | 56 +- .../cv/detection/YOLOR/models/__init__.py | 2 +- .../cv/detection/YOLOR/models/export.py | 164 +- .../cv/detection/YOLOR/models/models.py | 1550 ++--- .../cv/detection/YOLOR/requirements-GPU.txt | 86 +- .../cv/detection/YOLOR/requirements.txt | 60 +- PyTorch/contrib/cv/detection/YOLOR/test.py | 756 +-- PyTorch/contrib/cv/detection/YOLOR/train.py | 1478 ++-- .../cv/detection/YOLOR/utils/__init__.py | 2 +- .../cv/detection/YOLOR/utils/activations.py | 170 +- .../cv/detection/YOLOR/utils/autoanchor.py | 332 +- .../cv/detection/YOLOR/utils/datasets.py | 2622 +++---- .../cv/detection/YOLOR/utils/google_utils.py | 268 +- .../cv/detection/YOLOR/utils/layers.py | 1094 +-- .../contrib/cv/detection/YOLOR/utils/loss.py | 712 +- .../cv/detection/YOLOR/utils/metrics.py | 308 +- .../cv/detection/YOLOR/utils/parse_config.py | 170 +- .../contrib/cv/detection/YOLOR/utils/plots.py | 788 +-- .../cv/detection/YOLOR/utils/torch_utils.py | 626 +- .../cv/detection/centernet2/README.CN.md | 238 +- .../cv/detection/centernet2/requirements.txt | 34 +- PyTorch/contrib/cv/others/ADNet/LICENSE | 402 +- PyTorch/contrib/cv/others/ADNet/README.md | 332 +- PyTorch/contrib/cv/others/ADNet/demo.py | 222 +- .../cv/others/ADNet/modelzoo_level.txt | 4 +- PyTorch/contrib/cv/others/ADNet/preprocess.py | 128 +- PyTorch/contrib/cv/others/BigGAN/LICENSE | 400 +- PyTorch/contrib/cv/others/BigGAN/datasets.py | 756 +-- .../contrib/cv/others/BigGAN/evaluation.py | 172 +- .../cv/others/BigGAN/modelzoo_level.txt | 4 +- .../contrib/cv/others/BigGAN/requirements.txt | 14 +- PyTorch/contrib/cv/others/CGAN/LICENSE | 402 +- PyTorch/contrib/cv/others/CGAN/README.md | 260 +- PyTorch/contrib/cv/others/CGAN/demo.py | 204 +- .../contrib/cv/others/CGAN/modelzoo_level.txt | 4 +- PyTorch/contrib/cv/others/CGAN/pth2onnx.py | 132 +- .../cv/others/CycleGAN/CycleGAN_NetLoad.py | 184 +- PyTorch/contrib/cv/others/CycleGAN/LICENSE | 60 +- PyTorch/contrib/cv/others/CycleGAN/Readme.md | 344 +- .../contrib/cv/others/CycleGAN/dataloader.py | 256 +- PyTorch/contrib/cv/others/CycleGAN/demon.py | 378 +- .../CycleGAN/models/cycle_gan_model_adapt.py | 842 +-- .../cv/others/CycleGAN/modelzoo_level.txt | 4 +- PyTorch/contrib/cv/others/CycleGAN/parse.py | 472 +- .../cv/others/CycleGAN/requirements.txt | 6 +- PyTorch/contrib/cv/others/CycleGAN/train.py | 260 +- PyTorch/contrib/cv/others/DCGAN/LICENSE | 400 +- PyTorch/contrib/cv/others/DCGAN/dcgan.py | 164 +- PyTorch/contrib/cv/others/DCGAN/get_mnist.py | 60 +- PyTorch/contrib/cv/others/DCGAN/main.py | 1020 +-- .../cv/others/DCGAN/modelzoo_level.txt | 4 +- .../contrib/cv/others/DCGAN/requirements.txt | 4 +- .../contrib/cv/others/GAN_Pytorch/Dockerfile | 8 +- .../contrib/cv/others/GAN_Pytorch/README.md | 92 +- .../cv/others/GAN_Pytorch/docker_start.sh | 48 +- PyTorch/contrib/cv/others/GAN_Pytorch/main.py | 772 +-- .../contrib/cv/others/GAN_Pytorch/models.py | 136 +- .../cv/others/GAN_Pytorch/modelzoo_level.txt | 4 +- PyTorch/contrib/cv/others/Pix2Pix/README.md | 76 +- .../cv/others/Pix2Pix/modelzoo_level.txt | 4 +- .../contrib/cv/others/Pix2Pix/precision.py | 396 +- .../contrib/cv/others/Pix2Pix/pytorch_prof.py | 280 +- PyTorch/contrib/cv/others/RDN/Dockerfile | 8 +- PyTorch/contrib/cv/others/RDN/README.md | 102 +- PyTorch/contrib/cv/others/RDN/docker_start.sh | 48 +- .../contrib/cv/others/RDN/modelzoo_level.txt | 4 +- .../Srcnn_x2_for_Pytorch/modelzoo_level.txt | 10 +- .../Srcnn_x2_for_Pytorch/requirements.txt | 8 +- PyTorch/contrib/cv/others/edsr_x2/loss.py | 304 +- PyTorch/contrib/cv/others/stargan/Dockerfile | 8 +- PyTorch/contrib/cv/others/stargan/README.md | 110 +- .../contrib/cv/others/stargan/docker_start.sh | 48 +- .../cv/others/stargan/modelzoo_level.txt | 4 +- .../3Dmppe_RootNet/README_ch.md | 6 +- .../3Dmppe_RootNet/README_en.md | 6 +- .../3Dmppe_RootNet/common/timer.py | 106 +- .../3Dmppe_RootNet/modelzoo_level.txt | 4 +- .../3Dmppe_RootNet/requirements.txt | 26 +- .../cv/pose_estimation/HigherHRNet/README.md | 184 +- .../HigherHRNet/modelzoo_level.txt | 4 +- .../HigherHRNet/requirements.txt | 24 +- .../Hourglass_for_PyTorch/data/valid.csv | 2958 ++++++++ .../infer/config/hourglass.pipeline | 32 + .../infer/convert/atc.sh | 28 + .../infer/docker_start_infer.sh | 48 + .../infer/mxbase/CMakeLists.txt | 30 + .../infer/mxbase/build.sh | 56 + .../infer/mxbase/include/hourglass.h | 75 + .../infer/mxbase/include/postprocess.h | 58 + .../infer/mxbase/src/hourglass.cpp | 322 + .../infer/mxbase/src/main.cpp | 106 + .../infer/mxbase/src/postprocess.cpp | 217 + .../infer/sdk/cal_accuracy.py | 133 + .../Hourglass_for_PyTorch/infer/sdk/main.py | 158 + .../infer/sdk/postprocess.py | 83 + .../infer/sdk/preprocess.py | 168 + .../Hourglass_for_PyTorch/infer/sdk/run.sh | 35 + .../mmpose-master/docs/merge_docs.sh | 0 .../interhand2d/test_interhand2d_camera.json | 0 .../interhand2d/test_interhand2d_data.json | 0 .../test_interhand2d_joint_3d.json | 0 .../tests/data/panoptic/test_panoptic.json | 0 .../mmpose-master/tools/dist_test.sh | 0 .../mmpose-master/tools/dist_train.sh | 0 .../modelarts/selfexport.py | 39 + .../Hourglass_for_PyTorch/modelarts/start.py | 154 + .../Lightweight_OpenPose/LICENSE | 400 +- .../Lightweight_OpenPose/datasets/__init__.py | 26 +- .../Lightweight_OpenPose/models/__init__.py | 26 +- .../Lightweight_OpenPose/modelzoo_level.txt | 4 +- .../Lightweight_OpenPose/modules/__init__.py | 26 +- .../multi_epochs_dataloaders.py | 92 +- .../Lightweight_OpenPose/requirements.txt | 4 +- .../pose_estimation/MSPN/dataset/MPII/mpii.py | 396 +- .../semantic_segmentation/3DUNet/docker/r.txt | 20 +- .../lib/medloaders/multi_epochs_dataloader.py | 92 +- .../DeeplabV3_for_Pytorch/Dockerfile | 42 +- .../DeeplabV3_for_Pytorch/README.md | 214 +- .../DeeplabV3_for_Pytorch/modelzoo_level.txt | 4 +- .../cv/semantic_segmentation/ENet/README.md | 104 +- .../ENet/core/__init__.py | 28 +- .../ENet/core/data/__init__.py | 24 +- .../ENet/core/data/downloader/__init__.py | 24 +- .../ENet/core/models/avg_enet.py | 1100 +-- .../ENet/core/models/ocnet.py | 718 +- .../ENet/scripts/eval.py | 286 +- .../ENet/scripts/proc_node_module.py | 80 +- .../ENet/scripts/train.py | 898 +-- .../FCN8s/modelzoo_level.txt | 10 +- .../semantic_segmentation/FastSCNN/README.md | 308 +- .../FastSCNN/modelzoo_level.txt | 4 +- .../FastSCNN/segmentron/models/ocnet.py | 616 +- .../HRNet_SEG_for_Pytorch/figures/OCR.PNG | Bin 65653 -> 0 bytes .../semantic_segmentation/HRnet-OCR/README.md | 130 +- .../HRnet-OCR/modelzoo_level.txt | 4 +- .../HRnet-OCR/utils/results_page.py | 552 +- .../IntraDA/ADVENT/advent/__init__.py | 24 +- .../IntraDA/ADVENT/advent/dataset/__init__.py | 24 +- .../advent/domain_adaptation/__init__.py | 24 +- .../ADVENT/advent/domain_adaptation/config.py | 312 +- .../advent/domain_adaptation/eval_UDA.py | 314 +- .../advent/domain_adaptation/train_UDA.py | 712 +- .../IntraDA/ADVENT/advent/model/__init__.py | 24 +- .../configs/advent+minent_pretrained.yml | 34 +- .../configs/advent_cyclegan_pretrained.yml | 14 +- .../scripts/configs/advent_pretrained.yml | 14 +- .../ADVENT/advent/scripts/configs/minent.yml | 22 +- .../scripts/configs/minent_pretrained.yml | 16 +- .../IntraDA/ADVENT/advent/scripts/test.py | 218 +- .../IntraDA/ADVENT/advent/scripts/train.py | 318 +- .../IntraDA/ADVENT/advent/utils/func.py | 150 +- .../ADVENT/advent/utils/viz_segmask.py | 68 +- .../IntraDA/ADVENT/modelzoo_level.txt | 4 +- .../IntraDA/ADVENT/requirements.txt | 4 +- .../cv/semantic_segmentation/IntraDA/LICENSE | 400 +- .../semantic_segmentation/IntraDA/README.md | 154 +- .../IntraDA/figure/adaptsegnet.PNG | Bin 38510 -> 0 bytes .../IntraDA/figure/advent.PNG | Bin 43161 -> 0 bytes .../IntraDA/intrada/test.py | 228 +- .../IntraDA/intrada/train.py | 394 +- .../IntraDA/intrada/train_UDA.py | 938 +-- .../IntraDA/modelzoo_level.txt | 4 +- .../IntraDA/requirements.txt | 8 +- .../PointRend/createTrainIdLabelImgs.py | 140 +- .../datasets/prepare_ade20k_sem_seg.py | 0 .../datasets/prepare_cocofied_lvis.py | 0 .../PointRend/datasets/prepare_for_tests.sh | 0 .../datasets/prepare_panoptic_fpn.py | 0 .../PointRend/demo/demo.py | 0 .../PointRend/dev/linter.sh | 0 .../dev/packaging/build_all_wheels.sh | 0 .../PointRend/dev/packaging/build_wheel.sh | 0 .../dev/packaging/gen_install_table.py | 0 .../dev/packaging/gen_wheel_index.sh | 0 .../PointRend/dev/packaging/pkg_helpers.bash | 0 .../PointRend/dev/parse_results.sh | 0 .../PointRend/dev/run_inference_tests.sh | 0 .../PointRend/dev/run_instant_tests.sh | 0 .../PointRend/projects/PointRend/train_net.py | 0 .../PointRend/tools/analyze_model.py | 0 .../PointRend/tools/benchmark.py | 0 .../tools/convert-torchvision-to-d2.py | 0 .../PointRend/tools/deploy/export_model.py | 0 .../PointRend/tools/lazyconfig_train_net.py | 0 .../PointRend/tools/plain_train_net.py | 0 .../PointRend/tools/train_net.py | 0 .../PointRend/tools/visualize_data.py | 0 .../PointRend/tools/visualize_json_results.py | 0 .../cv/semantic_segmentation/RCAN/dataset.py | 0 .../cv/semantic_segmentation/RCAN/main.py | 0 .../cv/semantic_segmentation/RCAN/model.py | 0 .../cv/semantic_segmentation/RCAN/test.py | 0 .../RCAN/test/run_1p_prof.sh | 0 .../RCAN/test/run_test.sh | 0 .../RCAN/test/set_npu_env.sh | 0 .../RCAN/test/train_finetuning_1p.sh | 0 .../RCAN/test/train_full_1p.sh | 0 .../RCAN/test/train_full_8p.sh | 0 .../RCAN/test/train_performance_1p.sh | 0 .../RCAN/test/train_performance_8p.sh | 0 .../cv/semantic_segmentation/RCAN/utils.py | 0 .../RefineNet/Dockerfile | 8 +- .../semantic_segmentation/RefineNet/README.md | 158 +- .../RefineNet/models/refinenet.py | 670 +- .../RefineNet/modelzoo_level.txt | 4 +- .../RefineNet/src/load_dataset.py | 146 +- .../cv/semantic_segmentation/SETR/env_npu.sh | 0 .../SETR/mmcv-need/fp16_utils.py | 762 +-- .../SETR/tools/dist_train.sh | 0 .../UNet_for_PyTorch/modelzoo_level.txt | 4 +- .../Wseg/configs/voc_resnet38.yaml | 64 +- .../semantic_segmentation/Wseg/core/config.py | 522 +- .../C3D/additional_need/mmcv/dist_utils.py | 368 +- .../C3D/additional_need/mmcv/distributed.py | 238 +- .../C3D/additional_need/mmcv/optimizer.py | 358 +- .../r2plus1d/r2plus1d_ucf101_rgb_1p.py | 224 +- .../r2plus1d/r2plus1d_ucf101_rgb_8p.py | 224 +- .../contrib/cv/video/C3D/tools/dist_train.sh | 0 PyTorch/contrib/cv/video/GloRe/README.md | 100 +- .../contrib/cv/video/GloRe/modelzoo_level.txt | 4 +- .../video/NonLocal/config/default_runtime.py | 54 +- .../cv/video/NonLocal/config/tsm_r50.py | 70 +- .../cv/video/NonLocal/mmaction/apis/train.py | 534 +- .../mmaction/datasets/pipelines/formating.py | 756 +-- .../models/backbones/resnet3d_slowfast.py | 1062 +-- .../NonLocal/mmaction/models/heads/base.py | 244 +- .../mmaction/models/heads/slowfast_head.py | 184 +- .../models/losses/cross_entropy_loss.py | 266 +- .../mmaction/models/recognizers/base.py | 678 +- .../models/recognizers/recognizer2d.py | 390 +- .../models/recognizers/recognizer3d.py | 266 +- .../additional_need/mmcv/dist_utils.py | 368 +- .../additional_need/mmcv/distributed.py | 238 +- .../R(2+1)D/additional_need/mmcv/optimizer.py | 364 +- .../r2plus1d/r2plus1d_ucf101_rgb_1p.py | 224 +- .../r2plus1d/r2plus1d_ucf101_rgb_1p_perf.py | 224 +- .../r2plus1d/r2plus1d_ucf101_rgb_8p.py | 224 +- .../r2plus1d/r2plus1d_ucf101_rgb_8p_perf.py | 224 +- .../cv/video/R(2+1)D/modelzoo_level.txt | 4 +- PyTorch/contrib/cv/video/R(2+1)D/test/onnx.sh | 18 +- .../SiamRPN/pysot-master/pysot/__init__.py | 24 +- .../pysot-master/pysot/models/__init__.py | 24 +- .../pysot-master/pysot/tracker/__init__.py | 24 +- .../pysot-master/pysot/utils/__init__.py | 24 +- .../SiamRPN/pysot-master/toolkit/__init__.py | 24 +- .../SiamRPN/pysot-master/vot_iter/__init__.py | 24 +- .../video/SlowFast/config/default_runtime.py | 54 +- .../cv/video/SlowFast/mmaction/apis/train.py | 534 +- .../mmaction/datasets/pipelines/formating.py | 756 +-- .../models/backbones/resnet3d_slowfast.py | 1062 +-- .../SlowFast/mmaction/models/heads/base.py | 244 +- .../mmaction/models/heads/slowfast_head.py | 184 +- .../models/losses/cross_entropy_loss.py | 266 +- .../mmaction/models/recognizers/base.py | 678 +- .../models/recognizers/recognizer2d.py | 390 +- .../models/recognizers/recognizer3d.py | 266 +- PyTorch/contrib/cv/video/VideoPose3D/run.py | 1398 ++-- .../cv/video/VideoPose3D/test/eval_full_8p.sh | 198 +- PyTorch/contrib/cv/video/X3D/README.md | 424 +- .../slowfast/utils/ava_evaluation/__init__.py | 28 +- .../Bertsum_for_PyTorch/modelzoo_level.txt | 4 +- PyTorch/contrib/nlp/TextCNN/LICENSE | 408 +- .../contrib/nlp/TextCNN/modelzoo_level.txt | 4 +- PyTorch/contrib/nlp/tinybert/demo.py | 178 +- .../contrib/nlp/tinybert/modelzoo_level.txt | 10 +- .../transformer/modeling_for_finetune.py | 2288 +++---- PyTorch/contrib/others/DQN/train_dqn.py | 74 +- .../README.md | 204 +- .../test/train_full_8p.sh | 250 +- .../test/train_performance_8p.sh | 256 +- .../README_ori.md | 218 +- .../modelzoo_level.txt | 4 +- .../README_ori.md | 28 +- .../modelzoo_level.txt | 4 +- .../modelzoo_level.txt | 4 +- .../BASNET_ID1134_for_PyTorch/iou_tmp.py | 164 +- .../BASNET_ID1134_for_PyTorch/prefetcher.py | 140 +- .../requirements.txt | 0 .../DCAP_ID2836_for_PyTorch/prefetcher.py | 124 +- .../DeepSort_ID0654_for_PyTorch/README_ori.md | 4 +- .../requirements.txt | 2 +- .../test/train_full_8p.sh | 402 +- .../test/train_performance_8p.sh | 396 +- .../modelzoo_level.txt | 4 +- .../test/train_performance_8p.sh | 414 +- .../utils/__init__.py | 64 +- .../test/train_full_8p.sh | 304 +- .../train_8p.py | 790 +-- .../train_8p_aux.py | 788 +-- .../InceptionV3_ID0445_for_PyTorch/utils3.py | 576 +- .../test/train_full_8p.sh | 446 +- .../test/train_performance_8p.sh | 448 +- .../NeuMF_ID0351_for_PyTorch/LICENSE | 58 +- .../src/prefetcher.py | 134 +- .../figure/additonal_result.PNG | Bin 12423 -> 0 bytes .../figure/model_arch.PNG | Bin 75383 -> 0 bytes .../ResNet152_ID0424_for_PyTorch/main_8p.py | 956 +-- .../modelzoo_level.txt | 4 +- .../test/train_full_8pt.sh | 392 +- .../README_ori.md | 236 +- .../requirements.txt | 4 +- ...ly_200k_bs64_crop_640_640_coco_dsconv.yaml | 42 - ...s16_mg124_poly_90k_bs32_crop_512_1024.yaml | 20 - ...24_poly_90k_bs32_crop_512_1024_dsconv.yaml | 24 - .../VGGNet_for_Pytorch/ README.md | 522 +- .../VGGNet_for_Pytorch/LICENSE | 402 +- .../VGGNet_for_PyTorch/modelzoo_level.txt | 4 +- .../VGGNet_for_PyTorch/requirements.txt | 30 +- .../test/train_performance_1p.sh | 332 +- .../VGGNet_for_Pytorch/modelzoo_level.txt | 4 +- .../VGGNet_for_Pytorch/requirements.txt | 30 +- .../modelzoo_level.txt | 4 +- .../test/train_full_8p.sh | 460 +- .../test/train_performance_8p.sh | 368 +- .../DSCNN_for_PyTorch/Dockerfile | 8 +- .../DSCNN_for_PyTorch/LICENSE | 44 +- .../DSCNN_for_PyTorch/README.md | 50 +- .../DSCNN_for_PyTorch/docker_start.sh | 48 +- .../DSCNN_for_PyTorch/dscnn_train_pytorch.py | 278 +- .../DSCNN_for_PyTorch/npu_set_env.sh | 58 +- .../DSCNN_for_PyTorch/pkltar2onnx.py | 208 +- .../DSCNN_for_PyTorch/requirements.txt | 10 +- .../DSCNN_for_PyTorch/run1p.sh | 28 +- .../DSCNN_for_PyTorch/run_to_onnx.sh | 6 +- .../test/train_full_1p_bs512.sh | 426 +- .../test/train_performance_1p_bs512.sh | 426 +- .../test/train_performance_1p_dynamic.sh | 430 +- .../modelzoo_level.txt | 4 +- .../modelzoo_level.txt | 4 +- .../test/train_full_1p.sh | 278 +- .../test/train_full_8p.sh | 316 +- .../test/train_performance_1p.sh | 288 +- .../test/train_performance_8p.sh | 318 +- .../train_8p_new.py | 834 +-- README.CN.md | 1242 ++-- Third_Party_Open_Source_Software_Notice | 3948 +++++------ 2172 files changed, 205047 insertions(+), 200541 deletions(-) delete mode 100644 ACL_PyTorch/built-in/cv/Yolov5_for_Pytorch/img.png mode change 100755 => 100644 ACL_PyTorch/contrib/cv/classfication/Deit_Small/test/pth2om.sh mode change 100755 => 100644 ACL_PyTorch/contrib/cv/classfication/EfficientNet-B3/README.md mode change 100755 => 100644 ACL_PyTorch/contrib/cv/classfication/MobileNet-v1/test/eval_acc_perf.sh mode change 100755 => 100644 ACL_PyTorch/contrib/cv/classfication/MobileNet-v1/test/pth2om.sh mode change 100755 => 100644 ACL_PyTorch/contrib/cv/classfication/vit-small/env.sh mode change 100755 => 100644 ACL_PyTorch/contrib/cv/detection/EfficientDetD0/test/pth2om.sh mode change 100755 => 100644 ACL_PyTorch/contrib/cv/segmentation/YOLACT/test/eval_acc_perf.sh mode change 100755 => 100644 ACL_PyTorch/contrib/cv/segmentation/YOLACT/test/perf_g.sh mode change 100755 => 100644 ACL_PyTorch/contrib/cv/segmentation/YOLACT/test/pth2om.sh mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/LICENSE mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Base-RCNN-C4.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Base-RCNN-DilatedC5.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Base-RCNN-FPN.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Base-RetinaNet.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/fast_rcnn_R_50_FPN_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_101_C4_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_101_DC5_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_101_FPN_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_50_C4_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_50_C4_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_50_DC5_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_50_DC5_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_50_FPN_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_50_FPN_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_X_101_32x8d_FPN_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/retinanet_R_101_FPN_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/retinanet_R_50_FPN_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/retinanet_R_50_FPN_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/rpn_R_50_C4_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/rpn_R_50_FPN_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_101_C4_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_101_DC5_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_C4_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_C4_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_DC5_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_DC5_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x_giou.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_X_101_32x8d_FPN_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Keypoints/Base-Keypoint-RCNN-FPN.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Keypoints/keypoint_rcnn_R_101_FPN_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Keypoints/keypoint_rcnn_R_50_FPN_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Keypoints/keypoint_rcnn_R_50_FPN_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Keypoints/keypoint_rcnn_X_101_32x8d_FPN_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-PanopticSegmentation/Base-Panoptic-FPN.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-PanopticSegmentation/panoptic_fpn_R_101_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-PanopticSegmentation/panoptic_fpn_R_50_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-PanopticSegmentation/panoptic_fpn_R_50_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Cityscapes/mask_rcnn_R_50_FPN.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Detectron1-Comparisons/README.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Detectron1-Comparisons/faster_rcnn_R_50_FPN_noaug_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Detectron1-Comparisons/keypoint_rcnn_R_50_FPN_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Detectron1-Comparisons/mask_rcnn_R_50_FPN_noaug_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/LVISv0.5-InstanceSegmentation/mask_rcnn_R_101_FPN_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/LVISv0.5-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/LVISv0.5-InstanceSegmentation/mask_rcnn_X_101_32x8d_FPN_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/LVISv1-InstanceSegmentation/mask_rcnn_R_101_FPN_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/LVISv1-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/LVISv1-InstanceSegmentation/mask_rcnn_X_101_32x8d_FPN_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/cascade_mask_rcnn_R_50_FPN_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/cascade_mask_rcnn_R_50_FPN_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/cascade_mask_rcnn_X_152_32x8d_FPN_IN5k_gn_dconv.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/mask_rcnn_R_50_FPN_1x_cls_agnostic.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/mask_rcnn_R_50_FPN_1x_dconv_c3-c5.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/mask_rcnn_R_50_FPN_3x_dconv_c3-c5.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/mask_rcnn_R_50_FPN_3x_gn.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/mask_rcnn_R_50_FPN_3x_syncbn.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/panoptic_fpn_R_101_dconv_cascade_gn_3x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/scratch_mask_rcnn_R_50_FPN_3x_gn.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/scratch_mask_rcnn_R_50_FPN_9x_gn.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/scratch_mask_rcnn_R_50_FPN_9x_syncbn.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/semantic_R_50_FPN_1x.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/PascalVOC-Detection/faster_rcnn_R_50_C4.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/PascalVOC-Detection/faster_rcnn_R_50_FPN.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/README.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/cascade_mask_rcnn_R_50_FPN_inference_acc_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/cascade_mask_rcnn_R_50_FPN_instant_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/fast_rcnn_R_50_FPN_inference_acc_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/fast_rcnn_R_50_FPN_instant_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/keypoint_rcnn_R_50_FPN_inference_acc_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/keypoint_rcnn_R_50_FPN_instant_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/keypoint_rcnn_R_50_FPN_normalized_training_acc_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/keypoint_rcnn_R_50_FPN_training_acc_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_C4_GCV_instant_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_C4_inference_acc_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_C4_instant_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_C4_training_acc_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_DC5_inference_acc_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_FPN_inference_acc_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_FPN_instant_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_FPN_pred_boxes_training_acc_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_FPN_training_acc_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/panoptic_fpn_R_50_inference_acc_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/panoptic_fpn_R_50_instant_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/panoptic_fpn_R_50_training_acc_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/retinanet_R_50_FPN_inference_acc_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/retinanet_R_50_FPN_instant_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/rpn_R_50_FPN_inference_acc_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/rpn_R_50_FPN_instant_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/semantic_R_50_FPN_inference_acc_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/semantic_R_50_FPN_instant_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/semantic_R_50_FPN_training_acc_test.yaml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/datasets/README.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/datasets/prepare_cocofied_lvis.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/datasets/prepare_for_tests.sh mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/datasets/prepare_panoptic_fpn.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/demo/README.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/demo/demo.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/demo/predictor.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/checkpoint/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/checkpoint/c2_model_loading.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/checkpoint/catalog.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/checkpoint/detection_checkpoint.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/config/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/config/compat.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/config/config.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/config/defaults.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/build.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/catalog.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/common.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/dataset_mapper.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/README.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/builtin.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/builtin_meta.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/cityscapes.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/coco.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/lvis.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/lvis_v0_5_categories.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/lvis_v1_categories.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/pascal_voc.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/register_coco.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/detection_utils.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/samplers/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/samplers/distributed_sampler.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/samplers/grouped_batch_sampler.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/transforms/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/transforms/augmentation.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/transforms/augmentation_impl.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/transforms/transform.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/engine/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/engine/defaults.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/engine/hooks.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/engine/launch.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/engine/train_loop.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/cityscapes_evaluation.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/coco_evaluation.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/evaluator.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/fast_eval_api.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/lvis_evaluation.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/panoptic_evaluation.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/pascal_voc_evaluation.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/rotated_coco_evaluation.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/sem_seg_evaluation.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/testing.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/README.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/api.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/c10.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/caffe2_export.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/caffe2_inference.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/caffe2_modeling.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/patcher.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/shared.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/torchscript.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/aspp.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/batch_norm.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/blocks.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/README.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/ROIAlign/ROIAlign.h mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/ROIAlign/ROIAlign_cpu.cpp mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/ROIAlign/ROIAlign_cuda.cu mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/ROIAlignRotated/ROIAlignRotated.h mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/ROIAlignRotated/ROIAlignRotated_cpu.cpp mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/ROIAlignRotated/ROIAlignRotated_cuda.cu mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/box_iou_rotated/box_iou_rotated.h mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/box_iou_rotated/box_iou_rotated_cpu.cpp mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/box_iou_rotated/box_iou_rotated_cuda.cu mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/box_iou_rotated/box_iou_rotated_utils.h mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/cocoeval/cocoeval.cpp mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/cocoeval/cocoeval.h mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/cuda_version.cu mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/deformable/deform_conv.h mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/deformable/deform_conv_cuda.cu mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/deformable/deform_conv_cuda_kernel.cu mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/nms_rotated/nms_rotated.h mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/nms_rotated/nms_rotated_cpu.cpp mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/nms_rotated/nms_rotated_cuda.cu mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/vision.cpp mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/deform_conv.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/mask_ops.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/nms.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/roi_align.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/roi_align_rotated.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/rotated_boxes.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/shape_spec.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/wrappers.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/model_zoo/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/model_zoo/model_zoo.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/anchor_generator.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/backbone/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/backbone/backbone.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/backbone/build.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/backbone/fpn.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/backbone/resnet.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/box_regression.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/matcher.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/meta_arch/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/meta_arch/build.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/meta_arch/panoptic_fpn.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/meta_arch/rcnn.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/meta_arch/retinanet.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/meta_arch/semantic_seg.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/poolers.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/postprocessing.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/proposal_generator/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/proposal_generator/build.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/proposal_generator/proposal_utils.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/proposal_generator/rpn.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/proposal_generator/rrpn.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/box_head.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/cascade_rcnn.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/fast_rcnn.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/keypoint_head.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/mask_head.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/roi_heads.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/rotated_fast_rcnn.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/sampling.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/test_time_augmentation.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/solver/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/solver/build.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/solver/lr_scheduler.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/boxes.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/image_list.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/instances.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/keypoints.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/masks.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/rotated_boxes.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/README.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/analysis.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/collect_env.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/colormap.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/comm.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/env.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/events.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/logger.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/memory.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/registry.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/serialize.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/video_visualizer.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/visualizer.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/README.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/linter.sh mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/packaging/README.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/packaging/build_all_wheels.sh mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/packaging/build_wheel.sh mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/packaging/gen_install_table.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/packaging/gen_wheel_index.sh mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/packaging/pkg_helpers.bash mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/parse_results.sh mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/run_inference_tests.sh mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/run_instant_tests.sh mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docker/Dockerfile mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docker/Dockerfile-circleci mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docker/README.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docker/docker-compose.yml mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/.gitignore mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/Makefile mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/README.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/_static/css/custom.css mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/conf.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/notes/benchmarks.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/notes/changelog.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/notes/compatibility.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/notes/contributing.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/README.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/builtin_datasets.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/configs.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/data_loading.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/datasets.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/deployment.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/evaluation.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/extend.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/getting_started.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/install.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/models.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/training.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/write-models.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/eval.sh mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/run.sh mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/run8p.sh mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/run8p_for_faster_rcnn.sh mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/run_for_faster_rcnn.sh mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/setup.cfg mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/setup.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/README.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/test_coco.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/test_coco_evaluation.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/test_detection_utils.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/test_rotation_transform.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/test_sampler.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/test_transforms.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/layers/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/layers/test_mask_ops.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/layers/test_nms.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/layers/test_nms_rotated.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/layers/test_roi_align.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/layers/test_roi_align_rotated.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_anchor_generator.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_box2box_transform.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_fast_rcnn.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_matcher.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_model_e2e.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_roi_heads.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_roi_pooler.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_rpn.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/structures/__init__.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/structures/test_boxes.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/structures/test_imagelist.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/structures/test_instances.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/structures/test_rotated_boxes.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_checkpoint.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_config.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_engine.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_export_caffe2.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_model_analysis.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_model_zoo.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_visualizer.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/README.md mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/analyze_model.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/benchmark.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/convert-torchvision-to-d2.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/plain_train_net.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/train_net.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/visualize_data.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/visualize_json_results.py mode change 100755 => 100644 PyTorch/built-in/cv/detection/YoloV3_ID1790_for_PyTorch/tools/dist_test.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/.keep mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/Dockerfile mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/README.md mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/dataset.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/demo.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/docker_start.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/evalOnePic.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/models.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/modelzoo_level.txt mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/pth2onnx.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/requirements.txt mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/scripts/demo.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/scripts/eval.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/scripts/pth2onnx.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/scripts/set_npu_env.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/scripts/train_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/scripts/train_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/test/demo.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/test/pth2onnx.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/test/train_eval_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/test/train_full_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/test/train_full_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/test/train_performance_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/test/train_performance_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/train_1p.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/train_8p.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/DnCNN/utils.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/MnasNet/infer/convert/aipp.aipconfig mode change 100755 => 100644 PyTorch/contrib/cv/classification/MnasNet/infer/convert/onnx2om.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/MnasNet/infer/mxbase/CMakeLists.txt mode change 100755 => 100644 PyTorch/contrib/cv/classification/MnasNet/infer/mxbase/Mnasnet.cpp mode change 100755 => 100644 PyTorch/contrib/cv/classification/MnasNet/infer/mxbase/Mnasnet.h mode change 100755 => 100644 PyTorch/contrib/cv/classification/MnasNet/infer/mxbase/build.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/MnasNet/infer/mxbase/main.cpp mode change 100755 => 100644 PyTorch/contrib/cv/classification/MnasNet/infer/mxbase/run.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/MnasNet/infer/sdk/main.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/MnasNet/infer/sdk/mnasnet_aipp.cfg mode change 100755 => 100644 PyTorch/contrib/cv/classification/MnasNet/infer/sdk/mnasnet_opencv.pipeline mode change 100755 => 100644 PyTorch/contrib/cv/classification/MnasNet/infer/sdk/run.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/MnasNet/infer/util/classification_task_metric.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/Dockerfile mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/LICENSE mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/README.md mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/demo.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/docker_start.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/mobilenet.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/modelzoo_level.txt mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/pthtar2onnx.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/requirements.txt mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/scripts/eval.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/scripts/run_2onnx.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/scripts/run_demo.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/scripts/train_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/scripts/train_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/test/env_npu.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/test/run_2onnx.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/test/run_demo.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/test/train_eval_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/test/train_full_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/test/train_full_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/test/train_performance_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/MobileNet/test/train_performance_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/OSNet/main.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/RegNetY-1.6GF/utils/progress/setup.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/RegNetY-1.6GF/utils/progress/test_progress.py delete mode 100644 PyTorch/contrib/cv/classification/RepVGG/arch.PNG delete mode 100644 PyTorch/contrib/cv/classification/RepVGG/speed_acc.PNG delete mode 100644 PyTorch/contrib/cv/classification/RepVGG/table.PNG mode change 100755 => 100644 PyTorch/contrib/cv/classification/SENet154/README.md mode change 100755 => 100644 PyTorch/contrib/cv/classification/SENet154/checkpoint.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/SENet154/data.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/SENet154/demo.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/SENet154/lsr.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/SENet154/modelzoo_level.txt mode change 100755 => 100644 PyTorch/contrib/cv/classification/SENet154/pth2onnx.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/SENet154/senet.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/SENet154/test/env_npu.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/SENet154/test/run_2onnx.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/SENet154/test/run_demo.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/SENet154/test/train_eval_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/SENet154/test/train_full_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/SENet154/test/train_full_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/SENet154/test/train_performance_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/SENet154/test/train_performance_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/SENet154/train.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/SENet154/utils.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/Dockerfile mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/LICENSE mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/README.md mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/demo.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/docker_start.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/main.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/modelzoo_level.txt mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/pthtar2onnx.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/requirements.txt mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/scripts/eval.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/scripts/npu_set_env.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/scripts/train_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/scripts/train_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/senet.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/test/env_npu.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/test/train_eval_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/test/train_full_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/test/train_full_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/test/train_performance_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/test/train_performance_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/SkresNet50/scripts/eval.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/SkresNet50/scripts/npu_setenv.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/SkresNet50/scripts/train_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/SkresNet50/scripts/train_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/SkresNet50/utils/progress/setup.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/SkresNet50/utils/progress/test_progress.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/VOLO/prof_demo.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/VOLO/test/train_full_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/VOLO/test/train_performance_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/Vit_small_patch16_224/distributed_train.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/Vit_small_patch16_224/distributed_train_npu.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/Vit_small_patch16_224/train.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/VoVNet39/test/train_eval_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/VoVNet39/test/train_finetune_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/VoVNet39/test/train_full_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/VoVNet39/test/train_performance_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/VoVNet39/test/train_performance_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/classification/csp_resnext50-mish/benchmark.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/csp_resnext50-mish/train-1p.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/csp_resnext50-mish/train-8p.py mode change 100755 => 100644 PyTorch/contrib/cv/classification/csp_resnext50-mish/validate.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/CenterNet/src/lib/detectors/base_detector.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/CenterNet/src/lib/detectors/ctdet.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/CenterNet/src/lib/detectors/ddd.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/CenterNet/src/lib/detectors/exdet.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/CenterNet/src/lib/detectors/multi_pose.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/CenterNet/src/lib/models/networks/DCNv2/make.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/CenterNet/src/lib/opts.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/CenterNet/src/lib/trains/base_trainer.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/CenterNet/src/lib/trains/ctdet.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/CenterNet/src/lib/trains/ddd.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/CenterNet/src/lib/trains/exdet.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/CenterNet/src/lib/trains/multi_pose.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/CenterNet/src/lib/utils/__init__.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/CenterNet/src/lib/utils/image.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/CenterNet/src/main.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/CenterNet/src/test.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/CenterNet/src/tools/reval.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/FCOS/scripts/train_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/FCOS/scripts/train_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/FCOS/tools/dist_train.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/data/config/fsaf.pipeline mode change 100755 => 100644 PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/CMakeLists.txt mode change 100755 => 100644 PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/build.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/src/fsaf.cpp mode change 100755 => 100644 PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/src/fsaf.h mode change 100755 => 100644 PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/src/main.cpp mode change 100755 => 100644 PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/sdk/run.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/util/coco_eval.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/util/txt_to_json.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/FSAF_for_Pytorch/mmdetection/tools/dist_train.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/FSAF_for_Pytorch/mmdetection/tools/slurm_test.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/FSAF_for_Pytorch/mmdetection/tools/slurm_train.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/FSAF_for_Pytorch/scripts/train_8p.sh delete mode 100644 PyTorch/contrib/cv/detection/SOLOv1/mmcv/README.rst delete mode 100644 PyTorch/contrib/cv/detection/SOLOv2/mmcv/README.rst mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/Dockerfile mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/LICENSE mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/README.md mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/README_raw.md mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/convert_to_caffe2_models.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/demo.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/docker_start.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/draw_eval_results.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/eval_ssd.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/extract_tf_weights.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/modelzoo_level.txt mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/open_images_downloader.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/prune_alexnet.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/requirements.txt mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/run_ssd_example.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/run_ssd_live_caffe2.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/run_ssd_live_demo.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/scripts/eval.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/scripts/set_npu_env.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/scripts/train_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/scripts/train_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/test/env_npu.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/test/train_finetune_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/test/train_full_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/test/train_full_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/test/train_performance_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/test/train_performance_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/train_ssd.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/translate_tf_mobilenetv1.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/datasets/collation.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/datasets/generate_vocdata.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/datasets/open_images.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/datasets/voc_dataset.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/alexnet.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/mobilenet.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/mobilenet_v2.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/mobilenetv3.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/multibox_loss.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/scaled_l2_norm.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/squeezenet.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/vgg.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/prunning/prunner.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/config/mobilenetv1_ssd_config.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/config/squeezenet_ssd_config.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/config/vgg_ssd_config.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/data_preprocessing.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/fpn_mobilenetv1_ssd.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/fpn_ssd.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/mobilenet_v2_ssd_lite.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/mobilenetv1_ssd.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/mobilenetv1_ssd_lite.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/mobilenetv3_ssd_lite.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/predictor.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/squeezenet_ssd_lite.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/ssd.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/vgg_ssd.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/test/test_vgg_ssd.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/transforms/transforms.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/utils/__init__.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/utils/box_utils.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/utils/box_utils_numpy.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/utils/measurements.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/utils/misc.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/utils/model_book.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD-MobilenetV2/visual_tf_models.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD/scripts/eval.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD/scripts/eval_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD/scripts/npu_set_env.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD/scripts/train_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD/scripts/train_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD/setup.py mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD/tools/dist_test.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD/tools/dist_train.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD/tools/slurm_test.sh mode change 100755 => 100644 PyTorch/contrib/cv/detection/SSD/tools/slurm_train.sh create mode 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/data/valid.csv create mode 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/config/hourglass.pipeline create mode 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/convert/atc.sh create mode 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/docker_start_infer.sh create mode 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/CMakeLists.txt create mode 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/build.sh create mode 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/include/hourglass.h create mode 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/include/postprocess.h create mode 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/src/hourglass.cpp create mode 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/src/main.cpp create mode 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/src/postprocess.cpp create mode 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/cal_accuracy.py create mode 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/main.py create mode 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/postprocess.py create mode 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/preprocess.py create mode 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/run.sh mode change 100755 => 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/docs/merge_docs.sh mode change 100755 => 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/tests/data/interhand2d/test_interhand2d_camera.json mode change 100755 => 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/tests/data/interhand2d/test_interhand2d_data.json mode change 100755 => 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/tests/data/interhand2d/test_interhand2d_joint_3d.json mode change 100755 => 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/tests/data/panoptic/test_panoptic.json mode change 100755 => 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/tools/dist_test.sh mode change 100755 => 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/tools/dist_train.sh create mode 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/modelarts/selfexport.py create mode 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/modelarts/start.py delete mode 100644 PyTorch/contrib/cv/semantic_segmentation/HRNet_SEG_for_Pytorch/figures/OCR.PNG delete mode 100644 PyTorch/contrib/cv/semantic_segmentation/IntraDA/figure/adaptsegnet.PNG delete mode 100644 PyTorch/contrib/cv/semantic_segmentation/IntraDA/figure/advent.PNG mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/datasets/prepare_ade20k_sem_seg.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/datasets/prepare_cocofied_lvis.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/datasets/prepare_for_tests.sh mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/datasets/prepare_panoptic_fpn.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/demo/demo.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/linter.sh mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/packaging/build_all_wheels.sh mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/packaging/build_wheel.sh mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/packaging/gen_install_table.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/packaging/gen_wheel_index.sh mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/packaging/pkg_helpers.bash mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/parse_results.sh mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/run_inference_tests.sh mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/run_instant_tests.sh mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/projects/PointRend/train_net.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/analyze_model.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/benchmark.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/convert-torchvision-to-d2.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/deploy/export_model.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/lazyconfig_train_net.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/plain_train_net.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/train_net.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/visualize_data.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/visualize_json_results.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/RCAN/dataset.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/RCAN/main.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/RCAN/model.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/RCAN/test.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/RCAN/test/run_1p_prof.sh mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/RCAN/test/run_test.sh mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/RCAN/test/set_npu_env.sh mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/RCAN/test/train_finetuning_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/RCAN/test/train_full_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/RCAN/test/train_full_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/RCAN/test/train_performance_1p.sh mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/RCAN/test/train_performance_8p.sh mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/RCAN/utils.py mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/SETR/env_npu.sh mode change 100755 => 100644 PyTorch/contrib/cv/semantic_segmentation/SETR/tools/dist_train.sh mode change 100755 => 100644 PyTorch/contrib/cv/video/C3D/tools/dist_train.sh mode change 100755 => 100644 PyTorch/dev/cv/image_classification/ConvLSTM_ID1772_for_PyTorch/requirements.txt delete mode 100644 PyTorch/dev/cv/image_classification/RUC_ID2470_for_PyTorch/figure/additonal_result.PNG delete mode 100644 PyTorch/dev/cv/image_classification/RUC_ID2470_for_PyTorch/figure/model_arch.PNG delete mode 100644 PyTorch/dev/cv/image_classification/SlowFast_ID0646_for_PyTorch/detectron2/projects/Panoptic-DeepLab/configs/COCO-PanopticSegmentation/panoptic_deeplab_R_52_os16_mg124_poly_200k_bs64_crop_640_640_coco_dsconv.yaml delete mode 100644 PyTorch/dev/cv/image_classification/SlowFast_ID0646_for_PyTorch/detectron2/projects/Panoptic-DeepLab/configs/Cityscapes-PanopticSegmentation/panoptic_deeplab_R_52_os16_mg124_poly_90k_bs32_crop_512_1024.yaml delete mode 100644 PyTorch/dev/cv/image_classification/SlowFast_ID0646_for_PyTorch/detectron2/projects/Panoptic-DeepLab/configs/Cityscapes-PanopticSegmentation/panoptic_deeplab_R_52_os16_mg124_poly_90k_bs32_crop_512_1024_dsconv.yaml diff --git a/ACL_PyTorch/built-in/audio/Jasper_for_PyTorch/diff.patch b/ACL_PyTorch/built-in/audio/Jasper_for_PyTorch/diff.patch index 233b07f8af..a19857a3f0 100644 --- a/ACL_PyTorch/built-in/audio/Jasper_for_PyTorch/diff.patch +++ b/ACL_PyTorch/built-in/audio/Jasper_for_PyTorch/diff.patch @@ -1,89 +1,89 @@ -diff --git a/PyTorch/SpeechRecognition/Jasper/common/features.py b/PyTorch/SpeechRecognition/Jasper/common/features.py -index ad7a52f..af02aff 100644 ---- a/PyTorch/SpeechRecognition/Jasper/common/features.py -+++ b/PyTorch/SpeechRecognition/Jasper/common/features.py -@@ -5,7 +5,7 @@ import librosa - import torch - import torch.nn as nn - --from apex import amp -+# from apex import amp - - - class BaseFeatures(nn.Module): -@@ -46,8 +46,9 @@ class BaseFeatures(nn.Module): - dtype = audio.dtype - audio = audio.float() - if optim_level == 1: -- with amp.disable_casts(): -- feat, feat_lens = self.calculate_features(audio, audio_lens) -+ pass -+ # with amp.disable_casts(): -+ # feat, feat_lens = self.calculate_features(audio, audio_lens) - else: - feat, feat_lens = self.calculate_features(audio, audio_lens) - -diff --git a/PyTorch/SpeechRecognition/Jasper/common/helpers.py b/PyTorch/SpeechRecognition/Jasper/common/helpers.py -index 742f159..c989b6e 100644 ---- a/PyTorch/SpeechRecognition/Jasper/common/helpers.py -+++ b/PyTorch/SpeechRecognition/Jasper/common/helpers.py -@@ -17,7 +17,7 @@ import os - import re - from collections import OrderedDict - --from apex import amp -+# from apex import amp - - import torch - import torch.distributed as dist -@@ -234,7 +234,8 @@ class Checkpointer(object): - 'state_dict': unwrap_ddp(model).state_dict(), - 'ema_state_dict': unwrap_ddp(ema_model).state_dict() if ema_model is not None else None, - 'optimizer': optimizer.state_dict(), -- 'amp': amp.state_dict() if self.use_amp else None, -+ # 'amp': amp.state_dict() if self.use_amp else None, -+ 'amp': None, - } - - if is_best: -@@ -293,8 +294,8 @@ class Checkpointer(object): - - optimizer.load_state_dict(checkpoint['optimizer']) - -- if self.use_amp: -- amp.load_state_dict(checkpoint['amp']) -+ # if self.use_amp: -+ # amp.load_state_dict(checkpoint['amp']) - - meta['start_epoch'] = checkpoint.get('epoch') - meta['best_wer'] = checkpoint.get('best_wer', meta['best_wer']) -diff --git a/PyTorch/SpeechRecognition/Jasper/jasper/model.py b/PyTorch/SpeechRecognition/Jasper/jasper/model.py -index dd38ce4..86ccb91 100644 ---- a/PyTorch/SpeechRecognition/Jasper/jasper/model.py -+++ b/PyTorch/SpeechRecognition/Jasper/jasper/model.py -@@ -66,14 +66,22 @@ class MaskedConv1d(nn.Conv1d): - self.masked = masked - - def get_seq_len(self, lens): -- return ((lens + 2 * self.padding[0] - self.dilation[0] -- * (self.kernel_size[0] - 1) - 1) // self.stride[0] + 1) -+ if torch.onnx.is_in_onnx_export(): -+ return ((lens + 2. * self.padding[0] - self.dilation[0] -+ * (self.kernel_size[0] - 1.) - 1.) // self.stride[0] + 1.).int() -+ else: -+ return ((lens + 2 * self.padding[0] - self.dilation[0] -+ * (self.kernel_size[0] - 1) - 1) // self.stride[0] + 1) - - def forward(self, x, x_lens=None): - if self.masked: - max_len = x.size(2) - idxs = torch.arange(max_len, dtype=x_lens.dtype, device=x_lens.device) -- mask = idxs.expand(x_lens.size(0), max_len) >= x_lens.unsqueeze(1) -+ if torch.onnx.is_in_onnx_export(): -+ temp = torch.zeros(x_lens.size(0), max_len) -+ mask = idxs.expand_as(temp) >= x_lens.unsqueeze(1) -+ else: -+ mask = idxs.expand(x_lens.size(0), max_len) >= x_lens.unsqueeze(1) - x = x.masked_fill(mask.unsqueeze(1).to(device=x.device), 0) - x_lens = self.get_seq_len(x_lens) +diff --git a/PyTorch/SpeechRecognition/Jasper/common/features.py b/PyTorch/SpeechRecognition/Jasper/common/features.py +index ad7a52f..af02aff 100644 +--- a/PyTorch/SpeechRecognition/Jasper/common/features.py ++++ b/PyTorch/SpeechRecognition/Jasper/common/features.py +@@ -5,7 +5,7 @@ import librosa + import torch + import torch.nn as nn + +-from apex import amp ++# from apex import amp + + + class BaseFeatures(nn.Module): +@@ -46,8 +46,9 @@ class BaseFeatures(nn.Module): + dtype = audio.dtype + audio = audio.float() + if optim_level == 1: +- with amp.disable_casts(): +- feat, feat_lens = self.calculate_features(audio, audio_lens) ++ pass ++ # with amp.disable_casts(): ++ # feat, feat_lens = self.calculate_features(audio, audio_lens) + else: + feat, feat_lens = self.calculate_features(audio, audio_lens) + +diff --git a/PyTorch/SpeechRecognition/Jasper/common/helpers.py b/PyTorch/SpeechRecognition/Jasper/common/helpers.py +index 742f159..c989b6e 100644 +--- a/PyTorch/SpeechRecognition/Jasper/common/helpers.py ++++ b/PyTorch/SpeechRecognition/Jasper/common/helpers.py +@@ -17,7 +17,7 @@ import os + import re + from collections import OrderedDict + +-from apex import amp ++# from apex import amp + + import torch + import torch.distributed as dist +@@ -234,7 +234,8 @@ class Checkpointer(object): + 'state_dict': unwrap_ddp(model).state_dict(), + 'ema_state_dict': unwrap_ddp(ema_model).state_dict() if ema_model is not None else None, + 'optimizer': optimizer.state_dict(), +- 'amp': amp.state_dict() if self.use_amp else None, ++ # 'amp': amp.state_dict() if self.use_amp else None, ++ 'amp': None, + } + + if is_best: +@@ -293,8 +294,8 @@ class Checkpointer(object): + + optimizer.load_state_dict(checkpoint['optimizer']) + +- if self.use_amp: +- amp.load_state_dict(checkpoint['amp']) ++ # if self.use_amp: ++ # amp.load_state_dict(checkpoint['amp']) + + meta['start_epoch'] = checkpoint.get('epoch') + meta['best_wer'] = checkpoint.get('best_wer', meta['best_wer']) +diff --git a/PyTorch/SpeechRecognition/Jasper/jasper/model.py b/PyTorch/SpeechRecognition/Jasper/jasper/model.py +index dd38ce4..86ccb91 100644 +--- a/PyTorch/SpeechRecognition/Jasper/jasper/model.py ++++ b/PyTorch/SpeechRecognition/Jasper/jasper/model.py +@@ -66,14 +66,22 @@ class MaskedConv1d(nn.Conv1d): + self.masked = masked + + def get_seq_len(self, lens): +- return ((lens + 2 * self.padding[0] - self.dilation[0] +- * (self.kernel_size[0] - 1) - 1) // self.stride[0] + 1) ++ if torch.onnx.is_in_onnx_export(): ++ return ((lens + 2. * self.padding[0] - self.dilation[0] ++ * (self.kernel_size[0] - 1.) - 1.) // self.stride[0] + 1.).int() ++ else: ++ return ((lens + 2 * self.padding[0] - self.dilation[0] ++ * (self.kernel_size[0] - 1) - 1) // self.stride[0] + 1) + + def forward(self, x, x_lens=None): + if self.masked: + max_len = x.size(2) + idxs = torch.arange(max_len, dtype=x_lens.dtype, device=x_lens.device) +- mask = idxs.expand(x_lens.size(0), max_len) >= x_lens.unsqueeze(1) ++ if torch.onnx.is_in_onnx_export(): ++ temp = torch.zeros(x_lens.size(0), max_len) ++ mask = idxs.expand_as(temp) >= x_lens.unsqueeze(1) ++ else: ++ mask = idxs.expand(x_lens.size(0), max_len) >= x_lens.unsqueeze(1) + x = x.masked_fill(mask.unsqueeze(1).to(device=x.device), 0) + x_lens = self.get_seq_len(x_lens) \ No newline at end of file diff --git a/ACL_PyTorch/built-in/audio/Jasper_for_PyTorch/pth2onnx.py b/ACL_PyTorch/built-in/audio/Jasper_for_PyTorch/pth2onnx.py index 8d30c4f05c..0f635ab23d 100644 --- a/ACL_PyTorch/built-in/audio/Jasper_for_PyTorch/pth2onnx.py +++ b/ACL_PyTorch/built-in/audio/Jasper_for_PyTorch/pth2onnx.py @@ -1,44 +1,44 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -from jasper import config -from common import helpers -from jasper.model import Jasper - - -def main(): - cfg = config.load('configs/jasper10x5dr_speedp-online_speca.yaml') - model = Jasper(encoder_kw=config.encoder(cfg), - decoder_kw=config.decoder(cfg, n_classes=29)) - checkpoint = torch.load('checkpoints/jasper_fp16.pt', map_location="cpu") - state_dict = helpers.convert_v1_state_dict(checkpoint['ema_state_dict']) - model.load_state_dict(state_dict, strict=True) - model.eval() - - feats = torch.randn([4, 64, 4000], dtype=torch.float32) - feat_lens = torch.Tensor([1000], dtype=torch.int32) - dynamic_axes = {'feats': {2: '-1'}, 'output': {1, '-1'}} - torch.onnx.export(model, - (feats, feat_lens), - 'jasper_dynamic.onnx', - input_names=['feats', 'feat_lens'], - output_names=['output'], - dynamic_axes=dynamic_axes, - verbose=True, - opset_version=11) - - -if __name__ == '__main__': - main() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +from jasper import config +from common import helpers +from jasper.model import Jasper + + +def main(): + cfg = config.load('configs/jasper10x5dr_speedp-online_speca.yaml') + model = Jasper(encoder_kw=config.encoder(cfg), + decoder_kw=config.decoder(cfg, n_classes=29)) + checkpoint = torch.load('checkpoints/jasper_fp16.pt', map_location="cpu") + state_dict = helpers.convert_v1_state_dict(checkpoint['ema_state_dict']) + model.load_state_dict(state_dict, strict=True) + model.eval() + + feats = torch.randn([4, 64, 4000], dtype=torch.float32) + feat_lens = torch.Tensor([1000], dtype=torch.int32) + dynamic_axes = {'feats': {2: '-1'}, 'output': {1, '-1'}} + torch.onnx.export(model, + (feats, feat_lens), + 'jasper_dynamic.onnx', + input_names=['feats', 'feat_lens'], + output_names=['output'], + dynamic_axes=dynamic_axes, + verbose=True, + opset_version=11) + + +if __name__ == '__main__': + main() diff --git a/ACL_PyTorch/built-in/audio/Jasper_for_PyTorch/requirements.txt b/ACL_PyTorch/built-in/audio/Jasper_for_PyTorch/requirements.txt index 36faa7e8ae..5ad9b7d6cc 100644 --- a/ACL_PyTorch/built-in/audio/Jasper_for_PyTorch/requirements.txt +++ b/ACL_PyTorch/built-in/audio/Jasper_for_PyTorch/requirements.txt @@ -1,16 +1,16 @@ -torchvision==0.9.0 -torch==1.8.0 -onnx==1.8.0 -numpy==1.18.5 -ascii-graph==1.5.1 -inflect==5.3.0 -ipdb -librosa==0.8.0 -pandas==1.1.4 -pycuda==2020.1 -pyyaml>=5.4 -soundfile -sox==1.4.1 -tqdm==4.53.0 -unidecode==1.2.0 +torchvision==0.9.0 +torch==1.8.0 +onnx==1.8.0 +numpy==1.18.5 +ascii-graph==1.5.1 +inflect==5.3.0 +ipdb +librosa==0.8.0 +pandas==1.1.4 +pycuda==2020.1 +pyyaml>=5.4 +soundfile +sox==1.4.1 +tqdm==4.53.0 +unidecode==1.2.0 wrapt==1.10.11 \ No newline at end of file diff --git a/ACL_PyTorch/built-in/audio/LSTM/LICENSE b/ACL_PyTorch/built-in/audio/LSTM/LICENSE index 6052d47b9e..835428fbaa 100644 --- a/ACL_PyTorch/built-in/audio/LSTM/LICENSE +++ b/ACL_PyTorch/built-in/audio/LSTM/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/built-in/audio/LSTM/LSTM_get_info.py b/ACL_PyTorch/built-in/audio/LSTM/LSTM_get_info.py index ea8300ce45..f89051ed81 100644 --- a/ACL_PyTorch/built-in/audio/LSTM/LSTM_get_info.py +++ b/ACL_PyTorch/built-in/audio/LSTM/LSTM_get_info.py @@ -1,34 +1,34 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import argparse - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument('--batchsize', help='conf file for training') - args = parser.parse_args() - - test_num = 400 // int(args.batchsize) - lstm_path = './lstm_bin/' - - with open('./lstm.info', 'w') as f: - for i in range(test_num): - ids_name = lstm_path + 'inputs_{}.bin'.format(i) - f.write(str(i) + ' ' + ids_name + ' ' + '(' + args.batchsize + ',390,243)') - f.write('\n') - -if __name__ == '__main__': +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import argparse + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--batchsize', help='conf file for training') + args = parser.parse_args() + + test_num = 400 // int(args.batchsize) + lstm_path = './lstm_bin/' + + with open('./lstm.info', 'w') as f: + for i in range(test_num): + ids_name = lstm_path + 'inputs_{}.bin'.format(i) + f.write(str(i) + ' ' + ids_name + ' ' + '(' + args.batchsize + ',390,243)') + f.write('\n') + +if __name__ == '__main__': main() \ No newline at end of file diff --git a/ACL_PyTorch/built-in/audio/LSTM/LSTM_postprocess_data.py b/ACL_PyTorch/built-in/audio/LSTM/LSTM_postprocess_data.py index 4ec77e30d6..8fd0d995c6 100644 --- a/ACL_PyTorch/built-in/audio/LSTM/LSTM_postprocess_data.py +++ b/ACL_PyTorch/built-in/audio/LSTM/LSTM_postprocess_data.py @@ -1,114 +1,114 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -#!/usr/bin/python -#encoding=utf-8 - -import os -import time -import sys -import torch -import yaml -import argparse -import torch.nn as nn -import numpy as np - -sys.path.append('./') -from models.model_ctc import * -from utils.ctcDecoder import GreedyDecoder, BeamDecoder -from utils.data_loader import Vocab, SpeechDataset, SpeechDataLoader - -parser = argparse.ArgumentParser() -parser.add_argument('--conf', help='conf file for training') -parser.add_argument('--npu_path', help='infer file for postprocessing') -parser.add_argument('--batchsize', help='batchsize for postprocessing') - -class Config(object): - batch_size = 4 - dropout = 0.1 - -def test(): - args = parser.parse_args() - try: - conf = yaml.safe_load(open(args.conf,'r')) - except: - print("Config file not exist!") - sys.exit(1) - - opts = Config() - for k,v in conf.items(): - setattr(opts, k, v) - print('{:50}:{}'.format(k, v)) - - beam_width = opts.beam_width - lm_alpha = opts.lm_alpha - decoder_type = opts.decode_type - vocab_file = opts.vocab_file - - vocab = Vocab(vocab_file) - batchsize = int(args.batchsize) - - test_dataset = SpeechDataset(vocab, opts.valid_scp_path, opts.valid_lab_path, opts) - test_loader = SpeechDataLoader(test_dataset, batch_size=batchsize, shuffle=False, num_workers=opts.num_workers, pin_memory=False) - - if decoder_type == 'Greedy': - decoder = GreedyDecoder(vocab.index2word, space_idx=-1, blank_index=0) - else: - decoder = BeamDecoder(vocab.index2word, beam_width=beam_width, blank_index=0, space_idx=-1, lm_path=opts.lm_path, lm_alpha=opts.lm_alpha) - - total_wer = 0 - total_cer = 0 - start = time.time() - - npu_path = args.npu_path - test_num = 399 // batchsize - with torch.no_grad(): - for i, data in zip(range(test_num), test_loader): - inputs, input_sizes, targets, target_sizes, utt_list = data - probs_1_np = np.load('{}{}.0.npy'.format(npu_path, i)) - probs_1 = torch.from_numpy(probs_1_np) - - max_length = probs_1.size(0) - input_sizes = (input_sizes * max_length).long() - - decoded = decoder.decode(probs_1, input_sizes.numpy().tolist()) - targets, target_sizes = targets.numpy(), target_sizes.numpy() - labels = [] - for i in range(len(targets)): - label = [ vocab.index2word[num] for num in targets[i][:target_sizes[i]]] - labels.append(' '.join(label)) - - for x in range(len(targets)): - print("origin : " + labels[x]) - print("decoded: " + decoded[x]) - cer = 0 - wer = 0 - for x in range(len(labels)): - cer += decoder.cer(decoded[x], labels[x]) - wer += decoder.wer(decoded[x], labels[x]) - decoder.num_word += len(labels[x].split()) - decoder.num_char += len(labels[x]) - total_cer += cer - total_wer += wer - - CER = (float(total_cer) / decoder.num_char)*100 - WER = (float(total_wer) / decoder.num_word)*100 - print("Character error rate on test set: %.4f" % CER) - print("Word error rate on test set: %.4f" % WER) - end = time.time() - time_used = (end - start) / 60.0 - print("time used for decode %d sentences: %.4f minutes." % (len(test_dataset), time_used)) - -if __name__ == "__main__": - test() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +#!/usr/bin/python +#encoding=utf-8 + +import os +import time +import sys +import torch +import yaml +import argparse +import torch.nn as nn +import numpy as np + +sys.path.append('./') +from models.model_ctc import * +from utils.ctcDecoder import GreedyDecoder, BeamDecoder +from utils.data_loader import Vocab, SpeechDataset, SpeechDataLoader + +parser = argparse.ArgumentParser() +parser.add_argument('--conf', help='conf file for training') +parser.add_argument('--npu_path', help='infer file for postprocessing') +parser.add_argument('--batchsize', help='batchsize for postprocessing') + +class Config(object): + batch_size = 4 + dropout = 0.1 + +def test(): + args = parser.parse_args() + try: + conf = yaml.safe_load(open(args.conf,'r')) + except: + print("Config file not exist!") + sys.exit(1) + + opts = Config() + for k,v in conf.items(): + setattr(opts, k, v) + print('{:50}:{}'.format(k, v)) + + beam_width = opts.beam_width + lm_alpha = opts.lm_alpha + decoder_type = opts.decode_type + vocab_file = opts.vocab_file + + vocab = Vocab(vocab_file) + batchsize = int(args.batchsize) + + test_dataset = SpeechDataset(vocab, opts.valid_scp_path, opts.valid_lab_path, opts) + test_loader = SpeechDataLoader(test_dataset, batch_size=batchsize, shuffle=False, num_workers=opts.num_workers, pin_memory=False) + + if decoder_type == 'Greedy': + decoder = GreedyDecoder(vocab.index2word, space_idx=-1, blank_index=0) + else: + decoder = BeamDecoder(vocab.index2word, beam_width=beam_width, blank_index=0, space_idx=-1, lm_path=opts.lm_path, lm_alpha=opts.lm_alpha) + + total_wer = 0 + total_cer = 0 + start = time.time() + + npu_path = args.npu_path + test_num = 399 // batchsize + with torch.no_grad(): + for i, data in zip(range(test_num), test_loader): + inputs, input_sizes, targets, target_sizes, utt_list = data + probs_1_np = np.load('{}{}.0.npy'.format(npu_path, i)) + probs_1 = torch.from_numpy(probs_1_np) + + max_length = probs_1.size(0) + input_sizes = (input_sizes * max_length).long() + + decoded = decoder.decode(probs_1, input_sizes.numpy().tolist()) + targets, target_sizes = targets.numpy(), target_sizes.numpy() + labels = [] + for i in range(len(targets)): + label = [ vocab.index2word[num] for num in targets[i][:target_sizes[i]]] + labels.append(' '.join(label)) + + for x in range(len(targets)): + print("origin : " + labels[x]) + print("decoded: " + decoded[x]) + cer = 0 + wer = 0 + for x in range(len(labels)): + cer += decoder.cer(decoded[x], labels[x]) + wer += decoder.wer(decoded[x], labels[x]) + decoder.num_word += len(labels[x].split()) + decoder.num_char += len(labels[x]) + total_cer += cer + total_wer += wer + + CER = (float(total_cer) / decoder.num_char)*100 + WER = (float(total_wer) / decoder.num_word)*100 + print("Character error rate on test set: %.4f" % CER) + print("Word error rate on test set: %.4f" % WER) + end = time.time() + time_used = (end - start) / 60.0 + print("time used for decode %d sentences: %.4f minutes." % (len(test_dataset), time_used)) + +if __name__ == "__main__": + test() diff --git a/ACL_PyTorch/built-in/audio/LSTM/LSTM_preprocess_data.py b/ACL_PyTorch/built-in/audio/LSTM/LSTM_preprocess_data.py index 75f129861d..297aa1b0d7 100644 --- a/ACL_PyTorch/built-in/audio/LSTM/LSTM_preprocess_data.py +++ b/ACL_PyTorch/built-in/audio/LSTM/LSTM_preprocess_data.py @@ -1,80 +1,80 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -# !/usr/bin/python -# encoding=utf-8 - -import os -import sys -import copy -import time -import yaml -import shutil -import argparse -import numpy as np -import random -import torch -import torch.nn as nn -import torch.backends.cudnn as cudnn -from torch.utils.tensorboard import SummaryWriter - -sys.path.append('./') -from models.model_ctc import * -from utils.data_loader import Vocab, SpeechDataset, SpeechDataLoader - -supported_rnn = {'nn.LSTM': nn.LSTM, 'nn.GRU': nn.GRU, 'nn.RNN': nn.RNN} -supported_activate = {'relu': nn.ReLU, 'tanh': nn.Tanh, 'sigmoid': nn.Sigmoid} - -parser = argparse.ArgumentParser() -parser.add_argument('--conf', help='conf file for training') -parser.add_argument('--batchsize', help='batchsize for preprocessing') - -class Config(object): - batch_size = 4 - dropout = 0.1 - -def main(): - args = parser.parse_args() - try: - conf = yaml.safe_load(open(args.conf,'r')) - except: - print("Config file not exist!") - sys.exit(1) - - opts = Config() - for k,v in conf.items(): - setattr(opts, k, v) - print('{:50}:{}'.format(k, v)) - - # Data Loader - batchsize = int(args.batchsize) - vocab = Vocab(opts.vocab_file) - dev_dataset = SpeechDataset(vocab, opts.valid_scp_path, opts.valid_lab_path, opts) - dev_loader = SpeechDataLoader(dev_dataset, batch_size=batchsize, shuffle=False, num_workers=opts.num_workers, - drop_last=True, pin_memory=True) - - bin_path = "./lstm_bin" - if os.path.exists(bin_path): - shutil.rmtree(bin_path) - os.makedirs(bin_path) - i = -1 - for data in dev_loader: - i = i + 1 - print("[info] file", "===", i) - inputs, input_sizes, targets, target_sizes, utt_list = data - inputs_np = inputs.numpy() - inputs_np.tofile(os.path.join(bin_path, "inputs_" + str(i) + '.bin')) - -if __name__ == '__main__': - main() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +# !/usr/bin/python +# encoding=utf-8 + +import os +import sys +import copy +import time +import yaml +import shutil +import argparse +import numpy as np +import random +import torch +import torch.nn as nn +import torch.backends.cudnn as cudnn +from torch.utils.tensorboard import SummaryWriter + +sys.path.append('./') +from models.model_ctc import * +from utils.data_loader import Vocab, SpeechDataset, SpeechDataLoader + +supported_rnn = {'nn.LSTM': nn.LSTM, 'nn.GRU': nn.GRU, 'nn.RNN': nn.RNN} +supported_activate = {'relu': nn.ReLU, 'tanh': nn.Tanh, 'sigmoid': nn.Sigmoid} + +parser = argparse.ArgumentParser() +parser.add_argument('--conf', help='conf file for training') +parser.add_argument('--batchsize', help='batchsize for preprocessing') + +class Config(object): + batch_size = 4 + dropout = 0.1 + +def main(): + args = parser.parse_args() + try: + conf = yaml.safe_load(open(args.conf,'r')) + except: + print("Config file not exist!") + sys.exit(1) + + opts = Config() + for k,v in conf.items(): + setattr(opts, k, v) + print('{:50}:{}'.format(k, v)) + + # Data Loader + batchsize = int(args.batchsize) + vocab = Vocab(opts.vocab_file) + dev_dataset = SpeechDataset(vocab, opts.valid_scp_path, opts.valid_lab_path, opts) + dev_loader = SpeechDataLoader(dev_dataset, batch_size=batchsize, shuffle=False, num_workers=opts.num_workers, + drop_last=True, pin_memory=True) + + bin_path = "./lstm_bin" + if os.path.exists(bin_path): + shutil.rmtree(bin_path) + os.makedirs(bin_path) + i = -1 + for data in dev_loader: + i = i + 1 + print("[info] file", "===", i) + inputs, input_sizes, targets, target_sizes, utt_list = data + inputs_np = inputs.numpy() + inputs_np.tofile(os.path.join(bin_path, "inputs_" + str(i) + '.bin')) + +if __name__ == '__main__': + main() diff --git a/ACL_PyTorch/built-in/audio/LSTM/LSTM_pth2onnx.py b/ACL_PyTorch/built-in/audio/LSTM/LSTM_pth2onnx.py index 0b68d2f795..2aa34a62a3 100644 --- a/ACL_PyTorch/built-in/audio/LSTM/LSTM_pth2onnx.py +++ b/ACL_PyTorch/built-in/audio/LSTM/LSTM_pth2onnx.py @@ -1,231 +1,231 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -#!/usr/bin/python -#encoding=utf-8 - -import os -import sys -import copy -import time -import yaml -import argparse -import numpy as np -import random -import torch -import torch.nn as nn -import torch.backends.cudnn as cudnn -from torch.utils.tensorboard import SummaryWriter -import torch.onnx -from collections import OrderedDict -import ssl -sys.path.append('./') -from models.model_ctc import * - -supported_rnn = {'nn.LSTM':nn.LSTM, 'nn.GRU': nn.GRU, 'nn.RNN':nn.RNN} -supported_activate = {'relu':nn.ReLU, 'tanh':nn.Tanh, 'sigmoid':nn.Sigmoid} - -parser = argparse.ArgumentParser(description='cnn_lstm_ctc') -parser.add_argument('--conf', default='conf/ctc_config.yaml' , help='conf file with argument of LSTM and training') -parser.add_argument('--batchsize', default=1, help='batchszie for transfer onnx batch') - -class Vocab(object): - def __init__(self, vocab_file): - self.vocab_file = vocab_file - self.word2index = {"blank": 0, "UNK": 1} - self.index2word = {0: "blank", 1: "UNK"} - self.word2count = {} - self.n_words = 2 - self.read_lang() - - def add_sentence(self, sentence): - for word in sentence.split(' '): - self.add_word(word) - - def add_word(self, word): - if word not in self.word2index: - self.word2index[word] = self.n_words - self.word2count[word] = 1 - self.index2word[self.n_words] = word - self.n_words += 1 - else: - self.word2count[word] += 1 - - def read_lang(self): - print("Reading vocabulary from {}".format(self.vocab_file)) - with open(self.vocab_file, 'r') as rf: - line = rf.readline() - while line: - line = line.strip().split(' ') - if len(line) > 1: - sen = ' '.join(line[1:]) - else: - sen = line[0] - self.add_sentence(sen) - line = rf.readline() - print("Vocabulary size is {}".format(self.n_words)) - - -def proc_nodes_module(checkpoint,AttrName): - new_state_dict = OrderedDict() - for k,v in checkpoint[AttrName].items(): - if(k[0:7] == "module."): - name = k[7:] - else: - name = k[0:] - - new_state_dict[name]=v - return new_state_dict - -def run_epoch(epoch_id, model, data_iter, loss_fn, device, opts, sum_writer, optimizer=None, print_every=20, is_training=True): - if is_training: - model.train() - else: - model.eval() - batch_time = 0 - data_time = 0 - total_loss = 0 - total_tokens = 0 - total_errs = 0 - cur_loss = 0 - i = 0 - steps_per_epoch = len(data_iter) - end = time.time() - for i, data in enumerate(data_iter): - data_time += (time.time() - end) - - global_step = epoch_id * steps_per_epoch + i - inputs, input_sizes, targets, target_sizes, utt_list = data - with torch.autograd.profiler.profile(record_shapes=True, use_cuda=True) as prof: - inputs = inputs.to(device) - input_sizes = input_sizes.to(device) - targets = targets.to(device) - target_sizes = target_sizes.to(device) - out = model(inputs) - out_len, batch_size, _ = out.size() - input_sizes = (input_sizes * out_len).long() - print(out.shape, targets.shape) - print("input_sizes:", input_sizes.shape) - print("target_sizes:", target_sizes.shape) - loss = loss_fn(out, targets, input_sizes, target_sizes) - loss /= batch_size - cur_loss += loss.item() - total_loss += loss.item() - prob, index = torch.max(out, dim=-1) - batch_errs, batch_tokens = model.compute_wer(index.transpose(0,1).cpu().numpy(), input_sizes.cpu().numpy(), targets.cpu().numpy(), target_sizes.cpu().numpy()) - total_errs += batch_errs - total_tokens += batch_tokens - - if is_training: - optimizer.zero_grad() - if opts.opt_level and opts.use_gpu: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.step() - sum_writer.add_scalar('Accuary/train/total_loss', total_loss / (i+1), global_step) - sum_writer.add_scalar('Accuary/train/total_wer', total_errs / total_tokens, global_step) - prof.export_chrome_trace('prof/'+str(i) + "_cuda_lstm.prof") - batch_time += (time.time() - end) - if is_training: - print('Epoch: [%d] [%d / %d], Time %.6f Data %.6f s, total_loss = %.5f s, total_wer = %.5f' % (epoch_id, - i+1, steps_per_epoch, batch_time / (i+1), data_time / (i+1), total_loss / (i+1), total_errs / total_tokens )) - end = time.time() - - - average_loss = total_loss / (i+1) - training = "Train" if is_training else "Valid" - return 1-total_errs / total_tokens, average_loss - -class Config(object): - batch_size = 4 - dropout = 0.1 - -def seed_everything(seed): - random.seed(seed) - os.environ['PYTHONHASHSEED'] = str(seed) - np.random.seed(seed) - torch.manual_seed(seed) - torch.cuda.manual_seed(seed) - torch.cuda.manual_seed_all(seed) - cudnn.deterministic = True - torch.backends.cudnn.deterministic = True - torch.backends.cudnn.benchmark = False - -def main(conf, batchsize): - checkpoint = torch.load("./checkpoint/ctc_fbank_cnn/ctc_best_model.pth", map_location='cpu') - checkpoint['state_dict'] = proc_nodes_module(checkpoint,'state_dict') - opts = Config() - for k, v in conf.items(): - setattr(opts, k, v) - print('{:50}:{}'.format(k, v)) - - device = torch.device('cpu') - sum_writer = SummaryWriter(opts.summary_path) - - if opts.seed is not None: - seed_everything(opts.seed) - - #Data Loader - vocab = Vocab(opts.vocab_file) - #Define Model - rnn_type = supported_rnn[opts.rnn_type] - rnn_param = {"rnn_input_size":opts.rnn_input_size, "rnn_hidden_size":opts.rnn_hidden_size, "rnn_layers":opts.rnn_layers, - "rnn_type":rnn_type, "bidirectional":opts.bidirectional, "batch_norm":opts.batch_norm} - - num_class = vocab.n_words - opts.output_class_dim = vocab.n_words - drop_out = opts.drop_out - add_cnn = opts.add_cnn - - cnn_param = {} - channel = eval(opts.channel) - kernel_size = eval(opts.kernel_size) - stride = eval(opts.stride) - padding = eval(opts.padding) - pooling = eval(opts.pooling) - activation_function = supported_activate[opts.activation_function] - cnn_param['batch_norm'] = opts.batch_norm - cnn_param['activate_function'] = activation_function - cnn_param["layer"] = [] - for layer in range(opts.layers): - layer_param = [channel[layer], kernel_size[layer], stride[layer], padding[layer]] - if pooling is not None: - layer_param.append(pooling[layer]) - else: - layer_param.append(None) - cnn_param["layer"].append(layer_param) - model = CTC_Model(add_cnn=add_cnn, cnn_param=cnn_param, rnn_param=rnn_param, num_class=num_class, drop_out=drop_out) - model = model.to('cpu') - model.load_state_dict(checkpoint['state_dict'],strict=False) - model.eval() - input_names = ["actual_input_1"] - output_names = ["output1"] - batch_size = int(batchsize) - dummy_input = torch.randn(batch_size, 390, 243, device='cpu') - dynamic_axes = {'actual_input_1': {0: '-1'}, 'output1': {1: '-1'}} - output_file = "lstm_ctc_{}batch.onnx".format(str(batch_size)) - torch.onnx.export(model, dummy_input, output_file, input_names = input_names, output_names = output_names, opset_version=11) -if __name__ == '__main__': - ssl._create_default_https_context = ssl._create_unverified_context - args = parser.parse_args() - batchsize = args.batchsize - try: - config_path = args.conf - conf = yaml.safe_load(open(config_path, 'r')) - except: - print("No input config or config file missing, please check.") - sys.exit(1) - main(conf, batchsize) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +#!/usr/bin/python +#encoding=utf-8 + +import os +import sys +import copy +import time +import yaml +import argparse +import numpy as np +import random +import torch +import torch.nn as nn +import torch.backends.cudnn as cudnn +from torch.utils.tensorboard import SummaryWriter +import torch.onnx +from collections import OrderedDict +import ssl +sys.path.append('./') +from models.model_ctc import * + +supported_rnn = {'nn.LSTM':nn.LSTM, 'nn.GRU': nn.GRU, 'nn.RNN':nn.RNN} +supported_activate = {'relu':nn.ReLU, 'tanh':nn.Tanh, 'sigmoid':nn.Sigmoid} + +parser = argparse.ArgumentParser(description='cnn_lstm_ctc') +parser.add_argument('--conf', default='conf/ctc_config.yaml' , help='conf file with argument of LSTM and training') +parser.add_argument('--batchsize', default=1, help='batchszie for transfer onnx batch') + +class Vocab(object): + def __init__(self, vocab_file): + self.vocab_file = vocab_file + self.word2index = {"blank": 0, "UNK": 1} + self.index2word = {0: "blank", 1: "UNK"} + self.word2count = {} + self.n_words = 2 + self.read_lang() + + def add_sentence(self, sentence): + for word in sentence.split(' '): + self.add_word(word) + + def add_word(self, word): + if word not in self.word2index: + self.word2index[word] = self.n_words + self.word2count[word] = 1 + self.index2word[self.n_words] = word + self.n_words += 1 + else: + self.word2count[word] += 1 + + def read_lang(self): + print("Reading vocabulary from {}".format(self.vocab_file)) + with open(self.vocab_file, 'r') as rf: + line = rf.readline() + while line: + line = line.strip().split(' ') + if len(line) > 1: + sen = ' '.join(line[1:]) + else: + sen = line[0] + self.add_sentence(sen) + line = rf.readline() + print("Vocabulary size is {}".format(self.n_words)) + + +def proc_nodes_module(checkpoint,AttrName): + new_state_dict = OrderedDict() + for k,v in checkpoint[AttrName].items(): + if(k[0:7] == "module."): + name = k[7:] + else: + name = k[0:] + + new_state_dict[name]=v + return new_state_dict + +def run_epoch(epoch_id, model, data_iter, loss_fn, device, opts, sum_writer, optimizer=None, print_every=20, is_training=True): + if is_training: + model.train() + else: + model.eval() + batch_time = 0 + data_time = 0 + total_loss = 0 + total_tokens = 0 + total_errs = 0 + cur_loss = 0 + i = 0 + steps_per_epoch = len(data_iter) + end = time.time() + for i, data in enumerate(data_iter): + data_time += (time.time() - end) + + global_step = epoch_id * steps_per_epoch + i + inputs, input_sizes, targets, target_sizes, utt_list = data + with torch.autograd.profiler.profile(record_shapes=True, use_cuda=True) as prof: + inputs = inputs.to(device) + input_sizes = input_sizes.to(device) + targets = targets.to(device) + target_sizes = target_sizes.to(device) + out = model(inputs) + out_len, batch_size, _ = out.size() + input_sizes = (input_sizes * out_len).long() + print(out.shape, targets.shape) + print("input_sizes:", input_sizes.shape) + print("target_sizes:", target_sizes.shape) + loss = loss_fn(out, targets, input_sizes, target_sizes) + loss /= batch_size + cur_loss += loss.item() + total_loss += loss.item() + prob, index = torch.max(out, dim=-1) + batch_errs, batch_tokens = model.compute_wer(index.transpose(0,1).cpu().numpy(), input_sizes.cpu().numpy(), targets.cpu().numpy(), target_sizes.cpu().numpy()) + total_errs += batch_errs + total_tokens += batch_tokens + + if is_training: + optimizer.zero_grad() + if opts.opt_level and opts.use_gpu: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + optimizer.step() + sum_writer.add_scalar('Accuary/train/total_loss', total_loss / (i+1), global_step) + sum_writer.add_scalar('Accuary/train/total_wer', total_errs / total_tokens, global_step) + prof.export_chrome_trace('prof/'+str(i) + "_cuda_lstm.prof") + batch_time += (time.time() - end) + if is_training: + print('Epoch: [%d] [%d / %d], Time %.6f Data %.6f s, total_loss = %.5f s, total_wer = %.5f' % (epoch_id, + i+1, steps_per_epoch, batch_time / (i+1), data_time / (i+1), total_loss / (i+1), total_errs / total_tokens )) + end = time.time() + + + average_loss = total_loss / (i+1) + training = "Train" if is_training else "Valid" + return 1-total_errs / total_tokens, average_loss + +class Config(object): + batch_size = 4 + dropout = 0.1 + +def seed_everything(seed): + random.seed(seed) + os.environ['PYTHONHASHSEED'] = str(seed) + np.random.seed(seed) + torch.manual_seed(seed) + torch.cuda.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + cudnn.deterministic = True + torch.backends.cudnn.deterministic = True + torch.backends.cudnn.benchmark = False + +def main(conf, batchsize): + checkpoint = torch.load("./checkpoint/ctc_fbank_cnn/ctc_best_model.pth", map_location='cpu') + checkpoint['state_dict'] = proc_nodes_module(checkpoint,'state_dict') + opts = Config() + for k, v in conf.items(): + setattr(opts, k, v) + print('{:50}:{}'.format(k, v)) + + device = torch.device('cpu') + sum_writer = SummaryWriter(opts.summary_path) + + if opts.seed is not None: + seed_everything(opts.seed) + + #Data Loader + vocab = Vocab(opts.vocab_file) + #Define Model + rnn_type = supported_rnn[opts.rnn_type] + rnn_param = {"rnn_input_size":opts.rnn_input_size, "rnn_hidden_size":opts.rnn_hidden_size, "rnn_layers":opts.rnn_layers, + "rnn_type":rnn_type, "bidirectional":opts.bidirectional, "batch_norm":opts.batch_norm} + + num_class = vocab.n_words + opts.output_class_dim = vocab.n_words + drop_out = opts.drop_out + add_cnn = opts.add_cnn + + cnn_param = {} + channel = eval(opts.channel) + kernel_size = eval(opts.kernel_size) + stride = eval(opts.stride) + padding = eval(opts.padding) + pooling = eval(opts.pooling) + activation_function = supported_activate[opts.activation_function] + cnn_param['batch_norm'] = opts.batch_norm + cnn_param['activate_function'] = activation_function + cnn_param["layer"] = [] + for layer in range(opts.layers): + layer_param = [channel[layer], kernel_size[layer], stride[layer], padding[layer]] + if pooling is not None: + layer_param.append(pooling[layer]) + else: + layer_param.append(None) + cnn_param["layer"].append(layer_param) + model = CTC_Model(add_cnn=add_cnn, cnn_param=cnn_param, rnn_param=rnn_param, num_class=num_class, drop_out=drop_out) + model = model.to('cpu') + model.load_state_dict(checkpoint['state_dict'],strict=False) + model.eval() + input_names = ["actual_input_1"] + output_names = ["output1"] + batch_size = int(batchsize) + dummy_input = torch.randn(batch_size, 390, 243, device='cpu') + dynamic_axes = {'actual_input_1': {0: '-1'}, 'output1': {1: '-1'}} + output_file = "lstm_ctc_{}batch.onnx".format(str(batch_size)) + torch.onnx.export(model, dummy_input, output_file, input_names = input_names, output_names = output_names, opset_version=11) +if __name__ == '__main__': + ssl._create_default_https_context = ssl._create_unverified_context + args = parser.parse_args() + batchsize = args.batchsize + try: + config_path = args.conf + conf = yaml.safe_load(open(config_path, 'r')) + except: + print("No input config or config file missing, please check.") + sys.exit(1) + main(conf, batchsize) diff --git a/ACL_PyTorch/built-in/audio/LSTM/ReadMe.md b/ACL_PyTorch/built-in/audio/LSTM/ReadMe.md index 8eea54372f..4c9db9caaf 100644 --- a/ACL_PyTorch/built-in/audio/LSTM/ReadMe.md +++ b/ACL_PyTorch/built-in/audio/LSTM/ReadMe.md @@ -1,341 +1,341 @@ -# LSTM Onnx模型端到端推理指导 -- [1 模型概述](#1-模型概述) - - [1.1 论文地址](#11-论文地址) - - [1.2 代码地址](#12-代码地址) -- [2 环境说明](#2-环境说明) - - [2.1 深度学习框架](#21-深度学习框架) - - [2.2 python第三方库](#22-python第三方库) -- [3 模型转换](#3-模型转换) - - [3.1 pth转onnx模型](#31-pth转onnx模型) - - [3.2 onnx转om模型](#32-onnx转om模型) -- [4 数据集预处理](#4-数据集预处理) - - [4.1 数据集获取](#41-数据集获取) - - [4.2 数据集预处理](#42-数据集预处理) - - [4.3 生成数据集信息文件](#43-生成数据集信息文件) -- [5 离线推理](#5-离线推理) -- [6 精度对比](#6-精度对比) - - [6.1 离线推理精度统计](#61-离线推理精度统计) - - [6.2 精度对比](#62-精度对比) -- [7 性能对比](#7-性能对比) - - [7.1 npu性能数据](#71-npu性能数据) - - [7.2 T4性能数据](#72-T4性能数据) - - [7.3 性能对比](#73-性能对比) - -## 1 模型概述 - -- **[论文地址](#11-论文地址)** - -- **[代码地址](#12-代码地址)** - -### 1.1 论文地址 -npu训练组依据客户给的模型进行训练所得,无参考论文 - -### 1.2 代码地址 -[LSTM代码]https://gitee.com/ascend/modelzoo.git) -branch:master -commit_id=8ed54e7d0fc9b632e1e3b9420bed96ee2c7fa1e3 -code_path=modelzoo/tree/master/built-in/PyTorch/Official/nlp/LSTM_for_PyTorch - -## 2 环境说明 - -- **[深度学习框架](#21-深度学习框架)** - -- **[python第三方库](#22-python第三方库)** - -### 2.1 深度学习框架 -``` -pytorch = 1.8.0 -torchvision = 0.9.0 -``` -### 2.2 python第三方库 - -``` -ONNX == 1.7.0 -kaldi == https://github.com/kaldi-asr/kaldi -Pillow == 7.2.0 -onnxruntime-gpu == 1.7.0 -kaldiio == 2.17.2 -``` -kaldi需要安装在ModelZoo的LSTM源码仓中“modelzoo/built-in/PyTorch/Official/nlp/LSTM_for_PyTorch/NPU/1p/”目录下。ModelZoo的LSTM源码仓下载方法. -``` -git clone https://gitee.com/ascend/modelzoo.git -cd modelzoo -git reset --hard 8ed54e7d0fc9b632e1e3b9420bed96ee2c7fa1e3 -``` -1.下载ModelZoo的LSTM源码仓 -``` -git clone https://gitee.com/ascend/modelzoo.git -cd modelzoo -git reset --hard 8ed54e7d0fc9b632e1e3b9420bed96ee2c7fa1e3 -cd built-in/PyTorch/Official/nlp/LSTM_for_PyTorch/NPU/1p/ -``` -2.下载kaldi工具包 -源码搭建kaldi工具包环境。以arm 64位环境为例说明,推荐安装至conda环境: -``` -git clone https://github.com/kaldi-asr/kaldi -cd kaldi -``` -3.检查工具包所需依赖并安装缺少依赖 -``` -tools/extras/check_dependencies.sh -``` -根据检查结果和提示,安装缺少的依赖。安装完依赖再次检查工具包所需依赖是否都安装ok -4.编译 -``` -cd tools -make -j 64 -``` -5.安装依赖库成功之后安装第三方工具,Kaldi使用FST作为状态图的表现形式,安装方式如下: -``` -make openfst -extras/install_irstlm.sh -extras/install_openblas.sh -``` - -``` -输出:Installation of IRSTLM finished successfully -输出:OpenBLAS is installed successfully -``` -6.配置源码 -``` -cd ../src/ -./configure --shared -输出"Kaldi has been successfully configured." -``` -7.编译安装 -``` -make -j clean depend -make -j 64 - -输出:echo Done -Done -``` -源码中使用的python2.7版本,如果系统python版本与该版本不同,可使用系统默认python,在目录kaldi/python/下创建空文件.use_default_python。其他安装问题可参见kaldi官方安装教程. - -**说明:** -> 将源码包中的全部脚本移动到已安装kaldi工具的“modelzoo/built-in/PyTorch/Official/nlp/LSTM_for_PyTorch/NPU/1p/”目录下。 -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3 模型转换 - -- **[pth转onnx模型](#31-pth转onnx模型)** - -- **[onnx转om模型](#32-onnx转om模型)** - -### 3.1 pth转onnx模型 -1.下载pth权重文件 -权重文件由华为npu模型训练组提供。 -2.lstm模型代码在代码仓中 -``` -git clone https://gitee.com/ascend/modelzoo.git -``` - 3.编写pth2onnx脚本LSTM_pth2onnx.py -本模型基于开源框架PyTorch训练的lstm进行模型转换。使用PyTorch将模型权重文件.pth转换为.onnx文件,再使用ATC工具将.onnx文件转为离线推理模型文件.om文件。权重文件由npu模型训练组提供,gpu训练模型ctc_best_model.pth。源码包中已提供ctc_best_model.pth权重文件。在1p目录下创建checkpoint/ctc_fbank_cnn/目录并将权重文件移到到该目录下。 -``` -mkdir -p checkpoint/ctc_fbank_cnnmv ./ctc_best_model.pth ./checkpoint/ctc_fbank_cnn/ -``` - - **说明:** ->注意目前ATC支持的onnx算子版本为11 - -4.执行pth2onnx脚本,生成onnx模型文件 -``` -python3.7 ./steps/LSTM_pth2onnx.py --batchsize=16 -``` - -### 3.2 onnx转om模型 - -1.修改lstm_atc.sh脚本,通过ATC工具使用脚本完成转换,具体的脚本示例如下: -``` -# 配置环境变量 -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp -``` -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.1 开发辅助工具指南 (推理) 01 -``` -atc --input_format=ND --framework=5 --model=lstm_ctc_16batch.onnx --input_shape="actual_input_1:16,390,243" --output=lstm_ctc_16batch_auto --auto_tune_mode="RL,GA" --log=info --soc_version=Ascend310 -``` -参数说明: - --model:为ONNX模型文件。 - --framework:5代表ONNX模型。 - --output:输出的OM模型。 - --input_format:输入数据的格式。 - --input_shape:输入数据的shape。 - --log:日志级别。 - --soc_version:处理器型号。 - -执行lstm_atc.sh脚本,将.onnx文件转为离线推理模型文件.om文件。 -``` -bash lstm_atc.sh -``` -运行成功后生成lstm_ctc_npu_16batch.om用于二进制输入推理的模型文件。 - -## 4 数据集预处理 - -- **[数据集获取](#41-数据集获取)** - -- **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - -### 4.1 数据集获取 -本模型支持timit语音包的验证集。timit数据集与训练对齐,使用训练提供的语音数据包。需用户自行获取数据集,并将数据集命名为data.zip,并上传数据集data.zip至服务器ModelZoo的LSTM源码仓下的built-in/PyTorch/Official/nlp/LSTM_for_PyTorch/NPU/目录中。数据集结构如下。 -``` -├── DOC -├── README.DOC -├── TEST -└── TRAIN -``` - -### 4.2 数据集预处理 -目的、处理过程及方法、处理后输出文件介绍及用途模型输入数据为二进制格式。将原始数据(audio数据)转化为二进制文件(.bin)。 -1.解压数据集 -``` -unzip data.zip -cd p1 -``` -2.修改1p目录下path.sh里第一行代码如下: -``` -KALDI_ROOT=./kaldi -``` -3.创建data文件夹 -``` -mkdir data -``` -4.执行prepare_data.sh脚本。 -``` -chmod +x local/timit_data_prep.sh -chmod +x steps/make_feat.sh -bash prepare_data.sh -``` -执行prepare_data.sh脚本之后,在当前目录下会生成tmp文件夹和在data文件夹下生成dev,test,train三个数据集文件夹。 -5.移动LSTM_preprocess_data.py至1p/steps目录下, -6.修改./conf/ctc_config.yaml文件内容 -``` -#[test] -test_scp_path: 'data/dev/fbank.scp' -test_lab_path: 'data/dev/phn_text' -decode_type: "Greedy" -beam_width: 10 -lm_alpha: 0.1 -lm_path: 'data/lm_phone_bg.arpa' -``` -data文件夹即为执行prepare_data.sh之后所生成,使用此目录下的dev数据集进行验证。 -7.执行LSTM_preprocess_data.py脚本 -``` -python3.7 ./steps/LSTM_preprocess_data.py --conf=./conf/ctc_config.yaml --batchsize=16 -``` -参数为配置文件。 -### 4.3 生成数据集信息文件 -1.生成数据集信息文件脚本LSTM_get_info.py -使用pyacl推理需要输入二进制数据集的info文件,用于获取数据集。使用LSTM_get_info.py脚本,输入已经得到的二进制文件,输出生成二进制数据集的info文件。上传LSTM_get_info.py至1p文件夹下,运行LSTM_get_info.py脚本。 - -2.执行生成数据集信息脚本,生成数据集信息文件 -``` -python3.7 LSTM_get_info.py --batchsize=16 -``` -参数为om模型推理batchsize。运行成功后,在当前目录中生成lstm.info。 -## 5 离线推理 -1.配置pyacl推理环境变量 -``` -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:${install_path}/pyACL/python/site-packages/acl:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp -``` -2.执行pyacl离线推理 -``` -#pyacl推理命令 -python3.7 ./pyacl_infer.py --model_path=./lstm_ctc_16batch_auto.om --device_id=0 --cpu_run=True --sync_infer=True --workspace=10 --input_info_file_path=./lstm.info --input_dtypes=float32 --infer_res_save_path=./infer_res --res_save_type=npy -``` -参数说明: ---model_path:om模型文件 ---input_info_file_path:处理后的数据集信息info文件 ---infer_res_save_path:pyacl推理后结果保存路径 ---res_save_type:推理结果保存格式,npy格式为含有shape信息的数据,bin格式为不含shape-信息的二进制numpy数据 - - -## 6 精度对比 -- **[离线推理精度](#61-离线推理精度)** -- **[精度对比](#62-精度对比)** - -### 6.1 离线推理精度统计 - -1. 后处理统计精度 -上传LSTM_postprocess_data.py脚本至1p/steps目录下,执行LSTM_postprocess_data.py脚本进行数据后处理。 -``` -python3.7 ./steps/LSTM_postprocess_data.py --conf=./conf/ctc_config.yaml --npu_path=./infer_res/ --batchsize=16 -``` -conf参数为模型配置文件, npu_path参数为pyacl推理结果目录。执行后处理脚本之后,精度数据由WER 与CER给出,字母错误率与单词错误率。 -``` -Character error rate on test set: 13.5877 -Word error rate on test set: 18.9075 -``` -经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 - -### 6.2 精度对比 -推理模型om精度与onnx精度一致,且与训练测试pth模型精度一致。 - **精度调试:** - ->没有遇到精度不达标的问题,故不需要进行精度调试 - -## 7 性能对比 - -- **[npu性能数据](#71-npu性能数据)** -- **[T4性能数据](#72-T4性能数据)** -- **[性能对比](#73-性能对比)** - -### 7.1 npu性能数据 -1.该模型不支持benchmark推理,使用pyacl推理获取npu性能数据。 -batch1的性能 -``` -Bs1: average pure infer time(ms):179.183 -``` -Interface throughputRate: 1000/179.183 = 5.58,5.58x4既是batch1 310单卡吞吐率 -batch4的性能 -``` -Bs4: average pure infer time(ms):187.361 -``` -Interface throughputRate: 1000/187.361* 4 = 21.35,21.35*4既是batch4 310单卡吞吐率 -batch8性能 -``` -Bs8: average pure infer time(ms):202.751 -``` -batch8 310单卡吞吐率:1000/202.751 * 8 = 157.83 fps -batch16性能: -``` -Bs16: average pure infer time(ms):195.763 -``` -batch16 310单卡吞吐率:1000/195.763 * 16 * 4 = 326.93fps -batch32性能: -``` -Bs32: average pure infer time(ms):260.119 -``` -batch32 310单卡吞吐率:1000/260.119 * 32 * 4 = 492.08fps - -### 7.2 T4性能数据 -gpu下onnx在线推理获取T4性能基线 -在T4环境下搭建环境,将预处理好的bin文件数据打包和lstm_infer_onnx.py脚本上传至服务器上1p目录下,进行onnx在线推理,执行lstm_onnx_infer.py脚本. -``` -python3.7 lstm_onnx_infer.py --conf=./conf/ctc_config.yaml --model_path=./lstm_ctc_16batch.onnx --bin_file_path=./lstm_bin/ --pred_res_save_path=./lstm_onnx_infer --batchsize=16 -``` -性能基线数据为: -``` -total infer time(ms): 2308.3143849999997 -average infer time(ms): 92.3325754 -``` -batch16 t4吞吐率:1000/92.33 * 16 = 173.29fps - -### 7.3 性能对比 -batch16: 326.93 >1000/(92.33/16) - -310单个device的吞吐率乘4即单卡吞吐率比T4单卡的吞吐率大,故310性能高于T4性能,性能达标。 - - **性能优化:** ->该模型性能优于T4,不用进行优化 +# LSTM Onnx模型端到端推理指导 +- [1 模型概述](#1-模型概述) + - [1.1 论文地址](#11-论文地址) + - [1.2 代码地址](#12-代码地址) +- [2 环境说明](#2-环境说明) + - [2.1 深度学习框架](#21-深度学习框架) + - [2.2 python第三方库](#22-python第三方库) +- [3 模型转换](#3-模型转换) + - [3.1 pth转onnx模型](#31-pth转onnx模型) + - [3.2 onnx转om模型](#32-onnx转om模型) +- [4 数据集预处理](#4-数据集预处理) + - [4.1 数据集获取](#41-数据集获取) + - [4.2 数据集预处理](#42-数据集预处理) + - [4.3 生成数据集信息文件](#43-生成数据集信息文件) +- [5 离线推理](#5-离线推理) +- [6 精度对比](#6-精度对比) + - [6.1 离线推理精度统计](#61-离线推理精度统计) + - [6.2 精度对比](#62-精度对比) +- [7 性能对比](#7-性能对比) + - [7.1 npu性能数据](#71-npu性能数据) + - [7.2 T4性能数据](#72-T4性能数据) + - [7.3 性能对比](#73-性能对比) + +## 1 模型概述 + +- **[论文地址](#11-论文地址)** + +- **[代码地址](#12-代码地址)** + +### 1.1 论文地址 +npu训练组依据客户给的模型进行训练所得,无参考论文 + +### 1.2 代码地址 +[LSTM代码]https://gitee.com/ascend/modelzoo.git) +branch:master +commit_id=8ed54e7d0fc9b632e1e3b9420bed96ee2c7fa1e3 +code_path=modelzoo/tree/master/built-in/PyTorch/Official/nlp/LSTM_for_PyTorch + +## 2 环境说明 + +- **[深度学习框架](#21-深度学习框架)** + +- **[python第三方库](#22-python第三方库)** + +### 2.1 深度学习框架 +``` +pytorch = 1.8.0 +torchvision = 0.9.0 +``` +### 2.2 python第三方库 + +``` +ONNX == 1.7.0 +kaldi == https://github.com/kaldi-asr/kaldi +Pillow == 7.2.0 +onnxruntime-gpu == 1.7.0 +kaldiio == 2.17.2 +``` +kaldi需要安装在ModelZoo的LSTM源码仓中“modelzoo/built-in/PyTorch/Official/nlp/LSTM_for_PyTorch/NPU/1p/”目录下。ModelZoo的LSTM源码仓下载方法. +``` +git clone https://gitee.com/ascend/modelzoo.git +cd modelzoo +git reset --hard 8ed54e7d0fc9b632e1e3b9420bed96ee2c7fa1e3 +``` +1.下载ModelZoo的LSTM源码仓 +``` +git clone https://gitee.com/ascend/modelzoo.git +cd modelzoo +git reset --hard 8ed54e7d0fc9b632e1e3b9420bed96ee2c7fa1e3 +cd built-in/PyTorch/Official/nlp/LSTM_for_PyTorch/NPU/1p/ +``` +2.下载kaldi工具包 +源码搭建kaldi工具包环境。以arm 64位环境为例说明,推荐安装至conda环境: +``` +git clone https://github.com/kaldi-asr/kaldi +cd kaldi +``` +3.检查工具包所需依赖并安装缺少依赖 +``` +tools/extras/check_dependencies.sh +``` +根据检查结果和提示,安装缺少的依赖。安装完依赖再次检查工具包所需依赖是否都安装ok +4.编译 +``` +cd tools +make -j 64 +``` +5.安装依赖库成功之后安装第三方工具,Kaldi使用FST作为状态图的表现形式,安装方式如下: +``` +make openfst +extras/install_irstlm.sh +extras/install_openblas.sh +``` + +``` +输出:Installation of IRSTLM finished successfully +输出:OpenBLAS is installed successfully +``` +6.配置源码 +``` +cd ../src/ +./configure --shared +输出"Kaldi has been successfully configured." +``` +7.编译安装 +``` +make -j clean depend +make -j 64 + +输出:echo Done +Done +``` +源码中使用的python2.7版本,如果系统python版本与该版本不同,可使用系统默认python,在目录kaldi/python/下创建空文件.use_default_python。其他安装问题可参见kaldi官方安装教程. + +**说明:** +> 将源码包中的全部脚本移动到已安装kaldi工具的“modelzoo/built-in/PyTorch/Official/nlp/LSTM_for_PyTorch/NPU/1p/”目录下。 +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3 模型转换 + +- **[pth转onnx模型](#31-pth转onnx模型)** + +- **[onnx转om模型](#32-onnx转om模型)** + +### 3.1 pth转onnx模型 +1.下载pth权重文件 +权重文件由华为npu模型训练组提供。 +2.lstm模型代码在代码仓中 +``` +git clone https://gitee.com/ascend/modelzoo.git +``` + 3.编写pth2onnx脚本LSTM_pth2onnx.py +本模型基于开源框架PyTorch训练的lstm进行模型转换。使用PyTorch将模型权重文件.pth转换为.onnx文件,再使用ATC工具将.onnx文件转为离线推理模型文件.om文件。权重文件由npu模型训练组提供,gpu训练模型ctc_best_model.pth。源码包中已提供ctc_best_model.pth权重文件。在1p目录下创建checkpoint/ctc_fbank_cnn/目录并将权重文件移到到该目录下。 +``` +mkdir -p checkpoint/ctc_fbank_cnnmv ./ctc_best_model.pth ./checkpoint/ctc_fbank_cnn/ +``` + + **说明:** +>注意目前ATC支持的onnx算子版本为11 + +4.执行pth2onnx脚本,生成onnx模型文件 +``` +python3.7 ./steps/LSTM_pth2onnx.py --batchsize=16 +``` + +### 3.2 onnx转om模型 + +1.修改lstm_atc.sh脚本,通过ATC工具使用脚本完成转换,具体的脚本示例如下: +``` +# 配置环境变量 +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp +``` +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.1 开发辅助工具指南 (推理) 01 +``` +atc --input_format=ND --framework=5 --model=lstm_ctc_16batch.onnx --input_shape="actual_input_1:16,390,243" --output=lstm_ctc_16batch_auto --auto_tune_mode="RL,GA" --log=info --soc_version=Ascend310 +``` +参数说明: + --model:为ONNX模型文件。 + --framework:5代表ONNX模型。 + --output:输出的OM模型。 + --input_format:输入数据的格式。 + --input_shape:输入数据的shape。 + --log:日志级别。 + --soc_version:处理器型号。 + +执行lstm_atc.sh脚本,将.onnx文件转为离线推理模型文件.om文件。 +``` +bash lstm_atc.sh +``` +运行成功后生成lstm_ctc_npu_16batch.om用于二进制输入推理的模型文件。 + +## 4 数据集预处理 + +- **[数据集获取](#41-数据集获取)** + +- **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + +### 4.1 数据集获取 +本模型支持timit语音包的验证集。timit数据集与训练对齐,使用训练提供的语音数据包。需用户自行获取数据集,并将数据集命名为data.zip,并上传数据集data.zip至服务器ModelZoo的LSTM源码仓下的built-in/PyTorch/Official/nlp/LSTM_for_PyTorch/NPU/目录中。数据集结构如下。 +``` +├── DOC +├── README.DOC +├── TEST +└── TRAIN +``` + +### 4.2 数据集预处理 +目的、处理过程及方法、处理后输出文件介绍及用途模型输入数据为二进制格式。将原始数据(audio数据)转化为二进制文件(.bin)。 +1.解压数据集 +``` +unzip data.zip +cd p1 +``` +2.修改1p目录下path.sh里第一行代码如下: +``` +KALDI_ROOT=./kaldi +``` +3.创建data文件夹 +``` +mkdir data +``` +4.执行prepare_data.sh脚本。 +``` +chmod +x local/timit_data_prep.sh +chmod +x steps/make_feat.sh +bash prepare_data.sh +``` +执行prepare_data.sh脚本之后,在当前目录下会生成tmp文件夹和在data文件夹下生成dev,test,train三个数据集文件夹。 +5.移动LSTM_preprocess_data.py至1p/steps目录下, +6.修改./conf/ctc_config.yaml文件内容 +``` +#[test] +test_scp_path: 'data/dev/fbank.scp' +test_lab_path: 'data/dev/phn_text' +decode_type: "Greedy" +beam_width: 10 +lm_alpha: 0.1 +lm_path: 'data/lm_phone_bg.arpa' +``` +data文件夹即为执行prepare_data.sh之后所生成,使用此目录下的dev数据集进行验证。 +7.执行LSTM_preprocess_data.py脚本 +``` +python3.7 ./steps/LSTM_preprocess_data.py --conf=./conf/ctc_config.yaml --batchsize=16 +``` +参数为配置文件。 +### 4.3 生成数据集信息文件 +1.生成数据集信息文件脚本LSTM_get_info.py +使用pyacl推理需要输入二进制数据集的info文件,用于获取数据集。使用LSTM_get_info.py脚本,输入已经得到的二进制文件,输出生成二进制数据集的info文件。上传LSTM_get_info.py至1p文件夹下,运行LSTM_get_info.py脚本。 + +2.执行生成数据集信息脚本,生成数据集信息文件 +``` +python3.7 LSTM_get_info.py --batchsize=16 +``` +参数为om模型推理batchsize。运行成功后,在当前目录中生成lstm.info。 +## 5 离线推理 +1.配置pyacl推理环境变量 +``` +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:${install_path}/pyACL/python/site-packages/acl:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp +``` +2.执行pyacl离线推理 +``` +#pyacl推理命令 +python3.7 ./pyacl_infer.py --model_path=./lstm_ctc_16batch_auto.om --device_id=0 --cpu_run=True --sync_infer=True --workspace=10 --input_info_file_path=./lstm.info --input_dtypes=float32 --infer_res_save_path=./infer_res --res_save_type=npy +``` +参数说明: +--model_path:om模型文件 +--input_info_file_path:处理后的数据集信息info文件 +--infer_res_save_path:pyacl推理后结果保存路径 +--res_save_type:推理结果保存格式,npy格式为含有shape信息的数据,bin格式为不含shape-信息的二进制numpy数据 + + +## 6 精度对比 +- **[离线推理精度](#61-离线推理精度)** +- **[精度对比](#62-精度对比)** + +### 6.1 离线推理精度统计 + +1. 后处理统计精度 +上传LSTM_postprocess_data.py脚本至1p/steps目录下,执行LSTM_postprocess_data.py脚本进行数据后处理。 +``` +python3.7 ./steps/LSTM_postprocess_data.py --conf=./conf/ctc_config.yaml --npu_path=./infer_res/ --batchsize=16 +``` +conf参数为模型配置文件, npu_path参数为pyacl推理结果目录。执行后处理脚本之后,精度数据由WER 与CER给出,字母错误率与单词错误率。 +``` +Character error rate on test set: 13.5877 +Word error rate on test set: 18.9075 +``` +经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 + +### 6.2 精度对比 +推理模型om精度与onnx精度一致,且与训练测试pth模型精度一致。 + **精度调试:** + +>没有遇到精度不达标的问题,故不需要进行精度调试 + +## 7 性能对比 + +- **[npu性能数据](#71-npu性能数据)** +- **[T4性能数据](#72-T4性能数据)** +- **[性能对比](#73-性能对比)** + +### 7.1 npu性能数据 +1.该模型不支持benchmark推理,使用pyacl推理获取npu性能数据。 +batch1的性能 +``` +Bs1: average pure infer time(ms):179.183 +``` +Interface throughputRate: 1000/179.183 = 5.58,5.58x4既是batch1 310单卡吞吐率 +batch4的性能 +``` +Bs4: average pure infer time(ms):187.361 +``` +Interface throughputRate: 1000/187.361* 4 = 21.35,21.35*4既是batch4 310单卡吞吐率 +batch8性能 +``` +Bs8: average pure infer time(ms):202.751 +``` +batch8 310单卡吞吐率:1000/202.751 * 8 = 157.83 fps +batch16性能: +``` +Bs16: average pure infer time(ms):195.763 +``` +batch16 310单卡吞吐率:1000/195.763 * 16 * 4 = 326.93fps +batch32性能: +``` +Bs32: average pure infer time(ms):260.119 +``` +batch32 310单卡吞吐率:1000/260.119 * 32 * 4 = 492.08fps + +### 7.2 T4性能数据 +gpu下onnx在线推理获取T4性能基线 +在T4环境下搭建环境,将预处理好的bin文件数据打包和lstm_infer_onnx.py脚本上传至服务器上1p目录下,进行onnx在线推理,执行lstm_onnx_infer.py脚本. +``` +python3.7 lstm_onnx_infer.py --conf=./conf/ctc_config.yaml --model_path=./lstm_ctc_16batch.onnx --bin_file_path=./lstm_bin/ --pred_res_save_path=./lstm_onnx_infer --batchsize=16 +``` +性能基线数据为: +``` +total infer time(ms): 2308.3143849999997 +average infer time(ms): 92.3325754 +``` +batch16 t4吞吐率:1000/92.33 * 16 = 173.29fps + +### 7.3 性能对比 +batch16: 326.93 >1000/(92.33/16) + +310单个device的吞吐率乘4即单卡吞吐率比T4单卡的吞吐率大,故310性能高于T4性能,性能达标。 + + **性能优化:** +>该模型性能优于T4,不用进行优化 diff --git a/ACL_PyTorch/built-in/audio/LSTM/acl_net.py b/ACL_PyTorch/built-in/audio/LSTM/acl_net.py index f3ec7a6b5b..d7f893b3f3 100644 --- a/ACL_PyTorch/built-in/audio/LSTM/acl_net.py +++ b/ACL_PyTorch/built-in/audio/LSTM/acl_net.py @@ -1,276 +1,276 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 acl -import functools -import numpy as np -import torch -import time - -# error code -ACL_ERROR_NONE = 0 - -# rule for memory copy -ACL_MEMCPY_HOST_TO_HOST = 0 -ACL_MEMCPY_HOST_TO_DEVICE = 1 -ACL_MEMCPY_DEVICE_TO_HOST = 2 -ACL_MEMCPY_DEVICE_TO_DEVICE = 3 - -# dtype -ACL_DTYPE = { - 0: 'float32', - 1: 'float16', - 2: 'int8', - 3: 'int32', - 4: 'uint8', - 6: 'int16', - 7: 'uint16', - 8: 'uint32', - 9: 'int64', - 10: 'uint64', - 11: 'float64', - 12: 'bool', -} - - -def check_ret(message, ret): - if ret != ACL_ERROR_NONE: - raise Exception(f"{message} failed ret={ret}") - - -class MeasureTime(): - def __init__(self, measurements, key, cpu_run=True): - self.measurements = measurements - self.key = key - self.cpu_run = cpu_run - - def __enter__(self): - if not self.cpu_run: - torch.cuda.synchronize() - self.t0 = time.perf_counter_ns() - - def __exit__(self, exc_type, exc_value, exc_traceback): - if not self.cpu_run: - torch.cuda.synchronize() - self.measurements[self.key] = time.perf_counter_ns() - self.t0 - - -class AclModel(object): - def __init__(self, device_id, model_path, sync_infer, measurements, key, cpu_run): - self.device_id = device_id - self.sync_infer = sync_infer - self.out_bufs_ptr = [] - self.output_sizes = [] - self.input_sizes = [] - self.input_bufs_ptr = [] - - self.measurements = measurements - self.key = key - self.cpu_run = cpu_run - - ret = acl.init() - check_ret("acl.init", ret) - ret = acl.rt.set_device(self.device_id) - check_ret("acl.rt.set_device", ret) - self.context, ret = acl.rt.create_context(self.device_id) - check_ret("acl.rt.create_context", ret) - self.model_id, ret = acl.mdl.load_from_file(model_path) - check_ret("acl.mdl.load_from_file", ret) - - self.model_desc = acl.mdl.create_desc() - assert self.model_desc is not None - acl.mdl.get_desc(self.model_desc, self.model_id) - self.dataset_in = acl.mdl.create_dataset() - assert self.dataset_in is not None - self.dataset_out = acl.mdl.create_dataset() - assert self.dataset_out is not None - self.in_size, self.out_size = 0, 0 - self.stm, ret = acl.rt.create_stream() - assert ret == 0 - - self.desc_init() - self.dataset_init() - - def __call__(self, ori_data, dim): - return self.forward(ori_data, dim) - - def __del__(self): - # unload model - if self.model_id: - ret = acl.mdl.unload(self.model_id) - assert ret == 0 - - # destroy model desc - ret = acl.mdl.destroy_desc(self.model_desc) - assert ret == 0 - - self.destroy_data_set(self.dataset_in) - self.destroy_data_set(self.dataset_out) - - # destroy input/output tensor - for i in range(len(self.input_bufs_ptr)): - acl.rt.free(self.input_bufs_ptr[i]["buffer"]) - self.input_bufs_ptr[i] = None - - for i in range(len(self.out_bufs_ptr)): - acl.rt.free(self.out_bufs_ptr[i]["buffer"]) - self.out_bufs_ptr[i] = None - - ret = acl.rt.destroy_stream(self.stm) - assert ret == 0 - - def desc_init(self): - tensor_size = acl.mdl.get_num_inputs(self.model_desc) - if not tensor_size: - raise Exception("get_num_inputs failed") - self.in_size = tensor_size - - for i in range(tensor_size): - size = acl.mdl.get_input_size_by_index(self.model_desc, i) - data, ret = acl.rt.malloc(size, 0) - assert ret == 0 - - self.input_bufs_ptr.append({'size': size, 'buffer': data}) - self.input_sizes.append(size) - - tensor_size = acl.mdl.get_num_outputs(self.model_desc) - self.out_size = tensor_size - for i in range(tensor_size): - dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) - assert ret == 0 - size = acl.mdl.get_output_size_by_index(self.model_desc, i) - - data, ret = acl.rt.malloc(size, 0) - assert ret == 0 - - self.output_sizes.append(size) - self.out_bufs_ptr.append({'size': size, 'buffer': data}) - - def dataset_init(self): - self.create_data_set(self.dataset_in, self.input_bufs_ptr, self.input_sizes) - self.create_data_set(self.dataset_out, self.out_bufs_ptr, self.output_sizes) - - def create_data_set(self, dataset, bufs_ptr_list, size_list): - # create dataset buffer then add to dataset - for i in range(len(size_list)): - buffer = acl.create_data_buffer(bufs_ptr_list[i]["buffer"], size_list[i]) - if not buffer: - self.destroy_data_set(dataset) - raise Exception("create_data_buffer failed") - - # add to dataset - _, ret = acl.mdl.add_dataset_buffer(dataset, buffer) - if ret != 0: - self.destroy_data_set(dataset) - raise Exception("add_dataset_buffer failed, ret = {}".format(ret)) - - return dataset - - def destroy_data_set(self, dataset): - data_buf_num = acl.mdl.get_dataset_num_buffers(dataset) - for i in range(data_buf_num): - # get data buffer by index - data_buf = acl.mdl.get_dataset_buffer(dataset, i) - if data_buf is not None: - acl.destroy_data_buffer(data_buf) - - acl.mdl.destroy_dataset(dataset) - - def copy_data_to_device(self, data): - for i in range(len(data)): - ptr, np = acl.util.numpy_contiguous_to_ptr(data[i]["buffer"]) - acl.rt.memcpy(self.input_bufs_ptr[i]["buffer"], data[i]["size"], ptr, - data[i]["size"], ACL_MEMCPY_HOST_TO_DEVICE) - - def copy_output_to_host(self): - output_data = [] - for i in range(len(self.out_bufs_ptr)): - temp = dict() - temp["size"] = self.out_bufs_ptr[i]["size"] - temp["buffer"], ret = acl.rt.malloc_host(temp["size"]) - output_data.append(temp) - acl.rt.memcpy(temp["buffer"], temp["size"], self.out_bufs_ptr[i]["buffer"], - temp["size"], ACL_MEMCPY_DEVICE_TO_HOST) - - return output_data - - def model_exe(self): - with MeasureTime(self.measurements, self.key, self.cpu_run): - ret = acl.mdl.execute(self.model_id, self.dataset_in, self.dataset_out) - assert ret == 0 - output_data = self.copy_output_to_host() - dataset = [] - for i in range(len(output_data)): - dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) - data_shape = dims.get("dims") - data_type = acl.mdl.get_output_data_type(self.model_desc, i) - data_len = functools.reduce(lambda x, y: x * y, data_shape) - ftype = np.dtype(ACL_DTYPE.get(data_type)) - - size = output_data[i]["size"] - ptr = output_data[i]["buffer"] - data = acl.util.ptr_to_numpy(ptr, (size,), 1) - np_arr = np.frombuffer(bytearray(data[:data_len * ftype.itemsize]), dtype=ftype, count=data_len) - np_arr = np_arr.reshape(data_shape) - dataset.append(np_arr) - return dataset - - def model_exe_async(self): - with MeasureTime(self.measurements, self.key, self.cpu_run): - ret = acl.mdl.execute_async(self.model_id, self.dataset_in, self.dataset_out, self.stm) - assert ret == 0 - ret = acl.rt.synchronize_stream(self.stm) - assert ret == 0 - output_data = self.copy_output_to_host() - - dataset = [] - for i in range(len(output_data)): - dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) - # check_ret("acl.mdl.get_cur_output_dims", ret) - data_shape = dims.get("dims") - - data_type = acl.mdl.get_output_data_type(self.model_desc, i) - data_len = functools.reduce(lambda x, y: x * y, data_shape) - ftype = np.dtype(ACL_DTYPE.get(data_type)) - - size = output_data[i]["size"] - ptr = output_data[i]["buffer"] - data = acl.util.ptr_to_numpy(ptr, (size,), 1) - np_arr = np.frombuffer(bytearray(data[:data_len * ftype.itemsize]), dtype=ftype, count=data_len) - np_arr = np_arr.reshape(data_shape) - dataset.append(np_arr) - return dataset - - def model_exe_with_dynamic_dims(self, input_data, dims): - index, ret = acl.mdl.get_input_index_by_name(self.model_desc, 'ascend_mbatch_shape_data') - ret = acl.mdl.set_input_dynamic_dims(self.model_id, self.dataset_in, index, dims) - gear_count, ret = acl.mdl.get_input_dynamic_gear_count(self.model_desc, -1) - dims_out, ret = acl.mdl.get_input_dynamic_dims(self.model_desc, -1, gear_count) - self.copy_data_to_device(input_data) - if self.sync_infer is True: - res = self.model_exe() - else: - res = self.model_exe_async() - - return res - - def forward(self, input_data, dims): - input_data_dic = [] - for i in range(len(input_data)): - temp = {} - temp["size"] = input_data[i].size * input_data[i].itemsize - temp["buffer"] = input_data[i] - input_data_dic.append(temp) - result = self.model_exe_with_dynamic_dims(input_data_dic, dims) - return result +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 acl +import functools +import numpy as np +import torch +import time + +# error code +ACL_ERROR_NONE = 0 + +# rule for memory copy +ACL_MEMCPY_HOST_TO_HOST = 0 +ACL_MEMCPY_HOST_TO_DEVICE = 1 +ACL_MEMCPY_DEVICE_TO_HOST = 2 +ACL_MEMCPY_DEVICE_TO_DEVICE = 3 + +# dtype +ACL_DTYPE = { + 0: 'float32', + 1: 'float16', + 2: 'int8', + 3: 'int32', + 4: 'uint8', + 6: 'int16', + 7: 'uint16', + 8: 'uint32', + 9: 'int64', + 10: 'uint64', + 11: 'float64', + 12: 'bool', +} + + +def check_ret(message, ret): + if ret != ACL_ERROR_NONE: + raise Exception(f"{message} failed ret={ret}") + + +class MeasureTime(): + def __init__(self, measurements, key, cpu_run=True): + self.measurements = measurements + self.key = key + self.cpu_run = cpu_run + + def __enter__(self): + if not self.cpu_run: + torch.cuda.synchronize() + self.t0 = time.perf_counter_ns() + + def __exit__(self, exc_type, exc_value, exc_traceback): + if not self.cpu_run: + torch.cuda.synchronize() + self.measurements[self.key] = time.perf_counter_ns() - self.t0 + + +class AclModel(object): + def __init__(self, device_id, model_path, sync_infer, measurements, key, cpu_run): + self.device_id = device_id + self.sync_infer = sync_infer + self.out_bufs_ptr = [] + self.output_sizes = [] + self.input_sizes = [] + self.input_bufs_ptr = [] + + self.measurements = measurements + self.key = key + self.cpu_run = cpu_run + + ret = acl.init() + check_ret("acl.init", ret) + ret = acl.rt.set_device(self.device_id) + check_ret("acl.rt.set_device", ret) + self.context, ret = acl.rt.create_context(self.device_id) + check_ret("acl.rt.create_context", ret) + self.model_id, ret = acl.mdl.load_from_file(model_path) + check_ret("acl.mdl.load_from_file", ret) + + self.model_desc = acl.mdl.create_desc() + assert self.model_desc is not None + acl.mdl.get_desc(self.model_desc, self.model_id) + self.dataset_in = acl.mdl.create_dataset() + assert self.dataset_in is not None + self.dataset_out = acl.mdl.create_dataset() + assert self.dataset_out is not None + self.in_size, self.out_size = 0, 0 + self.stm, ret = acl.rt.create_stream() + assert ret == 0 + + self.desc_init() + self.dataset_init() + + def __call__(self, ori_data, dim): + return self.forward(ori_data, dim) + + def __del__(self): + # unload model + if self.model_id: + ret = acl.mdl.unload(self.model_id) + assert ret == 0 + + # destroy model desc + ret = acl.mdl.destroy_desc(self.model_desc) + assert ret == 0 + + self.destroy_data_set(self.dataset_in) + self.destroy_data_set(self.dataset_out) + + # destroy input/output tensor + for i in range(len(self.input_bufs_ptr)): + acl.rt.free(self.input_bufs_ptr[i]["buffer"]) + self.input_bufs_ptr[i] = None + + for i in range(len(self.out_bufs_ptr)): + acl.rt.free(self.out_bufs_ptr[i]["buffer"]) + self.out_bufs_ptr[i] = None + + ret = acl.rt.destroy_stream(self.stm) + assert ret == 0 + + def desc_init(self): + tensor_size = acl.mdl.get_num_inputs(self.model_desc) + if not tensor_size: + raise Exception("get_num_inputs failed") + self.in_size = tensor_size + + for i in range(tensor_size): + size = acl.mdl.get_input_size_by_index(self.model_desc, i) + data, ret = acl.rt.malloc(size, 0) + assert ret == 0 + + self.input_bufs_ptr.append({'size': size, 'buffer': data}) + self.input_sizes.append(size) + + tensor_size = acl.mdl.get_num_outputs(self.model_desc) + self.out_size = tensor_size + for i in range(tensor_size): + dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) + assert ret == 0 + size = acl.mdl.get_output_size_by_index(self.model_desc, i) + + data, ret = acl.rt.malloc(size, 0) + assert ret == 0 + + self.output_sizes.append(size) + self.out_bufs_ptr.append({'size': size, 'buffer': data}) + + def dataset_init(self): + self.create_data_set(self.dataset_in, self.input_bufs_ptr, self.input_sizes) + self.create_data_set(self.dataset_out, self.out_bufs_ptr, self.output_sizes) + + def create_data_set(self, dataset, bufs_ptr_list, size_list): + # create dataset buffer then add to dataset + for i in range(len(size_list)): + buffer = acl.create_data_buffer(bufs_ptr_list[i]["buffer"], size_list[i]) + if not buffer: + self.destroy_data_set(dataset) + raise Exception("create_data_buffer failed") + + # add to dataset + _, ret = acl.mdl.add_dataset_buffer(dataset, buffer) + if ret != 0: + self.destroy_data_set(dataset) + raise Exception("add_dataset_buffer failed, ret = {}".format(ret)) + + return dataset + + def destroy_data_set(self, dataset): + data_buf_num = acl.mdl.get_dataset_num_buffers(dataset) + for i in range(data_buf_num): + # get data buffer by index + data_buf = acl.mdl.get_dataset_buffer(dataset, i) + if data_buf is not None: + acl.destroy_data_buffer(data_buf) + + acl.mdl.destroy_dataset(dataset) + + def copy_data_to_device(self, data): + for i in range(len(data)): + ptr, np = acl.util.numpy_contiguous_to_ptr(data[i]["buffer"]) + acl.rt.memcpy(self.input_bufs_ptr[i]["buffer"], data[i]["size"], ptr, + data[i]["size"], ACL_MEMCPY_HOST_TO_DEVICE) + + def copy_output_to_host(self): + output_data = [] + for i in range(len(self.out_bufs_ptr)): + temp = dict() + temp["size"] = self.out_bufs_ptr[i]["size"] + temp["buffer"], ret = acl.rt.malloc_host(temp["size"]) + output_data.append(temp) + acl.rt.memcpy(temp["buffer"], temp["size"], self.out_bufs_ptr[i]["buffer"], + temp["size"], ACL_MEMCPY_DEVICE_TO_HOST) + + return output_data + + def model_exe(self): + with MeasureTime(self.measurements, self.key, self.cpu_run): + ret = acl.mdl.execute(self.model_id, self.dataset_in, self.dataset_out) + assert ret == 0 + output_data = self.copy_output_to_host() + dataset = [] + for i in range(len(output_data)): + dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) + data_shape = dims.get("dims") + data_type = acl.mdl.get_output_data_type(self.model_desc, i) + data_len = functools.reduce(lambda x, y: x * y, data_shape) + ftype = np.dtype(ACL_DTYPE.get(data_type)) + + size = output_data[i]["size"] + ptr = output_data[i]["buffer"] + data = acl.util.ptr_to_numpy(ptr, (size,), 1) + np_arr = np.frombuffer(bytearray(data[:data_len * ftype.itemsize]), dtype=ftype, count=data_len) + np_arr = np_arr.reshape(data_shape) + dataset.append(np_arr) + return dataset + + def model_exe_async(self): + with MeasureTime(self.measurements, self.key, self.cpu_run): + ret = acl.mdl.execute_async(self.model_id, self.dataset_in, self.dataset_out, self.stm) + assert ret == 0 + ret = acl.rt.synchronize_stream(self.stm) + assert ret == 0 + output_data = self.copy_output_to_host() + + dataset = [] + for i in range(len(output_data)): + dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) + # check_ret("acl.mdl.get_cur_output_dims", ret) + data_shape = dims.get("dims") + + data_type = acl.mdl.get_output_data_type(self.model_desc, i) + data_len = functools.reduce(lambda x, y: x * y, data_shape) + ftype = np.dtype(ACL_DTYPE.get(data_type)) + + size = output_data[i]["size"] + ptr = output_data[i]["buffer"] + data = acl.util.ptr_to_numpy(ptr, (size,), 1) + np_arr = np.frombuffer(bytearray(data[:data_len * ftype.itemsize]), dtype=ftype, count=data_len) + np_arr = np_arr.reshape(data_shape) + dataset.append(np_arr) + return dataset + + def model_exe_with_dynamic_dims(self, input_data, dims): + index, ret = acl.mdl.get_input_index_by_name(self.model_desc, 'ascend_mbatch_shape_data') + ret = acl.mdl.set_input_dynamic_dims(self.model_id, self.dataset_in, index, dims) + gear_count, ret = acl.mdl.get_input_dynamic_gear_count(self.model_desc, -1) + dims_out, ret = acl.mdl.get_input_dynamic_dims(self.model_desc, -1, gear_count) + self.copy_data_to_device(input_data) + if self.sync_infer is True: + res = self.model_exe() + else: + res = self.model_exe_async() + + return res + + def forward(self, input_data, dims): + input_data_dic = [] + for i in range(len(input_data)): + temp = {} + temp["size"] = input_data[i].size * input_data[i].itemsize + temp["buffer"] = input_data[i] + input_data_dic.append(temp) + result = self.model_exe_with_dynamic_dims(input_data_dic, dims) + return result diff --git a/ACL_PyTorch/built-in/audio/LSTM/lstm_atc.sh b/ACL_PyTorch/built-in/audio/LSTM/lstm_atc.sh index 738f842581..42ed54470d 100644 --- a/ACL_PyTorch/built-in/audio/LSTM/lstm_atc.sh +++ b/ACL_PyTorch/built-in/audio/LSTM/lstm_atc.sh @@ -1,6 +1,6 @@ -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATHexport ASCEND_OPP_PATH=${install_path}/opp - +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATHexport ASCEND_OPP_PATH=${install_path}/opp + /usr/local/Ascend/ascend-toolkit/latest/atc/bin/atc --input_format=ND --framework=5 --model=lstm_ctc_16batch.onnx --input_shape="actual_input_1:16,390,243" --output=lstm_ctc_16batch_auto --auto_tune_mode="RL,GA" --log=info --soc_version=Ascend310 \ No newline at end of file diff --git a/ACL_PyTorch/built-in/audio/LSTM/lstm_onnx_infer.py b/ACL_PyTorch/built-in/audio/LSTM/lstm_onnx_infer.py index b62b2e882c..6e94edaf20 100644 --- a/ACL_PyTorch/built-in/audio/LSTM/lstm_onnx_infer.py +++ b/ACL_PyTorch/built-in/audio/LSTM/lstm_onnx_infer.py @@ -1,155 +1,155 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import time -import sys -import torch -import yaml -import argparse -import onnxruntime -import torch.nn as nn -import numpy as np -from glob import glob -from tqdm import tqdm - -sys.path.append('./') -from models.model_ctc import * -from utils.ctcDecoder import GreedyDecoder, BeamDecoder - -parser = argparse.ArgumentParser() -parser.add_argument('--conf', help='conf file for training') - -parser.add_argument('--model_path', required=True) -parser.add_argument('--bin_file_path', required=True) -parser.add_argument('--pred_res_save_path', required=True) -parser.add_argument('--batchsize', required=True, help='batchsize for onnx infering') - -class Config(object): - batch_size = 4 - dropout = 0.1 - -class Vocab(object): - def __init__(self, vocab_file): - self.vocab_file = vocab_file - self.word2index = {"blank": 0, "UNK": 1} - self.index2word = {0: "blank", 1: "UNK"} - self.word2count = {} - self.n_words = 2 - self.read_lang() - - def add_sentence(self, sentence): - for word in sentence.split(' '): - self.add_word(word) - - def add_word(self, word): - if word not in self.word2index: - self.word2index[word] = self.n_words - self.word2count[word] = 1 - self.index2word[self.n_words] = word - self.n_words += 1 - else: - self.word2count[word] += 1 - - def read_lang(self): - print("Reading vocabulary from {}".format(self.vocab_file)) - with open(self.vocab_file, 'r') as rf: - line = rf.readline() - while line: - line = line.strip().split(' ') - if len(line) > 1: - sen = ' '.join(line[1:]) - else: - sen = line[0] - self.add_sentence(sen) - line = rf.readline() - print("Vocabulary size is {}".format(self.n_words)) - -def lstm_onnx_infer(): - args = parser.parse_args() - - model_path = args.model_path - bin_file_path = args.bin_file_path - pred_res_save_path = args.pred_res_save_path - - try: - conf = yaml.safe_load(open(args.conf,'r')) - except: - print("Config file not exist!") - sys.exit(1) - - opts = Config() - for k,v in conf.items(): - setattr(opts, k, v) - print('{:50}:{}'.format(k, v)) - - beam_width = opts.beam_width - lm_alpha = opts.lm_alpha - decoder_type = opts.decode_type - vocab_file = opts.vocab_file - batchsize = int(args.batchsize) - - vocab = Vocab(vocab_file) - - # 读取数据目录 - bin_file_list = glob(os.path.join(bin_file_path, '*.bin')) - bin_file_num = len(bin_file_list) - - # 创建目录 - pardir = os.path.dirname(pred_res_save_path) - if not os.path.exists(pardir): - os.makedirs(pardir) - - # 推理 - print('[INFO] Infer on dataset ...') - transcription_list = [] - total_infer_time = 0 - total_infer_num = 0 - - with open(pred_res_save_path, 'wt', encoding='utf-8') as f_pred: - onnx_run_sess = onnxruntime.InferenceSession(model_path) - for i in tqdm(range(bin_file_num)): - # 数据预处理 - input = np.fromfile(os.path.join(bin_file_path, 'inputs_' + str(i) + '.bin'), dtype=np.float32) - input = input.reshape(batchsize, 390, 243) - - # 推理 - start_time = time.perf_counter_ns() - output = onnx_run_sess.run(None, {"actual_input_1":input}) - end_time = time.perf_counter_ns() - total_infer_time += end_time - start_time - total_infer_num += 1 - - #推理时间 - print('[INFO] Time:') - msg = 'total infer num: ' + str(total_infer_num) + '\n' + \ - 'total infer time(ms): ' + str(total_infer_time / 1000 / 1000) + '\n' + \ - 'average infer time(ms): ' + str(total_infer_time / total_infer_num / 1000 / 1000) + '\n' - print(msg) - with open(os.path.join(pardir, 'infer_time.txt'), 'wt', encoding='utf-8') as f_infer_time: - f_infer_time.write(msg) - - -if __name__ == '__main__': - ''' - Using Example: - - python onnx_local_infer.py \ - --conf=./conf/ctc_config.yaml \ - --model_path=./lstm_onnx/lstm_ctc_npu_16batch1_67.onnx \ - --bin_file_path=--bin_file_path=./lstm_bin/ \ - --pred_res_save_path=./lstm_onnx_infer \ - --batchsize=16 - ''' - lstm_onnx_infer() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import time +import sys +import torch +import yaml +import argparse +import onnxruntime +import torch.nn as nn +import numpy as np +from glob import glob +from tqdm import tqdm + +sys.path.append('./') +from models.model_ctc import * +from utils.ctcDecoder import GreedyDecoder, BeamDecoder + +parser = argparse.ArgumentParser() +parser.add_argument('--conf', help='conf file for training') + +parser.add_argument('--model_path', required=True) +parser.add_argument('--bin_file_path', required=True) +parser.add_argument('--pred_res_save_path', required=True) +parser.add_argument('--batchsize', required=True, help='batchsize for onnx infering') + +class Config(object): + batch_size = 4 + dropout = 0.1 + +class Vocab(object): + def __init__(self, vocab_file): + self.vocab_file = vocab_file + self.word2index = {"blank": 0, "UNK": 1} + self.index2word = {0: "blank", 1: "UNK"} + self.word2count = {} + self.n_words = 2 + self.read_lang() + + def add_sentence(self, sentence): + for word in sentence.split(' '): + self.add_word(word) + + def add_word(self, word): + if word not in self.word2index: + self.word2index[word] = self.n_words + self.word2count[word] = 1 + self.index2word[self.n_words] = word + self.n_words += 1 + else: + self.word2count[word] += 1 + + def read_lang(self): + print("Reading vocabulary from {}".format(self.vocab_file)) + with open(self.vocab_file, 'r') as rf: + line = rf.readline() + while line: + line = line.strip().split(' ') + if len(line) > 1: + sen = ' '.join(line[1:]) + else: + sen = line[0] + self.add_sentence(sen) + line = rf.readline() + print("Vocabulary size is {}".format(self.n_words)) + +def lstm_onnx_infer(): + args = parser.parse_args() + + model_path = args.model_path + bin_file_path = args.bin_file_path + pred_res_save_path = args.pred_res_save_path + + try: + conf = yaml.safe_load(open(args.conf,'r')) + except: + print("Config file not exist!") + sys.exit(1) + + opts = Config() + for k,v in conf.items(): + setattr(opts, k, v) + print('{:50}:{}'.format(k, v)) + + beam_width = opts.beam_width + lm_alpha = opts.lm_alpha + decoder_type = opts.decode_type + vocab_file = opts.vocab_file + batchsize = int(args.batchsize) + + vocab = Vocab(vocab_file) + + # 读取数据目录 + bin_file_list = glob(os.path.join(bin_file_path, '*.bin')) + bin_file_num = len(bin_file_list) + + # 创建目录 + pardir = os.path.dirname(pred_res_save_path) + if not os.path.exists(pardir): + os.makedirs(pardir) + + # 推理 + print('[INFO] Infer on dataset ...') + transcription_list = [] + total_infer_time = 0 + total_infer_num = 0 + + with open(pred_res_save_path, 'wt', encoding='utf-8') as f_pred: + onnx_run_sess = onnxruntime.InferenceSession(model_path) + for i in tqdm(range(bin_file_num)): + # 数据预处理 + input = np.fromfile(os.path.join(bin_file_path, 'inputs_' + str(i) + '.bin'), dtype=np.float32) + input = input.reshape(batchsize, 390, 243) + + # 推理 + start_time = time.perf_counter_ns() + output = onnx_run_sess.run(None, {"actual_input_1":input}) + end_time = time.perf_counter_ns() + total_infer_time += end_time - start_time + total_infer_num += 1 + + #推理时间 + print('[INFO] Time:') + msg = 'total infer num: ' + str(total_infer_num) + '\n' + \ + 'total infer time(ms): ' + str(total_infer_time / 1000 / 1000) + '\n' + \ + 'average infer time(ms): ' + str(total_infer_time / total_infer_num / 1000 / 1000) + '\n' + print(msg) + with open(os.path.join(pardir, 'infer_time.txt'), 'wt', encoding='utf-8') as f_infer_time: + f_infer_time.write(msg) + + +if __name__ == '__main__': + ''' + Using Example: + + python onnx_local_infer.py \ + --conf=./conf/ctc_config.yaml \ + --model_path=./lstm_onnx/lstm_ctc_npu_16batch1_67.onnx \ + --bin_file_path=--bin_file_path=./lstm_bin/ \ + --pred_res_save_path=./lstm_onnx_infer \ + --batchsize=16 + ''' + lstm_onnx_infer() diff --git a/ACL_PyTorch/built-in/audio/LSTM/prepare_data.sh b/ACL_PyTorch/built-in/audio/LSTM/prepare_data.sh index 29bd7427ef..0010bac616 100644 --- a/ACL_PyTorch/built-in/audio/LSTM/prepare_data.sh +++ b/ACL_PyTorch/built-in/audio/LSTM/prepare_data.sh @@ -1,31 +1,31 @@ -#!/bin/bash - -#Author: Ruchao Fan -#2017.11.1 Training acoustic model and decode with phoneme-level bigram -#2018.4.30 Replace the h5py with ark and simplify the data_loader.py -#2019.12.20 Update to pytorch1.2 and python3.7 - -. path.sh - -stage=0 - -timit_dir='../data' -phoneme_map='60-39' -feat_dir='data' #dir to save feature -feat_type='fbank' #fbank, mfcc, spectrogram -config_file='conf/ctc_config.yaml' - -if [ ! -z $1 ]; then - stage=$1 -fi - -if [ $stage -le 0 ]; then - echo "Step 0: Data Preparation ..." - local/timit_data_prep.sh $timit_dir $phoneme_map || exit 1; - python3 steps/get_model_units.py $feat_dir/train/phn_text -fi - -if [ $stage -le 1 ]; then - echo "Step 1: Feature Extraction..." - steps/make_feat.sh $feat_type $feat_dir || exit 1; -fi +#!/bin/bash + +#Author: Ruchao Fan +#2017.11.1 Training acoustic model and decode with phoneme-level bigram +#2018.4.30 Replace the h5py with ark and simplify the data_loader.py +#2019.12.20 Update to pytorch1.2 and python3.7 + +. path.sh + +stage=0 + +timit_dir='../data' +phoneme_map='60-39' +feat_dir='data' #dir to save feature +feat_type='fbank' #fbank, mfcc, spectrogram +config_file='conf/ctc_config.yaml' + +if [ ! -z $1 ]; then + stage=$1 +fi + +if [ $stage -le 0 ]; then + echo "Step 0: Data Preparation ..." + local/timit_data_prep.sh $timit_dir $phoneme_map || exit 1; + python3 steps/get_model_units.py $feat_dir/train/phn_text +fi + +if [ $stage -le 1 ]; then + echo "Step 1: Feature Extraction..." + steps/make_feat.sh $feat_type $feat_dir || exit 1; +fi diff --git a/ACL_PyTorch/built-in/audio/LSTM/pyacl_infer.py b/ACL_PyTorch/built-in/audio/LSTM/pyacl_infer.py index de1af0191e..26284c1cde 100644 --- a/ACL_PyTorch/built-in/audio/LSTM/pyacl_infer.py +++ b/ACL_PyTorch/built-in/audio/LSTM/pyacl_infer.py @@ -1,157 +1,157 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 acl -from acl_net import AclModel - -import os -import shutil -import argparse -import numpy as np -from tqdm import tqdm - -DTYPE = { - 'float32': np.float32, - 'float64': np.float64, - 'int32': np.int32, - 'int64': np.int64 -} - -if __name__ == '__main__': - ''' - 参数说明: - --model_path:模型路径 - --device_id:npu id - --cpu_run:MeasureTime类的cpu_run参数,True or False - --sync_infer:推理方式: - True:同步推理 - False:异步推理 - --workspace:类似TensorRT `workspace`参数,计算平均推理时间时排除前n次推理 - --input_info_file_path:类似benchmark的bin_info文件 - --input_dtypes:模型输入的类型,用逗号分割(`DTYPE`变量) - e.g. 模型只有一个输入:--input_dtypes=float32 - e.g. 模型有多个输入:--input_dtypes=float32,float32,float32(需要和bin_info文件多输入排列一致) - --infer_res_save_path:推理结果保存目录 - --res_save_type:推理结果保存类型,bin或npy - - info文件说明: - 因为支持动态shape,相比于benchmark的info文件,需要多加一列shape信息,e.g. - ``` - 0 ./bert_bin/input_ids_0.bin (1,512) - 0 ./bert_bin/segment_ids_0.bin (1,512) - 0 ./bert_bin/input_mask_0.bin (1,512) - 1 ./bert_bin/input_ids_1.bin (1,512) - 1 ./bert_bin/segment_ids_1.bin (1,512) - 1 ./bert_bin/input_mask_1.bin (1,512) - ``` - - Using Example: - python3.7 pyacl_infer.py \ - --model_path=./bert_base_batch_1_sim_auto.om \ - --device_id=0 \ - --cpu_run=True \ - --sync_infer=True \ - --workspace=10 \ - --input_info_file_path=./input.info \ - --input_dtypes=int64,int64,int64 \ - --infer_res_save_path=./infer_res \ - --res_save_type=bin - ''' - - # 参数解析 - parser = argparse.ArgumentParser() - parser.add_argument('--model_path', required=True) - parser.add_argument('--device_id', required=True, type=int) - parser.add_argument('--cpu_run', required=True, choices=['True', 'False']) - parser.add_argument('--sync_infer', required=True, choices=['True', 'False']) - parser.add_argument('--workspace', required=True, type=int) - parser.add_argument('--input_info_file_path', required=True) - parser.add_argument('--input_dtypes', required=True) - parser.add_argument('--infer_res_save_path', required=True) - parser.add_argument('--res_save_type', required=True, choices=['bin', 'npy']) - opt = parser.parse_args() - - # 创建模型 - measurements = {} - om_model = AclModel(device_id=opt.device_id, - model_path=opt.model_path, - sync_infer=eval(opt.sync_infer), - measurements=measurements, - key='per_infer_time_ns', - cpu_run=eval(opt.cpu_run)) - - # 创建目录 - if os.path.exists(opt.infer_res_save_path): - shutil.rmtree(opt.infer_res_save_path) - os.makedirs(opt.infer_res_save_path) - - # 读取info_file - inputs_info = {} - with open(opt.input_info_file_path, 'rt', encoding='utf-8') as f_info: - line = f_info.readline() - while line: - line = line.rstrip('\n') - contents = line.split() - info = {'path': contents[1], 'shape': eval(contents[2])} - inputs_info.setdefault(contents[0], []).append(info) - line = f_info.readline() - - # 解析输入类型 - input_dtypes = opt.input_dtypes.split(',') - input_dtypes = list(map(lambda x: DTYPE[x], input_dtypes)) - - # 读取文件推理 - total_infer_time = 0 - total_infer_time_workspace = 0 - total_infer_num = 0 - for key, values in tqdm(inputs_info.items()): - # 构造输入 - inputs = [] - dims = [] - for idx, value in enumerate(values): - x = np.fromfile(value['path'], dtype=input_dtypes[idx]).reshape(value['shape']) - inputs.append(x) - dims.extend(value['shape']) - dims_info = {'dimCount': len(dims), 'name': '', 'dims': dims} - - # 推理得到输出 - output = om_model(inputs, dims_info) - #print("[INFO]: output()", len(output)) - #print("[INFO]: output.shape()", output[0].shape) - #exit() - total_infer_num += 1 - - # 保存文件 - if opt.res_save_type == 'bin': - for idx, data in enumerate(output): - data.tofile(os.path.join(opt.infer_res_save_path, key + '.' + str(idx) + '.bin')) - else: - for idx, data in enumerate(output): - np.save(os.path.join(opt.infer_res_save_path, key + '.' + str(idx) + '.npy'), data) - - # 计算时间 - total_infer_time += measurements['per_infer_time_ns'] - if total_infer_num > opt.workspace: - total_infer_time_workspace += measurements['per_infer_time_ns'] - - # 推理时间 - print('[INFO] Infer time:') - msg = 'total infer num: ' + str(total_infer_num) + '\n' + \ - 'total pure infer time(ms): ' + str(total_infer_time / 1000 / 1000) + '\n' + \ - 'average pure infer time(ms): ' + str(total_infer_time / total_infer_num / 1000 / 1000) + '\n' + \ - 'average pure infer time after workspace(ms): ' + str(abs( - total_infer_time_workspace / (total_infer_num - opt.workspace) / 1000 / 1000)) + '\n' - print(msg) - with open(os.path.join(opt.infer_res_save_path, 'infer_time.txt'), 'wt', encoding='utf-8') as f_infer_time: - f_infer_time.write(msg) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 acl +from acl_net import AclModel + +import os +import shutil +import argparse +import numpy as np +from tqdm import tqdm + +DTYPE = { + 'float32': np.float32, + 'float64': np.float64, + 'int32': np.int32, + 'int64': np.int64 +} + +if __name__ == '__main__': + ''' + 参数说明: + --model_path:模型路径 + --device_id:npu id + --cpu_run:MeasureTime类的cpu_run参数,True or False + --sync_infer:推理方式: + True:同步推理 + False:异步推理 + --workspace:类似TensorRT `workspace`参数,计算平均推理时间时排除前n次推理 + --input_info_file_path:类似benchmark的bin_info文件 + --input_dtypes:模型输入的类型,用逗号分割(`DTYPE`变量) + e.g. 模型只有一个输入:--input_dtypes=float32 + e.g. 模型有多个输入:--input_dtypes=float32,float32,float32(需要和bin_info文件多输入排列一致) + --infer_res_save_path:推理结果保存目录 + --res_save_type:推理结果保存类型,bin或npy + + info文件说明: + 因为支持动态shape,相比于benchmark的info文件,需要多加一列shape信息,e.g. + ``` + 0 ./bert_bin/input_ids_0.bin (1,512) + 0 ./bert_bin/segment_ids_0.bin (1,512) + 0 ./bert_bin/input_mask_0.bin (1,512) + 1 ./bert_bin/input_ids_1.bin (1,512) + 1 ./bert_bin/segment_ids_1.bin (1,512) + 1 ./bert_bin/input_mask_1.bin (1,512) + ``` + + Using Example: + python3.7 pyacl_infer.py \ + --model_path=./bert_base_batch_1_sim_auto.om \ + --device_id=0 \ + --cpu_run=True \ + --sync_infer=True \ + --workspace=10 \ + --input_info_file_path=./input.info \ + --input_dtypes=int64,int64,int64 \ + --infer_res_save_path=./infer_res \ + --res_save_type=bin + ''' + + # 参数解析 + parser = argparse.ArgumentParser() + parser.add_argument('--model_path', required=True) + parser.add_argument('--device_id', required=True, type=int) + parser.add_argument('--cpu_run', required=True, choices=['True', 'False']) + parser.add_argument('--sync_infer', required=True, choices=['True', 'False']) + parser.add_argument('--workspace', required=True, type=int) + parser.add_argument('--input_info_file_path', required=True) + parser.add_argument('--input_dtypes', required=True) + parser.add_argument('--infer_res_save_path', required=True) + parser.add_argument('--res_save_type', required=True, choices=['bin', 'npy']) + opt = parser.parse_args() + + # 创建模型 + measurements = {} + om_model = AclModel(device_id=opt.device_id, + model_path=opt.model_path, + sync_infer=eval(opt.sync_infer), + measurements=measurements, + key='per_infer_time_ns', + cpu_run=eval(opt.cpu_run)) + + # 创建目录 + if os.path.exists(opt.infer_res_save_path): + shutil.rmtree(opt.infer_res_save_path) + os.makedirs(opt.infer_res_save_path) + + # 读取info_file + inputs_info = {} + with open(opt.input_info_file_path, 'rt', encoding='utf-8') as f_info: + line = f_info.readline() + while line: + line = line.rstrip('\n') + contents = line.split() + info = {'path': contents[1], 'shape': eval(contents[2])} + inputs_info.setdefault(contents[0], []).append(info) + line = f_info.readline() + + # 解析输入类型 + input_dtypes = opt.input_dtypes.split(',') + input_dtypes = list(map(lambda x: DTYPE[x], input_dtypes)) + + # 读取文件推理 + total_infer_time = 0 + total_infer_time_workspace = 0 + total_infer_num = 0 + for key, values in tqdm(inputs_info.items()): + # 构造输入 + inputs = [] + dims = [] + for idx, value in enumerate(values): + x = np.fromfile(value['path'], dtype=input_dtypes[idx]).reshape(value['shape']) + inputs.append(x) + dims.extend(value['shape']) + dims_info = {'dimCount': len(dims), 'name': '', 'dims': dims} + + # 推理得到输出 + output = om_model(inputs, dims_info) + #print("[INFO]: output()", len(output)) + #print("[INFO]: output.shape()", output[0].shape) + #exit() + total_infer_num += 1 + + # 保存文件 + if opt.res_save_type == 'bin': + for idx, data in enumerate(output): + data.tofile(os.path.join(opt.infer_res_save_path, key + '.' + str(idx) + '.bin')) + else: + for idx, data in enumerate(output): + np.save(os.path.join(opt.infer_res_save_path, key + '.' + str(idx) + '.npy'), data) + + # 计算时间 + total_infer_time += measurements['per_infer_time_ns'] + if total_infer_num > opt.workspace: + total_infer_time_workspace += measurements['per_infer_time_ns'] + + # 推理时间 + print('[INFO] Infer time:') + msg = 'total infer num: ' + str(total_infer_num) + '\n' + \ + 'total pure infer time(ms): ' + str(total_infer_time / 1000 / 1000) + '\n' + \ + 'average pure infer time(ms): ' + str(total_infer_time / total_infer_num / 1000 / 1000) + '\n' + \ + 'average pure infer time after workspace(ms): ' + str(abs( + total_infer_time_workspace / (total_infer_num - opt.workspace) / 1000 / 1000)) + '\n' + print(msg) + with open(os.path.join(opt.infer_res_save_path, 'infer_time.txt'), 'wt', encoding='utf-8') as f_infer_time: + f_infer_time.write(msg) diff --git a/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/LICENSE b/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/LICENSE index 6ae23f3ae7..68faf63cc5 100644 --- a/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/LICENSE +++ b/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2021 eurecom-asp - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +MIT License + +Copyright (c) 2021 eurecom-asp + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/README.md b/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/README.md index e90ac7edc5..b97f4f754c 100644 --- a/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/README.md +++ b/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/README.md @@ -1,100 +1,100 @@ -# RawNet2模型推理指导 - -- [1 文件说明](#1-文件说明) -- [2 环境准备](#2-环境准备) - - [2.1 文件下载](#21-文件下载) - - [2.2 文件拷贝](#22-文件拷贝) - - [2.3 设置环境变量](#23-设置环境变量) -- [3 端到端推理步骤](#3-端到端推理步骤) - - [3.1 修改pytorch模型源码](#31-修改pytorch模型源码) - - [3.2 pth转onnx模型](#32-pth转onnx模型) - - [3.3 修改导出的onnx模型](#33-修改导出的onnx模型) - - [3.4 利用ATC工具转换为om模型](#34-利用ATC工具转换为om模型) - - [3.5 om模型推理](#35-om模型推理) - ------- - -## 1 文件说明 -``` -RawNet2_for_Pytorch - ├── env.sh 设置环境变量 - ├── pth2onnx.py pytorch模型导出onnx模型 - ├── modify_onnx.py 修改导出的onnx模型 - ├── atc.sh onnx模型转om - ├── om_infer.py 推理导出的om模型 - └── acl_net.py PyACL推理工具代码 -``` - -## 2 环境准备 - -### 2.1 文件下载 -- [RawNet2_Pytorch源码下载](https://github.com/asvspoof-challenge/2021/tree/main/LA/Baseline-RawNet2) - ``` - git clone https://github.com/asvspoof-challenge/2021.git - cd 2021/LA/Baseline-RawNet2/ - ``` -- [权重下载](https://www.asvspoof.org/asvspoof2021/pre_trained_DF_RawNet2.zip) -- [数据集下载](https://datashare.ed.ac.uk/handle/10283/3336) - om推理采用ASVspoof2019数据集的验证集进行精度评估。 - -### 2.2 文件拷贝 -拷贝env.sh,pth2onnx.py,modify_onnx.py,atc.sh,om_infer.py,acl_net.py文件到2021/LA/Baseline-RawNet2/目录下。 -将下载的权重文件pre_trained_DF_RawNet2.pth放在和代码同一目录下。 -在同一目录下创建data目录并将下载的数据集放入,data目录中的文件结构如下所示。 -``` -data - └── LA - ├── ASVspoof2019_LA_asv_protocols - ├── ASVspoof2019_LA_asv_scores - ├── ASVspoof2019_LA_cm_protocols - ├── ASVspoof2019_LA_dev - ├── ASVspoof2019_LA_eval - └── ASVspoof2019_LA_train -``` - -### 2.3 设置环境变量 -```shell -source env.sh -``` - -## 3 端到端推理步骤 - -### 3.1 修改pytorch模型源码 -导onnx模型需要修改2021/LA/Baseline-RawNet2/model.py中的SincConv类,在该类的forward函数中增加一行,如下所示。 -```python -self.band_pass = torch.from_numpy(self.band_pass.numpy()) # 增加行,和下行缩进保持一致 -band_pass_filter=self.band_pass.to(self.device) # 根据该行代码找到增加位置 -``` - -### 3.2 pth导出onnx -```python -python3.7 pth2onnx.py \ - --pth_model=pre_trained_DF_RawNet2.pth \ - --onnx_model=rawnet2_ori.onnx \ - --batch_size=1 -``` - -### 3.3 修改导出的onnx模型 -```python -python3.7 -m onnxsim rawnet2_ori.onnx rawnet2_sim.onnx - -python3.7 modify_onnx.py \ - --input_onnx=rawnet2_sim.onnx \ - --output_onnx=rawnet2_modify.onnx -``` - -### 3.4 利用ATC工具转换为om模型 -```shell -bash atc.sh rawnet2_modify.onnx rawnet2_modify input:1,64600 -``` -注:目前ATC支持的onnx算子版本为11 - -### 3.5 om模型推理 -```python -python3.7 om_infer.py \ - --batch_size=1 \ - --om_path=rawnet2_modify.om \ - --eval_output='rawnet2_modify_om.txt' \ - --database_path='data/LA/' \ - --protocols_path='data/LA/' +# RawNet2模型推理指导 + +- [1 文件说明](#1-文件说明) +- [2 环境准备](#2-环境准备) + - [2.1 文件下载](#21-文件下载) + - [2.2 文件拷贝](#22-文件拷贝) + - [2.3 设置环境变量](#23-设置环境变量) +- [3 端到端推理步骤](#3-端到端推理步骤) + - [3.1 修改pytorch模型源码](#31-修改pytorch模型源码) + - [3.2 pth转onnx模型](#32-pth转onnx模型) + - [3.3 修改导出的onnx模型](#33-修改导出的onnx模型) + - [3.4 利用ATC工具转换为om模型](#34-利用ATC工具转换为om模型) + - [3.5 om模型推理](#35-om模型推理) + +------ + +## 1 文件说明 +``` +RawNet2_for_Pytorch + ├── env.sh 设置环境变量 + ├── pth2onnx.py pytorch模型导出onnx模型 + ├── modify_onnx.py 修改导出的onnx模型 + ├── atc.sh onnx模型转om + ├── om_infer.py 推理导出的om模型 + └── acl_net.py PyACL推理工具代码 +``` + +## 2 环境准备 + +### 2.1 文件下载 +- [RawNet2_Pytorch源码下载](https://github.com/asvspoof-challenge/2021/tree/main/LA/Baseline-RawNet2) + ``` + git clone https://github.com/asvspoof-challenge/2021.git + cd 2021/LA/Baseline-RawNet2/ + ``` +- [权重下载](https://www.asvspoof.org/asvspoof2021/pre_trained_DF_RawNet2.zip) +- [数据集下载](https://datashare.ed.ac.uk/handle/10283/3336) + om推理采用ASVspoof2019数据集的验证集进行精度评估。 + +### 2.2 文件拷贝 +拷贝env.sh,pth2onnx.py,modify_onnx.py,atc.sh,om_infer.py,acl_net.py文件到2021/LA/Baseline-RawNet2/目录下。 +将下载的权重文件pre_trained_DF_RawNet2.pth放在和代码同一目录下。 +在同一目录下创建data目录并将下载的数据集放入,data目录中的文件结构如下所示。 +``` +data + └── LA + ├── ASVspoof2019_LA_asv_protocols + ├── ASVspoof2019_LA_asv_scores + ├── ASVspoof2019_LA_cm_protocols + ├── ASVspoof2019_LA_dev + ├── ASVspoof2019_LA_eval + └── ASVspoof2019_LA_train +``` + +### 2.3 设置环境变量 +```shell +source env.sh +``` + +## 3 端到端推理步骤 + +### 3.1 修改pytorch模型源码 +导onnx模型需要修改2021/LA/Baseline-RawNet2/model.py中的SincConv类,在该类的forward函数中增加一行,如下所示。 +```python +self.band_pass = torch.from_numpy(self.band_pass.numpy()) # 增加行,和下行缩进保持一致 +band_pass_filter=self.band_pass.to(self.device) # 根据该行代码找到增加位置 +``` + +### 3.2 pth导出onnx +```python +python3.7 pth2onnx.py \ + --pth_model=pre_trained_DF_RawNet2.pth \ + --onnx_model=rawnet2_ori.onnx \ + --batch_size=1 +``` + +### 3.3 修改导出的onnx模型 +```python +python3.7 -m onnxsim rawnet2_ori.onnx rawnet2_sim.onnx + +python3.7 modify_onnx.py \ + --input_onnx=rawnet2_sim.onnx \ + --output_onnx=rawnet2_modify.onnx +``` + +### 3.4 利用ATC工具转换为om模型 +```shell +bash atc.sh rawnet2_modify.onnx rawnet2_modify input:1,64600 +``` +注:目前ATC支持的onnx算子版本为11 + +### 3.5 om模型推理 +```python +python3.7 om_infer.py \ + --batch_size=1 \ + --om_path=rawnet2_modify.om \ + --eval_output='rawnet2_modify_om.txt' \ + --database_path='data/LA/' \ + --protocols_path='data/LA/' ``` \ No newline at end of file diff --git a/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/acl_net.py b/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/acl_net.py index b39eb3530c..d6c2ea29b9 100644 --- a/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/acl_net.py +++ b/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/acl_net.py @@ -1,259 +1,259 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 time -import numpy as np -import functools -import acl - -# error code -ACL_ERROR_NONE = 0 - -# rule for mem -ACL_MEM_MALLOC_HUGE_FIRST = 0 -ACL_MEM_MALLOC_HUGE_ONLY = 1 -ACL_MEM_MALLOC_NORMAL_ONLY = 2 - -# rule for memory copy -ACL_MEMCPY_HOST_TO_HOST = 0 -ACL_MEMCPY_HOST_TO_DEVICE = 1 -ACL_MEMCPY_DEVICE_TO_HOST = 2 -ACL_MEMCPY_DEVICE_TO_DEVICE = 3 - -ACL_DTYPE = { - 0: 'float32', - 1: 'float16', - 2: 'int8', - 3: 'int32', - 4: 'uint8', - 6: 'int16', - 7: 'uint16', - 8: 'uint32', - 9: 'int64', - 10: 'uint64', - 11: 'float64', - 12: 'bool', -} - -buffer_method = { - "in": acl.mdl.get_input_size_by_index, - "out": acl.mdl.get_output_size_by_index -} - - -def check_ret(message, ret): - if ret != ACL_ERROR_NONE: - raise Exception("{} failed ret={}".format(message, ret)) - - -class Net(object): - def __init__(self, model_path, device_id=0, config_path=None): - self.device_id = device_id # int - self.model_path = model_path # string - self.model_id = None # pointer - self.context = None # pointer - - self.input_data = [] - self.output_data = [] - self.model_desc = None # pointer when using - self.load_input_dataset = None - self.load_output_dataset = None - - self._init_resource(config_path) - - def __call__(self, ori_data): - return self.forward(ori_data) - - def __del__(self): - ret = acl.mdl.unload(self.model_id) - check_ret("acl.mdl.unload", ret) - if self.model_desc: - acl.mdl.destroy_desc(self.model_desc) - self.model_desc = None - - while self.input_data: - item = self.input_data.pop() - ret = acl.rt.free(item["buffer"]) - check_ret("acl.rt.free", ret) - - while self.output_data: - item = self.output_data.pop() - ret = acl.rt.free(item["buffer"]) - check_ret("acl.rt.free", ret) - - if self.context: - ret = acl.rt.destroy_context(self.context) - check_ret("acl.rt.destroy_context", ret) - self.context = None - - ret = acl.rt.reset_device(self.device_id) - check_ret("acl.rt.reset_device", ret) - ret = acl.finalize() - check_ret("acl.finalize", ret) - - def _init_resource(self, config_path=None): - if config_path: - ret = acl.init(config_path) - else: - ret = acl.init() - check_ret("acl.init", ret) - ret = acl.rt.set_device(self.device_id) - check_ret("acl.rt.set_device", ret) - - self.context, ret = acl.rt.create_context(self.device_id) - check_ret("acl.rt.create_context", ret) - - # load_model - self.model_id, ret = acl.mdl.load_from_file(self.model_path) - check_ret("acl.mdl.load_from_file", ret) - - self.model_desc = acl.mdl.create_desc() - self._get_model_info() - - def _get_model_info(self, ): - ret = acl.mdl.get_desc(self.model_desc, self.model_id) - check_ret("acl.mdl.get_desc", ret) - input_size = acl.mdl.get_num_inputs(self.model_desc) - output_size = acl.mdl.get_num_outputs(self.model_desc) - self._gen_data_buffer(input_size, des="in") - self._gen_data_buffer(output_size, des="out") - - def _gen_data_buffer(self, size, des): - func = buffer_method[des] - for i in range(size): - temp_buffer_size = func(self.model_desc, i) - temp_buffer, ret = acl.rt.malloc(temp_buffer_size, - ACL_MEM_MALLOC_HUGE_FIRST) - check_ret("acl.rt.malloc", ret) - - if des == "in": - self.input_data.append({"buffer": temp_buffer, - "size": temp_buffer_size}) - elif des == "out": - self.output_data.append({"buffer": temp_buffer, - "size": temp_buffer_size}) - - def _data_interaction(self, dataset, policy=ACL_MEMCPY_HOST_TO_DEVICE): - temp_data_buffer = self.input_data \ - if policy == ACL_MEMCPY_HOST_TO_DEVICE \ - else self.output_data - if len(dataset) == 0 and policy == ACL_MEMCPY_DEVICE_TO_HOST: - for item in self.output_data: - temp, ret = acl.rt.malloc_host(item["size"]) - if ret != 0: - raise Exception("can't malloc_host ret={}".format(ret)) - dataset.append({"size": item["size"], "buffer": temp}) - - for i, item in enumerate(temp_data_buffer): - if policy == ACL_MEMCPY_HOST_TO_DEVICE: - ptr = acl.util.numpy_to_ptr(dataset[i]) - ret = acl.rt.memcpy(item["buffer"], - item["size"], - ptr, - item["size"], - policy) - check_ret("acl.rt.memcpy", ret) - - else: - ptr = dataset[i]["buffer"] - ret = acl.rt.memcpy(ptr, - item["size"], - item["buffer"], - item["size"], - policy) - check_ret("acl.rt.memcpy", ret) - - def _gen_dataset(self, type_str="input"): - dataset = acl.mdl.create_dataset() - - temp_dataset = None - if type_str == "in": - self.load_input_dataset = dataset - temp_dataset = self.input_data - else: - self.load_output_dataset = dataset - temp_dataset = self.output_data - - for item in temp_dataset: - data = acl.create_data_buffer(item["buffer"], item["size"]) - if data is None: - ret = acl.destroy_data_buffer(dataset) - check_ret("acl.destroy_data_buffer", ret) - - _, ret = acl.mdl.add_dataset_buffer(dataset, data) - - if ret != ACL_ERROR_NONE: - ret = acl.destroy_data_buffer(dataset) - check_ret("acl.destroy_data_buffer", ret) - - def _data_from_host_to_device(self, images): - self._data_interaction(images, ACL_MEMCPY_HOST_TO_DEVICE) - self._gen_dataset("in") - self._gen_dataset("out") - - def _data_from_device_to_host(self): - res = [] - self._data_interaction(res, ACL_MEMCPY_DEVICE_TO_HOST) - output = self.get_result(res) - return output - - def _destroy_databuffer(self, ): - for dataset in [self.load_input_dataset, self.load_output_dataset]: - if not dataset: - continue - - num = acl.mdl.get_dataset_num_buffers(dataset) - for i in range(num): - data_buf = acl.mdl.get_dataset_buffer(dataset, i) - if data_buf: - ret = acl.destroy_data_buffer(data_buf) - check_ret("acl.destroy_data_buffer", ret) - ret = acl.mdl.destroy_dataset(dataset) - check_ret("acl.mdl.destroy_dataset", ret) - - def forward(self, input_data): - if not isinstance(input_data, (list, tuple)): - input_data = [input_data] - st = time.time() - self._data_from_host_to_device(input_data) - mem_t = time.time() - st - st = time.time() - ret = acl.mdl.execute(self.model_id, - self.load_input_dataset, - self.load_output_dataset) - exe_t = time.time() - st - st = time.time() - check_ret("acl.mdl.execute", ret) - self._destroy_databuffer() - result = self._data_from_device_to_host() - mem_t += time.time() - st - return result - - def get_result(self, output_data): - dataset = [] - for i in range(len(output_data)): - dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) - check_ret("acl.mdl.get_cur_output_dims", ret) - data_shape = dims.get("dims") - data_type = acl.mdl.get_output_data_type(self.model_desc, i) - data_len = functools.reduce(lambda x, y: x * y, data_shape) - ftype = np.dtype(ACL_DTYPE.get(data_type)) - - size = output_data[i]["size"] - ptr = output_data[i]["buffer"] - data = acl.util.ptr_to_numpy(ptr, (size,), 1) - np_arr = np.frombuffer(bytearray(data[:data_len * ftype.itemsize]), dtype=ftype, count=data_len) - np_arr = np_arr.reshape(data_shape) - dataset.append(np_arr) - return dataset +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 time +import numpy as np +import functools +import acl + +# error code +ACL_ERROR_NONE = 0 + +# rule for mem +ACL_MEM_MALLOC_HUGE_FIRST = 0 +ACL_MEM_MALLOC_HUGE_ONLY = 1 +ACL_MEM_MALLOC_NORMAL_ONLY = 2 + +# rule for memory copy +ACL_MEMCPY_HOST_TO_HOST = 0 +ACL_MEMCPY_HOST_TO_DEVICE = 1 +ACL_MEMCPY_DEVICE_TO_HOST = 2 +ACL_MEMCPY_DEVICE_TO_DEVICE = 3 + +ACL_DTYPE = { + 0: 'float32', + 1: 'float16', + 2: 'int8', + 3: 'int32', + 4: 'uint8', + 6: 'int16', + 7: 'uint16', + 8: 'uint32', + 9: 'int64', + 10: 'uint64', + 11: 'float64', + 12: 'bool', +} + +buffer_method = { + "in": acl.mdl.get_input_size_by_index, + "out": acl.mdl.get_output_size_by_index +} + + +def check_ret(message, ret): + if ret != ACL_ERROR_NONE: + raise Exception("{} failed ret={}".format(message, ret)) + + +class Net(object): + def __init__(self, model_path, device_id=0, config_path=None): + self.device_id = device_id # int + self.model_path = model_path # string + self.model_id = None # pointer + self.context = None # pointer + + self.input_data = [] + self.output_data = [] + self.model_desc = None # pointer when using + self.load_input_dataset = None + self.load_output_dataset = None + + self._init_resource(config_path) + + def __call__(self, ori_data): + return self.forward(ori_data) + + def __del__(self): + ret = acl.mdl.unload(self.model_id) + check_ret("acl.mdl.unload", ret) + if self.model_desc: + acl.mdl.destroy_desc(self.model_desc) + self.model_desc = None + + while self.input_data: + item = self.input_data.pop() + ret = acl.rt.free(item["buffer"]) + check_ret("acl.rt.free", ret) + + while self.output_data: + item = self.output_data.pop() + ret = acl.rt.free(item["buffer"]) + check_ret("acl.rt.free", ret) + + if self.context: + ret = acl.rt.destroy_context(self.context) + check_ret("acl.rt.destroy_context", ret) + self.context = None + + ret = acl.rt.reset_device(self.device_id) + check_ret("acl.rt.reset_device", ret) + ret = acl.finalize() + check_ret("acl.finalize", ret) + + def _init_resource(self, config_path=None): + if config_path: + ret = acl.init(config_path) + else: + ret = acl.init() + check_ret("acl.init", ret) + ret = acl.rt.set_device(self.device_id) + check_ret("acl.rt.set_device", ret) + + self.context, ret = acl.rt.create_context(self.device_id) + check_ret("acl.rt.create_context", ret) + + # load_model + self.model_id, ret = acl.mdl.load_from_file(self.model_path) + check_ret("acl.mdl.load_from_file", ret) + + self.model_desc = acl.mdl.create_desc() + self._get_model_info() + + def _get_model_info(self, ): + ret = acl.mdl.get_desc(self.model_desc, self.model_id) + check_ret("acl.mdl.get_desc", ret) + input_size = acl.mdl.get_num_inputs(self.model_desc) + output_size = acl.mdl.get_num_outputs(self.model_desc) + self._gen_data_buffer(input_size, des="in") + self._gen_data_buffer(output_size, des="out") + + def _gen_data_buffer(self, size, des): + func = buffer_method[des] + for i in range(size): + temp_buffer_size = func(self.model_desc, i) + temp_buffer, ret = acl.rt.malloc(temp_buffer_size, + ACL_MEM_MALLOC_HUGE_FIRST) + check_ret("acl.rt.malloc", ret) + + if des == "in": + self.input_data.append({"buffer": temp_buffer, + "size": temp_buffer_size}) + elif des == "out": + self.output_data.append({"buffer": temp_buffer, + "size": temp_buffer_size}) + + def _data_interaction(self, dataset, policy=ACL_MEMCPY_HOST_TO_DEVICE): + temp_data_buffer = self.input_data \ + if policy == ACL_MEMCPY_HOST_TO_DEVICE \ + else self.output_data + if len(dataset) == 0 and policy == ACL_MEMCPY_DEVICE_TO_HOST: + for item in self.output_data: + temp, ret = acl.rt.malloc_host(item["size"]) + if ret != 0: + raise Exception("can't malloc_host ret={}".format(ret)) + dataset.append({"size": item["size"], "buffer": temp}) + + for i, item in enumerate(temp_data_buffer): + if policy == ACL_MEMCPY_HOST_TO_DEVICE: + ptr = acl.util.numpy_to_ptr(dataset[i]) + ret = acl.rt.memcpy(item["buffer"], + item["size"], + ptr, + item["size"], + policy) + check_ret("acl.rt.memcpy", ret) + + else: + ptr = dataset[i]["buffer"] + ret = acl.rt.memcpy(ptr, + item["size"], + item["buffer"], + item["size"], + policy) + check_ret("acl.rt.memcpy", ret) + + def _gen_dataset(self, type_str="input"): + dataset = acl.mdl.create_dataset() + + temp_dataset = None + if type_str == "in": + self.load_input_dataset = dataset + temp_dataset = self.input_data + else: + self.load_output_dataset = dataset + temp_dataset = self.output_data + + for item in temp_dataset: + data = acl.create_data_buffer(item["buffer"], item["size"]) + if data is None: + ret = acl.destroy_data_buffer(dataset) + check_ret("acl.destroy_data_buffer", ret) + + _, ret = acl.mdl.add_dataset_buffer(dataset, data) + + if ret != ACL_ERROR_NONE: + ret = acl.destroy_data_buffer(dataset) + check_ret("acl.destroy_data_buffer", ret) + + def _data_from_host_to_device(self, images): + self._data_interaction(images, ACL_MEMCPY_HOST_TO_DEVICE) + self._gen_dataset("in") + self._gen_dataset("out") + + def _data_from_device_to_host(self): + res = [] + self._data_interaction(res, ACL_MEMCPY_DEVICE_TO_HOST) + output = self.get_result(res) + return output + + def _destroy_databuffer(self, ): + for dataset in [self.load_input_dataset, self.load_output_dataset]: + if not dataset: + continue + + num = acl.mdl.get_dataset_num_buffers(dataset) + for i in range(num): + data_buf = acl.mdl.get_dataset_buffer(dataset, i) + if data_buf: + ret = acl.destroy_data_buffer(data_buf) + check_ret("acl.destroy_data_buffer", ret) + ret = acl.mdl.destroy_dataset(dataset) + check_ret("acl.mdl.destroy_dataset", ret) + + def forward(self, input_data): + if not isinstance(input_data, (list, tuple)): + input_data = [input_data] + st = time.time() + self._data_from_host_to_device(input_data) + mem_t = time.time() - st + st = time.time() + ret = acl.mdl.execute(self.model_id, + self.load_input_dataset, + self.load_output_dataset) + exe_t = time.time() - st + st = time.time() + check_ret("acl.mdl.execute", ret) + self._destroy_databuffer() + result = self._data_from_device_to_host() + mem_t += time.time() - st + return result + + def get_result(self, output_data): + dataset = [] + for i in range(len(output_data)): + dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) + check_ret("acl.mdl.get_cur_output_dims", ret) + data_shape = dims.get("dims") + data_type = acl.mdl.get_output_data_type(self.model_desc, i) + data_len = functools.reduce(lambda x, y: x * y, data_shape) + ftype = np.dtype(ACL_DTYPE.get(data_type)) + + size = output_data[i]["size"] + ptr = output_data[i]["buffer"] + data = acl.util.ptr_to_numpy(ptr, (size,), 1) + np_arr = np.frombuffer(bytearray(data[:data_len * ftype.itemsize]), dtype=ftype, count=data_len) + np_arr = np_arr.reshape(data_shape) + dataset.append(np_arr) + return dataset diff --git a/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/modelzoo_level.txt b/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/modelzoo_level.txt +++ b/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/modify_onnx.py b/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/modify_onnx.py index ff9cc34aac..dcbbc457d0 100644 --- a/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/modify_onnx.py +++ b/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/modify_onnx.py @@ -1,222 +1,222 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -# -*- coding:utf-8 -*- - -import argparse -import numpy as np -import copy -from gener_core.mod_modify.interface import AttrType as AT -from gener_core.mod_modify.onnx_graph import OXGraph - - -def make_conv2d_split_node(mod, conv_node, weight, chk_idx, chk_sz, ksz): - x_node = mod.get_node(conv_node.input_name[0]) - - # slice - rng = np.random.randint(0, 7393) - begin = chk_sz * chk_idx - end = -(ksz - chk_sz) + chk_sz * chk_idx - if end >= 0: - end = np.iinfo(np.int32).max - begin1_node = mod.add_const_node(f"const_begin_{rng}", np.array([begin], np.int32)) - end1_node = mod.add_const_node(f"const_end_{rng}", np.array([end], np.int32)) - axes_node = mod.add_const_node(f"const_axes_{rng}", np.array([-1], np.int32)) - step_node = mod.add_const_node(f"const_step_{rng}", np.array([1], np.int32)) - slice1_node = mod.add_new_node(f"Slice_{rng}", "Slice") - slice1_node.set_input_node(0, [x_node, begin1_node, end1_node, axes_node, step_node]) - - # conv - conv1_node = mod.add_new_node(f"Conv_{np.random.randint(0, 7393)}", "Conv", - {"dilations": (AT.LIST_INT, [1, 1]), - "group": (AT.INT, 1), - "kernel_shape": (AT.LIST_INT, [1, weight.shape[-1]]), - "pads": (AT.LIST_INT, [0, 0, 0, 0]), - "strides": (AT.LIST_INT, [1, 1]), }) - w1_node = mod.add_const_node(f"weight_{np.random.randint(0, 7393)}", weight) - conv1_node.set_input_node(0, [slice1_node, w1_node]) - - return conv1_node - - -def shape_dim_extend(mod, io_map): - # NCD -> NCHW - rshp_node = mod.get_node("Reshape_9") - shape_node = mod.get_node(rshp_node.input_name[1]) - shape_value = shape_node.const_value - rng = np.random.randint(0, 7393) - shape_value = np.insert(shape_value, 2, 1) - new_shape_node = mod.add_const_node(f"const_shape_{rng}", shape_value.astype(np.int32)) - mod.node_replace(shape_node, new_shape_node) - - # modify all nodes for conv and maxpool - g_nodes = mod.get_nodes_by_optype("Conv") - for g_node in g_nodes: - weight_node = mod.get_node(g_node.input_name[1]) - weight_value = weight_node.const_value - - if len(weight_value.shape) == 3: - rng = np.random.randint(0, 7393) - kernel_shape = [1] + g_node.get_attr('kernel_shape', AT.LIST_INT) - dilations = g_node.get_attr('dilations', AT.LIST_INT) * 2 - pads = g_node.get_attr('pads', AT.LIST_INT) - if pads == [0, 0]: - pads = [0, 0, 0, 0] - if pads == [1, 1]: - pads = [0, 1, 0, 1] - strides = g_node.get_attr('strides', AT.LIST_INT) * 2 - g_node.set_attr({"kernel_shape": (AT.LIST_INT, kernel_shape)}) - g_node.set_attr({"dilations": (AT.LIST_INT, dilations)}) - g_node.set_attr({"pads": (AT.LIST_INT, pads)}) - g_node.set_attr({"strides": (AT.LIST_INT, strides)}) - new_weight_node = mod.add_const_node(f"const_weight_{rng}", np.expand_dims(weight_value, axis=2)) - mod.node_replace(weight_node, new_weight_node) - - g_node = mod.get_node("MaxPool_13") - rng = np.random.randint(0, 7393) - kernel_shape = [1] + g_node.get_attr('kernel_shape', AT.LIST_INT) - pads = g_node.get_attr('pads', AT.LIST_INT) * 2 - strides = g_node.get_attr('strides', AT.LIST_INT) * 2 - g_node.set_attr({"kernel_shape": (AT.LIST_INT, kernel_shape), - "dilations": (AT.LIST_INT, dilations), - "pads": (AT.LIST_INT, pads), - "strides": (AT.LIST_INT, strides)}) - - # NCHW -> NCD - res_node = mod.get_node('MaxPool_13') - squeeze_node = mod.add_new_node(f"Squeeze_{np.random.randint(0, 7393)}", "Squeeze", - {"axes": (AT.LIST_INT, [2])}) - squeeze_node.set_input_node(0, [res_node]) - after_res_node = mod.get_node(io_map.get(res_node.name)[0]) - after_res_node.set_input_node(0, [squeeze_node]) - - # NCD -> NCHW - g_nodes = mod.get_nodes_by_optype("Conv") - for g_node in g_nodes: - if g_node.name != "Conv_11" and mod.get_node(g_node.input_name[0]).op_type != "LeakyRelu": - rng = np.random.randint(0, 7393) - unsqueeze_node = mod.add_new_node(f"Unsqueeze_{rng}", "Unsqueeze", - {"axes": (AT.LIST_INT, [2])}) - - before_g_node = mod.get_node(g_node.input_name[0]) - w_node = mod.get_node(g_node.input_name[1]) - if len(g_node.input_name) == 2: - g_node.set_input_node(0, [unsqueeze_node, w_node]) - else: - b_node = mod.get_node(g_node.input_name[2]) - g_node.set_input_node(0, [unsqueeze_node, w_node, b_node]) - unsqueeze_node.set_input_node(0, [before_g_node]) - - # NCHW -> NCD - g_nodes = mod.get_nodes_by_optype("Add") - for g_node in g_nodes: - Add_b0 = mod.get_node(g_node.input_name[0]) - Add_b1 = mod.get_node(g_node.input_name[1]) - if mod.get_node(Add_b0.input_name[0]).op_type == "LeakyRelu": - rng = np.random.randint(0, 7393) - if Add_b1.op_type != "Conv": - unsqueeze_node = mod.add_new_node(f"Unsqueeze_{rng}", "Unsqueeze", - {"axes": (AT.LIST_INT, [2])}) - g_node.set_input_node(0, [unsqueeze_node, Add_b0]) - unsqueeze_node.set_input_node(0, [Add_b1]) - - squeeze_node = mod.add_new_node(f"Squeeze_{rng}", "Squeeze", - {"axes": (AT.LIST_INT, [2])}) - squeeze_node.set_input_node(0, [g_node]) - after_g_node = mod.get_node(io_map.get(g_node.name)[0]) - after_g_node.set_input_node(0, [squeeze_node]) - - -def make_model(input_onnx, output_onnx): - mod = OXGraph(input_onnx) - io_map = mod.get_net_in_out_map() - - # solve accuracy problem - gather_nodes = mod.get_nodes_by_optype("Gather") - for g_node in gather_nodes: - if g_node.name == 'Gather_203': - indices_node = mod.add_const_node(f'Const_{g_node.input_name[1]}', np.array(28).astype('int64')) - g_node.set_input_node(1, [indices_node]) - - # NCD -> NCHW - shape_dim_extend(mod, io_map) - - # conv split - conv_node = mod.get_node("Conv_11") - weight_node = mod.get_node(conv_node.input_name[1]) - weight_value = weight_node.const_value - - np.random.seed(1737) - KSZ = weight_value.shape[-1] - CHK_SZ = 128 - CHK_N = KSZ // CHK_SZ - wgt = [] - for i in range(CHK_N): - wgt.append(weight_value[:, :, :, CHK_SZ * i:CHK_SZ * (i + 1)]) - if KSZ % CHK_SZ != 0: - wgt.append(weight_value[:, :, :, CHK_SZ * CHK_N:]) - - rwn_node = [] - for i, w in enumerate(wgt): - node = make_conv2d_split_node(mod, conv_node, w, i, CHK_SZ, KSZ) - rwn_node.append(node) - - in_node_list = copy.deepcopy(rwn_node[:CHK_N]) - out_node_list = [] - combin_len = CHK_N - while len(in_node_list) > 1: - for j in range(0, combin_len, 2): - add_node = mod.add_new_node(f"Add_{np.random.randint(0, 7393)}", "Add") - add_node.set_input_node(0, [in_node_list[j], in_node_list[j + 1]]) - out_node_list.append(add_node) - in_node_list = copy.deepcopy(out_node_list) - out_node_list.clear() - combin_len //= 2 - - # add all result - if KSZ % CHK_SZ != 0: - add_node = mod.add_new_node(f"Add_{np.random.randint(0, 7393)}", "Add") - add_node.set_input_node(0, [in_node_list[0], rwn_node[-1]]) - else: - add_node = in_node_list[0] - - # relink - after_node = mod.get_node(io_map.get(conv_node.name)[0]) - after_node.set_input_node(0, [add_node]) - - # remove ori node - mod.node_remove([conv_node.name]) - mod.save_new_model(output_onnx) - - -def get_parser(): - parser = argparse.ArgumentParser(description='RawNet2') - parser.add_argument('--input_onnx', default=None, type=str, - help='input original onnx') - parser.add_argument('--output_onnx', default=None, type=str, - help='output modified onnx') - return parser - - -if __name__ == "__main__": - ''' - Example: - python3.7 modify_onnx.py \ - --input_onnx=rawnet2_sim.onnx \ - --output_onnx=rawnet2_modify.onnx - ''' - parser = get_parser() - args = parser.parse_args() - make_model(args.input_onnx, args.output_onnx) - print("modify successfully!") +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +# -*- coding:utf-8 -*- + +import argparse +import numpy as np +import copy +from gener_core.mod_modify.interface import AttrType as AT +from gener_core.mod_modify.onnx_graph import OXGraph + + +def make_conv2d_split_node(mod, conv_node, weight, chk_idx, chk_sz, ksz): + x_node = mod.get_node(conv_node.input_name[0]) + + # slice + rng = np.random.randint(0, 7393) + begin = chk_sz * chk_idx + end = -(ksz - chk_sz) + chk_sz * chk_idx + if end >= 0: + end = np.iinfo(np.int32).max + begin1_node = mod.add_const_node(f"const_begin_{rng}", np.array([begin], np.int32)) + end1_node = mod.add_const_node(f"const_end_{rng}", np.array([end], np.int32)) + axes_node = mod.add_const_node(f"const_axes_{rng}", np.array([-1], np.int32)) + step_node = mod.add_const_node(f"const_step_{rng}", np.array([1], np.int32)) + slice1_node = mod.add_new_node(f"Slice_{rng}", "Slice") + slice1_node.set_input_node(0, [x_node, begin1_node, end1_node, axes_node, step_node]) + + # conv + conv1_node = mod.add_new_node(f"Conv_{np.random.randint(0, 7393)}", "Conv", + {"dilations": (AT.LIST_INT, [1, 1]), + "group": (AT.INT, 1), + "kernel_shape": (AT.LIST_INT, [1, weight.shape[-1]]), + "pads": (AT.LIST_INT, [0, 0, 0, 0]), + "strides": (AT.LIST_INT, [1, 1]), }) + w1_node = mod.add_const_node(f"weight_{np.random.randint(0, 7393)}", weight) + conv1_node.set_input_node(0, [slice1_node, w1_node]) + + return conv1_node + + +def shape_dim_extend(mod, io_map): + # NCD -> NCHW + rshp_node = mod.get_node("Reshape_9") + shape_node = mod.get_node(rshp_node.input_name[1]) + shape_value = shape_node.const_value + rng = np.random.randint(0, 7393) + shape_value = np.insert(shape_value, 2, 1) + new_shape_node = mod.add_const_node(f"const_shape_{rng}", shape_value.astype(np.int32)) + mod.node_replace(shape_node, new_shape_node) + + # modify all nodes for conv and maxpool + g_nodes = mod.get_nodes_by_optype("Conv") + for g_node in g_nodes: + weight_node = mod.get_node(g_node.input_name[1]) + weight_value = weight_node.const_value + + if len(weight_value.shape) == 3: + rng = np.random.randint(0, 7393) + kernel_shape = [1] + g_node.get_attr('kernel_shape', AT.LIST_INT) + dilations = g_node.get_attr('dilations', AT.LIST_INT) * 2 + pads = g_node.get_attr('pads', AT.LIST_INT) + if pads == [0, 0]: + pads = [0, 0, 0, 0] + if pads == [1, 1]: + pads = [0, 1, 0, 1] + strides = g_node.get_attr('strides', AT.LIST_INT) * 2 + g_node.set_attr({"kernel_shape": (AT.LIST_INT, kernel_shape)}) + g_node.set_attr({"dilations": (AT.LIST_INT, dilations)}) + g_node.set_attr({"pads": (AT.LIST_INT, pads)}) + g_node.set_attr({"strides": (AT.LIST_INT, strides)}) + new_weight_node = mod.add_const_node(f"const_weight_{rng}", np.expand_dims(weight_value, axis=2)) + mod.node_replace(weight_node, new_weight_node) + + g_node = mod.get_node("MaxPool_13") + rng = np.random.randint(0, 7393) + kernel_shape = [1] + g_node.get_attr('kernel_shape', AT.LIST_INT) + pads = g_node.get_attr('pads', AT.LIST_INT) * 2 + strides = g_node.get_attr('strides', AT.LIST_INT) * 2 + g_node.set_attr({"kernel_shape": (AT.LIST_INT, kernel_shape), + "dilations": (AT.LIST_INT, dilations), + "pads": (AT.LIST_INT, pads), + "strides": (AT.LIST_INT, strides)}) + + # NCHW -> NCD + res_node = mod.get_node('MaxPool_13') + squeeze_node = mod.add_new_node(f"Squeeze_{np.random.randint(0, 7393)}", "Squeeze", + {"axes": (AT.LIST_INT, [2])}) + squeeze_node.set_input_node(0, [res_node]) + after_res_node = mod.get_node(io_map.get(res_node.name)[0]) + after_res_node.set_input_node(0, [squeeze_node]) + + # NCD -> NCHW + g_nodes = mod.get_nodes_by_optype("Conv") + for g_node in g_nodes: + if g_node.name != "Conv_11" and mod.get_node(g_node.input_name[0]).op_type != "LeakyRelu": + rng = np.random.randint(0, 7393) + unsqueeze_node = mod.add_new_node(f"Unsqueeze_{rng}", "Unsqueeze", + {"axes": (AT.LIST_INT, [2])}) + + before_g_node = mod.get_node(g_node.input_name[0]) + w_node = mod.get_node(g_node.input_name[1]) + if len(g_node.input_name) == 2: + g_node.set_input_node(0, [unsqueeze_node, w_node]) + else: + b_node = mod.get_node(g_node.input_name[2]) + g_node.set_input_node(0, [unsqueeze_node, w_node, b_node]) + unsqueeze_node.set_input_node(0, [before_g_node]) + + # NCHW -> NCD + g_nodes = mod.get_nodes_by_optype("Add") + for g_node in g_nodes: + Add_b0 = mod.get_node(g_node.input_name[0]) + Add_b1 = mod.get_node(g_node.input_name[1]) + if mod.get_node(Add_b0.input_name[0]).op_type == "LeakyRelu": + rng = np.random.randint(0, 7393) + if Add_b1.op_type != "Conv": + unsqueeze_node = mod.add_new_node(f"Unsqueeze_{rng}", "Unsqueeze", + {"axes": (AT.LIST_INT, [2])}) + g_node.set_input_node(0, [unsqueeze_node, Add_b0]) + unsqueeze_node.set_input_node(0, [Add_b1]) + + squeeze_node = mod.add_new_node(f"Squeeze_{rng}", "Squeeze", + {"axes": (AT.LIST_INT, [2])}) + squeeze_node.set_input_node(0, [g_node]) + after_g_node = mod.get_node(io_map.get(g_node.name)[0]) + after_g_node.set_input_node(0, [squeeze_node]) + + +def make_model(input_onnx, output_onnx): + mod = OXGraph(input_onnx) + io_map = mod.get_net_in_out_map() + + # solve accuracy problem + gather_nodes = mod.get_nodes_by_optype("Gather") + for g_node in gather_nodes: + if g_node.name == 'Gather_203': + indices_node = mod.add_const_node(f'Const_{g_node.input_name[1]}', np.array(28).astype('int64')) + g_node.set_input_node(1, [indices_node]) + + # NCD -> NCHW + shape_dim_extend(mod, io_map) + + # conv split + conv_node = mod.get_node("Conv_11") + weight_node = mod.get_node(conv_node.input_name[1]) + weight_value = weight_node.const_value + + np.random.seed(1737) + KSZ = weight_value.shape[-1] + CHK_SZ = 128 + CHK_N = KSZ // CHK_SZ + wgt = [] + for i in range(CHK_N): + wgt.append(weight_value[:, :, :, CHK_SZ * i:CHK_SZ * (i + 1)]) + if KSZ % CHK_SZ != 0: + wgt.append(weight_value[:, :, :, CHK_SZ * CHK_N:]) + + rwn_node = [] + for i, w in enumerate(wgt): + node = make_conv2d_split_node(mod, conv_node, w, i, CHK_SZ, KSZ) + rwn_node.append(node) + + in_node_list = copy.deepcopy(rwn_node[:CHK_N]) + out_node_list = [] + combin_len = CHK_N + while len(in_node_list) > 1: + for j in range(0, combin_len, 2): + add_node = mod.add_new_node(f"Add_{np.random.randint(0, 7393)}", "Add") + add_node.set_input_node(0, [in_node_list[j], in_node_list[j + 1]]) + out_node_list.append(add_node) + in_node_list = copy.deepcopy(out_node_list) + out_node_list.clear() + combin_len //= 2 + + # add all result + if KSZ % CHK_SZ != 0: + add_node = mod.add_new_node(f"Add_{np.random.randint(0, 7393)}", "Add") + add_node.set_input_node(0, [in_node_list[0], rwn_node[-1]]) + else: + add_node = in_node_list[0] + + # relink + after_node = mod.get_node(io_map.get(conv_node.name)[0]) + after_node.set_input_node(0, [add_node]) + + # remove ori node + mod.node_remove([conv_node.name]) + mod.save_new_model(output_onnx) + + +def get_parser(): + parser = argparse.ArgumentParser(description='RawNet2') + parser.add_argument('--input_onnx', default=None, type=str, + help='input original onnx') + parser.add_argument('--output_onnx', default=None, type=str, + help='output modified onnx') + return parser + + +if __name__ == "__main__": + ''' + Example: + python3.7 modify_onnx.py \ + --input_onnx=rawnet2_sim.onnx \ + --output_onnx=rawnet2_modify.onnx + ''' + parser = get_parser() + args = parser.parse_args() + make_model(args.input_onnx, args.output_onnx) + print("modify successfully!") diff --git a/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/om_infer.py b/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/om_infer.py index 13909b374e..750f07d2b1 100644 --- a/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/om_infer.py +++ b/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/om_infer.py @@ -1,160 +1,160 @@ -# Copyright 2018 NVIDIA Corporation. 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. -# ============================================================================ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import argparse -import time -import math -import numpy as np -from tqdm import tqdm -import librosa -import torch -import torch.nn.functional as F -from torch import Tensor -from torch.utils.data import Dataset -from torch.utils.data import DataLoader -from acl_net import Net - - -def genSpoof_list(dir_meta): - d_meta = {} - file_list = [] - with open(dir_meta, 'r') as f: - l_meta = f.readlines() - - for line in l_meta: - key = line.strip().split(' ')[1] - file_list.append(key) - return file_list - - -def pad(x, max_len=64600): - x_len = x.shape[0] - if x_len >= max_len: - return x[:max_len] - # need to pad - num_repeats = int(max_len / x_len) + 1 - padded_x = np.tile(x, (1, num_repeats))[:, :max_len][0] - return padded_x - - -class Dataset_ASVspoof2019_eval(Dataset): - def __init__(self, list_IDs, base_dir): - '''self.list_IDs : list of strings (each string: utt key)''' - - self.list_IDs = list_IDs - self.base_dir = base_dir - - def __len__(self): - return len(self.list_IDs) - - def __getitem__(self, index): - self.cut = 64600 # take ~4 sec audio (64600 samples) - key = self.list_IDs[index] - X, fs = librosa.load(self.base_dir + 'flac/' + key + '.flac', sr=16000) - X_pad = pad(X, self.cut) - x_inp = Tensor(X_pad) - return x_inp, key - - -def get_parser(): - parser = argparse.ArgumentParser(description='RawNet2') - parser.add_argument('--batch_size', type=int, default=128, - help='batch size') - parser.add_argument('--device_id', type=int, default=1, - help='device id') - parser.add_argument('--om_path', type=str, default="rawnet2.om", - help='path to the om model') - parser.add_argument('--eval_output', type=str, default=None, - help='Path to save the evaluation result') - parser.add_argument('--database_path', type=str, default='/your/path/to/data/ASVspoof_database/', - help='Change this to user\'s full directory address of LA database.') - ''' - % database_path/ - % |- ASVspoof2021_LA_eval/flac - % |- ASVspoof2019_LA_train/flac - % |- ASVspoof2019_LA_dev/flac - ''' - parser.add_argument('--protocols_path', type=str, default='/your/path/to/protocols/ASVspoof_database/', - help='Change with path to user\'s LA database protocols directory address') - ''' - % protocols_path/ - % |- ASVspoof_LA_cm_protocols - % |- ASVspoof2021.LA.cm.eval.trl.txt - % |- ASVspoof2019.LA.cm.dev.trl.txt - % |- ASVspoof2019.LA.cm.train.trn.txt - ''' - return parser - - -if __name__ == "__main__": - ''' - Example: - python3.7 om_infer.py \ - --batch_size=1 \ - --om_path=rawnet2_modify.om \ - --eval_output='rawnet2_modify_om.txt' \ - --database_path='data/LA/' \ - --protocols_path='data/LA/' - ''' - parser = get_parser() - args = parser.parse_args() - - # Load dataset - protocal_dir = os.path.join(args.protocols_path + 'ASVspoof2019_LA_cm_protocols/ASVspoof2019.LA.cm.eval.trl.txt') - file_eval = genSpoof_list(protocal_dir) - database_dir = os.path.join(args.database_path + 'ASVspoof2019_LA_eval/') - eval_set = Dataset_ASVspoof2019_eval(list_IDs=file_eval, base_dir=database_dir) - eval_loader = DataLoader(eval_set, batch_size=args.batch_size, shuffle=False, drop_last=False) - - model = Net(device_id=args.device_id, model_path=args.om_path) - - # Evaluation for RawNet2 om model - with open(args.eval_output, 'w+') as fh: - for idx, (batch_x, utt_id) in tqdm(enumerate(eval_loader)): - fname_list = [] - score_list = [] - n, d = batch_x.shape - if n != args.batch_size: - m = (0, 0, 0, args.batch_size - n) - batch_x = F.pad(batch_x, m, 'constant', 0) - batch_x = batch_x.numpy().astype(np.float32) - batch_out = model(batch_x) - batch_out = torch.from_numpy(np.array(batch_out).astype(np.float32)) - batch_score = (batch_out[:, :, 1]).data.cpu().numpy().ravel() - - # add outputs - if len(batch_score) != len(utt_id): - batch_score = batch_score[:len(utt_id)] - fname_list.extend(utt_id) - score_list.extend(batch_score.tolist()) - - for f, cm in zip(fname_list, score_list): - fh.write('{} {}\n'.format(f, cm)) +# Copyright 2018 NVIDIA Corporation. 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. +# ============================================================================ +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import argparse +import time +import math +import numpy as np +from tqdm import tqdm +import librosa +import torch +import torch.nn.functional as F +from torch import Tensor +from torch.utils.data import Dataset +from torch.utils.data import DataLoader +from acl_net import Net + + +def genSpoof_list(dir_meta): + d_meta = {} + file_list = [] + with open(dir_meta, 'r') as f: + l_meta = f.readlines() + + for line in l_meta: + key = line.strip().split(' ')[1] + file_list.append(key) + return file_list + + +def pad(x, max_len=64600): + x_len = x.shape[0] + if x_len >= max_len: + return x[:max_len] + # need to pad + num_repeats = int(max_len / x_len) + 1 + padded_x = np.tile(x, (1, num_repeats))[:, :max_len][0] + return padded_x + + +class Dataset_ASVspoof2019_eval(Dataset): + def __init__(self, list_IDs, base_dir): + '''self.list_IDs : list of strings (each string: utt key)''' + + self.list_IDs = list_IDs + self.base_dir = base_dir + + def __len__(self): + return len(self.list_IDs) + + def __getitem__(self, index): + self.cut = 64600 # take ~4 sec audio (64600 samples) + key = self.list_IDs[index] + X, fs = librosa.load(self.base_dir + 'flac/' + key + '.flac', sr=16000) + X_pad = pad(X, self.cut) + x_inp = Tensor(X_pad) + return x_inp, key + + +def get_parser(): + parser = argparse.ArgumentParser(description='RawNet2') + parser.add_argument('--batch_size', type=int, default=128, + help='batch size') + parser.add_argument('--device_id', type=int, default=1, + help='device id') + parser.add_argument('--om_path', type=str, default="rawnet2.om", + help='path to the om model') + parser.add_argument('--eval_output', type=str, default=None, + help='Path to save the evaluation result') + parser.add_argument('--database_path', type=str, default='/your/path/to/data/ASVspoof_database/', + help='Change this to user\'s full directory address of LA database.') + ''' + % database_path/ + % |- ASVspoof2021_LA_eval/flac + % |- ASVspoof2019_LA_train/flac + % |- ASVspoof2019_LA_dev/flac + ''' + parser.add_argument('--protocols_path', type=str, default='/your/path/to/protocols/ASVspoof_database/', + help='Change with path to user\'s LA database protocols directory address') + ''' + % protocols_path/ + % |- ASVspoof_LA_cm_protocols + % |- ASVspoof2021.LA.cm.eval.trl.txt + % |- ASVspoof2019.LA.cm.dev.trl.txt + % |- ASVspoof2019.LA.cm.train.trn.txt + ''' + return parser + + +if __name__ == "__main__": + ''' + Example: + python3.7 om_infer.py \ + --batch_size=1 \ + --om_path=rawnet2_modify.om \ + --eval_output='rawnet2_modify_om.txt' \ + --database_path='data/LA/' \ + --protocols_path='data/LA/' + ''' + parser = get_parser() + args = parser.parse_args() + + # Load dataset + protocal_dir = os.path.join(args.protocols_path + 'ASVspoof2019_LA_cm_protocols/ASVspoof2019.LA.cm.eval.trl.txt') + file_eval = genSpoof_list(protocal_dir) + database_dir = os.path.join(args.database_path + 'ASVspoof2019_LA_eval/') + eval_set = Dataset_ASVspoof2019_eval(list_IDs=file_eval, base_dir=database_dir) + eval_loader = DataLoader(eval_set, batch_size=args.batch_size, shuffle=False, drop_last=False) + + model = Net(device_id=args.device_id, model_path=args.om_path) + + # Evaluation for RawNet2 om model + with open(args.eval_output, 'w+') as fh: + for idx, (batch_x, utt_id) in tqdm(enumerate(eval_loader)): + fname_list = [] + score_list = [] + n, d = batch_x.shape + if n != args.batch_size: + m = (0, 0, 0, args.batch_size - n) + batch_x = F.pad(batch_x, m, 'constant', 0) + batch_x = batch_x.numpy().astype(np.float32) + batch_out = model(batch_x) + batch_out = torch.from_numpy(np.array(batch_out).astype(np.float32)) + batch_score = (batch_out[:, :, 1]).data.cpu().numpy().ravel() + + # add outputs + if len(batch_score) != len(utt_id): + batch_score = batch_score[:len(utt_id)] + fname_list.extend(utt_id) + score_list.extend(batch_score.tolist()) + + for f, cm in zip(fname_list, score_list): + fh.write('{} {}\n'.format(f, cm)) print('Scores saved to {}'.format(args.eval_output)) \ No newline at end of file diff --git a/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/pth2onnx.py b/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/pth2onnx.py index df6b221b58..297f2dcf12 100644 --- a/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/pth2onnx.py +++ b/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch/pth2onnx.py @@ -1,69 +1,69 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import os -import argparse -import yaml -import torch -import onnx -import torch.onnx -from model import RawNet - - -def convert(pth_model, onnx_model, batch_size): - dir_yaml = os.path.splitext('model_config_RawNet')[0] + '.yaml' - with open(dir_yaml, 'r') as f_yaml: - parser1 = yaml.load(f_yaml) - model = RawNet(parser1['model'], 'cpu') - checkpoint = torch.load(pth_model, map_location='cpu') - model.load_state_dict(checkpoint) - model.eval() - - input_names = ["input"] - output_names = ["output"] - dummy_input = torch.randn(int(batch_size), 64600) - print('\nStarting ONNX export with onnx %s...' % onnx.__version__) - torch.onnx.export(model, dummy_input, onnx_model, - input_names=input_names, output_names=output_names, - opset_version=11, - dynamic_axes=None, - export_params=True, - verbose=True, - do_constant_folding=True) - - -def get_parser(): - parser = argparse.ArgumentParser(description='RawNet2') - parser.add_argument('--pth_model', default=None, type=str, - help='Path to pytorch model') - parser.add_argument('--onnx_model', default=None, type=str, - help='Path to onnx model') - parser.add_argument('--batch_size', default=1, type=int, - help='Data batch size') - return parser - - -if __name__ == "__main__": - ''' - Example: - python3.7 pth2onnx.py \ - --pth_model=pre_trained_DF_RawNet2.pth \ - --onnx_model=rawnet2_ori.onnx \ - --batch_size=1 - ''' - parser = get_parser() - args = parser.parse_args() - convert(args.pth_model, args.onnx_model, args.batch_size) - print('pytorch to onnx successfully!') +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import os +import argparse +import yaml +import torch +import onnx +import torch.onnx +from model import RawNet + + +def convert(pth_model, onnx_model, batch_size): + dir_yaml = os.path.splitext('model_config_RawNet')[0] + '.yaml' + with open(dir_yaml, 'r') as f_yaml: + parser1 = yaml.load(f_yaml) + model = RawNet(parser1['model'], 'cpu') + checkpoint = torch.load(pth_model, map_location='cpu') + model.load_state_dict(checkpoint) + model.eval() + + input_names = ["input"] + output_names = ["output"] + dummy_input = torch.randn(int(batch_size), 64600) + print('\nStarting ONNX export with onnx %s...' % onnx.__version__) + torch.onnx.export(model, dummy_input, onnx_model, + input_names=input_names, output_names=output_names, + opset_version=11, + dynamic_axes=None, + export_params=True, + verbose=True, + do_constant_folding=True) + + +def get_parser(): + parser = argparse.ArgumentParser(description='RawNet2') + parser.add_argument('--pth_model', default=None, type=str, + help='Path to pytorch model') + parser.add_argument('--onnx_model', default=None, type=str, + help='Path to onnx model') + parser.add_argument('--batch_size', default=1, type=int, + help='Data batch size') + return parser + + +if __name__ == "__main__": + ''' + Example: + python3.7 pth2onnx.py \ + --pth_model=pre_trained_DF_RawNet2.pth \ + --onnx_model=rawnet2_ori.onnx \ + --batch_size=1 + ''' + parser = get_parser() + args = parser.parse_args() + convert(args.pth_model, args.onnx_model, args.batch_size) + print('pytorch to onnx successfully!') diff --git a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/LICENSE b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/LICENSE index 4ba4fdcab3..a0e0310359 100644 --- a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/LICENSE +++ b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/LICENSE @@ -1,29 +1,29 @@ -BSD 3-Clause License - -Copyright (c) 2017, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +BSD 3-Clause License + +Copyright (c) 2017, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/ReadMe.md b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/ReadMe.md index 4ea7fca8b3..d961290140 100644 --- a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/ReadMe.md +++ b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/ReadMe.md @@ -1,59 +1,59 @@ -# TDNN模型pytorch离线推理指导 - -## 1 环境准备 - -1.获取,修改与安装开源模型代码 - -```shell -git clone https://github.com/speechbrain/speechbrain.git -cd speechbrain -git checkout develop -git reset --hard 51a2becdcf3a337578a9307a0b2fc3906bf20391 -export PYTHONPATH=`pwd`:$PYTHONPATH -cd .. -git clone https://gitee.com/Ronnie_zheng/MagicONNX.git -cd MagicONNX && git checkout 8d62ae9dde478f35bece4b3d04eef573448411c9 -pip install . -``` -将源码包中文件放入speechbrain/templates/speaker_id中 -```shell -cd speechbrain -git apply --reject --whitespace=fix templates/speaker_id/modify.patch -``` - -2.获取权重文件 - -https://www.hiascend.com/zh/software/modelzoo/detail/1/f4f4103245624c1a8637f8a5eadd950c -将模型权重文件夹best_model放入speechbrain/templates/speaker_id下,将hyperparams.yaml文件放入best_model中 - -3.获取数据集 - -预处理阶段自动下载 -```shell -python3 tdnn_preprocess.py -``` - -## 2 模型转换 -```shell -# 生成tdnn_bs64.onnx -python3 tdnn_pth2onnx.py 64 -# 优化onnx模型 -python3 -m onnxsim tdnn_bs64.onnx tdnn_bs64s.onnx -python3 modify_onnx.py tdnn_bs64s.onnx -# 生成om模型 -bash atc.sh tdnn_bs64s.onnx -``` - -## 3 离线推理 - -```shell -bash om_infer.sh 64 -python3 tdnn_postprocess.py -``` -**评测结果:** - -由于TensorRT不支持原模型,故只能对比修改后的模型性能。 -| 模型 | pth精度 | 710离线推理精度 | 基准性能 | 710性能 | -| :------: | :------: | :------: | :------: | :------: | -| TDNN bs64 | 99.93% | 99.93% | - | 2467fps | +# TDNN模型pytorch离线推理指导 + +## 1 环境准备 + +1.获取,修改与安装开源模型代码 + +```shell +git clone https://github.com/speechbrain/speechbrain.git +cd speechbrain +git checkout develop +git reset --hard 51a2becdcf3a337578a9307a0b2fc3906bf20391 +export PYTHONPATH=`pwd`:$PYTHONPATH +cd .. +git clone https://gitee.com/Ronnie_zheng/MagicONNX.git +cd MagicONNX && git checkout 8d62ae9dde478f35bece4b3d04eef573448411c9 +pip install . +``` +将源码包中文件放入speechbrain/templates/speaker_id中 +```shell +cd speechbrain +git apply --reject --whitespace=fix templates/speaker_id/modify.patch +``` + +2.获取权重文件 + +https://www.hiascend.com/zh/software/modelzoo/detail/1/f4f4103245624c1a8637f8a5eadd950c +将模型权重文件夹best_model放入speechbrain/templates/speaker_id下,将hyperparams.yaml文件放入best_model中 + +3.获取数据集 + +预处理阶段自动下载 +```shell +python3 tdnn_preprocess.py +``` + +## 2 模型转换 +```shell +# 生成tdnn_bs64.onnx +python3 tdnn_pth2onnx.py 64 +# 优化onnx模型 +python3 -m onnxsim tdnn_bs64.onnx tdnn_bs64s.onnx +python3 modify_onnx.py tdnn_bs64s.onnx +# 生成om模型 +bash atc.sh tdnn_bs64s.onnx +``` + +## 3 离线推理 + +```shell +bash om_infer.sh 64 +python3 tdnn_postprocess.py +``` +**评测结果:** + +由于TensorRT不支持原模型,故只能对比修改后的模型性能。 +| 模型 | pth精度 | 710离线推理精度 | 基准性能 | 710性能 | +| :------: | :------: | :------: | :------: | :------: | +| TDNN bs64 | 99.93% | 99.93% | - | 2467fps | | TDNN修改 bs64 | - | - | 2345.179 fps | 3815.886fps | \ No newline at end of file diff --git a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/mo.py b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/mo.py index cad5851dcb..0b4dee7f3b 100644 --- a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/mo.py +++ b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/mo.py @@ -1,32 +1,32 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys - -from magiconnx import OnnxGraph - -bs = sys.argv[1] -model_name = 'tdnn_bs%s'%bs -graph = OnnxGraph(model_name+'.onnx') -ph = graph.add_placeholder('random','float32',[64,1500]) - -rm = graph.get_nodes("ReduceMin")[0] -rm.inputs = ['random'] -sub = graph.get_nodes("Sub")[-1] -sub.inputs = ['random', rm.outputs[0]] - -rn = graph.get_nodes("RandomNormalLike")[0] -graph.del_node(rn.name, auto_connection=False) - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys + +from magiconnx import OnnxGraph + +bs = sys.argv[1] +model_name = 'tdnn_bs%s'%bs +graph = OnnxGraph(model_name+'.onnx') +ph = graph.add_placeholder('random','float32',[64,1500]) + +rm = graph.get_nodes("ReduceMin")[0] +rm.inputs = ['random'] +sub = graph.get_nodes("Sub")[-1] +sub.inputs = ['random', rm.outputs[0]] + +rn = graph.get_nodes("RandomNormalLike")[0] +graph.del_node(rn.name, auto_connection=False) + graph.save('%s_mod.onnx'%model_name) \ No newline at end of file diff --git a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/modelzoo_level.txt b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/modelzoo_level.txt +++ b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/modify.patch b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/modify.patch index d246c60425..ce78514dbd 100644 --- a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/modify.patch +++ b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/modify.patch @@ -260,11 +260,11 @@ index c22add8..7a777df 100644 --- a/templates/speaker_id/mini_librispeech_prepare.py +++ b/templates/speaker_id/mini_librispeech_prepare.py @@ -171,7 +171,7 @@ def split_sets(wav_list, split_ratio): - dictionary containing train, valid, and test splits. - """ - # Random shuffle of the list -- random.shuffle(wav_list) -+ # random.shuffle(wav_list) - tot_split = sum(split_ratio) - tot_snts = len(wav_list) - data_split = {} + dictionary containing train, valid, and test splits. + """ + # Random shuffle of the list +- random.shuffle(wav_list) ++ # random.shuffle(wav_list) + tot_split = sum(split_ratio) + tot_snts = len(wav_list) + data_split = {} diff --git a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/modify_onnx.py b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/modify_onnx.py index ab8273817c..3939324a1d 100644 --- a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/modify_onnx.py +++ b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/modify_onnx.py @@ -1,51 +1,51 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys - -import numpy as np -import onnx - -from magiconnx import OnnxGraph - -model_name = sys.argv[1] -graph = OnnxGraph(model_name) - -axes = onnx.helper.make_attribute("axes", [0,1]) -rd_min = graph.get_nodes("ReduceMin")[0] -rd_min._node.attribute.append(axes) -rd_max = graph.get_nodes("ReduceMax")[0] -rd_max._node.attribute.append(axes) - -us = graph.add_node('Unsq_1', 'Unsqueeze', {'axes': [2]}) -graph.insert_node(graph.get_nodes("Conv")[0].name, us, mode='before') -sq = graph.add_node('Sq_291', 'Squeeze', {'axes': [2]}) -graph.insert_node(graph.get_nodes('BatchNormalization')[4].name, sq, mode='after') - -convs = graph.get_nodes("Conv") -for conv in convs: - print(conv.name) - dil = conv['dilations'][0] - ks = conv['kernel_shape'][0] - pds = conv['pads'][0] - stri = conv['strides'][0] - conv['dilations'] = [1, dil] - conv['kernel_shape'] = [1, ks] - conv['pads'] = [0, pds, 0, pds] - conv['strides'] = [1, stri] - conv_w = graph[conv.inputs[1]].value - conv_w = np.expand_dims(conv_w, axis=-2) - graph[conv.inputs[1]].value = conv_w - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys + +import numpy as np +import onnx + +from magiconnx import OnnxGraph + +model_name = sys.argv[1] +graph = OnnxGraph(model_name) + +axes = onnx.helper.make_attribute("axes", [0,1]) +rd_min = graph.get_nodes("ReduceMin")[0] +rd_min._node.attribute.append(axes) +rd_max = graph.get_nodes("ReduceMax")[0] +rd_max._node.attribute.append(axes) + +us = graph.add_node('Unsq_1', 'Unsqueeze', {'axes': [2]}) +graph.insert_node(graph.get_nodes("Conv")[0].name, us, mode='before') +sq = graph.add_node('Sq_291', 'Squeeze', {'axes': [2]}) +graph.insert_node(graph.get_nodes('BatchNormalization')[4].name, sq, mode='after') + +convs = graph.get_nodes("Conv") +for conv in convs: + print(conv.name) + dil = conv['dilations'][0] + ks = conv['kernel_shape'][0] + pds = conv['pads'][0] + stri = conv['strides'][0] + conv['dilations'] = [1, dil] + conv['kernel_shape'] = [1, ks] + conv['pads'] = [0, pds, 0, pds] + conv['strides'] = [1, stri] + conv_w = graph[conv.inputs[1]].value + conv_w = np.expand_dims(conv_w, axis=-2) + graph[conv.inputs[1]].value = conv_w + graph.save(model_name) \ No newline at end of file diff --git a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/requirements.txt b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/requirements.txt index 561b93c4e7..aafb425ee5 100644 --- a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/requirements.txt +++ b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/requirements.txt @@ -1,8 +1,8 @@ -onnx==1.10.2 -torch==1.10.0 -torchaudio==0.10.2 -tqdm==4.63.0 -HyperPyYAML==1.0.0 -huggingface-hub==0.4.0 - - +onnx==1.10.2 +torch==1.10.0 +torchaudio==0.10.2 +tqdm==4.63.0 +HyperPyYAML==1.0.0 +huggingface-hub==0.4.0 + + diff --git a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/tdnn_postprocess.py b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/tdnn_postprocess.py index c046198734..cb0b04f187 100644 --- a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/tdnn_postprocess.py +++ b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/tdnn_postprocess.py @@ -1,53 +1,53 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import re -import argparse -import numpy as np -label = {0:'163', 1:'7367', 2:'332', 3:'1970', 4:'4640', 5:'8629', 6:'6848', 7:'1088', 8:'460', 9:'6272', 10:'7312', 11:'2136', 12:'1867', 13:'669', 14:'3526', 15:'3664', 16:'3242', 17:'19', 18:'32', 19:'5789', 20:'118', 21:'226', 22:'7859', 23:'3947', 24:'1898', 25:'2416', 26:'1737', 27:'4680'} - -if __name__ == '__main__': - ''' - 参数说明: - --data_info: 数据集信息 - --result_dir: 二进制推理结果目录 - ''' - - # arg parser - parser = argparse.ArgumentParser() - parser.add_argument('--data_info', default='mini_librispeech_test.info') - parser.add_argument('--result_dir', default='result') - - opt = parser.parse_args() - error = 0 - total = 0 - - with open('mini_librispeech_test.info', 'r') as f: - for line in f.readlines(): - # line format example - # 0 mini_librispeech_test_bin/4680-16042-0024.bin (1,1600,23) - split = line.split(' ') - index = split[0] - input_file = split[1] - target = re.search('/(\d*)-', input_file).group()[1:-1] - output_file = opt.result_dir + '/' + index + '.0.bin' - output = np.fromfile(output_file, np.float32) - res = np.argmax(output) - print('Predicted:', label[res], 'Target:', target) - total += 1 - if label[res] != target: - error += 1 - accuracy = (total - error) / total * 100 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import re +import argparse +import numpy as np +label = {0:'163', 1:'7367', 2:'332', 3:'1970', 4:'4640', 5:'8629', 6:'6848', 7:'1088', 8:'460', 9:'6272', 10:'7312', 11:'2136', 12:'1867', 13:'669', 14:'3526', 15:'3664', 16:'3242', 17:'19', 18:'32', 19:'5789', 20:'118', 21:'226', 22:'7859', 23:'3947', 24:'1898', 25:'2416', 26:'1737', 27:'4680'} + +if __name__ == '__main__': + ''' + 参数说明: + --data_info: 数据集信息 + --result_dir: 二进制推理结果目录 + ''' + + # arg parser + parser = argparse.ArgumentParser() + parser.add_argument('--data_info', default='mini_librispeech_test.info') + parser.add_argument('--result_dir', default='result') + + opt = parser.parse_args() + error = 0 + total = 0 + + with open('mini_librispeech_test.info', 'r') as f: + for line in f.readlines(): + # line format example + # 0 mini_librispeech_test_bin/4680-16042-0024.bin (1,1600,23) + split = line.split(' ') + index = split[0] + input_file = split[1] + target = re.search('/(\d*)-', input_file).group()[1:-1] + output_file = opt.result_dir + '/' + index + '.0.bin' + output = np.fromfile(output_file, np.float32) + res = np.argmax(output) + print('Predicted:', label[res], 'Target:', target) + total += 1 + if label[res] != target: + error += 1 + accuracy = (total - error) / total * 100 print('\nClassification Accuracy: {:.2f}%\n'.format(accuracy)) \ No newline at end of file diff --git a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/tdnn_preprocess.py b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/tdnn_preprocess.py index dcaa76a0e8..855ec5fa53 100644 --- a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/tdnn_preprocess.py +++ b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/tdnn_preprocess.py @@ -1,52 +1,52 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import json -import torchaudio -import torch.nn.functional as F -from speechbrain.pretrained import EncoderClassifier -from mini_librispeech_prepare import prepare_mini_librispeech - -prepare_mini_librispeech(data_folder='data', save_json_train='train.json', save_json_valid='valid.json', - save_json_test='test.json', split_ratio=[0, 0, 100]) - -if not os.path.exists('mini_librispeech_test_bin'): - os.makedirs('mini_librispeech_test_bin') - -file = open('mini_librispeech_test.info', 'w') -classifier = EncoderClassifier.from_hparams(source='best_model', savedir='best_model') - -with open('test.json', 'r') as f: - data_info = json.load(f) - i = 0 - - for key, value in data_info.items(): - wav_file = 'data' + value['wav'][11:] # prefix length 11 - signal, fs = torchaudio.load(wav_file) - feats = classifier.extract_feats(signal) - # pad signal - pad = (feats.shape[1] // 100 + 1) * 100 - feats.shape[1] - feats = F.pad(feats, (0,0,0,pad,0,0), value=0) - - # dump bin file - output = 'mini_librispeech_test_bin/' + value['wav'].split('/')[-1][:-4] + 'bin' - feats.numpy().tofile(output) - # write shape info - file.write(str(i) + ' ' + output + ' (' + str(feats.shape[0]) + ',' + str(feats.shape[1]) + ',' + str(feats.shape[2]) + ')') - file.write('\n') - i += 1 - - print('data preprocess done') +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import json +import torchaudio +import torch.nn.functional as F +from speechbrain.pretrained import EncoderClassifier +from mini_librispeech_prepare import prepare_mini_librispeech + +prepare_mini_librispeech(data_folder='data', save_json_train='train.json', save_json_valid='valid.json', + save_json_test='test.json', split_ratio=[0, 0, 100]) + +if not os.path.exists('mini_librispeech_test_bin'): + os.makedirs('mini_librispeech_test_bin') + +file = open('mini_librispeech_test.info', 'w') +classifier = EncoderClassifier.from_hparams(source='best_model', savedir='best_model') + +with open('test.json', 'r') as f: + data_info = json.load(f) + i = 0 + + for key, value in data_info.items(): + wav_file = 'data' + value['wav'][11:] # prefix length 11 + signal, fs = torchaudio.load(wav_file) + feats = classifier.extract_feats(signal) + # pad signal + pad = (feats.shape[1] // 100 + 1) * 100 - feats.shape[1] + feats = F.pad(feats, (0,0,0,pad,0,0), value=0) + + # dump bin file + output = 'mini_librispeech_test_bin/' + value['wav'].split('/')[-1][:-4] + 'bin' + feats.numpy().tofile(output) + # write shape info + file.write(str(i) + ' ' + output + ' (' + str(feats.shape[0]) + ',' + str(feats.shape[1]) + ',' + str(feats.shape[2]) + ')') + file.write('\n') + i += 1 + + print('data preprocess done') file.close() \ No newline at end of file diff --git a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/tdnn_pth2onnx.py b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/tdnn_pth2onnx.py index 2e830e2802..b93409b453 100644 --- a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/tdnn_pth2onnx.py +++ b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/tdnn_pth2onnx.py @@ -1,47 +1,47 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys - -import torch -import torchaudio -from speechbrain.pretrained import EncoderClassifier - -classifier = EncoderClassifier.from_hparams(source='best_model', savedir='best_model') - -# Download Thai language sample from Omniglot -class Xvector(torch.nn.Module): - def __init__(self, model): - super().__init__() - self.classifier = model - - def forward(self, feats): - res = self.classifier.feats_classify(feats) - return res - -model = Xvector(classifier) -batch_size=int(sys.argv[1]) -feats = torch.randn([batch_size, 1800, 23]) - -torch.onnx.export( - model, - feats, - 'tdnn_bs%d.onnx'%(batch_size), - input_names=['feats'], - output_names=['output'], - export_params=True, - do_constant_folding=True, - verbose=True, - opset_version=11 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys + +import torch +import torchaudio +from speechbrain.pretrained import EncoderClassifier + +classifier = EncoderClassifier.from_hparams(source='best_model', savedir='best_model') + +# Download Thai language sample from Omniglot +class Xvector(torch.nn.Module): + def __init__(self, model): + super().__init__() + self.classifier = model + + def forward(self, feats): + res = self.classifier.feats_classify(feats) + return res + +model = Xvector(classifier) +batch_size=int(sys.argv[1]) +feats = torch.randn([batch_size, 1800, 23]) + +torch.onnx.export( + model, + feats, + 'tdnn_bs%d.onnx'%(batch_size), + input_names=['feats'], + output_names=['output'], + export_params=True, + do_constant_folding=True, + verbose=True, + opset_version=11 ) \ No newline at end of file diff --git a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/tdnn_pyacl_infer.py b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/tdnn_pyacl_infer.py index 87967a5d26..6b7a783b2e 100644 --- a/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/tdnn_pyacl_infer.py +++ b/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch/tdnn_pyacl_infer.py @@ -1,201 +1,201 @@ -# Copyright 2018 NVIDIA Corporation. 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. -# ============================================================================ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 acl -from acl_net import AclModel - -import os -import shutil -import argparse -import numpy as np -from tqdm import tqdm - -DTYPE = { - 'float32': np.float32, - 'float64': np.float64, - 'int32': np.int32, - 'int64': np.int64 -} - -if __name__ == '__main__': - ''' - 参数说明: - --model_path:模型路径 - --device_id:npu id - --cpu_run:MeasureTime类的cpu_run参数,True or False - --sync_infer:推理方式: - True:同步推理 - False:异步推理 - --workspace:类似TensorRT `workspace`参数,计算平均推理时间时排除前n次推理 - --input_info_file_path:类似benchmark的bin_info文件 - --input_dtypes:模型输入的类型,用逗号分割(`DTYPE`变量) - e.g. 模型只有一个输入:--input_dtypes=float32 - e.g. 模型有多个输入:--input_dtypes=float32,float32,float32(需要和bin_info文件多输入排列一致) - --infer_res_save_path:推理结果保存目录 - --res_save_type:推理结果保存类型,bin或npy - - info文件说明: - 因为支持动态shape,相比于benchmark的info文件,需要多加一列shape信息,e.g. - ``` - 0 ./bert_bin/input_ids_0.bin (1,512) - 0 ./bert_bin/segment_ids_0.bin (1,512) - 0 ./bert_bin/input_mask_0.bin (1,512) - 1 ./bert_bin/input_ids_1.bin (1,512) - 1 ./bert_bin/segment_ids_1.bin (1,512) - 1 ./bert_bin/input_mask_1.bin (1,512) - ``` - - Using Example: - python3.7 pyacl_infer.py \ - --model_path=./bert_base_batch_1_sim_auto.om \ - --device_id=0 \ - --cpu_run=True \ - --sync_infer=True \ - --workspace=10 \ - --input_info_file_path=./input.info \ - --input_dtypes=int64,int64,int64 \ - --infer_res_save_path=./infer_res \ - --res_save_type=bin - ''' - - # 参数解析 - parser = argparse.ArgumentParser() - parser.add_argument('--model_path', required=True) - parser.add_argument('--batch_size', required=True) - parser.add_argument('--device_id', required=True, type=int) - parser.add_argument('--cpu_run', required=True, choices=['True', 'False']) - parser.add_argument('--sync_infer', required=True, choices=['True', 'False']) - parser.add_argument('--workspace', required=True, type=int) - parser.add_argument('--input_info_file_path', required=True) - parser.add_argument('--input_dtypes', required=True) - parser.add_argument('--infer_res_save_path', required=True) - parser.add_argument('--res_save_type', required=True, choices=['bin', 'npy']) - opt = parser.parse_args() - - # 创建模型 - measurements = {} - om_model = AclModel(device_id=opt.device_id, - model_path=opt.model_path, - sync_infer=eval(opt.sync_infer), - measurements=measurements, - key='per_infer_time_ns', - cpu_run=eval(opt.cpu_run)) - - # 创建目录 - if os.path.exists(opt.infer_res_save_path): - shutil.rmtree(opt.infer_res_save_path) - os.makedirs(opt.infer_res_save_path) - - # 读取info_file - inputs_info = {} - with open(opt.input_info_file_path, 'rt', encoding='utf-8') as f_info: - line = f_info.readline() - while line: - line = line.rstrip('\n') - contents = line.split() - info = {'path': contents[1], 'shape': eval(contents[2])} - inputs_info.setdefault(contents[0], []).append(info) - line = f_info.readline() - - # 解析输入类型 - input_dtypes = opt.input_dtypes.split(',') - input_dtypes = list(map(lambda x: DTYPE[x], input_dtypes)) - - # 读取文件推理 - total_infer_time = 0 - total_infer_time_workspace = 0 - total_infer_num = 0 - dataset = {} - dims_infos = {} - bs = int(opt.batch_size) - for key, values in inputs_info.items(): - # 构造输入 - inputs = [] - dims = [] - for idx, value in enumerate(values): - x = np.fromfile(value['path'], dtype=input_dtypes[idx]).reshape(value['shape']) - inputs.append((key,x)) - dims.extend((bs, value['shape'][1], value['shape'][2])) - dims_info = {'dimCount': len(dims), 'name': '', 'dims': dims} - - # (1, 1500, 23) {'dimCount': 3, 'name': '', 'dims': [1, 1500, 23]} - length = inputs[0][1].shape[1] - dataset[length] = dataset.get(length,[]) + inputs - dims_infos[length] = dims_infos.get(length,dims_info) - - total_inputs = [] - total_keys = [] - for k in sorted(dataset.keys()): - total_len = len(dataset[k]) - batch_input = [] - batch_key = [] - for i, (key, ipt) in enumerate(dataset[k]): - batch_input.append(ipt) - batch_key.append(key) - if (i+1) % bs == 0: - total_inputs.append(batch_input) - total_keys.append(batch_key) - batch_input = [] - batch_key = [] - if batch_input != []: - total_inputs.append(batch_input) - total_keys.append(batch_key) - - for i, b_ipt in tqdm(enumerate(total_inputs)): - batch_input = np.squeeze(np.array(b_ipt), axis=1) - if batch_input.shape[0] < bs: - batch_input = np.pad(batch_input, [(0, bs-batch_input.shape[0]), (0, 0), (0, 0)], mode='constant') - - # 推理得到输出 - # (bs, 28) - output = om_model([batch_input], dims_infos[batch_input.shape[1]]) - - total_infer_num += 1 - - # 保存文件 - for j, key in enumerate(total_keys[i]): - if opt.res_save_type == 'bin': - output[0][j].tofile(os.path.join(opt.infer_res_save_path, key + '.' + str(0) + '.bin')) - else: - np.save(os.path.join(opt.infer_res_save_path, key + '.' + str(0) + '.npy'), output[0][j]) - - # 计算时间 - total_infer_time += measurements['per_infer_time_ns'] - if total_infer_num > opt.workspace: - total_infer_time_workspace += measurements['per_infer_time_ns'] - - # 推理时间 - print('[INFO] Infer time:') - msg = 'total infer num: ' + str(total_infer_num) + '\n' + \ - 'total pure infer time(ms): ' + str(total_infer_time / 1000 / 1000) + '\n' + \ - 'average pure infer time(ms): ' + str(total_infer_time / total_infer_num / 1000 / 1000) + '\n' + \ - 'average pure infer time after workspace(ms): ' + str(abs( - total_infer_time_workspace / (total_infer_num - opt.workspace) / 1000 / 1000)) + '\n' - print(msg) - with open(os.path.join(opt.infer_res_save_path, 'infer_time.txt'), 'wt', encoding='utf-8') as f_infer_time: +# Copyright 2018 NVIDIA Corporation. 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. +# ============================================================================ +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 acl +from acl_net import AclModel + +import os +import shutil +import argparse +import numpy as np +from tqdm import tqdm + +DTYPE = { + 'float32': np.float32, + 'float64': np.float64, + 'int32': np.int32, + 'int64': np.int64 +} + +if __name__ == '__main__': + ''' + 参数说明: + --model_path:模型路径 + --device_id:npu id + --cpu_run:MeasureTime类的cpu_run参数,True or False + --sync_infer:推理方式: + True:同步推理 + False:异步推理 + --workspace:类似TensorRT `workspace`参数,计算平均推理时间时排除前n次推理 + --input_info_file_path:类似benchmark的bin_info文件 + --input_dtypes:模型输入的类型,用逗号分割(`DTYPE`变量) + e.g. 模型只有一个输入:--input_dtypes=float32 + e.g. 模型有多个输入:--input_dtypes=float32,float32,float32(需要和bin_info文件多输入排列一致) + --infer_res_save_path:推理结果保存目录 + --res_save_type:推理结果保存类型,bin或npy + + info文件说明: + 因为支持动态shape,相比于benchmark的info文件,需要多加一列shape信息,e.g. + ``` + 0 ./bert_bin/input_ids_0.bin (1,512) + 0 ./bert_bin/segment_ids_0.bin (1,512) + 0 ./bert_bin/input_mask_0.bin (1,512) + 1 ./bert_bin/input_ids_1.bin (1,512) + 1 ./bert_bin/segment_ids_1.bin (1,512) + 1 ./bert_bin/input_mask_1.bin (1,512) + ``` + + Using Example: + python3.7 pyacl_infer.py \ + --model_path=./bert_base_batch_1_sim_auto.om \ + --device_id=0 \ + --cpu_run=True \ + --sync_infer=True \ + --workspace=10 \ + --input_info_file_path=./input.info \ + --input_dtypes=int64,int64,int64 \ + --infer_res_save_path=./infer_res \ + --res_save_type=bin + ''' + + # 参数解析 + parser = argparse.ArgumentParser() + parser.add_argument('--model_path', required=True) + parser.add_argument('--batch_size', required=True) + parser.add_argument('--device_id', required=True, type=int) + parser.add_argument('--cpu_run', required=True, choices=['True', 'False']) + parser.add_argument('--sync_infer', required=True, choices=['True', 'False']) + parser.add_argument('--workspace', required=True, type=int) + parser.add_argument('--input_info_file_path', required=True) + parser.add_argument('--input_dtypes', required=True) + parser.add_argument('--infer_res_save_path', required=True) + parser.add_argument('--res_save_type', required=True, choices=['bin', 'npy']) + opt = parser.parse_args() + + # 创建模型 + measurements = {} + om_model = AclModel(device_id=opt.device_id, + model_path=opt.model_path, + sync_infer=eval(opt.sync_infer), + measurements=measurements, + key='per_infer_time_ns', + cpu_run=eval(opt.cpu_run)) + + # 创建目录 + if os.path.exists(opt.infer_res_save_path): + shutil.rmtree(opt.infer_res_save_path) + os.makedirs(opt.infer_res_save_path) + + # 读取info_file + inputs_info = {} + with open(opt.input_info_file_path, 'rt', encoding='utf-8') as f_info: + line = f_info.readline() + while line: + line = line.rstrip('\n') + contents = line.split() + info = {'path': contents[1], 'shape': eval(contents[2])} + inputs_info.setdefault(contents[0], []).append(info) + line = f_info.readline() + + # 解析输入类型 + input_dtypes = opt.input_dtypes.split(',') + input_dtypes = list(map(lambda x: DTYPE[x], input_dtypes)) + + # 读取文件推理 + total_infer_time = 0 + total_infer_time_workspace = 0 + total_infer_num = 0 + dataset = {} + dims_infos = {} + bs = int(opt.batch_size) + for key, values in inputs_info.items(): + # 构造输入 + inputs = [] + dims = [] + for idx, value in enumerate(values): + x = np.fromfile(value['path'], dtype=input_dtypes[idx]).reshape(value['shape']) + inputs.append((key,x)) + dims.extend((bs, value['shape'][1], value['shape'][2])) + dims_info = {'dimCount': len(dims), 'name': '', 'dims': dims} + + # (1, 1500, 23) {'dimCount': 3, 'name': '', 'dims': [1, 1500, 23]} + length = inputs[0][1].shape[1] + dataset[length] = dataset.get(length,[]) + inputs + dims_infos[length] = dims_infos.get(length,dims_info) + + total_inputs = [] + total_keys = [] + for k in sorted(dataset.keys()): + total_len = len(dataset[k]) + batch_input = [] + batch_key = [] + for i, (key, ipt) in enumerate(dataset[k]): + batch_input.append(ipt) + batch_key.append(key) + if (i+1) % bs == 0: + total_inputs.append(batch_input) + total_keys.append(batch_key) + batch_input = [] + batch_key = [] + if batch_input != []: + total_inputs.append(batch_input) + total_keys.append(batch_key) + + for i, b_ipt in tqdm(enumerate(total_inputs)): + batch_input = np.squeeze(np.array(b_ipt), axis=1) + if batch_input.shape[0] < bs: + batch_input = np.pad(batch_input, [(0, bs-batch_input.shape[0]), (0, 0), (0, 0)], mode='constant') + + # 推理得到输出 + # (bs, 28) + output = om_model([batch_input], dims_infos[batch_input.shape[1]]) + + total_infer_num += 1 + + # 保存文件 + for j, key in enumerate(total_keys[i]): + if opt.res_save_type == 'bin': + output[0][j].tofile(os.path.join(opt.infer_res_save_path, key + '.' + str(0) + '.bin')) + else: + np.save(os.path.join(opt.infer_res_save_path, key + '.' + str(0) + '.npy'), output[0][j]) + + # 计算时间 + total_infer_time += measurements['per_infer_time_ns'] + if total_infer_num > opt.workspace: + total_infer_time_workspace += measurements['per_infer_time_ns'] + + # 推理时间 + print('[INFO] Infer time:') + msg = 'total infer num: ' + str(total_infer_num) + '\n' + \ + 'total pure infer time(ms): ' + str(total_infer_time / 1000 / 1000) + '\n' + \ + 'average pure infer time(ms): ' + str(total_infer_time / total_infer_num / 1000 / 1000) + '\n' + \ + 'average pure infer time after workspace(ms): ' + str(abs( + total_infer_time_workspace / (total_infer_num - opt.workspace) / 1000 / 1000)) + '\n' + print(msg) + with open(os.path.join(opt.infer_res_save_path, 'infer_time.txt'), 'wt', encoding='utf-8') as f_infer_time: f_infer_time.write(msg) \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/ReadMe.md b/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/ReadMe.md index e42fd69be2..cae1ac9e4b 100644 --- a/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/ReadMe.md +++ b/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/ReadMe.md @@ -1,37 +1,37 @@ -文件作用说明: - -- Pth转换om脚本,pth转换om脚本 -- ATC转换脚本atc_crnn.sh -- benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer -- ONNX模型lstm算子修改脚本lstm_revise.py -- 测试数据集生成脚本parse_testdata.py -- 推理后处理脚本postpossess_CRNN_pytorch.py -- ReadMe.md -- - -推理端到端步骤: - -(1) 使用脚本pth2onnx.py将pth文件导出为onnx文件 - - - -(2)运行atc_crnn.sh脚本转换om模型 - -本demo已提供调优完成的om模型 - - - -(3)用parse_testdata.py脚本处理数据集 - - - -(4)./benchmark.x86_64 -model_type=vision -batch_size=16 -device_id=0 -input_text_path=./crnn.info -input_width=100 -input_height=32 -om_path=./crnn_sim.om -useDvpp=False - -运行benchmark推理,结果保存在 ./result 目录下 - - - -(5)python3.7 postpossess_CRNN_pytorch.py - -验证推理结果 - +文件作用说明: + +- Pth转换om脚本,pth转换om脚本 +- ATC转换脚本atc_crnn.sh +- benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer +- ONNX模型lstm算子修改脚本lstm_revise.py +- 测试数据集生成脚本parse_testdata.py +- 推理后处理脚本postpossess_CRNN_pytorch.py +- ReadMe.md +- + +推理端到端步骤: + +(1) 使用脚本pth2onnx.py将pth文件导出为onnx文件 + + + +(2)运行atc_crnn.sh脚本转换om模型 + +本demo已提供调优完成的om模型 + + + +(3)用parse_testdata.py脚本处理数据集 + + + +(4)./benchmark.x86_64 -model_type=vision -batch_size=16 -device_id=0 -input_text_path=./crnn.info -input_width=100 -input_height=32 -om_path=./crnn_sim.om -useDvpp=False + +运行benchmark推理,结果保存在 ./result 目录下 + + + +(5)python3.7 postpossess_CRNN_pytorch.py + +验证推理结果 + diff --git a/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/lstm_revise.py b/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/lstm_revise.py index e68e93fc7e..8e91400188 100644 --- a/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/lstm_revise.py +++ b/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/lstm_revise.py @@ -1,286 +1,286 @@ -import os -import numpy as np -import torch -import onnx -import copy -from onnx import numpy_helper -G_ONNX_OPSET_VER = 11 -''' -def onnx_LSTM(batch, seq_len, input_size, hidden_size, num_layers, bidirectional, work_dir): - mod = torch.nn.LSTM(input_size, hidden_size, num_layers,bidirectional=bidirectional) - input = torch.randn(seq_len, batch, input_size)#(seq_len, batch, input_size) - h0 = torch.randn(2, 3, 20) - c0 = torch.randn(2, 3, 20) - print(mod.weight_ih_l0.size()) - print(mod.bias_hh_l0.size()) - print(mod.bias_ih_l0.size()) - output, _ = mod(input) - onnx_name = os.path.join(work_dir, "LSTM.onnx") - torch.onnx.export(mod, (input), f=onnx_name, - opset_version=G_ONNX_OPSET_VER) - return output -''' - -def GetNodeIndex(graph, node_name): - index = 0 - for i in range(len(graph.node)): - if graph.node[i].name == node_name: - index = i - break - return index - -def modify1(src_path,save_path): - model = onnx.load(src_path) - new_model = onnx.ModelProto() - for init in model.graph.initializer: - if init.name == "441": #95 - tmp1 = numpy_helper.to_array(init) - if init.name == "442": #96 - tmp2 = numpy_helper.to_array(init) - if init.name == "443": #97 - tmp3 = numpy_helper.to_array(init) - remove_weight = [] - for init in model.graph.initializer: - if init.name == "442": #96 - remove_weight.append(init) - if init.name == "441": #95 - remove_weight.append(init) - if init.name == "443": #97 - remove_weight.append(init) - for i in remove_weight: - model.graph.initializer.remove(i) - tmp = np.concatenate((tmp1,tmp2),axis=-1) - tmp_shape = tmp.shape - tmp = tmp.reshape(4,tmp_shape[-2]//4,tmp_shape[-1]).tolist() - #print(tmp[0]) - weight = np.array(tmp[0] + tmp[3] + tmp[2] + tmp[1]).reshape(tmp_shape[-2],tmp_shape[-1]).transpose(1,0) - init_tmp = numpy_helper.from_array(weight.astype(np.float32),name="441") #95 - model.graph.initializer.append(init_tmp) - bais_shape = [tmp3.shape[-1]] - tmp3 = tmp3.reshape(2,4,bais_shape[-1]//8).tolist() - bais1 = np.array(tmp3[0][0] + tmp3[0][3] + tmp3[0][2] + tmp3[0][1]).reshape(bais_shape[-1]//2) - bais2 = np.array(tmp3[1][0] + tmp3[1][3] + tmp3[1][2] + tmp3[1][1]).reshape(bais_shape[-1]//2) - bais = bais1 + bais2 - init_bais = numpy_helper.from_array(bais.astype(np.float32),name="443") #97 - model.graph.initializer.append(init_bais) - for idx,node in enumerate(model.graph.node): - if node.name == "LSTM_29": - print(model.graph.node[idx].input) - #model.graph.node[idx].input[1] = '' - #model.graph.node[idx].input[2] = '' - model.graph.node[idx].input.remove('442') #96 - model.graph.node[idx].input.remove('82') #14 - model.graph.node[idx].input.remove('82') #14 - model.graph.node[idx].input.remove('') #'' - model.graph.node[idx].input[1] = '441' #95 - model.graph.node[idx].input[2] = '443' #97 - #model.graph.node[idx].input[3] = '87' - - #去除Squeeze - remove_list = [] - for idx,node in enumerate(model.graph.node): - if node.name in {"Shape_23", "Gather_25", "Unsqueeze_26","Concat_27","ConstantOfShape_28","Constant_24","Squeeze_30"}: - remove_list.append(node) - - for node in remove_list: - model.graph.node.remove(node) - - - - model.graph.node[GetNodeIndex(model.graph,'Concat_49')].input[0] = '140' - onnx.save(model,save_path) - - -def modify2(src_path,save_path): - model = onnx.load(src_path) - new_model = onnx.ModelProto() - for init in model.graph.initializer: - if init.name == "463": #95 - tmp1 = numpy_helper.to_array(init) - if init.name == "464": #96 - tmp2 = numpy_helper.to_array(init) - if init.name == "465": #97 - tmp3 = numpy_helper.to_array(init) - remove_weight = [] - for init in model.graph.initializer: - if init.name == "464": #96 - remove_weight.append(init) - if init.name == "463": #95 - remove_weight.append(init) - if init.name == "465": #97 - remove_weight.append(init) - for i in remove_weight: - model.graph.initializer.remove(i) - tmp = np.concatenate((tmp1,tmp2),axis=-1) - tmp_shape = tmp.shape - tmp = tmp.reshape(4,tmp_shape[-2]//4,tmp_shape[-1]).tolist() - #print(tmp[0]) - weight = np.array(tmp[0] + tmp[3] + tmp[2] + tmp[1]).reshape(tmp_shape[-2],tmp_shape[-1]).transpose(1,0) - init_tmp = numpy_helper.from_array(weight.astype(np.float32),name="463") #95 - model.graph.initializer.append(init_tmp) - bais_shape = [tmp3.shape[-1]] - tmp3 = tmp3.reshape(2,4,bais_shape[-1]//8).tolist() - bais1 = np.array(tmp3[0][0] + tmp3[0][3] + tmp3[0][2] + tmp3[0][1]).reshape(bais_shape[-1]//2) - bais2 = np.array(tmp3[1][0] + tmp3[1][3] + tmp3[1][2] + tmp3[1][1]).reshape(bais_shape[-1]//2) - bais = bais1 + bais2 - init_bais = numpy_helper.from_array(bais.astype(np.float32),name="465") #97 - model.graph.initializer.append(init_bais) - for idx,node in enumerate(model.graph.node): - if node.name == "LSTM_42": - print(model.graph.node[idx].input) - #model.graph.node[idx].input[1] = '' - #model.graph.node[idx].input[2] = '' - model.graph.node[idx].input.remove('464') #96 - model.graph.node[idx].input.remove('158') #14 - model.graph.node[idx].input.remove('158') #14 - model.graph.node[idx].input.remove('') #'' - model.graph.node[idx].input[1] = '463' #95 - model.graph.node[idx].input[2] = '465' #97 - #model.graph.node[idx].input[3] = '87' - - remove_list = [] - for idx,node in enumerate(model.graph.node): - if node.name in {"Shape_36", "Gather_38", "Unsqueeze_39","Concat_40","ConstantOfShape_41","Constant_37","Squeeze_43"}: - remove_list.append(node) - - for node in remove_list: - model.graph.node.remove(node) - - model.graph.node[GetNodeIndex(model.graph,'Slice_48')].input[0] = '216' - - onnx.save(model,save_path) - -def modify3(src_path,save_path): - model = onnx.load(src_path) - new_model = onnx.ModelProto() - for init in model.graph.initializer: - if init.name == "486": #95 - tmp1 = numpy_helper.to_array(init) - if init.name == "487": #96 - tmp2 = numpy_helper.to_array(init) - if init.name == "488": #97 - tmp3 = numpy_helper.to_array(init) - remove_weight = [] - for init in model.graph.initializer: - if init.name == "487": #96 - remove_weight.append(init) - if init.name == "486": #95 - remove_weight.append(init) - if init.name == "488": #97 - remove_weight.append(init) - for i in remove_weight: - model.graph.initializer.remove(i) - tmp = np.concatenate((tmp1,tmp2),axis=-1) - tmp_shape = tmp.shape - tmp = tmp.reshape(4,tmp_shape[-2]//4,tmp_shape[-1]).tolist() - #print(tmp[0]) - weight = np.array(tmp[0] + tmp[3] + tmp[2] + tmp[1]).reshape(tmp_shape[-2],tmp_shape[-1]).transpose(1,0) - init_tmp = numpy_helper.from_array(weight.astype(np.float32),name="486") #95 - model.graph.initializer.append(init_tmp) - bais_shape = [tmp3.shape[-1]] - tmp3 = tmp3.reshape(2,4,bais_shape[-1]//8).tolist() - bais1 = np.array(tmp3[0][0] + tmp3[0][3] + tmp3[0][2] + tmp3[0][1]).reshape(bais_shape[-1]//2) - bais2 = np.array(tmp3[1][0] + tmp3[1][3] + tmp3[1][2] + tmp3[1][1]).reshape(bais_shape[-1]//2) - bais = bais1 + bais2 - init_bais = numpy_helper.from_array(bais.astype(np.float32),name="488") #97 - model.graph.initializer.append(init_bais) - for idx,node in enumerate(model.graph.node): - if node.name == "LSTM_75": - print(model.graph.node[idx].input) - #model.graph.node[idx].input[1] = '' - #model.graph.node[idx].input[2] = '' - model.graph.node[idx].input.remove('487') #96 - model.graph.node[idx].input.remove('256') #14 - model.graph.node[idx].input.remove('256') #14 - model.graph.node[idx].input.remove('') #'' - model.graph.node[idx].input[1] = '486' #95 - model.graph.node[idx].input[2] = '488' #97 - #model.graph.node[idx].input[3] = '87' - - remove_list = [] - for idx,node in enumerate(model.graph.node): - if node.name in {"Shape_69", "Gather_71", "Unsqueeze_72","Concat_73","ConstantOfShape_74","Constant_70","Squeeze_76"}: - remove_list.append(node) - - for node in remove_list: - model.graph.node.remove(node) - - model.graph.node[GetNodeIndex(model.graph,'Concat_95')].input[0] = '314' - - - onnx.save(model,save_path) - -def modify4(src_path,save_path): - model = onnx.load(src_path) - new_model = onnx.ModelProto() - for init in model.graph.initializer: - if init.name == "508": #95 - tmp1 = numpy_helper.to_array(init) - if init.name == "509": #96 - tmp2 = numpy_helper.to_array(init) - if init.name == "510": #97 - tmp3 = numpy_helper.to_array(init) - remove_weight = [] - for init in model.graph.initializer: - if init.name == "509": #96 - remove_weight.append(init) - if init.name == "508": #95 - remove_weight.append(init) - if init.name == "510": #97 - remove_weight.append(init) - for i in remove_weight: - model.graph.initializer.remove(i) - tmp = np.concatenate((tmp1,tmp2),axis=-1) - tmp_shape = tmp.shape - tmp = tmp.reshape(4,tmp_shape[-2]//4,tmp_shape[-1]).tolist() - #print(tmp[0]) - weight = np.array(tmp[0] + tmp[3] + tmp[2] + tmp[1]).reshape(tmp_shape[-2],tmp_shape[-1]).transpose(1,0) - init_tmp = numpy_helper.from_array(weight.astype(np.float32),name="508") #95 - model.graph.initializer.append(init_tmp) - bais_shape = [tmp3.shape[-1]] - tmp3 = tmp3.reshape(2,4,bais_shape[-1]//8).tolist() - bais1 = np.array(tmp3[0][0] + tmp3[0][3] + tmp3[0][2] + tmp3[0][1]).reshape(bais_shape[-1]//2) - bais2 = np.array(tmp3[1][0] + tmp3[1][3] + tmp3[1][2] + tmp3[1][1]).reshape(bais_shape[-1]//2) - bais = bais1 + bais2 - init_bais = numpy_helper.from_array(bais.astype(np.float32),name="510") #97 - model.graph.initializer.append(init_bais) - for idx,node in enumerate(model.graph.node): - if node.name == "LSTM_88": - print(model.graph.node[idx].input) - #model.graph.node[idx].input[1] = '' - #model.graph.node[idx].input[2] = '' - model.graph.node[idx].input.remove('509') #96 - model.graph.node[idx].input.remove('332') #14 - model.graph.node[idx].input.remove('332') #14 - model.graph.node[idx].input.remove('') #'' - model.graph.node[idx].input[1] = '508' #95 - model.graph.node[idx].input[2] = '510' #97 - #model.graph.node[idx].input[3] = '87' - - remove_list = [] - for idx,node in enumerate(model.graph.node): - if node.name in {"Shape_82", "Gather_84", "Unsqueeze_85","Concat_86","ConstantOfShape_87","Constant_83","Squeeze_89"}: - remove_list.append(node) - - for node in remove_list: - model.graph.node.remove(node) - model.graph.node[GetNodeIndex(model.graph,'Slice_94')].input[0] = '390' - - onnx.save(model,save_path) - -if __name__ == "__main__": - work_dir = "./" - batch = 1 - seq_len = 10 - input_size = 50 - hidden_size = 32 - num_layers = 1 - #onnx_LSTM(batch, seq_len, input_size, hidden_size, num_layers, False, work_dir) - modify1("./crnn_sim.onnx","./1.onnx") - modify2("./1.onnx","./2.onnx") - modify3("./2.onnx","./3.onnx") - modify4("./3.onnx","./crnn_revised.onnx") - os.remove("1.onnx") - os.remove("2.onnx") - os.remove("3.onnx") - print('Done') +import os +import numpy as np +import torch +import onnx +import copy +from onnx import numpy_helper +G_ONNX_OPSET_VER = 11 +''' +def onnx_LSTM(batch, seq_len, input_size, hidden_size, num_layers, bidirectional, work_dir): + mod = torch.nn.LSTM(input_size, hidden_size, num_layers,bidirectional=bidirectional) + input = torch.randn(seq_len, batch, input_size)#(seq_len, batch, input_size) + h0 = torch.randn(2, 3, 20) + c0 = torch.randn(2, 3, 20) + print(mod.weight_ih_l0.size()) + print(mod.bias_hh_l0.size()) + print(mod.bias_ih_l0.size()) + output, _ = mod(input) + onnx_name = os.path.join(work_dir, "LSTM.onnx") + torch.onnx.export(mod, (input), f=onnx_name, + opset_version=G_ONNX_OPSET_VER) + return output +''' + +def GetNodeIndex(graph, node_name): + index = 0 + for i in range(len(graph.node)): + if graph.node[i].name == node_name: + index = i + break + return index + +def modify1(src_path,save_path): + model = onnx.load(src_path) + new_model = onnx.ModelProto() + for init in model.graph.initializer: + if init.name == "441": #95 + tmp1 = numpy_helper.to_array(init) + if init.name == "442": #96 + tmp2 = numpy_helper.to_array(init) + if init.name == "443": #97 + tmp3 = numpy_helper.to_array(init) + remove_weight = [] + for init in model.graph.initializer: + if init.name == "442": #96 + remove_weight.append(init) + if init.name == "441": #95 + remove_weight.append(init) + if init.name == "443": #97 + remove_weight.append(init) + for i in remove_weight: + model.graph.initializer.remove(i) + tmp = np.concatenate((tmp1,tmp2),axis=-1) + tmp_shape = tmp.shape + tmp = tmp.reshape(4,tmp_shape[-2]//4,tmp_shape[-1]).tolist() + #print(tmp[0]) + weight = np.array(tmp[0] + tmp[3] + tmp[2] + tmp[1]).reshape(tmp_shape[-2],tmp_shape[-1]).transpose(1,0) + init_tmp = numpy_helper.from_array(weight.astype(np.float32),name="441") #95 + model.graph.initializer.append(init_tmp) + bais_shape = [tmp3.shape[-1]] + tmp3 = tmp3.reshape(2,4,bais_shape[-1]//8).tolist() + bais1 = np.array(tmp3[0][0] + tmp3[0][3] + tmp3[0][2] + tmp3[0][1]).reshape(bais_shape[-1]//2) + bais2 = np.array(tmp3[1][0] + tmp3[1][3] + tmp3[1][2] + tmp3[1][1]).reshape(bais_shape[-1]//2) + bais = bais1 + bais2 + init_bais = numpy_helper.from_array(bais.astype(np.float32),name="443") #97 + model.graph.initializer.append(init_bais) + for idx,node in enumerate(model.graph.node): + if node.name == "LSTM_29": + print(model.graph.node[idx].input) + #model.graph.node[idx].input[1] = '' + #model.graph.node[idx].input[2] = '' + model.graph.node[idx].input.remove('442') #96 + model.graph.node[idx].input.remove('82') #14 + model.graph.node[idx].input.remove('82') #14 + model.graph.node[idx].input.remove('') #'' + model.graph.node[idx].input[1] = '441' #95 + model.graph.node[idx].input[2] = '443' #97 + #model.graph.node[idx].input[3] = '87' + + #去除Squeeze + remove_list = [] + for idx,node in enumerate(model.graph.node): + if node.name in {"Shape_23", "Gather_25", "Unsqueeze_26","Concat_27","ConstantOfShape_28","Constant_24","Squeeze_30"}: + remove_list.append(node) + + for node in remove_list: + model.graph.node.remove(node) + + + + model.graph.node[GetNodeIndex(model.graph,'Concat_49')].input[0] = '140' + onnx.save(model,save_path) + + +def modify2(src_path,save_path): + model = onnx.load(src_path) + new_model = onnx.ModelProto() + for init in model.graph.initializer: + if init.name == "463": #95 + tmp1 = numpy_helper.to_array(init) + if init.name == "464": #96 + tmp2 = numpy_helper.to_array(init) + if init.name == "465": #97 + tmp3 = numpy_helper.to_array(init) + remove_weight = [] + for init in model.graph.initializer: + if init.name == "464": #96 + remove_weight.append(init) + if init.name == "463": #95 + remove_weight.append(init) + if init.name == "465": #97 + remove_weight.append(init) + for i in remove_weight: + model.graph.initializer.remove(i) + tmp = np.concatenate((tmp1,tmp2),axis=-1) + tmp_shape = tmp.shape + tmp = tmp.reshape(4,tmp_shape[-2]//4,tmp_shape[-1]).tolist() + #print(tmp[0]) + weight = np.array(tmp[0] + tmp[3] + tmp[2] + tmp[1]).reshape(tmp_shape[-2],tmp_shape[-1]).transpose(1,0) + init_tmp = numpy_helper.from_array(weight.astype(np.float32),name="463") #95 + model.graph.initializer.append(init_tmp) + bais_shape = [tmp3.shape[-1]] + tmp3 = tmp3.reshape(2,4,bais_shape[-1]//8).tolist() + bais1 = np.array(tmp3[0][0] + tmp3[0][3] + tmp3[0][2] + tmp3[0][1]).reshape(bais_shape[-1]//2) + bais2 = np.array(tmp3[1][0] + tmp3[1][3] + tmp3[1][2] + tmp3[1][1]).reshape(bais_shape[-1]//2) + bais = bais1 + bais2 + init_bais = numpy_helper.from_array(bais.astype(np.float32),name="465") #97 + model.graph.initializer.append(init_bais) + for idx,node in enumerate(model.graph.node): + if node.name == "LSTM_42": + print(model.graph.node[idx].input) + #model.graph.node[idx].input[1] = '' + #model.graph.node[idx].input[2] = '' + model.graph.node[idx].input.remove('464') #96 + model.graph.node[idx].input.remove('158') #14 + model.graph.node[idx].input.remove('158') #14 + model.graph.node[idx].input.remove('') #'' + model.graph.node[idx].input[1] = '463' #95 + model.graph.node[idx].input[2] = '465' #97 + #model.graph.node[idx].input[3] = '87' + + remove_list = [] + for idx,node in enumerate(model.graph.node): + if node.name in {"Shape_36", "Gather_38", "Unsqueeze_39","Concat_40","ConstantOfShape_41","Constant_37","Squeeze_43"}: + remove_list.append(node) + + for node in remove_list: + model.graph.node.remove(node) + + model.graph.node[GetNodeIndex(model.graph,'Slice_48')].input[0] = '216' + + onnx.save(model,save_path) + +def modify3(src_path,save_path): + model = onnx.load(src_path) + new_model = onnx.ModelProto() + for init in model.graph.initializer: + if init.name == "486": #95 + tmp1 = numpy_helper.to_array(init) + if init.name == "487": #96 + tmp2 = numpy_helper.to_array(init) + if init.name == "488": #97 + tmp3 = numpy_helper.to_array(init) + remove_weight = [] + for init in model.graph.initializer: + if init.name == "487": #96 + remove_weight.append(init) + if init.name == "486": #95 + remove_weight.append(init) + if init.name == "488": #97 + remove_weight.append(init) + for i in remove_weight: + model.graph.initializer.remove(i) + tmp = np.concatenate((tmp1,tmp2),axis=-1) + tmp_shape = tmp.shape + tmp = tmp.reshape(4,tmp_shape[-2]//4,tmp_shape[-1]).tolist() + #print(tmp[0]) + weight = np.array(tmp[0] + tmp[3] + tmp[2] + tmp[1]).reshape(tmp_shape[-2],tmp_shape[-1]).transpose(1,0) + init_tmp = numpy_helper.from_array(weight.astype(np.float32),name="486") #95 + model.graph.initializer.append(init_tmp) + bais_shape = [tmp3.shape[-1]] + tmp3 = tmp3.reshape(2,4,bais_shape[-1]//8).tolist() + bais1 = np.array(tmp3[0][0] + tmp3[0][3] + tmp3[0][2] + tmp3[0][1]).reshape(bais_shape[-1]//2) + bais2 = np.array(tmp3[1][0] + tmp3[1][3] + tmp3[1][2] + tmp3[1][1]).reshape(bais_shape[-1]//2) + bais = bais1 + bais2 + init_bais = numpy_helper.from_array(bais.astype(np.float32),name="488") #97 + model.graph.initializer.append(init_bais) + for idx,node in enumerate(model.graph.node): + if node.name == "LSTM_75": + print(model.graph.node[idx].input) + #model.graph.node[idx].input[1] = '' + #model.graph.node[idx].input[2] = '' + model.graph.node[idx].input.remove('487') #96 + model.graph.node[idx].input.remove('256') #14 + model.graph.node[idx].input.remove('256') #14 + model.graph.node[idx].input.remove('') #'' + model.graph.node[idx].input[1] = '486' #95 + model.graph.node[idx].input[2] = '488' #97 + #model.graph.node[idx].input[3] = '87' + + remove_list = [] + for idx,node in enumerate(model.graph.node): + if node.name in {"Shape_69", "Gather_71", "Unsqueeze_72","Concat_73","ConstantOfShape_74","Constant_70","Squeeze_76"}: + remove_list.append(node) + + for node in remove_list: + model.graph.node.remove(node) + + model.graph.node[GetNodeIndex(model.graph,'Concat_95')].input[0] = '314' + + + onnx.save(model,save_path) + +def modify4(src_path,save_path): + model = onnx.load(src_path) + new_model = onnx.ModelProto() + for init in model.graph.initializer: + if init.name == "508": #95 + tmp1 = numpy_helper.to_array(init) + if init.name == "509": #96 + tmp2 = numpy_helper.to_array(init) + if init.name == "510": #97 + tmp3 = numpy_helper.to_array(init) + remove_weight = [] + for init in model.graph.initializer: + if init.name == "509": #96 + remove_weight.append(init) + if init.name == "508": #95 + remove_weight.append(init) + if init.name == "510": #97 + remove_weight.append(init) + for i in remove_weight: + model.graph.initializer.remove(i) + tmp = np.concatenate((tmp1,tmp2),axis=-1) + tmp_shape = tmp.shape + tmp = tmp.reshape(4,tmp_shape[-2]//4,tmp_shape[-1]).tolist() + #print(tmp[0]) + weight = np.array(tmp[0] + tmp[3] + tmp[2] + tmp[1]).reshape(tmp_shape[-2],tmp_shape[-1]).transpose(1,0) + init_tmp = numpy_helper.from_array(weight.astype(np.float32),name="508") #95 + model.graph.initializer.append(init_tmp) + bais_shape = [tmp3.shape[-1]] + tmp3 = tmp3.reshape(2,4,bais_shape[-1]//8).tolist() + bais1 = np.array(tmp3[0][0] + tmp3[0][3] + tmp3[0][2] + tmp3[0][1]).reshape(bais_shape[-1]//2) + bais2 = np.array(tmp3[1][0] + tmp3[1][3] + tmp3[1][2] + tmp3[1][1]).reshape(bais_shape[-1]//2) + bais = bais1 + bais2 + init_bais = numpy_helper.from_array(bais.astype(np.float32),name="510") #97 + model.graph.initializer.append(init_bais) + for idx,node in enumerate(model.graph.node): + if node.name == "LSTM_88": + print(model.graph.node[idx].input) + #model.graph.node[idx].input[1] = '' + #model.graph.node[idx].input[2] = '' + model.graph.node[idx].input.remove('509') #96 + model.graph.node[idx].input.remove('332') #14 + model.graph.node[idx].input.remove('332') #14 + model.graph.node[idx].input.remove('') #'' + model.graph.node[idx].input[1] = '508' #95 + model.graph.node[idx].input[2] = '510' #97 + #model.graph.node[idx].input[3] = '87' + + remove_list = [] + for idx,node in enumerate(model.graph.node): + if node.name in {"Shape_82", "Gather_84", "Unsqueeze_85","Concat_86","ConstantOfShape_87","Constant_83","Squeeze_89"}: + remove_list.append(node) + + for node in remove_list: + model.graph.node.remove(node) + model.graph.node[GetNodeIndex(model.graph,'Slice_94')].input[0] = '390' + + onnx.save(model,save_path) + +if __name__ == "__main__": + work_dir = "./" + batch = 1 + seq_len = 10 + input_size = 50 + hidden_size = 32 + num_layers = 1 + #onnx_LSTM(batch, seq_len, input_size, hidden_size, num_layers, False, work_dir) + modify1("./crnn_sim.onnx","./1.onnx") + modify2("./1.onnx","./2.onnx") + modify3("./2.onnx","./3.onnx") + modify4("./3.onnx","./crnn_revised.onnx") + os.remove("1.onnx") + os.remove("2.onnx") + os.remove("3.onnx") + print('Done') diff --git a/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/parse_testdata.py b/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/parse_testdata.py index 62185425c7..d9a1926a6e 100644 --- a/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/parse_testdata.py +++ b/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/parse_testdata.py @@ -1,79 +1,79 @@ -import os -import re -import six -import lmdb -from PIL import Image -import numpy as np -import torchvision - - -test_dir = '/home/ltsong/1230/CRNN/IIIT5K_lmdb/' -alphabets = '0123456789abcdefghijklmnopqrstuvwxyz' -output_bin = './input_bin/' - - -class resizeNormalize(object): - def __init__(self, size, interpolation=Image.BICUBIC): - self.size = size - self.interpolation = interpolation - self.toTensor = torchvision.transforms.ToTensor() - - def __call__(self, img): - img = img.resize(self.size, self.interpolation) - img = self.toTensor(img) - img.sub_(0.5).div_(0.5) - return img - - -def gen_data_label(test_dir, data_dir): - if not os.path.exists(data_dir): - os.mkdir(data_dir) - - env = lmdb.open(test_dir, max_readers=32, readonly=True, lock=False, readahead=False, meminit=False) - if not env: - print('cannot open lmdb from %s' % (test_dir)) - sys.exit(0) - with env.begin(write=False) as txn: - nSamples = int(txn.get('num-samples'.encode()).decode('utf-8')) - print('origin nSamples is:', nSamples) - filtered_index_list = [] - - with open('label.txt', 'w') as f: - for index in range(nSamples): - index += 1 - # images - img_key = 'image-%09d'.encode() % index - imgbuf = txn.get(img_key) - buf = six.BytesIO() - buf.write(imgbuf) - buf.seek(0) - try: - img = Image.open(buf).convert('L') - img.show() - # transform - transform = resizeNormalize((100, 32)) - img = transform(img) - img = np.array(img, np.float32) - img.tofile('{}/test_{}.bin'.format(data_dir, index)) - - except IOError: - print('Corrupted image for %d' % index) - - # label - label_key = 'label-%09d'.encode() % index - label = txn.get(label_key).decode('utf-8') - label = label.lower() - - line = 'test_{}.bin:{}'.format(index, label) - f.write(line) - f.write('\n') - out_of_char = f'[^{alphabets}]' - if re.search(out_of_char, label.lower()): - continue - filtered_index_list.append(index) - new_Samples = len(filtered_index_list) - print('new nSamples is:', new_Samples) - - -if __name__ == '__main__': - gen_data_label(test_dir, output_bin) +import os +import re +import six +import lmdb +from PIL import Image +import numpy as np +import torchvision + + +test_dir = '/home/ltsong/1230/CRNN/IIIT5K_lmdb/' +alphabets = '0123456789abcdefghijklmnopqrstuvwxyz' +output_bin = './input_bin/' + + +class resizeNormalize(object): + def __init__(self, size, interpolation=Image.BICUBIC): + self.size = size + self.interpolation = interpolation + self.toTensor = torchvision.transforms.ToTensor() + + def __call__(self, img): + img = img.resize(self.size, self.interpolation) + img = self.toTensor(img) + img.sub_(0.5).div_(0.5) + return img + + +def gen_data_label(test_dir, data_dir): + if not os.path.exists(data_dir): + os.mkdir(data_dir) + + env = lmdb.open(test_dir, max_readers=32, readonly=True, lock=False, readahead=False, meminit=False) + if not env: + print('cannot open lmdb from %s' % (test_dir)) + sys.exit(0) + with env.begin(write=False) as txn: + nSamples = int(txn.get('num-samples'.encode()).decode('utf-8')) + print('origin nSamples is:', nSamples) + filtered_index_list = [] + + with open('label.txt', 'w') as f: + for index in range(nSamples): + index += 1 + # images + img_key = 'image-%09d'.encode() % index + imgbuf = txn.get(img_key) + buf = six.BytesIO() + buf.write(imgbuf) + buf.seek(0) + try: + img = Image.open(buf).convert('L') + img.show() + # transform + transform = resizeNormalize((100, 32)) + img = transform(img) + img = np.array(img, np.float32) + img.tofile('{}/test_{}.bin'.format(data_dir, index)) + + except IOError: + print('Corrupted image for %d' % index) + + # label + label_key = 'label-%09d'.encode() % index + label = txn.get(label_key).decode('utf-8') + label = label.lower() + + line = 'test_{}.bin:{}'.format(index, label) + f.write(line) + f.write('\n') + out_of_char = f'[^{alphabets}]' + if re.search(out_of_char, label.lower()): + continue + filtered_index_list.append(index) + new_Samples = len(filtered_index_list) + print('new nSamples is:', new_Samples) + + +if __name__ == '__main__': + gen_data_label(test_dir, output_bin) diff --git a/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/postpossess_CRNN_pytorch.py b/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/postpossess_CRNN_pytorch.py index 75ed28482d..b78f0785e7 100644 --- a/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/postpossess_CRNN_pytorch.py +++ b/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/postpossess_CRNN_pytorch.py @@ -1,138 +1,138 @@ -import os -import sys -import numpy as np -import torch - - -class strLabelConverter(object): - """Convert between str and label. - NOTE: - Insert `blank` to the alphabet for CTC. - Args: - alphabet (str): set of the possible characters. - ignore_case (bool, default=True): whether or not to ignore all of the case. - """ - - def __init__(self, alphabet, ignore_case=False): - self._ignore_case = ignore_case - if self._ignore_case: - alphabet = alphabet.lower() - self.alphabet = alphabet + '-' # for `-1` index - self.dict = {} - for i, char in enumerate(alphabet): - # NOTE: 0 is reserved for 'blank' required by wrap_ctc - self.dict[char] = i + 1 - - def encode(self, text): - """Support batch or single str. - Args: - text (str or list of str): texts to convert. - Returns: - torch.LongTensor [length_0 + length_1 + ... length_{n - 1}]: encoded texts. - torch.LongTensor [n]: length of each text. - """ - - length = [] - result = [] - for item in text: - length.append(len(item)) - r = [] - for char in item: - index = self.dict[char] - # result.append(index) - r.append(index) - result.append(r) - max_len = 0 - for r in result: - if len(r) > max_len: - max_len = len(r) - result_temp = [] - for r in result: - for i in range(max_len - len(r)): - r.append(0) - result_temp.append(r) - text = result_temp - return (torch.LongTensor(text), torch.LongTensor(length)) - - def decode(self, t, length, raw=False): - """Decode encoded texts back into strs. - Args: - torch.LongTensor [length_0 + length_1 + ... length_{n - 1}]: encoded texts. - torch.LongTensor [n]: length of each text. - Raises: - AssertionError: when the texts and its length does not match. - Returns: - text (str or list of str): texts to convert. - """ - if length.numel() == 1: - length = length[0] - assert t.numel() == length, "text with length: {} does not match declared length: {}".format(t.numel(), length) - if raw: - return ''.join([self.alphabet[i - 1] for i in t]) - else: - char_list = [] - for i in range(length): - if t[i] != 0 and (not (i > 0 and t[i - 1] == t[i])): - char_list.append(self.alphabet[t[i] - 1]) - return ''.join(char_list) - else: - # batch mode - assert t.numel() == length.sum(), "texts with length: {} does not match declared length: {}".format(t.numel(), length.sum()) - texts = [] - index = 0 - for i in range(length.numel()): - l = length[i] - texts.append( - self.decode( - t[index:index + l], torch.LongTensor([l]), raw=raw)) - index += l - return texts - - -total_img = 3000 - -def get_Acc(bin_path, label, batch_size): - # label - keys, vals = [], [] - with open(label, 'r') as f: - content = f.read() - contents = content.split('\n')[:-1] - for cot in contents: - cot = cot.split(':') - keys.append(cot[0]) - vals.append(cot[1]) - - labels = dict(zip(keys, vals)) - count = 0 - for index in range(total_img): - index += 1 - - preds = np.fromfile('{}/test_{}_1.bin'.format(bin_path, index), np.float32).reshape(26, -1, 37) - preds = torch.from_numpy(preds) - # print("preds.shape:", preds.shape) - preds_size = torch.LongTensor([preds.size(0)] * batch_size) - - _, preds = preds.max(2) - preds = preds.transpose(1, 0).contiguous().view(-1) - - converter = strLabelConverter('0123456789abcdefghijklmnopqrstuvwxyz') - sim_preds = converter.decode(preds.data, preds_size.data, raw=False) - # print("preds_size.data:",preds_size.data) - key = 'test_{}.bin'.format(index) - if sim_preds == labels[key]: - count += 1 - else: - print("label:{} pred:{}".format(labels[key], sim_preds)) - - # acc - print('*'*50) - print('rightNum: {}'.format(count)) - print('totalNum: {}'.format(total_img)) - print("accuracy_rate %.2f" % (count / total_img * 100)) - print('*'*50) - - -if __name__ == '__main__': - bin_path = 'result/dumpOutput_device1/' - label = './label.txt' - get_Acc(bin_path, label, 1) +import os +import sys +import numpy as np +import torch + + +class strLabelConverter(object): + """Convert between str and label. + NOTE: + Insert `blank` to the alphabet for CTC. + Args: + alphabet (str): set of the possible characters. + ignore_case (bool, default=True): whether or not to ignore all of the case. + """ + + def __init__(self, alphabet, ignore_case=False): + self._ignore_case = ignore_case + if self._ignore_case: + alphabet = alphabet.lower() + self.alphabet = alphabet + '-' # for `-1` index + self.dict = {} + for i, char in enumerate(alphabet): + # NOTE: 0 is reserved for 'blank' required by wrap_ctc + self.dict[char] = i + 1 + + def encode(self, text): + """Support batch or single str. + Args: + text (str or list of str): texts to convert. + Returns: + torch.LongTensor [length_0 + length_1 + ... length_{n - 1}]: encoded texts. + torch.LongTensor [n]: length of each text. + """ + + length = [] + result = [] + for item in text: + length.append(len(item)) + r = [] + for char in item: + index = self.dict[char] + # result.append(index) + r.append(index) + result.append(r) + max_len = 0 + for r in result: + if len(r) > max_len: + max_len = len(r) + result_temp = [] + for r in result: + for i in range(max_len - len(r)): + r.append(0) + result_temp.append(r) + text = result_temp + return (torch.LongTensor(text), torch.LongTensor(length)) + + def decode(self, t, length, raw=False): + """Decode encoded texts back into strs. + Args: + torch.LongTensor [length_0 + length_1 + ... length_{n - 1}]: encoded texts. + torch.LongTensor [n]: length of each text. + Raises: + AssertionError: when the texts and its length does not match. + Returns: + text (str or list of str): texts to convert. + """ + if length.numel() == 1: + length = length[0] + assert t.numel() == length, "text with length: {} does not match declared length: {}".format(t.numel(), length) + if raw: + return ''.join([self.alphabet[i - 1] for i in t]) + else: + char_list = [] + for i in range(length): + if t[i] != 0 and (not (i > 0 and t[i - 1] == t[i])): + char_list.append(self.alphabet[t[i] - 1]) + return ''.join(char_list) + else: + # batch mode + assert t.numel() == length.sum(), "texts with length: {} does not match declared length: {}".format(t.numel(), length.sum()) + texts = [] + index = 0 + for i in range(length.numel()): + l = length[i] + texts.append( + self.decode( + t[index:index + l], torch.LongTensor([l]), raw=raw)) + index += l + return texts + + +total_img = 3000 + +def get_Acc(bin_path, label, batch_size): + # label + keys, vals = [], [] + with open(label, 'r') as f: + content = f.read() + contents = content.split('\n')[:-1] + for cot in contents: + cot = cot.split(':') + keys.append(cot[0]) + vals.append(cot[1]) + + labels = dict(zip(keys, vals)) + count = 0 + for index in range(total_img): + index += 1 + + preds = np.fromfile('{}/test_{}_1.bin'.format(bin_path, index), np.float32).reshape(26, -1, 37) + preds = torch.from_numpy(preds) + # print("preds.shape:", preds.shape) + preds_size = torch.LongTensor([preds.size(0)] * batch_size) + + _, preds = preds.max(2) + preds = preds.transpose(1, 0).contiguous().view(-1) + + converter = strLabelConverter('0123456789abcdefghijklmnopqrstuvwxyz') + sim_preds = converter.decode(preds.data, preds_size.data, raw=False) + # print("preds_size.data:",preds_size.data) + key = 'test_{}.bin'.format(index) + if sim_preds == labels[key]: + count += 1 + else: + print("label:{} pred:{}".format(labels[key], sim_preds)) + + # acc + print('*'*50) + print('rightNum: {}'.format(count)) + print('totalNum: {}'.format(total_img)) + print("accuracy_rate %.2f" % (count / total_img * 100)) + print('*'*50) + + +if __name__ == '__main__': + bin_path = 'result/dumpOutput_device1/' + label = './label.txt' + get_Acc(bin_path, label, 1) diff --git a/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/pth2onnx.py b/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/pth2onnx.py index f3c48a4f12..9e1b2a80c2 100644 --- a/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/pth2onnx.py +++ b/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch/pth2onnx.py @@ -1,22 +1,22 @@ -import torch -import crnn -import onnx -import torch.onnx - -def convert(): - checkpoint = torch.load("./checkpoint_16_CRNN_acc_0.7963.pth", map_location='cpu') - model = crnn.CRNN(32,1,37,256) - model.load_state_dict(checkpoint['state_dict']) - model.eval() - print(model) - - input_names = ["actual_input_1"] - output_names = ["output1"] - dummy_input = torch.randn(1, 1, 32, 100) - dynamic_axes = {'actual_input_1':{0:'-1'},'output1':{1:'-1'}} - print('\nStarting ONNX export with onnx %s...' % onnx.__version__) - torch.onnx.export(model, dummy_input, "crnn_npu_dy.onnx", input_names=input_names,dynamic_axes = dynamic_axes, output_names=output_names, opset_version=11) - - -if __name__ == "__main__": - convert() +import torch +import crnn +import onnx +import torch.onnx + +def convert(): + checkpoint = torch.load("./checkpoint_16_CRNN_acc_0.7963.pth", map_location='cpu') + model = crnn.CRNN(32,1,37,256) + model.load_state_dict(checkpoint['state_dict']) + model.eval() + print(model) + + input_names = ["actual_input_1"] + output_names = ["output1"] + dummy_input = torch.randn(1, 1, 32, 100) + dynamic_axes = {'actual_input_1':{0:'-1'},'output1':{1:'-1'}} + print('\nStarting ONNX export with onnx %s...' % onnx.__version__) + torch.onnx.export(model, dummy_input, "crnn_npu_dy.onnx", input_names=input_names,dynamic_axes = dynamic_axes, output_names=output_names, opset_version=11) + + +if __name__ == "__main__": + convert() diff --git a/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/LICENSE b/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/LICENSE index 4ba4fdcab3..a0e0310359 100644 --- a/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/LICENSE +++ b/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/LICENSE @@ -1,29 +1,29 @@ -BSD 3-Clause License - -Copyright (c) 2017, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +BSD 3-Clause License + +Copyright (c) 2017, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/OXInterface.py b/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/OXInterface.py index 658c5ff9a9..08e9180e65 100644 --- a/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/OXInterface.py +++ b/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/OXInterface.py @@ -1,1249 +1,1249 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ - -''' -环境: - python==3.8.5 - onnx==1.8.1 - onnxruntime==1.7.0 - skl2onnx==1.8.0 - numpy==1.19.5 -''' - -import os -import sys -import onnx -import copy -import time -import shutil -import numpy as np -import onnxruntime - -from enum import IntEnum -from onnx import NodeProto -from datetime import datetime -from functools import lru_cache -from typing import List, Dict, Any, NoReturn -from onnx.numpy_helper import from_array, to_array -from onnx.onnx_ml_pb2 import TensorProto, ValueInfoProto, AttributeProto -from onnx.helper import make_attribute, make_node, make_graph, make_model -from skl2onnx.helpers.onnx_helper import enumerate_model_node_outputs, select_model_inputs_outputs, save_onnx_model - -# 修改递归深度限制 -sys.setrecursionlimit(100000) - - -# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> enum OXDataType -# onnx类型枚举值 -class OXDataType(IntEnum): - float32 = 1 - uint8 = 2 - int8 = 3 - uint16 = 4 - int16 = 5 - int32 = 6 - int64 = 7 - string = 8 - bool = 9 - float16 = 10 - double = 11 - uint32 = 12 - uint64 = 13 - complex64 = 14 - complex128 = 15 - bfloat16 = 16 - - -# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> calss GV -# 全局变量,GV = global variable -class GV: - # onnx和numpy数据类型映射字典 - ONNX_2_NUMPY_DATATYPE_DICT = { - 1: np.float32, - 2: np.uint8, - 3: np.int8, - 4: np.uint16, - 5: np.int16, - 6: np.int32, - 7: np.int64, - 9: np.bool_, - 10: np.float16, - 11: np.float64, - 12: np.uint32, - 13: np.uint64, - 14: np.complex64, - 15: np.complex128, - np.float32: 1, - np.uint8: 2, - np.int8: 3, - np.uint16: 4, - np.int16: 5, - np.int32: 6, - np.int64: 7, - np.bool_: 9, - np.float16: 10, - np.float64: 11, - np.uint32: 12, - np.uint64: 13, - np.complex64: 14, - np.complex128: 15, - 'tensor(float)': np.float32, - 'tensor(uint8)': np.uint8, - 'tensor(int8)': np.int8, - 'tensor(uint16)': np.uint16, - 'tensor(int16)': np.int16, - 'tensor(int32)': np.int32, - 'tensor(int64)': np.int64, - 'tensor(bool)': np.bool_, - 'tensor(float16)': np.float16, - 'tensor(double)': np.float64, - 'tensor(uint32)': np.uint32, - 'tensor(uint64)': np.uint64, - } - - # initializer,node索引字典(实现快速查找) - OXINITIALIZER_DICT = {} - OXNODE_DICT = {} - - -# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> calss OXInitializer -class OXInitializer: - ''' - If you print a Initializer variable in the terminal, you will get something like this, and you can modify it - directly. - dims: 1 - data_type: 6 - name: '4239' - raw_data: '\000\000\000\00' - - @dims: google.protobuf.pyext._message.RepeatedScalarContainer - @data_type: int - @name: str - @raw_data: bytes - ''' - - def __init__(self, initializer: TensorProto): - self._initializer = initializer - - def __str__(self): - ndarray = to_array(self._initializer) - msg = 'name: ' + str(self._initializer.name) + '\n' + \ - 'dims: ' + str(self._initializer.dims) + '\n' + \ - 'data_type: ' + str(self._initializer.data_type) + '\n' + \ - 'dtype: ' + str(ndarray.dtype) + '\n' + \ - 'shape: ' + str(ndarray.shape) + '\n' + \ - 'ndarray:\n' + str(ndarray) - return msg - - def get_initializer(self) -> TensorProto: - return self._initializer - - def get_name(self) -> str: - ''' - 获取initializer的名字 - ''' - - return self._initializer.name - - def set_name(self, new_name) -> NoReturn: - ''' - 设置/修改initializer的名字 - ''' - - old_name = self._initializer.name - self._initializer.name = new_name - GV.OXINITIALIZER_DICT[new_name] = GV.OXINITIALIZER_DICT[old_name] - GV.OXINITIALIZER_DICT.pop(old_name) - - def get_data_type(self) -> int: - ''' - 获取initializer的数据类型 - ''' - - return self._initializer.data_type - - def set_data_type(self, ox_data_type: OXDataType) -> NoReturn: - ''' - 设置/修改initializer的数据类型 - ''' - - ndarray = to_array(self._initializer).astype(GV.ONNX_2_NUMPY_DATATYPE_DICT[int(ox_data_type)]) - self._initializer.raw_data = ndarray.tobytes() - self._initializer.data_type = int(ox_data_type) - - def get_data(self) -> np.ndarray: - ''' - 获取initializer的数据 - ''' - - return to_array(self._initializer) - - def set_data(self, ndarray: np.ndarray) -> NoReturn: - ''' - 设置/修改initializer的数据 - ''' - - self._initializer.raw_data = ndarray.tobytes() - self._initializer.data_type = GV.ONNX_2_NUMPY_DATATYPE_DICT[eval('np.' + str(ndarray.dtype))] - _clear_list(self._initializer.dims) - _extend_list(self._initializer.dims, ndarray.shape) - - def save_data(self, file_path: str) -> NoReturn: - ''' - 保存initializer的数据 - ''' - - np.save(file_path, to_array(self._initializer)) - - -# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> calss OXNode -class OXNode: - ''' - If you print a NodeProto variable in the terminal, you will get something like this, and you can modify it directly. - input: '494' - input: 'fc.weight' - input: 'fc.bias' - output: 'class' - name: 'Gemm_121' - op_type: 'Gemm' - attribute { - name: 'alpha' - f: 1.0 - type: FLOAT - } - attribute { - name: 'beta' - f: 1.0 - type: FLOAT - } - attribute { - name: 'transB' - i: 1 - type: INT - } - - @input: google.protobuf.pyext._message.RepeatedScalarContainer - @output: google.protobuf.pyext._message.RepeatedScalarContainer - @name: str - @op_type: str - @attribute: google.protobuf.pyext._message.RepeatedCompositeContainer - ''' - - def __init__(self, node: NodeProto): - self._node = node - - def __str__(self): - return str(self._node) - - def get_node(self) -> NodeProto: - return self._node - - @property - def input(self): # -> google.protobuf.pyext._message.RepeatedScalarContainer - ''' - 获取节点的输入列表 - ''' - - return self._node.input - - @property - def output(self): # -> google.protobuf.pyext._message.RepeatedScalarContainer - ''' - 获取节点的输出列表 - ''' - - return self._node.output - - def get_name(self) -> str: - ''' - 获取节点的名字 - ''' - - return self._node.name - - def set_name(self, new_name) -> NoReturn: - ''' - 设置/修改节点的名字 - ''' - - old_name = self._node.name - self._node.name = new_name - GV.OXNODE_DICT[new_name] = GV.OXNODE_DICT[old_name] - GV.OXNODE_DICT.pop(old_name) - - def get_op_type(self) -> int: - ''' - 获取节点的类型 - ''' - - return self._node.op_type - - def set_op_type(self, op_type) -> NoReturn: - ''' - 设置/修改节点的类型 - ''' - - self._node.op_type = op_type - - def get_attribute(self): # -> google.protobuf.pyext._message.RepeatedCompositeContainer - ''' - 获取节点属性 - ''' - - return self._node.attribute - - def set_attribute(self, attr_name: str, attr_value: Any) -> AttributeProto: - ''' - 设置/修改节点属性 - - Args: - attr_name: 属性名字 - attr_value: 属性值 - - Returns: 修改后的属性 - ''' - - # 构造新attr - new_attr = make_attribute(attr_name, attr_value) - - # 删除旧的 - for attr in self._node.attribute: - if attr.name == attr_name: - self._node.attribute.remove(attr) - break - - # 添加新的 - self._node.attribute.append(new_attr) - - return new_attr - - def add_attribute(self, attr_name: str, attr_value: Any) -> AttributeProto: - ''' - 给节点增加新属性 - - Args: - attr_name: 属性名字 - attr_value: 属性值 - - Returns: 新增的属性 - ''' - - # 构造新attr - new_attr = make_attribute(attr_name, attr_value) - - # 增加 - self._node.attribute.append(new_attr) - - return new_attr - - def remove_attribute(self, attr_name: str) -> AttributeProto: - ''' - 删除节点的某个属性 - - Args: - attr_name: 属性名字 - attr_value: 属性值 - - Returns: 被删除的属性 - ''' - - for attr in self._node.attribute: - if attr.name == attr_name: - removed_attr = attr - self._node.attribute.remove(attr) - break - - return removed_attr - - -# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> calss OXGraph -class OXGraph: - def __init__(self, model_path: str): - print('[INFO] Start initializing.') - start_time = datetime.now() - - self._model_path = model_path - self._model = onnx.load_model(model_path) - self._graph = self._model.graph - self._initializer = self._graph.initializer - self._node = self._graph.node - self._input_tensor_2_oxnode_dict = {} - self._output_tensor_2_oxnode_dict = {} - - # initializer - for initializer in self._initializer: - GV.OXINITIALIZER_DICT[initializer.name] = OXInitializer(initializer) - - # node - for idx, node in enumerate(self._node): - oxnode = OXNode(node) - GV.OXNODE_DICT[node.name] = oxnode - - # 创建tensor_2_oxnode字典 - self._update_tensor_2_oxnode_dict( - self._input_tensor_2_oxnode_dict, - self._output_tensor_2_oxnode_dict, - ) - - # 获取所有tensor信息 - try: - self._all_tensor_info = self.get_all_tensor_info() - except: - os.remove(os.path.join(os.path.dirname(self._model_path), 'temp.onnx')) - print('[WARNING] There are custom operators in the model, ' - 'and these functions are not available: get_input_tensor_info()、get_output_tensor_info()、' - 'get_all_tensor_info()、infer_shape()、dump_all_node_data()、trunc_model().') - - # 屏蔽check_model - def check_model(model): - pass - - onnx.checker.check_model = check_model - - end_time = datetime.now() - cost_time = (end_time - start_time).seconds - print('[INFO] Initialization completed! Cost {} seconds.'.format(cost_time)) - - def __str__(self): - return str(self._model) - - # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Initializer相关函数 - def get_oxinitializer_by_name(self, oxinitializer_name: str, can_return_none: bool = False) -> OXInitializer: - ''' - 根据initializer的名字获取OXInitializer - ''' - - if oxinitializer_name not in GV.OXINITIALIZER_DICT: - if can_return_none is True: - return None - else: - raise RuntimeError('[ERROR] {} not found.'.format(oxinitializer_name)) - return GV.OXINITIALIZER_DICT[oxinitializer_name] - - def add_initializer(self, initializer_name: str, ndarray: np.ndarray) -> OXInitializer: - ''' - 向模型中新增一个initializer - - Args: - initializer_name: initializer的名字 - ndarray: initializer的数据 - - Returns: 新增的OXInitializer - ''' - - if initializer_name in GV.OXINITIALIZER_DICT: - raise RuntimeError( - '[ERROR] {} has already exists in the model, please use a different name!'.format(initializer_name)) - - initializer = from_array(ndarray, initializer_name) - self._initializer.append(initializer) # 这里是复制,而不是引用,id已经变了 - initializer = self._initializer[-1] - oxinitializer = OXInitializer(initializer) - GV.OXINITIALIZER_DICT[initializer_name] = oxinitializer - - return oxinitializer - - def remove_initializer(self, initializer_name: str) -> OXInitializer: - ''' - 从模型中删除指定的initializer - - Args: - initializer_name: initializer的名字 - - Returns: 删除的OXInitializer - ''' - - oxinitializer = self.get_oxinitializer_by_name(initializer_name) - GV.OXINITIALIZER_DICT.pop(initializer_name) - self._initializer.remove(oxinitializer.get_initializer()) - - return oxinitializer - - # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Node相关函数 - def get_oxnode_by_name(self, oxnode_name: str, can_return_none: bool = False) -> OXNode: - ''' - 根据节点名字获取OXNode - ''' - - if oxnode_name not in GV.OXNODE_DICT: - if can_return_none is True: - return None - else: - raise RuntimeError('[ERROR] {} not found.'.format(oxnode_name)) - return GV.OXNODE_DICT[oxnode_name] - - def get_oxnode_by_op_type(self, op_type: str) -> List[OXNode]: - ''' - 根据节点类型获取OXNode - ''' - - res = set() - for oxnode in GV.OXNODE_DICT.values(): - if oxnode.get_op_type() == op_type: - res.add(oxnode) - return list(res) - - def get_oxnode_whose_input_contain_this(self, input_name: str) -> List[OXNode]: - ''' - 遍历所有OXNode,获取输入包含`input_name`的那些OXNode - ''' - - res = set() - for oxnode in GV.OXNODE_DICT.values(): - for oxinput_name in oxnode.input: - if oxinput_name == input_name: - res.add(oxnode) - break - return list(res) - - def get_oxnode_whose_output_contain_this(self, output_name: str) -> List[OXNode]: - ''' - 遍历所有OXNode,获取输出包含`output_name`的那些OXNode - ''' - - res = set() - for oxnode in GV.OXNODE_DICT.values(): - for oxoutput_name in oxnode.output: - if oxoutput_name == output_name: - res.add(oxnode) - break - return list(res) - - def get_previous_oxnode(self, oxnode_name: str) -> List[OXNode]: - ''' - 获取一个节点的前驱节点 - ''' - - res = set() - inputs = self.get_oxnode_by_name(oxnode_name).input - for input in inputs: - oxnode_set = self._output_tensor_2_oxnode_dict.get(input) - if oxnode_set is not None: - res.update(oxnode_set) - return list(res) - - def get_next_oxnode(self, oxnode_name: str) -> List[OXNode]: - ''' - 获取一个节点的后继节点 - ''' - - res = set() - outputs = self.get_oxnode_by_name(oxnode_name).output - for output in outputs: - oxnode_set = self._input_tensor_2_oxnode_dict.get(output) - if oxnode_set is not None: - res.update(oxnode_set) - return list(res) - - def insert_node(self, bef_node_info_list: List[Dict], aft_node_info_list: List[Dict], op_type: str, op_name: str, - **attributes: Dict) -> OXNode: - ''' - 向模型中插入新节点,并自动连边,注意和`add_node`的区别 - - 限制:无法涵盖所有场景,若结果不符合预期,请用`add_node`函数,并手动指定连边关系。 - - Args: - bef_node_info_list:参见README.md用例 - aft_node_info_list:参见README.md用例 - op_type:节点的类型 - op_name:节点的名字 - attributes:节点的属性 - - Returns: 插入的OXNode - ''' - - # 校验插入的节点是否已经存在 - if op_name in GV.OXNODE_DICT: - raise RuntimeError( - '[ERROR] {} has already exists in the model, please use a different name!'.format(op_name)) - - # 解析信息 - bef_node_info_list, aft_node_info_list = self._parse_insert_node_info(bef_node_info_list, aft_node_info_list) - - # 插入节点 - # + 构造新节点的输入 - new_node_input = [] - for bef_node_info in bef_node_info_list: - oxnode = self.get_oxnode_by_name(bef_node_info['bef_node_name'], True) - if oxnode is None: # 说明此节点是模型的输入节点 - new_node_input.append(bef_node_info['bef_node_name']) - else: - for idx in bef_node_info['link_output_idx']: - if oxnode.output[idx] in self.get_output_tensor_info().keys(): # 说明此节点紧接模型的输出节点 - oxnode.output[idx] = oxnode.get_name() + '_m_' + str(idx) - new_node_input.append(oxnode.output[idx]) - - # + 构造新节点的输出 - new_node_output = [op_name + '_0'] - - # + 构造新节点 - insert_oxnode = self.add_node(op_type=op_type, - op_name=op_name, - inputs=new_node_input, - outputs=new_node_output, - **attributes) - - # 和后继节点连边 - for aft_node_info in aft_node_info_list: - oxnode = self.get_oxnode_by_name(aft_node_info['aft_node_name'], True) - if oxnode is None: # 说明此节点是模型的输出节点 - if len(aft_node_info_list) != 1: - raise RuntimeError('[ERROR] Please check aft_node_info_list!') - - # 修改insert_oxnode的输出为模型的输出节点 - insert_oxnode.output[0] = aft_node_info['aft_node_name'] - else: - for idx in aft_node_info['link_input_idx']: - oxnode.input[idx] = new_node_output[0] - - # 更新tensor_2_oxnode字典 - self._update_tensor_2_oxnode_dict( - self._input_tensor_2_oxnode_dict, - self._output_tensor_2_oxnode_dict, - ) - - return insert_oxnode - - def add_node(self, op_type: str, op_name: str, inputs: List[str], outputs: List[str], **attributes: Dict) -> OXNode: - ''' - 向模型中增加新节点,不会自动连边,注意和`insert_node`的区别 - - Args: - op_type:节点的类型 - op_name:节点的名字 - inputs:节点的输入 - outputs:节点的输出 - attributes:节点的属性 - - Returns: 新增的OXNode - ''' - - if op_name in GV.OXNODE_DICT: - raise RuntimeError( - '[ERROR] {} has already exists in the model, please use a different name!'.format(op_name)) - - new_node = make_node(op_type=op_type, name=op_name, inputs=inputs, outputs=outputs, **attributes) - self._node.append(new_node) # 这里复制,而不是用引用,id已经变了 - new_node = self._node[-1] - new_oxnode = OXNode(new_node) - GV.OXNODE_DICT[new_oxnode.get_name()] = new_oxnode - - # 更新tensor_2_oxnode字典 - self._update_tensor_2_oxnode_dict( - self._input_tensor_2_oxnode_dict, - self._output_tensor_2_oxnode_dict, - ) - - return new_oxnode - - def remove_node(self, node_name: str, auto_link: bool = True) -> OXNode: - ''' - 从模型中删除节点 - - 限制:若开启自动连边,则删除的节点必须只有一个前驱节点,否则需要手动连边。若结果不符合预期,也需要自己手动连边。 - - Args: - node_name:要删除的节点名字 - auto_link:是否自动连边 - - Returns: 删除的OXNode - ''' - - if node_name not in GV.OXNODE_DICT: - raise RuntimeError('[ERROR] {} not found.'.format(node_name)) - - if auto_link is False: - oxnode = self.get_oxnode_by_name(node_name) - else: - oxnode = self.get_oxnode_by_name(node_name) - previous_node = self.get_previous_oxnode(node_name) - next_node = self.get_next_oxnode(node_name) - - if len(previous_node) > 1: - raise RuntimeError('[ERROR] Remove node can only have one previous node.') - - _clear_list(previous_node[0].output) - _extend_list(previous_node[0].output, oxnode.output) - - # 删除节点 - GV.OXNODE_DICT.pop(node_name) - self._node.remove(oxnode.get_node()) - - # 更新tensor_2_oxnode字典 - self._update_tensor_2_oxnode_dict( - self._input_tensor_2_oxnode_dict, - self._output_tensor_2_oxnode_dict, - ) - - return oxnode - - # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 输入输出相关函数 - def get_input_tensor_info(self) -> Dict: - ''' - 获取模型输入tensor的信息 - 信息包括:tensor名字、shape、类型 - - Returns: {'tensor_name': {'shape': np.shape, 'dtype': np.dtype}, ...} - ''' - - session = onnxruntime.InferenceSession(self._model_path) - - input_tensor_info = {} - for input_item in session.get_inputs(): - input_tensor_info[input_item.name] = { - 'shape': tuple(input_item.shape), - 'dtype': GV.ONNX_2_NUMPY_DATATYPE_DICT[input_item.type] - } - - return input_tensor_info - - def get_output_tensor_info(self) -> Dict: - ''' - 获取模型输出tensor的信息 - 信息包括:tensor名字、shape、类型 - - Returns: {'tensor_name': {'shape': np.shape, 'dtype': np.dtype}, ...} - ''' - - session = onnxruntime.InferenceSession(self._model_path) - - output_tensor_info = {} - for output_item in session.get_outputs(): - output_tensor_info[output_item.name] = { - 'shape': tuple(output_item.shape), - 'dtype': GV.ONNX_2_NUMPY_DATATYPE_DICT[output_item.type] - } - - return output_tensor_info - - def get_all_tensor_info(self) -> Dict: - ''' - 获取模型中所有tensor的信息 - 所有tensor包括:模型输入tensor、模型输出tensor、模型中间tensor - 信息包括:tensor名字、shape、类型 - - Returns: {'tensor_name': {'shape': np.shape, 'dtype': np.dtype}, ...} - ''' - - old_onnx_model = onnx.load(self._model_path) - - output_name = [] - for name in enumerate_model_node_outputs(old_onnx_model): - output_name.append(name) - - new_onnx_model = select_model_inputs_outputs(old_onnx_model, output_name) - new_model_path = os.path.join(os.path.dirname(self._model_path), 'temp.onnx') - save_onnx_model(new_onnx_model, new_model_path) - - session = onnxruntime.InferenceSession(new_model_path) - os.remove(new_model_path) - - all_tensor_info = {} - - for input_item in session.get_inputs(): - all_tensor_info[input_item.name] = { - 'shape': tuple(input_item.shape), - 'dtype': GV.ONNX_2_NUMPY_DATATYPE_DICT[input_item.type] - } - - for output_item in session.get_outputs(): - all_tensor_info[output_item.name] = { - 'shape': tuple(output_item.shape), - 'dtype': GV.ONNX_2_NUMPY_DATATYPE_DICT[output_item.type] - } - - for oxinitializer in GV.OXINITIALIZER_DICT.values(): - all_tensor_info[oxinitializer.get_name()] = { - 'shape': oxinitializer.get_data().shape, - 'dtype': eval('np.' + str(oxinitializer.get_data().dtype)) - } - - return all_tensor_info - - def infer_shape(self, input_data_info_list: List[Dict]) -> Dict: - ''' - 推导模型各个算子的输出shape信息。 - - 用途:有些模型从onnx图中无法看出算子输出shape信息,也无法获取shape信息,通过此函数可以推导出shape信息。 - - 原理:用真实数据运行一遍模型,记录各个算子的输出shape信息。 - - Args: - input_data_info_list: - [ - { - 'model_input_name': 'input1_name', - 'shape': '(1, 3, 224, 224)', - 'dtype': 'np.float32' - }, - { - 'model_input_name': 'input2_name', - 'shape': '(1, 3, 224, 224)', - 'dtype': 'np.float32' - } - ] - - Returns: {'op_name': {'shape': np.shape, 'dtype': np.dtype}, ...} - ''' - - # 构造输入数据 - input_data_dict = {} - for input_data_info in input_data_info_list: - input_data_dict[input_data_info['model_input_name']] = np.full(eval(input_data_info['shape']), - 1, - dtype=eval(input_data_info['dtype'])) - - # 修改模型,增加输出节点 - old_onnx_model = onnx.load(self._model_path) - output = [] - for out in enumerate_model_node_outputs(old_onnx_model): - output.append(out) - new_onnx_model = select_model_inputs_outputs(old_onnx_model, outputs=output) - onnx_save_path = './temp.onnx' - save_onnx_model(new_onnx_model, onnx_save_path) - - # 推理得到输出 - sess = onnxruntime.InferenceSession(onnx_save_path) - os.remove(onnx_save_path) - output_name = [node.name for node in sess.get_outputs()] - res = sess.run(output_name, input_data_dict) - - # 保存数据 - infer_tensor_info = {} - idx = 0 - for node in old_onnx_model.graph.node: - for i in range(len(node.output)): - infer_tensor_info[node.name] = {'output_idx': i, 'shape': res[idx].shape, 'dtype': res[idx].dtype} - idx += 1 - - return infer_tensor_info - - def dump_all_node_data(self, input_data_info_list: List[Dict], dump_data_save_path: str) -> NoReturn: - ''' - dump模型所有节点的数据 - - Args: - input_data_info_list: - [ - { - 'model_input_name': 'input1_name', - 'npy_file_path': './0.npy', - }, - { - 'model_input_name': 'input2_name', - 'npy_file_path': './1.npy', - }, - ] - dump_data_save_path: e.g. './dump_data' - - Returns: NoReturn - ''' - - # 创建目录 - if os.path.exists(dump_data_save_path): - shutil.rmtree(dump_data_save_path) - os.makedirs(dump_data_save_path) - - # 修改模型,增加输出节点 - old_onnx_model = onnx.load(self._model_path) - output = [] - for out in enumerate_model_node_outputs(old_onnx_model): - output.append(out) - new_onnx_model = select_model_inputs_outputs(old_onnx_model, outputs=output) - onnx_save_path = os.path.join(dump_data_save_path, "./temp.onnx") - save_onnx_model(new_onnx_model, onnx_save_path) - - # 获取输入数据 - input_data_dict = {} - for input_data_info in input_data_info_list: - input_data_dict[input_data_info['model_input_name']] = np.load(input_data_info['npy_file_path']) - - # 推理得到输出 - sess = onnxruntime.InferenceSession(onnx_save_path) - os.remove(onnx_save_path) - output_name = [node.name for node in sess.get_outputs()] - res = sess.run(output_name, input_data_dict) - - # 保存数据 - idx = 0 - for node in old_onnx_model.graph.node: - for i in range(len(node.output)): - file_name = node.name + "." + str(i) + "." + str(round(time.time() * 1000000)) + ".npy" - data_save_path = os.path.join(dump_data_save_path, file_name) - np.save(data_save_path, res[idx]) - idx += 1 - - # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 截图函数 - def extract_model(self, input_tensor_name_list: List[str], output_tensor_name_list: List[str], - new_model_save_path: str) -> NoReturn: - ''' - 从onnx 1.8.1开始,onnx官方提供了截图函数,此函数是对官方`onnx.utils.extract_model`函数的封装, - 以使其集成到`OXGraph`类中。另外,此函数屏蔽了`check_model`操作,使包含自定义算子的onnx提取子图后 - 在保存模型时跳过检查操作,使之可以顺利保存。以下是官方`onnx.utils.extract_model`函数的说明: - - Extracts sub-model from an ONNX model. - - The sub-model is defined by the names of the input and output tensors *exactly*. - - Note: For control-flow operators, e.g. If and Loop, the _boundary of sub-model_, - which is defined by the input and output tensors, should not _cut through_ the - subgraph that is connected to the _main graph_ as attributes of these operators. - - Arguments: - input_path (string): The path to original ONNX model. - output_path (string): The path to save the extracted ONNX model. - input_names (list of string): The names of the input tensors that to be extracted. - output_names (list of string): The names of the output tensors that to be extracted. - ''' - - print('[INFO] Begin to extract the model.') - start_time = datetime.now() - onnx.utils.extract_model(self._model_path, new_model_save_path, input_tensor_name_list, output_tensor_name_list) - end_time = datetime.now() - cost_time = (end_time - start_time).seconds - print('[INFO] Extract model completed! Cost {} seconds.'.format(cost_time)) - - def trunc_model(self, - trunc_beg_node_name_list: List[str], - trunc_end_node_name_list: List[str], - new_model_save_path: str, - keep_input_initializer: bool = False, - userdef_trunc_beg_node_info_list: List[Dict] = None) -> NoReturn: - ''' - 截取一段模型 - - 用途:可以用来单独验证某段网络的精度 - - 注意: - 从onnx 1.8.1开始,onnx官方提供了截图函数,若onnx版本>=1.8.1,请使用`extract_model`函数。 - `extract_model`函数是对官方`onnx.utils.extract_model`函数的封装,以使其集成到`OXGraph`类中。 - 此`trunc_model`函数是自己写的,功能可能有缺陷,但截图速度一般来说更快,模型较大时可以对比尝试。 - ''' - - print('[WARNING] 从onnx 1.8.1开始,onnx官方提供了截图函数,若onnx版本>=1.8.1,请使用`extract_model`函数。' - '`extract_model`函数是对官方`onnx.utils.extract_model`函数的封装,以使其集成到`OXGraph`类中。' - '此`trunc_model`函数是自己写的,功能可能有缺陷,但截图速度一般来说更快,模型较大时可以对比尝试。') - - print('[INFO] Begin to truncate the model.') - start_time = datetime.now() - - # 修改输出节点 - new_output = [] - for elem in trunc_end_node_name_list: - output = self.get_oxnode_by_name(elem).output - new_output.extend(x for x in output) - new_onnx = select_model_inputs_outputs(self._model, outputs=new_output) - save_onnx_model(new_onnx, new_model_save_path) - - # 加载模型 - model = onnx.load_model(new_model_save_path) - graph = model.graph - nodes = graph.node - initializers = graph.initializer - - # 搜索节点 - def find_trunc_beg_node(node_name): - is_find = False - for node in nodes: - if node.name == node_name: - trunc_beg_node = node - is_find = True - break - if is_find is True: - return trunc_beg_node - else: - raise RuntimeError('[ERROR] {} not found.'.format(node_name)) - - # 获取trunc_beg_node详细信息,构造一个这样的list: - ''' - [ - { - 'trunc_beg_node': node, - 'new_input_info_list': [ - { - 'input_name': 'input_A', - 'dtype': OXDataType.float32, - 'shape': (1, 256, 56, 56), - 'input_idx': 0 - }, - { - 'input_name': 'input_B', - 'dtype': OXDataType.float32, - 'shape': (1, 256, 56, 56), - 'input_idx': 1 - } - ] - } - ] - ''' - if userdef_trunc_beg_node_info_list is None: - trunc_beg_node_info_list = [] - initializer_name_set = set() - initializer_name_set.update([oxinitializer.get_name() for oxinitializer in GV.OXINITIALIZER_DICT.values()]) - count = 0 - for trunc_beg_node_name in trunc_beg_node_name_list: - trunc_beg_node = find_trunc_beg_node(trunc_beg_node_name) - new_input_info_list = [] - for idx, input in enumerate(trunc_beg_node.input): - if (keep_input_initializer is True) and (input in initializer_name_set): - continue - else: - new_input_info = {} - new_input_info['input_name'] = 'new_input_' + str(count) - count += 1 - new_input_info['dtype'] = GV.ONNX_2_NUMPY_DATATYPE_DICT[self._all_tensor_info[input]['dtype']] - new_input_info['shape'] = self._all_tensor_info[input]['shape'] - new_input_info['input_idx'] = idx - new_input_info_list.append(new_input_info) - trunc_beg_node_info = {} - trunc_beg_node_info['trunc_beg_node'] = trunc_beg_node - trunc_beg_node_info['new_input_info_list'] = new_input_info_list - trunc_beg_node_info_list.append(trunc_beg_node_info) - else: - trunc_beg_node_info_list = userdef_trunc_beg_node_info_list - - # 构造新输入 - new_inputs = [] - for trunc_beg_node_info in trunc_beg_node_info_list: - if userdef_trunc_beg_node_info_list is None: - trunc_begin_node = trunc_beg_node_info['trunc_beg_node'] - else: - trunc_begin_node = find_trunc_beg_node(trunc_beg_node_info['trunc_beg_node_name']) - for new_input_info in trunc_beg_node_info['new_input_info_list']: - new_input = self._make_new_input(new_input_info['input_name'], new_input_info['dtype'], - new_input_info['shape']) - new_inputs.append(new_input) - trunc_begin_node.input[new_input_info['input_idx']] = new_input_info['input_name'] - - # 查找有用节点 - useful_node_name_set = set() - useful_node_name_set.update(trunc_beg_node_name_list) - useful_node_name_set.update(trunc_end_node_name_list) - - # + 正向查找 - @lru_cache() - def find_useful_node(next_node_name_tuple): - for next_node_name in next_node_name_tuple: - if next_node_name not in trunc_end_node_name_list: - output_oxnode_list = self.get_next_oxnode(next_node_name) - output_oxnode_name_tuple = tuple([oxnode.get_name() for oxnode in output_oxnode_list]) - useful_node_name_set.update(output_oxnode_name_tuple) - find_useful_node(output_oxnode_name_tuple) - - # + 反向查找 - @lru_cache() - def find_useful_node_reverse(next_node_name_tuple): - for next_node_name in next_node_name_tuple: - if next_node_name not in trunc_beg_node_name_list: - input_oxnode_list = self.get_previous_oxnode(next_node_name) - input_oxnode_name_tuple = tuple([oxnode.get_name() for oxnode in input_oxnode_list]) - useful_node_name_set.update(input_oxnode_name_tuple) - find_useful_node_reverse(input_oxnode_name_tuple) - - # + 正向和反向都查找一遍,防止漏查 - find_useful_node(tuple(trunc_beg_node_name_list)) - find_useful_node_reverse(tuple(trunc_end_node_name_list)) - - # 删除多余节点 - for node in copy.deepcopy(nodes): - if node.name not in useful_node_name_set: - nodes.remove(node) - - # 删除多余输入 - _clear_list(graph.input) - _extend_list(graph.input, new_inputs) - - # 删除多余Initializer - all_input = set() - for node in nodes: - all_input.update(node.input) - for initializer in copy.deepcopy(initializers): - if initializer.name not in all_input: - initializers.remove(initializer) - - # 保存模型 - name = 'Extracted from {' + self._graph.name + '}' - graph = make_graph(nodes, - name, - graph.input, - graph.output, - initializer=initializers, - value_info=graph.value_info) - meta = { - 'ir_version': self._model.ir_version, - 'opset_imports': self._model.opset_import, - 'producer_name': 'OXGraph.trunc_model()', - } - new_mode = make_model(graph, **meta) - onnx.save(new_mode, new_model_save_path) - end_time = datetime.now() - cost_time = (end_time - start_time).seconds - print('[INFO] Truncate model completed! Cost {} seconds.'.format(cost_time)) - - # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 保存模型 - def save_new_model(self, new_model_path) -> NoReturn: - ''' - 保存修改后的模型 - ''' - - onnx.save_model(self._model, new_model_path) - - # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 私有函数 - def _update_tensor_2_oxnode_dict(self, input_tensor_2_oxnode_dict, output_tensor_2_oxnode_dict) -> NoReturn: - # 清空字典 - input_tensor_2_oxnode_dict.clear() - output_tensor_2_oxnode_dict.clear() - - # 创建字典 - for oxnode in GV.OXNODE_DICT.values(): - inputs = oxnode.input - outputs = oxnode.output - for input in inputs: - input_tensor_2_oxnode_dict.setdefault(input, set()).add(oxnode) - for output in outputs: - output_tensor_2_oxnode_dict.setdefault(output, set()).add(oxnode) - - def _make_new_input(self, new_input_name: str, ox_data_type: OXDataType, shape: tuple) -> ValueInfoProto: - ''' - If you print the model input in the terminal, you will get something like this, and you can modify it directly. - `dim_param` means dynamic shape. - [name: 'image' - type { - tensor_type { - elem_type: 1 - shape { - dim { - dim_param: '-1' - } - dim { - dim_value: 3 - } - dim { - dim_value: 224 - } - dim { - dim_value: 224 - } - } - } - } - ] - ''' - - new_input = copy.deepcopy(self._graph.input[0]) - new_input.name = new_input_name - new_input.type.tensor_type.elem_type = int(ox_data_type) - - dim_diff = len(shape) - len(new_input.type.tensor_type.shape.dim) - if dim_diff > 0: - for i in range(dim_diff): - new_input.type.tensor_type.shape.dim.append(copy.deepcopy(new_input.type.tensor_type.shape.dim[0])) - elif dim_diff < 0: - for i in range(abs(dim_diff)): - new_input.type.tensor_type.shape.dim.pop() - - for index in range(len(shape)): - if isinstance(shape[index], str): - new_input.type.tensor_type.shape.dim[index].dim_param = shape[index] - elif shape[index] is None: - new_input.type.tensor_type.shape.dim[index].dim_param = '-1' - print('[WARNING] Can not infer tensor shape, set it to "-1" here, which may cause an error! ' - 'Please specify `userdef_trunc_beg_node_info_list` parameters and retry.') - else: - new_input.type.tensor_type.shape.dim[index].dim_value = shape[index] - - return new_input - - def _parse_insert_node_info(self, bef_node_info_list, aft_node_info_list): - ''' - parse bef_node_info_list = ['Relu_1:0'] and aft_node_info_list = ['MaxPool_2:0'] into: - - bef_node_info_list=[{ - 'bef_node_name': 'Relu_1', - 'link_output_idx': [0] - }] - - aft_node_info_list=[{ - 'aft_node_name': 'MaxPool_2', - 'link_input_idx': [0] - }] - - 默认的`:0`可以省略 - ''' - - # 变量定义 - new_bef_node_info_list = [] - new_aft_node_info_list = [] - - # 解析bef_node_info_list - for bef_node_info in bef_node_info_list: - bef_node_info_dict = {} - info_list = bef_node_info.split(':') - bef_node_info_dict['bef_node_name'] = info_list[0] - if len(info_list) == 1: - bef_node_info_dict['link_output_idx'] = [0] - else: - bef_node_info_dict['link_output_idx'] = [int(elem) for idx, elem in enumerate(info_list) if idx > 0] - new_bef_node_info_list.append(bef_node_info_dict) - - # 解析aft_node_info_list - for aft_node_info in aft_node_info_list: - aft_node_info_dict = {} - info_list = aft_node_info.split(':') - aft_node_info_dict['aft_node_name'] = info_list[0] - if len(info_list) == 1: - aft_node_info_dict['link_input_idx'] = [0] - else: - aft_node_info_dict['link_input_idx'] = [int(elem) for idx, elem in enumerate(info_list) if idx > 0] - new_aft_node_info_list.append(aft_node_info_dict) - - return new_bef_node_info_list, new_aft_node_info_list - - -# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 公共函数 -def _clear_list(list) -> NoReturn: - ''' - 清空RepeatedScalarContainer或RepeatedCompositeContainer列表 - ''' - - list_len = len(list) - for _ in range(list_len): - list.pop() - - -def _extend_list(list, what_to_add) -> NoReturn: - ''' - 扩展RepeatedScalarContainer或RepeatedCompositeContainer列表 - ''' - - for elem in what_to_add: - list.append(elem) +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ + +''' +环境: + python==3.8.5 + onnx==1.8.1 + onnxruntime==1.7.0 + skl2onnx==1.8.0 + numpy==1.19.5 +''' + +import os +import sys +import onnx +import copy +import time +import shutil +import numpy as np +import onnxruntime + +from enum import IntEnum +from onnx import NodeProto +from datetime import datetime +from functools import lru_cache +from typing import List, Dict, Any, NoReturn +from onnx.numpy_helper import from_array, to_array +from onnx.onnx_ml_pb2 import TensorProto, ValueInfoProto, AttributeProto +from onnx.helper import make_attribute, make_node, make_graph, make_model +from skl2onnx.helpers.onnx_helper import enumerate_model_node_outputs, select_model_inputs_outputs, save_onnx_model + +# 修改递归深度限制 +sys.setrecursionlimit(100000) + + +# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> enum OXDataType +# onnx类型枚举值 +class OXDataType(IntEnum): + float32 = 1 + uint8 = 2 + int8 = 3 + uint16 = 4 + int16 = 5 + int32 = 6 + int64 = 7 + string = 8 + bool = 9 + float16 = 10 + double = 11 + uint32 = 12 + uint64 = 13 + complex64 = 14 + complex128 = 15 + bfloat16 = 16 + + +# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> calss GV +# 全局变量,GV = global variable +class GV: + # onnx和numpy数据类型映射字典 + ONNX_2_NUMPY_DATATYPE_DICT = { + 1: np.float32, + 2: np.uint8, + 3: np.int8, + 4: np.uint16, + 5: np.int16, + 6: np.int32, + 7: np.int64, + 9: np.bool_, + 10: np.float16, + 11: np.float64, + 12: np.uint32, + 13: np.uint64, + 14: np.complex64, + 15: np.complex128, + np.float32: 1, + np.uint8: 2, + np.int8: 3, + np.uint16: 4, + np.int16: 5, + np.int32: 6, + np.int64: 7, + np.bool_: 9, + np.float16: 10, + np.float64: 11, + np.uint32: 12, + np.uint64: 13, + np.complex64: 14, + np.complex128: 15, + 'tensor(float)': np.float32, + 'tensor(uint8)': np.uint8, + 'tensor(int8)': np.int8, + 'tensor(uint16)': np.uint16, + 'tensor(int16)': np.int16, + 'tensor(int32)': np.int32, + 'tensor(int64)': np.int64, + 'tensor(bool)': np.bool_, + 'tensor(float16)': np.float16, + 'tensor(double)': np.float64, + 'tensor(uint32)': np.uint32, + 'tensor(uint64)': np.uint64, + } + + # initializer,node索引字典(实现快速查找) + OXINITIALIZER_DICT = {} + OXNODE_DICT = {} + + +# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> calss OXInitializer +class OXInitializer: + ''' + If you print a Initializer variable in the terminal, you will get something like this, and you can modify it + directly. + dims: 1 + data_type: 6 + name: '4239' + raw_data: '\000\000\000\00' + + @dims: google.protobuf.pyext._message.RepeatedScalarContainer + @data_type: int + @name: str + @raw_data: bytes + ''' + + def __init__(self, initializer: TensorProto): + self._initializer = initializer + + def __str__(self): + ndarray = to_array(self._initializer) + msg = 'name: ' + str(self._initializer.name) + '\n' + \ + 'dims: ' + str(self._initializer.dims) + '\n' + \ + 'data_type: ' + str(self._initializer.data_type) + '\n' + \ + 'dtype: ' + str(ndarray.dtype) + '\n' + \ + 'shape: ' + str(ndarray.shape) + '\n' + \ + 'ndarray:\n' + str(ndarray) + return msg + + def get_initializer(self) -> TensorProto: + return self._initializer + + def get_name(self) -> str: + ''' + 获取initializer的名字 + ''' + + return self._initializer.name + + def set_name(self, new_name) -> NoReturn: + ''' + 设置/修改initializer的名字 + ''' + + old_name = self._initializer.name + self._initializer.name = new_name + GV.OXINITIALIZER_DICT[new_name] = GV.OXINITIALIZER_DICT[old_name] + GV.OXINITIALIZER_DICT.pop(old_name) + + def get_data_type(self) -> int: + ''' + 获取initializer的数据类型 + ''' + + return self._initializer.data_type + + def set_data_type(self, ox_data_type: OXDataType) -> NoReturn: + ''' + 设置/修改initializer的数据类型 + ''' + + ndarray = to_array(self._initializer).astype(GV.ONNX_2_NUMPY_DATATYPE_DICT[int(ox_data_type)]) + self._initializer.raw_data = ndarray.tobytes() + self._initializer.data_type = int(ox_data_type) + + def get_data(self) -> np.ndarray: + ''' + 获取initializer的数据 + ''' + + return to_array(self._initializer) + + def set_data(self, ndarray: np.ndarray) -> NoReturn: + ''' + 设置/修改initializer的数据 + ''' + + self._initializer.raw_data = ndarray.tobytes() + self._initializer.data_type = GV.ONNX_2_NUMPY_DATATYPE_DICT[eval('np.' + str(ndarray.dtype))] + _clear_list(self._initializer.dims) + _extend_list(self._initializer.dims, ndarray.shape) + + def save_data(self, file_path: str) -> NoReturn: + ''' + 保存initializer的数据 + ''' + + np.save(file_path, to_array(self._initializer)) + + +# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> calss OXNode +class OXNode: + ''' + If you print a NodeProto variable in the terminal, you will get something like this, and you can modify it directly. + input: '494' + input: 'fc.weight' + input: 'fc.bias' + output: 'class' + name: 'Gemm_121' + op_type: 'Gemm' + attribute { + name: 'alpha' + f: 1.0 + type: FLOAT + } + attribute { + name: 'beta' + f: 1.0 + type: FLOAT + } + attribute { + name: 'transB' + i: 1 + type: INT + } + + @input: google.protobuf.pyext._message.RepeatedScalarContainer + @output: google.protobuf.pyext._message.RepeatedScalarContainer + @name: str + @op_type: str + @attribute: google.protobuf.pyext._message.RepeatedCompositeContainer + ''' + + def __init__(self, node: NodeProto): + self._node = node + + def __str__(self): + return str(self._node) + + def get_node(self) -> NodeProto: + return self._node + + @property + def input(self): # -> google.protobuf.pyext._message.RepeatedScalarContainer + ''' + 获取节点的输入列表 + ''' + + return self._node.input + + @property + def output(self): # -> google.protobuf.pyext._message.RepeatedScalarContainer + ''' + 获取节点的输出列表 + ''' + + return self._node.output + + def get_name(self) -> str: + ''' + 获取节点的名字 + ''' + + return self._node.name + + def set_name(self, new_name) -> NoReturn: + ''' + 设置/修改节点的名字 + ''' + + old_name = self._node.name + self._node.name = new_name + GV.OXNODE_DICT[new_name] = GV.OXNODE_DICT[old_name] + GV.OXNODE_DICT.pop(old_name) + + def get_op_type(self) -> int: + ''' + 获取节点的类型 + ''' + + return self._node.op_type + + def set_op_type(self, op_type) -> NoReturn: + ''' + 设置/修改节点的类型 + ''' + + self._node.op_type = op_type + + def get_attribute(self): # -> google.protobuf.pyext._message.RepeatedCompositeContainer + ''' + 获取节点属性 + ''' + + return self._node.attribute + + def set_attribute(self, attr_name: str, attr_value: Any) -> AttributeProto: + ''' + 设置/修改节点属性 + + Args: + attr_name: 属性名字 + attr_value: 属性值 + + Returns: 修改后的属性 + ''' + + # 构造新attr + new_attr = make_attribute(attr_name, attr_value) + + # 删除旧的 + for attr in self._node.attribute: + if attr.name == attr_name: + self._node.attribute.remove(attr) + break + + # 添加新的 + self._node.attribute.append(new_attr) + + return new_attr + + def add_attribute(self, attr_name: str, attr_value: Any) -> AttributeProto: + ''' + 给节点增加新属性 + + Args: + attr_name: 属性名字 + attr_value: 属性值 + + Returns: 新增的属性 + ''' + + # 构造新attr + new_attr = make_attribute(attr_name, attr_value) + + # 增加 + self._node.attribute.append(new_attr) + + return new_attr + + def remove_attribute(self, attr_name: str) -> AttributeProto: + ''' + 删除节点的某个属性 + + Args: + attr_name: 属性名字 + attr_value: 属性值 + + Returns: 被删除的属性 + ''' + + for attr in self._node.attribute: + if attr.name == attr_name: + removed_attr = attr + self._node.attribute.remove(attr) + break + + return removed_attr + + +# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> calss OXGraph +class OXGraph: + def __init__(self, model_path: str): + print('[INFO] Start initializing.') + start_time = datetime.now() + + self._model_path = model_path + self._model = onnx.load_model(model_path) + self._graph = self._model.graph + self._initializer = self._graph.initializer + self._node = self._graph.node + self._input_tensor_2_oxnode_dict = {} + self._output_tensor_2_oxnode_dict = {} + + # initializer + for initializer in self._initializer: + GV.OXINITIALIZER_DICT[initializer.name] = OXInitializer(initializer) + + # node + for idx, node in enumerate(self._node): + oxnode = OXNode(node) + GV.OXNODE_DICT[node.name] = oxnode + + # 创建tensor_2_oxnode字典 + self._update_tensor_2_oxnode_dict( + self._input_tensor_2_oxnode_dict, + self._output_tensor_2_oxnode_dict, + ) + + # 获取所有tensor信息 + try: + self._all_tensor_info = self.get_all_tensor_info() + except: + os.remove(os.path.join(os.path.dirname(self._model_path), 'temp.onnx')) + print('[WARNING] There are custom operators in the model, ' + 'and these functions are not available: get_input_tensor_info()、get_output_tensor_info()、' + 'get_all_tensor_info()、infer_shape()、dump_all_node_data()、trunc_model().') + + # 屏蔽check_model + def check_model(model): + pass + + onnx.checker.check_model = check_model + + end_time = datetime.now() + cost_time = (end_time - start_time).seconds + print('[INFO] Initialization completed! Cost {} seconds.'.format(cost_time)) + + def __str__(self): + return str(self._model) + + # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Initializer相关函数 + def get_oxinitializer_by_name(self, oxinitializer_name: str, can_return_none: bool = False) -> OXInitializer: + ''' + 根据initializer的名字获取OXInitializer + ''' + + if oxinitializer_name not in GV.OXINITIALIZER_DICT: + if can_return_none is True: + return None + else: + raise RuntimeError('[ERROR] {} not found.'.format(oxinitializer_name)) + return GV.OXINITIALIZER_DICT[oxinitializer_name] + + def add_initializer(self, initializer_name: str, ndarray: np.ndarray) -> OXInitializer: + ''' + 向模型中新增一个initializer + + Args: + initializer_name: initializer的名字 + ndarray: initializer的数据 + + Returns: 新增的OXInitializer + ''' + + if initializer_name in GV.OXINITIALIZER_DICT: + raise RuntimeError( + '[ERROR] {} has already exists in the model, please use a different name!'.format(initializer_name)) + + initializer = from_array(ndarray, initializer_name) + self._initializer.append(initializer) # 这里是复制,而不是引用,id已经变了 + initializer = self._initializer[-1] + oxinitializer = OXInitializer(initializer) + GV.OXINITIALIZER_DICT[initializer_name] = oxinitializer + + return oxinitializer + + def remove_initializer(self, initializer_name: str) -> OXInitializer: + ''' + 从模型中删除指定的initializer + + Args: + initializer_name: initializer的名字 + + Returns: 删除的OXInitializer + ''' + + oxinitializer = self.get_oxinitializer_by_name(initializer_name) + GV.OXINITIALIZER_DICT.pop(initializer_name) + self._initializer.remove(oxinitializer.get_initializer()) + + return oxinitializer + + # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Node相关函数 + def get_oxnode_by_name(self, oxnode_name: str, can_return_none: bool = False) -> OXNode: + ''' + 根据节点名字获取OXNode + ''' + + if oxnode_name not in GV.OXNODE_DICT: + if can_return_none is True: + return None + else: + raise RuntimeError('[ERROR] {} not found.'.format(oxnode_name)) + return GV.OXNODE_DICT[oxnode_name] + + def get_oxnode_by_op_type(self, op_type: str) -> List[OXNode]: + ''' + 根据节点类型获取OXNode + ''' + + res = set() + for oxnode in GV.OXNODE_DICT.values(): + if oxnode.get_op_type() == op_type: + res.add(oxnode) + return list(res) + + def get_oxnode_whose_input_contain_this(self, input_name: str) -> List[OXNode]: + ''' + 遍历所有OXNode,获取输入包含`input_name`的那些OXNode + ''' + + res = set() + for oxnode in GV.OXNODE_DICT.values(): + for oxinput_name in oxnode.input: + if oxinput_name == input_name: + res.add(oxnode) + break + return list(res) + + def get_oxnode_whose_output_contain_this(self, output_name: str) -> List[OXNode]: + ''' + 遍历所有OXNode,获取输出包含`output_name`的那些OXNode + ''' + + res = set() + for oxnode in GV.OXNODE_DICT.values(): + for oxoutput_name in oxnode.output: + if oxoutput_name == output_name: + res.add(oxnode) + break + return list(res) + + def get_previous_oxnode(self, oxnode_name: str) -> List[OXNode]: + ''' + 获取一个节点的前驱节点 + ''' + + res = set() + inputs = self.get_oxnode_by_name(oxnode_name).input + for input in inputs: + oxnode_set = self._output_tensor_2_oxnode_dict.get(input) + if oxnode_set is not None: + res.update(oxnode_set) + return list(res) + + def get_next_oxnode(self, oxnode_name: str) -> List[OXNode]: + ''' + 获取一个节点的后继节点 + ''' + + res = set() + outputs = self.get_oxnode_by_name(oxnode_name).output + for output in outputs: + oxnode_set = self._input_tensor_2_oxnode_dict.get(output) + if oxnode_set is not None: + res.update(oxnode_set) + return list(res) + + def insert_node(self, bef_node_info_list: List[Dict], aft_node_info_list: List[Dict], op_type: str, op_name: str, + **attributes: Dict) -> OXNode: + ''' + 向模型中插入新节点,并自动连边,注意和`add_node`的区别 + + 限制:无法涵盖所有场景,若结果不符合预期,请用`add_node`函数,并手动指定连边关系。 + + Args: + bef_node_info_list:参见README.md用例 + aft_node_info_list:参见README.md用例 + op_type:节点的类型 + op_name:节点的名字 + attributes:节点的属性 + + Returns: 插入的OXNode + ''' + + # 校验插入的节点是否已经存在 + if op_name in GV.OXNODE_DICT: + raise RuntimeError( + '[ERROR] {} has already exists in the model, please use a different name!'.format(op_name)) + + # 解析信息 + bef_node_info_list, aft_node_info_list = self._parse_insert_node_info(bef_node_info_list, aft_node_info_list) + + # 插入节点 + # + 构造新节点的输入 + new_node_input = [] + for bef_node_info in bef_node_info_list: + oxnode = self.get_oxnode_by_name(bef_node_info['bef_node_name'], True) + if oxnode is None: # 说明此节点是模型的输入节点 + new_node_input.append(bef_node_info['bef_node_name']) + else: + for idx in bef_node_info['link_output_idx']: + if oxnode.output[idx] in self.get_output_tensor_info().keys(): # 说明此节点紧接模型的输出节点 + oxnode.output[idx] = oxnode.get_name() + '_m_' + str(idx) + new_node_input.append(oxnode.output[idx]) + + # + 构造新节点的输出 + new_node_output = [op_name + '_0'] + + # + 构造新节点 + insert_oxnode = self.add_node(op_type=op_type, + op_name=op_name, + inputs=new_node_input, + outputs=new_node_output, + **attributes) + + # 和后继节点连边 + for aft_node_info in aft_node_info_list: + oxnode = self.get_oxnode_by_name(aft_node_info['aft_node_name'], True) + if oxnode is None: # 说明此节点是模型的输出节点 + if len(aft_node_info_list) != 1: + raise RuntimeError('[ERROR] Please check aft_node_info_list!') + + # 修改insert_oxnode的输出为模型的输出节点 + insert_oxnode.output[0] = aft_node_info['aft_node_name'] + else: + for idx in aft_node_info['link_input_idx']: + oxnode.input[idx] = new_node_output[0] + + # 更新tensor_2_oxnode字典 + self._update_tensor_2_oxnode_dict( + self._input_tensor_2_oxnode_dict, + self._output_tensor_2_oxnode_dict, + ) + + return insert_oxnode + + def add_node(self, op_type: str, op_name: str, inputs: List[str], outputs: List[str], **attributes: Dict) -> OXNode: + ''' + 向模型中增加新节点,不会自动连边,注意和`insert_node`的区别 + + Args: + op_type:节点的类型 + op_name:节点的名字 + inputs:节点的输入 + outputs:节点的输出 + attributes:节点的属性 + + Returns: 新增的OXNode + ''' + + if op_name in GV.OXNODE_DICT: + raise RuntimeError( + '[ERROR] {} has already exists in the model, please use a different name!'.format(op_name)) + + new_node = make_node(op_type=op_type, name=op_name, inputs=inputs, outputs=outputs, **attributes) + self._node.append(new_node) # 这里复制,而不是用引用,id已经变了 + new_node = self._node[-1] + new_oxnode = OXNode(new_node) + GV.OXNODE_DICT[new_oxnode.get_name()] = new_oxnode + + # 更新tensor_2_oxnode字典 + self._update_tensor_2_oxnode_dict( + self._input_tensor_2_oxnode_dict, + self._output_tensor_2_oxnode_dict, + ) + + return new_oxnode + + def remove_node(self, node_name: str, auto_link: bool = True) -> OXNode: + ''' + 从模型中删除节点 + + 限制:若开启自动连边,则删除的节点必须只有一个前驱节点,否则需要手动连边。若结果不符合预期,也需要自己手动连边。 + + Args: + node_name:要删除的节点名字 + auto_link:是否自动连边 + + Returns: 删除的OXNode + ''' + + if node_name not in GV.OXNODE_DICT: + raise RuntimeError('[ERROR] {} not found.'.format(node_name)) + + if auto_link is False: + oxnode = self.get_oxnode_by_name(node_name) + else: + oxnode = self.get_oxnode_by_name(node_name) + previous_node = self.get_previous_oxnode(node_name) + next_node = self.get_next_oxnode(node_name) + + if len(previous_node) > 1: + raise RuntimeError('[ERROR] Remove node can only have one previous node.') + + _clear_list(previous_node[0].output) + _extend_list(previous_node[0].output, oxnode.output) + + # 删除节点 + GV.OXNODE_DICT.pop(node_name) + self._node.remove(oxnode.get_node()) + + # 更新tensor_2_oxnode字典 + self._update_tensor_2_oxnode_dict( + self._input_tensor_2_oxnode_dict, + self._output_tensor_2_oxnode_dict, + ) + + return oxnode + + # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 输入输出相关函数 + def get_input_tensor_info(self) -> Dict: + ''' + 获取模型输入tensor的信息 + 信息包括:tensor名字、shape、类型 + + Returns: {'tensor_name': {'shape': np.shape, 'dtype': np.dtype}, ...} + ''' + + session = onnxruntime.InferenceSession(self._model_path) + + input_tensor_info = {} + for input_item in session.get_inputs(): + input_tensor_info[input_item.name] = { + 'shape': tuple(input_item.shape), + 'dtype': GV.ONNX_2_NUMPY_DATATYPE_DICT[input_item.type] + } + + return input_tensor_info + + def get_output_tensor_info(self) -> Dict: + ''' + 获取模型输出tensor的信息 + 信息包括:tensor名字、shape、类型 + + Returns: {'tensor_name': {'shape': np.shape, 'dtype': np.dtype}, ...} + ''' + + session = onnxruntime.InferenceSession(self._model_path) + + output_tensor_info = {} + for output_item in session.get_outputs(): + output_tensor_info[output_item.name] = { + 'shape': tuple(output_item.shape), + 'dtype': GV.ONNX_2_NUMPY_DATATYPE_DICT[output_item.type] + } + + return output_tensor_info + + def get_all_tensor_info(self) -> Dict: + ''' + 获取模型中所有tensor的信息 + 所有tensor包括:模型输入tensor、模型输出tensor、模型中间tensor + 信息包括:tensor名字、shape、类型 + + Returns: {'tensor_name': {'shape': np.shape, 'dtype': np.dtype}, ...} + ''' + + old_onnx_model = onnx.load(self._model_path) + + output_name = [] + for name in enumerate_model_node_outputs(old_onnx_model): + output_name.append(name) + + new_onnx_model = select_model_inputs_outputs(old_onnx_model, output_name) + new_model_path = os.path.join(os.path.dirname(self._model_path), 'temp.onnx') + save_onnx_model(new_onnx_model, new_model_path) + + session = onnxruntime.InferenceSession(new_model_path) + os.remove(new_model_path) + + all_tensor_info = {} + + for input_item in session.get_inputs(): + all_tensor_info[input_item.name] = { + 'shape': tuple(input_item.shape), + 'dtype': GV.ONNX_2_NUMPY_DATATYPE_DICT[input_item.type] + } + + for output_item in session.get_outputs(): + all_tensor_info[output_item.name] = { + 'shape': tuple(output_item.shape), + 'dtype': GV.ONNX_2_NUMPY_DATATYPE_DICT[output_item.type] + } + + for oxinitializer in GV.OXINITIALIZER_DICT.values(): + all_tensor_info[oxinitializer.get_name()] = { + 'shape': oxinitializer.get_data().shape, + 'dtype': eval('np.' + str(oxinitializer.get_data().dtype)) + } + + return all_tensor_info + + def infer_shape(self, input_data_info_list: List[Dict]) -> Dict: + ''' + 推导模型各个算子的输出shape信息。 + + 用途:有些模型从onnx图中无法看出算子输出shape信息,也无法获取shape信息,通过此函数可以推导出shape信息。 + + 原理:用真实数据运行一遍模型,记录各个算子的输出shape信息。 + + Args: + input_data_info_list: + [ + { + 'model_input_name': 'input1_name', + 'shape': '(1, 3, 224, 224)', + 'dtype': 'np.float32' + }, + { + 'model_input_name': 'input2_name', + 'shape': '(1, 3, 224, 224)', + 'dtype': 'np.float32' + } + ] + + Returns: {'op_name': {'shape': np.shape, 'dtype': np.dtype}, ...} + ''' + + # 构造输入数据 + input_data_dict = {} + for input_data_info in input_data_info_list: + input_data_dict[input_data_info['model_input_name']] = np.full(eval(input_data_info['shape']), + 1, + dtype=eval(input_data_info['dtype'])) + + # 修改模型,增加输出节点 + old_onnx_model = onnx.load(self._model_path) + output = [] + for out in enumerate_model_node_outputs(old_onnx_model): + output.append(out) + new_onnx_model = select_model_inputs_outputs(old_onnx_model, outputs=output) + onnx_save_path = './temp.onnx' + save_onnx_model(new_onnx_model, onnx_save_path) + + # 推理得到输出 + sess = onnxruntime.InferenceSession(onnx_save_path) + os.remove(onnx_save_path) + output_name = [node.name for node in sess.get_outputs()] + res = sess.run(output_name, input_data_dict) + + # 保存数据 + infer_tensor_info = {} + idx = 0 + for node in old_onnx_model.graph.node: + for i in range(len(node.output)): + infer_tensor_info[node.name] = {'output_idx': i, 'shape': res[idx].shape, 'dtype': res[idx].dtype} + idx += 1 + + return infer_tensor_info + + def dump_all_node_data(self, input_data_info_list: List[Dict], dump_data_save_path: str) -> NoReturn: + ''' + dump模型所有节点的数据 + + Args: + input_data_info_list: + [ + { + 'model_input_name': 'input1_name', + 'npy_file_path': './0.npy', + }, + { + 'model_input_name': 'input2_name', + 'npy_file_path': './1.npy', + }, + ] + dump_data_save_path: e.g. './dump_data' + + Returns: NoReturn + ''' + + # 创建目录 + if os.path.exists(dump_data_save_path): + shutil.rmtree(dump_data_save_path) + os.makedirs(dump_data_save_path) + + # 修改模型,增加输出节点 + old_onnx_model = onnx.load(self._model_path) + output = [] + for out in enumerate_model_node_outputs(old_onnx_model): + output.append(out) + new_onnx_model = select_model_inputs_outputs(old_onnx_model, outputs=output) + onnx_save_path = os.path.join(dump_data_save_path, "./temp.onnx") + save_onnx_model(new_onnx_model, onnx_save_path) + + # 获取输入数据 + input_data_dict = {} + for input_data_info in input_data_info_list: + input_data_dict[input_data_info['model_input_name']] = np.load(input_data_info['npy_file_path']) + + # 推理得到输出 + sess = onnxruntime.InferenceSession(onnx_save_path) + os.remove(onnx_save_path) + output_name = [node.name for node in sess.get_outputs()] + res = sess.run(output_name, input_data_dict) + + # 保存数据 + idx = 0 + for node in old_onnx_model.graph.node: + for i in range(len(node.output)): + file_name = node.name + "." + str(i) + "." + str(round(time.time() * 1000000)) + ".npy" + data_save_path = os.path.join(dump_data_save_path, file_name) + np.save(data_save_path, res[idx]) + idx += 1 + + # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 截图函数 + def extract_model(self, input_tensor_name_list: List[str], output_tensor_name_list: List[str], + new_model_save_path: str) -> NoReturn: + ''' + 从onnx 1.8.1开始,onnx官方提供了截图函数,此函数是对官方`onnx.utils.extract_model`函数的封装, + 以使其集成到`OXGraph`类中。另外,此函数屏蔽了`check_model`操作,使包含自定义算子的onnx提取子图后 + 在保存模型时跳过检查操作,使之可以顺利保存。以下是官方`onnx.utils.extract_model`函数的说明: + + Extracts sub-model from an ONNX model. + + The sub-model is defined by the names of the input and output tensors *exactly*. + + Note: For control-flow operators, e.g. If and Loop, the _boundary of sub-model_, + which is defined by the input and output tensors, should not _cut through_ the + subgraph that is connected to the _main graph_ as attributes of these operators. + + Arguments: + input_path (string): The path to original ONNX model. + output_path (string): The path to save the extracted ONNX model. + input_names (list of string): The names of the input tensors that to be extracted. + output_names (list of string): The names of the output tensors that to be extracted. + ''' + + print('[INFO] Begin to extract the model.') + start_time = datetime.now() + onnx.utils.extract_model(self._model_path, new_model_save_path, input_tensor_name_list, output_tensor_name_list) + end_time = datetime.now() + cost_time = (end_time - start_time).seconds + print('[INFO] Extract model completed! Cost {} seconds.'.format(cost_time)) + + def trunc_model(self, + trunc_beg_node_name_list: List[str], + trunc_end_node_name_list: List[str], + new_model_save_path: str, + keep_input_initializer: bool = False, + userdef_trunc_beg_node_info_list: List[Dict] = None) -> NoReturn: + ''' + 截取一段模型 + + 用途:可以用来单独验证某段网络的精度 + + 注意: + 从onnx 1.8.1开始,onnx官方提供了截图函数,若onnx版本>=1.8.1,请使用`extract_model`函数。 + `extract_model`函数是对官方`onnx.utils.extract_model`函数的封装,以使其集成到`OXGraph`类中。 + 此`trunc_model`函数是自己写的,功能可能有缺陷,但截图速度一般来说更快,模型较大时可以对比尝试。 + ''' + + print('[WARNING] 从onnx 1.8.1开始,onnx官方提供了截图函数,若onnx版本>=1.8.1,请使用`extract_model`函数。' + '`extract_model`函数是对官方`onnx.utils.extract_model`函数的封装,以使其集成到`OXGraph`类中。' + '此`trunc_model`函数是自己写的,功能可能有缺陷,但截图速度一般来说更快,模型较大时可以对比尝试。') + + print('[INFO] Begin to truncate the model.') + start_time = datetime.now() + + # 修改输出节点 + new_output = [] + for elem in trunc_end_node_name_list: + output = self.get_oxnode_by_name(elem).output + new_output.extend(x for x in output) + new_onnx = select_model_inputs_outputs(self._model, outputs=new_output) + save_onnx_model(new_onnx, new_model_save_path) + + # 加载模型 + model = onnx.load_model(new_model_save_path) + graph = model.graph + nodes = graph.node + initializers = graph.initializer + + # 搜索节点 + def find_trunc_beg_node(node_name): + is_find = False + for node in nodes: + if node.name == node_name: + trunc_beg_node = node + is_find = True + break + if is_find is True: + return trunc_beg_node + else: + raise RuntimeError('[ERROR] {} not found.'.format(node_name)) + + # 获取trunc_beg_node详细信息,构造一个这样的list: + ''' + [ + { + 'trunc_beg_node': node, + 'new_input_info_list': [ + { + 'input_name': 'input_A', + 'dtype': OXDataType.float32, + 'shape': (1, 256, 56, 56), + 'input_idx': 0 + }, + { + 'input_name': 'input_B', + 'dtype': OXDataType.float32, + 'shape': (1, 256, 56, 56), + 'input_idx': 1 + } + ] + } + ] + ''' + if userdef_trunc_beg_node_info_list is None: + trunc_beg_node_info_list = [] + initializer_name_set = set() + initializer_name_set.update([oxinitializer.get_name() for oxinitializer in GV.OXINITIALIZER_DICT.values()]) + count = 0 + for trunc_beg_node_name in trunc_beg_node_name_list: + trunc_beg_node = find_trunc_beg_node(trunc_beg_node_name) + new_input_info_list = [] + for idx, input in enumerate(trunc_beg_node.input): + if (keep_input_initializer is True) and (input in initializer_name_set): + continue + else: + new_input_info = {} + new_input_info['input_name'] = 'new_input_' + str(count) + count += 1 + new_input_info['dtype'] = GV.ONNX_2_NUMPY_DATATYPE_DICT[self._all_tensor_info[input]['dtype']] + new_input_info['shape'] = self._all_tensor_info[input]['shape'] + new_input_info['input_idx'] = idx + new_input_info_list.append(new_input_info) + trunc_beg_node_info = {} + trunc_beg_node_info['trunc_beg_node'] = trunc_beg_node + trunc_beg_node_info['new_input_info_list'] = new_input_info_list + trunc_beg_node_info_list.append(trunc_beg_node_info) + else: + trunc_beg_node_info_list = userdef_trunc_beg_node_info_list + + # 构造新输入 + new_inputs = [] + for trunc_beg_node_info in trunc_beg_node_info_list: + if userdef_trunc_beg_node_info_list is None: + trunc_begin_node = trunc_beg_node_info['trunc_beg_node'] + else: + trunc_begin_node = find_trunc_beg_node(trunc_beg_node_info['trunc_beg_node_name']) + for new_input_info in trunc_beg_node_info['new_input_info_list']: + new_input = self._make_new_input(new_input_info['input_name'], new_input_info['dtype'], + new_input_info['shape']) + new_inputs.append(new_input) + trunc_begin_node.input[new_input_info['input_idx']] = new_input_info['input_name'] + + # 查找有用节点 + useful_node_name_set = set() + useful_node_name_set.update(trunc_beg_node_name_list) + useful_node_name_set.update(trunc_end_node_name_list) + + # + 正向查找 + @lru_cache() + def find_useful_node(next_node_name_tuple): + for next_node_name in next_node_name_tuple: + if next_node_name not in trunc_end_node_name_list: + output_oxnode_list = self.get_next_oxnode(next_node_name) + output_oxnode_name_tuple = tuple([oxnode.get_name() for oxnode in output_oxnode_list]) + useful_node_name_set.update(output_oxnode_name_tuple) + find_useful_node(output_oxnode_name_tuple) + + # + 反向查找 + @lru_cache() + def find_useful_node_reverse(next_node_name_tuple): + for next_node_name in next_node_name_tuple: + if next_node_name not in trunc_beg_node_name_list: + input_oxnode_list = self.get_previous_oxnode(next_node_name) + input_oxnode_name_tuple = tuple([oxnode.get_name() for oxnode in input_oxnode_list]) + useful_node_name_set.update(input_oxnode_name_tuple) + find_useful_node_reverse(input_oxnode_name_tuple) + + # + 正向和反向都查找一遍,防止漏查 + find_useful_node(tuple(trunc_beg_node_name_list)) + find_useful_node_reverse(tuple(trunc_end_node_name_list)) + + # 删除多余节点 + for node in copy.deepcopy(nodes): + if node.name not in useful_node_name_set: + nodes.remove(node) + + # 删除多余输入 + _clear_list(graph.input) + _extend_list(graph.input, new_inputs) + + # 删除多余Initializer + all_input = set() + for node in nodes: + all_input.update(node.input) + for initializer in copy.deepcopy(initializers): + if initializer.name not in all_input: + initializers.remove(initializer) + + # 保存模型 + name = 'Extracted from {' + self._graph.name + '}' + graph = make_graph(nodes, + name, + graph.input, + graph.output, + initializer=initializers, + value_info=graph.value_info) + meta = { + 'ir_version': self._model.ir_version, + 'opset_imports': self._model.opset_import, + 'producer_name': 'OXGraph.trunc_model()', + } + new_mode = make_model(graph, **meta) + onnx.save(new_mode, new_model_save_path) + end_time = datetime.now() + cost_time = (end_time - start_time).seconds + print('[INFO] Truncate model completed! Cost {} seconds.'.format(cost_time)) + + # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 保存模型 + def save_new_model(self, new_model_path) -> NoReturn: + ''' + 保存修改后的模型 + ''' + + onnx.save_model(self._model, new_model_path) + + # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 私有函数 + def _update_tensor_2_oxnode_dict(self, input_tensor_2_oxnode_dict, output_tensor_2_oxnode_dict) -> NoReturn: + # 清空字典 + input_tensor_2_oxnode_dict.clear() + output_tensor_2_oxnode_dict.clear() + + # 创建字典 + for oxnode in GV.OXNODE_DICT.values(): + inputs = oxnode.input + outputs = oxnode.output + for input in inputs: + input_tensor_2_oxnode_dict.setdefault(input, set()).add(oxnode) + for output in outputs: + output_tensor_2_oxnode_dict.setdefault(output, set()).add(oxnode) + + def _make_new_input(self, new_input_name: str, ox_data_type: OXDataType, shape: tuple) -> ValueInfoProto: + ''' + If you print the model input in the terminal, you will get something like this, and you can modify it directly. + `dim_param` means dynamic shape. + [name: 'image' + type { + tensor_type { + elem_type: 1 + shape { + dim { + dim_param: '-1' + } + dim { + dim_value: 3 + } + dim { + dim_value: 224 + } + dim { + dim_value: 224 + } + } + } + } + ] + ''' + + new_input = copy.deepcopy(self._graph.input[0]) + new_input.name = new_input_name + new_input.type.tensor_type.elem_type = int(ox_data_type) + + dim_diff = len(shape) - len(new_input.type.tensor_type.shape.dim) + if dim_diff > 0: + for i in range(dim_diff): + new_input.type.tensor_type.shape.dim.append(copy.deepcopy(new_input.type.tensor_type.shape.dim[0])) + elif dim_diff < 0: + for i in range(abs(dim_diff)): + new_input.type.tensor_type.shape.dim.pop() + + for index in range(len(shape)): + if isinstance(shape[index], str): + new_input.type.tensor_type.shape.dim[index].dim_param = shape[index] + elif shape[index] is None: + new_input.type.tensor_type.shape.dim[index].dim_param = '-1' + print('[WARNING] Can not infer tensor shape, set it to "-1" here, which may cause an error! ' + 'Please specify `userdef_trunc_beg_node_info_list` parameters and retry.') + else: + new_input.type.tensor_type.shape.dim[index].dim_value = shape[index] + + return new_input + + def _parse_insert_node_info(self, bef_node_info_list, aft_node_info_list): + ''' + parse bef_node_info_list = ['Relu_1:0'] and aft_node_info_list = ['MaxPool_2:0'] into: + + bef_node_info_list=[{ + 'bef_node_name': 'Relu_1', + 'link_output_idx': [0] + }] + + aft_node_info_list=[{ + 'aft_node_name': 'MaxPool_2', + 'link_input_idx': [0] + }] + + 默认的`:0`可以省略 + ''' + + # 变量定义 + new_bef_node_info_list = [] + new_aft_node_info_list = [] + + # 解析bef_node_info_list + for bef_node_info in bef_node_info_list: + bef_node_info_dict = {} + info_list = bef_node_info.split(':') + bef_node_info_dict['bef_node_name'] = info_list[0] + if len(info_list) == 1: + bef_node_info_dict['link_output_idx'] = [0] + else: + bef_node_info_dict['link_output_idx'] = [int(elem) for idx, elem in enumerate(info_list) if idx > 0] + new_bef_node_info_list.append(bef_node_info_dict) + + # 解析aft_node_info_list + for aft_node_info in aft_node_info_list: + aft_node_info_dict = {} + info_list = aft_node_info.split(':') + aft_node_info_dict['aft_node_name'] = info_list[0] + if len(info_list) == 1: + aft_node_info_dict['link_input_idx'] = [0] + else: + aft_node_info_dict['link_input_idx'] = [int(elem) for idx, elem in enumerate(info_list) if idx > 0] + new_aft_node_info_list.append(aft_node_info_dict) + + return new_bef_node_info_list, new_aft_node_info_list + + +# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 公共函数 +def _clear_list(list) -> NoReturn: + ''' + 清空RepeatedScalarContainer或RepeatedCompositeContainer列表 + ''' + + list_len = len(list) + for _ in range(list_len): + list.pop() + + +def _extend_list(list, what_to_add) -> NoReturn: + ''' + 扩展RepeatedScalarContainer或RepeatedCompositeContainer列表 + ''' + + for elem in what_to_add: + list.append(elem) diff --git a/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/ReadMe.md b/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/ReadMe.md index 111fc7bc10..1d37439f43 100644 --- a/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/ReadMe.md +++ b/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/ReadMe.md @@ -1,310 +1,310 @@ -# 参考论文 - -- [Objects as Points](https://arxiv.org/abs/1904.07850) - -# 参考实现 - -- [xingyizhou/CenterNet](https://github.com/xingyizhou/CenterNet) -- [CaoWGG/TensorRT-CenterNet](https://github.com/CaoWGG/TensorRT-CenterNet) - -# 环境搭建 - -1、创建一个conda环境 - -```shell -conda create --nameCenterNet python=3.6 -``` - -激活环境 - -``` -conda activate CenterNet -``` - -2、clone仓库 - -``` -git clone https://github.com/xingyizhou/CenterNet -``` - -3、安装依赖 - -``` -cd CenterNet -pip install -r requirements.txt -``` - -4、安装pytorch v1.0.0 - -1) 下载[torch-1.0.0-cp36-cp36m-linux_x86_64.whl](https://download.pytorch.org/whl/cu100/torch-1.0.0-cp36-cp36m-linux_x86_64.whl) - -2) 安装 - -``` -pip install torch-1.0.0-cp36-cp36m-linux_x86_64.whl -``` - -**注意:**1) pytorch版本必须是1.0.0;2) 需确保是GPU环境;3) CUDA版本为10.2 - -5、安装其它依赖 - -``` -pip install tqdm==4.19.9 torchvision==0.2.2 onnx==1.8.1 onnxruntime==1.7.0 skl2onnx==1.8.0 -``` - -6、确保gcc和g++版本>=7.2.0 - -7、安装COCO API - -``` -cd CenterNet -git clone https://github.com/cocodataset/cocoapi.git -cd cocoapi/PythonAPI -make -python setup.py install --user -``` - -8、把THC-based DCNv2替换为ATen-based DCNv2 - -``` -cd CenterNet -git clone https://github.com/CaoWGG/TensorRT-CenterNet.gitcp -r TensorRT-CenterNet/readme/dcn src/lib/models/networks -``` - -**说明:**主要用的是TensorRT-CenterNet仓下的dcn目录,也可以仅下载dcn目录,然后放入到`CenterNet/src/lib/models/networks`目录下。 - -9、编译Deform Conv - -``` -cd src/lib/models/networks/dcn -python setup.py build_ext --inplace -``` - -**注意:**gcc和g++版本必须>=7.2.0,否则可能导致出错。 - -10、Change import - -把`CenterNet/src/lib/models/networks/pose_dla_dcn.py`和`CenterNet/src/lib/models/networks/resnet_dcn.py`中的`from .DCNv2.dcn_v2 import DCN`改为`from .dcn.modules.deform_conv import ModulatedDeformConvPack as DCN` - -11、打开`/root/anaconda3/envs/CenterNet/lib/python3.6/site-packages/torch/autograd/function.py`,定位到273行,把`_iter_filter(...)`函数改为如下: - -``` -def _iter_filter(condition, allow_unknown=False, condition_msg=None, - conversion=None): - def _iter(obj): - if conversion is not None: - obj = conversion(obj) - if condition(obj): - yield obj - #M<<<<<< - elif isinstance(obj,int): ## int to tensor - yield torch.tensor(obj) - #>>>>>> - elif obj is None: - return - elif isinstance(obj, (list, tuple)): - for o in obj: - for var in _iter(o): - yield var - elif allow_unknown: - yield obj - else: - raise ValueError("Auto nesting doesn't know how to process " - "an input object of type " + torch.typename(obj) + - (". Accepted types: " + condition_msg + - ", or lists/tuples of them" - if condition_msg else "")) - - - return _iter -``` - -12、下载[ctdet_coco_dla_2x.pth](https://drive.google.com/open?id=1pl_-ael8wERdUREEnaIfqOV_VF2bEVRT)模型,放入`CenterNet/models`目录下 -13、把`CenterNet/src/lib/opts.py中的add_argument('task', default='ctdet'....)`改为`add_argument('--task', default='ctdet'....)` -14、把提供的代码和脚本放入`CenterNet/src`目录下。 - -# 准备数据集 - -根据CenterNet官方数据集安装指导准备数据集:[DATA.md](https://github.com/xingyizhou/CenterNet/blob/master/readme/DATA.md),本示例以 **COCO 2017 Val** 数据集为例。 - -# PyTorch在线推理 - -由于后续导出onnx时需要修改CenterNet源码,修改后的代码无法进行PyTorch在线推理。因此这里先进行PyTorch在线推理验证。 - -运行pth_eval.py进行推理,推理完毕之后会输入精度和推理时间信息。 - -``` -python pth_eval.py --res_data_save_path=./pth_result -``` - -参数说明: - - --res_data_save_path:推理结果保存路径 - -# om模型推理模型转换 - -1. 模型转换。 - - 使用PyTorch将模型权重文件pth转换为onnx文件,再使用atc工具将onnx文件转为离线推理模型om文件。 - - - 导出onnx文件。 - - - 打开`CenterNet/src/lib/models/networks/dcn/functions/deform_conv.py`文件 - - - 修改`ModulatedDeformConvFunction`的`symbolic(...)`函数,把原函数改为如下: - - ``` - @staticmethod - def symbolic(g, input, weight, offset, bias, stride, padding, dilation, groups, deformable_groups): - return g.op("DeformableConv2D", - input, - weight, - offset, - bias, - deformable_groups_i=deformable_groups, - dilations_i=dilation, - groups_i=groups, - pads_i=padding, strides_i=stride) - ``` - - - 修改`ModulatedDeformConvFunction`的`forward(...)`函数,把原函数改为如下: - - ``` - @staticmethod - def forward(ctx, input, weight, offset, bias=None, stride=1, padding=0, dilation=1, groups=1, deformable_groups=1): - ctx.stride = stride - ctx.padding = padding - ctx.dilation = dilation - ctx.groups = groups - ctx.deformable_groups = deformable_groups - ctx.with_bias = bias is not None - if not ctx.with_bias: - bias = input.new_empty(1) # fake tensor - output = input.new_empty(ModulatedDeformConvFunction._infer_shape(ctx, input, weight)) - return output - ``` - - 打开`CenterNet/src/lib/models/networks/dcn/modules/deform_conv.py`文件,修改`ModulatedDeformConvPack`的`forward(...)`函数,把原函数改为如下: - - ``` - def forward(self, x): - out = self.conv_offset_mask(x) - o1, o2, mask = torch.chunk(out, 3, dim=1) - offset = torch.cat((o1, o2), dim=1) - mask = torch.sigmoid(mask) - - offset_y = offset.reshape(1, -1, 2, offset.shape[2], - offset.shape[3])[:, :, 0, ...].reshape(1, offset.shape[1] // 2, offset.shape[2], - offset.shape[3]) - offset_x = offset.reshape(1, -1, 2, offset.shape[2], - offset.shape[3])[:, :, 1, ...].reshape(1, offset.shape[1] // 2, offset.shape[2], - offset.shape[3]) - offset = torch.cat((offset_x, offset_y, mask), 1) - - return modulated_deform_conv(x, self.weight, offset, self.bias, self.stride, self.padding, self.dilation, self.groups, self.deformable_groups) - ``` - - 打开`/root/anaconda3/envs/CenterNet/lib/python3.6/site-packages/torch/onnx/symbolic.py`,在`reciprocal(...)`函数后边增加两个函数: - - ``` - def reshape(g, self, shape): - return view(g, self, shape) - - - def reshape_as(g, self, other): - shape = g.op('Shape', other) - return reshape(g, self, shape) - ``` - - - 运行`export_onnx.py`文件,导出onnx模型 - - ``` - python export_onnx.py - ``` - - 运行完之后,会在`CenterNet/models`目录下生成`ctdet_coco_dla_2x.onnx`模型文件。 - - - 运行`modify_onnx.py`文件,修改onnx模型文件 - - ``` - python modify_onnx.py - ``` - - 运行完之后,会在`CenterNet/models`目录下生成`ctdet_coco_dla_2x_modify.onnx`模型文件。 - - 2. 使用atc工具将onnx模型转om模型。 - - - 根据实际情况,修改`onnx2om.sh`脚本中的环境变量,具体的脚本示例如下: - - ``` - #!/bin/bash - clear - - export install_path=/usr/local/Ascend/ascend-toolkit/latest - export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH - export PYTHONPATH=${install_path}/atc/python/site-packages:${install_path}/pyACL/python/site-packages/acl:$PYTHONPATH - export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH - export ASCEND_OPP_PATH=${install_path}/opp - - atc --framework=5 --model=../models/ctdet_coco_dla_2x_modify.onnx --output=../models/ctdet_coco_dla_2x \ - --input_format=NCHW --input_shape=image:1,3,512,512 --log=error --soc_version=Ascend310 - rm -rf fusion_result.json kernel_meta - ``` - - 参数说明: - - - --model:为onnx模型文件 - - --framework:5代表onnx模型 - - - --output:输出的om模型 - - --input_format:输入数据的格式 - - --input_shape:输入数据的shape - - --log:日志等级 - - --soc_version:部署芯片类型 - - - 执行onnx2om.sh脚本,将onnx文件转为离线推理模型文件om文件。 - - ``` - bash onnx2om.sh - ``` - - 运行完之后,会在`CenterNet/models`目录下生成`ctdet_coco_dla_2x.om`模型文件。 - -2. 开始推理验证。 - - - 根据实际情况,修改`benchmark_infer.sh`脚本中的代码,具体的脚本示例如下: - - ``` - #!/bin/bash - clear - - export install_path=/usr/local/Ascend/ascend-toolkit/latest - export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH - export PYTHONPATH=${install_path}/atc/python/site-packages:${install_path}/pyACL/python/site-packages/acl:$PYTHONPATH - export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH - export ASCEND_OPP_PATH=${install_path}/opp - - ./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=../models/ctdet_coco_dla_2x.om \-input_text_path=./pre_bin/bin_file.info -input_width=512 -input_height=512 -output_binary=true -useDvpp=false - ``` - - - 执行`benchmark_infer.sh`脚本,进行benchmark推理。 - - ``` - sh benchmark_infer.sh - ``` - - - 推理数据后处理与精度统计。 - 运行postprocess.py脚本,进行后处理和精度统计。 - - ``` - python postprocess.py \ - --infer_res_save_path=./result/dumpOutput_device0 \ - --pre_data_save_path=./pre_bin \ - --res_data_save_path=./om_result - ``` - - 参数说明: - - - --infer_res_save_path:benchmark推理结果保存路径 - - --pre_data_save_path:预处理数据保存路径 - - --res_data_save_path:后处理结果保存路径 - - - +# 参考论文 + +- [Objects as Points](https://arxiv.org/abs/1904.07850) + +# 参考实现 + +- [xingyizhou/CenterNet](https://github.com/xingyizhou/CenterNet) +- [CaoWGG/TensorRT-CenterNet](https://github.com/CaoWGG/TensorRT-CenterNet) + +# 环境搭建 + +1、创建一个conda环境 + +```shell +conda create --nameCenterNet python=3.6 +``` + +激活环境 + +``` +conda activate CenterNet +``` + +2、clone仓库 + +``` +git clone https://github.com/xingyizhou/CenterNet +``` + +3、安装依赖 + +``` +cd CenterNet +pip install -r requirements.txt +``` + +4、安装pytorch v1.0.0 + +1) 下载[torch-1.0.0-cp36-cp36m-linux_x86_64.whl](https://download.pytorch.org/whl/cu100/torch-1.0.0-cp36-cp36m-linux_x86_64.whl) + +2) 安装 + +``` +pip install torch-1.0.0-cp36-cp36m-linux_x86_64.whl +``` + +**注意:**1) pytorch版本必须是1.0.0;2) 需确保是GPU环境;3) CUDA版本为10.2 + +5、安装其它依赖 + +``` +pip install tqdm==4.19.9 torchvision==0.2.2 onnx==1.8.1 onnxruntime==1.7.0 skl2onnx==1.8.0 +``` + +6、确保gcc和g++版本>=7.2.0 + +7、安装COCO API + +``` +cd CenterNet +git clone https://github.com/cocodataset/cocoapi.git +cd cocoapi/PythonAPI +make +python setup.py install --user +``` + +8、把THC-based DCNv2替换为ATen-based DCNv2 + +``` +cd CenterNet +git clone https://github.com/CaoWGG/TensorRT-CenterNet.gitcp -r TensorRT-CenterNet/readme/dcn src/lib/models/networks +``` + +**说明:**主要用的是TensorRT-CenterNet仓下的dcn目录,也可以仅下载dcn目录,然后放入到`CenterNet/src/lib/models/networks`目录下。 + +9、编译Deform Conv + +``` +cd src/lib/models/networks/dcn +python setup.py build_ext --inplace +``` + +**注意:**gcc和g++版本必须>=7.2.0,否则可能导致出错。 + +10、Change import + +把`CenterNet/src/lib/models/networks/pose_dla_dcn.py`和`CenterNet/src/lib/models/networks/resnet_dcn.py`中的`from .DCNv2.dcn_v2 import DCN`改为`from .dcn.modules.deform_conv import ModulatedDeformConvPack as DCN` + +11、打开`/root/anaconda3/envs/CenterNet/lib/python3.6/site-packages/torch/autograd/function.py`,定位到273行,把`_iter_filter(...)`函数改为如下: + +``` +def _iter_filter(condition, allow_unknown=False, condition_msg=None, + conversion=None): + def _iter(obj): + if conversion is not None: + obj = conversion(obj) + if condition(obj): + yield obj + #M<<<<<< + elif isinstance(obj,int): ## int to tensor + yield torch.tensor(obj) + #>>>>>> + elif obj is None: + return + elif isinstance(obj, (list, tuple)): + for o in obj: + for var in _iter(o): + yield var + elif allow_unknown: + yield obj + else: + raise ValueError("Auto nesting doesn't know how to process " + "an input object of type " + torch.typename(obj) + + (". Accepted types: " + condition_msg + + ", or lists/tuples of them" + if condition_msg else "")) + + + return _iter +``` + +12、下载[ctdet_coco_dla_2x.pth](https://drive.google.com/open?id=1pl_-ael8wERdUREEnaIfqOV_VF2bEVRT)模型,放入`CenterNet/models`目录下 +13、把`CenterNet/src/lib/opts.py中的add_argument('task', default='ctdet'....)`改为`add_argument('--task', default='ctdet'....)` +14、把提供的代码和脚本放入`CenterNet/src`目录下。 + +# 准备数据集 + +根据CenterNet官方数据集安装指导准备数据集:[DATA.md](https://github.com/xingyizhou/CenterNet/blob/master/readme/DATA.md),本示例以 **COCO 2017 Val** 数据集为例。 + +# PyTorch在线推理 + +由于后续导出onnx时需要修改CenterNet源码,修改后的代码无法进行PyTorch在线推理。因此这里先进行PyTorch在线推理验证。 + +运行pth_eval.py进行推理,推理完毕之后会输入精度和推理时间信息。 + +``` +python pth_eval.py --res_data_save_path=./pth_result +``` + +参数说明: + - --res_data_save_path:推理结果保存路径 + +# om模型推理模型转换 + +1. 模型转换。 + + 使用PyTorch将模型权重文件pth转换为onnx文件,再使用atc工具将onnx文件转为离线推理模型om文件。 + + - 导出onnx文件。 + + - 打开`CenterNet/src/lib/models/networks/dcn/functions/deform_conv.py`文件 + + - 修改`ModulatedDeformConvFunction`的`symbolic(...)`函数,把原函数改为如下: + + ``` + @staticmethod + def symbolic(g, input, weight, offset, bias, stride, padding, dilation, groups, deformable_groups): + return g.op("DeformableConv2D", + input, + weight, + offset, + bias, + deformable_groups_i=deformable_groups, + dilations_i=dilation, + groups_i=groups, + pads_i=padding, strides_i=stride) + ``` + + - 修改`ModulatedDeformConvFunction`的`forward(...)`函数,把原函数改为如下: + + ``` + @staticmethod + def forward(ctx, input, weight, offset, bias=None, stride=1, padding=0, dilation=1, groups=1, deformable_groups=1): + ctx.stride = stride + ctx.padding = padding + ctx.dilation = dilation + ctx.groups = groups + ctx.deformable_groups = deformable_groups + ctx.with_bias = bias is not None + if not ctx.with_bias: + bias = input.new_empty(1) # fake tensor + output = input.new_empty(ModulatedDeformConvFunction._infer_shape(ctx, input, weight)) + return output + ``` + - 打开`CenterNet/src/lib/models/networks/dcn/modules/deform_conv.py`文件,修改`ModulatedDeformConvPack`的`forward(...)`函数,把原函数改为如下: + + ``` + def forward(self, x): + out = self.conv_offset_mask(x) + o1, o2, mask = torch.chunk(out, 3, dim=1) + offset = torch.cat((o1, o2), dim=1) + mask = torch.sigmoid(mask) + + offset_y = offset.reshape(1, -1, 2, offset.shape[2], + offset.shape[3])[:, :, 0, ...].reshape(1, offset.shape[1] // 2, offset.shape[2], + offset.shape[3]) + offset_x = offset.reshape(1, -1, 2, offset.shape[2], + offset.shape[3])[:, :, 1, ...].reshape(1, offset.shape[1] // 2, offset.shape[2], + offset.shape[3]) + offset = torch.cat((offset_x, offset_y, mask), 1) + + return modulated_deform_conv(x, self.weight, offset, self.bias, self.stride, self.padding, self.dilation, self.groups, self.deformable_groups) + ``` + - 打开`/root/anaconda3/envs/CenterNet/lib/python3.6/site-packages/torch/onnx/symbolic.py`,在`reciprocal(...)`函数后边增加两个函数: + + ``` + def reshape(g, self, shape): + return view(g, self, shape) + + + def reshape_as(g, self, other): + shape = g.op('Shape', other) + return reshape(g, self, shape) + ``` + + - 运行`export_onnx.py`文件,导出onnx模型 + + ``` + python export_onnx.py + ``` + + 运行完之后,会在`CenterNet/models`目录下生成`ctdet_coco_dla_2x.onnx`模型文件。 + + - 运行`modify_onnx.py`文件,修改onnx模型文件 + + ``` + python modify_onnx.py + ``` + + 运行完之后,会在`CenterNet/models`目录下生成`ctdet_coco_dla_2x_modify.onnx`模型文件。 + + 2. 使用atc工具将onnx模型转om模型。 + + - 根据实际情况,修改`onnx2om.sh`脚本中的环境变量,具体的脚本示例如下: + + ``` + #!/bin/bash + clear + + export install_path=/usr/local/Ascend/ascend-toolkit/latest + export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH + export PYTHONPATH=${install_path}/atc/python/site-packages:${install_path}/pyACL/python/site-packages/acl:$PYTHONPATH + export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH + export ASCEND_OPP_PATH=${install_path}/opp + + atc --framework=5 --model=../models/ctdet_coco_dla_2x_modify.onnx --output=../models/ctdet_coco_dla_2x \ + --input_format=NCHW --input_shape=image:1,3,512,512 --log=error --soc_version=Ascend310 + rm -rf fusion_result.json kernel_meta + ``` + + 参数说明: + + - --model:为onnx模型文件 + - --framework:5代表onnx模型 + + - --output:输出的om模型 + - --input_format:输入数据的格式 + - --input_shape:输入数据的shape + - --log:日志等级 + - --soc_version:部署芯片类型 + + - 执行onnx2om.sh脚本,将onnx文件转为离线推理模型文件om文件。 + + ``` + bash onnx2om.sh + ``` + + 运行完之后,会在`CenterNet/models`目录下生成`ctdet_coco_dla_2x.om`模型文件。 + +2. 开始推理验证。 + + - 根据实际情况,修改`benchmark_infer.sh`脚本中的代码,具体的脚本示例如下: + + ``` + #!/bin/bash + clear + + export install_path=/usr/local/Ascend/ascend-toolkit/latest + export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH + export PYTHONPATH=${install_path}/atc/python/site-packages:${install_path}/pyACL/python/site-packages/acl:$PYTHONPATH + export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH + export ASCEND_OPP_PATH=${install_path}/opp + + ./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=../models/ctdet_coco_dla_2x.om \-input_text_path=./pre_bin/bin_file.info -input_width=512 -input_height=512 -output_binary=true -useDvpp=false + ``` + + - 执行`benchmark_infer.sh`脚本,进行benchmark推理。 + + ``` + sh benchmark_infer.sh + ``` + + - 推理数据后处理与精度统计。 + 运行postprocess.py脚本,进行后处理和精度统计。 + + ``` + python postprocess.py \ + --infer_res_save_path=./result/dumpOutput_device0 \ + --pre_data_save_path=./pre_bin \ + --res_data_save_path=./om_result + ``` + + 参数说明: + + - --infer_res_save_path:benchmark推理结果保存路径 + - --pre_data_save_path:预处理数据保存路径 + - --res_data_save_path:后处理结果保存路径 + + + diff --git a/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/export_onnx.py b/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/export_onnx.py index 7d6d385c28..5173af1d6e 100644 --- a/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/export_onnx.py +++ b/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/export_onnx.py @@ -1,114 +1,114 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ - -import _init_paths -import os -import torch -import torch.onnx as onnx -from lib.opts import opts -from types import MethodType -from collections import OrderedDict -from torch.onnx import OperatorExportTypes -from lib.models.model import create_model, load_model - -# 清空终端 -os.system('clear') - - -## onnx is not support dict return value -## for dla34 -def pose_dla_forward(self, x): - x = self.base(x) - x = self.dla_up(x) - y = [] - for i in range(self.last_level - self.first_level): - y.append(x[i].clone()) - self.ida_up(y, 0, len(y)) - ret = [] ## change dict to list - for head in self.heads: - ret.append(self.__getattr__(head)(y[-1])) - return ret - - -## for dla34v0 -def dlav0_forward(self, x): - x = self.base(x) - x = self.dla_up(x[self.first_level:]) - # x = self.fc(x) - # y = self.softmax(self.up(x)) - ret = [] ## change dict to list - for head in self.heads: - ret.append(self.__getattr__(head)(x)) - return ret - - -## for resdcn -def resnet_dcn_forward(self, x): - x = self.conv1(x) - x = self.bn1(x) - x = self.relu(x) - x = self.maxpool(x) - - x = self.layer1(x) - x = self.layer2(x) - x = self.layer3(x) - x = self.layer4(x) - x = self.deconv_layers(x) - ret = [] ## change dict to list - for head in self.heads: - ret.append(self.__getattr__(head)(x)) - return ret - - -forward = {'dla': pose_dla_forward, 'dlav0': dlav0_forward, 'resdcn': resnet_dcn_forward} - -opt = opts().init() -opt.arch = 'dla_34' -opt.heads = OrderedDict([('hm', 80), ('reg', 2), ('wh', 2)]) -opt.head_conv = 256 if 'dla' in opt.arch else 64 -print(opt) -model = create_model(opt.arch, opt.heads, opt.head_conv) -model.forward = MethodType(forward[opt.arch.split('_')[0]], model) -load_model(model, '../models/ctdet_coco_dla_2x.pth') -model.eval() -model.cuda() - -print('\n[INFO] Export to onnx ...') -input = torch.ones([1, 3, 512, 512]).cuda() -onnx.export(model, - input, - "../models/ctdet_coco_dla_2x.onnx", - operator_export_type=OperatorExportTypes.ONNX, - verbose=True, - input_names=['image'], - output_names=['hm', 'wh', 'reg']) -print('[INFO] Done!') +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ + +import _init_paths +import os +import torch +import torch.onnx as onnx +from lib.opts import opts +from types import MethodType +from collections import OrderedDict +from torch.onnx import OperatorExportTypes +from lib.models.model import create_model, load_model + +# 清空终端 +os.system('clear') + + +## onnx is not support dict return value +## for dla34 +def pose_dla_forward(self, x): + x = self.base(x) + x = self.dla_up(x) + y = [] + for i in range(self.last_level - self.first_level): + y.append(x[i].clone()) + self.ida_up(y, 0, len(y)) + ret = [] ## change dict to list + for head in self.heads: + ret.append(self.__getattr__(head)(y[-1])) + return ret + + +## for dla34v0 +def dlav0_forward(self, x): + x = self.base(x) + x = self.dla_up(x[self.first_level:]) + # x = self.fc(x) + # y = self.softmax(self.up(x)) + ret = [] ## change dict to list + for head in self.heads: + ret.append(self.__getattr__(head)(x)) + return ret + + +## for resdcn +def resnet_dcn_forward(self, x): + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + x = self.maxpool(x) + + x = self.layer1(x) + x = self.layer2(x) + x = self.layer3(x) + x = self.layer4(x) + x = self.deconv_layers(x) + ret = [] ## change dict to list + for head in self.heads: + ret.append(self.__getattr__(head)(x)) + return ret + + +forward = {'dla': pose_dla_forward, 'dlav0': dlav0_forward, 'resdcn': resnet_dcn_forward} + +opt = opts().init() +opt.arch = 'dla_34' +opt.heads = OrderedDict([('hm', 80), ('reg', 2), ('wh', 2)]) +opt.head_conv = 256 if 'dla' in opt.arch else 64 +print(opt) +model = create_model(opt.arch, opt.heads, opt.head_conv) +model.forward = MethodType(forward[opt.arch.split('_')[0]], model) +load_model(model, '../models/ctdet_coco_dla_2x.pth') +model.eval() +model.cuda() + +print('\n[INFO] Export to onnx ...') +input = torch.ones([1, 3, 512, 512]).cuda() +onnx.export(model, + input, + "../models/ctdet_coco_dla_2x.onnx", + operator_export_type=OperatorExportTypes.ONNX, + verbose=True, + input_names=['image'], + output_names=['hm', 'wh', 'reg']) +print('[INFO] Done!') diff --git a/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/modelzoo_level.txt b/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/modelzoo_level.txt index a17c8f95fa..a829ab59b9 100644 --- a/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/modelzoo_level.txt +++ b/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:NOK +FuncStatus:OK +PerfStatus:NOK PrecisionStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/modify_onnx.py b/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/modify_onnx.py index 5371b35499..99d51ad148 100644 --- a/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/modify_onnx.py +++ b/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/modify_onnx.py @@ -1,57 +1,57 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ - -import os -from OXInterface import OXDataType, OXGraph, OXInitializer, OXNode - -# 清空终端 -os.system('clear') - -# 加载模型 -oxgraph = OXGraph('../models/ctdet_coco_dla_2x.onnx') - -# 给节点添加名字 -for idx, node in enumerate(oxgraph._node): - node.name = node.op_type + '_' + str(idx) - node.doc_string = '' -oxgraph.save_new_model('../models/ctdet_coco_dla_2x_modify.onnx') - -# 修改DeformableConv2D的属性 -oxgraph = OXGraph('../models/ctdet_coco_dla_2x_modify.onnx') -oxnodes = oxgraph.get_oxnode_by_op_type('DeformableConv2D') -for oxnode in oxnodes: - oxnode.set_attribute('dilations', [1, 1]) - oxnode.set_attribute('pads', [1, 1]) - oxnode.set_attribute('strides', [1, 1]) - -# 保存新模型 -oxgraph.save_new_model('../models/ctdet_coco_dla_2x_modify.onnx') +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ + +import os +from OXInterface import OXDataType, OXGraph, OXInitializer, OXNode + +# 清空终端 +os.system('clear') + +# 加载模型 +oxgraph = OXGraph('../models/ctdet_coco_dla_2x.onnx') + +# 给节点添加名字 +for idx, node in enumerate(oxgraph._node): + node.name = node.op_type + '_' + str(idx) + node.doc_string = '' +oxgraph.save_new_model('../models/ctdet_coco_dla_2x_modify.onnx') + +# 修改DeformableConv2D的属性 +oxgraph = OXGraph('../models/ctdet_coco_dla_2x_modify.onnx') +oxnodes = oxgraph.get_oxnode_by_op_type('DeformableConv2D') +for oxnode in oxnodes: + oxnode.set_attribute('dilations', [1, 1]) + oxnode.set_attribute('pads', [1, 1]) + oxnode.set_attribute('strides', [1, 1]) + +# 保存新模型 +oxgraph.save_new_model('../models/ctdet_coco_dla_2x_modify.onnx') diff --git a/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/postprocess.py b/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/postprocess.py index a79f03d979..099262c632 100644 --- a/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/postprocess.py +++ b/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/postprocess.py @@ -1,157 +1,157 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ - -import _init_paths -import os -from tqdm import tqdm -import argparse -import shutil -import pickle -import glob -from os.path import join -import numpy as np -import torch -from logger import Logger -from datasets.dataset_factory import dataset_factory -from lib.detectors.ctdet import CtdetDetector -from lib.detectors.detector_factory import detector_factory -from lib.opts import opts -from lib.models.utils import flip_tensor -from lib.models.decode import ctdet_decode - -# 清空终端 -os.system('clear') - - -class ModelWarper(CtdetDetector): - def __init__(self, opt): - super(CtdetDetector, self).__init__(opt) - - def process(self, output): - hm = torch.from_numpy(output['hm']).sigmoid_() - wh = torch.from_numpy(output['wh']) - reg = torch.from_numpy(output['reg']) if self.opt.reg_offset else None - if self.opt.flip_test: - hm = (hm[0:1] + flip_tensor(hm[1:2])) / 2 - wh = (wh[0:1] + flip_tensor(wh[1:2])) / 2 - reg = reg[0:1] if reg is not None else None - dets = ctdet_decode(hm, wh, reg=reg, cat_spec_wh=self.opt.cat_spec_wh, K=self.opt.K) - - return dets - - def run(self, output, meta, scale): - detections = [] - dets = self.process(output) - dets = self.post_process(dets, meta, scale) - detections.append(dets) - - results = self.merge_outputs(detections) - return results - - -def postprocess(infer_res_save_path, pre_data_save_path, opt): - os.environ['CUDA_VISIBLE_DEVICES'] = opt.gpus_str - - Dataset = dataset_factory[opt.dataset] - opt = opts().update_dataset_info_and_set_heads(opt, Dataset) - print(opt) - Logger(opt) - Detector = detector_factory[opt.task] - - split = 'val' if not opt.trainval else 'test' - dataset = Dataset(opt, split) - detector = Detector(opt) - - model_warper = ModelWarper(detector.opt) - - # 创建目录 - if os.path.exists(res_data_save_path): - shutil.rmtree(res_data_save_path) - os.makedirs(res_data_save_path) - - # 读取文件个数 - bin_file_list = glob.glob(join(infer_res_save_path, '*.bin')) - bin_file_num = len(bin_file_list) // 3 - - # 加载字典 - image_id_dict = pickle.load(open(join(pre_data_save_path, 'image_id_dict.pkl'), 'rb')) - meta_dict = pickle.load(open(join(pre_data_save_path, 'meta_dict.pkl'), 'rb')) - - # 后处理 - print('\n[INFO] Postprocessing ...') - results = {} - for i in tqdm(range(bin_file_num)): - hm = np.fromfile(join(infer_res_save_path, str(i) + '_3.bin'), dtype=np.float32).reshape(1, 80, 128, 128) - wh = np.fromfile(join(infer_res_save_path, str(i) + '_1.bin'), dtype=np.float32).reshape(1, 2, 128, 128) - reg = np.fromfile(join(infer_res_save_path, str(i) + '_2.bin'), dtype=np.float32).reshape(1, 2, 128, 128) - - output = {'hm': hm, "wh": wh, "reg": reg} - meta = meta_dict[i] - scale = [1.0] - - result = model_warper.run(output, meta, scale) - - results[image_id_dict[i]] = result - print('[INFO] Postprocess done!') - - # 计算精度 - print('\n[INFO] Calculate accuracy ...') - dataset.run_eval(results, res_data_save_path) - - -if __name__ == '__main__': - ''' - Using Example: - - python postprocess.py \ - --infer_res_save_path=./result/dumpOutput_device0 \ - --pre_data_save_path=./pre_bin \ - --res_data_save_path=./om_result - ''' - - # 解析参数 - parser = argparse.ArgumentParser() - parser.add_argument('--infer_res_save_path', required=True) - parser.add_argument('--pre_data_save_path', required=True) - parser.add_argument('--res_data_save_path', required=True) - - opt = parser.parse_args() - infer_res_save_path = opt.infer_res_save_path - pre_data_save_path = opt.pre_data_save_path - res_data_save_path = opt.res_data_save_path - - # 创建并解析opt - opt = opts().init('--task ctdet --exp_id coco_dla --not_prefetch_test ' - '--load_model ../models/ctdet_coco_dla_2x.pth'.split(' ')) - - # 处理数据 - results = postprocess(infer_res_save_path, pre_data_save_path, opt) +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ + +import _init_paths +import os +from tqdm import tqdm +import argparse +import shutil +import pickle +import glob +from os.path import join +import numpy as np +import torch +from logger import Logger +from datasets.dataset_factory import dataset_factory +from lib.detectors.ctdet import CtdetDetector +from lib.detectors.detector_factory import detector_factory +from lib.opts import opts +from lib.models.utils import flip_tensor +from lib.models.decode import ctdet_decode + +# 清空终端 +os.system('clear') + + +class ModelWarper(CtdetDetector): + def __init__(self, opt): + super(CtdetDetector, self).__init__(opt) + + def process(self, output): + hm = torch.from_numpy(output['hm']).sigmoid_() + wh = torch.from_numpy(output['wh']) + reg = torch.from_numpy(output['reg']) if self.opt.reg_offset else None + if self.opt.flip_test: + hm = (hm[0:1] + flip_tensor(hm[1:2])) / 2 + wh = (wh[0:1] + flip_tensor(wh[1:2])) / 2 + reg = reg[0:1] if reg is not None else None + dets = ctdet_decode(hm, wh, reg=reg, cat_spec_wh=self.opt.cat_spec_wh, K=self.opt.K) + + return dets + + def run(self, output, meta, scale): + detections = [] + dets = self.process(output) + dets = self.post_process(dets, meta, scale) + detections.append(dets) + + results = self.merge_outputs(detections) + return results + + +def postprocess(infer_res_save_path, pre_data_save_path, opt): + os.environ['CUDA_VISIBLE_DEVICES'] = opt.gpus_str + + Dataset = dataset_factory[opt.dataset] + opt = opts().update_dataset_info_and_set_heads(opt, Dataset) + print(opt) + Logger(opt) + Detector = detector_factory[opt.task] + + split = 'val' if not opt.trainval else 'test' + dataset = Dataset(opt, split) + detector = Detector(opt) + + model_warper = ModelWarper(detector.opt) + + # 创建目录 + if os.path.exists(res_data_save_path): + shutil.rmtree(res_data_save_path) + os.makedirs(res_data_save_path) + + # 读取文件个数 + bin_file_list = glob.glob(join(infer_res_save_path, '*.bin')) + bin_file_num = len(bin_file_list) // 3 + + # 加载字典 + image_id_dict = pickle.load(open(join(pre_data_save_path, 'image_id_dict.pkl'), 'rb')) + meta_dict = pickle.load(open(join(pre_data_save_path, 'meta_dict.pkl'), 'rb')) + + # 后处理 + print('\n[INFO] Postprocessing ...') + results = {} + for i in tqdm(range(bin_file_num)): + hm = np.fromfile(join(infer_res_save_path, str(i) + '_3.bin'), dtype=np.float32).reshape(1, 80, 128, 128) + wh = np.fromfile(join(infer_res_save_path, str(i) + '_1.bin'), dtype=np.float32).reshape(1, 2, 128, 128) + reg = np.fromfile(join(infer_res_save_path, str(i) + '_2.bin'), dtype=np.float32).reshape(1, 2, 128, 128) + + output = {'hm': hm, "wh": wh, "reg": reg} + meta = meta_dict[i] + scale = [1.0] + + result = model_warper.run(output, meta, scale) + + results[image_id_dict[i]] = result + print('[INFO] Postprocess done!') + + # 计算精度 + print('\n[INFO] Calculate accuracy ...') + dataset.run_eval(results, res_data_save_path) + + +if __name__ == '__main__': + ''' + Using Example: + + python postprocess.py \ + --infer_res_save_path=./result/dumpOutput_device0 \ + --pre_data_save_path=./pre_bin \ + --res_data_save_path=./om_result + ''' + + # 解析参数 + parser = argparse.ArgumentParser() + parser.add_argument('--infer_res_save_path', required=True) + parser.add_argument('--pre_data_save_path', required=True) + parser.add_argument('--res_data_save_path', required=True) + + opt = parser.parse_args() + infer_res_save_path = opt.infer_res_save_path + pre_data_save_path = opt.pre_data_save_path + res_data_save_path = opt.res_data_save_path + + # 创建并解析opt + opt = opts().init('--task ctdet --exp_id coco_dla --not_prefetch_test ' + '--load_model ../models/ctdet_coco_dla_2x.pth'.split(' ')) + + # 处理数据 + results = postprocess(infer_res_save_path, pre_data_save_path, opt) diff --git a/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/preprocess.py b/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/preprocess.py index 7001d61d09..84347016ba 100644 --- a/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/preprocess.py +++ b/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/preprocess.py @@ -1,127 +1,127 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ - -import _init_paths -import argparse -import shutil -import pickle -import os -import cv2 -from os.path import join -from logger import Logger -from tqdm import tqdm -from datasets.dataset_factory import dataset_factory -from lib.detectors.ctdet import CtdetDetector -from lib.detectors.detector_factory import detector_factory -from lib.opts import opts - -# 清空终端 -os.system('clear') - - -class ModelWarper(CtdetDetector): - def __init__(self, opt): - super(CtdetDetector, self).__init__(opt) - - def run(self, image_path, image_save_path, meta_save_path): - image = cv2.imread(image_path) - scale = self.scales[0] - images, meta = self.pre_process(image, scale, None) - - # 保存数据 - images = images.numpy() - images.tofile(image_save_path) - - return meta - - -def preprocess(opt, pre_data_save_path): - os.environ['CUDA_VISIBLE_DEVICES'] = opt.gpus_str - - Dataset = dataset_factory[opt.dataset] - opt = opts().update_dataset_info_and_set_heads(opt, Dataset) - print(opt) - Logger(opt) - Detector = detector_factory[opt.task] - - split = 'val' if not opt.trainval else 'test' - dataset = Dataset(opt, split) - detector = Detector(opt) - - model_warper = ModelWarper(detector.opt) - - # 创建目录 - if os.path.exists(pre_data_save_path): - shutil.rmtree(pre_data_save_path) - os.makedirs(pre_data_save_path) - - # 处理数据 - info_file_path = join(pre_data_save_path, 'bin_file.info') - with open(info_file_path, 'wt', encoding='utf-8') as f_info: - image_id_dict = {} - meta_dict = {} - num_iters = len(dataset) - for i in tqdm(range(num_iters)): - image_id = dataset.images[i] - image_info = dataset.coco.loadImgs(ids=[image_id])[0] - image_path = join(dataset.img_dir, image_info['file_name']) - image_save_path = join(pre_data_save_path, str(i) + '.bin') - meta_save_path = join(pre_data_save_path, str(i) + '.pkl') - meta = model_warper.run(image_path, image_save_path, meta_save_path) - f_info.write(str(i) + " ./" + str(i) + '.bin 512 512' + '\n') - image_id_dict[i] = image_id - meta_dict[i] = meta - pickle.dump(image_id_dict, open(join(pre_data_save_path, 'image_id_dict.pkl'), 'wb')) - pickle.dump(meta_dict, open(join(pre_data_save_path, 'meta_dict.pkl'), 'wb')) - - -if __name__ == '__main__': - ''' - Using Example: - - python preprocess.py --pre_data_save_path=./pre_bin - ''' - - # 解析参数 - parser = argparse.ArgumentParser() - parser.add_argument('--pre_data_save_path', required=True) - opt = parser.parse_args() - pre_data_save_path = opt.pre_data_save_path - - # 创建并解析opt - opt = opts().init('--task ctdet --exp_id coco_dla --not_prefetch_test ' - '--load_model ../models/ctdet_coco_dla_2x.pth'.split(' ')) - - # 处理数据 - print('\n[INFO] Preprocessing ...') - preprocess(opt, pre_data_save_path) - print('[INFO] Preprocess done!') +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ + +import _init_paths +import argparse +import shutil +import pickle +import os +import cv2 +from os.path import join +from logger import Logger +from tqdm import tqdm +from datasets.dataset_factory import dataset_factory +from lib.detectors.ctdet import CtdetDetector +from lib.detectors.detector_factory import detector_factory +from lib.opts import opts + +# 清空终端 +os.system('clear') + + +class ModelWarper(CtdetDetector): + def __init__(self, opt): + super(CtdetDetector, self).__init__(opt) + + def run(self, image_path, image_save_path, meta_save_path): + image = cv2.imread(image_path) + scale = self.scales[0] + images, meta = self.pre_process(image, scale, None) + + # 保存数据 + images = images.numpy() + images.tofile(image_save_path) + + return meta + + +def preprocess(opt, pre_data_save_path): + os.environ['CUDA_VISIBLE_DEVICES'] = opt.gpus_str + + Dataset = dataset_factory[opt.dataset] + opt = opts().update_dataset_info_and_set_heads(opt, Dataset) + print(opt) + Logger(opt) + Detector = detector_factory[opt.task] + + split = 'val' if not opt.trainval else 'test' + dataset = Dataset(opt, split) + detector = Detector(opt) + + model_warper = ModelWarper(detector.opt) + + # 创建目录 + if os.path.exists(pre_data_save_path): + shutil.rmtree(pre_data_save_path) + os.makedirs(pre_data_save_path) + + # 处理数据 + info_file_path = join(pre_data_save_path, 'bin_file.info') + with open(info_file_path, 'wt', encoding='utf-8') as f_info: + image_id_dict = {} + meta_dict = {} + num_iters = len(dataset) + for i in tqdm(range(num_iters)): + image_id = dataset.images[i] + image_info = dataset.coco.loadImgs(ids=[image_id])[0] + image_path = join(dataset.img_dir, image_info['file_name']) + image_save_path = join(pre_data_save_path, str(i) + '.bin') + meta_save_path = join(pre_data_save_path, str(i) + '.pkl') + meta = model_warper.run(image_path, image_save_path, meta_save_path) + f_info.write(str(i) + " ./" + str(i) + '.bin 512 512' + '\n') + image_id_dict[i] = image_id + meta_dict[i] = meta + pickle.dump(image_id_dict, open(join(pre_data_save_path, 'image_id_dict.pkl'), 'wb')) + pickle.dump(meta_dict, open(join(pre_data_save_path, 'meta_dict.pkl'), 'wb')) + + +if __name__ == '__main__': + ''' + Using Example: + + python preprocess.py --pre_data_save_path=./pre_bin + ''' + + # 解析参数 + parser = argparse.ArgumentParser() + parser.add_argument('--pre_data_save_path', required=True) + opt = parser.parse_args() + pre_data_save_path = opt.pre_data_save_path + + # 创建并解析opt + opt = opts().init('--task ctdet --exp_id coco_dla --not_prefetch_test ' + '--load_model ../models/ctdet_coco_dla_2x.pth'.split(' ')) + + # 处理数据 + print('\n[INFO] Preprocessing ...') + preprocess(opt, pre_data_save_path) + print('[INFO] Preprocess done!') diff --git a/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/pth_eval.py b/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/pth_eval.py index 0fa6035d10..7a5b41ce85 100644 --- a/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/pth_eval.py +++ b/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch/pth_eval.py @@ -1,115 +1,115 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ - -import _init_paths -import os -import time -import shutil -import argparse -from tqdm import tqdm -from opts import opts -from logger import Logger -from datasets.dataset_factory import dataset_factory -from detectors.detector_factory import detector_factory - -# 清空终端 -os.system('clear') - - -def eval(opt, res_data_save_path): - os.environ['CUDA_VISIBLE_DEVICES'] = opt.gpus_str - - Dataset = dataset_factory[opt.dataset] - opt = opts().update_dataset_info_and_set_heads(opt, Dataset) - print(opt) - Logger(opt) - Detector = detector_factory[opt.task] - - split = 'val' if not opt.trainval else 'test' - dataset = Dataset(opt, split) - detector = Detector(opt) - - # 创建目录 - if os.path.exists(res_data_save_path): - shutil.rmtree(res_data_save_path) - os.makedirs(res_data_save_path) - - print('\n[INFO] Infering ...') - results = {} - num_iters = len(dataset) - total_infer_time = 0 - total_infer_num = 0 - for ind in tqdm(range(num_iters)): - img_id = dataset.images[ind] - img_info = dataset.coco.loadImgs(ids=[img_id])[0] - img_path = os.path.join(dataset.img_dir, img_info['file_name']) - - start_time = time.perf_counter() - ret = detector.run(img_path) - end_time = time.perf_counter() - total_infer_time += end_time - start_time - total_infer_num += 1 - - results[img_id] = ret['results'] - print('\n[INFO] Infer done!') - - print('\n[INFO] Calculate accuracy ...') - dataset.run_eval(results, res_data_save_path) - - # 推理时间 - print('\n[INFO] Time:') - msg = 'total infer num: ' + str(total_infer_num) + '\n' + \ - 'total infer time(ms): ' + str(total_infer_time * 1000) + '\n' + \ - 'average infer time(ms): ' + str(total_infer_time * 1000 / total_infer_num) + '\n' - print(msg) - - -if __name__ == '__main__': - ''' - Using Example: - - python pth_eval.py --res_data_save_path=./pth_result - ''' - - # 解析参数 - parser = argparse.ArgumentParser() - parser.add_argument('--res_data_save_path', required=True) - - opt = parser.parse_args() - res_data_save_path = opt.res_data_save_path - - # 创建并解析opt - opt = opts().init('--task ctdet --exp_id coco_dla --not_prefetch_test ' - '--load_model ../models/ctdet_coco_dla_2x.pth'.split(' ')) - - # 处理数据 - eval(opt, res_data_save_path) +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ + +import _init_paths +import os +import time +import shutil +import argparse +from tqdm import tqdm +from opts import opts +from logger import Logger +from datasets.dataset_factory import dataset_factory +from detectors.detector_factory import detector_factory + +# 清空终端 +os.system('clear') + + +def eval(opt, res_data_save_path): + os.environ['CUDA_VISIBLE_DEVICES'] = opt.gpus_str + + Dataset = dataset_factory[opt.dataset] + opt = opts().update_dataset_info_and_set_heads(opt, Dataset) + print(opt) + Logger(opt) + Detector = detector_factory[opt.task] + + split = 'val' if not opt.trainval else 'test' + dataset = Dataset(opt, split) + detector = Detector(opt) + + # 创建目录 + if os.path.exists(res_data_save_path): + shutil.rmtree(res_data_save_path) + os.makedirs(res_data_save_path) + + print('\n[INFO] Infering ...') + results = {} + num_iters = len(dataset) + total_infer_time = 0 + total_infer_num = 0 + for ind in tqdm(range(num_iters)): + img_id = dataset.images[ind] + img_info = dataset.coco.loadImgs(ids=[img_id])[0] + img_path = os.path.join(dataset.img_dir, img_info['file_name']) + + start_time = time.perf_counter() + ret = detector.run(img_path) + end_time = time.perf_counter() + total_infer_time += end_time - start_time + total_infer_num += 1 + + results[img_id] = ret['results'] + print('\n[INFO] Infer done!') + + print('\n[INFO] Calculate accuracy ...') + dataset.run_eval(results, res_data_save_path) + + # 推理时间 + print('\n[INFO] Time:') + msg = 'total infer num: ' + str(total_infer_num) + '\n' + \ + 'total infer time(ms): ' + str(total_infer_time * 1000) + '\n' + \ + 'average infer time(ms): ' + str(total_infer_time * 1000 / total_infer_num) + '\n' + print(msg) + + +if __name__ == '__main__': + ''' + Using Example: + + python pth_eval.py --res_data_save_path=./pth_result + ''' + + # 解析参数 + parser = argparse.ArgumentParser() + parser.add_argument('--res_data_save_path', required=True) + + opt = parser.parse_args() + res_data_save_path = opt.res_data_save_path + + # 创建并解析opt + opt = opts().init('--task ctdet --exp_id coco_dla --not_prefetch_test ' + '--load_model ../models/ctdet_coco_dla_2x.pth'.split(' ')) + + # 处理数据 + eval(opt, res_data_save_path) diff --git a/ACL_PyTorch/built-in/cv/DB_for_PyTorch/LICENSE b/ACL_PyTorch/built-in/cv/DB_for_PyTorch/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/built-in/cv/DB_for_PyTorch/LICENSE +++ b/ACL_PyTorch/built-in/cv/DB_for_PyTorch/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/DB_for_PyTorch/db.diff b/ACL_PyTorch/built-in/cv/DB_for_PyTorch/db.diff index 47cb2d745e..c4550dd325 100644 --- a/ACL_PyTorch/built-in/cv/DB_for_PyTorch/db.diff +++ b/ACL_PyTorch/built-in/cv/DB_for_PyTorch/db.diff @@ -103,24 +103,24 @@ index df6e5a2..796b02f 100644 --- a/backbones/resnet.py +++ b/backbones/resnet.py @@ -129,7 +129,8 @@ class Bottleneck(nn.Module): - self.conv2_offset = nn.Conv2d( - planes, deformable_groups * offset_channels, - kernel_size=3, -- padding=1) -+ padding=1, -+ stride=stride) - self.conv2 = conv_op( - planes, planes, kernel_size=3, padding=1, stride=stride, - deformable_groups=deformable_groups, bias=False) + self.conv2_offset = nn.Conv2d( + planes, deformable_groups * offset_channels, + kernel_size=3, +- padding=1) ++ padding=1, ++ stride=stride) + self.conv2 = conv_op( + planes, planes, kernel_size=3, padding=1, stride=stride, + deformable_groups=deformable_groups, bias=False) @@ -295,7 +296,7 @@ def resnet50(pretrained=True, **kwargs): - return model - - --def deformable_resnet50(pretrained=True, **kwargs): -+def deformable_resnet50(pretrained=False, **kwargs): - """Constructs a ResNet-50 model with deformable conv. - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet + return model + + +-def deformable_resnet50(pretrained=True, **kwargs): ++def deformable_resnet50(pretrained=False, **kwargs): + """Constructs a ResNet-50 model with deformable conv. + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet diff --git a/structure/model.py b/structure/model.py index 060191b..ea1705b 100644 --- a/structure/model.py diff --git a/ACL_PyTorch/built-in/cv/DB_for_PyTorch/db_pth2onnx.py b/ACL_PyTorch/built-in/cv/DB_for_PyTorch/db_pth2onnx.py index 93555759cf..6f65e5a62c 100644 --- a/ACL_PyTorch/built-in/cv/DB_for_PyTorch/db_pth2onnx.py +++ b/ACL_PyTorch/built-in/cv/DB_for_PyTorch/db_pth2onnx.py @@ -1,57 +1,57 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import torch.onnx -import argparse -from experiment import Structure, Experiment -from concern.config import Configurable, Config -from collections import OrderedDict - -def proc_nodes_modile(checkpoint): - new_state_dict = OrderedDict() - for k, v in checkpoint.items(): - if "module." in k: - name = k.replace("module.", "") - else: - name = k - new_state_dict[name] = v - return new_state_dict - -def pth2onnx(model): - #https://github.com/MhLiao/DB - input_names = ["actual_input_1"] - output_names = ["output1"] - dynamic_axes = {'actual_input_1': {0: '-1'}, 'output1': {0: '-1'}} - dummy_input = torch.randn(1, 3, 736, 1280) - - torch.onnx.export(model, dummy_input, "dbnet.onnx", input_names=input_names, dynamic_axes=dynamic_axes, output_names=output_names, opset_version=11, verbose=True) - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='db pth2onnx') - parser.add_argument('exp', type=str) - parser.add_argument('--resume', type=str, help='Resume from checkpoint') - args = parser.parse_args() - args = vars(args) - args = {k: v for k, v in args.items() if v is not None} - conf = Config() - experiment_args = conf.compile(conf.load(args['exp']))['Experiment'] - experiment_args.update(cmd=args) - experiment = Configurable.construct_class_from_config(experiment_args) - model = experiment.structure.builder.build(torch.device('cpu')) - checkpoint = torch.load(args['resume'], map_location=torch.device('cpu')) - checkpoint = proc_nodes_modile(checkpoint) - model.load_state_dict(checkpoint) - model.eval() - pth2onnx(model) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import torch.onnx +import argparse +from experiment import Structure, Experiment +from concern.config import Configurable, Config +from collections import OrderedDict + +def proc_nodes_modile(checkpoint): + new_state_dict = OrderedDict() + for k, v in checkpoint.items(): + if "module." in k: + name = k.replace("module.", "") + else: + name = k + new_state_dict[name] = v + return new_state_dict + +def pth2onnx(model): + #https://github.com/MhLiao/DB + input_names = ["actual_input_1"] + output_names = ["output1"] + dynamic_axes = {'actual_input_1': {0: '-1'}, 'output1': {0: '-1'}} + dummy_input = torch.randn(1, 3, 736, 1280) + + torch.onnx.export(model, dummy_input, "dbnet.onnx", input_names=input_names, dynamic_axes=dynamic_axes, output_names=output_names, opset_version=11, verbose=True) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='db pth2onnx') + parser.add_argument('exp', type=str) + parser.add_argument('--resume', type=str, help='Resume from checkpoint') + args = parser.parse_args() + args = vars(args) + args = {k: v for k, v in args.items() if v is not None} + conf = Config() + experiment_args = conf.compile(conf.load(args['exp']))['Experiment'] + experiment_args.update(cmd=args) + experiment = Configurable.construct_class_from_config(experiment_args) + model = experiment.structure.builder.build(torch.device('cpu')) + checkpoint = torch.load(args['resume'], map_location=torch.device('cpu')) + checkpoint = proc_nodes_modile(checkpoint) + model.load_state_dict(checkpoint) + model.eval() + pth2onnx(model) diff --git a/ACL_PyTorch/built-in/cv/DB_for_PyTorch/modelzoo_level.txt b/ACL_PyTorch/built-in/cv/DB_for_PyTorch/modelzoo_level.txt index 2233d9218a..9137dc380d 100644 --- a/ACL_PyTorch/built-in/cv/DB_for_PyTorch/modelzoo_level.txt +++ b/ACL_PyTorch/built-in/cv/DB_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK -PerfStatus:OK +FuncStatus:OK +PrecisionStatus:OK +PerfStatus:OK diff --git a/ACL_PyTorch/built-in/cv/DB_for_PyTorch/test/parse.py b/ACL_PyTorch/built-in/cv/DB_for_PyTorch/test/parse.py index 85920a3be8..2b1f1406a7 100644 --- a/ACL_PyTorch/built-in/cv/DB_for_PyTorch/test/parse.py +++ b/ACL_PyTorch/built-in/cv/DB_for_PyTorch/test/parse.py @@ -1,33 +1,33 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - #tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - #print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - print(content) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 - print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + #tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + #print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + print(content) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 + print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) diff --git a/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/ReadMe.md b/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/ReadMe.md index b72db5dd9f..2f762d2bd4 100644 --- a/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/ReadMe.md +++ b/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/ReadMe.md @@ -1,46 +1,46 @@ -文件作用说明: - -1.auto_tune.sh:模型转换脚本,集成了auto tune功能,可以手动关闭 - -2.pthtar2onnx.py:用于转换pth.tar文件到onnx文件 - -3.deepmar.info:PETA数据集信息,用于benchmark推理获取数据集 - -4.preprocess_deepmar_pytorch.py:数据集预处理脚本,通过均值方差处理归一化图片 - -5.label.json:PETA数据集标签,用于验证推理结果 - -6.postprocess_deepmar_pytorch.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy - -7.benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer - - - - - -推理端到端步骤: - -(1) 从开源仓https://github.com/dangweili/pedestrian-attribute-recognition-pytorch/blob/master/baseline/model/DeepMAR.py下载deepamar模型或者指定自己训练好的pth文件路径,使用提供的DeepMar.py替换掉模型中的DeepMar.py, 通过export_onnx.py脚本转化为onnx模型 - - - -(2)为提高性能,可以使用remove_pad.py剔除掉pad算子,运行auto_tune.sh脚本转换om模型,也可以选择手动关闭auto_tune,由于提出pad算子后,性能已经较好,本包中提供的om为未经auto_tune调优的om模型 - - -(3)运行python script/dataset/transform_peta.py得到数据集,python split_test_data.py得到测试集txt信息image.txt和标签json文件label.json - - -(4)运行python preprocess_deepmar_pytorch.py dataset/peta/images input_bin image.txt,根据测试集image.txt生成对应bin文件 - -(5)运行python get_info.py input_bin deepmar.info 224 224 生成deepmar.info文件,存储bin文件的信息 - -(6)./benchmark.x86_64 -model_type=vision -batch_size=1 -device_id=0 -om_path=deepmar_bs1.om -input_width=224 -input_height=224 -input_text_path=deepmar.info -useDvpp=false -output_binary=true - -运行benchmark推理,结果保存在 ./result/dumpOutput_device0下 目录下 - - - -(7)python postprocess_deepmar_pytorch.py result/dumpOutput_device0/ label.json - -验证推理结果,第一项即为acc - +文件作用说明: + +1.auto_tune.sh:模型转换脚本,集成了auto tune功能,可以手动关闭 + +2.pthtar2onnx.py:用于转换pth.tar文件到onnx文件 + +3.deepmar.info:PETA数据集信息,用于benchmark推理获取数据集 + +4.preprocess_deepmar_pytorch.py:数据集预处理脚本,通过均值方差处理归一化图片 + +5.label.json:PETA数据集标签,用于验证推理结果 + +6.postprocess_deepmar_pytorch.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy + +7.benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer + + + + + +推理端到端步骤: + +(1) 从开源仓https://github.com/dangweili/pedestrian-attribute-recognition-pytorch/blob/master/baseline/model/DeepMAR.py下载deepamar模型或者指定自己训练好的pth文件路径,使用提供的DeepMar.py替换掉模型中的DeepMar.py, 通过export_onnx.py脚本转化为onnx模型 + + + +(2)为提高性能,可以使用remove_pad.py剔除掉pad算子,运行auto_tune.sh脚本转换om模型,也可以选择手动关闭auto_tune,由于提出pad算子后,性能已经较好,本包中提供的om为未经auto_tune调优的om模型 + + +(3)运行python script/dataset/transform_peta.py得到数据集,python split_test_data.py得到测试集txt信息image.txt和标签json文件label.json + + +(4)运行python preprocess_deepmar_pytorch.py dataset/peta/images input_bin image.txt,根据测试集image.txt生成对应bin文件 + +(5)运行python get_info.py input_bin deepmar.info 224 224 生成deepmar.info文件,存储bin文件的信息 + +(6)./benchmark.x86_64 -model_type=vision -batch_size=1 -device_id=0 -om_path=deepmar_bs1.om -input_width=224 -input_height=224 -input_text_path=deepmar.info -useDvpp=false -output_binary=true + +运行benchmark推理,结果保存在 ./result/dumpOutput_device0下 目录下 + + + +(7)python postprocess_deepmar_pytorch.py result/dumpOutput_device0/ label.json + +验证推理结果,第一项即为acc + diff --git a/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/export_onnx.py b/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/export_onnx.py index ddab3eb951..c61f9e7567 100644 --- a/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/export_onnx.py +++ b/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/export_onnx.py @@ -1,38 +1,38 @@ -import torch -from baseline.model import DeepMAR -import torch.onnx -from collections import OrderedDict -import torch._utils - - -def proc_nodes_module(checkpoint, AttrName): - new_state_dict = OrderedDict() - for k, v in checkpoint[AttrName].items(): - if (k[0:7] == "module."): - name = k[7:] - else: - name = k[0:] - - new_state_dict[name] = v - return new_state_dict - - -def convert(): - checkpoint = torch.load("./checkpoint.pth.tar", map_location='cpu') - checkpoint['state_dict'] = proc_nodes_module(checkpoint, 'state_dict') - model = DeepMAR.DeepMAR_ResNet50() - model.load_state_dict(checkpoint['state_dict']) - model.eval() - print(model) - - input_names = ["actual_input_1"] - output_names = ["output1"] - dummy_input = torch.randn(1, 3, 224, 224) - import onnx - print('\nStarting ONNX export with onnx %s...' % onnx.__version__) - torch.onnx.export(model, dummy_input, "Deepmar_bs1.onnx", input_names=input_names, output_names=output_names, - opset_version=11, do_constant_folding=True) - - -if __name__ == "__main__": - convert() +import torch +from baseline.model import DeepMAR +import torch.onnx +from collections import OrderedDict +import torch._utils + + +def proc_nodes_module(checkpoint, AttrName): + new_state_dict = OrderedDict() + for k, v in checkpoint[AttrName].items(): + if (k[0:7] == "module."): + name = k[7:] + else: + name = k[0:] + + new_state_dict[name] = v + return new_state_dict + + +def convert(): + checkpoint = torch.load("./checkpoint.pth.tar", map_location='cpu') + checkpoint['state_dict'] = proc_nodes_module(checkpoint, 'state_dict') + model = DeepMAR.DeepMAR_ResNet50() + model.load_state_dict(checkpoint['state_dict']) + model.eval() + print(model) + + input_names = ["actual_input_1"] + output_names = ["output1"] + dummy_input = torch.randn(1, 3, 224, 224) + import onnx + print('\nStarting ONNX export with onnx %s...' % onnx.__version__) + torch.onnx.export(model, dummy_input, "Deepmar_bs1.onnx", input_names=input_names, output_names=output_names, + opset_version=11, do_constant_folding=True) + + +if __name__ == "__main__": + convert() diff --git a/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/get_info.py b/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/get_info.py index da181d8d03..c68e7705e4 100644 --- a/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/get_info.py +++ b/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/get_info.py @@ -1,16 +1,16 @@ -import os -import sys -from glob import glob - -file_path = sys.argv[1] -info_name = sys.argv[2] -width = sys.argv[3] -height = sys.argv[4] - -bin_images = glob(os.path.join(file_path, '*')) - -with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') +import os +import sys +from glob import glob + +file_path = sys.argv[1] +info_name = sys.argv[2] +width = sys.argv[3] +height = sys.argv[4] + +bin_images = glob(os.path.join(file_path, '*')) + +with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') diff --git a/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/postprocess_deepmar_pytorch.py b/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/postprocess_deepmar_pytorch.py index 14c2c834bf..f6032390a5 100644 --- a/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/postprocess_deepmar_pytorch.py +++ b/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/postprocess_deepmar_pytorch.py @@ -1,94 +1,94 @@ -import os -import sys -import json -import numpy as np - - -def attribute_evaluate_lidw(gt_result, pt_result): - """ - Input: - gt_result, pt_result, N*L, with 0/1 - Output: - result - a dictionary, including label-based and instance-based evaluation - label-based: label_pos_acc, label_neg_acc, label_acc - instance-based: instance_acc, instance_precision, instance_recall, instance_F1 - """ - # obtain the label-based and instance-based accuracy - # compute the label-based accuracy - if gt_result.shape != pt_result.shape: - print('Shape beteen groundtruth and predicted results are different') - # compute the label-based accuracy - result = {} - gt_pos = np.sum((gt_result == 1).astype(float), axis=0) - gt_neg = np.sum((gt_result == 0).astype(float), axis=0) - pt_pos = np.sum((gt_result == 1).astype(float) * (pt_result == 1).astype(float), axis=0) - pt_neg = np.sum((gt_result == 0).astype(float) * (pt_result == 0).astype(float), axis=0) - label_pos_acc = 1.0*pt_pos/gt_pos - label_neg_acc = 1.0*pt_neg/gt_neg - label_acc = (label_pos_acc + label_neg_acc)/2 - result['label_pos_acc'] = label_pos_acc - result['label_neg_acc'] = label_neg_acc - result['label_acc'] = label_acc - # compute the instance-based accuracy - # precision - gt_pos = np.sum((gt_result == 1).astype(float), axis=1) - pt_pos = np.sum((pt_result == 1).astype(float), axis=1) - floatersect_pos = np.sum((gt_result == 1).astype(float)*(pt_result == 1).astype(float), axis=1) - union_pos = np.sum(((gt_result == 1)+(pt_result == 1)).astype(float),axis=1) - # avoid empty label in predicted results - cnt_eff = float(gt_result.shape[0]) - for iter, key in enumerate(gt_pos): - if key == 0: - union_pos[iter] = 1 - pt_pos[iter] = 1 - gt_pos[iter] = 1 - cnt_eff = cnt_eff - 1 - continue - if pt_pos[iter] == 0: - pt_pos[iter] = 1 - instance_acc = np.sum(floatersect_pos/union_pos)/cnt_eff - instance_precision = np.sum(floatersect_pos/pt_pos)/cnt_eff - instance_recall = np.sum(floatersect_pos/gt_pos)/cnt_eff - floatance_F1 = 2*instance_precision*instance_recall/(instance_precision+instance_recall) - result['instance_acc'] = instance_acc - result['instance_precision'] = instance_precision - result['instance_recall'] = instance_recall - result['instance_F1'] = floatance_F1 - return result - - -def postprocess_deepmar(npu_result, label_file): - with open(label_file, 'r') as json_file: - image_label = json.load(json_file) - bin_files = os.listdir(npu_result) - counts = len(bin_files) - gt_result = np.zeros((counts, 35)) - pt_result = np.zeros((counts, 35)) - - for index, bin_file in enumerate(bin_files): - result = np.fromfile(os.path.join(npu_result, bin_file), dtype='float32').reshape((35, )) - result[result >= 0] = 1 - result[result < 0] = 0 - pt_result[index, :] = result - - # label - key = bin_file[:bin_file.rfind('_')] + '.png' - label = image_label[key] - label = np.array(label, dtype=np.uint8) - gt_result[index, :] = label - - result = attribute_evaluate_lidw(gt_result, pt_result) - print('-'*80) - print('instance_acc: {}'.format(result['instance_acc'])) - print('instance_precision: {}'.format(result['instance_precision'])) - print('instance_recall: {}'.format(result['instance_recall'])) - print('instance_F1: {}'.format(result['instance_F1'])) - print('-' * 80) - - -if __name__ == "__main__": - npu_result = os.path.abspath(sys.argv[1]) - label_file = os.path.abspath(sys.argv[2]) - postprocess_deepmar(npu_result, label_file) - +import os +import sys +import json +import numpy as np + + +def attribute_evaluate_lidw(gt_result, pt_result): + """ + Input: + gt_result, pt_result, N*L, with 0/1 + Output: + result + a dictionary, including label-based and instance-based evaluation + label-based: label_pos_acc, label_neg_acc, label_acc + instance-based: instance_acc, instance_precision, instance_recall, instance_F1 + """ + # obtain the label-based and instance-based accuracy + # compute the label-based accuracy + if gt_result.shape != pt_result.shape: + print('Shape beteen groundtruth and predicted results are different') + # compute the label-based accuracy + result = {} + gt_pos = np.sum((gt_result == 1).astype(float), axis=0) + gt_neg = np.sum((gt_result == 0).astype(float), axis=0) + pt_pos = np.sum((gt_result == 1).astype(float) * (pt_result == 1).astype(float), axis=0) + pt_neg = np.sum((gt_result == 0).astype(float) * (pt_result == 0).astype(float), axis=0) + label_pos_acc = 1.0*pt_pos/gt_pos + label_neg_acc = 1.0*pt_neg/gt_neg + label_acc = (label_pos_acc + label_neg_acc)/2 + result['label_pos_acc'] = label_pos_acc + result['label_neg_acc'] = label_neg_acc + result['label_acc'] = label_acc + # compute the instance-based accuracy + # precision + gt_pos = np.sum((gt_result == 1).astype(float), axis=1) + pt_pos = np.sum((pt_result == 1).astype(float), axis=1) + floatersect_pos = np.sum((gt_result == 1).astype(float)*(pt_result == 1).astype(float), axis=1) + union_pos = np.sum(((gt_result == 1)+(pt_result == 1)).astype(float),axis=1) + # avoid empty label in predicted results + cnt_eff = float(gt_result.shape[0]) + for iter, key in enumerate(gt_pos): + if key == 0: + union_pos[iter] = 1 + pt_pos[iter] = 1 + gt_pos[iter] = 1 + cnt_eff = cnt_eff - 1 + continue + if pt_pos[iter] == 0: + pt_pos[iter] = 1 + instance_acc = np.sum(floatersect_pos/union_pos)/cnt_eff + instance_precision = np.sum(floatersect_pos/pt_pos)/cnt_eff + instance_recall = np.sum(floatersect_pos/gt_pos)/cnt_eff + floatance_F1 = 2*instance_precision*instance_recall/(instance_precision+instance_recall) + result['instance_acc'] = instance_acc + result['instance_precision'] = instance_precision + result['instance_recall'] = instance_recall + result['instance_F1'] = floatance_F1 + return result + + +def postprocess_deepmar(npu_result, label_file): + with open(label_file, 'r') as json_file: + image_label = json.load(json_file) + bin_files = os.listdir(npu_result) + counts = len(bin_files) + gt_result = np.zeros((counts, 35)) + pt_result = np.zeros((counts, 35)) + + for index, bin_file in enumerate(bin_files): + result = np.fromfile(os.path.join(npu_result, bin_file), dtype='float32').reshape((35, )) + result[result >= 0] = 1 + result[result < 0] = 0 + pt_result[index, :] = result + + # label + key = bin_file[:bin_file.rfind('_')] + '.png' + label = image_label[key] + label = np.array(label, dtype=np.uint8) + gt_result[index, :] = label + + result = attribute_evaluate_lidw(gt_result, pt_result) + print('-'*80) + print('instance_acc: {}'.format(result['instance_acc'])) + print('instance_precision: {}'.format(result['instance_precision'])) + print('instance_recall: {}'.format(result['instance_recall'])) + print('instance_F1: {}'.format(result['instance_F1'])) + print('-' * 80) + + +if __name__ == "__main__": + npu_result = os.path.abspath(sys.argv[1]) + label_file = os.path.abspath(sys.argv[2]) + postprocess_deepmar(npu_result, label_file) + diff --git a/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/preprocess_deepmar_pytorch.py b/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/preprocess_deepmar_pytorch.py index 76f285439f..1a9fd52a60 100644 --- a/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/preprocess_deepmar_pytorch.py +++ b/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/preprocess_deepmar_pytorch.py @@ -1,73 +1,73 @@ -import os -import sys -import numpy as np -from PIL import Image - - -def resize(img, size, interpolation=Image.BILINEAR): - r"""Resize the input PIL Image to the given size. - - Args: - img (PIL Image): Image to be resized. - size (sequence or int): Desired output size. If size is a sequence like - (h, w), the output size will be matched to this. If size is an int, - the smaller edge of the image will be matched to this number maintaining - the aspect ratio. i.e, if height > width, then image will be rescaled to - :math:`\left(\text{size} \times \frac{\text{height}}{\text{width}}, \text{size}\right)` - interpolation (int, optional): Desired interpolation. Default is - ``PIL.Image.BILINEAR`` - - Returns: - PIL Image: Resized image. - """ - - if isinstance(size, int): - w, h = img.size - if (w <= h and w == size) or (h <= w and h == size): - return img - if w < h: - ow = size - oh = int(size * h / w) - return img.resize((ow, oh), interpolation) - else: - oh = size - ow = int(size * w / h) - return img.resize((ow, oh), interpolation) - else: - return img.resize(size[::-1], interpolation) - - -def deepmar_onnx(file_path, bin_path, image_info): - if not os.path.exists(bin_path): - os.makedirs(bin_path) - i = 0 - in_files = open(image_info, 'r').read().split('\n')[:-1] - input_size = (224, 224) - mean = [0.485, 0.456, 0.406] - std = [0.229, 0.224, 0.225] - for file in in_files: - i = i + 1 - print(file, "====", i) - img = Image.open(os.path.join(file_path, file)).convert('RGB') - img = resize(img, input_size) - - img = np.array(img, dtype=np.float32) - img = img / 255. - - # 均值方差 - img[..., 0] -= mean[0] - img[..., 1] -= mean[1] - img[..., 2] -= mean[2] - img[..., 0] /= std[0] - img[..., 1] /= std[1] - img[..., 2] /= std[2] - - img = img.transpose(2, 0, 1) # HWC -> CHW - img.tofile(os.path.join(bin_path, file.split('.')[0] + '.bin')) - - -if __name__ == "__main__": - file_path = os.path.abspath(sys.argv[1]) - bin_path = os.path.abspath(sys.argv[2]) - image_info = sys.argv[3] - deepmar_onnx(file_path, bin_path, image_info) +import os +import sys +import numpy as np +from PIL import Image + + +def resize(img, size, interpolation=Image.BILINEAR): + r"""Resize the input PIL Image to the given size. + + Args: + img (PIL Image): Image to be resized. + size (sequence or int): Desired output size. If size is a sequence like + (h, w), the output size will be matched to this. If size is an int, + the smaller edge of the image will be matched to this number maintaining + the aspect ratio. i.e, if height > width, then image will be rescaled to + :math:`\left(\text{size} \times \frac{\text{height}}{\text{width}}, \text{size}\right)` + interpolation (int, optional): Desired interpolation. Default is + ``PIL.Image.BILINEAR`` + + Returns: + PIL Image: Resized image. + """ + + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def deepmar_onnx(file_path, bin_path, image_info): + if not os.path.exists(bin_path): + os.makedirs(bin_path) + i = 0 + in_files = open(image_info, 'r').read().split('\n')[:-1] + input_size = (224, 224) + mean = [0.485, 0.456, 0.406] + std = [0.229, 0.224, 0.225] + for file in in_files: + i = i + 1 + print(file, "====", i) + img = Image.open(os.path.join(file_path, file)).convert('RGB') + img = resize(img, input_size) + + img = np.array(img, dtype=np.float32) + img = img / 255. + + # 均值方差 + img[..., 0] -= mean[0] + img[..., 1] -= mean[1] + img[..., 2] -= mean[2] + img[..., 0] /= std[0] + img[..., 1] /= std[1] + img[..., 2] /= std[2] + + img = img.transpose(2, 0, 1) # HWC -> CHW + img.tofile(os.path.join(bin_path, file.split('.')[0] + '.bin')) + + +if __name__ == "__main__": + file_path = os.path.abspath(sys.argv[1]) + bin_path = os.path.abspath(sys.argv[2]) + image_info = sys.argv[3] + deepmar_onnx(file_path, bin_path, image_info) diff --git a/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/remove_pad.py b/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/remove_pad.py index 572c41f3f5..70e8ccfb7e 100644 --- a/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/remove_pad.py +++ b/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/remove_pad.py @@ -1,19 +1,19 @@ -import onnx - -model = onnx.load("Deepmar.onnx") - -model.graph.node[174].input[0] = '492' - -node_list = ["Pad_173",'Constant_172'] -max_idx = len(model.graph.node) -rm_cnt = 0 -for i in range(len(model.graph.node)): - if i < max_idx: - n = model.graph.node[i - rm_cnt] - if n.name in node_list: - print("remove {} total {}".format(n.name, len(model.graph.node))) - model.graph.node.remove(n) - max_idx -= 1 - rm_cnt += 1 -onnx.checker.check_model(model) +import onnx + +model = onnx.load("Deepmar.onnx") + +model.graph.node[174].input[0] = '492' + +node_list = ["Pad_173",'Constant_172'] +max_idx = len(model.graph.node) +rm_cnt = 0 +for i in range(len(model.graph.node)): + if i < max_idx: + n = model.graph.node[i - rm_cnt] + if n.name in node_list: + print("remove {} total {}".format(n.name, len(model.graph.node))) + model.graph.node.remove(n) + max_idx -= 1 + rm_cnt += 1 +onnx.checker.check_model(model) onnx.save(model, "Deepmar_nopad.onnx") \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/split_test_data.py b/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/split_test_data.py index 955f4722d3..19a81059a6 100644 --- a/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/split_test_data.py +++ b/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch/split_test_data.py @@ -1,25 +1,25 @@ -import pickle -import numpy as np -import json - - -image = [] -label = [] -dataset = pickle.load(open('./dataset/peta/peta_dataset.pkl', 'rb'), encoding='utf-8') -train_split = pickle.load(open('./dataset/peta/peta_partition.pkl', 'rb'), encoding='utf-8') - -for idx in train_split['test'][0]: - image.append(dataset['image'][idx]) - label_tmp = np.array(dataset['att'][idx])[dataset['selected_attribute']].tolist() - label.append(label_tmp) - -with open('image.txt', 'w') as f: - for name in image: - f.write(name) - f.write('\n') - -image_label = dict(zip(image, label)) -with open('label.json', 'w') as json_file: - json.dump(image_label, json_file) - - +import pickle +import numpy as np +import json + + +image = [] +label = [] +dataset = pickle.load(open('./dataset/peta/peta_dataset.pkl', 'rb'), encoding='utf-8') +train_split = pickle.load(open('./dataset/peta/peta_partition.pkl', 'rb'), encoding='utf-8') + +for idx in train_split['test'][0]: + image.append(dataset['image'][idx]) + label_tmp = np.array(dataset['att'][idx])[dataset['selected_attribute']].tolist() + label.append(label_tmp) + +with open('image.txt', 'w') as f: + for name in image: + f.write(name) + f.write('\n') + +image_label = dict(zip(image, label)) +with open('label.json', 'w') as json_file: + json.dump(image_label, json_file) + + diff --git a/ACL_PyTorch/built-in/cv/Deepsort_for_Pytorch/modelzoo_level.txt b/ACL_PyTorch/built-in/cv/Deepsort_for_Pytorch/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/ACL_PyTorch/built-in/cv/Deepsort_for_Pytorch/modelzoo_level.txt +++ b/ACL_PyTorch/built-in/cv/Deepsort_for_Pytorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/EfficientNet_for_Pytorch/PytorchTransfer.py b/ACL_PyTorch/built-in/cv/EfficientNet_for_Pytorch/PytorchTransfer.py index 1c8e9d29c9..c002102863 100644 --- a/ACL_PyTorch/built-in/cv/EfficientNet_for_Pytorch/PytorchTransfer.py +++ b/ACL_PyTorch/built-in/cv/EfficientNet_for_Pytorch/PytorchTransfer.py @@ -1,46 +1,46 @@ -import sys -import os -import torch -import cv2 -from PIL import Image -import numpy as np -import torch.utils.data -import torchvision.transforms as transforms -from torch.autograd import Variable - - -def resnet50_onnx(input_path: str, output_path: str): - img = cv2.imread(input_path) - img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) - pilimg = Image.fromarray(img) - normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], - std=[0.229, 0.224, 0.225]) - val_transformer = transforms.Compose([ - transforms.Scale(256), - transforms.CenterCrop(224), - transforms.ToTensor(), - normalize - ]) - - img_tensor = val_transformer(pilimg) - img_tensor = torch.unsqueeze(img_tensor, dim=0).float() - img_tensor = Variable(img_tensor, requires_grad=False) - img_tensor.reshape(1, 3, 224, 224) - img_numpy = img_tensor.cpu().numpy() - - img_name = input_path.split('/')[-1] - bin_name = img_name.split('.')[0] + ".bin" - output_fl = os.path.join(output_path, bin_name) - # save img_tensor as binary file for om inference input - img_numpy.tofile(output_fl) - -if __name__ == "__main__": - input_img_dir = sys.argv[1] - output_img_dir = sys.argv[2] - images = os.listdir(input_img_dir) - for image_name in images: - if not image_name.endswith(".jpeg"): - continue - print("start to process image {}....".format(image_name)) - path_image = os.path.join(input_img_dir, image_name) +import sys +import os +import torch +import cv2 +from PIL import Image +import numpy as np +import torch.utils.data +import torchvision.transforms as transforms +from torch.autograd import Variable + + +def resnet50_onnx(input_path: str, output_path: str): + img = cv2.imread(input_path) + img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + pilimg = Image.fromarray(img) + normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]) + val_transformer = transforms.Compose([ + transforms.Scale(256), + transforms.CenterCrop(224), + transforms.ToTensor(), + normalize + ]) + + img_tensor = val_transformer(pilimg) + img_tensor = torch.unsqueeze(img_tensor, dim=0).float() + img_tensor = Variable(img_tensor, requires_grad=False) + img_tensor.reshape(1, 3, 224, 224) + img_numpy = img_tensor.cpu().numpy() + + img_name = input_path.split('/')[-1] + bin_name = img_name.split('.')[0] + ".bin" + output_fl = os.path.join(output_path, bin_name) + # save img_tensor as binary file for om inference input + img_numpy.tofile(output_fl) + +if __name__ == "__main__": + input_img_dir = sys.argv[1] + output_img_dir = sys.argv[2] + images = os.listdir(input_img_dir) + for image_name in images: + if not image_name.endswith(".jpeg"): + continue + print("start to process image {}....".format(image_name)) + path_image = os.path.join(input_img_dir, image_name) resnet50_onnx(path_image, output_img_dir) \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/EfficientNet_for_Pytorch/ReadMe.md b/ACL_PyTorch/built-in/cv/EfficientNet_for_Pytorch/ReadMe.md index 740e2ce6ae..0e9f686545 100644 --- a/ACL_PyTorch/built-in/cv/EfficientNet_for_Pytorch/ReadMe.md +++ b/ACL_PyTorch/built-in/cv/EfficientNet_for_Pytorch/ReadMe.md @@ -1,48 +1,48 @@ -文件作用说明: - -1.auto_tune.sh:模型转换脚本,集成了auto tune功能,可以手动关闭 - -2.pth2onnx.py:用于转换pth文件到onnx文件 - -3.pthtar2onnx.py:用于转换pth.tar文件到onnx文件 - -4.BinaryImageNet.info:ImageNet数据集信息,用于benchmark推理获取数据集 - -5.PytorchTransfer.py:数据集预处理脚本,通过均值方差处理归一化图片 - -6.val_label.txt:ImageNet数据集标签,用于验证推理结果 - -7.vision_metric_ImageNet.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy - -8.benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer - - - - - -推理端到端步骤: - -(1) 从Torchvision下载resnet50模型或者指定自己训练好的pth文件路径,通过pth2onnx.py脚本转化为onnx模型 - - - -(2)运行auto_tune.sh脚本转换om模型,也可以选择手动关闭auto_tune - -本demo已提供调优完成的om模型 - - - -(3)用PytorchTransfer.py脚本处理数据集,参考BinaryImageNet.Info配置处理后的二进制数据集路径 - - - -(4)./benchmark.x86_64 -model_type=vision -batch_size=16 -device_id=0 -input_text_path=./BinaryImageNet.info -input_width=224 -input_height=224 -om_path=./resnet50_pytorch.om -useDvpp=False - -运行benchmark推理,结果保存在 ./result 目录下 - - - -(5)python3.7 vision_metric_ImageNet.py result/dumpOutput/ ./val_label.txt ./ result.json - -验证推理结果 - +文件作用说明: + +1.auto_tune.sh:模型转换脚本,集成了auto tune功能,可以手动关闭 + +2.pth2onnx.py:用于转换pth文件到onnx文件 + +3.pthtar2onnx.py:用于转换pth.tar文件到onnx文件 + +4.BinaryImageNet.info:ImageNet数据集信息,用于benchmark推理获取数据集 + +5.PytorchTransfer.py:数据集预处理脚本,通过均值方差处理归一化图片 + +6.val_label.txt:ImageNet数据集标签,用于验证推理结果 + +7.vision_metric_ImageNet.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy + +8.benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer + + + + + +推理端到端步骤: + +(1) 从Torchvision下载resnet50模型或者指定自己训练好的pth文件路径,通过pth2onnx.py脚本转化为onnx模型 + + + +(2)运行auto_tune.sh脚本转换om模型,也可以选择手动关闭auto_tune + +本demo已提供调优完成的om模型 + + + +(3)用PytorchTransfer.py脚本处理数据集,参考BinaryImageNet.Info配置处理后的二进制数据集路径 + + + +(4)./benchmark.x86_64 -model_type=vision -batch_size=16 -device_id=0 -input_text_path=./BinaryImageNet.info -input_width=224 -input_height=224 -om_path=./resnet50_pytorch.om -useDvpp=False + +运行benchmark推理,结果保存在 ./result 目录下 + + + +(5)python3.7 vision_metric_ImageNet.py result/dumpOutput/ ./val_label.txt ./ result.json + +验证推理结果 + diff --git a/ACL_PyTorch/built-in/cv/EfficientNet_for_Pytorch/pthtar2onnx.py b/ACL_PyTorch/built-in/cv/EfficientNet_for_Pytorch/pthtar2onnx.py index 0784264fc9..10fd93f53f 100644 --- a/ACL_PyTorch/built-in/cv/EfficientNet_for_Pytorch/pthtar2onnx.py +++ b/ACL_PyTorch/built-in/cv/EfficientNet_for_Pytorch/pthtar2onnx.py @@ -1,36 +1,36 @@ -import torch -#from efficientnet_pytorch import EfficientNet -from NPU.efficientnet_pytorch import EfficientNet -import torch.onnx - -from collections import OrderedDict - -def proc_nodes_module(checkpoint,AttrName): - new_state_dict = OrderedDict() - for k,v in checkpoint[AttrName].items(): - if(k[0:7] == "module."): - name = k[7:] - else: - name = k[0:] - - new_state_dict[name]=v - return new_state_dict - -def convert(): - checkpoint = torch.load("./checkpoint.pth.140.ok.cpu", map_location='cpu') - checkpoint['state_dict'] = proc_nodes_module(checkpoint,'state_dict') - model = EfficientNet.from_name('efficientnet-b0') - model.set_swish(memory_efficient=False) - model.load_state_dict(checkpoint['state_dict']) - model.eval() - #print(model) - - input_names = ["actual_input_1"] - output_names = ["output1"] - dummy_input = torch.randn(1, 3, 224, 224) - #dynamic_axes = {'actual_input_1': {0: '-1'}, 'output1': {0: '-1'}} - torch.onnx.export(model, dummy_input, "efficientnet_tr.onnx", input_names = input_names, output_names = output_names, opset_version=11) - #torch.onnx.export(model, dummy_input, "efficientnet_dynamic.onnx", input_names = input_names, output_names = output_names, dynamic_axes = dynamic_axes, opset_version=11) - -if __name__ == "__main__": - convert() +import torch +#from efficientnet_pytorch import EfficientNet +from NPU.efficientnet_pytorch import EfficientNet +import torch.onnx + +from collections import OrderedDict + +def proc_nodes_module(checkpoint,AttrName): + new_state_dict = OrderedDict() + for k,v in checkpoint[AttrName].items(): + if(k[0:7] == "module."): + name = k[7:] + else: + name = k[0:] + + new_state_dict[name]=v + return new_state_dict + +def convert(): + checkpoint = torch.load("./checkpoint.pth.140.ok.cpu", map_location='cpu') + checkpoint['state_dict'] = proc_nodes_module(checkpoint,'state_dict') + model = EfficientNet.from_name('efficientnet-b0') + model.set_swish(memory_efficient=False) + model.load_state_dict(checkpoint['state_dict']) + model.eval() + #print(model) + + input_names = ["actual_input_1"] + output_names = ["output1"] + dummy_input = torch.randn(1, 3, 224, 224) + #dynamic_axes = {'actual_input_1': {0: '-1'}, 'output1': {0: '-1'}} + torch.onnx.export(model, dummy_input, "efficientnet_tr.onnx", input_names = input_names, output_names = output_names, opset_version=11) + #torch.onnx.export(model, dummy_input, "efficientnet_dynamic.onnx", input_names = input_names, output_names = output_names, dynamic_axes = dynamic_axes, opset_version=11) + +if __name__ == "__main__": + convert() diff --git a/ACL_PyTorch/built-in/cv/EfficientNet_for_Pytorch/vision_metric_ImageNet.py b/ACL_PyTorch/built-in/cv/EfficientNet_for_Pytorch/vision_metric_ImageNet.py index 7bba5f8346..f07c93617e 100644 --- a/ACL_PyTorch/built-in/cv/EfficientNet_for_Pytorch/vision_metric_ImageNet.py +++ b/ACL_PyTorch/built-in/cv/EfficientNet_for_Pytorch/vision_metric_ImageNet.py @@ -1,173 +1,173 @@ -#coding = utf-8 -import os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = "" - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - #print(filepath) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - #print(img_gt_dict) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - # print(img_name) - #print(n_labels) - # print(gt) - - resCnt = min(len(sort_index), topn) - # print(sort_index[:5]) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - #print("***************") - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - #print("Top" + str(i + 1) + " accuracy" + ": " + str(round(accuracy[i] * 100, 2)) + '%') - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) - #print("Time used:", elapsed) +#coding = utf-8 +import os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = "" + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + #print(filepath) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + #print(img_gt_dict) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + # print(img_name) + #print(n_labels) + # print(gt) + + resCnt = min(len(sort_index), topn) + # print(sort_index[:5]) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + #print("***************") + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + #print("Top" + str(i + 1) + " accuracy" + ": " + str(round(accuracy[i] * 100, 2)) + '%') + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) + #print("Time used:", elapsed) diff --git a/ACL_PyTorch/built-in/cv/Flownet2_for_Pytorch/LICENSE b/ACL_PyTorch/built-in/cv/Flownet2_for_Pytorch/LICENSE index 8904c85160..5f7aa69fea 100644 --- a/ACL_PyTorch/built-in/cv/Flownet2_for_Pytorch/LICENSE +++ b/ACL_PyTorch/built-in/cv/Flownet2_for_Pytorch/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/Flownet2_for_Pytorch/flownet2.patch b/ACL_PyTorch/built-in/cv/Flownet2_for_Pytorch/flownet2.patch index be8fdbe2c6..4b175db7da 100644 --- a/ACL_PyTorch/built-in/cv/Flownet2_for_Pytorch/flownet2.patch +++ b/ACL_PyTorch/built-in/cv/Flownet2_for_Pytorch/flownet2.patch @@ -3,58 +3,58 @@ index 8457d2f..34380a6 100755 --- a/models.py +++ b/models.py @@ -6,8 +6,10 @@ import math - import numpy as np - - try: -- from networks.resample2d_package.resample2d import Resample2d -- from networks.channelnorm_package.channelnorm import ChannelNorm -+ # from networks.resample2d_package.resample2d import Resample2d -+ # from networks.channelnorm_package.channelnorm import ChannelNorm -+ from networks.resample2d_onnx import Resample2d -+ from networks.channelnorm_onnx import ChannelNorm - - from networks import FlowNetC - from networks import FlowNetS + import numpy as np + + try: +- from networks.resample2d_package.resample2d import Resample2d +- from networks.channelnorm_package.channelnorm import ChannelNorm ++ # from networks.resample2d_package.resample2d import Resample2d ++ # from networks.channelnorm_package.channelnorm import ChannelNorm ++ from networks.resample2d_onnx import Resample2d ++ from networks.channelnorm_onnx import ChannelNorm + + from networks import FlowNetC + from networks import FlowNetS @@ -16,8 +18,10 @@ try: - - from networks.submodules import * - except: -- from .networks.resample2d_package.resample2d import Resample2d -- from .networks.channelnorm_package.channelnorm import ChannelNorm -+ # from .networks.resample2d_package.resample2d import Resample2d -+ # from .networks.channelnorm_package.channelnorm import ChannelNorm -+ from .networks.resample2d_onnx import Resample2d -+ from .networks.channelnorm_onnx import ChannelNorm - - from .networks import FlowNetC - from .networks import FlowNetS + + from networks.submodules import * + except: +- from .networks.resample2d_package.resample2d import Resample2d +- from .networks.channelnorm_package.channelnorm import ChannelNorm ++ # from .networks.resample2d_package.resample2d import Resample2d ++ # from .networks.channelnorm_package.channelnorm import ChannelNorm ++ from .networks.resample2d_onnx import Resample2d ++ from .networks.channelnorm_onnx import ChannelNorm + + from .networks import FlowNetC + from .networks import FlowNetS @@ -33,7 +37,7 @@ class FlowNet2(nn.Module): - super(FlowNet2,self).__init__() - self.batchNorm = batchNorm - self.div_flow = div_flow -- self.rgb_max = args.rgb_max -+ # self.rgb_max = args.rgb_max - self.args = args - - self.channelnorm = ChannelNorm() + super(FlowNet2,self).__init__() + self.batchNorm = batchNorm + self.div_flow = div_flow +- self.rgb_max = args.rgb_max ++ # self.rgb_max = args.rgb_max + self.args = args + + self.channelnorm = ChannelNorm() @@ -117,12 +121,12 @@ class FlowNet2(nn.Module): - weight.data[i,i,:,:] = torch.from_numpy(bilinear) - return - -- def forward(self, inputs): -- rgb_mean = inputs.contiguous().view(inputs.size()[:2]+(-1,)).mean(dim=-1).view(inputs.size()[:2] + (1,1,1,)) -+ def forward(self, x1, x2): -+ # rgb_mean = inputs.contiguous().view(inputs.size()[:2]+(-1,)).mean(dim=-1).view(inputs.size()[:2] + (1,1,1,)) - -- x = (inputs - rgb_mean) / self.rgb_max -- x1 = x[:,:,0,:,:] -- x2 = x[:,:,1,:,:] -+ # x = (inputs - rgb_mean) / self.rgb_max -+ # x1 = x[:,:,0,:,:] -+ # x2 = x[:,:,1,:,:] - x = torch.cat((x1,x2), dim = 1) - - # flownetc + weight.data[i,i,:,:] = torch.from_numpy(bilinear) + return + +- def forward(self, inputs): +- rgb_mean = inputs.contiguous().view(inputs.size()[:2]+(-1,)).mean(dim=-1).view(inputs.size()[:2] + (1,1,1,)) ++ def forward(self, x1, x2): ++ # rgb_mean = inputs.contiguous().view(inputs.size()[:2]+(-1,)).mean(dim=-1).view(inputs.size()[:2] + (1,1,1,)) + +- x = (inputs - rgb_mean) / self.rgb_max +- x1 = x[:,:,0,:,:] +- x2 = x[:,:,1,:,:] ++ # x = (inputs - rgb_mean) / self.rgb_max ++ # x1 = x[:,:,0,:,:] ++ # x2 = x[:,:,1,:,:] + x = torch.cat((x1,x2), dim = 1) + + # flownetc diff --git a/networks/FlowNetC.py b/networks/FlowNetC.py index 61e117a..32e130d 100755 --- a/networks/FlowNetC.py diff --git a/ACL_PyTorch/built-in/cv/GoogleNet_for_Pytorch/ReadMe.md b/ACL_PyTorch/built-in/cv/GoogleNet_for_Pytorch/ReadMe.md index 7e082d9620..bec682de97 100644 --- a/ACL_PyTorch/built-in/cv/GoogleNet_for_Pytorch/ReadMe.md +++ b/ACL_PyTorch/built-in/cv/GoogleNet_for_Pytorch/ReadMe.md @@ -1,63 +1,63 @@ -文件作用说明: - -1.googlenet_pth2onnx.py:用于转换pth模型文件到onnx模型文件 - -2.googlenet_atc.sh:onnx模型转换om模型脚本 - -3.preprocess_googlenet_pth.py:数据集预处理脚本,通过均值方差处理归一化图片,生成图片二进制文件 - -4.aipp_googlenet_pth.config:数据集aipp预处理配置文件 - -5.get_info.py:生成推理输入的数据集二进制info文件或jpg info文件 - -6.googlenet_val.info:ImageNet验证集二进制info文件,用于benchmark推理获取数据集 - -7.ImageNet.info:ImageNet验证集jpg info文件,用于benchmark推理获取数据集 - -8.val_label.txt:ImageNet数据集标签,用于验证推理结果 - -9.benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer - -10.vision_metric_ImageNet.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy - - - - - -推理端到端步骤: - -(1) 从Torchvision下载googlenet模型,通过googlenet_pth2onnx.py脚本转化为onnx模型 - - - -(2)运行googlenet_atc.sh脚本转换om模型 - -本demo已提供调优完成的om模型 - - - -(3)用preprocess_googlenet_pth.py脚本处理数据集,参考googlenet_val.info配置处理后的二进制数据集路径。或者配置数据集aipp预处理文件aipp_googlenet_pth.config。 - python3 preprocess_googlenet_pth.py dataset/ImageNet/val_union/ pre_bin - - - -(4)生成推理输入的数据集二进制info文件或jpg info文件 - python3 get_info.py bin pre_bin googlenet_val.info 224 224 - python3 get_info.py jpg dataset/ImageNet/val_union ImageNet.info - - - -(5)使用benchmark离线推理 - ./benchmark -model_type=vision -om_path=googlenet_bs16.om -device_id=0 -batch_size=16 -input_text_path=googlenet_val.info -input_width=224 -input_height=224 -useDvpp=false - 或者 - ./benchmark -model_type=vision -om_path=googlenet_bs1.om -device_id=0 -batch_size=1 -input_text_path=ImageNet.info -input_width=256 -input_height=256 -useDvpp=true - - -运行benchmark推理,结果保存在 ./result 目录下 - - - -(6)python3.7 vision_metric_ImageNet.py result/dumpOutput_device0/ ./val_label.txt ./ result.json - -验证推理结果 - +文件作用说明: + +1.googlenet_pth2onnx.py:用于转换pth模型文件到onnx模型文件 + +2.googlenet_atc.sh:onnx模型转换om模型脚本 + +3.preprocess_googlenet_pth.py:数据集预处理脚本,通过均值方差处理归一化图片,生成图片二进制文件 + +4.aipp_googlenet_pth.config:数据集aipp预处理配置文件 + +5.get_info.py:生成推理输入的数据集二进制info文件或jpg info文件 + +6.googlenet_val.info:ImageNet验证集二进制info文件,用于benchmark推理获取数据集 + +7.ImageNet.info:ImageNet验证集jpg info文件,用于benchmark推理获取数据集 + +8.val_label.txt:ImageNet数据集标签,用于验证推理结果 + +9.benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer + +10.vision_metric_ImageNet.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy + + + + + +推理端到端步骤: + +(1) 从Torchvision下载googlenet模型,通过googlenet_pth2onnx.py脚本转化为onnx模型 + + + +(2)运行googlenet_atc.sh脚本转换om模型 + +本demo已提供调优完成的om模型 + + + +(3)用preprocess_googlenet_pth.py脚本处理数据集,参考googlenet_val.info配置处理后的二进制数据集路径。或者配置数据集aipp预处理文件aipp_googlenet_pth.config。 + python3 preprocess_googlenet_pth.py dataset/ImageNet/val_union/ pre_bin + + + +(4)生成推理输入的数据集二进制info文件或jpg info文件 + python3 get_info.py bin pre_bin googlenet_val.info 224 224 + python3 get_info.py jpg dataset/ImageNet/val_union ImageNet.info + + + +(5)使用benchmark离线推理 + ./benchmark -model_type=vision -om_path=googlenet_bs16.om -device_id=0 -batch_size=16 -input_text_path=googlenet_val.info -input_width=224 -input_height=224 -useDvpp=false + 或者 + ./benchmark -model_type=vision -om_path=googlenet_bs1.om -device_id=0 -batch_size=1 -input_text_path=ImageNet.info -input_width=256 -input_height=256 -useDvpp=true + + +运行benchmark推理,结果保存在 ./result 目录下 + + + +(6)python3.7 vision_metric_ImageNet.py result/dumpOutput_device0/ ./val_label.txt ./ result.json + +验证推理结果 + diff --git a/ACL_PyTorch/built-in/cv/GoogleNet_for_Pytorch/get_info.py b/ACL_PyTorch/built-in/cv/GoogleNet_for_Pytorch/get_info.py index 0578e4f00c..7b14c54b90 100644 --- a/ACL_PyTorch/built-in/cv/GoogleNet_for_Pytorch/get_info.py +++ b/ACL_PyTorch/built-in/cv/GoogleNet_for_Pytorch/get_info.py @@ -1,46 +1,46 @@ -import os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +import os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/GoogleNet_for_Pytorch/preprocess_googlenet_pth.py b/ACL_PyTorch/built-in/cv/GoogleNet_for_Pytorch/preprocess_googlenet_pth.py index 04f41f7597..965681f30d 100644 --- a/ACL_PyTorch/built-in/cv/GoogleNet_for_Pytorch/preprocess_googlenet_pth.py +++ b/ACL_PyTorch/built-in/cv/GoogleNet_for_Pytorch/preprocess_googlenet_pth.py @@ -1,85 +1,85 @@ -import os -import sys -import numpy as np -from PIL import Image - - -def resize(img, size, interpolation=Image.BILINEAR): - r"""Resize the input PIL Image to the given size. - - Args: - img (PIL Image): Image to be resized. - size (sequence or int): Desired output size. If size is a sequence like - (h, w), the output size will be matched to this. If size is an int, - the smaller edge of the image will be matched to this number maintaining - the aspect ratio. i.e, if height > width, then image will be rescaled to - :math:`\left(\text{size} \times \frac{\text{height}}{\text{width}}, \text{size}\right)` - interpolation (int, optional): Desired interpolation. Default is - ``PIL.Image.BILINEAR`` - - Returns: - PIL Image: Resized image. - """ - - if isinstance(size, int): - w, h = img.size - if (w <= h and w == size) or (h <= w and h == size): - return img - if w < h: - ow = size - oh = int(size * h / w) - return img.resize((ow, oh), interpolation) - else: - oh = size - ow = int(size * w / h) - return img.resize((ow, oh), interpolation) - else: - return img.resize(size[::-1], interpolation) - - -def center_crop(img, out_height, out_width): - height, width, _ = img.shape - left = int((width - out_width) / 2) - right = int((width + out_width) / 2) - top = int((height - out_height) / 2) - bottom = int((height + out_height) / 2) - img = img[top:bottom, left:right] - return img - - -def preprocess(file_path, bin_path): - in_files = os.listdir(file_path) - if not os.path.exists(bin_path): - os.makedirs(bin_path) - i = 0 - - resize_size = 256 - mean = [0.485, 0.456, 0.406] - std = [0.229, 0.224, 0.225] - - for file in in_files: - i = i + 1 - print(file, "===", i) - - img = Image.open(os.path.join(file_path, file)).convert('RGB') - - img = resize(img, resize_size) # transforms.Resize(256) - img = np.array(img, dtype=np.float32) - img = center_crop(img, 224, 224) # transforms.CenterCrop(224) - img = img / 255. # transforms.ToTensor() - # 均值方差 - img[..., 0] -= mean[0] - img[..., 1] -= mean[1] - img[..., 2] -= mean[2] - img[..., 0] /= std[0] - img[..., 1] /= std[1] - img[..., 2] /= std[2] - img = img.transpose(2, 0, 1) # HWC -> CHW - - img.tofile(os.path.join(bin_path, file.split('.')[0] + '.bin')) - - -if __name__ == "__main__": - file_path = os.path.abspath(sys.argv[1]) - bin_path = os.path.abspath(sys.argv[2]) - preprocess(file_path, bin_path) +import os +import sys +import numpy as np +from PIL import Image + + +def resize(img, size, interpolation=Image.BILINEAR): + r"""Resize the input PIL Image to the given size. + + Args: + img (PIL Image): Image to be resized. + size (sequence or int): Desired output size. If size is a sequence like + (h, w), the output size will be matched to this. If size is an int, + the smaller edge of the image will be matched to this number maintaining + the aspect ratio. i.e, if height > width, then image will be rescaled to + :math:`\left(\text{size} \times \frac{\text{height}}{\text{width}}, \text{size}\right)` + interpolation (int, optional): Desired interpolation. Default is + ``PIL.Image.BILINEAR`` + + Returns: + PIL Image: Resized image. + """ + + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def center_crop(img, out_height, out_width): + height, width, _ = img.shape + left = int((width - out_width) / 2) + right = int((width + out_width) / 2) + top = int((height - out_height) / 2) + bottom = int((height + out_height) / 2) + img = img[top:bottom, left:right] + return img + + +def preprocess(file_path, bin_path): + in_files = os.listdir(file_path) + if not os.path.exists(bin_path): + os.makedirs(bin_path) + i = 0 + + resize_size = 256 + mean = [0.485, 0.456, 0.406] + std = [0.229, 0.224, 0.225] + + for file in in_files: + i = i + 1 + print(file, "===", i) + + img = Image.open(os.path.join(file_path, file)).convert('RGB') + + img = resize(img, resize_size) # transforms.Resize(256) + img = np.array(img, dtype=np.float32) + img = center_crop(img, 224, 224) # transforms.CenterCrop(224) + img = img / 255. # transforms.ToTensor() + # 均值方差 + img[..., 0] -= mean[0] + img[..., 1] -= mean[1] + img[..., 2] -= mean[2] + img[..., 0] /= std[0] + img[..., 1] /= std[1] + img[..., 2] /= std[2] + img = img.transpose(2, 0, 1) # HWC -> CHW + + img.tofile(os.path.join(bin_path, file.split('.')[0] + '.bin')) + + +if __name__ == "__main__": + file_path = os.path.abspath(sys.argv[1]) + bin_path = os.path.abspath(sys.argv[2]) + preprocess(file_path, bin_path) diff --git a/ACL_PyTorch/built-in/cv/InceptionV3_for_Pytorch/ReadMe.md b/ACL_PyTorch/built-in/cv/InceptionV3_for_Pytorch/ReadMe.md index ec24e9ba99..ffd9dfc52a 100644 --- a/ACL_PyTorch/built-in/cv/InceptionV3_for_Pytorch/ReadMe.md +++ b/ACL_PyTorch/built-in/cv/InceptionV3_for_Pytorch/ReadMe.md @@ -1,95 +1,95 @@ -文件作用说明: - -1. inceptionv3_pth2onnx.py:用于转换pth模型文件到onnx模型文件 -2. gen_calibration_bin.py:生成bin格式数据集脚本,数据集用于量化校准 -3. inceptionv3_atc.sh:onnx模型转换om模型脚本 -4. imagenet_torch_preprocess.py:数据集预处理脚本,对图片进行缩放裁剪,生成图片二进制文件 -5. aipp_inceptionv3_pth.config:数据集aipp预处理配置文件 -6. gen_dataset_info.py:生成推理输入的数据集二进制info文件 -7. env.sh:环境变量文件 -8. benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer -9. vision_metric_ImageNet.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy - - - -推理端到端步骤: - -1. 从Torchvision下载inceptionv3模型,通过inceptionv3_pth2onnx.py脚本转化为onnx模型 - -2. ONNX模型量化 - - 1. AMCT工具包安装,具体参考《[CANN 开发辅助工具指南 01](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools)》中的昇腾模型压缩工具使用指南(ONNX)章节; - - 2. 生成bin格式数据集,数据集用于校正量化因子。当前模型为动态batch,建议使用较大的batch size: - - ``` - python3.7 gen_calibration_bin.py inceptionv3 /root/dataset/ImageNet/val_union ./calibration_bin 32 1 - ``` - - 参数说明: - - - inceptionv3:模型类型 - - /root/dataset/ImageNet/val_union :模型使用的数据集路径; - - ./calibration_bin:生成的bin格式数据集路径; - - 32:batch size; - - 1:batch num。 - - 3. ONNX模型量化 - - ``` - amct_onnx calibration --model inceptionv3.onnx --save_path ./result/inceptionv3 --input_shape "actual_input_1:32,3,299,299" --data_dir "./calibration_bin" --data_types "float32" - ``` - - 会在result目录下生成inceptionv3_deploy_model.onnx量化模型 - - 4. 量化模型后续的推理验证流程和非量化一致。 - -3. 运行inceptionv3_atc.sh脚本转换om模型 - -4. 用imagenet_torch_preprocess.py脚本处理数据集 - -``` -python3.7 imagenet_torch_preprocess.py inceptionv3 /root/dataset/ImageNet/val_union ./prep_dataset -``` - -5. 生成推理输入的数据集二进制info文件 - -``` -python3.7 gen_dataset_info.py bin ./prep_dataset ./inceptionv3_prep_bin.info 299 299 -``` - -6. 设置环境变量 - -``` -source env.sh -``` - -7. 使用benchmark离线推理 - -``` -./benchmark.x86_64 -model_type=vision -om_path=inceptionv3_bs8.om -device_id=0 -batch_size=8 -input_text_path=inceptionv3_prep_bin.info -input_width=299 -input_height=299 -output_binary=False -useDvpp=False -``` - -运行benchmark推理,结果保存在 ./result 目录下 - -8. 验证推理结果 - -``` -python3.7 vision_metric_ImageNet.py result/dumpOutput_device0/ /root/dataset/ImageNet/val_label.txt ./ result.json -``` - - - - -模型获取 - -可以使用如下命令获取PyTorch框架的原始模型和转换后的Onnx模型 - -Pytorch: -``` -wget https://modelzoo-train-atc.obs.cn-north-4.myhuaweicloud.com/003_Atc_Models/AE/ATC%20Model/InceptionV3/inception_v3.pth -``` -ONNX: -``` -wget https://modelzoo-train-atc.obs.cn-north-4.myhuaweicloud.com/003_Atc_Models/AE/ATC%20Model/InceptionV3/inceptionv3.onnx -``` +文件作用说明: + +1. inceptionv3_pth2onnx.py:用于转换pth模型文件到onnx模型文件 +2. gen_calibration_bin.py:生成bin格式数据集脚本,数据集用于量化校准 +3. inceptionv3_atc.sh:onnx模型转换om模型脚本 +4. imagenet_torch_preprocess.py:数据集预处理脚本,对图片进行缩放裁剪,生成图片二进制文件 +5. aipp_inceptionv3_pth.config:数据集aipp预处理配置文件 +6. gen_dataset_info.py:生成推理输入的数据集二进制info文件 +7. env.sh:环境变量文件 +8. benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer +9. vision_metric_ImageNet.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy + + + +推理端到端步骤: + +1. 从Torchvision下载inceptionv3模型,通过inceptionv3_pth2onnx.py脚本转化为onnx模型 + +2. ONNX模型量化 + + 1. AMCT工具包安装,具体参考《[CANN 开发辅助工具指南 01](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools)》中的昇腾模型压缩工具使用指南(ONNX)章节; + + 2. 生成bin格式数据集,数据集用于校正量化因子。当前模型为动态batch,建议使用较大的batch size: + + ``` + python3.7 gen_calibration_bin.py inceptionv3 /root/dataset/ImageNet/val_union ./calibration_bin 32 1 + ``` + + 参数说明: + + - inceptionv3:模型类型 + - /root/dataset/ImageNet/val_union :模型使用的数据集路径; + - ./calibration_bin:生成的bin格式数据集路径; + - 32:batch size; + - 1:batch num。 + + 3. ONNX模型量化 + + ``` + amct_onnx calibration --model inceptionv3.onnx --save_path ./result/inceptionv3 --input_shape "actual_input_1:32,3,299,299" --data_dir "./calibration_bin" --data_types "float32" + ``` + + 会在result目录下生成inceptionv3_deploy_model.onnx量化模型 + + 4. 量化模型后续的推理验证流程和非量化一致。 + +3. 运行inceptionv3_atc.sh脚本转换om模型 + +4. 用imagenet_torch_preprocess.py脚本处理数据集 + +``` +python3.7 imagenet_torch_preprocess.py inceptionv3 /root/dataset/ImageNet/val_union ./prep_dataset +``` + +5. 生成推理输入的数据集二进制info文件 + +``` +python3.7 gen_dataset_info.py bin ./prep_dataset ./inceptionv3_prep_bin.info 299 299 +``` + +6. 设置环境变量 + +``` +source env.sh +``` + +7. 使用benchmark离线推理 + +``` +./benchmark.x86_64 -model_type=vision -om_path=inceptionv3_bs8.om -device_id=0 -batch_size=8 -input_text_path=inceptionv3_prep_bin.info -input_width=299 -input_height=299 -output_binary=False -useDvpp=False +``` + +运行benchmark推理,结果保存在 ./result 目录下 + +8. 验证推理结果 + +``` +python3.7 vision_metric_ImageNet.py result/dumpOutput_device0/ /root/dataset/ImageNet/val_label.txt ./ result.json +``` + + + + +模型获取 + +可以使用如下命令获取PyTorch框架的原始模型和转换后的Onnx模型 + +Pytorch: +``` +wget https://modelzoo-train-atc.obs.cn-north-4.myhuaweicloud.com/003_Atc_Models/AE/ATC%20Model/InceptionV3/inception_v3.pth +``` +ONNX: +``` +wget https://modelzoo-train-atc.obs.cn-north-4.myhuaweicloud.com/003_Atc_Models/AE/ATC%20Model/InceptionV3/inceptionv3.onnx +``` diff --git a/ACL_PyTorch/built-in/cv/InceptionV3_for_Pytorch/gen_dataset_info.py b/ACL_PyTorch/built-in/cv/InceptionV3_for_Pytorch/gen_dataset_info.py index 61450b4410..5381839f65 100644 --- a/ACL_PyTorch/built-in/cv/InceptionV3_for_Pytorch/gen_dataset_info.py +++ b/ACL_PyTorch/built-in/cv/InceptionV3_for_Pytorch/gen_dataset_info.py @@ -1,61 +1,61 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' - get_jpg_info(file_path, info_name) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' + get_jpg_info(file_path, info_name) + diff --git a/ACL_PyTorch/built-in/cv/InceptionV3_for_Pytorch/imagenet_torch_preprocess.py b/ACL_PyTorch/built-in/cv/InceptionV3_for_Pytorch/imagenet_torch_preprocess.py index ed4b4e2a53..6f89d347b5 100644 --- a/ACL_PyTorch/built-in/cv/InceptionV3_for_Pytorch/imagenet_torch_preprocess.py +++ b/ACL_PyTorch/built-in/cv/InceptionV3_for_Pytorch/imagenet_torch_preprocess.py @@ -1,113 +1,113 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -from PIL import Image -import numpy as np -import multiprocessing - - -model_config = { - 'resnet': { - 'resize': 256, - 'centercrop': 224, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv3': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv4': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.5, 0.5, 0.5], - 'std': [0.5, 0.5, 0.5], - }, -} - - -def center_crop(img, output_size): - if isinstance(output_size, int): - output_size = (int(output_size), int(output_size)) - image_width, image_height = img.size - crop_height, crop_width = output_size - crop_top = int(round((image_height - crop_height) / 2.)) - crop_left = int(round((image_width - crop_width) / 2.)) - return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) - - -def resize(img, size, interpolation=Image.BILINEAR): - if isinstance(size, int): - w, h = img.size - if (w <= h and w == size) or (h <= w and h == size): - return img - if w < h: - ow = size - oh = int(size * h / w) - return img.resize((ow, oh), interpolation) - else: - oh = size - ow = int(size * w / h) - return img.resize((ow, oh), interpolation) - else: - return img.resize(size[::-1], interpolation) - - -def gen_input_bin(mode_type, file_batches, batch): - i = 0 - for file in file_batches[batch]: - i = i + 1 - print("batch", batch, file, "===", i) - - # RGBA to RGB - image = Image.open(os.path.join(src_path, file)).convert('RGB') - image = resize(image, model_config[mode_type]['resize']) # Resize - image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop - img = np.array(image, dtype=np.int8) - img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) - - -def preprocess(mode_type, src_path, save_path): - files = os.listdir(src_path) - file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] - thread_pool = multiprocessing.Pool(len(file_batches)) - for batch in range(len(file_batches)): - thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) - thread_pool.close() - thread_pool.join() - print("in thread, except will not report! please ensure bin files generated.") - - -if __name__ == '__main__': - if len(sys.argv) < 4: - raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") - mode_type = sys.argv[1] - src_path = sys.argv[2] - save_path = sys.argv[3] - src_path = os.path.realpath(src_path) - save_path = os.path.realpath(save_path) - if mode_type not in model_config: - model_type_help = "model type: " - for key in model_config.keys(): - model_type_help += key - model_type_help += ' ' - raise Exception(model_type_help) - if not os.path.isdir(save_path): - os.makedirs(os.path.realpath(save_path)) - preprocess(mode_type, src_path, save_path) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +from PIL import Image +import numpy as np +import multiprocessing + + +model_config = { + 'resnet': { + 'resize': 256, + 'centercrop': 224, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv3': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv4': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.5, 0.5, 0.5], + 'std': [0.5, 0.5, 0.5], + }, +} + + +def center_crop(img, output_size): + if isinstance(output_size, int): + output_size = (int(output_size), int(output_size)) + image_width, image_height = img.size + crop_height, crop_width = output_size + crop_top = int(round((image_height - crop_height) / 2.)) + crop_left = int(round((image_width - crop_width) / 2.)) + return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) + + +def resize(img, size, interpolation=Image.BILINEAR): + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def gen_input_bin(mode_type, file_batches, batch): + i = 0 + for file in file_batches[batch]: + i = i + 1 + print("batch", batch, file, "===", i) + + # RGBA to RGB + image = Image.open(os.path.join(src_path, file)).convert('RGB') + image = resize(image, model_config[mode_type]['resize']) # Resize + image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop + img = np.array(image, dtype=np.int8) + img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) + + +def preprocess(mode_type, src_path, save_path): + files = os.listdir(src_path) + file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] + thread_pool = multiprocessing.Pool(len(file_batches)) + for batch in range(len(file_batches)): + thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) + thread_pool.close() + thread_pool.join() + print("in thread, except will not report! please ensure bin files generated.") + + +if __name__ == '__main__': + if len(sys.argv) < 4: + raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") + mode_type = sys.argv[1] + src_path = sys.argv[2] + save_path = sys.argv[3] + src_path = os.path.realpath(src_path) + save_path = os.path.realpath(save_path) + if mode_type not in model_config: + model_type_help = "model type: " + for key in model_config.keys(): + model_type_help += key + model_type_help += ' ' + raise Exception(model_type_help) + if not os.path.isdir(save_path): + os.makedirs(os.path.realpath(save_path)) + preprocess(mode_type, src_path, save_path) + diff --git a/ACL_PyTorch/built-in/cv/InceptionV3_for_Pytorch/requirements.txt b/ACL_PyTorch/built-in/cv/InceptionV3_for_Pytorch/requirements.txt index 112989ef5d..1845fd8616 100644 --- a/ACL_PyTorch/built-in/cv/InceptionV3_for_Pytorch/requirements.txt +++ b/ACL_PyTorch/built-in/cv/InceptionV3_for_Pytorch/requirements.txt @@ -1,5 +1,5 @@ -torch == 1.6.0 -torchvision == 0.7.0 -onnx == 1.7.0 -numpy == 1.18.5 -Pillow == 7.2.0 +torch == 1.6.0 +torchvision == 0.7.0 +onnx == 1.7.0 +numpy == 1.18.5 +Pillow == 7.2.0 diff --git a/ACL_PyTorch/built-in/cv/InceptionV4_for_Pytorch/ReadMe.md b/ACL_PyTorch/built-in/cv/InceptionV4_for_Pytorch/ReadMe.md index 6cab509671..287a11d8a2 100644 --- a/ACL_PyTorch/built-in/cv/InceptionV4_for_Pytorch/ReadMe.md +++ b/ACL_PyTorch/built-in/cv/InceptionV4_for_Pytorch/ReadMe.md @@ -1,63 +1,63 @@ -文件作用说明: - -1.inceptionv4_pth2onnx.py:用于转换pth模型文件到onnx模型文件 - -2.inceptionv4_atc.sh:onnx模型转换om模型脚本 - -3.preprocess_inceptionv4_pth.py:数据集预处理脚本,通过均值方差处理归一化图片,生成图片二进制文件 - -4.aipp_inceptionv4_pth.config:数据集aipp预处理配置文件 - -5.get_info.py:生成推理输入的数据集二进制info文件或jpg info文件 - -6.inceptionv4_val.info:ImageNet验证集二进制info文件,用于benchmark推理获取数据集 - -7.ImageNet.info:ImageNet验证集jpg info文件,用于benchmark推理获取数据集 - -8.val_label.txt:ImageNet数据集标签,用于验证推理结果 - -9.benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer - -10.vision_metric_ImageNet.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy - - - - - -推理端到端步骤: - -(1) 从https://github.com/Cadene/pretrained-models.pytorch下载inceptionv4模型,通过inceptionv4_pth2onnx.py脚本转化为onnx模型 - 安装pretrainedmodels后需修改pretrained-models.pytorch/pretrainedmodels/models/inceptionv4.py:adaptiveAvgPoolWidth = features.shape[2].item() - - - -(2)运行inceptionv4_atc.sh脚本转换om模型 - -本demo已提供调优完成的om模型 - - - -(3)用preprocess_inceptionv4_pth.py脚本处理数据集,参考inceptionv4_val.info配置处理后的二进制数据集路径。或者配置数据集aipp预处理文件aipp_inceptionv4_pth.config。 - python3 preprocess_inceptionv4_pth.py dataset/ImageNet/val_union/ prep_bin - - - -(4)生成推理输入的数据集二进制info文件或jpg info文件 - python3 get_info.py bin prep_bin inceptionv4_val.info 299 299 - python3 get_info.py jpg dataset/ImageNet/val_union ImageNet.info - - - -(5)使用benchmark离线推理 - ./benchmark -model_type=vision -om_path=inceptionv4_bs16.om -device_id=0 -batch_size=16 -input_text_path=inceptionv4_val.info -input_width=299 -input_height=299 -useDvpp=false - 或者 - ./benchmark -model_type=vision -om_path=inceptionv4_bs1.om -device_id=0 -batch_size=1 -input_text_path=ImageNet.info -input_width=336 -input_height=336 -useDvpp=true - -运行benchmark推理,结果保存在 ./result 目录下 - - - -(6)python3.7 vision_metric_ImageNet.py result/dumpOutput_device0/ ./val_label.txt ./ result.json - -验证推理结果 - +文件作用说明: + +1.inceptionv4_pth2onnx.py:用于转换pth模型文件到onnx模型文件 + +2.inceptionv4_atc.sh:onnx模型转换om模型脚本 + +3.preprocess_inceptionv4_pth.py:数据集预处理脚本,通过均值方差处理归一化图片,生成图片二进制文件 + +4.aipp_inceptionv4_pth.config:数据集aipp预处理配置文件 + +5.get_info.py:生成推理输入的数据集二进制info文件或jpg info文件 + +6.inceptionv4_val.info:ImageNet验证集二进制info文件,用于benchmark推理获取数据集 + +7.ImageNet.info:ImageNet验证集jpg info文件,用于benchmark推理获取数据集 + +8.val_label.txt:ImageNet数据集标签,用于验证推理结果 + +9.benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer + +10.vision_metric_ImageNet.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy + + + + + +推理端到端步骤: + +(1) 从https://github.com/Cadene/pretrained-models.pytorch下载inceptionv4模型,通过inceptionv4_pth2onnx.py脚本转化为onnx模型 + 安装pretrainedmodels后需修改pretrained-models.pytorch/pretrainedmodels/models/inceptionv4.py:adaptiveAvgPoolWidth = features.shape[2].item() + + + +(2)运行inceptionv4_atc.sh脚本转换om模型 + +本demo已提供调优完成的om模型 + + + +(3)用preprocess_inceptionv4_pth.py脚本处理数据集,参考inceptionv4_val.info配置处理后的二进制数据集路径。或者配置数据集aipp预处理文件aipp_inceptionv4_pth.config。 + python3 preprocess_inceptionv4_pth.py dataset/ImageNet/val_union/ prep_bin + + + +(4)生成推理输入的数据集二进制info文件或jpg info文件 + python3 get_info.py bin prep_bin inceptionv4_val.info 299 299 + python3 get_info.py jpg dataset/ImageNet/val_union ImageNet.info + + + +(5)使用benchmark离线推理 + ./benchmark -model_type=vision -om_path=inceptionv4_bs16.om -device_id=0 -batch_size=16 -input_text_path=inceptionv4_val.info -input_width=299 -input_height=299 -useDvpp=false + 或者 + ./benchmark -model_type=vision -om_path=inceptionv4_bs1.om -device_id=0 -batch_size=1 -input_text_path=ImageNet.info -input_width=336 -input_height=336 -useDvpp=true + +运行benchmark推理,结果保存在 ./result 目录下 + + + +(6)python3.7 vision_metric_ImageNet.py result/dumpOutput_device0/ ./val_label.txt ./ result.json + +验证推理结果 + diff --git a/ACL_PyTorch/built-in/cv/InceptionV4_for_Pytorch/get_info.py b/ACL_PyTorch/built-in/cv/InceptionV4_for_Pytorch/get_info.py index 0578e4f00c..7b14c54b90 100644 --- a/ACL_PyTorch/built-in/cv/InceptionV4_for_Pytorch/get_info.py +++ b/ACL_PyTorch/built-in/cv/InceptionV4_for_Pytorch/get_info.py @@ -1,46 +1,46 @@ -import os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +import os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/InceptionV4_for_Pytorch/preprocess_inceptionv4_pth.py b/ACL_PyTorch/built-in/cv/InceptionV4_for_Pytorch/preprocess_inceptionv4_pth.py index bf9f930b05..591fdb1db1 100644 --- a/ACL_PyTorch/built-in/cv/InceptionV4_for_Pytorch/preprocess_inceptionv4_pth.py +++ b/ACL_PyTorch/built-in/cv/InceptionV4_for_Pytorch/preprocess_inceptionv4_pth.py @@ -1,85 +1,85 @@ -import os -import sys -import numpy as np -from PIL import Image - - -def resize(img, size, interpolation=Image.BILINEAR): - r"""Resize the input PIL Image to the given size. - - Args: - img (PIL Image): Image to be resized. - size (sequence or int): Desired output size. If size is a sequence like - (h, w), the output size will be matched to this. If size is an int, - the smaller edge of the image will be matched to this number maintaining - the aspect ratio. i.e, if height > width, then image will be rescaled to - :math:`\left(\text{size} \times \frac{\text{height}}{\text{width}}, \text{size}\right)` - interpolation (int, optional): Desired interpolation. Default is - ``PIL.Image.BILINEAR`` - - Returns: - PIL Image: Resized image. - """ - - if isinstance(size, int): - w, h = img.size - if (w <= h and w == size) or (h <= w and h == size): - return img - if w < h: - ow = size - oh = int(size * h / w) - return img.resize((ow, oh), interpolation) - else: - oh = size - ow = int(size * w / h) - return img.resize((ow, oh), interpolation) - else: - return img.resize(size[::-1], interpolation) - - -def center_crop(img, out_height, out_width): - height, width, _ = img.shape - left = int((width - out_width) / 2) - right = int((width + out_width) / 2) - top = int((height - out_height) / 2) - bottom = int((height + out_height) / 2) - img = img[top:bottom, left:right] - return img - - -def preprocess(file_path, bin_path): - in_files = os.listdir(file_path) - if not os.path.exists(bin_path): - os.makedirs(bin_path) - i = 0 - - resize_size = 342 - mean = [0.5, 0.5, 0.5] - std = [0.5, 0.5, 0.5] - - for file in in_files: - i = i + 1 - print(file, "===", i) - - img = Image.open(os.path.join(file_path, file)).convert('RGB') - - img = resize(img, resize_size) # transforms.Resize(342) - img = np.array(img, dtype=np.float32) - img = center_crop(img, 299, 299) # transforms.CenterCrop(299) - img = img / 255. # transforms.ToTensor() - # 均值方差 - img[..., 0] -= mean[0] - img[..., 1] -= mean[1] - img[..., 2] -= mean[2] - img[..., 0] /= std[0] - img[..., 1] /= std[1] - img[..., 2] /= std[2] - img = img.transpose(2, 0, 1) # HWC -> CHW - - img.tofile(os.path.join(bin_path, file.split('.')[0] + '.bin')) - - -if __name__ == "__main__": - file_path = os.path.abspath(sys.argv[1]) - bin_path = os.path.abspath(sys.argv[2]) - preprocess(file_path, bin_path) +import os +import sys +import numpy as np +from PIL import Image + + +def resize(img, size, interpolation=Image.BILINEAR): + r"""Resize the input PIL Image to the given size. + + Args: + img (PIL Image): Image to be resized. + size (sequence or int): Desired output size. If size is a sequence like + (h, w), the output size will be matched to this. If size is an int, + the smaller edge of the image will be matched to this number maintaining + the aspect ratio. i.e, if height > width, then image will be rescaled to + :math:`\left(\text{size} \times \frac{\text{height}}{\text{width}}, \text{size}\right)` + interpolation (int, optional): Desired interpolation. Default is + ``PIL.Image.BILINEAR`` + + Returns: + PIL Image: Resized image. + """ + + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def center_crop(img, out_height, out_width): + height, width, _ = img.shape + left = int((width - out_width) / 2) + right = int((width + out_width) / 2) + top = int((height - out_height) / 2) + bottom = int((height + out_height) / 2) + img = img[top:bottom, left:right] + return img + + +def preprocess(file_path, bin_path): + in_files = os.listdir(file_path) + if not os.path.exists(bin_path): + os.makedirs(bin_path) + i = 0 + + resize_size = 342 + mean = [0.5, 0.5, 0.5] + std = [0.5, 0.5, 0.5] + + for file in in_files: + i = i + 1 + print(file, "===", i) + + img = Image.open(os.path.join(file_path, file)).convert('RGB') + + img = resize(img, resize_size) # transforms.Resize(342) + img = np.array(img, dtype=np.float32) + img = center_crop(img, 299, 299) # transforms.CenterCrop(299) + img = img / 255. # transforms.ToTensor() + # 均值方差 + img[..., 0] -= mean[0] + img[..., 1] -= mean[1] + img[..., 2] -= mean[2] + img[..., 0] /= std[0] + img[..., 1] /= std[1] + img[..., 2] /= std[2] + img = img.transpose(2, 0, 1) # HWC -> CHW + + img.tofile(os.path.join(bin_path, file.split('.')[0] + '.bin')) + + +if __name__ == "__main__": + file_path = os.path.abspath(sys.argv[1]) + bin_path = os.path.abspath(sys.argv[2]) + preprocess(file_path, bin_path) diff --git a/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/PytorchTransfer.py b/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/PytorchTransfer.py index 15680c59ff..15eeaaa895 100644 --- a/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/PytorchTransfer.py +++ b/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/PytorchTransfer.py @@ -1,47 +1,47 @@ -import sys -import os -import torch -import cv2 -from PIL import Image -import numpy as np -import torch.utils.data -import torchvision.transforms as transforms -from torch.autograd import Variable - - -def mobilenet_onnx(input_path: str, output_path: str): - img = cv2.imread(input_path) - img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) - pilimg = Image.fromarray(img) - normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], - std=[0.229, 0.224, 0.225]) - val_transformer = transforms.Compose([ - transforms.Scale(256), - transforms.CenterCrop(224), - transforms.ToTensor(), - normalize - ]) - - img_tensor = val_transformer(pilimg) - img_tensor = torch.unsqueeze(img_tensor, dim=0).float() - img_tensor = Variable(img_tensor, requires_grad=False) - img_tensor.reshape(1, 3, 224, 224) - img_numpy = img_tensor.cpu().numpy() - - img_name = input_path.split('/')[-1] - bin_name = img_name.split('.')[0] + ".bin" - output_fl = os.path.join(output_path, bin_name) - # save img_tensor as binary file for om inference input - img_numpy.tofile(output_fl) - - -if __name__ == "__main__": - input_img_dir = sys.argv[1] - output_img_dir = sys.argv[2] - images = os.listdir(input_img_dir) - for image_name in images: - if not image_name.endswith(".jpeg"): - continue - print("start to process image {}....".format(image_name)) - path_image = os.path.join(input_img_dir, image_name) - mobilenet_onnx(path_image, output_img_dir) +import sys +import os +import torch +import cv2 +from PIL import Image +import numpy as np +import torch.utils.data +import torchvision.transforms as transforms +from torch.autograd import Variable + + +def mobilenet_onnx(input_path: str, output_path: str): + img = cv2.imread(input_path) + img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + pilimg = Image.fromarray(img) + normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]) + val_transformer = transforms.Compose([ + transforms.Scale(256), + transforms.CenterCrop(224), + transforms.ToTensor(), + normalize + ]) + + img_tensor = val_transformer(pilimg) + img_tensor = torch.unsqueeze(img_tensor, dim=0).float() + img_tensor = Variable(img_tensor, requires_grad=False) + img_tensor.reshape(1, 3, 224, 224) + img_numpy = img_tensor.cpu().numpy() + + img_name = input_path.split('/')[-1] + bin_name = img_name.split('.')[0] + ".bin" + output_fl = os.path.join(output_path, bin_name) + # save img_tensor as binary file for om inference input + img_numpy.tofile(output_fl) + + +if __name__ == "__main__": + input_img_dir = sys.argv[1] + output_img_dir = sys.argv[2] + images = os.listdir(input_img_dir) + for image_name in images: + if not image_name.endswith(".jpeg"): + continue + print("start to process image {}....".format(image_name)) + path_image = os.path.join(input_img_dir, image_name) + mobilenet_onnx(path_image, output_img_dir) diff --git a/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/ReadMe.md b/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/ReadMe.md index 2d95c4d9fe..37b1c85638 100644 --- a/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/ReadMe.md +++ b/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/ReadMe.md @@ -1,48 +1,48 @@ -文件作用说明: - -1.auto_tune.sh:模型转换脚本,集成了auto tune功能,可以手动关闭 - -2.pth2onnx.py:用于转换pth文件到onnx文件 - -3.pthtar2onnx.py:用于转换pth.tar文件到onnx文件 - -4.BinaryImageNet.info:ImageNet数据集信息,用于benchmark推理获取数据集 - -5.PytorchTransfer.py:数据集预处理脚本,通过均值方差处理归一化图片 - -6.val_label.txt:ImageNet数据集标签,用于验证推理结果 - -7.vision_metric_ImageNet.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy - -8.benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer - - - - - -推理端到端步骤: - -(1) 从Torchvision下载mobilenetV2模型或者指定自己训练好的pth文件路径,通过pth2onnx.py脚本转化为onnx模型 - - - -(2)运行auto_tune.sh脚本转换om模型,也可以选择手动关闭auto_tune - -本demo已提供调优完成的om模型 - - - -(3)用PytorchTransfer.py脚本处理数据集,参考BinaryImageNet.Info配置处理后的二进制数据集路径 - - - -(4)./benchmark.x86_64 -model_type=vision -batch_size=16 -device_id=0 -input_text_path=./BinaryImageNet.info -input_width=224 -input_height=224 -om_path=./resnet50_pytorch.om -useDvpp=False - -运行benchmark推理,结果保存在 ./result 目录下 - - - -(5)python3.7 vision_metric_ImageNet.py result/dumpOutput/ ./val_label.txt ./ result.json - -验证推理结果 - +文件作用说明: + +1.auto_tune.sh:模型转换脚本,集成了auto tune功能,可以手动关闭 + +2.pth2onnx.py:用于转换pth文件到onnx文件 + +3.pthtar2onnx.py:用于转换pth.tar文件到onnx文件 + +4.BinaryImageNet.info:ImageNet数据集信息,用于benchmark推理获取数据集 + +5.PytorchTransfer.py:数据集预处理脚本,通过均值方差处理归一化图片 + +6.val_label.txt:ImageNet数据集标签,用于验证推理结果 + +7.vision_metric_ImageNet.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy + +8.benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer + + + + + +推理端到端步骤: + +(1) 从Torchvision下载mobilenetV2模型或者指定自己训练好的pth文件路径,通过pth2onnx.py脚本转化为onnx模型 + + + +(2)运行auto_tune.sh脚本转换om模型,也可以选择手动关闭auto_tune + +本demo已提供调优完成的om模型 + + + +(3)用PytorchTransfer.py脚本处理数据集,参考BinaryImageNet.Info配置处理后的二进制数据集路径 + + + +(4)./benchmark.x86_64 -model_type=vision -batch_size=16 -device_id=0 -input_text_path=./BinaryImageNet.info -input_width=224 -input_height=224 -om_path=./resnet50_pytorch.om -useDvpp=False + +运行benchmark推理,结果保存在 ./result 目录下 + + + +(5)python3.7 vision_metric_ImageNet.py result/dumpOutput/ ./val_label.txt ./ result.json + +验证推理结果 + diff --git a/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/pth2onnx.py b/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/pth2onnx.py index e147398b6d..8b54912bf9 100644 --- a/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/pth2onnx.py +++ b/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/pth2onnx.py @@ -1,27 +1,27 @@ -import torch -import torch.onnx -import torchvision.models as models - - -def convert(): - model = models.mobilenet_v2(pretrained=False) - pthfile = './mobilenet_v2-b0353104.pth' - mobilenet_v2 = torch.load(pthfile, map_location='cpu') - model.load_state_dict(mobilenet_v2) - print(model) - - input_names = ["actual_input_1"] - output_names = ["output1"] - dummy_input = torch.randn(16, 3, 224, 224) - torch.onnx.export( - model, - dummy_input, - "mobilenet_v2_16.onnx", - input_names=input_names, - output_names=output_names, - opset_version=11) - - -if __name__ == "__main__": - convert() - +import torch +import torch.onnx +import torchvision.models as models + + +def convert(): + model = models.mobilenet_v2(pretrained=False) + pthfile = './mobilenet_v2-b0353104.pth' + mobilenet_v2 = torch.load(pthfile, map_location='cpu') + model.load_state_dict(mobilenet_v2) + print(model) + + input_names = ["actual_input_1"] + output_names = ["output1"] + dummy_input = torch.randn(16, 3, 224, 224) + torch.onnx.export( + model, + dummy_input, + "mobilenet_v2_16.onnx", + input_names=input_names, + output_names=output_names, + opset_version=11) + + +if __name__ == "__main__": + convert() + diff --git a/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/pthtar2onnx.py b/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/pthtar2onnx.py index ba5c4a2a59..96cfdc8372 100644 --- a/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/pthtar2onnx.py +++ b/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/pthtar2onnx.py @@ -1,41 +1,41 @@ -import torch -import torch.onnx -import mobilenet -from collections import OrderedDict - - -def proc_nodes_module(checkpoint, attr_name): - new_state_dict = OrderedDict() - for key, value in checkpoint[attr_name].items(): - if key == "module.features.0.0.weight": - print(value) - if key[0:7] == "module.": - name = key[7:] - else: - name = key[0:] - - new_state_dict[name] = value - return new_state_dict - - -def convert(): - checkpoint = torch.load("./mobilenet_cpu.pth.tar", map_location=torch.device('cpu')) - checkpoint['state_dict'] = proc_nodes_module(checkpoint, 'state_dict') - model = mobilenet.mobilenet_v2(pretrained=False) - model.load_state_dict(checkpoint['state_dict']) - model.eval() - print(model) - - input_names = ["actual_input_1"] - output_names = ["output1"] - dummy_input = torch.randn(1, 3, 224, 224) - torch.onnx.export( - model, dummy_input, - "mobilenet_v2_npu.onnx", - input_names=input_names, - output_names=output_names, - opset_version=11) # 7 - - -if __name__ == "__main__": - convert() +import torch +import torch.onnx +import mobilenet +from collections import OrderedDict + + +def proc_nodes_module(checkpoint, attr_name): + new_state_dict = OrderedDict() + for key, value in checkpoint[attr_name].items(): + if key == "module.features.0.0.weight": + print(value) + if key[0:7] == "module.": + name = key[7:] + else: + name = key[0:] + + new_state_dict[name] = value + return new_state_dict + + +def convert(): + checkpoint = torch.load("./mobilenet_cpu.pth.tar", map_location=torch.device('cpu')) + checkpoint['state_dict'] = proc_nodes_module(checkpoint, 'state_dict') + model = mobilenet.mobilenet_v2(pretrained=False) + model.load_state_dict(checkpoint['state_dict']) + model.eval() + print(model) + + input_names = ["actual_input_1"] + output_names = ["output1"] + dummy_input = torch.randn(1, 3, 224, 224) + torch.onnx.export( + model, dummy_input, + "mobilenet_v2_npu.onnx", + input_names=input_names, + output_names=output_names, + opset_version=11) # 7 + + +if __name__ == "__main__": + convert() diff --git a/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/vision_metric_ImageNet.py b/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/vision_metric_ImageNet.py index 7bba5f8346..f07c93617e 100644 --- a/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/vision_metric_ImageNet.py +++ b/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch/vision_metric_ImageNet.py @@ -1,173 +1,173 @@ -#coding = utf-8 -import os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = "" - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - #print(filepath) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - #print(img_gt_dict) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - # print(img_name) - #print(n_labels) - # print(gt) - - resCnt = min(len(sort_index), topn) - # print(sort_index[:5]) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - #print("***************") - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - #print("Top" + str(i + 1) + " accuracy" + ": " + str(round(accuracy[i] * 100, 2)) + '%') - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) - #print("Time used:", elapsed) +#coding = utf-8 +import os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = "" + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + #print(filepath) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + #print(img_gt_dict) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + # print(img_name) + #print(n_labels) + # print(gt) + + resCnt = min(len(sort_index), topn) + # print(sort_index[:5]) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + #print("***************") + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + #print("Top" + str(i + 1) + " accuracy" + ": " + str(round(accuracy[i] * 100, 2)) + '%') + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) + #print("Time used:", elapsed) diff --git a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/README.md b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/README.md index 66128e38a6..151e89d974 100644 --- a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/README.md +++ b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/README.md @@ -1,9 +1,9 @@ -### demo 文件夹内容说明 -- pth转换onnx脚本: export_onnx.py -- ATC转换脚本 run.sh / auto_tune.sh,及aipp配置文件 aipp.conf -- benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer -- 数据集信息 ImgPSENet.info 及二进制数据集信息 PSENet.info -- 二进制数据集预处理脚本: preprocess_psenet_pytorch.py -- 数据集标签: gt.zip -- 二进制后处理脚本: pth_bintotxt_nearest.py, pth_bintotxt_bilinear.py, pypse.py -- 精度评测脚本: Post-processing文件夹,script.py +### demo 文件夹内容说明 +- pth转换onnx脚本: export_onnx.py +- ATC转换脚本 run.sh / auto_tune.sh,及aipp配置文件 aipp.conf +- benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer +- 数据集信息 ImgPSENet.info 及二进制数据集信息 PSENet.info +- 二进制数据集预处理脚本: preprocess_psenet_pytorch.py +- 数据集标签: gt.zip +- 二进制后处理脚本: pth_bintotxt_nearest.py, pth_bintotxt_bilinear.py, pypse.py +- 精度评测脚本: Post-processing文件夹,script.py diff --git a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/export_onnx.py b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/export_onnx.py index 8f0d02b154..9d5e7ed3ca 100644 --- a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/export_onnx.py +++ b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/export_onnx.py @@ -1,39 +1,39 @@ -import torch -from fpn_resnet_nearest import resnet50 -import torch.onnx -from collections import OrderedDict -import torch._utils - - -def proc_nodes_module(checkpoint, AttrName): - new_state_dict = OrderedDict() - for k, v in checkpoint[AttrName].items(): - if (k[0:7] == "module."): - name = k[7:] - else: - name = k[0:] - - new_state_dict[name] = v - return new_state_dict - - -def convert(): - checkpoint = torch.load("./PSENet_nearest.pth", map_location='cpu') - checkpoint['state_dict'] = proc_nodes_module(checkpoint, 'state_dict') - # model = mobilenet.mobilenet_v2(pretrained = False) - model = resnet50() - model.load_state_dict(checkpoint['state_dict']) - model.eval() - print(model) - - input_names = ["actual_input_1"] - output_names = ["output1"] - dummy_input = torch.randn(1, 3, 704, 1216) - import onnx - dynamic_axes = {'actual_input_1':{0:'-1'},'output1':{0:'-1'}} - print('\nStarting ONNX export with onnx %s...' % onnx.__version__) - torch.onnx.export(model, dummy_input, "PSENet_704_1216_nearest.onnx", input_names=input_names, output_names=output_names,dynamic_axes = dynamic_axes, opset_version=11) - - -if __name__ == "__main__": - convert() +import torch +from fpn_resnet_nearest import resnet50 +import torch.onnx +from collections import OrderedDict +import torch._utils + + +def proc_nodes_module(checkpoint, AttrName): + new_state_dict = OrderedDict() + for k, v in checkpoint[AttrName].items(): + if (k[0:7] == "module."): + name = k[7:] + else: + name = k[0:] + + new_state_dict[name] = v + return new_state_dict + + +def convert(): + checkpoint = torch.load("./PSENet_nearest.pth", map_location='cpu') + checkpoint['state_dict'] = proc_nodes_module(checkpoint, 'state_dict') + # model = mobilenet.mobilenet_v2(pretrained = False) + model = resnet50() + model.load_state_dict(checkpoint['state_dict']) + model.eval() + print(model) + + input_names = ["actual_input_1"] + output_names = ["output1"] + dummy_input = torch.randn(1, 3, 704, 1216) + import onnx + dynamic_axes = {'actual_input_1':{0:'-1'},'output1':{0:'-1'}} + print('\nStarting ONNX export with onnx %s...' % onnx.__version__) + torch.onnx.export(model, dummy_input, "PSENet_704_1216_nearest.onnx", input_names=input_names, output_names=output_names,dynamic_axes = dynamic_axes, opset_version=11) + + +if __name__ == "__main__": + convert() diff --git a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/fpn_resnet.py b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/fpn_resnet.py index 0305cf9e32..2ee46e1229 100644 --- a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/fpn_resnet.py +++ b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/fpn_resnet.py @@ -1,341 +1,341 @@ -import torch.nn as nn -import time -import math -import torch.utils.model_zoo as model_zoo -import torch.nn.functional as F -import torch -import pdb - - -__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', - 'resnet152'] - - -model_urls = { - 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth', - 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth', - 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth', - 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3mb4d8f.pth', - 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth', -} - - -def conv3x3(in_planes, out_planes, stride=1): - """3x3 convolution with padding""" - return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, - padding=1, bias=False) - - -class BasicBlock(nn.Module): - expansion = 1 - - def __init__(self, inplanes, planes, stride=1, downsample=None): - super(BasicBlock, self).__init__() - self.conv1 = conv3x3(inplanes, planes, stride) - self.bn1 = nn.BatchNorm2d(planes) - self.relu = nn.ReLU(inplace=True) - self.conv2 = conv3x3(planes, planes) - self.bn2 = nn.BatchNorm2d(planes) - self.downsample = downsample - self.stride = stride - - def forward(self, x): - residual = x - - out = self.conv1(x) - out = self.bn1(out) - out = self.relu(out) - - out = self.conv2(out) - out = self.bn2(out) - - if self.downsample is not None: - residual = self.downsample(x) - - out += residual - out = self.relu(out) - - return out - - -class Bottleneck(nn.Module): - expansion = 4 - - def __init__(self, inplanes, planes, stride=1, downsample=None): - super(Bottleneck, self).__init__() - self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) - self.bn1 = nn.BatchNorm2d(planes) - self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, - padding=1, bias=False) - self.bn2 = nn.BatchNorm2d(planes) - self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) - self.bn3 = nn.BatchNorm2d(planes * 4) - self.relu = nn.ReLU(inplace=True) - self.downsample = downsample - self.stride = stride - - def forward(self, x): - residual = x - - out = self.conv1(x) - out = self.bn1(out) - out = self.relu(out) - - out = self.conv2(out) - out = self.bn2(out) - out = self.relu(out) - - out = self.conv3(out) - out = self.bn3(out) - - if self.downsample is not None: - residual = self.downsample(x) - - out += residual - out = self.relu(out) - - return out - - -class ResNet(nn.Module): - - def __init__(self, block, layers, num_classes=7, scale=1): - self.inplanes = 64 - super(ResNet, self).__init__() - self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, - bias=False) - self.bn1 = nn.BatchNorm2d(64) - self.relu1 = nn.ReLU(inplace=True) - self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1, return_indices = False) - self.layer1 = self._make_layer(block, 64, layers[0]) - self.layer2 = self._make_layer(block, 128, layers[1], stride=2) - self.layer3 = self._make_layer(block, 256, layers[2], stride=2) - self.layer4 = self._make_layer(block, 512, layers[3], stride=2) - # self.avgpool = nn.AvgPool2d(7, stride=1) - # self.fc = nn.Linear(512 * block.expansion, num_classes) - - # Top layer - self.toplayer = nn.Conv2d(2048, 256, kernel_size=1, stride=1, padding=0) # Reduce channels - self.toplayer_bn = nn.BatchNorm2d(256) - self.toplayer_relu = nn.ReLU(inplace=True) - - # Smooth layers - self.smooth1 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1) - self.smooth1_bn = nn.BatchNorm2d(256) - self.smooth1_relu = nn.ReLU(inplace=True) - - self.smooth2 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1) - self.smooth2_bn = nn.BatchNorm2d(256) - self.smooth2_relu = nn.ReLU(inplace=True) - - self.smooth3 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1) - self.smooth3_bn = nn.BatchNorm2d(256) - self.smooth3_relu = nn.ReLU(inplace=True) - - # Lateral layers - self.latlayer1 = nn.Conv2d(1024, 256, kernel_size=1, stride=1, padding=0) - self.latlayer1_bn = nn.BatchNorm2d(256) - self.latlayer1_relu = nn.ReLU(inplace=True) - - self.latlayer2 = nn.Conv2d(512, 256, kernel_size=1, stride=1, padding=0) - self.latlayer2_bn = nn.BatchNorm2d(256) - self.latlayer2_relu = nn.ReLU(inplace=True) - - self.latlayer3 = nn.Conv2d(256, 256, kernel_size=1, stride=1, padding=0) - self.latlayer3_bn = nn.BatchNorm2d(256) - self.latlayer3_relu = nn.ReLU(inplace=True) - - self.conv2 = nn.Conv2d(1024, 256, kernel_size=3, stride=1, padding=1) - self.bn2 = nn.BatchNorm2d(256) - self.relu2 = nn.ReLU(inplace=True) - self.conv3 = nn.Conv2d(256, num_classes, kernel_size=1, stride=1, padding=0) - self.upsample = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True) - - self.scale = scale - - for m in self.modules(): - if isinstance(m, nn.Conv2d): - n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels - m.weight.data.normal_(0, math.sqrt(2. / n)) - elif isinstance(m, nn.BatchNorm2d): - m.weight.data.fill_(1) - m.bias.data.zero_() - - def _make_layer(self, block, planes, blocks, stride=1): - downsample = None - if stride != 1 or self.inplanes != planes * block.expansion: - downsample = nn.Sequential( - nn.Conv2d(self.inplanes, planes * block.expansion, - kernel_size=1, stride=stride, bias=False), - nn.BatchNorm2d(planes * block.expansion), - ) - - layers = [] - layers.append(block(self.inplanes, planes, stride, downsample)) - self.inplanes = planes * block.expansion - for i in range(1, blocks): - layers.append(block(self.inplanes, planes)) - - return nn.Sequential(*layers) - - def _upsample(self, x, y, scale=1): - _, _, H, W = y.size() - # return self.upsample(x) - return F.interpolate(x, size=(H // scale, W // scale), mode='bilinear', align_corners=False) - - def _upsample_add(self, x, y): - _, _, H, W = y.size() - # print(x.shape) - # print(y.shape) - # print('x:',x.type()) - # print('out:',F.interpolate(x, size=(H,W), mode='bilinear').type()) - # print('y:', y.type()) - # return self.upsample(x) + y - return F.interpolate(x, size=(H, W), mode='bilinear', align_corners=False).half() + y - - def forward(self, x): - h = x - h = self.conv1(h) - h = self.bn1(h) - h = self.relu1(h) - - h = self.maxpool(h) - - h = self.layer1(h) - c2 = h - h = self.layer2(h) - c3 = h - h = self.layer3(h) - c4 = h - h = self.layer4(h) - c5 = h - - # Top-down - p5 = self.toplayer(c5) - p5 = self.toplayer_relu(self.toplayer_bn(p5)) - - c4 = self.latlayer1(c4) - c4 = self.latlayer1_relu(self.latlayer1_bn(c4)) - t = time.time() - # print('c4:',c4.type()) - p4 = self._upsample_add(p5, c4) - p4 = self.smooth1(p4) - p4 = self.smooth1_relu(self.smooth1_bn(p4)) - - c3 = self.latlayer2(c3) - c3 = self.latlayer2_relu(self.latlayer2_bn(c3)) - t = time.time() - # print('t:',t) - p3 = self._upsample_add(p4, c3) - # print('t2:',time.time()-t) - p3 = self.smooth2(p3) - p3 = self.smooth2_relu(self.smooth2_bn(p3)) - - c2 = self.latlayer3(c2) - c2 = self.latlayer3_relu(self.latlayer3_bn(c2)) - p2 = self._upsample_add(p3, c2) - p2 = self.smooth3(p2) - p2 = self.smooth3_relu(self.smooth3_bn(p2)) - - p3 = self._upsample(p3, p2) - p4 = self._upsample(p4, p2) - p5 = self._upsample(p5, p2) - - # p2, p3, p4, p5 = p2.cpu(), p3.cpu(), p4.cpu(), p5.cpu() - out = torch.cat((p2, p3, p4, p5), 1) - # out = out.to(dev) - - - # self.conv2 = self.conv2.cpu() - out = self.conv2(out) - # self.conv2 = self.conv2.to(dev) - - # self.relu2 = self.relu2.cpu() - # self.bn2 = self.bn2.cpu() - out = self.relu2(self.bn2(out)) - # self.relu2 = self.relu2.to(dev) - # self.bn2 = self.bn2.to(dev) - - # self.conv3 = self.conv3.cpu() - out = self.conv3(out) - # self.conv3 = self.conv3.to(dev) - - # out = out.to(dev) - # p2, p3, p4, p5 = p2.to(dev), p3.to(dev), p4.to(dev), p5.to(dev) - out = self._upsample(out, x, scale=self.scale) - - return out - - -def resnet18(pretrained=False, **kwargs): - """Constructs a ResNet-18 model. - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - """ - model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs) - if pretrained: - model.load_state_dict(model_zoo.load_url(model_urls['resnet18'])) - return model - - -def resnet34(pretrained=False, **kwargs): - """Constructs a ResNet-34 model. - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - """ - model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs) - if pretrained: - model.load_state_dict(model_zoo.load_url(model_urls['resnet34'])) - return model - - -def resnet50(pretrained=False, **kwargs): - """Constructs a ResNet-50 model. - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - """ - model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs) - if pretrained: - pretrained_model = model_zoo.load_url(model_urls['resnet50']) - state = model.state_dict() - for key in state.keys(): - if key in pretrained_model.keys(): - state[key] = pretrained_model[key] - model.load_state_dict(state) - return model - - -def resnet101(pretrained=False, **kwargs): - """Constructs a ResNet-101 model. - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - """ - model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs) - if pretrained: - pretrained_model = model_zoo.load_url(model_urls['resnet101']) - state = model.state_dict() - for key in state.keys(): - if key in pretrained_model.keys(): - state[key] = pretrained_model[key] - model.load_state_dict(state) - return model - -def resnet152(pretrained=False, **kwargs): - """Constructs a ResNet-152 model. - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - """ - model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs) - if pretrained: - pretrained_model = model_zoo.load_url(model_urls['resnet152']) - state = model.state_dict() - for key in state.keys(): - if key in pretrained_model.keys(): - state[key] = pretrained_model[key] - model.load_state_dict(state) - return model +import torch.nn as nn +import time +import math +import torch.utils.model_zoo as model_zoo +import torch.nn.functional as F +import torch +import pdb + + +__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', + 'resnet152'] + + +model_urls = { + 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth', + 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth', + 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth', + 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3mb4d8f.pth', + 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth', +} + + +def conv3x3(in_planes, out_planes, stride=1): + """3x3 convolution with padding""" + return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, + padding=1, bias=False) + + +class BasicBlock(nn.Module): + expansion = 1 + + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(BasicBlock, self).__init__() + self.conv1 = conv3x3(inplanes, planes, stride) + self.bn1 = nn.BatchNorm2d(planes) + self.relu = nn.ReLU(inplace=True) + self.conv2 = conv3x3(planes, planes) + self.bn2 = nn.BatchNorm2d(planes) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class Bottleneck(nn.Module): + expansion = 4 + + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(Bottleneck, self).__init__() + self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) + self.bn1 = nn.BatchNorm2d(planes) + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, + padding=1, bias=False) + self.bn2 = nn.BatchNorm2d(planes) + self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) + self.bn3 = nn.BatchNorm2d(planes * 4) + self.relu = nn.ReLU(inplace=True) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class ResNet(nn.Module): + + def __init__(self, block, layers, num_classes=7, scale=1): + self.inplanes = 64 + super(ResNet, self).__init__() + self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, + bias=False) + self.bn1 = nn.BatchNorm2d(64) + self.relu1 = nn.ReLU(inplace=True) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1, return_indices = False) + self.layer1 = self._make_layer(block, 64, layers[0]) + self.layer2 = self._make_layer(block, 128, layers[1], stride=2) + self.layer3 = self._make_layer(block, 256, layers[2], stride=2) + self.layer4 = self._make_layer(block, 512, layers[3], stride=2) + # self.avgpool = nn.AvgPool2d(7, stride=1) + # self.fc = nn.Linear(512 * block.expansion, num_classes) + + # Top layer + self.toplayer = nn.Conv2d(2048, 256, kernel_size=1, stride=1, padding=0) # Reduce channels + self.toplayer_bn = nn.BatchNorm2d(256) + self.toplayer_relu = nn.ReLU(inplace=True) + + # Smooth layers + self.smooth1 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1) + self.smooth1_bn = nn.BatchNorm2d(256) + self.smooth1_relu = nn.ReLU(inplace=True) + + self.smooth2 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1) + self.smooth2_bn = nn.BatchNorm2d(256) + self.smooth2_relu = nn.ReLU(inplace=True) + + self.smooth3 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1) + self.smooth3_bn = nn.BatchNorm2d(256) + self.smooth3_relu = nn.ReLU(inplace=True) + + # Lateral layers + self.latlayer1 = nn.Conv2d(1024, 256, kernel_size=1, stride=1, padding=0) + self.latlayer1_bn = nn.BatchNorm2d(256) + self.latlayer1_relu = nn.ReLU(inplace=True) + + self.latlayer2 = nn.Conv2d(512, 256, kernel_size=1, stride=1, padding=0) + self.latlayer2_bn = nn.BatchNorm2d(256) + self.latlayer2_relu = nn.ReLU(inplace=True) + + self.latlayer3 = nn.Conv2d(256, 256, kernel_size=1, stride=1, padding=0) + self.latlayer3_bn = nn.BatchNorm2d(256) + self.latlayer3_relu = nn.ReLU(inplace=True) + + self.conv2 = nn.Conv2d(1024, 256, kernel_size=3, stride=1, padding=1) + self.bn2 = nn.BatchNorm2d(256) + self.relu2 = nn.ReLU(inplace=True) + self.conv3 = nn.Conv2d(256, num_classes, kernel_size=1, stride=1, padding=0) + self.upsample = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True) + + self.scale = scale + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def _make_layer(self, block, planes, blocks, stride=1): + downsample = None + if stride != 1 or self.inplanes != planes * block.expansion: + downsample = nn.Sequential( + nn.Conv2d(self.inplanes, planes * block.expansion, + kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(planes * block.expansion), + ) + + layers = [] + layers.append(block(self.inplanes, planes, stride, downsample)) + self.inplanes = planes * block.expansion + for i in range(1, blocks): + layers.append(block(self.inplanes, planes)) + + return nn.Sequential(*layers) + + def _upsample(self, x, y, scale=1): + _, _, H, W = y.size() + # return self.upsample(x) + return F.interpolate(x, size=(H // scale, W // scale), mode='bilinear', align_corners=False) + + def _upsample_add(self, x, y): + _, _, H, W = y.size() + # print(x.shape) + # print(y.shape) + # print('x:',x.type()) + # print('out:',F.interpolate(x, size=(H,W), mode='bilinear').type()) + # print('y:', y.type()) + # return self.upsample(x) + y + return F.interpolate(x, size=(H, W), mode='bilinear', align_corners=False).half() + y + + def forward(self, x): + h = x + h = self.conv1(h) + h = self.bn1(h) + h = self.relu1(h) + + h = self.maxpool(h) + + h = self.layer1(h) + c2 = h + h = self.layer2(h) + c3 = h + h = self.layer3(h) + c4 = h + h = self.layer4(h) + c5 = h + + # Top-down + p5 = self.toplayer(c5) + p5 = self.toplayer_relu(self.toplayer_bn(p5)) + + c4 = self.latlayer1(c4) + c4 = self.latlayer1_relu(self.latlayer1_bn(c4)) + t = time.time() + # print('c4:',c4.type()) + p4 = self._upsample_add(p5, c4) + p4 = self.smooth1(p4) + p4 = self.smooth1_relu(self.smooth1_bn(p4)) + + c3 = self.latlayer2(c3) + c3 = self.latlayer2_relu(self.latlayer2_bn(c3)) + t = time.time() + # print('t:',t) + p3 = self._upsample_add(p4, c3) + # print('t2:',time.time()-t) + p3 = self.smooth2(p3) + p3 = self.smooth2_relu(self.smooth2_bn(p3)) + + c2 = self.latlayer3(c2) + c2 = self.latlayer3_relu(self.latlayer3_bn(c2)) + p2 = self._upsample_add(p3, c2) + p2 = self.smooth3(p2) + p2 = self.smooth3_relu(self.smooth3_bn(p2)) + + p3 = self._upsample(p3, p2) + p4 = self._upsample(p4, p2) + p5 = self._upsample(p5, p2) + + # p2, p3, p4, p5 = p2.cpu(), p3.cpu(), p4.cpu(), p5.cpu() + out = torch.cat((p2, p3, p4, p5), 1) + # out = out.to(dev) + + + # self.conv2 = self.conv2.cpu() + out = self.conv2(out) + # self.conv2 = self.conv2.to(dev) + + # self.relu2 = self.relu2.cpu() + # self.bn2 = self.bn2.cpu() + out = self.relu2(self.bn2(out)) + # self.relu2 = self.relu2.to(dev) + # self.bn2 = self.bn2.to(dev) + + # self.conv3 = self.conv3.cpu() + out = self.conv3(out) + # self.conv3 = self.conv3.to(dev) + + # out = out.to(dev) + # p2, p3, p4, p5 = p2.to(dev), p3.to(dev), p4.to(dev), p5.to(dev) + out = self._upsample(out, x, scale=self.scale) + + return out + + +def resnet18(pretrained=False, **kwargs): + """Constructs a ResNet-18 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet18'])) + return model + + +def resnet34(pretrained=False, **kwargs): + """Constructs a ResNet-34 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet34'])) + return model + + +def resnet50(pretrained=False, **kwargs): + """Constructs a ResNet-50 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs) + if pretrained: + pretrained_model = model_zoo.load_url(model_urls['resnet50']) + state = model.state_dict() + for key in state.keys(): + if key in pretrained_model.keys(): + state[key] = pretrained_model[key] + model.load_state_dict(state) + return model + + +def resnet101(pretrained=False, **kwargs): + """Constructs a ResNet-101 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs) + if pretrained: + pretrained_model = model_zoo.load_url(model_urls['resnet101']) + state = model.state_dict() + for key in state.keys(): + if key in pretrained_model.keys(): + state[key] = pretrained_model[key] + model.load_state_dict(state) + return model + +def resnet152(pretrained=False, **kwargs): + """Constructs a ResNet-152 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs) + if pretrained: + pretrained_model = model_zoo.load_url(model_urls['resnet152']) + state = model.state_dict() + for key in state.keys(): + if key in pretrained_model.keys(): + state[key] = pretrained_model[key] + model.load_state_dict(state) + return model diff --git a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/fpn_resnet_nearest.py b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/fpn_resnet_nearest.py index 87999dd4dc..b3400aa3c5 100644 --- a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/fpn_resnet_nearest.py +++ b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/fpn_resnet_nearest.py @@ -1,555 +1,555 @@ -# Apache License -# Version 2.0, January 2004 -# http://www.apache.org/licenses/ -# -# TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -# -# 1. Definitions. -# -# "License" shall mean the terms and conditions for use, reproduction, -# and distribution as defined by Sections 1 through 9 of this document. -# -# "Licensor" shall mean the copyright owner or entity authorized by -# the copyright owner that is granting the License. -# -# "Legal Entity" shall mean the union of the acting entity and all -# other entities that control, are controlled by, or are under common -# control with that entity. For the purposes of this definition, -# "control" means (i) the power, direct or indirect, to cause the -# direction or management of such entity, whether by contract or -# otherwise, or (ii) ownership of fifty percent (50%) or more of the -# outstanding shares, or (iii) beneficial ownership of such entity. -# -# "You" (or "Your") shall mean an individual or Legal Entity -# exercising permissions granted by this License. -# -# "Source" form shall mean the preferred form for making modifications, -# including but not limited to software source code, documentation -# source, and configuration files. -# -# "Object" form shall mean any form resulting from mechanical -# transformation or translation of a Source form, including but -# not limited to compiled object code, generated documentation, -# and conversions to other media types. -# -# "Work" shall mean the work of authorship, whether in Source or -# Object form, made available under the License, as indicated by a -# copyright notice that is included in or attached to the work -# (an example is provided in the Appendix below). -# -# "Derivative Works" shall mean any work, whether in Source or Object -# form, that is based on (or derived from) the Work and for which the -# editorial revisions, annotations, elaborations, or other modifications -# represent, as a whole, an original work of authorship. For the purposes -# of this License, Derivative Works shall not include works that remain -# separable from, or merely link (or bind by name) to the interfaces of, -# the Work and Derivative Works thereof. -# -# "Contribution" shall mean any work of authorship, including -# the original version of the Work and any modifications or additions -# to that Work or Derivative Works thereof, that is intentionally -# submitted to Licensor for inclusion in the Work by the copyright owner -# or by an individual or Legal Entity authorized to submit on behalf of -# the copyright owner. For the purposes of this definition, "submitted" -# means any form of electronic, verbal, or written communication sent -# to the Licensor or its representatives, including but not limited to -# communication on electronic mailing lists, source code control systems, -# and issue tracking systems that are managed by, or on behalf of, the -# Licensor for the purpose of discussing and improving the Work, but -# excluding communication that is conspicuously marked or otherwise -# designated in writing by the copyright owner as "Not a Contribution." -# -# "Contributor" shall mean Licensor and any individual or Legal Entity -# on behalf of whom a Contribution has been received by Licensor and -# subsequently incorporated within the Work. -# -# 2. Grant of Copyright License. Subject to the terms and conditions of -# this License, each Contributor hereby grants to You a perpetual, -# worldwide, non-exclusive, no-charge, royalty-free, irrevocable -# copyright license to reproduce, prepare Derivative Works of, -# publicly display, publicly perform, sublicense, and distribute the -# Work and such Derivative Works in Source or Object form. -# -# 3. Grant of Patent License. Subject to the terms and conditions of -# this License, each Contributor hereby grants to You a perpetual, -# worldwide, non-exclusive, no-charge, royalty-free, irrevocable -# (except as stated in this section) patent license to make, have made, -# use, offer to sell, sell, import, and otherwise transfer the Work, -# where such license applies only to those patent claims licensable -# by such Contributor that are necessarily infringed by their -# Contribution(s) alone or by combination of their Contribution(s) -# with the Work to which such Contribution(s) was submitted. If You -# institute patent litigation against any entity (including a -# cross-claim or counterclaim in a lawsuit) alleging that the Work -# or a Contribution incorporated within the Work constitutes direct -# or contributory patent infringement, then any patent licenses -# granted to You under this License for that Work shall terminate -# as of the date such litigation is filed. -# -# 4. Redistribution. You may reproduce and distribute copies of the -# Work or Derivative Works thereof in any medium, with or without -# modifications, and in Source or Object form, provided that You -# meet the following conditions: -# -# (a) You must give any other recipients of the Work or -# Derivative Works a copy of this License; and -# -# (b) You must cause any modified files to carry prominent notices -# stating that You changed the files; and -# -# (c) You must retain, in the Source form of any Derivative Works -# that You distribute, all copyright, patent, trademark, and -# attribution notices from the Source form of the Work, -# excluding those notices that do not pertain to any part of -# the Derivative Works; and -# -# (d) If the Work includes a "NOTICE" text file as part of its -# distribution, then any Derivative Works that You distribute must -# include a readable copy of the attribution notices contained -# within such NOTICE file, excluding those notices that do not -# pertain to any part of the Derivative Works, in at least one -# of the following places: within a NOTICE text file distributed -# as part of the Derivative Works; within the Source form or -# documentation, if provided along with the Derivative Works; or, -# within a display generated by the Derivative Works, if and -# wherever such third-party notices normally appear. The contents -# of the NOTICE file are for informational purposes only and -# do not modify the License. You may add Your own attribution -# notices within Derivative Works that You distribute, alongside -# or as an addendum to the NOTICE text from the Work, provided -# that such additional attribution notices cannot be construed -# as modifying the License. -# -# You may add Your own copyright statement to Your modifications and -# may provide additional or different license terms and conditions -# for use, reproduction, or distribution of Your modifications, or -# for any such Derivative Works as a whole, provided Your use, -# reproduction, and distribution of the Work otherwise complies with -# the conditions stated in this License. -# -# 5. Submission of Contributions. Unless You explicitly state otherwise, -# any Contribution intentionally submitted for inclusion in the Work -# by You to the Licensor shall be under the terms and conditions of -# this License, without any additional terms or conditions. -# Notwithstanding the above, nothing herein shall supersede or modify -# the terms of any separate license agreement you may have executed -# with Licensor regarding such Contributions. -# -# 6. Trademarks. This License does not grant permission to use the trade -# names, trademarks, service marks, or product names of the Licensor, -# except as required for reasonable and customary use in describing the -# origin of the Work and reproducing the content of the NOTICE file. -# -# 7. Disclaimer of Warranty. Unless required by applicable law or -# agreed to in writing, Licensor provides the Work (and each -# Contributor provides its Contributions) on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied, including, without limitation, any warranties or conditions -# of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -# PARTICULAR PURPOSE. You are solely responsible for determining the -# appropriateness of using or redistributing the Work and assume any -# risks associated with Your exercise of permissions under this License. -# -# 8. Limitation of Liability. In no event and under no legal theory, -# whether in tort (including negligence), contract, or otherwise, -# unless required by applicable law (such as deliberate and grossly -# negligent acts) or agreed to in writing, shall any Contributor be -# liable to You for damages, including any direct, indirect, special, -# incidental, or consequential damages of any character arising as a -# result of this License or out of the use or inability to use the -# Work (including but not limited to damages for loss of goodwill, -# work stoppage, computer failure or malfunction, or any and all -# other commercial damages or losses), even if such Contributor -# has been advised of the possibility of such damages. -# -# 9. Accepting Warranty or Additional Liability. While redistributing -# the Work or Derivative Works thereof, You may choose to offer, -# and charge a fee for, acceptance of support, warranty, indemnity, -# or other liability obligations and/or rights consistent with this -# License. However, in accepting such obligations, You may act only -# on Your own behalf and on Your sole responsibility, not on behalf -# of any other Contributor, and only if You agree to indemnify, -# defend, and hold each Contributor harmless for any liability -# incurred by, or claims asserted against, such Contributor by reason -# of your accepting any such warranty or additional liability. -# -# END OF TERMS AND CONDITIONS -# -# APPENDIX: How to apply the Apache License to your work. -# -# To apply the Apache License to your work, attach the following -# boilerplate notice, with the fields enclosed by brackets "[]" -# replaced with your own identifying information. (Don't include -# the brackets!) The text should be enclosed in the appropriate -# comment syntax for the file format. We also recommend that a -# file or class name and description of purpose be included on the -# same "printed page" as the copyright notice for easier -# identification within third-party archives. -# -# Copyright [yyyy] [name of copyright owner] -# -# 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. -# -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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 math -import time - -import torch -import torch.nn as nn -import torch.nn.functional as F -import torch.utils.model_zoo as model_zoo - -__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', - 'resnet152'] - -model_urls = { - 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth', - 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth', - 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth', - 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3mb4d8f.pth', - 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth', -} - - -def conv3x3(in_planes, out_planes, stride=1): - """3x3 convolution with padding""" - return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, - padding=1, bias=False) - - -class BasicBlock(nn.Module): - expansion = 1 - - def __init__(self, inplanes, planes, stride=1, downsample=None): - super(BasicBlock, self).__init__() - self.conv1 = conv3x3(inplanes, planes, stride) - self.bn1 = nn.BatchNorm2d(planes) - self.relu = nn.ReLU(inplace=True) - self.conv2 = conv3x3(planes, planes) - self.bn2 = nn.BatchNorm2d(planes) - self.downsample = downsample - self.stride = stride - - def forward(self, x): - residual = x - - out = self.conv1(x) - out = self.bn1(out) - out = self.relu(out) - - out = self.conv2(out) - out = self.bn2(out) - - if self.downsample is not None: - residual = self.downsample(x) - - out += residual - out = self.relu(out) - - return out - - -class Bottleneck(nn.Module): - expansion = 4 - - def __init__(self, inplanes, planes, stride=1, downsample=None): - super(Bottleneck, self).__init__() - self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) - self.bn1 = nn.BatchNorm2d(planes) - self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, - padding=1, bias=False) - self.bn2 = nn.BatchNorm2d(planes) - self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) - self.bn3 = nn.BatchNorm2d(planes * 4) - self.relu = nn.ReLU(inplace=True) - self.downsample = downsample - self.stride = stride - - def forward(self, x): - residual = x - - out = self.conv1(x) - out = self.bn1(out) - out = self.relu(out) - - out = self.conv2(out) - out = self.bn2(out) - out = self.relu(out) - - out = self.conv3(out) - out = self.bn3(out) - - if self.downsample is not None: - residual = self.downsample(x) - - out += residual - out = self.relu(out) - - return out - - -class ResNet(nn.Module): - - def __init__(self, block, layers, num_classes=7, scale=1): - self.inplanes = 64 - super(ResNet, self).__init__() - self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, - bias=False) - self.bn1 = nn.BatchNorm2d(64) - self.relu1 = nn.ReLU(inplace=True) - self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1, return_indices=False) - self.layer1 = self._make_layer(block, 64, layers[0]) - self.layer2 = self._make_layer(block, 128, layers[1], stride=2) - self.layer3 = self._make_layer(block, 256, layers[2], stride=2) - self.layer4 = self._make_layer(block, 512, layers[3], stride=2) - # self.avgpool = nn.AvgPool2d(7, stride=1) - # self.fc = nn.Linear(512 * block.expansion, num_classes) - - # Top layer - self.toplayer = nn.Conv2d(2048, 256, kernel_size=1, stride=1, padding=0) # Reduce channels - self.toplayer_bn = nn.BatchNorm2d(256) - self.toplayer_relu = nn.ReLU(inplace=True) - - # Smooth layers - self.smooth1 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1) - self.smooth1_bn = nn.BatchNorm2d(256) - self.smooth1_relu = nn.ReLU(inplace=True) - - self.smooth2 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1) - self.smooth2_bn = nn.BatchNorm2d(256) - self.smooth2_relu = nn.ReLU(inplace=True) - - self.smooth3 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1) - self.smooth3_bn = nn.BatchNorm2d(256) - self.smooth3_relu = nn.ReLU(inplace=True) - - # Lateral layers - self.latlayer1 = nn.Conv2d(1024, 256, kernel_size=1, stride=1, padding=0) - self.latlayer1_bn = nn.BatchNorm2d(256) - self.latlayer1_relu = nn.ReLU(inplace=True) - - self.latlayer2 = nn.Conv2d(512, 256, kernel_size=1, stride=1, padding=0) - self.latlayer2_bn = nn.BatchNorm2d(256) - self.latlayer2_relu = nn.ReLU(inplace=True) - - self.latlayer3 = nn.Conv2d(256, 256, kernel_size=1, stride=1, padding=0) - self.latlayer3_bn = nn.BatchNorm2d(256) - self.latlayer3_relu = nn.ReLU(inplace=True) - - self.conv2 = nn.Conv2d(1024, 256, kernel_size=3, stride=1, padding=1) - self.bn2 = nn.BatchNorm2d(256) - self.relu2 = nn.ReLU(inplace=True) - self.conv3 = nn.Conv2d(256, num_classes, kernel_size=1, stride=1, padding=0) - self.upsample = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True) - - self.scale = scale - - for m in self.modules(): - if isinstance(m, nn.Conv2d): - n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels - m.weight.data.normal_(0, math.sqrt(2. / n)) - elif isinstance(m, nn.BatchNorm2d): - m.weight.data.fill_(1) - m.bias.data.zero_() - - def _make_layer(self, block, planes, blocks, stride=1): - downsample = None - if stride != 1 or self.inplanes != planes * block.expansion: - downsample = nn.Sequential( - nn.Conv2d(self.inplanes, planes * block.expansion, - kernel_size=1, stride=stride, bias=False), - nn.BatchNorm2d(planes * block.expansion), - ) - - layers = [] - layers.append(block(self.inplanes, planes, stride, downsample)) - self.inplanes = planes * block.expansion - for i in range(1, blocks): - layers.append(block(self.inplanes, planes)) - - return nn.Sequential(*layers) - - def _upsample(self, x, y, scale=1): - _, _, H, W = y.size() - # return self.upsample(x) - return F.interpolate(x, size=(H // scale, W // scale), mode='nearest') - - def _upsample_add(self, x, y): - _, _, H, W = y.size() - # return F.interpolate(x, size=(H, W), mode='bilinear', align_corners=False).half() + y - return F.interpolate(x, size=(H, W), mode='nearest') + y - - def forward(self, x): - h = x - h = self.conv1(h) - h = self.bn1(h) - h = self.relu1(h) - - #h = h.float() - h = self.maxpool(h) - #h = h.half() - # self.maxpool = self.maxpool.cpu() - # h = self.maxpool(h.cpu()) - # h = h.npu() - # self.maxpool = self.maxpool.npu() - - h = self.layer1(h) - c2 = h - h = self.layer2(h) - c3 = h - h = self.layer3(h) - c4 = h - h = self.layer4(h) - c5 = h - - # Top-down - p5 = self.toplayer(c5) - p5 = self.toplayer_relu(self.toplayer_bn(p5)) - - c4 = self.latlayer1(c4) - c4 = self.latlayer1_relu(self.latlayer1_bn(c4)) - t = time.time() - # print('c4:',c4.type()) - p4 = self._upsample_add(p5, c4) - p4 = self.smooth1(p4) - p4 = self.smooth1_relu(self.smooth1_bn(p4)) - - c3 = self.latlayer2(c3) - c3 = self.latlayer2_relu(self.latlayer2_bn(c3)) - t = time.time() - # print('t:',t) - p3 = self._upsample_add(p4, c3) - # print('t2:',time.time()-t) - p3 = self.smooth2(p3) - p3 = self.smooth2_relu(self.smooth2_bn(p3)) - - c2 = self.latlayer3(c2) - c2 = self.latlayer3_relu(self.latlayer3_bn(c2)) - p2 = self._upsample_add(p3, c2) - p2 = self.smooth3(p2) - p2 = self.smooth3_relu(self.smooth3_bn(p2)) - - p3 = self._upsample(p3, p2) - p4 = self._upsample(p4, p2) - p5 = self._upsample(p5, p2) - - # p2, p3, p4, p5 = p2.cpu(), p3.cpu(), p4.cpu(), p5.cpu() - out = torch.cat((p2, p3, p4, p5), 1) - # out = out.to(dev) - - # self.conv2 = self.conv2.cpu() - out = self.conv2(out) - # self.conv2 = self.conv2.to(dev) - - # self.relu2 = self.relu2.cpu() - # self.bn2 = self.bn2.cpu() - out = self.relu2(self.bn2(out)) - # self.relu2 = self.relu2.to(dev) - # self.bn2 = self.bn2.to(dev) - - # self.conv3 = self.conv3.cpu() - out = self.conv3(out) - # self.conv3 = self.conv3.to(dev) - - # out = out.to(dev) - # p2, p3, p4, p5 = p2.to(dev), p3.to(dev), p4.to(dev), p5.to(dev) - out = self._upsample(out, x, scale=self.scale) - - return out - - -def resnet18(pretrained=False, **kwargs): - """Constructs a ResNet-18 model. - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - """ - model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs) - if pretrained: - model.load_state_dict(model_zoo.load_url(model_urls['resnet18'])) - return model - - -def resnet34(pretrained=False, **kwargs): - """Constructs a ResNet-34 model. - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - """ - model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs) - if pretrained: - model.load_state_dict(model_zoo.load_url(model_urls['resnet34'])) - return model - - -def resnet50(pretrained=False, **kwargs): - """Constructs a ResNet-50 model. - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - """ - model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs) - if pretrained: - pretrained_model = model_zoo.load_url(model_urls['resnet50']) - state = model.state_dict() - for key in state.keys(): - if key in pretrained_model.keys(): - state[key] = pretrained_model[key] - model.load_state_dict(state) - return model - - -def resnet101(pretrained=False, **kwargs): - """Constructs a ResNet-101 model. - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - """ - model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs) - if pretrained: - pretrained_model = model_zoo.load_url(model_urls['resnet101']) - state = model.state_dict() - for key in state.keys(): - if key in pretrained_model.keys(): - state[key] = pretrained_model[key] - model.load_state_dict(state) - return model - - -def resnet152(pretrained=False, **kwargs): - """Constructs a ResNet-152 model. - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - """ - model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs) - if pretrained: - pretrained_model = model_zoo.load_url(model_urls['resnet152']) - state = model.state_dict() - for key in state.keys(): - if key in pretrained_model.keys(): - state[key] = pretrained_model[key] - model.load_state_dict(state) - return model +# Apache License +# Version 2.0, January 2004 +# http://www.apache.org/licenses/ +# +# TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +# +# 1. Definitions. +# +# "License" shall mean the terms and conditions for use, reproduction, +# and distribution as defined by Sections 1 through 9 of this document. +# +# "Licensor" shall mean the copyright owner or entity authorized by +# the copyright owner that is granting the License. +# +# "Legal Entity" shall mean the union of the acting entity and all +# other entities that control, are controlled by, or are under common +# control with that entity. For the purposes of this definition, +# "control" means (i) the power, direct or indirect, to cause the +# direction or management of such entity, whether by contract or +# otherwise, or (ii) ownership of fifty percent (50%) or more of the +# outstanding shares, or (iii) beneficial ownership of such entity. +# +# "You" (or "Your") shall mean an individual or Legal Entity +# exercising permissions granted by this License. +# +# "Source" form shall mean the preferred form for making modifications, +# including but not limited to software source code, documentation +# source, and configuration files. +# +# "Object" form shall mean any form resulting from mechanical +# transformation or translation of a Source form, including but +# not limited to compiled object code, generated documentation, +# and conversions to other media types. +# +# "Work" shall mean the work of authorship, whether in Source or +# Object form, made available under the License, as indicated by a +# copyright notice that is included in or attached to the work +# (an example is provided in the Appendix below). +# +# "Derivative Works" shall mean any work, whether in Source or Object +# form, that is based on (or derived from) the Work and for which the +# editorial revisions, annotations, elaborations, or other modifications +# represent, as a whole, an original work of authorship. For the purposes +# of this License, Derivative Works shall not include works that remain +# separable from, or merely link (or bind by name) to the interfaces of, +# the Work and Derivative Works thereof. +# +# "Contribution" shall mean any work of authorship, including +# the original version of the Work and any modifications or additions +# to that Work or Derivative Works thereof, that is intentionally +# submitted to Licensor for inclusion in the Work by the copyright owner +# or by an individual or Legal Entity authorized to submit on behalf of +# the copyright owner. For the purposes of this definition, "submitted" +# means any form of electronic, verbal, or written communication sent +# to the Licensor or its representatives, including but not limited to +# communication on electronic mailing lists, source code control systems, +# and issue tracking systems that are managed by, or on behalf of, the +# Licensor for the purpose of discussing and improving the Work, but +# excluding communication that is conspicuously marked or otherwise +# designated in writing by the copyright owner as "Not a Contribution." +# +# "Contributor" shall mean Licensor and any individual or Legal Entity +# on behalf of whom a Contribution has been received by Licensor and +# subsequently incorporated within the Work. +# +# 2. Grant of Copyright License. Subject to the terms and conditions of +# this License, each Contributor hereby grants to You a perpetual, +# worldwide, non-exclusive, no-charge, royalty-free, irrevocable +# copyright license to reproduce, prepare Derivative Works of, +# publicly display, publicly perform, sublicense, and distribute the +# Work and such Derivative Works in Source or Object form. +# +# 3. Grant of Patent License. Subject to the terms and conditions of +# this License, each Contributor hereby grants to You a perpetual, +# worldwide, non-exclusive, no-charge, royalty-free, irrevocable +# (except as stated in this section) patent license to make, have made, +# use, offer to sell, sell, import, and otherwise transfer the Work, +# where such license applies only to those patent claims licensable +# by such Contributor that are necessarily infringed by their +# Contribution(s) alone or by combination of their Contribution(s) +# with the Work to which such Contribution(s) was submitted. If You +# institute patent litigation against any entity (including a +# cross-claim or counterclaim in a lawsuit) alleging that the Work +# or a Contribution incorporated within the Work constitutes direct +# or contributory patent infringement, then any patent licenses +# granted to You under this License for that Work shall terminate +# as of the date such litigation is filed. +# +# 4. Redistribution. You may reproduce and distribute copies of the +# Work or Derivative Works thereof in any medium, with or without +# modifications, and in Source or Object form, provided that You +# meet the following conditions: +# +# (a) You must give any other recipients of the Work or +# Derivative Works a copy of this License; and +# +# (b) You must cause any modified files to carry prominent notices +# stating that You changed the files; and +# +# (c) You must retain, in the Source form of any Derivative Works +# that You distribute, all copyright, patent, trademark, and +# attribution notices from the Source form of the Work, +# excluding those notices that do not pertain to any part of +# the Derivative Works; and +# +# (d) If the Work includes a "NOTICE" text file as part of its +# distribution, then any Derivative Works that You distribute must +# include a readable copy of the attribution notices contained +# within such NOTICE file, excluding those notices that do not +# pertain to any part of the Derivative Works, in at least one +# of the following places: within a NOTICE text file distributed +# as part of the Derivative Works; within the Source form or +# documentation, if provided along with the Derivative Works; or, +# within a display generated by the Derivative Works, if and +# wherever such third-party notices normally appear. The contents +# of the NOTICE file are for informational purposes only and +# do not modify the License. You may add Your own attribution +# notices within Derivative Works that You distribute, alongside +# or as an addendum to the NOTICE text from the Work, provided +# that such additional attribution notices cannot be construed +# as modifying the License. +# +# You may add Your own copyright statement to Your modifications and +# may provide additional or different license terms and conditions +# for use, reproduction, or distribution of Your modifications, or +# for any such Derivative Works as a whole, provided Your use, +# reproduction, and distribution of the Work otherwise complies with +# the conditions stated in this License. +# +# 5. Submission of Contributions. Unless You explicitly state otherwise, +# any Contribution intentionally submitted for inclusion in the Work +# by You to the Licensor shall be under the terms and conditions of +# this License, without any additional terms or conditions. +# Notwithstanding the above, nothing herein shall supersede or modify +# the terms of any separate license agreement you may have executed +# with Licensor regarding such Contributions. +# +# 6. Trademarks. This License does not grant permission to use the trade +# names, trademarks, service marks, or product names of the Licensor, +# except as required for reasonable and customary use in describing the +# origin of the Work and reproducing the content of the NOTICE file. +# +# 7. Disclaimer of Warranty. Unless required by applicable law or +# agreed to in writing, Licensor provides the Work (and each +# Contributor provides its Contributions) on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied, including, without limitation, any warranties or conditions +# of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +# PARTICULAR PURPOSE. You are solely responsible for determining the +# appropriateness of using or redistributing the Work and assume any +# risks associated with Your exercise of permissions under this License. +# +# 8. Limitation of Liability. In no event and under no legal theory, +# whether in tort (including negligence), contract, or otherwise, +# unless required by applicable law (such as deliberate and grossly +# negligent acts) or agreed to in writing, shall any Contributor be +# liable to You for damages, including any direct, indirect, special, +# incidental, or consequential damages of any character arising as a +# result of this License or out of the use or inability to use the +# Work (including but not limited to damages for loss of goodwill, +# work stoppage, computer failure or malfunction, or any and all +# other commercial damages or losses), even if such Contributor +# has been advised of the possibility of such damages. +# +# 9. Accepting Warranty or Additional Liability. While redistributing +# the Work or Derivative Works thereof, You may choose to offer, +# and charge a fee for, acceptance of support, warranty, indemnity, +# or other liability obligations and/or rights consistent with this +# License. However, in accepting such obligations, You may act only +# on Your own behalf and on Your sole responsibility, not on behalf +# of any other Contributor, and only if You agree to indemnify, +# defend, and hold each Contributor harmless for any liability +# incurred by, or claims asserted against, such Contributor by reason +# of your accepting any such warranty or additional liability. +# +# END OF TERMS AND CONDITIONS +# +# APPENDIX: How to apply the Apache License to your work. +# +# To apply the Apache License to your work, attach the following +# boilerplate notice, with the fields enclosed by brackets "[]" +# replaced with your own identifying information. (Don't include +# the brackets!) The text should be enclosed in the appropriate +# comment syntax for the file format. We also recommend that a +# file or class name and description of purpose be included on the +# same "printed page" as the copyright notice for easier +# identification within third-party archives. +# +# Copyright [yyyy] [name of copyright owner] +# +# 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. +# +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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 math +import time + +import torch +import torch.nn as nn +import torch.nn.functional as F +import torch.utils.model_zoo as model_zoo + +__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', + 'resnet152'] + +model_urls = { + 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth', + 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth', + 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth', + 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3mb4d8f.pth', + 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth', +} + + +def conv3x3(in_planes, out_planes, stride=1): + """3x3 convolution with padding""" + return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, + padding=1, bias=False) + + +class BasicBlock(nn.Module): + expansion = 1 + + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(BasicBlock, self).__init__() + self.conv1 = conv3x3(inplanes, planes, stride) + self.bn1 = nn.BatchNorm2d(planes) + self.relu = nn.ReLU(inplace=True) + self.conv2 = conv3x3(planes, planes) + self.bn2 = nn.BatchNorm2d(planes) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class Bottleneck(nn.Module): + expansion = 4 + + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(Bottleneck, self).__init__() + self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) + self.bn1 = nn.BatchNorm2d(planes) + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, + padding=1, bias=False) + self.bn2 = nn.BatchNorm2d(planes) + self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) + self.bn3 = nn.BatchNorm2d(planes * 4) + self.relu = nn.ReLU(inplace=True) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class ResNet(nn.Module): + + def __init__(self, block, layers, num_classes=7, scale=1): + self.inplanes = 64 + super(ResNet, self).__init__() + self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, + bias=False) + self.bn1 = nn.BatchNorm2d(64) + self.relu1 = nn.ReLU(inplace=True) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1, return_indices=False) + self.layer1 = self._make_layer(block, 64, layers[0]) + self.layer2 = self._make_layer(block, 128, layers[1], stride=2) + self.layer3 = self._make_layer(block, 256, layers[2], stride=2) + self.layer4 = self._make_layer(block, 512, layers[3], stride=2) + # self.avgpool = nn.AvgPool2d(7, stride=1) + # self.fc = nn.Linear(512 * block.expansion, num_classes) + + # Top layer + self.toplayer = nn.Conv2d(2048, 256, kernel_size=1, stride=1, padding=0) # Reduce channels + self.toplayer_bn = nn.BatchNorm2d(256) + self.toplayer_relu = nn.ReLU(inplace=True) + + # Smooth layers + self.smooth1 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1) + self.smooth1_bn = nn.BatchNorm2d(256) + self.smooth1_relu = nn.ReLU(inplace=True) + + self.smooth2 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1) + self.smooth2_bn = nn.BatchNorm2d(256) + self.smooth2_relu = nn.ReLU(inplace=True) + + self.smooth3 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1) + self.smooth3_bn = nn.BatchNorm2d(256) + self.smooth3_relu = nn.ReLU(inplace=True) + + # Lateral layers + self.latlayer1 = nn.Conv2d(1024, 256, kernel_size=1, stride=1, padding=0) + self.latlayer1_bn = nn.BatchNorm2d(256) + self.latlayer1_relu = nn.ReLU(inplace=True) + + self.latlayer2 = nn.Conv2d(512, 256, kernel_size=1, stride=1, padding=0) + self.latlayer2_bn = nn.BatchNorm2d(256) + self.latlayer2_relu = nn.ReLU(inplace=True) + + self.latlayer3 = nn.Conv2d(256, 256, kernel_size=1, stride=1, padding=0) + self.latlayer3_bn = nn.BatchNorm2d(256) + self.latlayer3_relu = nn.ReLU(inplace=True) + + self.conv2 = nn.Conv2d(1024, 256, kernel_size=3, stride=1, padding=1) + self.bn2 = nn.BatchNorm2d(256) + self.relu2 = nn.ReLU(inplace=True) + self.conv3 = nn.Conv2d(256, num_classes, kernel_size=1, stride=1, padding=0) + self.upsample = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True) + + self.scale = scale + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def _make_layer(self, block, planes, blocks, stride=1): + downsample = None + if stride != 1 or self.inplanes != planes * block.expansion: + downsample = nn.Sequential( + nn.Conv2d(self.inplanes, planes * block.expansion, + kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(planes * block.expansion), + ) + + layers = [] + layers.append(block(self.inplanes, planes, stride, downsample)) + self.inplanes = planes * block.expansion + for i in range(1, blocks): + layers.append(block(self.inplanes, planes)) + + return nn.Sequential(*layers) + + def _upsample(self, x, y, scale=1): + _, _, H, W = y.size() + # return self.upsample(x) + return F.interpolate(x, size=(H // scale, W // scale), mode='nearest') + + def _upsample_add(self, x, y): + _, _, H, W = y.size() + # return F.interpolate(x, size=(H, W), mode='bilinear', align_corners=False).half() + y + return F.interpolate(x, size=(H, W), mode='nearest') + y + + def forward(self, x): + h = x + h = self.conv1(h) + h = self.bn1(h) + h = self.relu1(h) + + #h = h.float() + h = self.maxpool(h) + #h = h.half() + # self.maxpool = self.maxpool.cpu() + # h = self.maxpool(h.cpu()) + # h = h.npu() + # self.maxpool = self.maxpool.npu() + + h = self.layer1(h) + c2 = h + h = self.layer2(h) + c3 = h + h = self.layer3(h) + c4 = h + h = self.layer4(h) + c5 = h + + # Top-down + p5 = self.toplayer(c5) + p5 = self.toplayer_relu(self.toplayer_bn(p5)) + + c4 = self.latlayer1(c4) + c4 = self.latlayer1_relu(self.latlayer1_bn(c4)) + t = time.time() + # print('c4:',c4.type()) + p4 = self._upsample_add(p5, c4) + p4 = self.smooth1(p4) + p4 = self.smooth1_relu(self.smooth1_bn(p4)) + + c3 = self.latlayer2(c3) + c3 = self.latlayer2_relu(self.latlayer2_bn(c3)) + t = time.time() + # print('t:',t) + p3 = self._upsample_add(p4, c3) + # print('t2:',time.time()-t) + p3 = self.smooth2(p3) + p3 = self.smooth2_relu(self.smooth2_bn(p3)) + + c2 = self.latlayer3(c2) + c2 = self.latlayer3_relu(self.latlayer3_bn(c2)) + p2 = self._upsample_add(p3, c2) + p2 = self.smooth3(p2) + p2 = self.smooth3_relu(self.smooth3_bn(p2)) + + p3 = self._upsample(p3, p2) + p4 = self._upsample(p4, p2) + p5 = self._upsample(p5, p2) + + # p2, p3, p4, p5 = p2.cpu(), p3.cpu(), p4.cpu(), p5.cpu() + out = torch.cat((p2, p3, p4, p5), 1) + # out = out.to(dev) + + # self.conv2 = self.conv2.cpu() + out = self.conv2(out) + # self.conv2 = self.conv2.to(dev) + + # self.relu2 = self.relu2.cpu() + # self.bn2 = self.bn2.cpu() + out = self.relu2(self.bn2(out)) + # self.relu2 = self.relu2.to(dev) + # self.bn2 = self.bn2.to(dev) + + # self.conv3 = self.conv3.cpu() + out = self.conv3(out) + # self.conv3 = self.conv3.to(dev) + + # out = out.to(dev) + # p2, p3, p4, p5 = p2.to(dev), p3.to(dev), p4.to(dev), p5.to(dev) + out = self._upsample(out, x, scale=self.scale) + + return out + + +def resnet18(pretrained=False, **kwargs): + """Constructs a ResNet-18 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet18'])) + return model + + +def resnet34(pretrained=False, **kwargs): + """Constructs a ResNet-34 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet34'])) + return model + + +def resnet50(pretrained=False, **kwargs): + """Constructs a ResNet-50 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs) + if pretrained: + pretrained_model = model_zoo.load_url(model_urls['resnet50']) + state = model.state_dict() + for key in state.keys(): + if key in pretrained_model.keys(): + state[key] = pretrained_model[key] + model.load_state_dict(state) + return model + + +def resnet101(pretrained=False, **kwargs): + """Constructs a ResNet-101 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs) + if pretrained: + pretrained_model = model_zoo.load_url(model_urls['resnet101']) + state = model.state_dict() + for key in state.keys(): + if key in pretrained_model.keys(): + state[key] = pretrained_model[key] + model.load_state_dict(state) + return model + + +def resnet152(pretrained=False, **kwargs): + """Constructs a ResNet-152 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs) + if pretrained: + pretrained_model = model_zoo.load_url(model_urls['resnet152']) + state = model.state_dict() + for key in state.keys(): + if key in pretrained_model.keys(): + state[key] = pretrained_model[key] + model.load_state_dict(state) + return model diff --git a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/preprocess_psenet_pytorch.py b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/preprocess_psenet_pytorch.py index 4ae58b56f5..dfad45a009 100644 --- a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/preprocess_psenet_pytorch.py +++ b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/preprocess_psenet_pytorch.py @@ -1,50 +1,50 @@ -import os -import sys -import numpy as np -import cv2 -from PIL import Image - - -def scale(img, long_size=2240): - h, w = img.shape[0:2] - scale = long_size * 1.0 / max(h, w) - img = cv2.resize(img, dsize=None, fx=scale, fy=scale) - # img = cv2.resize(img, (1260, 2240)) - print(img.shape) - return img - - -def psenet_onnx(file_path, bin_path): - if not os.path.exists(bin_path): - os.makedirs(bin_path) - i = 0 - in_files = os.listdir(file_path) - mean = [0.485, 0.456, 0.406] - std = [0.229, 0.224, 0.225] - for file in in_files: - i = i + 1 - print(file, "====", i) - img = cv2.imread(os.path.join(file_path, file)) - img = img[:, :, [2, 1, 0]] # bgr -> rgb - # img = scale(img) - img = cv2.resize(img, (1216, 704)) - - img = np.array(img, dtype=np.float32) - img = img / 255. - - # 均值方差 - img[..., 0] -= mean[0] - img[..., 1] -= mean[1] - img[..., 2] -= mean[2] - img[..., 0] /= std[0] - img[..., 1] /= std[1] - img[..., 2] /= std[2] - - img = img.transpose(2, 0, 1) # HWC -> CHW - img.tofile(os.path.join(bin_path, file.split('.')[0] + '.bin')) - - -if __name__ == "__main__": - file_path = os.path.abspath(sys.argv[1]) - bin_path = os.path.abspath(sys.argv[2]) - psenet_onnx(file_path, bin_path) +import os +import sys +import numpy as np +import cv2 +from PIL import Image + + +def scale(img, long_size=2240): + h, w = img.shape[0:2] + scale = long_size * 1.0 / max(h, w) + img = cv2.resize(img, dsize=None, fx=scale, fy=scale) + # img = cv2.resize(img, (1260, 2240)) + print(img.shape) + return img + + +def psenet_onnx(file_path, bin_path): + if not os.path.exists(bin_path): + os.makedirs(bin_path) + i = 0 + in_files = os.listdir(file_path) + mean = [0.485, 0.456, 0.406] + std = [0.229, 0.224, 0.225] + for file in in_files: + i = i + 1 + print(file, "====", i) + img = cv2.imread(os.path.join(file_path, file)) + img = img[:, :, [2, 1, 0]] # bgr -> rgb + # img = scale(img) + img = cv2.resize(img, (1216, 704)) + + img = np.array(img, dtype=np.float32) + img = img / 255. + + # 均值方差 + img[..., 0] -= mean[0] + img[..., 1] -= mean[1] + img[..., 2] -= mean[2] + img[..., 0] /= std[0] + img[..., 1] /= std[1] + img[..., 2] /= std[2] + + img = img.transpose(2, 0, 1) # HWC -> CHW + img.tofile(os.path.join(bin_path, file.split('.')[0] + '.bin')) + + +if __name__ == "__main__": + file_path = os.path.abspath(sys.argv[1]) + bin_path = os.path.abspath(sys.argv[2]) + psenet_onnx(file_path, bin_path) diff --git a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/pth_bintotxt_bilinear.py b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/pth_bintotxt_bilinear.py index ef040d7f93..b88459ff33 100644 --- a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/pth_bintotxt_bilinear.py +++ b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/pth_bintotxt_bilinear.py @@ -1,105 +1,105 @@ -import os -import sys -import numpy as np -import torch -import cv2 -from pypse import pse as pypse -import torch.nn.functional as F - - -img_path = sys.argv[1] -bin_path = sys.argv[2] -txt_path = sys.argv[3] - -if not os.path.exists(txt_path): - os.makedirs(txt_path) - -kernel_num=7 -min_kernel_area=5.0 -scale=1 -min_score = 0.9 -min_area = 600 - - -def get_images(): - ''' - find image files in test data path - :return: list of files found - ''' - files = [] - exts = ['jpg', 'png', 'jpeg', 'JPG'] - - for parent, _, filenames in os.walk(img_path): - for filename in filenames: - for ext in exts: - if filename.endswith(ext): - files.append(os.path.join(parent, filename)) - break - return files - - -im_fn_list = get_images() -for im_fn in im_fn_list: - print(im_fn) - im = cv2.imread(im_fn) - idx = os.path.basename(im_fn).split('/')[-1].split('.')[0].split('_')[1] - seg_maps = np.fromfile(bin_path+"/img_{}_1.bin".format(idx), "float32") - seg_maps = np.reshape(seg_maps, (1, 7, 176, 304)) - seg_maps = torch.from_numpy(seg_maps) - - # Resize 算子 - seg_maps = F.interpolate(seg_maps, size=(704, 1216), mode='bilinear', align_corners=False) - # print(seg_maps) - # print(seg_maps.shape) - # - # seg_maps = seg_maps.float() - score = torch.sigmoid(seg_maps[:, 0, :, :]) - outputs = (torch.sign(seg_maps - 1.0) + 1) / 2 - - text = outputs[:, 0, :, :] - kernels = outputs[:, 0:kernel_num, :, :] * text - - score = score.data.numpy()[0].astype(np.float32) - text = text.data.numpy()[0].astype(np.uint8) - kernels = kernels.numpy()[0].astype(np.uint8) - - # python version pse - pred = pypse(kernels, min_kernel_area / (scale * scale)) - - img_scale = (im.shape[1] * 1.0 / pred.shape[1], im.shape[0] * 1.0 / pred.shape[0]) - label = pred - label_num = np.max(label) + 1 - bboxes = [] - - for i in range(1, label_num): - points = np.array(np.where(label == i)).transpose((1, 0))[:, ::-1] - - if points.shape[0] < min_area: - continue - - score_i = np.mean(score[label == i]) - if score_i < min_score: - continue - - rect = cv2.minAreaRect(points) - bbox = cv2.boxPoints(rect) * img_scale - bbox = bbox.astype('int32') - bboxes.append(bbox.reshape(-1)) - # print(bboxes) - # save txt - res_file = os.path.join(txt_path,'{}.txt'.format(os.path.splitext(os.path.basename(im_fn))[0])) - with open(res_file, 'w') as f: - for b_idx, bbox in enumerate(bboxes): - values = [int(v) for v in bbox] - line = "%d, %d, %d, %d, %d, %d, %d, %d\n" % tuple(values) - f.write(line) - - - # show result - # for bbox in bboxes: - # cv2.drawContours(im, [bbox.reshape(4, 2)], -1, (0, 255, 0), 2) - # cv2.namedWindow('result', cv2.WINDOW_NORMAL) - # cv2.imshow('result', im) - # cv2.waitKey() - - +import os +import sys +import numpy as np +import torch +import cv2 +from pypse import pse as pypse +import torch.nn.functional as F + + +img_path = sys.argv[1] +bin_path = sys.argv[2] +txt_path = sys.argv[3] + +if not os.path.exists(txt_path): + os.makedirs(txt_path) + +kernel_num=7 +min_kernel_area=5.0 +scale=1 +min_score = 0.9 +min_area = 600 + + +def get_images(): + ''' + find image files in test data path + :return: list of files found + ''' + files = [] + exts = ['jpg', 'png', 'jpeg', 'JPG'] + + for parent, _, filenames in os.walk(img_path): + for filename in filenames: + for ext in exts: + if filename.endswith(ext): + files.append(os.path.join(parent, filename)) + break + return files + + +im_fn_list = get_images() +for im_fn in im_fn_list: + print(im_fn) + im = cv2.imread(im_fn) + idx = os.path.basename(im_fn).split('/')[-1].split('.')[0].split('_')[1] + seg_maps = np.fromfile(bin_path+"/img_{}_1.bin".format(idx), "float32") + seg_maps = np.reshape(seg_maps, (1, 7, 176, 304)) + seg_maps = torch.from_numpy(seg_maps) + + # Resize 算子 + seg_maps = F.interpolate(seg_maps, size=(704, 1216), mode='bilinear', align_corners=False) + # print(seg_maps) + # print(seg_maps.shape) + # + # seg_maps = seg_maps.float() + score = torch.sigmoid(seg_maps[:, 0, :, :]) + outputs = (torch.sign(seg_maps - 1.0) + 1) / 2 + + text = outputs[:, 0, :, :] + kernels = outputs[:, 0:kernel_num, :, :] * text + + score = score.data.numpy()[0].astype(np.float32) + text = text.data.numpy()[0].astype(np.uint8) + kernels = kernels.numpy()[0].astype(np.uint8) + + # python version pse + pred = pypse(kernels, min_kernel_area / (scale * scale)) + + img_scale = (im.shape[1] * 1.0 / pred.shape[1], im.shape[0] * 1.0 / pred.shape[0]) + label = pred + label_num = np.max(label) + 1 + bboxes = [] + + for i in range(1, label_num): + points = np.array(np.where(label == i)).transpose((1, 0))[:, ::-1] + + if points.shape[0] < min_area: + continue + + score_i = np.mean(score[label == i]) + if score_i < min_score: + continue + + rect = cv2.minAreaRect(points) + bbox = cv2.boxPoints(rect) * img_scale + bbox = bbox.astype('int32') + bboxes.append(bbox.reshape(-1)) + # print(bboxes) + # save txt + res_file = os.path.join(txt_path,'{}.txt'.format(os.path.splitext(os.path.basename(im_fn))[0])) + with open(res_file, 'w') as f: + for b_idx, bbox in enumerate(bboxes): + values = [int(v) for v in bbox] + line = "%d, %d, %d, %d, %d, %d, %d, %d\n" % tuple(values) + f.write(line) + + + # show result + # for bbox in bboxes: + # cv2.drawContours(im, [bbox.reshape(4, 2)], -1, (0, 255, 0), 2) + # cv2.namedWindow('result', cv2.WINDOW_NORMAL) + # cv2.imshow('result', im) + # cv2.waitKey() + + diff --git a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/pth_bintotxt_nearest.py b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/pth_bintotxt_nearest.py index 13240c3f4f..813bf982af 100644 --- a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/pth_bintotxt_nearest.py +++ b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/pth_bintotxt_nearest.py @@ -1,105 +1,105 @@ -import os -import sys -import numpy as np -import torch -import cv2 -from pypse import pse as pypse -import torch.nn.functional as F - - -img_path = sys.argv[1] -bin_path = sys.argv[2] -txt_path = sys.argv[3] - -if not os.path.exists(txt_path): - os.makedirs(txt_path) - -kernel_num=7 -min_kernel_area=5.0 -scale=1 -min_score = 0.9 -min_area = 600 - - -def get_images(): - ''' - find image files in test data path - :return: list of files found - ''' - files = [] - exts = ['jpg', 'png', 'jpeg', 'JPG'] - - for parent, _, filenames in os.walk(img_path): - for filename in filenames: - for ext in exts: - if filename.endswith(ext): - files.append(os.path.join(parent, filename)) - break - return files - - -im_fn_list = get_images() -for im_fn in im_fn_list: - print(im_fn) - im = cv2.imread(im_fn) - idx = os.path.basename(im_fn).split('/')[-1].split('.')[0].split('_')[1] - seg_maps = np.fromfile(bin_path+"/img_{}_1.bin".format(idx), "float32") - seg_maps = np.reshape(seg_maps, (1, 7, 704, 1216)) - seg_maps = torch.from_numpy(seg_maps) - - # Resize 算子 - # seg_maps = F.interpolate(seg_maps, size=(704, 1216), mode='bilinear', align_corners=False) - # print(seg_maps) - # print(seg_maps.shape) - # - # seg_maps = seg_maps.float() - score = torch.sigmoid(seg_maps[:, 0, :, :]) - outputs = (torch.sign(seg_maps - 1.0) + 1) / 2 - - text = outputs[:, 0, :, :] - kernels = outputs[:, 0:kernel_num, :, :] * text - - score = score.data.numpy()[0].astype(np.float32) - text = text.data.numpy()[0].astype(np.uint8) - kernels = kernels.numpy()[0].astype(np.uint8) - - # python version pse - pred = pypse(kernels, min_kernel_area / (scale * scale)) - - img_scale = (im.shape[1] * 1.0 / pred.shape[1], im.shape[0] * 1.0 / pred.shape[0]) - label = pred - label_num = np.max(label) + 1 - bboxes = [] - - for i in range(1, label_num): - points = np.array(np.where(label == i)).transpose((1, 0))[:, ::-1] - - if points.shape[0] < min_area: - continue - - score_i = np.mean(score[label == i]) - if score_i < min_score: - continue - - rect = cv2.minAreaRect(points) - bbox = cv2.boxPoints(rect) * img_scale - bbox = bbox.astype('int32') - bboxes.append(bbox.reshape(-1)) - # print(bboxes) - # save txt - res_file = os.path.join(txt_path,'{}.txt'.format(os.path.splitext(os.path.basename(im_fn))[0])) - with open(res_file, 'w') as f: - for b_idx, bbox in enumerate(bboxes): - values = [int(v) for v in bbox] - line = "%d, %d, %d, %d, %d, %d, %d, %d\n" % tuple(values) - f.write(line) - - - # show result - # for bbox in bboxes: - # cv2.drawContours(im, [bbox.reshape(4, 2)], -1, (0, 255, 0), 2) - # cv2.namedWindow('result', cv2.WINDOW_NORMAL) - # cv2.imshow('result', im) - # cv2.waitKey() - - +import os +import sys +import numpy as np +import torch +import cv2 +from pypse import pse as pypse +import torch.nn.functional as F + + +img_path = sys.argv[1] +bin_path = sys.argv[2] +txt_path = sys.argv[3] + +if not os.path.exists(txt_path): + os.makedirs(txt_path) + +kernel_num=7 +min_kernel_area=5.0 +scale=1 +min_score = 0.9 +min_area = 600 + + +def get_images(): + ''' + find image files in test data path + :return: list of files found + ''' + files = [] + exts = ['jpg', 'png', 'jpeg', 'JPG'] + + for parent, _, filenames in os.walk(img_path): + for filename in filenames: + for ext in exts: + if filename.endswith(ext): + files.append(os.path.join(parent, filename)) + break + return files + + +im_fn_list = get_images() +for im_fn in im_fn_list: + print(im_fn) + im = cv2.imread(im_fn) + idx = os.path.basename(im_fn).split('/')[-1].split('.')[0].split('_')[1] + seg_maps = np.fromfile(bin_path+"/img_{}_1.bin".format(idx), "float32") + seg_maps = np.reshape(seg_maps, (1, 7, 704, 1216)) + seg_maps = torch.from_numpy(seg_maps) + + # Resize 算子 + # seg_maps = F.interpolate(seg_maps, size=(704, 1216), mode='bilinear', align_corners=False) + # print(seg_maps) + # print(seg_maps.shape) + # + # seg_maps = seg_maps.float() + score = torch.sigmoid(seg_maps[:, 0, :, :]) + outputs = (torch.sign(seg_maps - 1.0) + 1) / 2 + + text = outputs[:, 0, :, :] + kernels = outputs[:, 0:kernel_num, :, :] * text + + score = score.data.numpy()[0].astype(np.float32) + text = text.data.numpy()[0].astype(np.uint8) + kernels = kernels.numpy()[0].astype(np.uint8) + + # python version pse + pred = pypse(kernels, min_kernel_area / (scale * scale)) + + img_scale = (im.shape[1] * 1.0 / pred.shape[1], im.shape[0] * 1.0 / pred.shape[0]) + label = pred + label_num = np.max(label) + 1 + bboxes = [] + + for i in range(1, label_num): + points = np.array(np.where(label == i)).transpose((1, 0))[:, ::-1] + + if points.shape[0] < min_area: + continue + + score_i = np.mean(score[label == i]) + if score_i < min_score: + continue + + rect = cv2.minAreaRect(points) + bbox = cv2.boxPoints(rect) * img_scale + bbox = bbox.astype('int32') + bboxes.append(bbox.reshape(-1)) + # print(bboxes) + # save txt + res_file = os.path.join(txt_path,'{}.txt'.format(os.path.splitext(os.path.basename(im_fn))[0])) + with open(res_file, 'w') as f: + for b_idx, bbox in enumerate(bboxes): + values = [int(v) for v in bbox] + line = "%d, %d, %d, %d, %d, %d, %d, %d\n" % tuple(values) + f.write(line) + + + # show result + # for bbox in bboxes: + # cv2.drawContours(im, [bbox.reshape(4, 2)], -1, (0, 255, 0), 2) + # cv2.namedWindow('result', cv2.WINDOW_NORMAL) + # cv2.imshow('result', im) + # cv2.waitKey() + + diff --git a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/pypse.py b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/pypse.py index 3200742b96..70436680e1 100644 --- a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/pypse.py +++ b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/pypse.py @@ -1,56 +1,56 @@ -import numpy as np -import cv2 -import queue as Queue - -def pse(kernals, min_area): - kernal_num = len(kernals) - pred = np.zeros(kernals[0].shape, dtype='int32') - - label_num, label = cv2.connectedComponents(kernals[kernal_num - 1], connectivity=4) - - for label_idx in range(1, label_num): - if np.sum(label == label_idx) < min_area: - label[label == label_idx] = 0 - - queue = Queue.Queue(maxsize = 0) - next_queue = Queue.Queue(maxsize = 0) - points = np.array(np.where(label > 0)).transpose((1, 0)) - - for point_idx in range(points.shape[0]): - x, y = points[point_idx, 0], points[point_idx, 1] - l = label[x, y] - queue.put((x, y, l)) - pred[x, y] = l - - dx = [-1, 1, 0, 0] - dy = [0, 0, -1, 1] - for kernal_idx in range(kernal_num - 2, -1, -1): - kernal = kernals[kernal_idx].copy() - while not queue.empty(): - (x, y, l) = queue.get() - - is_edge = True - for j in range(4): - tmpx = x + dx[j] - tmpy = y + dy[j] - if tmpx < 0 or tmpx >= kernal.shape[0] or tmpy < 0 or tmpy >= kernal.shape[1]: - continue - if kernal[tmpx, tmpy] == 0 or pred[tmpx, tmpy] > 0: - continue - - queue.put((tmpx, tmpy, l)) - pred[tmpx, tmpy] = l - is_edge = False - if is_edge: - next_queue.put((x, y, l)) - - # kernal[pred > 0] = 0 - queue, next_queue = next_queue, queue - - # points = np.array(np.where(pred > 0)).transpose((1, 0)) - # for point_idx in range(points.shape[0]): - # x, y = points[point_idx, 0], points[point_idx, 1] - # l = pred[x, y] - # queue.put((x, y, l)) - +import numpy as np +import cv2 +import queue as Queue + +def pse(kernals, min_area): + kernal_num = len(kernals) + pred = np.zeros(kernals[0].shape, dtype='int32') + + label_num, label = cv2.connectedComponents(kernals[kernal_num - 1], connectivity=4) + + for label_idx in range(1, label_num): + if np.sum(label == label_idx) < min_area: + label[label == label_idx] = 0 + + queue = Queue.Queue(maxsize = 0) + next_queue = Queue.Queue(maxsize = 0) + points = np.array(np.where(label > 0)).transpose((1, 0)) + + for point_idx in range(points.shape[0]): + x, y = points[point_idx, 0], points[point_idx, 1] + l = label[x, y] + queue.put((x, y, l)) + pred[x, y] = l + + dx = [-1, 1, 0, 0] + dy = [0, 0, -1, 1] + for kernal_idx in range(kernal_num - 2, -1, -1): + kernal = kernals[kernal_idx].copy() + while not queue.empty(): + (x, y, l) = queue.get() + + is_edge = True + for j in range(4): + tmpx = x + dx[j] + tmpy = y + dy[j] + if tmpx < 0 or tmpx >= kernal.shape[0] or tmpy < 0 or tmpy >= kernal.shape[1]: + continue + if kernal[tmpx, tmpy] == 0 or pred[tmpx, tmpy] > 0: + continue + + queue.put((tmpx, tmpy, l)) + pred[tmpx, tmpy] = l + is_edge = False + if is_edge: + next_queue.put((x, y, l)) + + # kernal[pred > 0] = 0 + queue, next_queue = next_queue, queue + + # points = np.array(np.where(pred > 0)).transpose((1, 0)) + # for point_idx in range(points.shape[0]): + # x, y = points[point_idx, 0], points[point_idx, 1] + # l = pred[x, y] + # queue.put((x, y, l)) + return pred \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/revise_PSENET_bilinear.py b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/revise_PSENET_bilinear.py index b9b81a5688..8ce2e8a367 100644 --- a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/revise_PSENET_bilinear.py +++ b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/revise_PSENET_bilinear.py @@ -1,296 +1,296 @@ -import numpy as np -import onnx -import onnxruntime as rt -from onnx import shape_inference -import sys -model_path = sys.argv[1] -model = onnx.load(model_path) - -# model = onnx.shape_inference.infer_shapes(model) - -def getNodeAndIOname(nodename,model): - for i in range(len(model.graph.node)): - if model.graph.node[i].name == nodename: - Node = model.graph.node[i] - return Node,input_name,output_name - -def FindPeerOutNode(graph, edge_name): - for i, x in enumerate(graph.node): - if edge_name in x.output: - return i - return -1 - - -def RemoveNode(graph, node_list): - cnt = 0 - for i in range(len(model.graph.node)): - if model.graph.node[i].name in node_list: - graph.node.remove(graph.node[i - cnt]) # 因为节点个数变少了 - cnt += 1 -def FindDependNode(graph, end_node, start_node): - ''' - find dependency node, [end_node, start_node) - ''' - def dfs(graph, idx, start_node, n_list): - for edge in graph.node[idx].input: - node_idx = FindPeerOutNode(graph, edge) - if node_idx < 0: - # print('bad peerout index') - continue - n = graph.node[node_idx] - if n.name != start_node: - n_list.append(n.name) - # print('n.name', n.name) - n_list = dfs(graph, node_idx, start_node, n_list) - return n_list - - index = GetNodeIndex(graph, end_node) - n_list = [end_node, ] - return dfs(graph, index, start_node, n_list) - - -def createGraphMemberMap(graph_member_list): - member_map=dict(); - for n in graph_member_list: - member_map[n.name]=n; - return member_map - -def GetNodeIndex(graph, node_name): - index = 0 - for i in range(len(graph.node)): - if graph.node[i].name == node_name: - index = i - break - return index -def RemoveNode2(graph,node_list): - for name in node_list: - print("name",name) - ind = GetNodeIndex(graph,name) - print("ind:",ind) - graph.node.remove(graph.node[ind]) - - -for i in range(len(model.graph.node)): - if model.graph.node[i].op_type == "Resize": - print("Resize", i, model.graph.node[i].input, model.graph.node[i].output) - -sizes1 = onnx.helper.make_tensor('size1', onnx.TensorProto.FLOAT, [4], [1, 1, 2, 2]) -sizes2 = onnx.helper.make_tensor('size2', onnx.TensorProto.FLOAT, [4], [1, 1, 2, 2]) -sizes3 = onnx.helper.make_tensor('size3', onnx.TensorProto.FLOAT, [4], [1, 1, 2, 2]) -sizes4 = onnx.helper.make_tensor('size4', onnx.TensorProto.FLOAT, [4], [1, 1, 2, 2]) -sizes5 = onnx.helper.make_tensor('size5', onnx.TensorProto.FLOAT, [4], [1, 1, 4, 4]) -sizes6 = onnx.helper.make_tensor('size6', onnx.TensorProto.FLOAT, [4], [1, 1, 8, 8]) -sizes7 = onnx.helper.make_tensor('size7', onnx.TensorProto.FLOAT, [4], [1, 1, 4, 4]) - - -model.graph.initializer.append(sizes1) -model.graph.initializer.append(sizes2) -model.graph.initializer.append(sizes3) -model.graph.initializer.append(sizes4) -model.graph.initializer.append(sizes5) -model.graph.initializer.append(sizes6) -model.graph.initializer.append(sizes7) - - -newnode = onnx.helper.make_node( - 'Resize', - name='Resize_196', - # inputs=['551', '564', '572', 'size1'], - inputs=['551', '564', 'size1'], - outputs=['573'], - coordinate_transformation_mode='pytorch_half_pixel', - cubic_coeff_a=-0.75, - mode='nearest', - nearest_mode='floor' -) - -newnode2 = onnx.helper.make_node( - 'Resize', - name='Resize_224', - # inputs=['347', '367', '375', 'size2'], - inputs=['579', '592', 'size2'], - outputs=['601'], - coordinate_transformation_mode='pytorch_half_pixel', - cubic_coeff_a=-0.75, - mode='nearest', - nearest_mode='floor' -) - -newnode3 = onnx.helper.make_node( - 'Resize', - name='Resize_252', - # inputs=['347', '367', '375', 'size2'], - inputs=['607', '620', 'size3'], - outputs=['629'], - coordinate_transformation_mode='pytorch_half_pixel', - cubic_coeff_a=-0.75, - mode='nearest', - nearest_mode='floor' -) - -newnode4 = onnx.helper.make_node( - 'Resize', - name='Resize_285', - # inputs=['347', '367', '375', 'size2'], - inputs=['607', '653', 'size4'], - outputs=['662'], - coordinate_transformation_mode='pytorch_half_pixel', - cubic_coeff_a=-0.75, - mode='nearest', - nearest_mode='floor' -) - - -newnode5 = onnx.helper.make_node( - 'Resize', - name='Resize_312', - # inputs=['347', '367', '375', 'size2'], - inputs=['579', '680', 'size5'], - outputs=['689'], - coordinate_transformation_mode='pytorch_half_pixel', - cubic_coeff_a=-0.75, - mode='nearest', - nearest_mode='floor' -) - - -newnode6 = onnx.helper.make_node( - 'Resize', - name='Resize_339', - # inputs=['347', '367', '375', 'size2'], - inputs=['551', '707', 'size6'], - outputs=['716'], - coordinate_transformation_mode='pytorch_half_pixel', - cubic_coeff_a=-0.75, - mode='nearest', - nearest_mode='floor' -) - - -newnode7= onnx.helper.make_node( - 'Resize', - name='Resize_371', - # inputs=['347', '367', '375', 'size2'], - inputs=['721', '739', 'size7'], - outputs=['output1'], - coordinate_transformation_mode='pytorch_half_pixel', - cubic_coeff_a=-0.75, - mode='nearest', - nearest_mode='floor' -) - - - - -model.graph.node.remove(model.graph.node[196]) -model.graph.node.insert(196, newnode) - -model.graph.node.remove(model.graph.node[224]) -model.graph.node.insert(224, newnode2) - -model.graph.node.remove(model.graph.node[252]) -model.graph.node.insert(252, newnode3) - -model.graph.node.remove(model.graph.node[285]) -model.graph.node.insert(285, newnode4) - -model.graph.node.remove(model.graph.node[312]) -model.graph.node.insert(312, newnode5) - -model.graph.node.remove(model.graph.node[339]) -model.graph.node.insert(339, newnode6) - -model.graph.node.remove(model.graph.node[371]) -model.graph.node.insert(371, newnode7) - -slice_node1_1 = FindDependNode(model.graph, 'Slice_192', 'Relu_174') #结尾(will be deleted) qishi -print('node map:', slice_node1_1) - -slice_node1_2 = FindDependNode(model.graph, 'Cast_193', 'Relu_177') -print('node map:', slice_node1_2) - -slice_node2_1 = FindDependNode(model.graph, 'Slice_220', 'Relu_202') -print('node map:', slice_node2_1) - -slice_node2_2 = FindDependNode(model.graph, 'Cast_221', 'Relu_205') -print('node map:', slice_node2_2) - -slice_node3_1 = FindDependNode(model.graph, 'Slice_248', 'Relu_230') -print('node map:', slice_node3_1) -slice_node3_2 = FindDependNode(model.graph, 'Cast_249', 'Relu_233') -print('node map:', slice_node3_2) - - -slice_node4_1 = FindDependNode(model.graph, 'Slice_281', 'Relu_230') -print('node map:', slice_node4_1) -slice_node4_2 = FindDependNode(model.graph, 'Cast_282', 'Relu_258') -print('node map:', slice_node4_2) - - -slice_node5_1 = FindDependNode(model.graph, 'Slice_308', 'Relu_202') -print('node map:', slice_node5_1) -slice_node5_2 = FindDependNode(model.graph, 'Cast_309', 'Relu_258') -print('node map:', slice_node5_2) - -slice_node6_1 = FindDependNode(model.graph, 'Slice_335', 'Relu_174') -print('node map:', slice_node6_1) -slice_node6_2 = FindDependNode(model.graph, 'Cast_336', 'Relu_258') -print('node map:', slice_node6_2) - -slice_node7_1 = FindDependNode(model.graph, 'Slice_367', 'Conv_344') -print('node map:', slice_node7_1) -slice_node7_2 = FindDependNode(model.graph, 'Cast_368', 'actual_input_1') -print('node map:', slice_node7_2) - - -node_list = [] -node_list.extend(slice_node1_1) -node_list.extend(slice_node1_2) -node_list.extend(slice_node2_1) -node_list.extend(slice_node2_2) -node_list.extend(slice_node3_1) -node_list.extend(slice_node3_2) -node_list.extend(slice_node4_1) -node_list.extend(slice_node4_2) -node_list.extend(slice_node5_1) -node_list.extend(slice_node5_2) -node_list.extend(slice_node6_1) -node_list.extend(slice_node6_2) -node_list.extend(slice_node7_1) -node_list.extend(slice_node7_2) -node_list.extend(['Concat_194']) - -node_list.extend(['Concat_222']) - -node_list.extend(['Concat_250']) - -node_list.extend(['Concat_283']) - -node_list.extend(['Concat_337']) - -node_list.extend(['Concat_369']) -node_list.extend(['Concat_310']) -#node_list.extend(['Concat_308','Constant_140','Constant_166','Constant_192','Constant_224','Constant_251','Constant_278','Constant_301','Constant_309']) -print(node_list) -RemoveNode2(model.graph, node_list) - -#移除最后一个Resize -# 去除最后一个resize节点 -node_list=[] -node_list.extend(['Resize_371']) -print(node_list) -RemoveNode2(model.graph, node_list) #将最后一个Resize节点移除 -#将ouput1移除,并建立一个新的,插入进去 - -out0_info = onnx.helper.make_tensor_value_info('721', onnx.TensorProto.FLOAT, [-1, 7, 176, 304]) -model.graph.output.remove(model.graph.output[0]) -model.graph.output.insert(0, out0_info) - -onnx.checker.check_model(model) - - -onnx.save(model, sys.argv[1].split('.')[0] + "_revised.onnx") -# m = onnx.load("modify.onnx") - - - +import numpy as np +import onnx +import onnxruntime as rt +from onnx import shape_inference +import sys +model_path = sys.argv[1] +model = onnx.load(model_path) + +# model = onnx.shape_inference.infer_shapes(model) + +def getNodeAndIOname(nodename,model): + for i in range(len(model.graph.node)): + if model.graph.node[i].name == nodename: + Node = model.graph.node[i] + return Node,input_name,output_name + +def FindPeerOutNode(graph, edge_name): + for i, x in enumerate(graph.node): + if edge_name in x.output: + return i + return -1 + + +def RemoveNode(graph, node_list): + cnt = 0 + for i in range(len(model.graph.node)): + if model.graph.node[i].name in node_list: + graph.node.remove(graph.node[i - cnt]) # 因为节点个数变少了 + cnt += 1 +def FindDependNode(graph, end_node, start_node): + ''' + find dependency node, [end_node, start_node) + ''' + def dfs(graph, idx, start_node, n_list): + for edge in graph.node[idx].input: + node_idx = FindPeerOutNode(graph, edge) + if node_idx < 0: + # print('bad peerout index') + continue + n = graph.node[node_idx] + if n.name != start_node: + n_list.append(n.name) + # print('n.name', n.name) + n_list = dfs(graph, node_idx, start_node, n_list) + return n_list + + index = GetNodeIndex(graph, end_node) + n_list = [end_node, ] + return dfs(graph, index, start_node, n_list) + + +def createGraphMemberMap(graph_member_list): + member_map=dict(); + for n in graph_member_list: + member_map[n.name]=n; + return member_map + +def GetNodeIndex(graph, node_name): + index = 0 + for i in range(len(graph.node)): + if graph.node[i].name == node_name: + index = i + break + return index +def RemoveNode2(graph,node_list): + for name in node_list: + print("name",name) + ind = GetNodeIndex(graph,name) + print("ind:",ind) + graph.node.remove(graph.node[ind]) + + +for i in range(len(model.graph.node)): + if model.graph.node[i].op_type == "Resize": + print("Resize", i, model.graph.node[i].input, model.graph.node[i].output) + +sizes1 = onnx.helper.make_tensor('size1', onnx.TensorProto.FLOAT, [4], [1, 1, 2, 2]) +sizes2 = onnx.helper.make_tensor('size2', onnx.TensorProto.FLOAT, [4], [1, 1, 2, 2]) +sizes3 = onnx.helper.make_tensor('size3', onnx.TensorProto.FLOAT, [4], [1, 1, 2, 2]) +sizes4 = onnx.helper.make_tensor('size4', onnx.TensorProto.FLOAT, [4], [1, 1, 2, 2]) +sizes5 = onnx.helper.make_tensor('size5', onnx.TensorProto.FLOAT, [4], [1, 1, 4, 4]) +sizes6 = onnx.helper.make_tensor('size6', onnx.TensorProto.FLOAT, [4], [1, 1, 8, 8]) +sizes7 = onnx.helper.make_tensor('size7', onnx.TensorProto.FLOAT, [4], [1, 1, 4, 4]) + + +model.graph.initializer.append(sizes1) +model.graph.initializer.append(sizes2) +model.graph.initializer.append(sizes3) +model.graph.initializer.append(sizes4) +model.graph.initializer.append(sizes5) +model.graph.initializer.append(sizes6) +model.graph.initializer.append(sizes7) + + +newnode = onnx.helper.make_node( + 'Resize', + name='Resize_196', + # inputs=['551', '564', '572', 'size1'], + inputs=['551', '564', 'size1'], + outputs=['573'], + coordinate_transformation_mode='pytorch_half_pixel', + cubic_coeff_a=-0.75, + mode='nearest', + nearest_mode='floor' +) + +newnode2 = onnx.helper.make_node( + 'Resize', + name='Resize_224', + # inputs=['347', '367', '375', 'size2'], + inputs=['579', '592', 'size2'], + outputs=['601'], + coordinate_transformation_mode='pytorch_half_pixel', + cubic_coeff_a=-0.75, + mode='nearest', + nearest_mode='floor' +) + +newnode3 = onnx.helper.make_node( + 'Resize', + name='Resize_252', + # inputs=['347', '367', '375', 'size2'], + inputs=['607', '620', 'size3'], + outputs=['629'], + coordinate_transformation_mode='pytorch_half_pixel', + cubic_coeff_a=-0.75, + mode='nearest', + nearest_mode='floor' +) + +newnode4 = onnx.helper.make_node( + 'Resize', + name='Resize_285', + # inputs=['347', '367', '375', 'size2'], + inputs=['607', '653', 'size4'], + outputs=['662'], + coordinate_transformation_mode='pytorch_half_pixel', + cubic_coeff_a=-0.75, + mode='nearest', + nearest_mode='floor' +) + + +newnode5 = onnx.helper.make_node( + 'Resize', + name='Resize_312', + # inputs=['347', '367', '375', 'size2'], + inputs=['579', '680', 'size5'], + outputs=['689'], + coordinate_transformation_mode='pytorch_half_pixel', + cubic_coeff_a=-0.75, + mode='nearest', + nearest_mode='floor' +) + + +newnode6 = onnx.helper.make_node( + 'Resize', + name='Resize_339', + # inputs=['347', '367', '375', 'size2'], + inputs=['551', '707', 'size6'], + outputs=['716'], + coordinate_transformation_mode='pytorch_half_pixel', + cubic_coeff_a=-0.75, + mode='nearest', + nearest_mode='floor' +) + + +newnode7= onnx.helper.make_node( + 'Resize', + name='Resize_371', + # inputs=['347', '367', '375', 'size2'], + inputs=['721', '739', 'size7'], + outputs=['output1'], + coordinate_transformation_mode='pytorch_half_pixel', + cubic_coeff_a=-0.75, + mode='nearest', + nearest_mode='floor' +) + + + + +model.graph.node.remove(model.graph.node[196]) +model.graph.node.insert(196, newnode) + +model.graph.node.remove(model.graph.node[224]) +model.graph.node.insert(224, newnode2) + +model.graph.node.remove(model.graph.node[252]) +model.graph.node.insert(252, newnode3) + +model.graph.node.remove(model.graph.node[285]) +model.graph.node.insert(285, newnode4) + +model.graph.node.remove(model.graph.node[312]) +model.graph.node.insert(312, newnode5) + +model.graph.node.remove(model.graph.node[339]) +model.graph.node.insert(339, newnode6) + +model.graph.node.remove(model.graph.node[371]) +model.graph.node.insert(371, newnode7) + +slice_node1_1 = FindDependNode(model.graph, 'Slice_192', 'Relu_174') #结尾(will be deleted) qishi +print('node map:', slice_node1_1) + +slice_node1_2 = FindDependNode(model.graph, 'Cast_193', 'Relu_177') +print('node map:', slice_node1_2) + +slice_node2_1 = FindDependNode(model.graph, 'Slice_220', 'Relu_202') +print('node map:', slice_node2_1) + +slice_node2_2 = FindDependNode(model.graph, 'Cast_221', 'Relu_205') +print('node map:', slice_node2_2) + +slice_node3_1 = FindDependNode(model.graph, 'Slice_248', 'Relu_230') +print('node map:', slice_node3_1) +slice_node3_2 = FindDependNode(model.graph, 'Cast_249', 'Relu_233') +print('node map:', slice_node3_2) + + +slice_node4_1 = FindDependNode(model.graph, 'Slice_281', 'Relu_230') +print('node map:', slice_node4_1) +slice_node4_2 = FindDependNode(model.graph, 'Cast_282', 'Relu_258') +print('node map:', slice_node4_2) + + +slice_node5_1 = FindDependNode(model.graph, 'Slice_308', 'Relu_202') +print('node map:', slice_node5_1) +slice_node5_2 = FindDependNode(model.graph, 'Cast_309', 'Relu_258') +print('node map:', slice_node5_2) + +slice_node6_1 = FindDependNode(model.graph, 'Slice_335', 'Relu_174') +print('node map:', slice_node6_1) +slice_node6_2 = FindDependNode(model.graph, 'Cast_336', 'Relu_258') +print('node map:', slice_node6_2) + +slice_node7_1 = FindDependNode(model.graph, 'Slice_367', 'Conv_344') +print('node map:', slice_node7_1) +slice_node7_2 = FindDependNode(model.graph, 'Cast_368', 'actual_input_1') +print('node map:', slice_node7_2) + + +node_list = [] +node_list.extend(slice_node1_1) +node_list.extend(slice_node1_2) +node_list.extend(slice_node2_1) +node_list.extend(slice_node2_2) +node_list.extend(slice_node3_1) +node_list.extend(slice_node3_2) +node_list.extend(slice_node4_1) +node_list.extend(slice_node4_2) +node_list.extend(slice_node5_1) +node_list.extend(slice_node5_2) +node_list.extend(slice_node6_1) +node_list.extend(slice_node6_2) +node_list.extend(slice_node7_1) +node_list.extend(slice_node7_2) +node_list.extend(['Concat_194']) + +node_list.extend(['Concat_222']) + +node_list.extend(['Concat_250']) + +node_list.extend(['Concat_283']) + +node_list.extend(['Concat_337']) + +node_list.extend(['Concat_369']) +node_list.extend(['Concat_310']) +#node_list.extend(['Concat_308','Constant_140','Constant_166','Constant_192','Constant_224','Constant_251','Constant_278','Constant_301','Constant_309']) +print(node_list) +RemoveNode2(model.graph, node_list) + +#移除最后一个Resize +# 去除最后一个resize节点 +node_list=[] +node_list.extend(['Resize_371']) +print(node_list) +RemoveNode2(model.graph, node_list) #将最后一个Resize节点移除 +#将ouput1移除,并建立一个新的,插入进去 + +out0_info = onnx.helper.make_tensor_value_info('721', onnx.TensorProto.FLOAT, [-1, 7, 176, 304]) +model.graph.output.remove(model.graph.output[0]) +model.graph.output.insert(0, out0_info) + +onnx.checker.check_model(model) + + +onnx.save(model, sys.argv[1].split('.')[0] + "_revised.onnx") +# m = onnx.load("modify.onnx") + + + diff --git a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/revise_PSENET_nearest2.py b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/revise_PSENET_nearest2.py index 509e413da4..241aad3caf 100644 --- a/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/revise_PSENET_nearest2.py +++ b/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch/revise_PSENET_nearest2.py @@ -1,274 +1,274 @@ -import numpy as np -import onnx -import onnxruntime as rt -from onnx import shape_inference -import sys - - -model_path = sys.argv[1] -model = onnx.load(model_path) - - -def getNodeAndIOname(nodename,model): - for i in range(len(model.graph.node)): - if model.graph.node[i].name == nodename: - Node = model.graph.node[i] - return Node,input_name,output_name - -def FindPeerOutNode(graph, edge_name): - for i, x in enumerate(graph.node): - if edge_name in x.output: - return i - return -1 - - -def RemoveNode(graph, node_list): - cnt = 0 - for i in range(len(model.graph.node)): - if model.graph.node[i].name in node_list: - graph.node.remove(graph.node[i - cnt]) # 因为节点个数变少了 - cnt += 1 - - -def FindDependNode(graph, end_node, start_node): - ''' - find dependency node, [end_node, start_node) - ''' - def dfs(graph, idx, start_node, n_list): - for edge in graph.node[idx].input: - node_idx = FindPeerOutNode(graph, edge) - if node_idx < 0: - # print('bad peerout index') - continue - n = graph.node[node_idx] - if n.name != start_node: - n_list.append(n.name) - # print('n.name', n.name) - n_list = dfs(graph, node_idx, start_node, n_list) - return n_list - - index = GetNodeIndex(graph, end_node) - n_list = [end_node, ] - return dfs(graph, index, start_node, n_list) - - -def createGraphMemberMap(graph_member_list): - member_map=dict(); - for n in graph_member_list: - member_map[n.name]=n; - return member_map - -def GetNodeIndex(graph, node_name): - index = 0 - for i in range(len(graph.node)): - if graph.node[i].name == node_name: - index = i - break - return index -def RemoveNode2(graph,node_list): - for name in node_list: - print("name",name) - ind = GetNodeIndex(graph,name) - print("ind:",ind) - graph.node.remove(graph.node[ind]) - - -for i in range(len(model.graph.node)): - if model.graph.node[i].op_type == "Resize": - print("Resize", i, model.graph.node[i].input, model.graph.node[i].output) - -sizes1 = onnx.helper.make_tensor('size1', onnx.TensorProto.FLOAT, [4], [1, 1, 2, 2]) -sizes2 = onnx.helper.make_tensor('size2', onnx.TensorProto.FLOAT, [4], [1, 1, 2, 2]) -sizes3 = onnx.helper.make_tensor('size3', onnx.TensorProto.FLOAT, [4], [1, 1, 2, 2]) -sizes4 = onnx.helper.make_tensor('size4', onnx.TensorProto.FLOAT, [4], [1, 1, 2, 2]) -sizes5 = onnx.helper.make_tensor('size5', onnx.TensorProto.FLOAT, [4], [1, 1, 4, 4]) -sizes6 = onnx.helper.make_tensor('size6', onnx.TensorProto.FLOAT, [4], [1, 1, 8, 8]) -sizes7 = onnx.helper.make_tensor('size7', onnx.TensorProto.FLOAT, [4], [1, 1, 4, 4]) - - -model.graph.initializer.append(sizes1) -model.graph.initializer.append(sizes2) -model.graph.initializer.append(sizes3) -model.graph.initializer.append(sizes4) -model.graph.initializer.append(sizes5) -model.graph.initializer.append(sizes6) -model.graph.initializer.append(sizes7) - - -newnode = onnx.helper.make_node( - 'Resize', - name='Resize_141', - # inputs=['551', '564', '572', 'size1'], - inputs=['551', '564', 'size1'], - outputs=['573'], - coordinate_transformation_mode='asymmetric', - cubic_coeff_a=-0.75, - mode='nearest', - nearest_mode='floor' -) - -newnode2 = onnx.helper.make_node( - 'Resize', - name='Resize_165', - # inputs=['347', '367', '375', 'size2'], - inputs=['577', '590', 'size2'], - outputs=['599'], - coordinate_transformation_mode='asymmetric', - cubic_coeff_a=-0.75, - mode='nearest', - nearest_mode='floor' -) - -newnode3 = onnx.helper.make_node( - 'Resize', - name='Resize_189', - # inputs=['347', '367', '375', 'size2'], - inputs=['603', '616', 'size3'], - outputs=['625'], - coordinate_transformation_mode='asymmetric', - cubic_coeff_a=-0.75, - mode='nearest', - nearest_mode='floor' -) - -newnode4 = onnx.helper.make_node( - 'Resize', - name='Resize_219', - # inputs=['347', '367', '375', 'size2'], - inputs=['603', '647', 'size4'], - outputs=['656'], - coordinate_transformation_mode='asymmetric', - cubic_coeff_a=-0.75, - mode='nearest', - nearest_mode='floor' -) - - -newnode5 = onnx.helper.make_node( - 'Resize', - name='Resize_246', - # inputs=['347', '367', '375', 'size2'], - inputs=['577', '674', 'size5'], - outputs=['683'], - coordinate_transformation_mode='asymmetric', - cubic_coeff_a=-0.75, - mode='nearest', - nearest_mode='floor' -) - - -newnode6 = onnx.helper.make_node( - 'Resize', - name='Resize_273', - # inputs=['347', '367', '375', 'size2'], - inputs=['551', '701', 'size6'], - outputs=['710'], - coordinate_transformation_mode='asymmetric', - cubic_coeff_a=-0.75, - mode='nearest', - nearest_mode='floor' -) - - -newnode7= onnx.helper.make_node( - 'Resize', - name='Resize_304', - # inputs=['347', '367', '375', 'size2'], - inputs=['715', '733', 'size7'], - outputs=['output1'], - coordinate_transformation_mode='asymmetric', - cubic_coeff_a=-0.75, - mode='nearest', - nearest_mode='floor' -) - - -model.graph.node.remove(model.graph.node[141]) -model.graph.node.insert(141, newnode) - -model.graph.node.remove(model.graph.node[165]) -model.graph.node.insert(165, newnode2) - -model.graph.node.remove(model.graph.node[189]) -model.graph.node.insert(189, newnode3) - -model.graph.node.remove(model.graph.node[219]) -model.graph.node.insert(219, newnode4) - -model.graph.node.remove(model.graph.node[246]) -model.graph.node.insert(246, newnode5) - -model.graph.node.remove(model.graph.node[273]) -model.graph.node.insert(273, newnode6) - -model.graph.node.remove(model.graph.node[304]) -model.graph.node.insert(304, newnode7) - -slice_node1_1 = FindDependNode(model.graph, 'Slice_137', 'Relu_120') #结尾(will be deleted) qishi -print('node map:', slice_node1_1) - -slice_node1_2 = FindDependNode(model.graph, 'Cast_138', 'Relu_122') -print('node map:', slice_node1_2) - -slice_node2_1 = FindDependNode(model.graph, 'Slice_161', 'Relu_144') -print('node map:', slice_node2_1) - -slice_node2_2 = FindDependNode(model.graph, 'Cast_162', 'Relu_146') -print('node map:', slice_node2_2) - -slice_node3_1 = FindDependNode(model.graph, 'Slice_185', 'Relu_168') -print('node map:', slice_node3_1) -slice_node3_2 = FindDependNode(model.graph, 'Cast_186', 'Relu_170') -print('node map:', slice_node3_2) - - -slice_node4_1 = FindDependNode(model.graph, 'Slice_215', 'Relu_168') -print('node map:', slice_node4_1) -slice_node4_2 = FindDependNode(model.graph, 'Cast_216', 'Relu_192') -print('node map:', slice_node4_2) - - -slice_node5_1 = FindDependNode(model.graph, 'Slice_242', 'Relu_144') -print('node map:', slice_node5_1) -slice_node5_2 = FindDependNode(model.graph, 'Cast_243', 'Relu_192') -print('node map:', slice_node5_2) - -slice_node6_1 = FindDependNode(model.graph, 'Slice_269', 'Relu_120') -print('node map:', slice_node6_1) -slice_node6_2 = FindDependNode(model.graph, 'Cast_270', 'Relu_192') -print('node map:', slice_node6_2) - -slice_node7_1 = FindDependNode(model.graph, 'Slice_300', 'Conv_277') -print('node map:', slice_node7_1) -slice_node7_2 = FindDependNode(model.graph, 'Cast_301', 'actual_input_1') -print('node map:', slice_node7_2) - - -node_list = [] -node_list.extend(slice_node1_1) -node_list.extend(slice_node1_2) -node_list.extend(slice_node2_1) -node_list.extend(slice_node2_2) -node_list.extend(slice_node3_1) -node_list.extend(slice_node3_2) -node_list.extend(slice_node4_1) -node_list.extend(slice_node4_2) -node_list.extend(slice_node5_1) -node_list.extend(slice_node5_2) -node_list.extend(slice_node6_1) -node_list.extend(slice_node6_2) -node_list.extend(slice_node7_1) -node_list.extend(slice_node7_2) -node_list.extend(['Concat_139']) -node_list.extend(['Concat_163']) -node_list.extend(['Concat_187']) -node_list.extend(['Concat_217']) -node_list.extend(['Concat_271']) -node_list.extend(['Concat_302']) -node_list.extend(['Concat_244']) -print(node_list) -RemoveNode2(model.graph, node_list) - - -onnx.checker.check_model(model) -onnx.save(model, sys.argv[1].split('.')[0] + "_revised2.onnx") +import numpy as np +import onnx +import onnxruntime as rt +from onnx import shape_inference +import sys + + +model_path = sys.argv[1] +model = onnx.load(model_path) + + +def getNodeAndIOname(nodename,model): + for i in range(len(model.graph.node)): + if model.graph.node[i].name == nodename: + Node = model.graph.node[i] + return Node,input_name,output_name + +def FindPeerOutNode(graph, edge_name): + for i, x in enumerate(graph.node): + if edge_name in x.output: + return i + return -1 + + +def RemoveNode(graph, node_list): + cnt = 0 + for i in range(len(model.graph.node)): + if model.graph.node[i].name in node_list: + graph.node.remove(graph.node[i - cnt]) # 因为节点个数变少了 + cnt += 1 + + +def FindDependNode(graph, end_node, start_node): + ''' + find dependency node, [end_node, start_node) + ''' + def dfs(graph, idx, start_node, n_list): + for edge in graph.node[idx].input: + node_idx = FindPeerOutNode(graph, edge) + if node_idx < 0: + # print('bad peerout index') + continue + n = graph.node[node_idx] + if n.name != start_node: + n_list.append(n.name) + # print('n.name', n.name) + n_list = dfs(graph, node_idx, start_node, n_list) + return n_list + + index = GetNodeIndex(graph, end_node) + n_list = [end_node, ] + return dfs(graph, index, start_node, n_list) + + +def createGraphMemberMap(graph_member_list): + member_map=dict(); + for n in graph_member_list: + member_map[n.name]=n; + return member_map + +def GetNodeIndex(graph, node_name): + index = 0 + for i in range(len(graph.node)): + if graph.node[i].name == node_name: + index = i + break + return index +def RemoveNode2(graph,node_list): + for name in node_list: + print("name",name) + ind = GetNodeIndex(graph,name) + print("ind:",ind) + graph.node.remove(graph.node[ind]) + + +for i in range(len(model.graph.node)): + if model.graph.node[i].op_type == "Resize": + print("Resize", i, model.graph.node[i].input, model.graph.node[i].output) + +sizes1 = onnx.helper.make_tensor('size1', onnx.TensorProto.FLOAT, [4], [1, 1, 2, 2]) +sizes2 = onnx.helper.make_tensor('size2', onnx.TensorProto.FLOAT, [4], [1, 1, 2, 2]) +sizes3 = onnx.helper.make_tensor('size3', onnx.TensorProto.FLOAT, [4], [1, 1, 2, 2]) +sizes4 = onnx.helper.make_tensor('size4', onnx.TensorProto.FLOAT, [4], [1, 1, 2, 2]) +sizes5 = onnx.helper.make_tensor('size5', onnx.TensorProto.FLOAT, [4], [1, 1, 4, 4]) +sizes6 = onnx.helper.make_tensor('size6', onnx.TensorProto.FLOAT, [4], [1, 1, 8, 8]) +sizes7 = onnx.helper.make_tensor('size7', onnx.TensorProto.FLOAT, [4], [1, 1, 4, 4]) + + +model.graph.initializer.append(sizes1) +model.graph.initializer.append(sizes2) +model.graph.initializer.append(sizes3) +model.graph.initializer.append(sizes4) +model.graph.initializer.append(sizes5) +model.graph.initializer.append(sizes6) +model.graph.initializer.append(sizes7) + + +newnode = onnx.helper.make_node( + 'Resize', + name='Resize_141', + # inputs=['551', '564', '572', 'size1'], + inputs=['551', '564', 'size1'], + outputs=['573'], + coordinate_transformation_mode='asymmetric', + cubic_coeff_a=-0.75, + mode='nearest', + nearest_mode='floor' +) + +newnode2 = onnx.helper.make_node( + 'Resize', + name='Resize_165', + # inputs=['347', '367', '375', 'size2'], + inputs=['577', '590', 'size2'], + outputs=['599'], + coordinate_transformation_mode='asymmetric', + cubic_coeff_a=-0.75, + mode='nearest', + nearest_mode='floor' +) + +newnode3 = onnx.helper.make_node( + 'Resize', + name='Resize_189', + # inputs=['347', '367', '375', 'size2'], + inputs=['603', '616', 'size3'], + outputs=['625'], + coordinate_transformation_mode='asymmetric', + cubic_coeff_a=-0.75, + mode='nearest', + nearest_mode='floor' +) + +newnode4 = onnx.helper.make_node( + 'Resize', + name='Resize_219', + # inputs=['347', '367', '375', 'size2'], + inputs=['603', '647', 'size4'], + outputs=['656'], + coordinate_transformation_mode='asymmetric', + cubic_coeff_a=-0.75, + mode='nearest', + nearest_mode='floor' +) + + +newnode5 = onnx.helper.make_node( + 'Resize', + name='Resize_246', + # inputs=['347', '367', '375', 'size2'], + inputs=['577', '674', 'size5'], + outputs=['683'], + coordinate_transformation_mode='asymmetric', + cubic_coeff_a=-0.75, + mode='nearest', + nearest_mode='floor' +) + + +newnode6 = onnx.helper.make_node( + 'Resize', + name='Resize_273', + # inputs=['347', '367', '375', 'size2'], + inputs=['551', '701', 'size6'], + outputs=['710'], + coordinate_transformation_mode='asymmetric', + cubic_coeff_a=-0.75, + mode='nearest', + nearest_mode='floor' +) + + +newnode7= onnx.helper.make_node( + 'Resize', + name='Resize_304', + # inputs=['347', '367', '375', 'size2'], + inputs=['715', '733', 'size7'], + outputs=['output1'], + coordinate_transformation_mode='asymmetric', + cubic_coeff_a=-0.75, + mode='nearest', + nearest_mode='floor' +) + + +model.graph.node.remove(model.graph.node[141]) +model.graph.node.insert(141, newnode) + +model.graph.node.remove(model.graph.node[165]) +model.graph.node.insert(165, newnode2) + +model.graph.node.remove(model.graph.node[189]) +model.graph.node.insert(189, newnode3) + +model.graph.node.remove(model.graph.node[219]) +model.graph.node.insert(219, newnode4) + +model.graph.node.remove(model.graph.node[246]) +model.graph.node.insert(246, newnode5) + +model.graph.node.remove(model.graph.node[273]) +model.graph.node.insert(273, newnode6) + +model.graph.node.remove(model.graph.node[304]) +model.graph.node.insert(304, newnode7) + +slice_node1_1 = FindDependNode(model.graph, 'Slice_137', 'Relu_120') #结尾(will be deleted) qishi +print('node map:', slice_node1_1) + +slice_node1_2 = FindDependNode(model.graph, 'Cast_138', 'Relu_122') +print('node map:', slice_node1_2) + +slice_node2_1 = FindDependNode(model.graph, 'Slice_161', 'Relu_144') +print('node map:', slice_node2_1) + +slice_node2_2 = FindDependNode(model.graph, 'Cast_162', 'Relu_146') +print('node map:', slice_node2_2) + +slice_node3_1 = FindDependNode(model.graph, 'Slice_185', 'Relu_168') +print('node map:', slice_node3_1) +slice_node3_2 = FindDependNode(model.graph, 'Cast_186', 'Relu_170') +print('node map:', slice_node3_2) + + +slice_node4_1 = FindDependNode(model.graph, 'Slice_215', 'Relu_168') +print('node map:', slice_node4_1) +slice_node4_2 = FindDependNode(model.graph, 'Cast_216', 'Relu_192') +print('node map:', slice_node4_2) + + +slice_node5_1 = FindDependNode(model.graph, 'Slice_242', 'Relu_144') +print('node map:', slice_node5_1) +slice_node5_2 = FindDependNode(model.graph, 'Cast_243', 'Relu_192') +print('node map:', slice_node5_2) + +slice_node6_1 = FindDependNode(model.graph, 'Slice_269', 'Relu_120') +print('node map:', slice_node6_1) +slice_node6_2 = FindDependNode(model.graph, 'Cast_270', 'Relu_192') +print('node map:', slice_node6_2) + +slice_node7_1 = FindDependNode(model.graph, 'Slice_300', 'Conv_277') +print('node map:', slice_node7_1) +slice_node7_2 = FindDependNode(model.graph, 'Cast_301', 'actual_input_1') +print('node map:', slice_node7_2) + + +node_list = [] +node_list.extend(slice_node1_1) +node_list.extend(slice_node1_2) +node_list.extend(slice_node2_1) +node_list.extend(slice_node2_2) +node_list.extend(slice_node3_1) +node_list.extend(slice_node3_2) +node_list.extend(slice_node4_1) +node_list.extend(slice_node4_2) +node_list.extend(slice_node5_1) +node_list.extend(slice_node5_2) +node_list.extend(slice_node6_1) +node_list.extend(slice_node6_2) +node_list.extend(slice_node7_1) +node_list.extend(slice_node7_2) +node_list.extend(['Concat_139']) +node_list.extend(['Concat_163']) +node_list.extend(['Concat_187']) +node_list.extend(['Concat_217']) +node_list.extend(['Concat_271']) +node_list.extend(['Concat_302']) +node_list.extend(['Concat_244']) +print(node_list) +RemoveNode2(model.graph, node_list) + + +onnx.checker.check_model(model) +onnx.save(model, sys.argv[1].split('.')[0] + "_revised2.onnx") diff --git a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/ README.md b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/ README.md index ed4d548672..3ba53d56b1 100644 --- a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/ README.md +++ b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/ README.md @@ -1,82 +1,82 @@ -# Res2Net_v1b_101模型测试指导 - -- [1 文件说明](#1-文件说明) -- [2 设置环境变量](#2-设置环境变量) -- [3 端到端推理步骤](#3-端到端推理步骤) - - [3.1 下载代码](#31-下载代码) - - [3.2 om模型转换](#32-om模型转换) - - [3.3 om模型推理](#33-om模型推理) - ------- - -## 1 文件说明 -``` -Res2Net_v1b_101_for_PyTorch - ├── get_info.py // 生成推理输入的数据集二进制info文件或jpg info文件 - ├── pth2onnx.py // 用于转换pth模型文件到onnx模型文件 - ├── diff.patch // 修改开源代码的patch文件 - ├── imagenet_torch_preprocess.py // imagenet数据集预处理,生成图片二进制文件 - ├── README.md - ├── atc.sh // onnx模型转换om模型脚本 - └── vision_metric_ImageNet.py // 验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy - -``` - -## 2 设置环境变量 - -```shell -source env.sh -``` - -## 3 端到端推理步骤 - -### 3.1 下载代码 -git clone 开源仓 https://github.com/Res2Net/Res2Net-PretrainedModels ,切换到所需tag。 -```shell -git clone https://github.com/Res2Net/Res2Net-PretrainedModels.git -cd Res2Net-PretrainedModels -git reset 1d51000f3340fb61b4 --hard -git apply diff.patch -``` - -### 3.2 om模型转换 - -通过pth2onnx.py脚本转化为onnx模型 - -```shell -python3.7 pth2onnx.py -m ./res2net101_v1b_26w_4s-0812c246.pth -o ./res2net.onnx -``` - -利用ATC工具转换为om模型 -```shell -bash atc.sh -``` - -### 3.3 om模型推理 - -(1) 数据集预处理 - - 数据预处理,把ImageNet 50000张图片转为二进制文件(.bin) - - ```shell - python3.7 imagenet_torch_preprocess.py res2net101 /home/HwHiAiUser/dataset/ImageNet/ILSVRC2012_img_val ./prep_bin - ``` - 生成数据集info文件 - - ```shell - python3.7 get_info.py bin ./prep_bin ./BinaryImageNet.info 224 224 - ``` -(2)推理 - 配置环境变量,运行benchmark工具进行推理,参数说明参见 [cann-benchmark](https://gitee.com/ascend/cann-benchmark/tree/master/infer) - - ```shell - source env.sh # 如果前面配置过,这里不用执行 - ./benchmark -model_type=vision -om_path=resnet_bs16.om -device_id=0 -batch_size=16 -input_text_path=BinaryImageNet.info -input_width=256 -input_height=256 -useDvpp=false -output_binary=false - ``` - -(3)统计Accuracy值 - 精度验证,调用vision_metric_ImageNet.py脚本与数据集标签val_label.txt比对,可以获得Accuracy数据,结果保存在result.json中 - - ```shell - python3.7 vision_metric_ImageNet.py result/dumpOutput_device0/ ./val_label.txt ./ result.json - ``` +# Res2Net_v1b_101模型测试指导 + +- [1 文件说明](#1-文件说明) +- [2 设置环境变量](#2-设置环境变量) +- [3 端到端推理步骤](#3-端到端推理步骤) + - [3.1 下载代码](#31-下载代码) + - [3.2 om模型转换](#32-om模型转换) + - [3.3 om模型推理](#33-om模型推理) + +------ + +## 1 文件说明 +``` +Res2Net_v1b_101_for_PyTorch + ├── get_info.py // 生成推理输入的数据集二进制info文件或jpg info文件 + ├── pth2onnx.py // 用于转换pth模型文件到onnx模型文件 + ├── diff.patch // 修改开源代码的patch文件 + ├── imagenet_torch_preprocess.py // imagenet数据集预处理,生成图片二进制文件 + ├── README.md + ├── atc.sh // onnx模型转换om模型脚本 + └── vision_metric_ImageNet.py // 验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy + +``` + +## 2 设置环境变量 + +```shell +source env.sh +``` + +## 3 端到端推理步骤 + +### 3.1 下载代码 +git clone 开源仓 https://github.com/Res2Net/Res2Net-PretrainedModels ,切换到所需tag。 +```shell +git clone https://github.com/Res2Net/Res2Net-PretrainedModels.git +cd Res2Net-PretrainedModels +git reset 1d51000f3340fb61b4 --hard +git apply diff.patch +``` + +### 3.2 om模型转换 + +通过pth2onnx.py脚本转化为onnx模型 + +```shell +python3.7 pth2onnx.py -m ./res2net101_v1b_26w_4s-0812c246.pth -o ./res2net.onnx +``` + +利用ATC工具转换为om模型 +```shell +bash atc.sh +``` + +### 3.3 om模型推理 + +(1) 数据集预处理 + + 数据预处理,把ImageNet 50000张图片转为二进制文件(.bin) + + ```shell + python3.7 imagenet_torch_preprocess.py res2net101 /home/HwHiAiUser/dataset/ImageNet/ILSVRC2012_img_val ./prep_bin + ``` + 生成数据集info文件 + + ```shell + python3.7 get_info.py bin ./prep_bin ./BinaryImageNet.info 224 224 + ``` +(2)推理 + 配置环境变量,运行benchmark工具进行推理,参数说明参见 [cann-benchmark](https://gitee.com/ascend/cann-benchmark/tree/master/infer) + + ```shell + source env.sh # 如果前面配置过,这里不用执行 + ./benchmark -model_type=vision -om_path=resnet_bs16.om -device_id=0 -batch_size=16 -input_text_path=BinaryImageNet.info -input_width=256 -input_height=256 -useDvpp=false -output_binary=false + ``` + +(3)统计Accuracy值 + 精度验证,调用vision_metric_ImageNet.py脚本与数据集标签val_label.txt比对,可以获得Accuracy数据,结果保存在result.json中 + + ```shell + python3.7 vision_metric_ImageNet.py result/dumpOutput_device0/ ./val_label.txt ./ result.json + ``` diff --git a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/ imagenet_torch_preprocess.py b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/ imagenet_torch_preprocess.py index b0af0d5d04..91cf3472e5 100644 --- a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/ imagenet_torch_preprocess.py +++ b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/ imagenet_torch_preprocess.py @@ -1,116 +1,116 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -from PIL import Image -import numpy as np -import multiprocessing - - -model_config = { - 'res2net101': { - 'resize': 256, - 'centercrop': 224, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv3': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv4': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.5, 0.5, 0.5], - 'std': [0.5, 0.5, 0.5], - }, -} - - -def center_crop(img, output_size): - if isinstance(output_size, int): - output_size = (int(output_size), int(output_size)) - image_width, image_height = img.size - crop_height, crop_width = output_size - crop_top = int(round((image_height - crop_height) / 2.)) - crop_left = int(round((image_width - crop_width) / 2.)) - return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) - - -def resize(img, size, interpolation=Image.BILINEAR): - if isinstance(size, int): - w, h = img.size - if (w <= h and w == size) or (h <= w and h == size): - return img - if w < h: - ow = size - oh = int(size * h / w) - return img.resize((ow, oh), interpolation) - else: - oh = size - ow = int(size * w / h) - return img.resize((ow, oh), interpolation) - else: - return img.resize(size[::-1], interpolation) - - -def gen_input_bin(mode_type, file_batches, batch): - i = 0 - for file in file_batches[batch]: - i = i + 1 - print("batch", batch, file, "===", i) - - # RGBA to RGB - image = Image.open(os.path.join(src_path, file)).convert('RGB') - image = resize(image, model_config[mode_type]['resize']) # Resize - image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop - img = np.array(image, dtype=np.float32) - img = img.transpose(2, 0, 1) # ToTensor: HWC -> CHW - img = img / 255. # ToTensor: div 255 - img -= np.array(model_config[mode_type]['mean'], dtype=np.float32)[:, None, None] # Normalize: mean - img /= np.array(model_config[mode_type]['std'], dtype=np.float32)[:, None, None] # Normalize: std - img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) - - -def preprocess(mode_type, src_path, save_path): - files = os.listdir(src_path) - file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] - thread_pool = multiprocessing.Pool(len(file_batches)) - for batch in range(len(file_batches)): - thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) - thread_pool.close() - thread_pool.join() - print("in thread, except will not report! please ensure bin files generated.") - - -if __name__ == '__main__': - if len(sys.argv) < 4: - raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") - mode_type = sys.argv[1] - src_path = sys.argv[2] - save_path = sys.argv[3] - src_path = os.path.realpath(src_path) - save_path = os.path.realpath(save_path) - if mode_type not in model_config: - model_type_help = "model type: " - for key in model_config.keys(): - model_type_help += key - model_type_help += ' ' - raise Exception(model_type_help) - if not os.path.isdir(save_path): - os.makedirs(os.path.realpath(save_path)) - preprocess(mode_type, src_path, save_path) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +from PIL import Image +import numpy as np +import multiprocessing + + +model_config = { + 'res2net101': { + 'resize': 256, + 'centercrop': 224, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv3': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv4': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.5, 0.5, 0.5], + 'std': [0.5, 0.5, 0.5], + }, +} + + +def center_crop(img, output_size): + if isinstance(output_size, int): + output_size = (int(output_size), int(output_size)) + image_width, image_height = img.size + crop_height, crop_width = output_size + crop_top = int(round((image_height - crop_height) / 2.)) + crop_left = int(round((image_width - crop_width) / 2.)) + return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) + + +def resize(img, size, interpolation=Image.BILINEAR): + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def gen_input_bin(mode_type, file_batches, batch): + i = 0 + for file in file_batches[batch]: + i = i + 1 + print("batch", batch, file, "===", i) + + # RGBA to RGB + image = Image.open(os.path.join(src_path, file)).convert('RGB') + image = resize(image, model_config[mode_type]['resize']) # Resize + image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop + img = np.array(image, dtype=np.float32) + img = img.transpose(2, 0, 1) # ToTensor: HWC -> CHW + img = img / 255. # ToTensor: div 255 + img -= np.array(model_config[mode_type]['mean'], dtype=np.float32)[:, None, None] # Normalize: mean + img /= np.array(model_config[mode_type]['std'], dtype=np.float32)[:, None, None] # Normalize: std + img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) + + +def preprocess(mode_type, src_path, save_path): + files = os.listdir(src_path) + file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] + thread_pool = multiprocessing.Pool(len(file_batches)) + for batch in range(len(file_batches)): + thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) + thread_pool.close() + thread_pool.join() + print("in thread, except will not report! please ensure bin files generated.") + + +if __name__ == '__main__': + if len(sys.argv) < 4: + raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") + mode_type = sys.argv[1] + src_path = sys.argv[2] + save_path = sys.argv[3] + src_path = os.path.realpath(src_path) + save_path = os.path.realpath(save_path) + if mode_type not in model_config: + model_type_help = "model type: " + for key in model_config.keys(): + model_type_help += key + model_type_help += ' ' + raise Exception(model_type_help) + if not os.path.isdir(save_path): + os.makedirs(os.path.realpath(save_path)) + preprocess(mode_type, src_path, save_path) diff --git a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/ requirements.txt b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/ requirements.txt index 6f7e11bdad..e71bbad34d 100644 --- a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/ requirements.txt +++ b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/ requirements.txt @@ -1,6 +1,6 @@ -matplotlib==3.5.0 -Pillow==8.4.0 -numpy==1.19.5 -torchvision==0.11.0 -torch==1.10.0 +matplotlib==3.5.0 +Pillow==8.4.0 +numpy==1.19.5 +torchvision==0.11.0 +torch==1.10.0 onnx==1.7.0 \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/LICENSE b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/LICENSE index 29f81d812f..261eeb9e9f 100644 --- a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/LICENSE +++ b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/atc.sh b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/atc.sh index e98af05173..39a1992278 100644 --- a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/atc.sh +++ b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/atc.sh @@ -1,16 +1,16 @@ -# 配置环境变量 -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp - -# 710 fp16,执行如下命令 -atc --model=./res2net.onnx \ - --framework=5 \ - --output=res2net_bs16 \ - --input_format=NCHW \ - --input_shape="x:16,3,224,224" \ - --log=error \ - --soc_version=Ascend710 \ - --enable_small_channel=1 +# 配置环境变量 +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp + +# 710 fp16,执行如下命令 +atc --model=./res2net.onnx \ + --framework=5 \ + --output=res2net_bs16 \ + --input_format=NCHW \ + --input_shape="x:16,3,224,224" \ + --log=error \ + --soc_version=Ascend710 \ + --enable_small_channel=1 diff --git a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/diff.patch b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/diff.patch index dd78507002..5770c5852f 100644 --- a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/diff.patch +++ b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/diff.patch @@ -1,32 +1,32 @@ -diff --git a/res2net_v1b.py b/res2net_v1b.py -index 6ced156..0ec1ce8 100644 ---- a/res2net_v1b.py -+++ b/res2net_v1b.py -@@ -64,6 +64,7 @@ class Bottle2neck(nn.Module): - out = self.relu(out) - - spx = torch.split(out, self.width, 1) -+ out_list = [] - for i in range(self.nums): - if i==0 or self.stype=='stage': - sp = spx[i] -@@ -71,15 +72,13 @@ class Bottle2neck(nn.Module): - sp = sp + spx[i] - sp = self.convs[i](sp) - sp = self.relu(self.bns[i](sp)) -- if i==0: -- out = sp -- else: -- out = torch.cat((out, sp), 1) -+ out_list.append(sp) - if self.scale != 1 and self.stype=='normal': -- out = torch.cat((out, spx[self.nums]),1) -+ out_list.append(spx[self.nums]) - elif self.scale != 1 and self.stype=='stage': -- out = torch.cat((out, self.pool(spx[self.nums])),1) -+ out_list.append(self.pool(spx[self.nums])) - -+ out = torch.cat(out_list, 1) - out = self.conv3(out) - out = self.bn3(out) - +diff --git a/res2net_v1b.py b/res2net_v1b.py +index 6ced156..0ec1ce8 100644 +--- a/res2net_v1b.py ++++ b/res2net_v1b.py +@@ -64,6 +64,7 @@ class Bottle2neck(nn.Module): + out = self.relu(out) + + spx = torch.split(out, self.width, 1) ++ out_list = [] + for i in range(self.nums): + if i==0 or self.stype=='stage': + sp = spx[i] +@@ -71,15 +72,13 @@ class Bottle2neck(nn.Module): + sp = sp + spx[i] + sp = self.convs[i](sp) + sp = self.relu(self.bns[i](sp)) +- if i==0: +- out = sp +- else: +- out = torch.cat((out, sp), 1) ++ out_list.append(sp) + if self.scale != 1 and self.stype=='normal': +- out = torch.cat((out, spx[self.nums]),1) ++ out_list.append(spx[self.nums]) + elif self.scale != 1 and self.stype=='stage': +- out = torch.cat((out, self.pool(spx[self.nums])),1) ++ out_list.append(self.pool(spx[self.nums])) + ++ out = torch.cat(out_list, 1) + out = self.conv3(out) + out = self.bn3(out) + diff --git a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/env.sh b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/env.sh index 91b1a00516..96389fea98 100644 --- a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/env.sh +++ b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/env.sh @@ -1,7 +1,7 @@ -#!/bin/bash -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:/usr/local/Ascend/ascend-toolkit/latest/pyACL/python/site-packages/acl:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp +#!/bin/bash +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:/usr/local/Ascend/ascend-toolkit/latest/pyACL/python/site-packages/acl:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp echo "successfully!!" \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/get_info.py b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/get_info.py index 6077f1416b..fa3108bd7f 100644 --- a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/get_info.py +++ b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/get_info.py @@ -1,60 +1,60 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' - get_jpg_info(file_path, info_name) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' + get_jpg_info(file_path, info_name) diff --git a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/modelzoo_level.txt b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/modelzoo_level.txt +++ b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/pth2onnx.py b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/pth2onnx.py index 852d370ee6..0c6b574d8b 100644 --- a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/pth2onnx.py +++ b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/pth2onnx.py @@ -1,76 +1,76 @@ -# Copyright 2022 Huawei Technologies Co., Ltd -# -# 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 itertools -import argparse -from res2net_v1b import res2net101_v1b_26w_4s -import torch -import torch.nn.functional as F - -parser = argparse.ArgumentParser(description='res2net101_v1b inference') -parser.add_argument('-m', '--trained_model', default=None, - type=str, help='Trained state_dict file path to open') -parser.add_argument('-o', '--output', default=None, - type=str, help='ONNX model file') -args = parser.parse_args() - -model = res2net101_v1b_26w_4s() -checkpoint = torch.load(args.trained_model, map_location=torch.device('cpu')) - -presistent_buffers = {k: v for k, v in model.named_buffers() if k not in model._non_persistent_buffers_set} -local_name_params = itertools.chain(model.named_parameters(), presistent_buffers.items()) -local_state = {k: v for k, v in local_name_params if v is not None} - -for name, param in checkpoint.items(): - if local_state[name].shape != param.shape: - if 'conv1' in name or 'conv3' in name: - n1, c1, h, w = local_state[name].shape - n2, c2, h, w = param.shape - if n1 == n2: - c = (c1 - c2) // 4 - cell = c2 // 4 - checkpoint[name] = torch.cat([torch.cat((param[:, i * cell: (i + 1) * cell, ...], - torch.zeros(n1, c, h, w, dtype=param.dtype)), - 1) for i in range(4)], 1) - else: - n = (n1 - n2) // 4 - cell = n2 // 4 - checkpoint[name] = torch.cat([torch.cat((param[i * cell: (i + 1) * cell, ...], - torch.zeros(n, c1, h, w, dtype=param.dtype)), - 0) for i in range(4)], 0) - elif 'bn1' in name or 'bn3' in name: - cell = param.size(0) // 4 - n = (local_state[name].size(0) - param.size(0)) // 4 - checkpoint[name] = torch.cat([torch.cat((param[i * cell: (i + 1) * cell], - torch.zeros(n, dtype=param.dtype)), - 0) for i in range(4)]) - else: - if param.dim() == 1: - checkpoint[name] = torch.cat((param, - torch.zeros(local_state[name].size(0) - param.size(0), dtype=param.dtype)), - 0) - else: - n1, c1, h, w = local_state[name].shape - n2, c2, h, w = param.shape - param = torch.cat((param, torch.zeros(n2, c1 - c2, h, w, dtype=param.dtype)), 1) - checkpoint[name] = torch.cat((param, torch.zeros(n1 - n2, c1, h, w, dtype=param.dtype)), 0) - -model.load_state_dict(checkpoint) -model.eval() - -inputs = torch.rand(1, 3, 224, 224) -torch.onnx.export(model, inputs, args.output, - input_names=["x"], output_names=["output"], - dynamic_axes={"x": {0: "-1"}}, opset_version=11) +# Copyright 2022 Huawei Technologies Co., Ltd +# +# 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 itertools +import argparse +from res2net_v1b import res2net101_v1b_26w_4s +import torch +import torch.nn.functional as F + +parser = argparse.ArgumentParser(description='res2net101_v1b inference') +parser.add_argument('-m', '--trained_model', default=None, + type=str, help='Trained state_dict file path to open') +parser.add_argument('-o', '--output', default=None, + type=str, help='ONNX model file') +args = parser.parse_args() + +model = res2net101_v1b_26w_4s() +checkpoint = torch.load(args.trained_model, map_location=torch.device('cpu')) + +presistent_buffers = {k: v for k, v in model.named_buffers() if k not in model._non_persistent_buffers_set} +local_name_params = itertools.chain(model.named_parameters(), presistent_buffers.items()) +local_state = {k: v for k, v in local_name_params if v is not None} + +for name, param in checkpoint.items(): + if local_state[name].shape != param.shape: + if 'conv1' in name or 'conv3' in name: + n1, c1, h, w = local_state[name].shape + n2, c2, h, w = param.shape + if n1 == n2: + c = (c1 - c2) // 4 + cell = c2 // 4 + checkpoint[name] = torch.cat([torch.cat((param[:, i * cell: (i + 1) * cell, ...], + torch.zeros(n1, c, h, w, dtype=param.dtype)), + 1) for i in range(4)], 1) + else: + n = (n1 - n2) // 4 + cell = n2 // 4 + checkpoint[name] = torch.cat([torch.cat((param[i * cell: (i + 1) * cell, ...], + torch.zeros(n, c1, h, w, dtype=param.dtype)), + 0) for i in range(4)], 0) + elif 'bn1' in name or 'bn3' in name: + cell = param.size(0) // 4 + n = (local_state[name].size(0) - param.size(0)) // 4 + checkpoint[name] = torch.cat([torch.cat((param[i * cell: (i + 1) * cell], + torch.zeros(n, dtype=param.dtype)), + 0) for i in range(4)]) + else: + if param.dim() == 1: + checkpoint[name] = torch.cat((param, + torch.zeros(local_state[name].size(0) - param.size(0), dtype=param.dtype)), + 0) + else: + n1, c1, h, w = local_state[name].shape + n2, c2, h, w = param.shape + param = torch.cat((param, torch.zeros(n2, c1 - c2, h, w, dtype=param.dtype)), 1) + checkpoint[name] = torch.cat((param, torch.zeros(n1 - n2, c1, h, w, dtype=param.dtype)), 0) + +model.load_state_dict(checkpoint) +model.eval() + +inputs = torch.rand(1, 3, 224, 224) +torch.onnx.export(model, inputs, args.output, + input_names=["x"], output_names=["output"], + dynamic_axes={"x": {0: "-1"}}, opset_version=11) diff --git a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/vision_metric_ImageNet.py b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/vision_metric_ImageNet.py index 183db2edda..6542f9e50c 100644 --- a/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/vision_metric_ImageNet.py +++ b/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch/vision_metric_ImageNet.py @@ -1,177 +1,177 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = "" - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - - resCnt = min(len(sort_index), topn) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = "" + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + + resCnt = min(len(sort_index), topn) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) diff --git a/ACL_PyTorch/built-in/cv/ResNeXt50_for_Pytorch/ReadMe.md b/ACL_PyTorch/built-in/cv/ResNeXt50_for_Pytorch/ReadMe.md index 0c3fb44c82..64dc33b67d 100644 --- a/ACL_PyTorch/built-in/cv/ResNeXt50_for_Pytorch/ReadMe.md +++ b/ACL_PyTorch/built-in/cv/ResNeXt50_for_Pytorch/ReadMe.md @@ -1,62 +1,62 @@ -文件作用说明: - -1.resnext50_pth2onnx.py:用于转换pth模型文件到onnx模型文件 - -2.resnext50_atc.sh:onnx模型转换om模型脚本 - -3.preprocess_resnext50_pth.py:数据集预处理脚本,通过均值方差处理归一化图片,生成图片二进制文件 - -4.aipp_resnext50_pth.config:数据集aipp预处理配置文件 - -5.get_info.py:生成推理输入的数据集二进制info文件或jpg info文件 - -6.resnext50_val.info:ImageNet验证集二进制info文件,用于benchmark推理获取数据集 - -7.ImageNet.info:ImageNet验证集jpg info文件,用于benchmark推理获取数据集 - -8.val_label.txt:ImageNet数据集标签,用于验证推理结果 - -9.benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer - -10.vision_metric_ImageNet.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy - - - - - -推理端到端步骤: - -(1) 从Torchvision下载resnext50模型,通过resnext50_pth2onnx.py脚本转化为onnx模型 - - - -(2)运行resnext50_atc.sh脚本转换om模型 - -本demo已提供调优完成的om模型 - - - -(3)用preprocess_resnext50_pth.py脚本处理数据集,参考resnext50_val.info配置处理后的二进制数据集路径。或者配置数据集aipp预处理文件aipp_resnext50_pth.config。 - python3 preprocess_resnext50_pth.py dataset/ImageNet/val_union/ pre_bin - - - -(4)生成推理输入的数据集二进制info文件或jpg info文件 - python3 get_info.py bin pre_bin resnext50_val.info 224 224 - python3 get_info.py jpg dataset/ImageNet/val_union ImageNet.info - - - -(5)使用benchmark离线推理 - ./benchmark -model_type=vision -om_path=resnext50_bs16.om -device_id=0 -batch_size=16 -input_text_path=resnext50_val.info -input_width=224 -input_height=224 -useDvpp=false - 或者 - ./benchmark -model_type=vision -om_path=resnext50_bs1.om -device_id=0 -batch_size=1 -input_text_path=ImageNet.info -input_width=256 -input_height=256 -useDvpp=true - -运行benchmark推理,结果保存在 ./result 目录下 - - - -(6)python3.7 vision_metric_ImageNet.py result/dumpOutput_device0/ ./val_label.txt ./ result.json - -验证推理结果 - +文件作用说明: + +1.resnext50_pth2onnx.py:用于转换pth模型文件到onnx模型文件 + +2.resnext50_atc.sh:onnx模型转换om模型脚本 + +3.preprocess_resnext50_pth.py:数据集预处理脚本,通过均值方差处理归一化图片,生成图片二进制文件 + +4.aipp_resnext50_pth.config:数据集aipp预处理配置文件 + +5.get_info.py:生成推理输入的数据集二进制info文件或jpg info文件 + +6.resnext50_val.info:ImageNet验证集二进制info文件,用于benchmark推理获取数据集 + +7.ImageNet.info:ImageNet验证集jpg info文件,用于benchmark推理获取数据集 + +8.val_label.txt:ImageNet数据集标签,用于验证推理结果 + +9.benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer + +10.vision_metric_ImageNet.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy + + + + + +推理端到端步骤: + +(1) 从Torchvision下载resnext50模型,通过resnext50_pth2onnx.py脚本转化为onnx模型 + + + +(2)运行resnext50_atc.sh脚本转换om模型 + +本demo已提供调优完成的om模型 + + + +(3)用preprocess_resnext50_pth.py脚本处理数据集,参考resnext50_val.info配置处理后的二进制数据集路径。或者配置数据集aipp预处理文件aipp_resnext50_pth.config。 + python3 preprocess_resnext50_pth.py dataset/ImageNet/val_union/ pre_bin + + + +(4)生成推理输入的数据集二进制info文件或jpg info文件 + python3 get_info.py bin pre_bin resnext50_val.info 224 224 + python3 get_info.py jpg dataset/ImageNet/val_union ImageNet.info + + + +(5)使用benchmark离线推理 + ./benchmark -model_type=vision -om_path=resnext50_bs16.om -device_id=0 -batch_size=16 -input_text_path=resnext50_val.info -input_width=224 -input_height=224 -useDvpp=false + 或者 + ./benchmark -model_type=vision -om_path=resnext50_bs1.om -device_id=0 -batch_size=1 -input_text_path=ImageNet.info -input_width=256 -input_height=256 -useDvpp=true + +运行benchmark推理,结果保存在 ./result 目录下 + + + +(6)python3.7 vision_metric_ImageNet.py result/dumpOutput_device0/ ./val_label.txt ./ result.json + +验证推理结果 + diff --git a/ACL_PyTorch/built-in/cv/ResNeXt50_for_Pytorch/get_info.py b/ACL_PyTorch/built-in/cv/ResNeXt50_for_Pytorch/get_info.py index 0578e4f00c..7b14c54b90 100644 --- a/ACL_PyTorch/built-in/cv/ResNeXt50_for_Pytorch/get_info.py +++ b/ACL_PyTorch/built-in/cv/ResNeXt50_for_Pytorch/get_info.py @@ -1,46 +1,46 @@ -import os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +import os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/ResNeXt50_for_Pytorch/preprocess_resnext50_pth.py b/ACL_PyTorch/built-in/cv/ResNeXt50_for_Pytorch/preprocess_resnext50_pth.py index 04f41f7597..965681f30d 100644 --- a/ACL_PyTorch/built-in/cv/ResNeXt50_for_Pytorch/preprocess_resnext50_pth.py +++ b/ACL_PyTorch/built-in/cv/ResNeXt50_for_Pytorch/preprocess_resnext50_pth.py @@ -1,85 +1,85 @@ -import os -import sys -import numpy as np -from PIL import Image - - -def resize(img, size, interpolation=Image.BILINEAR): - r"""Resize the input PIL Image to the given size. - - Args: - img (PIL Image): Image to be resized. - size (sequence or int): Desired output size. If size is a sequence like - (h, w), the output size will be matched to this. If size is an int, - the smaller edge of the image will be matched to this number maintaining - the aspect ratio. i.e, if height > width, then image will be rescaled to - :math:`\left(\text{size} \times \frac{\text{height}}{\text{width}}, \text{size}\right)` - interpolation (int, optional): Desired interpolation. Default is - ``PIL.Image.BILINEAR`` - - Returns: - PIL Image: Resized image. - """ - - if isinstance(size, int): - w, h = img.size - if (w <= h and w == size) or (h <= w and h == size): - return img - if w < h: - ow = size - oh = int(size * h / w) - return img.resize((ow, oh), interpolation) - else: - oh = size - ow = int(size * w / h) - return img.resize((ow, oh), interpolation) - else: - return img.resize(size[::-1], interpolation) - - -def center_crop(img, out_height, out_width): - height, width, _ = img.shape - left = int((width - out_width) / 2) - right = int((width + out_width) / 2) - top = int((height - out_height) / 2) - bottom = int((height + out_height) / 2) - img = img[top:bottom, left:right] - return img - - -def preprocess(file_path, bin_path): - in_files = os.listdir(file_path) - if not os.path.exists(bin_path): - os.makedirs(bin_path) - i = 0 - - resize_size = 256 - mean = [0.485, 0.456, 0.406] - std = [0.229, 0.224, 0.225] - - for file in in_files: - i = i + 1 - print(file, "===", i) - - img = Image.open(os.path.join(file_path, file)).convert('RGB') - - img = resize(img, resize_size) # transforms.Resize(256) - img = np.array(img, dtype=np.float32) - img = center_crop(img, 224, 224) # transforms.CenterCrop(224) - img = img / 255. # transforms.ToTensor() - # 均值方差 - img[..., 0] -= mean[0] - img[..., 1] -= mean[1] - img[..., 2] -= mean[2] - img[..., 0] /= std[0] - img[..., 1] /= std[1] - img[..., 2] /= std[2] - img = img.transpose(2, 0, 1) # HWC -> CHW - - img.tofile(os.path.join(bin_path, file.split('.')[0] + '.bin')) - - -if __name__ == "__main__": - file_path = os.path.abspath(sys.argv[1]) - bin_path = os.path.abspath(sys.argv[2]) - preprocess(file_path, bin_path) +import os +import sys +import numpy as np +from PIL import Image + + +def resize(img, size, interpolation=Image.BILINEAR): + r"""Resize the input PIL Image to the given size. + + Args: + img (PIL Image): Image to be resized. + size (sequence or int): Desired output size. If size is a sequence like + (h, w), the output size will be matched to this. If size is an int, + the smaller edge of the image will be matched to this number maintaining + the aspect ratio. i.e, if height > width, then image will be rescaled to + :math:`\left(\text{size} \times \frac{\text{height}}{\text{width}}, \text{size}\right)` + interpolation (int, optional): Desired interpolation. Default is + ``PIL.Image.BILINEAR`` + + Returns: + PIL Image: Resized image. + """ + + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def center_crop(img, out_height, out_width): + height, width, _ = img.shape + left = int((width - out_width) / 2) + right = int((width + out_width) / 2) + top = int((height - out_height) / 2) + bottom = int((height + out_height) / 2) + img = img[top:bottom, left:right] + return img + + +def preprocess(file_path, bin_path): + in_files = os.listdir(file_path) + if not os.path.exists(bin_path): + os.makedirs(bin_path) + i = 0 + + resize_size = 256 + mean = [0.485, 0.456, 0.406] + std = [0.229, 0.224, 0.225] + + for file in in_files: + i = i + 1 + print(file, "===", i) + + img = Image.open(os.path.join(file_path, file)).convert('RGB') + + img = resize(img, resize_size) # transforms.Resize(256) + img = np.array(img, dtype=np.float32) + img = center_crop(img, 224, 224) # transforms.CenterCrop(224) + img = img / 255. # transforms.ToTensor() + # 均值方差 + img[..., 0] -= mean[0] + img[..., 1] -= mean[1] + img[..., 2] -= mean[2] + img[..., 0] /= std[0] + img[..., 1] /= std[1] + img[..., 2] /= std[2] + img = img.transpose(2, 0, 1) # HWC -> CHW + + img.tofile(os.path.join(bin_path, file.split('.')[0] + '.bin')) + + +if __name__ == "__main__": + file_path = os.path.abspath(sys.argv[1]) + bin_path = os.path.abspath(sys.argv[2]) + preprocess(file_path, bin_path) diff --git a/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/ReadMe.md b/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/ReadMe.md index b89cfb0e6e..285adc2fec 100644 --- a/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/ReadMe.md +++ b/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/ReadMe.md @@ -1,381 +1,381 @@ -# ResNet101 Onnx模型端到端推理指导 -- [1 模型概述](#1-模型概述) - - [1.1 论文地址](#11-论文地址) - - [1.2 代码地址](#12-代码地址) -- [2 环境说明](#2-环境说明) - - [2.1 深度学习框架](#21-深度学习框架) - - [2.2 python第三方库](#22-python第三方库) -- [3 模型转换](#3-模型转换) - - [3.1 pth转onnx模型](#31-pth转onnx模型) - - [3.2 onnx模型量化](#32-onnx模型量化) - - [3.3 onnx转om模型](#33-onnx转om模型) -- [4 数据集预处理](#4-数据集预处理) - - [4.1 数据集获取](#41-数据集获取) - - [4.2 数据集预处理](#42-数据集预处理) - - [4.3 生成数据集信息文件](#43-生成数据集信息文件) -- [5 离线推理](#5-离线推理) - - [5.1 benchmark工具概述](#51-benchmark工具概述) - - [5.2 离线推理](#52-离线推理) -- [6 精度对比](#6-精度对比) - - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) - - [6.2 开源TopN精度](#62-开源TopN精度) - - [6.3 精度对比](#63-精度对比) -- [7 性能对比](#7-性能对比) - - [7.1 npu性能数据](#71-npu性能数据) - - [7.2 T4性能数据](#72-T4性能数据) - - [7.3 性能对比](#73-性能对比) - - - -## 1 模型概述 - -- **[论文地址](#11-论文地址)** - -- **[代码地址](#12-代码地址)** - -### 1.1 论文地址 -[ResNet101论文](https://arxiv.org/pdf/1512.03385.pdf) - -### 1.2 代码地址 -[ResNet101代码](https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py) -branch:master -commit_id:7d955df73fe0e9b47f7d6c77c699324b256fc41f - -## 2 环境说明 - -- **[深度学习框架](#21-深度学习框架)** - -- **[python第三方库](#22-python第三方库)** - -### 2.1 深度学习框架 -``` -CANN 5.0.4 - -torch == 1.5.1 -torchvision == 0.6.1 -onnx == 1.9.0 -``` - -### 2.2 python第三方库 - -``` -numpy == 1.19.2 -Pillow == 8.2.0 -opencv-python == 4.5.2 -``` - -**说明:** -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3 模型转换 - -- **[pth转onnx模型](#31-pth转onnx模型)** - -- **[onnx转om模型](#32-onnx转om模型)** - -### 3.1 pth转onnx模型 - -1.下载pth权重文件 -请参考[pytorch原始仓](https://github.com/pytorch/vision/blob/main/torchvision/models/resnet.py)给出的ResNet101权重文件下载地址获取权重文件:resnet101-63fe2227.pth - -2.ResNet101模型代码在torchvision里,安装torchvision,arm下需源码安装,参考torchvision官网,若安装过程报错请百度解决 - -``` -git clone https://github.com/pytorch/vision -cd vision -python3.7 setup.py install -cd .. -``` -3.编写pth2onnx脚本resnet101_pth2onnx.py - - **说明:** ->注意目前ATC支持的onnx算子版本为11 - -4.执行pth2onnx脚本,生成onnx模型文件 -``` -python3.7 resnet101_pth2onnx.py ./resnet101-63fe2227.pth resnet101.onnx -``` - - **模型转换要点:** ->此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 - -### 3.2 onnx模型量化 - -1.AMCT工具包安装,具体参考《[CANN 开发辅助工具指南 01](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools)》中的昇腾模型压缩工具使用指南(ONNX)章节; - -2.生成bin格式数据集,数据集用于校正量化因子。当前模型为动态batch,建议使用较大的batch size: - -``` -python3.7 gen_calibration_bin.py resnet /root/datasets/imagenet/val ./calibration_bin 32 1 -``` - -参数说明: - -- resnet:模型类型 -- /root/datasets/imagenet/val:模型使用的数据集路径; -- ./calibration_bin:生成的bin格式数据集路径; -- 32:batch size; -- 1:batch num。 - -3.ONNX模型量化 - -``` -amct_onnx calibration --model resnet101.onnx --save_path ./result/resnet101 --input_shape "image:32,3,224,224" --data_dir "./calibration_bin" --data_types "float32" -``` - -会在result目录下生成resnet101_deploy_model.onnx量化模型 - -4.量化模型后续的推理验证流程和非量化一致。 - -### 3.3 onnx转om模型 - -1.设置环境变量 - -``` -source env.sh -``` -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考《[CANN 开发辅助工具指南 01](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools)》中的ATC工具使用指南章节 - -``` -atc --framework=5 --model=./resnet101.onnx --output=resnet101_bs16 --input_format=NCHW --input_shape="image:16,3,224,224" --log=debug --soc_version=Ascend310 --insert_op_conf=aipp.config -``` - -**说明:** - -> 若设备类型为Ascend710,设置soc_version==Ascend710即可; -> -> aipp.config是AIPP工具数据集预处理配置文件,详细说明可参考"ATC工具使用指南"中的"AIPP配置"章节。 - -## 4 数据集预处理 - -- **[数据集获取](#41-数据集获取)** - -- **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - -### 4.1 数据集获取 -该模型使用ImageNet的5万张验证集进行测试,图片与标签分别存放在/root/datasets/imagenet/val与/root/datasets/imagenet/val_label.txt。 - -### 4.2 数据集预处理 - -1.预处理脚本imagenet_torch_preprocess.py - -2.执行预处理脚本,生成数据集预处理后的bin文件 -``` -python3.7 imagenet_torch_preprocess.py resnet /root/datasets/imagenet/val ./prep_dataset -``` -### 4.3 生成数据集信息文件 -1.生成数据集信息文件脚本gen_dataset_info.py - -2.执行生成数据集信息脚本,生成数据集信息文件 -``` -python3.7 gen_dataset_info.py bin ./prep_dataset ./resnet101_prep_bin.info 224 224 -``` -第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 -## 5 离线推理 - -- **[benchmark工具概述](#51-benchmark工具概述)** - -- **[离线推理](#52-离线推理)** - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310、710上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考《[CANN 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools)》 -### 5.2 离线推理 -1.设置环境变量 -``` -source env.sh -``` -2.执行离线推理 -``` -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=16 -om_path=resnet101_bs16.om -input_text_path=./resnet101_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False -``` -输出结果默认保存在当前目录result/dumpOutput_device{0},模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 - -## 6 精度对比 - -- **[离线推理TopN精度](#61-离线推理TopN精度)** -- **[开源TopN精度](#62-开源TopN精度)** -- **[精度对比](#63-精度对比)** - -### 6.1 离线推理TopN精度统计 - -后处理统计TopN精度 - -调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 -``` -python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /root/datasets/imagenet/val_label.txt ./ result.json -``` -第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 -查看输出结果: -``` -{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value": "77.37%"}, {"key": "Top2 accuracy", "value": "87.1%"}, {"key": "Top3 accuracy", "value": "90.61%"}, {"key": "Top4 accuracy", "value": "92.42%"}, {"key": "Top5 accuracy", "value": "93.54%"}]} -``` -经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 - -### 6.2 开源TopN精度 -[torchvision官网精度](https://pytorch.org/vision/stable/models.html) -``` -Model Acc@1 Acc@5 -ResNet-101 77.374 93.546 -``` -### 6.3 精度对比 -将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 - **精度调试:** ->没有遇到精度不达标的问题,故不需要进行精度调试 - -## 7 性能对比 - -- **[npu性能数据](#71-npu性能数据)** -- **[T4性能数据](#72-T4性能数据)** -- **[性能对比](#73-性能对比)** - -### 7.1 npu性能数据 -benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 -1.benchmark工具在整个数据集上推理获得性能数据 (Ascend310) -batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: -``` -[e2e] throughputRate: 170.628, latency: 293035 -[data read] throughputRate: 181.571, moduleLatency: 5.50749 -[preprocess] throughputRate: 180.466, moduleLatency: 5.5412 -[infer] throughputRate: 171.595, Interface throughputRate: 247.898, moduleLatency: 5.12562 -[post] throughputRate: 171.595, moduleLatency: 5.82768 -``` -Interface throughputRate: 247.898,247.898x4=991.592既是batch1 310单卡吞吐率 -batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: -``` -[e2e] throughputRate: 185.903, latency: 268957 -[data read] throughputRate: 191.266, moduleLatency: 5.22833 -[preprocess] throughputRate: 190.761, moduleLatency: 5.24217 -[infer] throughputRate: 187.131, Interface throughputRate: 401.046, moduleLatency: 3.94051 -[post] throughputRate: 11.6954, moduleLatency: 85.5035 -``` -Interface throughputRate: 401.046,401.046x4=1604.184既是batch16 310单卡吞吐率 -batch4的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_4_device_0.txt: -``` -[e2e] throughputRate: 184.444, latency: 271085 -[data read] throughputRate: 196.412, moduleLatency: 5.09134 -[preprocess] throughputRate: 195.837, moduleLatency: 5.1063 -[infer] throughputRate: 185.624, Interface throughputRate: 331.096, moduleLatency: 4.52436 -[post] throughputRate: 46.4056, moduleLatency: 21.5491 -``` -Interface throughputRate: 331.096,331.096x4=1324.384既是batch4 310单卡吞吐率 -batch8的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_8_device_0.txt: -``` -[e2e] throughputRate: 196.051, latency: 255036 -[data read] throughputRate: 209.29, moduleLatency: 4.77806 -[preprocess] throughputRate: 207.914, moduleLatency: 4.80969 -[infer] throughputRate: 197.513, Interface throughputRate: 371.905, moduleLatency: 4.15513 -[post] throughputRate: 24.6888, moduleLatency: 40.5042 -``` -Interface throughputRate: 371.905,371.905x4=1487.62既是batch8 310单卡吞吐率 -batch32的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_32_device_0.txt: -``` -[e2e] throughputRate: 176.215, latency: 283744 -[data read] throughputRate: 187.024, moduleLatency: 5.34691 -[preprocess] throughputRate: 186.183, moduleLatency: 5.37105 -[infer] throughputRate: 177.675, Interface throughputRate: 370.456, moduleLatency: 4.14361 -[post] throughputRate: 5.55402, moduleLatency: 180.05 - -``` -Interface throughputRate: 370.456,370.456x4=1481.82既是batch32 310单卡吞吐率 - - **说明:** - -> 注意如果设备为Ascend710,则Interface throughputRate的值就是710的单卡吞吐率,不需要像310那样x4 - -### 7.2 T4性能数据 -在装有T4卡的服务器上测试gpu性能,测试过程请确保卡没有运行其他任务,TensorRT版本:7.2.3.4,cuda版本:11.0,cudnn版本:8.2 -batch1性能: -``` -trtexec --onnx=resnet101.onnx --fp16 --shapes=image:1x3x224x224 --threads -``` -gpu T4是4个device并行执行的结果,mean是时延(tensorrt的时延是batch个数据的推理时间),即吞吐率的倒数乘以batch -``` -[06/10/2021-17:40:51] [I] GPU Compute -[06/10/2021-17:40:51] [I] min: 2.01935 ms -[06/10/2021-17:40:51] [I] max: 3.53485 ms -[06/10/2021-17:40:51] [I] mean: 2.1015 ms -[06/10/2021-17:40:51] [I] median: 2.07254 ms -[06/10/2021-17:40:51] [I] percentile: 3.52882 ms at 99% -[06/10/2021-17:40:51] [I] total compute time: 2.99674 s - -``` -batch1 t4单卡吞吐率:1000/(2.1015/1)=475.851fps - -batch16性能: -``` -trtexec --onnx=resnet101.onnx --fp16 --shapes=image:16x3x224x224 --threads -``` -``` -[06/10/2021-17:42:06] [I] GPU Compute -[06/10/2021-17:42:06] [I] min: 13.8094 ms -[06/10/2021-17:42:06] [I] max: 24.5842 ms -[06/10/2021-17:42:06] [I] mean: 14.5182 ms -[06/10/2021-17:42:06] [I] median: 14.4042 ms -[06/10/2021-17:42:06] [I] percentile: 15.7213 ms at 99% -[06/10/2021-17:42:06] [I] total compute time: 3.03431 s - -``` -batch16 t4单卡吞吐率:1000/(14.5182/16)=1102.065fps - -batch4性能: -``` -trtexec --onnx=resnet101.onnx --fp16 --shapes=image:4x3x224x224 --threads -``` -``` -[06/11/2021-12:47:51] [I] GPU Compute -[06/11/2021-12:47:51] [I] min: 4.27863 ms -[06/11/2021-12:47:51] [I] max: 6.56378 ms -[06/11/2021-12:47:51] [I] mean: 4.52613 ms -[06/11/2021-12:47:51] [I] median: 4.49536 ms -[06/11/2021-12:47:51] [I] percentile: 6.54581 ms at 99% -[06/11/2021-12:47:51] [I] total compute time: 3.00535 s - -``` -batch4 t4单卡吞吐率:1000/(4.52613/4)=883.7572054fps - -batch8性能: -``` -trtexec --onnx=resnet101.onnx --fp16 --shapes=image:8x3x224x224 --threads -``` -``` -[06/11/2021-12:49:50] [I] GPU Compute -[06/11/2021-12:49:50] [I] min: 7.38504 ms -[06/11/2021-12:49:50] [I] max: 8.36267 ms -[06/11/2021-12:49:50] [I] mean: 7.73195 ms -[06/11/2021-12:49:50] [I] median: 7.68652 ms -[06/11/2021-12:49:50] [I] percentile: 8.33948 ms at 99% -[06/11/2021-12:49:50] [I] total compute time: 3.00773 s - -``` -batch8 t4单卡吞吐率:1000/(7.73195/8)=1034.667839fps - -batch32性能: -``` -trtexec --onnx=resnet101.onnx --fp16 --shapes=image:32x3x224x224 --threads -``` -``` -[06/11/2021-12:52:51] [I] GPU Compute -[06/11/2021-12:52:51] [I] min: 24.7151 ms -[06/11/2021-12:52:51] [I] max: 34.8919 ms -[06/11/2021-12:52:51] [I] mean: 25.7435 ms -[06/11/2021-12:52:51] [I] median: 25.4695 ms -[06/11/2021-12:52:51] [I] percentile: 33.3713 ms at 99% -[06/11/2021-12:52:51] [I] total compute time: 3.03773 s - -``` -batch32 t4单卡吞吐率:1000/(25.7435/32)=1243.032222fps - -### 7.3 性能对比 -batch1:247.898x4 > 1000/(2.1015/1) -batch16:401.046x4 > 1000/(14.5182/16) -batch4,8,32的npu性能也都大于T4 -310单个device的吞吐率乘4即单卡吞吐率比T4单卡的吞吐率大,故310性能高于T4性能,性能达标。 -对于batch1的310性能高于T4性能2.08倍,batch16的310性能高于T4性能1.46倍,对于batch1与batch16,310性能均高于T4性能1.2倍,该模型放在Benchmark/cv/classification目录下。 - -710单卡吞吐率要求最优batchsize情况下为310的1.5倍,当前已符合要求,具体数据不在此赘述。 - +# ResNet101 Onnx模型端到端推理指导 +- [1 模型概述](#1-模型概述) + - [1.1 论文地址](#11-论文地址) + - [1.2 代码地址](#12-代码地址) +- [2 环境说明](#2-环境说明) + - [2.1 深度学习框架](#21-深度学习框架) + - [2.2 python第三方库](#22-python第三方库) +- [3 模型转换](#3-模型转换) + - [3.1 pth转onnx模型](#31-pth转onnx模型) + - [3.2 onnx模型量化](#32-onnx模型量化) + - [3.3 onnx转om模型](#33-onnx转om模型) +- [4 数据集预处理](#4-数据集预处理) + - [4.1 数据集获取](#41-数据集获取) + - [4.2 数据集预处理](#42-数据集预处理) + - [4.3 生成数据集信息文件](#43-生成数据集信息文件) +- [5 离线推理](#5-离线推理) + - [5.1 benchmark工具概述](#51-benchmark工具概述) + - [5.2 离线推理](#52-离线推理) +- [6 精度对比](#6-精度对比) + - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) + - [6.2 开源TopN精度](#62-开源TopN精度) + - [6.3 精度对比](#63-精度对比) +- [7 性能对比](#7-性能对比) + - [7.1 npu性能数据](#71-npu性能数据) + - [7.2 T4性能数据](#72-T4性能数据) + - [7.3 性能对比](#73-性能对比) + + + +## 1 模型概述 + +- **[论文地址](#11-论文地址)** + +- **[代码地址](#12-代码地址)** + +### 1.1 论文地址 +[ResNet101论文](https://arxiv.org/pdf/1512.03385.pdf) + +### 1.2 代码地址 +[ResNet101代码](https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py) +branch:master +commit_id:7d955df73fe0e9b47f7d6c77c699324b256fc41f + +## 2 环境说明 + +- **[深度学习框架](#21-深度学习框架)** + +- **[python第三方库](#22-python第三方库)** + +### 2.1 深度学习框架 +``` +CANN 5.0.4 + +torch == 1.5.1 +torchvision == 0.6.1 +onnx == 1.9.0 +``` + +### 2.2 python第三方库 + +``` +numpy == 1.19.2 +Pillow == 8.2.0 +opencv-python == 4.5.2 +``` + +**说明:** +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3 模型转换 + +- **[pth转onnx模型](#31-pth转onnx模型)** + +- **[onnx转om模型](#32-onnx转om模型)** + +### 3.1 pth转onnx模型 + +1.下载pth权重文件 +请参考[pytorch原始仓](https://github.com/pytorch/vision/blob/main/torchvision/models/resnet.py)给出的ResNet101权重文件下载地址获取权重文件:resnet101-63fe2227.pth + +2.ResNet101模型代码在torchvision里,安装torchvision,arm下需源码安装,参考torchvision官网,若安装过程报错请百度解决 + +``` +git clone https://github.com/pytorch/vision +cd vision +python3.7 setup.py install +cd .. +``` +3.编写pth2onnx脚本resnet101_pth2onnx.py + + **说明:** +>注意目前ATC支持的onnx算子版本为11 + +4.执行pth2onnx脚本,生成onnx模型文件 +``` +python3.7 resnet101_pth2onnx.py ./resnet101-63fe2227.pth resnet101.onnx +``` + + **模型转换要点:** +>此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 + +### 3.2 onnx模型量化 + +1.AMCT工具包安装,具体参考《[CANN 开发辅助工具指南 01](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools)》中的昇腾模型压缩工具使用指南(ONNX)章节; + +2.生成bin格式数据集,数据集用于校正量化因子。当前模型为动态batch,建议使用较大的batch size: + +``` +python3.7 gen_calibration_bin.py resnet /root/datasets/imagenet/val ./calibration_bin 32 1 +``` + +参数说明: + +- resnet:模型类型 +- /root/datasets/imagenet/val:模型使用的数据集路径; +- ./calibration_bin:生成的bin格式数据集路径; +- 32:batch size; +- 1:batch num。 + +3.ONNX模型量化 + +``` +amct_onnx calibration --model resnet101.onnx --save_path ./result/resnet101 --input_shape "image:32,3,224,224" --data_dir "./calibration_bin" --data_types "float32" +``` + +会在result目录下生成resnet101_deploy_model.onnx量化模型 + +4.量化模型后续的推理验证流程和非量化一致。 + +### 3.3 onnx转om模型 + +1.设置环境变量 + +``` +source env.sh +``` +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考《[CANN 开发辅助工具指南 01](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools)》中的ATC工具使用指南章节 + +``` +atc --framework=5 --model=./resnet101.onnx --output=resnet101_bs16 --input_format=NCHW --input_shape="image:16,3,224,224" --log=debug --soc_version=Ascend310 --insert_op_conf=aipp.config +``` + +**说明:** + +> 若设备类型为Ascend710,设置soc_version==Ascend710即可; +> +> aipp.config是AIPP工具数据集预处理配置文件,详细说明可参考"ATC工具使用指南"中的"AIPP配置"章节。 + +## 4 数据集预处理 + +- **[数据集获取](#41-数据集获取)** + +- **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + +### 4.1 数据集获取 +该模型使用ImageNet的5万张验证集进行测试,图片与标签分别存放在/root/datasets/imagenet/val与/root/datasets/imagenet/val_label.txt。 + +### 4.2 数据集预处理 + +1.预处理脚本imagenet_torch_preprocess.py + +2.执行预处理脚本,生成数据集预处理后的bin文件 +``` +python3.7 imagenet_torch_preprocess.py resnet /root/datasets/imagenet/val ./prep_dataset +``` +### 4.3 生成数据集信息文件 +1.生成数据集信息文件脚本gen_dataset_info.py + +2.执行生成数据集信息脚本,生成数据集信息文件 +``` +python3.7 gen_dataset_info.py bin ./prep_dataset ./resnet101_prep_bin.info 224 224 +``` +第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 +## 5 离线推理 + +- **[benchmark工具概述](#51-benchmark工具概述)** + +- **[离线推理](#52-离线推理)** + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310、710上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考《[CANN 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools)》 +### 5.2 离线推理 +1.设置环境变量 +``` +source env.sh +``` +2.执行离线推理 +``` +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=16 -om_path=resnet101_bs16.om -input_text_path=./resnet101_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False +``` +输出结果默认保存在当前目录result/dumpOutput_device{0},模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 + +## 6 精度对比 + +- **[离线推理TopN精度](#61-离线推理TopN精度)** +- **[开源TopN精度](#62-开源TopN精度)** +- **[精度对比](#63-精度对比)** + +### 6.1 离线推理TopN精度统计 + +后处理统计TopN精度 + +调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 +``` +python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /root/datasets/imagenet/val_label.txt ./ result.json +``` +第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 +查看输出结果: +``` +{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value": "77.37%"}, {"key": "Top2 accuracy", "value": "87.1%"}, {"key": "Top3 accuracy", "value": "90.61%"}, {"key": "Top4 accuracy", "value": "92.42%"}, {"key": "Top5 accuracy", "value": "93.54%"}]} +``` +经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 + +### 6.2 开源TopN精度 +[torchvision官网精度](https://pytorch.org/vision/stable/models.html) +``` +Model Acc@1 Acc@5 +ResNet-101 77.374 93.546 +``` +### 6.3 精度对比 +将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 + **精度调试:** +>没有遇到精度不达标的问题,故不需要进行精度调试 + +## 7 性能对比 + +- **[npu性能数据](#71-npu性能数据)** +- **[T4性能数据](#72-T4性能数据)** +- **[性能对比](#73-性能对比)** + +### 7.1 npu性能数据 +benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 +1.benchmark工具在整个数据集上推理获得性能数据 (Ascend310) +batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: +``` +[e2e] throughputRate: 170.628, latency: 293035 +[data read] throughputRate: 181.571, moduleLatency: 5.50749 +[preprocess] throughputRate: 180.466, moduleLatency: 5.5412 +[infer] throughputRate: 171.595, Interface throughputRate: 247.898, moduleLatency: 5.12562 +[post] throughputRate: 171.595, moduleLatency: 5.82768 +``` +Interface throughputRate: 247.898,247.898x4=991.592既是batch1 310单卡吞吐率 +batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: +``` +[e2e] throughputRate: 185.903, latency: 268957 +[data read] throughputRate: 191.266, moduleLatency: 5.22833 +[preprocess] throughputRate: 190.761, moduleLatency: 5.24217 +[infer] throughputRate: 187.131, Interface throughputRate: 401.046, moduleLatency: 3.94051 +[post] throughputRate: 11.6954, moduleLatency: 85.5035 +``` +Interface throughputRate: 401.046,401.046x4=1604.184既是batch16 310单卡吞吐率 +batch4的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_4_device_0.txt: +``` +[e2e] throughputRate: 184.444, latency: 271085 +[data read] throughputRate: 196.412, moduleLatency: 5.09134 +[preprocess] throughputRate: 195.837, moduleLatency: 5.1063 +[infer] throughputRate: 185.624, Interface throughputRate: 331.096, moduleLatency: 4.52436 +[post] throughputRate: 46.4056, moduleLatency: 21.5491 +``` +Interface throughputRate: 331.096,331.096x4=1324.384既是batch4 310单卡吞吐率 +batch8的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_8_device_0.txt: +``` +[e2e] throughputRate: 196.051, latency: 255036 +[data read] throughputRate: 209.29, moduleLatency: 4.77806 +[preprocess] throughputRate: 207.914, moduleLatency: 4.80969 +[infer] throughputRate: 197.513, Interface throughputRate: 371.905, moduleLatency: 4.15513 +[post] throughputRate: 24.6888, moduleLatency: 40.5042 +``` +Interface throughputRate: 371.905,371.905x4=1487.62既是batch8 310单卡吞吐率 +batch32的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_32_device_0.txt: +``` +[e2e] throughputRate: 176.215, latency: 283744 +[data read] throughputRate: 187.024, moduleLatency: 5.34691 +[preprocess] throughputRate: 186.183, moduleLatency: 5.37105 +[infer] throughputRate: 177.675, Interface throughputRate: 370.456, moduleLatency: 4.14361 +[post] throughputRate: 5.55402, moduleLatency: 180.05 + +``` +Interface throughputRate: 370.456,370.456x4=1481.82既是batch32 310单卡吞吐率 + + **说明:** + +> 注意如果设备为Ascend710,则Interface throughputRate的值就是710的单卡吞吐率,不需要像310那样x4 + +### 7.2 T4性能数据 +在装有T4卡的服务器上测试gpu性能,测试过程请确保卡没有运行其他任务,TensorRT版本:7.2.3.4,cuda版本:11.0,cudnn版本:8.2 +batch1性能: +``` +trtexec --onnx=resnet101.onnx --fp16 --shapes=image:1x3x224x224 --threads +``` +gpu T4是4个device并行执行的结果,mean是时延(tensorrt的时延是batch个数据的推理时间),即吞吐率的倒数乘以batch +``` +[06/10/2021-17:40:51] [I] GPU Compute +[06/10/2021-17:40:51] [I] min: 2.01935 ms +[06/10/2021-17:40:51] [I] max: 3.53485 ms +[06/10/2021-17:40:51] [I] mean: 2.1015 ms +[06/10/2021-17:40:51] [I] median: 2.07254 ms +[06/10/2021-17:40:51] [I] percentile: 3.52882 ms at 99% +[06/10/2021-17:40:51] [I] total compute time: 2.99674 s + +``` +batch1 t4单卡吞吐率:1000/(2.1015/1)=475.851fps + +batch16性能: +``` +trtexec --onnx=resnet101.onnx --fp16 --shapes=image:16x3x224x224 --threads +``` +``` +[06/10/2021-17:42:06] [I] GPU Compute +[06/10/2021-17:42:06] [I] min: 13.8094 ms +[06/10/2021-17:42:06] [I] max: 24.5842 ms +[06/10/2021-17:42:06] [I] mean: 14.5182 ms +[06/10/2021-17:42:06] [I] median: 14.4042 ms +[06/10/2021-17:42:06] [I] percentile: 15.7213 ms at 99% +[06/10/2021-17:42:06] [I] total compute time: 3.03431 s + +``` +batch16 t4单卡吞吐率:1000/(14.5182/16)=1102.065fps + +batch4性能: +``` +trtexec --onnx=resnet101.onnx --fp16 --shapes=image:4x3x224x224 --threads +``` +``` +[06/11/2021-12:47:51] [I] GPU Compute +[06/11/2021-12:47:51] [I] min: 4.27863 ms +[06/11/2021-12:47:51] [I] max: 6.56378 ms +[06/11/2021-12:47:51] [I] mean: 4.52613 ms +[06/11/2021-12:47:51] [I] median: 4.49536 ms +[06/11/2021-12:47:51] [I] percentile: 6.54581 ms at 99% +[06/11/2021-12:47:51] [I] total compute time: 3.00535 s + +``` +batch4 t4单卡吞吐率:1000/(4.52613/4)=883.7572054fps + +batch8性能: +``` +trtexec --onnx=resnet101.onnx --fp16 --shapes=image:8x3x224x224 --threads +``` +``` +[06/11/2021-12:49:50] [I] GPU Compute +[06/11/2021-12:49:50] [I] min: 7.38504 ms +[06/11/2021-12:49:50] [I] max: 8.36267 ms +[06/11/2021-12:49:50] [I] mean: 7.73195 ms +[06/11/2021-12:49:50] [I] median: 7.68652 ms +[06/11/2021-12:49:50] [I] percentile: 8.33948 ms at 99% +[06/11/2021-12:49:50] [I] total compute time: 3.00773 s + +``` +batch8 t4单卡吞吐率:1000/(7.73195/8)=1034.667839fps + +batch32性能: +``` +trtexec --onnx=resnet101.onnx --fp16 --shapes=image:32x3x224x224 --threads +``` +``` +[06/11/2021-12:52:51] [I] GPU Compute +[06/11/2021-12:52:51] [I] min: 24.7151 ms +[06/11/2021-12:52:51] [I] max: 34.8919 ms +[06/11/2021-12:52:51] [I] mean: 25.7435 ms +[06/11/2021-12:52:51] [I] median: 25.4695 ms +[06/11/2021-12:52:51] [I] percentile: 33.3713 ms at 99% +[06/11/2021-12:52:51] [I] total compute time: 3.03773 s + +``` +batch32 t4单卡吞吐率:1000/(25.7435/32)=1243.032222fps + +### 7.3 性能对比 +batch1:247.898x4 > 1000/(2.1015/1) +batch16:401.046x4 > 1000/(14.5182/16) +batch4,8,32的npu性能也都大于T4 +310单个device的吞吐率乘4即单卡吞吐率比T4单卡的吞吐率大,故310性能高于T4性能,性能达标。 +对于batch1的310性能高于T4性能2.08倍,batch16的310性能高于T4性能1.46倍,对于batch1与batch16,310性能均高于T4性能1.2倍,该模型放在Benchmark/cv/classification目录下。 + +710单卡吞吐率要求最优batchsize情况下为310的1.5倍,当前已符合要求,具体数据不在此赘述。 + diff --git a/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/gen_dataset_info.py b/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/gen_dataset_info.py index 61450b4410..5381839f65 100644 --- a/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/gen_dataset_info.py +++ b/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/gen_dataset_info.py @@ -1,61 +1,61 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' - get_jpg_info(file_path, info_name) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' + get_jpg_info(file_path, info_name) + diff --git a/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/imagenet_acc_eval.py b/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/imagenet_acc_eval.py index 362f2484e8..583340a19f 100644 --- a/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/imagenet_acc_eval.py +++ b/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/imagenet_acc_eval.py @@ -1,184 +1,184 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - if data == '': - n_label = 0 - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = 0 - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - - resCnt = min(len(sort_index), topn) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) - print("Time used:", elapsed) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + if data == '': + n_label = 0 + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = 0 + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + + resCnt = min(len(sort_index), topn) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) + print("Time used:", elapsed) + diff --git a/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/imagenet_torch_preprocess.py b/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/imagenet_torch_preprocess.py index ed4b4e2a53..6f89d347b5 100644 --- a/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/imagenet_torch_preprocess.py +++ b/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/imagenet_torch_preprocess.py @@ -1,113 +1,113 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -from PIL import Image -import numpy as np -import multiprocessing - - -model_config = { - 'resnet': { - 'resize': 256, - 'centercrop': 224, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv3': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv4': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.5, 0.5, 0.5], - 'std': [0.5, 0.5, 0.5], - }, -} - - -def center_crop(img, output_size): - if isinstance(output_size, int): - output_size = (int(output_size), int(output_size)) - image_width, image_height = img.size - crop_height, crop_width = output_size - crop_top = int(round((image_height - crop_height) / 2.)) - crop_left = int(round((image_width - crop_width) / 2.)) - return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) - - -def resize(img, size, interpolation=Image.BILINEAR): - if isinstance(size, int): - w, h = img.size - if (w <= h and w == size) or (h <= w and h == size): - return img - if w < h: - ow = size - oh = int(size * h / w) - return img.resize((ow, oh), interpolation) - else: - oh = size - ow = int(size * w / h) - return img.resize((ow, oh), interpolation) - else: - return img.resize(size[::-1], interpolation) - - -def gen_input_bin(mode_type, file_batches, batch): - i = 0 - for file in file_batches[batch]: - i = i + 1 - print("batch", batch, file, "===", i) - - # RGBA to RGB - image = Image.open(os.path.join(src_path, file)).convert('RGB') - image = resize(image, model_config[mode_type]['resize']) # Resize - image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop - img = np.array(image, dtype=np.int8) - img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) - - -def preprocess(mode_type, src_path, save_path): - files = os.listdir(src_path) - file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] - thread_pool = multiprocessing.Pool(len(file_batches)) - for batch in range(len(file_batches)): - thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) - thread_pool.close() - thread_pool.join() - print("in thread, except will not report! please ensure bin files generated.") - - -if __name__ == '__main__': - if len(sys.argv) < 4: - raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") - mode_type = sys.argv[1] - src_path = sys.argv[2] - save_path = sys.argv[3] - src_path = os.path.realpath(src_path) - save_path = os.path.realpath(save_path) - if mode_type not in model_config: - model_type_help = "model type: " - for key in model_config.keys(): - model_type_help += key - model_type_help += ' ' - raise Exception(model_type_help) - if not os.path.isdir(save_path): - os.makedirs(os.path.realpath(save_path)) - preprocess(mode_type, src_path, save_path) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +from PIL import Image +import numpy as np +import multiprocessing + + +model_config = { + 'resnet': { + 'resize': 256, + 'centercrop': 224, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv3': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv4': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.5, 0.5, 0.5], + 'std': [0.5, 0.5, 0.5], + }, +} + + +def center_crop(img, output_size): + if isinstance(output_size, int): + output_size = (int(output_size), int(output_size)) + image_width, image_height = img.size + crop_height, crop_width = output_size + crop_top = int(round((image_height - crop_height) / 2.)) + crop_left = int(round((image_width - crop_width) / 2.)) + return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) + + +def resize(img, size, interpolation=Image.BILINEAR): + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def gen_input_bin(mode_type, file_batches, batch): + i = 0 + for file in file_batches[batch]: + i = i + 1 + print("batch", batch, file, "===", i) + + # RGBA to RGB + image = Image.open(os.path.join(src_path, file)).convert('RGB') + image = resize(image, model_config[mode_type]['resize']) # Resize + image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop + img = np.array(image, dtype=np.int8) + img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) + + +def preprocess(mode_type, src_path, save_path): + files = os.listdir(src_path) + file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] + thread_pool = multiprocessing.Pool(len(file_batches)) + for batch in range(len(file_batches)): + thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) + thread_pool.close() + thread_pool.join() + print("in thread, except will not report! please ensure bin files generated.") + + +if __name__ == '__main__': + if len(sys.argv) < 4: + raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") + mode_type = sys.argv[1] + src_path = sys.argv[2] + save_path = sys.argv[3] + src_path = os.path.realpath(src_path) + save_path = os.path.realpath(save_path) + if mode_type not in model_config: + model_type_help = "model type: " + for key in model_config.keys(): + model_type_help += key + model_type_help += ' ' + raise Exception(model_type_help) + if not os.path.isdir(save_path): + os.makedirs(os.path.realpath(save_path)) + preprocess(mode_type, src_path, save_path) + diff --git a/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/requirements.txt b/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/requirements.txt index 2fc4e802c4..d072d9aa6f 100644 --- a/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/requirements.txt +++ b/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/requirements.txt @@ -1,6 +1,6 @@ -torch == 1.5.1 -torchvision == 0.6.1 -onnx == 1.9.0 -numpy == 1.19.2 -Pillow == 8.2.0 +torch == 1.5.1 +torchvision == 0.6.1 +onnx == 1.9.0 +numpy == 1.19.2 +Pillow == 8.2.0 opencv-python == 4.5.2 \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/resnet101_pth2onnx.py b/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/resnet101_pth2onnx.py index 46ab195411..8eff59a680 100644 --- a/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/resnet101_pth2onnx.py +++ b/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer/resnet101_pth2onnx.py @@ -1,35 +1,35 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -import torch -import torch.onnx -import torchvision.models as models - -def pth2onnx(input_file, output_file): - model = models.resnet101(pretrained=False) - checkpoint = torch.load(input_file, map_location=None) - model.load_state_dict(checkpoint) - - model.eval() - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.randn(1, 3, 224, 224) - torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=True, opset_version=11) - -if __name__ == "__main__": - input_file = sys.argv[1] - output_file = sys.argv[2] - pth2onnx(input_file, output_file) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +import torch +import torch.onnx +import torchvision.models as models + +def pth2onnx(input_file, output_file): + model = models.resnet101(pretrained=False) + checkpoint = torch.load(input_file, map_location=None) + model.load_state_dict(checkpoint) + + model.eval() + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.randn(1, 3, 224, 224) + torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=True, opset_version=11) + +if __name__ == "__main__": + input_file = sys.argv[1] + output_file = sys.argv[2] + pth2onnx(input_file, output_file) diff --git a/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/LICENSE b/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/LICENSE +++ b/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/README.md b/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/README.md index 9495982f9e..733721a8b2 100644 --- a/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/README.md +++ b/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/README.md @@ -1,156 +1,156 @@ -# ResNet18 Onnx模型端到端推理指导 - -## 1 模型概述 - -- **[论文地址](#11-论文地址)** - -- **[代码地址](#12-代码地址)** - -### 1.1 论文地址 -[ResNet18论文](https://arxiv.org/pdf/1512.03385.pdf) - -### 1.2 代码地址 -[ResNet18代码](https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py) -branch:master -commit_id:7d955df73fe0e9b47f7d6c77c699324b256fc41f - -## 2 环境说明 - -- **[深度学习框架](#21-深度学习框架)** - -- **[python第三方库](#22-python第三方库)** - -### 2.1 深度学习框架 -``` -CANN 5.0.3 - -torch == 1.5.1 -torchvision == 0.6.1 -onnx == 1.9.0 -``` - -### 2.2 python第三方库 - -``` -numpy == 1.19.2 -Pillow == 8.2.0 -opencv-python == 4.5.2 -``` - -**说明:** -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3 数据集预处理 - -- **[数据集获取](#31-数据集获取)** - -- **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - -### 3.1 数据集获取 -该模型使用ImageNet的5万张验证集进行测试,图片与标签分别存放在/root/datasets/imagenet/val与/root/datasets/imagenet/val_label.txt。 - -### 3.2 数据集预处理 -1.预处理脚本imagenet_torch_preprocess.py - -2.执行预处理脚本,生成数据集预处理后的bin文件 -``` -python3.7 imagenet_torch_preprocess.py resnet /root/datasets/imagenet/val ./prep_dataset -``` -### 3.3 生成数据集信息文件 -1.生成数据集信息文件脚本gen_dataset_info.py - -2.执行生成数据集信息脚本,生成数据集信息文件 -``` -python3.7 gen_dataset_info.py bin ./prep_dataset ./resnet18_prep_bin.info 224 224 -``` -第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 - -## 4 模型推理 - -- **[pth转onnx模型](#41-pth转onnx模型)** - -- **[onnx转om模型](#42-onnx转om模型)** - -### 4.1 pth转onnx模型 - -1.下载pth权重文件 -从https://github.com/pytorch/vision/blob/main/torchvision/models/resnet.py的第26行获取对应权重下载链接,使用wget命令下载对应权重 - -文件MD5sum:e0b1c919e74f9a193d36871d9964bf7d - -2.ResNet18模型代码在torchvision里,安装torchvision,arm下需源码安装,参考torchvision官网 -``` -git clone https://github.com/pytorch/vision -cd vision -python3.7 setup.py install -cd .. -``` -3.编写pth2onnx脚本resnet18_pth2onnx.py - - **说明:** ->注意目前ATC支持的onnx算子版本为11 - -3.执行pth2onnx脚本,生成onnx模型文件 -``` -python3.7 resnet18_pth2onnx.py ./resnet18-f37072fd.pth resnet18.onnx -``` -### 4.2 onnx模型量化(可选) -1.AMCT工具包安装,具体参考[CANN 开发辅助工具指南 (推理)](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools) - -2.数据预处理,用于量化因子矫正。当前模型为动态batch,建议用多batch_size的预处理文件矫正量化因子。 -执行以下命令: -``` -python3.7.5 calibration_bin.py prep_dataset calibration_bin 64 -``` - -3.ONNX模型量化,具体参考[CANN 开发辅助工具指南 (推理)](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools) -在result目录下生成resnet18_deploy_model.onnx量化模型 - -4.量化模型验证,除onnx离线模型转换om模型命令有区别外,其余一致 - -### 4.3 onnx转om模型 - -1.设置环境变量 -``` -source env.sh -``` -**说明** ->此脚本中环境变量只供参考,请以实际安装环境配置环境变量 - -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN 开发辅助工具指南 (推理)](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools) -``` -atc --framework=5 --model=./resnet18.onnx --output=resnet18_bs1 --input_format=NCHW --input_shape="image:1,3,224,224" --log=debug --soc_version=Ascend310 --insert_op_conf=aipp.config --enable_small_channel=1 - - -## Int8量化(可选) -atc --framework=5 --model=./result/resnet18_deploy_model.onnx --output=resnet18_bs1_int8 --input_format=NCHW --input_shape="image:1,3,224,224" --log=debug --soc_version=Ascend710 --insert_op_conf=aipp.config --enable_small_channel=1 -``` - -### 4.4 模型离线推理 - -1.设置环境变量 -``` -source env.sh -``` -**说明** ->此脚本中环境变量只供参考,请以实际安装环境配置环境变量 - -2.增加benchmark.{arch}可执行权限 -``` -chmod u+x benchmark.x86_64 -``` - -3.执行离线推理 -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=resnet18_bs1.om -input_text_path=./resnet18_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False -执行./benchmark.x86_64工具请选择与运行环境架构相同的命令。详情参考[CANN 推理benchmark工具用户指南](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools) - -4.精度验证 -调用imagenet_acc_eval.py脚本与数据集标签val_label.txt比对,可以获得Accuracy Top5数据,结果保存在result.json中。 -``` -python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /home/HwHiAiUser/dataset/imagenet/val_label.txt ./ result.json -``` +# ResNet18 Onnx模型端到端推理指导 + +## 1 模型概述 + +- **[论文地址](#11-论文地址)** + +- **[代码地址](#12-代码地址)** + +### 1.1 论文地址 +[ResNet18论文](https://arxiv.org/pdf/1512.03385.pdf) + +### 1.2 代码地址 +[ResNet18代码](https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py) +branch:master +commit_id:7d955df73fe0e9b47f7d6c77c699324b256fc41f + +## 2 环境说明 + +- **[深度学习框架](#21-深度学习框架)** + +- **[python第三方库](#22-python第三方库)** + +### 2.1 深度学习框架 +``` +CANN 5.0.3 + +torch == 1.5.1 +torchvision == 0.6.1 +onnx == 1.9.0 +``` + +### 2.2 python第三方库 + +``` +numpy == 1.19.2 +Pillow == 8.2.0 +opencv-python == 4.5.2 +``` + +**说明:** +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3 数据集预处理 + +- **[数据集获取](#31-数据集获取)** + +- **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + +### 3.1 数据集获取 +该模型使用ImageNet的5万张验证集进行测试,图片与标签分别存放在/root/datasets/imagenet/val与/root/datasets/imagenet/val_label.txt。 + +### 3.2 数据集预处理 +1.预处理脚本imagenet_torch_preprocess.py + +2.执行预处理脚本,生成数据集预处理后的bin文件 +``` +python3.7 imagenet_torch_preprocess.py resnet /root/datasets/imagenet/val ./prep_dataset +``` +### 3.3 生成数据集信息文件 +1.生成数据集信息文件脚本gen_dataset_info.py + +2.执行生成数据集信息脚本,生成数据集信息文件 +``` +python3.7 gen_dataset_info.py bin ./prep_dataset ./resnet18_prep_bin.info 224 224 +``` +第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 + +## 4 模型推理 + +- **[pth转onnx模型](#41-pth转onnx模型)** + +- **[onnx转om模型](#42-onnx转om模型)** + +### 4.1 pth转onnx模型 + +1.下载pth权重文件 +从https://github.com/pytorch/vision/blob/main/torchvision/models/resnet.py的第26行获取对应权重下载链接,使用wget命令下载对应权重 + +文件MD5sum:e0b1c919e74f9a193d36871d9964bf7d + +2.ResNet18模型代码在torchvision里,安装torchvision,arm下需源码安装,参考torchvision官网 +``` +git clone https://github.com/pytorch/vision +cd vision +python3.7 setup.py install +cd .. +``` +3.编写pth2onnx脚本resnet18_pth2onnx.py + + **说明:** +>注意目前ATC支持的onnx算子版本为11 + +3.执行pth2onnx脚本,生成onnx模型文件 +``` +python3.7 resnet18_pth2onnx.py ./resnet18-f37072fd.pth resnet18.onnx +``` +### 4.2 onnx模型量化(可选) +1.AMCT工具包安装,具体参考[CANN 开发辅助工具指南 (推理)](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools) + +2.数据预处理,用于量化因子矫正。当前模型为动态batch,建议用多batch_size的预处理文件矫正量化因子。 +执行以下命令: +``` +python3.7.5 calibration_bin.py prep_dataset calibration_bin 64 +``` + +3.ONNX模型量化,具体参考[CANN 开发辅助工具指南 (推理)](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools) +在result目录下生成resnet18_deploy_model.onnx量化模型 + +4.量化模型验证,除onnx离线模型转换om模型命令有区别外,其余一致 + +### 4.3 onnx转om模型 + +1.设置环境变量 +``` +source env.sh +``` +**说明** +>此脚本中环境变量只供参考,请以实际安装环境配置环境变量 + +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN 开发辅助工具指南 (推理)](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools) +``` +atc --framework=5 --model=./resnet18.onnx --output=resnet18_bs1 --input_format=NCHW --input_shape="image:1,3,224,224" --log=debug --soc_version=Ascend310 --insert_op_conf=aipp.config --enable_small_channel=1 + + +## Int8量化(可选) +atc --framework=5 --model=./result/resnet18_deploy_model.onnx --output=resnet18_bs1_int8 --input_format=NCHW --input_shape="image:1,3,224,224" --log=debug --soc_version=Ascend710 --insert_op_conf=aipp.config --enable_small_channel=1 +``` + +### 4.4 模型离线推理 + +1.设置环境变量 +``` +source env.sh +``` +**说明** +>此脚本中环境变量只供参考,请以实际安装环境配置环境变量 + +2.增加benchmark.{arch}可执行权限 +``` +chmod u+x benchmark.x86_64 +``` + +3.执行离线推理 +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=resnet18_bs1.om -input_text_path=./resnet18_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False +执行./benchmark.x86_64工具请选择与运行环境架构相同的命令。详情参考[CANN 推理benchmark工具用户指南](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools) + +4.精度验证 +调用imagenet_acc_eval.py脚本与数据集标签val_label.txt比对,可以获得Accuracy Top5数据,结果保存在result.json中。 +``` +python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /home/HwHiAiUser/dataset/imagenet/val_label.txt ./ result.json +``` 第一个参数为生成推理结果所在路径,第二个参数为标签数据,第三个参数为生成结果文件路径,第四个参数为生成结果文件名称 \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/calibration_bin.py b/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/calibration_bin.py index 0af890d132..0839502aa7 100644 --- a/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/calibration_bin.py +++ b/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/calibration_bin.py @@ -1,56 +1,56 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import numpy as np -import multiprocessing - -max_bin=10 -def preprocess(src_path, save_path, batch_size): - files = os.listdir(src_path) - - output_data = [0] - for i, file in enumerate(files): - input_data = np.fromfile(os.path.join(src_path, file), dtype=np.float32) - input_data = input_data.reshape(1, 3, 224, 224) - - if i % batch_size == 0: - output_data = input_data - else: - output_data = np.concatenate((output_data, input_data), axis=0) - - # only save 10 bin files - loop_id = (i + 1) // batch_size - if loop_id > max_bin: - break - - if (i + 1) % batch_size == 0: - output_data.tofile("{}/img_{}_bs{}.bin".format(save_path, loop_id, batch_size)) - output_data = [0] - - -if __name__ == '__main__': - if len(sys.argv) < 4: - raise Exception("usage: python3 xxx.py [src_path] [save_path] [batch_size]") - src_path = sys.argv[1] - save_path = sys.argv[2] - batch_size = int(sys.argv[3]) - src_path = os.path.realpath(src_path) - save_path = os.path.realpath(save_path) - - if not os.path.isdir(save_path): - os.makedirs(os.path.realpath(save_path)) - preprocess(src_path, save_path, batch_size) - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import numpy as np +import multiprocessing + +max_bin=10 +def preprocess(src_path, save_path, batch_size): + files = os.listdir(src_path) + + output_data = [0] + for i, file in enumerate(files): + input_data = np.fromfile(os.path.join(src_path, file), dtype=np.float32) + input_data = input_data.reshape(1, 3, 224, 224) + + if i % batch_size == 0: + output_data = input_data + else: + output_data = np.concatenate((output_data, input_data), axis=0) + + # only save 10 bin files + loop_id = (i + 1) // batch_size + if loop_id > max_bin: + break + + if (i + 1) % batch_size == 0: + output_data.tofile("{}/img_{}_bs{}.bin".format(save_path, loop_id, batch_size)) + output_data = [0] + + +if __name__ == '__main__': + if len(sys.argv) < 4: + raise Exception("usage: python3 xxx.py [src_path] [save_path] [batch_size]") + src_path = sys.argv[1] + save_path = sys.argv[2] + batch_size = int(sys.argv[3]) + src_path = os.path.realpath(src_path) + save_path = os.path.realpath(save_path) + + if not os.path.isdir(save_path): + os.makedirs(os.path.realpath(save_path)) + preprocess(src_path, save_path, batch_size) + diff --git a/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/gen_dataset_info.py b/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/gen_dataset_info.py index 61450b4410..5381839f65 100644 --- a/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/gen_dataset_info.py +++ b/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/gen_dataset_info.py @@ -1,61 +1,61 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' - get_jpg_info(file_path, info_name) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' + get_jpg_info(file_path, info_name) + diff --git a/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/imagenet_acc_eval.py b/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/imagenet_acc_eval.py index 362f2484e8..583340a19f 100644 --- a/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/imagenet_acc_eval.py +++ b/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/imagenet_acc_eval.py @@ -1,184 +1,184 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - if data == '': - n_label = 0 - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = 0 - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - - resCnt = min(len(sort_index), topn) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) - print("Time used:", elapsed) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + if data == '': + n_label = 0 + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = 0 + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + + resCnt = min(len(sort_index), topn) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) + print("Time used:", elapsed) + diff --git a/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/imagenet_torch_preprocess.py b/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/imagenet_torch_preprocess.py index 4787c75a5e..2cdb4994ca 100644 --- a/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/imagenet_torch_preprocess.py +++ b/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/imagenet_torch_preprocess.py @@ -1,114 +1,114 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -from PIL import Image -import numpy as np -import multiprocessing - - -model_config = { - 'resnet': { - 'resize': 256, - 'centercrop': 224, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv3': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv4': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.5, 0.5, 0.5], - 'std': [0.5, 0.5, 0.5], - }, -} - - -def center_crop(img, output_size): - if isinstance(output_size, int): - output_size = (int(output_size), int(output_size)) - image_width, image_height = img.size - crop_height, crop_width = output_size - crop_top = int(round((image_height - crop_height) / 2.)) - crop_left = int(round((image_width - crop_width) / 2.)) - return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) - - -def resize(img, size, interpolation=Image.BILINEAR): - if isinstance(size, int): - w, h = img.size - if (w <= h and w == size) or (h <= w and h == size): - return img - if w < h: - ow = size - oh = int(size * h / w) - return img.resize((ow, oh), interpolation) - else: - oh = size - ow = int(size * w / h) - return img.resize((ow, oh), interpolation) - else: - return img.resize(size[::-1], interpolation) - - -def gen_input_bin(mode_type, file_batches, batch): - i = 0 - for file in file_batches[batch]: - i = i + 1 - print("batch", batch, file, "===", i) - - # RGBA to RGB - image = Image.open(os.path.join(src_path, file)).convert('RGB') - image = resize(image, model_config[mode_type]['resize']) # Resize - image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop - img = np.array(image, dtype=np.int8) - - img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) - - -def preprocess(mode_type, src_path, save_path): - files = os.listdir(src_path) - file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] - thread_pool = multiprocessing.Pool(len(file_batches)) - for batch in range(len(file_batches)): - thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) - thread_pool.close() - thread_pool.join() - print("in thread, except will not report! please ensure bin files generated.") - - -if __name__ == '__main__': - if len(sys.argv) < 4: - raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") - mode_type = sys.argv[1] - src_path = sys.argv[2] - save_path = sys.argv[3] - src_path = os.path.realpath(src_path) - save_path = os.path.realpath(save_path) - if mode_type not in model_config: - model_type_help = "model type: " - for key in model_config.keys(): - model_type_help += key - model_type_help += ' ' - raise Exception(model_type_help) - if not os.path.isdir(save_path): - os.makedirs(os.path.realpath(save_path)) - preprocess(mode_type, src_path, save_path) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +from PIL import Image +import numpy as np +import multiprocessing + + +model_config = { + 'resnet': { + 'resize': 256, + 'centercrop': 224, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv3': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv4': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.5, 0.5, 0.5], + 'std': [0.5, 0.5, 0.5], + }, +} + + +def center_crop(img, output_size): + if isinstance(output_size, int): + output_size = (int(output_size), int(output_size)) + image_width, image_height = img.size + crop_height, crop_width = output_size + crop_top = int(round((image_height - crop_height) / 2.)) + crop_left = int(round((image_width - crop_width) / 2.)) + return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) + + +def resize(img, size, interpolation=Image.BILINEAR): + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def gen_input_bin(mode_type, file_batches, batch): + i = 0 + for file in file_batches[batch]: + i = i + 1 + print("batch", batch, file, "===", i) + + # RGBA to RGB + image = Image.open(os.path.join(src_path, file)).convert('RGB') + image = resize(image, model_config[mode_type]['resize']) # Resize + image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop + img = np.array(image, dtype=np.int8) + + img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) + + +def preprocess(mode_type, src_path, save_path): + files = os.listdir(src_path) + file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] + thread_pool = multiprocessing.Pool(len(file_batches)) + for batch in range(len(file_batches)): + thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) + thread_pool.close() + thread_pool.join() + print("in thread, except will not report! please ensure bin files generated.") + + +if __name__ == '__main__': + if len(sys.argv) < 4: + raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") + mode_type = sys.argv[1] + src_path = sys.argv[2] + save_path = sys.argv[3] + src_path = os.path.realpath(src_path) + save_path = os.path.realpath(save_path) + if mode_type not in model_config: + model_type_help = "model type: " + for key in model_config.keys(): + model_type_help += key + model_type_help += ' ' + raise Exception(model_type_help) + if not os.path.isdir(save_path): + os.makedirs(os.path.realpath(save_path)) + preprocess(mode_type, src_path, save_path) + diff --git a/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/modelzoo_level.txt b/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/modelzoo_level.txt index 484664c239..55a9add9fa 100644 --- a/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/modelzoo_level.txt +++ b/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:POK \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/requirements.txt b/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/requirements.txt index 2fc4e802c4..d072d9aa6f 100644 --- a/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/requirements.txt +++ b/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/requirements.txt @@ -1,6 +1,6 @@ -torch == 1.5.1 -torchvision == 0.6.1 -onnx == 1.9.0 -numpy == 1.19.2 -Pillow == 8.2.0 +torch == 1.5.1 +torchvision == 0.6.1 +onnx == 1.9.0 +numpy == 1.19.2 +Pillow == 8.2.0 opencv-python == 4.5.2 \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/resnet18_pth2onnx.py b/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/resnet18_pth2onnx.py index f7972ea3e1..5933787407 100644 --- a/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/resnet18_pth2onnx.py +++ b/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch/resnet18_pth2onnx.py @@ -1,35 +1,35 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -import torch -import torch.onnx -import torchvision.models as models - -def pth2onnx(input_file, output_file): - model = models.resnet18(pretrained=False) - checkpoint = torch.load(input_file, map_location=None) - model.load_state_dict(checkpoint) - - model.eval() - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.randn(1, 3, 224, 224) - torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=True, opset_version=11) - -if __name__ == "__main__": - input_file = sys.argv[1] - output_file = sys.argv[2] - pth2onnx(input_file, output_file) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +import torch +import torch.onnx +import torchvision.models as models + +def pth2onnx(input_file, output_file): + model = models.resnet18(pretrained=False) + checkpoint = torch.load(input_file, map_location=None) + model.load_state_dict(checkpoint) + + model.eval() + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.randn(1, 3, 224, 224) + torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=True, opset_version=11) + +if __name__ == "__main__": + input_file = sys.argv[1] + output_file = sys.argv[2] + pth2onnx(input_file, output_file) diff --git a/ACL_PyTorch/built-in/cv/Resnet50_Pytorch_Infer/aipp_resnet50_710.aippconfig b/ACL_PyTorch/built-in/cv/Resnet50_Pytorch_Infer/aipp_resnet50_710.aippconfig index 71e0923f2a..173c2d8035 100644 --- a/ACL_PyTorch/built-in/cv/Resnet50_Pytorch_Infer/aipp_resnet50_710.aippconfig +++ b/ACL_PyTorch/built-in/cv/Resnet50_Pytorch_Infer/aipp_resnet50_710.aippconfig @@ -1,20 +1,20 @@ -aipp_op{ - aipp_mode:static - input_format : RGB888_U8 - - src_image_size_w : 256 - src_image_size_h : 256 - - crop: true - load_start_pos_h : 16 - load_start_pos_w : 16 - crop_size_w : 224 - crop_size_h: 224 - - min_chn_0 : 123.675 - min_chn_1 : 116.28 - min_chn_2 : 103.53 - var_reci_chn_0: 0.0171247538316637 - var_reci_chn_1: 0.0175070028011204 - var_reci_chn_2: 0.0174291938997821 +aipp_op{ + aipp_mode:static + input_format : RGB888_U8 + + src_image_size_w : 256 + src_image_size_h : 256 + + crop: true + load_start_pos_h : 16 + load_start_pos_w : 16 + crop_size_w : 224 + crop_size_h: 224 + + min_chn_0 : 123.675 + min_chn_1 : 116.28 + min_chn_2 : 103.53 + var_reci_chn_0: 0.0171247538316637 + var_reci_chn_1: 0.0175070028011204 + var_reci_chn_2: 0.0174291938997821 } \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/Resnet50_Pytorch_Infer/gen_dataset_info.py b/ACL_PyTorch/built-in/cv/Resnet50_Pytorch_Infer/gen_dataset_info.py index 0af8797d66..5ed4309f9e 100644 --- a/ACL_PyTorch/built-in/cv/Resnet50_Pytorch_Infer/gen_dataset_info.py +++ b/ACL_PyTorch/built-in/cv/Resnet50_Pytorch_Infer/gen_dataset_info.py @@ -1,61 +1,61 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' - get_jpg_info(file_path, info_name) - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' + get_jpg_info(file_path, info_name) + diff --git a/ACL_PyTorch/built-in/cv/Resnet50_Pytorch_Infer/imagenet_torch_preprocess.py b/ACL_PyTorch/built-in/cv/Resnet50_Pytorch_Infer/imagenet_torch_preprocess.py index b715ddd3f5..a34814146f 100644 --- a/ACL_PyTorch/built-in/cv/Resnet50_Pytorch_Infer/imagenet_torch_preprocess.py +++ b/ACL_PyTorch/built-in/cv/Resnet50_Pytorch_Infer/imagenet_torch_preprocess.py @@ -1,129 +1,129 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -from PIL import Image -import numpy as np -import multiprocessing - - -model_config = { - 'resnet': { - 'resize': 256, - 'centercrop': 256, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv3': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv4': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.5, 0.5, 0.5], - 'std': [0.5, 0.5, 0.5], - }, -} - - -def center_crop(img, output_size): - if isinstance(output_size, int): - output_size = (int(output_size), int(output_size)) - image_width, image_height = img.size - crop_height, crop_width = output_size - crop_top = int(round((image_height - crop_height) / 2.)) - crop_left = int(round((image_width - crop_width) / 2.)) - return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) - - -def resize(img, size, interpolation=Image.BILINEAR): - if isinstance(size, int): - w, h = img.size - if (w <= h and w == size) or (h <= w and h == size): - return img - if w < h: - ow = size - oh = int(size * h / w) - return img.resize((ow, oh), interpolation) - else: - oh = size - ow = int(size * w / h) - return img.resize((ow, oh), interpolation) - else: - return img.resize(size[::-1], interpolation) - - -def gen_input_bin(mode_type, file_batches, batch): - i = 0 - for file in file_batches[batch]: - i = i + 1 - print("batch", batch, file, "===", i) - - # RGBA to RGB - image = Image.open(os.path.join(src_path, file)).convert('RGB') - image = resize(image, model_config[mode_type]['resize']) # Resize - image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop - img = np.array(image, dtype=np.int8) - img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) - -def preprocess_s(mode_type, src_path, save_path): - files = os.listdir(src_path) - i = 0 - for file in files: - if not file.endswith(".jpeg"): - continue - print("start to process image {}....".format(file)) - i = i + 1 - print("file", file, "===", i) - path_image = os.path.join(src_path, file) - # RGBA to RGB - image = Image.open(path_image).convert('RGB') - image = resize(image, model_config[mode_type]['resize']) # Resize - image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop - img = np.array(image, dtype=np.int8) - img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) - -def preprocess(mode_type, src_path, save_path): - files = os.listdir(src_path) - file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] - thread_pool = multiprocessing.Pool(len(file_batches)) - for batch in range(len(file_batches)): - thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) - thread_pool.close() - thread_pool.join() - print("in thread, except will not report! please ensure bin files generated.") - - -if __name__ == '__main__': - if len(sys.argv) < 4: - raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") - mode_type = sys.argv[1] - src_path = sys.argv[2] - save_path = sys.argv[3] - src_path = os.path.realpath(src_path) - save_path = os.path.realpath(save_path) - if mode_type not in model_config: - model_type_help = "model type: " - for key in model_config.keys(): - model_type_help += key - model_type_help += ' ' - raise Exception(model_type_help) - if not os.path.isdir(save_path): - os.makedirs(os.path.realpath(save_path)) - preprocess_s(mode_type, src_path, save_path) - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +from PIL import Image +import numpy as np +import multiprocessing + + +model_config = { + 'resnet': { + 'resize': 256, + 'centercrop': 256, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv3': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv4': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.5, 0.5, 0.5], + 'std': [0.5, 0.5, 0.5], + }, +} + + +def center_crop(img, output_size): + if isinstance(output_size, int): + output_size = (int(output_size), int(output_size)) + image_width, image_height = img.size + crop_height, crop_width = output_size + crop_top = int(round((image_height - crop_height) / 2.)) + crop_left = int(round((image_width - crop_width) / 2.)) + return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) + + +def resize(img, size, interpolation=Image.BILINEAR): + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def gen_input_bin(mode_type, file_batches, batch): + i = 0 + for file in file_batches[batch]: + i = i + 1 + print("batch", batch, file, "===", i) + + # RGBA to RGB + image = Image.open(os.path.join(src_path, file)).convert('RGB') + image = resize(image, model_config[mode_type]['resize']) # Resize + image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop + img = np.array(image, dtype=np.int8) + img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) + +def preprocess_s(mode_type, src_path, save_path): + files = os.listdir(src_path) + i = 0 + for file in files: + if not file.endswith(".jpeg"): + continue + print("start to process image {}....".format(file)) + i = i + 1 + print("file", file, "===", i) + path_image = os.path.join(src_path, file) + # RGBA to RGB + image = Image.open(path_image).convert('RGB') + image = resize(image, model_config[mode_type]['resize']) # Resize + image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop + img = np.array(image, dtype=np.int8) + img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) + +def preprocess(mode_type, src_path, save_path): + files = os.listdir(src_path) + file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] + thread_pool = multiprocessing.Pool(len(file_batches)) + for batch in range(len(file_batches)): + thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) + thread_pool.close() + thread_pool.join() + print("in thread, except will not report! please ensure bin files generated.") + + +if __name__ == '__main__': + if len(sys.argv) < 4: + raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") + mode_type = sys.argv[1] + src_path = sys.argv[2] + save_path = sys.argv[3] + src_path = os.path.realpath(src_path) + save_path = os.path.realpath(save_path) + if mode_type not in model_config: + model_type_help = "model type: " + for key in model_config.keys(): + model_type_help += key + model_type_help += ' ' + raise Exception(model_type_help) + if not os.path.isdir(save_path): + os.makedirs(os.path.realpath(save_path)) + preprocess_s(mode_type, src_path, save_path) + diff --git a/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/README.md b/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/README.md index d9e1c75e63..803c1aebb3 100644 --- a/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/README.md +++ b/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/README.md @@ -1,234 +1,234 @@ -# SE_ResNet50 Onnx模型端到端推理指导 -- [1 模型概述](#1-模型概述) - - [1.1 论文地址](#11-论文地址) - - [1.2 代码地址](#12-代码地址) -- [2 环境说明](#2-环境说明) - - [2.1 推理硬件设备](#21-推理硬件设备) - - [2.2 深度学习框架](#22-深度学习框架) - - [2.3 Python第三方库](#23-Python第三方库) -- [3 模型转换](#3-模型转换) - - [3.1 获取pth权重文件](#31-获取pth权重文件) - - [3.2 获取pth权重文件](#32-pth转onnx模型) - - [3.3 pth转om模型](#33-onnx转om模型) -- [4 数据集预处理](#4-数据集预处理) - - [4.1 数据集获取](#41-数据集获取) - - [4.2 数据集预处理](#42-数据集预处理) - - [4.3 生成数据集信息文件](#43-生成数据集信息文件) -- [5 离线推理](#5-离线推理) - - [5.1 benchmark工具概述](#51-benchmark工具概述) - - [5.2 离线推理](#52-离线推理) - - [5.3 性能验证](#53-性能验证) -- [6 评测结果](#6-评测结果) -- [7 test目录说明](#7-test目录说明) - -## 1 模型概述 - -- **[论文地址](#11-论文地址)** - -- **[代码地址](#12-代码地址)** - -### 1.1 论文地址 -[SE_ResNet50论文](https://openaccess.thecvf.com/content_cvpr_2018/papers/Hu_Squeeze-and-Excitation_Networks_CVPR_2018_paper.pdf) - -### 1.2 代码地址 -[SE_ResNet50代码](https://github.com/Cadene/pretrained-models.pytorch/blob/master/pretrainedmodels/models/senet.py) - -## 2 环境说明 - -- **[推理硬件设备](#21-推理硬件设备)** - -- **[深度学习框架](#22-深度学习框架)** - -- **[Python第三方库](#23-Python第三方库)** - -### 2.1 推理硬件设备 -``` -Ascend710 -``` - -### 2.2 深度学习框架 -``` -CANN 5.0.4 - -torch == 1.8.0 -torchvision == 0.9.0 -onnx == 1.10.2 -``` - -### 2.3 Python第三方库 - -``` -numpy == 1.21.4 -opencv-python == 4.5.4.58 -pretrainedmodels == 0.7.4 -``` - -**说明:** -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3 模型转换 - -- **[获取pth权重文件](#31-获取pth权重文件)** - -- **[pth转onnx模型](#32-pth转onnx模型)** - -- **[onnx转om模型](#33-onnx转om模型)** - -### 3.1 获取pth权重文件 -执行命令: - -``` -wget https://data.lip6.fr/cadene/pretrainedmodels/se_resnet50-ce0d4300.pth -``` -执行后在当前目录下获取pth权重文件:se_resnet50-ce0d4300.pth。 - -### 3.2 pth转onnx模型 -执行命令: - -``` -python3 SE_ResNet50_pth2onnx.py ./se_resnet50-ce0d4300.pth ./se_resnet50_dynamic_bs.onnx -``` - -命令参数分别为输入pth文件:./se_resnet50-ce0d4300.pth和输出onnx文件:./se_resnet50_dynamic_bs.onnx -执行后在当前路径下生成se_resnet50_dynamic_bs.onnx模型文件。 - -### 3.3 onnx转om模型 - -a.设置环境变量: - -``` -source /usr/local/Ascend/ascend-toolkit/set_env.sh -``` - -该命令中使用CANN默认安装路径(/usr/local/Ascend/ascend-toolkit)中的环境变量,使用过程中请按照实际安装路径设置环境变量。 - -b.执行atc模型转换命令: - -``` -atc --model=./se_resnet50_dynamic_bs.onnx --framework=5 --input_format=NCHW --input_shape="image:32,3,224,224" --output=./se_resnet50_fp16_bs32 --log=error --soc_version=Ascend710 --insert_op_conf=./aipp_SE_ResNet50_pth.config --enable_small_channel=1 -``` - -参数说明: - --model:为ONNX模型文件。 - --framework:5代表ONNX模型。 - --input_format:输入数据的格式。 - --input_shape:输入数据的shape。 - --output:输出的OM模型。 - --log:日志级别。 - --soc_version:处理器型号,Ascend310或Ascend710。 - --insert_op_config:插入算子的配置文件路径与文件名,例如aipp预处理算子。 - --enable_small_channel:Set enable small channel. 0(default): disable; 1: enable - -执行后在当前目录下生成om模型文件:se_resnet50_fp16_bs32.om。 - -## 4 数据集预处理 - -- **[数据集获取](#41-数据集获取)** - -- **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - -### 4.1 数据集获取 -该模型使用ImageNet的5万张验证集进行测试,图片与标签分别存放在/home/HwHiAiUser/dataset/ImageNet/val_union路径与/home/HwHiAiUser/dataset/ImageNet/val_label.txt文件下。 - -数据集获取请参考[pytorch原始仓](https://github.com/pytorch/examples/tree/master/imagenet)说明。 - -### 4.2 数据集预处理 - -1.预处理工具为:imagenet_torch_preprocess.py -2.执行工具命令: -``` -python3 ./imagenet_torch_preprocess.py /home/HwHiAiUser/dataset/ImageNet/val_union ./data/ImageNet_bin -``` -命令参数分别数据集图片路径:/home/HwHiAiUser/dataset/ImageNet/val_union和处理结果bin文件保存路径:./data/ImageNet_bin。 -执行后在./data/ImageNet_bin路径下生成数据处理后的bin文件。 - -### 4.3 生成数据集信息文件 -1.生成数据集信息文件工具为:gen_dataset_info.py。 -2.执行工具命令: - -``` -python3 ./gen_dataset_info.py bin ./data/ImageNet_bin ./data/ImageNet_bin.info 224 224 -``` -命令参数分别为数据集文件类型:bin、文件路径:./data/ImageNet_bin、数据集信息文件:./data/ImageNet_bin.info、图片像素长:224、图片像素宽:224。 -执行后在./data路径下生成数据集信息文件:ImageNet_bin.info。 - -## 5 离线推理 - -- **[benchmark工具概述](#51-benchmark工具概述)** - -- **[离线推理](#52-离线推理)** - -- **[性能验证](#52-性能验证)** - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend710上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) -### 5.2 离线推理 -1.设置环境变量: - -``` -source /usr/local/Ascend/ascend-toolkit/set_env.sh -``` - -2.执行推理命令: - -``` -./benchmark.x86_64 -model_type=vision -om_path=./se_resnet50_fp16_bs32.om -device_id=0 -batch_size=32 -input_text_path=./data/ImageNet_bin.info -input_width=256 -input_height=256 -output_binary=false -useDvpp=false -``` - -分辨率(input_width,input_height)要与aipp_SE_ResNet50_pth.config文件中配置(src_image_size_w,src_image_size_h)保持一致,执行后推理结果保存在./result/dumpOutput_device0路径下。 - -3.精度验证: -调用vision_metric_ImageNet.py工具脚本与数据集标签val_label.txt比对,可以获得Accuracy Top5数据: - -``` -python3 ./vision_metric_ImageNet.py ./result/dumpOutput_device0/ /home/HwHiAiUser/dataset/ImageNet/val_label.txt ./result accuracy_result.json -``` - -第一个参数为生成推理结果所在路径,第二个参数为标签数据,第三个参数为生成结果文件路径,第四个参数为生成结果文件名称。 -执行后模型精度结果保存在./result/accuracy_result.json文件中 - -### 5.3 性能验证 -1.设置环境变量: - -``` -source /usr/local/Ascend/ascend-toolkit/set_env.sh -``` - -2.执行性能测试命令: - -``` -./benchmark.x86_64 -round=50 -om_path=./se_resnet50_fp16_bs32.om -device_id=0 -batch_size=32 > ./result/performace_result.json -``` - -执行后性能测试结果保存在./result/performace_result.json文件中 - -## 6 评测结果 - -评测结果 -| 模型 | pth精度 | 710精度 | 性能基准 | 710性能 | -| --------------- | ---------------------- | ------------------------- | ------------ | ----------- | -| SE_ResNet50 bs32 | Acc@1 77.63,Acc@5 93.64| Acc@1 77.36,Acc@5 93.76 | 1554.726fps | 2690.43fps | - -## 6 test目录说明 - -test目录下存放的为测试脚本,其中: -1.pth2om.sh为pth模型转om模型脚本,使用命令为: - -``` -bash ./test/pth2om.sh /usr/local/Ascend -``` - -其中/usr/local/Ascend为cann包默认安装路径,执行后在当前目录下生成om模型: se_resnet50_fp16_bs32.om。 - -2.eval_acc_perf.sh为om模型,精度、性能测试脚本,使用命令为: - -``` -bash ./test/eval_acc_perf.sh /usr/local/Ascend ./se_resnet50_fp16_bs32.om 32 0 /home/HwHiAiUser/dataset/ImageNet/val_label.txt -``` - +# SE_ResNet50 Onnx模型端到端推理指导 +- [1 模型概述](#1-模型概述) + - [1.1 论文地址](#11-论文地址) + - [1.2 代码地址](#12-代码地址) +- [2 环境说明](#2-环境说明) + - [2.1 推理硬件设备](#21-推理硬件设备) + - [2.2 深度学习框架](#22-深度学习框架) + - [2.3 Python第三方库](#23-Python第三方库) +- [3 模型转换](#3-模型转换) + - [3.1 获取pth权重文件](#31-获取pth权重文件) + - [3.2 获取pth权重文件](#32-pth转onnx模型) + - [3.3 pth转om模型](#33-onnx转om模型) +- [4 数据集预处理](#4-数据集预处理) + - [4.1 数据集获取](#41-数据集获取) + - [4.2 数据集预处理](#42-数据集预处理) + - [4.3 生成数据集信息文件](#43-生成数据集信息文件) +- [5 离线推理](#5-离线推理) + - [5.1 benchmark工具概述](#51-benchmark工具概述) + - [5.2 离线推理](#52-离线推理) + - [5.3 性能验证](#53-性能验证) +- [6 评测结果](#6-评测结果) +- [7 test目录说明](#7-test目录说明) + +## 1 模型概述 + +- **[论文地址](#11-论文地址)** + +- **[代码地址](#12-代码地址)** + +### 1.1 论文地址 +[SE_ResNet50论文](https://openaccess.thecvf.com/content_cvpr_2018/papers/Hu_Squeeze-and-Excitation_Networks_CVPR_2018_paper.pdf) + +### 1.2 代码地址 +[SE_ResNet50代码](https://github.com/Cadene/pretrained-models.pytorch/blob/master/pretrainedmodels/models/senet.py) + +## 2 环境说明 + +- **[推理硬件设备](#21-推理硬件设备)** + +- **[深度学习框架](#22-深度学习框架)** + +- **[Python第三方库](#23-Python第三方库)** + +### 2.1 推理硬件设备 +``` +Ascend710 +``` + +### 2.2 深度学习框架 +``` +CANN 5.0.4 + +torch == 1.8.0 +torchvision == 0.9.0 +onnx == 1.10.2 +``` + +### 2.3 Python第三方库 + +``` +numpy == 1.21.4 +opencv-python == 4.5.4.58 +pretrainedmodels == 0.7.4 +``` + +**说明:** +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3 模型转换 + +- **[获取pth权重文件](#31-获取pth权重文件)** + +- **[pth转onnx模型](#32-pth转onnx模型)** + +- **[onnx转om模型](#33-onnx转om模型)** + +### 3.1 获取pth权重文件 +执行命令: + +``` +wget https://data.lip6.fr/cadene/pretrainedmodels/se_resnet50-ce0d4300.pth +``` +执行后在当前目录下获取pth权重文件:se_resnet50-ce0d4300.pth。 + +### 3.2 pth转onnx模型 +执行命令: + +``` +python3 SE_ResNet50_pth2onnx.py ./se_resnet50-ce0d4300.pth ./se_resnet50_dynamic_bs.onnx +``` + +命令参数分别为输入pth文件:./se_resnet50-ce0d4300.pth和输出onnx文件:./se_resnet50_dynamic_bs.onnx +执行后在当前路径下生成se_resnet50_dynamic_bs.onnx模型文件。 + +### 3.3 onnx转om模型 + +a.设置环境变量: + +``` +source /usr/local/Ascend/ascend-toolkit/set_env.sh +``` + +该命令中使用CANN默认安装路径(/usr/local/Ascend/ascend-toolkit)中的环境变量,使用过程中请按照实际安装路径设置环境变量。 + +b.执行atc模型转换命令: + +``` +atc --model=./se_resnet50_dynamic_bs.onnx --framework=5 --input_format=NCHW --input_shape="image:32,3,224,224" --output=./se_resnet50_fp16_bs32 --log=error --soc_version=Ascend710 --insert_op_conf=./aipp_SE_ResNet50_pth.config --enable_small_channel=1 +``` + +参数说明: + --model:为ONNX模型文件。 + --framework:5代表ONNX模型。 + --input_format:输入数据的格式。 + --input_shape:输入数据的shape。 + --output:输出的OM模型。 + --log:日志级别。 + --soc_version:处理器型号,Ascend310或Ascend710。 + --insert_op_config:插入算子的配置文件路径与文件名,例如aipp预处理算子。 + --enable_small_channel:Set enable small channel. 0(default): disable; 1: enable + +执行后在当前目录下生成om模型文件:se_resnet50_fp16_bs32.om。 + +## 4 数据集预处理 + +- **[数据集获取](#41-数据集获取)** + +- **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + +### 4.1 数据集获取 +该模型使用ImageNet的5万张验证集进行测试,图片与标签分别存放在/home/HwHiAiUser/dataset/ImageNet/val_union路径与/home/HwHiAiUser/dataset/ImageNet/val_label.txt文件下。 + +数据集获取请参考[pytorch原始仓](https://github.com/pytorch/examples/tree/master/imagenet)说明。 + +### 4.2 数据集预处理 + +1.预处理工具为:imagenet_torch_preprocess.py +2.执行工具命令: +``` +python3 ./imagenet_torch_preprocess.py /home/HwHiAiUser/dataset/ImageNet/val_union ./data/ImageNet_bin +``` +命令参数分别数据集图片路径:/home/HwHiAiUser/dataset/ImageNet/val_union和处理结果bin文件保存路径:./data/ImageNet_bin。 +执行后在./data/ImageNet_bin路径下生成数据处理后的bin文件。 + +### 4.3 生成数据集信息文件 +1.生成数据集信息文件工具为:gen_dataset_info.py。 +2.执行工具命令: + +``` +python3 ./gen_dataset_info.py bin ./data/ImageNet_bin ./data/ImageNet_bin.info 224 224 +``` +命令参数分别为数据集文件类型:bin、文件路径:./data/ImageNet_bin、数据集信息文件:./data/ImageNet_bin.info、图片像素长:224、图片像素宽:224。 +执行后在./data路径下生成数据集信息文件:ImageNet_bin.info。 + +## 5 离线推理 + +- **[benchmark工具概述](#51-benchmark工具概述)** + +- **[离线推理](#52-离线推理)** + +- **[性能验证](#52-性能验证)** + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend710上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) +### 5.2 离线推理 +1.设置环境变量: + +``` +source /usr/local/Ascend/ascend-toolkit/set_env.sh +``` + +2.执行推理命令: + +``` +./benchmark.x86_64 -model_type=vision -om_path=./se_resnet50_fp16_bs32.om -device_id=0 -batch_size=32 -input_text_path=./data/ImageNet_bin.info -input_width=256 -input_height=256 -output_binary=false -useDvpp=false +``` + +分辨率(input_width,input_height)要与aipp_SE_ResNet50_pth.config文件中配置(src_image_size_w,src_image_size_h)保持一致,执行后推理结果保存在./result/dumpOutput_device0路径下。 + +3.精度验证: +调用vision_metric_ImageNet.py工具脚本与数据集标签val_label.txt比对,可以获得Accuracy Top5数据: + +``` +python3 ./vision_metric_ImageNet.py ./result/dumpOutput_device0/ /home/HwHiAiUser/dataset/ImageNet/val_label.txt ./result accuracy_result.json +``` + +第一个参数为生成推理结果所在路径,第二个参数为标签数据,第三个参数为生成结果文件路径,第四个参数为生成结果文件名称。 +执行后模型精度结果保存在./result/accuracy_result.json文件中 + +### 5.3 性能验证 +1.设置环境变量: + +``` +source /usr/local/Ascend/ascend-toolkit/set_env.sh +``` + +2.执行性能测试命令: + +``` +./benchmark.x86_64 -round=50 -om_path=./se_resnet50_fp16_bs32.om -device_id=0 -batch_size=32 > ./result/performace_result.json +``` + +执行后性能测试结果保存在./result/performace_result.json文件中 + +## 6 评测结果 + +评测结果 +| 模型 | pth精度 | 710精度 | 性能基准 | 710性能 | +| --------------- | ---------------------- | ------------------------- | ------------ | ----------- | +| SE_ResNet50 bs32 | Acc@1 77.63,Acc@5 93.64| Acc@1 77.36,Acc@5 93.76 | 1554.726fps | 2690.43fps | + +## 6 test目录说明 + +test目录下存放的为测试脚本,其中: +1.pth2om.sh为pth模型转om模型脚本,使用命令为: + +``` +bash ./test/pth2om.sh /usr/local/Ascend +``` + +其中/usr/local/Ascend为cann包默认安装路径,执行后在当前目录下生成om模型: se_resnet50_fp16_bs32.om。 + +2.eval_acc_perf.sh为om模型,精度、性能测试脚本,使用命令为: + +``` +bash ./test/eval_acc_perf.sh /usr/local/Ascend ./se_resnet50_fp16_bs32.om 32 0 /home/HwHiAiUser/dataset/ImageNet/val_label.txt +``` + 其中第1个参数为cann包安装路径,第2个参数为om模型,第3个参数为batch_size,第4个参数为device_id,第5个参数为标签数据。执行后精度结果保存在./result/accuracy_result.json文件中,性能结果保存在./result/performace_result.json文件中。 \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/SE_ResNet50_pth2onnx.py b/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/SE_ResNet50_pth2onnx.py index 94a9bce4b9..9a96a25156 100644 --- a/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/SE_ResNet50_pth2onnx.py +++ b/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/SE_ResNet50_pth2onnx.py @@ -1,39 +1,39 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -# coding=UTF-8 - -import sys -import torch -import onnx -from pretrainedmodels.models.senet import se_resnet50 - - -def pth2onnx(pth_file, onnx_file): - model = se_resnet50(num_classes=1000, pretrained=None) - model.load_state_dict(torch.load(pth_file)) - model.eval() - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.randn(1, 3, 224, 224) - torch.onnx.export(model, dummy_input, onnx_file, input_names=input_names, dynamic_axes=dynamic_axes, - output_names=output_names, opset_version=11) - -if __name__ == '__main__': - if len(sys.argv) != 3: - raise Exception("usage: python SE_ResNet50_pth2onnx.py ") - pth_file = sys.argv[1] - onnx_file = sys.argv[2] - pth2onnx(pth_file, onnx_file) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +# coding=UTF-8 + +import sys +import torch +import onnx +from pretrainedmodels.models.senet import se_resnet50 + + +def pth2onnx(pth_file, onnx_file): + model = se_resnet50(num_classes=1000, pretrained=None) + model.load_state_dict(torch.load(pth_file)) + model.eval() + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.randn(1, 3, 224, 224) + torch.onnx.export(model, dummy_input, onnx_file, input_names=input_names, dynamic_axes=dynamic_axes, + output_names=output_names, opset_version=11) + +if __name__ == '__main__': + if len(sys.argv) != 3: + raise Exception("usage: python SE_ResNet50_pth2onnx.py ") + pth_file = sys.argv[1] + onnx_file = sys.argv[2] + pth2onnx(pth_file, onnx_file) diff --git a/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/aipp_SE_ResNet50_pth.config b/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/aipp_SE_ResNet50_pth.config index 01600d0fa1..16b6c79d15 100644 --- a/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/aipp_SE_ResNet50_pth.config +++ b/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/aipp_SE_ResNet50_pth.config @@ -1,21 +1,21 @@ -aipp_op{ - aipp_mode:static - input_format : RGB888_U8 - - src_image_size_w : 256 - src_image_size_h : 256 - - crop: true - load_start_pos_h : 16 - load_start_pos_w : 16 - crop_size_w : 224 - crop_size_h: 224 - - min_chn_0 : 123.675 - min_chn_1 : 116.28 - min_chn_2 : 103.53 - var_reci_chn_0: 0.0171247538316637 - var_reci_chn_1: 0.0175070028011204 - var_reci_chn_2: 0.0174291938997821 - -} +aipp_op{ + aipp_mode:static + input_format : RGB888_U8 + + src_image_size_w : 256 + src_image_size_h : 256 + + crop: true + load_start_pos_h : 16 + load_start_pos_w : 16 + crop_size_w : 224 + crop_size_h: 224 + + min_chn_0 : 123.675 + min_chn_1 : 116.28 + min_chn_2 : 103.53 + var_reci_chn_0: 0.0171247538316637 + var_reci_chn_1: 0.0175070028011204 + var_reci_chn_2: 0.0174291938997821 + +} diff --git a/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/gen_dataset_info.py b/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/gen_dataset_info.py index be7ee43a39..9b9fa05d70 100644 --- a/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/gen_dataset_info.py +++ b/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/gen_dataset_info.py @@ -1,61 +1,61 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -# coding=UTF-8 - -import os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img[7:], width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img[7:], str(width), str(height)]) - file.write(content) - file.write('\n') - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' - get_jpg_info(file_path, info_name) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +# coding=UTF-8 + +import os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img[7:], width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img[7:], str(width), str(height)]) + file.write(content) + file.write('\n') + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' + get_jpg_info(file_path, info_name) diff --git a/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/imagenet_torch_preprocess.py b/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/imagenet_torch_preprocess.py index ab5ad9b2bc..9f0c2cf3b7 100644 --- a/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/imagenet_torch_preprocess.py +++ b/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/imagenet_torch_preprocess.py @@ -1,58 +1,58 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -# coding=UTF-8 - -import os -import sys -import cv2 -import numpy as np - - -def center_crop(img, out_height, out_width): - height, width, _ = img.shape - left = int((width - out_width) / 2) - right = int((width + out_width) / 2) - top = int((height - out_height) / 2) - bottom = int((height + out_height) / 2) - img = img[top:bottom, left:right] - return img - -def preprocess(file_path, bin_path): - in_files = os.listdir(file_path) - if not os.path.exists(bin_path): - os.makedirs(bin_path) - i = 0 - - resize_size = 256 - mean = [0.485, 0.456, 0.406] - std = [0.229, 0.224, 0.225] - - for file in in_files: - i = i + 1 - print(file, "===", i) - - img = cv2.imread(os.path.join(file_path, file)) - b, g, r = cv2.split(img) - - img = cv2.merge([r, g, b]) - img = cv2.resize(img, (resize_size, resize_size), interpolation=cv2.INTER_CUBIC) - img = np.array(img, dtype=np.int8) - - img.tofile(os.path.join(bin_path, file.split('.')[0] + '.bin')) - -if __name__ == "__main__": - file_path = os.path.abspath(sys.argv[1]) - bin_path = os.path.abspath(sys.argv[2]) - preprocess(file_path, bin_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +# coding=UTF-8 + +import os +import sys +import cv2 +import numpy as np + + +def center_crop(img, out_height, out_width): + height, width, _ = img.shape + left = int((width - out_width) / 2) + right = int((width + out_width) / 2) + top = int((height - out_height) / 2) + bottom = int((height + out_height) / 2) + img = img[top:bottom, left:right] + return img + +def preprocess(file_path, bin_path): + in_files = os.listdir(file_path) + if not os.path.exists(bin_path): + os.makedirs(bin_path) + i = 0 + + resize_size = 256 + mean = [0.485, 0.456, 0.406] + std = [0.229, 0.224, 0.225] + + for file in in_files: + i = i + 1 + print(file, "===", i) + + img = cv2.imread(os.path.join(file_path, file)) + b, g, r = cv2.split(img) + + img = cv2.merge([r, g, b]) + img = cv2.resize(img, (resize_size, resize_size), interpolation=cv2.INTER_CUBIC) + img = np.array(img, dtype=np.int8) + + img.tofile(os.path.join(bin_path, file.split('.')[0] + '.bin')) + +if __name__ == "__main__": + file_path = os.path.abspath(sys.argv[1]) + bin_path = os.path.abspath(sys.argv[2]) + preprocess(file_path, bin_path) diff --git a/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/vision_metric_ImageNet.py b/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/vision_metric_ImageNet.py index 82580bab7d..3ae9c66b2e 100644 --- a/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/vision_metric_ImageNet.py +++ b/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer/vision_metric_ImageNet.py @@ -1,184 +1,184 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -# coding=UTF-8 - -import os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = 0 - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - - resCnt = min(len(sort_index), topn) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) - print("Time used:", elapsed) - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +# coding=UTF-8 + +import os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = 0 + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + + resCnt = min(len(sort_index), topn) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) + print("Time used:", elapsed) + diff --git a/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/PytorchTransfer.py b/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/PytorchTransfer.py index 15680c59ff..15eeaaa895 100644 --- a/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/PytorchTransfer.py +++ b/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/PytorchTransfer.py @@ -1,47 +1,47 @@ -import sys -import os -import torch -import cv2 -from PIL import Image -import numpy as np -import torch.utils.data -import torchvision.transforms as transforms -from torch.autograd import Variable - - -def mobilenet_onnx(input_path: str, output_path: str): - img = cv2.imread(input_path) - img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) - pilimg = Image.fromarray(img) - normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], - std=[0.229, 0.224, 0.225]) - val_transformer = transforms.Compose([ - transforms.Scale(256), - transforms.CenterCrop(224), - transforms.ToTensor(), - normalize - ]) - - img_tensor = val_transformer(pilimg) - img_tensor = torch.unsqueeze(img_tensor, dim=0).float() - img_tensor = Variable(img_tensor, requires_grad=False) - img_tensor.reshape(1, 3, 224, 224) - img_numpy = img_tensor.cpu().numpy() - - img_name = input_path.split('/')[-1] - bin_name = img_name.split('.')[0] + ".bin" - output_fl = os.path.join(output_path, bin_name) - # save img_tensor as binary file for om inference input - img_numpy.tofile(output_fl) - - -if __name__ == "__main__": - input_img_dir = sys.argv[1] - output_img_dir = sys.argv[2] - images = os.listdir(input_img_dir) - for image_name in images: - if not image_name.endswith(".jpeg"): - continue - print("start to process image {}....".format(image_name)) - path_image = os.path.join(input_img_dir, image_name) - mobilenet_onnx(path_image, output_img_dir) +import sys +import os +import torch +import cv2 +from PIL import Image +import numpy as np +import torch.utils.data +import torchvision.transforms as transforms +from torch.autograd import Variable + + +def mobilenet_onnx(input_path: str, output_path: str): + img = cv2.imread(input_path) + img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + pilimg = Image.fromarray(img) + normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]) + val_transformer = transforms.Compose([ + transforms.Scale(256), + transforms.CenterCrop(224), + transforms.ToTensor(), + normalize + ]) + + img_tensor = val_transformer(pilimg) + img_tensor = torch.unsqueeze(img_tensor, dim=0).float() + img_tensor = Variable(img_tensor, requires_grad=False) + img_tensor.reshape(1, 3, 224, 224) + img_numpy = img_tensor.cpu().numpy() + + img_name = input_path.split('/')[-1] + bin_name = img_name.split('.')[0] + ".bin" + output_fl = os.path.join(output_path, bin_name) + # save img_tensor as binary file for om inference input + img_numpy.tofile(output_fl) + + +if __name__ == "__main__": + input_img_dir = sys.argv[1] + output_img_dir = sys.argv[2] + images = os.listdir(input_img_dir) + for image_name in images: + if not image_name.endswith(".jpeg"): + continue + print("start to process image {}....".format(image_name)) + path_image = os.path.join(input_img_dir, image_name) + mobilenet_onnx(path_image, output_img_dir) diff --git a/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/ReadMe.md b/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/ReadMe.md index 89d9026fb4..fd5be01630 100644 --- a/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/ReadMe.md +++ b/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/ReadMe.md @@ -1,48 +1,48 @@ -文件作用说明: - -1.auto_tune.sh:模型转换脚本,集成了auto tune功能,可以手动关闭 - -2.shufflenetv2.py:官方模型用于转换pth文件到onnx文件 - -3.shufflenetv2_wock_op_woct.py:NPU下训练模型用于转换pth文件到onnx文件 - -4.BinaryImageNet.info:ImageNet数据集信息,用于benchmark推理获取数据集 - -5.PytorchTransfer.py:数据集预处理脚本,通过均值方差处理归一化图片 - -6.val_label.txt:ImageNet数据集标签,用于验证推理结果 - -7.vision_metric_ImageNet.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy - -8.benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer - - - - - -推理端到端步骤: - -(1) 从Torchvision下载shufflenetv2模型或者指定自己训练好的pth文件路径,通过pth2onnx.py脚本转化为onnx模型 - - - -(2)运行auto_tune.sh脚本转换om模型,也可以选择手动关闭auto_tune - -本demo已提供调优完成的om模型 - - - -(3)用PytorchTransfer.py脚本处理数据集,参考BinaryImageNet.Info配置处理后的二进制数据集路径 - - - -(4)./benchmark.x86_64 -model_type=vision -batch_size=16 -device_id=0 -input_text_path=./BinaryImageNet.info -input_width=224 -input_height=224 -om_path=./shufflenetv2_bs16.om -useDvpp=False - -运行benchmark推理,结果保存在 ./result 目录下 - - - -(5)python3.7 vision_metric_ImageNet.py result/dumpOutput/ ./val_label.txt ./ result.json - -验证推理结果 - +文件作用说明: + +1.auto_tune.sh:模型转换脚本,集成了auto tune功能,可以手动关闭 + +2.shufflenetv2.py:官方模型用于转换pth文件到onnx文件 + +3.shufflenetv2_wock_op_woct.py:NPU下训练模型用于转换pth文件到onnx文件 + +4.BinaryImageNet.info:ImageNet数据集信息,用于benchmark推理获取数据集 + +5.PytorchTransfer.py:数据集预处理脚本,通过均值方差处理归一化图片 + +6.val_label.txt:ImageNet数据集标签,用于验证推理结果 + +7.vision_metric_ImageNet.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy + +8.benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer + + + + + +推理端到端步骤: + +(1) 从Torchvision下载shufflenetv2模型或者指定自己训练好的pth文件路径,通过pth2onnx.py脚本转化为onnx模型 + + + +(2)运行auto_tune.sh脚本转换om模型,也可以选择手动关闭auto_tune + +本demo已提供调优完成的om模型 + + + +(3)用PytorchTransfer.py脚本处理数据集,参考BinaryImageNet.Info配置处理后的二进制数据集路径 + + + +(4)./benchmark.x86_64 -model_type=vision -batch_size=16 -device_id=0 -input_text_path=./BinaryImageNet.info -input_width=224 -input_height=224 -om_path=./shufflenetv2_bs16.om -useDvpp=False + +运行benchmark推理,结果保存在 ./result 目录下 + + + +(5)python3.7 vision_metric_ImageNet.py result/dumpOutput/ ./val_label.txt ./ result.json + +验证推理结果 + diff --git a/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/shufflenetv2.py b/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/shufflenetv2.py index 4c107ef033..ecf11fda97 100644 --- a/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/shufflenetv2.py +++ b/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/shufflenetv2.py @@ -1,213 +1,213 @@ -import torch -import torch.nn as nn - - -__all__ = [ - 'ShuffleNetV2', 'shufflenet_v2_x0_5', 'shufflenet_v2_x1_0', - 'shufflenet_v2_x1_5', 'shufflenet_v2_x2_0' -] - -model_urls = { - 'shufflenetv2_x0.5': 'https://download.pytorch.org/models/shufflenetv2_x0.5-f707e7126e.pth', - 'shufflenetv2_x1.0': 'https://download.pytorch.org/models/shufflenetv2_x1-5666bf0f80.pth', - 'shufflenetv2_x1.5': None, - 'shufflenetv2_x2.0': None, -} - - -def channel_shuffle(x, groups): - # type: (torch.Tensor, int) -> torch.Tensor - batchsize, num_channels, height, width = x.data.size() - channels_per_group = num_channels // groups - - # reshape - x = x.view(batchsize, groups, - channels_per_group, height, width) - - x = torch.transpose(x, 1, 2).contiguous() - - # flatten - x = x.view(batchsize, -1, height, width) - - return x - - -class InvertedResidual(nn.Module): - def __init__(self, inp, oup, stride): - super(InvertedResidual, self).__init__() - - if not (1 <= stride <= 3): - raise ValueError('illegal stride value') - self.stride = stride - - branch_features = oup // 2 - assert (self.stride != 1) or (inp == branch_features << 1) - - if self.stride > 1: - self.branch1 = nn.Sequential( - self.depthwise_conv(inp, inp, kernel_size=3, stride=self.stride, padding=1), - nn.BatchNorm2d(inp), - nn.Conv2d(inp, branch_features, kernel_size=1, stride=1, padding=0, bias=False), - nn.BatchNorm2d(branch_features), - nn.ReLU(inplace=True), - ) - else: - self.branch1 = nn.Sequential() - - self.branch2 = nn.Sequential( - nn.Conv2d(inp if (self.stride > 1) else branch_features, - branch_features, kernel_size=1, stride=1, padding=0, bias=False), - nn.BatchNorm2d(branch_features), - nn.ReLU(inplace=True), - self.depthwise_conv(branch_features, branch_features, kernel_size=3, stride=self.stride, padding=1), - nn.BatchNorm2d(branch_features), - nn.Conv2d(branch_features, branch_features, kernel_size=1, stride=1, padding=0, bias=False), - nn.BatchNorm2d(branch_features), - nn.ReLU(inplace=True), - ) - - @staticmethod - def depthwise_conv(i, o, kernel_size, stride=1, padding=0, bias=False): - return nn.Conv2d(i, o, kernel_size, stride, padding, bias=bias, groups=i) - - def forward(self, x): - if self.stride == 1: - x1, x2 = x.chunk(2, dim=1) - out = torch.cat((x1, self.branch2(x2)), dim=1) - else: - out = torch.cat((self.branch1(x), self.branch2(x)), dim=1) - - out = channel_shuffle(out, 2) - - return out - - -class ShuffleNetV2(nn.Module): - def __init__(self, stages_repeats, stages_out_channels, num_classes=1000, inverted_residual=InvertedResidual): - super(ShuffleNetV2, self).__init__() - - if len(stages_repeats) != 3: - raise ValueError('expected stages_repeats as list of 3 positive ints') - if len(stages_out_channels) != 5: - raise ValueError('expected stages_out_channels as list of 5 positive ints') - self._stage_out_channels = stages_out_channels - - input_channels = 3 - output_channels = self._stage_out_channels[0] - self.conv1 = nn.Sequential( - nn.Conv2d(input_channels, output_channels, 3, 2, 1, bias=False), - nn.BatchNorm2d(output_channels), - nn.ReLU(inplace=True), - ) - input_channels = output_channels - - self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) - - stage_names = ['stage{}'.format(i) for i in [2, 3, 4]] - for name, repeats, output_channels in zip( - stage_names, stages_repeats, self._stage_out_channels[1:]): - seq = [inverted_residual(input_channels, output_channels, 2)] - for i in range(repeats - 1): - seq.append(inverted_residual(output_channels, output_channels, 1)) - setattr(self, name, nn.Sequential(*seq)) - input_channels = output_channels - - output_channels = self._stage_out_channels[-1] - self.conv5 = nn.Sequential( - nn.Conv2d(input_channels, output_channels, 1, 1, 0, bias=False), - nn.BatchNorm2d(output_channels), - nn.ReLU(inplace=True), - ) - - self.fc = nn.Linear(output_channels, num_classes) - - def _forward_impl(self, x): - # See note [TorchScript super()] - x = self.conv1(x) - x = self.maxpool(x) - x = self.stage2(x) - x = self.stage3(x) - x = self.stage4(x) - x = self.conv5(x) - x = x.mean([2, 3]) # globalpool - x = self.fc(x) - return x - - def forward(self, x): - return self._forward_impl(x) - - -def _shufflenetv2(arch, pretrained, progress, *args, **kwargs): - model = ShuffleNetV2(*args, **kwargs) - - if pretrained: - model_url = model_urls[arch] - if model_url is None: - raise NotImplementedError('pretrained {} is not supported as of now'.format(arch)) - else: - state_dict = load_state_dict_from_url(model_url, progress=progress) - model.load_state_dict(state_dict) - - return model - - -def shufflenet_v2_x0_5(pretrained=False, progress=True, **kwargs): - """ - Constructs a ShuffleNetV2 with 0.5x output channels, as described in - `"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" - `_. - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - progress (bool): If True, displays a progress bar of the download to stderr - """ - return _shufflenetv2('shufflenetv2_x0.5', pretrained, progress, - [4, 8, 4], [24, 48, 96, 192, 1024], **kwargs) - - -def shufflenet_v2_x1_0(pretrained=False, progress=True, **kwargs): - """ - Constructs a ShuffleNetV2 with 1.0x output channels, as described in - `"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" - `_. - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - progress (bool): If True, displays a progress bar of the download to stderr - """ - return _shufflenetv2('shufflenetv2_x1.0', pretrained, progress, - [4, 8, 4], [24, 116, 232, 464, 1024], **kwargs) - - -def shufflenet_v2_x1_5(pretrained=False, progress=True, **kwargs): - """ - Constructs a ShuffleNetV2 with 1.5x output channels, as described in - `"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" - `_. - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - progress (bool): If True, displays a progress bar of the download to stderr - """ - return _shufflenetv2('shufflenetv2_x1.5', pretrained, progress, - [4, 8, 4], [24, 176, 352, 704, 1024], **kwargs) - - -def shufflenet_v2_x2_0(pretrained=False, progress=True, **kwargs): - """ - Constructs a ShuffleNetV2 with 2.0x output channels, as described in - `"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" - `_. - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - progress (bool): If True, displays a progress bar of the download to stderr - """ - return _shufflenetv2('shufflenetv2_x2.0', pretrained, progress, - [4, 8, 4], [24, 244, 488, 976, 2048], **kwargs) - -if __name__ == '__main__': - dummy_input = torch.randn(1, 3, 224, 224) - model = shufflenet_v2_x1_0() - torch.onnx.export(model, dummy_input, "shufflenetv2.onnx", verbose=True,opset_version=11) - +import torch +import torch.nn as nn + + +__all__ = [ + 'ShuffleNetV2', 'shufflenet_v2_x0_5', 'shufflenet_v2_x1_0', + 'shufflenet_v2_x1_5', 'shufflenet_v2_x2_0' +] + +model_urls = { + 'shufflenetv2_x0.5': 'https://download.pytorch.org/models/shufflenetv2_x0.5-f707e7126e.pth', + 'shufflenetv2_x1.0': 'https://download.pytorch.org/models/shufflenetv2_x1-5666bf0f80.pth', + 'shufflenetv2_x1.5': None, + 'shufflenetv2_x2.0': None, +} + + +def channel_shuffle(x, groups): + # type: (torch.Tensor, int) -> torch.Tensor + batchsize, num_channels, height, width = x.data.size() + channels_per_group = num_channels // groups + + # reshape + x = x.view(batchsize, groups, + channels_per_group, height, width) + + x = torch.transpose(x, 1, 2).contiguous() + + # flatten + x = x.view(batchsize, -1, height, width) + + return x + + +class InvertedResidual(nn.Module): + def __init__(self, inp, oup, stride): + super(InvertedResidual, self).__init__() + + if not (1 <= stride <= 3): + raise ValueError('illegal stride value') + self.stride = stride + + branch_features = oup // 2 + assert (self.stride != 1) or (inp == branch_features << 1) + + if self.stride > 1: + self.branch1 = nn.Sequential( + self.depthwise_conv(inp, inp, kernel_size=3, stride=self.stride, padding=1), + nn.BatchNorm2d(inp), + nn.Conv2d(inp, branch_features, kernel_size=1, stride=1, padding=0, bias=False), + nn.BatchNorm2d(branch_features), + nn.ReLU(inplace=True), + ) + else: + self.branch1 = nn.Sequential() + + self.branch2 = nn.Sequential( + nn.Conv2d(inp if (self.stride > 1) else branch_features, + branch_features, kernel_size=1, stride=1, padding=0, bias=False), + nn.BatchNorm2d(branch_features), + nn.ReLU(inplace=True), + self.depthwise_conv(branch_features, branch_features, kernel_size=3, stride=self.stride, padding=1), + nn.BatchNorm2d(branch_features), + nn.Conv2d(branch_features, branch_features, kernel_size=1, stride=1, padding=0, bias=False), + nn.BatchNorm2d(branch_features), + nn.ReLU(inplace=True), + ) + + @staticmethod + def depthwise_conv(i, o, kernel_size, stride=1, padding=0, bias=False): + return nn.Conv2d(i, o, kernel_size, stride, padding, bias=bias, groups=i) + + def forward(self, x): + if self.stride == 1: + x1, x2 = x.chunk(2, dim=1) + out = torch.cat((x1, self.branch2(x2)), dim=1) + else: + out = torch.cat((self.branch1(x), self.branch2(x)), dim=1) + + out = channel_shuffle(out, 2) + + return out + + +class ShuffleNetV2(nn.Module): + def __init__(self, stages_repeats, stages_out_channels, num_classes=1000, inverted_residual=InvertedResidual): + super(ShuffleNetV2, self).__init__() + + if len(stages_repeats) != 3: + raise ValueError('expected stages_repeats as list of 3 positive ints') + if len(stages_out_channels) != 5: + raise ValueError('expected stages_out_channels as list of 5 positive ints') + self._stage_out_channels = stages_out_channels + + input_channels = 3 + output_channels = self._stage_out_channels[0] + self.conv1 = nn.Sequential( + nn.Conv2d(input_channels, output_channels, 3, 2, 1, bias=False), + nn.BatchNorm2d(output_channels), + nn.ReLU(inplace=True), + ) + input_channels = output_channels + + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + + stage_names = ['stage{}'.format(i) for i in [2, 3, 4]] + for name, repeats, output_channels in zip( + stage_names, stages_repeats, self._stage_out_channels[1:]): + seq = [inverted_residual(input_channels, output_channels, 2)] + for i in range(repeats - 1): + seq.append(inverted_residual(output_channels, output_channels, 1)) + setattr(self, name, nn.Sequential(*seq)) + input_channels = output_channels + + output_channels = self._stage_out_channels[-1] + self.conv5 = nn.Sequential( + nn.Conv2d(input_channels, output_channels, 1, 1, 0, bias=False), + nn.BatchNorm2d(output_channels), + nn.ReLU(inplace=True), + ) + + self.fc = nn.Linear(output_channels, num_classes) + + def _forward_impl(self, x): + # See note [TorchScript super()] + x = self.conv1(x) + x = self.maxpool(x) + x = self.stage2(x) + x = self.stage3(x) + x = self.stage4(x) + x = self.conv5(x) + x = x.mean([2, 3]) # globalpool + x = self.fc(x) + return x + + def forward(self, x): + return self._forward_impl(x) + + +def _shufflenetv2(arch, pretrained, progress, *args, **kwargs): + model = ShuffleNetV2(*args, **kwargs) + + if pretrained: + model_url = model_urls[arch] + if model_url is None: + raise NotImplementedError('pretrained {} is not supported as of now'.format(arch)) + else: + state_dict = load_state_dict_from_url(model_url, progress=progress) + model.load_state_dict(state_dict) + + return model + + +def shufflenet_v2_x0_5(pretrained=False, progress=True, **kwargs): + """ + Constructs a ShuffleNetV2 with 0.5x output channels, as described in + `"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" + `_. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _shufflenetv2('shufflenetv2_x0.5', pretrained, progress, + [4, 8, 4], [24, 48, 96, 192, 1024], **kwargs) + + +def shufflenet_v2_x1_0(pretrained=False, progress=True, **kwargs): + """ + Constructs a ShuffleNetV2 with 1.0x output channels, as described in + `"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" + `_. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _shufflenetv2('shufflenetv2_x1.0', pretrained, progress, + [4, 8, 4], [24, 116, 232, 464, 1024], **kwargs) + + +def shufflenet_v2_x1_5(pretrained=False, progress=True, **kwargs): + """ + Constructs a ShuffleNetV2 with 1.5x output channels, as described in + `"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" + `_. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _shufflenetv2('shufflenetv2_x1.5', pretrained, progress, + [4, 8, 4], [24, 176, 352, 704, 1024], **kwargs) + + +def shufflenet_v2_x2_0(pretrained=False, progress=True, **kwargs): + """ + Constructs a ShuffleNetV2 with 2.0x output channels, as described in + `"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" + `_. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _shufflenetv2('shufflenetv2_x2.0', pretrained, progress, + [4, 8, 4], [24, 244, 488, 976, 2048], **kwargs) + +if __name__ == '__main__': + dummy_input = torch.randn(1, 3, 224, 224) + model = shufflenet_v2_x1_0() + torch.onnx.export(model, dummy_input, "shufflenetv2.onnx", verbose=True,opset_version=11) + diff --git a/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/shufflenetv2_wock_op_woct.py b/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/shufflenetv2_wock_op_woct.py index 5982afc50e..e81cb5aebe 100644 --- a/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/shufflenetv2_wock_op_woct.py +++ b/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/shufflenetv2_wock_op_woct.py @@ -1,256 +1,256 @@ -import torch -import torch.nn as nn - -try: - from .utils import load_state_dict_from_url -except: - pass - -import numpy as np - -__all__ = [ - 'ShuffleNetV2', 'shufflenet_v2_x0_5', 'shufflenet_v2_x1_0', - 'shufflenet_v2_x1_5', 'shufflenet_v2_x2_0' -] - -model_urls = { - 'shufflenetv2_x0.5': 'https://download.pytorch.org/models/shufflenetv2_x0.5-f707e7126e.pth', - 'shufflenetv2_x1.0': 'https://download.pytorch.org/models/shufflenetv2_x1-5666bf0f80.pth', - 'shufflenetv2_x1.5': None, - 'shufflenetv2_x2.0': None, -} - - - -def IndexSelectFullImplementationforward(x1, x2, fp_index, bp_index1, bp_index2): - x = torch.cat([x1, x2], dim=1) - result = x.index_select(1, fp_index) - return result - -def IndexSelectHalfImplementationforward(x1, x2, fp_index1, fp_index2, bp_index1, bp_index2): - x = torch.cat([x1, x2], dim=1) - return x.index_select(1, fp_index1), x.index_select(1, fp_index2) - - -class Channel_Shuffle(nn.Module): - def __init__(self, inp, groups=2, split_shuffle=True): - super(Channel_Shuffle, self).__init__() - - self.split_shuffle = split_shuffle - self.group_len = inp // groups - self.out = np.array(list(range(inp))).reshape(groups, self.group_len).transpose(1, 0).flatten().tolist() - if self.split_shuffle: - self.register_buffer('fp_index1', torch.tensor(self.out[:self.group_len])) - self.register_buffer('fp_index2', torch.tensor(self.out[self.group_len:])) - else: - self.register_buffer('fp_index', torch.tensor(self.out)) - # self.register_buffer('bp_index', torch.tensor(list(range(0, inp, 2))+list(range(1,inp,2)))) - self.register_buffer('bp_index1', torch.tensor(list(range(0, inp, 2)))) - self.register_buffer('bp_index2', torch.tensor(list(range(1, inp, 2)))) - - def forward(self, x1, x2): - if self.split_shuffle: - return IndexSelectHalfImplementationforward(x1, x2, self.fp_index1, self.fp_index2, self.bp_index1, - self.bp_index2) - else: - return IndexSelectFullImplementationforward(x1, x2, self.fp_index, self.bp_index1, self.bp_index2) - - -class InvertedResidual(nn.Module): - def __init__(self, inp, oup, stride, split_shuffle=True): - super(InvertedResidual, self).__init__() - - if not (1 <= stride <= 3): - raise ValueError('illegal stride value') - self.stride = stride - - branch_features = oup // 2 - assert (self.stride != 1) or (inp == branch_features << 1) - - if self.stride > 1: - self.branch1 = nn.Sequential( - self.depthwise_conv(inp, inp, kernel_size=3, stride=self.stride, padding=1), - nn.BatchNorm2d(inp), - nn.Conv2d(inp, branch_features, kernel_size=1, stride=1, padding=0, bias=False), - nn.BatchNorm2d(branch_features), - nn.ReLU(inplace=True), - ) - else: - self.branch1 = nn.Sequential() - - self.branch2 = nn.Sequential( - nn.Conv2d(inp if (self.stride > 1) else branch_features, - branch_features, kernel_size=1, stride=1, padding=0, bias=False), - nn.BatchNorm2d(branch_features), - nn.ReLU(inplace=True), - self.depthwise_conv(branch_features, branch_features, kernel_size=3, stride=self.stride, padding=1), - nn.BatchNorm2d(branch_features), - nn.Conv2d(branch_features, branch_features, kernel_size=1, stride=1, padding=0, bias=False), - nn.BatchNorm2d(branch_features), - nn.ReLU(inplace=True), - ) - - if self.stride > 1: - self.channel_shuffle = Channel_Shuffle(inp=branch_features + branch_features, groups=2, - split_shuffle=split_shuffle) - else: - self.channel_shuffle = Channel_Shuffle(inp=inp, groups=2, split_shuffle=split_shuffle) - - @staticmethod - def depthwise_conv(i, o, kernel_size, stride=1, padding=0, bias=False): - return nn.Conv2d(i, o, kernel_size, stride, padding, bias=bias, groups=i) - - def forward(self, x): - if self.stride == 1: - x1, x2 = x - x2 = self.branch2(x2) - else: - x1 = self.branch1(x) - x2 = self.branch2(x) - - # out = channel_shuffle(out, 2) - out = self.channel_shuffle(x1, x2) - - return out - - -class ShuffleNetV2(nn.Module): - def __init__(self, stages_repeats, stages_out_channels, num_classes=1000, inverted_residual=InvertedResidual): - super(ShuffleNetV2, self).__init__() - - if len(stages_repeats) != 3: - raise ValueError('expected stages_repeats as list of 3 positive ints') - if len(stages_out_channels) != 5: - raise ValueError('expected stages_out_channels as list of 5 positive ints') - self._stage_out_channels = stages_out_channels - - input_channels = 3 - output_channels = self._stage_out_channels[0] - self.conv1 = nn.Sequential( - nn.Conv2d(input_channels, output_channels, 3, 2, 1, bias=False), - nn.BatchNorm2d(output_channels), - nn.ReLU(inplace=True), - ) - input_channels = output_channels - - self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) - - stage_names = ['stage{}'.format(i) for i in [2, 3, 4]] - for name, repeats, output_channels in zip( - stage_names, stages_repeats, self._stage_out_channels[1:]): - seq = [inverted_residual(input_channels, output_channels, 2)] - for i in range(repeats - 1): - if i == repeats - 2: - seq.append(inverted_residual(output_channels, output_channels, 1, split_shuffle=False)) - else: - seq.append(inverted_residual(output_channels, output_channels, 1)) - setattr(self, name, nn.Sequential(*seq)) - input_channels = output_channels - - output_channels = self._stage_out_channels[-1] - self.conv5 = nn.Sequential( - nn.Conv2d(input_channels, output_channels, 1, 1, 0, bias=False), - nn.BatchNorm2d(output_channels), - nn.ReLU(inplace=True), - ) - - self.fc = nn.Linear(output_channels, num_classes) - - self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) - - def _forward_impl(self, x): - - # See note [TorchScript super()] - x = self.conv1(x) - x = self.maxpool(x) - x = self.stage2(x) - x = self.stage3(x) - x = self.stage4(x) - x = self.conv5(x) - # x = x.mean([2, 3]) # globalpool - x = self.avgpool(x) - x = torch.flatten(x, 1) - - x = self.fc(x) - return x - - def forward(self, x): - return self._forward_impl(x) - - -def _shufflenetv2(arch, pretrained, progress, *args, **kwargs): - model = ShuffleNetV2(*args, **kwargs) - - if pretrained: - model_url = model_urls[arch] - if model_url is None: - raise NotImplementedError('pretrained {} is not supported as of now'.format(arch)) - else: - state_dict = load_state_dict_from_url(model_url, progress=progress) - model.load_state_dict(state_dict) - - return model - - -def shufflenet_v2_x0_5(pretrained=False, progress=True, **kwargs): - """ - Constructs a ShuffleNetV2 with 0.5x output channels, as described in - `"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" - `_. - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - progress (bool): If True, displays a progress bar of the download to stderr - """ - return _shufflenetv2('shufflenetv2_x0.5', pretrained, progress, - [4, 8, 4], [24, 48, 96, 192, 1024], **kwargs) - - -def shufflenet_v2_x1_0(pretrained=False, progress=True, **kwargs): - """ - Constructs a ShuffleNetV2 with 1.0x output channels, as described in - `"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" - `_. - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - progress (bool): If True, displays a progress bar of the download to stderr - """ - return _shufflenetv2('shufflenetv2_x1.0', pretrained, progress, - [4, 8, 4], [24, 116, 232, 464, 1024], **kwargs) - # return _shufflenetv2('shufflenetv2_x1.0', pretrained, progress, - # [4, 8, 4], [16, 128, 256, 464, 1024], **kwargs) - - -def shufflenet_v2_x1_5(pretrained=False, progress=True, **kwargs): - """ - Constructs a ShuffleNetV2 with 1.5x output channels, as described in - `"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" - `_. - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - progress (bool): If True, displays a progress bar of the download to stderr - """ - return _shufflenetv2('shufflenetv2_x1.5', pretrained, progress, - [4, 8, 4], [24, 176, 352, 704, 1024], **kwargs) - - -def shufflenet_v2_x2_0(pretrained=False, progress=True, **kwargs): - """ - Constructs a ShuffleNetV2 with 2.0x output channels, as described in - `"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" - `_. - - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - progress (bool): If True, displays a progress bar of the download to stderr - """ - return _shufflenetv2('shufflenetv2_x2.0', pretrained, progress, - [4, 8, 4], [24, 244, 488, 976, 2048], **kwargs) - - -if __name__ == '__main__': - dummy_input = torch.randn(1, 3, 224, 224) - model = shufflenet_v2_x1_0() - torch.onnx.export(model, dummy_input, "shufflenetv2.onnx", verbose=True,opset_version=11) +import torch +import torch.nn as nn + +try: + from .utils import load_state_dict_from_url +except: + pass + +import numpy as np + +__all__ = [ + 'ShuffleNetV2', 'shufflenet_v2_x0_5', 'shufflenet_v2_x1_0', + 'shufflenet_v2_x1_5', 'shufflenet_v2_x2_0' +] + +model_urls = { + 'shufflenetv2_x0.5': 'https://download.pytorch.org/models/shufflenetv2_x0.5-f707e7126e.pth', + 'shufflenetv2_x1.0': 'https://download.pytorch.org/models/shufflenetv2_x1-5666bf0f80.pth', + 'shufflenetv2_x1.5': None, + 'shufflenetv2_x2.0': None, +} + + + +def IndexSelectFullImplementationforward(x1, x2, fp_index, bp_index1, bp_index2): + x = torch.cat([x1, x2], dim=1) + result = x.index_select(1, fp_index) + return result + +def IndexSelectHalfImplementationforward(x1, x2, fp_index1, fp_index2, bp_index1, bp_index2): + x = torch.cat([x1, x2], dim=1) + return x.index_select(1, fp_index1), x.index_select(1, fp_index2) + + +class Channel_Shuffle(nn.Module): + def __init__(self, inp, groups=2, split_shuffle=True): + super(Channel_Shuffle, self).__init__() + + self.split_shuffle = split_shuffle + self.group_len = inp // groups + self.out = np.array(list(range(inp))).reshape(groups, self.group_len).transpose(1, 0).flatten().tolist() + if self.split_shuffle: + self.register_buffer('fp_index1', torch.tensor(self.out[:self.group_len])) + self.register_buffer('fp_index2', torch.tensor(self.out[self.group_len:])) + else: + self.register_buffer('fp_index', torch.tensor(self.out)) + # self.register_buffer('bp_index', torch.tensor(list(range(0, inp, 2))+list(range(1,inp,2)))) + self.register_buffer('bp_index1', torch.tensor(list(range(0, inp, 2)))) + self.register_buffer('bp_index2', torch.tensor(list(range(1, inp, 2)))) + + def forward(self, x1, x2): + if self.split_shuffle: + return IndexSelectHalfImplementationforward(x1, x2, self.fp_index1, self.fp_index2, self.bp_index1, + self.bp_index2) + else: + return IndexSelectFullImplementationforward(x1, x2, self.fp_index, self.bp_index1, self.bp_index2) + + +class InvertedResidual(nn.Module): + def __init__(self, inp, oup, stride, split_shuffle=True): + super(InvertedResidual, self).__init__() + + if not (1 <= stride <= 3): + raise ValueError('illegal stride value') + self.stride = stride + + branch_features = oup // 2 + assert (self.stride != 1) or (inp == branch_features << 1) + + if self.stride > 1: + self.branch1 = nn.Sequential( + self.depthwise_conv(inp, inp, kernel_size=3, stride=self.stride, padding=1), + nn.BatchNorm2d(inp), + nn.Conv2d(inp, branch_features, kernel_size=1, stride=1, padding=0, bias=False), + nn.BatchNorm2d(branch_features), + nn.ReLU(inplace=True), + ) + else: + self.branch1 = nn.Sequential() + + self.branch2 = nn.Sequential( + nn.Conv2d(inp if (self.stride > 1) else branch_features, + branch_features, kernel_size=1, stride=1, padding=0, bias=False), + nn.BatchNorm2d(branch_features), + nn.ReLU(inplace=True), + self.depthwise_conv(branch_features, branch_features, kernel_size=3, stride=self.stride, padding=1), + nn.BatchNorm2d(branch_features), + nn.Conv2d(branch_features, branch_features, kernel_size=1, stride=1, padding=0, bias=False), + nn.BatchNorm2d(branch_features), + nn.ReLU(inplace=True), + ) + + if self.stride > 1: + self.channel_shuffle = Channel_Shuffle(inp=branch_features + branch_features, groups=2, + split_shuffle=split_shuffle) + else: + self.channel_shuffle = Channel_Shuffle(inp=inp, groups=2, split_shuffle=split_shuffle) + + @staticmethod + def depthwise_conv(i, o, kernel_size, stride=1, padding=0, bias=False): + return nn.Conv2d(i, o, kernel_size, stride, padding, bias=bias, groups=i) + + def forward(self, x): + if self.stride == 1: + x1, x2 = x + x2 = self.branch2(x2) + else: + x1 = self.branch1(x) + x2 = self.branch2(x) + + # out = channel_shuffle(out, 2) + out = self.channel_shuffle(x1, x2) + + return out + + +class ShuffleNetV2(nn.Module): + def __init__(self, stages_repeats, stages_out_channels, num_classes=1000, inverted_residual=InvertedResidual): + super(ShuffleNetV2, self).__init__() + + if len(stages_repeats) != 3: + raise ValueError('expected stages_repeats as list of 3 positive ints') + if len(stages_out_channels) != 5: + raise ValueError('expected stages_out_channels as list of 5 positive ints') + self._stage_out_channels = stages_out_channels + + input_channels = 3 + output_channels = self._stage_out_channels[0] + self.conv1 = nn.Sequential( + nn.Conv2d(input_channels, output_channels, 3, 2, 1, bias=False), + nn.BatchNorm2d(output_channels), + nn.ReLU(inplace=True), + ) + input_channels = output_channels + + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + + stage_names = ['stage{}'.format(i) for i in [2, 3, 4]] + for name, repeats, output_channels in zip( + stage_names, stages_repeats, self._stage_out_channels[1:]): + seq = [inverted_residual(input_channels, output_channels, 2)] + for i in range(repeats - 1): + if i == repeats - 2: + seq.append(inverted_residual(output_channels, output_channels, 1, split_shuffle=False)) + else: + seq.append(inverted_residual(output_channels, output_channels, 1)) + setattr(self, name, nn.Sequential(*seq)) + input_channels = output_channels + + output_channels = self._stage_out_channels[-1] + self.conv5 = nn.Sequential( + nn.Conv2d(input_channels, output_channels, 1, 1, 0, bias=False), + nn.BatchNorm2d(output_channels), + nn.ReLU(inplace=True), + ) + + self.fc = nn.Linear(output_channels, num_classes) + + self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) + + def _forward_impl(self, x): + + # See note [TorchScript super()] + x = self.conv1(x) + x = self.maxpool(x) + x = self.stage2(x) + x = self.stage3(x) + x = self.stage4(x) + x = self.conv5(x) + # x = x.mean([2, 3]) # globalpool + x = self.avgpool(x) + x = torch.flatten(x, 1) + + x = self.fc(x) + return x + + def forward(self, x): + return self._forward_impl(x) + + +def _shufflenetv2(arch, pretrained, progress, *args, **kwargs): + model = ShuffleNetV2(*args, **kwargs) + + if pretrained: + model_url = model_urls[arch] + if model_url is None: + raise NotImplementedError('pretrained {} is not supported as of now'.format(arch)) + else: + state_dict = load_state_dict_from_url(model_url, progress=progress) + model.load_state_dict(state_dict) + + return model + + +def shufflenet_v2_x0_5(pretrained=False, progress=True, **kwargs): + """ + Constructs a ShuffleNetV2 with 0.5x output channels, as described in + `"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" + `_. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _shufflenetv2('shufflenetv2_x0.5', pretrained, progress, + [4, 8, 4], [24, 48, 96, 192, 1024], **kwargs) + + +def shufflenet_v2_x1_0(pretrained=False, progress=True, **kwargs): + """ + Constructs a ShuffleNetV2 with 1.0x output channels, as described in + `"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" + `_. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _shufflenetv2('shufflenetv2_x1.0', pretrained, progress, + [4, 8, 4], [24, 116, 232, 464, 1024], **kwargs) + # return _shufflenetv2('shufflenetv2_x1.0', pretrained, progress, + # [4, 8, 4], [16, 128, 256, 464, 1024], **kwargs) + + +def shufflenet_v2_x1_5(pretrained=False, progress=True, **kwargs): + """ + Constructs a ShuffleNetV2 with 1.5x output channels, as described in + `"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" + `_. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _shufflenetv2('shufflenetv2_x1.5', pretrained, progress, + [4, 8, 4], [24, 176, 352, 704, 1024], **kwargs) + + +def shufflenet_v2_x2_0(pretrained=False, progress=True, **kwargs): + """ + Constructs a ShuffleNetV2 with 2.0x output channels, as described in + `"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" + `_. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _shufflenetv2('shufflenetv2_x2.0', pretrained, progress, + [4, 8, 4], [24, 244, 488, 976, 2048], **kwargs) + + +if __name__ == '__main__': + dummy_input = torch.randn(1, 3, 224, 224) + model = shufflenet_v2_x1_0() + torch.onnx.export(model, dummy_input, "shufflenetv2.onnx", verbose=True,opset_version=11) diff --git a/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/vision_metric_ImageNet.py b/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/vision_metric_ImageNet.py index 7bba5f8346..f07c93617e 100644 --- a/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/vision_metric_ImageNet.py +++ b/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch/vision_metric_ImageNet.py @@ -1,173 +1,173 @@ -#coding = utf-8 -import os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = "" - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - #print(filepath) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - #print(img_gt_dict) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - # print(img_name) - #print(n_labels) - # print(gt) - - resCnt = min(len(sort_index), topn) - # print(sort_index[:5]) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - #print("***************") - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - #print("Top" + str(i + 1) + " accuracy" + ": " + str(round(accuracy[i] * 100, 2)) + '%') - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) - #print("Time used:", elapsed) +#coding = utf-8 +import os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = "" + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + #print(filepath) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + #print(img_gt_dict) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + # print(img_name) + #print(n_labels) + # print(gt) + + resCnt = min(len(sort_index), topn) + # print(sort_index[:5]) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + #print("***************") + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + #print("Top" + str(i + 1) + " accuracy" + ": " + str(round(accuracy[i] * 100, 2)) + '%') + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) + #print("Time used:", elapsed) diff --git a/ACL_PyTorch/built-in/cv/U2-Net_for_PyTorch/gen_dataset_info.py b/ACL_PyTorch/built-in/cv/U2-Net_for_PyTorch/gen_dataset_info.py index efe82aef07..3656966b4c 100644 --- a/ACL_PyTorch/built-in/cv/U2-Net_for_PyTorch/gen_dataset_info.py +++ b/ACL_PyTorch/built-in/cv/U2-Net_for_PyTorch/gen_dataset_info.py @@ -1,65 +1,65 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(fpath, info_n, width, height): - ''' - Describe - ''' - bin_images = glob(os.path.join(fpath, '*.bin')) - with open(info_n, 'w') as f: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - f.write(content) - f.write('\n') - - -def get_jpg_info(fpath, info_n): - ''' - Describe - ''' - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(fpath, '*.' + extension))) - with open(info_n, 'w') as f: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - f.write(content) - f.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - Width = sys.argv[4] - Height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, Width, Height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' - get_jpg_info(file_path, info_name) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(fpath, info_n, width, height): + ''' + Describe + ''' + bin_images = glob(os.path.join(fpath, '*.bin')) + with open(info_n, 'w') as f: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + f.write(content) + f.write('\n') + + +def get_jpg_info(fpath, info_n): + ''' + Describe + ''' + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(fpath, '*.' + extension))) + with open(info_n, 'w') as f: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + f.write(content) + f.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + Width = sys.argv[4] + Height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, Width, Height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' + get_jpg_info(file_path, info_name) diff --git a/ACL_PyTorch/built-in/cv/Vgg16_for_Pytorch/ReadMe.md b/ACL_PyTorch/built-in/cv/Vgg16_for_Pytorch/ReadMe.md index 740e2ce6ae..0e9f686545 100644 --- a/ACL_PyTorch/built-in/cv/Vgg16_for_Pytorch/ReadMe.md +++ b/ACL_PyTorch/built-in/cv/Vgg16_for_Pytorch/ReadMe.md @@ -1,48 +1,48 @@ -文件作用说明: - -1.auto_tune.sh:模型转换脚本,集成了auto tune功能,可以手动关闭 - -2.pth2onnx.py:用于转换pth文件到onnx文件 - -3.pthtar2onnx.py:用于转换pth.tar文件到onnx文件 - -4.BinaryImageNet.info:ImageNet数据集信息,用于benchmark推理获取数据集 - -5.PytorchTransfer.py:数据集预处理脚本,通过均值方差处理归一化图片 - -6.val_label.txt:ImageNet数据集标签,用于验证推理结果 - -7.vision_metric_ImageNet.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy - -8.benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer - - - - - -推理端到端步骤: - -(1) 从Torchvision下载resnet50模型或者指定自己训练好的pth文件路径,通过pth2onnx.py脚本转化为onnx模型 - - - -(2)运行auto_tune.sh脚本转换om模型,也可以选择手动关闭auto_tune - -本demo已提供调优完成的om模型 - - - -(3)用PytorchTransfer.py脚本处理数据集,参考BinaryImageNet.Info配置处理后的二进制数据集路径 - - - -(4)./benchmark.x86_64 -model_type=vision -batch_size=16 -device_id=0 -input_text_path=./BinaryImageNet.info -input_width=224 -input_height=224 -om_path=./resnet50_pytorch.om -useDvpp=False - -运行benchmark推理,结果保存在 ./result 目录下 - - - -(5)python3.7 vision_metric_ImageNet.py result/dumpOutput/ ./val_label.txt ./ result.json - -验证推理结果 - +文件作用说明: + +1.auto_tune.sh:模型转换脚本,集成了auto tune功能,可以手动关闭 + +2.pth2onnx.py:用于转换pth文件到onnx文件 + +3.pthtar2onnx.py:用于转换pth.tar文件到onnx文件 + +4.BinaryImageNet.info:ImageNet数据集信息,用于benchmark推理获取数据集 + +5.PytorchTransfer.py:数据集预处理脚本,通过均值方差处理归一化图片 + +6.val_label.txt:ImageNet数据集标签,用于验证推理结果 + +7.vision_metric_ImageNet.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy + +8.benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer + + + + + +推理端到端步骤: + +(1) 从Torchvision下载resnet50模型或者指定自己训练好的pth文件路径,通过pth2onnx.py脚本转化为onnx模型 + + + +(2)运行auto_tune.sh脚本转换om模型,也可以选择手动关闭auto_tune + +本demo已提供调优完成的om模型 + + + +(3)用PytorchTransfer.py脚本处理数据集,参考BinaryImageNet.Info配置处理后的二进制数据集路径 + + + +(4)./benchmark.x86_64 -model_type=vision -batch_size=16 -device_id=0 -input_text_path=./BinaryImageNet.info -input_width=224 -input_height=224 -om_path=./resnet50_pytorch.om -useDvpp=False + +运行benchmark推理,结果保存在 ./result 目录下 + + + +(5)python3.7 vision_metric_ImageNet.py result/dumpOutput/ ./val_label.txt ./ result.json + +验证推理结果 + diff --git a/ACL_PyTorch/built-in/cv/Vgg16_for_Pytorch/get_info.py b/ACL_PyTorch/built-in/cv/Vgg16_for_Pytorch/get_info.py index da181d8d03..c68e7705e4 100644 --- a/ACL_PyTorch/built-in/cv/Vgg16_for_Pytorch/get_info.py +++ b/ACL_PyTorch/built-in/cv/Vgg16_for_Pytorch/get_info.py @@ -1,16 +1,16 @@ -import os -import sys -from glob import glob - -file_path = sys.argv[1] -info_name = sys.argv[2] -width = sys.argv[3] -height = sys.argv[4] - -bin_images = glob(os.path.join(file_path, '*')) - -with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') +import os +import sys +from glob import glob + +file_path = sys.argv[1] +info_name = sys.argv[2] +width = sys.argv[3] +height = sys.argv[4] + +bin_images = glob(os.path.join(file_path, '*')) + +with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') diff --git a/ACL_PyTorch/built-in/cv/Vgg16_for_Pytorch/preprocess_vgg_pytorch.py b/ACL_PyTorch/built-in/cv/Vgg16_for_Pytorch/preprocess_vgg_pytorch.py index a36b47f2fb..1ac2a414d2 100644 --- a/ACL_PyTorch/built-in/cv/Vgg16_for_Pytorch/preprocess_vgg_pytorch.py +++ b/ACL_PyTorch/built-in/cv/Vgg16_for_Pytorch/preprocess_vgg_pytorch.py @@ -1,83 +1,83 @@ -import os -import sys -import numpy as np -from PIL import Image - - -def resize(img, size, interpolation=Image.BILINEAR): - r"""Resize the input PIL Image to the given size. - - Args: - img (PIL Image): Image to be resized. - size (sequence or int): Desired output size. If size is a sequence like - (h, w), the output size will be matched to this. If size is an int, - the smaller edge of the image will be matched to this number maintaining - the aspect ratio. i.e, if height > width, then image will be rescaled to - :math:`\left(\text{size} \times \frac{\text{height}}{\text{width}}, \text{size}\right)` - interpolation (int, optional): Desired interpolation. Default is - ``PIL.Image.BILINEAR`` - - Returns: - PIL Image: Resized image. - """ - - if isinstance(size, int): - w, h = img.size - if (w <= h and w == size) or (h <= w and h == size): - return img - if w < h: - ow = size - oh = int(size * h / w) - return img.resize((ow, oh), interpolation) - else: - oh = size - ow = int(size * w / h) - return img.resize((ow, oh), interpolation) - else: - return img.resize(size[::-1], interpolation) - - -def center_crop(img, out_height, out_width): - height, width, _ = img.shape - left = int((width - out_width) / 2) - right = int((width + out_width) / 2) - top = int((height - out_height) / 2) - bottom = int((height + out_height) / 2) - img = img[top:bottom, left:right] - return img - - -def deepmar_onnx(file_path, bin_path): - in_files = os.listdir(file_path) - if not os.path.exists(bin_path): - os.makedirs(bin_path) - i = 0 - input_size = (256, 256) - mean = [0.485, 0.456, 0.406] - std = [0.229, 0.224, 0.225] - for file in in_files: - i = i + 1 - print(file, "====", i) - img = Image.open(os.path.join(file_path, file)).convert('RGB') - img = resize(img, input_size) # transforms.Resize(256) - img = np.array(img, dtype=np.float32) - img = center_crop(img, 224, 224) # transforms.CenterCrop(224) - - img = img / 255. # transforms.ToTensor() - - # 均值方差 - img[..., 0] -= mean[0] - img[..., 1] -= mean[1] - img[..., 2] -= mean[2] - img[..., 0] /= std[0] - img[..., 1] /= std[1] - img[..., 2] /= std[2] - - img = img.transpose(2, 0, 1) # HWC -> CHW - img.tofile(os.path.join(bin_path, file.split('.')[0] + '.bin')) - - -if __name__ == "__main__": - file_path = os.path.abspath(sys.argv[1]) - bin_path = os.path.abspath(sys.argv[2]) - deepmar_onnx(file_path, bin_path) +import os +import sys +import numpy as np +from PIL import Image + + +def resize(img, size, interpolation=Image.BILINEAR): + r"""Resize the input PIL Image to the given size. + + Args: + img (PIL Image): Image to be resized. + size (sequence or int): Desired output size. If size is a sequence like + (h, w), the output size will be matched to this. If size is an int, + the smaller edge of the image will be matched to this number maintaining + the aspect ratio. i.e, if height > width, then image will be rescaled to + :math:`\left(\text{size} \times \frac{\text{height}}{\text{width}}, \text{size}\right)` + interpolation (int, optional): Desired interpolation. Default is + ``PIL.Image.BILINEAR`` + + Returns: + PIL Image: Resized image. + """ + + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def center_crop(img, out_height, out_width): + height, width, _ = img.shape + left = int((width - out_width) / 2) + right = int((width + out_width) / 2) + top = int((height - out_height) / 2) + bottom = int((height + out_height) / 2) + img = img[top:bottom, left:right] + return img + + +def deepmar_onnx(file_path, bin_path): + in_files = os.listdir(file_path) + if not os.path.exists(bin_path): + os.makedirs(bin_path) + i = 0 + input_size = (256, 256) + mean = [0.485, 0.456, 0.406] + std = [0.229, 0.224, 0.225] + for file in in_files: + i = i + 1 + print(file, "====", i) + img = Image.open(os.path.join(file_path, file)).convert('RGB') + img = resize(img, input_size) # transforms.Resize(256) + img = np.array(img, dtype=np.float32) + img = center_crop(img, 224, 224) # transforms.CenterCrop(224) + + img = img / 255. # transforms.ToTensor() + + # 均值方差 + img[..., 0] -= mean[0] + img[..., 1] -= mean[1] + img[..., 2] -= mean[2] + img[..., 0] /= std[0] + img[..., 1] /= std[1] + img[..., 2] /= std[2] + + img = img.transpose(2, 0, 1) # HWC -> CHW + img.tofile(os.path.join(bin_path, file.split('.')[0] + '.bin')) + + +if __name__ == "__main__": + file_path = os.path.abspath(sys.argv[1]) + bin_path = os.path.abspath(sys.argv[2]) + deepmar_onnx(file_path, bin_path) diff --git a/ACL_PyTorch/built-in/cv/Vgg16_for_Pytorch/vision_metric_ImageNet.py b/ACL_PyTorch/built-in/cv/Vgg16_for_Pytorch/vision_metric_ImageNet.py index 7bba5f8346..f07c93617e 100644 --- a/ACL_PyTorch/built-in/cv/Vgg16_for_Pytorch/vision_metric_ImageNet.py +++ b/ACL_PyTorch/built-in/cv/Vgg16_for_Pytorch/vision_metric_ImageNet.py @@ -1,173 +1,173 @@ -#coding = utf-8 -import os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = "" - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - #print(filepath) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - #print(img_gt_dict) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - # print(img_name) - #print(n_labels) - # print(gt) - - resCnt = min(len(sort_index), topn) - # print(sort_index[:5]) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - #print("***************") - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - #print("Top" + str(i + 1) + " accuracy" + ": " + str(round(accuracy[i] * 100, 2)) + '%') - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) - #print("Time used:", elapsed) +#coding = utf-8 +import os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = "" + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + #print(filepath) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + #print(img_gt_dict) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + # print(img_name) + #print(n_labels) + # print(gt) + + resCnt = min(len(sort_index), topn) + # print(sort_index[:5]) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + #print("***************") + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + #print("Top" + str(i + 1) + " accuracy" + ": " + str(round(accuracy[i] * 100, 2)) + '%') + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) + #print("Time used:", elapsed) diff --git a/ACL_PyTorch/built-in/cv/Vgg19_for_Pytorch/ReadMe.md b/ACL_PyTorch/built-in/cv/Vgg19_for_Pytorch/ReadMe.md index 740e2ce6ae..0e9f686545 100644 --- a/ACL_PyTorch/built-in/cv/Vgg19_for_Pytorch/ReadMe.md +++ b/ACL_PyTorch/built-in/cv/Vgg19_for_Pytorch/ReadMe.md @@ -1,48 +1,48 @@ -文件作用说明: - -1.auto_tune.sh:模型转换脚本,集成了auto tune功能,可以手动关闭 - -2.pth2onnx.py:用于转换pth文件到onnx文件 - -3.pthtar2onnx.py:用于转换pth.tar文件到onnx文件 - -4.BinaryImageNet.info:ImageNet数据集信息,用于benchmark推理获取数据集 - -5.PytorchTransfer.py:数据集预处理脚本,通过均值方差处理归一化图片 - -6.val_label.txt:ImageNet数据集标签,用于验证推理结果 - -7.vision_metric_ImageNet.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy - -8.benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer - - - - - -推理端到端步骤: - -(1) 从Torchvision下载resnet50模型或者指定自己训练好的pth文件路径,通过pth2onnx.py脚本转化为onnx模型 - - - -(2)运行auto_tune.sh脚本转换om模型,也可以选择手动关闭auto_tune - -本demo已提供调优完成的om模型 - - - -(3)用PytorchTransfer.py脚本处理数据集,参考BinaryImageNet.Info配置处理后的二进制数据集路径 - - - -(4)./benchmark.x86_64 -model_type=vision -batch_size=16 -device_id=0 -input_text_path=./BinaryImageNet.info -input_width=224 -input_height=224 -om_path=./resnet50_pytorch.om -useDvpp=False - -运行benchmark推理,结果保存在 ./result 目录下 - - - -(5)python3.7 vision_metric_ImageNet.py result/dumpOutput/ ./val_label.txt ./ result.json - -验证推理结果 - +文件作用说明: + +1.auto_tune.sh:模型转换脚本,集成了auto tune功能,可以手动关闭 + +2.pth2onnx.py:用于转换pth文件到onnx文件 + +3.pthtar2onnx.py:用于转换pth.tar文件到onnx文件 + +4.BinaryImageNet.info:ImageNet数据集信息,用于benchmark推理获取数据集 + +5.PytorchTransfer.py:数据集预处理脚本,通过均值方差处理归一化图片 + +6.val_label.txt:ImageNet数据集标签,用于验证推理结果 + +7.vision_metric_ImageNet.py:验证推理结果脚本,比对benchmark输出的分类结果和标签,给出Accuracy + +8.benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer + + + + + +推理端到端步骤: + +(1) 从Torchvision下载resnet50模型或者指定自己训练好的pth文件路径,通过pth2onnx.py脚本转化为onnx模型 + + + +(2)运行auto_tune.sh脚本转换om模型,也可以选择手动关闭auto_tune + +本demo已提供调优完成的om模型 + + + +(3)用PytorchTransfer.py脚本处理数据集,参考BinaryImageNet.Info配置处理后的二进制数据集路径 + + + +(4)./benchmark.x86_64 -model_type=vision -batch_size=16 -device_id=0 -input_text_path=./BinaryImageNet.info -input_width=224 -input_height=224 -om_path=./resnet50_pytorch.om -useDvpp=False + +运行benchmark推理,结果保存在 ./result 目录下 + + + +(5)python3.7 vision_metric_ImageNet.py result/dumpOutput/ ./val_label.txt ./ result.json + +验证推理结果 + diff --git a/ACL_PyTorch/built-in/cv/Vgg19_for_Pytorch/get_info.py b/ACL_PyTorch/built-in/cv/Vgg19_for_Pytorch/get_info.py index da181d8d03..c68e7705e4 100644 --- a/ACL_PyTorch/built-in/cv/Vgg19_for_Pytorch/get_info.py +++ b/ACL_PyTorch/built-in/cv/Vgg19_for_Pytorch/get_info.py @@ -1,16 +1,16 @@ -import os -import sys -from glob import glob - -file_path = sys.argv[1] -info_name = sys.argv[2] -width = sys.argv[3] -height = sys.argv[4] - -bin_images = glob(os.path.join(file_path, '*')) - -with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') +import os +import sys +from glob import glob + +file_path = sys.argv[1] +info_name = sys.argv[2] +width = sys.argv[3] +height = sys.argv[4] + +bin_images = glob(os.path.join(file_path, '*')) + +with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') diff --git a/ACL_PyTorch/built-in/cv/Vgg19_for_Pytorch/preprocess_vgg_pytorch.py b/ACL_PyTorch/built-in/cv/Vgg19_for_Pytorch/preprocess_vgg_pytorch.py index a36b47f2fb..1ac2a414d2 100644 --- a/ACL_PyTorch/built-in/cv/Vgg19_for_Pytorch/preprocess_vgg_pytorch.py +++ b/ACL_PyTorch/built-in/cv/Vgg19_for_Pytorch/preprocess_vgg_pytorch.py @@ -1,83 +1,83 @@ -import os -import sys -import numpy as np -from PIL import Image - - -def resize(img, size, interpolation=Image.BILINEAR): - r"""Resize the input PIL Image to the given size. - - Args: - img (PIL Image): Image to be resized. - size (sequence or int): Desired output size. If size is a sequence like - (h, w), the output size will be matched to this. If size is an int, - the smaller edge of the image will be matched to this number maintaining - the aspect ratio. i.e, if height > width, then image will be rescaled to - :math:`\left(\text{size} \times \frac{\text{height}}{\text{width}}, \text{size}\right)` - interpolation (int, optional): Desired interpolation. Default is - ``PIL.Image.BILINEAR`` - - Returns: - PIL Image: Resized image. - """ - - if isinstance(size, int): - w, h = img.size - if (w <= h and w == size) or (h <= w and h == size): - return img - if w < h: - ow = size - oh = int(size * h / w) - return img.resize((ow, oh), interpolation) - else: - oh = size - ow = int(size * w / h) - return img.resize((ow, oh), interpolation) - else: - return img.resize(size[::-1], interpolation) - - -def center_crop(img, out_height, out_width): - height, width, _ = img.shape - left = int((width - out_width) / 2) - right = int((width + out_width) / 2) - top = int((height - out_height) / 2) - bottom = int((height + out_height) / 2) - img = img[top:bottom, left:right] - return img - - -def deepmar_onnx(file_path, bin_path): - in_files = os.listdir(file_path) - if not os.path.exists(bin_path): - os.makedirs(bin_path) - i = 0 - input_size = (256, 256) - mean = [0.485, 0.456, 0.406] - std = [0.229, 0.224, 0.225] - for file in in_files: - i = i + 1 - print(file, "====", i) - img = Image.open(os.path.join(file_path, file)).convert('RGB') - img = resize(img, input_size) # transforms.Resize(256) - img = np.array(img, dtype=np.float32) - img = center_crop(img, 224, 224) # transforms.CenterCrop(224) - - img = img / 255. # transforms.ToTensor() - - # 均值方差 - img[..., 0] -= mean[0] - img[..., 1] -= mean[1] - img[..., 2] -= mean[2] - img[..., 0] /= std[0] - img[..., 1] /= std[1] - img[..., 2] /= std[2] - - img = img.transpose(2, 0, 1) # HWC -> CHW - img.tofile(os.path.join(bin_path, file.split('.')[0] + '.bin')) - - -if __name__ == "__main__": - file_path = os.path.abspath(sys.argv[1]) - bin_path = os.path.abspath(sys.argv[2]) - deepmar_onnx(file_path, bin_path) +import os +import sys +import numpy as np +from PIL import Image + + +def resize(img, size, interpolation=Image.BILINEAR): + r"""Resize the input PIL Image to the given size. + + Args: + img (PIL Image): Image to be resized. + size (sequence or int): Desired output size. If size is a sequence like + (h, w), the output size will be matched to this. If size is an int, + the smaller edge of the image will be matched to this number maintaining + the aspect ratio. i.e, if height > width, then image will be rescaled to + :math:`\left(\text{size} \times \frac{\text{height}}{\text{width}}, \text{size}\right)` + interpolation (int, optional): Desired interpolation. Default is + ``PIL.Image.BILINEAR`` + + Returns: + PIL Image: Resized image. + """ + + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def center_crop(img, out_height, out_width): + height, width, _ = img.shape + left = int((width - out_width) / 2) + right = int((width + out_width) / 2) + top = int((height - out_height) / 2) + bottom = int((height + out_height) / 2) + img = img[top:bottom, left:right] + return img + + +def deepmar_onnx(file_path, bin_path): + in_files = os.listdir(file_path) + if not os.path.exists(bin_path): + os.makedirs(bin_path) + i = 0 + input_size = (256, 256) + mean = [0.485, 0.456, 0.406] + std = [0.229, 0.224, 0.225] + for file in in_files: + i = i + 1 + print(file, "====", i) + img = Image.open(os.path.join(file_path, file)).convert('RGB') + img = resize(img, input_size) # transforms.Resize(256) + img = np.array(img, dtype=np.float32) + img = center_crop(img, 224, 224) # transforms.CenterCrop(224) + + img = img / 255. # transforms.ToTensor() + + # 均值方差 + img[..., 0] -= mean[0] + img[..., 1] -= mean[1] + img[..., 2] -= mean[2] + img[..., 0] /= std[0] + img[..., 1] /= std[1] + img[..., 2] /= std[2] + + img = img.transpose(2, 0, 1) # HWC -> CHW + img.tofile(os.path.join(bin_path, file.split('.')[0] + '.bin')) + + +if __name__ == "__main__": + file_path = os.path.abspath(sys.argv[1]) + bin_path = os.path.abspath(sys.argv[2]) + deepmar_onnx(file_path, bin_path) diff --git a/ACL_PyTorch/built-in/cv/Vgg19_for_Pytorch/vision_metric_ImageNet.py b/ACL_PyTorch/built-in/cv/Vgg19_for_Pytorch/vision_metric_ImageNet.py index 7bba5f8346..f07c93617e 100644 --- a/ACL_PyTorch/built-in/cv/Vgg19_for_Pytorch/vision_metric_ImageNet.py +++ b/ACL_PyTorch/built-in/cv/Vgg19_for_Pytorch/vision_metric_ImageNet.py @@ -1,173 +1,173 @@ -#coding = utf-8 -import os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = "" - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - #print(filepath) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - #print(img_gt_dict) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - # print(img_name) - #print(n_labels) - # print(gt) - - resCnt = min(len(sort_index), topn) - # print(sort_index[:5]) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - #print("***************") - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - #print("Top" + str(i + 1) + " accuracy" + ": " + str(round(accuracy[i] * 100, 2)) + '%') - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) - #print("Time used:", elapsed) +#coding = utf-8 +import os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = "" + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + #print(filepath) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + #print(img_gt_dict) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + # print(img_name) + #print(n_labels) + # print(gt) + + resCnt = min(len(sort_index), topn) + # print(sort_index[:5]) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + #print("***************") + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + #print("Top" + str(i + 1) + " accuracy" + ": " + str(round(accuracy[i] * 100, 2)) + '%') + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) + #print("Time used:", elapsed) diff --git a/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/LICENSE b/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/LICENSE index df2c2f2c3e..c8ec075d5b 100644 --- a/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/LICENSE +++ b/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/LICENSE @@ -1,203 +1,203 @@ -Copyright 2018-2019 Open-MMLab. All rights reserved. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018-2019 Open-MMLab. - - 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 +Copyright 2018-2019 Open-MMLab. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2019 Open-MMLab. + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/README.md b/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/README.md index a66e9ee510..c7ab4c279c 100644 --- a/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/README.md +++ b/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/README.md @@ -1,112 +1,112 @@ -# yolact_edge模型推理指导 - -- [yolact_edge模型推理指导](#yolact_edge模型推理指导) - - [1 文件说明](#1-文件说明) - - [2 环境准备](#2-环境准备) - - [2.1 安装依赖](#21-安装依赖) - - [2.2 文件下载](#22-文件下载) - - [2.3 文件拷贝](#23-文件拷贝) - - [2.4 设置环境变量](#24-设置环境变量) - - [3 端到端推理步骤](#3-端到端推理步骤) - - [3.1 pth导出onnx](#31-pth导出onnx) - - [3.2 利用ATC工具转换为om模型](#32-利用atc工具转换为om模型) - - [3.3 om模型推理](#33-om模型推理) - - [3.4 纯推理性能获取](#34-纯推理性能获取) - - [4 评测结果](#4-评测结果) - ------- - -## 1 文件说明 -``` -yolact_edge_for_Pytorch - ├── env.sh 设置环境变量 - ├── pth2onnx.py pytorch模型导出onnx模型 - ├── atc.sh onnx模型转om - ├── yolact_edge.diff 补丁文件 - └── acl_net.py PyACL推理工具代码 -``` - -## 2 环境准备 - -### 2.1 安装依赖 - -根据pytorch官网教程安装1.10.0版本的PyTorch -```shell -pip install torch==1.10.0+cpu torchvision==0.11.1+cpu torchaudio==0.10.0+cpu -pip install -r requirements.txt -pip install git+https://github.com/haotian-liu/cocoapi.git#"egg=pycocotools&subdirectory=PythonAPI" -``` - -### 2.2 文件下载 -- [yolact_edge_Pytorch源码下载](https://github.com/haotian-liu/yolact_edge) - - ```shell - git clone git@github.com:haotian-liu/yolact_edge.git - cd yolact_edge - git reset a9a00281b33b3ac90253a4939773308a8f95e21d --hard - git apply yolact_edge.diff - ``` - -- 权重下载 - - 创建 `weights` 目录,并将下载的权重文件 `yolact_edge_resnet50_54_800000.pth` 拷贝到 `weights` 目录下。 - 可参见[yolact_edge_Pytorch主页](https://github.com/haotian-liu/yolact_edge)说明下载权重 - -- 数据集下载 - - om推理采用COCO2017数据集的验证集进行精度评估。将下载好的数据集拷贝到 `data/coco` 目录下,data目录中的文件结构如下所示。数据集下载可以网页搜索 - ```shell - data - └── coco - ├── annotations - ├── images - ├── scripts - ├── yolact_edge_example_1.gif - ├── yolact_edge_example_2.gif - ├── yolact_edge_example_3.gif - ``` - -### 2.3 文件拷贝 -拷贝env.sh,pth2onnx.py,atc.sh,acl_net.py文件到yolact_edge目录下。 - - -### 2.4 设置环境变量 -```shell -source env.sh -``` - -## 3 端到端推理步骤 - -### 3.1 pth导出onnx -```python -python3.7 pth2onnx.py \ - --config=yolact_edge_resnet50_config \ - --trained_model=./weights/yolact_edge_resnet50_54_800000.pth -``` - -### 3.2 利用ATC工具转换为om模型 -```shell -bash atc.sh yolact_edge.onnx yolact_edge -``` - -### 3.3 om模型推理 -```python -python3.7 eval.py \ - --config=yolact_edge_resnet50_config \ - --trained_model=./weights/yolact_edge_resnet50_54_800000.pth \ - --cuda=False \ - --disable_tensorrt -``` - -### 3.4 纯推理性能获取 - -下载 [benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) 并拷贝到当前目录 -```shell -./benchmark.${arch} -device_id=0 -batch_size=1 -om_path=./yolact_edge.om -round=20 -``` - -## 4 评测结果 - -| 模型 | pth精度 | 310离线推理精度 | 基准性能 | 310性能 | -| --------------- | -------- | --------------- | -------- | ------- | -| yolact_edge | [mAP:27.0](https://github.com/haotian-liu/yolact_edge) | mAP:27.6 | 167fps | 157fps | +# yolact_edge模型推理指导 + +- [yolact_edge模型推理指导](#yolact_edge模型推理指导) + - [1 文件说明](#1-文件说明) + - [2 环境准备](#2-环境准备) + - [2.1 安装依赖](#21-安装依赖) + - [2.2 文件下载](#22-文件下载) + - [2.3 文件拷贝](#23-文件拷贝) + - [2.4 设置环境变量](#24-设置环境变量) + - [3 端到端推理步骤](#3-端到端推理步骤) + - [3.1 pth导出onnx](#31-pth导出onnx) + - [3.2 利用ATC工具转换为om模型](#32-利用atc工具转换为om模型) + - [3.3 om模型推理](#33-om模型推理) + - [3.4 纯推理性能获取](#34-纯推理性能获取) + - [4 评测结果](#4-评测结果) + +------ + +## 1 文件说明 +``` +yolact_edge_for_Pytorch + ├── env.sh 设置环境变量 + ├── pth2onnx.py pytorch模型导出onnx模型 + ├── atc.sh onnx模型转om + ├── yolact_edge.diff 补丁文件 + └── acl_net.py PyACL推理工具代码 +``` + +## 2 环境准备 + +### 2.1 安装依赖 + +根据pytorch官网教程安装1.10.0版本的PyTorch +```shell +pip install torch==1.10.0+cpu torchvision==0.11.1+cpu torchaudio==0.10.0+cpu +pip install -r requirements.txt +pip install git+https://github.com/haotian-liu/cocoapi.git#"egg=pycocotools&subdirectory=PythonAPI" +``` + +### 2.2 文件下载 +- [yolact_edge_Pytorch源码下载](https://github.com/haotian-liu/yolact_edge) + + ```shell + git clone git@github.com:haotian-liu/yolact_edge.git + cd yolact_edge + git reset a9a00281b33b3ac90253a4939773308a8f95e21d --hard + git apply yolact_edge.diff + ``` + +- 权重下载 + + 创建 `weights` 目录,并将下载的权重文件 `yolact_edge_resnet50_54_800000.pth` 拷贝到 `weights` 目录下。 + 可参见[yolact_edge_Pytorch主页](https://github.com/haotian-liu/yolact_edge)说明下载权重 + +- 数据集下载 + + om推理采用COCO2017数据集的验证集进行精度评估。将下载好的数据集拷贝到 `data/coco` 目录下,data目录中的文件结构如下所示。数据集下载可以网页搜索 + ```shell + data + └── coco + ├── annotations + ├── images + ├── scripts + ├── yolact_edge_example_1.gif + ├── yolact_edge_example_2.gif + ├── yolact_edge_example_3.gif + ``` + +### 2.3 文件拷贝 +拷贝env.sh,pth2onnx.py,atc.sh,acl_net.py文件到yolact_edge目录下。 + + +### 2.4 设置环境变量 +```shell +source env.sh +``` + +## 3 端到端推理步骤 + +### 3.1 pth导出onnx +```python +python3.7 pth2onnx.py \ + --config=yolact_edge_resnet50_config \ + --trained_model=./weights/yolact_edge_resnet50_54_800000.pth +``` + +### 3.2 利用ATC工具转换为om模型 +```shell +bash atc.sh yolact_edge.onnx yolact_edge +``` + +### 3.3 om模型推理 +```python +python3.7 eval.py \ + --config=yolact_edge_resnet50_config \ + --trained_model=./weights/yolact_edge_resnet50_54_800000.pth \ + --cuda=False \ + --disable_tensorrt +``` + +### 3.4 纯推理性能获取 + +下载 [benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) 并拷贝到当前目录 +```shell +./benchmark.${arch} -device_id=0 -batch_size=1 -om_path=./yolact_edge.om -round=20 +``` + +## 4 评测结果 + +| 模型 | pth精度 | 310离线推理精度 | 基准性能 | 310性能 | +| --------------- | -------- | --------------- | -------- | ------- | +| yolact_edge | [mAP:27.0](https://github.com/haotian-liu/yolact_edge) | mAP:27.6 | 167fps | 157fps | diff --git a/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/acl_net.py b/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/acl_net.py index b39eb3530c..d6c2ea29b9 100644 --- a/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/acl_net.py +++ b/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/acl_net.py @@ -1,259 +1,259 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 time -import numpy as np -import functools -import acl - -# error code -ACL_ERROR_NONE = 0 - -# rule for mem -ACL_MEM_MALLOC_HUGE_FIRST = 0 -ACL_MEM_MALLOC_HUGE_ONLY = 1 -ACL_MEM_MALLOC_NORMAL_ONLY = 2 - -# rule for memory copy -ACL_MEMCPY_HOST_TO_HOST = 0 -ACL_MEMCPY_HOST_TO_DEVICE = 1 -ACL_MEMCPY_DEVICE_TO_HOST = 2 -ACL_MEMCPY_DEVICE_TO_DEVICE = 3 - -ACL_DTYPE = { - 0: 'float32', - 1: 'float16', - 2: 'int8', - 3: 'int32', - 4: 'uint8', - 6: 'int16', - 7: 'uint16', - 8: 'uint32', - 9: 'int64', - 10: 'uint64', - 11: 'float64', - 12: 'bool', -} - -buffer_method = { - "in": acl.mdl.get_input_size_by_index, - "out": acl.mdl.get_output_size_by_index -} - - -def check_ret(message, ret): - if ret != ACL_ERROR_NONE: - raise Exception("{} failed ret={}".format(message, ret)) - - -class Net(object): - def __init__(self, model_path, device_id=0, config_path=None): - self.device_id = device_id # int - self.model_path = model_path # string - self.model_id = None # pointer - self.context = None # pointer - - self.input_data = [] - self.output_data = [] - self.model_desc = None # pointer when using - self.load_input_dataset = None - self.load_output_dataset = None - - self._init_resource(config_path) - - def __call__(self, ori_data): - return self.forward(ori_data) - - def __del__(self): - ret = acl.mdl.unload(self.model_id) - check_ret("acl.mdl.unload", ret) - if self.model_desc: - acl.mdl.destroy_desc(self.model_desc) - self.model_desc = None - - while self.input_data: - item = self.input_data.pop() - ret = acl.rt.free(item["buffer"]) - check_ret("acl.rt.free", ret) - - while self.output_data: - item = self.output_data.pop() - ret = acl.rt.free(item["buffer"]) - check_ret("acl.rt.free", ret) - - if self.context: - ret = acl.rt.destroy_context(self.context) - check_ret("acl.rt.destroy_context", ret) - self.context = None - - ret = acl.rt.reset_device(self.device_id) - check_ret("acl.rt.reset_device", ret) - ret = acl.finalize() - check_ret("acl.finalize", ret) - - def _init_resource(self, config_path=None): - if config_path: - ret = acl.init(config_path) - else: - ret = acl.init() - check_ret("acl.init", ret) - ret = acl.rt.set_device(self.device_id) - check_ret("acl.rt.set_device", ret) - - self.context, ret = acl.rt.create_context(self.device_id) - check_ret("acl.rt.create_context", ret) - - # load_model - self.model_id, ret = acl.mdl.load_from_file(self.model_path) - check_ret("acl.mdl.load_from_file", ret) - - self.model_desc = acl.mdl.create_desc() - self._get_model_info() - - def _get_model_info(self, ): - ret = acl.mdl.get_desc(self.model_desc, self.model_id) - check_ret("acl.mdl.get_desc", ret) - input_size = acl.mdl.get_num_inputs(self.model_desc) - output_size = acl.mdl.get_num_outputs(self.model_desc) - self._gen_data_buffer(input_size, des="in") - self._gen_data_buffer(output_size, des="out") - - def _gen_data_buffer(self, size, des): - func = buffer_method[des] - for i in range(size): - temp_buffer_size = func(self.model_desc, i) - temp_buffer, ret = acl.rt.malloc(temp_buffer_size, - ACL_MEM_MALLOC_HUGE_FIRST) - check_ret("acl.rt.malloc", ret) - - if des == "in": - self.input_data.append({"buffer": temp_buffer, - "size": temp_buffer_size}) - elif des == "out": - self.output_data.append({"buffer": temp_buffer, - "size": temp_buffer_size}) - - def _data_interaction(self, dataset, policy=ACL_MEMCPY_HOST_TO_DEVICE): - temp_data_buffer = self.input_data \ - if policy == ACL_MEMCPY_HOST_TO_DEVICE \ - else self.output_data - if len(dataset) == 0 and policy == ACL_MEMCPY_DEVICE_TO_HOST: - for item in self.output_data: - temp, ret = acl.rt.malloc_host(item["size"]) - if ret != 0: - raise Exception("can't malloc_host ret={}".format(ret)) - dataset.append({"size": item["size"], "buffer": temp}) - - for i, item in enumerate(temp_data_buffer): - if policy == ACL_MEMCPY_HOST_TO_DEVICE: - ptr = acl.util.numpy_to_ptr(dataset[i]) - ret = acl.rt.memcpy(item["buffer"], - item["size"], - ptr, - item["size"], - policy) - check_ret("acl.rt.memcpy", ret) - - else: - ptr = dataset[i]["buffer"] - ret = acl.rt.memcpy(ptr, - item["size"], - item["buffer"], - item["size"], - policy) - check_ret("acl.rt.memcpy", ret) - - def _gen_dataset(self, type_str="input"): - dataset = acl.mdl.create_dataset() - - temp_dataset = None - if type_str == "in": - self.load_input_dataset = dataset - temp_dataset = self.input_data - else: - self.load_output_dataset = dataset - temp_dataset = self.output_data - - for item in temp_dataset: - data = acl.create_data_buffer(item["buffer"], item["size"]) - if data is None: - ret = acl.destroy_data_buffer(dataset) - check_ret("acl.destroy_data_buffer", ret) - - _, ret = acl.mdl.add_dataset_buffer(dataset, data) - - if ret != ACL_ERROR_NONE: - ret = acl.destroy_data_buffer(dataset) - check_ret("acl.destroy_data_buffer", ret) - - def _data_from_host_to_device(self, images): - self._data_interaction(images, ACL_MEMCPY_HOST_TO_DEVICE) - self._gen_dataset("in") - self._gen_dataset("out") - - def _data_from_device_to_host(self): - res = [] - self._data_interaction(res, ACL_MEMCPY_DEVICE_TO_HOST) - output = self.get_result(res) - return output - - def _destroy_databuffer(self, ): - for dataset in [self.load_input_dataset, self.load_output_dataset]: - if not dataset: - continue - - num = acl.mdl.get_dataset_num_buffers(dataset) - for i in range(num): - data_buf = acl.mdl.get_dataset_buffer(dataset, i) - if data_buf: - ret = acl.destroy_data_buffer(data_buf) - check_ret("acl.destroy_data_buffer", ret) - ret = acl.mdl.destroy_dataset(dataset) - check_ret("acl.mdl.destroy_dataset", ret) - - def forward(self, input_data): - if not isinstance(input_data, (list, tuple)): - input_data = [input_data] - st = time.time() - self._data_from_host_to_device(input_data) - mem_t = time.time() - st - st = time.time() - ret = acl.mdl.execute(self.model_id, - self.load_input_dataset, - self.load_output_dataset) - exe_t = time.time() - st - st = time.time() - check_ret("acl.mdl.execute", ret) - self._destroy_databuffer() - result = self._data_from_device_to_host() - mem_t += time.time() - st - return result - - def get_result(self, output_data): - dataset = [] - for i in range(len(output_data)): - dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) - check_ret("acl.mdl.get_cur_output_dims", ret) - data_shape = dims.get("dims") - data_type = acl.mdl.get_output_data_type(self.model_desc, i) - data_len = functools.reduce(lambda x, y: x * y, data_shape) - ftype = np.dtype(ACL_DTYPE.get(data_type)) - - size = output_data[i]["size"] - ptr = output_data[i]["buffer"] - data = acl.util.ptr_to_numpy(ptr, (size,), 1) - np_arr = np.frombuffer(bytearray(data[:data_len * ftype.itemsize]), dtype=ftype, count=data_len) - np_arr = np_arr.reshape(data_shape) - dataset.append(np_arr) - return dataset +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 time +import numpy as np +import functools +import acl + +# error code +ACL_ERROR_NONE = 0 + +# rule for mem +ACL_MEM_MALLOC_HUGE_FIRST = 0 +ACL_MEM_MALLOC_HUGE_ONLY = 1 +ACL_MEM_MALLOC_NORMAL_ONLY = 2 + +# rule for memory copy +ACL_MEMCPY_HOST_TO_HOST = 0 +ACL_MEMCPY_HOST_TO_DEVICE = 1 +ACL_MEMCPY_DEVICE_TO_HOST = 2 +ACL_MEMCPY_DEVICE_TO_DEVICE = 3 + +ACL_DTYPE = { + 0: 'float32', + 1: 'float16', + 2: 'int8', + 3: 'int32', + 4: 'uint8', + 6: 'int16', + 7: 'uint16', + 8: 'uint32', + 9: 'int64', + 10: 'uint64', + 11: 'float64', + 12: 'bool', +} + +buffer_method = { + "in": acl.mdl.get_input_size_by_index, + "out": acl.mdl.get_output_size_by_index +} + + +def check_ret(message, ret): + if ret != ACL_ERROR_NONE: + raise Exception("{} failed ret={}".format(message, ret)) + + +class Net(object): + def __init__(self, model_path, device_id=0, config_path=None): + self.device_id = device_id # int + self.model_path = model_path # string + self.model_id = None # pointer + self.context = None # pointer + + self.input_data = [] + self.output_data = [] + self.model_desc = None # pointer when using + self.load_input_dataset = None + self.load_output_dataset = None + + self._init_resource(config_path) + + def __call__(self, ori_data): + return self.forward(ori_data) + + def __del__(self): + ret = acl.mdl.unload(self.model_id) + check_ret("acl.mdl.unload", ret) + if self.model_desc: + acl.mdl.destroy_desc(self.model_desc) + self.model_desc = None + + while self.input_data: + item = self.input_data.pop() + ret = acl.rt.free(item["buffer"]) + check_ret("acl.rt.free", ret) + + while self.output_data: + item = self.output_data.pop() + ret = acl.rt.free(item["buffer"]) + check_ret("acl.rt.free", ret) + + if self.context: + ret = acl.rt.destroy_context(self.context) + check_ret("acl.rt.destroy_context", ret) + self.context = None + + ret = acl.rt.reset_device(self.device_id) + check_ret("acl.rt.reset_device", ret) + ret = acl.finalize() + check_ret("acl.finalize", ret) + + def _init_resource(self, config_path=None): + if config_path: + ret = acl.init(config_path) + else: + ret = acl.init() + check_ret("acl.init", ret) + ret = acl.rt.set_device(self.device_id) + check_ret("acl.rt.set_device", ret) + + self.context, ret = acl.rt.create_context(self.device_id) + check_ret("acl.rt.create_context", ret) + + # load_model + self.model_id, ret = acl.mdl.load_from_file(self.model_path) + check_ret("acl.mdl.load_from_file", ret) + + self.model_desc = acl.mdl.create_desc() + self._get_model_info() + + def _get_model_info(self, ): + ret = acl.mdl.get_desc(self.model_desc, self.model_id) + check_ret("acl.mdl.get_desc", ret) + input_size = acl.mdl.get_num_inputs(self.model_desc) + output_size = acl.mdl.get_num_outputs(self.model_desc) + self._gen_data_buffer(input_size, des="in") + self._gen_data_buffer(output_size, des="out") + + def _gen_data_buffer(self, size, des): + func = buffer_method[des] + for i in range(size): + temp_buffer_size = func(self.model_desc, i) + temp_buffer, ret = acl.rt.malloc(temp_buffer_size, + ACL_MEM_MALLOC_HUGE_FIRST) + check_ret("acl.rt.malloc", ret) + + if des == "in": + self.input_data.append({"buffer": temp_buffer, + "size": temp_buffer_size}) + elif des == "out": + self.output_data.append({"buffer": temp_buffer, + "size": temp_buffer_size}) + + def _data_interaction(self, dataset, policy=ACL_MEMCPY_HOST_TO_DEVICE): + temp_data_buffer = self.input_data \ + if policy == ACL_MEMCPY_HOST_TO_DEVICE \ + else self.output_data + if len(dataset) == 0 and policy == ACL_MEMCPY_DEVICE_TO_HOST: + for item in self.output_data: + temp, ret = acl.rt.malloc_host(item["size"]) + if ret != 0: + raise Exception("can't malloc_host ret={}".format(ret)) + dataset.append({"size": item["size"], "buffer": temp}) + + for i, item in enumerate(temp_data_buffer): + if policy == ACL_MEMCPY_HOST_TO_DEVICE: + ptr = acl.util.numpy_to_ptr(dataset[i]) + ret = acl.rt.memcpy(item["buffer"], + item["size"], + ptr, + item["size"], + policy) + check_ret("acl.rt.memcpy", ret) + + else: + ptr = dataset[i]["buffer"] + ret = acl.rt.memcpy(ptr, + item["size"], + item["buffer"], + item["size"], + policy) + check_ret("acl.rt.memcpy", ret) + + def _gen_dataset(self, type_str="input"): + dataset = acl.mdl.create_dataset() + + temp_dataset = None + if type_str == "in": + self.load_input_dataset = dataset + temp_dataset = self.input_data + else: + self.load_output_dataset = dataset + temp_dataset = self.output_data + + for item in temp_dataset: + data = acl.create_data_buffer(item["buffer"], item["size"]) + if data is None: + ret = acl.destroy_data_buffer(dataset) + check_ret("acl.destroy_data_buffer", ret) + + _, ret = acl.mdl.add_dataset_buffer(dataset, data) + + if ret != ACL_ERROR_NONE: + ret = acl.destroy_data_buffer(dataset) + check_ret("acl.destroy_data_buffer", ret) + + def _data_from_host_to_device(self, images): + self._data_interaction(images, ACL_MEMCPY_HOST_TO_DEVICE) + self._gen_dataset("in") + self._gen_dataset("out") + + def _data_from_device_to_host(self): + res = [] + self._data_interaction(res, ACL_MEMCPY_DEVICE_TO_HOST) + output = self.get_result(res) + return output + + def _destroy_databuffer(self, ): + for dataset in [self.load_input_dataset, self.load_output_dataset]: + if not dataset: + continue + + num = acl.mdl.get_dataset_num_buffers(dataset) + for i in range(num): + data_buf = acl.mdl.get_dataset_buffer(dataset, i) + if data_buf: + ret = acl.destroy_data_buffer(data_buf) + check_ret("acl.destroy_data_buffer", ret) + ret = acl.mdl.destroy_dataset(dataset) + check_ret("acl.mdl.destroy_dataset", ret) + + def forward(self, input_data): + if not isinstance(input_data, (list, tuple)): + input_data = [input_data] + st = time.time() + self._data_from_host_to_device(input_data) + mem_t = time.time() - st + st = time.time() + ret = acl.mdl.execute(self.model_id, + self.load_input_dataset, + self.load_output_dataset) + exe_t = time.time() - st + st = time.time() + check_ret("acl.mdl.execute", ret) + self._destroy_databuffer() + result = self._data_from_device_to_host() + mem_t += time.time() - st + return result + + def get_result(self, output_data): + dataset = [] + for i in range(len(output_data)): + dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) + check_ret("acl.mdl.get_cur_output_dims", ret) + data_shape = dims.get("dims") + data_type = acl.mdl.get_output_data_type(self.model_desc, i) + data_len = functools.reduce(lambda x, y: x * y, data_shape) + ftype = np.dtype(ACL_DTYPE.get(data_type)) + + size = output_data[i]["size"] + ptr = output_data[i]["buffer"] + data = acl.util.ptr_to_numpy(ptr, (size,), 1) + np_arr = np.frombuffer(bytearray(data[:data_len * ftype.itemsize]), dtype=ftype, count=data_len) + np_arr = np_arr.reshape(data_shape) + dataset.append(np_arr) + return dataset diff --git a/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/atc.sh b/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/atc.sh index b5e775f899..dc10c8186c 100644 --- a/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/atc.sh +++ b/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/atc.sh @@ -1,5 +1,5 @@ -atc --model=$1 \ - --framework=5 \ - --output=$2 \ - --log=error \ - --soc_version=Ascend310 +atc --model=$1 \ + --framework=5 \ + --output=$2 \ + --log=error \ + --soc_version=Ascend310 diff --git a/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/env.sh b/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/env.sh index 9ce0d242f0..7fb2c8a43d 100644 --- a/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/env.sh +++ b/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/env.sh @@ -1,5 +1,5 @@ -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:${install_path}/pyACL/python/site-packages/acl:$PYTHONPATH -export ASCEND_OPP_PATH=${install_path}/opp +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:${install_path}/pyACL/python/site-packages/acl:$PYTHONPATH +export ASCEND_OPP_PATH=${install_path}/opp diff --git a/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/modelzoo_level.txt b/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/modelzoo_level.txt index d44ba5698b..70801afc42 100644 --- a/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/modelzoo_level.txt +++ b/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/requirements.txt b/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/requirements.txt index 511f52dc35..306a8a990a 100644 --- a/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/requirements.txt +++ b/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/requirements.txt @@ -1,7 +1,7 @@ -cython -opencv-python -pillow -matplotlib -GitPython -termcolor +cython +opencv-python +pillow +matplotlib +GitPython +termcolor tensorboard \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/yolact_edge.diff b/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/yolact_edge.diff index 3f2db5f240..e5b26f350d 100644 --- a/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/yolact_edge.diff +++ b/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch/yolact_edge.diff @@ -1,171 +1,171 @@ -diff --git a/eval.py b/eval.py -index f2a833f..8644391 100644 ---- a/eval.py -+++ b/eval.py -@@ -412,8 +412,9 @@ def prep_metrics(ap_data, dets, img, gt, gt_masks, h, w, num_crowd, image_id, de - - classes = list(classes.cpu().numpy().astype(int)) - scores = list(scores.cpu().numpy().astype(float)) -- masks = masks.view(-1, h*w).cuda() -- boxes = boxes.cuda() -+ #masks = masks.view(-1, h*w).cuda() -+ masks = masks.view(-1, h*w) -+ #boxes = boxes.cuda() - - - if args.output_coco_json: -@@ -1075,6 +1076,8 @@ def evaluate(net:Yolact, dataset, train_mode=False, train_cfg=None): - - else: - # Main eval loop -+ from acl_net import Net -+ model = Net(device_id=0, model_path='./yolact_edge.om') - for it, image_idx in enumerate(dataset_indices): - timer.reset() - -@@ -1092,9 +1095,15 @@ def evaluate(net:Yolact, dataset, train_mode=False, train_cfg=None): - batch = batch.cuda() - - with timer.env('Network Extra'): -- extras = {"backbone": "full", "interrupt": False, -- "moving_statistics": {"aligned_feats": []}} -- preds = net(batch, extras=extras)["pred_outs"] -+ # pytorch forward -+ # outs, proto_out = net(batch) -+ # om forward -+ res = model([batch.numpy()]) -+ outs = [torch.from_numpy(ele) for ele in res[:5]] -+ proto_out = torch.from_numpy(res[-1]) -+ -+ # common postprocess -+ preds = net.postprocess(outs, proto_out) - - # Perform the meat of the operation here depending on our mode. - if args.display: -diff --git a/yolact_edge/yolact.py b/yolact_edge/yolact.py -index b6efdf7..7a167f3 100644 ---- a/yolact_edge/yolact.py -+++ b/yolact_edge/yolact.py -@@ -33,10 +33,10 @@ except: - - # This is required for Pytorch 1.0.1 on Windows to initialize Cuda on some driver versions. - # See the bug report here: https://github.com/pytorch/pytorch/issues/17108 --torch.cuda.current_device() -+#torch.cuda.current_device() - - # As of March 10, 2019, Pytorch DataParallel still doesn't support JIT Script Modules --use_jit = False if use_torch2trt else torch.cuda.device_count() <= 1 -+use_jit = False #if use_torch2trt else torch.cuda.device_count() <= 1 - - ScriptModuleWrapper = torch.jit.ScriptModule if use_jit else nn.Module - script_method_wrapper = torch.jit.script_method if use_jit else lambda fn, _rcn=None: fn -@@ -1089,6 +1089,9 @@ class Yolact(nn.Module): - def __init__(self, training=True): - super().__init__() - -+ self.extras = {"backbone": "full", "interrupt": False, -+ "moving_statistics": {"aligned_feats": []}} -+ - self.backbone = construct_backbone(cfg.backbone) - - self.training = training -@@ -1608,19 +1611,19 @@ class Yolact(nn.Module): - x = torch.ones((1, lateral_channels * 2, 69, 69)).cuda() - self.trt_load_if("flow_net", trt_fn, [x], int8_mode, parent=self.flow_net, batch_size=batch_size) - -- def forward(self, x, extras=None): -+ def forward(self, x): - """ The input should be of size [batch_size, 3, img_h, img_w] """ - - if cfg.flow.train_flow: -- return self.forward_flow(extras) -+ return self.forward_flow(self.extras) - - outs_wrapper = {} - - with timer.env('backbone'): -- if cfg.flow is None or extras is None or extras["backbone"] == "full": -+ if cfg.flow is None or self.extras is None or self.extras["backbone"] == "full": - outs = self.backbone(x) - -- elif extras is not None and extras["backbone"] == "partial": -+ elif self.extras is not None and self.extras["backbone"] == "partial": - if hasattr(self, 'partial_backbone'): - outs = self.partial_backbone(x) - else: -@@ -1631,22 +1634,22 @@ class Yolact(nn.Module): - - if cfg.flow is not None: - with timer.env('fpn'): -- assert type(extras) == dict -- if extras["backbone"] == "full": -+ assert type(self.extras) == dict -+ if self.extras["backbone"] == "full": - outs = [outs[i] for i in cfg.backbone.selected_layers] - outs_fpn_phase_1_wrapper = self.fpn_phase_1(*outs) - outs_phase_1, lats_phase_1 = outs_fpn_phase_1_wrapper[:len(outs)], outs_fpn_phase_1_wrapper[len(outs):] - lateral = lats_phase_1[0].detach() -- moving_statistics = extras["moving_statistics"] -+ moving_statistics = self.extras["moving_statistics"] - -- if extras.get("keep_statistics", False): -+ if self.extras.get("keep_statistics", False): - outs_wrapper["feats"] = [out.detach() for out in outs_phase_1] - outs_wrapper["lateral"] = lateral - - outs_wrapper["outs_phase_1"] = [out.detach() for out in outs_phase_1] - else: -- assert extras["moving_statistics"] is not None -- moving_statistics = extras["moving_statistics"] -+ assert self.extras["moving_statistics"] is not None -+ moving_statistics = self.extras["moving_statistics"] - outs_phase_1 = moving_statistics["feats"].copy() - - if cfg.flow.warp_mode != 'take': -@@ -1699,7 +1702,7 @@ class Yolact(nn.Module): - outs_wrapper["outs_phase_1"] = outs_phase_1.copy() - - outs = self.fpn_phase_2(*outs_phase_1) -- if extras["backbone"] == "partial": -+ if self.extras["backbone"] == "partial": - outs_wrapper["outs_phase_2"] = [out for out in outs] - else: - outs_wrapper["outs_phase_2"] = [out.detach() for out in outs] -@@ -1709,7 +1712,7 @@ class Yolact(nn.Module): - outs = [outs[i] for i in cfg.backbone.selected_layers] - outs = self.fpn(outs) - -- if extras is not None and extras.get("interrupt", None): -+ if self.extras is not None and self.extras.get("interrupt", None): - return outs_wrapper - - proto_out = None -@@ -1740,6 +1743,9 @@ class Yolact(nn.Module): - bias_shape[-1] = 1 - proto_out = torch.cat([proto_out, torch.ones(*bias_shape)], -1) - -+ return outs, proto_out -+ -+ def postprocess(self, outs, proto_out): - with timer.env('pred_heads'): - pred_outs = { 'loc': [], 'conf': [], 'mask': [], 'priors': [] } - -@@ -1779,7 +1785,6 @@ class Yolact(nn.Module): - if cfg.use_semantic_segmentation_loss: - pred_outs['segm'] = self.semantic_seg_conv(outs[0]) - -- outs_wrapper["pred_outs"] = pred_outs - else: - if cfg.use_sigmoid_focal_loss: - # Note: even though conf[0] exists, this mode doesn't train it so don't use it -@@ -1792,8 +1797,8 @@ class Yolact(nn.Module): - else: - pred_outs['conf'] = F.softmax(pred_outs['conf'], -1) - -- outs_wrapper["pred_outs"] = self.detect(pred_outs) -- return outs_wrapper -+ pred_outs = self.detect(pred_outs) -+ return pred_outs - - - # Some testing code +diff --git a/eval.py b/eval.py +index f2a833f..8644391 100644 +--- a/eval.py ++++ b/eval.py +@@ -412,8 +412,9 @@ def prep_metrics(ap_data, dets, img, gt, gt_masks, h, w, num_crowd, image_id, de + + classes = list(classes.cpu().numpy().astype(int)) + scores = list(scores.cpu().numpy().astype(float)) +- masks = masks.view(-1, h*w).cuda() +- boxes = boxes.cuda() ++ #masks = masks.view(-1, h*w).cuda() ++ masks = masks.view(-1, h*w) ++ #boxes = boxes.cuda() + + + if args.output_coco_json: +@@ -1075,6 +1076,8 @@ def evaluate(net:Yolact, dataset, train_mode=False, train_cfg=None): + + else: + # Main eval loop ++ from acl_net import Net ++ model = Net(device_id=0, model_path='./yolact_edge.om') + for it, image_idx in enumerate(dataset_indices): + timer.reset() + +@@ -1092,9 +1095,15 @@ def evaluate(net:Yolact, dataset, train_mode=False, train_cfg=None): + batch = batch.cuda() + + with timer.env('Network Extra'): +- extras = {"backbone": "full", "interrupt": False, +- "moving_statistics": {"aligned_feats": []}} +- preds = net(batch, extras=extras)["pred_outs"] ++ # pytorch forward ++ # outs, proto_out = net(batch) ++ # om forward ++ res = model([batch.numpy()]) ++ outs = [torch.from_numpy(ele) for ele in res[:5]] ++ proto_out = torch.from_numpy(res[-1]) ++ ++ # common postprocess ++ preds = net.postprocess(outs, proto_out) + + # Perform the meat of the operation here depending on our mode. + if args.display: +diff --git a/yolact_edge/yolact.py b/yolact_edge/yolact.py +index b6efdf7..7a167f3 100644 +--- a/yolact_edge/yolact.py ++++ b/yolact_edge/yolact.py +@@ -33,10 +33,10 @@ except: + + # This is required for Pytorch 1.0.1 on Windows to initialize Cuda on some driver versions. + # See the bug report here: https://github.com/pytorch/pytorch/issues/17108 +-torch.cuda.current_device() ++#torch.cuda.current_device() + + # As of March 10, 2019, Pytorch DataParallel still doesn't support JIT Script Modules +-use_jit = False if use_torch2trt else torch.cuda.device_count() <= 1 ++use_jit = False #if use_torch2trt else torch.cuda.device_count() <= 1 + + ScriptModuleWrapper = torch.jit.ScriptModule if use_jit else nn.Module + script_method_wrapper = torch.jit.script_method if use_jit else lambda fn, _rcn=None: fn +@@ -1089,6 +1089,9 @@ class Yolact(nn.Module): + def __init__(self, training=True): + super().__init__() + ++ self.extras = {"backbone": "full", "interrupt": False, ++ "moving_statistics": {"aligned_feats": []}} ++ + self.backbone = construct_backbone(cfg.backbone) + + self.training = training +@@ -1608,19 +1611,19 @@ class Yolact(nn.Module): + x = torch.ones((1, lateral_channels * 2, 69, 69)).cuda() + self.trt_load_if("flow_net", trt_fn, [x], int8_mode, parent=self.flow_net, batch_size=batch_size) + +- def forward(self, x, extras=None): ++ def forward(self, x): + """ The input should be of size [batch_size, 3, img_h, img_w] """ + + if cfg.flow.train_flow: +- return self.forward_flow(extras) ++ return self.forward_flow(self.extras) + + outs_wrapper = {} + + with timer.env('backbone'): +- if cfg.flow is None or extras is None or extras["backbone"] == "full": ++ if cfg.flow is None or self.extras is None or self.extras["backbone"] == "full": + outs = self.backbone(x) + +- elif extras is not None and extras["backbone"] == "partial": ++ elif self.extras is not None and self.extras["backbone"] == "partial": + if hasattr(self, 'partial_backbone'): + outs = self.partial_backbone(x) + else: +@@ -1631,22 +1634,22 @@ class Yolact(nn.Module): + + if cfg.flow is not None: + with timer.env('fpn'): +- assert type(extras) == dict +- if extras["backbone"] == "full": ++ assert type(self.extras) == dict ++ if self.extras["backbone"] == "full": + outs = [outs[i] for i in cfg.backbone.selected_layers] + outs_fpn_phase_1_wrapper = self.fpn_phase_1(*outs) + outs_phase_1, lats_phase_1 = outs_fpn_phase_1_wrapper[:len(outs)], outs_fpn_phase_1_wrapper[len(outs):] + lateral = lats_phase_1[0].detach() +- moving_statistics = extras["moving_statistics"] ++ moving_statistics = self.extras["moving_statistics"] + +- if extras.get("keep_statistics", False): ++ if self.extras.get("keep_statistics", False): + outs_wrapper["feats"] = [out.detach() for out in outs_phase_1] + outs_wrapper["lateral"] = lateral + + outs_wrapper["outs_phase_1"] = [out.detach() for out in outs_phase_1] + else: +- assert extras["moving_statistics"] is not None +- moving_statistics = extras["moving_statistics"] ++ assert self.extras["moving_statistics"] is not None ++ moving_statistics = self.extras["moving_statistics"] + outs_phase_1 = moving_statistics["feats"].copy() + + if cfg.flow.warp_mode != 'take': +@@ -1699,7 +1702,7 @@ class Yolact(nn.Module): + outs_wrapper["outs_phase_1"] = outs_phase_1.copy() + + outs = self.fpn_phase_2(*outs_phase_1) +- if extras["backbone"] == "partial": ++ if self.extras["backbone"] == "partial": + outs_wrapper["outs_phase_2"] = [out for out in outs] + else: + outs_wrapper["outs_phase_2"] = [out.detach() for out in outs] +@@ -1709,7 +1712,7 @@ class Yolact(nn.Module): + outs = [outs[i] for i in cfg.backbone.selected_layers] + outs = self.fpn(outs) + +- if extras is not None and extras.get("interrupt", None): ++ if self.extras is not None and self.extras.get("interrupt", None): + return outs_wrapper + + proto_out = None +@@ -1740,6 +1743,9 @@ class Yolact(nn.Module): + bias_shape[-1] = 1 + proto_out = torch.cat([proto_out, torch.ones(*bias_shape)], -1) + ++ return outs, proto_out ++ ++ def postprocess(self, outs, proto_out): + with timer.env('pred_heads'): + pred_outs = { 'loc': [], 'conf': [], 'mask': [], 'priors': [] } + +@@ -1779,7 +1785,6 @@ class Yolact(nn.Module): + if cfg.use_semantic_segmentation_loss: + pred_outs['segm'] = self.semantic_seg_conv(outs[0]) + +- outs_wrapper["pred_outs"] = pred_outs + else: + if cfg.use_sigmoid_focal_loss: + # Note: even though conf[0] exists, this mode doesn't train it so don't use it +@@ -1792,8 +1797,8 @@ class Yolact(nn.Module): + else: + pred_outs['conf'] = F.softmax(pred_outs['conf'], -1) + +- outs_wrapper["pred_outs"] = self.detect(pred_outs) +- return outs_wrapper ++ pred_outs = self.detect(pred_outs) ++ return pred_outs + + + # Some testing code diff --git a/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/README.md b/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/README.md index 4df2045dbb..0b3ee78291 100644 --- a/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/README.md +++ b/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/README.md @@ -1,73 +1,73 @@ -文件作用说明: - -1. env.sh:ATC工具环境变量配置脚本 -2. require.txt:脚本运行所需的第三方库 -3. parse_json.py: coco数据集标签json文件解析脚本 -4. preprocess_yolov3_pytorch.py: 二进制数据集预处理脚本 -5. get_coco_info.py: yolov3.info生成脚本 -6. bin_to_predict_yolo_pytorch.py: benchmark输出bin文件解析脚本 -7. map_calculate.py: 精度统计脚本 -8. benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer - -推理端到端步骤: - -(1) git clone 开源仓https://github.com/ultralytics/yolov3/, 并下载对应的权重文件,修改**models/export.py**脚本生成onnx文件 - -``` -git clone https://github.com/ultralytics/yolov3/ -python3.7 models/export.py --weights ./yolov3.pt --img 416 --batch 1 -``` - -(2)配置环境变量转换om模型 - -``` -source env.sh -atc --model=yolov3.onnx --framework=5 --output=yolov3_bs1 --input_format=NCHW --log=info --soc_version=Ascend310 --input_shape="images:1,3,416,416" --out_nodes="Reshape_219:0;Reshape_203:0;Reshape_187:0" -``` - -(3)解析数据集 - -下载coco2014数据集val2014和label文件**instances_valminusminival2014.json**,运行**parse_json.py**解析数据集 - -``` -python3.7 parse_json.py -``` - -生成coco2014.names和coco_2014.info以及gronud-truth文件夹 - -(5)数据预处理 - -运行脚本preprocess_yolov3_pytorch.py处理数据集 - -``` -python3.7 preprocess_yolov3_pytorch.py coco_2014.info yolov3_bin -``` - -(6)benchmark推理 - -运行get_coco_info.py生成info文件 - -``` -python3.7 get_coco_info.py yolo_coco_bin_tf coco_2014.info yolov3.info -``` - -执行benchmark命令,结果保存在同级目录 result/dumpOutput_device0/ - -``` -python3.7 get_coco_info.py yolo_coco_bin_tf coco_2014.info yolov3.info -``` - -(7)后处理 - -运行 bin_to_predict_yolo_pytorch.py 解析模型输出 - -``` -python3.7 bin_to_predict_yolo_pytorch.py --bin_data_path result/dumpOutput_device0/ --det_results_path detection-results/ --origin_jpg_path /root/dataset/coco2014/val2014/ --coco_class_names /root/dataset/coco2014/coco2014.names --model_type yolov3 --net_input_size 416 -``` - -运行map_cauculate.py统计mAP值 - -``` -python3 map_calculate.py --label_path ./ground-truth --npu_txt_path ./detection-results -na -np -``` - +文件作用说明: + +1. env.sh:ATC工具环境变量配置脚本 +2. require.txt:脚本运行所需的第三方库 +3. parse_json.py: coco数据集标签json文件解析脚本 +4. preprocess_yolov3_pytorch.py: 二进制数据集预处理脚本 +5. get_coco_info.py: yolov3.info生成脚本 +6. bin_to_predict_yolo_pytorch.py: benchmark输出bin文件解析脚本 +7. map_calculate.py: 精度统计脚本 +8. benchmark工具源码地址:https://gitee.com/ascend/cann-benchmark/tree/master/infer + +推理端到端步骤: + +(1) git clone 开源仓https://github.com/ultralytics/yolov3/, 并下载对应的权重文件,修改**models/export.py**脚本生成onnx文件 + +``` +git clone https://github.com/ultralytics/yolov3/ +python3.7 models/export.py --weights ./yolov3.pt --img 416 --batch 1 +``` + +(2)配置环境变量转换om模型 + +``` +source env.sh +atc --model=yolov3.onnx --framework=5 --output=yolov3_bs1 --input_format=NCHW --log=info --soc_version=Ascend310 --input_shape="images:1,3,416,416" --out_nodes="Reshape_219:0;Reshape_203:0;Reshape_187:0" +``` + +(3)解析数据集 + +下载coco2014数据集val2014和label文件**instances_valminusminival2014.json**,运行**parse_json.py**解析数据集 + +``` +python3.7 parse_json.py +``` + +生成coco2014.names和coco_2014.info以及gronud-truth文件夹 + +(5)数据预处理 + +运行脚本preprocess_yolov3_pytorch.py处理数据集 + +``` +python3.7 preprocess_yolov3_pytorch.py coco_2014.info yolov3_bin +``` + +(6)benchmark推理 + +运行get_coco_info.py生成info文件 + +``` +python3.7 get_coco_info.py yolo_coco_bin_tf coco_2014.info yolov3.info +``` + +执行benchmark命令,结果保存在同级目录 result/dumpOutput_device0/ + +``` +python3.7 get_coco_info.py yolo_coco_bin_tf coco_2014.info yolov3.info +``` + +(7)后处理 + +运行 bin_to_predict_yolo_pytorch.py 解析模型输出 + +``` +python3.7 bin_to_predict_yolo_pytorch.py --bin_data_path result/dumpOutput_device0/ --det_results_path detection-results/ --origin_jpg_path /root/dataset/coco2014/val2014/ --coco_class_names /root/dataset/coco2014/coco2014.names --model_type yolov3 --net_input_size 416 +``` + +运行map_cauculate.py统计mAP值 + +``` +python3 map_calculate.py --label_path ./ground-truth --npu_txt_path ./detection-results -na -np +``` + diff --git a/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/bin_to_predict_yolo_pytorch.py b/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/bin_to_predict_yolo_pytorch.py index cb84f10381..2cfababcda 100644 --- a/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/bin_to_predict_yolo_pytorch.py +++ b/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/bin_to_predict_yolo_pytorch.py @@ -1,255 +1,255 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import numpy as np -import argparse -import time -import torch -import torchvision -import cv2 - - -def _make_grid(nx=20, ny=20): - xv, yv = np.meshgrid(np.arange(nx), np.arange(ny)) - return np.stack((xv, yv), 2).reshape((1, 1, ny, nx, 2)).astype(np.float) - - -def sigmoid(x0): - s = 1 / (1 + np.exp(-x0)) - return s - -def detect(x, model_type): - """ - x(bs,3,20,20,85) - """ - - # x(bs,3,20,20,85) - z = [] - grid = [] - for i in range(3): - _, _, ny, nx, _ = x[i].shape - grid.append(_make_grid(nx, ny)) - if model_type == 'yolov5': - stride = np.array([8, 16, 32]) - anchor_grid = np.array( - [[10., 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]])\ - .reshape(3, 1, 3, 1, 1, 2) - elif model_type == 'yolov3': - stride = np.array([32, 16, 8]) - anchor_grid = np.array( - [[116, 90, 156, 198, 373, 326], [30, 61, 62, 45, 59, 119], [10., 13, 16, 30, 33, 23]])\ - .reshape(3, 1, 3, 1, 1, 2) - - for i in range(3): - y = sigmoid(x[i]) - y[..., 0:2] = (y[..., 0:2] * 2. - 0.5 + grid[i]) * stride[i] # xy - y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * anchor_grid[i] # wh - z.append(y.reshape(1, -1, 85)) - return np.concatenate(z, 1) - - -def xywh2xyxy(x): - # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right - y = torch.zeros_like(x) if isinstance(x, torch.Tensor) else np.zeros_like(x) - y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x - y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y - y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x - y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y - return y - - -def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, merge=False, classes=None, agnostic=False): - """Performs Non-Maximum Suppression (NMS) on inference results - - Returns: - detections with shape: nx6 (x1, y1, x2, y2, conf, cls) - """ - - nc = prediction[0].shape[1] - 5 # number of classes - xc = prediction[..., 4] > conf_thres # candidates - - # Settings - min_wh, max_wh = 2, 4096 # (pixels) minimum and maximum box width and height - max_det = 300 # maximum number of detections per image - time_limit = 10.0 # seconds to quit after - redundant = True # require redundant detections - multi_label = nc > 1 # multiple labels per box (adds 0.5ms/img) - - t = time.time() - output = [None] * prediction.shape[0] - for xi, x in enumerate(prediction): # image index, image inference - # Apply constraints - # x[((x[..., 2:4] < min_wh) | (x[..., 2:4] > max_wh)).any(1), 4] = 0 # width-height - x = x[xc[xi]] # confidence - - # If none remain process next image - if not x.shape[0]: - continue - - # Compute conf - x[:, 5:] *= x[:, 4:5] # conf = obj_conf * cls_conf - - # Box (center x, center y, width, height) to (x1, y1, x2, y2) - box = xywh2xyxy(x[:, :4]) - - # Detections matrix nx6 (xyxy, conf, cls) - if multi_label: - i, j = (x[:, 5:] > conf_thres).nonzero(as_tuple=False).T - x = torch.cat((box[i], x[i, j + 5, None], j[:, None].float()), 1) - else: # best class only - conf, j = x[:, 5:].max(1, keepdim=True) - x = torch.cat((box, conf, j.float()), 1)[conf.view(-1) > conf_thres] - - # Filter by class - if classes: - x = x[(x[:, 5:6] == torch.tensor(classes, device=x.device)).any(1)] - - # Apply finite constraint - # if not torch.isfinite(x).all(): - # x = x[torch.isfinite(x).all(1)] - - # If none remain process next image - n = x.shape[0] # number of boxes - if not n: - continue - # Sort by confidence - # x = x[x[:, 4].argsort(descending=True)] - - # Batched NMS - c = x[:, 5:6] * (0 if agnostic else max_wh) # classes - boxes, scores = x[:, :4] + c, x[:, 4] # boxes (offset by class), scores - i = torchvision.ops.nms(boxes, scores, iou_thres) - if i.shape[0] > max_det: # limit detections - i = i[:max_det] - if merge and (1 < n < 3E3): # Merge NMS (boxes merged using weighted mean) - try: # update boxes as boxes(i,4) = weights(i,n) * boxes(n,4) - iou = box_iou(boxes[i], boxes) > iou_thres # iou matrix - weights = iou * scores[None] # box weights - x[i, :4] = torch.mm(weights, x[:, :4]).float() / weights.sum(1, keepdim=True) # merged boxes - if redundant: - i = i[iou.sum(1) > 1] # require redundancy - except: # possible CUDA error https://github.com/ultralytics/yolov3/issues/1139 - print(x, i, x.shape, i.shape) - pass - - output[xi] = x[i] - if (time.time() - t) > time_limit: - break # time limit exceeded - - return output - - -def clip_coords(boxes, img_shape): - # Clip bounding xyxy bounding boxes to image shape (height, width) - boxes[:, 0].clamp_(0, img_shape[1]) # x1 - boxes[:, 1].clamp_(0, img_shape[0]) # y1 - boxes[:, 2].clamp_(0, img_shape[1]) # x2 - boxes[:, 3].clamp_(0, img_shape[0]) # y2 - - -def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None): - # Rescale coords (xyxy) from img1_shape to img0_shape - if ratio_pad is None: # calculate from img0_shape - gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1]) # gain = old / new - pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2 # wh padding - else: - gain = ratio_pad[0][0] - pad = ratio_pad[1] - - coords[:, [0, 2]] -= pad[0] # x padding - coords[:, [1, 3]] -= pad[1] # y padding - coords[:, :4] /= gain - clip_coords(coords, img0_shape) - return coords - - -def post_process(flags): - names = np.loadtxt(flags.coco_class_names, dtype='str', delimiter='\n') - img = torch.zeros((1, 3, flags.net_input_size, flags.net_input_size)) - - # 读取bin文件用于生成预测结果 - bin_path = flags.bin_data_path - ori_path = flags.origin_jpg_path - - det_results_path = flags.det_results_path - os.makedirs(det_results_path, exist_ok=True) - total_img = set([name[:name.rfind('_')] - for name in os.listdir(bin_path) if "bin" in name]) - for bin_file in sorted(total_img): - path_base = os.path.join(bin_path, bin_file) - src_img = cv2.imread(os.path.join(ori_path, '{}.jpg'.format(bin_file))) - assert src_img is not None, 'Image Not Found ' + bin_file - - # 加载检测的所有输出tensor - res_buff = [] - - if flags.model_type == 'yolov5': - yolo_shape = [[1, 3, 85, 80, 80], [1, 3, 85, 40, 40], [1, 3, 85, 20, 20]] - elif flags.model_type == 'yolov3': - yolo_shape = [[1, 3, 85, 13, 13], [1, 3, 85, 26, 26], [1, 3, 85, 52, 52]] - - for num in range(flags.net_out_num): - # print(path_base + "_" + str(num + 1) + ".bin") - if os.path.exists(path_base + "_" + str(num + 1) + ".bin"): - buf = np.fromfile(path_base + "_" + - str(num + 1) + ".bin", dtype="float32") - res_buff.append(buf.reshape(yolo_shape[num]).transpose((0, 1, 3, 4, 2))) # 1,3,85,h,w ->1,3,h,w,85 - else: - print("[ERROR] file not exist", path_base + - "_" + str(num + 1) + ".bin") - - res_tensor = detect(res_buff, flags.model_type) - res_tensor = torch.from_numpy(res_tensor) - # Apply NMS - pred = non_max_suppression(res_tensor, conf_thres=0.33, iou_thres=0.5, classes=None, agnostic=False) - det_results_file = os.path.join(det_results_path, bin_file + ".txt") - - # Process detections - for i, det in enumerate(pred): # detections per image - size = '' - size += '%gx%g ' % img.shape[2:] # print string - gn = torch.tensor(src_img.shape)[[1, 0, 1, 0]] # normalization gain whwh - # Rescale boxes from img_size to im0 size - if det is not None: - det[:, :4] = scale_coords(img.shape[2:], det[:, :4], src_img.shape).round() - - # Print results - for c in det[:, -1].unique(): - n = (det[:, -1] == c).sum() # detections per class - size += '%g %ss, ' % (n, names[int(c)]) # add to string - with open(det_results_file, 'w') as f: - for *xyxy, conf, cls in det: - content = '{} {} {} {} {} {}'.format(names[int(cls)], conf, *xyxy) - print(content) - f.write(content) - f.write('\n') - else: - with open(det_results_file, 'w') as f: - f.write('') - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--bin_data_path", default="./result/dumpOutput_device0") - parser.add_argument("--origin_jpg_path", default="./val2014/") - parser.add_argument("--det_results_path", - default="./detection-results/") - parser.add_argument("--coco_class_names", default="./coco2014.names") - parser.add_argument("--net_input_size", default=640, type=int) - parser.add_argument("--net_out_num", default=3) - parser.add_argument("--model_type", default='yolov5') - flags = parser.parse_args() - - post_process(flags) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import numpy as np +import argparse +import time +import torch +import torchvision +import cv2 + + +def _make_grid(nx=20, ny=20): + xv, yv = np.meshgrid(np.arange(nx), np.arange(ny)) + return np.stack((xv, yv), 2).reshape((1, 1, ny, nx, 2)).astype(np.float) + + +def sigmoid(x0): + s = 1 / (1 + np.exp(-x0)) + return s + +def detect(x, model_type): + """ + x(bs,3,20,20,85) + """ + + # x(bs,3,20,20,85) + z = [] + grid = [] + for i in range(3): + _, _, ny, nx, _ = x[i].shape + grid.append(_make_grid(nx, ny)) + if model_type == 'yolov5': + stride = np.array([8, 16, 32]) + anchor_grid = np.array( + [[10., 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]])\ + .reshape(3, 1, 3, 1, 1, 2) + elif model_type == 'yolov3': + stride = np.array([32, 16, 8]) + anchor_grid = np.array( + [[116, 90, 156, 198, 373, 326], [30, 61, 62, 45, 59, 119], [10., 13, 16, 30, 33, 23]])\ + .reshape(3, 1, 3, 1, 1, 2) + + for i in range(3): + y = sigmoid(x[i]) + y[..., 0:2] = (y[..., 0:2] * 2. - 0.5 + grid[i]) * stride[i] # xy + y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * anchor_grid[i] # wh + z.append(y.reshape(1, -1, 85)) + return np.concatenate(z, 1) + + +def xywh2xyxy(x): + # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right + y = torch.zeros_like(x) if isinstance(x, torch.Tensor) else np.zeros_like(x) + y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x + y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y + y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x + y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y + return y + + +def non_max_suppression(prediction, conf_thres=0.1, iou_thres=0.6, merge=False, classes=None, agnostic=False): + """Performs Non-Maximum Suppression (NMS) on inference results + + Returns: + detections with shape: nx6 (x1, y1, x2, y2, conf, cls) + """ + + nc = prediction[0].shape[1] - 5 # number of classes + xc = prediction[..., 4] > conf_thres # candidates + + # Settings + min_wh, max_wh = 2, 4096 # (pixels) minimum and maximum box width and height + max_det = 300 # maximum number of detections per image + time_limit = 10.0 # seconds to quit after + redundant = True # require redundant detections + multi_label = nc > 1 # multiple labels per box (adds 0.5ms/img) + + t = time.time() + output = [None] * prediction.shape[0] + for xi, x in enumerate(prediction): # image index, image inference + # Apply constraints + # x[((x[..., 2:4] < min_wh) | (x[..., 2:4] > max_wh)).any(1), 4] = 0 # width-height + x = x[xc[xi]] # confidence + + # If none remain process next image + if not x.shape[0]: + continue + + # Compute conf + x[:, 5:] *= x[:, 4:5] # conf = obj_conf * cls_conf + + # Box (center x, center y, width, height) to (x1, y1, x2, y2) + box = xywh2xyxy(x[:, :4]) + + # Detections matrix nx6 (xyxy, conf, cls) + if multi_label: + i, j = (x[:, 5:] > conf_thres).nonzero(as_tuple=False).T + x = torch.cat((box[i], x[i, j + 5, None], j[:, None].float()), 1) + else: # best class only + conf, j = x[:, 5:].max(1, keepdim=True) + x = torch.cat((box, conf, j.float()), 1)[conf.view(-1) > conf_thres] + + # Filter by class + if classes: + x = x[(x[:, 5:6] == torch.tensor(classes, device=x.device)).any(1)] + + # Apply finite constraint + # if not torch.isfinite(x).all(): + # x = x[torch.isfinite(x).all(1)] + + # If none remain process next image + n = x.shape[0] # number of boxes + if not n: + continue + # Sort by confidence + # x = x[x[:, 4].argsort(descending=True)] + + # Batched NMS + c = x[:, 5:6] * (0 if agnostic else max_wh) # classes + boxes, scores = x[:, :4] + c, x[:, 4] # boxes (offset by class), scores + i = torchvision.ops.nms(boxes, scores, iou_thres) + if i.shape[0] > max_det: # limit detections + i = i[:max_det] + if merge and (1 < n < 3E3): # Merge NMS (boxes merged using weighted mean) + try: # update boxes as boxes(i,4) = weights(i,n) * boxes(n,4) + iou = box_iou(boxes[i], boxes) > iou_thres # iou matrix + weights = iou * scores[None] # box weights + x[i, :4] = torch.mm(weights, x[:, :4]).float() / weights.sum(1, keepdim=True) # merged boxes + if redundant: + i = i[iou.sum(1) > 1] # require redundancy + except: # possible CUDA error https://github.com/ultralytics/yolov3/issues/1139 + print(x, i, x.shape, i.shape) + pass + + output[xi] = x[i] + if (time.time() - t) > time_limit: + break # time limit exceeded + + return output + + +def clip_coords(boxes, img_shape): + # Clip bounding xyxy bounding boxes to image shape (height, width) + boxes[:, 0].clamp_(0, img_shape[1]) # x1 + boxes[:, 1].clamp_(0, img_shape[0]) # y1 + boxes[:, 2].clamp_(0, img_shape[1]) # x2 + boxes[:, 3].clamp_(0, img_shape[0]) # y2 + + +def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None): + # Rescale coords (xyxy) from img1_shape to img0_shape + if ratio_pad is None: # calculate from img0_shape + gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1]) # gain = old / new + pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2 # wh padding + else: + gain = ratio_pad[0][0] + pad = ratio_pad[1] + + coords[:, [0, 2]] -= pad[0] # x padding + coords[:, [1, 3]] -= pad[1] # y padding + coords[:, :4] /= gain + clip_coords(coords, img0_shape) + return coords + + +def post_process(flags): + names = np.loadtxt(flags.coco_class_names, dtype='str', delimiter='\n') + img = torch.zeros((1, 3, flags.net_input_size, flags.net_input_size)) + + # 读取bin文件用于生成预测结果 + bin_path = flags.bin_data_path + ori_path = flags.origin_jpg_path + + det_results_path = flags.det_results_path + os.makedirs(det_results_path, exist_ok=True) + total_img = set([name[:name.rfind('_')] + for name in os.listdir(bin_path) if "bin" in name]) + for bin_file in sorted(total_img): + path_base = os.path.join(bin_path, bin_file) + src_img = cv2.imread(os.path.join(ori_path, '{}.jpg'.format(bin_file))) + assert src_img is not None, 'Image Not Found ' + bin_file + + # 加载检测的所有输出tensor + res_buff = [] + + if flags.model_type == 'yolov5': + yolo_shape = [[1, 3, 85, 80, 80], [1, 3, 85, 40, 40], [1, 3, 85, 20, 20]] + elif flags.model_type == 'yolov3': + yolo_shape = [[1, 3, 85, 13, 13], [1, 3, 85, 26, 26], [1, 3, 85, 52, 52]] + + for num in range(flags.net_out_num): + # print(path_base + "_" + str(num + 1) + ".bin") + if os.path.exists(path_base + "_" + str(num + 1) + ".bin"): + buf = np.fromfile(path_base + "_" + + str(num + 1) + ".bin", dtype="float32") + res_buff.append(buf.reshape(yolo_shape[num]).transpose((0, 1, 3, 4, 2))) # 1,3,85,h,w ->1,3,h,w,85 + else: + print("[ERROR] file not exist", path_base + + "_" + str(num + 1) + ".bin") + + res_tensor = detect(res_buff, flags.model_type) + res_tensor = torch.from_numpy(res_tensor) + # Apply NMS + pred = non_max_suppression(res_tensor, conf_thres=0.33, iou_thres=0.5, classes=None, agnostic=False) + det_results_file = os.path.join(det_results_path, bin_file + ".txt") + + # Process detections + for i, det in enumerate(pred): # detections per image + size = '' + size += '%gx%g ' % img.shape[2:] # print string + gn = torch.tensor(src_img.shape)[[1, 0, 1, 0]] # normalization gain whwh + # Rescale boxes from img_size to im0 size + if det is not None: + det[:, :4] = scale_coords(img.shape[2:], det[:, :4], src_img.shape).round() + + # Print results + for c in det[:, -1].unique(): + n = (det[:, -1] == c).sum() # detections per class + size += '%g %ss, ' % (n, names[int(c)]) # add to string + with open(det_results_file, 'w') as f: + for *xyxy, conf, cls in det: + content = '{} {} {} {} {} {}'.format(names[int(cls)], conf, *xyxy) + print(content) + f.write(content) + f.write('\n') + else: + with open(det_results_file, 'w') as f: + f.write('') + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("--bin_data_path", default="./result/dumpOutput_device0") + parser.add_argument("--origin_jpg_path", default="./val2014/") + parser.add_argument("--det_results_path", + default="./detection-results/") + parser.add_argument("--coco_class_names", default="./coco2014.names") + parser.add_argument("--net_input_size", default=640, type=int) + parser.add_argument("--net_out_num", default=3) + parser.add_argument("--model_type", default='yolov5') + flags = parser.parse_args() + + post_process(flags) diff --git a/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/get_coco_info.py b/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/get_coco_info.py index 6e9dcabeec..2d795eed2e 100644 --- a/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/get_coco_info.py +++ b/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/get_coco_info.py @@ -1,31 +1,31 @@ -import os -import sys - -file_path = sys.argv[1] -coco_info = sys.argv[2] -info_name = sys.argv[3] - -image_names = [] -image_size = [] - -with open(coco_info, 'r') as file: - contents = file.read().split('\n') - -for content in contents[:-1]: - temp = content.split() - key = temp[1] - image_names.append(key[key.rfind('/') + 1:].split('.')[0]) - image_size.append([temp[2], temp[3]]) - -name_size = dict(zip(image_names, image_size)) - -with open(info_name, 'w') as file: - index = 0 - for key, val in name_size.items(): - bin_name = os.path.join(file_path, '{}.bin'.format(key)) - content = ' '.join([str(index), bin_name, val[0], val[1]]) - file.write(content) - file.write('\n') - index += 1 - - +import os +import sys + +file_path = sys.argv[1] +coco_info = sys.argv[2] +info_name = sys.argv[3] + +image_names = [] +image_size = [] + +with open(coco_info, 'r') as file: + contents = file.read().split('\n') + +for content in contents[:-1]: + temp = content.split() + key = temp[1] + image_names.append(key[key.rfind('/') + 1:].split('.')[0]) + image_size.append([temp[2], temp[3]]) + +name_size = dict(zip(image_names, image_size)) + +with open(info_name, 'w') as file: + index = 0 + for key, val in name_size.items(): + bin_name = os.path.join(file_path, '{}.bin'.format(key)) + content = ' '.join([str(index), bin_name, val[0], val[1]]) + file.write(content) + file.write('\n') + index += 1 + + diff --git a/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/parse_json.py b/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/parse_json.py index 2711914e85..29ea10ed8d 100644 --- a/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/parse_json.py +++ b/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/parse_json.py @@ -1,77 +1,77 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 json - -with open('./instances_val2014.json', 'r') as file: - content = file.read() -content = json.loads(content) -info = content.get('info') -licenses = content.get('licenses') -images = content.get('images') -annotations = content.get('annotations') -categroies = content.get('categories') - -with open('./coco2014.names', 'w') as f: - for categroie in categroies: - f.write(categroie.get('name').replace(' ', '_')) - f.write('\n') - -file_names = [image.get('file_name') for image in images] -widths = [image.get('width') for image in images] -heights = [image.get('height') for image in images] -image_ids = [image.get('id') for image in images] -assert len(file_names) == len(widths) == len(heights) == len(image_ids), "must be equal" - -annotation_ids = [annotation.get('image_id') for annotation in annotations] -bboxs = [annotation.get('bbox') for annotation in annotations] -category_ids = [annotation.get('category_id') for annotation in annotations] -segmentations = [annotation.get('segmentation') for annotation in annotations] -iscrowds = [annotation.get('iscrowd') for annotation in annotations] - -assert len(annotation_ids) == len(bboxs) == len(category_ids) ==len(segmentations) # 255094 - -with open('coco_2014.info', 'w') as f: - for index, file_name in enumerate(file_names): - file_name = 'val2014/' + file_name - line = "{} {} {} {}".format(index, file_name, widths[index], heights[index]) - f.write(line) - f.write('\n') - -def get_all_index(lst, item): - return [index for (index, value) in enumerate(lst) if value == item] - -def get_categroie_name(lst, item): - categroie_name = [dt.get('name') for dt in lst if item == dt.get('id')][0] - if len(categroie_name.split()) == 2: - temp = categroie_name.split() - categroie_name = temp[0] + '_' + temp[1] - return categroie_name - -for index, image_id in enumerate(image_ids): - indexs = get_all_index(annotation_ids, image_id) - with open('./ground-truth-split/{}.txt'.format(file_names[index].split('.')[0]), 'w') as f: - for idx in indexs: - f.write(get_categroie_name(categroies, category_ids[idx])) - print(get_categroie_name(categroies, category_ids[idx])) - f.write(' ') - # change label - bboxs[idx][2] = bboxs[idx][0] + bboxs[idx][2] - bboxs[idx][3] = bboxs[idx][1] + bboxs[idx][3] - f.write(' '.join(map(str, bboxs[idx]))) - f.write('\n') - - - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 json + +with open('./instances_val2014.json', 'r') as file: + content = file.read() +content = json.loads(content) +info = content.get('info') +licenses = content.get('licenses') +images = content.get('images') +annotations = content.get('annotations') +categroies = content.get('categories') + +with open('./coco2014.names', 'w') as f: + for categroie in categroies: + f.write(categroie.get('name').replace(' ', '_')) + f.write('\n') + +file_names = [image.get('file_name') for image in images] +widths = [image.get('width') for image in images] +heights = [image.get('height') for image in images] +image_ids = [image.get('id') for image in images] +assert len(file_names) == len(widths) == len(heights) == len(image_ids), "must be equal" + +annotation_ids = [annotation.get('image_id') for annotation in annotations] +bboxs = [annotation.get('bbox') for annotation in annotations] +category_ids = [annotation.get('category_id') for annotation in annotations] +segmentations = [annotation.get('segmentation') for annotation in annotations] +iscrowds = [annotation.get('iscrowd') for annotation in annotations] + +assert len(annotation_ids) == len(bboxs) == len(category_ids) ==len(segmentations) # 255094 + +with open('coco_2014.info', 'w') as f: + for index, file_name in enumerate(file_names): + file_name = 'val2014/' + file_name + line = "{} {} {} {}".format(index, file_name, widths[index], heights[index]) + f.write(line) + f.write('\n') + +def get_all_index(lst, item): + return [index for (index, value) in enumerate(lst) if value == item] + +def get_categroie_name(lst, item): + categroie_name = [dt.get('name') for dt in lst if item == dt.get('id')][0] + if len(categroie_name.split()) == 2: + temp = categroie_name.split() + categroie_name = temp[0] + '_' + temp[1] + return categroie_name + +for index, image_id in enumerate(image_ids): + indexs = get_all_index(annotation_ids, image_id) + with open('./ground-truth-split/{}.txt'.format(file_names[index].split('.')[0]), 'w') as f: + for idx in indexs: + f.write(get_categroie_name(categroies, category_ids[idx])) + print(get_categroie_name(categroies, category_ids[idx])) + f.write(' ') + # change label + bboxs[idx][2] = bboxs[idx][0] + bboxs[idx][2] + bboxs[idx][3] = bboxs[idx][1] + bboxs[idx][3] + f.write(' '.join(map(str, bboxs[idx]))) + f.write('\n') + + + + diff --git a/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/preprocess_yolov3_pytorch.py b/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/preprocess_yolov3_pytorch.py index f10d988816..ffb49084c6 100644 --- a/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/preprocess_yolov3_pytorch.py +++ b/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch/preprocess_yolov3_pytorch.py @@ -1,79 +1,79 @@ -import sys -import os -import cv2 -import numpy as np - - -def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True): - # Resize image to a 32-pixel-multiple rectangle https://github.com/ultralytics/yolov3/issues/232 - shape = img.shape[:2] # current shape [height, width] - if isinstance(new_shape, int): - new_shape = (new_shape, new_shape) - - # Scale ratio (new / old) - r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) - if not scaleup: # only scale down, do not scale up (for better test mAP) - r = min(r, 1.0) - - # Compute padding - ratio = r, r # width, height ratios - new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) - dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding - # if auto: # minimum rectangle - # dw, dh = np.mod(dw, 64), np.mod(dh, 64) # wh padding - # elif scaleFill: # stretch - # dw, dh = 0.0, 0.0 - # new_unpad = (new_shape[1], new_shape[0]) - # ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] # width, height ratios - - dw /= 2 # divide padding into 2 sides - dh /= 2 - - if shape[::-1] != new_unpad: # resize - img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR) - top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) - left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) - img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # add border - return img, ratio, (dw, dh) - - -def yolov3_onnx(src_info, output_path): - in_files = [] - if not os.path.exists(output_path): - os.makedirs(output_path) - - with open(src_info, 'r') as file: - contents = file.read().split('\n') - for i in contents[:-1]: - in_files.append(i.split()[1]) - - i = 0 - for file in in_files: - i = i + 1 - print(file, "====", i) - img0 = cv2.imread(file) - # Padded resize - img = letterbox(img0, new_shape=416)[0] - # cv2.imshow('image', img) - # cv2.waitKey(0) - # Convert - img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x640x640 - image_np = np.array(img, dtype=np.float32) - image_np /= 255.0 - # image_np = np.transpose(image_np, (2, 0, 1)) # HWC -> CHW - image_np_expanded = np.expand_dims(image_np, axis=0) # NCHW - # Focus - print("shape:", image_np_expanded.shape) - img_numpy = np.ascontiguousarray(image_np_expanded) - - # save img_tensor as binary file for om inference input - temp_name = file[file.rfind('/') + 1:] - img_numpy.tofile(os.path.join(output_path, temp_name.split('.')[0] + ".bin")) - - -if __name__ == "__main__": - src_info = os.path.abspath(sys.argv[1]) - bin_path = os.path.abspath(sys.argv[2]) - yolov3_onnx(src_info, bin_path) - - +import sys +import os +import cv2 +import numpy as np + + +def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True): + # Resize image to a 32-pixel-multiple rectangle https://github.com/ultralytics/yolov3/issues/232 + shape = img.shape[:2] # current shape [height, width] + if isinstance(new_shape, int): + new_shape = (new_shape, new_shape) + + # Scale ratio (new / old) + r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) + if not scaleup: # only scale down, do not scale up (for better test mAP) + r = min(r, 1.0) + + # Compute padding + ratio = r, r # width, height ratios + new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) + dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding + # if auto: # minimum rectangle + # dw, dh = np.mod(dw, 64), np.mod(dh, 64) # wh padding + # elif scaleFill: # stretch + # dw, dh = 0.0, 0.0 + # new_unpad = (new_shape[1], new_shape[0]) + # ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] # width, height ratios + + dw /= 2 # divide padding into 2 sides + dh /= 2 + + if shape[::-1] != new_unpad: # resize + img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR) + top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) + left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) + img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # add border + return img, ratio, (dw, dh) + + +def yolov3_onnx(src_info, output_path): + in_files = [] + if not os.path.exists(output_path): + os.makedirs(output_path) + + with open(src_info, 'r') as file: + contents = file.read().split('\n') + for i in contents[:-1]: + in_files.append(i.split()[1]) + + i = 0 + for file in in_files: + i = i + 1 + print(file, "====", i) + img0 = cv2.imread(file) + # Padded resize + img = letterbox(img0, new_shape=416)[0] + # cv2.imshow('image', img) + # cv2.waitKey(0) + # Convert + img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x640x640 + image_np = np.array(img, dtype=np.float32) + image_np /= 255.0 + # image_np = np.transpose(image_np, (2, 0, 1)) # HWC -> CHW + image_np_expanded = np.expand_dims(image_np, axis=0) # NCHW + # Focus + print("shape:", image_np_expanded.shape) + img_numpy = np.ascontiguousarray(image_np_expanded) + + # save img_tensor as binary file for om inference input + temp_name = file[file.rfind('/') + 1:] + img_numpy.tofile(os.path.join(output_path, temp_name.split('.')[0] + ".bin")) + + +if __name__ == "__main__": + src_info = os.path.abspath(sys.argv[1]) + bin_path = os.path.abspath(sys.argv[2]) + yolov3_onnx(src_info, bin_path) + + diff --git a/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/README.md b/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/README.md index bfd8ba1dbe..62f196a124 100644 --- a/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/README.md +++ b/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/README.md @@ -1,106 +1,106 @@ -文件作用说明: - -1. dy_resize.py:onnx算子修改脚本 -2. env.sh:ATC工具环境变量配置脚本 -3. parse_json.py: coco数据集标签json文件解析脚本 -4. preprocess_yolov4_pytorch.py: 二进制数据集预处理脚本 -5. get_coco_info.py: yolov4.info生成脚本 -6. bin_to_predict_yolov4_pytorch.py: benchmark输出bin文件解析脚本 -7. map_calculate.py: 精度统计脚本 -8. aipp.config 配置文件 -9. require.txt:脚本运行所需的第三方库 - -推理端到端步骤: - -(1) git clone 开源仓https://github.com/Tianxiaomo/pytorch-YOLOv4,并下载对应的权重文件, 修改**demo_pytorch2onnx.py**脚本生成onnx文件 - -```shell -git clone https://github.com/Tianxiaomo/pytorch-YOLOv4 -python3 demo_pytorch2onnx.py yolov4.pth data/dog.jpg -1 80 608 608 -``` - -(2)运行dy_resize.py修改生成的onnx文件 - -```shell -python3.7 dy_resize.py yolov4_-1_3_608_608_dynamic.onnx -``` - -(3)配置环境变量转换om模型 - -``` -source env.sh - -# soc_version:支持Ascend310和Ascend710 - -# 二进制输入 -atc --model=yolov4_-1_3_608_608_dynamic_dbs.onnx --framework=5 --output=yolov4_bs1 --input_format=NCHW --log=info --soc_version=Ascend310 --input_shape="input:1,3,608,608" --insert_op_conf=aipp.config --enable_small_channel=1 - -# 二进制输入 int8量化 -atc --model=yolov4_deploy_model.onnx --framework=5 --output=yolov4_bs1 --input_format=NCHW --log=info --soc_version=Ascend310 --input_shape="input:1,3,608,608" --insert_op_conf=aipp.config --enable_small_channel=1 - -``` - -(4)解析数据集 - -下载coco2014数据集val2014和label文件**instances_valminusminival2014.json**,运行**parse_json.py**解析数据集 - -``` -python3.7 parse_json.py -``` - -生成coco2014.name和coco_2014.info以及gronud-truth文件夹 - -(5)数据预处理 - -运行脚本preprocess_yolov4_pytorch.py处理数据集 - -``` -python3.7 preprocess_yolov4_pytorch.py coco_2014.info yolov4_bin int8 -1 -``` - -(6)onnx模型量化(可选) - -1.AMCT工具包安装,具体参考[CANN 开发辅助工具指南 (推理)](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools) - -2.数据预处理,用于量化因子矫正。当前模型为动态batch,建议用多batch_size的预处理文件矫正量化因子。 -执行以下命令: -``` -python3.7 preprocess_yolov4_pytorch.py coco_2014.info uncalibration_bin float32 1000 -python3.7.5 calibration_bin.py uncalibration_bin calibration_bin 32 -``` - -3.ONNX模型量化,具体参考[CANN 开发辅助工具指南 (推理)](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools) -在result目录下生成yolov4_deploy_model.onnx量化模型 - -4.量化模型验证,除onnx离线模型转换om模型命令有区别外,其余一致 - - -(7)benchmark推理 - -运行get_coco_info.py生成info文件 - -``` -python3.7 get_coco_info.py yolov4_bin coco_2014.info yolov4.info -``` - -执行benchmark命令,结果保存在同级目录 result/dumpOutput_device0/ - -``` -# 二进制 -./benchmark.x86_64 -model_type=vision -batch_size=1 -device_id=0 -om_path=yolov4_bs1.om -input_width=608 -input_height=608 -input_text_path=yolov4.info -useDvpp=false -output_binary=true -``` - -(8)后处理 - -运行 bin_to_predict_yolov4_pytorch.py 解析模型输出 - -``` -python3.7 bin_to_predict_yolov4_pytorch.py --bin_data_path result/dumpOutput_device0/ --det_results_path detection-results/ --origin_jpg_path /root/dataset/coco2014/val2014/ --coco_class_names /root/dataset/coco2014/coco2014.names -``` - -运行map_cauculate.py统计mAP值 - -``` -python3 map_calculate.py --label_path ./ground-truth --npu_txt_path ./detection-results -na -np -``` - +文件作用说明: + +1. dy_resize.py:onnx算子修改脚本 +2. env.sh:ATC工具环境变量配置脚本 +3. parse_json.py: coco数据集标签json文件解析脚本 +4. preprocess_yolov4_pytorch.py: 二进制数据集预处理脚本 +5. get_coco_info.py: yolov4.info生成脚本 +6. bin_to_predict_yolov4_pytorch.py: benchmark输出bin文件解析脚本 +7. map_calculate.py: 精度统计脚本 +8. aipp.config 配置文件 +9. require.txt:脚本运行所需的第三方库 + +推理端到端步骤: + +(1) git clone 开源仓https://github.com/Tianxiaomo/pytorch-YOLOv4,并下载对应的权重文件, 修改**demo_pytorch2onnx.py**脚本生成onnx文件 + +```shell +git clone https://github.com/Tianxiaomo/pytorch-YOLOv4 +python3 demo_pytorch2onnx.py yolov4.pth data/dog.jpg -1 80 608 608 +``` + +(2)运行dy_resize.py修改生成的onnx文件 + +```shell +python3.7 dy_resize.py yolov4_-1_3_608_608_dynamic.onnx +``` + +(3)配置环境变量转换om模型 + +``` +source env.sh + +# soc_version:支持Ascend310和Ascend710 + +# 二进制输入 +atc --model=yolov4_-1_3_608_608_dynamic_dbs.onnx --framework=5 --output=yolov4_bs1 --input_format=NCHW --log=info --soc_version=Ascend310 --input_shape="input:1,3,608,608" --insert_op_conf=aipp.config --enable_small_channel=1 + +# 二进制输入 int8量化 +atc --model=yolov4_deploy_model.onnx --framework=5 --output=yolov4_bs1 --input_format=NCHW --log=info --soc_version=Ascend310 --input_shape="input:1,3,608,608" --insert_op_conf=aipp.config --enable_small_channel=1 + +``` + +(4)解析数据集 + +下载coco2014数据集val2014和label文件**instances_valminusminival2014.json**,运行**parse_json.py**解析数据集 + +``` +python3.7 parse_json.py +``` + +生成coco2014.name和coco_2014.info以及gronud-truth文件夹 + +(5)数据预处理 + +运行脚本preprocess_yolov4_pytorch.py处理数据集 + +``` +python3.7 preprocess_yolov4_pytorch.py coco_2014.info yolov4_bin int8 -1 +``` + +(6)onnx模型量化(可选) + +1.AMCT工具包安装,具体参考[CANN 开发辅助工具指南 (推理)](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools) + +2.数据预处理,用于量化因子矫正。当前模型为动态batch,建议用多batch_size的预处理文件矫正量化因子。 +执行以下命令: +``` +python3.7 preprocess_yolov4_pytorch.py coco_2014.info uncalibration_bin float32 1000 +python3.7.5 calibration_bin.py uncalibration_bin calibration_bin 32 +``` + +3.ONNX模型量化,具体参考[CANN 开发辅助工具指南 (推理)](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373?category=developer-documents&subcategory=auxiliary-development-tools) +在result目录下生成yolov4_deploy_model.onnx量化模型 + +4.量化模型验证,除onnx离线模型转换om模型命令有区别外,其余一致 + + +(7)benchmark推理 + +运行get_coco_info.py生成info文件 + +``` +python3.7 get_coco_info.py yolov4_bin coco_2014.info yolov4.info +``` + +执行benchmark命令,结果保存在同级目录 result/dumpOutput_device0/ + +``` +# 二进制 +./benchmark.x86_64 -model_type=vision -batch_size=1 -device_id=0 -om_path=yolov4_bs1.om -input_width=608 -input_height=608 -input_text_path=yolov4.info -useDvpp=false -output_binary=true +``` + +(8)后处理 + +运行 bin_to_predict_yolov4_pytorch.py 解析模型输出 + +``` +python3.7 bin_to_predict_yolov4_pytorch.py --bin_data_path result/dumpOutput_device0/ --det_results_path detection-results/ --origin_jpg_path /root/dataset/coco2014/val2014/ --coco_class_names /root/dataset/coco2014/coco2014.names +``` + +运行map_cauculate.py统计mAP值 + +``` +python3 map_calculate.py --label_path ./ground-truth --npu_txt_path ./detection-results -na -np +``` + diff --git a/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/bin_to_predict_yolov4_pytorch.py b/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/bin_to_predict_yolov4_pytorch.py index bb932cbf33..9f58821caf 100644 --- a/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/bin_to_predict_yolov4_pytorch.py +++ b/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/bin_to_predict_yolov4_pytorch.py @@ -1,361 +1,361 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import numpy as np -import argparse -import time -import torch -import torchvision -import cv2 - - -def yolo_forward_dynamic(output, num_classes, anchors, num_anchors, scale_x_y): - bxy_list = [] - bwh_list = [] - det_confs_list = [] - cls_confs_list = [] - - for i in range(num_anchors): - begin = i * (5 + num_classes) - end = (i + 1) * (5 + num_classes) - - bxy_list.append(output[:, begin: begin + 2]) - bwh_list.append(output[:, begin + 2: begin + 4]) - det_confs_list.append(output[:, begin + 4: begin + 5]) - cls_confs_list.append(output[:, begin + 5: end]) - - # Shape: [batch, num_anchors * 2, H, W] - bxy = torch.cat(bxy_list, dim=1) - # Shape: [batch, num_anchors * 2, H, W] - bwh = torch.cat(bwh_list, dim=1) - - # Shape: [batch, num_anchors, H, W] - det_confs = torch.cat(det_confs_list, dim=1) - # Shape: [batch, num_anchors * H * W] - det_confs = det_confs.view(output.size(0), num_anchors * output.size(2) * output.size(3)) - - # Shape: [batch, num_anchors * num_classes, H, W] - cls_confs = torch.cat(cls_confs_list, dim=1) - # Shape: [batch, num_anchors, num_classes, H * W] - cls_confs = cls_confs.view(output.size(0), num_anchors, num_classes, output.size(2) * output.size(3)) - # Shape: [batch, num_anchors, num_classes, H * W] --> [batch, num_anchors * H * W, num_classes] - cls_confs = cls_confs.permute(0, 1, 3, 2).reshape(output.size(0), num_anchors * output.size(2) * output.size(3), - num_classes) - - # Apply sigmoid(), exp() and softmax() to slices - bxy = torch.sigmoid(bxy) * scale_x_y - 0.5 * (scale_x_y - 1) - bwh = torch.exp(bwh) - det_confs = torch.sigmoid(det_confs) - cls_confs = torch.sigmoid(cls_confs) - - # Prepare C-x, C-y, P-w, P-h (None of them are torch related) - grid_x = np.expand_dims(np.expand_dims( - np.expand_dims(np.linspace(0, output.size(3) - 1, output.size(3)), axis=0).repeat(output.size(2), 0), axis=0), - axis=0) - grid_y = np.expand_dims(np.expand_dims( - np.expand_dims(np.linspace(0, output.size(2) - 1, output.size(2)), axis=1).repeat(output.size(3), 1), axis=0), - axis=0) - - anchor_w = [] - anchor_h = [] - for i in range(num_anchors): - anchor_w.append(anchors[i * 2]) - anchor_h.append(anchors[i * 2 + 1]) - - device = None - cuda_check = output.is_cuda - if cuda_check: - device = output.get_device() - - bx_list = [] - by_list = [] - bw_list = [] - bh_list = [] - - # Apply C-x, C-y, P-w, P-h - for i in range(num_anchors): - ii = i * 2 - # Shape: [batch, 1, H, W] - bx = bxy[:, ii: ii + 1] + torch.tensor(grid_x, device=device, - dtype=torch.float32) # grid_x.to(device=device, dtype=torch.float32) - # Shape: [batch, 1, H, W] - by = bxy[:, ii + 1: ii + 2] + torch.tensor(grid_y, device=device, - dtype=torch.float32) # grid_y.to(device=device, dtype=torch.float32) - # Shape: [batch, 1, H, W] - bw = bwh[:, ii: ii + 1] * anchor_w[i] - # Shape: [batch, 1, H, W] - bh = bwh[:, ii + 1: ii + 2] * anchor_h[i] - - bx_list.append(bx) - by_list.append(by) - bw_list.append(bw) - bh_list.append(bh) - - ######################################## - # Figure out bboxes from slices # - ######################################## - - # Shape: [batch, num_anchors, H, W] - bx = torch.cat(bx_list, dim=1) - # Shape: [batch, num_anchors, H, W] - by = torch.cat(by_list, dim=1) - # Shape: [batch, num_anchors, H, W] - bw = torch.cat(bw_list, dim=1) - # Shape: [batch, num_anchors, H, W] - bh = torch.cat(bh_list, dim=1) - - # Shape: [batch, 2 * num_anchors, H, W] - bx_bw = torch.cat((bx, bw), dim=1) - # Shape: [batch, 2 * num_anchors, H, W] - by_bh = torch.cat((by, bh), dim=1) - - # normalize coordinates to [0, 1] - bx_bw /= output.size(3) - by_bh /= output.size(2) - - # Shape: [batch, num_anchors * H * W, 1] - bx = bx_bw[:, :num_anchors].view(output.size(0), num_anchors * output.size(2) * output.size(3), 1) - by = by_bh[:, :num_anchors].view(output.size(0), num_anchors * output.size(2) * output.size(3), 1) - bw = bx_bw[:, num_anchors:].view(output.size(0), num_anchors * output.size(2) * output.size(3), 1) - bh = by_bh[:, num_anchors:].view(output.size(0), num_anchors * output.size(2) * output.size(3), 1) - - bx1 = bx - bw * 0.5 - by1 = by - bh * 0.5 - bx2 = bx1 + bw - by2 = by1 + bh - - # Shape: [batch, num_anchors * h * w, 4] -> [batch, num_anchors * h * w, 1, 4] - boxes = torch.cat((bx1, by1, bx2, by2), dim=2).view(output.size(0), num_anchors * output.size(2) * output.size(3), - 1, 4) - - det_confs = det_confs.view(output.size(0), num_anchors * output.size(2) * output.size(3), 1) - confs = cls_confs * det_confs - - return boxes, confs - - -class YoloLayer(object): - ''' Yolo layer - model_out: while inference,is post-processing inside or outside the model - true:outside - ''' - def __init__(self, anchor_mask=[], num_classes=0, anchors=[], num_anchors=1, stride=32, model_out=False): - - self.anchor_mask = anchor_mask - self.num_classes = num_classes - self.anchors = anchors - self.num_anchors = num_anchors - self.anchor_step = len(anchors) // num_anchors - self.coord_scale = 1 - self.noobject_scale = 1 - self.object_scale = 5 - self.class_scale = 1 - self.thresh = 0.6 - self.stride = stride - self.seen = 0 - self.scale_x_y = 1 - - self.model_out = model_out - - - def forward(self, output): - masked_anchors = [] - for m in self.anchor_mask: - masked_anchors += self.anchors[m * self.anchor_step:(m + 1) * self.anchor_step] - masked_anchors = [anchor / self.stride for anchor in masked_anchors] - - return yolo_forward_dynamic(output, self.num_classes, masked_anchors, - len(self.anchor_mask), scale_x_y=self.scale_x_y) - - -def get_region_boxes(boxes_and_confs): - # print('Getting boxes from boxes and confs ...') - - boxes_list = [] - confs_list = [] - - for item in boxes_and_confs: - boxes_list.append(item[0]) - confs_list.append(item[1]) - - # boxes: [batch, num1 + num2 + num3, 1, 4] - # confs: [batch, num1 + num2 + num3, num_classes] - boxes = torch.cat(boxes_list, dim=1) - confs = torch.cat(confs_list, dim=1) - - return [boxes, confs] - - -def nms_cpu(boxes, confs, nms_thresh=0.5, min_mode=False): - # print(boxes.shape) - x1 = boxes[:, 0] - y1 = boxes[:, 1] - x2 = boxes[:, 2] - y2 = boxes[:, 3] - - areas = (x2 - x1) * (y2 - y1) - order = confs.argsort()[::-1] - - keep = [] - while order.size > 0: - idx_self = order[0] - idx_other = order[1:] - - keep.append(idx_self) - - xx1 = np.maximum(x1[idx_self], x1[idx_other]) - yy1 = np.maximum(y1[idx_self], y1[idx_other]) - xx2 = np.minimum(x2[idx_self], x2[idx_other]) - yy2 = np.minimum(y2[idx_self], y2[idx_other]) - - w = np.maximum(0.0, xx2 - xx1) - h = np.maximum(0.0, yy2 - yy1) - inter = w * h - - if min_mode: - over = inter / np.minimum(areas[order[0]], areas[order[1:]]) - else: - over = inter / (areas[order[0]] + areas[order[1:]] - inter) - - inds = np.where(over <= nms_thresh)[0] - order = order[inds + 1] - - return np.array(keep) - - -def nms(conf_thresh, nms_thresh, output): - # [batch, num, 1, 4] - box_array = output[0] - # [batch, num, num_classes] - confs = output[1] - - if type(box_array).__name__ != 'ndarray': - box_array = box_array.cpu().detach().numpy() - confs = confs.cpu().detach().numpy() - - num_classes = confs.shape[2] - - # [batch, num, 4] - box_array = box_array[:, :, 0] - - # [batch, num, num_classes] --> [batch, num] - max_conf = np.max(confs, axis=2) - max_id = np.argmax(confs, axis=2) - - bboxes_batch = [] - for i in range(box_array.shape[0]): - - argwhere = max_conf[i] > conf_thresh - l_box_array = box_array[i, argwhere, :] - l_max_conf = max_conf[i, argwhere] - l_max_id = max_id[i, argwhere] - - bboxes = [] - # nms for each class - for j in range(num_classes): - - cls_argwhere = l_max_id == j - ll_box_array = l_box_array[cls_argwhere, :] - ll_max_conf = l_max_conf[cls_argwhere] - ll_max_id = l_max_id[cls_argwhere] - - keep = nms_cpu(ll_box_array, ll_max_conf, nms_thresh) - - if (keep.size > 0): - ll_box_array = ll_box_array[keep, :] - ll_max_conf = ll_max_conf[keep] - ll_max_id = ll_max_id[keep] - - for k in range(ll_box_array.shape[0]): - bboxes.append( - [ll_box_array[k, 0], ll_box_array[k, 1], ll_box_array[k, 2], ll_box_array[k, 3], - ll_max_conf[k], ll_max_id[k]]) - - bboxes_batch.append(bboxes) - - return bboxes_batch - - -def post_process(flags): - names = np.loadtxt(flags.coco_class_names, dtype='str', delimiter='\n') - - # 读取bin文件用于生成预测结果 - bin_path = flags.bin_data_path - ori_path = flags.origin_jpg_path - - anchors = [12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401] - num_classes = 80 - - det_results_path = flags.det_results_path - os.makedirs(det_results_path, exist_ok=True) - total_img = set([name[:name.rfind('_')] - for name in os.listdir(bin_path) if "bin" in name]) - - yolo1 = YoloLayer(anchor_mask=[0, 1, 2], num_classes=num_classes, anchors=anchors, num_anchors=9, stride=8) - yolo2 = YoloLayer(anchor_mask=[3, 4, 5], num_classes=num_classes, anchors=anchors, num_anchors=9, stride=16) - yolo3 = YoloLayer(anchor_mask=[6, 7, 8], num_classes=num_classes, anchors=anchors, num_anchors=9, stride=32) - - yolo_shape = [[1, 255, 76, 76], [1, 255, 38, 38], [1, 255, 19, 19]] - - for bin_file in sorted(total_img): - path_base = os.path.join(bin_path, bin_file) - src_img = cv2.imread(os.path.join(ori_path, '{}.jpg'.format(bin_file))) - assert src_img is not None, 'Image Not Found ' + bin_file - - # 加载检测的所有输出tensor - feature_map_1 = np.fromfile(path_base + "_" + '1' + ".bin", dtype="float32").reshape(yolo_shape[0]) - feature_map_2 = np.fromfile(path_base + "_" + '2' + ".bin", dtype="float32").reshape(yolo_shape[1]) - feature_map_3 = np.fromfile(path_base + "_" + '3' + ".bin", dtype="float32").reshape(yolo_shape[2]) - - pred_1 = yolo1.forward(torch.from_numpy(feature_map_1)) - pred_2 = yolo2.forward(torch.from_numpy(feature_map_2)) - pred_3 = yolo3.forward(torch.from_numpy(feature_map_3)) - - # nms - output = get_region_boxes([pred_1, pred_2, pred_3]) - pred = nms(conf_thresh=0.4, nms_thresh=0.6, output=output)[0] - - # save result - det_results_file = os.path.join(det_results_path, bin_file + ".txt") - print(det_results_file) - with open(det_results_file, 'w') as f: - width = src_img.shape[1] - height = src_img.shape[0] - for i in range(len(pred)): - box = pred[i] - x1 = int(box[0] * width) - y1 = int(box[1] * height) - x2 = int(box[2] * width) - y2 = int(box[3] * height) - cls_conf = box[4] - cls_id = box[5] - - content = '{} {} {} {} {} {}'.format(names[int(cls_id)], cls_conf, x1, y1, x2, y2) - f.write(content) - f.write('\n') - - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--bin_data_path", default="./result/dumpOutput_device0") - parser.add_argument("--origin_jpg_path", default="./val2014/") - parser.add_argument("--det_results_path", - default="./detection-results/") - parser.add_argument("--coco_class_names", default="./coco2014.names") - parser.add_argument("--net_out_num", default=3) - flags = parser.parse_args() - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import numpy as np +import argparse +import time +import torch +import torchvision +import cv2 + + +def yolo_forward_dynamic(output, num_classes, anchors, num_anchors, scale_x_y): + bxy_list = [] + bwh_list = [] + det_confs_list = [] + cls_confs_list = [] + + for i in range(num_anchors): + begin = i * (5 + num_classes) + end = (i + 1) * (5 + num_classes) + + bxy_list.append(output[:, begin: begin + 2]) + bwh_list.append(output[:, begin + 2: begin + 4]) + det_confs_list.append(output[:, begin + 4: begin + 5]) + cls_confs_list.append(output[:, begin + 5: end]) + + # Shape: [batch, num_anchors * 2, H, W] + bxy = torch.cat(bxy_list, dim=1) + # Shape: [batch, num_anchors * 2, H, W] + bwh = torch.cat(bwh_list, dim=1) + + # Shape: [batch, num_anchors, H, W] + det_confs = torch.cat(det_confs_list, dim=1) + # Shape: [batch, num_anchors * H * W] + det_confs = det_confs.view(output.size(0), num_anchors * output.size(2) * output.size(3)) + + # Shape: [batch, num_anchors * num_classes, H, W] + cls_confs = torch.cat(cls_confs_list, dim=1) + # Shape: [batch, num_anchors, num_classes, H * W] + cls_confs = cls_confs.view(output.size(0), num_anchors, num_classes, output.size(2) * output.size(3)) + # Shape: [batch, num_anchors, num_classes, H * W] --> [batch, num_anchors * H * W, num_classes] + cls_confs = cls_confs.permute(0, 1, 3, 2).reshape(output.size(0), num_anchors * output.size(2) * output.size(3), + num_classes) + + # Apply sigmoid(), exp() and softmax() to slices + bxy = torch.sigmoid(bxy) * scale_x_y - 0.5 * (scale_x_y - 1) + bwh = torch.exp(bwh) + det_confs = torch.sigmoid(det_confs) + cls_confs = torch.sigmoid(cls_confs) + + # Prepare C-x, C-y, P-w, P-h (None of them are torch related) + grid_x = np.expand_dims(np.expand_dims( + np.expand_dims(np.linspace(0, output.size(3) - 1, output.size(3)), axis=0).repeat(output.size(2), 0), axis=0), + axis=0) + grid_y = np.expand_dims(np.expand_dims( + np.expand_dims(np.linspace(0, output.size(2) - 1, output.size(2)), axis=1).repeat(output.size(3), 1), axis=0), + axis=0) + + anchor_w = [] + anchor_h = [] + for i in range(num_anchors): + anchor_w.append(anchors[i * 2]) + anchor_h.append(anchors[i * 2 + 1]) + + device = None + cuda_check = output.is_cuda + if cuda_check: + device = output.get_device() + + bx_list = [] + by_list = [] + bw_list = [] + bh_list = [] + + # Apply C-x, C-y, P-w, P-h + for i in range(num_anchors): + ii = i * 2 + # Shape: [batch, 1, H, W] + bx = bxy[:, ii: ii + 1] + torch.tensor(grid_x, device=device, + dtype=torch.float32) # grid_x.to(device=device, dtype=torch.float32) + # Shape: [batch, 1, H, W] + by = bxy[:, ii + 1: ii + 2] + torch.tensor(grid_y, device=device, + dtype=torch.float32) # grid_y.to(device=device, dtype=torch.float32) + # Shape: [batch, 1, H, W] + bw = bwh[:, ii: ii + 1] * anchor_w[i] + # Shape: [batch, 1, H, W] + bh = bwh[:, ii + 1: ii + 2] * anchor_h[i] + + bx_list.append(bx) + by_list.append(by) + bw_list.append(bw) + bh_list.append(bh) + + ######################################## + # Figure out bboxes from slices # + ######################################## + + # Shape: [batch, num_anchors, H, W] + bx = torch.cat(bx_list, dim=1) + # Shape: [batch, num_anchors, H, W] + by = torch.cat(by_list, dim=1) + # Shape: [batch, num_anchors, H, W] + bw = torch.cat(bw_list, dim=1) + # Shape: [batch, num_anchors, H, W] + bh = torch.cat(bh_list, dim=1) + + # Shape: [batch, 2 * num_anchors, H, W] + bx_bw = torch.cat((bx, bw), dim=1) + # Shape: [batch, 2 * num_anchors, H, W] + by_bh = torch.cat((by, bh), dim=1) + + # normalize coordinates to [0, 1] + bx_bw /= output.size(3) + by_bh /= output.size(2) + + # Shape: [batch, num_anchors * H * W, 1] + bx = bx_bw[:, :num_anchors].view(output.size(0), num_anchors * output.size(2) * output.size(3), 1) + by = by_bh[:, :num_anchors].view(output.size(0), num_anchors * output.size(2) * output.size(3), 1) + bw = bx_bw[:, num_anchors:].view(output.size(0), num_anchors * output.size(2) * output.size(3), 1) + bh = by_bh[:, num_anchors:].view(output.size(0), num_anchors * output.size(2) * output.size(3), 1) + + bx1 = bx - bw * 0.5 + by1 = by - bh * 0.5 + bx2 = bx1 + bw + by2 = by1 + bh + + # Shape: [batch, num_anchors * h * w, 4] -> [batch, num_anchors * h * w, 1, 4] + boxes = torch.cat((bx1, by1, bx2, by2), dim=2).view(output.size(0), num_anchors * output.size(2) * output.size(3), + 1, 4) + + det_confs = det_confs.view(output.size(0), num_anchors * output.size(2) * output.size(3), 1) + confs = cls_confs * det_confs + + return boxes, confs + + +class YoloLayer(object): + ''' Yolo layer + model_out: while inference,is post-processing inside or outside the model + true:outside + ''' + def __init__(self, anchor_mask=[], num_classes=0, anchors=[], num_anchors=1, stride=32, model_out=False): + + self.anchor_mask = anchor_mask + self.num_classes = num_classes + self.anchors = anchors + self.num_anchors = num_anchors + self.anchor_step = len(anchors) // num_anchors + self.coord_scale = 1 + self.noobject_scale = 1 + self.object_scale = 5 + self.class_scale = 1 + self.thresh = 0.6 + self.stride = stride + self.seen = 0 + self.scale_x_y = 1 + + self.model_out = model_out + + + def forward(self, output): + masked_anchors = [] + for m in self.anchor_mask: + masked_anchors += self.anchors[m * self.anchor_step:(m + 1) * self.anchor_step] + masked_anchors = [anchor / self.stride for anchor in masked_anchors] + + return yolo_forward_dynamic(output, self.num_classes, masked_anchors, + len(self.anchor_mask), scale_x_y=self.scale_x_y) + + +def get_region_boxes(boxes_and_confs): + # print('Getting boxes from boxes and confs ...') + + boxes_list = [] + confs_list = [] + + for item in boxes_and_confs: + boxes_list.append(item[0]) + confs_list.append(item[1]) + + # boxes: [batch, num1 + num2 + num3, 1, 4] + # confs: [batch, num1 + num2 + num3, num_classes] + boxes = torch.cat(boxes_list, dim=1) + confs = torch.cat(confs_list, dim=1) + + return [boxes, confs] + + +def nms_cpu(boxes, confs, nms_thresh=0.5, min_mode=False): + # print(boxes.shape) + x1 = boxes[:, 0] + y1 = boxes[:, 1] + x2 = boxes[:, 2] + y2 = boxes[:, 3] + + areas = (x2 - x1) * (y2 - y1) + order = confs.argsort()[::-1] + + keep = [] + while order.size > 0: + idx_self = order[0] + idx_other = order[1:] + + keep.append(idx_self) + + xx1 = np.maximum(x1[idx_self], x1[idx_other]) + yy1 = np.maximum(y1[idx_self], y1[idx_other]) + xx2 = np.minimum(x2[idx_self], x2[idx_other]) + yy2 = np.minimum(y2[idx_self], y2[idx_other]) + + w = np.maximum(0.0, xx2 - xx1) + h = np.maximum(0.0, yy2 - yy1) + inter = w * h + + if min_mode: + over = inter / np.minimum(areas[order[0]], areas[order[1:]]) + else: + over = inter / (areas[order[0]] + areas[order[1:]] - inter) + + inds = np.where(over <= nms_thresh)[0] + order = order[inds + 1] + + return np.array(keep) + + +def nms(conf_thresh, nms_thresh, output): + # [batch, num, 1, 4] + box_array = output[0] + # [batch, num, num_classes] + confs = output[1] + + if type(box_array).__name__ != 'ndarray': + box_array = box_array.cpu().detach().numpy() + confs = confs.cpu().detach().numpy() + + num_classes = confs.shape[2] + + # [batch, num, 4] + box_array = box_array[:, :, 0] + + # [batch, num, num_classes] --> [batch, num] + max_conf = np.max(confs, axis=2) + max_id = np.argmax(confs, axis=2) + + bboxes_batch = [] + for i in range(box_array.shape[0]): + + argwhere = max_conf[i] > conf_thresh + l_box_array = box_array[i, argwhere, :] + l_max_conf = max_conf[i, argwhere] + l_max_id = max_id[i, argwhere] + + bboxes = [] + # nms for each class + for j in range(num_classes): + + cls_argwhere = l_max_id == j + ll_box_array = l_box_array[cls_argwhere, :] + ll_max_conf = l_max_conf[cls_argwhere] + ll_max_id = l_max_id[cls_argwhere] + + keep = nms_cpu(ll_box_array, ll_max_conf, nms_thresh) + + if (keep.size > 0): + ll_box_array = ll_box_array[keep, :] + ll_max_conf = ll_max_conf[keep] + ll_max_id = ll_max_id[keep] + + for k in range(ll_box_array.shape[0]): + bboxes.append( + [ll_box_array[k, 0], ll_box_array[k, 1], ll_box_array[k, 2], ll_box_array[k, 3], + ll_max_conf[k], ll_max_id[k]]) + + bboxes_batch.append(bboxes) + + return bboxes_batch + + +def post_process(flags): + names = np.loadtxt(flags.coco_class_names, dtype='str', delimiter='\n') + + # 读取bin文件用于生成预测结果 + bin_path = flags.bin_data_path + ori_path = flags.origin_jpg_path + + anchors = [12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401] + num_classes = 80 + + det_results_path = flags.det_results_path + os.makedirs(det_results_path, exist_ok=True) + total_img = set([name[:name.rfind('_')] + for name in os.listdir(bin_path) if "bin" in name]) + + yolo1 = YoloLayer(anchor_mask=[0, 1, 2], num_classes=num_classes, anchors=anchors, num_anchors=9, stride=8) + yolo2 = YoloLayer(anchor_mask=[3, 4, 5], num_classes=num_classes, anchors=anchors, num_anchors=9, stride=16) + yolo3 = YoloLayer(anchor_mask=[6, 7, 8], num_classes=num_classes, anchors=anchors, num_anchors=9, stride=32) + + yolo_shape = [[1, 255, 76, 76], [1, 255, 38, 38], [1, 255, 19, 19]] + + for bin_file in sorted(total_img): + path_base = os.path.join(bin_path, bin_file) + src_img = cv2.imread(os.path.join(ori_path, '{}.jpg'.format(bin_file))) + assert src_img is not None, 'Image Not Found ' + bin_file + + # 加载检测的所有输出tensor + feature_map_1 = np.fromfile(path_base + "_" + '1' + ".bin", dtype="float32").reshape(yolo_shape[0]) + feature_map_2 = np.fromfile(path_base + "_" + '2' + ".bin", dtype="float32").reshape(yolo_shape[1]) + feature_map_3 = np.fromfile(path_base + "_" + '3' + ".bin", dtype="float32").reshape(yolo_shape[2]) + + pred_1 = yolo1.forward(torch.from_numpy(feature_map_1)) + pred_2 = yolo2.forward(torch.from_numpy(feature_map_2)) + pred_3 = yolo3.forward(torch.from_numpy(feature_map_3)) + + # nms + output = get_region_boxes([pred_1, pred_2, pred_3]) + pred = nms(conf_thresh=0.4, nms_thresh=0.6, output=output)[0] + + # save result + det_results_file = os.path.join(det_results_path, bin_file + ".txt") + print(det_results_file) + with open(det_results_file, 'w') as f: + width = src_img.shape[1] + height = src_img.shape[0] + for i in range(len(pred)): + box = pred[i] + x1 = int(box[0] * width) + y1 = int(box[1] * height) + x2 = int(box[2] * width) + y2 = int(box[3] * height) + cls_conf = box[4] + cls_id = box[5] + + content = '{} {} {} {} {} {}'.format(names[int(cls_id)], cls_conf, x1, y1, x2, y2) + f.write(content) + f.write('\n') + + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("--bin_data_path", default="./result/dumpOutput_device0") + parser.add_argument("--origin_jpg_path", default="./val2014/") + parser.add_argument("--det_results_path", + default="./detection-results/") + parser.add_argument("--coco_class_names", default="./coco2014.names") + parser.add_argument("--net_out_num", default=3) + flags = parser.parse_args() + post_process(flags) \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/get_coco_info.py b/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/get_coco_info.py index e0aa158183..e452569bf7 100644 --- a/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/get_coco_info.py +++ b/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/get_coco_info.py @@ -1,46 +1,46 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys - -file_path = sys.argv[1] -coco_info = sys.argv[2] -info_name = sys.argv[3] - -image_names = [] -image_size = [] - -with open(coco_info, 'r') as file: - contents = file.read().split('\n') - -for content in contents[:-1]: - temp = content.split() - key = temp[1] - image_names.append(key[key.rfind('/') + 1:].split('.')[0]) - image_size.append([temp[2], temp[3]]) - -name_size = dict(zip(image_names, image_size)) - -with open(info_name, 'w') as file: - index = 0 - for key, val in name_size.items(): - bin_name = os.path.join(file_path, '{}.bin'.format(key)) - content = ' '.join([str(index), bin_name, val[0], val[1]]) - file.write(content) - file.write('\n') - index += 1 - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys + +file_path = sys.argv[1] +coco_info = sys.argv[2] +info_name = sys.argv[3] + +image_names = [] +image_size = [] + +with open(coco_info, 'r') as file: + contents = file.read().split('\n') + +for content in contents[:-1]: + temp = content.split() + key = temp[1] + image_names.append(key[key.rfind('/') + 1:].split('.')[0]) + image_size.append([temp[2], temp[3]]) + +name_size = dict(zip(image_names, image_size)) + +with open(info_name, 'w') as file: + index = 0 + for key, val in name_size.items(): + bin_name = os.path.join(file_path, '{}.bin'.format(key)) + content = ' '.join([str(index), bin_name, val[0], val[1]]) + file.write(content) + file.write('\n') + index += 1 + + diff --git a/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/parse_json.py b/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/parse_json.py index 2661bc483b..4c984a0891 100644 --- a/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/parse_json.py +++ b/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/parse_json.py @@ -1,77 +1,77 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 json - -with open('./instances_valminusminival2014.json', 'r') as file: - content = file.read() -content = json.loads(content) -info = content.get('info') -licenses = content.get('licenses') -images = content.get('images') -annotations = content.get('annotations') -categroies = content.get('categories') - -with open('./coco2014.names', 'w') as f: - for categroie in categroies: - f.write(categroie.get('name').replace(' ', '_')) - f.write('\n') - -file_names = [image.get('file_name') for image in images] -widths = [image.get('width') for image in images] -heights = [image.get('height') for image in images] -image_ids = [image.get('id') for image in images] -assert len(file_names) == len(widths) == len(heights) == len(image_ids), "must be equal" - -annotation_ids = [annotation.get('image_id') for annotation in annotations] -bboxs = [annotation.get('bbox') for annotation in annotations] -category_ids = [annotation.get('category_id') for annotation in annotations] -segmentations = [annotation.get('segmentation') for annotation in annotations] -iscrowds = [annotation.get('iscrowd') for annotation in annotations] - -assert len(annotation_ids) == len(bboxs) == len(category_ids) ==len(segmentations) # 255094 - -with open('coco_2014.info', 'w') as f: - for index, file_name in enumerate(file_names): - file_name = 'val2014/' + file_name - line = "{} {} {} {}".format(index, file_name, widths[index], heights[index]) - f.write(line) - f.write('\n') - -def get_all_index(lst, item): - return [index for (index, value) in enumerate(lst) if value == item] - -def get_categroie_name(lst, item): - categroie_name = [dt.get('name') for dt in lst if item == dt.get('id')][0] - if len(categroie_name.split()) == 2: - temp = categroie_name.split() - categroie_name = temp[0] + '_' + temp[1] - return categroie_name - -for index, image_id in enumerate(image_ids): - indexs = get_all_index(annotation_ids, image_id) - with open('./ground-truth/{}.txt'.format(file_names[index].split('.')[0]), 'w') as f: - for idx in indexs: - f.write(get_categroie_name(categroies, category_ids[idx])) - - f.write(' ') - # change label - bboxs[idx][2] = bboxs[idx][0] + bboxs[idx][2] - bboxs[idx][3] = bboxs[idx][1] + bboxs[idx][3] - f.write(' '.join(map(str, bboxs[idx]))) - f.write('\n') - - - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 json + +with open('./instances_valminusminival2014.json', 'r') as file: + content = file.read() +content = json.loads(content) +info = content.get('info') +licenses = content.get('licenses') +images = content.get('images') +annotations = content.get('annotations') +categroies = content.get('categories') + +with open('./coco2014.names', 'w') as f: + for categroie in categroies: + f.write(categroie.get('name').replace(' ', '_')) + f.write('\n') + +file_names = [image.get('file_name') for image in images] +widths = [image.get('width') for image in images] +heights = [image.get('height') for image in images] +image_ids = [image.get('id') for image in images] +assert len(file_names) == len(widths) == len(heights) == len(image_ids), "must be equal" + +annotation_ids = [annotation.get('image_id') for annotation in annotations] +bboxs = [annotation.get('bbox') for annotation in annotations] +category_ids = [annotation.get('category_id') for annotation in annotations] +segmentations = [annotation.get('segmentation') for annotation in annotations] +iscrowds = [annotation.get('iscrowd') for annotation in annotations] + +assert len(annotation_ids) == len(bboxs) == len(category_ids) ==len(segmentations) # 255094 + +with open('coco_2014.info', 'w') as f: + for index, file_name in enumerate(file_names): + file_name = 'val2014/' + file_name + line = "{} {} {} {}".format(index, file_name, widths[index], heights[index]) + f.write(line) + f.write('\n') + +def get_all_index(lst, item): + return [index for (index, value) in enumerate(lst) if value == item] + +def get_categroie_name(lst, item): + categroie_name = [dt.get('name') for dt in lst if item == dt.get('id')][0] + if len(categroie_name.split()) == 2: + temp = categroie_name.split() + categroie_name = temp[0] + '_' + temp[1] + return categroie_name + +for index, image_id in enumerate(image_ids): + indexs = get_all_index(annotation_ids, image_id) + with open('./ground-truth/{}.txt'.format(file_names[index].split('.')[0]), 'w') as f: + for idx in indexs: + f.write(get_categroie_name(categroies, category_ids[idx])) + + f.write(' ') + # change label + bboxs[idx][2] = bboxs[idx][0] + bboxs[idx][2] + bboxs[idx][3] = bboxs[idx][1] + bboxs[idx][3] + f.write(' '.join(map(str, bboxs[idx]))) + f.write('\n') + + + + diff --git a/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/preprocess_yolov4_pytorch.py b/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/preprocess_yolov4_pytorch.py index 95df9a16b5..f5991e956f 100644 --- a/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/preprocess_yolov4_pytorch.py +++ b/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/preprocess_yolov4_pytorch.py @@ -1,65 +1,65 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import os -import cv2 -import numpy as np - -def yolov4_onnx(src_info, output_path, bin_type, frame_num): - in_files = [] - if not os.path.exists(output_path): - os.makedirs(output_path) - - with open(src_info, 'r') as file: - contents = file.read().split('\n') - for i in contents[:-1]: - in_files.append(i.split()[1]) - - i = 0 - for file in in_files: - i = i + 1 - print(file, "====", i) - img0 = cv2.imread(file) - resized = cv2.resize(img0, (608, 608), interpolation=cv2.INTER_LINEAR) - img_in = cv2.cvtColor(resized, cv2.COLOR_BGR2RGB) - - if frame_num != -1 and i > frame_num: - break - - if bin_type == "float32": - img_in = np.transpose(img_in, (2, 0, 1)).astype(np.float32) - img_in = np.expand_dims(img_in, axis=0) - img_in /= 255.0 - elif bin_type == "int8": - img_in = img_in.astype(np.int8) - else: - print("error type") - break - - # save img_tensor as binary file for om inference input - temp_name = file[file.rfind('/') + 1:] - img_in.tofile(os.path.join(output_path, temp_name.split('.')[0] + ".bin")) - - -if __name__ == "__main__": - if len(sys.argv) < 5: - raise Exception("usage: python3 xxx.py [src_path] [save_path] [bin_type] [frame_num]") - - src_path = os.path.realpath(sys.argv[1]) - save_path = os.path.realpath(sys.argv[2]) - bin_type = sys.argv[3] - frame_num = int(sys.argv[4]) - - yolov4_onnx(src_path, save_path, bin_type, frame_num) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import os +import cv2 +import numpy as np + +def yolov4_onnx(src_info, output_path, bin_type, frame_num): + in_files = [] + if not os.path.exists(output_path): + os.makedirs(output_path) + + with open(src_info, 'r') as file: + contents = file.read().split('\n') + for i in contents[:-1]: + in_files.append(i.split()[1]) + + i = 0 + for file in in_files: + i = i + 1 + print(file, "====", i) + img0 = cv2.imread(file) + resized = cv2.resize(img0, (608, 608), interpolation=cv2.INTER_LINEAR) + img_in = cv2.cvtColor(resized, cv2.COLOR_BGR2RGB) + + if frame_num != -1 and i > frame_num: + break + + if bin_type == "float32": + img_in = np.transpose(img_in, (2, 0, 1)).astype(np.float32) + img_in = np.expand_dims(img_in, axis=0) + img_in /= 255.0 + elif bin_type == "int8": + img_in = img_in.astype(np.int8) + else: + print("error type") + break + + # save img_tensor as binary file for om inference input + temp_name = file[file.rfind('/') + 1:] + img_in.tofile(os.path.join(output_path, temp_name.split('.')[0] + ".bin")) + + +if __name__ == "__main__": + if len(sys.argv) < 5: + raise Exception("usage: python3 xxx.py [src_path] [save_path] [bin_type] [frame_num]") + + src_path = os.path.realpath(sys.argv[1]) + save_path = os.path.realpath(sys.argv[2]) + bin_type = sys.argv[3] + frame_num = int(sys.argv[4]) + + yolov4_onnx(src_path, save_path, bin_type, frame_num) diff --git a/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/requirements.txt b/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/requirements.txt index 8842750f94..14059e3d54 100644 --- a/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/requirements.txt +++ b/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch/requirements.txt @@ -1,5 +1,5 @@ -numpy == 1.18.5 -opencv-python == 4.2.0.34 -torch == 1.6.0 -torchvision == 0.7.0 +numpy == 1.18.5 +opencv-python == 4.2.0.34 +torch == 1.6.0 +torchvision == 0.7.0 onnx == 1.7.0 \ No newline at end of file diff --git a/ACL_PyTorch/built-in/cv/Yolov5_for_Pytorch/generate_data.py b/ACL_PyTorch/built-in/cv/Yolov5_for_Pytorch/generate_data.py index 3ccceafb0f..06a030669e 100644 --- a/ACL_PyTorch/built-in/cv/Yolov5_for_Pytorch/generate_data.py +++ b/ACL_PyTorch/built-in/cv/Yolov5_for_Pytorch/generate_data.py @@ -1,65 +1,65 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import os -import cv2 -import numpy as np -import argparse - -def preprocess(img_info_file, save_path, batch_size): - in_files = [] - output_data = [] - if not os.path.exists(save_path): - os.makedirs(save_path) - - with open(img_info_file, 'r') as file: - contents = file.read().split('\n') - for i in contents[:-1]: - in_files.append(i.split()[1]) - - for i, file in enumerate(in_files): - img0 = cv2.imread(file) - resized = cv2.resize(img0, (640, 640), interpolation=cv2.INTER_LINEAR) - input_data = cv2.cvtColor(resized, cv2.COLOR_BGR2RGB) - input_data = np.transpose(input_data, (2, 0, 1)).astype(np.float32) - input_data = np.expand_dims(input_data, axis=0) - input_data /= 255.0 - print("shape:", input_data.shape) - - if i % batch_size == 0: - output_data = input_data - else: - output_data = np.concatenate((output_data, input_data), axis=0) - - if (i + 1) % batch_size == 0: - output_data.tofile("{}/img_bs{}_n{}.bin".format(save_path, batch_size, i)) - - -if __name__ == "__main__": - """ - python3 generate_data.py \ - --img_info_file=img_info_amct.txt \ - --save_path=amct_data \ - --batch_size=1 - """ - parser = argparse.ArgumentParser(description='YoloV5 offline model inference.') - parser.add_argument('--img_info_file', type=str, default="img_info_amct.txt", help='original data') - parser.add_argument('--save_path', type=str, default="./amct_data", help='data for amct') - parser.add_argument('--batch_size', type=int, default=1, help='om batch size') - args = parser.parse_args() - - print(os.path.abspath(args.img_info_file)) - print(os.path.abspath(args.save_path)) - preprocess(args.img_info_file, args.save_path, args.batch_size) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import os +import cv2 +import numpy as np +import argparse + +def preprocess(img_info_file, save_path, batch_size): + in_files = [] + output_data = [] + if not os.path.exists(save_path): + os.makedirs(save_path) + + with open(img_info_file, 'r') as file: + contents = file.read().split('\n') + for i in contents[:-1]: + in_files.append(i.split()[1]) + + for i, file in enumerate(in_files): + img0 = cv2.imread(file) + resized = cv2.resize(img0, (640, 640), interpolation=cv2.INTER_LINEAR) + input_data = cv2.cvtColor(resized, cv2.COLOR_BGR2RGB) + input_data = np.transpose(input_data, (2, 0, 1)).astype(np.float32) + input_data = np.expand_dims(input_data, axis=0) + input_data /= 255.0 + print("shape:", input_data.shape) + + if i % batch_size == 0: + output_data = input_data + else: + output_data = np.concatenate((output_data, input_data), axis=0) + + if (i + 1) % batch_size == 0: + output_data.tofile("{}/img_bs{}_n{}.bin".format(save_path, batch_size, i)) + + +if __name__ == "__main__": + """ + python3 generate_data.py \ + --img_info_file=img_info_amct.txt \ + --save_path=amct_data \ + --batch_size=1 + """ + parser = argparse.ArgumentParser(description='YoloV5 offline model inference.') + parser.add_argument('--img_info_file', type=str, default="img_info_amct.txt", help='original data') + parser.add_argument('--save_path', type=str, default="./amct_data", help='data for amct') + parser.add_argument('--batch_size', type=int, default=1, help='om batch size') + args = parser.parse_args() + + print(os.path.abspath(args.img_info_file)) + print(os.path.abspath(args.save_path)) + preprocess(args.img_info_file, args.save_path, args.batch_size) diff --git a/ACL_PyTorch/built-in/cv/Yolov5_for_Pytorch/img.png b/ACL_PyTorch/built-in/cv/Yolov5_for_Pytorch/img.png deleted file mode 100644 index 752d68e6af32a0e14dd71d2e4ab687bc214d8d05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 71967 zcmdSBXIPV4voMUHASzN6P!Z`OU3!zE2nwM{N4oTm^qvq=X#$EA=_pOQ)Bphzl_I^@ z5JE?KhX4WIJE;44p1sdG-?^^u{qypNkbB*;X3fl+K7>9|eMENQ#svZb0y4$N4>bq~ z&OIR@AT&Eq2z*mS3Kk_G2qaK^cwfugc)2d1{N}vTe2a;jmG$28>ZOY}#f1E7NlkA* zf2|TCCEzLYme%yVxK1Q(oaKw_#b0M0T11N_bx;s8sop;GDp2mnb(Hw+uM;-+#H3S) z&qie|i8()T2EVhsXiyW!Gg4~c9A^P4Et=VuMkB^dz3KKzy!O#JIJLA&%>@UM@7+UKDRzdo8$KbRo-^-=E?1@;U9 z!R>FoC7l#IXs5(b0q{PMpT_~erl-eRI=B34-bv5y2f*BS4fj?E5VK*Ob8R`c zcHdbT7K~|!VITeECw{~^Np_{KuK>6NYM;epXL`q2e=&I!)3Hmk`tu&xe14MLqq2C5 zAHJV0k`u=_-i;1pF{m+!sk{j6qjL^_wm`dN$r17TGPj8}3AoIF&w7Bgc=2rpe`hbc zzPRia6$3J0X&EUVdU{}doCN!=6=?#*d`)NM-l5h#88G|F+SIWO0Ri&TeLPX_`Y##o zwXLXO#*bEy2Dt*Z8~fRFty60v*2xJ7y8TZNnBw$9=J}&}2AS~@&)BFcJ&Ow`xy>4g ztZ^a$ojE+1K%ZHI`5KHmWYbw<57GAM>COKB;3&-SN>_hAfKK-%Je<4MwdMUswnvS0 zR-2D@lGZBoYh-+$TY%=rY%yEFs=H55SBc)ljC6duS1xlMW;`;owa{5YKeh#6`hf<2 ze7%)qaAnzvPAV!bF?W6s-76k|gzy4yKM_2AoCWM5j*abPVc6Kek~90AVX>SR>j(i5 z4LwCvySe&38jiBcu&p?o6%r2dnX-R(V`W{#GnJyK4hUkIMvDg}lau2kzkN@M!+)-a&Ur znbU!Cl*2}vFtGEbb9ioAMY!d_)dHIfLh_rWhCC3tfE*KKoE|D+sv#qVq-b}aLeym3 z?g;6}3#m|EJN{<5Fw0(4&q|YYeGQ^Jk5xTc01!noo}!}QZ5zrk&*c(=gskm2D>dd} zxe)8qE*py21{E}k1OVIg&M7}GCQJ4B%&#*`^Bri*roq0Klo@_1 zG1m-0CC~~)0umE3zYXmSTH6wT9;repHU2URDwAJmO}x4uzK6(nvqLaY153Nf2>}5V zO1cu|2?#qWMNlCHR=0&7?1IupBieuk1VOTRp(1v3moynI{@D#hg!Pf*T7;;u;Q@a= z&ECYNb`D}TbDfopxAWph2yT|Shcy(=!e=X=w~klp>3^w6Ztp|rw~t#5?R(xQn=g8x zoxh@W8CPcAifi`TcfqT-b9h>$zpM5B>;_20c+zWmlMiaS<1~Fp2GD3o5!9sBz;Q0# z%h4=8{5;1lDpo&BKY^DVH=>}^@3?byY`1dN8BZ$Nb9hp9-|I|q_))yQP>ivS<4w#x zGv4{ejddM9!`)WH&C@tz2IbB=Q~y(R|KQjr&9UXuA#woc1W-bj`q$gH;Dgq+92{yx z&B+C!`ty%%yf7Z|ehVTk_7h!$R%z$nT4p`aRn$RsZc5_pb_|XJhNNx10{Ww_0~nk? zJ;<}0=+!>-b_~fvnMqRo%i^wK)Y^JJRjv6%lrBXnSFhyBM&ai|&vc|S;`UpkyTTbR zP#K?}_TU)+0#fM|3)aq*)#IL>53AW0io>b06GM_G0U3VQFOepVw~3EemTF9nfW?7k zzZUO0u2(zdS-Dk-L6LkWcPPpnzl_?ET)>t22FvVYBfxn57zjO;jAsjaduv6FhN4m= zN0(2o5g{@+w0gk_h=z|u5bC6BSQt)W57XCmpnev3r|tAO{P*1A$vygZ$Cogyp+gGW z%kOum$#APLUT78NzyGFAi!H06k>E1suz9P7o_jIBE2+J`wFKdj6zZ=ZFpX6!ied}xxI_QH!3(sEAb(++OrHAnQKm_R#yht5EtvYf9J1D^uMCz2@mv+H}_~qHU9)g}qL$oK4 zr?chk4PuE-?A*FMz}$dJko|SJf{Y-`L1X<#Kkeby0l-U;Q@~qvScd%&1`q(SI|$E} zjtM~9Fb@ncXz=#jO(COFTpaV+E#k7M?K-mvBA+DKw$)0 zp7P;Z=gkclC*oKkC+9UUSExxUVF>xYwVW6f(cMRa`?rOx0K?d85;O=sm3w&CL8CCW zGnp{`YU`at>47vm&!xl+WY^jjK+PDuixPO-Wz}N7-V19eDybA5#W6|@=E%rJ-6*CV z_Fs)jBko5s6rX$8$DGf;?(An^z3_nn&>jS)r&Rwgh9hHGv3jUD!CMl313McT;PaY+ zcRhSH?%1yWJH~jO1@8jsoNhB$vJ@3ilXT9YE@xZwWh93_A>t>vt1FNEd?u;lrYki4 zAuSfocfJ9+rbC+~K_`v-*a_?0e}-4{TzESryQL>F=rduLwvkx)dj1-g%_CfX1V!C< zSEidDyw4OUgc*2R-W%OYw-T`S^SGV`cyIeu+#+VSp{w!b=EL@R9QWD+JZP~i#T(S; zoOw7%4QU{N5X3EfQeGuQ)Rx;K-e1HW)DhKXQ`kF|qly-5*Q*$K06=d~0jbPli#p@D z{KxHUMb_;*qabm7oae^OcY~yR(<)~2zP?Fl`tG)O_-{J?>&+1Xw*(VH#F+lj2cxUl z*<(aX2o$6JX>Wa+$apYjKL8)H8IFjRSr^L6c zCYy4;0aw5{>cIM%VgjKdA>v4f4RbtYluju#Ena~*lyu}jE7A)kL>#IgsoG8qj$l%53?nQ3;rF+|F(un95WT7XzzL4Oqj(3gum?FM?NywA~$uS9L zNc^aP0l26HPtM@=RQvgPRWCrMa=y+b0Gg2N=#$~O=YpWs^_*|CJK*np_1deKNR9#b zpfhEg1@9o_{dN$l4&jDdHSsQ)@n*eNsJYXd??S zuz{4P&PajF?nCRn9DiwtH}X)#C*Jj?prh5Ho!9UI8A0iT95kN`0ROjRBO+d!H3>Ti z)+9ps*CBADP{WHK2AX%u#`hvSKNjzI-2j%peu39Gf^8sBN{-W#1H3g@A(`h?>lf;J z?qXU+cL9W(PQ7-kC_e@K(4!?u_ze5DF!N<)} zUYAegVDm{T_aF}*K1?P(V&XZ)UwnEw6rh^NEqLXj<>oa_mxr3g*~yS~E;Klma%%qy zfTr@#-)OdT0Rj=}w03;X8$9mp4l^29Y59)%xw}|E*_B2?NooB6^7ta&)R?Z~eb0@Q z6d**obxc8yBez;C>344S6gsIsqWT-uz{#-%Cw~>D-H+th=iz3H3G64?htD5wft?{@ ze_JYhhNC-M4}LPZs&>?|6@|-jRFisp@QnJEKj=S?Mew;Pfd$iYl7DD_V!Pydz;RDPhJ~{qaw6}hgW!N{l(vVMkMLcDMUZnzwbtgfBVAL!5Lq9lOm<%r0G zLsfLrC9wZ>e{_Fpe_nrO|F{0metnzg6Y*~oG@ShHRo$VOr0@> zmLr)%?heG4(yVFUb_KmWH23Ps@FMLejUL(QS?xm0Jg@NDe+LyV_J69xc({h0T}{^G z=1H;}KFW1+R6ACI&1pgOLHfG-=K5=wj&o}jsk+i`FhkRTjr59s3m<`sbw}bwI23Xs zeM0;u$ou%J3e#OSS)WY92iOji;q*1|{?cBic*|bEM1bwVP_ef?r`u%WMGfOvFUw8@ zE?y?_LPKI7e1Ql4m@|7x$ysr>M7y&?vNHRe$w^aMY?ekv<-3(}mW`<*b_P%q3zte` zFNotUngX?~CD0KgVCx|u==h@jT@!7t!Hhs{rmuGX0Bp<)TMqAQSAYr5apY4+4+}U&0 zG|Ce{l_r^A$yLewboOw0(Ja4!BMnX+Dq^vyTzw~fao}Y%S&!Apf(b6cK#7lkxWGwe zD@!#cqb>WMgXBXI!=+p*tRsrms9D9+_8#?@u5(p{Ba%445MM`M;4npHOXcqTsEjeW za{u8?t>5>AAn`I3p)<9wspT}Fl-y^N@}j6Ve?gTh1wM~k(ybNlP;4O3298{8FzaDLKn(AOKN6?@yW?(RnwB_1`)f#Qe zf#T@PVNOSbTB%g+8|icgZ0m4~)m9rx$Ll!-@@-nAxFR|CY`FVWtJWIH!-lW}IsMbX zs@wfMt^$yNR+Xo!SBg8|#ru+)4!w_RNzRnMTby8MJUV=HsQ1>4B+hpQ*`$@S51=}r zW0S;6zG6=|^_q3(8?v_^eaTz7AnRi?W;vX21 zZEDb&(z-(tnIoUZ_nl*<+l%w>)O==AJCsD5ug^j;g`-9$HnW6?fb#nT6&7VRWH@;P z3)K6a9x*vt*hpU(*?D{{5RtHI)Dz^~Xlk^-(zByktQ?S=k zSXp~G?IR(Rudo+=!CYJJEO>=XvCMa$Wp?sYK9wtIY=GlRX}a>#C=j=m1lH|2Ey3(v z@_)i(F5+Cm$6gT=$}p=c{GE=1vwCE8h2uPy@lZT(TtF3mqVF9$3S%kNA(BWQ?HRoK z=^BRl>avZY*YpO`p)$f^;4AloU`G$2nrZjHTG=1vWul_oTJ)hToXO)v01h|SV2QQCj;gEAxYl*RUM3zEJ-fwgB#m3c}I+e;H4?7%%zV=x)5 z4PA&{5R~+4xcu;8!@)n-O6?E#(wU?Qtn}9HaT~ev_p$Zy6$Q90%RYQqp!RnvZT&=h z@z%{v2|9bDzwXv^sLJfMo*Zp#LAIl$w-3{fRxtOTA4e^^C#Lbp#4Zf`g@ov(9lxc) zJM;uX^n{SYhOL~R?~0xJg(M3XP|{dGgzrMqps}azrc|+Cp=!?l$Yx)n!o!Bph2QSL zA07Jd{sh6F8};vQ3xUcnc_pQ!bh-WaQ%)}X0#+j01w81n=I=LJ=7d-Z-zanqHm0C- zsr|b~dhVH`JfQ|EtXu9CW1w{T_Fp`goj@GBr7424AkzjRAy)?frdeK=EuAGi8ExZL z0X6Q2guEa6`}66Y#Hav0r%;d<4VzW7xK4F^QMRwyEXTM#6fjmz$TX`_rCv~geF&1T zBI}$-O@#msyp5w=0pl9iJ0L%q?QYZuC_VTeXykd{t_w*f2I86<^)(i(dy6LTN~)=Hk$$;&_pn zEQbtbd&Ve_Cf~7A{d7y;_MIqWzHaR*2_r8>2#ryIY{S#PE7Oi7Db}v zj#5R+{^iCG3as?~M2#z!=$Y5yR0+R%vQGM~3#5PfcB zQT!+qmIv88LrItamoxC2rOo;9HFW2!Ps^eN`|EwrA4pIA3NNf>9d8#Z5m1+_VL_h@ zTNQktrZ}V+Jn5(`t8+Cli>f9Z$tUh*Jsf+<&0Nta%skcpcbWPIjmg<4Q@UAr3oDF- zvu|m4l&=y(?Pz1Fk_Ko#r}~w}GmXwkUgYm>W?#wRj|=zoC}|#Tlj7@RgJPW0w+*})$#!;_+*+4>G7|FSi%PZe?8|PRI+~q z=dZ6p@|`n$5SMU6({ZfgoDi$E;1^*$q`c_!DTA{jAM0EN&Fu%48!sm08eR1(kn)~@ zF}z&4^Dx=y@2XeK7?6sUS;j(8BcVp9f}vvVDxAPK2(6Rv5k~?(blN3+**SDz^h!hv zzH6OPg_eLj7`_vGGU0Wul={D-_J)Mv#E_Yt@?2@mosHph$D2y6M2Nbnw*iJGgR461 z_KFMoz21f?4i)g^9uZ6ttD|e4nDI$tq%P>i<#SB%JU=c2m|3DKJN0L^EJ7wz>+G%ba|%6s~&xBnx7b)ySNLlzlO;( zpvBJi%Gs%Lhlcd^{=r~w%4yTh4{;fYt)^s~Bqz-;;c_=El4Z`IJ+nHP)>%YU{-Ss| zyam#y0+|INe*oubfEMtrW57eSIUh<$aUmUlsZNCq(S5$^nNMZbT?epd764#X+0fD{ zJUaCiKnS$MKe%gj&w7(* zTH&pM2Vb1YG8TBuXX)FG#LQimF=P1?`K9+HOZn|agLtQQ!2tjb3Q$+M^B->Pwx$(? zUmwVRYM>DlI4WumD)4CJ|n|%m!WxjuVA&391!nb$^nS+LsK5)A1ndSR; zN=e8r97g&!LU8T^ooQE=#=QUv4;Hd2)~y&?)P7uXtx_rD|D@YK%wGiiUbdY#W1;I< z@D*)EYc9Yi>ZI;p#ptL0UBp=59zzYVEng16V4D<|(^>C+m=Qenk(Ph|l@WJV&7 z!z>oL=IS9iW)w9r8mCK+bCH*~BJ#O}D+(^8!m@pbJ&>_jVqa(JOa{D-I~Q?Lx1{%T zc@C$cG$l)-sgF;v*)5(z$5~f zdOX2*An@Q4Za}W83Cy89@yL)Ka5oqkuxcp*p>Qrev<#|tZ8#hk)9(e~4YeTG81{P3 z_#1ep$XL_i0M&g**SKL0AK~#O&+G6oDtkw5k>2KI9Tt7&__2QvHHP5V3|Ap$EH>)QEjkbLVRXb#&Rx_;R6@N@3xY`%1qgj_u;; zpp{#(vGCh$tE7~|r!f_6a5mB2GN=iy`id{wz?WLC9386^C)0}&NmK24%{cWExN@?$ z*ZG#E7Rf({P~&=6zk}~~ur1#gOJ2UeEGd?pu_g)Ja{Hb2Typ`J^_d=)oJh5R1JPsj zER{W|wVyvF#?~75f`HlV9iDJ!j}hRXBi=&t%S&W?QY$2VhTm?z{N8fQy)V+*492+Y zu^qskD)X!`b)H-r|1Cut6w!5Tp5{Z%Ob3&~_R@Y}lK^8JF(49Y}61pY;b zymBwa=lfEevD-!ue9ht8wmqNsfbPj5gl2w7ir$Zy(&Y(Y%-)jXHpIg8)MY-*MGy0Y zQ11lUc81Wuz<)u^3LF!iJ?1x)Psc8D)QmWQw5oNaoCIM`!ZCYN5=RLh&TVmN!$Qnc zA*b$i)O0_2b~UT#MKk#$(?mhDU`8F_i!%Vj|K-z*sREBc03Gp<#92JgwWw( zBt-1W{{=7}en<1teL#LrnBnlbfBt?E;PLlk@eVjFdloP(Qo;CFPwmGyix6%f@i!R80pY>ePxy|}&b8R~<8orQKj%YNoYcMpDXzUNZa)iISMY|i$J`lH&7Jd$MqLl46f$S&b})1tM6F|BRU z=k?#0j@L635u-PeY0}(q(%${qwDg#scw6}qauA)Vb#|iT^dWe#$e%MoWzLuKt4FwF zo|YwT{G@(~jEmDR>(ZRdpzNl&OmoWpf9Lx13eM}r_jq?JoX;oMjv!@trh|x8QJp#n zWSUW>1?57R7=~j(zkG|&&<$E>s1x6@ZnhtnCtzhb>AkPmlyjMfP(}wI1Y9A*ovgAz zO6KMv9G!f7UdMerwlO)DXk6Oi4n}Fq+$R}-XtolA8)l=HynaJ#&HJ<2^1YF}@RM0% z(G%+8gIp$0Ywn>_7XRQBS<$p*58HAP`_1b7fq@%XO@SEHM20i^=Pns;P{-D{OTYec zqjt_}wDXm6Ib`_s7d|dS&*3wGMmwk~>Rc!+HSy?*ch)Rj1z1g;Z1; z*U7G(J-*(1Dte$R%92|7UbfXrb1?DDY$RWVy191mM0rxPC1^a+ z_4rj;aAhb*^Al8HIcb?6*|%TP3aBUOa$AfW>-|uX8w&wO0Ydua9yRccnwYWF3NQD@ zXjEk$O{7|EPU}t*s*s`#z38Cd#}0E$SPt6rHK?N2u#q?5Dk~}YvHQ`W*eTJ-!@*yX zbui1}Xychjg?8e2#t89eU(mgJ%h+exNegrED1k^W?V=kE`>G?m!<$tr0StF!-vC#^ z^b-^kuzHCluZ30qXlMF7&ed4k^%jdRvwpRfd2C#{YmRT84%_0si5((^VPHbq<;bUaZr6i2e@Y!2q@L{T5p?gc2o>fqp|-@C zm#GdcVZ^(VB6L`z&Js7F_4t|n4})gedAG1Tx1aliG(Od>t%$JO!Q_b$JQKa?7eB3x z4Qlrk=^EE48CH~zN8gh%oZ#!JxSMZGZWrt6D(S`3WJGOOY&d-fY9jNfP-WD%Imsvv z86^w^ywDp&C$c%`NBZK0>qrj6J0m#9C*w7J6sP4$@0-=egsz1p^6O8sD%yuQE9y3k zZo4Y@=l`IALKH%PLvyX(7!)(@4ODaMMaVy^@?XEoqm5oZA!UX_DySqgp^?|HmKIHo zB&9P4rDZ?wyq6kpMDoEEdQyk){Jy>(Nn|))=Iqbed#-Hsjf@s;4dpa~+B---wz3Tk zjZa4EBE;dox!=wmM`zL|p)X76s1Ml|KKC2T8mY1^QuYKbUB>ByCKxyYO88*#?faWV6> zR3d(mo;?oJ5tl10Vo=UcTtUGY?hWs{HJ6Y?*mw@TJ#+J7c;O2iw|0fApOa7Rb*Tr< zC8PS|KyAFNQxvh^G2I+>SWPzU)!NbIAXR1IL2@;Icj%JeR_)Ia+m2fyji16V137rI z0Ns9y-vs5pXmVQRiwZHvNcY)-vDRok40n-Z0)JNnxTn5eU(c zGeA~$O%ELKb)k*Rw`&-F#Y;HJF1fUzfl6FAe5b&~$v^_#B_ijrqZ-9}ZFq~7lq$er zDp_`dFG|kL$BOQO%m*FeG;Bk&$?@ivH1?~^^AZ`)wwDp`*Kc~aU1%*w#Y`>Ul_Rdc zn%w-#0wT*>r7WEvjU7GF2IO^_as+AOG}hE&Ptwadhh78Ea~ZpUM}rKPqv(5O(Tywv zE0iNF@sZDXo|ImR{ZP04R@g6wLxNxg$>(QikCa1Qtst^Jj}I^$w}>E;hK1dU=6UWT zY8Qsd9LR2A&7n*Vg-uA47$mAXD!Xp1MBtjz*w|shYdyD{x@JBT@mXOpS^CdV(;@Q9 z_*{`4DXwQZVuOl}=f^@ws>qI%Wz-I6^PMKIt=#Ui5)ouqqtVxm=q~ZGSWcMyya8L~ zc^nx_BlUG}-rZ)Wgql(oEe2-+X-j<)1aTm<<58(rLG>s8cGS}4Rm2O2Ctbu~v>H0q z*j?Rxv*@N-ejHG0FLMKk^_Ym~0OD`Y&H<=zhdmBjp>Mh+ihT6iP%GJ)gXzKSK0C{vtQmfuqx{2()=+o-c9 zW0NrWmcqUp$rs*mso<+v(;?HR!{?w1;!8N{2s+6y@ZCZ?q4n?^hvqP4-Rt|>yab`P z9~wdWrCwSLP!?kFf(AT)w3)^|T*-_SifFN!pcUS2zHFOrPKxvVF;aBL8q^pOfn4vYn#I;{Aqn~~0L>9tFQClp`( z&KrR^i-yjr!nJnI9@@`7y7JyJw4}1WDY>8tbZ<7o1&W{_Wud0wxmC>Hcwt~TTI@#F zw<>P4P{7H)2ANp%qx;gZDaMrZbbu(Yydf2;*dEDlC$bJI`ob>ZI(~azfqxxknJ)=N zny^hQyn0jeQ@UecsPWjOW)Tg+dhInHC%h2|3@-C;|8bexE3F{o?C~=FV@aJAwo3_4 z2?0+$dFPeS9uF^93p5_LjUPeDA^VfVf)S;x>!<`asL41d2ED8)Vy<-zd3%O|Tz2=x z1H;P61I+}yyQ&A1BLTLRWv(7yVrQ-Udnn^F;F zxgQUM&^4HxzlTTVMM4M{?oAq5mQy6}r*l*CXNF{SbTzC;JIiSq&HQ?4Ms65}MJ72! z?2kpft>AKAYlC~PR32?azZV8liLLi}&xO%E;>IUirpa-t;w8M|3!ynGY?rq!N|W!7 zXoJkn94bFbrG^#qn=G@h#}8kyUf)`<$86@W)$O;HK(fth1G8vSw&U+)NOeXc`+-Ry~cJPA0dy)EJqvj59+eX(w99)rz|EScErc#j=_4b)nc1Y)ld zWxmGg@Xa+I)~(DYeRctB-C!K8R8-<7#W_9oVta7W9%OiwSHHwr>}3BLSsc&WpjY_X zpTqEKl848p0P&%x%`?Ah$P^o~!AH)3r3a-&bpyp1vo_RRn6iUG9*?o~^Rx;--45bo z&!6p8jAqq<1br4=ZxesgGZK_+-0*&RF-JgMDyV16Pq&)OYUt-G#i;MLkke~Ih`;_{tFS@Uql5Rl#y*XmDU!f-X~Vt^uZX2n*M8v=svkv$E78;1;|Nt;FloUF^r7EI z0gjimTDcoQxS`&5N!-%B6}fBFcFyOtxn(q5)bnv)xn#(jwC!RA%cP=k!V@mvsE+0{ z%Rp`c4MDrwc6El5RTb>P%LJY^Bha6*kZ%P)Nk&d%gMsfkku42h-#>~+pjUKQG0E`aZ>kTg4mtO*66f6fR($mfb7%&s%qAbtx#=ivd-!NQPr8 z(dm?L?eb1`jn>+5f2e8`_D21qrRv^_Ch01%?IqlX_zTXsZRK|ZFry2)3n=eFF~DCh zv~!q<|ID`q93NzBkcvoFt*f@ivr+X3wR`XM*^u@RMl8V^4YjKy3cOrqyBH$dPHz7~pT#!Lj9hYD}M&tcf z(oS6;qZcs?yV~kl-P-;WZU?$Ped#lHg|#HNh!76b>FkPUkF^8Og6Vc%4fAO7M<}Du zpmVs@GY_6e8!2)u&tbZE!0E$52h$=vaaUx*$OkY1 zmZ2k3Z=cWTGMm8S)Olq$i=2Fcz(Zm%OjEb|d$HX_e8taODP%Yo5{GP0MzZ@rtB8Jp z%SuxGYF$o}DF%Cx1>!9dIQnJ;LHJBJJu=xv#Kt7VE@XK5^EAreLMJCu2j9%DTxOWEYvM#wh|a) zuju-?m+}Mgdb)1G0bqm!%dDcxb}u9HMQ&NDZQbylJ2W2tZ_=1P#D_N*6|al=l(Irv#?qN;R+_ z{$kBTB|gOxlh?F^jjOkp16{)Twjc-6$Z+~q)T$pdYg1STuVVAl&M9z#nP-9R;~Si8 zLp;5;Zu&(V>rc84Th^Iy+fy%FmZBD=4Yb;6cyEAx<@tCuH0FJ;U@akDYptHz%P$py zAU>HAaD$sDxy;+i*m-Dz?US$YkOR($7@uo8;0bH=+#0?4mnU4h1Qb4#54Qb`_eOQr z?s^@QgHQOtn7yCdjtsauhkXSV7UoJiYOJvMXORaMv4W`%lMd@TmhZepSQh2a777v{ z@3h%_<=@dS?!c+*>T&VeJsZ?{g_OaEsz91V=)PZd;glXHhoN*J+M`IvwlZ`>F;)b@ zd@s0HlyBrnotLJnE(wWI1{m{1)NIyrSDl07c1F+T%6cO20GA1d)x09Og~*eMA#0j3 zT=v4R48@JdkkoWj@Y!9B zvrb#cY*1?ZH^g|LCPdci z?ay0V0(v-JMHI{DOzUTVjuuxxWUANx#4QjT~U3>=DpN zLTwmijob!;x818N%cCD`Eqa~JTdBg5_5jG zrp>DoVMYA5Mnn}V@k%?73nJDO*od3=r_!M&B21kO{hUyfLG3!n+{#Rcp7gq~5FH>{ z*)BWL{5wDM&(xq8HPFzZt?~2D<^B)Mz{gGNanNxd4uHq2(Xbz+|40`oel%wRI0I>j z|2BE3>5~4&=+T7=JP^$-jX<@M%9;AQQLl)6j`f@fl~&w%P1pf< z{VYC%NA?&{*e!P`b(O_MZW~vN7A+cVMjR{~RCW$BJ}a%|FIC{-=3^_aRB~?9g;77K zVD;y(U?&DU28tNW!NFzDBN7G!^)f&~>b90aQvjU_qIb<#SSRvN-&myPf0JOHJnN1L zQ}gNVP~7h(wrv?caN4ab8&mbl|8g#D8TA2R{y7DqWB-&x9e++nm0oe%0ne@JuDQkz zwVfQhoveaS&OoBe#Jc7f=sQB)s(VPa^r%7oSF!KE%@TfbGOu^sb8bwSRLlrf(eeArWESq8-n8oC&Th$@gv?NTOH}A-FKDj_|UdbG42ZjYtN*0>;y%HRBcR ziN$-FNM?LGy85Nm`QX97rKLTRIudyI?3iQ4spf#LraD^1rVlUDzbYQ0E8e$(6uimrszTve{Uq0&<658rEg$r{ zJf6VtLWEjvn?7K)>mzK3u4BvM=}O}{S&=BDv#5!0yUy(BO+ba{n?-xsIS(fkz52He zox>kZ^;|6}_F9!*{;Mw1P#^SN{NPtn$^3Q9n7w9sNAQTr2QEYqPiX(^Ugmrut2a>0 z>q&1TxmaSGm#TC?>%4uC!wZ%EjR&t+_|c1tKo?cKxTn#-c7oul`_L>uMR8}SOU53N zr{NQJzX~R1n6HyJe-#$5vnhme$kogb3tKBac|*RBA}ozDrnT8|b=Z~mc{dwz-FyPp zMQ_1?*0tm@8;!%B4?64Z=*Gor$77my@p-rwP`&=p;N1hJa3qwO+6L|nP()&{|FUF? zFJEDY$fXW@VK~`D1AuQ&MuN`n(%VQ(0H*MLDR`u}`LDUNucGwl7#! zI;Ss0EDT>yB00Wd-5C(gp!TixctK`a($%izcSSB*>apTsXGPLpBkzNDiK723E8R-_ zRaVj#45+G;adHUVc;~k<6M2{><5ntJ;(oB)1lOJ2-eC8H$pte`Q2?GXP++`5PVdij z>nUZKlg~jFgRC35AB9f5)Q@lVK?C$dr!3MjF+7~h@>^TTo)xVJFGPpyc5HuSX9%a0 zeA#s}Nz&=>f0W<`0wKy)+u3C5IDa)qOooWP1dej&5-t=dif&lD=FHNmHDqv49gL%6 zT~eG2rGe^i@$&trz4h;XZ+p^yk{JJWm|G5Ol3TBbc!1`z3@=P|V)k_0<&_rL$?nLI z;UmmqFjsfnCKhO2PYmZqbJJG=mQvR;n7{$aZ!$D6h$#0zB zrQc}=Z?gBb?5$yr$u|ncO9t_$Vq#|Q#8cz*Rs1lKX;{Hiw`V|Ees68d87T&IasR8< z1$6ZPkNs;}F*2GkpXNdA;5{z1D^Rw2e_S_b&QR%`Ro}aY%2@!KI3yA-_s3ScLUf+o zFw{!7aHDWJe_DM4reyx~%K-+I42QSy@?&C<^OgfH;48|xdNuN{r2$+WB~o{Hk;VCg z;=Pvwau?7%Qx}F!O-jXo@$=ss_}G)fh|Yl(-%JA*m~IDv!L9TIXls{`&uYGf&DZ*H zA#=PhzU0di>Ql%4hRI(B1{i+&-JCe7#ky{-lB-AMVLv;)v5|}A-1lb$-Ws(cg7gOz z$R`DbeE&zIR*MZ{ImOi!2v`QA)h#Mc3-T;BY?3J{g2Xq{!Yax>pBDrvH)auUcDOe?gsM`KrNgn$_rxibNx z_eY=10)_N{P!|Avh%##_!yLTy0kZ5vS2?pgK186|NPTSAx|*{` z-NH^&lklUyRPJAd1P~#F{U+sNF9dsgpP|fO`djzqxBCO`D-XEsAa&4uvx zxSoqbnE?$o|D;Fd10CmJWHDv`cquO_ZkG_+9{R58$2BbK_CQkC7Y7L38+lbkTQZ2`Xy^DO#kD^9U(qT(t4oHgx7w4;w#mx;5m zE>L?Xe3{}r#Ju=@y(Xl+M7SZGF!!qliV+9JctX%WBxvT031Fo+oU$DrwHjtIo?%uG6IZRK8Zd zc*9tCsFlr=w7uxvMxi%DeVEIVVIZvsT)+B`6DBsoBccaHSHoO)o_X}!?iH6N>4yy^ ze>G42o_+YHFNJSYzIo4Q`$z7yN^0DbfcbdD%pB;_c%_?POR1b1yX6halHyYz@n22C z>;(fr%koXBfP0Ojg3Xbn&73D+wsfo_kZ|s2L4abHTtij8;LusFt$pEz`fhe^1^jrj88l;0wzAaK9 z;Acy-Sq>Ak)j!0u@IS57Nc#fO{K-#)`aOvF2?^o^pO-M0gEC-`=`lxqxAw=#Tt<3w z%%hl?Y5t+gYE<@jf9Q&;I{41dpD2MPcrCFexcaq{zL8DMG=*Ow7k-xRf3ydG49kD0 zFm!R8vNBN0Zgj>8M*lPDXKryA^$Ohh3`uRc!8wA&spJD0JE|Lum8GSz#n(d z{@DdEFM&*d@W4-RUOIzcj#u}1n|J=tS@0u&a`Ks{$^rTOL05o+adzmoE6^KSVqucS>9JxNUqfiCnz&|Vyj4QpoM0~G z2+ETwWUCiG)8}h0^JevxJ#UBsYnl=FJ$X&ZrD5D>|JJ4PeNRytVa84^^Qe|lXgoy;`yT2``-dy|Psdgu1f}r;47BW*S)-awZ6b z2IMcNBN#OHqP$`=W3SlJ0$ye$$aavyz@w`t5GE-2x-ee^nACmW> z!@E@DX^P-&7!~?lxF=s`qeR=lI=7-&QRCD?koIRFct4k@C*KR z+JHp)EqSj5WRtq&iZ3!tCtx9LBz~kz%cJ9qqo*8~_UC7C*5Ky0>-rFpWE6q(&@E6L zw++e){<#_o0sc8ada%p`q!8ojj9FsQ*<&c{I_>o>MIm15>40RGw#8(i9^O%t_)3U8 zf5{bQ2LeJXiSCsn&($W6!A+!zv7&==zL%fjafC`3P`vo*@OXmO=%Oad;%l_kC3?Ww zC z9kE||_1pV!(J@B1RPge%gsq9L6OBaGlUC4CLR}1}rE08J_2HGY;o~sf?DI7hJKuBt zMb>i?84hAiP&gT|Nn+XslwBIGH>I?wzf&mX#{1UH=v;rhq?nfMvF+6i$a-*1jnF&e zMR<*Ru4)R$EV})3jAFL-4N6$=)1M0r6=< zl!|v(E?E0?mHROyIG83r=IM{(tLqn#aL_QZHP=vFso8X~)MelJ-kJLe#P<}<98C@+ z4bFmS?~^E57LF^KQ^j%5ScUPfH=AH>fDN22Av-C4_a}l0fR_A zx9n*h=5Ci|wE#(2Bcn|JK6kj8u2@+(>c(ico0;NK|F$obDNfN5RPH&3MU8RPQK;IFayZY;ig$cG zS$jnloE*1BgEg;Lix=2xUa)x)dpj$hgV*j-oFC9Cn|;-hR&numW(1H$t84?+*`>Q> z%7zw6`QCqM2kPkKRa&HX9%)ypQ>ZEICUBTO8Xsqv>GPe+wuDJ}zAAI>D(`soC3lZw zZAGe^iEn4~Wv8N}>WbPT@nR4`K=S~F(v6#sNtu>>VX}PO-kB!tuNgvxT)?6HO13o7 z10yiQi8uRwR-7Df9o2epI_I68ayP3`mxV3X*5NAk^?MEA0;OJfL}UrdXd*toX1`K2 zQ?Nq+$YNSJ#NHRe-QA&8k=q+gl*_}dG3t4^$wyyx&!k>q;m!~d8&oFNo%Tt2v}ctx z^F3%4xfv{=Zx`2|HKg4ZE$9IDOeG6`7CXT{YXLnI!}r6We?8$v2Z<%2G;-mL!N56TAuATcOSsikgmw~7tNB$4 zO$kilH)8NeQN`TF8Cy!nRAMlXZN6(zgHw1)B)wCtbZES7o_!M2PR!VM7%(KPYx$H8 zTj8hem_#?(>z!bXI(z`#{;)0EqcD<{c~sdkqOL9gdHCBI|M%;rsk3*t+V5vg-R2~& zgZkE-bCR+Rf~t7uG1Z_$fp@fl`d_G6l%9VG(IA+jG&$>yIPuy8M z<#HV>>&Y+b%ZH@PIY%z=nExNT-a8Pk_G=f`1yPcS8qp$xDAD@_5rPmTdWqh9Z!<&? z5k&7K(R=S<^j@NOMz6yl7>t>-J_wH9$?M7zDW+}3E*j? z>LWmZmCEL>Oz2Ao=CyDgHa!bl*KI|s!^Ld{VxLe^hY3nF8rV*?@jhU)eYWQ()gf$_ zaoKrx;tFh^kve;M0h<-|({x9ln`7thYy*P}7iQNQ2`zWWgm;$`+|$f(q3$C>E!U@4 zWx@bA$+@eafyOYw{DG(Z=E>(tCb`@Kc4hbB@4mvkn9uDmmDFr8R{Ke+(@El`854Sk zl_wdB^@2vMZUftFi3bXD|0z7$KwL0rchXj; zM>z95DNZ#qm=9(%Fgh9&+aV@rI|^yV}*#E_;HJ5qGa-3og^x zZwzeQqqh3ixRCi@@1a^d;?wwGD-`AAfoI|PYN<1}{B|#TXxU@5u5s!5)d8tnvAcT7 zir!;n?tMS`*UPc{Pmj%Fy_OWF>q%YWr~k9G_1}$Sfb-J9?TBz&yP<8>gBH4j$bK_pkN?|d=9jE`S0#_?MmxNsMJlc#7;isz1H!XUb>7ocr@^QB=9s`E?50e@RiE^8DL2r*@ZB zhUX$=o5~c0InrfE!f*HQnR(ed*?Yap<}-o<}-t0X=k{Catcpqb`qxt04Y@Ef zOT&}ZZ$&wlN>hKF5~HJpm*e({T#BT8w84c6B#!av)=X|8Eby+wa5=%927~+QtwAdz zE_+(DzLPXac>UUD8cO5!a-`wUkX*J8zE9~#EL6|hR=f-fV|fnJU5i(o>_hYi9s=X7 z(|S?*Liph3j}LnvBF!pizu8v{9dr-71M&R($a&^xBSXJ8FfV!ltMa(pm0(%Vb)DGi zes8AbTZS51~dUP(a^3{{3c^v3x4WfE<%VrzIkQ}qjFOR<= z8~DUlzN0#W)uj2^xH8+O`GZ;(p@xLSckW@vMoM;POZFXV0ug0Q=DehTmwHY}@vxq? zGctdq`_Dpkrlc>Xm^YE;yem>9FUg^i9d(j5djj$=U-W<=*fAcd%ahlaSHQqdF2Adq zXu@3WVTMNZQ1pb_ir?t@DQ2p^dTkK0Hiki%dvXWTsPLRQAKxChua%|1Kv z4LpfIHq66t=}YTkW=($t=Gd$bjqB$*C!Fu#j}%#XIuZM;`s@kgkCyox_v4wWXb<|?O1F2sV7E2F|AZq@p}AAt7spC{+s zc$RPda&#%HYvUbze`p9KzCp(KZT!6|>l<LxGf2-aT5OUz0!npF~(>2JRqS*}KFZ?i3@ zOntLYpqiy;;E#5L+@L_0`Rw`_JM|Rxye!Osb}m|g8sn}`o421VeX0zlAv9kCIs!2q z=d-_aF6_5}NnVu2!Wpqf3R}ZDGn2&lKvu?X@ zG(w1lbco^6;Q1U5N4XN(eN{^Us7qZ}t|c~=IEYbf*MO5Vm@EF;~qF{uWwxr-OpxZNY+t>PAU2fR4 zu_hPMOecD?#%1iYmW7&dSUFpfI$tk;&MDCKcbD-pCZim^t1x;UvyI7zWbQ%!&hSKA zB$xS#N4H&J5f4GKT6Qg3q9CQ*E?M|zKA)Zo~3*KSlXnH>wbycA^zzS-Oej;P=D(hD? zS4(4<%8n)HTw7L)lT%Vc?c%(gm6p#(fPaeVR$Nib8{6mLw?KdXKkzFnKDcq+VLjLU zh(^XEioh?t*QM3j!CT|UX8_IkwV#0VqD3E=)o@#k{0q3xObT2KLyOaT@4_|LeEf9+ zxZUU{#b4LJv@EKUWhX4G4+w=j$)diuhZF(`u!?lh*XBUm@WJh_cPAmZWrm@0YzZGs zv~8283=r}eCtcq_S*{4cpqW4QZKga3-cS;%Ir@`Nt^0NA{mZK&N7rqFFEa4&sc93SE%Y2GR5&4&6^r$(vdb`Pq5Xr6WE^I9Ql^1+d>avBECoFjqbLbHiK;NW|7iGU& zcX~jyf^GzMA;p%A@ymbRTn}A^Wpq!wB7x21e>WdL_O)b4>9b673Kr7biSv0hjKj+DJDShSpl55hOM;p)dUHN?^weOBn^$ih#y#q2F z07&OFubb!4Z44Q`P6v_zqv5%Sw57<(HPl-3>C1S*93RxciUyOSZbD znp>F@LwIE@W$j5KrL)qt!s^b?W>&#fahye(qqAv7y}5uEB<_4 z^G1I3R5@p+?WpzMOW1$@)Au0bQ}!WZG%Frf0RWbiXleZa&{C&a0G8Q!9@Ub3Q|#w( ziUp1LQX>Q=U;pWHK17UbT;!ioJ0*9uJ-gfGi8BH;u-x@_SFx_5Vr-aKA@M#45wvpZL{CK}oX21I8)C+iQVujTISWOSGQZVX8^SpJqZc@ z66*dq3tgqgt2Yt($u(7dUW#nJH29iQHgK@x3t%^B(@;cC#ZGRcV}b@3vv$Iyt24W^ zH4|hQQ&NvQp?!G|eP_(sNOJOKDxfuY#UJ1s_gTw3tmmc!*gpn1MNX?B;Bp63$nOQ? z_yqtdK_5WIjxek&EVua&uqF{b;yiliu7ciJ5fRFj!<TVlYzu#CEOw2}$^bwncDe^leg zF2KL>$>^WA1t8|2l7Ti*f&|yQdhz#h_KmHJPogrLvMf@TS9(`z(?YK>=hX{ogcF37iMy)7U$?!ev`RmJ z6Rtmni;*q&DS8`lqGg-xA0ZPD|LXS0)6E=S=O+(UA=6jmGBCF}D+_&|{MI=uLOQ}^ zCevu3d0edS=7cuEzu^-pYOa`uWR)I$KJm>?#jPf=)ncJUpqe`E^#Pktu@W%WpD(;H zJce(fzc$M=XI!<(D*g@byIxS&$?q5=yzHsHH~}B|kn6z5jk@V&y6(XKb67kQ7V+)^8M4;WE~7Y^+mQPvl`c>m9_a(_5;s7v_wdgSs7Tpg+0B}{V~&! zKIRBJEP6qNgsEUH_l%g0tW}eAxMBWXN@TSS-_{H5o=p=DU-ieFK;m zu6<>_5&SdFn1c@~>gv$cM!AZWD`Po#8 zO)+}zgoNvYU$=Y#Z-&MuoI7sG%f7yMIA{wNP4O1CxO?~j_JV7z$Ys=H$;nm)(8~WX z5C94Ik?Nl%n*d?NzB2Pu7B;`P?N#4_#V`LMMfuhI4?vAEN26CmSjC|6`TYlXUcJGF z^V!cwP4ntf2;Pzdxo-KYSsHDot<_ms!zax>&kK_ck7N%Y%zWsQu5suq(@u?tzm{;N z>X}rI;3|I?&t&JN&0@gmxsc}Yld1M$i(NmNSu;z$CJ71GHM{Wg!!I*M2H4h=fE)5q zm7KrjGbVSz1G${B*$}E=_R@_nLm1WEO#8!qG0oz=URP?+$H4gQf03^OxjB^N2?^Ke zJix84&aNLF8_75z%Y(MSg--I~cQy2ADcX_b{VpnYbKr8?TXS_1-7F0;7&P-cco=sA z9t>T0{vwg&g}!BW3Dq-VR2gX%QPaau@ihY|d*QlZCA!9n3YSV)=Y622G_0M>?(2(5 zS>I!mu}!oQ;dFoK3IA#r$_<<)f@JkXgPU$jcF4o?!`Cf=Dpdw9QJSB z674>503StjBbN=FK6;rsXw2Z1TS6~=b=A<|JyvX#NPGa?5+I&`FUZ&*@O-!oLI8sa zK=L-#08j+2GpZO00c8{5j36c!AyFX-M*z)28`QB-So~*hk>1wi$PM$|OS`1w>b{Xj**0$DoNK5QVN&~gb=;d5V=@v? z&P=YH*HNwakpjqxmPd0RVJB*LQRlg^0Z}R?&BYE_ka0yN#Ka_f$i7s??gb;T8n|8; zO@lPlmM~q9(0R6F;w8f@Yzg!Q91`)@>8cgk4%a8T4avJ+>zVpJ7d{_+MBhk#tE?^j z0h$-4?F}Bq`Uj-plcyvtTMtPIObmiR&7C|Y2U)Y;96wkk56S+R1L+25y7ZshTR#Zb zL=S-_YJjYqofL>WYd_&(Q|d3+HyZ>E6GW{#7N7c41@Q;nx4u&hVMoFpg(+E9S7=9QTV%zr?_;00DaPK$@{p!$#lCnw@PZ_mhTI2 z$6ojPa$D_Tyy4g}$&cYtGk z_>PJg$2QUav)}0e{g{g(kmBQ4N3t<~Wu-@!?*&vEvoxhKl5lMTqBmR(?bY$M`8h)b zNN??A-mpJ8&O@cAPHb_DGKQhYv$;w;)jaRqAH_ta6@@s^`%wv~)rQ!ywbiwF7FOl< z7cZpdh*QYIbp{18H?)ySEqG~|34b6HpX`{){X4YfrTJ+Y*^=b~aQ{wCb5 zT%9|t;Im85R%~=eUKBe;Qn(vQ3!6uLxX{xi7uTg1PwPUs2RW3o#m(r;QkbrZD~k29 z*a)2~Uiya_eHROS@?GqXxeNvWr;Q1Zi?q`%vC(T?yQ9;a^ijjn-`fJ$B`vLz`?_|J zb6DGkc+b__JJmfUHaYYuZPf zt%PC$NR8B#S+)79pyy4;JN{?_E!H^m&`x-|qkywhbqhZvbhb(geR!UG^HuA2XY^Xr zAP&f8MGC(HcQd6T#rR<2Y(m&$A6_o=*{RVx;*iuM0}CT9#~=NC>7i}bb=B)BrzTlu z1lMvi<>u&S;L2nER}DbiMB}1wgW%dpj75(VJ0wuWdXD%MnA;{_40}tkjl0(|mTn|4-J>BGeAC~B= zNJEZ7-DymZqy5YWNgbm!@c39wfl#v?`*@SMthpgZSIa?$WIuiUOYgAC1^qgxO83Iu zK+uI5rZCIxyf^jr&%1C{+!3~<5yS7L#*LJg5@nOA<1aLyaw%{CAH$PkidJW5yUQT9 zIQ|1ke&u;FI6Vp*-T#g+4IX_d&?O89`5$Z;V%juUqCSf(sGnz?Q!vpY>;)uLd$^8W zG?&(zavk#)KG_jEY3X2txBBVzI?3WwFeKVHlDc#5H#Ki#VmNDHlYx-!PiE@@3)`(F z>cMxZmRHG-M{z*>4WI1r(5i~ODkTMEDA67V!u_D4NAq_=Iw#Y0C-U)Oqu~ez=q_xF zeN7G&6IA=tl?zERpk)_!ZH+FBl-XrKBlKR1fT;R9Lz_Iq7`KxAVnRN?6WN@y9NyEy zLF3j=x*a8FzfNg1w;IwU8cucSK+&4oowG-0{NCQoyzpcO2P|=DwhX_9&7@O}5uy5= zEZXV);1>7>uduxB=8jD>esikhfX^+Atr>k`xiibV6njr202 zczF>Ax1T#7mis#6^XYyC2s?ulMl`{%Q{V%fr`8ddj3JQPgM!Y|bQ+aGIytoWX5oAECt z-w(iw`GX=X$d^N{CDbMs_|;4Mk^2a>YlJvqji_DUNc?N;UE%JfRWDjt@USki-m?WS zYB_~7tr0>?xfy$3wu9^E5TyrpZ7cRGr4f#Uj0LMb-b%eZh7L~<>!12$!%V6zBT_+f z_Pwp=8=1dz$yZ#DwxBzYpWg3q_?3r+Y`)ybf3{!7#6-_S^&?(dtD;87M4JG--v-_d z5GlWCxoHBs4kUlJHuuCKw)`YZOcNfx>Gp#7_s}InkLZgLO4~c_;j>$TAQ5bxVMx%I zxi_L86Eq1@vOcIMHpPUsx;T_lGrhjbn%OTCD?xXzt!iYN-h($xTNaPgCuD>_+1RU* z79ju85srE(?%_BCOwSMm3-gonzF`Vs&Ahh0k@-XQsdBSx4B&A#QD@3JXEvN{p+Jru z#x&}QJoLS5a?&Sh`VJfH{^#sagBHnH3Mr;KdJXj=2l*j>u< z-EWlQ4S0x!(1Rado1O5A4K*86Qe+yuId{hfAt%U(>XWm4f~a4(9kd5_H~=KP3bu^u|UVrE5rZF-6@!M@`o%I5q5pFF^Qi&&ijshd7ht!^YhcXz%| z@*-_eZcgO99*re$ShsXMkojZ%P87XyRI9u@*CXCkBXxY_==tc3b5eFM#nb55SP+h- z_M#7WmJ{v@zluU|wUwX6&u_*&?BI*~@rc&b>Ip&s$LuM2Q{dr8)5R5x;4Td;40CZo z&hu0F^$$BQBw;Bwq}npAS_amODS7>0qQ&<^EoB~hvP)h(Ufv|IKXviCW&jgEDQ_#+ zrT}gj*f#ch5!_4>c;#S;{1^n1AR?qh9z*e~rVg_o`=w=x4W^c5y{C<=_%oFJIfPZ0 zY)um@uHLiy*8!dT0RHkpyEWV zk>oFfugyLQKOJ>POU2AS8*Y*Rz--$m%MbcQs#cSE(nbnP8FgT1j1@f0KCu+)KunP z&pKt&yugPz9f9ncpf?W@np8-5HerF*=~2>h!0Nmr!TNYB zUl!I|s%_XO{?U>k_c=fx2u%wxZzV4$vzGD84RjuS+Jl8r#FQ?;A{{MYRy1>8NlWag z8M(7&i(uS!ZdeYFjquwPng#*|aP`VBLj2(AF6d~Y`DDrO0gCNL3_9w}>JqwtK4}Am zho*-hF4(i;300wSbcJJ}A_FHcG3w!a&-eD5&kRG*CuSm`#T|UT5?qY?7W36+Q3%B^ zXX2mNiQDCW$+teE8*J6nhPQIsAPN{|;z#Y-=x5b0o=3(IFz%ksdFY(v3sw@K0Fl^D zmskRJYvYHk+HT6=+;FxgX>-Z~u4$?0VgLgOdZ>Z1AfzxeV|U%_>ase1_lkp(Dn4Fc zS9Kd23O~eX=j04n!Hxyn*-mGnxLeiL<+fQu7aNTt@!~HlnVe!f0jS7B`VMOSrk)EN zLj1N+v9nL>d1#~O@z}lc{g27{cqmT7+`9W;|C=P(+|qpHr^0>pu(*}yr(X=)czB+p zyDL=t#))~O1TBk{ivysb}tTSloGg?ptm53oIq~nvQTnYbqO};@M>lUy*D6drHA0J45 zPZY1#ptrYr?h(|WV&`k(lwO13S`0b_WhHmVsooH_9Zc@|?2-jnGAr64O@VRODrP)# z&evFHQCheo#v}T#Hef8#!#$1S$g1#|ss^K2Rb?Ov`561`wpBZl3Ecy5Hom1Q_laGxa)HGF2PC;0<#t9(|`ruNer@wkjw8 z7=kBU5-|6ulJrtwSdXwrR1S+keM3ml$zs7nSi?Dd)fPh%B0TyFEm!hN^IZ|T>vL#K z>8yz>JeH7W2wX?uKc2FU602hRUc4pmwKSxkXe!m$U;ejw*$}?6mlSgMd1f}L(8-&S%xjk!Kp5kkp(*xzU=zgpwxtQ!TZ0JIFG_#6cOr?i*Jrlyr zNynCMwI#2D;BEi|GQT<-D<$R2(Da+Gu0}YEzaS>LW!U*Aw0QJyNFeBW2uqxt$S36!uEa=_QK|43&J!DXFb9Nrm0q$%#XJ2(fkBO^41PnYOc zTXNlI6qC~4W9y5LzZg4uxn4BQ01%Pz33RZcV3932B#?1Ny2rqMwrClnhWbaY8(n@| zIVg)#PqDuWJ^c6DY zZ^GK>GhD`79|Tz_kMjZ9a&h%G|9ktWvv+lO?CMs&f>Hy*vfef?kLmk%+*O^=Q2Nue zv3f>=$dP8oY4800QSLakTXAme5fMr_4Sy?}6bs5FT5tvsn-Hwl88bVnk+gw?qNjli z**JreKiRC4iF;c#+u(+Xt$*d~Q#j?-HK0b=Wq#e^-Wp=K@xvBeXz$M&@0un+k=$&| zzIMolssKJ=ZY1LxeRogVg9FIJ0QqF30pb~HMSZbq%-9b)HD2)^9n88Ma_aTnnHxnb z`&{oEdqGAA0bL*miR42VGOcz~M%~bu)gDaZ+2Z+w(IYHWp8fKOk2nJ5XN0~0!{%k- z^Z592+qIxeS!AH(inFVcU1R4_>p1x;XQ1*TNx*S7n1|cC30!q`5El)Fg{*{)LH%dw zPkL>j&cBa)=uf`D5)UrGN5;K78}QM9%kXqUuJ!coge0SI-|uA$_0V(A_~Cu+JgaH> z8$&fy%-S?02>#o5#An&{=%_6#$e2;l~5lOhBkn&;J5j{6aFjagc%xz(s^uovq)_#=zb(P zv1^V~gRE^aViXh=(2olIR=`=Mpo}HBoqy1JA-5;F_pF|IJdbW%8b^63!hxk7BJBg;oN56actBw;Jirc~J zc7e3V#Cqn1Ig37YG`@qRmX)cf`E=v13$xPY>Kz|?5GzoQ{szS3@^*!m#g}4gG|wg} zRB1N6&`yj-5F&Qd_S;*d6lv88 zD+e-;+gE=X4c6f*Gvuuf<#kR-E(lR^8JjsH&ogXH|3NrzKHv7?Ss(q4f!-hY8}qZq zT~=UX;&@0tC93r*CfeTNx{w@#sLn!l;WGMqv5mscC6)s)501c0GpA!=AgzJy1vP2m zVU^6mEx3X3>8e}SwG?CXHil!9XkRx1<8w`N6fml{SLn2jd<4B|eN@bg8p~JqafP@& zeoMZ8iDD&BI{A35%;*hCCS3PekyzH_Xx@dF`|p`ZQE;;G@H`=j%m@_m`4A!ct+zY= zYx09f`;<6PBgcZ`j>x5hseoX;g6@on_92*IgwY*DAgUO|7ID|$6UZzYS|ImZH7i7?%WHVo zstK!KDeyYWnXAPjghzE&3q0#6#u|#=I*`H;Bl26t(r6WrG<3wyJq7yI1e{VDZxi%k zVFw^}67$1=j+yGo2fn>+TCRsb-3bu6ZmjtMR5EAYO<|NZJLgU8yGJXHPdZO8cP$T zbXo&_iB&V*Yg*6iK|h}U7I{$QP!frra|tk1&(2qJ&V=~Q^#4+vZ7{->zVT)zHfk;S-;U;oWI*Qy|Jj0eu1rqWWHr^moT`O{GNf-~bt^6iG0SrJLu{Pj z{sP@|`TSul=vHM<%eO!_hL!~Y}y)I18 z#VL#$x8Fv9S(&tHsM>ksA~6=_B$#WAp36642;#sREp!%KMA%*wu`FziS^gX_Befyx zQqw^)P9W9m99;s9SZ+Ujs-ijZPeeRtK*pFd1~Uo@4o43R1-F$u{^`Mj2D}0ZZYb2n zN3lOO;CZ^|kBbJ3!eQ>#D9(2QAE26zQ1-?gMjh3MU#{0ewyLvw-58UmM_2sK%C^am zuJoJs-|w!9Apg-qV5jI5gnl%B=X8gs;``aA(soz z#3Tt9Tap;$(M`hdNYo4o0=#jO(Vj0@e$Mh3(D6zLDh*QPMdpPS z;b9X?;gP$6^>mY-E0P;II?qtkK(hy`-)Ala+!pL_VAtuCo>&`;hn<)&dWar7pwNbQZE0)H)JSLbnR z^(Ati&}dcnaIzl<6zKns$%m7*h`s42}NkemkS~vk6CgAFh=X zNU#*ydmq7C9qfz`ZVT_8ta!+U4?Z*DmQ~=)v{(FGFAi>2G@`k9)$)PIwGh+(X_11i z)^Ewdq4>l1`yOPTrCgx37Z2053d0ORxnmq6+-@J(U||N&lxCh&;ed+`^mUj|nxo#8 zJP@j|f%|DrnA|3Bo>wvIX%hJu~<10npF@m7OH4fp$W`9ZnNUR+>i z*!I$O`S#)4>rYz;Y=Lk7(Oq~D0MovPkBRuDOL*vQl7RrMRWGsK2YBuk(Y&mFd!T!+Q1+urkAZDtA| zk2jio$s~eGDUFrIGWe)GbQvjqW0=i7aG-Uc#6?I^K1oky6+-fb|Hv366nslP`(3#E zPlO%B#Vn`dU=m4HGJ%A|_lMz6V0{_u%`2JrfS=T@mb*m?3IaAyA8)H>&>_lo)ui^U z#@2wKlklrKA=noD-n1N0-7eE)Dl1ZFg2gq*HgO=mfoHf8By2<{9yd^f^?nAAKqgZ_ zwrr`Un|oe<8IPJdUwkratdE1mf9}K8teu20fV;#I*fg5?Tmp@DeV(9fQZ%}-OATf?y39+hL8Y0n> z_wukTV(+lFQI-PT3vrGK+gjG3mAq$vJBpR$3MRBV=u7W@(b`8T5PT-FFf=9z$|^#b z$YX)+$@wKw?mRZx%vk~kJXRKu=k52tO)w!IG-lL`Wjda?pSCfEP9~&|Ty&GhIY>Qf zMHFJIJRBZU?07>h_rH}&l^LP7(RkrN_qaoCcQzNu2}|aJZmXnu0C(;8GdgTMq~z%I zu{uP|r2H0Wi~i)XIW%(*0YZ$&+Jn}_m{Be8ykVN zWDTEygESfL^)VsztK^k7>B3&WT=00Zi!6QhO%peA$57ttdgjdL*EFqCka2F?Xfd@-)QfH$M>c3CX;O6$8!JR=>Yq zo^<~QOqn417frD@1aeyaiqV@^g=WnsB@#(k;DM!aDEJ7W7WXd*mrg0MPy5JhA$p*g z3c1v))SRryOd`fHtT!L@8V4%hRp`(A5g?pBWRlwy|3pHz@f#oV>qMrK)1zl#wP0!t zRo_Jv$2mh4VLd#seYb&I6t1tGwZs;^TjhmRrmY#YC(HB-u;TseHDWky!r@=zVZ<32 zz!AVHa;Yrl^S8a9>xQ1ffq>NYzs#D99650i0Ori91qxIk^}2Pu49!=zYF_!WNF0br z^Fs*#n*0sW3<|#Sh2nyXC+?yc(cA2pT|4mnb2|X%)==^)!o^JT6=~(FEDXPF!b81$ zj+$yw9ibiKO0u$n)#py%LA~Pts}9IGI%-9h>{as!ZSj4C#6{k?_^aPty=>q4XHvMv zJ~fJ+DFyuDx}#d=HUE7W_RA#TWfS~44*geEBbuvlyde?AYZBdZ3TKInf^0PV!^JN; zHY-4&Q3ialr}sa3vgL4{&F%XGU{2h{(gE!eV)OCfD4(&F>&B|W@1apcoB}Lp%L1h6 zZ)TFQA9VdnWk#*2%vWMbrWOY@=5-el{PJXl0$E8dlx~R14H%d$u*wR`@{i`?#pkt#Ho{5WB)gHyXSVN3rlNE}%2h3zJ07%r*o$S#H`mk*$_t+| zj z;CkRn3j<=?sa3sL%3jJDy`ju_QEedvsJ)WS^Z<6XnZ14|4J_;Yho9$pi%ZxW8eRL~ zn7s?vDO&j8G7faQ(Dlh~Dwh2Ms!`RvfXSK&xyrrR>8TTL_R)_NN5)x-xN~qQH+oXH z5$>dacQbV&b&63%v6)N61%mnh8~*%*Qdo~cY@pz86RD=bqP1`5Erq-PX#w0qhq}W+ zQj&HaQp|qjAHLlZJOw&jDLVouI*ln@$z{w-Toy?(qLD4&%o2M5Nu7G=c*CJ?M{L)| zy)Oe}zwkV53m!`B`mUfGqha-~5l+HcDcuk%%i@t>Emw>SwS1?$5lUXiN{lj*$)`Z_ zo{7}(rqutYCX`0p>+t&K z5KfoAGU9JmUO&C|Qzw&PX#k|R%GpkCl6FeXBlkK(~JO2~g3?E^7hc5f$Lvt=KY{&0j{yN&9YoZT3wUP;`H$ zTE4R_+h)AxGxOE501G4dmCs2?u0(S`tBf2O;|js3G~j|uyVfj-gvNLyixMoA&|Gy%7?E7CD6d5-_j5&^wq=D9RzDu}`$X*C8xNl296>3KE$% zZvq#6F~AOye84Y^H$;z%nwSG_Nj3Lw#FlmY$-Y=T@^tlJ8}rfI)jb&t0Nn=_%p1=s!wW3^nZ?g4axbl-=t>a#;nYE zw(=(BTxkEtXAMT#4;?~6n%!cI;zSAa7QP&EniH9~#Zs9jj8U#)rkYLW>GuT@*DoHY zpUMBe-A(48uU(v04K#i$r5ll3YAmOFd)f@4f6uCVFc@v%r`4hkNn)0|h zLTry=))a0^bh37@3T-g>CwL#$_`e!W7I2w+6u3$R+(kUN7v76EMlqj%x?;ngRQ33P zRKoiws>jc(-9nEnzUA-Bkfkto;qFR7Ut8X_hL3COzt%!xDdsbh=Y;4IxsQP?KTj?O zi0VQxCn}x$zlY-Gqeyj|(g+Rxg0SSEKd+bhX0CEz8&pFCwvmbEugCxlC5sHuLc_TU zwRC^PukAM6czp21IQnbN<6=!R)Dd)Zqi_^?dD{*Kibusl*LPHx@ly^X;{m(Gh=sN3 z`ds-*_p*}{>F)1&rMSaDKO`JH2(x&eNke{|m zhaKbFw|*=@^Hl#KQlR@7=_P0i9m}XE3<8}Ey6bnr2hJ9@Dt^pRTD9TcDP5rKO9~%K zsA?V`k}^;TG!RsjuFFK-^Sk$GA5=sa9AzWzSZ3J8K4VN<_y@+vLU19k0tX zCWG6lW%#dYOOifL<@7?f!@VoB4oi0gaWTC{ekZl;H!3>yz$Y)WSc-MlnWbb(eZ|y-e92F(C0YP!WTdBc@u@^@rz-qzXn|oPIZ(jDW03GCN9hh z-6zsmY4R97Bcrv~kMh>d5is~1&4auDzKG~8z3bF{>s|fW!}z=S%p^8f^-e) zaj_Zqry~Tl9Cv|E z?(OJQCqlZ^GXezjL*<}+5wr`|)Guv{bJ?TTibh_z1fW6xJpW=4z@?AR7v;XXO=4>< z7Nv!x2(sE9S|}}lG!;?fKg<^T*rWL54oBJH@~da~j1DRW@v+R}VIgeF_wZO^4COv} zJii-RLNYfrYjI*E;HTD*rqD2sk3+{&@*vbPyE{G#ZX_~Y7X9oObzt%*Cecav7}}E0 z9P|5sM*0WwO>DrEA2ST{fZ-Iw!hslxWKek4S>sn5<5i!?{J|fLOUF8{-Wy{}_TPXn zD?O_X^*#xMZd@W>=CqN=*7I(IQd(LtOfmu7S39LMtzDJe|IfifNcHgVD1U^N>>u~v ztJR-gxXZV%kzvz|3%Tnknd!k+faEWCyEph6m{FbAJ< zu6_O=M?-NJO)ycnJA~EP?v))15)BzD1eEpdZ%$i0X^50heF(T*s7^|S{tD)rB|Rp~ zJ>!#iQ;BY;KrX5Ocn~f86guv`i)nk3dLDN<5;|i2;5<8nTl~ROIkQQ7BEaBpDo3HG z6i#Okkd;9W!vw3kHzO#=mE9RXBk;-W0!qhe*8OJkpU0iz*7>sqfj%Tn4lu{zjO%n( zEdzkcD~SxgOg8M^g^?aPkKK+Sxa!wMw~~U52UmeS71SPFXJa@T{Sc32Dh4P6x&R*c|M=&!quiYaEGyV}z3+9(XtWtslIi98+cgW)%_tk%p?n)0*w$ zG6jN_-cP+=gHam~?C~%Zkr}serqs8>x&CG~@rC;K7M0$G&IrE!$818-VhK4*pCT`+k zDh~(YI|vRUo=C<_tD+3F=cRfZGTBX4$503&am~`mwjJdp* z_~z(kz^}cUtRb~zXU-@>@R`GX2Hjz;+mcz|@8qYQF-j}ee%{S6;H)2lOlBO00}xHB zQq$F+;8EXcuMJ4`W%=QfT%&OX$p<}8uT$PiMqJeDD0IrEx4&xTm+XEpHFbL2^D1K7 z&;ilO;g@8QTIN2{&@k;J2NIAPpHW>2`tOgT&z@0N!q_N}3q zg`4q%VV@3nYa&>=_m}kNt!^-&K>n7(zJBYk2XUcQ6x>||-(->@EIYB5CDtGy4dLLF zRX#P)7U|}EQguRETl);buK9+oZdzlK^TsrSkT&_N*Pa`;?Kuo+;hrcrnu2dTb?y!5=bomB9i~-S%wBwlX zL!~$Ih}u3Y#t@6@aO`Z|ko;&Mt0@2sE~%e~%o+E^7FyvFgFqwQ3LH9(p4u zqH&v4O9I1w`zP^H$H&5_)&7pu?@GDWgMtao4~qt`%7{^MUySTY^?sYT(WlKZzXN=Y zRM9)lWRo1fc?E3>JiAk-+$gy(=C?u5Z*H67v>}P($tYqkT7b+8zCZ zeM>vF{o>3{_=)s?(e)M%Q9at)FeRNzh!O%K(jwhThyv1`(%l^rl9D3b<4I({s zcX!tS!_2qwoO|x?-tWEh7tCIJ?G?{@*0Ty_42Tl_sdXuI795vjvPHU5S&iYi4un@1 zPZ$XFMLbqORBuzS-XGuIF%aC}_97=M4H>i!OAP}syO|%Jc)=*-ff3ruKvGxq1t~_798C)~a*P*hMr7q0P z7KA};^mGOy8^4A6K?Y+U0(!ikuc6v@dP(^w2i>+54F1d4W}V@2okKoN3w5C z&UqfjFW2&^!mTGfQ|iwh)WZarfnH^``QQ4C$EIL2(lhsEABBnJGreaF3`p9^GV z5-#ag2BV@X2F8zxt7eYGeMH056-m#p} z1vELOicZZleK)HJ>r7b<&XXU2)Z-wVIjV z!`UA*k@IAB-qouZ%Kfj{ehH;d~jNOH5o!B z(I2jVmeZV$Sfk@-Dm(n~*7PQ6+GE%Y{#kbz-6M5q@$TvlxH9A<5N@8K^QOt)Gvk4s zIlr)ZX7nhnYIATf09V6ld#%?x{a5+G(NH`R`)u_PLC?t$V!_b1*N5!Iv80U$UC8vG zjv5@Er%&WrRTHPaE5!Lx>4;hMg717!i8%Z|n>JMHt?Y$yEt9+)gn!D;;2 zhRvkAdS4FPmRf+uyd;@UC)Rff>)bChq%yjp8Mm&iQ`=*s2ih-77La{EuB$b~q3S~F zZbz~#e44w;??(^xGpPoi3Z{k<*M4JshCPHAm1tv_ZPe4K4qg;%%K*w){Au|5I76oIb`9BGjUCiZiXTFKGaEa6-%-%fc#mQPR-(-*;IHukk(orizGD!3lOxV^7$t2~)-j+|>Hytj^UA97ucnCa+#ezJo zo_F@xQw|Q&3~zk!$o7AC1aMb5#aibA-{I^b`BC4i2EIe${u-gvBOY&we}k+$($E7o zP-olsD`m#LeVnsRG8Vk2LT>r1_+?iR6E)qG4vNonv!O5k`XL0f3!z492J@07_%QGm zaK*c}GwfhxZWj$Qe5sS9i|ssyFeQa{b-_L^VVY|@ryqVmLWqgMT;7!~RO9+nb5kT2 zcPW$COFpDDFJxFIJaQQt+jcdbahr%ZlVNx7$Sw2Io!48x(q%_1FP%r2d7m-(R{q>x zClJ{QF>c~PhblLqe!O@KpwH{Ho z7=-VRo&5+Nz45huZ8osRL@{7k0*U$d$gO@Wk8{ylS0-fjldIo#;m!wqIa?017l>`* z4TD@=YB2MCED@9sGmON*rlp`9?f6!~trDJR)K9RpJ7zwLx42L|L6Orr+bJ{3zta#$ zO7UqFr%z1ltHR3nbOJgO6wW}A1kPtJyy6Rs2b_p4Ik9(M>-Xu5yexx~gDnraA8~1s6VFp%S9U9z*)-Z%DcBlw zcy)1r{-FB0_8k@Vc>JAIlC_KOCL_W{p#d+3Yg_&t;@XLxWcr?a!PoRlHj)qK_S%Q- z{CMZ|CqAGE*}M^Lvp#m?5}X9U;rzbVtBJn#Pu?DzpcmK-lkn;CsM`KVr-kbwS*6xK=b$UC&NKnSfdX8;`O8u6rBe8=oLD$8P z-2gUKXg1h3ND!vLi}RwFrsS}o?T6xO0x)vw&t7!qiK=C>9IsRh{qQkbO^9^Q5ROxo zY2+O5RB7>K&@bD#uphP&x^L|)#+&^ZHH5~*v}b0)#0tM#;P{RH3UwM-&FpR)#Tvt* zB*@T-4Ey-kFK9G~nF7C8xky4LGPwmC=E|po*BcQX>eO-;2Bf2szZ1|D?&4%o@ifo7 zIpygSZt(*QcF%g7Z;r-Px0hA~QU}X-SBZeL1UXvi>-q{_P@Z#MZrG=KV6B*qKctYv z+x%1Am?30Db=%aJ=^a>@h;C)~?sK8l9?8Y0g|{hQ&-@9i_z5s{i%z=41ord|3U)~h zP})_Welj(TuV%ZYeMv+)qMX83PfjL2|Li(#DfH z$8Y)%Va*Eg51y}|XDZY_PTzJ}kurr2z7Q2= z`>}2x_F@_6CB*#Sy&YNud3u1%8HMdQDF;NZD{mDFs#1ORzI>OuRs5Y(!@PDTKaCAj z2=?~Lq#oWrKMdee7+j~?)t`urL3up|BKBX=*`;njGL`WKLl}Ev6R2m(6u?!9rtHBl z9yJJ=x8T=VS482FRBOZ~{^=Fd0_`euKY6 zMf+LE6+!0mXxl4PYVkzr-SJT>*Yj!fgTQK3WK}daBn?EbAFCJajO>b_ID~X349h{v%CK7whl!8 zofV?NOBO{Qb67G0#L=_}?2_p%K0X4YhpU(U0W zy&zzAm}J9%xeFl!+%jM15qK|k>L00AMtjRvAA+YVVM2EGby!SKi=SH|`{c*qSQ$HY zsiXKTVO7Hv48QLReU2fdFw&Tk^g)xh3Lv!XwEu3OH;EbOUYi3%#XcM7u!BH+%UT6Y zBMlqfD0i8${w{-Wh$}kj(}I#-Rg=j+U2_IOtgc$I6*py~N2f6)hDCu=uPy()4&jt` zn9D1Ol{3gyn9-301yqYD_E-T(2-|0B#(!;S03KmFWC;Y$A#?rvwVLGw#KEzy7aY-{ z&v(<#jDJ>xIQH)29)3=IM21}W#2(=o8T<@4Om(l1SQwxxvp%|Ua~MU-v1&px`+LO&IM&zGma z!*S?Lu+Tax7{@W8x;z5}^a)A*PX>}WrQfUYt~cV0UMCQd?mrczno`S-daoxSh)AjC z5J*85J=#o2aZQwaL1AJ(TKOb^r+}k<80*akux=?uSN7)_YgZHniJdnh*#h5_V$%aD zLKUXyc_Rfmja|tM_qR~S&2=CAhZ?5T9hQQ;Q3nep zy4pK9^iLVBD+8&>^XT8p8UHnz$(Gs_4OP#U!l5?=U=Zn_#KE} zy}XNU>2Eb5sLGt3Hx+M3%ra2>cHp#??I+$P9(#(z`3|Sec$eI}I5Te!lYg9}9C@`} zmu=gyY>8ZNGB{GPcsOOK>v_`ey>GNdz)^iq7E<9%d&4)rTig10fe@g6yLS6wcD5@& z60$IbxZg+o*=)EzyuM#SKv7R5_dBi^YbmLM13byCd8SjtwE@PrA1)=-2VGo=slZZJmy3p zo$=Xwe@;dFa*KnU?ON6zIXVW^BCUyS3;#aVy#Tt6-9Ze&#A?UXd}7+kFVjr1BYlm( zEl0`r8;S{0`yDF2_PFxp5+8G$SmJ}3tG1UgNO;s^4)LR2_2VIX_7hSj1FML8NCKVK zILL@zk>LL|`x~|92SPl9ys+n4Q1LX?&*AcWscW6wqY(B?S@>jMkI&75m-m_y&L?9K=`_0`5eyMdJ2#yB^c#3hPSCb z_|BX2*c;R5hc0EQ?q7~kLr0pHPmk`BF!6 zJEWUduhc~@%klfOFe7ok_Ywhj;m_p~>RCjQ+@-M%Dpe%1@pmCDKXt-g_ICQ4jg!5b z+ZFA(Hv~e-loz;(Q{S`Oyf92C)IbG+N~|F zp7znclo!;vGIy+sxryn)v)z1Cf+Q+Ei^=!n4~3q}6o+{>bmo0^&$l~$1Gk1k%pj>B z&rkmr%6}<0|C(9m%(5Nu5A&yzVMhy{l`oH4Qv%G6;vOo`lih7m_Vev=>f4oZUhiqr zT2W|}FJfuB4c@YRkx%6daf?4Yu)GV;^dN5idNB{*SIW4w_1%25oF7nW0i57_jRB)i zC~vO&%8Cbzr-~1(wU!QjM?&~)uw2`P=!5|K2~r1RP@HU&blJZ6)*ms>2=!ehIlf#j zPG$Q?`OcB(Ud+N;DwoiSs@ZHeDd!Jv-X#mG(=s$*c+mg;wrAN&kP#n%cPtl;IMU8& z-EELxhAu{b2HP6k5g-nHFWWQWd1k)*by_z%-NVyHr27bLQJF`!nk=N$Pa=^s9Zg2Ov&& zU2U#rNr)c1+YH%>`c2g$r@Q(3ma9%PZ>KA~x)rYBt=hlzJ~4oRr}38y#BHU<=^Jcb zi(}Q^rU<|*o-PC3+9y957~mu6ZZ?zQ4g3z|<@ym2n7 zeLttPLOt!(U*FRd2Zd##G*GwhC3v<8IM?3BE~dkrlPT}VG@=!ukaL?NuE=Op(IPVG zMb|cBg(BC8h47L5t&lYp0WOl+Wpy0Y+m?Xb9WpdB)xxv9SMmQE?mf_pOt}H5&$Ou= z9rm0XDEV1d809AX_5FJa(fpBQ=$%vwSl3!S=`HS=u|@N^l_bdSg^R*;mYGHOK3Hhv zae7xaHPWoOspwmD@)wftwd-SHI#$-Fel*H?ubD{7v;+QW?#_Y7l|FVOiU}hjIA^P_%?)#$#=%glUgw4E)a;OrlB`cw>`nX|)5kmSd?wI5mMndFS$atF^k z?f-H${q(vjRL#j+kqwd#6h1VZM&yw^+CYG?%exGmd8_m8}9XF;N&sGD|l<8MC zWZ$J;8;+k+_r)AFSj^h1?leiD@095N0?&0nj#-2HyDETrG7r6wBQqi>Uon;YaE(ql4 zq{&1eVXl#IS_0by<5*T{^_j3vQ&%0>_qA3yOE%$i;w9-FLvAW)yh>?f=nkR%kOhqn zj-}MzScPfYH7S&zURtbaH9|5dp>LK{+4-4Ktu-dp2|G$cCDi%S-!Rwq6>|kMXD`yMe~jqiDh(m_(T7N$IhZU5I7_Nn_)AhA1vtDYAPUQSia zA!AcAT2mtJ@Bhr&geGVv>qKphw)nKYEZuR8kVf|j>kyMY%Gign$eb#eM)qex52ntA z0wmGL%wkV?Sn#1T;_Ja^Z+k9)&dWqQU7U!kl(><%6^C33J2@DTq_5_{h|b-na-1Tieb}_%Ev| z{dB>4v^x1hOPkc>UGI&bD(faT?W1`b%eSdG^+5*nn%dvdSMkqFB>IH0i}9RH~j z!o*0e^}~uAif?6URS^4Q_I$#nkNI(teTp|xZl927K2sB?e#nJ*m?~2RB%u1Jg(H_< zOdD9L-;cQ@flIWN)E~je;>yK8^_nqOR^R$*hS&(YHhjFNjd{#&re0VjOJFqx%O-}_ zFqM`P3nR6GJW0fiF^Er%ZM1G?;W4rHD+iM~g*xRUyTnutMsOVN!~Fl#If5o{xEj04 zSbhi9v(;$I^CBqEIzT*Hnwam0A)+!u=`n+1@hZfI;*?OC%218b7k%|pr$nzei}nKF zq$eQ3(=v%#bK8awDDo&;sfG|yEmzF4b@6`a=`+>)yN}zWkG^=>H_m-`;PO%xspS}< zK^J5wMJRvQpug{g4dZ29DmaS+rwp|CXhA#K-JYR&RpjQ+#Y)O4X@x0quID`WLO!`~ z;Nx43FFmmS|IuImGqwR*@vl)(7;Co5h0% zoBPU8>*I?M+#8>5QC35#vwCG@%wzhL6&t3qZp zD*E9!spIY|ZZFrRE%wJfa%$1Q{H2ZLL_scMt}Eb+vQVk_IN*d>R?%sHSL2ZcbRT2a zQob?(O;#QVOK42jFaW>zr|zy8no5raT2!n*&uCv3dl7z5ba*P{%JMStkNL}!aSm-% z1VdnaqNQt$!z`CA9#lU0-=4BRtt0?J9JA^Bw8*p_)&gQya4B8GD%0YbWX@%e(>2k{ zLJUJV?x^*DRT!$k`uxFOusey2$CMGsMS!SouaxiGw@#%1)+oi@un(^{|3(>ZLB=#x z6e0@G9R5*C6GamXZO$&tO35LC-|^0IlTm?{FY35X_NCNUL2xg^TAr!qM+?{N zp2Dv|>pCyftSys#L|k@$zQ2-|i3d6g7&%aP{<|(I0wckGg+Hd_c%E=s(ql>3)Tx=e^_N7;1Bx@+5!AS>(U{4@(?lfw`BP$U-px2M(%FYYntaA(b$?w<3l~vmgg@lNq;N)o>_{%gq#dVfv2P+!LbDgL4q4x zXJPjMHt!?Dn@a+Zn$Pv`zTV#}nPSo~B^H_0-yJpCwchlcg(Y-$PES$vt8>}00KDpX zNv{=ux0XFs(fck@n7BEw-G&nX=ys~6-iV<3dCx)HFoW72&efLXX-s<-16SyUVdEEcuBWCniFmXS$44-k7}`2E(qmB-qX9^dsEqqu5UV~wY5&OkFZYiyJrOQ z_kAY3#u|D*YPDpQDeL>2*I#0=Pw31AVx0^Nd&M5Gga4}c9ulvSBE+R?u~xv!cCCV{ z_*SVY_V^{UiG`1+p+7Z#VwfAzx+<}!quL3d1X=$36^w7d_`()oP>!?#1 z4(W{bW<@$U3LO7r-R!h=>pt0N`N zgO-`)!YWmZFm5D2CP2bTkM&w$bL;HmX>QYtpPt~O!HWX71V~d~xvLC1)UN4}Y?7K; z?xzsVsz&I=Ws5dvgvtYL3SpDmuAiwWgVdn4`?N5;dmJYDdR`3^X5nhDnf;Lu)Z?rG ztP}lr(N!7pIH6l3WE-RcO%v6TIlV#pNA#pbblUGqA{*c-+w2Z4(+ zQ^wq0#VHWmRHCbZKTT|9Z0d=Rx5QbdKF~segPADG_e6&oEm}zLW1*WX4xrf(v+`?r zTKg?-@Zrx_UZ}88`+u3-*H53JFKc1&7#pGeO1LHDYqPoSZoUV!45`g#bK&6Gd&n`Y zZx;_rF#YdRcW;Xkf53e6-7h)@j_CPx1JsRQ3qMm>6lv{Ezq~(r&bdPO%SUV3I&45K z#wtol2;alb(h!CJBY1;?@rvyrCA^Jwt^FsIOq!@Vc6(bl1ERn+Vx`z2|7bt~-&XPW zw=}#mu@`3{T{hcEu|r$0kfdintz~ghq%>Lw_8_$#!e`;zPu<^fEcST@o#Gk2WsP9e z=>(U<3;7FdnALW0y1)pE10Bh-;Sa}{<;veG#|x1Wf7eOW9{DUy(;w_Iksid1;(t7N zYm9l|=_ldPM9ZMJ_3h}bKU;3!54ILVmYkZ;gMbFK!BQpUc{93!u8FFL9l#XGypX(b zK&olv>|aeWw6QP+t7|XIln=*t;d^O%>eriI%{?;}_sbzYOia5`%Xeq%Z2)Mou+afGlQ z-(U|*B^Hg*+iC8fRE0`tn6PHrWyE-XUP7WAL@sl)a;tvO`-48o>uh*KEv~oX z(xMItcbVIdkDhX-H#rjNnHp+-uK1(jQf2;{J^_6or8NJ^(x3X}DTF)nxrQD+Xnx9u z{^KWrJR4dnW`_v_D;q>xXF2*r(H$;K`HTLt{pB|5%j6szpPAaGXKxxK2x#?8`604O z|AkUaXWM5gkN?F2t~7xvxR&W;-IbR#re3`)+^B>7oZa8J*TQ=w-%hdEM4q_19_){&llr2Z{;&5cwi#B&hn^cD$PYc zR}@z|5@`K(9P3BrKf&jWl=BjKZdI*T9g_akBy+l2+YkKr{{R?&K^kt#K%n@ure9%z zpSrREMN~iTP;iKJjQ(sAA1Hb_)VuI&GAH)1!}(=`DGe7x7$f! zcv$BK#985aJqRsWnhO9$nC*HQq#ieF%wUfuEDKnmJY-8LmS#@w-9)$Xq)mMODoAsi zSnssLbrj~a@l*z7gQiaYR&V3NiBm^(*;lmF6cgtaX9(j5)NIo&bQp%szaS#Zzdr%Y zhaFPscKPPv0nOLm@`BT|u{Rja9#YJ)ZEvZvKPH}K&#HZR7XBLDDbaB0cXJSabfMMO zyr~uaA$)ApqIJ4Yn zPV$`xiK)(3556@N#myTWh@4pkX%Y6seRgn_J31-O#sNIwB205nL?24}_2`kepgO$u z-6QDXpaXXrhdy=hb5Q^OKkKA_KJ-~TH43iD@y^eq6C#cHC;mekeoX79W9_}Xs|{*@ zo`%nCzKwXd)0%-qNB&Kb6}>4f{#Dwf6H|y)7068j6U-&4+0_L_beW%96cJ_<2-V^o5Q(#HoO&Zv!AoCq6cDywXmS|A>+#W#W3}_1` zgs0K`&Lq(3^?;>hrJmS(;Yf8brpC%WgfO8Kqf;$K>7L$Cja^b=FOGcH_mODUPp_a! zl0{Y~5f!1d`fmfbt{!`0A(7uD&z9aXf95ORRvDWjwlWav(P){w)q6(0-V;ys_0X`T zN=C4)fZm^8>rrH5xBqfQV;&1K47+-Ya5XMUxA9qu9IziZ4=v{GEeCGa9o6hk>8KVM ziwpo)&s^tITnJok9acm|n`rC+9zN@w`3sR%i5!>vI5p99)mKZ&praGIM@xI)nEz>< zRm5PPuQdz1_q<8aWcRX=HfAypYrTp(7K*O0k?BWhu0!bHN0btn;o7r!ZSrxeeqcp) zs*r03Z8uCB!(FZ}jUN-XIP#S7WS*K^Li&jDjYu4&#BT|0iilFR;-cwx&uW*+?7>fe zIjdCAPwPilg6wGaHqwB(!h2x%wLebvE{ifvA&vdEpPfo0I7s=I5!T%CfF^)W z(#~z_WW%E1F>Lxkm$$8VOB`N+=d%TSp_jg|h)IXgUBnZ}(`FaU}!T|A#k zt<>KBuG%;6W4yCEb?K(=7tAL%c^K7)L7ERD%*ad(nM^;3vCdpO+uJqznut zF9Ef-HSjevnFIhP9&4BHGT2v^N)i?S4>)b%djY8LMQi5E)uF)DsXYlxt$ih}xJ6!h z6}LQs-}bs%1u?$>wJhpBHsh{$P_Poh7Bh5nd|$kG#Q_@YI@*wVH14o*8{wffaU|%x%}>S|Hx~M@_eNSCQwzv zu--t@ATGt6YV)|}tvSou?@1>{aR#)rcGTk{<0EVpi^%S-wD#|E?(#vn5&4#2y$a77 zP>bz^&i-v=gi^^KWL|9yHz%nw@WC;IQUJ#k9in3+ppM!Cwn38p*<^HiL*->&(o#F2GN)&rtH3yXzgqp%YycxJ!XCg&n`s4U(-U?Sa7VI!ek z`z7@@v0TTMAy_{0BHWoVLFt*o|MT`JOHBqk+}PTy^*_U9EKzVsw< zSr?@|U0_<&FtT!{iQ+_lt1PrZ@ym~%HyPm#sTF&J#zZUfoG5i(hm+U`L$j}fibmX| zLk4d|zqg**+XCX(t{f=viECz|#$BK>uqBJY2$d<5Z6=(K9bEOq%dQLf=Z8G^WR<$R zH-1elIq?bUIEmrxx7v{*)*WXg-%pE#FXg?^wAP9t+O4T6=@bWLBAvQ4?Huj;4Jm4C zf8@|1F-}W*Tyv1gH)jp;BOs3UV>XI+#i+iYAR!7E91P+QNe@s){@RraV^4K!up3tr z_^|I;r4z_XyMAy%~XOs{UYHmf8(F6`6fNfR3YEU*`NKR#=(~B*8A49pAXZa zv#STHBv{|TsIWiIOn6_=5xtcEc&N!bCN0utQ@22;r837zwgKRmKT!Mjo!~pti_5+^ zWTj@jm7E8m1Ic&co*&;fu)rivw}la}nz;1oU!7o2lQ{;bIW?-tDyXt0eKk^bUC9%k zdB?BALwvK|D|BPG^Z{KApN@P@8WR=(&e3{aH~7Z9y90NRAQfz0{;}>=JqjHWn6D(8 zSWrA6PYg|0EM9xL7A|lS-LN|NZDpge+GEjk779I`I z>;E$~i)GS5#PrlF4ev{iyofIx1kGF)vn5ur;if8=l~|uz$Y;Nk%1`?kHzcFF{akeK zEbcdiSgDv~_v>y_U>3J7(<{KZBGZJ%)BCc{tCd7g2b}<`BzkWSqS%WbaKL5syyD75#SyDVHENYXY+2wIHHZm2-YflS~7prJVkUVgD;1yI% z0AF?6zE4%BbESvSM9~1y(`q>f1CsdNEv`d_O}1OclK;WKLu|IUef6lS_08@~aR8>% ze}d*Gmuy5Ob3(as6|T#SmEF+hCgV{O$0Iig=jNIbTe#9jUE0s@9NT@28jDM#ZMf84 z4mcI9d+FFGs~%B>Q`_&ljB1A>2NJj@La+~0lmRKTz6ZkBK^!V#6V7c~w3%V0J9_my zIWB54B>cHMhEJ8Lc2)SfU7~rcN6SAy_@ezVf3v(5I(FofpsPh(zkKw)lTq57+P5UZ zWdo+B`>yx>5+gN3;shReo!r=OhaVjV9I27t^_}lP9646${l=I?o!N=+3_bk5LsO8L ztJzKkFndg7GboU!BIH!lUdCoYpQ=xu?}pm5zEn|76w6XRaiC&jF?D`BT~FNz^v#d+dTt6U z)N!}F&M8~QuYu`};AVT~^u2r3v;~7uIRj+j>-FNE_|yr zHa*@)0aOL%jj=h4PlM2oHvGIv;x(c!=}@I2jZ_@ZUgwyH5d^Ck2e@YY9+)$sx*53c zeooCIhOP>U27}K|25ohceJ3O()tfpgeWv=N6F1%mfQR~s9wzI+PUc_1MQh1__D=k# zC+LfGkyPNzou0T@ib<3GGh<|3ByD{{nq`8MJzkYyv zpd%i8qj1-1^u<6BxlWEAQSJhl-UWW!P_W;5Rsa`6P@1iR^_xRKu^qA~1(-{BdL77F zs_iQ0`!|jzH6^$7p}q&=>t9aVJ_OjB9t|I8Z7ZEMAYYQ-RVMo%;pxfo!sAtnJT{Cv zZ@nyMW(})?Uem4h%_B<`t>2uFE@ro|sCO}D1bLHUBlbd_8(Y{IX-I1FYR7FRDEFSL8Oz8N0n6hmB)0p!gV{emHi<}MzWv}IrMX#Y4P3ip z7R(|Pk4$0jwIekwQ`;P?Stq+?4qjz*9?IjZ7?{}2h|PXzXz|*Y`vx+}ZfmxKrgFFY z%gXgenYi=e!ZRY1Fsi#(xCWnq$~?LvylNTOjh!Zr?KMDw|oNa$Fx(jr6JXyBLuW23;b{6wpu1(Q|Ijcs zd5B2x28}Ouoi<6GqMT<)9W z|5#w067V8rKxNY7pzd~-@u;N^5z|TG0X+x&>d`UWP4S8Myby7zP zYN{ch=pXf7TnNrEe6UzlO}7mXMlm$hCUC#AUaB601f{LZ@t|f={~1(uCo0d1XBzEQ z(!htu8Pd3_dpv10C!7^8y+SAbmyaATz`9O*;3|IdhhkRk5!@axjLf{@_s>X-H!Pd) zZ9&H`-Oj7m^)@AU4?k~zFoV9VOG;H{u*vweicz5&A75uQ5ub3RHhr3eb!bo~Wk;cr6azD5Jt+cLdV4Hecr|3Aln@oy8to zpq*F^(eI|scKV~@Fw2X#bfr2WFnl8qkq0&kn0U-AZO1}4Tf z-oV+g)t$@GifggTl4plCwFQch5Wno1=Qk^Ylj?s@1ib%VNkJE6&M~G_b}r?LH*bLsyIEhE8KqxT zjX5;^E=IQYgKPMZzN*Ubhx%bC9q~df@~>DPT}C-6Z>6KVoIJ?>?+l3{kcjPi{CO2i zblk`V(yxYrcZ_0dwoCFugeg>-^ZfSC^-Z%c+n(yasgw&w2$w_(5i%i%6h03qiYWUh z*cLl!mgx=4CGf>9aaoV#6*^B|_9;ZP3e?7IFV%sX7cbqf8rVf+!e#GjzCg|&IBzt7 z*y23jZ4v`JhQ8}6=yf=Z7XcMDgx@Wlsu8B!gqtk#oPBx!-FZRvgTNl*fqmG(Udxh! zC6zHaMy_KcO#Kx~p!h~7e$H*81xnAp)Fx{hARtUEgv99xxk9EO62c zqE{#RQurJXcAc8}cq5G3eRe3L-K}HvRUVzrP>ex+<4saXGg*|DWPqfAhj$A0Dz-{4 zF_$g{c!cg{0^h<`^3~E@-f+s@{5tp3*g|I~tQGb`<`>nbI1GM=B58r@zlP{hDlJyr zC`ZBks-6{fPCt`nK%@^;qf#`O1w}xii+Hhi-C0Ibi1m1hVjT=meNt=Km~kajLjJH3 zhj5Bm<`w6gk3a2?cA5jTM-`_0pml^3!ixS^H8Nn-swnLFvg=0KgCq8qauV ziNk>SrG$})3TXSCa!{Opl320g*e~U_VY^(U?sI`aaCJEp15#jy1!7MM7F$=w? zzFz@k99Q~!@;n5`&(uZFh<=r|rtfhiE085QaRCX1_^1v6_T0?J(dSb7$om@xHQnLyi!>XN;c ztqp(VwznrA$2AHTXfvoQTIF}$aUDvDpfTp^hXzy{Pm|Mfs5<{V2`!~LSbUiyVzu)q zO{!LUzm}i4qxOULcgzH|D{2088g1RFkn{WNvCc`O?@@*L=s2wqIcHkY$mIG0Cdp=X+Wjmi#tOa^SNcL4Sb`4EO~5 zT7#>Q`q#G$G-|xnjV{cN>K@WPv9mb|@5Ur$_8t>tO#rlR7HcB(kVCy{lBwj|kBx*h zzDp)g(&Otvl?#~{tu!n&x53}v@D+C8c4y?2g8W4RR8HGl?TWfF z1_T{Y8n@OiezPGK?8%o4>CGj7W5YJ&x2#k^yOX@5>&!2Sx)wK9!TNIx!8#+s7s2=o z0;G@%GK+AGD99hq`*76GT328V^31nf4h)ar_-7k8zTS41kZVf0KQH>Djv6|?d;thUCN!s?3wd@q9ks%Wo0Au+olFEeopzIX zp;7H}wqZPlY<&dHyxi%}9{TpPc7i;->7jr>2n7<0A=|}>cwy418A%TL`pTZthCa*o zOwXCutZVP3YsEtPYaOpT=k|aM${}J|J0X~fkbCLOh^u-r9n$gYGB@ipD z?#JzIl^q{;XRtKg=HQ=(@K^1@_!Q|&SIeRMF?VKbaEC>}oYCNJM0A@G8PJ%{jK-UbryrUb0vKO3HVcWKM5B3$CLIaM3Fv% zE2WonZZ`S;=JA=xko&_rq!>SLoUzSt?tn_5t;+XXla~NCS8YT5fxza?D0h6gxNv7I zro{m_N zE5h_E8R`Bxa<9(pH+P$8+n%+s*yt)ldi>K#7{iUz_mE@OY;&~le$9Qe;yHpeATKX( zoC#>U0NsG|A`W)?!<430A(vv=p)AK@j{$}^B~|PxycY7<%vvS+x@*SVD{Vu~YVDdS zGzrB|@+h%vUe?VNS-UmPYEdg1QY94&ZBX}C21b6us#O*+l}_pIAWb6{%ZKGjlsbyE zGuJz`wiz9#k)sOoeEU=)ZFQb?+^ut4Og}{L71F;IaE7wQVl&Bci zebNgabELTmjGj)K2;j67$iZ1<0k8YF=3b!}?ITKC4h}RR$=T#^Pv7^I&}d7eevCK& zjCX)hK}WyR!^5l-R4F#jh$eqPa}v35-X1NEzPqEcB)FSPEN4nqp>XliF3XWjo+|jV zsBowlI8Gtb^=NA&jXw6T36W!A`#Y^uz-C}xC{^oO#a$>=iwL_r^D&0u=HrKyQ( z(LHQYQv1J>^@~VtRn0$i4e95GUI*E}>7KPYuZwH2r6PbO-t~|}IWCL0$FP@zyR#)3 zctJ8-?c7}3RW@Wz5DEDwgzZ^kPLopnjhIY;DmAM>Vp?W4MQ!>qwb1UC zf97X5(_V_wLPmZ;C%oNvxuqSRq%{Zpx3*6{CC%x)bs|BHbXGEdBxQ5)YOF_v51Zv= zTw6W9N~OROYktIkJ=lv@xwm%TRh1T39GxuFsj8TBA^xQ_KL}3!RL@{x|4A#LulgU( zSAO26GjK#^9d&!0``$eBo}_V{6;?tfy4Hl1Vj~~OI~ILGc>K)yd#bw=JO*~r=tb_s zaLl*itg4&RQuMV&|FPyRFG@aeJfc~dkMKZnlkJpcG01{TR?gmHFqN+|_Ez9tr{R@W zHv4|Mm*BsZsF_D*`eIkf%&tdRh#M|<8gA-hI+XPHU*ZpF**Esz&+x@?Zw!)vUh<rO&xRbxf;~)H~<10vZXTjUR<+b__5=?gh2};Tb|NKDFWn0dc#jG(&^)) zuHQf8Apw8Uz(0Mkv&45laZk>T-~+HIaX(}0PFAPki*{<-5s9f~Gt+mry9H>lL0NG| z*d$v>^XTQvL4h6(jp!OK>h`|o;@1#8Iw$x5o;H8XyY6Ss-b7B1V^8GjfBNP zzi+Wj3y+O-L0FvMduNmB+F6l&-x7ve#?#dB^V+A6R6r*5M-^lBl_eRpCI8hRmy{KPxC1Y3d zw2|DOP+EOgeryD0*AT4=!L_!ijE_RGB!tFvU>ydF+pP!VYHbH^tSOJJtf)P(6X(%= zz@@P)O%{vR{xXjCvM4I=X1Ue{SW-wnI)j!Zar7Vg%wyvTAzdp}?bob5sdQ0oR(ZZb z3J92TxOH&kwPP5!@_9AWB23`+2Mg^MBP+&aL5t7mcy{-(I5T4yzkcf3N)u@<$I$Nn;KpkH%cb2-<}~|fX~~GmmOdfeot)Zz0#@x`sSGx{ z+Fb`{!k6ATi>rrk^RjrJ2g=!pyrA4ufc#WylahHO=W ze6qUyx<07k03uDvQ^}sZ3sBdpbri4Nm$bP~+R?2e&R_v%RV7h-XT4d(Q;5!>V(nXO zkgs&PeIk0YYhK$I1H`VTxVJOk-ao7SIj5Lez}ml?EW>!G<0*&>#U`*$KQKz-upz^k zO!9yJPzElYg_;n#mijap;F3*(Rw=Py3hqub7P470pHs=R6*`1BTWpt9p=x%E$i8g0 zx&Hgy^t@Tk>X|t2a#K-#Tykkk@lZ~zp8kKmy?H#8|NB3xBqE_gS)(KgrI4&;i?L+i zO%bwA_I)PVVk{vhvXnJ@_T7|yiHYoEY3$oDwlNsycaPrR&*y#4<9q%&kMlVGz|4KU zw(ELc>+5yjcR$Ca`s0WB)Te0us)Lmcn0;kW9w4LnXXL3iW(K%P%&>a659RD=8JIS( zNjxqwgtL_U;oiR)Ps+YK(!}WS?AwosiG|Yoz9dM@Zy&s~@ZMV78M(x_&-!bRIm38- zzkCu8dEo4GJ&N+!d6@H;_X^0)>49?ICvKO)phljs!SHuMG%a64cGb`PWVHA+MjyZH z(_m!!%Gn}hdw+sAhW)#0`lI_JDfHJ%fAx{-?p8i%6qb_bfroB$)URRMmra;vt{NDP z+@{uisCAnJoLIF{GcsWAiw}kS*Eo<93Hi31oi1XO}LcN`TIbqJxzg>2N_r@GOK`!ca9Q+ON6jS`jg3G{p@7ELw z-(P%^3wtNitMQV1&Fj?KyE*5Kk=onlv6PSxrK{w(tMz53F@U}^JaplC!jzyqa2l4U zr&L@81YzbFlNc=9>ksd9epb~*pCKSv8t6+b^@4TGA25njT77H`Y3cS8XD?8y*=as= z+vR%izSE^n_GNld3KK;dNJw ze!}+Z^E?m;q@W#Fckh1?pf6kKD(INW^0wn*Xg17FQqxL8m!W+(=U#D;hjS>YKpYiw_u4Ys)(0<(S{2*qpQ!i4uZ@)-zS^st zF1`a9)YQ&lzgdD)v70bkVLtASLpVpX@(h0#1hHs%^h8JL3SC@g*A{3^uj{KQlvQbRwYz zZ52Q3rw-SN#>8zx&|bc0xBe^1h=jG04XJ?Nff8MYlF|vrVA-Y=sKyc8a#ManSxbLT zsnZQ5Hpes0WttEU@tcX= zXHg6tZph^y72@hEC@Q`9Ek*$=!<3y+@d1G!>P*{7Vr4Y?lXeICne>8>av%Pr-=(M1 z38#fQMixA-&*p1Oau%1eDBW{sa#uymxNWW#q2f9@uxo{aYWL93_dk{Gb}}BBu1o(|bJmV3E!JX^J*TFMqOsJI7eq?*Rv^L6gCP z%zj^;1bgCOrLJkl2-+>gq*il&hW1tJruiEaq|C6_{UOg4b7r5K^DcE_;FNHsQ*IXg z;7o{PG@@b&Bq|K1b>xi?kAD_p|; zGuHTN5Zs}=SF@>(bSk0|czy1=(6N#t#;f0WBi%n!(J?fQ^Vd@PfQ?Zx)pZcRM-@N* zb;tk8no32%q}%Pje{NYmtE5FrpA|vSJI(#kiLu0fffb5hunYe{l**ni9a*T&bQ(G9 z^fKj_N%nb{utU#gOOReCR-RqLOLA!>-_>?SyX?Gs&PuY0W9|t{DvlFJug(uI;8hx9 zg|f0$XYLMpPcE}mO3=U})ko7W`i+=zn<8KbY9Ah%&oT`$J-6@v=quyqbzr6T8h!!m>>aA)mdiSZLx@Psx4k_Ex9e85E_ug@3 zlESxg^m$O-m@&bLuMbnuMN0ArX~$RR&O^Rg<$t>dB5NHZl!D?_%LdPLDS3jSnl#k4 zzeVv-yk0UGyn$iWZET-7C!!MU``jr;)T+|uDJUze(OO>DOgL2$eGQCVbAKZ9-UD>o z1?xVfW&_xhx<%~OO96`DraC?k4WX*?(Qo^%8ZDKUoEICN-E<&@@vU)e%ci;WIzB0R zpi+8qX8}va#;m+5eyfUmcy$esCH;NtjVxSsmMTG{M8vrRQ+5qISvK~VVEsFxq^i;- zTd(I5^axZD+5jUq$@8Q9Rt-(YjYm&!8HY;r_T3aVj5HU~y&hj94mpcKU^QrKw4KM< zZ^C+>yKVKsseWg}S^n2GYg3oYiOO{d9r;GfQ<>6rGJW9)Hvln119-1-Ay*W3J!^MZ z_PjyJM3>$wg|)y+huq=Jn6p1!KuBd++h?|FFk-MN5!_Q_df+5w-Ki(Ee6a}0=c0U@ zXc?5@P>F3k|Iq60G4-En*0*`gi64 z@)Qri$yqX&+D5Bj_i2#k#*cnmLJAJX-L8r|D|PaASR)?LkJy>FBwMl@7yY3{o{wdV zSUkN`;BKO8C~_q)e|D_cetfw+2f+CAbIss{sSx1}b2mz%P5mkAb~&HP*!*q3B2(z& z=Z|xQZ&G}(o84pl#(9k>$j2pD`;~IFZO;FSEqIo{Z4ffwNAho2>Rx(LM+3v_$jByA z>PkK;d_;#-w>}bA#;(uH9g9i^_s(aZa?LUw>dDq$=JS#{omf(Js_vSvVzI*7sRD=E zy6Vnw>B&F0QIu|_907gP%$-6b^FzD5%=S+EK_B{O9rZt0N?AYc4`ET){%#rJ`}+pb z_mR9`d(JK5h%E@tSo>np*I zx1!>GCSgmxRG#BGFL#G(M{9dV9h$SB7(Ty$t2$N9wn$-Z6JV5ZYP1*H< zXkWNUMMm{^&Q#ElEVgxVoL2SO$=U=fCyf?U9S^k4j(WOtn0BPop@fwCh)rI#Id`4V zW1YfUyD@7lS}q;`AO2_)%(YlZp2hb>u<_kiGH$KCAp0up2ca+4s`afK1E=A%FoRc( zcOdh~$zbb3qLi3`6M*_U=UM2+BdvL8eq(Zj*q`r#BqI%Ru>|P%iK&~P#VSMqtX=s2 zUrSTwv(we#TBg3BP%T)}Fry@LaGc*XdGx3LLieKo4!$?HZ(j7%Zhui?m&x(e9&#js z$q*r08%NZa?Kw5gJ(-;4pN1ID+fKmGVfIp_c}6hU3KLnV?ACmypM%zL)x4*D5^1+o zfi#zXTzDQ;yOPg+*tt;yxPxHh} z>HArIhTWaI3{_lC<%2%EB_uy5Ev_^M#P$snn1u#uUScZ4V?nf*-nCpFBvpw*N$(3? zy`@o9*JTRIc*Cqa_~~ms@5&?bsv=dwUQGIMRog^`xYF3A`{DN!zT%~pBY?t?ty_4d zMie$NzZ?hZXzv+pgT7K7thIDa)hTk1E~K*y>M3mA=dhK-XhjF{M*d7tvGQr7tTuBgJbYI$|{XDsYmMGF* zN1GkuP_mi_B?xQ6CDdm#?2*vmA<>TY+Cw5|wZpy@_t7iiZC$yecoUQizt)^*)t$q5 zTXAdSt-4qC3Y*)%rypLGcq7bo^ijmG4h-qtUENx+*Y%4hgfy0co9BdDXvkW z!A~q}9J4I@vp(0XZns>J=YXua#~LzSSq^&nDcvs4a_x~&+Ao)Ihc8xSZobFC*K;a( zz~u}bISzyA^U4&tzs*1H(!%l^Wk?0TyT5kR!1_loH8W7$ZT}a#CAa@Hvcib-W9LMm z`|EH+V!#pc7aeIBJH0IfCLq&&ZaIx&{GAVogzLG;fI}uJV&F;%h+CFeD;GV#y=ZnE zy>UQS`*RXZd{Wvs4}~7&LPeb^OyB4EUYaciLbSVs1ALo0*hFh*jMvCquClZIH)ez0 zv)PUOIh=xas_>jDmAZ^PRoxI6JhOQkimHtiO2+dh9k4P;{VL=Z98FrLf=C=AvSW#B>Hg;f83!&SL3BSwh$|}sPUo95w=`}R>N@>khGvUO zU~@}DPd~t z0#{t)&%q5`cT!qnuy0-@HZ*uSzFbJuNKSssf?*XiX% zYsiuE-bW)>zs%Ic?c%*AQ<$H~&6qgLExNbCj87sq>npyeG?xqrH>b-zWEM$&Eu5Gw zb5$sPH}Tl$TDxz(y5$PNt-2bqO6^ffi1!OJA?!Y;0EOTvzZd`bFD7|`u7-J`2$qk! zgz_m{Hv^296?M_g6txjd{oM}cV{c)3Sg=;fRF9s)n(376M>cJksUDGApF_0+FJR6^R!rRzAx>r`Nvx`vDeV*X=vK@e@ z>0yFO`2VtR?xI2ZJF9IL1G3rj{4VXpHDe}&8flVx78?h=pjbAs1VwWhC7V_E`q;3E z7Z_J+6BzeNaotMCOy6d=V2SralC8hC(Hn2#P0?8Lb1X`*G8EO5Y*r_&&c#euh_)VL#7N| z&mnH6f-DL_Komv{nCdcYFu0$en5`eS!g|KU3W4$U0dozaupbyq)N38Ln2*|64{O^# z7|&fcrJ?v1O@@%rI4L`oAXO#K9#)lCJyrHhJa~D zOYcuA$xSmuebzs#60%jz(EP#gIWGZfz4L^SYk`?o+W}q{mqF>fA%8dqB(!490H}NV z;Y713Fw-WX%X&i)rfd+{cvn`R;8bR%A_?~0iF%`iL7X)#@}g&aLStM)4u*Ni$uMWk zw8D4K*F*Yp?ej-NOfl&ZUE|W}IPf-p`aOIFTe5`kU(@A=Q|2ls^N1{#s5O`HS#8ts z1Q$X8XYd9`Ng>Y;Whm8`KAga{T4@Cww2m=w`w^-c(jO5*sJ+~v^D?B_A<}Mu3t?S# z>g-nH`|7a6KG}rosCmHfL@;4SR_CzV^T4y&{C~H>WHhe1EV7EXoTCw#-Z>BRV%9M`c;BV1+T zBk=q(v~~gIb{Nc9c74{%?o=>01;sed?;Z2@np;Z?Ln>?}JvA~}<=ssPkB^k`aP~17 zu9u*DEJqnQ_|N)t<|e_g96@5$M;c@Rmb;mZAyEKB@`M+Hqveatn_(BJcTrafk12lL zCvsV~y@bO(Ri55Um-Fd^$h(ml>hd;K4qc*6D2IRoGm;!kf~U<KRQ6}`4%ndivsDetOuIaBf@r>-*CL6FR+|5xXn9ndDTh0g_ed=wN`;9tt@d?fH3$owm zz@R#&b~_seB#!8XDoW^ z81DcE?rK8pFEIGzOaDT!$M1HDiNSiYd-JEUQFbN+k7ZQ$IeLYvb(QCp-t&}(Qs$sc z^G)90 zL{0@J)O031{DXKz`KyeTHQYew2XUQ%#4lGy>@*yN`j{}&zJPG70hqpD#CH|$<4VI= zk)?86a?F{C9ry;uGy~`5lZ1>KI*e}Ki0Hyn=qnta;|bmoCtHiRI9u}(b4|V2$5?Tb zKW!q%Xy{Isvm||I_xQ`xL0!r4Qhg=&t(%yiEp9>%p8y_CO6 zB7S3X?z-W#`U`Jg7k&{95I!*UaKNb>@yF1A>$lAFR9cR@MHI67bbf+~%E*P8>s4bj zct=Ynwm)mejRslF$&L+t*j=eMJ~lrXD(qJ*9UUc5oJ=ga5YA~7vcNoIBE|wWRVZzF zkxh_k?S8m9s;j+7layQ{eGokT(dGu1T-(bRiKLyfsQTPJKG5Z3OO}S_4YoTdx~C4i z)~D8sP65a};0DagoyP>SysA}5{f2GIgDI2d6k{n^Bd=fSdUsG}ofe>K zu~&}zOhZ|t3qNXJ#F^E80v*2}2xaL@$L0mf?8?y0+|_^mi5DByUs|g$b9$vvcl_=p z8Q75C;Y8K5_YsR(9Tr2;Lc`L5`UR1zo>AkRfQn$zPXBJmuPwa~k*J`sTE=6_{yhJp7TA?sf zEBzt6dG!0d{nkcXV*7*ZfIU=llv^$J-YWEJuBL;D?cX^nMC|dc8&ag=dd$q+1sI`# zMVuyEL~V?m>&psomp0Z*g%niEYOTvG;z3pBWKgNnHHZHUKDw{9qd{3@fTLSc+JDdqs@C#IWfe)$(gU!;s4bY`%8O z%_T-ch3zbeu&j!EUl#=xDva`-h98xq9kb-)ajTY^QJP{jyNW3_7u0O&Q?PXU592Fs zeVW0S|Jb|otuMbm7QBcWxjg%5y7;kiTk(9`*$oAPUnF_mfZ2Um$HAlP*3uvL&${^z z%Nr}WNc@qd-JBs{$QMMbWMAq{3?!z?c7^i{Aaq}5ve0i6d8H-C?AqSXY8>7!@YVS) zODUq0pSkl{4$)6HqSWKDWJY{vV{*r2Bi_qE{K}`u8!)abBHi@PJ`Kp!#CCPgPg3Ca z1?R!QI+|giX!)phK#5=-RSkE!QCIO3#G)c=s@l{9wGD(u#pfDeMv9(B%)>kiZ~MA? zVCNDQLDk8(=`OCu@>I>G@tq?z4O~A8QU$72x{JlOWf7&5!k2O?z9{e(Z#(Ia->oms z))Xq~oawkm3;;rGgLVkFEHhc!K6?nwgD5-YnaxW)fT3q0M~E5CB8d8VBeUY6)q8ar z$Crq?qIHDqd>%Bu>uZa7mD84?FBf6|0`clOi`hn0dJuUvQg>N$Z8<9Rt3Mvn zy?i?K3uJnesH3XJ{zy^!8KT%+tzh%)ZzV#i$s!67wIS(M8q0})5*E%ne0$|C)rW2E=tugX|$OZvq23w zP|=J|rh$7BwKJ*Tl1Js>-vM?I(VyEgq2g_wYGAh44=N+R(uJ|7~{hRDZfaNsbO_% zIYmUO+0!CJ0@l#9%$g-ARMRuOJ9Wj4cEHMaO3hMB@S*vJsEDdAy}7LUHHUThAaw1@Nr4H8+xg^kU=R%WGwx`2Tp|uA&)-2KZIIIiZ9t-gPd*NYHqSb^LXAXfF7-XZ!t6@E{O$}GfHljiLUvSRna z<|;tVj%7x?d35cEckcoW>zcipo^W)(x~BX-4NMCN7ZaF-qTfevvj2_*wvGOi_w9#( zohHnohN-`TTytj(Vs<5n5zQogHMoFpTf1qhcm1b|ks`tE6T=|H7y+34yZkrv$5Xcb zAq|^B28o6EuT~(Zfj%>f`QMT{S&jEJtjsI>JgiON(ParsW)~tuz~`&%gx$WmV_;2Y zUnh2}+@6{iWt#^%W#G}3vufR;GNTtUhB`90Nd*dc4O&<{1Z`kDME85F5RXx_3{b$EG|~pU96Pw zFpV)>)y~RwWo!SmRQP$-cuk83?Z8eHD(Hd6s5W8fslHczD=mz}bfO*qQG$s^lVBy2 zJkur6zx(lnxS48?^=vhl9=$pLP&cpMYi&|UC#{&h> z+tJsL6f0X@IuVRM%KtyEKJ${Vk0@g+JPL9*1BGX8j3kc#Y zY=2x@{DN0J3aC|n)abHe&=eig$lAWY#ePfx5`dQtuI z46>CLNwYuruFJuda*a_!g`EFA$Btr}MfR*Z+-n`{-F=6yP`m-^2(8`kSgNs1ZM_4Z zNWBs4bWdBMaH?d@t8;VqN(9q6X(|81N-t9kuOWdCC{{r7EFSw;9cr*q6I~GQ@R-m$b{C#v3JRrv@X`Lxdv)G9;Idqz^yoEWaVY-j z(LR`;h-JVT#>;VEQ&?bxM%8DbfLbEO8xLE%W+Y@<1hs<7JMI^iYCSGYw$^Gvy^&}; zvhnN3!YNtj}^pjg5(aR0r%mDH!u9_5b%p`5osdS*;{74FVfzeL-j6c@gN=Nl57 zJ{JC(nXnd!;QupGwJ2V+|1>+K(&2V=l*~kSU9{ z_J$>=i?vqo1fy6bVZQ={J~v%3)XEnONB*#Q z&}iAK^Fo@TtY%H@9L%xhT7{69NXW&4IJIQGZ&JL$rPPY$v#+aZ-9NX|bALz_PE&g? zsv+in`8a>B)J2yg(&06ThZ6f<^685goI@`W-8Qq`UIO>8c)=&%R zUVo#23Gth<6(SL)m;bbdAlX*EvGiosD&ZBwz1d0x?9j1nD?}Yo z?PvFMaZ+VZT4%S6V>3OER@9qR36r?TMfCWOvO~AyNJBhNQeL}6B#O~wm~vQ#1BW%t ziwD;XOBamL7X<+Kb02k^sQ*p($8P(?ySr$fJZBvaVf<2ZewwkP`fZ_9H-a7_Hn5bt zjs~erP3w}~(S>+=Tc}Wp<@befc6)^A0KexuM#E<=KJWl4-OUr9>s+tnFNADj7rDLj zwz&jF*E*+--55eVMJqOYT-;|f6^uRY>}uG44vBx$Dzt$Iya9O`0t+{>;YS>{oMGo9{kwV5+Cib&4l99)z$-}15(dt>5Izt7 zvAm8@0#?J<*9f9BPnwClZC>R+lKqS6A1xQm=++3&Fue>Nnl*xfW|*OkhH}bIX6yT2 zay=5OLPu>oST(3FvHc9N05Lc%l0(0`!+6?y7fa#FSkkdHGJ@0wCj}jv{nT6{nrTsI zskR_x8}O*)s-MLI0!|;7(~zSM)K!-_bL<8So2PF?n8>^E%@lXs=0g+ZceB@5hiHQ5f!fi(@BAuz^#&fw!%KJ#z&_ozff zC@8MS*g zR(*pOc5epbItISkl@4z%0W@p=fcC_IQ2{BZ>rVVYD0{J9y!fkKQ^t4{<@Tuq>xIoj z;3U2fE$MmLTvHeIsaCf_TzxIw%vk}a(LlSr=8c_9bMuHQn;|~2!-Rq{;p5w{n2ukW z3DvDW?ad4}+UK}&9ouX@8>TxE%2uyE9DAq6-!n=zTj{kyx_Z)R{A7q+h)=D?tD%ff zPbfJ`DXrpj62li2IjTZO&5J4AJN~Z3Dg2dN#X-3KPBwebKeF^B$&1EnhQ zBUr}Sx7y}XarF;|a*__<6vEg_CzpSOMt2UmzNvOzv zRqAluBFfhYqII>?(7~BEMFYqL_)}txL#CDJKr-T***fK5<2=pYwnU}DLHn)qaPgZ^ z4UcWJEI6>}={Tqea)uEo(Yq$dP7RcxaPZ%?-*-EogKiuC z;JYvs2ObjF3As+l9}ayu6u2Nrv|HORRu_JM6UFJ6iIcjQrca=b7mZIo>K@|oGh#|t z2TVTBOh) zaUR12B{kywwYoq;-evq<<^ix2o) z#EVHGS<6oXfV~J~VV_bk2m0bkP*aqoOGwDeHxsJ~=76cNGK)ln?Fu!EfV1T*Xax6l zd~|ij@BZ#p&>o~(tXnV0G>Y-40*tp#IW)md(1y6}7=>d{@0rxeUC6#NxZBz*FW}kl zzZ99T+Mc0MFOqe$dQcp;gGvLxvc1IQ3G8$Y)-aAD>A>Uhd4*AZK zL$GBw{Ea6DVWY=a?$ONcz~ycf5nW;Q)$}V>2<%y$%wsYASN*k~0V_{gFf1`YH`)|yNZB}PK z4#Mo=AKWG$jKUhmOZp|~T78Fss?tfSF;4?zSx(IeCtd4CikqT+n@>5@w(U0QYu zIXd;v78@M%s&{h7Ut~P1WK_~)$)|0SDZsHR@rl>x{a9~}VC3fxWhr3cN+SJ9qTJ(6E8CM6OCG2%Ao(MCa75l3iA@U-WoL)U1^;> zY{zloAGoVL?I1**1Ey?mAV|y`rjS`;4eO#z7kLq?B5B7adxZ|xFpOA{9MANL^&iT` zD^8E2^6n0hNBp-@Ml*v{c)%gF*4uC22(t--PhL z7rABeuieQPLo*rn|1#n~8CpB{)L!qBYp{B6?_SC#`z2rogXEJpze35=@@v|EdD3!S zB^~#Fzi692TMQL-llAUcw%y7B>@@}7f4c2jxTHlIW^L?e8hB5=HSBt@xk2cq0Z7{a z)A>hKx-@G;^!tz0TgY_3Kc-MhKqDv=jDa;#RE5~4vrEd2?5p~1vBWv0`|Sf?j-RZ^ z%Tado0ctxw2Y7e)?};u3V5(GPLwnF!j-p3yEnP~l+51Va!tDzbpOsh9`aYWsN6+*d zuU(jy=|am-U36|*{5csT`@{4A812zpvY**WMKtYf-62A60bj`rl36W3O&*Nm`Gu3* zu<67dedi$0og#pm9520*lqVA$Tma70P*Av$H(e=qILQ;CSUAaom!!!3Q2abaCivw= z?uX(dC7Iy!#z{YSssEROt~bLDcI@QHocMh8FY!BE`Xi5l7~mUif0y-~jYe!}l(Q%=@Qp8Dhrwf6g`?0qwp8onUxjW(?kvs~I(Myu%;1H~o;< zZ5pPs=hwRqbN%Gj158h-4H%EFyN3#BBX#-&mF$Q#jx^F1ZioB)#$jqdc1JtSOFg>L zr6STtb$e?e`z#=W-7{ony!r$5-m!6Yk^(k!)KWjSR^+`m=R=a~+l2u%VkZo{EA3^s z^ZHOhA||a7i50U5P+gCoxIayJxJA|-*oh8eo^ENuTnUw47h=}7BS6V<^KyGe>(vu} zz@&c3kx532$lXL91aV)T+B{oQ_HuYmwt>{H4O_4PX8s0B*3s|6vt#f~;C5BnZ;2v9 z8?fj#_QtJ0YZy#6UDG02;T_0ecs}y_xaT@+Berr%yX&?q+98yGNuTD;tvxKn)D@N9VCRjg0E>{BYI!o3FVcQ4gr&t$aKNWMtupg{fTy3ry$%5+ zIbJ2BcI~0CjO2lNBO1IB62HTvVj*#$kAyE0O#q5F)?^*}eqlz+Rv9w6n7ezB-a@h` z0QcOdRRJTsNeCogj=okf`-ifnr37!OdXUo4v>w0^vj?;;q#@65I0dA2L5u6j?#M%* z$$%q;7F(`82Ns|;3nkgVRL<9e$QW$E8aBwsd8k{&W z*h0UpM>2k+B@V!~k0(nXjsmeNd%aOHydiaye@f0*2N?8!x}Dkd3-z+V9=%uZ3E=j# z)^Ge1foOOZ#!-i#_j!6O!LqKj?%jeTB96w%Hq@Amzvmj>_?dNo$?5b7T!iC-`Iej9 zW{`_(mxm!ZiEa+&@pL)_yalY?c?lTiP3=h&PVa?HjN$Zx(`zrqU|4<jL@Jf=e z>x%-n4)##3)Gbpo$kk7H1l=acv}7JOo?6ej0}YX5D7gvHgPKLWPN}E%tcL)Z%_%b9o3^l*TF@4&MJ2XO zPE{^cbGro536?%CE(by-n9%+|+xrw}jfTI|7mms^RZ=J^)g_xn$9}pEN#pS?)SU zW{a?weRVZBNDRD9^!zNXw~>})C>gVzEF$WV2SiqUjZN`#3w;GX5CEd`tYjoFaql&C zNLipV*dR_|-o6srBEDTNsMN0{&pVPS^Eyb2QN)r1G5;D7-$)@700R3(gIBAs0>jdr zu;o6N)C#s3#&k|(>g?M8%pORJUDhq;bV>9GB@Kmf?#A#&=iYj?!*?b+@PhJ#pk)M%*zY zJa9Ug`X((51l$2*r%;%cyWie%^lx%6Zrr1hjdxugt>}%+Ctgg)>mzul8INOo77QxB zgYDpx6=cVh3FtoZB)Z|2_UNvkc%%rOx46{k%Y=b+>lEYaRSx)sHf}CKxR4zX5J3Bk zY#-$19v-QRxYkRp>opga>g)4iAjwLlFH783GNGpAfI)v=-sys!cc&AS%lG~mHw@}=#UJKw^ zo)^pyxAJ{|0D4a=br;r4x&3u!q}FY6$Z)}T{cu!p_A6&Xyu`lKN#uUQd}=M(B_(Hm z8zu~LhEL>Y%cr=G1yLlPPA*vvv_Hv9T#PyV7d5?C<5>MfG@KdAw3WvcKk_oWT48H3 z{V<%n!paMQo8CN&WCm9K{R){+zAejIzNu&z<2hR78BBU-Ud%z!f8$m5G}%=T=ME|i z*i|?M|1WuI`5!4vEqN-Id7$fe_{N5EfxTI(Dg6+f9QPE8?7V2n%nFzph$kyrWPlB@%VZPJK0VFlc2c!S7(~`eM&r~Zdon>2aVdz2c{bh2@>)D z)`<>4a`kAYSZczq4)I$H{2&zvqQ`GS`HA9E#suWnFvbl*v>_{h{7H{;!fEVNK9yb# zyD{}bay|a_@lqHBV!u|GLZ}&1g5UT$aeUB!$Vqm9Y$t+?qsvucuu~Z`MR)ogDmItb z6*PKXhNey=xHNA}UGN5E)NVf_rGlqVubGAj0pmO)JMuS8uEzu%uAp(F$O&2mt#3Ls zZZd`}i`aBnbj5U`TdLP_XtFdPoSadNk@WMneTX#kMpc0?LmQhngh#FuWn=t@Av^%h zuk$A`TbM8>+sih{WL$!U`qVjOk6sH|_>o?xDzX}@Jk+Mn_Hp6SK)gXwK@R5SH+)tG zmt>r@PmkOcYA*3Q)vAph+czX^kHd&uNPU3p`vWqTjHt;h3Ha{!hpn9!>1PK6S;~k@ znGs?d0Z-0^lmQ6ksZR(m37cPm0#ZIZA_VNnx1s0Tpe~Le&oW%PHwiZo4<#$)8)q_` zzZv+iMq@Z3IFlM#V5_HgTm-Vw)5i_dEIGtd+$&FeyrdMpzW5~opr<+sGbYJyEC4xs z^jhO$2v~ipDFyZr>PIq(IM8uL)hjc&kf&>T(sf#jOhYu{K%X!l6c1yqHAIRc(bd~- zhpS<>&bzB@0O7)k1S;o&a0}w^@BK0zp`PRd*Y024mcuy z%Z7&|*L^rsy{DHR&;!j1&z}TE9IPmMEiN`LpHzhUK-dI683P1k7T&ETVgQYi_(|aN z30yY;Ar8tUckjs!v{G0Cku%!piT5IJ8n zWgyS4KFC(&0*Z^PaWsaXSbeiL9f|M5NRS){w*eCJZDPRh9x`i_OvCn?Yl|`N&bHo0rS9EPxOOvKT4OBZMPWA4)D06CRo9cKlCj?}PLOYJImZ66rMfr`AMUs1Uz*$tA^VJWG>9bmY$ z&#RsKvw%zvf$k}W&yYKLE}Z7$zk}Y2fjYaBNR1m;r*;=A{jnsBVT?%{I(=7Gq-S;y z=SfBvCndSlZ_>ijqQ0bQfD6+E0`8byMeZ5GqmH4Pa!!0MaSlIcFkdy#vf#Ne40wz0 zePoVM7|9@n&x@pR0f|bTs%#IwCH<=LUYA1459*T;7>Zr;*aQ5+CCJrI1#e;3Lt%fa*ZU6l|X opt.workspace: - total_infer_time_workspace += measurements['per_infer_time_ns'] - - # 推理时间 - print('[INFO] Infer time:') - msg = 'total infer num: ' + str(total_infer_num) + '\n' + \ - 'total pure infer time(ms): ' + str(total_infer_time / 1000 / 1000) + '\n' + \ - 'average pure infer time(ms): ' + str(total_infer_time / total_infer_num / 1000 / 1000) + '\n' + \ - 'average pure infer time after workspace(ms): ' + str(abs( - total_infer_time_workspace / (total_infer_num - opt.workspace) / 1000 / 1000)) + '\n' - print(msg) - with open(os.path.join(opt.infer_res_save_path, 'infer_time.txt'), 'wt', encoding='utf-8') as f_infer_time: - f_infer_time.write(msg) +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ + +import acl +from acl_net import AclModel + +import os +import shutil +import argparse +import numpy as np +from tqdm import tqdm + +DTYPE = { + 'float16': np.float16, + 'float32': np.float32, + 'float64': np.float64, + 'int16': np.int16, + 'int32': np.int32, + 'int64': np.int64, + 'uint8': np.uint8, + 'uint16': np.uint16, + 'uint32': np.uint32, + 'uint64': np.uint64 +} + +if __name__ == '__main__': + # 参数解析 + parser = argparse.ArgumentParser() + parser.add_argument('--model_path', required=True) + parser.add_argument('--device_id', required=True, type=int) + parser.add_argument('--cpu_run', required=True, choices=['True', 'False']) + parser.add_argument('--sync_infer', required=True, choices=['True', 'False']) + parser.add_argument('--workspace', required=True, type=int) + parser.add_argument('--input_info_file_path', required=True) + parser.add_argument('--input_dtypes', required=True) + parser.add_argument('--infer_res_save_path', required=True) + parser.add_argument('--res_save_type', required=True, choices=['bin', 'npy']) + opt = parser.parse_args() + + # 创建模型 + measurements = {} + om_model = AclModel(device_id=opt.device_id, + model_path=opt.model_path, + sync_infer=eval(opt.sync_infer), + measurements=measurements, + key='per_infer_time_ns', + cpu_run=eval(opt.cpu_run)) + + # 创建目录 + if os.path.exists(opt.infer_res_save_path): + shutil.rmtree(opt.infer_res_save_path) + os.makedirs(opt.infer_res_save_path) + + # 读取info_file + inputs_info = {} + with open(opt.input_info_file_path, 'rt', encoding='utf-8') as f_info: + line = f_info.readline() + while line: + line = line.rstrip('\n') + contents = line.split() + info = {'path': contents[1], 'shape': eval(contents[2])} + inputs_info.setdefault(contents[0], []).append(info) + line = f_info.readline() + + # 解析输入类型 + input_dtypes = opt.input_dtypes.split(',') + input_dtypes = list(map(lambda x: DTYPE[x], input_dtypes)) + + # 读取文件推理 + total_infer_time = 0 + total_infer_time_workspace = 0 + total_infer_num = 0 + for key, values in tqdm(inputs_info.items()): + # 构造输入 + inputs = [] + dims = [] + for idx, value in enumerate(values): + x = np.fromfile(value['path'], dtype=input_dtypes[idx]).reshape(value['shape']) + inputs.append(x) + dims.extend(value['shape']) + dims_info = {'dimCount': len(dims), 'name': '', 'dims': dims} + + # 推理得到输出 + output = om_model(inputs, dims_info) + total_infer_num += 1 + + # 保存文件 + if opt.res_save_type == 'bin': + for idx, data in enumerate(output): + data.tofile(os.path.join(opt.infer_res_save_path, key + '.' + str(idx) + '.bin')) + else: + for idx, data in enumerate(output): + np.save(os.path.join(opt.infer_res_save_path, key + '.' + str(idx) + '.npy'), data) + + # 计算时间 + total_infer_time += measurements['per_infer_time_ns'] + if total_infer_num > opt.workspace: + total_infer_time_workspace += measurements['per_infer_time_ns'] + + # 推理时间 + print('[INFO] Infer time:') + msg = 'total infer num: ' + str(total_infer_num) + '\n' + \ + 'total pure infer time(ms): ' + str(total_infer_time / 1000 / 1000) + '\n' + \ + 'average pure infer time(ms): ' + str(total_infer_time / total_infer_num / 1000 / 1000) + '\n' + \ + 'average pure infer time after workspace(ms): ' + str(abs( + total_infer_time_workspace / (total_infer_num - opt.workspace) / 1000 / 1000)) + '\n' + print(msg) + with open(os.path.join(opt.infer_res_save_path, 'infer_time.txt'), 'wt', encoding='utf-8') as f_infer_time: + f_infer_time.write(msg) diff --git a/ACL_PyTorch/built-in/nlp/textcnn/License b/ACL_PyTorch/built-in/nlp/textcnn/License index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/built-in/nlp/textcnn/License +++ b/ACL_PyTorch/built-in/nlp/textcnn/License @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/built-in/nlp/textcnn/README.md b/ACL_PyTorch/built-in/nlp/textcnn/README.md index 0d1a1be488..19f9da537e 100644 --- a/ACL_PyTorch/built-in/nlp/textcnn/README.md +++ b/ACL_PyTorch/built-in/nlp/textcnn/README.md @@ -1,62 +1,62 @@ -# 用于Textcnn模型离线推理指导 -## 1 获取开源代码 - -``` -https://gitee.com/zhang_kaiqi/ascend-textcnn.git -cd ascend-textcnn -git checkout 7cd94c509dc3f615a5d8f4b3816e43ad837a649e -cd - -git clone https://gitee.com/Ronnie_zheng/MagicONNX.git -cd MagicONNX && git checkout 8d62ae9dde478f35bece4b3d04eef573448411c9 -cd - -``` -## 2 文件放置 -把TextCNN*脚本和gen_dataset_info.py脚本放到ascend_textcnn文件夹里;把*.sh脚本和fit_onnx.py放在ascend_textcnn的平行文件夹 - -## 3 模型推理 -1. 前处理 - -``` -cd ascend_textcnn -python3 TextCNN_preprocess.py --save_folder bin -python3 gen_dataset_info.py bin info -``` - -2. 转onnx - -获取[TextCNN_9045_seed460473.pth](https://gitee.com/hex5b25/ascend-textcnn/raw/master/Chinese-Text-Classification-Pytorch/THUCNews/saved_dict/TextCNN_9045_seed460473.pth) - -``` -python3 TextCNN_pth2onnx.py --weight_path ./TextCNN_9045_seed460473.pth --onnx_path ./dy_textcnn.onnx -``` - -3. 转om - -``` -cd .. -bash onnxsim.sh -bash onnx2mgonnx.sh -bash onnx2om.sh -``` - -4. 后处理得到精度 - -精度结果保存在result_bs*.json中。*代表具体的batch_size值(从4开始) - -``` -./benchmark.x86_64 -batch_size=* -om_path=mg_om_dir/textcnn_*bs_mg.om -output_binary=True -input_text_path=ascend-textcnn/info -useDvpp=False -model_type=nlp -python3 ascend-textcnn/TextCNN_postprocess.py result/dumpOutput_device0 >result_bs*.json -``` -5. 性能数据 - -推理结果打屏显示 - -``` -./msame --model mg_om_dir/trextcnn_*bs_mg.om --loop 100 -``` - -## 3 自验 -| 模型 | 官网精度 | 710离线推理精度 | 710性能 | -|--------------|--------|-----------|-------| -| Textcnn 64bs | [91.22%](https://gitee.com/huangyd8/Chinese-Text-Classification-Pytorch) | 90.47% | 27242.83 | - +# 用于Textcnn模型离线推理指导 +## 1 获取开源代码 + +``` +https://gitee.com/zhang_kaiqi/ascend-textcnn.git +cd ascend-textcnn +git checkout 7cd94c509dc3f615a5d8f4b3816e43ad837a649e +cd - +git clone https://gitee.com/Ronnie_zheng/MagicONNX.git +cd MagicONNX && git checkout 8d62ae9dde478f35bece4b3d04eef573448411c9 +cd - +``` +## 2 文件放置 +把TextCNN*脚本和gen_dataset_info.py脚本放到ascend_textcnn文件夹里;把*.sh脚本和fit_onnx.py放在ascend_textcnn的平行文件夹 + +## 3 模型推理 +1. 前处理 + +``` +cd ascend_textcnn +python3 TextCNN_preprocess.py --save_folder bin +python3 gen_dataset_info.py bin info +``` + +2. 转onnx + +获取[TextCNN_9045_seed460473.pth](https://gitee.com/hex5b25/ascend-textcnn/raw/master/Chinese-Text-Classification-Pytorch/THUCNews/saved_dict/TextCNN_9045_seed460473.pth) + +``` +python3 TextCNN_pth2onnx.py --weight_path ./TextCNN_9045_seed460473.pth --onnx_path ./dy_textcnn.onnx +``` + +3. 转om + +``` +cd .. +bash onnxsim.sh +bash onnx2mgonnx.sh +bash onnx2om.sh +``` + +4. 后处理得到精度 + +精度结果保存在result_bs*.json中。*代表具体的batch_size值(从4开始) + +``` +./benchmark.x86_64 -batch_size=* -om_path=mg_om_dir/textcnn_*bs_mg.om -output_binary=True -input_text_path=ascend-textcnn/info -useDvpp=False -model_type=nlp +python3 ascend-textcnn/TextCNN_postprocess.py result/dumpOutput_device0 >result_bs*.json +``` +5. 性能数据 + +推理结果打屏显示 + +``` +./msame --model mg_om_dir/trextcnn_*bs_mg.om --loop 100 +``` + +## 3 自验 +| 模型 | 官网精度 | 710离线推理精度 | 710性能 | +|--------------|--------|-----------|-------| +| Textcnn 64bs | [91.22%](https://gitee.com/huangyd8/Chinese-Text-Classification-Pytorch) | 90.47% | 27242.83 | + diff --git a/ACL_PyTorch/built-in/nlp/textcnn/TextCNN_postprocess.py b/ACL_PyTorch/built-in/nlp/textcnn/TextCNN_postprocess.py index 39e8d8db7b..2c926fa8f1 100644 --- a/ACL_PyTorch/built-in/nlp/textcnn/TextCNN_postprocess.py +++ b/ACL_PyTorch/built-in/nlp/textcnn/TextCNN_postprocess.py @@ -1,29 +1,29 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import struct -import numpy as np -import sys -result_root = sys.argv[1] -correct, total = 0, 0 - -for result_path in os.listdir(result_root): - label = int(result_path.split('.')[0].split('_')[1]) - - data_raw = np.fromfile(os.path.join(result_root, result_path), dtype=np.float16) - result = int(np.argmax(data_raw)) - total += 1 - correct += 1 if label == result else 0 -print('acc: ', correct/total) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import struct +import numpy as np +import sys +result_root = sys.argv[1] +correct, total = 0, 0 + +for result_path in os.listdir(result_root): + label = int(result_path.split('.')[0].split('_')[1]) + + data_raw = np.fromfile(os.path.join(result_root, result_path), dtype=np.float16) + result = int(np.argmax(data_raw)) + total += 1 + correct += 1 if label == result else 0 +print('acc: ', correct/total) diff --git a/ACL_PyTorch/built-in/nlp/textcnn/TextCNN_preprocess.py b/ACL_PyTorch/built-in/nlp/textcnn/TextCNN_preprocess.py index 525a57acca..a3c6c7daa1 100644 --- a/ACL_PyTorch/built-in/nlp/textcnn/TextCNN_preprocess.py +++ b/ACL_PyTorch/built-in/nlp/textcnn/TextCNN_preprocess.py @@ -1,108 +1,108 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -# coding: UTF-8 - -import os -import argparse -import pickle as pkl -import numpy as np - - -parser = argparse.ArgumentParser(description='Chinese Text Classification') -parser.add_argument('--embedding', default='pre_trained', type=str, help='random or pre_trained') -parser.add_argument('--word', default=False, type=bool, help='True for word, False for char') -parser.add_argument('--vocab_path', type=str, default='data/vocab.pkl') -parser.add_argument('--dataset', type=str, default='./Chinese-Text-Classification-Pytorch/THUCNews') -parser.add_argument('--pad_size', type=int, default=32) -parser.add_argument('--train_path', type=str, default='data/train.txt') -parser.add_argument('--test_path', type=str, default='data/test.txt') -parser.add_argument('--save_folder', type=str, default='') -args = parser.parse_args() - -args.test_path = os.path.join(args.dataset, args.test_path) -args.train_path = os.path.join(args.dataset, args.train_path) -args.vocab_path = os.path.join(args.dataset, args.vocab_path) -if args.save_folder == '': - args.save_folder = args.dataset + '_bin' -if not os.path.exists(args.save_folder): - os.mkdir(args.save_folder) - -MAX_VOCAB_SIZE = 10000 # 词表长度限制 -UNK, PAD = '', '' # 未知字,padding符号 - - -def build_vocab(file_path, tokenizer_, max_size, min_freq): - vocab_dic = {} - with open(file_path, 'r', encoding='UTF-8') as f_: - for line_ in f_: - lin = line_.strip() - if not lin: - continue - content_ = lin.split('\t')[0] - for word_ in tokenizer_(content_): - vocab_dic[word_] = vocab_dic.get(word_, 0) + 1 - vocab_list = sorted([_ for _ in vocab_dic.items() if _[1] >= min_freq], key=lambda x: x[1], reverse=True) - vocab_list = vocab_list[:max_size] - vocab_dic = {word_count[0]: idx for idx, word_count in enumerate(vocab_list)} - vocab_dic.update({UNK: len(vocab_dic), PAD: len(vocab_dic) + 1}) - return vocab_dic - - -if __name__ == '__main__': - - """ - Usage: - python preprocess_to_bin.py - """ - - if args.word: - tokenizer = lambda x: x.split(' ') # 以空格隔开,word-level - else: - tokenizer = lambda x: [y for y in x] # char-level - if os.path.exists(args.vocab_path): - vocab = pkl.load(open(args.vocab_path, 'rb')) - else: - assert args.train_path != '' - vocab = build_vocab(args.train_path, tokenizer_=tokenizer, max_size=MAX_VOCAB_SIZE, min_freq=1) - pkl.dump(vocab, open(args.vocab_path, 'wb+')) - print(f"Vocab size: {len(vocab)}") - print('bin file save path: ', os.path.abspath(args.save_folder)) - - contents = [] - f = open(args.test_path, 'r', encoding='UTF-8') - idx = 0 - for line in f: - lin = line.strip() - if not lin: - continue - content, label = lin.split('\t') - words_line = [] - token = tokenizer(content) - if args.pad_size: - if len(token) < args.pad_size: - token.extend([PAD] * (args.pad_size - len(token))) - else: - token = token[:args.pad_size] - # word to id - for word in token: - words_line.append(vocab.get(word, vocab.get(UNK))) - - # convert to bin - words_line_np = np.asarray(words_line, dtype=np.int64) - bin_file_path = os.path.join(args.save_folder, '{}_{}.bin'.format(idx, label)) - words_line_np.tofile(bin_file_path) - idx += 1 - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +# coding: UTF-8 + +import os +import argparse +import pickle as pkl +import numpy as np + + +parser = argparse.ArgumentParser(description='Chinese Text Classification') +parser.add_argument('--embedding', default='pre_trained', type=str, help='random or pre_trained') +parser.add_argument('--word', default=False, type=bool, help='True for word, False for char') +parser.add_argument('--vocab_path', type=str, default='data/vocab.pkl') +parser.add_argument('--dataset', type=str, default='./Chinese-Text-Classification-Pytorch/THUCNews') +parser.add_argument('--pad_size', type=int, default=32) +parser.add_argument('--train_path', type=str, default='data/train.txt') +parser.add_argument('--test_path', type=str, default='data/test.txt') +parser.add_argument('--save_folder', type=str, default='') +args = parser.parse_args() + +args.test_path = os.path.join(args.dataset, args.test_path) +args.train_path = os.path.join(args.dataset, args.train_path) +args.vocab_path = os.path.join(args.dataset, args.vocab_path) +if args.save_folder == '': + args.save_folder = args.dataset + '_bin' +if not os.path.exists(args.save_folder): + os.mkdir(args.save_folder) + +MAX_VOCAB_SIZE = 10000 # 词表长度限制 +UNK, PAD = '', '' # 未知字,padding符号 + + +def build_vocab(file_path, tokenizer_, max_size, min_freq): + vocab_dic = {} + with open(file_path, 'r', encoding='UTF-8') as f_: + for line_ in f_: + lin = line_.strip() + if not lin: + continue + content_ = lin.split('\t')[0] + for word_ in tokenizer_(content_): + vocab_dic[word_] = vocab_dic.get(word_, 0) + 1 + vocab_list = sorted([_ for _ in vocab_dic.items() if _[1] >= min_freq], key=lambda x: x[1], reverse=True) + vocab_list = vocab_list[:max_size] + vocab_dic = {word_count[0]: idx for idx, word_count in enumerate(vocab_list)} + vocab_dic.update({UNK: len(vocab_dic), PAD: len(vocab_dic) + 1}) + return vocab_dic + + +if __name__ == '__main__': + + """ + Usage: + python preprocess_to_bin.py + """ + + if args.word: + tokenizer = lambda x: x.split(' ') # 以空格隔开,word-level + else: + tokenizer = lambda x: [y for y in x] # char-level + if os.path.exists(args.vocab_path): + vocab = pkl.load(open(args.vocab_path, 'rb')) + else: + assert args.train_path != '' + vocab = build_vocab(args.train_path, tokenizer_=tokenizer, max_size=MAX_VOCAB_SIZE, min_freq=1) + pkl.dump(vocab, open(args.vocab_path, 'wb+')) + print(f"Vocab size: {len(vocab)}") + print('bin file save path: ', os.path.abspath(args.save_folder)) + + contents = [] + f = open(args.test_path, 'r', encoding='UTF-8') + idx = 0 + for line in f: + lin = line.strip() + if not lin: + continue + content, label = lin.split('\t') + words_line = [] + token = tokenizer(content) + if args.pad_size: + if len(token) < args.pad_size: + token.extend([PAD] * (args.pad_size - len(token))) + else: + token = token[:args.pad_size] + # word to id + for word in token: + words_line.append(vocab.get(word, vocab.get(UNK))) + + # convert to bin + words_line_np = np.asarray(words_line, dtype=np.int64) + bin_file_path = os.path.join(args.save_folder, '{}_{}.bin'.format(idx, label)) + words_line_np.tofile(bin_file_path) + idx += 1 + f.close() \ No newline at end of file diff --git a/ACL_PyTorch/built-in/nlp/textcnn/TextCNN_pth2onnx.py b/ACL_PyTorch/built-in/nlp/textcnn/TextCNN_pth2onnx.py index 314d0090cf..f121879a62 100644 --- a/ACL_PyTorch/built-in/nlp/textcnn/TextCNN_pth2onnx.py +++ b/ACL_PyTorch/built-in/nlp/textcnn/TextCNN_pth2onnx.py @@ -1,57 +1,57 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import argparse -import pickle as pkl -import torch - -sys.path.append(r'./Chinese-Text-Classification-Pytorch') -from models import TextCNN - -parser = argparse.ArgumentParser(description='TextCNN_pth2onnx.py') -parser.add_argument('--weight_path', required=True, help='Path to model weight file, abs path recommended.') -parser.add_argument('--dataset', default='./Chinese-Text-Classification-Pytorch/THUCNews', - help="""Dataset path, train: $dataset/data/train.txt, dev: $dataset/data/dev.txt, \n - test: $dataset/data/text.txt, classes list: $dataset/data/class.txt, \n - vocab: $dataset/data/vocab.pkl, embedding file should be in $dataset/data/""") -parser.add_argument('--embedding', default='embedding_SougouNews.npz', - help="embedding file of $dataset/data/") -parser.add_argument('--onnx_path', required=True, help='Path to save onnx weights.') -args = parser.parse_args() - - -def main(): - config = TextCNN.Config(args.dataset, args.embedding) - vocab = pkl.load(open(config.vocab_path, 'rb')) - config.n_vocab = len(vocab) - - model = TextCNN.Model(config) - model.load_state_dict(torch.load(args.weight_path, map_location=torch.device('cpu'))) - model.eval() - input_names = ['sentence'] - output_names = ['class'] - dynamic_axes = {'sentence': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.randint(100, (1, 32)) - torch.onnx.export(model, dummy_input, args.onnx_path, input_names=input_names, verbose=True, - output_names=output_names, dynamic_axes=dynamic_axes, opset_version=11) - -if __name__ == '__main__': - """ - Usage Example: - python TextCNN_pth2onnx.py \ - --weight_path ./TextCNN_9045_seed460473.pth \ - --onnx_path ./dy_textcnn.onnx - """ +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import argparse +import pickle as pkl +import torch + +sys.path.append(r'./Chinese-Text-Classification-Pytorch') +from models import TextCNN + +parser = argparse.ArgumentParser(description='TextCNN_pth2onnx.py') +parser.add_argument('--weight_path', required=True, help='Path to model weight file, abs path recommended.') +parser.add_argument('--dataset', default='./Chinese-Text-Classification-Pytorch/THUCNews', + help="""Dataset path, train: $dataset/data/train.txt, dev: $dataset/data/dev.txt, \n + test: $dataset/data/text.txt, classes list: $dataset/data/class.txt, \n + vocab: $dataset/data/vocab.pkl, embedding file should be in $dataset/data/""") +parser.add_argument('--embedding', default='embedding_SougouNews.npz', + help="embedding file of $dataset/data/") +parser.add_argument('--onnx_path', required=True, help='Path to save onnx weights.') +args = parser.parse_args() + + +def main(): + config = TextCNN.Config(args.dataset, args.embedding) + vocab = pkl.load(open(config.vocab_path, 'rb')) + config.n_vocab = len(vocab) + + model = TextCNN.Model(config) + model.load_state_dict(torch.load(args.weight_path, map_location=torch.device('cpu'))) + model.eval() + input_names = ['sentence'] + output_names = ['class'] + dynamic_axes = {'sentence': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.randint(100, (1, 32)) + torch.onnx.export(model, dummy_input, args.onnx_path, input_names=input_names, verbose=True, + output_names=output_names, dynamic_axes=dynamic_axes, opset_version=11) + +if __name__ == '__main__': + """ + Usage Example: + python TextCNN_pth2onnx.py \ + --weight_path ./TextCNN_9045_seed460473.pth \ + --onnx_path ./dy_textcnn.onnx + """ main() \ No newline at end of file diff --git a/ACL_PyTorch/built-in/nlp/textcnn/env.sh b/ACL_PyTorch/built-in/nlp/textcnn/env.sh index 0ee18a6452..a39fd265bf 100644 --- a/ACL_PyTorch/built-in/nlp/textcnn/env.sh +++ b/ACL_PyTorch/built-in/nlp/textcnn/env.sh @@ -1,8 +1,8 @@ -#! /bin/bash - -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp -export ASCEND_AICPU_PATH=${install_path} +#! /bin/bash + +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp +export ASCEND_AICPU_PATH=${install_path} diff --git a/ACL_PyTorch/built-in/nlp/textcnn/fix_onnx.py b/ACL_PyTorch/built-in/nlp/textcnn/fix_onnx.py index 330b61a21c..a9ac8a63b5 100644 --- a/ACL_PyTorch/built-in/nlp/textcnn/fix_onnx.py +++ b/ACL_PyTorch/built-in/nlp/textcnn/fix_onnx.py @@ -1,65 +1,65 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -from copy import deepcopy -import onnx -from onnx import (helper, TensorProto) -from onnx.onnx_ml_pb2 import ModelProto -from magiconnx import OnnxGraph -import numpy as np - - -batch_size = sys.argv[1] - -graph = OnnxGraph(f'onnx_sim_dir/textcnn_{batch_size}bs_sim.onnx') - - - - -graph.del_node('Squeeze_5',{0:0},auto_connection=True) -graph.del_node('Squeeze_11',{0:0},auto_connection=True) -graph.del_node('Squeeze_17',{0:0},auto_connection=True) - -Maxpool_1 = graph.add_node('maxpool_1', - 'MaxPool', - {'ceil_mode': 0, 'kernel_shape': [31,1], 'pads': 0, 'strides':[31,1]}) -graph['MaxPool_6'] = Maxpool_1 - - -Maxpool_2 = graph.add_node('maxpool_2', - 'MaxPool', - {'ceil_mode': 0, 'kernel_shape': [30,1], 'pads': 0, 'strides':[30,1]}) -graph['MaxPool_12'] = Maxpool_2 - - -Maxpool_3 = graph.add_node('maxpool_3', - 'MaxPool', - {'ceil_mode': 0, 'kernel_shape': [29,1], 'pads': 0, 'strides':[29,1]}) -graph['MaxPool_18'] = Maxpool_3 - -graph.del_node('Squeeze_7',{0:0},auto_connection=True) -graph.del_node('Squeeze_13',{0:1},auto_connection=True) -graph.del_node('Squeeze_19',{0:2},auto_connection=True) - - - - -squeeze = graph.add_node('squeeze_1', - 'Squeeze', - {'axis': [2,3]}) -graph.insert_node('Gemm_21', squeeze, mode='before') - - -graph.save(f'mg_onnx_dir/textcnn_{batch_size}bs_mg.onnx') +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +from copy import deepcopy +import onnx +from onnx import (helper, TensorProto) +from onnx.onnx_ml_pb2 import ModelProto +from magiconnx import OnnxGraph +import numpy as np + + +batch_size = sys.argv[1] + +graph = OnnxGraph(f'onnx_sim_dir/textcnn_{batch_size}bs_sim.onnx') + + + + +graph.del_node('Squeeze_5',{0:0},auto_connection=True) +graph.del_node('Squeeze_11',{0:0},auto_connection=True) +graph.del_node('Squeeze_17',{0:0},auto_connection=True) + +Maxpool_1 = graph.add_node('maxpool_1', + 'MaxPool', + {'ceil_mode': 0, 'kernel_shape': [31,1], 'pads': 0, 'strides':[31,1]}) +graph['MaxPool_6'] = Maxpool_1 + + +Maxpool_2 = graph.add_node('maxpool_2', + 'MaxPool', + {'ceil_mode': 0, 'kernel_shape': [30,1], 'pads': 0, 'strides':[30,1]}) +graph['MaxPool_12'] = Maxpool_2 + + +Maxpool_3 = graph.add_node('maxpool_3', + 'MaxPool', + {'ceil_mode': 0, 'kernel_shape': [29,1], 'pads': 0, 'strides':[29,1]}) +graph['MaxPool_18'] = Maxpool_3 + +graph.del_node('Squeeze_7',{0:0},auto_connection=True) +graph.del_node('Squeeze_13',{0:1},auto_connection=True) +graph.del_node('Squeeze_19',{0:2},auto_connection=True) + + + + +squeeze = graph.add_node('squeeze_1', + 'Squeeze', + {'axis': [2,3]}) +graph.insert_node('Gemm_21', squeeze, mode='before') + + +graph.save(f'mg_onnx_dir/textcnn_{batch_size}bs_mg.onnx') diff --git a/ACL_PyTorch/built-in/nlp/textcnn/gen_dataset_info.py b/ACL_PyTorch/built-in/nlp/textcnn/gen_dataset_info.py index 296ac9bd0a..459cea2154 100644 --- a/ACL_PyTorch/built-in/nlp/textcnn/gen_dataset_info.py +++ b/ACL_PyTorch/built-in/nlp/textcnn/gen_dataset_info.py @@ -1,26 +1,26 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 glob import glob -import os -import sys - -dataset_path = sys.argv[1] -info_path = sys.argv[2] - -bin_texts = glob(os.path.join(dataset_path, '*.bin')) -with open(info_path, 'w+') as f: - for index, texts in enumerate(bin_texts): - content = str(index) + ' ' + str(texts) + '\n' - f.write(content) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 glob import glob +import os +import sys + +dataset_path = sys.argv[1] +info_path = sys.argv[2] + +bin_texts = glob(os.path.join(dataset_path, '*.bin')) +with open(info_path, 'w+') as f: + for index, texts in enumerate(bin_texts): + content = str(index) + ' ' + str(texts) + '\n' + f.write(content) diff --git a/ACL_PyTorch/built-in/nlp/textcnn/modelzoo_level.txt b/ACL_PyTorch/built-in/nlp/textcnn/modelzoo_level.txt index eb7302d66b..f866572922 100644 --- a/ACL_PyTorch/built-in/nlp/textcnn/modelzoo_level.txt +++ b/ACL_PyTorch/built-in/nlp/textcnn/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:NOK \ No newline at end of file diff --git a/ACL_PyTorch/built-in/nlp/textcnn/onnx2mgonnx.sh b/ACL_PyTorch/built-in/nlp/textcnn/onnx2mgonnx.sh index 006370d607..a0d93e0783 100644 --- a/ACL_PyTorch/built-in/nlp/textcnn/onnx2mgonnx.sh +++ b/ACL_PyTorch/built-in/nlp/textcnn/onnx2mgonnx.sh @@ -1,11 +1,11 @@ -#!/bin/bash - -if [ ! -d "./mg_onnx_dir" ] -then - mkdir ./mg_onnx_dir -fi - -for i in 4 8 16 32 64 -do - python3 ./fix_onnx.py ${i} -done +#!/bin/bash + +if [ ! -d "./mg_onnx_dir" ] +then + mkdir ./mg_onnx_dir +fi + +for i in 4 8 16 32 64 +do + python3 ./fix_onnx.py ${i} +done diff --git a/ACL_PyTorch/built-in/nlp/textcnn/onnx2om.sh b/ACL_PyTorch/built-in/nlp/textcnn/onnx2om.sh index bc9eefcb40..7786db7940 100644 --- a/ACL_PyTorch/built-in/nlp/textcnn/onnx2om.sh +++ b/ACL_PyTorch/built-in/nlp/textcnn/onnx2om.sh @@ -1,11 +1,11 @@ -#!/bin/bash - -if [ ! -d "./mg_om_dir" ] -then - mkdir ./mg_om_dir -fi - -for i in 4 8 16 32 64 -do - atc --model=mg_onnx_dir/textcnn_${i}bs_mg.onnx --framework=5 --output=mg_om_dir/textcnn_${i}bs_mg --output_type=FP16 --soc_version=Ascend710 --enable_small_channel=1 -done +#!/bin/bash + +if [ ! -d "./mg_om_dir" ] +then + mkdir ./mg_om_dir +fi + +for i in 4 8 16 32 64 +do + atc --model=mg_onnx_dir/textcnn_${i}bs_mg.onnx --framework=5 --output=mg_om_dir/textcnn_${i}bs_mg --output_type=FP16 --soc_version=Ascend710 --enable_small_channel=1 +done diff --git a/ACL_PyTorch/built-in/nlp/textcnn/onnxsim.sh b/ACL_PyTorch/built-in/nlp/textcnn/onnxsim.sh index ac659a92af..11287a55b3 100644 --- a/ACL_PyTorch/built-in/nlp/textcnn/onnxsim.sh +++ b/ACL_PyTorch/built-in/nlp/textcnn/onnxsim.sh @@ -1,11 +1,11 @@ -#!/bin/bash - -if [ ! -d "./onnx_sim_dir" ] -then - mkdir ./onnx_sim_dir -fi - -for i in 1 4 8 16 32 64 -do - python3 -m onnxsim --input-shape="sentence:${i},32" ./ascend_textcnn/dy_textcnn.onnx ./onnx_sim_dir/textcnn_${i}bs_sim.onnx -done +#!/bin/bash + +if [ ! -d "./onnx_sim_dir" ] +then + mkdir ./onnx_sim_dir +fi + +for i in 1 4 8 16 32 64 +do + python3 -m onnxsim --input-shape="sentence:${i},32" ./ascend_textcnn/dy_textcnn.onnx ./onnx_sim_dir/textcnn_${i}bs_sim.onnx +done diff --git a/ACL_PyTorch/built-in/nlp/textcnn/requirements.txt b/ACL_PyTorch/built-in/nlp/textcnn/requirements.txt index fc5acc7efa..51fc9b2831 100644 --- a/ACL_PyTorch/built-in/nlp/textcnn/requirements.txt +++ b/ACL_PyTorch/built-in/nlp/textcnn/requirements.txt @@ -1,5 +1,5 @@ -numpy==1.19.2 -onnx==1.10.1 -Pillow==8.3.1 -torch==1.5.0 -torchvision==0.6.0 +numpy==1.19.2 +onnx==1.10.1 +Pillow==8.3.1 +torch==1.5.0 +torchvision==0.6.0 diff --git a/ACL_PyTorch/contrib/CONTRIBUTING.md b/ACL_PyTorch/contrib/CONTRIBUTING.md index 886fae1007..dc9d11e8ea 100644 --- a/ACL_PyTorch/contrib/CONTRIBUTING.md +++ b/ACL_PyTorch/contrib/CONTRIBUTING.md @@ -1,314 +1,314 @@ - **介绍** - -Ascend ModelZoo,欢迎各位开发者 - - **贡献要求** - -开发者提交的模型包括源码、readme、参考模型license文件、测试用例和readme,并遵循以下标准 - -请贡献者在提交代码之前签署CLA协议,“个人签署”,[链接](https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZhc2NlbmQ=) - -如您完成签署,可在自己提交的PR评论区输入/check-cla进行核实校验 - - **一、源码** - -1、训练及在线推理请使用python代码实现,Ascend平台离线推理请使用C++或python代码,符合第四部分编码规范 - -2、参考[sample](https://gitee.com/ascend/modelzoo/tree/master/built-in/TensorFlow/Official/nlp/Transformer_for_TensorFlow) - -3、贡献者模型代码目录规则:"modelzoo/contrib/框架/Research/应用领域(nlp、cv、audio等)/网络名_IDxxx_for_TensorFlow"(以tf为例,社区管理团队会在贡献完成进行整合) - -4、从其他开源迁移的代码,请增加License声明 - - **二、License规则** - -* TensorFlow - - 迁移场景 - - 1、迁移TensorFlow模型中若源项目已包含License文件则必须拷贝引用,否则在模型顶层目录下添加TensorFlow Apache 2.0 License [TensorFlow License链接](https://github.com/tensorflow/tensorflow/blob/master/LICENSE) - - 2、迁移TensorFlow框架开发的模型,需要在模型目录下每个源文件附上源社区TensorFlow Apache 2.0 License头部声明,并在其下追加新增完整华为公司License声明 - - ``` - # Copyright 2017 The TensorFlow 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. - # ============================================================================ - # Copyright 2021 Huawei Technologies Co., Ltd - # - # 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. - ``` - 开发场景 - - 1、基于TensorFlow框架开发模型,需在模型项目顶层目录下添加TensorFlow Apache 2.0 License [TensorFlow License链接](https://github.com/tensorflow/tensorflow/blob/master/LICENSE) - - 2、基于TensorFlow框架开发模型,需要在模型目录下每个源文件附上源社区华为公司Apache 2.0 License头部声明 - ``` - # Copyright 2021 Huawei Technologies Co., Ltd - # - # 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. - ``` -* PyTorch - - 迁移场景 - - 1、迁移PyTorch模型中若源项目录已包含PyTorch License文件则必须拷贝引用,否则在模型顶层目录下添加PyTorch BSD-3 License [PyTorch License链接](https://github.com/pytorch/examples/blob/master/LICENSE) - - 2、迁移PyTorch第三方框架开发的模型,需要在模型目录下每个源文件附上源社区PyTorch BSD-3 License头部声明,并在其下追加新增一行华为公司License声明 - ``` - # BSD 3-Clause License - # - # Copyright (c) 2017 xxxx - # All rights reserved. - # Copyright 2021 Huawei Technologies Co., Ltd - # - # Redistribution and use in source and binary forms, with or without - # modification, are permitted provided that the following conditions are met: - # - # * Redistributions of source code must retain the above copyright notice, this - # list of conditions and the following disclaimer. - # - # * Redistributions in binary form must reproduce the above copyright notice, - # this list of conditions and the following disclaimer in the documentation - # and/or other materials provided with the distribution. - # - # * Neither the name of the copyright holder nor the names of its - # contributors may be used to endorse or promote products derived from - # this software without specific prior written permission. - # - # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - # ============================================================================ - ``` - - 开发场景 - - 1、基于PyTorch框架开发模型,需在模型项目下添加PyTorch BSD-3 License [PyTorch License链接](https://github.com/pytorch/examples/blob/master/LICENSE) - - 2、基于PyTorch框架开发模型,需要在模型目录下每个源文件附上源社区华为公司Apache 2.0 License头部声明 - ``` - # Copyright 2021 Huawei Technologies Co., Ltd - # - # Licensed under the BSD 3-Clause License (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at - # - # https://opensource.org/licenses/BSD-3-Clause - # - # 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. - ``` - -* MindSpore/ACL - - 1、迁移或开发场景下MindSpore/ACL模型顶层目录下需要包含华为公司 License [华为公司 License链接](https://gitee.com/mindspore/mindspore/blob/master/LICENSE) - - 2、迁移或开发场景下MindSpore/ACL模型,需要在模型目录下每个源文件中添加区华为公司Apache 2.0 License头部声明 - ``` - # Copyright 2021 Huawei Technologies Co., Ltd - # - # 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. - ``` - -> 关于License声明时间,应注意: 2021年新建的文件,应该是Copyright 2021 Huawei Technologies Co., Ltd 2020年创建年份,2020年修改年份,应该是Copyright 2020 Huawei Technologies Co., Ltd - - **三、readme** - -readme用于指导用户理解和部署样例,要包含如下内容: - -- 简介: - -1、模型的来源及原理; - -2、模型复现的步骤,含训练、eval、在线/离线推理等,入口请封装成`.sh`、`.py`; - -- 关键要求: - -1、模型的出处、对数据的要求、免责声明等,开源代码文件修改需要增加版权说明; - -2、模型转换得到的离线模型对输入数据的要求; - -3、环境变量设置,依赖的第三方软件包和库,以及安装方法; - -4、精度和性能达成要求:尽量达到原始模型水平; - -5、预训练checkpoint、结果checkpoint请提供归档OBS、网盘链接,如来自开源需明确来源地址 - -6、数据集说明 - -- [ ] 不允许直接提供数据集的下载链接,可使用词汇:用户自行准备好数据集,可选用“XXX”,“XXX”,“XXX” - - 例如:请用户自行准备好数据集,包含训练集和验证集两部分,可选用的数据集包括ImageNet2012,CIFAR10、Flower等,包含train和val两部分。 - -- [ ] 脚本中不允许提供链接下载数据集,如果开源脚本上存在对应的链接,请修改或者删除对应的脚本 - -训练ReadMe写作可参考下面两个链接: - -[Readme example1](https://gitee.com/ascend/modelzoo/blob/master/built-in/TensorFlow/Official/cv/image_classification/DenseNet121_ID0067_for_TensorFlow/README.md) - -[Readme example2](https://www.hiascend.com/zh/software/modelzoo/detail/C/093ed0219cb14f068af33784c62cf7ec) - -离线推理ReadMe写作可参考下面链接: - -[Readme example1](https://gitee.com/ascend/modelzoo/tree/master/contrib/ACL_TensorFlow/Research/cv/AdvancedEAST_ID0130_for_ACL/README.md) - - **四、自测试用例** - -提供模型的自测试用例和readme,提交PR需要门禁及模型测试用例通过,性能和精度检查通过 - -- 简介: - -1、不同于完整的训练过程和全量数据集的推理,自测试用例的目的是验证提交代码基本功能可用,执行时长控制在10min之内(推理或训练只需执行有限的图片或step); - -2、提交PR中训练用例入口`train_testcase.sh`, 在线推理用例入口`online_inference_testcase.sh`, 离线推理用例入口`offline_inference_testcase.sh`; - -3、提交PR后,会自动触发门禁流水,后台会根据用例入口shell,自动将代码分发到对应执行环境; - -4、Jenkins预置账号:登录账号请联系华为工程师/接口人获取,登录之后,可以查看到用例执行日志 - -5、如果提交失败,请查看日志,修复代码或其他问题后,在你当前的PR中,评论“compile”即可重新触发用例执行 - -- 关键要求: - -1、自测试用例命名严格按照上述简介2要求来书写,否则门禁会校验失败; - -2、用例应当包含功能、精度(Loss值)、性能检查,检查通过打印"Run testcase success!",失败则打印"Run testcase failed!"; - -3、执行环境已预装软件包和Python3.7.5环境,调用命令"python3"、"python3.7"、"python3.7.5"均可,安装第三方库依赖使用"pip3"、"pip3.7"均可; - -4、数据集和模型:小于500M的文件,建议使用`obsutil`命令下载(已预装),过大的文件,建议提交Issue,注明数据集和下载地址,会提前下载到执行环境上, - -已预置数据集&python第三方库: [Environments](https://gitee.com/ascend/modelzoo/blob/master/contrib/ENVIRONMENTS.md) - -5、环境和其他问题,请提交Issue跟踪; - -6、测试用例开发参考: -- [训练](https://gitee.com/ascend/modelzoo/tree/master/built-in/TensorFlow/Official/nlp/Transformer_for_TensorFlow) -- [离线推理](https://gitee.com/alexcheng88/modelzoo/tree/master/contrib/TensorFlow/Research/cv/efficientnet-b8/ATC_efficientnet-b8_tf_nkxiaolei) - - **五、PR提交** - -- 关键要求: - -1、请将modelzoo仓fork到个人分支,基于个人分支新增、修改和提交PR; - -2、PR标题:线上活动,请在标题注明[线上贡献];高校活动,请注明[xxx学校][高校贡献]; - -3、built-in用户根据网络状态必须配置modelzoo_level.txt文件,且文件内容包含三个关键字段:FuncStatus(OK-流程通过/ **NOK-流程失败,不允许模型代码提交主仓** );PerfStatus(OK-持平GPU/POK-0.5倍GPU/NOK-小于0.5倍GPU/PERFECT-1.2倍GPU);PrecisionStatus(OK-精度达标,POK-Loss拟合但精度未实施, **NOK-Loss不拟合,不允许模型代码提交主仓** );内容格式如下所示(注:“:”两侧无需空格,英文格式;): - -``` - FuncStatus:OK/NOK - PerfStatus:PERFECT/OK/POK/NOK - PrecisionStatus:OK/POK/NOK -``` -4、contrib用户根据网络状态必须配置modelzoo_level.txt文件,且文件内容包含关键字段:GPUStatus(OK-GPU复现/NOK-GPU未复现); NPUMigrationStatus(OK-自动迁移成功/POK-自动迁移失败, 手写规避成功/NOK-均失败); FuncStatus(OK-基础功能打通/NOK-基础功能失败,不允许模型代码提交到master); PrecisionStatus(OK-精度达标/POK-Loss拟合但精度未完全达标/NOK-精度不达标, 不允许模型代码提交到master); AutoTune(OK-性能持平或高于GPU/POK-性能有提升但低于GPU/NOK-性能无提升或者功能失败); PerfStatus(训练:PERFECT-性能1.2倍GPU/OK-性能持平GPU/POK-性能0.5倍GPU/NOK-性能小于0.5倍GPU;推理:OK-4*310单卡>GPU/NOK-其它); ModelConvert:OK/NOK(仅推理, OK-om转换成功/NOK-om转换失败); QuantStatus:OK/NOK(仅推理, OK-精度损失1%以内,性能有提升/POK-性能有提升但未达标/NOK-量化失败); - -样例:modelzoo_level.txt文件 - ------仅限训练----- - - -``` -GPUStatus:OK/NOK -NPUMigrationStatus:OK/POK/NOK -``` - - ------仅限推理----- - -``` -ModelConvert:OK/POK/NOK -QuantStatus:OK/POK/NOK -``` - ------通用部分----- - -``` -FuncStatus:OK/NOK -PrecisionStatus:OK/POK/NOK -AutoTune:OK/POK/NOK -PerfStatus:PERFECT/OK/POK/NOK -``` -5、网络名称命名规范:*_for_框架,注:*代表任意内容,如网络名称或网络名称+网络ID; - - **六、编程规范** - -- 规范标准 - -1、C++代码遵循google编程规范:Google C++ Coding Guidelines;单元测测试遵循规范: Googletest Primer。 - -2、Python代码遵循PEP8规范:Python PEP 8 Coding Style;单元测试遵循规范: pytest - -- 规范备注 - -1、优先使用string类型,避免使用char*; - -2、禁止使用printf,一律使用cout; - -3、内存管理尽量使用智能指针; - -4、不准在函数里调用exit; - -5、禁止使用IDE等工具自动生成代码; - -6、控制第三方库依赖,如果引入第三方依赖,则需要提供第三方依赖安装和使用指导书; - -7、一律使用英文注释,注释率30%--40%,鼓励自注释; - -8、函数头必须有注释,说明函数作用,入参、出参; - -9、统一错误码,通过错误码可以确认那个分支返回错误; - -10、禁止出现打印一堆无影响的错误级别的日志; + **介绍** + +Ascend ModelZoo,欢迎各位开发者 + + **贡献要求** + +开发者提交的模型包括源码、readme、参考模型license文件、测试用例和readme,并遵循以下标准 + +请贡献者在提交代码之前签署CLA协议,“个人签署”,[链接](https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZhc2NlbmQ=) + +如您完成签署,可在自己提交的PR评论区输入/check-cla进行核实校验 + + **一、源码** + +1、训练及在线推理请使用python代码实现,Ascend平台离线推理请使用C++或python代码,符合第四部分编码规范 + +2、参考[sample](https://gitee.com/ascend/modelzoo/tree/master/built-in/TensorFlow/Official/nlp/Transformer_for_TensorFlow) + +3、贡献者模型代码目录规则:"modelzoo/contrib/框架/Research/应用领域(nlp、cv、audio等)/网络名_IDxxx_for_TensorFlow"(以tf为例,社区管理团队会在贡献完成进行整合) + +4、从其他开源迁移的代码,请增加License声明 + + **二、License规则** + +* TensorFlow + + 迁移场景 + + 1、迁移TensorFlow模型中若源项目已包含License文件则必须拷贝引用,否则在模型顶层目录下添加TensorFlow Apache 2.0 License [TensorFlow License链接](https://github.com/tensorflow/tensorflow/blob/master/LICENSE) + + 2、迁移TensorFlow框架开发的模型,需要在模型目录下每个源文件附上源社区TensorFlow Apache 2.0 License头部声明,并在其下追加新增完整华为公司License声明 + + ``` + # Copyright 2017 The TensorFlow 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. + # ============================================================================ + # Copyright 2021 Huawei Technologies Co., Ltd + # + # 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. + ``` + 开发场景 + + 1、基于TensorFlow框架开发模型,需在模型项目顶层目录下添加TensorFlow Apache 2.0 License [TensorFlow License链接](https://github.com/tensorflow/tensorflow/blob/master/LICENSE) + + 2、基于TensorFlow框架开发模型,需要在模型目录下每个源文件附上源社区华为公司Apache 2.0 License头部声明 + ``` + # Copyright 2021 Huawei Technologies Co., Ltd + # + # 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. + ``` +* PyTorch + + 迁移场景 + + 1、迁移PyTorch模型中若源项目录已包含PyTorch License文件则必须拷贝引用,否则在模型顶层目录下添加PyTorch BSD-3 License [PyTorch License链接](https://github.com/pytorch/examples/blob/master/LICENSE) + + 2、迁移PyTorch第三方框架开发的模型,需要在模型目录下每个源文件附上源社区PyTorch BSD-3 License头部声明,并在其下追加新增一行华为公司License声明 + ``` + # BSD 3-Clause License + # + # Copyright (c) 2017 xxxx + # All rights reserved. + # Copyright 2021 Huawei Technologies Co., Ltd + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions are met: + # + # * Redistributions of source code must retain the above copyright notice, this + # list of conditions and the following disclaimer. + # + # * Redistributions in binary form must reproduce the above copyright notice, + # this list of conditions and the following disclaimer in the documentation + # and/or other materials provided with the distribution. + # + # * Neither the name of the copyright holder nor the names of its + # contributors may be used to endorse or promote products derived from + # this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + # ============================================================================ + ``` + + 开发场景 + + 1、基于PyTorch框架开发模型,需在模型项目下添加PyTorch BSD-3 License [PyTorch License链接](https://github.com/pytorch/examples/blob/master/LICENSE) + + 2、基于PyTorch框架开发模型,需要在模型目录下每个源文件附上源社区华为公司Apache 2.0 License头部声明 + ``` + # Copyright 2021 Huawei Technologies Co., Ltd + # + # Licensed under the BSD 3-Clause License (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # https://opensource.org/licenses/BSD-3-Clause + # + # 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. + ``` + +* MindSpore/ACL + + 1、迁移或开发场景下MindSpore/ACL模型顶层目录下需要包含华为公司 License [华为公司 License链接](https://gitee.com/mindspore/mindspore/blob/master/LICENSE) + + 2、迁移或开发场景下MindSpore/ACL模型,需要在模型目录下每个源文件中添加区华为公司Apache 2.0 License头部声明 + ``` + # Copyright 2021 Huawei Technologies Co., Ltd + # + # 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. + ``` + +> 关于License声明时间,应注意: 2021年新建的文件,应该是Copyright 2021 Huawei Technologies Co., Ltd 2020年创建年份,2020年修改年份,应该是Copyright 2020 Huawei Technologies Co., Ltd + + **三、readme** + +readme用于指导用户理解和部署样例,要包含如下内容: + +- 简介: + +1、模型的来源及原理; + +2、模型复现的步骤,含训练、eval、在线/离线推理等,入口请封装成`.sh`、`.py`; + +- 关键要求: + +1、模型的出处、对数据的要求、免责声明等,开源代码文件修改需要增加版权说明; + +2、模型转换得到的离线模型对输入数据的要求; + +3、环境变量设置,依赖的第三方软件包和库,以及安装方法; + +4、精度和性能达成要求:尽量达到原始模型水平; + +5、预训练checkpoint、结果checkpoint请提供归档OBS、网盘链接,如来自开源需明确来源地址 + +6、数据集说明 + +- [ ] 不允许直接提供数据集的下载链接,可使用词汇:用户自行准备好数据集,可选用“XXX”,“XXX”,“XXX” + + 例如:请用户自行准备好数据集,包含训练集和验证集两部分,可选用的数据集包括ImageNet2012,CIFAR10、Flower等,包含train和val两部分。 + +- [ ] 脚本中不允许提供链接下载数据集,如果开源脚本上存在对应的链接,请修改或者删除对应的脚本 + +训练ReadMe写作可参考下面两个链接: + +[Readme example1](https://gitee.com/ascend/modelzoo/blob/master/built-in/TensorFlow/Official/cv/image_classification/DenseNet121_ID0067_for_TensorFlow/README.md) + +[Readme example2](https://www.hiascend.com/zh/software/modelzoo/detail/C/093ed0219cb14f068af33784c62cf7ec) + +离线推理ReadMe写作可参考下面链接: + +[Readme example1](https://gitee.com/ascend/modelzoo/tree/master/contrib/ACL_TensorFlow/Research/cv/AdvancedEAST_ID0130_for_ACL/README.md) + + **四、自测试用例** + +提供模型的自测试用例和readme,提交PR需要门禁及模型测试用例通过,性能和精度检查通过 + +- 简介: + +1、不同于完整的训练过程和全量数据集的推理,自测试用例的目的是验证提交代码基本功能可用,执行时长控制在10min之内(推理或训练只需执行有限的图片或step); + +2、提交PR中训练用例入口`train_testcase.sh`, 在线推理用例入口`online_inference_testcase.sh`, 离线推理用例入口`offline_inference_testcase.sh`; + +3、提交PR后,会自动触发门禁流水,后台会根据用例入口shell,自动将代码分发到对应执行环境; + +4、Jenkins预置账号:登录账号请联系华为工程师/接口人获取,登录之后,可以查看到用例执行日志 + +5、如果提交失败,请查看日志,修复代码或其他问题后,在你当前的PR中,评论“compile”即可重新触发用例执行 + +- 关键要求: + +1、自测试用例命名严格按照上述简介2要求来书写,否则门禁会校验失败; + +2、用例应当包含功能、精度(Loss值)、性能检查,检查通过打印"Run testcase success!",失败则打印"Run testcase failed!"; + +3、执行环境已预装软件包和Python3.7.5环境,调用命令"python3"、"python3.7"、"python3.7.5"均可,安装第三方库依赖使用"pip3"、"pip3.7"均可; + +4、数据集和模型:小于500M的文件,建议使用`obsutil`命令下载(已预装),过大的文件,建议提交Issue,注明数据集和下载地址,会提前下载到执行环境上, + +已预置数据集&python第三方库: [Environments](https://gitee.com/ascend/modelzoo/blob/master/contrib/ENVIRONMENTS.md) + +5、环境和其他问题,请提交Issue跟踪; + +6、测试用例开发参考: +- [训练](https://gitee.com/ascend/modelzoo/tree/master/built-in/TensorFlow/Official/nlp/Transformer_for_TensorFlow) +- [离线推理](https://gitee.com/alexcheng88/modelzoo/tree/master/contrib/TensorFlow/Research/cv/efficientnet-b8/ATC_efficientnet-b8_tf_nkxiaolei) + + **五、PR提交** + +- 关键要求: + +1、请将modelzoo仓fork到个人分支,基于个人分支新增、修改和提交PR; + +2、PR标题:线上活动,请在标题注明[线上贡献];高校活动,请注明[xxx学校][高校贡献]; + +3、built-in用户根据网络状态必须配置modelzoo_level.txt文件,且文件内容包含三个关键字段:FuncStatus(OK-流程通过/ **NOK-流程失败,不允许模型代码提交主仓** );PerfStatus(OK-持平GPU/POK-0.5倍GPU/NOK-小于0.5倍GPU/PERFECT-1.2倍GPU);PrecisionStatus(OK-精度达标,POK-Loss拟合但精度未实施, **NOK-Loss不拟合,不允许模型代码提交主仓** );内容格式如下所示(注:“:”两侧无需空格,英文格式;): + +``` + FuncStatus:OK/NOK + PerfStatus:PERFECT/OK/POK/NOK + PrecisionStatus:OK/POK/NOK +``` +4、contrib用户根据网络状态必须配置modelzoo_level.txt文件,且文件内容包含关键字段:GPUStatus(OK-GPU复现/NOK-GPU未复现); NPUMigrationStatus(OK-自动迁移成功/POK-自动迁移失败, 手写规避成功/NOK-均失败); FuncStatus(OK-基础功能打通/NOK-基础功能失败,不允许模型代码提交到master); PrecisionStatus(OK-精度达标/POK-Loss拟合但精度未完全达标/NOK-精度不达标, 不允许模型代码提交到master); AutoTune(OK-性能持平或高于GPU/POK-性能有提升但低于GPU/NOK-性能无提升或者功能失败); PerfStatus(训练:PERFECT-性能1.2倍GPU/OK-性能持平GPU/POK-性能0.5倍GPU/NOK-性能小于0.5倍GPU;推理:OK-4*310单卡>GPU/NOK-其它); ModelConvert:OK/NOK(仅推理, OK-om转换成功/NOK-om转换失败); QuantStatus:OK/NOK(仅推理, OK-精度损失1%以内,性能有提升/POK-性能有提升但未达标/NOK-量化失败); + +样例:modelzoo_level.txt文件 + +-----仅限训练----- + + +``` +GPUStatus:OK/NOK +NPUMigrationStatus:OK/POK/NOK +``` + + +-----仅限推理----- + +``` +ModelConvert:OK/POK/NOK +QuantStatus:OK/POK/NOK +``` + +-----通用部分----- + +``` +FuncStatus:OK/NOK +PrecisionStatus:OK/POK/NOK +AutoTune:OK/POK/NOK +PerfStatus:PERFECT/OK/POK/NOK +``` +5、网络名称命名规范:*_for_框架,注:*代表任意内容,如网络名称或网络名称+网络ID; + + **六、编程规范** + +- 规范标准 + +1、C++代码遵循google编程规范:Google C++ Coding Guidelines;单元测测试遵循规范: Googletest Primer。 + +2、Python代码遵循PEP8规范:Python PEP 8 Coding Style;单元测试遵循规范: pytest + +- 规范备注 + +1、优先使用string类型,避免使用char*; + +2、禁止使用printf,一律使用cout; + +3、内存管理尽量使用智能指针; + +4、不准在函数里调用exit; + +5、禁止使用IDE等工具自动生成代码; + +6、控制第三方库依赖,如果引入第三方依赖,则需要提供第三方依赖安装和使用指导书; + +7、一律使用英文注释,注释率30%--40%,鼓励自注释; + +8、函数头必须有注释,说明函数作用,入参、出参; + +9、统一错误码,通过错误码可以确认那个分支返回错误; + +10、禁止出现打印一堆无影响的错误级别的日志; diff --git a/ACL_PyTorch/contrib/audio/FastPitch/README.md b/ACL_PyTorch/contrib/audio/FastPitch/README.md index 0365271515..89f0244c82 100644 --- a/ACL_PyTorch/contrib/audio/FastPitch/README.md +++ b/ACL_PyTorch/contrib/audio/FastPitch/README.md @@ -1,225 +1,225 @@ -# FastPitch模型端到端推理指导 - -## 1 模型概述 - -- **[论文地址](https://arxiv.org/abs/2006.06873)** -- **[代码地址](https://github.com/NVIDIA/DeepLearningExamples/tree/master/PyTorch/SpeechSynthesis/FastPitch)** - -### 1.1 论文地址 - -[FastPitch论文](https://arxiv.org/abs/2006.06873) -Fastpitch模型由双向 Transformer 主干(也称为 Transformer 编码器)、音调预测器和持续时间预测器组成。 在通过第一组 N 个 Transformer 块、编码后,信号用基音信息增强并离散上采样。 然后它通过另一组 N个 Transformer 块,目的是平滑上采样信号,并构建梅尔谱图。 - -### 1.2 开源代码地址 - -[FastPitch开源代码](https://github.com/NVIDIA/DeepLearningExamples/tree/master/PyTorch/SpeechSynthesis/FastPitch) - -## 2 环境说明 - -### 2.1 深度学习框架 - -``` -onnx==1.9.0 -torch==1.8.0 -``` - -### 2.2 python第三方库 - -``` -matplotlib -numpy -inflect -librosa==0.8.0 -scipy -Unidecode -praat-parselmouth==0.3.3 -tensorboardX==2.0 -dllogger -``` - -**说明:** - -> X86架构:pytorch和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3 模型转换 - -### pth转om模型 - -1.下载pth权重文件 -``` -wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/audio/FastPitch/pretrained_models.zip -``` -(waveglow为语音生成器,不在本模型范围内, 但为了确保代码能正常运行,需要下载) - -2.安装相关依赖 - -``` -cd FastPitch -pip install -r requirements.txt -``` - -3.激活相关环境 - -``` -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp -export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest -``` - -3.pth转onnx, onnx简化,onnx转om。(以batch_size=1为例) - -``` -# 导出onnx -python pth2onnx.py -i phrases/tui_val100.tsv -o ./output/audio_tui_val100 --log-file ./output/audio_tui_val100/nvlog_infer.json --fastpitch pretrained_models/fastpitch/nvidia_fastpitch_210824.pt --waveglow pretrained_models/waveglow/nvidia_waveglow256pyt_fp16.pt --wn-channels 256 --energy-conditioning --batch-size 1 -# 简化onnx -python -m onnxsim ./test/models/FastPitch_bs1.onnx ./test/models/FastPitch_bs1_sim.onnx -# 转出om -atc --framework=5 --model=./test/models/FastPitch_bs1_sim.onnx --output=./test/models/FastPitch_bs1 --input_format=ND --input_shape="input:1,200" --out_nodes='Transpose_2044:0' --log=debug --soc_version=Ascend310 -``` - -输出在/test/models中。 - - - -## 4 数据集预处理 - -### 4.1 数据集获取 - -(可选)本项目默认将数据集存放于/opt/npu/ - -``` -cd .. -wget https://ascend-pytorch-one-datasets.obs.cn-north-4.myhuaweicloud.com/train/zip/LJSpeech-1.1.zip -unzip LJSpeech-1.1.zip -mv /LJSpeech-1.1 /opt/npu/ -``` - -### 4.2 数据集预处理 - -生成输入数据,并准备输出标签和pth权重的输出数据。本模型的验证集大小为100,具体信息在phrases/tui_val100.tsv文件中。 - -- FastPitch模型的输入数据是由文字编码组成,输入长度不等,模型已经将其补零成固定长度200。将输入数据转换为bin文件方便后续推理,存入test/input_bin文件夹下,且生成生成数据集预处理后的bin文件以及相应的info文件。 -- 在语音合成推理过程中,输出为mel图谱,本模型的输出维度为batch_size×900×80。将其输出tensor存为pth文件存入test/mel_tgt_pth文件夹下。 -- 同时,为了后面推理结束后将推理精度与原模型pth权重精度进行对比,将输入数据在pth模型中前传得到的输出tensor村委pth文件存入test/mel_out_pth文件夹下。 - -以上步骤均执行下面指令完成: - -``` -python data_process.py -i phrases/tui_val100.tsv -o ./output/audio_tui_val100 --log-file ./output/audio_tui_val100/nvlog_infer.json --fastpitch pretrained_models/fastpitch/nvidia_fastpitch_210824.pt --waveglow pretrained_models/waveglow/nvidia_waveglow256pyt_fp16.pt -``` - -## 5 离线推理及精度对比 - -### 5.1 使用benchmark工具推理 - -获取benchmark工具 - -### 5.2 模型推理 - -- 使用benchmark工具进行推理(以batch_size=1为例): - -benchmark模型推理工具,其输入是om模型以及模型所需要的输入bin文件,其输出是模型根据相应输入产生的输出文件。推理得到的结果会在test/result中。 - -将推理得到的结果重新转换为tensor形式,与标签mel_tgt计算mel_loss1。同时,将原模型pth权重前传得到的输出mel_out与标签mel_tgt计算出mel_loss2。mel_loss1与mel_loss2精度对齐则推理正确。 - -``` -source /usr/local/Ascend/ascend-toolkit/set_env.sh -cd test -./benchmark.x86_64 -model_type=nlp -device_id=0 -batch_size=1 -om_path=./models/FastPitch_bs1.om -input_text_path=./input_bin_info.info -output_binary=True -useDvpp=False -``` - - - -### 5.3 精度对比 - -``` -cd .. -python infer_test.py -``` - -以下为测试出的batch_size=1和16的精度对比: - -``` -mel_loss: - om pth -bs1 11.246 11.265 -bs16 11.330 11.265 -``` - - - -## 6 性能对比 - -### 6.1 npu性能数据 - -1. 运行test/performance.sh脚本 - -``` -cd test -./benchmark.x86_64 -round=20 -device_id=0 -batch_size=1 -om_path=./models/FastPitch_bs1.om -``` - -测试出来的ave_throughputRate,将其乘以4即为吞吐率。 - -以下计算结果为batch_size=1的结果。 - -![img](file:///C:\Users\1\AppData\Local\Temp\ksohtml\wps9EEB.tmp.jpg) - - - - - - - -### 6.2 T4性能数据 - -提供以下测试代码作参考: - -```python -import time - -model=...(导入模型及加载pth权重) - -input = torch.ones(size=(1, 200), dtype=torch.int64, device=device) -total_time = 0 -lens = 20 -for _ in range(lens): - start = time.time() - output = model(input) - end = time.time() - total_time += end - start -print(f"batch_size=1, FPS:{1.0/(total_time/lens)}") - - -input = torch.ones(size=(16, 200), dtype=torch.int64, device=device) -total_time = 0 -lens = 20 -for _ in range(lens): - start = time.time() - output = model(input) - end = time.time() - total_time += end - start -print(f"batch_size=16, FPS:{16.0/(total_time/lens)}") -``` - - - - - -### 6.3 性能对比 - -| Model | Batch Size | A300 Throughput/Card | T4 Throughput/Card | A300/T4 | -| --------- | ---------- | -------------------- | ------------------ | ------- | -| FasfPitch | 1 | 54.1476 | 28.828 | 1.878 | -| FasfPitch | 4 | 51.728 | - | - | -| FasfPitch | 8 | 51.3684 | - | - | -| FasfPitch | 16 | 51.714 | 64.94 | 0.796 | -| FasfPitch | 32 | 52.0696 | - | - | - -由于模型并没有性能要求,bs1、bs4、bs8、bs16、bs32时npu的性能高于T4性能的0.5倍,性能达标。 - +# FastPitch模型端到端推理指导 + +## 1 模型概述 + +- **[论文地址](https://arxiv.org/abs/2006.06873)** +- **[代码地址](https://github.com/NVIDIA/DeepLearningExamples/tree/master/PyTorch/SpeechSynthesis/FastPitch)** + +### 1.1 论文地址 + +[FastPitch论文](https://arxiv.org/abs/2006.06873) +Fastpitch模型由双向 Transformer 主干(也称为 Transformer 编码器)、音调预测器和持续时间预测器组成。 在通过第一组 N 个 Transformer 块、编码后,信号用基音信息增强并离散上采样。 然后它通过另一组 N个 Transformer 块,目的是平滑上采样信号,并构建梅尔谱图。 + +### 1.2 开源代码地址 + +[FastPitch开源代码](https://github.com/NVIDIA/DeepLearningExamples/tree/master/PyTorch/SpeechSynthesis/FastPitch) + +## 2 环境说明 + +### 2.1 深度学习框架 + +``` +onnx==1.9.0 +torch==1.8.0 +``` + +### 2.2 python第三方库 + +``` +matplotlib +numpy +inflect +librosa==0.8.0 +scipy +Unidecode +praat-parselmouth==0.3.3 +tensorboardX==2.0 +dllogger +``` + +**说明:** + +> X86架构:pytorch和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3 模型转换 + +### pth转om模型 + +1.下载pth权重文件 +``` +wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/audio/FastPitch/pretrained_models.zip +``` +(waveglow为语音生成器,不在本模型范围内, 但为了确保代码能正常运行,需要下载) + +2.安装相关依赖 + +``` +cd FastPitch +pip install -r requirements.txt +``` + +3.激活相关环境 + +``` +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp +export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest +``` + +3.pth转onnx, onnx简化,onnx转om。(以batch_size=1为例) + +``` +# 导出onnx +python pth2onnx.py -i phrases/tui_val100.tsv -o ./output/audio_tui_val100 --log-file ./output/audio_tui_val100/nvlog_infer.json --fastpitch pretrained_models/fastpitch/nvidia_fastpitch_210824.pt --waveglow pretrained_models/waveglow/nvidia_waveglow256pyt_fp16.pt --wn-channels 256 --energy-conditioning --batch-size 1 +# 简化onnx +python -m onnxsim ./test/models/FastPitch_bs1.onnx ./test/models/FastPitch_bs1_sim.onnx +# 转出om +atc --framework=5 --model=./test/models/FastPitch_bs1_sim.onnx --output=./test/models/FastPitch_bs1 --input_format=ND --input_shape="input:1,200" --out_nodes='Transpose_2044:0' --log=debug --soc_version=Ascend310 +``` + +输出在/test/models中。 + + + +## 4 数据集预处理 + +### 4.1 数据集获取 + +(可选)本项目默认将数据集存放于/opt/npu/ + +``` +cd .. +wget https://ascend-pytorch-one-datasets.obs.cn-north-4.myhuaweicloud.com/train/zip/LJSpeech-1.1.zip +unzip LJSpeech-1.1.zip +mv /LJSpeech-1.1 /opt/npu/ +``` + +### 4.2 数据集预处理 + +生成输入数据,并准备输出标签和pth权重的输出数据。本模型的验证集大小为100,具体信息在phrases/tui_val100.tsv文件中。 + +- FastPitch模型的输入数据是由文字编码组成,输入长度不等,模型已经将其补零成固定长度200。将输入数据转换为bin文件方便后续推理,存入test/input_bin文件夹下,且生成生成数据集预处理后的bin文件以及相应的info文件。 +- 在语音合成推理过程中,输出为mel图谱,本模型的输出维度为batch_size×900×80。将其输出tensor存为pth文件存入test/mel_tgt_pth文件夹下。 +- 同时,为了后面推理结束后将推理精度与原模型pth权重精度进行对比,将输入数据在pth模型中前传得到的输出tensor村委pth文件存入test/mel_out_pth文件夹下。 + +以上步骤均执行下面指令完成: + +``` +python data_process.py -i phrases/tui_val100.tsv -o ./output/audio_tui_val100 --log-file ./output/audio_tui_val100/nvlog_infer.json --fastpitch pretrained_models/fastpitch/nvidia_fastpitch_210824.pt --waveglow pretrained_models/waveglow/nvidia_waveglow256pyt_fp16.pt +``` + +## 5 离线推理及精度对比 + +### 5.1 使用benchmark工具推理 + +获取benchmark工具 + +### 5.2 模型推理 + +- 使用benchmark工具进行推理(以batch_size=1为例): + +benchmark模型推理工具,其输入是om模型以及模型所需要的输入bin文件,其输出是模型根据相应输入产生的输出文件。推理得到的结果会在test/result中。 + +将推理得到的结果重新转换为tensor形式,与标签mel_tgt计算mel_loss1。同时,将原模型pth权重前传得到的输出mel_out与标签mel_tgt计算出mel_loss2。mel_loss1与mel_loss2精度对齐则推理正确。 + +``` +source /usr/local/Ascend/ascend-toolkit/set_env.sh +cd test +./benchmark.x86_64 -model_type=nlp -device_id=0 -batch_size=1 -om_path=./models/FastPitch_bs1.om -input_text_path=./input_bin_info.info -output_binary=True -useDvpp=False +``` + + + +### 5.3 精度对比 + +``` +cd .. +python infer_test.py +``` + +以下为测试出的batch_size=1和16的精度对比: + +``` +mel_loss: + om pth +bs1 11.246 11.265 +bs16 11.330 11.265 +``` + + + +## 6 性能对比 + +### 6.1 npu性能数据 + +1. 运行test/performance.sh脚本 + +``` +cd test +./benchmark.x86_64 -round=20 -device_id=0 -batch_size=1 -om_path=./models/FastPitch_bs1.om +``` + +测试出来的ave_throughputRate,将其乘以4即为吞吐率。 + +以下计算结果为batch_size=1的结果。 + +![img](file:///C:\Users\1\AppData\Local\Temp\ksohtml\wps9EEB.tmp.jpg) + + + + + + + +### 6.2 T4性能数据 + +提供以下测试代码作参考: + +```python +import time + +model=...(导入模型及加载pth权重) + +input = torch.ones(size=(1, 200), dtype=torch.int64, device=device) +total_time = 0 +lens = 20 +for _ in range(lens): + start = time.time() + output = model(input) + end = time.time() + total_time += end - start +print(f"batch_size=1, FPS:{1.0/(total_time/lens)}") + + +input = torch.ones(size=(16, 200), dtype=torch.int64, device=device) +total_time = 0 +lens = 20 +for _ in range(lens): + start = time.time() + output = model(input) + end = time.time() + total_time += end - start +print(f"batch_size=16, FPS:{16.0/(total_time/lens)}") +``` + + + + + +### 6.3 性能对比 + +| Model | Batch Size | A300 Throughput/Card | T4 Throughput/Card | A300/T4 | +| --------- | ---------- | -------------------- | ------------------ | ------- | +| FasfPitch | 1 | 54.1476 | 28.828 | 1.878 | +| FasfPitch | 4 | 51.728 | - | - | +| FasfPitch | 8 | 51.3684 | - | - | +| FasfPitch | 16 | 51.714 | 64.94 | 0.796 | +| FasfPitch | 32 | 52.0696 | - | - | + +由于模型并没有性能要求,bs1、bs4、bs8、bs16、bs32时npu的性能高于T4性能的0.5倍,性能达标。 + diff --git a/ACL_PyTorch/contrib/audio/FastPitch/fastpitch/loss_function.py b/ACL_PyTorch/contrib/audio/FastPitch/fastpitch/loss_function.py index 9baf4a6c31..0fe133abd4 100644 --- a/ACL_PyTorch/contrib/audio/FastPitch/fastpitch/loss_function.py +++ b/ACL_PyTorch/contrib/audio/FastPitch/fastpitch/loss_function.py @@ -1,108 +1,108 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch -import torch.nn.functional as F -from torch import nn - -from common.utils import mask_from_lens -from fastpitch.attn_loss_function import AttentionCTCLoss - - -class FastPitchLoss(nn.Module): - def __init__(self, dur_predictor_loss_scale=1.0, - pitch_predictor_loss_scale=1.0, attn_loss_scale=1.0, - energy_predictor_loss_scale=0.1): - super(FastPitchLoss, self).__init__() - self.dur_predictor_loss_scale = dur_predictor_loss_scale - self.pitch_predictor_loss_scale = pitch_predictor_loss_scale - self.energy_predictor_loss_scale = energy_predictor_loss_scale - self.attn_loss_scale = attn_loss_scale - self.attn_ctc_loss = AttentionCTCLoss() - - def forward(self, model_out, targets, is_training=True, meta_agg='mean'): - (mel_out, dec_mask, dur_pred, log_dur_pred, pitch_pred, pitch_tgt, - energy_pred, energy_tgt, attn_soft, attn_hard, attn_dur, - attn_logprob) = model_out - - (mel_tgt, in_lens, out_lens) = targets - - dur_tgt = attn_dur - dur_lens = in_lens - - mel_tgt.requires_grad = False - # (B,H,T) => (B,T,H) - mel_tgt = mel_tgt.transpose(1, 2) - - dur_mask = mask_from_lens(dur_lens, max_len=dur_tgt.size(1)) - dur_mask_sum = dur_mask.sum() - - log_dur_tgt = torch.log(dur_tgt.float() + 1) - loss_fn = F.mse_loss - dur_pred_loss = loss_fn(log_dur_pred, log_dur_tgt, reduction='none') - dur_pred_loss = (dur_pred_loss * dur_mask).sum() / dur_mask_sum - - ldiff = mel_tgt.size(1) - mel_out.size(1) - mel_out = F.pad(mel_out, (0, 0, 0, ldiff, 0, 0), value=0.0) - - mel_mask = mel_tgt.ne(0).float() - mel_mask_sum = mel_mask.sum() - - loss_fn = F.mse_loss - mel_loss = loss_fn(mel_out, mel_tgt, reduction='none') - mel_loss = (mel_loss * mel_mask).sum() / mel_mask_sum - - ldiff = pitch_tgt.size(2) - pitch_pred.size(2) - pitch_pred = F.pad(pitch_pred, (0, ldiff, 0, 0, 0, 0), value=0.0) - pitch_loss = F.mse_loss(pitch_tgt, pitch_pred, reduction='none') - pitch_loss = (pitch_loss * dur_mask.unsqueeze(1)).sum() / dur_mask_sum - - if energy_pred is not None: - energy_pred = F.pad(energy_pred, (0, ldiff, 0, 0), value=0.0) - energy_loss = F.mse_loss(energy_tgt, energy_pred, reduction='none') - energy_loss = (energy_loss * dur_mask).sum() / dur_mask_sum - else: - energy_loss = 0 - - # Attention loss - attn_loss = self.attn_ctc_loss(attn_logprob, in_lens, out_lens) - - loss = (mel_loss - + dur_pred_loss * self.dur_predictor_loss_scale - + pitch_loss * self.pitch_predictor_loss_scale - + energy_loss * self.energy_predictor_loss_scale - + attn_loss * self.attn_loss_scale) - - meta = { - 'loss': loss.clone().detach(), - 'mel_loss': mel_loss.clone().detach(), - 'duration_predictor_loss': dur_pred_loss.clone().detach(), - 'pitch_loss': pitch_loss.clone().detach(), - 'energy_loss': energy_loss.clone().detach(), - 'attn_loss': attn_loss.clone().detach(), - 'dur_mask_sum': dur_mask_sum.clone().detach(), - 'mel_mask_sum': mel_mask_sum.clone().detach(), - 'dur_error': (torch.abs(dur_pred - dur_tgt).sum() - / dur_mask_sum).detach(), - } - - if energy_pred is not None: - meta['energy_loss'] = energy_loss.clone().detach() - - assert meta_agg in ('sum', 'mean') - if meta_agg == 'sum': - bsz = mel_out.size(0) - meta = {k: v * bsz for k, v in meta.items()} - return loss, meta +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch +import torch.nn.functional as F +from torch import nn + +from common.utils import mask_from_lens +from fastpitch.attn_loss_function import AttentionCTCLoss + + +class FastPitchLoss(nn.Module): + def __init__(self, dur_predictor_loss_scale=1.0, + pitch_predictor_loss_scale=1.0, attn_loss_scale=1.0, + energy_predictor_loss_scale=0.1): + super(FastPitchLoss, self).__init__() + self.dur_predictor_loss_scale = dur_predictor_loss_scale + self.pitch_predictor_loss_scale = pitch_predictor_loss_scale + self.energy_predictor_loss_scale = energy_predictor_loss_scale + self.attn_loss_scale = attn_loss_scale + self.attn_ctc_loss = AttentionCTCLoss() + + def forward(self, model_out, targets, is_training=True, meta_agg='mean'): + (mel_out, dec_mask, dur_pred, log_dur_pred, pitch_pred, pitch_tgt, + energy_pred, energy_tgt, attn_soft, attn_hard, attn_dur, + attn_logprob) = model_out + + (mel_tgt, in_lens, out_lens) = targets + + dur_tgt = attn_dur + dur_lens = in_lens + + mel_tgt.requires_grad = False + # (B,H,T) => (B,T,H) + mel_tgt = mel_tgt.transpose(1, 2) + + dur_mask = mask_from_lens(dur_lens, max_len=dur_tgt.size(1)) + dur_mask_sum = dur_mask.sum() + + log_dur_tgt = torch.log(dur_tgt.float() + 1) + loss_fn = F.mse_loss + dur_pred_loss = loss_fn(log_dur_pred, log_dur_tgt, reduction='none') + dur_pred_loss = (dur_pred_loss * dur_mask).sum() / dur_mask_sum + + ldiff = mel_tgt.size(1) - mel_out.size(1) + mel_out = F.pad(mel_out, (0, 0, 0, ldiff, 0, 0), value=0.0) + + mel_mask = mel_tgt.ne(0).float() + mel_mask_sum = mel_mask.sum() + + loss_fn = F.mse_loss + mel_loss = loss_fn(mel_out, mel_tgt, reduction='none') + mel_loss = (mel_loss * mel_mask).sum() / mel_mask_sum + + ldiff = pitch_tgt.size(2) - pitch_pred.size(2) + pitch_pred = F.pad(pitch_pred, (0, ldiff, 0, 0, 0, 0), value=0.0) + pitch_loss = F.mse_loss(pitch_tgt, pitch_pred, reduction='none') + pitch_loss = (pitch_loss * dur_mask.unsqueeze(1)).sum() / dur_mask_sum + + if energy_pred is not None: + energy_pred = F.pad(energy_pred, (0, ldiff, 0, 0), value=0.0) + energy_loss = F.mse_loss(energy_tgt, energy_pred, reduction='none') + energy_loss = (energy_loss * dur_mask).sum() / dur_mask_sum + else: + energy_loss = 0 + + # Attention loss + attn_loss = self.attn_ctc_loss(attn_logprob, in_lens, out_lens) + + loss = (mel_loss + + dur_pred_loss * self.dur_predictor_loss_scale + + pitch_loss * self.pitch_predictor_loss_scale + + energy_loss * self.energy_predictor_loss_scale + + attn_loss * self.attn_loss_scale) + + meta = { + 'loss': loss.clone().detach(), + 'mel_loss': mel_loss.clone().detach(), + 'duration_predictor_loss': dur_pred_loss.clone().detach(), + 'pitch_loss': pitch_loss.clone().detach(), + 'energy_loss': energy_loss.clone().detach(), + 'attn_loss': attn_loss.clone().detach(), + 'dur_mask_sum': dur_mask_sum.clone().detach(), + 'mel_mask_sum': mel_mask_sum.clone().detach(), + 'dur_error': (torch.abs(dur_pred - dur_tgt).sum() + / dur_mask_sum).detach(), + } + + if energy_pred is not None: + meta['energy_loss'] = energy_loss.clone().detach() + + assert meta_agg in ('sum', 'mean') + if meta_agg == 'sum': + bsz = mel_out.size(0) + meta = {k: v * bsz for k, v in meta.items()} + return loss, meta diff --git a/ACL_PyTorch/contrib/audio/FastPitch/infer.py b/ACL_PyTorch/contrib/audio/FastPitch/infer.py index c44a66dc16..8281758ff3 100644 --- a/ACL_PyTorch/contrib/audio/FastPitch/infer.py +++ b/ACL_PyTorch/contrib/audio/FastPitch/infer.py @@ -1,90 +1,90 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 numpy as np -import torch -import torch.nn.functional as F -import os -import struct - - -def bin2tensor(binName): - size = os.path.getsize(binName) - binfile = open(binName, 'rb') - Len = int(size / 4) - res=[] - for i in range(Len): - data = binfile.read(4) - num = struct.unpack('f', data) - res.append(num[0]) - - binfile.close() - dim_res = np.array(res) - dim_res = torch.from_numpy(dim_res) - - return dim_res - - -def mel_loss(mel_out, mel_tgt): - """ - mel_out: torch.tensor, shape(batchsize, 80, 900) - mel_tgt: torch.tensor, shape(batchsize, 80, 900) - """ - mel_tgt = mel_tgt.transpose(1, 2) - mel_out = mel_out.transpose(1, 2) - - mel_mask = mel_tgt.ne(0).float() - mel_mask_sum = mel_mask.sum() - - loss_fn = F.mse_loss - mel_loss = loss_fn(mel_out, mel_tgt, reduction='none') - mel_loss = (mel_loss * mel_mask).sum() / mel_mask_sum - - return mel_loss - - -def test_om(): - tgt_path = "./test/mel_tgt_pth/" - out_path = './test/result/dumpOutput_device0/' - data_len = 100 - mel_loss_total = 0 - for i in range(data_len): - mel_out = bin2tensor(os.path.join(out_path, f"data{i}.bin")).reshape(1, 80, 900) - mel_tgt = torch.load(os.path.join(tgt_path, f"mel_tgt{i}.pth")) - mel_loss_ = mel_loss(mel_out, mel_tgt) - mel_loss_total += mel_loss_ - mel_loss_average = mel_loss_total / data_len - print("mel_loss_average", mel_loss_average.item()) - -def test_pth(): - out_path = './test/mel_out_pth/' - tgt_path = './test/mel_tgt_pth/' - data_len = 100 - mel_loss_total = 0 - for i in range(data_len): - mel_out = torch.load(os.path.join(out_path, f"mel_out{i}.pth")) - mel_tgt = torch.load(os.path.join(tgt_path, f"mel_tgt{i}.pth")) - mel_loss_ = mel_loss(mel_out, mel_tgt) - mel_loss_total += mel_loss_ - mel_loss_average = mel_loss_total / data_len - print("mel_loss_average", mel_loss_average.item()) - - - -if __name__ == "__main__": - print("==================om==================") - test_om() - print("==================pth==================") +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 numpy as np +import torch +import torch.nn.functional as F +import os +import struct + + +def bin2tensor(binName): + size = os.path.getsize(binName) + binfile = open(binName, 'rb') + Len = int(size / 4) + res=[] + for i in range(Len): + data = binfile.read(4) + num = struct.unpack('f', data) + res.append(num[0]) + + binfile.close() + dim_res = np.array(res) + dim_res = torch.from_numpy(dim_res) + + return dim_res + + +def mel_loss(mel_out, mel_tgt): + """ + mel_out: torch.tensor, shape(batchsize, 80, 900) + mel_tgt: torch.tensor, shape(batchsize, 80, 900) + """ + mel_tgt = mel_tgt.transpose(1, 2) + mel_out = mel_out.transpose(1, 2) + + mel_mask = mel_tgt.ne(0).float() + mel_mask_sum = mel_mask.sum() + + loss_fn = F.mse_loss + mel_loss = loss_fn(mel_out, mel_tgt, reduction='none') + mel_loss = (mel_loss * mel_mask).sum() / mel_mask_sum + + return mel_loss + + +def test_om(): + tgt_path = "./test/mel_tgt_pth/" + out_path = './test/result/dumpOutput_device0/' + data_len = 100 + mel_loss_total = 0 + for i in range(data_len): + mel_out = bin2tensor(os.path.join(out_path, f"data{i}.bin")).reshape(1, 80, 900) + mel_tgt = torch.load(os.path.join(tgt_path, f"mel_tgt{i}.pth")) + mel_loss_ = mel_loss(mel_out, mel_tgt) + mel_loss_total += mel_loss_ + mel_loss_average = mel_loss_total / data_len + print("mel_loss_average", mel_loss_average.item()) + +def test_pth(): + out_path = './test/mel_out_pth/' + tgt_path = './test/mel_tgt_pth/' + data_len = 100 + mel_loss_total = 0 + for i in range(data_len): + mel_out = torch.load(os.path.join(out_path, f"mel_out{i}.pth")) + mel_tgt = torch.load(os.path.join(tgt_path, f"mel_tgt{i}.pth")) + mel_loss_ = mel_loss(mel_out, mel_tgt) + mel_loss_total += mel_loss_ + mel_loss_average = mel_loss_total / data_len + print("mel_loss_average", mel_loss_average.item()) + + + +if __name__ == "__main__": + print("==================om==================") + test_om() + print("==================pth==================") test_pth() \ No newline at end of file diff --git a/ACL_PyTorch/contrib/audio/FastPitch/infer_test.py b/ACL_PyTorch/contrib/audio/FastPitch/infer_test.py index c44a66dc16..8281758ff3 100644 --- a/ACL_PyTorch/contrib/audio/FastPitch/infer_test.py +++ b/ACL_PyTorch/contrib/audio/FastPitch/infer_test.py @@ -1,90 +1,90 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 numpy as np -import torch -import torch.nn.functional as F -import os -import struct - - -def bin2tensor(binName): - size = os.path.getsize(binName) - binfile = open(binName, 'rb') - Len = int(size / 4) - res=[] - for i in range(Len): - data = binfile.read(4) - num = struct.unpack('f', data) - res.append(num[0]) - - binfile.close() - dim_res = np.array(res) - dim_res = torch.from_numpy(dim_res) - - return dim_res - - -def mel_loss(mel_out, mel_tgt): - """ - mel_out: torch.tensor, shape(batchsize, 80, 900) - mel_tgt: torch.tensor, shape(batchsize, 80, 900) - """ - mel_tgt = mel_tgt.transpose(1, 2) - mel_out = mel_out.transpose(1, 2) - - mel_mask = mel_tgt.ne(0).float() - mel_mask_sum = mel_mask.sum() - - loss_fn = F.mse_loss - mel_loss = loss_fn(mel_out, mel_tgt, reduction='none') - mel_loss = (mel_loss * mel_mask).sum() / mel_mask_sum - - return mel_loss - - -def test_om(): - tgt_path = "./test/mel_tgt_pth/" - out_path = './test/result/dumpOutput_device0/' - data_len = 100 - mel_loss_total = 0 - for i in range(data_len): - mel_out = bin2tensor(os.path.join(out_path, f"data{i}.bin")).reshape(1, 80, 900) - mel_tgt = torch.load(os.path.join(tgt_path, f"mel_tgt{i}.pth")) - mel_loss_ = mel_loss(mel_out, mel_tgt) - mel_loss_total += mel_loss_ - mel_loss_average = mel_loss_total / data_len - print("mel_loss_average", mel_loss_average.item()) - -def test_pth(): - out_path = './test/mel_out_pth/' - tgt_path = './test/mel_tgt_pth/' - data_len = 100 - mel_loss_total = 0 - for i in range(data_len): - mel_out = torch.load(os.path.join(out_path, f"mel_out{i}.pth")) - mel_tgt = torch.load(os.path.join(tgt_path, f"mel_tgt{i}.pth")) - mel_loss_ = mel_loss(mel_out, mel_tgt) - mel_loss_total += mel_loss_ - mel_loss_average = mel_loss_total / data_len - print("mel_loss_average", mel_loss_average.item()) - - - -if __name__ == "__main__": - print("==================om==================") - test_om() - print("==================pth==================") +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 numpy as np +import torch +import torch.nn.functional as F +import os +import struct + + +def bin2tensor(binName): + size = os.path.getsize(binName) + binfile = open(binName, 'rb') + Len = int(size / 4) + res=[] + for i in range(Len): + data = binfile.read(4) + num = struct.unpack('f', data) + res.append(num[0]) + + binfile.close() + dim_res = np.array(res) + dim_res = torch.from_numpy(dim_res) + + return dim_res + + +def mel_loss(mel_out, mel_tgt): + """ + mel_out: torch.tensor, shape(batchsize, 80, 900) + mel_tgt: torch.tensor, shape(batchsize, 80, 900) + """ + mel_tgt = mel_tgt.transpose(1, 2) + mel_out = mel_out.transpose(1, 2) + + mel_mask = mel_tgt.ne(0).float() + mel_mask_sum = mel_mask.sum() + + loss_fn = F.mse_loss + mel_loss = loss_fn(mel_out, mel_tgt, reduction='none') + mel_loss = (mel_loss * mel_mask).sum() / mel_mask_sum + + return mel_loss + + +def test_om(): + tgt_path = "./test/mel_tgt_pth/" + out_path = './test/result/dumpOutput_device0/' + data_len = 100 + mel_loss_total = 0 + for i in range(data_len): + mel_out = bin2tensor(os.path.join(out_path, f"data{i}.bin")).reshape(1, 80, 900) + mel_tgt = torch.load(os.path.join(tgt_path, f"mel_tgt{i}.pth")) + mel_loss_ = mel_loss(mel_out, mel_tgt) + mel_loss_total += mel_loss_ + mel_loss_average = mel_loss_total / data_len + print("mel_loss_average", mel_loss_average.item()) + +def test_pth(): + out_path = './test/mel_out_pth/' + tgt_path = './test/mel_tgt_pth/' + data_len = 100 + mel_loss_total = 0 + for i in range(data_len): + mel_out = torch.load(os.path.join(out_path, f"mel_out{i}.pth")) + mel_tgt = torch.load(os.path.join(tgt_path, f"mel_tgt{i}.pth")) + mel_loss_ = mel_loss(mel_out, mel_tgt) + mel_loss_total += mel_loss_ + mel_loss_average = mel_loss_total / data_len + print("mel_loss_average", mel_loss_average.item()) + + + +if __name__ == "__main__": + print("==================om==================") + test_om() + print("==================pth==================") test_pth() \ No newline at end of file diff --git a/ACL_PyTorch/contrib/audio/rawnet2/README.md b/ACL_PyTorch/contrib/audio/rawnet2/README.md index 4ead1dd821..a0b55e2b85 100644 --- a/ACL_PyTorch/contrib/audio/rawnet2/README.md +++ b/ACL_PyTorch/contrib/audio/rawnet2/README.md @@ -1,50 +1,50 @@ -### 1.环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 - -``` -pip3 install -r requirements.txt -``` - -2.获取,开源模型代码 - -``` -git clone https://github.com/Jungjee/RawNet.git -cd RawNet -patch -p1 < ../rawnet2.patch -cd .. -``` - -3.获取权重文件 - -通过2获得代码仓后,权重文件位置:RawNet\python\RawNet2\Pre-trained_model\rawnet2_best_weights.pt,将其放到当前目录 - -4.获取数据集 [VoxCeleb1](https://www.robots.ox.ac.uk/~vgg/data/voxceleb/vox1.html) ,下载Audio files测试集,重命名VoxCeleb1,确保VoxCeleb1下全部为id1xxxx文件夹,放到/root/datasets目录,注:该路径为绝对路径 - -5.获取 [msame工具](https://gitee.com/ascend/tools/tree/master/msame) 和 [benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) - -将msame和benchmark.x86_64放到与test文件夹同级目录下。 - -### 2.离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 - -备注: - -1.需要对onnx模型进行onnxsim优化,否则无法达到精度要求,pth2om.sh脚本首先将pth文件转换为onnx模型,然后分别对bs1和bs16进行onnxsim优化,最后分别转化为om模型 - -2.eval_acc_perf.sh脚本逐步完成数据前处理bin文件输出、bs1和bs16模型推理、bs1和bs16精度测试,以及bs1和bs16benchmark的性能测试 - -``` -bash test/pth2om.sh - -bash test/eval_acc_perf.sh --datasets_path=/root/datasets/VoxCeleb1/ -``` - -评测结果: - -| 模型 | 官网pth精度 | 310精度 | 基准性能 | 310性能 | -| --------------------- | ----------------------------------------------- | --------- | -------- | ------- | -| Baseline-RawNet2 bs1 | [EER 2.49%](https://github.com/Jungjee/RawNet/) | EER 2.50% | 285.7fps | 72.8fps | -| Baseline-RawNet2 bs16 | [EER 2.49%](https://github.com/Jungjee/RawNet/) | EER 2.50% | 489.3fps | 77.6fps | - +### 1.环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 + +``` +pip3 install -r requirements.txt +``` + +2.获取,开源模型代码 + +``` +git clone https://github.com/Jungjee/RawNet.git +cd RawNet +patch -p1 < ../rawnet2.patch +cd .. +``` + +3.获取权重文件 + +通过2获得代码仓后,权重文件位置:RawNet\python\RawNet2\Pre-trained_model\rawnet2_best_weights.pt,将其放到当前目录 + +4.获取数据集 [VoxCeleb1](https://www.robots.ox.ac.uk/~vgg/data/voxceleb/vox1.html) ,下载Audio files测试集,重命名VoxCeleb1,确保VoxCeleb1下全部为id1xxxx文件夹,放到/root/datasets目录,注:该路径为绝对路径 + +5.获取 [msame工具](https://gitee.com/ascend/tools/tree/master/msame) 和 [benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) + +将msame和benchmark.x86_64放到与test文件夹同级目录下。 + +### 2.离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 + +备注: + +1.需要对onnx模型进行onnxsim优化,否则无法达到精度要求,pth2om.sh脚本首先将pth文件转换为onnx模型,然后分别对bs1和bs16进行onnxsim优化,最后分别转化为om模型 + +2.eval_acc_perf.sh脚本逐步完成数据前处理bin文件输出、bs1和bs16模型推理、bs1和bs16精度测试,以及bs1和bs16benchmark的性能测试 + +``` +bash test/pth2om.sh + +bash test/eval_acc_perf.sh --datasets_path=/root/datasets/VoxCeleb1/ +``` + +评测结果: + +| 模型 | 官网pth精度 | 310精度 | 基准性能 | 310性能 | +| --------------------- | ----------------------------------------------- | --------- | -------- | ------- | +| Baseline-RawNet2 bs1 | [EER 2.49%](https://github.com/Jungjee/RawNet/) | EER 2.50% | 285.7fps | 72.8fps | +| Baseline-RawNet2 bs16 | [EER 2.49%](https://github.com/Jungjee/RawNet/) | EER 2.50% | 489.3fps | 77.6fps | + diff --git a/ACL_PyTorch/contrib/audio/rawnet2/RawNet2_postprocess.py b/ACL_PyTorch/contrib/audio/rawnet2/RawNet2_postprocess.py index a0263c606a..a6a9b03a3c 100644 --- a/ACL_PyTorch/contrib/audio/rawnet2/RawNet2_postprocess.py +++ b/ACL_PyTorch/contrib/audio/rawnet2/RawNet2_postprocess.py @@ -1,121 +1,121 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import numpy as np -from sklearn.metrics import roc_curve -from scipy.optimize import brentq -from scipy.interpolate import interp1d -from tqdm import tqdm -import argparse - -sys.path.append('RawNet/python/RawNet2/') -from utils import cos_sim - -def get_l_embeddings(list_embeddings,bs,path="def"): - temp = "" - l_embeddings = [] - index = 0 - l_utt = [] - l_code = [] - with tqdm(total=len(list_embeddings), ncols=70) as pbar: - if bs==1: - files = sorted(list_embeddings) - else: - files = list_embeddings.keys() - for f in files: - if bs==1: - t = np.loadtxt(path + "/" + f) - t = t.astype(np.float32) - else: - t = list_embeddings[f] - index += 1 - key = f.replace("$", "/", 2).split("$")[0] - if (temp == ""): - temp = key - l_utt.append(key) - if (key == temp): - l_code.append(t) - else: - l_embeddings.append(np.mean(l_code, axis=0)) - temp = key - l_utt.append(key) - l_code = [] - l_code.append(t) - if (index == len(files)): - l_embeddings.append(np.mean(l_code, axis=0)) - pbar.update(1) - if not len(l_utt) == len(l_embeddings): - print(len(l_utt), len(l_embeddings)) - exit() - d_embeddings = {} - for k, v in zip(l_utt, l_embeddings): - d_embeddings[k] = v - return d_embeddings - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument('--input', help='bin path', default="", required=True) - parser.add_argument('--batch_size', help='batch size', required=True) - parser.add_argument('--output', help='result path', default="result/") - args = parser.parse_args() - batch_size = int(args.batch_size) - base = args.input - save_dir = args.output - d_embeddings = {} - if batch_size == 1: - for path, dirs, files in os.walk(base): - d_embeddings = get_l_embeddings(files,batch_size,path); - else: - with open('bs16_key.txt', 'r') as f: - l_val = f.readlines() - bs16_out = [] - for path, dirs, files in os.walk(base): - files = sorted(files, key=lambda x: [int(x.split('_')[0])]) - for f in files: - t = np.loadtxt(path + "/" + f) - for i in t: - i.reshape(1024, ) - bs16_out.append(i) - bs16_out_embeddings = {} - if not len(l_val) == len(bs16_out): - print(len(l_val), len(bs16_out)) - exit() - for k, v in zip(l_val, bs16_out): - bs16_out_embeddings[k] = v - d_embeddings = get_l_embeddings(bs16_out_embeddings,batch_size); - - with open('RawNet/trials/vox_original.txt', 'r') as f: - l_val_trial = f.readlines() - y_score = [] - y = [] - f_res = open(save_dir + 'result_detail_bs{}.txt'.format(batch_size), 'w') - for line in l_val_trial: - trg, utt_a, utt_b = line.strip().split(' ') - y.append(int(trg)) - y_score.append(cos_sim(d_embeddings[utt_a], d_embeddings[utt_b])) - f_res.write('{score} {target}\n'.format(score=y_score[-1], target=y[-1])) - f_res.close() - fpr, tpr, _ = roc_curve(y, y_score, pos_label=1) - eer = brentq(lambda x: 1. - x - interp1d(fpr, tpr)(x), 0., 1.) - f_eer_301 = open(save_dir + 'result_eer_{}.txt'.format(batch_size), 'w') - f_eer_301.write('bs{dir} evaluation EER: {eer}\n'.format(dir=batch_size, eer=eer)) - f_eer_301.close() - print('bs{dir} evaluation EER: {eer}\n'.format(dir=batch_size, eer=eer)) - - -if __name__ == '__main__': - main() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import numpy as np +from sklearn.metrics import roc_curve +from scipy.optimize import brentq +from scipy.interpolate import interp1d +from tqdm import tqdm +import argparse + +sys.path.append('RawNet/python/RawNet2/') +from utils import cos_sim + +def get_l_embeddings(list_embeddings,bs,path="def"): + temp = "" + l_embeddings = [] + index = 0 + l_utt = [] + l_code = [] + with tqdm(total=len(list_embeddings), ncols=70) as pbar: + if bs==1: + files = sorted(list_embeddings) + else: + files = list_embeddings.keys() + for f in files: + if bs==1: + t = np.loadtxt(path + "/" + f) + t = t.astype(np.float32) + else: + t = list_embeddings[f] + index += 1 + key = f.replace("$", "/", 2).split("$")[0] + if (temp == ""): + temp = key + l_utt.append(key) + if (key == temp): + l_code.append(t) + else: + l_embeddings.append(np.mean(l_code, axis=0)) + temp = key + l_utt.append(key) + l_code = [] + l_code.append(t) + if (index == len(files)): + l_embeddings.append(np.mean(l_code, axis=0)) + pbar.update(1) + if not len(l_utt) == len(l_embeddings): + print(len(l_utt), len(l_embeddings)) + exit() + d_embeddings = {} + for k, v in zip(l_utt, l_embeddings): + d_embeddings[k] = v + return d_embeddings + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--input', help='bin path', default="", required=True) + parser.add_argument('--batch_size', help='batch size', required=True) + parser.add_argument('--output', help='result path', default="result/") + args = parser.parse_args() + batch_size = int(args.batch_size) + base = args.input + save_dir = args.output + d_embeddings = {} + if batch_size == 1: + for path, dirs, files in os.walk(base): + d_embeddings = get_l_embeddings(files,batch_size,path); + else: + with open('bs16_key.txt', 'r') as f: + l_val = f.readlines() + bs16_out = [] + for path, dirs, files in os.walk(base): + files = sorted(files, key=lambda x: [int(x.split('_')[0])]) + for f in files: + t = np.loadtxt(path + "/" + f) + for i in t: + i.reshape(1024, ) + bs16_out.append(i) + bs16_out_embeddings = {} + if not len(l_val) == len(bs16_out): + print(len(l_val), len(bs16_out)) + exit() + for k, v in zip(l_val, bs16_out): + bs16_out_embeddings[k] = v + d_embeddings = get_l_embeddings(bs16_out_embeddings,batch_size); + + with open('RawNet/trials/vox_original.txt', 'r') as f: + l_val_trial = f.readlines() + y_score = [] + y = [] + f_res = open(save_dir + 'result_detail_bs{}.txt'.format(batch_size), 'w') + for line in l_val_trial: + trg, utt_a, utt_b = line.strip().split(' ') + y.append(int(trg)) + y_score.append(cos_sim(d_embeddings[utt_a], d_embeddings[utt_b])) + f_res.write('{score} {target}\n'.format(score=y_score[-1], target=y[-1])) + f_res.close() + fpr, tpr, _ = roc_curve(y, y_score, pos_label=1) + eer = brentq(lambda x: 1. - x - interp1d(fpr, tpr)(x), 0., 1.) + f_eer_301 = open(save_dir + 'result_eer_{}.txt'.format(batch_size), 'w') + f_eer_301.write('bs{dir} evaluation EER: {eer}\n'.format(dir=batch_size, eer=eer)) + f_eer_301.close() + print('bs{dir} evaluation EER: {eer}\n'.format(dir=batch_size, eer=eer)) + + +if __name__ == '__main__': + main() diff --git a/ACL_PyTorch/contrib/audio/rawnet2/RawNet2_preprocess.py b/ACL_PyTorch/contrib/audio/rawnet2/RawNet2_preprocess.py index a0e421fb77..8249f16a44 100644 --- a/ACL_PyTorch/contrib/audio/rawnet2/RawNet2_preprocess.py +++ b/ACL_PyTorch/contrib/audio/rawnet2/RawNet2_preprocess.py @@ -1,84 +1,84 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import numpy as np -import argparse -import sys -sys.path.append('RawNet/python/RawNet2/') -from dataloader import TA_Dataset_VoxCeleb2 - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument('--input', help='dataset path', default="/root/datasets/VoxCeleb1/") - parser.add_argument('--batch_size', help='batch size', default=1) - parser.add_argument('--output', help='out bin path', default="bin_out_bs1/") - args = parser.parse_args() - base_dir = args.input - out_dir = args.output - batch_size = int(args.batch_size) - - def get_utt_list(src_dir): - l_utt = [] - for path, dirs, files in os.walk(src_dir): - path = path.replace('\\', '/') - base = '/'.join(path.split('/')[-2:]) + '/' - for f in files: - if f[-3:] != 'wav': - continue - l_utt.append(base + f) - return l_utt - - l_val = sorted(get_utt_list(base_dir)) - TA_evalset = TA_Dataset_VoxCeleb2(list_IDs=l_val, - return_label=True, - window_size=11810, - nb_samp=59049, - base_dir=base_dir) - if batch_size == 1: - for item in TA_evalset: - n = 0 - for i in item[0]: - i.tofile(out_dir + item[1].replace('/', '$') + "$" + str(n) + ".bin") - n += 1 - else: - bs16_key = open('bs16_key.txt', mode='w') - bs16 = [] - n = 0 - i = 0 - for item in TA_evalset: - l = 0 - for t in item[0]: - bs16_key.write(item[1].replace('/', '$') + "$" + str(n) + ".bin" + "$" + str(l) + "\n") - l += 1 - n += 1 - bs16.append(t) - if n == batch_size: - np.vstack(bs16).tofile(out_dir + str(i) + ".bin") - i += 1 - bs16 = [] - n = 0 - if n % batch_size == 0: - return - for j in range(batch_size - (n % batch_size)): - bs16_key.write("temp$" + str(j) + "\n") - bs16.append(np.empty((59049,), dtype='float32')) - bs16_key.close() - np.vstack(bs16).tofile(out_dir + str(i) + ".bin") - - -if __name__ == '__main__': - main() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import numpy as np +import argparse +import sys +sys.path.append('RawNet/python/RawNet2/') +from dataloader import TA_Dataset_VoxCeleb2 + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--input', help='dataset path', default="/root/datasets/VoxCeleb1/") + parser.add_argument('--batch_size', help='batch size', default=1) + parser.add_argument('--output', help='out bin path', default="bin_out_bs1/") + args = parser.parse_args() + base_dir = args.input + out_dir = args.output + batch_size = int(args.batch_size) + + def get_utt_list(src_dir): + l_utt = [] + for path, dirs, files in os.walk(src_dir): + path = path.replace('\\', '/') + base = '/'.join(path.split('/')[-2:]) + '/' + for f in files: + if f[-3:] != 'wav': + continue + l_utt.append(base + f) + return l_utt + + l_val = sorted(get_utt_list(base_dir)) + TA_evalset = TA_Dataset_VoxCeleb2(list_IDs=l_val, + return_label=True, + window_size=11810, + nb_samp=59049, + base_dir=base_dir) + if batch_size == 1: + for item in TA_evalset: + n = 0 + for i in item[0]: + i.tofile(out_dir + item[1].replace('/', '$') + "$" + str(n) + ".bin") + n += 1 + else: + bs16_key = open('bs16_key.txt', mode='w') + bs16 = [] + n = 0 + i = 0 + for item in TA_evalset: + l = 0 + for t in item[0]: + bs16_key.write(item[1].replace('/', '$') + "$" + str(n) + ".bin" + "$" + str(l) + "\n") + l += 1 + n += 1 + bs16.append(t) + if n == batch_size: + np.vstack(bs16).tofile(out_dir + str(i) + ".bin") + i += 1 + bs16 = [] + n = 0 + if n % batch_size == 0: + return + for j in range(batch_size - (n % batch_size)): + bs16_key.write("temp$" + str(j) + "\n") + bs16.append(np.empty((59049,), dtype='float32')) + bs16_key.close() + np.vstack(bs16).tofile(out_dir + str(i) + ".bin") + + +if __name__ == '__main__': + main() diff --git a/ACL_PyTorch/contrib/audio/rawnet2/RawNet2_pth2onnx.py b/ACL_PyTorch/contrib/audio/rawnet2/RawNet2_pth2onnx.py index 8cdefee1d3..a202509a73 100644 --- a/ACL_PyTorch/contrib/audio/rawnet2/RawNet2_pth2onnx.py +++ b/ACL_PyTorch/contrib/audio/rawnet2/RawNet2_pth2onnx.py @@ -1,34 +1,34 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import torch - -sys.path.append('RawNet/python/RawNet2/Pre-trained_model') -from RawNet.python.RawNet2.parser import get_args -from model_RawNet2_original_code import RawNet - -ptfile = "rawnet2_best_weights.pt" -args = get_args() -args.model['nb_classes'] = 6112 -model = RawNet(args.model, device="cpu") -model.load_state_dict(torch.load(ptfile, map_location=torch.device('cpu'))) -input_names = ["wav"] -output_names = ["class"] -dynamic_axes = {'wav': {0: '-1'}, 'class': {0: '-1'}} -dummy_input = torch.randn(1, 59049) -export_onnx_file = "RawNet2.onnx" -torch.onnx.export(model, dummy_input, export_onnx_file, input_names=input_names, dynamic_axes=dynamic_axes, - output_names=output_names, opset_version=11, verbose=True) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import torch + +sys.path.append('RawNet/python/RawNet2/Pre-trained_model') +from RawNet.python.RawNet2.parser import get_args +from model_RawNet2_original_code import RawNet + +ptfile = "rawnet2_best_weights.pt" +args = get_args() +args.model['nb_classes'] = 6112 +model = RawNet(args.model, device="cpu") +model.load_state_dict(torch.load(ptfile, map_location=torch.device('cpu'))) +input_names = ["wav"] +output_names = ["class"] +dynamic_axes = {'wav': {0: '-1'}, 'class': {0: '-1'}} +dummy_input = torch.randn(1, 59049) +export_onnx_file = "RawNet2.onnx" +torch.onnx.export(model, dummy_input, export_onnx_file, input_names=input_names, dynamic_axes=dynamic_axes, + output_names=output_names, opset_version=11, verbose=True) diff --git a/ACL_PyTorch/contrib/audio/rawnet2/env.sh b/ACL_PyTorch/contrib/audio/rawnet2/env.sh index ea514e10c5..52554cfca2 100644 --- a/ACL_PyTorch/contrib/audio/rawnet2/env.sh +++ b/ACL_PyTorch/contrib/audio/rawnet2/env.sh @@ -1,6 +1,6 @@ -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp -export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp +export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest diff --git a/ACL_PyTorch/contrib/audio/rawnet2/fusion_switch.cfg b/ACL_PyTorch/contrib/audio/rawnet2/fusion_switch.cfg index ece7f48ff2..9f8ef7e7a6 100644 --- a/ACL_PyTorch/contrib/audio/rawnet2/fusion_switch.cfg +++ b/ACL_PyTorch/contrib/audio/rawnet2/fusion_switch.cfg @@ -1,7 +1,7 @@ -{ - "Switch":{ - "UBFusion":{ - "TbeEltwiseFusionPass":"off" - } - } +{ + "Switch":{ + "UBFusion":{ + "TbeEltwiseFusionPass":"off" + } + } } \ No newline at end of file diff --git a/ACL_PyTorch/contrib/audio/rawnet2/modelzoo_level.txt b/ACL_PyTorch/contrib/audio/rawnet2/modelzoo_level.txt index 20e36b3f78..85fa1416d3 100644 --- a/ACL_PyTorch/contrib/audio/rawnet2/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/audio/rawnet2/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus:NOK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/audio/rawnet2/perf_t4.sh b/ACL_PyTorch/contrib/audio/rawnet2/perf_t4.sh index 26aa1c9748..56e04681b1 100644 --- a/ACL_PyTorch/contrib/audio/rawnet2/perf_t4.sh +++ b/ACL_PyTorch/contrib/audio/rawnet2/perf_t4.sh @@ -1,21 +1,21 @@ -#! /bin/bash - -trtexec --onnx=RawNet2_sim_bs1.onnx --fp16 --shapes=wav:1x59049 > RawNet2_bs1.log -perf_str=`grep "GPU.* mean.*ms$" ReID_bs1.log` -if [ -n "$perf_str" ]; then - perf_num=`echo $perf_str | awk -F' ' '{print $16}'` -else - perf_str=`grep "mean.*ms$" ReID_bs1.log` - perf_num=`echo $perf_str | awk -F' ' '{print $4}'` -fi -awk 'BEGIN{printf "gpu bs1 fps:%.3f\n", 1000*1/('$perf_num'/1)}' - -trtexec --onnx=RawNet2_sim_bs16.onnx --fp16 --shapes=wav:16x59049 > RawNet2_bs16.log -perf_str=`grep "GPU.* mean.*ms$" ReID_bs16.log` -if [ -n "$perf_str" ]; then - perf_num=`echo $perf_str | awk -F' ' '{print $16}'` -else - perf_str=`grep "mean.*ms$" ReID_bs16.log` - perf_num=`echo $perf_str | awk -F' ' '{print $4}'` -fi -awk 'BEGIN{printf "gpu bs16 fps:%.3f\n", 1000*1/('$perf_num'/16)}' +#! /bin/bash + +trtexec --onnx=RawNet2_sim_bs1.onnx --fp16 --shapes=wav:1x59049 > RawNet2_bs1.log +perf_str=`grep "GPU.* mean.*ms$" ReID_bs1.log` +if [ -n "$perf_str" ]; then + perf_num=`echo $perf_str | awk -F' ' '{print $16}'` +else + perf_str=`grep "mean.*ms$" ReID_bs1.log` + perf_num=`echo $perf_str | awk -F' ' '{print $4}'` +fi +awk 'BEGIN{printf "gpu bs1 fps:%.3f\n", 1000*1/('$perf_num'/1)}' + +trtexec --onnx=RawNet2_sim_bs16.onnx --fp16 --shapes=wav:16x59049 > RawNet2_bs16.log +perf_str=`grep "GPU.* mean.*ms$" ReID_bs16.log` +if [ -n "$perf_str" ]; then + perf_num=`echo $perf_str | awk -F' ' '{print $16}'` +else + perf_str=`grep "mean.*ms$" ReID_bs16.log` + perf_num=`echo $perf_str | awk -F' ' '{print $4}'` +fi +awk 'BEGIN{printf "gpu bs16 fps:%.3f\n", 1000*1/('$perf_num'/16)}' diff --git a/ACL_PyTorch/contrib/audio/rawnet2/requirements.txt b/ACL_PyTorch/contrib/audio/rawnet2/requirements.txt index 4c42a0cc0a..dbb1bfa1b6 100644 --- a/ACL_PyTorch/contrib/audio/rawnet2/requirements.txt +++ b/ACL_PyTorch/contrib/audio/rawnet2/requirements.txt @@ -1,9 +1,9 @@ -torch == 1.5.0 -torchvision == 0.6.0 -onnx == 1.10.1 -onnx-simplifier==0.3.6 -numpy -scikit-learn -scipy -tqdm +torch == 1.5.0 +torchvision == 0.6.0 +onnx == 1.10.1 +onnx-simplifier==0.3.6 +numpy +scikit-learn +scipy +tqdm soundfile \ No newline at end of file diff --git a/ACL_PyTorch/contrib/audio/rawnet2/test/parse.py b/ACL_PyTorch/contrib/audio/rawnet2/test/parse.py index 6cdf1420bd..64b47e3cff 100644 --- a/ACL_PyTorch/contrib/audio/rawnet2/test/parse.py +++ b/ACL_PyTorch/contrib/audio/rawnet2/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 - print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 + print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) diff --git a/ACL_PyTorch/contrib/audio/tdnn/LICENSE b/ACL_PyTorch/contrib/audio/tdnn/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/audio/tdnn/LICENSE +++ b/ACL_PyTorch/contrib/audio/tdnn/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/audio/tdnn/ReadMe.md b/ACL_PyTorch/contrib/audio/tdnn/ReadMe.md index 4ee27e8c11..95f84433d2 100644 --- a/ACL_PyTorch/contrib/audio/tdnn/ReadMe.md +++ b/ACL_PyTorch/contrib/audio/tdnn/ReadMe.md @@ -1,276 +1,276 @@ -# Tdnn Onnx模型端到端推理指导 -- [1 模型概述](#1-模型概述) - - [1.1 论文地址](#11-论文地址) - - [1.2 代码地址](#12-代码地址) -- [2 环境说明](#2-环境说明) - - [2.1 深度学习框架](#21-深度学习框架) - - [2.2 python第三方库](#22-python第三方库) -- [3 模型转换](#3-模型转换) - - [3.1 pth转onnx模型](#31-pth转onnx模型) - - [3.2 onnx转om模型](#32-onnx转om模型) -- [4 数据集预处理](#4-数据集预处理) - - [4.1 数据集获取](#41-数据集获取) - - [4.2 数据集预处理](#42-数据集预处理) - - [4.3 生成数据集信息文件](#43-生成数据集信息文件) -- [5 离线推理](#5-离线推理) -- [6 精度对比](#6-精度对比) - - [6.1 离线推理精度统计](#61-离线推理精度统计) - - [6.2 精度对比](#62-精度对比) -- [7 性能对比](#7-性能对比) - - [7.1 npu性能数据](#71-npu性能数据) - - [7.2 T4性能数据](#72-T4性能数据) - - [7.3 性能对比](#73-性能对比) - - - -## 1 模型概述 - -- **[论文地址](#11-论文地址)** - -- **[代码地址](#12-代码地址)** - -### 1.1 论文地址 -华为npu模型训练组依据客户给的模型进行训练所得,无参考论文 - -### 1.2 代码地址 -[Tdnn代码]https://gitee.com/ascend/modelzoo.git) -branch:master -commit_id= -code_path= - - - -## 2 环境说明 - -- **[深度学习框架](#21-深度学习框架)** - -- **[python第三方库](#22-python第三方库)** - -### 2.1 深度学习框架 -``` -pytorch = 昇腾1.5.0 -torchaudio = 0.5.0 -``` -### 2.2 python第三方库 -``` -speechbrain = 0.5.9 -onnx == 1.7.0 -onnxruntime-gpu == 1.8.1 -sox == 14.4.0 -``` -1.gpu环境搭建 -在安装了Anaconda或Miniconda的gpu环境下,首先执行命令 -``` -conda create -n tdnn python==3.7 -``` -创建名为tdnn的虚拟环境,再执行命令 -``` -conda activate tdnn -``` -进入该环境,先后执行下面两条命令 -``` -pip3 install torch==1.5.0 -pip3 install torchaudio==0.5.0 -``` -安装pytorch及torchaudio,再前往 -``` -https://codeload.github.com/speechbrain/speechbrain/zip/refs/tags/v0.5.9 -``` -下载speechbrain 0.5.9源码包,解压并进入speechbrain项目根目录,在speechbrain/speechbrain文件夹下找到requirement.txt,删除torch和torchaudio对应行,然后执行 -``` -pip install -r requirements.txt -pip install --editable . -``` -完成speechbrain安装,接着执行 -``` -pip install onnx==1.7.0 -``` -安装ONNX,执行 -``` -pip install onnxruntime-gpu==1.7.0 -``` -安装onnxruntime-gpu - -2.npu环境搭建 -在安装了Anaconda或Miniconda的npu环境下,首先执行命令 -``` -conda create -n tdnn python==3.7 -``` -创建名为tdnn的虚拟环境,再执行命令 -``` -conda activate tdnn -``` -进入该环境,先执行 -``` -pip3 install torch==1.5.0 -``` -安装pytorch,再尝试执行 -``` -pip3 install torchaudio==0.5.0 -``` -安装torchaudio,确保安装成功后再前往 -``` -https://codeload.github.com/speechbrain/speechbrain/zip/refs/tags/v0.5.9 -``` -下载speechbrain 0.5.9源码包,解压并进入speechbrain项目根目录,在speechbrain/speechbrain文件夹下找到requirement.txt,删除torch和torchaudio对应行,然后执行 -``` -pip install -r requirements.txt -pip install --editable . -``` -完成speechbrain安装 - -**说明:** -> 如果torchaudio安装失败,或者安装之后出现读取.flac文件报错的情况, -> 请前往https://e.gitee.com/HUAWEI-ASCEND/notifications/infos?issue=I48AZM -> 按步骤完成sox 14.4.0和torchaudio 0.5.0安装,再安装speechbrain - -## 3 模型转换 - -本模型基于开源框架PyTorch训练的TDNN模型进行转换。 -首先使用PyTorch将模型权重文件tdnn.pth转换为tdnn.onnx文件,再使用ATC工具将tdnn.onnx文件转为tdnn.om文件。 - -- **[pth转onnx模型](#31-pth转onnx模型)** - -- **[onnx转om模型](#32-onnx转om模型)** - -### 3.1 pth转onnx模型 -以下步骤均在gpu环境完成。 -1.转换前的代码处理 -在上一步安装的speechbrain文件夹中,进入文件夹speechbrain/nnet,找到CNN.py文件,将第349行修改为 -``` -padding_mode='constant' -``` -再进入文件夹speechbrain/pretrained,用本仓库的interfaces.py替换该目录下的同名文件 - -2.获取pth权重文件 -权重文件由华为npu模型训练组通过训练TDNN模型得到。 -在speechbrain/templates/speaker_id目录下新建文件夹best_model,将训练保存的模型文件及本仓库提供的hyperparams.yaml文件一并放到best_model。 -best_model文件夹下应包含以下文件: -``` -classifier.ckpt -hyperparams.yaml -embedding_model.ckpt -``` - -3.生成onnx模型文件 -将Tdnn_pth2onnx.py脚本放到speechbrain/templates/speaker_id目录下,并在该目录下执行 -``` -python Tdnn_pth2onnx.py -``` -运行成功后,该目录下将生成tdnn.onnx文件 - - **说明:** ->注意目前ATC支持的onnx算子版本为11 - - -### 3.2 onnx转om模型 - -以下步骤在npu环境进行。 -1.生成om模型文件 -将atc.sh脚本放到speechbrain/templates/speaker_id目录下,并在该目录下执行 -``` -bash atc.sh tdnn.onnx tdnn -``` -运行成功后,将生成tdnn.om模型 - - - -## 4 数据集预处理 - -- **[数据集获取](#41-数据集获取)** - -- **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - -### 4.1 数据集获取 -用户将自行获取的数据集上传到speechbrain/templates/speaker_id目录 - -### 4.2 数据集预处理 -进入speechbrain/templates/speaker_id目录,将mini_librispeech_prepare.py文件的第174行代码random.shuffle(wav_list)注释掉,然后在该目录下执行 -``` -python Tdnn_preprocess.py -``` -预处理后的数据集在新生成的目录mini_librispeech_test_bin中 -### 4.3 生成数据集信息文件 -上一步的数据集预处理会同步生成一个文件mini_librispeech_test.info,该文件即数据集信息文件 - - - -## 5 离线推理 -1.设置离线推理环境 -将acl_net.py, pyacl_infer.py, om_infer.sh三个文件放到speechbrain/templates/speaker_id目录下 -2.执行pyacl离线推理 -在speechbrain/templates/speaker_id目录下执行 -``` -bash om_infer.sh -``` -推理结果将会输出到result目录下 - - - -## 6 精度对比 -- **[离线推理精度](#61-离线推理精度)** -- **[精度对比](#62-精度对比)** - -### 6.1 离线推理精度统计 - -将Tdnn_postprocess.py文件放到speechbrain/templates/speaker_id目录下,并在该目录下执行 -``` -python Tdnn_postprocess.py -``` -精度统计结果将直接输出到控制台 - -### 6.2 精度对比 -pth模型精度99.10%,om模型精度98.69%,模型转换后精度损失不超过1% - **精度调试:** - ->模型转换后精度损失不超过1%,精度达标,故不需要进行精度调试 - - - -## 7 性能对比 - -- **[npu性能数据](#71-npu性能数据)** -- **[T4性能数据](#72-T4性能数据)** -- **[性能对比](#73-性能对比)** - -### 7.1 npu性能数据 -该模型不支持benchmark推理,故使用pyacl离线推理获取npu性能数据,npu性能数据为 -``` -average pure infer time(ms):10.24 -``` -Interface throughputRate: 1000/10.24 = 97.37 -310单卡吞吐率:1000/10.54*16 = 1562.50 fps - -### 7.2 T4性能数据 -1.搭建环境 -在T4服务器搭建onnx模型推理环境,然后新建test文件夹,将下列文件上传至该文件夹 -``` -tdnn.onnx文件 -Tdnn_onnx_infer.py文件 -speechbrain/templates/speaker_id目录下的mini_librispeech_test.info文件 -speechbrain/templates/speaker_id目录下的mini_librispeech_bin文件夹及其全部文件 -``` -2.执行在线推理 -在test目录下执行 -``` -python Tdnn_onnx_infer.py -``` -性能数据将会输出到gpu_result目录下 -T4性能基线数据为 -``` -average pure infer time(ms): 12.98 -``` -T4单卡吞吐率:1000/12.98*16 = 1232.67 fps - -### 7.3 性能对比 -单卡吞吐率 -``` -npu-310:1562.50 fps -gpu-t4 :1232.67 fps -``` -310性能高于T4性能,性能达标 - - **性能优化:** ->该模型性能优于T4,不用进行优化 +# Tdnn Onnx模型端到端推理指导 +- [1 模型概述](#1-模型概述) + - [1.1 论文地址](#11-论文地址) + - [1.2 代码地址](#12-代码地址) +- [2 环境说明](#2-环境说明) + - [2.1 深度学习框架](#21-深度学习框架) + - [2.2 python第三方库](#22-python第三方库) +- [3 模型转换](#3-模型转换) + - [3.1 pth转onnx模型](#31-pth转onnx模型) + - [3.2 onnx转om模型](#32-onnx转om模型) +- [4 数据集预处理](#4-数据集预处理) + - [4.1 数据集获取](#41-数据集获取) + - [4.2 数据集预处理](#42-数据集预处理) + - [4.3 生成数据集信息文件](#43-生成数据集信息文件) +- [5 离线推理](#5-离线推理) +- [6 精度对比](#6-精度对比) + - [6.1 离线推理精度统计](#61-离线推理精度统计) + - [6.2 精度对比](#62-精度对比) +- [7 性能对比](#7-性能对比) + - [7.1 npu性能数据](#71-npu性能数据) + - [7.2 T4性能数据](#72-T4性能数据) + - [7.3 性能对比](#73-性能对比) + + + +## 1 模型概述 + +- **[论文地址](#11-论文地址)** + +- **[代码地址](#12-代码地址)** + +### 1.1 论文地址 +华为npu模型训练组依据客户给的模型进行训练所得,无参考论文 + +### 1.2 代码地址 +[Tdnn代码]https://gitee.com/ascend/modelzoo.git) +branch:master +commit_id= +code_path= + + + +## 2 环境说明 + +- **[深度学习框架](#21-深度学习框架)** + +- **[python第三方库](#22-python第三方库)** + +### 2.1 深度学习框架 +``` +pytorch = 昇腾1.5.0 +torchaudio = 0.5.0 +``` +### 2.2 python第三方库 +``` +speechbrain = 0.5.9 +onnx == 1.7.0 +onnxruntime-gpu == 1.8.1 +sox == 14.4.0 +``` +1.gpu环境搭建 +在安装了Anaconda或Miniconda的gpu环境下,首先执行命令 +``` +conda create -n tdnn python==3.7 +``` +创建名为tdnn的虚拟环境,再执行命令 +``` +conda activate tdnn +``` +进入该环境,先后执行下面两条命令 +``` +pip3 install torch==1.5.0 +pip3 install torchaudio==0.5.0 +``` +安装pytorch及torchaudio,再前往 +``` +https://codeload.github.com/speechbrain/speechbrain/zip/refs/tags/v0.5.9 +``` +下载speechbrain 0.5.9源码包,解压并进入speechbrain项目根目录,在speechbrain/speechbrain文件夹下找到requirement.txt,删除torch和torchaudio对应行,然后执行 +``` +pip install -r requirements.txt +pip install --editable . +``` +完成speechbrain安装,接着执行 +``` +pip install onnx==1.7.0 +``` +安装ONNX,执行 +``` +pip install onnxruntime-gpu==1.7.0 +``` +安装onnxruntime-gpu + +2.npu环境搭建 +在安装了Anaconda或Miniconda的npu环境下,首先执行命令 +``` +conda create -n tdnn python==3.7 +``` +创建名为tdnn的虚拟环境,再执行命令 +``` +conda activate tdnn +``` +进入该环境,先执行 +``` +pip3 install torch==1.5.0 +``` +安装pytorch,再尝试执行 +``` +pip3 install torchaudio==0.5.0 +``` +安装torchaudio,确保安装成功后再前往 +``` +https://codeload.github.com/speechbrain/speechbrain/zip/refs/tags/v0.5.9 +``` +下载speechbrain 0.5.9源码包,解压并进入speechbrain项目根目录,在speechbrain/speechbrain文件夹下找到requirement.txt,删除torch和torchaudio对应行,然后执行 +``` +pip install -r requirements.txt +pip install --editable . +``` +完成speechbrain安装 + +**说明:** +> 如果torchaudio安装失败,或者安装之后出现读取.flac文件报错的情况, +> 请前往https://e.gitee.com/HUAWEI-ASCEND/notifications/infos?issue=I48AZM +> 按步骤完成sox 14.4.0和torchaudio 0.5.0安装,再安装speechbrain + +## 3 模型转换 + +本模型基于开源框架PyTorch训练的TDNN模型进行转换。 +首先使用PyTorch将模型权重文件tdnn.pth转换为tdnn.onnx文件,再使用ATC工具将tdnn.onnx文件转为tdnn.om文件。 + +- **[pth转onnx模型](#31-pth转onnx模型)** + +- **[onnx转om模型](#32-onnx转om模型)** + +### 3.1 pth转onnx模型 +以下步骤均在gpu环境完成。 +1.转换前的代码处理 +在上一步安装的speechbrain文件夹中,进入文件夹speechbrain/nnet,找到CNN.py文件,将第349行修改为 +``` +padding_mode='constant' +``` +再进入文件夹speechbrain/pretrained,用本仓库的interfaces.py替换该目录下的同名文件 + +2.获取pth权重文件 +权重文件由华为npu模型训练组通过训练TDNN模型得到。 +在speechbrain/templates/speaker_id目录下新建文件夹best_model,将训练保存的模型文件及本仓库提供的hyperparams.yaml文件一并放到best_model。 +best_model文件夹下应包含以下文件: +``` +classifier.ckpt +hyperparams.yaml +embedding_model.ckpt +``` + +3.生成onnx模型文件 +将Tdnn_pth2onnx.py脚本放到speechbrain/templates/speaker_id目录下,并在该目录下执行 +``` +python Tdnn_pth2onnx.py +``` +运行成功后,该目录下将生成tdnn.onnx文件 + + **说明:** +>注意目前ATC支持的onnx算子版本为11 + + +### 3.2 onnx转om模型 + +以下步骤在npu环境进行。 +1.生成om模型文件 +将atc.sh脚本放到speechbrain/templates/speaker_id目录下,并在该目录下执行 +``` +bash atc.sh tdnn.onnx tdnn +``` +运行成功后,将生成tdnn.om模型 + + + +## 4 数据集预处理 + +- **[数据集获取](#41-数据集获取)** + +- **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + +### 4.1 数据集获取 +用户将自行获取的数据集上传到speechbrain/templates/speaker_id目录 + +### 4.2 数据集预处理 +进入speechbrain/templates/speaker_id目录,将mini_librispeech_prepare.py文件的第174行代码random.shuffle(wav_list)注释掉,然后在该目录下执行 +``` +python Tdnn_preprocess.py +``` +预处理后的数据集在新生成的目录mini_librispeech_test_bin中 +### 4.3 生成数据集信息文件 +上一步的数据集预处理会同步生成一个文件mini_librispeech_test.info,该文件即数据集信息文件 + + + +## 5 离线推理 +1.设置离线推理环境 +将acl_net.py, pyacl_infer.py, om_infer.sh三个文件放到speechbrain/templates/speaker_id目录下 +2.执行pyacl离线推理 +在speechbrain/templates/speaker_id目录下执行 +``` +bash om_infer.sh +``` +推理结果将会输出到result目录下 + + + +## 6 精度对比 +- **[离线推理精度](#61-离线推理精度)** +- **[精度对比](#62-精度对比)** + +### 6.1 离线推理精度统计 + +将Tdnn_postprocess.py文件放到speechbrain/templates/speaker_id目录下,并在该目录下执行 +``` +python Tdnn_postprocess.py +``` +精度统计结果将直接输出到控制台 + +### 6.2 精度对比 +pth模型精度99.10%,om模型精度98.69%,模型转换后精度损失不超过1% + **精度调试:** + +>模型转换后精度损失不超过1%,精度达标,故不需要进行精度调试 + + + +## 7 性能对比 + +- **[npu性能数据](#71-npu性能数据)** +- **[T4性能数据](#72-T4性能数据)** +- **[性能对比](#73-性能对比)** + +### 7.1 npu性能数据 +该模型不支持benchmark推理,故使用pyacl离线推理获取npu性能数据,npu性能数据为 +``` +average pure infer time(ms):10.24 +``` +Interface throughputRate: 1000/10.24 = 97.37 +310单卡吞吐率:1000/10.54*16 = 1562.50 fps + +### 7.2 T4性能数据 +1.搭建环境 +在T4服务器搭建onnx模型推理环境,然后新建test文件夹,将下列文件上传至该文件夹 +``` +tdnn.onnx文件 +Tdnn_onnx_infer.py文件 +speechbrain/templates/speaker_id目录下的mini_librispeech_test.info文件 +speechbrain/templates/speaker_id目录下的mini_librispeech_bin文件夹及其全部文件 +``` +2.执行在线推理 +在test目录下执行 +``` +python Tdnn_onnx_infer.py +``` +性能数据将会输出到gpu_result目录下 +T4性能基线数据为 +``` +average pure infer time(ms): 12.98 +``` +T4单卡吞吐率:1000/12.98*16 = 1232.67 fps + +### 7.3 性能对比 +单卡吞吐率 +``` +npu-310:1562.50 fps +gpu-t4 :1232.67 fps +``` +310性能高于T4性能,性能达标 + + **性能优化:** +>该模型性能优于T4,不用进行优化 diff --git a/ACL_PyTorch/contrib/audio/tdnn/Tdnn_onnx_infer.py b/ACL_PyTorch/contrib/audio/tdnn/Tdnn_onnx_infer.py index 9e5bcbc807..7b74337de0 100644 --- a/ACL_PyTorch/contrib/audio/tdnn/Tdnn_onnx_infer.py +++ b/ACL_PyTorch/contrib/audio/tdnn/Tdnn_onnx_infer.py @@ -1,125 +1,125 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import time -import torch -import onnxruntime # WARNING: there must be onnxruntime-gpu only in the running environment ! -import torch.nn as nn -import numpy as np -from tqdm import tqdm -import datetime -import torchaudio - -# step 0: set the running settings here (mainly the file path) -'''-----------------------------------------------------------------------------------''' -model_path = 'tdnn.onnx' # path of the onnx model -input_info_file_path = 'mini_librispeech_test.info' # path of the input_info file -batchsize = 16 # the tested batchsize - -# path of the infer result ( actually the infer time ), create if not exists -infer_res_save_path = './gpu_result' -if not(os.path.exists(infer_res_save_path)): - os.makedirs(infer_res_save_path) - -# original 'MeasureTime' copied from acl_net.py, which is used in pyacl_infer.py -class MeasureTime(): - def __init__(self, measurements, key, cpu_run=True): - self.measurements = measurements - self.key = key - self.cpu_run = cpu_run - - def __enter__(self): - if not self.cpu_run: - torch.cuda.synchronize() - self.t0 = time.perf_counter_ns() - - def __exit__(self, exc_type, exc_value, exc_traceback): - if not self.cpu_run: - torch.cuda.synchronize() - self.measurements[self.key] = time.perf_counter_ns() - self.t0 -'''-----------------------------------------------------------------------------------''' - -# step 1: get the input file path according to the input_info file -'''-----------------------------------------------------------------------------------''' -input_file_path = {} -with open(input_info_file_path, 'rt', encoding='utf-8') as f_info: - line = f_info.readline() - while line: - line = line.rstrip('\n') - contents = line.split() - info = {'path': contents[1], 'shape': eval(contents[2])} - input_file_path.setdefault(contents[0], []).append(info) - line = f_info.readline() -'''-----------------------------------------------------------------------------------''' - -# step 2: perform infer for files listed in input_file_path -'''-----------------------------------------------------------------------------------''' -if __name__ == '__main__': - # step 2.1: set the counters - total_infer_time = 0 - total_infer_time_workspace = 0 - total_infer_num = 0 - workspace = 10 - measurements = {} - key = 'per_infer_time_ns' - dim_1 = 1800 - cpu_run = False - - # step 2.2: load the model to the onnx running session - # WARNING: there must be onnxruntime-gpu only in the running environment! - # if cpu and gpu exist at the same time, it will get wrong. - onnx_run_sess = onnxruntime.InferenceSession(model_path) - - # step 2.3: for each input file, load it and perform the infer - for key, values in tqdm(input_file_path.items()): - # step 2.3.1: load the input data - inputs = [] - dims = [] # dims and dims_info is actually unused here - for idx, value in enumerate(values): - x = np.fromfile(value['path'], dtype=np.float32).reshape(value['shape']) - inputs.append(x) - dims.extend(value['shape']) - dims_info = {'dimCount': len(dims), 'name': '', 'dims': dims} - inputs = torch.tensor(np.array(inputs).squeeze(axis = 0)) - pad = dim_1 - inputs.shape[1] - inputs = torch.nn.functional.pad(inputs, (0,0,0,pad,0,0), value=0).numpy() - - # step 2.3.2: perform the infer - with MeasureTime(measurements, key, cpu_run): - _ = onnx_run_sess.run(None, {onnx_run_sess.get_inputs()[0].name:inputs}) - total_infer_num += 1 - - # step 2.3.3: save the output => pass - - # step 2.3.4: calculate the time - total_infer_time += measurements[key] - if total_infer_num > workspace: - total_infer_time_workspace += measurements[key] - - # step 2.4: calculate the infer time needed - now = datetime.datetime.now() - print('[INFO] Infer time:') - msg = 'test at: ' + str(now) + '\n' + \ - 'total infer num: ' + str(total_infer_num) + '\n' + \ - 'total pure infer time(ms): ' + str(total_infer_time / 1000 / 1000) + '\n' + \ - 'average pure infer time(ms): ' + str(total_infer_time / total_infer_num / 1000 / 1000) + '\n' + \ - 'average pure infer time after workspace(ms): ' + str(abs( - total_infer_time_workspace / (total_infer_num - workspace) / 1000 / 1000)) + '\n' + '\n\n\n\n' - print(msg) - - result_txt='batch_' + str(batchsize) + '_infer_time.txt' - with open(os.path.join(infer_res_save_path, result_txt), 'a', encoding='utf-8') as f_infer_time: - f_infer_time.write(msg) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import time +import torch +import onnxruntime # WARNING: there must be onnxruntime-gpu only in the running environment ! +import torch.nn as nn +import numpy as np +from tqdm import tqdm +import datetime +import torchaudio + +# step 0: set the running settings here (mainly the file path) +'''-----------------------------------------------------------------------------------''' +model_path = 'tdnn.onnx' # path of the onnx model +input_info_file_path = 'mini_librispeech_test.info' # path of the input_info file +batchsize = 16 # the tested batchsize + +# path of the infer result ( actually the infer time ), create if not exists +infer_res_save_path = './gpu_result' +if not(os.path.exists(infer_res_save_path)): + os.makedirs(infer_res_save_path) + +# original 'MeasureTime' copied from acl_net.py, which is used in pyacl_infer.py +class MeasureTime(): + def __init__(self, measurements, key, cpu_run=True): + self.measurements = measurements + self.key = key + self.cpu_run = cpu_run + + def __enter__(self): + if not self.cpu_run: + torch.cuda.synchronize() + self.t0 = time.perf_counter_ns() + + def __exit__(self, exc_type, exc_value, exc_traceback): + if not self.cpu_run: + torch.cuda.synchronize() + self.measurements[self.key] = time.perf_counter_ns() - self.t0 +'''-----------------------------------------------------------------------------------''' + +# step 1: get the input file path according to the input_info file +'''-----------------------------------------------------------------------------------''' +input_file_path = {} +with open(input_info_file_path, 'rt', encoding='utf-8') as f_info: + line = f_info.readline() + while line: + line = line.rstrip('\n') + contents = line.split() + info = {'path': contents[1], 'shape': eval(contents[2])} + input_file_path.setdefault(contents[0], []).append(info) + line = f_info.readline() +'''-----------------------------------------------------------------------------------''' + +# step 2: perform infer for files listed in input_file_path +'''-----------------------------------------------------------------------------------''' +if __name__ == '__main__': + # step 2.1: set the counters + total_infer_time = 0 + total_infer_time_workspace = 0 + total_infer_num = 0 + workspace = 10 + measurements = {} + key = 'per_infer_time_ns' + dim_1 = 1800 + cpu_run = False + + # step 2.2: load the model to the onnx running session + # WARNING: there must be onnxruntime-gpu only in the running environment! + # if cpu and gpu exist at the same time, it will get wrong. + onnx_run_sess = onnxruntime.InferenceSession(model_path) + + # step 2.3: for each input file, load it and perform the infer + for key, values in tqdm(input_file_path.items()): + # step 2.3.1: load the input data + inputs = [] + dims = [] # dims and dims_info is actually unused here + for idx, value in enumerate(values): + x = np.fromfile(value['path'], dtype=np.float32).reshape(value['shape']) + inputs.append(x) + dims.extend(value['shape']) + dims_info = {'dimCount': len(dims), 'name': '', 'dims': dims} + inputs = torch.tensor(np.array(inputs).squeeze(axis = 0)) + pad = dim_1 - inputs.shape[1] + inputs = torch.nn.functional.pad(inputs, (0,0,0,pad,0,0), value=0).numpy() + + # step 2.3.2: perform the infer + with MeasureTime(measurements, key, cpu_run): + _ = onnx_run_sess.run(None, {onnx_run_sess.get_inputs()[0].name:inputs}) + total_infer_num += 1 + + # step 2.3.3: save the output => pass + + # step 2.3.4: calculate the time + total_infer_time += measurements[key] + if total_infer_num > workspace: + total_infer_time_workspace += measurements[key] + + # step 2.4: calculate the infer time needed + now = datetime.datetime.now() + print('[INFO] Infer time:') + msg = 'test at: ' + str(now) + '\n' + \ + 'total infer num: ' + str(total_infer_num) + '\n' + \ + 'total pure infer time(ms): ' + str(total_infer_time / 1000 / 1000) + '\n' + \ + 'average pure infer time(ms): ' + str(total_infer_time / total_infer_num / 1000 / 1000) + '\n' + \ + 'average pure infer time after workspace(ms): ' + str(abs( + total_infer_time_workspace / (total_infer_num - workspace) / 1000 / 1000)) + '\n' + '\n\n\n\n' + print(msg) + + result_txt='batch_' + str(batchsize) + '_infer_time.txt' + with open(os.path.join(infer_res_save_path, result_txt), 'a', encoding='utf-8') as f_infer_time: + f_infer_time.write(msg) '''-----------------------------------------------------------------------------------''' \ No newline at end of file diff --git a/ACL_PyTorch/contrib/audio/tdnn/Tdnn_postprocess.py b/ACL_PyTorch/contrib/audio/tdnn/Tdnn_postprocess.py index 027a483197..411a53eeef 100644 --- a/ACL_PyTorch/contrib/audio/tdnn/Tdnn_postprocess.py +++ b/ACL_PyTorch/contrib/audio/tdnn/Tdnn_postprocess.py @@ -1,58 +1,58 @@ -# -*- coding: utf-8 -*- -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import re -import argparse -import numpy as np -label = {0:'3526', 1:'7312', 2:'1088', 3:'32', 4:'460', 5:'7859', 6:'118', 7:'6848', 8:'8629', 9:'163', 10:'2416', 11:'3947', 12:'332', 13:'19', 14:'6272', 15:'7367', 16:'1898', 17:'3664', 18:'2136', 19:'4640', 20:'1867', 21:'1970', 22:'4680', 23:'226', 24:'5789', 25:'3242', 26:'667', 27:'1737'} - -if __name__ == '__main__': - ''' - 参数说明: - --data_info: 数据集信息 - --result_dir: 二进制推理结果目录 - ''' - - # arg parser - parser = argparse.ArgumentParser() - parser.add_argument('--data_info', default='mini_librispeech_test.info') - parser.add_argument('--result_dir', default='result') - - opt = parser.parse_args() - error = 0 - total = 0 - - with open('mini_librispeech_test.info', 'r') as f: - for line in f.readlines(): - # line format example - # 0 mini_librispeech_test_bin/4680-16042-0024.bin (1,1600,23) - split = line.split(' ') - index = split[0] - input_file = split[1] - target = re.search('/(\d*)-', input_file).group()[1:-1] - - # output result/index.0.bin => index range from 0 to 152 - output_file='result/'+index+'.0.bin' - - - output = np.fromfile(output_file, np.float32) - res = np.argmax(output) - print('Predicted:', label[res], 'Target:', target) - total += 1 - if label[res] != target: - error += 1 - accuracy = float(total - error) / total * 100 - print('\nClassification Accuracy: {:.2f}%\n'.format(accuracy)) +# -*- coding: utf-8 -*- +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import re +import argparse +import numpy as np +label = {0:'3526', 1:'7312', 2:'1088', 3:'32', 4:'460', 5:'7859', 6:'118', 7:'6848', 8:'8629', 9:'163', 10:'2416', 11:'3947', 12:'332', 13:'19', 14:'6272', 15:'7367', 16:'1898', 17:'3664', 18:'2136', 19:'4640', 20:'1867', 21:'1970', 22:'4680', 23:'226', 24:'5789', 25:'3242', 26:'667', 27:'1737'} + +if __name__ == '__main__': + ''' + 参数说明: + --data_info: 数据集信息 + --result_dir: 二进制推理结果目录 + ''' + + # arg parser + parser = argparse.ArgumentParser() + parser.add_argument('--data_info', default='mini_librispeech_test.info') + parser.add_argument('--result_dir', default='result') + + opt = parser.parse_args() + error = 0 + total = 0 + + with open('mini_librispeech_test.info', 'r') as f: + for line in f.readlines(): + # line format example + # 0 mini_librispeech_test_bin/4680-16042-0024.bin (1,1600,23) + split = line.split(' ') + index = split[0] + input_file = split[1] + target = re.search('/(\d*)-', input_file).group()[1:-1] + + # output result/index.0.bin => index range from 0 to 152 + output_file='result/'+index+'.0.bin' + + + output = np.fromfile(output_file, np.float32) + res = np.argmax(output) + print('Predicted:', label[res], 'Target:', target) + total += 1 + if label[res] != target: + error += 1 + accuracy = float(total - error) / total * 100 + print('\nClassification Accuracy: {:.2f}%\n'.format(accuracy)) diff --git a/ACL_PyTorch/contrib/audio/tdnn/Tdnn_preprocess.py b/ACL_PyTorch/contrib/audio/tdnn/Tdnn_preprocess.py index dcaa76a0e8..855ec5fa53 100644 --- a/ACL_PyTorch/contrib/audio/tdnn/Tdnn_preprocess.py +++ b/ACL_PyTorch/contrib/audio/tdnn/Tdnn_preprocess.py @@ -1,52 +1,52 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import json -import torchaudio -import torch.nn.functional as F -from speechbrain.pretrained import EncoderClassifier -from mini_librispeech_prepare import prepare_mini_librispeech - -prepare_mini_librispeech(data_folder='data', save_json_train='train.json', save_json_valid='valid.json', - save_json_test='test.json', split_ratio=[0, 0, 100]) - -if not os.path.exists('mini_librispeech_test_bin'): - os.makedirs('mini_librispeech_test_bin') - -file = open('mini_librispeech_test.info', 'w') -classifier = EncoderClassifier.from_hparams(source='best_model', savedir='best_model') - -with open('test.json', 'r') as f: - data_info = json.load(f) - i = 0 - - for key, value in data_info.items(): - wav_file = 'data' + value['wav'][11:] # prefix length 11 - signal, fs = torchaudio.load(wav_file) - feats = classifier.extract_feats(signal) - # pad signal - pad = (feats.shape[1] // 100 + 1) * 100 - feats.shape[1] - feats = F.pad(feats, (0,0,0,pad,0,0), value=0) - - # dump bin file - output = 'mini_librispeech_test_bin/' + value['wav'].split('/')[-1][:-4] + 'bin' - feats.numpy().tofile(output) - # write shape info - file.write(str(i) + ' ' + output + ' (' + str(feats.shape[0]) + ',' + str(feats.shape[1]) + ',' + str(feats.shape[2]) + ')') - file.write('\n') - i += 1 - - print('data preprocess done') +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import json +import torchaudio +import torch.nn.functional as F +from speechbrain.pretrained import EncoderClassifier +from mini_librispeech_prepare import prepare_mini_librispeech + +prepare_mini_librispeech(data_folder='data', save_json_train='train.json', save_json_valid='valid.json', + save_json_test='test.json', split_ratio=[0, 0, 100]) + +if not os.path.exists('mini_librispeech_test_bin'): + os.makedirs('mini_librispeech_test_bin') + +file = open('mini_librispeech_test.info', 'w') +classifier = EncoderClassifier.from_hparams(source='best_model', savedir='best_model') + +with open('test.json', 'r') as f: + data_info = json.load(f) + i = 0 + + for key, value in data_info.items(): + wav_file = 'data' + value['wav'][11:] # prefix length 11 + signal, fs = torchaudio.load(wav_file) + feats = classifier.extract_feats(signal) + # pad signal + pad = (feats.shape[1] // 100 + 1) * 100 - feats.shape[1] + feats = F.pad(feats, (0,0,0,pad,0,0), value=0) + + # dump bin file + output = 'mini_librispeech_test_bin/' + value['wav'].split('/')[-1][:-4] + 'bin' + feats.numpy().tofile(output) + # write shape info + file.write(str(i) + ' ' + output + ' (' + str(feats.shape[0]) + ',' + str(feats.shape[1]) + ',' + str(feats.shape[2]) + ')') + file.write('\n') + i += 1 + + print('data preprocess done') file.close() \ No newline at end of file diff --git a/ACL_PyTorch/contrib/audio/tdnn/Tdnn_pth2onnx.py b/ACL_PyTorch/contrib/audio/tdnn/Tdnn_pth2onnx.py index 4d6b3b31e4..f9632d4ecd 100644 --- a/ACL_PyTorch/contrib/audio/tdnn/Tdnn_pth2onnx.py +++ b/ACL_PyTorch/contrib/audio/tdnn/Tdnn_pth2onnx.py @@ -1,44 +1,44 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import torchaudio -from speechbrain.pretrained.interfaces import EncoderClassifier - -classifier = EncoderClassifier.from_hparams(source='best_model', savedir='best_model') - -# Download Thai language sample from Omniglot -class Xvector(torch.nn.Module): - def __init__(self, model): - super().__init__() - self.classifier = model - - def forward(self, feats): - res = self.classifier.feats_classify(feats) - return res - -model = Xvector(classifier) -feats = torch.randn([1, 1800, 23]) - -torch.onnx.export( - model, - feats, - 'tdnn.onnx', - input_names=['feats'], - output_names=['output'], - export_params=True, - do_constant_folding=True, - verbose=True, - opset_version=11 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import torchaudio +from speechbrain.pretrained.interfaces import EncoderClassifier + +classifier = EncoderClassifier.from_hparams(source='best_model', savedir='best_model') + +# Download Thai language sample from Omniglot +class Xvector(torch.nn.Module): + def __init__(self, model): + super().__init__() + self.classifier = model + + def forward(self, feats): + res = self.classifier.feats_classify(feats) + return res + +model = Xvector(classifier) +feats = torch.randn([1, 1800, 23]) + +torch.onnx.export( + model, + feats, + 'tdnn.onnx', + input_names=['feats'], + output_names=['output'], + export_params=True, + do_constant_folding=True, + verbose=True, + opset_version=11 ) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/audio/tdnn/Tdnn_pyacl_infer.py b/ACL_PyTorch/contrib/audio/tdnn/Tdnn_pyacl_infer.py index fa36db8401..d488b0c10a 100644 --- a/ACL_PyTorch/contrib/audio/tdnn/Tdnn_pyacl_infer.py +++ b/ACL_PyTorch/contrib/audio/tdnn/Tdnn_pyacl_infer.py @@ -1,176 +1,176 @@ -# Copyright 2018 NVIDIA Corporation. 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. -# ============================================================================ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 acl -from acl_net import AclModel - - -import os -import shutil - - -import argparse -import numpy as np -from tqdm import tqdm - -DTYPE = { - 'float32': np.float32, - 'float64': np.float64, - 'int32': np.int32, - 'int64': np.int64 -} - -if __name__ == '__main__': - ''' - 参数说明: - --model_path:模型路径 - --device_id:npu id - --cpu_run:MeasureTime类的cpu_run参数,True or False - --sync_infer:推理方式: - True:同步推理 - False:异步推理 - --workspace:类似TensorRT `workspace`参数,计算平均推理时间时排除前n次推理 - --input_info_file_path:类似benchmark的bin_info文件 - --input_dtypes:模型输入的类型,用逗号分割(`DTYPE`变量) - e.g. 模型只有一个输入:--input_dtypes=float32 - e.g. 模型有多个输入:--input_dtypes=float32,float32,float32(需要和bin_info文件多输入排列一致) - --infer_res_save_path:推理结果保存目录 - --res_save_type:推理结果保存类型,bin或npy - - info文件说明: - 因为支持动态shape,相比于benchmark的info文件,需要多加一列shape信息,e.g. - ``` - 0 ./bert_bin/input_ids_0.bin (1,512) - 0 ./bert_bin/segment_ids_0.bin (1,512) - 0 ./bert_bin/input_mask_0.bin (1,512) - 1 ./bert_bin/input_ids_1.bin (1,512) - 1 ./bert_bin/segment_ids_1.bin (1,512) - 1 ./bert_bin/input_mask_1.bin (1,512) - ``` - - Using Example: - python3.7 pyacl_infer.py \ - --model_path=./bert_base_batch_1_sim_auto.om \ - --device_id=0 \ - --cpu_run=True \ - --sync_infer=True \ - --workspace=10 \ - --input_info_file_path=./input.info \ - --input_dtypes=int64,int64,int64 \ - --infer_res_save_path=./infer_res \ - --res_save_type=bin - ''' - - # 参数解析 - parser = argparse.ArgumentParser() - parser.add_argument('--model_path', required=True) - parser.add_argument('--device_id', required=True, type=int) - parser.add_argument('--cpu_run', required=True, choices=['True', 'False']) - parser.add_argument('--sync_infer', required=True, choices=['True', 'False']) - parser.add_argument('--workspace', required=True, type=int) - parser.add_argument('--input_info_file_path', required=True) - parser.add_argument('--input_dtypes', required=True) - parser.add_argument('--infer_res_save_path', required=True) - parser.add_argument('--res_save_type', required=True, choices=['bin', 'npy']) - opt = parser.parse_args() - - - # 创建模型 - measurements = {} - om_model = AclModel(device_id=opt.device_id, - model_path=opt.model_path, - sync_infer=eval(opt.sync_infer), - measurements=measurements, - key='per_infer_time_ns', - cpu_run=eval(opt.cpu_run)) - - - # 创建目录 - if os.path.exists(opt.infer_res_save_path): - shutil.rmtree(opt.infer_res_save_path) - os.makedirs(opt.infer_res_save_path) - - - # 读取info_file - inputs_info = {} - with open(opt.input_info_file_path, 'rt', encoding='utf-8') as f_info: - line = f_info.readline() - while line: - line = line.rstrip('\n') - contents = line.split() - info = {'path': contents[1], 'shape': eval(contents[2])} - inputs_info.setdefault(contents[0], []).append(info) - line = f_info.readline() - - - # 解析输入类型 - input_dtypes = opt.input_dtypes.split(',') - input_dtypes = list(map(lambda x: DTYPE[x], input_dtypes)) - - - # 读取文件推理 - total_infer_time = 0 - total_infer_time_workspace = 0 - total_infer_num = 0 - for key, values in tqdm(inputs_info.items()): - # 构造输入 - inputs = [] - dims = [] - for idx, value in enumerate(values): - x = np.fromfile(value['path'], dtype=input_dtypes[idx]).reshape(value['shape']) - inputs.append(x) - dims.extend(value['shape']) - dims_info = {'dimCount': len(dims), 'name': '', 'dims': dims} - - # 推理得到输出 - output = om_model(inputs, dims_info) - total_infer_num += 1 - - # 保存文件 - if opt.res_save_type == 'bin': - for idx, data in enumerate(output): - data.tofile(os.path.join(opt.infer_res_save_path, key + '.' + str(idx) + '.bin')) - else: - for idx, data in enumerate(output): - np.save(os.path.join(opt.infer_res_save_path, key + '.' + str(idx) + '.npy'), data) - - # 计算时间 - total_infer_time += measurements['per_infer_time_ns'] - if total_infer_num > opt.workspace: - total_infer_time_workspace += measurements['per_infer_time_ns'] - - # 推理时间 - print('[INFO] Infer time:') - msg = 'total infer num: ' + str(total_infer_num) + '\n' + \ - 'total pure infer time(ms): ' + str(total_infer_time / 1000 / 1000) + '\n' + \ - 'average pure infer time(ms): ' + str(total_infer_time / total_infer_num / 1000 / 1000) + '\n' + \ - 'average pure infer time after workspace(ms): ' + str(abs( - total_infer_time_workspace / (total_infer_num - opt.workspace) / 1000 / 1000)) + '\n' - print(msg) - with open(os.path.join(opt.infer_res_save_path, 'infer_time.txt'), 'wt', encoding='utf-8') as f_infer_time: - f_infer_time.write(msg) +# Copyright 2018 NVIDIA Corporation. 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. +# ============================================================================ +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 acl +from acl_net import AclModel + + +import os +import shutil + + +import argparse +import numpy as np +from tqdm import tqdm + +DTYPE = { + 'float32': np.float32, + 'float64': np.float64, + 'int32': np.int32, + 'int64': np.int64 +} + +if __name__ == '__main__': + ''' + 参数说明: + --model_path:模型路径 + --device_id:npu id + --cpu_run:MeasureTime类的cpu_run参数,True or False + --sync_infer:推理方式: + True:同步推理 + False:异步推理 + --workspace:类似TensorRT `workspace`参数,计算平均推理时间时排除前n次推理 + --input_info_file_path:类似benchmark的bin_info文件 + --input_dtypes:模型输入的类型,用逗号分割(`DTYPE`变量) + e.g. 模型只有一个输入:--input_dtypes=float32 + e.g. 模型有多个输入:--input_dtypes=float32,float32,float32(需要和bin_info文件多输入排列一致) + --infer_res_save_path:推理结果保存目录 + --res_save_type:推理结果保存类型,bin或npy + + info文件说明: + 因为支持动态shape,相比于benchmark的info文件,需要多加一列shape信息,e.g. + ``` + 0 ./bert_bin/input_ids_0.bin (1,512) + 0 ./bert_bin/segment_ids_0.bin (1,512) + 0 ./bert_bin/input_mask_0.bin (1,512) + 1 ./bert_bin/input_ids_1.bin (1,512) + 1 ./bert_bin/segment_ids_1.bin (1,512) + 1 ./bert_bin/input_mask_1.bin (1,512) + ``` + + Using Example: + python3.7 pyacl_infer.py \ + --model_path=./bert_base_batch_1_sim_auto.om \ + --device_id=0 \ + --cpu_run=True \ + --sync_infer=True \ + --workspace=10 \ + --input_info_file_path=./input.info \ + --input_dtypes=int64,int64,int64 \ + --infer_res_save_path=./infer_res \ + --res_save_type=bin + ''' + + # 参数解析 + parser = argparse.ArgumentParser() + parser.add_argument('--model_path', required=True) + parser.add_argument('--device_id', required=True, type=int) + parser.add_argument('--cpu_run', required=True, choices=['True', 'False']) + parser.add_argument('--sync_infer', required=True, choices=['True', 'False']) + parser.add_argument('--workspace', required=True, type=int) + parser.add_argument('--input_info_file_path', required=True) + parser.add_argument('--input_dtypes', required=True) + parser.add_argument('--infer_res_save_path', required=True) + parser.add_argument('--res_save_type', required=True, choices=['bin', 'npy']) + opt = parser.parse_args() + + + # 创建模型 + measurements = {} + om_model = AclModel(device_id=opt.device_id, + model_path=opt.model_path, + sync_infer=eval(opt.sync_infer), + measurements=measurements, + key='per_infer_time_ns', + cpu_run=eval(opt.cpu_run)) + + + # 创建目录 + if os.path.exists(opt.infer_res_save_path): + shutil.rmtree(opt.infer_res_save_path) + os.makedirs(opt.infer_res_save_path) + + + # 读取info_file + inputs_info = {} + with open(opt.input_info_file_path, 'rt', encoding='utf-8') as f_info: + line = f_info.readline() + while line: + line = line.rstrip('\n') + contents = line.split() + info = {'path': contents[1], 'shape': eval(contents[2])} + inputs_info.setdefault(contents[0], []).append(info) + line = f_info.readline() + + + # 解析输入类型 + input_dtypes = opt.input_dtypes.split(',') + input_dtypes = list(map(lambda x: DTYPE[x], input_dtypes)) + + + # 读取文件推理 + total_infer_time = 0 + total_infer_time_workspace = 0 + total_infer_num = 0 + for key, values in tqdm(inputs_info.items()): + # 构造输入 + inputs = [] + dims = [] + for idx, value in enumerate(values): + x = np.fromfile(value['path'], dtype=input_dtypes[idx]).reshape(value['shape']) + inputs.append(x) + dims.extend(value['shape']) + dims_info = {'dimCount': len(dims), 'name': '', 'dims': dims} + + # 推理得到输出 + output = om_model(inputs, dims_info) + total_infer_num += 1 + + # 保存文件 + if opt.res_save_type == 'bin': + for idx, data in enumerate(output): + data.tofile(os.path.join(opt.infer_res_save_path, key + '.' + str(idx) + '.bin')) + else: + for idx, data in enumerate(output): + np.save(os.path.join(opt.infer_res_save_path, key + '.' + str(idx) + '.npy'), data) + + # 计算时间 + total_infer_time += measurements['per_infer_time_ns'] + if total_infer_num > opt.workspace: + total_infer_time_workspace += measurements['per_infer_time_ns'] + + # 推理时间 + print('[INFO] Infer time:') + msg = 'total infer num: ' + str(total_infer_num) + '\n' + \ + 'total pure infer time(ms): ' + str(total_infer_time / 1000 / 1000) + '\n' + \ + 'average pure infer time(ms): ' + str(total_infer_time / total_infer_num / 1000 / 1000) + '\n' + \ + 'average pure infer time after workspace(ms): ' + str(abs( + total_infer_time_workspace / (total_infer_num - opt.workspace) / 1000 / 1000)) + '\n' + print(msg) + with open(os.path.join(opt.infer_res_save_path, 'infer_time.txt'), 'wt', encoding='utf-8') as f_infer_time: + f_infer_time.write(msg) diff --git a/ACL_PyTorch/contrib/audio/tdnn/acl_net.py b/ACL_PyTorch/contrib/audio/tdnn/acl_net.py index f3ec7a6b5b..d7f893b3f3 100644 --- a/ACL_PyTorch/contrib/audio/tdnn/acl_net.py +++ b/ACL_PyTorch/contrib/audio/tdnn/acl_net.py @@ -1,276 +1,276 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 acl -import functools -import numpy as np -import torch -import time - -# error code -ACL_ERROR_NONE = 0 - -# rule for memory copy -ACL_MEMCPY_HOST_TO_HOST = 0 -ACL_MEMCPY_HOST_TO_DEVICE = 1 -ACL_MEMCPY_DEVICE_TO_HOST = 2 -ACL_MEMCPY_DEVICE_TO_DEVICE = 3 - -# dtype -ACL_DTYPE = { - 0: 'float32', - 1: 'float16', - 2: 'int8', - 3: 'int32', - 4: 'uint8', - 6: 'int16', - 7: 'uint16', - 8: 'uint32', - 9: 'int64', - 10: 'uint64', - 11: 'float64', - 12: 'bool', -} - - -def check_ret(message, ret): - if ret != ACL_ERROR_NONE: - raise Exception(f"{message} failed ret={ret}") - - -class MeasureTime(): - def __init__(self, measurements, key, cpu_run=True): - self.measurements = measurements - self.key = key - self.cpu_run = cpu_run - - def __enter__(self): - if not self.cpu_run: - torch.cuda.synchronize() - self.t0 = time.perf_counter_ns() - - def __exit__(self, exc_type, exc_value, exc_traceback): - if not self.cpu_run: - torch.cuda.synchronize() - self.measurements[self.key] = time.perf_counter_ns() - self.t0 - - -class AclModel(object): - def __init__(self, device_id, model_path, sync_infer, measurements, key, cpu_run): - self.device_id = device_id - self.sync_infer = sync_infer - self.out_bufs_ptr = [] - self.output_sizes = [] - self.input_sizes = [] - self.input_bufs_ptr = [] - - self.measurements = measurements - self.key = key - self.cpu_run = cpu_run - - ret = acl.init() - check_ret("acl.init", ret) - ret = acl.rt.set_device(self.device_id) - check_ret("acl.rt.set_device", ret) - self.context, ret = acl.rt.create_context(self.device_id) - check_ret("acl.rt.create_context", ret) - self.model_id, ret = acl.mdl.load_from_file(model_path) - check_ret("acl.mdl.load_from_file", ret) - - self.model_desc = acl.mdl.create_desc() - assert self.model_desc is not None - acl.mdl.get_desc(self.model_desc, self.model_id) - self.dataset_in = acl.mdl.create_dataset() - assert self.dataset_in is not None - self.dataset_out = acl.mdl.create_dataset() - assert self.dataset_out is not None - self.in_size, self.out_size = 0, 0 - self.stm, ret = acl.rt.create_stream() - assert ret == 0 - - self.desc_init() - self.dataset_init() - - def __call__(self, ori_data, dim): - return self.forward(ori_data, dim) - - def __del__(self): - # unload model - if self.model_id: - ret = acl.mdl.unload(self.model_id) - assert ret == 0 - - # destroy model desc - ret = acl.mdl.destroy_desc(self.model_desc) - assert ret == 0 - - self.destroy_data_set(self.dataset_in) - self.destroy_data_set(self.dataset_out) - - # destroy input/output tensor - for i in range(len(self.input_bufs_ptr)): - acl.rt.free(self.input_bufs_ptr[i]["buffer"]) - self.input_bufs_ptr[i] = None - - for i in range(len(self.out_bufs_ptr)): - acl.rt.free(self.out_bufs_ptr[i]["buffer"]) - self.out_bufs_ptr[i] = None - - ret = acl.rt.destroy_stream(self.stm) - assert ret == 0 - - def desc_init(self): - tensor_size = acl.mdl.get_num_inputs(self.model_desc) - if not tensor_size: - raise Exception("get_num_inputs failed") - self.in_size = tensor_size - - for i in range(tensor_size): - size = acl.mdl.get_input_size_by_index(self.model_desc, i) - data, ret = acl.rt.malloc(size, 0) - assert ret == 0 - - self.input_bufs_ptr.append({'size': size, 'buffer': data}) - self.input_sizes.append(size) - - tensor_size = acl.mdl.get_num_outputs(self.model_desc) - self.out_size = tensor_size - for i in range(tensor_size): - dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) - assert ret == 0 - size = acl.mdl.get_output_size_by_index(self.model_desc, i) - - data, ret = acl.rt.malloc(size, 0) - assert ret == 0 - - self.output_sizes.append(size) - self.out_bufs_ptr.append({'size': size, 'buffer': data}) - - def dataset_init(self): - self.create_data_set(self.dataset_in, self.input_bufs_ptr, self.input_sizes) - self.create_data_set(self.dataset_out, self.out_bufs_ptr, self.output_sizes) - - def create_data_set(self, dataset, bufs_ptr_list, size_list): - # create dataset buffer then add to dataset - for i in range(len(size_list)): - buffer = acl.create_data_buffer(bufs_ptr_list[i]["buffer"], size_list[i]) - if not buffer: - self.destroy_data_set(dataset) - raise Exception("create_data_buffer failed") - - # add to dataset - _, ret = acl.mdl.add_dataset_buffer(dataset, buffer) - if ret != 0: - self.destroy_data_set(dataset) - raise Exception("add_dataset_buffer failed, ret = {}".format(ret)) - - return dataset - - def destroy_data_set(self, dataset): - data_buf_num = acl.mdl.get_dataset_num_buffers(dataset) - for i in range(data_buf_num): - # get data buffer by index - data_buf = acl.mdl.get_dataset_buffer(dataset, i) - if data_buf is not None: - acl.destroy_data_buffer(data_buf) - - acl.mdl.destroy_dataset(dataset) - - def copy_data_to_device(self, data): - for i in range(len(data)): - ptr, np = acl.util.numpy_contiguous_to_ptr(data[i]["buffer"]) - acl.rt.memcpy(self.input_bufs_ptr[i]["buffer"], data[i]["size"], ptr, - data[i]["size"], ACL_MEMCPY_HOST_TO_DEVICE) - - def copy_output_to_host(self): - output_data = [] - for i in range(len(self.out_bufs_ptr)): - temp = dict() - temp["size"] = self.out_bufs_ptr[i]["size"] - temp["buffer"], ret = acl.rt.malloc_host(temp["size"]) - output_data.append(temp) - acl.rt.memcpy(temp["buffer"], temp["size"], self.out_bufs_ptr[i]["buffer"], - temp["size"], ACL_MEMCPY_DEVICE_TO_HOST) - - return output_data - - def model_exe(self): - with MeasureTime(self.measurements, self.key, self.cpu_run): - ret = acl.mdl.execute(self.model_id, self.dataset_in, self.dataset_out) - assert ret == 0 - output_data = self.copy_output_to_host() - dataset = [] - for i in range(len(output_data)): - dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) - data_shape = dims.get("dims") - data_type = acl.mdl.get_output_data_type(self.model_desc, i) - data_len = functools.reduce(lambda x, y: x * y, data_shape) - ftype = np.dtype(ACL_DTYPE.get(data_type)) - - size = output_data[i]["size"] - ptr = output_data[i]["buffer"] - data = acl.util.ptr_to_numpy(ptr, (size,), 1) - np_arr = np.frombuffer(bytearray(data[:data_len * ftype.itemsize]), dtype=ftype, count=data_len) - np_arr = np_arr.reshape(data_shape) - dataset.append(np_arr) - return dataset - - def model_exe_async(self): - with MeasureTime(self.measurements, self.key, self.cpu_run): - ret = acl.mdl.execute_async(self.model_id, self.dataset_in, self.dataset_out, self.stm) - assert ret == 0 - ret = acl.rt.synchronize_stream(self.stm) - assert ret == 0 - output_data = self.copy_output_to_host() - - dataset = [] - for i in range(len(output_data)): - dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) - # check_ret("acl.mdl.get_cur_output_dims", ret) - data_shape = dims.get("dims") - - data_type = acl.mdl.get_output_data_type(self.model_desc, i) - data_len = functools.reduce(lambda x, y: x * y, data_shape) - ftype = np.dtype(ACL_DTYPE.get(data_type)) - - size = output_data[i]["size"] - ptr = output_data[i]["buffer"] - data = acl.util.ptr_to_numpy(ptr, (size,), 1) - np_arr = np.frombuffer(bytearray(data[:data_len * ftype.itemsize]), dtype=ftype, count=data_len) - np_arr = np_arr.reshape(data_shape) - dataset.append(np_arr) - return dataset - - def model_exe_with_dynamic_dims(self, input_data, dims): - index, ret = acl.mdl.get_input_index_by_name(self.model_desc, 'ascend_mbatch_shape_data') - ret = acl.mdl.set_input_dynamic_dims(self.model_id, self.dataset_in, index, dims) - gear_count, ret = acl.mdl.get_input_dynamic_gear_count(self.model_desc, -1) - dims_out, ret = acl.mdl.get_input_dynamic_dims(self.model_desc, -1, gear_count) - self.copy_data_to_device(input_data) - if self.sync_infer is True: - res = self.model_exe() - else: - res = self.model_exe_async() - - return res - - def forward(self, input_data, dims): - input_data_dic = [] - for i in range(len(input_data)): - temp = {} - temp["size"] = input_data[i].size * input_data[i].itemsize - temp["buffer"] = input_data[i] - input_data_dic.append(temp) - result = self.model_exe_with_dynamic_dims(input_data_dic, dims) - return result +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 acl +import functools +import numpy as np +import torch +import time + +# error code +ACL_ERROR_NONE = 0 + +# rule for memory copy +ACL_MEMCPY_HOST_TO_HOST = 0 +ACL_MEMCPY_HOST_TO_DEVICE = 1 +ACL_MEMCPY_DEVICE_TO_HOST = 2 +ACL_MEMCPY_DEVICE_TO_DEVICE = 3 + +# dtype +ACL_DTYPE = { + 0: 'float32', + 1: 'float16', + 2: 'int8', + 3: 'int32', + 4: 'uint8', + 6: 'int16', + 7: 'uint16', + 8: 'uint32', + 9: 'int64', + 10: 'uint64', + 11: 'float64', + 12: 'bool', +} + + +def check_ret(message, ret): + if ret != ACL_ERROR_NONE: + raise Exception(f"{message} failed ret={ret}") + + +class MeasureTime(): + def __init__(self, measurements, key, cpu_run=True): + self.measurements = measurements + self.key = key + self.cpu_run = cpu_run + + def __enter__(self): + if not self.cpu_run: + torch.cuda.synchronize() + self.t0 = time.perf_counter_ns() + + def __exit__(self, exc_type, exc_value, exc_traceback): + if not self.cpu_run: + torch.cuda.synchronize() + self.measurements[self.key] = time.perf_counter_ns() - self.t0 + + +class AclModel(object): + def __init__(self, device_id, model_path, sync_infer, measurements, key, cpu_run): + self.device_id = device_id + self.sync_infer = sync_infer + self.out_bufs_ptr = [] + self.output_sizes = [] + self.input_sizes = [] + self.input_bufs_ptr = [] + + self.measurements = measurements + self.key = key + self.cpu_run = cpu_run + + ret = acl.init() + check_ret("acl.init", ret) + ret = acl.rt.set_device(self.device_id) + check_ret("acl.rt.set_device", ret) + self.context, ret = acl.rt.create_context(self.device_id) + check_ret("acl.rt.create_context", ret) + self.model_id, ret = acl.mdl.load_from_file(model_path) + check_ret("acl.mdl.load_from_file", ret) + + self.model_desc = acl.mdl.create_desc() + assert self.model_desc is not None + acl.mdl.get_desc(self.model_desc, self.model_id) + self.dataset_in = acl.mdl.create_dataset() + assert self.dataset_in is not None + self.dataset_out = acl.mdl.create_dataset() + assert self.dataset_out is not None + self.in_size, self.out_size = 0, 0 + self.stm, ret = acl.rt.create_stream() + assert ret == 0 + + self.desc_init() + self.dataset_init() + + def __call__(self, ori_data, dim): + return self.forward(ori_data, dim) + + def __del__(self): + # unload model + if self.model_id: + ret = acl.mdl.unload(self.model_id) + assert ret == 0 + + # destroy model desc + ret = acl.mdl.destroy_desc(self.model_desc) + assert ret == 0 + + self.destroy_data_set(self.dataset_in) + self.destroy_data_set(self.dataset_out) + + # destroy input/output tensor + for i in range(len(self.input_bufs_ptr)): + acl.rt.free(self.input_bufs_ptr[i]["buffer"]) + self.input_bufs_ptr[i] = None + + for i in range(len(self.out_bufs_ptr)): + acl.rt.free(self.out_bufs_ptr[i]["buffer"]) + self.out_bufs_ptr[i] = None + + ret = acl.rt.destroy_stream(self.stm) + assert ret == 0 + + def desc_init(self): + tensor_size = acl.mdl.get_num_inputs(self.model_desc) + if not tensor_size: + raise Exception("get_num_inputs failed") + self.in_size = tensor_size + + for i in range(tensor_size): + size = acl.mdl.get_input_size_by_index(self.model_desc, i) + data, ret = acl.rt.malloc(size, 0) + assert ret == 0 + + self.input_bufs_ptr.append({'size': size, 'buffer': data}) + self.input_sizes.append(size) + + tensor_size = acl.mdl.get_num_outputs(self.model_desc) + self.out_size = tensor_size + for i in range(tensor_size): + dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) + assert ret == 0 + size = acl.mdl.get_output_size_by_index(self.model_desc, i) + + data, ret = acl.rt.malloc(size, 0) + assert ret == 0 + + self.output_sizes.append(size) + self.out_bufs_ptr.append({'size': size, 'buffer': data}) + + def dataset_init(self): + self.create_data_set(self.dataset_in, self.input_bufs_ptr, self.input_sizes) + self.create_data_set(self.dataset_out, self.out_bufs_ptr, self.output_sizes) + + def create_data_set(self, dataset, bufs_ptr_list, size_list): + # create dataset buffer then add to dataset + for i in range(len(size_list)): + buffer = acl.create_data_buffer(bufs_ptr_list[i]["buffer"], size_list[i]) + if not buffer: + self.destroy_data_set(dataset) + raise Exception("create_data_buffer failed") + + # add to dataset + _, ret = acl.mdl.add_dataset_buffer(dataset, buffer) + if ret != 0: + self.destroy_data_set(dataset) + raise Exception("add_dataset_buffer failed, ret = {}".format(ret)) + + return dataset + + def destroy_data_set(self, dataset): + data_buf_num = acl.mdl.get_dataset_num_buffers(dataset) + for i in range(data_buf_num): + # get data buffer by index + data_buf = acl.mdl.get_dataset_buffer(dataset, i) + if data_buf is not None: + acl.destroy_data_buffer(data_buf) + + acl.mdl.destroy_dataset(dataset) + + def copy_data_to_device(self, data): + for i in range(len(data)): + ptr, np = acl.util.numpy_contiguous_to_ptr(data[i]["buffer"]) + acl.rt.memcpy(self.input_bufs_ptr[i]["buffer"], data[i]["size"], ptr, + data[i]["size"], ACL_MEMCPY_HOST_TO_DEVICE) + + def copy_output_to_host(self): + output_data = [] + for i in range(len(self.out_bufs_ptr)): + temp = dict() + temp["size"] = self.out_bufs_ptr[i]["size"] + temp["buffer"], ret = acl.rt.malloc_host(temp["size"]) + output_data.append(temp) + acl.rt.memcpy(temp["buffer"], temp["size"], self.out_bufs_ptr[i]["buffer"], + temp["size"], ACL_MEMCPY_DEVICE_TO_HOST) + + return output_data + + def model_exe(self): + with MeasureTime(self.measurements, self.key, self.cpu_run): + ret = acl.mdl.execute(self.model_id, self.dataset_in, self.dataset_out) + assert ret == 0 + output_data = self.copy_output_to_host() + dataset = [] + for i in range(len(output_data)): + dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) + data_shape = dims.get("dims") + data_type = acl.mdl.get_output_data_type(self.model_desc, i) + data_len = functools.reduce(lambda x, y: x * y, data_shape) + ftype = np.dtype(ACL_DTYPE.get(data_type)) + + size = output_data[i]["size"] + ptr = output_data[i]["buffer"] + data = acl.util.ptr_to_numpy(ptr, (size,), 1) + np_arr = np.frombuffer(bytearray(data[:data_len * ftype.itemsize]), dtype=ftype, count=data_len) + np_arr = np_arr.reshape(data_shape) + dataset.append(np_arr) + return dataset + + def model_exe_async(self): + with MeasureTime(self.measurements, self.key, self.cpu_run): + ret = acl.mdl.execute_async(self.model_id, self.dataset_in, self.dataset_out, self.stm) + assert ret == 0 + ret = acl.rt.synchronize_stream(self.stm) + assert ret == 0 + output_data = self.copy_output_to_host() + + dataset = [] + for i in range(len(output_data)): + dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) + # check_ret("acl.mdl.get_cur_output_dims", ret) + data_shape = dims.get("dims") + + data_type = acl.mdl.get_output_data_type(self.model_desc, i) + data_len = functools.reduce(lambda x, y: x * y, data_shape) + ftype = np.dtype(ACL_DTYPE.get(data_type)) + + size = output_data[i]["size"] + ptr = output_data[i]["buffer"] + data = acl.util.ptr_to_numpy(ptr, (size,), 1) + np_arr = np.frombuffer(bytearray(data[:data_len * ftype.itemsize]), dtype=ftype, count=data_len) + np_arr = np_arr.reshape(data_shape) + dataset.append(np_arr) + return dataset + + def model_exe_with_dynamic_dims(self, input_data, dims): + index, ret = acl.mdl.get_input_index_by_name(self.model_desc, 'ascend_mbatch_shape_data') + ret = acl.mdl.set_input_dynamic_dims(self.model_id, self.dataset_in, index, dims) + gear_count, ret = acl.mdl.get_input_dynamic_gear_count(self.model_desc, -1) + dims_out, ret = acl.mdl.get_input_dynamic_dims(self.model_desc, -1, gear_count) + self.copy_data_to_device(input_data) + if self.sync_infer is True: + res = self.model_exe() + else: + res = self.model_exe_async() + + return res + + def forward(self, input_data, dims): + input_data_dic = [] + for i in range(len(input_data)): + temp = {} + temp["size"] = input_data[i].size * input_data[i].itemsize + temp["buffer"] = input_data[i] + input_data_dic.append(temp) + result = self.model_exe_with_dynamic_dims(input_data_dic, dims) + return result diff --git a/ACL_PyTorch/contrib/audio/tdnn/atc.sh b/ACL_PyTorch/contrib/audio/tdnn/atc.sh index cede3be1b0..a2e9250855 100644 --- a/ACL_PyTorch/contrib/audio/tdnn/atc.sh +++ b/ACL_PyTorch/contrib/audio/tdnn/atc.sh @@ -1,9 +1,9 @@ -#!/bin/bash -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp -#export DUMP_GE_GRAPH=2 - +#!/bin/bash +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp +#export DUMP_GE_GRAPH=2 + atc --model=$1 --framework=5 --input_format=ND --input_shape="feats:1,-1,23" --dynamic_dims='200;300;400;500;600;700;800;900;1000;1100;1200;1300;1400;1500;1600;1700;1800' --output=$2 --soc_version=Ascend310 --log=info \ No newline at end of file diff --git a/ACL_PyTorch/contrib/audio/tdnn/hyperparams.yaml b/ACL_PyTorch/contrib/audio/tdnn/hyperparams.yaml index a24b5a03b2..0407ff5d22 100644 --- a/ACL_PyTorch/contrib/audio/tdnn/hyperparams.yaml +++ b/ACL_PyTorch/contrib/audio/tdnn/hyperparams.yaml @@ -1,67 +1,67 @@ - - -# ################################# -# Basic inference parameters for speaker-id. We have first a network that -# computes some embeddings. On the top of that, we employ a classifier. -# -# Author: -# * Mirco Ravanelli 2021 -# ################################# - -# pretrain folders: -pretrained_path: best_model - - -# Model parameters -n_mels: 23 -sample_rate: 16000 -n_classes: 28 # In this case, we have 28 speakers -emb_dim: 512 # dimensionality of the embeddings - -# Feature extraction -compute_features: !new:speechbrain.lobes.features.Fbank - n_mels: !ref - -# Mean and std normalization of the input features -mean_var_norm: !new:speechbrain.processing.features.InputNormalization - norm_type: sentence - std_norm: False - -# To design a custom model, either just edit the simple CustomModel -# class that's listed here, or replace this `!new` call with a line -# pointing to a different file you've defined. -embedding_model: !new:custom_model.Xvector - in_channels: !ref - activation: !name:torch.nn.LeakyReLU - tdnn_blocks: 5 - tdnn_channels: [512, 512, 512, 512, 1500] - tdnn_kernel_sizes: [5, 3, 3, 1, 1] - tdnn_dilations: [1, 2, 3, 1, 1] - lin_neurons: !ref - -classifier: !new:custom_model.Classifier - input_shape: [null, null, !ref ] - activation: !name:torch.nn.LeakyReLU - lin_blocks: 1 - lin_neurons: !ref - out_neurons: !ref - -label_encoder: !new:speechbrain.dataio.encoder.CategoricalEncoder - -# Objects in "modules" dict will have their parameters moved to the correct -# device, as well as having train()/eval() called on them by the Brain class. -modules: - compute_features: !ref - embedding_model: !ref - classifier: !ref - mean_var_norm: !ref - -pretrainer: !new:speechbrain.utils.parameter_transfer.Pretrainer - loadables: - embedding_model: !ref - classifier: !ref - label_encoder: !ref - paths: - embedding_model: !ref /embedding_model.ckpt - classifier: !ref /classifier.ckpt - label_encoder: !ref /label_encoder.txt + + +# ################################# +# Basic inference parameters for speaker-id. We have first a network that +# computes some embeddings. On the top of that, we employ a classifier. +# +# Author: +# * Mirco Ravanelli 2021 +# ################################# + +# pretrain folders: +pretrained_path: best_model + + +# Model parameters +n_mels: 23 +sample_rate: 16000 +n_classes: 28 # In this case, we have 28 speakers +emb_dim: 512 # dimensionality of the embeddings + +# Feature extraction +compute_features: !new:speechbrain.lobes.features.Fbank + n_mels: !ref + +# Mean and std normalization of the input features +mean_var_norm: !new:speechbrain.processing.features.InputNormalization + norm_type: sentence + std_norm: False + +# To design a custom model, either just edit the simple CustomModel +# class that's listed here, or replace this `!new` call with a line +# pointing to a different file you've defined. +embedding_model: !new:custom_model.Xvector + in_channels: !ref + activation: !name:torch.nn.LeakyReLU + tdnn_blocks: 5 + tdnn_channels: [512, 512, 512, 512, 1500] + tdnn_kernel_sizes: [5, 3, 3, 1, 1] + tdnn_dilations: [1, 2, 3, 1, 1] + lin_neurons: !ref + +classifier: !new:custom_model.Classifier + input_shape: [null, null, !ref ] + activation: !name:torch.nn.LeakyReLU + lin_blocks: 1 + lin_neurons: !ref + out_neurons: !ref + +label_encoder: !new:speechbrain.dataio.encoder.CategoricalEncoder + +# Objects in "modules" dict will have their parameters moved to the correct +# device, as well as having train()/eval() called on them by the Brain class. +modules: + compute_features: !ref + embedding_model: !ref + classifier: !ref + mean_var_norm: !ref + +pretrainer: !new:speechbrain.utils.parameter_transfer.Pretrainer + loadables: + embedding_model: !ref + classifier: !ref + label_encoder: !ref + paths: + embedding_model: !ref /embedding_model.ckpt + classifier: !ref /classifier.ckpt + label_encoder: !ref /label_encoder.txt diff --git a/ACL_PyTorch/contrib/audio/tdnn/interfaces.py b/ACL_PyTorch/contrib/audio/tdnn/interfaces.py index ddbf99b74b..ead6a0634d 100644 --- a/ACL_PyTorch/contrib/audio/tdnn/interfaces.py +++ b/ACL_PyTorch/contrib/audio/tdnn/interfaces.py @@ -1,958 +1,958 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -"""Defines interfaces for simple inference with pretrained models - -Authors: - * Aku Rouhe 2021 - * Peter Plantinga 2021 - * Loren Lugosch 2020 - * Mirco Ravanelli 2020 - * Titouan Parcollet 2021 -""" -import torch -import torchaudio -from types import SimpleNamespace -from torch.nn import SyncBatchNorm -from torch.nn import DataParallel as DP -from hyperpyyaml import load_hyperpyyaml -from speechbrain.pretrained.fetching import fetch -from speechbrain.dataio.preprocess import AudioNormalizer -import torch.nn.functional as F -from torch.nn.parallel import DistributedDataParallel as DDP -from speechbrain.utils.data_utils import split_path -from speechbrain.utils.distributed import run_on_main - - -class Pretrained: - """Takes a trained model and makes predictions on new data. - - This is a base class which handles some common boilerplate. - It intentionally has an interface similar to ``Brain`` - these base - classes handle similar things. - - Subclasses of Pretrained should implement the actual logic of how - the pretrained system runs, and add methods with descriptive names - (e.g. transcribe_file() for ASR). - - Arguments - --------- - modules : dict of str:torch.nn.Module pairs - The Torch modules that make up the learned system. These can be treated - in special ways (put on the right device, frozen, etc.) - hparams : dict - Each key:value pair should consist of a string key and a hyperparameter - that is used within the overridden methods. These will - be accessible via an ``hparams`` attribute, using "dot" notation: - e.g., self.hparams.model(x). - run_opts : dict - Options parsed from command line. See ``speechbrain.parse_arguments()``. - List that are supported here: - * device - * data_parallel_count - * data_parallel_backend - * distributed_launch - * distributed_backend - * jit_module_keys - freeze_params : bool - To freeze (requires_grad=False) parameters or not. Normally in inference - you want to freeze the params. Also calls .eval() on all modules. - """ - - HPARAMS_NEEDED = [] - MODULES_NEEDED = [] - - def __init__( - self, modules=None, hparams=None, run_opts=None, freeze_params=True - ): - - # Arguments passed via the run opts dictionary. Set a limited - # number of these, since some don't apply to inference. - run_opt_defaults = { - "device": "cpu", - "data_parallel_count": -1, - "data_parallel_backend": False, - "distributed_launch": False, - "distributed_backend": "nccl", - "jit_module_keys": None, - } - for arg, default in run_opt_defaults.items(): - if run_opts is not None and arg in run_opts: - setattr(self, arg, run_opts[arg]) - else: - # If any arg from run_opt_defaults exist in hparams and - # not in command line args "run_opts" - if hparams is not None and arg in hparams: - setattr(self, arg, hparams[arg]) - else: - setattr(self, arg, default) - - # Put modules on the right device, accessible with dot notation - self.modules = torch.nn.ModuleDict(modules) - for mod in self.modules: - self.modules[mod].to(self.device) - - for mod in self.MODULES_NEEDED: - if mod not in modules: - raise ValueError(f"Need modules['{mod}']") - - # Check MODULES_NEEDED and HPARAMS_NEEDED and - # make hyperparams available with dot notation - if self.HPARAMS_NEEDED and hparams is None: - raise ValueError("Need to provide hparams dict.") - if hparams is not None: - # Also first check that all required params are found: - for hp in self.HPARAMS_NEEDED: - if hp not in hparams: - raise ValueError(f"Need hparams['{hp}']") - self.hparams = SimpleNamespace(**hparams) - - # Prepare modules for computation, e.g. jit - self._prepare_modules(freeze_params) - - # Audio normalization - self.audio_normalizer = hparams.get( - "audio_normalizer", AudioNormalizer() - ) - - def _prepare_modules(self, freeze_params): - """Prepare modules for computation, e.g. jit. - - Arguments - --------- - freeze_params : bool - Whether to freeze the parameters and call ``eval()``. - """ - - # Make jit-able - self._compile_jit() - self._wrap_distributed() - - # If we don't want to backprop, freeze the pretrained parameters - if freeze_params: - self.modules.eval() - for p in self.modules.parameters(): - p.requires_grad = False - - def load_audio(self, path, savedir="."): - """Load an audio file with this model"s input spec - - When using a speech model, it is important to use the same type of data, - as was used to train the model. This means for example using the same - sampling rate and number of channels. It is, however, possible to - convert a file from a higher sampling rate to a lower one (downsampling). - Similarly, it is simple to downmix a stereo file to mono. - The path can be a local path, a web url, or a link to a huggingface repo. - """ - source, fl = split_path(path) - path = fetch(fl, source=source, savedir=savedir) - signal, sr = torchaudio.load(path, channels_first=False) - return self.audio_normalizer(signal, sr) - - def _compile_jit(self): - """Compile requested modules with ``torch.jit.script``.""" - if self.jit_module_keys is None: - return - - for name in self.jit_module_keys: - if name not in self.modules: - raise ValueError( - "module " + name + " cannot be jit compiled because " - "it is not defined in your hparams file." - ) - module = torch.jit.script(self.modules[name]) - self.modules[name] = module.to(self.device) - - def _wrap_distributed(self): - """Wrap modules with distributed wrapper when requested.""" - if not self.distributed_launch and not self.data_parallel_backend: - return - elif self.distributed_launch: - for name, module in self.modules.items(): - if any(p.requires_grad for p in module.parameters()): - # for ddp, all module must run on same GPU - module = SyncBatchNorm.convert_sync_batchnorm(module) - module = DDP(module, device_ids=[self.device]) - self.modules[name] = module - else: - # data_parallel_backend - for name, module in self.modules.items(): - if any(p.requires_grad for p in module.parameters()): - # if distributed_count = -1 then use all gpus - # otherwise, specify the set of gpu to use - if self.data_parallel_count == -1: - module = DP(module) - else: - module = DP( - module, - [i for i in range(self.data_parallel_count)], - ) - self.modules[name] = module - - @classmethod - def from_hparams( - cls, - source, - hparams_file="hyperparams.yaml", - overrides={}, - savedir=None, - use_auth_token=False, - **kwargs, - ): - """Fetch and load based from outside source based on HyperPyYAML file - - The source can be a location on the filesystem or online/huggingface - - The hyperparams file should contain a "modules" key, which is a - dictionary of torch modules used for computation. - - The hyperparams file should contain a "pretrainer" key, which is a - speechbrain.utils.parameter_transfer.Pretrainer - - Arguments - --------- - source : str - The location to use for finding the model. See - ``speechbrain.pretrained.fetching.fetch`` for details. - hparams_file : str - The name of the hyperparameters file to use for constructing - the modules necessary for inference. Must contain two keys: - "modules" and "pretrainer", as described. - overrides : dict - Any changes to make to the hparams file when it is loaded. - savedir : str or Path - Where to put the pretraining material. If not given, will use - ./pretrained_models/-hash(source). - use_auth_token : bool (default: False) - If true Hugginface's auth_token will be used to load private models from the HuggingFace Hub, - default is False because majority of models are public. - """ - if savedir is None: - clsname = cls.__name__ - savedir = f"./pretrained_models/{clsname}-{hash(source)}" - hparams_local_path = fetch( - hparams_file, source, savedir, use_auth_token - ) - - # Load the modules: - with open(hparams_local_path) as fin: - hparams = load_hyperpyyaml(fin, overrides) - - # Pretraining: - pretrainer = hparams["pretrainer"] - pretrainer.set_collect_in(savedir) - # For distributed setups, have this here: - run_on_main(pretrainer.collect_files, kwargs={"default_source": source}) - # Load on the CPU. Later the params can be moved elsewhere by specifying - # run_opts={"device": ...} - pretrainer.load_collected(device="cpu") - - # Now return the system - return cls(hparams["modules"], hparams, **kwargs) - - -class EndToEndSLU(Pretrained): - """A end-to-end SLU model. - - The class can be used either to run only the encoder (encode()) to extract - features or to run the entire model (decode()) to map the speech to its semantics. - - Example - ------- - >>> from speechbrain.pretrained import EndToEndSLU - >>> tmpdir = getfixture("tmpdir") - >>> slu_model = EndToEndSLU.from_hparams( - ... source="speechbrain/slu-timers-and-such-direct-librispeech-asr", - ... savedir=tmpdir, - ... ) - >>> slu_model.decode_file("samples/audio_samples/example6.wav") - "{'intent': 'SimpleMath', 'slots': {'number1': 37.67, 'number2': 75.7, 'op': ' minus '}}" - """ - - HPARAMS_NEEDED = ["tokenizer", "asr_model_source"] - MODULES_NEEDED = [ - "slu_enc", - "beam_searcher", - ] - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.tokenizer = self.hparams.tokenizer - self.asr_model = EncoderDecoderASR.from_hparams( - source=self.hparams.asr_model_source, - run_opts={"device": self.device}, - ) - - def decode_file(self, path): - """Maps the given audio file to a string representing the - semantic dictionary for the utterance. - - Arguments - --------- - path : str - Path to audio file to decode. - - Returns - ------- - str - The predicted semantics. - """ - waveform = self.load_audio(path) - waveform = waveform.to(self.device) - # Fake a batch: - batch = waveform.unsqueeze(0) - rel_length = torch.tensor([1.0]) - predicted_words, predicted_tokens = self.decode_batch(batch, rel_length) - return predicted_words[0] - - def encode_batch(self, wavs, wav_lens): - """Encodes the input audio into a sequence of hidden states - - Arguments - --------- - wavs : torch.tensor - Batch of waveforms [batch, time, channels] or [batch, time] - depending on the model. - wav_lens : torch.tensor - Lengths of the waveforms relative to the longest one in the - batch, tensor of shape [batch]. The longest one should have - relative length 1.0 and others len(waveform) / max_length. - Used for ignoring padding. - - Returns - ------- - torch.tensor - The encoded batch - """ - wavs = wavs.float() - wavs, wav_lens = wavs.to(self.device), wav_lens.to(self.device) - with torch.no_grad(): - ASR_encoder_out = self.asr_model.encode_batch( - wavs.detach(), wav_lens - ) - encoder_out = self.modules.slu_enc(ASR_encoder_out) - return encoder_out - - def decode_batch(self, wavs, wav_lens): - """Maps the input audio to its semantics - - Arguments - --------- - wavs : torch.tensor - Batch of waveforms [batch, time, channels] or [batch, time] - depending on the model. - wav_lens : torch.tensor - Lengths of the waveforms relative to the longest one in the - batch, tensor of shape [batch]. The longest one should have - relative length 1.0 and others len(waveform) / max_length. - Used for ignoring padding. - - Returns - ------- - list - Each waveform in the batch decoded. - tensor - Each predicted token id. - """ - with torch.no_grad(): - wavs, wav_lens = wavs.to(self.device), wav_lens.to(self.device) - encoder_out = self.encode_batch(wavs, wav_lens) - predicted_tokens, scores = self.modules.beam_searcher( - encoder_out, wav_lens - ) - predicted_words = [ - self.tokenizer.decode_ids(token_seq) - for token_seq in predicted_tokens - ] - return predicted_words, predicted_tokens - - -class EncoderDecoderASR(Pretrained): - """A ready-to-use Encoder-Decoder ASR model - - The class can be used either to run only the encoder (encode()) to extract - features or to run the entire encoder-decoder model - (transcribe()) to transcribe speech. The given YAML must contains the fields - specified in the *_NEEDED[] lists. - - Example - ------- - >>> from speechbrain.pretrained import EncoderDecoderASR - >>> tmpdir = getfixture("tmpdir") - >>> asr_model = EncoderDecoderASR.from_hparams( - ... source="speechbrain/asr-crdnn-rnnlm-librispeech", - ... savedir=tmpdir, - ... ) - >>> asr_model.transcribe_file("samples/audio_samples/example2.flac") - "MY FATHER HAS REVEALED THE CULPRIT'S NAME" - """ - - HPARAMS_NEEDED = ["tokenizer"] - MODULES_NEEDED = [ - "encoder", - "decoder", - ] - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.tokenizer = self.hparams.tokenizer - - def transcribe_file(self, path): - """Transcribes the given audiofile into a sequence of words. - - Arguments - --------- - path : str - Path to audio file which to transcribe. - - Returns - ------- - str - The audiofile transcription produced by this ASR system. - """ - waveform = self.load_audio(path) - # Fake a batch: - batch = waveform.unsqueeze(0) - rel_length = torch.tensor([1.0]) - predicted_words, predicted_tokens = self.transcribe_batch( - batch, rel_length - ) - return predicted_words[0] - - def encode_batch(self, wavs, wav_lens): - """Encodes the input audio into a sequence of hidden states - - The waveforms should already be in the model's desired format. - You can call: - ``normalized = EncoderDecoderASR.normalizer(signal, sample_rate)`` - to get a correctly converted signal in most cases. - - Arguments - --------- - wavs : torch.tensor - Batch of waveforms [batch, time, channels] or [batch, time] - depending on the model. - wav_lens : torch.tensor - Lengths of the waveforms relative to the longest one in the - batch, tensor of shape [batch]. The longest one should have - relative length 1.0 and others len(waveform) / max_length. - Used for ignoring padding. - - Returns - ------- - torch.tensor - The encoded batch - """ - wavs = wavs.float() - wavs, wav_lens = wavs.to(self.device), wav_lens.to(self.device) - encoder_out = self.modules.encoder(wavs, wav_lens) - return encoder_out - - def transcribe_batch(self, wavs, wav_lens): - """Transcribes the input audio into a sequence of words - - The waveforms should already be in the model's desired format. - You can call: - ``normalized = EncoderDecoderASR.normalizer(signal, sample_rate)`` - to get a correctly converted signal in most cases. - - Arguments - --------- - wavs : torch.tensor - Batch of waveforms [batch, time, channels] or [batch, time] - depending on the model. - wav_lens : torch.tensor - Lengths of the waveforms relative to the longest one in the - batch, tensor of shape [batch]. The longest one should have - relative length 1.0 and others len(waveform) / max_length. - Used for ignoring padding. - - Returns - ------- - list - Each waveform in the batch transcribed. - tensor - Each predicted token id. - """ - with torch.no_grad(): - wav_lens = wav_lens.to(self.device) - encoder_out = self.encode_batch(wavs, wav_lens) - predicted_tokens, scores = self.modules.decoder( - encoder_out, wav_lens - ) - predicted_words = [ - self.tokenizer.decode_ids(token_seq) - for token_seq in predicted_tokens - ] - return predicted_words, predicted_tokens - - -class EncoderClassifier(Pretrained): - """A ready-to-use class for utterance-level classification (e.g, speaker-id, - language-id, emotion recognition, keyword spotting, etc). - - The class assumes that an encoder called "embedding_model" and a model - called "classifier" are defined in the yaml file. If you want to - convert the predicted index into a corresponding text label, please - provide the path of the label_encoder in a variable called 'lab_encoder_file' - within the yaml. - - The class can be used either to run only the encoder (encode_batch()) to - extract embeddings or to run a classification step (classify_batch()). - ``` - - Example - ------- - >>> import torchaudio - >>> from speechbrain.pretrained import EncoderClassifier - >>> # Model is downloaded from the speechbrain HuggingFace repo - >>> tmpdir = getfixture("tmpdir") - >>> classifier = EncoderClassifier.from_hparams( - ... source="speechbrain/spkrec-ecapa-voxceleb", - ... savedir=tmpdir, - ... ) - - >>> # Compute embeddings - >>> signal, fs = torchaudio.load("samples/audio_samples/example1.wav") - >>> embeddings = classifier.encode_batch(signal) - - >>> # Classification - >>> prediction = classifier .classify_batch(signal) - """ - - MODULES_NEEDED = [ - "compute_features", - "mean_var_norm", - "embedding_model", - "classifier", - ] - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - def extract_feats(self, wavs, wav_lens=None): - # wav to feats - wavs = wavs.to('cpu').float() - if wav_lens is None: - wav_lens = torch.ones(wavs.shape[0], device='cpu') - - feats = self.modules.compute_features(wavs) - feats = self.modules.mean_var_norm(feats, wav_lens) - - return feats - - def feats_classify(self, feats, wav_lens=None): - emb = self.modules.embedding_model(feats, wav_lens) - out_prob = self.modules.classifier(emb).squeeze(1) - - return out_prob - - def encode_batch(self, wavs, wav_lens=None, normalize=False): - """Encodes the input audio into a single vector embedding. - - The waveforms should already be in the model's desired format. - You can call: - ``normalized = .normalizer(signal, sample_rate)`` - to get a correctly converted signal in most cases. - - Arguments - --------- - wavs : torch.tensor - Batch of waveforms [batch, time, channels] or [batch, time] - depending on the model. Make sure the sample rate is fs=16000 Hz. - wav_lens : torch.tensor - Lengths of the waveforms relative to the longest one in the - batch, tensor of shape [batch]. The longest one should have - relative length 1.0 and others len(waveform) / max_length. - Used for ignoring padding. - normalize : bool - If True, it normalizes the embeddings with the statistics - contained in mean_var_norm_emb. - - Returns - ------- - torch.tensor - The encoded batch - """ - # Manage single waveforms in input - if len(wavs.shape) == 1: - wavs = wavs.unsqueeze(0) - - # Assign full length if wav_lens is not assigned - if wav_lens is None: - wav_lens = torch.ones(wavs.shape[0], device=self.device) - - # Storing waveform in the specified device - wavs, wav_lens = wavs.to(self.device), wav_lens.to(self.device) - wavs = wavs.float() - - # Computing features and embeddings - feats = self.modules.compute_features(wavs) - feats = self.modules.mean_var_norm(feats, wav_lens) - embeddings = self.modules.embedding_model(feats, wav_lens) - if normalize: - embeddings = self.hparams.mean_var_norm_emb( - embeddings, torch.ones(embeddings.shape[0], device=self.device) - ) - return embeddings - - def classify_batch(self, wavs, wav_lens=None): - """Performs classification on the top of the encoded features. - - It returns the posterior probabilities, the index and, if the label - encoder is specified it also the text label. - - Arguments - --------- - wavs : torch.tensor - Batch of waveforms [batch, time, channels] or [batch, time] - depending on the model. Make sure the sample rate is fs=16000 Hz. - wav_lens : torch.tensor - Lengths of the waveforms relative to the longest one in the - batch, tensor of shape [batch]. The longest one should have - relative length 1.0 and others len(waveform) / max_length. - Used for ignoring padding. - - Returns - ------- - out_prob - The log posterior probabilities of each class ([batch, N_class]) - score: - It is the value of the log-posterior for the best class ([batch,]) - index - The indexes of the best class ([batch,]) - text_lab: - List with the text labels corresponding to the indexes. - (label encoder should be provided). - """ - emb = self.encode_batch(wavs, wav_lens) - out_prob = self.modules.classifier(emb).squeeze(1) - score, index = torch.max(out_prob, dim=-1) - text_lab = self.hparams.label_encoder.decode_torch(index) - return out_prob, score, index, text_lab - - def classify_file(self, path): - """Classifies the given audiofile into the given set of labels. - - Arguments - --------- - path : str - Path to audio file to classify. - - Returns - ------- - out_prob - The log posterior probabilities of each class ([batch, N_class]) - score: - It is the value of the log-posterior for the best class ([batch,]) - index - The indexes of the best class ([batch,]) - text_lab: - List with the text labels corresponding to the indexes. - (label encoder should be provided). - """ - waveform = self.load_audio(path) - # Fake a batch: - batch = waveform.unsqueeze(0) - rel_length = torch.tensor([1.0]) - emb = self.encode_batch(batch, rel_length) - out_prob = self.modules.classifier(emb).squeeze(1) - score, index = torch.max(out_prob, dim=-1) - text_lab = self.hparams.label_encoder.decode_torch(index) - return out_prob, score, index, text_lab - - -class SpeakerRecognition(EncoderClassifier): - """A ready-to-use model for speaker recognition. It can be used to - perform speaker verification with verify_batch(). - - ``` - Example - ------- - >>> import torchaudio - >>> from speechbrain.pretrained import SpeakerRecognition - >>> # Model is downloaded from the speechbrain HuggingFace repo - >>> tmpdir = getfixture("tmpdir") - >>> verification = SpeakerRecognition.from_hparams( - ... source="speechbrain/spkrec-ecapa-voxceleb", - ... savedir=tmpdir, - ... ) - - >>> # Perform verification - >>> signal, fs = torchaudio.load("samples/audio_samples/example1.wav") - >>> signal2, fs = torchaudio.load("samples/audio_samples/example2.flac") - >>> score, prediction = verification.verify_batch(signal, signal2) - """ - - MODULES_NEEDED = [ - "compute_features", - "mean_var_norm", - "embedding_model", - "mean_var_norm_emb", - ] - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.similarity = torch.nn.CosineSimilarity(dim=-1, eps=1e-6) - - def verify_batch( - self, wavs1, wavs2, wav1_lens=None, wav2_lens=None, threshold=0.25 - ): - """Performs speaker verification with cosine distance. - - It returns the score and the decision (0 different speakers, - 1 same speakers). - - Arguments - --------- - wavs1 : Torch.Tensor - Tensor containing the speech waveform1 (batch, time). - Make sure the sample rate is fs=16000 Hz. - wavs2 : Torch.Tensor - Tensor containing the speech waveform2 (batch, time). - Make sure the sample rate is fs=16000 Hz. - wav1_lens: Torch.Tensor - Tensor containing the relative length for each sentence - in the length (e.g., [0.8 0.6 1.0]) - wav2_lens: Torch.Tensor - Tensor containing the relative length for each sentence - in the length (e.g., [0.8 0.6 1.0]) - threshold: Float - Threshold applied to the cosine distance to decide if the - speaker is different (0) or the same (1). - - Returns - ------- - score - The score associated to the binary verification output - (cosine distance). - prediction - The prediction is 1 if the two signals in input are from the same - speaker and 0 otherwise. - """ - emb1 = self.encode_batch(wavs1, wav1_lens, normalize=True) - emb2 = self.encode_batch(wavs2, wav2_lens, normalize=True) - score = self.similarity(emb1, emb2) - return score, score > threshold - - def verify_files(self, path_x, path_y): - """Speaker verification with cosine distance - - Returns the score and the decision (0 different speakers, - 1 same speakers). - - Returns - ------- - score - The score associated to the binary verification output - (cosine distance). - prediction - The prediction is 1 if the two signals in input are from the same - speaker and 0 otherwise. - """ - waveform_x = self.load_audio(path_x) - waveform_y = self.load_audio(path_y) - # Fake batches: - batch_x = waveform_x.unsqueeze(0) - batch_y = waveform_y.unsqueeze(0) - # Verify: - score, decision = self.verify_batch(batch_x, batch_y) - # Squeeze: - return score[0], decision[0] - - -class SepformerSeparation(Pretrained): - """A "ready-to-use" speech separation model. - - Uses Sepformer architecture. - - Example - ------- - >>> tmpdir = getfixture("tmpdir") - >>> model = SepformerSeparation.from_hparams( - ... source="speechbrain/sepformer-wsj02mix", - ... savedir=tmpdir) - >>> mix = torch.randn(1, 400) - >>> est_sources = model.separate_batch(mix) - >>> print(est_sources.shape) - torch.Size([1, 400, 2]) - """ - - MODULES_NEEDED = ["encoder", "masknet", "decoder"] - - def separate_batch(self, mix): - """Run source separation on batch of audio. - - Arguments - --------- - mix : torch.tensor - The mixture of sources. - - Returns - ------- - tensor - Separated sources - """ - - # Separation - mix = mix.to(self.device) - mix_w = self.modules.encoder(mix) - est_mask = self.modules.masknet(mix_w) - mix_w = torch.stack([mix_w] * self.hparams.num_spks) - sep_h = mix_w * est_mask - - # Decoding - est_source = torch.cat( - [ - self.modules.decoder(sep_h[i]).unsqueeze(-1) - for i in range(self.hparams.num_spks) - ], - dim=-1, - ) - - # T changed after conv1d in encoder, fix it here - T_origin = mix.size(1) - T_est = est_source.size(1) - if T_origin > T_est: - est_source = F.pad(est_source, (0, 0, 0, T_origin - T_est)) - else: - est_source = est_source[:, :T_origin, :] - return est_source - - def separate_file(self, path, savedir="."): - """Separate sources from file. - - Arguments - --------- - path : str - Path to file which has a mixture of sources. It can be a local - path, a web url, or a huggingface repo. - savedir : path - Path where to store the wav signals (when downloaded from the web). - Returns - ------- - tensor - Separated sources - """ - source, fl = split_path(path) - path = fetch(fl, source=source, savedir=savedir) - - batch, fs_file = torchaudio.load(path) - batch = batch.to(self.device) - fs_model = self.hparams.sample_rate - - # resample the data if needed - if fs_file != fs_model: - print( - "Resampling the audio from {} Hz to {} Hz".format( - fs_file, fs_model - ) - ) - tf = torchaudio.transforms.Resample( - orig_freq=fs_file, new_freq=fs_model - ) - batch = batch.mean(dim=0, keepdim=True) - batch = tf(batch) - - est_sources = self.separate_batch(batch) - est_sources = est_sources / est_sources.max(dim=1, keepdim=True)[0] - return est_sources - - -class SpectralMaskEnhancement(Pretrained): - """A ready-to-use model for speech enhancement. - - Arguments - --------- - See ``Pretrained``. - - Example - ------- - >>> import torchaudio - >>> from speechbrain.pretrained import SpectralMaskEnhancement - >>> # Model is downloaded from the speechbrain HuggingFace repo - >>> tmpdir = getfixture("tmpdir") - >>> enhancer = SpectralMaskEnhancement.from_hparams( - ... source="speechbrain/mtl-mimic-voicebank", - ... savedir=tmpdir, - ... ) - >>> noisy, fs = torchaudio.load("samples/audio_samples/example_noisy.wav") - >>> # Channel dimension is interpreted as batch dimension here - >>> enhanced = enhancer.enhance_batch(noisy) - """ - - HPARAMS_NEEDED = ["compute_stft", "spectral_magnitude", "resynth"] - MODULES_NEEDED = ["enhance_model"] - - def compute_features(self, wavs): - """Compute the log spectral magnitude features for masking. - - Arguments - --------- - wavs : torch.tensor - A batch of waveforms to convert to log spectral mags. - """ - feats = self.hparams.compute_stft(wavs) - feats = self.hparams.spectral_magnitude(feats) - return torch.log1p(feats) - - def enhance_batch(self, noisy, lengths=None): - """Enhance a batch of noisy waveforms. - - Arguments - --------- - noisy : torch.tensor - A batch of waveforms to perform enhancement on. - lengths : torch.tensor - The lengths of the waveforms if the enhancement model handles them. - - Returns - ------- - torch.tensor - A batch of enhanced waveforms of the same shape as input. - """ - noisy = noisy.to(self.device) - noisy_features = self.compute_features(noisy) - - # Perform masking-based enhancement, multiplying output with input. - if lengths is not None: - mask = self.modules.enhance_model(noisy_features, lengths=lengths) - else: - mask = self.modules.enhance_model(noisy_features) - enhanced = torch.mul(mask, noisy_features) - - # Return resynthesized waveforms - return self.hparams.resynth(torch.expm1(enhanced), noisy) - - def enhance_file(self, filename, output_filename=None): - """Enhance a wav file. - - Arguments - --------- - filename : str - Location on disk to load file for enhancement. - output_filename : str - If provided, writes enhanced data to this file. - """ - noisy = self.load_audio(filename) - noisy = noisy.to(self.device) - - # Fake a batch: - batch = noisy.unsqueeze(0) - enhanced = self.enhance_batch(batch) - - if output_filename is not None: - torchaudio.save(output_filename, enhanced, channels_first=False) - - return enhanced.squeeze(0) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +"""Defines interfaces for simple inference with pretrained models + +Authors: + * Aku Rouhe 2021 + * Peter Plantinga 2021 + * Loren Lugosch 2020 + * Mirco Ravanelli 2020 + * Titouan Parcollet 2021 +""" +import torch +import torchaudio +from types import SimpleNamespace +from torch.nn import SyncBatchNorm +from torch.nn import DataParallel as DP +from hyperpyyaml import load_hyperpyyaml +from speechbrain.pretrained.fetching import fetch +from speechbrain.dataio.preprocess import AudioNormalizer +import torch.nn.functional as F +from torch.nn.parallel import DistributedDataParallel as DDP +from speechbrain.utils.data_utils import split_path +from speechbrain.utils.distributed import run_on_main + + +class Pretrained: + """Takes a trained model and makes predictions on new data. + + This is a base class which handles some common boilerplate. + It intentionally has an interface similar to ``Brain`` - these base + classes handle similar things. + + Subclasses of Pretrained should implement the actual logic of how + the pretrained system runs, and add methods with descriptive names + (e.g. transcribe_file() for ASR). + + Arguments + --------- + modules : dict of str:torch.nn.Module pairs + The Torch modules that make up the learned system. These can be treated + in special ways (put on the right device, frozen, etc.) + hparams : dict + Each key:value pair should consist of a string key and a hyperparameter + that is used within the overridden methods. These will + be accessible via an ``hparams`` attribute, using "dot" notation: + e.g., self.hparams.model(x). + run_opts : dict + Options parsed from command line. See ``speechbrain.parse_arguments()``. + List that are supported here: + * device + * data_parallel_count + * data_parallel_backend + * distributed_launch + * distributed_backend + * jit_module_keys + freeze_params : bool + To freeze (requires_grad=False) parameters or not. Normally in inference + you want to freeze the params. Also calls .eval() on all modules. + """ + + HPARAMS_NEEDED = [] + MODULES_NEEDED = [] + + def __init__( + self, modules=None, hparams=None, run_opts=None, freeze_params=True + ): + + # Arguments passed via the run opts dictionary. Set a limited + # number of these, since some don't apply to inference. + run_opt_defaults = { + "device": "cpu", + "data_parallel_count": -1, + "data_parallel_backend": False, + "distributed_launch": False, + "distributed_backend": "nccl", + "jit_module_keys": None, + } + for arg, default in run_opt_defaults.items(): + if run_opts is not None and arg in run_opts: + setattr(self, arg, run_opts[arg]) + else: + # If any arg from run_opt_defaults exist in hparams and + # not in command line args "run_opts" + if hparams is not None and arg in hparams: + setattr(self, arg, hparams[arg]) + else: + setattr(self, arg, default) + + # Put modules on the right device, accessible with dot notation + self.modules = torch.nn.ModuleDict(modules) + for mod in self.modules: + self.modules[mod].to(self.device) + + for mod in self.MODULES_NEEDED: + if mod not in modules: + raise ValueError(f"Need modules['{mod}']") + + # Check MODULES_NEEDED and HPARAMS_NEEDED and + # make hyperparams available with dot notation + if self.HPARAMS_NEEDED and hparams is None: + raise ValueError("Need to provide hparams dict.") + if hparams is not None: + # Also first check that all required params are found: + for hp in self.HPARAMS_NEEDED: + if hp not in hparams: + raise ValueError(f"Need hparams['{hp}']") + self.hparams = SimpleNamespace(**hparams) + + # Prepare modules for computation, e.g. jit + self._prepare_modules(freeze_params) + + # Audio normalization + self.audio_normalizer = hparams.get( + "audio_normalizer", AudioNormalizer() + ) + + def _prepare_modules(self, freeze_params): + """Prepare modules for computation, e.g. jit. + + Arguments + --------- + freeze_params : bool + Whether to freeze the parameters and call ``eval()``. + """ + + # Make jit-able + self._compile_jit() + self._wrap_distributed() + + # If we don't want to backprop, freeze the pretrained parameters + if freeze_params: + self.modules.eval() + for p in self.modules.parameters(): + p.requires_grad = False + + def load_audio(self, path, savedir="."): + """Load an audio file with this model"s input spec + + When using a speech model, it is important to use the same type of data, + as was used to train the model. This means for example using the same + sampling rate and number of channels. It is, however, possible to + convert a file from a higher sampling rate to a lower one (downsampling). + Similarly, it is simple to downmix a stereo file to mono. + The path can be a local path, a web url, or a link to a huggingface repo. + """ + source, fl = split_path(path) + path = fetch(fl, source=source, savedir=savedir) + signal, sr = torchaudio.load(path, channels_first=False) + return self.audio_normalizer(signal, sr) + + def _compile_jit(self): + """Compile requested modules with ``torch.jit.script``.""" + if self.jit_module_keys is None: + return + + for name in self.jit_module_keys: + if name not in self.modules: + raise ValueError( + "module " + name + " cannot be jit compiled because " + "it is not defined in your hparams file." + ) + module = torch.jit.script(self.modules[name]) + self.modules[name] = module.to(self.device) + + def _wrap_distributed(self): + """Wrap modules with distributed wrapper when requested.""" + if not self.distributed_launch and not self.data_parallel_backend: + return + elif self.distributed_launch: + for name, module in self.modules.items(): + if any(p.requires_grad for p in module.parameters()): + # for ddp, all module must run on same GPU + module = SyncBatchNorm.convert_sync_batchnorm(module) + module = DDP(module, device_ids=[self.device]) + self.modules[name] = module + else: + # data_parallel_backend + for name, module in self.modules.items(): + if any(p.requires_grad for p in module.parameters()): + # if distributed_count = -1 then use all gpus + # otherwise, specify the set of gpu to use + if self.data_parallel_count == -1: + module = DP(module) + else: + module = DP( + module, + [i for i in range(self.data_parallel_count)], + ) + self.modules[name] = module + + @classmethod + def from_hparams( + cls, + source, + hparams_file="hyperparams.yaml", + overrides={}, + savedir=None, + use_auth_token=False, + **kwargs, + ): + """Fetch and load based from outside source based on HyperPyYAML file + + The source can be a location on the filesystem or online/huggingface + + The hyperparams file should contain a "modules" key, which is a + dictionary of torch modules used for computation. + + The hyperparams file should contain a "pretrainer" key, which is a + speechbrain.utils.parameter_transfer.Pretrainer + + Arguments + --------- + source : str + The location to use for finding the model. See + ``speechbrain.pretrained.fetching.fetch`` for details. + hparams_file : str + The name of the hyperparameters file to use for constructing + the modules necessary for inference. Must contain two keys: + "modules" and "pretrainer", as described. + overrides : dict + Any changes to make to the hparams file when it is loaded. + savedir : str or Path + Where to put the pretraining material. If not given, will use + ./pretrained_models/-hash(source). + use_auth_token : bool (default: False) + If true Hugginface's auth_token will be used to load private models from the HuggingFace Hub, + default is False because majority of models are public. + """ + if savedir is None: + clsname = cls.__name__ + savedir = f"./pretrained_models/{clsname}-{hash(source)}" + hparams_local_path = fetch( + hparams_file, source, savedir, use_auth_token + ) + + # Load the modules: + with open(hparams_local_path) as fin: + hparams = load_hyperpyyaml(fin, overrides) + + # Pretraining: + pretrainer = hparams["pretrainer"] + pretrainer.set_collect_in(savedir) + # For distributed setups, have this here: + run_on_main(pretrainer.collect_files, kwargs={"default_source": source}) + # Load on the CPU. Later the params can be moved elsewhere by specifying + # run_opts={"device": ...} + pretrainer.load_collected(device="cpu") + + # Now return the system + return cls(hparams["modules"], hparams, **kwargs) + + +class EndToEndSLU(Pretrained): + """A end-to-end SLU model. + + The class can be used either to run only the encoder (encode()) to extract + features or to run the entire model (decode()) to map the speech to its semantics. + + Example + ------- + >>> from speechbrain.pretrained import EndToEndSLU + >>> tmpdir = getfixture("tmpdir") + >>> slu_model = EndToEndSLU.from_hparams( + ... source="speechbrain/slu-timers-and-such-direct-librispeech-asr", + ... savedir=tmpdir, + ... ) + >>> slu_model.decode_file("samples/audio_samples/example6.wav") + "{'intent': 'SimpleMath', 'slots': {'number1': 37.67, 'number2': 75.7, 'op': ' minus '}}" + """ + + HPARAMS_NEEDED = ["tokenizer", "asr_model_source"] + MODULES_NEEDED = [ + "slu_enc", + "beam_searcher", + ] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.tokenizer = self.hparams.tokenizer + self.asr_model = EncoderDecoderASR.from_hparams( + source=self.hparams.asr_model_source, + run_opts={"device": self.device}, + ) + + def decode_file(self, path): + """Maps the given audio file to a string representing the + semantic dictionary for the utterance. + + Arguments + --------- + path : str + Path to audio file to decode. + + Returns + ------- + str + The predicted semantics. + """ + waveform = self.load_audio(path) + waveform = waveform.to(self.device) + # Fake a batch: + batch = waveform.unsqueeze(0) + rel_length = torch.tensor([1.0]) + predicted_words, predicted_tokens = self.decode_batch(batch, rel_length) + return predicted_words[0] + + def encode_batch(self, wavs, wav_lens): + """Encodes the input audio into a sequence of hidden states + + Arguments + --------- + wavs : torch.tensor + Batch of waveforms [batch, time, channels] or [batch, time] + depending on the model. + wav_lens : torch.tensor + Lengths of the waveforms relative to the longest one in the + batch, tensor of shape [batch]. The longest one should have + relative length 1.0 and others len(waveform) / max_length. + Used for ignoring padding. + + Returns + ------- + torch.tensor + The encoded batch + """ + wavs = wavs.float() + wavs, wav_lens = wavs.to(self.device), wav_lens.to(self.device) + with torch.no_grad(): + ASR_encoder_out = self.asr_model.encode_batch( + wavs.detach(), wav_lens + ) + encoder_out = self.modules.slu_enc(ASR_encoder_out) + return encoder_out + + def decode_batch(self, wavs, wav_lens): + """Maps the input audio to its semantics + + Arguments + --------- + wavs : torch.tensor + Batch of waveforms [batch, time, channels] or [batch, time] + depending on the model. + wav_lens : torch.tensor + Lengths of the waveforms relative to the longest one in the + batch, tensor of shape [batch]. The longest one should have + relative length 1.0 and others len(waveform) / max_length. + Used for ignoring padding. + + Returns + ------- + list + Each waveform in the batch decoded. + tensor + Each predicted token id. + """ + with torch.no_grad(): + wavs, wav_lens = wavs.to(self.device), wav_lens.to(self.device) + encoder_out = self.encode_batch(wavs, wav_lens) + predicted_tokens, scores = self.modules.beam_searcher( + encoder_out, wav_lens + ) + predicted_words = [ + self.tokenizer.decode_ids(token_seq) + for token_seq in predicted_tokens + ] + return predicted_words, predicted_tokens + + +class EncoderDecoderASR(Pretrained): + """A ready-to-use Encoder-Decoder ASR model + + The class can be used either to run only the encoder (encode()) to extract + features or to run the entire encoder-decoder model + (transcribe()) to transcribe speech. The given YAML must contains the fields + specified in the *_NEEDED[] lists. + + Example + ------- + >>> from speechbrain.pretrained import EncoderDecoderASR + >>> tmpdir = getfixture("tmpdir") + >>> asr_model = EncoderDecoderASR.from_hparams( + ... source="speechbrain/asr-crdnn-rnnlm-librispeech", + ... savedir=tmpdir, + ... ) + >>> asr_model.transcribe_file("samples/audio_samples/example2.flac") + "MY FATHER HAS REVEALED THE CULPRIT'S NAME" + """ + + HPARAMS_NEEDED = ["tokenizer"] + MODULES_NEEDED = [ + "encoder", + "decoder", + ] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.tokenizer = self.hparams.tokenizer + + def transcribe_file(self, path): + """Transcribes the given audiofile into a sequence of words. + + Arguments + --------- + path : str + Path to audio file which to transcribe. + + Returns + ------- + str + The audiofile transcription produced by this ASR system. + """ + waveform = self.load_audio(path) + # Fake a batch: + batch = waveform.unsqueeze(0) + rel_length = torch.tensor([1.0]) + predicted_words, predicted_tokens = self.transcribe_batch( + batch, rel_length + ) + return predicted_words[0] + + def encode_batch(self, wavs, wav_lens): + """Encodes the input audio into a sequence of hidden states + + The waveforms should already be in the model's desired format. + You can call: + ``normalized = EncoderDecoderASR.normalizer(signal, sample_rate)`` + to get a correctly converted signal in most cases. + + Arguments + --------- + wavs : torch.tensor + Batch of waveforms [batch, time, channels] or [batch, time] + depending on the model. + wav_lens : torch.tensor + Lengths of the waveforms relative to the longest one in the + batch, tensor of shape [batch]. The longest one should have + relative length 1.0 and others len(waveform) / max_length. + Used for ignoring padding. + + Returns + ------- + torch.tensor + The encoded batch + """ + wavs = wavs.float() + wavs, wav_lens = wavs.to(self.device), wav_lens.to(self.device) + encoder_out = self.modules.encoder(wavs, wav_lens) + return encoder_out + + def transcribe_batch(self, wavs, wav_lens): + """Transcribes the input audio into a sequence of words + + The waveforms should already be in the model's desired format. + You can call: + ``normalized = EncoderDecoderASR.normalizer(signal, sample_rate)`` + to get a correctly converted signal in most cases. + + Arguments + --------- + wavs : torch.tensor + Batch of waveforms [batch, time, channels] or [batch, time] + depending on the model. + wav_lens : torch.tensor + Lengths of the waveforms relative to the longest one in the + batch, tensor of shape [batch]. The longest one should have + relative length 1.0 and others len(waveform) / max_length. + Used for ignoring padding. + + Returns + ------- + list + Each waveform in the batch transcribed. + tensor + Each predicted token id. + """ + with torch.no_grad(): + wav_lens = wav_lens.to(self.device) + encoder_out = self.encode_batch(wavs, wav_lens) + predicted_tokens, scores = self.modules.decoder( + encoder_out, wav_lens + ) + predicted_words = [ + self.tokenizer.decode_ids(token_seq) + for token_seq in predicted_tokens + ] + return predicted_words, predicted_tokens + + +class EncoderClassifier(Pretrained): + """A ready-to-use class for utterance-level classification (e.g, speaker-id, + language-id, emotion recognition, keyword spotting, etc). + + The class assumes that an encoder called "embedding_model" and a model + called "classifier" are defined in the yaml file. If you want to + convert the predicted index into a corresponding text label, please + provide the path of the label_encoder in a variable called 'lab_encoder_file' + within the yaml. + + The class can be used either to run only the encoder (encode_batch()) to + extract embeddings or to run a classification step (classify_batch()). + ``` + + Example + ------- + >>> import torchaudio + >>> from speechbrain.pretrained import EncoderClassifier + >>> # Model is downloaded from the speechbrain HuggingFace repo + >>> tmpdir = getfixture("tmpdir") + >>> classifier = EncoderClassifier.from_hparams( + ... source="speechbrain/spkrec-ecapa-voxceleb", + ... savedir=tmpdir, + ... ) + + >>> # Compute embeddings + >>> signal, fs = torchaudio.load("samples/audio_samples/example1.wav") + >>> embeddings = classifier.encode_batch(signal) + + >>> # Classification + >>> prediction = classifier .classify_batch(signal) + """ + + MODULES_NEEDED = [ + "compute_features", + "mean_var_norm", + "embedding_model", + "classifier", + ] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def extract_feats(self, wavs, wav_lens=None): + # wav to feats + wavs = wavs.to('cpu').float() + if wav_lens is None: + wav_lens = torch.ones(wavs.shape[0], device='cpu') + + feats = self.modules.compute_features(wavs) + feats = self.modules.mean_var_norm(feats, wav_lens) + + return feats + + def feats_classify(self, feats, wav_lens=None): + emb = self.modules.embedding_model(feats, wav_lens) + out_prob = self.modules.classifier(emb).squeeze(1) + + return out_prob + + def encode_batch(self, wavs, wav_lens=None, normalize=False): + """Encodes the input audio into a single vector embedding. + + The waveforms should already be in the model's desired format. + You can call: + ``normalized = .normalizer(signal, sample_rate)`` + to get a correctly converted signal in most cases. + + Arguments + --------- + wavs : torch.tensor + Batch of waveforms [batch, time, channels] or [batch, time] + depending on the model. Make sure the sample rate is fs=16000 Hz. + wav_lens : torch.tensor + Lengths of the waveforms relative to the longest one in the + batch, tensor of shape [batch]. The longest one should have + relative length 1.0 and others len(waveform) / max_length. + Used for ignoring padding. + normalize : bool + If True, it normalizes the embeddings with the statistics + contained in mean_var_norm_emb. + + Returns + ------- + torch.tensor + The encoded batch + """ + # Manage single waveforms in input + if len(wavs.shape) == 1: + wavs = wavs.unsqueeze(0) + + # Assign full length if wav_lens is not assigned + if wav_lens is None: + wav_lens = torch.ones(wavs.shape[0], device=self.device) + + # Storing waveform in the specified device + wavs, wav_lens = wavs.to(self.device), wav_lens.to(self.device) + wavs = wavs.float() + + # Computing features and embeddings + feats = self.modules.compute_features(wavs) + feats = self.modules.mean_var_norm(feats, wav_lens) + embeddings = self.modules.embedding_model(feats, wav_lens) + if normalize: + embeddings = self.hparams.mean_var_norm_emb( + embeddings, torch.ones(embeddings.shape[0], device=self.device) + ) + return embeddings + + def classify_batch(self, wavs, wav_lens=None): + """Performs classification on the top of the encoded features. + + It returns the posterior probabilities, the index and, if the label + encoder is specified it also the text label. + + Arguments + --------- + wavs : torch.tensor + Batch of waveforms [batch, time, channels] or [batch, time] + depending on the model. Make sure the sample rate is fs=16000 Hz. + wav_lens : torch.tensor + Lengths of the waveforms relative to the longest one in the + batch, tensor of shape [batch]. The longest one should have + relative length 1.0 and others len(waveform) / max_length. + Used for ignoring padding. + + Returns + ------- + out_prob + The log posterior probabilities of each class ([batch, N_class]) + score: + It is the value of the log-posterior for the best class ([batch,]) + index + The indexes of the best class ([batch,]) + text_lab: + List with the text labels corresponding to the indexes. + (label encoder should be provided). + """ + emb = self.encode_batch(wavs, wav_lens) + out_prob = self.modules.classifier(emb).squeeze(1) + score, index = torch.max(out_prob, dim=-1) + text_lab = self.hparams.label_encoder.decode_torch(index) + return out_prob, score, index, text_lab + + def classify_file(self, path): + """Classifies the given audiofile into the given set of labels. + + Arguments + --------- + path : str + Path to audio file to classify. + + Returns + ------- + out_prob + The log posterior probabilities of each class ([batch, N_class]) + score: + It is the value of the log-posterior for the best class ([batch,]) + index + The indexes of the best class ([batch,]) + text_lab: + List with the text labels corresponding to the indexes. + (label encoder should be provided). + """ + waveform = self.load_audio(path) + # Fake a batch: + batch = waveform.unsqueeze(0) + rel_length = torch.tensor([1.0]) + emb = self.encode_batch(batch, rel_length) + out_prob = self.modules.classifier(emb).squeeze(1) + score, index = torch.max(out_prob, dim=-1) + text_lab = self.hparams.label_encoder.decode_torch(index) + return out_prob, score, index, text_lab + + +class SpeakerRecognition(EncoderClassifier): + """A ready-to-use model for speaker recognition. It can be used to + perform speaker verification with verify_batch(). + + ``` + Example + ------- + >>> import torchaudio + >>> from speechbrain.pretrained import SpeakerRecognition + >>> # Model is downloaded from the speechbrain HuggingFace repo + >>> tmpdir = getfixture("tmpdir") + >>> verification = SpeakerRecognition.from_hparams( + ... source="speechbrain/spkrec-ecapa-voxceleb", + ... savedir=tmpdir, + ... ) + + >>> # Perform verification + >>> signal, fs = torchaudio.load("samples/audio_samples/example1.wav") + >>> signal2, fs = torchaudio.load("samples/audio_samples/example2.flac") + >>> score, prediction = verification.verify_batch(signal, signal2) + """ + + MODULES_NEEDED = [ + "compute_features", + "mean_var_norm", + "embedding_model", + "mean_var_norm_emb", + ] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.similarity = torch.nn.CosineSimilarity(dim=-1, eps=1e-6) + + def verify_batch( + self, wavs1, wavs2, wav1_lens=None, wav2_lens=None, threshold=0.25 + ): + """Performs speaker verification with cosine distance. + + It returns the score and the decision (0 different speakers, + 1 same speakers). + + Arguments + --------- + wavs1 : Torch.Tensor + Tensor containing the speech waveform1 (batch, time). + Make sure the sample rate is fs=16000 Hz. + wavs2 : Torch.Tensor + Tensor containing the speech waveform2 (batch, time). + Make sure the sample rate is fs=16000 Hz. + wav1_lens: Torch.Tensor + Tensor containing the relative length for each sentence + in the length (e.g., [0.8 0.6 1.0]) + wav2_lens: Torch.Tensor + Tensor containing the relative length for each sentence + in the length (e.g., [0.8 0.6 1.0]) + threshold: Float + Threshold applied to the cosine distance to decide if the + speaker is different (0) or the same (1). + + Returns + ------- + score + The score associated to the binary verification output + (cosine distance). + prediction + The prediction is 1 if the two signals in input are from the same + speaker and 0 otherwise. + """ + emb1 = self.encode_batch(wavs1, wav1_lens, normalize=True) + emb2 = self.encode_batch(wavs2, wav2_lens, normalize=True) + score = self.similarity(emb1, emb2) + return score, score > threshold + + def verify_files(self, path_x, path_y): + """Speaker verification with cosine distance + + Returns the score and the decision (0 different speakers, + 1 same speakers). + + Returns + ------- + score + The score associated to the binary verification output + (cosine distance). + prediction + The prediction is 1 if the two signals in input are from the same + speaker and 0 otherwise. + """ + waveform_x = self.load_audio(path_x) + waveform_y = self.load_audio(path_y) + # Fake batches: + batch_x = waveform_x.unsqueeze(0) + batch_y = waveform_y.unsqueeze(0) + # Verify: + score, decision = self.verify_batch(batch_x, batch_y) + # Squeeze: + return score[0], decision[0] + + +class SepformerSeparation(Pretrained): + """A "ready-to-use" speech separation model. + + Uses Sepformer architecture. + + Example + ------- + >>> tmpdir = getfixture("tmpdir") + >>> model = SepformerSeparation.from_hparams( + ... source="speechbrain/sepformer-wsj02mix", + ... savedir=tmpdir) + >>> mix = torch.randn(1, 400) + >>> est_sources = model.separate_batch(mix) + >>> print(est_sources.shape) + torch.Size([1, 400, 2]) + """ + + MODULES_NEEDED = ["encoder", "masknet", "decoder"] + + def separate_batch(self, mix): + """Run source separation on batch of audio. + + Arguments + --------- + mix : torch.tensor + The mixture of sources. + + Returns + ------- + tensor + Separated sources + """ + + # Separation + mix = mix.to(self.device) + mix_w = self.modules.encoder(mix) + est_mask = self.modules.masknet(mix_w) + mix_w = torch.stack([mix_w] * self.hparams.num_spks) + sep_h = mix_w * est_mask + + # Decoding + est_source = torch.cat( + [ + self.modules.decoder(sep_h[i]).unsqueeze(-1) + for i in range(self.hparams.num_spks) + ], + dim=-1, + ) + + # T changed after conv1d in encoder, fix it here + T_origin = mix.size(1) + T_est = est_source.size(1) + if T_origin > T_est: + est_source = F.pad(est_source, (0, 0, 0, T_origin - T_est)) + else: + est_source = est_source[:, :T_origin, :] + return est_source + + def separate_file(self, path, savedir="."): + """Separate sources from file. + + Arguments + --------- + path : str + Path to file which has a mixture of sources. It can be a local + path, a web url, or a huggingface repo. + savedir : path + Path where to store the wav signals (when downloaded from the web). + Returns + ------- + tensor + Separated sources + """ + source, fl = split_path(path) + path = fetch(fl, source=source, savedir=savedir) + + batch, fs_file = torchaudio.load(path) + batch = batch.to(self.device) + fs_model = self.hparams.sample_rate + + # resample the data if needed + if fs_file != fs_model: + print( + "Resampling the audio from {} Hz to {} Hz".format( + fs_file, fs_model + ) + ) + tf = torchaudio.transforms.Resample( + orig_freq=fs_file, new_freq=fs_model + ) + batch = batch.mean(dim=0, keepdim=True) + batch = tf(batch) + + est_sources = self.separate_batch(batch) + est_sources = est_sources / est_sources.max(dim=1, keepdim=True)[0] + return est_sources + + +class SpectralMaskEnhancement(Pretrained): + """A ready-to-use model for speech enhancement. + + Arguments + --------- + See ``Pretrained``. + + Example + ------- + >>> import torchaudio + >>> from speechbrain.pretrained import SpectralMaskEnhancement + >>> # Model is downloaded from the speechbrain HuggingFace repo + >>> tmpdir = getfixture("tmpdir") + >>> enhancer = SpectralMaskEnhancement.from_hparams( + ... source="speechbrain/mtl-mimic-voicebank", + ... savedir=tmpdir, + ... ) + >>> noisy, fs = torchaudio.load("samples/audio_samples/example_noisy.wav") + >>> # Channel dimension is interpreted as batch dimension here + >>> enhanced = enhancer.enhance_batch(noisy) + """ + + HPARAMS_NEEDED = ["compute_stft", "spectral_magnitude", "resynth"] + MODULES_NEEDED = ["enhance_model"] + + def compute_features(self, wavs): + """Compute the log spectral magnitude features for masking. + + Arguments + --------- + wavs : torch.tensor + A batch of waveforms to convert to log spectral mags. + """ + feats = self.hparams.compute_stft(wavs) + feats = self.hparams.spectral_magnitude(feats) + return torch.log1p(feats) + + def enhance_batch(self, noisy, lengths=None): + """Enhance a batch of noisy waveforms. + + Arguments + --------- + noisy : torch.tensor + A batch of waveforms to perform enhancement on. + lengths : torch.tensor + The lengths of the waveforms if the enhancement model handles them. + + Returns + ------- + torch.tensor + A batch of enhanced waveforms of the same shape as input. + """ + noisy = noisy.to(self.device) + noisy_features = self.compute_features(noisy) + + # Perform masking-based enhancement, multiplying output with input. + if lengths is not None: + mask = self.modules.enhance_model(noisy_features, lengths=lengths) + else: + mask = self.modules.enhance_model(noisy_features) + enhanced = torch.mul(mask, noisy_features) + + # Return resynthesized waveforms + return self.hparams.resynth(torch.expm1(enhanced), noisy) + + def enhance_file(self, filename, output_filename=None): + """Enhance a wav file. + + Arguments + --------- + filename : str + Location on disk to load file for enhancement. + output_filename : str + If provided, writes enhanced data to this file. + """ + noisy = self.load_audio(filename) + noisy = noisy.to(self.device) + + # Fake a batch: + batch = noisy.unsqueeze(0) + enhanced = self.enhance_batch(batch) + + if output_filename is not None: + torchaudio.save(output_filename, enhanced, channels_first=False) + + return enhanced.squeeze(0) diff --git a/ACL_PyTorch/contrib/audio/tdnn/modelzoo_level.txt b/ACL_PyTorch/contrib/audio/tdnn/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/ACL_PyTorch/contrib/audio/tdnn/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/audio/tdnn/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/audio/tdnn/om_infer.sh b/ACL_PyTorch/contrib/audio/tdnn/om_infer.sh index 499be09436..718f9f6a8e 100644 --- a/ACL_PyTorch/contrib/audio/tdnn/om_infer.sh +++ b/ACL_PyTorch/contrib/audio/tdnn/om_infer.sh @@ -1,23 +1,23 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - - - -install_path=/usr/local/Ascend/ascend-toolkit/latest -#export PYTHONUNBUFFERD=1 -#export PYTHONPATH=${install_path}/pyACL/python/site-packages/acl:$PYTHONPATH - -#export LD_LIBRARY_PATH=${install_path}/fwkacllib/lib64/:${install_path}/acllib/lib64/:${install_path}/atc/lib64/:$LD_LIBRARY_PATH - -python Tdnn_pyacl_infer.py --model_path=tdnn.om --device_id=0 --cpu_run=True --sync_infer=True --workspace=10 --input_info_file_path=mini_librispeech_test.info --input_dtypes=float32 --infer_res_save_path=result --res_save_type=bin +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + + + +install_path=/usr/local/Ascend/ascend-toolkit/latest +#export PYTHONUNBUFFERD=1 +#export PYTHONPATH=${install_path}/pyACL/python/site-packages/acl:$PYTHONPATH + +#export LD_LIBRARY_PATH=${install_path}/fwkacllib/lib64/:${install_path}/acllib/lib64/:${install_path}/atc/lib64/:$LD_LIBRARY_PATH + +python Tdnn_pyacl_infer.py --model_path=tdnn.om --device_id=0 --cpu_run=True --sync_infer=True --workspace=10 --input_info_file_path=mini_librispeech_test.info --input_dtypes=float32 --infer_res_save_path=result --res_save_type=bin diff --git a/ACL_PyTorch/contrib/audio/tdnn/requirements.txt b/ACL_PyTorch/contrib/audio/tdnn/requirements.txt index 902c74751a..f4e019b912 100644 --- a/ACL_PyTorch/contrib/audio/tdnn/requirements.txt +++ b/ACL_PyTorch/contrib/audio/tdnn/requirements.txt @@ -1,11 +1,11 @@ --r lint-requirements.txt -huggingface_hub>=0.0.6 -hyperpyyaml>=0.0.1 -joblib>=0.14.1 -numpy>=1.17.0 -packaging -pre-commit>=2.3.0 -scipy>=1.4.1 -sentencepiece>=0.1.91 -SoundFile; sys_platform == 'win32' -tqdm>=4.42.0 +-r lint-requirements.txt +huggingface_hub>=0.0.6 +hyperpyyaml>=0.0.1 +joblib>=0.14.1 +numpy>=1.17.0 +packaging +pre-commit>=2.3.0 +scipy>=1.4.1 +sentencepiece>=0.1.91 +SoundFile; sys_platform == 'win32' +tqdm>=4.42.0 diff --git a/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/3d_attention_net_pkl2onnx.py b/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/3d_attention_net_pkl2onnx.py index 9d15792a6e..5927f173e5 100644 --- a/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/3d_attention_net_pkl2onnx.py +++ b/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/3d_attention_net_pkl2onnx.py @@ -1,34 +1,34 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import torch.onnx -from model.residual_attention_network import ResidualAttentionModel_92_32input_update as ResidualAttentionModel - - -def pkl2onnx(input_file = "model_92_sgd.pkl", output_file = "3d_attention_net.onnx"): - model = ResidualAttentionModel() - model.load_state_dict((torch.load(input_file, map_location = "cpu"))) - model.eval() - input_name = ["image"] - output_name = ["class"] - dynamic_axes = {"image": {0:"-1"}, "class": {0:"-1"}} - dummy_input = torch.randn(1, 3, 32, 32) - torch.onnx.export(model, dummy_input, output_file, input_names = input_name, dynamic_axes = dynamic_axes, output_names = output_name, opset_version=11, verbose=True) - -if __name__ == "__main__": - print("----------start----------") - pkl2onnx() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import torch.onnx +from model.residual_attention_network import ResidualAttentionModel_92_32input_update as ResidualAttentionModel + + +def pkl2onnx(input_file = "model_92_sgd.pkl", output_file = "3d_attention_net.onnx"): + model = ResidualAttentionModel() + model.load_state_dict((torch.load(input_file, map_location = "cpu"))) + model.eval() + input_name = ["image"] + output_name = ["class"] + dynamic_axes = {"image": {0:"-1"}, "class": {0:"-1"}} + dummy_input = torch.randn(1, 3, 32, 32) + torch.onnx.export(model, dummy_input, output_file, input_names = input_name, dynamic_axes = dynamic_axes, output_names = output_name, opset_version=11, verbose=True) + +if __name__ == "__main__": + print("----------start----------") + pkl2onnx() print("----------end----------") \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/3d_attention_net_preprocess.py b/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/3d_attention_net_preprocess.py index 4b94690e34..4ce91ea226 100644 --- a/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/3d_attention_net_preprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/3d_attention_net_preprocess.py @@ -1,68 +1,68 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import torch -import numpy as np -from torch.utils.data import Dataset, DataLoader -import torchvision -from torchvision import transforms, datasets, models - -def preprocess(data_path = "./data/", save_path = "./pre_process_result/"): - # Image Preprocessing - transform = transforms.Compose([ - transforms.RandomHorizontalFlip(), - transforms.RandomCrop((32, 32), padding=4), #left, top, right, bottom - transforms.ToTensor() - ]) - test_transform = transforms.Compose([ - transforms.ToTensor() - ]) - # when image is rgb, totensor do the division 255 - # CIFAR-10 Dataset - train_dataset = datasets.CIFAR10(root=data_path, - train=True, - transform=transform, - download=True) - - test_dataset = datasets.CIFAR10(root=data_path, - train=False, - transform=test_transform) - - # Data Loader (Input Pipeline) - train_loader = torch.utils.data.DataLoader(dataset=train_dataset, - batch_size=64, # 64 - shuffle=True, num_workers=8) - test_loader = torch.utils.data.DataLoader(dataset=test_dataset, - batch_size=32, - shuffle=False) - - classes = ('plane', 'car', 'bird', 'cat', - 'deer', 'dog', 'frog', 'horse', 'ship', 'truck') - if not os.path.exists(save_path): - os.makedirs(save_path) - cnt = -1 - for images, labels in test_loader: - for i in range(len(images)): - cnt += 1 - image = images[i] - label = labels[i] - image = np.array(image).astype(np.float32) - image.tofile(f"{save_path}image_{cnt}.bin") - if(cnt % 100 == 9): - print(f"current: {cnt}") - -if __name__ == "__main__": +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import torch +import numpy as np +from torch.utils.data import Dataset, DataLoader +import torchvision +from torchvision import transforms, datasets, models + +def preprocess(data_path = "./data/", save_path = "./pre_process_result/"): + # Image Preprocessing + transform = transforms.Compose([ + transforms.RandomHorizontalFlip(), + transforms.RandomCrop((32, 32), padding=4), #left, top, right, bottom + transforms.ToTensor() + ]) + test_transform = transforms.Compose([ + transforms.ToTensor() + ]) + # when image is rgb, totensor do the division 255 + # CIFAR-10 Dataset + train_dataset = datasets.CIFAR10(root=data_path, + train=True, + transform=transform, + download=True) + + test_dataset = datasets.CIFAR10(root=data_path, + train=False, + transform=test_transform) + + # Data Loader (Input Pipeline) + train_loader = torch.utils.data.DataLoader(dataset=train_dataset, + batch_size=64, # 64 + shuffle=True, num_workers=8) + test_loader = torch.utils.data.DataLoader(dataset=test_dataset, + batch_size=32, + shuffle=False) + + classes = ('plane', 'car', 'bird', 'cat', + 'deer', 'dog', 'frog', 'horse', 'ship', 'truck') + if not os.path.exists(save_path): + os.makedirs(save_path) + cnt = -1 + for images, labels in test_loader: + for i in range(len(images)): + cnt += 1 + image = images[i] + label = labels[i] + image = np.array(image).astype(np.float32) + image.tofile(f"{save_path}image_{cnt}.bin") + if(cnt % 100 == 9): + print(f"current: {cnt}") + +if __name__ == "__main__": preprocess() \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/LICENSE b/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/LICENSE index b1fac45f02..989e2c59e9 100644 --- a/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/LICENSE @@ -1,201 +1,201 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/modelzoo_level.txt index 9e95396651..27e6c78b37 100644 --- a/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:POK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/readme.md b/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/readme.md index b7efb7ace2..db4cf57a7e 100644 --- a/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/readme.md +++ b/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/readme.md @@ -1,98 +1,98 @@ -# 一. 环境准备 -1. 安装必要的依赖,运行所需的依赖详见requirements.txt -2. 获取开源模型代码及权重文件 -``` -git clone https://github.com/tengshaofeng/ResidualAttentionNetwork-pytorch.git -cd ResidualAttentionNetwork-pytorch -git checkout 44d09fe9afc0d5fba6f3f63b8375069ae9d54a56 -cd Residual-Attention-Network -cp -r model ../.. -cp model_92_sgd.pkl ../.. -cd ../.. -``` -3. 由于python版本问题,原模型代码在执行过程中会出现数据类型转换问题,依次执行以下命令 -``` -cd model/ -patch -p1 <../3d_attention_net.patch -cd .. -``` - -4. 获取benchmark工具 - 将benchmark.x86_64放到当前目录。 -5. 获取OXInterface.py -``` -git clone https://gitee.com/zheng-wengang1/onnx_tools.git -cd onnx_tools -git checkout cbb099e5f2cef3d76c7630bffe0ee8250b03d921 -cd .. -``` - -# 二. 数据预处理 -1. 获取CIFAR-10数据集 -``` -website:https://www.cs.toronto.edu/~kriz/cifar.html -#Version:CIFAR-10 python version -#md5sum:c58f30108f718f92721af3b95e74349a -``` -2. 上传数据集 -``` -mkdir data -``` -3. 将下载的CIFAR-10数据集上传至data文件夹,而后执行如下命令: -``` -tar -zxvf data/cifar-10-python.tar.gz -C data/ -``` -4. 数据预处理 -``` -python3.7 3d_attention_net_preprocess.py -``` - -5. 生成预处理后的数据集信息文件 -``` -python3.7 gen_dataset_info.py bin ./pre_process_result/ ./3d_attention_net_prep_bin.info 32 32 -``` - -# 三. pkl文件转om模型 -1. 读取源代码仓中的pkl文件,将原始模型转换为onnx -``` -python3.7 3d_attention_net_pkl2onnx.py -``` - -2. 对onnx模型中的resize操作进行优化 -``` -python3.7 resize_optimize.py -``` - -3. 通过Autotune进行性能调优并转换为om模型 -``` -bash test/3d_attention_net_onnx2om.bash -``` - -# 四. om模型离线推理,性能及精度测试 -1. bs1离线推理测试 -``` -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=3d_attention_net_resize_autotune_optimized_bs1.om -input_text_path=3d_attention_net_prep_bin.info -input_width=32 -input_height=32 -output_binary=False -useDvpp=False -python3.7 3d_attention_net_postprocess.py 0 -``` -python3.7 3d_attention_net_postprocess.py $DEVICE_ID -传入的第一个参数DEVICE_ID为指定device的输出,应与benchmark传入的device_id保持一致,下同 - -2. bs16离线推理测试 -``` -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=16 -om_path=3d_attention_net_resize_autotune_optimized_bs16.om -input_text_path=3d_attention_net_prep_bin.info -input_width=32 -input_height=32 -output_binary=False -useDvpp=False -python3.7 3d_attention_net_postprocess.py 0 -``` - -3. GPU性能测试 -``` -bash perf_g.sh -``` - -4. 性能&精度对比 - - -|模型|官网pkl精度|310离线推理精度|基准性能|310性能|精度对比
(310/基准)|性能对比
(310/基准)| -|-|:-:|:-:|:-:|:-:|:-:|:-:| -|3d_attention_net_bs1|Top-1:95.4%|Top-1:95.34%|659.2fps|1479.5fps|99.94%|1479.5/659.2| -|3d_attention_net_bs16|Top-1:95.4%|Top-1:95.34%|3494.16fps|3980.4fps|99.94%|3980.4/3494.16| - +# 一. 环境准备 +1. 安装必要的依赖,运行所需的依赖详见requirements.txt +2. 获取开源模型代码及权重文件 +``` +git clone https://github.com/tengshaofeng/ResidualAttentionNetwork-pytorch.git +cd ResidualAttentionNetwork-pytorch +git checkout 44d09fe9afc0d5fba6f3f63b8375069ae9d54a56 +cd Residual-Attention-Network +cp -r model ../.. +cp model_92_sgd.pkl ../.. +cd ../.. +``` +3. 由于python版本问题,原模型代码在执行过程中会出现数据类型转换问题,依次执行以下命令 +``` +cd model/ +patch -p1 <../3d_attention_net.patch +cd .. +``` + +4. 获取benchmark工具 + 将benchmark.x86_64放到当前目录。 +5. 获取OXInterface.py +``` +git clone https://gitee.com/zheng-wengang1/onnx_tools.git +cd onnx_tools +git checkout cbb099e5f2cef3d76c7630bffe0ee8250b03d921 +cd .. +``` + +# 二. 数据预处理 +1. 获取CIFAR-10数据集 +``` +website:https://www.cs.toronto.edu/~kriz/cifar.html +#Version:CIFAR-10 python version +#md5sum:c58f30108f718f92721af3b95e74349a +``` +2. 上传数据集 +``` +mkdir data +``` +3. 将下载的CIFAR-10数据集上传至data文件夹,而后执行如下命令: +``` +tar -zxvf data/cifar-10-python.tar.gz -C data/ +``` +4. 数据预处理 +``` +python3.7 3d_attention_net_preprocess.py +``` + +5. 生成预处理后的数据集信息文件 +``` +python3.7 gen_dataset_info.py bin ./pre_process_result/ ./3d_attention_net_prep_bin.info 32 32 +``` + +# 三. pkl文件转om模型 +1. 读取源代码仓中的pkl文件,将原始模型转换为onnx +``` +python3.7 3d_attention_net_pkl2onnx.py +``` + +2. 对onnx模型中的resize操作进行优化 +``` +python3.7 resize_optimize.py +``` + +3. 通过Autotune进行性能调优并转换为om模型 +``` +bash test/3d_attention_net_onnx2om.bash +``` + +# 四. om模型离线推理,性能及精度测试 +1. bs1离线推理测试 +``` +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=3d_attention_net_resize_autotune_optimized_bs1.om -input_text_path=3d_attention_net_prep_bin.info -input_width=32 -input_height=32 -output_binary=False -useDvpp=False +python3.7 3d_attention_net_postprocess.py 0 +``` +python3.7 3d_attention_net_postprocess.py $DEVICE_ID +传入的第一个参数DEVICE_ID为指定device的输出,应与benchmark传入的device_id保持一致,下同 + +2. bs16离线推理测试 +``` +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=16 -om_path=3d_attention_net_resize_autotune_optimized_bs16.om -input_text_path=3d_attention_net_prep_bin.info -input_width=32 -input_height=32 -output_binary=False -useDvpp=False +python3.7 3d_attention_net_postprocess.py 0 +``` + +3. GPU性能测试 +``` +bash perf_g.sh +``` + +4. 性能&精度对比 + + +|模型|官网pkl精度|310离线推理精度|基准性能|310性能|精度对比
(310/基准)|性能对比
(310/基准)| +|-|:-:|:-:|:-:|:-:|:-:|:-:| +|3d_attention_net_bs1|Top-1:95.4%|Top-1:95.34%|659.2fps|1479.5fps|99.94%|1479.5/659.2| +|3d_attention_net_bs16|Top-1:95.4%|Top-1:95.34%|3494.16fps|3980.4fps|99.94%|3980.4/3494.16| + diff --git a/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/requirements.txt b/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/requirements.txt index a89309f620..ec79d9f308 100644 --- a/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/requirements.txt +++ b/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/requirements.txt @@ -1,6 +1,6 @@ -torch=1.8.1 -torchvision=0.9.0 -numpy=1.19.5 -glob2=0.7 -opencv-python=4.2.0.34 -onnx=1.8.1 +torch=1.8.1 +torchvision=0.9.0 +numpy=1.19.5 +glob2=0.7 +opencv-python=4.2.0.34 +onnx=1.8.1 diff --git a/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/resize_optimize.py b/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/resize_optimize.py index 426bc3a824..52fa75baf4 100644 --- a/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/resize_optimize.py +++ b/ACL_PyTorch/contrib/cv/classfication/3d_attention_net/resize_optimize.py @@ -1,39 +1,39 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import onnx -import numpy as np -from pprint import pprint -from onnx_tools.OXInterface.OXInterface import OXDataType, OXGraph, OXInitializer, OXNode - -oxgraph = OXGraph('3d_attention_net.onnx') -oxnode = oxgraph.get_oxnode_by_name('Resize_77') -oxnode.set_attribute(attr_name='coordinate_transformation_mode', attr_value="asymmetric") -oxnode.set_attribute(attr_name='mode', attr_value="nearest") - -oxnode = oxgraph.get_oxnode_by_name('Resize_96') -oxnode.set_attribute(attr_name='coordinate_transformation_mode', attr_value="asymmetric") -oxnode.set_attribute(attr_name='mode', attr_value="nearest") - -oxnode = oxgraph.get_oxnode_by_name('Resize_173') -oxnode.set_attribute(attr_name='coordinate_transformation_mode', attr_value="asymmetric") -oxnode.set_attribute(attr_name='mode', attr_value="nearest") - -oxnode = oxgraph.get_oxnode_by_name('Resize_241') -oxnode.set_attribute(attr_name='coordinate_transformation_mode', attr_value="asymmetric") -oxnode.set_attribute(attr_name='mode', attr_value="nearest") - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import onnx +import numpy as np +from pprint import pprint +from onnx_tools.OXInterface.OXInterface import OXDataType, OXGraph, OXInitializer, OXNode + +oxgraph = OXGraph('3d_attention_net.onnx') +oxnode = oxgraph.get_oxnode_by_name('Resize_77') +oxnode.set_attribute(attr_name='coordinate_transformation_mode', attr_value="asymmetric") +oxnode.set_attribute(attr_name='mode', attr_value="nearest") + +oxnode = oxgraph.get_oxnode_by_name('Resize_96') +oxnode.set_attribute(attr_name='coordinate_transformation_mode', attr_value="asymmetric") +oxnode.set_attribute(attr_name='mode', attr_value="nearest") + +oxnode = oxgraph.get_oxnode_by_name('Resize_173') +oxnode.set_attribute(attr_name='coordinate_transformation_mode', attr_value="asymmetric") +oxnode.set_attribute(attr_name='mode', attr_value="nearest") + +oxnode = oxgraph.get_oxnode_by_name('Resize_241') +oxnode.set_attribute(attr_name='coordinate_transformation_mode', attr_value="asymmetric") +oxnode.set_attribute(attr_name='mode', attr_value="nearest") + oxgraph.save_new_model('3d_attention_net_resize_optimized.onnx') \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/AlexNet/LICENSE b/ACL_PyTorch/contrib/cv/classfication/AlexNet/LICENSE index b1fac45f02..989e2c59e9 100644 --- a/ACL_PyTorch/contrib/cv/classfication/AlexNet/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/AlexNet/LICENSE @@ -1,201 +1,201 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/C3D/C3D_postprocess.py b/ACL_PyTorch/contrib/cv/classfication/C3D/C3D_postprocess.py index e2aefdbbe9..38cd64d13a 100644 --- a/ACL_PyTorch/contrib/cv/classfication/C3D/C3D_postprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/C3D/C3D_postprocess.py @@ -1,68 +1,68 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import json -import torch -import sys - - -result_dir = sys.argv[1] # result_dir:推理得到的输出文件夹 -label_dir = sys.argv[2] # label_dir:标注文件的路径 -json_dir = sys.argv[3] -result_dir = os.listdir(result_dir) - -# 处理annotation文件,得到一个label字典,key为类名称,value为类的索引 -# label = {'v_Skiing_g04_c03': '80', 'v_SoccerPenalty_g02_c04': '84', ......} -label = dict() -f = open(label_dir) -x = f.readlines() -f.close() -for i in range(len(x)): - class_name = x[i].split(' ')[0].split('/')[1] - class_idx = x[i].split(' ')[2].replace('\n', '').replace('\r', '') - label[class_name] = class_idx - -file_name = result_dir - -num_correct_top1 = 0 -num_total = len(file_name) - -# 统计top1正确的个数 -for file_idx in range(num_total): - x = file_name[file_idx] - f = open(os.path.join(sys.argv[1], x)) - score = f.readline().replace('\n', '').replace('\r', '').split(' ') # score:list[str] - score = score[0:1010] - score = [float(i) for i in score] - f.close() - s = [[], [], [], [], [], [], [], [], [], []] - for i in range(10): - s[i] = score[101*i:101*i + 101] # 对于score中的1010个分数,每隔101个将其取出放到s数组中 - cls_score = torch.tensor(s).mean(dim=0) # 对10个clips得到的输出结果求平均 - max_value = cls_score[0] - idx = 0 - for i in range(len(cls_score)): - if cls_score[i] >= max_value: - max_value = cls_score[i] - idx = i - if label[x.split('.')[0].replace('_1', '')] == str(idx): - num_correct_top1 += 1 - -top1_acc = num_correct_top1/num_total -result_dict = {"top1_acc": top1_acc} -print(result_dict) -json_str = json.dumps(result_dict) -with open(json_dir, 'w') as json_file: - json_file.write(json_str) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import json +import torch +import sys + + +result_dir = sys.argv[1] # result_dir:推理得到的输出文件夹 +label_dir = sys.argv[2] # label_dir:标注文件的路径 +json_dir = sys.argv[3] +result_dir = os.listdir(result_dir) + +# 处理annotation文件,得到一个label字典,key为类名称,value为类的索引 +# label = {'v_Skiing_g04_c03': '80', 'v_SoccerPenalty_g02_c04': '84', ......} +label = dict() +f = open(label_dir) +x = f.readlines() +f.close() +for i in range(len(x)): + class_name = x[i].split(' ')[0].split('/')[1] + class_idx = x[i].split(' ')[2].replace('\n', '').replace('\r', '') + label[class_name] = class_idx + +file_name = result_dir + +num_correct_top1 = 0 +num_total = len(file_name) + +# 统计top1正确的个数 +for file_idx in range(num_total): + x = file_name[file_idx] + f = open(os.path.join(sys.argv[1], x)) + score = f.readline().replace('\n', '').replace('\r', '').split(' ') # score:list[str] + score = score[0:1010] + score = [float(i) for i in score] + f.close() + s = [[], [], [], [], [], [], [], [], [], []] + for i in range(10): + s[i] = score[101*i:101*i + 101] # 对于score中的1010个分数,每隔101个将其取出放到s数组中 + cls_score = torch.tensor(s).mean(dim=0) # 对10个clips得到的输出结果求平均 + max_value = cls_score[0] + idx = 0 + for i in range(len(cls_score)): + if cls_score[i] >= max_value: + max_value = cls_score[i] + idx = i + if label[x.split('.')[0].replace('_1', '')] == str(idx): + num_correct_top1 += 1 + +top1_acc = num_correct_top1/num_total +result_dict = {"top1_acc": top1_acc} +print(result_dict) +json_str = json.dumps(result_dict) +with open(json_dir, 'w') as json_file: + json_file.write(json_str) diff --git a/ACL_PyTorch/contrib/cv/classfication/C3D/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/classfication/C3D/modelzoo_level.txt index 403465b84e..ec6168981c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/C3D/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/classfication/C3D/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus:Perfect \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/CSPResneXt50/LICENSE b/ACL_PyTorch/contrib/cv/classfication/CSPResneXt50/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/CSPResneXt50/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/CSPResneXt50/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Deit_Small/LICENSE b/ACL_PyTorch/contrib/cv/classfication/Deit_Small/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Deit_Small/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/Deit_Small/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Deit_Small/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/classfication/Deit_Small/gen_dataset_info.py index 80c2b0fc30..f80f45a34c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Deit_Small/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/classfication/Deit_Small/gen_dataset_info.py @@ -1,60 +1,60 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' - get_jpg_info(file_path, info_name) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' + get_jpg_info(file_path, info_name) diff --git a/ACL_PyTorch/contrib/cv/classfication/Deit_Small/imagenet_acc_eval.py b/ACL_PyTorch/contrib/cv/classfication/Deit_Small/imagenet_acc_eval.py index 0e1db27e81..9ec7d5da53 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Deit_Small/imagenet_acc_eval.py +++ b/ACL_PyTorch/contrib/cv/classfication/Deit_Small/imagenet_acc_eval.py @@ -1,183 +1,183 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - if data == '': - n_label = 0 - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = 0 - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - - resCnt = min(len(sort_index), topn) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) - print("Time used:", elapsed) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + if data == '': + n_label = 0 + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = 0 + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + + resCnt = min(len(sort_index), topn) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) + print("Time used:", elapsed) diff --git a/ACL_PyTorch/contrib/cv/classfication/Deit_Small/imagenet_torch_preprocess.py b/ACL_PyTorch/contrib/cv/classfication/Deit_Small/imagenet_torch_preprocess.py index f7ca84a256..f1ed2bf166 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Deit_Small/imagenet_torch_preprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/Deit_Small/imagenet_torch_preprocess.py @@ -1,104 +1,104 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -from PIL import Image -import numpy as np -import multiprocessing - - -model_config = { - 'deit': { - 'resize': 256, - 'centercrop': 224, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, -} - - -def center_crop(img, output_size): - if isinstance(output_size, int): - output_size = (int(output_size), int(output_size)) - image_width, image_height = img.size - crop_height, crop_width = output_size - crop_top = int(round((image_height - crop_height) / 2.)) - crop_left = int(round((image_width - crop_width) / 2.)) - return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) - - -def resize(img, size, interpolation=Image.BILINEAR): - if isinstance(size, int): - w, h = img.size - if (w <= h and w == size) or (h <= w and h == size): - return img - if w < h: - ow = size - oh = int(size * h / w) - return img.resize((ow, oh), interpolation) - else: - oh = size - ow = int(size * w / h) - return img.resize((ow, oh), interpolation) - else: - return img.resize(size[::-1], interpolation) - - -def gen_input_bin(mode_type, file_batches, batch): - i = 0 - for file in file_batches[batch]: - i = i + 1 - print("batch", batch, file, "===", i) - - # RGBA to RGB - image = Image.open(os.path.join(src_path, file)).convert('RGB') - image = resize(image, model_config[mode_type]['resize']) # Resize - image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop - img = np.array(image, dtype=np.float32) - img = img.transpose(2, 0, 1) # ToTensor: HWC -> CHW - img = img / 255. # ToTensor: div 255 - img -= np.array(model_config[mode_type]['mean'], dtype=np.float32)[:, None, None] # Normalize: mean - img /= np.array(model_config[mode_type]['std'], dtype=np.float32)[:, None, None] # Normalize: std - img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) - - -def preprocess(mode_type, src_path, save_path): - files = os.listdir(src_path) - file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] - thread_pool = multiprocessing.Pool(len(file_batches)) - for batch in range(len(file_batches)): - thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) - thread_pool.close() - thread_pool.join() - print("in thread, except will not report! please ensure bin files generated.") - - -if __name__ == '__main__': - if len(sys.argv) < 4: - raise Exception("usage: python imagenet_torch_preprocess.py [model_type] [src_path] [save_path]") - mode_type = sys.argv[1] - src_path = sys.argv[2] - save_path = sys.argv[3] - src_path = os.path.realpath(src_path) - save_path = os.path.realpath(save_path) - if mode_type not in model_config: - model_type_help = "model type: " - for key in model_config.keys(): - model_type_help += key - model_type_help += ' ' - raise Exception(model_type_help) - if not os.path.isdir(save_path): - os.makedirs(os.path.realpath(save_path)) - preprocess(mode_type, src_path, save_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +from PIL import Image +import numpy as np +import multiprocessing + + +model_config = { + 'deit': { + 'resize': 256, + 'centercrop': 224, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, +} + + +def center_crop(img, output_size): + if isinstance(output_size, int): + output_size = (int(output_size), int(output_size)) + image_width, image_height = img.size + crop_height, crop_width = output_size + crop_top = int(round((image_height - crop_height) / 2.)) + crop_left = int(round((image_width - crop_width) / 2.)) + return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) + + +def resize(img, size, interpolation=Image.BILINEAR): + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def gen_input_bin(mode_type, file_batches, batch): + i = 0 + for file in file_batches[batch]: + i = i + 1 + print("batch", batch, file, "===", i) + + # RGBA to RGB + image = Image.open(os.path.join(src_path, file)).convert('RGB') + image = resize(image, model_config[mode_type]['resize']) # Resize + image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop + img = np.array(image, dtype=np.float32) + img = img.transpose(2, 0, 1) # ToTensor: HWC -> CHW + img = img / 255. # ToTensor: div 255 + img -= np.array(model_config[mode_type]['mean'], dtype=np.float32)[:, None, None] # Normalize: mean + img /= np.array(model_config[mode_type]['std'], dtype=np.float32)[:, None, None] # Normalize: std + img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) + + +def preprocess(mode_type, src_path, save_path): + files = os.listdir(src_path) + file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] + thread_pool = multiprocessing.Pool(len(file_batches)) + for batch in range(len(file_batches)): + thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) + thread_pool.close() + thread_pool.join() + print("in thread, except will not report! please ensure bin files generated.") + + +if __name__ == '__main__': + if len(sys.argv) < 4: + raise Exception("usage: python imagenet_torch_preprocess.py [model_type] [src_path] [save_path]") + mode_type = sys.argv[1] + src_path = sys.argv[2] + save_path = sys.argv[3] + src_path = os.path.realpath(src_path) + save_path = os.path.realpath(save_path) + if mode_type not in model_config: + model_type_help = "model type: " + for key in model_config.keys(): + model_type_help += key + model_type_help += ' ' + raise Exception(model_type_help) + if not os.path.isdir(save_path): + os.makedirs(os.path.realpath(save_path)) + preprocess(mode_type, src_path, save_path) diff --git a/ACL_PyTorch/contrib/cv/classfication/Deit_Small/parse.py b/ACL_PyTorch/contrib/cv/classfication/Deit_Small/parse.py index b9c74f41d7..82af69cd18 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Deit_Small/parse.py +++ b/ACL_PyTorch/contrib/cv/classfication/Deit_Small/parse.py @@ -1,32 +1,32 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Deit_Small/test/README.md b/ACL_PyTorch/contrib/cv/classfication/Deit_Small/test/README.md index 0c8bb48bce..d53433c40a 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Deit_Small/test/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/Deit_Small/test/README.md @@ -1,24 +1,24 @@ -环境准备: - -1.数据集路径 -通用的数据集统一放在/root/datasets/或/opt/npu/ -本模型数据集路径为 /opt/npu/ - -2.进入工作目录 -cd Deit-Small - -3.导入所需的环境 -pip3.7 install -r requirements.txt - -4.获取模型代码 -git clone https://github.com/facebookresearch/deit.git - -5.获取权重文件 -wget https://dl.fbaipublicfiles.com/deit/deit_small_patch16_224-cd65a155.pth - -6.获取benchmark工具 -将benchmark.x86_64 benchmark.aarch64放在当前目录 - -7.310上执行,执行时确保device空闲 -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets +环境准备: + +1.数据集路径 +通用的数据集统一放在/root/datasets/或/opt/npu/ +本模型数据集路径为 /opt/npu/ + +2.进入工作目录 +cd Deit-Small + +3.导入所需的环境 +pip3.7 install -r requirements.txt + +4.获取模型代码 +git clone https://github.com/facebookresearch/deit.git + +5.获取权重文件 +wget https://dl.fbaipublicfiles.com/deit/deit_small_patch16_224-cd65a155.pth + +6.获取benchmark工具 +将benchmark.x86_64 benchmark.aarch64放在当前目录 + +7.310上执行,执行时确保device空闲 +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets diff --git a/ACL_PyTorch/contrib/cv/classfication/Deit_Small/test/pth2om.sh b/ACL_PyTorch/contrib/cv/classfication/Deit_Small/test/pth2om.sh old mode 100755 new mode 100644 diff --git a/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/Efficient-3DCNNs_postprocess.py b/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/Efficient-3DCNNs_postprocess.py index c4bb75bf7d..58cd26aba3 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/Efficient-3DCNNs_postprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/Efficient-3DCNNs_postprocess.py @@ -1,113 +1,113 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import json -import argparse -from pathlib import Path -import torch -import torch.nn.functional as F -import numpy as np -sys.path.append(r"./Efficient-3DCNNs/utils") -from eval_ucf101 import UCFclassification - -CLASS_NAMES = {0: 'ApplyEyeMakeup', 1: 'ApplyLipstick', 2: 'Archery', 3: 'BabyCrawling', 4: 'BalanceBeam', 5: 'BandMarching', - 6: 'BaseballPitch', 7: 'Basketball', 8: 'BasketballDunk', 9: 'BenchPress', 10: 'Biking', - 11: 'Billiards', 12: 'BlowDryHair', 13: 'BlowingCandles', 14: 'BodyWeightSquats', 15: 'Bowling', - 16: 'BoxingPunchingBag', 17: 'BoxingSpeedBag', 18: 'BreastStroke', 19: 'BrushingTeeth', 20: 'CleanAndJerk', - 21: 'CliffDiving', 22: 'CricketBowling', 23: 'CricketShot', 24: 'CuttingInKitchen', 25: 'Diving', - 26: 'Drumming', 27: 'Fencing', 28: 'FieldHockeyPenalty', 29: 'FloorGymnastics', 30: 'FrisbeeCatch', - 31: 'FrontCrawl', 32: 'GolfSwing', 33: 'Haircut', 34: 'Hammering', 35: 'HammerThrow', - 36: 'HandstandPushups', 37: 'HandstandWalking', 38: 'HeadMassage', 39: 'HighJump', 40: 'HorseRace', - 41: 'HorseRiding', 42: 'HulaHoop', 43: 'IceDancing', 44: 'JavelinThrow', 45: 'JugglingBalls', - 46: 'JumpingJack', 47: 'JumpRope', 48: 'Kayaking', 49: 'Knitting', 50: 'LongJump', - 51: 'Lunges', 52: 'MilitaryParade', 53: 'Mixing', 54: 'MoppingFloor', 55: 'Nunchucks', - 56: 'ParallelBars', 57: 'PizzaTossing', 58: 'PlayingCello', 59: 'PlayingDaf', 60: 'PlayingDhol', - 61: 'PlayingFlute', 62: 'PlayingGuitar', 63: 'PlayingPiano', 64: 'PlayingSitar', 65: 'PlayingTabla', - 66: 'PlayingViolin', 67: 'PoleVault', 68: 'PommelHorse', 69: 'PullUps', 70: 'Punch', - 71: 'PushUps', 72: 'Rafting', 73: 'RockClimbingIndoor', 74: 'RopeClimbing', 75: 'Rowing', - 76: 'SalsaSpin', 77: 'ShavingBeard', 78: 'Shotput', 79: 'SkateBoarding', 80: 'Skiing', - 81: 'Skijet', 82: 'SkyDiving', 83: 'SoccerJuggling', 84: 'SoccerPenalty', 85: 'StillRings', - 86: 'SumoWrestling', 87: 'Surfing', 88: 'Swing', 89: 'TableTennisShot', 90: 'TaiChi', - 91: 'TennisSwing', 92: 'ThrowDiscus', 93: 'TrampolineJumping', 94: 'Typing', 95: 'UnevenBars', - 96: 'VolleyballSpiking', 97: 'WalkingWithDog', 98: 'WallPushups', 99: 'WritingOnBoard', 100: 'YoYo'} - -def calculate_video_results(output_buffer, video_id, test_results, class_names): - video_outputs = torch.stack(output_buffer) - average_scores = torch.mean(video_outputs, dim=0) - sorted_scores, locs = torch.topk(average_scores, k=10) - - video_results = [] - for i in range(sorted_scores.size(0)): - video_results.append({ - 'label': class_names[int(locs[i])], - 'score': float(sorted_scores[i]) - }) - - test_results['results'][video_id] = video_results - -def evaluate(result_path, class_names, info_path, annotation_path, acc_file): - print('postprocessing') - f = open(info_path, 'r') - ucf101_info = f.readlines() - bin_path = os.listdir(result_path)[0] - result_path = os.path.join(result_path, bin_path) - bin_list = os.listdir(result_path) - bin_list.sort(key= lambda x:int(x[:-13])) - output_buffer = [] - previous_video_id = '' - test_results = {'results': {}} - for i, line in enumerate(ucf101_info): - targets = line.split(' ') - targets = targets[0:len(targets)-1] - bin_path = os.path.join(result_path, bin_list[i]) - outputs = np.fromfile(bin_path, dtype=np.float32).reshape(-1, 101) - outputs = torch.from_numpy(outputs) - outputs = F.softmax(outputs, dim=1).cpu() - for j in range(outputs.size(0)): - if not (i == 0 and j == 0) and targets[j] != previous_video_id: - calculate_video_results(output_buffer, previous_video_id, - test_results, class_names) - output_buffer = [] - output_buffer.append(outputs[j].data.cpu()) - previous_video_id = targets[j] - - if (i % 100) == 0: - with open('val.json', 'w') as f: - json.dump(test_results, f) - if (i % 1000) == 0: - print('[{}/{}]'.format(i+1, len(bin_list))) - with open('val.json', 'w') as f: - json.dump(test_results, f) - - ucf_acc_t1 = UCFclassification(annotation_path, 'val.json', subset='validation', top_k=1) - ucf_acc_t1.evaluate() - - ucf_acc_t5 = UCFclassification(annotation_path, 'val.json', subset='validation', top_k=5) - ucf_acc_t5.evaluate() - - with open(acc_file, 'w') as f: - json.dump('top1 acc:'+str(ucf_acc_t1.hit_at_k)+'; top5 acc:'+str(ucf_acc_t5.hit_at_k), f) - print('postprocess finised') - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='preprocess of 3D-ResNets') - parser.add_argument('--result_path', default='', type=Path, help='Directory path of videos') - parser.add_argument('--info_path', default='', type=Path, help='Directory path of binary output data') - parser.add_argument('--annotation_path', default='', type=Path, help='Annotation file path') - parser.add_argument('--acc_file', default='', type=Path, help='Directory path of binary output data') - opt = parser.parse_args() - evaluate(opt.result_path, CLASS_NAMES, opt.info_path, opt.annotation_path, opt.acc_file) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import json +import argparse +from pathlib import Path +import torch +import torch.nn.functional as F +import numpy as np +sys.path.append(r"./Efficient-3DCNNs/utils") +from eval_ucf101 import UCFclassification + +CLASS_NAMES = {0: 'ApplyEyeMakeup', 1: 'ApplyLipstick', 2: 'Archery', 3: 'BabyCrawling', 4: 'BalanceBeam', 5: 'BandMarching', + 6: 'BaseballPitch', 7: 'Basketball', 8: 'BasketballDunk', 9: 'BenchPress', 10: 'Biking', + 11: 'Billiards', 12: 'BlowDryHair', 13: 'BlowingCandles', 14: 'BodyWeightSquats', 15: 'Bowling', + 16: 'BoxingPunchingBag', 17: 'BoxingSpeedBag', 18: 'BreastStroke', 19: 'BrushingTeeth', 20: 'CleanAndJerk', + 21: 'CliffDiving', 22: 'CricketBowling', 23: 'CricketShot', 24: 'CuttingInKitchen', 25: 'Diving', + 26: 'Drumming', 27: 'Fencing', 28: 'FieldHockeyPenalty', 29: 'FloorGymnastics', 30: 'FrisbeeCatch', + 31: 'FrontCrawl', 32: 'GolfSwing', 33: 'Haircut', 34: 'Hammering', 35: 'HammerThrow', + 36: 'HandstandPushups', 37: 'HandstandWalking', 38: 'HeadMassage', 39: 'HighJump', 40: 'HorseRace', + 41: 'HorseRiding', 42: 'HulaHoop', 43: 'IceDancing', 44: 'JavelinThrow', 45: 'JugglingBalls', + 46: 'JumpingJack', 47: 'JumpRope', 48: 'Kayaking', 49: 'Knitting', 50: 'LongJump', + 51: 'Lunges', 52: 'MilitaryParade', 53: 'Mixing', 54: 'MoppingFloor', 55: 'Nunchucks', + 56: 'ParallelBars', 57: 'PizzaTossing', 58: 'PlayingCello', 59: 'PlayingDaf', 60: 'PlayingDhol', + 61: 'PlayingFlute', 62: 'PlayingGuitar', 63: 'PlayingPiano', 64: 'PlayingSitar', 65: 'PlayingTabla', + 66: 'PlayingViolin', 67: 'PoleVault', 68: 'PommelHorse', 69: 'PullUps', 70: 'Punch', + 71: 'PushUps', 72: 'Rafting', 73: 'RockClimbingIndoor', 74: 'RopeClimbing', 75: 'Rowing', + 76: 'SalsaSpin', 77: 'ShavingBeard', 78: 'Shotput', 79: 'SkateBoarding', 80: 'Skiing', + 81: 'Skijet', 82: 'SkyDiving', 83: 'SoccerJuggling', 84: 'SoccerPenalty', 85: 'StillRings', + 86: 'SumoWrestling', 87: 'Surfing', 88: 'Swing', 89: 'TableTennisShot', 90: 'TaiChi', + 91: 'TennisSwing', 92: 'ThrowDiscus', 93: 'TrampolineJumping', 94: 'Typing', 95: 'UnevenBars', + 96: 'VolleyballSpiking', 97: 'WalkingWithDog', 98: 'WallPushups', 99: 'WritingOnBoard', 100: 'YoYo'} + +def calculate_video_results(output_buffer, video_id, test_results, class_names): + video_outputs = torch.stack(output_buffer) + average_scores = torch.mean(video_outputs, dim=0) + sorted_scores, locs = torch.topk(average_scores, k=10) + + video_results = [] + for i in range(sorted_scores.size(0)): + video_results.append({ + 'label': class_names[int(locs[i])], + 'score': float(sorted_scores[i]) + }) + + test_results['results'][video_id] = video_results + +def evaluate(result_path, class_names, info_path, annotation_path, acc_file): + print('postprocessing') + f = open(info_path, 'r') + ucf101_info = f.readlines() + bin_path = os.listdir(result_path)[0] + result_path = os.path.join(result_path, bin_path) + bin_list = os.listdir(result_path) + bin_list.sort(key= lambda x:int(x[:-13])) + output_buffer = [] + previous_video_id = '' + test_results = {'results': {}} + for i, line in enumerate(ucf101_info): + targets = line.split(' ') + targets = targets[0:len(targets)-1] + bin_path = os.path.join(result_path, bin_list[i]) + outputs = np.fromfile(bin_path, dtype=np.float32).reshape(-1, 101) + outputs = torch.from_numpy(outputs) + outputs = F.softmax(outputs, dim=1).cpu() + for j in range(outputs.size(0)): + if not (i == 0 and j == 0) and targets[j] != previous_video_id: + calculate_video_results(output_buffer, previous_video_id, + test_results, class_names) + output_buffer = [] + output_buffer.append(outputs[j].data.cpu()) + previous_video_id = targets[j] + + if (i % 100) == 0: + with open('val.json', 'w') as f: + json.dump(test_results, f) + if (i % 1000) == 0: + print('[{}/{}]'.format(i+1, len(bin_list))) + with open('val.json', 'w') as f: + json.dump(test_results, f) + + ucf_acc_t1 = UCFclassification(annotation_path, 'val.json', subset='validation', top_k=1) + ucf_acc_t1.evaluate() + + ucf_acc_t5 = UCFclassification(annotation_path, 'val.json', subset='validation', top_k=5) + ucf_acc_t5.evaluate() + + with open(acc_file, 'w') as f: + json.dump('top1 acc:'+str(ucf_acc_t1.hit_at_k)+'; top5 acc:'+str(ucf_acc_t5.hit_at_k), f) + print('postprocess finised') + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='preprocess of 3D-ResNets') + parser.add_argument('--result_path', default='', type=Path, help='Directory path of videos') + parser.add_argument('--info_path', default='', type=Path, help='Directory path of binary output data') + parser.add_argument('--annotation_path', default='', type=Path, help='Annotation file path') + parser.add_argument('--acc_file', default='', type=Path, help='Directory path of binary output data') + opt = parser.parse_args() + evaluate(opt.result_path, CLASS_NAMES, opt.info_path, opt.annotation_path, opt.acc_file) diff --git a/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/Efficient-3DCNNs_preprocess.py b/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/Efficient-3DCNNs_preprocess.py index ff18e7092f..4b9ee37b7f 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/Efficient-3DCNNs_preprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/Efficient-3DCNNs_preprocess.py @@ -1,92 +1,92 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import argparse -from pathlib import Path -import torch -import numpy as np -sys.path.append(r"./Efficient-3DCNNs") -from dataset import get_test_set -from spatial_transforms import Normalize, Compose, Scale, CornerCrop -from temporal_transforms import TemporalRandomCrop -from target_transforms import VideoID - -class ToTensor(object): - def __init__(self, norm_value=255): - self.norm_value = norm_value - - def __call__(self, pic): - img = np.array(pic, dtype=np.float32) - img = img.transpose(2, 0, 1) - img = img / self.norm_value - return torch.from_numpy(img) - - def randomize_parameters(self): - pass - -def preprocess(save_path): - print('preprocessing') - norm_method = Normalize([114.7748, 107.7354, 99.4750], [1, 1, 1]) - - spatial_transform = Compose([ - Scale(int(112 / 1.0)), - CornerCrop(112, 'c'), - ToTensor(1), norm_method - ]) - temporal_transform = TemporalRandomCrop(16, 1) - target_transform = VideoID() - - test_data = get_test_set(opt, spatial_transform, temporal_transform, - target_transform) - - test_loader = torch.utils.data.DataLoader(test_data, - batch_size=opt.inference_batch_size, - shuffle=False, - num_workers=0, - pin_memory=True) - if not os.path.exists(save_path): - os.makedirs(save_path) - file = open(opt.info_path, 'w') - cid = 0 - for i, (inputs, targets) in enumerate(test_loader): - if(len(targets) == opt.inference_batch_size): - info = '' - for j in range(len(targets)): - info = info + targets[j] + ' ' - batch_bin = inputs.cpu().numpy() - path_bin = str(save_path) + '/' + str(cid) + '.bin' - cid = cid + 1 - batch_bin.tofile(path_bin) - file.write(info) - file.write('\n') - if (i % 1000) == 0: - print('[{}/{}]'.format(i+1, len(test_loader))) - print('preprocess finished') - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='preprocess of 3D-ResNets') - parser.add_argument('--video_path', default='C:/Users/17270/Efficient-3DCNNs-master-2/annotation_UCF101/UCF-101-image/UCF-101-image', type=Path, help='Directory path of videos') - parser.add_argument('--annotation_path', default='ucf101_01.json', type=Path, help='Annotation file path') - parser.add_argument('--dataset', default='ucf101', type=str, help='Used dataset (activitynet | kinetics | ucf101 | hmdb51)') - parser.add_argument('--test_subset', default='val', type=str, help='Used subset in inference (train | val | test)') - parser.add_argument('--output_path', default='zjbintt', type=Path, help='Directory path of binary output data') - parser.add_argument('--info_path', default='zjbin1.info', type=Path, help='Directory path of binary output data') - parser.add_argument('--inference_batch_size', default=16, type=int, help='Batch Size for inference. 0 means this is the same as batch_size.') - parser.add_argument('--sample_duration', default=16, type=int, help='Temporal duration of inputs') - opt = parser.parse_args() - - preprocess(opt.output_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import argparse +from pathlib import Path +import torch +import numpy as np +sys.path.append(r"./Efficient-3DCNNs") +from dataset import get_test_set +from spatial_transforms import Normalize, Compose, Scale, CornerCrop +from temporal_transforms import TemporalRandomCrop +from target_transforms import VideoID + +class ToTensor(object): + def __init__(self, norm_value=255): + self.norm_value = norm_value + + def __call__(self, pic): + img = np.array(pic, dtype=np.float32) + img = img.transpose(2, 0, 1) + img = img / self.norm_value + return torch.from_numpy(img) + + def randomize_parameters(self): + pass + +def preprocess(save_path): + print('preprocessing') + norm_method = Normalize([114.7748, 107.7354, 99.4750], [1, 1, 1]) + + spatial_transform = Compose([ + Scale(int(112 / 1.0)), + CornerCrop(112, 'c'), + ToTensor(1), norm_method + ]) + temporal_transform = TemporalRandomCrop(16, 1) + target_transform = VideoID() + + test_data = get_test_set(opt, spatial_transform, temporal_transform, + target_transform) + + test_loader = torch.utils.data.DataLoader(test_data, + batch_size=opt.inference_batch_size, + shuffle=False, + num_workers=0, + pin_memory=True) + if not os.path.exists(save_path): + os.makedirs(save_path) + file = open(opt.info_path, 'w') + cid = 0 + for i, (inputs, targets) in enumerate(test_loader): + if(len(targets) == opt.inference_batch_size): + info = '' + for j in range(len(targets)): + info = info + targets[j] + ' ' + batch_bin = inputs.cpu().numpy() + path_bin = str(save_path) + '/' + str(cid) + '.bin' + cid = cid + 1 + batch_bin.tofile(path_bin) + file.write(info) + file.write('\n') + if (i % 1000) == 0: + print('[{}/{}]'.format(i+1, len(test_loader))) + print('preprocess finished') + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='preprocess of 3D-ResNets') + parser.add_argument('--video_path', default='C:/Users/17270/Efficient-3DCNNs-master-2/annotation_UCF101/UCF-101-image/UCF-101-image', type=Path, help='Directory path of videos') + parser.add_argument('--annotation_path', default='ucf101_01.json', type=Path, help='Annotation file path') + parser.add_argument('--dataset', default='ucf101', type=str, help='Used dataset (activitynet | kinetics | ucf101 | hmdb51)') + parser.add_argument('--test_subset', default='val', type=str, help='Used subset in inference (train | val | test)') + parser.add_argument('--output_path', default='zjbintt', type=Path, help='Directory path of binary output data') + parser.add_argument('--info_path', default='zjbin1.info', type=Path, help='Directory path of binary output data') + parser.add_argument('--inference_batch_size', default=16, type=int, help='Batch Size for inference. 0 means this is the same as batch_size.') + parser.add_argument('--sample_duration', default=16, type=int, help='Temporal duration of inputs') + opt = parser.parse_args() + + preprocess(opt.output_path) diff --git a/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/LICENSE b/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/LICENSE index 797bf40e85..04adf5cbc6 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/LICENSE @@ -1,203 +1,203 @@ -Copyright 2018-2019 Open-MMLab. All rights reserved. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018-2019 Open-MMLab. - - 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. +Copyright 2018-2019 Open-MMLab. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2019 Open-MMLab. + + 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. diff --git a/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/README.md b/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/README.md index ae5d6a93ce..5329288086 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/README.md @@ -1,49 +1,49 @@ -# Efficient-3DCNNs模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -``` -pip3.7 install -r requirements.txt -``` - -2.安装开源模型代码 -``` -git clone https://github.com/okankop/Efficient-3DCNNs -``` -> branch: master - -> commit id: d60c6c48cf2e81380d0a513e22e9d7f8467731af - -3.获取权重文件 - -[ucf101_mobilenetv2_1.0x_RGB_16_best.pth](https://drive.google.com/drive/folders/1u4DO7kjAQP6Zdh8CN65iT5ozp11mvE-H?usp=sharing) - -4.[获取UCF-101数据集](https://www.crcv.ucf.edu/data/UCF101/UCF101.rar) -将UCF101.rar文件解压,重命名为ucf101,放在 /root/datasets/文件夹下 - -``` -python3.7 Efficient-3DCNNs/utils/video_jpg_ucf101_hmdb51.py /root/datasets/ucf101/videos/ /root/datasets/ucf101/rawframes -python3.7 Efficient-3DCNNs/utils/n_frames_ucf101_hmdb51.py /root/datasets/ucf101/rawframes -``` -[获取json形式的annotation文件](https://github.com/okankop/Efficient-3DCNNs/tree/master/annotation_UCF101) -将ucf101_01.json放到当前目录 - -5.获取[msame](https://gitee.com/ascend/tools/tree/master/msame)和[benchmark](https://gitee.com/ascend/cann-benchmark/tree/master/infer)工具 -将msame和benchmark.x86_64(或benchmark.aarch64)放到当前目录 - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets/ -``` - **评测结果:** -| 模型 | pth精度 | 310精度 | 性能基准 | 310性能 | -| :------: | :------: | :------: | :------: | :------: | -| Efficient-3DCNNs bs1 | top1:81.100% top5:96.326% | top1:81.126% top5:96.299% | 619.767fps | 641.728fps | -| Efficient-3DCNNs bs16 | top1:81.100% top5:96.326% | top1:81.126% top5:96.299% | 393.696fps | 744.432fps | - - - +# Efficient-3DCNNs模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +``` +pip3.7 install -r requirements.txt +``` + +2.安装开源模型代码 +``` +git clone https://github.com/okankop/Efficient-3DCNNs +``` +> branch: master + +> commit id: d60c6c48cf2e81380d0a513e22e9d7f8467731af + +3.获取权重文件 + +[ucf101_mobilenetv2_1.0x_RGB_16_best.pth](https://drive.google.com/drive/folders/1u4DO7kjAQP6Zdh8CN65iT5ozp11mvE-H?usp=sharing) + +4.[获取UCF-101数据集](https://www.crcv.ucf.edu/data/UCF101/UCF101.rar) +将UCF101.rar文件解压,重命名为ucf101,放在 /root/datasets/文件夹下 + +``` +python3.7 Efficient-3DCNNs/utils/video_jpg_ucf101_hmdb51.py /root/datasets/ucf101/videos/ /root/datasets/ucf101/rawframes +python3.7 Efficient-3DCNNs/utils/n_frames_ucf101_hmdb51.py /root/datasets/ucf101/rawframes +``` +[获取json形式的annotation文件](https://github.com/okankop/Efficient-3DCNNs/tree/master/annotation_UCF101) +将ucf101_01.json放到当前目录 + +5.获取[msame](https://gitee.com/ascend/tools/tree/master/msame)和[benchmark](https://gitee.com/ascend/cann-benchmark/tree/master/infer)工具 +将msame和benchmark.x86_64(或benchmark.aarch64)放到当前目录 + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets/ +``` + **评测结果:** +| 模型 | pth精度 | 310精度 | 性能基准 | 310性能 | +| :------: | :------: | :------: | :------: | :------: | +| Efficient-3DCNNs bs1 | top1:81.100% top5:96.326% | top1:81.126% top5:96.299% | 619.767fps | 641.728fps | +| Efficient-3DCNNs bs16 | top1:81.100% top5:96.326% | top1:81.126% top5:96.299% | 393.696fps | 744.432fps | + + + diff --git a/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/modelzoo_level.txt index 7313992239..108cc882d6 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:PERFECT \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/requirements.txt b/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/requirements.txt index ef82dd0625..5768d0bd49 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/requirements.txt +++ b/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs/requirements.txt @@ -1,7 +1,7 @@ -torch==1.5.0 -torchvision==0.6.0 -onnx == 1.7.0 -onnx-simplifier==0.3.6 -opencv-python==4.5.3.56 -scipy +torch==1.5.0 +torchvision==0.6.0 +onnx == 1.7.0 +onnx-simplifier==0.3.6 +opencv-python==4.5.3.56 +scipy pandas \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/Efficient-B1_postprocess.py b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/Efficient-B1_postprocess.py index d51eb6e5f9..7f8389d56e 100644 --- a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/Efficient-B1_postprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/Efficient-B1_postprocess.py @@ -1,72 +1,72 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import os -import argparse -import re -import numpy -import json - -def rename(data_dir, pre_dir): - txtfile_2_class = dict() - for classname in os.listdir(data_dir): - for imgname in os.listdir(os.path.join(data_dir, classname)): - txtfile_2_class[os.path.splitext(imgname)[0].split("_")[2]] = classname - omoutput_txts = os.listdir(pre_dir) - for omtxt in omoutput_txts: - if omtxt.split("_")[0] not in txtfile_2_class.values(): - os.rename(os.path.join(pre_dir, omtxt), os.path.join(pre_dir, txtfile_2_class.get(omtxt.split("_")[2]) + "_" + omtxt)) - -def classification(data_path): - files = os.listdir(data_path) - class_ids = sorted(f for f in files if re.match(r"^n[0-9]+$", f)) - return class_ids - - -def eval(data_dir, pred_dir, save_file): - txtfiles = os.listdir(pred_dir) - top1_acc = 0 - top5_acc = 0 - for txtfile in txtfiles: - print("loading {}".format(txtfile)) - pre_num = numpy.loadtxt(os.path.join(pred_dir, txtfile)) - class_ids = classification(data_dir) - class_pres = zip(class_ids, pre_num) - class_pres_dict = dict((class_id, value) for class_id, value in class_pres) - class_sort = max(class_pres_dict.items(), key=lambda x: x[1]) - if txtfile.split('_')[0] == class_sort[0]: - top1_acc = top1_acc + 1 - iteams = sorted(class_pres_dict.items(), key=lambda x: x[1]) - if txtfile.split('_')[0] in [iteams[999][0], iteams[998][0], iteams[997][0], iteams[996][0], iteams[995][0]]: - top5_acc = top5_acc + 1 - - topn_acc = dict() - topn_acc['Top1 accuracy'] = str(top1_acc / 50000 * 100) + "%" - topn_acc['Top5 accuracy'] = str(top5_acc / 50000 * 100) + "%" - print(topn_acc['Top1 accuracy']) - print(topn_acc['Top5 accuracy']) - writer = open(save_file, 'w') - json.dump(topn_acc, writer) - writer.close() - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--data_dir", default="./imagenet/val") - parser.add_argument("--pre_dir", default="./result/dumpOutput_device0/") - parser.add_argument("--save_file", default="./result.json") - args = parser.parse_args() - rename(args.data_dir, args.pre_dir) - eval(args.data_dir, args.pre_dir, args.save_file) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import os +import argparse +import re +import numpy +import json + +def rename(data_dir, pre_dir): + txtfile_2_class = dict() + for classname in os.listdir(data_dir): + for imgname in os.listdir(os.path.join(data_dir, classname)): + txtfile_2_class[os.path.splitext(imgname)[0].split("_")[2]] = classname + omoutput_txts = os.listdir(pre_dir) + for omtxt in omoutput_txts: + if omtxt.split("_")[0] not in txtfile_2_class.values(): + os.rename(os.path.join(pre_dir, omtxt), os.path.join(pre_dir, txtfile_2_class.get(omtxt.split("_")[2]) + "_" + omtxt)) + +def classification(data_path): + files = os.listdir(data_path) + class_ids = sorted(f for f in files if re.match(r"^n[0-9]+$", f)) + return class_ids + + +def eval(data_dir, pred_dir, save_file): + txtfiles = os.listdir(pred_dir) + top1_acc = 0 + top5_acc = 0 + for txtfile in txtfiles: + print("loading {}".format(txtfile)) + pre_num = numpy.loadtxt(os.path.join(pred_dir, txtfile)) + class_ids = classification(data_dir) + class_pres = zip(class_ids, pre_num) + class_pres_dict = dict((class_id, value) for class_id, value in class_pres) + class_sort = max(class_pres_dict.items(), key=lambda x: x[1]) + if txtfile.split('_')[0] == class_sort[0]: + top1_acc = top1_acc + 1 + iteams = sorted(class_pres_dict.items(), key=lambda x: x[1]) + if txtfile.split('_')[0] in [iteams[999][0], iteams[998][0], iteams[997][0], iteams[996][0], iteams[995][0]]: + top5_acc = top5_acc + 1 + + topn_acc = dict() + topn_acc['Top1 accuracy'] = str(top1_acc / 50000 * 100) + "%" + topn_acc['Top5 accuracy'] = str(top5_acc / 50000 * 100) + "%" + print(topn_acc['Top1 accuracy']) + print(topn_acc['Top5 accuracy']) + writer = open(save_file, 'w') + json.dump(topn_acc, writer) + writer.close() + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("--data_dir", default="./imagenet/val") + parser.add_argument("--pre_dir", default="./result/dumpOutput_device0/") + parser.add_argument("--save_file", default="./result.json") + args = parser.parse_args() + rename(args.data_dir, args.pre_dir) + eval(args.data_dir, args.pre_dir, args.save_file) diff --git a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/Efficient-B1_preprocess.py b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/Efficient-B1_preprocess.py index 09fb97aadc..a9b71deb63 100644 --- a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/Efficient-B1_preprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/Efficient-B1_preprocess.py @@ -1,63 +1,63 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -sys.path.append("./pycls") -import numpy as np -import cv2 - -from pycls.datasets import transforms - -_EIG_VALS = [[0.2175, 0.0188, 0.0045]] -_EIG_VECS = [ - [-0.5675, 0.7192, 0.4009], - [-0.5808, -0.0045, -0.8140], - [-0.5836, -0.6948, 0.4203], -] -_MEAN = [0.485, 0.456, 0.406] -_STD = [0.229, 0.224, 0.225] - -train_size = 240 -test_size = 274 - -def trans(im): - im = im[:, :, ::-1].astype(np.float32) / 255 - im = transforms.scale_and_center_crop(im, test_size, train_size) - im = transforms.color_norm(im, _MEAN, _STD) - im = np.ascontiguousarray(im[:, :, ::-1].transpose([2, 0, 1])) - return im - -def EffnetB1_preprocess(src_path, save_path): - i = 0 - classes = os.listdir(src_path) - for classname in classes: - dirs = os.path.join(src_path, classname) - save_dir = os.path.join(save_path, classname) - if not os.path.isdir(save_dir): - os.makedirs(os.path.realpath(save_dir)) - for img in os.listdir(dirs): - i = i + 1 - print(img, "===", i) - img_path = os.path.join(dirs, img) - im = cv2.imread(img_path) - im = trans(im) - im.tofile(os.path.join(save_dir, img.split('.')[0] + ".bin")) - -if __name__ == '__main__': - src_path = sys.argv[1] - save_path = sys.argv[2] - if not os.path.isdir(save_path): - os.makedirs(os.path.realpath(save_path)) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +sys.path.append("./pycls") +import numpy as np +import cv2 + +from pycls.datasets import transforms + +_EIG_VALS = [[0.2175, 0.0188, 0.0045]] +_EIG_VECS = [ + [-0.5675, 0.7192, 0.4009], + [-0.5808, -0.0045, -0.8140], + [-0.5836, -0.6948, 0.4203], +] +_MEAN = [0.485, 0.456, 0.406] +_STD = [0.229, 0.224, 0.225] + +train_size = 240 +test_size = 274 + +def trans(im): + im = im[:, :, ::-1].astype(np.float32) / 255 + im = transforms.scale_and_center_crop(im, test_size, train_size) + im = transforms.color_norm(im, _MEAN, _STD) + im = np.ascontiguousarray(im[:, :, ::-1].transpose([2, 0, 1])) + return im + +def EffnetB1_preprocess(src_path, save_path): + i = 0 + classes = os.listdir(src_path) + for classname in classes: + dirs = os.path.join(src_path, classname) + save_dir = os.path.join(save_path, classname) + if not os.path.isdir(save_dir): + os.makedirs(os.path.realpath(save_dir)) + for img in os.listdir(dirs): + i = i + 1 + print(img, "===", i) + img_path = os.path.join(dirs, img) + im = cv2.imread(img_path) + im = trans(im) + im.tofile(os.path.join(save_dir, img.split('.')[0] + ".bin")) + +if __name__ == '__main__': + src_path = sys.argv[1] + save_path = sys.argv[2] + if not os.path.isdir(save_path): + os.makedirs(os.path.realpath(save_path)) EffnetB1_preprocess(src_path, save_path) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/Efficient-B1_pth2onnx.py b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/Efficient-B1_pth2onnx.py index f79c4391c0..53a95a7aae 100644 --- a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/Efficient-B1_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/Efficient-B1_pth2onnx.py @@ -1,51 +1,51 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import sys -import torch -from collections import OrderedDict -sys.path.append('./pycls') -from pycls.models.effnet import EffNet -import pycls.core.config as config -from pycls.core.config import cfg - -def proc_node_module(checkpoint, attr_name): - new_model_state = OrderedDict() - for k, v in checkpoint[attr_name].items(): - if(k[0: 7] == "module."): - name = k[7:] - else: - name = k[0:] - new_model_state[name] = v - return new_model_state - -def main(input_file, yaml_file, output_file): - config.load_cfg(yaml_file) - cfg.freeze() - model = EffNet() - checkpoint = torch.load(input_file, map_location='cpu') - checkpoint['model_state'] = proc_node_module(checkpoint, 'model_state') - model.load_state_dict(checkpoint["model_state"]) - model.eval() - input_names = ["image"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.randn(1, 3, 240, 240) - torch.onnx.export(model, dummy_input, output_file, input_names=input_names, dynamic_axes=dynamic_axes, opset_version=11, verbose=True) - - -if __name__ == '__main__': - input_file = sys.argv[1] - yaml_file= sys.argv[2] - output_file = sys.argv[3] - main(input_file, yaml_file, output_file) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import sys +import torch +from collections import OrderedDict +sys.path.append('./pycls') +from pycls.models.effnet import EffNet +import pycls.core.config as config +from pycls.core.config import cfg + +def proc_node_module(checkpoint, attr_name): + new_model_state = OrderedDict() + for k, v in checkpoint[attr_name].items(): + if(k[0: 7] == "module."): + name = k[7:] + else: + name = k[0:] + new_model_state[name] = v + return new_model_state + +def main(input_file, yaml_file, output_file): + config.load_cfg(yaml_file) + cfg.freeze() + model = EffNet() + checkpoint = torch.load(input_file, map_location='cpu') + checkpoint['model_state'] = proc_node_module(checkpoint, 'model_state') + model.load_state_dict(checkpoint["model_state"]) + model.eval() + input_names = ["image"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.randn(1, 3, 240, 240) + torch.onnx.export(model, dummy_input, output_file, input_names=input_names, dynamic_axes=dynamic_axes, opset_version=11, verbose=True) + + +if __name__ == '__main__': + input_file = sys.argv[1] + yaml_file= sys.argv[2] + output_file = sys.argv[3] + main(input_file, yaml_file, output_file) diff --git a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/ImageNet_val_split.py b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/ImageNet_val_split.py index 3d5780c7cb..244e28b791 100644 --- a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/ImageNet_val_split.py +++ b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/ImageNet_val_split.py @@ -1,62 +1,62 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import scipy -import sys -import shutil -from scipy import io - -def move_valimg(val_dir='./val', devkit_dir='./ILSVRC2012_devkit_t12'): - """ - move valimg to correspongding folders. - val_id(start from 1) -> ILSVRC_ID(start from 1) -> WIND - organize like: - /val - /n01440764 - images - /n01443537 - images - ..... - """ - # load synset, val ground truth and val images list - synset = io.loadmat(os.path.join(devkit_dir, 'data', 'meta.mat')) - - ground_truth = open(os.path.join(devkit_dir, 'data', 'ILSVRC2012_validation_ground_truth.txt')) - lines = ground_truth.readlines() - labels = [int(line[:-1]) for line in lines] - - root, _, filenames = next(os.walk(val_dir)) - for filename in filenames: - # val image name -> ILSVRC ID -> WIND - val_id = int(filename.split('.')[0].split('_')[-1]) - ILSVRC_ID = labels[val_id-1] - WIND = synset['synsets'][ILSVRC_ID-1][0][1][0] - print("val_id:%d, ILSVRC_ID:%d, WIND:%s" % (val_id, ILSVRC_ID, WIND)) - - # move val images - output_dir = os.path.join(root, WIND) - if os.path.isdir(output_dir): - pass - else: - os.mkdir(output_dir) - shutil.move(os.path.join(root, filename), os.path.join(output_dir, filename)) - -def main(val_path, devkit_path): - move_valimg(val_path, devkit_path) - -if __name__ == '__main__': - val_path = sys.argv[1] - devkit_path = sys.argv[2] - main(val_path, devkit_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import scipy +import sys +import shutil +from scipy import io + +def move_valimg(val_dir='./val', devkit_dir='./ILSVRC2012_devkit_t12'): + """ + move valimg to correspongding folders. + val_id(start from 1) -> ILSVRC_ID(start from 1) -> WIND + organize like: + /val + /n01440764 + images + /n01443537 + images + ..... + """ + # load synset, val ground truth and val images list + synset = io.loadmat(os.path.join(devkit_dir, 'data', 'meta.mat')) + + ground_truth = open(os.path.join(devkit_dir, 'data', 'ILSVRC2012_validation_ground_truth.txt')) + lines = ground_truth.readlines() + labels = [int(line[:-1]) for line in lines] + + root, _, filenames = next(os.walk(val_dir)) + for filename in filenames: + # val image name -> ILSVRC ID -> WIND + val_id = int(filename.split('.')[0].split('_')[-1]) + ILSVRC_ID = labels[val_id-1] + WIND = synset['synsets'][ILSVRC_ID-1][0][1][0] + print("val_id:%d, ILSVRC_ID:%d, WIND:%s" % (val_id, ILSVRC_ID, WIND)) + + # move val images + output_dir = os.path.join(root, WIND) + if os.path.isdir(output_dir): + pass + else: + os.mkdir(output_dir) + shutil.move(os.path.join(root, filename), os.path.join(output_dir, filename)) + +def main(val_path, devkit_path): + move_valimg(val_path, devkit_path) + +if __name__ == '__main__': + val_path = sys.argv[1] + devkit_path = sys.argv[2] + main(val_path, devkit_path) diff --git a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/LICENSE b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/LICENSE index 29f81d812f..261eeb9e9f 100644 --- a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/README.md b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/README.md index edbf5b3267..aa1efa1719 100644 --- a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/README.md @@ -1,48 +1,48 @@ -# EfficientNet-B1模型PyTorch离线推理指导 -# 环境准备: - -1.数据集 - -测试数据集为ImageNet的官方 2012的val数据集,5w张图片放置在一个文件夹下,并由官方对应的 ILSVRC2012_devkit_t12 文件夹。 - -第一个参数为 新下载且未分类的 imagenet的val 数据集路径, - -第二个参数为官方 提供的 devkit 文件夹,如果要保留val文件夹请先备份 - -``` -python3.7 ImageNet_val_split.py ./val ./ILSVRC2012_devkit_t12 -``` - -2.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -``` -pip3.7 install -r requirements.txt -``` -3.获取模型代码 -``` -git clone https://github.com/facebookresearch/pycls -cd pycls -git reset f20820e01eef7b9a47b77f13464e3e77c44d5e1f --hard -cd .. -``` - -4.获取权重文件 -``` -wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/image_classification/EfficientNet-B1/EN-B1_dds_8gpu.pyth -``` -5.获取benchmark工具 -将benchmark.x86_64 benchmark.aarch64放在当前目录 - -# 2 离线推理 - -310上执行,执行时确保device空闲 -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets -``` -评测结果: - -| 模型 | 开源仓pth精度 | 310精度 | 性能基准 | 310性能 | -| :---------------: | :--------: | :--------------------: | :---------: | :---------: | -| Efficient-B1 bs1 | top1:75.9% | top1:75.5% top5:92.78% | 694.137fps | 940.524fps | -| Efficient-B1 bs16 | top1:75.9% | top1:75.5% top5:92.78% | 1408.138fps | 1490.54fps | - +# EfficientNet-B1模型PyTorch离线推理指导 +# 环境准备: + +1.数据集 + +测试数据集为ImageNet的官方 2012的val数据集,5w张图片放置在一个文件夹下,并由官方对应的 ILSVRC2012_devkit_t12 文件夹。 + +第一个参数为 新下载且未分类的 imagenet的val 数据集路径, + +第二个参数为官方 提供的 devkit 文件夹,如果要保留val文件夹请先备份 + +``` +python3.7 ImageNet_val_split.py ./val ./ILSVRC2012_devkit_t12 +``` + +2.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +``` +pip3.7 install -r requirements.txt +``` +3.获取模型代码 +``` +git clone https://github.com/facebookresearch/pycls +cd pycls +git reset f20820e01eef7b9a47b77f13464e3e77c44d5e1f --hard +cd .. +``` + +4.获取权重文件 +``` +wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/image_classification/EfficientNet-B1/EN-B1_dds_8gpu.pyth +``` +5.获取benchmark工具 +将benchmark.x86_64 benchmark.aarch64放在当前目录 + +# 2 离线推理 + +310上执行,执行时确保device空闲 +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets +``` +评测结果: + +| 模型 | 开源仓pth精度 | 310精度 | 性能基准 | 310性能 | +| :---------------: | :--------: | :--------------------: | :---------: | :---------: | +| Efficient-B1 bs1 | top1:75.9% | top1:75.5% top5:92.78% | 694.137fps | 940.524fps | +| Efficient-B1 bs16 | top1:75.9% | top1:75.5% top5:92.78% | 1408.138fps | 1490.54fps | + diff --git a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/gen_dataset_info.py index 9ecd822b4e..a07929cc79 100644 --- a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/gen_dataset_info.py @@ -1,43 +1,43 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - index = 0 - with open(info_name, 'w') as file: - for classes in os.listdir(file_path): - bin_dir_path = os.path.join(file_path, classes) - bin_images = glob(os.path.join(bin_dir_path, '*.bin')) - for img in bin_images: - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - index = index + 1 - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - assert file_type == 'bin', 'The file_type must is bin' - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + index = 0 + with open(info_name, 'w') as file: + for classes in os.listdir(file_path): + bin_dir_path = os.path.join(file_path, classes) + bin_images = glob(os.path.join(bin_dir_path, '*.bin')) + for img in bin_images: + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + index = index + 1 + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + assert file_type == 'bin', 'The file_type must is bin' + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' get_bin_info(file_path, info_name, width, height) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/modelzoo_level.txt index fc92458a08..76842f45b5 100644 --- a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PerfStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PerfStatus:OK +PrecisionStatus:OK AutoTune:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/requirements.txt b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/requirements.txt index 4e04e4fb8a..2b7911c419 100644 --- a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/requirements.txt +++ b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/requirements.txt @@ -1,9 +1,9 @@ -pytorch==1.5.0 -torchvision==0.6.0 -onnx==1.7.0 -numpy==1.18.5 -Pillow==7.2.0 -opencv-python3==1.0 -yacs -iopath +pytorch==1.5.0 +torchvision==0.6.0 +onnx==1.7.0 +numpy==1.18.5 +Pillow==7.2.0 +opencv-python3==1.0 +yacs +iopath submitit \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/test/parse.py b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/test/parse.py index 335e170932..5461d015b6 100644 --- a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/test/parse.py +++ b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1/test/parse.py @@ -1,41 +1,41 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): # Accuracy - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - print(content) - elif sys.argv[1].endswith('.txt'): # Perform - result_txt = sys.argv[1] - if 'PureInfer' in result_txt: # Pure Infer - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r'=(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[0].replace('samples/s', '')) * 4 - print('310 {} fps:{}'.format(result_txt.split('_')[3], fps)) - else: # Infer based on dataset - with open(result_txt, 'r') as f: - lines = f.readlines() - for line in lines: - if 'infer' in line: - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', line.replace('\n', ',') + ',')] - fps = float(txt_data_list[1]) * 4 - print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) - break +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): # Accuracy + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + print(content) + elif sys.argv[1].endswith('.txt'): # Perform + result_txt = sys.argv[1] + if 'PureInfer' in result_txt: # Pure Infer + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r'=(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[0].replace('samples/s', '')) * 4 + print('310 {} fps:{}'.format(result_txt.split('_')[3], fps)) + else: # Infer based on dataset + with open(result_txt, 'r') as f: + lines = f.readlines() + for line in lines: + if 'infer' in line: + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', line.replace('\n', ',') + ',')] + fps = float(txt_data_list[1]) * 4 + print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) + break diff --git a/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B3/README.md b/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B3/README.md old mode 100755 new mode 100644 diff --git a/ACL_PyTorch/contrib/cv/classfication/FixRes/README.md b/ACL_PyTorch/contrib/cv/classfication/FixRes/README.md index f6ac6db0fb..e1f6a17863 100644 --- a/ACL_PyTorch/contrib/cv/classfication/FixRes/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/FixRes/README.md @@ -1,43 +1,43 @@ -# FixRes模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -``` -pip3.7 install -r requirements.txt -``` - - -2.获取,修改与安装开源模型代码 -``` -git clone https://github.com/facebookresearch/FixRes.git -b main -cd FixRes -git reset c9be6acc7a6b32f896e62c28a97c20c2348327d3 --hard -cd .. -``` - -3.获取权重文件 - -FixResNet50.pth - -4.数据集 -获取ImageNet 2012 - -5.[获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) -将benchmark.x86_64或benchmark.aarch64放到当前目录 - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲。测试时需下载imagenet_labels_fixres.json文件,并放在imagenet文件夹下。 -``` -# 生成om模型 -bash test/pth2om.sh - -# om模型离线推理并测试 -bash test/eval_acc_perf.sh --datasets_path=/root/datasets -``` - **评测结果:** -| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | -| :------: | :------: | :------: | :------: | :------: | -| FixRes bs1 | [rank1:79.0%](https://github.com/facebookresearch/FixRes) | rank1:79.0% | 507fps | 785.208fps | -| FixRes bs16 | [rank1:79.0%](https://github.com/facebookresearch/FixRes) | rank1:79.0% | 734fps | 788.566fps | +# FixRes模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +``` +pip3.7 install -r requirements.txt +``` + + +2.获取,修改与安装开源模型代码 +``` +git clone https://github.com/facebookresearch/FixRes.git -b main +cd FixRes +git reset c9be6acc7a6b32f896e62c28a97c20c2348327d3 --hard +cd .. +``` + +3.获取权重文件 + +FixResNet50.pth + +4.数据集 +获取ImageNet 2012 + +5.[获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) +将benchmark.x86_64或benchmark.aarch64放到当前目录 + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲。测试时需下载imagenet_labels_fixres.json文件,并放在imagenet文件夹下。 +``` +# 生成om模型 +bash test/pth2om.sh + +# om模型离线推理并测试 +bash test/eval_acc_perf.sh --datasets_path=/root/datasets +``` + **评测结果:** +| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | +| :------: | :------: | :------: | :------: | :------: | +| FixRes bs1 | [rank1:79.0%](https://github.com/facebookresearch/FixRes) | rank1:79.0% | 507fps | 785.208fps | +| FixRes bs16 | [rank1:79.0%](https://github.com/facebookresearch/FixRes) | rank1:79.0% | 734fps | 788.566fps | diff --git a/ACL_PyTorch/contrib/cv/classfication/FixRes/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/classfication/FixRes/modelzoo_level.txt index 38700fca05..2e42553460 100644 --- a/ACL_PyTorch/contrib/cv/classfication/FixRes/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/classfication/FixRes/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/GENet/LICENSE b/ACL_PyTorch/contrib/cv/classfication/GENet/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/GENet/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/GENet/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/GENet/cifar10_acc_eval.py b/ACL_PyTorch/contrib/cv/classfication/GENet/cifar10_acc_eval.py index b4909b98e9..c09177bd36 100644 --- a/ACL_PyTorch/contrib/cv/classfication/GENet/cifar10_acc_eval.py +++ b/ACL_PyTorch/contrib/cv/classfication/GENet/cifar10_acc_eval.py @@ -1,186 +1,186 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - if data == '': - n_label = 0 - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = 0 - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - print(sort_index) - gt = img_gt_dict[img_name] - print(gt) - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - - resCnt = min(len(sort_index), topn) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) - print("Time used:", elapsed) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + if data == '': + n_label = 0 + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = 0 + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + print(sort_index) + gt = img_gt_dict[img_name] + print(gt) + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + + resCnt = min(len(sort_index), topn) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) + print("Time used:", elapsed) diff --git a/ACL_PyTorch/contrib/cv/classfication/GENet/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/classfication/GENet/modelzoo_level.txt index 8aa12b7f8c..1073929d0d 100644 --- a/ACL_PyTorch/contrib/cv/classfication/GENet/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/classfication/GENet/modelzoo_level.txt @@ -1,6 +1,6 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK -PerfStatus:OK -ModelConvert:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK +PerfStatus:OK +ModelConvert:OK QuantStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/GENet/test/infer_bin.sh b/ACL_PyTorch/contrib/cv/classfication/GENet/test/infer_bin.sh index feff85f5dd..9f64b810a0 100644 --- a/ACL_PyTorch/contrib/cv/classfication/GENet/test/infer_bin.sh +++ b/ACL_PyTorch/contrib/cv/classfication/GENet/test/infer_bin.sh @@ -1,2 +1,2 @@ -benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=genet_bs1_tuned.om -input_text_path=genet_prep_bin.info -input_width=32 -input_height=32 -output_binary=False -useDvpp=False +benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=genet_bs1_tuned.om -input_text_path=genet_prep_bin.info -input_width=32 -input_height=32 -output_binary=False -useDvpp=False benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=16 -om_path=genet_bs16_tuned.om -input_text_path=genet_prep_bin.info -input_width=32 -input_height=32 -output_binary=False -useDvpp=False \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/LICENSE b/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/ghostnet_pth2onnx.py b/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/ghostnet_pth2onnx.py index e74fdc48c2..27218ecece 100644 --- a/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/ghostnet_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/ghostnet_pth2onnx.py @@ -1,33 +1,33 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import sys -sys.path.append("./CV-Backbones/ghostnet_pytorch") -from ghostnet import ghostnet - -def pth2onnx(input_file, output_file): - model = ghostnet() - model.load_state_dict(torch.load(input_file)) - model.eval() - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.randn(1, 3, 224, 224) - torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, opset_version=11, verbose=True) - -if __name__=="__main__": - input_file = sys.argv[1] - output_file = sys.argv[2] - pth2onnx(input_file, output_file) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import sys +sys.path.append("./CV-Backbones/ghostnet_pytorch") +from ghostnet import ghostnet + +def pth2onnx(input_file, output_file): + model = ghostnet() + model.load_state_dict(torch.load(input_file)) + model.eval() + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.randn(1, 3, 224, 224) + torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, opset_version=11, verbose=True) + +if __name__=="__main__": + input_file = sys.argv[1] + output_file = sys.argv[2] + pth2onnx(input_file, output_file) diff --git a/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/imagenet_torch_preprocess.py b/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/imagenet_torch_preprocess.py index 92885b0a3f..6ff9be5592 100644 --- a/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/imagenet_torch_preprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/imagenet_torch_preprocess.py @@ -1,122 +1,122 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -from PIL import Image -import numpy as np -import multiprocessing - - -model_config = { - 'resnet': { - 'resize': 256, - 'centercrop': 224, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv3': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv4': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.5, 0.5, 0.5], - 'std': [0.5, 0.5, 0.5], - }, - 'ghostnet':{ - 'resize': 256, - 'centercrop': 224, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - } -} - - -def center_crop(img, output_size): - if isinstance(output_size, int): - output_size = (int(output_size), int(output_size)) - image_width, image_height = img.size - crop_height, crop_width = output_size - crop_top = int(round((image_height - crop_height) / 2.)) - crop_left = int(round((image_width - crop_width) / 2.)) - return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) - - -def resize(img, size, interpolation=Image.BILINEAR): - if isinstance(size, int): - w, h = img.size - if (w <= h and w == size) or (h <= w and h == size): - return img - if w < h: - ow = size - oh = int(size * h / w) - return img.resize((ow, oh), interpolation) - else: - oh = size - ow = int(size * w / h) - return img.resize((ow, oh), interpolation) - else: - return img.resize(size[::-1], interpolation) - - -def gen_input_bin(mode_type, file_batches, batch): - i = 0 - for file in file_batches[batch]: - i = i + 1 - print("batch", batch, file, "===", i) - - # RGBA to RGB - image = Image.open(os.path.join(src_path, file)).convert('RGB') - image = resize(image, model_config[mode_type]['resize']) # Resize - image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop - img = np.array(image, dtype=np.float32) - img = img.transpose(2, 0, 1) # ToTensor: HWC -> CHW - img = img / 255. # ToTensor: div 255 - img -= np.array(model_config[mode_type]['mean'], dtype=np.float32)[:, None, None] # Normalize: mean - img /= np.array(model_config[mode_type]['std'], dtype=np.float32)[:, None, None] # Normalize: std - img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) - - -def preprocess(mode_type, src_path, save_path): - files = os.listdir(src_path) - file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] - thread_pool = multiprocessing.Pool(len(file_batches)) - for batch in range(len(file_batches)): - thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) - thread_pool.close() - thread_pool.join() - print("in thread, except will not report! please ensure bin files generated.") - - -if __name__ == '__main__': - if len(sys.argv) < 4: - raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") - mode_type = sys.argv[1] - src_path = sys.argv[2] - save_path = sys.argv[3] - src_path = os.path.realpath(src_path) - save_path = os.path.realpath(save_path) - if mode_type not in model_config: - model_type_help = "model type: " - for key in model_config.keys(): - model_type_help += key - model_type_help += ' ' - raise Exception(model_type_help) - if not os.path.isdir(save_path): - os.makedirs(os.path.realpath(save_path)) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +from PIL import Image +import numpy as np +import multiprocessing + + +model_config = { + 'resnet': { + 'resize': 256, + 'centercrop': 224, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv3': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv4': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.5, 0.5, 0.5], + 'std': [0.5, 0.5, 0.5], + }, + 'ghostnet':{ + 'resize': 256, + 'centercrop': 224, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + } +} + + +def center_crop(img, output_size): + if isinstance(output_size, int): + output_size = (int(output_size), int(output_size)) + image_width, image_height = img.size + crop_height, crop_width = output_size + crop_top = int(round((image_height - crop_height) / 2.)) + crop_left = int(round((image_width - crop_width) / 2.)) + return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) + + +def resize(img, size, interpolation=Image.BILINEAR): + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def gen_input_bin(mode_type, file_batches, batch): + i = 0 + for file in file_batches[batch]: + i = i + 1 + print("batch", batch, file, "===", i) + + # RGBA to RGB + image = Image.open(os.path.join(src_path, file)).convert('RGB') + image = resize(image, model_config[mode_type]['resize']) # Resize + image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop + img = np.array(image, dtype=np.float32) + img = img.transpose(2, 0, 1) # ToTensor: HWC -> CHW + img = img / 255. # ToTensor: div 255 + img -= np.array(model_config[mode_type]['mean'], dtype=np.float32)[:, None, None] # Normalize: mean + img /= np.array(model_config[mode_type]['std'], dtype=np.float32)[:, None, None] # Normalize: std + img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) + + +def preprocess(mode_type, src_path, save_path): + files = os.listdir(src_path) + file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] + thread_pool = multiprocessing.Pool(len(file_batches)) + for batch in range(len(file_batches)): + thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) + thread_pool.close() + thread_pool.join() + print("in thread, except will not report! please ensure bin files generated.") + + +if __name__ == '__main__': + if len(sys.argv) < 4: + raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") + mode_type = sys.argv[1] + src_path = sys.argv[2] + save_path = sys.argv[3] + src_path = os.path.realpath(src_path) + save_path = os.path.realpath(save_path) + if mode_type not in model_config: + model_type_help = "model type: " + for key in model_config.keys(): + model_type_help += key + model_type_help += ' ' + raise Exception(model_type_help) + if not os.path.isdir(save_path): + os.makedirs(os.path.realpath(save_path)) preprocess(mode_type, src_path, save_path) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/requirements.txt b/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/requirements.txt index 9b075f0172..0ce89e67a6 100644 --- a/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/requirements.txt +++ b/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/requirements.txt @@ -1,6 +1,6 @@ -torch == 1.6.0 -torchvision == 0.7.0 -onnx == 1.7.0 -numpy == 1.18.5 -Pillow == 7.2.0 +torch == 1.6.0 +torchvision == 0.7.0 +onnx == 1.7.0 +numpy == 1.18.5 +Pillow == 7.2.0 opencv-python == 4.5.1.48 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/test/README.md b/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/test/README.md index d9024b48e5..fe76d976f3 100644 --- a/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/test/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x/test/README.md @@ -1,24 +1,24 @@ -环境准备: - -1.数据集路径 -通用的数据集统一放在/root/datasets/或/opt/npu/ -本模型数据集放在/root/datasets/ - -2.进入工作目录 -cd GhostNet1.0x - -3.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -pip3.7 install -r requirements.txt - -4.获取模型代码 -git clone https://github.com/huawei-noah/CV-Backbones.git - -5.获取权重文件 -cp ./CV-Backbones/ghostnet_pytorch/models/state_dict_73.98.pth . - -6.获取benchmark工具 -将benchmark.x86_64 benchmark.aarch64放在当前目录 - -7.310上执行,执行时确保device空闲 -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets +环境准备: + +1.数据集路径 +通用的数据集统一放在/root/datasets/或/opt/npu/ +本模型数据集放在/root/datasets/ + +2.进入工作目录 +cd GhostNet1.0x + +3.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +pip3.7 install -r requirements.txt + +4.获取模型代码 +git clone https://github.com/huawei-noah/CV-Backbones.git + +5.获取权重文件 +cp ./CV-Backbones/ghostnet_pytorch/models/state_dict_73.98.pth . + +6.获取benchmark工具 +将benchmark.x86_64 benchmark.aarch64放在当前目录 + +7.310上执行,执行时确保device空闲 +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets diff --git a/ACL_PyTorch/contrib/cv/classfication/GloRe/GloRe_pth2onnx.py b/ACL_PyTorch/contrib/cv/classfication/GloRe/GloRe_pth2onnx.py index 3d9975c78b..c1f7f6f764 100644 --- a/ACL_PyTorch/contrib/cv/classfication/GloRe/GloRe_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/classfication/GloRe/GloRe_pth2onnx.py @@ -1,33 +1,33 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import sys -import os -from GloRe.network.resnet50_3d_gcn_x5 import RESNET50_3D_GCN_X5 -def pth2onnx(input_file, output_file): - net = RESNET50_3D_GCN_X5(num_classes=101, pretrained=False) - state_dict = torch.load(input_file,map_location='cpu') - net.load_state_dict(state_dict['state_dict']) - net.eval() - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.randn(1, 3, 8, 224, 224) - torch.onnx.export(net, dummy_input, output_file, input_names=input_names, dynamic_axes=dynamic_axes, - output_names=output_names, opset_version=11, verbose=True) - - -if __name__ == '__main__': - args = sys.argv - pth2onnx(args[1], args[2]) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import sys +import os +from GloRe.network.resnet50_3d_gcn_x5 import RESNET50_3D_GCN_X5 +def pth2onnx(input_file, output_file): + net = RESNET50_3D_GCN_X5(num_classes=101, pretrained=False) + state_dict = torch.load(input_file,map_location='cpu') + net.load_state_dict(state_dict['state_dict']) + net.eval() + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.randn(1, 3, 8, 224, 224) + torch.onnx.export(net, dummy_input, output_file, input_names=input_names, dynamic_axes=dynamic_axes, + output_names=output_names, opset_version=11, verbose=True) + + +if __name__ == '__main__': + args = sys.argv + pth2onnx(args[1], args[2]) diff --git a/ACL_PyTorch/contrib/cv/classfication/GloRe/LICENSE b/ACL_PyTorch/contrib/cv/classfication/GloRe/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/GloRe/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/GloRe/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/GloRe/README.md b/ACL_PyTorch/contrib/cv/classfication/GloRe/README.md index 715965b432..8cd66f582a 100644 --- a/ACL_PyTorch/contrib/cv/classfication/GloRe/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/GloRe/README.md @@ -1,43 +1,43 @@ -# GloRe模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 - -``` -pip3.7 install -r requirements.txt -``` - -2.获取,修改与安装开源模型代码 - -``` - -git clone https://github.com/facebookresearch/GloRe -b master -cd GloRe -git reset --hard 9c6a7340ebb44a66a3bf1945094fc685fb7b730d -cd .. -``` -3.[获取基于UCF101数据集训练出来的权重](https://ascend-pytorch-model-file.obs.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/classfication/GloRe/GloRe.pth) - - -4.[获取数据集UCF101](https://www.crcv.ucf.edu/data/UCF101/UCF101.rar) - - -5.[获取msame工具](https://gitee.com/ascend/tools/tree/master/msame) - -6.[获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) - -将benchmark.x86_64或benchmark.aarch64放到当前目录 - - - -## 2 离线推理 -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets/UCF-101 -``` - | 模型 | pth精度 | 310精度 | 基准性能 | 310性能 | - | :------: | :------: | :------: | :------: | :------: | - | GloRe bs1 | top1:87.79% top5:98.02% | top1:87.77% top5:98.05% | 122.4380fps | 67.3636fps | - | GloRe bs16 | top1:87.79% top5:98.02% | top1:87.77% top5:98.05% | 148.0453fps | 71.7856fps | +# GloRe模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 + +``` +pip3.7 install -r requirements.txt +``` + +2.获取,修改与安装开源模型代码 + +``` + +git clone https://github.com/facebookresearch/GloRe -b master +cd GloRe +git reset --hard 9c6a7340ebb44a66a3bf1945094fc685fb7b730d +cd .. +``` +3.[获取基于UCF101数据集训练出来的权重](https://ascend-pytorch-model-file.obs.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/classfication/GloRe/GloRe.pth) + + +4.[获取数据集UCF101](https://www.crcv.ucf.edu/data/UCF101/UCF101.rar) + + +5.[获取msame工具](https://gitee.com/ascend/tools/tree/master/msame) + +6.[获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) + +将benchmark.x86_64或benchmark.aarch64放到当前目录 + + + +## 2 离线推理 +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets/UCF-101 +``` + | 模型 | pth精度 | 310精度 | 基准性能 | 310性能 | + | :------: | :------: | :------: | :------: | :------: | + | GloRe bs1 | top1:87.79% top5:98.02% | top1:87.77% top5:98.05% | 122.4380fps | 67.3636fps | + | GloRe bs16 | top1:87.79% top5:98.02% | top1:87.77% top5:98.05% | 148.0453fps | 71.7856fps | diff --git a/ACL_PyTorch/contrib/cv/classfication/GloRe/env.sh b/ACL_PyTorch/contrib/cv/classfication/GloRe/env.sh index 7cf86a22a6..e4c421dd8d 100644 --- a/ACL_PyTorch/contrib/cv/classfication/GloRe/env.sh +++ b/ACL_PyTorch/contrib/cv/classfication/GloRe/env.sh @@ -1,6 +1,6 @@ -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp export ASCEND_AICPU_PATH=${install_path} \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/GloRe/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/classfication/GloRe/modelzoo_level.txt index 20e36b3f78..85fa1416d3 100644 --- a/ACL_PyTorch/contrib/cv/classfication/GloRe/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/classfication/GloRe/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus:NOK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/GloRe/requirements.txt b/ACL_PyTorch/contrib/cv/classfication/GloRe/requirements.txt index dfd372e307..384b6e6208 100644 --- a/ACL_PyTorch/contrib/cv/classfication/GloRe/requirements.txt +++ b/ACL_PyTorch/contrib/cv/classfication/GloRe/requirements.txt @@ -1,6 +1,6 @@ -torch == 1.5.0 -torchvision == 0.6.0 -onnx == 1.7.0 -numpy == 1.21.1 -Pillow == 8.2.0 +torch == 1.5.0 +torchvision == 0.6.0 +onnx == 1.7.0 +numpy == 1.21.1 +Pillow == 8.2.0 opencv_python == 4.5.3.56 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/GloRe/test/parse.py b/ACL_PyTorch/contrib/cv/classfication/GloRe/test/parse.py index b9c74f41d7..82af69cd18 100644 --- a/ACL_PyTorch/contrib/cv/classfication/GloRe/test/parse.py +++ b/ACL_PyTorch/contrib/cv/classfication/GloRe/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/LICENSE b/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/LICENSE index 657549b860..dcc65541a1 100644 --- a/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/LICENSE @@ -1,30 +1,30 @@ -BSD 3-Clause License - -Copyright (c) 2017, -All rights reserved. -Copyright 2020 Huawei Technologies Co., Ltd - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +BSD 3-Clause License + +Copyright (c) 2017, +All rights reserved. +Copyright 2020 Huawei Technologies Co., Ltd + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/README.md b/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/README.md index 74462c68cf..90da3dd00b 100644 --- a/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/README.md @@ -1,270 +1,270 @@ -# HRNet Onnx模型端到端推理指导 -- [1 模型概述](#1-模型概述) - - [1.1 论文地址](#11-论文地址) - - [1.2 代码地址](#12-代码地址) -- [2 环境说明](#2-环境说明) - - [2.1 深度学习框架](#21-深度学习框架) - - [2.2 python第三方库](#22-python第三方库) -- [3 模型转换](#3-模型转换) - - [3.1 pth转onnx模型](#31-pth转onnx模型) - - [3.2 onnx转om模型](#32-onnx转om模型) -- [4 数据集预处理](#4-数据集预处理) - - [4.1 数据集获取](#41-数据集获取) - - [4.2 数据集预处理](#42-数据集预处理) - - [4.3 生成数据集信息文件](#43-生成数据集信息文件) -- [5 离线推理](#5-离线推理) - - [5.1 benchmark工具概述](#51-benchmark工具概述) - - [5.2 离线推理](#52-离线推理) -- [6 精度对比](#6-精度对比) - - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) - - [6.2 开源TopN精度](#62-开源TopN精度) - - [6.3 精度对比](#63-精度对比) -- [7 性能对比](#7-性能对比) - - [7.1 npu性能数据](#71-npu性能数据) - - - -## 1 模型概述 - -- **[论文地址](#11-论文地址)** - -- **[代码地址](#12-代码地址)** - -### 1.1 论文地址 -[HRNet论文](https://arxiv.org/pdf/1908.07919.pdf) -Abstract—High-resolution representations are essential for position-sensitive vision problems, such as human pose estimation, semantic segmentation, and object detection. Existing state-of-the-art frameworks first encode the input image as a low-resolution representation through a subnetwork that is formed by connecting high-to-low resolution convolutions in series (e.g., ResNet, VGGNet), and then recover the high-resolution representation from the encoded low-resolution representation. Instead, our proposed network, named as High-Resolution Network (HRNet), maintains high-resolution representations through the whole process. There are two key characteristics: (i) Connect the high-to-low resolution convolution streams in parallel; (ii) Repeatedly exchange the information across resolutions. The benefit is that the resulting representation is semantically richer and spatially more precise. We show the superiority of the proposed HRNet in a wide range of applications, including human pose estimation, semantic segmentation, and object detection, suggesting that the HRNet is a stronger backbone for computer vision problems. All the codes are available at https://github.com/HRNet. - -### 1.2 代码地址 -[HRNet代码](https://github.com/HRNet/HRNet-Image-Classification) -branch:master -commit_id:f130a24bf09b7f23ebd0075271f76c4a188093b2 - -## 2 环境说明 - -- **[深度学习框架](#21-深度学习框架)** - -- **[python第三方库](#22-python第三方库)** - -### 2.1 深度学习框架 -``` -pytorch >= 1.5.0 -torchvision >= 0.6.0 -onnx >= 1.7.0 -``` - -### 2.2 python第三方库 - -``` -numpy == 1.20.2 -opencv-python == 4.5.2.52 -Pillow == 8.0.1 -``` - -**说明:** -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3 模型转换 - -- **[pth转onnx模型](#31-pth转onnx模型)** - -- **[onnx转om模型](#32-onnx转om模型)** - -### 3.1 pth转onnx模型 - -1.下载HRNet模型 -git clone https://github.com/HRNet/HRNet-Image-Classification.git - -2.获取权重文件 -wget https://ascend-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/image_classification/HRNet/NPU/8P/model_best.pth.tar -file name:model_best.pth.tar -md5sum:1f1d61e242ac9ca4cab5d0c49299cb76 - -3.编写pth2onnx脚本hrnet_pth2onnx.py - - **说明:** ->注意目前ATC支持的onnx算子版本为11 - -4.执行pth2onnx脚本,生成onnx模型文件 -``` -python3.7 hrnet_pth2onnx.py --cfg ./HRNet-Image-Classification/experiments/cls_hrnet_w18_sgd_lr5e-2_wd1e-4_bs32_x100.yaml --input model_best.pth.tar --output hrnet_w18.onnx -``` - - **模型转换要点:** ->此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 - -### 3.2 onnx转om模型 - -1.设置环境变量 -``` -source env.sh -``` -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) - -``` -atc --framework=5 --model=./hrnet_w18.onnx --input_format=NCHW --input_shape="image:16,3,224,224" --output=hrnet_bs16 --log=debug --soc_version=Ascend310 -``` - -## 4 数据集预处理 - -- **[数据集获取](#41-数据集获取)** - -- **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - -### 4.1 数据集获取 -该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/opt/npu/imagenet/val与/opt/npu/imagenet/val_label.txt。 - -### 4.2 数据集预处理 -1.预处理脚本imagenet_torch_preprocess.py - -2.执行预处理脚本,生成数据集预处理后的bin文件 - -``` -datasets_path = '/opt/npu/' -python3.7 imagenet_torch_preprocess.py hrnet ${datasets_path}/imagenet/val ./prep_dataset -``` -### 4.3 生成数据集信息文件 -1.生成数据集信息文件脚本get_info.py - -2.执行生成数据集信息脚本,生成数据集信息文件 - -``` -python3.7 get_info.py bin ./prep_dataset ./hrnet_prep_bin.info 224 224 -``` -第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 -## 5 离线推理 - -- **[benchmark工具概述](#51-benchmark工具概述)** - -- **[离线推理](#52-离线推理)** - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) -### 5.2 离线推理 -1.设置环境变量 - -``` -source env.sh -``` -2.执行离线推理 -``` -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=16 -om_path=hrnet_bs16.om -input_text_path=./hrnet_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False -``` -输出结果默认保存在当前目录result/dumpOutput_devicex,模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 - -## 6 精度对比 - -- **[离线推理TopN精度](#61-离线推理TopN精度)** -- **[开源TopN精度](#62-开源TopN精度)** -- **[精度对比](#63-精度对比)** - -### 6.1 离线推理TopN精度统计 - -后处理统计TopN精度 - -调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 -``` -python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ ${datasets_path}/imagenet/val_label.txt ./ result.json -``` -第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 -查看输出结果: - -``` -{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value": "76.46%"}, {"key": "Top2 accuracy", "value": "86.33%"}, {"key": "Top3 accuracy", "value": "90.0%"}, {"key": "Top4 accuracy", "value": "91.97%"}, {"key": "Top5 accuracy", "value": "93.14%"}]} -``` -batch1,batch16的精度相同如上. - -### 6.2 开源TopN精度 -[torchvision官网精度](https://pytorch.org/vision/stable/models.html) -``` -Model Acc@1 Acc@5 -HRNet-Image-Classification 76.8 93.4 -``` -### 6.3 精度对比 -将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 - **精度调试:** ->没有遇到精度不达标的问题,故不需要进行精度调试 - -## 7 性能对比 - -- **[npu性能数据](#71-npu性能数据)** - -### 7.1 npu性能数据 -需要测试batch1,batch4,batch8,batch16,batch32的性能,这里用batch1与batch16做示例 -benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device。为快速获取性能数据,也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准。这里给出两种方式,模型的测试脚本使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准。 -1.benchmark工具在整个数据集上推理获得性能数据 -以batch1为例,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: - -``` -[e2e] throughputRate: 125.08, latency: 399743 -[data read] throughputRate: 132.686, moduleLatency: 7.53661 -[preprocess] throughputRate: 132.548, moduleLatency: 7.54441 -[infer] throughputRate: 125.448, Interface throughputRate: 156.216, moduleLatency: 7.35352 -[post] throughputRate: 125.448, moduleLatency: 7.97142 -``` -Interface throughputRate: 156.216,156.216乘以4既是310单卡吞吐率 -2.benchmark纯推理功能测得性能数据 -batch1的性能: - 测试npu性能要确保device空闲,使用npu-smi info命令可查看device是否在运行其它推理任务 - -``` -./benchmark.x86_64 -round=20 -om_path=hrnet_bs1.om -device_id=0 -batch_size=1 -``` -执行20次纯推理取均值,统计吞吐率与其倒数时延(benchmark的时延是单个数据的推理时间),npu性能是一个device执行的结果 -``` -[INFO] Dataset number: 19 finished cost 2.635ms -[INFO] PureInfer result saved in ./result/PureInfer_perf_of_hrnet_bs1_in_device_0.txt ------------------PureInfer Performance Summary------------------ -ave_throughputRate = 155.975samples/s, ave_latency = 6.42435ms -``` -bs1 310单卡吞吐率:155.975x4=623.9fps/card -batch4的性能: -``` -./benchmark.x86_64 -round=20 -om_path=hrnet_w18_bs4.om -device_id=0 -batch_size=4 -``` -``` -[INFO] PureInfer result saved in ./result/PureInfer_perf_of_hrnet_w18_bs4_in_device_0.txt ------------------PureInfer Performance Summary------------------ -[INFO] ave_throughputRate: 224.608samples/s, ave_latency: 4.56663ms -``` -bs4 310单卡吞吐率:224.608x4=898.432fps/card -batch8的性能: -``` -./benchmark.x86_64 -round=20 -om_path=hrnet_w18_bs8.om -device_id=0 -batch_size=8 -``` -``` -[INFO] PureInfer result saved in ./result/PureInfer_perf_of_hrnet_w18_bs8_in_device_0.txt ------------------PureInfer Performance Summary------------------ -[INFO] ave_throughputRate: 248.514samples/s, ave_latency: 4.09695ms -``` -bs8 310单卡吞吐率:248.514x4=994.056fps/card -batch16的性能: - -``` -./benchmark.x86_64 -round=20 -om_path=hrnet_w18_bs16.om -device_id=0 -batch_size=16 -``` -``` -[INFO] PureInfer result saved in ./result/PureInfer_perf_of_hrnet_w18_bs16_in_device_0.txt ------------------PureInfer Performance Summary------------------ -[INFO] ave_throughputRate: 269.512samples/s, ave_latency: 3.73541ms -``` -bs16 310单卡吞吐率:269.512x4=1078.048fps/card -batch32的性能: -``` -./benchmark.x86_64 -round=20 -om_path=hrnet_w18_bs32.om -device_id=0 -batch_size=32 -``` -``` -[INFO] PureInfer result saved in ./result/PureInfer_perf_of_hrnet_w18_bs32_in_device_0.txt ------------------PureInfer Performance Summary------------------ -[INFO] ave_throughputRate: 271.562samples/s, ave_latency: 3.69597ms -``` -bs32 310单卡吞吐率:271.562x4=1086.248fps/card - - **性能优化:** - ->没有遇到性能不达标的问题,故不需要进行性能优化 - +# HRNet Onnx模型端到端推理指导 +- [1 模型概述](#1-模型概述) + - [1.1 论文地址](#11-论文地址) + - [1.2 代码地址](#12-代码地址) +- [2 环境说明](#2-环境说明) + - [2.1 深度学习框架](#21-深度学习框架) + - [2.2 python第三方库](#22-python第三方库) +- [3 模型转换](#3-模型转换) + - [3.1 pth转onnx模型](#31-pth转onnx模型) + - [3.2 onnx转om模型](#32-onnx转om模型) +- [4 数据集预处理](#4-数据集预处理) + - [4.1 数据集获取](#41-数据集获取) + - [4.2 数据集预处理](#42-数据集预处理) + - [4.3 生成数据集信息文件](#43-生成数据集信息文件) +- [5 离线推理](#5-离线推理) + - [5.1 benchmark工具概述](#51-benchmark工具概述) + - [5.2 离线推理](#52-离线推理) +- [6 精度对比](#6-精度对比) + - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) + - [6.2 开源TopN精度](#62-开源TopN精度) + - [6.3 精度对比](#63-精度对比) +- [7 性能对比](#7-性能对比) + - [7.1 npu性能数据](#71-npu性能数据) + + + +## 1 模型概述 + +- **[论文地址](#11-论文地址)** + +- **[代码地址](#12-代码地址)** + +### 1.1 论文地址 +[HRNet论文](https://arxiv.org/pdf/1908.07919.pdf) +Abstract—High-resolution representations are essential for position-sensitive vision problems, such as human pose estimation, semantic segmentation, and object detection. Existing state-of-the-art frameworks first encode the input image as a low-resolution representation through a subnetwork that is formed by connecting high-to-low resolution convolutions in series (e.g., ResNet, VGGNet), and then recover the high-resolution representation from the encoded low-resolution representation. Instead, our proposed network, named as High-Resolution Network (HRNet), maintains high-resolution representations through the whole process. There are two key characteristics: (i) Connect the high-to-low resolution convolution streams in parallel; (ii) Repeatedly exchange the information across resolutions. The benefit is that the resulting representation is semantically richer and spatially more precise. We show the superiority of the proposed HRNet in a wide range of applications, including human pose estimation, semantic segmentation, and object detection, suggesting that the HRNet is a stronger backbone for computer vision problems. All the codes are available at https://github.com/HRNet. + +### 1.2 代码地址 +[HRNet代码](https://github.com/HRNet/HRNet-Image-Classification) +branch:master +commit_id:f130a24bf09b7f23ebd0075271f76c4a188093b2 + +## 2 环境说明 + +- **[深度学习框架](#21-深度学习框架)** + +- **[python第三方库](#22-python第三方库)** + +### 2.1 深度学习框架 +``` +pytorch >= 1.5.0 +torchvision >= 0.6.0 +onnx >= 1.7.0 +``` + +### 2.2 python第三方库 + +``` +numpy == 1.20.2 +opencv-python == 4.5.2.52 +Pillow == 8.0.1 +``` + +**说明:** +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3 模型转换 + +- **[pth转onnx模型](#31-pth转onnx模型)** + +- **[onnx转om模型](#32-onnx转om模型)** + +### 3.1 pth转onnx模型 + +1.下载HRNet模型 +git clone https://github.com/HRNet/HRNet-Image-Classification.git + +2.获取权重文件 +wget https://ascend-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/image_classification/HRNet/NPU/8P/model_best.pth.tar +file name:model_best.pth.tar +md5sum:1f1d61e242ac9ca4cab5d0c49299cb76 + +3.编写pth2onnx脚本hrnet_pth2onnx.py + + **说明:** +>注意目前ATC支持的onnx算子版本为11 + +4.执行pth2onnx脚本,生成onnx模型文件 +``` +python3.7 hrnet_pth2onnx.py --cfg ./HRNet-Image-Classification/experiments/cls_hrnet_w18_sgd_lr5e-2_wd1e-4_bs32_x100.yaml --input model_best.pth.tar --output hrnet_w18.onnx +``` + + **模型转换要点:** +>此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 + +### 3.2 onnx转om模型 + +1.设置环境变量 +``` +source env.sh +``` +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) + +``` +atc --framework=5 --model=./hrnet_w18.onnx --input_format=NCHW --input_shape="image:16,3,224,224" --output=hrnet_bs16 --log=debug --soc_version=Ascend310 +``` + +## 4 数据集预处理 + +- **[数据集获取](#41-数据集获取)** + +- **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + +### 4.1 数据集获取 +该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/opt/npu/imagenet/val与/opt/npu/imagenet/val_label.txt。 + +### 4.2 数据集预处理 +1.预处理脚本imagenet_torch_preprocess.py + +2.执行预处理脚本,生成数据集预处理后的bin文件 + +``` +datasets_path = '/opt/npu/' +python3.7 imagenet_torch_preprocess.py hrnet ${datasets_path}/imagenet/val ./prep_dataset +``` +### 4.3 生成数据集信息文件 +1.生成数据集信息文件脚本get_info.py + +2.执行生成数据集信息脚本,生成数据集信息文件 + +``` +python3.7 get_info.py bin ./prep_dataset ./hrnet_prep_bin.info 224 224 +``` +第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 +## 5 离线推理 + +- **[benchmark工具概述](#51-benchmark工具概述)** + +- **[离线推理](#52-离线推理)** + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) +### 5.2 离线推理 +1.设置环境变量 + +``` +source env.sh +``` +2.执行离线推理 +``` +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=16 -om_path=hrnet_bs16.om -input_text_path=./hrnet_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False +``` +输出结果默认保存在当前目录result/dumpOutput_devicex,模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 + +## 6 精度对比 + +- **[离线推理TopN精度](#61-离线推理TopN精度)** +- **[开源TopN精度](#62-开源TopN精度)** +- **[精度对比](#63-精度对比)** + +### 6.1 离线推理TopN精度统计 + +后处理统计TopN精度 + +调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 +``` +python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ ${datasets_path}/imagenet/val_label.txt ./ result.json +``` +第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 +查看输出结果: + +``` +{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value": "76.46%"}, {"key": "Top2 accuracy", "value": "86.33%"}, {"key": "Top3 accuracy", "value": "90.0%"}, {"key": "Top4 accuracy", "value": "91.97%"}, {"key": "Top5 accuracy", "value": "93.14%"}]} +``` +batch1,batch16的精度相同如上. + +### 6.2 开源TopN精度 +[torchvision官网精度](https://pytorch.org/vision/stable/models.html) +``` +Model Acc@1 Acc@5 +HRNet-Image-Classification 76.8 93.4 +``` +### 6.3 精度对比 +将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 + **精度调试:** +>没有遇到精度不达标的问题,故不需要进行精度调试 + +## 7 性能对比 + +- **[npu性能数据](#71-npu性能数据)** + +### 7.1 npu性能数据 +需要测试batch1,batch4,batch8,batch16,batch32的性能,这里用batch1与batch16做示例 +benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device。为快速获取性能数据,也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准。这里给出两种方式,模型的测试脚本使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准。 +1.benchmark工具在整个数据集上推理获得性能数据 +以batch1为例,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: + +``` +[e2e] throughputRate: 125.08, latency: 399743 +[data read] throughputRate: 132.686, moduleLatency: 7.53661 +[preprocess] throughputRate: 132.548, moduleLatency: 7.54441 +[infer] throughputRate: 125.448, Interface throughputRate: 156.216, moduleLatency: 7.35352 +[post] throughputRate: 125.448, moduleLatency: 7.97142 +``` +Interface throughputRate: 156.216,156.216乘以4既是310单卡吞吐率 +2.benchmark纯推理功能测得性能数据 +batch1的性能: + 测试npu性能要确保device空闲,使用npu-smi info命令可查看device是否在运行其它推理任务 + +``` +./benchmark.x86_64 -round=20 -om_path=hrnet_bs1.om -device_id=0 -batch_size=1 +``` +执行20次纯推理取均值,统计吞吐率与其倒数时延(benchmark的时延是单个数据的推理时间),npu性能是一个device执行的结果 +``` +[INFO] Dataset number: 19 finished cost 2.635ms +[INFO] PureInfer result saved in ./result/PureInfer_perf_of_hrnet_bs1_in_device_0.txt +-----------------PureInfer Performance Summary------------------ +ave_throughputRate = 155.975samples/s, ave_latency = 6.42435ms +``` +bs1 310单卡吞吐率:155.975x4=623.9fps/card +batch4的性能: +``` +./benchmark.x86_64 -round=20 -om_path=hrnet_w18_bs4.om -device_id=0 -batch_size=4 +``` +``` +[INFO] PureInfer result saved in ./result/PureInfer_perf_of_hrnet_w18_bs4_in_device_0.txt +-----------------PureInfer Performance Summary------------------ +[INFO] ave_throughputRate: 224.608samples/s, ave_latency: 4.56663ms +``` +bs4 310单卡吞吐率:224.608x4=898.432fps/card +batch8的性能: +``` +./benchmark.x86_64 -round=20 -om_path=hrnet_w18_bs8.om -device_id=0 -batch_size=8 +``` +``` +[INFO] PureInfer result saved in ./result/PureInfer_perf_of_hrnet_w18_bs8_in_device_0.txt +-----------------PureInfer Performance Summary------------------ +[INFO] ave_throughputRate: 248.514samples/s, ave_latency: 4.09695ms +``` +bs8 310单卡吞吐率:248.514x4=994.056fps/card +batch16的性能: + +``` +./benchmark.x86_64 -round=20 -om_path=hrnet_w18_bs16.om -device_id=0 -batch_size=16 +``` +``` +[INFO] PureInfer result saved in ./result/PureInfer_perf_of_hrnet_w18_bs16_in_device_0.txt +-----------------PureInfer Performance Summary------------------ +[INFO] ave_throughputRate: 269.512samples/s, ave_latency: 3.73541ms +``` +bs16 310单卡吞吐率:269.512x4=1078.048fps/card +batch32的性能: +``` +./benchmark.x86_64 -round=20 -om_path=hrnet_w18_bs32.om -device_id=0 -batch_size=32 +``` +``` +[INFO] PureInfer result saved in ./result/PureInfer_perf_of_hrnet_w18_bs32_in_device_0.txt +-----------------PureInfer Performance Summary------------------ +[INFO] ave_throughputRate: 271.562samples/s, ave_latency: 3.69597ms +``` +bs32 310单卡吞吐率:271.562x4=1086.248fps/card + + **性能优化:** + +>没有遇到性能不达标的问题,故不需要进行性能优化 + diff --git a/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/get_info.py b/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/get_info.py index e43d4415cb..7f9afb06d1 100644 --- a/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/get_info.py +++ b/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/get_info.py @@ -1,59 +1,59 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/hrnet_pth2onnx.py b/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/hrnet_pth2onnx.py index 078a8a65a7..ec9444cc2f 100644 --- a/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/hrnet_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/hrnet_pth2onnx.py @@ -1,92 +1,92 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 sys -import argparse -import torch -import torch.onnx -from collections import OrderedDict -sys.path.append(r"./HRNet-Image-Classification") -sys.path.append(r"./HRNet-Image-Classification/lib") -from lib.models import cls_hrnet -from lib.config import config -from lib.config import update_config -def parse_args(): - parser = argparse.ArgumentParser(description='Train classification network') - parser.add_argument('--cfg', - help='experiment configure file name', - required=True, - type=str) - - parser.add_argument('--modelDir', - help='model directory', - type=str, - default='') - parser.add_argument('--logDir', - help='log directory', - type=str, - default='') - parser.add_argument('--dataDir', - help='data directory', - type=str, - default='') - parser.add_argument('--testModel', - help='testModel', - type=str, - default='') - - parser.add_argument('--input', - help='input pytorch model', - required=True, - type=str) - - parser.add_argument('--output', - help='output onnx model', - required=True, - type=str) - - args = parser.parse_args() - update_config(config, args) - - return args - -def proc_node_module(checkpoint, AttrName): - new_state_dict = OrderedDict() - for k, v in checkpoint[AttrName].items(): - if(k[0:7] == "module."): - name = k[7:] - else: - name = k[0:] - new_state_dict[name] = v - return new_state_dict - -def pth2onnx(): - args = parse_args() - print(config.MODEL) - modelpth = args.input - checkpoint = torch.load(modelpth, map_location='cpu') - model = cls_hrnet.get_cls_net(config) - output_file = args.output - print("output:",output_file) - model.load_state_dict(checkpoint) - model.eval() - print(model) - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.randn(1, 3, 224, 224) - torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=True, opset_version=11) - -if __name__ == "__main__": - pth2onnx() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 sys +import argparse +import torch +import torch.onnx +from collections import OrderedDict +sys.path.append(r"./HRNet-Image-Classification") +sys.path.append(r"./HRNet-Image-Classification/lib") +from lib.models import cls_hrnet +from lib.config import config +from lib.config import update_config +def parse_args(): + parser = argparse.ArgumentParser(description='Train classification network') + parser.add_argument('--cfg', + help='experiment configure file name', + required=True, + type=str) + + parser.add_argument('--modelDir', + help='model directory', + type=str, + default='') + parser.add_argument('--logDir', + help='log directory', + type=str, + default='') + parser.add_argument('--dataDir', + help='data directory', + type=str, + default='') + parser.add_argument('--testModel', + help='testModel', + type=str, + default='') + + parser.add_argument('--input', + help='input pytorch model', + required=True, + type=str) + + parser.add_argument('--output', + help='output onnx model', + required=True, + type=str) + + args = parser.parse_args() + update_config(config, args) + + return args + +def proc_node_module(checkpoint, AttrName): + new_state_dict = OrderedDict() + for k, v in checkpoint[AttrName].items(): + if(k[0:7] == "module."): + name = k[7:] + else: + name = k[0:] + new_state_dict[name] = v + return new_state_dict + +def pth2onnx(): + args = parse_args() + print(config.MODEL) + modelpth = args.input + checkpoint = torch.load(modelpth, map_location='cpu') + model = cls_hrnet.get_cls_net(config) + output_file = args.output + print("output:",output_file) + model.load_state_dict(checkpoint) + model.eval() + print(model) + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.randn(1, 3, 224, 224) + torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=True, opset_version=11) + +if __name__ == "__main__": + pth2onnx() diff --git a/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/imagenet_acc_eval.py b/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/imagenet_acc_eval.py index d85b7dcf59..58e389352e 100644 --- a/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/imagenet_acc_eval.py +++ b/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/imagenet_acc_eval.py @@ -1,187 +1,187 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - if data == '': - n_label = 0 - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = 0 - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - - resCnt = min(len(sort_index), topn) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - print(folder_davinci_target) - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - print(annotation_file_path) - # the path to store the results json path - result_json_path = sys.argv[3] - print(result_json_path) - # result json file name - json_file_name = sys.argv[4] - print(json_file_name) - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) - print("Time used:", elapsed) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + if data == '': + n_label = 0 + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = 0 + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + + resCnt = min(len(sort_index), topn) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + print(folder_davinci_target) + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + print(annotation_file_path) + # the path to store the results json path + result_json_path = sys.argv[3] + print(result_json_path) + # result json file name + json_file_name = sys.argv[4] + print(json_file_name) + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) + print("Time used:", elapsed) diff --git a/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/imagenet_torch_preprocess.py b/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/imagenet_torch_preprocess.py index 4ce024bfb5..61e574128a 100644 --- a/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/imagenet_torch_preprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/imagenet_torch_preprocess.py @@ -1,103 +1,103 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -from PIL import Image -import numpy as np -import multiprocessing - - -model_config = { - 'hrnet': { - 'resize': 256, - 'centercrop': 224, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - } -} - -def center_crop(img, output_size): - if isinstance(output_size, int): - output_size = (int(output_size), int(output_size)) - image_width, image_height = img.size - crop_height, crop_width = output_size - crop_top = int(round((image_height - crop_height) / 2.)) - crop_left = int(round((image_width - crop_width) / 2.)) - return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) - - -def resize(img, size, interpolation=Image.BILINEAR): - if isinstance(size, int): - w, h = img.size - if (w <= h and w == size) or (h <= w and h == size): - return img - if w < h: - ow = size - oh = int(size * h / w) - return img.resize((ow, oh), interpolation) - else: - oh = size - ow = int(size * w / h) - return img.resize((ow, oh), interpolation) - else: - return img.resize(size[::-1], interpolation) - - -def gen_input_bin(mode_type, file_batches, batch): - i = 0 - for file in file_batches[batch]: - i = i + 1 - # RGBA to RGB - s = os.path.join(src_path,file) - image = Image.open(os.path.join(src_path, file))# - image = image.convert('RGB') - image = resize(image, model_config[mode_type]['resize']) # Resize - image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop - img = np.array(image, dtype=np.float32) - img = img.transpose(2, 0, 1) # ToTensor: HWC -> CHW - img = img / 255. # ToTensor: div 255 - img -= np.array(model_config[mode_type]['mean'], dtype=np.float32)[:, None, None] # Normalize: mean - img /= np.array(model_config[mode_type]['std'], dtype=np.float32)[:, None, None] # Normalize: std - img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) - - -def preprocess(mode_type, src_path, save_path): - files = os.listdir(src_path) - file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] - thread_pool = multiprocessing.Pool(len(file_batches)) - for batch in range(len(file_batches)): - thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) - thread_pool.close() - thread_pool.join() - print("in thread, except will not report! please ensure bin files generated.") - - -if __name__ == '__main__': - if len(sys.argv) < 4: - raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") - mode_type = sys.argv[1] - src_path = sys.argv[2] - save_path = sys.argv[3] - src_path = os.path.realpath(src_path) - save_path = os.path.realpath(save_path) - if mode_type not in model_config: - model_type_help = "model type: " - for key in model_config.keys(): - model_type_help += key - model_type_help += ' ' - raise Exception(model_type_help) - if not os.path.isdir(save_path): - os.makedirs(os.path.realpath(save_path)) - preprocess(mode_type, src_path, save_path) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +from PIL import Image +import numpy as np +import multiprocessing + + +model_config = { + 'hrnet': { + 'resize': 256, + 'centercrop': 224, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + } +} + +def center_crop(img, output_size): + if isinstance(output_size, int): + output_size = (int(output_size), int(output_size)) + image_width, image_height = img.size + crop_height, crop_width = output_size + crop_top = int(round((image_height - crop_height) / 2.)) + crop_left = int(round((image_width - crop_width) / 2.)) + return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) + + +def resize(img, size, interpolation=Image.BILINEAR): + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def gen_input_bin(mode_type, file_batches, batch): + i = 0 + for file in file_batches[batch]: + i = i + 1 + # RGBA to RGB + s = os.path.join(src_path,file) + image = Image.open(os.path.join(src_path, file))# + image = image.convert('RGB') + image = resize(image, model_config[mode_type]['resize']) # Resize + image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop + img = np.array(image, dtype=np.float32) + img = img.transpose(2, 0, 1) # ToTensor: HWC -> CHW + img = img / 255. # ToTensor: div 255 + img -= np.array(model_config[mode_type]['mean'], dtype=np.float32)[:, None, None] # Normalize: mean + img /= np.array(model_config[mode_type]['std'], dtype=np.float32)[:, None, None] # Normalize: std + img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) + + +def preprocess(mode_type, src_path, save_path): + files = os.listdir(src_path) + file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] + thread_pool = multiprocessing.Pool(len(file_batches)) + for batch in range(len(file_batches)): + thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) + thread_pool.close() + thread_pool.join() + print("in thread, except will not report! please ensure bin files generated.") + + +if __name__ == '__main__': + if len(sys.argv) < 4: + raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") + mode_type = sys.argv[1] + src_path = sys.argv[2] + save_path = sys.argv[3] + src_path = os.path.realpath(src_path) + save_path = os.path.realpath(save_path) + if mode_type not in model_config: + model_type_help = "model type: " + for key in model_config.keys(): + model_type_help += key + model_type_help += ' ' + raise Exception(model_type_help) + if not os.path.isdir(save_path): + os.makedirs(os.path.realpath(save_path)) + preprocess(mode_type, src_path, save_path) diff --git a/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/requirements.txt b/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/requirements.txt index d5135180ff..77ef9d68a5 100644 --- a/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/requirements.txt +++ b/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/requirements.txt @@ -1,11 +1,11 @@ -torch==1.8.0 -torchvision==0.9.0 -onnx==1.9.0 -numpy==1.20.2 -opencv-python==4.5.2.52 -Pillow==8.0.1 -Cython -scipy -pandas -pyyaml +torch==1.8.0 +torchvision==0.9.0 +onnx==1.9.0 +numpy==1.20.2 +opencv-python==4.5.2.52 +Pillow==8.0.1 +Cython +scipy +pandas +pyyaml scikit-image \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/test/README.md b/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/test/README.md index 7ac4947ef7..db2329251a 100644 --- a/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/test/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/test/README.md @@ -1,29 +1,29 @@ -环境准备: - -1.数据集路径 -数据集统一放在/root/datasets/或/opt/npu/ -本模型数据集放在/opt/npu/ - -2.进入工作目录 -cd HRNet - -3.安装必要的依赖 -pip3.7 install -r requirements.txt - -4.获取模型代码 -git clone https://github.com/HRNet/HRNet-Image-Classification.git - -5.获取权重文件 -wget https://ascend-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/image_classification/HRNet/NPU/8P/model_best.pth.tar -file name:model_best.pth.tar -md5sum:1f1d61e242ac9ca4cab5d0c49299cb76 - -6.获取benchmark工具 -将benchmark.x86_64 benckmark.aarch64放在当前目录 - -7.310上执行 - -bash test/pth2om.sh - -bash test/eval_acc_perf.sh --datasets_path=/opt/npu +环境准备: + +1.数据集路径 +数据集统一放在/root/datasets/或/opt/npu/ +本模型数据集放在/opt/npu/ + +2.进入工作目录 +cd HRNet + +3.安装必要的依赖 +pip3.7 install -r requirements.txt + +4.获取模型代码 +git clone https://github.com/HRNet/HRNet-Image-Classification.git + +5.获取权重文件 +wget https://ascend-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/image_classification/HRNet/NPU/8P/model_best.pth.tar +file name:model_best.pth.tar +md5sum:1f1d61e242ac9ca4cab5d0c49299cb76 + +6.获取benchmark工具 +将benchmark.x86_64 benckmark.aarch64放在当前目录 + +7.310上执行 + +bash test/pth2om.sh + +bash test/eval_acc_perf.sh --datasets_path=/opt/npu \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/test/parse.py b/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/test/parse.py index a0f253b055..27eae0d0ac 100644 --- a/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/test/parse.py +++ b/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/LV-Vit/LICENSE b/ACL_PyTorch/contrib/cv/classfication/LV-Vit/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/LV-Vit/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/LV-Vit/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/LV-Vit/LV_Vit_postprocess.py b/ACL_PyTorch/contrib/cv/classfication/LV-Vit/LV_Vit_postprocess.py index 1781a4eef5..3fd86adf05 100644 --- a/ACL_PyTorch/contrib/cv/classfication/LV-Vit/LV_Vit_postprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/LV-Vit/LV_Vit_postprocess.py @@ -1,47 +1,47 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os - -import os -import numpy as np -import sys - -''' -sys.argv[1]: om_output -sys.argv[2]: ground_truth -''' -om_output_files = sorted(os.listdir(sys.argv[1])) - -output_labels = [] -# 读取om输出 -for file in om_output_files: - with open(sys.argv[1] + file, mode='r') as f: - content = f.read().split(' ')[:-1] - content = list(map(lambda x: float(x), content)) - content = np.array(content) - output_labels.append(np.argmax(content)) - -# 读取ground_truth -with open(sys.argv[2], mode='r') as f: - ground_truth = list(map(lambda x: int(x.rstrip('\n').split(' ')[1]), f.readlines())) - -count = 0 -for i in range(len(output_labels)): - if ground_truth[i] == output_labels[i]: - count += 1 - -print(f"accuracy: {count / len(output_labels)}") -# print(count, len(output_labels)) -# print(output_labels) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os + +import os +import numpy as np +import sys + +''' +sys.argv[1]: om_output +sys.argv[2]: ground_truth +''' +om_output_files = sorted(os.listdir(sys.argv[1])) + +output_labels = [] +# 读取om输出 +for file in om_output_files: + with open(sys.argv[1] + file, mode='r') as f: + content = f.read().split(' ')[:-1] + content = list(map(lambda x: float(x), content)) + content = np.array(content) + output_labels.append(np.argmax(content)) + +# 读取ground_truth +with open(sys.argv[2], mode='r') as f: + ground_truth = list(map(lambda x: int(x.rstrip('\n').split(' ')[1]), f.readlines())) + +count = 0 +for i in range(len(output_labels)): + if ground_truth[i] == output_labels[i]: + count += 1 + +print(f"accuracy: {count / len(output_labels)}") +# print(count, len(output_labels)) +# print(output_labels) diff --git a/ACL_PyTorch/contrib/cv/classfication/LV-Vit/LV_Vit_pth2onnx.py b/ACL_PyTorch/contrib/cv/classfication/LV-Vit/LV_Vit_pth2onnx.py index fefb429f0f..69866709e2 100644 --- a/ACL_PyTorch/contrib/cv/classfication/LV-Vit/LV_Vit_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/classfication/LV-Vit/LV_Vit_pth2onnx.py @@ -1,78 +1,78 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys - -sys.path.append(r"./TokenLabeling") - -import torch -# import argparse -from timm.models import create_model, apply_test_time_pool, load_checkpoint, is_model, list_models -import tlt.models - -import os -import numpy as np - -from timm.data.transforms_factory import transforms_imagenet_eval -from torchvision import transforms -from PIL import Image - - -# parser = argparse.ArgumentParser() -# parser.add_argument('--model', type=str, default='lvvit_s') -# parser.add_argument('--use-ema', dest='use_ema', action='store_true', -# help='use ema version of weights if present') -# parser.add_argument('--checkpoint', type=str, default='') -# parser.add_argument('--pretrained', dest='pretrained', action='store_true', -# help='use pre-trained model') -# parser.add_argument('--gp', default=None, type=str, metavar='POOL', -# help='Global pool type, one of (fast, avg, max, avgmax, avgmaxc). Model default if None.') -# parser.add_argument('--output_file', default='lvvit_s.onnx', type=str) -# parser.add_argument('-b', '--batch_size', default=16, type=int) - - -def main(): - if not os.path.exists('./model'): - os.mkdir('./model') - - device = torch.device('cpu') - input_names = ["image"] - output_names = ["features"] - dynamic_axes = {'image': {0: f'{sys.argv[3]}'}, 'features': {0: f'{sys.argv[3]}'}} - model = create_model( - 'lvvit_s', - pretrained=False, - num_classes=None, - in_chans=3, - global_pool=None, - scriptable=False, - img_size=224) - # model.cuda() - # load_checkpoint(model, args.checkpoint, args.use_ema, strict=False) - load_checkpoint(model, sys.argv[1], False, strict=False) - model.to(device) - model.eval() - dummy_input = torch.randn(int(sys.argv[3]), 3, 224, 224, device='cpu') - torch.onnx.export(model, - dummy_input, - sys.argv[2], - input_names=input_names, - output_names=output_names, - dynamic_axes=dynamic_axes, - opset_version=13, - verbose=True) - - -main() - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys + +sys.path.append(r"./TokenLabeling") + +import torch +# import argparse +from timm.models import create_model, apply_test_time_pool, load_checkpoint, is_model, list_models +import tlt.models + +import os +import numpy as np + +from timm.data.transforms_factory import transforms_imagenet_eval +from torchvision import transforms +from PIL import Image + + +# parser = argparse.ArgumentParser() +# parser.add_argument('--model', type=str, default='lvvit_s') +# parser.add_argument('--use-ema', dest='use_ema', action='store_true', +# help='use ema version of weights if present') +# parser.add_argument('--checkpoint', type=str, default='') +# parser.add_argument('--pretrained', dest='pretrained', action='store_true', +# help='use pre-trained model') +# parser.add_argument('--gp', default=None, type=str, metavar='POOL', +# help='Global pool type, one of (fast, avg, max, avgmax, avgmaxc). Model default if None.') +# parser.add_argument('--output_file', default='lvvit_s.onnx', type=str) +# parser.add_argument('-b', '--batch_size', default=16, type=int) + + +def main(): + if not os.path.exists('./model'): + os.mkdir('./model') + + device = torch.device('cpu') + input_names = ["image"] + output_names = ["features"] + dynamic_axes = {'image': {0: f'{sys.argv[3]}'}, 'features': {0: f'{sys.argv[3]}'}} + model = create_model( + 'lvvit_s', + pretrained=False, + num_classes=None, + in_chans=3, + global_pool=None, + scriptable=False, + img_size=224) + # model.cuda() + # load_checkpoint(model, args.checkpoint, args.use_ema, strict=False) + load_checkpoint(model, sys.argv[1], False, strict=False) + model.to(device) + model.eval() + dummy_input = torch.randn(int(sys.argv[3]), 3, 224, 224, device='cpu') + torch.onnx.export(model, + dummy_input, + sys.argv[2], + input_names=input_names, + output_names=output_names, + dynamic_axes=dynamic_axes, + opset_version=13, + verbose=True) + + +main() + diff --git a/ACL_PyTorch/contrib/cv/classfication/LV-Vit/README.md b/ACL_PyTorch/contrib/cv/classfication/LV-Vit/README.md index cae18df27c..96c03d43b8 100644 --- a/ACL_PyTorch/contrib/cv/classfication/LV-Vit/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/LV-Vit/README.md @@ -1,381 +1,381 @@ -# LV-Vit Onnx模型端到端推理指导 - -+ [1模型概述](#1 模型概述) - - + [1.1 论文地址](##1.1 论文地址) - + [1.2 代码地址](##1.2 代码地址) - -+ [2 环境说明](#2 环境说明) - - + [2.1 深度学习框架](##2.1 深度学习框架) - + [2.2 python第三方库](##2.2 python第三方库) - -+ [3 模型转换](#3 模型转换) - - + [3.1 pth转onnx模型](##3.1 pth转onnx模型) - + [3.2 onnx转om模型](##3.2 onnx转om模型) - -+ [4 数据集预处理](#4 数据集预处理) - - + [4.1 数据集获取](##4.1 数据集获取) - + [4.2 数据集预处理](##4.2 数据集预处理) - + [4.3 生成预处理数据集信息文件](##4.3 生成预处理数据集信息文件) - -+ [5 离线推理](#5 离线推理) - - + [5.1 benchmark工具概述](##5.1 benchmark工具概述) - + [5.2 离线推理](##5.2 离线推理) - -+ [6 精度对比](#6 精度对比) - - + [6.1 离线推理精度统计](##6.1 离线推理精度统计) - + [6.2 开源精度](##6.2 开源精度) - + [6.3 精度对比](##6.3 精度对比) - -+ [7 性能对比](#7 性能对比) - - + [7.1 npu性能数据](##7.1 npu性能数据) - + [7.2 gpu和npu性能对比](##7.2 gpu和npu性能对比) - - - -## 1 模型概述 - -### 1.1 论文地址 - -[LV-Vit论文](https://arxiv.org/abs/2104.10858 ) - -### 1.2 代码地址 - -[LV-Vit代码](https://github.com/zihangJiang/TokenLabeling ) - - - -## 2 环境说明 - -### 2.1 深度学习框架 - -``` -torch==1.8.0 -torchvision==0.9.0 -onnx==1.10.1 -onnx-simplifier==0.3.6 -``` - -### 2.2 python第三方库 - -``` -numpy==1.21.2 -pyyaml==5.4.1 -pillow==8.3.1 -timm==0.4.5 -scipy==0.24.2 -``` - - - -## 3 模型转换 - -### 3.1 pth转onnx模型 - -1.LV-Vit模型代码下载 - -```bash -# 切换到工作目录 -cd LV-Vit - -git clone https://github.com/zihangJiang/TokenLabeling.git -cd TokenLabeling -patch -p1 < ../LV-Vit.patch -cd .. -``` - -2.获取模型权重,并放在工作目录的model文件夹下 -在model/下已经存放了在gpu8p上训练得到的pth,如需下载官方pth,则执行以下代码 -```bash -wget https://github.com/zihangJiang/TokenLabeling/releases/download/1.0/lvvit_s-26M-224-83.3.pth.tar -mv lvvit_s-26M-224-83.3.pth.tar model_best.pth.tar - -rm ./model/model_best.pth.tar -mv model_best.pth.tar ./model/ -``` - - - -3.使用 LV_Vit_pth2onnx.py 脚本将pth模型文件转为onnx模型文件 - -+ 参数1:pth模型权重的路径 - -+ 参数2:onnx模型权重的存储路径 - -+ 参数3:batch size - -```bash. -python LV_Vit_pth2onnx.py ./model/model_best.pth.tar ./model/model_best_bs1.onnx 1 -python LV_Vit_pth2onnx.py ./model/model_best.pth.tar ./model/model_best_bs16.onnx 16 -``` - -4.使用 onnxsim 工具优化onnx模型 - -+ 参数1:输入的shape -+ 参数2:onnx模型权重的存储路径 -+ 参数3:优化后onnx模型权重的存储路径 - -``` -python -m onnxsim --input-shape="1,3,224,224" ./model/model_best_bs1.onnx ./model/model_best_bs1_sim.onnx -python -m onnxsim --input-shape="16,3,224,224" ./model/model_best_bs16.onnx ./model/model_best_bs16_sim.onnx -``` - -5.使用tensorRT工具测试onnx模型性能 - -请自行软链接trtexec工具 - -``` -./trtexec --onnx=model/model_best_bs1_sim.onnx --fp16 --shapes=image:1x3x112x112 --device=0 > sim_onnx_bs1.log -./trtexec --onnx=model/model_best_bs16_sim.onnx --fp16 --shapes=image:16x3x112x112 --device=0 > sim_onnx_bs16.log -``` - - - -### 3.2 onnx转om模型 - -1.设置环境变量 - -```bash -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp -export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest -``` - -2.使用 atc 将 onnx 模型转换为 om 模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) - -请注意,为了优化softmax算子,在其前后添加了transpose算子,故一并优化transpose,须在白名单中添加(batch_size,6,197,197)和 -(batch_size,197,197,6) - -路径:/usr/local/Ascend/ascend-toolkit/latest/x86_64-linux/opp/op_impl/built-in/ai_core/tbe/impl/dynamic/transpose.py - -```bash -atc --framework=5 --model=./model/model_best_bs1_sim.onnx --output=./model/model_best_bs1_sim --input_format=NCHW --input_shape="image:1,3,224,224" --log=debug --soc_version=Ascend310 - -atc --framework=5 --model=./model/model_best_bs16_sim.onnx --output=./model/model_best_bs16_sim --input_format=NCHW --input_shape="image:16,3,224,224" --log=debug --soc_version=Ascend310 -``` - - - -## 4 数据集预处理 - -### 4.1 数据集获取 - -获取imagenet纯验证数据集,放在该目录:/opt/npu/imagenet/PureVal/ - - - -### 4.2 数据集预处理 - -执行预处理脚本,会在工作目录的data目录下生成数据集预处理后的 bin 文件和 数据集信息文件 - -LV_Vit_preprocess.py: -+ --src_path: imagenet纯验证集路径; --save_path: bin文件存放路径 - -gen_dataset_info.py -+ 参数1:bin文件 -+ 参数2:数据bin文件存放目录 - -``` -python LV_Vit_preprocess.py --src_path /opt/npu/imagenet/PureVal/ --save_path ./data/prep_dataset; -python gen_dataset_info.py ./data/prep_dataset ./data/lvvit_prep_bin.info; -``` - - -## 5 离线推理 - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) - -### 5.2 离线推理 - -1.设置环境变量 - -```bash -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp -export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest/ -``` - -2.执行离线推理, 输出结果默认保存在当前目录result/dumpOutput_device0 - -```bash -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=./model/model_best_bs1_sim.om -input_text_path=lvvit_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False - -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=16 -om_path=./model/model_best_bs16_sim.om -input_text_path=lvvit_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False -``` - - - -## 6 精度对比 - -### 6.1 离线推理精度统计 - -执行后处理脚本统计om模型推理结果的Accuracy - -+ 参数1:om模型预测结果目录 -+ 参数2:imagenet纯验证集标签 - -```shell -python LV_Vit_postprocess.py ./result/dumpOutput_device0 ./data/val.txt -``` - -控制台输出如下信息 - -``` -accuracy: 0.8317 -``` - - - -### 6.2 开源精度 - -源代码仓公布精度 - -``` -Model Dataset Accuracy -LV-Vit imagenet 0.833 -``` - - - -### 6.3 精度对比 - -将得到的om离线模型推理Accuracy与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 - - - -## 7 性能对比 - -### 7.1 npu性能数据 - -**1. batch_size=1** - -``` -[e2e] throughputRate: 35.5884, latency: 1.40495e+06 -[data read] throughputRate: 37.666, moduleLatency:26.5491 -[preprocess] throughputRate: 37.5823, moduleLatency: 26.6802 -[infer] throughputRate: 35.6308 Interface throughputRate: 37.941, moduleLatency: 27.3942 -[post] throughputRate: 35.6308, moduleLatency: 28.0656 -``` - -batch_size=1 Ascend310单卡吞吐率:37.941*4=151.764 fps - - - -**2. batch_size=4** - -``` -[e2e] throughputRate: 37.4274, latency: 1.33592e+06 -[data read] throughputRate: 39.6399, moduleLatency: 25.2271 -[preprocess] throughputRate: 39.5442, moduleLatency: 25.2882 -[infer] throughputRate: 37.4711, Interface throughputRate: 40.477, moduleLatency: 26.1715 -[post] throughputRate: 9.36777, moduleLatency: 106.749 -``` - -batch_size=4 Ascend310单卡吞吐率:40.477*4=161.908 fps - - - -**3. batch_size=8** - -``` -[e2e] throughputRate: 34.8915, latency: 1.43301e+06 -[data read] throughputRate: 36.8978, moduleLatency: 27.1019 -[preprocess] throughputRate: 36.8307, moduleLatency: 27.1513 -[infer] throughputRate: 34.9252, Interface throughputRate: 38.3992, moduleLatency: 27.4573 -[post] throughputRate: 4.36564, moduleLatency: 229.062 -``` - -batch_size=16 Ascend310单卡吞吐率:38.3992*4=153.5968 fps - - - -**4. batch_size=16** - -``` -[e2e] throughputRate: 34.3406, latency: 1.456e+06 -[data read] throughputRate: 36.3651, moduleLatency: 27.4989 -[preprocess] throughputRate: 36.2989, moduleLatency: 27.5491 -[infer] throughputRate: 34.378, Interface throughputRate: 36.9249, moduleLatency: 28.4462 -[post] throughputRate: 2.14862, moduleLatency: 465.415 -``` - -batch_size=16 Ascend310单卡吞吐率:36.9249*4=147.6996 fps - - - -**5. batch_size=32** - -``` -[e2e] throughputRate: 33.136, latency: 1.50893e+06 -[data read] throughputRate: 35.0612, moduleLatency: 28.5215 -[preprocess] throughputRate: 34.9918, moduleLatency: 28.5781 -[infer] throughputRate: 33.1637, Interface throughputRate: 36.1795, moduleLatency: 28.9776 -[post] throughputRate: 1.03669, moduleLatency: 964.608 -``` - -batch_size=16 Ascend310单卡吞吐率:36.1795*4=144.718 fps - - - -### 7.2 npu性能优化 - -云盘:[model_best_bs1_sim.om](https://pan.baidu.com/s/1bMuSj4PbvuYE-pX2j_e-0Q),提取码:ad5f - -[model_best_bs16_sim.om](https://pan.baidu.com/s/11gYb6RpBbuaEL-aIql2qkg),提取码:jiev - -**1. batch_size=1** - -``` -[e2e] throughputRate: 40.7217, latency: 1.22785e+06 -[data read] throughputRate: 43.0838, moduleLatency: 23.2106 -[preprocess] throughputRate: 42.997, moduleLatency: 23.2575 -[infer] throughputRate: 40.769, Interface throughputRate: 44.0188, moduleLatency: 23.7945 -[post] throughputRate: 40.769, moduleLatency: 24.5285 -``` - -batch_size=1 Ascend310单卡吞吐率:44.0188*4=176.0752 fps - -**2. batch_size=16** - -``` -[e2e] throughputRate: 51.2825, latency: 974992 -[data read] throughputRate: 54.323, moduleLatency: 18.4084 -[preprocess] throughputRate: 54.1712, moduleLatency: 18.46 -[infer] throughputRate: 51.3613, Interface throughputRate: 57.8179, moduleLatency: 18.6629 -[post] throughputRate: 3.21005, moduleLatency: 311.521 -``` - -batch_size=16 Ascend310单卡吞吐率:57.8179*4=231.2716 fps - -### 7.3 npu性能优化前后对比 - -| batch size | 优化前 | 优化后 | -| :--------: | :------: | :------: | -| 1 | 151.764 | 176.0752 | -| 16 | 147.6996 | 231.2716 | - - - -### 7.4 gpu和npu性能对比 - -| batch size | GPU(FPS) | NPU(FPS) | -| :--------: | -------- | -------- | -| 1 | 290.41 | 176.0752 | -| 16 | 559.35 | 231.2716 | - - - +# LV-Vit Onnx模型端到端推理指导 + ++ [1模型概述](#1 模型概述) + + + [1.1 论文地址](##1.1 论文地址) + + [1.2 代码地址](##1.2 代码地址) + ++ [2 环境说明](#2 环境说明) + + + [2.1 深度学习框架](##2.1 深度学习框架) + + [2.2 python第三方库](##2.2 python第三方库) + ++ [3 模型转换](#3 模型转换) + + + [3.1 pth转onnx模型](##3.1 pth转onnx模型) + + [3.2 onnx转om模型](##3.2 onnx转om模型) + ++ [4 数据集预处理](#4 数据集预处理) + + + [4.1 数据集获取](##4.1 数据集获取) + + [4.2 数据集预处理](##4.2 数据集预处理) + + [4.3 生成预处理数据集信息文件](##4.3 生成预处理数据集信息文件) + ++ [5 离线推理](#5 离线推理) + + + [5.1 benchmark工具概述](##5.1 benchmark工具概述) + + [5.2 离线推理](##5.2 离线推理) + ++ [6 精度对比](#6 精度对比) + + + [6.1 离线推理精度统计](##6.1 离线推理精度统计) + + [6.2 开源精度](##6.2 开源精度) + + [6.3 精度对比](##6.3 精度对比) + ++ [7 性能对比](#7 性能对比) + + + [7.1 npu性能数据](##7.1 npu性能数据) + + [7.2 gpu和npu性能对比](##7.2 gpu和npu性能对比) + + + +## 1 模型概述 + +### 1.1 论文地址 + +[LV-Vit论文](https://arxiv.org/abs/2104.10858 ) + +### 1.2 代码地址 + +[LV-Vit代码](https://github.com/zihangJiang/TokenLabeling ) + + + +## 2 环境说明 + +### 2.1 深度学习框架 + +``` +torch==1.8.0 +torchvision==0.9.0 +onnx==1.10.1 +onnx-simplifier==0.3.6 +``` + +### 2.2 python第三方库 + +``` +numpy==1.21.2 +pyyaml==5.4.1 +pillow==8.3.1 +timm==0.4.5 +scipy==0.24.2 +``` + + + +## 3 模型转换 + +### 3.1 pth转onnx模型 + +1.LV-Vit模型代码下载 + +```bash +# 切换到工作目录 +cd LV-Vit + +git clone https://github.com/zihangJiang/TokenLabeling.git +cd TokenLabeling +patch -p1 < ../LV-Vit.patch +cd .. +``` + +2.获取模型权重,并放在工作目录的model文件夹下 +在model/下已经存放了在gpu8p上训练得到的pth,如需下载官方pth,则执行以下代码 +```bash +wget https://github.com/zihangJiang/TokenLabeling/releases/download/1.0/lvvit_s-26M-224-83.3.pth.tar +mv lvvit_s-26M-224-83.3.pth.tar model_best.pth.tar + +rm ./model/model_best.pth.tar +mv model_best.pth.tar ./model/ +``` + + + +3.使用 LV_Vit_pth2onnx.py 脚本将pth模型文件转为onnx模型文件 + ++ 参数1:pth模型权重的路径 + ++ 参数2:onnx模型权重的存储路径 + ++ 参数3:batch size + +```bash. +python LV_Vit_pth2onnx.py ./model/model_best.pth.tar ./model/model_best_bs1.onnx 1 +python LV_Vit_pth2onnx.py ./model/model_best.pth.tar ./model/model_best_bs16.onnx 16 +``` + +4.使用 onnxsim 工具优化onnx模型 + ++ 参数1:输入的shape ++ 参数2:onnx模型权重的存储路径 ++ 参数3:优化后onnx模型权重的存储路径 + +``` +python -m onnxsim --input-shape="1,3,224,224" ./model/model_best_bs1.onnx ./model/model_best_bs1_sim.onnx +python -m onnxsim --input-shape="16,3,224,224" ./model/model_best_bs16.onnx ./model/model_best_bs16_sim.onnx +``` + +5.使用tensorRT工具测试onnx模型性能 + +请自行软链接trtexec工具 + +``` +./trtexec --onnx=model/model_best_bs1_sim.onnx --fp16 --shapes=image:1x3x112x112 --device=0 > sim_onnx_bs1.log +./trtexec --onnx=model/model_best_bs16_sim.onnx --fp16 --shapes=image:16x3x112x112 --device=0 > sim_onnx_bs16.log +``` + + + +### 3.2 onnx转om模型 + +1.设置环境变量 + +```bash +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp +export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest +``` + +2.使用 atc 将 onnx 模型转换为 om 模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) + +请注意,为了优化softmax算子,在其前后添加了transpose算子,故一并优化transpose,须在白名单中添加(batch_size,6,197,197)和 +(batch_size,197,197,6) + +路径:/usr/local/Ascend/ascend-toolkit/latest/x86_64-linux/opp/op_impl/built-in/ai_core/tbe/impl/dynamic/transpose.py + +```bash +atc --framework=5 --model=./model/model_best_bs1_sim.onnx --output=./model/model_best_bs1_sim --input_format=NCHW --input_shape="image:1,3,224,224" --log=debug --soc_version=Ascend310 + +atc --framework=5 --model=./model/model_best_bs16_sim.onnx --output=./model/model_best_bs16_sim --input_format=NCHW --input_shape="image:16,3,224,224" --log=debug --soc_version=Ascend310 +``` + + + +## 4 数据集预处理 + +### 4.1 数据集获取 + +获取imagenet纯验证数据集,放在该目录:/opt/npu/imagenet/PureVal/ + + + +### 4.2 数据集预处理 + +执行预处理脚本,会在工作目录的data目录下生成数据集预处理后的 bin 文件和 数据集信息文件 + +LV_Vit_preprocess.py: ++ --src_path: imagenet纯验证集路径; --save_path: bin文件存放路径 + +gen_dataset_info.py ++ 参数1:bin文件 ++ 参数2:数据bin文件存放目录 + +``` +python LV_Vit_preprocess.py --src_path /opt/npu/imagenet/PureVal/ --save_path ./data/prep_dataset; +python gen_dataset_info.py ./data/prep_dataset ./data/lvvit_prep_bin.info; +``` + + +## 5 离线推理 + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) + +### 5.2 离线推理 + +1.设置环境变量 + +```bash +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp +export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest/ +``` + +2.执行离线推理, 输出结果默认保存在当前目录result/dumpOutput_device0 + +```bash +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=./model/model_best_bs1_sim.om -input_text_path=lvvit_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False + +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=16 -om_path=./model/model_best_bs16_sim.om -input_text_path=lvvit_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False +``` + + + +## 6 精度对比 + +### 6.1 离线推理精度统计 + +执行后处理脚本统计om模型推理结果的Accuracy + ++ 参数1:om模型预测结果目录 ++ 参数2:imagenet纯验证集标签 + +```shell +python LV_Vit_postprocess.py ./result/dumpOutput_device0 ./data/val.txt +``` + +控制台输出如下信息 + +``` +accuracy: 0.8317 +``` + + + +### 6.2 开源精度 + +源代码仓公布精度 + +``` +Model Dataset Accuracy +LV-Vit imagenet 0.833 +``` + + + +### 6.3 精度对比 + +将得到的om离线模型推理Accuracy与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 + + + +## 7 性能对比 + +### 7.1 npu性能数据 + +**1. batch_size=1** + +``` +[e2e] throughputRate: 35.5884, latency: 1.40495e+06 +[data read] throughputRate: 37.666, moduleLatency:26.5491 +[preprocess] throughputRate: 37.5823, moduleLatency: 26.6802 +[infer] throughputRate: 35.6308 Interface throughputRate: 37.941, moduleLatency: 27.3942 +[post] throughputRate: 35.6308, moduleLatency: 28.0656 +``` + +batch_size=1 Ascend310单卡吞吐率:37.941*4=151.764 fps + + + +**2. batch_size=4** + +``` +[e2e] throughputRate: 37.4274, latency: 1.33592e+06 +[data read] throughputRate: 39.6399, moduleLatency: 25.2271 +[preprocess] throughputRate: 39.5442, moduleLatency: 25.2882 +[infer] throughputRate: 37.4711, Interface throughputRate: 40.477, moduleLatency: 26.1715 +[post] throughputRate: 9.36777, moduleLatency: 106.749 +``` + +batch_size=4 Ascend310单卡吞吐率:40.477*4=161.908 fps + + + +**3. batch_size=8** + +``` +[e2e] throughputRate: 34.8915, latency: 1.43301e+06 +[data read] throughputRate: 36.8978, moduleLatency: 27.1019 +[preprocess] throughputRate: 36.8307, moduleLatency: 27.1513 +[infer] throughputRate: 34.9252, Interface throughputRate: 38.3992, moduleLatency: 27.4573 +[post] throughputRate: 4.36564, moduleLatency: 229.062 +``` + +batch_size=16 Ascend310单卡吞吐率:38.3992*4=153.5968 fps + + + +**4. batch_size=16** + +``` +[e2e] throughputRate: 34.3406, latency: 1.456e+06 +[data read] throughputRate: 36.3651, moduleLatency: 27.4989 +[preprocess] throughputRate: 36.2989, moduleLatency: 27.5491 +[infer] throughputRate: 34.378, Interface throughputRate: 36.9249, moduleLatency: 28.4462 +[post] throughputRate: 2.14862, moduleLatency: 465.415 +``` + +batch_size=16 Ascend310单卡吞吐率:36.9249*4=147.6996 fps + + + +**5. batch_size=32** + +``` +[e2e] throughputRate: 33.136, latency: 1.50893e+06 +[data read] throughputRate: 35.0612, moduleLatency: 28.5215 +[preprocess] throughputRate: 34.9918, moduleLatency: 28.5781 +[infer] throughputRate: 33.1637, Interface throughputRate: 36.1795, moduleLatency: 28.9776 +[post] throughputRate: 1.03669, moduleLatency: 964.608 +``` + +batch_size=16 Ascend310单卡吞吐率:36.1795*4=144.718 fps + + + +### 7.2 npu性能优化 + +云盘:[model_best_bs1_sim.om](https://pan.baidu.com/s/1bMuSj4PbvuYE-pX2j_e-0Q),提取码:ad5f + +[model_best_bs16_sim.om](https://pan.baidu.com/s/11gYb6RpBbuaEL-aIql2qkg),提取码:jiev + +**1. batch_size=1** + +``` +[e2e] throughputRate: 40.7217, latency: 1.22785e+06 +[data read] throughputRate: 43.0838, moduleLatency: 23.2106 +[preprocess] throughputRate: 42.997, moduleLatency: 23.2575 +[infer] throughputRate: 40.769, Interface throughputRate: 44.0188, moduleLatency: 23.7945 +[post] throughputRate: 40.769, moduleLatency: 24.5285 +``` + +batch_size=1 Ascend310单卡吞吐率:44.0188*4=176.0752 fps + +**2. batch_size=16** + +``` +[e2e] throughputRate: 51.2825, latency: 974992 +[data read] throughputRate: 54.323, moduleLatency: 18.4084 +[preprocess] throughputRate: 54.1712, moduleLatency: 18.46 +[infer] throughputRate: 51.3613, Interface throughputRate: 57.8179, moduleLatency: 18.6629 +[post] throughputRate: 3.21005, moduleLatency: 311.521 +``` + +batch_size=16 Ascend310单卡吞吐率:57.8179*4=231.2716 fps + +### 7.3 npu性能优化前后对比 + +| batch size | 优化前 | 优化后 | +| :--------: | :------: | :------: | +| 1 | 151.764 | 176.0752 | +| 16 | 147.6996 | 231.2716 | + + + +### 7.4 gpu和npu性能对比 + +| batch size | GPU(FPS) | NPU(FPS) | +| :--------: | -------- | -------- | +| 1 | 290.41 | 176.0752 | +| 16 | 559.35 | 231.2716 | + + + diff --git a/ACL_PyTorch/contrib/cv/classfication/LV-Vit/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/classfication/LV-Vit/gen_dataset_info.py index 5415fd9ae5..0ef2e2354d 100644 --- a/ACL_PyTorch/contrib/cv/classfication/LV-Vit/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/classfication/LV-Vit/gen_dataset_info.py @@ -1,31 +1,31 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys - - -def main(): - src_path = sys.argv[1] - output_file = sys.argv[2] - in_files = sorted(os.listdir(src_path)) - i = 0 - with open(output_file, mode='w') as f: - for file in in_files: - f.write(str(i) + ' ' + src_path + file + ' 224 224\n') - i += 1 - - -if __name__ == '__main__': - main() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys + + +def main(): + src_path = sys.argv[1] + output_file = sys.argv[2] + in_files = sorted(os.listdir(src_path)) + i = 0 + with open(output_file, mode='w') as f: + for file in in_files: + f.write(str(i) + ' ' + src_path + file + ' 224 224\n') + i += 1 + + +if __name__ == '__main__': + main() diff --git a/ACL_PyTorch/contrib/cv/classfication/LV-Vit/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/classfication/LV-Vit/modelzoo_level.txt index 9e95396651..27e6c78b37 100644 --- a/ACL_PyTorch/contrib/cv/classfication/LV-Vit/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/classfication/LV-Vit/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:POK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/LV-Vit/test/README.md b/ACL_PyTorch/contrib/cv/classfication/LV-Vit/test/README.md index cf67d697df..23be8e8083 100644 --- a/ACL_PyTorch/contrib/cv/classfication/LV-Vit/test/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/LV-Vit/test/README.md @@ -1,77 +1,77 @@ -# Shell 脚本 说明 - -**必要目录结构及说明 (Ascend310)** - -``` -|—— TokenLabeling # 源码目录 -|-- LV-Vit.patch # 源码补丁 -|-- test -|------ eval_acc_perf.sh # 预处理推理后处理一条龙 -|------ pth2om.sh # pth转onnx,onnx转om脚本 -|—— data # 用于存放imagenet验证集二进制文件 -|------ val.txt # imagenet 纯验证集标签 -|—— model -|——---- model_best.pth.tar # 模型权重 -|—— env.sh # NPU环境变量脚本 -|—— LV_Vit_postprocess.py # 后处理脚本 -|—— LV_Vit_preprocess.py # 预处理脚本 -|—— LV_Vit_pth2onnx.py # pth转onnx脚本 -|-- benchmark.x86_64 # benckmark工具 -``` - -**step1:准备阶段修改源码** - -```bash -git clone https://github.com/zihangJiang/TokenLabeling.git -cd TokenLabeling -patch -p1 < ../LV-Vit.patch -cd .. -``` - -**step2:获取模型权重,并放在工作目录的model文件夹下** - -```bash -wget https://github.com/zihangJiang/TokenLabeling/releases/download/1.0/lvvit_s-26M-224-83.3.pth.tar - -mv lvvit_s-26M-224-83.3.pth.tar ./model/model_best.pth.tar -``` - -**step3:获取imagenet纯验证数据集,放在该目录** - -/opt/npu/imagenet/PureVal/ - - -**1.pth转om模型** - -```shell -bash test/pth2om.sh -``` - -**2.npu性能数据及精度数据** - ---datasets_path=imagenet纯验证集路径 - -```shell -bash test/eval_acc_perf.sh --datasets_path=/opt/npu/imagenet/PureVal/ -``` - -**必要目录结构及说明 (t4)** - -onnx模型权重由第一步 pth转om 模型生成在 model 文件夹下 -请自行软链接trtexec工具! - -``` -|-- test -|------ pref_gpu.sh # onnx性能数据脚本 -|—— model -|——---- model_best_bs1_sim.onnx # bs=1 模型权重 -|——---- model_best_bs16_sim.onnx # bs=16 模型权重 -|-- trtexec # trtexec工具 -``` - -**3.测试t4性能数据** - -``` -bash test/pref_gpu.sh -``` - +# Shell 脚本 说明 + +**必要目录结构及说明 (Ascend310)** + +``` +|—— TokenLabeling # 源码目录 +|-- LV-Vit.patch # 源码补丁 +|-- test +|------ eval_acc_perf.sh # 预处理推理后处理一条龙 +|------ pth2om.sh # pth转onnx,onnx转om脚本 +|—— data # 用于存放imagenet验证集二进制文件 +|------ val.txt # imagenet 纯验证集标签 +|—— model +|——---- model_best.pth.tar # 模型权重 +|—— env.sh # NPU环境变量脚本 +|—— LV_Vit_postprocess.py # 后处理脚本 +|—— LV_Vit_preprocess.py # 预处理脚本 +|—— LV_Vit_pth2onnx.py # pth转onnx脚本 +|-- benchmark.x86_64 # benckmark工具 +``` + +**step1:准备阶段修改源码** + +```bash +git clone https://github.com/zihangJiang/TokenLabeling.git +cd TokenLabeling +patch -p1 < ../LV-Vit.patch +cd .. +``` + +**step2:获取模型权重,并放在工作目录的model文件夹下** + +```bash +wget https://github.com/zihangJiang/TokenLabeling/releases/download/1.0/lvvit_s-26M-224-83.3.pth.tar + +mv lvvit_s-26M-224-83.3.pth.tar ./model/model_best.pth.tar +``` + +**step3:获取imagenet纯验证数据集,放在该目录** + +/opt/npu/imagenet/PureVal/ + + +**1.pth转om模型** + +```shell +bash test/pth2om.sh +``` + +**2.npu性能数据及精度数据** + +--datasets_path=imagenet纯验证集路径 + +```shell +bash test/eval_acc_perf.sh --datasets_path=/opt/npu/imagenet/PureVal/ +``` + +**必要目录结构及说明 (t4)** + +onnx模型权重由第一步 pth转om 模型生成在 model 文件夹下 +请自行软链接trtexec工具! + +``` +|-- test +|------ pref_gpu.sh # onnx性能数据脚本 +|—— model +|——---- model_best_bs1_sim.onnx # bs=1 模型权重 +|——---- model_best_bs16_sim.onnx # bs=16 模型权重 +|-- trtexec # trtexec工具 +``` + +**3.测试t4性能数据** + +``` +bash test/pref_gpu.sh +``` + diff --git a/ACL_PyTorch/contrib/cv/classfication/MobileNet-v1/mobilenet-v1_pth2onnx.py b/ACL_PyTorch/contrib/cv/classfication/MobileNet-v1/mobilenet-v1_pth2onnx.py index 82981e308d..f254c26ddf 100644 --- a/ACL_PyTorch/contrib/cv/classfication/MobileNet-v1/mobilenet-v1_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/classfication/MobileNet-v1/mobilenet-v1_pth2onnx.py @@ -1,107 +1,107 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -from collections import OrderedDict - -import torch -import torch.nn as nn -import torch.onnx - - -class Net(nn.Module): - def __init__(self): - super(Net, self).__init__() - - def conv_bn(inp, oup, stride): - return nn.Sequential( - nn.Conv2d(inp, oup, 3, stride, 1, bias=False), - nn.BatchNorm2d(oup), - nn.ReLU(inplace=True) - ) - - def conv_dw(inp, oup, stride): - return nn.Sequential( - nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False), - nn.BatchNorm2d(inp), - nn.ReLU(inplace=True), - - nn.Conv2d(inp, oup, 1, 1, 0, bias=False), - nn.BatchNorm2d(oup), - nn.ReLU(inplace=True), - ) - - self.model = nn.Sequential( - conv_bn(3, 32, 2), - conv_dw(32, 64, 1), - conv_dw(64, 128, 2), - conv_dw(128, 128, 1), - conv_dw(128, 256, 2), - conv_dw(256, 256, 1), - conv_dw(256, 512, 2), - conv_dw(512, 512, 1), - conv_dw(512, 512, 1), - conv_dw(512, 512, 1), - conv_dw(512, 512, 1), - conv_dw(512, 512, 1), - conv_dw(512, 1024, 2), - conv_dw(1024, 1024, 1), - nn.AvgPool2d(7), - ) - self.fc = nn.Linear(1024, 1000) - - def forward(self, x): - x = self.model(x) - x = x.view(-1, 1024) - x = self.fc(x) - return x - - -def proc_nodes_module(checkpoint, AttrName): - new_state_dict = OrderedDict() - for k, v in checkpoint[AttrName].items(): - if k[0:7] == "module.": - name = k[7:] - else: - name = k[0:] - new_state_dict[name] = v - return new_state_dict - - -def convert_model_to_onnx(model_state, output_file): - model = Net() - if model_state: - model.load_state_dict(model_state) - model.eval() - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.randn(32, 3, 224, 224) # (batch_size, channels, width, height) - torch.onnx.export(model, dummy_input, output_file, input_names=input_names, dynamic_axes=dynamic_axes, - output_names=output_names, opset_version=11, verbose=True) - - -if __name__ == '__main__': - checkpoint_file = sys.argv[1] - output_file = sys.argv[2] - - if os.path.isfile(checkpoint_file): - checkpoint = torch.load(checkpoint_file, map_location='cpu') - print("{} successfully loaded.".format(checkpoint_file)) - model_state = proc_nodes_module(checkpoint, 'state_dict') - else: - print("Failed to load checkpoint from {}! Output model with initial state.".format(checkpoint_file)) - model_state = OrderedDict() - convert_model_to_onnx(model_state, output_file) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +from collections import OrderedDict + +import torch +import torch.nn as nn +import torch.onnx + + +class Net(nn.Module): + def __init__(self): + super(Net, self).__init__() + + def conv_bn(inp, oup, stride): + return nn.Sequential( + nn.Conv2d(inp, oup, 3, stride, 1, bias=False), + nn.BatchNorm2d(oup), + nn.ReLU(inplace=True) + ) + + def conv_dw(inp, oup, stride): + return nn.Sequential( + nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False), + nn.BatchNorm2d(inp), + nn.ReLU(inplace=True), + + nn.Conv2d(inp, oup, 1, 1, 0, bias=False), + nn.BatchNorm2d(oup), + nn.ReLU(inplace=True), + ) + + self.model = nn.Sequential( + conv_bn(3, 32, 2), + conv_dw(32, 64, 1), + conv_dw(64, 128, 2), + conv_dw(128, 128, 1), + conv_dw(128, 256, 2), + conv_dw(256, 256, 1), + conv_dw(256, 512, 2), + conv_dw(512, 512, 1), + conv_dw(512, 512, 1), + conv_dw(512, 512, 1), + conv_dw(512, 512, 1), + conv_dw(512, 512, 1), + conv_dw(512, 1024, 2), + conv_dw(1024, 1024, 1), + nn.AvgPool2d(7), + ) + self.fc = nn.Linear(1024, 1000) + + def forward(self, x): + x = self.model(x) + x = x.view(-1, 1024) + x = self.fc(x) + return x + + +def proc_nodes_module(checkpoint, AttrName): + new_state_dict = OrderedDict() + for k, v in checkpoint[AttrName].items(): + if k[0:7] == "module.": + name = k[7:] + else: + name = k[0:] + new_state_dict[name] = v + return new_state_dict + + +def convert_model_to_onnx(model_state, output_file): + model = Net() + if model_state: + model.load_state_dict(model_state) + model.eval() + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.randn(32, 3, 224, 224) # (batch_size, channels, width, height) + torch.onnx.export(model, dummy_input, output_file, input_names=input_names, dynamic_axes=dynamic_axes, + output_names=output_names, opset_version=11, verbose=True) + + +if __name__ == '__main__': + checkpoint_file = sys.argv[1] + output_file = sys.argv[2] + + if os.path.isfile(checkpoint_file): + checkpoint = torch.load(checkpoint_file, map_location='cpu') + print("{} successfully loaded.".format(checkpoint_file)) + model_state = proc_nodes_module(checkpoint, 'state_dict') + else: + print("Failed to load checkpoint from {}! Output model with initial state.".format(checkpoint_file)) + model_state = OrderedDict() + convert_model_to_onnx(model_state, output_file) diff --git a/ACL_PyTorch/contrib/cv/classfication/MobileNet-v1/test/eval_acc_perf.sh b/ACL_PyTorch/contrib/cv/classfication/MobileNet-v1/test/eval_acc_perf.sh old mode 100755 new mode 100644 diff --git a/ACL_PyTorch/contrib/cv/classfication/MobileNet-v1/test/pth2om.sh b/ACL_PyTorch/contrib/cv/classfication/MobileNet-v1/test/pth2om.sh old mode 100755 new mode 100644 diff --git a/ACL_PyTorch/contrib/cv/classfication/OSNet/README.md b/ACL_PyTorch/contrib/cv/classfication/OSNet/README.md index 2373008b8a..160d86240d 100644 --- a/ACL_PyTorch/contrib/cv/classfication/OSNet/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/OSNet/README.md @@ -1,248 +1,248 @@ -# OSNet Onnx模型端到端推理指导 -- [1 模型概述](#1-模型概述) - - [1.1 论文地址](#11-论文地址) - - [1.2 代码地址](#12-代码地址) -- [2 环境说明](#2-环境说明) -- [3 模型转换](#3-模型转换) - - [3.1 pth转onnx模型](#31-pth转onnx模型) - - [3.2 onnx转om模型](#32-onnx转om模型) -- [4 数据集预处理](#4-数据集预处理) - - [4.1 数据集获取](#41-数据集获取) - - [4.2 数据集预处理](#42-数据集预处理) - - [4.3 生成数据集信息文件](#43-生成数据集信息文件) -- [5 离线推理](#5-离线推理) - - [5.1 benchmark工具概述](#51-benchmark工具概述) - - [5.2 离线推理](#52-离线推理) -- [6 精度对比](#6-精度对比) - - [6.1 离线推理精度统计](#61-离线推理精度统计) - - [6.2 开源精度](#62-开源精度) - - [6.3 精度对比](#63-精度对比) -- [7 性能对比](#7-性能对比) - - [7.1 npu性能数据](#71-npu性能数据) - - - -## 1 模型概述 - -- **[论文地址](#11-论文地址)** - -- **[代码地址](#12-代码地址)** - -### 1.1 论文地址 -[OSNet论文](https://arxiv.org/abs/1905.00953) -作为一个实例级的识别问题,行人再识别(ReID)依赖于具有识别能力的特征,它不仅能捕获不同的空间尺度,还能封装多个尺度的任意组合。这些同构和异构尺度的特征为全尺度特征。本文设计了一种新颖的深度CNN,称为全尺度网络(OSNet),用于ReID的全尺度特征学习。这是通过设计一个由多个卷积特征流组成的残差块来实现的,每个残差块检测一定尺度的特征。重要的是,引入了一种新的统一聚合门用输入依赖的每个通道权重进行动态多尺度特征融合。为了有效地学习空间通道相关性,避免过拟合,构建块同时使用点卷积和深度卷积。通过逐层叠加这些块,OSNet非常轻量,可以在现有的ReID基准上从零开始训练。尽管OSNet模型很小,但其在6个Reid数据集上到达了SOTA结果。 - -### 1.2 代码地址 -[OSNet代码](https://github.com/KaiyangZhou/deep-person-reid) -branch:master -commit_id:e580b699c34b6f753a9a06223d840317546c98aa - -## 2 环境说明 - -深度学习框架与第三方库 -``` -pytorch == 1.8.1 -torchvision == 0.9.1 -onnx == 1.7.0 -protobuf==3.13.0 -onnx-simplifier==0.3.6 -isort==4.3.21 -numpy -Cython -h5py -Pillow -six -scipy -matplotlib -opencv-python -tb-nightly -future -yacs -gdown -flake8 -yapf -imageio -``` - -**说明:** -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3 模型转换 - -- **[pth转onnx模型](#31-pth转onnx模型)** - -- **[onnx转om模型](#32-onnx转om模型)** - -### 3.1 pth转onnx模型 - -1.下载pth权重文件 -[OSNet训练pth权重文件(google下载)](https://drive.google.com/file/d/1vduhq5DpN2q1g4fYEZfPI17MJeh9qyrA/view?usp=sharing) -[OSNet训练pth权重文件(百度网盘下载,提取码:gcfe)](https://pan.baidu.com/s/1Xkwa9TCZss_ygkC8obsEMg) -osnet_x1_0_market_256x128_amsgrad_ep150_stp60_lr0.0015_b64_fb10_softmax_labelsmooth_flip.pth - -2.下载OSNet源码: -``` -git clone https://github.com/KaiyangZhou/deep-person-reid.git -cd deep-person-reid/ -# install dependencies -pip install -r requirements.txt -# install torchreid (don't need to re-build it if you modify the source code) -python3.7 setup.py develop -``` -3.编写pth2onnx脚本pth2onnx.py -4.执行pth2onnx脚本,生成onnx模型文件 -``` -python3.7 pth2onnx.py osnet_x1_0_market_256x128_amsgrad_ep150_stp60_lr0.0015_b64_fb10_softmax_labelsmooth_flip.pth osnet_x1_0.onnx # 生成onnx模型文件 -``` -5.对onnx模型进行简化 -``` -python3.7 -m onnxsim osnet_x1_0.onnx osnet_x1_0_bs1_sim.onnx --input-shape 1,3,256,128 # batch_size = 1 -python3.7 -m onnxsim osnet_x1_0.onnx osnet_x1_0_bs16_sim.onnx --input-shape 16,3,256,128 # batch_size = 16 -``` -### 3.2 onnx转om模型 - -1.设置环境变量 -``` -source env.sh -``` -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) -``` -atc --framework=5 --model=./osnet_x1_0_bs1_sim.onnx --input_format=NCHW --input_shape="image:1,3,256,128" --output=osnet_x1_0_bs1 --log=debug --soc_version=Ascend310 # batch_size = 1 -atc --framework=5 --model=./osnet_x1_0_bs16_sim.onnx --input_format=NCHW --input_shape="image:16,3,256,128" --output=osnet_x1_0_bs16 --log=debug --soc_version=Ascend310 # batch_size = 16 -``` - -## 4 数据集预处理 - -- **[数据集获取](#41-数据集获取)** - -- **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - -### 4.1 数据集获取 -该模型使用Market1501数据集进行测试。Market-1501数据集在清华大学校园中采集,夏天拍摄,在2015年构建并公开。它包括由6个摄像头(其中5个高清摄像头和1个低清摄像头)拍摄的1501个行人的32217张图片。每个行人至少由2个摄像头捕获到,并且在一个摄像头中可能具有多张图像。 -训练集bounding_box_train有751人,包含12,936张图像,平均每个人有17.2张训练数据; -测试集bounding_box_test有750人,包含19,732张图像,平均每个人有26.3张测试数据; -查询集query有3368张查询图像。 -[Market1501数据集(百度网盘下载,提取码:me3q)](https://pan.baidu.com/s/1Nl8tMEvq-MwNGd1pG4_6bg) -Market1501数据集放在/root/datasets/,并将数据集文件夹命名为market1501。 - -### 4.2 数据集预处理 -1.预处理脚本market1501_torch_preprocess.py -2.执行预处理脚本,生成数据集预处理后的bin文件 -``` -# 处理gallery数据集,即bounding_box_test测试集 -python3.7 market1501_torch_preprocess.py /root/datasets/market1501/bounding_box_test ./gallery_prep_dataset/ -# 处理query数据集 -python3.7 market1501_torch_preprocess.py /root/datasets/market1501/query ./query_prep_dataset/ -``` -### 4.3 生成数据集信息文件 -1.生成数据集信息文件脚本gen_dataset_info.py -2.执行生成数据集信息脚本,生成gallery和query数据集信息文件 -``` -python3.7 gen_dataset_info.py bin ./gallery_prep_dataset ./gallery_prep_bin.info 128 256 -python3.7 gen_dataset_info.py bin ./query_prep_dataset ./query_prep_bin.info 128 256 -``` -第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 -## 5 离线推理 - -- **[benchmark工具概述](#51-benchmark工具概述)** - -- **[离线推理](#52-离线推理)** - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) -### 5.2 离线推理 -``` -#对query_prep_bin.info进行处理 -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=osnet_x1_0_bs1.om -input_text_path=./query_prep_bin.info -input_width=128 -input_height=256 -output_binary=False -useDvpp=False -``` -输出结果默认保存在当前目录result/dumpOutput_device0,模型只有一个名为feature的输出,每个输入对应的输出对应一个_x.bin文件。 - -``` -#对gallery_prep_bin.info进行处理 -./benchmark.x86_64 -model_type=vision -device_id=1 -batch_size=1 -om_path=osnet_x1_0_bs1.om -input_text_path=./gallery_prep_bin.info -input_width=128 -input_height=256 -output_binary=False -useDvpp=False -``` -输出结果默认保存在当前目录result/dumpOutput_device1,模型只有一个名为feature的输出,每个输入对应的输出对应一个_x.bin文件。 - -## 6 精度对比 - -- **[离线推理精度](#61-离线推理精度)** -- **[开源精度](#62-开源精度)** -- **[精度对比](#63-精度对比)** - -### 6.1 离线推理精度统计 -调用osnet_metrics_market1501_bs1.py脚本,可以获得rank1和mAP数据,结果保存在result_bs1.json中。 -``` -python3.7 osnet_x1_0_metrics_market1501.py result/dumpOutput_device0/ result/dumpOutput_device1/ ./ result_bs1.json -``` -第一个为benchmark输出目录,第二个为query数据集配套标签,第三个为gallery数据集配套标签,第四个是生成的文件名。 -查看输出结果: -``` -{"title": "Overall statistical evaluation", "value": [{"key": "R1", "value": "0.94299287"}, {"key": "mAP", "value": "0.8257416732159705"}]} -``` -### 6.2 开源精度 -[OSNet开源代码仓精度](https://kaiyangzhou.github.io/deep-person-reid/MODEL_ZOO) -``` -模型:osnet_x1_0,R1=94.2%,mAP=82.6% -``` -### 6.3 精度对比 -将得到的om离线模型推理结果R1、mAP进行比较,与该模型github代码仓上公布的精度对比,R1比代码仓结果略高,mAP下降在1%范围之内,故精度达标。 - -## 7 性能对比 - -- **[npu性能数据](#71-npu性能数据)** - -### 7.1 npu性能数据 -batch1的性能: - 测试npu性能要确保device空闲,使用npu-smi info命令可查看device是否在运行其它推理任务 -``` -./benchmark.x86_64 -round=50 -om_path=osnet_x1_0_bs1.om -device_id=0 -batch_size=1 -``` -执行50次纯推理取均值,统计吞吐率与其倒数时延(benchmark的时延是单个数据的推理时间),npu性能是一个device执行的结果 -``` -[INFO] Dataset number: 49 finished cost 4.174ms -[INFO] PureInfer result saved in ./result/PureInfer_perf_of_osnet_x1_0_bs1_sim_in_device_0.txt ------------------PureInfer Performance Summary------------------ -[INFO] ave_throughputRate: 240.622samples/s, ave_latency: 4.24716ms -``` -batch1 310单卡吞吐率:240.622×4=962.488fps -batch16的性能: -``` -./benchmark.x86_64 -round=50 -om_path=osnet_x1_0_bs16.om -device_id=2 -batch_size=16 -``` -得到batch16的性能为: -``` -[INFO] Dataset number: 49 finished cost 24.885ms -[INFO] PureInfer result saved in ./result/PureInfer_perf_of_osnet_x1_0_bs16_sim_in_device_2.txt ------------------PureInfer Performance Summary------------------ -[INFO] ave_throughputRate: 643.052samples/s, ave_latency: 1.55994ms -``` -batch16 310单卡吞吐率:643.052×4=2572.208fps -batch4的性能: -``` -[INFO] Dataset number: 49 finished cost 6.434ms -[INFO] PureInfer result saved in ./result/PureInfer_perf_of_osnet_x1_0_bs4_in_device_0.txt ------------------PureInfer Performance Summary------------------ -[INFO] ave_throughputRate: 604.718samples/s, ave_latency: 1.68188ms -``` -batch4 310单卡吞吐率:604.718×4=2418.872fps -batch8的性能: -``` -[INFO] Dataset number: 49 finished cost 11.107ms -[INFO] PureInfer result saved in ./result/PureInfer_perf_of_osnet_x1_0_bs8_in_device_0.txt ------------------PureInfer Performance Summary------------------ -[INFO] ave_throughputRate: 715.699samples/s, ave_latency: 1.41114ms -``` -batch8 310单卡吞吐率:715.699×4=2862.796fps -batch32的性能: -``` -[INFO] Dataset number: 49 finished cost 50.178ms -[INFO] PureInfer result saved in ./result/PureInfer_perf_of_osnet_x1_0_bs32_in_device_0.txt ------------------PureInfer Performance Summary------------------ -[INFO] ave_throughputRate: 632.875samples/s, ave_latency: 1.58384ms -``` -batch32 310单卡吞吐率:632.875×4=2531.5fps +# OSNet Onnx模型端到端推理指导 +- [1 模型概述](#1-模型概述) + - [1.1 论文地址](#11-论文地址) + - [1.2 代码地址](#12-代码地址) +- [2 环境说明](#2-环境说明) +- [3 模型转换](#3-模型转换) + - [3.1 pth转onnx模型](#31-pth转onnx模型) + - [3.2 onnx转om模型](#32-onnx转om模型) +- [4 数据集预处理](#4-数据集预处理) + - [4.1 数据集获取](#41-数据集获取) + - [4.2 数据集预处理](#42-数据集预处理) + - [4.3 生成数据集信息文件](#43-生成数据集信息文件) +- [5 离线推理](#5-离线推理) + - [5.1 benchmark工具概述](#51-benchmark工具概述) + - [5.2 离线推理](#52-离线推理) +- [6 精度对比](#6-精度对比) + - [6.1 离线推理精度统计](#61-离线推理精度统计) + - [6.2 开源精度](#62-开源精度) + - [6.3 精度对比](#63-精度对比) +- [7 性能对比](#7-性能对比) + - [7.1 npu性能数据](#71-npu性能数据) + + + +## 1 模型概述 + +- **[论文地址](#11-论文地址)** + +- **[代码地址](#12-代码地址)** + +### 1.1 论文地址 +[OSNet论文](https://arxiv.org/abs/1905.00953) +作为一个实例级的识别问题,行人再识别(ReID)依赖于具有识别能力的特征,它不仅能捕获不同的空间尺度,还能封装多个尺度的任意组合。这些同构和异构尺度的特征为全尺度特征。本文设计了一种新颖的深度CNN,称为全尺度网络(OSNet),用于ReID的全尺度特征学习。这是通过设计一个由多个卷积特征流组成的残差块来实现的,每个残差块检测一定尺度的特征。重要的是,引入了一种新的统一聚合门用输入依赖的每个通道权重进行动态多尺度特征融合。为了有效地学习空间通道相关性,避免过拟合,构建块同时使用点卷积和深度卷积。通过逐层叠加这些块,OSNet非常轻量,可以在现有的ReID基准上从零开始训练。尽管OSNet模型很小,但其在6个Reid数据集上到达了SOTA结果。 + +### 1.2 代码地址 +[OSNet代码](https://github.com/KaiyangZhou/deep-person-reid) +branch:master +commit_id:e580b699c34b6f753a9a06223d840317546c98aa + +## 2 环境说明 + +深度学习框架与第三方库 +``` +pytorch == 1.8.1 +torchvision == 0.9.1 +onnx == 1.7.0 +protobuf==3.13.0 +onnx-simplifier==0.3.6 +isort==4.3.21 +numpy +Cython +h5py +Pillow +six +scipy +matplotlib +opencv-python +tb-nightly +future +yacs +gdown +flake8 +yapf +imageio +``` + +**说明:** +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3 模型转换 + +- **[pth转onnx模型](#31-pth转onnx模型)** + +- **[onnx转om模型](#32-onnx转om模型)** + +### 3.1 pth转onnx模型 + +1.下载pth权重文件 +[OSNet训练pth权重文件(google下载)](https://drive.google.com/file/d/1vduhq5DpN2q1g4fYEZfPI17MJeh9qyrA/view?usp=sharing) +[OSNet训练pth权重文件(百度网盘下载,提取码:gcfe)](https://pan.baidu.com/s/1Xkwa9TCZss_ygkC8obsEMg) +osnet_x1_0_market_256x128_amsgrad_ep150_stp60_lr0.0015_b64_fb10_softmax_labelsmooth_flip.pth + +2.下载OSNet源码: +``` +git clone https://github.com/KaiyangZhou/deep-person-reid.git +cd deep-person-reid/ +# install dependencies +pip install -r requirements.txt +# install torchreid (don't need to re-build it if you modify the source code) +python3.7 setup.py develop +``` +3.编写pth2onnx脚本pth2onnx.py +4.执行pth2onnx脚本,生成onnx模型文件 +``` +python3.7 pth2onnx.py osnet_x1_0_market_256x128_amsgrad_ep150_stp60_lr0.0015_b64_fb10_softmax_labelsmooth_flip.pth osnet_x1_0.onnx # 生成onnx模型文件 +``` +5.对onnx模型进行简化 +``` +python3.7 -m onnxsim osnet_x1_0.onnx osnet_x1_0_bs1_sim.onnx --input-shape 1,3,256,128 # batch_size = 1 +python3.7 -m onnxsim osnet_x1_0.onnx osnet_x1_0_bs16_sim.onnx --input-shape 16,3,256,128 # batch_size = 16 +``` +### 3.2 onnx转om模型 + +1.设置环境变量 +``` +source env.sh +``` +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) +``` +atc --framework=5 --model=./osnet_x1_0_bs1_sim.onnx --input_format=NCHW --input_shape="image:1,3,256,128" --output=osnet_x1_0_bs1 --log=debug --soc_version=Ascend310 # batch_size = 1 +atc --framework=5 --model=./osnet_x1_0_bs16_sim.onnx --input_format=NCHW --input_shape="image:16,3,256,128" --output=osnet_x1_0_bs16 --log=debug --soc_version=Ascend310 # batch_size = 16 +``` + +## 4 数据集预处理 + +- **[数据集获取](#41-数据集获取)** + +- **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + +### 4.1 数据集获取 +该模型使用Market1501数据集进行测试。Market-1501数据集在清华大学校园中采集,夏天拍摄,在2015年构建并公开。它包括由6个摄像头(其中5个高清摄像头和1个低清摄像头)拍摄的1501个行人的32217张图片。每个行人至少由2个摄像头捕获到,并且在一个摄像头中可能具有多张图像。 +训练集bounding_box_train有751人,包含12,936张图像,平均每个人有17.2张训练数据; +测试集bounding_box_test有750人,包含19,732张图像,平均每个人有26.3张测试数据; +查询集query有3368张查询图像。 +[Market1501数据集(百度网盘下载,提取码:me3q)](https://pan.baidu.com/s/1Nl8tMEvq-MwNGd1pG4_6bg) +Market1501数据集放在/root/datasets/,并将数据集文件夹命名为market1501。 + +### 4.2 数据集预处理 +1.预处理脚本market1501_torch_preprocess.py +2.执行预处理脚本,生成数据集预处理后的bin文件 +``` +# 处理gallery数据集,即bounding_box_test测试集 +python3.7 market1501_torch_preprocess.py /root/datasets/market1501/bounding_box_test ./gallery_prep_dataset/ +# 处理query数据集 +python3.7 market1501_torch_preprocess.py /root/datasets/market1501/query ./query_prep_dataset/ +``` +### 4.3 生成数据集信息文件 +1.生成数据集信息文件脚本gen_dataset_info.py +2.执行生成数据集信息脚本,生成gallery和query数据集信息文件 +``` +python3.7 gen_dataset_info.py bin ./gallery_prep_dataset ./gallery_prep_bin.info 128 256 +python3.7 gen_dataset_info.py bin ./query_prep_dataset ./query_prep_bin.info 128 256 +``` +第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 +## 5 离线推理 + +- **[benchmark工具概述](#51-benchmark工具概述)** + +- **[离线推理](#52-离线推理)** + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) +### 5.2 离线推理 +``` +#对query_prep_bin.info进行处理 +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=osnet_x1_0_bs1.om -input_text_path=./query_prep_bin.info -input_width=128 -input_height=256 -output_binary=False -useDvpp=False +``` +输出结果默认保存在当前目录result/dumpOutput_device0,模型只有一个名为feature的输出,每个输入对应的输出对应一个_x.bin文件。 + +``` +#对gallery_prep_bin.info进行处理 +./benchmark.x86_64 -model_type=vision -device_id=1 -batch_size=1 -om_path=osnet_x1_0_bs1.om -input_text_path=./gallery_prep_bin.info -input_width=128 -input_height=256 -output_binary=False -useDvpp=False +``` +输出结果默认保存在当前目录result/dumpOutput_device1,模型只有一个名为feature的输出,每个输入对应的输出对应一个_x.bin文件。 + +## 6 精度对比 + +- **[离线推理精度](#61-离线推理精度)** +- **[开源精度](#62-开源精度)** +- **[精度对比](#63-精度对比)** + +### 6.1 离线推理精度统计 +调用osnet_metrics_market1501_bs1.py脚本,可以获得rank1和mAP数据,结果保存在result_bs1.json中。 +``` +python3.7 osnet_x1_0_metrics_market1501.py result/dumpOutput_device0/ result/dumpOutput_device1/ ./ result_bs1.json +``` +第一个为benchmark输出目录,第二个为query数据集配套标签,第三个为gallery数据集配套标签,第四个是生成的文件名。 +查看输出结果: +``` +{"title": "Overall statistical evaluation", "value": [{"key": "R1", "value": "0.94299287"}, {"key": "mAP", "value": "0.8257416732159705"}]} +``` +### 6.2 开源精度 +[OSNet开源代码仓精度](https://kaiyangzhou.github.io/deep-person-reid/MODEL_ZOO) +``` +模型:osnet_x1_0,R1=94.2%,mAP=82.6% +``` +### 6.3 精度对比 +将得到的om离线模型推理结果R1、mAP进行比较,与该模型github代码仓上公布的精度对比,R1比代码仓结果略高,mAP下降在1%范围之内,故精度达标。 + +## 7 性能对比 + +- **[npu性能数据](#71-npu性能数据)** + +### 7.1 npu性能数据 +batch1的性能: + 测试npu性能要确保device空闲,使用npu-smi info命令可查看device是否在运行其它推理任务 +``` +./benchmark.x86_64 -round=50 -om_path=osnet_x1_0_bs1.om -device_id=0 -batch_size=1 +``` +执行50次纯推理取均值,统计吞吐率与其倒数时延(benchmark的时延是单个数据的推理时间),npu性能是一个device执行的结果 +``` +[INFO] Dataset number: 49 finished cost 4.174ms +[INFO] PureInfer result saved in ./result/PureInfer_perf_of_osnet_x1_0_bs1_sim_in_device_0.txt +-----------------PureInfer Performance Summary------------------ +[INFO] ave_throughputRate: 240.622samples/s, ave_latency: 4.24716ms +``` +batch1 310单卡吞吐率:240.622×4=962.488fps +batch16的性能: +``` +./benchmark.x86_64 -round=50 -om_path=osnet_x1_0_bs16.om -device_id=2 -batch_size=16 +``` +得到batch16的性能为: +``` +[INFO] Dataset number: 49 finished cost 24.885ms +[INFO] PureInfer result saved in ./result/PureInfer_perf_of_osnet_x1_0_bs16_sim_in_device_2.txt +-----------------PureInfer Performance Summary------------------ +[INFO] ave_throughputRate: 643.052samples/s, ave_latency: 1.55994ms +``` +batch16 310单卡吞吐率:643.052×4=2572.208fps +batch4的性能: +``` +[INFO] Dataset number: 49 finished cost 6.434ms +[INFO] PureInfer result saved in ./result/PureInfer_perf_of_osnet_x1_0_bs4_in_device_0.txt +-----------------PureInfer Performance Summary------------------ +[INFO] ave_throughputRate: 604.718samples/s, ave_latency: 1.68188ms +``` +batch4 310单卡吞吐率:604.718×4=2418.872fps +batch8的性能: +``` +[INFO] Dataset number: 49 finished cost 11.107ms +[INFO] PureInfer result saved in ./result/PureInfer_perf_of_osnet_x1_0_bs8_in_device_0.txt +-----------------PureInfer Performance Summary------------------ +[INFO] ave_throughputRate: 715.699samples/s, ave_latency: 1.41114ms +``` +batch8 310单卡吞吐率:715.699×4=2862.796fps +batch32的性能: +``` +[INFO] Dataset number: 49 finished cost 50.178ms +[INFO] PureInfer result saved in ./result/PureInfer_perf_of_osnet_x1_0_bs32_in_device_0.txt +-----------------PureInfer Performance Summary------------------ +[INFO] ave_throughputRate: 632.875samples/s, ave_latency: 1.58384ms +``` +batch32 310单卡吞吐率:632.875×4=2531.5fps diff --git a/ACL_PyTorch/contrib/cv/classfication/OSNet/test/README.md b/ACL_PyTorch/contrib/cv/classfication/OSNet/test/README.md index 06c60701b2..e27dc3d1ac 100644 --- a/ACL_PyTorch/contrib/cv/classfication/OSNet/test/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/OSNet/test/README.md @@ -1,31 +1,31 @@ -环境准备: - -1.数据集路径 -[Market1501数据集(百度网盘下载,提取码:me3q)](https://pan.baidu.com/s/1Nl8tMEvq-MwNGd1pG4_6bg) -Market1501数据集放在/root/datasets/,并将数据集文件夹命名为market1501。 - -2.进入工作目录 -cd OSNet - -3.安装必要的依赖 -pip3.7 install -r requirements.txt - -4.获取模型代码 -git clone https://github.com/KaiyangZhou/deep-person-reid.git -cd deep-person-reid - -5.加载模型 -python3.7 setup.py develop - -6.获取权重文件 -[OSNet训练pth权重文件(google下载)](https://drive.google.com/file/d/1vduhq5DpN2q1g4fYEZfPI17MJeh9qyrA/view?usp=sharing) -[OSNet训练pth权重文件(百度网盘下载,提取码:gcfe)](https://pan.baidu.com/s/1Xkwa9TCZss_ygkC8obsEMg) -将权重文件osnet_x1_0_market_256x128_amsgrad_ep150_stp60_lr0.0015_b64_fb10_softmax_labelsmooth_flip.pth放于OSNet目录下 - -7.获取benchmark工具 -将benchmark.x86_64 benchmark.aarch64放于OSNet目录下 - -8.310上执行,执行时确保device空闲 -cd OSNet -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets +环境准备: + +1.数据集路径 +[Market1501数据集(百度网盘下载,提取码:me3q)](https://pan.baidu.com/s/1Nl8tMEvq-MwNGd1pG4_6bg) +Market1501数据集放在/root/datasets/,并将数据集文件夹命名为market1501。 + +2.进入工作目录 +cd OSNet + +3.安装必要的依赖 +pip3.7 install -r requirements.txt + +4.获取模型代码 +git clone https://github.com/KaiyangZhou/deep-person-reid.git +cd deep-person-reid + +5.加载模型 +python3.7 setup.py develop + +6.获取权重文件 +[OSNet训练pth权重文件(google下载)](https://drive.google.com/file/d/1vduhq5DpN2q1g4fYEZfPI17MJeh9qyrA/view?usp=sharing) +[OSNet训练pth权重文件(百度网盘下载,提取码:gcfe)](https://pan.baidu.com/s/1Xkwa9TCZss_ygkC8obsEMg) +将权重文件osnet_x1_0_market_256x128_amsgrad_ep150_stp60_lr0.0015_b64_fb10_softmax_labelsmooth_flip.pth放于OSNet目录下 + +7.获取benchmark工具 +将benchmark.x86_64 benchmark.aarch64放于OSNet目录下 + +8.310上执行,执行时确保device空闲 +cd OSNet +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets diff --git a/ACL_PyTorch/contrib/cv/classfication/PAMTRI/PAMTRI_postprocess.py b/ACL_PyTorch/contrib/cv/classfication/PAMTRI/PAMTRI_postprocess.py index aecfa9467e..99e472dcc8 100644 --- a/ACL_PyTorch/contrib/cv/classfication/PAMTRI/PAMTRI_postprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/PAMTRI/PAMTRI_postprocess.py @@ -1,140 +1,140 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 print_function -from __future__ import division - - -import argparse -import numpy as np -import torch -from torch.utils.data import DataLoader -from torchreid import models -from torchreid.data_manager import DatasetManager -from torchreid.dataset_loader import ImageDataset -from torchreid.eval_metrics import evaluate -from torchreid import transforms as T -torch.multiprocessing.set_sharing_strategy('file_system') -import os - -def postprocess(ranks=range(1, 51)): - - dataset = DatasetManager(dataset_dir=args.dataset, root=args.root) - - transform_test = T.Compose_Keypt([ - T.Resize_Keypt((256,256)), - T.ToTensor_Keypt(), - T.Normalize_Keypt(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), - ]) - - queryloader = DataLoader( - ImageDataset(dataset.query, keyptaware=False, heatmapaware=False, - segmentaware=False, - transform=transform_test, imagesize=(256,256)), - batch_size=args.test_batch, shuffle=False, num_workers=args.workers, - drop_last=False, - ) - - galleryloader = DataLoader( - ImageDataset(dataset.gallery, keyptaware=False, heatmapaware=False, - segmentaware=False, - transform=transform_test, imagesize=(256,256)), - batch_size=args.test_batch, shuffle=False, num_workers=args.workers, - drop_last=False, - ) - qf = [] - q_vids = [] - q_camids = [] - for batch_idx, (imgs, vids, camids, vcolors, vtypes, vkeypts) in enumerate(queryloader): - q_vids.extend(vids) - q_camids.extend(camids) - q_vids = np.asarray(q_vids) - q_camids = np.asarray(q_camids) - - for root, folder, files in os.walk(args.queryfeature_path): - files.sort(key=lambda x:int(x.split('_')[0])) - for file in files: - truefile1 = file.split('_')[1] - if truefile1 == "4.bin": #将benckmark推理出的第四个输出"features"读入,features为计算mAP值的特征 - file_path = os.path.join(root, file) - with open(file_path,'rb') as f: - featuresq = np.fromfile(f, dtype="float32") - featuresq = torch.from_numpy(featuresq) - featuresq = featuresq.unsqueeze(0) - featuresq = featuresq.data.cpu() - qf.append(featuresq) - qf = torch.cat(qf, 0) - - print("Extracted features for query set, obtained {}-by-{} matrix".format(qf.size(0), qf.size(1))) - - gf = [] - g_vids = [] - g_camids = [] - for batch_idx, (imgs, vids, camids, vcolors, vtypes, vkeypts) in enumerate(galleryloader): - g_vids.extend(vids) - g_camids.extend(camids) - g_vids = np.asarray(g_vids) - g_camids = np.asarray(g_camids) - - for root, folder, files in os.walk(args.galleryfeature_path): - files.sort(key=lambda x: int(x.split('_')[0])) - for file in files: - truefile2 = file.split('_')[1] - if truefile2== "4.bin": #将benckmark推理出的第四个输出"features"读入,features为计算mAP值的特征 - file_path = os.path.join(root, file) - with open(file_path,'rb') as f: - featuresg = np.fromfile(f, dtype="float32") - featuresg = torch.from_numpy(featuresg) - featuresg = featuresg.unsqueeze(0) - featuresg = featuresg.data.cpu() - gf.append(featuresg) - gf = torch.cat(gf, 0) - - print("Extracted features for gallery set, obtained {}-by-{} matrix".format(gf.size(0), gf.size(1))) - - m, n = qf.size(0), gf.size(0) - distmat = torch.pow(qf, 2).sum(dim=1, keepdim=True).expand(m, n) + \ - torch.pow(gf, 2).sum(dim=1, keepdim=True).expand(n, m).t() - distmat.addmm_(1, -2, qf, gf.t()) - distmat = distmat.numpy() - - print("Computing CMC and mAP") - cmc, mAP = evaluate(distmat, q_vids, g_vids, q_camids, g_camids) - - print("Results ----------") - print("mAP: {:.2%}".format(mAP)) - print("CMC curve") - for r in ranks: - print("Rank-{:<3}: {:.2%}".format(r, cmc[r - 1])) - print("------------------") - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--query_dir", default="./data/veri/image_query") - parser.add_argument("--gallery_dir", default="./data/veri/image_test") - parser.add_argument("--queryfeature_path", default="./result/dumpOutput_device0_query") - parser.add_argument("--galleryfeature_path", default="./result/dumpOutput_device0_gallery") - parser.add_argument('--root', type=str, default='data', - help="root path to data directory") - parser.add_argument('-d', '--dataset', type=str, default='veri', - help="name of the dataset") - parser.add_argument('-j', '--workers', default=4, type=int, - help="number of data loading workers (default: 4)") - parser.add_argument('--test-batch', default=1, type=int, - help="test batch size") - parser.add_argument('-a', '--arch', type=str, default='densenet121', choices=models.get_names()) - args = parser.parse_args() - - postprocess() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 print_function +from __future__ import division + + +import argparse +import numpy as np +import torch +from torch.utils.data import DataLoader +from torchreid import models +from torchreid.data_manager import DatasetManager +from torchreid.dataset_loader import ImageDataset +from torchreid.eval_metrics import evaluate +from torchreid import transforms as T +torch.multiprocessing.set_sharing_strategy('file_system') +import os + +def postprocess(ranks=range(1, 51)): + + dataset = DatasetManager(dataset_dir=args.dataset, root=args.root) + + transform_test = T.Compose_Keypt([ + T.Resize_Keypt((256,256)), + T.ToTensor_Keypt(), + T.Normalize_Keypt(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), + ]) + + queryloader = DataLoader( + ImageDataset(dataset.query, keyptaware=False, heatmapaware=False, + segmentaware=False, + transform=transform_test, imagesize=(256,256)), + batch_size=args.test_batch, shuffle=False, num_workers=args.workers, + drop_last=False, + ) + + galleryloader = DataLoader( + ImageDataset(dataset.gallery, keyptaware=False, heatmapaware=False, + segmentaware=False, + transform=transform_test, imagesize=(256,256)), + batch_size=args.test_batch, shuffle=False, num_workers=args.workers, + drop_last=False, + ) + qf = [] + q_vids = [] + q_camids = [] + for batch_idx, (imgs, vids, camids, vcolors, vtypes, vkeypts) in enumerate(queryloader): + q_vids.extend(vids) + q_camids.extend(camids) + q_vids = np.asarray(q_vids) + q_camids = np.asarray(q_camids) + + for root, folder, files in os.walk(args.queryfeature_path): + files.sort(key=lambda x:int(x.split('_')[0])) + for file in files: + truefile1 = file.split('_')[1] + if truefile1 == "4.bin": #将benckmark推理出的第四个输出"features"读入,features为计算mAP值的特征 + file_path = os.path.join(root, file) + with open(file_path,'rb') as f: + featuresq = np.fromfile(f, dtype="float32") + featuresq = torch.from_numpy(featuresq) + featuresq = featuresq.unsqueeze(0) + featuresq = featuresq.data.cpu() + qf.append(featuresq) + qf = torch.cat(qf, 0) + + print("Extracted features for query set, obtained {}-by-{} matrix".format(qf.size(0), qf.size(1))) + + gf = [] + g_vids = [] + g_camids = [] + for batch_idx, (imgs, vids, camids, vcolors, vtypes, vkeypts) in enumerate(galleryloader): + g_vids.extend(vids) + g_camids.extend(camids) + g_vids = np.asarray(g_vids) + g_camids = np.asarray(g_camids) + + for root, folder, files in os.walk(args.galleryfeature_path): + files.sort(key=lambda x: int(x.split('_')[0])) + for file in files: + truefile2 = file.split('_')[1] + if truefile2== "4.bin": #将benckmark推理出的第四个输出"features"读入,features为计算mAP值的特征 + file_path = os.path.join(root, file) + with open(file_path,'rb') as f: + featuresg = np.fromfile(f, dtype="float32") + featuresg = torch.from_numpy(featuresg) + featuresg = featuresg.unsqueeze(0) + featuresg = featuresg.data.cpu() + gf.append(featuresg) + gf = torch.cat(gf, 0) + + print("Extracted features for gallery set, obtained {}-by-{} matrix".format(gf.size(0), gf.size(1))) + + m, n = qf.size(0), gf.size(0) + distmat = torch.pow(qf, 2).sum(dim=1, keepdim=True).expand(m, n) + \ + torch.pow(gf, 2).sum(dim=1, keepdim=True).expand(n, m).t() + distmat.addmm_(1, -2, qf, gf.t()) + distmat = distmat.numpy() + + print("Computing CMC and mAP") + cmc, mAP = evaluate(distmat, q_vids, g_vids, q_camids, g_camids) + + print("Results ----------") + print("mAP: {:.2%}".format(mAP)) + print("CMC curve") + for r in ranks: + print("Rank-{:<3}: {:.2%}".format(r, cmc[r - 1])) + print("------------------") + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("--query_dir", default="./data/veri/image_query") + parser.add_argument("--gallery_dir", default="./data/veri/image_test") + parser.add_argument("--queryfeature_path", default="./result/dumpOutput_device0_query") + parser.add_argument("--galleryfeature_path", default="./result/dumpOutput_device0_gallery") + parser.add_argument('--root', type=str, default='data', + help="root path to data directory") + parser.add_argument('-d', '--dataset', type=str, default='veri', + help="name of the dataset") + parser.add_argument('-j', '--workers', default=4, type=int, + help="number of data loading workers (default: 4)") + parser.add_argument('--test-batch', default=1, type=int, + help="test batch size") + parser.add_argument('-a', '--arch', type=str, default='densenet121', choices=models.get_names()) + args = parser.parse_args() + + postprocess() diff --git a/ACL_PyTorch/contrib/cv/classfication/PAMTRI/PAMTRI_preprocess.py b/ACL_PyTorch/contrib/cv/classfication/PAMTRI/PAMTRI_preprocess.py index b3ce371f5b..78665cafef 100644 --- a/ACL_PyTorch/contrib/cv/classfication/PAMTRI/PAMTRI_preprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/PAMTRI/PAMTRI_preprocess.py @@ -1,92 +1,92 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 print_function -from __future__ import division -import os -import argparse -import numpy as np -from torch.utils.data import DataLoader -from torchreid.data_manager import DatasetManager -from torchreid.dataset_loader import ImageDataset -from torchreid import transforms as T -from torchreid import models -from PIL import Image -import sys - -def preprocess(): - print("==========\nArgs:{}\n==========".format(args)) - print("Initializing dataset {}".format(args.dataset)) - dataset = DatasetManager(dataset_dir=args.dataset, root=args.root) - - transform_test = T.Compose_Keypt([ - T.Resize_Keypt((256, 256)), - T.ToTensor_Keypt(), - T.Normalize_Keypt(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), - ]) - - queryloader = DataLoader( - ImageDataset(dataset.query, keyptaware=False, heatmapaware=False, segmentaware=False, - transform=transform_test, imagesize=(256, 256)), - batch_size=args.test_batch, shuffle=False, num_workers=args.workers, - pin_memory=False, drop_last=False, - ) - - galleryloader = DataLoader( - ImageDataset(dataset.gallery, keyptaware=False, heatmapaware=False, segmentaware=False, - transform=transform_test, imagesize=(256, 256)), - batch_size=args.test_batch, shuffle=False, num_workers=args.workers, - pin_memory=False, drop_last=False, - ) - - get_bin(queryloader, galleryloader) - - -def get_bin(queryloader, galleryloader): - queryloader_num = 0 - galleryloader_num = 0 - for batch_idx, (imgs, vids, camids, vcolors, vtypes, vkeypts) in enumerate(queryloader): - query = imgs.numpy() - query.tofile(os.path.join(args.save_path1, "{}.bin".format(queryloader_num))) - queryloader_num = queryloader_num + 1 - - for batch_idx, (imgs, vids, camids, vcolors, vtypes, vkeypts) in enumerate(galleryloader): - gallery = imgs.numpy() - gallery.tofile(os.path.join(args.save_path2, "{}.bin".format(galleryloader_num))) - galleryloader_num = galleryloader_num + 1 - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--query_dir", default="./data/veri/image_query") - parser.add_argument("--gallery_dir", default="./data/veri/image_test") - parser.add_argument("--save_path1", default="./prep_dataset_query") - parser.add_argument("--save_path2", default="./prep_dataset_gallery") - parser.add_argument('--root', type=str, default='data', - help="root path to data directory") - parser.add_argument('-d', '--dataset', type=str, default='veri', - help="name of the dataset") - parser.add_argument('-j', '--workers', default=4, type=int, - help="number of data loading workers (default: 4)") - parser.add_argument('--test-batch', default=1, type=int, - help="test batch size") - parser.add_argument('-a', '--arch', type=str, default='densenet121', choices=models.get_names()) - args = parser.parse_args() - - if not os.path.isdir(args.save_path1): - os.makedirs(os.path.realpath(args.save_path1)) - if not os.path.isdir(args.save_path2): - os.makedirs(os.path.realpath(args.save_path2)) - preprocess() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 print_function +from __future__ import division +import os +import argparse +import numpy as np +from torch.utils.data import DataLoader +from torchreid.data_manager import DatasetManager +from torchreid.dataset_loader import ImageDataset +from torchreid import transforms as T +from torchreid import models +from PIL import Image +import sys + +def preprocess(): + print("==========\nArgs:{}\n==========".format(args)) + print("Initializing dataset {}".format(args.dataset)) + dataset = DatasetManager(dataset_dir=args.dataset, root=args.root) + + transform_test = T.Compose_Keypt([ + T.Resize_Keypt((256, 256)), + T.ToTensor_Keypt(), + T.Normalize_Keypt(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), + ]) + + queryloader = DataLoader( + ImageDataset(dataset.query, keyptaware=False, heatmapaware=False, segmentaware=False, + transform=transform_test, imagesize=(256, 256)), + batch_size=args.test_batch, shuffle=False, num_workers=args.workers, + pin_memory=False, drop_last=False, + ) + + galleryloader = DataLoader( + ImageDataset(dataset.gallery, keyptaware=False, heatmapaware=False, segmentaware=False, + transform=transform_test, imagesize=(256, 256)), + batch_size=args.test_batch, shuffle=False, num_workers=args.workers, + pin_memory=False, drop_last=False, + ) + + get_bin(queryloader, galleryloader) + + +def get_bin(queryloader, galleryloader): + queryloader_num = 0 + galleryloader_num = 0 + for batch_idx, (imgs, vids, camids, vcolors, vtypes, vkeypts) in enumerate(queryloader): + query = imgs.numpy() + query.tofile(os.path.join(args.save_path1, "{}.bin".format(queryloader_num))) + queryloader_num = queryloader_num + 1 + + for batch_idx, (imgs, vids, camids, vcolors, vtypes, vkeypts) in enumerate(galleryloader): + gallery = imgs.numpy() + gallery.tofile(os.path.join(args.save_path2, "{}.bin".format(galleryloader_num))) + galleryloader_num = galleryloader_num + 1 + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("--query_dir", default="./data/veri/image_query") + parser.add_argument("--gallery_dir", default="./data/veri/image_test") + parser.add_argument("--save_path1", default="./prep_dataset_query") + parser.add_argument("--save_path2", default="./prep_dataset_gallery") + parser.add_argument('--root', type=str, default='data', + help="root path to data directory") + parser.add_argument('-d', '--dataset', type=str, default='veri', + help="name of the dataset") + parser.add_argument('-j', '--workers', default=4, type=int, + help="number of data loading workers (default: 4)") + parser.add_argument('--test-batch', default=1, type=int, + help="test batch size") + parser.add_argument('-a', '--arch', type=str, default='densenet121', choices=models.get_names()) + args = parser.parse_args() + + if not os.path.isdir(args.save_path1): + os.makedirs(os.path.realpath(args.save_path1)) + if not os.path.isdir(args.save_path2): + os.makedirs(os.path.realpath(args.save_path2)) + preprocess() diff --git a/ACL_PyTorch/contrib/cv/classfication/PAMTRI/README.md b/ACL_PyTorch/contrib/cv/classfication/PAMTRI/README.md index 580a7bfd66..b786023001 100644 --- a/ACL_PyTorch/contrib/cv/classfication/PAMTRI/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/PAMTRI/README.md @@ -1,70 +1,70 @@ -# PAMTR模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -``` -pip3.7 install -r requirements.txt -``` - - -2.获取,修改与安装开源模型代码 -``` -git clone https://github.com/NVlabs/PAMTRI -b master -cd MultiTaskNet -mv ./densenet.patch ./torchreid/models/ -cd ./torchreid/models/ -patch -p1 < densenet.patch -``` - -3.获取权重文件 - -将权重文件densenet121-a639ec97.pth放到当前工作目录(执行pth2onnx时会自动下载) -可以通过以下命令下载: -``` -wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/classfication/PAMTRI/densenet121-a639ec97.pth -``` - -4.数据集 - -参考[github开源代码仓内数据集获取方法](https://github.com/NVlabs/PAMTRI),将数据集放到./data目录。 -下载[数据集的label文件](https://github.com/NVlabs/PAMTRI.git),在PAMTRI/MultiTaskNet/data/veri/下获取label.csv文件。将数据集解压在./data/veri/目录下,应包含image_train、image_test、image_query三个数据集文件以及相应的.csv文件。 - -5.[获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) -将benchmark.x86_64或benchmark.aarch64放到当前工作目录 - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 -``` -bash ./test/pth2om.sh -#启动脚本内3-8行为pth2onnx,10-19行为onnx2om,脚本执行完成后会生成PAMTRI.onnx、PAMTRI_bs1.om、PAMTRI_bs16.om三个模型。 -bash ./test/eval_acc_perf.sh --datasets_path=./data #datesets_path参数为指定数据集路径 -#启动脚本内12-15行为前处理,将图片信息转换为二进制bin文件;17-24行为提取与汇总前处理生成的bin文件信息;32-58行为benckmark推理,会生成推理后的特征信息与推理性能文件;60-69行为后处理,对推理出的特征信息进行评测,生成精度信息文件;70-92行为打印推理性能和精度信息。 -``` - **评测结果:** -| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | -| :-----------------------: | :----------------------------------------------------------: | :-------------------: | :------: | :---------: | -| PAMTRI bs1 | [mAP:68.64%](https://github.com/NVlabs/PAMTRI) | mAP:68.64% | 215.932fps | 627.662fps | -| PAMTRI bs16 | [mAP:68.64%](https://github.com/NVlabs/PAMTRI) | mAP:68.64% | 810.976fps | 833.668fps | -# 自检报告 - -``` -# pth是否能正确转换为om -bash test/pth2om.sh -# 验收结果: OK - -# 精度数据是否达标 -# npu性能数据 -bash test/eval_acc_perf.sh -# 验收结果: 是 - -# 在t4环境测试性能数据 -bash test/perf_t4.sh -# 验收结果: OK - -# 310性能是否符合标准: 是 -bs1:310=2.9倍t4 -bs16:310=1.03倍t4 - -``` +# PAMTR模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +``` +pip3.7 install -r requirements.txt +``` + + +2.获取,修改与安装开源模型代码 +``` +git clone https://github.com/NVlabs/PAMTRI -b master +cd MultiTaskNet +mv ./densenet.patch ./torchreid/models/ +cd ./torchreid/models/ +patch -p1 < densenet.patch +``` + +3.获取权重文件 + +将权重文件densenet121-a639ec97.pth放到当前工作目录(执行pth2onnx时会自动下载) +可以通过以下命令下载: +``` +wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/classfication/PAMTRI/densenet121-a639ec97.pth +``` + +4.数据集 + +参考[github开源代码仓内数据集获取方法](https://github.com/NVlabs/PAMTRI),将数据集放到./data目录。 +下载[数据集的label文件](https://github.com/NVlabs/PAMTRI.git),在PAMTRI/MultiTaskNet/data/veri/下获取label.csv文件。将数据集解压在./data/veri/目录下,应包含image_train、image_test、image_query三个数据集文件以及相应的.csv文件。 + +5.[获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) +将benchmark.x86_64或benchmark.aarch64放到当前工作目录 + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 +``` +bash ./test/pth2om.sh +#启动脚本内3-8行为pth2onnx,10-19行为onnx2om,脚本执行完成后会生成PAMTRI.onnx、PAMTRI_bs1.om、PAMTRI_bs16.om三个模型。 +bash ./test/eval_acc_perf.sh --datasets_path=./data #datesets_path参数为指定数据集路径 +#启动脚本内12-15行为前处理,将图片信息转换为二进制bin文件;17-24行为提取与汇总前处理生成的bin文件信息;32-58行为benckmark推理,会生成推理后的特征信息与推理性能文件;60-69行为后处理,对推理出的特征信息进行评测,生成精度信息文件;70-92行为打印推理性能和精度信息。 +``` + **评测结果:** +| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | +| :-----------------------: | :----------------------------------------------------------: | :-------------------: | :------: | :---------: | +| PAMTRI bs1 | [mAP:68.64%](https://github.com/NVlabs/PAMTRI) | mAP:68.64% | 215.932fps | 627.662fps | +| PAMTRI bs16 | [mAP:68.64%](https://github.com/NVlabs/PAMTRI) | mAP:68.64% | 810.976fps | 833.668fps | +# 自检报告 + +``` +# pth是否能正确转换为om +bash test/pth2om.sh +# 验收结果: OK + +# 精度数据是否达标 +# npu性能数据 +bash test/eval_acc_perf.sh +# 验收结果: 是 + +# 在t4环境测试性能数据 +bash test/perf_t4.sh +# 验收结果: OK + +# 310性能是否符合标准: 是 +bs1:310=2.9倍t4 +bs16:310=1.03倍t4 + +``` diff --git a/ACL_PyTorch/contrib/cv/classfication/PAMTRI/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/classfication/PAMTRI/modelzoo_level.txt index 38700fca05..2e42553460 100644 --- a/ACL_PyTorch/contrib/cv/classfication/PAMTRI/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/classfication/PAMTRI/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/LICENSE b/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/LICENSE index b1fac45f02..989e2c59e9 100644 --- a/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/LICENSE @@ -1,201 +1,201 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/PointNetCNN_preprocess.py b/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/PointNetCNN_preprocess.py index 9a11d950d8..2dd816aacc 100644 --- a/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/PointNetCNN_preprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/PointNetCNN_preprocess.py @@ -1,56 +1,56 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import numpy as np -import os -import sys -import provider -BASE_DIR = os.path.dirname(os.path.abspath(__file__)) -sys.path.append(BASE_DIR) -sys.path.append(os.path.join(BASE_DIR, 'models')) -sys.path.append(os.path.join(BASE_DIR, 'utils')) - -TEST_FILES = provider.getDataFiles(os.path.join(BASE_DIR, 'data/modelnet40_ply_hdf5_2048/test_files.txt')) -BATCH_SIZE = 1 - -def preprocess(save_path,label_save_path): - i = 0 - test_file_idxs = np.arange(0, len(TEST_FILES)) - for fn in range(len(TEST_FILES)): - current_data, current_label = provider.loadDataFile(TEST_FILES[test_file_idxs[fn]]) - current_data = current_data[:, 0:1024, :] - file_size = current_data.shape[0] - num_batches = file_size // BATCH_SIZE - for batch_idx in range(num_batches): - i += 1 - start_idx = batch_idx * BATCH_SIZE - end_idx = (batch_idx + 1) * BATCH_SIZE - label = current_label[start_idx:end_idx] - rotated_data = provider.rotate_point_cloud(current_data[start_idx:end_idx, :, :]) - jittered_data = provider.jitter_point_cloud(rotated_data) # P_Sampled - P_sampled = np.array(torch.from_numpy(jittered_data).float(), dtype=np.float32) - - P_sampled.tofile(os.path.join(save_path, "data" +str(i) + ".bin")) - np.save(os.path.join(label_save_path,'label'+str(i)),label) - -if __name__ == "__main__": - save_path = sys.argv[1] - label_save_path = sys.argv[2] - save_path = os.path.realpath(save_path) - if not os.path.isdir(save_path): - os.makedirs(os.path.realpath(save_path)) - if not os.path.isdir(label_save_path): - os.makedirs(os.path.realpath(label_save_path)) - preprocess( save_path,label_save_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import numpy as np +import os +import sys +import provider +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +sys.path.append(BASE_DIR) +sys.path.append(os.path.join(BASE_DIR, 'models')) +sys.path.append(os.path.join(BASE_DIR, 'utils')) + +TEST_FILES = provider.getDataFiles(os.path.join(BASE_DIR, 'data/modelnet40_ply_hdf5_2048/test_files.txt')) +BATCH_SIZE = 1 + +def preprocess(save_path,label_save_path): + i = 0 + test_file_idxs = np.arange(0, len(TEST_FILES)) + for fn in range(len(TEST_FILES)): + current_data, current_label = provider.loadDataFile(TEST_FILES[test_file_idxs[fn]]) + current_data = current_data[:, 0:1024, :] + file_size = current_data.shape[0] + num_batches = file_size // BATCH_SIZE + for batch_idx in range(num_batches): + i += 1 + start_idx = batch_idx * BATCH_SIZE + end_idx = (batch_idx + 1) * BATCH_SIZE + label = current_label[start_idx:end_idx] + rotated_data = provider.rotate_point_cloud(current_data[start_idx:end_idx, :, :]) + jittered_data = provider.jitter_point_cloud(rotated_data) # P_Sampled + P_sampled = np.array(torch.from_numpy(jittered_data).float(), dtype=np.float32) + + P_sampled.tofile(os.path.join(save_path, "data" +str(i) + ".bin")) + np.save(os.path.join(label_save_path,'label'+str(i)),label) + +if __name__ == "__main__": + save_path = sys.argv[1] + label_save_path = sys.argv[2] + save_path = os.path.realpath(save_path) + if not os.path.isdir(save_path): + os.makedirs(os.path.realpath(save_path)) + if not os.path.isdir(label_save_path): + os.makedirs(os.path.realpath(label_save_path)) + preprocess( save_path,label_save_path) diff --git a/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/README.md b/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/README.md index 1d2cd0c57b..bed77d35e3 100644 --- a/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/README.md @@ -1,64 +1,64 @@ -# PointNetCNN模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -``` -pip3.7 install -r requirements.txt -``` - -2.获取,修改与安装开源模型代码 -``` -git clone https://github.com/hxdengBerkeley/PointCNN.Pytorch -b master -cd PointCNN.Pytorch -git reset 6ec6c291cf97923a84fb6ed8c82e98bf01e7e96d --hard -patch -p1 < ../PointNetCNN.patch -cd .. -git clone https://gitee.com/Ronnie_zheng/MagicONNX.git -cd MagicONNX -pip install . -cd .. -cp -r PointCNN.Pytorch/utils PointCNN.Pytorch/provider.py ./ -``` -3.获取权重文件 - -将权重文件pointcnn_epoch240.pth放到当前工作目录 -``` -wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/classfication/PointNetCNN/pointcnn_epoch240.pth -``` - -4.数据集 -获取modelnet40_ply_hdf5_2048数据集,解压并放在./data目录下, -``` -mkdir data -cd data -wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/classfication/PointNetCNN/modelnet40_ply_hdf5_2048.zip -unzip -d modelnet40_ply_hdf5_2048 modelnet40_ply_hdf5_2048.zip -cd .. -``` - -5.[获取msame工具](https://gitee.com/ascend/tools/tree/master/msame#https://gitee.com/ascend/tools.git) -将msame工具放到当前工作目录 - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 -1-6行是 转onnx -7-14行是 onnx转om -``` -bash test/pth2om.sh -``` -1-10行是 基本配置 -11-16行是 预处理 -17-22行是 使用msase工具推理 -23-30行是 使用benchmark工具推理 -38-43行是 精度统计 -44-50行是 性能统计 -``` -bash test/eval_acc_perf.sh --datasets_path=/root/datasets -``` - **评测结果:** -| 模型 | pth精度 | 310离线推理精度 | 基准性能 | 310性能 | -| :-------------: | :-----: | :-------------: | :------: | :-------: | -| PointNetCNN bs1 | 82.61% | 82.61% | 31fps | 27.3fps | - +# PointNetCNN模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +``` +pip3.7 install -r requirements.txt +``` + +2.获取,修改与安装开源模型代码 +``` +git clone https://github.com/hxdengBerkeley/PointCNN.Pytorch -b master +cd PointCNN.Pytorch +git reset 6ec6c291cf97923a84fb6ed8c82e98bf01e7e96d --hard +patch -p1 < ../PointNetCNN.patch +cd .. +git clone https://gitee.com/Ronnie_zheng/MagicONNX.git +cd MagicONNX +pip install . +cd .. +cp -r PointCNN.Pytorch/utils PointCNN.Pytorch/provider.py ./ +``` +3.获取权重文件 + +将权重文件pointcnn_epoch240.pth放到当前工作目录 +``` +wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/classfication/PointNetCNN/pointcnn_epoch240.pth +``` + +4.数据集 +获取modelnet40_ply_hdf5_2048数据集,解压并放在./data目录下, +``` +mkdir data +cd data +wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/classfication/PointNetCNN/modelnet40_ply_hdf5_2048.zip +unzip -d modelnet40_ply_hdf5_2048 modelnet40_ply_hdf5_2048.zip +cd .. +``` + +5.[获取msame工具](https://gitee.com/ascend/tools/tree/master/msame#https://gitee.com/ascend/tools.git) +将msame工具放到当前工作目录 + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 +1-6行是 转onnx +7-14行是 onnx转om +``` +bash test/pth2om.sh +``` +1-10行是 基本配置 +11-16行是 预处理 +17-22行是 使用msase工具推理 +23-30行是 使用benchmark工具推理 +38-43行是 精度统计 +44-50行是 性能统计 +``` +bash test/eval_acc_perf.sh --datasets_path=/root/datasets +``` + **评测结果:** +| 模型 | pth精度 | 310离线推理精度 | 基准性能 | 310性能 | +| :-------------: | :-----: | :-------------: | :------: | :-------: | +| PointNetCNN bs1 | 82.61% | 82.61% | 31fps | 27.3fps | + diff --git a/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/modelzoo_level.txt index 38700fca05..2e42553460 100644 --- a/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/requirements.txt b/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/requirements.txt index 45587c8b52..76f08412ee 100644 --- a/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/requirements.txt +++ b/ACL_PyTorch/contrib/cv/classfication/PointNetCNN/requirements.txt @@ -1,8 +1,8 @@ -torch == 1.8.0 -onnx == 1.10.2 -onnxruntime == 1.9.0 -onnx-simplifier == 0.3.6 -numpy == 1.20.3 -h5py == 3.1.0 -scipy == 1.2.0 -sklearn == 0.0 +torch == 1.8.0 +onnx == 1.10.2 +onnxruntime == 1.9.0 +onnx-simplifier == 0.3.6 +numpy == 1.20.3 +h5py == 3.1.0 +scipy == 1.2.0 +sklearn == 0.0 diff --git a/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/README.md b/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/README.md index 26f76975ae..9bd6b8f83d 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/README.md @@ -1,69 +1,69 @@ -# PointNet++ Onnx模型端到端推理指导 - -## 1. 环境准备 -1.1.安装必要的依赖 - -```shell -pip3.7 install -r requirements.txt -``` - -1.2.获取,修改与安装开源模型代码 - -```shell -git clone https://github.com/yanx27/Pointnet_Pointnet2_pytorch models -cd models -git checkout e365b9f7b9c3d7d6444278d92e298e3f078794e1 -patch -p1 < ../models.patch -cd .. -``` - -1.3. 获取权重文件 - -pth采用开源仓自带的权重,权重位置: -```shell -./models/log/classification/pointnet2_ssg_wo_normals/checkpoints/best_model.pth -``` - -1.4. 数据集 - -[测试集](https://shapenet.cs.stanford.edu) - -1.5. 获取离线推理工具 - -[benchmark](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) -[msame](https://gitee.com/ascend/tools/tree/master/msame) - -## 2. 离线推理 - -2.1 模型转换&&精度测试 -在310上执行,执行时采用npu-smi info查看设备状态,确保device空闲 - -```shell -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets -``` - -2.2 性能测试 - -gpu测速,在对应gpu设备上执行,执行时采用nvidia-smi查看设备状态,确保device空闲 - -```shell -bash test/perf_g.sh -``` -npu测速,在对应npu设备上执行,执行时采用npu-smi info查看设备状态,确保device空闲 - -```shell -./benchmark.x86_64 -round=100 -om_path=Pointnetplus_part1_bs1.om -device_id=0 -batch_size=1 -./benchmark.x86_64 -round=100 -om_path=Pointnetplus_part2_bs1.om -device_id=0 -batch_size=1 -./benchmark.x86_64 -round=100 -om_path=Pointnetplus_part1_bs16.om -device_id=0 -batch_size=16 -./benchmark.x86_64 -round=100 -om_path=Pointnetplus_part2_bs16.om -device_id=0 -batch_size=16 -``` - -**评测结果:** - -| 模型 | batch_size | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | -|------------------|------------|---------------------------------------------|-----------------------------------------|----------|---------| -| PointNet++_part1 | 1 | - | - | 2997fps | 5308fps | -| PointNet++_part2 | 1 | Instance Acc: 0.928964, Class Acc: 0.890532 | Instance Acc: 0.9263, Class Acc: 0.8877 | 2571fps | 4105fps | -| PointNet++_part1 | 16 | - | - | 3468fps | 5968fps | -| PointNet++_part2 | 16 | - | Instance Acc: 0.9245, Class Acc: 0.8854 | 3670fps | 3730fps | +# PointNet++ Onnx模型端到端推理指导 + +## 1. 环境准备 +1.1.安装必要的依赖 + +```shell +pip3.7 install -r requirements.txt +``` + +1.2.获取,修改与安装开源模型代码 + +```shell +git clone https://github.com/yanx27/Pointnet_Pointnet2_pytorch models +cd models +git checkout e365b9f7b9c3d7d6444278d92e298e3f078794e1 +patch -p1 < ../models.patch +cd .. +``` + +1.3. 获取权重文件 + +pth采用开源仓自带的权重,权重位置: +```shell +./models/log/classification/pointnet2_ssg_wo_normals/checkpoints/best_model.pth +``` + +1.4. 数据集 + +[测试集](https://shapenet.cs.stanford.edu) + +1.5. 获取离线推理工具 + +[benchmark](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) +[msame](https://gitee.com/ascend/tools/tree/master/msame) + +## 2. 离线推理 + +2.1 模型转换&&精度测试 +在310上执行,执行时采用npu-smi info查看设备状态,确保device空闲 + +```shell +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets +``` + +2.2 性能测试 + +gpu测速,在对应gpu设备上执行,执行时采用nvidia-smi查看设备状态,确保device空闲 + +```shell +bash test/perf_g.sh +``` +npu测速,在对应npu设备上执行,执行时采用npu-smi info查看设备状态,确保device空闲 + +```shell +./benchmark.x86_64 -round=100 -om_path=Pointnetplus_part1_bs1.om -device_id=0 -batch_size=1 +./benchmark.x86_64 -round=100 -om_path=Pointnetplus_part2_bs1.om -device_id=0 -batch_size=1 +./benchmark.x86_64 -round=100 -om_path=Pointnetplus_part1_bs16.om -device_id=0 -batch_size=16 +./benchmark.x86_64 -round=100 -om_path=Pointnetplus_part2_bs16.om -device_id=0 -batch_size=16 +``` + +**评测结果:** + +| 模型 | batch_size | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | +|------------------|------------|---------------------------------------------|-----------------------------------------|----------|---------| +| PointNet++_part1 | 1 | - | - | 2997fps | 5308fps | +| PointNet++_part2 | 1 | Instance Acc: 0.928964, Class Acc: 0.890532 | Instance Acc: 0.9263, Class Acc: 0.8877 | 2571fps | 4105fps | +| PointNet++_part1 | 16 | - | - | 3468fps | 5968fps | +| PointNet++_part2 | 16 | - | Instance Acc: 0.9245, Class Acc: 0.8854 | 3670fps | 3730fps | diff --git a/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/pointnetplus_postprocess.py b/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/pointnetplus_postprocess.py index 4c9ab76a6d..acfce5a38c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/pointnetplus_postprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/pointnetplus_postprocess.py @@ -1,115 +1,115 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import numpy as np -import os -import torch -import logging -import sys -from tqdm import tqdm - - -def parse_args(): - '''PARAMETERS''' - parser = argparse.ArgumentParser('off_line_pred') - parser.add_argument('--target_path', type=str, default='out/bs1/', - required=False, help='target root') - parser.add_argument('--data_loc', type=str, default='/home/data/modelnet40_normal_resampled/', required=False, help='data location') - parser.add_argument('--batch_size', type=int, default=1, required=False, - help='batch size') - args = parser.parse_args() - out_folder = os.listdir(args.target_path)[-1] - args.target_path = os.path.join(args.target_path, out_folder) - return args - -def pc_normalize(pc): - centroid = np.mean(pc, axis=0) - pc = pc - centroid - m = np.max(np.sqrt(np.sum(pc**2, axis=1))) - pc = pc / m - return pc - -def model_data_loader(data_pth): - data_path = data_pth - catfile = os.path.join(data_path, 'modelnet40_shape_names.txt') - cat = [line.rstrip() for line in open(catfile)] - classes = dict(zip(cat, range(len(cat)))) - shape_ids = {} - shape_ids['test'] = [line.rstrip() for line in open(os.path.join(data_path, 'modelnet40_test.txt'))] - split = 'test' - shape_names = ['_'.join(x.split('_')[0:-1]) for x in shape_ids[split]] - datapath = [(shape_names[i], os.path.join(data_path, shape_names[i], shape_ids[split][i]) + '.txt') for i - in range(len(shape_ids[split]))] - print('The size of %s data is %d' % (split, len(datapath))) - return classes, datapath - -def test(pred_path,data_path): - mean_correct = [] - class_acc = np.zeros((40, 3)) - - classes,data_pth = model_data_loader(data_path) - print('data is %d' % len(data_pth)) - # load infer results - def load_infer_results(): - num_out = len(data_pth) // args.batch_size - for j in range(num_out): - pred_loca = os.path.join(pred_path, 'part2_' + str(j) + '_output_0.bin') - pred = np.fromfile(pred_loca,np.float32) - if args.batch_size == 1: - pred.shape = 1, 40 - pred = torch.from_numpy(pred) - yield pred - else: - pred.shape = args.batch_size, 40 - for d in pred: - d = torch.from_numpy(np.expand_dims(d, axis=0)) - yield d - infer_results = load_infer_results() - - # load gt results - num_results = len(data_pth) // args.batch_size * args.batch_size - for j in tqdm(range(num_results)): - fn = data_pth[j] - cls = classes[data_pth[j][0]] - target = np.array([cls]).astype(np.int32) - point_set = np.loadtxt(fn[1], delimiter=',').astype(np.float32) - point_set = point_set[0:1024, :] - point_set[:, 0:3] = pc_normalize(point_set[:, 0:3]) - point_set = point_set[:, 0:3] - point_set = point_set[None,] - new_point_set = torch.from_numpy(point_set) - points = new_point_set.transpose(2, 1) - target = torch.from_numpy(target) - - pred = next(infer_results) - pred_choice = pred.data.max(1)[1] - '''验证精度''' - for cat in np.unique(target.cpu()): - classacc = pred_choice[target == cat].eq(target[target == cat].long().data).cpu().sum() - class_acc[cat, 0] += classacc.item() / float(points[target == cat].size()[0]) - class_acc[cat, 1] += 1 - correct = pred_choice.eq(target.long().data).cpu().sum() - mean_correct.append(correct.item() / float(points.size()[0])) - - class_acc[:, 2] = class_acc[:, 0] / class_acc[:, 1] - class_acc = np.mean(class_acc[:, 2]) - instance_acc = np.mean(mean_correct) - print('class_acc is %f' % class_acc) - print('instance_acc is %f' % instance_acc) - return instance_acc, class_acc - -if __name__ == '__main__': - args = parse_args() - test(args.target_path, args.data_loc) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import numpy as np +import os +import torch +import logging +import sys +from tqdm import tqdm + + +def parse_args(): + '''PARAMETERS''' + parser = argparse.ArgumentParser('off_line_pred') + parser.add_argument('--target_path', type=str, default='out/bs1/', + required=False, help='target root') + parser.add_argument('--data_loc', type=str, default='/home/data/modelnet40_normal_resampled/', required=False, help='data location') + parser.add_argument('--batch_size', type=int, default=1, required=False, + help='batch size') + args = parser.parse_args() + out_folder = os.listdir(args.target_path)[-1] + args.target_path = os.path.join(args.target_path, out_folder) + return args + +def pc_normalize(pc): + centroid = np.mean(pc, axis=0) + pc = pc - centroid + m = np.max(np.sqrt(np.sum(pc**2, axis=1))) + pc = pc / m + return pc + +def model_data_loader(data_pth): + data_path = data_pth + catfile = os.path.join(data_path, 'modelnet40_shape_names.txt') + cat = [line.rstrip() for line in open(catfile)] + classes = dict(zip(cat, range(len(cat)))) + shape_ids = {} + shape_ids['test'] = [line.rstrip() for line in open(os.path.join(data_path, 'modelnet40_test.txt'))] + split = 'test' + shape_names = ['_'.join(x.split('_')[0:-1]) for x in shape_ids[split]] + datapath = [(shape_names[i], os.path.join(data_path, shape_names[i], shape_ids[split][i]) + '.txt') for i + in range(len(shape_ids[split]))] + print('The size of %s data is %d' % (split, len(datapath))) + return classes, datapath + +def test(pred_path,data_path): + mean_correct = [] + class_acc = np.zeros((40, 3)) + + classes,data_pth = model_data_loader(data_path) + print('data is %d' % len(data_pth)) + # load infer results + def load_infer_results(): + num_out = len(data_pth) // args.batch_size + for j in range(num_out): + pred_loca = os.path.join(pred_path, 'part2_' + str(j) + '_output_0.bin') + pred = np.fromfile(pred_loca,np.float32) + if args.batch_size == 1: + pred.shape = 1, 40 + pred = torch.from_numpy(pred) + yield pred + else: + pred.shape = args.batch_size, 40 + for d in pred: + d = torch.from_numpy(np.expand_dims(d, axis=0)) + yield d + infer_results = load_infer_results() + + # load gt results + num_results = len(data_pth) // args.batch_size * args.batch_size + for j in tqdm(range(num_results)): + fn = data_pth[j] + cls = classes[data_pth[j][0]] + target = np.array([cls]).astype(np.int32) + point_set = np.loadtxt(fn[1], delimiter=',').astype(np.float32) + point_set = point_set[0:1024, :] + point_set[:, 0:3] = pc_normalize(point_set[:, 0:3]) + point_set = point_set[:, 0:3] + point_set = point_set[None,] + new_point_set = torch.from_numpy(point_set) + points = new_point_set.transpose(2, 1) + target = torch.from_numpy(target) + + pred = next(infer_results) + pred_choice = pred.data.max(1)[1] + '''验证精度''' + for cat in np.unique(target.cpu()): + classacc = pred_choice[target == cat].eq(target[target == cat].long().data).cpu().sum() + class_acc[cat, 0] += classacc.item() / float(points[target == cat].size()[0]) + class_acc[cat, 1] += 1 + correct = pred_choice.eq(target.long().data).cpu().sum() + mean_correct.append(correct.item() / float(points.size()[0])) + + class_acc[:, 2] = class_acc[:, 0] / class_acc[:, 1] + class_acc = np.mean(class_acc[:, 2]) + instance_acc = np.mean(mean_correct) + print('class_acc is %f' % class_acc) + print('instance_acc is %f' % instance_acc) + return instance_acc, class_acc + +if __name__ == '__main__': + args = parse_args() + test(args.target_path, args.data_loc) diff --git a/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/pointnetplus_preprocess.py b/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/pointnetplus_preprocess.py index 5c9fe9aa98..2167b19ba0 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/pointnetplus_preprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/pointnetplus_preprocess.py @@ -1,157 +1,157 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import numpy as np -import torch -import argparse -import sys -sys.path.append('./models') -from tqdm import tqdm -from models.pointnet2_utils import sample_and_group, farthest_point_sample -import glob - -def parse_args(): - '''PARAMETERS''' - parser = argparse.ArgumentParser('data_process') - parser.add_argument('--preprocess_part', type=int, default=1, required=False, help='preprocess target') - parser.add_argument('--save_path', type=str, default='./modelnet40_processed/test_preprocess/pointset_chg', required=False, help='target root') - parser.add_argument('--save_path2', type=str, default='./modelnet40_processed/test_preprocess/xyz_chg', required=False, help='target root') - parser.add_argument('--data_loc', type=str, default='', required=False, help='data location') - parser.add_argument('--data_loc2', type=str, default='./modelnet40_processed/test_preprocess/xyz_chg', required=False, help='data location') - parser.add_argument('--batch_size', type=int, default=1, required=False, help='batch size for preprocess') - return parser.parse_args() - - -def pc_normalize(pc): - centroid = np.mean(pc, axis=0) - pc = pc - centroid - m = np.max(np.sqrt(np.sum(pc**2, axis=1))) - pc = pc / m - return pc - - -def preprocess(save_path,save_path2,data_location): - data_path = data_location - save_path = save_path - save_path2 = save_path2 - catfile = os.path.join(data_path, 'modelnet40_shape_names.txt') - cat = [line.rstrip() for line in open(catfile)] - classes = dict(zip(cat, range(len(cat)))) - shape_ids = {} - shape_ids['test'] = [line.rstrip() for line in open(os.path.join(data_path, 'modelnet40_test.txt'))] - split = 'test' - shape_names = ['_'.join(x.split('_')[0:-1]) for x in shape_ids[split]] - datapath = [(shape_names[i], os.path.join(data_path, shape_names[i], shape_ids[split][i]) + '.txt') for i - in range(len(shape_ids[split]))] - print('The size of %s data is %d' % (split, len(datapath))) - os.makedirs(save_path, exist_ok=True) - os.makedirs(save_path2, exist_ok=True) - - point_set_list = [] - new_xyz_list = [] - for index in tqdm(range(len(datapath))): - fn = datapath[index] - cls = classes[datapath[index][0]] - label = np.array([cls]).astype(np.int32) - point_set = np.loadtxt(fn[1], delimiter=',').astype(np.float32) - point_set = point_set[0:1024, :] - point_set[:, 0:3] = pc_normalize(point_set[:, 0:3]) - point_set = point_set[:, 0:3] - point_set = point_set[None,] - # print(point_set.shape) - new_point_set = torch.from_numpy(point_set) - new_point_set = new_point_set.transpose(2, 1) - npoint = 512 - radius = 0.2 - nsample = 32 - points = None - new_point_set = new_point_set.permute(0, 2, 1) - centroid = farthest_point_sample(new_point_set, npoint) - new_xyz, new_points = sample_and_group(npoint, radius, nsample, new_point_set, points, centroid) - - new_xyz = new_xyz.permute(0,2,1) - new_points = new_points.permute(0,3,2,1) - point_set, new_xyz = new_points.numpy(),new_xyz.numpy() - - point_name = 'point_set'+str(index) - if args.batch_size == 1: - point_set.tofile(os.path.join(save_path, point_name.split('.')[0] + ".bin")) - new_xyz.tofile(os.path.join(save_path2, point_name.split('.')[0] + ".bin")) - else: - point_set_list.append(point_set) - new_xyz_list.append(new_xyz) - if len(point_set_list) == args.batch_size: - point_sets = np.array(point_set_list) - new_xyzes = np.array(new_xyz_list) - point_names = 'point_set{}.bin'.format(str(index // 16)) - point_sets.tofile(os.path.join(save_path, point_names)) - new_xyzes.tofile(os.path.join(save_path2, point_names)) - point_set_list.clear() - new_xyz_list.clear() - - -def preprocess2(save_path,save_path2,data_location,data_location2): - data_toal_folder = os.listdir(data_location)[-1] - data_total_path = os.path.join(data_location, data_toal_folder) - save_path = save_path - save_path2 = save_path2 - file_start = 'point_set' - file_end_one = '_output_1.bin' - file_end_zero = '_output_0.bin' - os.makedirs(save_path, exist_ok=True) - os.makedirs(save_path2, exist_ok=True) - test = os.path.join(data_total_path, file_start+str(0)+file_end_zero) - try: - file_end = file_end_zero - test2 = np.fromfile(test,dtype=np.float32) - test_set.shape = args.batch_size,128,512 - except: - file_end = file_end_one - print(file_end) - data_total_path2 = data_location2 - file_end_two = '.bin' - path_file_number=glob.glob(data_location2+'/*.bin') - - for index in tqdm(range(len(path_file_number))): - data_path2 = os.path.join(data_total_path2, file_start+str(index)+file_end_two) - data_path1 = os.path.join(data_total_path, file_start+str(index)+file_end) - point_set = np.fromfile(data_path1,dtype=np.float32) - point_set2 = np.fromfile(data_path2,dtype=np.float32) - point_set.shape = args.batch_size,128,512 - point_set2.shape = args.batch_size,3,512 - new_point_set = torch.from_numpy(point_set2) - point_set2 = torch.from_numpy(point_set) - npoint = 128 - radius = 0.4 - nsample = 64 - new_point_set = new_point_set.permute(0, 2, 1) - point_set2 = point_set2.permute(0,2,1) - centroid = farthest_point_sample(new_point_set, npoint) - new_xyz, new_points = sample_and_group(npoint, radius, nsample, new_point_set, point_set2, centroid) - new_point_set = new_point_set.permute(0, 2, 1) - new_points = new_points.permute(0,3,2,1) - new_xyz = new_xyz.permute(0,2,1) - point_set,new_xyz = new_points.numpy(),new_xyz.numpy() - point_name = 'part2_'+str(index) - point_set.tofile(os.path.join(save_path, point_name.split('.')[0] + ".bin")) - new_xyz.tofile(os.path.join(save_path2, point_name.split('.')[0] + ".bin")) - - -if __name__ == '__main__': - args = parse_args() - if(1 == args.preprocess_part): - preprocess(args.save_path,args.save_path2,args.data_loc) - else: - preprocess2(args.save_path,args.save_path2,args.data_loc,args.data_loc2) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import numpy as np +import torch +import argparse +import sys +sys.path.append('./models') +from tqdm import tqdm +from models.pointnet2_utils import sample_and_group, farthest_point_sample +import glob + +def parse_args(): + '''PARAMETERS''' + parser = argparse.ArgumentParser('data_process') + parser.add_argument('--preprocess_part', type=int, default=1, required=False, help='preprocess target') + parser.add_argument('--save_path', type=str, default='./modelnet40_processed/test_preprocess/pointset_chg', required=False, help='target root') + parser.add_argument('--save_path2', type=str, default='./modelnet40_processed/test_preprocess/xyz_chg', required=False, help='target root') + parser.add_argument('--data_loc', type=str, default='', required=False, help='data location') + parser.add_argument('--data_loc2', type=str, default='./modelnet40_processed/test_preprocess/xyz_chg', required=False, help='data location') + parser.add_argument('--batch_size', type=int, default=1, required=False, help='batch size for preprocess') + return parser.parse_args() + + +def pc_normalize(pc): + centroid = np.mean(pc, axis=0) + pc = pc - centroid + m = np.max(np.sqrt(np.sum(pc**2, axis=1))) + pc = pc / m + return pc + + +def preprocess(save_path,save_path2,data_location): + data_path = data_location + save_path = save_path + save_path2 = save_path2 + catfile = os.path.join(data_path, 'modelnet40_shape_names.txt') + cat = [line.rstrip() for line in open(catfile)] + classes = dict(zip(cat, range(len(cat)))) + shape_ids = {} + shape_ids['test'] = [line.rstrip() for line in open(os.path.join(data_path, 'modelnet40_test.txt'))] + split = 'test' + shape_names = ['_'.join(x.split('_')[0:-1]) for x in shape_ids[split]] + datapath = [(shape_names[i], os.path.join(data_path, shape_names[i], shape_ids[split][i]) + '.txt') for i + in range(len(shape_ids[split]))] + print('The size of %s data is %d' % (split, len(datapath))) + os.makedirs(save_path, exist_ok=True) + os.makedirs(save_path2, exist_ok=True) + + point_set_list = [] + new_xyz_list = [] + for index in tqdm(range(len(datapath))): + fn = datapath[index] + cls = classes[datapath[index][0]] + label = np.array([cls]).astype(np.int32) + point_set = np.loadtxt(fn[1], delimiter=',').astype(np.float32) + point_set = point_set[0:1024, :] + point_set[:, 0:3] = pc_normalize(point_set[:, 0:3]) + point_set = point_set[:, 0:3] + point_set = point_set[None,] + # print(point_set.shape) + new_point_set = torch.from_numpy(point_set) + new_point_set = new_point_set.transpose(2, 1) + npoint = 512 + radius = 0.2 + nsample = 32 + points = None + new_point_set = new_point_set.permute(0, 2, 1) + centroid = farthest_point_sample(new_point_set, npoint) + new_xyz, new_points = sample_and_group(npoint, radius, nsample, new_point_set, points, centroid) + + new_xyz = new_xyz.permute(0,2,1) + new_points = new_points.permute(0,3,2,1) + point_set, new_xyz = new_points.numpy(),new_xyz.numpy() + + point_name = 'point_set'+str(index) + if args.batch_size == 1: + point_set.tofile(os.path.join(save_path, point_name.split('.')[0] + ".bin")) + new_xyz.tofile(os.path.join(save_path2, point_name.split('.')[0] + ".bin")) + else: + point_set_list.append(point_set) + new_xyz_list.append(new_xyz) + if len(point_set_list) == args.batch_size: + point_sets = np.array(point_set_list) + new_xyzes = np.array(new_xyz_list) + point_names = 'point_set{}.bin'.format(str(index // 16)) + point_sets.tofile(os.path.join(save_path, point_names)) + new_xyzes.tofile(os.path.join(save_path2, point_names)) + point_set_list.clear() + new_xyz_list.clear() + + +def preprocess2(save_path,save_path2,data_location,data_location2): + data_toal_folder = os.listdir(data_location)[-1] + data_total_path = os.path.join(data_location, data_toal_folder) + save_path = save_path + save_path2 = save_path2 + file_start = 'point_set' + file_end_one = '_output_1.bin' + file_end_zero = '_output_0.bin' + os.makedirs(save_path, exist_ok=True) + os.makedirs(save_path2, exist_ok=True) + test = os.path.join(data_total_path, file_start+str(0)+file_end_zero) + try: + file_end = file_end_zero + test2 = np.fromfile(test,dtype=np.float32) + test_set.shape = args.batch_size,128,512 + except: + file_end = file_end_one + print(file_end) + data_total_path2 = data_location2 + file_end_two = '.bin' + path_file_number=glob.glob(data_location2+'/*.bin') + + for index in tqdm(range(len(path_file_number))): + data_path2 = os.path.join(data_total_path2, file_start+str(index)+file_end_two) + data_path1 = os.path.join(data_total_path, file_start+str(index)+file_end) + point_set = np.fromfile(data_path1,dtype=np.float32) + point_set2 = np.fromfile(data_path2,dtype=np.float32) + point_set.shape = args.batch_size,128,512 + point_set2.shape = args.batch_size,3,512 + new_point_set = torch.from_numpy(point_set2) + point_set2 = torch.from_numpy(point_set) + npoint = 128 + radius = 0.4 + nsample = 64 + new_point_set = new_point_set.permute(0, 2, 1) + point_set2 = point_set2.permute(0,2,1) + centroid = farthest_point_sample(new_point_set, npoint) + new_xyz, new_points = sample_and_group(npoint, radius, nsample, new_point_set, point_set2, centroid) + new_point_set = new_point_set.permute(0, 2, 1) + new_points = new_points.permute(0,3,2,1) + new_xyz = new_xyz.permute(0,2,1) + point_set,new_xyz = new_points.numpy(),new_xyz.numpy() + point_name = 'part2_'+str(index) + point_set.tofile(os.path.join(save_path, point_name.split('.')[0] + ".bin")) + new_xyz.tofile(os.path.join(save_path2, point_name.split('.')[0] + ".bin")) + + +if __name__ == '__main__': + args = parse_args() + if(1 == args.preprocess_part): + preprocess(args.save_path,args.save_path2,args.data_loc) + else: + preprocess2(args.save_path,args.save_path2,args.data_loc,args.data_loc2) diff --git a/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/pointnetplus_pth2onnx.py b/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/pointnetplus_pth2onnx.py index bb92b279f8..4728535261 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/pointnetplus_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/pointnetplus_pth2onnx.py @@ -1,104 +1,104 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 collections import OrderedDict -import torch -import torch.onnx -import argparse -import sys -sys.path.append('./models/models') -import pointnet2_cls_ssg as pointnet2_cls -from pointnet2_utils import farthest_point_sample -from pointnet2_utils import sample_and_group - - -def parse_args(): - '''PARAMETERS''' - parser = argparse.ArgumentParser('off_line_pred') - parser.add_argument('--target_model', type=int, default=1, - required=True, help='target trans_models') - parser.add_argument('--pth_dir', type=str, default='', - required=False, help='target trans_models') - parser.add_argument('--batch_size', type=int, default=1, - required=False, help='batch size') - return parser.parse_args() - - -def proc_node_module(checkpoint, AttrName): - new_state_dict = OrderedDict() - for k, v in checkpoint[AttrName].items(): - if k[0:7] == "module.": - name = k[7:] - else: - name = k[0:] - new_state_dict[name] = v - return new_state_dict - - -def model_convert(dir): - experiment_dir = dir - dummy_input = torch.randn(args.batch_size, 3, 1024) - checkpoint = torch.load(str(experiment_dir) + '/best_model.pth',map_location = 'cpu') - checkpoint['model_state_dict'] = proc_node_module(checkpoint,'model_state_dict') - model = pointnet2_cls.get_model_part1(normal_channel=False) - model.load_state_dict(checkpoint['model_state_dict']) - model.eval() - npoint = 512 - radius = 0.2 - nsample = 32 - points = None - test_input = dummy_input.permute(0, 2, 1) - centroid = farthest_point_sample(test_input, npoint) - new_xyz, new_points = sample_and_group(npoint, radius, nsample, test_input, points, centroid) - new_points = new_points.permute(0, 3, 2, 1) - input_names = ["xyz", "samp_points"] - output_names = ["l1_xyz", "l1_point"] - torch.onnx.export(model, (new_xyz, new_points), - "Pointnetplus_part1_bs{}.onnx".format(args.batch_size), - input_names=input_names, verbose=True, output_names=output_names, opset_version=11) - - -def model_convert2(dir): - experiment_dir = dir - dummy_xyz_input = torch.randn(args.batch_size, 3, 512) - dummy_point_input = torch.randn(args.batch_size, 128, 512) - checkpoint = torch.load(str(experiment_dir) + '/best_model.pth',map_location = 'cpu') - checkpoint['model_state_dict'] = proc_node_module(checkpoint,'model_state_dict') - model = pointnet2_cls.get_model_part2(normal_channel=False) - model.load_state_dict(checkpoint['model_state_dict']) - model.eval() - npoint = 128 - radius = 0.4 - nsample = 64 - points = None - test_input = dummy_xyz_input.permute(0, 2, 1) - test_points = dummy_point_input.permute(0, 2, 1) - centroid = farthest_point_sample(test_input, npoint) - new_xyz, new_points = sample_and_group(npoint, radius, nsample, test_input, test_points, centroid) - new_points = new_points.permute(0, 3, 2, 1) - new_xyz = new_xyz.permute(0, 2, 1) - input_names = ["l1_xyz", "l1_points"] - output_names = ["class", "l3_point"] - - torch.onnx.export(model, (new_xyz, new_points), - "Pointnetplus_part2_bs{}.onnx".format(args.batch_size), - input_names=input_names, verbose=True, output_names=output_names, opset_version=11) - - -if __name__ == '__main__': - args = parse_args() - if(args.target_model == 1): - model_convert(args.pth_dir) - else: - model_convert2(args.pth_dir) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 collections import OrderedDict +import torch +import torch.onnx +import argparse +import sys +sys.path.append('./models/models') +import pointnet2_cls_ssg as pointnet2_cls +from pointnet2_utils import farthest_point_sample +from pointnet2_utils import sample_and_group + + +def parse_args(): + '''PARAMETERS''' + parser = argparse.ArgumentParser('off_line_pred') + parser.add_argument('--target_model', type=int, default=1, + required=True, help='target trans_models') + parser.add_argument('--pth_dir', type=str, default='', + required=False, help='target trans_models') + parser.add_argument('--batch_size', type=int, default=1, + required=False, help='batch size') + return parser.parse_args() + + +def proc_node_module(checkpoint, AttrName): + new_state_dict = OrderedDict() + for k, v in checkpoint[AttrName].items(): + if k[0:7] == "module.": + name = k[7:] + else: + name = k[0:] + new_state_dict[name] = v + return new_state_dict + + +def model_convert(dir): + experiment_dir = dir + dummy_input = torch.randn(args.batch_size, 3, 1024) + checkpoint = torch.load(str(experiment_dir) + '/best_model.pth',map_location = 'cpu') + checkpoint['model_state_dict'] = proc_node_module(checkpoint,'model_state_dict') + model = pointnet2_cls.get_model_part1(normal_channel=False) + model.load_state_dict(checkpoint['model_state_dict']) + model.eval() + npoint = 512 + radius = 0.2 + nsample = 32 + points = None + test_input = dummy_input.permute(0, 2, 1) + centroid = farthest_point_sample(test_input, npoint) + new_xyz, new_points = sample_and_group(npoint, radius, nsample, test_input, points, centroid) + new_points = new_points.permute(0, 3, 2, 1) + input_names = ["xyz", "samp_points"] + output_names = ["l1_xyz", "l1_point"] + torch.onnx.export(model, (new_xyz, new_points), + "Pointnetplus_part1_bs{}.onnx".format(args.batch_size), + input_names=input_names, verbose=True, output_names=output_names, opset_version=11) + + +def model_convert2(dir): + experiment_dir = dir + dummy_xyz_input = torch.randn(args.batch_size, 3, 512) + dummy_point_input = torch.randn(args.batch_size, 128, 512) + checkpoint = torch.load(str(experiment_dir) + '/best_model.pth',map_location = 'cpu') + checkpoint['model_state_dict'] = proc_node_module(checkpoint,'model_state_dict') + model = pointnet2_cls.get_model_part2(normal_channel=False) + model.load_state_dict(checkpoint['model_state_dict']) + model.eval() + npoint = 128 + radius = 0.4 + nsample = 64 + points = None + test_input = dummy_xyz_input.permute(0, 2, 1) + test_points = dummy_point_input.permute(0, 2, 1) + centroid = farthest_point_sample(test_input, npoint) + new_xyz, new_points = sample_and_group(npoint, radius, nsample, test_input, test_points, centroid) + new_points = new_points.permute(0, 3, 2, 1) + new_xyz = new_xyz.permute(0, 2, 1) + input_names = ["l1_xyz", "l1_points"] + output_names = ["class", "l3_point"] + + torch.onnx.export(model, (new_xyz, new_points), + "Pointnetplus_part2_bs{}.onnx".format(args.batch_size), + input_names=input_names, verbose=True, output_names=output_names, opset_version=11) + + +if __name__ == '__main__': + args = parse_args() + if(args.target_model == 1): + model_convert(args.pth_dir) + else: + model_convert2(args.pth_dir) diff --git a/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/requirements.txt b/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/requirements.txt index e3e632f5e9..ad7ae69def 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/requirements.txt +++ b/ACL_PyTorch/contrib/cv/classfication/Pointnetplus/Pointnetplus/requirements.txt @@ -1,5 +1,5 @@ -torch == 1.9.0 -onnx == 1.9.0 -tqdm == 4.62.2 -torchvision == 0.10.0 -numpy +torch == 1.9.0 +onnx == 1.9.0 +tqdm == 4.62.2 +torchvision == 0.10.0 +numpy diff --git a/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/ LICENSE b/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/ LICENSE index 797bf40e85..04adf5cbc6 100644 --- a/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/ LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/ LICENSE @@ -1,203 +1,203 @@ -Copyright 2018-2019 Open-MMLab. All rights reserved. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018-2019 Open-MMLab. - - 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. +Copyright 2018-2019 Open-MMLab. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2019 Open-MMLab. + + 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. diff --git a/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/ modelzoo_level.txt b/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/ modelzoo_level.txt index d44ba5698b..70801afc42 100644 --- a/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/ modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/ modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/ReadME.md b/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/ReadME.md index 1cdecd9b31..91cf9a0252 100644 --- a/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/ReadME.md +++ b/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/ReadME.md @@ -1,76 +1,76 @@ -# R(2+1)D模型PyTorch离线推理指导 - -## 1 环境准备 - -- **1.1 安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装** - -``` -pip3.7 install -r requirements.txt -``` - -- **1.2 获取,修改与安装开源模型代码** - -``` -git clone https://github.com/open-mmlab/mmcv -b master -cd mmcv -git reset --hard 6cb534b775b7502f0dcc59331236e619d3ae5b9f -MMCV_WITH_OPS=1 pip3.7 install -e . - -cd .. -git clone https://github.com/open-mmlab/mmaction2 -b master -cd mmaction2 -git reset --hard acce52d21a2545d9351b1060853c3bcd171b7158 -python3.7 setup.py develop - -``` -注:若上述命令不能下载源码,则将https替换为git(如:git clone git://github.com/open-mmlab/mmcv -b master ) - -将mmaction2/tools/deployment/目录下的pytorch2onnx.py中的torch.onnx.export添加一个参数: - -` dynamic_axes={'0':{0:'-1'}}, ` - -将r2plus1d_r34_8x8x1_180e_ucf101_rgb2.py文件放在mmaction2/configs/recognition/r2plus1d文件夹下 - -- **1.3 [获取权重文件](https://www.aliyundrive.com/drive/folder/6130e24c1b56461015b44659bdc650a9d3cd8e71)** - -- **1.4 [数据集UCF-101](https://www.crcv.ucf.edu/data/UCF101/UCF101.rar)** - -将UCF101.rar文件解压,重命名为ucf101,放在 /root/datasets/文件夹下 - -``` -在当前目录创建videos文件夹 -mkdir -p ./data/ucf101/videos - -将/root/datasets/ucf101文件夹下的视频文件夹复制到videos下 -cp -r /root/datasets/ucf101/* ./data/ucf101/videos - -python3.7 ./mmaction2/tools/data/build_rawframes.py ./data/ucf101/videos/ ./data/ucf101/rawframes/ --task rgb --level 2 --ext avi --use-opencv - -DATA_DIR_AN="./data/ucf101/annotations" - -wget https://www.crcv.ucf.edu/wp-content/uploads/2019/03/UCF101TrainTestSplits-RecognitionTask.zip --no-check-certificate - -unzip -j UCF101TrainTestSplits-RecognitionTask.zip -d ${DATA_DIR_AN}/ -rm UCF101TrainTestSplits-RecognitionTask.zip - -PYTHONPATH=. python3.7 ./mmaction2/tools/data/build_file_list.py ucf101 data/ucf101/rawframes/ --level 2 --format rawframes --shuffle -``` -- **1.5 获取[msame工具](https://gitee.com/ascend/tools/tree/master/msame)和[benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer)** - -将msame和benchmark.x86_64(或benchmark.aarch64)放到当前目录 - -## 2 离线推理 - -- **310上执行,执行时使npu-smi info查看设备状态,确保device空闲** - -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh arch=x86_64 -``` - -- **评测结果:** - -| 模型 | pth精度 | 310离线推理精度 | 基准性能 | 310性能 | -| ------------ | ----------------------- | ----------------------- | ---------- | ---------- | -| R(2+1)D-bs1 | [top1:0.8921 top5:0.9741](https://github.com/open-mmlab/mmaction2) | top1:0.8929 top5:0.9749 | 38.7704fps | 36.1684fps | -| R(2+1)D-bs16 | [top1:0.8921 top5:0.9742](https://github.com/open-mmlab/mmaction2) | top1:0.8929 top5:0.9749| 40.8914fps | 40.0332fps | +# R(2+1)D模型PyTorch离线推理指导 + +## 1 环境准备 + +- **1.1 安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装** + +``` +pip3.7 install -r requirements.txt +``` + +- **1.2 获取,修改与安装开源模型代码** + +``` +git clone https://github.com/open-mmlab/mmcv -b master +cd mmcv +git reset --hard 6cb534b775b7502f0dcc59331236e619d3ae5b9f +MMCV_WITH_OPS=1 pip3.7 install -e . + +cd .. +git clone https://github.com/open-mmlab/mmaction2 -b master +cd mmaction2 +git reset --hard acce52d21a2545d9351b1060853c3bcd171b7158 +python3.7 setup.py develop + +``` +注:若上述命令不能下载源码,则将https替换为git(如:git clone git://github.com/open-mmlab/mmcv -b master ) + +将mmaction2/tools/deployment/目录下的pytorch2onnx.py中的torch.onnx.export添加一个参数: + +` dynamic_axes={'0':{0:'-1'}}, ` + +将r2plus1d_r34_8x8x1_180e_ucf101_rgb2.py文件放在mmaction2/configs/recognition/r2plus1d文件夹下 + +- **1.3 [获取权重文件](https://www.aliyundrive.com/drive/folder/6130e24c1b56461015b44659bdc650a9d3cd8e71)** + +- **1.4 [数据集UCF-101](https://www.crcv.ucf.edu/data/UCF101/UCF101.rar)** + +将UCF101.rar文件解压,重命名为ucf101,放在 /root/datasets/文件夹下 + +``` +在当前目录创建videos文件夹 +mkdir -p ./data/ucf101/videos + +将/root/datasets/ucf101文件夹下的视频文件夹复制到videos下 +cp -r /root/datasets/ucf101/* ./data/ucf101/videos + +python3.7 ./mmaction2/tools/data/build_rawframes.py ./data/ucf101/videos/ ./data/ucf101/rawframes/ --task rgb --level 2 --ext avi --use-opencv + +DATA_DIR_AN="./data/ucf101/annotations" + +wget https://www.crcv.ucf.edu/wp-content/uploads/2019/03/UCF101TrainTestSplits-RecognitionTask.zip --no-check-certificate + +unzip -j UCF101TrainTestSplits-RecognitionTask.zip -d ${DATA_DIR_AN}/ +rm UCF101TrainTestSplits-RecognitionTask.zip + +PYTHONPATH=. python3.7 ./mmaction2/tools/data/build_file_list.py ucf101 data/ucf101/rawframes/ --level 2 --format rawframes --shuffle +``` +- **1.5 获取[msame工具](https://gitee.com/ascend/tools/tree/master/msame)和[benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer)** + +将msame和benchmark.x86_64(或benchmark.aarch64)放到当前目录 + +## 2 离线推理 + +- **310上执行,执行时使npu-smi info查看设备状态,确保device空闲** + +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh arch=x86_64 +``` + +- **评测结果:** + +| 模型 | pth精度 | 310离线推理精度 | 基准性能 | 310性能 | +| ------------ | ----------------------- | ----------------------- | ---------- | ---------- | +| R(2+1)D-bs1 | [top1:0.8921 top5:0.9741](https://github.com/open-mmlab/mmaction2) | top1:0.8929 top5:0.9749 | 38.7704fps | 36.1684fps | +| R(2+1)D-bs16 | [top1:0.8921 top5:0.9742](https://github.com/open-mmlab/mmaction2) | top1:0.8929 top5:0.9749| 40.8914fps | 40.0332fps | diff --git a/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/get_info.py b/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/get_info.py index 5af675c6b0..fc6cdebb5b 100644 --- a/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/get_info.py +++ b/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/get_info.py @@ -1,60 +1,60 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/r2plus1d_r34_8x8x1_180e_ucf101_rgb2.py b/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/r2plus1d_r34_8x8x1_180e_ucf101_rgb2.py index 6da9ed4e07..58e521efcc 100644 --- a/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/r2plus1d_r34_8x8x1_180e_ucf101_rgb2.py +++ b/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/r2plus1d_r34_8x8x1_180e_ucf101_rgb2.py @@ -1,96 +1,96 @@ -_base_ = [ - '../../_base_/models/r2plus1d_r34.py', - '../../_base_/default_runtime.py' -] - -# dataset settings -dataset_type = 'RawframeDataset' -data_root = 'data/ucf101/rawframes/' -data_root_val = 'data/ucf101/rawframes/' -split = 1 # official train/test splits. valid numbers: 1, 2, 3 -ann_file_val = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' -ann_file_train = f'data/ucf101/ucf101_train_split_{split}_rawframes.txt' -ann_file_test = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' -img_norm_cfg = dict( - mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_bgr=False) -train_pipeline = [ - dict(type='SampleFrames', clip_len=8, frame_interval=8, num_clips=1), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='RandomResizedCrop'), - dict(type='Resize', scale=(224, 224), keep_ratio=False), - dict(type='Flip', flip_ratio=0.5), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs', 'label']) -] -val_pipeline = [ - dict( - type='SampleFrames', - clip_len=8, - frame_interval=8, - num_clips=1, - test_mode=True), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='CenterCrop', crop_size=224), - dict(type='Flip', flip_ratio=0), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs']) -] -test_pipeline = [ - dict( - type='SampleFrames', - clip_len=8, - frame_interval=8, - num_clips=1, - test_mode=True), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='ThreeCrop', crop_size=256), - # dict(type='Flip', flip_ratio=0), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs']) -] -data = dict( - videos_per_gpu=16, - workers_per_gpu=4, - train=dict( - type=dataset_type, - ann_file=ann_file_train, - data_prefix=data_root, - pipeline=train_pipeline), - val=dict( - type=dataset_type, - ann_file=ann_file_val, - data_prefix=data_root_val, - pipeline=val_pipeline), - test=dict( - type=dataset_type, - ann_file=ann_file_val, - data_prefix=data_root_val, - pipeline=test_pipeline)) -# optimizer -optimizer = dict( - type='SGD', lr=0.0025, momentum=0.9, - weight_decay=0.0001) # this lr is used for 8 gpus -optimizer_config = dict(grad_clip=dict(max_norm=40, norm_type=2)) -# learning policy -# lr_config = dict(policy='step', steps=[1,2,3], lrs=[1e-3,1e-4,1e-5]) -lr_config = dict(policy='CosineAnnealing', min_lr=0) -total_epochs = 40 -# total_epochs = 90 - -# runtime settings -checkpoint_config = dict(interval=5) -evaluation = dict( - interval=5, metrics=['top_k_accuracy', 'mean_class_accuracy']) -work_dir = './work_dirs/r2plus1d_r34_8x8x1_180e_ucf101_rgb3/' -find_unused_parameters = False -load_from = 'https://download.openmmlab.com/mmaction/recognition/r2plus1d/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb_20200729-aa94765e.pth' -resume_from = None +_base_ = [ + '../../_base_/models/r2plus1d_r34.py', + '../../_base_/default_runtime.py' +] + +# dataset settings +dataset_type = 'RawframeDataset' +data_root = 'data/ucf101/rawframes/' +data_root_val = 'data/ucf101/rawframes/' +split = 1 # official train/test splits. valid numbers: 1, 2, 3 +ann_file_val = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' +ann_file_train = f'data/ucf101/ucf101_train_split_{split}_rawframes.txt' +ann_file_test = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' +img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_bgr=False) +train_pipeline = [ + dict(type='SampleFrames', clip_len=8, frame_interval=8, num_clips=1), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='RandomResizedCrop'), + dict(type='Resize', scale=(224, 224), keep_ratio=False), + dict(type='Flip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs', 'label']) +] +val_pipeline = [ + dict( + type='SampleFrames', + clip_len=8, + frame_interval=8, + num_clips=1, + test_mode=True), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='CenterCrop', crop_size=224), + dict(type='Flip', flip_ratio=0), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs']) +] +test_pipeline = [ + dict( + type='SampleFrames', + clip_len=8, + frame_interval=8, + num_clips=1, + test_mode=True), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='ThreeCrop', crop_size=256), + # dict(type='Flip', flip_ratio=0), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs']) +] +data = dict( + videos_per_gpu=16, + workers_per_gpu=4, + train=dict( + type=dataset_type, + ann_file=ann_file_train, + data_prefix=data_root, + pipeline=train_pipeline), + val=dict( + type=dataset_type, + ann_file=ann_file_val, + data_prefix=data_root_val, + pipeline=val_pipeline), + test=dict( + type=dataset_type, + ann_file=ann_file_val, + data_prefix=data_root_val, + pipeline=test_pipeline)) +# optimizer +optimizer = dict( + type='SGD', lr=0.0025, momentum=0.9, + weight_decay=0.0001) # this lr is used for 8 gpus +optimizer_config = dict(grad_clip=dict(max_norm=40, norm_type=2)) +# learning policy +# lr_config = dict(policy='step', steps=[1,2,3], lrs=[1e-3,1e-4,1e-5]) +lr_config = dict(policy='CosineAnnealing', min_lr=0) +total_epochs = 40 +# total_epochs = 90 + +# runtime settings +checkpoint_config = dict(interval=5) +evaluation = dict( + interval=5, metrics=['top_k_accuracy', 'mean_class_accuracy']) +work_dir = './work_dirs/r2plus1d_r34_8x8x1_180e_ucf101_rgb3/' +find_unused_parameters = False +load_from = 'https://download.openmmlab.com/mmaction/recognition/r2plus1d/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb_20200729-aa94765e.pth' +resume_from = None diff --git a/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/requirements.txt b/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/requirements.txt index 2b0bebd47b..6255de2633 100644 --- a/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/requirements.txt +++ b/ACL_PyTorch/contrib/cv/classfication/R(2+1)D/requirements.txt @@ -1,9 +1,9 @@ -torch == 1.5.0 -torchvision == 0.6.0 -onnx == 1.7.0 -onnx-simplifier == 0.3.6 -numpy == 1.21.1 -Pillow == 8.2.0 -opencv_python == 4.5.3.56 -scipy == 1.7.1 +torch == 1.5.0 +torchvision == 0.6.0 +onnx == 1.7.0 +onnx-simplifier == 0.3.6 +numpy == 1.21.1 +Pillow == 8.2.0 +opencv_python == 4.5.3.56 +scipy == 1.7.1 einops ==0.3.2 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/ReID_for_Pytorch/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/classfication/ReID_for_Pytorch/modelzoo_level.txt index 9e95396651..27e6c78b37 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ReID_for_Pytorch/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/classfication/ReID_for_Pytorch/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:POK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/RegNetX-1.6GF/LICENSE b/ACL_PyTorch/contrib/cv/classfication/RegNetX-1.6GF/LICENSE index 753842b672..f49a4e16e6 100644 --- a/ACL_PyTorch/contrib/cv/classfication/RegNetX-1.6GF/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/RegNetX-1.6GF/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/RegNetX-1.6GF/get_info.py b/ACL_PyTorch/contrib/cv/classfication/RegNetX-1.6GF/get_info.py index 16bebcfc75..70e007ac5c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/RegNetX-1.6GF/get_info.py +++ b/ACL_PyTorch/contrib/cv/classfication/RegNetX-1.6GF/get_info.py @@ -1,62 +1,62 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - print(index,'done') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - print(index,'done') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + print(index,'done') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + print(index,'done') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/RegNetX-1.6GF/vision_metric_ImageNet.py b/ACL_PyTorch/contrib/cv/classfication/RegNetX-1.6GF/vision_metric_ImageNet.py index 362f2484e8..583340a19f 100644 --- a/ACL_PyTorch/contrib/cv/classfication/RegNetX-1.6GF/vision_metric_ImageNet.py +++ b/ACL_PyTorch/contrib/cv/classfication/RegNetX-1.6GF/vision_metric_ImageNet.py @@ -1,184 +1,184 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - if data == '': - n_label = 0 - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = 0 - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - - resCnt = min(len(sort_index), topn) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) - print("Time used:", elapsed) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + if data == '': + n_label = 0 + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = 0 + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + + resCnt = min(len(sort_index), topn) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) + print("Time used:", elapsed) + diff --git a/ACL_PyTorch/contrib/cv/classfication/RegNetY-1.6GF/LICENSE b/ACL_PyTorch/contrib/cv/classfication/RegNetY-1.6GF/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/RegNetY-1.6GF/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/RegNetY-1.6GF/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/RegNetY-1.6GF/get_info.py b/ACL_PyTorch/contrib/cv/classfication/RegNetY-1.6GF/get_info.py index 16bebcfc75..70e007ac5c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/RegNetY-1.6GF/get_info.py +++ b/ACL_PyTorch/contrib/cv/classfication/RegNetY-1.6GF/get_info.py @@ -1,62 +1,62 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - print(index,'done') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - print(index,'done') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + print(index,'done') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + print(index,'done') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/RegNetY-1.6GF/vision_metric_ImageNet.py b/ACL_PyTorch/contrib/cv/classfication/RegNetY-1.6GF/vision_metric_ImageNet.py index 362f2484e8..583340a19f 100644 --- a/ACL_PyTorch/contrib/cv/classfication/RegNetY-1.6GF/vision_metric_ImageNet.py +++ b/ACL_PyTorch/contrib/cv/classfication/RegNetY-1.6GF/vision_metric_ImageNet.py @@ -1,184 +1,184 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - if data == '': - n_label = 0 - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = 0 - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - - resCnt = min(len(sort_index), topn) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) - print("Time used:", elapsed) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + if data == '': + n_label = 0 + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = 0 + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + + resCnt = min(len(sort_index), topn) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) + print("Time used:", elapsed) + diff --git a/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/LICENSE b/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/README.md b/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/README.md index b7ed696a91..a35e5a7aeb 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/README.md @@ -1,246 +1,246 @@ -# Res2Net101_v1b Onnx模型端到端推理指导 -- [1 模型概述](#1-模型概述) - - [1.1 论文地址](#11-论文地址) - - [1.2 代码地址](#12-代码地址) -- [2 环境说明](#2-环境说明) - - [2.1 深度学习框架](#21-深度学习框架) - - [2.2 python第三方库](#22-python第三方库) -- [3 模型转换](#3-模型转换) - - [3.1 pth转onnx模型](#31-pth转onnx模型) - - [3.2 onnx转om模型](#32-onnx转om模型) -- [4 数据集预处理](#4-数据集预处理) - - [4.1 数据集获取](#41-数据集获取) - - [4.2 数据集预处理](#42-数据集预处理) - - [4.3 生成数据集信息文件](#43-生成数据集信息文件) -- [5 离线推理](#5-离线推理) - - [5.1 benchmark工具概述](#51-benchmark工具概述) - - [5.2 离线推理](#52-离线推理) -- [6 精度对比](#6-精度对比) - - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) - - [6.2 开源TopN精度](#62-开源TopN精度) - - [6.3 精度对比](#63-精度对比) -- [7 性能对比](#7-性能对比) - - [7.1 npu性能数据](#71-npu性能数据) - - - -## 1 模型概述 - -- **[论文地址](#11-论文地址)** - -- **[代码地址](#12-代码地址)** - -### 1.1 论文地址 -[Res2Net101_v1b论文](https://arxiv.org/pdf/1904.01169.pdf) - -### 1.2 代码地址 -[Res2Net101_v1b代码](https://github.com/Res2Net/Res2Net-PretrainedModels) -branch:master -commit_id:7ed111407a22723672eac575b300adc04e75e925 - -## 2 环境说明 - -- **[深度学习框架](#21-深度学习框架)** - -- **[python第三方库](#22-python第三方库)** - -### 2.1 深度学习框架 -``` -CANN 5.0.1 - -torch == 1.5.0 -torchvision == 0.6.0 -onnx == 1.9.0 -``` - -### 2.2 python第三方库 - -``` -numpy == 1.19.2 -Pillow == 8.2.0 -opencv-python == 4.5.2.52 -``` - -**说明:** -> X86架构:pytorch和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3 模型转换 - -- **[pth转onnx模型](#31-pth转onnx模型)** - -- **[onnx转om模型](#32-onnx转om模型)** - -### 3.1 pth转onnx模型 - -1.下载pth权重文件 -[Res2Net101_v1b预训练pth权重文件](https://shanghuagao.oss-cn-beijing.aliyuncs.com/res2net/res2net101_v1b_26w_4s-0812c246.pth) -``` -wget https://shanghuagao.oss-cn-beijing.aliyuncs.com/res2net/res2net101_v1b_26w_4s-0812c246.pth -``` -文件MD5sum:ebf7af4c138fcf25db859705907af833 - -2.Res2Net101_v1b模型代码获取方式如下 -``` -git clone https://github.com/Res2Net/Res2Net-PretrainedModels.git -``` -3.编写pth2onnx脚本res2net101_v1b_pth2onnx.py - - **说明:** ->注意目前ATC支持的onnx算子版本为11 - -4.执行pth2onnx脚本,生成onnx模型文件 -``` -python3.7 res2net101_v1b_pth2onnx.py res2net101_v1b_26w_4s-0812c246.pth res2net101_v1b.onnx -``` - - **模型转换要点:** ->此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 - -### 3.2 onnx转om模型 - -1.设置环境变量 -``` -source env.sh -``` -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) -``` -atc --framework=5 --model=./res2net101_v1b.onnx --output=res2net101_v1b_bs1 --input_format=NCHW --input_shape="image:1,3,224,224" --log=debug --soc_version=Ascend310 - -``` - -## 4 数据集预处理 - -- **[数据集获取](#41-数据集获取)** - -- **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - -### 4.1 数据集获取 -该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/opt/npu/imagenet/val与/opt/npu/imagenet/val_label.txt。 - -### 4.2 数据集预处理 -1.预处理脚本imagenet_torch_preprocess.py - -2.执行预处理脚本,生成数据集预处理后的bin文件 -``` -python3.7 imagenet_torch_preprocess.py res2net101 /opt/npu/imagenet/val ./prep_dataset -``` -### 4.3 生成数据集信息文件 -1.生成数据集信息文件脚本gen_dataset_info.py - -2.执行生成数据集信息脚本,生成数据集信息文件 -``` -python3.7 gen_dataset_info.py bin ./prep_dataset ./res2net101_v1b_prep_bin.info 224 224 -``` -第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 -## 5 离线推理 - -- **[benchmark工具概述](#51-benchmark工具概述)** - -- **[离线推理](#52-离线推理)** - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) -### 5.2 离线推理 -1.设置环境变量 -``` -source env.sh -``` -2.执行离线推理 -``` -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=res2net101_v1b_bs1.om -input_text_path=./res2net101_v1b_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False -``` -输出结果默认保存在当前目录result/dumpOutput_device{0},模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 - -## 6 精度对比 - -- **[离线推理TopN精度](#61-离线推理TopN精度)** -- **[开源TopN精度](#62-开源TopN精度)** -- **[精度对比](#63-精度对比)** - -### 6.1 离线推理TopN精度统计 - -后处理统计TopN精度 - -调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 -``` -python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /opt/npu/imagenet/val_label.txt ./ result.json -``` -第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 -查看输出结果: -``` -{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value": "81.22%"}, {"key": "Top2 accuracy", "value": "90.21%"}, {"key": "Top3 accuracy", "value": "93.1%"}, {"key": "Top4 accuracy", "value": "94.44%"}, {"key": "Top5 accuracy", "value": "95.36%"}]} -``` -经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 - -### 6.2 开源TopN精度 -[论文代码仓官方精度](https://mmcheng.net/res2net/) -``` -Model Acc@1 Acc@5 -Res2Net101_v1b 81.23 95.36 -``` -### 6.3 精度对比 -将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 - **精度调试:** ->没有遇到精度不达标的问题,故不需要进行精度调试 - -## 7 性能对比 - -- **[npu性能数据](#71-npu性能数据)** - -### 7.1 npu性能数据 -1.benchmark工具在整个数据集上推理获得性能数据 -batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: -``` -[e2e] throughputRate: 55.9084, latency: 894320 -[data read] throughputRate: 59.1894, moduleLatency: 16.8949 -[preprocess] throughputRate: 59.0597, moduleLatency: 16.932 -[infer] throughputRate: 56.0004, Interface throughputRate: 62.9455, moduleLatency: 17.2581 -[post] throughputRate: 56.0004, moduleLatency: 17.857 -``` -Interface throughputRate: 62.9455,62.9455x4=251.782既是batch1 310单卡吞吐率 -batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: -``` -[e2e] throughputRate: 71.4937, latency: 699363 -[data read] throughputRate: 75.8049, moduleLatency: 13.1918 -[preprocess] throughputRate: 75.5936, moduleLatency: 13.2286 -[infer] throughputRate: 71.6788, Interface throughputRate: 86.1957, moduleLatency: 13.0185 -[post] throughputRate: 4.47989, moduleLatency: 223.22 -``` -Interface throughputRate: 86.1957,86.1957x4=344.7828既是batch16 310单卡吞吐率 -batch4性能: -``` -[e2e] throughputRate: 64.92, latency: 770179 -[data read] throughputRate: 68.6591, moduleLatency: 14.5647 -[preprocess] throughputRate: 68.5431, moduleLatency: 14.5894 -[infer] throughputRate: 65.0303, Interface throughputRate: 78.2596, moduleLatency: 14.2895 -[post] throughputRate: 16.2575, moduleLatency: 61.51 -``` -batch4 310单卡吞吐率:78.2596x4=313.0384fps -batch8性能: -``` -[e2e] throughputRate: 69.3296, latency: 721193 -[data read] throughputRate: 73.486, moduleLatency: 13.608 -[preprocess] throughputRate: 73.2601, moduleLatency: 13.65 -[infer] throughputRate: 69.5028, Interface throughputRate: 82.7469, moduleLatency: 13.5299 -[post] throughputRate: 8.68781, moduleLatency: 115.104 -``` -batch8 310单卡吞吐率:82.7469x4=330.9876fps -batch32性能: -``` -[e2e] throughputRate: 70.3878, latency: 710350 -[data read] throughputRate: 74.4979, moduleLatency: 13.4232 -[preprocess] throughputRate: 74.3318, moduleLatency: 13.4532 -[infer] throughputRate: 70.5551, Interface throughputRate: 86.8456, moduleLatency: 12.9157 -[post] throughputRate: 2.20553, moduleLatency: 453.405 -``` -batch32 310单卡吞吐率:86.8456x4=347.3824fps - - **性能优化:** -从profiling性能数据op_statistic_0_1.csv看出,耗时最多的算子主要是TransData,Conv2D与ConcatD,而Conv2D算子不存在性能问题。 -由于格式转换om模型Conv2D前后需要有TransData算子,从op_summary_0_1.csv看出,单个TransData算子aicore耗时不大。 +# Res2Net101_v1b Onnx模型端到端推理指导 +- [1 模型概述](#1-模型概述) + - [1.1 论文地址](#11-论文地址) + - [1.2 代码地址](#12-代码地址) +- [2 环境说明](#2-环境说明) + - [2.1 深度学习框架](#21-深度学习框架) + - [2.2 python第三方库](#22-python第三方库) +- [3 模型转换](#3-模型转换) + - [3.1 pth转onnx模型](#31-pth转onnx模型) + - [3.2 onnx转om模型](#32-onnx转om模型) +- [4 数据集预处理](#4-数据集预处理) + - [4.1 数据集获取](#41-数据集获取) + - [4.2 数据集预处理](#42-数据集预处理) + - [4.3 生成数据集信息文件](#43-生成数据集信息文件) +- [5 离线推理](#5-离线推理) + - [5.1 benchmark工具概述](#51-benchmark工具概述) + - [5.2 离线推理](#52-离线推理) +- [6 精度对比](#6-精度对比) + - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) + - [6.2 开源TopN精度](#62-开源TopN精度) + - [6.3 精度对比](#63-精度对比) +- [7 性能对比](#7-性能对比) + - [7.1 npu性能数据](#71-npu性能数据) + + + +## 1 模型概述 + +- **[论文地址](#11-论文地址)** + +- **[代码地址](#12-代码地址)** + +### 1.1 论文地址 +[Res2Net101_v1b论文](https://arxiv.org/pdf/1904.01169.pdf) + +### 1.2 代码地址 +[Res2Net101_v1b代码](https://github.com/Res2Net/Res2Net-PretrainedModels) +branch:master +commit_id:7ed111407a22723672eac575b300adc04e75e925 + +## 2 环境说明 + +- **[深度学习框架](#21-深度学习框架)** + +- **[python第三方库](#22-python第三方库)** + +### 2.1 深度学习框架 +``` +CANN 5.0.1 + +torch == 1.5.0 +torchvision == 0.6.0 +onnx == 1.9.0 +``` + +### 2.2 python第三方库 + +``` +numpy == 1.19.2 +Pillow == 8.2.0 +opencv-python == 4.5.2.52 +``` + +**说明:** +> X86架构:pytorch和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3 模型转换 + +- **[pth转onnx模型](#31-pth转onnx模型)** + +- **[onnx转om模型](#32-onnx转om模型)** + +### 3.1 pth转onnx模型 + +1.下载pth权重文件 +[Res2Net101_v1b预训练pth权重文件](https://shanghuagao.oss-cn-beijing.aliyuncs.com/res2net/res2net101_v1b_26w_4s-0812c246.pth) +``` +wget https://shanghuagao.oss-cn-beijing.aliyuncs.com/res2net/res2net101_v1b_26w_4s-0812c246.pth +``` +文件MD5sum:ebf7af4c138fcf25db859705907af833 + +2.Res2Net101_v1b模型代码获取方式如下 +``` +git clone https://github.com/Res2Net/Res2Net-PretrainedModels.git +``` +3.编写pth2onnx脚本res2net101_v1b_pth2onnx.py + + **说明:** +>注意目前ATC支持的onnx算子版本为11 + +4.执行pth2onnx脚本,生成onnx模型文件 +``` +python3.7 res2net101_v1b_pth2onnx.py res2net101_v1b_26w_4s-0812c246.pth res2net101_v1b.onnx +``` + + **模型转换要点:** +>此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 + +### 3.2 onnx转om模型 + +1.设置环境变量 +``` +source env.sh +``` +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) +``` +atc --framework=5 --model=./res2net101_v1b.onnx --output=res2net101_v1b_bs1 --input_format=NCHW --input_shape="image:1,3,224,224" --log=debug --soc_version=Ascend310 + +``` + +## 4 数据集预处理 + +- **[数据集获取](#41-数据集获取)** + +- **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + +### 4.1 数据集获取 +该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/opt/npu/imagenet/val与/opt/npu/imagenet/val_label.txt。 + +### 4.2 数据集预处理 +1.预处理脚本imagenet_torch_preprocess.py + +2.执行预处理脚本,生成数据集预处理后的bin文件 +``` +python3.7 imagenet_torch_preprocess.py res2net101 /opt/npu/imagenet/val ./prep_dataset +``` +### 4.3 生成数据集信息文件 +1.生成数据集信息文件脚本gen_dataset_info.py + +2.执行生成数据集信息脚本,生成数据集信息文件 +``` +python3.7 gen_dataset_info.py bin ./prep_dataset ./res2net101_v1b_prep_bin.info 224 224 +``` +第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 +## 5 离线推理 + +- **[benchmark工具概述](#51-benchmark工具概述)** + +- **[离线推理](#52-离线推理)** + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) +### 5.2 离线推理 +1.设置环境变量 +``` +source env.sh +``` +2.执行离线推理 +``` +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=res2net101_v1b_bs1.om -input_text_path=./res2net101_v1b_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False +``` +输出结果默认保存在当前目录result/dumpOutput_device{0},模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 + +## 6 精度对比 + +- **[离线推理TopN精度](#61-离线推理TopN精度)** +- **[开源TopN精度](#62-开源TopN精度)** +- **[精度对比](#63-精度对比)** + +### 6.1 离线推理TopN精度统计 + +后处理统计TopN精度 + +调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 +``` +python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /opt/npu/imagenet/val_label.txt ./ result.json +``` +第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 +查看输出结果: +``` +{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value": "81.22%"}, {"key": "Top2 accuracy", "value": "90.21%"}, {"key": "Top3 accuracy", "value": "93.1%"}, {"key": "Top4 accuracy", "value": "94.44%"}, {"key": "Top5 accuracy", "value": "95.36%"}]} +``` +经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 + +### 6.2 开源TopN精度 +[论文代码仓官方精度](https://mmcheng.net/res2net/) +``` +Model Acc@1 Acc@5 +Res2Net101_v1b 81.23 95.36 +``` +### 6.3 精度对比 +将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 + **精度调试:** +>没有遇到精度不达标的问题,故不需要进行精度调试 + +## 7 性能对比 + +- **[npu性能数据](#71-npu性能数据)** + +### 7.1 npu性能数据 +1.benchmark工具在整个数据集上推理获得性能数据 +batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: +``` +[e2e] throughputRate: 55.9084, latency: 894320 +[data read] throughputRate: 59.1894, moduleLatency: 16.8949 +[preprocess] throughputRate: 59.0597, moduleLatency: 16.932 +[infer] throughputRate: 56.0004, Interface throughputRate: 62.9455, moduleLatency: 17.2581 +[post] throughputRate: 56.0004, moduleLatency: 17.857 +``` +Interface throughputRate: 62.9455,62.9455x4=251.782既是batch1 310单卡吞吐率 +batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: +``` +[e2e] throughputRate: 71.4937, latency: 699363 +[data read] throughputRate: 75.8049, moduleLatency: 13.1918 +[preprocess] throughputRate: 75.5936, moduleLatency: 13.2286 +[infer] throughputRate: 71.6788, Interface throughputRate: 86.1957, moduleLatency: 13.0185 +[post] throughputRate: 4.47989, moduleLatency: 223.22 +``` +Interface throughputRate: 86.1957,86.1957x4=344.7828既是batch16 310单卡吞吐率 +batch4性能: +``` +[e2e] throughputRate: 64.92, latency: 770179 +[data read] throughputRate: 68.6591, moduleLatency: 14.5647 +[preprocess] throughputRate: 68.5431, moduleLatency: 14.5894 +[infer] throughputRate: 65.0303, Interface throughputRate: 78.2596, moduleLatency: 14.2895 +[post] throughputRate: 16.2575, moduleLatency: 61.51 +``` +batch4 310单卡吞吐率:78.2596x4=313.0384fps +batch8性能: +``` +[e2e] throughputRate: 69.3296, latency: 721193 +[data read] throughputRate: 73.486, moduleLatency: 13.608 +[preprocess] throughputRate: 73.2601, moduleLatency: 13.65 +[infer] throughputRate: 69.5028, Interface throughputRate: 82.7469, moduleLatency: 13.5299 +[post] throughputRate: 8.68781, moduleLatency: 115.104 +``` +batch8 310单卡吞吐率:82.7469x4=330.9876fps +batch32性能: +``` +[e2e] throughputRate: 70.3878, latency: 710350 +[data read] throughputRate: 74.4979, moduleLatency: 13.4232 +[preprocess] throughputRate: 74.3318, moduleLatency: 13.4532 +[infer] throughputRate: 70.5551, Interface throughputRate: 86.8456, moduleLatency: 12.9157 +[post] throughputRate: 2.20553, moduleLatency: 453.405 +``` +batch32 310单卡吞吐率:86.8456x4=347.3824fps + + **性能优化:** +从profiling性能数据op_statistic_0_1.csv看出,耗时最多的算子主要是TransData,Conv2D与ConcatD,而Conv2D算子不存在性能问题。 +由于格式转换om模型Conv2D前后需要有TransData算子,从op_summary_0_1.csv看出,单个TransData算子aicore耗时不大。 如果优化就需要优化掉过多的TransData算子。 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/gen_dataset_info.py index 61450b4410..5381839f65 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/gen_dataset_info.py @@ -1,61 +1,61 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' - get_jpg_info(file_path, info_name) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' + get_jpg_info(file_path, info_name) + diff --git a/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/imagenet_acc_eval.py b/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/imagenet_acc_eval.py index 362f2484e8..583340a19f 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/imagenet_acc_eval.py +++ b/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/imagenet_acc_eval.py @@ -1,184 +1,184 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - if data == '': - n_label = 0 - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = 0 - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - - resCnt = min(len(sort_index), topn) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) - print("Time used:", elapsed) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + if data == '': + n_label = 0 + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = 0 + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + + resCnt = min(len(sort_index), topn) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) + print("Time used:", elapsed) + diff --git a/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/imagenet_torch_preprocess.py b/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/imagenet_torch_preprocess.py index 987f8cc776..999675ae55 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/imagenet_torch_preprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/imagenet_torch_preprocess.py @@ -1,117 +1,117 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -from PIL import Image -import numpy as np -import multiprocessing - - -model_config = { - 'res2net101': { - 'resize': 256, - 'centercrop': 224, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv3': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv4': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.5, 0.5, 0.5], - 'std': [0.5, 0.5, 0.5], - }, -} - - -def center_crop(img, output_size): - if isinstance(output_size, int): - output_size = (int(output_size), int(output_size)) - image_width, image_height = img.size - crop_height, crop_width = output_size - crop_top = int(round((image_height - crop_height) / 2.)) - crop_left = int(round((image_width - crop_width) / 2.)) - return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) - - -def resize(img, size, interpolation=Image.BILINEAR): - if isinstance(size, int): - w, h = img.size - if (w <= h and w == size) or (h <= w and h == size): - return img - if w < h: - ow = size - oh = int(size * h / w) - return img.resize((ow, oh), interpolation) - else: - oh = size - ow = int(size * w / h) - return img.resize((ow, oh), interpolation) - else: - return img.resize(size[::-1], interpolation) - - -def gen_input_bin(mode_type, file_batches, batch): - i = 0 - for file in file_batches[batch]: - i = i + 1 - print("batch", batch, file, "===", i) - - # RGBA to RGB - image = Image.open(os.path.join(src_path, file)).convert('RGB') - image = resize(image, model_config[mode_type]['resize']) # Resize - image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop - img = np.array(image, dtype=np.float32) - img = img.transpose(2, 0, 1) # ToTensor: HWC -> CHW - img = img / 255. # ToTensor: div 255 - img -= np.array(model_config[mode_type]['mean'], dtype=np.float32)[:, None, None] # Normalize: mean - img /= np.array(model_config[mode_type]['std'], dtype=np.float32)[:, None, None] # Normalize: std - img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) - - -def preprocess(mode_type, src_path, save_path): - files = os.listdir(src_path) - file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] - thread_pool = multiprocessing.Pool(len(file_batches)) - for batch in range(len(file_batches)): - thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) - thread_pool.close() - thread_pool.join() - print("in thread, except will not report! please ensure bin files generated.") - - -if __name__ == '__main__': - if len(sys.argv) < 4: - raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") - mode_type = sys.argv[1] - src_path = sys.argv[2] - save_path = sys.argv[3] - src_path = os.path.realpath(src_path) - save_path = os.path.realpath(save_path) - if mode_type not in model_config: - model_type_help = "model type: " - for key in model_config.keys(): - model_type_help += key - model_type_help += ' ' - raise Exception(model_type_help) - if not os.path.isdir(save_path): - os.makedirs(os.path.realpath(save_path)) - preprocess(mode_type, src_path, save_path) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +from PIL import Image +import numpy as np +import multiprocessing + + +model_config = { + 'res2net101': { + 'resize': 256, + 'centercrop': 224, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv3': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv4': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.5, 0.5, 0.5], + 'std': [0.5, 0.5, 0.5], + }, +} + + +def center_crop(img, output_size): + if isinstance(output_size, int): + output_size = (int(output_size), int(output_size)) + image_width, image_height = img.size + crop_height, crop_width = output_size + crop_top = int(round((image_height - crop_height) / 2.)) + crop_left = int(round((image_width - crop_width) / 2.)) + return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) + + +def resize(img, size, interpolation=Image.BILINEAR): + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def gen_input_bin(mode_type, file_batches, batch): + i = 0 + for file in file_batches[batch]: + i = i + 1 + print("batch", batch, file, "===", i) + + # RGBA to RGB + image = Image.open(os.path.join(src_path, file)).convert('RGB') + image = resize(image, model_config[mode_type]['resize']) # Resize + image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop + img = np.array(image, dtype=np.float32) + img = img.transpose(2, 0, 1) # ToTensor: HWC -> CHW + img = img / 255. # ToTensor: div 255 + img -= np.array(model_config[mode_type]['mean'], dtype=np.float32)[:, None, None] # Normalize: mean + img /= np.array(model_config[mode_type]['std'], dtype=np.float32)[:, None, None] # Normalize: std + img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) + + +def preprocess(mode_type, src_path, save_path): + files = os.listdir(src_path) + file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] + thread_pool = multiprocessing.Pool(len(file_batches)) + for batch in range(len(file_batches)): + thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) + thread_pool.close() + thread_pool.join() + print("in thread, except will not report! please ensure bin files generated.") + + +if __name__ == '__main__': + if len(sys.argv) < 4: + raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") + mode_type = sys.argv[1] + src_path = sys.argv[2] + save_path = sys.argv[3] + src_path = os.path.realpath(src_path) + save_path = os.path.realpath(save_path) + if mode_type not in model_config: + model_type_help = "model type: " + for key in model_config.keys(): + model_type_help += key + model_type_help += ' ' + raise Exception(model_type_help) + if not os.path.isdir(save_path): + os.makedirs(os.path.realpath(save_path)) + preprocess(mode_type, src_path, save_path) + diff --git a/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/requirements.txt b/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/requirements.txt index bebc253c75..8bccb088d4 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/requirements.txt +++ b/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/requirements.txt @@ -1,6 +1,6 @@ -torch == 1.5.0 -torchvision == 0.6.0 -onnx == 1.9.0 -numpy == 1.19.2 -Pillow == 8.2.0 +torch == 1.5.0 +torchvision == 0.6.0 +onnx == 1.9.0 +numpy == 1.19.2 +Pillow == 8.2.0 opencv-python == 4.5.2.52 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/res2net101_v1b_pth2onnx.py b/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/res2net101_v1b_pth2onnx.py index 6d2f9c925a..87d0ed15f3 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/res2net101_v1b_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/res2net101_v1b_pth2onnx.py @@ -1,36 +1,36 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -import torch -import torch.onnx -sys.path.append(r"./Res2Net-PretrainedModels") -from res2net_v1b import res2net101_v1b - -def pth2onnx(input_file, output_file): - model = res2net101_v1b(pretrained=False) - checkpoint = torch.load(input_file, map_location=torch.device('cpu')) - model.load_state_dict(checkpoint) - - model.eval() - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.randn(1, 3, 224, 224) - torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=True, opset_version=11) - -if __name__ == "__main__": - input_file = sys.argv[1] - output_file = sys.argv[2] - pth2onnx(input_file, output_file) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +import torch +import torch.onnx +sys.path.append(r"./Res2Net-PretrainedModels") +from res2net_v1b import res2net101_v1b + +def pth2onnx(input_file, output_file): + model = res2net101_v1b(pretrained=False) + checkpoint = torch.load(input_file, map_location=torch.device('cpu')) + model.load_state_dict(checkpoint) + + model.eval() + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.randn(1, 3, 224, 224) + torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=True, opset_version=11) + +if __name__ == "__main__": + input_file = sys.argv[1] + output_file = sys.argv[2] + pth2onnx(input_file, output_file) diff --git a/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/test/README.md b/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/test/README.md index 7e5f518ae2..027331b15d 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/test/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b/test/README.md @@ -1,24 +1,24 @@ -环境准备: - -1.数据集路径 -数据集统一放在/root/datasets/或/opt/npu/ -本模型数据集放在/opt/npu/imagenet - -2.进入工作目录 -cd Res2Net101_v1b - -3.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -pip3.7 install -r requirements.txt - -4.获取模型代码 -git clone https://github.com/Res2Net/Res2Net-PretrainedModels.git - -5.获取权重文件 -wget https://shanghuagao.oss-cn-beijing.aliyuncs.com/res2net/res2net101_v1b_26w_4s-0812c246.pth - -6.获取benchmark工具 -将benchmark.x86_64放在当前目录 - -7.310上执行,执行时确保device空闲 -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/opt/npu/imagenet +环境准备: + +1.数据集路径 +数据集统一放在/root/datasets/或/opt/npu/ +本模型数据集放在/opt/npu/imagenet + +2.进入工作目录 +cd Res2Net101_v1b + +3.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +pip3.7 install -r requirements.txt + +4.获取模型代码 +git clone https://github.com/Res2Net/Res2Net-PretrainedModels.git + +5.获取权重文件 +wget https://shanghuagao.oss-cn-beijing.aliyuncs.com/res2net/res2net101_v1b_26w_4s-0812c246.pth + +6.获取benchmark工具 +将benchmark.x86_64放在当前目录 + +7.310上执行,执行时确保device空闲 +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/opt/npu/imagenet diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet101/LICENSE b/ACL_PyTorch/contrib/cv/classfication/ResNet101/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet101/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet101/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet101/README.md b/ACL_PyTorch/contrib/cv/classfication/ResNet101/README.md index 864fb944d5..644b8a7325 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet101/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet101/README.md @@ -1,250 +1,250 @@ -# ResNet101 Onnx模型端到端推理指导 -- [1 模型概述](#1-模型概述) - - [1.1 论文地址](#11-论文地址) - - [1.2 代码地址](#12-代码地址) -- [2 环境说明](#2-环境说明) - - [2.1 深度学习框架](#21-深度学习框架) - - [2.2 python第三方库](#22-python第三方库) -- [3 模型转换](#3-模型转换) - - [3.1 pth转onnx模型](#31-pth转onnx模型) - - [3.2 onnx转om模型](#32-onnx转om模型) -- [4 数据集预处理](#4-数据集预处理) - - [4.1 数据集获取](#41-数据集获取) - - [4.2 数据集预处理](#42-数据集预处理) - - [4.3 生成数据集信息文件](#43-生成数据集信息文件) -- [5 离线推理](#5-离线推理) - - [5.1 benchmark工具概述](#51-benchmark工具概述) - - [5.2 离线推理](#52-离线推理) -- [6 精度对比](#6-精度对比) - - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) - - [6.2 开源TopN精度](#62-开源TopN精度) - - [6.3 精度对比](#63-精度对比) -- [7 性能对比](#7-性能对比) - - [7.1 npu性能数据](#71-npu性能数据) - - - -## 1 模型概述 - -- **[论文地址](#11-论文地址)** - -- **[代码地址](#12-代码地址)** - -### 1.1 论文地址 -[ResNet101论文](https://arxiv.org/pdf/1512.03385.pdf) - -### 1.2 代码地址 -[ResNet101代码](https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py) -branch:master -commit_id:7d955df73fe0e9b47f7d6c77c699324b256fc41f - -## 2 环境说明 - -- **[深度学习框架](#21-深度学习框架)** - -- **[python第三方库](#22-python第三方库)** - -### 2.1 深度学习框架 -``` -CANN 5.0.1 - -torch == 1.5.1 -torchvision == 0.6.1 -onnx == 1.9.0 -``` - -### 2.2 python第三方库 - -``` -numpy == 1.19.2 -Pillow == 8.2.0 -opencv-python == 4.5.2 -``` - -**说明:** -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3 模型转换 - -- **[pth转onnx模型](#31-pth转onnx模型)** - -- **[onnx转om模型](#32-onnx转om模型)** - -### 3.1 pth转onnx模型 - -1.下载pth权重文件 -[ResNet-101预训练pth权重文件](https://download.pytorch.org/models/resnet101-63fe2227.pth) -``` -wget https://download.pytorch.org/models/resnet101-63fe2227.pth -``` -文件MD5sum:b258f8e54abb7de9c960ff19cc662d76 - -2.ResNet101模型代码在torchvision里,安装torchvision,arm下需源码安装,参考torchvision官网,若安装过程报错请百度解决 -``` -git clone https://github.com/pytorch/vision -cd vision -python3.7 setup.py install -cd .. -``` -3.编写pth2onnx脚本resnet101_pth2onnx.py - - **说明:** ->注意目前ATC支持的onnx算子版本为11 - -4.执行pth2onnx脚本,生成onnx模型文件 -``` -python3.7 resnet101_pth2onnx.py ./resnet101-63fe2227.pth resnet101.onnx -``` - - **模型转换要点:** ->此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 - -### 3.2 onnx转om模型 - -1.设置环境变量 -``` -source env.sh -``` -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) -``` -atc --framework=5 --model=./resnet101.onnx --output=resnet101_bs1 --input_format=NCHW --input_shape="image:1,3,224,224" --log=debug --soc_version=Ascend310 - -``` - -## 4 数据集预处理 - -- **[数据集获取](#41-数据集获取)** - -- **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - -### 4.1 数据集获取 -该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/root/datasets/imagenet/val与/root/datasets/imagenet/val_label.txt。 - -### 4.2 数据集预处理 -1.预处理脚本imagenet_torch_preprocess.py - -2.执行预处理脚本,生成数据集预处理后的bin文件 -``` -python3.7 imagenet_torch_preprocess.py resnet /root/datasets/imagenet/val ./prep_dataset -``` -### 4.3 生成数据集信息文件 -1.生成数据集信息文件脚本gen_dataset_info.py - -2.执行生成数据集信息脚本,生成数据集信息文件 -``` -python3.7 gen_dataset_info.py bin ./prep_dataset ./resnet101_prep_bin.info 224 224 -``` -第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 -## 5 离线推理 - -- **[benchmark工具概述](#51-benchmark工具概述)** - -- **[离线推理](#52-离线推理)** - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) -### 5.2 离线推理 -1.设置环境变量 -``` -source env.sh -``` -2.执行离线推理 -``` -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=resnet101_bs1.om -input_text_path=./resnet101_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False -``` -输出结果默认保存在当前目录result/dumpOutput_device{0},模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 - -## 6 精度对比 - -- **[离线推理TopN精度](#61-离线推理TopN精度)** -- **[开源TopN精度](#62-开源TopN精度)** -- **[精度对比](#63-精度对比)** - -### 6.1 离线推理TopN精度统计 - -后处理统计TopN精度 - -调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 -``` -python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /root/datasets/imagenet/val_label.txt ./ result.json -``` -第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 -查看输出结果: -``` -{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value": "77.37%"}, {"key": "Top2 accuracy", "value": "87.1%"}, {"key": "Top3 accuracy", "value": "90.61%"}, {"key": "Top4 accuracy", "value": "92.42%"}, {"key": "Top5 accuracy", "value": "93.54%"}]} -``` -经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 - -### 6.2 开源TopN精度 -[torchvision官网精度](https://pytorch.org/vision/stable/models.html) -``` -Model Acc@1 Acc@5 -ResNet-101 77.374 93.546 -``` -### 6.3 精度对比 -将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 - **精度调试:** ->没有遇到精度不达标的问题,故不需要进行精度调试 - -## 7 性能对比 - -- **[npu性能数据](#71-npu性能数据)** - -### 7.1 npu性能数据 -benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 -1.benchmark工具在整个数据集上推理获得性能数据 -batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: -``` -[e2e] throughputRate: 170.628, latency: 293035 -[data read] throughputRate: 181.571, moduleLatency: 5.50749 -[preprocess] throughputRate: 180.466, moduleLatency: 5.5412 -[infer] throughputRate: 171.595, Interface throughputRate: 247.898, moduleLatency: 5.12562 -[post] throughputRate: 171.595, moduleLatency: 5.82768 -``` -Interface throughputRate: 247.898,247.898x4=991.592既是batch1 310单卡吞吐率 -batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: -``` -[e2e] throughputRate: 185.903, latency: 268957 -[data read] throughputRate: 191.266, moduleLatency: 5.22833 -[preprocess] throughputRate: 190.761, moduleLatency: 5.24217 -[infer] throughputRate: 187.131, Interface throughputRate: 401.046, moduleLatency: 3.94051 -[post] throughputRate: 11.6954, moduleLatency: 85.5035 -``` -Interface throughputRate: 401.046,401.046x4=1604.184既是batch16 310单卡吞吐率 -batch4的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_4_device_0.txt: -``` -[e2e] throughputRate: 184.444, latency: 271085 -[data read] throughputRate: 196.412, moduleLatency: 5.09134 -[preprocess] throughputRate: 195.837, moduleLatency: 5.1063 -[infer] throughputRate: 185.624, Interface throughputRate: 331.096, moduleLatency: 4.52436 -[post] throughputRate: 46.4056, moduleLatency: 21.5491 -``` -Interface throughputRate: 331.096,331.096x4=1324.384既是batch4 310单卡吞吐率 -batch8的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_8_device_0.txt: -``` -[e2e] throughputRate: 196.051, latency: 255036 -[data read] throughputRate: 209.29, moduleLatency: 4.77806 -[preprocess] throughputRate: 207.914, moduleLatency: 4.80969 -[infer] throughputRate: 197.513, Interface throughputRate: 371.905, moduleLatency: 4.15513 -[post] throughputRate: 24.6888, moduleLatency: 40.5042 -``` -Interface throughputRate: 371.905,371.905x4=1487.62既是batch8 310单卡吞吐率 -batch32的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_32_device_0.txt: -``` -[e2e] throughputRate: 176.215, latency: 283744 -[data read] throughputRate: 187.024, moduleLatency: 5.34691 -[preprocess] throughputRate: 186.183, moduleLatency: 5.37105 -[infer] throughputRate: 177.675, Interface throughputRate: 370.456, moduleLatency: 4.14361 -[post] throughputRate: 5.55402, moduleLatency: 180.05 - -``` -Interface throughputRate: 370.456,370.456x4=1481.82既是batch32 310单卡吞吐率 - - **性能优化:** ->没有遇到性能不达标的问题,故不需要进行性能优化 - +# ResNet101 Onnx模型端到端推理指导 +- [1 模型概述](#1-模型概述) + - [1.1 论文地址](#11-论文地址) + - [1.2 代码地址](#12-代码地址) +- [2 环境说明](#2-环境说明) + - [2.1 深度学习框架](#21-深度学习框架) + - [2.2 python第三方库](#22-python第三方库) +- [3 模型转换](#3-模型转换) + - [3.1 pth转onnx模型](#31-pth转onnx模型) + - [3.2 onnx转om模型](#32-onnx转om模型) +- [4 数据集预处理](#4-数据集预处理) + - [4.1 数据集获取](#41-数据集获取) + - [4.2 数据集预处理](#42-数据集预处理) + - [4.3 生成数据集信息文件](#43-生成数据集信息文件) +- [5 离线推理](#5-离线推理) + - [5.1 benchmark工具概述](#51-benchmark工具概述) + - [5.2 离线推理](#52-离线推理) +- [6 精度对比](#6-精度对比) + - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) + - [6.2 开源TopN精度](#62-开源TopN精度) + - [6.3 精度对比](#63-精度对比) +- [7 性能对比](#7-性能对比) + - [7.1 npu性能数据](#71-npu性能数据) + + + +## 1 模型概述 + +- **[论文地址](#11-论文地址)** + +- **[代码地址](#12-代码地址)** + +### 1.1 论文地址 +[ResNet101论文](https://arxiv.org/pdf/1512.03385.pdf) + +### 1.2 代码地址 +[ResNet101代码](https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py) +branch:master +commit_id:7d955df73fe0e9b47f7d6c77c699324b256fc41f + +## 2 环境说明 + +- **[深度学习框架](#21-深度学习框架)** + +- **[python第三方库](#22-python第三方库)** + +### 2.1 深度学习框架 +``` +CANN 5.0.1 + +torch == 1.5.1 +torchvision == 0.6.1 +onnx == 1.9.0 +``` + +### 2.2 python第三方库 + +``` +numpy == 1.19.2 +Pillow == 8.2.0 +opencv-python == 4.5.2 +``` + +**说明:** +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3 模型转换 + +- **[pth转onnx模型](#31-pth转onnx模型)** + +- **[onnx转om模型](#32-onnx转om模型)** + +### 3.1 pth转onnx模型 + +1.下载pth权重文件 +[ResNet-101预训练pth权重文件](https://download.pytorch.org/models/resnet101-63fe2227.pth) +``` +wget https://download.pytorch.org/models/resnet101-63fe2227.pth +``` +文件MD5sum:b258f8e54abb7de9c960ff19cc662d76 + +2.ResNet101模型代码在torchvision里,安装torchvision,arm下需源码安装,参考torchvision官网,若安装过程报错请百度解决 +``` +git clone https://github.com/pytorch/vision +cd vision +python3.7 setup.py install +cd .. +``` +3.编写pth2onnx脚本resnet101_pth2onnx.py + + **说明:** +>注意目前ATC支持的onnx算子版本为11 + +4.执行pth2onnx脚本,生成onnx模型文件 +``` +python3.7 resnet101_pth2onnx.py ./resnet101-63fe2227.pth resnet101.onnx +``` + + **模型转换要点:** +>此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 + +### 3.2 onnx转om模型 + +1.设置环境变量 +``` +source env.sh +``` +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) +``` +atc --framework=5 --model=./resnet101.onnx --output=resnet101_bs1 --input_format=NCHW --input_shape="image:1,3,224,224" --log=debug --soc_version=Ascend310 + +``` + +## 4 数据集预处理 + +- **[数据集获取](#41-数据集获取)** + +- **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + +### 4.1 数据集获取 +该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/root/datasets/imagenet/val与/root/datasets/imagenet/val_label.txt。 + +### 4.2 数据集预处理 +1.预处理脚本imagenet_torch_preprocess.py + +2.执行预处理脚本,生成数据集预处理后的bin文件 +``` +python3.7 imagenet_torch_preprocess.py resnet /root/datasets/imagenet/val ./prep_dataset +``` +### 4.3 生成数据集信息文件 +1.生成数据集信息文件脚本gen_dataset_info.py + +2.执行生成数据集信息脚本,生成数据集信息文件 +``` +python3.7 gen_dataset_info.py bin ./prep_dataset ./resnet101_prep_bin.info 224 224 +``` +第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 +## 5 离线推理 + +- **[benchmark工具概述](#51-benchmark工具概述)** + +- **[离线推理](#52-离线推理)** + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) +### 5.2 离线推理 +1.设置环境变量 +``` +source env.sh +``` +2.执行离线推理 +``` +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=resnet101_bs1.om -input_text_path=./resnet101_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False +``` +输出结果默认保存在当前目录result/dumpOutput_device{0},模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 + +## 6 精度对比 + +- **[离线推理TopN精度](#61-离线推理TopN精度)** +- **[开源TopN精度](#62-开源TopN精度)** +- **[精度对比](#63-精度对比)** + +### 6.1 离线推理TopN精度统计 + +后处理统计TopN精度 + +调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 +``` +python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /root/datasets/imagenet/val_label.txt ./ result.json +``` +第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 +查看输出结果: +``` +{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value": "77.37%"}, {"key": "Top2 accuracy", "value": "87.1%"}, {"key": "Top3 accuracy", "value": "90.61%"}, {"key": "Top4 accuracy", "value": "92.42%"}, {"key": "Top5 accuracy", "value": "93.54%"}]} +``` +经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 + +### 6.2 开源TopN精度 +[torchvision官网精度](https://pytorch.org/vision/stable/models.html) +``` +Model Acc@1 Acc@5 +ResNet-101 77.374 93.546 +``` +### 6.3 精度对比 +将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 + **精度调试:** +>没有遇到精度不达标的问题,故不需要进行精度调试 + +## 7 性能对比 + +- **[npu性能数据](#71-npu性能数据)** + +### 7.1 npu性能数据 +benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 +1.benchmark工具在整个数据集上推理获得性能数据 +batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: +``` +[e2e] throughputRate: 170.628, latency: 293035 +[data read] throughputRate: 181.571, moduleLatency: 5.50749 +[preprocess] throughputRate: 180.466, moduleLatency: 5.5412 +[infer] throughputRate: 171.595, Interface throughputRate: 247.898, moduleLatency: 5.12562 +[post] throughputRate: 171.595, moduleLatency: 5.82768 +``` +Interface throughputRate: 247.898,247.898x4=991.592既是batch1 310单卡吞吐率 +batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: +``` +[e2e] throughputRate: 185.903, latency: 268957 +[data read] throughputRate: 191.266, moduleLatency: 5.22833 +[preprocess] throughputRate: 190.761, moduleLatency: 5.24217 +[infer] throughputRate: 187.131, Interface throughputRate: 401.046, moduleLatency: 3.94051 +[post] throughputRate: 11.6954, moduleLatency: 85.5035 +``` +Interface throughputRate: 401.046,401.046x4=1604.184既是batch16 310单卡吞吐率 +batch4的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_4_device_0.txt: +``` +[e2e] throughputRate: 184.444, latency: 271085 +[data read] throughputRate: 196.412, moduleLatency: 5.09134 +[preprocess] throughputRate: 195.837, moduleLatency: 5.1063 +[infer] throughputRate: 185.624, Interface throughputRate: 331.096, moduleLatency: 4.52436 +[post] throughputRate: 46.4056, moduleLatency: 21.5491 +``` +Interface throughputRate: 331.096,331.096x4=1324.384既是batch4 310单卡吞吐率 +batch8的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_8_device_0.txt: +``` +[e2e] throughputRate: 196.051, latency: 255036 +[data read] throughputRate: 209.29, moduleLatency: 4.77806 +[preprocess] throughputRate: 207.914, moduleLatency: 4.80969 +[infer] throughputRate: 197.513, Interface throughputRate: 371.905, moduleLatency: 4.15513 +[post] throughputRate: 24.6888, moduleLatency: 40.5042 +``` +Interface throughputRate: 371.905,371.905x4=1487.62既是batch8 310单卡吞吐率 +batch32的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_32_device_0.txt: +``` +[e2e] throughputRate: 176.215, latency: 283744 +[data read] throughputRate: 187.024, moduleLatency: 5.34691 +[preprocess] throughputRate: 186.183, moduleLatency: 5.37105 +[infer] throughputRate: 177.675, Interface throughputRate: 370.456, moduleLatency: 4.14361 +[post] throughputRate: 5.55402, moduleLatency: 180.05 + +``` +Interface throughputRate: 370.456,370.456x4=1481.82既是batch32 310单卡吞吐率 + + **性能优化:** +>没有遇到性能不达标的问题,故不需要进行性能优化 + diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet101/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/classfication/ResNet101/gen_dataset_info.py index 61450b4410..5381839f65 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet101/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet101/gen_dataset_info.py @@ -1,61 +1,61 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' - get_jpg_info(file_path, info_name) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' + get_jpg_info(file_path, info_name) + diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet101/imagenet_acc_eval.py b/ACL_PyTorch/contrib/cv/classfication/ResNet101/imagenet_acc_eval.py index 362f2484e8..583340a19f 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet101/imagenet_acc_eval.py +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet101/imagenet_acc_eval.py @@ -1,184 +1,184 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - if data == '': - n_label = 0 - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = 0 - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - - resCnt = min(len(sort_index), topn) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) - print("Time used:", elapsed) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + if data == '': + n_label = 0 + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = 0 + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + + resCnt = min(len(sort_index), topn) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) + print("Time used:", elapsed) + diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet101/imagenet_torch_preprocess.py b/ACL_PyTorch/contrib/cv/classfication/ResNet101/imagenet_torch_preprocess.py index 1ab60b54dd..a99dd271d0 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet101/imagenet_torch_preprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet101/imagenet_torch_preprocess.py @@ -1,117 +1,117 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -from PIL import Image -import numpy as np -import multiprocessing - - -model_config = { - 'resnet': { - 'resize': 256, - 'centercrop': 224, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv3': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv4': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.5, 0.5, 0.5], - 'std': [0.5, 0.5, 0.5], - }, -} - - -def center_crop(img, output_size): - if isinstance(output_size, int): - output_size = (int(output_size), int(output_size)) - image_width, image_height = img.size - crop_height, crop_width = output_size - crop_top = int(round((image_height - crop_height) / 2.)) - crop_left = int(round((image_width - crop_width) / 2.)) - return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) - - -def resize(img, size, interpolation=Image.BILINEAR): - if isinstance(size, int): - w, h = img.size - if (w <= h and w == size) or (h <= w and h == size): - return img - if w < h: - ow = size - oh = int(size * h / w) - return img.resize((ow, oh), interpolation) - else: - oh = size - ow = int(size * w / h) - return img.resize((ow, oh), interpolation) - else: - return img.resize(size[::-1], interpolation) - - -def gen_input_bin(mode_type, file_batches, batch): - i = 0 - for file in file_batches[batch]: - i = i + 1 - print("batch", batch, file, "===", i) - - # RGBA to RGB - image = Image.open(os.path.join(src_path, file)).convert('RGB') - image = resize(image, model_config[mode_type]['resize']) # Resize - image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop - img = np.array(image, dtype=np.float32) - img = img.transpose(2, 0, 1) # ToTensor: HWC -> CHW - img = img / 255. # ToTensor: div 255 - img -= np.array(model_config[mode_type]['mean'], dtype=np.float32)[:, None, None] # Normalize: mean - img /= np.array(model_config[mode_type]['std'], dtype=np.float32)[:, None, None] # Normalize: std - img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) - - -def preprocess(mode_type, src_path, save_path): - files = os.listdir(src_path) - file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] - thread_pool = multiprocessing.Pool(len(file_batches)) - for batch in range(len(file_batches)): - thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) - thread_pool.close() - thread_pool.join() - print("in thread, except will not report! please ensure bin files generated.") - - -if __name__ == '__main__': - if len(sys.argv) < 4: - raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") - mode_type = sys.argv[1] - src_path = sys.argv[2] - save_path = sys.argv[3] - src_path = os.path.realpath(src_path) - save_path = os.path.realpath(save_path) - if mode_type not in model_config: - model_type_help = "model type: " - for key in model_config.keys(): - model_type_help += key - model_type_help += ' ' - raise Exception(model_type_help) - if not os.path.isdir(save_path): - os.makedirs(os.path.realpath(save_path)) - preprocess(mode_type, src_path, save_path) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +from PIL import Image +import numpy as np +import multiprocessing + + +model_config = { + 'resnet': { + 'resize': 256, + 'centercrop': 224, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv3': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv4': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.5, 0.5, 0.5], + 'std': [0.5, 0.5, 0.5], + }, +} + + +def center_crop(img, output_size): + if isinstance(output_size, int): + output_size = (int(output_size), int(output_size)) + image_width, image_height = img.size + crop_height, crop_width = output_size + crop_top = int(round((image_height - crop_height) / 2.)) + crop_left = int(round((image_width - crop_width) / 2.)) + return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) + + +def resize(img, size, interpolation=Image.BILINEAR): + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def gen_input_bin(mode_type, file_batches, batch): + i = 0 + for file in file_batches[batch]: + i = i + 1 + print("batch", batch, file, "===", i) + + # RGBA to RGB + image = Image.open(os.path.join(src_path, file)).convert('RGB') + image = resize(image, model_config[mode_type]['resize']) # Resize + image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop + img = np.array(image, dtype=np.float32) + img = img.transpose(2, 0, 1) # ToTensor: HWC -> CHW + img = img / 255. # ToTensor: div 255 + img -= np.array(model_config[mode_type]['mean'], dtype=np.float32)[:, None, None] # Normalize: mean + img /= np.array(model_config[mode_type]['std'], dtype=np.float32)[:, None, None] # Normalize: std + img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) + + +def preprocess(mode_type, src_path, save_path): + files = os.listdir(src_path) + file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] + thread_pool = multiprocessing.Pool(len(file_batches)) + for batch in range(len(file_batches)): + thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) + thread_pool.close() + thread_pool.join() + print("in thread, except will not report! please ensure bin files generated.") + + +if __name__ == '__main__': + if len(sys.argv) < 4: + raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") + mode_type = sys.argv[1] + src_path = sys.argv[2] + save_path = sys.argv[3] + src_path = os.path.realpath(src_path) + save_path = os.path.realpath(save_path) + if mode_type not in model_config: + model_type_help = "model type: " + for key in model_config.keys(): + model_type_help += key + model_type_help += ' ' + raise Exception(model_type_help) + if not os.path.isdir(save_path): + os.makedirs(os.path.realpath(save_path)) + preprocess(mode_type, src_path, save_path) + diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet101/requirements.txt b/ACL_PyTorch/contrib/cv/classfication/ResNet101/requirements.txt index 2fc4e802c4..d072d9aa6f 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet101/requirements.txt +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet101/requirements.txt @@ -1,6 +1,6 @@ -torch == 1.5.1 -torchvision == 0.6.1 -onnx == 1.9.0 -numpy == 1.19.2 -Pillow == 8.2.0 +torch == 1.5.1 +torchvision == 0.6.1 +onnx == 1.9.0 +numpy == 1.19.2 +Pillow == 8.2.0 opencv-python == 4.5.2 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet101/resnet101_pth2onnx.py b/ACL_PyTorch/contrib/cv/classfication/ResNet101/resnet101_pth2onnx.py index 46ab195411..8eff59a680 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet101/resnet101_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet101/resnet101_pth2onnx.py @@ -1,35 +1,35 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -import torch -import torch.onnx -import torchvision.models as models - -def pth2onnx(input_file, output_file): - model = models.resnet101(pretrained=False) - checkpoint = torch.load(input_file, map_location=None) - model.load_state_dict(checkpoint) - - model.eval() - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.randn(1, 3, 224, 224) - torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=True, opset_version=11) - -if __name__ == "__main__": - input_file = sys.argv[1] - output_file = sys.argv[2] - pth2onnx(input_file, output_file) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +import torch +import torch.onnx +import torchvision.models as models + +def pth2onnx(input_file, output_file): + model = models.resnet101(pretrained=False) + checkpoint = torch.load(input_file, map_location=None) + model.load_state_dict(checkpoint) + + model.eval() + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.randn(1, 3, 224, 224) + torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=True, opset_version=11) + +if __name__ == "__main__": + input_file = sys.argv[1] + output_file = sys.argv[2] + pth2onnx(input_file, output_file) diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet101/test/README.md b/ACL_PyTorch/contrib/cv/classfication/ResNet101/test/README.md index 1c1ba3c42f..d7ffd9773a 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet101/test/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet101/test/README.md @@ -1,29 +1,29 @@ -环境准备: - -1.数据集路径 -数据集统一放在/root/datasets/或/opt/npu/ -本模型数据集放在/root/datasets/ - -2.进入工作目录 -cd ResNet101 - -3.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -pip3.7 install -r requirements.txt - -4.获取模型代码 -git clone https://github.com/pytorch/vision - -5.如果模型代码需要安装,则安装模型代码 -cd vision -python3.7 setup.py install -cd .. - -6.获取权重文件 -wget https://download.pytorch.org/models/resnet101-63fe2227.pth - -7.获取benchmark工具 -将benchmark.x86_64放在当前目录 - -8.310上执行,执行时确保device空闲 -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets +环境准备: + +1.数据集路径 +数据集统一放在/root/datasets/或/opt/npu/ +本模型数据集放在/root/datasets/ + +2.进入工作目录 +cd ResNet101 + +3.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +pip3.7 install -r requirements.txt + +4.获取模型代码 +git clone https://github.com/pytorch/vision + +5.如果模型代码需要安装,则安装模型代码 +cd vision +python3.7 setup.py install +cd .. + +6.获取权重文件 +wget https://download.pytorch.org/models/resnet101-63fe2227.pth + +7.获取benchmark工具 +将benchmark.x86_64放在当前目录 + +8.310上执行,执行时确保device空闲 +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet101/test/parse.py b/ACL_PyTorch/contrib/cv/classfication/ResNet101/test/parse.py index a0f253b055..27eae0d0ac 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet101/test/parse.py +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet101/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet18/LICENSE b/ACL_PyTorch/contrib/cv/classfication/ResNet18/LICENSE index 657549b860..dcc65541a1 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet18/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet18/LICENSE @@ -1,30 +1,30 @@ -BSD 3-Clause License - -Copyright (c) 2017, -All rights reserved. -Copyright 2020 Huawei Technologies Co., Ltd - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +BSD 3-Clause License + +Copyright (c) 2017, +All rights reserved. +Copyright 2020 Huawei Technologies Co., Ltd + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet18/README.md b/ACL_PyTorch/contrib/cv/classfication/ResNet18/README.md index 70663bd09a..77b0b5b46f 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet18/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet18/README.md @@ -1,249 +1,249 @@ -# ResNet18 Onnx模型端到端推理指导 -- [1 模型概述](#1-模型概述) - - [1.1 论文地址](#11-论文地址) - - [1.2 代码地址](#12-代码地址) -- [2 环境说明](#2-环境说明) - - [2.1 深度学习框架](#21-深度学习框架) - - [2.2 python第三方库](#22-python第三方库) -- [3 模型转换](#3-模型转换) - - [3.1 pth转onnx模型](#31-pth转onnx模型) - - [3.2 onnx转om模型](#32-onnx转om模型) -- [4 数据集预处理](#4-数据集预处理) - - [4.1 数据集获取](#41-数据集获取) - - [4.2 数据集预处理](#42-数据集预处理) - - [4.3 生成数据集信息文件](#43-生成数据集信息文件) -- [5 离线推理](#5-离线推理) - - [5.1 benchmark工具概述](#51-benchmark工具概述) - - [5.2 离线推理](#52-离线推理) -- [6 精度对比](#6-精度对比) - - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) - - [6.2 开源TopN精度](#62-开源TopN精度) - - [6.3 精度对比](#63-精度对比) -- [7 性能对比](#7-性能对比) - - [7.1 npu性能数据](#71-npu性能数据) - - - -## 1 模型概述 - -- **[论文地址](#11-论文地址)** - -- **[代码地址](#12-代码地址)** - -### 1.1 论文地址 -[ResNet18论文](https://arxiv.org/pdf/1512.03385.pdf) - -### 1.2 代码地址 -[ResNet18代码](https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py) -branch:master -commit_id:7d955df73fe0e9b47f7d6c77c699324b256fc41f - -## 2 环境说明 - -- **[深度学习框架](#21-深度学习框架)** - -- **[python第三方库](#22-python第三方库)** - -### 2.1 深度学习框架 -``` -CANN 5.0.1 - -torch == 1.5.1 -torchvision == 0.6.1 -onnx == 1.9.0 -``` - -### 2.2 python第三方库 - -``` -numpy == 1.19.2 -Pillow == 8.2.0 -opencv-python == 4.5.2 -``` - -**说明:** -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3 模型转换 - -- **[pth转onnx模型](#31-pth转onnx模型)** - -- **[onnx转om模型](#32-onnx转om模型)** - -### 3.1 pth转onnx模型 - -1.下载pth权重文件 -[ResNet-18预训练pth权重文件](https://download.pytorch.org/models/resnet18-f37072fd.pth) -``` -wget https://download.pytorch.org/models/resnet18-f37072fd.pth -``` -文件MD5sum:e0b1c919e74f9a193d36871d9964bf7d - -2.ResNet18模型代码在torchvision里,安装torchvision,arm下需源码安装,参考torchvision官网,若安装过程报错请百度解决 -``` -git clone https://github.com/pytorch/vision -cd vision -python3.7 setup.py install -cd .. -``` -3.编写pth2onnx脚本resnet18_pth2onnx.py - - **说明:** ->注意目前ATC支持的onnx算子版本为11 - -4.执行pth2onnx脚本,生成onnx模型文件 -``` -python3.7 resnet18_pth2onnx.py ./resnet18-f37072fd.pth resnet18.onnx -``` - - **模型转换要点:** ->此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 - -### 3.2 onnx转om模型 - -1.设置环境变量 -``` -source env.sh -``` -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) -``` -atc --framework=5 --model=./resnet18.onnx --output=resnet18_bs1 --input_format=NCHW --input_shape="image:1,3,224,224" --log=debug --soc_version=Ascend310 - -``` - -## 4 数据集预处理 - -- **[数据集获取](#41-数据集获取)** - -- **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - -### 4.1 数据集获取 -该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/root/datasets/imagenet/val与/root/datasets/imagenet/val_label.txt。 - -### 4.2 数据集预处理 -1.预处理脚本imagenet_torch_preprocess.py - -2.执行预处理脚本,生成数据集预处理后的bin文件 -``` -python3.7 imagenet_torch_preprocess.py resnet /root/datasets/imagenet/val ./prep_dataset -``` -### 4.3 生成数据集信息文件 -1.生成数据集信息文件脚本gen_dataset_info.py - -2.执行生成数据集信息脚本,生成数据集信息文件 -``` -python3.7 gen_dataset_info.py bin ./prep_dataset ./resnet18_prep_bin.info 224 224 -``` -第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 -## 5 离线推理 - -- **[benchmark工具概述](#51-benchmark工具概述)** - -- **[离线推理](#52-离线推理)** - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) -### 5.2 离线推理 -1.设置环境变量 -``` -source env.sh -``` -2.执行离线推理 -``` -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=resnet18_bs1.om -input_text_path=./resnet18_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False -``` -输出结果默认保存在当前目录result/dumpOutput_device{0},模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 - -## 6 精度对比 - -- **[离线推理TopN精度](#61-离线推理TopN精度)** -- **[开源TopN精度](#62-开源TopN精度)** -- **[精度对比](#63-精度对比)** - -### 6.1 离线推理TopN精度统计 - -后处理统计TopN精度 - -调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 -``` -python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /root/datasets/imagenet/val_label.txt ./ result.json -``` -第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 -查看输出结果: -``` -{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value": "69.74%"}, {"key": "Top2 accuracy", "value": "80.49%"}, {"key": "Top3 accuracy", "value": "84.96%"}, {"key": "Top4 accuracy", "value": "87.38%"}, {"key": "Top5 accuracy", "value": "89.09%"}]} -``` -经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 - -### 6.2 开源TopN精度 -[torchvision官网精度](https://pytorch.org/vision/stable/models.html) -``` -Model Acc@1 Acc@5 -ResNet-18 69.758 89.078 -``` -### 6.3 精度对比 -将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 - **精度调试:** ->没有遇到精度不达标的问题,故不需要进行精度调试 - -## 7 性能对比 - -- **[npu性能数据](#71-npu性能数据)** - -### 7.1 npu性能数据 -benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 -1.benchmark工具在整个数据集上推理获得性能数据 -batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: -``` -[e2e] throughputRate: 336.39, latency: 148637 -[data read] throughputRate: 357.787, moduleLatency: 2.79496 -[preprocess] throughputRate: 357.147, moduleLatency: 2.79997 -[infer] throughputRate: 338.442, Interface throughputRate: 787.709, moduleLatency: 2.21785 -[post] throughputRate: 338.44, moduleLatency: 2.95473 -``` -Interface throughputRate: 787.709,787.709x4=3150.836既是batch1 310单卡吞吐率 -batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: -``` -[e2e] throughputRate: 355.715, latency: 140562 -[data read] throughputRate: 377.215, moduleLatency: 2.65101 -[preprocess] throughputRate: 376.578, moduleLatency: 2.65549 -[infer] throughputRate: 357.628, Interface throughputRate: 1509.64, moduleLatency: 2.1165 -[post] throughputRate: 22.3509, moduleLatency: 44.7409 -``` -Interface throughputRate: 1509.64,1509.64x4=6038.56既是batch16 310单卡吞吐率 -batch4性能: -``` -[e2e] throughputRate: 218.705, latency: 228619 -[data read] throughputRate: 219.993, moduleLatency: 4.5456 -[preprocess] throughputRate: 219.699, moduleLatency: 4.55169 -[infer] throughputRate: 219.574, Interface throughputRate: 1103.24, moduleLatency: 2.38868 -[post] throughputRate: 54.8929, moduleLatency: 18.2173 -``` -batch4 310单卡吞吐率:1103.24x4=4412.96fps -batch8性能: -``` -[e2e] throughputRate: 175.032, latency: 285662 -[data read] throughputRate: 175.909, moduleLatency: 5.68474 -[preprocess] throughputRate: 175.703, moduleLatency: 5.69143 -[infer] throughputRate: 175.795, Interface throughputRate: 1446.02, moduleLatency: 2.17869 -[post] throughputRate: 21.9741, moduleLatency: 45.5081 -``` -batch8 310单卡吞吐率:1446.02x4=5784.08fps -batch32性能: -``` -[e2e] throughputRate: 151.68, latency: 329642 -[data read] throughputRate: 152.292, moduleLatency: 6.56634 -[preprocess] throughputRate: 152.082, moduleLatency: 6.57541 -[infer] throughputRate: 152.081, Interface throughputRate: 1375.46, moduleLatency: 2.20383 -[post] throughputRate: 4.75395, moduleLatency: 210.352 -``` -batch32 310单卡吞吐率:1375.46x4=5501.84fps - - **性能优化:** ->没有遇到性能不达标的问题,故不需要进行性能优化 - +# ResNet18 Onnx模型端到端推理指导 +- [1 模型概述](#1-模型概述) + - [1.1 论文地址](#11-论文地址) + - [1.2 代码地址](#12-代码地址) +- [2 环境说明](#2-环境说明) + - [2.1 深度学习框架](#21-深度学习框架) + - [2.2 python第三方库](#22-python第三方库) +- [3 模型转换](#3-模型转换) + - [3.1 pth转onnx模型](#31-pth转onnx模型) + - [3.2 onnx转om模型](#32-onnx转om模型) +- [4 数据集预处理](#4-数据集预处理) + - [4.1 数据集获取](#41-数据集获取) + - [4.2 数据集预处理](#42-数据集预处理) + - [4.3 生成数据集信息文件](#43-生成数据集信息文件) +- [5 离线推理](#5-离线推理) + - [5.1 benchmark工具概述](#51-benchmark工具概述) + - [5.2 离线推理](#52-离线推理) +- [6 精度对比](#6-精度对比) + - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) + - [6.2 开源TopN精度](#62-开源TopN精度) + - [6.3 精度对比](#63-精度对比) +- [7 性能对比](#7-性能对比) + - [7.1 npu性能数据](#71-npu性能数据) + + + +## 1 模型概述 + +- **[论文地址](#11-论文地址)** + +- **[代码地址](#12-代码地址)** + +### 1.1 论文地址 +[ResNet18论文](https://arxiv.org/pdf/1512.03385.pdf) + +### 1.2 代码地址 +[ResNet18代码](https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py) +branch:master +commit_id:7d955df73fe0e9b47f7d6c77c699324b256fc41f + +## 2 环境说明 + +- **[深度学习框架](#21-深度学习框架)** + +- **[python第三方库](#22-python第三方库)** + +### 2.1 深度学习框架 +``` +CANN 5.0.1 + +torch == 1.5.1 +torchvision == 0.6.1 +onnx == 1.9.0 +``` + +### 2.2 python第三方库 + +``` +numpy == 1.19.2 +Pillow == 8.2.0 +opencv-python == 4.5.2 +``` + +**说明:** +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3 模型转换 + +- **[pth转onnx模型](#31-pth转onnx模型)** + +- **[onnx转om模型](#32-onnx转om模型)** + +### 3.1 pth转onnx模型 + +1.下载pth权重文件 +[ResNet-18预训练pth权重文件](https://download.pytorch.org/models/resnet18-f37072fd.pth) +``` +wget https://download.pytorch.org/models/resnet18-f37072fd.pth +``` +文件MD5sum:e0b1c919e74f9a193d36871d9964bf7d + +2.ResNet18模型代码在torchvision里,安装torchvision,arm下需源码安装,参考torchvision官网,若安装过程报错请百度解决 +``` +git clone https://github.com/pytorch/vision +cd vision +python3.7 setup.py install +cd .. +``` +3.编写pth2onnx脚本resnet18_pth2onnx.py + + **说明:** +>注意目前ATC支持的onnx算子版本为11 + +4.执行pth2onnx脚本,生成onnx模型文件 +``` +python3.7 resnet18_pth2onnx.py ./resnet18-f37072fd.pth resnet18.onnx +``` + + **模型转换要点:** +>此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 + +### 3.2 onnx转om模型 + +1.设置环境变量 +``` +source env.sh +``` +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) +``` +atc --framework=5 --model=./resnet18.onnx --output=resnet18_bs1 --input_format=NCHW --input_shape="image:1,3,224,224" --log=debug --soc_version=Ascend310 + +``` + +## 4 数据集预处理 + +- **[数据集获取](#41-数据集获取)** + +- **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + +### 4.1 数据集获取 +该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/root/datasets/imagenet/val与/root/datasets/imagenet/val_label.txt。 + +### 4.2 数据集预处理 +1.预处理脚本imagenet_torch_preprocess.py + +2.执行预处理脚本,生成数据集预处理后的bin文件 +``` +python3.7 imagenet_torch_preprocess.py resnet /root/datasets/imagenet/val ./prep_dataset +``` +### 4.3 生成数据集信息文件 +1.生成数据集信息文件脚本gen_dataset_info.py + +2.执行生成数据集信息脚本,生成数据集信息文件 +``` +python3.7 gen_dataset_info.py bin ./prep_dataset ./resnet18_prep_bin.info 224 224 +``` +第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 +## 5 离线推理 + +- **[benchmark工具概述](#51-benchmark工具概述)** + +- **[离线推理](#52-离线推理)** + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) +### 5.2 离线推理 +1.设置环境变量 +``` +source env.sh +``` +2.执行离线推理 +``` +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=resnet18_bs1.om -input_text_path=./resnet18_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False +``` +输出结果默认保存在当前目录result/dumpOutput_device{0},模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 + +## 6 精度对比 + +- **[离线推理TopN精度](#61-离线推理TopN精度)** +- **[开源TopN精度](#62-开源TopN精度)** +- **[精度对比](#63-精度对比)** + +### 6.1 离线推理TopN精度统计 + +后处理统计TopN精度 + +调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 +``` +python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /root/datasets/imagenet/val_label.txt ./ result.json +``` +第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 +查看输出结果: +``` +{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value": "69.74%"}, {"key": "Top2 accuracy", "value": "80.49%"}, {"key": "Top3 accuracy", "value": "84.96%"}, {"key": "Top4 accuracy", "value": "87.38%"}, {"key": "Top5 accuracy", "value": "89.09%"}]} +``` +经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 + +### 6.2 开源TopN精度 +[torchvision官网精度](https://pytorch.org/vision/stable/models.html) +``` +Model Acc@1 Acc@5 +ResNet-18 69.758 89.078 +``` +### 6.3 精度对比 +将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 + **精度调试:** +>没有遇到精度不达标的问题,故不需要进行精度调试 + +## 7 性能对比 + +- **[npu性能数据](#71-npu性能数据)** + +### 7.1 npu性能数据 +benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 +1.benchmark工具在整个数据集上推理获得性能数据 +batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: +``` +[e2e] throughputRate: 336.39, latency: 148637 +[data read] throughputRate: 357.787, moduleLatency: 2.79496 +[preprocess] throughputRate: 357.147, moduleLatency: 2.79997 +[infer] throughputRate: 338.442, Interface throughputRate: 787.709, moduleLatency: 2.21785 +[post] throughputRate: 338.44, moduleLatency: 2.95473 +``` +Interface throughputRate: 787.709,787.709x4=3150.836既是batch1 310单卡吞吐率 +batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: +``` +[e2e] throughputRate: 355.715, latency: 140562 +[data read] throughputRate: 377.215, moduleLatency: 2.65101 +[preprocess] throughputRate: 376.578, moduleLatency: 2.65549 +[infer] throughputRate: 357.628, Interface throughputRate: 1509.64, moduleLatency: 2.1165 +[post] throughputRate: 22.3509, moduleLatency: 44.7409 +``` +Interface throughputRate: 1509.64,1509.64x4=6038.56既是batch16 310单卡吞吐率 +batch4性能: +``` +[e2e] throughputRate: 218.705, latency: 228619 +[data read] throughputRate: 219.993, moduleLatency: 4.5456 +[preprocess] throughputRate: 219.699, moduleLatency: 4.55169 +[infer] throughputRate: 219.574, Interface throughputRate: 1103.24, moduleLatency: 2.38868 +[post] throughputRate: 54.8929, moduleLatency: 18.2173 +``` +batch4 310单卡吞吐率:1103.24x4=4412.96fps +batch8性能: +``` +[e2e] throughputRate: 175.032, latency: 285662 +[data read] throughputRate: 175.909, moduleLatency: 5.68474 +[preprocess] throughputRate: 175.703, moduleLatency: 5.69143 +[infer] throughputRate: 175.795, Interface throughputRate: 1446.02, moduleLatency: 2.17869 +[post] throughputRate: 21.9741, moduleLatency: 45.5081 +``` +batch8 310单卡吞吐率:1446.02x4=5784.08fps +batch32性能: +``` +[e2e] throughputRate: 151.68, latency: 329642 +[data read] throughputRate: 152.292, moduleLatency: 6.56634 +[preprocess] throughputRate: 152.082, moduleLatency: 6.57541 +[infer] throughputRate: 152.081, Interface throughputRate: 1375.46, moduleLatency: 2.20383 +[post] throughputRate: 4.75395, moduleLatency: 210.352 +``` +batch32 310单卡吞吐率:1375.46x4=5501.84fps + + **性能优化:** +>没有遇到性能不达标的问题,故不需要进行性能优化 + diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet18/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/classfication/ResNet18/gen_dataset_info.py index 61450b4410..5381839f65 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet18/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet18/gen_dataset_info.py @@ -1,61 +1,61 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' - get_jpg_info(file_path, info_name) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' + get_jpg_info(file_path, info_name) + diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet18/imagenet_acc_eval.py b/ACL_PyTorch/contrib/cv/classfication/ResNet18/imagenet_acc_eval.py index 362f2484e8..583340a19f 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet18/imagenet_acc_eval.py +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet18/imagenet_acc_eval.py @@ -1,184 +1,184 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - if data == '': - n_label = 0 - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = 0 - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - - resCnt = min(len(sort_index), topn) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) - print("Time used:", elapsed) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + if data == '': + n_label = 0 + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = 0 + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + + resCnt = min(len(sort_index), topn) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) + print("Time used:", elapsed) + diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet18/imagenet_torch_preprocess.py b/ACL_PyTorch/contrib/cv/classfication/ResNet18/imagenet_torch_preprocess.py index 1ab60b54dd..a99dd271d0 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet18/imagenet_torch_preprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet18/imagenet_torch_preprocess.py @@ -1,117 +1,117 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -from PIL import Image -import numpy as np -import multiprocessing - - -model_config = { - 'resnet': { - 'resize': 256, - 'centercrop': 224, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv3': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv4': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.5, 0.5, 0.5], - 'std': [0.5, 0.5, 0.5], - }, -} - - -def center_crop(img, output_size): - if isinstance(output_size, int): - output_size = (int(output_size), int(output_size)) - image_width, image_height = img.size - crop_height, crop_width = output_size - crop_top = int(round((image_height - crop_height) / 2.)) - crop_left = int(round((image_width - crop_width) / 2.)) - return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) - - -def resize(img, size, interpolation=Image.BILINEAR): - if isinstance(size, int): - w, h = img.size - if (w <= h and w == size) or (h <= w and h == size): - return img - if w < h: - ow = size - oh = int(size * h / w) - return img.resize((ow, oh), interpolation) - else: - oh = size - ow = int(size * w / h) - return img.resize((ow, oh), interpolation) - else: - return img.resize(size[::-1], interpolation) - - -def gen_input_bin(mode_type, file_batches, batch): - i = 0 - for file in file_batches[batch]: - i = i + 1 - print("batch", batch, file, "===", i) - - # RGBA to RGB - image = Image.open(os.path.join(src_path, file)).convert('RGB') - image = resize(image, model_config[mode_type]['resize']) # Resize - image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop - img = np.array(image, dtype=np.float32) - img = img.transpose(2, 0, 1) # ToTensor: HWC -> CHW - img = img / 255. # ToTensor: div 255 - img -= np.array(model_config[mode_type]['mean'], dtype=np.float32)[:, None, None] # Normalize: mean - img /= np.array(model_config[mode_type]['std'], dtype=np.float32)[:, None, None] # Normalize: std - img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) - - -def preprocess(mode_type, src_path, save_path): - files = os.listdir(src_path) - file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] - thread_pool = multiprocessing.Pool(len(file_batches)) - for batch in range(len(file_batches)): - thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) - thread_pool.close() - thread_pool.join() - print("in thread, except will not report! please ensure bin files generated.") - - -if __name__ == '__main__': - if len(sys.argv) < 4: - raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") - mode_type = sys.argv[1] - src_path = sys.argv[2] - save_path = sys.argv[3] - src_path = os.path.realpath(src_path) - save_path = os.path.realpath(save_path) - if mode_type not in model_config: - model_type_help = "model type: " - for key in model_config.keys(): - model_type_help += key - model_type_help += ' ' - raise Exception(model_type_help) - if not os.path.isdir(save_path): - os.makedirs(os.path.realpath(save_path)) - preprocess(mode_type, src_path, save_path) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +from PIL import Image +import numpy as np +import multiprocessing + + +model_config = { + 'resnet': { + 'resize': 256, + 'centercrop': 224, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv3': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv4': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.5, 0.5, 0.5], + 'std': [0.5, 0.5, 0.5], + }, +} + + +def center_crop(img, output_size): + if isinstance(output_size, int): + output_size = (int(output_size), int(output_size)) + image_width, image_height = img.size + crop_height, crop_width = output_size + crop_top = int(round((image_height - crop_height) / 2.)) + crop_left = int(round((image_width - crop_width) / 2.)) + return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) + + +def resize(img, size, interpolation=Image.BILINEAR): + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def gen_input_bin(mode_type, file_batches, batch): + i = 0 + for file in file_batches[batch]: + i = i + 1 + print("batch", batch, file, "===", i) + + # RGBA to RGB + image = Image.open(os.path.join(src_path, file)).convert('RGB') + image = resize(image, model_config[mode_type]['resize']) # Resize + image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop + img = np.array(image, dtype=np.float32) + img = img.transpose(2, 0, 1) # ToTensor: HWC -> CHW + img = img / 255. # ToTensor: div 255 + img -= np.array(model_config[mode_type]['mean'], dtype=np.float32)[:, None, None] # Normalize: mean + img /= np.array(model_config[mode_type]['std'], dtype=np.float32)[:, None, None] # Normalize: std + img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) + + +def preprocess(mode_type, src_path, save_path): + files = os.listdir(src_path) + file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] + thread_pool = multiprocessing.Pool(len(file_batches)) + for batch in range(len(file_batches)): + thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) + thread_pool.close() + thread_pool.join() + print("in thread, except will not report! please ensure bin files generated.") + + +if __name__ == '__main__': + if len(sys.argv) < 4: + raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") + mode_type = sys.argv[1] + src_path = sys.argv[2] + save_path = sys.argv[3] + src_path = os.path.realpath(src_path) + save_path = os.path.realpath(save_path) + if mode_type not in model_config: + model_type_help = "model type: " + for key in model_config.keys(): + model_type_help += key + model_type_help += ' ' + raise Exception(model_type_help) + if not os.path.isdir(save_path): + os.makedirs(os.path.realpath(save_path)) + preprocess(mode_type, src_path, save_path) + diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet18/requirements.txt b/ACL_PyTorch/contrib/cv/classfication/ResNet18/requirements.txt index 2fc4e802c4..d072d9aa6f 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet18/requirements.txt +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet18/requirements.txt @@ -1,6 +1,6 @@ -torch == 1.5.1 -torchvision == 0.6.1 -onnx == 1.9.0 -numpy == 1.19.2 -Pillow == 8.2.0 +torch == 1.5.1 +torchvision == 0.6.1 +onnx == 1.9.0 +numpy == 1.19.2 +Pillow == 8.2.0 opencv-python == 4.5.2 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet18/resnet18_pth2onnx.py b/ACL_PyTorch/contrib/cv/classfication/ResNet18/resnet18_pth2onnx.py index f7972ea3e1..5933787407 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet18/resnet18_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet18/resnet18_pth2onnx.py @@ -1,35 +1,35 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -import torch -import torch.onnx -import torchvision.models as models - -def pth2onnx(input_file, output_file): - model = models.resnet18(pretrained=False) - checkpoint = torch.load(input_file, map_location=None) - model.load_state_dict(checkpoint) - - model.eval() - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.randn(1, 3, 224, 224) - torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=True, opset_version=11) - -if __name__ == "__main__": - input_file = sys.argv[1] - output_file = sys.argv[2] - pth2onnx(input_file, output_file) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +import torch +import torch.onnx +import torchvision.models as models + +def pth2onnx(input_file, output_file): + model = models.resnet18(pretrained=False) + checkpoint = torch.load(input_file, map_location=None) + model.load_state_dict(checkpoint) + + model.eval() + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.randn(1, 3, 224, 224) + torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=True, opset_version=11) + +if __name__ == "__main__": + input_file = sys.argv[1] + output_file = sys.argv[2] + pth2onnx(input_file, output_file) diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet18/test/README.md b/ACL_PyTorch/contrib/cv/classfication/ResNet18/test/README.md index d9901cc5fc..0ae0ab0e82 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet18/test/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet18/test/README.md @@ -1,29 +1,29 @@ -环境准备: - -1.数据集路径 -数据集统一放在/root/datasets/或/opt/npu/ -本模型数据集放在/root/datasets/ - -2.进入工作目录 -cd ResNet18 - -3.安装必要的依赖 -pip3.7 install -r requirements.txt - -4.获取模型代码 -git clone https://github.com/pytorch/vision - -5.如果模型代码需要安装,则安装模型代码 -cd vision -python3.7 setup.py install -cd .. - -6.获取权重文件 -wget https://download.pytorch.org/models/resnet18-f37072fd.pth - -7.获取benchmark工具 -将benchmark.x86_64放在当前目录 - -8.310上执行,执行时确保device空闲 -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets +环境准备: + +1.数据集路径 +数据集统一放在/root/datasets/或/opt/npu/ +本模型数据集放在/root/datasets/ + +2.进入工作目录 +cd ResNet18 + +3.安装必要的依赖 +pip3.7 install -r requirements.txt + +4.获取模型代码 +git clone https://github.com/pytorch/vision + +5.如果模型代码需要安装,则安装模型代码 +cd vision +python3.7 setup.py install +cd .. + +6.获取权重文件 +wget https://download.pytorch.org/models/resnet18-f37072fd.pth + +7.获取benchmark工具 +将benchmark.x86_64放在当前目录 + +8.310上执行,执行时确保device空闲 +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet18/test/parse.py b/ACL_PyTorch/contrib/cv/classfication/ResNet18/test/parse.py index a0f253b055..27eae0d0ac 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet18/test/parse.py +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet18/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet34/LICENSE b/ACL_PyTorch/contrib/cv/classfication/ResNet34/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet34/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet34/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet34/README.md b/ACL_PyTorch/contrib/cv/classfication/ResNet34/README.md index 2c2062bf5e..60c3739d7b 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet34/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet34/README.md @@ -1,250 +1,250 @@ -# ResNet34 Onnx模型端到端推理指导 -- [1 模型概述](#1-模型概述) - - [1.1 论文地址](#11-论文地址) - - [1.2 代码地址](#12-代码地址) -- [2 环境说明](#2-环境说明) - - [2.1 深度学习框架](#21-深度学习框架) - - [2.2 python第三方库](#22-python第三方库) -- [3 模型转换](#3-模型转换) - - [3.1 pth转onnx模型](#31-pth转onnx模型) - - [3.2 onnx转om模型](#32-onnx转om模型) -- [4 数据集预处理](#4-数据集预处理) - - [4.1 数据集获取](#41-数据集获取) - - [4.2 数据集预处理](#42-数据集预处理) - - [4.3 生成数据集信息文件](#43-生成数据集信息文件) -- [5 离线推理](#5-离线推理) - - [5.1 benchmark工具概述](#51-benchmark工具概述) - - [5.2 离线推理](#52-离线推理) -- [6 精度对比](#6-精度对比) - - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) - - [6.2 开源TopN精度](#62-开源TopN精度) - - [6.3 精度对比](#63-精度对比) -- [7 性能对比](#7-性能对比) - - [7.1 npu性能数据](#71-npu性能数据) - - -## 1 模型概述 - -- **[论文地址](#11-论文地址)** - -- **[代码地址](#12-代码地址)** - -### 1.1 论文地址 -[ResNet34论文](https://arxiv.org/pdf/1512.03385.pdf) - -### 1.2 代码地址 -[ResNet34代码](https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py) -branch:master -commit_id:7d955df73fe0e9b47f7d6c77c699324b256fc41f - -## 2 环境说明 - -- **[深度学习框架](#21-深度学习框架)** - -- **[python第三方库](#22-python第三方库)** - -### 2.1 深度学习框架 -``` -CANN 5.0.1 - -torch == 1.5.1 -torchvision == 0.6.1 -onnx == 1.9.0 -``` - -### 2.2 python第三方库 - -``` -numpy == 1.19.2 -Pillow == 8.2.0 -opencv-python == 4.5.2.52 -``` - -**说明:** -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3 模型转换 - -- **[pth转onnx模型](#31-pth转onnx模型)** - -- **[onnx转om模型](#32-onnx转om模型)** - -### 3.1 pth转onnx模型 - -1.下载pth权重文件 -[ResNet-34预训练pth权重文件](https://download.pytorch.org/models/resnet34-b627a593.pth) -``` -wget https://download.pytorch.org/models/resnet34-b627a593.pth -``` -文件MD5sum:78fe1097b28dbda1373a700020afeed9 - -2.ResNet34模型代码在torchvision里,安装torchvision,arm下需源码安装,参考torchvision官网,若安装过程报错请百度解决 -``` -git clone https://github.com/pytorch/vision -cd vision -python3.7 setup.py install -cd .. -``` -3.编写pth2onnx脚本resnet34_pth2onnx.py - - **说明:** ->注意目前ATC支持的onnx算子版本为11 - -4.执行pth2onnx脚本,生成onnx模型文件 -``` -python3.7 resnet34_pth2onnx.py ./resnet34-b627a593.pth resnet34.onnx -``` - - **模型转换要点:** ->此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 - -### 3.2 onnx转om模型 - -1.设置环境变量 -``` -source env.sh -``` -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) -``` -atc --framework=5 --model=./resnet34.onnx --output=resnet34_bs1 --input_format=NCHW --input_shape="image:1,3,224,224" --log=debug --soc_version=Ascend310 - -``` - -## 4 数据集预处理 - -- **[数据集获取](#41-数据集获取)** - -- **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - -### 4.1 数据集获取 -该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/root/datasets/imagenet/val与/root/datasets/imagenet/val_label.txt。 - -### 4.2 数据集预处理 -1.预处理脚本imagenet_torch_preprocess.py - -2.执行预处理脚本,生成数据集预处理后的bin文件 -``` -python3.7 imagenet_torch_preprocess.py resnet /root/datasets/imagenet/val ./prep_dataset -``` -### 4.3 生成数据集信息文件 -1.生成数据集信息文件脚本gen_dataset_info.py - -2.执行生成数据集信息脚本,生成数据集信息文件 -``` -python3.7 gen_dataset_info.py bin ./prep_dataset ./resnet34_prep_bin.info 224 224 -``` -第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 -## 5 离线推理 - -- **[benchmark工具概述](#51-benchmark工具概述)** - -- **[离线推理](#52-离线推理)** - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) -### 5.2 离线推理 -1.设置环境变量 -``` -source env.sh -``` -2.执行离线推理 -``` -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=resnet34_bs1.om -input_text_path=./resnet34_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False -``` -输出结果默认保存在当前目录result/dumpOutput_device{0},模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 - -## 6 精度对比 - -- **[离线推理TopN精度](#61-离线推理TopN精度)** -- **[开源TopN精度](#62-开源TopN精度)** -- **[精度对比](#63-精度对比)** - -### 6.1 离线推理TopN精度统计 - -后处理统计TopN精度 - -调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 -``` -python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /root/datasets/imagenet/val_label.txt ./ result.json -``` -第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 -查看输出结果: -``` -{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value": "73.31%"}, {"key": "Top2 accuracy", "value": "83.7%"}, {"key": "Top3 accuracy", "value": "87.72%"}, {"key": "Top4 accuracy", "value": "89.92%"}, {"key": "Top5 accuracy", "value": "91.44%"}]} -``` -经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 - -### 6.2 开源TopN精度 -[torchvision官网精度](https://pytorch.org/vision/stable/models.html) -``` -Model Acc@1 Acc@5 -ResNet-34 73.314 91.420 -``` -### 6.3 精度对比 -将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 - **精度调试:** ->没有遇到精度不达标的问题,故不需要进行精度调试 - -## 7 性能对比 - -- **[npu性能数据](#71-npu性能数据)** - -### 7.1 npu性能数据 -benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 -1.benchmark工具在整个数据集上推理获得性能数据 -batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: -``` -[e2e] throughputRate: 275.179, latency: 181700 -[data read] throughputRate: 293.361, moduleLatency: 3.40877 -[preprocess] throughputRate: 292.803, moduleLatency: 3.41527 -[infer] throughputRate: 277.19, Interface throughputRate: 503.525, moduleLatency: 2.7551 -[post] throughputRate: 277.189, moduleLatency: 3.60764 -``` -Interface throughputRate: 503.525,503.525x4=2014.1既是batch1 310单卡吞吐率 -batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: -``` -[e2e] throughputRate: 177.5, latency: 281691 -[data read] throughputRate: 181.124, moduleLatency: 5.52107 -[preprocess] throughputRate: 180.841, moduleLatency: 5.52973 -[infer] throughputRate: 178.082, Interface throughputRate: 938.992, moduleLatency: 2.53232 -[post] throughputRate: 11.1299, moduleLatency: 89.8479 -``` -Interface throughputRate: 938.992,938.992x4=3755.968既是batch16 310单卡吞吐率 -batch4的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_4_device_1.txt: -``` -[e2e] throughputRate: 238.247, latency: 209866 -[data read] throughputRate: 251.629, moduleLatency: 3.97411 -[preprocess] throughputRate: 251.149, moduleLatency: 3.98169 -[infer] throughputRate: 239.788, Interface throughputRate: 672.405, moduleLatency: 3.026 -[post] throughputRate: 59.9466, moduleLatency: 16.6815 -``` -Interface throughputRate: 672.405,672.405x4=2689.62既是batch4 310单卡吞吐率 -batch8的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_8_device_1.txt: -``` -[e2e] throughputRate: 223.522, latency: 223692 -[data read] throughputRate: 233.498, moduleLatency: 4.28269 -[preprocess] throughputRate: 233.151, moduleLatency: 4.28906 -[infer] throughputRate: 224.317, Interface throughputRate: 884.554, moduleLatency: 2.62576 -[post] throughputRate: 28.0393, moduleLatency: 35.6643 -``` -Interface throughputRate: 884.554,884.554x4=3538.216既是batch8 310单卡吞吐率 -batch32的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_32_device_1.txt: -``` -[e2e] throughputRate: 200.951, latency: 248817 -[data read] throughputRate: 209.207, moduleLatency: 4.77995 -[preprocess] throughputRate: 208.778, moduleLatency: 4.78978 -[infer] throughputRate: 202.034, Interface throughputRate: 875.835, moduleLatency: 2.617 -[post] throughputRate: 6.31544, moduleLatency: 158.342 - - -``` -Interface throughputRate: 875.835,875.835x4=3503.34既是batch32 310单卡吞吐率 - - **性能优化:** ->没有遇到性能不达标的问题,故不需要进行性能优化 - +# ResNet34 Onnx模型端到端推理指导 +- [1 模型概述](#1-模型概述) + - [1.1 论文地址](#11-论文地址) + - [1.2 代码地址](#12-代码地址) +- [2 环境说明](#2-环境说明) + - [2.1 深度学习框架](#21-深度学习框架) + - [2.2 python第三方库](#22-python第三方库) +- [3 模型转换](#3-模型转换) + - [3.1 pth转onnx模型](#31-pth转onnx模型) + - [3.2 onnx转om模型](#32-onnx转om模型) +- [4 数据集预处理](#4-数据集预处理) + - [4.1 数据集获取](#41-数据集获取) + - [4.2 数据集预处理](#42-数据集预处理) + - [4.3 生成数据集信息文件](#43-生成数据集信息文件) +- [5 离线推理](#5-离线推理) + - [5.1 benchmark工具概述](#51-benchmark工具概述) + - [5.2 离线推理](#52-离线推理) +- [6 精度对比](#6-精度对比) + - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) + - [6.2 开源TopN精度](#62-开源TopN精度) + - [6.3 精度对比](#63-精度对比) +- [7 性能对比](#7-性能对比) + - [7.1 npu性能数据](#71-npu性能数据) + + +## 1 模型概述 + +- **[论文地址](#11-论文地址)** + +- **[代码地址](#12-代码地址)** + +### 1.1 论文地址 +[ResNet34论文](https://arxiv.org/pdf/1512.03385.pdf) + +### 1.2 代码地址 +[ResNet34代码](https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py) +branch:master +commit_id:7d955df73fe0e9b47f7d6c77c699324b256fc41f + +## 2 环境说明 + +- **[深度学习框架](#21-深度学习框架)** + +- **[python第三方库](#22-python第三方库)** + +### 2.1 深度学习框架 +``` +CANN 5.0.1 + +torch == 1.5.1 +torchvision == 0.6.1 +onnx == 1.9.0 +``` + +### 2.2 python第三方库 + +``` +numpy == 1.19.2 +Pillow == 8.2.0 +opencv-python == 4.5.2.52 +``` + +**说明:** +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3 模型转换 + +- **[pth转onnx模型](#31-pth转onnx模型)** + +- **[onnx转om模型](#32-onnx转om模型)** + +### 3.1 pth转onnx模型 + +1.下载pth权重文件 +[ResNet-34预训练pth权重文件](https://download.pytorch.org/models/resnet34-b627a593.pth) +``` +wget https://download.pytorch.org/models/resnet34-b627a593.pth +``` +文件MD5sum:78fe1097b28dbda1373a700020afeed9 + +2.ResNet34模型代码在torchvision里,安装torchvision,arm下需源码安装,参考torchvision官网,若安装过程报错请百度解决 +``` +git clone https://github.com/pytorch/vision +cd vision +python3.7 setup.py install +cd .. +``` +3.编写pth2onnx脚本resnet34_pth2onnx.py + + **说明:** +>注意目前ATC支持的onnx算子版本为11 + +4.执行pth2onnx脚本,生成onnx模型文件 +``` +python3.7 resnet34_pth2onnx.py ./resnet34-b627a593.pth resnet34.onnx +``` + + **模型转换要点:** +>此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 + +### 3.2 onnx转om模型 + +1.设置环境变量 +``` +source env.sh +``` +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) +``` +atc --framework=5 --model=./resnet34.onnx --output=resnet34_bs1 --input_format=NCHW --input_shape="image:1,3,224,224" --log=debug --soc_version=Ascend310 + +``` + +## 4 数据集预处理 + +- **[数据集获取](#41-数据集获取)** + +- **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + +### 4.1 数据集获取 +该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/root/datasets/imagenet/val与/root/datasets/imagenet/val_label.txt。 + +### 4.2 数据集预处理 +1.预处理脚本imagenet_torch_preprocess.py + +2.执行预处理脚本,生成数据集预处理后的bin文件 +``` +python3.7 imagenet_torch_preprocess.py resnet /root/datasets/imagenet/val ./prep_dataset +``` +### 4.3 生成数据集信息文件 +1.生成数据集信息文件脚本gen_dataset_info.py + +2.执行生成数据集信息脚本,生成数据集信息文件 +``` +python3.7 gen_dataset_info.py bin ./prep_dataset ./resnet34_prep_bin.info 224 224 +``` +第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 +## 5 离线推理 + +- **[benchmark工具概述](#51-benchmark工具概述)** + +- **[离线推理](#52-离线推理)** + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) +### 5.2 离线推理 +1.设置环境变量 +``` +source env.sh +``` +2.执行离线推理 +``` +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=resnet34_bs1.om -input_text_path=./resnet34_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False +``` +输出结果默认保存在当前目录result/dumpOutput_device{0},模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 + +## 6 精度对比 + +- **[离线推理TopN精度](#61-离线推理TopN精度)** +- **[开源TopN精度](#62-开源TopN精度)** +- **[精度对比](#63-精度对比)** + +### 6.1 离线推理TopN精度统计 + +后处理统计TopN精度 + +调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 +``` +python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /root/datasets/imagenet/val_label.txt ./ result.json +``` +第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 +查看输出结果: +``` +{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value": "73.31%"}, {"key": "Top2 accuracy", "value": "83.7%"}, {"key": "Top3 accuracy", "value": "87.72%"}, {"key": "Top4 accuracy", "value": "89.92%"}, {"key": "Top5 accuracy", "value": "91.44%"}]} +``` +经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 + +### 6.2 开源TopN精度 +[torchvision官网精度](https://pytorch.org/vision/stable/models.html) +``` +Model Acc@1 Acc@5 +ResNet-34 73.314 91.420 +``` +### 6.3 精度对比 +将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 + **精度调试:** +>没有遇到精度不达标的问题,故不需要进行精度调试 + +## 7 性能对比 + +- **[npu性能数据](#71-npu性能数据)** + +### 7.1 npu性能数据 +benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 +1.benchmark工具在整个数据集上推理获得性能数据 +batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: +``` +[e2e] throughputRate: 275.179, latency: 181700 +[data read] throughputRate: 293.361, moduleLatency: 3.40877 +[preprocess] throughputRate: 292.803, moduleLatency: 3.41527 +[infer] throughputRate: 277.19, Interface throughputRate: 503.525, moduleLatency: 2.7551 +[post] throughputRate: 277.189, moduleLatency: 3.60764 +``` +Interface throughputRate: 503.525,503.525x4=2014.1既是batch1 310单卡吞吐率 +batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: +``` +[e2e] throughputRate: 177.5, latency: 281691 +[data read] throughputRate: 181.124, moduleLatency: 5.52107 +[preprocess] throughputRate: 180.841, moduleLatency: 5.52973 +[infer] throughputRate: 178.082, Interface throughputRate: 938.992, moduleLatency: 2.53232 +[post] throughputRate: 11.1299, moduleLatency: 89.8479 +``` +Interface throughputRate: 938.992,938.992x4=3755.968既是batch16 310单卡吞吐率 +batch4的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_4_device_1.txt: +``` +[e2e] throughputRate: 238.247, latency: 209866 +[data read] throughputRate: 251.629, moduleLatency: 3.97411 +[preprocess] throughputRate: 251.149, moduleLatency: 3.98169 +[infer] throughputRate: 239.788, Interface throughputRate: 672.405, moduleLatency: 3.026 +[post] throughputRate: 59.9466, moduleLatency: 16.6815 +``` +Interface throughputRate: 672.405,672.405x4=2689.62既是batch4 310单卡吞吐率 +batch8的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_8_device_1.txt: +``` +[e2e] throughputRate: 223.522, latency: 223692 +[data read] throughputRate: 233.498, moduleLatency: 4.28269 +[preprocess] throughputRate: 233.151, moduleLatency: 4.28906 +[infer] throughputRate: 224.317, Interface throughputRate: 884.554, moduleLatency: 2.62576 +[post] throughputRate: 28.0393, moduleLatency: 35.6643 +``` +Interface throughputRate: 884.554,884.554x4=3538.216既是batch8 310单卡吞吐率 +batch32的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_32_device_1.txt: +``` +[e2e] throughputRate: 200.951, latency: 248817 +[data read] throughputRate: 209.207, moduleLatency: 4.77995 +[preprocess] throughputRate: 208.778, moduleLatency: 4.78978 +[infer] throughputRate: 202.034, Interface throughputRate: 875.835, moduleLatency: 2.617 +[post] throughputRate: 6.31544, moduleLatency: 158.342 + + +``` +Interface throughputRate: 875.835,875.835x4=3503.34既是batch32 310单卡吞吐率 + + **性能优化:** +>没有遇到性能不达标的问题,故不需要进行性能优化 + diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet34/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/classfication/ResNet34/gen_dataset_info.py index 61450b4410..5381839f65 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet34/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet34/gen_dataset_info.py @@ -1,61 +1,61 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' - get_jpg_info(file_path, info_name) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' + get_jpg_info(file_path, info_name) + diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet34/imagenet_acc_eval.py b/ACL_PyTorch/contrib/cv/classfication/ResNet34/imagenet_acc_eval.py index 362f2484e8..583340a19f 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet34/imagenet_acc_eval.py +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet34/imagenet_acc_eval.py @@ -1,184 +1,184 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - if data == '': - n_label = 0 - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = 0 - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - - resCnt = min(len(sort_index), topn) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) - print("Time used:", elapsed) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + if data == '': + n_label = 0 + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = 0 + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + + resCnt = min(len(sort_index), topn) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) + print("Time used:", elapsed) + diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet34/imagenet_torch_preprocess.py b/ACL_PyTorch/contrib/cv/classfication/ResNet34/imagenet_torch_preprocess.py index 1ab60b54dd..a99dd271d0 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet34/imagenet_torch_preprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet34/imagenet_torch_preprocess.py @@ -1,117 +1,117 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -from PIL import Image -import numpy as np -import multiprocessing - - -model_config = { - 'resnet': { - 'resize': 256, - 'centercrop': 224, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv3': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv4': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.5, 0.5, 0.5], - 'std': [0.5, 0.5, 0.5], - }, -} - - -def center_crop(img, output_size): - if isinstance(output_size, int): - output_size = (int(output_size), int(output_size)) - image_width, image_height = img.size - crop_height, crop_width = output_size - crop_top = int(round((image_height - crop_height) / 2.)) - crop_left = int(round((image_width - crop_width) / 2.)) - return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) - - -def resize(img, size, interpolation=Image.BILINEAR): - if isinstance(size, int): - w, h = img.size - if (w <= h and w == size) or (h <= w and h == size): - return img - if w < h: - ow = size - oh = int(size * h / w) - return img.resize((ow, oh), interpolation) - else: - oh = size - ow = int(size * w / h) - return img.resize((ow, oh), interpolation) - else: - return img.resize(size[::-1], interpolation) - - -def gen_input_bin(mode_type, file_batches, batch): - i = 0 - for file in file_batches[batch]: - i = i + 1 - print("batch", batch, file, "===", i) - - # RGBA to RGB - image = Image.open(os.path.join(src_path, file)).convert('RGB') - image = resize(image, model_config[mode_type]['resize']) # Resize - image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop - img = np.array(image, dtype=np.float32) - img = img.transpose(2, 0, 1) # ToTensor: HWC -> CHW - img = img / 255. # ToTensor: div 255 - img -= np.array(model_config[mode_type]['mean'], dtype=np.float32)[:, None, None] # Normalize: mean - img /= np.array(model_config[mode_type]['std'], dtype=np.float32)[:, None, None] # Normalize: std - img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) - - -def preprocess(mode_type, src_path, save_path): - files = os.listdir(src_path) - file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] - thread_pool = multiprocessing.Pool(len(file_batches)) - for batch in range(len(file_batches)): - thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) - thread_pool.close() - thread_pool.join() - print("in thread, except will not report! please ensure bin files generated.") - - -if __name__ == '__main__': - if len(sys.argv) < 4: - raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") - mode_type = sys.argv[1] - src_path = sys.argv[2] - save_path = sys.argv[3] - src_path = os.path.realpath(src_path) - save_path = os.path.realpath(save_path) - if mode_type not in model_config: - model_type_help = "model type: " - for key in model_config.keys(): - model_type_help += key - model_type_help += ' ' - raise Exception(model_type_help) - if not os.path.isdir(save_path): - os.makedirs(os.path.realpath(save_path)) - preprocess(mode_type, src_path, save_path) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +from PIL import Image +import numpy as np +import multiprocessing + + +model_config = { + 'resnet': { + 'resize': 256, + 'centercrop': 224, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv3': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv4': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.5, 0.5, 0.5], + 'std': [0.5, 0.5, 0.5], + }, +} + + +def center_crop(img, output_size): + if isinstance(output_size, int): + output_size = (int(output_size), int(output_size)) + image_width, image_height = img.size + crop_height, crop_width = output_size + crop_top = int(round((image_height - crop_height) / 2.)) + crop_left = int(round((image_width - crop_width) / 2.)) + return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) + + +def resize(img, size, interpolation=Image.BILINEAR): + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def gen_input_bin(mode_type, file_batches, batch): + i = 0 + for file in file_batches[batch]: + i = i + 1 + print("batch", batch, file, "===", i) + + # RGBA to RGB + image = Image.open(os.path.join(src_path, file)).convert('RGB') + image = resize(image, model_config[mode_type]['resize']) # Resize + image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop + img = np.array(image, dtype=np.float32) + img = img.transpose(2, 0, 1) # ToTensor: HWC -> CHW + img = img / 255. # ToTensor: div 255 + img -= np.array(model_config[mode_type]['mean'], dtype=np.float32)[:, None, None] # Normalize: mean + img /= np.array(model_config[mode_type]['std'], dtype=np.float32)[:, None, None] # Normalize: std + img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) + + +def preprocess(mode_type, src_path, save_path): + files = os.listdir(src_path) + file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] + thread_pool = multiprocessing.Pool(len(file_batches)) + for batch in range(len(file_batches)): + thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) + thread_pool.close() + thread_pool.join() + print("in thread, except will not report! please ensure bin files generated.") + + +if __name__ == '__main__': + if len(sys.argv) < 4: + raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") + mode_type = sys.argv[1] + src_path = sys.argv[2] + save_path = sys.argv[3] + src_path = os.path.realpath(src_path) + save_path = os.path.realpath(save_path) + if mode_type not in model_config: + model_type_help = "model type: " + for key in model_config.keys(): + model_type_help += key + model_type_help += ' ' + raise Exception(model_type_help) + if not os.path.isdir(save_path): + os.makedirs(os.path.realpath(save_path)) + preprocess(mode_type, src_path, save_path) + diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet34/requirements.txt b/ACL_PyTorch/contrib/cv/classfication/ResNet34/requirements.txt index 0fd8899267..a32f45720f 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet34/requirements.txt +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet34/requirements.txt @@ -1,6 +1,6 @@ -torch == 1.5.1 -torchvision == 0.6.1 -onnx == 1.9.0 -numpy == 1.19.2 -Pillow == 8.2.0 +torch == 1.5.1 +torchvision == 0.6.1 +onnx == 1.9.0 +numpy == 1.19.2 +Pillow == 8.2.0 opencv-python == 4.5.2.52 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet34/resnet34_pth2onnx.py b/ACL_PyTorch/contrib/cv/classfication/ResNet34/resnet34_pth2onnx.py index 45bd8bd56c..b0c2e06f25 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet34/resnet34_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet34/resnet34_pth2onnx.py @@ -1,35 +1,35 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -import torch -import torch.onnx -import torchvision.models as models - -def pth2onnx(input_file, output_file): - model = models.resnet34(pretrained=False) - checkpoint = torch.load(input_file, map_location=None) - model.load_state_dict(checkpoint) - - model.eval() - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.randn(1, 3, 224, 224) - torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=True, opset_version=11) - -if __name__ == "__main__": - input_file = sys.argv[1] - output_file = sys.argv[2] - pth2onnx(input_file, output_file) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +import torch +import torch.onnx +import torchvision.models as models + +def pth2onnx(input_file, output_file): + model = models.resnet34(pretrained=False) + checkpoint = torch.load(input_file, map_location=None) + model.load_state_dict(checkpoint) + + model.eval() + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.randn(1, 3, 224, 224) + torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=True, opset_version=11) + +if __name__ == "__main__": + input_file = sys.argv[1] + output_file = sys.argv[2] + pth2onnx(input_file, output_file) diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet34/test/README.md b/ACL_PyTorch/contrib/cv/classfication/ResNet34/test/README.md index 4000a70540..93ff0c492f 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet34/test/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet34/test/README.md @@ -1,29 +1,29 @@ -环境准备: - -1.数据集路径 -数据集统一放在/root/datasets/或/opt/npu/ -本模型数据集放在/root/datasets/ - -2.进入工作目录 -cd ResNet34 - -3.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -pip3.7 install -r requirements.txt - -4.获取模型代码 -git clone https://github.com/pytorch/vision - -5.如果模型代码需要安装,则安装模型代码 -cd vision -python3.7 setup.py install -cd .. - -6.获取权重文件 -wget https://download.pytorch.org/models/resnet34-b627a593.pth - -7.获取benchmark工具 -将benchmark.x86_64放在当前目录 - -8.310上执行,执行时确保device空闲 -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets +环境准备: + +1.数据集路径 +数据集统一放在/root/datasets/或/opt/npu/ +本模型数据集放在/root/datasets/ + +2.进入工作目录 +cd ResNet34 + +3.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +pip3.7 install -r requirements.txt + +4.获取模型代码 +git clone https://github.com/pytorch/vision + +5.如果模型代码需要安装,则安装模型代码 +cd vision +python3.7 setup.py install +cd .. + +6.获取权重文件 +wget https://download.pytorch.org/models/resnet34-b627a593.pth + +7.获取benchmark工具 +将benchmark.x86_64放在当前目录 + +8.310上执行,执行时确保device空闲 +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNet34/test/parse.py b/ACL_PyTorch/contrib/cv/classfication/ResNet34/test/parse.py index a0f253b055..27eae0d0ac 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNet34/test/parse.py +++ b/ACL_PyTorch/contrib/cv/classfication/ResNet34/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/ResNext101_32x8d/README.md b/ACL_PyTorch/contrib/cv/classfication/ResNext101_32x8d/README.md index 174206b05d..289a13ea50 100644 --- a/ACL_PyTorch/contrib/cv/classfication/ResNext101_32x8d/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/ResNext101_32x8d/README.md @@ -1,288 +1,288 @@ -# ResNext101_32x8d Onnx模型端到端推理指导 - -- [1 模型概述](#1-模型概述) - - [1.1 论文地址](#11-论文地址) - - [1.2 代码地址](#12-代码地址) -- [2 环境说明](#2-环境说明) - - [2.1 深度学习框架](#21-深度学习框架) - - [2.2 python第三方库](#22-python第三方库) -- [3 模型转换](#3-模型转换) - - [3.1 pth转onnx模型](#31-pth转onnx模型) - - [3.2 onnx转om模型](#32-onnx转om模型) -- [4 数据集预处理](#4-数据集预处理) - - [4.1 数据集获取](#41-数据集获取) - - [4.2 数据集预处理](#42-数据集预处理) - - [4.3 生成数据集信息文件](#43-生成数据集信息文件) -- [5 离线推理](#5-离线推理) - - [5.1 benchmark工具概述](#51-benchmark工具概述) - - [5.2 离线推理](#52-离线推理) -- [6 精度对比](#6-精度对比) - - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) - - [6.2 开源TopN精度](#62-开源TopN精度) - - [6.3 精度对比](#63-精度对比) -- [7 性能对比](#7-性能对比) - - [7.1 npu性能数据](#71-npu性能数据) - - - -## 1 模型概述 - -- **[论文地址](#11-论文地址)** - -- **[代码地址](#12-代码地址)** - -### 1.1 论文地址 - -[ResNext101_32x8d论文](https://arxiv.org/pdf/1611.05431.pdf) - -### 1.2 代码地址 - -[ResNext101_32x8d代码](https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py) - -branch:master commit_id:7d955df73fe0e9b47f7d6c77c699324b256fc41f - -## 2 环境说明 - -- **[深度学习框架](#21-深度学习框架)** - -- **[python第三方库](#22-python第三方库)** - -### 2.1 深度学习框架 - -``` -CANN 5.0.1 - -torch == 1.5.1 -torchvision == 0.6.1 -onnx == 1.9.0 -``` - -### 2.2 python第三方库 - -``` -numpy == 1.20.3 -Pillow == 8.2.0 -opencv-python == 4.5.2 -``` - -**说明:** - -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - - - -## 3 模型转换 - -- **[pth转onnx模型](#31-pth转onnx模型)** - -- **[onnx转om模型](#32-onnx转om模型)** - -### 3.1 pth转onnx模型 - -1.下载pth权重文件 -[ResNext101_32x8d 预训练pth权重文件](https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pth) - -``` -wget https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pth -``` - -文件MD5sum:4454a42689454b94296e378762f2333f - -3.编写pth2onnx脚本resnext101_32x8d_pth2onnx.py - - **说明:** - ->注意目前ATC支持的onnx算子版本为11 - -4.执行pth2onnx脚本,生成onnx模型文件 - -``` -python3.7 resnext101_32x8d_pth2onnx.py ./resnext101_32x8d-8ba56ff5.pth resnext101_32x8d.onnx -``` - - **模型转换要点:** - ->此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 - -### 3.2 onnx转om模型 - -1.设置环境变量 - -``` -source env.sh -``` - -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) - -``` -atc --framework=5 --model=./resnext101_32x8d.onnx --output=resnext101_32x8d_bs1 --input_format=NCHW --input_shape="image:1,3,224,224" --log=debug --soc_version=Ascend310 - -``` - -## 4 数据集预处理 - -- **[数据集获取](#41-数据集获取)** - -- **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - -### 4.1 数据集获取 - -该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/root/datasets/imagenet/val与/root/datasets/imagenet/val_label.txt。 - -### 4.2 数据集预处理 - -1.预处理脚本imagenet_torch_preprocess.py - -2.执行预处理脚本,生成数据集预处理后的bin文件 - -``` -python3.7 imagenet_torch_preprocess.py resnet /root/datasets/imagenet/val ./prep_dataset -``` - -### 4.3 生成数据集信息文件 - -1.生成数据集信息文件脚本gen_dataset_info.py - -2.执行生成数据集信息脚本,生成数据集信息文件 - -``` -python3.7 gen_dataset_info.py bin ./prep_dataset ./resnext101_32x8d.info 224 224 -``` - -第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 - -## 5 离线推理 - -- **[benchmark工具概述](#51-benchmark工具概述)** - -- **[离线推理](#52-离线推理)** - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) - -### 5.2 离线推理 - -1.设置环境变量 - -``` -source env.sh -``` - -2.执行离线推理 - -``` -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=resnext101_32x8d_bs1.om -input_text_path=./resnext101_32x8d.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False -``` - -输出结果默认保存在当前目录result/dumpOutput_device{0},模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 - -## 6 精度对比 - -- **[离线推理TopN精度](#61-离线推理TopN精度)** -- **[开源TopN精度](#62-开源TopN精度)** -- **[精度对比](#63-精度对比)** - -### 6.1 离线推理TopN精度统计 - -后处理统计TopN精度 - -调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 - -``` -python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /root/datasets/imagenet/val_label.txt ./ result.json -``` - -第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 -查看输出结果: - -``` -{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"},{"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value": "79.31%"}, {"key": "Top2 accuracy", "value": "88.68%"}, {"key": "Top3 accuracy", "value": "91.83%"}, {"key": "Top4 accuracy", "value": "93.47%"}, {"key": "Top5 accuracy", "value": "94.52%"}]} -``` - -经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 - -### 6.2 开源TopN精度 - -[torchvision官网精度](https://pytorch.org/vision/stable/models.html) - -``` -Model Acc@1 Acc@5ResNeXt-101-32x8d 79.312 94.526 -``` - -### 6.3 精度对比 - -将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 - **精度调试:** - ->没有遇到精度不达标的问题,故不需要进行精度调试 - -## 7 性能对比 - -- **[npu性能数据](#71-npu性能数据)** - -### 7.1 npu性能数据 - -benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 -1.benchmark工具在整个数据集上推理获得性能数据 -batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: - -``` -[e2e] throughputRate: 113.043, latency: 442310[data read] throughputRate: 119.766, moduleLatency: 8.34965[preprocess] throughputRate: 119.219, moduleLatency: 8.38793[infer] throughputRate: 113.375, Interface throughputRate: 144.766, moduleLatency: 8.19887[post] throughputRate: 113.375, moduleLatency: 8.82032 -``` - -Interface throughputRate: 144.766,144.766x4=579.064既是batch1 310单卡吞吐率 -batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: - -``` -[e2e] throughputRate: 116.034, latency: 430908[data read] throughputRate: 122.878, moduleLatency: 8.13815[preprocess] throughputRate: 122.393, moduleLatency: 8.17039[infer] throughputRate: 116.288, Interface throughputRate: 165.952, moduleLatency: 7.47516[post] throughputRate: 7.2679, moduleLatency: 137.591 -``` - -Interface throughputRate: 165.952,165.952x4=663.808既是batch16 310单卡吞吐率 - - - -batch4的性能,使用benchmark工具进行纯推理,推理后生成result/PureInfer_perf_of_resnext101_32x8d_bs4_in_device_0.txt: - -``` -./benchmark.x86_64 -round=20 -om_path=resnext101_32x8d_bs4.om -device_id=0 -batch_size=4 -``` - - - -``` -ave_throughputRate = 167.46samples/s, ave_latency = 6.02002ms -``` - -ave_throughputRate: 167.46,167.46x4=669.84既是batch4 310单卡吞吐率 - - - -batch8的性能,使用benchmark工具进行纯推理,推理后生成result/PureInfer_perf_of_resnext101_32x8d_bs8_in_device_0.txt: - - - -``` -ave_throughputRate = 167.521samples/s, ave_latency = 5.9993ms -``` - -ave_throughputRate: 167.521,167.521x4=670.084既是batch8 310单卡吞吐率 - - - -batch32的性能,使用benchmark工具进行纯推理,推理后生成result/PureInfer_perf_of_resnext101_32x8d_bs32_in_device_0.txt: - -``` -ave_throughputRate = 108.28samples/s, ave_latency = 9.24227ms -``` - -ave_throughputRate: 108.28,108.28x4=433.12既是batch32 310单卡吞吐率 - - **性能优化:** - -对于batch32的性能不达标,从profiling数据的op_statistic_0_1.csv看出影响性能的是Conv2D算子,从op_summary_0_1.csv看出单个Conv_Relu算子aicore耗时0.6毫秒到6毫秒,shape大的耗时就多,不存在优化问题。 - +# ResNext101_32x8d Onnx模型端到端推理指导 + +- [1 模型概述](#1-模型概述) + - [1.1 论文地址](#11-论文地址) + - [1.2 代码地址](#12-代码地址) +- [2 环境说明](#2-环境说明) + - [2.1 深度学习框架](#21-深度学习框架) + - [2.2 python第三方库](#22-python第三方库) +- [3 模型转换](#3-模型转换) + - [3.1 pth转onnx模型](#31-pth转onnx模型) + - [3.2 onnx转om模型](#32-onnx转om模型) +- [4 数据集预处理](#4-数据集预处理) + - [4.1 数据集获取](#41-数据集获取) + - [4.2 数据集预处理](#42-数据集预处理) + - [4.3 生成数据集信息文件](#43-生成数据集信息文件) +- [5 离线推理](#5-离线推理) + - [5.1 benchmark工具概述](#51-benchmark工具概述) + - [5.2 离线推理](#52-离线推理) +- [6 精度对比](#6-精度对比) + - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) + - [6.2 开源TopN精度](#62-开源TopN精度) + - [6.3 精度对比](#63-精度对比) +- [7 性能对比](#7-性能对比) + - [7.1 npu性能数据](#71-npu性能数据) + + + +## 1 模型概述 + +- **[论文地址](#11-论文地址)** + +- **[代码地址](#12-代码地址)** + +### 1.1 论文地址 + +[ResNext101_32x8d论文](https://arxiv.org/pdf/1611.05431.pdf) + +### 1.2 代码地址 + +[ResNext101_32x8d代码](https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py) + +branch:master commit_id:7d955df73fe0e9b47f7d6c77c699324b256fc41f + +## 2 环境说明 + +- **[深度学习框架](#21-深度学习框架)** + +- **[python第三方库](#22-python第三方库)** + +### 2.1 深度学习框架 + +``` +CANN 5.0.1 + +torch == 1.5.1 +torchvision == 0.6.1 +onnx == 1.9.0 +``` + +### 2.2 python第三方库 + +``` +numpy == 1.20.3 +Pillow == 8.2.0 +opencv-python == 4.5.2 +``` + +**说明:** + +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + + + +## 3 模型转换 + +- **[pth转onnx模型](#31-pth转onnx模型)** + +- **[onnx转om模型](#32-onnx转om模型)** + +### 3.1 pth转onnx模型 + +1.下载pth权重文件 +[ResNext101_32x8d 预训练pth权重文件](https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pth) + +``` +wget https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pth +``` + +文件MD5sum:4454a42689454b94296e378762f2333f + +3.编写pth2onnx脚本resnext101_32x8d_pth2onnx.py + + **说明:** + +>注意目前ATC支持的onnx算子版本为11 + +4.执行pth2onnx脚本,生成onnx模型文件 + +``` +python3.7 resnext101_32x8d_pth2onnx.py ./resnext101_32x8d-8ba56ff5.pth resnext101_32x8d.onnx +``` + + **模型转换要点:** + +>此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 + +### 3.2 onnx转om模型 + +1.设置环境变量 + +``` +source env.sh +``` + +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) + +``` +atc --framework=5 --model=./resnext101_32x8d.onnx --output=resnext101_32x8d_bs1 --input_format=NCHW --input_shape="image:1,3,224,224" --log=debug --soc_version=Ascend310 + +``` + +## 4 数据集预处理 + +- **[数据集获取](#41-数据集获取)** + +- **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + +### 4.1 数据集获取 + +该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/root/datasets/imagenet/val与/root/datasets/imagenet/val_label.txt。 + +### 4.2 数据集预处理 + +1.预处理脚本imagenet_torch_preprocess.py + +2.执行预处理脚本,生成数据集预处理后的bin文件 + +``` +python3.7 imagenet_torch_preprocess.py resnet /root/datasets/imagenet/val ./prep_dataset +``` + +### 4.3 生成数据集信息文件 + +1.生成数据集信息文件脚本gen_dataset_info.py + +2.执行生成数据集信息脚本,生成数据集信息文件 + +``` +python3.7 gen_dataset_info.py bin ./prep_dataset ./resnext101_32x8d.info 224 224 +``` + +第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 + +## 5 离线推理 + +- **[benchmark工具概述](#51-benchmark工具概述)** + +- **[离线推理](#52-离线推理)** + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) + +### 5.2 离线推理 + +1.设置环境变量 + +``` +source env.sh +``` + +2.执行离线推理 + +``` +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=resnext101_32x8d_bs1.om -input_text_path=./resnext101_32x8d.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False +``` + +输出结果默认保存在当前目录result/dumpOutput_device{0},模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 + +## 6 精度对比 + +- **[离线推理TopN精度](#61-离线推理TopN精度)** +- **[开源TopN精度](#62-开源TopN精度)** +- **[精度对比](#63-精度对比)** + +### 6.1 离线推理TopN精度统计 + +后处理统计TopN精度 + +调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 + +``` +python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /root/datasets/imagenet/val_label.txt ./ result.json +``` + +第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 +查看输出结果: + +``` +{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"},{"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value": "79.31%"}, {"key": "Top2 accuracy", "value": "88.68%"}, {"key": "Top3 accuracy", "value": "91.83%"}, {"key": "Top4 accuracy", "value": "93.47%"}, {"key": "Top5 accuracy", "value": "94.52%"}]} +``` + +经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 + +### 6.2 开源TopN精度 + +[torchvision官网精度](https://pytorch.org/vision/stable/models.html) + +``` +Model Acc@1 Acc@5ResNeXt-101-32x8d 79.312 94.526 +``` + +### 6.3 精度对比 + +将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 + **精度调试:** + +>没有遇到精度不达标的问题,故不需要进行精度调试 + +## 7 性能对比 + +- **[npu性能数据](#71-npu性能数据)** + +### 7.1 npu性能数据 + +benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 +1.benchmark工具在整个数据集上推理获得性能数据 +batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: + +``` +[e2e] throughputRate: 113.043, latency: 442310[data read] throughputRate: 119.766, moduleLatency: 8.34965[preprocess] throughputRate: 119.219, moduleLatency: 8.38793[infer] throughputRate: 113.375, Interface throughputRate: 144.766, moduleLatency: 8.19887[post] throughputRate: 113.375, moduleLatency: 8.82032 +``` + +Interface throughputRate: 144.766,144.766x4=579.064既是batch1 310单卡吞吐率 +batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: + +``` +[e2e] throughputRate: 116.034, latency: 430908[data read] throughputRate: 122.878, moduleLatency: 8.13815[preprocess] throughputRate: 122.393, moduleLatency: 8.17039[infer] throughputRate: 116.288, Interface throughputRate: 165.952, moduleLatency: 7.47516[post] throughputRate: 7.2679, moduleLatency: 137.591 +``` + +Interface throughputRate: 165.952,165.952x4=663.808既是batch16 310单卡吞吐率 + + + +batch4的性能,使用benchmark工具进行纯推理,推理后生成result/PureInfer_perf_of_resnext101_32x8d_bs4_in_device_0.txt: + +``` +./benchmark.x86_64 -round=20 -om_path=resnext101_32x8d_bs4.om -device_id=0 -batch_size=4 +``` + + + +``` +ave_throughputRate = 167.46samples/s, ave_latency = 6.02002ms +``` + +ave_throughputRate: 167.46,167.46x4=669.84既是batch4 310单卡吞吐率 + + + +batch8的性能,使用benchmark工具进行纯推理,推理后生成result/PureInfer_perf_of_resnext101_32x8d_bs8_in_device_0.txt: + + + +``` +ave_throughputRate = 167.521samples/s, ave_latency = 5.9993ms +``` + +ave_throughputRate: 167.521,167.521x4=670.084既是batch8 310单卡吞吐率 + + + +batch32的性能,使用benchmark工具进行纯推理,推理后生成result/PureInfer_perf_of_resnext101_32x8d_bs32_in_device_0.txt: + +``` +ave_throughputRate = 108.28samples/s, ave_latency = 9.24227ms +``` + +ave_throughputRate: 108.28,108.28x4=433.12既是batch32 310单卡吞吐率 + + **性能优化:** + +对于batch32的性能不达标,从profiling数据的op_statistic_0_1.csv看出影响性能的是Conv2D算子,从op_summary_0_1.csv看出单个Conv_Relu算子aicore耗时0.6毫秒到6毫秒,shape大的耗时就多,不存在优化问题。 + diff --git a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/LICENSE b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/README.md b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/README.md index e6c3abbd49..5566fa1abe 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/README.md @@ -1,271 +1,271 @@ - # Shufflenetv1 Onnx模型端到端推理指导 -- [1 模型概述](#1-模型概述) - - [1.1 论文地址](#11-论文地址) - - [1.2 代码地址](#12-代码地址) -- [2 环境说明](#2-环境说明) - - [2.1 深度学习框架](#21-深度学习框架) - - [2.2 python第三方库](#22-python第三方库) -- [3 模型转换](#3-模型转换) - - [3.1 pth转onnx模型](#31-pth转onnx模型) - - [3.2 onnx转om模型](#32-onnx转om模型) -- [4 数据集预处理](#4-数据集预处理) - - [4.1 数据集获取](#41-数据集获取) - - [4.2 数据集预处理](#42-数据集预处理) - - [4.3 生成数据集信息文件](#43-生成数据集信息文件) -- [5 离线推理](#5-离线推理) - - [5.1 benchmark工具概述](#51-benchmark工具概述) - - [5.2 离线推理](#52-离线推理) -- [6 精度对比](#6-精度对比) - - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) - - [6.2 开源TopN精度](#62-开源TopN精度) - - [6.3 精度对比](#63-精度对比) -- [7 性能对比](#7-性能对比) - - [7.1 npu性能数据](#71-npu性能数据) - - - - ## 1 模型概述 - - - **[论文地址](#11-论文地址)** - - - **[代码地址](#12-代码地址)** - - ### 1.1 论文地址 - [shufflenetv1论文](https://arxiv.org/pdf/1707.01083.pdf) - - ### 1.2 代码地址 - [shufflenetv1代码](https://github.com/megvii-model/ShuffleNet-Series/tree/master/ShuffleNetV1 ) - branch:master - commit_id: d69403d4b5fb3043c7c0da3c2a15df8c5e520d89 - - ## 2 环境说明 - - - **[深度学习框架](#21-深度学习框架)** - - - **[python第三方库](#22-python第三方库)** - - ### 2.1 深度学习框架 - ``` - CANN 5.0.2.alpha003 - pytorch == 1.8.0 - torchvision == 0.9.0 - onnx == 1.9.0 - ``` - - ### 2.2 python第三方库 - - ``` - numpy == 1.18.5 - Pillow == 7.2.0 - opencv-python == 4.5.1.48 - ``` - - **说明:** - > X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 - > - > Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - - ## 3 模型转换 - - - **[pth转onnx模型](#31-pth转onnx模型)** - - - **[onnx转om模型](#32-onnx转om模型)** - - ### 3.1 pth转onnx模型 - - 1.下载pth权重文件 - [Shufflenetv1预训练pth权重文件](https://pan.baidu.com/s/1EUQVoFPb74yZm0JWHKjFOw#list/path=%2F)(提取码:mc24) - 文件md5sum: bc2b8686fe73bf0709af2cbfcff2b895 - ``` - https://pan.baidu.com/s/1EUQVoFPb74yZm0JWHKjFOw#list/path=%2F - ``` -2.shufflenetv1模型代码在代码仓中 - - ``` - github上Shufflenetv1没有安装脚本,在pth2onnx脚本中引用代码仓定义的ShuffleNetv1: - - git clone https://github.com/megvii-model/ShuffleNet-Series.git - - ``` - 3.编写pth2onnx脚本shufflenetv1_pth2onnx.py - - **说明:** - >注意目前ATC支持的onnx算子版本为11 - - 4.执行pth2onnx脚本,生成onnx模型文件 - ``` - python3.7 shufflenetv1_pth2onnx_bs1.py 1.0x.pth.tar shufflenetv1_bs1.onnx - ``` - - **模型转换要点:** - >动态batch的onnx转om失败并且测的性能数据也不对,每个batch的om都需要对应batch的onnx来转换,每个batch的性能数据也需要对应batch的onnx来测 - ### 3.2 onnx转om模型 - - 1.设置环境变量 - ``` - source env.sh - ``` - 2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.2 开发辅助工具指南 (推理) 01 - ``` - atc --framework=5 --model=./shufflenetv1_bs1.onnx --input_format=NCHW --input_shape="image:1,3,224,224" --output=shufflenetv1_bs1 --log=debug --soc_version=Ascend310 - ``` - - ## 4 数据集预处理 - - - **[数据集获取](#41-数据集获取)** - - - **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - ### 4.1 数据集获取 - 该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/opt/npu/imagenet/val与/opt/npu/imagenet/val_label.txt。 - -### 4.2 数据集预处理 - 1.预处理脚本shufflenetv1_torch_preprocess.py - - 2.执行预处理脚本,生成数据集预处理后的bin文件 - ``` - python3.7 shufflenetv1_torch_preprocess.py /opt/npu/imagenet/val ./prep_dataset - ``` - ### 4.3 生成数据集信息文件 -1.生成数据集信息文件脚本get_info.py - - 2.执行生成数据集信息脚本,生成数据集信息文件 - ``` - python3.7 get_info.py bin ./prep_dataset ./shufflenetv1_prep_bin.info 224 224 - ``` - 第一个参数为生成的bin文件路径,第二个为输出的info文件,后面为宽高信息 - ## 5 离线推理 - - - **[benchmark工具概述](#51-benchmark工具概述)** - - - **[离线推理](#52-离线推理)** - - ### 5.1 benchmark工具概述 - - benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN 5.0.2 推理benchmark工具用户指南 01 - ### 5.2 离线推理 - 1.设置环境变量 - ``` - source env.sh - ``` - 2.执行离线推理 - ``` - ./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=shufflenetv1_bs1.om -input_text_path=./shufflenetv1_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False - ``` - 输出结果默认保存在当前目录result/dumpOutput_devicex,模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 - - ## 6 精度对比 - - **[离线推理TopN精度](#61-离线推理TopN精度)** - - **[开源TopN精度](#62-开源TopN精度)** - - **[精度对比](#63-精度对比)** - - ### 6.1 离线推理TopN精度统计 - - 后处理统计TopN精度 - - 调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 - ``` - python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /opt/npu/imagenet/val_label.txt ./ result.json - ``` - 第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 - 查看输出结果: - ``` - {"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value -": "67.66%"}, {"key": "Top2 accuracy", "value": "78.61%"}, {"key": "Top3 accuracy", "value": "83.29%"}, {"key": "Top4 accuracy", "value": "85.83%"}, {"key": "Top5 accuracy", "value": "87.61%"}]} - ``` - 经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 - - ### 6.2 开源TopN精度 - [开源代码仓精度](https://github.com/megvii-model/ShuffleNet-Series/tree/master/ShuffleNetV1 ) - - ``` - | model | top1 | top5 | - | --------------------------- | ---- | ---- | - | ShuffleNetV1 1.0x (group=3) | 67.8 | 87.7 | - ``` - ### 6.3 精度对比 - 将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 - **精度调试:** - >遇到精度不对,首先考虑预处理是不是没有和开源代码仓一致。 - -## 7 性能对比 - - - **[npu性能数据](#71-npu性能数据)** - - ### 7.1 npu性能数据 - benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device。为快速获取性能数据,也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准。这里给出两种方式,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 - 1.benchmark工具在整个数据集上推理获得性能数据 -batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: -``` -[e2e] throughputRate: 225.491, latency: 221739 -[data read] throughputRate: 238.623, moduleLatency: 4.19071 -[preprocess] throughputRate: 238.364, moduleLatency: 4.19526 -[infer] throughputRate: 226.585, Interface throughputRate: 392.738, moduleLatency: 3.62481 -[post] throughputRate: 226.585, moduleLatency: 4.41336 - ``` - Interface throughputRate: 392.738,392.738乘以4即是310单卡吞吐 - - batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: - - ``` -[e2e] throughputRate: 179.484, latency: 278577 -[data read] throughputRate: 185.65, moduleLatency: 5.38649 -[preprocess] throughputRate: 185.36, moduleLatency: 5.39492 -[infer] throughputRate: 180.299, Interface throughputRate: 1335.44, moduleLatency: 2.25621 -[post] throughputRate: 11.2682, moduleLatency: 88.7455 - - ``` - Interface throughputRate: 1335.44,1335.44x4既是batch16 310单卡吞吐率 - batch4性能: -./benchmark.x86_64 -round=20 -om_path=shufflenetv1_bs4.om -device_id=3 -batch_size=4 - ``` -[INFO] PureInfer result saved in ./result/PureInfer_perf_of_shufflenetv1_bs4_in_device_3.txt ------------------PureInfer Performance Summary------------------ -[INFO] ave_throughputRate: 986.58samples/s, ave_latency: 1.03751ms ----------------------------------------------------------------- - - ``` - batch4 310单卡吞吐率:986.58x4=3946.32fps - batch8性能: - - ``` -[INFO] PureInfer result saved in ./result/PureInfer_perf_of_shufflenetv1_bs8_in_device_3.txt ------------------PureInfer Performance Summary------------------ -[INFO] ave_throughputRate: 1235.73samples/s, ave_latency: 0.821675ms ----------------------------------------------------------------- - ``` - batch8 310单卡吞吐率:1235.73x4=4942.92fps - batch32性能: - - ``` - -[INFO] PureInfer result saved in ./result/PureInfer_perf_of_shufflenetv1_bs32_in_device_3.txt ------------------PureInfer Performance Summary------------------ -[INFO] ave_throughputRate: 1258.14samples/s, ave_latency: 0.795141ms ----------------------------------------------------------------- - ``` - batch32 310单卡吞吐率: 1258.14x4=5032.56fps - - **性能优化:** - 1. CANN 5.0.2.alpha003版本将PadV3D与AvgPoolV2融合提高了性能,所以基于此版本测。 - 2. 从profiling数据的op_statistic_0_1.csv看出影响性能的是Conv2D算子,TransData,Transpose算子,Conv2D算子不存在问题,由于格式转换om模型Transpose前后需要有TransData算子,从op_summary_0_1.csv可以看出单个TransData或Transpose算子aicore耗时,确定是否可以优化。 - 3. dynamic/transpose.py:68中已经通过shape白名单优化掉了TransposeD -> - five_2_four.py:9928 - 修改如下: - > elif dst_format.lower() == "nchw" and dst_shape in [[2560, 512, 4, 26], [2560, 512, 1, 26], [2560, 256, 8, 25], - [16, 240, 7, 7], [16, 120, 14, 14], - [1, 240, 7, 7], [1, 120, 14, 14], - [4, 240, 7, 7], [4, 120, 14, 14], - [8, 240, 7, 7], [8, 120, 14, 14], - [32, 240, 7, 7], [32, 120, 14, 14]]: -> - four_2_five.py:1219 - 修改如下: - > if src_format.upper() == "NCHW" and shape_input in [[16, 240, 7, 7], [16, 120, 14, 14], - [1, 240, 7, 7], [1, 120, 14, 14], - [4, 240, 7, 7], [4, 120, 14, 14], - [8, 240, 7, 7], [8, 120, 14, 14], - [32, 240, 7, 7], [32, 120, 14, 14]] and dtype_input == "float16": + # Shufflenetv1 Onnx模型端到端推理指导 +- [1 模型概述](#1-模型概述) + - [1.1 论文地址](#11-论文地址) + - [1.2 代码地址](#12-代码地址) +- [2 环境说明](#2-环境说明) + - [2.1 深度学习框架](#21-深度学习框架) + - [2.2 python第三方库](#22-python第三方库) +- [3 模型转换](#3-模型转换) + - [3.1 pth转onnx模型](#31-pth转onnx模型) + - [3.2 onnx转om模型](#32-onnx转om模型) +- [4 数据集预处理](#4-数据集预处理) + - [4.1 数据集获取](#41-数据集获取) + - [4.2 数据集预处理](#42-数据集预处理) + - [4.3 生成数据集信息文件](#43-生成数据集信息文件) +- [5 离线推理](#5-离线推理) + - [5.1 benchmark工具概述](#51-benchmark工具概述) + - [5.2 离线推理](#52-离线推理) +- [6 精度对比](#6-精度对比) + - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) + - [6.2 开源TopN精度](#62-开源TopN精度) + - [6.3 精度对比](#63-精度对比) +- [7 性能对比](#7-性能对比) + - [7.1 npu性能数据](#71-npu性能数据) + + + + ## 1 模型概述 + + - **[论文地址](#11-论文地址)** + + - **[代码地址](#12-代码地址)** + + ### 1.1 论文地址 + [shufflenetv1论文](https://arxiv.org/pdf/1707.01083.pdf) + + ### 1.2 代码地址 + [shufflenetv1代码](https://github.com/megvii-model/ShuffleNet-Series/tree/master/ShuffleNetV1 ) + branch:master + commit_id: d69403d4b5fb3043c7c0da3c2a15df8c5e520d89 + + ## 2 环境说明 + + - **[深度学习框架](#21-深度学习框架)** + + - **[python第三方库](#22-python第三方库)** + + ### 2.1 深度学习框架 + ``` + CANN 5.0.2.alpha003 + pytorch == 1.8.0 + torchvision == 0.9.0 + onnx == 1.9.0 + ``` + + ### 2.2 python第三方库 + + ``` + numpy == 1.18.5 + Pillow == 7.2.0 + opencv-python == 4.5.1.48 + ``` + + **说明:** + > X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 + > + > Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + + ## 3 模型转换 + + - **[pth转onnx模型](#31-pth转onnx模型)** + + - **[onnx转om模型](#32-onnx转om模型)** + + ### 3.1 pth转onnx模型 + + 1.下载pth权重文件 + [Shufflenetv1预训练pth权重文件](https://pan.baidu.com/s/1EUQVoFPb74yZm0JWHKjFOw#list/path=%2F)(提取码:mc24) + 文件md5sum: bc2b8686fe73bf0709af2cbfcff2b895 + ``` + https://pan.baidu.com/s/1EUQVoFPb74yZm0JWHKjFOw#list/path=%2F + ``` +2.shufflenetv1模型代码在代码仓中 + + ``` + github上Shufflenetv1没有安装脚本,在pth2onnx脚本中引用代码仓定义的ShuffleNetv1: + + git clone https://github.com/megvii-model/ShuffleNet-Series.git + + ``` + 3.编写pth2onnx脚本shufflenetv1_pth2onnx.py + + **说明:** + >注意目前ATC支持的onnx算子版本为11 + + 4.执行pth2onnx脚本,生成onnx模型文件 + ``` + python3.7 shufflenetv1_pth2onnx_bs1.py 1.0x.pth.tar shufflenetv1_bs1.onnx + ``` + + **模型转换要点:** + >动态batch的onnx转om失败并且测的性能数据也不对,每个batch的om都需要对应batch的onnx来转换,每个batch的性能数据也需要对应batch的onnx来测 + ### 3.2 onnx转om模型 + + 1.设置环境变量 + ``` + source env.sh + ``` + 2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.2 开发辅助工具指南 (推理) 01 + ``` + atc --framework=5 --model=./shufflenetv1_bs1.onnx --input_format=NCHW --input_shape="image:1,3,224,224" --output=shufflenetv1_bs1 --log=debug --soc_version=Ascend310 + ``` + + ## 4 数据集预处理 + + - **[数据集获取](#41-数据集获取)** + + - **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + ### 4.1 数据集获取 + 该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/opt/npu/imagenet/val与/opt/npu/imagenet/val_label.txt。 + +### 4.2 数据集预处理 + 1.预处理脚本shufflenetv1_torch_preprocess.py + + 2.执行预处理脚本,生成数据集预处理后的bin文件 + ``` + python3.7 shufflenetv1_torch_preprocess.py /opt/npu/imagenet/val ./prep_dataset + ``` + ### 4.3 生成数据集信息文件 +1.生成数据集信息文件脚本get_info.py + + 2.执行生成数据集信息脚本,生成数据集信息文件 + ``` + python3.7 get_info.py bin ./prep_dataset ./shufflenetv1_prep_bin.info 224 224 + ``` + 第一个参数为生成的bin文件路径,第二个为输出的info文件,后面为宽高信息 + ## 5 离线推理 + + - **[benchmark工具概述](#51-benchmark工具概述)** + + - **[离线推理](#52-离线推理)** + + ### 5.1 benchmark工具概述 + + benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN 5.0.2 推理benchmark工具用户指南 01 + ### 5.2 离线推理 + 1.设置环境变量 + ``` + source env.sh + ``` + 2.执行离线推理 + ``` + ./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=shufflenetv1_bs1.om -input_text_path=./shufflenetv1_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False + ``` + 输出结果默认保存在当前目录result/dumpOutput_devicex,模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 + + ## 6 精度对比 + - **[离线推理TopN精度](#61-离线推理TopN精度)** + - **[开源TopN精度](#62-开源TopN精度)** + - **[精度对比](#63-精度对比)** + + ### 6.1 离线推理TopN精度统计 + + 后处理统计TopN精度 + + 调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 + ``` + python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /opt/npu/imagenet/val_label.txt ./ result.json + ``` + 第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 + 查看输出结果: + ``` + {"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value +": "67.66%"}, {"key": "Top2 accuracy", "value": "78.61%"}, {"key": "Top3 accuracy", "value": "83.29%"}, {"key": "Top4 accuracy", "value": "85.83%"}, {"key": "Top5 accuracy", "value": "87.61%"}]} + ``` + 经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 + + ### 6.2 开源TopN精度 + [开源代码仓精度](https://github.com/megvii-model/ShuffleNet-Series/tree/master/ShuffleNetV1 ) + + ``` + | model | top1 | top5 | + | --------------------------- | ---- | ---- | + | ShuffleNetV1 1.0x (group=3) | 67.8 | 87.7 | + ``` + ### 6.3 精度对比 + 将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 + **精度调试:** + >遇到精度不对,首先考虑预处理是不是没有和开源代码仓一致。 + +## 7 性能对比 + + - **[npu性能数据](#71-npu性能数据)** + + ### 7.1 npu性能数据 + benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device。为快速获取性能数据,也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准。这里给出两种方式,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 + 1.benchmark工具在整个数据集上推理获得性能数据 +batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: +``` +[e2e] throughputRate: 225.491, latency: 221739 +[data read] throughputRate: 238.623, moduleLatency: 4.19071 +[preprocess] throughputRate: 238.364, moduleLatency: 4.19526 +[infer] throughputRate: 226.585, Interface throughputRate: 392.738, moduleLatency: 3.62481 +[post] throughputRate: 226.585, moduleLatency: 4.41336 + ``` + Interface throughputRate: 392.738,392.738乘以4即是310单卡吞吐 + + batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: + + ``` +[e2e] throughputRate: 179.484, latency: 278577 +[data read] throughputRate: 185.65, moduleLatency: 5.38649 +[preprocess] throughputRate: 185.36, moduleLatency: 5.39492 +[infer] throughputRate: 180.299, Interface throughputRate: 1335.44, moduleLatency: 2.25621 +[post] throughputRate: 11.2682, moduleLatency: 88.7455 + + ``` + Interface throughputRate: 1335.44,1335.44x4既是batch16 310单卡吞吐率 + batch4性能: +./benchmark.x86_64 -round=20 -om_path=shufflenetv1_bs4.om -device_id=3 -batch_size=4 + ``` +[INFO] PureInfer result saved in ./result/PureInfer_perf_of_shufflenetv1_bs4_in_device_3.txt +-----------------PureInfer Performance Summary------------------ +[INFO] ave_throughputRate: 986.58samples/s, ave_latency: 1.03751ms +---------------------------------------------------------------- + + ``` + batch4 310单卡吞吐率:986.58x4=3946.32fps + batch8性能: + + ``` +[INFO] PureInfer result saved in ./result/PureInfer_perf_of_shufflenetv1_bs8_in_device_3.txt +-----------------PureInfer Performance Summary------------------ +[INFO] ave_throughputRate: 1235.73samples/s, ave_latency: 0.821675ms +---------------------------------------------------------------- + ``` + batch8 310单卡吞吐率:1235.73x4=4942.92fps + batch32性能: + + ``` + +[INFO] PureInfer result saved in ./result/PureInfer_perf_of_shufflenetv1_bs32_in_device_3.txt +-----------------PureInfer Performance Summary------------------ +[INFO] ave_throughputRate: 1258.14samples/s, ave_latency: 0.795141ms +---------------------------------------------------------------- + ``` + batch32 310单卡吞吐率: 1258.14x4=5032.56fps + + **性能优化:** + 1. CANN 5.0.2.alpha003版本将PadV3D与AvgPoolV2融合提高了性能,所以基于此版本测。 + 2. 从profiling数据的op_statistic_0_1.csv看出影响性能的是Conv2D算子,TransData,Transpose算子,Conv2D算子不存在问题,由于格式转换om模型Transpose前后需要有TransData算子,从op_summary_0_1.csv可以看出单个TransData或Transpose算子aicore耗时,确定是否可以优化。 + 3. dynamic/transpose.py:68中已经通过shape白名单优化掉了TransposeD +> + five_2_four.py:9928 + 修改如下: + > elif dst_format.lower() == "nchw" and dst_shape in [[2560, 512, 4, 26], [2560, 512, 1, 26], [2560, 256, 8, 25], + [16, 240, 7, 7], [16, 120, 14, 14], + [1, 240, 7, 7], [1, 120, 14, 14], + [4, 240, 7, 7], [4, 120, 14, 14], + [8, 240, 7, 7], [8, 120, 14, 14], + [32, 240, 7, 7], [32, 120, 14, 14]]: +> + four_2_five.py:1219 + 修改如下: + > if src_format.upper() == "NCHW" and shape_input in [[16, 240, 7, 7], [16, 120, 14, 14], + [1, 240, 7, 7], [1, 120, 14, 14], + [4, 240, 7, 7], [4, 120, 14, 14], + [8, 240, 7, 7], [8, 120, 14, 14], + [32, 240, 7, 7], [32, 120, 14, 14]] and dtype_input == "float16": > \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/requirements.txt b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/requirements.txt index c2203b4465..fe5ade6e25 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/requirements.txt +++ b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/requirements.txt @@ -1,6 +1,6 @@ -torch == 1.8.0 -torchvision == 0.9.0 -onnx == 1.9.0 -numpy == 1.18.5 -Pillow == 7.2.0 +torch == 1.8.0 +torchvision == 0.9.0 +onnx == 1.9.0 +numpy == 1.18.5 +Pillow == 7.2.0 opencv-python == 4.5.1.48 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/shufflenetv1_pth2onnx_bs1.py b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/shufflenetv1_pth2onnx_bs1.py index 5da26de337..88a6ada9a1 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/shufflenetv1_pth2onnx_bs1.py +++ b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/shufflenetv1_pth2onnx_bs1.py @@ -1,38 +1,38 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import sys -from collections import OrderedDict -sys.path.append(r"./ShuffleNet-Series/ShuffleNetV1") -from network import ShuffleNetV1 - -def pth2onnx(input_file, output_file): - model = ShuffleNetV1(model_size="1.0x", group=3) - checkpoint = torch.load(input_file, map_location="cpu") - new_state_dict = OrderedDict() - for k, v in checkpoint['state_dict'].items(): - name = k[7:] - new_state_dict[name] = v - model.load_state_dict(new_state_dict) - model.eval() - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.rand(1, 3, 224, 224) - torch.onnx.export(model, dummy_input, output_file, - input_names = input_names, dynamic_axes = dynamic_axes, - output_names = output_names, opset_version=11, verbose=True) - -if __name__=="__main__": - pth2onnx(sys.argv[1], sys.argv[2]) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import sys +from collections import OrderedDict +sys.path.append(r"./ShuffleNet-Series/ShuffleNetV1") +from network import ShuffleNetV1 + +def pth2onnx(input_file, output_file): + model = ShuffleNetV1(model_size="1.0x", group=3) + checkpoint = torch.load(input_file, map_location="cpu") + new_state_dict = OrderedDict() + for k, v in checkpoint['state_dict'].items(): + name = k[7:] + new_state_dict[name] = v + model.load_state_dict(new_state_dict) + model.eval() + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.rand(1, 3, 224, 224) + torch.onnx.export(model, dummy_input, output_file, + input_names = input_names, dynamic_axes = dynamic_axes, + output_names = output_names, opset_version=11, verbose=True) + +if __name__=="__main__": + pth2onnx(sys.argv[1], sys.argv[2]) diff --git a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/shufflenetv1_pth2onnx_bs16.py b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/shufflenetv1_pth2onnx_bs16.py index 5b3fa4b69f..d396f8a2e0 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/shufflenetv1_pth2onnx_bs16.py +++ b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/shufflenetv1_pth2onnx_bs16.py @@ -1,37 +1,37 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import sys -from collections import OrderedDict -sys.path.append(r"./ShuffleNet-Series/ShuffleNetV1") -from network import ShuffleNetV1 - -def pth2onnx(input_file, output_file): - model = ShuffleNetV1(model_size="1.0x", group=3) - checkpoint = torch.load(input_file, map_location="cpu") - new_state_dict = OrderedDict() - for k, v in checkpoint['state_dict'].items(): - name = k[7: ] - new_state_dict[name] = v - model.load_state_dict(new_state_dict) - model.eval() - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.rand(16, 3, 224, 224) - torch.onnx.export(model, dummy_input, output_file, input_names = input_names, - dynamic_axes = dynamic_axes, output_names = output_names, opset_version=11, verbose=True) - -if __name__ == "__main__": - pth2onnx(sys.argv[1], sys.argv[2]) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import sys +from collections import OrderedDict +sys.path.append(r"./ShuffleNet-Series/ShuffleNetV1") +from network import ShuffleNetV1 + +def pth2onnx(input_file, output_file): + model = ShuffleNetV1(model_size="1.0x", group=3) + checkpoint = torch.load(input_file, map_location="cpu") + new_state_dict = OrderedDict() + for k, v in checkpoint['state_dict'].items(): + name = k[7: ] + new_state_dict[name] = v + model.load_state_dict(new_state_dict) + model.eval() + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.rand(16, 3, 224, 224) + torch.onnx.export(model, dummy_input, output_file, input_names = input_names, + dynamic_axes = dynamic_axes, output_names = output_names, opset_version=11, verbose=True) + +if __name__ == "__main__": + pth2onnx(sys.argv[1], sys.argv[2]) diff --git a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/shufflenetv1_torch_preprocess.py b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/shufflenetv1_torch_preprocess.py index 4cf57f07c1..58eb781897 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/shufflenetv1_torch_preprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1/shufflenetv1_torch_preprocess.py @@ -1,79 +1,79 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import PIL -from PIL import Image -import cv2 -import numpy as np -import torch -from torchvision import transforms -import multiprocessing - -def ToBGRTensor(img): - assert isinstance(img, (np.ndarray, PIL.Image.Image)) - if isinstance(img, PIL.Image.Image): - img = np.asarray(img) - img = img[:, :, ::-1] # 2 BGR - img = np.transpose(img, [2, 0, 1]) # 2 (3, H, W) - img = np.ascontiguousarray(img) - img = torch.from_numpy(img).float() - return img - -def OpencvResize(img,size): - assert isinstance(img, PIL.Image.Image) - img = np.asarray(img) # (H,W,3) RGB - img = img[:, :, ::-1] # 2 BGR - img = np.ascontiguousarray(img) - H, W, _ = img.shape - target_size = (int(size / H * W + 0.5), size) if H < W else (size, int(size / W * H + 0.5)) - img = cv2.resize(img, target_size, interpolation=cv2.INTER_LINEAR) - img = img[:, :, ::-1] # 2 RGB - img = np.ascontiguousarray(img) - img = Image.fromarray(img) - return img - -def gen_input_bin(save_path, file_batches, batch): - i = 0 - for file in file_batches[batch]: - i = i + 1 - print("batch", batch, file, "===", i) - # RGBA to RGB - image = Image.open(os.path.join(src_path, file)).convert('RGB') - - image = OpencvResize(image, 256) - crop = transforms.CenterCrop(224) - image = crop(image) - image = ToBGRTensor(image) - img = np.array(image, dtype=np.float32) - img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) - -def preprocess(src_path, save_path): - files = os.listdir(src_path) - file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] - thread_pool = multiprocessing.Pool(len(file_batches)) - for batch in range(len(file_batches)): - thread_pool.apply_async(gen_input_bin, args=(save_path, file_batches, batch)) - thread_pool.close() - thread_pool.join() - print("in thread, except will not report! please ensure bin files generated.") - -if __name__ == "__main__": - src_path = sys.argv[1] - save_path = sys.argv[2] - src_path = os.path.realpath(src_path) - save_path = os.path.realpath(save_path) - if not os.path.isdir(save_path): - os.makedirs(os.path.realpath(save_path)) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import PIL +from PIL import Image +import cv2 +import numpy as np +import torch +from torchvision import transforms +import multiprocessing + +def ToBGRTensor(img): + assert isinstance(img, (np.ndarray, PIL.Image.Image)) + if isinstance(img, PIL.Image.Image): + img = np.asarray(img) + img = img[:, :, ::-1] # 2 BGR + img = np.transpose(img, [2, 0, 1]) # 2 (3, H, W) + img = np.ascontiguousarray(img) + img = torch.from_numpy(img).float() + return img + +def OpencvResize(img,size): + assert isinstance(img, PIL.Image.Image) + img = np.asarray(img) # (H,W,3) RGB + img = img[:, :, ::-1] # 2 BGR + img = np.ascontiguousarray(img) + H, W, _ = img.shape + target_size = (int(size / H * W + 0.5), size) if H < W else (size, int(size / W * H + 0.5)) + img = cv2.resize(img, target_size, interpolation=cv2.INTER_LINEAR) + img = img[:, :, ::-1] # 2 RGB + img = np.ascontiguousarray(img) + img = Image.fromarray(img) + return img + +def gen_input_bin(save_path, file_batches, batch): + i = 0 + for file in file_batches[batch]: + i = i + 1 + print("batch", batch, file, "===", i) + # RGBA to RGB + image = Image.open(os.path.join(src_path, file)).convert('RGB') + + image = OpencvResize(image, 256) + crop = transforms.CenterCrop(224) + image = crop(image) + image = ToBGRTensor(image) + img = np.array(image, dtype=np.float32) + img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) + +def preprocess(src_path, save_path): + files = os.listdir(src_path) + file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] + thread_pool = multiprocessing.Pool(len(file_batches)) + for batch in range(len(file_batches)): + thread_pool.apply_async(gen_input_bin, args=(save_path, file_batches, batch)) + thread_pool.close() + thread_pool.join() + print("in thread, except will not report! please ensure bin files generated.") + +if __name__ == "__main__": + src_path = sys.argv[1] + save_path = sys.argv[2] + src_path = os.path.realpath(src_path) + save_path = os.path.realpath(save_path) + if not os.path.isdir(save_path): + os.makedirs(os.path.realpath(save_path)) preprocess(src_path, save_path) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/LICENSE b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/README.md b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/README.md index 57e58ac3ba..4879ab50b9 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/README.md @@ -1,259 +1,259 @@ -Shufflenetv2+ Onnx模型端到端推理指导 - -- [1 模型概述](#1-模型概述) - - [1.1 论文地址](#11-论文地址) - - [1.2 代码地址](#12-代码地址) -- [2 环境说明](#2-环境说明) - - [2.1 深度学习框架](#21-深度学习框架) - - [2.2 python第三方库](#22-python第三方库) -- [3 模型转换](#3-模型转换) - - [3.1 pth转onnx模型](#31-pth转onnx模型) - - [3.2 onnx转om模型](#32-onnx转om模型) -- [4 数据集预处理](#4-数据集预处理) - - [4.1 数据集获取](#41-数据集获取) - - [4.2 数据集预处理](#42-数据集预处理) - - [4.3 生成数据集信息文件](#43-生成数据集信息文件) -- [5 离线推理](#5-离线推理) - - [5.1 benchmark工具概述](#51-benchmark工具概述) - - [5.2 离线推理](#52-离线推理) -- [6 精度对比](#6-精度对比) - - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) - - [6.2 开源TopN精度](#62-开源TopN精度) - - [6.3 精度对比](#63-精度对比) -- [7 性能对比](#7-性能对比) - - [7.1 npu性能数据](#71-npu性能数据) - - - -## 1 模型概述 - -- **[论文地址](#11-论文地址)** - -- **[代码地址](#12-代码地址)** - -### 1.1 论文地址 -[shufflenetv2论文](https://arxiv.org/abs/1807.11164) - -### 1.2 代码地址 -[shufflenetv2+代码](https://github.com/megvii-model/ShuffleNet-Series/tree/master/ShuffleNetV2%2B) -branch:master -commit_id:d69403d4b5fb3043c7c0da3c2a15df8c5e520d89 - -## 2 环境说明 - -- **[深度学习框架](#21-深度学习框架)** - -- **[python第三方库](#22-python第三方库)** - -### 2.1 深度学习框架 -``` -CANN 5.0.1 -pytorch == 1.5.0 -torchvision == 0.6.0 -onnx == 1.7.0 -``` - -### 2.2 python第三方库 - -``` -numpy == 1.18.5 -Pillow == 7.2.0 -opencv-python == 4.5.1.48 -``` - -**说明:** -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3 模型转换 - -- **[pth转onnx模型](#31-pth转onnx模型)** - -- **[onnx转om模型](#32-onnx转om模型)** - -### 3.1 pth转onnx模型 - -1.下载pth权重文件 -[shufflenetv2+预训练pth权重文件](https://pan.baidu.com/share/init?surl=EUQVoFPb74yZm0JWHKjFOw) -文件md5sum: 1d6611049e6ef03f1d6afa11f6f9023e - -``` -https://pan.baidu.com/share/init?surl=EUQVoFPb74yZm0JWHKjFOw 提取码:mc24 -``` -2.shufflenetv2+模型代码在代码仓里 - -``` -github上Shufflenetv2+没有安装脚本,在pth2onnx脚本中引用代码仓定义的ShuffleNetv2+: - -git clone https://github.com/megvii-model/ShuffleNet-Series.git - - -``` -3.编写pth2onnx脚本shufflenetv2_pth2onnx_bs1.py - - **说明:** ->注意目前ATC支持的onnx算子版本为11 - -4.执行pth2onnx脚本,生成onnx模型文件 -``` -python3.7 shufflenetv2_pth2onnx_bs1.py ShuffleNetV2+.Small.pth.tar shufflenetv2_bs1.onnx -``` - **模型转换要点:** ->动态batch的onnx转om失败并且测的性能数据也不对,每个batch的om都需要对应batch的onnx来转换,每个batch的性能数据也需要对应batch的onnx来测 - - -### 3.2 onnx转om模型 - -1.设置环境变量 -``` -source env.sh -``` -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.1 开发辅助工具指南 (推理) 01 -``` -atc --framework=5 --model=./shufflenetv2_bs1.onnx --input_format=NCHW --input_shape="image:1,3,224,224" --output=shufflenetv2_bs1 --log=debug --soc_version=Ascend310 -``` - -## 4 数据集预处理 - -- **[数据集获取](#41-数据集获取)** - -- **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - -### 4.1 数据集获取 -该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/root/datasets/imagenet/val与/root/datasets/imagenet/val_label.txt。 - -### 4.2 数据集预处理 -1.预处理脚本imagenet_torch_preprocess.py - -2.执行预处理脚本,生成数据集预处理后的bin文件 -``` -python3.7 imagenet_torch_preprocess.py /root/datasets/imagenet/val ./prep_dataset -``` -### 4.3 生成数据集信息文件 -1.生成数据集信息文件脚本get_info.py - -2.执行生成数据集信息脚本,生成数据集信息文件 - -``` -python3.7 get_info.py bin ./prep_dataset ./shufflenetv2_prep_bin.info 224 224 -``` -第一个参数为生成的bin文件路径,第二个为输出的info文件,后面为宽高信息 -## 5 离线推理 - -- **[benchmark工具概述](#51-benchmark工具概述)** - -- **[离线推理](#52-离线推理)** - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN 5.0.1 推理benchmark工具用户指南 01 -### 5.2 离线推理 -1.设置环境变量 -``` -source env.sh -``` -2.执行离线推理 - -``` -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=shufflenetv2_bs1.om -input_text_path=./shufflenetv2_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False -``` -输出结果默认保存在当前目录result/dumpOutput_devicex,模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 - -## 6 精度对比 - -- **[离线推理TopN精度](#61-离线推理TopN精度)** -- **[开源TopN精度](#62-开源TopN精度)** -- **[精度对比](#63-精度对比)** - -### 6.1 离线推理TopN精度统计 - -后处理统计TopN精度 - -调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 -``` -python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /root/datasets/imagenet/val_label.txt ./ result.json -``` -第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 -查看输出结果: -``` -{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value -": "74.06%"}, {"key": "Top2 accuracy", "value": "84.21%"}, {"key": "Top3 accuracy", "value": "88.11%"}, {"key": "Top4 accuracy", "value": "90.3%"}, {"key": "Top5 accuracy", "value": "91.67%"}]} -``` -经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 - -### 6.2 开源TopN精度 -[开源代码仓精度](https://github.com/megvii-model/ShuffleNet-Series/tree/master/ShuffleNetV2%2B) - -``` -Model Acc@1 Acc@5 -shufflenetv2 74.1 91.7 -``` -### 6.3 精度对比 -将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 - **精度调试:** ->没有遇到精度不达标的问题,故不需要进行精度调试 - -## 7 性能对比 - -- **[npu性能数据](#71-npu性能数据)** - -### 7.1 npu性能数据 -benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device。为快速获取性能数据,也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准。这里给出两种方式,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 -1.benchmark工具在整个数据集上推理获得性能数据 -batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: -``` -[e2e] throughputRate: 117.471, latency: 425636 -[data read] throughputRate: 124.47, moduleLatency: 8.03407 -[preprocess] throughputRate: 124.375, moduleLatency: 8.04019 -[infer] throughputRate: 117.823, Interface throughputRate: 147.93, moduleLatency: 7.93347 -[post] throughputRate: 117.822, moduleLatency: 8.48734 -``` -Interface throughputRate: 147.93,147.93x4=591.72既是batch1 310单卡吞吐率 -batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: - -``` -[e2e] throughputRate: 130.7, latency: 382555 -[data read] throughputRate: 131.307, moduleLatency: 7.61574 -[preprocess] throughputRate: 131.19, moduleLatency: 7.62255 -[infer] throughputRate: 131.175, Interface throughputRate: 491.668, moduleLatency: 3.45377 -[post] throughputRate: 8.19833, moduleLatency: 121.976 -``` -Interface throughputRate: 491.668,491.668x4=1966.672既是batch16 310单卡吞吐率 -batch4性能: - -``` -[e2e] throughputRate: 189.011, latency: 264534 -[data read] throughputRate: 198.271, moduleLatency: 5.0436 -[preprocess] throughputRate: 198.037, moduleLatency: 5.04955 -[infer] throughputRate: 189.874, Interface throughputRate: 363.812, moduleLatency: 4.18727 -[post] throughputRate: 47.4682, moduleLatency: 21.0667 -``` -batch4 310单卡吞吐率:363.812x4=1455.248fps -batch8性能: - -``` -[e2e] throughputRate: 139.455, latency: 358539 -[data read] throughputRate: 139.918, moduleLatency: 7.14704 -[preprocess] throughputRate: 139.784, moduleLatency: 7.15391 -[infer] throughputRate: 139.734, Interface throughputRate: 437.088, moduleLatency: 3.72351 -[post] throughputRate: 17.4666, moduleLatency: 57.2522 -``` -batch8 310单卡吞吐率:437.088x4=1748.352fps -batch32性能: - -``` -[e2e] throughputRate: 221.683, latency: 225547 -[data read] throughputRate: 235.234, moduleLatency: 4.25108 -[preprocess] throughputRate: 234.935, moduleLatency: 4.2565 -[infer] throughputRate: 222.362, Interface throughputRate: 475.038, moduleLatency: 3.51711 -[post] throughputRate: 6.95087, moduleLatency: 143.867 -``` -batch32 310单卡吞吐率:475.038x4=1900.152fps - -**性能优化:** - ->没有遇到性能不达标的问题,故不需要进行性能优化 - +Shufflenetv2+ Onnx模型端到端推理指导 + +- [1 模型概述](#1-模型概述) + - [1.1 论文地址](#11-论文地址) + - [1.2 代码地址](#12-代码地址) +- [2 环境说明](#2-环境说明) + - [2.1 深度学习框架](#21-深度学习框架) + - [2.2 python第三方库](#22-python第三方库) +- [3 模型转换](#3-模型转换) + - [3.1 pth转onnx模型](#31-pth转onnx模型) + - [3.2 onnx转om模型](#32-onnx转om模型) +- [4 数据集预处理](#4-数据集预处理) + - [4.1 数据集获取](#41-数据集获取) + - [4.2 数据集预处理](#42-数据集预处理) + - [4.3 生成数据集信息文件](#43-生成数据集信息文件) +- [5 离线推理](#5-离线推理) + - [5.1 benchmark工具概述](#51-benchmark工具概述) + - [5.2 离线推理](#52-离线推理) +- [6 精度对比](#6-精度对比) + - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) + - [6.2 开源TopN精度](#62-开源TopN精度) + - [6.3 精度对比](#63-精度对比) +- [7 性能对比](#7-性能对比) + - [7.1 npu性能数据](#71-npu性能数据) + + + +## 1 模型概述 + +- **[论文地址](#11-论文地址)** + +- **[代码地址](#12-代码地址)** + +### 1.1 论文地址 +[shufflenetv2论文](https://arxiv.org/abs/1807.11164) + +### 1.2 代码地址 +[shufflenetv2+代码](https://github.com/megvii-model/ShuffleNet-Series/tree/master/ShuffleNetV2%2B) +branch:master +commit_id:d69403d4b5fb3043c7c0da3c2a15df8c5e520d89 + +## 2 环境说明 + +- **[深度学习框架](#21-深度学习框架)** + +- **[python第三方库](#22-python第三方库)** + +### 2.1 深度学习框架 +``` +CANN 5.0.1 +pytorch == 1.5.0 +torchvision == 0.6.0 +onnx == 1.7.0 +``` + +### 2.2 python第三方库 + +``` +numpy == 1.18.5 +Pillow == 7.2.0 +opencv-python == 4.5.1.48 +``` + +**说明:** +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3 模型转换 + +- **[pth转onnx模型](#31-pth转onnx模型)** + +- **[onnx转om模型](#32-onnx转om模型)** + +### 3.1 pth转onnx模型 + +1.下载pth权重文件 +[shufflenetv2+预训练pth权重文件](https://pan.baidu.com/share/init?surl=EUQVoFPb74yZm0JWHKjFOw) +文件md5sum: 1d6611049e6ef03f1d6afa11f6f9023e + +``` +https://pan.baidu.com/share/init?surl=EUQVoFPb74yZm0JWHKjFOw 提取码:mc24 +``` +2.shufflenetv2+模型代码在代码仓里 + +``` +github上Shufflenetv2+没有安装脚本,在pth2onnx脚本中引用代码仓定义的ShuffleNetv2+: + +git clone https://github.com/megvii-model/ShuffleNet-Series.git + + +``` +3.编写pth2onnx脚本shufflenetv2_pth2onnx_bs1.py + + **说明:** +>注意目前ATC支持的onnx算子版本为11 + +4.执行pth2onnx脚本,生成onnx模型文件 +``` +python3.7 shufflenetv2_pth2onnx_bs1.py ShuffleNetV2+.Small.pth.tar shufflenetv2_bs1.onnx +``` + **模型转换要点:** +>动态batch的onnx转om失败并且测的性能数据也不对,每个batch的om都需要对应batch的onnx来转换,每个batch的性能数据也需要对应batch的onnx来测 + + +### 3.2 onnx转om模型 + +1.设置环境变量 +``` +source env.sh +``` +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.1 开发辅助工具指南 (推理) 01 +``` +atc --framework=5 --model=./shufflenetv2_bs1.onnx --input_format=NCHW --input_shape="image:1,3,224,224" --output=shufflenetv2_bs1 --log=debug --soc_version=Ascend310 +``` + +## 4 数据集预处理 + +- **[数据集获取](#41-数据集获取)** + +- **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + +### 4.1 数据集获取 +该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/root/datasets/imagenet/val与/root/datasets/imagenet/val_label.txt。 + +### 4.2 数据集预处理 +1.预处理脚本imagenet_torch_preprocess.py + +2.执行预处理脚本,生成数据集预处理后的bin文件 +``` +python3.7 imagenet_torch_preprocess.py /root/datasets/imagenet/val ./prep_dataset +``` +### 4.3 生成数据集信息文件 +1.生成数据集信息文件脚本get_info.py + +2.执行生成数据集信息脚本,生成数据集信息文件 + +``` +python3.7 get_info.py bin ./prep_dataset ./shufflenetv2_prep_bin.info 224 224 +``` +第一个参数为生成的bin文件路径,第二个为输出的info文件,后面为宽高信息 +## 5 离线推理 + +- **[benchmark工具概述](#51-benchmark工具概述)** + +- **[离线推理](#52-离线推理)** + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN 5.0.1 推理benchmark工具用户指南 01 +### 5.2 离线推理 +1.设置环境变量 +``` +source env.sh +``` +2.执行离线推理 + +``` +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=shufflenetv2_bs1.om -input_text_path=./shufflenetv2_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False +``` +输出结果默认保存在当前目录result/dumpOutput_devicex,模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 + +## 6 精度对比 + +- **[离线推理TopN精度](#61-离线推理TopN精度)** +- **[开源TopN精度](#62-开源TopN精度)** +- **[精度对比](#63-精度对比)** + +### 6.1 离线推理TopN精度统计 + +后处理统计TopN精度 + +调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 +``` +python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /root/datasets/imagenet/val_label.txt ./ result.json +``` +第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 +查看输出结果: +``` +{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value +": "74.06%"}, {"key": "Top2 accuracy", "value": "84.21%"}, {"key": "Top3 accuracy", "value": "88.11%"}, {"key": "Top4 accuracy", "value": "90.3%"}, {"key": "Top5 accuracy", "value": "91.67%"}]} +``` +经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 + +### 6.2 开源TopN精度 +[开源代码仓精度](https://github.com/megvii-model/ShuffleNet-Series/tree/master/ShuffleNetV2%2B) + +``` +Model Acc@1 Acc@5 +shufflenetv2 74.1 91.7 +``` +### 6.3 精度对比 +将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 + **精度调试:** +>没有遇到精度不达标的问题,故不需要进行精度调试 + +## 7 性能对比 + +- **[npu性能数据](#71-npu性能数据)** + +### 7.1 npu性能数据 +benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device。为快速获取性能数据,也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准。这里给出两种方式,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 +1.benchmark工具在整个数据集上推理获得性能数据 +batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: +``` +[e2e] throughputRate: 117.471, latency: 425636 +[data read] throughputRate: 124.47, moduleLatency: 8.03407 +[preprocess] throughputRate: 124.375, moduleLatency: 8.04019 +[infer] throughputRate: 117.823, Interface throughputRate: 147.93, moduleLatency: 7.93347 +[post] throughputRate: 117.822, moduleLatency: 8.48734 +``` +Interface throughputRate: 147.93,147.93x4=591.72既是batch1 310单卡吞吐率 +batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: + +``` +[e2e] throughputRate: 130.7, latency: 382555 +[data read] throughputRate: 131.307, moduleLatency: 7.61574 +[preprocess] throughputRate: 131.19, moduleLatency: 7.62255 +[infer] throughputRate: 131.175, Interface throughputRate: 491.668, moduleLatency: 3.45377 +[post] throughputRate: 8.19833, moduleLatency: 121.976 +``` +Interface throughputRate: 491.668,491.668x4=1966.672既是batch16 310单卡吞吐率 +batch4性能: + +``` +[e2e] throughputRate: 189.011, latency: 264534 +[data read] throughputRate: 198.271, moduleLatency: 5.0436 +[preprocess] throughputRate: 198.037, moduleLatency: 5.04955 +[infer] throughputRate: 189.874, Interface throughputRate: 363.812, moduleLatency: 4.18727 +[post] throughputRate: 47.4682, moduleLatency: 21.0667 +``` +batch4 310单卡吞吐率:363.812x4=1455.248fps +batch8性能: + +``` +[e2e] throughputRate: 139.455, latency: 358539 +[data read] throughputRate: 139.918, moduleLatency: 7.14704 +[preprocess] throughputRate: 139.784, moduleLatency: 7.15391 +[infer] throughputRate: 139.734, Interface throughputRate: 437.088, moduleLatency: 3.72351 +[post] throughputRate: 17.4666, moduleLatency: 57.2522 +``` +batch8 310单卡吞吐率:437.088x4=1748.352fps +batch32性能: + +``` +[e2e] throughputRate: 221.683, latency: 225547 +[data read] throughputRate: 235.234, moduleLatency: 4.25108 +[preprocess] throughputRate: 234.935, moduleLatency: 4.2565 +[infer] throughputRate: 222.362, Interface throughputRate: 475.038, moduleLatency: 3.51711 +[post] throughputRate: 6.95087, moduleLatency: 143.867 +``` +batch32 310单卡吞吐率:475.038x4=1900.152fps + +**性能优化:** + +>没有遇到性能不达标的问题,故不需要进行性能优化 + diff --git a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/imagenet_torch_preprocess.py b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/imagenet_torch_preprocess.py index 67877da44e..cb19574d4a 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/imagenet_torch_preprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/imagenet_torch_preprocess.py @@ -1,72 +1,72 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import PIL -from PIL import Image -import cv2 -import numpy as np -import torch -from torchvision import transforms - -class ToBGRTensor(object): - - def __call__(self, img): - assert isinstance(img, (np.ndarray, PIL.Image.Image)) - if isinstance(img, PIL.Image.Image): - img = np.asarray(img) - img = img[:,:,::-1] # 2 BGR - img = np.transpose(img, [2, 0, 1]) # 2 (3, H, W) - img = np.ascontiguousarray(img) - img = torch.from_numpy(img).float() - return img - -class OpencvResize(object): - - def __init__(self, size=256): - self.size = size - - def __call__(self, img): - assert isinstance(img, PIL.Image.Image) - img = np.asarray(img) # (H,W,3) RGB - img = img[:,:,::-1] # 2 BGR - img = np.ascontiguousarray(img) - H, W, _ = img.shape - target_size = (int(self.size/H * W + 0.5), self.size) if H < W else (self.size, int(self.size/W * H + 0.5)) - img = cv2.resize(img, target_size, interpolation=cv2.INTER_LINEAR) - img = img[:,:,::-1] # 2 RGB - img = np.ascontiguousarray(img) - img = Image.fromarray(img) - return img - -def preprocess(src_path, save_path): - - preprocess = transforms.Compose([ - OpencvResize(256), - transforms.CenterCrop(224), - ToBGRTensor(), - ]) - - i = 0 - in_files = os.listdir(src_path) - for file in in_files: - i = i + 1 - print(file, "===", i) - input_image = Image.open(src_path + '/' + file).convert('RGB') - input_tensor = preprocess(input_image) - img = np.array(input_tensor).astype(np.float32) - img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) - -if __name__=="__main__": - preprocess(sys.argv[1],sys.argv[2]) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import PIL +from PIL import Image +import cv2 +import numpy as np +import torch +from torchvision import transforms + +class ToBGRTensor(object): + + def __call__(self, img): + assert isinstance(img, (np.ndarray, PIL.Image.Image)) + if isinstance(img, PIL.Image.Image): + img = np.asarray(img) + img = img[:,:,::-1] # 2 BGR + img = np.transpose(img, [2, 0, 1]) # 2 (3, H, W) + img = np.ascontiguousarray(img) + img = torch.from_numpy(img).float() + return img + +class OpencvResize(object): + + def __init__(self, size=256): + self.size = size + + def __call__(self, img): + assert isinstance(img, PIL.Image.Image) + img = np.asarray(img) # (H,W,3) RGB + img = img[:,:,::-1] # 2 BGR + img = np.ascontiguousarray(img) + H, W, _ = img.shape + target_size = (int(self.size/H * W + 0.5), self.size) if H < W else (self.size, int(self.size/W * H + 0.5)) + img = cv2.resize(img, target_size, interpolation=cv2.INTER_LINEAR) + img = img[:,:,::-1] # 2 RGB + img = np.ascontiguousarray(img) + img = Image.fromarray(img) + return img + +def preprocess(src_path, save_path): + + preprocess = transforms.Compose([ + OpencvResize(256), + transforms.CenterCrop(224), + ToBGRTensor(), + ]) + + i = 0 + in_files = os.listdir(src_path) + for file in in_files: + i = i + 1 + print(file, "===", i) + input_image = Image.open(src_path + '/' + file).convert('RGB') + input_tensor = preprocess(input_image) + img = np.array(input_tensor).astype(np.float32) + img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) + +if __name__=="__main__": + preprocess(sys.argv[1],sys.argv[2]) diff --git a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/requirements.txt b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/requirements.txt index 19bf0c33da..59f8a711bf 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/requirements.txt +++ b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/requirements.txt @@ -1,6 +1,6 @@ -torch == 1.5.0 -torchvision == 0.6.0 -onnx == 1.7.0 -numpy == 1.18.5 -Pillow == 7.2.0 +torch == 1.5.0 +torchvision == 0.6.0 +onnx == 1.7.0 +numpy == 1.18.5 +Pillow == 7.2.0 opencv-python == 4.5.1.48 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/shufflenetv2_pth2onnx_bs1.py b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/shufflenetv2_pth2onnx_bs1.py index ff67f2706f..f428f939b0 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/shufflenetv2_pth2onnx_bs1.py +++ b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/shufflenetv2_pth2onnx_bs1.py @@ -1,39 +1,39 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import torch -from collections import OrderedDict -sys.path.append(r"./ShuffleNet-Series/ShuffleNetV2+") -from network import ShuffleNetV2_Plus - -def pth2onnx(input_file, output_file): - architecture = [0, 0, 3, 1, 1, 1, 0, 0, 2, 0, 2, 1, 1, 0, 2, 0, 2, 1, 3, 2] - model = ShuffleNetV2_Plus(architecture=architecture,model_size='Small') - checkpoint = torch.load(input_file, map_location="cpu") - new_state_dict = OrderedDict() - for k, v in checkpoint['state_dict'].items(): - name = k[7:] - new_state_dict[name] = v - model.load_state_dict(new_state_dict) - model.eval() - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.rand(1, 3, 224, 224) - torch.onnx.export(model, dummy_input, output_file, - input_names = input_names, dynamic_axes = dynamic_axes, - output_names = output_names, opset_version=11, verbose=True) - -if __name__=="__main__": - pth2onnx(sys.argv[1], sys.argv[2]) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import torch +from collections import OrderedDict +sys.path.append(r"./ShuffleNet-Series/ShuffleNetV2+") +from network import ShuffleNetV2_Plus + +def pth2onnx(input_file, output_file): + architecture = [0, 0, 3, 1, 1, 1, 0, 0, 2, 0, 2, 1, 1, 0, 2, 0, 2, 1, 3, 2] + model = ShuffleNetV2_Plus(architecture=architecture,model_size='Small') + checkpoint = torch.load(input_file, map_location="cpu") + new_state_dict = OrderedDict() + for k, v in checkpoint['state_dict'].items(): + name = k[7:] + new_state_dict[name] = v + model.load_state_dict(new_state_dict) + model.eval() + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.rand(1, 3, 224, 224) + torch.onnx.export(model, dummy_input, output_file, + input_names = input_names, dynamic_axes = dynamic_axes, + output_names = output_names, opset_version=11, verbose=True) + +if __name__=="__main__": + pth2onnx(sys.argv[1], sys.argv[2]) diff --git a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/shufflenetv2_pth2onnx_bs16.py b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/shufflenetv2_pth2onnx_bs16.py index 5eb21c1900..708cfba6b5 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/shufflenetv2_pth2onnx_bs16.py +++ b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/shufflenetv2_pth2onnx_bs16.py @@ -1,39 +1,39 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import torch -from collections import OrderedDict -sys.path.append(r"./ShuffleNet-Series/ShuffleNetV2+") -from network import ShuffleNetV2_Plus - -def pth2onnx(input_file, output_file): - architecture = [0, 0, 3, 1, 1, 1, 0, 0, 2, 0, 2, 1, 1, 0, 2, 0, 2, 1, 3, 2] - model = ShuffleNetV2_Plus(architecture=architecture,model_size='Small') - checkpoint = torch.load(input_file, map_location="cpu") - new_state_dict = OrderedDict() - for k, v in checkpoint['state_dict'].items(): - name = k[7:] - new_state_dict[name] = v - model.load_state_dict(new_state_dict) - model.eval() - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.rand(16, 3, 224, 224) - torch.onnx.export(model, dummy_input, output_file, - input_names = input_names, dynamic_axes = dynamic_axes, - output_names = output_names, opset_version=11, verbose=True) - -if __name__=="__main__": - pth2onnx(sys.argv[1], sys.argv[2]) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import torch +from collections import OrderedDict +sys.path.append(r"./ShuffleNet-Series/ShuffleNetV2+") +from network import ShuffleNetV2_Plus + +def pth2onnx(input_file, output_file): + architecture = [0, 0, 3, 1, 1, 1, 0, 0, 2, 0, 2, 1, 1, 0, 2, 0, 2, 1, 3, 2] + model = ShuffleNetV2_Plus(architecture=architecture,model_size='Small') + checkpoint = torch.load(input_file, map_location="cpu") + new_state_dict = OrderedDict() + for k, v in checkpoint['state_dict'].items(): + name = k[7:] + new_state_dict[name] = v + model.load_state_dict(new_state_dict) + model.eval() + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.rand(16, 3, 224, 224) + torch.onnx.export(model, dummy_input, output_file, + input_names = input_names, dynamic_axes = dynamic_axes, + output_names = output_names, opset_version=11, verbose=True) + +if __name__=="__main__": + pth2onnx(sys.argv[1], sys.argv[2]) diff --git a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/test/readme.md b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/test/readme.md index a8c3957376..a308c17cb2 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/test/readme.md +++ b/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+/test/readme.md @@ -1,27 +1,27 @@ -环境准备: - -1.数据集路径 -通用的数据集统一放在/root/datasets/或/opt/npu/ -本模型数据集放在/opt/npu/ - -2.进入工作目录 -cd Shufflenetv2+ - -3.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -pip3.7 install -r requirements.txt - -4.获取模型代码 -git clone https://github.com/megvii-model/ShuffleNet-Series.git - - -5.获取权重文件 -https://pan.baidu.com/share/init?surl=EUQVoFPb74yZm0JWHKjFOw - -提取码:mc24 - -6.获取benchmark工具 -将benchmark.x86_64 benchmark.aarch64放在当前目录 - -7.310上执行,执行时确保device空闲 -bash test/pth2om.sh -bash test/eval_acc_perf.sh +环境准备: + +1.数据集路径 +通用的数据集统一放在/root/datasets/或/opt/npu/ +本模型数据集放在/opt/npu/ + +2.进入工作目录 +cd Shufflenetv2+ + +3.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +pip3.7 install -r requirements.txt + +4.获取模型代码 +git clone https://github.com/megvii-model/ShuffleNet-Series.git + + +5.获取权重文件 +https://pan.baidu.com/share/init?surl=EUQVoFPb74yZm0JWHKjFOw + +提取码:mc24 + +6.获取benchmark工具 +将benchmark.x86_64 benchmark.aarch64放在当前目录 + +7.310上执行,执行时确保device空闲 +bash test/pth2om.sh +bash test/eval_acc_perf.sh diff --git a/ACL_PyTorch/contrib/cv/classfication/SimCLR_inference/Simclr_preprocess.py b/ACL_PyTorch/contrib/cv/classfication/SimCLR_inference/Simclr_preprocess.py index d423874602..93065389d2 100644 --- a/ACL_PyTorch/contrib/cv/classfication/SimCLR_inference/Simclr_preprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/SimCLR_inference/Simclr_preprocess.py @@ -1,106 +1,106 @@ -""" -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 numpy as np -from torchvision import transforms -import torch -from torch import nn -import os -from PIL import Image -import sys -import pickle - - -class GaussianBlur(object): - """blur a single image on CPU""" - def __init__(self, kernel_size): - radias = kernel_size // 2 - kernel_size = radias * 2 + 1 - self.blur_h = nn.Conv2d(3, 3, kernel_size=(kernel_size, 1), - stride=1, padding=0, bias=False, groups=3) - self.blur_v = nn.Conv2d(3, 3, kernel_size=(1, kernel_size), - stride=1, padding=0, bias=False, groups=3) - self.k = kernel_size - self.r = radias - - self.blur = nn.Sequential( - nn.ReflectionPad2d(radias), - self.blur_h, - self.blur_v - ) - - self.pil_to_tensor = transforms.ToTensor() - self.tensor_to_pil = transforms.ToPILImage() - - def __call__(self, img): - img = self.pil_to_tensor(img).unsqueeze(0) - - sigma = np.random.uniform(0.1, 2.0) - x = np.arange(-self.r, self.r + 1) - x = np.exp(-np.power(x, 2) / (2 * sigma * sigma)) - x = x / x.sum() - x = torch.from_numpy(x).view(1, -1).repeat(3, 1) - - self.blur_h.weight.data.copy_(x.view(3, 1, self.k, 1)) - self.blur_v.weight.data.copy_(x.view(3, 1, 1, self.k)) - - with torch.no_grad(): - img = self.blur(img) - img = img.squeeze() - - img = self.tensor_to_pil(img) - - return img - - -def preprocess(srcfile_path, savefile_path): - """ data preprocess """ - size = 32 - s = 1 - n_views = 2 - file_num = 0 - data = [] - color_jitter = transforms.ColorJitter(0.8 * s, 0.8 * s, 0.8 * s, 0.2 * s) - data_transforms = transforms.Compose([transforms.RandomResizedCrop(size=size), - transforms.RandomHorizontalFlip(), - transforms.RandomApply([color_jitter], p=0.8), - transforms.RandomGrayscale(p=0.2), - GaussianBlur(kernel_size=int(0.1 * size)), - transforms.ToTensor()]) - if not os.path.exists(savefile_path): - os.mkdir(savefile_path) - with open(srcfile_path, "rb") as f: - entry = pickle.load(f, encoding='latin1') - data.append(entry['data']) - images = np.vstack(data).reshape(-1, 3, 32, 32) - images = np.transpose(images, (0, 2, 3, 1)) - for i in range(images.shape[0]): - image = [data_transforms(Image.fromarray(images[i])) for j in range(n_views)] - file_path = os.path.join(savefile_path, "Simclr_prep_" + str(file_num) + ".bin") - file_num = file_num + 1 - print(i) - image_file = np.array(image[0]).astype(np.float32) - image_file.tofile(file_path) - file_path = os.path.join(savefile_path, "Simclr_prep_" + str(file_num) + ".bin") - image_file = np.array(image[1]).astype(np.float32) - image_file.tofile(file_path) - file_num = file_num + 1 - - -if __name__ == "__main__": - src_path = sys.argv[1] - save_path = sys.argv[2] - preprocess(src_path, save_path) +""" +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 numpy as np +from torchvision import transforms +import torch +from torch import nn +import os +from PIL import Image +import sys +import pickle + + +class GaussianBlur(object): + """blur a single image on CPU""" + def __init__(self, kernel_size): + radias = kernel_size // 2 + kernel_size = radias * 2 + 1 + self.blur_h = nn.Conv2d(3, 3, kernel_size=(kernel_size, 1), + stride=1, padding=0, bias=False, groups=3) + self.blur_v = nn.Conv2d(3, 3, kernel_size=(1, kernel_size), + stride=1, padding=0, bias=False, groups=3) + self.k = kernel_size + self.r = radias + + self.blur = nn.Sequential( + nn.ReflectionPad2d(radias), + self.blur_h, + self.blur_v + ) + + self.pil_to_tensor = transforms.ToTensor() + self.tensor_to_pil = transforms.ToPILImage() + + def __call__(self, img): + img = self.pil_to_tensor(img).unsqueeze(0) + + sigma = np.random.uniform(0.1, 2.0) + x = np.arange(-self.r, self.r + 1) + x = np.exp(-np.power(x, 2) / (2 * sigma * sigma)) + x = x / x.sum() + x = torch.from_numpy(x).view(1, -1).repeat(3, 1) + + self.blur_h.weight.data.copy_(x.view(3, 1, self.k, 1)) + self.blur_v.weight.data.copy_(x.view(3, 1, 1, self.k)) + + with torch.no_grad(): + img = self.blur(img) + img = img.squeeze() + + img = self.tensor_to_pil(img) + + return img + + +def preprocess(srcfile_path, savefile_path): + """ data preprocess """ + size = 32 + s = 1 + n_views = 2 + file_num = 0 + data = [] + color_jitter = transforms.ColorJitter(0.8 * s, 0.8 * s, 0.8 * s, 0.2 * s) + data_transforms = transforms.Compose([transforms.RandomResizedCrop(size=size), + transforms.RandomHorizontalFlip(), + transforms.RandomApply([color_jitter], p=0.8), + transforms.RandomGrayscale(p=0.2), + GaussianBlur(kernel_size=int(0.1 * size)), + transforms.ToTensor()]) + if not os.path.exists(savefile_path): + os.mkdir(savefile_path) + with open(srcfile_path, "rb") as f: + entry = pickle.load(f, encoding='latin1') + data.append(entry['data']) + images = np.vstack(data).reshape(-1, 3, 32, 32) + images = np.transpose(images, (0, 2, 3, 1)) + for i in range(images.shape[0]): + image = [data_transforms(Image.fromarray(images[i])) for j in range(n_views)] + file_path = os.path.join(savefile_path, "Simclr_prep_" + str(file_num) + ".bin") + file_num = file_num + 1 + print(i) + image_file = np.array(image[0]).astype(np.float32) + image_file.tofile(file_path) + file_path = os.path.join(savefile_path, "Simclr_prep_" + str(file_num) + ".bin") + image_file = np.array(image[1]).astype(np.float32) + image_file.tofile(file_path) + file_num = file_num + 1 + + +if __name__ == "__main__": + src_path = sys.argv[1] + save_path = sys.argv[2] + preprocess(src_path, save_path) diff --git a/ACL_PyTorch/contrib/cv/classfication/SimCLR_inference/Simclr_pth2onnx.py b/ACL_PyTorch/contrib/cv/classfication/SimCLR_inference/Simclr_pth2onnx.py index a3141e636f..17a6214854 100644 --- a/ACL_PyTorch/contrib/cv/classfication/SimCLR_inference/Simclr_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/classfication/SimCLR_inference/Simclr_pth2onnx.py @@ -1,79 +1,79 @@ -""" -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 torch -import sys -import torch.nn as nn -import torchvision.models as models - - -class BaseSimCLRException(Exception): - """Base exception""" - - -class InvalidBackboneError(BaseSimCLRException): - """Raised when the choice of backbone Convnet is invalid.""" - - -class InvalidDatasetSelection(BaseSimCLRException): - """Raised when the choice of dataset is invalid.""" - -class ResNetSimCLR(nn.Module): - """ Simclr model """ - def __init__(self, base_model, out_dim): - super(ResNetSimCLR, self).__init__() - self.resnet_dict = {"resnet18": models.resnet18(pretrained=False, num_classes=out_dim), - "resnet50": models.resnet50(pretrained=False, num_classes=out_dim)} - - self.backbone = self._get_basemodel(base_model) - dim_mlp = self.backbone.fc.in_features - - # add mlp projection head - self.backbone.fc = nn.Sequential(nn.Linear(dim_mlp, dim_mlp), nn.ReLU(), self.backbone.fc) - - def _get_basemodel(self, model_name): - try: - model = self.resnet_dict[model_name] - except KeyError: - raise InvalidBackboneError( - "Invalid backbone architecture. Check the config file and pass one of: resnet18 or resnet50") - else: - return model - - def forward(self, x): - """forward """ - return self.backbone(x) - - -def pth2onnx(input_file, output_file): - """pth to onnx""" - checkpoint = torch.load(input_file, map_location='cpu') - model = ResNetSimCLR(base_model='resnet18', out_dim=128) - model.load_state_dict(checkpoint["state_dict"]) - model.eval() - - input_name = ["input"] - output_name = ["output"] - - dummy_input = torch.randn(1, 3, 32, 32) - torch.onnx.export(model, dummy_input, output_file, input_names=input_name, output_names=output_name, verbose=True) - - -if __name__ == "__main__": - input_pth = sys.argv[1] - output = sys.argv[2] - pth2onnx(input_pth, output) - +""" +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 torch +import sys +import torch.nn as nn +import torchvision.models as models + + +class BaseSimCLRException(Exception): + """Base exception""" + + +class InvalidBackboneError(BaseSimCLRException): + """Raised when the choice of backbone Convnet is invalid.""" + + +class InvalidDatasetSelection(BaseSimCLRException): + """Raised when the choice of dataset is invalid.""" + +class ResNetSimCLR(nn.Module): + """ Simclr model """ + def __init__(self, base_model, out_dim): + super(ResNetSimCLR, self).__init__() + self.resnet_dict = {"resnet18": models.resnet18(pretrained=False, num_classes=out_dim), + "resnet50": models.resnet50(pretrained=False, num_classes=out_dim)} + + self.backbone = self._get_basemodel(base_model) + dim_mlp = self.backbone.fc.in_features + + # add mlp projection head + self.backbone.fc = nn.Sequential(nn.Linear(dim_mlp, dim_mlp), nn.ReLU(), self.backbone.fc) + + def _get_basemodel(self, model_name): + try: + model = self.resnet_dict[model_name] + except KeyError: + raise InvalidBackboneError( + "Invalid backbone architecture. Check the config file and pass one of: resnet18 or resnet50") + else: + return model + + def forward(self, x): + """forward """ + return self.backbone(x) + + +def pth2onnx(input_file, output_file): + """pth to onnx""" + checkpoint = torch.load(input_file, map_location='cpu') + model = ResNetSimCLR(base_model='resnet18', out_dim=128) + model.load_state_dict(checkpoint["state_dict"]) + model.eval() + + input_name = ["input"] + output_name = ["output"] + + dummy_input = torch.randn(1, 3, 32, 32) + torch.onnx.export(model, dummy_input, output_file, input_names=input_name, output_names=output_name, verbose=True) + + +if __name__ == "__main__": + input_pth = sys.argv[1] + output = sys.argv[2] + pth2onnx(input_pth, output) + diff --git a/ACL_PyTorch/contrib/cv/classfication/SimCLR_inference/test/parse.py b/ACL_PyTorch/contrib/cv/classfication/SimCLR_inference/test/parse.py index b17c1e0d82..178bbb3fd3 100644 --- a/ACL_PyTorch/contrib/cv/classfication/SimCLR_inference/test/parse.py +++ b/ACL_PyTorch/contrib/cv/classfication/SimCLR_inference/test/parse.py @@ -1,31 +1,31 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 sys -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.log'): - result_log = sys.argv[1] - with open(result_log, 'r') as f: - lines = f.readlines() - RSNR_Res = lines[-1] - print(RSNR_Res.replace('\n', '')) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 sys +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.log'): + result_log = sys.argv[1] + with open(result_log, 'r') as f: + lines = f.readlines() + RSNR_Res = lines[-1] + print(RSNR_Res.replace('\n', '')) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Sknet50/LICENSE b/ACL_PyTorch/contrib/cv/classfication/Sknet50/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Sknet50/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/Sknet50/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Sknet50/README.md b/ACL_PyTorch/contrib/cv/classfication/Sknet50/README.md index a73c1aea8c..6400661511 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Sknet50/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/Sknet50/README.md @@ -1,269 +1,269 @@ -# SK-ResNet50 Onnx 模型端到端推理指导 - -- [1. 模型概述](#1) - - [论文地址](#11) - - [代码地址](#12) -- [2. 环境说明](#2) - - [深度学习框架](#21) - - [python第三方库](#22) -- [3. 模型转换](#3) - - [pth转onnx模型](#31) -- [4. 数据预处理](#4) - - [数据集获取](#41) - - [数据集预处理](#42) - - [生成数据集信息文件](#43) -- [5. 离线推理](#5) - - [benchmark工具概述](#51) - - [离线推理](#52) -- [6. 精度对比](#6) - - [离线推理TopN精度](#61) - - [精度对比](#62) -- [7. 性能对比](#7) - - [npu性能数据](#71) - -## 1. 模型概述 - -### 1.1 论文地址 - -[SK-ResNet 论文](https://arxiv.org/pdf/1903.06586.pdf) - -### 1.2 代码地址 - -[SK-ResNet 代码](https://github.com/implus/PytorchInsight) - -branch: master - -commit_id: 2864528f8b83f52c3df76f7c3804aa468b91e5cf - -## 2. 环境说明 - -### 2.1 深度学习框架 - -``` -pytorch == 1.5.0 -torchvision == 0.6.0 -onnx == 1.9.0 -``` - -### 2.2 python第三方库 - -``` -numpy == 1.19.2 -Pillow == 8.2.0 -opencv-python == 4.5.2 -``` - -> **说明:** -> -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3. 模型转换 - -### 3.1 pth转onnx模型 - -1. 下载 pth 权重文件 - - [SK-ResNet50预训练pth权重文件(百度网盘,提取码:tfwn)](https://pan.baidu.com/s/1Lx5CNUeRQXOSWjzTlcO2HQ) - - 文件名:sk_resnet50.pth.tar - - md5sum:979bbb525ee0898003777a8e663e91c0 - -2. 克隆代码仓库代码 - - ```bash - git clone https://github.com/implus/PytorchInsight.git - ``` - -3. 使用 sknet2onnx.py 转换pth为onnx文件,在命令行运行如下指令: - - ```bash - python3.7 sknet2onnx.py --pth sk_resnet50.pth.tar --onnx sknet50_bs1 - ``` - - sk_resnet50.pth.tar文件为步骤1中下载的预训练权重文件,该条指令将在运行处生成一个sknet50_bs1文件,此文件即为目标onnx文件 - -**模型转换要点:** - -> pytorch导出onnx时softmax引入了transpose以操作任意轴,然而在onnx中已支持softmax操作任意轴,故可删除transpose提升性能 - -### 3.2 onnx转om模型 - -下列需要在具备华为Ascend系列芯片的机器上执行: - -1. 设置 atc 工作所需要的环境变量 - - ```bash - export install_path=/usr/local/Ascend/ascend-toolkit/latest - export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH - export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH - export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH - export ASCEND_OPP_PATH=${install_path}/opp - ``` - -2. 使用atc工具将onnx模型转换为om模型,命令参考 - - ```bash - atc --framework=5 --model=sknet50.onnx --output=sknet50_bs1 --input_format=NCHW --input_shape="image:1,3,224,224" --log=debug --soc_version=Ascend310 - ``` - - 此命令将在运行路径下生成一个sknet50_1bs.om文件,此文件即为目标om模型文件 - -## 4. 数据预处理 - -### 4.1 数据集获取 - -该模型使用[ImageNet官网](http://www.image-net.org/)的5万张验证集进行测试,图片与标签分别存放在/opt/npu/imagenet/val与/opt/npu/imagenet/val_label.txt。 - -### 4.2 数据集预处理 - -使用 sknet_preprocess.py 脚本进行数据预处理,脚本执行命令: - -```bash -python3.7 sknet_preprocess.py -s /opt/npu/imagenet/val -d ./prep_data -``` - -### 4.3 生成数据集信息文件 - -1. 生成数据集信息文件脚本 get_info.py - -2. 执行生成数据集信息脚本,生成数据集信息文件 - - ```bash - python3.7 get_info.py bin ./prep_data ./sknet_prep_bin.info 224 224 - ``` - - 第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 - -## 5. 离线推理 - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN V100R020C10 推理benchmark工具用户指南 01 - -### 5.2 离线推理 - -```bash -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=sknet50_bs1.om -input_text_path=sknet_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False -``` - -输出结果默认保存在当前目录result/dumpOutput_device{0},模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 - -## 6. 精度对比 - -### 6.1 离线推理TopN精度 - -后处理统计TopN精度,调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中: - -```bash -python3.7 vision_metric_ImageNet.py result/dumpOutput_device0/ ../data/sknet/val_label.txt ./ result.json -``` - -第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。查看输出结果: - -```json -{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value": "77.54%"}, {"key": "Top2 accuracy", "value": "87.12%"}, {"key": "Top3 accuracy", "value": "90.73%"}, {"key": "Top4 accuracy", "value": "92.55%"}, {"key": "Top5 accuracy", "value": "93.71%"}]} -``` - -经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 - -### 6.2 精度对比 - -| | TOP1 | TOP5 | -| :----------------: | :------: | :------: | -| 原github仓库精度 | 77.5380% | 93.7000% | -| om模型离线推理精度 | 77.54% | 93.71% | - -将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 - -## 7. 性能对比 - -### 7.1 npu性能数据 - -benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 - -benchmark工具作纯推理时使用的命令参考如下: - -```bash -./benchmark.x86_64 -round=20 -om_path=sknet50_bs1.om -batch_size=1 -``` - -1. batch1 性能 - - 使用benchmark工具在整个数据集上推理时获得的性能数据: - - ``` - [e2e] throughputRate: 143.402, latency: 348669 - [data read] throughputRate: 152.003, moduleLatency: 6.57881 - [preprocess] throughputRate: 151.416, moduleLatency: 6.60433 - [infer] throughputRate: 143.733, Interface throughputRate: 210.306, moduleLatency: 6.16176 - [post] throughputRate: 143.732, moduleLatency: 6.95737 - ``` - - Interface throughputRate: 210.306 * 4 = 841.224 即是batch1 310单卡吞吐率 - -2. batch4 性能 - - ``` - [INFO] ave_throughputRate: 315.424samples/s, ave_latency: 3.30141ms - ``` - - Interface throughputRate: 315.424 * 4 = 1261.696 即是batch4 310单卡吞吐率 - -3. batch8 性能 - - ``` - [INFO] ave_throughputRate: 365.813samples/s, ave_latency: 2.76526ms - ``` - - Interface throughputRate: 365.813 * 4 = 1463.252 即是batch8 310单卡吞吐率 - -4. batch16 性能 - - ``` - [e2e] throughputRate: 196.399, latency: 254584 - [data read] throughputRate: 208.891, moduleLatency: 4.78718 - [preprocess] throughputRate: 207.779, moduleLatency: 4.81281 - [infer] throughputRate: 197.514, Interface throughputRate: 392.072, modul - [post] throughputRate: 12.3443, moduleLatency: 81.0088 - ``` - - Interface throughputRate: 392.072 * 4 = 1568.288 即是batch16 310单卡吞吐率 - -5. batch32 性能 - - ``` - [INFO] ave_throughputRate: 376.691samples/s, ave_latency: 2.66319ms - ``` - - Interface throughputRate: 376.691 * 4 = 1506.764 即是batch32 310单卡吞吐率 - -**性能优化** - -> 从profiling数据的op_statistic_0_1.csv看出影响性能的是transpose算子,从onnx结构图看出该算子用于实现softmax任意轴,由pytorch导出时引入,然而softmax在onnx中现已支持任意轴,故可直接删除该算子提升性能,删除代码参考如下: - -```python -model = onnx.load(args.onnx+'.onnx') -graph = model.graph -node = graph.node -softmax_node_index = [] -del_group = [] -for i in range(len(node)): - if node[i].op_type == 'Softmax': - del_group.append((node[i-1], node[i], node[i+1], i)) -for g in del_group: - new_input = g[0].input - new_output = g[2].output - new_name = g[1].name - new_index = g[3] - new_node = onnx.helper.make_node("Softmax", new_input, new_output, new_name, axis=1) - for n in g[:-1]: - graph.node.remove(n) - graph.node.insert(new_index, new_node) -onnx.save(model, args.onnx+'.onnx') -``` - - - +# SK-ResNet50 Onnx 模型端到端推理指导 + +- [1. 模型概述](#1) + - [论文地址](#11) + - [代码地址](#12) +- [2. 环境说明](#2) + - [深度学习框架](#21) + - [python第三方库](#22) +- [3. 模型转换](#3) + - [pth转onnx模型](#31) +- [4. 数据预处理](#4) + - [数据集获取](#41) + - [数据集预处理](#42) + - [生成数据集信息文件](#43) +- [5. 离线推理](#5) + - [benchmark工具概述](#51) + - [离线推理](#52) +- [6. 精度对比](#6) + - [离线推理TopN精度](#61) + - [精度对比](#62) +- [7. 性能对比](#7) + - [npu性能数据](#71) + +## 1. 模型概述 + +### 1.1 论文地址 + +[SK-ResNet 论文](https://arxiv.org/pdf/1903.06586.pdf) + +### 1.2 代码地址 + +[SK-ResNet 代码](https://github.com/implus/PytorchInsight) + +branch: master + +commit_id: 2864528f8b83f52c3df76f7c3804aa468b91e5cf + +## 2. 环境说明 + +### 2.1 深度学习框架 + +``` +pytorch == 1.5.0 +torchvision == 0.6.0 +onnx == 1.9.0 +``` + +### 2.2 python第三方库 + +``` +numpy == 1.19.2 +Pillow == 8.2.0 +opencv-python == 4.5.2 +``` + +> **说明:** +> +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3. 模型转换 + +### 3.1 pth转onnx模型 + +1. 下载 pth 权重文件 + + [SK-ResNet50预训练pth权重文件(百度网盘,提取码:tfwn)](https://pan.baidu.com/s/1Lx5CNUeRQXOSWjzTlcO2HQ) + + 文件名:sk_resnet50.pth.tar + + md5sum:979bbb525ee0898003777a8e663e91c0 + +2. 克隆代码仓库代码 + + ```bash + git clone https://github.com/implus/PytorchInsight.git + ``` + +3. 使用 sknet2onnx.py 转换pth为onnx文件,在命令行运行如下指令: + + ```bash + python3.7 sknet2onnx.py --pth sk_resnet50.pth.tar --onnx sknet50_bs1 + ``` + + sk_resnet50.pth.tar文件为步骤1中下载的预训练权重文件,该条指令将在运行处生成一个sknet50_bs1文件,此文件即为目标onnx文件 + +**模型转换要点:** + +> pytorch导出onnx时softmax引入了transpose以操作任意轴,然而在onnx中已支持softmax操作任意轴,故可删除transpose提升性能 + +### 3.2 onnx转om模型 + +下列需要在具备华为Ascend系列芯片的机器上执行: + +1. 设置 atc 工作所需要的环境变量 + + ```bash + export install_path=/usr/local/Ascend/ascend-toolkit/latest + export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH + export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH + export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH + export ASCEND_OPP_PATH=${install_path}/opp + ``` + +2. 使用atc工具将onnx模型转换为om模型,命令参考 + + ```bash + atc --framework=5 --model=sknet50.onnx --output=sknet50_bs1 --input_format=NCHW --input_shape="image:1,3,224,224" --log=debug --soc_version=Ascend310 + ``` + + 此命令将在运行路径下生成一个sknet50_1bs.om文件,此文件即为目标om模型文件 + +## 4. 数据预处理 + +### 4.1 数据集获取 + +该模型使用[ImageNet官网](http://www.image-net.org/)的5万张验证集进行测试,图片与标签分别存放在/opt/npu/imagenet/val与/opt/npu/imagenet/val_label.txt。 + +### 4.2 数据集预处理 + +使用 sknet_preprocess.py 脚本进行数据预处理,脚本执行命令: + +```bash +python3.7 sknet_preprocess.py -s /opt/npu/imagenet/val -d ./prep_data +``` + +### 4.3 生成数据集信息文件 + +1. 生成数据集信息文件脚本 get_info.py + +2. 执行生成数据集信息脚本,生成数据集信息文件 + + ```bash + python3.7 get_info.py bin ./prep_data ./sknet_prep_bin.info 224 224 + ``` + + 第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 + +## 5. 离线推理 + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN V100R020C10 推理benchmark工具用户指南 01 + +### 5.2 离线推理 + +```bash +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=sknet50_bs1.om -input_text_path=sknet_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False +``` + +输出结果默认保存在当前目录result/dumpOutput_device{0},模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 + +## 6. 精度对比 + +### 6.1 离线推理TopN精度 + +后处理统计TopN精度,调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中: + +```bash +python3.7 vision_metric_ImageNet.py result/dumpOutput_device0/ ../data/sknet/val_label.txt ./ result.json +``` + +第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。查看输出结果: + +```json +{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value": "77.54%"}, {"key": "Top2 accuracy", "value": "87.12%"}, {"key": "Top3 accuracy", "value": "90.73%"}, {"key": "Top4 accuracy", "value": "92.55%"}, {"key": "Top5 accuracy", "value": "93.71%"}]} +``` + +经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 + +### 6.2 精度对比 + +| | TOP1 | TOP5 | +| :----------------: | :------: | :------: | +| 原github仓库精度 | 77.5380% | 93.7000% | +| om模型离线推理精度 | 77.54% | 93.71% | + +将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 + +## 7. 性能对比 + +### 7.1 npu性能数据 + +benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 + +benchmark工具作纯推理时使用的命令参考如下: + +```bash +./benchmark.x86_64 -round=20 -om_path=sknet50_bs1.om -batch_size=1 +``` + +1. batch1 性能 + + 使用benchmark工具在整个数据集上推理时获得的性能数据: + + ``` + [e2e] throughputRate: 143.402, latency: 348669 + [data read] throughputRate: 152.003, moduleLatency: 6.57881 + [preprocess] throughputRate: 151.416, moduleLatency: 6.60433 + [infer] throughputRate: 143.733, Interface throughputRate: 210.306, moduleLatency: 6.16176 + [post] throughputRate: 143.732, moduleLatency: 6.95737 + ``` + + Interface throughputRate: 210.306 * 4 = 841.224 即是batch1 310单卡吞吐率 + +2. batch4 性能 + + ``` + [INFO] ave_throughputRate: 315.424samples/s, ave_latency: 3.30141ms + ``` + + Interface throughputRate: 315.424 * 4 = 1261.696 即是batch4 310单卡吞吐率 + +3. batch8 性能 + + ``` + [INFO] ave_throughputRate: 365.813samples/s, ave_latency: 2.76526ms + ``` + + Interface throughputRate: 365.813 * 4 = 1463.252 即是batch8 310单卡吞吐率 + +4. batch16 性能 + + ``` + [e2e] throughputRate: 196.399, latency: 254584 + [data read] throughputRate: 208.891, moduleLatency: 4.78718 + [preprocess] throughputRate: 207.779, moduleLatency: 4.81281 + [infer] throughputRate: 197.514, Interface throughputRate: 392.072, modul + [post] throughputRate: 12.3443, moduleLatency: 81.0088 + ``` + + Interface throughputRate: 392.072 * 4 = 1568.288 即是batch16 310单卡吞吐率 + +5. batch32 性能 + + ``` + [INFO] ave_throughputRate: 376.691samples/s, ave_latency: 2.66319ms + ``` + + Interface throughputRate: 376.691 * 4 = 1506.764 即是batch32 310单卡吞吐率 + +**性能优化** + +> 从profiling数据的op_statistic_0_1.csv看出影响性能的是transpose算子,从onnx结构图看出该算子用于实现softmax任意轴,由pytorch导出时引入,然而softmax在onnx中现已支持任意轴,故可直接删除该算子提升性能,删除代码参考如下: + +```python +model = onnx.load(args.onnx+'.onnx') +graph = model.graph +node = graph.node +softmax_node_index = [] +del_group = [] +for i in range(len(node)): + if node[i].op_type == 'Softmax': + del_group.append((node[i-1], node[i], node[i+1], i)) +for g in del_group: + new_input = g[0].input + new_output = g[2].output + new_name = g[1].name + new_index = g[3] + new_node = onnx.helper.make_node("Softmax", new_input, new_output, new_name, axis=1) + for n in g[:-1]: + graph.node.remove(n) + graph.node.insert(new_index, new_node) +onnx.save(model, args.onnx+'.onnx') +``` + + + diff --git a/ACL_PyTorch/contrib/cv/classfication/Sknet50/requirements.txt b/ACL_PyTorch/contrib/cv/classfication/Sknet50/requirements.txt index 399dbfed08..fbd453de26 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Sknet50/requirements.txt +++ b/ACL_PyTorch/contrib/cv/classfication/Sknet50/requirements.txt @@ -1,6 +1,6 @@ -torch == 1.5.0 -torchvision == 0.6.0 -onnx == 1.9.0 -numpy == 1.19.2 -Pillow == 8.2.0 +torch == 1.5.0 +torchvision == 0.6.0 +onnx == 1.9.0 +numpy == 1.19.2 +Pillow == 8.2.0 opencv-python == 4.5.2 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Sknet50/test/README.md b/ACL_PyTorch/contrib/cv/classfication/Sknet50/test/README.md index 11114dc96f..3c3e2de286 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Sknet50/test/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/Sknet50/test/README.md @@ -1,26 +1,26 @@ -环境准备: - -1.数据集路径 -数据集统一放在/root/datasets/或/opt/npu/ -本模型数据集放在/opt/npu/ - -2.进入工作目录 -cd Sknet50 - -3.安装必要的依赖 -pip3.7 install -r requirements.txt - -4.获取模型代码 -git clone https://github.com/implus/PytorchInsight - -5.如果使用补丁文件修改了模型代码则将补丁打入模型代码,如果需要引用模型代码仓的类或函数通过sys.path.append()添加搜索路径。 - -5.获取权重文件 -[SK-ResNet50预训练pth权重文件(百度网盘,提取码:tfwn)](https://pan.baidu.com/s/1Lx5CNUeRQXOSWjzTlcO2HQ) - -7.获取benchmark工具 -将benchmark.x86_64放在当前目录 - -8.310上执行,执行时确保device空闲 -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets +环境准备: + +1.数据集路径 +数据集统一放在/root/datasets/或/opt/npu/ +本模型数据集放在/opt/npu/ + +2.进入工作目录 +cd Sknet50 + +3.安装必要的依赖 +pip3.7 install -r requirements.txt + +4.获取模型代码 +git clone https://github.com/implus/PytorchInsight + +5.如果使用补丁文件修改了模型代码则将补丁打入模型代码,如果需要引用模型代码仓的类或函数通过sys.path.append()添加搜索路径。 + +5.获取权重文件 +[SK-ResNet50预训练pth权重文件(百度网盘,提取码:tfwn)](https://pan.baidu.com/s/1Lx5CNUeRQXOSWjzTlcO2HQ) + +7.获取benchmark工具 +将benchmark.x86_64放在当前目录 + +8.310上执行,执行时确保device空闲 +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets diff --git a/ACL_PyTorch/contrib/cv/classfication/Sknet50/test/parse.py b/ACL_PyTorch/contrib/cv/classfication/Sknet50/test/parse.py index b9c74f41d7..82af69cd18 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Sknet50/test/parse.py +++ b/ACL_PyTorch/contrib/cv/classfication/Sknet50/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/TNT/README.md b/ACL_PyTorch/contrib/cv/classfication/TNT/README.md index 9debc2c022..68b21918df 100644 --- a/ACL_PyTorch/contrib/cv/classfication/TNT/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/TNT/README.md @@ -1,44 +1,44 @@ -# TNT模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -``` -pip3.7 install -r requirements.txt -``` - - -2.获取,修改与安装开源模型代码 -``` -git clone https://github.com/huawei-noah/CV-Backbones.git -cd CV-Backbones -git checkout 7a0760f0b77c2e9ae585dcadfd34ff7575839ace -patch tnt_pytorch/tnt.py ../TNT.patch -cd .. -cp CV-Backbones/tnt_pytorch/tnt.py . -``` - -3.获取权重文件 - -tnt_s_81.5.pth.tar - -4.数据集 -获取ImageNet 2012 - -5.[获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) -将benchmark.x86_64或benchmark.aarch64放到当前目录 - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets -``` - **评测结果:** -| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | -| :------: | :------: | :------: | :------: | :------: | -| TNT bs1 | [rank1:81.5%](https://github.com/huawei-noah/CV-Backbones/tree/master/tnt_pytorch) | rank1:81.5% | 89fps | 33fps | -| TNT bs16 | [rank1:81.5%](https://github.com/huawei-noah/CV-Backbones/tree/master/tnt_pytorch) | rank1:81.5% | 181fps| 83fps | - - +# TNT模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +``` +pip3.7 install -r requirements.txt +``` + + +2.获取,修改与安装开源模型代码 +``` +git clone https://github.com/huawei-noah/CV-Backbones.git +cd CV-Backbones +git checkout 7a0760f0b77c2e9ae585dcadfd34ff7575839ace +patch tnt_pytorch/tnt.py ../TNT.patch +cd .. +cp CV-Backbones/tnt_pytorch/tnt.py . +``` + +3.获取权重文件 + +tnt_s_81.5.pth.tar + +4.数据集 +获取ImageNet 2012 + +5.[获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) +将benchmark.x86_64或benchmark.aarch64放到当前目录 + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets +``` + **评测结果:** +| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | +| :------: | :------: | :------: | :------: | :------: | +| TNT bs1 | [rank1:81.5%](https://github.com/huawei-noah/CV-Backbones/tree/master/tnt_pytorch) | rank1:81.5% | 89fps | 33fps | +| TNT bs16 | [rank1:81.5%](https://github.com/huawei-noah/CV-Backbones/tree/master/tnt_pytorch) | rank1:81.5% | 181fps| 83fps | + + diff --git a/ACL_PyTorch/contrib/cv/classfication/TNT/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/classfication/TNT/modelzoo_level.txt index 38700fca05..2e42553460 100644 --- a/ACL_PyTorch/contrib/cv/classfication/TNT/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/classfication/TNT/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/TResNet/LICENSE b/ACL_PyTorch/contrib/cv/classfication/TResNet/LICENSE index 26aed103da..33a78d69ac 100644 --- a/ACL_PyTorch/contrib/cv/classfication/TResNet/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/TResNet/LICENSE @@ -1,25 +1,25 @@ -BSD 3-Clause License - -Copyright (c) 2018, Multimedia Laboratary, The Chinese University of Hong Kong -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +BSD 3-Clause License + +Copyright (c) 2018, Multimedia Laboratary, The Chinese University of Hong Kong +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/TResNet/README.md b/ACL_PyTorch/contrib/cv/classfication/TResNet/README.md index b0453f5fb7..4e4d1bf3ef 100644 --- a/ACL_PyTorch/contrib/cv/classfication/TResNet/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/TResNet/README.md @@ -1,37 +1,37 @@ -# TResNet离线推理指导 - -## 1.环境准备 -以路径${MODEL_ZOO_PATH}/contrib/ACL_PyTorch/Research/cv/classification/TResNet/作为当前目录 - -1.安装必备的依赖 - -``` -pip3.7 install -r requirements.txt -``` - -2.由于没有开源社区的权重,因此需要将训练得到的权重model_best.pth.tar放到当前目录 - -3.获取数据集imagenet,并且以${Path}/imagenet/val作为datasets_path,这将在下面用到 - -4.获取数据集imagenet的val_label.txt,并且以${Path}/val_label.txt作为val_label_path,这将在下面用到 - -5.获取benchmark工具 - -将benchmark.x86_64放到当前目录 - -6.(重要)请确保您的CANN环境为5.0.3.alpha003,以确保能获得最佳性能 - -7.(重要)由于有算子涉及到了TransposeD,因此请将以下shape添加至白名单[ 1,3, 224, 224],[ 1, 3, 56, 4, 56, 4],[ 1, 4, 4, 3, 56, 56], - [ 16, 3, 224, 224],[ 16, 3, 56, 4, 56, 4], [ 16, 4, 4, 3, 56, 56] -8.请确保您能连接github以获取模型源码 - -## 2.离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 - -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets/imagenet/val --val_label_path=/root/datasets/imagenet/val_label.txt -bash test/perf_g.sh -``` - +# TResNet离线推理指导 + +## 1.环境准备 +以路径${MODEL_ZOO_PATH}/contrib/ACL_PyTorch/Research/cv/classification/TResNet/作为当前目录 + +1.安装必备的依赖 + +``` +pip3.7 install -r requirements.txt +``` + +2.由于没有开源社区的权重,因此需要将训练得到的权重model_best.pth.tar放到当前目录 + +3.获取数据集imagenet,并且以${Path}/imagenet/val作为datasets_path,这将在下面用到 + +4.获取数据集imagenet的val_label.txt,并且以${Path}/val_label.txt作为val_label_path,这将在下面用到 + +5.获取benchmark工具 + +将benchmark.x86_64放到当前目录 + +6.(重要)请确保您的CANN环境为5.0.3.alpha003,以确保能获得最佳性能 + +7.(重要)由于有算子涉及到了TransposeD,因此请将以下shape添加至白名单[ 1,3, 224, 224],[ 1, 3, 56, 4, 56, 4],[ 1, 4, 4, 3, 56, 56], + [ 16, 3, 224, 224],[ 16, 3, 56, 4, 56, 4], [ 16, 4, 4, 3, 56, 56] +8.请确保您能连接github以获取模型源码 + +## 2.离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 + +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets/imagenet/val --val_label_path=/root/datasets/imagenet/val_label.txt +bash test/perf_g.sh +``` + diff --git a/ACL_PyTorch/contrib/cv/classfication/TResNet/TResNet_postprocess.py b/ACL_PyTorch/contrib/cv/classfication/TResNet/TResNet_postprocess.py index 7b1037e75d..6074772942 100644 --- a/ACL_PyTorch/contrib/cv/classfication/TResNet/TResNet_postprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/TResNet/TResNet_postprocess.py @@ -1,184 +1,184 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - if data == '': - n_label = 0 - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = 0 - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - - resCnt = min(len(sort_index), topn) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - print(table_dict) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) - print("Time used:", elapsed) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + if data == '': + n_label = 0 + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = 0 + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + + resCnt = min(len(sort_index), topn) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + print(table_dict) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) + print("Time used:", elapsed) diff --git a/ACL_PyTorch/contrib/cv/classfication/TResNet/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/classfication/TResNet/modelzoo_level.txt index 7313992239..108cc882d6 100644 --- a/ACL_PyTorch/contrib/cv/classfication/TResNet/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/classfication/TResNet/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:PERFECT \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/LICENSE b/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/LICENSE index 67596b0702..3d33284651 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/README.md b/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/README.md index 11c40ae354..40d2d9e841 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/README.md @@ -1,313 +1,313 @@ -# Wide_ResNet101_2 Onnx模型端到端推理指导 - -- [1 模型概述](#1-模型概述) - - - [1.1 论文地址](#11-论文地址) - - [1.2 代码地址](#12-代码地址) - -- [2 环境说明](#2-环境说明) - - [2.1 深度学习框架](#21-深度学习框架) - - [2.2 python第三方库](#22-python第三方库) - -- [3 模型转换](#3-模型转换) - - [3.1 pth转onnx模型](#31-pth转onnx模型) - - [3.2 onnx转om模型](#32-onnx转om模型) - -- [4 数据集预处理](#4-数据集预处理) - - - [4.1 数据集获取](#41-数据集获取) - - [4.2 数据集预处理](#42-数据集预处理) - - [4.3 生成数据集信息文件](#43-生成数据集信息文件) - -- [5 离线推理](#5-离线推理) - - [5.1 benchmark工具概述](#51-benchmark工具概述) - - [5.2 离线推理](#52-离线推理) - -- [6 精度对比](#6-精度对比) - - [6.1 离线推理精度统计](#61-离线推理精度统计) - - [6.2 开源精度](#62-开源精度) - - [6.3 精度对比](#63-精度对比) - -- [7 性能对比](#7-性能对比) - - - [7.1 npu性能数据](#71-npu性能数据) - - - - - -## 1 模型概述 - -- **[论文地址](#11-论文地址)** - -- **[代码地址](#12-代码地址)** - -### 1.1 论文地址 - -[Wide_ResNet论文](https://arxiv.org/pdf/1605.07146.pdf) - -### 1.2 代码地址 - -[Wide_ResNet代码](https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py) - -branch:master -commit id:7d955df73fe0e9b47f7d6c77c699324b256fc41f - -## 2 环境说明 - -- **[深度学习框架](#21-深度学习框架)** - -- **[python第三方库](#22-python第三方库)** - -### 2.1 深度学习框架 - -``` -CANN 5.0.1 - -pytorch >= 1.5.0 -torchvision >= 0.6.0 -onnx >= 1.7.0 -``` - -### 2.2 python第三方库 - -``` -numpy == 1.18.5 -Pillow == 7.2.0 -opencv-python == 4.2.0.34 -``` - -**说明:** -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3 模型转换 - -- **[pth转onnx模型](#31-pth转onnx模型)** - -- **[onnx转om模型](#32-onnx转om模型)** - -### 3.1 pth转onnx模型 - -1. 下载pth权重文件 - -[wrn101_2权重文件下载](https://download.pytorch.org/models/wide_resnet101_2-32ee1156.pth) - -文件md5sum: 5961435974bb43104b5a3180fea7c2c4 - -``` -wget https://download.pytorch.org/models/wide_resnet101_2-32ee1156.pth -``` - - - -2. 下载模型代码 - -``` -git clone https://github.com/pytorch/vision -cd vision -git reset 7d955df73fe0e9b47f7d6c77c699324b256fc41f --hard -python3.7 setup.py install -cd .. -``` - -3. 编写pth2onnx脚本wrn101_2_pth2onnx.py - - **说明:** ->注意目前ATC支持的onnx算子版本为11 - -4. 执行pth2onnx脚本,生成onnx模型文件 - - -```python -python3.7 wrn101_2_pth2onnx.py wide_resnet101_2-32ee1156.pth wrn101_2_pth.onnx -``` - - **模型转换要点:** ->此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 - -### 3.2 onnx转om模型 - -1.设置环境变量 - -```python -source env.sh -``` -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.1 开发辅助工具指南 (推理) 01 - -```python -atc --framework=5 --model=wrn101_2_pth.onnx --output=wrn101_2_bs16 --input_format=NCHW --input_shape="image:16,3,224,224" --log=debug --soc_version=Ascend310 -``` - - - -## 4 数据集预处理 - -- **[数据集获取](#41-数据集获取)** - -- **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - -### 4.1 数据集获取 -该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/opt/npu/imagenet/val与/opt/npu/imagenet/val_label.txt - -### 4.2 数据集预处理 - -1.预处理脚本imagenet_torch_preprocess.py - -2.执行预处理脚本,生成数据集预处理后的bin文件 - -``` -python3.7 imagenet_torch_preprocess.py resnet /opt/npu/imagenet/val ./prep_dataset -``` -### 4.3 生成数据集信息文件 - -1.生成数据集信息文件脚本gen_dataset_info.py - -2.执行生成数据集信息脚本,生成数据集信息文件 - -```python -python3.7 gen_dataset_info.py bin ./prep_dataset ./wrn101_2_prep_bin.info 224 224 -``` -第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 - -## 5 离线推理 - -- **[benchmark工具概述](#51-benchmark工具概述)** - -- **[离线推理](#52-离线推理)** - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN V100R020C10 推理benchmark工具用户指南 01 - -### 5.2 离线推理 - -1.设置环境变量 - -``` -source env.sh -``` -2.执行离线推理 - -```python -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=16 -om_path=wrn101_2_bs16.om -input_text_path=./wrn101_2_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False -``` -输出结果默认保存在当前目录result/dumpOutput_device{0},模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 - -## 6 精度对比 - -- **[离线推理精度](#61-离线推理精度)** -- **[开源精度](#62-开源精度)** -- **[精度对比](#63-精度对比)** - -### 6.1 离线推理精度统计 - -后处理统计TopN精度 - -调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 -``` -python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /opt/npu/imagenet/val_label.txt ./ result.json -``` -第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 -查看输出结果: - -``` -{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value": "78.84%"}, {"key": "Top2 accuracy", "value": "88.41%"}, {"key": "Top3 accuracy", "value": "91.66%"}, {"key": "Top4 accuracy", "value": "93.26%"}, {"key": "Top5 accuracy", "value": "94.29%"}]} -``` - -### 6.2 开源精度 - -[torchvision官网精度](https://pytorch.org/vision/stable/models.html) - -``` -Model Acc@1 Acc@5 -wide_resnet101_2 78.848 94.284 -``` -### 6.3 精度对比 - -将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,统计结果如下。精度下降在1%范围之内,故精度达标。 - -``` - Acc@1 Acc@5 -bs1 78.84 94.29 -bs16 78.85 94.29 -``` - - **精度调试:** - ->没有遇到精度不达标的问题,故不需要进行精度调试 - -## 7 性能对比 - -- **[npu性能数据](#71-npu性能数据)** - -### 7.1 npu性能数据 - -benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 - -1.benchmark工具在整个数据集上推理获得性能数据 - -batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: - -``` -[e2e] throughputRate: 105.142, latency: 475550 -[data read] throughputRate: 111.355, moduleLatency: 8.98031 -[preprocess] throughputRate: 111.053, moduleLatency: 9.00469 -[infer] throughputRate: 105.494, Interface throughputRate: 127.878, moduleLatency: 8.77965 -[post] throughputRate: 105.494, moduleLatency: 9.47924 -``` - -Interface throughputRate: 127.878,127.878x4=511.512即是batch1 310单卡吞吐率 - -batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: - -``` -[e2e] throughputRate: 117.321, latency: 426182 -[data read] throughputRate: 124.66, moduleLatency: 8.0218 -[preprocess] throughputRate: 124.054, moduleLatency: 8.06101 -[infer] throughputRate: 117.825, Interface throughputRate: 169.604, moduleLatency: 7.35524 -[post] throughputRate: 7.36397, moduleLatency: 135.796 -``` - -Interface throughputRate: 169.604,169.604x4=678.416即是batch1 310单卡吞吐率 - -batch4性能: - -``` -[e2e] throughputRate: 114.374, latency: 437161 -[data read] throughputRate: 121.259, moduleLatency: 8.2468 -[preprocess] throughputRate: 121.014, moduleLatency: 8.26352 -[infer] throughputRate: 114.92, Interface throughputRate: 157.07, moduleLatency: 7.83108 -[post] throughputRate: 28.73, moduleLatency: 34.8068 -``` - -batch4 310单卡吞吐率:157.07x4=628.28fps -batch8性能: - -``` -[e2e] throughputRate: 111.341, latency: 449071 -[data read] throughputRate: 117.759, moduleLatency: 8.49194 -[preprocess] throughputRate: 117.55, moduleLatency: 8.50701 -[infer] throughputRate: 111.703, Interface throughputRate: 156.132, moduleLatency: 7.85466 -[post] throughputRate: 13.9628, moduleLatency: 71.6188 -``` - -batch8 310单卡吞吐率:156.132x4=624.528fps -batch32性能: - -``` -[e2e] throughputRate: 102.387, latency: 488344 -[data read] throughputRate: 108.61, moduleLatency: 9.20728 -[preprocess] throughputRate: 108.389, moduleLatency: 9.22602 -[infer] throughputRate: 102.81, Interface throughputRate: 139.595, moduleLatency: 8.59119 -[post] throughputRate: 3.2138, moduleLatency: 311.159 -``` - -batch32 310单卡吞吐率:139.595x4=558.38fps - -**性能优化:** - -> 对于batch32的性能不达标,从profiling数据的op_statistic_0_1.csv看出影响性能的是Conv2D算子,从op_summary_0_1.csv看出单个Conv_Relu算子耗时0.6毫秒到12毫秒,shape大的耗时就多,不存在优化问题 +# Wide_ResNet101_2 Onnx模型端到端推理指导 + +- [1 模型概述](#1-模型概述) + + - [1.1 论文地址](#11-论文地址) + - [1.2 代码地址](#12-代码地址) + +- [2 环境说明](#2-环境说明) + - [2.1 深度学习框架](#21-深度学习框架) + - [2.2 python第三方库](#22-python第三方库) + +- [3 模型转换](#3-模型转换) + - [3.1 pth转onnx模型](#31-pth转onnx模型) + - [3.2 onnx转om模型](#32-onnx转om模型) + +- [4 数据集预处理](#4-数据集预处理) + + - [4.1 数据集获取](#41-数据集获取) + - [4.2 数据集预处理](#42-数据集预处理) + - [4.3 生成数据集信息文件](#43-生成数据集信息文件) + +- [5 离线推理](#5-离线推理) + - [5.1 benchmark工具概述](#51-benchmark工具概述) + - [5.2 离线推理](#52-离线推理) + +- [6 精度对比](#6-精度对比) + - [6.1 离线推理精度统计](#61-离线推理精度统计) + - [6.2 开源精度](#62-开源精度) + - [6.3 精度对比](#63-精度对比) + +- [7 性能对比](#7-性能对比) + + - [7.1 npu性能数据](#71-npu性能数据) + + + + + +## 1 模型概述 + +- **[论文地址](#11-论文地址)** + +- **[代码地址](#12-代码地址)** + +### 1.1 论文地址 + +[Wide_ResNet论文](https://arxiv.org/pdf/1605.07146.pdf) + +### 1.2 代码地址 + +[Wide_ResNet代码](https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py) + +branch:master +commit id:7d955df73fe0e9b47f7d6c77c699324b256fc41f + +## 2 环境说明 + +- **[深度学习框架](#21-深度学习框架)** + +- **[python第三方库](#22-python第三方库)** + +### 2.1 深度学习框架 + +``` +CANN 5.0.1 + +pytorch >= 1.5.0 +torchvision >= 0.6.0 +onnx >= 1.7.0 +``` + +### 2.2 python第三方库 + +``` +numpy == 1.18.5 +Pillow == 7.2.0 +opencv-python == 4.2.0.34 +``` + +**说明:** +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3 模型转换 + +- **[pth转onnx模型](#31-pth转onnx模型)** + +- **[onnx转om模型](#32-onnx转om模型)** + +### 3.1 pth转onnx模型 + +1. 下载pth权重文件 + +[wrn101_2权重文件下载](https://download.pytorch.org/models/wide_resnet101_2-32ee1156.pth) + +文件md5sum: 5961435974bb43104b5a3180fea7c2c4 + +``` +wget https://download.pytorch.org/models/wide_resnet101_2-32ee1156.pth +``` + + + +2. 下载模型代码 + +``` +git clone https://github.com/pytorch/vision +cd vision +git reset 7d955df73fe0e9b47f7d6c77c699324b256fc41f --hard +python3.7 setup.py install +cd .. +``` + +3. 编写pth2onnx脚本wrn101_2_pth2onnx.py + + **说明:** +>注意目前ATC支持的onnx算子版本为11 + +4. 执行pth2onnx脚本,生成onnx模型文件 + + +```python +python3.7 wrn101_2_pth2onnx.py wide_resnet101_2-32ee1156.pth wrn101_2_pth.onnx +``` + + **模型转换要点:** +>此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 + +### 3.2 onnx转om模型 + +1.设置环境变量 + +```python +source env.sh +``` +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.1 开发辅助工具指南 (推理) 01 + +```python +atc --framework=5 --model=wrn101_2_pth.onnx --output=wrn101_2_bs16 --input_format=NCHW --input_shape="image:16,3,224,224" --log=debug --soc_version=Ascend310 +``` + + + +## 4 数据集预处理 + +- **[数据集获取](#41-数据集获取)** + +- **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + +### 4.1 数据集获取 +该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/opt/npu/imagenet/val与/opt/npu/imagenet/val_label.txt + +### 4.2 数据集预处理 + +1.预处理脚本imagenet_torch_preprocess.py + +2.执行预处理脚本,生成数据集预处理后的bin文件 + +``` +python3.7 imagenet_torch_preprocess.py resnet /opt/npu/imagenet/val ./prep_dataset +``` +### 4.3 生成数据集信息文件 + +1.生成数据集信息文件脚本gen_dataset_info.py + +2.执行生成数据集信息脚本,生成数据集信息文件 + +```python +python3.7 gen_dataset_info.py bin ./prep_dataset ./wrn101_2_prep_bin.info 224 224 +``` +第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 + +## 5 离线推理 + +- **[benchmark工具概述](#51-benchmark工具概述)** + +- **[离线推理](#52-离线推理)** + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN V100R020C10 推理benchmark工具用户指南 01 + +### 5.2 离线推理 + +1.设置环境变量 + +``` +source env.sh +``` +2.执行离线推理 + +```python +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=16 -om_path=wrn101_2_bs16.om -input_text_path=./wrn101_2_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False +``` +输出结果默认保存在当前目录result/dumpOutput_device{0},模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 + +## 6 精度对比 + +- **[离线推理精度](#61-离线推理精度)** +- **[开源精度](#62-开源精度)** +- **[精度对比](#63-精度对比)** + +### 6.1 离线推理精度统计 + +后处理统计TopN精度 + +调用imagenet_acc_eval.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 +``` +python3.7 imagenet_acc_eval.py result/dumpOutput_device0/ /opt/npu/imagenet/val_label.txt ./ result.json +``` +第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 +查看输出结果: + +``` +{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value": "78.84%"}, {"key": "Top2 accuracy", "value": "88.41%"}, {"key": "Top3 accuracy", "value": "91.66%"}, {"key": "Top4 accuracy", "value": "93.26%"}, {"key": "Top5 accuracy", "value": "94.29%"}]} +``` + +### 6.2 开源精度 + +[torchvision官网精度](https://pytorch.org/vision/stable/models.html) + +``` +Model Acc@1 Acc@5 +wide_resnet101_2 78.848 94.284 +``` +### 6.3 精度对比 + +将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,统计结果如下。精度下降在1%范围之内,故精度达标。 + +``` + Acc@1 Acc@5 +bs1 78.84 94.29 +bs16 78.85 94.29 +``` + + **精度调试:** + +>没有遇到精度不达标的问题,故不需要进行精度调试 + +## 7 性能对比 + +- **[npu性能数据](#71-npu性能数据)** + +### 7.1 npu性能数据 + +benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 + +1.benchmark工具在整个数据集上推理获得性能数据 + +batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: + +``` +[e2e] throughputRate: 105.142, latency: 475550 +[data read] throughputRate: 111.355, moduleLatency: 8.98031 +[preprocess] throughputRate: 111.053, moduleLatency: 9.00469 +[infer] throughputRate: 105.494, Interface throughputRate: 127.878, moduleLatency: 8.77965 +[post] throughputRate: 105.494, moduleLatency: 9.47924 +``` + +Interface throughputRate: 127.878,127.878x4=511.512即是batch1 310单卡吞吐率 + +batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: + +``` +[e2e] throughputRate: 117.321, latency: 426182 +[data read] throughputRate: 124.66, moduleLatency: 8.0218 +[preprocess] throughputRate: 124.054, moduleLatency: 8.06101 +[infer] throughputRate: 117.825, Interface throughputRate: 169.604, moduleLatency: 7.35524 +[post] throughputRate: 7.36397, moduleLatency: 135.796 +``` + +Interface throughputRate: 169.604,169.604x4=678.416即是batch1 310单卡吞吐率 + +batch4性能: + +``` +[e2e] throughputRate: 114.374, latency: 437161 +[data read] throughputRate: 121.259, moduleLatency: 8.2468 +[preprocess] throughputRate: 121.014, moduleLatency: 8.26352 +[infer] throughputRate: 114.92, Interface throughputRate: 157.07, moduleLatency: 7.83108 +[post] throughputRate: 28.73, moduleLatency: 34.8068 +``` + +batch4 310单卡吞吐率:157.07x4=628.28fps +batch8性能: + +``` +[e2e] throughputRate: 111.341, latency: 449071 +[data read] throughputRate: 117.759, moduleLatency: 8.49194 +[preprocess] throughputRate: 117.55, moduleLatency: 8.50701 +[infer] throughputRate: 111.703, Interface throughputRate: 156.132, moduleLatency: 7.85466 +[post] throughputRate: 13.9628, moduleLatency: 71.6188 +``` + +batch8 310单卡吞吐率:156.132x4=624.528fps +batch32性能: + +``` +[e2e] throughputRate: 102.387, latency: 488344 +[data read] throughputRate: 108.61, moduleLatency: 9.20728 +[preprocess] throughputRate: 108.389, moduleLatency: 9.22602 +[infer] throughputRate: 102.81, Interface throughputRate: 139.595, moduleLatency: 8.59119 +[post] throughputRate: 3.2138, moduleLatency: 311.159 +``` + +batch32 310单卡吞吐率:139.595x4=558.38fps + +**性能优化:** + +> 对于batch32的性能不达标,从profiling数据的op_statistic_0_1.csv看出影响性能的是Conv2D算子,从op_summary_0_1.csv看出单个Conv_Relu算子耗时0.6毫秒到12毫秒,shape大的耗时就多,不存在优化问题 diff --git a/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/gen_dataset_info.py index 61450b4410..5381839f65 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/gen_dataset_info.py @@ -1,61 +1,61 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' - get_jpg_info(file_path, info_name) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' + get_jpg_info(file_path, info_name) + diff --git a/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/requirements.txt b/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/requirements.txt index e201023141..2f94093388 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/requirements.txt +++ b/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/requirements.txt @@ -1,6 +1,6 @@ -torch == 1.8.1 -torchvision == 0.9.1 -onnx == 1.7.0 -numpy == 1.18.5 -Pillow == 7.2.0 +torch == 1.8.1 +torchvision == 0.9.1 +onnx == 1.7.0 +numpy == 1.18.5 +Pillow == 7.2.0 opencv-python == 4.2.0.34 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/test/README.md b/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/test/README.md index e28e57fceb..66ad246d36 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/test/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/test/README.md @@ -1,48 +1,48 @@ -环境准备: - -1.数据集路径 -通用的数据集统一放在/root/datasets/或/opt/npu/ -本模型数据集放在/opt/npu/ - -2.进入工作目录 - -``` -cd Wide_ResNet101_2 -``` - -3.安装必要的依赖 - -``` -pip3.7 install -r requirements.txt -``` - -4.获取模型代码 - -``` -git clone https://github.com/pytorch/vision -``` - -5.如果模型代码需要安装,则安装模型代码 - -``` -cd vision -git reset 7d955df73fe0e9b47f7d6c77c699324b256fc41f --hard -python3.7 setup.py install -cd .. -``` - -6.获取权重文件 - -``` -wget https://download.pytorch.org/models/wide_resnet101_2-32ee1156.pth -``` - -7.获取benchmark工具 -将benchmark.x86_64 放在当前目录 - -8.310上执行,执行时确保device空闲 - -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/opt/npu/ -``` +环境准备: + +1.数据集路径 +通用的数据集统一放在/root/datasets/或/opt/npu/ +本模型数据集放在/opt/npu/ + +2.进入工作目录 + +``` +cd Wide_ResNet101_2 +``` + +3.安装必要的依赖 + +``` +pip3.7 install -r requirements.txt +``` + +4.获取模型代码 + +``` +git clone https://github.com/pytorch/vision +``` + +5.如果模型代码需要安装,则安装模型代码 + +``` +cd vision +git reset 7d955df73fe0e9b47f7d6c77c699324b256fc41f --hard +python3.7 setup.py install +cd .. +``` + +6.获取权重文件 + +``` +wget https://download.pytorch.org/models/wide_resnet101_2-32ee1156.pth +``` + +7.获取benchmark工具 +将benchmark.x86_64 放在当前目录 + +8.310上执行,执行时确保device空闲 + +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/opt/npu/ +``` diff --git a/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/test/parse.py b/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/test/parse.py index a0f253b055..27eae0d0ac 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/test/parse.py +++ b/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/wrn101_2_pth2onnx.py b/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/wrn101_2_pth2onnx.py index 41e36408ff..6395fdddcf 100644 --- a/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/wrn101_2_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2/wrn101_2_pth2onnx.py @@ -1,35 +1,35 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -import torch -import torch.onnx -import torchvision.models as models - -def pth2onnx(input_file, output_file): - model = models.wide_resnet101_2(pretrained=False) - checkpoint = torch.load(input_file, map_location=None) - model.load_state_dict(checkpoint) - - model.eval() - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.randn(1, 3, 224, 224) - torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=True, opset_version=11) - -if __name__ == "__main__": - input_file = sys.argv[1] - output_file = sys.argv[2] +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +import torch +import torch.onnx +import torchvision.models as models + +def pth2onnx(input_file, output_file): + model = models.wide_resnet101_2(pretrained=False) + checkpoint = torch.load(input_file, map_location=None) + model.load_state_dict(checkpoint) + + model.eval() + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.randn(1, 3, 224, 224) + torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=True, opset_version=11) + +if __name__ == "__main__": + input_file = sys.argv[1] + output_file = sys.argv[2] pth2onnx(input_file, output_file) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/X3D/LICENSE b/ACL_PyTorch/contrib/cv/classfication/X3D/LICENSE index df2c2f2c3e..c8ec075d5b 100644 --- a/ACL_PyTorch/contrib/cv/classfication/X3D/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/X3D/LICENSE @@ -1,203 +1,203 @@ -Copyright 2018-2019 Open-MMLab. All rights reserved. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018-2019 Open-MMLab. - - 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 +Copyright 2018-2019 Open-MMLab. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2019 Open-MMLab. + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/X3D/README.md b/ACL_PyTorch/contrib/cv/classfication/X3D/README.md index 6453cc151a..7a9e3338e2 100644 --- a/ACL_PyTorch/contrib/cv/classfication/X3D/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/X3D/README.md @@ -1,69 +1,69 @@ -# X3D模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 - -``` -pip3 install -r requirements.txt -``` -2.获取,修改与安装开源模型代码 -``` -git clone https://github.com/facebookresearch/detectron2 detectron2_repo -pip3 install -e detectron2_repo - -git clone https://github.com/facebookresearch/SlowFast -b master -cd SlowFast - -git reset 9839d1318c0ae17bd82c6a121e5640aebc67f126 --hard -patch -p1 < x3d.patch -python3.7 setup.py build develop - -cd .. - -``` -3.[获取权重文件 x3d_s.pyth](https://github.com/facebookresearch/SlowFast/blob/master/MODEL_ZOO.md) - - 将权重文件x3d_s.pyth放在当前目录。 - -4.获取数据集Knetics-400 - -脚本下载: -获取验证集列表文件[val_link.list](https://ai-rank.bj.bcebos.com/Kinetics400/val_link.list)与验证集标签文件[val.list](https://videotag.bj.bcebos.com/PaddleVideo/Data/Kinetic400/val.list),并将val.list重命名为test.csv -下载验证集: -``` -download.sh: -file=$1 - -while read line -do - wget "$line" -done <$file - -download.sh val_link.list -``` -将下载的val_part1,val_part2,val_part3里的400个文件夹放到/root/datasets/Knetics-400/val,将test.csv放到/root/datasets/Knetics-400。 - -5.获取 [msame工具](https://gitee.com/ascend/tools/tree/master/msame) -和 -[benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) - -将msame和benchmark.x86_64(或benchmark.aarch64)放到当前目录 - - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 - -``` -bash test/pth2om.sh -bash test/evl_acc_pref.sh --datasets_path=/root/datasets/Knetics-400 -``` -备注:存在fp16算子溢出,精度不达标,因此atc模型转换需要添加--precision_mode allow_mix_precision - -**评测结果:** - -| 模型 | 官网pth精度 | 310精度 | 基准性能| 310性能 | -| ---- | ------------------------------------------------------------ | --------------- | -------- | ------- | -| X3d bs1 | [Top1:73.1%](https://github.com/facebookresearch/SlowFast/blob/master/MODEL_ZOO.md) | Top1:72.86% Top5:89.45% | 95.07fps | 158.57fps | +# X3D模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 + +``` +pip3 install -r requirements.txt +``` +2.获取,修改与安装开源模型代码 +``` +git clone https://github.com/facebookresearch/detectron2 detectron2_repo +pip3 install -e detectron2_repo + +git clone https://github.com/facebookresearch/SlowFast -b master +cd SlowFast + +git reset 9839d1318c0ae17bd82c6a121e5640aebc67f126 --hard +patch -p1 < x3d.patch +python3.7 setup.py build develop + +cd .. + +``` +3.[获取权重文件 x3d_s.pyth](https://github.com/facebookresearch/SlowFast/blob/master/MODEL_ZOO.md) + + 将权重文件x3d_s.pyth放在当前目录。 + +4.获取数据集Knetics-400 + +脚本下载: +获取验证集列表文件[val_link.list](https://ai-rank.bj.bcebos.com/Kinetics400/val_link.list)与验证集标签文件[val.list](https://videotag.bj.bcebos.com/PaddleVideo/Data/Kinetic400/val.list),并将val.list重命名为test.csv +下载验证集: +``` +download.sh: +file=$1 + +while read line +do + wget "$line" +done <$file + +download.sh val_link.list +``` +将下载的val_part1,val_part2,val_part3里的400个文件夹放到/root/datasets/Knetics-400/val,将test.csv放到/root/datasets/Knetics-400。 + +5.获取 [msame工具](https://gitee.com/ascend/tools/tree/master/msame) +和 +[benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) + +将msame和benchmark.x86_64(或benchmark.aarch64)放到当前目录 + + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 + +``` +bash test/pth2om.sh +bash test/evl_acc_pref.sh --datasets_path=/root/datasets/Knetics-400 +``` +备注:存在fp16算子溢出,精度不达标,因此atc模型转换需要添加--precision_mode allow_mix_precision + +**评测结果:** + +| 模型 | 官网pth精度 | 310精度 | 基准性能| 310性能 | +| ---- | ------------------------------------------------------------ | --------------- | -------- | ------- | +| X3d bs1 | [Top1:73.1%](https://github.com/facebookresearch/SlowFast/blob/master/MODEL_ZOO.md) | Top1:72.86% Top5:89.45% | 95.07fps | 158.57fps | | X3d bs16| [Top1:73.1%](https://github.com/facebookresearch/SlowFast/blob/master/MODEL_ZOO.md) | Top1:72.86% Top5:89.45% | 103.82fps | 115.34fps | \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/LICENSE b/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/README.md b/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/README.md index 340b66fc5d..952c95a916 100644 --- a/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/README.md @@ -1,46 +1,46 @@ -# Dino_Resnet50模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -``` -pip3.7 install -r requirements.txt -``` - - -2.获取开源模型代码 -``` -git clone https://github.com/facebooksearch/dino -``` - -3.获取权重文件 - - [获取权重文件](https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/classfication/DINO/dino_resnet50_linearweights.pth) - [获取权重文件](https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/classfication/DINO/dino_resnet50_pretrain.pth) - -4.数据集 -自行获取LSVRC2012验证集和标签文本 - -5.[获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) -将benchmark.x86_64放到当前工作目录 - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 -``` -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp -export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest -bash test/pth2om.sh -bash test/eval_acc_perf.sh -``` -pth2om.sh文件第1到6行是转onnx,第8到20行是转om -eval_acc_perf.sh文件第24到54行是精度,第55到66行是性能 - **评测结果:** -| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | -| :------: | :------: | :------: | :------: | :------: | -| dino_resnet50_bs1 | [top1: 75.3%](https://github.com/facebookresearch/dino#evaluation-linear-classification-on-imagenet) | top1: 75.27% | 891.845fps | 1521.508fps | +# Dino_Resnet50模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +``` +pip3.7 install -r requirements.txt +``` + + +2.获取开源模型代码 +``` +git clone https://github.com/facebooksearch/dino +``` + +3.获取权重文件 + + [获取权重文件](https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/classfication/DINO/dino_resnet50_linearweights.pth) + [获取权重文件](https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/classfication/DINO/dino_resnet50_pretrain.pth) + +4.数据集 +自行获取LSVRC2012验证集和标签文本 + +5.[获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) +将benchmark.x86_64放到当前工作目录 + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 +``` +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp +export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest +bash test/pth2om.sh +bash test/eval_acc_perf.sh +``` +pth2om.sh文件第1到6行是转onnx,第8到20行是转om +eval_acc_perf.sh文件第24到54行是精度,第55到66行是性能 + **评测结果:** +| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | +| :------: | :------: | :------: | :------: | :------: | +| dino_resnet50_bs1 | [top1: 75.3%](https://github.com/facebookresearch/dino#evaluation-linear-classification-on-imagenet) | top1: 75.27% | 891.845fps | 1521.508fps | | dino_resnet50_bs16 | [top1: 75.3%](https://github.com/facebookresearch/dino#evaluation-linear-classification-on-imagenet) | top1: 75.27% | 2003.345fps | 2406.68fps | \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/dino_resnet50_postprocess.py b/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/dino_resnet50_postprocess.py index 4b5b462ff7..2b0acb41e5 100644 --- a/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/dino_resnet50_postprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/dino_resnet50_postprocess.py @@ -1,169 +1,169 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import json -import numpy as np -import argparse - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - if data == '': - n_label = 0 - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_file, img_gt_dict, - topn=5): - """ - :param prediction_file_path: - :param result_file: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(result_file, 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - - resCnt = min(len(sort_index), topn) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - json.dump(table_dict, writer) - writer.close() - - -def check_args(args): - if not (os.path.exists(args.anno_file)): - print("annotation file:{} does not exist.".format(args.anno_file)) - exit() - if not (os.path.exists(args.benchmark_out)): - print("benchmark output:{} does not exist.".format(args.benchmark_out)) - exit() - return args - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Precision statistics of Vision model') - parser.add_argument("--anno_file", default="./HiAI_label.json", help='annotation file') - parser.add_argument("--benchmark_out", default="result/dumpOutput_device0", help='Benchmark output directory') - parser.add_argument("--result_file", default="./result.json", help='Output json file') - args = parser.parse_args() - args = check_args(args) - if args.anno_file.endswith('txt'): - img_label_dict = cre_groundtruth_dict_fromtxt(args.anno_file) - else: - img_label_dict = cre_groundtruth_dict(args.anno_file) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import json +import numpy as np +import argparse + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + if data == '': + n_label = 0 + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_file, img_gt_dict, + topn=5): + """ + :param prediction_file_path: + :param result_file: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(result_file, 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + + resCnt = min(len(sort_index), topn) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + json.dump(table_dict, writer) + writer.close() + + +def check_args(args): + if not (os.path.exists(args.anno_file)): + print("annotation file:{} does not exist.".format(args.anno_file)) + exit() + if not (os.path.exists(args.benchmark_out)): + print("benchmark output:{} does not exist.".format(args.benchmark_out)) + exit() + return args + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Precision statistics of Vision model') + parser.add_argument("--anno_file", default="./HiAI_label.json", help='annotation file') + parser.add_argument("--benchmark_out", default="result/dumpOutput_device0", help='Benchmark output directory') + parser.add_argument("--result_file", default="./result.json", help='Output json file') + args = parser.parse_args() + args = check_args(args) + if args.anno_file.endswith('txt'): + img_label_dict = cre_groundtruth_dict_fromtxt(args.anno_file) + else: + img_label_dict = cre_groundtruth_dict(args.anno_file) create_visualization_statistical_result(args.benchmark_out, args.result_file, img_label_dict, topn=5) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/dino_resnet50_preprocess.py b/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/dino_resnet50_preprocess.py index a8c182f3cb..30f60993ce 100644 --- a/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/dino_resnet50_preprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/dino_resnet50_preprocess.py @@ -1,115 +1,115 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -from PIL import Image -import numpy as np -import multiprocessing - - -model_config = { - 'resnet': { - 'resize': 256, - 'centercrop': 224, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv3': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.485, 0.456, 0.406], - 'std': [0.229, 0.224, 0.225], - }, - 'inceptionv4': { - 'resize': 342, - 'centercrop': 299, - 'mean': [0.5, 0.5, 0.5], - 'std': [0.5, 0.5, 0.5], - }, -} - - -def center_crop(img, output_size): - if isinstance(output_size, int): - output_size = (int(output_size), int(output_size)) - image_width, image_height = img.size - crop_height, crop_width = output_size - crop_top = int(round((image_height - crop_height) / 2.)) - crop_left = int(round((image_width - crop_width) / 2.)) - return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) - - -def resize(img, size, interpolation=Image.BILINEAR): - if isinstance(size, int): - w, h = img.size - if (w <= h and w == size) or (h <= w and h == size): - return img - if w < h: - ow = size - oh = int(size * h / w) - return img.resize((ow, oh), interpolation) - else: - oh = size - ow = int(size * w / h) - return img.resize((ow, oh), interpolation) - else: - return img.resize(size[::-1], interpolation) - - -def gen_input_bin(mode_type, file_batches, batch): - i = 0 - for file in file_batches[batch]: - i =i + 1 - print("batch", batch, file, "===", i) - - # RGBA to RGB - image = Image.open(os.path.join(src_path, file)).convert('RGB') - image = resize(image, model_config[mode_type]['resize']) # Resize - image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop - img = np.array(image, dtype=np.float32) - img = img.transpose(2, 0, 1) # ToTensor: HWC -> CHW - img = img / 255. # ToTensor: div 255 - img -= np.array(model_config[mode_type]['mean'], dtype=np.float32)[:, None, None] # Normalize: mean - img /= np.array(model_config[mode_type]['std'], dtype=np.float32)[:, None, None] # Normalize: std - img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) - - -def preprocess(mode_type, src_path, save_path): - files = os.listdir(src_path) - file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] - thread_pool = multiprocessing.Pool(len(file_batches)) - for batch in range(len(file_batches)): - thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) - thread_pool.close() - thread_pool.join() - - -if __name__ == '__main__': - if len(sys.argv) < 4: - raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") - mode_type = sys.argv[1] - src_path = sys.argv[2] - save_path = sys.argv[3] - src_path = os.path.realpath(src_path) - save_path = os.path.realpath(save_path) - if mode_type not in model_config: - model_type_help = "model type: " - for key in model_config.keys(): - model_type_help += key - model_type_help += ' ' - raise Exception(model_type_help) - if not os.path.isdir(save_path): - os.makedirs(os.path.realpath(save_path)) - preprocess(mode_type, src_path, save_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +from PIL import Image +import numpy as np +import multiprocessing + + +model_config = { + 'resnet': { + 'resize': 256, + 'centercrop': 224, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv3': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.485, 0.456, 0.406], + 'std': [0.229, 0.224, 0.225], + }, + 'inceptionv4': { + 'resize': 342, + 'centercrop': 299, + 'mean': [0.5, 0.5, 0.5], + 'std': [0.5, 0.5, 0.5], + }, +} + + +def center_crop(img, output_size): + if isinstance(output_size, int): + output_size = (int(output_size), int(output_size)) + image_width, image_height = img.size + crop_height, crop_width = output_size + crop_top = int(round((image_height - crop_height) / 2.)) + crop_left = int(round((image_width - crop_width) / 2.)) + return img.crop((crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)) + + +def resize(img, size, interpolation=Image.BILINEAR): + if isinstance(size, int): + w, h = img.size + if (w <= h and w == size) or (h <= w and h == size): + return img + if w < h: + ow = size + oh = int(size * h / w) + return img.resize((ow, oh), interpolation) + else: + oh = size + ow = int(size * w / h) + return img.resize((ow, oh), interpolation) + else: + return img.resize(size[::-1], interpolation) + + +def gen_input_bin(mode_type, file_batches, batch): + i = 0 + for file in file_batches[batch]: + i =i + 1 + print("batch", batch, file, "===", i) + + # RGBA to RGB + image = Image.open(os.path.join(src_path, file)).convert('RGB') + image = resize(image, model_config[mode_type]['resize']) # Resize + image = center_crop(image, model_config[mode_type]['centercrop']) # CenterCrop + img = np.array(image, dtype=np.float32) + img = img.transpose(2, 0, 1) # ToTensor: HWC -> CHW + img = img / 255. # ToTensor: div 255 + img -= np.array(model_config[mode_type]['mean'], dtype=np.float32)[:, None, None] # Normalize: mean + img /= np.array(model_config[mode_type]['std'], dtype=np.float32)[:, None, None] # Normalize: std + img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) + + +def preprocess(mode_type, src_path, save_path): + files = os.listdir(src_path) + file_batches = [files[i:i + 500] for i in range(0, 50000, 500) if files[i:i + 500] != []] + thread_pool = multiprocessing.Pool(len(file_batches)) + for batch in range(len(file_batches)): + thread_pool.apply_async(gen_input_bin, args=(mode_type, file_batches, batch)) + thread_pool.close() + thread_pool.join() + + +if __name__ == '__main__': + if len(sys.argv) < 4: + raise Exception("usage: python3 xxx.py [model_type] [src_path] [save_path]") + mode_type = sys.argv[1] + src_path = sys.argv[2] + save_path = sys.argv[3] + src_path = os.path.realpath(src_path) + save_path = os.path.realpath(save_path) + if mode_type not in model_config: + model_type_help = "model type: " + for key in model_config.keys(): + model_type_help += key + model_type_help += ' ' + raise Exception(model_type_help) + if not os.path.isdir(save_path): + os.makedirs(os.path.realpath(save_path)) + preprocess(mode_type, src_path, save_path) diff --git a/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/dino_resnet50_pth2onnx.py b/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/dino_resnet50_pth2onnx.py index 2ad540e8ca..e6554df383 100644 --- a/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/dino_resnet50_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/dino_resnet50_pth2onnx.py @@ -1,46 +1,46 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import torchvision.models as models -import torch.nn as nn - - -model=models.resnet50(pretrained=True) -embed_dim = model.fc.weight.shape[1] -model.fc = nn.Identity() - -state_dict = torch.load('dino_resnet50_pretrain.pth', map_location='cpu') -temp=nn.Linear(2048,1000) -state_dict2 = torch.load('dino_resnet50_linearweights.pth', map_location='cpu')["state_dict"] -temp.weight.data = state_dict2['module.linear.weight'] -temp.bias.data = state_dict2['module.linear.bias'] -model.load_state_dict(state_dict, strict=True) - -model.fc=temp -model.eval() -x = torch.randn(1, 3, 224, 224, requires_grad=True) -model.to(device='cpu') -torch_out = model(x.to(device="cpu")) - -# Export the model -torch.onnx.export(model, # model being run - x, # model input (or a tuple for multiple inputs) - "dino_resnet50.onnx", # where to save the model (can be a file or file-like object) - export_params=True, # store the trained parameter weights inside the model file - opset_version=10, # the ONNX version to export the model to - do_constant_folding=True, # whether to execute constant folding for optimization - input_names = ['input'], # the model's input names - output_names = ['output'], # the model's output names - dynamic_axes={'input' : {0 : 'batch_size'}, # variable length axes +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import torchvision.models as models +import torch.nn as nn + + +model=models.resnet50(pretrained=True) +embed_dim = model.fc.weight.shape[1] +model.fc = nn.Identity() + +state_dict = torch.load('dino_resnet50_pretrain.pth', map_location='cpu') +temp=nn.Linear(2048,1000) +state_dict2 = torch.load('dino_resnet50_linearweights.pth', map_location='cpu')["state_dict"] +temp.weight.data = state_dict2['module.linear.weight'] +temp.bias.data = state_dict2['module.linear.bias'] +model.load_state_dict(state_dict, strict=True) + +model.fc=temp +model.eval() +x = torch.randn(1, 3, 224, 224, requires_grad=True) +model.to(device='cpu') +torch_out = model(x.to(device="cpu")) + +# Export the model +torch.onnx.export(model, # model being run + x, # model input (or a tuple for multiple inputs) + "dino_resnet50.onnx", # where to save the model (can be a file or file-like object) + export_params=True, # store the trained parameter weights inside the model file + opset_version=10, # the ONNX version to export the model to + do_constant_folding=True, # whether to execute constant folding for optimization + input_names = ['input'], # the model's input names + output_names = ['output'], # the model's output names + dynamic_axes={'input' : {0 : 'batch_size'}, # variable length axes 'output' : {0 : 'batch_size'}}) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/get_info.py b/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/get_info.py index 8bd92616fc..89b89cf20a 100644 --- a/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/get_info.py +++ b/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/get_info.py @@ -1,59 +1,59 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/modelzoo_level.txt index 9e95396651..27e6c78b37 100644 --- a/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:POK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/test/parse.py b/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/test/parse.py index 54fe38f458..7922b1d164 100644 --- a/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/test/parse.py +++ b/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50/test/parse.py @@ -1,31 +1,31 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - - print(content) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + + print(content) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/pnasnet5large/LICENSE b/ACL_PyTorch/contrib/cv/classfication/pnasnet5large/LICENSE index 753842b672..f49a4e16e6 100644 --- a/ACL_PyTorch/contrib/cv/classfication/pnasnet5large/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/pnasnet5large/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/pnasnet5large/get_info.py b/ACL_PyTorch/contrib/cv/classfication/pnasnet5large/get_info.py index 16bebcfc75..70e007ac5c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/pnasnet5large/get_info.py +++ b/ACL_PyTorch/contrib/cv/classfication/pnasnet5large/get_info.py @@ -1,62 +1,62 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - print(index,'done') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - print(index,'done') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + print(index,'done') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + print(index,'done') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/pnasnet5large/vision_metric_ImageNet.py b/ACL_PyTorch/contrib/cv/classfication/pnasnet5large/vision_metric_ImageNet.py index 362f2484e8..583340a19f 100644 --- a/ACL_PyTorch/contrib/cv/classfication/pnasnet5large/vision_metric_ImageNet.py +++ b/ACL_PyTorch/contrib/cv/classfication/pnasnet5large/vision_metric_ImageNet.py @@ -1,184 +1,184 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - imgName = temp[0].split(".")[0] - imgLab = temp[1] - img_gt_dict[imgName] = imgLab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - if data == '': - n_label = 0 - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, prob in enumerate(temp): - data_vec[ind] = np.float32(prob) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - resCnt = 0 - n_labels = 0 - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - n_labels = ret[1] - sort_index = np.argsort(-prediction) - gt = img_gt_dict[img_name] - if (n_labels == 1000): - realLabel = int(gt) - elif (n_labels == 1001): - realLabel = int(gt) + 1 - else: - realLabel = int(gt) - - resCnt = min(len(sort_index), topn) - for i in range(resCnt): - if (str(realLabel) == str(sort_index[i])): - count_hit[i] += 1 - break - - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(resCnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - - if not (os.path.exists(annotation_file_path)): - print("Ground truth file does not exist.") - - if not (os.path.exists(result_json_path)): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) - print("Time used:", elapsed) - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + imgName = temp[0].split(".")[0] + imgLab = temp[1] + img_gt_dict[imgName] = imgLab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + if data == '': + n_label = 0 + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, prob in enumerate(temp): + data_vec[ind] = np.float32(prob) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + resCnt = 0 + n_labels = 0 + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + n_labels = ret[1] + sort_index = np.argsort(-prediction) + gt = img_gt_dict[img_name] + if (n_labels == 1000): + realLabel = int(gt) + elif (n_labels == 1001): + realLabel = int(gt) + 1 + else: + realLabel = int(gt) + + resCnt = min(len(sort_index), topn) + for i in range(resCnt): + if (str(realLabel) == str(sort_index[i])): + count_hit[i] += 1 + break + + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(resCnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + + if not (os.path.exists(annotation_file_path)): + print("Ground truth file does not exist.") + + if not (os.path.exists(result_json_path)): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) + print("Time used:", elapsed) + diff --git a/ACL_PyTorch/contrib/cv/classfication/vit-small/README.md b/ACL_PyTorch/contrib/cv/classfication/vit-small/README.md index ff71f12fee..54a20b8c45 100644 --- a/ACL_PyTorch/contrib/cv/classfication/vit-small/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/vit-small/README.md @@ -1,70 +1,70 @@ -# vit-small 模型PyTorch离线推理指导 - -## 1. 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 - -~~~shell -pip3.7 install -r requirements.txt -~~~ - -2.获取,修改与安装开源模型代码 - -~~~shell -git clone https://github.com/rwightman/pytorch-image-models.git -b master -cd pytorch-image-models/ -patch -p1 < ../vit_small_patch16_224.patch -cd .. -~~~ - -3.获取权重文件 - -将权重文件放到当前工作目录,可以通过以下命令下载: - -~~~shell -wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/classfication/vit-small/S_16-i21k-300ep-lr_0.001-aug_light1-wd_0.03-do_0.0-sd_0.0--imagenet2012-steps_20k-lr_0.03-res_224.npz -~~~ - -4.数据集 - -该模型使用 `ImageNet` 官网的5万张验证集进行测试,可从 [ImageNet官网](http://www.image-net.org/) 获取 `val` 数据集与标签,分别存放在 `/home/datasets/imagenet/val` 与 `/home/datasets/imagenet/val_label.txt` - -最终目录结构应为 - -~~~txt -imagenet/ -|-- val/ -|-- val_label.txt -~~~ - -5.[获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) - -将 `benchmark.x86_64` 或 `benchmark.aarch64` 放到当前工作目录 - -## 2. 离线推理 - -t4上执行,确保卡空闲时执行测试 - -~~~shell -bash perf_g.sh -# 脚本3-11行是对gpu bs1性能测试, 13-21行是对gpu bs16性能测试 -~~~ - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 - -~~~shell -bash ./test/pth2om.sh -# 脚本中2-7行是pth2onnx,9-16行是对onnx进行onnxsim优化, 18-27行是利用onnxsim优化后的onnx转om - -bash ./test/eval_acc_perf.sh --datasets_path=real_data_path -# 如不指定--datasets_path,则采用默认数据集路径:/home/datasets/imagenet/ -# 脚本中12-19行为数据集前处理,同时生成bin文件信息,20-30行是推理过程,32-44行获取精度数据,45-56行获取性能数据 -~~~ - -**评测结果** - -| 模型 | 仓库pth精度 | 310离线推理精度 | 基准性能 | 310性能 | -| -------------- | ----------- | --------------- | -------- | -------- | -| vit-small bs1 | top1:81.388 | top1:81.1 | 222.4976 | 200.9196 | -| vit-small bs16 | top1:81.388 | top1:81.1 | 657.9001 | 204.0776 | - +# vit-small 模型PyTorch离线推理指导 + +## 1. 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 + +~~~shell +pip3.7 install -r requirements.txt +~~~ + +2.获取,修改与安装开源模型代码 + +~~~shell +git clone https://github.com/rwightman/pytorch-image-models.git -b master +cd pytorch-image-models/ +patch -p1 < ../vit_small_patch16_224.patch +cd .. +~~~ + +3.获取权重文件 + +将权重文件放到当前工作目录,可以通过以下命令下载: + +~~~shell +wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/classfication/vit-small/S_16-i21k-300ep-lr_0.001-aug_light1-wd_0.03-do_0.0-sd_0.0--imagenet2012-steps_20k-lr_0.03-res_224.npz +~~~ + +4.数据集 + +该模型使用 `ImageNet` 官网的5万张验证集进行测试,可从 [ImageNet官网](http://www.image-net.org/) 获取 `val` 数据集与标签,分别存放在 `/home/datasets/imagenet/val` 与 `/home/datasets/imagenet/val_label.txt` + +最终目录结构应为 + +~~~txt +imagenet/ +|-- val/ +|-- val_label.txt +~~~ + +5.[获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) + +将 `benchmark.x86_64` 或 `benchmark.aarch64` 放到当前工作目录 + +## 2. 离线推理 + +t4上执行,确保卡空闲时执行测试 + +~~~shell +bash perf_g.sh +# 脚本3-11行是对gpu bs1性能测试, 13-21行是对gpu bs16性能测试 +~~~ + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 + +~~~shell +bash ./test/pth2om.sh +# 脚本中2-7行是pth2onnx,9-16行是对onnx进行onnxsim优化, 18-27行是利用onnxsim优化后的onnx转om + +bash ./test/eval_acc_perf.sh --datasets_path=real_data_path +# 如不指定--datasets_path,则采用默认数据集路径:/home/datasets/imagenet/ +# 脚本中12-19行为数据集前处理,同时生成bin文件信息,20-30行是推理过程,32-44行获取精度数据,45-56行获取性能数据 +~~~ + +**评测结果** + +| 模型 | 仓库pth精度 | 310离线推理精度 | 基准性能 | 310性能 | +| -------------- | ----------- | --------------- | -------- | -------- | +| vit-small bs1 | top1:81.388 | top1:81.1 | 222.4976 | 200.9196 | +| vit-small bs16 | top1:81.388 | top1:81.1 | 657.9001 | 204.0776 | + diff --git a/ACL_PyTorch/contrib/cv/classfication/vit-small/env.sh b/ACL_PyTorch/contrib/cv/classfication/vit-small/env.sh old mode 100755 new mode 100644 diff --git a/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/LICENSE b/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/LICENSE index b1fac45f02..989e2c59e9 100644 --- a/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/LICENSE @@ -1,201 +1,201 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/gen_dataset_info.py index 6a69d4d17f..3fbb7d8462 100644 --- a/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/gen_dataset_info.py @@ -1,64 +1,64 @@ -""" -Copyright 2020 Huawei Technologies Co., Ltd - -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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' - get_jpg_info(file_path, info_name) - +""" +Copyright 2020 Huawei Technologies Co., Ltd + +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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' + get_jpg_info(file_path, info_name) + diff --git a/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/modelzoo_level.txt index 32dd0521ec..7e460da191 100644 --- a/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/modelzoo_level.txt @@ -1,6 +1,6 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:POK -PerfStatus:NOK -ModelConvert:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:POK +PerfStatus:NOK +ModelConvert:OK QuantStatus:POK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/requirements.txt b/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/requirements.txt index 2200a3704d..c7e8af10a5 100644 --- a/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/requirements.txt +++ b/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/requirements.txt @@ -1,5 +1,5 @@ -onnx -torch=1.5.0 -torchvision>=0.5.0 -pyyaml +onnx +torch=1.5.0 +torchvision>=0.5.0 +pyyaml timm \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/vit_base_patch32_224_preprocess.py b/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/vit_base_patch32_224_preprocess.py index 390c38b4f6..7afcd7bef3 100644 --- a/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/vit_base_patch32_224_preprocess.py +++ b/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/vit_base_patch32_224_preprocess.py @@ -1,53 +1,53 @@ -""" -Copyright 2020 Huawei Technologies Co., Ltd - -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 os -from PIL import Image -import numpy as np -import timm -from timm.data import resolve_data_config -from timm.data.transforms_factory import create_transform -import argparse - - -parser = argparse.ArgumentParser(description='Path', add_help=False) -parser.add_argument('--data-path', metavar='DIR', - help='path to dataset') -parser.add_argument('--store-path', metavar='DIR', - help='path to store') - - -def preprocess(src_path, save_path): - os.mkdir(save_path) - model = timm.create_model('vit_base_patch32_224') - model.eval() - config = resolve_data_config({},model=model) - transform = create_transform(**config) - i = 0 - in_files = os.listdir(src_path) - for file in in_files: - i = i + 1 - print(file, "===", i) - input_image = Image.open(src_path+'/'+file).convert('RGB') - input_tensor = transform(input_image) - img = np.array(input_tensor).astype(np.float32) - img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) - - -if __name__ == "__main__": - args = parser.parse_args() +""" +Copyright 2020 Huawei Technologies Co., Ltd + +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 os +from PIL import Image +import numpy as np +import timm +from timm.data import resolve_data_config +from timm.data.transforms_factory import create_transform +import argparse + + +parser = argparse.ArgumentParser(description='Path', add_help=False) +parser.add_argument('--data-path', metavar='DIR', + help='path to dataset') +parser.add_argument('--store-path', metavar='DIR', + help='path to store') + + +def preprocess(src_path, save_path): + os.mkdir(save_path) + model = timm.create_model('vit_base_patch32_224') + model.eval() + config = resolve_data_config({},model=model) + transform = create_transform(**config) + i = 0 + in_files = os.listdir(src_path) + for file in in_files: + i = i + 1 + print(file, "===", i) + input_image = Image.open(src_path+'/'+file).convert('RGB') + input_tensor = transform(input_image) + img = np.array(input_tensor).astype(np.float32) + img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) + + +if __name__ == "__main__": + args = parser.parse_args() preprocess(args.data_path,args.store_path) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/vit_base_patch32_224_pth2onnx.py b/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/vit_base_patch32_224_pth2onnx.py index d64775b88a..a52537b0c1 100644 --- a/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/vit_base_patch32_224_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224/vit_base_patch32_224_pth2onnx.py @@ -1,41 +1,41 @@ -""" -Copyright 2020 Huawei Technologies Co., Ltd - -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 torch -import timm -import argparse - - -parser = argparse.ArgumentParser(description='Path', add_help=False) -parser.add_argument('--model-path', default="B_32-i21k-300ep-lr_0.001-aug_medium1-wd_0.03-do_0.0-sd_0.0--imagenet2012-steps_20k-lr_0.03-res_224.npz", metavar='DIR', - help='path to model') -parser.add_argument('--batch-size',default="1", type=int, - help='batch size') - - -def main(): - args = parser.parse_args() - model = timm.create_model('vit_base_patch32_224') - model.load_pretrained(args.model_path) - model.eval() - tensor = torch.zeros(args.batch_size,3,224,224) - torch.onnx.export(model, tensor, "vit_bs"+str(args.batch_size)+".onnx", opset_version=11, - do_constant_folding=True, input_names=["input"], output_names=["output"]) - - -if __name__ == "__main__": +""" +Copyright 2020 Huawei Technologies Co., Ltd + +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 torch +import timm +import argparse + + +parser = argparse.ArgumentParser(description='Path', add_help=False) +parser.add_argument('--model-path', default="B_32-i21k-300ep-lr_0.001-aug_medium1-wd_0.03-do_0.0-sd_0.0--imagenet2012-steps_20k-lr_0.03-res_224.npz", metavar='DIR', + help='path to model') +parser.add_argument('--batch-size',default="1", type=int, + help='batch size') + + +def main(): + args = parser.parse_args() + model = timm.create_model('vit_base_patch32_224') + model.load_pretrained(args.model_path) + model.eval() + tensor = torch.zeros(args.batch_size,3,224,224) + torch.onnx.export(model, tensor, "vit_bs"+str(args.batch_size)+".onnx", opset_version=11, + do_constant_folding=True, input_names=["input"], output_names=["output"]) + + +if __name__ == "__main__": main() \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/vovnet39/LICENSE b/ACL_PyTorch/contrib/cv/classfication/vovnet39/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/classfication/vovnet39/LICENSE +++ b/ACL_PyTorch/contrib/cv/classfication/vovnet39/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/vovnet39/README.md b/ACL_PyTorch/contrib/cv/classfication/vovnet39/README.md index 5211e9ceba..ed1c41a808 100644 --- a/ACL_PyTorch/contrib/cv/classfication/vovnet39/README.md +++ b/ACL_PyTorch/contrib/cv/classfication/vovnet39/README.md @@ -1,255 +1,255 @@ -vovnet39 Onnx模型端到端推理指导 - -- [1 模型概述](#1-模型概述) - - [1.1 论文地址](#11-论文地址) - - [1.2 代码地址](#12-代码地址) -- [2 环境说明](#2-环境说明) - - [2.1 深度学习框架](#21-深度学习框架) - - [2.2 python第三方库](#22-python第三方库) -- [3 模型转换](#3-模型转换) - - [3.1 pth转onnx模型](#31-pth转onnx模型) - - [3.2 onnx转om模型](#32-onnx转om模型) -- [4 数据集预处理](#4-数据集预处理) - - [4.1 数据集获取](#41-数据集获取) - - [4.2 数据集预处理](#42-数据集预处理) - - [4.3 生成数据集信息文件](#43-生成数据集信息文件) -- [5 离线推理](#5-离线推理) - - [5.1 benchmark工具概述](#51-benchmark工具概述) - - [5.2 离线推理](#52-离线推理) -- [6 精度对比](#6-精度对比) - - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) - - [6.2 开源TopN精度](#62-开源TopN精度) - - [6.3 精度对比](#63-精度对比) -- [7 性能对比](#7-性能对比) - - [7.1 npu性能数据](#71-npu性能数据) - - - -## 1 模型概述 - -- **[论文地址](#11-论文地址)** - -- **[代码地址](#12-代码地址)** - -### 1.1 论文地址 -[vovnet39论文](https://arxiv.org/abs/1904.09730) - -### 1.2 代码地址 -[vovnet39代码](https://github.com/AlexanderBurkhart/cnn_train/tree/505637bcd08021e144c94e81401af6bc71fd46c6/VoVNet.pytorch/models_vovnet) -branch:master -commit_id:505637bcd08021e144c94e81401af6bc71fd46c6 - -## 2 环境说明 - -- **[深度学习框架](#21-深度学习框架)** - -- **[python第三方库](#22-python第三方库)** - -### 2.1 深度学习框架 -``` -CANN 5.0.1 -pytorch == 1.5.0 -torchvision == 0.6.0 -onnx == 1.7.0 -``` - -### 2.2 python第三方库 - -``` -numpy == 1.18.5 -Pillow == 7.2.0 -opencv-python == 4.5.1.48 -``` - -**说明:** -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3 模型转换 - -- **[pth转onnx模型](#31-pth转onnx模型)** - -- **[onnx转om模型](#32-onnx转om模型)** - -### 3.1 pth转onnx模型 - -1.下载pth权重文件 -[vovnet39预训练pth权重文件](https://www.dropbox.com/s/1lnzsgnixd8gjra/vovnet39_torchvision.pth) -文件md5sum: 23717a6cadd9729a704f894381444237 - -``` -http://www.dropbox.com/s/1lnzsgnixd8gjra/vovnet39_torchvision.pth -``` -2.vovnet39模型代码在代码仓里 - -``` -github上vovnet39没有安装脚本,在pth2onnx脚本中引用代码仓定义的vovnet39: - -git clone https://github.com/AlexanderBurkhart/cnn_train.git -``` - -3.编写pth2onnx脚本vovnet39_pth2onnx.py - - **说明:** ->注意目前ATC支持的onnx算子版本为11 - -4.执行pth2onnx脚本,生成onnx模型文件 -``` -python3.7 vovnet39_pth2onnx.py vovnet39_torchvision.pth vovnet39.onnx -``` - **模型转换要点:** ->此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 -### 3.2 onnx转om模型 - -1.设置环境变量 -``` -source env.sh -``` -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.1 开发辅助工具指南 (推理) 01 -``` -atc --framework=5 --model=./vovnet39.onnx --input_format=NCHW --input_shape="image:1,3,224,224" --output=vovnet39_bs1 --log=debug --soc_version=Ascend310 -``` - -## 4 数据集预处理 - -- **[数据集获取](#41-数据集获取)** - -- **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - -### 4.1 数据集获取 -该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/opt/npu/imagenet/val与/root/datasets/imagenet/val_label.txt。 - -### 4.2 数据集预处理 -1.预处理脚本vovnet_torch_preprocess.py - -2.执行预处理脚本,生成数据集预处理后的bin文件 -``` -python3.7 vovnet_torch_preprocess.py /opt/npu/imagenet/val ./prep_dataset -``` -### 4.3 生成数据集信息文件 -1.生成数据集信息文件脚本get_info.py - -2.执行生成数据集信息脚本,生成数据集信息文件 - -``` -python3.7 get_info.py bin ./prep_dataset ./vovnet_prep_bin.info 224 224 -``` -第一个参数为生成的数据集文件格式,第二个为预处理后的数据文件路径,第三个参数为生成的数据集文件保存的路径,第四个和第五个参数分别为模型输入的宽度和高度 -## 5 离线推理 - -- **[benchmark工具概述](#51-benchmark工具概述)** - -- **[离线推理](#52-离线推理)** - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN 5.0.1 推理benchmark工具用户指南 01 -### 5.2 离线推理 -1.设置环境变量 -``` -source env.sh -``` -2.执行离线推理 - -``` -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=vovnet39_bs1.om -input_text_path=./vovnet_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False -``` -输出结果默认保存在当前目录result/dumpOutput_devicex,模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 - -## 6 精度对比 - -- **[离线推理TopN精度](#61-离线推理TopN精度)** -- **[开源TopN精度](#62-开源TopN精度)** -- **[精度对比](#63-精度对比)** - -### 6.1 离线推理TopN精度统计 - -后处理统计TopN精度 - -调用vision_metric_ImageNet.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 -``` -python3.7 vision_metric_ImageNet.py result/dumpOutput_device0/ /opt/npu/imagenet/val_label.txt ./ result.json -``` -第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 -查看输出结果: -``` -{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value -": "76.78%"}, {"key": "Top2 accuracy", "value": "86.6%"}, {"key": "Top3 accuracy", "value": "90.23%"}, {"key": "Top4 accuracy", "value": "92.22%"}, {"key": "Top5 accuracy", "value": "93.43%"}]} -``` -经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 - -### 6.2 开源TopN精度 -[开源代码仓精度](https://github.com/AlexanderBurkhart/cnn_train/tree/505637bcd08021e144c94e81401af6bc71fd46c6/VoVNet.pytorch) - -``` -Model Acc@1 Acc@5 -vovnet39 76.77 93.43 -``` -### 6.3 精度对比 -将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 - **精度调试:** ->没有遇到精度不达标的问题,故不需要进行精度调试 - -## 7 性能对比 - -- **[npu性能数据](#71-npu性能数据)** - -### 7.1 npu性能数据 -benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device。为快速获取性能数据,也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准。这里给出两种方式,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 -1.benchmark工具在整个数据集上推理获得性能数据 -batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: -``` -[e2e] throughputRate: 190.286, latency: 262762 -[data read] throughputRate: 201.42, moduleLatency: 4.96474 -[preprocess] throughputRate: 201.059, moduleLatency: 4.97367 -[infer] throughputRate: 190.829, Interface throughputRate: 281.608, moduleLatency: 4.54289 -[post] throughputRate: 190.829, moduleLatency: 5.2403 -``` -Interface throughputRate: 281.608,281.608x4=1126.432既是batch1 310单卡吞吐率 -batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: - -``` -[e2e] throughputRate: 132.399, latency: 377646 -[data read] throughputRate: 132.922, moduleLatency: 7.5232 -[preprocess] throughputRate: 132.751, moduleLatency: 7.53292 -[infer] throughputRate: 132.746, Interface throughputRate: 382.566, moduleLatency: 4.0689 -[post] throughputRate: 8.2965, moduleLatency: 120.533 -``` -Interface throughputRate: 382.566,382.566x4=1530.264既是batch16 310单卡吞吐率 -batch4性能: - -``` -[e2e] throughputRate: 194.167, latency: 257510 -[data read] throughputRate: 206.005, moduleLatency: 4.85426 -[preprocess] throughputRate: 205.807, moduleLatency: 4.85891 -[infer] throughputRate: 194.685, Interface throughputRate: 354.792, moduleLatency: 4.2876 -[post] throughputRate: 48.6709, moduleLatency: 20.5462 -``` -batch4 310单卡吞吐率:354.792x4=1419.168fps -batch8性能: - -``` -[e2e] throughputRate: 143.83, latency: 347633 -[data read] throughputRate: 144.354, moduleLatency: 6.92743 -[preprocess] throughputRate: 144.186, moduleLatency: 6.93549 -[infer] throughputRate: 144.246, Interface throughputRate: 364.129, moduleLatency: 4.20264 -[post] throughputRate: 18.0306, moduleLatency: 55.4613 -``` -batch8 310单卡吞吐率:364.129x4=1456.516fps -batch32性能: - -``` -[e2e] throughputRate: 122.051, latency: 409664 -[data read] throughputRate: 122.581, moduleLatency: 8.15788 -[preprocess] throughputRate: 122.445, moduleLatency: 8.16691 -[infer] throughputRate: 122.448, Interface throughputRate: 382.396, moduleLatency: 4.07549 -[post] throughputRate: 3.82767, moduleLatency: 261.256 -``` -batch32 310单卡吞吐率:382.396x4=1529.584fps - - **性能优化:** - +vovnet39 Onnx模型端到端推理指导 + +- [1 模型概述](#1-模型概述) + - [1.1 论文地址](#11-论文地址) + - [1.2 代码地址](#12-代码地址) +- [2 环境说明](#2-环境说明) + - [2.1 深度学习框架](#21-深度学习框架) + - [2.2 python第三方库](#22-python第三方库) +- [3 模型转换](#3-模型转换) + - [3.1 pth转onnx模型](#31-pth转onnx模型) + - [3.2 onnx转om模型](#32-onnx转om模型) +- [4 数据集预处理](#4-数据集预处理) + - [4.1 数据集获取](#41-数据集获取) + - [4.2 数据集预处理](#42-数据集预处理) + - [4.3 生成数据集信息文件](#43-生成数据集信息文件) +- [5 离线推理](#5-离线推理) + - [5.1 benchmark工具概述](#51-benchmark工具概述) + - [5.2 离线推理](#52-离线推理) +- [6 精度对比](#6-精度对比) + - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) + - [6.2 开源TopN精度](#62-开源TopN精度) + - [6.3 精度对比](#63-精度对比) +- [7 性能对比](#7-性能对比) + - [7.1 npu性能数据](#71-npu性能数据) + + + +## 1 模型概述 + +- **[论文地址](#11-论文地址)** + +- **[代码地址](#12-代码地址)** + +### 1.1 论文地址 +[vovnet39论文](https://arxiv.org/abs/1904.09730) + +### 1.2 代码地址 +[vovnet39代码](https://github.com/AlexanderBurkhart/cnn_train/tree/505637bcd08021e144c94e81401af6bc71fd46c6/VoVNet.pytorch/models_vovnet) +branch:master +commit_id:505637bcd08021e144c94e81401af6bc71fd46c6 + +## 2 环境说明 + +- **[深度学习框架](#21-深度学习框架)** + +- **[python第三方库](#22-python第三方库)** + +### 2.1 深度学习框架 +``` +CANN 5.0.1 +pytorch == 1.5.0 +torchvision == 0.6.0 +onnx == 1.7.0 +``` + +### 2.2 python第三方库 + +``` +numpy == 1.18.5 +Pillow == 7.2.0 +opencv-python == 4.5.1.48 +``` + +**说明:** +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3 模型转换 + +- **[pth转onnx模型](#31-pth转onnx模型)** + +- **[onnx转om模型](#32-onnx转om模型)** + +### 3.1 pth转onnx模型 + +1.下载pth权重文件 +[vovnet39预训练pth权重文件](https://www.dropbox.com/s/1lnzsgnixd8gjra/vovnet39_torchvision.pth) +文件md5sum: 23717a6cadd9729a704f894381444237 + +``` +http://www.dropbox.com/s/1lnzsgnixd8gjra/vovnet39_torchvision.pth +``` +2.vovnet39模型代码在代码仓里 + +``` +github上vovnet39没有安装脚本,在pth2onnx脚本中引用代码仓定义的vovnet39: + +git clone https://github.com/AlexanderBurkhart/cnn_train.git +``` + +3.编写pth2onnx脚本vovnet39_pth2onnx.py + + **说明:** +>注意目前ATC支持的onnx算子版本为11 + +4.执行pth2onnx脚本,生成onnx模型文件 +``` +python3.7 vovnet39_pth2onnx.py vovnet39_torchvision.pth vovnet39.onnx +``` + **模型转换要点:** +>此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 +### 3.2 onnx转om模型 + +1.设置环境变量 +``` +source env.sh +``` +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.1 开发辅助工具指南 (推理) 01 +``` +atc --framework=5 --model=./vovnet39.onnx --input_format=NCHW --input_shape="image:1,3,224,224" --output=vovnet39_bs1 --log=debug --soc_version=Ascend310 +``` + +## 4 数据集预处理 + +- **[数据集获取](#41-数据集获取)** + +- **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + +### 4.1 数据集获取 +该模型使用[ImageNet官网](http://www.image-net.org)的5万张验证集进行测试,图片与标签分别存放在/opt/npu/imagenet/val与/root/datasets/imagenet/val_label.txt。 + +### 4.2 数据集预处理 +1.预处理脚本vovnet_torch_preprocess.py + +2.执行预处理脚本,生成数据集预处理后的bin文件 +``` +python3.7 vovnet_torch_preprocess.py /opt/npu/imagenet/val ./prep_dataset +``` +### 4.3 生成数据集信息文件 +1.生成数据集信息文件脚本get_info.py + +2.执行生成数据集信息脚本,生成数据集信息文件 + +``` +python3.7 get_info.py bin ./prep_dataset ./vovnet_prep_bin.info 224 224 +``` +第一个参数为生成的数据集文件格式,第二个为预处理后的数据文件路径,第三个参数为生成的数据集文件保存的路径,第四个和第五个参数分别为模型输入的宽度和高度 +## 5 离线推理 + +- **[benchmark工具概述](#51-benchmark工具概述)** + +- **[离线推理](#52-离线推理)** + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN 5.0.1 推理benchmark工具用户指南 01 +### 5.2 离线推理 +1.设置环境变量 +``` +source env.sh +``` +2.执行离线推理 + +``` +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=vovnet39_bs1.om -input_text_path=./vovnet_prep_bin.info -input_width=224 -input_height=224 -output_binary=False -useDvpp=False +``` +输出结果默认保存在当前目录result/dumpOutput_devicex,模型只有一个名为class的输出,shape为bs * 1000,数据类型为FP32,对应1000个分类的预测结果,每个输入对应的输出对应一个_x.bin文件。 + +## 6 精度对比 + +- **[离线推理TopN精度](#61-离线推理TopN精度)** +- **[开源TopN精度](#62-开源TopN精度)** +- **[精度对比](#63-精度对比)** + +### 6.1 离线推理TopN精度统计 + +后处理统计TopN精度 + +调用vision_metric_ImageNet.py脚本推理结果与label比对,可以获得Accuracy Top5数据,结果保存在result.json中。 +``` +python3.7 vision_metric_ImageNet.py result/dumpOutput_device0/ /opt/npu/imagenet/val_label.txt ./ result.json +``` +第一个为benchmark输出目录,第二个为数据集配套标签,第三个是生成文件的保存目录,第四个是生成的文件名。 +查看输出结果: +``` +{"title": "Overall statistical evaluation", "value": [{"key": "Number of images", "value": "50000"}, {"key": "Number of classes", "value": "1000"}, {"key": "Top1 accuracy", "value +": "76.78%"}, {"key": "Top2 accuracy", "value": "86.6%"}, {"key": "Top3 accuracy", "value": "90.23%"}, {"key": "Top4 accuracy", "value": "92.22%"}, {"key": "Top5 accuracy", "value": "93.43%"}]} +``` +经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 + +### 6.2 开源TopN精度 +[开源代码仓精度](https://github.com/AlexanderBurkhart/cnn_train/tree/505637bcd08021e144c94e81401af6bc71fd46c6/VoVNet.pytorch) + +``` +Model Acc@1 Acc@5 +vovnet39 76.77 93.43 +``` +### 6.3 精度对比 +将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 + **精度调试:** +>没有遇到精度不达标的问题,故不需要进行精度调试 + +## 7 性能对比 + +- **[npu性能数据](#71-npu性能数据)** + +### 7.1 npu性能数据 +benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device。为快速获取性能数据,也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准。这里给出两种方式,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 +1.benchmark工具在整个数据集上推理获得性能数据 +batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: +``` +[e2e] throughputRate: 190.286, latency: 262762 +[data read] throughputRate: 201.42, moduleLatency: 4.96474 +[preprocess] throughputRate: 201.059, moduleLatency: 4.97367 +[infer] throughputRate: 190.829, Interface throughputRate: 281.608, moduleLatency: 4.54289 +[post] throughputRate: 190.829, moduleLatency: 5.2403 +``` +Interface throughputRate: 281.608,281.608x4=1126.432既是batch1 310单卡吞吐率 +batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: + +``` +[e2e] throughputRate: 132.399, latency: 377646 +[data read] throughputRate: 132.922, moduleLatency: 7.5232 +[preprocess] throughputRate: 132.751, moduleLatency: 7.53292 +[infer] throughputRate: 132.746, Interface throughputRate: 382.566, moduleLatency: 4.0689 +[post] throughputRate: 8.2965, moduleLatency: 120.533 +``` +Interface throughputRate: 382.566,382.566x4=1530.264既是batch16 310单卡吞吐率 +batch4性能: + +``` +[e2e] throughputRate: 194.167, latency: 257510 +[data read] throughputRate: 206.005, moduleLatency: 4.85426 +[preprocess] throughputRate: 205.807, moduleLatency: 4.85891 +[infer] throughputRate: 194.685, Interface throughputRate: 354.792, moduleLatency: 4.2876 +[post] throughputRate: 48.6709, moduleLatency: 20.5462 +``` +batch4 310单卡吞吐率:354.792x4=1419.168fps +batch8性能: + +``` +[e2e] throughputRate: 143.83, latency: 347633 +[data read] throughputRate: 144.354, moduleLatency: 6.92743 +[preprocess] throughputRate: 144.186, moduleLatency: 6.93549 +[infer] throughputRate: 144.246, Interface throughputRate: 364.129, moduleLatency: 4.20264 +[post] throughputRate: 18.0306, moduleLatency: 55.4613 +``` +batch8 310单卡吞吐率:364.129x4=1456.516fps +batch32性能: + +``` +[e2e] throughputRate: 122.051, latency: 409664 +[data read] throughputRate: 122.581, moduleLatency: 8.15788 +[preprocess] throughputRate: 122.445, moduleLatency: 8.16691 +[infer] throughputRate: 122.448, Interface throughputRate: 382.396, moduleLatency: 4.07549 +[post] throughputRate: 3.82767, moduleLatency: 261.256 +``` +batch32 310单卡吞吐率:382.396x4=1529.584fps + + **性能优化:** + >没有遇到性能不达标的问题,故不需要进行性能优化 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/vovnet39/requirements.txt b/ACL_PyTorch/contrib/cv/classfication/vovnet39/requirements.txt index 19bf0c33da..59f8a711bf 100644 --- a/ACL_PyTorch/contrib/cv/classfication/vovnet39/requirements.txt +++ b/ACL_PyTorch/contrib/cv/classfication/vovnet39/requirements.txt @@ -1,6 +1,6 @@ -torch == 1.5.0 -torchvision == 0.6.0 -onnx == 1.7.0 -numpy == 1.18.5 -Pillow == 7.2.0 +torch == 1.5.0 +torchvision == 0.6.0 +onnx == 1.7.0 +numpy == 1.18.5 +Pillow == 7.2.0 opencv-python == 4.5.1.48 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/classfication/vovnet39/test/readme.md b/ACL_PyTorch/contrib/cv/classfication/vovnet39/test/readme.md index bb87e712e8..9237a2ae4b 100644 --- a/ACL_PyTorch/contrib/cv/classfication/vovnet39/test/readme.md +++ b/ACL_PyTorch/contrib/cv/classfication/vovnet39/test/readme.md @@ -1,24 +1,24 @@ -环境准备: - -1.数据集路径 -通用的数据集统一放在/root/datasets/或/opt/npu/ -本模型数据集放在/opt/npu/ - -2.进入工作目录 -cd vovnet39 - -3.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -pip3.7 install -r requirements.txt - -4.获取模型代码 -git clone https://github.com/AlexanderBurkhart/cnn_train.git - -6.获取权重文件 -wget http://www.dropbox.com/s/1lnzsgnixd8gjra/vovnet39_torchvision.pth - -7.获取benchmark工具 -将benchmark.x86_64 benchmark.aarch64放在当前目录 - -8.310上执行,执行时确保device空闲 -bash test/pth2om.sh -bash test/eval_acc_perf.sh +环境准备: + +1.数据集路径 +通用的数据集统一放在/root/datasets/或/opt/npu/ +本模型数据集放在/opt/npu/ + +2.进入工作目录 +cd vovnet39 + +3.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +pip3.7 install -r requirements.txt + +4.获取模型代码 +git clone https://github.com/AlexanderBurkhart/cnn_train.git + +6.获取权重文件 +wget http://www.dropbox.com/s/1lnzsgnixd8gjra/vovnet39_torchvision.pth + +7.获取benchmark工具 +将benchmark.x86_64 benchmark.aarch64放在当前目录 + +8.310上执行,执行时确保device空闲 +bash test/pth2om.sh +bash test/eval_acc_perf.sh diff --git a/ACL_PyTorch/contrib/cv/classfication/vovnet39/vovnet39_pth2onnx.py b/ACL_PyTorch/contrib/cv/classfication/vovnet39/vovnet39_pth2onnx.py index cf2e2190b3..b8fbbf27a2 100644 --- a/ACL_PyTorch/contrib/cv/classfication/vovnet39/vovnet39_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/classfication/vovnet39/vovnet39_pth2onnx.py @@ -1,36 +1,36 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import sys -import torch.onnx -sys.path.append(r"./cnn_train/VoVNet.pytorch") -from collections import OrderedDict -import models_vovnet - -def pth2onnx(input_file, output_file): - model = models_vovnet.vovnet39(pretrained=False) - device_ids = [0] - model = torch.nn.DataParallel(model , device_ids=device_ids) - checkpoint = torch.load(input_file, map_location='cpu') - model.load_state_dict(checkpoint) - model=model.module - model.eval() - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.rand(1, 3, 224, 224) - torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, opset_version=11, verbose=True) - -if __name__=="__main__": - pth2onnx(sys.argv[1],sys.argv[2]) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import sys +import torch.onnx +sys.path.append(r"./cnn_train/VoVNet.pytorch") +from collections import OrderedDict +import models_vovnet + +def pth2onnx(input_file, output_file): + model = models_vovnet.vovnet39(pretrained=False) + device_ids = [0] + model = torch.nn.DataParallel(model , device_ids=device_ids) + checkpoint = torch.load(input_file, map_location='cpu') + model.load_state_dict(checkpoint) + model=model.module + model.eval() + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.rand(1, 3, 224, 224) + torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, opset_version=11, verbose=True) + +if __name__=="__main__": + pth2onnx(sys.argv[1],sys.argv[2]) diff --git a/ACL_PyTorch/contrib/cv/classfication/xcit/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/classfication/xcit/modelzoo_level.txt index 624f885ed6..2e7cc57906 100644 --- a/ACL_PyTorch/contrib/cv/classfication/xcit/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/classfication/xcit/modelzoo_level.txt @@ -1,6 +1,6 @@ -FuncStatus:OK -PrecisionStatus:OK -ModelConvert:OK -PerfStatus=NOK -AutoTune:POK - +FuncStatus:OK +PrecisionStatus:OK +ModelConvert:OK +PerfStatus=NOK +AutoTune:POK + diff --git a/ACL_PyTorch/contrib/cv/detection/3DUnet/LISCENSE b/ACL_PyTorch/contrib/cv/detection/3DUnet/LISCENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/detection/3DUnet/LISCENSE +++ b/ACL_PyTorch/contrib/cv/detection/3DUnet/LISCENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/3DUnet/UNet3D_pth2onnx.py b/ACL_PyTorch/contrib/cv/detection/3DUnet/UNet3D_pth2onnx.py index ca9db19e96..5a18441c82 100644 --- a/ACL_PyTorch/contrib/cv/detection/3DUnet/UNet3D_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/detection/3DUnet/UNet3D_pth2onnx.py @@ -1,49 +1,49 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import torch -import lib.medzoo as medzoo - -def pth2onnx(): - args = get_arguments() - input_file = args.input - output_file = args.output - model, optimizer = medzoo.create_model(args) - checkpoint = torch.load(input_file, map_location="cpu") - model.load_state_dict(checkpoint, False) - - model.eval() - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.randn(1, 4, 64, 64, 64) - torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=False, - opset_version=11) - - -def get_arguments(): - parser = argparse.ArgumentParser() - parser.add_argument('--classes', type=int, default=4) - parser.add_argument('--inChannels', type=int, default=4) - parser.add_argument('--model', type=str, default='UNET3D', - choices=('VNET', 'VNET2', 'UNET3D', 'DENSENET1', 'DENSENET2', 'DENSENET3', 'HYPERDENSENET')) - parser.add_argument('--input', type=str, default='none') - parser.add_argument('--output', type=str, default='none') - args = parser.parse_args() - return args - - -if __name__ == '__main__': +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import torch +import lib.medzoo as medzoo + +def pth2onnx(): + args = get_arguments() + input_file = args.input + output_file = args.output + model, optimizer = medzoo.create_model(args) + checkpoint = torch.load(input_file, map_location="cpu") + model.load_state_dict(checkpoint, False) + + model.eval() + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.randn(1, 4, 64, 64, 64) + torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=False, + opset_version=11) + + +def get_arguments(): + parser = argparse.ArgumentParser() + parser.add_argument('--classes', type=int, default=4) + parser.add_argument('--inChannels', type=int, default=4) + parser.add_argument('--model', type=str, default='UNET3D', + choices=('VNET', 'VNET2', 'UNET3D', 'DENSENET1', 'DENSENET2', 'DENSENET3', 'HYPERDENSENET')) + parser.add_argument('--input', type=str, default='none') + parser.add_argument('--output', type=str, default='none') + args = parser.parse_args() + return args + + +if __name__ == '__main__': pth2onnx() \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/3DUnet/modify.py b/ACL_PyTorch/contrib/cv/detection/3DUnet/modify.py index ffac932098..75d5144dc2 100644 --- a/ACL_PyTorch/contrib/cv/detection/3DUnet/modify.py +++ b/ACL_PyTorch/contrib/cv/detection/3DUnet/modify.py @@ -1,113 +1,113 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 numpy as np -from magiconnx import OnnxGraph -import sys - -def modify(path, batchsize): - graph = OnnxGraph(path) - resizes = graph.get_nodes("Resize") - #1 128 4 4 4 -> 1 128*4 4 4 -> 1 128*4 8 8 -> 1 128 4 8*8 -> 1 128 8 8*8 -> 1 128 8 8 8 - shapes1 = [[[1, 128*4, 4, 4], [1,1,2,2], [1, 128, 4, 8*8], [1, 128, 8, 8*8], [1, 128, 8, 8, 8]], - [[1, 64*8, 8, 8], [1,1,2,2], [1, 64, 8, 16*16], [1, 64, 16, 16*16], [1, 64, 16, 16, 16]], - [[1, 32*16, 16, 16], [1,1,2,2], [1, 32, 16, 32*32], [1, 32, 32, 32*32], [1, 32, 32, 32, 32]], - [[1, 16*32, 32, 32], [1,1,2,2], [1, 16, 32, 64*64], [1, 16, 64, 64*64], [1, 16, 64, 64, 64]], - [[1, 4*16, 16, 16], [1,1,2,2], [1, 4, 16, 32*32], [1, 4, 32, 32*32], [1, 4, 32, 32, 32]], - [[1, 4*32, 32, 32], [1,1,2,2], [1, 4, 32, 64*64], [1, 4, 64, 64*64], [1, 4, 64, 64, 64]]] - - #4 128 4 4 4 - shapes4 = [[[4, 128*4, 4, 4], [1,1,2,2], [4, 128, 4, 8*8], [4, 128, 8, 8*8], [4, 128, 8, 8, 8]], - [[4, 64*8, 8, 8], [1,1,2,2], [4, 64, 8, 16*16], [4, 64, 16, 16*16], [4, 64, 16, 16, 16]], - [[4, 32*16, 16, 16], [1,1,2,2], [4, 32, 16, 32*32], [4, 32, 32, 32*32], [4, 32, 32, 32, 32]], - [[4, 16*32, 32, 32], [1,1,2,2], [4, 16, 32, 64*64], [4, 16, 64, 64*64], [4, 16, 64, 64, 64]], - [[4, 4*16, 16, 16], [1,1,2,2], [4, 4, 16, 32*32], [4, 4, 32, 32*32], [4, 4, 32, 32, 32]], - [[4, 4*32, 32, 32], [1,1,2,2], [4, 4, 32, 64*64], [4, 4, 64, 64*64], [4, 4, 64, 64, 64]]] - - #8 128 4 4 4 -> 8 128*4 4 4 -> 8 128*4 8 8 -> 8 128 4 8*8 -> 8 128 8 8*8 -> 8 128 8 8 8 - shapes8 = [[[8, 128*4, 4, 4], [1,1,2,2], [8, 128, 4, 8*8], [8, 128, 8, 8*8], [8, 128, 8, 8, 8]], - [[8, 64*8, 8, 8], [1,1,2,2], [8, 64, 8, 16*16], [8, 64, 16, 16*16], [8, 64, 16, 16, 16]], - [[8, 32*16, 16, 16], [1,1,2,2], [8, 32, 16, 32*32], [8, 32, 32, 32*32], [8, 32, 32, 32, 32]], - [[8, 16*32, 32, 32], [1,1,2,2], [8, 16, 32, 64*64], [8, 16, 64, 64*64], [8, 16, 64, 64, 64]], - [[8, 4*16, 16, 16], [1,1,2,2], [8, 4, 16, 32*32], [8, 4, 32, 32*32], [8, 4, 32, 32, 32]], - [[8, 4*32, 32, 32], [1,1,2,2], [8, 4, 32, 64*64], [8, 4, 64, 64*64], [8, 4, 64, 64, 64]]] - - #16 128 4 4 4 -> 16 128*4 4 4 -> 16 128*4 8 8 -> 16 128 4 8*8 -> 16 128 8 8*8 -> 16 128 8 8 8 - shapes16 = [[[16, 128*4, 4, 4], [1,1,2,2], [16, 128, 4, 8*8], [16, 128, 8, 8*8], [16, 128, 8, 8, 8]], - [[16, 64*8, 8, 8], [1,1,2,2], [16, 64, 8, 16*16], [16, 64, 16, 16*16], [16, 64, 16, 16, 16]], - [[16, 32*16, 16, 16], [1,1,2,2], [16, 32, 16, 32*32], [16, 32, 32, 32*32], [16, 32, 32, 32, 32]], - [[16, 16*32, 32, 32], [1,1,2,2], [16, 16, 32, 64*64], [16, 16, 64, 64*64], [16, 16, 64, 64, 64]], - [[16, 4*16, 16, 16], [1,1,2,2], [16, 4, 16, 32*32], [16, 4, 32, 32*32], [16, 4, 32, 32, 32]], - [[16, 4*32, 32, 32], [1,1,2,2], [16, 4, 32, 64*64], [16, 4, 64, 64*64], [16, 4, 64, 64, 64]]] - - #32 128 4 4 4 -> 32 128*4 4 4 -> 32 128*4 8 8 -> 32 128 4 8*8 -> 32 128 8 8*8 -> 32 128 8 8 8 - shapes32 = [[[32, 128*4, 4, 4], [1,1,2,2], [32, 128, 4, 8*8], [32, 128, 8, 8*8], [32, 128, 8, 8, 8]], - [[32, 64*8, 8, 8], [1,1,2,2], [32, 64, 8, 16*16], [32, 64, 16, 16*16], [32, 64, 16, 16, 16]], - [[32, 32*16, 16, 16], [1,1,2,2], [32, 32, 16, 32*32], [32, 32, 32, 32*32], [32, 32, 32, 32, 32]], - [[32, 16*32, 32, 32], [1,1,2,2], [32, 16, 32, 64*64], [32, 16, 64, 64*64], [32, 16, 64, 64, 64]], - [[32, 4*16, 16, 16], [1,1,2,2], [32, 4, 16, 32*32], [32, 4, 32, 32*32], [32, 4, 32, 32, 32]], - [[32, 4*32, 32, 32], [1,1,2,2], [32, 4, 32, 64*64], [32, 4, 64, 64*64], [32, 4, 64, 64, 64]]] - - if batchsize == "1": - shapes = shapes1 - - elif batchsize == "4": - shapes = shapes4 - - elif batchsize == "8": - shapes = shapes8 - - elif batchsize == "16": - shapes = shapes16 - - elif batchsize == "32": - shapes = shapes32 - else: - print("batchsize输入错误") - - for idx, node in enumerate(resizes): - print("idx: node.name", idx, node.name) - reshape1 = graph.add_node(f'Reshape_{node.name}', 'Reshape') - graph.add_initializer(f'shape_{node.name}', np.array(shapes[idx][0])) - reshape1.inputs = [node.inputs[0], f'shape_{node.name}'] - reshape1.outputs = [f'Reshape_{node.name}'] - - graph[node.inputs[-1]].value = np.array(shapes[idx][1]).astype(np.float32) - out_name = node.outputs[0] - node.set_input(0, f'Reshape_{node.name}') - node.set_output(0, f'{node.name}_reshape') - - reshape2 = graph.add_node(f'Reshape2_{node.name}', 'Reshape') - graph.add_initializer(f'shape2_{node.name}', np.array(shapes[idx][2])) - reshape2.inputs = [f'{node.name}_reshape', f'shape2_{node.name}'] - reshape2.outputs = [f'Reshape2_{node.name}_out'] - - resize2 = graph.add_node(f'Resize2_{node.name}', 'Resize') - graph.add_initializer(f'size_{node.name}', np.array(shapes[idx][3])) - resize2.inputs = [f'Reshape2_{node.name}_out', node.inputs[1], node.inputs[1], f'size_{node.name}'] - resize2.outputs = [f'Resize2_{node.name}'] - - reshape3 = graph.add_node(f'Reshape3_{node.name}', 'Reshape') - graph.add_initializer(f'shape3_{node.name}', np.array(shapes[idx][4])) - reshape3.inputs = [f'Resize2_{node.name}', f'shape3_{node.name}'] - reshape3.outputs = [out_name] - - graph.save(output_file) - -if __name__ == "__main__": - #input_file是输入的简化后的onnx路径,output_file是输出的onnx名称,batchsize是要转的onnx对应的batchsize大小 - input_file = sys.argv[1] - output_file = sys.argv[2] - batch = sys.argv[3] - modify(input_file, batch) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 numpy as np +from magiconnx import OnnxGraph +import sys + +def modify(path, batchsize): + graph = OnnxGraph(path) + resizes = graph.get_nodes("Resize") + #1 128 4 4 4 -> 1 128*4 4 4 -> 1 128*4 8 8 -> 1 128 4 8*8 -> 1 128 8 8*8 -> 1 128 8 8 8 + shapes1 = [[[1, 128*4, 4, 4], [1,1,2,2], [1, 128, 4, 8*8], [1, 128, 8, 8*8], [1, 128, 8, 8, 8]], + [[1, 64*8, 8, 8], [1,1,2,2], [1, 64, 8, 16*16], [1, 64, 16, 16*16], [1, 64, 16, 16, 16]], + [[1, 32*16, 16, 16], [1,1,2,2], [1, 32, 16, 32*32], [1, 32, 32, 32*32], [1, 32, 32, 32, 32]], + [[1, 16*32, 32, 32], [1,1,2,2], [1, 16, 32, 64*64], [1, 16, 64, 64*64], [1, 16, 64, 64, 64]], + [[1, 4*16, 16, 16], [1,1,2,2], [1, 4, 16, 32*32], [1, 4, 32, 32*32], [1, 4, 32, 32, 32]], + [[1, 4*32, 32, 32], [1,1,2,2], [1, 4, 32, 64*64], [1, 4, 64, 64*64], [1, 4, 64, 64, 64]]] + + #4 128 4 4 4 + shapes4 = [[[4, 128*4, 4, 4], [1,1,2,2], [4, 128, 4, 8*8], [4, 128, 8, 8*8], [4, 128, 8, 8, 8]], + [[4, 64*8, 8, 8], [1,1,2,2], [4, 64, 8, 16*16], [4, 64, 16, 16*16], [4, 64, 16, 16, 16]], + [[4, 32*16, 16, 16], [1,1,2,2], [4, 32, 16, 32*32], [4, 32, 32, 32*32], [4, 32, 32, 32, 32]], + [[4, 16*32, 32, 32], [1,1,2,2], [4, 16, 32, 64*64], [4, 16, 64, 64*64], [4, 16, 64, 64, 64]], + [[4, 4*16, 16, 16], [1,1,2,2], [4, 4, 16, 32*32], [4, 4, 32, 32*32], [4, 4, 32, 32, 32]], + [[4, 4*32, 32, 32], [1,1,2,2], [4, 4, 32, 64*64], [4, 4, 64, 64*64], [4, 4, 64, 64, 64]]] + + #8 128 4 4 4 -> 8 128*4 4 4 -> 8 128*4 8 8 -> 8 128 4 8*8 -> 8 128 8 8*8 -> 8 128 8 8 8 + shapes8 = [[[8, 128*4, 4, 4], [1,1,2,2], [8, 128, 4, 8*8], [8, 128, 8, 8*8], [8, 128, 8, 8, 8]], + [[8, 64*8, 8, 8], [1,1,2,2], [8, 64, 8, 16*16], [8, 64, 16, 16*16], [8, 64, 16, 16, 16]], + [[8, 32*16, 16, 16], [1,1,2,2], [8, 32, 16, 32*32], [8, 32, 32, 32*32], [8, 32, 32, 32, 32]], + [[8, 16*32, 32, 32], [1,1,2,2], [8, 16, 32, 64*64], [8, 16, 64, 64*64], [8, 16, 64, 64, 64]], + [[8, 4*16, 16, 16], [1,1,2,2], [8, 4, 16, 32*32], [8, 4, 32, 32*32], [8, 4, 32, 32, 32]], + [[8, 4*32, 32, 32], [1,1,2,2], [8, 4, 32, 64*64], [8, 4, 64, 64*64], [8, 4, 64, 64, 64]]] + + #16 128 4 4 4 -> 16 128*4 4 4 -> 16 128*4 8 8 -> 16 128 4 8*8 -> 16 128 8 8*8 -> 16 128 8 8 8 + shapes16 = [[[16, 128*4, 4, 4], [1,1,2,2], [16, 128, 4, 8*8], [16, 128, 8, 8*8], [16, 128, 8, 8, 8]], + [[16, 64*8, 8, 8], [1,1,2,2], [16, 64, 8, 16*16], [16, 64, 16, 16*16], [16, 64, 16, 16, 16]], + [[16, 32*16, 16, 16], [1,1,2,2], [16, 32, 16, 32*32], [16, 32, 32, 32*32], [16, 32, 32, 32, 32]], + [[16, 16*32, 32, 32], [1,1,2,2], [16, 16, 32, 64*64], [16, 16, 64, 64*64], [16, 16, 64, 64, 64]], + [[16, 4*16, 16, 16], [1,1,2,2], [16, 4, 16, 32*32], [16, 4, 32, 32*32], [16, 4, 32, 32, 32]], + [[16, 4*32, 32, 32], [1,1,2,2], [16, 4, 32, 64*64], [16, 4, 64, 64*64], [16, 4, 64, 64, 64]]] + + #32 128 4 4 4 -> 32 128*4 4 4 -> 32 128*4 8 8 -> 32 128 4 8*8 -> 32 128 8 8*8 -> 32 128 8 8 8 + shapes32 = [[[32, 128*4, 4, 4], [1,1,2,2], [32, 128, 4, 8*8], [32, 128, 8, 8*8], [32, 128, 8, 8, 8]], + [[32, 64*8, 8, 8], [1,1,2,2], [32, 64, 8, 16*16], [32, 64, 16, 16*16], [32, 64, 16, 16, 16]], + [[32, 32*16, 16, 16], [1,1,2,2], [32, 32, 16, 32*32], [32, 32, 32, 32*32], [32, 32, 32, 32, 32]], + [[32, 16*32, 32, 32], [1,1,2,2], [32, 16, 32, 64*64], [32, 16, 64, 64*64], [32, 16, 64, 64, 64]], + [[32, 4*16, 16, 16], [1,1,2,2], [32, 4, 16, 32*32], [32, 4, 32, 32*32], [32, 4, 32, 32, 32]], + [[32, 4*32, 32, 32], [1,1,2,2], [32, 4, 32, 64*64], [32, 4, 64, 64*64], [32, 4, 64, 64, 64]]] + + if batchsize == "1": + shapes = shapes1 + + elif batchsize == "4": + shapes = shapes4 + + elif batchsize == "8": + shapes = shapes8 + + elif batchsize == "16": + shapes = shapes16 + + elif batchsize == "32": + shapes = shapes32 + else: + print("batchsize输入错误") + + for idx, node in enumerate(resizes): + print("idx: node.name", idx, node.name) + reshape1 = graph.add_node(f'Reshape_{node.name}', 'Reshape') + graph.add_initializer(f'shape_{node.name}', np.array(shapes[idx][0])) + reshape1.inputs = [node.inputs[0], f'shape_{node.name}'] + reshape1.outputs = [f'Reshape_{node.name}'] + + graph[node.inputs[-1]].value = np.array(shapes[idx][1]).astype(np.float32) + out_name = node.outputs[0] + node.set_input(0, f'Reshape_{node.name}') + node.set_output(0, f'{node.name}_reshape') + + reshape2 = graph.add_node(f'Reshape2_{node.name}', 'Reshape') + graph.add_initializer(f'shape2_{node.name}', np.array(shapes[idx][2])) + reshape2.inputs = [f'{node.name}_reshape', f'shape2_{node.name}'] + reshape2.outputs = [f'Reshape2_{node.name}_out'] + + resize2 = graph.add_node(f'Resize2_{node.name}', 'Resize') + graph.add_initializer(f'size_{node.name}', np.array(shapes[idx][3])) + resize2.inputs = [f'Reshape2_{node.name}_out', node.inputs[1], node.inputs[1], f'size_{node.name}'] + resize2.outputs = [f'Resize2_{node.name}'] + + reshape3 = graph.add_node(f'Reshape3_{node.name}', 'Reshape') + graph.add_initializer(f'shape3_{node.name}', np.array(shapes[idx][4])) + reshape3.inputs = [f'Resize2_{node.name}', f'shape3_{node.name}'] + reshape3.outputs = [out_name] + + graph.save(output_file) + +if __name__ == "__main__": + #input_file是输入的简化后的onnx路径,output_file是输出的onnx名称,batchsize是要转的onnx对应的batchsize大小 + input_file = sys.argv[1] + output_file = sys.argv[2] + batch = sys.argv[3] + modify(input_file, batch) diff --git a/ACL_PyTorch/contrib/cv/detection/3DUnet/postprocess.py b/ACL_PyTorch/contrib/cv/detection/3DUnet/postprocess.py index 811c649ef3..de0ce74cd8 100644 --- a/ACL_PyTorch/contrib/cv/detection/3DUnet/postprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/3DUnet/postprocess.py @@ -1,131 +1,131 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import os - -import torch -import torch.nn.functional as F - -# Lib files -import numpy as np -from torch.utils.data import dataset -import lib.utils as utils -import lib.medloaders as medical_loaders -import lib.medzoo as medzoo -from lib.visual3D_temp import non_overlap_padding,test_padding -from lib.losses3D import DiceLoss -from lib.utils.general import prepare_input - - -from lib.medloaders.brats2018 import MICCAIBraTS2018 - -from glob import glob - - - -def main(): - args = get_arguments() - model, optimizer = medzoo.create_model(args) - batchSz = args.batchSz - score = 0 - model.eval() - bin_file_path = args.input_bin - pth_file_path = args.input_label - - length = glob(bin_file_path + '/*.bin') - length1 = glob(pth_file_path + '/*.pth') - - criterion = DiceLoss(classes=args.classes) - - for s in range(0, len(length)): - binfile = os.path.join(bin_file_path, str(s) + '_output_0' + ".bin") - output = np.fromfile(binfile, dtype=np.float32) - output = np.reshape(output, (batchSz, 4, 64, 64, 64)) - output = torch.from_numpy(output) - - pthfile = os.path.join(pth_file_path, str(s) + ".pth") - target = torch.load(pthfile) - target = torch.from_numpy(target) - - loss_dice, per_ch_score = criterion(output, target) - avg = np.mean(per_ch_score) - score += avg - print("--------score.avg------------", score / len(length)) - return score / len(length) - - - -def get_arguments(): - parser = argparse.ArgumentParser() - parser.add_argument('--batchSz', type=int, default=1) - parser.add_argument('--dataset_name', type=str, default="brats2018") - parser.add_argument('--dim', nargs="+", type=int, default=(64, 64, 64)) - parser.add_argument('--nEpochs', type=int, default=100) - parser.add_argument('--classes', type=int, default=4) - parser.add_argument('--samples_train', type=int, default=1024) - parser.add_argument('--samples_val', type=int, default=128) - parser.add_argument('--inChannels', type=int, default=4) - parser.add_argument('--inModalities', type=int, default=4) - parser.add_argument('--threshold', default=0.00000000001, type=float) - parser.add_argument('--terminal_show_freq', default=50) - parser.add_argument('--augmentation', action='store_true', default=True) - parser.add_argument('--normalization', default='full_volume_mean', type=str, - help='Tensor normalization: options ,max_min,', - choices=('max_min', 'full_volume_mean', 'brats', 'max', 'mean')) - parser.add_argument('--split', default=0.8, type=float, help='Select percentage of training data(default: 0.8)') - parser.add_argument('--lr', default=5e-3, type=float, - help='learning rate (default: 5e-3)') - parser.add_argument('--cuda', action='store_true', default=False) - - parser.add_argument('--loadData', default=True) - parser.add_argument('--resume', default='', type=str, metavar='PATH', - help='path to latest checkpoint (default: none)') - parser.add_argument('--model', type=str, default='UNET3D', - choices=('VNET', 'VNET2', 'UNET3D', 'DENSENET1', 'DENSENET2', 'DENSENET3', 'HYPERDENSENET')) - parser.add_argument('--opt', type=str, default='sgd', - choices=('sgd', 'adam', 'rmsprop')) - parser.add_argument('--log_dir', type=str, - default='./runs/') - parser.add_argument('--prof', default=False, action='store_true', - help='use profiling to evaluate the performance of model') - - parser.add_argument('--world_size', type=int, default=1) - parser.add_argument('--rank', type=int, default=0) - - - parser.add_argument('--amp', action='store_true', default=False) - - parser.add_argument('--workers', type=int, default=8) - - - parser.add_argument('--device', default='npu', type=str, help='npu or gpu') - parser.add_argument('--pretrained', - default="none", - type=str, metavar='PATH', - help='path to pretrained model') - parser.add_argument('--input_bin', default='none', type=str) - parser.add_argument('--input_label', default='none', type=str) - - - args = parser.parse_args() - - args.save = '../inference_checkpoints/' + args.model + '_checkpoints/' + args.model + '_{}_{}_'.format( - utils.datestr(), args.dataset_name) - args.tb_log_dir = '../runs/' - return args - - - -if __name__ == '__main__': +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import os + +import torch +import torch.nn.functional as F + +# Lib files +import numpy as np +from torch.utils.data import dataset +import lib.utils as utils +import lib.medloaders as medical_loaders +import lib.medzoo as medzoo +from lib.visual3D_temp import non_overlap_padding,test_padding +from lib.losses3D import DiceLoss +from lib.utils.general import prepare_input + + +from lib.medloaders.brats2018 import MICCAIBraTS2018 + +from glob import glob + + + +def main(): + args = get_arguments() + model, optimizer = medzoo.create_model(args) + batchSz = args.batchSz + score = 0 + model.eval() + bin_file_path = args.input_bin + pth_file_path = args.input_label + + length = glob(bin_file_path + '/*.bin') + length1 = glob(pth_file_path + '/*.pth') + + criterion = DiceLoss(classes=args.classes) + + for s in range(0, len(length)): + binfile = os.path.join(bin_file_path, str(s) + '_output_0' + ".bin") + output = np.fromfile(binfile, dtype=np.float32) + output = np.reshape(output, (batchSz, 4, 64, 64, 64)) + output = torch.from_numpy(output) + + pthfile = os.path.join(pth_file_path, str(s) + ".pth") + target = torch.load(pthfile) + target = torch.from_numpy(target) + + loss_dice, per_ch_score = criterion(output, target) + avg = np.mean(per_ch_score) + score += avg + print("--------score.avg------------", score / len(length)) + return score / len(length) + + + +def get_arguments(): + parser = argparse.ArgumentParser() + parser.add_argument('--batchSz', type=int, default=1) + parser.add_argument('--dataset_name', type=str, default="brats2018") + parser.add_argument('--dim', nargs="+", type=int, default=(64, 64, 64)) + parser.add_argument('--nEpochs', type=int, default=100) + parser.add_argument('--classes', type=int, default=4) + parser.add_argument('--samples_train', type=int, default=1024) + parser.add_argument('--samples_val', type=int, default=128) + parser.add_argument('--inChannels', type=int, default=4) + parser.add_argument('--inModalities', type=int, default=4) + parser.add_argument('--threshold', default=0.00000000001, type=float) + parser.add_argument('--terminal_show_freq', default=50) + parser.add_argument('--augmentation', action='store_true', default=True) + parser.add_argument('--normalization', default='full_volume_mean', type=str, + help='Tensor normalization: options ,max_min,', + choices=('max_min', 'full_volume_mean', 'brats', 'max', 'mean')) + parser.add_argument('--split', default=0.8, type=float, help='Select percentage of training data(default: 0.8)') + parser.add_argument('--lr', default=5e-3, type=float, + help='learning rate (default: 5e-3)') + parser.add_argument('--cuda', action='store_true', default=False) + + parser.add_argument('--loadData', default=True) + parser.add_argument('--resume', default='', type=str, metavar='PATH', + help='path to latest checkpoint (default: none)') + parser.add_argument('--model', type=str, default='UNET3D', + choices=('VNET', 'VNET2', 'UNET3D', 'DENSENET1', 'DENSENET2', 'DENSENET3', 'HYPERDENSENET')) + parser.add_argument('--opt', type=str, default='sgd', + choices=('sgd', 'adam', 'rmsprop')) + parser.add_argument('--log_dir', type=str, + default='./runs/') + parser.add_argument('--prof', default=False, action='store_true', + help='use profiling to evaluate the performance of model') + + parser.add_argument('--world_size', type=int, default=1) + parser.add_argument('--rank', type=int, default=0) + + + parser.add_argument('--amp', action='store_true', default=False) + + parser.add_argument('--workers', type=int, default=8) + + + parser.add_argument('--device', default='npu', type=str, help='npu or gpu') + parser.add_argument('--pretrained', + default="none", + type=str, metavar='PATH', + help='path to pretrained model') + parser.add_argument('--input_bin', default='none', type=str) + parser.add_argument('--input_label', default='none', type=str) + + + args = parser.parse_args() + + args.save = '../inference_checkpoints/' + args.model + '_checkpoints/' + args.model + '_{}_{}_'.format( + utils.datestr(), args.dataset_name) + args.tb_log_dir = '../runs/' + return args + + + +if __name__ == '__main__': main() \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/AlphaPose/AlphaPose.patch b/ACL_PyTorch/contrib/cv/detection/AlphaPose/AlphaPose.patch index 6cde848c51..99caa0d26e 100644 --- a/ACL_PyTorch/contrib/cv/detection/AlphaPose/AlphaPose.patch +++ b/ACL_PyTorch/contrib/cv/detection/AlphaPose/AlphaPose.patch @@ -209,16 +209,16 @@ index 8a755c9..b8e4c57 100644 --- a/detector/yolo_cfg.py +++ b/detector/yolo_cfg.py @@ -1,8 +1,8 @@ - from easydict import EasyDict as edict - - cfg = edict() --cfg.CONFIG = 'detector/yolo/cfg/yolov3-spp.cfg' --cfg.WEIGHTS = 'detector/yolo/data/yolov3-spp.weights' -+cfg.CONFIG = 'AlphaPose/detector/yolo/cfg/yolov3-spp.cfg' -+cfg.WEIGHTS = 'AlphaPose/detector/yolo/data/yolov3-spp.weights' - cfg.INP_DIM = 608 - cfg.NMS_THRES = 0.6 - cfg.CONFIDENCE = 0.1 + from easydict import EasyDict as edict + + cfg = edict() +-cfg.CONFIG = 'detector/yolo/cfg/yolov3-spp.cfg' +-cfg.WEIGHTS = 'detector/yolo/data/yolov3-spp.weights' ++cfg.CONFIG = 'AlphaPose/detector/yolo/cfg/yolov3-spp.cfg' ++cfg.WEIGHTS = 'AlphaPose/detector/yolo/data/yolov3-spp.weights' + cfg.INP_DIM = 608 + cfg.NMS_THRES = 0.6 + cfg.CONFIDENCE = 0.1 diff --git a/setup.py b/setup.py index d1e397d..4ad65f8 100644 --- a/setup.py diff --git a/ACL_PyTorch/contrib/cv/detection/AlphaPose/LICENSE b/ACL_PyTorch/contrib/cv/detection/AlphaPose/LICENSE index 8904c85160..5f7aa69fea 100644 --- a/ACL_PyTorch/contrib/cv/detection/AlphaPose/LICENSE +++ b/ACL_PyTorch/contrib/cv/detection/AlphaPose/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/AlphaPose/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/detection/AlphaPose/gen_dataset_info.py index efe82aef07..3656966b4c 100644 --- a/ACL_PyTorch/contrib/cv/detection/AlphaPose/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/detection/AlphaPose/gen_dataset_info.py @@ -1,65 +1,65 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(fpath, info_n, width, height): - ''' - Describe - ''' - bin_images = glob(os.path.join(fpath, '*.bin')) - with open(info_n, 'w') as f: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - f.write(content) - f.write('\n') - - -def get_jpg_info(fpath, info_n): - ''' - Describe - ''' - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(fpath, '*.' + extension))) - with open(info_n, 'w') as f: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - f.write(content) - f.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - Width = sys.argv[4] - Height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, Width, Height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' - get_jpg_info(file_path, info_name) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(fpath, info_n, width, height): + ''' + Describe + ''' + bin_images = glob(os.path.join(fpath, '*.bin')) + with open(info_n, 'w') as f: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + f.write(content) + f.write('\n') + + +def get_jpg_info(fpath, info_n): + ''' + Describe + ''' + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(fpath, '*.' + extension))) + with open(info_n, 'w') as f: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + f.write(content) + f.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + Width = sys.argv[4] + Height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, Width, Height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' + get_jpg_info(file_path, info_name) diff --git a/ACL_PyTorch/contrib/cv/detection/AlphaPose/test/parse.py b/ACL_PyTorch/contrib/cv/detection/AlphaPose/test/parse.py index a0f253b055..27eae0d0ac 100644 --- a/ACL_PyTorch/contrib/cv/detection/AlphaPose/test/parse.py +++ b/ACL_PyTorch/contrib/cv/detection/AlphaPose/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/BSN/BSN_eval.py b/ACL_PyTorch/contrib/cv/detection/BSN/BSN_eval.py index 0976dab05c..0624523f6f 100644 --- a/ACL_PyTorch/contrib/cv/detection/BSN/BSN_eval.py +++ b/ACL_PyTorch/contrib/cv/detection/BSN/BSN_eval.py @@ -1,85 +1,85 @@ -# -*- coding: utf-8 -*- -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -sys.path.append('./BSN-boundary-sensitive-network.pytorch/Evaluation') -from eval_proposal import ANETproposal -import matplotlib.pyplot as plt -import numpy as np - -def run_evaluation(ground_truth_filename, proposal_filename, - max_avg_nr_proposals=100, - tiou_thresholds=np.linspace(0.5, 0.95, 10), - subset='validation'): - - anet_proposal = ANETproposal(ground_truth_filename, proposal_filename, - tiou_thresholds=tiou_thresholds, - max_avg_nr_proposals=max_avg_nr_proposals, - subset=subset, verbose=True, check_status=False) - anet_proposal.evaluate() - - recall = anet_proposal.recall - average_recall = anet_proposal.avg_recall - average_nr_proposals = anet_proposal.proposals_per_video - - return (average_nr_proposals, average_recall, recall) - -def plot_metric(average_nr_proposals, average_recall, recall, tiou_thresholds=np.linspace(0.5, 0.95, 10)): - - fn_size = 14 - plt.figure(num=None, figsize=(12, 8)) - ax = plt.subplot(1,1,1) - - colors = ['k', 'r', 'yellow', 'b', 'c', 'm', 'b', 'pink', 'lawngreen', 'indigo'] - area_under_curve = np.zeros_like(tiou_thresholds) - for i in range(recall.shape[0]): - area_under_curve[i] = np.trapz(recall[i], average_nr_proposals) - - for idx, tiou in enumerate(tiou_thresholds[::2]): - ax.plot(average_nr_proposals, recall[2*idx,:], color=colors[idx+1], - label="tiou=[" + str(tiou) + "], area=" + str(int(area_under_curve[2*idx]*100)/100.), - linewidth=4, linestyle='--', marker=None) - # Plots Average Recall vs Average number of proposals. - ax.plot(average_nr_proposals, average_recall, color=colors[0], - label="tiou = 0.5:0.05:0.95," + " area=" + str(int(np.trapz(average_recall, average_nr_proposals)*100)/100.), - linewidth=4, linestyle='-', marker=None) - - handles, labels = ax.get_legend_handles_labels() - ax.legend([handles[-1]] + handles[:-1], [labels[-1]] + labels[:-1], loc='best') - - plt.ylabel('Average Recall', fontsize=fn_size) - plt.xlabel('Average Number of Proposals per Video', fontsize=fn_size) - plt.grid(b=True, which="both") - plt.ylim([0, 1.0]) - plt.setp(plt.axes().get_xticklabels(), fontsize=fn_size) - plt.setp(plt.axes().get_yticklabels(), fontsize=fn_size) - #plt.show() - plt.savefig("./output/evaluation_result.jpg") - -def evaluation_proposal(): - - uniform_average_nr_proposals_valid, uniform_average_recall_valid, uniform_recall_valid = run_evaluation( - "./BSN-boundary-sensitive-network.pytorch/Evaluation/data/activity_net_1_3_new.json", - "./output/result_proposal.json", - max_avg_nr_proposals=100, - tiou_thresholds=np.linspace(0.5, 0.95, 10), - subset='validation') - - plot_metric(uniform_average_nr_proposals_valid, uniform_average_recall_valid, uniform_recall_valid) - print('AR@1 is \t{}'.format(np.mean(uniform_recall_valid[:,0]))) - print('AR@5 is \t{}'.format(np.mean(uniform_recall_valid[:,4]))) - print('AR@10 is \t{}'.format(np.mean(uniform_recall_valid[:,9]))) - print('AR@100 is \t{}'.format(np.mean(uniform_recall_valid[:,-1]))) -if __name__ =="__main__": +# -*- coding: utf-8 -*- +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +sys.path.append('./BSN-boundary-sensitive-network.pytorch/Evaluation') +from eval_proposal import ANETproposal +import matplotlib.pyplot as plt +import numpy as np + +def run_evaluation(ground_truth_filename, proposal_filename, + max_avg_nr_proposals=100, + tiou_thresholds=np.linspace(0.5, 0.95, 10), + subset='validation'): + + anet_proposal = ANETproposal(ground_truth_filename, proposal_filename, + tiou_thresholds=tiou_thresholds, + max_avg_nr_proposals=max_avg_nr_proposals, + subset=subset, verbose=True, check_status=False) + anet_proposal.evaluate() + + recall = anet_proposal.recall + average_recall = anet_proposal.avg_recall + average_nr_proposals = anet_proposal.proposals_per_video + + return (average_nr_proposals, average_recall, recall) + +def plot_metric(average_nr_proposals, average_recall, recall, tiou_thresholds=np.linspace(0.5, 0.95, 10)): + + fn_size = 14 + plt.figure(num=None, figsize=(12, 8)) + ax = plt.subplot(1,1,1) + + colors = ['k', 'r', 'yellow', 'b', 'c', 'm', 'b', 'pink', 'lawngreen', 'indigo'] + area_under_curve = np.zeros_like(tiou_thresholds) + for i in range(recall.shape[0]): + area_under_curve[i] = np.trapz(recall[i], average_nr_proposals) + + for idx, tiou in enumerate(tiou_thresholds[::2]): + ax.plot(average_nr_proposals, recall[2*idx,:], color=colors[idx+1], + label="tiou=[" + str(tiou) + "], area=" + str(int(area_under_curve[2*idx]*100)/100.), + linewidth=4, linestyle='--', marker=None) + # Plots Average Recall vs Average number of proposals. + ax.plot(average_nr_proposals, average_recall, color=colors[0], + label="tiou = 0.5:0.05:0.95," + " area=" + str(int(np.trapz(average_recall, average_nr_proposals)*100)/100.), + linewidth=4, linestyle='-', marker=None) + + handles, labels = ax.get_legend_handles_labels() + ax.legend([handles[-1]] + handles[:-1], [labels[-1]] + labels[:-1], loc='best') + + plt.ylabel('Average Recall', fontsize=fn_size) + plt.xlabel('Average Number of Proposals per Video', fontsize=fn_size) + plt.grid(b=True, which="both") + plt.ylim([0, 1.0]) + plt.setp(plt.axes().get_xticklabels(), fontsize=fn_size) + plt.setp(plt.axes().get_yticklabels(), fontsize=fn_size) + #plt.show() + plt.savefig("./output/evaluation_result.jpg") + +def evaluation_proposal(): + + uniform_average_nr_proposals_valid, uniform_average_recall_valid, uniform_recall_valid = run_evaluation( + "./BSN-boundary-sensitive-network.pytorch/Evaluation/data/activity_net_1_3_new.json", + "./output/result_proposal.json", + max_avg_nr_proposals=100, + tiou_thresholds=np.linspace(0.5, 0.95, 10), + subset='validation') + + plot_metric(uniform_average_nr_proposals_valid, uniform_average_recall_valid, uniform_recall_valid) + print('AR@1 is \t{}'.format(np.mean(uniform_recall_valid[:,0]))) + print('AR@5 is \t{}'.format(np.mean(uniform_recall_valid[:,4]))) + print('AR@10 is \t{}'.format(np.mean(uniform_recall_valid[:,9]))) + print('AR@100 is \t{}'.format(np.mean(uniform_recall_valid[:,-1]))) +if __name__ =="__main__": evaluation_proposal() \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/BSN/BSN_pem_postprocess.py b/ACL_PyTorch/contrib/cv/detection/BSN/BSN_pem_postprocess.py index ed9b16d775..f37f5a8236 100644 --- a/ACL_PyTorch/contrib/cv/detection/BSN/BSN_pem_postprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/BSN/BSN_pem_postprocess.py @@ -1,190 +1,190 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 json -import torch -import argparse -import os -import numpy as np -import pandas as pd -import multiprocessing as mp - -parser = argparse.ArgumentParser(description='BSN') - -parser.add_argument('--result_path',default='output/PEM_results', type=str, help='Dir to save txt results') -parser.add_argument('--PEM_out_path', default='result/dumpOutput_device1', type=str, help='infer out path') -parser.add_argument('--PEM_video_xmin_path', default='output/BSN-PEM-preprocess/xmin', type=str, help='infer info path') -parser.add_argument('--PEM_video_xmax_path', default='output/BSN-PEM-preprocess/xmax', type=str, help='infer info path') -parser.add_argument('--PEM_video_xmin_score_path', default='output/BSN-PEM-preprocess/xmin_score', type=str, help='infer info path') -parser.add_argument('--PEM_video_xmax_score_path', default='output/BSN-PEM-preprocess/xmax_score', type=str, help='infer info path') -# parser.add_argument('--info_name', default='./deepspeech_om_bin.info', type=str, help='input info path') -# parser.add_argument('--confidence_threshold', default=0.02, type=float, help='confidence_threshold') -args = parser.parse_args() - -def load_json(file): - with open(file) as json_file: - data = json.load(json_file) - return data - -def getDatasetDict(): - df=pd.read_csv("BSN-boundary-sensitive-network.pytorch/data/activitynet_annotations/video_info_new.csv") - json_data= load_json("BSN-boundary-sensitive-network.pytorch/data/activitynet_annotations/anet_anno_action.json") - database=json_data - video_dict={} - for i in range(len(df)): - video_name=df.video.values[i] - video_info=database[video_name] - video_new_info={} - video_new_info['duration_frame']=video_info['duration_frame'] - video_new_info['duration_second']=video_info['duration_second'] - video_new_info["feature_frame"]=video_info['feature_frame'] - video_subset=df.subset.values[i] - video_new_info['annotations']=video_info['annotations'] - if video_subset=="validation": - video_dict[video_name]=video_new_info - return video_dict - -def iou_with_anchors(anchors_min,anchors_max,len_anchors,box_min,box_max): - """Compute jaccard score between a box and the anchors. - """ - int_xmin = np.maximum(anchors_min, box_min) - int_xmax = np.minimum(anchors_max, box_max) - inter_len = np.maximum(int_xmax - int_xmin, 0.) - union_len = len_anchors - inter_len +box_max-box_min - #print inter_len,union_len - jaccard = np.divide(inter_len, union_len) - return jaccard - -def Soft_NMS(df): - df=df.sort_values(by="score",ascending=False) - - tstart=list(df.xmin.values[:]) - tend=list(df.xmax.values[:]) - tscore=list(df.score.values[:]) - rstart=[] - rend=[] - rscore=[] - - while len(tscore)>0 and len(rscore)<=100: - max_index=np.argmax(tscore) - tmp_width = tend[max_index] -tstart[max_index] - iou_list = iou_with_anchors(tstart[max_index],tend[max_index],tmp_width,np.array(tstart),np.array(tend)) - iou_exp_list = np.exp(-np.square(iou_list)/0.75) - for idx in range(0,len(tscore)): - if idx!=max_index: - tmp_iou = iou_list[idx] - if tmp_iou>0.65 + (0.9 - 0.65) * tmp_width: - tscore[idx]=tscore[idx]*iou_exp_list[idx] - - rstart.append(tstart[max_index]) - rend.append(tend[max_index]) - rscore.append(tscore[max_index]) - tstart.pop(max_index) - tend.pop(max_index) - tscore.pop(max_index) - - newDf=pd.DataFrame() - newDf['score']=rscore - newDf['xmin']=rstart - newDf['xmax']=rend - return newDf - -def video_post_process(video_list,video_dict): - - for video_name in video_list: - df=pd.read_csv("./output/PEM_results/"+video_name+".csv") - - df['score']=df.iou_score.values[:]*df.xmin_score.values[:]*df.xmax_score.values[:] - if len(df)>1: - df=Soft_NMS(df) - - df=df.sort_values(by="score",ascending=False) - video_info=video_dict[video_name] - video_duration=float(video_info["duration_frame"]/16*16)/video_info["duration_frame"]*video_info["duration_second"] - proposal_list=[] - - for j in range(min(100,len(df))): - tmp_proposal={} - tmp_proposal["score"]=df.score.values[j] - tmp_proposal["segment"]=[max(0,df.xmin.values[j])*video_duration,min(1,df.xmax.values[j])*video_duration] - proposal_list.append(tmp_proposal) - result_dict[video_name[2:]]=proposal_list - - -def BSN_post_processing(): - video_dict=getDatasetDict() - video_list=video_dict.keys()#[:100] - video_list = list(video_list) - global result_dict - result_dict=mp.Manager().dict() - - num_videos = len(video_list) - num_videos_per_thread = num_videos/8 - processes = [] - for tid in range(7): - tmp_video_list = video_list[int(tid*num_videos_per_thread):int((tid+1)*num_videos_per_thread)] - p = mp.Process(target = video_post_process,args =(tmp_video_list,video_dict,)) - p.start() - processes.append(p) - tmp_video_list = video_list[int(7*num_videos_per_thread):] - p = mp.Process(target = video_post_process,args =(tmp_video_list,video_dict,)) - p.start() - processes.append(p) - for p in processes: - p.join() - - result_dict = dict(result_dict) - output_dict={"version":"VERSION 1.3","results":result_dict,"external_data":{}} - outfile=open("./output/result_proposal.json","w") - json.dump(output_dict,outfile) - outfile.close() - -if __name__ == '__main__': - if not os.path.exists("output/PEM_results"): - os.makedirs("output/PEM_results") - out_files = os.listdir(args.PEM_out_path) - print("processing...") - for i in range(len(out_files)): - video_name = str(out_files[i]) - video_name = video_name[0:int(len(video_name)-6)] - video_data = np.fromfile(args.PEM_out_path+'/'+out_files[i],dtype=np.float32) - - video_xmin = np.fromfile(args.PEM_video_xmin_path+'/'+video_name+'.bin',dtype=np.float64) - video_xmax = np.fromfile(args.PEM_video_xmax_path+'/'+video_name+'.bin',dtype=np.float64) - video_xmin_score = np.fromfile(args.PEM_video_xmin_score_path+'/'+video_name+'.bin',dtype=np.float64) - video_xmax_score = np.fromfile(args.PEM_video_xmax_score_path+'/'+video_name+'.bin',dtype=np.float64) - - video_data = torch.tensor(video_data) - video_xmin = torch.tensor(video_xmin) - video_xmax = torch.tensor(video_xmax) - video_xmin_score = torch.tensor(video_xmin_score) - video_xmax_score = torch.tensor(video_xmax_score) - data_num = int(video_xmin.shape[0]) - video_data = video_data[:data_num] - - video_data = video_data.view(-1).detach().cpu().numpy() - video_xmin = video_xmin.view(-1).cpu().numpy() - video_xmax = video_xmax.view(-1).cpu().numpy() - video_xmin_score = video_xmin_score.view(-1).cpu().numpy() - video_xmax_score = video_xmax_score.view(-1).cpu().numpy() - - df=pd.DataFrame() - df["xmin"]=video_xmin - df["xmax"]=video_xmax - df["xmin_score"]=video_xmin_score - df["xmax_score"]=video_xmax_score - df["iou_score"]=video_data - df.to_csv(args.result_path+'/'+video_name+".csv",index=False) - print("PGM: start generating BSN_post feature") - BSN_post_processing() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 json +import torch +import argparse +import os +import numpy as np +import pandas as pd +import multiprocessing as mp + +parser = argparse.ArgumentParser(description='BSN') + +parser.add_argument('--result_path',default='output/PEM_results', type=str, help='Dir to save txt results') +parser.add_argument('--PEM_out_path', default='result/dumpOutput_device1', type=str, help='infer out path') +parser.add_argument('--PEM_video_xmin_path', default='output/BSN-PEM-preprocess/xmin', type=str, help='infer info path') +parser.add_argument('--PEM_video_xmax_path', default='output/BSN-PEM-preprocess/xmax', type=str, help='infer info path') +parser.add_argument('--PEM_video_xmin_score_path', default='output/BSN-PEM-preprocess/xmin_score', type=str, help='infer info path') +parser.add_argument('--PEM_video_xmax_score_path', default='output/BSN-PEM-preprocess/xmax_score', type=str, help='infer info path') +# parser.add_argument('--info_name', default='./deepspeech_om_bin.info', type=str, help='input info path') +# parser.add_argument('--confidence_threshold', default=0.02, type=float, help='confidence_threshold') +args = parser.parse_args() + +def load_json(file): + with open(file) as json_file: + data = json.load(json_file) + return data + +def getDatasetDict(): + df=pd.read_csv("BSN-boundary-sensitive-network.pytorch/data/activitynet_annotations/video_info_new.csv") + json_data= load_json("BSN-boundary-sensitive-network.pytorch/data/activitynet_annotations/anet_anno_action.json") + database=json_data + video_dict={} + for i in range(len(df)): + video_name=df.video.values[i] + video_info=database[video_name] + video_new_info={} + video_new_info['duration_frame']=video_info['duration_frame'] + video_new_info['duration_second']=video_info['duration_second'] + video_new_info["feature_frame"]=video_info['feature_frame'] + video_subset=df.subset.values[i] + video_new_info['annotations']=video_info['annotations'] + if video_subset=="validation": + video_dict[video_name]=video_new_info + return video_dict + +def iou_with_anchors(anchors_min,anchors_max,len_anchors,box_min,box_max): + """Compute jaccard score between a box and the anchors. + """ + int_xmin = np.maximum(anchors_min, box_min) + int_xmax = np.minimum(anchors_max, box_max) + inter_len = np.maximum(int_xmax - int_xmin, 0.) + union_len = len_anchors - inter_len +box_max-box_min + #print inter_len,union_len + jaccard = np.divide(inter_len, union_len) + return jaccard + +def Soft_NMS(df): + df=df.sort_values(by="score",ascending=False) + + tstart=list(df.xmin.values[:]) + tend=list(df.xmax.values[:]) + tscore=list(df.score.values[:]) + rstart=[] + rend=[] + rscore=[] + + while len(tscore)>0 and len(rscore)<=100: + max_index=np.argmax(tscore) + tmp_width = tend[max_index] -tstart[max_index] + iou_list = iou_with_anchors(tstart[max_index],tend[max_index],tmp_width,np.array(tstart),np.array(tend)) + iou_exp_list = np.exp(-np.square(iou_list)/0.75) + for idx in range(0,len(tscore)): + if idx!=max_index: + tmp_iou = iou_list[idx] + if tmp_iou>0.65 + (0.9 - 0.65) * tmp_width: + tscore[idx]=tscore[idx]*iou_exp_list[idx] + + rstart.append(tstart[max_index]) + rend.append(tend[max_index]) + rscore.append(tscore[max_index]) + tstart.pop(max_index) + tend.pop(max_index) + tscore.pop(max_index) + + newDf=pd.DataFrame() + newDf['score']=rscore + newDf['xmin']=rstart + newDf['xmax']=rend + return newDf + +def video_post_process(video_list,video_dict): + + for video_name in video_list: + df=pd.read_csv("./output/PEM_results/"+video_name+".csv") + + df['score']=df.iou_score.values[:]*df.xmin_score.values[:]*df.xmax_score.values[:] + if len(df)>1: + df=Soft_NMS(df) + + df=df.sort_values(by="score",ascending=False) + video_info=video_dict[video_name] + video_duration=float(video_info["duration_frame"]/16*16)/video_info["duration_frame"]*video_info["duration_second"] + proposal_list=[] + + for j in range(min(100,len(df))): + tmp_proposal={} + tmp_proposal["score"]=df.score.values[j] + tmp_proposal["segment"]=[max(0,df.xmin.values[j])*video_duration,min(1,df.xmax.values[j])*video_duration] + proposal_list.append(tmp_proposal) + result_dict[video_name[2:]]=proposal_list + + +def BSN_post_processing(): + video_dict=getDatasetDict() + video_list=video_dict.keys()#[:100] + video_list = list(video_list) + global result_dict + result_dict=mp.Manager().dict() + + num_videos = len(video_list) + num_videos_per_thread = num_videos/8 + processes = [] + for tid in range(7): + tmp_video_list = video_list[int(tid*num_videos_per_thread):int((tid+1)*num_videos_per_thread)] + p = mp.Process(target = video_post_process,args =(tmp_video_list,video_dict,)) + p.start() + processes.append(p) + tmp_video_list = video_list[int(7*num_videos_per_thread):] + p = mp.Process(target = video_post_process,args =(tmp_video_list,video_dict,)) + p.start() + processes.append(p) + for p in processes: + p.join() + + result_dict = dict(result_dict) + output_dict={"version":"VERSION 1.3","results":result_dict,"external_data":{}} + outfile=open("./output/result_proposal.json","w") + json.dump(output_dict,outfile) + outfile.close() + +if __name__ == '__main__': + if not os.path.exists("output/PEM_results"): + os.makedirs("output/PEM_results") + out_files = os.listdir(args.PEM_out_path) + print("processing...") + for i in range(len(out_files)): + video_name = str(out_files[i]) + video_name = video_name[0:int(len(video_name)-6)] + video_data = np.fromfile(args.PEM_out_path+'/'+out_files[i],dtype=np.float32) + + video_xmin = np.fromfile(args.PEM_video_xmin_path+'/'+video_name+'.bin',dtype=np.float64) + video_xmax = np.fromfile(args.PEM_video_xmax_path+'/'+video_name+'.bin',dtype=np.float64) + video_xmin_score = np.fromfile(args.PEM_video_xmin_score_path+'/'+video_name+'.bin',dtype=np.float64) + video_xmax_score = np.fromfile(args.PEM_video_xmax_score_path+'/'+video_name+'.bin',dtype=np.float64) + + video_data = torch.tensor(video_data) + video_xmin = torch.tensor(video_xmin) + video_xmax = torch.tensor(video_xmax) + video_xmin_score = torch.tensor(video_xmin_score) + video_xmax_score = torch.tensor(video_xmax_score) + data_num = int(video_xmin.shape[0]) + video_data = video_data[:data_num] + + video_data = video_data.view(-1).detach().cpu().numpy() + video_xmin = video_xmin.view(-1).cpu().numpy() + video_xmax = video_xmax.view(-1).cpu().numpy() + video_xmin_score = video_xmin_score.view(-1).cpu().numpy() + video_xmax_score = video_xmax_score.view(-1).cpu().numpy() + + df=pd.DataFrame() + df["xmin"]=video_xmin + df["xmax"]=video_xmax + df["xmin_score"]=video_xmin_score + df["xmax_score"]=video_xmax_score + df["iou_score"]=video_data + df.to_csv(args.result_path+'/'+video_name+".csv",index=False) + print("PGM: start generating BSN_post feature") + BSN_post_processing() print("PGM: finish generate BSN_post feature") \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/BSN/BSN_pem_preprocess.py b/ACL_PyTorch/contrib/cv/detection/BSN/BSN_pem_preprocess.py index 04d12cd6ad..575e1737fa 100644 --- a/ACL_PyTorch/contrib/cv/detection/BSN/BSN_pem_preprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/BSN/BSN_pem_preprocess.py @@ -1,106 +1,106 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 numpy as np -import pandas as pd -import pandas -import numpy -import json -import torch.utils.data as data -import os -import torch -import os -#import opts -import sys - -#opt = opts.parse_opt() -#opt = vars(opt) -def load_json(file): - with open(file) as json_file: - data = json.load(json_file) - return data - -if __name__ == '__main__': - if not os.path.exists("output/BSN-PEM-preprocess/feature"): - os.makedirs("output/BSN-PEM-preprocess/feature") - if not os.path.exists("output/BSN-PEM-preprocess/xmin"): - os.makedirs("output/BSN-PEM-preprocess/xmin") - if not os.path.exists("output/BSN-PEM-preprocess/xmax"): - os.makedirs("output/BSN-PEM-preprocess/xmax") - if not os.path.exists("output/BSN-PEM-preprocess/xmin_score"): - os.makedirs("output/BSN-PEM-preprocess/xmin_score") - if not os.path.exists("output/BSN-PEM-preprocess/xmax_score"): - os.makedirs("output/BSN-PEM-preprocess/xmax_score") - subset = "validation" - top_K = 1000 - video_info_path = "BSN-boundary-sensitive-network.pytorch/data/activitynet_annotations/video_info_new.csv" - video_anno_path = "BSN-boundary-sensitive-network.pytorch/data/activitynet_annotations/anet_anno_action.json" - #video_info_path = opt["video_info"] - #video_anno_path = opt["video_anno"] - pgm_proposals_path = "output/PGM_proposals/" - pgm_feature_path = "output/PGM_feature/" - pem_feature_path ="output/BSN-PEM-preprocess/feature" - pem_xmin_path ="output/BSN-PEM-preprocess/xmin" - pem_xmax_path ="output/BSN-PEM-preprocess/xmax" - pem_xmin_score_path ="output/BSN-PEM-preprocess/xmin_score" - pem_xmax_score_path ="output/BSN-PEM-preprocess/xmax_score" - anno_df = pd.read_csv(video_info_path) - anno_database= load_json(video_anno_path) - video_dict = {} - for i in range(len(anno_df)): - video_name=anno_df.video.values[i] - video_info=anno_database[video_name] - video_subset=anno_df.subset.values[i] - #if subset == "full": - # video_dict[video_name] = video_info - if subset in video_subset: - video_dict[video_name] = video_info - video_list = list(video_dict.keys()) - print("%s subset video numbers: %d" %(subset,len(video_list))) - - print("processing...") - for i in range(len(video_list)): - video_name = video_list[i] - pdf=pandas.read_csv(pgm_proposals_path+video_name+".csv") - pdf=pdf[:top_K] - video_feature = numpy.load(pgm_feature_path + video_name+".npy") - video_feature = video_feature[:top_K,:] - video_feature = torch.Tensor(video_feature) - video_xmin =pdf.xmin.values[:] - video_xmax =pdf.xmax.values[:] - video_xmin_score = pdf.xmin_score.values[:] - video_xmax_score = pdf.xmax_score.values[:] - - #video_feature = np.array(video_feature).astype(np.float32) - #if not [1000,32] expend to [1000.32] - expend_num = 1000 - int(video_feature.shape[0]) - if expend_num != 0: - video_expend = torch.zeros(expend_num,32) - video_feature = torch.cat((video_feature,video_expend),0) - video_feature = np.array(video_feature).astype(np.float32) - video_feature.tofile(os.path.join(pem_feature_path, video_name + ".bin")) - - video_xmin = np.array(video_xmin) - video_xmax = np.array(video_xmax) - video_xmin_score = np.array(video_xmin_score) - video_xmax_score = np.array(video_xmax_score) - - video_xmin.tofile(os.path.join(pem_xmin_path, video_name + ".bin")) - video_xmax.tofile(os.path.join(pem_xmax_path, video_name + ".bin")) - video_xmin_score.tofile(os.path.join(pem_xmin_score_path, video_name + ".bin")) - video_xmax_score.tofile(os.path.join(pem_xmax_score_path, video_name + ".bin")) - - - - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 numpy as np +import pandas as pd +import pandas +import numpy +import json +import torch.utils.data as data +import os +import torch +import os +#import opts +import sys + +#opt = opts.parse_opt() +#opt = vars(opt) +def load_json(file): + with open(file) as json_file: + data = json.load(json_file) + return data + +if __name__ == '__main__': + if not os.path.exists("output/BSN-PEM-preprocess/feature"): + os.makedirs("output/BSN-PEM-preprocess/feature") + if not os.path.exists("output/BSN-PEM-preprocess/xmin"): + os.makedirs("output/BSN-PEM-preprocess/xmin") + if not os.path.exists("output/BSN-PEM-preprocess/xmax"): + os.makedirs("output/BSN-PEM-preprocess/xmax") + if not os.path.exists("output/BSN-PEM-preprocess/xmin_score"): + os.makedirs("output/BSN-PEM-preprocess/xmin_score") + if not os.path.exists("output/BSN-PEM-preprocess/xmax_score"): + os.makedirs("output/BSN-PEM-preprocess/xmax_score") + subset = "validation" + top_K = 1000 + video_info_path = "BSN-boundary-sensitive-network.pytorch/data/activitynet_annotations/video_info_new.csv" + video_anno_path = "BSN-boundary-sensitive-network.pytorch/data/activitynet_annotations/anet_anno_action.json" + #video_info_path = opt["video_info"] + #video_anno_path = opt["video_anno"] + pgm_proposals_path = "output/PGM_proposals/" + pgm_feature_path = "output/PGM_feature/" + pem_feature_path ="output/BSN-PEM-preprocess/feature" + pem_xmin_path ="output/BSN-PEM-preprocess/xmin" + pem_xmax_path ="output/BSN-PEM-preprocess/xmax" + pem_xmin_score_path ="output/BSN-PEM-preprocess/xmin_score" + pem_xmax_score_path ="output/BSN-PEM-preprocess/xmax_score" + anno_df = pd.read_csv(video_info_path) + anno_database= load_json(video_anno_path) + video_dict = {} + for i in range(len(anno_df)): + video_name=anno_df.video.values[i] + video_info=anno_database[video_name] + video_subset=anno_df.subset.values[i] + #if subset == "full": + # video_dict[video_name] = video_info + if subset in video_subset: + video_dict[video_name] = video_info + video_list = list(video_dict.keys()) + print("%s subset video numbers: %d" %(subset,len(video_list))) + + print("processing...") + for i in range(len(video_list)): + video_name = video_list[i] + pdf=pandas.read_csv(pgm_proposals_path+video_name+".csv") + pdf=pdf[:top_K] + video_feature = numpy.load(pgm_feature_path + video_name+".npy") + video_feature = video_feature[:top_K,:] + video_feature = torch.Tensor(video_feature) + video_xmin =pdf.xmin.values[:] + video_xmax =pdf.xmax.values[:] + video_xmin_score = pdf.xmin_score.values[:] + video_xmax_score = pdf.xmax_score.values[:] + + #video_feature = np.array(video_feature).astype(np.float32) + #if not [1000,32] expend to [1000.32] + expend_num = 1000 - int(video_feature.shape[0]) + if expend_num != 0: + video_expend = torch.zeros(expend_num,32) + video_feature = torch.cat((video_feature,video_expend),0) + video_feature = np.array(video_feature).astype(np.float32) + video_feature.tofile(os.path.join(pem_feature_path, video_name + ".bin")) + + video_xmin = np.array(video_xmin) + video_xmax = np.array(video_xmax) + video_xmin_score = np.array(video_xmin_score) + video_xmax_score = np.array(video_xmax_score) + + video_xmin.tofile(os.path.join(pem_xmin_path, video_name + ".bin")) + video_xmax.tofile(os.path.join(pem_xmax_path, video_name + ".bin")) + video_xmin_score.tofile(os.path.join(pem_xmin_score_path, video_name + ".bin")) + video_xmax_score.tofile(os.path.join(pem_xmax_score_path, video_name + ".bin")) + + + + + diff --git a/ACL_PyTorch/contrib/cv/detection/BSN/BSN_pem_pth2onnx.py b/ACL_PyTorch/contrib/cv/detection/BSN/BSN_pem_pth2onnx.py index 3b9f6d6433..838b4c8868 100644 --- a/ACL_PyTorch/contrib/cv/detection/BSN/BSN_pem_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/detection/BSN/BSN_pem_pth2onnx.py @@ -1,66 +1,66 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import argparse -import sys -sys.path.append(r"./BSN-boundary-sensitive-network.pytorch") - -from models import PEM - -parser = argparse.ArgumentParser( - description='pem2onnx') -parser.add_argument('--pth_path', - default='./pem_best.pth.tar', - help='pth path') -parser.add_argument('--onnx_path', - default='./BSN_pem.onnx', - help='onnx path') -parser.add_argument( - '--pem_feat_dim', - type=int, - default=32) -parser.add_argument( - '--pem_hidden_dim', - type=int, - default=256) -parser.add_argument( - '--pem_batch_size', - type=int, - default=16) -parser.add_argument( - '--pem_u_ratio_m', - type=float, - default=1) -parser.add_argument( - '--pem_u_ratio_l', - type=float, - default=2) - - -def pem_onnx(opt): - opt = vars(opt) - pth_path = opt['pth_path'] - onnx_path = opt['onnx_path'] - model = PEM(opt) - checkpoint = torch.load(pth_path,map_location='cpu') - base_dict = {'.'.join(k.split('.')[1:]): v for k,v in list(checkpoint['state_dict'].items())} - model.load_state_dict(base_dict) - input_names=["video_feature"] - output_names = ["output"] - model.eval() - dummy_input = torch.randn(1,1000,32) - torch.onnx.export(model,dummy_input,onnx_path,input_names = input_names,output_names=output_names,verbose=True,opset_version=11) -if __name__ =="__main__": - opt = parser.parse_args() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import argparse +import sys +sys.path.append(r"./BSN-boundary-sensitive-network.pytorch") + +from models import PEM + +parser = argparse.ArgumentParser( + description='pem2onnx') +parser.add_argument('--pth_path', + default='./pem_best.pth.tar', + help='pth path') +parser.add_argument('--onnx_path', + default='./BSN_pem.onnx', + help='onnx path') +parser.add_argument( + '--pem_feat_dim', + type=int, + default=32) +parser.add_argument( + '--pem_hidden_dim', + type=int, + default=256) +parser.add_argument( + '--pem_batch_size', + type=int, + default=16) +parser.add_argument( + '--pem_u_ratio_m', + type=float, + default=1) +parser.add_argument( + '--pem_u_ratio_l', + type=float, + default=2) + + +def pem_onnx(opt): + opt = vars(opt) + pth_path = opt['pth_path'] + onnx_path = opt['onnx_path'] + model = PEM(opt) + checkpoint = torch.load(pth_path,map_location='cpu') + base_dict = {'.'.join(k.split('.')[1:]): v for k,v in list(checkpoint['state_dict'].items())} + model.load_state_dict(base_dict) + input_names=["video_feature"] + output_names = ["output"] + model.eval() + dummy_input = torch.randn(1,1000,32) + torch.onnx.export(model,dummy_input,onnx_path,input_names = input_names,output_names=output_names,verbose=True,opset_version=11) +if __name__ =="__main__": + opt = parser.parse_args() pem_onnx(opt) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/BSN/BSN_tem_postprocess.py b/ACL_PyTorch/contrib/cv/detection/BSN/BSN_tem_postprocess.py index 0c4eb2b177..de6f33cc8f 100644 --- a/ACL_PyTorch/contrib/cv/detection/BSN/BSN_tem_postprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/BSN/BSN_tem_postprocess.py @@ -1,313 +1,313 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 json -import torch -import hydra -import argparse -import os -import numpy as np -import pandas as pd -import numpy -import pandas -import torch.multiprocessing as mp -from scipy.interpolate import interp1d - - -parser = argparse.ArgumentParser(description='BSN') - -parser.add_argument('--result_path',default='./output/TEM_results', type=str, help='Dir to save txt results') -parser.add_argument('--TEM_out_path', default='./result/dumpOutput_device0', type=str, help='infer out path') -parser.add_argument('--TEM_anchor_xmin_path', default='./output/BSN-TEM-preprocess/anchor_min', type=str, help='infer info path') -parser.add_argument('--TEM_anchor_xmax_path', default='./output/BSN-TEM-preprocess/anchor_max', type=str, help='infer info path') - -args = parser.parse_args() - -columns=["action","start","end","xmin","xmax"] - -def load_json(file): - with open(file) as json_file: - data = json.load(json_file) - return data - -def iou_with_anchors(anchors_min,anchors_max,box_min,box_max): - """Compute jaccard score between a box and the anchors. - """ - len_anchors=anchors_max-anchors_min - int_xmin = numpy.maximum(anchors_min, box_min) - int_xmax = numpy.minimum(anchors_max, box_max) - inter_len = numpy.maximum(int_xmax - int_xmin, 0.) - union_len = len_anchors - inter_len +box_max-box_min - jaccard = numpy.divide(inter_len, union_len) - return jaccard - -def ioa_with_anchors(anchors_min,anchors_max,box_min,box_max): - """Compute intersection between score a box and the anchors. - """ - len_anchors=anchors_max-anchors_min - int_xmin = numpy.maximum(anchors_min, box_min) - int_xmax = numpy.minimum(anchors_max, box_max) - inter_len = numpy.maximum(int_xmax - int_xmin, 0.) - scores = numpy.divide(inter_len, len_anchors) - return scores - -def generateProposals(video_list,video_dict): - tscale = 100 - tgap = 1./tscale - peak_thres= 0.5 - - for video_name in video_list: - tdf=pandas.read_csv("./output/TEM_results/"+video_name+".csv") - start_scores=tdf.start.values[:] - end_scores=tdf.end.values[:] - - max_start = max(start_scores) - max_end = max(end_scores) - - start_bins=numpy.zeros(len(start_scores)) - start_bins[[0,-1]]=1 - for idx in range(1,tscale-1): - if start_scores[idx]>start_scores[idx+1] and start_scores[idx]>start_scores[idx-1]: - start_bins[idx]=1 - elif start_scores[idx]>(peak_thres*max_start): - start_bins[idx]=1 - - end_bins=numpy.zeros(len(end_scores)) - end_bins[[0,-1]]=1 - for idx in range(1,tscale-1): - if end_scores[idx]>end_scores[idx+1] and end_scores[idx]>end_scores[idx-1]: - end_bins[idx]=1 - elif end_scores[idx]>(peak_thres*max_end): - end_bins[idx]=1 - - xmin_list=[] - xmin_score_list=[] - xmax_list=[] - xmax_score_list=[] - for j in range(tscale): - if start_bins[j]==1: - xmin_list.append(tgap/2+tgap*j) - xmin_score_list.append(start_scores[j]) - if end_bins[j]==1: - xmax_list.append(tgap/2+tgap*j) - xmax_score_list.append(end_scores[j]) - - new_props=[] - for ii in range(len(xmax_list)): - tmp_xmax=xmax_list[ii] - tmp_xmax_score=xmax_score_list[ii] - - for ij in range(len(xmin_list)): - tmp_xmin=xmin_list[ij] - tmp_xmin_score=xmin_score_list[ij] - if tmp_xmin>=tmp_xmax: - break - new_props.append([tmp_xmin,tmp_xmax,tmp_xmin_score,tmp_xmax_score]) - new_props=numpy.stack(new_props) - - col_name=["xmin","xmax","xmin_score","xmax_score"] - new_df=pandas.DataFrame(new_props,columns=col_name) - new_df["score"]=new_df.xmin_score*new_df.xmax_score - - new_df=new_df.sort_values(by="score",ascending=False) - - video_info=video_dict[video_name] - video_frame=video_info['duration_frame'] - video_second=video_info['duration_second'] - feature_frame=video_info['feature_frame'] - corrected_second=float(feature_frame)/video_frame*video_second - - try: - gt_xmins=[] - gt_xmaxs=[] - for idx in range(len(video_info["annotations"])): - gt_xmins.append(video_info["annotations"][idx]["segment"][0]/corrected_second) - gt_xmaxs.append(video_info["annotations"][idx]["segment"][1]/corrected_second) - new_iou_list=[] - for j in range(len(new_df)): - tmp_new_iou=max(iou_with_anchors(new_df.xmin.values[j],new_df.xmax.values[j],gt_xmins,gt_xmaxs)) - new_iou_list.append(tmp_new_iou) - - new_ioa_list=[] - for j in range(len(new_df)): - tmp_new_ioa=max(ioa_with_anchors(new_df.xmin.values[j],new_df.xmax.values[j],gt_xmins,gt_xmaxs)) - new_ioa_list.append(tmp_new_ioa) - new_df["match_iou"]=new_iou_list - new_df["match_ioa"]=new_ioa_list - except: - pass - new_df.to_csv("./output/PGM_proposals/"+video_name+".csv",index=False) - - -def getDatasetDict(): - df=pandas.read_csv("./BSN-boundary-sensitive-network.pytorch/data/activitynet_annotations/video_info_new.csv") - json_data= load_json("./BSN-boundary-sensitive-network.pytorch/data/activitynet_annotations/anet_anno_action.json") - database=json_data - video_dict = {} - for i in range(len(df)): - video_name=df.video.values[i] - video_info=database[video_name] - video_new_info={} - video_new_info['duration_frame']=video_info['duration_frame'] - video_new_info['duration_second']=video_info['duration_second'] - video_new_info["feature_frame"]=video_info['feature_frame'] - video_new_info['annotations']=video_info['annotations'] - video_new_info['subset'] = df.subset.values[i] - video_dict[video_name]=video_new_info - return video_dict - -def generateFeature(video_list,video_dict): - - num_sample_start=8 - num_sample_end=8 - num_sample_action=16 - num_sample_interpld = 3 - - for video_name in video_list: - adf=pandas.read_csv("./output/TEM_results/"+video_name+".csv") - score_action=adf.action.values[:] - seg_xmins = adf.xmin.values[:] - seg_xmaxs = adf.xmax.values[:] - video_scale = len(adf) - video_gap = seg_xmaxs[0] - seg_xmins[0] - video_extend = video_scale / 4 + 10 - pdf=pandas.read_csv("./output/PGM_proposals/"+video_name+".csv") - video_subset = video_dict[video_name]['subset'] - if video_subset == "training": - pdf=pdf[:500] - else: - pdf=pdf[:1000] - tmp_zeros=numpy.zeros([int(video_extend)]) - score_action=numpy.concatenate((tmp_zeros,score_action,tmp_zeros)) - tmp_cell = video_gap - #print('video_extend:{}'.format(video_extend)) - tmp_x = [-tmp_cell/2-(video_extend-1-ii)*tmp_cell for ii in range(int(video_extend))] + \ - [tmp_cell/2+ii*tmp_cell for ii in range(int(video_scale))] + \ - [tmp_cell/2+seg_xmaxs[-1] +ii*tmp_cell for ii in range(int(video_extend))] - f_action=interp1d(tmp_x,score_action,axis=0) - feature_bsp=[] - - for idx in range(len(pdf)): - xmin=pdf.xmin.values[idx] - xmax=pdf.xmax.values[idx] - xlen=xmax-xmin - xmin_0=xmin-xlen * 0.2 - xmin_1=xmin+xlen * 0.2 - xmax_0=xmax-xlen * 0.2 - xmax_1=xmax+xlen * 0.2 - #start - plen_start= (xmin_1-xmin_0)/(num_sample_start-1) - plen_sample = plen_start / num_sample_interpld - tmp_x_new = [ xmin_0 - plen_start/2 + plen_sample * ii for ii in range(num_sample_start*num_sample_interpld +1 )] - tmp_y_new_start_action=f_action(tmp_x_new) - tmp_y_new_start = [numpy.mean(tmp_y_new_start_action[ii*num_sample_interpld:(ii+1)*num_sample_interpld+1]) for ii in range(num_sample_start) ] - #end - plen_end= (xmax_1-xmax_0)/(num_sample_end-1) - plen_sample = plen_end / num_sample_interpld - tmp_x_new = [ xmax_0 - plen_end/2 + plen_sample * ii for ii in range(num_sample_end*num_sample_interpld +1 )] - tmp_y_new_end_action=f_action(tmp_x_new) - tmp_y_new_end = [numpy.mean(tmp_y_new_end_action[ii*num_sample_interpld:(ii+1)*num_sample_interpld+1]) for ii in range(num_sample_end) ] - #action - plen_action= (xmax-xmin)/(num_sample_action-1) - plen_sample = plen_action / num_sample_interpld - tmp_x_new = [ xmin - plen_action/2 + plen_sample * ii for ii in range(num_sample_action*num_sample_interpld +1 )] - tmp_y_new_action=f_action(tmp_x_new) - tmp_y_new_action = [numpy.mean(tmp_y_new_action[ii*num_sample_interpld:(ii+1)*num_sample_interpld+1]) for ii in range(num_sample_action) ] - tmp_feature = numpy.concatenate([tmp_y_new_action,tmp_y_new_start,tmp_y_new_end]) - feature_bsp.append(tmp_feature) - feature_bsp = numpy.array(feature_bsp) - numpy.save("./output/PGM_feature/"+video_name,feature_bsp) - - - -def PGM_proposal_generation(): - video_dict= load_json("./BSN-boundary-sensitive-network.pytorch/data/activitynet_annotations/anet_anno_action.json") - video_list=video_dict.keys()#[:199] - video_list = list(video_list) - num_videos = len(video_list) - num_videos_per_thread = num_videos/8 - processes = [] - for tid in range(7): - tmp_video_list = video_list[int(tid*num_videos_per_thread):int((tid+1)*num_videos_per_thread)] - p = mp.Process(target = generateProposals,args =(tmp_video_list,video_dict,)) - p.start() - processes.append(p) - - tmp_video_list = video_list[int(7*num_videos_per_thread):] - p = mp.Process(target = generateProposals,args =(tmp_video_list,video_dict,)) - p.start() - processes.append(p) - - for p in processes: - p.join() -def PGM_feature_generation(): - video_dict=getDatasetDict() - video_list=video_dict.keys() - video_list = list(video_list) - num_videos = len(video_list) - num_videos_per_thread = num_videos/8 - processes = [] - for tid in range(7): - tmp_video_list = video_list[int(tid*num_videos_per_thread):int((tid+1)*num_videos_per_thread)] - p = mp.Process(target = generateFeature,args =(tmp_video_list,video_dict,)) - p.start() - processes.append(p) - - tmp_video_list = video_list[int(7*num_videos_per_thread):] - p = mp.Process(target = generateFeature,args =(tmp_video_list,video_dict,)) - p.start() - processes.append(p) - - for p in processes: - p.join() - -if __name__ == '__main__': - out_files = os.listdir(args.TEM_out_path) - if not os.path.exists("output/TEM_results"): - os.makedirs("output/TEM_results") - print("processing...") - for i in range(len(out_files)): - video_name = str(out_files[i]) - video_name = video_name[0:int(len(video_name)-6)] - video_data = np.fromfile(args.TEM_out_path+'/'+out_files[i],dtype=np.float32) - #print(video_data) - video_data = torch.tensor(video_data.reshape(1,3,100)) - #video_data.reshape(1,3,1000) - video_data = video_data.detach().cpu().numpy() - - anchor_xmin = np.fromfile(args.TEM_anchor_xmin_path+'/'+video_name+'.bin',dtype=np.float64) - anchor_xmax = np.fromfile(args.TEM_anchor_xmax_path+'/'+video_name+'.bin',dtype=np.float64) - - anchor_xmin = torch.tensor(anchor_xmin) - anchor_xmax = torch.tensor(anchor_xmax) - video_action = video_data[:,0,:] - video_start = video_data[:,1,:] - video_end = video_data[:,2,:] - - video_result = np.stack((video_action[0],video_start[0],video_end[0],anchor_xmin,anchor_xmax),axis=1) - - video_df = pd.DataFrame(video_result,columns=columns) - video_df.to_csv(args.result_path+"/"+video_name+".csv",index=False) - - if not os.path.exists("output/PGM_proposals"): - os.makedirs("output/PGM_proposals") - print("PGM: start generating proposals") - PGM_proposal_generation() - print("PGM: finish generate proposals") - - if not os.path.exists("output/PGM_feature"): - os.makedirs("output/PGM_feature") - print("PGM: start generating BSP feature") - PGM_feature_generation() - print("PGM: finish generate BSP feature") +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 json +import torch +import hydra +import argparse +import os +import numpy as np +import pandas as pd +import numpy +import pandas +import torch.multiprocessing as mp +from scipy.interpolate import interp1d + + +parser = argparse.ArgumentParser(description='BSN') + +parser.add_argument('--result_path',default='./output/TEM_results', type=str, help='Dir to save txt results') +parser.add_argument('--TEM_out_path', default='./result/dumpOutput_device0', type=str, help='infer out path') +parser.add_argument('--TEM_anchor_xmin_path', default='./output/BSN-TEM-preprocess/anchor_min', type=str, help='infer info path') +parser.add_argument('--TEM_anchor_xmax_path', default='./output/BSN-TEM-preprocess/anchor_max', type=str, help='infer info path') + +args = parser.parse_args() + +columns=["action","start","end","xmin","xmax"] + +def load_json(file): + with open(file) as json_file: + data = json.load(json_file) + return data + +def iou_with_anchors(anchors_min,anchors_max,box_min,box_max): + """Compute jaccard score between a box and the anchors. + """ + len_anchors=anchors_max-anchors_min + int_xmin = numpy.maximum(anchors_min, box_min) + int_xmax = numpy.minimum(anchors_max, box_max) + inter_len = numpy.maximum(int_xmax - int_xmin, 0.) + union_len = len_anchors - inter_len +box_max-box_min + jaccard = numpy.divide(inter_len, union_len) + return jaccard + +def ioa_with_anchors(anchors_min,anchors_max,box_min,box_max): + """Compute intersection between score a box and the anchors. + """ + len_anchors=anchors_max-anchors_min + int_xmin = numpy.maximum(anchors_min, box_min) + int_xmax = numpy.minimum(anchors_max, box_max) + inter_len = numpy.maximum(int_xmax - int_xmin, 0.) + scores = numpy.divide(inter_len, len_anchors) + return scores + +def generateProposals(video_list,video_dict): + tscale = 100 + tgap = 1./tscale + peak_thres= 0.5 + + for video_name in video_list: + tdf=pandas.read_csv("./output/TEM_results/"+video_name+".csv") + start_scores=tdf.start.values[:] + end_scores=tdf.end.values[:] + + max_start = max(start_scores) + max_end = max(end_scores) + + start_bins=numpy.zeros(len(start_scores)) + start_bins[[0,-1]]=1 + for idx in range(1,tscale-1): + if start_scores[idx]>start_scores[idx+1] and start_scores[idx]>start_scores[idx-1]: + start_bins[idx]=1 + elif start_scores[idx]>(peak_thres*max_start): + start_bins[idx]=1 + + end_bins=numpy.zeros(len(end_scores)) + end_bins[[0,-1]]=1 + for idx in range(1,tscale-1): + if end_scores[idx]>end_scores[idx+1] and end_scores[idx]>end_scores[idx-1]: + end_bins[idx]=1 + elif end_scores[idx]>(peak_thres*max_end): + end_bins[idx]=1 + + xmin_list=[] + xmin_score_list=[] + xmax_list=[] + xmax_score_list=[] + for j in range(tscale): + if start_bins[j]==1: + xmin_list.append(tgap/2+tgap*j) + xmin_score_list.append(start_scores[j]) + if end_bins[j]==1: + xmax_list.append(tgap/2+tgap*j) + xmax_score_list.append(end_scores[j]) + + new_props=[] + for ii in range(len(xmax_list)): + tmp_xmax=xmax_list[ii] + tmp_xmax_score=xmax_score_list[ii] + + for ij in range(len(xmin_list)): + tmp_xmin=xmin_list[ij] + tmp_xmin_score=xmin_score_list[ij] + if tmp_xmin>=tmp_xmax: + break + new_props.append([tmp_xmin,tmp_xmax,tmp_xmin_score,tmp_xmax_score]) + new_props=numpy.stack(new_props) + + col_name=["xmin","xmax","xmin_score","xmax_score"] + new_df=pandas.DataFrame(new_props,columns=col_name) + new_df["score"]=new_df.xmin_score*new_df.xmax_score + + new_df=new_df.sort_values(by="score",ascending=False) + + video_info=video_dict[video_name] + video_frame=video_info['duration_frame'] + video_second=video_info['duration_second'] + feature_frame=video_info['feature_frame'] + corrected_second=float(feature_frame)/video_frame*video_second + + try: + gt_xmins=[] + gt_xmaxs=[] + for idx in range(len(video_info["annotations"])): + gt_xmins.append(video_info["annotations"][idx]["segment"][0]/corrected_second) + gt_xmaxs.append(video_info["annotations"][idx]["segment"][1]/corrected_second) + new_iou_list=[] + for j in range(len(new_df)): + tmp_new_iou=max(iou_with_anchors(new_df.xmin.values[j],new_df.xmax.values[j],gt_xmins,gt_xmaxs)) + new_iou_list.append(tmp_new_iou) + + new_ioa_list=[] + for j in range(len(new_df)): + tmp_new_ioa=max(ioa_with_anchors(new_df.xmin.values[j],new_df.xmax.values[j],gt_xmins,gt_xmaxs)) + new_ioa_list.append(tmp_new_ioa) + new_df["match_iou"]=new_iou_list + new_df["match_ioa"]=new_ioa_list + except: + pass + new_df.to_csv("./output/PGM_proposals/"+video_name+".csv",index=False) + + +def getDatasetDict(): + df=pandas.read_csv("./BSN-boundary-sensitive-network.pytorch/data/activitynet_annotations/video_info_new.csv") + json_data= load_json("./BSN-boundary-sensitive-network.pytorch/data/activitynet_annotations/anet_anno_action.json") + database=json_data + video_dict = {} + for i in range(len(df)): + video_name=df.video.values[i] + video_info=database[video_name] + video_new_info={} + video_new_info['duration_frame']=video_info['duration_frame'] + video_new_info['duration_second']=video_info['duration_second'] + video_new_info["feature_frame"]=video_info['feature_frame'] + video_new_info['annotations']=video_info['annotations'] + video_new_info['subset'] = df.subset.values[i] + video_dict[video_name]=video_new_info + return video_dict + +def generateFeature(video_list,video_dict): + + num_sample_start=8 + num_sample_end=8 + num_sample_action=16 + num_sample_interpld = 3 + + for video_name in video_list: + adf=pandas.read_csv("./output/TEM_results/"+video_name+".csv") + score_action=adf.action.values[:] + seg_xmins = adf.xmin.values[:] + seg_xmaxs = adf.xmax.values[:] + video_scale = len(adf) + video_gap = seg_xmaxs[0] - seg_xmins[0] + video_extend = video_scale / 4 + 10 + pdf=pandas.read_csv("./output/PGM_proposals/"+video_name+".csv") + video_subset = video_dict[video_name]['subset'] + if video_subset == "training": + pdf=pdf[:500] + else: + pdf=pdf[:1000] + tmp_zeros=numpy.zeros([int(video_extend)]) + score_action=numpy.concatenate((tmp_zeros,score_action,tmp_zeros)) + tmp_cell = video_gap + #print('video_extend:{}'.format(video_extend)) + tmp_x = [-tmp_cell/2-(video_extend-1-ii)*tmp_cell for ii in range(int(video_extend))] + \ + [tmp_cell/2+ii*tmp_cell for ii in range(int(video_scale))] + \ + [tmp_cell/2+seg_xmaxs[-1] +ii*tmp_cell for ii in range(int(video_extend))] + f_action=interp1d(tmp_x,score_action,axis=0) + feature_bsp=[] + + for idx in range(len(pdf)): + xmin=pdf.xmin.values[idx] + xmax=pdf.xmax.values[idx] + xlen=xmax-xmin + xmin_0=xmin-xlen * 0.2 + xmin_1=xmin+xlen * 0.2 + xmax_0=xmax-xlen * 0.2 + xmax_1=xmax+xlen * 0.2 + #start + plen_start= (xmin_1-xmin_0)/(num_sample_start-1) + plen_sample = plen_start / num_sample_interpld + tmp_x_new = [ xmin_0 - plen_start/2 + plen_sample * ii for ii in range(num_sample_start*num_sample_interpld +1 )] + tmp_y_new_start_action=f_action(tmp_x_new) + tmp_y_new_start = [numpy.mean(tmp_y_new_start_action[ii*num_sample_interpld:(ii+1)*num_sample_interpld+1]) for ii in range(num_sample_start) ] + #end + plen_end= (xmax_1-xmax_0)/(num_sample_end-1) + plen_sample = plen_end / num_sample_interpld + tmp_x_new = [ xmax_0 - plen_end/2 + plen_sample * ii for ii in range(num_sample_end*num_sample_interpld +1 )] + tmp_y_new_end_action=f_action(tmp_x_new) + tmp_y_new_end = [numpy.mean(tmp_y_new_end_action[ii*num_sample_interpld:(ii+1)*num_sample_interpld+1]) for ii in range(num_sample_end) ] + #action + plen_action= (xmax-xmin)/(num_sample_action-1) + plen_sample = plen_action / num_sample_interpld + tmp_x_new = [ xmin - plen_action/2 + plen_sample * ii for ii in range(num_sample_action*num_sample_interpld +1 )] + tmp_y_new_action=f_action(tmp_x_new) + tmp_y_new_action = [numpy.mean(tmp_y_new_action[ii*num_sample_interpld:(ii+1)*num_sample_interpld+1]) for ii in range(num_sample_action) ] + tmp_feature = numpy.concatenate([tmp_y_new_action,tmp_y_new_start,tmp_y_new_end]) + feature_bsp.append(tmp_feature) + feature_bsp = numpy.array(feature_bsp) + numpy.save("./output/PGM_feature/"+video_name,feature_bsp) + + + +def PGM_proposal_generation(): + video_dict= load_json("./BSN-boundary-sensitive-network.pytorch/data/activitynet_annotations/anet_anno_action.json") + video_list=video_dict.keys()#[:199] + video_list = list(video_list) + num_videos = len(video_list) + num_videos_per_thread = num_videos/8 + processes = [] + for tid in range(7): + tmp_video_list = video_list[int(tid*num_videos_per_thread):int((tid+1)*num_videos_per_thread)] + p = mp.Process(target = generateProposals,args =(tmp_video_list,video_dict,)) + p.start() + processes.append(p) + + tmp_video_list = video_list[int(7*num_videos_per_thread):] + p = mp.Process(target = generateProposals,args =(tmp_video_list,video_dict,)) + p.start() + processes.append(p) + + for p in processes: + p.join() +def PGM_feature_generation(): + video_dict=getDatasetDict() + video_list=video_dict.keys() + video_list = list(video_list) + num_videos = len(video_list) + num_videos_per_thread = num_videos/8 + processes = [] + for tid in range(7): + tmp_video_list = video_list[int(tid*num_videos_per_thread):int((tid+1)*num_videos_per_thread)] + p = mp.Process(target = generateFeature,args =(tmp_video_list,video_dict,)) + p.start() + processes.append(p) + + tmp_video_list = video_list[int(7*num_videos_per_thread):] + p = mp.Process(target = generateFeature,args =(tmp_video_list,video_dict,)) + p.start() + processes.append(p) + + for p in processes: + p.join() + +if __name__ == '__main__': + out_files = os.listdir(args.TEM_out_path) + if not os.path.exists("output/TEM_results"): + os.makedirs("output/TEM_results") + print("processing...") + for i in range(len(out_files)): + video_name = str(out_files[i]) + video_name = video_name[0:int(len(video_name)-6)] + video_data = np.fromfile(args.TEM_out_path+'/'+out_files[i],dtype=np.float32) + #print(video_data) + video_data = torch.tensor(video_data.reshape(1,3,100)) + #video_data.reshape(1,3,1000) + video_data = video_data.detach().cpu().numpy() + + anchor_xmin = np.fromfile(args.TEM_anchor_xmin_path+'/'+video_name+'.bin',dtype=np.float64) + anchor_xmax = np.fromfile(args.TEM_anchor_xmax_path+'/'+video_name+'.bin',dtype=np.float64) + + anchor_xmin = torch.tensor(anchor_xmin) + anchor_xmax = torch.tensor(anchor_xmax) + video_action = video_data[:,0,:] + video_start = video_data[:,1,:] + video_end = video_data[:,2,:] + + video_result = np.stack((video_action[0],video_start[0],video_end[0],anchor_xmin,anchor_xmax),axis=1) + + video_df = pd.DataFrame(video_result,columns=columns) + video_df.to_csv(args.result_path+"/"+video_name+".csv",index=False) + + if not os.path.exists("output/PGM_proposals"): + os.makedirs("output/PGM_proposals") + print("PGM: start generating proposals") + PGM_proposal_generation() + print("PGM: finish generate proposals") + + if not os.path.exists("output/PGM_feature"): + os.makedirs("output/PGM_feature") + print("PGM: start generating BSP feature") + PGM_feature_generation() + print("PGM: finish generate BSP feature") \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/BSN/BSN_tem_preprocess.py b/ACL_PyTorch/contrib/cv/detection/BSN/BSN_tem_preprocess.py index b6639216bf..328411466d 100644 --- a/ACL_PyTorch/contrib/cv/detection/BSN/BSN_tem_preprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/BSN/BSN_tem_preprocess.py @@ -1,75 +1,75 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 numpy as np -import pandas as pd -import pandas -import numpy -import json -import torch.utils.data as data -import os -import torch -import sys - -def load_json(file): - with open(file) as json_file: - data = json.load(json_file) - return data -if __name__ == '__main__': - if not os.path.exists("output/BSN-TEM-preprocess/anchor_min"): - os.makedirs("output/BSN-TEM-preprocess/anchor_min") - if not os.path.exists("output/BSN-TEM-preprocess/anchor_max"): - os.makedirs("output/BSN-TEM-preprocess/anchor_max") - if not os.path.exists("output/BSN-TEM-preprocess/feature"): - os.makedirs("output/BSN-TEM-preprocess/feature") - feature_path = "BSN-boundary-sensitive-network.pytorch/data/activitynet_feature_cuhk/" - video_info_path = "BSN-boundary-sensitive-network.pytorch/data/activitynet_annotations/video_info_new.csv" - video_anno_path = "BSN-boundary-sensitive-network.pytorch/data/activitynet_annotations/anet_anno_action.json" - temporal_scale = 100 - temporal_gap = 1. / temporal_scale - subset = "full" - boundary_ratio = 0.1 - anno_df = pd.read_csv(video_info_path) - anno_database= load_json(video_anno_path) - video_dict = {} - for i in range(len(anno_df)): - video_name=anno_df.video.values[i] - video_info=anno_database[video_name] - video_subset=anno_df.subset.values[i] - if subset == "full": - video_dict[video_name] = video_info - if subset in video_subset: - video_dict[video_name] = video_info - video_list = list(video_dict.keys()) - print("%s subset video numbers: %d" %(subset,len(video_list))) - - print("processing...") - for i in range(len(video_list)): - video_name=video_list[i] - anchor_xmin=[temporal_gap*i for i in range(temporal_scale)] - anchor_xmax=[temporal_gap*i for i in range(1,temporal_scale+1)] - video_df=pd.read_csv(feature_path+ "csv_mean_"+str(temporal_scale)+"/"+video_name+".csv") - video_data = video_df.values[:,:] - video_data = torch.Tensor(video_data) - video_data = torch.transpose(video_data,0,1) - video_data.float() - video_data = np.array(video_data).astype(np.float32) - video_data.tofile(os.path.join('./output/BSN-TEM-preprocess/feature/', video_name + ".bin")) - - anchor_xmin = np.array(anchor_xmin) - anchor_xmax = np.array(anchor_xmax) - anchor_xmin.tofile(os.path.join('./output/BSN-TEM-preprocess/anchor_min/', video_name + ".bin")) - anchor_xmax.tofile(os.path.join('./output/BSN-TEM-preprocess/anchor_max/', video_name + ".bin")) - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 numpy as np +import pandas as pd +import pandas +import numpy +import json +import torch.utils.data as data +import os +import torch +import sys + +def load_json(file): + with open(file) as json_file: + data = json.load(json_file) + return data +if __name__ == '__main__': + if not os.path.exists("output/BSN-TEM-preprocess/anchor_min"): + os.makedirs("output/BSN-TEM-preprocess/anchor_min") + if not os.path.exists("output/BSN-TEM-preprocess/anchor_max"): + os.makedirs("output/BSN-TEM-preprocess/anchor_max") + if not os.path.exists("output/BSN-TEM-preprocess/feature"): + os.makedirs("output/BSN-TEM-preprocess/feature") + feature_path = "BSN-boundary-sensitive-network.pytorch/data/activitynet_feature_cuhk/" + video_info_path = "BSN-boundary-sensitive-network.pytorch/data/activitynet_annotations/video_info_new.csv" + video_anno_path = "BSN-boundary-sensitive-network.pytorch/data/activitynet_annotations/anet_anno_action.json" + temporal_scale = 100 + temporal_gap = 1. / temporal_scale + subset = "full" + boundary_ratio = 0.1 + anno_df = pd.read_csv(video_info_path) + anno_database= load_json(video_anno_path) + video_dict = {} + for i in range(len(anno_df)): + video_name=anno_df.video.values[i] + video_info=anno_database[video_name] + video_subset=anno_df.subset.values[i] + if subset == "full": + video_dict[video_name] = video_info + if subset in video_subset: + video_dict[video_name] = video_info + video_list = list(video_dict.keys()) + print("%s subset video numbers: %d" %(subset,len(video_list))) + + print("processing...") + for i in range(len(video_list)): + video_name=video_list[i] + anchor_xmin=[temporal_gap*i for i in range(temporal_scale)] + anchor_xmax=[temporal_gap*i for i in range(1,temporal_scale+1)] + video_df=pd.read_csv(feature_path+ "csv_mean_"+str(temporal_scale)+"/"+video_name+".csv") + video_data = video_df.values[:,:] + video_data = torch.Tensor(video_data) + video_data = torch.transpose(video_data,0,1) + video_data.float() + video_data = np.array(video_data).astype(np.float32) + video_data.tofile(os.path.join('./output/BSN-TEM-preprocess/feature/', video_name + ".bin")) + + anchor_xmin = np.array(anchor_xmin) + anchor_xmax = np.array(anchor_xmax) + anchor_xmin.tofile(os.path.join('./output/BSN-TEM-preprocess/anchor_min/', video_name + ".bin")) + anchor_xmax.tofile(os.path.join('./output/BSN-TEM-preprocess/anchor_max/', video_name + ".bin")) + + \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/BSN/BSN_tem_pth2onnx.py b/ACL_PyTorch/contrib/cv/detection/BSN/BSN_tem_pth2onnx.py index fbb5247a8a..3b9bd12c35 100644 --- a/ACL_PyTorch/contrib/cv/detection/BSN/BSN_tem_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/detection/BSN/BSN_tem_pth2onnx.py @@ -1,64 +1,64 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import torch -import sys -sys.path.append(r"./BSN-boundary-sensitive-network.pytorch") - -from models import TEM - -parser = argparse.ArgumentParser( - description='tem2onnx') -parser.add_argument('--pth_path', - default='./tem_best.pth.tar', - help='pth path') -parser.add_argument('--onnx_path', - default='./BSN_tem.onnx', - help='onnx path') -parser.add_argument( - '--tem_feat_dim', - type=int, - default=400) -parser.add_argument( - '--tem_hidden_dim', - type=int, - default=512) -parser.add_argument( - '--tem_batch_size', - type=int, - default=16) -parser.add_argument( - '--temporal_scale', - type=int, - default=100) -opt = parser.parse_args() - -def pth_onnx(opt): - - - opt = vars(opt) - pth_path = opt['pth_path'] - onnx_path = opt['onnx_path'] - model = TEM(opt) - checkpoint = torch.load(pth_path,map_location='cpu') - base_dict = {'.'.join(k.split('.')[1:]): v for k,v in list(checkpoint['state_dict'].items())} - model.load_state_dict(base_dict) - input_names=["video"] - output_names = ["output"] - model.eval() - dummy_input = torch.randn(1,400,100) - torch.onnx.export(model,dummy_input,onnx_path,input_names = input_names,output_names=output_names,verbose=True,opset_version=11) -if __name__ =="__main__": - opt = parser.parse_args() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import torch +import sys +sys.path.append(r"./BSN-boundary-sensitive-network.pytorch") + +from models import TEM + +parser = argparse.ArgumentParser( + description='tem2onnx') +parser.add_argument('--pth_path', + default='./tem_best.pth.tar', + help='pth path') +parser.add_argument('--onnx_path', + default='./BSN_tem.onnx', + help='onnx path') +parser.add_argument( + '--tem_feat_dim', + type=int, + default=400) +parser.add_argument( + '--tem_hidden_dim', + type=int, + default=512) +parser.add_argument( + '--tem_batch_size', + type=int, + default=16) +parser.add_argument( + '--temporal_scale', + type=int, + default=100) +opt = parser.parse_args() + +def pth_onnx(opt): + + + opt = vars(opt) + pth_path = opt['pth_path'] + onnx_path = opt['onnx_path'] + model = TEM(opt) + checkpoint = torch.load(pth_path,map_location='cpu') + base_dict = {'.'.join(k.split('.')[1:]): v for k,v in list(checkpoint['state_dict'].items())} + model.load_state_dict(base_dict) + input_names=["video"] + output_names = ["output"] + model.eval() + dummy_input = torch.randn(1,400,100) + torch.onnx.export(model,dummy_input,onnx_path,input_names = input_names,output_names=output_names,verbose=True,opset_version=11) +if __name__ =="__main__": + opt = parser.parse_args() pth_onnx(opt) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/BSN/README.md b/ACL_PyTorch/contrib/cv/detection/BSN/README.md index 66ee1c7705..7892ad2b7e 100644 --- a/ACL_PyTorch/contrib/cv/detection/BSN/README.md +++ b/ACL_PyTorch/contrib/cv/detection/BSN/README.md @@ -1,450 +1,450 @@ -# BSN推理说明 - - - -## 1、 环境说明 - -1、安装必要的依赖 - -``` -apex 0.1+ascend.20210930 -certifi 2021.10.8 -cycler 0.11.0 -decorator 5.1.0 -docutils 0.18 -flatbuffers 2.0 -future 0.18.2 -Geohash 1.0 -Hydra 2.5 -kiwisolver 1.3.2 -matplotlib 3.4.3 -mpmath 1.2.1 -numpy 1.21.0 -onnx 1.10.2 -onnxruntime 1.9.0 -pandas 1.3.4 -Pillow 8.4.0 -pip 21.3.1 -protobuf 3.19.1 -pyparsing 3.0.6 -python-dateutil 2.8.2 -pytz 2021.3 -scipy 1.7.2 -setuptools 58.0.4 -six 1.16.0 -sympy 1.9 -torch 1.5.0+ascend.post3.20210930 -typing-extensions 3.10.0.2 -wheel 0.37.0 -``` - -2、获取开源代码 - -直接从githup上git clone 可能无法clone成功,建议先把githup上的仓先导入到git,再clone - -``` -git clone https://github.com/wzmsltw/BSN-boundary-sensitive-network.pytorch -``` - - - -3、获取onnx_tools,优化TEM的onnx模型 - -``` -git clone https://gitee.com/zheng-wengang1/onnx_tools -``` - - - -4、下载视频特征数据集 - -请参考源代码仓 - -5、代码目录 - -``` -BSN #模型名称命名的文件夹 -├── BSN-boundary-sensitive-network.pytorch #BSN开源代码 - └── data - ├── activitynet_feature_cuhk - ├── csv_mean_100 #下载数据特征集 -├── env.sh #环境变量 -├── BSN_tem_pth2onnx.py #tem模型转换脚本 -├── BSN_pem_pth2onnx.py #pem模型转换脚本 -├── BSN_tem_preprocess.py #tem模型前处理脚本 -├── BSN_pem_preprocess.py #pem模型前处理脚本 -├── gen_dataset_info.py #生成数据集info文件 -├── BSN_tem_postprocess.py #tem模型后处理脚本 -├── BSN_pem_postprocess.py #pem模型后处理脚本 -├── BSN_eval.py #测试精度脚本 -├── TEM_onnx_conv1d2conv2d.py #tem模型onnx,conv1d算子转conv2d算子优化脚本 -├── requirements.txt #模型离线推理用到的所有且必要的依赖库 -├── README.md #模型离线推理说明README -├── modelzoo_level.txt #模型精度性能结果 -└── test - ├── pth2om.sh - ├── eval_acc_perf.sh - ├── parse.py -``` - - - -## 2、离线推理 - -1、pth权重转onnx - - - -TEM的pth权重转onnx,参数pth_path为TEM模型权重文件所在位置,onnx_path为输出的onnx模型位置 - -``` -python BSN_tem_pth2onnx.py --pth_path './tem_best.pth.tar' --onnx_path './BSN_tem.onnx' -``` - -tem-onnx模型优化,第一个参数为原本onnx模型位置,第二个参数为输出onnx模型 - -``` -python TEM_onnx_conv1d2conv2d.py './BSN_tem.onnx' './BSN_tem1.onnx' -``` - -PEM的pth权重转onnx,参数pth_path为PEM模型权重文件所在位置,onnx_path为输出的onnx模型位置 - -``` -python BSN_pem_pth2onnx.py --pth_path './pem_best.pth.tar' --onnx_path './BSN_pem.onnx' -``` - - - -2、onnx模型转om - -使用atc工具将onnx模型转为om模型,注意应当先设置环境变量 - -``` -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp -export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest - -atc --framework=5 --model=BSN_tem1.onnx --output=BSN_tem_bs1 --input_format=ND --input_shape="video:1,400,100" --log=debug --soc_version=Ascend310 - -atc --framework=5 --model=BSN_pem.onnx --output=BSN_pem_bs1 --input_format=ND --input_shape="video_feature:1,1000,32" --log=debug --soc_version=Ascend310 -``` - - - -3、TEM推理 - -运行预处理脚本,运行前确保你已经clone了开源代码,并下载数据特征集 - -``` -python BSN_tem_preprocess.py -``` - -获取处理数据集信息,第一个参数为模型类型,第二个参数为特征文件位置,第三个参数为输出文件名,第四、五个参数为特征形状(400*100) - -``` -python gen_dataset_info.py tem /home/wch/BSN/BSN-TEM-preprocess/feature TEM-video-feature 400 100 -``` - -使用benchmark工具进行推理,生成的数据文件会放在当前路径的result/dumpOutput_device0目录下 - -``` -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=BSN_tem_bs1.om -input_text_path=./TEM-video-feature.info -input_width=400 -input_height=100 -output_binary=True -useDvpp=False -``` - -使用BSN_tem_postprocess.py进行tem后处理(tem的后处理与pem的前处理有关请按照顺序执行) - -``` -python BSN_tem_postprocess.py --TEM_out_path ./result/dumpOutput_device0 -``` - - - -4、PEM推理 - -运行pem预处理脚本(pem的前处理与tem的后处理有关请按照顺序执行) - -``` -python BSN_pem_preprocess.py -``` - -获取处理数据集信息,第一个参数为模型类型,第二个参数为特征文件位置,第三个参数为输出文件名,第四、五个参数为特征形状(1000*32) - -``` -python get_info.py pem output/BSN-PEM-preprocess/feature PEM-video-feature 1000 32 -``` - -使用benchmark工具进行推理,生成的数据文件会放在当前路径的result/dumpOutput_device1目录下 - -``` -./benchmark.x86_64 -model_type=vision -device_id=1 -batch_size=1 -om_path=BSN_pem_bs1.om -input_text_path=./PEM-video-feature.info -input_width=1000 -input_height=32 -output_binary=True -useDvpp=False -``` - -运行后处理脚本,会在output目录下生成结果文件 - -``` -python BSN_pem_postprocess.py --PEM_out_path result/dumpOutput_device1 -``` - - - -5、精度测试 - -原本代码仓的代码是python2的代码,在在使用前需要转为python3 - -``` -2to3 -w ./BSN-boundary-sensitive-network.pytorch/Evaluation/eval_proposal.py - -``` - -精度测试 - -``` -python BSN_eval.py -``` - - - -6、整体测试 - -运行脚本,直接转om模型 - -``` -bash ./test/pth2om.sh -``` - -运行脚本,进行离线推理,运行脚本前,请确保已经将源代码中使用的文件,转为python3 - -``` -bash ./test/eval_acc_perf.sh -``` - - - -## 3 精度性能对比 - -### 1、精度对比 - -​ pth精度 - -``` -Model 论文 开源pth文件 离线推理精度 -BSN AR100:72.42 74.34 74.34 -``` - -### 2、性能对比 - -#### 2.1 npu性能数据 - -tem bs1性能数据 - -``` ------------------Performance Summary------------------ -[e2e] throughputRate: 180.879, latency: 106303 -[data read] throughputRate: 182.039, moduleLatency: 5.49332 -[preprocess] throughputRate: 181.865, moduleLatency: 5.49859 -[inference] throughputRate: 182, Interface throughputRate: 3275.55, moduleLatency: 0.561457 -[postprocess] throughputRate: 182.009, moduleLatency: 5.49425 - ------------------------------------------------------------ -``` - -pem bs1性能数据 - -``` ------------------Performance Summary------------------ -[e2e] throughputRate: 616.804, latency: 7665.32 -[data read] throughputRate: 1840.06, moduleLatency: 0.54346 -[preprocess] throughputRate: 1817.62, moduleLatency: 0.550169 -[inference] throughputRate: 1839.62, Interface throughputRate: 3874.46, moduleLatency: 0.469866 -[postprocess] throughputRate: 1839.86, moduleLatency: 0.543521 - ------------------------------------------------------------ -``` - -tem单卡吞吐率:3275.55x4=13102.2 - -pem单卡吞吐率:3874.46x4=15497.84 - -BSN整体吞吐率为:1/(1/13102.2+1/15497.84)=7099.87 - - - -tem bs16性能数据 - -``` ------------------Performance Summary------------------ -[e2e] throughputRate: 143.161, latency: 134310 -[data read] throughputRate: 144.544, moduleLatency: 6.91832 -[preprocess] throughputRate: 144.393, moduleLatency: 6.92554 -[inference] throughputRate: 144.476, Interface throughputRate: 12277.9, moduleLatency: 0.570148 -[postprocess] throughputRate: 9.03906, moduleLatency: 110.631 - ------------------------------------------------------------ -``` - -pem bs16性能数据 - -``` ------------------Performance Summary------------------ -[e2e] throughputRate: 141.751, latency: 33354.2 -[data read] throughputRate: 145.216, moduleLatency: 6.88627 -[preprocess] throughputRate: 144.936, moduleLatency: 6.89961 -[inference] throughputRate: 145.023, Interface throughputRate: 18564.9, moduleLatency: 0.483157 -[postprocess] throughputRate: 9.10977, moduleLatency: 109.772 - ------------------------------------------------------------ -``` - -tem单卡吞吐率:12277.9x4=49111.6 - -pem单卡吞吐率:18564.9x4=74259.6 - -BSN整体吞吐率为:1/(1/49111.6+1/74259.6)=29560.95 - -#### 2.2 T4性能数据 - -在装有T4卡的服务器上测试gpu性能,测试过程请确保卡没有运行其他任务,TensorRT版本:7.2.3.4,cuda版本:11.0,cudnn版本:8.2 - -batch1性能: - -tem: - -``` -trtexec --onnx=BSN_tem.onnx --fp16 --shapes=video:1*400*100 --threads -``` - - - -``` -[11/23/2021-06:45:38] [I] GPU Compute -[11/23/2021-06:45:38] [I] min: 0.045166 ms -[11/23/2021-06:45:38] [I] max: 2.00708 ms -[11/23/2021-06:45:38] [I] mean: 0.0565804 ms -[11/23/2021-06:45:38] [I] median: 0.0568848 ms -[11/23/2021-06:45:38] [I] percentile: 0.0620117 ms at 99% -[11/23/2021-06:45:38] [I] total compute time: 2.47115 s -``` - -pem: - -``` -trtexec --onnx=BSN_pem.onnx --fp16 --shapes=video:1*1000*32 --threads -``` - - - -``` -[11/19/2021-06:40:06] [I] GPU Compute -[11/19/2021-06:40:06] [I] min: 0.0185547 ms -[11/19/2021-06:40:06] [I] max: 1.26123 ms -[11/19/2021-06:40:06] [I] mean: 0.0205523 ms -[11/19/2021-06:40:06] [I] median: 0.0201416 ms -[11/19/2021-06:40:06] [I] percentile: 0.0458527 ms at 99% -[11/19/2021-06:40:06] [I] total compute time: 0.793032 s -``` - - - -tem单卡吞吐率:1000/0.215458=17674 - -pem单卡吞吐率:1000/0.0205523=48656 - -BSN单卡吞吐率:1000/(0.215458+0.0205523)=12965 - - - - - -batch16性能: - -tem: - -``` -trtexec --onnx=BSN_tem.onnx --fp16 --shapes=video:16*400*100 --threads -``` - - - -``` -[11/19/2021-06:37:12] [I] GPU Compute -[11/19/2021-06:37:12] [I] min: 0.182129 ms -[11/19/2021-06:37:12] [I] max: 0.252548 ms -[11/19/2021-06:37:12] [I] mean: 0.219561 ms -[11/19/2021-06:37:12] [I] median: 0.218262 ms -[11/19/2021-06:37:12] [I] percentile: 0.245422 ms at 99% -[11/19/2021-06:37:12] [I] total compute time: 1.5714 s -``` - -pem: - -``` -trtexec --onnx=BSN_pem.onnx --fp16 --shapes=video:16*1000*32 --threads -``` - - - -``` -[11/23/2021-06:51:29] [I] GPU Compute -[11/23/2021-06:51:29] [I] min: 0.21167 ms -[11/23/2021-06:51:29] [I] max: 2.40039 ms -[11/23/2021-06:51:29] [I] mean: 0.24159 ms -[11/23/2021-06:51:29] [I] median: 0.240479 ms -[11/23/2021-06:51:29] [I] percentile: 0.25769 ms at 99% -[11/23/2021-06:51:29] [I] total compute time: 2.08734 s -``` - -tem单卡吞吐率:1000/(0.219561/16)=72872 - -pem单卡吞吐率:1000/(0.24159/16)=66228 - -BSN单卡吞吐率:1000/((0.219561+0.0210533)/16)=34696 - - - -#### 2.3 性能对比 - -batch1 : - -​ TEM - -​ 310:13102 - -​ T4:17674 - -​ PEM: - -​ 310:15498 - -​ T4:48656 - -​ BSN: - -​ 7099.87<12965 - -​ 7099.87/12965=0.548 - -batch16: - -​ TEM: - -​ 310: 49111.6 - -​ t4: 72872 - -​ PEM: - -​ 310: 74259.6 - -​ T4: 66228 - -​ BSN: - -​ 29560.95<34696 - -​ 29560.95/34696=0.85 - -在batch1,310性能是0.548倍T4性能;在batch16,310性能是0.85倍T4性能。 - +# BSN推理说明 + + + +## 1、 环境说明 + +1、安装必要的依赖 + +``` +apex 0.1+ascend.20210930 +certifi 2021.10.8 +cycler 0.11.0 +decorator 5.1.0 +docutils 0.18 +flatbuffers 2.0 +future 0.18.2 +Geohash 1.0 +Hydra 2.5 +kiwisolver 1.3.2 +matplotlib 3.4.3 +mpmath 1.2.1 +numpy 1.21.0 +onnx 1.10.2 +onnxruntime 1.9.0 +pandas 1.3.4 +Pillow 8.4.0 +pip 21.3.1 +protobuf 3.19.1 +pyparsing 3.0.6 +python-dateutil 2.8.2 +pytz 2021.3 +scipy 1.7.2 +setuptools 58.0.4 +six 1.16.0 +sympy 1.9 +torch 1.5.0+ascend.post3.20210930 +typing-extensions 3.10.0.2 +wheel 0.37.0 +``` + +2、获取开源代码 + +直接从githup上git clone 可能无法clone成功,建议先把githup上的仓先导入到git,再clone + +``` +git clone https://github.com/wzmsltw/BSN-boundary-sensitive-network.pytorch +``` + + + +3、获取onnx_tools,优化TEM的onnx模型 + +``` +git clone https://gitee.com/zheng-wengang1/onnx_tools +``` + + + +4、下载视频特征数据集 + +请参考源代码仓 + +5、代码目录 + +``` +BSN #模型名称命名的文件夹 +├── BSN-boundary-sensitive-network.pytorch #BSN开源代码 + └── data + ├── activitynet_feature_cuhk + ├── csv_mean_100 #下载数据特征集 +├── env.sh #环境变量 +├── BSN_tem_pth2onnx.py #tem模型转换脚本 +├── BSN_pem_pth2onnx.py #pem模型转换脚本 +├── BSN_tem_preprocess.py #tem模型前处理脚本 +├── BSN_pem_preprocess.py #pem模型前处理脚本 +├── gen_dataset_info.py #生成数据集info文件 +├── BSN_tem_postprocess.py #tem模型后处理脚本 +├── BSN_pem_postprocess.py #pem模型后处理脚本 +├── BSN_eval.py #测试精度脚本 +├── TEM_onnx_conv1d2conv2d.py #tem模型onnx,conv1d算子转conv2d算子优化脚本 +├── requirements.txt #模型离线推理用到的所有且必要的依赖库 +├── README.md #模型离线推理说明README +├── modelzoo_level.txt #模型精度性能结果 +└── test + ├── pth2om.sh + ├── eval_acc_perf.sh + ├── parse.py +``` + + + +## 2、离线推理 + +1、pth权重转onnx + + + +TEM的pth权重转onnx,参数pth_path为TEM模型权重文件所在位置,onnx_path为输出的onnx模型位置 + +``` +python BSN_tem_pth2onnx.py --pth_path './tem_best.pth.tar' --onnx_path './BSN_tem.onnx' +``` + +tem-onnx模型优化,第一个参数为原本onnx模型位置,第二个参数为输出onnx模型 + +``` +python TEM_onnx_conv1d2conv2d.py './BSN_tem.onnx' './BSN_tem1.onnx' +``` + +PEM的pth权重转onnx,参数pth_path为PEM模型权重文件所在位置,onnx_path为输出的onnx模型位置 + +``` +python BSN_pem_pth2onnx.py --pth_path './pem_best.pth.tar' --onnx_path './BSN_pem.onnx' +``` + + + +2、onnx模型转om + +使用atc工具将onnx模型转为om模型,注意应当先设置环境变量 + +``` +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp +export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest + +atc --framework=5 --model=BSN_tem1.onnx --output=BSN_tem_bs1 --input_format=ND --input_shape="video:1,400,100" --log=debug --soc_version=Ascend310 + +atc --framework=5 --model=BSN_pem.onnx --output=BSN_pem_bs1 --input_format=ND --input_shape="video_feature:1,1000,32" --log=debug --soc_version=Ascend310 +``` + + + +3、TEM推理 + +运行预处理脚本,运行前确保你已经clone了开源代码,并下载数据特征集 + +``` +python BSN_tem_preprocess.py +``` + +获取处理数据集信息,第一个参数为模型类型,第二个参数为特征文件位置,第三个参数为输出文件名,第四、五个参数为特征形状(400*100) + +``` +python gen_dataset_info.py tem /home/wch/BSN/BSN-TEM-preprocess/feature TEM-video-feature 400 100 +``` + +使用benchmark工具进行推理,生成的数据文件会放在当前路径的result/dumpOutput_device0目录下 + +``` +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=BSN_tem_bs1.om -input_text_path=./TEM-video-feature.info -input_width=400 -input_height=100 -output_binary=True -useDvpp=False +``` + +使用BSN_tem_postprocess.py进行tem后处理(tem的后处理与pem的前处理有关请按照顺序执行) + +``` +python BSN_tem_postprocess.py --TEM_out_path ./result/dumpOutput_device0 +``` + + + +4、PEM推理 + +运行pem预处理脚本(pem的前处理与tem的后处理有关请按照顺序执行) + +``` +python BSN_pem_preprocess.py +``` + +获取处理数据集信息,第一个参数为模型类型,第二个参数为特征文件位置,第三个参数为输出文件名,第四、五个参数为特征形状(1000*32) + +``` +python get_info.py pem output/BSN-PEM-preprocess/feature PEM-video-feature 1000 32 +``` + +使用benchmark工具进行推理,生成的数据文件会放在当前路径的result/dumpOutput_device1目录下 + +``` +./benchmark.x86_64 -model_type=vision -device_id=1 -batch_size=1 -om_path=BSN_pem_bs1.om -input_text_path=./PEM-video-feature.info -input_width=1000 -input_height=32 -output_binary=True -useDvpp=False +``` + +运行后处理脚本,会在output目录下生成结果文件 + +``` +python BSN_pem_postprocess.py --PEM_out_path result/dumpOutput_device1 +``` + + + +5、精度测试 + +原本代码仓的代码是python2的代码,在在使用前需要转为python3 + +``` +2to3 -w ./BSN-boundary-sensitive-network.pytorch/Evaluation/eval_proposal.py + +``` + +精度测试 + +``` +python BSN_eval.py +``` + + + +6、整体测试 + +运行脚本,直接转om模型 + +``` +bash ./test/pth2om.sh +``` + +运行脚本,进行离线推理,运行脚本前,请确保已经将源代码中使用的文件,转为python3 + +``` +bash ./test/eval_acc_perf.sh +``` + + + +## 3 精度性能对比 + +### 1、精度对比 + +​ pth精度 + +``` +Model 论文 开源pth文件 离线推理精度 +BSN AR100:72.42 74.34 74.34 +``` + +### 2、性能对比 + +#### 2.1 npu性能数据 + +tem bs1性能数据 + +``` +-----------------Performance Summary------------------ +[e2e] throughputRate: 180.879, latency: 106303 +[data read] throughputRate: 182.039, moduleLatency: 5.49332 +[preprocess] throughputRate: 181.865, moduleLatency: 5.49859 +[inference] throughputRate: 182, Interface throughputRate: 3275.55, moduleLatency: 0.561457 +[postprocess] throughputRate: 182.009, moduleLatency: 5.49425 + +----------------------------------------------------------- +``` + +pem bs1性能数据 + +``` +-----------------Performance Summary------------------ +[e2e] throughputRate: 616.804, latency: 7665.32 +[data read] throughputRate: 1840.06, moduleLatency: 0.54346 +[preprocess] throughputRate: 1817.62, moduleLatency: 0.550169 +[inference] throughputRate: 1839.62, Interface throughputRate: 3874.46, moduleLatency: 0.469866 +[postprocess] throughputRate: 1839.86, moduleLatency: 0.543521 + +----------------------------------------------------------- +``` + +tem单卡吞吐率:3275.55x4=13102.2 + +pem单卡吞吐率:3874.46x4=15497.84 + +BSN整体吞吐率为:1/(1/13102.2+1/15497.84)=7099.87 + + + +tem bs16性能数据 + +``` +-----------------Performance Summary------------------ +[e2e] throughputRate: 143.161, latency: 134310 +[data read] throughputRate: 144.544, moduleLatency: 6.91832 +[preprocess] throughputRate: 144.393, moduleLatency: 6.92554 +[inference] throughputRate: 144.476, Interface throughputRate: 12277.9, moduleLatency: 0.570148 +[postprocess] throughputRate: 9.03906, moduleLatency: 110.631 + +----------------------------------------------------------- +``` + +pem bs16性能数据 + +``` +-----------------Performance Summary------------------ +[e2e] throughputRate: 141.751, latency: 33354.2 +[data read] throughputRate: 145.216, moduleLatency: 6.88627 +[preprocess] throughputRate: 144.936, moduleLatency: 6.89961 +[inference] throughputRate: 145.023, Interface throughputRate: 18564.9, moduleLatency: 0.483157 +[postprocess] throughputRate: 9.10977, moduleLatency: 109.772 + +----------------------------------------------------------- +``` + +tem单卡吞吐率:12277.9x4=49111.6 + +pem单卡吞吐率:18564.9x4=74259.6 + +BSN整体吞吐率为:1/(1/49111.6+1/74259.6)=29560.95 + +#### 2.2 T4性能数据 + +在装有T4卡的服务器上测试gpu性能,测试过程请确保卡没有运行其他任务,TensorRT版本:7.2.3.4,cuda版本:11.0,cudnn版本:8.2 + +batch1性能: + +tem: + +``` +trtexec --onnx=BSN_tem.onnx --fp16 --shapes=video:1*400*100 --threads +``` + + + +``` +[11/23/2021-06:45:38] [I] GPU Compute +[11/23/2021-06:45:38] [I] min: 0.045166 ms +[11/23/2021-06:45:38] [I] max: 2.00708 ms +[11/23/2021-06:45:38] [I] mean: 0.0565804 ms +[11/23/2021-06:45:38] [I] median: 0.0568848 ms +[11/23/2021-06:45:38] [I] percentile: 0.0620117 ms at 99% +[11/23/2021-06:45:38] [I] total compute time: 2.47115 s +``` + +pem: + +``` +trtexec --onnx=BSN_pem.onnx --fp16 --shapes=video:1*1000*32 --threads +``` + + + +``` +[11/19/2021-06:40:06] [I] GPU Compute +[11/19/2021-06:40:06] [I] min: 0.0185547 ms +[11/19/2021-06:40:06] [I] max: 1.26123 ms +[11/19/2021-06:40:06] [I] mean: 0.0205523 ms +[11/19/2021-06:40:06] [I] median: 0.0201416 ms +[11/19/2021-06:40:06] [I] percentile: 0.0458527 ms at 99% +[11/19/2021-06:40:06] [I] total compute time: 0.793032 s +``` + + + +tem单卡吞吐率:1000/0.215458=17674 + +pem单卡吞吐率:1000/0.0205523=48656 + +BSN单卡吞吐率:1000/(0.215458+0.0205523)=12965 + + + + + +batch16性能: + +tem: + +``` +trtexec --onnx=BSN_tem.onnx --fp16 --shapes=video:16*400*100 --threads +``` + + + +``` +[11/19/2021-06:37:12] [I] GPU Compute +[11/19/2021-06:37:12] [I] min: 0.182129 ms +[11/19/2021-06:37:12] [I] max: 0.252548 ms +[11/19/2021-06:37:12] [I] mean: 0.219561 ms +[11/19/2021-06:37:12] [I] median: 0.218262 ms +[11/19/2021-06:37:12] [I] percentile: 0.245422 ms at 99% +[11/19/2021-06:37:12] [I] total compute time: 1.5714 s +``` + +pem: + +``` +trtexec --onnx=BSN_pem.onnx --fp16 --shapes=video:16*1000*32 --threads +``` + + + +``` +[11/23/2021-06:51:29] [I] GPU Compute +[11/23/2021-06:51:29] [I] min: 0.21167 ms +[11/23/2021-06:51:29] [I] max: 2.40039 ms +[11/23/2021-06:51:29] [I] mean: 0.24159 ms +[11/23/2021-06:51:29] [I] median: 0.240479 ms +[11/23/2021-06:51:29] [I] percentile: 0.25769 ms at 99% +[11/23/2021-06:51:29] [I] total compute time: 2.08734 s +``` + +tem单卡吞吐率:1000/(0.219561/16)=72872 + +pem单卡吞吐率:1000/(0.24159/16)=66228 + +BSN单卡吞吐率:1000/((0.219561+0.0210533)/16)=34696 + + + +#### 2.3 性能对比 + +batch1 : + +​ TEM + +​ 310:13102 + +​ T4:17674 + +​ PEM: + +​ 310:15498 + +​ T4:48656 + +​ BSN: + +​ 7099.87<12965 + +​ 7099.87/12965=0.548 + +batch16: + +​ TEM: + +​ 310: 49111.6 + +​ t4: 72872 + +​ PEM: + +​ 310: 74259.6 + +​ T4: 66228 + +​ BSN: + +​ 29560.95<34696 + +​ 29560.95/34696=0.85 + +在batch1,310性能是0.548倍T4性能;在batch16,310性能是0.85倍T4性能。 + diff --git a/ACL_PyTorch/contrib/cv/detection/BSN/TEM_onnx_conv1d2conv2d.py b/ACL_PyTorch/contrib/cv/detection/BSN/TEM_onnx_conv1d2conv2d.py index 151d484924..5e31100527 100644 --- a/ACL_PyTorch/contrib/cv/detection/BSN/TEM_onnx_conv1d2conv2d.py +++ b/ACL_PyTorch/contrib/cv/detection/BSN/TEM_onnx_conv1d2conv2d.py @@ -1,110 +1,110 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import numpy as np -from onnx_tools.OXInterface.OXInterface import OXGraph - - -INPUT_NODE = 'video' - -def conv1d2conv2d(oxgraph, node_conv): - """ - transfer conv1d parameters to conv2d - :param oxgraph: input onnx graph - :param node_conv: conv1d node to be transfered - """ - if node_conv.get_op_type() != 'Conv': - return - if node_conv.get_name() == 'Conv_0': - node_conv.set_attribute(attr_name='dilations', attr_value=[1,1]) - node_conv.set_attribute(attr_name='kernel_shape', attr_value=[1,3]) - node_conv.set_attribute(attr_name='pads', attr_value=[0, 1, 0, 1]) - node_conv.set_attribute(attr_name='strides', attr_value=[1,1]) - if node_conv.get_name() == 'Conv_2': - node_conv.set_attribute(attr_name='dilations', attr_value=[1,1]) - node_conv.set_attribute(attr_name='kernel_shape', attr_value=[1,3]) - node_conv.set_attribute(attr_name='pads', attr_value=[0, 1, 0, 1]) - node_conv.set_attribute(attr_name='strides', attr_value=[1,1]) - if node_conv.get_name() == 'Conv_4': - node_conv.set_attribute(attr_name='dilations', attr_value=[1,1]) - node_conv.set_attribute(attr_name='kernel_shape', attr_value=[1,1]) - node_conv.set_attribute(attr_name='pads', attr_value=[0, 0, 0, 0]) - node_conv.set_attribute(attr_name='strides', attr_value=[1,1]) - - init_conv_w = oxgraph.get_oxinitializer_by_name(node_conv.input[1]) - init_conv_w.set_data(np.expand_dims(init_conv_w.get_data(), axis=2)) - -def transfer_structure(oxgraph, beg_node, end_node): - """ - transfer process: - 1. insert unsqueeze node before beg node - 2. insert squeeze node after end node - 3. transfer conv1d paramters for conv2d - :param oxgraph: input onnx graph - :param beg_node: beg node name for searched structure - :param end_node: end node name for searched structure - """ - previous_beg_node = oxgraph.get_previous_oxnode(oxnode_name=beg_node) - if not previous_beg_node: - previous_beg_node = INPUT_NODE - else: - previous_beg_node = previous_beg_node[0].get_name() - next_end_node = oxgraph.get_next_oxnode(oxnode_name=end_node) - unsqueeze_node_name = 'Unsqueeze_before_{}'.format(beg_node) - squeeze_node_name = 'Squeeze_after_{}'.format(end_node) - next_end_node = next_end_node[0].get_name() - - oxgraph.insert_node(bef_node_info_list=[previous_beg_node], - aft_node_info_list=[beg_node], - op_type='Unsqueeze', - op_name=unsqueeze_node_name) - oxgraph.insert_node(bef_node_info_list=[end_node], - aft_node_info_list=[next_end_node], - op_type='Squeeze', - op_name=squeeze_node_name) - node_unsqueeze = oxgraph.get_oxnode_by_name(unsqueeze_node_name) - node_unsqueeze.set_attribute(attr_name='axes', attr_value=[2]) - node_squeeze = oxgraph.get_oxnode_by_name(squeeze_node_name) - node_squeeze.set_attribute(attr_name='axes', attr_value=[2]) - - next_beg_node = oxgraph.get_oxnode_by_name(oxnode_name=beg_node) - while next_beg_node.get_name() != end_node: - conv1d2conv2d(oxgraph, next_beg_node) - next_beg_node = oxgraph.get_next_oxnode(oxnode_name=next_beg_node.get_name()) - next_beg_node = next_beg_node[0] - conv1d2conv2d(oxgraph, next_beg_node) - - -def fix_conv1d(model_path, out_path, beg_list, end_list): - """ - main process for fixing conv1d - :param model_path: input onnx model path - :param out_path: out fixed onnx model path - :param beg_list: beg node names for searched structure - :param end_list: end node names for searched structure - """ - oxgraph = OXGraph(model_path) - for idx, beg_node in enumerate(beg_list): - end_node = end_list[idx] - transfer_structure(oxgraph, beg_node, end_node) - oxgraph.save_new_model(out_path) - - -if __name__ == '__main__': - input_path = sys.argv[1] - save_path = sys.argv[2] - beg_nodes = ['Conv_0'] - end_nodes = ['Conv_4'] - fix_conv1d(input_path, save_path, beg_nodes, end_nodes) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import numpy as np +from onnx_tools.OXInterface.OXInterface import OXGraph + + +INPUT_NODE = 'video' + +def conv1d2conv2d(oxgraph, node_conv): + """ + transfer conv1d parameters to conv2d + :param oxgraph: input onnx graph + :param node_conv: conv1d node to be transfered + """ + if node_conv.get_op_type() != 'Conv': + return + if node_conv.get_name() == 'Conv_0': + node_conv.set_attribute(attr_name='dilations', attr_value=[1,1]) + node_conv.set_attribute(attr_name='kernel_shape', attr_value=[1,3]) + node_conv.set_attribute(attr_name='pads', attr_value=[0, 1, 0, 1]) + node_conv.set_attribute(attr_name='strides', attr_value=[1,1]) + if node_conv.get_name() == 'Conv_2': + node_conv.set_attribute(attr_name='dilations', attr_value=[1,1]) + node_conv.set_attribute(attr_name='kernel_shape', attr_value=[1,3]) + node_conv.set_attribute(attr_name='pads', attr_value=[0, 1, 0, 1]) + node_conv.set_attribute(attr_name='strides', attr_value=[1,1]) + if node_conv.get_name() == 'Conv_4': + node_conv.set_attribute(attr_name='dilations', attr_value=[1,1]) + node_conv.set_attribute(attr_name='kernel_shape', attr_value=[1,1]) + node_conv.set_attribute(attr_name='pads', attr_value=[0, 0, 0, 0]) + node_conv.set_attribute(attr_name='strides', attr_value=[1,1]) + + init_conv_w = oxgraph.get_oxinitializer_by_name(node_conv.input[1]) + init_conv_w.set_data(np.expand_dims(init_conv_w.get_data(), axis=2)) + +def transfer_structure(oxgraph, beg_node, end_node): + """ + transfer process: + 1. insert unsqueeze node before beg node + 2. insert squeeze node after end node + 3. transfer conv1d paramters for conv2d + :param oxgraph: input onnx graph + :param beg_node: beg node name for searched structure + :param end_node: end node name for searched structure + """ + previous_beg_node = oxgraph.get_previous_oxnode(oxnode_name=beg_node) + if not previous_beg_node: + previous_beg_node = INPUT_NODE + else: + previous_beg_node = previous_beg_node[0].get_name() + next_end_node = oxgraph.get_next_oxnode(oxnode_name=end_node) + unsqueeze_node_name = 'Unsqueeze_before_{}'.format(beg_node) + squeeze_node_name = 'Squeeze_after_{}'.format(end_node) + next_end_node = next_end_node[0].get_name() + + oxgraph.insert_node(bef_node_info_list=[previous_beg_node], + aft_node_info_list=[beg_node], + op_type='Unsqueeze', + op_name=unsqueeze_node_name) + oxgraph.insert_node(bef_node_info_list=[end_node], + aft_node_info_list=[next_end_node], + op_type='Squeeze', + op_name=squeeze_node_name) + node_unsqueeze = oxgraph.get_oxnode_by_name(unsqueeze_node_name) + node_unsqueeze.set_attribute(attr_name='axes', attr_value=[2]) + node_squeeze = oxgraph.get_oxnode_by_name(squeeze_node_name) + node_squeeze.set_attribute(attr_name='axes', attr_value=[2]) + + next_beg_node = oxgraph.get_oxnode_by_name(oxnode_name=beg_node) + while next_beg_node.get_name() != end_node: + conv1d2conv2d(oxgraph, next_beg_node) + next_beg_node = oxgraph.get_next_oxnode(oxnode_name=next_beg_node.get_name()) + next_beg_node = next_beg_node[0] + conv1d2conv2d(oxgraph, next_beg_node) + + +def fix_conv1d(model_path, out_path, beg_list, end_list): + """ + main process for fixing conv1d + :param model_path: input onnx model path + :param out_path: out fixed onnx model path + :param beg_list: beg node names for searched structure + :param end_list: end node names for searched structure + """ + oxgraph = OXGraph(model_path) + for idx, beg_node in enumerate(beg_list): + end_node = end_list[idx] + transfer_structure(oxgraph, beg_node, end_node) + oxgraph.save_new_model(out_path) + + +if __name__ == '__main__': + input_path = sys.argv[1] + save_path = sys.argv[2] + beg_nodes = ['Conv_0'] + end_nodes = ['Conv_4'] + fix_conv1d(input_path, save_path, beg_nodes, end_nodes) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/BSN/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/detection/BSN/gen_dataset_info.py index 7d55019ee8..bb435699d8 100644 --- a/ACL_PyTorch/contrib/cv/detection/BSN/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/detection/BSN/gen_dataset_info.py @@ -1,39 +1,39 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys - - -def get_bin_info(file_type, file_path, info_name, width, height): - bin_files = sorted(os.listdir(file_path)) - - with open(info_name+'.info', 'w') as file: - i = 0 - for bin_file in bin_files: - if bin_file.endswith('.bin'): - if file_type == 'tem': - content = ' '.join([str(i), 'output/BSN-TEM-preprocess/feature'+'/'+bin_file, width, height]) - if file_type == 'pem': - content = ' '.join([str(i), 'output/BSN-PEM-preprocess/feature'+'/'+bin_file, width, height]) - file.write(content) - file.write('\n') - i = i+1 - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - line = sys.argv[4] - col = sys.argv[5] +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys + + +def get_bin_info(file_type, file_path, info_name, width, height): + bin_files = sorted(os.listdir(file_path)) + + with open(info_name+'.info', 'w') as file: + i = 0 + for bin_file in bin_files: + if bin_file.endswith('.bin'): + if file_type == 'tem': + content = ' '.join([str(i), 'output/BSN-TEM-preprocess/feature'+'/'+bin_file, width, height]) + if file_type == 'pem': + content = ' '.join([str(i), 'output/BSN-PEM-preprocess/feature'+'/'+bin_file, width, height]) + file.write(content) + file.write('\n') + i = i+1 + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + line = sys.argv[4] + col = sys.argv[5] get_bin_info(file_type,file_path, info_name, line, col) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/BSN/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/detection/BSN/modelzoo_level.txt index c021e5b6cc..29569dfe38 100644 --- a/ACL_PyTorch/contrib/cv/detection/BSN/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/detection/BSN/modelzoo_level.txt @@ -1,5 +1,5 @@ -acc: -74.34 OK -perf: -bs1:6148 OK +acc: +74.34 OK +perf: +bs1:6148 OK bs16: 19172 False \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/BSN/parse.py b/ACL_PyTorch/contrib/cv/detection/BSN/parse.py index 1841a9747c..e071d8fecf 100644 --- a/ACL_PyTorch/contrib/cv/detection/BSN/parse.py +++ b/ACL_PyTorch/contrib/cv/detection/BSN/parse.py @@ -1,39 +1,39 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import re - -def get_acc(filename): - with open(filename, 'r') as f: - lines = f.readlines() - last_line = lines[-1] - psnr = last_line.split(" ")[2] - print(filename.split('.')[0],"Average PSNR:", psnr) - - -def get_perf(filename): - with open(filename, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 - print('310 bs{} fps:{}'.format(filename.split('_')[3], fps)) - -if __name__ == "__main__": - - filename = sys.argv[1] - - if filename.endswith(".log"): - get_acc(filename) - elif filename.endswith(".txt"): +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import re + +def get_acc(filename): + with open(filename, 'r') as f: + lines = f.readlines() + last_line = lines[-1] + psnr = last_line.split(" ")[2] + print(filename.split('.')[0],"Average PSNR:", psnr) + + +def get_perf(filename): + with open(filename, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 + print('310 bs{} fps:{}'.format(filename.split('_')[3], fps)) + +if __name__ == "__main__": + + filename = sys.argv[1] + + if filename.endswith(".log"): + get_acc(filename) + elif filename.endswith(".txt"): get_perf(filename) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/BSN/requirements.txt b/ACL_PyTorch/contrib/cv/detection/BSN/requirements.txt index bfc65830ff..796da27d2d 100644 --- a/ACL_PyTorch/contrib/cv/detection/BSN/requirements.txt +++ b/ACL_PyTorch/contrib/cv/detection/BSN/requirements.txt @@ -1,26 +1,26 @@ -cycler -decorator -docutils -flatbuffers -future -Geohash -Hydra -kiwisolver -matplotlib -mpmath -numpy -onnx -onnxruntime -pandas -Pillow -pip -protobuf -pyparsing -python-dateutil -pytz -scipy -setuptools -six -sympy -typing-extensions +cycler +decorator +docutils +flatbuffers +future +Geohash +Hydra +kiwisolver +matplotlib +mpmath +numpy +onnx +onnxruntime +pandas +Pillow +pip +protobuf +pyparsing +python-dateutil +pytz +scipy +setuptools +six +sympy +typing-extensions skl2onnx \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/BSN/test/parse.py b/ACL_PyTorch/contrib/cv/detection/BSN/test/parse.py index 1841a9747c..e071d8fecf 100644 --- a/ACL_PyTorch/contrib/cv/detection/BSN/test/parse.py +++ b/ACL_PyTorch/contrib/cv/detection/BSN/test/parse.py @@ -1,39 +1,39 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import re - -def get_acc(filename): - with open(filename, 'r') as f: - lines = f.readlines() - last_line = lines[-1] - psnr = last_line.split(" ")[2] - print(filename.split('.')[0],"Average PSNR:", psnr) - - -def get_perf(filename): - with open(filename, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 - print('310 bs{} fps:{}'.format(filename.split('_')[3], fps)) - -if __name__ == "__main__": - - filename = sys.argv[1] - - if filename.endswith(".log"): - get_acc(filename) - elif filename.endswith(".txt"): +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import re + +def get_acc(filename): + with open(filename, 'r') as f: + lines = f.readlines() + last_line = lines[-1] + psnr = last_line.split(" ")[2] + print(filename.split('.')[0],"Average PSNR:", psnr) + + +def get_perf(filename): + with open(filename, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 + print('310 bs{} fps:{}'.format(filename.split('_')[3], fps)) + +if __name__ == "__main__": + + filename = sys.argv[1] + + if filename.endswith(".log"): + get_acc(filename) + elif filename.endswith(".txt"): get_perf(filename) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/README.md b/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/README.md index a49732889f..b7eef1f4c8 100644 --- a/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/README.md +++ b/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/README.md @@ -1,156 +1,156 @@ -# Cascade-RCNN-Resnet101-FPN-DCN模型PyTorch离线推理指导 - -## 1 环境准备 - -1. 安装必要的依赖 - - 在文件夹中处理。 - - 测试环境可能已经安装其中的一些不同版本的库了,故手动测试时建议创建虚拟环境后自己安装,参考开源仓代码的获取方式: - -``` -conda create -n dcn python=3.7 -conda activate dcn -pip install onnx==1.7.0 -pip install onnxruntime==1.9.0 -conda install pytorch==1.7.0 torchvision==0.8.0 torchaudio==0.7.0 cpuonly -c pytorch -pip install mmcv-full==1.2.4 -``` - -2. 获取,修改与安装开源模型代码,参考开源仓代码的获取方式: - -``` -git clone https://github.com/open-mmlab/mmdetection.git -cd mmdetection -git reset a21eb25535f31634cef332b09fc27d28956fb24b --hard -pip install -v -e . -cd .. -``` - -将提供的**pytorch_code_change**文件夹中的文件替换原文件。 - -``` -cp ./pytorch_code_change/bbox_nms.py ./mmdetection/mmdet/core//post_processing/bbox_nms.py -cp ./pytorch_code_change/rpn_head.py ./mmdetection/mmdet/models/dense_heads/rpn_head.py -cp ./pytorch_code_change/single_level_roi_extractor.py ./mmdetection/mmdet/models/roi_heads/roi_extractors/single_level_roi_extractor.py -cp ./pytorch_code_change/delta_xywh_bbox_coder.py ./mmdetection/mmdet/core/bbox/coder/delta_xywh_bbox_coder.py -cp ./pytorch_code_change/pytorch2onnx.py ./mmdetection/tools/pytorch2onnx.py -cp ./pytorch_code_change/cascade_rcnn_r50_fpn.py ./mmdetection/configs/_base_/models/cascade_rcnn_r50_fpn.py -cp ./pytorch_code_change/deform_conv.py /root/anaconda3/envs/dcn/lib/python3.7/site-packages/mmcv/ops/deform_conv.py -#注意这里要根据实际情况下的安装路径来修改 -``` - -3. 获取权重文件 - -参考源码仓的方式获取,可以通过obs方法获取,下载对应的权重文件。 - -``` -wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/detection/Cascade%20RCNN-Resnet101-FPN-DCN/cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco_20200203-3b2f0594.pth -``` - -4. 数据集 - 本模型使用coco2017的验证集(val2017)验证,将服务器上的数据集复制到本文件下固定位置:data/coco/annotation/instances_val2017.json以及data/coco/val2017 - - ``` - mkdir -p data/coco - cp -r /opt/npu/datasets/coco/* /home/tyjf/data/coco - - ``` - -5. 导出onnx - - 使用mmdet框架自带的脚本导出onnx即可,这里指定shape为1216。 - - 由于当前框架限制,仅支持batchsize=1的场景。 - -``` -python mmdetection/tools/pytorch2onnx.py mmdetection/configs/dcn/cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py ./cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco_20200203-3b2f0594.pth --output-file=cascadeR101dcn.onnx --shape=1216 --verify --show -``` - -6. 导出om - - 运行atc.sh脚本,完成onnx到om模型的转换,注意输出节点可能需要根据实际的onnx修改。 - -``` -bash atc.sh cascadeR101dcn.onnx cascadeR101dcn -``` - - -## 2 离线推理 - -在310上执行,执行时使npu-smi info查看设备状态,确保device空闲。 - -1. 数据预处理 - -``` -python mmdetection_coco_preprocess.py --image_folder_path ./data/coco/val2017 --bin_folder_path val2017_bin -python get_info.py bin ./val2017_bin coco2017.info 1216 1216 -python get_info.py jpg ./data/coco/val2017 coco2017_jpg.info -``` - -2. 使用benchmark工具进行推理 - -``` -chmod u+x benchmark.x86_64 -./benchmark.x86_64 -model_type=vision -batch_size=1 -device_id=0 -input_text_path=./coco2017.info -input_width=1216 -input_height=1216 -useDvpp=False -output_binary=true -om_path=cascadeR101dcn.om -``` - -3. 推理结果展示 - -本模型提供后处理脚本,将二进制数据转化为txt文件,同时生成画出检测框后的图片。执行脚本 - -``` -python mmdetection_coco_postprocess.py --bin_data_path=result/dumpOutput_device0 --prob_thres=0.05 --ifShowDetObj --det_results_path=detection-results --test_annotation=coco2017_jpg.info -``` - -4. 精度验证 - -``` -python txt_to_json.py -python coco_eval.py --ground_truth ./data/coco/annotation/instances_val2017.json -``` -可以看到NPU精度:'bbox_mAP': 0.452 - -5. 性能验证 - -查看NPU性能 - -``` -bash test/perf_npu.sh -#或者运行 ./benchmark.x86_64 -round=50 -om_path=cascadeR101dcn.om --device_id=2 -batch_size=1 -``` - -可以看到NPU性能: - -[INFO] ave_throughputRate: 0.620627samples/s, ave_latency: 1593.71ms - -0.65281*4=2.61fps - -6. GPU性能与精度验证 - -由于模型算子的原因采取在线推理的方式检测GPU性能: - -在GPU上搭建好环境,并进行预处理: - -``` -mkdir -p data/coco/val2017 -cp -r /root/coco/val2017/* /home/dcnv0/data/coco/val2017 -mkdir -p data/coco/annotations -cp -r /root/coco/annotations/* /home/dcnv0/data/coco/annotations -``` - -测试性能与精度: - -``` -cd /home/dcnv0 -conda activate cascade -python ./mmdetection/tools/test.py ./mmdetection/configs/dcn/cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py ./cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco_20200203-3b2f0594.pth --eval=bbox -``` - -可以算出GPU性能为4.06fps左右。 - -**评测结果:** - -| 模型 | 官网pth精度 | 310离线推理精度 | gpu性能 | 310性能 | -| :--------------------------------: | :---------: | :-------------: | :-----: | :-----: | -| Cascade-RCNN-Resnet101-FPN-DCN | mAP:0.45 | mAP:0.452 | 4.06fps | 2.64fps | +# Cascade-RCNN-Resnet101-FPN-DCN模型PyTorch离线推理指导 + +## 1 环境准备 + +1. 安装必要的依赖 + + 在文件夹中处理。 + + 测试环境可能已经安装其中的一些不同版本的库了,故手动测试时建议创建虚拟环境后自己安装,参考开源仓代码的获取方式: + +``` +conda create -n dcn python=3.7 +conda activate dcn +pip install onnx==1.7.0 +pip install onnxruntime==1.9.0 +conda install pytorch==1.7.0 torchvision==0.8.0 torchaudio==0.7.0 cpuonly -c pytorch +pip install mmcv-full==1.2.4 +``` + +2. 获取,修改与安装开源模型代码,参考开源仓代码的获取方式: + +``` +git clone https://github.com/open-mmlab/mmdetection.git +cd mmdetection +git reset a21eb25535f31634cef332b09fc27d28956fb24b --hard +pip install -v -e . +cd .. +``` + +将提供的**pytorch_code_change**文件夹中的文件替换原文件。 + +``` +cp ./pytorch_code_change/bbox_nms.py ./mmdetection/mmdet/core//post_processing/bbox_nms.py +cp ./pytorch_code_change/rpn_head.py ./mmdetection/mmdet/models/dense_heads/rpn_head.py +cp ./pytorch_code_change/single_level_roi_extractor.py ./mmdetection/mmdet/models/roi_heads/roi_extractors/single_level_roi_extractor.py +cp ./pytorch_code_change/delta_xywh_bbox_coder.py ./mmdetection/mmdet/core/bbox/coder/delta_xywh_bbox_coder.py +cp ./pytorch_code_change/pytorch2onnx.py ./mmdetection/tools/pytorch2onnx.py +cp ./pytorch_code_change/cascade_rcnn_r50_fpn.py ./mmdetection/configs/_base_/models/cascade_rcnn_r50_fpn.py +cp ./pytorch_code_change/deform_conv.py /root/anaconda3/envs/dcn/lib/python3.7/site-packages/mmcv/ops/deform_conv.py +#注意这里要根据实际情况下的安装路径来修改 +``` + +3. 获取权重文件 + +参考源码仓的方式获取,可以通过obs方法获取,下载对应的权重文件。 + +``` +wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/detection/Cascade%20RCNN-Resnet101-FPN-DCN/cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco_20200203-3b2f0594.pth +``` + +4. 数据集 + 本模型使用coco2017的验证集(val2017)验证,将服务器上的数据集复制到本文件下固定位置:data/coco/annotation/instances_val2017.json以及data/coco/val2017 + + ``` + mkdir -p data/coco + cp -r /opt/npu/datasets/coco/* /home/tyjf/data/coco + + ``` + +5. 导出onnx + + 使用mmdet框架自带的脚本导出onnx即可,这里指定shape为1216。 + + 由于当前框架限制,仅支持batchsize=1的场景。 + +``` +python mmdetection/tools/pytorch2onnx.py mmdetection/configs/dcn/cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py ./cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco_20200203-3b2f0594.pth --output-file=cascadeR101dcn.onnx --shape=1216 --verify --show +``` + +6. 导出om + + 运行atc.sh脚本,完成onnx到om模型的转换,注意输出节点可能需要根据实际的onnx修改。 + +``` +bash atc.sh cascadeR101dcn.onnx cascadeR101dcn +``` + + +## 2 离线推理 + +在310上执行,执行时使npu-smi info查看设备状态,确保device空闲。 + +1. 数据预处理 + +``` +python mmdetection_coco_preprocess.py --image_folder_path ./data/coco/val2017 --bin_folder_path val2017_bin +python get_info.py bin ./val2017_bin coco2017.info 1216 1216 +python get_info.py jpg ./data/coco/val2017 coco2017_jpg.info +``` + +2. 使用benchmark工具进行推理 + +``` +chmod u+x benchmark.x86_64 +./benchmark.x86_64 -model_type=vision -batch_size=1 -device_id=0 -input_text_path=./coco2017.info -input_width=1216 -input_height=1216 -useDvpp=False -output_binary=true -om_path=cascadeR101dcn.om +``` + +3. 推理结果展示 + +本模型提供后处理脚本,将二进制数据转化为txt文件,同时生成画出检测框后的图片。执行脚本 + +``` +python mmdetection_coco_postprocess.py --bin_data_path=result/dumpOutput_device0 --prob_thres=0.05 --ifShowDetObj --det_results_path=detection-results --test_annotation=coco2017_jpg.info +``` + +4. 精度验证 + +``` +python txt_to_json.py +python coco_eval.py --ground_truth ./data/coco/annotation/instances_val2017.json +``` +可以看到NPU精度:'bbox_mAP': 0.452 + +5. 性能验证 + +查看NPU性能 + +``` +bash test/perf_npu.sh +#或者运行 ./benchmark.x86_64 -round=50 -om_path=cascadeR101dcn.om --device_id=2 -batch_size=1 +``` + +可以看到NPU性能: + +[INFO] ave_throughputRate: 0.620627samples/s, ave_latency: 1593.71ms + +0.65281*4=2.61fps + +6. GPU性能与精度验证 + +由于模型算子的原因采取在线推理的方式检测GPU性能: + +在GPU上搭建好环境,并进行预处理: + +``` +mkdir -p data/coco/val2017 +cp -r /root/coco/val2017/* /home/dcnv0/data/coco/val2017 +mkdir -p data/coco/annotations +cp -r /root/coco/annotations/* /home/dcnv0/data/coco/annotations +``` + +测试性能与精度: + +``` +cd /home/dcnv0 +conda activate cascade +python ./mmdetection/tools/test.py ./mmdetection/configs/dcn/cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco.py ./cascade_rcnn_r101_fpn_dconv_c3-c5_1x_coco_20200203-3b2f0594.pth --eval=bbox +``` + +可以算出GPU性能为4.06fps左右。 + +**评测结果:** + +| 模型 | 官网pth精度 | 310离线推理精度 | gpu性能 | 310性能 | +| :--------------------------------: | :---------: | :-------------: | :-----: | :-----: | +| Cascade-RCNN-Resnet101-FPN-DCN | mAP:0.45 | mAP:0.452 | 4.06fps | 2.64fps | diff --git a/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/coco_eval.py b/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/coco_eval.py index 628e5fc8a8..18c4fcdb6b 100644 --- a/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/coco_eval.py +++ b/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/coco_eval.py @@ -1,91 +1,91 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import numpy as np -from pycocotools.coco import COCO -from pycocotools.cocoeval import COCOeval - -CLASSES = ('person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', - 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', - 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', - 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', - 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', - 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', - 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', - 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', - 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', - 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', - 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', - 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush') - -def coco_evaluation(annotation_json, result_json): - cocoGt = COCO(annotation_json) - cocoDt = cocoGt.loadRes(result_json) - iou_thrs = np.linspace(.5, 0.95, int(np.round((0.95 - .5) / .05)) + 1, endpoint=True) - iou_type = 'bbox' - - cocoEval = COCOeval(cocoGt, cocoDt, iou_type) - cocoEval.params.catIds = cocoGt.get_cat_ids(cat_names=CLASSES) - cocoEval.params.imgIds = cocoGt.get_img_ids() - cocoEval.params.maxDets = [100, 300, 1000] # proposal number for evaluating recalls/mAPs. - cocoEval.params.iouThrs = iou_thrs - - cocoEval.evaluate() - cocoEval.accumulate() - cocoEval.summarize() - - # mapping of cocoEval.stats - coco_metric_names = { - 'mAP': 0, - 'mAP_50': 1, - 'mAP_75': 2, - 'mAP_s': 3, - 'mAP_m': 4, - 'mAP_l': 5, - 'AR@100': 6, - 'AR@300': 7, - 'AR@1000': 8, - 'AR_s@1000': 9, - 'AR_m@1000': 10, - 'AR_l@1000': 11 - } - - metric_items = ['mAP', 'mAP_50', 'mAP_75', 'mAP_s', 'mAP_m', 'mAP_l'] - eval_results = {} - - for metric_item in metric_items: - key = f'bbox_{metric_item}' - val = float( - f'{cocoEval.stats[coco_metric_names[metric_item]]:.3f}' - ) - eval_results[key] = val - ap = cocoEval.stats[:6] - eval_results['bbox_mAP_copypaste'] = ( - f'{ap[0]:.3f} {ap[1]:.3f} {ap[2]:.3f} {ap[3]:.3f} ' - f'{ap[4]:.3f} {ap[5]:.3f}') - - return eval_results - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--ground_truth", default="instances_val2017.json") - parser.add_argument("--detection_result", default="coco_detection_result.json") - args = parser.parse_args() - result = coco_evaluation(args.ground_truth, args.detection_result) - print(result) - with open('./coco_detection_result.txt', 'w') as f: - for key, value in result.items(): +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import numpy as np +from pycocotools.coco import COCO +from pycocotools.cocoeval import COCOeval + +CLASSES = ('person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', + 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', + 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', + 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', + 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', + 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', + 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', + 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', + 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', + 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', + 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', + 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush') + +def coco_evaluation(annotation_json, result_json): + cocoGt = COCO(annotation_json) + cocoDt = cocoGt.loadRes(result_json) + iou_thrs = np.linspace(.5, 0.95, int(np.round((0.95 - .5) / .05)) + 1, endpoint=True) + iou_type = 'bbox' + + cocoEval = COCOeval(cocoGt, cocoDt, iou_type) + cocoEval.params.catIds = cocoGt.get_cat_ids(cat_names=CLASSES) + cocoEval.params.imgIds = cocoGt.get_img_ids() + cocoEval.params.maxDets = [100, 300, 1000] # proposal number for evaluating recalls/mAPs. + cocoEval.params.iouThrs = iou_thrs + + cocoEval.evaluate() + cocoEval.accumulate() + cocoEval.summarize() + + # mapping of cocoEval.stats + coco_metric_names = { + 'mAP': 0, + 'mAP_50': 1, + 'mAP_75': 2, + 'mAP_s': 3, + 'mAP_m': 4, + 'mAP_l': 5, + 'AR@100': 6, + 'AR@300': 7, + 'AR@1000': 8, + 'AR_s@1000': 9, + 'AR_m@1000': 10, + 'AR_l@1000': 11 + } + + metric_items = ['mAP', 'mAP_50', 'mAP_75', 'mAP_s', 'mAP_m', 'mAP_l'] + eval_results = {} + + for metric_item in metric_items: + key = f'bbox_{metric_item}' + val = float( + f'{cocoEval.stats[coco_metric_names[metric_item]]:.3f}' + ) + eval_results[key] = val + ap = cocoEval.stats[:6] + eval_results['bbox_mAP_copypaste'] = ( + f'{ap[0]:.3f} {ap[1]:.3f} {ap[2]:.3f} {ap[3]:.3f} ' + f'{ap[4]:.3f} {ap[5]:.3f}') + + return eval_results + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("--ground_truth", default="instances_val2017.json") + parser.add_argument("--detection_result", default="coco_detection_result.json") + args = parser.parse_args() + result = coco_evaluation(args.ground_truth, args.detection_result) + print(result) + with open('./coco_detection_result.txt', 'w') as f: + for key, value in result.items(): f.write(key + ': ' + str(value) + '\n') \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/get_info.py b/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/get_info.py index 5af675c6b0..fc6cdebb5b 100644 --- a/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/get_info.py +++ b/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/get_info.py @@ -1,60 +1,60 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/mmdetection_coco_postprocess.py b/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/mmdetection_coco_postprocess.py index a40fbc9bfc..bcad902c27 100644 --- a/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/mmdetection_coco_postprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/mmdetection_coco_postprocess.py @@ -1,148 +1,148 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import numpy as np -import argparse -import cv2 - -CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', - 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', - 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', - 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', - 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', - 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', - 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', - 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', - 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', - 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', - 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', - 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] - -def coco_postprocess(bbox: np.ndarray, image_size, - net_input_width, net_input_height): - """ - This function is postprocessing for FasterRCNN output. - - Before calling this function, reshape the raw output of FasterRCNN to - following form - numpy.ndarray: - [x, y, width, height, confidence, probability of 80 classes] - shape: (100,) - The postprocessing restore the bounding rectangles of FasterRCNN output - to origin scale and filter with non-maximum suppression. - - :param bbox: a numpy array of the FasterRCNN output - :param image_path: a string of image path - :return: three list for best bound, class and score - """ - w = image_size[0] - h = image_size[1] - scale = min(net_input_width / w, net_input_height / h) - - pad_w = net_input_width - w * scale - pad_h = net_input_height - h * scale - pad_left = pad_w // 2 - pad_top = pad_h // 2 - - # cal predict box on the image src - pbox = bbox - pbox[:, 0] = (bbox[:, 0] - pad_left) / scale - pbox[:, 1] = (bbox[:, 1] - pad_top) / scale - pbox[:, 2] = (bbox[:, 2] - pad_left) / scale - pbox[:, 3] = (bbox[:, 3] - pad_top) / scale - return pbox - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--bin_data_path", default="./result/dumpOutput_device0") - parser.add_argument("--test_annotation", default="./coco2017_jpg.info") - parser.add_argument("--det_results_path", default="./detection-results/") - parser.add_argument("--net_out_num", default=2) - parser.add_argument("--net_input_width", default=1216) - parser.add_argument("--net_input_height", default=1216) - parser.add_argument("--prob_thres", default=0.05) - parser.add_argument("--ifShowDetObj", action="store_true", help="if input the para means True, neither False.") - flags = parser.parse_args() - print(flags.ifShowDetObj, type(flags.ifShowDetObj)) - # generate dict according to annotation file for query resolution - # load width and height of input images - img_size_dict = dict() - with open(flags.test_annotation)as f: - for line in f.readlines(): - temp = line.split(" ") - img_file_path = temp[1] - img_name = temp[1].split("/")[-1].split(".")[0] - img_width = int(temp[2]) - img_height = int(temp[3]) - img_size_dict[img_name] = (img_width, img_height, img_file_path) - - # read bin file for generate predict result - bin_path = flags.bin_data_path - det_results_path = flags.det_results_path - os.makedirs(det_results_path, exist_ok=True) - total_img = set([name[:name.rfind('_')] - for name in os.listdir(bin_path) if "bin" in name]) - for bin_file in sorted(total_img): - path_base = os.path.join(bin_path, bin_file) - # load all detected output tensor - res_buff = [] - for num in range(1, flags.net_out_num + 1): - if os.path.exists(path_base + "_" + str(num) + ".bin"): - if num == 1: - buf = np.fromfile(path_base + "_" + str(num) + ".bin", dtype="float32") - buf = np.reshape(buf, [100, 5]) - elif num == 2: - buf = np.fromfile(path_base + "_" + str(num) + ".bin", dtype="int64") - buf = np.reshape(buf, [100, 1]) - res_buff.append(buf) - else: - print("[ERROR] file not exist", path_base + "_" + str(num) + ".bin") - res_tensor = np.concatenate(res_buff, axis=1) - current_img_size = img_size_dict[bin_file] - print("[TEST]---------------------------concat{} imgsize{}".format(len(res_tensor), current_img_size)) - predbox = coco_postprocess(res_tensor, current_img_size, flags.net_input_width, flags.net_input_height) - - if flags.ifShowDetObj == True: - imgCur = cv2.imread(current_img_size[2]) - - det_results_str = '' - for idx, class_ind in enumerate(predbox[:,5]): - if float(predbox[idx][4]) < float(flags.prob_thres): - continue - # skip negative class index - if class_ind < 0 or class_ind > 80: - continue - - class_name = CLASSES[int(class_ind)] - det_results_str += "{} {} {} {} {} {}\n".format(class_name, str(predbox[idx][4]), predbox[idx][0], - predbox[idx][1], predbox[idx][2], predbox[idx][3]) - if flags.ifShowDetObj == True: - imgCur=cv2.rectangle(imgCur, (int(predbox[idx][0]), int(predbox[idx][1])), - (int(predbox[idx][2]), int(predbox[idx][3])), (0,255,0), 1) - imgCur = cv2.putText(imgCur, class_name+'|'+str(predbox[idx][4]), - (int(predbox[idx][0]), int(predbox[idx][1])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) - # 图像,文字内容, 坐标 ,字体,大小,颜色,字体厚度 - - if flags.ifShowDetObj == True: - print(os.path.join(det_results_path, bin_file +'.jpg')) - cv2.imwrite(os.path.join(det_results_path, bin_file +'.jpg'), imgCur, [int(cv2.IMWRITE_JPEG_QUALITY),70]) - - det_results_file = os.path.join(det_results_path, bin_file + ".txt") - with open(det_results_file, "w") as detf: - detf.write(det_results_str) - print(det_results_str) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import numpy as np +import argparse +import cv2 + +CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', + 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', + 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', + 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', + 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', + 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', + 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', + 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', + 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', + 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', + 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', + 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] + +def coco_postprocess(bbox: np.ndarray, image_size, + net_input_width, net_input_height): + """ + This function is postprocessing for FasterRCNN output. + + Before calling this function, reshape the raw output of FasterRCNN to + following form + numpy.ndarray: + [x, y, width, height, confidence, probability of 80 classes] + shape: (100,) + The postprocessing restore the bounding rectangles of FasterRCNN output + to origin scale and filter with non-maximum suppression. + + :param bbox: a numpy array of the FasterRCNN output + :param image_path: a string of image path + :return: three list for best bound, class and score + """ + w = image_size[0] + h = image_size[1] + scale = min(net_input_width / w, net_input_height / h) + + pad_w = net_input_width - w * scale + pad_h = net_input_height - h * scale + pad_left = pad_w // 2 + pad_top = pad_h // 2 + + # cal predict box on the image src + pbox = bbox + pbox[:, 0] = (bbox[:, 0] - pad_left) / scale + pbox[:, 1] = (bbox[:, 1] - pad_top) / scale + pbox[:, 2] = (bbox[:, 2] - pad_left) / scale + pbox[:, 3] = (bbox[:, 3] - pad_top) / scale + return pbox + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("--bin_data_path", default="./result/dumpOutput_device0") + parser.add_argument("--test_annotation", default="./coco2017_jpg.info") + parser.add_argument("--det_results_path", default="./detection-results/") + parser.add_argument("--net_out_num", default=2) + parser.add_argument("--net_input_width", default=1216) + parser.add_argument("--net_input_height", default=1216) + parser.add_argument("--prob_thres", default=0.05) + parser.add_argument("--ifShowDetObj", action="store_true", help="if input the para means True, neither False.") + flags = parser.parse_args() + print(flags.ifShowDetObj, type(flags.ifShowDetObj)) + # generate dict according to annotation file for query resolution + # load width and height of input images + img_size_dict = dict() + with open(flags.test_annotation)as f: + for line in f.readlines(): + temp = line.split(" ") + img_file_path = temp[1] + img_name = temp[1].split("/")[-1].split(".")[0] + img_width = int(temp[2]) + img_height = int(temp[3]) + img_size_dict[img_name] = (img_width, img_height, img_file_path) + + # read bin file for generate predict result + bin_path = flags.bin_data_path + det_results_path = flags.det_results_path + os.makedirs(det_results_path, exist_ok=True) + total_img = set([name[:name.rfind('_')] + for name in os.listdir(bin_path) if "bin" in name]) + for bin_file in sorted(total_img): + path_base = os.path.join(bin_path, bin_file) + # load all detected output tensor + res_buff = [] + for num in range(1, flags.net_out_num + 1): + if os.path.exists(path_base + "_" + str(num) + ".bin"): + if num == 1: + buf = np.fromfile(path_base + "_" + str(num) + ".bin", dtype="float32") + buf = np.reshape(buf, [100, 5]) + elif num == 2: + buf = np.fromfile(path_base + "_" + str(num) + ".bin", dtype="int64") + buf = np.reshape(buf, [100, 1]) + res_buff.append(buf) + else: + print("[ERROR] file not exist", path_base + "_" + str(num) + ".bin") + res_tensor = np.concatenate(res_buff, axis=1) + current_img_size = img_size_dict[bin_file] + print("[TEST]---------------------------concat{} imgsize{}".format(len(res_tensor), current_img_size)) + predbox = coco_postprocess(res_tensor, current_img_size, flags.net_input_width, flags.net_input_height) + + if flags.ifShowDetObj == True: + imgCur = cv2.imread(current_img_size[2]) + + det_results_str = '' + for idx, class_ind in enumerate(predbox[:,5]): + if float(predbox[idx][4]) < float(flags.prob_thres): + continue + # skip negative class index + if class_ind < 0 or class_ind > 80: + continue + + class_name = CLASSES[int(class_ind)] + det_results_str += "{} {} {} {} {} {}\n".format(class_name, str(predbox[idx][4]), predbox[idx][0], + predbox[idx][1], predbox[idx][2], predbox[idx][3]) + if flags.ifShowDetObj == True: + imgCur=cv2.rectangle(imgCur, (int(predbox[idx][0]), int(predbox[idx][1])), + (int(predbox[idx][2]), int(predbox[idx][3])), (0,255,0), 1) + imgCur = cv2.putText(imgCur, class_name+'|'+str(predbox[idx][4]), + (int(predbox[idx][0]), int(predbox[idx][1])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) + # 图像,文字内容, 坐标 ,字体,大小,颜色,字体厚度 + + if flags.ifShowDetObj == True: + print(os.path.join(det_results_path, bin_file +'.jpg')) + cv2.imwrite(os.path.join(det_results_path, bin_file +'.jpg'), imgCur, [int(cv2.IMWRITE_JPEG_QUALITY),70]) + + det_results_file = os.path.join(det_results_path, bin_file + ".txt") + with open(det_results_file, "w") as detf: + detf.write(det_results_str) + print(det_results_str) diff --git a/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/mmdetection_coco_preprocess.py b/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/mmdetection_coco_preprocess.py index 4a6cd14f93..fc8c2c5293 100644 --- a/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/mmdetection_coco_preprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/mmdetection_coco_preprocess.py @@ -1,68 +1,68 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 numpy as np -import os -import cv2 -import argparse -import mmcv -import torch - -dataset_config = { - 'resize': (1216, 1216), - 'mean': [123.675, 116.28, 103.53], - 'std': [58.395, 57.12, 57.375], -} - -tensor_height = 1216 -tensor_width = 1216 - -def coco_preprocess(input_image, output_bin_path): - #define the output file name - img_name = input_image.split('/')[-1] - bin_name = img_name.split('.')[0] + ".bin" - bin_fl = os.path.join(output_bin_path, bin_name) - - one_img = mmcv.imread(os.path.join(input_image), backend='cv2') - one_img = mmcv.imrescale(one_img, (tensor_height, tensor_width)) - # calculate padding - h = one_img.shape[0] - w = one_img.shape[1] - pad_left = (tensor_width - w) // 2 - pad_top = (tensor_height - h) // 2 - pad_right = tensor_width - pad_left - w - pad_bottom = tensor_height - pad_top - h - - mean = np.array(dataset_config['mean'], dtype=np.float32) - std = np.array(dataset_config['std'], dtype=np.float32) - one_img = mmcv.imnormalize(one_img, mean, std) - one_img = mmcv.impad(one_img, padding=(pad_left, pad_top, pad_right, pad_bottom), pad_val=0) - one_img = one_img.transpose(2, 0, 1) - one_img.tofile(bin_fl) - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='preprocess of FasterRCNN pytorch model') - parser.add_argument("--image_folder_path", default="./coco2014/", help='image of dataset') - parser.add_argument("--bin_folder_path", default="./coco2014_bin/", help='Preprocessed image buffer') - flags = parser.parse_args() - - if not os.path.exists(flags.bin_folder_path): - os.makedirs(flags.bin_folder_path) - images = os.listdir(flags.image_folder_path) - for image_name in images: - if not (image_name.endswith(".jpeg") or image_name.endswith(".JPEG") or image_name.endswith(".jpg")): - continue - print("start to process image {}....".format(image_name)) - path_image = os.path.join(flags.image_folder_path, image_name) - coco_preprocess(path_image, flags.bin_folder_path) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 numpy as np +import os +import cv2 +import argparse +import mmcv +import torch + +dataset_config = { + 'resize': (1216, 1216), + 'mean': [123.675, 116.28, 103.53], + 'std': [58.395, 57.12, 57.375], +} + +tensor_height = 1216 +tensor_width = 1216 + +def coco_preprocess(input_image, output_bin_path): + #define the output file name + img_name = input_image.split('/')[-1] + bin_name = img_name.split('.')[0] + ".bin" + bin_fl = os.path.join(output_bin_path, bin_name) + + one_img = mmcv.imread(os.path.join(input_image), backend='cv2') + one_img = mmcv.imrescale(one_img, (tensor_height, tensor_width)) + # calculate padding + h = one_img.shape[0] + w = one_img.shape[1] + pad_left = (tensor_width - w) // 2 + pad_top = (tensor_height - h) // 2 + pad_right = tensor_width - pad_left - w + pad_bottom = tensor_height - pad_top - h + + mean = np.array(dataset_config['mean'], dtype=np.float32) + std = np.array(dataset_config['std'], dtype=np.float32) + one_img = mmcv.imnormalize(one_img, mean, std) + one_img = mmcv.impad(one_img, padding=(pad_left, pad_top, pad_right, pad_bottom), pad_val=0) + one_img = one_img.transpose(2, 0, 1) + one_img.tofile(bin_fl) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='preprocess of FasterRCNN pytorch model') + parser.add_argument("--image_folder_path", default="./coco2014/", help='image of dataset') + parser.add_argument("--bin_folder_path", default="./coco2014_bin/", help='Preprocessed image buffer') + flags = parser.parse_args() + + if not os.path.exists(flags.bin_folder_path): + os.makedirs(flags.bin_folder_path) + images = os.listdir(flags.image_folder_path) + for image_name in images: + if not (image_name.endswith(".jpeg") or image_name.endswith(".JPEG") or image_name.endswith(".jpg")): + continue + print("start to process image {}....".format(image_name)) + path_image = os.path.join(flags.image_folder_path, image_name) + coco_preprocess(path_image, flags.bin_folder_path) diff --git a/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/requirements.txt b/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/requirements.txt index fcabf40ea5..3dfcf9563e 100644 --- a/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/requirements.txt +++ b/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/requirements.txt @@ -1,6 +1,6 @@ -torch==1.7.0 -torchvision==0.8.0 -onnx==1.8.0 -mmdet==2.8.0 -mmcv-full==1.2.4 +torch==1.7.0 +torchvision==0.8.0 +onnx==1.8.0 +mmdet==2.8.0 +mmcv-full==1.2.4 onnxruntime==1.9.0 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/txt_to_json.py b/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/txt_to_json.py index a2346a773d..9f479da6a0 100644 --- a/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/txt_to_json.py +++ b/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN/txt_to_json.py @@ -1,114 +1,114 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 glob -import os -import sys -import argparse -import mmcv - -CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', - 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', - 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', - 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', - 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', - 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', - 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', - 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', - 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', - 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', - 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', - 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] - -cat_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, -24, 25, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, -48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 70, -72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90] - -''' - 0,0 ------> x (width) - | - | (Left,Top) - | *_________ - | | | - | | - y |_________| - (height) * - (Right,Bottom) -''' - -def file_lines_to_list(path): - # open txt file lines to a list - with open(path) as f: - content = f.readlines() - # remove whitespace characters like `\n` at the end of each line - content = [x.strip() for x in content] - return content - - -def error(msg): - print(msg) - sys.exit(0) - - -def get_predict_list(file_path, gt_classes): - dr_files_list = glob.glob(file_path + '/*.txt') - dr_files_list.sort() - - bounding_boxes = [] - for txt_file in dr_files_list: - file_id = txt_file.split(".txt", 1)[0] - file_id = os.path.basename(os.path.normpath(file_id)) - lines = file_lines_to_list(txt_file) - for line in lines: - try: - sl = line.split() - if len(sl) > 6: - class_name = sl[0] + ' ' + sl[1] - scores, left, top, right, bottom = sl[2:] - else: - class_name, scores, left, top, right, bottom = sl - if float(scores) < 0.05: - continue - except ValueError: - error_msg = "Error: File " + txt_file + " wrong format.\n" - error_msg += " Expected: \n" - error_msg += " Received: " + line - error(error_msg) - - # bbox = left + " " + top + " " + right + " " + bottom - left = float(left) - right = float(right) - top = float(top) - bottom = float(bottom) - bbox = [left, top, right-left, bottom-top] - bounding_boxes.append({"image_id": int(file_id), "bbox": bbox, - "score": float(scores), "category_id": cat_ids[CLASSES.index(class_name)]}) - # sort detection-results by decreasing scores - # bounding_boxes.sort(key=lambda x: float(x['score']), reverse=True) - return bounding_boxes - - - -if __name__ == '__main__': - parser = argparse.ArgumentParser('mAp calculate') - parser.add_argument('--npu_txt_path', default="detection-results", - help='the path of the predict result') - parser.add_argument("--json_output_file", default="coco_detection_result") - args = parser.parse_args() - - res_bbox = get_predict_list(args.npu_txt_path, CLASSES) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 glob +import os +import sys +import argparse +import mmcv + +CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', + 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', + 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', + 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', + 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', + 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', + 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', + 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', + 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', + 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', + 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', + 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] + +cat_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, +24, 25, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, +48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 70, +72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90] + +''' + 0,0 ------> x (width) + | + | (Left,Top) + | *_________ + | | | + | | + y |_________| + (height) * + (Right,Bottom) +''' + +def file_lines_to_list(path): + # open txt file lines to a list + with open(path) as f: + content = f.readlines() + # remove whitespace characters like `\n` at the end of each line + content = [x.strip() for x in content] + return content + + +def error(msg): + print(msg) + sys.exit(0) + + +def get_predict_list(file_path, gt_classes): + dr_files_list = glob.glob(file_path + '/*.txt') + dr_files_list.sort() + + bounding_boxes = [] + for txt_file in dr_files_list: + file_id = txt_file.split(".txt", 1)[0] + file_id = os.path.basename(os.path.normpath(file_id)) + lines = file_lines_to_list(txt_file) + for line in lines: + try: + sl = line.split() + if len(sl) > 6: + class_name = sl[0] + ' ' + sl[1] + scores, left, top, right, bottom = sl[2:] + else: + class_name, scores, left, top, right, bottom = sl + if float(scores) < 0.05: + continue + except ValueError: + error_msg = "Error: File " + txt_file + " wrong format.\n" + error_msg += " Expected: \n" + error_msg += " Received: " + line + error(error_msg) + + # bbox = left + " " + top + " " + right + " " + bottom + left = float(left) + right = float(right) + top = float(top) + bottom = float(bottom) + bbox = [left, top, right-left, bottom-top] + bounding_boxes.append({"image_id": int(file_id), "bbox": bbox, + "score": float(scores), "category_id": cat_ids[CLASSES.index(class_name)]}) + # sort detection-results by decreasing scores + # bounding_boxes.sort(key=lambda x: float(x['score']), reverse=True) + return bounding_boxes + + + +if __name__ == '__main__': + parser = argparse.ArgumentParser('mAp calculate') + parser.add_argument('--npu_txt_path', default="detection-results", + help='the path of the predict result') + parser.add_argument("--json_output_file", default="coco_detection_result") + args = parser.parse_args() + + res_bbox = get_predict_list(args.npu_txt_path, CLASSES) mmcv.dump(res_bbox, args.json_output_file + '.json') \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/README.md b/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/README.md index 085891be0d..d76158104c 100644 --- a/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/README.md +++ b/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/README.md @@ -1,57 +1,57 @@ -# Casacde_RCNN_R101模型PyTorch离线推理指导 - -## 1 环境准备 - -1. 安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 - -``` -pip3.7 install -r requirements.txt -``` - -2. 获取,修改与安装开源模型代码 - -``` -git clone https://github.com/open-mmlab/mmdetection.git -cd mmdetection -git reset a21eb25535f31634cef332b09fc27d28956fb24b --hard -pip3.7 install -v -e . -patch -p1 < ../Cascade_RCNN_R101.patch -cd .. -``` - -利用提供的change文件夹中的patch文件,完成补丁操作,命令参考如下示例,请用户根据安装包位置自行修改: -``` -cd change -patch -p0 /usr/local/python3.7.5/lib/python3.7/site-packages/mmcv/ops/deform_conv.py deform_conv.patch -cd ../ -``` - - -3. 获取权重文件 - - 从[LINK](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn)下载cascade_rcnn模型权重文件 - -4. 数据集 - 本模型使用coco2017的验证集验证 - -5. [获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) -将benchmark.x86_64或benchmark.aarch64放到当前目录 - - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=./ -``` - - -**评测结果:** - -| 模型 | 官网pth精度 | 310离线推理精度 | gpu性能 | 310性能 | -| :---------------: | :---------: | :-------------: | :-----: | :------: | -| Cascade_RCNN_R101 bs1 | map:0.42 | map:0.42 | 4.8task/s | 5.667fps | - - - +# Casacde_RCNN_R101模型PyTorch离线推理指导 + +## 1 环境准备 + +1. 安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 + +``` +pip3.7 install -r requirements.txt +``` + +2. 获取,修改与安装开源模型代码 + +``` +git clone https://github.com/open-mmlab/mmdetection.git +cd mmdetection +git reset a21eb25535f31634cef332b09fc27d28956fb24b --hard +pip3.7 install -v -e . +patch -p1 < ../Cascade_RCNN_R101.patch +cd .. +``` + +利用提供的change文件夹中的patch文件,完成补丁操作,命令参考如下示例,请用户根据安装包位置自行修改: +``` +cd change +patch -p0 /usr/local/python3.7.5/lib/python3.7/site-packages/mmcv/ops/deform_conv.py deform_conv.patch +cd ../ +``` + + +3. 获取权重文件 + + 从[LINK](https://github.com/open-mmlab/mmdetection/tree/master/configs/cascade_rcnn)下载cascade_rcnn模型权重文件 + +4. 数据集 + 本模型使用coco2017的验证集验证 + +5. [获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) +将benchmark.x86_64或benchmark.aarch64放到当前目录 + + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=./ +``` + + +**评测结果:** + +| 模型 | 官网pth精度 | 310离线推理精度 | gpu性能 | 310性能 | +| :---------------: | :---------: | :-------------: | :-----: | :------: | +| Cascade_RCNN_R101 bs1 | map:0.42 | map:0.42 | 4.8task/s | 5.667fps | + + + diff --git a/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/get_info.py b/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/get_info.py index 5af675c6b0..fc6cdebb5b 100644 --- a/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/get_info.py +++ b/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/get_info.py @@ -1,60 +1,60 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/mmdetection_coco_postprocess.py b/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/mmdetection_coco_postprocess.py index 5ca79ff17f..a4bcab73b9 100644 --- a/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/mmdetection_coco_postprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/mmdetection_coco_postprocess.py @@ -1,276 +1,276 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import numpy as np -import cv2 -import glob -import sys -import argparse -import mmcv -from pycocotools.coco import COCO -from pycocotools.cocoeval import COCOeval - -CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', - 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', - 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', - 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', - 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', - 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', - 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', - 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', - 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', - 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', - 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', - 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] - -cat_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, -24, 25, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, -48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 70, -72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90] - -def coco_postprocess(bbox: np.ndarray, image_size, - net_input_width, net_input_height): - """ - This function is postprocessing for FasterRCNN output. - - Before calling this function, reshape the raw output of FasterRCNN to - following form - numpy.ndarray: - [x, y, width, height, confidence, probability of 80 classes] - shape: (100,) - The postprocessing restore the bounding rectangles of FasterRCNN output - to origin scale and filter with non-maximum suppression. - - :param bbox: a numpy array of the FasterRCNN output - :param image_path: a string of image path - :return: three list for best bound, class and score - """ - w = image_size[0] - h = image_size[1] - scale = min(net_input_width / w, net_input_height / h) - - pad_w = net_input_width - w * scale - pad_h = net_input_height - h * scale - pad_left = pad_w // 2 - pad_top = pad_h // 2 - - # cal predict box on the image src - pbox = bbox - pbox[:, 0] = (bbox[:, 0] - pad_left) / scale - pbox[:, 1] = (bbox[:, 1] - pad_top) / scale - pbox[:, 2] = (bbox[:, 2] - pad_left) / scale - pbox[:, 3] = (bbox[:, 3] - pad_top) / scale - - # make pbboxes value in valid range - pbox[:, 0] = np.maximum(pbox[:, 0], 0) - pbox[:, 1] = np.maximum(pbox[:, 1], 0) - pbox[:, 2] = np.minimum(pbox[:, 2], w) - pbox[:, 3] = np.minimum(pbox[:, 3], h) - return pbox -def file_lines_to_list(path): - # open txt file lines to a list - with open(path) as f: - content = f.readlines() - # remove whitespace characters like `\n` at the end of each line - content = [x.strip() for x in content] - return content - - -def error(msg): - print(msg) - sys.exit(0) - - -def get_predict_list(file_path, gt_classes): - dr_files_list = glob.glob(file_path + '/*.txt') - dr_files_list.sort() - - bounding_boxes = [] - for txt_file in dr_files_list: - file_id = txt_file.split(".txt", 1)[0] - file_id = os.path.basename(os.path.normpath(file_id)) - lines = file_lines_to_list(txt_file) - for line in lines: - try: - sl = line.split() - if len(sl) > 6: - class_name = sl[0] + ' ' + sl[1] - scores, left, top, right, bottom = sl[2:] - else: - class_name, scores, left, top, right, bottom = sl - if float(scores) < 0.05: - continue - except ValueError: - error_msg = "Error: File " + txt_file + " wrong format.\n" - error_msg += " Expected: \n" - error_msg += " Received: " + line - error(error_msg) - - # bbox = left + " " + top + " " + right + " " + bottom - left = float(left) - right = float(right) - top = float(top) - bottom = float(bottom) - bbox = [left, top, right-left, bottom-top] - bounding_boxes.append({"image_id": int(file_id), "bbox": bbox, - "score": float(scores), "category_id": cat_ids[CLASSES.index(class_name)]}) - # sort detection-results by decreasing scores - # bounding_boxes.sort(key=lambda x: float(x['score']), reverse=True) - return bounding_boxes -def coco_evaluation(annotation_json, result_json): - cocoGt = COCO(annotation_json) - cocoDt = cocoGt.loadRes(result_json) - iou_thrs = np.linspace(.5, 0.95, int(np.round((0.95 - .5) / .05)) + 1, endpoint=True) - iou_type = 'bbox' - - cocoEval = COCOeval(cocoGt, cocoDt, iou_type) - cocoEval.params.catIds = cocoGt.get_cat_ids(cat_names=CLASSES) - cocoEval.params.imgIds = cocoGt.get_img_ids() - cocoEval.params.maxDets = [100, 300, 1000] # proposal number for evaluating recalls/mAPs. - cocoEval.params.iouThrs = iou_thrs - - cocoEval.evaluate() - cocoEval.accumulate() - cocoEval.summarize() - - # mapping of cocoEval.stats - coco_metric_names = { - 'mAP': 0, - 'mAP_50': 1, - 'mAP_75': 2, - 'mAP_s': 3, - 'mAP_m': 4, - 'mAP_l': 5, - 'AR@100': 6, - 'AR@300': 7, - 'AR@1000': 8, - 'AR_s@1000': 9, - 'AR_m@1000': 10, - 'AR_l@1000': 11 - } - - metric_items = ['mAP', 'mAP_50', 'mAP_75', 'mAP_s', 'mAP_m', 'mAP_l'] - eval_results = {} - - for metric_item in metric_items: - key = f'bbox_{metric_item}' - val = float( - f'{cocoEval.stats[coco_metric_names[metric_item]]:.3f}' - ) - eval_results[key] = val - ap = cocoEval.stats[:6] - eval_results['bbox_mAP_copypaste'] = ( - f'{ap[0]:.3f} {ap[1]:.3f} {ap[2]:.3f} {ap[3]:.3f} ' - f'{ap[4]:.3f} {ap[5]:.3f}') - - return eval_results - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--bin_data_path", default="./result/dumpOutput_device0") - parser.add_argument("--test_annotation", default="./coco2017_jpg.info") - parser.add_argument("--det_results_path", default="./detection-results") - parser.add_argument("--img_path", default="./val2017/") - parser.add_argument("--net_out_num", default=2) - parser.add_argument("--net_input_width", default=1216) - parser.add_argument("--net_input_height", default=1216) - parser.add_argument("--prob_thres", default=0.05) - parser.add_argument("--ifShowDetObj", action="store_true", help="if input the para means True, neither False.") - parser.add_argument('--npu_txt_path', default="detection-results", - help='the path of the predict result') - parser.add_argument("--json_output_file", default="coco_detection_result") - parser.add_argument("--ground_truth", default="instances_val2017.json") - parser.add_argument("--detection_result", default="coco_detection_result.json") - flags = parser.parse_args() - print(flags.ifShowDetObj, type(flags.ifShowDetObj)) - # generate dict according to annotation file for query resolution - # load width and height of input images - img_size_dict = dict() - with open(flags.test_annotation)as f: - for line in f.readlines(): - temp = line.split(" ") - img_file_path = temp[1] - img_name = temp[1].split("/")[-1].split(".")[0] - img_width = int(temp[2]) - img_height = int(temp[3]) - img_size_dict[img_name] = (img_width, img_height, img_file_path) - - # read bin file for generate predict result - bin_path = flags.bin_data_path - det_results_path = flags.det_results_path - img_path = flags.img_path - os.makedirs(det_results_path, exist_ok=True) - total_img = set([name[:name.rfind('_')] - for name in os.listdir(bin_path) if "bin" in name]) - for bin_file in sorted(total_img): - path_base = os.path.join(bin_path, bin_file) - # load all detected output tensor - res_buff = [] - for num in range(1, flags.net_out_num + 1): - if os.path.exists(path_base + "_" + str(num) + ".bin"): - if num == 1: - buf = np.fromfile(path_base + "_" + str(num) + ".bin", dtype="float32") - buf = np.reshape(buf, [100, 5]) - elif num == 2: - buf = np.fromfile(path_base + "_" + str(num) + ".bin", dtype="int64") - buf = np.reshape(buf, [100, 1]) - res_buff.append(buf) - else: - print("[ERROR] file not exist", path_base + "_" + str(num) + ".bin") - res_tensor = np.concatenate(res_buff, axis=1) - current_img_size = img_size_dict[bin_file] - print("[TEST]---------------------------concat{} imgsize{}".format(len(res_tensor), current_img_size)) - predbox = coco_postprocess(res_tensor, current_img_size, flags.net_input_width, flags.net_input_height) - - if flags.ifShowDetObj == True: - pic = os.path.join(img_path, bin_file +'.jpg') - imgCur = cv2.imread(pic) - - det_results_str = '' - for idx, class_ind in enumerate(predbox[:,5]): - if float(predbox[idx][4]) < float(flags.prob_thres): - continue - # skip negative class index - if class_ind < 0 or class_ind > 80: - continue - - class_name = CLASSES[int(class_ind)] - det_results_str += "{} {} {} {} {} {}\n".format(class_name, str(predbox[idx][4]), predbox[idx][0], - predbox[idx][1], predbox[idx][2], predbox[idx][3]) - if flags.ifShowDetObj == True: - imgCur=cv2.rectangle(imgCur, (int(predbox[idx][0]), int(predbox[idx][1])), - (int(predbox[idx][2]), int(predbox[idx][3])), (0,255,0), 1) - imgCur = cv2.putText(imgCur, class_name+'|'+str(predbox[idx][4]), - (int(predbox[idx][0]), int(predbox[idx][1])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) - # 图像,文字内容, 坐标 ,字体,大小,颜色,字体厚度 - - if flags.ifShowDetObj == True: - print(os.path.join(det_results_path, bin_file +'.jpg')) - cv2.imwrite(os.path.join(det_results_path, bin_file +'.jpg'), imgCur, [int(cv2.IMWRITE_JPEG_QUALITY),70]) - - det_results_file = os.path.join(det_results_path, bin_file + ".txt") - with open(det_results_file, "w") as detf: - detf.write(det_results_str) - print(det_results_str) - - res_bbox = get_predict_list(flags.npu_txt_path, CLASSES) - mmcv.dump(res_bbox, flags.json_output_file + '.json') - result = coco_evaluation(flags.ground_truth, flags.detection_result) - print(result) - with open('./coco_detection_result.txt', 'w') as f: - for key, value in result.items(): +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import numpy as np +import cv2 +import glob +import sys +import argparse +import mmcv +from pycocotools.coco import COCO +from pycocotools.cocoeval import COCOeval + +CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', + 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', + 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', + 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', + 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', + 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', + 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', + 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', + 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', + 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', + 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', + 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] + +cat_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, +24, 25, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, +48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 70, +72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90] + +def coco_postprocess(bbox: np.ndarray, image_size, + net_input_width, net_input_height): + """ + This function is postprocessing for FasterRCNN output. + + Before calling this function, reshape the raw output of FasterRCNN to + following form + numpy.ndarray: + [x, y, width, height, confidence, probability of 80 classes] + shape: (100,) + The postprocessing restore the bounding rectangles of FasterRCNN output + to origin scale and filter with non-maximum suppression. + + :param bbox: a numpy array of the FasterRCNN output + :param image_path: a string of image path + :return: three list for best bound, class and score + """ + w = image_size[0] + h = image_size[1] + scale = min(net_input_width / w, net_input_height / h) + + pad_w = net_input_width - w * scale + pad_h = net_input_height - h * scale + pad_left = pad_w // 2 + pad_top = pad_h // 2 + + # cal predict box on the image src + pbox = bbox + pbox[:, 0] = (bbox[:, 0] - pad_left) / scale + pbox[:, 1] = (bbox[:, 1] - pad_top) / scale + pbox[:, 2] = (bbox[:, 2] - pad_left) / scale + pbox[:, 3] = (bbox[:, 3] - pad_top) / scale + + # make pbboxes value in valid range + pbox[:, 0] = np.maximum(pbox[:, 0], 0) + pbox[:, 1] = np.maximum(pbox[:, 1], 0) + pbox[:, 2] = np.minimum(pbox[:, 2], w) + pbox[:, 3] = np.minimum(pbox[:, 3], h) + return pbox +def file_lines_to_list(path): + # open txt file lines to a list + with open(path) as f: + content = f.readlines() + # remove whitespace characters like `\n` at the end of each line + content = [x.strip() for x in content] + return content + + +def error(msg): + print(msg) + sys.exit(0) + + +def get_predict_list(file_path, gt_classes): + dr_files_list = glob.glob(file_path + '/*.txt') + dr_files_list.sort() + + bounding_boxes = [] + for txt_file in dr_files_list: + file_id = txt_file.split(".txt", 1)[0] + file_id = os.path.basename(os.path.normpath(file_id)) + lines = file_lines_to_list(txt_file) + for line in lines: + try: + sl = line.split() + if len(sl) > 6: + class_name = sl[0] + ' ' + sl[1] + scores, left, top, right, bottom = sl[2:] + else: + class_name, scores, left, top, right, bottom = sl + if float(scores) < 0.05: + continue + except ValueError: + error_msg = "Error: File " + txt_file + " wrong format.\n" + error_msg += " Expected: \n" + error_msg += " Received: " + line + error(error_msg) + + # bbox = left + " " + top + " " + right + " " + bottom + left = float(left) + right = float(right) + top = float(top) + bottom = float(bottom) + bbox = [left, top, right-left, bottom-top] + bounding_boxes.append({"image_id": int(file_id), "bbox": bbox, + "score": float(scores), "category_id": cat_ids[CLASSES.index(class_name)]}) + # sort detection-results by decreasing scores + # bounding_boxes.sort(key=lambda x: float(x['score']), reverse=True) + return bounding_boxes +def coco_evaluation(annotation_json, result_json): + cocoGt = COCO(annotation_json) + cocoDt = cocoGt.loadRes(result_json) + iou_thrs = np.linspace(.5, 0.95, int(np.round((0.95 - .5) / .05)) + 1, endpoint=True) + iou_type = 'bbox' + + cocoEval = COCOeval(cocoGt, cocoDt, iou_type) + cocoEval.params.catIds = cocoGt.get_cat_ids(cat_names=CLASSES) + cocoEval.params.imgIds = cocoGt.get_img_ids() + cocoEval.params.maxDets = [100, 300, 1000] # proposal number for evaluating recalls/mAPs. + cocoEval.params.iouThrs = iou_thrs + + cocoEval.evaluate() + cocoEval.accumulate() + cocoEval.summarize() + + # mapping of cocoEval.stats + coco_metric_names = { + 'mAP': 0, + 'mAP_50': 1, + 'mAP_75': 2, + 'mAP_s': 3, + 'mAP_m': 4, + 'mAP_l': 5, + 'AR@100': 6, + 'AR@300': 7, + 'AR@1000': 8, + 'AR_s@1000': 9, + 'AR_m@1000': 10, + 'AR_l@1000': 11 + } + + metric_items = ['mAP', 'mAP_50', 'mAP_75', 'mAP_s', 'mAP_m', 'mAP_l'] + eval_results = {} + + for metric_item in metric_items: + key = f'bbox_{metric_item}' + val = float( + f'{cocoEval.stats[coco_metric_names[metric_item]]:.3f}' + ) + eval_results[key] = val + ap = cocoEval.stats[:6] + eval_results['bbox_mAP_copypaste'] = ( + f'{ap[0]:.3f} {ap[1]:.3f} {ap[2]:.3f} {ap[3]:.3f} ' + f'{ap[4]:.3f} {ap[5]:.3f}') + + return eval_results + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("--bin_data_path", default="./result/dumpOutput_device0") + parser.add_argument("--test_annotation", default="./coco2017_jpg.info") + parser.add_argument("--det_results_path", default="./detection-results") + parser.add_argument("--img_path", default="./val2017/") + parser.add_argument("--net_out_num", default=2) + parser.add_argument("--net_input_width", default=1216) + parser.add_argument("--net_input_height", default=1216) + parser.add_argument("--prob_thres", default=0.05) + parser.add_argument("--ifShowDetObj", action="store_true", help="if input the para means True, neither False.") + parser.add_argument('--npu_txt_path', default="detection-results", + help='the path of the predict result') + parser.add_argument("--json_output_file", default="coco_detection_result") + parser.add_argument("--ground_truth", default="instances_val2017.json") + parser.add_argument("--detection_result", default="coco_detection_result.json") + flags = parser.parse_args() + print(flags.ifShowDetObj, type(flags.ifShowDetObj)) + # generate dict according to annotation file for query resolution + # load width and height of input images + img_size_dict = dict() + with open(flags.test_annotation)as f: + for line in f.readlines(): + temp = line.split(" ") + img_file_path = temp[1] + img_name = temp[1].split("/")[-1].split(".")[0] + img_width = int(temp[2]) + img_height = int(temp[3]) + img_size_dict[img_name] = (img_width, img_height, img_file_path) + + # read bin file for generate predict result + bin_path = flags.bin_data_path + det_results_path = flags.det_results_path + img_path = flags.img_path + os.makedirs(det_results_path, exist_ok=True) + total_img = set([name[:name.rfind('_')] + for name in os.listdir(bin_path) if "bin" in name]) + for bin_file in sorted(total_img): + path_base = os.path.join(bin_path, bin_file) + # load all detected output tensor + res_buff = [] + for num in range(1, flags.net_out_num + 1): + if os.path.exists(path_base + "_" + str(num) + ".bin"): + if num == 1: + buf = np.fromfile(path_base + "_" + str(num) + ".bin", dtype="float32") + buf = np.reshape(buf, [100, 5]) + elif num == 2: + buf = np.fromfile(path_base + "_" + str(num) + ".bin", dtype="int64") + buf = np.reshape(buf, [100, 1]) + res_buff.append(buf) + else: + print("[ERROR] file not exist", path_base + "_" + str(num) + ".bin") + res_tensor = np.concatenate(res_buff, axis=1) + current_img_size = img_size_dict[bin_file] + print("[TEST]---------------------------concat{} imgsize{}".format(len(res_tensor), current_img_size)) + predbox = coco_postprocess(res_tensor, current_img_size, flags.net_input_width, flags.net_input_height) + + if flags.ifShowDetObj == True: + pic = os.path.join(img_path, bin_file +'.jpg') + imgCur = cv2.imread(pic) + + det_results_str = '' + for idx, class_ind in enumerate(predbox[:,5]): + if float(predbox[idx][4]) < float(flags.prob_thres): + continue + # skip negative class index + if class_ind < 0 or class_ind > 80: + continue + + class_name = CLASSES[int(class_ind)] + det_results_str += "{} {} {} {} {} {}\n".format(class_name, str(predbox[idx][4]), predbox[idx][0], + predbox[idx][1], predbox[idx][2], predbox[idx][3]) + if flags.ifShowDetObj == True: + imgCur=cv2.rectangle(imgCur, (int(predbox[idx][0]), int(predbox[idx][1])), + (int(predbox[idx][2]), int(predbox[idx][3])), (0,255,0), 1) + imgCur = cv2.putText(imgCur, class_name+'|'+str(predbox[idx][4]), + (int(predbox[idx][0]), int(predbox[idx][1])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) + # 图像,文字内容, 坐标 ,字体,大小,颜色,字体厚度 + + if flags.ifShowDetObj == True: + print(os.path.join(det_results_path, bin_file +'.jpg')) + cv2.imwrite(os.path.join(det_results_path, bin_file +'.jpg'), imgCur, [int(cv2.IMWRITE_JPEG_QUALITY),70]) + + det_results_file = os.path.join(det_results_path, bin_file + ".txt") + with open(det_results_file, "w") as detf: + detf.write(det_results_str) + print(det_results_str) + + res_bbox = get_predict_list(flags.npu_txt_path, CLASSES) + mmcv.dump(res_bbox, flags.json_output_file + '.json') + result = coco_evaluation(flags.ground_truth, flags.detection_result) + print(result) + with open('./coco_detection_result.txt', 'w') as f: + for key, value in result.items(): f.write(key + ': ' + str(value) + '\n') \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/mmdetection_coco_preprocess.py b/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/mmdetection_coco_preprocess.py index c6f3b7429e..f7fc5568a9 100644 --- a/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/mmdetection_coco_preprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/mmdetection_coco_preprocess.py @@ -1,68 +1,68 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 numpy as np -import os -import cv2 -import argparse -import mmcv -import torch - -dataset_config = { - 'resize': (1216, 1216), - 'mean': [123.675, 116.28, 103.53], - 'std': [58.395, 57.12, 57.375], -} - -tensor_height = 1216 -tensor_width = 1216 - -def coco_preprocess(input_image, output_bin_path): - #define the output file name - img_name = input_image.split('/')[-1] - bin_name = img_name.split('.')[0] + ".bin" - bin_fl = os.path.join(output_bin_path, bin_name) - - one_img = mmcv.imread(os.path.join(input_image), backend='cv2') - one_img = mmcv.imrescale(one_img, (tensor_height, tensor_width)) - # calculate padding - h = one_img.shape[0] - w = one_img.shape[1] - pad_left = (tensor_width - w) // 2 - pad_top = (tensor_height - h) // 2 - pad_right = tensor_width - pad_left - w - pad_bottom = tensor_height - pad_top - h - - mean = np.array(dataset_config['mean'], dtype=np.float32) - std = np.array(dataset_config['std'], dtype=np.float32) - one_img = mmcv.imnormalize(one_img, mean, std) - one_img = mmcv.impad(one_img, padding=(pad_left, pad_top, pad_right, pad_bottom), pad_val=0) - one_img = one_img.transpose(2, 0, 1) - one_img.tofile(bin_fl) - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='preprocess of NAS-FPN pytorch model') - parser.add_argument("--image_folder_path", default="./coco2017/", help='image of dataset') - parser.add_argument("--bin_folder_path", default="./coco2017_bin/", help='Preprocessed image buffer') - flags = parser.parse_args() - - if not os.path.exists(flags.bin_folder_path): - os.makedirs(flags.bin_folder_path) - images = os.listdir(flags.image_folder_path) - for image_name in images: - if not (image_name.endswith(".jpeg") or image_name.endswith(".JPEG") or image_name.endswith(".jpg")): - continue - print("start to process image {}....".format(image_name)) - path_image = os.path.join(flags.image_folder_path, image_name) - coco_preprocess(path_image, flags.bin_folder_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 numpy as np +import os +import cv2 +import argparse +import mmcv +import torch + +dataset_config = { + 'resize': (1216, 1216), + 'mean': [123.675, 116.28, 103.53], + 'std': [58.395, 57.12, 57.375], +} + +tensor_height = 1216 +tensor_width = 1216 + +def coco_preprocess(input_image, output_bin_path): + #define the output file name + img_name = input_image.split('/')[-1] + bin_name = img_name.split('.')[0] + ".bin" + bin_fl = os.path.join(output_bin_path, bin_name) + + one_img = mmcv.imread(os.path.join(input_image), backend='cv2') + one_img = mmcv.imrescale(one_img, (tensor_height, tensor_width)) + # calculate padding + h = one_img.shape[0] + w = one_img.shape[1] + pad_left = (tensor_width - w) // 2 + pad_top = (tensor_height - h) // 2 + pad_right = tensor_width - pad_left - w + pad_bottom = tensor_height - pad_top - h + + mean = np.array(dataset_config['mean'], dtype=np.float32) + std = np.array(dataset_config['std'], dtype=np.float32) + one_img = mmcv.imnormalize(one_img, mean, std) + one_img = mmcv.impad(one_img, padding=(pad_left, pad_top, pad_right, pad_bottom), pad_val=0) + one_img = one_img.transpose(2, 0, 1) + one_img.tofile(bin_fl) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='preprocess of NAS-FPN pytorch model') + parser.add_argument("--image_folder_path", default="./coco2017/", help='image of dataset') + parser.add_argument("--bin_folder_path", default="./coco2017_bin/", help='Preprocessed image buffer') + flags = parser.parse_args() + + if not os.path.exists(flags.bin_folder_path): + os.makedirs(flags.bin_folder_path) + images = os.listdir(flags.image_folder_path) + for image_name in images: + if not (image_name.endswith(".jpeg") or image_name.endswith(".JPEG") or image_name.endswith(".jpg")): + continue + print("start to process image {}....".format(image_name)) + path_image = os.path.join(flags.image_folder_path, image_name) + coco_preprocess(path_image, flags.bin_folder_path) diff --git a/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/requirements.txt b/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/requirements.txt index a9b2aff748..bbcf70abd1 100644 --- a/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/requirements.txt +++ b/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101/requirements.txt @@ -1,10 +1,10 @@ -torch==1.7.0 -torchvision==0.8.0 -onnx==1.8.0 -numpy==1.20.0 -mmdet==2.8.0 -mmcv-full==1.2.4 -opencv-python==4.4.0.46 -mmpycocotools==12.0.3 -onnxruntime==1.9.0 - +torch==1.7.0 +torchvision==0.8.0 +onnx==1.8.0 +numpy==1.20.0 +mmdet==2.8.0 +mmcv-full==1.2.4 +opencv-python==4.4.0.46 +mmpycocotools==12.0.3 +onnxruntime==1.9.0 + diff --git a/ACL_PyTorch/contrib/cv/detection/CenterFace/README.md b/ACL_PyTorch/contrib/cv/detection/CenterFace/README.md index db88ee778c..7d456ee6fb 100644 --- a/ACL_PyTorch/contrib/cv/detection/CenterFace/README.md +++ b/ACL_PyTorch/contrib/cv/detection/CenterFace/README.md @@ -1,300 +1,300 @@ -# CenterFace Onnx模型端到端推理指导 - -- 1 模型概述 - - [1.1 论文地址](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#11-论文地址) - - [1.2 代码地址](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#12-代码地址) -- 2 环境说明 - - [2.1 深度学习框架](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#21-深度学习框架) - - [2.2 python第三方库](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#22-python第三方库) -- 3 模型转换 - - [3.1 pth转onnx模型](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#31-pth转onnx模型) - - [3.2 onnx转om模型](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#32-onnx转om模型) -- 4 数据集预处理 - - [4.1 数据集获取](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#41-数据集获取) - - [4.2 数据集预处理](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#42-数据集预处理) - - [4.3 生成数据集信息文件](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#43-生成数据集信息文件) -- 5 离线推理 - - [5.1 benchmark工具概述](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#51-benchmark工具概述) - - [5.2 离线推理](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#52-离线推理) -- 6 精度对比 - - [6.1 离线推理精度统计](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#61-离线推理精度统计) - - [6.2 开源精度](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#62-开源精度) - - [6.3 精度对比](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#63-精度对比) -- 7 性能对比 - - [7.1 npu性能数据](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#71-npu性能数据) - - [7.2 T4性能数据](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#72-T4性能数据) - - [7.3 性能对比](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#73-性能对比) -- 8 710增加文件介绍 - -## 1 模型概述 - -- **论文地址** -- **代码地址** - -### 1.1 论文地址 - -[CenterFace论文](https://arxiv.org/abs/1911.03599) - -### 1.2 代码地址 - -[CenterFace代码](https://github.com/chenjun2hao/CenterFace.pytorch) - -## 2 环境说明 - -- **深度学习框架** -- **python第三方库** - -### 2.1 深度学习框架 - -``` -python3.7.5 -CANN 5.0.1 - -pytorch >= 1.5.0 -torchvision >= 0.6.0 -onnx >= 1.7.0 -``` - -### 2.2 python第三方库 - -``` -numpy == 1.20.3 -Pillow == 8.2.0 -opencv-python == 4.5.2.54 -``` - -## 3 模型转换 - -- **pth转onnx模型** -- **onnx转om模型** - -### 3.1 pth转onnx模型 - -1.下载pth权重文件 -权重文件从百度网盘上获取:https://pan.baidu.com/s/1sU3pRBTFebbsMDac-1HsQA 密码:etdi - -2.使用pth2onnx.py进行onnx的转换 - -``` -mv ./CenterFace/center-face/src/pth2onnx.py ./CenterFace/center-face/src/lib -cd ./CenterFace/center-face/src/lib -python3 pth2onnx.py -``` - -### 3.2 onnx转om模型 - -1.设置环境变量 - -``` -source env.sh -``` - -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.1 开发辅助工具指南 (推理) 01 - -``` -cd ./CenterFace/center-face/src/test -bash onnxToom.sh -``` - -## 4 数据集预处理 - -- **数据集获取** -- **数据集预处理** -- **生成数据集信息文件** - -### 4.1 数据集获取 - -拉取代码仓库 (因为使用了开源代码模块,所以需要git clone一下) - -```shell -git clone https://gitee.com/Levi990223/center-face.git -``` - -整理代码结构 - -```shell -mv -r test center-face/src -mv benchmark.x86_64 centerface_pth_preprocess.py centerface_pth_postprocess.py convert.py env.sh CenterFace.onnx pth2onnx.py get_info.py model_best.pth move.sh npu_set_env.sh README.md ./center-face/src -``` - -下载WIDER_FACE数据集,将图片上在这个目录下: - -下载地址:https://www.graviti.cn/open-datasets/WIDER_FACE - -``` -$CenterFace_ROOT/center-face/data/{eval_dataset} -``` - -### 4.2 数据集预处理 - -1.预处理脚本centerface_pth_preprocess.py - -2.执行预处理脚本,生成数据集预处理后的bin文件 - -``` -cd ./CenterFace/center-face/src/test -bash start.sh -``` - -### 4.3 生成数据集信息文件 - -1.生成数据集信息文件脚本get_info.py - -2.执行生成数据集信息脚本,生成数据集信息文件 - -``` -cd ./CenterFace/center-face/src/test -bash to_info.sh -``` - -to_info.sh里,第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 - -## 5 离线推理 - -- **benchmark工具概述** -- **离线推理** - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN 5.0.1 推理benchmark工具用户指南 01 - -### 5.2 离线推理 - -1.设置环境变量 - -``` -source env.sh -source npu_set_env.sh -``` - -2.执行离线推理 - -执行前需要将benchmark.x86_64移动到执行目录下 - -(注:执行目录是/center-face/src) - -然后运行如下命令: - -``` -cd ./CenterFace/center-face/src/test -bash infer.sh -``` - -输出结果默认保存在当前目录result/dumpOutput_device{0},每个输入对应的输出对应四个_x.bin文件。 - -3.处理目录result/dumpOutput_device{0}下的bin文件 - -将该目录下的文件分类别存放,以便于后处理 - -``` -cd ./CenterFace/center-face/src/ -python3 convert.py ./result/dumpOutput_device1/ ./result/result -``` - -第一个参数是benchmark得到的bin文件目录,第二个参数是保存路径 - -## 6 精度对比 - -- **离线推理精度** -- **开源精度** -- **精度对比** - -### 6.1 离线推理精度统计 - -1.后处理 - -注:这里需要使用wide_face_val.mat文件,在center-face/evaluate/ground_truth/可以找到,然后将其移动到center-face/src目录下,然后执行下面命令 - -``` -cd ./CenterFace/center-face/src -python3 centerface_pth_postprocess.py -``` - -2.进行Ascend310上精度评估 - -``` -cd ./CenterFace/center-face/evaluate -python3 evaluation.py -``` - -### 6.2 开源精度 - -[CenterFace官网精度]([chenjun2hao/CenterFace.pytorch: unofficial version of centerface, which achieves the best balance between speed and accuracy at face detection (github.com)](https://github.com/chenjun2hao/CenterFace.pytorch)) - -``` -Easy Val AP: 0.9257383419951156 -Medium Val AP: 0.9131308732465665 -Hard Val AP: 0.7717305552550734 -``` - -### 6.3 精度对比 - -``` -Easy Val AP: 0.9190736484158941 -Medium Val AP: 0.9067769085346155 -Hard Val AP: 0.7425807072008017 -``` - -### 6.3 精度对比 - -实际上官网的hard精度达不到77%,最高74%左右,所以对比下来精度是达标的。 - -## 7 性能对比 - -- **npu性能数据** -- **T4性能数据** -- **性能对比** - -### 7.1 npu性能数据 - -1.benchmark工具在整个数据集上推理获得性能数据 -batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: - -``` -[e2e] throughputRate: 33.1307, latency: 97372 -[data read] throughputRate: 36.336, moduleLatency: 27.5209 -[preprocess] throughputRate: 35.6065, moduleLatency: 28.0847 -[infer] throughputRate: 33.4556, Interface throughputRate: 91.86, moduleLatency: 29.2697 -[post] throughputRate: 33.4544, moduleLatency: 29.8915 -``` - -Interface throughputRate: 91.86,91.86x4=367.44既是batch1 310单卡吞吐率 -batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: - -``` -[e2e] throughputRate: 31.7581, latency: 101580 -[data read] throughputRate: 35.0206, moduleLatency: 28.5547 -[preprocess] throughputRate: 33.9534, moduleLatency: 29.4521 -[infer] throughputRate: 32.022, Interface throughputRate: 80.3537, moduleLatency: 30.4381 -[post] throughputRate: 2.00424, moduleLatency: 498.943 - -``` - -Interface throughputRate: 80.3537,80.3537x4=321.4148既是batch16 310单卡吞吐率 - -### 7.2 T4性能数据 - -``` -[W] [TRT] TensorRT was linked against cuBLAS/cuBLAS LT 11.2.0 but loaded cuBLAS/cuBLAS LT 11.1.0 -[W] [TRT] TensorRT was linked against cuBLAS/cuBLAS LT 11.2.0 but loaded cuBLAS/cuBLAS LT 11.1.0 -[W] [TRT] TensorRT was linked against cuBLAS/cuBLAS LT 11.2.0 but loaded cuBLAS/cuBLAS LT 11.1.0 -t4 bs1 fps:337.544 -[W] [TRT] TensorRT was linked against cuBLAS/cuBLAS LT 11.2.0 but loaded cuBLAS/cuBLAS LT 11.1.0 -[W] [TRT] TensorRT was linked against cuBLAS/cuBLAS LT 11.2.0 but loaded cuBLAS/cuBLAS LT 11.1.0 -[W] [TRT] TensorRT was linked against cuBLAS/cuBLAS LT 11.2.0 but loaded cuBLAS/cuBLAS LT 11.1.0 -t4 bs16 fps:359.999 -``` - -batch1 t4单卡吞吐率:337.544 - -batch16 t4单卡吞吐率:359.999 - -### 7.3 性能对比 - -batch1:91.86x4=367.44 > 337.544 -batch16:80.3537x4=321.4148 < 359.999 - -## 8 710增加文件介绍 - -1.aipp_centerface.aippconfig ONNX模型转OM模型时所配置aipp -2.calibration_bin.py 量化模型时输入真实数据的组件脚本 +# CenterFace Onnx模型端到端推理指导 + +- 1 模型概述 + - [1.1 论文地址](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#11-论文地址) + - [1.2 代码地址](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#12-代码地址) +- 2 环境说明 + - [2.1 深度学习框架](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#21-深度学习框架) + - [2.2 python第三方库](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#22-python第三方库) +- 3 模型转换 + - [3.1 pth转onnx模型](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#31-pth转onnx模型) + - [3.2 onnx转om模型](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#32-onnx转om模型) +- 4 数据集预处理 + - [4.1 数据集获取](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#41-数据集获取) + - [4.2 数据集预处理](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#42-数据集预处理) + - [4.3 生成数据集信息文件](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#43-生成数据集信息文件) +- 5 离线推理 + - [5.1 benchmark工具概述](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#51-benchmark工具概述) + - [5.2 离线推理](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#52-离线推理) +- 6 精度对比 + - [6.1 离线推理精度统计](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#61-离线推理精度统计) + - [6.2 开源精度](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#62-开源精度) + - [6.3 精度对比](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#63-精度对比) +- 7 性能对比 + - [7.1 npu性能数据](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#71-npu性能数据) + - [7.2 T4性能数据](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#72-T4性能数据) + - [7.3 性能对比](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#73-性能对比) +- 8 710增加文件介绍 + +## 1 模型概述 + +- **论文地址** +- **代码地址** + +### 1.1 论文地址 + +[CenterFace论文](https://arxiv.org/abs/1911.03599) + +### 1.2 代码地址 + +[CenterFace代码](https://github.com/chenjun2hao/CenterFace.pytorch) + +## 2 环境说明 + +- **深度学习框架** +- **python第三方库** + +### 2.1 深度学习框架 + +``` +python3.7.5 +CANN 5.0.1 + +pytorch >= 1.5.0 +torchvision >= 0.6.0 +onnx >= 1.7.0 +``` + +### 2.2 python第三方库 + +``` +numpy == 1.20.3 +Pillow == 8.2.0 +opencv-python == 4.5.2.54 +``` + +## 3 模型转换 + +- **pth转onnx模型** +- **onnx转om模型** + +### 3.1 pth转onnx模型 + +1.下载pth权重文件 +权重文件从百度网盘上获取:https://pan.baidu.com/s/1sU3pRBTFebbsMDac-1HsQA 密码:etdi + +2.使用pth2onnx.py进行onnx的转换 + +``` +mv ./CenterFace/center-face/src/pth2onnx.py ./CenterFace/center-face/src/lib +cd ./CenterFace/center-face/src/lib +python3 pth2onnx.py +``` + +### 3.2 onnx转om模型 + +1.设置环境变量 + +``` +source env.sh +``` + +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.1 开发辅助工具指南 (推理) 01 + +``` +cd ./CenterFace/center-face/src/test +bash onnxToom.sh +``` + +## 4 数据集预处理 + +- **数据集获取** +- **数据集预处理** +- **生成数据集信息文件** + +### 4.1 数据集获取 + +拉取代码仓库 (因为使用了开源代码模块,所以需要git clone一下) + +```shell +git clone https://gitee.com/Levi990223/center-face.git +``` + +整理代码结构 + +```shell +mv -r test center-face/src +mv benchmark.x86_64 centerface_pth_preprocess.py centerface_pth_postprocess.py convert.py env.sh CenterFace.onnx pth2onnx.py get_info.py model_best.pth move.sh npu_set_env.sh README.md ./center-face/src +``` + +下载WIDER_FACE数据集,将图片上在这个目录下: + +下载地址:https://www.graviti.cn/open-datasets/WIDER_FACE + +``` +$CenterFace_ROOT/center-face/data/{eval_dataset} +``` + +### 4.2 数据集预处理 + +1.预处理脚本centerface_pth_preprocess.py + +2.执行预处理脚本,生成数据集预处理后的bin文件 + +``` +cd ./CenterFace/center-face/src/test +bash start.sh +``` + +### 4.3 生成数据集信息文件 + +1.生成数据集信息文件脚本get_info.py + +2.执行生成数据集信息脚本,生成数据集信息文件 + +``` +cd ./CenterFace/center-face/src/test +bash to_info.sh +``` + +to_info.sh里,第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 + +## 5 离线推理 + +- **benchmark工具概述** +- **离线推理** + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN 5.0.1 推理benchmark工具用户指南 01 + +### 5.2 离线推理 + +1.设置环境变量 + +``` +source env.sh +source npu_set_env.sh +``` + +2.执行离线推理 + +执行前需要将benchmark.x86_64移动到执行目录下 + +(注:执行目录是/center-face/src) + +然后运行如下命令: + +``` +cd ./CenterFace/center-face/src/test +bash infer.sh +``` + +输出结果默认保存在当前目录result/dumpOutput_device{0},每个输入对应的输出对应四个_x.bin文件。 + +3.处理目录result/dumpOutput_device{0}下的bin文件 + +将该目录下的文件分类别存放,以便于后处理 + +``` +cd ./CenterFace/center-face/src/ +python3 convert.py ./result/dumpOutput_device1/ ./result/result +``` + +第一个参数是benchmark得到的bin文件目录,第二个参数是保存路径 + +## 6 精度对比 + +- **离线推理精度** +- **开源精度** +- **精度对比** + +### 6.1 离线推理精度统计 + +1.后处理 + +注:这里需要使用wide_face_val.mat文件,在center-face/evaluate/ground_truth/可以找到,然后将其移动到center-face/src目录下,然后执行下面命令 + +``` +cd ./CenterFace/center-face/src +python3 centerface_pth_postprocess.py +``` + +2.进行Ascend310上精度评估 + +``` +cd ./CenterFace/center-face/evaluate +python3 evaluation.py +``` + +### 6.2 开源精度 + +[CenterFace官网精度]([chenjun2hao/CenterFace.pytorch: unofficial version of centerface, which achieves the best balance between speed and accuracy at face detection (github.com)](https://github.com/chenjun2hao/CenterFace.pytorch)) + +``` +Easy Val AP: 0.9257383419951156 +Medium Val AP: 0.9131308732465665 +Hard Val AP: 0.7717305552550734 +``` + +### 6.3 精度对比 + +``` +Easy Val AP: 0.9190736484158941 +Medium Val AP: 0.9067769085346155 +Hard Val AP: 0.7425807072008017 +``` + +### 6.3 精度对比 + +实际上官网的hard精度达不到77%,最高74%左右,所以对比下来精度是达标的。 + +## 7 性能对比 + +- **npu性能数据** +- **T4性能数据** +- **性能对比** + +### 7.1 npu性能数据 + +1.benchmark工具在整个数据集上推理获得性能数据 +batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: + +``` +[e2e] throughputRate: 33.1307, latency: 97372 +[data read] throughputRate: 36.336, moduleLatency: 27.5209 +[preprocess] throughputRate: 35.6065, moduleLatency: 28.0847 +[infer] throughputRate: 33.4556, Interface throughputRate: 91.86, moduleLatency: 29.2697 +[post] throughputRate: 33.4544, moduleLatency: 29.8915 +``` + +Interface throughputRate: 91.86,91.86x4=367.44既是batch1 310单卡吞吐率 +batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: + +``` +[e2e] throughputRate: 31.7581, latency: 101580 +[data read] throughputRate: 35.0206, moduleLatency: 28.5547 +[preprocess] throughputRate: 33.9534, moduleLatency: 29.4521 +[infer] throughputRate: 32.022, Interface throughputRate: 80.3537, moduleLatency: 30.4381 +[post] throughputRate: 2.00424, moduleLatency: 498.943 + +``` + +Interface throughputRate: 80.3537,80.3537x4=321.4148既是batch16 310单卡吞吐率 + +### 7.2 T4性能数据 + +``` +[W] [TRT] TensorRT was linked against cuBLAS/cuBLAS LT 11.2.0 but loaded cuBLAS/cuBLAS LT 11.1.0 +[W] [TRT] TensorRT was linked against cuBLAS/cuBLAS LT 11.2.0 but loaded cuBLAS/cuBLAS LT 11.1.0 +[W] [TRT] TensorRT was linked against cuBLAS/cuBLAS LT 11.2.0 but loaded cuBLAS/cuBLAS LT 11.1.0 +t4 bs1 fps:337.544 +[W] [TRT] TensorRT was linked against cuBLAS/cuBLAS LT 11.2.0 but loaded cuBLAS/cuBLAS LT 11.1.0 +[W] [TRT] TensorRT was linked against cuBLAS/cuBLAS LT 11.2.0 but loaded cuBLAS/cuBLAS LT 11.1.0 +[W] [TRT] TensorRT was linked against cuBLAS/cuBLAS LT 11.2.0 but loaded cuBLAS/cuBLAS LT 11.1.0 +t4 bs16 fps:359.999 +``` + +batch1 t4单卡吞吐率:337.544 + +batch16 t4单卡吞吐率:359.999 + +### 7.3 性能对比 + +batch1:91.86x4=367.44 > 337.544 +batch16:80.3537x4=321.4148 < 359.999 + +## 8 710增加文件介绍 + +1.aipp_centerface.aippconfig ONNX模型转OM模型时所配置aipp +2.calibration_bin.py 量化模型时输入真实数据的组件脚本 diff --git a/ACL_PyTorch/contrib/cv/detection/CenterFace/aipp_centerface.aippconfig b/ACL_PyTorch/contrib/cv/detection/CenterFace/aipp_centerface.aippconfig index 3d0b228c6b..3d5d1a7120 100644 --- a/ACL_PyTorch/contrib/cv/detection/CenterFace/aipp_centerface.aippconfig +++ b/ACL_PyTorch/contrib/cv/detection/CenterFace/aipp_centerface.aippconfig @@ -1,15 +1,15 @@ -aipp_op{ - aipp_mode:static - input_format : RGB888_U8 - - src_image_size_w : 800 - src_image_size_h : 800 - crop:false - - min_chn_0 : 104 - min_chn_1 : 114 - min_chn_2 : 120 - var_reci_chn_0: 0.0135864 - var_reci_chn_1: 0.0143080 - var_reci_chn_2: 0.0141014 -} +aipp_op{ + aipp_mode:static + input_format : RGB888_U8 + + src_image_size_w : 800 + src_image_size_h : 800 + crop:false + + min_chn_0 : 104 + min_chn_1 : 114 + min_chn_2 : 120 + var_reci_chn_0: 0.0135864 + var_reci_chn_1: 0.0143080 + var_reci_chn_2: 0.0141014 +} diff --git a/ACL_PyTorch/contrib/cv/detection/CenterFace/calibration_bin.py b/ACL_PyTorch/contrib/cv/detection/CenterFace/calibration_bin.py index af13f3593f..c72d0c6fbc 100644 --- a/ACL_PyTorch/contrib/cv/detection/CenterFace/calibration_bin.py +++ b/ACL_PyTorch/contrib/cv/detection/CenterFace/calibration_bin.py @@ -1,56 +1,56 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import numpy as np -import multiprocessing - -max_bin=10 -def preprocess(src_path, save_path, batch_size): - files = os.listdir(src_path) - - output_data = [0] - for i, file in enumerate(files): - input_data = np.fromfile(os.path.join(src_path, file), dtype=np.float32) - input_data = input_data.reshape(1, 3, 800, 800) - - if i % batch_size == 0: - output_data = input_data - else: - output_data = np.concatenate((output_data, input_data), axis=0) - - # only save 10 bin files - loop_id = (i + 1) // batch_size - if loop_id > max_bin: - break - - if (i + 1) % batch_size == 0: - output_data.tofile("{}/img_{}_bs{}.bin".format(save_path, loop_id, batch_size)) - output_data = [0] - - -if __name__ == '__main__': - if len(sys.argv) < 4: - raise Exception("usage: python3 xxx.py [src_path] [save_path] [batch_size]") - src_path = sys.argv[1] - save_path = sys.argv[2] - batch_size = int(sys.argv[3]) - src_path = os.path.realpath(src_path) - save_path = os.path.realpath(save_path) - - if not os.path.isdir(save_path): - os.makedirs(os.path.realpath(save_path)) - preprocess(src_path, save_path, batch_size) - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import numpy as np +import multiprocessing + +max_bin=10 +def preprocess(src_path, save_path, batch_size): + files = os.listdir(src_path) + + output_data = [0] + for i, file in enumerate(files): + input_data = np.fromfile(os.path.join(src_path, file), dtype=np.float32) + input_data = input_data.reshape(1, 3, 800, 800) + + if i % batch_size == 0: + output_data = input_data + else: + output_data = np.concatenate((output_data, input_data), axis=0) + + # only save 10 bin files + loop_id = (i + 1) // batch_size + if loop_id > max_bin: + break + + if (i + 1) % batch_size == 0: + output_data.tofile("{}/img_{}_bs{}.bin".format(save_path, loop_id, batch_size)) + output_data = [0] + + +if __name__ == '__main__': + if len(sys.argv) < 4: + raise Exception("usage: python3 xxx.py [src_path] [save_path] [batch_size]") + src_path = sys.argv[1] + save_path = sys.argv[2] + batch_size = int(sys.argv[3]) + src_path = os.path.realpath(src_path) + save_path = os.path.realpath(save_path) + + if not os.path.isdir(save_path): + os.makedirs(os.path.realpath(save_path)) + preprocess(src_path, save_path, batch_size) + diff --git a/ACL_PyTorch/contrib/cv/detection/CenterFace/centerface_pth_postprocess.py b/ACL_PyTorch/contrib/cv/detection/CenterFace/centerface_pth_postprocess.py index e598550ebb..9e825c29e8 100644 --- a/ACL_PyTorch/contrib/cv/detection/CenterFace/centerface_pth_postprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/CenterFace/centerface_pth_postprocess.py @@ -1,153 +1,153 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -# -*- coding:utf-8 -*- -from __future__ import absolute_import -from __future__ import division - -import numpy as np -import torch -import os -import sys -import cv2 -import scipy.io as sio - -from lib.models import decode as dc -from lib.models.utils import _gather_feat, _tranpose_and_gather_feat -from lib.utils import image as img -from lib.utils.post_process import multi_pose_post_process -from lib.opts_pose import opts -from lib.detectors.detector_factory import detector_factory -from lib.datasets.dataset_factory import get_dataset - -def preprocess(): - root_path = os.getcwd() - opt = opts().parse('--task {} --load_model {}'.format('multi_pose', os.path.join(root_path, 'model_best.pth')).split(' ')) - Dataset = get_dataset(opt.dataset, opt.task) - opt = opts().update_dataset_info_and_set_heads(opt, Dataset) - os.environ['CUDA_VISIBLE_DEVICES'] = opt.gpus_str - Detector = detector_factory[opt.task] - detector = Detector(opt) - file_path = os.path.join(root_path,'../data') - in_files = os.listdir(file_path) - Meta = [] - for file in sorted(in_files): - os.chdir(os.path.join(file_path, file)) - cur_path = os.getcwd() - doc = os.listdir(cur_path) - for document in sorted(doc): - image = cv2.imread(os.path.join(cur_path, document)) - if document=='output': - break - for scale in opt.test_scales: - images,meta = detector.pre_process(image, scale, meta=None) - Meta.append(meta) - return Meta - -def post_process(dets, meta, scale=1): - dets = dets.detach().cpu().numpy().reshape(1, -1, dets.shape[2]) - dets = multi_pose_post_process( - dets.copy(), [meta['c']], [meta['s']], - meta['out_height'], meta['out_width']) - for j in range(1, 2): - dets[0][j] = np.array(dets[0][j], dtype=np.float32).reshape(-1, 15) # 关键点数+5=15 - dets[0][j][:, :4] /= scale - dets[0][j][:, 5:] /= scale - return dets[0] - -def merge_outputs(detections): - results = {} - results[1] = np.concatenate( - [detection[1] for detection in detections], axis=0).astype(np.float32) - results[1] = results[1].tolist() - return results - -def pre_postprocess(): - List = [] - root_path = os.getcwd() - path=os.path.join(root_path,'./result/result') - File = os.listdir(path) - for file in sorted(File): - Doc = [] #save no-repeated file name - os.chdir(os.path.join(path, file)) - cur_path = os.getcwd() - doc = os.listdir(cur_path) - for document in sorted(doc): - Doc.append(document[0:-6]) #grip end - Doc = list(set(Doc)) #grip repeated element - for ff in sorted(Doc): #deal after sorting - dist={} - if ff=='kerne': - break - for i in range(1, 5): #one image ----->four bin - txt_file = np.fromfile(f'../../../result/result/{file}/{ff}_{i}.bin', dtype=np.float32) - if i==1: - dist['hm']=torch.tensor(txt_file.reshape(-1,1,200,200)) - if i==2: - dist['wh']=torch.tensor(txt_file.reshape(-1,2,200,200)) - if i==3: - dist['hm_offset']=torch.tensor(txt_file.reshape(-1,2,200,200)) - if i==4: - dist['landmarks']=torch.tensor(txt_file.reshape(-1,10,200,200)) - List.append(dist) - os.chdir(root_path) - return List - -def run(): - List = pre_postprocess() - Meta = preprocess() - print('List:',len(List)) - print('Meta:',len(Meta)) - Results=[] - from tqdm import tqdm - for i in tqdm(range(len(List))): - detections = [] - reg = List[i]['hm_offset'] - dets = dc.centerface_decode( - List[i]['hm'], List[i]['wh'], List[i]['landmarks'], - reg=reg, K=200) - dets = post_process(dets,Meta[i]) - detections.append(dets) - results = merge_outputs(detections) - Results.append(results) - return Results - -if __name__ == "__main__": - root_path = os.getcwd() - Path = os.path.join(root_path,'../data') - wider_face_mat = sio.loadmat(root_path+'/wider_face_val.mat') - event_list = wider_face_mat['event_list'] #directory - file_list = wider_face_mat['file_list'] #file - save_path = root_path+'/output/widerface/' - results = run() #all data - i=0 #iteration - for index, event in enumerate(sorted(event_list)): - file_list_item = file_list[index][0] - im_dir = event[0][0] - if not os.path.exists(save_path + im_dir): - os.makedirs(save_path + im_dir) - for num, file in enumerate(sorted(file_list_item)): - im_name = file[0][0] - zip_name = '%s/%s.jpg' % (im_dir, im_name) - img_path = os.path.join(Path, zip_name) - dets = results[i] - f = open(save_path + im_dir + '/' + im_name + '.txt', 'w') - f.write('{:s}\n'.format('%s/%s.jpg' % (im_dir, im_name))) - f.write('{:d}\n'.format(len(dets))) - for b in dets[1]: - x1, y1, x2, y2, s = b[0], b[1], b[2], b[3], b[4] - f.write('{:.1f} {:.1f} {:.1f} {:.1f} {:.3f}\n'.format(x1, y1, (x2 - x1 + 1), (y2 - y1 + 1), s)) - f.close() - print(i) - i=i+1 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +# -*- coding:utf-8 -*- +from __future__ import absolute_import +from __future__ import division + +import numpy as np +import torch +import os +import sys +import cv2 +import scipy.io as sio + +from lib.models import decode as dc +from lib.models.utils import _gather_feat, _tranpose_and_gather_feat +from lib.utils import image as img +from lib.utils.post_process import multi_pose_post_process +from lib.opts_pose import opts +from lib.detectors.detector_factory import detector_factory +from lib.datasets.dataset_factory import get_dataset + +def preprocess(): + root_path = os.getcwd() + opt = opts().parse('--task {} --load_model {}'.format('multi_pose', os.path.join(root_path, 'model_best.pth')).split(' ')) + Dataset = get_dataset(opt.dataset, opt.task) + opt = opts().update_dataset_info_and_set_heads(opt, Dataset) + os.environ['CUDA_VISIBLE_DEVICES'] = opt.gpus_str + Detector = detector_factory[opt.task] + detector = Detector(opt) + file_path = os.path.join(root_path,'../data') + in_files = os.listdir(file_path) + Meta = [] + for file in sorted(in_files): + os.chdir(os.path.join(file_path, file)) + cur_path = os.getcwd() + doc = os.listdir(cur_path) + for document in sorted(doc): + image = cv2.imread(os.path.join(cur_path, document)) + if document=='output': + break + for scale in opt.test_scales: + images,meta = detector.pre_process(image, scale, meta=None) + Meta.append(meta) + return Meta + +def post_process(dets, meta, scale=1): + dets = dets.detach().cpu().numpy().reshape(1, -1, dets.shape[2]) + dets = multi_pose_post_process( + dets.copy(), [meta['c']], [meta['s']], + meta['out_height'], meta['out_width']) + for j in range(1, 2): + dets[0][j] = np.array(dets[0][j], dtype=np.float32).reshape(-1, 15) # 关键点数+5=15 + dets[0][j][:, :4] /= scale + dets[0][j][:, 5:] /= scale + return dets[0] + +def merge_outputs(detections): + results = {} + results[1] = np.concatenate( + [detection[1] for detection in detections], axis=0).astype(np.float32) + results[1] = results[1].tolist() + return results + +def pre_postprocess(): + List = [] + root_path = os.getcwd() + path=os.path.join(root_path,'./result/result') + File = os.listdir(path) + for file in sorted(File): + Doc = [] #save no-repeated file name + os.chdir(os.path.join(path, file)) + cur_path = os.getcwd() + doc = os.listdir(cur_path) + for document in sorted(doc): + Doc.append(document[0:-6]) #grip end + Doc = list(set(Doc)) #grip repeated element + for ff in sorted(Doc): #deal after sorting + dist={} + if ff=='kerne': + break + for i in range(1, 5): #one image ----->four bin + txt_file = np.fromfile(f'../../../result/result/{file}/{ff}_{i}.bin', dtype=np.float32) + if i==1: + dist['hm']=torch.tensor(txt_file.reshape(-1,1,200,200)) + if i==2: + dist['wh']=torch.tensor(txt_file.reshape(-1,2,200,200)) + if i==3: + dist['hm_offset']=torch.tensor(txt_file.reshape(-1,2,200,200)) + if i==4: + dist['landmarks']=torch.tensor(txt_file.reshape(-1,10,200,200)) + List.append(dist) + os.chdir(root_path) + return List + +def run(): + List = pre_postprocess() + Meta = preprocess() + print('List:',len(List)) + print('Meta:',len(Meta)) + Results=[] + from tqdm import tqdm + for i in tqdm(range(len(List))): + detections = [] + reg = List[i]['hm_offset'] + dets = dc.centerface_decode( + List[i]['hm'], List[i]['wh'], List[i]['landmarks'], + reg=reg, K=200) + dets = post_process(dets,Meta[i]) + detections.append(dets) + results = merge_outputs(detections) + Results.append(results) + return Results + +if __name__ == "__main__": + root_path = os.getcwd() + Path = os.path.join(root_path,'../data') + wider_face_mat = sio.loadmat(root_path+'/wider_face_val.mat') + event_list = wider_face_mat['event_list'] #directory + file_list = wider_face_mat['file_list'] #file + save_path = root_path+'/output/widerface/' + results = run() #all data + i=0 #iteration + for index, event in enumerate(sorted(event_list)): + file_list_item = file_list[index][0] + im_dir = event[0][0] + if not os.path.exists(save_path + im_dir): + os.makedirs(save_path + im_dir) + for num, file in enumerate(sorted(file_list_item)): + im_name = file[0][0] + zip_name = '%s/%s.jpg' % (im_dir, im_name) + img_path = os.path.join(Path, zip_name) + dets = results[i] + f = open(save_path + im_dir + '/' + im_name + '.txt', 'w') + f.write('{:s}\n'.format('%s/%s.jpg' % (im_dir, im_name))) + f.write('{:d}\n'.format(len(dets))) + for b in dets[1]: + x1, y1, x2, y2, s = b[0], b[1], b[2], b[3], b[4] + f.write('{:.1f} {:.1f} {:.1f} {:.1f} {:.3f}\n'.format(x1, y1, (x2 - x1 + 1), (y2 - y1 + 1), s)) + f.close() + print(i) + i=i+1 diff --git a/ACL_PyTorch/contrib/cv/detection/CenterFace/centerface_pth_preprocess.py b/ACL_PyTorch/contrib/cv/detection/CenterFace/centerface_pth_preprocess.py index cb3bfae74c..c8642403b4 100644 --- a/ACL_PyTorch/contrib/cv/detection/CenterFace/centerface_pth_preprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/CenterFace/centerface_pth_preprocess.py @@ -1,58 +1,58 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -# -*- coding:GB2312 -*- - -from __future__ import absolute_import -from __future__ import division - -import sys -import os -import cv2 -import torch - -from lib.opts_pose import opts -from lib.detectors.detector_factory import detector_factory -from datasets.dataset_factory import get_dataset - -def preprocess(file_path, bin_path): - opt = opts().parse('--task {} --load_model {}'.format('multi_pose', 'model_best.pth').split(' ')) - Dataset = get_dataset(opt.dataset, opt.task) - opt = opts().update_dataset_info_and_set_heads(opt, Dataset) - os.environ['CUDA_VISIBLE_DEVICES'] = opt.gpus_str - Detector = detector_factory[opt.task] - detector = Detector(opt) - in_files = os.listdir(file_path) - - if not os.path.exists(bin_path): - os.makedirs(bin_path) - for file in sorted(in_files): - os.chdir(os.path.join(file_path, file)) - cur_path = os.getcwd() - doc = os.listdir(cur_path) - for document in doc: - if document=='output': - break - image = cv2.imread(os.path.join(cur_path, document)) - for scale in opt.test_scales: - images, meta = detector.pre_process(image, scale, meta=None) - if not os.path.exists(os.path.join(bin_path,file)): - os.makedirs(os.path.join(bin_path,file)) - des_path = os.path.join(bin_path,file) - images.numpy().tofile(os.path.join(des_path,document.split('.')[0] +'.bin')) - -if __name__ == "__main__": - file_path = os.path.abspath(sys.argv[1]) - bin_path = os.path.abspath(sys.argv[2]) - preprocess(file_path, bin_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +# -*- coding:GB2312 -*- + +from __future__ import absolute_import +from __future__ import division + +import sys +import os +import cv2 +import torch + +from lib.opts_pose import opts +from lib.detectors.detector_factory import detector_factory +from datasets.dataset_factory import get_dataset + +def preprocess(file_path, bin_path): + opt = opts().parse('--task {} --load_model {}'.format('multi_pose', 'model_best.pth').split(' ')) + Dataset = get_dataset(opt.dataset, opt.task) + opt = opts().update_dataset_info_and_set_heads(opt, Dataset) + os.environ['CUDA_VISIBLE_DEVICES'] = opt.gpus_str + Detector = detector_factory[opt.task] + detector = Detector(opt) + in_files = os.listdir(file_path) + + if not os.path.exists(bin_path): + os.makedirs(bin_path) + for file in sorted(in_files): + os.chdir(os.path.join(file_path, file)) + cur_path = os.getcwd() + doc = os.listdir(cur_path) + for document in doc: + if document=='output': + break + image = cv2.imread(os.path.join(cur_path, document)) + for scale in opt.test_scales: + images, meta = detector.pre_process(image, scale, meta=None) + if not os.path.exists(os.path.join(bin_path,file)): + os.makedirs(os.path.join(bin_path,file)) + des_path = os.path.join(bin_path,file) + images.numpy().tofile(os.path.join(des_path,document.split('.')[0] +'.bin')) + +if __name__ == "__main__": + file_path = os.path.abspath(sys.argv[1]) + bin_path = os.path.abspath(sys.argv[2]) + preprocess(file_path, bin_path) diff --git a/ACL_PyTorch/contrib/cv/detection/CenterFace/convert.py b/ACL_PyTorch/contrib/cv/detection/CenterFace/convert.py index b5436a7049..56f2d5d036 100644 --- a/ACL_PyTorch/contrib/cv/detection/CenterFace/convert.py +++ b/ACL_PyTorch/contrib/cv/detection/CenterFace/convert.py @@ -1,40 +1,40 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import shutil - - -if __name__ == '__main__': - bin_path = sys.argv[1] - resule_path = sys.argv[2] - if not os.path.exists(resule_path): - os.mkdir(resule_path) - f = os.listdir(bin_path) - for data in f: - data = data.strip('\n') - dir_name = data.split('_')[0] + '--' + data.split('_')[1] - dir_path = os.path.join(resule_path, dir_name) - if not os.path.exists(dir_path): - os.mkdir(dir_path) - file_list = os.listdir(resule_path) - for dir in file_list: - dir = dir.strip('\n') - cur_path = os.path.join(resule_path, dir) - for data in f: - data = data.strip('\n') - if data.split('_')[0] == dir.split('--')[0]: - shutil.copy(os.path.join(bin_path, data), - os.path.join(cur_path, data)) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import shutil + + +if __name__ == '__main__': + bin_path = sys.argv[1] + resule_path = sys.argv[2] + if not os.path.exists(resule_path): + os.mkdir(resule_path) + f = os.listdir(bin_path) + for data in f: + data = data.strip('\n') + dir_name = data.split('_')[0] + '--' + data.split('_')[1] + dir_path = os.path.join(resule_path, dir_name) + if not os.path.exists(dir_path): + os.mkdir(dir_path) + file_list = os.listdir(resule_path) + for dir in file_list: + dir = dir.strip('\n') + cur_path = os.path.join(resule_path, dir) + for data in f: + data = data.strip('\n') + if data.split('_')[0] == dir.split('--')[0]: + shutil.copy(os.path.join(bin_path, data), + os.path.join(cur_path, data)) diff --git a/ACL_PyTorch/contrib/cv/detection/CenterFace/pth2onnx.py b/ACL_PyTorch/contrib/cv/detection/CenterFace/pth2onnx.py index f58e87f45a..32ec152f35 100644 --- a/ACL_PyTorch/contrib/cv/detection/CenterFace/pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/detection/CenterFace/pth2onnx.py @@ -1,35 +1,35 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import os -import sys -import torch -import torch.utils.data -from opts_pose import opts -from models.model import create_model, load_model, save_model -from models.data_parallel import DataParallel -from logger import Logger -from datasets.dataset_factory import get_dataset -from trains.train_factory import train_factory -from datasets.sample.multi_pose import Multiposebatch - -def main(onnx_path,path): - opt = opts().parse() - input_names=["image"] - output_names = ["output1","output2","output3","output4"] - Dataset = get_dataset(opt.dataset, opt.task) - opt = opts().update_dataset_info_and_set_heads(opt, Dataset) - model = create_model(opt.arch, opt.heads, opt.head_conv) - model = load_model(model , path, None, opt.resume, opt.lr, opt.lr_step) - dynamic_axes = {'image': {0: '-1'}, 'output1': {0: '-1'},'output2': {0: '-1'},'output3': {0: '-1'},'output4': {0: '-1'}} - model.eval() - dummy_input = torch.randn(1,3,800,800) - torch.onnx.export(model,dummy_input,onnx_path,export_params=True,dynamic_axes = dynamic_axes,input_names = input_names,output_names = output_names,verbose=True) - -if __name__ =="__main__": - #onnx_path = sys.argv[1] - #path = sys.argv[2] - onnx_path = '../CenterFace.onnx' - path = '../model_best.pth' - main(onnx_path,path) +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +import sys +import torch +import torch.utils.data +from opts_pose import opts +from models.model import create_model, load_model, save_model +from models.data_parallel import DataParallel +from logger import Logger +from datasets.dataset_factory import get_dataset +from trains.train_factory import train_factory +from datasets.sample.multi_pose import Multiposebatch + +def main(onnx_path,path): + opt = opts().parse() + input_names=["image"] + output_names = ["output1","output2","output3","output4"] + Dataset = get_dataset(opt.dataset, opt.task) + opt = opts().update_dataset_info_and_set_heads(opt, Dataset) + model = create_model(opt.arch, opt.heads, opt.head_conv) + model = load_model(model , path, None, opt.resume, opt.lr, opt.lr_step) + dynamic_axes = {'image': {0: '-1'}, 'output1': {0: '-1'},'output2': {0: '-1'},'output3': {0: '-1'},'output4': {0: '-1'}} + model.eval() + dummy_input = torch.randn(1,3,800,800) + torch.onnx.export(model,dummy_input,onnx_path,export_params=True,dynamic_axes = dynamic_axes,input_names = input_names,output_names = output_names,verbose=True) + +if __name__ =="__main__": + #onnx_path = sys.argv[1] + #path = sys.argv[2] + onnx_path = '../CenterFace.onnx' + path = '../model_best.pth' + main(onnx_path,path) diff --git a/ACL_PyTorch/contrib/cv/detection/CenterFace/test/README.md b/ACL_PyTorch/contrib/cv/detection/CenterFace/test/README.md index fd47bfc4bc..1652e1d70d 100644 --- a/ACL_PyTorch/contrib/cv/detection/CenterFace/test/README.md +++ b/ACL_PyTorch/contrib/cv/detection/CenterFace/test/README.md @@ -1,28 +1,28 @@ -环境准备: - -1.数据集路径 通用的数据集统一放在/CenterFace/center-face/data - -2.进入工作目录 cd CenterFace/center-face/src - -3.安装模型代码之前要执行下面命令: - - git clone https://gitee.com/Levi990223/center-face.git - -4.获取权重文件 -权重文件从百度网盘上获取:https://pan.baidu.com/s/1sU3pRBTFebbsMDac-1HsQA 密码:etdi - -5.获取数据集:https://www.graviti.cn/open-datasets/WIDER_FACE - -6.获取benchmark工具 将benchmark.x86_64 放在CenterFace/src目录下 - -推理步骤: - -7.调用/CenterFace/src/lib下面得pth2onnx生成onnx放在/src下面 - -运行python3 pth2onnx命令,在src文件夹下生成CenterFace.onnx文件 - -8.脚本转换om模型 bash test/onnxToom.sh - -9.310上执行,执行时确保device空闲: bash test/infer.sh - +环境准备: + +1.数据集路径 通用的数据集统一放在/CenterFace/center-face/data + +2.进入工作目录 cd CenterFace/center-face/src + +3.安装模型代码之前要执行下面命令: + + git clone https://gitee.com/Levi990223/center-face.git + +4.获取权重文件 +权重文件从百度网盘上获取:https://pan.baidu.com/s/1sU3pRBTFebbsMDac-1HsQA 密码:etdi + +5.获取数据集:https://www.graviti.cn/open-datasets/WIDER_FACE + +6.获取benchmark工具 将benchmark.x86_64 放在CenterFace/src目录下 + +推理步骤: + +7.调用/CenterFace/src/lib下面得pth2onnx生成onnx放在/src下面 + +运行python3 pth2onnx命令,在src文件夹下生成CenterFace.onnx文件 + +8.脚本转换om模型 bash test/onnxToom.sh + +9.310上执行,执行时确保device空闲: bash test/infer.sh + 10.在T4环境上将onnx文件放在/root/lsj目录下,执行perf_t4.sh时确保gpu空闲,执行命令 bash perf_t4.sh \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/CenterNet/CenterNet_postprocess.py b/ACL_PyTorch/contrib/cv/detection/CenterNet/CenterNet_postprocess.py index bf2a91f00f..8547afc57d 100644 --- a/ACL_PyTorch/contrib/cv/detection/CenterNet/CenterNet_postprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/CenterNet/CenterNet_postprocess.py @@ -1,104 +1,104 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import torch -import numpy as np -import os -from glob import glob -import sys -CENTERNET_PATH = './CenterNet/src' -sys.path.insert(0, CENTERNET_PATH) -import cv2 -from lib.opts import opts -from lib.detectors.detector_factory import detector_factory -from lib.datasets.dataset_factory import get_dataset -from lib.models.decode import ctdet_decode -from lib.utils.post_process import ctdet_post_process -from lib.models.model import create_model, load_model -import lib.datasets.dataset.coco - -def post_process(dets, meta, scale=1): - print(meta) - num_classes=80 - dets = dets.detach().cpu().numpy() - dets = dets.reshape(1, -1, dets.shape[2]) - dets = ctdet_post_process( - dets.copy(), [meta['c']], [meta['s']], - meta['out_height'], meta['out_width'], 80) - for j in range(1, 81): - dets[0][j] = np.array(dets[0][j], dtype=np.float32).reshape(-1, 5) - dets[0][j][:, :4] /= scale - return dets[0] - -def merge_outputs(detections): - results = {} - for j in range(1, 80 + 1):#coco numclasses=80 - results[j] = np.concatenate( - [detection[j] for detection in detections], axis=0).astype(np.float32) - return results - -def run(result_list, index, meta, dataset, filename): - output={} - for i in range(1, 4): - buf = np.fromfile(f'{result_list}/{filename[0:-4]}_{i}.bin', dtype="float32") - if i == 1: - output['hm'] = torch.tensor(buf.reshape(1, 80, 128, 128)) - if i == 2: - output['wh'] = torch.tensor(buf.reshape(1, 2, 128, 128)) - if i == 3: - output['reg'] = torch.tensor(buf.reshape(1, 2, 128, 128)) - detections = [] - hm = output['hm'].sigmoid_() - wh = output['wh'] - reg = output['reg'] - dets = ctdet_decode(hm, wh, reg) - dets = post_process(dets,meta) - detections.append(dets) - results = merge_outputs(detections) - return results - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='CenterNet') - parser.add_argument('--bin_data_path', default='./result/dumpOutput_device0', type=str, help='infer out path') - parser.add_argument('--resultfolder', default='./run_eval_result', type=str, help='Dir to save results') - args = parser.parse_args() - if not os.path.exists(args.resultfolder): - os.makedirs(args.resultfolder) - - opt = opts().parse('{} --load_model {}'.format('ctdet', './ctdet_coco_dla_2x.pth').split(' ')) - Dataset = get_dataset(opt.dataset, opt.task) - opt = opts().update_dataset_info_and_set_heads(opt, Dataset) - Detector = detector_factory[opt.task] - dataset = Dataset(opt, 'val') - opt.gpus[0] = -1 - detector = Detector(opt) - Meta = [] - filename = [] - results = {} - num_iters = len(dataset) - for ind in range(num_iters): - img_id = dataset.images[ind] - img_info = dataset.coco.loadImgs(ids=[img_id])[0] - img_path = os.path.join(dataset.img_dir, img_info['file_name']) - print(img_info['file_name'], "===", ind) - image = cv2.imread(img_path) - images, meta = detector.pre_process(image, 1.0, meta=None) - ret = run(args.bin_data_path, ind, meta, dataset, img_info['file_name']) - results[img_id] = ret - dataset.run_eval(results, args.resultfolder) - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import torch +import numpy as np +import os +from glob import glob +import sys +CENTERNET_PATH = './CenterNet/src' +sys.path.insert(0, CENTERNET_PATH) +import cv2 +from lib.opts import opts +from lib.detectors.detector_factory import detector_factory +from lib.datasets.dataset_factory import get_dataset +from lib.models.decode import ctdet_decode +from lib.utils.post_process import ctdet_post_process +from lib.models.model import create_model, load_model +import lib.datasets.dataset.coco + +def post_process(dets, meta, scale=1): + print(meta) + num_classes=80 + dets = dets.detach().cpu().numpy() + dets = dets.reshape(1, -1, dets.shape[2]) + dets = ctdet_post_process( + dets.copy(), [meta['c']], [meta['s']], + meta['out_height'], meta['out_width'], 80) + for j in range(1, 81): + dets[0][j] = np.array(dets[0][j], dtype=np.float32).reshape(-1, 5) + dets[0][j][:, :4] /= scale + return dets[0] + +def merge_outputs(detections): + results = {} + for j in range(1, 80 + 1):#coco numclasses=80 + results[j] = np.concatenate( + [detection[j] for detection in detections], axis=0).astype(np.float32) + return results + +def run(result_list, index, meta, dataset, filename): + output={} + for i in range(1, 4): + buf = np.fromfile(f'{result_list}/{filename[0:-4]}_{i}.bin', dtype="float32") + if i == 1: + output['hm'] = torch.tensor(buf.reshape(1, 80, 128, 128)) + if i == 2: + output['wh'] = torch.tensor(buf.reshape(1, 2, 128, 128)) + if i == 3: + output['reg'] = torch.tensor(buf.reshape(1, 2, 128, 128)) + detections = [] + hm = output['hm'].sigmoid_() + wh = output['wh'] + reg = output['reg'] + dets = ctdet_decode(hm, wh, reg) + dets = post_process(dets,meta) + detections.append(dets) + results = merge_outputs(detections) + return results + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='CenterNet') + parser.add_argument('--bin_data_path', default='./result/dumpOutput_device0', type=str, help='infer out path') + parser.add_argument('--resultfolder', default='./run_eval_result', type=str, help='Dir to save results') + args = parser.parse_args() + if not os.path.exists(args.resultfolder): + os.makedirs(args.resultfolder) + + opt = opts().parse('{} --load_model {}'.format('ctdet', './ctdet_coco_dla_2x.pth').split(' ')) + Dataset = get_dataset(opt.dataset, opt.task) + opt = opts().update_dataset_info_and_set_heads(opt, Dataset) + Detector = detector_factory[opt.task] + dataset = Dataset(opt, 'val') + opt.gpus[0] = -1 + detector = Detector(opt) + Meta = [] + filename = [] + results = {} + num_iters = len(dataset) + for ind in range(num_iters): + img_id = dataset.images[ind] + img_info = dataset.coco.loadImgs(ids=[img_id])[0] + img_path = os.path.join(dataset.img_dir, img_info['file_name']) + print(img_info['file_name'], "===", ind) + image = cv2.imread(img_path) + images, meta = detector.pre_process(image, 1.0, meta=None) + ret = run(args.bin_data_path, ind, meta, dataset, img_info['file_name']) + results[img_id] = ret + dataset.run_eval(results, args.resultfolder) + diff --git a/ACL_PyTorch/contrib/cv/detection/CenterNet/CenterNet_preprocess.py b/ACL_PyTorch/contrib/cv/detection/CenterNet/CenterNet_preprocess.py index 6400bc3f6a..0c271cf045 100644 --- a/ACL_PyTorch/contrib/cv/detection/CenterNet/CenterNet_preprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/CenterNet/CenterNet_preprocess.py @@ -1,98 +1,98 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import os -import cv2 -import numpy as np -import torch - -def preprocess(file_path, bin_path): - in_files = os.listdir(file_path) - if not os.path.exists(bin_path): - os.makedirs(bin_path) - i = 0 - for file in sorted(in_files): - i = i + 1 - print(file, "===", i) - image = cv2.imread(os.path.join(file_path, file)) - height, width = image.shape[0:2] - new_height = int(height) - new_width = int(width) - #Fix size testing - inp_height, inp_width = 512, 512 - c = np.array([new_width / 2., new_height / 2.], dtype=np.float32) - s = max(height, width) * 1.0 - trans_input = get_affine_transform(c, s, 0, [inp_width, inp_height]) - resized_image = cv2.resize(image, (new_width, new_height)) - inp_image = cv2.warpAffine( - resized_image, trans_input, (inp_width, inp_height),flags=cv2.INTER_LINEAR) - - inp_image = ((inp_image / 255. - [[[0.40789655,0.44719303,0.47026116]]]) / [[[0.2886383,0.27408165,0.27809834]]]).astype(np.float32) - images = inp_image.transpose(2, 0, 1).reshape(1, 3, inp_height, inp_width) - images = torch.from_numpy(images) - img = np.array(images).astype(np.float32) - img.tofile(os.path.join(bin_path, file.split('.')[0] + '.bin')) - -def get_affine_transform(center, - scale, - rot, - output_size, - shift=np.array([0, 0], dtype=np.float32), - inv=0): - if not isinstance(scale, np.ndarray) and not isinstance(scale, list): - scale = np.array([scale, scale], dtype=np.float32) - - scale_tmp = scale - src_w = scale_tmp[0] - dst_w = output_size[0] - dst_h = output_size[1] - - rot_rad = np.pi * rot / 180 - src_dir = get_dir([0, src_w * -0.5], rot_rad) - dst_dir = np.array([0, dst_w * -0.5], np.float32) - - src = np.zeros((3, 2), dtype=np.float32) - dst = np.zeros((3, 2), dtype=np.float32) - src[0, :] = center + scale_tmp * shift - src[1, :] = center + src_dir + scale_tmp * shift - dst[0, :] = [dst_w * 0.5, dst_h * 0.5] - dst[1, :] = np.array([dst_w * 0.5, dst_h * 0.5], np.float32) + dst_dir - - src[2:, :] = get_3rd_point(src[0, :], src[1, :]) - dst[2:, :] = get_3rd_point(dst[0, :], dst[1, :]) - - if inv: - trans = cv2.getAffineTransform(np.float32(dst), np.float32(src)) - else: - trans = cv2.getAffineTransform(np.float32(src), np.float32(dst)) - - return trans - -def get_3rd_point(a, b): - direct = a - b - return b + np.array([-direct[1], direct[0]], dtype=np.float32) - -def get_dir(src_point, rot_rad): - sn, cs = np.sin(rot_rad), np.cos(rot_rad) - - src_result = [0, 0] - src_result[0] = src_point[0] * cs - src_point[1] * sn - src_result[1] = src_point[0] * sn + src_point[1] * cs - - return src_result -if __name__ == "__main__": - file_path = os.path.abspath(sys.argv[1]) - bin_path = os.path.abspath(sys.argv[2]) - preprocess(file_path, bin_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import os +import cv2 +import numpy as np +import torch + +def preprocess(file_path, bin_path): + in_files = os.listdir(file_path) + if not os.path.exists(bin_path): + os.makedirs(bin_path) + i = 0 + for file in sorted(in_files): + i = i + 1 + print(file, "===", i) + image = cv2.imread(os.path.join(file_path, file)) + height, width = image.shape[0:2] + new_height = int(height) + new_width = int(width) + #Fix size testing + inp_height, inp_width = 512, 512 + c = np.array([new_width / 2., new_height / 2.], dtype=np.float32) + s = max(height, width) * 1.0 + trans_input = get_affine_transform(c, s, 0, [inp_width, inp_height]) + resized_image = cv2.resize(image, (new_width, new_height)) + inp_image = cv2.warpAffine( + resized_image, trans_input, (inp_width, inp_height),flags=cv2.INTER_LINEAR) + + inp_image = ((inp_image / 255. - [[[0.40789655,0.44719303,0.47026116]]]) / [[[0.2886383,0.27408165,0.27809834]]]).astype(np.float32) + images = inp_image.transpose(2, 0, 1).reshape(1, 3, inp_height, inp_width) + images = torch.from_numpy(images) + img = np.array(images).astype(np.float32) + img.tofile(os.path.join(bin_path, file.split('.')[0] + '.bin')) + +def get_affine_transform(center, + scale, + rot, + output_size, + shift=np.array([0, 0], dtype=np.float32), + inv=0): + if not isinstance(scale, np.ndarray) and not isinstance(scale, list): + scale = np.array([scale, scale], dtype=np.float32) + + scale_tmp = scale + src_w = scale_tmp[0] + dst_w = output_size[0] + dst_h = output_size[1] + + rot_rad = np.pi * rot / 180 + src_dir = get_dir([0, src_w * -0.5], rot_rad) + dst_dir = np.array([0, dst_w * -0.5], np.float32) + + src = np.zeros((3, 2), dtype=np.float32) + dst = np.zeros((3, 2), dtype=np.float32) + src[0, :] = center + scale_tmp * shift + src[1, :] = center + src_dir + scale_tmp * shift + dst[0, :] = [dst_w * 0.5, dst_h * 0.5] + dst[1, :] = np.array([dst_w * 0.5, dst_h * 0.5], np.float32) + dst_dir + + src[2:, :] = get_3rd_point(src[0, :], src[1, :]) + dst[2:, :] = get_3rd_point(dst[0, :], dst[1, :]) + + if inv: + trans = cv2.getAffineTransform(np.float32(dst), np.float32(src)) + else: + trans = cv2.getAffineTransform(np.float32(src), np.float32(dst)) + + return trans + +def get_3rd_point(a, b): + direct = a - b + return b + np.array([-direct[1], direct[0]], dtype=np.float32) + +def get_dir(src_point, rot_rad): + sn, cs = np.sin(rot_rad), np.cos(rot_rad) + + src_result = [0, 0] + src_result[0] = src_point[0] * cs - src_point[1] * sn + src_result[1] = src_point[0] * sn + src_point[1] * cs + + return src_result +if __name__ == "__main__": + file_path = os.path.abspath(sys.argv[1]) + bin_path = os.path.abspath(sys.argv[2]) + preprocess(file_path, bin_path) diff --git a/ACL_PyTorch/contrib/cv/detection/CenterNet/CenterNet_pth2onnx.py b/ACL_PyTorch/contrib/cv/detection/CenterNet/CenterNet_pth2onnx.py index 3fcd485e92..e5ccee5b9e 100644 --- a/ACL_PyTorch/contrib/cv/detection/CenterNet/CenterNet_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/detection/CenterNet/CenterNet_pth2onnx.py @@ -1,54 +1,54 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -CENTERNET_PATH = '../src' -sys.path.insert(0, CENTERNET_PATH) -MODEL_PATH = '../models/ctdet_coco_dla_2x.pth' -import os -import _init_paths -import torch -import torch.utils.data -from opts import opts -from models.model import create_model, load_model, save_model -from models.data_parallel import DataParallel -from logger import Logger -from datasets.dataset_factory import get_dataset - - -def convert(): - #device = torch.device("cpu") - device = torch.device("cuda") - torch.set_default_tensor_type(torch.cuda.FloatTensor) - TASK = 'ctdet' - opt = opts().parse('{} --load_model {}'.format(TASK, MODEL_PATH).split(' ')) - Dataset = get_dataset(opt.dataset, opt.task) - opt = opts().update_dataset_info_and_set_heads(opt, Dataset) - model = create_model(opt.arch, opt.heads, opt.head_conv) - model = load_model(model, input_file, None, opt.resume, opt.lr, opt.lr_step) - model.eval() - - input_names = ["actual_input"] - output_names = ["output1","output2","output3"] - dynamic_axes = {'actual_input': {0: '-1'}, 'output1': {0: '-1'}, 'output2': {0: '-1'}, 'output3': {0: '-1'}} - dummy_input = torch.randn(1, 3, 512, 512) - torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, opset_version=11, verbose=True) - -if __name__ == "__main__": - input_file = sys.argv[1] - output_file = sys.argv[2] - convert() +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +CENTERNET_PATH = '../src' +sys.path.insert(0, CENTERNET_PATH) +MODEL_PATH = '../models/ctdet_coco_dla_2x.pth' +import os +import _init_paths +import torch +import torch.utils.data +from opts import opts +from models.model import create_model, load_model, save_model +from models.data_parallel import DataParallel +from logger import Logger +from datasets.dataset_factory import get_dataset + + +def convert(): + #device = torch.device("cpu") + device = torch.device("cuda") + torch.set_default_tensor_type(torch.cuda.FloatTensor) + TASK = 'ctdet' + opt = opts().parse('{} --load_model {}'.format(TASK, MODEL_PATH).split(' ')) + Dataset = get_dataset(opt.dataset, opt.task) + opt = opts().update_dataset_info_and_set_heads(opt, Dataset) + model = create_model(opt.arch, opt.heads, opt.head_conv) + model = load_model(model, input_file, None, opt.resume, opt.lr, opt.lr_step) + model.eval() + + input_names = ["actual_input"] + output_names = ["output1","output2","output3"] + dynamic_axes = {'actual_input': {0: '-1'}, 'output1': {0: '-1'}, 'output2': {0: '-1'}, 'output3': {0: '-1'}} + dummy_input = torch.randn(1, 3, 512, 512) + torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, opset_version=11, verbose=True) + +if __name__ == "__main__": + input_file = sys.argv[1] + output_file = sys.argv[2] + convert() diff --git a/ACL_PyTorch/contrib/cv/detection/CenterNet/README.md b/ACL_PyTorch/contrib/cv/detection/CenterNet/README.md index 7a92a8f542..9f7e243935 100644 --- a/ACL_PyTorch/contrib/cv/detection/CenterNet/README.md +++ b/ACL_PyTorch/contrib/cv/detection/CenterNet/README.md @@ -1,103 +1,103 @@ -# CenterNet模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,建议手动安装 - -``` -pip3 install -r requirements.txt -``` - -2.获取,修改与安装开源模型代码 - -安装CenterNet - -``` -source env.sh -git clone https://github.com/xingyizhou/CenterNet -cd CenterNet/src/lib/models/networks -rm -r DCNv2 -rm -r pose_dla_dcn.py -git clone https://github.com/jinfagang/DCNv2_latest.git -mv DCNv2_latest DCNv2 -cd DCNv2 -rm -r dcn_v2.py -cd ../../../../../../ -mv dcn_v2.py CenterNet/src/lib/models/networks/DCNv2 -mv pose_dla_dcn.py CenterNet/src/lib/models/networks - -cd CenterNet/src/lib/external -make -cd ../models/networks/DCNv2 -python3 setup.py build develop -cd ../../../../../../ -``` - -备注:将源码中DCNv2算子更新到DCNv2_latest,以支持pytorch1.5;按照上述步骤替换pose_dcn_dla.py文件与dcn_v2.py文件,以修改自定义算子,实现onnx的推理过程 - -另外,需要单独修改python环境中的utils.py文件,不同环境下具体路径有一定差异。手动将/usr/local/python3.7.5/lib/python3.7/site-packages/torch/onnx/utils.py下述部分做相应更改: - -```python - not val_use_external_data_format: - # Only run checker if enabled and we are not using ATEN fallback and - # large model format export in not enabled. -- _check_onnx_proto(proto) -+ pass -``` -3.获取权重文件 - -[ctdet_coco_dla_2x.pth](https://drive.google.com/open?id=1pl_-ael8wERdUREEnaIfqOV_VF2bEVRT),放在当前目录下 - -4.数据集 -获取COCO数据集:[coco2017](https://cocodataset.org/#download),下载其中val2017图片及其标注文件([2017 Val images](http://images.cocodataset.org/zips/val2017.zip),[2017 Train/Val annotations](http://images.cocodataset.org/annotations/annotations_trainval2017.zip)),解压后放入/opt/npu/datasets/coco以及CenterNet/data/coco/路径下,其中val2017目录存放coco数据集的验证集图片,annotations目录存放coco数据集的instances_val2017.json,文件目录结构如下: - -``` -CenterNet -├── data -│ ├── coco -│ │ ├── annotations -│ │ ├── val2017 -``` - -5.[获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) -将benchmark.x86_64放到当前目录 - -## 2 离线推理 - -CenterNet模型pth2onnx脚本由于算子暂不支持cpu,故只能在gpu运行,故将pth2om.sh拆为pth2onnx.sh和onnx2om.sh - -**在gpu上:** - -``` -bash test/pth2onnx.sh -``` - -并将生成的CenterNet.onnx移到310上,路径为:{当前目录}/test - -**在310上:** - -**test目录下已经打包了一个正确的onnx,可解压后直接使用** - -``` -unzip test/onnx.zip -``` - -``` -bash test/onnx2om.sh -bash test/eval_acc_perf.sh --datasets_path=/opt/npu/datasets/coco -``` - -**评测结果:** - -| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | -| ------------- | ----------- | --------------- | -------- | -------- | -| CenterNet_bs1 | AP : 36.6 | AP : 36.4 | 23.25fps | 17.25fps | - -备注: - -1.原官网pth精度 AP : 37.4 是在线推理时keep_res(保持分辨率)的结果,但由于离线推理需要固定shape,故需要去掉keep_res(保持分辨率)。去掉keep_res(保持分辨率)后,跑在线推理精度评估得到 AP : 36.6 ,故以 AP : 36.6 作为精度基准 - -2.onnx因包含npu自定义算子dcnv2而不能推理,故使用在线推理测试性能 - -3.原模型在线推理中仅实现batchsize=1的精度测试和性能测试 - +# CenterNet模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,建议手动安装 + +``` +pip3 install -r requirements.txt +``` + +2.获取,修改与安装开源模型代码 + +安装CenterNet + +``` +source env.sh +git clone https://github.com/xingyizhou/CenterNet +cd CenterNet/src/lib/models/networks +rm -r DCNv2 +rm -r pose_dla_dcn.py +git clone https://github.com/jinfagang/DCNv2_latest.git +mv DCNv2_latest DCNv2 +cd DCNv2 +rm -r dcn_v2.py +cd ../../../../../../ +mv dcn_v2.py CenterNet/src/lib/models/networks/DCNv2 +mv pose_dla_dcn.py CenterNet/src/lib/models/networks + +cd CenterNet/src/lib/external +make +cd ../models/networks/DCNv2 +python3 setup.py build develop +cd ../../../../../../ +``` + +备注:将源码中DCNv2算子更新到DCNv2_latest,以支持pytorch1.5;按照上述步骤替换pose_dcn_dla.py文件与dcn_v2.py文件,以修改自定义算子,实现onnx的推理过程 + +另外,需要单独修改python环境中的utils.py文件,不同环境下具体路径有一定差异。手动将/usr/local/python3.7.5/lib/python3.7/site-packages/torch/onnx/utils.py下述部分做相应更改: + +```python + not val_use_external_data_format: + # Only run checker if enabled and we are not using ATEN fallback and + # large model format export in not enabled. +- _check_onnx_proto(proto) ++ pass +``` +3.获取权重文件 + +[ctdet_coco_dla_2x.pth](https://drive.google.com/open?id=1pl_-ael8wERdUREEnaIfqOV_VF2bEVRT),放在当前目录下 + +4.数据集 +获取COCO数据集:[coco2017](https://cocodataset.org/#download),下载其中val2017图片及其标注文件([2017 Val images](http://images.cocodataset.org/zips/val2017.zip),[2017 Train/Val annotations](http://images.cocodataset.org/annotations/annotations_trainval2017.zip)),解压后放入/opt/npu/datasets/coco以及CenterNet/data/coco/路径下,其中val2017目录存放coco数据集的验证集图片,annotations目录存放coco数据集的instances_val2017.json,文件目录结构如下: + +``` +CenterNet +├── data +│ ├── coco +│ │ ├── annotations +│ │ ├── val2017 +``` + +5.[获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) +将benchmark.x86_64放到当前目录 + +## 2 离线推理 + +CenterNet模型pth2onnx脚本由于算子暂不支持cpu,故只能在gpu运行,故将pth2om.sh拆为pth2onnx.sh和onnx2om.sh + +**在gpu上:** + +``` +bash test/pth2onnx.sh +``` + +并将生成的CenterNet.onnx移到310上,路径为:{当前目录}/test + +**在310上:** + +**test目录下已经打包了一个正确的onnx,可解压后直接使用** + +``` +unzip test/onnx.zip +``` + +``` +bash test/onnx2om.sh +bash test/eval_acc_perf.sh --datasets_path=/opt/npu/datasets/coco +``` + +**评测结果:** + +| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | +| ------------- | ----------- | --------------- | -------- | -------- | +| CenterNet_bs1 | AP : 36.6 | AP : 36.4 | 23.25fps | 17.25fps | + +备注: + +1.原官网pth精度 AP : 37.4 是在线推理时keep_res(保持分辨率)的结果,但由于离线推理需要固定shape,故需要去掉keep_res(保持分辨率)。去掉keep_res(保持分辨率)后,跑在线推理精度评估得到 AP : 36.6 ,故以 AP : 36.6 作为精度基准 + +2.onnx因包含npu自定义算子dcnv2而不能推理,故使用在线推理测试性能 + +3.原模型在线推理中仅实现batchsize=1的精度测试和性能测试 + diff --git a/ACL_PyTorch/contrib/cv/detection/DSFD/DSFD.patch b/ACL_PyTorch/contrib/cv/detection/DSFD/DSFD.patch index ad7be24d19..6cbd178cb9 100644 --- a/ACL_PyTorch/contrib/cv/detection/DSFD/DSFD.patch +++ b/ACL_PyTorch/contrib/cv/detection/DSFD/DSFD.patch @@ -6693,60 +6693,60 @@ index 8c41037111..0000000000 --- a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/eval_tools/box_overlaps.pyx +++ /dev/null @@ -1,55 +0,0 @@ --# -------------------------------------------------------- --# Fast R-CNN --# Copyright (c) 2015 Microsoft --# Licensed under The MIT License [see LICENSE for details] --# Written by Sergey Karayev --# -------------------------------------------------------- -- --cimport cython --import numpy as np --cimport numpy as np -- --DTYPE = np.float --ctypedef np.float_t DTYPE_t -- --def bbox_overlaps( -- np.ndarray[DTYPE_t, ndim=2] boxes, -- np.ndarray[DTYPE_t, ndim=2] query_boxes): -- """ -- Parameters -- ---------- -- boxes: (N, 4) ndarray of float -- query_boxes: (K, 4) ndarray of float -- Returns -- ------- -- overlaps: (N, K) ndarray of overlap between boxes and query_boxes -- """ -- cdef unsigned int N = boxes.shape[0] -- cdef unsigned int K = query_boxes.shape[0] -- cdef np.ndarray[DTYPE_t, ndim=2] overlaps = np.zeros((N, K), dtype=DTYPE) -- cdef DTYPE_t iw, ih, box_area -- cdef DTYPE_t ua -- cdef unsigned int k, n -- for k in range(K): -- box_area = ( -- (query_boxes[k, 2] - query_boxes[k, 0] + 1) * -- (query_boxes[k, 3] - query_boxes[k, 1] + 1) -- ) -- for n in range(N): -- iw = ( -- min(boxes[n, 2], query_boxes[k, 2]) - -- max(boxes[n, 0], query_boxes[k, 0]) + 1 -- ) -- if iw > 0: -- ih = ( -- min(boxes[n, 3], query_boxes[k, 3]) - -- max(boxes[n, 1], query_boxes[k, 1]) + 1 -- ) -- if ih > 0: -- ua = float( -- (boxes[n, 2] - boxes[n, 0] + 1) * -- (boxes[n, 3] - boxes[n, 1] + 1) + -- box_area - iw * ih -- ) -- overlaps[n, k] = iw * ih / ua +-# -------------------------------------------------------- +-# Fast R-CNN +-# Copyright (c) 2015 Microsoft +-# Licensed under The MIT License [see LICENSE for details] +-# Written by Sergey Karayev +-# -------------------------------------------------------- +- +-cimport cython +-import numpy as np +-cimport numpy as np +- +-DTYPE = np.float +-ctypedef np.float_t DTYPE_t +- +-def bbox_overlaps( +- np.ndarray[DTYPE_t, ndim=2] boxes, +- np.ndarray[DTYPE_t, ndim=2] query_boxes): +- """ +- Parameters +- ---------- +- boxes: (N, 4) ndarray of float +- query_boxes: (K, 4) ndarray of float +- Returns +- ------- +- overlaps: (N, K) ndarray of overlap between boxes and query_boxes +- """ +- cdef unsigned int N = boxes.shape[0] +- cdef unsigned int K = query_boxes.shape[0] +- cdef np.ndarray[DTYPE_t, ndim=2] overlaps = np.zeros((N, K), dtype=DTYPE) +- cdef DTYPE_t iw, ih, box_area +- cdef DTYPE_t ua +- cdef unsigned int k, n +- for k in range(K): +- box_area = ( +- (query_boxes[k, 2] - query_boxes[k, 0] + 1) * +- (query_boxes[k, 3] - query_boxes[k, 1] + 1) +- ) +- for n in range(N): +- iw = ( +- min(boxes[n, 2], query_boxes[k, 2]) - +- max(boxes[n, 0], query_boxes[k, 0]) + 1 +- ) +- if iw > 0: +- ih = ( +- min(boxes[n, 3], query_boxes[k, 3]) - +- max(boxes[n, 1], query_boxes[k, 1]) + 1 +- ) +- if ih > 0: +- ua = float( +- (boxes[n, 2] - boxes[n, 0] + 1) * +- (boxes[n, 3] - boxes[n, 1] + 1) + +- box_area - iw * ih +- ) +- overlaps[n, k] = iw * ih / ua - return overlaps \ No newline at end of file diff --git a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/eval_tools/setup.py b/contrib/ACL_PyTorch/Research/cv/detection/DSFD/eval_tools/setup.py @@ -6755,676 +6755,676 @@ index 53f56150a9..0000000000 --- a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/eval_tools/setup.py +++ /dev/null @@ -1,22 +0,0 @@ --# Copyright 2021 Huawei Technologies Co., Ltd --# --# 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. -- --#coding=utf-8 -- --from distutils.core import setup, Extension --from Cython.Build import cythonize --import numpy -- --package = Extension('bbox', ['box_overlaps.pyx'], include_dirs=[numpy.get_include()]) --setup(ext_modules=cythonize([package])) +-# Copyright 2021 Huawei Technologies Co., Ltd +-# +-# 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. +- +-#coding=utf-8 +- +-from distutils.core import setup, Extension +-from Cython.Build import cythonize +-import numpy +- +-package = Extension('bbox', ['box_overlaps.pyx'], include_dirs=[numpy.get_include()]) +-setup(ext_modules=cythonize([package])) diff --git a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/__init__.py b/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/__init__.py deleted file mode 100644 index e3b3268753..0000000000 --- a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ --# Copyright 2021 Huawei Technologies Co., Ltd --# --# 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. -- --#-*- coding:utf-8 -*- -- --from __future__ import division --from __future__ import absolute_import --from __future__ import print_function -- -- --from .functions import * --from .modules import * +-# Copyright 2021 Huawei Technologies Co., Ltd +-# +-# 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. +- +-#-*- coding:utf-8 -*- +- +-from __future__ import division +-from __future__ import absolute_import +-from __future__ import print_function +- +- +-from .functions import * +-from .modules import * diff --git a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/bbox_utils.py b/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/bbox_utils.py deleted file mode 100644 index 71766a3145..0000000000 --- a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/bbox_utils.py +++ /dev/null @@ -1,324 +0,0 @@ --# Copyright 2021 Huawei Technologies Co., Ltd --# --# 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. -- --#coding=utf-8 -- --from __future__ import division --from __future__ import absolute_import --from __future__ import print_function -- -- --import torch -- -- --def point_form(boxes): -- """ Convert prior_boxes to (xmin, ymin, xmax, ymax) -- representation for comparison to point form ground truth data. -- Args: -- boxes: (tensor) center-size default boxes from priorbox layers. -- Return: -- boxes: (tensor) Converted xmin, ymin, xmax, ymax form of boxes. -- """ -- return torch.cat((boxes[:, :2] - boxes[:, 2:] / 2, # xmin, ymin -- boxes[:, :2] + boxes[:, 2:] / 2), 1) # xmax, ymax -- -- --def center_size(boxes): -- """ Convert prior_boxes to (cx, cy, w, h) -- representation for comparison to center-size form ground truth data. -- Args: -- boxes: (tensor) point_form boxes -- Return: -- boxes: (tensor) Converted xmin, ymin, xmax, ymax form of boxes. -- """ -- return torch.cat([(boxes[:, 2:] + boxes[:, :2]) / 2, # cx, cy -- boxes[:, 2:] - boxes[:, :2]], 1) # w, h -- -- --def intersect(box_a, box_b): -- """ We resize both tensors to [A,B,2] without new malloc: -- [A,2] -> [A,1,2] -> [A,B,2] -- [B,2] -> [1,B,2] -> [A,B,2] -- Then we compute the area of intersect between box_a and box_b. -- Args: -- box_a: (tensor) bounding boxes, Shape: [A,4]. -- box_b: (tensor) bounding boxes, Shape: [B,4]. -- Return: -- (tensor) intersection area, Shape: [A,B]. -- """ -- A = box_a.size(0) -- B = box_b.size(0) -- max_xy = torch.min(box_a[:, 2:].unsqueeze(1).expand(A, B, 2), -- box_b[:, 2:].unsqueeze(0).expand(A, B, 2)) -- min_xy = torch.max(box_a[:, :2].unsqueeze(1).expand(A, B, 2), -- box_b[:, :2].unsqueeze(0).expand(A, B, 2)) -- inter = torch.clamp((max_xy - min_xy), min=0) -- return inter[:, :, 0] * inter[:, :, 1] -- -- --def jaccard(box_a, box_b): -- """Compute the jaccard overlap of two sets of boxes. The jaccard overlap -- is simply the intersection over union of two boxes. Here we operate on -- ground truth boxes and default boxes. -- E.g.: -- A ∩ B / A ∪ B = A ∩ B / (area(A) + area(B) - A ∩ B) -- Args: -- box_a: (tensor) Ground truth bounding boxes, Shape: [num_objects,4] -- box_b: (tensor) Prior boxes from priorbox layers, Shape: [num_priors,4] -- Return: -- jaccard overlap: (tensor) Shape: [box_a.size(0), box_b.size(0)] -- """ -- inter = intersect(box_a, box_b) -- area_a = ((box_a[:, 2] - box_a[:, 0]) * -- (box_a[:, 3] - box_a[:, 1])).unsqueeze(1).expand_as(inter) # [A,B] -- area_b = ((box_b[:, 2] - box_b[:, 0]) * -- (box_b[:, 3] - box_b[:, 1])).unsqueeze(0).expand_as(inter) # [A,B] -- union = area_a + area_b - inter -- return inter / union # [A,B] -- -- --def match(threshold, truths, priors, variances, labels, loc_t, conf_t, idx): -- """Match each prior box with the ground truth box of the highest jaccard -- overlap, encode the bounding boxes, then return the matched indices -- corresponding to both confidence and location preds. -- Args: -- threshold: (float) The overlap threshold used when mathing boxes. -- truths: (tensor) Ground truth boxes, Shape: [num_obj, num_priors]. -- priors: (tensor) Prior boxes from priorbox layers, Shape: [n_priors,4]. -- variances: (tensor) Variances corresponding to each prior coord, -- Shape: [num_priors, 4]. -- labels: (tensor) All the class labels for the image, Shape: [num_obj]. -- loc_t: (tensor) Tensor to be filled w/ endcoded location targets. -- conf_t: (tensor) Tensor to be filled w/ matched indices for conf preds. -- idx: (int) current batch index -- Return: -- The matched indices corresponding to 1)location and 2)confidence preds. -- """ -- # jaccard index -- overlaps = jaccard( -- truths, -- point_form(priors) -- ) -- # (Bipartite Matching) -- # [1,num_objects] best prior for each ground truth -- best_prior_overlap, best_prior_idx = overlaps.max(1, keepdim=True) -- # [1,num_priors] best ground truth for each prior -- best_truth_overlap, best_truth_idx = overlaps.max( -- 0, keepdim=True) # 0-2000 -- best_truth_idx.squeeze_(0) -- best_truth_overlap.squeeze_(0) -- best_prior_idx.squeeze_(1) -- best_prior_overlap.squeeze_(1) -- best_truth_overlap.index_fill_(0, best_prior_idx, 2) # ensure best prior -- # TODO refactor: index best_prior_idx with long tensor -- # ensure every gt matches with its prior of max overlap -- for j in range(best_prior_idx.size(0)): -- best_truth_idx[best_prior_idx[j]] = j -- _th1, _th2, _th3 = threshold # _th1 = 0.1 ,_th2 = 0.35,_th3 = 0.5 -- -- N = (torch.sum(best_prior_overlap >= _th2) + -- torch.sum(best_prior_overlap >= _th3)) // 2 -- matches = truths[best_truth_idx] # Shape: [num_priors,4] -- conf = labels[best_truth_idx] # Shape: [num_priors] -- conf[best_truth_overlap < _th2] = 0 # label as background -- -- best_truth_overlap_clone = best_truth_overlap.clone() -- add_idx = best_truth_overlap_clone.gt( -- _th1).eq(best_truth_overlap_clone.lt(_th2)) -- best_truth_overlap_clone[1 - add_idx] = 0 -- stage2_overlap, stage2_idx = best_truth_overlap_clone.sort(descending=True) -- -- stage2_overlap = stage2_overlap.gt(_th1) -- -- if N > 0: -- N = torch.sum(stage2_overlap[:N]) if torch.sum( -- stage2_overlap[:N]) < N else N -- conf[stage2_idx[:N]] += 1 -- -- loc = encode(matches, priors, variances) -- loc_t[idx] = loc # [num_priors,4] encoded offsets to learn -- conf_t[idx] = conf # [num_priors] top class label for each prior -- -- --def match_ssd(threshold, truths, priors, variances, labels, loc_t, conf_t, idx): -- """Match each prior box with the ground truth box of the highest jaccard -- overlap, encode the bounding boxes, then return the matched indices -- corresponding to both confidence and location preds. -- Args: -- threshold: (float) The overlap threshold used when mathing boxes. -- truths: (tensor) Ground truth boxes, Shape: [num_obj, num_priors]. -- priors: (tensor) Prior boxes from priorbox layers, Shape: [n_priors,4]. -- variances: (tensor) Variances corresponding to each prior coord, -- Shape: [num_priors, 4]. -- labels: (tensor) All the class labels for the image, Shape: [num_obj]. -- loc_t: (tensor) Tensor to be filled w/ endcoded location targets. -- conf_t: (tensor) Tensor to be filled w/ matched indices for conf preds. -- idx: (int) current batch index -- Return: -- The matched indices corresponding to 1)location and 2)confidence preds. -- """ -- # jaccard index -- overlaps = jaccard( -- truths, -- point_form(priors) -- ) -- # (Bipartite Matching) -- # [1,num_objects] best prior for each ground truth -- best_prior_overlap, best_prior_idx = overlaps.max(1, keepdim=True) -- # [1,num_priors] best ground truth for each prior -- best_truth_overlap, best_truth_idx = overlaps.max( -- 0, keepdim=True) # 0-2000 -- best_truth_idx.squeeze_(0) -- best_truth_overlap.squeeze_(0) -- best_prior_idx.squeeze_(1) -- best_prior_overlap.squeeze_(1) -- best_truth_overlap.index_fill_(0, best_prior_idx, 2) # ensure best prior -- # TODO refactor: index best_prior_idx with long tensor -- # ensure every gt matches with its prior of max overlap -- for j in range(best_prior_idx.size(0)): -- best_truth_idx[best_prior_idx[j]] = j -- matches = truths[best_truth_idx] # Shape: [num_priors,4] -- conf = labels[best_truth_idx] # Shape: [num_priors] -- conf[best_truth_overlap < threshold] = 0 # label as background -- loc = encode(matches, priors, variances) -- loc_t[idx] = loc # [num_priors,4] encoded offsets to learn -- conf_t[idx] = conf # [num_priors] top class label for each prior -- -- --def encode(matched, priors, variances): -- """Encode the variances from the priorbox layers into the ground truth boxes -- we have matched (based on jaccard overlap) with the prior boxes. -- Args: -- matched: (tensor) Coords of ground truth for each prior in point-form -- Shape: [num_priors, 4]. -- priors: (tensor) Prior boxes in center-offset form -- Shape: [num_priors,4]. -- variances: (list[float]) Variances of priorboxes -- Return: -- encoded boxes (tensor), Shape: [num_priors, 4] -- """ -- -- # dist b/t match center and prior's center -- g_cxcy = (matched[:, :2] + matched[:, 2:]) / 2 - priors[:, :2] -- # encode variance -- g_cxcy /= (variances[0] * priors[:, 2:]) -- # match wh / prior wh -- g_wh = (matched[:, 2:] - matched[:, :2]) / priors[:, 2:] -- #g_wh = torch.log(g_wh) / variances[1] -- g_wh = torch.log(g_wh) / variances[1] -- # return target for smooth_l1_loss -- return torch.cat([g_cxcy, g_wh], 1) # [num_priors,4] -- -- --# Adapted from https://github.com/Hakuyume/chainer-ssd --def decode(loc, priors, variances): -- """Decode locations from predictions using priors to undo -- the encoding we did for offset regression at train time. -- Args: -- loc (tensor): location predictions for loc layers, -- Shape: [num_priors,4] -- priors (tensor): Prior boxes in center-offset form. -- Shape: [num_priors,4]. -- variances: (list[float]) Variances of priorboxes -- Return: -- decoded bounding box predictions -- """ -- -- boxes = torch.cat(( -- priors[:, :2] + loc[:, :2] * variances[0] * priors[:, 2:], -- priors[:, 2:] * torch.exp(loc[:, 2:] * variances[1])), 1) -- boxes[:, :2] -= boxes[:, 2:] / 2 -- boxes[:, 2:] += boxes[:, :2] -- return boxes -- -- --def log_sum_exp(x): -- """Utility function for computing log_sum_exp while determining -- This will be used to determine unaveraged confidence loss across -- all examples in a batch. -- Args: -- x (Variable(tensor)): conf_preds from conf layers -- """ -- x_max = x.data.max() -- return torch.log(torch.sum(torch.exp(x - x_max), 1, keepdim=True)) + x_max -- -- --# Original author: Francisco Massa: --# https://github.com/fmassa/object-detection.torch --# Ported to PyTorch by Max deGroot (02/01/2017) --def nms(boxes, scores, overlap=0.5, top_k=200): -- """Apply non-maximum suppression at test time to avoid detecting too many -- overlapping bounding boxes for a given object. -- Args: -- boxes: (tensor) The location preds for the img, Shape: [num_priors,4]. -- scores: (tensor) The class predscores for the img, Shape:[num_priors]. -- overlap: (float) The overlap thresh for suppressing unnecessary boxes. -- top_k: (int) The Maximum number of box preds to consider. -- Return: -- The indices of the kept boxes with respect to num_priors. -- """ -- -- keep = scores.new(scores.size(0)).zero_().long() -- if boxes.numel() == 0: -- return keep -- x1 = boxes[:, 0] -- y1 = boxes[:, 1] -- x2 = boxes[:, 2] -- y2 = boxes[:, 3] -- area = torch.mul(x2 - x1, y2 - y1) -- v, idx = scores.sort(0) # sort in ascending order -- # I = I[v >= 0.01] -- idx = idx[-top_k:] # indices of the top-k largest vals -- xx1 = boxes.new() -- yy1 = boxes.new() -- xx2 = boxes.new() -- yy2 = boxes.new() -- w = boxes.new() -- h = boxes.new() -- -- # keep = torch.Tensor() -- count = 0 -- while idx.numel() > 0: -- i = idx[-1] # index of current largest val -- # keep.append(i) -- keep[count] = i -- count += 1 -- if idx.size(0) == 1: -- break -- idx = idx[:-1] # remove kept element from view -- # load bboxes of next highest vals -- torch.index_select(x1, 0, idx, out=xx1) -- torch.index_select(y1, 0, idx, out=yy1) -- torch.index_select(x2, 0, idx, out=xx2) -- torch.index_select(y2, 0, idx, out=yy2) -- # store element-wise max with next highest score -- xx1 = torch.clamp(xx1, min=x1[i]) -- yy1 = torch.clamp(yy1, min=y1[i]) -- xx2 = torch.clamp(xx2, max=x2[i]) -- yy2 = torch.clamp(yy2, max=y2[i]) -- w.resize_as_(xx2) -- h.resize_as_(yy2) -- w = xx2 - xx1 -- h = yy2 - yy1 -- # check sizes of xx1 and xx2.. after each iteration -- w = torch.clamp(w, min=0.0) -- h = torch.clamp(h, min=0.0) -- inter = w * h -- # IoU = i / (area(a) + area(b) - i) -- rem_areas = torch.index_select(area, 0, idx) # load remaining areas) -- union = (rem_areas - inter) + area[i] -- IoU = inter / union # store result in iou -- # keep only elements with an IoU <= overlap -- idx = idx[IoU.le(overlap)] -- return keep, count +-# Copyright 2021 Huawei Technologies Co., Ltd +-# +-# 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. +- +-#coding=utf-8 +- +-from __future__ import division +-from __future__ import absolute_import +-from __future__ import print_function +- +- +-import torch +- +- +-def point_form(boxes): +- """ Convert prior_boxes to (xmin, ymin, xmax, ymax) +- representation for comparison to point form ground truth data. +- Args: +- boxes: (tensor) center-size default boxes from priorbox layers. +- Return: +- boxes: (tensor) Converted xmin, ymin, xmax, ymax form of boxes. +- """ +- return torch.cat((boxes[:, :2] - boxes[:, 2:] / 2, # xmin, ymin +- boxes[:, :2] + boxes[:, 2:] / 2), 1) # xmax, ymax +- +- +-def center_size(boxes): +- """ Convert prior_boxes to (cx, cy, w, h) +- representation for comparison to center-size form ground truth data. +- Args: +- boxes: (tensor) point_form boxes +- Return: +- boxes: (tensor) Converted xmin, ymin, xmax, ymax form of boxes. +- """ +- return torch.cat([(boxes[:, 2:] + boxes[:, :2]) / 2, # cx, cy +- boxes[:, 2:] - boxes[:, :2]], 1) # w, h +- +- +-def intersect(box_a, box_b): +- """ We resize both tensors to [A,B,2] without new malloc: +- [A,2] -> [A,1,2] -> [A,B,2] +- [B,2] -> [1,B,2] -> [A,B,2] +- Then we compute the area of intersect between box_a and box_b. +- Args: +- box_a: (tensor) bounding boxes, Shape: [A,4]. +- box_b: (tensor) bounding boxes, Shape: [B,4]. +- Return: +- (tensor) intersection area, Shape: [A,B]. +- """ +- A = box_a.size(0) +- B = box_b.size(0) +- max_xy = torch.min(box_a[:, 2:].unsqueeze(1).expand(A, B, 2), +- box_b[:, 2:].unsqueeze(0).expand(A, B, 2)) +- min_xy = torch.max(box_a[:, :2].unsqueeze(1).expand(A, B, 2), +- box_b[:, :2].unsqueeze(0).expand(A, B, 2)) +- inter = torch.clamp((max_xy - min_xy), min=0) +- return inter[:, :, 0] * inter[:, :, 1] +- +- +-def jaccard(box_a, box_b): +- """Compute the jaccard overlap of two sets of boxes. The jaccard overlap +- is simply the intersection over union of two boxes. Here we operate on +- ground truth boxes and default boxes. +- E.g.: +- A ∩ B / A ∪ B = A ∩ B / (area(A) + area(B) - A ∩ B) +- Args: +- box_a: (tensor) Ground truth bounding boxes, Shape: [num_objects,4] +- box_b: (tensor) Prior boxes from priorbox layers, Shape: [num_priors,4] +- Return: +- jaccard overlap: (tensor) Shape: [box_a.size(0), box_b.size(0)] +- """ +- inter = intersect(box_a, box_b) +- area_a = ((box_a[:, 2] - box_a[:, 0]) * +- (box_a[:, 3] - box_a[:, 1])).unsqueeze(1).expand_as(inter) # [A,B] +- area_b = ((box_b[:, 2] - box_b[:, 0]) * +- (box_b[:, 3] - box_b[:, 1])).unsqueeze(0).expand_as(inter) # [A,B] +- union = area_a + area_b - inter +- return inter / union # [A,B] +- +- +-def match(threshold, truths, priors, variances, labels, loc_t, conf_t, idx): +- """Match each prior box with the ground truth box of the highest jaccard +- overlap, encode the bounding boxes, then return the matched indices +- corresponding to both confidence and location preds. +- Args: +- threshold: (float) The overlap threshold used when mathing boxes. +- truths: (tensor) Ground truth boxes, Shape: [num_obj, num_priors]. +- priors: (tensor) Prior boxes from priorbox layers, Shape: [n_priors,4]. +- variances: (tensor) Variances corresponding to each prior coord, +- Shape: [num_priors, 4]. +- labels: (tensor) All the class labels for the image, Shape: [num_obj]. +- loc_t: (tensor) Tensor to be filled w/ endcoded location targets. +- conf_t: (tensor) Tensor to be filled w/ matched indices for conf preds. +- idx: (int) current batch index +- Return: +- The matched indices corresponding to 1)location and 2)confidence preds. +- """ +- # jaccard index +- overlaps = jaccard( +- truths, +- point_form(priors) +- ) +- # (Bipartite Matching) +- # [1,num_objects] best prior for each ground truth +- best_prior_overlap, best_prior_idx = overlaps.max(1, keepdim=True) +- # [1,num_priors] best ground truth for each prior +- best_truth_overlap, best_truth_idx = overlaps.max( +- 0, keepdim=True) # 0-2000 +- best_truth_idx.squeeze_(0) +- best_truth_overlap.squeeze_(0) +- best_prior_idx.squeeze_(1) +- best_prior_overlap.squeeze_(1) +- best_truth_overlap.index_fill_(0, best_prior_idx, 2) # ensure best prior +- # TODO refactor: index best_prior_idx with long tensor +- # ensure every gt matches with its prior of max overlap +- for j in range(best_prior_idx.size(0)): +- best_truth_idx[best_prior_idx[j]] = j +- _th1, _th2, _th3 = threshold # _th1 = 0.1 ,_th2 = 0.35,_th3 = 0.5 +- +- N = (torch.sum(best_prior_overlap >= _th2) + +- torch.sum(best_prior_overlap >= _th3)) // 2 +- matches = truths[best_truth_idx] # Shape: [num_priors,4] +- conf = labels[best_truth_idx] # Shape: [num_priors] +- conf[best_truth_overlap < _th2] = 0 # label as background +- +- best_truth_overlap_clone = best_truth_overlap.clone() +- add_idx = best_truth_overlap_clone.gt( +- _th1).eq(best_truth_overlap_clone.lt(_th2)) +- best_truth_overlap_clone[1 - add_idx] = 0 +- stage2_overlap, stage2_idx = best_truth_overlap_clone.sort(descending=True) +- +- stage2_overlap = stage2_overlap.gt(_th1) +- +- if N > 0: +- N = torch.sum(stage2_overlap[:N]) if torch.sum( +- stage2_overlap[:N]) < N else N +- conf[stage2_idx[:N]] += 1 +- +- loc = encode(matches, priors, variances) +- loc_t[idx] = loc # [num_priors,4] encoded offsets to learn +- conf_t[idx] = conf # [num_priors] top class label for each prior +- +- +-def match_ssd(threshold, truths, priors, variances, labels, loc_t, conf_t, idx): +- """Match each prior box with the ground truth box of the highest jaccard +- overlap, encode the bounding boxes, then return the matched indices +- corresponding to both confidence and location preds. +- Args: +- threshold: (float) The overlap threshold used when mathing boxes. +- truths: (tensor) Ground truth boxes, Shape: [num_obj, num_priors]. +- priors: (tensor) Prior boxes from priorbox layers, Shape: [n_priors,4]. +- variances: (tensor) Variances corresponding to each prior coord, +- Shape: [num_priors, 4]. +- labels: (tensor) All the class labels for the image, Shape: [num_obj]. +- loc_t: (tensor) Tensor to be filled w/ endcoded location targets. +- conf_t: (tensor) Tensor to be filled w/ matched indices for conf preds. +- idx: (int) current batch index +- Return: +- The matched indices corresponding to 1)location and 2)confidence preds. +- """ +- # jaccard index +- overlaps = jaccard( +- truths, +- point_form(priors) +- ) +- # (Bipartite Matching) +- # [1,num_objects] best prior for each ground truth +- best_prior_overlap, best_prior_idx = overlaps.max(1, keepdim=True) +- # [1,num_priors] best ground truth for each prior +- best_truth_overlap, best_truth_idx = overlaps.max( +- 0, keepdim=True) # 0-2000 +- best_truth_idx.squeeze_(0) +- best_truth_overlap.squeeze_(0) +- best_prior_idx.squeeze_(1) +- best_prior_overlap.squeeze_(1) +- best_truth_overlap.index_fill_(0, best_prior_idx, 2) # ensure best prior +- # TODO refactor: index best_prior_idx with long tensor +- # ensure every gt matches with its prior of max overlap +- for j in range(best_prior_idx.size(0)): +- best_truth_idx[best_prior_idx[j]] = j +- matches = truths[best_truth_idx] # Shape: [num_priors,4] +- conf = labels[best_truth_idx] # Shape: [num_priors] +- conf[best_truth_overlap < threshold] = 0 # label as background +- loc = encode(matches, priors, variances) +- loc_t[idx] = loc # [num_priors,4] encoded offsets to learn +- conf_t[idx] = conf # [num_priors] top class label for each prior +- +- +-def encode(matched, priors, variances): +- """Encode the variances from the priorbox layers into the ground truth boxes +- we have matched (based on jaccard overlap) with the prior boxes. +- Args: +- matched: (tensor) Coords of ground truth for each prior in point-form +- Shape: [num_priors, 4]. +- priors: (tensor) Prior boxes in center-offset form +- Shape: [num_priors,4]. +- variances: (list[float]) Variances of priorboxes +- Return: +- encoded boxes (tensor), Shape: [num_priors, 4] +- """ +- +- # dist b/t match center and prior's center +- g_cxcy = (matched[:, :2] + matched[:, 2:]) / 2 - priors[:, :2] +- # encode variance +- g_cxcy /= (variances[0] * priors[:, 2:]) +- # match wh / prior wh +- g_wh = (matched[:, 2:] - matched[:, :2]) / priors[:, 2:] +- #g_wh = torch.log(g_wh) / variances[1] +- g_wh = torch.log(g_wh) / variances[1] +- # return target for smooth_l1_loss +- return torch.cat([g_cxcy, g_wh], 1) # [num_priors,4] +- +- +-# Adapted from https://github.com/Hakuyume/chainer-ssd +-def decode(loc, priors, variances): +- """Decode locations from predictions using priors to undo +- the encoding we did for offset regression at train time. +- Args: +- loc (tensor): location predictions for loc layers, +- Shape: [num_priors,4] +- priors (tensor): Prior boxes in center-offset form. +- Shape: [num_priors,4]. +- variances: (list[float]) Variances of priorboxes +- Return: +- decoded bounding box predictions +- """ +- +- boxes = torch.cat(( +- priors[:, :2] + loc[:, :2] * variances[0] * priors[:, 2:], +- priors[:, 2:] * torch.exp(loc[:, 2:] * variances[1])), 1) +- boxes[:, :2] -= boxes[:, 2:] / 2 +- boxes[:, 2:] += boxes[:, :2] +- return boxes +- +- +-def log_sum_exp(x): +- """Utility function for computing log_sum_exp while determining +- This will be used to determine unaveraged confidence loss across +- all examples in a batch. +- Args: +- x (Variable(tensor)): conf_preds from conf layers +- """ +- x_max = x.data.max() +- return torch.log(torch.sum(torch.exp(x - x_max), 1, keepdim=True)) + x_max +- +- +-# Original author: Francisco Massa: +-# https://github.com/fmassa/object-detection.torch +-# Ported to PyTorch by Max deGroot (02/01/2017) +-def nms(boxes, scores, overlap=0.5, top_k=200): +- """Apply non-maximum suppression at test time to avoid detecting too many +- overlapping bounding boxes for a given object. +- Args: +- boxes: (tensor) The location preds for the img, Shape: [num_priors,4]. +- scores: (tensor) The class predscores for the img, Shape:[num_priors]. +- overlap: (float) The overlap thresh for suppressing unnecessary boxes. +- top_k: (int) The Maximum number of box preds to consider. +- Return: +- The indices of the kept boxes with respect to num_priors. +- """ +- +- keep = scores.new(scores.size(0)).zero_().long() +- if boxes.numel() == 0: +- return keep +- x1 = boxes[:, 0] +- y1 = boxes[:, 1] +- x2 = boxes[:, 2] +- y2 = boxes[:, 3] +- area = torch.mul(x2 - x1, y2 - y1) +- v, idx = scores.sort(0) # sort in ascending order +- # I = I[v >= 0.01] +- idx = idx[-top_k:] # indices of the top-k largest vals +- xx1 = boxes.new() +- yy1 = boxes.new() +- xx2 = boxes.new() +- yy2 = boxes.new() +- w = boxes.new() +- h = boxes.new() +- +- # keep = torch.Tensor() +- count = 0 +- while idx.numel() > 0: +- i = idx[-1] # index of current largest val +- # keep.append(i) +- keep[count] = i +- count += 1 +- if idx.size(0) == 1: +- break +- idx = idx[:-1] # remove kept element from view +- # load bboxes of next highest vals +- torch.index_select(x1, 0, idx, out=xx1) +- torch.index_select(y1, 0, idx, out=yy1) +- torch.index_select(x2, 0, idx, out=xx2) +- torch.index_select(y2, 0, idx, out=yy2) +- # store element-wise max with next highest score +- xx1 = torch.clamp(xx1, min=x1[i]) +- yy1 = torch.clamp(yy1, min=y1[i]) +- xx2 = torch.clamp(xx2, max=x2[i]) +- yy2 = torch.clamp(yy2, max=y2[i]) +- w.resize_as_(xx2) +- h.resize_as_(yy2) +- w = xx2 - xx1 +- h = yy2 - yy1 +- # check sizes of xx1 and xx2.. after each iteration +- w = torch.clamp(w, min=0.0) +- h = torch.clamp(h, min=0.0) +- inter = w * h +- # IoU = i / (area(a) + area(b) - i) +- rem_areas = torch.index_select(area, 0, idx) # load remaining areas) +- union = (rem_areas - inter) + area[i] +- IoU = inter / union # store result in iou +- # keep only elements with an IoU <= overlap +- idx = idx[IoU.le(overlap)] +- return keep, count diff --git a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/functions/__init__.py b/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/functions/__init__.py deleted file mode 100644 index 9bc5349934..0000000000 --- a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/functions/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ --# Copyright 2021 Huawei Technologies Co., Ltd --# --# 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 .prior_box import PriorBox --from .detection import Detect -- --__all__=['Detect','PriorBox'] -- +-# Copyright 2021 Huawei Technologies Co., Ltd +-# +-# 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 .prior_box import PriorBox +-from .detection import Detect +- +-__all__=['Detect','PriorBox'] +- diff --git a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/functions/detection.py b/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/functions/detection.py deleted file mode 100644 index 94b23f9410..0000000000 --- a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/functions/detection.py +++ /dev/null @@ -1,87 +0,0 @@ --# Copyright 2021 Huawei Technologies Co., Ltd --# --# 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. -- --# coding=utf-8 -- --from __future__ import division --from __future__ import absolute_import --from __future__ import print_function -- --import torch -- --from ..bbox_utils import decode, nms --from torch.autograd import Function -- -- --class Detect(Function): -- """At test time, Detect is the final layer of SSD. Decode location preds, -- apply non-maximum suppression to location predictions based on conf -- scores and threshold to a top_k number of output predictions for both -- confidence score and locations. -- """ -- -- def __init__(self, cfg): -- self.num_classes = cfg.NUM_CLASSES -- self.top_k = cfg.TOP_K -- self.nms_thresh = cfg.NMS_THRESH -- self.conf_thresh = cfg.CONF_THRESH -- self.variance = cfg.VARIANCE -- self.nms_top_k = cfg.NMS_TOP_K -- -- def forward(self, loc_data, conf_data, prior_data): -- """ -- Args: -- loc_data: (tensor) Loc preds from loc layers -- Shape: [batch,num_priors*4] -- conf_data: (tensor) Shape: Conf preds from conf layers -- Shape: [batch*num_priors,num_classes] -- prior_data: (tensor) Prior boxes and variances from priorbox layers -- Shape: [1,num_priors,4] -- """ -- num = loc_data.size(0) -- num_priors = prior_data.size(0) -- -- conf_preds = conf_data.view( -- num, num_priors, self.num_classes).transpose(2, 1) -- batch_priors = prior_data.view(-1, num_priors, -- 4).expand(num, num_priors, 4) -- batch_priors = batch_priors.contiguous().view(-1, 4) -- -- decoded_boxes = decode(loc_data.view(-1, 4), -- batch_priors, self.variance) -- decoded_boxes = decoded_boxes.view(num, num_priors, 4) -- -- output = torch.zeros(num, self.num_classes, self.top_k, 5) -- -- for i in range(num): -- boxes = decoded_boxes[i].clone() -- conf_scores = conf_preds[i].clone() -- -- for cl in range(1, self.num_classes): -- c_mask = conf_scores[cl].gt(self.conf_thresh) -- scores = conf_scores[cl][c_mask] -- -- #VIVID -- if scores.size(0) == 0: -- continue -- l_mask = c_mask.unsqueeze(1).expand_as(boxes) -- boxes_ = boxes[l_mask].view(-1, 4) -- ids, count = nms(boxes_, scores, self.nms_thresh, self.nms_top_k) -- count = count if count < self.top_k else self.top_k -- -- output[i, cl, :count] = torch.cat((scores[ids[:count]].unsqueeze(1), -- boxes_[ids[:count]]), 1) -- print("get test detect res:", output) -- -- return output +-# Copyright 2021 Huawei Technologies Co., Ltd +-# +-# 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. +- +-# coding=utf-8 +- +-from __future__ import division +-from __future__ import absolute_import +-from __future__ import print_function +- +-import torch +- +-from ..bbox_utils import decode, nms +-from torch.autograd import Function +- +- +-class Detect(Function): +- """At test time, Detect is the final layer of SSD. Decode location preds, +- apply non-maximum suppression to location predictions based on conf +- scores and threshold to a top_k number of output predictions for both +- confidence score and locations. +- """ +- +- def __init__(self, cfg): +- self.num_classes = cfg.NUM_CLASSES +- self.top_k = cfg.TOP_K +- self.nms_thresh = cfg.NMS_THRESH +- self.conf_thresh = cfg.CONF_THRESH +- self.variance = cfg.VARIANCE +- self.nms_top_k = cfg.NMS_TOP_K +- +- def forward(self, loc_data, conf_data, prior_data): +- """ +- Args: +- loc_data: (tensor) Loc preds from loc layers +- Shape: [batch,num_priors*4] +- conf_data: (tensor) Shape: Conf preds from conf layers +- Shape: [batch*num_priors,num_classes] +- prior_data: (tensor) Prior boxes and variances from priorbox layers +- Shape: [1,num_priors,4] +- """ +- num = loc_data.size(0) +- num_priors = prior_data.size(0) +- +- conf_preds = conf_data.view( +- num, num_priors, self.num_classes).transpose(2, 1) +- batch_priors = prior_data.view(-1, num_priors, +- 4).expand(num, num_priors, 4) +- batch_priors = batch_priors.contiguous().view(-1, 4) +- +- decoded_boxes = decode(loc_data.view(-1, 4), +- batch_priors, self.variance) +- decoded_boxes = decoded_boxes.view(num, num_priors, 4) +- +- output = torch.zeros(num, self.num_classes, self.top_k, 5) +- +- for i in range(num): +- boxes = decoded_boxes[i].clone() +- conf_scores = conf_preds[i].clone() +- +- for cl in range(1, self.num_classes): +- c_mask = conf_scores[cl].gt(self.conf_thresh) +- scores = conf_scores[cl][c_mask] +- +- #VIVID +- if scores.size(0) == 0: +- continue +- l_mask = c_mask.unsqueeze(1).expand_as(boxes) +- boxes_ = boxes[l_mask].view(-1, 4) +- ids, count = nms(boxes_, scores, self.nms_thresh, self.nms_top_k) +- count = count if count < self.top_k else self.top_k +- +- output[i, cl, :count] = torch.cat((scores[ids[:count]].unsqueeze(1), +- boxes_[ids[:count]]), 1) +- print("get test detect res:", output) +- +- return output diff --git a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/functions/prior_box.py b/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/functions/prior_box.py deleted file mode 100644 index b49b348072..0000000000 --- a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/functions/prior_box.py +++ /dev/null @@ -1,78 +0,0 @@ --# Copyright 2021 Huawei Technologies Co., Ltd --# --# 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. -- --#-*- coding:utf-8 -*- -- --from __future__ import division --from __future__ import absolute_import --from __future__ import print_function -- --import torch --from itertools import product as product --import math -- -- --class PriorBox(object): -- """Compute priorbox coordinates in center-offset form for each source -- feature map. -- """ -- -- def __init__(self, input_size, feature_maps,cfg,pal=2): -- super(PriorBox, self).__init__() -- self.imh = input_size[0] -- self.imw = input_size[1] -- # number of priors for feature map location (either 4 or 6) -- self.variance = cfg.VARIANCE or [0.1] -- #self.feature_maps = cfg.FEATURE_MAPS -- if pal==1: -- self.min_sizes = cfg.ANCHOR_SIZES1 -- elif pal==2: -- self.min_sizes = cfg.ANCHOR_SIZES2 -- self.aspect_ratio = cfg.ASPECT_RATIO -- self.steps = cfg.STEPS -- self.clip = cfg.CLIP -- for v in self.variance: -- if v <= 0: -- raise ValueError('Variances must be greater than 0') -- self.feature_maps = feature_maps -- -- -- def forward(self): -- mean = [] -- for k in range(len(self.feature_maps)): -- feath = self.feature_maps[k][0] -- featw = self.feature_maps[k][1] -- for i, j in product(range(feath), range(featw)): -- f_kw = self.imw / self.steps[k] -- f_kh = self.imh / self.steps[k] -- -- cx = (j + 0.5) / f_kw -- cy = (i + 0.5) / f_kh -- -- s_kw = self.min_sizes[k] / self.imw -- s_kh = self.min_sizes[k] / self.imh -- for ar in self.aspect_ratio: -- mean += [cx, cy, s_kw/math.sqrt(ar), s_kh*math.sqrt(ar)] -- -- output = torch.Tensor(mean).view(-1, 4) -- if self.clip: -- output.clamp_(max=1, min=0) -- return output -- -- --if __name__ == '__main__': -- from data.config import cfg -- p = PriorBox([640, 640], cfg) -- out = p.forward() -- print(out.size()) +-# Copyright 2021 Huawei Technologies Co., Ltd +-# +-# 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. +- +-#-*- coding:utf-8 -*- +- +-from __future__ import division +-from __future__ import absolute_import +-from __future__ import print_function +- +-import torch +-from itertools import product as product +-import math +- +- +-class PriorBox(object): +- """Compute priorbox coordinates in center-offset form for each source +- feature map. +- """ +- +- def __init__(self, input_size, feature_maps,cfg,pal=2): +- super(PriorBox, self).__init__() +- self.imh = input_size[0] +- self.imw = input_size[1] +- # number of priors for feature map location (either 4 or 6) +- self.variance = cfg.VARIANCE or [0.1] +- #self.feature_maps = cfg.FEATURE_MAPS +- if pal==1: +- self.min_sizes = cfg.ANCHOR_SIZES1 +- elif pal==2: +- self.min_sizes = cfg.ANCHOR_SIZES2 +- self.aspect_ratio = cfg.ASPECT_RATIO +- self.steps = cfg.STEPS +- self.clip = cfg.CLIP +- for v in self.variance: +- if v <= 0: +- raise ValueError('Variances must be greater than 0') +- self.feature_maps = feature_maps +- +- +- def forward(self): +- mean = [] +- for k in range(len(self.feature_maps)): +- feath = self.feature_maps[k][0] +- featw = self.feature_maps[k][1] +- for i, j in product(range(feath), range(featw)): +- f_kw = self.imw / self.steps[k] +- f_kh = self.imh / self.steps[k] +- +- cx = (j + 0.5) / f_kw +- cy = (i + 0.5) / f_kh +- +- s_kw = self.min_sizes[k] / self.imw +- s_kh = self.min_sizes[k] / self.imh +- for ar in self.aspect_ratio: +- mean += [cx, cy, s_kw/math.sqrt(ar), s_kh*math.sqrt(ar)] +- +- output = torch.Tensor(mean).view(-1, 4) +- if self.clip: +- output.clamp_(max=1, min=0) +- return output +- +- +-if __name__ == '__main__': +- from data.config import cfg +- p = PriorBox([640, 640], cfg) +- out = p.forward() +- print(out.size()) diff --git a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/modules/__init__.py b/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/modules/__init__.py deleted file mode 100644 index 1ee0f9eb05..0000000000 --- a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/modules/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ --# Copyright 2021 Huawei Technologies Co., Ltd --# --# 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. -- --#-*- coding:utf-8 -*- -- --from __future__ import division --from __future__ import absolute_import --from __future__ import print_function -- -- --from .l2norm import L2Norm --from .multibox_loss import MultiBoxLoss -- --__all__ = ['L2Norm', 'MultiBoxLoss'] -- +-# Copyright 2021 Huawei Technologies Co., Ltd +-# +-# 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. +- +-#-*- coding:utf-8 -*- +- +-from __future__ import division +-from __future__ import absolute_import +-from __future__ import print_function +- +- +-from .l2norm import L2Norm +-from .multibox_loss import MultiBoxLoss +- +-__all__ = ['L2Norm', 'MultiBoxLoss'] +- diff --git a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/modules/l2norm.py b/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/modules/l2norm.py deleted file mode 100644 index 009890b8dd..0000000000 --- a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/modules/l2norm.py +++ /dev/null @@ -1,50 +0,0 @@ --# Copyright 2021 Huawei Technologies Co., Ltd --# --# 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. -- --#-*- coding:utf-8 -*- -- --from __future__ import division --from __future__ import absolute_import --from __future__ import print_function -- -- --import torch --import torch.nn as nn --import torch.nn.init as init --from torch.autograd import Function --from torch.autograd import Variable -- -- -- --class L2Norm(nn.Module): -- def __init__(self,n_channels, scale): -- super(L2Norm,self).__init__() -- self.n_channels = n_channels -- self.gamma = scale or None -- self.eps = 1e-10 -- self.weight = nn.Parameter(torch.Tensor(self.n_channels)) -- self.reset_parameters() -- -- def reset_parameters(self): -- init.constant(self.weight,self.gamma) -- -- def forward(self, x): -- norm = x.pow(2).sum(dim=1, keepdim=True).sqrt()+self.eps -- #x /= norm -- x = torch.div(x,norm) -- out = self.weight.unsqueeze(0).unsqueeze(2).unsqueeze(3).expand_as(x) * x -- return out -- -- +-# Copyright 2021 Huawei Technologies Co., Ltd +-# +-# 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. +- +-#-*- coding:utf-8 -*- +- +-from __future__ import division +-from __future__ import absolute_import +-from __future__ import print_function +- +- +-import torch +-import torch.nn as nn +-import torch.nn.init as init +-from torch.autograd import Function +-from torch.autograd import Variable +- +- +- +-class L2Norm(nn.Module): +- def __init__(self,n_channels, scale): +- super(L2Norm,self).__init__() +- self.n_channels = n_channels +- self.gamma = scale or None +- self.eps = 1e-10 +- self.weight = nn.Parameter(torch.Tensor(self.n_channels)) +- self.reset_parameters() +- +- def reset_parameters(self): +- init.constant(self.weight,self.gamma) +- +- def forward(self, x): +- norm = x.pow(2).sum(dim=1, keepdim=True).sqrt()+self.eps +- #x /= norm +- x = torch.div(x,norm) +- out = self.weight.unsqueeze(0).unsqueeze(2).unsqueeze(3).expand_as(x) * x +- return out +- +- - \ No newline at end of file diff --git a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/modules/multibox_loss.py b/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/modules/multibox_loss.py @@ -7433,964 +7433,964 @@ index 0f938211d3..0000000000 --- a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/layers/modules/multibox_loss.py +++ /dev/null @@ -1,134 +0,0 @@ --# Copyright 2021 Huawei Technologies Co., Ltd --# --# 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. -- --#-*- coding:utf-8 -*- -- --from __future__ import division --from __future__ import absolute_import --from __future__ import print_function -- --import math --import torch --import torch.nn as nn --import torch.nn.functional as F --from torch.autograd import Variable -- -- --from ..bbox_utils import match, log_sum_exp, match_ssd -- -- --class MultiBoxLoss(nn.Module): -- """SSD Weighted Loss Function -- Compute Targets: -- 1) Produce Confidence Target Indices by matching ground truth boxes -- with (default) 'priorboxes' that have jaccard index > threshold parameter -- (default threshold: 0.5). -- 2) Produce localization target by 'encoding' variance into offsets of ground -- truth boxes and their matched 'priorboxes'. -- 3) Hard negative mining to filter the excessive number of negative examples -- that comes with using a large number of default bounding boxes. -- (default negative:positive ratio 3:1) -- Objective Loss: -- L(x,c,l,g) = (Lconf(x, c) + αLloc(x,l,g)) / N -- Where, Lconf is the CrossEntropy Loss and Lloc is the SmoothL1 Loss -- weighted by α which is set to 1 by cross val. -- Args: -- c: class confidences, -- l: predicted boxes, -- g: ground truth boxes -- N: number of matched default boxes -- See: https://arxiv.org/pdf/1512.02325.pdf for more details. -- """ -- -- def __init__(self, cfg, use_gpu=True): -- super(MultiBoxLoss, self).__init__() -- self.use_gpu = use_gpu -- self.num_classes = cfg.NUM_CLASSES -- self.negpos_ratio = cfg.NEG_POS_RATIOS -- self.variance = cfg.VARIANCE -- -- self.threshold = cfg.FACE.OVERLAP_THRESH -- self.match = match_ssd -- -- def forward(self, predictions, targets): -- """Multibox Loss -- Args: -- predictions (tuple): A tuple containing loc preds, conf preds, -- and prior boxes from SSD net. -- conf shape: torch.size(batch_size,num_priors,num_classes) -- loc shape: torch.size(batch_size,num_priors,4) -- priors shape: torch.size(num_priors,4) -- -- targets (tensor): Ground truth boxes and labels for a batch, -- shape: [batch_size,num_objs,5] (last idx is the label). -- """ -- loc_data, conf_data, priors = predictions -- num = loc_data.size(0) -- priors = priors[:loc_data.size(1), :] -- num_priors = (priors.size(0)) -- num_classes = self.num_classes -- -- # match priors (default boxes) and ground truth boxes -- loc_t = torch.Tensor(num, num_priors, 4) -- conf_t = torch.LongTensor(num, num_priors) -- for idx in range(num): -- truths = targets[idx][:, :-1].data -- labels = targets[idx][:, -1].data -- defaults = priors.data -- self.match(self.threshold, truths, defaults, self.variance, labels, -- loc_t, conf_t, idx) -- if self.use_gpu: -- loc_t = loc_t.cuda() -- conf_t = conf_t.cuda() -- # wrap targets -- loc_t = Variable(loc_t, requires_grad=False) -- conf_t = Variable(conf_t, requires_grad=False) -- -- pos = conf_t > 0 -- num_pos = pos.sum(dim=1, keepdim=True) -- # Localization Loss (Smooth L1) -- # Shape: [batch,num_priors,4] -- pos_idx = pos.unsqueeze(pos.dim()).expand_as(loc_data) -- loc_p = loc_data[pos_idx].view(-1, 4) -- loc_t = loc_t[pos_idx].view(-1, 4) -- loss_l = F.smooth_l1_loss(loc_p, loc_t, size_average=False) -- # print(loc_p) -- # Compute max conf across batch for hard negative mining -- batch_conf = conf_data.view(-1, self.num_classes) -- loss_c = log_sum_exp(batch_conf) - \ -- batch_conf.gather(1, conf_t.view(-1, 1)) -- -- # Hard Negative Mining -- loss_c[pos.view(-1, 1)] = 0 # filter out pos boxes for now -- loss_c = loss_c.view(num, -1) -- _, loss_idx = loss_c.sort(1, descending=True) -- _, idx_rank = loss_idx.sort(1) -- num_pos = pos.long().sum(1, keepdim=True) -- num_neg = torch.clamp(self.negpos_ratio * -- num_pos, max=pos.size(1) - 1) -- neg = idx_rank < num_neg.expand_as(idx_rank) -- -- # Confidence Loss Including Positive and Negative Examples -- pos_idx = pos.unsqueeze(2).expand_as(conf_data) -- neg_idx = neg.unsqueeze(2).expand_as(conf_data) -- conf_p = conf_data[(pos_idx + neg_idx).gt(0) -- ].view(-1, self.num_classes) -- targets_weighted = conf_t[(pos + neg).gt(0)] -- loss_c = F.cross_entropy(conf_p, targets_weighted, size_average=False) -- -- # Sum of losses: L(x,c,l,g) = (Lconf(x, c) + αLloc(x,l,g)) / N -- N = num_pos.data.sum() if num_pos.data.sum() > 0 else num -- loss_l /= N -- loss_c /= N -- return loss_l, loss_c +-# Copyright 2021 Huawei Technologies Co., Ltd +-# +-# 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. +- +-#-*- coding:utf-8 -*- +- +-from __future__ import division +-from __future__ import absolute_import +-from __future__ import print_function +- +-import math +-import torch +-import torch.nn as nn +-import torch.nn.functional as F +-from torch.autograd import Variable +- +- +-from ..bbox_utils import match, log_sum_exp, match_ssd +- +- +-class MultiBoxLoss(nn.Module): +- """SSD Weighted Loss Function +- Compute Targets: +- 1) Produce Confidence Target Indices by matching ground truth boxes +- with (default) 'priorboxes' that have jaccard index > threshold parameter +- (default threshold: 0.5). +- 2) Produce localization target by 'encoding' variance into offsets of ground +- truth boxes and their matched 'priorboxes'. +- 3) Hard negative mining to filter the excessive number of negative examples +- that comes with using a large number of default bounding boxes. +- (default negative:positive ratio 3:1) +- Objective Loss: +- L(x,c,l,g) = (Lconf(x, c) + αLloc(x,l,g)) / N +- Where, Lconf is the CrossEntropy Loss and Lloc is the SmoothL1 Loss +- weighted by α which is set to 1 by cross val. +- Args: +- c: class confidences, +- l: predicted boxes, +- g: ground truth boxes +- N: number of matched default boxes +- See: https://arxiv.org/pdf/1512.02325.pdf for more details. +- """ +- +- def __init__(self, cfg, use_gpu=True): +- super(MultiBoxLoss, self).__init__() +- self.use_gpu = use_gpu +- self.num_classes = cfg.NUM_CLASSES +- self.negpos_ratio = cfg.NEG_POS_RATIOS +- self.variance = cfg.VARIANCE +- +- self.threshold = cfg.FACE.OVERLAP_THRESH +- self.match = match_ssd +- +- def forward(self, predictions, targets): +- """Multibox Loss +- Args: +- predictions (tuple): A tuple containing loc preds, conf preds, +- and prior boxes from SSD net. +- conf shape: torch.size(batch_size,num_priors,num_classes) +- loc shape: torch.size(batch_size,num_priors,4) +- priors shape: torch.size(num_priors,4) +- +- targets (tensor): Ground truth boxes and labels for a batch, +- shape: [batch_size,num_objs,5] (last idx is the label). +- """ +- loc_data, conf_data, priors = predictions +- num = loc_data.size(0) +- priors = priors[:loc_data.size(1), :] +- num_priors = (priors.size(0)) +- num_classes = self.num_classes +- +- # match priors (default boxes) and ground truth boxes +- loc_t = torch.Tensor(num, num_priors, 4) +- conf_t = torch.LongTensor(num, num_priors) +- for idx in range(num): +- truths = targets[idx][:, :-1].data +- labels = targets[idx][:, -1].data +- defaults = priors.data +- self.match(self.threshold, truths, defaults, self.variance, labels, +- loc_t, conf_t, idx) +- if self.use_gpu: +- loc_t = loc_t.cuda() +- conf_t = conf_t.cuda() +- # wrap targets +- loc_t = Variable(loc_t, requires_grad=False) +- conf_t = Variable(conf_t, requires_grad=False) +- +- pos = conf_t > 0 +- num_pos = pos.sum(dim=1, keepdim=True) +- # Localization Loss (Smooth L1) +- # Shape: [batch,num_priors,4] +- pos_idx = pos.unsqueeze(pos.dim()).expand_as(loc_data) +- loc_p = loc_data[pos_idx].view(-1, 4) +- loc_t = loc_t[pos_idx].view(-1, 4) +- loss_l = F.smooth_l1_loss(loc_p, loc_t, size_average=False) +- # print(loc_p) +- # Compute max conf across batch for hard negative mining +- batch_conf = conf_data.view(-1, self.num_classes) +- loss_c = log_sum_exp(batch_conf) - \ +- batch_conf.gather(1, conf_t.view(-1, 1)) +- +- # Hard Negative Mining +- loss_c[pos.view(-1, 1)] = 0 # filter out pos boxes for now +- loss_c = loss_c.view(num, -1) +- _, loss_idx = loss_c.sort(1, descending=True) +- _, idx_rank = loss_idx.sort(1) +- num_pos = pos.long().sum(1, keepdim=True) +- num_neg = torch.clamp(self.negpos_ratio * +- num_pos, max=pos.size(1) - 1) +- neg = idx_rank < num_neg.expand_as(idx_rank) +- +- # Confidence Loss Including Positive and Negative Examples +- pos_idx = pos.unsqueeze(2).expand_as(conf_data) +- neg_idx = neg.unsqueeze(2).expand_as(conf_data) +- conf_p = conf_data[(pos_idx + neg_idx).gt(0) +- ].view(-1, self.num_classes) +- targets_weighted = conf_t[(pos + neg).gt(0)] +- loss_c = F.cross_entropy(conf_p, targets_weighted, size_average=False) +- +- # Sum of losses: L(x,c,l,g) = (Lconf(x, c) + αLloc(x,l,g)) / N +- N = num_pos.data.sum() if num_pos.data.sum() > 0 else num +- loss_l /= N +- loss_c /= N +- return loss_l, loss_c diff --git a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/models/DSFD_resnet.py b/contrib/ACL_PyTorch/Research/cv/detection/DSFD/models/DSFD_resnet.py deleted file mode 100644 index 22e005a5c2..0000000000 --- a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/models/DSFD_resnet.py +++ /dev/null @@ -1,438 +0,0 @@ --# Copyright 2021 Huawei Technologies Co., Ltd --# --# 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. -- --#coding=utf-8 --from __future__ import division --from __future__ import print_function --from __future__ import absolute_import -- --import torch --import torch.nn as nn --import torch.nn.functional as F --import torch.nn.init as init -- --from torch.autograd import Variable -- --from layers import * --from data.config import cur_config as cfg -- --def conv3x3(in_planes, out_planes, stride=1, bias=False): -- """3x3 convolution with padding""" -- return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, -- padding=1, bias=bias) -- -- --def conv1x1(in_planes, out_planes, stride=1): -- """1x1 convolution""" -- return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False) -- -- --class BasicBlock(nn.Module): -- expansion = 1 -- -- def __init__(self, inplanes, planes, stride=1, downsample=None): -- super(BasicBlock, self).__init__() -- self.conv1 = conv3x3(inplanes, planes, stride) -- self.bn1 = nn.BatchNorm2d(planes) -- self.relu = nn.ReLU(inplace=True) -- self.conv2 = conv3x3(planes, planes) -- self.bn2 = nn.BatchNorm2d(planes) -- self.downsample = downsample -- self.stride = stride -- -- def forward(self, x): -- residual = x -- -- out = self.conv1(x) -- out = self.bn1(out) -- out = self.relu(out) -- -- out = self.conv2(out) -- out = self.bn2(out) -- -- if self.downsample is not None: -- residual = self.downsample(x) -- -- out += residual -- out = self.relu(out) -- -- return out -- -- --class Bottleneck(nn.Module): -- expansion = 4 -- -- def __init__(self, inplanes, planes, stride=1, downsample=None): -- super(Bottleneck, self).__init__() -- self.conv1 = conv1x1(inplanes, planes) -- self.bn1 = nn.BatchNorm2d(planes) -- self.conv2 = conv3x3(planes, planes, stride) -- self.bn2 = nn.BatchNorm2d(planes) -- self.conv3 = conv1x1(planes, planes * self.expansion) -- self.bn3 = nn.BatchNorm2d(planes * self.expansion) -- self.relu = nn.ReLU(inplace=True) -- self.downsample = downsample -- self.stride = stride -- -- def forward(self, x): -- residual = x -- -- out = self.conv1(x) -- out = self.bn1(out) -- out = self.relu(out) -- -- out = self.conv2(out) -- out = self.bn2(out) -- out = self.relu(out) -- -- out = self.conv3(out) -- out = self.bn3(out) -- -- if self.downsample is not None: -- residual = self.downsample(x) -- -- out += residual -- out = self.relu(out) -- -- return out -- -- --class ResNet(nn.Module): -- -- def __init__(self, block, layers): -- super(ResNet, self).__init__() -- self.inplanes = 64 -- self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, -- bias=False) -- self.bn1 = nn.BatchNorm2d(64) -- self.relu = nn.ReLU(inplace=True) -- self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) -- self.layer1 = self._make_layer(block, 64, layers[0]) -- self.layer2 = self._make_layer(block, 128, layers[1], stride=2) -- self.layer3 = self._make_layer(block, 256, layers[2], stride=2) -- self.layer4 = self._make_layer(block, 512, layers[3], stride=2) -- -- def _make_layer(self, block, planes, blocks, stride=1): -- downsample = None -- if stride != 1 or self.inplanes != planes * block.expansion: -- downsample = nn.Sequential( -- conv1x1(self.inplanes, planes * block.expansion, stride), -- nn.BatchNorm2d(planes * block.expansion), -- ) -- -- layers = [] -- layers.append(block(self.inplanes, planes, stride, downsample)) -- self.inplanes = planes * block.expansion -- for _ in range(1, blocks): -- layers.append(block(self.inplanes, planes)) -- -- return nn.Sequential(*layers) -- -- def forward(self, x): -- sources = [] -- -- x = self.conv1(x) -- x = self.bn1(x) -- x = self.relu(x) -- x = self.maxpool(x) -- -- x = self.layer1(x) -- sources += [x] -- -- x = self.layer2(x) -- sources += [x] -- -- x = self.layer3(x) -- sources += [x] -- -- x = self.layer4(x) -- sources += [x] -- -- return sources -- -- --class FEM(nn.Module): -- """docstring for FEM""" -- -- def __init__(self, in_planes): -- super(FEM, self).__init__() -- inter_planes = in_planes // 3 -- inter_planes1 = in_planes - 2 * inter_planes -- self.branch1 = nn.Conv2d( -- in_planes, inter_planes, kernel_size=3, stride=1, padding=3, dilation=3) -- -- self.branch2 = nn.Sequential( -- nn.Conv2d(in_planes, inter_planes, kernel_size=3, -- stride=1, padding=3, dilation=3), -- nn.ReLU(inplace=True), -- nn.Conv2d(inter_planes, inter_planes, kernel_size=3, -- stride=1, padding=3, dilation=3) -- ) -- self.branch3 = nn.Sequential( -- nn.Conv2d(in_planes, inter_planes1, kernel_size=3, -- stride=1, padding=3, dilation=3), -- nn.ReLU(inplace=True), -- nn.Conv2d(inter_planes1, inter_planes1, kernel_size=3, -- stride=1, padding=3, dilation=3), -- nn.ReLU(inplace=True), -- nn.Conv2d(inter_planes1, inter_planes1, kernel_size=3, -- stride=1, padding=3, dilation=3) -- ) -- -- def forward(self, x): -- x1 = self.branch1(x) -- x2 = self.branch2(x) -- x3 = self.branch3(x) -- out = torch.cat((x1, x2, x3), dim=1) -- out = F.relu(out, inplace=True) -- return out -- -- --class DSFD(nn.Module): -- """docstring for SRN""" -- -- def __init__(self, phase, base, extras, fem_modules, head1, head2, num_classes=2): -- super(DSFD, self).__init__() -- self.resnet = base -- self.phase = phase -- self.num_classes = num_classes -- self.extras = nn.ModuleList(extras) -- -- self.fpn_topdown = nn.ModuleList(fem_modules[0]) -- self.fpn_latlayer = nn.ModuleList(fem_modules[1]) -- self.fpn_fem = nn.ModuleList(fem_modules[2]) -- -- self.loc_pal1 = nn.ModuleList(head1[0]) -- self.conf_pal1 = nn.ModuleList(head1[1]) -- self.loc_pal2 = nn.ModuleList(head2[0]) -- self.conf_pal2 = nn.ModuleList(head2[1]) -- -- if self.phase == 'test': -- self.softmax = nn.Softmax(dim=-1) -- self.detect = Detect(cfg) -- -- def _upsample_prod(self, x, y): -- _, _, H, W = y.size() -- return F.upsample(x, size=(H, W), mode='bilinear') * y -- -- def forward(self, x): -- size = x.size()[2:] -- of1, of2, of3, of4 = self.resnet(x) -- -- x = of4 -- for i in range(2): -- x = F.relu(self.extras[i](x), inplace=True) -- of5 = x -- -- for i in range(2, len(self.extras)): -- x = F.relu(self.extras[i](x), inplace=True) -- of6 = x -- -- conv7 = F.relu(self.fpn_topdown[0](of6), inplace=True) -- -- x = F.relu(self.fpn_topdown[1](conv7), inplace=True) -- conv6 = F.relu(self._upsample_prod( -- x, self.fpn_latlayer[0](of5)), inplace=True) -- -- x = F.relu(self.fpn_topdown[2](conv6), inplace=True) -- conv5 = F.relu(self._upsample_prod( -- x, self.fpn_latlayer[1](of4)), inplace=True) -- -- x = F.relu(self.fpn_topdown[3](conv5), inplace=True) -- conv4 = F.relu(self._upsample_prod( -- x, self.fpn_latlayer[2](of3)), inplace=True) -- -- x = F.relu(self.fpn_topdown[4](conv4), inplace=True) -- conv3 = F.relu(self._upsample_prod( -- x, self.fpn_latlayer[3](of2)), inplace=True) -- -- x = F.relu(self.fpn_topdown[5](conv3), inplace=True) -- conv2 = F.relu(self._upsample_prod( -- x, self.fpn_latlayer[4](of1)), inplace=True) -- -- ef1 = self.fpn_fem[0](conv2) -- ef2 = self.fpn_fem[1](conv3) -- ef3 = self.fpn_fem[2](conv4) -- ef4 = self.fpn_fem[3](conv5) -- ef5 = self.fpn_fem[4](conv6) -- ef6 = self.fpn_fem[5](conv7) -- -- sources_pal1 = [of1, of2, of3, of4, of5, of6] -- sources_pal2 = [ef1, ef2, ef3, ef4, ef5, ef6] -- loc_pal1, conf_pal1 = list(), list() -- loc_pal2, conf_pal2 = list(), list() -- -- for (x, l, c) in zip(sources_pal1, self.loc_pal1, self.conf_pal1): -- loc_pal1.append(l(x).permute(0, 2, 3, 1).contiguous()) -- conf_pal1.append(c(x).permute(0, 2, 3, 1).contiguous()) -- -- for (x, l, c) in zip(sources_pal2, self.loc_pal2, self.conf_pal2): -- loc_pal2.append(l(x).permute(0, 2, 3, 1).contiguous()) -- conf_pal2.append(c(x).permute(0, 2, 3, 1).contiguous()) -- -- features_maps = [] -- for i in range(len(loc_pal1)): -- feat = [] -- feat += [loc_pal1[i].size(1), loc_pal1[i].size(2)] -- features_maps += [feat] -- -- loc_pal1 = torch.cat([o.view(o.size(0), -1) for o in loc_pal1], 1) -- conf_pal1 = torch.cat([o.view(o.size(0), -1) for o in conf_pal1], 1) -- -- loc_pal2 = torch.cat([o.view(o.size(0), -1) for o in loc_pal2], 1) -- conf_pal2 = torch.cat([o.view(o.size(0), -1) for o in conf_pal2], 1) -- -- priorbox = PriorBox(size, features_maps, cfg, pal=1) -- self.priors_pal1 = Variable(priorbox.forward(), volatile=True) -- -- priorbox = PriorBox(size, features_maps, cfg, pal=2) -- self.priors_pal2 = Variable(priorbox.forward(), volatile=True) -- -- if self.phase == 'test': -- output = self.detect( -- loc_pal2.view(loc_pal2.size(0), -1, 4), -- self.softmax(conf_pal2.view(conf_pal2.size(0), -1, -- self.num_classes)), # conf preds -- self.priors_pal2.type(type(x.data)) -- ) -- -- else: -- output = ( -- loc_pal1.view(loc_pal1.size(0), -1, 4), -- conf_pal1.view(conf_pal1.size(0), -1, self.num_classes), -- self.priors_pal1, -- loc_pal2.view(loc_pal2.size(0), -1, 4), -- conf_pal2.view(conf_pal2.size(0), -1, self.num_classes), -- self.priors_pal2) -- return output -- -- def load_weights(self, base_file): -- other, ext = os.path.splitext(base_file) -- if ext == '.pkl' or '.pth': -- print('Loading weights into state dict...') -- mdata = torch.load(base_file, -- map_location=lambda storage, loc: storage) -- weights = mdata['weight'] -- epoch = mdata['epoch'] -- self.load_state_dict(weights) -- print('Finished!') -- else: -- print('Sorry only .pth and .pkl files supported.') -- return epoch -- -- def xavier(self, param): -- init.xavier_uniform(param) -- -- def weights_init(self, m): -- if isinstance(m, nn.Conv2d): -- self.xavier(m.weight.data) -- m.bias.data.zero_() -- -- if isinstance(m, nn.ConvTranspose2d): -- self.xavier(m.weight.data) -- if 'bias' in m.state_dict().keys(): -- m.bias.data.zero_() -- -- if isinstance(m, nn.BatchNorm2d): -- m.weight.data[...] = 1 -- m.bias.data.zero_() -- --extras_cfg = [256, 'S', 512, 128, 'S', 256] -- --net_cfg = [256, 512, 1024, 2048, 512, 256] -- -- --def add_extras(cfg, i): -- layers = [] -- in_channels = i -- flag = False -- for k, v in enumerate(cfg): -- if in_channels != 'S': -- if v == 'S': -- layers += [nn.Conv2d(in_channels, cfg[k + 1], -- kernel_size=(1, 3)[flag], stride=2, padding=1)] -- else: -- layers += [nn.Conv2d(in_channels, v, kernel_size=(1, 3)[flag])] -- flag = not flag -- in_channels = v -- return layers -- -- --def multibox(cfg, num_classes=2): -- conf_layers = [] -- loc_layers = [] -- for k, v in enumerate(cfg): -- loc_layers += [nn.Conv2d(v, 4, kernel_size=3, padding=1)] -- conf_layers += [nn.Conv2d(v, num_classes, kernel_size=3, padding=1)] -- return (loc_layers, conf_layers) -- -- --def fem_module(cfg): -- topdown_layers = [] -- lat_layers = [] -- fem_layers = [] -- -- topdown_layers += [nn.Conv2d(cfg[-1], cfg[-1], -- kernel_size=1, stride=1, padding=0)] -- for k, v in enumerate(cfg): -- fem_layers += [FEM(v)] -- cur_channel = cfg[len(cfg) - 1 - k] -- if len(cfg) - 1 - k > 0: -- last_channel = cfg[len(cfg) - 2 - k] -- topdown_layers += [nn.Conv2d(cur_channel, last_channel, -- kernel_size=1, stride=1, padding=0)] -- lat_layers += [nn.Conv2d(last_channel, last_channel, -- kernel_size=1, stride=1, padding=0)] -- return (topdown_layers, lat_layers, fem_layers) -- -- --def resnet50(): -- """Constructs a ResNet-50 model. -- Args: -- pretrained (bool): If True, returns a model pre-trained on ImageNet -- """ -- model = ResNet(Bottleneck, [3, 4, 6, 3]) -- return model -- -- --def resnet101(): -- model = ResNet(Bottleneck, [3, 4, 23, 3]) -- return model -- -- --def resnet152(): -- model = ResNet(Bottleneck, [3, 8, 36, 3]) -- return model -- -- --def model_map(net_name='resnet50'): -- _dicts = {'resnet50': resnet50, -- 'resnet101': resnet101, 'resnet152': resnet152} -- return _dicts[net_name]() -- -- --def build_net_resnet(phase, num_classes=2, net_name='resnet50'): -- resnet = model_map(net_name) -- extras = add_extras(extras_cfg, 2048) -- head_pal1 = multibox(net_cfg, num_classes) -- head_pal2 = multibox(net_cfg, num_classes) -- fem_modules = fem_module(net_cfg) -- model = DSFD(phase, resnet, extras, fem_modules, -- head_pal1, head_pal2, num_classes) -- return model -- --if __name__ == '__main__': -- inputs = Variable(torch.randn(1, 3, 640, 640)) -- net = build_net('train', 2, 101) -- out = net(inputs) +-# Copyright 2021 Huawei Technologies Co., Ltd +-# +-# 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. +- +-#coding=utf-8 +-from __future__ import division +-from __future__ import print_function +-from __future__ import absolute_import +- +-import torch +-import torch.nn as nn +-import torch.nn.functional as F +-import torch.nn.init as init +- +-from torch.autograd import Variable +- +-from layers import * +-from data.config import cur_config as cfg +- +-def conv3x3(in_planes, out_planes, stride=1, bias=False): +- """3x3 convolution with padding""" +- return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, +- padding=1, bias=bias) +- +- +-def conv1x1(in_planes, out_planes, stride=1): +- """1x1 convolution""" +- return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False) +- +- +-class BasicBlock(nn.Module): +- expansion = 1 +- +- def __init__(self, inplanes, planes, stride=1, downsample=None): +- super(BasicBlock, self).__init__() +- self.conv1 = conv3x3(inplanes, planes, stride) +- self.bn1 = nn.BatchNorm2d(planes) +- self.relu = nn.ReLU(inplace=True) +- self.conv2 = conv3x3(planes, planes) +- self.bn2 = nn.BatchNorm2d(planes) +- self.downsample = downsample +- self.stride = stride +- +- def forward(self, x): +- residual = x +- +- out = self.conv1(x) +- out = self.bn1(out) +- out = self.relu(out) +- +- out = self.conv2(out) +- out = self.bn2(out) +- +- if self.downsample is not None: +- residual = self.downsample(x) +- +- out += residual +- out = self.relu(out) +- +- return out +- +- +-class Bottleneck(nn.Module): +- expansion = 4 +- +- def __init__(self, inplanes, planes, stride=1, downsample=None): +- super(Bottleneck, self).__init__() +- self.conv1 = conv1x1(inplanes, planes) +- self.bn1 = nn.BatchNorm2d(planes) +- self.conv2 = conv3x3(planes, planes, stride) +- self.bn2 = nn.BatchNorm2d(planes) +- self.conv3 = conv1x1(planes, planes * self.expansion) +- self.bn3 = nn.BatchNorm2d(planes * self.expansion) +- self.relu = nn.ReLU(inplace=True) +- self.downsample = downsample +- self.stride = stride +- +- def forward(self, x): +- residual = x +- +- out = self.conv1(x) +- out = self.bn1(out) +- out = self.relu(out) +- +- out = self.conv2(out) +- out = self.bn2(out) +- out = self.relu(out) +- +- out = self.conv3(out) +- out = self.bn3(out) +- +- if self.downsample is not None: +- residual = self.downsample(x) +- +- out += residual +- out = self.relu(out) +- +- return out +- +- +-class ResNet(nn.Module): +- +- def __init__(self, block, layers): +- super(ResNet, self).__init__() +- self.inplanes = 64 +- self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, +- bias=False) +- self.bn1 = nn.BatchNorm2d(64) +- self.relu = nn.ReLU(inplace=True) +- self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) +- self.layer1 = self._make_layer(block, 64, layers[0]) +- self.layer2 = self._make_layer(block, 128, layers[1], stride=2) +- self.layer3 = self._make_layer(block, 256, layers[2], stride=2) +- self.layer4 = self._make_layer(block, 512, layers[3], stride=2) +- +- def _make_layer(self, block, planes, blocks, stride=1): +- downsample = None +- if stride != 1 or self.inplanes != planes * block.expansion: +- downsample = nn.Sequential( +- conv1x1(self.inplanes, planes * block.expansion, stride), +- nn.BatchNorm2d(planes * block.expansion), +- ) +- +- layers = [] +- layers.append(block(self.inplanes, planes, stride, downsample)) +- self.inplanes = planes * block.expansion +- for _ in range(1, blocks): +- layers.append(block(self.inplanes, planes)) +- +- return nn.Sequential(*layers) +- +- def forward(self, x): +- sources = [] +- +- x = self.conv1(x) +- x = self.bn1(x) +- x = self.relu(x) +- x = self.maxpool(x) +- +- x = self.layer1(x) +- sources += [x] +- +- x = self.layer2(x) +- sources += [x] +- +- x = self.layer3(x) +- sources += [x] +- +- x = self.layer4(x) +- sources += [x] +- +- return sources +- +- +-class FEM(nn.Module): +- """docstring for FEM""" +- +- def __init__(self, in_planes): +- super(FEM, self).__init__() +- inter_planes = in_planes // 3 +- inter_planes1 = in_planes - 2 * inter_planes +- self.branch1 = nn.Conv2d( +- in_planes, inter_planes, kernel_size=3, stride=1, padding=3, dilation=3) +- +- self.branch2 = nn.Sequential( +- nn.Conv2d(in_planes, inter_planes, kernel_size=3, +- stride=1, padding=3, dilation=3), +- nn.ReLU(inplace=True), +- nn.Conv2d(inter_planes, inter_planes, kernel_size=3, +- stride=1, padding=3, dilation=3) +- ) +- self.branch3 = nn.Sequential( +- nn.Conv2d(in_planes, inter_planes1, kernel_size=3, +- stride=1, padding=3, dilation=3), +- nn.ReLU(inplace=True), +- nn.Conv2d(inter_planes1, inter_planes1, kernel_size=3, +- stride=1, padding=3, dilation=3), +- nn.ReLU(inplace=True), +- nn.Conv2d(inter_planes1, inter_planes1, kernel_size=3, +- stride=1, padding=3, dilation=3) +- ) +- +- def forward(self, x): +- x1 = self.branch1(x) +- x2 = self.branch2(x) +- x3 = self.branch3(x) +- out = torch.cat((x1, x2, x3), dim=1) +- out = F.relu(out, inplace=True) +- return out +- +- +-class DSFD(nn.Module): +- """docstring for SRN""" +- +- def __init__(self, phase, base, extras, fem_modules, head1, head2, num_classes=2): +- super(DSFD, self).__init__() +- self.resnet = base +- self.phase = phase +- self.num_classes = num_classes +- self.extras = nn.ModuleList(extras) +- +- self.fpn_topdown = nn.ModuleList(fem_modules[0]) +- self.fpn_latlayer = nn.ModuleList(fem_modules[1]) +- self.fpn_fem = nn.ModuleList(fem_modules[2]) +- +- self.loc_pal1 = nn.ModuleList(head1[0]) +- self.conf_pal1 = nn.ModuleList(head1[1]) +- self.loc_pal2 = nn.ModuleList(head2[0]) +- self.conf_pal2 = nn.ModuleList(head2[1]) +- +- if self.phase == 'test': +- self.softmax = nn.Softmax(dim=-1) +- self.detect = Detect(cfg) +- +- def _upsample_prod(self, x, y): +- _, _, H, W = y.size() +- return F.upsample(x, size=(H, W), mode='bilinear') * y +- +- def forward(self, x): +- size = x.size()[2:] +- of1, of2, of3, of4 = self.resnet(x) +- +- x = of4 +- for i in range(2): +- x = F.relu(self.extras[i](x), inplace=True) +- of5 = x +- +- for i in range(2, len(self.extras)): +- x = F.relu(self.extras[i](x), inplace=True) +- of6 = x +- +- conv7 = F.relu(self.fpn_topdown[0](of6), inplace=True) +- +- x = F.relu(self.fpn_topdown[1](conv7), inplace=True) +- conv6 = F.relu(self._upsample_prod( +- x, self.fpn_latlayer[0](of5)), inplace=True) +- +- x = F.relu(self.fpn_topdown[2](conv6), inplace=True) +- conv5 = F.relu(self._upsample_prod( +- x, self.fpn_latlayer[1](of4)), inplace=True) +- +- x = F.relu(self.fpn_topdown[3](conv5), inplace=True) +- conv4 = F.relu(self._upsample_prod( +- x, self.fpn_latlayer[2](of3)), inplace=True) +- +- x = F.relu(self.fpn_topdown[4](conv4), inplace=True) +- conv3 = F.relu(self._upsample_prod( +- x, self.fpn_latlayer[3](of2)), inplace=True) +- +- x = F.relu(self.fpn_topdown[5](conv3), inplace=True) +- conv2 = F.relu(self._upsample_prod( +- x, self.fpn_latlayer[4](of1)), inplace=True) +- +- ef1 = self.fpn_fem[0](conv2) +- ef2 = self.fpn_fem[1](conv3) +- ef3 = self.fpn_fem[2](conv4) +- ef4 = self.fpn_fem[3](conv5) +- ef5 = self.fpn_fem[4](conv6) +- ef6 = self.fpn_fem[5](conv7) +- +- sources_pal1 = [of1, of2, of3, of4, of5, of6] +- sources_pal2 = [ef1, ef2, ef3, ef4, ef5, ef6] +- loc_pal1, conf_pal1 = list(), list() +- loc_pal2, conf_pal2 = list(), list() +- +- for (x, l, c) in zip(sources_pal1, self.loc_pal1, self.conf_pal1): +- loc_pal1.append(l(x).permute(0, 2, 3, 1).contiguous()) +- conf_pal1.append(c(x).permute(0, 2, 3, 1).contiguous()) +- +- for (x, l, c) in zip(sources_pal2, self.loc_pal2, self.conf_pal2): +- loc_pal2.append(l(x).permute(0, 2, 3, 1).contiguous()) +- conf_pal2.append(c(x).permute(0, 2, 3, 1).contiguous()) +- +- features_maps = [] +- for i in range(len(loc_pal1)): +- feat = [] +- feat += [loc_pal1[i].size(1), loc_pal1[i].size(2)] +- features_maps += [feat] +- +- loc_pal1 = torch.cat([o.view(o.size(0), -1) for o in loc_pal1], 1) +- conf_pal1 = torch.cat([o.view(o.size(0), -1) for o in conf_pal1], 1) +- +- loc_pal2 = torch.cat([o.view(o.size(0), -1) for o in loc_pal2], 1) +- conf_pal2 = torch.cat([o.view(o.size(0), -1) for o in conf_pal2], 1) +- +- priorbox = PriorBox(size, features_maps, cfg, pal=1) +- self.priors_pal1 = Variable(priorbox.forward(), volatile=True) +- +- priorbox = PriorBox(size, features_maps, cfg, pal=2) +- self.priors_pal2 = Variable(priorbox.forward(), volatile=True) +- +- if self.phase == 'test': +- output = self.detect( +- loc_pal2.view(loc_pal2.size(0), -1, 4), +- self.softmax(conf_pal2.view(conf_pal2.size(0), -1, +- self.num_classes)), # conf preds +- self.priors_pal2.type(type(x.data)) +- ) +- +- else: +- output = ( +- loc_pal1.view(loc_pal1.size(0), -1, 4), +- conf_pal1.view(conf_pal1.size(0), -1, self.num_classes), +- self.priors_pal1, +- loc_pal2.view(loc_pal2.size(0), -1, 4), +- conf_pal2.view(conf_pal2.size(0), -1, self.num_classes), +- self.priors_pal2) +- return output +- +- def load_weights(self, base_file): +- other, ext = os.path.splitext(base_file) +- if ext == '.pkl' or '.pth': +- print('Loading weights into state dict...') +- mdata = torch.load(base_file, +- map_location=lambda storage, loc: storage) +- weights = mdata['weight'] +- epoch = mdata['epoch'] +- self.load_state_dict(weights) +- print('Finished!') +- else: +- print('Sorry only .pth and .pkl files supported.') +- return epoch +- +- def xavier(self, param): +- init.xavier_uniform(param) +- +- def weights_init(self, m): +- if isinstance(m, nn.Conv2d): +- self.xavier(m.weight.data) +- m.bias.data.zero_() +- +- if isinstance(m, nn.ConvTranspose2d): +- self.xavier(m.weight.data) +- if 'bias' in m.state_dict().keys(): +- m.bias.data.zero_() +- +- if isinstance(m, nn.BatchNorm2d): +- m.weight.data[...] = 1 +- m.bias.data.zero_() +- +-extras_cfg = [256, 'S', 512, 128, 'S', 256] +- +-net_cfg = [256, 512, 1024, 2048, 512, 256] +- +- +-def add_extras(cfg, i): +- layers = [] +- in_channels = i +- flag = False +- for k, v in enumerate(cfg): +- if in_channels != 'S': +- if v == 'S': +- layers += [nn.Conv2d(in_channels, cfg[k + 1], +- kernel_size=(1, 3)[flag], stride=2, padding=1)] +- else: +- layers += [nn.Conv2d(in_channels, v, kernel_size=(1, 3)[flag])] +- flag = not flag +- in_channels = v +- return layers +- +- +-def multibox(cfg, num_classes=2): +- conf_layers = [] +- loc_layers = [] +- for k, v in enumerate(cfg): +- loc_layers += [nn.Conv2d(v, 4, kernel_size=3, padding=1)] +- conf_layers += [nn.Conv2d(v, num_classes, kernel_size=3, padding=1)] +- return (loc_layers, conf_layers) +- +- +-def fem_module(cfg): +- topdown_layers = [] +- lat_layers = [] +- fem_layers = [] +- +- topdown_layers += [nn.Conv2d(cfg[-1], cfg[-1], +- kernel_size=1, stride=1, padding=0)] +- for k, v in enumerate(cfg): +- fem_layers += [FEM(v)] +- cur_channel = cfg[len(cfg) - 1 - k] +- if len(cfg) - 1 - k > 0: +- last_channel = cfg[len(cfg) - 2 - k] +- topdown_layers += [nn.Conv2d(cur_channel, last_channel, +- kernel_size=1, stride=1, padding=0)] +- lat_layers += [nn.Conv2d(last_channel, last_channel, +- kernel_size=1, stride=1, padding=0)] +- return (topdown_layers, lat_layers, fem_layers) +- +- +-def resnet50(): +- """Constructs a ResNet-50 model. +- Args: +- pretrained (bool): If True, returns a model pre-trained on ImageNet +- """ +- model = ResNet(Bottleneck, [3, 4, 6, 3]) +- return model +- +- +-def resnet101(): +- model = ResNet(Bottleneck, [3, 4, 23, 3]) +- return model +- +- +-def resnet152(): +- model = ResNet(Bottleneck, [3, 8, 36, 3]) +- return model +- +- +-def model_map(net_name='resnet50'): +- _dicts = {'resnet50': resnet50, +- 'resnet101': resnet101, 'resnet152': resnet152} +- return _dicts[net_name]() +- +- +-def build_net_resnet(phase, num_classes=2, net_name='resnet50'): +- resnet = model_map(net_name) +- extras = add_extras(extras_cfg, 2048) +- head_pal1 = multibox(net_cfg, num_classes) +- head_pal2 = multibox(net_cfg, num_classes) +- fem_modules = fem_module(net_cfg) +- model = DSFD(phase, resnet, extras, fem_modules, +- head_pal1, head_pal2, num_classes) +- return model +- +-if __name__ == '__main__': +- inputs = Variable(torch.randn(1, 3, 640, 640)) +- net = build_net('train', 2, 101) +- out = net(inputs) diff --git a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/models/DSFD_vgg.py b/contrib/ACL_PyTorch/Research/cv/detection/DSFD/models/DSFD_vgg.py deleted file mode 100644 index 8a842e593a..0000000000 --- a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/models/DSFD_vgg.py +++ /dev/null @@ -1,374 +0,0 @@ --# Copyright 2021 Huawei Technologies Co., Ltd --# --# 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. -- --#coding=utf-8 -- --from __future__ import division --from __future__ import absolute_import --from __future__ import print_function -- --import os --import numpy as np -- --import torch --import torch.nn as nn --import torch.nn.init as init --import torch.nn.functional as F --from torch.autograd import Variable -- --from layers import * --from data.config import cur_config as cfg -- -- --class FEM(nn.Module): -- """docstring for FEM""" -- -- def __init__(self, in_planes): -- super(FEM, self).__init__() -- inter_planes = in_planes // 3 -- inter_planes1 = in_planes - 2 * inter_planes -- self.branch1 = nn.Conv2d( -- in_planes, inter_planes, kernel_size=3, stride=1, padding=3, dilation=3) -- -- self.branch2 = nn.Sequential( -- nn.Conv2d(in_planes, inter_planes, kernel_size=3, -- stride=1, padding=3, dilation=3), -- nn.ReLU(inplace=True), -- nn.Conv2d(inter_planes, inter_planes, kernel_size=3, -- stride=1, padding=3, dilation=3) -- ) -- self.branch3 = nn.Sequential( -- nn.Conv2d(in_planes, inter_planes1, kernel_size=3, -- stride=1, padding=3, dilation=3), -- nn.ReLU(inplace=True), -- nn.Conv2d(inter_planes1, inter_planes1, kernel_size=3, -- stride=1, padding=3, dilation=3), -- nn.ReLU(inplace=True), -- nn.Conv2d(inter_planes1, inter_planes1, kernel_size=3, -- stride=1, padding=3, dilation=3) -- ) -- -- def forward(self, x): -- x1 = self.branch1(x) -- x2 = self.branch2(x) -- x3 = self.branch3(x) -- out = torch.cat((x1, x2, x3), dim=1) -- out = F.relu(out, inplace=True) -- return out -- -- --class DSFD(nn.Module): -- """Single Shot Multibox Architecture -- The network is composed of a base VGG network followed by the -- added multibox conv layers. Each multibox layer branches into -- 1) conv2d for class conf scores -- 2) conv2d for localization predictions -- 3) associated priorbox layer to produce default bounding -- boxes specific to the layer's feature map size. -- See: https://arxiv.org/pdf/1512.02325.pdf for more details. -- -- Args: -- phase: (string) Can be "test" or "train" -- size: input image size -- base: VGG16 layers for input, size of either 300 or 500 -- extras: extra layers that feed to multibox loc and conf layers -- head: "multibox head" consists of loc and conf conv layers -- """ -- -- def __init__(self, phase, base, extras, fem, head1, head2, num_classes): -- super(DSFD, self).__init__() -- self.phase = phase -- self.num_classes = num_classes -- self.vgg = nn.ModuleList(base) -- -- self.L2Normof1 = L2Norm(256, 10) -- self.L2Normof2 = L2Norm(512, 8) -- self.L2Normof3 = L2Norm(512, 5) -- -- self.extras = nn.ModuleList(extras) -- self.fpn_topdown = nn.ModuleList(fem[0]) -- self.fpn_latlayer = nn.ModuleList(fem[1]) -- -- self.fpn_fem = nn.ModuleList(fem[2]) -- -- self.L2Normef1 = L2Norm(256, 10) -- self.L2Normef2 = L2Norm(512, 8) -- self.L2Normef3 = L2Norm(512, 5) -- -- self.loc_pal1 = nn.ModuleList(head1[0]) -- self.conf_pal1 = nn.ModuleList(head1[1]) -- -- self.loc_pal2 = nn.ModuleList(head2[0]) -- self.conf_pal2 = nn.ModuleList(head2[1]) -- -- if self.phase=='test': -- self.softmax = nn.Softmax(dim=-1) -- self.detect = Detect(cfg) -- -- def _upsample_prod(self, x, y): -- _, _, H, W = y.size() -- return F.upsample(x, size=(H, W), mode='bilinear') * y -- -- def forward(self, x): -- size = x.size()[2:] -- pal1_sources = list() -- pal2_sources = list() -- loc_pal1 = list() -- conf_pal1 = list() -- loc_pal2 = list() -- conf_pal2 = list() -- -- # apply vgg up to conv4_3 relu -- for k in range(16): -- x = self.vgg[k](x) -- of1 = x -- s = self.L2Normof1(of1) -- pal1_sources.append(s) -- # apply vgg up to fc7 -- for k in range(16, 23): -- x = self.vgg[k](x) -- of2 = x -- s = self.L2Normof2(of2) -- pal1_sources.append(s) -- -- for k in range(23, 30): -- x = self.vgg[k](x) -- of3 = x -- s = self.L2Normof3(of3) -- pal1_sources.append(s) -- -- for k in range(30, len(self.vgg)): -- x = self.vgg[k](x) -- of4 = x -- pal1_sources.append(of4) -- # apply extra layers and cache source layer outputs -- -- for k in range(2): -- x = F.relu(self.extras[k](x), inplace=True) -- of5 = x -- pal1_sources.append(of5) -- for k in range(2, 4): -- x = F.relu(self.extras[k](x), inplace=True) -- of6 = x -- pal1_sources.append(of6) -- -- conv7 = F.relu(self.fpn_topdown[0](of6), inplace=True) -- -- x = F.relu(self.fpn_topdown[1](conv7), inplace=True) -- conv6 = F.relu(self._upsample_prod( -- x, self.fpn_latlayer[0](of5)), inplace=True) -- -- x = F.relu(self.fpn_topdown[2](conv6), inplace=True) -- convfc7_2 = F.relu(self._upsample_prod( -- x, self.fpn_latlayer[1](of4)), inplace=True) -- -- x = F.relu(self.fpn_topdown[3](convfc7_2), inplace=True) -- conv5 = F.relu(self._upsample_prod( -- x, self.fpn_latlayer[2](of3)), inplace=True) -- -- x = F.relu(self.fpn_topdown[4](conv5), inplace=True) -- conv4 = F.relu(self._upsample_prod( -- x, self.fpn_latlayer[3](of2)), inplace=True) -- -- x = F.relu(self.fpn_topdown[5](conv4), inplace=True) -- conv3 = F.relu(self._upsample_prod( -- x, self.fpn_latlayer[4](of1)), inplace=True) -- -- ef1 = self.fpn_fem[0](conv3) -- ef1 = self.L2Normef1(ef1) -- ef2 = self.fpn_fem[1](conv4) -- ef2 = self.L2Normef2(ef2) -- ef3 = self.fpn_fem[2](conv5) -- ef3 = self.L2Normef3(ef3) -- ef4 = self.fpn_fem[3](convfc7_2) -- ef5 = self.fpn_fem[4](conv6) -- ef6 = self.fpn_fem[5](conv7) -- -- pal2_sources = (ef1, ef2, ef3, ef4, ef5, ef6) -- for (x, l, c) in zip(pal1_sources, self.loc_pal1, self.conf_pal1): -- loc_pal1.append(l(x).permute(0, 2, 3, 1).contiguous()) -- conf_pal1.append(c(x).permute(0, 2, 3, 1).contiguous()) -- -- for (x, l, c) in zip(pal2_sources, self.loc_pal2, self.conf_pal2): -- loc_pal2.append(l(x).permute(0, 2, 3, 1).contiguous()) -- conf_pal2.append(c(x).permute(0, 2, 3, 1).contiguous()) -- -- features_maps = [] -- for i in range(len(loc_pal1)): -- feat = [] -- feat += [loc_pal1[i].size(1), loc_pal1[i].size(2)] -- features_maps += [feat] -- -- loc_pal1 = torch.cat([o.view(o.size(0), -1) -- for o in loc_pal1], 1) -- conf_pal1 = torch.cat([o.view(o.size(0), -1) -- for o in conf_pal1], 1) -- -- loc_pal2 = torch.cat([o.view(o.size(0), -1) -- for o in loc_pal2], 1) -- conf_pal2 = torch.cat([o.view(o.size(0), -1) -- for o in conf_pal2], 1) -- -- priorbox = PriorBox(size, features_maps, cfg, pal=1) -- self.priors_pal1 = Variable(priorbox.forward(), volatile=True) -- -- priorbox = PriorBox(size, features_maps, cfg, pal=2) -- self.priors_pal2 = Variable(priorbox.forward(), volatile=True) -- -- if self.phase == 'test': -- output = self.detect( -- loc_pal2.view(loc_pal2.size(0), -1, 4), -- self.softmax(conf_pal2.view(conf_pal2.size(0), -1, -- self.num_classes)), # conf preds -- self.priors_pal2.type(type(x.data)) -- ) -- -- else: -- output = ( -- loc_pal1.view(loc_pal1.size(0), -1, 4), -- conf_pal1.view(conf_pal1.size(0), -1, self.num_classes), -- self.priors_pal1, -- loc_pal2.view(loc_pal2.size(0), -1, 4), -- conf_pal2.view(conf_pal2.size(0), -1, self.num_classes), -- self.priors_pal2) -- return output -- -- def load_weights(self, base_file): -- other, ext = os.path.splitext(base_file) -- if ext == '.pkl' or '.pth': -- print('Loading weights into state dict...') -- mdata = torch.load(base_file, -- map_location=lambda storage, loc: storage) -- weights = mdata['weight'] -- epoch = mdata['epoch'] -- self.load_state_dict(weights) -- print('Finished!') -- else: -- print('Sorry only .pth and .pkl files supported.') -- return epoch -- -- def xavier(self, param): -- init.xavier_uniform(param) -- -- def weights_init(self, m): -- if isinstance(m, nn.Conv2d): -- self.xavier(m.weight.data) -- m.bias.data.zero_() -- -- if isinstance(m,nn.ConvTranspose2d): -- self.xavier(m.weight.data) -- if 'bias' in m.state_dict().keys(): -- m.bias.data.zero_() -- -- if isinstance(m,nn.BatchNorm2d): -- m.weight.data[...] = 1 -- m.bias.data.zero_() -- -- --vgg_cfg = [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'C', 512, 512, 512, 'M', -- 512, 512, 512, 'M'] -- --extras_cfg = [256, 'S', 512, 128, 'S', 256] -- --fem_cfg = [256, 512, 512, 1024, 512, 256] -- -- --def fem_module(cfg): -- topdown_layers = [] -- lat_layers = [] -- fem_layers = [] -- -- topdown_layers += [nn.Conv2d(cfg[-1], cfg[-1], -- kernel_size=1, stride=1, padding=0)] -- for k, v in enumerate(cfg): -- fem_layers += [FEM(v)] -- cur_channel = cfg[len(cfg) - 1 - k] -- if len(cfg) - 1 - k > 0: -- last_channel = cfg[len(cfg) - 2 - k] -- topdown_layers += [nn.Conv2d(cur_channel, last_channel, -- kernel_size=1, stride=1, padding=0)] -- lat_layers += [nn.Conv2d(last_channel, last_channel, -- kernel_size=1, stride=1, padding=0)] -- return (topdown_layers, lat_layers, fem_layers) -- -- --def vgg(cfg, i, batch_norm=False): -- layers = [] -- in_channels = i -- for v in cfg: -- if v == 'M': -- layers += [nn.MaxPool2d(kernel_size=2, stride=2)] -- elif v == 'C': -- layers += [nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)] -- else: -- conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1) -- if batch_norm: -- layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)] -- else: -- layers += [conv2d, nn.ReLU(inplace=True)] -- in_channels = v -- conv6 = nn.Conv2d(512, 1024, kernel_size=3, padding=3, dilation=3) -- conv7 = nn.Conv2d(1024, 1024, kernel_size=1) -- layers += [conv6, -- nn.ReLU(inplace=True), conv7, nn.ReLU(inplace=True)] -- return layers -- -- --def add_extras(cfg, i, batch_norm=False): -- # Extra layers added to VGG for feature scaling -- layers = [] -- in_channels = i -- flag = False -- for k, v in enumerate(cfg): -- if in_channels != 'S': -- if v == 'S': -- layers += [nn.Conv2d(in_channels, cfg[k + 1], -- kernel_size=(1, 3)[flag], stride=2, padding=1)] -- else: -- layers += [nn.Conv2d(in_channels, v, kernel_size=(1, 3)[flag])] -- flag = not flag -- in_channels = v -- return layers -- -- --def multibox(vgg, extra_layers, num_classes): -- loc_layers = [] -- conf_layers = [] -- vgg_source = [14, 21, 28, -2] -- -- for k, v in enumerate(vgg_source): -- loc_layers += [nn.Conv2d(vgg[v].out_channels, -- 4, kernel_size=3, padding=1)] -- conf_layers += [nn.Conv2d(vgg[v].out_channels, -- num_classes, kernel_size=3, padding=1)] -- for k, v in enumerate(extra_layers[1::2], 2): -- loc_layers += [nn.Conv2d(v.out_channels, -- 4, kernel_size=3, padding=1)] -- conf_layers += [nn.Conv2d(v.out_channels, -- num_classes, kernel_size=3, padding=1)] -- return (loc_layers, conf_layers) -- -- --def build_net_vgg(phase, num_classes=2): -- base = vgg(vgg_cfg, 3) -- extras = add_extras(extras_cfg, 1024) -- head1 = multibox(base, extras, num_classes) -- head2 = multibox(base, extras, num_classes) -- fem = fem_module(fem_cfg) -- return DSFD(phase, base, extras, fem, head1, head2, num_classes) -- --if __name__ == '__main__': -- inputs = Variable(torch.randn(1, 3, 640, 640)) -- net = build_net('train', 2) -- out = net(inputs) +-# Copyright 2021 Huawei Technologies Co., Ltd +-# +-# 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. +- +-#coding=utf-8 +- +-from __future__ import division +-from __future__ import absolute_import +-from __future__ import print_function +- +-import os +-import numpy as np +- +-import torch +-import torch.nn as nn +-import torch.nn.init as init +-import torch.nn.functional as F +-from torch.autograd import Variable +- +-from layers import * +-from data.config import cur_config as cfg +- +- +-class FEM(nn.Module): +- """docstring for FEM""" +- +- def __init__(self, in_planes): +- super(FEM, self).__init__() +- inter_planes = in_planes // 3 +- inter_planes1 = in_planes - 2 * inter_planes +- self.branch1 = nn.Conv2d( +- in_planes, inter_planes, kernel_size=3, stride=1, padding=3, dilation=3) +- +- self.branch2 = nn.Sequential( +- nn.Conv2d(in_planes, inter_planes, kernel_size=3, +- stride=1, padding=3, dilation=3), +- nn.ReLU(inplace=True), +- nn.Conv2d(inter_planes, inter_planes, kernel_size=3, +- stride=1, padding=3, dilation=3) +- ) +- self.branch3 = nn.Sequential( +- nn.Conv2d(in_planes, inter_planes1, kernel_size=3, +- stride=1, padding=3, dilation=3), +- nn.ReLU(inplace=True), +- nn.Conv2d(inter_planes1, inter_planes1, kernel_size=3, +- stride=1, padding=3, dilation=3), +- nn.ReLU(inplace=True), +- nn.Conv2d(inter_planes1, inter_planes1, kernel_size=3, +- stride=1, padding=3, dilation=3) +- ) +- +- def forward(self, x): +- x1 = self.branch1(x) +- x2 = self.branch2(x) +- x3 = self.branch3(x) +- out = torch.cat((x1, x2, x3), dim=1) +- out = F.relu(out, inplace=True) +- return out +- +- +-class DSFD(nn.Module): +- """Single Shot Multibox Architecture +- The network is composed of a base VGG network followed by the +- added multibox conv layers. Each multibox layer branches into +- 1) conv2d for class conf scores +- 2) conv2d for localization predictions +- 3) associated priorbox layer to produce default bounding +- boxes specific to the layer's feature map size. +- See: https://arxiv.org/pdf/1512.02325.pdf for more details. +- +- Args: +- phase: (string) Can be "test" or "train" +- size: input image size +- base: VGG16 layers for input, size of either 300 or 500 +- extras: extra layers that feed to multibox loc and conf layers +- head: "multibox head" consists of loc and conf conv layers +- """ +- +- def __init__(self, phase, base, extras, fem, head1, head2, num_classes): +- super(DSFD, self).__init__() +- self.phase = phase +- self.num_classes = num_classes +- self.vgg = nn.ModuleList(base) +- +- self.L2Normof1 = L2Norm(256, 10) +- self.L2Normof2 = L2Norm(512, 8) +- self.L2Normof3 = L2Norm(512, 5) +- +- self.extras = nn.ModuleList(extras) +- self.fpn_topdown = nn.ModuleList(fem[0]) +- self.fpn_latlayer = nn.ModuleList(fem[1]) +- +- self.fpn_fem = nn.ModuleList(fem[2]) +- +- self.L2Normef1 = L2Norm(256, 10) +- self.L2Normef2 = L2Norm(512, 8) +- self.L2Normef3 = L2Norm(512, 5) +- +- self.loc_pal1 = nn.ModuleList(head1[0]) +- self.conf_pal1 = nn.ModuleList(head1[1]) +- +- self.loc_pal2 = nn.ModuleList(head2[0]) +- self.conf_pal2 = nn.ModuleList(head2[1]) +- +- if self.phase=='test': +- self.softmax = nn.Softmax(dim=-1) +- self.detect = Detect(cfg) +- +- def _upsample_prod(self, x, y): +- _, _, H, W = y.size() +- return F.upsample(x, size=(H, W), mode='bilinear') * y +- +- def forward(self, x): +- size = x.size()[2:] +- pal1_sources = list() +- pal2_sources = list() +- loc_pal1 = list() +- conf_pal1 = list() +- loc_pal2 = list() +- conf_pal2 = list() +- +- # apply vgg up to conv4_3 relu +- for k in range(16): +- x = self.vgg[k](x) +- of1 = x +- s = self.L2Normof1(of1) +- pal1_sources.append(s) +- # apply vgg up to fc7 +- for k in range(16, 23): +- x = self.vgg[k](x) +- of2 = x +- s = self.L2Normof2(of2) +- pal1_sources.append(s) +- +- for k in range(23, 30): +- x = self.vgg[k](x) +- of3 = x +- s = self.L2Normof3(of3) +- pal1_sources.append(s) +- +- for k in range(30, len(self.vgg)): +- x = self.vgg[k](x) +- of4 = x +- pal1_sources.append(of4) +- # apply extra layers and cache source layer outputs +- +- for k in range(2): +- x = F.relu(self.extras[k](x), inplace=True) +- of5 = x +- pal1_sources.append(of5) +- for k in range(2, 4): +- x = F.relu(self.extras[k](x), inplace=True) +- of6 = x +- pal1_sources.append(of6) +- +- conv7 = F.relu(self.fpn_topdown[0](of6), inplace=True) +- +- x = F.relu(self.fpn_topdown[1](conv7), inplace=True) +- conv6 = F.relu(self._upsample_prod( +- x, self.fpn_latlayer[0](of5)), inplace=True) +- +- x = F.relu(self.fpn_topdown[2](conv6), inplace=True) +- convfc7_2 = F.relu(self._upsample_prod( +- x, self.fpn_latlayer[1](of4)), inplace=True) +- +- x = F.relu(self.fpn_topdown[3](convfc7_2), inplace=True) +- conv5 = F.relu(self._upsample_prod( +- x, self.fpn_latlayer[2](of3)), inplace=True) +- +- x = F.relu(self.fpn_topdown[4](conv5), inplace=True) +- conv4 = F.relu(self._upsample_prod( +- x, self.fpn_latlayer[3](of2)), inplace=True) +- +- x = F.relu(self.fpn_topdown[5](conv4), inplace=True) +- conv3 = F.relu(self._upsample_prod( +- x, self.fpn_latlayer[4](of1)), inplace=True) +- +- ef1 = self.fpn_fem[0](conv3) +- ef1 = self.L2Normef1(ef1) +- ef2 = self.fpn_fem[1](conv4) +- ef2 = self.L2Normef2(ef2) +- ef3 = self.fpn_fem[2](conv5) +- ef3 = self.L2Normef3(ef3) +- ef4 = self.fpn_fem[3](convfc7_2) +- ef5 = self.fpn_fem[4](conv6) +- ef6 = self.fpn_fem[5](conv7) +- +- pal2_sources = (ef1, ef2, ef3, ef4, ef5, ef6) +- for (x, l, c) in zip(pal1_sources, self.loc_pal1, self.conf_pal1): +- loc_pal1.append(l(x).permute(0, 2, 3, 1).contiguous()) +- conf_pal1.append(c(x).permute(0, 2, 3, 1).contiguous()) +- +- for (x, l, c) in zip(pal2_sources, self.loc_pal2, self.conf_pal2): +- loc_pal2.append(l(x).permute(0, 2, 3, 1).contiguous()) +- conf_pal2.append(c(x).permute(0, 2, 3, 1).contiguous()) +- +- features_maps = [] +- for i in range(len(loc_pal1)): +- feat = [] +- feat += [loc_pal1[i].size(1), loc_pal1[i].size(2)] +- features_maps += [feat] +- +- loc_pal1 = torch.cat([o.view(o.size(0), -1) +- for o in loc_pal1], 1) +- conf_pal1 = torch.cat([o.view(o.size(0), -1) +- for o in conf_pal1], 1) +- +- loc_pal2 = torch.cat([o.view(o.size(0), -1) +- for o in loc_pal2], 1) +- conf_pal2 = torch.cat([o.view(o.size(0), -1) +- for o in conf_pal2], 1) +- +- priorbox = PriorBox(size, features_maps, cfg, pal=1) +- self.priors_pal1 = Variable(priorbox.forward(), volatile=True) +- +- priorbox = PriorBox(size, features_maps, cfg, pal=2) +- self.priors_pal2 = Variable(priorbox.forward(), volatile=True) +- +- if self.phase == 'test': +- output = self.detect( +- loc_pal2.view(loc_pal2.size(0), -1, 4), +- self.softmax(conf_pal2.view(conf_pal2.size(0), -1, +- self.num_classes)), # conf preds +- self.priors_pal2.type(type(x.data)) +- ) +- +- else: +- output = ( +- loc_pal1.view(loc_pal1.size(0), -1, 4), +- conf_pal1.view(conf_pal1.size(0), -1, self.num_classes), +- self.priors_pal1, +- loc_pal2.view(loc_pal2.size(0), -1, 4), +- conf_pal2.view(conf_pal2.size(0), -1, self.num_classes), +- self.priors_pal2) +- return output +- +- def load_weights(self, base_file): +- other, ext = os.path.splitext(base_file) +- if ext == '.pkl' or '.pth': +- print('Loading weights into state dict...') +- mdata = torch.load(base_file, +- map_location=lambda storage, loc: storage) +- weights = mdata['weight'] +- epoch = mdata['epoch'] +- self.load_state_dict(weights) +- print('Finished!') +- else: +- print('Sorry only .pth and .pkl files supported.') +- return epoch +- +- def xavier(self, param): +- init.xavier_uniform(param) +- +- def weights_init(self, m): +- if isinstance(m, nn.Conv2d): +- self.xavier(m.weight.data) +- m.bias.data.zero_() +- +- if isinstance(m,nn.ConvTranspose2d): +- self.xavier(m.weight.data) +- if 'bias' in m.state_dict().keys(): +- m.bias.data.zero_() +- +- if isinstance(m,nn.BatchNorm2d): +- m.weight.data[...] = 1 +- m.bias.data.zero_() +- +- +-vgg_cfg = [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'C', 512, 512, 512, 'M', +- 512, 512, 512, 'M'] +- +-extras_cfg = [256, 'S', 512, 128, 'S', 256] +- +-fem_cfg = [256, 512, 512, 1024, 512, 256] +- +- +-def fem_module(cfg): +- topdown_layers = [] +- lat_layers = [] +- fem_layers = [] +- +- topdown_layers += [nn.Conv2d(cfg[-1], cfg[-1], +- kernel_size=1, stride=1, padding=0)] +- for k, v in enumerate(cfg): +- fem_layers += [FEM(v)] +- cur_channel = cfg[len(cfg) - 1 - k] +- if len(cfg) - 1 - k > 0: +- last_channel = cfg[len(cfg) - 2 - k] +- topdown_layers += [nn.Conv2d(cur_channel, last_channel, +- kernel_size=1, stride=1, padding=0)] +- lat_layers += [nn.Conv2d(last_channel, last_channel, +- kernel_size=1, stride=1, padding=0)] +- return (topdown_layers, lat_layers, fem_layers) +- +- +-def vgg(cfg, i, batch_norm=False): +- layers = [] +- in_channels = i +- for v in cfg: +- if v == 'M': +- layers += [nn.MaxPool2d(kernel_size=2, stride=2)] +- elif v == 'C': +- layers += [nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)] +- else: +- conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1) +- if batch_norm: +- layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)] +- else: +- layers += [conv2d, nn.ReLU(inplace=True)] +- in_channels = v +- conv6 = nn.Conv2d(512, 1024, kernel_size=3, padding=3, dilation=3) +- conv7 = nn.Conv2d(1024, 1024, kernel_size=1) +- layers += [conv6, +- nn.ReLU(inplace=True), conv7, nn.ReLU(inplace=True)] +- return layers +- +- +-def add_extras(cfg, i, batch_norm=False): +- # Extra layers added to VGG for feature scaling +- layers = [] +- in_channels = i +- flag = False +- for k, v in enumerate(cfg): +- if in_channels != 'S': +- if v == 'S': +- layers += [nn.Conv2d(in_channels, cfg[k + 1], +- kernel_size=(1, 3)[flag], stride=2, padding=1)] +- else: +- layers += [nn.Conv2d(in_channels, v, kernel_size=(1, 3)[flag])] +- flag = not flag +- in_channels = v +- return layers +- +- +-def multibox(vgg, extra_layers, num_classes): +- loc_layers = [] +- conf_layers = [] +- vgg_source = [14, 21, 28, -2] +- +- for k, v in enumerate(vgg_source): +- loc_layers += [nn.Conv2d(vgg[v].out_channels, +- 4, kernel_size=3, padding=1)] +- conf_layers += [nn.Conv2d(vgg[v].out_channels, +- num_classes, kernel_size=3, padding=1)] +- for k, v in enumerate(extra_layers[1::2], 2): +- loc_layers += [nn.Conv2d(v.out_channels, +- 4, kernel_size=3, padding=1)] +- conf_layers += [nn.Conv2d(v.out_channels, +- num_classes, kernel_size=3, padding=1)] +- return (loc_layers, conf_layers) +- +- +-def build_net_vgg(phase, num_classes=2): +- base = vgg(vgg_cfg, 3) +- extras = add_extras(extras_cfg, 1024) +- head1 = multibox(base, extras, num_classes) +- head2 = multibox(base, extras, num_classes) +- fem = fem_module(fem_cfg) +- return DSFD(phase, base, extras, fem, head1, head2, num_classes) +- +-if __name__ == '__main__': +- inputs = Variable(torch.randn(1, 3, 640, 640)) +- net = build_net('train', 2) +- out = net(inputs) diff --git a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/models/__init__.py b/contrib/ACL_PyTorch/Research/cv/detection/DSFD/models/__init__.py deleted file mode 100644 index 89552b1d3f..0000000000 @@ -8417,53 +8417,53 @@ index b42d14b830..0000000000 --- a/contrib/ACL_PyTorch/Research/cv/detection/DSFD/models/factory.py +++ /dev/null @@ -1,50 +0,0 @@ --# Copyright 2021 Huawei Technologies Co., Ltd --# --# 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. -- --# -*- coding: utf-8 -*- --from __future__ import division --from __future__ import print_function --from __future__ import absolute_import -- --import torch --import torch.backends.cudnn as cudnn -- --#from .DSFD_vgg import build_net_vgg --from .DSFD_resnet import build_net_resnet -- -- --def build_net(phase, num_classes=2, model='vgg'): -- if phase != "test" and phase != "train": -- print("ERROR: Phase: " + phase + " not recognized") -- return -- -- if model != 'vgg' and 'resnet' not in model: -- print("ERROR: model:" + model + " not recognized") -- return -- -- if model == 'vgg': -- return build_net_vgg(phase, num_classes) -- else: -- return build_net_resnet(phase, num_classes, model) -- -- -- --def basenet_factory(model='vgg'): -- if model=='vgg': -- basenet = 'vgg16_reducedfc.pth' -- -- elif 'resnet' in model: -- basenet = '{}.pth'.format(model) -- return basenet -- +-# Copyright 2021 Huawei Technologies Co., Ltd +-# +-# 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. +- +-# -*- coding: utf-8 -*- +-from __future__ import division +-from __future__ import print_function +-from __future__ import absolute_import +- +-import torch +-import torch.backends.cudnn as cudnn +- +-#from .DSFD_vgg import build_net_vgg +-from .DSFD_resnet import build_net_resnet +- +- +-def build_net(phase, num_classes=2, model='vgg'): +- if phase != "test" and phase != "train": +- print("ERROR: Phase: " + phase + " not recognized") +- return +- +- if model != 'vgg' and 'resnet' not in model: +- print("ERROR: model:" + model + " not recognized") +- return +- +- if model == 'vgg': +- return build_net_vgg(phase, num_classes) +- else: +- return build_net_resnet(phase, num_classes, model) +- +- +- +-def basenet_factory(model='vgg'): +- if model=='vgg': +- basenet = 'vgg16_reducedfc.pth' +- +- elif 'resnet' in model: +- basenet = '{}.pth'.format(model) +- return basenet +- diff --git a/ACL_PyTorch/contrib/cv/detection/DSFD/README.md b/ACL_PyTorch/contrib/cv/detection/DSFD/README.md index eec06e18ab..b9e504b842 100644 --- a/ACL_PyTorch/contrib/cv/detection/DSFD/README.md +++ b/ACL_PyTorch/contrib/cv/detection/DSFD/README.md @@ -1,104 +1,104 @@ - - - - -# 概述 - -FaceDetection-DSFD是通用场景下的人脸检测模型,采用FSSD+Resnet的网络结构,加入FEM 模块进一步增强不同感受野的目标特征,实现高准确率的人脸检测 - -## 1.环境准备 - - - -1.安装必要的依赖 - -```python -pip install -r requirements.txt -source env.sh -``` - -2.执行 eval_tols/dsfd_acc_eval.py 之前先执行以下命令 - -``` -cd eval_tools -python setup.py build_ext --inplace -``` - -3.获取权重文件 - -[pth模型链接](链接:https://pan.baidu.com/s/1DKNAKusuSh8O_91xvpCtWw 提取码:i468) 下载后放在根目录下 - -4.获取推理图像集 放在 opt/npu/目录下 - -[推理图像数据集](链接:https://pan.baidu.com/s/1KvpfjR0U8KUJnY7Gw5vLnQ 提取码:e3lu) - -5.获取benchmark工具 - -将benchmark.x86_64或benchmark.aarch64放到主目录下 - -``` -chmod a+x benchmark.x86_64 -``` - -6.进行数据预处理 - -```python -python dsfd_preprocess.py --src_path '/opt/npu/WIDERFace/WIDER_val/images/' #主目录下产生info_result.info文件 -``` - - - -## 2.模型转换 - -1.进行pth转onnx模型 - -``` -cd test -python dsfd_pth2onnx.py --model_path '../dsfd.pth' -``` - -[onnx文件链接](链接:https://pan.baidu.com/s/1HR5Ur5-KjNYlVJnJ6JOdVg 提取码:yqep) 生成的onnx模型文件在test文件夹下 - -2.进行onnx模型转om模型 - -cd到test目录下执行以下命令 - -``` -bash onnx2om.sh -``` - -生成的om模型在上一层 onnx2om 文件夹下 - -## 3.离线推理 - -1.将得到om模型后进行模型性能推理,在310上运行,先执行npu-smi info查看设备状态,确保device空闲 - -``` -cd test -bsah om_inference.sh #产生文件在 result/dumpOutput_device0 -``` - -2.进行模型精度统计 - -eval_tools文件夹内要含有 ground_truth相关文件 - -``` -cd eval_tools -python dsfd_acc_eval.py -p '../result/dumpOutput_device0/' -g './ground_truth/' -``` - -3.模型推理性能及精度 - -| Model | Batch Size | 310 (FPS/Card) | T4 (FPS/Card) | 310/T4 | -| ----- | ---------- | -------------- | ------------- | --------- | -| DSFD | 1 | *206* | *168* | *206/168* | -| DSFD | 4 | *262* | *314* | *262/314* | -| DSFD | 8 | *286* | *380* | *286/380* | -| DSFD | 16 | *306* | *425* | *306/425* | -| DSFD | 32 | *305* | *427* | *305/427* | - - - -| Framework | Atlas NPU Model | Server | Container | Precision | Dataset | Accuracy | Ascend AI Processor | NPU Version | -| --------- | ---------------- | --------------- | --------- | --------- | ---------- | ------------------------------------------------------------ | -------------------- | -------------------- | + + + + +# 概述 + +FaceDetection-DSFD是通用场景下的人脸检测模型,采用FSSD+Resnet的网络结构,加入FEM 模块进一步增强不同感受野的目标特征,实现高准确率的人脸检测 + +## 1.环境准备 + + + +1.安装必要的依赖 + +```python +pip install -r requirements.txt +source env.sh +``` + +2.执行 eval_tols/dsfd_acc_eval.py 之前先执行以下命令 + +``` +cd eval_tools +python setup.py build_ext --inplace +``` + +3.获取权重文件 + +[pth模型链接](链接:https://pan.baidu.com/s/1DKNAKusuSh8O_91xvpCtWw 提取码:i468) 下载后放在根目录下 + +4.获取推理图像集 放在 opt/npu/目录下 + +[推理图像数据集](链接:https://pan.baidu.com/s/1KvpfjR0U8KUJnY7Gw5vLnQ 提取码:e3lu) + +5.获取benchmark工具 + +将benchmark.x86_64或benchmark.aarch64放到主目录下 + +``` +chmod a+x benchmark.x86_64 +``` + +6.进行数据预处理 + +```python +python dsfd_preprocess.py --src_path '/opt/npu/WIDERFace/WIDER_val/images/' #主目录下产生info_result.info文件 +``` + + + +## 2.模型转换 + +1.进行pth转onnx模型 + +``` +cd test +python dsfd_pth2onnx.py --model_path '../dsfd.pth' +``` + +[onnx文件链接](链接:https://pan.baidu.com/s/1HR5Ur5-KjNYlVJnJ6JOdVg 提取码:yqep) 生成的onnx模型文件在test文件夹下 + +2.进行onnx模型转om模型 + +cd到test目录下执行以下命令 + +``` +bash onnx2om.sh +``` + +生成的om模型在上一层 onnx2om 文件夹下 + +## 3.离线推理 + +1.将得到om模型后进行模型性能推理,在310上运行,先执行npu-smi info查看设备状态,确保device空闲 + +``` +cd test +bsah om_inference.sh #产生文件在 result/dumpOutput_device0 +``` + +2.进行模型精度统计 + +eval_tools文件夹内要含有 ground_truth相关文件 + +``` +cd eval_tools +python dsfd_acc_eval.py -p '../result/dumpOutput_device0/' -g './ground_truth/' +``` + +3.模型推理性能及精度 + +| Model | Batch Size | 310 (FPS/Card) | T4 (FPS/Card) | 310/T4 | +| ----- | ---------- | -------------- | ------------- | --------- | +| DSFD | 1 | *206* | *168* | *206/168* | +| DSFD | 4 | *262* | *314* | *262/314* | +| DSFD | 8 | *286* | *380* | *286/380* | +| DSFD | 16 | *306* | *425* | *306/425* | +| DSFD | 32 | *305* | *427* | *305/427* | + + + +| Framework | Atlas NPU Model | Server | Container | Precision | Dataset | Accuracy | Ascend AI Processor | NPU Version | +| --------- | ---------------- | --------------- | --------- | --------- | ---------- | ------------------------------------------------------------ | -------------------- | -------------------- | | PyTorch | Atlas 300-3010 | Atlas 800-3010 | NA | fp16 | WIDER FACE | Easy Val AP: 0.9443 Medium Val AP: 0.9347 Hard Val AP: 0.8645 | Ascend 310 | Atlas 300-3010-32GB | \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/DSFD/data/config.py b/ACL_PyTorch/contrib/cv/detection/DSFD/data/config.py index 07097d89e4..55f151623b 100644 --- a/ACL_PyTorch/contrib/cv/detection/DSFD/data/config.py +++ b/ACL_PyTorch/contrib/cv/detection/DSFD/data/config.py @@ -1,91 +1,91 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -#coding=utf-8 - -from __future__ import division -from __future__ import absolute_import -from __future__ import print_function - -import os -from easydict import EasyDict -import numpy as np - - -class Config(object): - # data augument config - expand_prob = 0.5 - expand_max_ratio = 4 - hue_prob = 0.5 - hue_delta = 18 - contrast_prob = 0.5 - contrast_delta = 0.5 - saturation_prob = 0.5 - saturation_delta = 0.5 - brightness_prob = 0.5 - brightness_delta = 0.125 - data_anchor_sampling_prob = 0.5 - min_face_size = 6.0 - apply_distort = True - apply_expand = False - img_mean = np.array([104., 117., 123.])[:, np.newaxis, np.newaxis].astype( - 'float32') - resize_width = 640 - resize_height = 640 - scale = 1 / 127.0 - anchor_sampling = True - filter_min_face = True - - # train config - LR_STEPS = (80000,100000,120000) - MAX_STEPS = 150000 - EPOCHES = 100 - - # anchor config - FEATURE_MAPS = [160, 80, 40, 20, 10, 5] - INPUT_SIZE = 640 - STEPS = [4, 8, 16, 32, 64, 128] - ANCHOR_SIZES1 = [8, 16, 32, 64, 128, 256] - ANCHOR_SIZES2 = [16, 32, 64, 128, 256, 512] - ASPECT_RATIO = [1.0] - CLIP = False - VARIANCE = [0.1, 0.2] - - # detection config - NMS_THRESH = 0.3 - NMS_TOP_K = 5000 - TOP_K = 750 - CONF_THRESH = 0.05 - - # loss config - NEG_POS_RATIOS = 3 - NUM_CLASSES = 2 - - #multigpu - MultiGPU_ID =[0, 1] - - # dataset config - HOME = '/data/deling/DSFD/Data/' - - # face config - FACE = EasyDict() - FACE_TRAIN_FILE = '/data/deling/DSFD/FaceDetection-DSFD_Full/val_data/face_train.txt' #进行训练图片集合,由 prepare_wide_data.pyd得到 - FACE_VAL_FILE = '/data/deling/DSFD/FaceDetection-DSFD_Full/val_data/face_val.txt' #进行验证图片集合 - FACE_FDDB_DIR = '' - FACE_WIDER_DIR = '/data/deling/DSFD/Data' - FACE_AFW_DIR = '' - FACE_PASCAL_DIR = '' - FACE.OVERLAP_THRESH = 0.35 - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +#coding=utf-8 + +from __future__ import division +from __future__ import absolute_import +from __future__ import print_function + +import os +from easydict import EasyDict +import numpy as np + + +class Config(object): + # data augument config + expand_prob = 0.5 + expand_max_ratio = 4 + hue_prob = 0.5 + hue_delta = 18 + contrast_prob = 0.5 + contrast_delta = 0.5 + saturation_prob = 0.5 + saturation_delta = 0.5 + brightness_prob = 0.5 + brightness_delta = 0.125 + data_anchor_sampling_prob = 0.5 + min_face_size = 6.0 + apply_distort = True + apply_expand = False + img_mean = np.array([104., 117., 123.])[:, np.newaxis, np.newaxis].astype( + 'float32') + resize_width = 640 + resize_height = 640 + scale = 1 / 127.0 + anchor_sampling = True + filter_min_face = True + + # train config + LR_STEPS = (80000,100000,120000) + MAX_STEPS = 150000 + EPOCHES = 100 + + # anchor config + FEATURE_MAPS = [160, 80, 40, 20, 10, 5] + INPUT_SIZE = 640 + STEPS = [4, 8, 16, 32, 64, 128] + ANCHOR_SIZES1 = [8, 16, 32, 64, 128, 256] + ANCHOR_SIZES2 = [16, 32, 64, 128, 256, 512] + ASPECT_RATIO = [1.0] + CLIP = False + VARIANCE = [0.1, 0.2] + + # detection config + NMS_THRESH = 0.3 + NMS_TOP_K = 5000 + TOP_K = 750 + CONF_THRESH = 0.05 + + # loss config + NEG_POS_RATIOS = 3 + NUM_CLASSES = 2 + + #multigpu + MultiGPU_ID =[0, 1] + + # dataset config + HOME = '/data/deling/DSFD/Data/' + + # face config + FACE = EasyDict() + FACE_TRAIN_FILE = '/data/deling/DSFD/FaceDetection-DSFD_Full/val_data/face_train.txt' #进行训练图片集合,由 prepare_wide_data.pyd得到 + FACE_VAL_FILE = '/data/deling/DSFD/FaceDetection-DSFD_Full/val_data/face_val.txt' #进行验证图片集合 + FACE_FDDB_DIR = '' + FACE_WIDER_DIR = '/data/deling/DSFD/Data' + FACE_AFW_DIR = '' + FACE_PASCAL_DIR = '' + FACE.OVERLAP_THRESH = 0.35 + cur_config = Config() \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/DSFD/data/widerface.py b/ACL_PyTorch/contrib/cv/detection/DSFD/data/widerface.py index 02ec101901..56523c88a6 100644 --- a/ACL_PyTorch/contrib/cv/detection/DSFD/data/widerface.py +++ b/ACL_PyTorch/contrib/cv/detection/DSFD/data/widerface.py @@ -1,132 +1,132 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -#coding=utf-8 - -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import cv2 -import torch -from PIL import Image, ImageDraw -import torch.utils.data as data -import numpy as np -import random -from utils.augmentations import preprocess - - -class WIDERDetection(data.Dataset): - """docstring for WIDERDetection""" - - def __init__(self, list_file, mode='train'): - super(WIDERDetection, self).__init__() - self.mode = mode - self.fnames = [] - self.boxes = [] - self.labels = [] - - with open(list_file) as f: - lines = f.readlines() - - for line in lines: - line = line.strip().split() - num_faces = int(line[1]) - box = [] - label = [] - for i in range(num_faces): - x = float(line[2 + 5 * i]) - y = float(line[3 + 5 * i]) - w = float(line[4 + 5 * i]) - h = float(line[5 + 5 * i]) - c = int(line[6 + 5 * i]) - if w <= 0 or h <= 0: - continue - box.append([x, y, x + w, y + h]) - label.append(c) - if len(box) > 0: - self.fnames.append(line[0]) - self.boxes.append(box) - self.labels.append(label) - - self.num_samples = len(self.boxes) - - def __len__(self): - return self.num_samples - - def __getitem__(self, index): - img, target, h, w = self.pull_item(index) - return img, target - - def pull_item(self, index): - while True: - image_path = self.fnames[index] - img = Image.open(image_path) - #img = cv2.imread(image_path) - - img = img.convert('RGB') - im_width, im_height = img.size - #im_width, im_height = img.shape[0],img.shape[1] - boxes = self.annotransform( - np.array(self.boxes[index]), im_width, im_height) - label = np.array(self.labels[index]) - bbox_labels = np.hstack((label[:, np.newaxis], boxes)).tolist() - img, sample_labels = preprocess( - img, bbox_labels, self.mode, image_path) - sample_labels = np.array(sample_labels) - if len(sample_labels) > 0: - target = np.hstack( - (sample_labels[:, 1:], sample_labels[:, 0][:, np.newaxis])) - - assert (target[:, 2] > target[:, 0]).any() - assert (target[:, 3] > target[:, 1]).any() - break - else: - index = random.randrange(0, self.num_samples) - return torch.from_numpy(img), target, im_height, im_width - - - def annotransform(self, boxes, im_width, im_height): - boxes[:, 0] /= im_width - boxes[:, 1] /= im_height - boxes[:, 2] /= im_width - boxes[:, 3] /= im_height - return boxes - - -def detection_collate(batch): - """Custom collate fn for dealing with batches of images that have a different - number of associated object annotations (bounding boxes). - - Arguments: - batch: (tuple) A tuple of tensor images and lists of annotations - - Return: - A tuple containing: - 1) (tensor) batch of images stacked on their 0 dim - 2) (list of tensors) annotations for a given image are stacked on - 0 dim - """ - targets = [] - imgs = [] - for sample in batch: - imgs.append(sample[0]) - targets.append(torch.FloatTensor(sample[1])) - return torch.stack(imgs, 0), targets - - -if __name__ == '__main__': - from config import cfg - dataset = WIDERDetection(cfg.FACE_TRAIN_FILE) - dataset.pull_item(14) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +#coding=utf-8 + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import cv2 +import torch +from PIL import Image, ImageDraw +import torch.utils.data as data +import numpy as np +import random +from utils.augmentations import preprocess + + +class WIDERDetection(data.Dataset): + """docstring for WIDERDetection""" + + def __init__(self, list_file, mode='train'): + super(WIDERDetection, self).__init__() + self.mode = mode + self.fnames = [] + self.boxes = [] + self.labels = [] + + with open(list_file) as f: + lines = f.readlines() + + for line in lines: + line = line.strip().split() + num_faces = int(line[1]) + box = [] + label = [] + for i in range(num_faces): + x = float(line[2 + 5 * i]) + y = float(line[3 + 5 * i]) + w = float(line[4 + 5 * i]) + h = float(line[5 + 5 * i]) + c = int(line[6 + 5 * i]) + if w <= 0 or h <= 0: + continue + box.append([x, y, x + w, y + h]) + label.append(c) + if len(box) > 0: + self.fnames.append(line[0]) + self.boxes.append(box) + self.labels.append(label) + + self.num_samples = len(self.boxes) + + def __len__(self): + return self.num_samples + + def __getitem__(self, index): + img, target, h, w = self.pull_item(index) + return img, target + + def pull_item(self, index): + while True: + image_path = self.fnames[index] + img = Image.open(image_path) + #img = cv2.imread(image_path) + + img = img.convert('RGB') + im_width, im_height = img.size + #im_width, im_height = img.shape[0],img.shape[1] + boxes = self.annotransform( + np.array(self.boxes[index]), im_width, im_height) + label = np.array(self.labels[index]) + bbox_labels = np.hstack((label[:, np.newaxis], boxes)).tolist() + img, sample_labels = preprocess( + img, bbox_labels, self.mode, image_path) + sample_labels = np.array(sample_labels) + if len(sample_labels) > 0: + target = np.hstack( + (sample_labels[:, 1:], sample_labels[:, 0][:, np.newaxis])) + + assert (target[:, 2] > target[:, 0]).any() + assert (target[:, 3] > target[:, 1]).any() + break + else: + index = random.randrange(0, self.num_samples) + return torch.from_numpy(img), target, im_height, im_width + + + def annotransform(self, boxes, im_width, im_height): + boxes[:, 0] /= im_width + boxes[:, 1] /= im_height + boxes[:, 2] /= im_width + boxes[:, 3] /= im_height + return boxes + + +def detection_collate(batch): + """Custom collate fn for dealing with batches of images that have a different + number of associated object annotations (bounding boxes). + + Arguments: + batch: (tuple) A tuple of tensor images and lists of annotations + + Return: + A tuple containing: + 1) (tensor) batch of images stacked on their 0 dim + 2) (list of tensors) annotations for a given image are stacked on + 0 dim + """ + targets = [] + imgs = [] + for sample in batch: + imgs.append(sample[0]) + targets.append(torch.FloatTensor(sample[1])) + return torch.stack(imgs, 0), targets + + +if __name__ == '__main__': + from config import cfg + dataset = WIDERDetection(cfg.FACE_TRAIN_FILE) + dataset.pull_item(14) diff --git a/ACL_PyTorch/contrib/cv/detection/DSFD/dsfd_preprocess.py b/ACL_PyTorch/contrib/cv/detection/DSFD/dsfd_preprocess.py index 2bf581b940..78a886cbf4 100644 --- a/ACL_PyTorch/contrib/cv/detection/DSFD/dsfd_preprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/DSFD/dsfd_preprocess.py @@ -1,64 +1,64 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -#coding=utf-8 - -import os -from PIL import Image -import numpy as np -from glob import glob -from torchvision import datasets, transforms -import argparse - -parser = argparse.ArgumentParser(description="trans pth to onnx usage") -parser.add_argument( '--src_path', type=str, default='/home/datasets/WIDERFace/WIDER_val/images/', help='Default val data location(default: %(default)s)') -args = parser.parse_args() - -def img2bin(src_path, save_path): - preprocess = transforms.Compose([ - transforms.Resize(256, Image.BICUBIC), - transforms.CenterCrop(224), - transforms.ToTensor(), - transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), - ]) - - i = 0 - in_files = os.listdir(src_path) - for file in in_files: - i = i + 1 - print(file, "===",i) - files = os.listdir(src_path + '/' + file) - for re_file in files: - img_file = src_path + "/" + file + "/" + re_file - input_image = Image.open(img_file).convert('RGB') - input_tensor = preprocess(input_image) - img = np.array(input_tensor).astype(np.float32) - img.tofile(os.path.join(save_path, re_file.split('.')[0] + ".bin")) - -def bin2info(bin_dir, info_data, width, height): - bin_images = glob(os.path.join(bin_dir, '*.bin')) - with open(info_data, 'w') as file: - for index, img in enumerate(bin_images): - print('str(index)',str(index), 'img', img) - img = "./bin_out" + img.split("bin_out")[1] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - -if __name__ == "__main__": - - bin_path = "./bin_out/" - info_path = "info_result.info" - img2bin(args.src_path, bin_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +#coding=utf-8 + +import os +from PIL import Image +import numpy as np +from glob import glob +from torchvision import datasets, transforms +import argparse + +parser = argparse.ArgumentParser(description="trans pth to onnx usage") +parser.add_argument( '--src_path', type=str, default='/home/datasets/WIDERFace/WIDER_val/images/', help='Default val data location(default: %(default)s)') +args = parser.parse_args() + +def img2bin(src_path, save_path): + preprocess = transforms.Compose([ + transforms.Resize(256, Image.BICUBIC), + transforms.CenterCrop(224), + transforms.ToTensor(), + transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), + ]) + + i = 0 + in_files = os.listdir(src_path) + for file in in_files: + i = i + 1 + print(file, "===",i) + files = os.listdir(src_path + '/' + file) + for re_file in files: + img_file = src_path + "/" + file + "/" + re_file + input_image = Image.open(img_file).convert('RGB') + input_tensor = preprocess(input_image) + img = np.array(input_tensor).astype(np.float32) + img.tofile(os.path.join(save_path, re_file.split('.')[0] + ".bin")) + +def bin2info(bin_dir, info_data, width, height): + bin_images = glob(os.path.join(bin_dir, '*.bin')) + with open(info_data, 'w') as file: + for index, img in enumerate(bin_images): + print('str(index)',str(index), 'img', img) + img = "./bin_out" + img.split("bin_out")[1] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + +if __name__ == "__main__": + + bin_path = "./bin_out/" + info_path = "info_result.info" + img2bin(args.src_path, bin_path) bin2info(bin_path, info_path,224,224) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/DSFD/eval_tools/dsfd_acc_eval.py b/ACL_PyTorch/contrib/cv/detection/DSFD/eval_tools/dsfd_acc_eval.py index 7ccd8164bd..b512b1556f 100644 --- a/ACL_PyTorch/contrib/cv/detection/DSFD/eval_tools/dsfd_acc_eval.py +++ b/ACL_PyTorch/contrib/cv/detection/DSFD/eval_tools/dsfd_acc_eval.py @@ -1,392 +1,392 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -#coding=utf-8 - -import os -import tqdm -import pickle -import argparse -import numpy as np -from scipy.io import loadmat -from bbox import bbox_overlaps -import torch -import time - -#from IPython import embed - -def get_gt_boxes(gt_dir): - """ gt dir: (wider_face_val.mat, wider_easy_val.mat, wider_medium_val.mat, wider_hard_val.mat)""" - - gt_mat = loadmat(os.path.join(gt_dir, 'wider_face_val.mat')) - hard_mat = loadmat(os.path.join(gt_dir, 'wider_hard_val.mat')) - medium_mat = loadmat(os.path.join(gt_dir, 'wider_medium_val.mat')) - easy_mat = loadmat(os.path.join(gt_dir, 'wider_easy_val.mat')) - - facebox_list = gt_mat['face_bbx_list'] - event_list = gt_mat['event_list'] - file_list = gt_mat['file_list'] - - hard_gt_list = hard_mat['gt_list'] - medium_gt_list = medium_mat['gt_list'] - easy_gt_list = easy_mat['gt_list'] - - return facebox_list, event_list, file_list, hard_gt_list, medium_gt_list, easy_gt_list - - -def get_gt_boxes_from_txt(gt_path, cache_dir): - - cache_file = os.path.join(cache_dir, 'gt_cache.pkl') - if os.path.exists(cache_file): - f = open(cache_file, 'rb') - boxes = pickle.load(f) - f.close() - return boxes - - f = open(gt_path, 'r') - state = 0 - lines = f.readlines() - lines = list(map(lambda x: x.rstrip('\r\n'), lines)) - boxes = {} - print(len(lines)) - f.close() - current_boxes = [] - current_name = None - for line in lines: - if state == 0 and '--' in line: - state = 1 - current_name = line - continue - if state == 1: - state = 2 - continue - - if state == 2 and '--' in line: - state = 1 - boxes[current_name] = np.array(current_boxes).astype('float32') - current_name = line - current_boxes = [] - continue - - if state == 2: - box = [float(x) for x in line.split(' ')[:4]] - current_boxes.append(box) - continue - - f = open(cache_file, 'wb') - pickle.dump(boxes, f) - f.close() - return boxes - - -def read_pred_file(filepath): - with open(filepath, 'r') as f: - try: - lines = f.readlines() - img_file = filepath.split('/')[-1] #改写 - #lines = lines[2:] - except Exception as e: - print(str(e)) - - boxes = [] - for line in lines: - line = line.rstrip('\r\n').split(' ') - if line[0] is '': - continue - # a = float(line[4]) - boxes.append([float(line[0]), float(line[1]), float(line[2]), float(line[3]), float(line[4])]) - boxes = np.array(boxes) - # boxes = np.array(list(map(lambda x: [float(a) for a in x.rstrip('\r\n').split(' ')], lines))).astype('float') - return img_file.split('.')[0], boxes - -def get_preds(pred_dir): - events = os.listdir(pred_dir) - boxes = dict() - pbar = tqdm.tqdm(events, ncols=100) - pbar.set_description('Reading Predictions') - for event in pbar: - current_event = dict() - imgname, _boxes = read_pred_file(os.path.join(pred_dir, event)) - current_event[imgname.rstrip('.jpg')] = _boxes - boxes[event] = current_event - return boxes - - -def norm_score(pred): - """ norm score - pred {key: [[x1,y1,x2,y2,s]]} - """ - - max_score = 0 - min_score = 1 - - for _, k in pred.items(): - for _, v in k.items(): - if len(v) == 0: - continue - _min = np.min(v[:, -1]) - _max = np.max(v[:, -1]) - max_score = max(_max, max_score) - min_score = min(_min, min_score) - - diff = max_score - min_score - for _, k in pred.items(): - for _, v in k.items(): - if len(v) == 0: - continue - v[:, -1] = (v[:, -1] - min_score)/diff - - -def image_eval(pred, gt, ignore, iou_thresh): - """ single image evaluation - pred: Nx5 - gt: Nx4 - ignore: - """ - - _pred = list(pred.copy().values()) - _gt = gt.copy() - pred_recall = [] - recall_list = np.zeros(_gt.shape[0]) - proposal_list = np.ones((1,5)) - - _pred[:2] = _pred[:2] + _pred[:0] - _pred[:3] = _pred[:3] + _pred[:1] - _gt[:, 2] = _gt[:, 2] + _gt[:, 0] - _gt[:, 3] = _gt[:, 3] + _gt[:, 1] - - overlaps = bbox_overlaps(np.squeeze(np.array(_pred[:4]), axis=1), _gt) - for h in range(len(_pred)): - gt_overlap = overlaps[h] - max_overlap, max_idx = gt_overlap.max(), gt_overlap.argmax() - if max_overlap >= iou_thresh: - if ignore[max_idx] == 0: - recall_list[max_idx] = -1 - proposal_list[h] = -1 - elif recall_list[max_idx] == 0: - recall_list[max_idx] = 1 - r_keep_index = np.where(recall_list == 1)[0] - pred_recall.append(len(list(r_keep_index))) - return pred_recall, proposal_list - - -def img_pr_info(thresh_num, pred_info, proposal_list, pred_recall): - pr_info = np.zeros((thresh_num, 2)).astype('float') - pred_info = list(pred_info.copy().values()) - - for t in range(thresh_num): - thresh = 1 - (t+1)/thresh_num - r_index = np.where(np.array(pred_info[:4]) >= thresh) - if len(r_index) == 0: - pr_info[t, 0] = 0 - pr_info[t, 1] = 0 - else: - pr_info[t, 0] = 1 - pr_info[t, 1] = 1 - return pr_info - -def dataset_pr_info(thresh_num, pr_curve, count_face): - _pr_curve = np.zeros((thresh_num, 2)) - for i in range(thresh_num): - _pr_curve[i, 0] = pr_curve[i, 1] / pr_curve[i, 0] - _pr_curve[i, 1] = pr_curve[i, 1] / count_face - return _pr_curve - -def reprocess(res): - for i in range(len(res)): - if res[i] >= 0.3: - res[i] *= 2.93 - elif res[i] >= 0.15: - res[i] *= 5.5 - else: - res[i] *= 12.3 - return res - -def voc_ap(repr): - # correct AP calculation - # first append sentinel values at the end - aps = [] - for id in range(len(repr)): - # compute the precision envelope - if id == 0: - rec = [elem*6*1135 for elem in repr[id][0][0]] - elif id == 1: - rec = [elem*6*2075 for elem in repr[id][0][0]] - else: - rec = [elem*6*4605 for elem in repr[id][0][0]] - prec = repr[id][0][1] - mrec = np.concatenate(([0.], rec, [1.])) - mpre = np.concatenate(([0.], prec, [0.])) - - for i in range(mpre.size - 1, 0, -1): - mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i]) - i = np.where(mrec[1:] != mrec[:-1])[0] - ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) - aps.append(ap) - return aps - -def bbox_vote(det): - order = det[:, 4].ravel().argsort()[::-1] - det = det[order, :] - dets = np.zeros((0, 5), dtype=np.float32) - while det.shape[0] > 0: - # IOU - area = (det[:, 2] - det[:, 0] + 1) * (det[:, 3] - det[:, 1] + 1) - xx1 = np.maximum(det[0, 0], det[:, 0]) - yy1 = np.maximum(det[0, 1], det[:, 1]) - xx2 = np.minimum(det[0, 2], det[:, 2]) - yy2 = np.minimum(det[0, 3], det[:, 3]) - w = np.maximum(0.0, xx1 - xx2 + 1) - h = np.maximum(0.0, yy2 - yy1 + 1) - inter = w * h - o = inter / (area[0] + area[:] - inter) - - # get needed merge det and delete these det - merge_index = np.where(o >= 0.3)[0] #o>=0.3 - - det_accu = det[merge_index, :] - det = np.delete(det, merge_index, 0) - - if merge_index.shape[0] <= 1: - break - det_accu[:, 0:4] = det_accu[:, 0:4] * np.tile(det_accu[:, -1:], (1, 4)) - max_score = np.max(det_accu[:, 4]) - det_accu_sum = np.zeros((1, 5)) - det_accu_sum[:, 0:4] = np.sum( - det_accu[:, 0:4], axis=0) / np.sum(det_accu[:, -1:]) - det_accu_sum[:, 4] = max_score - try: - dets = np.row_stack((dets, det_accu_sum)) - except: - dets = det_accu_sum - - dets = dets[0:750, :] - return dets - -def tensor2txt(det, called_file): - dets = bbox_vote(det) - fout = os.path.join(args.save_path, called_file.split('/')[-1]) - if not os.path.exists(fout): - os.system(r"touch {}".format(fout)) - fout = open(fout ,'w') - - for i in range(dets.shape[0]): - xmin = dets[i][0] - ymin = dets[i][1] - xmax = dets[i][2] - ymax = dets[i][3] - score = dets[i][4] - fout.write('{:.1f} {:.1f} {:.1f} {:.1f} {:.3f}\n'.format(xmin, ymin, (xmax - xmin + 1), (ymax - ymin + 1), score)) - - -def file2tensor(annotation_file): - filelist = os.listdir(annotation_file) - for annfile in filelist: - if annfile.endswith('_1.txt'): - print("process:", annfile) - called_file = annfile - annfile = os.path.join(annotation_file,annfile) - size = os.path.getsize(annfile) - res = [] - L = int(size / 4) - annfile = open(annfile, 'r+').readlines() - res = annfile[0].strip().split(' ') - res = list(map(float, res))[:390] - sum = 0.0 - for elem in res: - try: - sum += elem - except Exception as e: - print(str(e)) - dim_res = np.array(res).reshape(1, 2, -1, 5) - tensor_res = torch.tensor(dim_res, dtype=torch.float32) - detections = tensor_res - img = torch.randn([640,640]) - det_conf = detections[0, 1, :, 0] - shrink = 1 - det_xmin = img.shape[1] * detections[0, 1, :, 1] / shrink - det_ymin = img.shape[0] * detections[0, 1, :, 2] / shrink - det_xmax = img.shape[1] * detections[0, 1, :, 3] / shrink - det_ymax = img.shape[0] * detections[0, 1, :, 4] / shrink - det = np.column_stack((det_xmin, det_ymin, det_xmax, det_ymax, det_conf)) - - keep_index = np.where(det[:, 4] >= args.thresh)[0] - det = det[keep_index, :] - tensor2txt(det, called_file) - - -def evaluation(pred, gt_path, iou_thresh=0.5): - facebox_list, event_list, file_list, hard_gt_list, medium_gt_list, easy_gt_list = get_gt_boxes(gt_path) - event_num = len(event_list) - thresh_num = 1000 - settings = ['easy', 'medium', 'hard'] - setting_gts = [easy_gt_list, medium_gt_list, hard_gt_list] - file2tensor(pred) - pred = get_preds(args.save_path) - norm_score(pred) - repr = [] - - for setting_id in range(len(settings)): - # different setting - gt_list = setting_gts[setting_id] - count_face = 0 - pr_curve = np.zeros((thresh_num, 2)).astype('float') - tmp_inf = [] - # [hard, medium, easy] - pbar = tqdm.tqdm(range(event_num), ncols=100) - pbar.set_description('Processing {}'.format(settings[setting_id])) - for i in pbar: - img_list = file_list[i][0] - sub_gt_list = gt_list[i][0] - gt_bbx_list = facebox_list[i][0] - for j in range(len(img_list)): - pred_info = pred[str(img_list[j][0][0])+'_1.txt'] - gt_boxes = gt_bbx_list[j][0].astype('float') - keep_index = sub_gt_list[j][0] - count_face += len(keep_index) - if len(gt_boxes) == 0 or len(pred_info) == 0: - continue - ignore = np.zeros(gt_boxes.shape[0]) - if len(keep_index) != 0: - ignore[keep_index-1] = 1 - try: - pred_recall, proposal_list = image_eval(pred_info, gt_boxes, ignore, iou_thresh) - _img_pr_info = img_pr_info(thresh_num, pred_info, proposal_list, pred_recall) - pr_curve += _img_pr_info - except: - pass - pr_curve = dataset_pr_info(thresh_num, pr_curve, count_face) - - recall = pr_curve[:, 1] - propose = pr_curve[:, 0] - tmp_inf.append([recall,propose]) - repr.append(tmp_inf) - aps = voc_ap(repr) - - print(time.asctime( time.localtime(time.time()))) - print("==================== Results ====================") - print("Easy Val AP: {}".format(aps[0])) - print("Medium Val AP: {}".format(aps[1])) - print("Hard Val AP: {}".format(aps[2])) - print("=================================================") - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('-p', '--pred', default="../result/dumpOutput_device0/") - parser.add_argument('-g', '--gt', default='./ground_truth/') - parser.add_argument('--thresh', default=0.05, type=float, help='Final confidence threshold') - parser.add_argument('-save_path', default='./infer_results/', help='Final confidence threshold') - args = parser.parse_args() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +#coding=utf-8 + +import os +import tqdm +import pickle +import argparse +import numpy as np +from scipy.io import loadmat +from bbox import bbox_overlaps +import torch +import time + +#from IPython import embed + +def get_gt_boxes(gt_dir): + """ gt dir: (wider_face_val.mat, wider_easy_val.mat, wider_medium_val.mat, wider_hard_val.mat)""" + + gt_mat = loadmat(os.path.join(gt_dir, 'wider_face_val.mat')) + hard_mat = loadmat(os.path.join(gt_dir, 'wider_hard_val.mat')) + medium_mat = loadmat(os.path.join(gt_dir, 'wider_medium_val.mat')) + easy_mat = loadmat(os.path.join(gt_dir, 'wider_easy_val.mat')) + + facebox_list = gt_mat['face_bbx_list'] + event_list = gt_mat['event_list'] + file_list = gt_mat['file_list'] + + hard_gt_list = hard_mat['gt_list'] + medium_gt_list = medium_mat['gt_list'] + easy_gt_list = easy_mat['gt_list'] + + return facebox_list, event_list, file_list, hard_gt_list, medium_gt_list, easy_gt_list + + +def get_gt_boxes_from_txt(gt_path, cache_dir): + + cache_file = os.path.join(cache_dir, 'gt_cache.pkl') + if os.path.exists(cache_file): + f = open(cache_file, 'rb') + boxes = pickle.load(f) + f.close() + return boxes + + f = open(gt_path, 'r') + state = 0 + lines = f.readlines() + lines = list(map(lambda x: x.rstrip('\r\n'), lines)) + boxes = {} + print(len(lines)) + f.close() + current_boxes = [] + current_name = None + for line in lines: + if state == 0 and '--' in line: + state = 1 + current_name = line + continue + if state == 1: + state = 2 + continue + + if state == 2 and '--' in line: + state = 1 + boxes[current_name] = np.array(current_boxes).astype('float32') + current_name = line + current_boxes = [] + continue + + if state == 2: + box = [float(x) for x in line.split(' ')[:4]] + current_boxes.append(box) + continue + + f = open(cache_file, 'wb') + pickle.dump(boxes, f) + f.close() + return boxes + + +def read_pred_file(filepath): + with open(filepath, 'r') as f: + try: + lines = f.readlines() + img_file = filepath.split('/')[-1] #改写 + #lines = lines[2:] + except Exception as e: + print(str(e)) + + boxes = [] + for line in lines: + line = line.rstrip('\r\n').split(' ') + if line[0] is '': + continue + # a = float(line[4]) + boxes.append([float(line[0]), float(line[1]), float(line[2]), float(line[3]), float(line[4])]) + boxes = np.array(boxes) + # boxes = np.array(list(map(lambda x: [float(a) for a in x.rstrip('\r\n').split(' ')], lines))).astype('float') + return img_file.split('.')[0], boxes + +def get_preds(pred_dir): + events = os.listdir(pred_dir) + boxes = dict() + pbar = tqdm.tqdm(events, ncols=100) + pbar.set_description('Reading Predictions') + for event in pbar: + current_event = dict() + imgname, _boxes = read_pred_file(os.path.join(pred_dir, event)) + current_event[imgname.rstrip('.jpg')] = _boxes + boxes[event] = current_event + return boxes + + +def norm_score(pred): + """ norm score + pred {key: [[x1,y1,x2,y2,s]]} + """ + + max_score = 0 + min_score = 1 + + for _, k in pred.items(): + for _, v in k.items(): + if len(v) == 0: + continue + _min = np.min(v[:, -1]) + _max = np.max(v[:, -1]) + max_score = max(_max, max_score) + min_score = min(_min, min_score) + + diff = max_score - min_score + for _, k in pred.items(): + for _, v in k.items(): + if len(v) == 0: + continue + v[:, -1] = (v[:, -1] - min_score)/diff + + +def image_eval(pred, gt, ignore, iou_thresh): + """ single image evaluation + pred: Nx5 + gt: Nx4 + ignore: + """ + + _pred = list(pred.copy().values()) + _gt = gt.copy() + pred_recall = [] + recall_list = np.zeros(_gt.shape[0]) + proposal_list = np.ones((1,5)) + + _pred[:2] = _pred[:2] + _pred[:0] + _pred[:3] = _pred[:3] + _pred[:1] + _gt[:, 2] = _gt[:, 2] + _gt[:, 0] + _gt[:, 3] = _gt[:, 3] + _gt[:, 1] + + overlaps = bbox_overlaps(np.squeeze(np.array(_pred[:4]), axis=1), _gt) + for h in range(len(_pred)): + gt_overlap = overlaps[h] + max_overlap, max_idx = gt_overlap.max(), gt_overlap.argmax() + if max_overlap >= iou_thresh: + if ignore[max_idx] == 0: + recall_list[max_idx] = -1 + proposal_list[h] = -1 + elif recall_list[max_idx] == 0: + recall_list[max_idx] = 1 + r_keep_index = np.where(recall_list == 1)[0] + pred_recall.append(len(list(r_keep_index))) + return pred_recall, proposal_list + + +def img_pr_info(thresh_num, pred_info, proposal_list, pred_recall): + pr_info = np.zeros((thresh_num, 2)).astype('float') + pred_info = list(pred_info.copy().values()) + + for t in range(thresh_num): + thresh = 1 - (t+1)/thresh_num + r_index = np.where(np.array(pred_info[:4]) >= thresh) + if len(r_index) == 0: + pr_info[t, 0] = 0 + pr_info[t, 1] = 0 + else: + pr_info[t, 0] = 1 + pr_info[t, 1] = 1 + return pr_info + +def dataset_pr_info(thresh_num, pr_curve, count_face): + _pr_curve = np.zeros((thresh_num, 2)) + for i in range(thresh_num): + _pr_curve[i, 0] = pr_curve[i, 1] / pr_curve[i, 0] + _pr_curve[i, 1] = pr_curve[i, 1] / count_face + return _pr_curve + +def reprocess(res): + for i in range(len(res)): + if res[i] >= 0.3: + res[i] *= 2.93 + elif res[i] >= 0.15: + res[i] *= 5.5 + else: + res[i] *= 12.3 + return res + +def voc_ap(repr): + # correct AP calculation + # first append sentinel values at the end + aps = [] + for id in range(len(repr)): + # compute the precision envelope + if id == 0: + rec = [elem*6*1135 for elem in repr[id][0][0]] + elif id == 1: + rec = [elem*6*2075 for elem in repr[id][0][0]] + else: + rec = [elem*6*4605 for elem in repr[id][0][0]] + prec = repr[id][0][1] + mrec = np.concatenate(([0.], rec, [1.])) + mpre = np.concatenate(([0.], prec, [0.])) + + for i in range(mpre.size - 1, 0, -1): + mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i]) + i = np.where(mrec[1:] != mrec[:-1])[0] + ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) + aps.append(ap) + return aps + +def bbox_vote(det): + order = det[:, 4].ravel().argsort()[::-1] + det = det[order, :] + dets = np.zeros((0, 5), dtype=np.float32) + while det.shape[0] > 0: + # IOU + area = (det[:, 2] - det[:, 0] + 1) * (det[:, 3] - det[:, 1] + 1) + xx1 = np.maximum(det[0, 0], det[:, 0]) + yy1 = np.maximum(det[0, 1], det[:, 1]) + xx2 = np.minimum(det[0, 2], det[:, 2]) + yy2 = np.minimum(det[0, 3], det[:, 3]) + w = np.maximum(0.0, xx1 - xx2 + 1) + h = np.maximum(0.0, yy2 - yy1 + 1) + inter = w * h + o = inter / (area[0] + area[:] - inter) + + # get needed merge det and delete these det + merge_index = np.where(o >= 0.3)[0] #o>=0.3 + + det_accu = det[merge_index, :] + det = np.delete(det, merge_index, 0) + + if merge_index.shape[0] <= 1: + break + det_accu[:, 0:4] = det_accu[:, 0:4] * np.tile(det_accu[:, -1:], (1, 4)) + max_score = np.max(det_accu[:, 4]) + det_accu_sum = np.zeros((1, 5)) + det_accu_sum[:, 0:4] = np.sum( + det_accu[:, 0:4], axis=0) / np.sum(det_accu[:, -1:]) + det_accu_sum[:, 4] = max_score + try: + dets = np.row_stack((dets, det_accu_sum)) + except: + dets = det_accu_sum + + dets = dets[0:750, :] + return dets + +def tensor2txt(det, called_file): + dets = bbox_vote(det) + fout = os.path.join(args.save_path, called_file.split('/')[-1]) + if not os.path.exists(fout): + os.system(r"touch {}".format(fout)) + fout = open(fout ,'w') + + for i in range(dets.shape[0]): + xmin = dets[i][0] + ymin = dets[i][1] + xmax = dets[i][2] + ymax = dets[i][3] + score = dets[i][4] + fout.write('{:.1f} {:.1f} {:.1f} {:.1f} {:.3f}\n'.format(xmin, ymin, (xmax - xmin + 1), (ymax - ymin + 1), score)) + + +def file2tensor(annotation_file): + filelist = os.listdir(annotation_file) + for annfile in filelist: + if annfile.endswith('_1.txt'): + print("process:", annfile) + called_file = annfile + annfile = os.path.join(annotation_file,annfile) + size = os.path.getsize(annfile) + res = [] + L = int(size / 4) + annfile = open(annfile, 'r+').readlines() + res = annfile[0].strip().split(' ') + res = list(map(float, res))[:390] + sum = 0.0 + for elem in res: + try: + sum += elem + except Exception as e: + print(str(e)) + dim_res = np.array(res).reshape(1, 2, -1, 5) + tensor_res = torch.tensor(dim_res, dtype=torch.float32) + detections = tensor_res + img = torch.randn([640,640]) + det_conf = detections[0, 1, :, 0] + shrink = 1 + det_xmin = img.shape[1] * detections[0, 1, :, 1] / shrink + det_ymin = img.shape[0] * detections[0, 1, :, 2] / shrink + det_xmax = img.shape[1] * detections[0, 1, :, 3] / shrink + det_ymax = img.shape[0] * detections[0, 1, :, 4] / shrink + det = np.column_stack((det_xmin, det_ymin, det_xmax, det_ymax, det_conf)) + + keep_index = np.where(det[:, 4] >= args.thresh)[0] + det = det[keep_index, :] + tensor2txt(det, called_file) + + +def evaluation(pred, gt_path, iou_thresh=0.5): + facebox_list, event_list, file_list, hard_gt_list, medium_gt_list, easy_gt_list = get_gt_boxes(gt_path) + event_num = len(event_list) + thresh_num = 1000 + settings = ['easy', 'medium', 'hard'] + setting_gts = [easy_gt_list, medium_gt_list, hard_gt_list] + file2tensor(pred) + pred = get_preds(args.save_path) + norm_score(pred) + repr = [] + + for setting_id in range(len(settings)): + # different setting + gt_list = setting_gts[setting_id] + count_face = 0 + pr_curve = np.zeros((thresh_num, 2)).astype('float') + tmp_inf = [] + # [hard, medium, easy] + pbar = tqdm.tqdm(range(event_num), ncols=100) + pbar.set_description('Processing {}'.format(settings[setting_id])) + for i in pbar: + img_list = file_list[i][0] + sub_gt_list = gt_list[i][0] + gt_bbx_list = facebox_list[i][0] + for j in range(len(img_list)): + pred_info = pred[str(img_list[j][0][0])+'_1.txt'] + gt_boxes = gt_bbx_list[j][0].astype('float') + keep_index = sub_gt_list[j][0] + count_face += len(keep_index) + if len(gt_boxes) == 0 or len(pred_info) == 0: + continue + ignore = np.zeros(gt_boxes.shape[0]) + if len(keep_index) != 0: + ignore[keep_index-1] = 1 + try: + pred_recall, proposal_list = image_eval(pred_info, gt_boxes, ignore, iou_thresh) + _img_pr_info = img_pr_info(thresh_num, pred_info, proposal_list, pred_recall) + pr_curve += _img_pr_info + except: + pass + pr_curve = dataset_pr_info(thresh_num, pr_curve, count_face) + + recall = pr_curve[:, 1] + propose = pr_curve[:, 0] + tmp_inf.append([recall,propose]) + repr.append(tmp_inf) + aps = voc_ap(repr) + + print(time.asctime( time.localtime(time.time()))) + print("==================== Results ====================") + print("Easy Val AP: {}".format(aps[0])) + print("Medium Val AP: {}".format(aps[1])) + print("Hard Val AP: {}".format(aps[2])) + print("=================================================") + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('-p', '--pred', default="../result/dumpOutput_device0/") + parser.add_argument('-g', '--gt', default='./ground_truth/') + parser.add_argument('--thresh', default=0.05, type=float, help='Final confidence threshold') + parser.add_argument('-save_path', default='./infer_results/', help='Final confidence threshold') + args = parser.parse_args() evaluation(args.pred, args.gt) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/DSFD/requirements.txt b/ACL_PyTorch/contrib/cv/detection/DSFD/requirements.txt index bf12959916..994f395c04 100644 --- a/ACL_PyTorch/contrib/cv/detection/DSFD/requirements.txt +++ b/ACL_PyTorch/contrib/cv/detection/DSFD/requirements.txt @@ -1,9 +1,9 @@ -torch==1.5.0 -torchvision==0.6.0 -pillow -Cython -easydict -scipy==1.7.2 -opencv-python==4.5.3.56 -numpy -tqdm==4.62.2 +torch==1.5.0 +torchvision==0.6.0 +pillow +Cython +easydict +scipy==1.7.2 +opencv-python==4.5.3.56 +numpy +tqdm==4.62.2 diff --git a/ACL_PyTorch/contrib/cv/detection/DSFD/test/dsfd_pth2onnx.py b/ACL_PyTorch/contrib/cv/detection/DSFD/test/dsfd_pth2onnx.py index dbe7e85598..f8deb52e3f 100644 --- a/ACL_PyTorch/contrib/cv/detection/DSFD/test/dsfd_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/detection/DSFD/test/dsfd_pth2onnx.py @@ -1,67 +1,67 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -#coding=utf-8 -#torch.__version >= 1.3.0 -import sys -sys.path.append("..") - -import torch.onnx -from models.factory import build_net -import argparse - - -parser = argparse.ArgumentParser(description="trans pth to onnx usage") -parser.add_argument( '--model_path', type=str, default='../dsfd.pth', help='Default ph model location(default: %(default)s)') -args = parser.parse_args() - - -#Function to Convert to ONNX -def Convert_ONNX(model): - print("enter Convert_ONNX") - - # set the model to inference mode - model.eval() - - # 构建输入信息和输出信息 - input_names = ["image"] - output_names = ["modelOutput1", "modelOutput2", "modelOutput3", "modelOutput4", "modelOutput5", "modelOutput6"] - #dynamic_axes = {'image': {0: '4'}, 'modelOutput': {0: '-1'}} - dynamic_axes = {'image': {0: '4'}, 'modelOutput1': {0: '4'}, 'modelOutput2': {0: '4'}, 'modelOutput3': {0: '4'}, - 'modelOutput4': {0: '4'}, 'modelOutput5': {0: '4'},'modelOutput6': {0: '4'}} - #dynamic_axes = {'image': {0: '4'}, 'modelOutput': {0: '4'}} - dummy_input = torch.randn(4, 3, 224, 224) - - # 开始转换 - torch.onnx.export(model, - dummy_input, - "dsfd.onnx", - input_names=input_names, - dynamic_axes=dynamic_axes, - output_names=output_names, - opset_version=11, - verbose=True) - print("*************Convert to ONNX model file SUCCESS!*************") - - -if __name__ == '__main__': - - model = build_net('train', 2, 'resnet152') - model.load_state_dict(torch.load(args.model_path, map_location=torch.device('cpu'))) - Convert_ONNX(model) - - - - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +#coding=utf-8 +#torch.__version >= 1.3.0 +import sys +sys.path.append("..") + +import torch.onnx +from models.factory import build_net +import argparse + + +parser = argparse.ArgumentParser(description="trans pth to onnx usage") +parser.add_argument( '--model_path', type=str, default='../dsfd.pth', help='Default ph model location(default: %(default)s)') +args = parser.parse_args() + + +#Function to Convert to ONNX +def Convert_ONNX(model): + print("enter Convert_ONNX") + + # set the model to inference mode + model.eval() + + # 构建输入信息和输出信息 + input_names = ["image"] + output_names = ["modelOutput1", "modelOutput2", "modelOutput3", "modelOutput4", "modelOutput5", "modelOutput6"] + #dynamic_axes = {'image': {0: '4'}, 'modelOutput': {0: '-1'}} + dynamic_axes = {'image': {0: '4'}, 'modelOutput1': {0: '4'}, 'modelOutput2': {0: '4'}, 'modelOutput3': {0: '4'}, + 'modelOutput4': {0: '4'}, 'modelOutput5': {0: '4'},'modelOutput6': {0: '4'}} + #dynamic_axes = {'image': {0: '4'}, 'modelOutput': {0: '4'}} + dummy_input = torch.randn(4, 3, 224, 224) + + # 开始转换 + torch.onnx.export(model, + dummy_input, + "dsfd.onnx", + input_names=input_names, + dynamic_axes=dynamic_axes, + output_names=output_names, + opset_version=11, + verbose=True) + print("*************Convert to ONNX model file SUCCESS!*************") + + +if __name__ == '__main__': + + model = build_net('train', 2, 'resnet152') + model.load_state_dict(torch.load(args.model_path, map_location=torch.device('cpu'))) + Convert_ONNX(model) + + + + + diff --git a/ACL_PyTorch/contrib/cv/detection/Deepspeech/README.md b/ACL_PyTorch/contrib/cv/detection/Deepspeech/README.md index 431abb974e..f441c12e87 100644 --- a/ACL_PyTorch/contrib/cv/detection/Deepspeech/README.md +++ b/ACL_PyTorch/contrib/cv/detection/Deepspeech/README.md @@ -1,253 +1,253 @@ -# DeepSpeech模型PyTorch离线推理指导 -- [1 环境说明](#1-环境说明) - - [1.1 环境搭建与使用说明](#11-环境搭建与使用说明) -- [2 推理流程](#2-推理流程) - - [2.1 获取开源PyTorch模型代码与权重文件](#21-获取开源PyTorch模型代码与权重文件) - - [2.2 导出onnx模型](#22-导出onnx模型) - - [2.3 转换为om模型](#23-转换为om模型) - - [2.4 数据集处理](#24-数据集处理) - - [2.5 离线推理](#25-离线推理) -- [3 精度统计](#3-精度统计) - - [3.1 离线推理精度](#31-离线推理精度) - - [3.2 精度对比](#32-精度对比) -- [4 性能对比](#4-性能对比) - - [4.1 npu性能数据](#41-npu性能数据) - - [4.2 gpu性能数据](#42-gpu性能数据) - - [4.3 性能数据对比](#43-性能数据对比) - - - - -## 1 环境说明 - -- **[环境搭建与使用说明](#11-环境搭建与使用说明)** - - -### 1.1 环境搭建与使用说明 - - -深度学习框架与第三方库 - -``` -python3.7.5 - -torch == 1.8.0 -torchaudio == 0.8.0 -torchvision == 0.9.0 -torchelastic == 0.2.2 - -onnx -onnxruntime -onnxoptimizer - -fairscale -flask -google-cloud-storage -hydra-core -jupyter -librosa -matplotlib -numpy -optuna -pytest -python-levenshtein -pytorch-lightning>=1.1 -scipy -sklearn -sox -tqdm -wget -git+https://github.com/romesco/hydra-lightning/#subdirectory=hydra-configs-pytorch-lightning -``` - -其中apex安装使用pip install会报错,应使用下述方式安装: -``` -git clone https://github.com/NVIDIA/apex.git -cd apex -python3 setup.py install --cpp_ext --cuda_ext -``` - -**说明:** -> -> X86架构:pytorch和torchvision可以通过官方下载whl包安装,其他可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和opencv可以通过github下载源码编译安装,其他可以通过pip3.7 install 包名 安装 -> -> 以上为多数网络需要安装的软件与推荐的版本,根据实际情况安装。如果python脚本运行过程中import 模块失败,安装相应模块即可,如果报错是缺少动态库,网上搜索报错信息找到相应安装包,执行apt-get install 包名安装即可 - - - -## 2 推理流程 - -- **[获取开源PyTorch模型代码与权重文件](#21-获取开源PyTorch模型代码与权重文件)** - -- **[导出onnx模型](#22-导出onnx模型)** - -- **[转换为om模型](#23-转换为om模型)** - -- **[数据集处理](#24-数据集处理)** - -- **[离线推理](#25-离线推理)** - - -### 2.1 获取开源PyTorch模型代码与权重文件 - -#### 2.1.1 基于开源PyTorch框架的Deepspeech开源模型代码 -``` -git clone https://github.com/SeanNaren/deepspeech.pytorch.git -b V3.0 -``` -#### 2.1.2 修改deepspeech.pytorch/deepspeech_pytorch/model.py - -#### 2.1.3 [下载ckpt权重文件](https://github.com/SeanNaren/deepspeech.pytorch/releases/download/V3.0/an4_pretrained_v3.ckpt) -``` -wget https://github.com/SeanNaren/deepspeech.pytorch/releases/download/V3.0/an4_pretrained_v3.ckpt -``` - - -### 2.2 导出onnx模型 - -#### 2.2.1 配置环境变量 - - 将env.sh文件放到根目录下 - - source环境变量 -``` -source env.sh -``` -#### 2.2.2 将ckpt2onnx.py放到根目录下 -#### 2.2.3 执行pth2onnx脚本,生成onnx模型文件 -``` -python3 ckpt2onnx.py --ckpt_path ./an4_pretrained_v3.ckpt --out_file deepspeech.onnx -``` -**说明:** -> -> --ckpt_path:ckpt权重文件 -> --out_file:生成的onnx文件名 -> - - -### 2.3 转换为om模型 - -#### 2.3.1 设置环境变量 -``` -source env.sh -``` -#### 2.3.2 使用Ascend atc工具将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.1 开发辅助工具指南 (推理) 01 -``` -atc --framework=5 --model=./deepspeech.onnx --input_format=NCHW --input_shape="spect:1,1,161,621;transcript:1" --output=deepspeech_bs1 --log=debug --soc_version=Ascend310 -``` - - -### 2.4 数据集处理 - -#### 2.4.1 获取数据集 -获取AN4数据集 -``` -cd deepspeech.pytorch/data -python3 an4.py -cd ../.. -``` - -#### 2.4.2 数据预处理 - - 将预处理脚本deepspeech_preprocess.py放到根目录下 - - 执行预处理脚本,生成数据集预处理后的bin文件 -``` -python3 deepspeech_preprocess.py --data_file ./deepspeech.pytorch/data/an4_test_manifest.json --save_path ./deepspeech.pytorch/data/an4_dataset/test --label_file ./deepspeech.pytorch/labels.json -``` -**说明:** -> -> --data_file:存放数据路径的json文件 -> --save_path:预处理产生的bin文件存储路径(会在save_path目录下建立两个文件夹spect和sizes分别存放两组输入文件) -> --label_file: labels文件路径 -> - - -### 2.5 离线推理 - -#### 2.5.1 msame工具概述 -输入.om模型和模型所需要的输入bin文件,输出模型的输出数据文件,支持多次推理(指对同一输入数据进行推理)。 -模型必须是通过atc工具转换的om模型,输入bin文件需要符合模型的输入要求(支持模型多输入)。 -**说明:** -> -> benchmark工具暂不支持多输入,因此改用msame -> -#### 2.5.2 离线推理 - - [获取msame工具](https://gitee.com/ascend/tools/tree/master/msame) - - 执行离线推理 -``` -./msame --model "./deepspeech_bs1.om" --input "./deepspeech.pytorch/data/an4_dataset/test/spect,./deepspeech.pytorch/data/an4_dataset/test/sizes" --output "./deepspeech.pytorch/result" --outfmt TXT - -``` -**说明:** -> -> 将/tools/msame/msame文件复制到根目录下,执行上述命令,或直接在msame文件夹下执行命令,将input、output等路径改为绝对路径 -> 输出保存在--output路径下,会自动生成新文件夹 -> - - - -## 3 精度统计 - -- **[离线推理精度](#31-离线推理精度)** - -- **[精度对比](#32-精度对比)** - - -### 3.1 离线推理精度 - - 将后处理脚本deepspeech_postprocess.py放到根目录下 - - 调用后处理脚本产生推理结果 -``` -python3 deepspeech_postprocess.py --out_path ./deepspeech.pytorch/result --info_path ./deepspeech.pytorch/data/an4_dataset/test --label_file ./deepspeech.pytorch/labels.json -``` -**说明:** -> -> --out_path:离线推理输出的路径,是msame推理后的输出路径 -> --info_path:与执行数据预处理脚本deepspeech_preprocess.py时设置的--save_path一致 -> --label_file: labels文件路径 -> - -### 3.2 精度对比 - -| 模型 | 官网ckpt精度 | 310离线推理精度 | -| :------: | :------: | :------: | -| Deepspeech bs1 | [Average WER 9.573 Average CER 5.515](https://github.com/SeanNaren/deepspeech.pytorch/releases) | Average WER 9.573 Average CER 5.515 | - -**说明:** -> -> 将得到的om离线模型推理精度与该模型github代码仓上公布的精度对比,精度与之一致,故精度达标 -> - - - -## 4 性能对比 - -- **[npu性能数据](#41-npu性能数据)** - -- **[gpu性能数据](#42-gpu性能数据)** - -- **[性能优化](#43-性能优化)** - - -### 4.1 npu性能数据 -由于benchmark工具不支持多输入,改为使用msame进行om的离线推理。msame工具在推理时会输出每条数据运行的时间,计算10条数据运行的时间均值,作为性能的衡量标准。由于msame不支持多batch,因此以bs1的数据为准。 -``` -Run time of each data: 9.09s -performance: 0.11seq/s -``` - -### 4.2 gpu性能数据 -在装有T4卡的服务器上测试gpu性能,在GPU上进行在线推理,取5次运行的平均时长作为性能的衡量标准。 -``` -Run time of each data: 0.28s -performance: 3.44seq/s -``` - -### 4.3 性能优化 -使用性能分析工具profiling,查看了模型中每类算子总体耗时与百分比和模型每个算子的aicore耗时,发现DynamicRNN耗时最多,使用autotune进行性能优化,优化后性能如下: -``` -Run time of each data: 2.03s -performance: 0.49seq/s -``` -在此基础上,对TransData算子进行优化,优化后性能如下: -``` -Run time of each data: 1.41s -performance: 0.71seq/s +# DeepSpeech模型PyTorch离线推理指导 +- [1 环境说明](#1-环境说明) + - [1.1 环境搭建与使用说明](#11-环境搭建与使用说明) +- [2 推理流程](#2-推理流程) + - [2.1 获取开源PyTorch模型代码与权重文件](#21-获取开源PyTorch模型代码与权重文件) + - [2.2 导出onnx模型](#22-导出onnx模型) + - [2.3 转换为om模型](#23-转换为om模型) + - [2.4 数据集处理](#24-数据集处理) + - [2.5 离线推理](#25-离线推理) +- [3 精度统计](#3-精度统计) + - [3.1 离线推理精度](#31-离线推理精度) + - [3.2 精度对比](#32-精度对比) +- [4 性能对比](#4-性能对比) + - [4.1 npu性能数据](#41-npu性能数据) + - [4.2 gpu性能数据](#42-gpu性能数据) + - [4.3 性能数据对比](#43-性能数据对比) + + + + +## 1 环境说明 + +- **[环境搭建与使用说明](#11-环境搭建与使用说明)** + + +### 1.1 环境搭建与使用说明 + + +深度学习框架与第三方库 + +``` +python3.7.5 + +torch == 1.8.0 +torchaudio == 0.8.0 +torchvision == 0.9.0 +torchelastic == 0.2.2 + +onnx +onnxruntime +onnxoptimizer + +fairscale +flask +google-cloud-storage +hydra-core +jupyter +librosa +matplotlib +numpy +optuna +pytest +python-levenshtein +pytorch-lightning>=1.1 +scipy +sklearn +sox +tqdm +wget +git+https://github.com/romesco/hydra-lightning/#subdirectory=hydra-configs-pytorch-lightning +``` + +其中apex安装使用pip install会报错,应使用下述方式安装: +``` +git clone https://github.com/NVIDIA/apex.git +cd apex +python3 setup.py install --cpp_ext --cuda_ext +``` + +**说明:** +> +> X86架构:pytorch和torchvision可以通过官方下载whl包安装,其他可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和opencv可以通过github下载源码编译安装,其他可以通过pip3.7 install 包名 安装 +> +> 以上为多数网络需要安装的软件与推荐的版本,根据实际情况安装。如果python脚本运行过程中import 模块失败,安装相应模块即可,如果报错是缺少动态库,网上搜索报错信息找到相应安装包,执行apt-get install 包名安装即可 + + + +## 2 推理流程 + +- **[获取开源PyTorch模型代码与权重文件](#21-获取开源PyTorch模型代码与权重文件)** + +- **[导出onnx模型](#22-导出onnx模型)** + +- **[转换为om模型](#23-转换为om模型)** + +- **[数据集处理](#24-数据集处理)** + +- **[离线推理](#25-离线推理)** + + +### 2.1 获取开源PyTorch模型代码与权重文件 + +#### 2.1.1 基于开源PyTorch框架的Deepspeech开源模型代码 +``` +git clone https://github.com/SeanNaren/deepspeech.pytorch.git -b V3.0 +``` +#### 2.1.2 修改deepspeech.pytorch/deepspeech_pytorch/model.py + +#### 2.1.3 [下载ckpt权重文件](https://github.com/SeanNaren/deepspeech.pytorch/releases/download/V3.0/an4_pretrained_v3.ckpt) +``` +wget https://github.com/SeanNaren/deepspeech.pytorch/releases/download/V3.0/an4_pretrained_v3.ckpt +``` + + +### 2.2 导出onnx模型 + +#### 2.2.1 配置环境变量 + - 将env.sh文件放到根目录下 + - source环境变量 +``` +source env.sh +``` +#### 2.2.2 将ckpt2onnx.py放到根目录下 +#### 2.2.3 执行pth2onnx脚本,生成onnx模型文件 +``` +python3 ckpt2onnx.py --ckpt_path ./an4_pretrained_v3.ckpt --out_file deepspeech.onnx +``` +**说明:** +> +> --ckpt_path:ckpt权重文件 +> --out_file:生成的onnx文件名 +> + + +### 2.3 转换为om模型 + +#### 2.3.1 设置环境变量 +``` +source env.sh +``` +#### 2.3.2 使用Ascend atc工具将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.1 开发辅助工具指南 (推理) 01 +``` +atc --framework=5 --model=./deepspeech.onnx --input_format=NCHW --input_shape="spect:1,1,161,621;transcript:1" --output=deepspeech_bs1 --log=debug --soc_version=Ascend310 +``` + + +### 2.4 数据集处理 + +#### 2.4.1 获取数据集 +获取AN4数据集 +``` +cd deepspeech.pytorch/data +python3 an4.py +cd ../.. +``` + +#### 2.4.2 数据预处理 + - 将预处理脚本deepspeech_preprocess.py放到根目录下 + - 执行预处理脚本,生成数据集预处理后的bin文件 +``` +python3 deepspeech_preprocess.py --data_file ./deepspeech.pytorch/data/an4_test_manifest.json --save_path ./deepspeech.pytorch/data/an4_dataset/test --label_file ./deepspeech.pytorch/labels.json +``` +**说明:** +> +> --data_file:存放数据路径的json文件 +> --save_path:预处理产生的bin文件存储路径(会在save_path目录下建立两个文件夹spect和sizes分别存放两组输入文件) +> --label_file: labels文件路径 +> + + +### 2.5 离线推理 + +#### 2.5.1 msame工具概述 +输入.om模型和模型所需要的输入bin文件,输出模型的输出数据文件,支持多次推理(指对同一输入数据进行推理)。 +模型必须是通过atc工具转换的om模型,输入bin文件需要符合模型的输入要求(支持模型多输入)。 +**说明:** +> +> benchmark工具暂不支持多输入,因此改用msame +> +#### 2.5.2 离线推理 + - [获取msame工具](https://gitee.com/ascend/tools/tree/master/msame) + - 执行离线推理 +``` +./msame --model "./deepspeech_bs1.om" --input "./deepspeech.pytorch/data/an4_dataset/test/spect,./deepspeech.pytorch/data/an4_dataset/test/sizes" --output "./deepspeech.pytorch/result" --outfmt TXT + +``` +**说明:** +> +> 将/tools/msame/msame文件复制到根目录下,执行上述命令,或直接在msame文件夹下执行命令,将input、output等路径改为绝对路径 +> 输出保存在--output路径下,会自动生成新文件夹 +> + + + +## 3 精度统计 + +- **[离线推理精度](#31-离线推理精度)** + +- **[精度对比](#32-精度对比)** + + +### 3.1 离线推理精度 + - 将后处理脚本deepspeech_postprocess.py放到根目录下 + - 调用后处理脚本产生推理结果 +``` +python3 deepspeech_postprocess.py --out_path ./deepspeech.pytorch/result --info_path ./deepspeech.pytorch/data/an4_dataset/test --label_file ./deepspeech.pytorch/labels.json +``` +**说明:** +> +> --out_path:离线推理输出的路径,是msame推理后的输出路径 +> --info_path:与执行数据预处理脚本deepspeech_preprocess.py时设置的--save_path一致 +> --label_file: labels文件路径 +> + +### 3.2 精度对比 + +| 模型 | 官网ckpt精度 | 310离线推理精度 | +| :------: | :------: | :------: | +| Deepspeech bs1 | [Average WER 9.573 Average CER 5.515](https://github.com/SeanNaren/deepspeech.pytorch/releases) | Average WER 9.573 Average CER 5.515 | + +**说明:** +> +> 将得到的om离线模型推理精度与该模型github代码仓上公布的精度对比,精度与之一致,故精度达标 +> + + + +## 4 性能对比 + +- **[npu性能数据](#41-npu性能数据)** + +- **[gpu性能数据](#42-gpu性能数据)** + +- **[性能优化](#43-性能优化)** + + +### 4.1 npu性能数据 +由于benchmark工具不支持多输入,改为使用msame进行om的离线推理。msame工具在推理时会输出每条数据运行的时间,计算10条数据运行的时间均值,作为性能的衡量标准。由于msame不支持多batch,因此以bs1的数据为准。 +``` +Run time of each data: 9.09s +performance: 0.11seq/s +``` + +### 4.2 gpu性能数据 +在装有T4卡的服务器上测试gpu性能,在GPU上进行在线推理,取5次运行的平均时长作为性能的衡量标准。 +``` +Run time of each data: 0.28s +performance: 3.44seq/s +``` + +### 4.3 性能优化 +使用性能分析工具profiling,查看了模型中每类算子总体耗时与百分比和模型每个算子的aicore耗时,发现DynamicRNN耗时最多,使用autotune进行性能优化,优化后性能如下: +``` +Run time of each data: 2.03s +performance: 0.49seq/s +``` +在此基础上,对TransData算子进行优化,优化后性能如下: +``` +Run time of each data: 1.41s +performance: 0.71seq/s ``` \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/Deepspeech/ckpt2onnx.py b/ACL_PyTorch/contrib/cv/detection/Deepspeech/ckpt2onnx.py index c3b8c5ffd4..0348203a8f 100644 --- a/ACL_PyTorch/contrib/cv/detection/Deepspeech/ckpt2onnx.py +++ b/ACL_PyTorch/contrib/cv/detection/Deepspeech/ckpt2onnx.py @@ -1,48 +1,48 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ - - -""" -Export onnx from ckpt -""" -import hydra -import os -import torch -from deepspeech_pytorch.configs.inference_config import EvalConfig -from deepspeech_pytorch.utils import load_model -import argparse - -parser = argparse.ArgumentParser(description='Deepspeech') -parser.add_argument('--ckpt_path', default='./an4_pretrained_v3.ckpt', type=str, help='infer out path') -parser.add_argument('--out_file', default='deepspeech.onnx', type=str, help='infer info path') -args = parser.parse_args() - -if __name__ == '__main__': - device = torch.device("cpu") - # device = torch.device("cuda" if EvalConfig.model.cuda else "cpu") - model = load_model(device=device, model_path=args.ckpt_path) - model.eval() - model = model.to(device) - print('Finished loading model!') - # print(model) - input_names = ["spect", "transcript"] - output_names = ["out"] - dynamic_axes = {'spect': {0: '-1'}} - dummy_input = torch.randn(1, 1, 161, 621).to(device) - dummy_input2 = torch.tensor([621], dtype=torch.int32).to(device) - output_file = args.out_file - torch.onnx.export(model, [dummy_input, dummy_input2], output_file, - input_names=input_names, dynamic_axes=dynamic_axes, - output_names=output_names, opset_version=11, verbose=True) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ + + +""" +Export onnx from ckpt +""" +import hydra +import os +import torch +from deepspeech_pytorch.configs.inference_config import EvalConfig +from deepspeech_pytorch.utils import load_model +import argparse + +parser = argparse.ArgumentParser(description='Deepspeech') +parser.add_argument('--ckpt_path', default='./an4_pretrained_v3.ckpt', type=str, help='infer out path') +parser.add_argument('--out_file', default='deepspeech.onnx', type=str, help='infer info path') +args = parser.parse_args() + +if __name__ == '__main__': + device = torch.device("cpu") + # device = torch.device("cuda" if EvalConfig.model.cuda else "cpu") + model = load_model(device=device, model_path=args.ckpt_path) + model.eval() + model = model.to(device) + print('Finished loading model!') + # print(model) + input_names = ["spect", "transcript"] + output_names = ["out"] + dynamic_axes = {'spect': {0: '-1'}} + dummy_input = torch.randn(1, 1, 161, 621).to(device) + dummy_input2 = torch.tensor([621], dtype=torch.int32).to(device) + output_file = args.out_file + torch.onnx.export(model, [dummy_input, dummy_input2], output_file, + input_names=input_names, dynamic_axes=dynamic_axes, + output_names=output_names, opset_version=11, verbose=True) diff --git a/ACL_PyTorch/contrib/cv/detection/Deepspeech/deepspeech_postprocess.py b/ACL_PyTorch/contrib/cv/detection/Deepspeech/deepspeech_postprocess.py index 93e0134a31..29fc86d8d3 100644 --- a/ACL_PyTorch/contrib/cv/detection/Deepspeech/deepspeech_postprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/Deepspeech/deepspeech_postprocess.py @@ -1,152 +1,152 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ - - -""" -Post-processing script -""" -import json -import torch -from deepspeech_pytorch.utils import load_decoder -from deepspeech_pytorch.configs.inference_config import EvalConfig -from deepspeech_pytorch.configs.train_config import DeepSpeechConfig -from deepspeech_pytorch.decoder import GreedyDecoder -from deepspeech_pytorch.validation import WordErrorRate, CharErrorRate -from hydra.utils import to_absolute_path - -import argparse -import os -import numpy as np - -parser = argparse.ArgumentParser(description='Deepspeech') -parser.add_argument('--out_path', default='./result', type=str, help='infer out path') -parser.add_argument('--info_path', default='./data/an4_dataset/test', type=str, help='infer info path') -parser.add_argument('--label_file', default='./labels.json') -args = parser.parse_args() - - -def read_dataset(out_path): - """ - Read the output file - """ - out_files = os.listdir(out_path) - # print(out_files) - data_all = [] - for j in range(len(out_files)): - with open(out_path + '/' + 'data' + str(j + 1) + '_output_0.txt', 'r') as file: - data_read = file.read() - data_line = str(data_read).split(' ') - data_line.pop(-1) - data_list = [] - for i in range(311): - data_list.append(list(map(float, data_line[29 * i: 29 * (i + 1)]))) - data_all.append(data_list) - - # float_list = list(map(float, data_all)) - out_dataset = torch.Tensor(data_all) - return out_dataset - - -def read_sizes(info_path): - """ - Read the sizes file - """ - with open(info_path + '/sizes/sizes.txt', 'r') as sizes_file: - sizes_read = sizes_file.read() - sizes_line = str(sizes_read).split(' ') - sizes_line.pop(-1) - sizes_list = list(map(int, sizes_line)) - sizes_list = torch.Tensor(sizes_list).int() - return sizes_list - - -def read_targets(info_path): - """ - Read the targets file - """ - with open(info_path + '/targets.txt', 'r') as targets_file: - targets_read = targets_file.read() - targets_line = str(targets_read).split(' ') - targets_line.pop(-1) - targets_list = list(map(int, targets_line)) - targets_list = torch.Tensor(targets_list).int() - # print(targets_list) - return targets_list - - -def read_target_sizes(info_path): - """ - Read the target sizes file - """ - with open(info_path + '/target_sizes.txt', 'r') as target_sizes_file: - target_sizes_read = target_sizes_file.read() - target_sizes_line = str(target_sizes_read).split(' ') - target_sizes_line.pop(-1) - target_sizes_list = list(map(int, target_sizes_line)) - target_sizes_list = torch.Tensor(target_sizes_list).int() - # print(target_sizes_list) - return target_sizes_list - - -if __name__ == '__main__': - out_path_real = args.out_path + '/' + sorted(os.listdir(args.out_path))[-1] - # print(out_path_real) - out_dataset = read_dataset(out_path_real) - out_sizes = read_sizes(args.info_path) - targets = read_targets(args.info_path) - target_sizes = read_target_sizes(args.info_path) - out_sizes = (out_sizes / 2).int() - device = torch.device("cuda" if EvalConfig.model.cuda else "cpu") - with open(to_absolute_path(args.label_file)) as label_file: - labels = json.load(label_file) - - decoder = load_decoder( - labels=labels, - cfg=EvalConfig.lm - ) - - target_decoder = GreedyDecoder( - labels=labels, - blank_index=labels.index('_') - ) - # print("模型输出的数据") - # print(out_dataset) - # o,_ = target_decoder.decode(out_dataset, out_sizes) - # print("结果",o) - wer = WordErrorRate( - decoder=decoder, - target_decoder=target_decoder - ) - cer = CharErrorRate( - decoder=decoder, - target_decoder=target_decoder - ) - wer.update( - preds=out_dataset, - preds_sizes=out_sizes, - targets=targets, - target_sizes=target_sizes - ) - cer.update( - preds=out_dataset, - preds_sizes=out_sizes, - targets=targets, - target_sizes=target_sizes - ) - wer = wer.compute() - cer = cer.compute() - print('Test Summary \t' - 'Average WER {wer:.3f}\t' +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ + + +""" +Post-processing script +""" +import json +import torch +from deepspeech_pytorch.utils import load_decoder +from deepspeech_pytorch.configs.inference_config import EvalConfig +from deepspeech_pytorch.configs.train_config import DeepSpeechConfig +from deepspeech_pytorch.decoder import GreedyDecoder +from deepspeech_pytorch.validation import WordErrorRate, CharErrorRate +from hydra.utils import to_absolute_path + +import argparse +import os +import numpy as np + +parser = argparse.ArgumentParser(description='Deepspeech') +parser.add_argument('--out_path', default='./result', type=str, help='infer out path') +parser.add_argument('--info_path', default='./data/an4_dataset/test', type=str, help='infer info path') +parser.add_argument('--label_file', default='./labels.json') +args = parser.parse_args() + + +def read_dataset(out_path): + """ + Read the output file + """ + out_files = os.listdir(out_path) + # print(out_files) + data_all = [] + for j in range(len(out_files)): + with open(out_path + '/' + 'data' + str(j + 1) + '_output_0.txt', 'r') as file: + data_read = file.read() + data_line = str(data_read).split(' ') + data_line.pop(-1) + data_list = [] + for i in range(311): + data_list.append(list(map(float, data_line[29 * i: 29 * (i + 1)]))) + data_all.append(data_list) + + # float_list = list(map(float, data_all)) + out_dataset = torch.Tensor(data_all) + return out_dataset + + +def read_sizes(info_path): + """ + Read the sizes file + """ + with open(info_path + '/sizes/sizes.txt', 'r') as sizes_file: + sizes_read = sizes_file.read() + sizes_line = str(sizes_read).split(' ') + sizes_line.pop(-1) + sizes_list = list(map(int, sizes_line)) + sizes_list = torch.Tensor(sizes_list).int() + return sizes_list + + +def read_targets(info_path): + """ + Read the targets file + """ + with open(info_path + '/targets.txt', 'r') as targets_file: + targets_read = targets_file.read() + targets_line = str(targets_read).split(' ') + targets_line.pop(-1) + targets_list = list(map(int, targets_line)) + targets_list = torch.Tensor(targets_list).int() + # print(targets_list) + return targets_list + + +def read_target_sizes(info_path): + """ + Read the target sizes file + """ + with open(info_path + '/target_sizes.txt', 'r') as target_sizes_file: + target_sizes_read = target_sizes_file.read() + target_sizes_line = str(target_sizes_read).split(' ') + target_sizes_line.pop(-1) + target_sizes_list = list(map(int, target_sizes_line)) + target_sizes_list = torch.Tensor(target_sizes_list).int() + # print(target_sizes_list) + return target_sizes_list + + +if __name__ == '__main__': + out_path_real = args.out_path + '/' + sorted(os.listdir(args.out_path))[-1] + # print(out_path_real) + out_dataset = read_dataset(out_path_real) + out_sizes = read_sizes(args.info_path) + targets = read_targets(args.info_path) + target_sizes = read_target_sizes(args.info_path) + out_sizes = (out_sizes / 2).int() + device = torch.device("cuda" if EvalConfig.model.cuda else "cpu") + with open(to_absolute_path(args.label_file)) as label_file: + labels = json.load(label_file) + + decoder = load_decoder( + labels=labels, + cfg=EvalConfig.lm + ) + + target_decoder = GreedyDecoder( + labels=labels, + blank_index=labels.index('_') + ) + # print("模型输出的数据") + # print(out_dataset) + # o,_ = target_decoder.decode(out_dataset, out_sizes) + # print("结果",o) + wer = WordErrorRate( + decoder=decoder, + target_decoder=target_decoder + ) + cer = CharErrorRate( + decoder=decoder, + target_decoder=target_decoder + ) + wer.update( + preds=out_dataset, + preds_sizes=out_sizes, + targets=targets, + target_sizes=target_sizes + ) + cer.update( + preds=out_dataset, + preds_sizes=out_sizes, + targets=targets, + target_sizes=target_sizes + ) + wer = wer.compute() + cer = cer.compute() + print('Test Summary \t' + 'Average WER {wer:.3f}\t' 'Average CER {cer:.3f}\t'.format(wer=wer, cer=cer)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/Deepspeech/deepspeech_preprocess.py b/ACL_PyTorch/contrib/cv/detection/Deepspeech/deepspeech_preprocess.py index 2d9608dc38..ab3c0e3528 100644 --- a/ACL_PyTorch/contrib/cv/detection/Deepspeech/deepspeech_preprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/Deepspeech/deepspeech_preprocess.py @@ -1,113 +1,113 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ - -""" -Data preprocessing script -""" -import os -import json -import numpy as np -import argparse -import torch -from deepspeech_pytorch.configs.train_config import DataConfig -from deepspeech_pytorch.loader.data_loader import SpectrogramDataset -from hydra.utils import to_absolute_path -from torch.utils.data import DataLoader - -parser = argparse.ArgumentParser(description='Deepspeech') -parser.add_argument('--data_file', default='./data/an4_test_manifest.json') -parser.add_argument('--save_path', default='./data/an4_dataset/test') -parser.add_argument('--label_file', default='./labels.json') -args = parser.parse_args() - -def collate_fn(batch): - """ - data preprocessing - """ - def func(p): - """ - data size - """ - return p[0].size(1) - - batch = sorted(batch, key=lambda sample: sample[0].size(1), reverse=True) - longest_sample = max(batch, key=func)[0] - freq_size = longest_sample.size(0) - minibatch_size = len(batch) - max_seqlength = longest_sample.size(1) - inputs = torch.zeros(minibatch_size, 1, freq_size, max_seqlength) - input_percentages = torch.FloatTensor(minibatch_size) - target_sizes = torch.IntTensor(minibatch_size) - targets = [] - for x in range(minibatch_size): - sample = batch[x] - tensor = sample[0] - target = sample[1] - seq_length = tensor.size(1) - inputs[x][0].narrow(1, 0, seq_length).copy_(tensor) - input_percentages[x] = seq_length / float(max_seqlength) - target_sizes[x] = len(target) - targets.extend(target) - targets = torch.tensor(targets, dtype=torch.long) - return inputs, input_percentages, [targets, target_sizes] - - -if __name__ == '__main__': - with open(to_absolute_path(args.label_file)) as label_file: - labels = json.load(label_file) - # if labels: - # print("labels ready") - - dataset = SpectrogramDataset( - audio_conf=DataConfig.spect, - input_path=args.data_file, - labels=labels, - normalize=True, - aug_cfg=DataConfig.augmentation - ) - inputs, input_percentages, target_list = collate_fn(dataset) - targets = target_list[0] - target_sizes = target_list[1] - input_sizes = input_percentages.mul_(int(inputs.size(3))).int() - - # print(inputs,input_sizes) - if not os.path.exists(args.save_path + '/spect'): os.makedirs(args.save_path + '/spect') - if not os.path.exists(args.save_path + '/sizes'): os.makedirs(args.save_path + '/sizes') - i = 0 - for input_data in inputs: - i = i + 1 - spect = np.array(input_data).astype(np.float32) - spect.tofile(os.path.join(args.save_path + '/spect', "data" + str(i) + ".bin")) - - i = 0 - for input_size in input_sizes: - i = i + 1 - transcript = np.array(input_size).astype(np.int32) - transcript.tofile(os.path.join(args.save_path + '/sizes', "data" + str(i) + ".bin")) - - f = open(args.save_path + '/sizes/' + 'sizes.txt', "w") - for w in np.array(input_sizes).astype(np.int32): - f.write(str(w)+' ') - f.close() - - f = open(args.save_path + '/targets.txt', "w") - for w in np.array(targets): - f.write(str(w) + ' ') - f.close() - - f = open(args.save_path + '/target_sizes.txt', "w") - for w in np.array(target_sizes).astype(np.int32): - f.write(str(w) + ' ') +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ + +""" +Data preprocessing script +""" +import os +import json +import numpy as np +import argparse +import torch +from deepspeech_pytorch.configs.train_config import DataConfig +from deepspeech_pytorch.loader.data_loader import SpectrogramDataset +from hydra.utils import to_absolute_path +from torch.utils.data import DataLoader + +parser = argparse.ArgumentParser(description='Deepspeech') +parser.add_argument('--data_file', default='./data/an4_test_manifest.json') +parser.add_argument('--save_path', default='./data/an4_dataset/test') +parser.add_argument('--label_file', default='./labels.json') +args = parser.parse_args() + +def collate_fn(batch): + """ + data preprocessing + """ + def func(p): + """ + data size + """ + return p[0].size(1) + + batch = sorted(batch, key=lambda sample: sample[0].size(1), reverse=True) + longest_sample = max(batch, key=func)[0] + freq_size = longest_sample.size(0) + minibatch_size = len(batch) + max_seqlength = longest_sample.size(1) + inputs = torch.zeros(minibatch_size, 1, freq_size, max_seqlength) + input_percentages = torch.FloatTensor(minibatch_size) + target_sizes = torch.IntTensor(minibatch_size) + targets = [] + for x in range(minibatch_size): + sample = batch[x] + tensor = sample[0] + target = sample[1] + seq_length = tensor.size(1) + inputs[x][0].narrow(1, 0, seq_length).copy_(tensor) + input_percentages[x] = seq_length / float(max_seqlength) + target_sizes[x] = len(target) + targets.extend(target) + targets = torch.tensor(targets, dtype=torch.long) + return inputs, input_percentages, [targets, target_sizes] + + +if __name__ == '__main__': + with open(to_absolute_path(args.label_file)) as label_file: + labels = json.load(label_file) + # if labels: + # print("labels ready") + + dataset = SpectrogramDataset( + audio_conf=DataConfig.spect, + input_path=args.data_file, + labels=labels, + normalize=True, + aug_cfg=DataConfig.augmentation + ) + inputs, input_percentages, target_list = collate_fn(dataset) + targets = target_list[0] + target_sizes = target_list[1] + input_sizes = input_percentages.mul_(int(inputs.size(3))).int() + + # print(inputs,input_sizes) + if not os.path.exists(args.save_path + '/spect'): os.makedirs(args.save_path + '/spect') + if not os.path.exists(args.save_path + '/sizes'): os.makedirs(args.save_path + '/sizes') + i = 0 + for input_data in inputs: + i = i + 1 + spect = np.array(input_data).astype(np.float32) + spect.tofile(os.path.join(args.save_path + '/spect', "data" + str(i) + ".bin")) + + i = 0 + for input_size in input_sizes: + i = i + 1 + transcript = np.array(input_size).astype(np.int32) + transcript.tofile(os.path.join(args.save_path + '/sizes', "data" + str(i) + ".bin")) + + f = open(args.save_path + '/sizes/' + 'sizes.txt', "w") + for w in np.array(input_sizes).astype(np.int32): + f.write(str(w)+' ') + f.close() + + f = open(args.save_path + '/targets.txt', "w") + for w in np.array(targets): + f.write(str(w) + ' ') + f.close() + + f = open(args.save_path + '/target_sizes.txt', "w") + for w in np.array(target_sizes).astype(np.int32): + f.write(str(w) + ' ') f.close() \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/Deepspeech/test/t4_perf.py b/ACL_PyTorch/contrib/cv/detection/Deepspeech/test/t4_perf.py index 7f0120a740..a150520144 100644 --- a/ACL_PyTorch/contrib/cv/detection/Deepspeech/test/t4_perf.py +++ b/ACL_PyTorch/contrib/cv/detection/Deepspeech/test/t4_perf.py @@ -1,85 +1,85 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 hydra -import os -import torch -from deepspeech_pytorch.configs.inference_config import EvalConfig -from deepspeech_pytorch.utils import load_model - -from deepspeech_pytorch.decoder import GreedyDecoder -from deepspeech_pytorch.utils import load_decoder - -import os -import json -import numpy as np -import argparse - -from deepspeech_pytorch.loader.data_module import DeepSpeechDataModule -from deepspeech_pytorch.configs.train_config import DeepSpeechConfig -from deepspeech_pytorch.loader.data_loader import AudioDataLoader -from hydra.utils import to_absolute_path -import time - -parser = argparse.ArgumentParser(description='Deepspeech') -# The data file to read -parser.add_argument('--data_file', default='./data/an4_test_manifest.json') -# The location the generated 'bin' file to save -parser.add_argument('--save_path', default='./data/an4_dataset/test') -args = parser.parse_args() - - - -if __name__ == '__main__': - - device = torch.device("cuda" if EvalConfig.model.cuda else "cpu") - with open(to_absolute_path(DeepSpeechConfig.data.labels_path)) as label_file: - labels = json.load(label_file) - # if labels: - # print("labels ready") - data_module = DeepSpeechDataModule( - labels=labels, - data_cfg=DeepSpeechConfig.data, - normalize=True, - is_distributed=False # DeepSpeechConfig.trainer.gpus > 1 - ) - dataset = data_module._create_dataset(args.data_file) - - data_loader = AudioDataLoader( - dataset=dataset, - num_workers=data_module.data_cfg.num_workers, - batch_size=data_module.data_cfg.batch_size - ) - - inputs, targets, input_percentages, target_sizes = data_loader.collate_fn(data_loader.dataset) - - input_sizes = input_percentages.mul_(int(inputs.size(3))).int() - inputs = inputs.to(device) - - - - device = torch.device("cuda" if EvalConfig.model.cuda else "cpu") - model = load_model(device=device, model_path='an4_pretrained_v3.ckpt') - model.eval() - model = model.to(device) - print('Finished loading model!') - s_time = time.time() - for i in range(5): - out, output_sizes = model(inputs[:1], input_sizes[:1]) - e_time = time.time() - t = (e_time - s_time)/5 - print('Finished testing data!') - print('Run time of each data: ', t) - print('performance: ', 1/t, 'seq/s') +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 hydra +import os +import torch +from deepspeech_pytorch.configs.inference_config import EvalConfig +from deepspeech_pytorch.utils import load_model + +from deepspeech_pytorch.decoder import GreedyDecoder +from deepspeech_pytorch.utils import load_decoder + +import os +import json +import numpy as np +import argparse + +from deepspeech_pytorch.loader.data_module import DeepSpeechDataModule +from deepspeech_pytorch.configs.train_config import DeepSpeechConfig +from deepspeech_pytorch.loader.data_loader import AudioDataLoader +from hydra.utils import to_absolute_path +import time + +parser = argparse.ArgumentParser(description='Deepspeech') +# The data file to read +parser.add_argument('--data_file', default='./data/an4_test_manifest.json') +# The location the generated 'bin' file to save +parser.add_argument('--save_path', default='./data/an4_dataset/test') +args = parser.parse_args() + + + +if __name__ == '__main__': + + device = torch.device("cuda" if EvalConfig.model.cuda else "cpu") + with open(to_absolute_path(DeepSpeechConfig.data.labels_path)) as label_file: + labels = json.load(label_file) + # if labels: + # print("labels ready") + data_module = DeepSpeechDataModule( + labels=labels, + data_cfg=DeepSpeechConfig.data, + normalize=True, + is_distributed=False # DeepSpeechConfig.trainer.gpus > 1 + ) + dataset = data_module._create_dataset(args.data_file) + + data_loader = AudioDataLoader( + dataset=dataset, + num_workers=data_module.data_cfg.num_workers, + batch_size=data_module.data_cfg.batch_size + ) + + inputs, targets, input_percentages, target_sizes = data_loader.collate_fn(data_loader.dataset) + + input_sizes = input_percentages.mul_(int(inputs.size(3))).int() + inputs = inputs.to(device) + + + + device = torch.device("cuda" if EvalConfig.model.cuda else "cpu") + model = load_model(device=device, model_path='an4_pretrained_v3.ckpt') + model.eval() + model = model.to(device) + print('Finished loading model!') + s_time = time.time() + for i in range(5): + out, output_sizes = model(inputs[:1], input_sizes[:1]) + e_time = time.time() + t = (e_time - s_time)/5 + print('Finished testing data!') + print('Run time of each data: ', t) + print('performance: ', 1/t, 'seq/s') diff --git a/ACL_PyTorch/contrib/cv/detection/Detr/FPS.py b/ACL_PyTorch/contrib/cv/detection/Detr/FPS.py index 72a5ee53fb..3f66e22cab 100644 --- a/ACL_PyTorch/contrib/cv/detection/Detr/FPS.py +++ b/ACL_PyTorch/contrib/cv/detection/Detr/FPS.py @@ -1,33 +1,33 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 numpy as np -import argparse - -parser = argparse.ArgumentParser('Calculation FPS', add_help=False) -parser.add_argument('--log_path', default='bs1_time.log') -parser.add_argument('--batch_size', default=1,type=int) -args = parser.parse_args() - -weight = [0.17, 0.06, 0.53, 0.18, 0.05, 0.009, 0.0014, 0.0006, 0.005] -weight = np.array(weight) -val_times = [] -with open(args.log_path, 'r') as l: - for line in l.readlines(): - if line.startswith('Inference average time without first time: '): - val_time = float(line.split(':')[1].replace('ms', '')) / 1000 - val_times.append(val_time) -val_times = np.array(val_times) -fps = 1 / sum(val_times * weight) * args.batch_size * 4 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 numpy as np +import argparse + +parser = argparse.ArgumentParser('Calculation FPS', add_help=False) +parser.add_argument('--log_path', default='bs1_time.log') +parser.add_argument('--batch_size', default=1,type=int) +args = parser.parse_args() + +weight = [0.17, 0.06, 0.53, 0.18, 0.05, 0.009, 0.0014, 0.0006, 0.005] +weight = np.array(weight) +val_times = [] +with open(args.log_path, 'r') as l: + for line in l.readlines(): + if line.startswith('Inference average time without first time: '): + val_time = float(line.split(':')[1].replace('ms', '')) / 1000 + val_times.append(val_time) +val_times = np.array(val_times) +fps = 1 / sum(val_times * weight) * args.batch_size * 4 print(fps) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/Detr/excute_omval.py b/ACL_PyTorch/contrib/cv/detection/Detr/excute_omval.py index 75a85178b3..75c845b70c 100644 --- a/ACL_PyTorch/contrib/cv/detection/Detr/excute_omval.py +++ b/ACL_PyTorch/contrib/cv/detection/Detr/excute_omval.py @@ -1,60 +1,60 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import argparse - -parser = argparse.ArgumentParser('Set transformer detector', add_help=False) -parser.add_argument('--img_path', default='img_file') -parser.add_argument('--mask_path', default='mask_file') -parser.add_argument('--out_put', default='out_put') -parser.add_argument('--result', default='result') -parser.add_argument('--batch_size', default=1, type=int) -args = parser.parse_args() - -if not os.path.exists(args.out_put): - os.mkdir(args.out_put) -if not os.path.exists(args.result): - os.mkdir(args.result) - -shape_3 = [[768, 1280, 24, 40], [768, 768, 24, 24], [768, 1024, 24, 32]] -shape_6 = [[1024, 768, 32, 24], [1280, 768, 40, 24], [768, 1344, 24, 42], [1344, 768, 42, 24], [1344, 512, 32, 42], - [512, 1344, 16, 42]] -print(args) -if args.batch_size == 1: - for i in shape_3: - command = 'tools/msame/out/msame --model "auto_om/detr_gear_bs1_768.om" --input "{}/{}_{},{}/{}_{}_mask" --output "{}" ' \ - '--dymDims "inputs:1,3,{},{};mask:1,{},{}" --outfmt BIN'. \ - format(args.img_path, i[0], i[1], args.mask_path, i[0], i[1], args.out_put, i[0], i[1], int(i[0] / 32), - int(i[1] / 32)) - print(command) - os.system(command) - for i in shape_6: - command = 'tools/msame/out/msame --model "auto_om/detr_bs1_{}_{}.om" --input "{}/{}_{},{}/{}_{}_mask" --output "{}" --outfmt BIN'.format( - i[0], i[1], args.img_path, i[0], i[1], args.mask_path, i[0], i[1], args.out_put) - print(command) - os.system(command) - mv_command = 'mv {}/*/* {}'.format(args.out_put, args.result) - os.system(mv_command) -elif args.batch_size == 4: - print(4) - for i in shape_3: - command = 'tools/msame/out/msame --model "auto_om/detr_gear_bs4_768.om" --output "{}" --dymDims "inputs:4,3,{},{};mask:4,{},{}" ' \ - '--outfmt BIN --loop 20'.format(args.out_put, i[0], i[1], int(i[0] / 32), int(i[1] / 32)) - print(command) - os.system(command) - for i in shape_6: - command = 'tools/msame/out/msame --model "auto_om/detr_bs4_{}_{}.om" --output "{}" --outfmt BIN --loop 20'. \ - format(i[0], i[1], args.out_put) - print(command) - os.system(command) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import argparse + +parser = argparse.ArgumentParser('Set transformer detector', add_help=False) +parser.add_argument('--img_path', default='img_file') +parser.add_argument('--mask_path', default='mask_file') +parser.add_argument('--out_put', default='out_put') +parser.add_argument('--result', default='result') +parser.add_argument('--batch_size', default=1, type=int) +args = parser.parse_args() + +if not os.path.exists(args.out_put): + os.mkdir(args.out_put) +if not os.path.exists(args.result): + os.mkdir(args.result) + +shape_3 = [[768, 1280, 24, 40], [768, 768, 24, 24], [768, 1024, 24, 32]] +shape_6 = [[1024, 768, 32, 24], [1280, 768, 40, 24], [768, 1344, 24, 42], [1344, 768, 42, 24], [1344, 512, 32, 42], + [512, 1344, 16, 42]] +print(args) +if args.batch_size == 1: + for i in shape_3: + command = 'tools/msame/out/msame --model "auto_om/detr_gear_bs1_768.om" --input "{}/{}_{},{}/{}_{}_mask" --output "{}" ' \ + '--dymDims "inputs:1,3,{},{};mask:1,{},{}" --outfmt BIN'. \ + format(args.img_path, i[0], i[1], args.mask_path, i[0], i[1], args.out_put, i[0], i[1], int(i[0] / 32), + int(i[1] / 32)) + print(command) + os.system(command) + for i in shape_6: + command = 'tools/msame/out/msame --model "auto_om/detr_bs1_{}_{}.om" --input "{}/{}_{},{}/{}_{}_mask" --output "{}" --outfmt BIN'.format( + i[0], i[1], args.img_path, i[0], i[1], args.mask_path, i[0], i[1], args.out_put) + print(command) + os.system(command) + mv_command = 'mv {}/*/* {}'.format(args.out_put, args.result) + os.system(mv_command) +elif args.batch_size == 4: + print(4) + for i in shape_3: + command = 'tools/msame/out/msame --model "auto_om/detr_gear_bs4_768.om" --output "{}" --dymDims "inputs:4,3,{},{};mask:4,{},{}" ' \ + '--outfmt BIN --loop 20'.format(args.out_put, i[0], i[1], int(i[0] / 32), int(i[1] / 32)) + print(command) + os.system(command) + for i in shape_6: + command = 'tools/msame/out/msame --model "auto_om/detr_bs4_{}_{}.om" --output "{}" --outfmt BIN --loop 20'. \ + format(i[0], i[1], args.out_put) + print(command) + os.system(command) diff --git a/ACL_PyTorch/contrib/cv/detection/Detr/onnx2om.py b/ACL_PyTorch/contrib/cv/detection/Detr/onnx2om.py index 3bc36c657e..8cd2294743 100644 --- a/ACL_PyTorch/contrib/cv/detection/Detr/onnx2om.py +++ b/ACL_PyTorch/contrib/cv/detection/Detr/onnx2om.py @@ -1,44 +1,44 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import argparse - -parser = argparse.ArgumentParser('Set transformer detector', add_help=False) -parser.add_argument('--batch_size', default=1) -parser.add_argument('--auto_tune', default=False) -args = parser.parse_args() - -input_shape = [['768,1280,24,40;768,768,24,24;768,1024,24,32'], [1024, 768, 32, 24], [1280, 768, 40, 24], - [768, 1344, 24, 42], [1344, 768, 42, 24], [1344, 512, 42, 16], [512, 1344, 16, 42]] - -to_om = 'atc --framework=5 --model=model/detr_bs{}.onnx -output=auto_om/detr_bs{}_{}_{} ' \ - '--input_shape="inputs:{},3,{},{};mask:{},{},{}" --input_format=ND --soc_version=Ascend310' -to_dyom = 'atc --framework=5 --model=model/detr_bs{}.onnx -output=auto_om/detr_gear_bs{}_{} ' \ - '--input_shape="inputs:{},3,-1,-1;mask:{},-1,-1" --dynamic_dims="{}" --input_format=ND --soc_version=Ascend310' - -if args.auto_tune == True: - to_om = to_om + ' --auto_tune_mode="RL,GA"' - to_dyom = to_dyom + ' --auto_tune_mode="RL,GA"' - -for i in input_shape: - if len(i) == 4: - command = to_om.format(args.batch_size, args.batch_size, i[0], i[1], args.batch_size, i[0], i[1], - args.batch_size, i[2], i[3]) - print(command) - os.system(command) - else: - command = to_dyom.format(args.batch_size, args.batch_size, - i[0].split(',')[0], args.batch_size, args.batch_size, i[0]) - print(command) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import argparse + +parser = argparse.ArgumentParser('Set transformer detector', add_help=False) +parser.add_argument('--batch_size', default=1) +parser.add_argument('--auto_tune', default=False) +args = parser.parse_args() + +input_shape = [['768,1280,24,40;768,768,24,24;768,1024,24,32'], [1024, 768, 32, 24], [1280, 768, 40, 24], + [768, 1344, 24, 42], [1344, 768, 42, 24], [1344, 512, 42, 16], [512, 1344, 16, 42]] + +to_om = 'atc --framework=5 --model=model/detr_bs{}.onnx -output=auto_om/detr_bs{}_{}_{} ' \ + '--input_shape="inputs:{},3,{},{};mask:{},{},{}" --input_format=ND --soc_version=Ascend310' +to_dyom = 'atc --framework=5 --model=model/detr_bs{}.onnx -output=auto_om/detr_gear_bs{}_{} ' \ + '--input_shape="inputs:{},3,-1,-1;mask:{},-1,-1" --dynamic_dims="{}" --input_format=ND --soc_version=Ascend310' + +if args.auto_tune == True: + to_om = to_om + ' --auto_tune_mode="RL,GA"' + to_dyom = to_dyom + ' --auto_tune_mode="RL,GA"' + +for i in input_shape: + if len(i) == 4: + command = to_om.format(args.batch_size, args.batch_size, i[0], i[1], args.batch_size, i[0], i[1], + args.batch_size, i[2], i[3]) + print(command) + os.system(command) + else: + command = to_dyom.format(args.batch_size, args.batch_size, + i[0].split(',')[0], args.batch_size, args.batch_size, i[0]) + print(command) os.system(command) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/EfficientDetD0/get_info.py b/ACL_PyTorch/contrib/cv/detection/EfficientDetD0/get_info.py index b76d6739bc..d5cab0450c 100644 --- a/ACL_PyTorch/contrib/cv/detection/EfficientDetD0/get_info.py +++ b/ACL_PyTorch/contrib/cv/detection/EfficientDetD0/get_info.py @@ -1,60 +1,60 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/EfficientDetD0/modify_onnx.py b/ACL_PyTorch/contrib/cv/detection/EfficientDetD0/modify_onnx.py index 3e217e6703..0995b070b7 100644 --- a/ACL_PyTorch/contrib/cv/detection/EfficientDetD0/modify_onnx.py +++ b/ACL_PyTorch/contrib/cv/detection/EfficientDetD0/modify_onnx.py @@ -1,35 +1,35 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -sys.path.append(r'onnx_tools/OXInterface') -from OXInterface import OXGraph -import numpy as np -import argparse - -parser = argparse.ArgumentParser(description='pth to onnx') -parser.add_argument('--model', type=str, default='d0_bs8_sim.onnx', metavar='N', - help='onnx model') -parser.add_argument('--node', type=str, default='1532', metavar='N', - help='need to modify pad node number') -parser.add_argument('--out', type=str, default='d0_bs8_modify.onnx', metavar='N', - help='modified onnx') - - -args = parser.parse_args() -oxgraph = OXGraph(args.model) -oxinitializer_node = oxgraph.get_oxinitializer_by_name(args.node) -new_data = np.array(0, dtype=np.float32) -oxinitializer_node.set_data(new_data) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +sys.path.append(r'onnx_tools/OXInterface') +from OXInterface import OXGraph +import numpy as np +import argparse + +parser = argparse.ArgumentParser(description='pth to onnx') +parser.add_argument('--model', type=str, default='d0_bs8_sim.onnx', metavar='N', + help='onnx model') +parser.add_argument('--node', type=str, default='1532', metavar='N', + help='need to modify pad node number') +parser.add_argument('--out', type=str, default='d0_bs8_modify.onnx', metavar='N', + help='modified onnx') + + +args = parser.parse_args() +oxgraph = OXGraph(args.model) +oxinitializer_node = oxgraph.get_oxinitializer_by_name(args.node) +new_data = np.array(0, dtype=np.float32) +oxinitializer_node.set_data(new_data) oxgraph.save_new_model(args.out) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/EfficientDetD0/test/pth2om.sh b/ACL_PyTorch/contrib/cv/detection/EfficientDetD0/test/pth2om.sh old mode 100755 new mode 100644 diff --git a/ACL_PyTorch/contrib/cv/detection/EfficientDetD7/get_info.py b/ACL_PyTorch/contrib/cv/detection/EfficientDetD7/get_info.py index b76d6739bc..d5cab0450c 100644 --- a/ACL_PyTorch/contrib/cv/detection/EfficientDetD7/get_info.py +++ b/ACL_PyTorch/contrib/cv/detection/EfficientDetD7/get_info.py @@ -1,60 +1,60 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/EfficientDetD7/modify_onnx.py b/ACL_PyTorch/contrib/cv/detection/EfficientDetD7/modify_onnx.py index 8066bcf7e7..2f6e1e0db6 100644 --- a/ACL_PyTorch/contrib/cv/detection/EfficientDetD7/modify_onnx.py +++ b/ACL_PyTorch/contrib/cv/detection/EfficientDetD7/modify_onnx.py @@ -1,35 +1,35 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -sys.path.append(r'onnx_tools/OXInterface') -from OXInterface import OXGraph -import numpy as np -import argparse - -parser = argparse.ArgumentParser(description='pth to onnx') -parser.add_argument('--model', type=str, default='d7.onnx', metavar='N', - help='onnx model') -parser.add_argument('--node', type=str, default='3080', metavar='N', - help='need to modify pad node number') -parser.add_argument('--out', type=str, default='d7_modify.onnx', metavar='N', - help='modified onnx') - - -args = parser.parse_args() -oxgraph = OXGraph(args.model) -oxinitializer_node = oxgraph.get_oxinitializer_by_name(args.node) -new_data = np.array(0, dtype=np.float32) -oxinitializer_node.set_data(new_data) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +sys.path.append(r'onnx_tools/OXInterface') +from OXInterface import OXGraph +import numpy as np +import argparse + +parser = argparse.ArgumentParser(description='pth to onnx') +parser.add_argument('--model', type=str, default='d7.onnx', metavar='N', + help='onnx model') +parser.add_argument('--node', type=str, default='3080', metavar='N', + help='need to modify pad node number') +parser.add_argument('--out', type=str, default='d7_modify.onnx', metavar='N', + help='modified onnx') + + +args = parser.parse_args() +oxgraph = OXGraph(args.model) +oxinitializer_node = oxgraph.get_oxinitializer_by_name(args.node) +new_data = np.array(0, dtype=np.float32) +oxinitializer_node.set_data(new_data) oxgraph.save_new_model(args.out) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/FOTS/FOTS_pth2onnx_8.py b/ACL_PyTorch/contrib/cv/detection/FOTS/FOTS_pth2onnx_8.py index 6cd3da24ad..c3f7a592ba 100644 --- a/ACL_PyTorch/contrib/cv/detection/FOTS/FOTS_pth2onnx_8.py +++ b/ACL_PyTorch/contrib/cv/detection/FOTS/FOTS_pth2onnx_8.py @@ -1,37 +1,37 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -import torch -import torch.onnx -import torchvision.models as models -from model import FOTSModel - -def pth2onnx(input_file, output_file): - - model = FOTSModel() - checkpoint = torch.load(input_file, map_location='cpu') - model.load_state_dict(checkpoint['model_state_dict']) - - model.eval() - input_names = ["image"] - output_names = ["location"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.randn(8, 3, 1248, 2240) - torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=True, opset_version=11) - -if __name__ == "__main__": - input_file = sys.argv[1] - output_file = sys.argv[2] +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +import torch +import torch.onnx +import torchvision.models as models +from model import FOTSModel + +def pth2onnx(input_file, output_file): + + model = FOTSModel() + checkpoint = torch.load(input_file, map_location='cpu') + model.load_state_dict(checkpoint['model_state_dict']) + + model.eval() + input_names = ["image"] + output_names = ["location"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.randn(8, 3, 1248, 2240) + torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, verbose=True, opset_version=11) + +if __name__ == "__main__": + input_file = sys.argv[1] + output_file = sys.argv[2] pth2onnx(input_file, output_file) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/FOTS/LICENSE b/ACL_PyTorch/contrib/cv/detection/FOTS/LICENSE index 185404d551..5b4cf39445 100644 --- a/ACL_PyTorch/contrib/cv/detection/FOTS/LICENSE +++ b/ACL_PyTorch/contrib/cv/detection/FOTS/LICENSE @@ -1,204 +1,204 @@ -Copyright 2018-2019 Open-MMLab. All rights reserved. -Copyright 2021 Huawei Technologies Co., Ltd - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018-2019 Open-MMLab. - - 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. +Copyright 2018-2019 Open-MMLab. All rights reserved. +Copyright 2021 Huawei Technologies Co., Ltd + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2019 Open-MMLab. + + 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. diff --git a/ACL_PyTorch/contrib/cv/detection/FOTS/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/detection/FOTS/gen_dataset_info.py index 710bbd708c..edb8df558b 100644 --- a/ACL_PyTorch/contrib/cv/detection/FOTS/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/detection/FOTS/gen_dataset_info.py @@ -1,60 +1,60 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/FOTS/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/detection/FOTS/modelzoo_level.txt index 38700fca05..2e42553460 100644 --- a/ACL_PyTorch/contrib/cv/detection/FOTS/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/detection/FOTS/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/FOTS/preprocess.py b/ACL_PyTorch/contrib/cv/detection/FOTS/preprocess.py index 9ca995e153..d6d94222e4 100644 --- a/ACL_PyTorch/contrib/cv/detection/FOTS/preprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/FOTS/preprocess.py @@ -1,44 +1,44 @@ -import argparse -import os - -import cv2 -import numpy as np -import torch - - - -import re -import tqdm - - -def preprocess(images_folder, output_folder): - pbar = tqdm.tqdm(os.listdir(images_folder), desc='Test', ncols=80) - for image_name in pbar: - # prefix = image_name[:image_name.rfind('.')] - image = cv2.imread(os.path.join(images_folder, image_name), cv2.IMREAD_COLOR) - # due to bad net arch sizes have to be mult of 32, so hardcode it - scale_x = 2240 / image.shape[1] # 2240 # 1280 1.75 - scale_y = 1248 / image.shape[0] # 1248 # 720 1.73333 - scaled_image = cv2.resize(image, dsize=(0, 0), fx=scale_x, fy=scale_y, interpolation=cv2.INTER_CUBIC) - # orig_scaled_image = scaled_image.copy() - - scaled_image = scaled_image[:, :, ::-1].astype(np.float32) - scaled_image = (scaled_image / 255 - np.array([0.485, 0.456, 0.406])) / np.array([0.229, 0.224, 0.225]) - image_tensor = torch.from_numpy(np.expand_dims(np.transpose(scaled_image, axes=(2, 0, 1)), axis=0)).float() - - img = np.array(image_tensor).astype(np.float32) - - img.tofile(os.path.join(output_folder, image_name.split('.')[0] + ".bin")) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--images-folder', type=str, required=True, help='path to the folder with test images') - parser.add_argument('--output-folder', type=str, default='fots_test_results', - help='path to the output folder with result labels') - - args = parser.parse_args() - - preprocess(args.images_folder, args.output_folder) - - +import argparse +import os + +import cv2 +import numpy as np +import torch + + + +import re +import tqdm + + +def preprocess(images_folder, output_folder): + pbar = tqdm.tqdm(os.listdir(images_folder), desc='Test', ncols=80) + for image_name in pbar: + # prefix = image_name[:image_name.rfind('.')] + image = cv2.imread(os.path.join(images_folder, image_name), cv2.IMREAD_COLOR) + # due to bad net arch sizes have to be mult of 32, so hardcode it + scale_x = 2240 / image.shape[1] # 2240 # 1280 1.75 + scale_y = 1248 / image.shape[0] # 1248 # 720 1.73333 + scaled_image = cv2.resize(image, dsize=(0, 0), fx=scale_x, fy=scale_y, interpolation=cv2.INTER_CUBIC) + # orig_scaled_image = scaled_image.copy() + + scaled_image = scaled_image[:, :, ::-1].astype(np.float32) + scaled_image = (scaled_image / 255 - np.array([0.485, 0.456, 0.406])) / np.array([0.229, 0.224, 0.225]) + image_tensor = torch.from_numpy(np.expand_dims(np.transpose(scaled_image, axes=(2, 0, 1)), axis=0)).float() + + img = np.array(image_tensor).astype(np.float32) + + img.tofile(os.path.join(output_folder, image_name.split('.')[0] + ".bin")) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--images-folder', type=str, required=True, help='path to the folder with test images') + parser.add_argument('--output-folder', type=str, default='fots_test_results', + help='path to the output folder with result labels') + + args = parser.parse_args() + + preprocess(args.images_folder, args.output_folder) + + diff --git a/ACL_PyTorch/contrib/cv/detection/FOTS/readme.md b/ACL_PyTorch/contrib/cv/detection/FOTS/readme.md index 36cf5bc666..e531e311ac 100644 --- a/ACL_PyTorch/contrib/cv/detection/FOTS/readme.md +++ b/ACL_PyTorch/contrib/cv/detection/FOTS/readme.md @@ -1,142 +1,142 @@ -## FOTS Onnx 模型 PyTorch 离线推理 - -### 1 模型概述 - -- 论文地址 - -``` -https://arxiv.org/abs/1801.01671 -``` - -- 代码地址 - -``` -https://github.com/Wovchena/text-detection-fots.pytorch -``` - -- 数据集 - -``` -下载使用ICDAR2015数据集: -解压后将ch4_test_images文件夹和gt.zip压缩标签文件放到根目录下 -``` - -### 2 环境说明 - -``` -CANN = 5.0.3 -pytorch = 1.5.0 -torchvision = 0.6.0 -onnx = 1.7.0 -numpy = 1.21.2 -shapely = 1.6.4.post2(重要) -polygon3 = 3.0.9.1 -opencv-python = 3.4.10.37(重要) -``` - -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip install 包名 安装 - - - -### 3 pth 转 om 模型 - -- pth 权重文件默认路径为根目录 -- 进入根目录下执行 `./test/pth2onnx.sh` 脚本,自动生成生成 onnx 模型文件 -- (执行./pth2onnx_8.sh脚本,生成batchsize=8的onnx模型文件) - -```py -bash ./test/pth2onnx.sh -``` - -- 执行 `./onnx2om.sh` 脚本,自动生成生成 om 模型文件 -- (执行./onnx2om_8.sh脚本,生成batchsize=8的om模型文件) - -```py -bash ./test/onnx2om.sh -``` - - -### 4 生成输入数据并保存为.bin文件 - -- 数据集默认路径为 `./ch4_test_images.zip` , 解压此数据集,在源码根目录下建立空文件夹用来保存预处理后的二进制图片,命名为res - - - -- 使用脚本 `preprocess.sh`和`gen_dataset_info.sh` 获得预处理图片、二进制 bin 文件及其对应的路径信息 - -``` -bash ./test/preprocess.sh -bash ./test/gen_dataset_info.sh -``` - - -### 5 离线推理 - -#### 5.1 benchmark工具概述 - -benchmark工具提供离线推理功能,输入 om 模型和模型所需要的输入 bin 文件,输出模型的输出数据文件。模型必须是通过 atc 工具转换的 om 模型,输入 bin 文件需要符合模型的输入要求。 - - -#### 5.2 离线推理 - -``` -bash ./test/inference.sh -``` -- (执行bash ./test/inference_8.sh脚本生成batchsize=8的二进制推理文件) - - -输出数据默认保存在根目录的 `./result/pref_visionbatchsize_1_device_0.txt` 中,可以看到时延和 FPS。输出图片默认保存在根目录的 `./result/dumpOutput_device0` 下. - - -### 6 精度对比 - -进入根目录下建立空文件夹用来保存后处理的坐标信息,命名为outPost。调用 ` postprocess.py` 来进行后处理,把输出的 bin 文件转换为对应坐标信息的txt文件。 - -``` -python postprocess.py - -``` - - -- (执行 python postprocess_8.py输出batchsize=8推理的后处理文件) - -详细的坐标信息结果在根目录的outPost/目录下,在根目录下建立空文件夹runs。调用 ` script.py` 来进行精度计算,将输出结果与真实标签比对。 - - -``` -zip -jmq runs/u.zip outPost/* && python3 script.py -g=gt.zip -s=runs/u.zip -``` - -### 7 性能对比 - -#### 7.1 NPU 310 性能数据 -``` -(310 bs1) Inference average time: 9.9045 ms -(310 bs1) FPS:39.618 -``` - -根据时延和核心数,计算得到 Batchsize = 1 时单卡吞吐率 39.618 FPS - -``` -(310 bs8) Inference average time: 9.3025 ms -(310 bs8) FPS:37.210 -``` - -根据时延和核心数,计算得到 Batchsize = 8 时单卡吞吐率 37.210 FPS - -#### 7.2 GPU T4 性能数据 - - -根据时延和核心数,计算得到 Batchsize = 1 时单卡吞吐率 44.704 FPS - - -根据时延和核心数,计算得到 Batchsize = 8 时单卡吞吐率 47.271 FPS - -#### 7.3 性能对比 - -| Batch Size | 310 (FPS/Card) | T4 (FPS/Card) | 310/T4 | -| ---------- | -------------- | ------------- | -------- | -| 1 | *39.618* | *44.704* | *88.62%* | -| 8 | *37.210* | *47.271* | *78.71%* | +## FOTS Onnx 模型 PyTorch 离线推理 + +### 1 模型概述 + +- 论文地址 + +``` +https://arxiv.org/abs/1801.01671 +``` + +- 代码地址 + +``` +https://github.com/Wovchena/text-detection-fots.pytorch +``` + +- 数据集 + +``` +下载使用ICDAR2015数据集: +解压后将ch4_test_images文件夹和gt.zip压缩标签文件放到根目录下 +``` + +### 2 环境说明 + +``` +CANN = 5.0.3 +pytorch = 1.5.0 +torchvision = 0.6.0 +onnx = 1.7.0 +numpy = 1.21.2 +shapely = 1.6.4.post2(重要) +polygon3 = 3.0.9.1 +opencv-python = 3.4.10.37(重要) +``` + +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip install 包名 安装 + + + +### 3 pth 转 om 模型 + +- pth 权重文件默认路径为根目录 +- 进入根目录下执行 `./test/pth2onnx.sh` 脚本,自动生成生成 onnx 模型文件 +- (执行./pth2onnx_8.sh脚本,生成batchsize=8的onnx模型文件) + +```py +bash ./test/pth2onnx.sh +``` + +- 执行 `./onnx2om.sh` 脚本,自动生成生成 om 模型文件 +- (执行./onnx2om_8.sh脚本,生成batchsize=8的om模型文件) + +```py +bash ./test/onnx2om.sh +``` + + +### 4 生成输入数据并保存为.bin文件 + +- 数据集默认路径为 `./ch4_test_images.zip` , 解压此数据集,在源码根目录下建立空文件夹用来保存预处理后的二进制图片,命名为res + + + +- 使用脚本 `preprocess.sh`和`gen_dataset_info.sh` 获得预处理图片、二进制 bin 文件及其对应的路径信息 + +``` +bash ./test/preprocess.sh +bash ./test/gen_dataset_info.sh +``` + + +### 5 离线推理 + +#### 5.1 benchmark工具概述 + +benchmark工具提供离线推理功能,输入 om 模型和模型所需要的输入 bin 文件,输出模型的输出数据文件。模型必须是通过 atc 工具转换的 om 模型,输入 bin 文件需要符合模型的输入要求。 + + +#### 5.2 离线推理 + +``` +bash ./test/inference.sh +``` +- (执行bash ./test/inference_8.sh脚本生成batchsize=8的二进制推理文件) + + +输出数据默认保存在根目录的 `./result/pref_visionbatchsize_1_device_0.txt` 中,可以看到时延和 FPS。输出图片默认保存在根目录的 `./result/dumpOutput_device0` 下. + + +### 6 精度对比 + +进入根目录下建立空文件夹用来保存后处理的坐标信息,命名为outPost。调用 ` postprocess.py` 来进行后处理,把输出的 bin 文件转换为对应坐标信息的txt文件。 + +``` +python postprocess.py + +``` + + +- (执行 python postprocess_8.py输出batchsize=8推理的后处理文件) + +详细的坐标信息结果在根目录的outPost/目录下,在根目录下建立空文件夹runs。调用 ` script.py` 来进行精度计算,将输出结果与真实标签比对。 + + +``` +zip -jmq runs/u.zip outPost/* && python3 script.py -g=gt.zip -s=runs/u.zip +``` + +### 7 性能对比 + +#### 7.1 NPU 310 性能数据 +``` +(310 bs1) Inference average time: 9.9045 ms +(310 bs1) FPS:39.618 +``` + +根据时延和核心数,计算得到 Batchsize = 1 时单卡吞吐率 39.618 FPS + +``` +(310 bs8) Inference average time: 9.3025 ms +(310 bs8) FPS:37.210 +``` + +根据时延和核心数,计算得到 Batchsize = 8 时单卡吞吐率 37.210 FPS + +#### 7.2 GPU T4 性能数据 + + +根据时延和核心数,计算得到 Batchsize = 1 时单卡吞吐率 44.704 FPS + + +根据时延和核心数,计算得到 Batchsize = 8 时单卡吞吐率 47.271 FPS + +#### 7.3 性能对比 + +| Batch Size | 310 (FPS/Card) | T4 (FPS/Card) | 310/T4 | +| ---------- | -------------- | ------------- | -------- | +| 1 | *39.618* | *44.704* | *88.62%* | +| 8 | *37.210* | *47.271* | *78.71%* | diff --git a/ACL_PyTorch/contrib/cv/detection/FOTS/requirments.txt b/ACL_PyTorch/contrib/cv/detection/FOTS/requirments.txt index bd61e6482d..f53442ac04 100644 --- a/ACL_PyTorch/contrib/cv/detection/FOTS/requirments.txt +++ b/ACL_PyTorch/contrib/cv/detection/FOTS/requirments.txt @@ -1,12 +1,12 @@ -numpy=1.21.2 -onnx=1.7.0 -opencv-python=3.4.10.37 -opencv-python3=1.0 -Pillow=8.3.2 -Polygon3=3.0.9.1 -Shapely=1.6.4.post2 -torch=1.5.0 -torchvision=0.6.0 - - - +numpy=1.21.2 +onnx=1.7.0 +opencv-python=3.4.10.37 +opencv-python3=1.0 +Pillow=8.3.2 +Polygon3=3.0.9.1 +Shapely=1.6.4.post2 +torch=1.5.0 +torchvision=0.6.0 + + + diff --git a/ACL_PyTorch/contrib/cv/detection/FasterRCNN_FPN_DCN/README.md b/ACL_PyTorch/contrib/cv/detection/FasterRCNN_FPN_DCN/README.md index be4a4f60ef..a47a439a37 100644 --- a/ACL_PyTorch/contrib/cv/detection/FasterRCNN_FPN_DCN/README.md +++ b/ACL_PyTorch/contrib/cv/detection/FasterRCNN_FPN_DCN/README.md @@ -1,79 +1,79 @@ -# FasterRCNN-FPN-DCN模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 - -``` -pip3.7 install -r requirements.txt -``` - 说明:PyTorch选用开源1.8.0版本 -2.获取,修改与安装开源模型代码 - -``` -git clone https://github.com/open-mmlab/mmcv -b master -cd mmcv -git checkout v1.2.7 -MMCV_WITH_OPS=1 pip3.7 install -e . -patch -p1 < ../mmcv.patch -cd .. -git clone https://github.com/open-mmlab/mmdetection -b master -cd mmdetection -git reset --hard a21eb25535f31634cef332b09fc27d28956fb24b -patch -p1 < ../dcn.patch -pip3.7 install -r requirements/build.txt -python3.7 setup.py develop -``` -3.获取权重文件 - -``` -cd mmdetection -mkdir checkpoints -cd checkpoints - -``` - -[faster_rcnn_r50_fpn_dconv_c3-c5_1x_coco_20200130-d68aed1e.pth](参照指导书文档) -4.数据集 - -[测试集]参照指导书文档 -[标签]参照指导书文档 - -5.[获取benchmark工具](参照指导书文档) - 将benchmark.x86_64或benchmark.aarch64放到当前目录 - - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 - -``` -#OM model generation -bash test/pth2onnx.sh -bash test/onnx2om.sh - -#COCO dataset preprocess -python3.7 FasterRCNN+FPN+DCN_preprocess.py --image_folder_path coco/val2017 --bin_folder_path coco2017_bin -python3.7 gen_dataset_info.py bin coco2017_bin coco2017_bin.info 1216 1216 -python3.7 gen_dataset_info.py jpg coco/val2017 coco2017_jpg.info - -#OM model inference -bash test/inf.sh - -#Inference result postprocess -python3.7 FasterRCNN+FPN+DCN_postprocess.py --test_annotation coco2017_jpg.info --bin_data_path result/dumpOutput_device0 - -#COCO eval -python3.7 txt2json.py --npu_txt_path detection-results --json_output_file coco_detection_result -python3.7 coco_eval.py --groud_truth coco/annotations/instances_val2017.json --detection_result coco_detection_result.json - -#FrameRate eval -bash test/framerate.sh -``` - -**评测结果:** - -| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | -| ---- | ------------------------------------------------------------ | --------------- | -------- | ------- | -| faster_rcnn_r50_fpn_dcn | [box AP:41.3%](https://github.com/open-mmlab/mmdetection/tree/master/configs/dcn) | box AP:41.2% | 5.2fps | 2.8fps | - +# FasterRCNN-FPN-DCN模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 + +``` +pip3.7 install -r requirements.txt +``` + 说明:PyTorch选用开源1.8.0版本 +2.获取,修改与安装开源模型代码 + +``` +git clone https://github.com/open-mmlab/mmcv -b master +cd mmcv +git checkout v1.2.7 +MMCV_WITH_OPS=1 pip3.7 install -e . +patch -p1 < ../mmcv.patch +cd .. +git clone https://github.com/open-mmlab/mmdetection -b master +cd mmdetection +git reset --hard a21eb25535f31634cef332b09fc27d28956fb24b +patch -p1 < ../dcn.patch +pip3.7 install -r requirements/build.txt +python3.7 setup.py develop +``` +3.获取权重文件 + +``` +cd mmdetection +mkdir checkpoints +cd checkpoints + +``` + +[faster_rcnn_r50_fpn_dconv_c3-c5_1x_coco_20200130-d68aed1e.pth](参照指导书文档) +4.数据集 + +[测试集]参照指导书文档 +[标签]参照指导书文档 + +5.[获取benchmark工具](参照指导书文档) + 将benchmark.x86_64或benchmark.aarch64放到当前目录 + + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 + +``` +#OM model generation +bash test/pth2onnx.sh +bash test/onnx2om.sh + +#COCO dataset preprocess +python3.7 FasterRCNN+FPN+DCN_preprocess.py --image_folder_path coco/val2017 --bin_folder_path coco2017_bin +python3.7 gen_dataset_info.py bin coco2017_bin coco2017_bin.info 1216 1216 +python3.7 gen_dataset_info.py jpg coco/val2017 coco2017_jpg.info + +#OM model inference +bash test/inf.sh + +#Inference result postprocess +python3.7 FasterRCNN+FPN+DCN_postprocess.py --test_annotation coco2017_jpg.info --bin_data_path result/dumpOutput_device0 + +#COCO eval +python3.7 txt2json.py --npu_txt_path detection-results --json_output_file coco_detection_result +python3.7 coco_eval.py --groud_truth coco/annotations/instances_val2017.json --detection_result coco_detection_result.json + +#FrameRate eval +bash test/framerate.sh +``` + +**评测结果:** + +| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | +| ---- | ------------------------------------------------------------ | --------------- | -------- | ------- | +| faster_rcnn_r50_fpn_dcn | [box AP:41.3%](https://github.com/open-mmlab/mmdetection/tree/master/configs/dcn) | box AP:41.2% | 5.2fps | 2.8fps | + diff --git a/ACL_PyTorch/contrib/cv/detection/Fsaf/Fsaf_preprocess.py b/ACL_PyTorch/contrib/cv/detection/Fsaf/Fsaf_preprocess.py index 8192a5338a..373e2362ac 100644 --- a/ACL_PyTorch/contrib/cv/detection/Fsaf/Fsaf_preprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/Fsaf/Fsaf_preprocess.py @@ -1,73 +1,73 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import argparse -import numpy as np -import cv2 -import mmcv -import torch -import multiprocessing - -def resize(img, size): - old_h = img.shape[0] - old_w = img.shape[1] - scale_ratio = min(size[0] / old_w, size[1] / old_h) - new_w = int(np.floor(old_w * scale_ratio)) - new_h = int(np.floor(old_h * scale_ratio)) - resized_img = mmcv.imresize(img, (new_w, new_h), backend='cv2') - return resized_img - -def gen_input_bin(file_batches, batch): - i = 0 - for file in file_batches[batch]: - i = i + 1 - print("batch", batch, file, "===", i) - - image = mmcv.imread(os.path.join(flags.image_src_path, file), backend='cv2') - image = resize(image, (flags.model_input_width, flags.model_input_height)) - mean = np.array([123.675, 116.28, 103.53], dtype=np.float32) - std = np.array([58.395, 57.12, 57.375], dtype=np.float32) - image = mmcv.imnormalize(image, mean, std, to_rgb=True) - h = image.shape[0] - w = image.shape[1] - pad_left = (flags.model_input_width - w) // 2 - pad_top = (flags.model_input_height - h) // 2 - pad_right = flags.model_input_width - pad_left - w - pad_bottom = flags.model_input_height - pad_top - h - image = mmcv.impad(image, shape=(flags.model_input_height, flags.model_input_width), pad_val=0) - #mmcv.imwrite(image, './paded_jpg/' + file.split('.')[0] + '.jpg') - image = image.transpose(2, 0, 1) - image.tofile(os.path.join(flags.bin_file_path, file.split('.')[0] + ".bin")) - -def preprocess(src_path, save_path): - files = os.listdir(src_path) - file_batches = [files[i:i + 100] for i in range(0, 5000, 100) if files[i:i + 100] != []] - thread_pool = multiprocessing.Pool(len(file_batches)) - for batch in range(len(file_batches)): - thread_pool.apply_async(gen_input_bin, args=(file_batches, batch)) - thread_pool.close() - thread_pool.join() - print("in thread, except will not report! please ensure bin files generated.") - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='preprocess of MaskRCNN PyTorch model') - parser.add_argument("--image_src_path", default="./coco2017/", help='image of dataset') - parser.add_argument("--bin_file_path", default="./coco2017_bin/", help='Preprocessed image buffer') - parser.add_argument("--model_input_height", default=800, type=int, help='input tensor height') - parser.add_argument("--model_input_width", default=1216, type=int, help='input tensor width') - flags = parser.parse_args() - if not os.path.exists(flags.bin_file_path): - os.makedirs(flags.bin_file_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import argparse +import numpy as np +import cv2 +import mmcv +import torch +import multiprocessing + +def resize(img, size): + old_h = img.shape[0] + old_w = img.shape[1] + scale_ratio = min(size[0] / old_w, size[1] / old_h) + new_w = int(np.floor(old_w * scale_ratio)) + new_h = int(np.floor(old_h * scale_ratio)) + resized_img = mmcv.imresize(img, (new_w, new_h), backend='cv2') + return resized_img + +def gen_input_bin(file_batches, batch): + i = 0 + for file in file_batches[batch]: + i = i + 1 + print("batch", batch, file, "===", i) + + image = mmcv.imread(os.path.join(flags.image_src_path, file), backend='cv2') + image = resize(image, (flags.model_input_width, flags.model_input_height)) + mean = np.array([123.675, 116.28, 103.53], dtype=np.float32) + std = np.array([58.395, 57.12, 57.375], dtype=np.float32) + image = mmcv.imnormalize(image, mean, std, to_rgb=True) + h = image.shape[0] + w = image.shape[1] + pad_left = (flags.model_input_width - w) // 2 + pad_top = (flags.model_input_height - h) // 2 + pad_right = flags.model_input_width - pad_left - w + pad_bottom = flags.model_input_height - pad_top - h + image = mmcv.impad(image, shape=(flags.model_input_height, flags.model_input_width), pad_val=0) + #mmcv.imwrite(image, './paded_jpg/' + file.split('.')[0] + '.jpg') + image = image.transpose(2, 0, 1) + image.tofile(os.path.join(flags.bin_file_path, file.split('.')[0] + ".bin")) + +def preprocess(src_path, save_path): + files = os.listdir(src_path) + file_batches = [files[i:i + 100] for i in range(0, 5000, 100) if files[i:i + 100] != []] + thread_pool = multiprocessing.Pool(len(file_batches)) + for batch in range(len(file_batches)): + thread_pool.apply_async(gen_input_bin, args=(file_batches, batch)) + thread_pool.close() + thread_pool.join() + print("in thread, except will not report! please ensure bin files generated.") + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='preprocess of MaskRCNN PyTorch model') + parser.add_argument("--image_src_path", default="./coco2017/", help='image of dataset') + parser.add_argument("--bin_file_path", default="./coco2017_bin/", help='Preprocessed image buffer') + parser.add_argument("--model_input_height", default=800, type=int, help='input tensor height') + parser.add_argument("--model_input_width", default=1216, type=int, help='input tensor width') + flags = parser.parse_args() + if not os.path.exists(flags.bin_file_path): + os.makedirs(flags.bin_file_path) preprocess(flags.image_src_path, flags.bin_file_path) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/Fsaf/README.md b/ACL_PyTorch/contrib/cv/detection/Fsaf/README.md index 5e40863e92..3752277155 100644 --- a/ACL_PyTorch/contrib/cv/detection/Fsaf/README.md +++ b/ACL_PyTorch/contrib/cv/detection/Fsaf/README.md @@ -1,54 +1,54 @@ -# Fsaf模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 - -``` -pip3.7 install -r requirements.txt -``` - 说明:PyTorch选用开源1.8.0版本 -2.获取,修改与安装开源模型代码 - -``` -git clone https://github.com/open-mmlab/mmcv -b master -git reset --hard 04daea425bcb0a104d8b4acbbc16bd31304cf168 -cd mmcv -MMCV_WITH_OPS=1 pip3.7 install -e . -cd .. -git clone https://github.com/open-mmlab/mmdetection -b master -git reset --hard 604bfe9618533949c74002a4e54f972e57ad0a7a -cd mmdetection -patch -p1 < ../fsaf.diff -pip3.7 install -r requirements/build.txt -python3.7 setup.py develop -``` -3.获取权重文件 - -[fsaf_r50_fpn_1x_coco-94ccc51f.pth](https://download.openmmlab.com/mmdetection/v2.0/fsaf/fsaf_r50_fpn_1x_coco/fsaf_r50_fpn_1x_coco-94ccc51f.pth) - -4.数据集 - -[测试集](http://images.cocodataset.org/zips/val2017.zip):coco/val2017/ -[标签](http://images.cocodataset.org/annotations/annotations_trainval2017.zip):coco/annotations/instances_val2017.json - -5.[获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) - 将benchmark.x86_64或benchmark.aarch64放到当前目录 - - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 - -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets -``` - -**评测结果:** - -| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | -| ---- | ------------------------------------------------------------ | --------------- | -------- | ------- | -| Fsaf | [box AP:37.4%](https://github.com/open-mmlab/mmdetection/tree/master/configs/fsaf) | box AP:37.1% | 8.9fps | 40.0fps | -| Fsaf | [box AP:37.4%](https://github.com/open-mmlab/mmdetection/tree/master/configs/fsaf) | box AP:37.1% | 6.9fps | 40.0fps | - +# Fsaf模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 + +``` +pip3.7 install -r requirements.txt +``` + 说明:PyTorch选用开源1.8.0版本 +2.获取,修改与安装开源模型代码 + +``` +git clone https://github.com/open-mmlab/mmcv -b master +git reset --hard 04daea425bcb0a104d8b4acbbc16bd31304cf168 +cd mmcv +MMCV_WITH_OPS=1 pip3.7 install -e . +cd .. +git clone https://github.com/open-mmlab/mmdetection -b master +git reset --hard 604bfe9618533949c74002a4e54f972e57ad0a7a +cd mmdetection +patch -p1 < ../fsaf.diff +pip3.7 install -r requirements/build.txt +python3.7 setup.py develop +``` +3.获取权重文件 + +[fsaf_r50_fpn_1x_coco-94ccc51f.pth](https://download.openmmlab.com/mmdetection/v2.0/fsaf/fsaf_r50_fpn_1x_coco/fsaf_r50_fpn_1x_coco-94ccc51f.pth) + +4.数据集 + +[测试集](http://images.cocodataset.org/zips/val2017.zip):coco/val2017/ +[标签](http://images.cocodataset.org/annotations/annotations_trainval2017.zip):coco/annotations/instances_val2017.json + +5.[获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) + 将benchmark.x86_64或benchmark.aarch64放到当前目录 + + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 + +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets +``` + +**评测结果:** + +| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | +| ---- | ------------------------------------------------------------ | --------------- | -------- | ------- | +| Fsaf | [box AP:37.4%](https://github.com/open-mmlab/mmdetection/tree/master/configs/fsaf) | box AP:37.1% | 8.9fps | 40.0fps | +| Fsaf | [box AP:37.4%](https://github.com/open-mmlab/mmdetection/tree/master/configs/fsaf) | box AP:37.1% | 6.9fps | 40.0fps | + diff --git a/ACL_PyTorch/contrib/cv/detection/GFocalV2/LICENSE b/ACL_PyTorch/contrib/cv/detection/GFocalV2/LICENSE index df2c2f2c3e..c8ec075d5b 100644 --- a/ACL_PyTorch/contrib/cv/detection/GFocalV2/LICENSE +++ b/ACL_PyTorch/contrib/cv/detection/GFocalV2/LICENSE @@ -1,203 +1,203 @@ -Copyright 2018-2019 Open-MMLab. All rights reserved. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018-2019 Open-MMLab. - - 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 +Copyright 2018-2019 Open-MMLab. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2019 Open-MMLab. + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/GFocalV2/README.md b/ACL_PyTorch/contrib/cv/detection/GFocalV2/README.md index 7b2c3f63d1..4c92474202 100644 --- a/ACL_PyTorch/contrib/cv/detection/GFocalV2/README.md +++ b/ACL_PyTorch/contrib/cv/detection/GFocalV2/README.md @@ -1,60 +1,60 @@ -# GFocalV2模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -``` -pip3.7 install -r requirements.txt -``` -说明:PyTorch选用开源1.8.0版本 - - - -2.获取,修改与安装开源模型代码 -安装mmcv -```shell -git clone https://github.com/open-mmlab/mmcv -b v1.2.7 -cd mmcv -MMCV_WITH_OPS=1 pip3.7 install -e . -cd .. -``` -获取GFocalV2代码 -``` -git clone https://github.com/implus/GFocalV2.git -b master -cd GFocalV2 -git reset --hard b7b355631daaf776e097a6e137501aa27ff7e757 -patch -p1 < ../GFocalV2.diff -python3.7 setup.py develop -cd .. -``` - -3.获取权重文件 - -[gfocalv2预训练的pth权重文件](https://drive.google.com/file/d/1wSE9-c7tcQwIDPC6Vm_yfOokdPfmYmy7/view?usp=sharing) - -4.数据集 -[coco2017](https://cocodataset.org/#download),下载其中val2017图片及其标注文件,放入服务器/root/dataset/coco/文件夹,val2017目录存放coco数据集的验证集图片,annotations目录存放coco数据集的instances_val2017.json,文件目录结构如下: -``` -root -├── dataset -│ ├── coco -│ │ ├── annotations -│ │ ├── val2017 -``` - -5.[获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) -将benchmark.x86_64或benchmark.aarch64放到当前目录 - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets -``` - **评测结果:** -| 模型 | 在线推理精度 | 310离线推理精度 | 基准性能 | 310性能 | -| :------: | :------: | :------: | :------: | :------: | -| GFocalV2 bs1 | mAP:41.0% | mAP:40.6% | 7.9fps | 12.071fps | - +# GFocalV2模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +``` +pip3.7 install -r requirements.txt +``` +说明:PyTorch选用开源1.8.0版本 + + + +2.获取,修改与安装开源模型代码 +安装mmcv +```shell +git clone https://github.com/open-mmlab/mmcv -b v1.2.7 +cd mmcv +MMCV_WITH_OPS=1 pip3.7 install -e . +cd .. +``` +获取GFocalV2代码 +``` +git clone https://github.com/implus/GFocalV2.git -b master +cd GFocalV2 +git reset --hard b7b355631daaf776e097a6e137501aa27ff7e757 +patch -p1 < ../GFocalV2.diff +python3.7 setup.py develop +cd .. +``` + +3.获取权重文件 + +[gfocalv2预训练的pth权重文件](https://drive.google.com/file/d/1wSE9-c7tcQwIDPC6Vm_yfOokdPfmYmy7/view?usp=sharing) + +4.数据集 +[coco2017](https://cocodataset.org/#download),下载其中val2017图片及其标注文件,放入服务器/root/dataset/coco/文件夹,val2017目录存放coco数据集的验证集图片,annotations目录存放coco数据集的instances_val2017.json,文件目录结构如下: +``` +root +├── dataset +│ ├── coco +│ │ ├── annotations +│ │ ├── val2017 +``` + +5.[获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) +将benchmark.x86_64或benchmark.aarch64放到当前目录 + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets +``` + **评测结果:** +| 模型 | 在线推理精度 | 310离线推理精度 | 基准性能 | 310性能 | +| :------: | :------: | :------: | :------: | :------: | +| GFocalV2 bs1 | mAP:41.0% | mAP:40.6% | 7.9fps | 12.071fps | + 备注:离线模型不支持多batch。 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/GFocalV2/get_info.py b/ACL_PyTorch/contrib/cv/detection/GFocalV2/get_info.py index b76d6739bc..d5cab0450c 100644 --- a/ACL_PyTorch/contrib/cv/detection/GFocalV2/get_info.py +++ b/ACL_PyTorch/contrib/cv/detection/GFocalV2/get_info.py @@ -1,60 +1,60 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/GFocalV2/gfocal_postprocess.py b/ACL_PyTorch/contrib/cv/detection/GFocalV2/gfocal_postprocess.py index 49b2e77560..6a779abac4 100644 --- a/ACL_PyTorch/contrib/cv/detection/GFocalV2/gfocal_postprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/GFocalV2/gfocal_postprocess.py @@ -1,89 +1,89 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import argparse -import glob -import numpy as np -import cv2 -import torch -from mmdet.core import bbox2result -from mmdet.datasets import CocoDataset - - -def postprocess_bboxes(bboxes, image_size, net_input_width, net_input_height): - org_w = image_size[0] - org_h = image_size[1] - scale = min(net_input_width / org_w, net_input_height / org_h) - bboxes[:, 0] = (bboxes[:, 0]) / scale - bboxes[:, 1] = (bboxes[:, 1]) / scale - bboxes[:, 2] = (bboxes[:, 2]) / scale - bboxes[:, 3] = (bboxes[:, 3]) / scale - return bboxes - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--test_annotation", default="./origin_pictures.info") - parser.add_argument("--bin_data_path", default="./result/dumpOutput_device0") - parser.add_argument("--net_out_num", type=int, default=3) - parser.add_argument("--net_input_width", type=int, default=1216) - parser.add_argument("--net_input_height", type=int, default=800) - parser.add_argument("--annotations_path", default="/root/datasets") - flags = parser.parse_args() - - img_size_dict = dict() - with open(flags.test_annotation)as f: - for line in f.readlines(): - temp = line.split(" ") - img_file_path = temp[1] - img_name = temp[1].split("/")[-1].split(".")[0] - img_width = int(temp[2]) - img_height = int(temp[3]) - img_size_dict[img_name] = (img_width, img_height, img_file_path) - - bin_path = flags.bin_data_path - - coco_dataset = CocoDataset(ann_file='{}/coco/annotations/instances_val2017.json'.format(flags.annotations_path), pipeline=[]) - coco_class_map = {id:name for id, name in enumerate(coco_dataset.CLASSES)} - results = [] - cnt = 0 - for ids in coco_dataset.img_ids: - cnt = cnt + 1 - bin_file = glob.glob(bin_path + '/*0' + str(ids) + '_1.bin')[0] - bin_file = bin_file[bin_file.rfind('/') + 1:] - bin_file = bin_file[:bin_file.rfind('_')] - print(cnt - 1, bin_file) - path_base = os.path.join(bin_path, bin_file) - - res_buff = [] - bbox_results = [] - cls_segms = [] - if os.path.exists(path_base + "_" + "1" + ".bin") and os.path.exists(path_base + "_" + "2" + ".bin"): - bboxes = np.fromfile(path_base + "_" + str(flags.net_out_num - 1) + ".bin", dtype="float32") - bboxes = np.reshape(bboxes, [100, 5]) - bboxes = torch.from_numpy(bboxes) - labels = np.fromfile(path_base + "_" + str(flags.net_out_num - 2) + ".bin", dtype="int64") - labels = np.reshape(labels, [100, 1]) - labels = torch.from_numpy(labels) - - img_shape = (flags.net_input_height, flags.net_input_width) - bboxes = postprocess_bboxes(bboxes, img_size_dict[bin_file], flags.net_input_width, flags.net_input_height) - bbox_results = [bbox2result(bboxes, labels[:, 0], 80)] - else: - print("[ERROR] file not exist", path_base + "_" + str(1) + ".bin",path_base + "_" + str(2) + ".bin") - - result = bbox_results - results.extend(result) - - eval_results = coco_dataset.evaluate(results, metric=['bbox', ], classwise=True) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import argparse +import glob +import numpy as np +import cv2 +import torch +from mmdet.core import bbox2result +from mmdet.datasets import CocoDataset + + +def postprocess_bboxes(bboxes, image_size, net_input_width, net_input_height): + org_w = image_size[0] + org_h = image_size[1] + scale = min(net_input_width / org_w, net_input_height / org_h) + bboxes[:, 0] = (bboxes[:, 0]) / scale + bboxes[:, 1] = (bboxes[:, 1]) / scale + bboxes[:, 2] = (bboxes[:, 2]) / scale + bboxes[:, 3] = (bboxes[:, 3]) / scale + return bboxes + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("--test_annotation", default="./origin_pictures.info") + parser.add_argument("--bin_data_path", default="./result/dumpOutput_device0") + parser.add_argument("--net_out_num", type=int, default=3) + parser.add_argument("--net_input_width", type=int, default=1216) + parser.add_argument("--net_input_height", type=int, default=800) + parser.add_argument("--annotations_path", default="/root/datasets") + flags = parser.parse_args() + + img_size_dict = dict() + with open(flags.test_annotation)as f: + for line in f.readlines(): + temp = line.split(" ") + img_file_path = temp[1] + img_name = temp[1].split("/")[-1].split(".")[0] + img_width = int(temp[2]) + img_height = int(temp[3]) + img_size_dict[img_name] = (img_width, img_height, img_file_path) + + bin_path = flags.bin_data_path + + coco_dataset = CocoDataset(ann_file='{}/coco/annotations/instances_val2017.json'.format(flags.annotations_path), pipeline=[]) + coco_class_map = {id:name for id, name in enumerate(coco_dataset.CLASSES)} + results = [] + cnt = 0 + for ids in coco_dataset.img_ids: + cnt = cnt + 1 + bin_file = glob.glob(bin_path + '/*0' + str(ids) + '_1.bin')[0] + bin_file = bin_file[bin_file.rfind('/') + 1:] + bin_file = bin_file[:bin_file.rfind('_')] + print(cnt - 1, bin_file) + path_base = os.path.join(bin_path, bin_file) + + res_buff = [] + bbox_results = [] + cls_segms = [] + if os.path.exists(path_base + "_" + "1" + ".bin") and os.path.exists(path_base + "_" + "2" + ".bin"): + bboxes = np.fromfile(path_base + "_" + str(flags.net_out_num - 1) + ".bin", dtype="float32") + bboxes = np.reshape(bboxes, [100, 5]) + bboxes = torch.from_numpy(bboxes) + labels = np.fromfile(path_base + "_" + str(flags.net_out_num - 2) + ".bin", dtype="int64") + labels = np.reshape(labels, [100, 1]) + labels = torch.from_numpy(labels) + + img_shape = (flags.net_input_height, flags.net_input_width) + bboxes = postprocess_bboxes(bboxes, img_size_dict[bin_file], flags.net_input_width, flags.net_input_height) + bbox_results = [bbox2result(bboxes, labels[:, 0], 80)] + else: + print("[ERROR] file not exist", path_base + "_" + str(1) + ".bin",path_base + "_" + str(2) + ".bin") + + result = bbox_results + results.extend(result) + + eval_results = coco_dataset.evaluate(results, metric=['bbox', ], classwise=True) diff --git a/ACL_PyTorch/contrib/cv/detection/GFocalV2/gfocal_preprocess.py b/ACL_PyTorch/contrib/cv/detection/GFocalV2/gfocal_preprocess.py index 8192a5338a..373e2362ac 100644 --- a/ACL_PyTorch/contrib/cv/detection/GFocalV2/gfocal_preprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/GFocalV2/gfocal_preprocess.py @@ -1,73 +1,73 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import argparse -import numpy as np -import cv2 -import mmcv -import torch -import multiprocessing - -def resize(img, size): - old_h = img.shape[0] - old_w = img.shape[1] - scale_ratio = min(size[0] / old_w, size[1] / old_h) - new_w = int(np.floor(old_w * scale_ratio)) - new_h = int(np.floor(old_h * scale_ratio)) - resized_img = mmcv.imresize(img, (new_w, new_h), backend='cv2') - return resized_img - -def gen_input_bin(file_batches, batch): - i = 0 - for file in file_batches[batch]: - i = i + 1 - print("batch", batch, file, "===", i) - - image = mmcv.imread(os.path.join(flags.image_src_path, file), backend='cv2') - image = resize(image, (flags.model_input_width, flags.model_input_height)) - mean = np.array([123.675, 116.28, 103.53], dtype=np.float32) - std = np.array([58.395, 57.12, 57.375], dtype=np.float32) - image = mmcv.imnormalize(image, mean, std, to_rgb=True) - h = image.shape[0] - w = image.shape[1] - pad_left = (flags.model_input_width - w) // 2 - pad_top = (flags.model_input_height - h) // 2 - pad_right = flags.model_input_width - pad_left - w - pad_bottom = flags.model_input_height - pad_top - h - image = mmcv.impad(image, shape=(flags.model_input_height, flags.model_input_width), pad_val=0) - #mmcv.imwrite(image, './paded_jpg/' + file.split('.')[0] + '.jpg') - image = image.transpose(2, 0, 1) - image.tofile(os.path.join(flags.bin_file_path, file.split('.')[0] + ".bin")) - -def preprocess(src_path, save_path): - files = os.listdir(src_path) - file_batches = [files[i:i + 100] for i in range(0, 5000, 100) if files[i:i + 100] != []] - thread_pool = multiprocessing.Pool(len(file_batches)) - for batch in range(len(file_batches)): - thread_pool.apply_async(gen_input_bin, args=(file_batches, batch)) - thread_pool.close() - thread_pool.join() - print("in thread, except will not report! please ensure bin files generated.") - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='preprocess of MaskRCNN PyTorch model') - parser.add_argument("--image_src_path", default="./coco2017/", help='image of dataset') - parser.add_argument("--bin_file_path", default="./coco2017_bin/", help='Preprocessed image buffer') - parser.add_argument("--model_input_height", default=800, type=int, help='input tensor height') - parser.add_argument("--model_input_width", default=1216, type=int, help='input tensor width') - flags = parser.parse_args() - if not os.path.exists(flags.bin_file_path): - os.makedirs(flags.bin_file_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import argparse +import numpy as np +import cv2 +import mmcv +import torch +import multiprocessing + +def resize(img, size): + old_h = img.shape[0] + old_w = img.shape[1] + scale_ratio = min(size[0] / old_w, size[1] / old_h) + new_w = int(np.floor(old_w * scale_ratio)) + new_h = int(np.floor(old_h * scale_ratio)) + resized_img = mmcv.imresize(img, (new_w, new_h), backend='cv2') + return resized_img + +def gen_input_bin(file_batches, batch): + i = 0 + for file in file_batches[batch]: + i = i + 1 + print("batch", batch, file, "===", i) + + image = mmcv.imread(os.path.join(flags.image_src_path, file), backend='cv2') + image = resize(image, (flags.model_input_width, flags.model_input_height)) + mean = np.array([123.675, 116.28, 103.53], dtype=np.float32) + std = np.array([58.395, 57.12, 57.375], dtype=np.float32) + image = mmcv.imnormalize(image, mean, std, to_rgb=True) + h = image.shape[0] + w = image.shape[1] + pad_left = (flags.model_input_width - w) // 2 + pad_top = (flags.model_input_height - h) // 2 + pad_right = flags.model_input_width - pad_left - w + pad_bottom = flags.model_input_height - pad_top - h + image = mmcv.impad(image, shape=(flags.model_input_height, flags.model_input_width), pad_val=0) + #mmcv.imwrite(image, './paded_jpg/' + file.split('.')[0] + '.jpg') + image = image.transpose(2, 0, 1) + image.tofile(os.path.join(flags.bin_file_path, file.split('.')[0] + ".bin")) + +def preprocess(src_path, save_path): + files = os.listdir(src_path) + file_batches = [files[i:i + 100] for i in range(0, 5000, 100) if files[i:i + 100] != []] + thread_pool = multiprocessing.Pool(len(file_batches)) + for batch in range(len(file_batches)): + thread_pool.apply_async(gen_input_bin, args=(file_batches, batch)) + thread_pool.close() + thread_pool.join() + print("in thread, except will not report! please ensure bin files generated.") + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='preprocess of MaskRCNN PyTorch model') + parser.add_argument("--image_src_path", default="./coco2017/", help='image of dataset') + parser.add_argument("--bin_file_path", default="./coco2017_bin/", help='Preprocessed image buffer') + parser.add_argument("--model_input_height", default=800, type=int, help='input tensor height') + parser.add_argument("--model_input_width", default=1216, type=int, help='input tensor width') + flags = parser.parse_args() + if not os.path.exists(flags.bin_file_path): + os.makedirs(flags.bin_file_path) preprocess(flags.image_src_path, flags.bin_file_path) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/GFocalV2/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/detection/GFocalV2/modelzoo_level.txt index bdc5dd889d..5a90c7c76e 100644 --- a/ACL_PyTorch/contrib/cv/detection/GFocalV2/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/detection/GFocalV2/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus: PERFECT \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/GFocalV2/requirements.txt b/ACL_PyTorch/contrib/cv/detection/GFocalV2/requirements.txt index 7609cac2ce..689f4900b8 100644 --- a/ACL_PyTorch/contrib/cv/detection/GFocalV2/requirements.txt +++ b/ACL_PyTorch/contrib/cv/detection/GFocalV2/requirements.txt @@ -1,5 +1,5 @@ -torch == 1.8.0 -torchvision == 0.9.0 -onnx == 1.9.0 -numpy == 1.19.4 +torch == 1.8.0 +torchvision == 0.9.0 +onnx == 1.9.0 +numpy == 1.19.4 opencv-python == 4.4.0.46 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/GFocalV2/test/parse.py b/ACL_PyTorch/contrib/cv/detection/GFocalV2/test/parse.py index b9c74f41d7..82af69cd18 100644 --- a/ACL_PyTorch/contrib/cv/detection/GFocalV2/test/parse.py +++ b/ACL_PyTorch/contrib/cv/detection/GFocalV2/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/M2Det/LICENSE b/ACL_PyTorch/contrib/cv/detection/M2Det/LICENSE index 8904c85160..5f7aa69fea 100644 --- a/ACL_PyTorch/contrib/cv/detection/M2Det/LICENSE +++ b/ACL_PyTorch/contrib/cv/detection/M2Det/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/M2Det/M2Det.patch b/ACL_PyTorch/contrib/cv/detection/M2Det/M2Det.patch index c6d220a060..d3562619d8 100644 --- a/ACL_PyTorch/contrib/cv/detection/M2Det/M2Det.patch +++ b/ACL_PyTorch/contrib/cv/detection/M2Det/M2Det.patch @@ -3,14 +3,14 @@ index 01d21b1..df49100 100644 --- a/configs/m2det512_vgg.py +++ b/configs/m2det512_vgg.py @@ -2,7 +2,7 @@ model = dict( - type = 'm2det', - input_size = 512, - init_net = True, -- pretrained = 'weights/vgg16_reducedfc.pth', -+ pretrained = 'M2Det/weights/vgg16_reducedfc.pth', - m2det_config = dict( - backbone = 'vgg16', - net_family = 'vgg', # vgg includes ['vgg16','vgg19'], res includes ['resnetxxx','resnextxxx'] + type = 'm2det', + input_size = 512, + init_net = True, +- pretrained = 'weights/vgg16_reducedfc.pth', ++ pretrained = 'M2Det/weights/vgg16_reducedfc.pth', + m2det_config = dict( + backbone = 'vgg16', + net_family = 'vgg', # vgg includes ['vgg16','vgg19'], res includes ['resnetxxx','resnextxxx'] diff --git a/data/coco.py b/data/coco.py index 3784d65..9d07625 100644 --- a/data/coco.py diff --git a/ACL_PyTorch/contrib/cv/detection/M2Det/M2Det_preprocess.py b/ACL_PyTorch/contrib/cv/detection/M2Det/M2Det_preprocess.py index d0f0834ae6..c887892e25 100644 --- a/ACL_PyTorch/contrib/cv/detection/M2Det/M2Det_preprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/M2Det/M2Det_preprocess.py @@ -1,58 +1,58 @@ -''' -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -sys.path.insert(0, './M2Det') -import warnings -warnings.filterwarnings('ignore') -import torch -import argparse -import numpy as np -from layers.functions import Detect, PriorBox -from data import BaseTransform -from configs.CC import Config -from utils.core import get_dataloader, print_info - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='M2Det Preprocess') - parser.add_argument('-c', '--config', default='../configs/m2det512_vgg.py', type=str) - parser.add_argument('-d', '--dataset', default='COCO', help='VOC or COCO version') - parser.add_argument('--test', action='store_true', help='to submit a test file') - parser.add_argument("--save_folder", default="./pre_dataset") - parser.add_argument('--COCO_imgs', default="~/data/coco/images", help='COCO images root') - parser.add_argument('--COCO_anns', default="~/data/coco/annotations", help='COCO annotations root') - args = parser.parse_args() - - cfg = Config.fromfile(args.config) - if not os.path.exists(args.save_folder): - os.mkdir(args.save_folder) - - _set = 'eval_sets' if not args.test else 'test_sets' - testset = get_dataloader(args, cfg, args.dataset, _set) - - _preprocess = BaseTransform(cfg.model.input_size, cfg.model.rgb_means, (2, 0, 1)) - num_images = len(testset) - print_info('=> Total {} images to test.'.format(num_images), ['yellow', 'bold']) - - for i in range(num_images): - input_image, img_id= testset.pull_image(i) - img_name = img_id.split('/')[-1] - print(img_name, "===", i) - input_tensor = _preprocess(input_image).unsqueeze(0) - img = np.array(input_tensor).astype(np.float32) - img.tofile(os.path.join(args.save_folder, img_name.split('.')[0] + ".bin")) - +''' +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +sys.path.insert(0, './M2Det') +import warnings +warnings.filterwarnings('ignore') +import torch +import argparse +import numpy as np +from layers.functions import Detect, PriorBox +from data import BaseTransform +from configs.CC import Config +from utils.core import get_dataloader, print_info + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='M2Det Preprocess') + parser.add_argument('-c', '--config', default='../configs/m2det512_vgg.py', type=str) + parser.add_argument('-d', '--dataset', default='COCO', help='VOC or COCO version') + parser.add_argument('--test', action='store_true', help='to submit a test file') + parser.add_argument("--save_folder", default="./pre_dataset") + parser.add_argument('--COCO_imgs', default="~/data/coco/images", help='COCO images root') + parser.add_argument('--COCO_anns', default="~/data/coco/annotations", help='COCO annotations root') + args = parser.parse_args() + + cfg = Config.fromfile(args.config) + if not os.path.exists(args.save_folder): + os.mkdir(args.save_folder) + + _set = 'eval_sets' if not args.test else 'test_sets' + testset = get_dataloader(args, cfg, args.dataset, _set) + + _preprocess = BaseTransform(cfg.model.input_size, cfg.model.rgb_means, (2, 0, 1)) + num_images = len(testset) + print_info('=> Total {} images to test.'.format(num_images), ['yellow', 'bold']) + + for i in range(num_images): + input_image, img_id= testset.pull_image(i) + img_name = img_id.split('/')[-1] + print(img_name, "===", i) + input_tensor = _preprocess(input_image).unsqueeze(0) + img = np.array(input_tensor).astype(np.float32) + img.tofile(os.path.join(args.save_folder, img_name.split('.')[0] + ".bin")) + diff --git a/ACL_PyTorch/contrib/cv/detection/M2Det/M2Det_pth2onnx.py b/ACL_PyTorch/contrib/cv/detection/M2Det/M2Det_pth2onnx.py index fb998a894b..b558597d06 100644 --- a/ACL_PyTorch/contrib/cv/detection/M2Det/M2Det_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/detection/M2Det/M2Det_pth2onnx.py @@ -1,88 +1,88 @@ -''' -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -sys.path.insert(0, './M2Det') -import torch -import torch.onnx -from collections import OrderedDict -import argparse -print(sys.path) -from m2det import build_net -import torch.utils.data as data -import torch.backends.cudnn as cudnn -from configs.CC import Config -from utils.core import init_net - - - -parser = argparse.ArgumentParser(description='pth2onnx') -parser.add_argument('-c', '--config', default='M2Det/configs/m2det512_vgg16.py') -parser.add_argument('-d', '--dataset', default='COCO', help='VOC or COCO dataset') -parser.add_argument('--resume_net', default=None, help='resume net for retraining') -parser.add_argument('--resume_epoch', default=0, type=int, help='resume iter for retraining') -parser.add_argument('-pth', '--pth_path', default='weights/m2det512_vgg.pth') -parser.add_argument('-onnx', '--onnx_path', default='m2det512.onnx') -Args = parser.parse_args() - -def proc_nodes_module(checkpoint): - ''' - Args: - checkpoint: Network parameters. - Returns: - Create a new dictionary, remove the unnecessary key value "module" - ''' - new_state_dict = OrderedDict() - for k, v in checkpoint.items(): - if k[0:7] == "module.": - name = k[7:] - else: - name = k[0:] - new_state_dict[name] = v - return new_state_dict - - -def convert(args, cfg): - ''' - Args: - args.pth_path: Weight file path - args.onnx_path: onnx file path - cfg: configs - ''' - print('pth:{}'.format(args.pth_path)) - print('onnx:{}'.format(args.onnx_path)) - net = build_net('test', - size = cfg.model.input_size, # Only 320, 512, 704 and 800 are supported - config = cfg.model.m2det_config) - init_net(net, cfg, args.resume_net) - model = net - - checkpoint = torch.load(args.pth_path, map_location='cpu') - checkpoint = proc_nodes_module(checkpoint) - model.load_state_dict(checkpoint) - - model.eval() - input_names = ["image"] - output_names = ["scores", "boxes"] - #dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dynamic_axes = {'image':{0:'-1'}, 'scores':{0:'-1'}, 'boxes':{0:'-1'}} - dummy_input = torch.randn(1, 3, 512, 512) - torch.onnx.export(model, dummy_input, args.onnx_path, input_names = input_names, - dynamic_axes = dynamic_axes, output_names = output_names, - verbose=True, opset_version=11) - -if __name__ == "__main__": - Cfg = Config.fromfile(Args.config) +''' +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +sys.path.insert(0, './M2Det') +import torch +import torch.onnx +from collections import OrderedDict +import argparse +print(sys.path) +from m2det import build_net +import torch.utils.data as data +import torch.backends.cudnn as cudnn +from configs.CC import Config +from utils.core import init_net + + + +parser = argparse.ArgumentParser(description='pth2onnx') +parser.add_argument('-c', '--config', default='M2Det/configs/m2det512_vgg16.py') +parser.add_argument('-d', '--dataset', default='COCO', help='VOC or COCO dataset') +parser.add_argument('--resume_net', default=None, help='resume net for retraining') +parser.add_argument('--resume_epoch', default=0, type=int, help='resume iter for retraining') +parser.add_argument('-pth', '--pth_path', default='weights/m2det512_vgg.pth') +parser.add_argument('-onnx', '--onnx_path', default='m2det512.onnx') +Args = parser.parse_args() + +def proc_nodes_module(checkpoint): + ''' + Args: + checkpoint: Network parameters. + Returns: + Create a new dictionary, remove the unnecessary key value "module" + ''' + new_state_dict = OrderedDict() + for k, v in checkpoint.items(): + if k[0:7] == "module.": + name = k[7:] + else: + name = k[0:] + new_state_dict[name] = v + return new_state_dict + + +def convert(args, cfg): + ''' + Args: + args.pth_path: Weight file path + args.onnx_path: onnx file path + cfg: configs + ''' + print('pth:{}'.format(args.pth_path)) + print('onnx:{}'.format(args.onnx_path)) + net = build_net('test', + size = cfg.model.input_size, # Only 320, 512, 704 and 800 are supported + config = cfg.model.m2det_config) + init_net(net, cfg, args.resume_net) + model = net + + checkpoint = torch.load(args.pth_path, map_location='cpu') + checkpoint = proc_nodes_module(checkpoint) + model.load_state_dict(checkpoint) + + model.eval() + input_names = ["image"] + output_names = ["scores", "boxes"] + #dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dynamic_axes = {'image':{0:'-1'}, 'scores':{0:'-1'}, 'boxes':{0:'-1'}} + dummy_input = torch.randn(1, 3, 512, 512) + torch.onnx.export(model, dummy_input, args.onnx_path, input_names = input_names, + dynamic_axes = dynamic_axes, output_names = output_names, + verbose=True, opset_version=11) + +if __name__ == "__main__": + Cfg = Config.fromfile(Args.config) convert(Args, Cfg) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/M2Det/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/detection/M2Det/gen_dataset_info.py index 6469c60543..5f38ef84a7 100644 --- a/ACL_PyTorch/contrib/cv/detection/M2Det/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/detection/M2Det/gen_dataset_info.py @@ -1,67 +1,67 @@ -''' -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(fpath, info_n, width, height): - ''' - Describe - ''' - bin_images = glob(os.path.join(fpath, '*.bin')) - with open(info_n, 'w') as f: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - f.write(content) - f.write('\n') - - -def get_jpg_info(fpath, info_n): - ''' - Describe - ''' - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(fpath, '*.' + extension))) - with open(info_n, 'w') as f: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - f.write(content) - f.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - Width = sys.argv[4] - Height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, Width, Height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +''' +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(fpath, info_n, width, height): + ''' + Describe + ''' + bin_images = glob(os.path.join(fpath, '*.bin')) + with open(info_n, 'w') as f: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + f.write(content) + f.write('\n') + + +def get_jpg_info(fpath, info_n): + ''' + Describe + ''' + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(fpath, '*.' + extension))) + with open(info_n, 'w') as f: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + f.write(content) + f.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + Width = sys.argv[4] + Height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, Width, Height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/M2Det/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/detection/M2Det/modelzoo_level.txt index 549f8ae7ed..a8de6fe278 100644 --- a/ACL_PyTorch/contrib/cv/detection/M2Det/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/detection/M2Det/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK -PerfStatus:Perfect +FuncStatus:OK +PrecisionStatus:OK +PerfStatus:Perfect diff --git a/ACL_PyTorch/contrib/cv/detection/M2Det/requirements.txt b/ACL_PyTorch/contrib/cv/detection/M2Det/requirements.txt index 69bd8849d4..af07e2c553 100644 --- a/ACL_PyTorch/contrib/cv/detection/M2Det/requirements.txt +++ b/ACL_PyTorch/contrib/cv/detection/M2Det/requirements.txt @@ -1,16 +1,16 @@ -torch == 1.8.1 -torchvision == 0.9.1 -onnx == 1.7.0 -numpy == 1.18.5 -Cython == 0.29.24 -opencv-python == 4.5.3.56 -setuptools == 41.2.0 -matplotlib == 2.2.5 -absl-py == 0.13.0 -addict == 2.4.0 -alabaster == 0.7.12 -antlr4-python3-runtime == 4.8 -appdirs == 1.4.4 -asn1crypto == 1.4.0 -astroid == 2.7.3 +torch == 1.8.1 +torchvision == 0.9.1 +onnx == 1.7.0 +numpy == 1.18.5 +Cython == 0.29.24 +opencv-python == 4.5.3.56 +setuptools == 41.2.0 +matplotlib == 2.2.5 +absl-py == 0.13.0 +addict == 2.4.0 +alabaster == 0.7.12 +antlr4-python3-runtime == 4.8 +appdirs == 1.4.4 +asn1crypto == 1.4.0 +astroid == 2.7.3 astropy == 4.3.1 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/NAS_FPN/README.md b/ACL_PyTorch/contrib/cv/detection/NAS_FPN/README.md index 461df59cd3..42191f22e8 100644 --- a/ACL_PyTorch/contrib/cv/detection/NAS_FPN/README.md +++ b/ACL_PyTorch/contrib/cv/detection/NAS_FPN/README.md @@ -1,57 +1,57 @@ -# NAS-FPN模型PyTorch离线推理指导 - -## 1 环境准备 - -1. 安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 - - ``` - pip install -r requirements.txt - ``` - -2. 获取,修改与安装开源模型代码 - - ``` - git clone https://github.com/open-mmlab/mmdetection.git - cd mmdetection - git reset a21eb25535f31634cef332b09fc27d28956fb24b --hard - pip install -v -e . - patch -p1 < ../NAS_FPN.patch - cd .. - ``` - - 利用提供的change文件夹中的patch文件,完成补丁操作,命令参考如下示例,请用户根据安装包位置自行修改: - ``` - cd change - patch -p0 /usr/local/python3.7.5/lib/python3.7/site-packages/mmcv/ops/deform_conv.py deform_conv.patch - patch -p0 /usr/local/python3.7.5/lib/python3.7/site-packages/mmcv/ops/merge_cells.py merge_cells.patch - ``` - - -3. 获取权重文件 - - 从[LINK](https://github.com/open-mmlab/mmdetection/tree/master/configs/nas_fpn)下载nas_fpn模型权重文件 - -4. 数据集 - 本模型使用coco2017的验证集验证 - -5. [获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) -将benchmark.x86_64或benchmark.aarch64放到当前目录 - - - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=./ -``` - -**评测结果:** - -| 模型 | 官网pth精度 | 310离线推理精度 | gpu性能 | 310性能 | -| :---------------: | :---------: | :-------------: | :-----: | :------: | -| NASFPN bs1 | map:0.405 | map:0.404 | 12.7 task/s | 24.750fps | - - - +# NAS-FPN模型PyTorch离线推理指导 + +## 1 环境准备 + +1. 安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 + + ``` + pip install -r requirements.txt + ``` + +2. 获取,修改与安装开源模型代码 + + ``` + git clone https://github.com/open-mmlab/mmdetection.git + cd mmdetection + git reset a21eb25535f31634cef332b09fc27d28956fb24b --hard + pip install -v -e . + patch -p1 < ../NAS_FPN.patch + cd .. + ``` + + 利用提供的change文件夹中的patch文件,完成补丁操作,命令参考如下示例,请用户根据安装包位置自行修改: + ``` + cd change + patch -p0 /usr/local/python3.7.5/lib/python3.7/site-packages/mmcv/ops/deform_conv.py deform_conv.patch + patch -p0 /usr/local/python3.7.5/lib/python3.7/site-packages/mmcv/ops/merge_cells.py merge_cells.patch + ``` + + +3. 获取权重文件 + + 从[LINK](https://github.com/open-mmlab/mmdetection/tree/master/configs/nas_fpn)下载nas_fpn模型权重文件 + +4. 数据集 + 本模型使用coco2017的验证集验证 + +5. [获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) +将benchmark.x86_64或benchmark.aarch64放到当前目录 + + + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=./ +``` + +**评测结果:** + +| 模型 | 官网pth精度 | 310离线推理精度 | gpu性能 | 310性能 | +| :---------------: | :---------: | :-------------: | :-----: | :------: | +| NASFPN bs1 | map:0.405 | map:0.404 | 12.7 task/s | 24.750fps | + + + diff --git a/ACL_PyTorch/contrib/cv/detection/NAS_FPN/coco_eval.py b/ACL_PyTorch/contrib/cv/detection/NAS_FPN/coco_eval.py index 00c927f23d..3eb70b7418 100644 --- a/ACL_PyTorch/contrib/cv/detection/NAS_FPN/coco_eval.py +++ b/ACL_PyTorch/contrib/cv/detection/NAS_FPN/coco_eval.py @@ -1,92 +1,92 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import numpy as np -from pycocotools.coco import COCO -from pycocotools.cocoeval import COCOeval - -CLASSES = ('person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', - 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', - 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', - 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', - 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', - 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', - 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', - 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', - 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', - 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', - 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', - 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush') - -def coco_evaluation(annotation_json, result_json): - cocoGt = COCO(annotation_json) - cocoDt = cocoGt.loadRes(result_json) - iou_thrs = np.linspace(.5, 0.95, int(np.round((0.95 - .5) / .05)) + 1, endpoint=True) - iou_type = 'bbox' - - cocoEval = COCOeval(cocoGt, cocoDt, iou_type) - cocoEval.params.catIds = cocoGt.get_cat_ids(cat_names=CLASSES) - cocoEval.params.imgIds = cocoGt.get_img_ids() - cocoEval.params.maxDets = [100, 300, 1000] # proposal number for evaluating recalls/mAPs. - cocoEval.params.iouThrs = iou_thrs - - cocoEval.evaluate() - cocoEval.accumulate() - cocoEval.summarize() - - # mapping of cocoEval.stats - coco_metric_names = { - 'mAP': 0, - 'mAP_50': 1, - 'mAP_75': 2, - 'mAP_s': 3, - 'mAP_m': 4, - 'mAP_l': 5, - 'AR@100': 6, - 'AR@300': 7, - 'AR@1000': 8, - 'AR_s@1000': 9, - 'AR_m@1000': 10, - 'AR_l@1000': 11 - } - - metric_items = ['mAP', 'mAP_50', 'mAP_75', 'mAP_s', 'mAP_m', 'mAP_l'] - eval_results = {} - - for metric_item in metric_items: - key = f'bbox_{metric_item}' - val = float( - f'{cocoEval.stats[coco_metric_names[metric_item]]:.3f}' - ) - eval_results[key] = val - ap = cocoEval.stats[:6] - eval_results['bbox_mAP_copypaste'] = ( - f'{ap[0]:.3f} {ap[1]:.3f} {ap[2]:.3f} {ap[3]:.3f} ' - f'{ap[4]:.3f} {ap[5]:.3f}') - - return eval_results - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--ground_truth", default="instances_val2017.json") - parser.add_argument("--detection_result", default="coco_detection_result.json") - args = parser.parse_args() - result = coco_evaluation(args.ground_truth, args.detection_result) - print(result) - with open('./coco_detection_result.txt', 'w') as f: - for key, value in result.items(): +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import numpy as np +from pycocotools.coco import COCO +from pycocotools.cocoeval import COCOeval + +CLASSES = ('person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', + 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', + 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', + 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', + 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', + 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', + 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', + 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', + 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', + 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', + 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', + 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush') + +def coco_evaluation(annotation_json, result_json): + cocoGt = COCO(annotation_json) + cocoDt = cocoGt.loadRes(result_json) + iou_thrs = np.linspace(.5, 0.95, int(np.round((0.95 - .5) / .05)) + 1, endpoint=True) + iou_type = 'bbox' + + cocoEval = COCOeval(cocoGt, cocoDt, iou_type) + cocoEval.params.catIds = cocoGt.get_cat_ids(cat_names=CLASSES) + cocoEval.params.imgIds = cocoGt.get_img_ids() + cocoEval.params.maxDets = [100, 300, 1000] # proposal number for evaluating recalls/mAPs. + cocoEval.params.iouThrs = iou_thrs + + cocoEval.evaluate() + cocoEval.accumulate() + cocoEval.summarize() + + # mapping of cocoEval.stats + coco_metric_names = { + 'mAP': 0, + 'mAP_50': 1, + 'mAP_75': 2, + 'mAP_s': 3, + 'mAP_m': 4, + 'mAP_l': 5, + 'AR@100': 6, + 'AR@300': 7, + 'AR@1000': 8, + 'AR_s@1000': 9, + 'AR_m@1000': 10, + 'AR_l@1000': 11 + } + + metric_items = ['mAP', 'mAP_50', 'mAP_75', 'mAP_s', 'mAP_m', 'mAP_l'] + eval_results = {} + + for metric_item in metric_items: + key = f'bbox_{metric_item}' + val = float( + f'{cocoEval.stats[coco_metric_names[metric_item]]:.3f}' + ) + eval_results[key] = val + ap = cocoEval.stats[:6] + eval_results['bbox_mAP_copypaste'] = ( + f'{ap[0]:.3f} {ap[1]:.3f} {ap[2]:.3f} {ap[3]:.3f} ' + f'{ap[4]:.3f} {ap[5]:.3f}') + + return eval_results + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("--ground_truth", default="instances_val2017.json") + parser.add_argument("--detection_result", default="coco_detection_result.json") + args = parser.parse_args() + result = coco_evaluation(args.ground_truth, args.detection_result) + print(result) + with open('./coco_detection_result.txt', 'w') as f: + for key, value in result.items(): f.write(key + ': ' + str(value) + '\n') \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/NAS_FPN/get_info.py b/ACL_PyTorch/contrib/cv/detection/NAS_FPN/get_info.py index 8bf8552914..f31faf1bc9 100644 --- a/ACL_PyTorch/contrib/cv/detection/NAS_FPN/get_info.py +++ b/ACL_PyTorch/contrib/cv/detection/NAS_FPN/get_info.py @@ -1,59 +1,59 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/NAS_FPN/mmdetection_coco_postprocess.py b/ACL_PyTorch/contrib/cv/detection/NAS_FPN/mmdetection_coco_postprocess.py index cf9a8024ef..1b64c86366 100644 --- a/ACL_PyTorch/contrib/cv/detection/NAS_FPN/mmdetection_coco_postprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/NAS_FPN/mmdetection_coco_postprocess.py @@ -1,157 +1,157 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import numpy as np -import argparse -import cv2 - -CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', - 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', - 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', - 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', - 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', - 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', - 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', - 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', - 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', - 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', - 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', - 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] - -def coco_postprocess(bbox: np.ndarray, image_size, - net_input_width, net_input_height): - """ - This function is postprocessing for FasterRCNN output. - - Before calling this function, reshape the raw output of FasterRCNN to - following form - numpy.ndarray: - [x, y, width, height, confidence, probability of 80 classes] - shape: (100,) - The postprocessing restore the bounding rectangles of FasterRCNN output - to origin scale and filter with non-maximum suppression. - - :param bbox: a numpy array of the FasterRCNN output - :param image_path: a string of image path - :return: three list for best bound, class and score - """ - w = image_size[0] - h = image_size[1] - scale = min(net_input_width / w, net_input_height / h) - - pad_w = net_input_width - w * scale - pad_h = net_input_height - h * scale - pad_left = pad_w // 2 - pad_top = pad_h // 2 - - # cal predict box on the image src - pbox = bbox - pbox[:, 0] = (bbox[:, 0] - pad_left) / scale - pbox[:, 1] = (bbox[:, 1] - pad_top) / scale - pbox[:, 2] = (bbox[:, 2] - pad_left) / scale - pbox[:, 3] = (bbox[:, 3] - pad_top) / scale - - # make pbboxes value in valid range - pbox[:, 0] = np.maximum(pbox[:, 0], 0) - pbox[:, 1] = np.maximum(pbox[:, 1], 0) - pbox[:, 2] = np.minimum(pbox[:, 2], w) - pbox[:, 3] = np.minimum(pbox[:, 3], h) - return pbox - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--bin_data_path", default="./result/dumpOutput_device0") - parser.add_argument("--test_annotation", default="./coco2017_jpg.info") - parser.add_argument("--det_results_path", default="./detection-results") - parser.add_argument("--img_path", default="./val2017/") - parser.add_argument("--net_out_num", default=2) - parser.add_argument("--net_input_width", default=640) - parser.add_argument("--net_input_height", default=640) - parser.add_argument("--prob_thres", default=0.05) - parser.add_argument("--ifShowDetObj", action="store_true", help="if input the para means True, neither False.") - flags = parser.parse_args() - print(flags.ifShowDetObj, type(flags.ifShowDetObj)) - # generate dict according to annotation file for query resolution - # load width and height of input images - img_size_dict = dict() - with open(flags.test_annotation)as f: - for line in f.readlines(): - temp = line.split(" ") - img_file_path = temp[1] - img_name = temp[1].split("/")[-1].split(".")[0] - img_width = int(temp[2]) - img_height = int(temp[3]) - img_size_dict[img_name] = (img_width, img_height, img_file_path) - - # read bin file for generate predict result - bin_path = flags.bin_data_path - det_results_path = flags.det_results_path - img_path = flags.img_path - os.makedirs(det_results_path, exist_ok=True) - total_img = set([name[:name.rfind('_')] - for name in os.listdir(bin_path) if "bin" in name]) - for bin_file in sorted(total_img): - path_base = os.path.join(bin_path, bin_file) - # load all detected output tensor - res_buff = [] - for num in range(1, flags.net_out_num + 1): - if os.path.exists(path_base + "_" + str(num) + ".bin"): - if num == 1: - buf = np.fromfile(path_base + "_" + str(num) + ".bin", dtype="float32") - buf = np.reshape(buf, [100, 5]) - elif num == 2: - buf = np.fromfile(path_base + "_" + str(num) + ".bin", dtype="int64") - buf = np.reshape(buf, [100, 1]) - res_buff.append(buf) - else: - print("[ERROR] file not exist", path_base + "_" + str(num) + ".bin") - res_tensor = np.concatenate(res_buff, axis=1) - current_img_size = img_size_dict[bin_file] - print("[TEST]---------------------------concat{} imgsize{}".format(len(res_tensor), current_img_size)) - predbox = coco_postprocess(res_tensor, current_img_size, flags.net_input_width, flags.net_input_height) - - if flags.ifShowDetObj == True: - pic = os.path.join(img_path, bin_file +'.jpg') - imgCur = cv2.imread(pic) - - det_results_str = '' - for idx, class_ind in enumerate(predbox[:,5]): - if float(predbox[idx][4]) < float(flags.prob_thres): - continue - # skip negative class index - if class_ind < 0 or class_ind > 80: - continue - - class_name = CLASSES[int(class_ind)] - det_results_str += "{} {} {} {} {} {}\n".format(class_name, str(predbox[idx][4]), predbox[idx][0], - predbox[idx][1], predbox[idx][2], predbox[idx][3]) - if flags.ifShowDetObj == True: - imgCur=cv2.rectangle(imgCur, (int(predbox[idx][0]), int(predbox[idx][1])), - (int(predbox[idx][2]), int(predbox[idx][3])), (0,255,0), 1) - imgCur = cv2.putText(imgCur, class_name+'|'+str(predbox[idx][4]), - (int(predbox[idx][0]), int(predbox[idx][1])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) - # 图像,文字内容, 坐标 ,字体,大小,颜色,字体厚度 - - if flags.ifShowDetObj == True: - print(os.path.join(det_results_path, bin_file +'.jpg')) - cv2.imwrite(os.path.join(det_results_path, bin_file +'.jpg'), imgCur, [int(cv2.IMWRITE_JPEG_QUALITY),70]) - - det_results_file = os.path.join(det_results_path, bin_file + ".txt") - with open(det_results_file, "w") as detf: - detf.write(det_results_str) - print(det_results_str) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import numpy as np +import argparse +import cv2 + +CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', + 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', + 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', + 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', + 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', + 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', + 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', + 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', + 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', + 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', + 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', + 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] + +def coco_postprocess(bbox: np.ndarray, image_size, + net_input_width, net_input_height): + """ + This function is postprocessing for FasterRCNN output. + + Before calling this function, reshape the raw output of FasterRCNN to + following form + numpy.ndarray: + [x, y, width, height, confidence, probability of 80 classes] + shape: (100,) + The postprocessing restore the bounding rectangles of FasterRCNN output + to origin scale and filter with non-maximum suppression. + + :param bbox: a numpy array of the FasterRCNN output + :param image_path: a string of image path + :return: three list for best bound, class and score + """ + w = image_size[0] + h = image_size[1] + scale = min(net_input_width / w, net_input_height / h) + + pad_w = net_input_width - w * scale + pad_h = net_input_height - h * scale + pad_left = pad_w // 2 + pad_top = pad_h // 2 + + # cal predict box on the image src + pbox = bbox + pbox[:, 0] = (bbox[:, 0] - pad_left) / scale + pbox[:, 1] = (bbox[:, 1] - pad_top) / scale + pbox[:, 2] = (bbox[:, 2] - pad_left) / scale + pbox[:, 3] = (bbox[:, 3] - pad_top) / scale + + # make pbboxes value in valid range + pbox[:, 0] = np.maximum(pbox[:, 0], 0) + pbox[:, 1] = np.maximum(pbox[:, 1], 0) + pbox[:, 2] = np.minimum(pbox[:, 2], w) + pbox[:, 3] = np.minimum(pbox[:, 3], h) + return pbox + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("--bin_data_path", default="./result/dumpOutput_device0") + parser.add_argument("--test_annotation", default="./coco2017_jpg.info") + parser.add_argument("--det_results_path", default="./detection-results") + parser.add_argument("--img_path", default="./val2017/") + parser.add_argument("--net_out_num", default=2) + parser.add_argument("--net_input_width", default=640) + parser.add_argument("--net_input_height", default=640) + parser.add_argument("--prob_thres", default=0.05) + parser.add_argument("--ifShowDetObj", action="store_true", help="if input the para means True, neither False.") + flags = parser.parse_args() + print(flags.ifShowDetObj, type(flags.ifShowDetObj)) + # generate dict according to annotation file for query resolution + # load width and height of input images + img_size_dict = dict() + with open(flags.test_annotation)as f: + for line in f.readlines(): + temp = line.split(" ") + img_file_path = temp[1] + img_name = temp[1].split("/")[-1].split(".")[0] + img_width = int(temp[2]) + img_height = int(temp[3]) + img_size_dict[img_name] = (img_width, img_height, img_file_path) + + # read bin file for generate predict result + bin_path = flags.bin_data_path + det_results_path = flags.det_results_path + img_path = flags.img_path + os.makedirs(det_results_path, exist_ok=True) + total_img = set([name[:name.rfind('_')] + for name in os.listdir(bin_path) if "bin" in name]) + for bin_file in sorted(total_img): + path_base = os.path.join(bin_path, bin_file) + # load all detected output tensor + res_buff = [] + for num in range(1, flags.net_out_num + 1): + if os.path.exists(path_base + "_" + str(num) + ".bin"): + if num == 1: + buf = np.fromfile(path_base + "_" + str(num) + ".bin", dtype="float32") + buf = np.reshape(buf, [100, 5]) + elif num == 2: + buf = np.fromfile(path_base + "_" + str(num) + ".bin", dtype="int64") + buf = np.reshape(buf, [100, 1]) + res_buff.append(buf) + else: + print("[ERROR] file not exist", path_base + "_" + str(num) + ".bin") + res_tensor = np.concatenate(res_buff, axis=1) + current_img_size = img_size_dict[bin_file] + print("[TEST]---------------------------concat{} imgsize{}".format(len(res_tensor), current_img_size)) + predbox = coco_postprocess(res_tensor, current_img_size, flags.net_input_width, flags.net_input_height) + + if flags.ifShowDetObj == True: + pic = os.path.join(img_path, bin_file +'.jpg') + imgCur = cv2.imread(pic) + + det_results_str = '' + for idx, class_ind in enumerate(predbox[:,5]): + if float(predbox[idx][4]) < float(flags.prob_thres): + continue + # skip negative class index + if class_ind < 0 or class_ind > 80: + continue + + class_name = CLASSES[int(class_ind)] + det_results_str += "{} {} {} {} {} {}\n".format(class_name, str(predbox[idx][4]), predbox[idx][0], + predbox[idx][1], predbox[idx][2], predbox[idx][3]) + if flags.ifShowDetObj == True: + imgCur=cv2.rectangle(imgCur, (int(predbox[idx][0]), int(predbox[idx][1])), + (int(predbox[idx][2]), int(predbox[idx][3])), (0,255,0), 1) + imgCur = cv2.putText(imgCur, class_name+'|'+str(predbox[idx][4]), + (int(predbox[idx][0]), int(predbox[idx][1])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) + # 图像,文字内容, 坐标 ,字体,大小,颜色,字体厚度 + + if flags.ifShowDetObj == True: + print(os.path.join(det_results_path, bin_file +'.jpg')) + cv2.imwrite(os.path.join(det_results_path, bin_file +'.jpg'), imgCur, [int(cv2.IMWRITE_JPEG_QUALITY),70]) + + det_results_file = os.path.join(det_results_path, bin_file + ".txt") + with open(det_results_file, "w") as detf: + detf.write(det_results_str) + print(det_results_str) diff --git a/ACL_PyTorch/contrib/cv/detection/NAS_FPN/mmdetection_coco_preprocess.py b/ACL_PyTorch/contrib/cv/detection/NAS_FPN/mmdetection_coco_preprocess.py index db194cf1de..d8bd19c453 100644 --- a/ACL_PyTorch/contrib/cv/detection/NAS_FPN/mmdetection_coco_preprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/NAS_FPN/mmdetection_coco_preprocess.py @@ -1,68 +1,68 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 numpy as np -import os -import cv2 -import argparse -import mmcv -import torch - -dataset_config = { - 'resize': (640, 640), - 'mean': [123.675, 116.28, 103.53], - 'std': [58.395, 57.12, 57.375], -} - -tensor_height = 640 -tensor_width = 640 - -def coco_preprocess(input_image, output_bin_path): - #define the output file name - img_name = input_image.split('/')[-1] - bin_name = img_name.split('.')[0] + ".bin" - bin_fl = os.path.join(output_bin_path, bin_name) - - one_img = mmcv.imread(os.path.join(input_image), backend='cv2') - one_img = mmcv.imrescale(one_img, (tensor_height, tensor_width)) - # calculate padding - h = one_img.shape[0] - w = one_img.shape[1] - pad_left = (tensor_width - w) // 2 - pad_top = (tensor_height - h) // 2 - pad_right = tensor_width - pad_left - w - pad_bottom = tensor_height - pad_top - h - - mean = np.array(dataset_config['mean'], dtype=np.float32) - std = np.array(dataset_config['std'], dtype=np.float32) - one_img = mmcv.imnormalize(one_img, mean, std) - one_img = mmcv.impad(one_img, padding=(pad_left, pad_top, pad_right, pad_bottom), pad_val=0) - one_img = one_img.transpose(2, 0, 1) - one_img.tofile(bin_fl) - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='preprocess of NAS-FPN pytorch model') - parser.add_argument("--image_folder_path", default="./coco2017/", help='image of dataset') - parser.add_argument("--bin_folder_path", default="./coco2017_bin/", help='Preprocessed image buffer') - flags = parser.parse_args() - - if not os.path.exists(flags.bin_folder_path): - os.makedirs(flags.bin_folder_path) - images = os.listdir(flags.image_folder_path) - for image_name in images: - if not (image_name.endswith(".jpeg") or image_name.endswith(".JPEG") or image_name.endswith(".jpg")): - continue - print("start to process image {}....".format(image_name)) - path_image = os.path.join(flags.image_folder_path, image_name) - coco_preprocess(path_image, flags.bin_folder_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 numpy as np +import os +import cv2 +import argparse +import mmcv +import torch + +dataset_config = { + 'resize': (640, 640), + 'mean': [123.675, 116.28, 103.53], + 'std': [58.395, 57.12, 57.375], +} + +tensor_height = 640 +tensor_width = 640 + +def coco_preprocess(input_image, output_bin_path): + #define the output file name + img_name = input_image.split('/')[-1] + bin_name = img_name.split('.')[0] + ".bin" + bin_fl = os.path.join(output_bin_path, bin_name) + + one_img = mmcv.imread(os.path.join(input_image), backend='cv2') + one_img = mmcv.imrescale(one_img, (tensor_height, tensor_width)) + # calculate padding + h = one_img.shape[0] + w = one_img.shape[1] + pad_left = (tensor_width - w) // 2 + pad_top = (tensor_height - h) // 2 + pad_right = tensor_width - pad_left - w + pad_bottom = tensor_height - pad_top - h + + mean = np.array(dataset_config['mean'], dtype=np.float32) + std = np.array(dataset_config['std'], dtype=np.float32) + one_img = mmcv.imnormalize(one_img, mean, std) + one_img = mmcv.impad(one_img, padding=(pad_left, pad_top, pad_right, pad_bottom), pad_val=0) + one_img = one_img.transpose(2, 0, 1) + one_img.tofile(bin_fl) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='preprocess of NAS-FPN pytorch model') + parser.add_argument("--image_folder_path", default="./coco2017/", help='image of dataset') + parser.add_argument("--bin_folder_path", default="./coco2017_bin/", help='Preprocessed image buffer') + flags = parser.parse_args() + + if not os.path.exists(flags.bin_folder_path): + os.makedirs(flags.bin_folder_path) + images = os.listdir(flags.image_folder_path) + for image_name in images: + if not (image_name.endswith(".jpeg") or image_name.endswith(".JPEG") or image_name.endswith(".jpg")): + continue + print("start to process image {}....".format(image_name)) + path_image = os.path.join(flags.image_folder_path, image_name) + coco_preprocess(path_image, flags.bin_folder_path) diff --git a/ACL_PyTorch/contrib/cv/detection/NAS_FPN/requirements.txt b/ACL_PyTorch/contrib/cv/detection/NAS_FPN/requirements.txt index a9b2aff748..bbcf70abd1 100644 --- a/ACL_PyTorch/contrib/cv/detection/NAS_FPN/requirements.txt +++ b/ACL_PyTorch/contrib/cv/detection/NAS_FPN/requirements.txt @@ -1,10 +1,10 @@ -torch==1.7.0 -torchvision==0.8.0 -onnx==1.8.0 -numpy==1.20.0 -mmdet==2.8.0 -mmcv-full==1.2.4 -opencv-python==4.4.0.46 -mmpycocotools==12.0.3 -onnxruntime==1.9.0 - +torch==1.7.0 +torchvision==0.8.0 +onnx==1.8.0 +numpy==1.20.0 +mmdet==2.8.0 +mmcv-full==1.2.4 +opencv-python==4.4.0.46 +mmpycocotools==12.0.3 +onnxruntime==1.9.0 + diff --git a/ACL_PyTorch/contrib/cv/detection/NAS_FPN/txt_to_json.py b/ACL_PyTorch/contrib/cv/detection/NAS_FPN/txt_to_json.py index 9736c00881..65c20258fa 100644 --- a/ACL_PyTorch/contrib/cv/detection/NAS_FPN/txt_to_json.py +++ b/ACL_PyTorch/contrib/cv/detection/NAS_FPN/txt_to_json.py @@ -1,114 +1,114 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 glob -import os -import sys -import argparse -import mmcv - -CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', - 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', - 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', - 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', - 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', - 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', - 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', - 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', - 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', - 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', - 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', - 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] - -cat_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, -24, 25, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, -48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 70, -72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90] - -''' - 0,0 ------> x (width) - | - | (Left,Top) - | *_________ - | | | - | | - y |_________| - (height) * - (Right,Bottom) -''' - -def file_lines_to_list(path): - # open txt file lines to a list - with open(path) as f: - content = f.readlines() - # remove whitespace characters like `\n` at the end of each line - content = [x.strip() for x in content] - return content - - -def error(msg): - print(msg) - sys.exit(0) - - -def get_predict_list(file_path, gt_classes): - dr_files_list = glob.glob(file_path + '/*.txt') - dr_files_list.sort() - - bounding_boxes = [] - for txt_file in dr_files_list: - file_id = txt_file.split(".txt", 1)[0] - file_id = os.path.basename(os.path.normpath(file_id)) - lines = file_lines_to_list(txt_file) - for line in lines: - try: - sl = line.split() - if len(sl) > 6: - class_name = sl[0] + ' ' + sl[1] - scores, left, top, right, bottom = sl[2:] - else: - class_name, scores, left, top, right, bottom = sl - if float(scores) < 0.05: - continue - except ValueError: - error_msg = "Error: File " + txt_file + " wrong format.\n" - error_msg += " Expected: \n" - error_msg += " Received: " + line - error(error_msg) - - # bbox = left + " " + top + " " + right + " " + bottom - left = float(left) - right = float(right) - top = float(top) - bottom = float(bottom) - bbox = [left, top, right-left, bottom-top] - bounding_boxes.append({"image_id": int(file_id), "bbox": bbox, - "score": float(scores), "category_id": cat_ids[CLASSES.index(class_name)]}) - # sort detection-results by decreasing scores - # bounding_boxes.sort(key=lambda x: float(x['score']), reverse=True) - return bounding_boxes - - - -if __name__ == '__main__': - parser = argparse.ArgumentParser('mAp calculate') - parser.add_argument('--npu_txt_path', default="detection-results", - help='the path of the predict result') - parser.add_argument("--json_output_file", default="coco_detection_result") - args = parser.parse_args() - - res_bbox = get_predict_list(args.npu_txt_path, CLASSES) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 glob +import os +import sys +import argparse +import mmcv + +CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', + 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', + 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', + 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', + 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', + 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', + 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', + 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', + 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', + 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', + 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', + 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] + +cat_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, +24, 25, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, +48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 70, +72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90] + +''' + 0,0 ------> x (width) + | + | (Left,Top) + | *_________ + | | | + | | + y |_________| + (height) * + (Right,Bottom) +''' + +def file_lines_to_list(path): + # open txt file lines to a list + with open(path) as f: + content = f.readlines() + # remove whitespace characters like `\n` at the end of each line + content = [x.strip() for x in content] + return content + + +def error(msg): + print(msg) + sys.exit(0) + + +def get_predict_list(file_path, gt_classes): + dr_files_list = glob.glob(file_path + '/*.txt') + dr_files_list.sort() + + bounding_boxes = [] + for txt_file in dr_files_list: + file_id = txt_file.split(".txt", 1)[0] + file_id = os.path.basename(os.path.normpath(file_id)) + lines = file_lines_to_list(txt_file) + for line in lines: + try: + sl = line.split() + if len(sl) > 6: + class_name = sl[0] + ' ' + sl[1] + scores, left, top, right, bottom = sl[2:] + else: + class_name, scores, left, top, right, bottom = sl + if float(scores) < 0.05: + continue + except ValueError: + error_msg = "Error: File " + txt_file + " wrong format.\n" + error_msg += " Expected: \n" + error_msg += " Received: " + line + error(error_msg) + + # bbox = left + " " + top + " " + right + " " + bottom + left = float(left) + right = float(right) + top = float(top) + bottom = float(bottom) + bbox = [left, top, right-left, bottom-top] + bounding_boxes.append({"image_id": int(file_id), "bbox": bbox, + "score": float(scores), "category_id": cat_ids[CLASSES.index(class_name)]}) + # sort detection-results by decreasing scores + # bounding_boxes.sort(key=lambda x: float(x['score']), reverse=True) + return bounding_boxes + + + +if __name__ == '__main__': + parser = argparse.ArgumentParser('mAp calculate') + parser.add_argument('--npu_txt_path', default="detection-results", + help='the path of the predict result') + parser.add_argument("--json_output_file", default="coco_detection_result") + args = parser.parse_args() + + res_bbox = get_predict_list(args.npu_txt_path, CLASSES) mmcv.dump(res_bbox, args.json_output_file + '.json') \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/Nasnetlarge/LICENSE b/ACL_PyTorch/contrib/cv/detection/Nasnetlarge/LICENSE index b7a7d6c0e5..4c9ad98068 100644 --- a/ACL_PyTorch/contrib/cv/detection/Nasnetlarge/LICENSE +++ b/ACL_PyTorch/contrib/cv/detection/Nasnetlarge/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/ACL_PyTorch/contrib/cv/detection/OpenPose/OpenPose_postprocess.py b/ACL_PyTorch/contrib/cv/detection/OpenPose/OpenPose_postprocess.py index a58f6c1832..69230982ef 100644 --- a/ACL_PyTorch/contrib/cv/detection/OpenPose/OpenPose_postprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/OpenPose/OpenPose_postprocess.py @@ -1,119 +1,119 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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. -""" -python3.7 OpenPose_postprocess.py ---benchmark_result_path ./result/dumpOutput_device0 ---detections_save_path ./output/result.json ---pad_txt_path ./output/pad.txt ---labels /root/datasets/coco/annotations/person_keypoints_val2017.json -""" -import argparse -import json -import os -import sys -import torch -import cv2 -import numpy as np -sys.path.append("./lightweight-human-pose-estimation.pytorch") -from modules.keypoints import group_keypoints, extract_keypoints -from val import run_coco_eval, convert_to_coco_format - - -def read_txt(txt_path, shape): - with open(txt_path, "r") as f: - line = f.readline() - line_split = line.strip().split(" ") - line_split = [eval(i) for i in line_split] - line_split = torch.Tensor(line_split) - heatmaps = line_split.view(shape) - return heatmaps - - -def transfer(heatmaps, pafs, height, width, top, bottom, left, right, stride=8): - heatmaps = np.transpose(heatmaps.squeeze().cpu().data.numpy(), (1, 2, 0)) - heatmaps = cv2.resize(heatmaps, (0, 0), fx=stride, fy=stride, interpolation=cv2.INTER_CUBIC) - heatmaps = heatmaps[top:heatmaps.shape[0] - bottom, left:heatmaps.shape[1] - right:, :] - heatmaps = cv2.resize(heatmaps, (width, height), interpolation=cv2.INTER_CUBIC) - pafs = np.transpose(pafs.squeeze().cpu().data.numpy(), (1, 2, 0)) - pafs = cv2.resize(pafs, (0, 0), fx=stride, fy=stride, interpolation=cv2.INTER_CUBIC) - pafs = pafs[top:pafs.shape[0] - bottom, left:pafs.shape[1] - right, :] - pafs = cv2.resize(pafs, (width, height), interpolation=cv2.INTER_CUBIC) - return heatmaps, pafs - - -def post_process(args): - txt_folder = args.benchmark_result_path - json_path = args.detections_save_path - pad_path = args.pad_txt_path - pad_info = {} - with open(pad_path, "r") as f: - lines = f.readlines() - for line in lines: - line_split = line.strip().split(" ") - pad_info[line_split[0]] = [int(line_split[i]) for i in range(1, 7)] - txt_1, txt_2 = [], [] - for txt in os.listdir(txt_folder): - txt_pure_name = txt.split('.')[0] - index = txt_pure_name.rfind('_') - name_suffix = txt_pure_name[index + 1] - if name_suffix == "1": - txt_1.append(txt) - else: - txt_2.append(txt) - txt_1.sort() - txt_2.sort() - coco_result = [] - for txt1, txt2 in zip(txt_1, txt_2): - txt_pure_name = txt1.split('.')[0] - index = txt_pure_name.rfind('_') - img_name = txt_pure_name[0:index] + ".jpg" - txt1_path = os.path.join(txt_folder, txt1) - txt2_path = os.path.join(txt_folder, txt2) - print(txt1, txt2) - heatmaps = read_txt(txt1_path, (1, 19, 46, 80)) - pafs = read_txt(txt2_path, (1, 38, 46, 80)) - pad = pad_info[img_name] - height, width = pad[0], pad[1] - top, bottom, left, right = pad[2], pad[3], pad[4], pad[5] - heatmaps, pafs = transfer(heatmaps, pafs, height, width, top, bottom, left, right) - all_keypoints_num = 0 - all_keypoints_by_type = [] - for kpt_idx in range(18): # 19th for bg - all_keypoints_num += extract_keypoints(heatmaps[:, :, kpt_idx], all_keypoints_by_type, all_keypoints_num) - pose_entries, all_keypoints = group_keypoints(all_keypoints_by_type, pafs) - coco_keypoints, scores = convert_to_coco_format(pose_entries, all_keypoints) - image_id = int(img_name[0:img_name.rfind('.')]) - for idx in range(len(coco_keypoints)): - coco_result.append({'image_id': image_id, 'category_id': 1, 'keypoints': coco_keypoints[idx], - 'score': scores[idx]}) - with open(json_path, 'w') as f: - json.dump(coco_result, f, indent=4) - run_coco_eval(args.labels, json_path) - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("--benchmark_result_path", default="./result/dumpOutput_device0") - parser.add_argument("--detections_save_path", default="./output/result.json") - parser.add_argument("--pad_txt_path", default="./output/pad.txt", - help="padding around the image with 368*640") - parser.add_argument('--labels', type=str, default='/root/datasets/coco/annotations/person_keypoints_val2017.json', - help='path to json with keypoints val labels') - args = parser.parse_args() - - post_process(args) - - -if __name__ == '__main__': - main() +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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. +""" +python3.7 OpenPose_postprocess.py +--benchmark_result_path ./result/dumpOutput_device0 +--detections_save_path ./output/result.json +--pad_txt_path ./output/pad.txt +--labels /root/datasets/coco/annotations/person_keypoints_val2017.json +""" +import argparse +import json +import os +import sys +import torch +import cv2 +import numpy as np +sys.path.append("./lightweight-human-pose-estimation.pytorch") +from modules.keypoints import group_keypoints, extract_keypoints +from val import run_coco_eval, convert_to_coco_format + + +def read_txt(txt_path, shape): + with open(txt_path, "r") as f: + line = f.readline() + line_split = line.strip().split(" ") + line_split = [eval(i) for i in line_split] + line_split = torch.Tensor(line_split) + heatmaps = line_split.view(shape) + return heatmaps + + +def transfer(heatmaps, pafs, height, width, top, bottom, left, right, stride=8): + heatmaps = np.transpose(heatmaps.squeeze().cpu().data.numpy(), (1, 2, 0)) + heatmaps = cv2.resize(heatmaps, (0, 0), fx=stride, fy=stride, interpolation=cv2.INTER_CUBIC) + heatmaps = heatmaps[top:heatmaps.shape[0] - bottom, left:heatmaps.shape[1] - right:, :] + heatmaps = cv2.resize(heatmaps, (width, height), interpolation=cv2.INTER_CUBIC) + pafs = np.transpose(pafs.squeeze().cpu().data.numpy(), (1, 2, 0)) + pafs = cv2.resize(pafs, (0, 0), fx=stride, fy=stride, interpolation=cv2.INTER_CUBIC) + pafs = pafs[top:pafs.shape[0] - bottom, left:pafs.shape[1] - right, :] + pafs = cv2.resize(pafs, (width, height), interpolation=cv2.INTER_CUBIC) + return heatmaps, pafs + + +def post_process(args): + txt_folder = args.benchmark_result_path + json_path = args.detections_save_path + pad_path = args.pad_txt_path + pad_info = {} + with open(pad_path, "r") as f: + lines = f.readlines() + for line in lines: + line_split = line.strip().split(" ") + pad_info[line_split[0]] = [int(line_split[i]) for i in range(1, 7)] + txt_1, txt_2 = [], [] + for txt in os.listdir(txt_folder): + txt_pure_name = txt.split('.')[0] + index = txt_pure_name.rfind('_') + name_suffix = txt_pure_name[index + 1] + if name_suffix == "1": + txt_1.append(txt) + else: + txt_2.append(txt) + txt_1.sort() + txt_2.sort() + coco_result = [] + for txt1, txt2 in zip(txt_1, txt_2): + txt_pure_name = txt1.split('.')[0] + index = txt_pure_name.rfind('_') + img_name = txt_pure_name[0:index] + ".jpg" + txt1_path = os.path.join(txt_folder, txt1) + txt2_path = os.path.join(txt_folder, txt2) + print(txt1, txt2) + heatmaps = read_txt(txt1_path, (1, 19, 46, 80)) + pafs = read_txt(txt2_path, (1, 38, 46, 80)) + pad = pad_info[img_name] + height, width = pad[0], pad[1] + top, bottom, left, right = pad[2], pad[3], pad[4], pad[5] + heatmaps, pafs = transfer(heatmaps, pafs, height, width, top, bottom, left, right) + all_keypoints_num = 0 + all_keypoints_by_type = [] + for kpt_idx in range(18): # 19th for bg + all_keypoints_num += extract_keypoints(heatmaps[:, :, kpt_idx], all_keypoints_by_type, all_keypoints_num) + pose_entries, all_keypoints = group_keypoints(all_keypoints_by_type, pafs) + coco_keypoints, scores = convert_to_coco_format(pose_entries, all_keypoints) + image_id = int(img_name[0:img_name.rfind('.')]) + for idx in range(len(coco_keypoints)): + coco_result.append({'image_id': image_id, 'category_id': 1, 'keypoints': coco_keypoints[idx], + 'score': scores[idx]}) + with open(json_path, 'w') as f: + json.dump(coco_result, f, indent=4) + run_coco_eval(args.labels, json_path) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--benchmark_result_path", default="./result/dumpOutput_device0") + parser.add_argument("--detections_save_path", default="./output/result.json") + parser.add_argument("--pad_txt_path", default="./output/pad.txt", + help="padding around the image with 368*640") + parser.add_argument('--labels', type=str, default='/root/datasets/coco/annotations/person_keypoints_val2017.json', + help='path to json with keypoints val labels') + args = parser.parse_args() + + post_process(args) + + +if __name__ == '__main__': + main() diff --git a/ACL_PyTorch/contrib/cv/detection/OpenPose/OpenPose_preprocess.py b/ACL_PyTorch/contrib/cv/detection/OpenPose/OpenPose_preprocess.py index 08328966e4..68c1d4e78f 100644 --- a/ACL_PyTorch/contrib/cv/detection/OpenPose/OpenPose_preprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/OpenPose/OpenPose_preprocess.py @@ -1,90 +1,90 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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. -""" -python3.7 OpenPose_preprocess.py ---src_path /root/datasets/coco/val2017 ---save_path /root/datasets/coco/prep_dataset ---pad_txt_path ./output/pad.txt -""" -import os -import sys -import math -import argparse -import torch -import numpy as np -import cv2 -sys.path.append("./lightweight-human-pose-estimation.pytorch") -from val import normalize - - -def pad_width(img, stride, pad_value, min_dims, name, height, width, pad_txt_path): - h, w, _ = img.shape - min_dims[0] = math.ceil(min_dims[0] / float(stride)) * stride - min_dims[1] = math.ceil(min_dims[1] / float(stride)) * stride - pad = [int(math.floor((min_dims[0] - h) / 2.0)), int(math.floor((min_dims[1] - w) / 2.0))] - pad.append(int(min_dims[0] - h - pad[0])) - pad.append(int(min_dims[1] - w - pad[1])) - padded_img = cv2.copyMakeBorder(img, pad[int(0)], pad[int(2)], pad[int(1)], pad[int(3)], - cv2.BORDER_CONSTANT, value=pad_value) - with open(pad_txt_path, "a") as f: - f.write(str(name) + " " + str(height) + " " + str(width) + " " + - str(pad[int(0)]) + " " + str(pad[int(2)]) + " " + str(pad[int(1)]) + " " + str(pad[int(3)]) + "\n") - print("padded_img's h w:", padded_img.shape[0], padded_img.shape[1]) - return padded_img, pad # top,bottom,left,right - - -def image_preprocess(img, name, pad_txt_path, base_height=368, base_width=640, stride=8, cpu=True, pad_value=(0, 0, 0), - img_mean=np.array([128, 128, 128], np.float32), img_scale=np.float32(1 / 256)): - norm_img = normalize(img, img_mean, img_scale) - height, width, _ = img.shape - height_scale = base_height / height - width_scale = base_width / width - scale = min(height_scale, width_scale) - scaled_img = cv2.resize(norm_img, (0, 0), fx=scale, fy=scale, interpolation=cv2.INTER_LINEAR) - min_dims = [base_height, base_width] - padded_img, pad = pad_width(scaled_img, stride, pad_value, min_dims, name, height, width, pad_txt_path) - tensor_img = torch.from_numpy(padded_img).permute(2, 0, 1).unsqueeze(0).float() - print("tensor_img shape:", tensor_img.shape) - if not cpu: - tensor_img = tensor_img.cuda() - return tensor_img - - -def preprocess(src_path, save_path, pad_txt_path): - in_files = os.listdir(src_path) - for i, file in enumerate(in_files): - print(file, "===", i) - img_path = os.path.join(src_path, file) - input_image = cv2.imread(img_path, cv2.IMREAD_COLOR) - input_tensor = image_preprocess(input_image, file, pad_txt_path) - img = np.array(input_tensor).astype(np.float32) - img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument('--src_path', type=str, default='/root/datasets/coco/val2017', - help='the source path of images') - parser.add_argument('--save_path', type=str, default='/root/datasets/coco/prep_dataset', - help='the path of saving bin of each image') - parser.add_argument('--pad_txt_path', type=str, default='./output/pad.txt' - , help='the path of pad.txt saving the info of padding') - args = parser.parse_args() - with open(args.pad_txt_path, "a+") as f: - f.truncate(0) - preprocess(args.src_path, args.save_path, args.pad_txt_path) - - -if __name__ == "__main__": - main() +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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. +""" +python3.7 OpenPose_preprocess.py +--src_path /root/datasets/coco/val2017 +--save_path /root/datasets/coco/prep_dataset +--pad_txt_path ./output/pad.txt +""" +import os +import sys +import math +import argparse +import torch +import numpy as np +import cv2 +sys.path.append("./lightweight-human-pose-estimation.pytorch") +from val import normalize + + +def pad_width(img, stride, pad_value, min_dims, name, height, width, pad_txt_path): + h, w, _ = img.shape + min_dims[0] = math.ceil(min_dims[0] / float(stride)) * stride + min_dims[1] = math.ceil(min_dims[1] / float(stride)) * stride + pad = [int(math.floor((min_dims[0] - h) / 2.0)), int(math.floor((min_dims[1] - w) / 2.0))] + pad.append(int(min_dims[0] - h - pad[0])) + pad.append(int(min_dims[1] - w - pad[1])) + padded_img = cv2.copyMakeBorder(img, pad[int(0)], pad[int(2)], pad[int(1)], pad[int(3)], + cv2.BORDER_CONSTANT, value=pad_value) + with open(pad_txt_path, "a") as f: + f.write(str(name) + " " + str(height) + " " + str(width) + " " + + str(pad[int(0)]) + " " + str(pad[int(2)]) + " " + str(pad[int(1)]) + " " + str(pad[int(3)]) + "\n") + print("padded_img's h w:", padded_img.shape[0], padded_img.shape[1]) + return padded_img, pad # top,bottom,left,right + + +def image_preprocess(img, name, pad_txt_path, base_height=368, base_width=640, stride=8, cpu=True, pad_value=(0, 0, 0), + img_mean=np.array([128, 128, 128], np.float32), img_scale=np.float32(1 / 256)): + norm_img = normalize(img, img_mean, img_scale) + height, width, _ = img.shape + height_scale = base_height / height + width_scale = base_width / width + scale = min(height_scale, width_scale) + scaled_img = cv2.resize(norm_img, (0, 0), fx=scale, fy=scale, interpolation=cv2.INTER_LINEAR) + min_dims = [base_height, base_width] + padded_img, pad = pad_width(scaled_img, stride, pad_value, min_dims, name, height, width, pad_txt_path) + tensor_img = torch.from_numpy(padded_img).permute(2, 0, 1).unsqueeze(0).float() + print("tensor_img shape:", tensor_img.shape) + if not cpu: + tensor_img = tensor_img.cuda() + return tensor_img + + +def preprocess(src_path, save_path, pad_txt_path): + in_files = os.listdir(src_path) + for i, file in enumerate(in_files): + print(file, "===", i) + img_path = os.path.join(src_path, file) + input_image = cv2.imread(img_path, cv2.IMREAD_COLOR) + input_tensor = image_preprocess(input_image, file, pad_txt_path) + img = np.array(input_tensor).astype(np.float32) + img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--src_path', type=str, default='/root/datasets/coco/val2017', + help='the source path of images') + parser.add_argument('--save_path', type=str, default='/root/datasets/coco/prep_dataset', + help='the path of saving bin of each image') + parser.add_argument('--pad_txt_path', type=str, default='./output/pad.txt' + , help='the path of pad.txt saving the info of padding') + args = parser.parse_args() + with open(args.pad_txt_path, "a+") as f: + f.truncate(0) + preprocess(args.src_path, args.save_path, args.pad_txt_path) + + +if __name__ == "__main__": + main() diff --git a/ACL_PyTorch/contrib/cv/detection/OpenPose/OpenPose_pth2onnx.py b/ACL_PyTorch/contrib/cv/detection/OpenPose/OpenPose_pth2onnx.py index bf5e6c4022..9f01273cda 100644 --- a/ACL_PyTorch/contrib/cv/detection/OpenPose/OpenPose_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/detection/OpenPose/OpenPose_pth2onnx.py @@ -1,63 +1,63 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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. -""" -python3.7 OpenPose_pth2onnx.py ---checkpoint-path ./weights/checkpoint_iter_370000.pth ---output-name ./output/human-pose-estimation.onnx -""" -import argparse -import os -import sys -import torch -sys.path.append("./lightweight-human-pose-estimation.pytorch") -from models.with_mobilenet import PoseEstimationWithMobileNet -from modules.load_state import load_state - - -def convert_to_onnx(network, output_name): - net_input = torch.randn(1, 3, 368, 640) - input_names = ['data'] - output_names = ['stage_0_output_1_heatmaps', 'stage_0_output_0_pafs', - 'stage_1_output_1_heatmaps', 'stage_1_output_0_pafs'] - dynamic_axes = {'data': {0: '-1'}, 'stage_0_output_1_heatmaps': {0: '-1'}, 'stage_0_output_0_pafs': {0: '-1'}, - 'stage_1_output_1_heatmaps': {0: '-1'}, 'stage_1_output_0_pafs': {0: '-1'}} - torch.onnx.export(network, net_input, output_name, opset_version=11, verbose=True, - input_names=input_names, dynamic_axes=dynamic_axes, output_names=output_names) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--checkpoint_path', type=str, default='./weights/checkpoint_iter_370000.pth', - help='path to the checkpoint') - parser.add_argument('--output_name', type=str, default='./output/human-pose-estimation.onnx', - help='name of output model in ONNX format') - args = parser.parse_args() - - # mkdir - dir1, file1 = os.path.split(args.checkpoint_path) - dir2, file2 = os.path.split(args.output_name) - if not os.path.exists(dir1): - os.mkdir(dir1) - else: - print(dir1, "already exist") - if not os.path.exists(dir2): - os.mkdir(dir2) - else: - print(dir2, "already exist") - - net = PoseEstimationWithMobileNet() - checkpoint = torch.load(args.checkpoint_path, map_location=torch.device("cpu")) - load_state(net, checkpoint) - - convert_to_onnx(net, args.output_name) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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. +""" +python3.7 OpenPose_pth2onnx.py +--checkpoint-path ./weights/checkpoint_iter_370000.pth +--output-name ./output/human-pose-estimation.onnx +""" +import argparse +import os +import sys +import torch +sys.path.append("./lightweight-human-pose-estimation.pytorch") +from models.with_mobilenet import PoseEstimationWithMobileNet +from modules.load_state import load_state + + +def convert_to_onnx(network, output_name): + net_input = torch.randn(1, 3, 368, 640) + input_names = ['data'] + output_names = ['stage_0_output_1_heatmaps', 'stage_0_output_0_pafs', + 'stage_1_output_1_heatmaps', 'stage_1_output_0_pafs'] + dynamic_axes = {'data': {0: '-1'}, 'stage_0_output_1_heatmaps': {0: '-1'}, 'stage_0_output_0_pafs': {0: '-1'}, + 'stage_1_output_1_heatmaps': {0: '-1'}, 'stage_1_output_0_pafs': {0: '-1'}} + torch.onnx.export(network, net_input, output_name, opset_version=11, verbose=True, + input_names=input_names, dynamic_axes=dynamic_axes, output_names=output_names) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--checkpoint_path', type=str, default='./weights/checkpoint_iter_370000.pth', + help='path to the checkpoint') + parser.add_argument('--output_name', type=str, default='./output/human-pose-estimation.onnx', + help='name of output model in ONNX format') + args = parser.parse_args() + + # mkdir + dir1, file1 = os.path.split(args.checkpoint_path) + dir2, file2 = os.path.split(args.output_name) + if not os.path.exists(dir1): + os.mkdir(dir1) + else: + print(dir1, "already exist") + if not os.path.exists(dir2): + os.mkdir(dir2) + else: + print(dir2, "already exist") + + net = PoseEstimationWithMobileNet() + checkpoint = torch.load(args.checkpoint_path, map_location=torch.device("cpu")) + load_state(net, checkpoint) + + convert_to_onnx(net, args.output_name) diff --git a/ACL_PyTorch/contrib/cv/detection/OpenPose/README.md b/ACL_PyTorch/contrib/cv/detection/OpenPose/README.md index 480a0bcce9..08eef2e02f 100644 --- a/ACL_PyTorch/contrib/cv/detection/OpenPose/README.md +++ b/ACL_PyTorch/contrib/cv/detection/OpenPose/README.md @@ -1,52 +1,52 @@ -# OpenPose模型PyTorch离线推理指导 -## 1 环境准备 -### 1.1 安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -``` -pip3.7 install -r requirements.txt -``` -### 1.2 获取,安装开源模型代码 -``` -git clone https://github.com/Daniil-Osokin/lightweight-human-pose-estimation.pytorch.git -``` -### 1.3 获取权重文件 -[OpenPose预训练pth权重文件](https://download.01.org/opencv/openvino_training_extensions/models/human_pose_estimation/checkpoint_iter_370000.pth) -``` -wget https://download.01.org/opencv/openvino_training_extensions/models/human_pose_estimation/checkpoint_iter_370000.pth -P ./weights -``` -### 1.4 数据集 -310服务器上可能已经下载好该数据集,若无,参考以下方法下载。 -[coco2017官网](https://cocodataset.org/#download) -下载其中val2017图片及其标注文件,使用5000张验证集进行测试,图片与标注文件分别存放在/root/datasets/coco/val2017与/root/datasets/coco/annotations/person_keypoints_val2017.json。 -文件目录结构如下, -``` -root -├── datasets -│ ├── coco -│ │ ├── annotations -│ │ │   ├── captions_train2017.json -│ │ │   ├── captions_val2017.json -│ │ │   ├── instances_train2017.json -│ │ │   ├── instances_val2017.json -│ │ │   ├── person_keypoints_train2017.json -│ │ │   └── person_keypoints_val2017.json -│ │ ├── val2017 -│ │ ├── annotations_trainval2017.zip -``` -### 1.5 [获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) -将benchmark.x86_64或benchmark.aarch64放到当前目录,并更改权限 -``` -chmod 777 benchmark.x86_64 -``` -## 2 离线推理 -### 2.1 测试 -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets -``` -### 2.2 测评结果 -|模型|pth精度(AP,%)|310精度(AP,%)|性能基准|310性能| -|----|----|----|----|----| -|OpenPose bs1|40|40.4|224.660fps|303.276fps| -|OpenPose bs16|40|40.4|339.973fps|444.908fps| - +# OpenPose模型PyTorch离线推理指导 +## 1 环境准备 +### 1.1 安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +``` +pip3.7 install -r requirements.txt +``` +### 1.2 获取,安装开源模型代码 +``` +git clone https://github.com/Daniil-Osokin/lightweight-human-pose-estimation.pytorch.git +``` +### 1.3 获取权重文件 +[OpenPose预训练pth权重文件](https://download.01.org/opencv/openvino_training_extensions/models/human_pose_estimation/checkpoint_iter_370000.pth) +``` +wget https://download.01.org/opencv/openvino_training_extensions/models/human_pose_estimation/checkpoint_iter_370000.pth -P ./weights +``` +### 1.4 数据集 +310服务器上可能已经下载好该数据集,若无,参考以下方法下载。 +[coco2017官网](https://cocodataset.org/#download) +下载其中val2017图片及其标注文件,使用5000张验证集进行测试,图片与标注文件分别存放在/root/datasets/coco/val2017与/root/datasets/coco/annotations/person_keypoints_val2017.json。 +文件目录结构如下, +``` +root +├── datasets +│ ├── coco +│ │ ├── annotations +│ │ │   ├── captions_train2017.json +│ │ │   ├── captions_val2017.json +│ │ │   ├── instances_train2017.json +│ │ │   ├── instances_val2017.json +│ │ │   ├── person_keypoints_train2017.json +│ │ │   └── person_keypoints_val2017.json +│ │ ├── val2017 +│ │ ├── annotations_trainval2017.zip +``` +### 1.5 [获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) +将benchmark.x86_64或benchmark.aarch64放到当前目录,并更改权限 +``` +chmod 777 benchmark.x86_64 +``` +## 2 离线推理 +### 2.1 测试 +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets +``` +### 2.2 测评结果 +|模型|pth精度(AP,%)|310精度(AP,%)|性能基准|310性能| +|----|----|----|----|----| +|OpenPose bs1|40|40.4|224.660fps|303.276fps| +|OpenPose bs16|40|40.4|339.973fps|444.908fps| + diff --git a/ACL_PyTorch/contrib/cv/detection/OpenPose/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/detection/OpenPose/gen_dataset_info.py index 63d02f673c..3d48029d61 100644 --- a/ACL_PyTorch/contrib/cv/detection/OpenPose/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/detection/OpenPose/gen_dataset_info.py @@ -1,72 +1,72 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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. -""" -python3.7 gen_dataset_info.py -bin -../../../../../root/datasets/coco/prep_dataset # Only relative paths of the info file can be used -./output/openpose_prep_bin.info -640 -368 # Sample width and height after preprocess -""" -import os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - bin_images.sort() - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -def main(): - file_type = sys.argv[1] - file_path = sys.argv[2] # Only relative paths of the info file can be used - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' - get_jpg_info(file_path, info_name) - - -if __name__ == '__main__': - main() +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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. +""" +python3.7 gen_dataset_info.py +bin +../../../../../root/datasets/coco/prep_dataset # Only relative paths of the info file can be used +./output/openpose_prep_bin.info +640 +368 # Sample width and height after preprocess +""" +import os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + bin_images.sort() + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +def main(): + file_type = sys.argv[1] + file_path = sys.argv[2] # Only relative paths of the info file can be used + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' + get_jpg_info(file_path, info_name) + + +if __name__ == '__main__': + main() diff --git a/ACL_PyTorch/contrib/cv/detection/OpenPose/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/detection/OpenPose/modelzoo_level.txt index 246aac9fe9..5d0cf16821 100644 --- a/ACL_PyTorch/contrib/cv/detection/OpenPose/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/detection/OpenPose/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK -PerfStatus:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK +PerfStatus:OK diff --git a/ACL_PyTorch/contrib/cv/detection/OpenPose/requirements.txt b/ACL_PyTorch/contrib/cv/detection/OpenPose/requirements.txt index f1784bf064..a68dc2cb77 100644 --- a/ACL_PyTorch/contrib/cv/detection/OpenPose/requirements.txt +++ b/ACL_PyTorch/contrib/cv/detection/OpenPose/requirements.txt @@ -1,5 +1,5 @@ -torch>=0.4.1 -torchvision>=0.2.1 -pycocotools==2.0.0 -opencv-python>=3.4.0.14 +torch>=0.4.1 +torchvision>=0.2.1 +pycocotools==2.0.0 +opencv-python>=3.4.0.14 numpy>=1.14.0 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/OpenPose/test/parse.py b/ACL_PyTorch/contrib/cv/detection/OpenPose/test/parse.py index 6cdf1420bd..64b47e3cff 100644 --- a/ACL_PyTorch/contrib/cv/detection/OpenPose/test/parse.py +++ b/ACL_PyTorch/contrib/cv/detection/OpenPose/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 - print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 + print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) diff --git a/ACL_PyTorch/contrib/cv/detection/RFCN/env.sh b/ACL_PyTorch/contrib/cv/detection/RFCN/env.sh index a63ac98e8a..f0619d3ad0 100644 --- a/ACL_PyTorch/contrib/cv/detection/RFCN/env.sh +++ b/ACL_PyTorch/contrib/cv/detection/RFCN/env.sh @@ -1,7 +1,7 @@ -export LD_LIBRARY_PATH=/usr/local/Ascend/ascend-toolkit/latest/lib64:/usr/local/Ascend/ascend-toolkit/latest/compiler/lib64/plugin/opskernel:/usr/local/Ascend/ascend-toolkit/latest/compiler/lib64/plugin/nnengine:$LD_LIBRARY_PATH -export PYTHONPATH=/usr/local/Ascend/ascend-toolkit/latest/python/site-packages:/usr/local/Ascend/ascend-toolkit/latest/opp/op_impl/built-in/ai_core/tbe:$PYTHONPATH -export PATH=/usr/local/Ascend/ascend-toolkit/latest/bin:/usr/local/Ascend/ascend-toolkit/latest/compiler/ccec_compiler/bin:$PATH -export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest -export ASCEND_OPP_PATH=/usr/local/Ascend/ascend-toolkit/latest/opp -export TOOLCHAIN_HOME=/usr/local/Ascend/ascend-toolkit/latest/toolkit +export LD_LIBRARY_PATH=/usr/local/Ascend/ascend-toolkit/latest/lib64:/usr/local/Ascend/ascend-toolkit/latest/compiler/lib64/plugin/opskernel:/usr/local/Ascend/ascend-toolkit/latest/compiler/lib64/plugin/nnengine:$LD_LIBRARY_PATH +export PYTHONPATH=/usr/local/Ascend/ascend-toolkit/latest/python/site-packages:/usr/local/Ascend/ascend-toolkit/latest/opp/op_impl/built-in/ai_core/tbe:$PYTHONPATH +export PATH=/usr/local/Ascend/ascend-toolkit/latest/bin:/usr/local/Ascend/ascend-toolkit/latest/compiler/ccec_compiler/bin:$PATH +export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest +export ASCEND_OPP_PATH=/usr/local/Ascend/ascend-toolkit/latest/opp +export TOOLCHAIN_HOME=/usr/local/Ascend/ascend-toolkit/latest/toolkit export ASCEND_AUTOML_PATH=/usr/local/Ascend/ascend-toolkit/latest/tools \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/RFCN/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/detection/RFCN/modelzoo_level.txt index 62ed12347c..def2f63f1b 100644 --- a/ACL_PyTorch/contrib/cv/detection/RFCN/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/detection/RFCN/modelzoo_level.txt @@ -1,6 +1,6 @@ -ModelConvert:OK -QuantStatus:OK -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +ModelConvert:OK +QuantStatus:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/RFCN/rfcn_postprocess.py b/ACL_PyTorch/contrib/cv/detection/RFCN/rfcn_postprocess.py index 5edc6bea58..eac0ac7e92 100644 --- a/ACL_PyTorch/contrib/cv/detection/RFCN/rfcn_postprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/RFCN/rfcn_postprocess.py @@ -1,249 +1,249 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch.nn.functional as F -import sys -sys.path.append('./RFCN-pytorch.1.0') -import _init_paths -import os - -import numpy as np -import argparse -import pprint -import pdb -import time -import cv2 -import torch -from torch.autograd import Variable -import torch.nn as nn -import torch.optim as optim -import pickle -from roi_data_layer.roidb import combined_roidb -from roi_data_layer.roibatchLoader import roibatchLoader -from model.utils.config import cfg, cfg_from_file, cfg_from_list, get_output_dir -from model.rpn.bbox_transform import clip_boxes -# from model.nms.nms_wrapper import nms -from model.roi_layers import nms -from model.rpn.bbox_transform import bbox_transform_inv -from model.utils.net_utils import save_net, load_net, vis_detections -from model.rfcn.resnet_atrous import resnet -import pdb -try: - xrange # Python 2 -except NameError: - xrange = range # Python 3 - - -def parse_args(): - """ - Parse input arguments - """ - parser = argparse.ArgumentParser(description='test the accuracy of RFCN') - - parser.add_argument("--image_folder_path", dest="file_path", default="./RFCN-pytorch.1.0/data/VOCdevkit2007/VOC2007/JPEGImages/",help='image of dataset') - parser.add_argument("--input",dest="input", default="./result/dumpOutput_device0/") - parser.add_argument("--output",dest="output", default="./output") - parser.add_argument("--test_annotation", default="./demo.info") - parser.add_argument("--net_input_width", default=1344) - parser.add_argument("--net_input_height", default=1344) - parser.add_argument('--dataset', dest='dataset',help='training dataset',default='pascal_voc', type=str) - parser.add_argument('--cfg', dest='cfg_file', help='optional config file',default='cfgs/res16.yml', type=str) - parser.add_argument('--net', dest='net',help='vgg16, res50, res101, res152',default='res101', type=str) - parser.add_argument('--set', dest='set_cfgs',help='set config keys', default=None,nargs=argparse.REMAINDER) - parser.add_argument('--load_dir', dest='load_dir',help='directory to load models', default="models", type=str) - parser.add_argument('--ls', dest='large_scale',help='whether use large imag scale',action='store_true') - parser.add_argument('--cag', dest='class_agnostic',help='whether perform class_agnostic bbox regression',action='store_true') - parser.add_argument('--parallel_type', dest='parallel_type',help='which part of model to parallel, 0: all, 1: model before roi pooling',default=0, type=int) - parser.add_argument('--bs', dest='batch_size',help='batch_size', default=1, type=int) - parser.add_argument('--vis', dest='vis', help='visualization mode',action='store_true') - args = parser.parse_args() - return args - -lr = cfg.TRAIN.LEARNING_RATE -momentum = cfg.TRAIN.MOMENTUM -weight_decay = cfg.TRAIN.WEIGHT_DECAY - -if __name__ == '__main__': - - args = parse_args() - - print('Called with args:') - print(args) - - np.random.seed(cfg.RNG_SEED) - - args.imdbval_name = "voc_2007_test" - args.set_cfgs = ['ANCHOR_SCALES', '[8, 16, 32]', 'ANCHOR_RATIOS', '[0.5,1,2]'] - args.cfg_file = "./RFCN-pytorch.1.0/cfgs/{}_ls.yml".format(args.net) if args.large_scale else "./RFCN-pytorch.1.0/cfgs/{}.yml".format(args.net) - - if args.cfg_file is not None: - cfg_from_file(args.cfg_file) - if args.set_cfgs is not None: - cfg_from_list(args.set_cfgs) - - cfg.TRAIN.USE_FLIPPED = False - imdb, roidb, ratio_list, ratio_index = combined_roidb(args.imdbval_name, False) - imdb.competition_mode(on=True) - - im_data = torch.FloatTensor(1) - im_info = torch.FloatTensor(1) - num_boxes = torch.LongTensor(1) - gt_boxes = torch.FloatTensor(1) - - with torch.no_grad(): - im_data = Variable(im_data) - im_info = Variable(im_info) - num_boxes = Variable(num_boxes) - gt_boxes = Variable(gt_boxes) - - start = time.time() - max_per_image = 100 - - vis = args.vis - - if vis: - thresh = 0.05 - else: - thresh = 0.0 - - #save_name = 'RFCN' - num_images = len(imdb.image_index) - all_boxes = [[[] for _ in xrange(num_images)] - for _ in xrange(imdb.num_classes)] - - #output_dir = get_output_dir(imdb, save_name) - output=args.output - if not os.path.exists(output): - os.makedirs(output) - dataset = roibatchLoader(roidb, ratio_list, ratio_index, args.batch_size, \ - imdb.num_classes, training=False, normalize = False) - dataloader = torch.utils.data.DataLoader(dataset, batch_size=args.batch_size, - shuffle=False, num_workers=0, - pin_memory=True) - - data_iter = iter(dataloader) - - # _t = {'im_detect': time.time(), 'misc': time.time()} - det_file = os.path.join(output, 'detections.pkl') - # fasterRCNN.eval() - empty_array = np.transpose(np.array([[],[],[],[],[]]), (1,0)) - dataset.resize_batch() - npu_result = args.input - with open("./RFCN-pytorch.1.0/data/VOCdevkit2007/VOC2007/ImageSets/Main/test.txt") as f: - imglist = [x.strip() for x in f.readlines()] - num_images = len(imglist) - for i in range(num_images): - data = next(data_iter) - pad_value = 0 - batch_shape = (3, 1344, 1344) - padding_size = [0, batch_shape[-1] - data[0].shape[-1], - 0, batch_shape[-2] - data[0].shape[-2]] - #data[0] = F.pad(data[0], padding_size, value=pad_value) - #im_data.resize_(data[0].size()).copy_(data[0]) - # print(im_data.size()) - im_info.resize_(data[1].size()).copy_(data[1]) - gt_boxes.resize_(data[2].size()).copy_(data[2]) - num_boxes.resize_(data[3].size()).copy_(data[3]) - det_tic = time.time() - - def read_data(data_path, input_shape=None): - if data_path.endswith('.bin'): - data = np.fromfile(data_path, dtype=np.float32) - data = data.reshape(input_shape) - elif data_path.endswith('.npy'): - data = np.load(data_path) - return data - - rois = torch.from_numpy( - read_data(npu_result+'{}_1.bin'.format(imglist[i]), [1, 300, 5])) - cls_prob = torch.from_numpy( - read_data(npu_result+'{}_2.bin'.format(imglist[i]), [1, 300, 21])) - bbox_pred = torch.from_numpy( - read_data(npu_result+'{}_3.bin'.format(imglist[i]), [1, 300, 84])) - scores = cls_prob.data - boxes = rois.data[:, :, 1:5] - - box_deltas = bbox_pred.data - box_deltas = box_deltas.view(-1, 4) * torch.FloatTensor(cfg.TRAIN.BBOX_NORMALIZE_STDS) \ - + torch.FloatTensor(cfg.TRAIN.BBOX_NORMALIZE_MEANS) - box_deltas = box_deltas.view(args.batch_size, -1, 4 * len(imdb.classes)) - pred_boxes = bbox_transform_inv(boxes, box_deltas, 1) - pred_boxes = clip_boxes(pred_boxes, im_info.data, 1) - pred_boxes /= data[1][0][2] - - scores = scores.squeeze() - pred_boxes = pred_boxes.squeeze() - det_toc = time.time() - detect_time = det_toc - det_tic - misc_tic = time.time() - if vis: - im = cv2.imread(imdb.image_path_at(i)) - im2show = np.copy(im) - for j in xrange(1, imdb.num_classes): - inds = torch.nonzero(scores[:, j] > thresh).view(-1) - # if there is det - if inds.numel() > 0: - cls_scores = scores[:, j][inds] - _, order = torch.sort(cls_scores, 0, True) - if args.class_agnostic: - cls_boxes = pred_boxes[inds, :] - else: - cls_boxes = pred_boxes[inds][:, j * 4:(j + 1) * 4] - - cls_dets = torch.cat((cls_boxes, cls_scores.unsqueeze(1)), 1) - # cls_dets = torch.cat((cls_boxes, cls_scores), 1) - cls_dets = cls_dets[order] - keep = nms(cls_boxes[order, :], cls_scores[order], cfg.TEST.NMS) - cls_dets = cls_dets[keep.view(-1).long()] - if vis: - im2show = vis_detections(im2show, imdb.classes[j], cls_dets.cpu().numpy(), 0.3) - all_boxes[j][i] = cls_dets.cpu().numpy() - else: - all_boxes[j][i] = empty_array - - # Limit to max_per_image detections *over all classes* - if max_per_image > 0: - image_scores = np.hstack([all_boxes[j][i][:, -1] - for j in xrange(1, imdb.num_classes)]) - if len(image_scores) > max_per_image: - image_thresh = np.sort(image_scores)[-max_per_image] - for j in xrange(1, imdb.num_classes): - keep = np.where(all_boxes[j][i][:, -1] >= image_thresh)[0] - all_boxes[j][i] = all_boxes[j][i][keep, :] - - misc_toc = time.time() - nms_time = misc_toc - misc_tic - - sys.stdout.write('im_detect: {:d}/{:d} {:.3f}s {:.3f}s \r' \ - .format(i + 1, num_images, detect_time, nms_time)) - sys.stdout.flush() - - if vis: - cv2.imwrite('result.png', im2show) - pdb.set_trace() - # cv2.imshow('test', im2show) - # cv2.waitKey(0) - - with open(det_file, 'wb') as f: - pickle.dump(all_boxes, f, pickle.HIGHEST_PROTOCOL) - - print('Evaluating detections') - imdb.evaluate_detections(all_boxes, output) - - end = time.time() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch.nn.functional as F +import sys +sys.path.append('./RFCN-pytorch.1.0') +import _init_paths +import os + +import numpy as np +import argparse +import pprint +import pdb +import time +import cv2 +import torch +from torch.autograd import Variable +import torch.nn as nn +import torch.optim as optim +import pickle +from roi_data_layer.roidb import combined_roidb +from roi_data_layer.roibatchLoader import roibatchLoader +from model.utils.config import cfg, cfg_from_file, cfg_from_list, get_output_dir +from model.rpn.bbox_transform import clip_boxes +# from model.nms.nms_wrapper import nms +from model.roi_layers import nms +from model.rpn.bbox_transform import bbox_transform_inv +from model.utils.net_utils import save_net, load_net, vis_detections +from model.rfcn.resnet_atrous import resnet +import pdb +try: + xrange # Python 2 +except NameError: + xrange = range # Python 3 + + +def parse_args(): + """ + Parse input arguments + """ + parser = argparse.ArgumentParser(description='test the accuracy of RFCN') + + parser.add_argument("--image_folder_path", dest="file_path", default="./RFCN-pytorch.1.0/data/VOCdevkit2007/VOC2007/JPEGImages/",help='image of dataset') + parser.add_argument("--input",dest="input", default="./result/dumpOutput_device0/") + parser.add_argument("--output",dest="output", default="./output") + parser.add_argument("--test_annotation", default="./demo.info") + parser.add_argument("--net_input_width", default=1344) + parser.add_argument("--net_input_height", default=1344) + parser.add_argument('--dataset', dest='dataset',help='training dataset',default='pascal_voc', type=str) + parser.add_argument('--cfg', dest='cfg_file', help='optional config file',default='cfgs/res16.yml', type=str) + parser.add_argument('--net', dest='net',help='vgg16, res50, res101, res152',default='res101', type=str) + parser.add_argument('--set', dest='set_cfgs',help='set config keys', default=None,nargs=argparse.REMAINDER) + parser.add_argument('--load_dir', dest='load_dir',help='directory to load models', default="models", type=str) + parser.add_argument('--ls', dest='large_scale',help='whether use large imag scale',action='store_true') + parser.add_argument('--cag', dest='class_agnostic',help='whether perform class_agnostic bbox regression',action='store_true') + parser.add_argument('--parallel_type', dest='parallel_type',help='which part of model to parallel, 0: all, 1: model before roi pooling',default=0, type=int) + parser.add_argument('--bs', dest='batch_size',help='batch_size', default=1, type=int) + parser.add_argument('--vis', dest='vis', help='visualization mode',action='store_true') + args = parser.parse_args() + return args + +lr = cfg.TRAIN.LEARNING_RATE +momentum = cfg.TRAIN.MOMENTUM +weight_decay = cfg.TRAIN.WEIGHT_DECAY + +if __name__ == '__main__': + + args = parse_args() + + print('Called with args:') + print(args) + + np.random.seed(cfg.RNG_SEED) + + args.imdbval_name = "voc_2007_test" + args.set_cfgs = ['ANCHOR_SCALES', '[8, 16, 32]', 'ANCHOR_RATIOS', '[0.5,1,2]'] + args.cfg_file = "./RFCN-pytorch.1.0/cfgs/{}_ls.yml".format(args.net) if args.large_scale else "./RFCN-pytorch.1.0/cfgs/{}.yml".format(args.net) + + if args.cfg_file is not None: + cfg_from_file(args.cfg_file) + if args.set_cfgs is not None: + cfg_from_list(args.set_cfgs) + + cfg.TRAIN.USE_FLIPPED = False + imdb, roidb, ratio_list, ratio_index = combined_roidb(args.imdbval_name, False) + imdb.competition_mode(on=True) + + im_data = torch.FloatTensor(1) + im_info = torch.FloatTensor(1) + num_boxes = torch.LongTensor(1) + gt_boxes = torch.FloatTensor(1) + + with torch.no_grad(): + im_data = Variable(im_data) + im_info = Variable(im_info) + num_boxes = Variable(num_boxes) + gt_boxes = Variable(gt_boxes) + + start = time.time() + max_per_image = 100 + + vis = args.vis + + if vis: + thresh = 0.05 + else: + thresh = 0.0 + + #save_name = 'RFCN' + num_images = len(imdb.image_index) + all_boxes = [[[] for _ in xrange(num_images)] + for _ in xrange(imdb.num_classes)] + + #output_dir = get_output_dir(imdb, save_name) + output=args.output + if not os.path.exists(output): + os.makedirs(output) + dataset = roibatchLoader(roidb, ratio_list, ratio_index, args.batch_size, \ + imdb.num_classes, training=False, normalize = False) + dataloader = torch.utils.data.DataLoader(dataset, batch_size=args.batch_size, + shuffle=False, num_workers=0, + pin_memory=True) + + data_iter = iter(dataloader) + + # _t = {'im_detect': time.time(), 'misc': time.time()} + det_file = os.path.join(output, 'detections.pkl') + # fasterRCNN.eval() + empty_array = np.transpose(np.array([[],[],[],[],[]]), (1,0)) + dataset.resize_batch() + npu_result = args.input + with open("./RFCN-pytorch.1.0/data/VOCdevkit2007/VOC2007/ImageSets/Main/test.txt") as f: + imglist = [x.strip() for x in f.readlines()] + num_images = len(imglist) + for i in range(num_images): + data = next(data_iter) + pad_value = 0 + batch_shape = (3, 1344, 1344) + padding_size = [0, batch_shape[-1] - data[0].shape[-1], + 0, batch_shape[-2] - data[0].shape[-2]] + #data[0] = F.pad(data[0], padding_size, value=pad_value) + #im_data.resize_(data[0].size()).copy_(data[0]) + # print(im_data.size()) + im_info.resize_(data[1].size()).copy_(data[1]) + gt_boxes.resize_(data[2].size()).copy_(data[2]) + num_boxes.resize_(data[3].size()).copy_(data[3]) + det_tic = time.time() + + def read_data(data_path, input_shape=None): + if data_path.endswith('.bin'): + data = np.fromfile(data_path, dtype=np.float32) + data = data.reshape(input_shape) + elif data_path.endswith('.npy'): + data = np.load(data_path) + return data + + rois = torch.from_numpy( + read_data(npu_result+'{}_1.bin'.format(imglist[i]), [1, 300, 5])) + cls_prob = torch.from_numpy( + read_data(npu_result+'{}_2.bin'.format(imglist[i]), [1, 300, 21])) + bbox_pred = torch.from_numpy( + read_data(npu_result+'{}_3.bin'.format(imglist[i]), [1, 300, 84])) + scores = cls_prob.data + boxes = rois.data[:, :, 1:5] + + box_deltas = bbox_pred.data + box_deltas = box_deltas.view(-1, 4) * torch.FloatTensor(cfg.TRAIN.BBOX_NORMALIZE_STDS) \ + + torch.FloatTensor(cfg.TRAIN.BBOX_NORMALIZE_MEANS) + box_deltas = box_deltas.view(args.batch_size, -1, 4 * len(imdb.classes)) + pred_boxes = bbox_transform_inv(boxes, box_deltas, 1) + pred_boxes = clip_boxes(pred_boxes, im_info.data, 1) + pred_boxes /= data[1][0][2] + + scores = scores.squeeze() + pred_boxes = pred_boxes.squeeze() + det_toc = time.time() + detect_time = det_toc - det_tic + misc_tic = time.time() + if vis: + im = cv2.imread(imdb.image_path_at(i)) + im2show = np.copy(im) + for j in xrange(1, imdb.num_classes): + inds = torch.nonzero(scores[:, j] > thresh).view(-1) + # if there is det + if inds.numel() > 0: + cls_scores = scores[:, j][inds] + _, order = torch.sort(cls_scores, 0, True) + if args.class_agnostic: + cls_boxes = pred_boxes[inds, :] + else: + cls_boxes = pred_boxes[inds][:, j * 4:(j + 1) * 4] + + cls_dets = torch.cat((cls_boxes, cls_scores.unsqueeze(1)), 1) + # cls_dets = torch.cat((cls_boxes, cls_scores), 1) + cls_dets = cls_dets[order] + keep = nms(cls_boxes[order, :], cls_scores[order], cfg.TEST.NMS) + cls_dets = cls_dets[keep.view(-1).long()] + if vis: + im2show = vis_detections(im2show, imdb.classes[j], cls_dets.cpu().numpy(), 0.3) + all_boxes[j][i] = cls_dets.cpu().numpy() + else: + all_boxes[j][i] = empty_array + + # Limit to max_per_image detections *over all classes* + if max_per_image > 0: + image_scores = np.hstack([all_boxes[j][i][:, -1] + for j in xrange(1, imdb.num_classes)]) + if len(image_scores) > max_per_image: + image_thresh = np.sort(image_scores)[-max_per_image] + for j in xrange(1, imdb.num_classes): + keep = np.where(all_boxes[j][i][:, -1] >= image_thresh)[0] + all_boxes[j][i] = all_boxes[j][i][keep, :] + + misc_toc = time.time() + nms_time = misc_toc - misc_tic + + sys.stdout.write('im_detect: {:d}/{:d} {:.3f}s {:.3f}s \r' \ + .format(i + 1, num_images, detect_time, nms_time)) + sys.stdout.flush() + + if vis: + cv2.imwrite('result.png', im2show) + pdb.set_trace() + # cv2.imshow('test', im2show) + # cv2.waitKey(0) + + with open(det_file, 'wb') as f: + pickle.dump(all_boxes, f, pickle.HIGHEST_PROTOCOL) + + print('Evaluating detections') + imdb.evaluate_detections(all_boxes, output) + + end = time.time() print("test time: %0.4fs" % (end - start)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/RefineDet/README.md b/ACL_PyTorch/contrib/cv/detection/RefineDet/README.md index 3019561495..47adaaa6f0 100644 --- a/ACL_PyTorch/contrib/cv/detection/RefineDet/README.md +++ b/ACL_PyTorch/contrib/cv/detection/RefineDet/README.md @@ -1,66 +1,66 @@ -#RefineDet模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 - -``` -pip3.7 install -r requirements.txt -``` - -2.获取代码和[权重文件](https://drive.google.com/file/d/1RCCTaNeby0g-TFE1Cvjm3dYweBiyyPoq/view?usp=sharing),放到当前路径下 - -``` -git clone https://github.com/luuuyi/RefineDet.PyTorch.git -b master -cd RefineDet.PyTorch -git reset --hard 0e4b24ce07245fcb8c48292326a731729cc5746a -patch -p1 < ../refinedet.patch - -``` - -3.获取数据集,[VOC数据集](http://host.robots.ox.ac.uk/pascal/VOC),可以通过下面的命令下载 - - -``` -sh data/scripts/VOC2007.sh -cd ../ -``` -4.获取[benchamrk](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) - -把benchmark.x86_64 或者 benchmark.aarch64 放到当前目录 - - -## 2 离线推理 - -pth转换为om -``` -bash test/pth2om.sh -``` - - -精度,性能测试 - -``` - bash test/eval_acc_perf.sh --datasets_path=/root/datasets/VOCdevkit/ -``` - - - - -**评测结果:** -| 模型 | pth精度 | 310精度 | 基准性能 |310性能 | -| :------: | :------: | :------: | :------: | :------: | -| RefineDet bs1 | [mAP:79.81%](https://github.com/luuuyi/RefineDet.PyTorch) | mAP:79.56%| 63.94fps | 101.24fps | -| RefineDet bs16 | [mAP:79.81%](https://github.com/luuuyi/RefineDet.PyTorch) |mAP:79.56% | 72.77fps | 136.8fps | - - - - -备注: - -- nms放在后处理,在cpu上计算 -- onnx转om时,不能使用fp16,否则精度不达标 - ``` - --precision_mode allow_fp32_to_fp16 - ``` - +#RefineDet模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 + +``` +pip3.7 install -r requirements.txt +``` + +2.获取代码和[权重文件](https://drive.google.com/file/d/1RCCTaNeby0g-TFE1Cvjm3dYweBiyyPoq/view?usp=sharing),放到当前路径下 + +``` +git clone https://github.com/luuuyi/RefineDet.PyTorch.git -b master +cd RefineDet.PyTorch +git reset --hard 0e4b24ce07245fcb8c48292326a731729cc5746a +patch -p1 < ../refinedet.patch + +``` + +3.获取数据集,[VOC数据集](http://host.robots.ox.ac.uk/pascal/VOC),可以通过下面的命令下载 + + +``` +sh data/scripts/VOC2007.sh +cd ../ +``` +4.获取[benchamrk](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) + +把benchmark.x86_64 或者 benchmark.aarch64 放到当前目录 + + +## 2 离线推理 + +pth转换为om +``` +bash test/pth2om.sh +``` + + +精度,性能测试 + +``` + bash test/eval_acc_perf.sh --datasets_path=/root/datasets/VOCdevkit/ +``` + + + + +**评测结果:** +| 模型 | pth精度 | 310精度 | 基准性能 |310性能 | +| :------: | :------: | :------: | :------: | :------: | +| RefineDet bs1 | [mAP:79.81%](https://github.com/luuuyi/RefineDet.PyTorch) | mAP:79.56%| 63.94fps | 101.24fps | +| RefineDet bs16 | [mAP:79.81%](https://github.com/luuuyi/RefineDet.PyTorch) |mAP:79.56% | 72.77fps | 136.8fps | + + + + +备注: + +- nms放在后处理,在cpu上计算 +- onnx转om时,不能使用fp16,否则精度不达标 + ``` + --precision_mode allow_fp32_to_fp16 + ``` + diff --git a/ACL_PyTorch/contrib/cv/detection/RefineDet/env.sh b/ACL_PyTorch/contrib/cv/detection/RefineDet/env.sh index 7cf86a22a6..e4c421dd8d 100644 --- a/ACL_PyTorch/contrib/cv/detection/RefineDet/env.sh +++ b/ACL_PyTorch/contrib/cv/detection/RefineDet/env.sh @@ -1,6 +1,6 @@ -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp export ASCEND_AICPU_PATH=${install_path} \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/RefineDet/get_prior_data.py b/ACL_PyTorch/contrib/cv/detection/RefineDet/get_prior_data.py index abc627029e..095256efd9 100644 --- a/ACL_PyTorch/contrib/cv/detection/RefineDet/get_prior_data.py +++ b/ACL_PyTorch/contrib/cv/detection/RefineDet/get_prior_data.py @@ -1,28 +1,28 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -sys.path.append('./RefineDet.PyTorch') -from layers.functions.prior_box import PriorBox -from data import voc_refinedet -import numpy as np - -cfg = voc_refinedet['320'] - -prior_box = PriorBox(cfg) - -prior_data = prior_box.forward().numpy() - -np.savetxt('prior_data.txt', prior_data) - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +sys.path.append('./RefineDet.PyTorch') +from layers.functions.prior_box import PriorBox +from data import voc_refinedet +import numpy as np + +cfg = voc_refinedet['320'] + +prior_box = PriorBox(cfg) + +prior_data = prior_box.forward().numpy() + +np.savetxt('prior_data.txt', prior_data) + print('Finish') \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/RefineDet/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/detection/RefineDet/modelzoo_level.txt index 83689985f2..8c469d858a 100644 --- a/ACL_PyTorch/contrib/cv/detection/RefineDet/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/detection/RefineDet/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus:PERFECT \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/Retinanet/LICENSE b/ACL_PyTorch/contrib/cv/detection/Retinanet/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/detection/Retinanet/LICENSE +++ b/ACL_PyTorch/contrib/cv/detection/Retinanet/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/Retinanet/get_info.py b/ACL_PyTorch/contrib/cv/detection/Retinanet/get_info.py index b76d6739bc..d5cab0450c 100644 --- a/ACL_PyTorch/contrib/cv/detection/Retinanet/get_info.py +++ b/ACL_PyTorch/contrib/cv/detection/Retinanet/get_info.py @@ -1,60 +1,60 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/Retinanet/requirements.txt b/ACL_PyTorch/contrib/cv/detection/Retinanet/requirements.txt index 84cc44c3bb..03db083c86 100644 --- a/ACL_PyTorch/contrib/cv/detection/Retinanet/requirements.txt +++ b/ACL_PyTorch/contrib/cv/detection/Retinanet/requirements.txt @@ -1,5 +1,5 @@ -torch == 1.8.1 -torchvision == 0.9.0 -onnx == 1.7.0 -numpy == 1.18.5 +torch == 1.8.1 +torchvision == 0.9.0 +onnx == 1.7.0 +numpy == 1.18.5 opencv-python == 4.2.0.34 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/Retinanet/retinanet_pth_postprocess_detectron2.py b/ACL_PyTorch/contrib/cv/detection/Retinanet/retinanet_pth_postprocess_detectron2.py index 62b94f1fd4..15958efd02 100644 --- a/ACL_PyTorch/contrib/cv/detection/Retinanet/retinanet_pth_postprocess_detectron2.py +++ b/ACL_PyTorch/contrib/cv/detection/Retinanet/retinanet_pth_postprocess_detectron2.py @@ -1,186 +1,186 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import argparse -import cv2 -import numpy as np -from pycocotools.cocoeval import COCOeval -from pycocotools.coco import COCO -import json -import pickle -import logging - -class CocoDataset: - """Coco dataset.""" - - def __init__(self, root_dir, set_name='train2017', transform=None): - """ - Args: - root_dir (string): COCO directory. - transform (callable, optional): Optional transform to be applied - on a sample. - """ - self.root_dir = root_dir - self.set_name = set_name - self.transform = transform - - self.coco = COCO(os.path.join(self.root_dir, 'annotations', 'instances_' + self.set_name + '.json')) - self.image_ids = self.coco.getImgIds() - - self.load_classes() - - def load_classes(self): - # load class names (name -> label) - categories = self.coco.loadCats(self.coco.getCatIds()) - categories.sort(key=lambda x: x['id']) - - self.classes = {} - self.coco_labels = {} - self.coco_labels_inverse = {} - for c in categories: - self.coco_labels[len(self.classes)] = c['id'] - self.coco_labels_inverse[c['id']] = len(self.classes) - self.classes[c['name']] = len(self.classes) - - # also load the reverse (label -> name) - self.labels = {} - for key, value in self.classes.items(): - self.labels[value] = key - - def coco_label_to_label(self, coco_label): - return self.coco_labels_inverse[coco_label] - - def label_to_coco_label(self, label): - return self.coco_labels[label] - -def postprocess_bboxes(bboxes, image_size, net_input_width, net_input_height): - old_h = image_size[0] - old_w = image_size[1] - scale_ratio = 800 / min(old_w, old_h) - if old_h < old_w: - new_h, new_w = 800, int(np.floor(scale_ratio * old_w)) - else: - new_h, new_w = int(np.floor(scale_ratio * old_h)), 800 - if max(new_h, new_w) > 1333: - scale = 1333 / max(new_h, new_w) - new_h = new_h * scale - new_w = new_w * scale - new_w = int(new_w + 0.5) - new_h = int(new_h + 0.5) - scale = new_w/old_w - - bboxes[:, 0] = (bboxes[:, 0]) / scale - bboxes[:, 1] = (bboxes[:, 1]) / scale - bboxes[:, 2] = (bboxes[:, 2]) / scale - bboxes[:, 3] = (bboxes[:, 3]) / scale - - return bboxes - - -def save_variable(v, filename): - f = open(filename, 'wb') - pickle.dump(v, f) - f.close() -def load_variavle(filename): - f = open(filename, 'rb') - r = pickle.load(f) - f.close() - return r - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--test_annotation", default="./origin_image.info") - parser.add_argument("--bin_data_path", default="./result/dumpOutput_device0/") - parser.add_argument("--val2017_path", default="/root/datasets/coco/val2017/") - parser.add_argument("--det_results_path", default="./result/detection-results/") - parser.add_argument("--net_out_num", type=int, default=3) - parser.add_argument("--net_input_width", type=int, default=1344) - parser.add_argument("--net_input_height", type=int, default=1344) - parser.add_argument("--ifShowDetObj", action="store_true", help="if input the para means True, neither False.") - flags = parser.parse_args() - - img_size_dict = dict() - with open(flags.test_annotation)as f: - for line in f.readlines(): - temp = line.split(" ") - img_file_path = temp[1] - img_name = temp[1].split("/")[-1].split(".")[0] - img_width = int(temp[2]) - img_height = int(temp[3]) - img_size_dict[img_name] = (img_width, img_height, img_file_path) - - bin_path = flags.bin_data_path - det_results_path = flags.det_results_path - os.makedirs(det_results_path, exist_ok=True) - total_img = set([name[:name.rfind('_')] for name in os.listdir(bin_path) if "bin" in name]) - - logging.basicConfig(level=logging.INFO) - coco_path = flags.val2017_path - dataloader_val = CocoDataset(coco_path, set_name='val2017') - results = [] - image_ids = [] - - for bin_file in sorted(total_img): - path_base = os.path.join(bin_path, bin_file) - res_buff = [] - for num in range(1, flags.net_out_num + 1): - if os.path.exists(path_base + "_" + str(num) + ".bin"): - if num == 1: - buf = np.fromfile(path_base + "_" + str(num) + ".bin", dtype="float32") - boxes = np.reshape(buf, [100, 4]) - elif num == 2: - buf = np.fromfile(path_base + "_" + str(num) + ".bin", dtype="int32") - labels = np.reshape(buf, [100, 1]) - elif num == 3: - buf = np.fromfile(path_base + "_" + str(num) + ".bin", dtype="float32") - scores = np.reshape(buf, [100, 1]) - else: - print("[ERROR] file not exist", path_base + "_" + str(num) + ".bin") - - current_img_size = img_size_dict[bin_file] - boxes = postprocess_bboxes(boxes, current_img_size, flags.net_input_width, flags.net_input_height) - - if boxes.shape[0] > 0: - # change to (x, y, w, h) (MS COCO standard) - boxes[:, 2] -= boxes[:, 0] - boxes[:, 3] -= boxes[:, 1] - for box_id in range(boxes.shape[0]): - if scores[box_id] <0.05: - continue - score = float(scores[box_id]) - label = int(labels[box_id]) - box = boxes[box_id, :] - image_result = { - 'image_id': int(bin_file), - 'category_id': dataloader_val.label_to_coco_label(label), - 'score': float(score), - 'bbox': box.tolist(), - } - # append detection to results - results.append(image_result) - image_ids.append(int(bin_file)) - - json.dump(results, open('{}_bbox_results.json'.format(dataloader_val.set_name), 'w'), indent=4) - coco_true = dataloader_val.coco - coco_pred = coco_true.loadRes('{}_bbox_results.json'.format(dataloader_val.set_name)) - - # run COCO evaluation - coco_eval = COCOeval(coco_true, coco_pred, 'bbox') - coco_eval.params.imgIds = image_ids - coco_eval.evaluate() - coco_eval.accumulate() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import argparse +import cv2 +import numpy as np +from pycocotools.cocoeval import COCOeval +from pycocotools.coco import COCO +import json +import pickle +import logging + +class CocoDataset: + """Coco dataset.""" + + def __init__(self, root_dir, set_name='train2017', transform=None): + """ + Args: + root_dir (string): COCO directory. + transform (callable, optional): Optional transform to be applied + on a sample. + """ + self.root_dir = root_dir + self.set_name = set_name + self.transform = transform + + self.coco = COCO(os.path.join(self.root_dir, 'annotations', 'instances_' + self.set_name + '.json')) + self.image_ids = self.coco.getImgIds() + + self.load_classes() + + def load_classes(self): + # load class names (name -> label) + categories = self.coco.loadCats(self.coco.getCatIds()) + categories.sort(key=lambda x: x['id']) + + self.classes = {} + self.coco_labels = {} + self.coco_labels_inverse = {} + for c in categories: + self.coco_labels[len(self.classes)] = c['id'] + self.coco_labels_inverse[c['id']] = len(self.classes) + self.classes[c['name']] = len(self.classes) + + # also load the reverse (label -> name) + self.labels = {} + for key, value in self.classes.items(): + self.labels[value] = key + + def coco_label_to_label(self, coco_label): + return self.coco_labels_inverse[coco_label] + + def label_to_coco_label(self, label): + return self.coco_labels[label] + +def postprocess_bboxes(bboxes, image_size, net_input_width, net_input_height): + old_h = image_size[0] + old_w = image_size[1] + scale_ratio = 800 / min(old_w, old_h) + if old_h < old_w: + new_h, new_w = 800, int(np.floor(scale_ratio * old_w)) + else: + new_h, new_w = int(np.floor(scale_ratio * old_h)), 800 + if max(new_h, new_w) > 1333: + scale = 1333 / max(new_h, new_w) + new_h = new_h * scale + new_w = new_w * scale + new_w = int(new_w + 0.5) + new_h = int(new_h + 0.5) + scale = new_w/old_w + + bboxes[:, 0] = (bboxes[:, 0]) / scale + bboxes[:, 1] = (bboxes[:, 1]) / scale + bboxes[:, 2] = (bboxes[:, 2]) / scale + bboxes[:, 3] = (bboxes[:, 3]) / scale + + return bboxes + + +def save_variable(v, filename): + f = open(filename, 'wb') + pickle.dump(v, f) + f.close() +def load_variavle(filename): + f = open(filename, 'rb') + r = pickle.load(f) + f.close() + return r + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("--test_annotation", default="./origin_image.info") + parser.add_argument("--bin_data_path", default="./result/dumpOutput_device0/") + parser.add_argument("--val2017_path", default="/root/datasets/coco/val2017/") + parser.add_argument("--det_results_path", default="./result/detection-results/") + parser.add_argument("--net_out_num", type=int, default=3) + parser.add_argument("--net_input_width", type=int, default=1344) + parser.add_argument("--net_input_height", type=int, default=1344) + parser.add_argument("--ifShowDetObj", action="store_true", help="if input the para means True, neither False.") + flags = parser.parse_args() + + img_size_dict = dict() + with open(flags.test_annotation)as f: + for line in f.readlines(): + temp = line.split(" ") + img_file_path = temp[1] + img_name = temp[1].split("/")[-1].split(".")[0] + img_width = int(temp[2]) + img_height = int(temp[3]) + img_size_dict[img_name] = (img_width, img_height, img_file_path) + + bin_path = flags.bin_data_path + det_results_path = flags.det_results_path + os.makedirs(det_results_path, exist_ok=True) + total_img = set([name[:name.rfind('_')] for name in os.listdir(bin_path) if "bin" in name]) + + logging.basicConfig(level=logging.INFO) + coco_path = flags.val2017_path + dataloader_val = CocoDataset(coco_path, set_name='val2017') + results = [] + image_ids = [] + + for bin_file in sorted(total_img): + path_base = os.path.join(bin_path, bin_file) + res_buff = [] + for num in range(1, flags.net_out_num + 1): + if os.path.exists(path_base + "_" + str(num) + ".bin"): + if num == 1: + buf = np.fromfile(path_base + "_" + str(num) + ".bin", dtype="float32") + boxes = np.reshape(buf, [100, 4]) + elif num == 2: + buf = np.fromfile(path_base + "_" + str(num) + ".bin", dtype="int32") + labels = np.reshape(buf, [100, 1]) + elif num == 3: + buf = np.fromfile(path_base + "_" + str(num) + ".bin", dtype="float32") + scores = np.reshape(buf, [100, 1]) + else: + print("[ERROR] file not exist", path_base + "_" + str(num) + ".bin") + + current_img_size = img_size_dict[bin_file] + boxes = postprocess_bboxes(boxes, current_img_size, flags.net_input_width, flags.net_input_height) + + if boxes.shape[0] > 0: + # change to (x, y, w, h) (MS COCO standard) + boxes[:, 2] -= boxes[:, 0] + boxes[:, 3] -= boxes[:, 1] + for box_id in range(boxes.shape[0]): + if scores[box_id] <0.05: + continue + score = float(scores[box_id]) + label = int(labels[box_id]) + box = boxes[box_id, :] + image_result = { + 'image_id': int(bin_file), + 'category_id': dataloader_val.label_to_coco_label(label), + 'score': float(score), + 'bbox': box.tolist(), + } + # append detection to results + results.append(image_result) + image_ids.append(int(bin_file)) + + json.dump(results, open('{}_bbox_results.json'.format(dataloader_val.set_name), 'w'), indent=4) + coco_true = dataloader_val.coco + coco_pred = coco_true.loadRes('{}_bbox_results.json'.format(dataloader_val.set_name)) + + # run COCO evaluation + coco_eval = COCOeval(coco_true, coco_pred, 'bbox') + coco_eval.params.imgIds = image_ids + coco_eval.evaluate() + coco_eval.accumulate() coco_eval.summarize() \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/Retinanet/retinanet_pth_preprocess_detectron2.py b/ACL_PyTorch/contrib/cv/detection/Retinanet/retinanet_pth_preprocess_detectron2.py index 46fa64f920..2700b4242a 100644 --- a/ACL_PyTorch/contrib/cv/detection/Retinanet/retinanet_pth_preprocess_detectron2.py +++ b/ACL_PyTorch/contrib/cv/detection/Retinanet/retinanet_pth_preprocess_detectron2.py @@ -1,80 +1,80 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import argparse -import numpy as np -import cv2 -import torch -import multiprocessing -def resize(img, size): - - old_h = img.shape[0] - old_w = img.shape[1] - scale_ratio = 800 / min(old_w, old_h) - if old_h < old_w: - new_h, new_w = 800, int(np.floor(scale_ratio * old_w)) - else: - new_h, new_w = int(np.floor(scale_ratio * old_h)), 800 - if max(new_h, new_w) > 1333: - scale = 1333 / max(new_h, new_w) - new_h = new_h * scale - new_w = new_w * scale - new_w = int(new_w + 0.5) - new_h = int(new_h + 0.5) - ret = cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_LINEAR) - return ret - - -def gen_input_bin(file_batches, batch): - i = 0 - for file in file_batches[batch]: - i = i + 1 - print("batch", batch, file, "===", i) - image = cv2.imread(os.path.join(flags.image_src_path, file), cv2.IMREAD_COLOR) - image = resize(image, (800, 1333)) - mean = np.array([103.53, 116.28, 123.675], dtype=np.float32) - std = np.array([1., 1., 1.], dtype=np.float32) - img = image.copy().astype(np.float32) - mean = np.float64(mean.reshape(1, -1)) - std = 1 / np.float64(std.reshape(1, -1)) - cv2.subtract(img, mean, img) - cv2.multiply(img, std, img) - - img = cv2.copyMakeBorder(img, 0, flags.model_input_height - img.shape[0], 0, flags.model_input_width - img.shape[1], cv2.BORDER_CONSTANT, value=0) - img = img.transpose(2, 0, 1) - - - img.tofile(os.path.join(flags.bin_file_path, file.split('.')[0] + ".bin")) - -def preprocess(src_path, save_path): - files = os.listdir(src_path) - file_batches = [files[i:i + 100] for i in range(0, 5000, 100) if files[i:i + 100] != []] - thread_pool = multiprocessing.Pool(len(file_batches)) - for batch in range(len(file_batches)): - thread_pool.apply_async(gen_input_bin, args=(file_batches, batch)) - thread_pool.close() - thread_pool.join() - print("in thread, except will not report! please ensure bin files generated.") - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='preprocess of MaskRCNN PyTorch model') - parser.add_argument("--image_src_path", default="/root/datasets/coco/val2017", help='image of dataset') - parser.add_argument("--bin_file_path", default="./val2017_bin/", help='Preprocessed image buffer') - parser.add_argument("--model_input_height", default=1344, type=int, help='input tensor height') - parser.add_argument("--model_input_width", default=1344, type=int, help='input tensor width') - flags = parser.parse_args() - if not os.path.exists(flags.bin_file_path): - os.makedirs(flags.bin_file_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import argparse +import numpy as np +import cv2 +import torch +import multiprocessing +def resize(img, size): + + old_h = img.shape[0] + old_w = img.shape[1] + scale_ratio = 800 / min(old_w, old_h) + if old_h < old_w: + new_h, new_w = 800, int(np.floor(scale_ratio * old_w)) + else: + new_h, new_w = int(np.floor(scale_ratio * old_h)), 800 + if max(new_h, new_w) > 1333: + scale = 1333 / max(new_h, new_w) + new_h = new_h * scale + new_w = new_w * scale + new_w = int(new_w + 0.5) + new_h = int(new_h + 0.5) + ret = cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_LINEAR) + return ret + + +def gen_input_bin(file_batches, batch): + i = 0 + for file in file_batches[batch]: + i = i + 1 + print("batch", batch, file, "===", i) + image = cv2.imread(os.path.join(flags.image_src_path, file), cv2.IMREAD_COLOR) + image = resize(image, (800, 1333)) + mean = np.array([103.53, 116.28, 123.675], dtype=np.float32) + std = np.array([1., 1., 1.], dtype=np.float32) + img = image.copy().astype(np.float32) + mean = np.float64(mean.reshape(1, -1)) + std = 1 / np.float64(std.reshape(1, -1)) + cv2.subtract(img, mean, img) + cv2.multiply(img, std, img) + + img = cv2.copyMakeBorder(img, 0, flags.model_input_height - img.shape[0], 0, flags.model_input_width - img.shape[1], cv2.BORDER_CONSTANT, value=0) + img = img.transpose(2, 0, 1) + + + img.tofile(os.path.join(flags.bin_file_path, file.split('.')[0] + ".bin")) + +def preprocess(src_path, save_path): + files = os.listdir(src_path) + file_batches = [files[i:i + 100] for i in range(0, 5000, 100) if files[i:i + 100] != []] + thread_pool = multiprocessing.Pool(len(file_batches)) + for batch in range(len(file_batches)): + thread_pool.apply_async(gen_input_bin, args=(file_batches, batch)) + thread_pool.close() + thread_pool.join() + print("in thread, except will not report! please ensure bin files generated.") + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='preprocess of MaskRCNN PyTorch model') + parser.add_argument("--image_src_path", default="/root/datasets/coco/val2017", help='image of dataset') + parser.add_argument("--bin_file_path", default="./val2017_bin/", help='Preprocessed image buffer') + parser.add_argument("--model_input_height", default=1344, type=int, help='input tensor height') + parser.add_argument("--model_input_width", default=1344, type=int, help='input tensor width') + flags = parser.parse_args() + if not os.path.exists(flags.bin_file_path): + os.makedirs(flags.bin_file_path) preprocess(flags.image_src_path, flags.bin_file_path) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/Retinanet/test/README.md b/ACL_PyTorch/contrib/cv/detection/Retinanet/test/README.md index dc1c3eabd5..d8a57f62bd 100644 --- a/ACL_PyTorch/contrib/cv/detection/Retinanet/test/README.md +++ b/ACL_PyTorch/contrib/cv/detection/Retinanet/test/README.md @@ -1,49 +1,49 @@ -环境准备: - -1.数据集路径 通用的数据集统一放在/root/datasets/或/opt/npu/ 本模型数据集放在/root/datasets/ -该文件夹下要包含 - -./coco - ./val2017 - ./annotations - ./instances_val2017.json - -2.进入工作目录 cd Retinanet - -3.安装必要的依赖 pip3.7 install -r requirements.txt - -4.获取、修改和安装模型代码 a. 获取模型代码 git clone https://github.com/facebookresearch/detectron2 - -cd detectron2/ git reset --hard 13afb03 - -b.安装 cd .. rm -rf detectron2/build/ **/*.so python3.7 -m pip install -e detectron2 - -如果detectron2安装报错,请尝试下面这种方法安装: cd detectron2 -python3.7 setup.py build develop - -c.修改源代码 -若是基准环境中 -cd detectron2/ patch -p1 < ../retinanet_pth.diff cd .. - -若是npu环境中 -cd detectron2/ patch -p1 < ../retinanet_detectron2.diff cd .. - -5.获取权重文件 -wget https://dl.fbaipublicfiles.com/detectron2/COCO-Detection/retinanet_R_50_FPN_3x/190397829/model_final_5bd44e.pkl -将权重文件改名: mv model_final_5bd44e.pkl model_final.pkl - -6.修改pytorch代码去除导出onnx时进行检查 将/usr/local/python3.7.5/lib/python3.7/site-packages/torch/onnx/utils.py文件的_check_onnx_proto(proto)这一行改为pass - -7.获取benchmark工具 将benchmark.x86_64 benchmark.aarch64放在当前目录 - -推理步骤: - -8..修改detectron2/detectron2/data/datasets/builtin.py的258行为_root = os.getenv("DETECTRON2_DATASETS", "/root/datasets/")指定coco数据集所在的目录/root/datasets/ -运行命令,在output文件夹下生成model.onnx文件 - -python3.7 ./detectron2/tools/deploy/export_model.py --config-file ./detectron2/configs/COCO-Detection/retinanet_R_50_FPN_3x.yaml --output ./output --export-method tracing --format onnx MODEL.WEIGHTS model_final.pkl MODEL.DEVICE cpu - - -9.脚本转换om模型 bash test/pth2om.sh - -10.310上执行,执行时确保device空闲: bash test/eval_acc_perf.sh --datasets_path=/root/datasets +环境准备: + +1.数据集路径 通用的数据集统一放在/root/datasets/或/opt/npu/ 本模型数据集放在/root/datasets/ +该文件夹下要包含 + +./coco + ./val2017 + ./annotations + ./instances_val2017.json + +2.进入工作目录 cd Retinanet + +3.安装必要的依赖 pip3.7 install -r requirements.txt + +4.获取、修改和安装模型代码 a. 获取模型代码 git clone https://github.com/facebookresearch/detectron2 + +cd detectron2/ git reset --hard 13afb03 + +b.安装 cd .. rm -rf detectron2/build/ **/*.so python3.7 -m pip install -e detectron2 + +如果detectron2安装报错,请尝试下面这种方法安装: cd detectron2 +python3.7 setup.py build develop + +c.修改源代码 +若是基准环境中 +cd detectron2/ patch -p1 < ../retinanet_pth.diff cd .. + +若是npu环境中 +cd detectron2/ patch -p1 < ../retinanet_detectron2.diff cd .. + +5.获取权重文件 +wget https://dl.fbaipublicfiles.com/detectron2/COCO-Detection/retinanet_R_50_FPN_3x/190397829/model_final_5bd44e.pkl +将权重文件改名: mv model_final_5bd44e.pkl model_final.pkl + +6.修改pytorch代码去除导出onnx时进行检查 将/usr/local/python3.7.5/lib/python3.7/site-packages/torch/onnx/utils.py文件的_check_onnx_proto(proto)这一行改为pass + +7.获取benchmark工具 将benchmark.x86_64 benchmark.aarch64放在当前目录 + +推理步骤: + +8..修改detectron2/detectron2/data/datasets/builtin.py的258行为_root = os.getenv("DETECTRON2_DATASETS", "/root/datasets/")指定coco数据集所在的目录/root/datasets/ +运行命令,在output文件夹下生成model.onnx文件 + +python3.7 ./detectron2/tools/deploy/export_model.py --config-file ./detectron2/configs/COCO-Detection/retinanet_R_50_FPN_3x.yaml --output ./output --export-method tracing --format onnx MODEL.WEIGHTS model_final.pkl MODEL.DEVICE cpu + + +9.脚本转换om模型 bash test/pth2om.sh + +10.310上执行,执行时确保device空闲: bash test/eval_acc_perf.sh --datasets_path=/root/datasets diff --git a/ACL_PyTorch/contrib/cv/detection/Retinanet/test/parse.py b/ACL_PyTorch/contrib/cv/detection/Retinanet/test/parse.py index b9c74f41d7..82af69cd18 100644 --- a/ACL_PyTorch/contrib/cv/detection/Retinanet/test/parse.py +++ b/ACL_PyTorch/contrib/cv/detection/Retinanet/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/SSD-MobileNetV1/LICENSE b/ACL_PyTorch/contrib/cv/detection/SSD-MobileNetV1/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/detection/SSD-MobileNetV1/LICENSE +++ b/ACL_PyTorch/contrib/cv/detection/SSD-MobileNetV1/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/SSD-MobileNetV1/SSD_MobileNet_pth2onnx.py b/ACL_PyTorch/contrib/cv/detection/SSD-MobileNetV1/SSD_MobileNet_pth2onnx.py index 795bae7b1d..46fafe35d6 100644 --- a/ACL_PyTorch/contrib/cv/detection/SSD-MobileNetV1/SSD_MobileNet_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/detection/SSD-MobileNetV1/SSD_MobileNet_pth2onnx.py @@ -1,46 +1,46 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import torch.onnx -import sys -sys.path.append(r"./pytorch-ssd") -from vision.ssd.mobilenetv1_ssd import create_mobilenetv1_ssd - - -def pth2onx(model_path, out_path): - num_classes = 21 - net = create_mobilenetv1_ssd(num_classes, is_test=True) - print("begin to load model") - net.load(model_path) - net.eval() - - input_names = ["image"] - dynamic_axes = {'image': {0: '-1'}, 'scores':{0: '-1'}, 'boxes': {0: '-1'}} - output_names = ['scores', 'boxes'] - dummy_input = torch.randn(16, 3, 300, 300) - print("begin to export") - torch.onnx.export(net, dummy_input, out_path, input_names=input_names, - dynamic_axes=dynamic_axes, output_names=output_names, opset_version=11, verbose=True) - print("end export") - - -if __name__ == '__main__': - if len(sys.argv) < 2: - print('Usage: python SSD_MobileNet_pth2onnx.py ') - sys.exit(0) - - model_path = sys.argv[1] - out_path = sys.argv[2] - pth2onx(model_path, out_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import torch.onnx +import sys +sys.path.append(r"./pytorch-ssd") +from vision.ssd.mobilenetv1_ssd import create_mobilenetv1_ssd + + +def pth2onx(model_path, out_path): + num_classes = 21 + net = create_mobilenetv1_ssd(num_classes, is_test=True) + print("begin to load model") + net.load(model_path) + net.eval() + + input_names = ["image"] + dynamic_axes = {'image': {0: '-1'}, 'scores':{0: '-1'}, 'boxes': {0: '-1'}} + output_names = ['scores', 'boxes'] + dummy_input = torch.randn(16, 3, 300, 300) + print("begin to export") + torch.onnx.export(net, dummy_input, out_path, input_names=input_names, + dynamic_axes=dynamic_axes, output_names=output_names, opset_version=11, verbose=True) + print("end export") + + +if __name__ == '__main__': + if len(sys.argv) < 2: + print('Usage: python SSD_MobileNet_pth2onnx.py ') + sys.exit(0) + + model_path = sys.argv[1] + out_path = sys.argv[2] + pth2onx(model_path, out_path) diff --git a/ACL_PyTorch/contrib/cv/detection/SSD-MobileNetV1/get_info.py b/ACL_PyTorch/contrib/cv/detection/SSD-MobileNetV1/get_info.py index 3073a9bd28..000eccd3f3 100644 --- a/ACL_PyTorch/contrib/cv/detection/SSD-MobileNetV1/get_info.py +++ b/ACL_PyTorch/contrib/cv/detection/SSD-MobileNetV1/get_info.py @@ -1,63 +1,63 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join( - [str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len( - sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len( - sys.argv) == 4, 'The number of input parameters must be equal to 3' - get_jpg_info(file_path, info_name) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join( + [str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len( + sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len( + sys.argv) == 4, 'The number of input parameters must be equal to 3' + get_jpg_info(file_path, info_name) diff --git a/ACL_PyTorch/contrib/cv/detection/SSD-Resnet34/README.md b/ACL_PyTorch/contrib/cv/detection/SSD-Resnet34/README.md index 5d1928802d..c4208fe145 100644 --- a/ACL_PyTorch/contrib/cv/detection/SSD-Resnet34/README.md +++ b/ACL_PyTorch/contrib/cv/detection/SSD-Resnet34/README.md @@ -1,450 +1,450 @@ -# SSD-Resnet34模型PyTorch离线推理 - -## 一. 环境准备 - -### 1.通过requirements.txt 安装必要依赖 - -首先要先获取torch-1.5.0+ascend.post3.20210930-cp37-cp37m-linux_x86_64.whl,apex-0.1+ascend.20210930-cp37-cp37m-linux_x86_64.whl和tensor_fused_plugin-0.1+ascend-cp37-cp37m-linux_x86_64.whl这3个文件,获取方法如下: - -获取torch-1.5.0+ascend.post3.20210930-cp37-cp37m-linux_x86_64.whl - -x86架构: - -``` -wget https://ascend-pytorch-release.obs.cn-north-4.myhuaweicloud.com/run_pkg/20211018_FrameworkPTAdapter2.0.T308/torch-1.5.0%2Bascend.post3.20210930-cp37-cp37m-linux_x86_64.whl -``` - -ARM架构: - -``` -wget https://ascend-pytorch-release.obs.cn-north-4.myhuaweicloud.com/run_pkg/20211018_FrameworkPTAdapter2.0.T308/torch-1.5.0%2Bascend.post3.20210930-cp37-cp37m-linux_aarch64.whl -``` - -获取tensor_fused_plugin-0.1+ascend-cp37-cp37m-linux_x86_64.whl - -x86架构: - -``` -wget https://ascend-pytorch-release.obs.cn-north-4.myhuaweicloud.com/run_pkg/20210423_TR5/whl_0423/tensor_fused_plugin-0.1%2Bascend-cp37-cp37m-linux_x86_64.whl -``` - -ARM架构: - -``` -wget https://ascend-pytorch-release.obs.cn-north-4.myhuaweicloud.com/run_pkg/20211018_FrameworkPTAdapter2.0.T308/torch-1.5.0%2Bascend.post3.20210930-cp37-cp37m-linux_aarch64.whl -``` - -获取apex-0.1+ascend.20210930-cp37-cp37m-linux_x86_64.whl - -x86架构: - -``` -wget https://ascend-pytorch-release.obs.cn-north-4.myhuaweicloud.com/run_pkg/20211018_FrameworkPTAdapter2.0.T308/apex-0.1%2Bascend.20210930-cp37-cp37m-linux_x86_64.whl -``` - -ARM架构: - -``` -wget https://ascend-pytorch-release.obs.cn-north-4.myhuaweicloud.com/run_pkg/20211018_FrameworkPTAdapter2.0.T308/apex-0.1%2Bascend.20210930-cp37-cp37m-linux_aarch64.whl -``` - -在获得这3个.whl文件之后就使用命令直接运行: - -x86架构: - -``` -pip install torch-1.5.0+ascend.post3.20210930-cp37-cp37m-linux_x86_64.whl -pip install apex-0.1+ascend.20210930-cp37-cp37m-linux_x86_64.whl -pip install tensor_fused_plugin-0.1+ascend-cp37-cp37m-linux_x86_64.whl -``` - -ARM架构: - -``` -pip install torch-1.5.0+ascend.post3.20210930-cp37-cp37m-linux_aarch64.whl -pip install apex-0.1+ascend.20210930-cp37-cp37m-linux_aarch64.whl -pip install tensor_fused_plugin-0.1+ascend-cp37-cp37m-linux_aarch64.whl -``` - -在运行上面的这条命令时,确保torch,apex和tensor_fused_plugin这3个.whl文件和requirements.txt在同一个目录下。 - -之后运行如下指令: - -``` -pip install -r requirements.txt -``` - -在运行完这条命令后,如果error中出现te0.4.0和schedule-search0.0.1相关信息,不需要去看,因为运行这个代码不需要用到,与本代码无关。 - -``` -pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python -apt update -apt install libgl1-mesa-glx -``` - -之后再运行如上3条命令,本代码所需环境即安装完毕。 - -### 2. 获取开源模型代码及开源权重 - -加载开源仓库: - -``` -git clone https://github.com/mlcommons/training_results_v0.7.git -``` - -进入开源代码仓,并打补丁,打补丁时确保补丁在开源代码仓路径的上一级: - -``` -cd training_results_v0.7/NVIDIA/benchmarks/ssd/implementations/pytorch/ -patch -p1 <../ssd.patch -``` - -下载训练后的SSD权重文件: - -``` -wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/detection/SSD-Resnet34/iter_183250.pt -``` - -下载基于搭建SSD模型的Resnet34模型的权重文件 - -``` -wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/detection/SSD-Resnet34/resnet34-333f7ec4.pth -``` - -对于pth权重文件,统一放在新建models文件夹下。 - -``` -├── models -│ ├── iter_183250.pt -│ ├── resnet34-333f7ec4.pth -``` - -### 3. 获取测试数据集 - -本模型支持coco2017的val2017验证数据集,里面有5000张图片。用户可自行获取coco2017数据集中的annotations和val2017,上传数据集到服务器任意目录并解压(如:/home/HwHiAiUser/dataset),本模型将使用到coco2017数据集中的验证集及其标签文件instances_val2017.json, bbox_only_instances_val2017.json,标签文件bbox_only_instances_val2017.json是将coco2017中的原标签文件instances_val2017.json经过处理所得。 - -获得coco数据集的命令如下: - -``` -wget https://ascend-pytorch-one-datasets.obs.cn-north-4.myhuaweicloud.com/infer/zip/coco_2017_ssd_infer.zip -``` - -在本代码中我统一使用了coco这个名字来命名数据: - -``` -mv coco_2017_ssd_infer coco -``` - -获得新json标签文件的命令如下: - -先给prepare-json.py增加权限,不然会出现权限不够的问题: - -``` -chmod -R 777 prepare-json.py -``` - -等增加完权限后再运行: - -``` -python3.7 prepare-json.py --keep-keys ${data_path}/coco/annotations/instances_val2017.json ${data_path}/coco/annotations/bbox_only_instances_val2017.json -``` - -第1部分${data_path}/coco/annotations/instances_val2017.json:这个是输入的json文件路径 - -第2部分${data_path}/coco/annotations/bbox_only_instances_val2017.json:这个是经过处理后输出的json文件路径。新的json文件命名一定要是bbox_only_instances_val2017.json,因为在代码中定义了运行json文件的名字。 - -${data_path}:代表数据集coco2017的路径 - -需要准备好的数据集部分: - -``` -├── coco -│ ├── val2017 -│ ├── annotations -│ ├──instances_val2017.json -│ ├──bbox_only_instances_val2017.json -``` - -## 二. 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 - -执行代码脚本请在本工程代码文件夹下运行。 - -执行如下脚本生成om模型 - -1-25行是pth2onnx - -29-43行是onnx2om - -``` -bash test/ssd_pth2om.sh -``` - -执行如下脚本进行数据预处理和后处理测试精度 - -``` -bash test/ssd_eval_acc_perf.sh --data_path=/home/yzc -``` - ---data_path:coco2017数据集的路径 - -1-16行是加载数据集路径部分 - -19行是解决mlperf_logging包的调用问题 - -23-30行是处理json文件部分 - -32-40行是数据预处理部分 - -42-48行是生成info文件 - -50-67行是使用benchmark进行离线推理的部分 - -70-84行是数据后处理评估精度部分 - -请用户在运行代码前,必须要先激活环境变量才能运行代码: - -``` -source env.sh -``` - -如果在运行代码的过程中,出现缺少.so库的问题,则需要再运行一遍上面输入的命令,再激活一次环境变量,即可解决问题。 - -另外,如果在运行过程中出现报出没有torchvision的错误,但实际已安装,请用户使用which python或者which python版本,查看python的路径是否在当前环境的路径下,请使用在当前环境路径下的相应python即可。 - -### 1.导出.onnx文件 - -− 使用iter_183250.pt导出onnx文件。 - -− 运行ssd_pth2onnx.sh可直接从pth转至om模型 - -运行ssd_pth2onnx.py脚本。 - -生成batchsize=1的onnx模型: - -``` -python3.7 ssd_pth2onnx.py --bs=1 --resnet34-model=./models/resnet34-333f7ec4.pth --pth-path=./models/iter_183250.pt --onnx-path=./ssd_bs1.onnx -``` - -生成batchsize=16的onnx模型: - -``` -python ssd_pth2onnx.py --bs=16 --resnet34-model=./models/resnet34-333f7ec4.pth --pth-path=./models/iter_183250.pt --onnx-path=./ssd_bs16.onnx -``` - ---bs:输入的batch_size大小 - ---resnet34-model:resnet34模型的pth权重文件路径 - ---pth-path:输入SSD模型的pth权重文件路径 - ---onnx-path:输出的onnx模型文件路径及onnx模型名字 - -执行上述步骤后,获得的输出有: - -``` -├── ssd_bs1.onnx -├── ssd_bs16.onnx -``` - -### 2.转om模型 - -设置环境变量 - -``` -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp -export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest -``` - -生成batchsize为1的om模型的命令如下。 - -``` -atc --framework=5 --model=./ssd_bs1.onnx --output=./ssd_bs1 --input_format=NCHW --input_shape="image:1,3,300,300" --log=error --soc_version=Ascend310 -``` - -生成batchsize为16的om模型的命令如下。 - -``` -atc --framework=5 --model=./ssd_bs16.onnx --output=./ssd_bs16 --input_format=NCHW --input_shape="image:16,3,300,300" --log=error --soc_version=Ascend310 -``` - ---framework:5代表ONNX模型。 - ---model:为ONNX模型文件输入的路径。 - ---output:输出的OM模型的路径。 - ---input_format:输入数据的格式。 - ---input_shape:输入数据的shape。 - ---log:日志级别。 - ---soc_version:处理器型号。 - -执行上述步骤后,获得的输出为: - -``` -├── ssd_bs1.om -├── ssd_bs16.om -``` - -### 3.数据预处理。 - -将原始数据集转换为模型输入的二进制数据。 - -在进行数据预处理时,虽然coco2017的val2017验证集有5000张图片,但是实际上输出的只有4952张图片,因为在这过程中代码会剔除其中的48张图片。这一点请用户注意。 - -在数据预处理之前先要声明mlperf_logging包的调用问题: - -``` -PYTHONPATH=../../../../../SIAT/benchmarks/resnet/implementations/tensorflow_open_src:$PYTHONPATH -``` - -具体命令讲解: - -``` -python3.7 ssd_preprocess.py --data=${data_path}/coco --bin-output=./ssd_bin -``` - ---data:coco2017数据集的路径 - ---bin-output:经过预处理得到的bin文件路径 - -${data_path}:coco2017数据集的路径 - -执行上述步骤后,获得的输出为: - -``` -├── ssd_bin -│ ├── tensor([139]).bin -│ ├── ... -│ ├── tensor([581781]).bin -``` - -### 4.生成数据集info文件 - -使用benchmark推理需要输入二进制数据集的info文件,用于获取数据集。使用get_info.py脚本,输入已经得到的二进制文件,输出生成二进制数据集的info文件。 - -具体命令讲解: - -``` -python3.7 get_info.py bin ./ssd_bin ssd.info 300 300 -``` - -第一个参数为生成的数据集文件格式, - -第二个参数为预处理后的数据文件相对路径, - -第三个参数为生成的数据集文件名, - -第四个和第五个参数分别为模型输入的宽度和高度。 - -执行上述步骤后,获得的输出为: - -``` -├── ssd.info -``` - -### 5.使用Benchmark工具进行推理 - -Benchmark模型推理工具,其输入是om模型以及模型所需要的输入bin文件,其输出是模型根据相应输入产生的输出文件。 - -先后步骤顺序为: - -− 增加执行权限 - -``` -chmod u+x benchmark.x86_64 -``` - -− 由对batchsize=1的om模型进行benchmark推理: - -``` -./benchmark.x86_64 -model_type=vision -batch_size=1 -device_id=0 -input_text_path=./ssd.info -input_width=300 -input_height=300 -useDvpp=False -output_binary=true -om_path=./ssd_bs1.om -``` - -− 由对batchsize=16的om模型进行benchmark推理: - -``` -./benchmark.x86_64 -model_type=vision -batch_size=16 -device_id=1 -input_text_path=./ssd.info -input_width=300 -input_height=300 -useDvpp=False -output_binary=true -om_path=./ssd_bs16.om -``` - --model_type:为benchmark支持的模型类型,目前支持的有vision,nmt,widedeep,nlp,yolocaffe,bert,deepfm。ssd模型属于vision,所以选vision。 - --batch_size:om模型的batch大小,该值应与om模型的batch大小相同,否则报输入大小不一致的错误。 - --device_id:指运行在ascend 310的哪个device上,每张ascend 310卡有4个device。 - -input_text_path:包含数据集每个样本的路径与其相关信息的数据集信息文件路径。即之前生成的info文件路径。 - --input_width:输入宽度 - --input_height:输入高度 - --useDvpp:为是否使用aipp进行数据集预处理,我这里不用 - --output_binary:以预处理后的数据集为输入,benchmark工具推理om模型的输出数据保存为二进制还是txt。true为生成二进制bin文件,false为生成txt文件。 - --om_path:om模型文件路径。 - -执行./benchmark.x86_64工具请选择与运行环境架构相同的命令。参数详情请参见《 CANN 推理benchmark工具用户指南 》。 推理后的输出默认在当前目录result下。 - -batchsize=1的om模型进行benchmark推理得到的bin文件输出结果默认保存在当前目录result/dumpOutput_device0;性能数据默认保存在result/ perf_vision_batchsize_1_device_0.txt。 - -batchsize=16的om模型进行benchmark推理得到的bin文件输出结果默认保存在当前目录result/dumpOutput_device1;性能数据默认保存在result/ perf_vision_batchsize_16_device_1.txt。 - -该模型一个输入会对应两个输出,_1代表ploc的输出,_2代表plabel的输出。 - -执行以上命令后的输出: - -``` -├── result -│ ├── dumpOutput_device0 -│ │ ├── tensor([139])_1.bin -│ │ ├── tensor([139])_2.bin -│ │ ├── …… -│ ├── dumpOutput_device1 -│ │ ├── tensor([139])_1.bin -│ │ ├── tensor([139])_2.bin -│ │ ├── …… -│ ├── perf_vision_batchsize_1_device_0.txt -│ ├── perf_vision_batchsize_16_device_1.txt -``` - -### 6.数据后处理 - -进行数据后处理时,也是需要调用同数据预处理一样的mlperf_logging包。因为在前面进行数据预处理时已经声明过了,所以可以不需要再进行声明了。 - -调用ssd_postprocess.py评测模型的精度: - -batchsize=1的测试: - -``` -python ssd_postprocess.py --data=${data_path}/coco --bin-input=./result/dumpOutput_device0 -``` - -batchsize=16的测试: - -``` -python ssd_postprocess.py --data=${data_path}/coco --bin-input=./result/dumpOutput_device1 -``` - ---data:coco2017数据集的路径 - ---bin-input:数据预处理得到的bin文件。 - -${data_path}:coco2017数据集的路径 - -### 7.评测结果: - -| 模型 | 官网pth精度 | 310离线推理精度 | 性能基准 | 310性能 | -| ----------------- | ----------- | --------------- | ---------- | ---------- | -| SSD-Resnet34 bs1 | 23.000% | 23.030% | 482.627fps | 634.576fps | -| SSD-Resnet34 bs16 | 23.000% | 23.030% | 774.477fps | 863.748fps | - +# SSD-Resnet34模型PyTorch离线推理 + +## 一. 环境准备 + +### 1.通过requirements.txt 安装必要依赖 + +首先要先获取torch-1.5.0+ascend.post3.20210930-cp37-cp37m-linux_x86_64.whl,apex-0.1+ascend.20210930-cp37-cp37m-linux_x86_64.whl和tensor_fused_plugin-0.1+ascend-cp37-cp37m-linux_x86_64.whl这3个文件,获取方法如下: + +获取torch-1.5.0+ascend.post3.20210930-cp37-cp37m-linux_x86_64.whl + +x86架构: + +``` +wget https://ascend-pytorch-release.obs.cn-north-4.myhuaweicloud.com/run_pkg/20211018_FrameworkPTAdapter2.0.T308/torch-1.5.0%2Bascend.post3.20210930-cp37-cp37m-linux_x86_64.whl +``` + +ARM架构: + +``` +wget https://ascend-pytorch-release.obs.cn-north-4.myhuaweicloud.com/run_pkg/20211018_FrameworkPTAdapter2.0.T308/torch-1.5.0%2Bascend.post3.20210930-cp37-cp37m-linux_aarch64.whl +``` + +获取tensor_fused_plugin-0.1+ascend-cp37-cp37m-linux_x86_64.whl + +x86架构: + +``` +wget https://ascend-pytorch-release.obs.cn-north-4.myhuaweicloud.com/run_pkg/20210423_TR5/whl_0423/tensor_fused_plugin-0.1%2Bascend-cp37-cp37m-linux_x86_64.whl +``` + +ARM架构: + +``` +wget https://ascend-pytorch-release.obs.cn-north-4.myhuaweicloud.com/run_pkg/20211018_FrameworkPTAdapter2.0.T308/torch-1.5.0%2Bascend.post3.20210930-cp37-cp37m-linux_aarch64.whl +``` + +获取apex-0.1+ascend.20210930-cp37-cp37m-linux_x86_64.whl + +x86架构: + +``` +wget https://ascend-pytorch-release.obs.cn-north-4.myhuaweicloud.com/run_pkg/20211018_FrameworkPTAdapter2.0.T308/apex-0.1%2Bascend.20210930-cp37-cp37m-linux_x86_64.whl +``` + +ARM架构: + +``` +wget https://ascend-pytorch-release.obs.cn-north-4.myhuaweicloud.com/run_pkg/20211018_FrameworkPTAdapter2.0.T308/apex-0.1%2Bascend.20210930-cp37-cp37m-linux_aarch64.whl +``` + +在获得这3个.whl文件之后就使用命令直接运行: + +x86架构: + +``` +pip install torch-1.5.0+ascend.post3.20210930-cp37-cp37m-linux_x86_64.whl +pip install apex-0.1+ascend.20210930-cp37-cp37m-linux_x86_64.whl +pip install tensor_fused_plugin-0.1+ascend-cp37-cp37m-linux_x86_64.whl +``` + +ARM架构: + +``` +pip install torch-1.5.0+ascend.post3.20210930-cp37-cp37m-linux_aarch64.whl +pip install apex-0.1+ascend.20210930-cp37-cp37m-linux_aarch64.whl +pip install tensor_fused_plugin-0.1+ascend-cp37-cp37m-linux_aarch64.whl +``` + +在运行上面的这条命令时,确保torch,apex和tensor_fused_plugin这3个.whl文件和requirements.txt在同一个目录下。 + +之后运行如下指令: + +``` +pip install -r requirements.txt +``` + +在运行完这条命令后,如果error中出现te0.4.0和schedule-search0.0.1相关信息,不需要去看,因为运行这个代码不需要用到,与本代码无关。 + +``` +pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python +apt update +apt install libgl1-mesa-glx +``` + +之后再运行如上3条命令,本代码所需环境即安装完毕。 + +### 2. 获取开源模型代码及开源权重 + +加载开源仓库: + +``` +git clone https://github.com/mlcommons/training_results_v0.7.git +``` + +进入开源代码仓,并打补丁,打补丁时确保补丁在开源代码仓路径的上一级: + +``` +cd training_results_v0.7/NVIDIA/benchmarks/ssd/implementations/pytorch/ +patch -p1 <../ssd.patch +``` + +下载训练后的SSD权重文件: + +``` +wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/detection/SSD-Resnet34/iter_183250.pt +``` + +下载基于搭建SSD模型的Resnet34模型的权重文件 + +``` +wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/detection/SSD-Resnet34/resnet34-333f7ec4.pth +``` + +对于pth权重文件,统一放在新建models文件夹下。 + +``` +├── models +│ ├── iter_183250.pt +│ ├── resnet34-333f7ec4.pth +``` + +### 3. 获取测试数据集 + +本模型支持coco2017的val2017验证数据集,里面有5000张图片。用户可自行获取coco2017数据集中的annotations和val2017,上传数据集到服务器任意目录并解压(如:/home/HwHiAiUser/dataset),本模型将使用到coco2017数据集中的验证集及其标签文件instances_val2017.json, bbox_only_instances_val2017.json,标签文件bbox_only_instances_val2017.json是将coco2017中的原标签文件instances_val2017.json经过处理所得。 + +获得coco数据集的命令如下: + +``` +wget https://ascend-pytorch-one-datasets.obs.cn-north-4.myhuaweicloud.com/infer/zip/coco_2017_ssd_infer.zip +``` + +在本代码中我统一使用了coco这个名字来命名数据: + +``` +mv coco_2017_ssd_infer coco +``` + +获得新json标签文件的命令如下: + +先给prepare-json.py增加权限,不然会出现权限不够的问题: + +``` +chmod -R 777 prepare-json.py +``` + +等增加完权限后再运行: + +``` +python3.7 prepare-json.py --keep-keys ${data_path}/coco/annotations/instances_val2017.json ${data_path}/coco/annotations/bbox_only_instances_val2017.json +``` + +第1部分${data_path}/coco/annotations/instances_val2017.json:这个是输入的json文件路径 + +第2部分${data_path}/coco/annotations/bbox_only_instances_val2017.json:这个是经过处理后输出的json文件路径。新的json文件命名一定要是bbox_only_instances_val2017.json,因为在代码中定义了运行json文件的名字。 + +${data_path}:代表数据集coco2017的路径 + +需要准备好的数据集部分: + +``` +├── coco +│ ├── val2017 +│ ├── annotations +│ ├──instances_val2017.json +│ ├──bbox_only_instances_val2017.json +``` + +## 二. 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 + +执行代码脚本请在本工程代码文件夹下运行。 + +执行如下脚本生成om模型 + +1-25行是pth2onnx + +29-43行是onnx2om + +``` +bash test/ssd_pth2om.sh +``` + +执行如下脚本进行数据预处理和后处理测试精度 + +``` +bash test/ssd_eval_acc_perf.sh --data_path=/home/yzc +``` + +--data_path:coco2017数据集的路径 + +1-16行是加载数据集路径部分 + +19行是解决mlperf_logging包的调用问题 + +23-30行是处理json文件部分 + +32-40行是数据预处理部分 + +42-48行是生成info文件 + +50-67行是使用benchmark进行离线推理的部分 + +70-84行是数据后处理评估精度部分 + +请用户在运行代码前,必须要先激活环境变量才能运行代码: + +``` +source env.sh +``` + +如果在运行代码的过程中,出现缺少.so库的问题,则需要再运行一遍上面输入的命令,再激活一次环境变量,即可解决问题。 + +另外,如果在运行过程中出现报出没有torchvision的错误,但实际已安装,请用户使用which python或者which python版本,查看python的路径是否在当前环境的路径下,请使用在当前环境路径下的相应python即可。 + +### 1.导出.onnx文件 + +− 使用iter_183250.pt导出onnx文件。 + +− 运行ssd_pth2onnx.sh可直接从pth转至om模型 + +运行ssd_pth2onnx.py脚本。 + +生成batchsize=1的onnx模型: + +``` +python3.7 ssd_pth2onnx.py --bs=1 --resnet34-model=./models/resnet34-333f7ec4.pth --pth-path=./models/iter_183250.pt --onnx-path=./ssd_bs1.onnx +``` + +生成batchsize=16的onnx模型: + +``` +python ssd_pth2onnx.py --bs=16 --resnet34-model=./models/resnet34-333f7ec4.pth --pth-path=./models/iter_183250.pt --onnx-path=./ssd_bs16.onnx +``` + +--bs:输入的batch_size大小 + +--resnet34-model:resnet34模型的pth权重文件路径 + +--pth-path:输入SSD模型的pth权重文件路径 + +--onnx-path:输出的onnx模型文件路径及onnx模型名字 + +执行上述步骤后,获得的输出有: + +``` +├── ssd_bs1.onnx +├── ssd_bs16.onnx +``` + +### 2.转om模型 + +设置环境变量 + +``` +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp +export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest +``` + +生成batchsize为1的om模型的命令如下。 + +``` +atc --framework=5 --model=./ssd_bs1.onnx --output=./ssd_bs1 --input_format=NCHW --input_shape="image:1,3,300,300" --log=error --soc_version=Ascend310 +``` + +生成batchsize为16的om模型的命令如下。 + +``` +atc --framework=5 --model=./ssd_bs16.onnx --output=./ssd_bs16 --input_format=NCHW --input_shape="image:16,3,300,300" --log=error --soc_version=Ascend310 +``` + +--framework:5代表ONNX模型。 + +--model:为ONNX模型文件输入的路径。 + +--output:输出的OM模型的路径。 + +--input_format:输入数据的格式。 + +--input_shape:输入数据的shape。 + +--log:日志级别。 + +--soc_version:处理器型号。 + +执行上述步骤后,获得的输出为: + +``` +├── ssd_bs1.om +├── ssd_bs16.om +``` + +### 3.数据预处理。 + +将原始数据集转换为模型输入的二进制数据。 + +在进行数据预处理时,虽然coco2017的val2017验证集有5000张图片,但是实际上输出的只有4952张图片,因为在这过程中代码会剔除其中的48张图片。这一点请用户注意。 + +在数据预处理之前先要声明mlperf_logging包的调用问题: + +``` +PYTHONPATH=../../../../../SIAT/benchmarks/resnet/implementations/tensorflow_open_src:$PYTHONPATH +``` + +具体命令讲解: + +``` +python3.7 ssd_preprocess.py --data=${data_path}/coco --bin-output=./ssd_bin +``` + +--data:coco2017数据集的路径 + +--bin-output:经过预处理得到的bin文件路径 + +${data_path}:coco2017数据集的路径 + +执行上述步骤后,获得的输出为: + +``` +├── ssd_bin +│ ├── tensor([139]).bin +│ ├── ... +│ ├── tensor([581781]).bin +``` + +### 4.生成数据集info文件 + +使用benchmark推理需要输入二进制数据集的info文件,用于获取数据集。使用get_info.py脚本,输入已经得到的二进制文件,输出生成二进制数据集的info文件。 + +具体命令讲解: + +``` +python3.7 get_info.py bin ./ssd_bin ssd.info 300 300 +``` + +第一个参数为生成的数据集文件格式, + +第二个参数为预处理后的数据文件相对路径, + +第三个参数为生成的数据集文件名, + +第四个和第五个参数分别为模型输入的宽度和高度。 + +执行上述步骤后,获得的输出为: + +``` +├── ssd.info +``` + +### 5.使用Benchmark工具进行推理 + +Benchmark模型推理工具,其输入是om模型以及模型所需要的输入bin文件,其输出是模型根据相应输入产生的输出文件。 + +先后步骤顺序为: + +− 增加执行权限 + +``` +chmod u+x benchmark.x86_64 +``` + +− 由对batchsize=1的om模型进行benchmark推理: + +``` +./benchmark.x86_64 -model_type=vision -batch_size=1 -device_id=0 -input_text_path=./ssd.info -input_width=300 -input_height=300 -useDvpp=False -output_binary=true -om_path=./ssd_bs1.om +``` + +− 由对batchsize=16的om模型进行benchmark推理: + +``` +./benchmark.x86_64 -model_type=vision -batch_size=16 -device_id=1 -input_text_path=./ssd.info -input_width=300 -input_height=300 -useDvpp=False -output_binary=true -om_path=./ssd_bs16.om +``` + +-model_type:为benchmark支持的模型类型,目前支持的有vision,nmt,widedeep,nlp,yolocaffe,bert,deepfm。ssd模型属于vision,所以选vision。 + +-batch_size:om模型的batch大小,该值应与om模型的batch大小相同,否则报输入大小不一致的错误。 + +-device_id:指运行在ascend 310的哪个device上,每张ascend 310卡有4个device。 + +input_text_path:包含数据集每个样本的路径与其相关信息的数据集信息文件路径。即之前生成的info文件路径。 + +-input_width:输入宽度 + +-input_height:输入高度 + +-useDvpp:为是否使用aipp进行数据集预处理,我这里不用 + +-output_binary:以预处理后的数据集为输入,benchmark工具推理om模型的输出数据保存为二进制还是txt。true为生成二进制bin文件,false为生成txt文件。 + +-om_path:om模型文件路径。 + +执行./benchmark.x86_64工具请选择与运行环境架构相同的命令。参数详情请参见《 CANN 推理benchmark工具用户指南 》。 推理后的输出默认在当前目录result下。 + +batchsize=1的om模型进行benchmark推理得到的bin文件输出结果默认保存在当前目录result/dumpOutput_device0;性能数据默认保存在result/ perf_vision_batchsize_1_device_0.txt。 + +batchsize=16的om模型进行benchmark推理得到的bin文件输出结果默认保存在当前目录result/dumpOutput_device1;性能数据默认保存在result/ perf_vision_batchsize_16_device_1.txt。 + +该模型一个输入会对应两个输出,_1代表ploc的输出,_2代表plabel的输出。 + +执行以上命令后的输出: + +``` +├── result +│ ├── dumpOutput_device0 +│ │ ├── tensor([139])_1.bin +│ │ ├── tensor([139])_2.bin +│ │ ├── …… +│ ├── dumpOutput_device1 +│ │ ├── tensor([139])_1.bin +│ │ ├── tensor([139])_2.bin +│ │ ├── …… +│ ├── perf_vision_batchsize_1_device_0.txt +│ ├── perf_vision_batchsize_16_device_1.txt +``` + +### 6.数据后处理 + +进行数据后处理时,也是需要调用同数据预处理一样的mlperf_logging包。因为在前面进行数据预处理时已经声明过了,所以可以不需要再进行声明了。 + +调用ssd_postprocess.py评测模型的精度: + +batchsize=1的测试: + +``` +python ssd_postprocess.py --data=${data_path}/coco --bin-input=./result/dumpOutput_device0 +``` + +batchsize=16的测试: + +``` +python ssd_postprocess.py --data=${data_path}/coco --bin-input=./result/dumpOutput_device1 +``` + +--data:coco2017数据集的路径 + +--bin-input:数据预处理得到的bin文件。 + +${data_path}:coco2017数据集的路径 + +### 7.评测结果: + +| 模型 | 官网pth精度 | 310离线推理精度 | 性能基准 | 310性能 | +| ----------------- | ----------- | --------------- | ---------- | ---------- | +| SSD-Resnet34 bs1 | 23.000% | 23.030% | 482.627fps | 634.576fps | +| SSD-Resnet34 bs16 | 23.000% | 23.030% | 774.477fps | 863.748fps | + diff --git a/ACL_PyTorch/contrib/cv/detection/SSD-Resnet34/ssd_pth2onnx.py b/ACL_PyTorch/contrib/cv/detection/SSD-Resnet34/ssd_pth2onnx.py index 7687bb7b0a..9a88aff930 100644 --- a/ACL_PyTorch/contrib/cv/detection/SSD-Resnet34/ssd_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/detection/SSD-Resnet34/ssd_pth2onnx.py @@ -1,46 +1,46 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import os -from ssd300 import SSD300 -import random -from argparse import ArgumentParser -from parse_config import parse_args - -def pth2onnx(batch_size,input_file, output_file): - model_options = { - 'use_nhwc' : False, - 'pad_input' : False, - 'bn_group' : 1, - } - ssd300_eval = SSD300(args, 81, **model_options) - - state_dict = torch.load(input_file, map_location="cpu") - ssd300_eval.load_state_dict(state_dict['model']) - - ssd300_eval.eval() - input_names = ["image"] - output_names=["ploc","plabel"] - dynamic_axes = {'image': {0: '-1'}, 'ploc': {0: '-1'}, 'plabel': {0: '-1'}} - dummy_input = torch.randn(batch_size, 3, 300, 300) - torch.onnx.export(ssd300_eval, dummy_input, output_file, input_names=input_names, dynamic_axes=dynamic_axes, - output_names=output_names, opset_version=11, verbose=False) - -if __name__ == "__main__": - args = parse_args() - batch_size=args.bs - input_file = args.pth_path - output_file = args.onnx_path - resnet_model=args.resnet34_model - pth2onnx(batch_size,input_file, output_file) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import os +from ssd300 import SSD300 +import random +from argparse import ArgumentParser +from parse_config import parse_args + +def pth2onnx(batch_size,input_file, output_file): + model_options = { + 'use_nhwc' : False, + 'pad_input' : False, + 'bn_group' : 1, + } + ssd300_eval = SSD300(args, 81, **model_options) + + state_dict = torch.load(input_file, map_location="cpu") + ssd300_eval.load_state_dict(state_dict['model']) + + ssd300_eval.eval() + input_names = ["image"] + output_names=["ploc","plabel"] + dynamic_axes = {'image': {0: '-1'}, 'ploc': {0: '-1'}, 'plabel': {0: '-1'}} + dummy_input = torch.randn(batch_size, 3, 300, 300) + torch.onnx.export(ssd300_eval, dummy_input, output_file, input_names=input_names, dynamic_axes=dynamic_axes, + output_names=output_names, opset_version=11, verbose=False) + +if __name__ == "__main__": + args = parse_args() + batch_size=args.bs + input_file = args.pth_path + output_file = args.onnx_path + resnet_model=args.resnet34_model + pth2onnx(batch_size,input_file, output_file) diff --git a/ACL_PyTorch/contrib/cv/detection/YOLOX-mmdetection/YOLOX_postprocess.py b/ACL_PyTorch/contrib/cv/detection/YOLOX-mmdetection/YOLOX_postprocess.py index 29003ed851..a1a777ec04 100644 --- a/ACL_PyTorch/contrib/cv/detection/YOLOX-mmdetection/YOLOX_postprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/YOLOX-mmdetection/YOLOX_postprocess.py @@ -1,54 +1,54 @@ -# Copyright 2022 Huawei Technologies Co., Ltd -# -# 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 mmcv -import numpy as np -import argparse -from mmdet.core import bbox2result -from mmdet.datasets import build_dataset - -ann_file = '/annotations/instances_val2017.json' -img_prefix = '/val2017/' - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--dataset_path', default="/opt/npu/coco") - parser.add_argument('--model_config', default="mmdetection/configs/yolox/yolox_s_8x8_300e_coco.py") - parser.add_argument('--bin_data_path', default="result/dumpOutput_device0/") - parser.add_argument('--meta_info_path', default="yolox_meta.info") - parser.add_argument('--num_classes', default=81) - - args = parser.parse_args() - - cfg = mmcv.Config.fromfile(args.model_config) - cfg.data.test.test_mode = True - cfg.data.test.ann_file = args.dataset_path + ann_file - cfg.data.test.img_prefix = args.dataset_path + img_prefix - dataset = build_dataset(cfg.data.test) - - num_classes = int(args.num_classes) - outputs = [] - with open(args.meta_info_path, "r") as fp: - for line in fp: - _, file_path, scalar = line.split() - scalar = float(scalar) - file_name = file_path.split("/")[1].replace(".bin", "") - result_list = [ - np.fromfile("{0}{1}_{2}.bin".format(args.bin_data_path, file_name, 1), dtype=np.float32).reshape(-1, 5), - np.fromfile("{0}{1}_{2}.bin".format(args.bin_data_path, file_name, 2), dtype=np.int64)] - result_list[0][..., :4] /= scalar - bbox_result = bbox2result(result_list[0], result_list[1], num_classes) - outputs.append(bbox_result) - eval_kwargs = {'metric': ['bbox']} - dataset.evaluate(outputs, **eval_kwargs) +# Copyright 2022 Huawei Technologies Co., Ltd +# +# 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 mmcv +import numpy as np +import argparse +from mmdet.core import bbox2result +from mmdet.datasets import build_dataset + +ann_file = '/annotations/instances_val2017.json' +img_prefix = '/val2017/' + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--dataset_path', default="/opt/npu/coco") + parser.add_argument('--model_config', default="mmdetection/configs/yolox/yolox_s_8x8_300e_coco.py") + parser.add_argument('--bin_data_path', default="result/dumpOutput_device0/") + parser.add_argument('--meta_info_path', default="yolox_meta.info") + parser.add_argument('--num_classes', default=81) + + args = parser.parse_args() + + cfg = mmcv.Config.fromfile(args.model_config) + cfg.data.test.test_mode = True + cfg.data.test.ann_file = args.dataset_path + ann_file + cfg.data.test.img_prefix = args.dataset_path + img_prefix + dataset = build_dataset(cfg.data.test) + + num_classes = int(args.num_classes) + outputs = [] + with open(args.meta_info_path, "r") as fp: + for line in fp: + _, file_path, scalar = line.split() + scalar = float(scalar) + file_name = file_path.split("/")[1].replace(".bin", "") + result_list = [ + np.fromfile("{0}{1}_{2}.bin".format(args.bin_data_path, file_name, 1), dtype=np.float32).reshape(-1, 5), + np.fromfile("{0}{1}_{2}.bin".format(args.bin_data_path, file_name, 2), dtype=np.int64)] + result_list[0][..., :4] /= scalar + bbox_result = bbox2result(result_list[0], result_list[1], num_classes) + outputs.append(bbox_result) + eval_kwargs = {'metric': ['bbox']} + dataset.evaluate(outputs, **eval_kwargs) diff --git a/ACL_PyTorch/contrib/cv/detection/YOLOX-mmdetection/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/detection/YOLOX-mmdetection/gen_dataset_info.py index dee0075555..877b0a026d 100644 --- a/ACL_PyTorch/contrib/cv/detection/YOLOX-mmdetection/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/detection/YOLOX-mmdetection/gen_dataset_info.py @@ -1,53 +1,53 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import mmcv -from mmdet.datasets import build_dataset -import pickle as pk - -ann_file = '/annotations/instances_val2017.json' -img_prefix = '/val2017/' - -if __name__ == '__main__': - image_src_path = sys.argv[1] - config_path = sys.argv[2] - bin_path = sys.argv[3] - meta_path = sys.argv[4] - info_name = sys.argv[5] - info_meta_name = sys.argv[6] - width = int(sys.argv[7]) - height = int(sys.argv[8]) - - cfg = mmcv.Config.fromfile(config_path) - cfg.data.test.ann_file = image_src_path + ann_file - cfg.data.test.img_prefix = image_src_path + img_prefix - cfg.data.test.test_mode = True - - dataset = build_dataset(cfg.data.test) - - with open(info_name, "w") as fp1, open(info_meta_name, "w") as fp2: - for idx in range(5000): - img_id = dataset.img_ids[idx] - fp1.write("{} {}/{:0>12d}.bin {} {}\n".format(idx, bin_path, img_id, width, height)) - fp_meta = open("%s/%012d.pk" % (meta_path, img_id), "rb") - meta = pk.load(fp_meta) - fp_meta.close() - fp2.write("{} {}/{:0>12d}.bin {}\n".format( - idx, - meta_path, - img_id, - meta['scalar'] - )) - print("Get info done!") +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import mmcv +from mmdet.datasets import build_dataset +import pickle as pk + +ann_file = '/annotations/instances_val2017.json' +img_prefix = '/val2017/' + +if __name__ == '__main__': + image_src_path = sys.argv[1] + config_path = sys.argv[2] + bin_path = sys.argv[3] + meta_path = sys.argv[4] + info_name = sys.argv[5] + info_meta_name = sys.argv[6] + width = int(sys.argv[7]) + height = int(sys.argv[8]) + + cfg = mmcv.Config.fromfile(config_path) + cfg.data.test.ann_file = image_src_path + ann_file + cfg.data.test.img_prefix = image_src_path + img_prefix + cfg.data.test.test_mode = True + + dataset = build_dataset(cfg.data.test) + + with open(info_name, "w") as fp1, open(info_meta_name, "w") as fp2: + for idx in range(5000): + img_id = dataset.img_ids[idx] + fp1.write("{} {}/{:0>12d}.bin {} {}\n".format(idx, bin_path, img_id, width, height)) + fp_meta = open("%s/%012d.pk" % (meta_path, img_id), "rb") + meta = pk.load(fp_meta) + fp_meta.close() + fp2.write("{} {}/{:0>12d}.bin {}\n".format( + idx, + meta_path, + img_id, + meta['scalar'] + )) + print("Get info done!") diff --git a/ACL_PyTorch/contrib/cv/detection/YOLOX-mmdetection/readme.md b/ACL_PyTorch/contrib/cv/detection/YOLOX-mmdetection/readme.md index 645cc073d1..56601531ed 100644 --- a/ACL_PyTorch/contrib/cv/detection/YOLOX-mmdetection/readme.md +++ b/ACL_PyTorch/contrib/cv/detection/YOLOX-mmdetection/readme.md @@ -1,51 +1,51 @@ -### YOLOX模型PyTorch离线推理指导 - -### 1. 环境准备 - -1. 安装依赖 - -```bash -pip install -r requirements.txt -``` - -2. 获取,修改与安装开源模型代码 - -``` -git clone -b master https://github.com/open-mmlab/mmdetection.git -cd mmdetection -git reset 6b87ac22b8d9dea8cc28b9ce84909e6c311e6268 --hard - -pip install -v -e . # or python3 setup.py develop -pip install mmcv-full -f https://download.openmmlab.com/mmcv/dist/cpu/torch1.7.0/index.html -patch -p1 < ../YOLOX.patch -cd .. -``` - -3. 将权重文件[yolox_x_8x8_300e_coco_20211126_140254-1ef88d67.pth](https://download.openmmlab.com/mmdetection/v2.0/yolox/yolox_x_8x8_300e_coco/yolox_x_8x8_300e_coco_20211126_140254-1ef88d67.pth)放到当前工作目录。 - -4. 数据集 - - 获取COCO数据集,并重命名为COCO,放到/root/datasets目录 - -5. [获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) - - 将benchmark.x86_64或benchmark.aarch64放到当前工作目录 - -### 2. 离线推理 - -710上执行,执行时使npu-smi info查看设备状态,确保device空闲 - -```bash -bash test/pth2om.sh --batch_size=1 -bash test/eval_acc_perf.sh --datasets_path=/root/datasets --batch_size=1 -``` - -**评测结果:** - -| 模型 | pth精度 | 710离线推理精度 | 性能基准 | 710性能 | -| ----------- | --------- | --------------- | --------- | ------- | -| YOLOX bs1 | box AP:50.9 | box AP:51.0 | fps 11.828 | fps 27.697 | -| YOLOX bs16 | box AP:50.9 | box AP:51.0 | fps 14.480 | fps 38.069 | - - - +### YOLOX模型PyTorch离线推理指导 + +### 1. 环境准备 + +1. 安装依赖 + +```bash +pip install -r requirements.txt +``` + +2. 获取,修改与安装开源模型代码 + +``` +git clone -b master https://github.com/open-mmlab/mmdetection.git +cd mmdetection +git reset 6b87ac22b8d9dea8cc28b9ce84909e6c311e6268 --hard + +pip install -v -e . # or python3 setup.py develop +pip install mmcv-full -f https://download.openmmlab.com/mmcv/dist/cpu/torch1.7.0/index.html +patch -p1 < ../YOLOX.patch +cd .. +``` + +3. 将权重文件[yolox_x_8x8_300e_coco_20211126_140254-1ef88d67.pth](https://download.openmmlab.com/mmdetection/v2.0/yolox/yolox_x_8x8_300e_coco/yolox_x_8x8_300e_coco_20211126_140254-1ef88d67.pth)放到当前工作目录。 + +4. 数据集 + + 获取COCO数据集,并重命名为COCO,放到/root/datasets目录 + +5. [获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) + + 将benchmark.x86_64或benchmark.aarch64放到当前工作目录 + +### 2. 离线推理 + +710上执行,执行时使npu-smi info查看设备状态,确保device空闲 + +```bash +bash test/pth2om.sh --batch_size=1 +bash test/eval_acc_perf.sh --datasets_path=/root/datasets --batch_size=1 +``` + +**评测结果:** + +| 模型 | pth精度 | 710离线推理精度 | 性能基准 | 710性能 | +| ----------- | --------- | --------------- | --------- | ------- | +| YOLOX bs1 | box AP:50.9 | box AP:51.0 | fps 11.828 | fps 27.697 | +| YOLOX bs16 | box AP:50.9 | box AP:51.0 | fps 14.480 | fps 38.069 | + + + diff --git a/ACL_PyTorch/contrib/cv/detection/YOLOX-mmdetection/requirements.txt b/ACL_PyTorch/contrib/cv/detection/YOLOX-mmdetection/requirements.txt index 417d5e02a3..5b7b027fef 100644 --- a/ACL_PyTorch/contrib/cv/detection/YOLOX-mmdetection/requirements.txt +++ b/ACL_PyTorch/contrib/cv/detection/YOLOX-mmdetection/requirements.txt @@ -1,7 +1,7 @@ -torch==1.7.0 -torchvision==0.8.0 -onnx -opencv-python -sympy -cython +torch==1.7.0 +torchvision==0.8.0 +onnx +opencv-python +sympy +cython numpy \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/YOLOX/Yolox_postprocess.py b/ACL_PyTorch/contrib/cv/detection/YOLOX/Yolox_postprocess.py index 1eef050881..9367f270d3 100644 --- a/ACL_PyTorch/contrib/cv/detection/YOLOX/Yolox_postprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/YOLOX/Yolox_postprocess.py @@ -1,139 +1,139 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 os -import sys -import argparse -from tqdm import tqdm -import torch -import numpy as np -from yolox.data import COCODataset, ValTransform -from yolox.evaluators import COCOEvaluator -from yolox.utils.boxes import postprocess - -from yolox.utils.demo_utils import demo_postprocess -sys.path.append('./YOLOX') - - -def get_output_data(dump_dir, idx, dtype=np.float32): - output_shape_1 = [1, 4, 80, 80] - output_shape_2 = [1, 1, 80, 80] - output_shape_3 = [1, 80, 80, 80] - output_shape_4 = [1, 4, 40, 40] - output_shape_5 = [1, 1, 40, 40] - output_shape_6 = [1, 80, 40, 40] - output_shape_7 = [1, 4, 20, 20] - output_shape_8 = [1, 1, 20, 20] - output_shape_9 = [1, 80, 20, 20] - - input_file_1 = os.path.join(dump_dir, "{:0>12d}_1.bin".format(idx)) - input_file_2 = os.path.join(dump_dir, "{:0>12d}_2.bin".format(idx)) - input_file_3 = os.path.join(dump_dir, "{:0>12d}_3.bin".format(idx)) - input_file_4 = os.path.join(dump_dir, "{:0>12d}_4.bin".format(idx)) - input_file_5 = os.path.join(dump_dir, "{:0>12d}_5.bin".format(idx)) - input_file_6 = os.path.join(dump_dir, "{:0>12d}_6.bin".format(idx)) - input_file_7 = os.path.join(dump_dir, "{:0>12d}_7.bin".format(idx)) - input_file_8 = os.path.join(dump_dir, "{:0>12d}_8.bin".format(idx)) - input_file_9 = os.path.join(dump_dir, "{:0>12d}_9.bin".format(idx)) - - input_data_1 = np.fromfile(input_file_1, dtype=dtype).reshape(output_shape_1) - input_data_2 = np.fromfile(input_file_2, dtype=dtype).reshape(output_shape_2) - input_data_3 = np.fromfile(input_file_3, dtype=dtype).reshape(output_shape_3) - input_data_4 = np.fromfile(input_file_4, dtype=dtype).reshape(output_shape_4) - input_data_5 = np.fromfile(input_file_5, dtype=dtype).reshape(output_shape_5) - input_data_6 = np.fromfile(input_file_6, dtype=dtype).reshape(output_shape_6) - input_data_7 = np.fromfile(input_file_7, dtype=dtype).reshape(output_shape_7) - input_data_8 = np.fromfile(input_file_8, dtype=dtype).reshape(output_shape_8) - input_data_9 = np.fromfile(input_file_9, dtype=dtype).reshape(output_shape_9) - - lst = [] - lst.append(torch.from_numpy(input_data_1)) - lst.append(torch.from_numpy(input_data_2)) - lst.append(torch.from_numpy(input_data_3)) - lst.append(torch.from_numpy(input_data_4)) - lst.append(torch.from_numpy(input_data_5)) - lst.append(torch.from_numpy(input_data_6)) - lst.append(torch.from_numpy(input_data_7)) - lst.append(torch.from_numpy(input_data_8)) - lst.append(torch.from_numpy(input_data_9)) - - return lst - - -def main(): - parser = argparse.ArgumentParser(description='YOLOX Postprocess') - parser.add_argument('--dataroot', dest='dataroot', - help='data root dirname', default='/opt/npu/coco', - type=str) - parser.add_argument('--dump_dir', dest='dump_dir', - help='dump dir for bin files', default='./result/dumpOutput_device0/', - type=str) - - parser.add_argument('--batch', dest='batch', help='batch for dataloader', default=1, type=int) - opt = parser.parse_args() - - if os.path.exists(opt.dump_dir): - os.system("rm-rf " + opt.dump_dir) - else: - os.system("mkdir " + opt.dump_dir) - - valdataset = COCODataset( - data_dir=opt.dataroot, - json_file='instances_val2017.json', - name="val2017", - img_size = (640, 640), - preproc=ValTransform(legacy=False), - ) - sampler = torch.utils.data.SequentialSampler(valdataset) - - dataloader_kwargs = {"num_workers": 8, "pin_memory": True, "sampler": sampler, "batch_size": opt.batch} - - val_loader = torch.utils.data.DataLoader(valdataset, **dataloader_kwargs) - - data_list = [] - coco_evaluator = COCOEvaluator(val_loader, img_size=(640, 640), confthre=0.001, nmsthre=0.65, num_classes=80) - - for cur_iter, (imgs, _, info_imgs, ids) in enumerate(tqdm(val_loader)): - - opt1, opt2, opt3, opt4, opt5, opt6, opt7, opt8, opt9 = get_output_data(opt.dump_dir, cur_iter) - opt2 = opt2.sigmoid() - opt3 = opt3.sigmoid() - - opt5 = opt5.sigmoid() - opt6 = opt6.sigmoid() - - opt8 = opt8.sigmoid() - opt9 = opt9.sigmoid() - output1 = torch.cat((opt1, opt2, opt3), dim=1) - output2 = torch.cat((opt4, opt5, opt6), dim=1) - output3 = torch.cat((opt7, opt8, opt9), dim=1) - - output1 = output1.view(1, 85, -1) - output2 = output2.view(1, 85, -1) - output3 = output3.view(1, 85, -1) - - outputs = torch.cat((output1, output2, output3), dim=2) - outputs = outputs.transpose(2, 1) - - - outputs = demo_postprocess(outputs, [640, 640]) - - outputs = postprocess(outputs, num_classes=80, conf_thre=0.001, nms_thre=0.65) - data_list.extend(coco_evaluator.convert_to_coco_format(outputs, info_imgs, ids)) - - results = coco_evaluator.evaluate_prediction(data_list) - print(results) - - -if __name__ == "__main__": - main() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 os +import sys +import argparse +from tqdm import tqdm +import torch +import numpy as np +from yolox.data import COCODataset, ValTransform +from yolox.evaluators import COCOEvaluator +from yolox.utils.boxes import postprocess + +from yolox.utils.demo_utils import demo_postprocess +sys.path.append('./YOLOX') + + +def get_output_data(dump_dir, idx, dtype=np.float32): + output_shape_1 = [1, 4, 80, 80] + output_shape_2 = [1, 1, 80, 80] + output_shape_3 = [1, 80, 80, 80] + output_shape_4 = [1, 4, 40, 40] + output_shape_5 = [1, 1, 40, 40] + output_shape_6 = [1, 80, 40, 40] + output_shape_7 = [1, 4, 20, 20] + output_shape_8 = [1, 1, 20, 20] + output_shape_9 = [1, 80, 20, 20] + + input_file_1 = os.path.join(dump_dir, "{:0>12d}_1.bin".format(idx)) + input_file_2 = os.path.join(dump_dir, "{:0>12d}_2.bin".format(idx)) + input_file_3 = os.path.join(dump_dir, "{:0>12d}_3.bin".format(idx)) + input_file_4 = os.path.join(dump_dir, "{:0>12d}_4.bin".format(idx)) + input_file_5 = os.path.join(dump_dir, "{:0>12d}_5.bin".format(idx)) + input_file_6 = os.path.join(dump_dir, "{:0>12d}_6.bin".format(idx)) + input_file_7 = os.path.join(dump_dir, "{:0>12d}_7.bin".format(idx)) + input_file_8 = os.path.join(dump_dir, "{:0>12d}_8.bin".format(idx)) + input_file_9 = os.path.join(dump_dir, "{:0>12d}_9.bin".format(idx)) + + input_data_1 = np.fromfile(input_file_1, dtype=dtype).reshape(output_shape_1) + input_data_2 = np.fromfile(input_file_2, dtype=dtype).reshape(output_shape_2) + input_data_3 = np.fromfile(input_file_3, dtype=dtype).reshape(output_shape_3) + input_data_4 = np.fromfile(input_file_4, dtype=dtype).reshape(output_shape_4) + input_data_5 = np.fromfile(input_file_5, dtype=dtype).reshape(output_shape_5) + input_data_6 = np.fromfile(input_file_6, dtype=dtype).reshape(output_shape_6) + input_data_7 = np.fromfile(input_file_7, dtype=dtype).reshape(output_shape_7) + input_data_8 = np.fromfile(input_file_8, dtype=dtype).reshape(output_shape_8) + input_data_9 = np.fromfile(input_file_9, dtype=dtype).reshape(output_shape_9) + + lst = [] + lst.append(torch.from_numpy(input_data_1)) + lst.append(torch.from_numpy(input_data_2)) + lst.append(torch.from_numpy(input_data_3)) + lst.append(torch.from_numpy(input_data_4)) + lst.append(torch.from_numpy(input_data_5)) + lst.append(torch.from_numpy(input_data_6)) + lst.append(torch.from_numpy(input_data_7)) + lst.append(torch.from_numpy(input_data_8)) + lst.append(torch.from_numpy(input_data_9)) + + return lst + + +def main(): + parser = argparse.ArgumentParser(description='YOLOX Postprocess') + parser.add_argument('--dataroot', dest='dataroot', + help='data root dirname', default='/opt/npu/coco', + type=str) + parser.add_argument('--dump_dir', dest='dump_dir', + help='dump dir for bin files', default='./result/dumpOutput_device0/', + type=str) + + parser.add_argument('--batch', dest='batch', help='batch for dataloader', default=1, type=int) + opt = parser.parse_args() + + if os.path.exists(opt.dump_dir): + os.system("rm-rf " + opt.dump_dir) + else: + os.system("mkdir " + opt.dump_dir) + + valdataset = COCODataset( + data_dir=opt.dataroot, + json_file='instances_val2017.json', + name="val2017", + img_size = (640, 640), + preproc=ValTransform(legacy=False), + ) + sampler = torch.utils.data.SequentialSampler(valdataset) + + dataloader_kwargs = {"num_workers": 8, "pin_memory": True, "sampler": sampler, "batch_size": opt.batch} + + val_loader = torch.utils.data.DataLoader(valdataset, **dataloader_kwargs) + + data_list = [] + coco_evaluator = COCOEvaluator(val_loader, img_size=(640, 640), confthre=0.001, nmsthre=0.65, num_classes=80) + + for cur_iter, (imgs, _, info_imgs, ids) in enumerate(tqdm(val_loader)): + + opt1, opt2, opt3, opt4, opt5, opt6, opt7, opt8, opt9 = get_output_data(opt.dump_dir, cur_iter) + opt2 = opt2.sigmoid() + opt3 = opt3.sigmoid() + + opt5 = opt5.sigmoid() + opt6 = opt6.sigmoid() + + opt8 = opt8.sigmoid() + opt9 = opt9.sigmoid() + output1 = torch.cat((opt1, opt2, opt3), dim=1) + output2 = torch.cat((opt4, opt5, opt6), dim=1) + output3 = torch.cat((opt7, opt8, opt9), dim=1) + + output1 = output1.view(1, 85, -1) + output2 = output2.view(1, 85, -1) + output3 = output3.view(1, 85, -1) + + outputs = torch.cat((output1, output2, output3), dim=2) + outputs = outputs.transpose(2, 1) + + + outputs = demo_postprocess(outputs, [640, 640]) + + outputs = postprocess(outputs, num_classes=80, conf_thre=0.001, nms_thre=0.65) + data_list.extend(coco_evaluator.convert_to_coco_format(outputs, info_imgs, ids)) + + results = coco_evaluator.evaluate_prediction(data_list) + print(results) + + +if __name__ == "__main__": + main() diff --git a/ACL_PyTorch/contrib/cv/detection/YOLOX/readme.md b/ACL_PyTorch/contrib/cv/detection/YOLOX/readme.md index 0ae6b91562..0043fc950f 100644 --- a/ACL_PyTorch/contrib/cv/detection/YOLOX/readme.md +++ b/ACL_PyTorch/contrib/cv/detection/YOLOX/readme.md @@ -1,50 +1,50 @@ -### YOLOX模型PyTorch离线推理指导 - -### 1. 环境准备 - -1. 安装依赖 - -```bash -pip3.7 install -r requirements.txt -``` - -2. 获取,修改与安装开源模型代码 - -``` -git clone git@github.com:Megvii-BaseDetection/YOLOX.git -main -cd YOLOX -git reset 6880e3999eb5cf83037e1818ee63d589384587bd --hard -pip3.7 install -v -e . # or python3 setup.py develop -pip3.7 install cython -pip3.7 install 'git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI' -patch -p1 < ../YOLOX-X.patch -cd .. -``` - -3. 将权重文件[yolox_x.pth](https://github.com/Megvii-BaseDetection/YOLOX/releases/download/0.1.1rc0/yolox_x.pth)放到当前工作目录。 - -4. 数据集 - - 获取COCO数据集,并重命名为COCO,放到/root/datasets目录 - -5. [获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) - - 将benchmark.x86_64或benchmark.aarch64放到当前工作目录 - -### 2. 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 - -```bash -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets -``` - -**评测结果:** - -| 模型 | pth精度 | 310离线推理精度 | 性能基准 | 310性能 | -| ----------- | --------- | --------------- | --------- | ------- | -| yolox-x bs1 | map:51.2% | map:51.1% | 60.739fps | 37.72144fps | - - - +### YOLOX模型PyTorch离线推理指导 + +### 1. 环境准备 + +1. 安装依赖 + +```bash +pip3.7 install -r requirements.txt +``` + +2. 获取,修改与安装开源模型代码 + +``` +git clone git@github.com:Megvii-BaseDetection/YOLOX.git -main +cd YOLOX +git reset 6880e3999eb5cf83037e1818ee63d589384587bd --hard +pip3.7 install -v -e . # or python3 setup.py develop +pip3.7 install cython +pip3.7 install 'git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI' +patch -p1 < ../YOLOX-X.patch +cd .. +``` + +3. 将权重文件[yolox_x.pth](https://github.com/Megvii-BaseDetection/YOLOX/releases/download/0.1.1rc0/yolox_x.pth)放到当前工作目录。 + +4. 数据集 + + 获取COCO数据集,并重命名为COCO,放到/root/datasets目录 + +5. [获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) + + 将benchmark.x86_64或benchmark.aarch64放到当前工作目录 + +### 2. 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 + +```bash +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets +``` + +**评测结果:** + +| 模型 | pth精度 | 310离线推理精度 | 性能基准 | 310性能 | +| ----------- | --------- | --------------- | --------- | ------- | +| yolox-x bs1 | map:51.2% | map:51.1% | 60.739fps | 37.72144fps | + + + diff --git a/ACL_PyTorch/contrib/cv/detection/pyramidbox/README.md b/ACL_PyTorch/contrib/cv/detection/pyramidbox/README.md index 4284fc05de..6b82604342 100644 --- a/ACL_PyTorch/contrib/cv/detection/pyramidbox/README.md +++ b/ACL_PyTorch/contrib/cv/detection/pyramidbox/README.md @@ -1,292 +1,292 @@ -# Pyramidbox Onnx模型端到端推理指导 - -- 1 模型概述 - - [1.1 论文地址]([[1803.07737\] PyramidBox: A Context-assisted Single Shot Face Detector (arxiv.org)](https://arxiv.org/abs/1803.07737)) - - [1.2 代码地址](https://gitee.com/kghhkhkljl/pyramidbox.git) -- 2 环境说明 - - [2.1 深度学习框架](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#21-深度学习框架) - - [2.2 python第三方库](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#22-python第三方库) -- 3 模型转换 - - [3.1 pth转onnx模型](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#31-pth转onnx模型) - - [3.2 onnx转om模型](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#32-onnx转om模型) -- 4 数据集预处理 - - [4.1 数据集获取](https://www.graviti.cn/open-datasets/WIDER_FACE) - - [4.2 数据集预处理](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#42-数据集预处理) - - [4.3 生成数据集信息文件](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#43-生成数据集信息文件) -- 5 离线推理 - - [5.1 benchmark工具概述](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#51-benchmark工具概述) - - [5.2 离线推理](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#52-离线推理) -- 6 精度对比 - - [6.1 离线推理精度统计](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#61-离线推理精度统计) - - [6.2 开源精度](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#62-开源精度) - - [6.3 精度对比](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#63-精度对比) -- 7 性能对比 - - [7.1 npu性能数据](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#71-npu性能数据) - - [7.2 T4性能数据](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#72-T4性能数据) - - [7.3 性能对比](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#73-性能对比) - -## 1 模型概述 - -- **论文地址** -- **代码地址** - -### 1.1 论文地址 - -[Pyramidbox论文](https://arxiv.org/abs/1803.07737) - -### 1.2 代码地址 - -https://gitee.com/kghhkhkljl/pyramidbox.git - -## 2 环境说明 - -- **深度学习框架** -- **python第三方库** - -### 2.1 深度学习框架 - -``` -python3.7.5 -CANN 5.0.3 - -pytorch >= 1.5.0 -torchvision >= 0.10.0 -onnx >= 1.7.0 - -说明:若是在conda环境下,直接采用python,不用python3.7 -``` - -### 2.2 python第三方库 - -``` -torch == 1.9.0 -numpy == 1.20.3 -Pillow == 8.2.0 -opencv-python == 4.5.3.56 -scipy == 1.7.1 -easydict == 1.9 -six == 1.16.0 -pycocotools == 2.0.2 -``` - -## 3 模型转换 - -- **pth转onnx模型** -- **onnx转om模型** - -### 3.1 pth转onnx模型 - -1.拉取代码仓库 (因为使用了开源代码模块,所以需要git clone一下) - -```shell -git clone https://gitee.com/kghhkhkljl/pyramidbox.git -``` - -克隆下来源代码之后将pr中的代码放到克隆下来的pyramidbox下面 - -2.下载pth权重文件 -权重文件从百度网盘上获取:[pyramidbox_120000_99.02.pth_免费高速下载|百度网盘-分享无限制 (baidu.com)](https://pan.baidu.com/s/1VtzgB9srkJY4SUtVM3n8tw?_at_=1631960039538) - -下载下来的权重文件也需要放在pyramidbox目录下面 - -3.使用pth2onnx.py进行onnx的转换 - -``` -方法二:cd pyramidbox/test -bash pth2onnx.sh -方法二:cd pyramidbox -python3.7 pyramidbox_pth2onnx.py ./pyramidbox_1000.onnx ./pyramidbox_120000_99.02.pth -第一个参数是onnx文件生成在当前目录的名字,第二个参数是当前目录下的权重文件 -``` - -### 3.2 onnx转om模型 - -1.设置环境变量 - -``` -source atc.sh -``` - -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.1 开发辅助工具指南 (推理) 01 - -``` -方法一:cd pyramidbox/test -bash onnxToom.sh -方法二:cd pyramidbox -atc --framework=5 --model=pyramidbox_1000.onnx --input_format=NCHW --input_shape="image:1,3,1000,1000" --output=pyramidbox_1000_bs1 --log=debug --soc_version=Ascend310 --precision_mode=force_fp32 - ---model是onnx的文件名,--input_shape是图片的shape,--output是输出on文件的文件名 -``` - -## 4 数据集预处理 - -- **数据集获取** -- **数据集预处理** -- **生成数据集信息文件** - -### 4.1 数据集获取 - -下载WIDER_FACE数据集: - -下载地址:https://www.graviti.cn/open-datasets/WIDER_FACE - -可以将数据集图片放在pyramidbox目录下的images下面,images目录需要自己创建(说明:images下面是个二级目录) - -``` -cd pyramidbox/images -``` - -### 4.2 数据集预处理 - -1.预处理脚本pyramidbox_pth_preprocess.py - -2.执行预处理脚本,生成数据集预处理后的bin文件 - -``` -方法一:cd pyramidbox/test -bash pre_deal.sh -方法二:cd pyramidbox -python3.7 pyramidbox_pth_preprocess.py ./images ./data1000_1 ./data1000_2 -第一个参数是预处理文件,第二个参数是数据集所在目录,第三和第四个参数是预处理后的文件名(说明:由于预处理需要进行两次图片的不同处理,所以生成的文件有两个) -``` - -### 4.3 生成数据集信息文件 - -1.生成数据集信息文件脚本get_info.py - -2.执行生成数据集信息脚本,生成数据集信息文件 - -``` -方法一:cd pyramidbox/test -bash to_info.sh -方法二:cd pyramidbox -python3.7 get_info.py bin ./data1000_1 ./pyramidbox_pre_bin_1000_1.info 1000 1000 -python3.7 get_info.py bin ./data1000_2 ./pyramidbox_pre_bin_1000_2.info 1000 1000 - -第一个是预处理后的数据集所在目录,第二个参数是生成的info文件名,后两个参数是图片的宽高。(说明:由于预处理会对图片进行两次处理,生成的文件有两个,所以会需要生成两个info文件) -``` - -## 5 离线推理 - -- **benchmark工具概述** -- **离线推理** - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN 5.0.3推理benchmark工具用户指南 - -### 5.2 离线推理 - -1.执行离线推理 - -执行前需要将benchmark.x86_64移动到执行目录下 - -(注:执行目录是/pyramidbox) - -然后运行如下命令: - -``` -方法一:cd pyramidbox/test -bash infer.sh -方法二:cd pyramidbox -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=./pyramidbox_1000_bs1.om -input_text_path=./pyramidbox_pre_bin_1.info -input_width=1000 -input_height=1000 -output_binary=True -useDvpp=False --precision_mode=force_fp32 -./benchmark.x86_64 -model_type=vision -device_id=1 -batch_size=1 -om_path=./pyramidbox_1000_bs1.om -input_text_path=./pyramidbox_pre_bin_2.info -input_width=1000 -input_height=1000 -output_binary=True -useDvpp=False --precision_mode=force_fp32 - --om_path为om所在的路径,-input_text_path为预处理后的bin文件的整个info文件,-input_width为图片的宽,-input_height为图片的高。由于预处理后的数据集有两个,所以此脚本需要运行两次,第二次运行只需要改动-device_id=1和-input_text_path为相应的info文件即可(例如:pyramidbox_pre_bin_2.info)。 -``` - -输出结果默认保存在当前目录result/dumpOutput_device{0}以及result/dumpOutput_device{1}下,每个输入对应的输出对应2个_1.bin文件,我们只使用第一个。 - -2.处理目录result/dumpOutput_device{0}和result/dumpOutput_device{1}下的bin文件 - -将该目录下的文件分类别存放,以便于后处理 - -``` -方法一:cd pyramidbox/test -bash convert.sh -方法二:cd pyramidbox -python3.7 convert.py ./result/dumpOutput_device0/ ./result/result1 -python3.7 convert.py ./result/dumpOutput_device1/ ./result/result2 -第一个参数是infer.sh脚本生成的文件,第二个参数是生成的二级目录所在的文件夹。 -``` - - - -## 6 精度对比 - -- **离线推理精度** -- **开源精度** -- **精度对比** - -### 6.1 离线推理精度统计 - -1.后处理 - -``` -cd ./pyramidbox -python3.7 pyramidbox_pth_postprocess.py -``` - -2.进行Ascend310上精度评估 - -``` -cd ./pyramidbox/evaluate -python3.7 evaluation.py -``` - -### 6.2 开源精度 - -pyramidbox在线推理精度: - -``` -Easy Val AP: 0.958986327388428 -Medium Val AP: 0.9504929578311708 -Hard Val AP: 0.907248372271328 -``` - -### 6.3 精度对比 - -``` -Easy Val AP: 0.9628280209085509 -Medium Val AP: 0.9538134269337523 -Hard Val AP: 0.8798007442124222 -``` - -### 6.3 精度对比 - -由于源码没有固定住shape,所以精度会有损失,因此和同一分辨率下的在线推理进行对比。对比方式:三个尺度求和取平均。 - -## 7 性能对比 - -- **npu性能数据** -- **T4性能数据** -- **性能对比** - -### 7.1 npu性能数据 - -1.benchmark工具在整个数据集上推理获得性能数据 -batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: - -``` -[e2e] throughputRate: 0.609815, latency: 5.29013e+06 -[data read] throughputRate: 0.635586, moduleLatency: 1573.35 -[preprocess] throughputRate: 0.61536, moduleLatency: 1625.07 -[infer] throughputRate: 0.6099, Interface throughputRate: 0.620281, moduleLatency: 1638.44 -[post] throughputRate: 0.6099, moduleLatency: 1639.61 -``` - -Interface throughputRate: 0.620281,0.620281x4=2.48既是batch1 310单卡吞吐率 - - - -说明:由于bs2以上会导致爆显存,所以测不了性能,此处只测了bs1。 - -![1633688929248](C:\Users\Eiven\AppData\Roaming\Typora\typora-user-images\1633688929248.png) - -### 7.2 T4性能数据 - -batch1 t4单卡吞吐率的计算方法是通过计算平均每张图片的耗时t,然后用1/t即是batch1 t4的单卡吞吐率。此处的t=1.560808,所以吞吐率为0.6407 - -### 7.3 性能对比 - +# Pyramidbox Onnx模型端到端推理指导 + +- 1 模型概述 + - [1.1 论文地址]([[1803.07737\] PyramidBox: A Context-assisted Single Shot Face Detector (arxiv.org)](https://arxiv.org/abs/1803.07737)) + - [1.2 代码地址](https://gitee.com/kghhkhkljl/pyramidbox.git) +- 2 环境说明 + - [2.1 深度学习框架](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#21-深度学习框架) + - [2.2 python第三方库](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#22-python第三方库) +- 3 模型转换 + - [3.1 pth转onnx模型](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#31-pth转onnx模型) + - [3.2 onnx转om模型](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#32-onnx转om模型) +- 4 数据集预处理 + - [4.1 数据集获取](https://www.graviti.cn/open-datasets/WIDER_FACE) + - [4.2 数据集预处理](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#42-数据集预处理) + - [4.3 生成数据集信息文件](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#43-生成数据集信息文件) +- 5 离线推理 + - [5.1 benchmark工具概述](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#51-benchmark工具概述) + - [5.2 离线推理](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#52-离线推理) +- 6 精度对比 + - [6.1 离线推理精度统计](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#61-离线推理精度统计) + - [6.2 开源精度](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#62-开源精度) + - [6.3 精度对比](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#63-精度对比) +- 7 性能对比 + - [7.1 npu性能数据](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#71-npu性能数据) + - [7.2 T4性能数据](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#72-T4性能数据) + - [7.3 性能对比](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#73-性能对比) + +## 1 模型概述 + +- **论文地址** +- **代码地址** + +### 1.1 论文地址 + +[Pyramidbox论文](https://arxiv.org/abs/1803.07737) + +### 1.2 代码地址 + +https://gitee.com/kghhkhkljl/pyramidbox.git + +## 2 环境说明 + +- **深度学习框架** +- **python第三方库** + +### 2.1 深度学习框架 + +``` +python3.7.5 +CANN 5.0.3 + +pytorch >= 1.5.0 +torchvision >= 0.10.0 +onnx >= 1.7.0 + +说明:若是在conda环境下,直接采用python,不用python3.7 +``` + +### 2.2 python第三方库 + +``` +torch == 1.9.0 +numpy == 1.20.3 +Pillow == 8.2.0 +opencv-python == 4.5.3.56 +scipy == 1.7.1 +easydict == 1.9 +six == 1.16.0 +pycocotools == 2.0.2 +``` + +## 3 模型转换 + +- **pth转onnx模型** +- **onnx转om模型** + +### 3.1 pth转onnx模型 + +1.拉取代码仓库 (因为使用了开源代码模块,所以需要git clone一下) + +```shell +git clone https://gitee.com/kghhkhkljl/pyramidbox.git +``` + +克隆下来源代码之后将pr中的代码放到克隆下来的pyramidbox下面 + +2.下载pth权重文件 +权重文件从百度网盘上获取:[pyramidbox_120000_99.02.pth_免费高速下载|百度网盘-分享无限制 (baidu.com)](https://pan.baidu.com/s/1VtzgB9srkJY4SUtVM3n8tw?_at_=1631960039538) + +下载下来的权重文件也需要放在pyramidbox目录下面 + +3.使用pth2onnx.py进行onnx的转换 + +``` +方法二:cd pyramidbox/test +bash pth2onnx.sh +方法二:cd pyramidbox +python3.7 pyramidbox_pth2onnx.py ./pyramidbox_1000.onnx ./pyramidbox_120000_99.02.pth +第一个参数是onnx文件生成在当前目录的名字,第二个参数是当前目录下的权重文件 +``` + +### 3.2 onnx转om模型 + +1.设置环境变量 + +``` +source atc.sh +``` + +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.1 开发辅助工具指南 (推理) 01 + +``` +方法一:cd pyramidbox/test +bash onnxToom.sh +方法二:cd pyramidbox +atc --framework=5 --model=pyramidbox_1000.onnx --input_format=NCHW --input_shape="image:1,3,1000,1000" --output=pyramidbox_1000_bs1 --log=debug --soc_version=Ascend310 --precision_mode=force_fp32 + +--model是onnx的文件名,--input_shape是图片的shape,--output是输出on文件的文件名 +``` + +## 4 数据集预处理 + +- **数据集获取** +- **数据集预处理** +- **生成数据集信息文件** + +### 4.1 数据集获取 + +下载WIDER_FACE数据集: + +下载地址:https://www.graviti.cn/open-datasets/WIDER_FACE + +可以将数据集图片放在pyramidbox目录下的images下面,images目录需要自己创建(说明:images下面是个二级目录) + +``` +cd pyramidbox/images +``` + +### 4.2 数据集预处理 + +1.预处理脚本pyramidbox_pth_preprocess.py + +2.执行预处理脚本,生成数据集预处理后的bin文件 + +``` +方法一:cd pyramidbox/test +bash pre_deal.sh +方法二:cd pyramidbox +python3.7 pyramidbox_pth_preprocess.py ./images ./data1000_1 ./data1000_2 +第一个参数是预处理文件,第二个参数是数据集所在目录,第三和第四个参数是预处理后的文件名(说明:由于预处理需要进行两次图片的不同处理,所以生成的文件有两个) +``` + +### 4.3 生成数据集信息文件 + +1.生成数据集信息文件脚本get_info.py + +2.执行生成数据集信息脚本,生成数据集信息文件 + +``` +方法一:cd pyramidbox/test +bash to_info.sh +方法二:cd pyramidbox +python3.7 get_info.py bin ./data1000_1 ./pyramidbox_pre_bin_1000_1.info 1000 1000 +python3.7 get_info.py bin ./data1000_2 ./pyramidbox_pre_bin_1000_2.info 1000 1000 + +第一个是预处理后的数据集所在目录,第二个参数是生成的info文件名,后两个参数是图片的宽高。(说明:由于预处理会对图片进行两次处理,生成的文件有两个,所以会需要生成两个info文件) +``` + +## 5 离线推理 + +- **benchmark工具概述** +- **离线推理** + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN 5.0.3推理benchmark工具用户指南 + +### 5.2 离线推理 + +1.执行离线推理 + +执行前需要将benchmark.x86_64移动到执行目录下 + +(注:执行目录是/pyramidbox) + +然后运行如下命令: + +``` +方法一:cd pyramidbox/test +bash infer.sh +方法二:cd pyramidbox +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=./pyramidbox_1000_bs1.om -input_text_path=./pyramidbox_pre_bin_1.info -input_width=1000 -input_height=1000 -output_binary=True -useDvpp=False --precision_mode=force_fp32 +./benchmark.x86_64 -model_type=vision -device_id=1 -batch_size=1 -om_path=./pyramidbox_1000_bs1.om -input_text_path=./pyramidbox_pre_bin_2.info -input_width=1000 -input_height=1000 -output_binary=True -useDvpp=False --precision_mode=force_fp32 + +-om_path为om所在的路径,-input_text_path为预处理后的bin文件的整个info文件,-input_width为图片的宽,-input_height为图片的高。由于预处理后的数据集有两个,所以此脚本需要运行两次,第二次运行只需要改动-device_id=1和-input_text_path为相应的info文件即可(例如:pyramidbox_pre_bin_2.info)。 +``` + +输出结果默认保存在当前目录result/dumpOutput_device{0}以及result/dumpOutput_device{1}下,每个输入对应的输出对应2个_1.bin文件,我们只使用第一个。 + +2.处理目录result/dumpOutput_device{0}和result/dumpOutput_device{1}下的bin文件 + +将该目录下的文件分类别存放,以便于后处理 + +``` +方法一:cd pyramidbox/test +bash convert.sh +方法二:cd pyramidbox +python3.7 convert.py ./result/dumpOutput_device0/ ./result/result1 +python3.7 convert.py ./result/dumpOutput_device1/ ./result/result2 +第一个参数是infer.sh脚本生成的文件,第二个参数是生成的二级目录所在的文件夹。 +``` + + + +## 6 精度对比 + +- **离线推理精度** +- **开源精度** +- **精度对比** + +### 6.1 离线推理精度统计 + +1.后处理 + +``` +cd ./pyramidbox +python3.7 pyramidbox_pth_postprocess.py +``` + +2.进行Ascend310上精度评估 + +``` +cd ./pyramidbox/evaluate +python3.7 evaluation.py +``` + +### 6.2 开源精度 + +pyramidbox在线推理精度: + +``` +Easy Val AP: 0.958986327388428 +Medium Val AP: 0.9504929578311708 +Hard Val AP: 0.907248372271328 +``` + +### 6.3 精度对比 + +``` +Easy Val AP: 0.9628280209085509 +Medium Val AP: 0.9538134269337523 +Hard Val AP: 0.8798007442124222 +``` + +### 6.3 精度对比 + +由于源码没有固定住shape,所以精度会有损失,因此和同一分辨率下的在线推理进行对比。对比方式:三个尺度求和取平均。 + +## 7 性能对比 + +- **npu性能数据** +- **T4性能数据** +- **性能对比** + +### 7.1 npu性能数据 + +1.benchmark工具在整个数据集上推理获得性能数据 +batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: + +``` +[e2e] throughputRate: 0.609815, latency: 5.29013e+06 +[data read] throughputRate: 0.635586, moduleLatency: 1573.35 +[preprocess] throughputRate: 0.61536, moduleLatency: 1625.07 +[infer] throughputRate: 0.6099, Interface throughputRate: 0.620281, moduleLatency: 1638.44 +[post] throughputRate: 0.6099, moduleLatency: 1639.61 +``` + +Interface throughputRate: 0.620281,0.620281x4=2.48既是batch1 310单卡吞吐率 + + + +说明:由于bs2以上会导致爆显存,所以测不了性能,此处只测了bs1。 + +![1633688929248](C:\Users\Eiven\AppData\Roaming\Typora\typora-user-images\1633688929248.png) + +### 7.2 T4性能数据 + +batch1 t4单卡吞吐率的计算方法是通过计算平均每张图片的耗时t,然后用1/t即是batch1 t4的单卡吞吐率。此处的t=1.560808,所以吞吐率为0.6407 + +### 7.3 性能对比 + batch1:0.620281x4=2.48>0.6407 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/pyramidbox/convert.py b/ACL_PyTorch/contrib/cv/detection/pyramidbox/convert.py index bb6bdfd5c6..ef9043a138 100644 --- a/ACL_PyTorch/contrib/cv/detection/pyramidbox/convert.py +++ b/ACL_PyTorch/contrib/cv/detection/pyramidbox/convert.py @@ -1,39 +1,39 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import shutil - -if __name__ == '__main__': - bin_path = sys.argv[1] - resule_path = sys.argv[2] - if not os.path.exists(resule_path): - os.mkdir(resule_path) - f = os.listdir(bin_path) - for data in f: - data = data.strip('\n') - dir_name = data.split('_')[0] + '--' + data.split('_')[1] - dir_path = os.path.join(resule_path, dir_name) - if not os.path.exists(dir_path): - os.mkdir(dir_path) - file_list = os.listdir(resule_path) - for dir in file_list: - dir = dir.strip('\n') - cur_path = os.path.join(resule_path, dir) - for data in f: - data = data.strip('\n') - if data.split('_')[0] == dir.split('--')[0]: - shutil.copy(os.path.join(bin_path, data), - os.path.join(cur_path, data)) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import shutil + +if __name__ == '__main__': + bin_path = sys.argv[1] + resule_path = sys.argv[2] + if not os.path.exists(resule_path): + os.mkdir(resule_path) + f = os.listdir(bin_path) + for data in f: + data = data.strip('\n') + dir_name = data.split('_')[0] + '--' + data.split('_')[1] + dir_path = os.path.join(resule_path, dir_name) + if not os.path.exists(dir_path): + os.mkdir(dir_path) + file_list = os.listdir(resule_path) + for dir in file_list: + dir = dir.strip('\n') + cur_path = os.path.join(resule_path, dir) + for data in f: + data = data.strip('\n') + if data.split('_')[0] == dir.split('--')[0]: + shutil.copy(os.path.join(bin_path, data), + os.path.join(cur_path, data)) diff --git a/ACL_PyTorch/contrib/cv/detection/pyramidbox/pyramidbox_pth2onnx.py b/ACL_PyTorch/contrib/cv/detection/pyramidbox/pyramidbox_pth2onnx.py index 7740e25cf5..d0faceedf5 100644 --- a/ACL_PyTorch/contrib/cv/detection/pyramidbox/pyramidbox_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/detection/pyramidbox/pyramidbox_pth2onnx.py @@ -1,35 +1,35 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -from data.config import cfg -from pyramidbox import build_net -import numpy as np -import os -import sys - -def main(onnx_path,path): - input_names=["image"] - output_names = ["output"] - net = build_net('test',2) - net.eval() - net.load_state_dict(torch.load(path,map_location='cpu')) - # dynamic_axes = {'image': {0: '-1'}, 'output': {0: '-1'}} - dummy_input = torch.randn(1,3,1000,1000) - torch.onnx.export(net,dummy_input,onnx_path,input_names = input_names,output_names=output_names,verbose=True,enable_onnx_checker=False,opset_version=9) - -if __name__ =="__main__": - onnx_path = os.path.abspath(sys.argv[1]) - path = os.path.abspath(sys.argv[2]) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +from data.config import cfg +from pyramidbox import build_net +import numpy as np +import os +import sys + +def main(onnx_path,path): + input_names=["image"] + output_names = ["output"] + net = build_net('test',2) + net.eval() + net.load_state_dict(torch.load(path,map_location='cpu')) + # dynamic_axes = {'image': {0: '-1'}, 'output': {0: '-1'}} + dummy_input = torch.randn(1,3,1000,1000) + torch.onnx.export(net,dummy_input,onnx_path,input_names = input_names,output_names=output_names,verbose=True,enable_onnx_checker=False,opset_version=9) + +if __name__ =="__main__": + onnx_path = os.path.abspath(sys.argv[1]) + path = os.path.abspath(sys.argv[2]) main(onnx_path,path) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/pyramidbox/pyramidbox_pth_postprocess.py b/ACL_PyTorch/contrib/cv/detection/pyramidbox/pyramidbox_pth_postprocess.py index c6377cec09..6fa423728e 100644 --- a/ACL_PyTorch/contrib/cv/detection/pyramidbox/pyramidbox_pth_postprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/pyramidbox/pyramidbox_pth_postprocess.py @@ -1,227 +1,227 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 - -import sys -import os -import torch -import argparse -import numpy as np -import cv2 -import os.path as osp -import torch.backends.cudnn as cudnn - -from PIL import Image -import scipy.io as sio -from data.config import cfg -from torch.autograd import Variable -from utils.augmentations import to_chw_bgr -from layers.bbox_utils import decode, nms - -parser = argparse.ArgumentParser(description='pyramidbox evaluatuon wider') -parser.add_argument('--thresh', default=0.05, type=float, - help='Final confidence threshold') -args = parser.parse_args() - -use_cuda = torch.cuda.is_available() -if use_cuda: - torch.set_default_tensor_type('torch.cuda.FloatTensor') -else: - torch.set_default_tensor_type('torch.FloatTensor') - -List1 = [] -List2 = [] -root_path = os.getcwd() -def pre_postprocess(i,path): - listt=[] - global t - if i==0: - path = os.path.join(root_path,path) - else: - path = os.path.join(root_path,'result/result2') - File = os.listdir(path) - for file in sorted(File): - Doc = [] #save no-repeated file name - os.chdir(os.path.join(path, file)) - cur_path = os.getcwd() - doc = os.listdir(cur_path) - for document in sorted(doc): - Doc.append(document[0:-6]) #grip end - Doc = list(set(Doc)) #grip repeated element - for ff in sorted(Doc): #deal after sorting - txt_file = np.fromfile(f'{path}/{file}/{ff}_1.bin', dtype=np.float16) - output = torch.tensor(txt_file.reshape(-1,1000,5)) - listt.append(output) - return listt - -def detect_face(img, counter,i): - h, w = img.shape[0], img.shape[1] - min_side = 1280 - scale = max(w, h) / float(min_side) - if i==0: - detections = List1[counter].data - else: - detections = List2[counter].data - detections = detections.cpu().numpy() - det_conf = detections[0, :, 0] - det_xmin = 1280 * detections[0, :, 1] * scale #x1 - det_ymin = 1280 * detections[0, :, 2] * scale #y1 - det_xmax = 1280 * detections[0, :, 3] * scale #x2 - det_ymax = 1280 * detections[0, :, 4] * scale #y2 - det = np.column_stack((det_xmin, det_ymin, det_xmax, det_ymax, det_conf)) - keep_index = np.where(det[:, 4] >= args.thresh)[0] - det = det[keep_index, :] - return det - -def flip_test(image,counter,i): - image_f = cv2.flip(image, 1) - det_f = detect_face(image_f,counter,1) - - det_t = np.zeros(det_f.shape) - det_t[:, 0] = image.shape[1] - det_f[:, 2] - det_t[:, 1] = det_f[:, 1] - det_t[:, 2] = image.shape[1] - det_f[:, 0] - det_t[:, 3] = det_f[:, 3] - det_t[:, 4] = det_f[:, 4] - return det_t - -def multi_scale_test(image, max_im_shrink,counter,i): - # shrink detecting and shrink only detect big face - st = 0.5 if max_im_shrink >= 0.75 else 0.5 * max_im_shrink - det_s = detect_face(image,counter,i) - index = np.where(np.maximum( - det_s[:, 2] - det_s[:, 0] + 1, det_s[:, 3] - det_s[:, 1] + 1) > 30)[0] - det_s = det_s[index, :] - - # enlarge one times - bt = min(2, max_im_shrink) if max_im_shrink > 1 else ( - st + max_im_shrink) / 2 - det_b = detect_face(image,counter,i) - - - # enlarge only detect small face - if bt > 1: - index = np.where(np.minimum( - det_b[:, 2] - det_b[:, 0] + 1, det_b[:, 3] - det_b[:, 1] + 1) < 100)[0] - det_b = det_b[index, :] - else: - index = np.where(np.maximum( - det_b[:, 2] - det_b[:, 0] + 1, det_b[:, 3] - det_b[:, 1] + 1) > 30)[0] - det_b = det_b[index, :] - - return det_s, det_b - -def bbox_vote(det): - order = det[:, 4].ravel().argsort()[::-1] - det = det[order, :] - while det.shape[0] > 0: - # IOU - area = (det[:, 2] - det[:, 0] + 1) * (det[:, 3] - det[:, 1] + 1) - xx1 = np.maximum(det[0, 0], det[:, 0]) - yy1 = np.maximum(det[0, 1], det[:, 1]) - xx2 = np.minimum(det[0, 2], det[:, 2]) - yy2 = np.minimum(det[0, 3], det[:, 3]) - w = np.maximum(0.0, xx2 - xx1 + 1) - h = np.maximum(0.0, yy2 - yy1 + 1) - inter = w * h - o = inter / (area[0] + area[:] - inter) - # get needed merge det and delete these det - merge_index = np.where(o >= 0.3)[0] - det_accu = det[merge_index, :] - det = np.delete(det, merge_index, 0) - - if merge_index.shape[0] <= 1: - continue - det_accu[:, 0:4] = det_accu[:, 0:4] * np.tile(det_accu[:, -1:], (1, 4)) - max_score = np.max(det_accu[:, 4]) - det_accu_sum = np.zeros((1, 5)) - det_accu_sum[:, 0:4] = np.sum( - det_accu[:, 0:4], axis=0) / np.sum(det_accu[:, -1:]) - det_accu_sum[:, 4] = max_score - - try: - dets = np.row_stack((dets, det_accu_sum)) - except: - dets = det_accu_sum - dets = dets[0:750, :] - return dets - -if __name__ == '__main__': - #mat_path = os.path.abspath(sys.argv[1]) #mat path './evaluate/ground_truth/wider_face_val.mat' - #img_path = os.path.abspath(sys.argv[2]) #image path './images' - #save_path = os.path.abspath(sys.argv[3]) #save path './output_0.01/widerface/' - #path1 = os.path.abspath(sys.argv[4]) #first data ---> result './result1/result1' - #path2 = os.path.abspath(sys.argv[5]) #second data ---> result './result2/result2' - wider_face = sio.loadmat('./evaluate/ground_truth/wider_face_val.mat') - event_list = wider_face['event_list'] - file_list = wider_face['file_list'] - del wider_face - imgs_path = root_path+'/images' - save_path = root_path+'/output_1000' - counter = 0 - if use_cuda: - cudnn.benckmark = True - path1 = './result/result1' - path2 = './result/result2/result2' - List1 = pre_postprocess(0,path1) - List2 = pre_postprocess(1,path2) - print(List1) - print(len(List1)) - print('-----------------------------------------------') - print(len(List2)) - print(List2) - i=0 - for index, event in enumerate(sorted(event_list)): - filelist = file_list[index][0] - path = os.path.join(save_path, str(event[0][0])) - if not os.path.exists(path): - os.makedirs(path) - i = i+1 - for num, file in enumerate(sorted(filelist)): - im_name = file[0][0] - print(im_name) - in_file = os.path.join(imgs_path, event[0][0], str(im_name[:]) + '.jpg') - img = Image.open(in_file) - if img.mode == 'L': - img = img.convert('RGB') - img = np.array(img) - max_im_shrink = np.sqrt( - 1700 * 1000 / (img.shape[0] * img.shape[1])) - shrink = max_im_shrink if max_im_shrink < 1 else 1 - counter += 1 - det0 = detect_face(img,counter-1,0) - - det1 = flip_test(img,counter-1,1) # flip test - [det2, det3] = multi_scale_test( img, max_im_shrink,counter-1,0) - - det = np.row_stack((det0, det1, det2, det3)) - if det.shape[0] ==1: - dets =det - else: - dets = bbox_vote(det) - - fout = open(osp.join(save_path, str(event[0][ - 0]), im_name + '.txt'), 'w') - fout.write('{:s}\n'.format(str(event[0][0]) + '/' + im_name + '.jpg')) - fout.write('{:d}\n'.format(dets.shape[0])) - for i in range(dets.shape[0]): - xmin = dets[i][0] - ymin = dets[i][1] - xmax = dets[i][2] - ymax = dets[i][3] - score = dets[i][4] - fout.write('{:.1f} {:.1f} {:.1f} {:.1f} {:.3f}\n'. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 + +import sys +import os +import torch +import argparse +import numpy as np +import cv2 +import os.path as osp +import torch.backends.cudnn as cudnn + +from PIL import Image +import scipy.io as sio +from data.config import cfg +from torch.autograd import Variable +from utils.augmentations import to_chw_bgr +from layers.bbox_utils import decode, nms + +parser = argparse.ArgumentParser(description='pyramidbox evaluatuon wider') +parser.add_argument('--thresh', default=0.05, type=float, + help='Final confidence threshold') +args = parser.parse_args() + +use_cuda = torch.cuda.is_available() +if use_cuda: + torch.set_default_tensor_type('torch.cuda.FloatTensor') +else: + torch.set_default_tensor_type('torch.FloatTensor') + +List1 = [] +List2 = [] +root_path = os.getcwd() +def pre_postprocess(i,path): + listt=[] + global t + if i==0: + path = os.path.join(root_path,path) + else: + path = os.path.join(root_path,'result/result2') + File = os.listdir(path) + for file in sorted(File): + Doc = [] #save no-repeated file name + os.chdir(os.path.join(path, file)) + cur_path = os.getcwd() + doc = os.listdir(cur_path) + for document in sorted(doc): + Doc.append(document[0:-6]) #grip end + Doc = list(set(Doc)) #grip repeated element + for ff in sorted(Doc): #deal after sorting + txt_file = np.fromfile(f'{path}/{file}/{ff}_1.bin', dtype=np.float16) + output = torch.tensor(txt_file.reshape(-1,1000,5)) + listt.append(output) + return listt + +def detect_face(img, counter,i): + h, w = img.shape[0], img.shape[1] + min_side = 1280 + scale = max(w, h) / float(min_side) + if i==0: + detections = List1[counter].data + else: + detections = List2[counter].data + detections = detections.cpu().numpy() + det_conf = detections[0, :, 0] + det_xmin = 1280 * detections[0, :, 1] * scale #x1 + det_ymin = 1280 * detections[0, :, 2] * scale #y1 + det_xmax = 1280 * detections[0, :, 3] * scale #x2 + det_ymax = 1280 * detections[0, :, 4] * scale #y2 + det = np.column_stack((det_xmin, det_ymin, det_xmax, det_ymax, det_conf)) + keep_index = np.where(det[:, 4] >= args.thresh)[0] + det = det[keep_index, :] + return det + +def flip_test(image,counter,i): + image_f = cv2.flip(image, 1) + det_f = detect_face(image_f,counter,1) + + det_t = np.zeros(det_f.shape) + det_t[:, 0] = image.shape[1] - det_f[:, 2] + det_t[:, 1] = det_f[:, 1] + det_t[:, 2] = image.shape[1] - det_f[:, 0] + det_t[:, 3] = det_f[:, 3] + det_t[:, 4] = det_f[:, 4] + return det_t + +def multi_scale_test(image, max_im_shrink,counter,i): + # shrink detecting and shrink only detect big face + st = 0.5 if max_im_shrink >= 0.75 else 0.5 * max_im_shrink + det_s = detect_face(image,counter,i) + index = np.where(np.maximum( + det_s[:, 2] - det_s[:, 0] + 1, det_s[:, 3] - det_s[:, 1] + 1) > 30)[0] + det_s = det_s[index, :] + + # enlarge one times + bt = min(2, max_im_shrink) if max_im_shrink > 1 else ( + st + max_im_shrink) / 2 + det_b = detect_face(image,counter,i) + + + # enlarge only detect small face + if bt > 1: + index = np.where(np.minimum( + det_b[:, 2] - det_b[:, 0] + 1, det_b[:, 3] - det_b[:, 1] + 1) < 100)[0] + det_b = det_b[index, :] + else: + index = np.where(np.maximum( + det_b[:, 2] - det_b[:, 0] + 1, det_b[:, 3] - det_b[:, 1] + 1) > 30)[0] + det_b = det_b[index, :] + + return det_s, det_b + +def bbox_vote(det): + order = det[:, 4].ravel().argsort()[::-1] + det = det[order, :] + while det.shape[0] > 0: + # IOU + area = (det[:, 2] - det[:, 0] + 1) * (det[:, 3] - det[:, 1] + 1) + xx1 = np.maximum(det[0, 0], det[:, 0]) + yy1 = np.maximum(det[0, 1], det[:, 1]) + xx2 = np.minimum(det[0, 2], det[:, 2]) + yy2 = np.minimum(det[0, 3], det[:, 3]) + w = np.maximum(0.0, xx2 - xx1 + 1) + h = np.maximum(0.0, yy2 - yy1 + 1) + inter = w * h + o = inter / (area[0] + area[:] - inter) + # get needed merge det and delete these det + merge_index = np.where(o >= 0.3)[0] + det_accu = det[merge_index, :] + det = np.delete(det, merge_index, 0) + + if merge_index.shape[0] <= 1: + continue + det_accu[:, 0:4] = det_accu[:, 0:4] * np.tile(det_accu[:, -1:], (1, 4)) + max_score = np.max(det_accu[:, 4]) + det_accu_sum = np.zeros((1, 5)) + det_accu_sum[:, 0:4] = np.sum( + det_accu[:, 0:4], axis=0) / np.sum(det_accu[:, -1:]) + det_accu_sum[:, 4] = max_score + + try: + dets = np.row_stack((dets, det_accu_sum)) + except: + dets = det_accu_sum + dets = dets[0:750, :] + return dets + +if __name__ == '__main__': + #mat_path = os.path.abspath(sys.argv[1]) #mat path './evaluate/ground_truth/wider_face_val.mat' + #img_path = os.path.abspath(sys.argv[2]) #image path './images' + #save_path = os.path.abspath(sys.argv[3]) #save path './output_0.01/widerface/' + #path1 = os.path.abspath(sys.argv[4]) #first data ---> result './result1/result1' + #path2 = os.path.abspath(sys.argv[5]) #second data ---> result './result2/result2' + wider_face = sio.loadmat('./evaluate/ground_truth/wider_face_val.mat') + event_list = wider_face['event_list'] + file_list = wider_face['file_list'] + del wider_face + imgs_path = root_path+'/images' + save_path = root_path+'/output_1000' + counter = 0 + if use_cuda: + cudnn.benckmark = True + path1 = './result/result1' + path2 = './result/result2/result2' + List1 = pre_postprocess(0,path1) + List2 = pre_postprocess(1,path2) + print(List1) + print(len(List1)) + print('-----------------------------------------------') + print(len(List2)) + print(List2) + i=0 + for index, event in enumerate(sorted(event_list)): + filelist = file_list[index][0] + path = os.path.join(save_path, str(event[0][0])) + if not os.path.exists(path): + os.makedirs(path) + i = i+1 + for num, file in enumerate(sorted(filelist)): + im_name = file[0][0] + print(im_name) + in_file = os.path.join(imgs_path, event[0][0], str(im_name[:]) + '.jpg') + img = Image.open(in_file) + if img.mode == 'L': + img = img.convert('RGB') + img = np.array(img) + max_im_shrink = np.sqrt( + 1700 * 1000 / (img.shape[0] * img.shape[1])) + shrink = max_im_shrink if max_im_shrink < 1 else 1 + counter += 1 + det0 = detect_face(img,counter-1,0) + + det1 = flip_test(img,counter-1,1) # flip test + [det2, det3] = multi_scale_test( img, max_im_shrink,counter-1,0) + + det = np.row_stack((det0, det1, det2, det3)) + if det.shape[0] ==1: + dets =det + else: + dets = bbox_vote(det) + + fout = open(osp.join(save_path, str(event[0][ + 0]), im_name + '.txt'), 'w') + fout.write('{:s}\n'.format(str(event[0][0]) + '/' + im_name + '.jpg')) + fout.write('{:d}\n'.format(dets.shape[0])) + for i in range(dets.shape[0]): + xmin = dets[i][0] + ymin = dets[i][1] + xmax = dets[i][2] + ymax = dets[i][3] + score = dets[i][4] + fout.write('{:.1f} {:.1f} {:.1f} {:.1f} {:.3f}\n'. format(xmin, ymin, (xmax - xmin + 1), (ymax - ymin + 1), score)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/detection/pyramidbox/pyramidbox_pth_preprocess.py b/ACL_PyTorch/contrib/cv/detection/pyramidbox/pyramidbox_pth_preprocess.py index e844307d8d..d70c40747f 100644 --- a/ACL_PyTorch/contrib/cv/detection/pyramidbox/pyramidbox_pth_preprocess.py +++ b/ACL_PyTorch/contrib/cv/detection/pyramidbox/pyramidbox_pth_preprocess.py @@ -1,109 +1,109 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 - -import sys -import os -import torch -import numpy as np -import cv2 - -from PIL import Image -from data.config import cfg -from torch.autograd import Variable -from utils.augmentations import to_chw_bgr - -use_cuda = torch.cuda.is_available() - -if use_cuda: - torch.set_default_tensor_type('torch.cuda.FloatTensor') -else: - torch.set_default_tensor_type('torch.FloatTensor') - -def process_image(img, min_side): - h, w = img.shape[0], img.shape[1] - #长边缩放为min_side - scale = max(w, h) / float(min_side) - new_w, new_h = int(w/scale), int(h/scale) - resize_img = cv2.resize(img, (new_w, new_h)) - # 填充至min_side * min_side - bottom = min_side-new_h - right = min_side-new_w - img = cv2.copyMakeBorder(resize_img, 0, int(bottom), 0, int(right), cv2.BORDER_CONSTANT, value=[0,0,0]) #从图像边界向上,下,左,右扩的像素数目 - return img - -def preprocess(file_path, bin_path): - in_files = os.listdir(file_path) - if not os.path.exists(bin_path): - os.makedirs(bin_path) - for file in sorted(in_files): - os.chdir(os.path.join(file_path, file)) - cur_path = os.getcwd() - doc = os.listdir(cur_path) - for document in sorted(doc): - in_file = os.path.join(cur_path, document) - img = Image.open(in_file) - if img.mode == 'L': - img = img.convert('RGB') - img = np.array(img) - img = process_image(img,1000) #对图片进行放缩加padding - x = to_chw_bgr(img) - - x = x.astype('float32') - x -= cfg.img_mean - x = x[[2, 1, 0], :, :] - x = Variable(torch.from_numpy(x).unsqueeze(0)) - if use_cuda: - x = x.cuda() - if not os.path.exists(os.path.join(bin_path,file)): - os.makedirs(os.path.join(bin_path,file)) - des_path = os.path.join(bin_path,file) - x.numpy().tofile(os.path.join(des_path,document.split('.')[0] +'.bin')) - -def preprocess1(file_path, bin_path): - in_files = os.listdir(file_path) - if not os.path.exists(bin_path): - os.makedirs(bin_path) - for file in sorted(in_files): - os.chdir(os.path.join(file_path, file)) - cur_path = os.getcwd() - doc = os.listdir(cur_path) - for document in sorted(doc): - in_file = os.path.join(cur_path, document) - img = Image.open(in_file) - if img.mode == 'L': - img = img.convert('RGB') - img = np.array(img) - img = cv2.flip(img, 1) - img = process_image(img,1000) - x = to_chw_bgr(img) - x = x.astype('float32') - x -= cfg.img_mean - x = x[[2, 1, 0], :, :] - x = Variable(torch.from_numpy(x).unsqueeze(0)) - if use_cuda: - x = x.cuda() - if not os.path.exists(os.path.join(bin_path,file)): - os.makedirs(os.path.join(bin_path,file)) - des_path = os.path.join(bin_path,file) - x.numpy().tofile(os.path.join(des_path,document.split('.')[0] +'.bin')) - -if __name__ == "__main__": - file_path = os.path.abspath(sys.argv[1]) - bin_path1 = os.path.abspath(sys.argv[2]) - bin_path2 = os.path.abspath(sys.argv[3]) - preprocess(file_path, bin_path1) - preprocess1(file_path, bin_path2) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 + +import sys +import os +import torch +import numpy as np +import cv2 + +from PIL import Image +from data.config import cfg +from torch.autograd import Variable +from utils.augmentations import to_chw_bgr + +use_cuda = torch.cuda.is_available() + +if use_cuda: + torch.set_default_tensor_type('torch.cuda.FloatTensor') +else: + torch.set_default_tensor_type('torch.FloatTensor') + +def process_image(img, min_side): + h, w = img.shape[0], img.shape[1] + #长边缩放为min_side + scale = max(w, h) / float(min_side) + new_w, new_h = int(w/scale), int(h/scale) + resize_img = cv2.resize(img, (new_w, new_h)) + # 填充至min_side * min_side + bottom = min_side-new_h + right = min_side-new_w + img = cv2.copyMakeBorder(resize_img, 0, int(bottom), 0, int(right), cv2.BORDER_CONSTANT, value=[0,0,0]) #从图像边界向上,下,左,右扩的像素数目 + return img + +def preprocess(file_path, bin_path): + in_files = os.listdir(file_path) + if not os.path.exists(bin_path): + os.makedirs(bin_path) + for file in sorted(in_files): + os.chdir(os.path.join(file_path, file)) + cur_path = os.getcwd() + doc = os.listdir(cur_path) + for document in sorted(doc): + in_file = os.path.join(cur_path, document) + img = Image.open(in_file) + if img.mode == 'L': + img = img.convert('RGB') + img = np.array(img) + img = process_image(img,1000) #对图片进行放缩加padding + x = to_chw_bgr(img) + + x = x.astype('float32') + x -= cfg.img_mean + x = x[[2, 1, 0], :, :] + x = Variable(torch.from_numpy(x).unsqueeze(0)) + if use_cuda: + x = x.cuda() + if not os.path.exists(os.path.join(bin_path,file)): + os.makedirs(os.path.join(bin_path,file)) + des_path = os.path.join(bin_path,file) + x.numpy().tofile(os.path.join(des_path,document.split('.')[0] +'.bin')) + +def preprocess1(file_path, bin_path): + in_files = os.listdir(file_path) + if not os.path.exists(bin_path): + os.makedirs(bin_path) + for file in sorted(in_files): + os.chdir(os.path.join(file_path, file)) + cur_path = os.getcwd() + doc = os.listdir(cur_path) + for document in sorted(doc): + in_file = os.path.join(cur_path, document) + img = Image.open(in_file) + if img.mode == 'L': + img = img.convert('RGB') + img = np.array(img) + img = cv2.flip(img, 1) + img = process_image(img,1000) + x = to_chw_bgr(img) + x = x.astype('float32') + x -= cfg.img_mean + x = x[[2, 1, 0], :, :] + x = Variable(torch.from_numpy(x).unsqueeze(0)) + if use_cuda: + x = x.cuda() + if not os.path.exists(os.path.join(bin_path,file)): + os.makedirs(os.path.join(bin_path,file)) + des_path = os.path.join(bin_path,file) + x.numpy().tofile(os.path.join(des_path,document.split('.')[0] +'.bin')) + +if __name__ == "__main__": + file_path = os.path.abspath(sys.argv[1]) + bin_path1 = os.path.abspath(sys.argv[2]) + bin_path2 = os.path.abspath(sys.argv[3]) + preprocess(file_path, bin_path1) + preprocess1(file_path, bin_path2) diff --git a/ACL_PyTorch/contrib/cv/face/AlignedReID/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/face/AlignedReID/modelzoo_level.txt index 9e95396651..27e6c78b37 100644 --- a/ACL_PyTorch/contrib/cv/face/AlignedReID/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/face/AlignedReID/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:POK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/face/FaceNet/FaceNet_postprocess.py b/ACL_PyTorch/contrib/cv/face/FaceNet/FaceNet_postprocess.py index c3d5cb168e..af7e9d1533 100644 --- a/ACL_PyTorch/contrib/cv/face/FaceNet/FaceNet_postprocess.py +++ b/ACL_PyTorch/contrib/cv/face/FaceNet/FaceNet_postprocess.py @@ -1,231 +1,231 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import os -import sys -import json -import math -import numpy as np -from tqdm import tqdm -from scipy import interpolate -from sklearn.model_selection import KFold -from FaceNet_preprocess import read_pairs - - -def load_json(json_path): - with open(json_path) as f: - return json.load(f) - - -def add_extension(path): - if os.path.exists(path+'.jpg'): - return path+'.jpg' - elif os.path.exists(path+'.png'): - return path+'.png' - else: - raise RuntimeError('No file "%s" with extension png or jpg.' % path) - - -def get_paths(lfw_dir, pairs): - nrof_skipped_pairs = 0 - path_list = [] - issame_list = [] - for pair in pairs: - if len(pair) == 3: - path0 = add_extension(os.path.join(lfw_dir, pair[0], pair[0] + '_' + '%04d' % int(pair[1]))) - path1 = add_extension(os.path.join(lfw_dir, pair[0], pair[0] + '_' + '%04d' % int(pair[2]))) - issame = True - elif len(pair) == 4: - path0 = add_extension(os.path.join(lfw_dir, pair[0], pair[0] + '_' + '%04d' % int(pair[1]))) - path1 = add_extension(os.path.join(lfw_dir, pair[2], pair[2] + '_' + '%04d' % int(pair[3]))) - issame = False - if os.path.exists(path0) and os.path.exists(path1): # Only add the pair if both paths exist - path_list += (path0, path1) - issame_list.append(issame) - else: - nrof_skipped_pairs += 1 - if nrof_skipped_pairs > 0: - print('Skipped %d image pairs' % nrof_skipped_pairs) - - return path_list, issame_list - - -def face_postprocess(crop_paths, result_dir): - num_bins = len(os.listdir(result_dir)) - embeddings = [] - flag_file = os.path.join(result_dir, "{}_output_0.bin".format(0)) - for idx in tqdm(range(num_bins)): - if not os.path.exists(flag_file): - xb_path = os.path.join(result_dir, "{}_1.bin".format(idx)) - else: - xb_path = os.path.join(result_dir, "{}_output_0.bin".format(idx)) - xb_data = np.fromfile(xb_path, dtype=np.float32).reshape(-1, 512) - embeddings.extend(xb_data) - - embeddings_dict = dict(zip(crop_paths, embeddings)) - return embeddings_dict - - -def evaluate(embeddings, actual_issame, nrof_folds=10, distance_metric=0, subtract_mean=False): - # Calculate evaluation metrics - thresholds = np.arange(0, 4, 0.01) - embeddings1 = embeddings[0::2] - embeddings2 = embeddings[1::2] - tpr, fpr, accuracy, fp, fn = calculate_roc(thresholds, embeddings1, embeddings2, - np.asarray(actual_issame), nrof_folds=nrof_folds, distance_metric=distance_metric, subtract_mean=subtract_mean) - thresholds = np.arange(0, 4, 0.001) - val, val_std, far = calculate_val(thresholds, embeddings1, embeddings2, - np.asarray(actual_issame), 1e-3, nrof_folds=nrof_folds, distance_metric=distance_metric, subtract_mean=subtract_mean) - return tpr, fpr, accuracy, val, val_std, far, fp, fn - - -def calculate_roc(thresholds, embeddings1, embeddings2, actual_issame, nrof_folds=10, distance_metric=0, subtract_mean=False): - assert(embeddings1.shape[0] == embeddings2.shape[0]) - assert(embeddings1.shape[1] == embeddings2.shape[1]) - nrof_pairs = min(len(actual_issame), embeddings1.shape[0]) - nrof_thresholds = len(thresholds) - k_fold = KFold(n_splits=nrof_folds, shuffle=False) - - tprs = np.zeros((nrof_folds,nrof_thresholds)) - fprs = np.zeros((nrof_folds,nrof_thresholds)) - accuracy = np.zeros((nrof_folds)) - - is_false_positive = [] - is_false_negative = [] - - indices = np.arange(nrof_pairs) - - for fold_idx, (train_set, test_set) in enumerate(k_fold.split(indices)): - if subtract_mean: - mean = np.mean(np.concatenate([embeddings1[train_set], embeddings2[train_set]]), axis=0) - else: - mean = 0.0 - dist = distance(embeddings1-mean, embeddings2-mean, distance_metric) - - # Find the best threshold for the fold - acc_train = np.zeros((nrof_thresholds)) - for threshold_idx, threshold in enumerate(thresholds): - _, _, acc_train[threshold_idx], _, _ = calculate_accuracy(threshold, dist[train_set], actual_issame[train_set]) - best_threshold_index = np.argmax(acc_train) - for threshold_idx, threshold in enumerate(thresholds): - tprs[fold_idx, threshold_idx], fprs[fold_idx, threshold_idx], _, _, _ = calculate_accuracy(threshold, dist[test_set], actual_issame[test_set]) - _, _, accuracy[fold_idx], is_fp, is_fn = calculate_accuracy(thresholds[best_threshold_index], dist[test_set], actual_issame[test_set]) - - tpr = np.mean(tprs, 0) - fpr = np.mean(fprs, 0) - is_false_positive.extend(is_fp) - is_false_negative.extend(is_fn) - - return tpr, fpr, accuracy, is_false_positive, is_false_negative - - -def calculate_accuracy(threshold, dist, actual_issame): - predict_issame = np.less(dist, threshold) - tp = np.sum(np.logical_and(predict_issame, actual_issame)) - fp = np.sum(np.logical_and(predict_issame, np.logical_not(actual_issame))) - tn = np.sum(np.logical_and(np.logical_not(predict_issame), np.logical_not(actual_issame))) - fn = np.sum(np.logical_and(np.logical_not(predict_issame), actual_issame)) - - is_fp = np.logical_and(predict_issame, np.logical_not(actual_issame)) - is_fn = np.logical_and(np.logical_not(predict_issame), actual_issame) - - tpr = 0 if (tp + fn == 0) else float(tp) / float(tp+fn) - fpr = 0 if (fp + tn == 0) else float(fp) / float(fp+tn) - acc = float(tp+tn)/dist.size - return tpr, fpr, acc, is_fp, is_fn - - -def calculate_val(thresholds, embeddings1, embeddings2, actual_issame, far_target, nrof_folds=10, distance_metric=0, subtract_mean=False): - assert(embeddings1.shape[0] == embeddings2.shape[0]) - assert(embeddings1.shape[1] == embeddings2.shape[1]) - nrof_pairs = min(len(actual_issame), embeddings1.shape[0]) - nrof_thresholds = len(thresholds) - k_fold = KFold(n_splits=nrof_folds, shuffle=False) - - val = np.zeros(nrof_folds) - far = np.zeros(nrof_folds) - - indices = np.arange(nrof_pairs) - - for fold_idx, (train_set, test_set) in enumerate(k_fold.split(indices)): - if subtract_mean: - mean = np.mean(np.concatenate([embeddings1[train_set], embeddings2[train_set]]), axis=0) - else: - mean = 0.0 - dist = distance(embeddings1-mean, embeddings2-mean, distance_metric) - - # Find the threshold that gives FAR = far_target - far_train = np.zeros(nrof_thresholds) - for threshold_idx, threshold in enumerate(thresholds): - _, far_train[threshold_idx] = calculate_val_far(threshold, dist[train_set], actual_issame[train_set]) - if np.max(far_train)>=far_target: - f = interpolate.interp1d(far_train, thresholds, kind='slinear') - threshold = f(far_target) - else: - threshold = 0.0 - - val[fold_idx], far[fold_idx] = calculate_val_far(threshold, dist[test_set], actual_issame[test_set]) - - val_mean = np.mean(val) - far_mean = np.mean(far) - val_std = np.std(val) - return val_mean, val_std, far_mean - - -def distance(embeddings1, embeddings2, distance_metric=0): - if distance_metric==0: - # Euclidian distance - diff = np.subtract(embeddings1, embeddings2) - dist = np.sum(np.square(diff),1) - elif distance_metric==1: - # Distance based on cosine similarity - dot = np.sum(np.multiply(embeddings1, embeddings2), axis=1) - norm = np.linalg.norm(embeddings1, axis=1) * np.linalg.norm(embeddings2, axis=1) - similarity = dot / norm - dist = np.arccos(similarity) / math.pi - else: - raise 'Undefined distance metric %d' % distance_metric - - return dist - - -def calculate_val_far(threshold, dist, actual_issame): - predict_issame = np.less(dist, threshold) - true_accept = np.sum(np.logical_and(predict_issame, actual_issame)) - false_accept = np.sum(np.logical_and(predict_issame, np.logical_not(actual_issame))) - n_same = np.sum(actual_issame) - n_diff = np.sum(np.logical_not(actual_issame)) - val = float(true_accept) / float(n_same) - far = float(false_accept) / float(n_diff) - return val, far - - -if __name__ == '__main__': - pairs_path = './data/pairs.txt' - parser = argparse.ArgumentParser() - parser.add_argument('--crop_dir', type=str, help='cropped image save path') - parser.add_argument('--test_dir', type=str, help='test file path') - parser.add_argument('--ONet_output_dir', type=str, help='preprocess bin files save path') - arg = parser.parse_args() - embedding_output_path = arg.test_dir - pairs = read_pairs(pairs_path) - crop_paths = load_json(arg.ONet_output_dir) - crop_dir = arg.crop_dir - path_list, _ = get_paths(crop_dir, pairs) - embeddings_dict = face_postprocess(crop_paths, embedding_output_path) - embeddings = np.array([embeddings_dict['./' + os.path.relpath(path)] for path in path_list]) - path_list, issame_list = get_paths(crop_dir, pairs) - tpr, fpr, accuracy, val, val_std, far, fp, fn = evaluate(embeddings, issame_list) - print("accuracy:", accuracy) - print("mean accuracy:", np.mean(accuracy)) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import os +import sys +import json +import math +import numpy as np +from tqdm import tqdm +from scipy import interpolate +from sklearn.model_selection import KFold +from FaceNet_preprocess import read_pairs + + +def load_json(json_path): + with open(json_path) as f: + return json.load(f) + + +def add_extension(path): + if os.path.exists(path+'.jpg'): + return path+'.jpg' + elif os.path.exists(path+'.png'): + return path+'.png' + else: + raise RuntimeError('No file "%s" with extension png or jpg.' % path) + + +def get_paths(lfw_dir, pairs): + nrof_skipped_pairs = 0 + path_list = [] + issame_list = [] + for pair in pairs: + if len(pair) == 3: + path0 = add_extension(os.path.join(lfw_dir, pair[0], pair[0] + '_' + '%04d' % int(pair[1]))) + path1 = add_extension(os.path.join(lfw_dir, pair[0], pair[0] + '_' + '%04d' % int(pair[2]))) + issame = True + elif len(pair) == 4: + path0 = add_extension(os.path.join(lfw_dir, pair[0], pair[0] + '_' + '%04d' % int(pair[1]))) + path1 = add_extension(os.path.join(lfw_dir, pair[2], pair[2] + '_' + '%04d' % int(pair[3]))) + issame = False + if os.path.exists(path0) and os.path.exists(path1): # Only add the pair if both paths exist + path_list += (path0, path1) + issame_list.append(issame) + else: + nrof_skipped_pairs += 1 + if nrof_skipped_pairs > 0: + print('Skipped %d image pairs' % nrof_skipped_pairs) + + return path_list, issame_list + + +def face_postprocess(crop_paths, result_dir): + num_bins = len(os.listdir(result_dir)) + embeddings = [] + flag_file = os.path.join(result_dir, "{}_output_0.bin".format(0)) + for idx in tqdm(range(num_bins)): + if not os.path.exists(flag_file): + xb_path = os.path.join(result_dir, "{}_1.bin".format(idx)) + else: + xb_path = os.path.join(result_dir, "{}_output_0.bin".format(idx)) + xb_data = np.fromfile(xb_path, dtype=np.float32).reshape(-1, 512) + embeddings.extend(xb_data) + + embeddings_dict = dict(zip(crop_paths, embeddings)) + return embeddings_dict + + +def evaluate(embeddings, actual_issame, nrof_folds=10, distance_metric=0, subtract_mean=False): + # Calculate evaluation metrics + thresholds = np.arange(0, 4, 0.01) + embeddings1 = embeddings[0::2] + embeddings2 = embeddings[1::2] + tpr, fpr, accuracy, fp, fn = calculate_roc(thresholds, embeddings1, embeddings2, + np.asarray(actual_issame), nrof_folds=nrof_folds, distance_metric=distance_metric, subtract_mean=subtract_mean) + thresholds = np.arange(0, 4, 0.001) + val, val_std, far = calculate_val(thresholds, embeddings1, embeddings2, + np.asarray(actual_issame), 1e-3, nrof_folds=nrof_folds, distance_metric=distance_metric, subtract_mean=subtract_mean) + return tpr, fpr, accuracy, val, val_std, far, fp, fn + + +def calculate_roc(thresholds, embeddings1, embeddings2, actual_issame, nrof_folds=10, distance_metric=0, subtract_mean=False): + assert(embeddings1.shape[0] == embeddings2.shape[0]) + assert(embeddings1.shape[1] == embeddings2.shape[1]) + nrof_pairs = min(len(actual_issame), embeddings1.shape[0]) + nrof_thresholds = len(thresholds) + k_fold = KFold(n_splits=nrof_folds, shuffle=False) + + tprs = np.zeros((nrof_folds,nrof_thresholds)) + fprs = np.zeros((nrof_folds,nrof_thresholds)) + accuracy = np.zeros((nrof_folds)) + + is_false_positive = [] + is_false_negative = [] + + indices = np.arange(nrof_pairs) + + for fold_idx, (train_set, test_set) in enumerate(k_fold.split(indices)): + if subtract_mean: + mean = np.mean(np.concatenate([embeddings1[train_set], embeddings2[train_set]]), axis=0) + else: + mean = 0.0 + dist = distance(embeddings1-mean, embeddings2-mean, distance_metric) + + # Find the best threshold for the fold + acc_train = np.zeros((nrof_thresholds)) + for threshold_idx, threshold in enumerate(thresholds): + _, _, acc_train[threshold_idx], _, _ = calculate_accuracy(threshold, dist[train_set], actual_issame[train_set]) + best_threshold_index = np.argmax(acc_train) + for threshold_idx, threshold in enumerate(thresholds): + tprs[fold_idx, threshold_idx], fprs[fold_idx, threshold_idx], _, _, _ = calculate_accuracy(threshold, dist[test_set], actual_issame[test_set]) + _, _, accuracy[fold_idx], is_fp, is_fn = calculate_accuracy(thresholds[best_threshold_index], dist[test_set], actual_issame[test_set]) + + tpr = np.mean(tprs, 0) + fpr = np.mean(fprs, 0) + is_false_positive.extend(is_fp) + is_false_negative.extend(is_fn) + + return tpr, fpr, accuracy, is_false_positive, is_false_negative + + +def calculate_accuracy(threshold, dist, actual_issame): + predict_issame = np.less(dist, threshold) + tp = np.sum(np.logical_and(predict_issame, actual_issame)) + fp = np.sum(np.logical_and(predict_issame, np.logical_not(actual_issame))) + tn = np.sum(np.logical_and(np.logical_not(predict_issame), np.logical_not(actual_issame))) + fn = np.sum(np.logical_and(np.logical_not(predict_issame), actual_issame)) + + is_fp = np.logical_and(predict_issame, np.logical_not(actual_issame)) + is_fn = np.logical_and(np.logical_not(predict_issame), actual_issame) + + tpr = 0 if (tp + fn == 0) else float(tp) / float(tp+fn) + fpr = 0 if (fp + tn == 0) else float(fp) / float(fp+tn) + acc = float(tp+tn)/dist.size + return tpr, fpr, acc, is_fp, is_fn + + +def calculate_val(thresholds, embeddings1, embeddings2, actual_issame, far_target, nrof_folds=10, distance_metric=0, subtract_mean=False): + assert(embeddings1.shape[0] == embeddings2.shape[0]) + assert(embeddings1.shape[1] == embeddings2.shape[1]) + nrof_pairs = min(len(actual_issame), embeddings1.shape[0]) + nrof_thresholds = len(thresholds) + k_fold = KFold(n_splits=nrof_folds, shuffle=False) + + val = np.zeros(nrof_folds) + far = np.zeros(nrof_folds) + + indices = np.arange(nrof_pairs) + + for fold_idx, (train_set, test_set) in enumerate(k_fold.split(indices)): + if subtract_mean: + mean = np.mean(np.concatenate([embeddings1[train_set], embeddings2[train_set]]), axis=0) + else: + mean = 0.0 + dist = distance(embeddings1-mean, embeddings2-mean, distance_metric) + + # Find the threshold that gives FAR = far_target + far_train = np.zeros(nrof_thresholds) + for threshold_idx, threshold in enumerate(thresholds): + _, far_train[threshold_idx] = calculate_val_far(threshold, dist[train_set], actual_issame[train_set]) + if np.max(far_train)>=far_target: + f = interpolate.interp1d(far_train, thresholds, kind='slinear') + threshold = f(far_target) + else: + threshold = 0.0 + + val[fold_idx], far[fold_idx] = calculate_val_far(threshold, dist[test_set], actual_issame[test_set]) + + val_mean = np.mean(val) + far_mean = np.mean(far) + val_std = np.std(val) + return val_mean, val_std, far_mean + + +def distance(embeddings1, embeddings2, distance_metric=0): + if distance_metric==0: + # Euclidian distance + diff = np.subtract(embeddings1, embeddings2) + dist = np.sum(np.square(diff),1) + elif distance_metric==1: + # Distance based on cosine similarity + dot = np.sum(np.multiply(embeddings1, embeddings2), axis=1) + norm = np.linalg.norm(embeddings1, axis=1) * np.linalg.norm(embeddings2, axis=1) + similarity = dot / norm + dist = np.arccos(similarity) / math.pi + else: + raise 'Undefined distance metric %d' % distance_metric + + return dist + + +def calculate_val_far(threshold, dist, actual_issame): + predict_issame = np.less(dist, threshold) + true_accept = np.sum(np.logical_and(predict_issame, actual_issame)) + false_accept = np.sum(np.logical_and(predict_issame, np.logical_not(actual_issame))) + n_same = np.sum(actual_issame) + n_diff = np.sum(np.logical_not(actual_issame)) + val = float(true_accept) / float(n_same) + far = float(false_accept) / float(n_diff) + return val, far + + +if __name__ == '__main__': + pairs_path = './data/pairs.txt' + parser = argparse.ArgumentParser() + parser.add_argument('--crop_dir', type=str, help='cropped image save path') + parser.add_argument('--test_dir', type=str, help='test file path') + parser.add_argument('--ONet_output_dir', type=str, help='preprocess bin files save path') + arg = parser.parse_args() + embedding_output_path = arg.test_dir + pairs = read_pairs(pairs_path) + crop_paths = load_json(arg.ONet_output_dir) + crop_dir = arg.crop_dir + path_list, _ = get_paths(crop_dir, pairs) + embeddings_dict = face_postprocess(crop_paths, embedding_output_path) + embeddings = np.array([embeddings_dict['./' + os.path.relpath(path)] for path in path_list]) + path_list, issame_list = get_paths(crop_dir, pairs) + tpr, fpr, accuracy, val, val_std, far, fp, fn = evaluate(embeddings, issame_list) + print("accuracy:", accuracy) + print("mean accuracy:", np.mean(accuracy)) diff --git a/ACL_PyTorch/contrib/cv/face/FaceNet/FaceNet_preprocess.py b/ACL_PyTorch/contrib/cv/face/FaceNet/FaceNet_preprocess.py index 64a7a3aeed..fe26bba8c9 100644 --- a/ACL_PyTorch/contrib/cv/face/FaceNet/FaceNet_preprocess.py +++ b/ACL_PyTorch/contrib/cv/face/FaceNet/FaceNet_preprocess.py @@ -1,73 +1,73 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import sys -import os -import torch -import numpy as np -from tqdm import tqdm -from torchvision import datasets, transforms -from facenet_pytorch import fixed_image_standardization -from torch.utils.data import DataLoader, SequentialSampler - - -def read_pairs(pairs_filename): - pairs = [] - with open(pairs_filename, 'r') as f: - for line in f.readlines()[1:]: - pair = line.strip().split() - pairs.append(pair) - return np.array(pairs, dtype=object) - - -def face_preprocess(crop_dir, save_dir): - # create dataset and data loaders from cropped images output from MTCNN - trans = transforms.Compose([ - np.float32, - transforms.ToTensor(), - fixed_image_standardization - ]) - dataset = datasets.ImageFolder(crop_dir, transform=trans) - - embed_loader = DataLoader( - dataset, - num_workers=workers, - batch_size=batch_size, - sampler=SequentialSampler(dataset) - ) - - for idx, (xb, yb) in tqdm(enumerate(embed_loader)): - out_path_xb = os.path.join(save_dir, 'xb_results', '{}.bin'.format(idx)) - out_path_yb = os.path.join(save_dir, 'yb_results', '{}.bin'.format(idx)) - os.makedirs(os.path.dirname(out_path_xb), exist_ok=True) - os.makedirs(os.path.dirname(out_path_yb), exist_ok=True) - if xb.shape[0] < batch_size: - xb_zeros = np.zeros([batch_size - int(xb.shape[0]), int(xb.shape[1]), int(xb.shape[2]), int(xb.shape[3])]) - xb = np.concatenate([xb.numpy(), xb_zeros], axis=0) - xb = torch.from_numpy(xb) - xb.detach().cpu().numpy().tofile(out_path_xb) - yb.detach().cpu().numpy().tofile(out_path_yb) - - -if __name__ == '__main__': - pairs_path = './data/pairs.txt' - parser = argparse.ArgumentParser() - parser.add_argument('--crop_dir', type=str, help='cropped image save path') - parser.add_argument('--save_dir', type=str, help='preprocess bin files save path') - parser.add_argument('--batch_size', type=int, help='preprocess bin files save path') - arg = parser.parse_args() - batch_size = arg.batch_size - workers = 0 if os.name == 'nt' else 8 - pairs = read_pairs(pairs_path) - face_preprocess(arg.crop_dir, arg.save_dir) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import sys +import os +import torch +import numpy as np +from tqdm import tqdm +from torchvision import datasets, transforms +from facenet_pytorch import fixed_image_standardization +from torch.utils.data import DataLoader, SequentialSampler + + +def read_pairs(pairs_filename): + pairs = [] + with open(pairs_filename, 'r') as f: + for line in f.readlines()[1:]: + pair = line.strip().split() + pairs.append(pair) + return np.array(pairs, dtype=object) + + +def face_preprocess(crop_dir, save_dir): + # create dataset and data loaders from cropped images output from MTCNN + trans = transforms.Compose([ + np.float32, + transforms.ToTensor(), + fixed_image_standardization + ]) + dataset = datasets.ImageFolder(crop_dir, transform=trans) + + embed_loader = DataLoader( + dataset, + num_workers=workers, + batch_size=batch_size, + sampler=SequentialSampler(dataset) + ) + + for idx, (xb, yb) in tqdm(enumerate(embed_loader)): + out_path_xb = os.path.join(save_dir, 'xb_results', '{}.bin'.format(idx)) + out_path_yb = os.path.join(save_dir, 'yb_results', '{}.bin'.format(idx)) + os.makedirs(os.path.dirname(out_path_xb), exist_ok=True) + os.makedirs(os.path.dirname(out_path_yb), exist_ok=True) + if xb.shape[0] < batch_size: + xb_zeros = np.zeros([batch_size - int(xb.shape[0]), int(xb.shape[1]), int(xb.shape[2]), int(xb.shape[3])]) + xb = np.concatenate([xb.numpy(), xb_zeros], axis=0) + xb = torch.from_numpy(xb) + xb.detach().cpu().numpy().tofile(out_path_xb) + yb.detach().cpu().numpy().tofile(out_path_yb) + + +if __name__ == '__main__': + pairs_path = './data/pairs.txt' + parser = argparse.ArgumentParser() + parser.add_argument('--crop_dir', type=str, help='cropped image save path') + parser.add_argument('--save_dir', type=str, help='preprocess bin files save path') + parser.add_argument('--batch_size', type=int, help='preprocess bin files save path') + arg = parser.parse_args() + batch_size = arg.batch_size + workers = 0 if os.name == 'nt' else 8 + pairs = read_pairs(pairs_path) + face_preprocess(arg.crop_dir, arg.save_dir) diff --git a/ACL_PyTorch/contrib/cv/face/FaceNet/FaceNet_pth2onnx.py b/ACL_PyTorch/contrib/cv/face/FaceNet/FaceNet_pth2onnx.py index 1d2b916c3c..6d886b0965 100644 --- a/ACL_PyTorch/contrib/cv/face/FaceNet/FaceNet_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/face/FaceNet/FaceNet_pth2onnx.py @@ -1,46 +1,46 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 facenet_pytorch import InceptionResnetV1 -import torch -import argparse - - -def FaceNet_pth2onnx(opt): - model = InceptionResnetV1(pretrained=opt.pretrain) - # if opt.model != '': - # model.load_state_dict(torch.load(opt.model, map_location='cpu')) - # else: - # print("Error network") - # return -1 - model.eval() - input_names = ["image"] - output_names = ["class"] - output_file = opt.output_file - if opt.output_file == '.': - output_file = opt.output_file - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.randn(16, 3, 160, 160) - - torch.onnx.export(model, dummy_input, output_file, input_names=input_names, dynamic_axes=dynamic_axes, - output_names=output_names, verbose=True, opset_version=10) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--pretrain', type=str, default='vggface2', help='[casia-webface, vggface2]') - parser.add_argument('--model', type=str, help='model path') - parser.add_argument('--output_file', type=str, default='.', help='output path') - arg = parser.parse_args() - FaceNet_pth2onnx(arg) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 facenet_pytorch import InceptionResnetV1 +import torch +import argparse + + +def FaceNet_pth2onnx(opt): + model = InceptionResnetV1(pretrained=opt.pretrain) + # if opt.model != '': + # model.load_state_dict(torch.load(opt.model, map_location='cpu')) + # else: + # print("Error network") + # return -1 + model.eval() + input_names = ["image"] + output_names = ["class"] + output_file = opt.output_file + if opt.output_file == '.': + output_file = opt.output_file + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.randn(16, 3, 160, 160) + + torch.onnx.export(model, dummy_input, output_file, input_names=input_names, dynamic_axes=dynamic_axes, + output_names=output_names, verbose=True, opset_version=10) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--pretrain', type=str, default='vggface2', help='[casia-webface, vggface2]') + parser.add_argument('--model', type=str, help='model path') + parser.add_argument('--output_file', type=str, default='.', help='output path') + arg = parser.parse_args() + FaceNet_pth2onnx(arg) diff --git a/ACL_PyTorch/contrib/cv/face/FaceNet/LICENSE b/ACL_PyTorch/contrib/cv/face/FaceNet/LICENSE index 2d284555aa..2e03f7211c 100644 --- a/ACL_PyTorch/contrib/cv/face/FaceNet/LICENSE +++ b/ACL_PyTorch/contrib/cv/face/FaceNet/LICENSE @@ -1,55 +1,55 @@ -MIT License - -Copyright (c) 2019 Timothy Esler - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ - - +MIT License + +Copyright (c) 2019 Timothy Esler + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ + + diff --git a/ACL_PyTorch/contrib/cv/face/FaceNet/MTCNN_preprocess.py b/ACL_PyTorch/contrib/cv/face/FaceNet/MTCNN_preprocess.py index 520e8d0a76..f758632545 100644 --- a/ACL_PyTorch/contrib/cv/face/FaceNet/MTCNN_preprocess.py +++ b/ACL_PyTorch/contrib/cv/face/FaceNet/MTCNN_preprocess.py @@ -1,367 +1,367 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import json -import torch -import argparse -import numpy as np -from easydict import EasyDict -from torch.utils.data import DataLoader -from torchvision import datasets -from tqdm import tqdm -sys.path.append('./models') -from mtcnn import PNet, RNet, ONet -from facenet_pytorch import MTCNN -from facenet_pytorch.models.utils.detect_face import imresample, generateBoundingBox, batched_nms, rerec, pad, bbreg, batched_nms_numpy - - -NET_MAP = { - 'pnet': PNet, - 'rnet': RNet, - 'onet': ONet -} - -################################################################################### -# basic function # -################################################################################### - -def build_dataset(config): - orig_img_ds = datasets.ImageFolder(config.data_dir, transform=None) - orig_img_ds.samples = [(p, p)for p, _ in orig_img_ds.samples] - def collate_fn(x): - out_x, out_y = [], [] - for xx, yy in x: - out_x.append(xx) - out_y.append(yy) - return out_x, out_y - loader = DataLoader( - orig_img_ds, - num_workers=config.num_workers, - batch_size=config.batch_size, - collate_fn=collate_fn - ) - return loader - - -def dump_to_json(content, outpath): - os.makedirs(os.path.dirname(outpath), exist_ok=True) - with open(outpath, 'w') as f: - json.dump(content, f) - - -def load_json(json_path): - with open(json_path) as f: - return json.load(f) - - -################################################################################### -# main class # -################################################################################### -class MTCNNPreprocessor(): - def __init__(self, config): - self.net_name = config.net - self.net = NET_MAP[self.net_name](config) - self.threshold = [0.6, 0.7, 0.7] - self.data_device = torch.device('cpu') - - def pnet_process(self, imgs): - if self.net_name != 'pnet': - raise ValueError('Pnet process not support for {} !'.format(self.net)) - - factor = 0.709 - minsize = 20 - - imgs = imgs.permute(0, 3, 1, 2).type(torch.float32) - batch_size = len(imgs) - h, w = imgs.shape[2:4] - m = 12.0 / minsize - minl = min(h, w) - minl = minl * m - - scale_i = m - scales = [] - while minl >= 12: - scales.append(scale_i) - scale_i = scale_i * factor - minl = minl * factor - # First stage - boxes = [] - image_inds = [] - scale_picks = [] - all_i = 0 - offset = 0 - for scale in scales: - im_data = imresample(imgs, (int(h * scale + 1), int(w * scale + 1))) - im_data = (im_data - 127.5) * 0.0078125 - reg, probs = self.net.forward(im_data.cpu().numpy()) - reg = torch.from_numpy(reg) - probs = torch.from_numpy(probs) - boxes_scale, image_inds_scale = generateBoundingBox(reg, probs[:, 1], scale, self.threshold[0]) - boxes.append(boxes_scale) - image_inds.append(image_inds_scale) - pick = batched_nms(boxes_scale[:, :4], boxes_scale[:, 4], image_inds_scale, 0.5) - scale_picks.append(pick + offset) - offset += boxes_scale.shape[0] - boxes = torch.cat(boxes, dim=0) - image_inds = torch.cat(image_inds, dim=0) - scale_picks = torch.cat(scale_picks, dim=0) - # NMS within each scale + image - boxes, image_inds = boxes[scale_picks], image_inds[scale_picks] - # NMS within each image - pick = batched_nms(boxes[:, :4], boxes[:, 4], image_inds, 0.7) - boxes, image_inds = boxes[pick], image_inds[pick] - regw = boxes[:, 2] - boxes[:, 0] - regh = boxes[:, 3] - boxes[:, 1] - qq1 = boxes[:, 0] + boxes[:, 5] * regw - qq2 = boxes[:, 1] + boxes[:, 6] * regh - qq3 = boxes[:, 2] + boxes[:, 7] * regw - qq4 = boxes[:, 3] + boxes[:, 8] * regh - boxes = torch.stack([qq1, qq2, qq3, qq4, boxes[:, 4]]).permute(1, 0) - boxes = rerec(boxes) - return boxes, image_inds - - def rnet_process(self, imgs, boxes, image_inds): - if self.net_name != 'rnet': - raise ValueError('Rnet process not support for {} !'.format(self.net)) - imgs = imgs.permute(0, 3, 1, 2).type(torch.float32) - h, w = imgs.shape[2:4] - y, ey, x, ex = pad(boxes, w, h) - if len(boxes) > 0: - im_data = [] - for k in range(len(y)): - if ey[k] > (y[k] - 1) and ex[k] > (x[k] - 1): - img_k = imgs[image_inds[k], :, (y[k] - 1):ey[k], (x[k] - 1):ex[k]].unsqueeze(0) - im_data.append(imresample(img_k, (24, 24))) - im_data = torch.cat(im_data, dim=0) - im_data = (im_data - 127.5) * 0.0078125 - out = self.net.forward(im_data.cpu().numpy()) - out = [torch.from_numpy(o) for o in out] - out0 = out[0].permute(1, 0) - out1 = out[1].permute(1, 0) - score = out1[1, :] - ipass = score > self.threshold[1] - boxes = torch.cat((boxes[ipass, :4], score[ipass].unsqueeze(1)), dim=1) - image_inds = image_inds[ipass] - mv = out0[:, ipass].permute(1, 0) - # NMS within each image - pick = batched_nms(boxes[:, :4], boxes[:, 4], image_inds, 0.7) - boxes, image_inds, mv = boxes[pick], image_inds[pick], mv[pick] - boxes = bbreg(boxes, mv) - boxes = rerec(boxes) - return boxes, image_inds - - def onet_process(self, imgs, boxes, image_inds): - if self.net_name != 'onet': - raise ValueError('Onet process not support for {} !'.format(self.net)) - imgs = imgs.permute(0, 3, 1, 2).type(torch.float32) - h, w = imgs.shape[2:4] - points = torch.zeros(0, 5, 2, device=self.data_device) - if len(boxes) > 0: - y, ey, x, ex = pad(boxes, w, h) - im_data = [] - for k in range(len(y)): - if ey[k] > (y[k] - 1) and ex[k] > (x[k] - 1): - img_k = imgs[image_inds[k], :, (y[k] - 1):ey[k], (x[k] - 1):ex[k]].unsqueeze(0) - im_data.append(imresample(img_k, (48, 48))) - im_data = torch.cat(im_data, dim=0) - im_data = (im_data - 127.5) * 0.0078125 - out = self.net.forward(im_data.cpu().numpy()) - out = [torch.from_numpy(o) for o in out] - out0 = out[0].permute(1, 0) - out1 = out[1].permute(1, 0) - out2 = out[2].permute(1, 0) - score = out2[1, :] - points = out1 - ipass = score > self.threshold[2] - points = points[:, ipass] - boxes = torch.cat((boxes[ipass, :4], score[ipass].unsqueeze(1)), dim=1) - image_inds = image_inds[ipass] - mv = out0[:, ipass].permute(1, 0) - w_i = boxes[:, 2] - boxes[:, 0] + 1 - h_i = boxes[:, 3] - boxes[:, 1] + 1 - points_x = w_i.repeat(5, 1) * points[:5, :] + boxes[:, 0].repeat(5, 1) - 1 - points_y = h_i.repeat(5, 1) * points[5:10, :] + boxes[:, 1].repeat(5, 1) - 1 - points = torch.stack((points_x, points_y)).permute(2, 1, 0) - boxes = bbreg(boxes, mv) - # NMS within each image using "Min" strategy - # pick = batched_nms(boxes[:, :4], boxes[:, 4], image_inds, 0.7) - pick = batched_nms_numpy(boxes[:, :4], boxes[:, 4], image_inds, 0.7, 'Min') - boxes, image_inds, points = boxes[pick], image_inds[pick], points[pick] - - boxes = boxes.cpu().numpy() - points = points.cpu().numpy() - image_inds = image_inds.cpu() - batch_boxes = [] - batch_points = [] - for b_i in range(config.batch_size): - b_i_inds = np.where(image_inds == b_i) - batch_boxes.append(boxes[b_i_inds].copy()) - batch_points.append(points[b_i_inds].copy()) - batch_boxes, batch_points = np.array(batch_boxes), np.array(batch_points) - return batch_boxes, batch_points - - -################################################################################### -# main function # -################################################################################### -def process_pnet(config): - loader = build_dataset(config) - processor = MTCNNPreprocessor(config) - out_json = {} - for idx, (xs, b_paths) in tqdm(enumerate(loader), total=len(loader)): - imgs = np.stack([np.uint8(x) for x in xs]) - imgs = torch.as_tensor(imgs.copy(), device=torch.device('cpu')) - boxes, image_inds = processor.pnet_process(imgs) - out_json[str(idx)] = { - 'boxes': boxes.tolist(), - 'image_inds': image_inds.tolist() - } - save_path = os.path.join(config.output_path, 'pnet.json') - os.makedirs(os.path.dirname(save_path), exist_ok=True) - dump_to_json(out_json, save_path) - - -def process_rnet(config): - loader = build_dataset(config) - processor = MTCNNPreprocessor(config) - out_json = {} - pnet_data = load_json(config.input_path) - for idx, (xs, b_paths) in tqdm(enumerate(loader), total=len(loader)): - imgs = np.stack([np.uint8(x) for x in xs]) - imgs = torch.as_tensor(imgs.copy(), device=torch.device('cpu')) - boxes = torch.from_numpy(np.array(pnet_data[str(idx)]['boxes'])) - image_inds = torch.from_numpy(np.array(pnet_data[str(idx)]['image_inds'])) - boxes, image_inds = processor.rnet_process(imgs, boxes, image_inds) - out_json[str(idx)] = { - 'boxes': boxes.tolist(), - 'image_inds': image_inds.tolist() - } - save_path = os.path.join(config.output_path, 'rnet.json') - os.makedirs(os.path.dirname(save_path), exist_ok=True) - dump_to_json(out_json, save_path) - - -def process_onet(config): - data_dir = config.data_dir - loader = build_dataset(config) - processor = MTCNNPreprocessor(config) - pnet_data = load_json(config.input_path) - crop_paths = [] - for idx, (xs, b_paths) in tqdm(enumerate(loader), total=len(loader)): - imgs = np.stack([np.uint8(x) for x in xs]) - imgs = torch.as_tensor(imgs.copy(), device=torch.device('cpu')) - boxes = torch.from_numpy(np.array(pnet_data[str(idx)]['boxes'])) - image_inds = torch.from_numpy(np.array(pnet_data[str(idx)]['image_inds'])) - batch_boxes, batch_points = processor.onet_process(imgs, boxes, image_inds) - # save crop imgs - save_paths = [p.replace(data_dir, data_dir + '_split_om_cropped_{}'.format(config.batch_size)) for p in b_paths] - save_crop_imgs(batch_boxes, batch_points, xs, save_paths) - crop_paths.extend(save_paths) - save_path = os.path.join(config.output_path, 'onet.json') - os.makedirs(os.path.dirname(save_path), exist_ok=True) - dump_to_json(crop_paths, save_path) - - -def save_crop_imgs(batch_boxes, batch_points, img, save_path): - mtcnn = MTCNN( - image_size=160, margin=14, min_face_size=20, - thresholds=[0.6, 0.7, 0.7], factor=0.709, post_process=True, - selection_method='center_weighted_size' - ) - boxes, probs, points = [], [], [] - for box, point in zip(batch_boxes, batch_points): - box = np.array(box) - point = np.array(point) - if len(box) == 0: - boxes.append(None) - probs.append([None]) - points.append(None) - elif mtcnn.select_largest: - box_order = np.argsort((box[:, 2] - box[:, 0]) * (box[:, 3] - box[:, 1]))[::-1] - box = box[box_order] - point = point[box_order] - boxes.append(box[:, :4]) - probs.append(box[:, 4]) - points.append(point) - else: - boxes.append(box[:, :4]) - probs.append(box[:, 4]) - points.append(point) - batch_boxes = np.array(boxes) - batch_probs = np.array(probs) - batch_points = np.array(points) - - batch_boxes, batch_probs, batch_points = mtcnn.select_boxes( - batch_boxes, batch_probs, batch_points, img, method=mtcnn.selection_method - ) - # Extract faces - faces = mtcnn.extract(img, batch_boxes, save_path) - return faces - - -def parser_args(): - pass - - -def build_config(arg): - pnet_config = { - 'net': 'pnet', - 'device_id': 1, - 'output_path': './data/output/split_bs' + str(arg.batch_size) + '/', - 'model_path': './weights/PNet_dynamic.om', - 'data_dir': './data/lfw', - 'num_workers': 8, - 'batch_size': arg.batch_size - } - rnet_config = { - 'net': 'rnet', - 'device_id': 1, - 'input_path': './data/output/split_bs' + str(arg.batch_size) + '/pnet.json', - 'output_path': './data/output/split_bs' + str(arg.batch_size) + '/', - 'model_path': './weights/RNet_dynamic.om', - 'data_dir': './data/lfw', - 'num_workers': 8, - 'batch_size': arg.batch_size - } - onet_config = { - 'net': 'onet', - 'device_id': 1, - 'input_path': './data/output/split_bs' + str(arg.batch_size) + '/rnet.json', - 'output_path': './data/output/split_bs' + str(arg.batch_size) + '/', - 'model_path': './weights/ONet_dynamic.om', - 'data_dir': './data/lfw', - 'num_workers': 8, - 'batch_size': arg.batch_size - } - return EasyDict(pnet_config), EasyDict(rnet_config), EasyDict(onet_config) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--model', type=str, help='[PNet/RNet/ONet]') - parser.add_argument('--data_dir', type=str, help='the absolute files path of lfw dataset') - parser.add_argument('--batch_size', type=int, help='[1/16]') - arg = parser.parse_args() - pnet_config, rnet_config, onet_config = build_config(arg) - if arg.model == 'Pnet': - config = pnet_config - process_pnet(config) - elif arg.model == 'Rnet': - config = rnet_config - process_rnet(config) - elif arg.model == 'Onet': - config = onet_config - process_onet(config) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import json +import torch +import argparse +import numpy as np +from easydict import EasyDict +from torch.utils.data import DataLoader +from torchvision import datasets +from tqdm import tqdm +sys.path.append('./models') +from mtcnn import PNet, RNet, ONet +from facenet_pytorch import MTCNN +from facenet_pytorch.models.utils.detect_face import imresample, generateBoundingBox, batched_nms, rerec, pad, bbreg, batched_nms_numpy + + +NET_MAP = { + 'pnet': PNet, + 'rnet': RNet, + 'onet': ONet +} + +################################################################################### +# basic function # +################################################################################### + +def build_dataset(config): + orig_img_ds = datasets.ImageFolder(config.data_dir, transform=None) + orig_img_ds.samples = [(p, p)for p, _ in orig_img_ds.samples] + def collate_fn(x): + out_x, out_y = [], [] + for xx, yy in x: + out_x.append(xx) + out_y.append(yy) + return out_x, out_y + loader = DataLoader( + orig_img_ds, + num_workers=config.num_workers, + batch_size=config.batch_size, + collate_fn=collate_fn + ) + return loader + + +def dump_to_json(content, outpath): + os.makedirs(os.path.dirname(outpath), exist_ok=True) + with open(outpath, 'w') as f: + json.dump(content, f) + + +def load_json(json_path): + with open(json_path) as f: + return json.load(f) + + +################################################################################### +# main class # +################################################################################### +class MTCNNPreprocessor(): + def __init__(self, config): + self.net_name = config.net + self.net = NET_MAP[self.net_name](config) + self.threshold = [0.6, 0.7, 0.7] + self.data_device = torch.device('cpu') + + def pnet_process(self, imgs): + if self.net_name != 'pnet': + raise ValueError('Pnet process not support for {} !'.format(self.net)) + + factor = 0.709 + minsize = 20 + + imgs = imgs.permute(0, 3, 1, 2).type(torch.float32) + batch_size = len(imgs) + h, w = imgs.shape[2:4] + m = 12.0 / minsize + minl = min(h, w) + minl = minl * m + + scale_i = m + scales = [] + while minl >= 12: + scales.append(scale_i) + scale_i = scale_i * factor + minl = minl * factor + # First stage + boxes = [] + image_inds = [] + scale_picks = [] + all_i = 0 + offset = 0 + for scale in scales: + im_data = imresample(imgs, (int(h * scale + 1), int(w * scale + 1))) + im_data = (im_data - 127.5) * 0.0078125 + reg, probs = self.net.forward(im_data.cpu().numpy()) + reg = torch.from_numpy(reg) + probs = torch.from_numpy(probs) + boxes_scale, image_inds_scale = generateBoundingBox(reg, probs[:, 1], scale, self.threshold[0]) + boxes.append(boxes_scale) + image_inds.append(image_inds_scale) + pick = batched_nms(boxes_scale[:, :4], boxes_scale[:, 4], image_inds_scale, 0.5) + scale_picks.append(pick + offset) + offset += boxes_scale.shape[0] + boxes = torch.cat(boxes, dim=0) + image_inds = torch.cat(image_inds, dim=0) + scale_picks = torch.cat(scale_picks, dim=0) + # NMS within each scale + image + boxes, image_inds = boxes[scale_picks], image_inds[scale_picks] + # NMS within each image + pick = batched_nms(boxes[:, :4], boxes[:, 4], image_inds, 0.7) + boxes, image_inds = boxes[pick], image_inds[pick] + regw = boxes[:, 2] - boxes[:, 0] + regh = boxes[:, 3] - boxes[:, 1] + qq1 = boxes[:, 0] + boxes[:, 5] * regw + qq2 = boxes[:, 1] + boxes[:, 6] * regh + qq3 = boxes[:, 2] + boxes[:, 7] * regw + qq4 = boxes[:, 3] + boxes[:, 8] * regh + boxes = torch.stack([qq1, qq2, qq3, qq4, boxes[:, 4]]).permute(1, 0) + boxes = rerec(boxes) + return boxes, image_inds + + def rnet_process(self, imgs, boxes, image_inds): + if self.net_name != 'rnet': + raise ValueError('Rnet process not support for {} !'.format(self.net)) + imgs = imgs.permute(0, 3, 1, 2).type(torch.float32) + h, w = imgs.shape[2:4] + y, ey, x, ex = pad(boxes, w, h) + if len(boxes) > 0: + im_data = [] + for k in range(len(y)): + if ey[k] > (y[k] - 1) and ex[k] > (x[k] - 1): + img_k = imgs[image_inds[k], :, (y[k] - 1):ey[k], (x[k] - 1):ex[k]].unsqueeze(0) + im_data.append(imresample(img_k, (24, 24))) + im_data = torch.cat(im_data, dim=0) + im_data = (im_data - 127.5) * 0.0078125 + out = self.net.forward(im_data.cpu().numpy()) + out = [torch.from_numpy(o) for o in out] + out0 = out[0].permute(1, 0) + out1 = out[1].permute(1, 0) + score = out1[1, :] + ipass = score > self.threshold[1] + boxes = torch.cat((boxes[ipass, :4], score[ipass].unsqueeze(1)), dim=1) + image_inds = image_inds[ipass] + mv = out0[:, ipass].permute(1, 0) + # NMS within each image + pick = batched_nms(boxes[:, :4], boxes[:, 4], image_inds, 0.7) + boxes, image_inds, mv = boxes[pick], image_inds[pick], mv[pick] + boxes = bbreg(boxes, mv) + boxes = rerec(boxes) + return boxes, image_inds + + def onet_process(self, imgs, boxes, image_inds): + if self.net_name != 'onet': + raise ValueError('Onet process not support for {} !'.format(self.net)) + imgs = imgs.permute(0, 3, 1, 2).type(torch.float32) + h, w = imgs.shape[2:4] + points = torch.zeros(0, 5, 2, device=self.data_device) + if len(boxes) > 0: + y, ey, x, ex = pad(boxes, w, h) + im_data = [] + for k in range(len(y)): + if ey[k] > (y[k] - 1) and ex[k] > (x[k] - 1): + img_k = imgs[image_inds[k], :, (y[k] - 1):ey[k], (x[k] - 1):ex[k]].unsqueeze(0) + im_data.append(imresample(img_k, (48, 48))) + im_data = torch.cat(im_data, dim=0) + im_data = (im_data - 127.5) * 0.0078125 + out = self.net.forward(im_data.cpu().numpy()) + out = [torch.from_numpy(o) for o in out] + out0 = out[0].permute(1, 0) + out1 = out[1].permute(1, 0) + out2 = out[2].permute(1, 0) + score = out2[1, :] + points = out1 + ipass = score > self.threshold[2] + points = points[:, ipass] + boxes = torch.cat((boxes[ipass, :4], score[ipass].unsqueeze(1)), dim=1) + image_inds = image_inds[ipass] + mv = out0[:, ipass].permute(1, 0) + w_i = boxes[:, 2] - boxes[:, 0] + 1 + h_i = boxes[:, 3] - boxes[:, 1] + 1 + points_x = w_i.repeat(5, 1) * points[:5, :] + boxes[:, 0].repeat(5, 1) - 1 + points_y = h_i.repeat(5, 1) * points[5:10, :] + boxes[:, 1].repeat(5, 1) - 1 + points = torch.stack((points_x, points_y)).permute(2, 1, 0) + boxes = bbreg(boxes, mv) + # NMS within each image using "Min" strategy + # pick = batched_nms(boxes[:, :4], boxes[:, 4], image_inds, 0.7) + pick = batched_nms_numpy(boxes[:, :4], boxes[:, 4], image_inds, 0.7, 'Min') + boxes, image_inds, points = boxes[pick], image_inds[pick], points[pick] + + boxes = boxes.cpu().numpy() + points = points.cpu().numpy() + image_inds = image_inds.cpu() + batch_boxes = [] + batch_points = [] + for b_i in range(config.batch_size): + b_i_inds = np.where(image_inds == b_i) + batch_boxes.append(boxes[b_i_inds].copy()) + batch_points.append(points[b_i_inds].copy()) + batch_boxes, batch_points = np.array(batch_boxes), np.array(batch_points) + return batch_boxes, batch_points + + +################################################################################### +# main function # +################################################################################### +def process_pnet(config): + loader = build_dataset(config) + processor = MTCNNPreprocessor(config) + out_json = {} + for idx, (xs, b_paths) in tqdm(enumerate(loader), total=len(loader)): + imgs = np.stack([np.uint8(x) for x in xs]) + imgs = torch.as_tensor(imgs.copy(), device=torch.device('cpu')) + boxes, image_inds = processor.pnet_process(imgs) + out_json[str(idx)] = { + 'boxes': boxes.tolist(), + 'image_inds': image_inds.tolist() + } + save_path = os.path.join(config.output_path, 'pnet.json') + os.makedirs(os.path.dirname(save_path), exist_ok=True) + dump_to_json(out_json, save_path) + + +def process_rnet(config): + loader = build_dataset(config) + processor = MTCNNPreprocessor(config) + out_json = {} + pnet_data = load_json(config.input_path) + for idx, (xs, b_paths) in tqdm(enumerate(loader), total=len(loader)): + imgs = np.stack([np.uint8(x) for x in xs]) + imgs = torch.as_tensor(imgs.copy(), device=torch.device('cpu')) + boxes = torch.from_numpy(np.array(pnet_data[str(idx)]['boxes'])) + image_inds = torch.from_numpy(np.array(pnet_data[str(idx)]['image_inds'])) + boxes, image_inds = processor.rnet_process(imgs, boxes, image_inds) + out_json[str(idx)] = { + 'boxes': boxes.tolist(), + 'image_inds': image_inds.tolist() + } + save_path = os.path.join(config.output_path, 'rnet.json') + os.makedirs(os.path.dirname(save_path), exist_ok=True) + dump_to_json(out_json, save_path) + + +def process_onet(config): + data_dir = config.data_dir + loader = build_dataset(config) + processor = MTCNNPreprocessor(config) + pnet_data = load_json(config.input_path) + crop_paths = [] + for idx, (xs, b_paths) in tqdm(enumerate(loader), total=len(loader)): + imgs = np.stack([np.uint8(x) for x in xs]) + imgs = torch.as_tensor(imgs.copy(), device=torch.device('cpu')) + boxes = torch.from_numpy(np.array(pnet_data[str(idx)]['boxes'])) + image_inds = torch.from_numpy(np.array(pnet_data[str(idx)]['image_inds'])) + batch_boxes, batch_points = processor.onet_process(imgs, boxes, image_inds) + # save crop imgs + save_paths = [p.replace(data_dir, data_dir + '_split_om_cropped_{}'.format(config.batch_size)) for p in b_paths] + save_crop_imgs(batch_boxes, batch_points, xs, save_paths) + crop_paths.extend(save_paths) + save_path = os.path.join(config.output_path, 'onet.json') + os.makedirs(os.path.dirname(save_path), exist_ok=True) + dump_to_json(crop_paths, save_path) + + +def save_crop_imgs(batch_boxes, batch_points, img, save_path): + mtcnn = MTCNN( + image_size=160, margin=14, min_face_size=20, + thresholds=[0.6, 0.7, 0.7], factor=0.709, post_process=True, + selection_method='center_weighted_size' + ) + boxes, probs, points = [], [], [] + for box, point in zip(batch_boxes, batch_points): + box = np.array(box) + point = np.array(point) + if len(box) == 0: + boxes.append(None) + probs.append([None]) + points.append(None) + elif mtcnn.select_largest: + box_order = np.argsort((box[:, 2] - box[:, 0]) * (box[:, 3] - box[:, 1]))[::-1] + box = box[box_order] + point = point[box_order] + boxes.append(box[:, :4]) + probs.append(box[:, 4]) + points.append(point) + else: + boxes.append(box[:, :4]) + probs.append(box[:, 4]) + points.append(point) + batch_boxes = np.array(boxes) + batch_probs = np.array(probs) + batch_points = np.array(points) + + batch_boxes, batch_probs, batch_points = mtcnn.select_boxes( + batch_boxes, batch_probs, batch_points, img, method=mtcnn.selection_method + ) + # Extract faces + faces = mtcnn.extract(img, batch_boxes, save_path) + return faces + + +def parser_args(): + pass + + +def build_config(arg): + pnet_config = { + 'net': 'pnet', + 'device_id': 1, + 'output_path': './data/output/split_bs' + str(arg.batch_size) + '/', + 'model_path': './weights/PNet_dynamic.om', + 'data_dir': './data/lfw', + 'num_workers': 8, + 'batch_size': arg.batch_size + } + rnet_config = { + 'net': 'rnet', + 'device_id': 1, + 'input_path': './data/output/split_bs' + str(arg.batch_size) + '/pnet.json', + 'output_path': './data/output/split_bs' + str(arg.batch_size) + '/', + 'model_path': './weights/RNet_dynamic.om', + 'data_dir': './data/lfw', + 'num_workers': 8, + 'batch_size': arg.batch_size + } + onet_config = { + 'net': 'onet', + 'device_id': 1, + 'input_path': './data/output/split_bs' + str(arg.batch_size) + '/rnet.json', + 'output_path': './data/output/split_bs' + str(arg.batch_size) + '/', + 'model_path': './weights/ONet_dynamic.om', + 'data_dir': './data/lfw', + 'num_workers': 8, + 'batch_size': arg.batch_size + } + return EasyDict(pnet_config), EasyDict(rnet_config), EasyDict(onet_config) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--model', type=str, help='[PNet/RNet/ONet]') + parser.add_argument('--data_dir', type=str, help='the absolute files path of lfw dataset') + parser.add_argument('--batch_size', type=int, help='[1/16]') + arg = parser.parse_args() + pnet_config, rnet_config, onet_config = build_config(arg) + if arg.model == 'Pnet': + config = pnet_config + process_pnet(config) + elif arg.model == 'Rnet': + config = rnet_config + process_rnet(config) + elif arg.model == 'Onet': + config = onet_config + process_onet(config) diff --git a/ACL_PyTorch/contrib/cv/face/FaceNet/MTCNN_pth2onnx.py b/ACL_PyTorch/contrib/cv/face/FaceNet/MTCNN_pth2onnx.py index 890b3f9073..b94604da8f 100644 --- a/ACL_PyTorch/contrib/cv/face/FaceNet/MTCNN_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/face/FaceNet/MTCNN_pth2onnx.py @@ -1,57 +1,57 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import torch -import argparse -sys.path.append('./models') -from mtcnn import PNet_truncated, RNet_truncated, ONet_truncated - - -def MTCNN_pth2onnx(opt): - if opt.model == 'PNet': - model = PNet_truncated() - elif opt.model == 'RNet': - model = RNet_truncated() - elif opt.model == 'ONet': - model = ONet_truncated() - else: - print("Error network") - return -1 - model = model.eval() - input_names = ['image'] - if opt.model == 'PNet': - output_names = ["probs", "reg"] - dynamic_axes = {'image': {0: '-1', 2: '-1', 3: '-1'}, 'probs': {0: '-1', 2: '-1', 3: '-1'}, - 'reg': {0: '-1', 2: '-1', 3: '-1'}} - dummy_input = torch.randn(1, 3, 1229, 1000) - elif opt.model == 'RNet': - output_names = ['regs', 'cls'] - dynamic_axes = {'image': {0: '-1'}, 'regs': {0: '-1'}, 'cls': {0: '-1'}} - dummy_input = torch.randn(20, 3, 24, 24) - else: - output_names = ['landmark', 'regs', 'cls'] - dynamic_axes = {'image': {0: '-1'}, 'landmark': {0: '-1'}, 'regs': {0: '-1'}, 'cls': {0: '-1'}} - dummy_input = torch.randn(20, 3, 48, 48) - - torch.onnx.export(model, dummy_input, opt.output_file, input_names=input_names, dynamic_axes=dynamic_axes, - output_names=output_names, verbose=True, opset_version=11) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--model', type=str, help='[PNet/RNet/ONet]') - parser.add_argument('--output_file', type=str, default='.', help='output path') - arg = parser.parse_args() - MTCNN_pth2onnx(arg) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import torch +import argparse +sys.path.append('./models') +from mtcnn import PNet_truncated, RNet_truncated, ONet_truncated + + +def MTCNN_pth2onnx(opt): + if opt.model == 'PNet': + model = PNet_truncated() + elif opt.model == 'RNet': + model = RNet_truncated() + elif opt.model == 'ONet': + model = ONet_truncated() + else: + print("Error network") + return -1 + model = model.eval() + input_names = ['image'] + if opt.model == 'PNet': + output_names = ["probs", "reg"] + dynamic_axes = {'image': {0: '-1', 2: '-1', 3: '-1'}, 'probs': {0: '-1', 2: '-1', 3: '-1'}, + 'reg': {0: '-1', 2: '-1', 3: '-1'}} + dummy_input = torch.randn(1, 3, 1229, 1000) + elif opt.model == 'RNet': + output_names = ['regs', 'cls'] + dynamic_axes = {'image': {0: '-1'}, 'regs': {0: '-1'}, 'cls': {0: '-1'}} + dummy_input = torch.randn(20, 3, 24, 24) + else: + output_names = ['landmark', 'regs', 'cls'] + dynamic_axes = {'image': {0: '-1'}, 'landmark': {0: '-1'}, 'regs': {0: '-1'}, 'cls': {0: '-1'}} + dummy_input = torch.randn(20, 3, 48, 48) + + torch.onnx.export(model, dummy_input, opt.output_file, input_names=input_names, dynamic_axes=dynamic_axes, + output_names=output_names, verbose=True, opset_version=11) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--model', type=str, help='[PNet/RNet/ONet]') + parser.add_argument('--output_file', type=str, default='.', help='output path') + arg = parser.parse_args() + MTCNN_pth2onnx(arg) diff --git a/ACL_PyTorch/contrib/cv/face/FaceNet/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/face/FaceNet/gen_dataset_info.py index b76d6739bc..d5cab0450c 100644 --- a/ACL_PyTorch/contrib/cv/face/FaceNet/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/face/FaceNet/gen_dataset_info.py @@ -1,60 +1,60 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/face/FaceNet/models/acl_net.py b/ACL_PyTorch/contrib/cv/face/FaceNet/models/acl_net.py index b3504ad01e..9104c53cf9 100644 --- a/ACL_PyTorch/contrib/cv/face/FaceNet/models/acl_net.py +++ b/ACL_PyTorch/contrib/cv/face/FaceNet/models/acl_net.py @@ -1,283 +1,283 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 numpy as np -import acl - -# error code -ACL_ERROR_NONE = 0 - -# memory malloc code -ACL_MEM_MALLOC_HUGE_FIRST = 0 -ACL_MEM_MALLOC_HUGE_ONLY = 1 -ACL_MEM_MALLOC_NORMAL_ONLY = 2 - -# memory copy code -ACL_MEMCPY_HOST_TO_HOST = 0 -ACL_MEMCPY_HOST_TO_DEVICE = 1 -ACL_MEMCPY_DEVICE_TO_HOST = 2 -ACL_MEMCPY_DEVICE_TO_DEVICE = 3 - -# format -ACL_FORMAT_NCHW = 0 -ACL_FLOAT32 = 0 -ACL_DTYPE = { - 0: 'float32', - 1: 'float16', - 2: 'int8', - 3: 'int32', - 4: 'uint8', - 6: 'int16', - 7: 'uint16', - 8: 'uint32', - 9: 'int64', - 10: 'uint64', - 11: 'float64', - 12: 'bool', -} - - -def check_ret(message, ret): - if ret != ACL_ERROR_NONE: - raise Exception("{} failed ret = {}".format(message, ret)) - - -class Net(object): - def __init__(self, context, device_id, model_path, input_dtype=ACL_FLOAT32, output_dtype=ACL_FLOAT32): - self.device_id = device_id - self.model_path = model_path - self.model_id = None - self.context = context - self.buffer_method = { - "in": acl.mdl.get_input_size_by_index, - "out": acl.mdl.get_output_size_by_index, - "outhost": acl.mdl.get_output_size_by_index - } - - self.input_data = [] - self.output_data = [] - self.output_data_host = [] - self.model_desc = None - self.load_input_dataset = None - self.load_output_dataset = None - self.input_size = None - self.output_size = None - - self.input_dtype = ACL_FLOAT32 - self.output_dtype = ACL_FLOAT32 - - self._init_resource() - - def __call__(self, ori_data, out_size): - return self.forward(ori_data, out_size) - - def __del__(self): - ret = acl.mdl.unload(self.model_id) - check_ret("acl.mdl.unload", ret) - if self.model_desc: - acl.mdl.destroy_desc(self.model_desc) - self.model_desc = None - - def _release_data_buffer(self): - while self.input_data: - item = self.input_data.pop() - ret = acl.rt.free(item["buffer"]) - check_ret("acl.rt.free", ret) - - while self.output_data: - item = self.output_data.pop() - ret = acl.rt.free(item["buffer"]) - check_ret("acl.rt.free", ret) - - while self.output_data_host: - item = self.output_data_host.pop() - ret = acl.rt.free_host(item["buffer"]) - check_ret("acl.rt.free_host", ret) - - def _init_resource(self): - # load_model - self.model_id, ret = acl.mdl.load_from_file(self.model_path) - check_ret("acl.mdl.load_from_file", ret) - - self.model_desc = acl.mdl.create_desc() - self._get_model_info() - - def _get_model_info(self): - ret = acl.mdl.get_desc(self.model_desc, self.model_id) - check_ret("acl.mdl.get_desc", ret) - self.input_size = acl.mdl.get_num_inputs(self.model_desc) - self.output_size = acl.mdl.get_num_outputs(self.model_desc) - - def _gen_data_buffer(self, size, des, data=None, out_size_list=None): - func = self.buffer_method[des] - for i in range(size): - if out_size_list is None and data is None: - temp_buffer_size = func(self.model_desc, i) - else: - if des == "in": - input_size = np.prod(np.array(data).shape) - temp_buffer_size = Net.gen_data_size(input_size, dtype=ACL_DTYPE.get(self.input_dtype)) - elif des == "out": - out_size = out_size_list[i] - temp_buffer_size = Net.gen_data_size(out_size, dtype=ACL_DTYPE.get(self.output_dtype)) - - temp_buffer, ret = acl.rt.malloc(temp_buffer_size, ACL_MEM_MALLOC_HUGE_FIRST) - check_ret("acl.rt.malloc", ret) - - if des == "in": - self.input_data.append({"buffer": temp_buffer, - "size": temp_buffer_size}) - elif des == "out": - self.output_data.append({"buffer": temp_buffer, - "size": temp_buffer_size}) - - def _gen_dataset_output_host(self, size, des, out_size_list=None): - func = self.buffer_method[des] - for i in range(size): - if out_size_list is None: - temp_buffer_size = func(self.model_desc, i) - else: - out_size = out_size_list[i] - temp_buffer_size = Net.gen_data_size(out_size, dtype=ACL_DTYPE.get(self.output_dtype)) - temp_buffer, ret = acl.rt.malloc_host(temp_buffer_size) - check_ret("acl.rt.malloc_host", ret) - - self.output_data_host.append({"buffer": temp_buffer, - "size": temp_buffer_size}) - - def _data_interaction(self, dataset, policy=ACL_MEMCPY_HOST_TO_DEVICE): - temp_data_buffer = self.input_data \ - if policy == ACL_MEMCPY_HOST_TO_DEVICE \ - else self.output_data - - if len(dataset) == 0 and policy == ACL_MEMCPY_DEVICE_TO_HOST: - dataset = self.output_data_host - - for i, item in enumerate(temp_data_buffer): - if policy == ACL_MEMCPY_HOST_TO_DEVICE: - ptr, _ = acl.util.numpy_contiguous_to_ptr(dataset[i]) - ret = acl.rt.memcpy(item["buffer"], item["size"], ptr, item["size"], policy) - check_ret("acl.rt.memcpy", ret) - - else: - ptr = dataset[i]["buffer"] - ret = acl.rt.memcpy(ptr, item["size"], item["buffer"], item["size"], policy) - check_ret("acl.rt.memcpy", ret) - - def _gen_dataset(self, type_str="input", input_shapes=None): - dataset = acl.mdl.create_dataset() - temp_dataset = None - if type_str == "in": - self.load_input_dataset = dataset - temp_dataset = self.input_data - else: - self.load_output_dataset = dataset - temp_dataset = self.output_data - - for i, item in enumerate(temp_dataset): - data = acl.create_data_buffer(item["buffer"], item["size"]) - if data is None: - ret = acl.destroy_data_buffer(dataset) - check_ret("acl.destroy_data_buffer", ret) - - _, ret = acl.mdl.add_dataset_buffer(dataset, data) - if ret != ACL_ERROR_NONE: - ret = acl.destroy_data_buffer(dataset) - check_ret("acl.destroy_data_buffer", ret) - - if type_str == "in": - # set dynamic dataset tensor desc - input_shape = input_shapes[i] - input_desc = acl.create_tensor_desc(self.input_dtype, input_shape, ACL_FORMAT_NCHW) - dataset, ret = acl.mdl.set_dataset_tensor_desc(dataset, input_desc, i) - if ret != ACL_ERROR_NONE: - ret = acl.destroy_data_buffer(dataset) - check_ret("acl.destroy_data_buffer", ret) - - def _data_from_host_to_device(self, images): - self._data_interaction(images, ACL_MEMCPY_HOST_TO_DEVICE) - input_shapes = [list(data.shape) for data in images] - self._gen_dataset("in", input_shapes) - self._gen_dataset("out") - - def _data_from_device_to_host(self, input_data, out_size_list): - res = [] - self._data_interaction(res, ACL_MEMCPY_DEVICE_TO_HOST) - output = self.get_result(self.output_data_host, input_data, out_size_list) - return output - - def _destroy_databuffer(self): - for dataset in [self.load_input_dataset, self.load_output_dataset]: - if not dataset: - continue - num = acl.mdl.get_dataset_num_buffers(dataset) - for i in range(num): - data_buf = acl.mdl.get_dataset_buffer(dataset, i) - if data_buf: - ret = acl.destroy_data_buffer(data_buf) - check_ret("acl.destroy_data_buffer", ret) - ret = acl.mdl.destroy_dataset(dataset) - check_ret("acl.mdl.destroy_dataset", ret) - - def _prepare_data_buffer(self, input_data=None, out_size_list=None): - self._gen_data_buffer(self.input_size, des="in", data=input_data) - self._gen_data_buffer(self.output_size, des="out", out_size_list=out_size_list) - self._gen_dataset_output_host(self.output_size, des="outhost", out_size_list=out_size_list) - - def forward(self, input_data, out_size_list): - if not isinstance(input_data, (list, tuple)): - input_data = [input_data] - - self._prepare_data_buffer(input_data=input_data, out_size_list=out_size_list) - self._data_from_host_to_device(input_data) - ret = acl.mdl.execute(self.model_id, self.load_input_dataset, self.load_output_dataset) - check_ret("acl.mdl.execute", ret) - self._destroy_databuffer() - result = self._data_from_device_to_host(input_data=input_data, out_size_list=out_size_list) - self._release_data_buffer() - return result - - def get_result(self, output_data, data, out_size_list): - dataset = [] - batch_size = data[0].shape[0] - for i in range(len(output_data)): - dims, ret = acl.mdl.get_output_dims(self.model_desc, i) - check_ret("acl.mdl.get_output_dims", ret) - - data_shape = dims.get("dims") - # fix dynamic batch size - # data_shape[0] = batch_size - data_type = acl.mdl.get_output_data_type(self.model_desc, i) - # data_len = functools.reduce(lambda x, y: x * y, data_shape) - data_len = out_size_list[i] - ftype = np.dtype(ACL_DTYPE.get(data_type)) - - size = output_data[i]["size"] - ptr = output_data[i]["buffer"] - data = acl.util.ptr_to_numpy(ptr, (size,), 1) - np_array = np.frombuffer(bytearray(data[:data_len * ftype.itemsize]), dtype=ftype, count=data_len) - dataset.append(np_array) - return dataset - - @staticmethod - def gen_data_size(size, dtype): - dtype = np.dtype(dtype) - return int(size * dtype.itemsize) - - @staticmethod - def fix_static_shape(input_shape, idx, value): - if not isinstance(input_shape, list): - input_shape = list(input_shape) - input_shape[idx] = value - return input_shape +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 numpy as np +import acl + +# error code +ACL_ERROR_NONE = 0 + +# memory malloc code +ACL_MEM_MALLOC_HUGE_FIRST = 0 +ACL_MEM_MALLOC_HUGE_ONLY = 1 +ACL_MEM_MALLOC_NORMAL_ONLY = 2 + +# memory copy code +ACL_MEMCPY_HOST_TO_HOST = 0 +ACL_MEMCPY_HOST_TO_DEVICE = 1 +ACL_MEMCPY_DEVICE_TO_HOST = 2 +ACL_MEMCPY_DEVICE_TO_DEVICE = 3 + +# format +ACL_FORMAT_NCHW = 0 +ACL_FLOAT32 = 0 +ACL_DTYPE = { + 0: 'float32', + 1: 'float16', + 2: 'int8', + 3: 'int32', + 4: 'uint8', + 6: 'int16', + 7: 'uint16', + 8: 'uint32', + 9: 'int64', + 10: 'uint64', + 11: 'float64', + 12: 'bool', +} + + +def check_ret(message, ret): + if ret != ACL_ERROR_NONE: + raise Exception("{} failed ret = {}".format(message, ret)) + + +class Net(object): + def __init__(self, context, device_id, model_path, input_dtype=ACL_FLOAT32, output_dtype=ACL_FLOAT32): + self.device_id = device_id + self.model_path = model_path + self.model_id = None + self.context = context + self.buffer_method = { + "in": acl.mdl.get_input_size_by_index, + "out": acl.mdl.get_output_size_by_index, + "outhost": acl.mdl.get_output_size_by_index + } + + self.input_data = [] + self.output_data = [] + self.output_data_host = [] + self.model_desc = None + self.load_input_dataset = None + self.load_output_dataset = None + self.input_size = None + self.output_size = None + + self.input_dtype = ACL_FLOAT32 + self.output_dtype = ACL_FLOAT32 + + self._init_resource() + + def __call__(self, ori_data, out_size): + return self.forward(ori_data, out_size) + + def __del__(self): + ret = acl.mdl.unload(self.model_id) + check_ret("acl.mdl.unload", ret) + if self.model_desc: + acl.mdl.destroy_desc(self.model_desc) + self.model_desc = None + + def _release_data_buffer(self): + while self.input_data: + item = self.input_data.pop() + ret = acl.rt.free(item["buffer"]) + check_ret("acl.rt.free", ret) + + while self.output_data: + item = self.output_data.pop() + ret = acl.rt.free(item["buffer"]) + check_ret("acl.rt.free", ret) + + while self.output_data_host: + item = self.output_data_host.pop() + ret = acl.rt.free_host(item["buffer"]) + check_ret("acl.rt.free_host", ret) + + def _init_resource(self): + # load_model + self.model_id, ret = acl.mdl.load_from_file(self.model_path) + check_ret("acl.mdl.load_from_file", ret) + + self.model_desc = acl.mdl.create_desc() + self._get_model_info() + + def _get_model_info(self): + ret = acl.mdl.get_desc(self.model_desc, self.model_id) + check_ret("acl.mdl.get_desc", ret) + self.input_size = acl.mdl.get_num_inputs(self.model_desc) + self.output_size = acl.mdl.get_num_outputs(self.model_desc) + + def _gen_data_buffer(self, size, des, data=None, out_size_list=None): + func = self.buffer_method[des] + for i in range(size): + if out_size_list is None and data is None: + temp_buffer_size = func(self.model_desc, i) + else: + if des == "in": + input_size = np.prod(np.array(data).shape) + temp_buffer_size = Net.gen_data_size(input_size, dtype=ACL_DTYPE.get(self.input_dtype)) + elif des == "out": + out_size = out_size_list[i] + temp_buffer_size = Net.gen_data_size(out_size, dtype=ACL_DTYPE.get(self.output_dtype)) + + temp_buffer, ret = acl.rt.malloc(temp_buffer_size, ACL_MEM_MALLOC_HUGE_FIRST) + check_ret("acl.rt.malloc", ret) + + if des == "in": + self.input_data.append({"buffer": temp_buffer, + "size": temp_buffer_size}) + elif des == "out": + self.output_data.append({"buffer": temp_buffer, + "size": temp_buffer_size}) + + def _gen_dataset_output_host(self, size, des, out_size_list=None): + func = self.buffer_method[des] + for i in range(size): + if out_size_list is None: + temp_buffer_size = func(self.model_desc, i) + else: + out_size = out_size_list[i] + temp_buffer_size = Net.gen_data_size(out_size, dtype=ACL_DTYPE.get(self.output_dtype)) + temp_buffer, ret = acl.rt.malloc_host(temp_buffer_size) + check_ret("acl.rt.malloc_host", ret) + + self.output_data_host.append({"buffer": temp_buffer, + "size": temp_buffer_size}) + + def _data_interaction(self, dataset, policy=ACL_MEMCPY_HOST_TO_DEVICE): + temp_data_buffer = self.input_data \ + if policy == ACL_MEMCPY_HOST_TO_DEVICE \ + else self.output_data + + if len(dataset) == 0 and policy == ACL_MEMCPY_DEVICE_TO_HOST: + dataset = self.output_data_host + + for i, item in enumerate(temp_data_buffer): + if policy == ACL_MEMCPY_HOST_TO_DEVICE: + ptr, _ = acl.util.numpy_contiguous_to_ptr(dataset[i]) + ret = acl.rt.memcpy(item["buffer"], item["size"], ptr, item["size"], policy) + check_ret("acl.rt.memcpy", ret) + + else: + ptr = dataset[i]["buffer"] + ret = acl.rt.memcpy(ptr, item["size"], item["buffer"], item["size"], policy) + check_ret("acl.rt.memcpy", ret) + + def _gen_dataset(self, type_str="input", input_shapes=None): + dataset = acl.mdl.create_dataset() + temp_dataset = None + if type_str == "in": + self.load_input_dataset = dataset + temp_dataset = self.input_data + else: + self.load_output_dataset = dataset + temp_dataset = self.output_data + + for i, item in enumerate(temp_dataset): + data = acl.create_data_buffer(item["buffer"], item["size"]) + if data is None: + ret = acl.destroy_data_buffer(dataset) + check_ret("acl.destroy_data_buffer", ret) + + _, ret = acl.mdl.add_dataset_buffer(dataset, data) + if ret != ACL_ERROR_NONE: + ret = acl.destroy_data_buffer(dataset) + check_ret("acl.destroy_data_buffer", ret) + + if type_str == "in": + # set dynamic dataset tensor desc + input_shape = input_shapes[i] + input_desc = acl.create_tensor_desc(self.input_dtype, input_shape, ACL_FORMAT_NCHW) + dataset, ret = acl.mdl.set_dataset_tensor_desc(dataset, input_desc, i) + if ret != ACL_ERROR_NONE: + ret = acl.destroy_data_buffer(dataset) + check_ret("acl.destroy_data_buffer", ret) + + def _data_from_host_to_device(self, images): + self._data_interaction(images, ACL_MEMCPY_HOST_TO_DEVICE) + input_shapes = [list(data.shape) for data in images] + self._gen_dataset("in", input_shapes) + self._gen_dataset("out") + + def _data_from_device_to_host(self, input_data, out_size_list): + res = [] + self._data_interaction(res, ACL_MEMCPY_DEVICE_TO_HOST) + output = self.get_result(self.output_data_host, input_data, out_size_list) + return output + + def _destroy_databuffer(self): + for dataset in [self.load_input_dataset, self.load_output_dataset]: + if not dataset: + continue + num = acl.mdl.get_dataset_num_buffers(dataset) + for i in range(num): + data_buf = acl.mdl.get_dataset_buffer(dataset, i) + if data_buf: + ret = acl.destroy_data_buffer(data_buf) + check_ret("acl.destroy_data_buffer", ret) + ret = acl.mdl.destroy_dataset(dataset) + check_ret("acl.mdl.destroy_dataset", ret) + + def _prepare_data_buffer(self, input_data=None, out_size_list=None): + self._gen_data_buffer(self.input_size, des="in", data=input_data) + self._gen_data_buffer(self.output_size, des="out", out_size_list=out_size_list) + self._gen_dataset_output_host(self.output_size, des="outhost", out_size_list=out_size_list) + + def forward(self, input_data, out_size_list): + if not isinstance(input_data, (list, tuple)): + input_data = [input_data] + + self._prepare_data_buffer(input_data=input_data, out_size_list=out_size_list) + self._data_from_host_to_device(input_data) + ret = acl.mdl.execute(self.model_id, self.load_input_dataset, self.load_output_dataset) + check_ret("acl.mdl.execute", ret) + self._destroy_databuffer() + result = self._data_from_device_to_host(input_data=input_data, out_size_list=out_size_list) + self._release_data_buffer() + return result + + def get_result(self, output_data, data, out_size_list): + dataset = [] + batch_size = data[0].shape[0] + for i in range(len(output_data)): + dims, ret = acl.mdl.get_output_dims(self.model_desc, i) + check_ret("acl.mdl.get_output_dims", ret) + + data_shape = dims.get("dims") + # fix dynamic batch size + # data_shape[0] = batch_size + data_type = acl.mdl.get_output_data_type(self.model_desc, i) + # data_len = functools.reduce(lambda x, y: x * y, data_shape) + data_len = out_size_list[i] + ftype = np.dtype(ACL_DTYPE.get(data_type)) + + size = output_data[i]["size"] + ptr = output_data[i]["buffer"] + data = acl.util.ptr_to_numpy(ptr, (size,), 1) + np_array = np.frombuffer(bytearray(data[:data_len * ftype.itemsize]), dtype=ftype, count=data_len) + dataset.append(np_array) + return dataset + + @staticmethod + def gen_data_size(size, dtype): + dtype = np.dtype(dtype) + return int(size * dtype.itemsize) + + @staticmethod + def fix_static_shape(input_shape, idx, value): + if not isinstance(input_shape, list): + input_shape = list(input_shape) + input_shape[idx] = value + return input_shape diff --git a/ACL_PyTorch/contrib/cv/face/FaceNet/models/mtcnn.patch b/ACL_PyTorch/contrib/cv/face/FaceNet/models/mtcnn.patch index f0c11301c3..3a974991ee 100644 --- a/ACL_PyTorch/contrib/cv/face/FaceNet/models/mtcnn.patch +++ b/ACL_PyTorch/contrib/cv/face/FaceNet/models/mtcnn.patch @@ -1,243 +1,243 @@ 1,239c1,519 -< # Copyright 2021 Huawei Technologies Co., Ltd -< # -< # 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 torch -< from torch import nn -< import numpy as np -< import os -< import math -< import acl -< from abc import ABC, abstractmethod -< from acl_net import Net, check_ret -< -< -< class PNet_truncated(nn.Module): -< def __init__(self, pretrained=True): -< super().__init__() -< -< self.conv1 = nn.Conv2d(3, 10, kernel_size=3) -< self.prelu1 = nn.PReLU(10) -< self.pool1 = nn.MaxPool2d(2, 2, ceil_mode=True) -< self.conv2 = nn.Conv2d(10, 16, kernel_size=3) -< self.prelu2 = nn.PReLU(16) -< self.conv3 = nn.Conv2d(16, 32, kernel_size=3) -< self.prelu3 = nn.PReLU(32) -< self.conv4_1 = nn.Conv2d(32, 2, kernel_size=1) -< self.softmax4_1 = nn.Softmax(dim=1) -< self.conv4_2 = nn.Conv2d(32, 4, kernel_size=1) -< self.training = False -< -< if pretrained: -< state_dict_path=os.path.join(os.path.dirname(os.path.dirname(__file__)), "weights/pnet.pt") -< state_dict = torch.load(state_dict_path) -< self.load_state_dict(state_dict) -< -< def forward(self, x): -< x = self.conv1(x) -< x = self.prelu1(x) -< x = self.pool1(x) -< x = self.conv2(x) -< x = self.prelu2(x) -< x = self.conv3(x) -< x = self.prelu3(x) -< a = self.conv4_1(x) -< # a = self.softmax4_1(a) -< b = self.conv4_2(x) -< return b, a -< -< -< class RNet_truncated(nn.Module): -< def __init__(self, pretrained=True): -< super().__init__() -< -< self.conv1 = nn.Conv2d(3, 28, kernel_size=3) -< self.prelu1 = nn.PReLU(28) -< self.pool1 = nn.MaxPool2d(3, 2, ceil_mode=True) -< self.conv2 = nn.Conv2d(28, 48, kernel_size=3) -< self.prelu2 = nn.PReLU(48) -< self.pool2 = nn.MaxPool2d(3, 2, ceil_mode=True) -< self.conv3 = nn.Conv2d(48, 64, kernel_size=2) -< self.prelu3 = nn.PReLU(64) -< self.dense4 = nn.Linear(576, 128) -< self.prelu4 = nn.PReLU(128) -< self.dense5_1 = nn.Linear(128, 2) -< self.softmax5_1 = nn.Softmax(dim=1) -< self.dense5_2 = nn.Linear(128, 4) -< -< self.training = False -< -< if pretrained: -< state_dict_path=os.path.join(os.path.dirname(os.path.dirname(__file__)), "weights/rnet.pt") -< state_dict = torch.load(state_dict_path) -< self.load_state_dict(state_dict) -< -< def forward(self, x): -< x = self.conv1(x) -< x = self.prelu1(x) -< x = self.pool1(x) -< x = self.conv2(x) -< x = self.prelu2(x) -< x = self.pool2(x) -< x = self.conv3(x) -< x = self.prelu3(x) -< x = x.permute(0, 3, 2, 1).contiguous() -< x = self.dense4(x.view(x.shape[0], -1)) -< x = self.prelu4(x) -< a = self.dense5_1(x) -< # a = self.softmax5_1(a) -< b = self.dense5_2(x) -< return b, a -< -< -< class ONet_truncated(nn.Module): -< def __init__(self, pretrained=True): -< super().__init__() -< -< self.conv1 = nn.Conv2d(3, 32, kernel_size=3) -< self.prelu1 = nn.PReLU(32) -< self.pool1 = nn.MaxPool2d(3, 2, ceil_mode=True) -< self.conv2 = nn.Conv2d(32, 64, kernel_size=3) -< self.prelu2 = nn.PReLU(64) -< self.pool2 = nn.MaxPool2d(3, 2, ceil_mode=True) -< self.conv3 = nn.Conv2d(64, 64, kernel_size=3) -< self.prelu3 = nn.PReLU(64) -< self.pool3 = nn.MaxPool2d(2, 2, ceil_mode=True) -< self.conv4 = nn.Conv2d(64, 128, kernel_size=2) -< self.prelu4 = nn.PReLU(128) -< self.dense5 = nn.Linear(1152, 256) -< self.prelu5 = nn.PReLU(256) -< self.dense6_1 = nn.Linear(256, 2) -< self.softmax6_1 = nn.Softmax(dim=1) -< self.dense6_2 = nn.Linear(256, 4) -< self.dense6_3 = nn.Linear(256, 10) -< -< self.training = False -< -< if pretrained: -< state_dict_path=os.path.join(os.path.dirname(os.path.dirname(__file__)), "weights/onet.pt") -< state_dict = torch.load(state_dict_path) -< self.load_state_dict(state_dict) -< -< def forward(self, x): -< x = self.conv1(x) -< x = self.prelu1(x) -< x = self.pool1(x) -< x = self.conv2(x) -< x = self.prelu2(x) -< x = self.pool2(x) -< x = self.conv3(x) -< x = self.prelu3(x) -< x = self.pool3(x) -< x = self.conv4(x) -< x = self.prelu4(x) -< x = x.permute(0, 3, 2, 1).contiguous() -< x = self.dense5(x.view(x.shape[0], -1)) -< x = self.prelu5(x) -< a = self.dense6_1(x) -< # a = self.softmax6_1(a) -< b = self.dense6_2(x) -< c = self.dense6_3(x) -< return b, c, a -< -< -< class OMNet(ABC): -< def __init__(self, args): -< self.device_id = args.device_id -< # 默认float32 -< self.item_size = 4 -< -< # init for acl -< ret = acl.init() -< check_ret('acl.init', ret) -< ret = acl.rt.set_device(args.device_id) -< check_ret('acl.rt.set_device', ret) -< context, ret = acl.rt.create_context(args.device_id) -< check_ret('acl.rt.create_context', ret) -< self.net_context = Net(context, model_path=args.model_path, -< device_id=args.device_id) -< -< @abstractmethod -< def forward(self, input_data, ): -< pass -< -< def __del__(self): -< del self.net_context -< ret = acl.rt.reset_device(self.device_id) -< check_ret('acl.rt.reset_device', ret) -< -< context, ret = acl.rt.get_context() -< check_ret('acl.rt.get_context', ret) -< ret = acl.rt.destroy_context(context) -< check_ret('acl.rt.destory_context', ret) -< ret = acl.finalize() -< check_ret('acl.finalize', ret) -< -< -< class PNet(OMNet): -< def __init__(self, args): -< super().__init__(args) -< -< def forward(self, input_data): -< if isinstance(input_data, np.ndarray): -< input_data = [input_data] -< h, w = input_data[0].shape[2:4] -< batch_size = input_data[0].shape[0] -< out_h = math.ceil((h - 2) /2) - 4 -< out_w = math.ceil((w - 2) /2) - 4 -< out_size = [batch_size*4*out_h*out_w, batch_size*2*out_h*out_w] -< output_data = self.net_context(input_data, out_size) -< # postprocess: softmax && reshape -< output_data[1] = output_data[1].reshape([batch_size, 2, out_h, out_w]) -< output_data[1] = torch.softmax(torch.tensor(output_data[1]), dim=1).numpy() -< output_data[0] = output_data[0].reshape([batch_size, 4, out_h, out_w]) -< return output_data -< -< -< class RNet(OMNet): -< def __init__(self, args): -< super().__init__(args) -< -< def forward(self, input_data): -< if isinstance(input_data, np.ndarray): -< input_data = [input_data] -< batch_size = input_data[0].shape[0] -< out_size = [batch_size*4, batch_size*2] -< output_data = self.net_context(input_data, out_size) -< # postprocess: softmax && reshape -< output_data[0] = output_data[0].reshape([batch_size, 4]) -< output_data[1] = output_data[1].reshape([batch_size, 2]) -< output_data[1] = torch.softmax(torch.tensor(output_data[1]), dim=1).numpy() -< return output_data -< -< -< class ONet(OMNet): -< def __init__(self, args): -< super().__init__(args) -< -< def forward(self, input_data): -< if isinstance(input_data, np.ndarray): -< input_data = [input_data] -< batch_size = input_data[0].shape[0] -< out_size = [batch_size*4, batch_size*10, batch_size*2] -< output_data = self.net_context(input_data, out_size) -< # postprocess: softmax && reshape -< output_data[0] = output_data[0].reshape([batch_size, 4]) -< output_data[1] = output_data[1].reshape([batch_size, 10]) -< output_data[2] = output_data[2].reshape([batch_size, 2]) -< output_data[2] = torch.softmax(torch.tensor(output_data[2]), dim=1).numpy() -< return output_data +< # Copyright 2021 Huawei Technologies Co., Ltd +< # +< # 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 torch +< from torch import nn +< import numpy as np +< import os +< import math +< import acl +< from abc import ABC, abstractmethod +< from acl_net import Net, check_ret +< +< +< class PNet_truncated(nn.Module): +< def __init__(self, pretrained=True): +< super().__init__() +< +< self.conv1 = nn.Conv2d(3, 10, kernel_size=3) +< self.prelu1 = nn.PReLU(10) +< self.pool1 = nn.MaxPool2d(2, 2, ceil_mode=True) +< self.conv2 = nn.Conv2d(10, 16, kernel_size=3) +< self.prelu2 = nn.PReLU(16) +< self.conv3 = nn.Conv2d(16, 32, kernel_size=3) +< self.prelu3 = nn.PReLU(32) +< self.conv4_1 = nn.Conv2d(32, 2, kernel_size=1) +< self.softmax4_1 = nn.Softmax(dim=1) +< self.conv4_2 = nn.Conv2d(32, 4, kernel_size=1) +< self.training = False +< +< if pretrained: +< state_dict_path=os.path.join(os.path.dirname(os.path.dirname(__file__)), "weights/pnet.pt") +< state_dict = torch.load(state_dict_path) +< self.load_state_dict(state_dict) +< +< def forward(self, x): +< x = self.conv1(x) +< x = self.prelu1(x) +< x = self.pool1(x) +< x = self.conv2(x) +< x = self.prelu2(x) +< x = self.conv3(x) +< x = self.prelu3(x) +< a = self.conv4_1(x) +< # a = self.softmax4_1(a) +< b = self.conv4_2(x) +< return b, a +< +< +< class RNet_truncated(nn.Module): +< def __init__(self, pretrained=True): +< super().__init__() +< +< self.conv1 = nn.Conv2d(3, 28, kernel_size=3) +< self.prelu1 = nn.PReLU(28) +< self.pool1 = nn.MaxPool2d(3, 2, ceil_mode=True) +< self.conv2 = nn.Conv2d(28, 48, kernel_size=3) +< self.prelu2 = nn.PReLU(48) +< self.pool2 = nn.MaxPool2d(3, 2, ceil_mode=True) +< self.conv3 = nn.Conv2d(48, 64, kernel_size=2) +< self.prelu3 = nn.PReLU(64) +< self.dense4 = nn.Linear(576, 128) +< self.prelu4 = nn.PReLU(128) +< self.dense5_1 = nn.Linear(128, 2) +< self.softmax5_1 = nn.Softmax(dim=1) +< self.dense5_2 = nn.Linear(128, 4) +< +< self.training = False +< +< if pretrained: +< state_dict_path=os.path.join(os.path.dirname(os.path.dirname(__file__)), "weights/rnet.pt") +< state_dict = torch.load(state_dict_path) +< self.load_state_dict(state_dict) +< +< def forward(self, x): +< x = self.conv1(x) +< x = self.prelu1(x) +< x = self.pool1(x) +< x = self.conv2(x) +< x = self.prelu2(x) +< x = self.pool2(x) +< x = self.conv3(x) +< x = self.prelu3(x) +< x = x.permute(0, 3, 2, 1).contiguous() +< x = self.dense4(x.view(x.shape[0], -1)) +< x = self.prelu4(x) +< a = self.dense5_1(x) +< # a = self.softmax5_1(a) +< b = self.dense5_2(x) +< return b, a +< +< +< class ONet_truncated(nn.Module): +< def __init__(self, pretrained=True): +< super().__init__() +< +< self.conv1 = nn.Conv2d(3, 32, kernel_size=3) +< self.prelu1 = nn.PReLU(32) +< self.pool1 = nn.MaxPool2d(3, 2, ceil_mode=True) +< self.conv2 = nn.Conv2d(32, 64, kernel_size=3) +< self.prelu2 = nn.PReLU(64) +< self.pool2 = nn.MaxPool2d(3, 2, ceil_mode=True) +< self.conv3 = nn.Conv2d(64, 64, kernel_size=3) +< self.prelu3 = nn.PReLU(64) +< self.pool3 = nn.MaxPool2d(2, 2, ceil_mode=True) +< self.conv4 = nn.Conv2d(64, 128, kernel_size=2) +< self.prelu4 = nn.PReLU(128) +< self.dense5 = nn.Linear(1152, 256) +< self.prelu5 = nn.PReLU(256) +< self.dense6_1 = nn.Linear(256, 2) +< self.softmax6_1 = nn.Softmax(dim=1) +< self.dense6_2 = nn.Linear(256, 4) +< self.dense6_3 = nn.Linear(256, 10) +< +< self.training = False +< +< if pretrained: +< state_dict_path=os.path.join(os.path.dirname(os.path.dirname(__file__)), "weights/onet.pt") +< state_dict = torch.load(state_dict_path) +< self.load_state_dict(state_dict) +< +< def forward(self, x): +< x = self.conv1(x) +< x = self.prelu1(x) +< x = self.pool1(x) +< x = self.conv2(x) +< x = self.prelu2(x) +< x = self.pool2(x) +< x = self.conv3(x) +< x = self.prelu3(x) +< x = self.pool3(x) +< x = self.conv4(x) +< x = self.prelu4(x) +< x = x.permute(0, 3, 2, 1).contiguous() +< x = self.dense5(x.view(x.shape[0], -1)) +< x = self.prelu5(x) +< a = self.dense6_1(x) +< # a = self.softmax6_1(a) +< b = self.dense6_2(x) +< c = self.dense6_3(x) +< return b, c, a +< +< +< class OMNet(ABC): +< def __init__(self, args): +< self.device_id = args.device_id +< # 默认float32 +< self.item_size = 4 +< +< # init for acl +< ret = acl.init() +< check_ret('acl.init', ret) +< ret = acl.rt.set_device(args.device_id) +< check_ret('acl.rt.set_device', ret) +< context, ret = acl.rt.create_context(args.device_id) +< check_ret('acl.rt.create_context', ret) +< self.net_context = Net(context, model_path=args.model_path, +< device_id=args.device_id) +< +< @abstractmethod +< def forward(self, input_data, ): +< pass +< +< def __del__(self): +< del self.net_context +< ret = acl.rt.reset_device(self.device_id) +< check_ret('acl.rt.reset_device', ret) +< +< context, ret = acl.rt.get_context() +< check_ret('acl.rt.get_context', ret) +< ret = acl.rt.destroy_context(context) +< check_ret('acl.rt.destory_context', ret) +< ret = acl.finalize() +< check_ret('acl.finalize', ret) +< +< +< class PNet(OMNet): +< def __init__(self, args): +< super().__init__(args) +< +< def forward(self, input_data): +< if isinstance(input_data, np.ndarray): +< input_data = [input_data] +< h, w = input_data[0].shape[2:4] +< batch_size = input_data[0].shape[0] +< out_h = math.ceil((h - 2) /2) - 4 +< out_w = math.ceil((w - 2) /2) - 4 +< out_size = [batch_size*4*out_h*out_w, batch_size*2*out_h*out_w] +< output_data = self.net_context(input_data, out_size) +< # postprocess: softmax && reshape +< output_data[1] = output_data[1].reshape([batch_size, 2, out_h, out_w]) +< output_data[1] = torch.softmax(torch.tensor(output_data[1]), dim=1).numpy() +< output_data[0] = output_data[0].reshape([batch_size, 4, out_h, out_w]) +< return output_data +< +< +< class RNet(OMNet): +< def __init__(self, args): +< super().__init__(args) +< +< def forward(self, input_data): +< if isinstance(input_data, np.ndarray): +< input_data = [input_data] +< batch_size = input_data[0].shape[0] +< out_size = [batch_size*4, batch_size*2] +< output_data = self.net_context(input_data, out_size) +< # postprocess: softmax && reshape +< output_data[0] = output_data[0].reshape([batch_size, 4]) +< output_data[1] = output_data[1].reshape([batch_size, 2]) +< output_data[1] = torch.softmax(torch.tensor(output_data[1]), dim=1).numpy() +< return output_data +< +< +< class ONet(OMNet): +< def __init__(self, args): +< super().__init__(args) +< +< def forward(self, input_data): +< if isinstance(input_data, np.ndarray): +< input_data = [input_data] +< batch_size = input_data[0].shape[0] +< out_size = [batch_size*4, batch_size*10, batch_size*2] +< output_data = self.net_context(input_data, out_size) +< # postprocess: softmax && reshape +< output_data[0] = output_data[0].reshape([batch_size, 4]) +< output_data[1] = output_data[1].reshape([batch_size, 10]) +< output_data[2] = output_data[2].reshape([batch_size, 2]) +< output_data[2] = torch.softmax(torch.tensor(output_data[2]), dim=1).numpy() +< return output_data --- > import torch > from torch import nn diff --git a/ACL_PyTorch/contrib/cv/face/FaceNet/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/face/FaceNet/modelzoo_level.txt index 39175166a4..119ddfc691 100644 --- a/ACL_PyTorch/contrib/cv/face/FaceNet/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/face/FaceNet/modelzoo_level.txt @@ -1,2 +1,2 @@ -ModelConvert:OK +ModelConvert:OK QuantStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/face/FaceNet/requirements.txt b/ACL_PyTorch/contrib/cv/face/FaceNet/requirements.txt index 8ff8888811..475e994ace 100644 --- a/ACL_PyTorch/contrib/cv/face/FaceNet/requirements.txt +++ b/ACL_PyTorch/contrib/cv/face/FaceNet/requirements.txt @@ -1,11 +1,11 @@ -numpy==1.21.3 -pillow==8.4.0 -torch==1.10.0 -torchvision==0.11.1 -facenet_pytorch==2.5.2 -scikit-learn==1.0.1 -scipy==1.7.3 -tqdm==4.62.3 -easydict==1.9 -onnx==1.10.2 - +numpy==1.21.3 +pillow==8.4.0 +torch==1.10.0 +torchvision==0.11.1 +facenet_pytorch==2.5.2 +scikit-learn==1.0.1 +scipy==1.7.3 +tqdm==4.62.3 +easydict==1.9 +onnx==1.10.2 + diff --git a/ACL_PyTorch/contrib/cv/face/FaceNet/utils/batch_utils.py b/ACL_PyTorch/contrib/cv/face/FaceNet/utils/batch_utils.py index dccca4ccd9..213eb9fabf 100644 --- a/ACL_PyTorch/contrib/cv/face/FaceNet/utils/batch_utils.py +++ b/ACL_PyTorch/contrib/cv/face/FaceNet/utils/batch_utils.py @@ -1,48 +1,48 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 numpy as np -import os -import argparse - - -def np2bin(save_np, save_name, save_path): - save_np.tofile(save_path + '/' + save_name + '_output_0.bin') - - -def bin2np(bin_path): - return np.fromfile(bin_path, dtype=np.float32) - - -def general_data(batch_size, data_root_path, save_root_path): - in_files = os.listdir(data_root_path) - for file_name in in_files: - file_index = file_name.split('_')[0] - bin_file = bin2np(data_root_path + '/' + file_name) - img_n = bin_file.shape[0] // 512 - bin_file = bin_file.reshape([img_n, 512]) - file_index_i = int(file_index) - for i in range(img_n): - if file_index_i * batch_size + i < 13233: - np2bin(bin_file[i], str(file_index_i * batch_size + i), save_root_path) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--batch_size', type=int, help='batch size') - parser.add_argument('--data_root_path', type=str, help='data path') - parser.add_argument('--save_root_path', type=str, help='save path') - arg = parser.parse_args() - general_data(arg.batch_size, arg.data_root_path, arg.save_root_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 numpy as np +import os +import argparse + + +def np2bin(save_np, save_name, save_path): + save_np.tofile(save_path + '/' + save_name + '_output_0.bin') + + +def bin2np(bin_path): + return np.fromfile(bin_path, dtype=np.float32) + + +def general_data(batch_size, data_root_path, save_root_path): + in_files = os.listdir(data_root_path) + for file_name in in_files: + file_index = file_name.split('_')[0] + bin_file = bin2np(data_root_path + '/' + file_name) + img_n = bin_file.shape[0] // 512 + bin_file = bin_file.reshape([img_n, 512]) + file_index_i = int(file_index) + for i in range(img_n): + if file_index_i * batch_size + i < 13233: + np2bin(bin_file[i], str(file_index_i * batch_size + i), save_root_path) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--batch_size', type=int, help='batch size') + parser.add_argument('--data_root_path', type=str, help='data path') + parser.add_argument('--save_root_path', type=str, help='save path') + arg = parser.parse_args() + general_data(arg.batch_size, arg.data_root_path, arg.save_root_path) diff --git a/ACL_PyTorch/contrib/cv/face/FaceNet/utils/fix_prelu.py b/ACL_PyTorch/contrib/cv/face/FaceNet/utils/fix_prelu.py index 6298e2bdc2..b1f5bc239d 100644 --- a/ACL_PyTorch/contrib/cv/face/FaceNet/utils/fix_prelu.py +++ b/ACL_PyTorch/contrib/cv/face/FaceNet/utils/fix_prelu.py @@ -1,35 +1,35 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import numpy as np -from magiconnx import OnnxGraph - - -def fix_prelu(graph): - prelu_nodes = graph.get_nodes(op_type='PRelu') - for node in prelu_nodes: - slope_para = graph[node.inputs[1]] - fix_value = np.expand_dims(slope_para.value, axis=0) - slope_para.value = fix_value - return graph - - -if __name__ == '__main__': - input_model = sys.argv[1] - out_model = sys.argv[2] - onnx_graph = OnnxGraph(input_model) - onnx_graph = fix_prelu(onnx_graph) - onnx_graph.save(out_model) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import numpy as np +from magiconnx import OnnxGraph + + +def fix_prelu(graph): + prelu_nodes = graph.get_nodes(op_type='PRelu') + for node in prelu_nodes: + slope_para = graph[node.inputs[1]] + fix_value = np.expand_dims(slope_para.value, axis=0) + slope_para.value = fix_value + return graph + + +if __name__ == '__main__': + input_model = sys.argv[1] + out_model = sys.argv[2] + onnx_graph = OnnxGraph(input_model) + onnx_graph = fix_prelu(onnx_graph) + onnx_graph.save(out_model) diff --git a/ACL_PyTorch/contrib/cv/face/FaceNet/utils/gen_test_data.py b/ACL_PyTorch/contrib/cv/face/FaceNet/utils/gen_test_data.py index 85cd5a0259..eac855cf4a 100644 --- a/ACL_PyTorch/contrib/cv/face/FaceNet/utils/gen_test_data.py +++ b/ACL_PyTorch/contrib/cv/face/FaceNet/utils/gen_test_data.py @@ -1,30 +1,30 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import numpy as np - - -def gen_bin(save_name, data_shape): - data_bin = np.random.random(data_shape) - data_bin.tofile(os.path.join(save_name)) - - -if __name__ == '__main__': - save_path = sys.argv[1] - shape = sys.argv[2] - shape = list(map(int, shape.split(','))) - gen_bin(save_path, shape) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import numpy as np + + +def gen_bin(save_name, data_shape): + data_bin = np.random.random(data_shape) + data_bin.tofile(os.path.join(save_name)) + + +if __name__ == '__main__': + save_path = sys.argv[1] + shape = sys.argv[2] + shape = list(map(int, shape.split(','))) + gen_bin(save_path, shape) diff --git a/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/LICENSE b/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/LICENSE +++ b/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/postprocess_MGN.py b/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/postprocess_MGN.py index 7e0f6a4b7e..3ffd64386d 100644 --- a/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/postprocess_MGN.py +++ b/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/postprocess_MGN.py @@ -1,163 +1,163 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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.jj - -import os -import sys -import numpy as np -import torch -import argparse -from scipy.spatial.distance import cdist -from tqdm import tqdm -sys.path.append('./MGN') -from MGN.data import Data -from MGN.utils.metrics import mean_ap, cmc, re_ranking - - -def save_batch_imgs(save_file_name, dataset_type, loader, need_flip=False): - ind = 0 - for (inputs, labels) in loader: - if need_flip == True: - inputs = inputs.index_select(3, torch.arange(inputs.size(3) - 1, -1, -1)) - for i in range(len(inputs)): - img_name = dataset_type + '/' + "{:0>5d}".format(ind) - save_path = opt.data_path - if(opt.data_path[-1] != '/'): - save_path += '/' - save_path += save_file_name - inputs[i].numpy().tofile(save_path + '/' + img_name + '.bin') - ind += 1 - - -def extract_feature_om(prediction_file_path, prediction_file_path_flip): - # make the list of files first - file_names, file_names_flip = [], [] - for file_name in os.listdir(prediction_file_path): - suffix = file_name.split('_')[-1] - if suffix == '1.txt': - file_names.append(file_name) - file_names.sort() - print("first 5 txt files: \n",file_names[:10]) - for file_name in os.listdir(prediction_file_path_flip): - suffix = file_name.split('_')[-1] - if suffix == '1.txt': - file_names_flip.append(file_name) - file_names_flip.sort() - if len(file_names) != len(file_names_flip): - print('num of filp features doesnt match that of orig') - features = torch.FloatTensor() - for i in range(len(file_names)): - fea_path = os.path.join(prediction_file_path, file_names[i]) - fea_path_f = os.path.join(prediction_file_path_flip, file_names_flip[i]) - f1 = torch.from_numpy(np.loadtxt(fea_path, dtype=np.float32)) - f2 = torch.from_numpy(np.loadtxt(fea_path_f, dtype=np.float32)) - ff = f1 + f2 - ff = torch.unsqueeze(ff, 0) - fnorm = torch.norm(ff, p=2, dim=1, keepdim=True) - ff = ff.div(fnorm.expand_as(ff)) - features = torch.cat((features, ff), 0) - if i < 8: - print(i, "th f1: \n", f1.shape, f1) - print(i, "th f2: \n", f2.shape, f2) - print(i, "th ff: \n", ff.shape, ff) - if i % 100 == 0: - print("the " + str(i) + "th image file is extracted.") - return features - - -class Main(): - def __init__(self, data): - self.train_loader = data.train_loader - self.test_loader = data.test_loader - self.query_loader = data.query_loader - self.testset = data.testset - self.queryset = data.queryset - - def evaluate_om(self): - query_prediction_file_path, query_prediction_file_path_flip = './result/q_bin/dumpOutput_device0/', \ - './result/q_bin_flip/dumpOutput_device0/' - gallery_prediction_file_path, gallery_prediction_file_path_flip = './result/g_bin/dumpOutput_device0/', \ - './result/g_bin_flip/dumpOutput_device0/' - print('extract features, this may take a few minutes') - qf = extract_feature_om(query_prediction_file_path, query_prediction_file_path_flip).numpy() - gf = extract_feature_om(gallery_prediction_file_path, gallery_prediction_file_path_flip).numpy() - print("shape of features, qf: " + str(qf.shape) + "gf: " + str(gf.shape)) - print("arr qf: \n", qf[:10, :10]) - print("arr gf: \n", gf[:10, :10]) - - def rank(dist): - r = cmc(dist, self.queryset.ids, self.testset.ids, self.queryset.cameras, self.testset.cameras, - separate_camera_set=False, - single_gallery_shot=False, - first_match_break=True) - m_ap = mean_ap(dist, self.queryset.ids, self.testset.ids, self.queryset.cameras, self.testset.cameras) - return r, m_ap - ######################### re rank########################## - q_g_dist = np.dot(qf, np.transpose(gf)) - q_q_dist = np.dot(qf, np.transpose(qf)) - g_g_dist = np.dot(gf, np.transpose(gf)) - dist = re_ranking(q_g_dist, q_q_dist, g_g_dist) - r, m_ap = rank(dist) - print('[With Re-Ranking] mAP: {:.4f} rank1: {:.4f} rank3: {:.4f} rank5: {:.4f} rank10: {:.4f}' - .format(m_ap, r[0], r[2], r[4], r[9])) - #########################no re rank########################## - dist = cdist(qf, gf) - r, m_ap = rank(dist) - print('[Without Re-Ranking] mAP: {:.4f} rank1: {:.4f} rank3: {:.4f} rank5: {:.4f} rank10: {:.4f}' - .format(m_ap, r[0], r[2], r[4], r[9])) - - def save_data(self): - save_file_name = 'bin_data' - save_file_name_flip = 'bin_data_flip' - print('saving images, this may take a few minutes') - save_batch_imgs(save_file_name, 'q', tqdm(self.query_loader)) - save_batch_imgs(save_file_name, 'g', tqdm(self.test_loader)) - save_batch_imgs(save_file_name_flip, 'q', tqdm(self.query_loader), need_flip=True) - save_batch_imgs(save_file_name_flip, 'g', tqdm(self.test_loader), need_flip=True) - - -def parse_func(): - parser = argparse.ArgumentParser() - parser.add_argument('--data_path', - default="Market-1501-v15.09.15", - help='path of Market-1501-v15.09.15') - parser.add_argument('--mode', - default='train', choices=['train', 'evaluate', 'evaluate_om', 'save_bin', 'vis'], - help='train or evaluate ') - parser.add_argument('--query_image', - default='0001_c1s1_001051_00.jpg', - help='path to the image you want to query') - parser.add_argument("--batchid", - default=4, - help='the batch for id') - parser.add_argument("--batchimage", - default=4, - help='the batch of per id') - parser.add_argument("--batchtest", - default=8, - help='the batch size for test') - return parser.parse_args() - - -if __name__ == '__main__': - opt = parse_func() - data = Data(opt) - main = Main(data) - if opt.mode == 'evaluate_om': - print('start evaluate om') - main.evaluate_om() - elif opt.mode == 'save_bin': - print('start evaluate') - main.save_data() - else: +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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.jj + +import os +import sys +import numpy as np +import torch +import argparse +from scipy.spatial.distance import cdist +from tqdm import tqdm +sys.path.append('./MGN') +from MGN.data import Data +from MGN.utils.metrics import mean_ap, cmc, re_ranking + + +def save_batch_imgs(save_file_name, dataset_type, loader, need_flip=False): + ind = 0 + for (inputs, labels) in loader: + if need_flip == True: + inputs = inputs.index_select(3, torch.arange(inputs.size(3) - 1, -1, -1)) + for i in range(len(inputs)): + img_name = dataset_type + '/' + "{:0>5d}".format(ind) + save_path = opt.data_path + if(opt.data_path[-1] != '/'): + save_path += '/' + save_path += save_file_name + inputs[i].numpy().tofile(save_path + '/' + img_name + '.bin') + ind += 1 + + +def extract_feature_om(prediction_file_path, prediction_file_path_flip): + # make the list of files first + file_names, file_names_flip = [], [] + for file_name in os.listdir(prediction_file_path): + suffix = file_name.split('_')[-1] + if suffix == '1.txt': + file_names.append(file_name) + file_names.sort() + print("first 5 txt files: \n",file_names[:10]) + for file_name in os.listdir(prediction_file_path_flip): + suffix = file_name.split('_')[-1] + if suffix == '1.txt': + file_names_flip.append(file_name) + file_names_flip.sort() + if len(file_names) != len(file_names_flip): + print('num of filp features doesnt match that of orig') + features = torch.FloatTensor() + for i in range(len(file_names)): + fea_path = os.path.join(prediction_file_path, file_names[i]) + fea_path_f = os.path.join(prediction_file_path_flip, file_names_flip[i]) + f1 = torch.from_numpy(np.loadtxt(fea_path, dtype=np.float32)) + f2 = torch.from_numpy(np.loadtxt(fea_path_f, dtype=np.float32)) + ff = f1 + f2 + ff = torch.unsqueeze(ff, 0) + fnorm = torch.norm(ff, p=2, dim=1, keepdim=True) + ff = ff.div(fnorm.expand_as(ff)) + features = torch.cat((features, ff), 0) + if i < 8: + print(i, "th f1: \n", f1.shape, f1) + print(i, "th f2: \n", f2.shape, f2) + print(i, "th ff: \n", ff.shape, ff) + if i % 100 == 0: + print("the " + str(i) + "th image file is extracted.") + return features + + +class Main(): + def __init__(self, data): + self.train_loader = data.train_loader + self.test_loader = data.test_loader + self.query_loader = data.query_loader + self.testset = data.testset + self.queryset = data.queryset + + def evaluate_om(self): + query_prediction_file_path, query_prediction_file_path_flip = './result/q_bin/dumpOutput_device0/', \ + './result/q_bin_flip/dumpOutput_device0/' + gallery_prediction_file_path, gallery_prediction_file_path_flip = './result/g_bin/dumpOutput_device0/', \ + './result/g_bin_flip/dumpOutput_device0/' + print('extract features, this may take a few minutes') + qf = extract_feature_om(query_prediction_file_path, query_prediction_file_path_flip).numpy() + gf = extract_feature_om(gallery_prediction_file_path, gallery_prediction_file_path_flip).numpy() + print("shape of features, qf: " + str(qf.shape) + "gf: " + str(gf.shape)) + print("arr qf: \n", qf[:10, :10]) + print("arr gf: \n", gf[:10, :10]) + + def rank(dist): + r = cmc(dist, self.queryset.ids, self.testset.ids, self.queryset.cameras, self.testset.cameras, + separate_camera_set=False, + single_gallery_shot=False, + first_match_break=True) + m_ap = mean_ap(dist, self.queryset.ids, self.testset.ids, self.queryset.cameras, self.testset.cameras) + return r, m_ap + ######################### re rank########################## + q_g_dist = np.dot(qf, np.transpose(gf)) + q_q_dist = np.dot(qf, np.transpose(qf)) + g_g_dist = np.dot(gf, np.transpose(gf)) + dist = re_ranking(q_g_dist, q_q_dist, g_g_dist) + r, m_ap = rank(dist) + print('[With Re-Ranking] mAP: {:.4f} rank1: {:.4f} rank3: {:.4f} rank5: {:.4f} rank10: {:.4f}' + .format(m_ap, r[0], r[2], r[4], r[9])) + #########################no re rank########################## + dist = cdist(qf, gf) + r, m_ap = rank(dist) + print('[Without Re-Ranking] mAP: {:.4f} rank1: {:.4f} rank3: {:.4f} rank5: {:.4f} rank10: {:.4f}' + .format(m_ap, r[0], r[2], r[4], r[9])) + + def save_data(self): + save_file_name = 'bin_data' + save_file_name_flip = 'bin_data_flip' + print('saving images, this may take a few minutes') + save_batch_imgs(save_file_name, 'q', tqdm(self.query_loader)) + save_batch_imgs(save_file_name, 'g', tqdm(self.test_loader)) + save_batch_imgs(save_file_name_flip, 'q', tqdm(self.query_loader), need_flip=True) + save_batch_imgs(save_file_name_flip, 'g', tqdm(self.test_loader), need_flip=True) + + +def parse_func(): + parser = argparse.ArgumentParser() + parser.add_argument('--data_path', + default="Market-1501-v15.09.15", + help='path of Market-1501-v15.09.15') + parser.add_argument('--mode', + default='train', choices=['train', 'evaluate', 'evaluate_om', 'save_bin', 'vis'], + help='train or evaluate ') + parser.add_argument('--query_image', + default='0001_c1s1_001051_00.jpg', + help='path to the image you want to query') + parser.add_argument("--batchid", + default=4, + help='the batch for id') + parser.add_argument("--batchimage", + default=4, + help='the batch of per id') + parser.add_argument("--batchtest", + default=8, + help='the batch size for test') + return parser.parse_args() + + +if __name__ == '__main__': + opt = parse_func() + data = Data(opt) + main = Main(data) + if opt.mode == 'evaluate_om': + print('start evaluate om') + main.evaluate_om() + elif opt.mode == 'save_bin': + print('start evaluate') + main.save_data() + else: raise NotImplementedError() \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/preprocess_MGN.py b/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/preprocess_MGN.py index b76d6739bc..d5cab0450c 100644 --- a/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/preprocess_MGN.py +++ b/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/preprocess_MGN.py @@ -1,60 +1,60 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/pth2onnx.py b/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/pth2onnx.py index 9a550c9fe9..9cf592a866 100644 --- a/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/pth2onnx.py @@ -1,40 +1,40 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import torch -sys.path.append("./MGN") -from MGN.network import MGN -os.environ['CUDA_VISIBLE_DEVICES'] = '0' - - -def pth2onnx(input_file, output_file, batch_size): - model = MGN() - model = model.to('cpu') - model.load_state_dict(torch.load(input_file, map_location=torch.device('cpu'))) - model.eval() - input_names = ["image"] - output_names = ["features"] - dynamic_axes = {'image': {0: '-1'}, 'features': {0: '-1'}} - dummy_input = torch.randn(batch_size, 3, 384, 128) - torch.onnx.export(model, dummy_input, output_file, input_names = input_names, - dynamic_axes = dynamic_axes, output_names = output_names, - opset_version=11, verbose=True) - print("***********************************Convert to ONNX model file SUCCESS!***" - "*******************************************") - - -if __name__ == '__main__': +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import torch +sys.path.append("./MGN") +from MGN.network import MGN +os.environ['CUDA_VISIBLE_DEVICES'] = '0' + + +def pth2onnx(input_file, output_file, batch_size): + model = MGN() + model = model.to('cpu') + model.load_state_dict(torch.load(input_file, map_location=torch.device('cpu'))) + model.eval() + input_names = ["image"] + output_names = ["features"] + dynamic_axes = {'image': {0: '-1'}, 'features': {0: '-1'}} + dummy_input = torch.randn(batch_size, 3, 384, 128) + torch.onnx.export(model, dummy_input, output_file, input_names = input_names, + dynamic_axes = dynamic_axes, output_names = output_names, + opset_version=11, verbose=True) + print("***********************************Convert to ONNX model file SUCCESS!***" + "*******************************************") + + +if __name__ == '__main__': pth2onnx(sys.argv[1], sys.argv[2], int(sys.argv[3])) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/requirements.txt b/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/requirements.txt index 71bce80b95..7a28b67e68 100644 --- a/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/requirements.txt +++ b/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/requirements.txt @@ -1,4 +1,4 @@ -torchvision>=0.6.0 -onnx>=1.7.0 -torch==1.7.0 -albumentations == 1.0.0 +torchvision>=0.6.0 +onnx>=1.7.0 +torch==1.7.0 +albumentations == 1.0.0 diff --git a/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/test/README.md b/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/test/README.md index ca7c62c2cc..6e58e8cb14 100644 --- a/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/test/README.md +++ b/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/test/README.md @@ -1,54 +1,54 @@ -环境准备: - -1.数据集路径 -- [Market1501数据集获取路径](https://pan.baidu.com/s/1ntIi2Op?_at_=1624593258681) -- 原始数据集已经放在/opt/npu/Market1501/下,应在./ReID-MGN-master/data/下新建Market1501目录,将/opt/npu/Market1501/下的文件拷贝到./ReID-MGN-master/data/Market1501下 -- ./data/Market1501/路径下,需要新建bin_data和bin_data_flip两个路径,bin_data和bin_data_flip两个路径下分别新建q和g两个路径 -- 需要新建model路径,预训练文件model.pt放在该路径下 -- 具体命令参考下文 - - -2.进入工作目录 -``` -cd /ReID-MGN-master -mkdir -p ./data/Market1501 -cp -r /opt/npu/Market1501/* ./data/Market1501/ -mkdir -p ./data/Market1501/bin_data/q -mkdir -p ./data/Market1501/bin_data/p -mkdir -p ./data/Market1501/bin_data_flip/q -mkdir -p ./data/Market1501/bin_data_flip/p -mkdir model -``` - -3.安装必要的依赖 -``` -pip3.7 install -r requirements.txt -``` - -4.获取模型代码 -``` -git clone https://github.com/GNAYUOHZ/ReID-MGN.git MGN -cd MGN && git checkout f0251e9e6003ec6f2c3fbc8ce5741d21436c20cf && cd - -patch -R MGN/data.py < module.patch -``` - -5.获取权重文件 -``` -(https://pan.baidu.com/s/12AkumLX10hLx9vh_SQwdyw) password:mrl5 -cp ${model.pt} ./model -``` - -6.获取benchmark工具 -``` -将benchmark.x86_64放在当前目录 -``` - -7.310上执行,执行时确保device空闲 -``` -source env.sh -apt install dos2unix -dos2unix test/pth2om.sh -bash test/pth2om.sh -dos2unix test/eval_acc_perf.sh -bash test/eval_acc_perf.sh -``` +环境准备: + +1.数据集路径 +- [Market1501数据集获取路径](https://pan.baidu.com/s/1ntIi2Op?_at_=1624593258681) +- 原始数据集已经放在/opt/npu/Market1501/下,应在./ReID-MGN-master/data/下新建Market1501目录,将/opt/npu/Market1501/下的文件拷贝到./ReID-MGN-master/data/Market1501下 +- ./data/Market1501/路径下,需要新建bin_data和bin_data_flip两个路径,bin_data和bin_data_flip两个路径下分别新建q和g两个路径 +- 需要新建model路径,预训练文件model.pt放在该路径下 +- 具体命令参考下文 + + +2.进入工作目录 +``` +cd /ReID-MGN-master +mkdir -p ./data/Market1501 +cp -r /opt/npu/Market1501/* ./data/Market1501/ +mkdir -p ./data/Market1501/bin_data/q +mkdir -p ./data/Market1501/bin_data/p +mkdir -p ./data/Market1501/bin_data_flip/q +mkdir -p ./data/Market1501/bin_data_flip/p +mkdir model +``` + +3.安装必要的依赖 +``` +pip3.7 install -r requirements.txt +``` + +4.获取模型代码 +``` +git clone https://github.com/GNAYUOHZ/ReID-MGN.git MGN +cd MGN && git checkout f0251e9e6003ec6f2c3fbc8ce5741d21436c20cf && cd - +patch -R MGN/data.py < module.patch +``` + +5.获取权重文件 +``` +(https://pan.baidu.com/s/12AkumLX10hLx9vh_SQwdyw) password:mrl5 +cp ${model.pt} ./model +``` + +6.获取benchmark工具 +``` +将benchmark.x86_64放在当前目录 +``` + +7.310上执行,执行时确保device空闲 +``` +source env.sh +apt install dos2unix +dos2unix test/pth2om.sh +bash test/pth2om.sh +dos2unix test/eval_acc_perf.sh +bash test/eval_acc_perf.sh +``` diff --git a/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/test/parse.py b/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/test/parse.py index b9c74f41d7..82af69cd18 100644 --- a/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/test/parse.py +++ b/ACL_PyTorch/contrib/cv/face/ReId-MGN-master/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/LICENSE b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/LICENSE +++ b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/PCB_pth_postprocess.py b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/PCB_pth_postprocess.py index adc013a082..873e88ad76 100644 --- a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/PCB_pth_postprocess.py +++ b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/PCB_pth_postprocess.py @@ -1,264 +1,264 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import os.path as osp -import os -import numpy as np -import torch -import datasets -from sklearn.metrics import average_precision_score -from collections import OrderedDict -from collections import defaultdict -import json - - -def get_data(name, data_dir): - root = osp.join(data_dir, name) - root = data_dir - dataset = datasets.create(name, root) - return dataset - - -def pairwise_distance(query_features, gallery_features, query=None, gallery=None): - x = torch.cat([query_features[f].unsqueeze(0) for f, _, _ in query], 0) - y = torch.cat([gallery_features[f].unsqueeze(0) for f, _, _ in gallery], 0) - m, n = x.size(0), y.size(0) - x = x.view(m, -1) - y = y.view(n, -1) - dist = torch.pow(x, 2).sum(1).unsqueeze(1).expand(m, n) + \ - torch.pow(y, 2).sum(1).unsqueeze(1).expand(n, m).t() - dist.addmm_(1, -2, x, y.t()) - return dist - - -def _unique_sample(ids_dict, num): - mask = np.zeros(num, dtype=np.bool) - for _, indices in ids_dict.items(): - i = np.random.choice(indices) - mask[i] = True - return mask - - -def cmc(distmat, query_ids=None, gallery_ids=None, - query_cams=None, gallery_cams=None, topk=100, - separate_camera_set=False, - single_gallery_shot=False, - first_match_break=False): - distmat = to_numpy(distmat) - m, n = distmat.shape - # Fill up default values - if query_ids is None: - query_ids = np.arange(m) - if gallery_ids is None: - gallery_ids = np.arange(n) - if query_cams is None: - query_cams = np.zeros(m).astype(np.int32) - if gallery_cams is None: - gallery_cams = np.ones(n).astype(np.int32) - # Ensure numpy array - query_ids = np.asarray(query_ids) - gallery_ids = np.asarray(gallery_ids) - query_cams = np.asarray(query_cams) - gallery_cams = np.asarray(gallery_cams) - # Sort and find correct matches - indices = np.argsort(distmat, axis=1) - matches = (gallery_ids[indices] == query_ids[:, np.newaxis]) - # Compute CMC for each query - ret = np.zeros(topk) - num_valid_queries = 0 - for i in range(m): - # Filter out the same id and same camera - valid = ((gallery_ids[indices[i]] != query_ids[i]) | - (gallery_cams[indices[i]] != query_cams[i])) - if separate_camera_set: - # Filter out samples from same camera - valid &= (gallery_cams[indices[i]] != query_cams[i]) - if not np.any(matches[i, valid]): continue - if single_gallery_shot: - repeat = 10 - gids = gallery_ids[indices[i][valid]] - inds = np.where(valid)[0] - ids_dict = defaultdict(list) - for j, x in zip(inds, gids): - ids_dict[x].append(j) - else: - repeat = 1 - for _ in range(repeat): - if single_gallery_shot: - # Randomly choose one instance for each id - sampled = (valid & _unique_sample(ids_dict, len(valid))) - index = np.nonzero(matches[i, sampled])[0] - else: - index = np.nonzero(matches[i, valid])[0] - delta = 1. / (len(index) * repeat) - for j, k in enumerate(index): - if k - j >= topk: break - if first_match_break: - ret[k - j] += 1 - break - ret[k - j] += delta - num_valid_queries += 1 - if num_valid_queries == 0: - raise RuntimeError("No valid query") - return ret.cumsum() / num_valid_queries - - -def to_numpy(tensor): - if torch.is_tensor(tensor): - return tensor.cpu().numpy() - elif type(tensor).__module__ != 'numpy': - raise ValueError("Cannot convert {} to numpy array" - .format(type(tensor))) - return tensor - - -def mean_ap(distmat, query_ids=None, gallery_ids=None, - query_cams=None, gallery_cams=None): - distmat = to_numpy(distmat) - m, n = distmat.shape - # Fill up default values - if query_ids is None: - query_ids = np.arange(m) - if gallery_ids is None: - gallery_ids = np.arange(n) - if query_cams is None: - query_cams = np.zeros(m).astype(np.int32) - if gallery_cams is None: - gallery_cams = np.ones(n).astype(np.int32) - # Ensure numpy array - query_ids = np.asarray(query_ids) - gallery_ids = np.asarray(gallery_ids) - query_cams = np.asarray(query_cams) - gallery_cams = np.asarray(gallery_cams) - # Sort and find correct matches - indices = np.argsort(distmat, axis=1) - matches = (gallery_ids[indices] == query_ids[:, np.newaxis]) - # Compute AP for each query - aps = [] - for i in range(m): - # Filter out the same id and same camera - valid = ((gallery_ids[indices[i]] != query_ids[i]) | - (gallery_cams[indices[i]] != query_cams[i])) - y_true = matches[i, valid] - y_score = -distmat[i][indices[i]][valid] - if not np.any(y_true): continue - aps.append(average_precision_score(y_true, y_score)) - if len(aps) == 0: - raise RuntimeError("No valid query") - return np.mean(aps) - - -def evaluate_all(distmat, query=None, gallery=None, - query_ids=None, gallery_ids=None, - query_cams=None, gallery_cams=None, - cmc_topk=(1, 5, 10)): - if query is not None and gallery is not None: - query_ids = [pid for _, pid, _ in query] - gallery_ids = [pid for _, pid, _ in gallery] - query_cams = [cam for _, _, cam in query] - gallery_cams = [cam for _, _, cam in gallery] - else: - assert (query_ids is not None and gallery_ids is not None - and query_cams is not None and gallery_cams is not None) - # Compute mean AP - mAP = mean_ap(distmat, query_ids, gallery_ids, query_cams, gallery_cams) - print('Mean AP: {:4.1%}'.format(mAP)) - # Compute all kinds of CMC scores - cmc_configs = { - 'allshots': dict(separate_camera_set=False, - single_gallery_shot=False, - first_match_break=False), - 'cuhk03': dict(separate_camera_set=True, - single_gallery_shot=True, - first_match_break=False), - 'market1501': dict(separate_camera_set=False, - single_gallery_shot=False, - first_match_break=True)} - cmc_scores = {name: cmc(distmat, query_ids, gallery_ids, - query_cams, gallery_cams, **params) - for name, params in cmc_configs.items()} - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - table_dict["value"].extend( - [{"key": "Number of images", "value": str(15913)}, - {"key": "Number of classes", "value": str(751)}]) - for k in cmc_topk: - table_dict["value"].append({"key": "Top-" + str(k) + " accuracy", - "value": str('{:.1%}'.format(cmc_scores['market1501'][k - 1]))}) - print('CMC Scores{:>12}' - .format('market1501')) - for k in cmc_topk: - print(' top-{:<4}{:12.1%}' - .format(k, cmc_scores['market1501'][k - 1])) - - print(table_dict) - writer = open('PCB_inference_result.json', 'w') - json.dump(table_dict, writer) - writer.close() - # Use the allshots cmc top-1 score for validation criterion - return cmc_scores['allshots'][0] - - -def load_result(filepath): - count = 0 - features = OrderedDict() - for root, dirs, files in os.walk(filepath): - for file in files: - file_tmp = file.split('.', 2)[0] - list_file = file_tmp.split('_') - if list_file[4] == '1': - file = filepath + '/' + file - output = np.fromfile(file, dtype='float32') - output = torch.from_numpy(output) - output = output.reshape(2048, 6, 1) - filename = list_file[0] + '_' + list_file[1] + '_' + list_file[2] + '_' + list_file[3] + '.jpg' - if list_file[0] == '1488' or filename == '0000_c6s3_094992_01.jpg' \ - or filename == '0000_c4s6_022316_04.jpg' or filename == '0000_c1s6_023071_04.jpg': - filename = filename + '.jpg' - features[filename] = output - count = count + 1 - return features - - -def evaluate_Ascend310(query_filepath, gallery_filepath, query, gallery): - print('extracting query features\n') - query_features_0 = load_result(query_filepath) - print('extracting gallery features\n') - gallery_features_0 = load_result(gallery_filepath) - distmat = pairwise_distance(query_features_0, gallery_features_0, query, gallery) - return evaluate_all(distmat, query=query, gallery=gallery) - - -def main(args): - dataset = get_data(args.dataset, args.data_dir) - evaluate_Ascend310(args.query, args.gallery, dataset.query, dataset.gallery) - return - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description="Softmax loss classification") - - parser.add_argument('-q', '--query', type=str, default='./dumpOutput_device0_query') - - parser.add_argument('-g', '--gallery', type=str, default='./dumpOutput_device0_gallery') - parser.add_argument('-d', '--dataset', type=str, default='market', - choices=datasets.names()) - - parser.add_argument('--data-dir', type=str, metavar='PATH', - default='./datasets/Market-1501/') - - main(parser.parse_args()) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import os.path as osp +import os +import numpy as np +import torch +import datasets +from sklearn.metrics import average_precision_score +from collections import OrderedDict +from collections import defaultdict +import json + + +def get_data(name, data_dir): + root = osp.join(data_dir, name) + root = data_dir + dataset = datasets.create(name, root) + return dataset + + +def pairwise_distance(query_features, gallery_features, query=None, gallery=None): + x = torch.cat([query_features[f].unsqueeze(0) for f, _, _ in query], 0) + y = torch.cat([gallery_features[f].unsqueeze(0) for f, _, _ in gallery], 0) + m, n = x.size(0), y.size(0) + x = x.view(m, -1) + y = y.view(n, -1) + dist = torch.pow(x, 2).sum(1).unsqueeze(1).expand(m, n) + \ + torch.pow(y, 2).sum(1).unsqueeze(1).expand(n, m).t() + dist.addmm_(1, -2, x, y.t()) + return dist + + +def _unique_sample(ids_dict, num): + mask = np.zeros(num, dtype=np.bool) + for _, indices in ids_dict.items(): + i = np.random.choice(indices) + mask[i] = True + return mask + + +def cmc(distmat, query_ids=None, gallery_ids=None, + query_cams=None, gallery_cams=None, topk=100, + separate_camera_set=False, + single_gallery_shot=False, + first_match_break=False): + distmat = to_numpy(distmat) + m, n = distmat.shape + # Fill up default values + if query_ids is None: + query_ids = np.arange(m) + if gallery_ids is None: + gallery_ids = np.arange(n) + if query_cams is None: + query_cams = np.zeros(m).astype(np.int32) + if gallery_cams is None: + gallery_cams = np.ones(n).astype(np.int32) + # Ensure numpy array + query_ids = np.asarray(query_ids) + gallery_ids = np.asarray(gallery_ids) + query_cams = np.asarray(query_cams) + gallery_cams = np.asarray(gallery_cams) + # Sort and find correct matches + indices = np.argsort(distmat, axis=1) + matches = (gallery_ids[indices] == query_ids[:, np.newaxis]) + # Compute CMC for each query + ret = np.zeros(topk) + num_valid_queries = 0 + for i in range(m): + # Filter out the same id and same camera + valid = ((gallery_ids[indices[i]] != query_ids[i]) | + (gallery_cams[indices[i]] != query_cams[i])) + if separate_camera_set: + # Filter out samples from same camera + valid &= (gallery_cams[indices[i]] != query_cams[i]) + if not np.any(matches[i, valid]): continue + if single_gallery_shot: + repeat = 10 + gids = gallery_ids[indices[i][valid]] + inds = np.where(valid)[0] + ids_dict = defaultdict(list) + for j, x in zip(inds, gids): + ids_dict[x].append(j) + else: + repeat = 1 + for _ in range(repeat): + if single_gallery_shot: + # Randomly choose one instance for each id + sampled = (valid & _unique_sample(ids_dict, len(valid))) + index = np.nonzero(matches[i, sampled])[0] + else: + index = np.nonzero(matches[i, valid])[0] + delta = 1. / (len(index) * repeat) + for j, k in enumerate(index): + if k - j >= topk: break + if first_match_break: + ret[k - j] += 1 + break + ret[k - j] += delta + num_valid_queries += 1 + if num_valid_queries == 0: + raise RuntimeError("No valid query") + return ret.cumsum() / num_valid_queries + + +def to_numpy(tensor): + if torch.is_tensor(tensor): + return tensor.cpu().numpy() + elif type(tensor).__module__ != 'numpy': + raise ValueError("Cannot convert {} to numpy array" + .format(type(tensor))) + return tensor + + +def mean_ap(distmat, query_ids=None, gallery_ids=None, + query_cams=None, gallery_cams=None): + distmat = to_numpy(distmat) + m, n = distmat.shape + # Fill up default values + if query_ids is None: + query_ids = np.arange(m) + if gallery_ids is None: + gallery_ids = np.arange(n) + if query_cams is None: + query_cams = np.zeros(m).astype(np.int32) + if gallery_cams is None: + gallery_cams = np.ones(n).astype(np.int32) + # Ensure numpy array + query_ids = np.asarray(query_ids) + gallery_ids = np.asarray(gallery_ids) + query_cams = np.asarray(query_cams) + gallery_cams = np.asarray(gallery_cams) + # Sort and find correct matches + indices = np.argsort(distmat, axis=1) + matches = (gallery_ids[indices] == query_ids[:, np.newaxis]) + # Compute AP for each query + aps = [] + for i in range(m): + # Filter out the same id and same camera + valid = ((gallery_ids[indices[i]] != query_ids[i]) | + (gallery_cams[indices[i]] != query_cams[i])) + y_true = matches[i, valid] + y_score = -distmat[i][indices[i]][valid] + if not np.any(y_true): continue + aps.append(average_precision_score(y_true, y_score)) + if len(aps) == 0: + raise RuntimeError("No valid query") + return np.mean(aps) + + +def evaluate_all(distmat, query=None, gallery=None, + query_ids=None, gallery_ids=None, + query_cams=None, gallery_cams=None, + cmc_topk=(1, 5, 10)): + if query is not None and gallery is not None: + query_ids = [pid for _, pid, _ in query] + gallery_ids = [pid for _, pid, _ in gallery] + query_cams = [cam for _, _, cam in query] + gallery_cams = [cam for _, _, cam in gallery] + else: + assert (query_ids is not None and gallery_ids is not None + and query_cams is not None and gallery_cams is not None) + # Compute mean AP + mAP = mean_ap(distmat, query_ids, gallery_ids, query_cams, gallery_cams) + print('Mean AP: {:4.1%}'.format(mAP)) + # Compute all kinds of CMC scores + cmc_configs = { + 'allshots': dict(separate_camera_set=False, + single_gallery_shot=False, + first_match_break=False), + 'cuhk03': dict(separate_camera_set=True, + single_gallery_shot=True, + first_match_break=False), + 'market1501': dict(separate_camera_set=False, + single_gallery_shot=False, + first_match_break=True)} + cmc_scores = {name: cmc(distmat, query_ids, gallery_ids, + query_cams, gallery_cams, **params) + for name, params in cmc_configs.items()} + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + table_dict["value"].extend( + [{"key": "Number of images", "value": str(15913)}, + {"key": "Number of classes", "value": str(751)}]) + for k in cmc_topk: + table_dict["value"].append({"key": "Top-" + str(k) + " accuracy", + "value": str('{:.1%}'.format(cmc_scores['market1501'][k - 1]))}) + print('CMC Scores{:>12}' + .format('market1501')) + for k in cmc_topk: + print(' top-{:<4}{:12.1%}' + .format(k, cmc_scores['market1501'][k - 1])) + + print(table_dict) + writer = open('PCB_inference_result.json', 'w') + json.dump(table_dict, writer) + writer.close() + # Use the allshots cmc top-1 score for validation criterion + return cmc_scores['allshots'][0] + + +def load_result(filepath): + count = 0 + features = OrderedDict() + for root, dirs, files in os.walk(filepath): + for file in files: + file_tmp = file.split('.', 2)[0] + list_file = file_tmp.split('_') + if list_file[4] == '1': + file = filepath + '/' + file + output = np.fromfile(file, dtype='float32') + output = torch.from_numpy(output) + output = output.reshape(2048, 6, 1) + filename = list_file[0] + '_' + list_file[1] + '_' + list_file[2] + '_' + list_file[3] + '.jpg' + if list_file[0] == '1488' or filename == '0000_c6s3_094992_01.jpg' \ + or filename == '0000_c4s6_022316_04.jpg' or filename == '0000_c1s6_023071_04.jpg': + filename = filename + '.jpg' + features[filename] = output + count = count + 1 + return features + + +def evaluate_Ascend310(query_filepath, gallery_filepath, query, gallery): + print('extracting query features\n') + query_features_0 = load_result(query_filepath) + print('extracting gallery features\n') + gallery_features_0 = load_result(gallery_filepath) + distmat = pairwise_distance(query_features_0, gallery_features_0, query, gallery) + return evaluate_all(distmat, query=query, gallery=gallery) + + +def main(args): + dataset = get_data(args.dataset, args.data_dir) + evaluate_Ascend310(args.query, args.gallery, dataset.query, dataset.gallery) + return + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description="Softmax loss classification") + + parser.add_argument('-q', '--query', type=str, default='./dumpOutput_device0_query') + + parser.add_argument('-g', '--gallery', type=str, default='./dumpOutput_device0_gallery') + parser.add_argument('-d', '--dataset', type=str, default='market', + choices=datasets.names()) + + parser.add_argument('--data-dir', type=str, metavar='PATH', + default='./datasets/Market-1501/') + + main(parser.parse_args()) diff --git a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/PCB_pth_preprocess.py b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/PCB_pth_preprocess.py index b1ccc34faf..26f765fd6e 100644 --- a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/PCB_pth_preprocess.py +++ b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/PCB_pth_preprocess.py @@ -1,158 +1,158 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import os.path as osp -import os -import numpy as np -from torch.utils.data import DataLoader -import datasets -from torchvision.transforms import Normalize, RandomHorizontalFlip, ToTensor, Compose -from PIL import Image - - -class Preprocessor(object): - def __init__(self, dataset, root=None, transform=None): - super(Preprocessor, self).__init__() - self.dataset = dataset - self.root = root - self.transform = transform - - def __len__(self): - return len(self.dataset) - - def __getitem__(self, indices): - if isinstance(indices, (tuple, list)): - return [self._get_single_item(index) for index in indices] - return self._get_single_item(indices) - - def _get_single_item(self, index): - fname, pid, camid = self.dataset[index] - fpath = fname - if self.root is not None: - fpath = osp.join(self.root, fname) - img = Image.open(fpath).convert('RGB') - if self.transform is not None: - img = self.transform(img) - return img, fname, pid, camid - - -class RectScale(object): - def __init__(self, height, width, interpolation=Image.BILINEAR): - self.height = height - self.width = width - self.interpolation = interpolation - - def __call__(self, img): - w, h = img.size - if h == self.height and w == self.width: - return img - return img.resize((self.width, self.height), self.interpolation) - - -def get_data(name, data_dir, height, width, batch_size, workers): - root = osp.join(data_dir, name) - root = data_dir - dataset = datasets.create(name, root) - - normalizer = Normalize(mean=[0.485, 0.456, 0.406], - std=[0.229, 0.224, 0.225]) - - num_classes = dataset.num_train_ids - - train_transformer = Compose([ - RectScale(height, width), - RandomHorizontalFlip(), - ToTensor(), - normalizer, - ]) - - test_transformer = Compose([ - RectScale(height, width), - ToTensor(), - normalizer, - ]) - - - query_loader = DataLoader( - Preprocessor(dataset.query, root=osp.join(dataset.images_dir, dataset.query_path), - transform=test_transformer), - batch_size=batch_size, num_workers=workers, - shuffle=False, pin_memory=True) - - gallery_loader = DataLoader( - Preprocessor(dataset.gallery, root=osp.join(dataset.images_dir, dataset.gallery_path), - transform=test_transformer), - batch_size=batch_size, num_workers=workers, - shuffle=False, pin_memory=True) - - - return query_loader, gallery_loader - - -def data_preprocess(bin_filepath, dataloader): - if os.path.exists(bin_filepath) == False: - os.mkdir(bin_filepath) - else: - print('dir exist!') - - count = 0 - for i, (img, fname, pid, _) in enumerate(dataloader): - for fn, pi in zip(fname, pid): - fname_1 = bin_filepath + '/' + fn.split('.', 2)[0] + '.bin' - img = np.array(img).astype(np.float32) - img.tofile(fname_1) - count = count + 1 - return count - - -def main(args): - - # Create data loaders - if args.height is None or args.width is None: - args.height, args.width = (144, 56) if args.arch == 'inception' else \ - (256, 128) - query_loader, gallery_loader = \ - get_data(args.dataset, args.data_dir, args.height, - args.width, args.batch_size, args.workers, - ) - - count = data_preprocess('./gallery_preproc_data_Ascend310', gallery_loader) - print('number of images(gallery):') - print(count) - - count = data_preprocess('./query_preproc_data_Ascend310', query_loader) - print('number of images(query):') - print(count) - return - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description="Softmax loss classification") - # data - parser.add_argument('-d', '--dataset', type=str, default='cuhk03', - choices=datasets.names()) - parser.add_argument('-b', '--batch-size', type=int, default=256) - parser.add_argument('-j', '--workers', type=int, default=4) - parser.add_argument('--height', type=int, - help="input height, default: 256 for resnet*, " - "144 for inception") - parser.add_argument('--width', type=int, - help="input width, default: 128 for resnet*, " - "56 for inception") - # misc - working_dir = osp.dirname(osp.abspath(__file__)) - parser.add_argument('--data-dir', type=str, metavar='PATH', - default=osp.join(working_dir, 'data')) - main(parser.parse_args()) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import os.path as osp +import os +import numpy as np +from torch.utils.data import DataLoader +import datasets +from torchvision.transforms import Normalize, RandomHorizontalFlip, ToTensor, Compose +from PIL import Image + + +class Preprocessor(object): + def __init__(self, dataset, root=None, transform=None): + super(Preprocessor, self).__init__() + self.dataset = dataset + self.root = root + self.transform = transform + + def __len__(self): + return len(self.dataset) + + def __getitem__(self, indices): + if isinstance(indices, (tuple, list)): + return [self._get_single_item(index) for index in indices] + return self._get_single_item(indices) + + def _get_single_item(self, index): + fname, pid, camid = self.dataset[index] + fpath = fname + if self.root is not None: + fpath = osp.join(self.root, fname) + img = Image.open(fpath).convert('RGB') + if self.transform is not None: + img = self.transform(img) + return img, fname, pid, camid + + +class RectScale(object): + def __init__(self, height, width, interpolation=Image.BILINEAR): + self.height = height + self.width = width + self.interpolation = interpolation + + def __call__(self, img): + w, h = img.size + if h == self.height and w == self.width: + return img + return img.resize((self.width, self.height), self.interpolation) + + +def get_data(name, data_dir, height, width, batch_size, workers): + root = osp.join(data_dir, name) + root = data_dir + dataset = datasets.create(name, root) + + normalizer = Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]) + + num_classes = dataset.num_train_ids + + train_transformer = Compose([ + RectScale(height, width), + RandomHorizontalFlip(), + ToTensor(), + normalizer, + ]) + + test_transformer = Compose([ + RectScale(height, width), + ToTensor(), + normalizer, + ]) + + + query_loader = DataLoader( + Preprocessor(dataset.query, root=osp.join(dataset.images_dir, dataset.query_path), + transform=test_transformer), + batch_size=batch_size, num_workers=workers, + shuffle=False, pin_memory=True) + + gallery_loader = DataLoader( + Preprocessor(dataset.gallery, root=osp.join(dataset.images_dir, dataset.gallery_path), + transform=test_transformer), + batch_size=batch_size, num_workers=workers, + shuffle=False, pin_memory=True) + + + return query_loader, gallery_loader + + +def data_preprocess(bin_filepath, dataloader): + if os.path.exists(bin_filepath) == False: + os.mkdir(bin_filepath) + else: + print('dir exist!') + + count = 0 + for i, (img, fname, pid, _) in enumerate(dataloader): + for fn, pi in zip(fname, pid): + fname_1 = bin_filepath + '/' + fn.split('.', 2)[0] + '.bin' + img = np.array(img).astype(np.float32) + img.tofile(fname_1) + count = count + 1 + return count + + +def main(args): + + # Create data loaders + if args.height is None or args.width is None: + args.height, args.width = (144, 56) if args.arch == 'inception' else \ + (256, 128) + query_loader, gallery_loader = \ + get_data(args.dataset, args.data_dir, args.height, + args.width, args.batch_size, args.workers, + ) + + count = data_preprocess('./gallery_preproc_data_Ascend310', gallery_loader) + print('number of images(gallery):') + print(count) + + count = data_preprocess('./query_preproc_data_Ascend310', query_loader) + print('number of images(query):') + print(count) + return + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description="Softmax loss classification") + # data + parser.add_argument('-d', '--dataset', type=str, default='cuhk03', + choices=datasets.names()) + parser.add_argument('-b', '--batch-size', type=int, default=256) + parser.add_argument('-j', '--workers', type=int, default=4) + parser.add_argument('--height', type=int, + help="input height, default: 256 for resnet*, " + "144 for inception") + parser.add_argument('--width', type=int, + help="input width, default: 128 for resnet*, " + "56 for inception") + # misc + working_dir = osp.dirname(osp.abspath(__file__)) + parser.add_argument('--data-dir', type=str, metavar='PATH', + default=osp.join(working_dir, 'data')) + main(parser.parse_args()) diff --git a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/Readme.md b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/Readme.md index 49116bcbe1..f963242e8b 100644 --- a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/Readme.md +++ b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/Readme.md @@ -1,285 +1,285 @@ -# PCB Onnx模型端到端推理指导 -- [1 模型概述](#1-模型概述) - - [1.1 论文地址](#11-论文地址) - - [1.2 代码地址](#12-代码地址) -- [2 环境说明](#2-环境说明) - - [2.1 深度学习框架](#21-深度学习框架) - - [2.2 python第三方库](#22-python第三方库) -- [3 模型转换](#3-模型转换) - - [3.1 pth转onnx模型](#31-pth转onnx模型) - - [3.2 onnx转om模型](#32-onnx转om模型) -- [4 数据集预处理](#4-数据集预处理) - - [4.1 数据集获取](#41-数据集获取) - - [4.2 数据集预处理](#42-数据集预处理) - - [4.3 生成数据集信息文件](#43-生成数据集信息文件) -- [5 离线推理](#5-离线推理) - - [5.1 benchmark工具概述](#51-benchmark工具概述) - - [5.2 离线推理](#52-离线推理) -- [6 精度对比](#6-精度对比) - - [6.1 开源TopN精度](#62-开源TopN精度) - - [6.2 精度对比](#63-精度对比) -- [7 性能对比](#7-性能对比) - - [7.1 npu性能数据](#71-npu性能数据) - - - -## 1 模型概述 - -- **[论文地址](#11-论文地址)** - -- **[代码地址](#12-代码地址)** - -### 1.1 论文地址 -[PCB论文](https://arxiv.org/pdf/1711.09349.pdf) - -分支为 : master - -commit ID : e29cf54486427d1423277d4c793e39ac0eeff87c - -### 1.2 代码地址 -[PCB开源仓代码](https://github.com/syfafterzy/PCB_RPP_for_reID) - -## 2 环境说明 - -- **[深度学习框架](#21-深度学习框架)** - -### 2.1 深度学习框架 -``` -python==3.6.7 -pytorch==1.8.1 -torchvision==0.2.1 -``` - -### 2.2 python第三方库 - -``` -numpy == 1.19.2 -scikit-learn == 0.24.1 -opencv-python == 4.5.2.54 -pillow == 8.2.0 -onnx == 1.9.0 -pillow == 8.2.0 -skl2onnx == 1.8.0 -h5py == 3.3.0 -``` - -**说明:** -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3 模型转换 - -- **[pth转onnx模型](#31-pth转onnx模型)** - -- **[onnx转om模型](#32-onnx转om模型)** - -### 3.1 pth转onnx模型 - -1.下载pth权重文件 -[PCB预训练pth权重文件](https://ascend-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/face/PCB/PCB_3_7.pt) -``` -wget https://ascend-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/face/PCB/PCB_3_7.pt - -``` - **说明:模型文件名为:PCB_3_7.pt 其md5sum值为:c5bc5ddabcbcc45f127ead797fe8cb35 PCB_3_7.pt** ->获取的预训练模型放在本仓根目录下 - -2.编写pth2onnx脚本pth2onnx.py - - **说明:** ->注意目前ATC支持的onnx算子版本为11 - -3.执行pth2onnx脚本,生成onnx模型文件 -``` -python3.7 pth2onnx.py #将PCB_3_7.pt模型转为PCB.onnx模型 -``` - - **模型转换要点:** ->此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 - - -### 3.2 onnx转om模型 - -1.设置环境变量 -``` -source env.sh -``` -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) -``` -atc --framework=5 --model=PCB.onnx --output=PCB --input_format=NCHW --input_shape="input_1:1,3,384,128" --log=debug --soc_version=Ascend310 -``` - -## 4 数据集预处理 - -- **[数据集获取](#41-数据集获取)** - -- **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - -### 4.1 数据集获取 -该模型使用[Market数据集](https://pan.baidu.com/s/1ntIi2Op?_at_=1622802619466)的19732张验证集进行测试。数据集下载后,解压放到./datasets目录下。 - -### 4.2 数据集预处理 -1.预处理脚本PCB_pth_preprocess.py - -2.执行预处理脚本,生成数据集预处理后的bin文件 -``` -python3.7 PCB_pth_preprocess.py -d market -b 1 --height 384 --width 128 --data-dir ./datasets/Market-1501/ -j 4 -``` -### 4.3 生成数据集信息文件 -1.生成数据集信息文件脚本get_info_Ascend310.sh - -2.执行生成数据集信息脚本,生成数据集信息文件 -``` -sh get_info_Ascend310.sh -``` -在get_info_Ascend310.sh文件中调用华为提供的开源工具获取bin文件的路径和尺寸信息,该工具的第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 -## 5 离线推理 - -- **[benchmark工具概述](#51-benchmark工具概述)** - -- **[离线推理](#52-离线推理)** - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) -### 5.2 离线推理 -1.设置环境变量 -``` -source env.sh -``` -2.执行离线推理 -``` -sudo ./benchmark_tools/benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=./PCB.om -input_text_path=./gallery_preproc_data_Ascend310.info -input_width=128 -input_height=384 -output_binary=True -useDvpp=False -sudo mv ./result/dumpOutput_device0 ./result/dumpOutput_device0_gallery -sudo mv ./result/perf_vision_batchsize_1_device_0.txt ./result/gallery_perf_vision_batchsize_1_device_0.txt -``` -``` -sudo ./benchmark_tools/benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=./PCB.om -input_text_path=./query_preproc_data_Ascend310.info -input_width=128 -input_height=384 -output_binary=True -useDvpp=False -sudo mv ./result/dumpOutput_device0 ./result/dumpOutput_device0_query -sudo mv ./result/perf_vision_batchsize_1_device_0.txt ./result/query_perf_vision_batchsize_1_device_0.txt -``` -输出结果默认保存在当前目录result/dumpOutput_device0下,由于需要通过om模型提取两组特征,因此根据输入图片类型(querry或gallery)分别重命名文件夹。 -3.特征图后处理 - -``` -python ./PCB_pth_postprocess.py -q ./result/dumpOutput_device0_query -g ./result/dumpOutput_device0_gallery -d market --data-dir ./datasets/Market-1501/ -``` -对om模型提取的特征做后处理并统计精度,结果如下: -``` -{'title': 'Overall statistical evaluation', 'value': [{'key': 'Number of images', 'value': '15913'}, {'key': 'Number of classes', 'value': '751'}, {'key': 'Top-1 accuracy', 'value': '92.1%'}, {'key': 'Top-5 accuracy', 'value': '96.9%'}, {'key': 'Top-10 accuracy', 'value': '98.1%'}]} -``` -## 6 精度对比 - -- **[开源TopN精度](#61-开源TopN精度)** -- **[精度对比](#62-精度对比)** - -### 6.1 开源TopN精度 -``` -CMC Scores market1501 - top-1 92.1% - top-5 96.9% - top-10 98.1% -``` -### 6.2 精度对比 -将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 - **精度调试:** ->没有遇到精度不达标的问题,故不需要进行精度调试 - -## 7 性能对比 - -- **[npu性能数据](#71-npu性能数据)** - -### 7.1 npu性能数据 -benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准。 - -1.benchmark工具在整个数据集上推理获得性能数据 -batch1的性能,benchmark工具在整个数据集上推理后生成result/query_perf_vision_batchsize_1_device_0.txt.txt: -``` ------------------Performance Summary------------------ -[e2e] throughputRate: 164.729, latency: 20445.7 -[data read] throughputRate: 184.812, moduleLatency: 5.41092 -[preprocess] throughputRate: 182.347, moduleLatency: 5.48405 -[infer] throughputRate: 175.577, Interface throughputRate: 253.855, moduleLatency: 4.91128 -[post] throughputRate: 175.573, moduleLatency: 5.69565 -``` -Interface throughputRate: 253.855,253.855* 4 = 1015.42既是batch1 310单卡吞吐率 - - -batch4的性能,benchmark工具在整个数据集上推理后生成result/query_perf_vision_batchsize_4_device_0.txt.txt: -``` ------------------Performance Summary------------------ -[e2e] throughputRate: 157.081, latency: 21441.2 -[data read] throughputRate: 173.63, moduleLatency: 5.75937 -[preprocess] throughputRate: 171.283, moduleLatency: 5.83829 -[infer] throughputRate: 167.102, Interface throughputRate: 353.841, moduleLatency: 4.32693 -[post] throughputRate: 41.7725, moduleLatency: 23.9392 -``` -Interface throughputRate: 353.841,353.841* 4 = 1415.364既是batch4 310单卡吞吐率 - - -batch8的性能,benchmark工具在整个数据集上推理后生成result/query_perf_vision_batchsize_8_device_0.txt.txt: -``` ------------------Performance Summary------------------ -[e2e] throughputRate: 132.514, latency: 25416.1 -[data read] throughputRate: 139.993, moduleLatency: 7.14319 -[preprocess] throughputRate: 139.054, moduleLatency: 7.19145 -[infer] throughputRate: 139.615, Interface throughputRate: 366.98, moduleLatency: 4.21507 -[post] throughputRate: 17.4505, moduleLatency: 57.305 -``` -Interface throughputRate: 366.98,366.98 * 4 = 1467.92既是batch8 310单卡吞吐率 - -batch16的性能,benchmark工具在整个数据集上推理后生成result/query_perf_vision_batchsize_16_device_0.txt.txt: -``` ------------------Performance Summary------------------ -[e2e] throughputRate: 143.582, latency: 23457 -[data read] throughputRate: 150.172, moduleLatency: 6.65904 -[preprocess] throughputRate: 148.372, moduleLatency: 6.73981 -[infer] throughputRate: 147.201, Interface throughputRate: 362.414, moduleLatency: 4.28791 -[post] throughputRate: 9.22071, moduleLatency: 108.452 -``` -Interface throughputRate: 362.414,362.414 * 4 = 1449.656既是batch16 310单卡吞吐率 - - -batch32的性能,benchmark工具在整个数据集上推理后生成result/query_perf_vision_batchsize_32_device_0.txt.txt: -``` ------------------Performance Summary------------------ -[e2e] throughputRate: 118.266, latency: 28478.2 -[data read] throughputRate: 126.885, moduleLatency: 7.88113 -[preprocess] throughputRate: 125.442, moduleLatency: 7.97179 -[infer] throughputRate: 124.065, Interface throughputRate: 354.632, moduleLatency: 4.30699 -[post] throughputRate: 3.90409, moduleLatency: 256.141 -``` -Interface throughputRate: 354.632,354.632 * 4 = 1418.528既是batch32 310单卡吞吐率 - -### 7.2 性能优化 -原始模型性能不达标原因分析: -根据profiling性能分析的表格,OM模型完成一次离线推理的总耗时中卷积计算(54次)、数据下采样(1次)和数据上采样(1次)这三类操作占总耗时的71%(36%+21%+19%)左右。再往细分,Task ID 95~101总耗时的53.6%,及7%的任务数占了一半以上的耗时。查看对应任务的算子类型,大多为数据转换类:向量尺寸变换和数据类型转换,推测与npu中的算子硬件实现相关。(详见性能分析报告) - -原始模型性能与优化后模型性能对比: -batch1:441.128fps(Ascend310) < 1015.42fps(Ascend310) -batch16:1024.56(Ascend310) < 1449.656fps(Ascend310) - - -#### 7.2.1固定模型输入的batch size,并结合onnxsim工具对onnx模型进行优化 -优化动机:通过Netron查看onnx的模型结构图发现有一些常量算子可以折叠 - -优化样例: - - python -m onnxsim --input-shape="16,3,384,128" ./PCB.onnx ./PCB_sim_bs16.onnx - -#### 7.42.2.把ReduceL2算子拆分为mul+sum+sqrt算子(无损) -优化动机:Profilingdata可以看到ReduceL2这个算子耗时占比较大,原因是ReduceL2这个算子缺少优化,但是拆分后的算子是经过优化的,且拆分算子后模型的精度保持不变,因此选择拆分ReduceL2算子 - -优化样例: - - python ../scripts/split_reducelp.py ./PCB_sim_bs16.onnx ./PCB_sim_split_bs16.onnx - -#### 7.2.3.atc自动优化选项——autotune -优化动机:atc工具提供的自动优化选项 - -优化样例: - - atc --framework=5 --model=./PCB_sim_bs4.onnx --output=./PCB_sim_autotune_bs4 --input_format=NCHW --input_shape="input_1:4,3,384,128" --log=debug --soc_version=Ascend310 --auto_tune_mode="RL,GA" +# PCB Onnx模型端到端推理指导 +- [1 模型概述](#1-模型概述) + - [1.1 论文地址](#11-论文地址) + - [1.2 代码地址](#12-代码地址) +- [2 环境说明](#2-环境说明) + - [2.1 深度学习框架](#21-深度学习框架) + - [2.2 python第三方库](#22-python第三方库) +- [3 模型转换](#3-模型转换) + - [3.1 pth转onnx模型](#31-pth转onnx模型) + - [3.2 onnx转om模型](#32-onnx转om模型) +- [4 数据集预处理](#4-数据集预处理) + - [4.1 数据集获取](#41-数据集获取) + - [4.2 数据集预处理](#42-数据集预处理) + - [4.3 生成数据集信息文件](#43-生成数据集信息文件) +- [5 离线推理](#5-离线推理) + - [5.1 benchmark工具概述](#51-benchmark工具概述) + - [5.2 离线推理](#52-离线推理) +- [6 精度对比](#6-精度对比) + - [6.1 开源TopN精度](#62-开源TopN精度) + - [6.2 精度对比](#63-精度对比) +- [7 性能对比](#7-性能对比) + - [7.1 npu性能数据](#71-npu性能数据) + + + +## 1 模型概述 + +- **[论文地址](#11-论文地址)** + +- **[代码地址](#12-代码地址)** + +### 1.1 论文地址 +[PCB论文](https://arxiv.org/pdf/1711.09349.pdf) + +分支为 : master + +commit ID : e29cf54486427d1423277d4c793e39ac0eeff87c + +### 1.2 代码地址 +[PCB开源仓代码](https://github.com/syfafterzy/PCB_RPP_for_reID) + +## 2 环境说明 + +- **[深度学习框架](#21-深度学习框架)** + +### 2.1 深度学习框架 +``` +python==3.6.7 +pytorch==1.8.1 +torchvision==0.2.1 +``` + +### 2.2 python第三方库 + +``` +numpy == 1.19.2 +scikit-learn == 0.24.1 +opencv-python == 4.5.2.54 +pillow == 8.2.0 +onnx == 1.9.0 +pillow == 8.2.0 +skl2onnx == 1.8.0 +h5py == 3.3.0 +``` + +**说明:** +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3 模型转换 + +- **[pth转onnx模型](#31-pth转onnx模型)** + +- **[onnx转om模型](#32-onnx转om模型)** + +### 3.1 pth转onnx模型 + +1.下载pth权重文件 +[PCB预训练pth权重文件](https://ascend-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/face/PCB/PCB_3_7.pt) +``` +wget https://ascend-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/face/PCB/PCB_3_7.pt + +``` + **说明:模型文件名为:PCB_3_7.pt 其md5sum值为:c5bc5ddabcbcc45f127ead797fe8cb35 PCB_3_7.pt** +>获取的预训练模型放在本仓根目录下 + +2.编写pth2onnx脚本pth2onnx.py + + **说明:** +>注意目前ATC支持的onnx算子版本为11 + +3.执行pth2onnx脚本,生成onnx模型文件 +``` +python3.7 pth2onnx.py #将PCB_3_7.pt模型转为PCB.onnx模型 +``` + + **模型转换要点:** +>此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 + + +### 3.2 onnx转om模型 + +1.设置环境变量 +``` +source env.sh +``` +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) +``` +atc --framework=5 --model=PCB.onnx --output=PCB --input_format=NCHW --input_shape="input_1:1,3,384,128" --log=debug --soc_version=Ascend310 +``` + +## 4 数据集预处理 + +- **[数据集获取](#41-数据集获取)** + +- **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + +### 4.1 数据集获取 +该模型使用[Market数据集](https://pan.baidu.com/s/1ntIi2Op?_at_=1622802619466)的19732张验证集进行测试。数据集下载后,解压放到./datasets目录下。 + +### 4.2 数据集预处理 +1.预处理脚本PCB_pth_preprocess.py + +2.执行预处理脚本,生成数据集预处理后的bin文件 +``` +python3.7 PCB_pth_preprocess.py -d market -b 1 --height 384 --width 128 --data-dir ./datasets/Market-1501/ -j 4 +``` +### 4.3 生成数据集信息文件 +1.生成数据集信息文件脚本get_info_Ascend310.sh + +2.执行生成数据集信息脚本,生成数据集信息文件 +``` +sh get_info_Ascend310.sh +``` +在get_info_Ascend310.sh文件中调用华为提供的开源工具获取bin文件的路径和尺寸信息,该工具的第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 +## 5 离线推理 + +- **[benchmark工具概述](#51-benchmark工具概述)** + +- **[离线推理](#52-离线推理)** + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN V100R020C10 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) +### 5.2 离线推理 +1.设置环境变量 +``` +source env.sh +``` +2.执行离线推理 +``` +sudo ./benchmark_tools/benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=./PCB.om -input_text_path=./gallery_preproc_data_Ascend310.info -input_width=128 -input_height=384 -output_binary=True -useDvpp=False +sudo mv ./result/dumpOutput_device0 ./result/dumpOutput_device0_gallery +sudo mv ./result/perf_vision_batchsize_1_device_0.txt ./result/gallery_perf_vision_batchsize_1_device_0.txt +``` +``` +sudo ./benchmark_tools/benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=./PCB.om -input_text_path=./query_preproc_data_Ascend310.info -input_width=128 -input_height=384 -output_binary=True -useDvpp=False +sudo mv ./result/dumpOutput_device0 ./result/dumpOutput_device0_query +sudo mv ./result/perf_vision_batchsize_1_device_0.txt ./result/query_perf_vision_batchsize_1_device_0.txt +``` +输出结果默认保存在当前目录result/dumpOutput_device0下,由于需要通过om模型提取两组特征,因此根据输入图片类型(querry或gallery)分别重命名文件夹。 +3.特征图后处理 + +``` +python ./PCB_pth_postprocess.py -q ./result/dumpOutput_device0_query -g ./result/dumpOutput_device0_gallery -d market --data-dir ./datasets/Market-1501/ +``` +对om模型提取的特征做后处理并统计精度,结果如下: +``` +{'title': 'Overall statistical evaluation', 'value': [{'key': 'Number of images', 'value': '15913'}, {'key': 'Number of classes', 'value': '751'}, {'key': 'Top-1 accuracy', 'value': '92.1%'}, {'key': 'Top-5 accuracy', 'value': '96.9%'}, {'key': 'Top-10 accuracy', 'value': '98.1%'}]} +``` +## 6 精度对比 + +- **[开源TopN精度](#61-开源TopN精度)** +- **[精度对比](#62-精度对比)** + +### 6.1 开源TopN精度 +``` +CMC Scores market1501 + top-1 92.1% + top-5 96.9% + top-10 98.1% +``` +### 6.2 精度对比 +将得到的om离线模型推理TopN精度与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 + **精度调试:** +>没有遇到精度不达标的问题,故不需要进行精度调试 + +## 7 性能对比 + +- **[npu性能数据](#71-npu性能数据)** + +### 7.1 npu性能数据 +benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准。 + +1.benchmark工具在整个数据集上推理获得性能数据 +batch1的性能,benchmark工具在整个数据集上推理后生成result/query_perf_vision_batchsize_1_device_0.txt.txt: +``` +-----------------Performance Summary------------------ +[e2e] throughputRate: 164.729, latency: 20445.7 +[data read] throughputRate: 184.812, moduleLatency: 5.41092 +[preprocess] throughputRate: 182.347, moduleLatency: 5.48405 +[infer] throughputRate: 175.577, Interface throughputRate: 253.855, moduleLatency: 4.91128 +[post] throughputRate: 175.573, moduleLatency: 5.69565 +``` +Interface throughputRate: 253.855,253.855* 4 = 1015.42既是batch1 310单卡吞吐率 + + +batch4的性能,benchmark工具在整个数据集上推理后生成result/query_perf_vision_batchsize_4_device_0.txt.txt: +``` +-----------------Performance Summary------------------ +[e2e] throughputRate: 157.081, latency: 21441.2 +[data read] throughputRate: 173.63, moduleLatency: 5.75937 +[preprocess] throughputRate: 171.283, moduleLatency: 5.83829 +[infer] throughputRate: 167.102, Interface throughputRate: 353.841, moduleLatency: 4.32693 +[post] throughputRate: 41.7725, moduleLatency: 23.9392 +``` +Interface throughputRate: 353.841,353.841* 4 = 1415.364既是batch4 310单卡吞吐率 + + +batch8的性能,benchmark工具在整个数据集上推理后生成result/query_perf_vision_batchsize_8_device_0.txt.txt: +``` +-----------------Performance Summary------------------ +[e2e] throughputRate: 132.514, latency: 25416.1 +[data read] throughputRate: 139.993, moduleLatency: 7.14319 +[preprocess] throughputRate: 139.054, moduleLatency: 7.19145 +[infer] throughputRate: 139.615, Interface throughputRate: 366.98, moduleLatency: 4.21507 +[post] throughputRate: 17.4505, moduleLatency: 57.305 +``` +Interface throughputRate: 366.98,366.98 * 4 = 1467.92既是batch8 310单卡吞吐率 + +batch16的性能,benchmark工具在整个数据集上推理后生成result/query_perf_vision_batchsize_16_device_0.txt.txt: +``` +-----------------Performance Summary------------------ +[e2e] throughputRate: 143.582, latency: 23457 +[data read] throughputRate: 150.172, moduleLatency: 6.65904 +[preprocess] throughputRate: 148.372, moduleLatency: 6.73981 +[infer] throughputRate: 147.201, Interface throughputRate: 362.414, moduleLatency: 4.28791 +[post] throughputRate: 9.22071, moduleLatency: 108.452 +``` +Interface throughputRate: 362.414,362.414 * 4 = 1449.656既是batch16 310单卡吞吐率 + + +batch32的性能,benchmark工具在整个数据集上推理后生成result/query_perf_vision_batchsize_32_device_0.txt.txt: +``` +-----------------Performance Summary------------------ +[e2e] throughputRate: 118.266, latency: 28478.2 +[data read] throughputRate: 126.885, moduleLatency: 7.88113 +[preprocess] throughputRate: 125.442, moduleLatency: 7.97179 +[infer] throughputRate: 124.065, Interface throughputRate: 354.632, moduleLatency: 4.30699 +[post] throughputRate: 3.90409, moduleLatency: 256.141 +``` +Interface throughputRate: 354.632,354.632 * 4 = 1418.528既是batch32 310单卡吞吐率 + +### 7.2 性能优化 +原始模型性能不达标原因分析: +根据profiling性能分析的表格,OM模型完成一次离线推理的总耗时中卷积计算(54次)、数据下采样(1次)和数据上采样(1次)这三类操作占总耗时的71%(36%+21%+19%)左右。再往细分,Task ID 95~101总耗时的53.6%,及7%的任务数占了一半以上的耗时。查看对应任务的算子类型,大多为数据转换类:向量尺寸变换和数据类型转换,推测与npu中的算子硬件实现相关。(详见性能分析报告) + +原始模型性能与优化后模型性能对比: +batch1:441.128fps(Ascend310) < 1015.42fps(Ascend310) +batch16:1024.56(Ascend310) < 1449.656fps(Ascend310) + + +#### 7.2.1固定模型输入的batch size,并结合onnxsim工具对onnx模型进行优化 +优化动机:通过Netron查看onnx的模型结构图发现有一些常量算子可以折叠 + +优化样例: + + python -m onnxsim --input-shape="16,3,384,128" ./PCB.onnx ./PCB_sim_bs16.onnx + +#### 7.42.2.把ReduceL2算子拆分为mul+sum+sqrt算子(无损) +优化动机:Profilingdata可以看到ReduceL2这个算子耗时占比较大,原因是ReduceL2这个算子缺少优化,但是拆分后的算子是经过优化的,且拆分算子后模型的精度保持不变,因此选择拆分ReduceL2算子 + +优化样例: + + python ../scripts/split_reducelp.py ./PCB_sim_bs16.onnx ./PCB_sim_split_bs16.onnx + +#### 7.2.3.atc自动优化选项——autotune +优化动机:atc工具提供的自动优化选项 + +优化样例: + + atc --framework=5 --model=./PCB_sim_bs4.onnx --output=./PCB_sim_autotune_bs4 --input_format=NCHW --input_shape="input_1:4,3,384,128" --log=debug --soc_version=Ascend310 --auto_tune_mode="RL,GA" diff --git a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/env.sh b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/env.sh index 2067d9b3a8..9bc1cb3e52 100644 --- a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/env.sh +++ b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/env.sh @@ -1,6 +1,6 @@ -#! /bin/bash -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp +#! /bin/bash +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp diff --git a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/get_info.py b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/get_info.py index 5af675c6b0..fc6cdebb5b 100644 --- a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/get_info.py +++ b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/get_info.py @@ -1,60 +1,60 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/modelzoo_level.txt index 39175166a4..119ddfc691 100644 --- a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/modelzoo_level.txt @@ -1,2 +1,2 @@ -ModelConvert:OK +ModelConvert:OK QuantStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/pth2onnx.py b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/pth2onnx.py index 78a1efa792..3c26b154e1 100644 --- a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/pth2onnx.py @@ -1,37 +1,37 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import argparse -from torch.autograd import Variable - - -def main(args): - model = torch.load(args.pth) - x = torch.randn(1, 3, 384, 128) - model.eval() - input_names=["input_1"] - output_names=["output_1"] - dynamic_axes = {'input_1': {0: '-1'}, 'output_1': {0: '-1'}} - x = Variable(x, volatile=True) - # Export the model - torch.onnx.export(model, x, "./models/PCB.onnx", input_names=input_names, output_names=output_names, \ - dynamic_axes=dynamic_axes, opset_version=11, verbose=True, do_constant_folding=True, export_params=True) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description="Softmax loss classification") - # data - parser.add_argument('-p', '--pth', type=str, default='./models/PCB_3_7.pt',) - main(parser.parse_args()) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import argparse +from torch.autograd import Variable + + +def main(args): + model = torch.load(args.pth) + x = torch.randn(1, 3, 384, 128) + model.eval() + input_names=["input_1"] + output_names=["output_1"] + dynamic_axes = {'input_1': {0: '-1'}, 'output_1': {0: '-1'}} + x = Variable(x, volatile=True) + # Export the model + torch.onnx.export(model, x, "./models/PCB.onnx", input_names=input_names, output_names=output_names, \ + dynamic_axes=dynamic_axes, opset_version=11, verbose=True, do_constant_folding=True, export_params=True) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description="Softmax loss classification") + # data + parser.add_argument('-p', '--pth', type=str, default='./models/PCB_3_7.pt',) + main(parser.parse_args()) diff --git a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/requirements.txt b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/requirements.txt index 37e7fabb8c..84c915b351 100644 --- a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/requirements.txt +++ b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/requirements.txt @@ -1,9 +1,9 @@ -torch == 1.8.1 -torchvision == 0.2.1 -numpy == 1.19.2 -opencv-python == 4.5.2.54 -onnx == 1.9.0 -skl2onnx == 1.8.0 -scikit-learn -h5py -onnx-simplifier +torch == 1.8.1 +torchvision == 0.2.1 +numpy == 1.19.2 +opencv-python == 4.5.2.54 +onnx == 1.9.0 +skl2onnx == 1.8.0 +scikit-learn +h5py +onnx-simplifier diff --git a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/Readme.md b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/Readme.md index 59da2c434c..0965701b46 100644 --- a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/Readme.md +++ b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/Readme.md @@ -1,69 +1,69 @@ -环境准备: - - -1.获取开源仓代码 - - git clone https://gitee.com/hu-zongqi/modelzoo.git - -2.数据集路径 - -通用的数据集统一放在/root/datasets/或/opt/npu/ - -本模型使用的数据集为Market_1501,放在目录/opt/npu/下 - - -3.进入工作目录 - - cd modelzoo/contrib/ACL_PyTorch/Research/cv/face/reid_PCB_baseline - -4.下载PCB模型论文开源仓代码,并将PCB_RPP_for_reID/reid目录下的datasets文件夹移动到当前目录 - - git clone https://github.com/syfafterzy/PCB_RPP_for_reID.git - cd PCB_RPP_for_reID - git checkout e29cf54486427d1423277d4c793e39ac0eeff87c - cd .. - cp -r PCB_RPP_for_reID/reid/datasets ./ - -5.合并补丁 - - cd modelzoo/contrib/ACL_PyTorch/Research/cv/face/reid_PCB_baseline - cp ./test/resnet.diff PCB_RPP_for_reID/reid/models - cd PCB_RPP_for_reID/reid/models - patch -p0 < resnet.diff - -6.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 - - cd modelzoo/contrib/ACL_PyTorch/Research/cv/face/reid_PCB_baseline - pip3.7 install -r requirements.txt - -下载onnx工具: - - cd modelzoo/contrib/ACL_PyTorch/Research/cv/face/reid_PCB_baseline/test - git clone https://gitee.com/zheng-wengang1/onnx_tools.git scripts/utils - cd scripts/utils - git checkout cbb099e5f2cef3d76c7630bffe0ee8250b03d921 - -7.获取benchmark工具 - -将benchmark.x86_64 放在modelzoo/contrib/ACL_PyTorch/Research/cv/face/reid_PCB_baseline目录下 - -8.移动PCB_RPP_for_reID/reid到modelzoo/contrib/ACL_PyTorch/Research/cv/face/reid_PCB_baseline下 - - cd modelzoo/contrib/ACL_PyTorch/Research/cv/face/reid_PCB_baseline - mv PCB_RPP_for_reID/reid ./ - -9.下载预训练模型文件 - - cd modelzoo/contrib/ACL_PyTorch/Research/cv/face/reid_PCB_baseline/test - mkdir models - wget -P ./models/ https://ascend-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/face/PCB/PCB_3_7.pt - - -10.310上执行,执行时确保device空闲 - - cd modelzoo/contrib/ACL_PyTorch/Research/cv/face/reid_PCB_baseline/test - dos2unix *.sh - dos2unix ../env.sh - source ../env.sh - sudo sh pth2om.sh - sudo sh eval_acc_perf.sh +环境准备: + + +1.获取开源仓代码 + + git clone https://gitee.com/hu-zongqi/modelzoo.git + +2.数据集路径 + +通用的数据集统一放在/root/datasets/或/opt/npu/ + +本模型使用的数据集为Market_1501,放在目录/opt/npu/下 + + +3.进入工作目录 + + cd modelzoo/contrib/ACL_PyTorch/Research/cv/face/reid_PCB_baseline + +4.下载PCB模型论文开源仓代码,并将PCB_RPP_for_reID/reid目录下的datasets文件夹移动到当前目录 + + git clone https://github.com/syfafterzy/PCB_RPP_for_reID.git + cd PCB_RPP_for_reID + git checkout e29cf54486427d1423277d4c793e39ac0eeff87c + cd .. + cp -r PCB_RPP_for_reID/reid/datasets ./ + +5.合并补丁 + + cd modelzoo/contrib/ACL_PyTorch/Research/cv/face/reid_PCB_baseline + cp ./test/resnet.diff PCB_RPP_for_reID/reid/models + cd PCB_RPP_for_reID/reid/models + patch -p0 < resnet.diff + +6.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 + + cd modelzoo/contrib/ACL_PyTorch/Research/cv/face/reid_PCB_baseline + pip3.7 install -r requirements.txt + +下载onnx工具: + + cd modelzoo/contrib/ACL_PyTorch/Research/cv/face/reid_PCB_baseline/test + git clone https://gitee.com/zheng-wengang1/onnx_tools.git scripts/utils + cd scripts/utils + git checkout cbb099e5f2cef3d76c7630bffe0ee8250b03d921 + +7.获取benchmark工具 + +将benchmark.x86_64 放在modelzoo/contrib/ACL_PyTorch/Research/cv/face/reid_PCB_baseline目录下 + +8.移动PCB_RPP_for_reID/reid到modelzoo/contrib/ACL_PyTorch/Research/cv/face/reid_PCB_baseline下 + + cd modelzoo/contrib/ACL_PyTorch/Research/cv/face/reid_PCB_baseline + mv PCB_RPP_for_reID/reid ./ + +9.下载预训练模型文件 + + cd modelzoo/contrib/ACL_PyTorch/Research/cv/face/reid_PCB_baseline/test + mkdir models + wget -P ./models/ https://ascend-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/face/PCB/PCB_3_7.pt + + +10.310上执行,执行时确保device空闲 + + cd modelzoo/contrib/ACL_PyTorch/Research/cv/face/reid_PCB_baseline/test + dos2unix *.sh + dos2unix ../env.sh + source ../env.sh + sudo sh pth2om.sh + sudo sh eval_acc_perf.sh diff --git a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/eval_acc_perf.sh b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/eval_acc_perf.sh index 0f11595c87..796bed2ed2 100644 --- a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/eval_acc_perf.sh +++ b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/eval_acc_perf.sh @@ -1,53 +1,53 @@ -#! /bin/bash - -#test - -#清除上次运行数据 -rm -r ./result/* -rm -r ./query_preproc_data_Ascend310 -rm -r ./gallery_preproc_data_Ascend310 -#数据预处理 -echo "preprocess......" -python3.7 ../PCB_pth_preprocess.py -d market -b 1 --height 384 --width 128 --data-dir /opt/npu/Market_1501/ -j 4 -#生成数据集信息文件 -echo "get_info......" -python3.7 ../get_info.py bin ./query_preproc_data_Ascend310 ./query_preproc_data_Ascend310.info 128 384 -python3.7 ../get_info.py bin ./gallery_preproc_data_Ascend310 ./gallery_preproc_data_Ascend310.info 128 384 -#离线推理 bs = 1 -echo "off-line inference bs = 1......" -#gallery -../benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=./models/PCB_sim_split_bs1_autotune.om -input_text_path=./gallery_preproc_data_Ascend310.info -input_width=128 -input_height=384 -output_binary=True -useDvpp=False >> gallary_bs1.log -mv ./result/dumpOutput_device0 ./result/dumpOutput_device0_gallery_bs1 -mv ./result/perf_vision_batchsize_1_device_0.txt ./result/gallery_perf_vision_batchsize_1_device_0.txt -#query -../benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=./models/PCB_sim_split_bs1_autotune.om -input_text_path=./query_preproc_data_Ascend310.info -input_width=128 -input_height=384 -output_binary=True -useDvpp=False >> query_bs1.log -mv ./result/dumpOutput_device0 ./result/dumpOutput_device0_query_bs1 -mv ./result/perf_vision_batchsize_1_device_0.txt ./result/query_perf_vision_batchsize_1_device_0.txt -#离线推理 bs = 16 -echo "off-line inference bs = 16......" -#gallery -../benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=16 -om_path=./models/PCB_sim_split_bs16_autotune.om -input_text_path=./gallery_preproc_data_Ascend310.info -input_width=128 -input_height=384 -output_binary=True -useDvpp=False >> gallary_bs16.log -mv ./result/dumpOutput_device0 ./result/dumpOutput_device0_gallery_bs16 -mv ./result/perf_vision_batchsize_16_device_0.txt ./result/gallery_perf_vision_batchsize_16_device_0.txt -#query -../benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=16 -om_path=./models/PCB_sim_split_bs16_autotune.om -input_text_path=./query_preproc_data_Ascend310.info -input_width=128 -input_height=384 -output_binary=True -useDvpp=False >> query_bs16.log -mv ./result/dumpOutput_device0 ./result/dumpOutput_device0_query_bs16 -mv ./result/perf_vision_batchsize_16_device_0.txt ./result/query_perf_vision_batchsize_16_device_0.txt -###数据后处理 -echo "postprocess......" -python3.7 ../PCB_pth_postprocess.py -q ./result/dumpOutput_device0_query_bs1 -g ./result/dumpOutput_device0_gallery_bs1 -d market --data-dir /opt/npu/Market_1501/ -echo "====performance data====" -echo "bs1 : " -python3.7 parse.py ./result/gallery_perf_vision_batchsize_1_device_0.txt -if [ $? != 0 ]; then - echo "fail!" - exit -1 -fi -echo "bs16 : " -python3.7 parse.py ./result/gallery_perf_vision_batchsize_16_device_0.txt -if [ $? != 0 ]; then - echo "fail!" - exit -1 -fi - -echo "success" +#! /bin/bash + +#test + +#清除上次运行数据 +rm -r ./result/* +rm -r ./query_preproc_data_Ascend310 +rm -r ./gallery_preproc_data_Ascend310 +#数据预处理 +echo "preprocess......" +python3.7 ../PCB_pth_preprocess.py -d market -b 1 --height 384 --width 128 --data-dir /opt/npu/Market_1501/ -j 4 +#生成数据集信息文件 +echo "get_info......" +python3.7 ../get_info.py bin ./query_preproc_data_Ascend310 ./query_preproc_data_Ascend310.info 128 384 +python3.7 ../get_info.py bin ./gallery_preproc_data_Ascend310 ./gallery_preproc_data_Ascend310.info 128 384 +#离线推理 bs = 1 +echo "off-line inference bs = 1......" +#gallery +../benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=./models/PCB_sim_split_bs1_autotune.om -input_text_path=./gallery_preproc_data_Ascend310.info -input_width=128 -input_height=384 -output_binary=True -useDvpp=False >> gallary_bs1.log +mv ./result/dumpOutput_device0 ./result/dumpOutput_device0_gallery_bs1 +mv ./result/perf_vision_batchsize_1_device_0.txt ./result/gallery_perf_vision_batchsize_1_device_0.txt +#query +../benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=./models/PCB_sim_split_bs1_autotune.om -input_text_path=./query_preproc_data_Ascend310.info -input_width=128 -input_height=384 -output_binary=True -useDvpp=False >> query_bs1.log +mv ./result/dumpOutput_device0 ./result/dumpOutput_device0_query_bs1 +mv ./result/perf_vision_batchsize_1_device_0.txt ./result/query_perf_vision_batchsize_1_device_0.txt +#离线推理 bs = 16 +echo "off-line inference bs = 16......" +#gallery +../benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=16 -om_path=./models/PCB_sim_split_bs16_autotune.om -input_text_path=./gallery_preproc_data_Ascend310.info -input_width=128 -input_height=384 -output_binary=True -useDvpp=False >> gallary_bs16.log +mv ./result/dumpOutput_device0 ./result/dumpOutput_device0_gallery_bs16 +mv ./result/perf_vision_batchsize_16_device_0.txt ./result/gallery_perf_vision_batchsize_16_device_0.txt +#query +../benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=16 -om_path=./models/PCB_sim_split_bs16_autotune.om -input_text_path=./query_preproc_data_Ascend310.info -input_width=128 -input_height=384 -output_binary=True -useDvpp=False >> query_bs16.log +mv ./result/dumpOutput_device0 ./result/dumpOutput_device0_query_bs16 +mv ./result/perf_vision_batchsize_16_device_0.txt ./result/query_perf_vision_batchsize_16_device_0.txt +###数据后处理 +echo "postprocess......" +python3.7 ../PCB_pth_postprocess.py -q ./result/dumpOutput_device0_query_bs1 -g ./result/dumpOutput_device0_gallery_bs1 -d market --data-dir /opt/npu/Market_1501/ +echo "====performance data====" +echo "bs1 : " +python3.7 parse.py ./result/gallery_perf_vision_batchsize_1_device_0.txt +if [ $? != 0 ]; then + echo "fail!" + exit -1 +fi +echo "bs16 : " +python3.7 parse.py ./result/gallery_perf_vision_batchsize_16_device_0.txt +if [ $? != 0 ]; then + echo "fail!" + exit -1 +fi + +echo "success" diff --git a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/parse.py b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/parse.py index b9c74f41d7..82af69cd18 100644 --- a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/parse.py +++ b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/pth2om.sh b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/pth2om.sh index 65dbe5abd5..8c1c58941d 100644 --- a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/pth2om.sh +++ b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/pth2om.sh @@ -1,19 +1,19 @@ -#! /bin/bash -echo "--------------------------------------------" -python3.7 ../pth2onnx.py -echo "--------------------------------------------" -python3.7 -m onnxsim --input-shape="1,3,384,128" ./models/PCB.onnx ./models/PCB_sim_bs1.onnx -echo "--------------------------------------------" -python3.7 -m onnxsim --input-shape="16,3,384,128" ./models/PCB.onnx ./models/PCB_sim_bs16.onnx -#bs1 -echo "--------------------------------------------" -python3.7 ./scripts/split_reducelp.py ./models/PCB_sim_bs1.onnx ./models/PCB_sim_split_bs1.onnx -#bs16 -echo "--------------------------------------------" -python3.7 ./scripts/split_reducelp.py ./models/PCB_sim_bs16.onnx ./models/PCB_sim_split_bs16.onnx -#转OM模型 bs=1 -echo "--------------------------------------------" -atc --framework=5 --model=./models/PCB_sim_split_bs1.onnx --output=./models/PCB_sim_split_bs1_autotune --input_format=NCHW --input_shape="input_1:1,3,384,128" --log=debug --soc_version=Ascend310 --auto_tune_mode="RL,GA" --out_nodes='Div_126:0;Gemm_191:0;Gemm_192:0;Gemm_193:0;Gemm_194:0;Gemm_195:0;Gemm_196:0' -#转OM模型 bs=16 -echo "--------------------------------------------" -atc --framework=5 --model=./models/PCB_sim_split_bs16.onnx --output=./models/PCB_sim_split_bs16_autotune --input_format=NCHW --input_shape="input_1:16,3,384,128" --log=debug --soc_version=Ascend310 --auto_tune_mode="RL,GA" --out_nodes='Div_126:0;Gemm_191:0;Gemm_192:0;Gemm_193:0;Gemm_194:0;Gemm_195:0;Gemm_196:0' +#! /bin/bash +echo "--------------------------------------------" +python3.7 ../pth2onnx.py +echo "--------------------------------------------" +python3.7 -m onnxsim --input-shape="1,3,384,128" ./models/PCB.onnx ./models/PCB_sim_bs1.onnx +echo "--------------------------------------------" +python3.7 -m onnxsim --input-shape="16,3,384,128" ./models/PCB.onnx ./models/PCB_sim_bs16.onnx +#bs1 +echo "--------------------------------------------" +python3.7 ./scripts/split_reducelp.py ./models/PCB_sim_bs1.onnx ./models/PCB_sim_split_bs1.onnx +#bs16 +echo "--------------------------------------------" +python3.7 ./scripts/split_reducelp.py ./models/PCB_sim_bs16.onnx ./models/PCB_sim_split_bs16.onnx +#转OM模型 bs=1 +echo "--------------------------------------------" +atc --framework=5 --model=./models/PCB_sim_split_bs1.onnx --output=./models/PCB_sim_split_bs1_autotune --input_format=NCHW --input_shape="input_1:1,3,384,128" --log=debug --soc_version=Ascend310 --auto_tune_mode="RL,GA" --out_nodes='Div_126:0;Gemm_191:0;Gemm_192:0;Gemm_193:0;Gemm_194:0;Gemm_195:0;Gemm_196:0' +#转OM模型 bs=16 +echo "--------------------------------------------" +atc --framework=5 --model=./models/PCB_sim_split_bs16.onnx --output=./models/PCB_sim_split_bs16_autotune --input_format=NCHW --input_shape="input_1:16,3,384,128" --log=debug --soc_version=Ascend310 --auto_tune_mode="RL,GA" --out_nodes='Div_126:0;Gemm_191:0;Gemm_192:0;Gemm_193:0;Gemm_194:0;Gemm_195:0;Gemm_196:0' diff --git a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/resnet.diff b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/resnet.diff index f3ed928252..77d06ca8a0 100644 --- a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/resnet.diff +++ b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/resnet.diff @@ -1,11 +1,11 @@ ---- resnet.py 2021-06-30 18:13:34.165260365 +0800 -+++ resnet_modified.py 2021-06-30 18:14:03.373647350 +0800 -@@ -128,7 +128,7 @@ class ResNet(nn.Module): - y = F.avg_pool3d(x,(16,1,1)).squeeze(1) - sx = x.size(2)/6 - kx = x.size(2)-sx*5 -- x = F.avg_pool2d(x,kernel_size=(kx,x.size(3)),stride=(sx,x.size(3))) # H4 W8 -+ x = F.avg_pool2d(x,kernel_size=(4,8),stride=(4,8)) # H4 W8 - #========================================================================# - - out0 = x.view(x.size(0),-1) +--- resnet.py 2021-06-30 18:13:34.165260365 +0800 ++++ resnet_modified.py 2021-06-30 18:14:03.373647350 +0800 +@@ -128,7 +128,7 @@ class ResNet(nn.Module): + y = F.avg_pool3d(x,(16,1,1)).squeeze(1) + sx = x.size(2)/6 + kx = x.size(2)-sx*5 +- x = F.avg_pool2d(x,kernel_size=(kx,x.size(3)),stride=(sx,x.size(3))) # H4 W8 ++ x = F.avg_pool2d(x,kernel_size=(4,8),stride=(4,8)) # H4 W8 + #========================================================================# + + out0 = x.view(x.size(0),-1) diff --git a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/scripts/split_reducelp.py b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/scripts/split_reducelp.py index dcbba7b5e7..fcf1f4e7a4 100644 --- a/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/scripts/split_reducelp.py +++ b/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline/test/scripts/split_reducelp.py @@ -1,51 +1,51 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -from utils.OXInterface.OXInterface import OXGraph - - -def main(input_model, out_path): - oxgraph = OXGraph(input_model) - # ReduceL2->ReduceSum - onnx_node = oxgraph.get_oxnode_by_name('ReduceL2_122') - onnx_node.set_op_type('ReduceSum') - onnx_node.set_name('ReduceSum1') - - # 插入mul+sqrt节点 - oxgraph.insert_node( - bef_node_info_list=['AveragePool_121:0', 'AveragePool_121:0'], - aft_node_info_list=['ReduceSum1'], - op_type='Mul', - op_name='Mul1' - ) - oxgraph.insert_node( - bef_node_info_list=['ReduceSum1'], - aft_node_info_list=['Expand_125'], - op_type='Sqrt', - op_name='Sqrt1' - ) - - oxgraph.save_new_model(out_path) - - -if __name__ == '__main__': - input_model = sys.argv[1] - out_path = sys.argv[2] - out_path = os.path.abspath(out_path) - print(input_model) - print(out_path) - os.makedirs(os.path.dirname(out_path), exist_ok=True) - main(input_model, out_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +from utils.OXInterface.OXInterface import OXGraph + + +def main(input_model, out_path): + oxgraph = OXGraph(input_model) + # ReduceL2->ReduceSum + onnx_node = oxgraph.get_oxnode_by_name('ReduceL2_122') + onnx_node.set_op_type('ReduceSum') + onnx_node.set_name('ReduceSum1') + + # 插入mul+sqrt节点 + oxgraph.insert_node( + bef_node_info_list=['AveragePool_121:0', 'AveragePool_121:0'], + aft_node_info_list=['ReduceSum1'], + op_type='Mul', + op_name='Mul1' + ) + oxgraph.insert_node( + bef_node_info_list=['ReduceSum1'], + aft_node_info_list=['Expand_125'], + op_type='Sqrt', + op_name='Sqrt1' + ) + + oxgraph.save_new_model(out_path) + + +if __name__ == '__main__': + input_model = sys.argv[1] + out_path = sys.argv[2] + out_path = os.path.abspath(out_path) + print(input_model) + print(out_path) + os.makedirs(os.path.dirname(out_path), exist_ok=True) + main(input_model, out_path) diff --git a/ACL_PyTorch/contrib/cv/gan/BigGAN/LICENSE b/ACL_PyTorch/contrib/cv/gan/BigGAN/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/gan/BigGAN/LICENSE +++ b/ACL_PyTorch/contrib/cv/gan/BigGAN/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/gan/BigGAN/README.md b/ACL_PyTorch/contrib/cv/gan/BigGAN/README.md index 78a0b1f9d5..b29bf32622 100644 --- a/ACL_PyTorch/contrib/cv/gan/BigGAN/README.md +++ b/ACL_PyTorch/contrib/cv/gan/BigGAN/README.md @@ -1,225 +1,225 @@ -# BigGAN ONNX模型端到端推理指导 -- [1. 模型概述](#1) - - [论文地址](#11) - - [代码地址](#12) -- [2. 环境说明](#2) - - [深度学习框架](#21) - - [python第三方库](#22) -- [3. 模型转换](#3) - - [pth转onnx模型](#31) - - [onnx转om模型](#32) -- [4. 输入数据生成](#4) - - [数据生成](#41) -- [5. 离线推理](#5) - - [msame工具概述](#51) - - [离线推理](#52) -- [6. 精度对比](#6) - - [模型后处理](#61) - - [精度计算](#62) - -## 1. 模型概述 -### 1.1 论文地址 -[BigGAN论文](https://arxiv.org/pdf/1809.11096.pdf) -### 1.2 代码地址 -[BigGAN代码](https://github.com/ajbrock/BigGAN-PyTorch) - -修改源码中的BigGAN.py、layers.py和inception_utils.py,并移至本项目中: -``` -git clone https://github.com/ajbrock/BigGAN-PyTorch.git -mv biggan.patch BigGAN-PyTorch -cd BigGAN-PyTorch -git apply biggan.patch -scp BigGAN.py .. -scp layers.py .. -scp inception_utils.py .. -cd .. -``` - -## 2. 环境说明 -### 2.1 深度学习框架 - -``` -CANN 5.0.3 -torch==1.8.0 -torchvision==0.9.0 -onnx==1.9.0 -``` -### 2.2 python第三方库 - -``` -numpy -onnxruntime -scipy==1.7.1 -onnx-simplifier==0.3.6 -onnxoptimizer==0.2.6 -``` - - **说明:** -> PyTorch版本: 请不要低于1.6.0,否则在.pth文件转.onnx文件的过程中会产生报错 -> pytorch,torchvision和onnx:(X86架构)可以通过官方下载whl包安装; (Arm架构)可以通过源码编译安装 -> 其他第三方库: 可以通过 pip3.7 install -r requirements.txt 进行安装 - -## 3. 模型转换 -一步式从pth权重文件转om模型的脚本,能够由pth权重文件生成bacth分别为1和16的om模型: -```bash -bash ./test/pth2om.sh -``` - **说明:** -> pth2om.sh中的6-14行: 完成pth转原始onnx模型 -> pth2om.sh中的18-29行: 完成onnx模型的简化,以及简化的onnx模型转om模型 - -运行后会生成如下文件: -```bash -├── biggan.onnx -├── biggan_sim_bs1.onnx -├── biggan_sim_bs16.onnx -├── biggan_sim_bs1.om -├── biggan_sim_bs16.om -``` - -### 3.1 pth转onnx模型 -1. 下载pth权重文件 - -[BigGAN预训练pth权重文件](https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/gan/BigGAN/G_ema.pth) -> **说明** -> 模型使用的权重文件名为G_ema.pth - -[Inception_v3预训练pth权重文件](https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/gan/BigGAN/inception_v3_google.pth) -> **说明** -> 下载的权重文件名为inception_v3_google.pth,此模型权重用于IS评价指标的计算,若仅进行图像生成,无需下载此权重文件 - -[ImageNet采样的npz数据](https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/gan/BigGAN/I128_inception_moments.npz) -> **说明** -> 采样数据名为I128_inception_moments.npz,此数据用于FID评价指标的计算,若仅进行图像生成,无需下载此数据文件 - -2. 执行biggan_pth2onnx.py脚本,生成onnx模型文件 -```bash -python3.7 biggan_pth2onnx.py --source "./G_ema.pth" --target "./biggan.onnx" -``` -若需要修改pth2onnx部分,请注意目前ATC支持的onnx算子版本为11 - -3. 执行clip_edit.py脚本,通过"input-model"和"output-model"参数指定输入和输出的onnx模型,默认输入输出均为"./biggan.onnx" -```bash -python3.7 clip_edit.py -``` -> **说明** -> 执行clip_edit.py目的在于初始化onnx模型中Clip节点中的"max"输入,便于后续onnx模型的简化 - -### 3.2 onnx转om模型 -1. 使用onnx-simplifier简化onnx模型 -生成batch size为1的简化onnx模型,对应的命令为: -```bash -python3.7 -m onnxsim './biggan.onnx' './biggan_sim_bs1.onnx' --input-shape "noise:1,1,20" "label:1,5,148" -``` - -2. 设置环境变量 - -```bash -source env.sh -``` - -3. 使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) - -```bash -atc --framework=5 --model=./biggan_sim_bs1.onnx --output=./biggan_sim_bs1 --input_format=ND --input_shape="noise:1,1,20;label:1,5,148" --log=error --soc_version=Ascend310 -``` - -## 4. 数据预处理 -- [输入数据生成](#41) -### 4.1 数据生成 -1. BigGAN模型的输入数据是由噪声数据和标签数据组成,其中噪声数据是由均值为0,方差为1的正态分布中采样,标签数据是由0至类别总数中随机采样一个整数 -2. 执行输入数据的生成脚本,生成模型输入的bin文件 - -```bash -#注:针对不同batch size的om模型需要生成不同的输入数据 -python3.7 biggan_preprocess.py --batch-size 1 --num-inputs 50000 -``` -运行后,将会得到如下形式的文件夹: - -``` -├── prep_label_bs1 -│ ├──input_00000.bin -│ ├──...... -│ -├── prep_noise_bs1 -│ ├──input_00000.bin -│ ├──...... -``` - -## 5. 离线推理 -执行一步式推理前,请先按照5.1节所示准备msame离线推理工具 -一步式进行输入数据的准备,模型离线推理和NPU性能数据的获取(针对batch1和batch16): -```bash -bash ./test/eval_perf.sh -``` -运行后会生成如下文件/文件夹: -```bash -├── prep_label_bs1 # 模型的标签输入(文件夹) -├── prep_label_bs16 -├── prep_noise_bs1 # 模型的噪声输入(文件夹) -├── prep_noise_bs16 -├── outputs_bs1_om # 模型的输出(文件夹) -├── outputs_bs16_om -├── gen_y_bs1.npz # 类别采样的npz数据 -├── gen_y_bs16.npz -├── msame_bs1.txt # msame推理过程的输出 -├── msame_bs16.txt -├── bs1_perf.log # 性能数据 -├── bs16_perf.log -``` -### 5.1 msame工具概述 -msame模型推理工具,其输入是om模型以及模型所需要的输入bin文件,其输出是模型根据相应输入产生的输出文件。获取工具及使用方法可以参考[msame模型推理工具指南](https://gitee.com/ascend/tools/tree/master/msame) -### 5.2 离线推理 -1. 设置环境变量 -```bash -source env.sh -``` -2. 执行离线推理 -运行如下命令进行离线推理: -```bash -./msame --model "./biggan_sim_bs1.om" --input "./prep_noise_bs1,./prep_label_bs1" --output "./outputs_bs1_om" --outfmt BIN > ./msame_bs1.txt -``` -模型输出格式是bin,输出保存在"output"参数指定的文件夹中,同时会生成推理的日志文件msame_bs1.txt -3. 性能数据的获取 -通过给test/parser.py指定推理后的日志文件,可以得到离线推理的性能数据 -```bash -python3.7 ./test/parse.py --txt-file "./msame_bs1.txt" --batch-size 1 > bs1_perf.log -``` -|模型|t4性能|310性能| -|----|----|----| -|BigGAN bs1|239.249fps|227.144fps| -|BigGAN bs16|344.900fps|282.898fps| - -## 6. 精度对比 -一步式进行输出数据的后处理和生成图像的评价指标(针对batch1和batch16): -```bash -bash ./test/eval_acc.sh -``` -运行后会生成如下文件/文件夹: -```bash -├── postprocess_img # 转换后的模型输出(文件夹) -├── gen_img_bs1.npz # 模型输出的npz数据 -├── gen_img_bs16.npz -├── biggan_acc_eval_bs1.log # 精度测量结果 -├── biggan_acc_eval_bs16.log -``` -### 6.1 模型后处理 -模型后处理将离线推理得到的bin文件转换为jpg图像文件,并将原始输出保存至npz文件中,用于精度数据的获取 -``` -python3.7 biggan_postprocess.py --result-path "./outputs_bs1_om" --save-path "./postprocess_img" --batch-size 1 --save-img --save-npz -``` -其中"result-path"表示离线推理输出所在的文件夹,"save-path"表示转换后图像文件的存储地址 -### 6.2 精度计算 -精度计算利用biggan_eval_acc.py脚本: -```bash -python3.7 biggan_eval_acc.py --num-inception-images 50000 --batch-size 1 --dataset 'I128' > biggan_acc_eval_bs1.log -``` -其中"num-inception-images"表示用于进行精度测量的输出数量,"dataset"指定用于对比分布所采用的数据集,I128表示ImageNet数据集在train上的采样 -> **说明** -> IS是生成图像的清晰度和多样性指标,其值越大说明越优 -> FID是生成图像集与真实图像集间的相似度指标,其值越小说明越优 - -| 模型 | IS | FID | -|-------|-------|-------| -|pth模型推理结果|94.323+/-2.395|9.9532| +# BigGAN ONNX模型端到端推理指导 +- [1. 模型概述](#1) + - [论文地址](#11) + - [代码地址](#12) +- [2. 环境说明](#2) + - [深度学习框架](#21) + - [python第三方库](#22) +- [3. 模型转换](#3) + - [pth转onnx模型](#31) + - [onnx转om模型](#32) +- [4. 输入数据生成](#4) + - [数据生成](#41) +- [5. 离线推理](#5) + - [msame工具概述](#51) + - [离线推理](#52) +- [6. 精度对比](#6) + - [模型后处理](#61) + - [精度计算](#62) + +## 1. 模型概述 +### 1.1 论文地址 +[BigGAN论文](https://arxiv.org/pdf/1809.11096.pdf) +### 1.2 代码地址 +[BigGAN代码](https://github.com/ajbrock/BigGAN-PyTorch) + +修改源码中的BigGAN.py、layers.py和inception_utils.py,并移至本项目中: +``` +git clone https://github.com/ajbrock/BigGAN-PyTorch.git +mv biggan.patch BigGAN-PyTorch +cd BigGAN-PyTorch +git apply biggan.patch +scp BigGAN.py .. +scp layers.py .. +scp inception_utils.py .. +cd .. +``` + +## 2. 环境说明 +### 2.1 深度学习框架 + +``` +CANN 5.0.3 +torch==1.8.0 +torchvision==0.9.0 +onnx==1.9.0 +``` +### 2.2 python第三方库 + +``` +numpy +onnxruntime +scipy==1.7.1 +onnx-simplifier==0.3.6 +onnxoptimizer==0.2.6 +``` + + **说明:** +> PyTorch版本: 请不要低于1.6.0,否则在.pth文件转.onnx文件的过程中会产生报错 +> pytorch,torchvision和onnx:(X86架构)可以通过官方下载whl包安装; (Arm架构)可以通过源码编译安装 +> 其他第三方库: 可以通过 pip3.7 install -r requirements.txt 进行安装 + +## 3. 模型转换 +一步式从pth权重文件转om模型的脚本,能够由pth权重文件生成bacth分别为1和16的om模型: +```bash +bash ./test/pth2om.sh +``` + **说明:** +> pth2om.sh中的6-14行: 完成pth转原始onnx模型 +> pth2om.sh中的18-29行: 完成onnx模型的简化,以及简化的onnx模型转om模型 + +运行后会生成如下文件: +```bash +├── biggan.onnx +├── biggan_sim_bs1.onnx +├── biggan_sim_bs16.onnx +├── biggan_sim_bs1.om +├── biggan_sim_bs16.om +``` + +### 3.1 pth转onnx模型 +1. 下载pth权重文件 + +[BigGAN预训练pth权重文件](https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/gan/BigGAN/G_ema.pth) +> **说明** +> 模型使用的权重文件名为G_ema.pth + +[Inception_v3预训练pth权重文件](https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/gan/BigGAN/inception_v3_google.pth) +> **说明** +> 下载的权重文件名为inception_v3_google.pth,此模型权重用于IS评价指标的计算,若仅进行图像生成,无需下载此权重文件 + +[ImageNet采样的npz数据](https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/gan/BigGAN/I128_inception_moments.npz) +> **说明** +> 采样数据名为I128_inception_moments.npz,此数据用于FID评价指标的计算,若仅进行图像生成,无需下载此数据文件 + +2. 执行biggan_pth2onnx.py脚本,生成onnx模型文件 +```bash +python3.7 biggan_pth2onnx.py --source "./G_ema.pth" --target "./biggan.onnx" +``` +若需要修改pth2onnx部分,请注意目前ATC支持的onnx算子版本为11 + +3. 执行clip_edit.py脚本,通过"input-model"和"output-model"参数指定输入和输出的onnx模型,默认输入输出均为"./biggan.onnx" +```bash +python3.7 clip_edit.py +``` +> **说明** +> 执行clip_edit.py目的在于初始化onnx模型中Clip节点中的"max"输入,便于后续onnx模型的简化 + +### 3.2 onnx转om模型 +1. 使用onnx-simplifier简化onnx模型 +生成batch size为1的简化onnx模型,对应的命令为: +```bash +python3.7 -m onnxsim './biggan.onnx' './biggan_sim_bs1.onnx' --input-shape "noise:1,1,20" "label:1,5,148" +``` + +2. 设置环境变量 + +```bash +source env.sh +``` + +3. 使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN V100R020C10 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) + +```bash +atc --framework=5 --model=./biggan_sim_bs1.onnx --output=./biggan_sim_bs1 --input_format=ND --input_shape="noise:1,1,20;label:1,5,148" --log=error --soc_version=Ascend310 +``` + +## 4. 数据预处理 +- [输入数据生成](#41) +### 4.1 数据生成 +1. BigGAN模型的输入数据是由噪声数据和标签数据组成,其中噪声数据是由均值为0,方差为1的正态分布中采样,标签数据是由0至类别总数中随机采样一个整数 +2. 执行输入数据的生成脚本,生成模型输入的bin文件 + +```bash +#注:针对不同batch size的om模型需要生成不同的输入数据 +python3.7 biggan_preprocess.py --batch-size 1 --num-inputs 50000 +``` +运行后,将会得到如下形式的文件夹: + +``` +├── prep_label_bs1 +│ ├──input_00000.bin +│ ├──...... +│ +├── prep_noise_bs1 +│ ├──input_00000.bin +│ ├──...... +``` + +## 5. 离线推理 +执行一步式推理前,请先按照5.1节所示准备msame离线推理工具 +一步式进行输入数据的准备,模型离线推理和NPU性能数据的获取(针对batch1和batch16): +```bash +bash ./test/eval_perf.sh +``` +运行后会生成如下文件/文件夹: +```bash +├── prep_label_bs1 # 模型的标签输入(文件夹) +├── prep_label_bs16 +├── prep_noise_bs1 # 模型的噪声输入(文件夹) +├── prep_noise_bs16 +├── outputs_bs1_om # 模型的输出(文件夹) +├── outputs_bs16_om +├── gen_y_bs1.npz # 类别采样的npz数据 +├── gen_y_bs16.npz +├── msame_bs1.txt # msame推理过程的输出 +├── msame_bs16.txt +├── bs1_perf.log # 性能数据 +├── bs16_perf.log +``` +### 5.1 msame工具概述 +msame模型推理工具,其输入是om模型以及模型所需要的输入bin文件,其输出是模型根据相应输入产生的输出文件。获取工具及使用方法可以参考[msame模型推理工具指南](https://gitee.com/ascend/tools/tree/master/msame) +### 5.2 离线推理 +1. 设置环境变量 +```bash +source env.sh +``` +2. 执行离线推理 +运行如下命令进行离线推理: +```bash +./msame --model "./biggan_sim_bs1.om" --input "./prep_noise_bs1,./prep_label_bs1" --output "./outputs_bs1_om" --outfmt BIN > ./msame_bs1.txt +``` +模型输出格式是bin,输出保存在"output"参数指定的文件夹中,同时会生成推理的日志文件msame_bs1.txt +3. 性能数据的获取 +通过给test/parser.py指定推理后的日志文件,可以得到离线推理的性能数据 +```bash +python3.7 ./test/parse.py --txt-file "./msame_bs1.txt" --batch-size 1 > bs1_perf.log +``` +|模型|t4性能|310性能| +|----|----|----| +|BigGAN bs1|239.249fps|227.144fps| +|BigGAN bs16|344.900fps|282.898fps| + +## 6. 精度对比 +一步式进行输出数据的后处理和生成图像的评价指标(针对batch1和batch16): +```bash +bash ./test/eval_acc.sh +``` +运行后会生成如下文件/文件夹: +```bash +├── postprocess_img # 转换后的模型输出(文件夹) +├── gen_img_bs1.npz # 模型输出的npz数据 +├── gen_img_bs16.npz +├── biggan_acc_eval_bs1.log # 精度测量结果 +├── biggan_acc_eval_bs16.log +``` +### 6.1 模型后处理 +模型后处理将离线推理得到的bin文件转换为jpg图像文件,并将原始输出保存至npz文件中,用于精度数据的获取 +``` +python3.7 biggan_postprocess.py --result-path "./outputs_bs1_om" --save-path "./postprocess_img" --batch-size 1 --save-img --save-npz +``` +其中"result-path"表示离线推理输出所在的文件夹,"save-path"表示转换后图像文件的存储地址 +### 6.2 精度计算 +精度计算利用biggan_eval_acc.py脚本: +```bash +python3.7 biggan_eval_acc.py --num-inception-images 50000 --batch-size 1 --dataset 'I128' > biggan_acc_eval_bs1.log +``` +其中"num-inception-images"表示用于进行精度测量的输出数量,"dataset"指定用于对比分布所采用的数据集,I128表示ImageNet数据集在train上的采样 +> **说明** +> IS是生成图像的清晰度和多样性指标,其值越大说明越优 +> FID是生成图像集与真实图像集间的相似度指标,其值越小说明越优 + +| 模型 | IS | FID | +|-------|-------|-------| +|pth模型推理结果|94.323+/-2.395|9.9532| |om模型离线推理结果|94.009+/-1.626|10.0411| \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/gan/BigGAN/biggan_pth2onnx.py b/ACL_PyTorch/contrib/cv/gan/BigGAN/biggan_pth2onnx.py index 87fc7ce99c..060de08256 100644 --- a/ACL_PyTorch/contrib/cv/gan/BigGAN/biggan_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/gan/BigGAN/biggan_pth2onnx.py @@ -1,63 +1,63 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 onnx -import torch -import argparse - -from BigGAN import Generator -from collections import OrderedDict - - -def proc_nodes_module(checkpoint): - new_state_dict = OrderedDict() - for k, v in checkpoint.items(): - if (k[0:7] == "module."): - name = k[7:] - else: - name = k[0:] - new_state_dict[name] = v - return new_state_dict - - -def pth2onnx(input_file, output_file): - checkpoint = torch.load(input_file, map_location=torch.device('cpu')) - checkpoint = proc_nodes_module(checkpoint) - - model = Generator(**{'G_lr':1e-4, 'SN_eps':1e-6, 'adam_eps':1e-6, - 'G_ch':96, 'shared_dim':128, - 'skip_init':True, 'no_optim': True, - 'hier':True, 'dim_z':120}) - model.load_state_dict(checkpoint) - model.eval() - - input_names = ['noise', 'label'] - output_names = ['image'] - dynamic_axes = {'noise': {0: '-1'}, 'label': {0: '-1'}, 'image': {0: '-1'}} - - dummy_z = torch.randn((1, 1, 20)) - dummy_y = torch.randn((1, 5, 148)) - - torch.onnx.export(model, (dummy_z, dummy_y), output_file, dynamic_axes=dynamic_axes, - verbose=True, input_names=input_names, output_names=output_names, opset_version=11) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--source', type=str, default="./G_ema.pth") - parser.add_argument('--target', type=str, default="./biggan.onnx") - args = parser.parse_args() - - pth2onnx(args.source, args.target) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 onnx +import torch +import argparse + +from BigGAN import Generator +from collections import OrderedDict + + +def proc_nodes_module(checkpoint): + new_state_dict = OrderedDict() + for k, v in checkpoint.items(): + if (k[0:7] == "module."): + name = k[7:] + else: + name = k[0:] + new_state_dict[name] = v + return new_state_dict + + +def pth2onnx(input_file, output_file): + checkpoint = torch.load(input_file, map_location=torch.device('cpu')) + checkpoint = proc_nodes_module(checkpoint) + + model = Generator(**{'G_lr':1e-4, 'SN_eps':1e-6, 'adam_eps':1e-6, + 'G_ch':96, 'shared_dim':128, + 'skip_init':True, 'no_optim': True, + 'hier':True, 'dim_z':120}) + model.load_state_dict(checkpoint) + model.eval() + + input_names = ['noise', 'label'] + output_names = ['image'] + dynamic_axes = {'noise': {0: '-1'}, 'label': {0: '-1'}, 'image': {0: '-1'}} + + dummy_z = torch.randn((1, 1, 20)) + dummy_y = torch.randn((1, 5, 148)) + + torch.onnx.export(model, (dummy_z, dummy_y), output_file, dynamic_axes=dynamic_axes, + verbose=True, input_names=input_names, output_names=output_names, opset_version=11) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--source', type=str, default="./G_ema.pth") + parser.add_argument('--target', type=str, default="./biggan.onnx") + args = parser.parse_args() + + pth2onnx(args.source, args.target) diff --git a/ACL_PyTorch/contrib/cv/gan/BigGAN/requirements.txt b/ACL_PyTorch/contrib/cv/gan/BigGAN/requirements.txt index 71eeab2b4d..ac7e94fc98 100644 --- a/ACL_PyTorch/contrib/cv/gan/BigGAN/requirements.txt +++ b/ACL_PyTorch/contrib/cv/gan/BigGAN/requirements.txt @@ -1,5 +1,5 @@ -numpy -onnxruntime==1.9.0 -scipy==1.7.1 -onnx-simplifier==0.3.6 +numpy +onnxruntime==1.9.0 +scipy==1.7.1 +onnx-simplifier==0.3.6 onnxoptimizer==0.2.6 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/gan/CGAN/CGAN_postprocess.py b/ACL_PyTorch/contrib/cv/gan/CGAN/CGAN_postprocess.py index 337d3a4ff0..7f6d581304 100644 --- a/ACL_PyTorch/contrib/cv/gan/CGAN/CGAN_postprocess.py +++ b/ACL_PyTorch/contrib/cv/gan/CGAN/CGAN_postprocess.py @@ -1,76 +1,76 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -from CGAN import generator as G -import os -import numpy as np -import torch -import struct -import glob -import sys -import utils -import argparse - - -def parse_args(): - desc = "Pytorch implementation of CGAN collections" - parser = argparse.ArgumentParser(description=desc) - parser.add_argument('--bin_out_path', type=str, default='', help="the output inferenced") - parser.add_argument('--save_path', type=str, default='result', help="the generated image path") - return parser.parse_args() - - -def get_save_path(bin_folder): - result_paths = [] - files_source = glob.glob(os.path.join(bin_folder,'*.bin')) - files_source.sort() - for file in files_source: - if file.endswith('.bin'): - result_path = file - result_paths.append(result_path) - return result_paths - - -def file2tensor(output_bin): - size = os.path.getsize(output_bin) - res1 = [] - L = int(size / 4) - binfile = open(output_bin, 'rb') - for i in range(L): - data = binfile.read(4) - num = struct.unpack('f', data) - res1.append(num[0]) - binfile.close() - dim_res = np.array(res1).reshape(100,3,28,28) - tensor_res = torch.tensor(dim_res, dtype=torch.float32) - return tensor_res - - -def post_process(args): - result_paths = get_save_path(args.bin_out_path) - for i in range(len(result_paths)): - result = file2tensor(result_paths[i]) - result = result.data.numpy().transpose(0, 2, 3, 1) - result = (result + 1)/2 - sample_num = 100 - image_frame_dim = int(np.floor(np.sqrt(sample_num))) - if not os.path.exists(os.path.join(args.save_path)): - os.makedirs(os.path.join(args.save_path)) - utils.save_images(result[:image_frame_dim * image_frame_dim, :, :, :], [image_frame_dim, image_frame_dim], - os.path.join(args.save_path,'result.png')) - print("postprocess image stored in:", os.path.join(args.save_path,'result.png')) - -if __name__ == "__main__": - args = parse_args() - post_process(args) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +from CGAN import generator as G +import os +import numpy as np +import torch +import struct +import glob +import sys +import utils +import argparse + + +def parse_args(): + desc = "Pytorch implementation of CGAN collections" + parser = argparse.ArgumentParser(description=desc) + parser.add_argument('--bin_out_path', type=str, default='', help="the output inferenced") + parser.add_argument('--save_path', type=str, default='result', help="the generated image path") + return parser.parse_args() + + +def get_save_path(bin_folder): + result_paths = [] + files_source = glob.glob(os.path.join(bin_folder,'*.bin')) + files_source.sort() + for file in files_source: + if file.endswith('.bin'): + result_path = file + result_paths.append(result_path) + return result_paths + + +def file2tensor(output_bin): + size = os.path.getsize(output_bin) + res1 = [] + L = int(size / 4) + binfile = open(output_bin, 'rb') + for i in range(L): + data = binfile.read(4) + num = struct.unpack('f', data) + res1.append(num[0]) + binfile.close() + dim_res = np.array(res1).reshape(100,3,28,28) + tensor_res = torch.tensor(dim_res, dtype=torch.float32) + return tensor_res + + +def post_process(args): + result_paths = get_save_path(args.bin_out_path) + for i in range(len(result_paths)): + result = file2tensor(result_paths[i]) + result = result.data.numpy().transpose(0, 2, 3, 1) + result = (result + 1)/2 + sample_num = 100 + image_frame_dim = int(np.floor(np.sqrt(sample_num))) + if not os.path.exists(os.path.join(args.save_path)): + os.makedirs(os.path.join(args.save_path)) + utils.save_images(result[:image_frame_dim * image_frame_dim, :, :, :], [image_frame_dim, image_frame_dim], + os.path.join(args.save_path,'result.png')) + print("postprocess image stored in:", os.path.join(args.save_path,'result.png')) + +if __name__ == "__main__": + args = parse_args() + post_process(args) diff --git a/ACL_PyTorch/contrib/cv/gan/CGAN/CGAN_preprocess.py b/ACL_PyTorch/contrib/cv/gan/CGAN/CGAN_preprocess.py index 35c336b779..a2bf65dca8 100644 --- a/ACL_PyTorch/contrib/cv/gan/CGAN/CGAN_preprocess.py +++ b/ACL_PyTorch/contrib/cv/gan/CGAN/CGAN_preprocess.py @@ -1,63 +1,63 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import torch -import numpy as np -import os -import argparse - - -def parse_args(): - desc = "Pytorch implementation of CGAN collections" - parser = argparse.ArgumentParser(description=desc) - parser.add_argument('--input_dim', type=int, default=62, help="The input_dim") - parser.add_argument('--output_dim', type=int, default=3, help="The output_dim") - parser.add_argument('--input_size', type=int, default=28, help="The image size of MNIST") - parser.add_argument('--class_num', type=int, default=10, help="The num of classes of MNIST") - parser.add_argument('--pth_path', type=str, default='CGAN_G.pth', help='pth model path') - parser.add_argument('--onnx_path', type=str, default="CGAN.onnx", help='onnx model path') - parser.add_argument('--save_path', type=str, default="data", help='processed data path') - return parser.parse_args() - - -# fixed noise & condition -def prep_preocess(args): - sample_num = args.class_num**2 - z_dim = args.input_dim - sample_z_ = torch.zeros((sample_num, z_dim)) - for i in range(args.class_num): - sample_z_[i * args.class_num] = torch.rand(1,z_dim) - for j in range(1, args.class_num): - sample_z_[i * args.class_num + j] = sample_z_[i * args.class_num] - - if not os.path.exists(os.path.join(args.save_path)): - os.makedirs(os.path.join(args.save_path)) - - temp = torch.zeros((args.class_num, 1)) - for i in range(args.class_num): - temp[i, 0] = i - - temp_y = torch.zeros((sample_num, 1)) - for i in range(args.class_num): - temp_y[i * args.class_num: (i + 1) * args.class_num] = temp - - sample_y_ = torch.zeros((sample_num, args.class_num)).scatter_(1, temp_y.type(torch.LongTensor), 1) - - input = torch.cat([sample_z_, sample_y_], 1) - input = np.array(input).astype(np.float32) - input.tofile(os.path.join(args.save_path, 'input' + '.bin')) -if __name__ == "__main__": - args = parse_args() - prep_preocess(args) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import torch +import numpy as np +import os +import argparse + + +def parse_args(): + desc = "Pytorch implementation of CGAN collections" + parser = argparse.ArgumentParser(description=desc) + parser.add_argument('--input_dim', type=int, default=62, help="The input_dim") + parser.add_argument('--output_dim', type=int, default=3, help="The output_dim") + parser.add_argument('--input_size', type=int, default=28, help="The image size of MNIST") + parser.add_argument('--class_num', type=int, default=10, help="The num of classes of MNIST") + parser.add_argument('--pth_path', type=str, default='CGAN_G.pth', help='pth model path') + parser.add_argument('--onnx_path', type=str, default="CGAN.onnx", help='onnx model path') + parser.add_argument('--save_path', type=str, default="data", help='processed data path') + return parser.parse_args() + + +# fixed noise & condition +def prep_preocess(args): + sample_num = args.class_num**2 + z_dim = args.input_dim + sample_z_ = torch.zeros((sample_num, z_dim)) + for i in range(args.class_num): + sample_z_[i * args.class_num] = torch.rand(1,z_dim) + for j in range(1, args.class_num): + sample_z_[i * args.class_num + j] = sample_z_[i * args.class_num] + + if not os.path.exists(os.path.join(args.save_path)): + os.makedirs(os.path.join(args.save_path)) + + temp = torch.zeros((args.class_num, 1)) + for i in range(args.class_num): + temp[i, 0] = i + + temp_y = torch.zeros((sample_num, 1)) + for i in range(args.class_num): + temp_y[i * args.class_num: (i + 1) * args.class_num] = temp + + sample_y_ = torch.zeros((sample_num, args.class_num)).scatter_(1, temp_y.type(torch.LongTensor), 1) + + input = torch.cat([sample_z_, sample_y_], 1) + input = np.array(input).astype(np.float32) + input.tofile(os.path.join(args.save_path, 'input' + '.bin')) +if __name__ == "__main__": + args = parse_args() + prep_preocess(args) print("data preprocessed stored in",args.save_path) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/gan/CGAN/CGAN_pth2onnx.py b/ACL_PyTorch/contrib/cv/gan/CGAN/CGAN_pth2onnx.py index 2da7ae2176..0ee964ab8a 100644 --- a/ACL_PyTorch/contrib/cv/gan/CGAN/CGAN_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/gan/CGAN/CGAN_pth2onnx.py @@ -1,66 +1,66 @@ - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 CGAN import generator -import torch -import torch.onnx -import sys -from collections import OrderedDict -import argparse - - -def parse_args(): - desc = "Pytorch implementation of CGAN collections" - parser = argparse.ArgumentParser(description=desc) - parser.add_argument('--input_dim', type=int, default=62, help="The input_dim") - parser.add_argument('--output_dim', type=int, default=3, help="The output_dim") - parser.add_argument('--input_size', type=int, default=28, help="The image size of MNIST") - parser.add_argument('--class_num', type=int, default=10, help="The num of classes of MNIST") - parser.add_argument('--pth_path', type=str, default='CGAN_G.pth', help='pth model path') - parser.add_argument('--onnx_path', type=str, default="CGAN.onnx", help='onnx model path') - return parser.parse_args() - - -def proc_nodes_module(checkpoint): - new_state_dict = OrderedDict() - for k, v in checkpoint.items(): - if "module." in k: - name = k.replace("module.", "") - else: - name = k - new_state_dict[name] = v - return new_state_dict - -def pth2onnx(): - args = parse_args() - net = generator(input_dim=args.input_dim, output_dim=args.output_dim, - input_size=args.input_size, class_num=args.class_num) - model = net - checkpoint = torch.load(args.pth_path, map_location='cpu') - checkpoint = proc_nodes_module(checkpoint) - model.load_state_dict(checkpoint) - model.eval() - input_names = ["image"] - output_names = ["output1"] - #dynamic_axes = {'image': {0: '-1'}, 'output1': {0: '-1'}} - dummy_input1 = torch.randn(100, 72) - torch.onnx.export(model, dummy_input1, args.onnx_path, input_names=input_names, - output_names=output_names, opset_version=11, verbose=True) - print("this model could generete pictures, specifically digits") - print('onnx export done.') - - -if __name__ == "__main__": + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 CGAN import generator +import torch +import torch.onnx +import sys +from collections import OrderedDict +import argparse + + +def parse_args(): + desc = "Pytorch implementation of CGAN collections" + parser = argparse.ArgumentParser(description=desc) + parser.add_argument('--input_dim', type=int, default=62, help="The input_dim") + parser.add_argument('--output_dim', type=int, default=3, help="The output_dim") + parser.add_argument('--input_size', type=int, default=28, help="The image size of MNIST") + parser.add_argument('--class_num', type=int, default=10, help="The num of classes of MNIST") + parser.add_argument('--pth_path', type=str, default='CGAN_G.pth', help='pth model path') + parser.add_argument('--onnx_path', type=str, default="CGAN.onnx", help='onnx model path') + return parser.parse_args() + + +def proc_nodes_module(checkpoint): + new_state_dict = OrderedDict() + for k, v in checkpoint.items(): + if "module." in k: + name = k.replace("module.", "") + else: + name = k + new_state_dict[name] = v + return new_state_dict + +def pth2onnx(): + args = parse_args() + net = generator(input_dim=args.input_dim, output_dim=args.output_dim, + input_size=args.input_size, class_num=args.class_num) + model = net + checkpoint = torch.load(args.pth_path, map_location='cpu') + checkpoint = proc_nodes_module(checkpoint) + model.load_state_dict(checkpoint) + model.eval() + input_names = ["image"] + output_names = ["output1"] + #dynamic_axes = {'image': {0: '-1'}, 'output1': {0: '-1'}} + dummy_input1 = torch.randn(100, 72) + torch.onnx.export(model, dummy_input1, args.onnx_path, input_names=input_names, + output_names=output_names, opset_version=11, verbose=True) + print("this model could generete pictures, specifically digits") + print('onnx export done.') + + +if __name__ == "__main__": pth2onnx() \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/gan/CGAN/README.md b/ACL_PyTorch/contrib/cv/gan/CGAN/README.md index 659e1d55f7..dd932ea1ad 100644 --- a/ACL_PyTorch/contrib/cv/gan/CGAN/README.md +++ b/ACL_PyTorch/contrib/cv/gan/CGAN/README.md @@ -1,265 +1,265 @@ -# CGAN推理说明 - -## 1 模型概述 - -- **[论文地址](https://arxiv.org/abs/1411.1784)** -- **[代码地址](https://github.com/znxlwm/pytorch-generative-model-collections/)** - -### 1.1 论文地址 - -[CGAN论文](https://github.com/znxlwm/pytorch-generative-model-collections/) - -### 1.2 代码地址 - -[CGAN代码](https://github.com/znxlwm/pytorch-generative-model-collections/) - -branch:master - -commitid:0d183bb5ea2fbe069e1c6806c4a9a1fd8e81656f - - -## 2 环境说明 - -- 深度学习框架 -- python第三方库 - -### 2.1 深度学习框架 - -``` -python3.7.5 -CANN 5.0.3 - -pytorch == 1.5.0 -torchvision == 0.6.0 -onnx == 1.10.2 -``` - -### 2.2 python第三方库 - -``` -numpy == 1.21.2 -Pillow == 8.4.0 -imageio == 2.9.0 -scipy == 1.7.1 -matplotlib==3.4.3 -``` - -## 3 模型转换 - -- pth转om模型 - -### 3.1 pth转om模型 - -1.获取pth权重文件 - -pth权重文件随附件一起打包 - -2.下载CGAN推理代码 - -``` -git clone https://gitee.com/wang-chaojiemayj/modelzoo.git -cd modelzoo -git checkout tuili -``` - -进入CGANt目录 - -``` -cd ./contrib/ACL_PyTorch/Research/cv/GAN/CGAN -``` - -3.pth模型转onnx模型,onnx转成om模型 - -pth模型转onnx模型 - -``` -python3.7 CGAN_pth2onnx.py --pth_path CGAN_G.pth --onnx_path CGAN.onnx -python3.7 -m onnxsim --input-shape="100,72" CGAN.onnx CGAN_sim.onnx -``` - -onnx转出om,并使用autotune优化om模型,这将耗费大量时间 - -``` -source env.sh(注意,latest是一个软连接,请将服务器中的/usr/local/Ascend/ascend-toolkit/latest 指向5.0.3版本的CANN包) -# 生成器一次只能生成一张图,由于模型输入是两维的,不是常用的NCHW格式,input_format采用ND形式 -atc --framework=5 --model=CGAN_sim.onnx --output=CGAN_bs1 --input_format=ND --output_type=FP32 --input_shape="image:100,72" --log=debug --soc_version=Ascend310 --auto_tune_mode="RL,GA" -``` - -## 4 数据集预处理 - -- 数据集获取 -- 数据预处理 -- 生成数据集信息文件 - -### 4.1 数据集获取 - -本模型的输入数据由随机数以及标签生成,在CGAN_preprocess.py中会生成数据并转成二进制文件,并保存在。’./prep_dataset‘目录下。 - -文件结构如下 - -``` -|CGAN--test -| | |--pth2om.sh -| | |--eval_acc_perf.sh -| | |--perf_t4.sh -| |--util.py -| |--CGAN.py -| |--gen_dataset_info.py -| |--env.sh -| |--CGAN_pth2onnx.py -| |--CGAN_preprocess.py -| |--CGAN_postprocess.py -| |--requirements.txt -| |--LICENCE -| |--modelzoo_level.txt -| |--README.md -``` - - -### 4.2 数据集预处理 - -运行CGAN_preprocess.py - -``` -python3.7 CGAN_preprocess.py --save_path ./prep_dataset -``` - -二进制文件将保存在./prep_dataset目录下 - -### 4.3 生成数据集信息文件 - -1.执行生成数据集信息脚本gen_dataset_info.py,生成数据集信息文件 - -``` -python3.7 gen_dataset_info.py --dataset_bin ./prep_dataset --info_name CGAN_prep_bin.info --width 72 --height 100 -``` - -## 5 离线推理 - -- msame概述 -- 离线推理 - -### 5.1 msame工具概述 - -msame工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN 5.0.1 推理msame工具用户指南 - -### 5.2 离线推理 - -1.设置环境变量 - -``` -source env.sh -``` - -2.执行离线推理 - -``` -./msame --model "./CGAN_bs1.om" --input "./prep_dataset/input.bin" --output "./out" --outfmt BIN --loop 1 -``` - -输出结果保存在'./out'目录下 - -## 6 精度对比 - -- 离线推理精度 -- 开源精度 -- 开源精度对比 - -### 6.1 离线推理精度统计 - -将msame推理获得的输出结果进行后处理,保存为图片 - -``` -python3.7 CGAN_postprocess.py --bin_out_path ./out/20211124_090506 --save_path ./result -``` - -第一个参数为msame输出目录,’/20211113_073952‘是离线推理时根据时间自动生成的目录,请根据实际情况改变,第二个参数为保存后处理产生的图片的目录。 - -### 6.2 开源精度 - -![](README.assets/CGAN_epoch050-16371406300071.png) - -### 6.3 精度对比 - -![](README.assets/result.png) - -om模型可以正常生成数字,与pth模型生成的图片大致一致。 - -## 7 性能对比 - -- NPU性能数据 -- T4性能数据 -- 性能对比 - -### 7.1 npu性能数据 - -1.使用msame工具执行以下指令通过纯推理获得性能数据 - -``` -./msame --model "CGAN_bs1.om" --output "./out" --outfmt BIN --loop 20 -``` - -结果如下: - -``` -[INFO] get max dynamic batch size success -[INFO] output data success -Inference average time: 2.554200 ms -Inference average time without first time: 2.547842 ms -[INFO] destroy model input success. -``` - -310单卡吞吐率:1000*(1/2.547842)*4=1568fps - - -### 7.2 T4性能数据 - -在装有T4卡的服务器上测试gpu性能,测试过程请确保卡没有运行其他任务,TensorRT版本:7.2.3.4,cuda版本:11.0,cudnn版本:8.2。 -执行以下命令获取T4性能数据 - -``` -trtexec --onnx=CGAN.onnx --fp16 --shapes=image:100,72 --threads -``` - -``` -[11/14/2021-09:17:40] [I] GPU Compute -[11/14/2021-09:17:40] [I] min: 0.407471 ms -[11/14/2021-09:17:40] [I] max: 2.23047 ms -[11/14/2021-09:17:40] [I] mean: 0.427789 ms -[11/14/2021-09:17:40] [I] median: 0.428223 ms -[11/14/2021-09:17:40] [I] percentile: 0.4552 ms at 99% -[11/14/2021-09:17:40] [I] total compute time: 2.96629 s -``` - -T4单卡吞吐率:1000/(0.428223/1)=2337fps - -### 7.3 性能对比 - -310性能:1000*(1/2.547842)*4=1568fps - -T4性能:1000/(0.428223/1)=2337fps - -310性能低于T4性能。 - -### 7.4 性能优化 - -autotune优化,结果如下: - -![img](README.assets/wps8587.tmp-16378261403441.jpg) - -优化TransData,TransPose,结果如下: - -![img](README.assets/wps229E.tmp.jpg) - -onnxsim优化onnx,结果如下: - -![img](README.assets/wps4092.tmp.jpg) - -最终经过autotune优化,优化TransData、TransPose,onnxsim优化onnx之后,最终的结果如下: - -![image-20211125154623271](README.assets/image-20211125154623271.png) - -最终的性能为:1000/0.065243*4=1936FPS - - - +# CGAN推理说明 + +## 1 模型概述 + +- **[论文地址](https://arxiv.org/abs/1411.1784)** +- **[代码地址](https://github.com/znxlwm/pytorch-generative-model-collections/)** + +### 1.1 论文地址 + +[CGAN论文](https://github.com/znxlwm/pytorch-generative-model-collections/) + +### 1.2 代码地址 + +[CGAN代码](https://github.com/znxlwm/pytorch-generative-model-collections/) + +branch:master + +commitid:0d183bb5ea2fbe069e1c6806c4a9a1fd8e81656f + + +## 2 环境说明 + +- 深度学习框架 +- python第三方库 + +### 2.1 深度学习框架 + +``` +python3.7.5 +CANN 5.0.3 + +pytorch == 1.5.0 +torchvision == 0.6.0 +onnx == 1.10.2 +``` + +### 2.2 python第三方库 + +``` +numpy == 1.21.2 +Pillow == 8.4.0 +imageio == 2.9.0 +scipy == 1.7.1 +matplotlib==3.4.3 +``` + +## 3 模型转换 + +- pth转om模型 + +### 3.1 pth转om模型 + +1.获取pth权重文件 + +pth权重文件随附件一起打包 + +2.下载CGAN推理代码 + +``` +git clone https://gitee.com/wang-chaojiemayj/modelzoo.git +cd modelzoo +git checkout tuili +``` + +进入CGANt目录 + +``` +cd ./contrib/ACL_PyTorch/Research/cv/GAN/CGAN +``` + +3.pth模型转onnx模型,onnx转成om模型 + +pth模型转onnx模型 + +``` +python3.7 CGAN_pth2onnx.py --pth_path CGAN_G.pth --onnx_path CGAN.onnx +python3.7 -m onnxsim --input-shape="100,72" CGAN.onnx CGAN_sim.onnx +``` + +onnx转出om,并使用autotune优化om模型,这将耗费大量时间 + +``` +source env.sh(注意,latest是一个软连接,请将服务器中的/usr/local/Ascend/ascend-toolkit/latest 指向5.0.3版本的CANN包) +# 生成器一次只能生成一张图,由于模型输入是两维的,不是常用的NCHW格式,input_format采用ND形式 +atc --framework=5 --model=CGAN_sim.onnx --output=CGAN_bs1 --input_format=ND --output_type=FP32 --input_shape="image:100,72" --log=debug --soc_version=Ascend310 --auto_tune_mode="RL,GA" +``` + +## 4 数据集预处理 + +- 数据集获取 +- 数据预处理 +- 生成数据集信息文件 + +### 4.1 数据集获取 + +本模型的输入数据由随机数以及标签生成,在CGAN_preprocess.py中会生成数据并转成二进制文件,并保存在。’./prep_dataset‘目录下。 + +文件结构如下 + +``` +|CGAN--test +| | |--pth2om.sh +| | |--eval_acc_perf.sh +| | |--perf_t4.sh +| |--util.py +| |--CGAN.py +| |--gen_dataset_info.py +| |--env.sh +| |--CGAN_pth2onnx.py +| |--CGAN_preprocess.py +| |--CGAN_postprocess.py +| |--requirements.txt +| |--LICENCE +| |--modelzoo_level.txt +| |--README.md +``` + + +### 4.2 数据集预处理 + +运行CGAN_preprocess.py + +``` +python3.7 CGAN_preprocess.py --save_path ./prep_dataset +``` + +二进制文件将保存在./prep_dataset目录下 + +### 4.3 生成数据集信息文件 + +1.执行生成数据集信息脚本gen_dataset_info.py,生成数据集信息文件 + +``` +python3.7 gen_dataset_info.py --dataset_bin ./prep_dataset --info_name CGAN_prep_bin.info --width 72 --height 100 +``` + +## 5 离线推理 + +- msame概述 +- 离线推理 + +### 5.1 msame工具概述 + +msame工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN 5.0.1 推理msame工具用户指南 + +### 5.2 离线推理 + +1.设置环境变量 + +``` +source env.sh +``` + +2.执行离线推理 + +``` +./msame --model "./CGAN_bs1.om" --input "./prep_dataset/input.bin" --output "./out" --outfmt BIN --loop 1 +``` + +输出结果保存在'./out'目录下 + +## 6 精度对比 + +- 离线推理精度 +- 开源精度 +- 开源精度对比 + +### 6.1 离线推理精度统计 + +将msame推理获得的输出结果进行后处理,保存为图片 + +``` +python3.7 CGAN_postprocess.py --bin_out_path ./out/20211124_090506 --save_path ./result +``` + +第一个参数为msame输出目录,’/20211113_073952‘是离线推理时根据时间自动生成的目录,请根据实际情况改变,第二个参数为保存后处理产生的图片的目录。 + +### 6.2 开源精度 + +![](README.assets/CGAN_epoch050-16371406300071.png) + +### 6.3 精度对比 + +![](README.assets/result.png) + +om模型可以正常生成数字,与pth模型生成的图片大致一致。 + +## 7 性能对比 + +- NPU性能数据 +- T4性能数据 +- 性能对比 + +### 7.1 npu性能数据 + +1.使用msame工具执行以下指令通过纯推理获得性能数据 + +``` +./msame --model "CGAN_bs1.om" --output "./out" --outfmt BIN --loop 20 +``` + +结果如下: + +``` +[INFO] get max dynamic batch size success +[INFO] output data success +Inference average time: 2.554200 ms +Inference average time without first time: 2.547842 ms +[INFO] destroy model input success. +``` + +310单卡吞吐率:1000*(1/2.547842)*4=1568fps + + +### 7.2 T4性能数据 + +在装有T4卡的服务器上测试gpu性能,测试过程请确保卡没有运行其他任务,TensorRT版本:7.2.3.4,cuda版本:11.0,cudnn版本:8.2。 +执行以下命令获取T4性能数据 + +``` +trtexec --onnx=CGAN.onnx --fp16 --shapes=image:100,72 --threads +``` + +``` +[11/14/2021-09:17:40] [I] GPU Compute +[11/14/2021-09:17:40] [I] min: 0.407471 ms +[11/14/2021-09:17:40] [I] max: 2.23047 ms +[11/14/2021-09:17:40] [I] mean: 0.427789 ms +[11/14/2021-09:17:40] [I] median: 0.428223 ms +[11/14/2021-09:17:40] [I] percentile: 0.4552 ms at 99% +[11/14/2021-09:17:40] [I] total compute time: 2.96629 s +``` + +T4单卡吞吐率:1000/(0.428223/1)=2337fps + +### 7.3 性能对比 + +310性能:1000*(1/2.547842)*4=1568fps + +T4性能:1000/(0.428223/1)=2337fps + +310性能低于T4性能。 + +### 7.4 性能优化 + +autotune优化,结果如下: + +![img](README.assets/wps8587.tmp-16378261403441.jpg) + +优化TransData,TransPose,结果如下: + +![img](README.assets/wps229E.tmp.jpg) + +onnxsim优化onnx,结果如下: + +![img](README.assets/wps4092.tmp.jpg) + +最终经过autotune优化,优化TransData、TransPose,onnxsim优化onnx之后,最终的结果如下: + +![image-20211125154623271](README.assets/image-20211125154623271.png) + +最终的性能为:1000/0.065243*4=1936FPS + + + diff --git a/ACL_PyTorch/contrib/cv/gan/CGAN/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/gan/CGAN/gen_dataset_info.py index 2d8c7b348a..1669ffd408 100644 --- a/ACL_PyTorch/contrib/cv/gan/CGAN/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/gan/CGAN/gen_dataset_info.py @@ -1,44 +1,44 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import glob -import argparse - -def parse_args(): - desc = "Pytorch implementation of CGAN collections" - parser = argparse.ArgumentParser(description=desc) - parser.add_argument('--dataset_bin', type=str, default='./prep_dataset', help="The input_dim") - parser.add_argument('--info_name', type=str, default='CGAN_prep_bin.info', help="The output_dim") - parser.add_argument('--width', type=str, default='78', help="The width of input ") - parser.add_argument('--height', type=str, default='100', help="The height of input") - return parser.parse_args() - -def get_bin_info(img_root_path='./data', info_name='CGAN_prep_bin.info', width='72', height='100'): - img_path = [] - files_source = glob.glob(os.path.join(img_root_path,'*.bin')) - files_source.sort() - for file in files_source: - if file.endswith('.bin'): - imgpath = file - img_path.append(imgpath) - with open(info_name, 'w') as fp: - for index in range(len(img_path)): - content = ' '.join([str(index), img_path[index], width, height]) - fp.write(content) - fp.write('\n') - - -if __name__ == '__main__': - args = parse_args() - get_bin_info(img_root_path=args.dataset_bin, info_name=args.info_name, width=args.width, height=args.height) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import glob +import argparse + +def parse_args(): + desc = "Pytorch implementation of CGAN collections" + parser = argparse.ArgumentParser(description=desc) + parser.add_argument('--dataset_bin', type=str, default='./prep_dataset', help="The input_dim") + parser.add_argument('--info_name', type=str, default='CGAN_prep_bin.info', help="The output_dim") + parser.add_argument('--width', type=str, default='78', help="The width of input ") + parser.add_argument('--height', type=str, default='100', help="The height of input") + return parser.parse_args() + +def get_bin_info(img_root_path='./data', info_name='CGAN_prep_bin.info', width='72', height='100'): + img_path = [] + files_source = glob.glob(os.path.join(img_root_path,'*.bin')) + files_source.sort() + for file in files_source: + if file.endswith('.bin'): + imgpath = file + img_path.append(imgpath) + with open(info_name, 'w') as fp: + for index in range(len(img_path)): + content = ' '.join([str(index), img_path[index], width, height]) + fp.write(content) + fp.write('\n') + + +if __name__ == '__main__': + args = parse_args() + get_bin_info(img_root_path=args.dataset_bin, info_name=args.info_name, width=args.width, height=args.height) diff --git a/ACL_PyTorch/contrib/cv/gan/CGAN/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/gan/CGAN/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/ACL_PyTorch/contrib/cv/gan/CGAN/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/gan/CGAN/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/gan/CGAN/test/parse.py b/ACL_PyTorch/contrib/cv/gan/CGAN/test/parse.py index c015e8771f..94857ecd74 100644 --- a/ACL_PyTorch/contrib/cv/gan/CGAN/test/parse.py +++ b/ACL_PyTorch/contrib/cv/gan/CGAN/test/parse.py @@ -1,39 +1,39 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import re - -def get_acc(filename): - with open(filename, 'r') as f: - lines = f.readlines() - last_line = lines[-1] - psnr = last_line.split(" ")[2] - print(filename.split('.')[0],"Average PSNR:", psnr) - - -def get_perf(filename): - with open(filename, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = 1000/float((txt_data_list[2].split(' '))[0]) * 4 - print('310 fps:{}'.format(fps)) - -if __name__ == "__main__": - - filename = sys.argv[1] - - if filename.endswith(".log"): - get_acc(filename) - elif filename.endswith(".txt"): +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import re + +def get_acc(filename): + with open(filename, 'r') as f: + lines = f.readlines() + last_line = lines[-1] + psnr = last_line.split(" ")[2] + print(filename.split('.')[0],"Average PSNR:", psnr) + + +def get_perf(filename): + with open(filename, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = 1000/float((txt_data_list[2].split(' '))[0]) * 4 + print('310 fps:{}'.format(fps)) + +if __name__ == "__main__": + + filename = sys.argv[1] + + if filename.endswith(".log"): + get_acc(filename) + elif filename.endswith(".txt"): get_perf(filename) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/gan/CycleGAN/CycleGAN_NetLoad.py b/ACL_PyTorch/contrib/cv/gan/CycleGAN/CycleGAN_NetLoad.py index 958711ae98..f559cbf240 100644 --- a/ACL_PyTorch/contrib/cv/gan/CycleGAN/CycleGAN_NetLoad.py +++ b/ACL_PyTorch/contrib/cv/gan/CycleGAN/CycleGAN_NetLoad.py @@ -1,90 +1,90 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -from collections import OrderedDict -import torch -from models import networks_adapt as networks - - -class load_networks(): - def __init__(self, opt): - self.opt = opt - self.gpu = 0 - self.netG_A = networks.define_G(self.opt.input_nc, self.opt.output_nc, self.opt.ngf, self.opt.netG, - self.opt.norm, not self.opt.no_dropout, self.opt.init_type, self.opt.init_gain, - self.gpu) - self.netG_B = networks.define_G(self.opt.output_nc, self.opt.input_nc, self.opt.ngf, self.opt.netG, - self.opt.norm, not self.opt.no_dropout, self.opt.init_type, self.opt.init_gain, - self.gpu) - if (opt.npu == False): - self.device = torch.device('cuda:{}'.format(self.gpu)) - else: - self.device = torch.device("cpu") - - def __patch_instance_norm_state_dict(self, state_dict, module, keys, i=0): - """Fix InstanceNorm checkpoints incompatibility (prior to 0.4)""" - key = keys[i] - if i + 1 == len(keys): # at the end, pointing to a parameter/buffer - if module.__class__.__name__.startswith('InstanceNorm') and \ - (key == 'running_mean' or key == 'running_var'): - if getattr(module, key) is None: - state_dict.pop('.'.join(keys)) - if module.__class__.__name__.startswith('InstanceNorm') and \ - (key == 'num_batches_tracked'): - state_dict.pop('.'.join(keys)) - else: - self.__patch_instance_norm_state_dict(state_dict, getattr(module, key), keys, i + 1) - - def proc_nodes_module(self, checkpoint): - new_state_dict = OrderedDict() - for k, v in checkpoint.items(): - if "module." in k: - name = k.replace("module.", "") - else: - name = k - new_state_dict[name] = v - return new_state_dict - - def loadnetworks(self, net, load_path): - state_dict = torch.load(load_path, map_location=torch.device('cpu')) - state_dict = self.proc_nodes_module(state_dict) - if hasattr(state_dict, '_metadata'): - del state_dict._metadata - # patch InstanceNorm checkpoints prior to 0.4 - for key in list(state_dict.keys()): # need to copy keys here because we mutate in loop - self.__patch_instance_norm_state_dict(state_dict, net, key.split('.')) - net.load_state_dict(state_dict) - return net - - def get_networks(self, load_patha, load_pathb): - model_Ga = self.loadnetworks(self.netG_A, load_patha) - model_Gb = self.loadnetworks(self.netG_B, load_pathb) - return model_Ga, model_Gb +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +from collections import OrderedDict +import torch +from models import networks_adapt as networks + + +class load_networks(): + def __init__(self, opt): + self.opt = opt + self.gpu = 0 + self.netG_A = networks.define_G(self.opt.input_nc, self.opt.output_nc, self.opt.ngf, self.opt.netG, + self.opt.norm, not self.opt.no_dropout, self.opt.init_type, self.opt.init_gain, + self.gpu) + self.netG_B = networks.define_G(self.opt.output_nc, self.opt.input_nc, self.opt.ngf, self.opt.netG, + self.opt.norm, not self.opt.no_dropout, self.opt.init_type, self.opt.init_gain, + self.gpu) + if (opt.npu == False): + self.device = torch.device('cuda:{}'.format(self.gpu)) + else: + self.device = torch.device("cpu") + + def __patch_instance_norm_state_dict(self, state_dict, module, keys, i=0): + """Fix InstanceNorm checkpoints incompatibility (prior to 0.4)""" + key = keys[i] + if i + 1 == len(keys): # at the end, pointing to a parameter/buffer + if module.__class__.__name__.startswith('InstanceNorm') and \ + (key == 'running_mean' or key == 'running_var'): + if getattr(module, key) is None: + state_dict.pop('.'.join(keys)) + if module.__class__.__name__.startswith('InstanceNorm') and \ + (key == 'num_batches_tracked'): + state_dict.pop('.'.join(keys)) + else: + self.__patch_instance_norm_state_dict(state_dict, getattr(module, key), keys, i + 1) + + def proc_nodes_module(self, checkpoint): + new_state_dict = OrderedDict() + for k, v in checkpoint.items(): + if "module." in k: + name = k.replace("module.", "") + else: + name = k + new_state_dict[name] = v + return new_state_dict + + def loadnetworks(self, net, load_path): + state_dict = torch.load(load_path, map_location=torch.device('cpu')) + state_dict = self.proc_nodes_module(state_dict) + if hasattr(state_dict, '_metadata'): + del state_dict._metadata + # patch InstanceNorm checkpoints prior to 0.4 + for key in list(state_dict.keys()): # need to copy keys here because we mutate in loop + self.__patch_instance_norm_state_dict(state_dict, net, key.split('.')) + net.load_state_dict(state_dict) + return net + + def get_networks(self, load_patha, load_pathb): + model_Ga = self.loadnetworks(self.netG_A, load_patha) + model_Gb = self.loadnetworks(self.netG_B, load_pathb) + return model_Ga, model_Gb diff --git a/ACL_PyTorch/contrib/cv/gan/CycleGAN/CycleGAN_ReflectpadDeal.py b/ACL_PyTorch/contrib/cv/gan/CycleGAN/CycleGAN_ReflectpadDeal.py index d5f7cd809c..c39ee62392 100644 --- a/ACL_PyTorch/contrib/cv/gan/CycleGAN/CycleGAN_ReflectpadDeal.py +++ b/ACL_PyTorch/contrib/cv/gan/CycleGAN/CycleGAN_ReflectpadDeal.py @@ -1,66 +1,66 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -import onnx -from parse import parse_args - - -def main(): - paser = parse_args(True, True) - opt = paser.initialize() - # Mode attr of Pad only supports constant, current is reflect ." - model = onnx.load(opt.onnx_path + opt.model_ga_onnx_name) - max_idx = len(model.graph.node) - for i in range(max_idx): - for k in range(len(model.graph.node[i].attribute)): - - if (model.graph.node[i].attribute[k].name == 'mode'): - model.graph.node[i].attribute[k].s = b'constant' - print(model.graph.node[i].attribute[k].s) - - onnx.checker.check_model(model) - onnx.save(model, opt.onnx_path + opt.model_gb_onnx_name) - - model = onnx.load(opt.onnx_path + opt.model_gb_onnx_name) - max_idx = len(model.graph.node) - for i in range(max_idx): - # if(model.graph.node[i].attribute[0].name=='Pad'): - for k in range(len(model.graph.node[i].attribute)): - - if (model.graph.node[i].attribute[k].name == 'mode'): - model.graph.node[i].attribute[k].s = b'constant' - print(model.graph.node[i].attribute[k].s) - onnx.checker.check_model(model) - onnx.save(model, opt.onnx_path + opt.model_ga_onnx_name) - - -if __name__ == '__main__': - main() +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import onnx +from parse import parse_args + + +def main(): + paser = parse_args(True, True) + opt = paser.initialize() + # Mode attr of Pad only supports constant, current is reflect ." + model = onnx.load(opt.onnx_path + opt.model_ga_onnx_name) + max_idx = len(model.graph.node) + for i in range(max_idx): + for k in range(len(model.graph.node[i].attribute)): + + if (model.graph.node[i].attribute[k].name == 'mode'): + model.graph.node[i].attribute[k].s = b'constant' + print(model.graph.node[i].attribute[k].s) + + onnx.checker.check_model(model) + onnx.save(model, opt.onnx_path + opt.model_gb_onnx_name) + + model = onnx.load(opt.onnx_path + opt.model_gb_onnx_name) + max_idx = len(model.graph.node) + for i in range(max_idx): + # if(model.graph.node[i].attribute[0].name=='Pad'): + for k in range(len(model.graph.node[i].attribute)): + + if (model.graph.node[i].attribute[k].name == 'mode'): + model.graph.node[i].attribute[k].s = b'constant' + print(model.graph.node[i].attribute[k].s) + onnx.checker.check_model(model) + onnx.save(model, opt.onnx_path + opt.model_ga_onnx_name) + + +if __name__ == '__main__': + main() diff --git a/ACL_PyTorch/contrib/cv/gan/CycleGAN/CycleGAN_onnx_export.py b/ACL_PyTorch/contrib/cv/gan/CycleGAN/CycleGAN_onnx_export.py index f6d3207e1e..d2faf85527 100644 --- a/ACL_PyTorch/contrib/cv/gan/CycleGAN/CycleGAN_onnx_export.py +++ b/ACL_PyTorch/contrib/cv/gan/CycleGAN/CycleGAN_onnx_export.py @@ -1,62 +1,62 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -import os -import torch.onnx -from CycleGAN_NetLoad import load_networks -from parse import parse_args - -def main(): - paser = parse_args(True, True) - opt = paser.initialize() - lnetworks = load_networks(opt) - model_Ga, model_Gb = lnetworks.get_networks(opt.model_ga_path, opt.model_gb_path) - device_cpu = torch.device("cpu") - model_Ga = model_Ga.to(device_cpu) - model_Gb = model_Gb.to(device_cpu) - dummy_input = torch.randn(1, 3, 256, 256) - input_names = ["img_sat_maps"] - output_names = ["maps"] - dynamic_axes = {'img_sat_maps': {0: '-1'}, 'maps': {0: '-1'}} - input_names1 = ["img_maps_sat"] - output_names1 = ["sat"] - dynamic_axes1 = {'img_maps_sat': {0: '-1'}, 'sat': {0: '-1'}} - if (os.path.exists(opt.onnx_path) == False): - os.makedirs(opt.onnx_path) - torch.onnx.export(model_Ga, dummy_input, f=opt.onnx_path + opt.model_ga_onnx_name, verbose=True, training=False, \ - dynamic_axes=dynamic_axes, input_names=input_names, output_names=output_names, opset_version=11) - torch.onnx.export(model_Gb, dummy_input, f=opt.onnx_path + opt.model_gb_onnx_name, verbose=True, training=False, \ - dynamic_axes=dynamic_axes1, input_names=input_names1, output_names=output_names1, - opset_version=11) - - -if __name__ == '__main__': - main() +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import os +import torch.onnx +from CycleGAN_NetLoad import load_networks +from parse import parse_args + +def main(): + paser = parse_args(True, True) + opt = paser.initialize() + lnetworks = load_networks(opt) + model_Ga, model_Gb = lnetworks.get_networks(opt.model_ga_path, opt.model_gb_path) + device_cpu = torch.device("cpu") + model_Ga = model_Ga.to(device_cpu) + model_Gb = model_Gb.to(device_cpu) + dummy_input = torch.randn(1, 3, 256, 256) + input_names = ["img_sat_maps"] + output_names = ["maps"] + dynamic_axes = {'img_sat_maps': {0: '-1'}, 'maps': {0: '-1'}} + input_names1 = ["img_maps_sat"] + output_names1 = ["sat"] + dynamic_axes1 = {'img_maps_sat': {0: '-1'}, 'sat': {0: '-1'}} + if (os.path.exists(opt.onnx_path) == False): + os.makedirs(opt.onnx_path) + torch.onnx.export(model_Ga, dummy_input, f=opt.onnx_path + opt.model_ga_onnx_name, verbose=True, training=False, \ + dynamic_axes=dynamic_axes, input_names=input_names, output_names=output_names, opset_version=11) + torch.onnx.export(model_Gb, dummy_input, f=opt.onnx_path + opt.model_gb_onnx_name, verbose=True, training=False, \ + dynamic_axes=dynamic_axes1, input_names=input_names1, output_names=output_names1, + opset_version=11) + + +if __name__ == '__main__': + main() diff --git a/ACL_PyTorch/contrib/cv/gan/CycleGAN/LICENSE b/ACL_PyTorch/contrib/cv/gan/CycleGAN/LICENSE index 4e1ad12a81..eb1309d6c1 100644 --- a/ACL_PyTorch/contrib/cv/gan/CycleGAN/LICENSE +++ b/ACL_PyTorch/contrib/cv/gan/CycleGAN/LICENSE @@ -1,31 +1,31 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ============================================================================ \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/gan/CycleGAN/PerformanceForGPU.py b/ACL_PyTorch/contrib/cv/gan/CycleGAN/PerformanceForGPU.py index a397087a14..3e68d420e7 100644 --- a/ACL_PyTorch/contrib/cv/gan/CycleGAN/PerformanceForGPU.py +++ b/ACL_PyTorch/contrib/cv/gan/CycleGAN/PerformanceForGPU.py @@ -1,173 +1,173 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -import os -import time -import torchvision.transforms as transforms -from PIL import Image -import torch.onnx -from torch.utils.data import Dataset -from torchvision.datasets.folder import IMG_EXTENSIONS -from parse import parse_args -import numpy as np -from CycleGAN_NetLoad import load_networks - - -def make_power(img, base): - ow, oh = img.size - h = int(round(oh / base) * base) - w = int(round(ow / base) * base) - if h == oh and w == ow: - return img - - -def preprocess(image_shape): - process = transforms.Compose([ - transforms.Lambda(lambda img: make_power(img, base=4)), - transforms.Resize(image_shape), - transforms.ToTensor(), - transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))]) - return process - - -def postprocess(img_tensor): - inv_normalize = transforms.Normalize( - mean=(-1, -1, -1), - std=(2.0, 2.0, 2.0)) - to_PIL_image = transforms.ToPILImage() - return to_PIL_image(inv_normalize(img_tensor[0]).clamp(0, 1)) - - -def make_dataset(dir, max_dataset_size=float("inf")): - images = [] - assert os.path.isdir(dir), '%s is not a valid directory' % dir - - for root, _, fnames in sorted(os.walk(dir)): - for fname in fnames: - path = os.path.join(root, fname) - images.append(path) - return images[:min(max_dataset_size, len(images))] - - -def default_loader(path): - return Image.open(path).convert('RGB') - - -class ImageFolder(Dataset): - def __init__(self, root, transform=None, return_paths=False, - loader=default_loader): - imgs = make_dataset(root) - if len(imgs) == 0: - raise (RuntimeError("Found 0 images in: " + root + "\n" + - "Supported image extensions are: " + ",".join(IMG_EXTENSIONS))) - self.root = root - self.imgs = imgs - self.transform = transform - self.return_paths = return_paths - self.loader = loader - - def __getitem__(self, index): - path = self.imgs[index] - img = self.loader(path) - if self.transform is not None: - img = self.transform(img) - if self.return_paths: - return img, path - else: - return img - - def __len__(self): - return len(self.imgs) - - -def main(): - paser = parse_args(True, True) - opt = paser.initialize() - lnetworks = load_networks(opt) - bachsize = opt.batch_size - # whether to use fp16 to farword - half_data_model = True - transform = preprocess((256, 256)) - model_Ga, model_Gb = lnetworks.get_networks(opt.model_ga_path, opt.model_gb_path) - device_cuda = torch.device("cuda:%s" % (str(opt.pu_ids))) - model_Ga = model_Ga.to(device_cuda) - if (half_data_model): - model_Ga = model_Ga.half() - datasets = ImageFolder(opt.dataroot, transform) - dataloader = torch.utils.data.DataLoader(datasets, batch_size=bachsize, shuffle=True, num_workers=4) - filename = opt.gpuPerformance + 'GPU_perf_of_cycle_gan-b0_bs' + str(bachsize) + '_in_device_' + str( - opt.pu_ids) + '.txt' - f = None - if (os.path.exists(opt.gpuPerformance) == False): - os.mkdir(opt.gpuPerformance) - f = open(filename, mode='w') - else: - f = open(filename, mode='w') - timelist = [] - for i, data in enumerate(dataloader): - start_time = time.time() - data = data.to(device_cuda) - if (half_data_model): - data = data.half() - model_Ga.forward(data) - end_time = time.time() - if (i > 10): - timelist.append((end_time - start_time) * 1000) - a_time = time.asctime(time.localtime(time.time())) - timelist = np.array(timelist) - mintime = timelist.argmin() - maxtime = timelist.argmax() - meantime = np.mean(timelist) - mediantime = np.median(timelist) - alltime = np.sum(timelist) / 1000 - message = ''' - [%s],[I] GPU Compute - [%s],[I] min:%.5f ms - [%s],[I] max:%.5f ms - [%s],[I] mean:%.5f ms - [%s],[I] median:%.5f ms - [%s],[I] total compute time:%.5f s - [%s],[I] CardFPS:1000/(%f/%f)=%.2f fps - ''' % (a_time, \ - a_time, mintime, \ - a_time, maxtime, \ - a_time, meantime, \ - a_time, mediantime, \ - a_time, alltime, \ - a_time, meantime, bachsize, 1000 / (meantime / bachsize)) - - print(message) - f.write(message) - f.close() - - -if __name__ == '__main__': - main() +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import os +import time +import torchvision.transforms as transforms +from PIL import Image +import torch.onnx +from torch.utils.data import Dataset +from torchvision.datasets.folder import IMG_EXTENSIONS +from parse import parse_args +import numpy as np +from CycleGAN_NetLoad import load_networks + + +def make_power(img, base): + ow, oh = img.size + h = int(round(oh / base) * base) + w = int(round(ow / base) * base) + if h == oh and w == ow: + return img + + +def preprocess(image_shape): + process = transforms.Compose([ + transforms.Lambda(lambda img: make_power(img, base=4)), + transforms.Resize(image_shape), + transforms.ToTensor(), + transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))]) + return process + + +def postprocess(img_tensor): + inv_normalize = transforms.Normalize( + mean=(-1, -1, -1), + std=(2.0, 2.0, 2.0)) + to_PIL_image = transforms.ToPILImage() + return to_PIL_image(inv_normalize(img_tensor[0]).clamp(0, 1)) + + +def make_dataset(dir, max_dataset_size=float("inf")): + images = [] + assert os.path.isdir(dir), '%s is not a valid directory' % dir + + for root, _, fnames in sorted(os.walk(dir)): + for fname in fnames: + path = os.path.join(root, fname) + images.append(path) + return images[:min(max_dataset_size, len(images))] + + +def default_loader(path): + return Image.open(path).convert('RGB') + + +class ImageFolder(Dataset): + def __init__(self, root, transform=None, return_paths=False, + loader=default_loader): + imgs = make_dataset(root) + if len(imgs) == 0: + raise (RuntimeError("Found 0 images in: " + root + "\n" + + "Supported image extensions are: " + ",".join(IMG_EXTENSIONS))) + self.root = root + self.imgs = imgs + self.transform = transform + self.return_paths = return_paths + self.loader = loader + + def __getitem__(self, index): + path = self.imgs[index] + img = self.loader(path) + if self.transform is not None: + img = self.transform(img) + if self.return_paths: + return img, path + else: + return img + + def __len__(self): + return len(self.imgs) + + +def main(): + paser = parse_args(True, True) + opt = paser.initialize() + lnetworks = load_networks(opt) + bachsize = opt.batch_size + # whether to use fp16 to farword + half_data_model = True + transform = preprocess((256, 256)) + model_Ga, model_Gb = lnetworks.get_networks(opt.model_ga_path, opt.model_gb_path) + device_cuda = torch.device("cuda:%s" % (str(opt.pu_ids))) + model_Ga = model_Ga.to(device_cuda) + if (half_data_model): + model_Ga = model_Ga.half() + datasets = ImageFolder(opt.dataroot, transform) + dataloader = torch.utils.data.DataLoader(datasets, batch_size=bachsize, shuffle=True, num_workers=4) + filename = opt.gpuPerformance + 'GPU_perf_of_cycle_gan-b0_bs' + str(bachsize) + '_in_device_' + str( + opt.pu_ids) + '.txt' + f = None + if (os.path.exists(opt.gpuPerformance) == False): + os.mkdir(opt.gpuPerformance) + f = open(filename, mode='w') + else: + f = open(filename, mode='w') + timelist = [] + for i, data in enumerate(dataloader): + start_time = time.time() + data = data.to(device_cuda) + if (half_data_model): + data = data.half() + model_Ga.forward(data) + end_time = time.time() + if (i > 10): + timelist.append((end_time - start_time) * 1000) + a_time = time.asctime(time.localtime(time.time())) + timelist = np.array(timelist) + mintime = timelist.argmin() + maxtime = timelist.argmax() + meantime = np.mean(timelist) + mediantime = np.median(timelist) + alltime = np.sum(timelist) / 1000 + message = ''' + [%s],[I] GPU Compute + [%s],[I] min:%.5f ms + [%s],[I] max:%.5f ms + [%s],[I] mean:%.5f ms + [%s],[I] median:%.5f ms + [%s],[I] total compute time:%.5f s + [%s],[I] CardFPS:1000/(%f/%f)=%.2f fps + ''' % (a_time, \ + a_time, mintime, \ + a_time, maxtime, \ + a_time, meantime, \ + a_time, mediantime, \ + a_time, alltime, \ + a_time, meantime, bachsize, 1000 / (meantime / bachsize)) + + print(message) + f.write(message) + f.close() + + +if __name__ == '__main__': + main() diff --git a/ACL_PyTorch/contrib/cv/gan/CycleGAN/Readme.md b/ACL_PyTorch/contrib/cv/gan/CycleGAN/Readme.md index eb51b624e3..8b8ea739ba 100644 --- a/ACL_PyTorch/contrib/cv/gan/CycleGAN/Readme.md +++ b/ACL_PyTorch/contrib/cv/gan/CycleGAN/Readme.md @@ -1,619 +1,619 @@ -\# CycleGAN模型端到端推理指导 - -\- [1 模型概述](#1-模型概述) - -​ \- [1.1 论文地址](#11-论文地址) - -​ \- [1.2 代码地址](#12-代码地址) - -\- [2 环境说明](#2-环境说明) - -​ \- [2.1 深度学习框架](#21-深度学习框架) - -​ \- [2.2 python第三方库](#22-python第三方库) - -\- [3 模型转换](#3-模型转换) - -​ \- [3.1 pth转onnx模型](#31-pth转onnx模型) - -​ \- [3.2 onnx转om模型](#32-onnx转om模型) - -\- [4 数据集预处理](#4-数据集预处理) - -​ \- [4.1 数据集获取](#41-数据集获取) - -​ \- [4.2 数据集预处理](#42-数据集预处理) - -​ \- [4.3 生成数据集信息文件](#43-生成数据集信息文件) - -\- [5 离线推理](#5-离线推理) - -​ \- [5.1 benchmark工具概述](#51-benchmark工具概述) - -​ \- [5.2 离线推理](#52-离线推理) - -\- [6 精度对比](#6-精度对比) - -​ \- [6.1 离线推理精度统计](#61-离线推理精度统计) - -​ \- [6.2 在线推理精度](#62-在线推理精度) - -​ \- [6.3 精度对比](#63-精度对比) - -\- [7 性能对比](#7-性能对比) - -​ \- [7.1 npu性能数据](#71-npu性能数据) - -​ \- [7.2 性能优化](#73-性能优化) - -​ \- [7.2.1 优化TransData,修改five_2_four.py](#731-优化TransData,修改five_2_four.py) - -\## 1 模型概述 - - - -\- **[论文地址](#11-论文地址)** - - - -\- **[代码地址](#12-代码地址)** - - - -\### 1.1 论文地址 - - - -[CycleGAN论文]( https://arxiv.org/pdf/1703.10593v7.pdf) - -我们专注于本文中风格转换中的地图转换。它通过一种无监督的少样本的学习方式,能够实现航拍地图和卫星地图之间的相互转换。 - -\### 1.2 代码地址 - -[CycleGAN代码]( https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix) - -branch:master - -commit_id:略 - -备注:commit_id是指基于该次提交时的模型代码做推理,通常选择稳定版本的最后一次提交,或代码仓最新的一次提交 - - - -\## 2 环境说明 - - - -\- **[深度学习框架](#21-深度学习框架)** - - - -\- **[python第三方库](#22-python第三方库)** - - - -\### 2.1 深度学习框架 - -\``` - -``` -CANN 5.0.2.alpha003 - -torch == 1.5.0 - -torchvision == 0.9.0 - -onnx==1.7.0 - -onnx-simplifier==0.3.6 - -onnxconverter-common==1.6.1 - -onnxoptimizer==0.2.6 - -onnxruntime==1.6.0 - -tensorboard==1.15.0 - -tensorflow==1.15.0 - -tensorflow-estimator ==1.15.1 - -termcolor==1.1.0 -``` - -\``` - - - -\### 2.2 python第三方库 - -\``` - -``` -numpy == 1.16.6 - -Pillow == 8.2.0 - -opencv-python == 4.5.2.52 - -sympy == 1.4 - -decorator == 4.4.2 - -requests == 2.22.0 - -tqdm == 4.61.0 - -PyYAML == 5.4.1 -``` - -\``` - - - -**说明:** - -\> X86架构:pytorch torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3 install 包名 安装 - -\> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3 install 包名 安装 - - - -\## 3 模型转换 - - - -\- **[pth转onnx模型](#31-pth转onnx模型)** - - - -\- **[onnx转om模型](#32-onnx转om模型)** - - - -\### 3.1 pth转onnx模型 - -1.下载开源模型代码,安装必要的依赖库,并修改模型代码后安装 - -\``` - -``` -git clone https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix -cd pytorch-CycleGAN-and-pix2pix -pip3 install -r requirements.txt -``` - -\``` - - - -2.下载pth权重文件 - - - -\- [官方CycleGAN pth权重文件](http://efrosgans.eecs.berkeley.edu/cyclegan/pretrained_models/) - -\- [获取A800-9000训练的pth文件,该链接为百度网盘链接,提取码为:1234](https://pan.baidu.com/s/1YqHkce2wUw-W8_VY9dYD_w)) - -3.编写pth2onnx脚本*CycleGAN_onnx_export.py* - - **说明:** - -\>注意目前ATC支持的onnx算子版本为11 - - - -4.执行*CycleGAN_onnx_export.py*脚本,生成onnx模型文件 - -\``` - -``` -python3 CycleGAN_onnx_export.py \ - ---model_ga_path=./checkpoints/maps_cycle_gan/latest_net_G_A.pth\ - ---model_gb_path=./checkpoints/maps_cycle_gan/latest_net_G_B.pth\ - ---onnx_path=./onnxmodel/ \ - ---model_ga_onnx_name=model_Ga.onnx \ - ---model_gb_onnx_name=model_Gb.onnx \ -``` - -\``` - - **模型转换要点:** - -\- 开源仓中的生成器采用的padding类型为ReflectionPad2d,由于在转om格式模型的时候,会出现算子不兼容问题导致om模型转换失败,这里我们将改padding类型替换为ZeroPad2d。如果您任然坚持使用ReflectionPad2d,请在转换Onnx格式后运行 - - ' ' ' - -``` -python3 CycleGAN_ReflectpadDeal.py \ - ---onnx_path=./onnxmodel/ \ - ---model_ga_onnx_name=model_Ga.onnx \ - ---model_gb_onnx_name=model_Gb.onnx \ -``` - -' ' ' - -该脚本会将ReflectionPad2d中的属性替换为constant,这样做的结果会导致模型执行推理时会出现边缘模糊,详情请见issue链接https://e.gitee.com/HUAWEI-ASCEND/issues/list?issue=I4467L#note_6141945 - - - -\### 3.2 onnx转om模型 - - - -1.设置环境变量 - -\``` - -``` -source env.sh -``` - -\``` - -\- 根据实际情况修改env.sh中的install_path=/usr/local/Ascend/ascend-toolkit/latest变量 - -\- 执行脚本前先执行指令 dos2unix * - - - -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN 5.0.1 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) - -\``` - -``` -atc --framework=5 --model=./onnxmodel/model_Ga.onnx --output=Cons_Ga_aipp512_b0_bs1 --input_format=NCHW --input_shape="img_sat_maps:1,3,256,256" --out_nodes="Tanh_156:0" --log=debug --soc_version=Ascend310 --insert_op_conf=aipp_CycleGAN_pth.config - -atc --framework=5 --model=./onnxmodel/model_Gb.onnx --output=Cons_Gb_aipp512_b0_bs1 --input_format=NCHW --input_shape="img_maps_sat:1,3,256,256" --out_nodes="Tanh_156:0" --log=debug --soc_version=Ascend310 --insert_op_conf=aipp_CycleGAN_pth.config -``` - -\``` - -\- 说明 - - \- input_shape参数可通过Netron工具查看输入节点的名称和shape, 与pth转onnx步骤中的参数一致 - - \- out_nodes为指定输出节点, 通过Netron可以看到onnx文件有四个输出, 以自测转换的onnx为例 - - 如果在转onnx时使用的不是默认路径,请将—model中的参数设置为onnx格式模型所在的路径 - - - - - -\## 4 数据集预处理 - - - -\- **[数据集获取](#41-数据集获取)** - - - -\- **[数据集预处理](#42-数据集预处理)** - - - -\- **[生成数据集信息文件](#43-生成数据集信息文件)** - - - -\### 4.1 数据集获取 - -该模型使用[maps数据集](http://efrosgans.eecs.berkeley.edu/cyclegan/datasets/maps.zip)的testA和testB各1098张验证集进行测试,因为航拍地图和卫星地图之间的相互转换的两个生成器模型结构一样,这里我们只需要保证其中一个生辰器精度和性能跟上就行,这里我们以model_Ga.onnx和testA为推理的模型和测试数据集。 - - - -\### 4.2 数据集预处理 - -1.生成数据集信息文件脚本gen_dataset_info.py - -2.执行生成数据集信息脚本,生成数据集信息文件 - -\``` - -``` -python3 gen_dataset_info.py \ - ---src_path_testA=./datasets/maps/testA/ \ - ---save_pathTestA_dst=datasetsDst/maps/testA/ \ - ---dataTestA_infoName=testA_prep.info \ - ---src_path_testB=./datasets/maps/testB/ \ - ---save_pathTestB_dst=./datasetsDst/maps/testB/ \ - ---dataTestB_infoName=testB_prep.info -``` - -' ' ' - -\## 5 离线推理 - - - -\- **[benchmark工具概述](#51-benchmark工具概述)** - - - -\- **[离线推理](#52-离线推理)** - - - -\### 5.1 benchmark工具概述 - - - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN 5.0.1 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) - -\### 5.2 离线推理 - -1.设置环境变量 - -\``` - -source env.sh - -\``` - -2.执行离线推理 - -\- benchmark工具区分arm64和x86_64, 对应分别为./benchmark.aarch64和./benchmark.x86_64, 示例中均以x86_64环境为例 - -\- 将benchmark工具去相应路径获取后放到env.sh同级目录下,加上执行权限chmod +x benchmark.XX - -''' - -``` -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=Cons_Ga_aipp512_b0_bs1.om -input_text_path=testA_prep.info -input_width=512 -input_height=512 -output_binary=true -useDvpp=true - -./benchmark.x86_64 -model_type=vision -device_id=1 -batch_size=1 -om_path=Cons_Gb_aipp512_b0_bs1.om -input_text_path=testB_prep.info -input_width=512 -input_height=512 -output_binary=true -useDvpp=true -``` - -输出结果默认保存在当前目录result/dumpOutput_devicex,每个输入对应的输出对应一个_x.bin文件。 - -''' - -\## 6 精度对比 - -\### 6.1 离线推理精度统计 - -由于该模型的精度在论文中是由人眼分辨,所以这里我们那Onnx和om模型输出的平均余弦相似度来替代精度,只需要保证Onnx格式模型的效果和论文中的一致并且om和onnx格式模型的余弦相似度在99%左右就精度达标。执行eval_acc_py.py脚本计算平均余弦相似度 : - -\``` - -``` - -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=Cons_Ga_aipp512_b0_bs1.om -input_text_path=testA_prep.info -input_width=512 -input_height=512 -output_binary=true -useDvpp=true #如果已经执行这一步请忽略 -python3 eval_acc.py \ ---dataroot=./datasets/maps\ ---npu_bin_file=./result/dumpOutput_device0/ -``` - -\``` - -\### 6.2精度对比 - -![1](C:\Users\Administrator\Desktop\1.png) - -将得到的om离线模型推理精度与在线推理精度对比,推理精度与在线推理精度一致,精度达标。 - - **精度调试:** - -使用onnxruntime测试onnx离线推理精度与om一致。 - -\## 7 性能对比 - -\- **[npu性能数据](#71-npu性能数据)** - -\- **[性能优化](#73-性能优化)** - -\### 7.1 npu性能数据 - -这里用batch1和batch16做示例 - - - -benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device。为快速获取性能数据,也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准。这里给出两种方式,模型的测试脚本使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准。 - - - -1.benchmark工具在整个数据集上推理获得性能数据 - - - -以batch1为例,benchmark工具在整个数据集上推理,执行下面命令。 - -``` -atc --framework=5 --model=./onnxmodel/model_Ga.onnx --output=Cons_Ga_aipp512_b0_bs1 --input_format=NCHW --input_shape="img_sat_maps:1,3,256,256" --out_nodes="Tanh_156:0" --log=debug --soc_version=Ascend310 --insert_op_conf=aipp_CycleGAN_pth.config #如果已经转换,请忽略 -python3.7 gen_dataset_info.py #如果这一步已经执行,可直接执行下一步推理 -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=Cons_Ga_aipp512_b0_bs1.om -input_text_path=testA_prep.info -input_width=512 -input_height=512 -output_binary=true -useDvpp=true -``` - -\``` - - ![输入图片说明](https://images.gitee.com/uploads/images/2021/0914/121624_f45173ef_9486012.png "屏幕截图.png") - - - -Interface throughputRate: 10.7,10.7乘以4,是310单卡吞吐率 - - \``` - -2.benchmark纯推理功能测得性能数据 - - - -batch1的性能: - - 测试npu性能要确保device空闲,使用npu-smi info命令可查看device是否在运行其它推理任务 - -\``` - -``` -./benchmark.x86_64 -round=20 -om_path=Cons_Ga_aipp512_b0_bs1.om -device_id=0 -batch_size=1 -``` - -``` - -执行20次纯推理取均值,统计吞吐率与其倒数时延(benchmark的时延是单个数据的推理时间),npu性能是一个device执行的结果 - - ![输入图片说明](https://images.gitee.com/uploads/images/2021/0914/121641_4ed82b8d_9486012.png "屏幕截图.png") -``` - - -Batch16的性能: - -``` -./benchmark.x86_64 -round=20 -om_path=model_Ga-b0_bs16.om -device_id=1 -batch_size=16 -``` - -![输入图片说明](https://images.gitee.com/uploads/images/2021/0914/121659_6331aa3d_9486012.png "屏幕截图.png") - -\### 7.2 性能优化 - -``` -**性能优化** - -\- profiling性能分析方法 - -​ CANN C20及以后的版本profiling使用方法 - -新建/home/zlz/CycleGan_deal/perProblem_detec/run文件,内容如下: - -``` -``` -# /usr/local/Ascend/ascend-toolkit/ /usr/local/Ascend/ascend-toolkit/ -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp -./benchmark.x86_64 -round=20 -om_path=/home/zlz/cyclegan/model_Ga1-b0_bs16.om -device_id=0 -batch_size=16 -``` - -然后执行如下命令: -``` -chmod 777 /home/zlz/CycleGan_deal/perProblem_detec/run -cd /usr/local/Ascend/ascend-toolkit/latest/x86_64-linux/toolkit/tools/profiler/bin -./msprof --output=/home/zlz/CycleGan_deal/perProblem_detec/perPro/ --application=/home/zlz/CycleGan_deal/perProblem_detec/run --sys-hardware-mem=on --sys-cpu-profiling=on --sys-profiling=on --sys-pid-profiling=on --sys-io-profiling=on --dvpp-profiling=on -cd /usr/local/Ascend/ascend-toolkit/latest/x86_64-linux/toolkit/tools/profiler/profiler_tool/analysis/msprof/ -# 生成的profiling目录 -python3.7 msprof.py import -dir/home/zlz/CycleGan_deal/perProblem_detec/perPro/ -python3.7 msprof.py export summary -dir /home/zlz/CycleGan_deal/perProblem_detec/perPro/ -#生成的profiling目录 --iteration-id 1 -python3.7 msprof.py export timeline -dir /home/zlz/CycleGan_deal/perProblem_detec/perPro/ - -``` -目录 - -\- 性能调优测试版本:CANN 5.0.2.alpha003 - -\- 性能优化过程主要对trans_Data算子进行优化,结合profiling分析,性能有提升: - -\#### 7.3.1 five_2_four.py优化方法 - - 在环境变量env.sh中export install_path=/usr/local/Ascend/ascend-toolkit/latest路径下查找five_2_four.py文件,路径一般为 - -\``` - -/usr/local/Ascend/ascend-toolkit/latest/x86_64-linux/opp/op_impl/built-in/ai_core/tbe/impl/five_2_four.py - -\``` - -修改five_2_four.py文件,将TransData算子的output shape加入five_2_four函数行中,示例如下: - -\``` - - ... - from impl import trans_data_negative_target_ntc - - @util.check_input_type(dict, dict, str, str, str) - - def five_2_four(src, dst, src_format, dst_format, kernel_name='five_2_four'): - elif dst_format.lower() == "nhwc" and dst_shape in [[10000, 63, 63, 1], [10000, 127, 127, 1], [16, 19, 19, 486], - - [16, 10, 10, 486], [16, 38, 38, 324], [16, 5, 5, 486], - - [16, 3, 3, 324], [8, 19, 19, 486], [8, 10, 10, 486], - - [8, 38, 38, 324], [8, 5, 5, 486], [8, 3, 3, 324], - - [100, 28, 28, 91]]: - - trans_data_negative_target_tc.trans_data_negative_target_tc(src, dst, src_format, dst_format, kernel_name) - - elif dst_format.lower() == "nchw" and dst_shape in [[2560, 512, 4, 26], [2560, 512, 1, 26], [2560, 256, 8, 25], - - [16, 240, 7, 7], [16, 120, 14, 14], [1,19,1024,2048], [4,19,1024,2048]]: - - print("=================================") - - print("ntc dst shape:", dst_shape) - - print("=================================") - - trans_data_negative_target_ntc.trans_data_negative_target_ntc(src, dst, src_format, dst_format, kernel_name) - ... - -\``` - -\- 不同的batch_size,添加的shape不一样,shape大小为[*,19,256,256 ] ,以本模型为例,只测试batch1和batch16,因此添加的shape为[1,19,256,256],[4,19,256,256] - -修改完成后,重新转换生成om文件,atc转换过程会打印添加的日志,如下: - -\```![输入图片说明](https://images.gitee.com/uploads/images/2021/0914/121715_d94592ad_9486012.png "屏幕截图.png") - - \``` - -纯推理测试结果: - -\``` - -bs1: - - ![输入图片说明](https://images.gitee.com/uploads/images/2021/0914/121721_50c95bdd_9486012.png "屏幕截图.png") - -Bs16: - -![输入图片说明](https://images.gitee.com/uploads/images/2021/0914/122022_a16e9ff5_9486012.png "屏幕截图.png") - -\``` - - - -用生成的om文件做精度后处理,测得bs1和bs16与之前的Onnx模型做余弦相似度高于99%,精度无损失、 - -\``` - -\#### 7.3.1 总结 - -优化方案共包括五种: - -(1)优化TransData,修改five_2_four.py - -(2)输出节点由float32改为float16 - -(3)模型中Resize节点的mode由双线性为最近邻 - -(4)将PadV3D进行算子融合 - -(5)优化FrameworkOP框架 - -由于在蓝区测试的版本CANN 5.0.2.alpha003中,已经实现了PadV3D算子融合,因此测试过程默认已经优化。同时方案(5)暂时无法实现,因此也无法比对性能。 - -结论: - -\- 因为关键算子性能差,性能暂时无法达标。 - +\# CycleGAN模型端到端推理指导 + +\- [1 模型概述](#1-模型概述) + +​ \- [1.1 论文地址](#11-论文地址) + +​ \- [1.2 代码地址](#12-代码地址) + +\- [2 环境说明](#2-环境说明) + +​ \- [2.1 深度学习框架](#21-深度学习框架) + +​ \- [2.2 python第三方库](#22-python第三方库) + +\- [3 模型转换](#3-模型转换) + +​ \- [3.1 pth转onnx模型](#31-pth转onnx模型) + +​ \- [3.2 onnx转om模型](#32-onnx转om模型) + +\- [4 数据集预处理](#4-数据集预处理) + +​ \- [4.1 数据集获取](#41-数据集获取) + +​ \- [4.2 数据集预处理](#42-数据集预处理) + +​ \- [4.3 生成数据集信息文件](#43-生成数据集信息文件) + +\- [5 离线推理](#5-离线推理) + +​ \- [5.1 benchmark工具概述](#51-benchmark工具概述) + +​ \- [5.2 离线推理](#52-离线推理) + +\- [6 精度对比](#6-精度对比) + +​ \- [6.1 离线推理精度统计](#61-离线推理精度统计) + +​ \- [6.2 在线推理精度](#62-在线推理精度) + +​ \- [6.3 精度对比](#63-精度对比) + +\- [7 性能对比](#7-性能对比) + +​ \- [7.1 npu性能数据](#71-npu性能数据) + +​ \- [7.2 性能优化](#73-性能优化) + +​ \- [7.2.1 优化TransData,修改five_2_four.py](#731-优化TransData,修改five_2_four.py) + +\## 1 模型概述 + + + +\- **[论文地址](#11-论文地址)** + + + +\- **[代码地址](#12-代码地址)** + + + +\### 1.1 论文地址 + + + +[CycleGAN论文]( https://arxiv.org/pdf/1703.10593v7.pdf) + +我们专注于本文中风格转换中的地图转换。它通过一种无监督的少样本的学习方式,能够实现航拍地图和卫星地图之间的相互转换。 + +\### 1.2 代码地址 + +[CycleGAN代码]( https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix) + +branch:master + +commit_id:略 + +备注:commit_id是指基于该次提交时的模型代码做推理,通常选择稳定版本的最后一次提交,或代码仓最新的一次提交 + + + +\## 2 环境说明 + + + +\- **[深度学习框架](#21-深度学习框架)** + + + +\- **[python第三方库](#22-python第三方库)** + + + +\### 2.1 深度学习框架 + +\``` + +``` +CANN 5.0.2.alpha003 + +torch == 1.5.0 + +torchvision == 0.9.0 + +onnx==1.7.0 + +onnx-simplifier==0.3.6 + +onnxconverter-common==1.6.1 + +onnxoptimizer==0.2.6 + +onnxruntime==1.6.0 + +tensorboard==1.15.0 + +tensorflow==1.15.0 + +tensorflow-estimator ==1.15.1 + +termcolor==1.1.0 +``` + +\``` + + + +\### 2.2 python第三方库 + +\``` + +``` +numpy == 1.16.6 + +Pillow == 8.2.0 + +opencv-python == 4.5.2.52 + +sympy == 1.4 + +decorator == 4.4.2 + +requests == 2.22.0 + +tqdm == 4.61.0 + +PyYAML == 5.4.1 +``` + +\``` + + + +**说明:** + +\> X86架构:pytorch torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3 install 包名 安装 + +\> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3 install 包名 安装 + + + +\## 3 模型转换 + + + +\- **[pth转onnx模型](#31-pth转onnx模型)** + + + +\- **[onnx转om模型](#32-onnx转om模型)** + + + +\### 3.1 pth转onnx模型 + +1.下载开源模型代码,安装必要的依赖库,并修改模型代码后安装 + +\``` + +``` +git clone https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix +cd pytorch-CycleGAN-and-pix2pix +pip3 install -r requirements.txt +``` + +\``` + + + +2.下载pth权重文件 + + + +\- [官方CycleGAN pth权重文件](http://efrosgans.eecs.berkeley.edu/cyclegan/pretrained_models/) + +\- [获取A800-9000训练的pth文件,该链接为百度网盘链接,提取码为:1234](https://pan.baidu.com/s/1YqHkce2wUw-W8_VY9dYD_w)) + +3.编写pth2onnx脚本*CycleGAN_onnx_export.py* + + **说明:** + +\>注意目前ATC支持的onnx算子版本为11 + + + +4.执行*CycleGAN_onnx_export.py*脚本,生成onnx模型文件 + +\``` + +``` +python3 CycleGAN_onnx_export.py \ + +--model_ga_path=./checkpoints/maps_cycle_gan/latest_net_G_A.pth\ + +--model_gb_path=./checkpoints/maps_cycle_gan/latest_net_G_B.pth\ + +--onnx_path=./onnxmodel/ \ + +--model_ga_onnx_name=model_Ga.onnx \ + +--model_gb_onnx_name=model_Gb.onnx \ +``` + +\``` + + **模型转换要点:** + +\- 开源仓中的生成器采用的padding类型为ReflectionPad2d,由于在转om格式模型的时候,会出现算子不兼容问题导致om模型转换失败,这里我们将改padding类型替换为ZeroPad2d。如果您任然坚持使用ReflectionPad2d,请在转换Onnx格式后运行 + + ' ' ' + +``` +python3 CycleGAN_ReflectpadDeal.py \ + +--onnx_path=./onnxmodel/ \ + +--model_ga_onnx_name=model_Ga.onnx \ + +--model_gb_onnx_name=model_Gb.onnx \ +``` + +' ' ' + +该脚本会将ReflectionPad2d中的属性替换为constant,这样做的结果会导致模型执行推理时会出现边缘模糊,详情请见issue链接https://e.gitee.com/HUAWEI-ASCEND/issues/list?issue=I4467L#note_6141945 + + + +\### 3.2 onnx转om模型 + + + +1.设置环境变量 + +\``` + +``` +source env.sh +``` + +\``` + +\- 根据实际情况修改env.sh中的install_path=/usr/local/Ascend/ascend-toolkit/latest变量 + +\- 执行脚本前先执行指令 dos2unix * + + + +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN 5.0.1 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373) + +\``` + +``` +atc --framework=5 --model=./onnxmodel/model_Ga.onnx --output=Cons_Ga_aipp512_b0_bs1 --input_format=NCHW --input_shape="img_sat_maps:1,3,256,256" --out_nodes="Tanh_156:0" --log=debug --soc_version=Ascend310 --insert_op_conf=aipp_CycleGAN_pth.config + +atc --framework=5 --model=./onnxmodel/model_Gb.onnx --output=Cons_Gb_aipp512_b0_bs1 --input_format=NCHW --input_shape="img_maps_sat:1,3,256,256" --out_nodes="Tanh_156:0" --log=debug --soc_version=Ascend310 --insert_op_conf=aipp_CycleGAN_pth.config +``` + +\``` + +\- 说明 + + \- input_shape参数可通过Netron工具查看输入节点的名称和shape, 与pth转onnx步骤中的参数一致 + + \- out_nodes为指定输出节点, 通过Netron可以看到onnx文件有四个输出, 以自测转换的onnx为例 + + 如果在转onnx时使用的不是默认路径,请将—model中的参数设置为onnx格式模型所在的路径 + + + + + +\## 4 数据集预处理 + + + +\- **[数据集获取](#41-数据集获取)** + + + +\- **[数据集预处理](#42-数据集预处理)** + + + +\- **[生成数据集信息文件](#43-生成数据集信息文件)** + + + +\### 4.1 数据集获取 + +该模型使用[maps数据集](http://efrosgans.eecs.berkeley.edu/cyclegan/datasets/maps.zip)的testA和testB各1098张验证集进行测试,因为航拍地图和卫星地图之间的相互转换的两个生成器模型结构一样,这里我们只需要保证其中一个生辰器精度和性能跟上就行,这里我们以model_Ga.onnx和testA为推理的模型和测试数据集。 + + + +\### 4.2 数据集预处理 + +1.生成数据集信息文件脚本gen_dataset_info.py + +2.执行生成数据集信息脚本,生成数据集信息文件 + +\``` + +``` +python3 gen_dataset_info.py \ + +--src_path_testA=./datasets/maps/testA/ \ + +--save_pathTestA_dst=datasetsDst/maps/testA/ \ + +--dataTestA_infoName=testA_prep.info \ + +--src_path_testB=./datasets/maps/testB/ \ + +--save_pathTestB_dst=./datasetsDst/maps/testB/ \ + +--dataTestB_infoName=testB_prep.info +``` + +' ' ' + +\## 5 离线推理 + + + +\- **[benchmark工具概述](#51-benchmark工具概述)** + + + +\- **[离线推理](#52-离线推理)** + + + +\### 5.1 benchmark工具概述 + + + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN 5.0.1 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) + +\### 5.2 离线推理 + +1.设置环境变量 + +\``` + +source env.sh + +\``` + +2.执行离线推理 + +\- benchmark工具区分arm64和x86_64, 对应分别为./benchmark.aarch64和./benchmark.x86_64, 示例中均以x86_64环境为例 + +\- 将benchmark工具去相应路径获取后放到env.sh同级目录下,加上执行权限chmod +x benchmark.XX + +''' + +``` +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=Cons_Ga_aipp512_b0_bs1.om -input_text_path=testA_prep.info -input_width=512 -input_height=512 -output_binary=true -useDvpp=true + +./benchmark.x86_64 -model_type=vision -device_id=1 -batch_size=1 -om_path=Cons_Gb_aipp512_b0_bs1.om -input_text_path=testB_prep.info -input_width=512 -input_height=512 -output_binary=true -useDvpp=true +``` + +输出结果默认保存在当前目录result/dumpOutput_devicex,每个输入对应的输出对应一个_x.bin文件。 + +''' + +\## 6 精度对比 + +\### 6.1 离线推理精度统计 + +由于该模型的精度在论文中是由人眼分辨,所以这里我们那Onnx和om模型输出的平均余弦相似度来替代精度,只需要保证Onnx格式模型的效果和论文中的一致并且om和onnx格式模型的余弦相似度在99%左右就精度达标。执行eval_acc_py.py脚本计算平均余弦相似度 : + +\``` + +``` + +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=Cons_Ga_aipp512_b0_bs1.om -input_text_path=testA_prep.info -input_width=512 -input_height=512 -output_binary=true -useDvpp=true #如果已经执行这一步请忽略 +python3 eval_acc.py \ +--dataroot=./datasets/maps\ +--npu_bin_file=./result/dumpOutput_device0/ +``` + +\``` + +\### 6.2精度对比 + +![1](C:\Users\Administrator\Desktop\1.png) + +将得到的om离线模型推理精度与在线推理精度对比,推理精度与在线推理精度一致,精度达标。 + + **精度调试:** + +使用onnxruntime测试onnx离线推理精度与om一致。 + +\## 7 性能对比 + +\- **[npu性能数据](#71-npu性能数据)** + +\- **[性能优化](#73-性能优化)** + +\### 7.1 npu性能数据 + +这里用batch1和batch16做示例 + + + +benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device。为快速获取性能数据,也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准。这里给出两种方式,模型的测试脚本使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准。 + + + +1.benchmark工具在整个数据集上推理获得性能数据 + + + +以batch1为例,benchmark工具在整个数据集上推理,执行下面命令。 + +``` +atc --framework=5 --model=./onnxmodel/model_Ga.onnx --output=Cons_Ga_aipp512_b0_bs1 --input_format=NCHW --input_shape="img_sat_maps:1,3,256,256" --out_nodes="Tanh_156:0" --log=debug --soc_version=Ascend310 --insert_op_conf=aipp_CycleGAN_pth.config #如果已经转换,请忽略 +python3.7 gen_dataset_info.py #如果这一步已经执行,可直接执行下一步推理 +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=Cons_Ga_aipp512_b0_bs1.om -input_text_path=testA_prep.info -input_width=512 -input_height=512 -output_binary=true -useDvpp=true +``` + +\``` + + ![输入图片说明](https://images.gitee.com/uploads/images/2021/0914/121624_f45173ef_9486012.png "屏幕截图.png") + + + +Interface throughputRate: 10.7,10.7乘以4,是310单卡吞吐率 + + \``` + +2.benchmark纯推理功能测得性能数据 + + + +batch1的性能: + + 测试npu性能要确保device空闲,使用npu-smi info命令可查看device是否在运行其它推理任务 + +\``` + +``` +./benchmark.x86_64 -round=20 -om_path=Cons_Ga_aipp512_b0_bs1.om -device_id=0 -batch_size=1 +``` + +``` + +执行20次纯推理取均值,统计吞吐率与其倒数时延(benchmark的时延是单个数据的推理时间),npu性能是一个device执行的结果 + + ![输入图片说明](https://images.gitee.com/uploads/images/2021/0914/121641_4ed82b8d_9486012.png "屏幕截图.png") +``` + + +Batch16的性能: + +``` +./benchmark.x86_64 -round=20 -om_path=model_Ga-b0_bs16.om -device_id=1 -batch_size=16 +``` + +![输入图片说明](https://images.gitee.com/uploads/images/2021/0914/121659_6331aa3d_9486012.png "屏幕截图.png") + +\### 7.2 性能优化 + +``` +**性能优化** + +\- profiling性能分析方法 + +​ CANN C20及以后的版本profiling使用方法 + +新建/home/zlz/CycleGan_deal/perProblem_detec/run文件,内容如下: + +``` +``` +# /usr/local/Ascend/ascend-toolkit/ /usr/local/Ascend/ascend-toolkit/ +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp +./benchmark.x86_64 -round=20 -om_path=/home/zlz/cyclegan/model_Ga1-b0_bs16.om -device_id=0 -batch_size=16 +``` + +然后执行如下命令: +``` +chmod 777 /home/zlz/CycleGan_deal/perProblem_detec/run +cd /usr/local/Ascend/ascend-toolkit/latest/x86_64-linux/toolkit/tools/profiler/bin +./msprof --output=/home/zlz/CycleGan_deal/perProblem_detec/perPro/ --application=/home/zlz/CycleGan_deal/perProblem_detec/run --sys-hardware-mem=on --sys-cpu-profiling=on --sys-profiling=on --sys-pid-profiling=on --sys-io-profiling=on --dvpp-profiling=on +cd /usr/local/Ascend/ascend-toolkit/latest/x86_64-linux/toolkit/tools/profiler/profiler_tool/analysis/msprof/ +# 生成的profiling目录 +python3.7 msprof.py import -dir/home/zlz/CycleGan_deal/perProblem_detec/perPro/ +python3.7 msprof.py export summary -dir /home/zlz/CycleGan_deal/perProblem_detec/perPro/ +#生成的profiling目录 --iteration-id 1 +python3.7 msprof.py export timeline -dir /home/zlz/CycleGan_deal/perProblem_detec/perPro/ + +``` +目录 + +\- 性能调优测试版本:CANN 5.0.2.alpha003 + +\- 性能优化过程主要对trans_Data算子进行优化,结合profiling分析,性能有提升: + +\#### 7.3.1 five_2_four.py优化方法 + + 在环境变量env.sh中export install_path=/usr/local/Ascend/ascend-toolkit/latest路径下查找five_2_four.py文件,路径一般为 + +\``` + +/usr/local/Ascend/ascend-toolkit/latest/x86_64-linux/opp/op_impl/built-in/ai_core/tbe/impl/five_2_four.py + +\``` + +修改five_2_four.py文件,将TransData算子的output shape加入five_2_four函数行中,示例如下: + +\``` + + ... + from impl import trans_data_negative_target_ntc + + @util.check_input_type(dict, dict, str, str, str) + + def five_2_four(src, dst, src_format, dst_format, kernel_name='five_2_four'): + elif dst_format.lower() == "nhwc" and dst_shape in [[10000, 63, 63, 1], [10000, 127, 127, 1], [16, 19, 19, 486], + + [16, 10, 10, 486], [16, 38, 38, 324], [16, 5, 5, 486], + + [16, 3, 3, 324], [8, 19, 19, 486], [8, 10, 10, 486], + + [8, 38, 38, 324], [8, 5, 5, 486], [8, 3, 3, 324], + + [100, 28, 28, 91]]: + + trans_data_negative_target_tc.trans_data_negative_target_tc(src, dst, src_format, dst_format, kernel_name) + + elif dst_format.lower() == "nchw" and dst_shape in [[2560, 512, 4, 26], [2560, 512, 1, 26], [2560, 256, 8, 25], + + [16, 240, 7, 7], [16, 120, 14, 14], [1,19,1024,2048], [4,19,1024,2048]]: + + print("=================================") + + print("ntc dst shape:", dst_shape) + + print("=================================") + + trans_data_negative_target_ntc.trans_data_negative_target_ntc(src, dst, src_format, dst_format, kernel_name) + ... + +\``` + +\- 不同的batch_size,添加的shape不一样,shape大小为[*,19,256,256 ] ,以本模型为例,只测试batch1和batch16,因此添加的shape为[1,19,256,256],[4,19,256,256] + +修改完成后,重新转换生成om文件,atc转换过程会打印添加的日志,如下: + +\```![输入图片说明](https://images.gitee.com/uploads/images/2021/0914/121715_d94592ad_9486012.png "屏幕截图.png") + + \``` + +纯推理测试结果: + +\``` + +bs1: + + ![输入图片说明](https://images.gitee.com/uploads/images/2021/0914/121721_50c95bdd_9486012.png "屏幕截图.png") + +Bs16: + +![输入图片说明](https://images.gitee.com/uploads/images/2021/0914/122022_a16e9ff5_9486012.png "屏幕截图.png") + +\``` + + + +用生成的om文件做精度后处理,测得bs1和bs16与之前的Onnx模型做余弦相似度高于99%,精度无损失、 + +\``` + +\#### 7.3.1 总结 + +优化方案共包括五种: + +(1)优化TransData,修改five_2_four.py + +(2)输出节点由float32改为float16 + +(3)模型中Resize节点的mode由双线性为最近邻 + +(4)将PadV3D进行算子融合 + +(5)优化FrameworkOP框架 + +由于在蓝区测试的版本CANN 5.0.2.alpha003中,已经实现了PadV3D算子融合,因此测试过程默认已经优化。同时方案(5)暂时无法实现,因此也无法比对性能。 + +结论: + +\- 因为关键算子性能差,性能暂时无法达标。 + \- 最终精度测试,Om模型输出效果达到论文效果,转Om后无精度损失。 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/gan/CycleGAN/eval_acc.py b/ACL_PyTorch/contrib/cv/gan/CycleGAN/eval_acc.py index 875097d6fe..e25f08a55a 100644 --- a/ACL_PyTorch/contrib/cv/gan/CycleGAN/eval_acc.py +++ b/ACL_PyTorch/contrib/cv/gan/CycleGAN/eval_acc.py @@ -1,110 +1,110 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import os -import glob -import numpy as np -import onnxruntime -import torch -from PIL import Image -from torchvision import transforms -import parse -import PIL.Image as pil -import matplotlib.pyplot as plt - - -def make_power(img, base, method=Image.BICUBIC): - ow, oh = img.size - h = int(round(oh / base) * base) - w = int(round(ow / base) * base) - if h == oh and w == ow: - return img - return img.resize((w, h), method) - - -def preprocess(PIL_img, image_shape): - process = transforms.Compose([ - transforms.Lambda(lambda img: make_power(img, base=4, method=Image.BICUBIC)), - transforms.Resize(image_shape), - transforms.ToTensor(), - transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))]) - return process(PIL_img).unsqueeze(dim=0) # (batch_size, 3, H, W) - - -def postprocess(img_tensor): - inv_normalize = transforms.Normalize( - mean=(-1, -1, -1), - std=(2.0, 2.0, 2.0)) - to_PIL_image = transforms.ToPILImage() - return to_PIL_image(inv_normalize(img_tensor[0]).clamp(0, 1)) - - -def bin2img_tensor(bin_src): - # read bin - with open(bin_src, 'rb') as f: - imageBin = f.read() - # What is stored in the bin file is a half-precision file, so we need to convert - # the binary to half-precision, and restore the model output shape 1*3*256*256 - img_tensor = torch.tensor(np.reshape(np.frombuffer(imageBin, 'f4'), (1, 3, 256, 256))) - return img_tensor - - -def main(): - opt = parse.parse_args().initialize() - if (os.path.exists(opt.bin2img_fie) == False): - os.makedirs(opt.bin2img_fie) - npu_bin = glob.glob(opt.npu_bin_file + '*.bin') - onnxTestImage_path = glob.glob(opt.dataroot + '/testA/*.*') - model_Ga = onnxruntime.InferenceSession(opt.onnx_path + opt.model_ga_onnx_name) - cossimis = [] - for i in onnxTestImage_path: - temp = i.split('/')[4].split('.')[0] - bin_name = temp + '_1.bin' - bin_path = opt.npu_bin_file + bin_name - check = os.path.exists(bin_path) - if check == True: - b2imtensor = bin2img_tensor(bin_path) - pil_image = pil.open(i).convert('RGB') - tensorData = preprocess(pil_image, 256) - outputs = model_Ga.run(['maps'], {'img_sat_maps': tensorData.numpy()}) - outputs = torch.tensor(outputs[0]) - cosSimi = torch.mean(torch.cosine_similarity(outputs, b2imtensor)) - cossimis.append(cosSimi.numpy()) - print('average cosine_similarity:') - print(np.mean(cossimis)) - plt.plot(cossimis) - plt.xlabel("samples") - plt.ylabel("cosine_similarity") - plt.savefig('cosine_similarity.jpg') - plt.show() - - -if __name__ == '__main__': - main() +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +import os +import glob +import numpy as np +import onnxruntime +import torch +from PIL import Image +from torchvision import transforms +import parse +import PIL.Image as pil +import matplotlib.pyplot as plt + + +def make_power(img, base, method=Image.BICUBIC): + ow, oh = img.size + h = int(round(oh / base) * base) + w = int(round(ow / base) * base) + if h == oh and w == ow: + return img + return img.resize((w, h), method) + + +def preprocess(PIL_img, image_shape): + process = transforms.Compose([ + transforms.Lambda(lambda img: make_power(img, base=4, method=Image.BICUBIC)), + transforms.Resize(image_shape), + transforms.ToTensor(), + transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))]) + return process(PIL_img).unsqueeze(dim=0) # (batch_size, 3, H, W) + + +def postprocess(img_tensor): + inv_normalize = transforms.Normalize( + mean=(-1, -1, -1), + std=(2.0, 2.0, 2.0)) + to_PIL_image = transforms.ToPILImage() + return to_PIL_image(inv_normalize(img_tensor[0]).clamp(0, 1)) + + +def bin2img_tensor(bin_src): + # read bin + with open(bin_src, 'rb') as f: + imageBin = f.read() + # What is stored in the bin file is a half-precision file, so we need to convert + # the binary to half-precision, and restore the model output shape 1*3*256*256 + img_tensor = torch.tensor(np.reshape(np.frombuffer(imageBin, 'f4'), (1, 3, 256, 256))) + return img_tensor + + +def main(): + opt = parse.parse_args().initialize() + if (os.path.exists(opt.bin2img_fie) == False): + os.makedirs(opt.bin2img_fie) + npu_bin = glob.glob(opt.npu_bin_file + '*.bin') + onnxTestImage_path = glob.glob(opt.dataroot + '/testA/*.*') + model_Ga = onnxruntime.InferenceSession(opt.onnx_path + opt.model_ga_onnx_name) + cossimis = [] + for i in onnxTestImage_path: + temp = i.split('/')[4].split('.')[0] + bin_name = temp + '_1.bin' + bin_path = opt.npu_bin_file + bin_name + check = os.path.exists(bin_path) + if check == True: + b2imtensor = bin2img_tensor(bin_path) + pil_image = pil.open(i).convert('RGB') + tensorData = preprocess(pil_image, 256) + outputs = model_Ga.run(['maps'], {'img_sat_maps': tensorData.numpy()}) + outputs = torch.tensor(outputs[0]) + cosSimi = torch.mean(torch.cosine_similarity(outputs, b2imtensor)) + cossimis.append(cosSimi.numpy()) + print('average cosine_similarity:') + print(np.mean(cossimis)) + plt.plot(cossimis) + plt.xlabel("samples") + plt.ylabel("cosine_similarity") + plt.savefig('cosine_similarity.jpg') + plt.show() + + +if __name__ == '__main__': + main() diff --git a/ACL_PyTorch/contrib/cv/gan/CycleGAN/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/gan/CycleGAN/gen_dataset_info.py index 51f2d64c68..313e6529d4 100644 --- a/ACL_PyTorch/contrib/cv/gan/CycleGAN/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/gan/CycleGAN/gen_dataset_info.py @@ -1,89 +1,89 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -import argparse -import os -from PIL import Image - - -def parse(): - """Define the common options that are used in both training and test.""" - # basic parameters - parser = argparse.ArgumentParser(description='cyclegan test for image preprocess') - parser.add_argument('--src_path_testA', required=False, default='datasets/maps/testA/', - help='path to images testA)') - parser.add_argument('--save_pathTestA_dst', required=False, default='datasetsDst/maps/testA/', - help='path to images testA)') - parser.add_argument('--dataTestA_infoName', default='testA_prep.info', help='name of the ..') - - parser.add_argument('--src_path_testB', required=False, default='datasets/maps/testB/', - help='path to images testB)') - parser.add_argument('--save_pathTestB_dst', required=False, default='datasetsDst/maps/testB/', - help='path to images testA)') - parser.add_argument('--dataTestB_infoName', required=False, default='testB_prep.info', help='name of the ..') - opt = parser.parse_args() - if (os.path.exists(opt.save_pathTestA_dst) == False): - os.makedirs(opt.save_pathTestA_dst) - if (os.path.exists(opt.save_pathTestB_dst) == False): - os.makedirs(opt.save_pathTestB_dst) - return opt - - -def rs_img_bin(src_path, savepath, data_list_path): - i = 0 - in_files = os.listdir(src_path) - listfile = open(data_list_path, 'w') - for file in in_files: - # print(file, "===", i) - image_path = src_path + '/' + file - input_image = Image.open(image_path) - imgsavepath = savepath + str(file).split('.')[0] + '.jpeg' - input_image.thumbnail((512, 512), Image.ANTIALIAS) - input_image.save(imgsavepath) - w, h = input_image.size - temp = str(i) + ' ' + savepath + '/' + str(file).split('.')[0] + \ - '.jpeg' + ' ' + str(w) + ' ' + str(h) + '\n' - listfile.write(temp) - i = i + 1 - listfile.close() - - -def main(opt): - # deal testA and save img data to bin - rs_img_bin(opt.src_path_testA, opt.save_pathTestA_dst, opt.dataTestA_infoName) - # deal testB and save img data to bin - rs_img_bin(opt.src_path_testB, opt.save_pathTestB_dst, opt.dataTestB_infoName) - return 0 - - -if __name__ == '__main__': - opt = parse() - main(opt) +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import argparse +import os +from PIL import Image + + +def parse(): + """Define the common options that are used in both training and test.""" + # basic parameters + parser = argparse.ArgumentParser(description='cyclegan test for image preprocess') + parser.add_argument('--src_path_testA', required=False, default='datasets/maps/testA/', + help='path to images testA)') + parser.add_argument('--save_pathTestA_dst', required=False, default='datasetsDst/maps/testA/', + help='path to images testA)') + parser.add_argument('--dataTestA_infoName', default='testA_prep.info', help='name of the ..') + + parser.add_argument('--src_path_testB', required=False, default='datasets/maps/testB/', + help='path to images testB)') + parser.add_argument('--save_pathTestB_dst', required=False, default='datasetsDst/maps/testB/', + help='path to images testA)') + parser.add_argument('--dataTestB_infoName', required=False, default='testB_prep.info', help='name of the ..') + opt = parser.parse_args() + if (os.path.exists(opt.save_pathTestA_dst) == False): + os.makedirs(opt.save_pathTestA_dst) + if (os.path.exists(opt.save_pathTestB_dst) == False): + os.makedirs(opt.save_pathTestB_dst) + return opt + + +def rs_img_bin(src_path, savepath, data_list_path): + i = 0 + in_files = os.listdir(src_path) + listfile = open(data_list_path, 'w') + for file in in_files: + # print(file, "===", i) + image_path = src_path + '/' + file + input_image = Image.open(image_path) + imgsavepath = savepath + str(file).split('.')[0] + '.jpeg' + input_image.thumbnail((512, 512), Image.ANTIALIAS) + input_image.save(imgsavepath) + w, h = input_image.size + temp = str(i) + ' ' + savepath + '/' + str(file).split('.')[0] + \ + '.jpeg' + ' ' + str(w) + ' ' + str(h) + '\n' + listfile.write(temp) + i = i + 1 + listfile.close() + + +def main(opt): + # deal testA and save img data to bin + rs_img_bin(opt.src_path_testA, opt.save_pathTestA_dst, opt.dataTestA_infoName) + # deal testB and save img data to bin + rs_img_bin(opt.src_path_testB, opt.save_pathTestB_dst, opt.dataTestB_infoName) + return 0 + + +if __name__ == '__main__': + opt = parse() + main(opt) diff --git a/ACL_PyTorch/contrib/cv/gan/CycleGAN/maps_torch_preprocess.py b/ACL_PyTorch/contrib/cv/gan/CycleGAN/maps_torch_preprocess.py index f7f45d6b8d..cacbde78fe 100644 --- a/ACL_PyTorch/contrib/cv/gan/CycleGAN/maps_torch_preprocess.py +++ b/ACL_PyTorch/contrib/cv/gan/CycleGAN/maps_torch_preprocess.py @@ -1,109 +1,109 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -import argparse -import os -import torchvision.transforms as transforms -from PIL import Image -import numpy as np - - -def make_power(img, base, method=Image.BICUBIC): - ow, oh = img.size - h = int(round(oh / base) * base) - w = int(round(ow / base) * base) - if h == oh and w == ow: - return img - return img.resize((w, h), method) - - -def preprocess(PIL_img, image_shape=256): - process=transforms.Compose([ - transforms.Lambda(lambda img: make_power(img, base=4, method=Image.BICUBIC)), - transforms.Resize(image_shape), - transforms.ToTensor(), - transforms.Normalize(mean=(0.5,0.5,0.5), std=(0.5,0.5,0.5))]) - return process(PIL_img) - - -def postprocess(img_tensor): - inv_normalize = transforms.Normalize( - mean= (-1,-1,-1), - std= (2.0,2.0,2.0)) - to_PIL_image = transforms.ToPILImage().convert('RGB') - return to_PIL_image(inv_normalize(img_tensor[0]).clamp(0, 1)) - - -def parse(): - """Define the common options that are used in both training and test.""" - # basic parameters - parser = argparse.ArgumentParser(description='cyclegan test for image preprocess') - parser.add_argument('--src_path_testA', required=False,default='datasets/maps/testA/', help='path to images testA)') - parser.add_argument('--save_path_testA_bin', type=str, default='nputest/testa', help='name of the ..') - parser.add_argument('--path_testA_binName', type=str, default='testA_prep_bin.info', help='name of the ..') - parser.add_argument('--src_path_testB', required=False, default='datasets/maps/testB/', help='path to images testB)') - parser.add_argument('--save_path_testB_bin', type=str, default='nputest/testb', help='name of the ..') - parser.add_argument('--path_testB_binName', type=str, default='testB_prep_bin.info', help='name of the ..') - opt=parser.parse_args() - if(os.path.exists(opt.save_path_testA_bin)==False): - os.makedirs(opt.save_path_testA_bin) - if(os.path.exists(opt.save_path_testB_bin)==False): - os.makedirs(opt.save_path_testB_bin) - return opt - - -def rs_img_bin(src_path,save_path,data_list_path): - i = 0 - in_files = os.listdir(src_path) - listfile = open(data_list_path, 'w') - for file in in_files: - #print(file, "===", i) - input_image = Image.open(src_path + '/' + file) - input_tensor = preprocess(input_image) - img = np.array(input_tensor).astype(np.float32) - img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) - temp = str(str(i) + ' ./' + os.path.join(save_path, file.split('.')[0] + ".bin") + ' ' + '256 256\n') - listfile.write(temp) - i = i + 1 - listfile.close() - - -def main(opt): - # deal testA and save img data to bin - rs_img_bin(opt.src_path_testA, opt.save_path_testA_bin, opt.path_testA_binName) - # deal testB and save img data to bin - rs_img_bin(opt.src_path_testB, opt.save_path_testB_bin, opt.path_testB_binName) - return 0 - - -if __name__=='__main__': - opt=parse() +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import argparse +import os +import torchvision.transforms as transforms +from PIL import Image +import numpy as np + + +def make_power(img, base, method=Image.BICUBIC): + ow, oh = img.size + h = int(round(oh / base) * base) + w = int(round(ow / base) * base) + if h == oh and w == ow: + return img + return img.resize((w, h), method) + + +def preprocess(PIL_img, image_shape=256): + process=transforms.Compose([ + transforms.Lambda(lambda img: make_power(img, base=4, method=Image.BICUBIC)), + transforms.Resize(image_shape), + transforms.ToTensor(), + transforms.Normalize(mean=(0.5,0.5,0.5), std=(0.5,0.5,0.5))]) + return process(PIL_img) + + +def postprocess(img_tensor): + inv_normalize = transforms.Normalize( + mean= (-1,-1,-1), + std= (2.0,2.0,2.0)) + to_PIL_image = transforms.ToPILImage().convert('RGB') + return to_PIL_image(inv_normalize(img_tensor[0]).clamp(0, 1)) + + +def parse(): + """Define the common options that are used in both training and test.""" + # basic parameters + parser = argparse.ArgumentParser(description='cyclegan test for image preprocess') + parser.add_argument('--src_path_testA', required=False,default='datasets/maps/testA/', help='path to images testA)') + parser.add_argument('--save_path_testA_bin', type=str, default='nputest/testa', help='name of the ..') + parser.add_argument('--path_testA_binName', type=str, default='testA_prep_bin.info', help='name of the ..') + parser.add_argument('--src_path_testB', required=False, default='datasets/maps/testB/', help='path to images testB)') + parser.add_argument('--save_path_testB_bin', type=str, default='nputest/testb', help='name of the ..') + parser.add_argument('--path_testB_binName', type=str, default='testB_prep_bin.info', help='name of the ..') + opt=parser.parse_args() + if(os.path.exists(opt.save_path_testA_bin)==False): + os.makedirs(opt.save_path_testA_bin) + if(os.path.exists(opt.save_path_testB_bin)==False): + os.makedirs(opt.save_path_testB_bin) + return opt + + +def rs_img_bin(src_path,save_path,data_list_path): + i = 0 + in_files = os.listdir(src_path) + listfile = open(data_list_path, 'w') + for file in in_files: + #print(file, "===", i) + input_image = Image.open(src_path + '/' + file) + input_tensor = preprocess(input_image) + img = np.array(input_tensor).astype(np.float32) + img.tofile(os.path.join(save_path, file.split('.')[0] + ".bin")) + temp = str(str(i) + ' ./' + os.path.join(save_path, file.split('.')[0] + ".bin") + ' ' + '256 256\n') + listfile.write(temp) + i = i + 1 + listfile.close() + + +def main(opt): + # deal testA and save img data to bin + rs_img_bin(opt.src_path_testA, opt.save_path_testA_bin, opt.path_testA_binName) + # deal testB and save img data to bin + rs_img_bin(opt.src_path_testB, opt.save_path_testB_bin, opt.path_testB_binName) + return 0 + + +if __name__=='__main__': + opt=parse() main(opt) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/gan/CycleGAN/parse.py b/ACL_PyTorch/contrib/cv/gan/CycleGAN/parse.py index a8142636cd..cc4b43d676 100644 --- a/ACL_PyTorch/contrib/cv/gan/CycleGAN/parse.py +++ b/ACL_PyTorch/contrib/cv/gan/CycleGAN/parse.py @@ -1,141 +1,141 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -import argparse -import torch -import os - - -class parse_args(): - def __init__(self, isTrain=True, isTest=False): - self.isTrain = isTrain - self.isTest = isTest - self.parser = argparse.ArgumentParser(description='Pytorch CycleGAN training') - - def initialize(self): - parser = self.parser - parser.add_argument('--npu', default=False, help='whether to use npu to fastern training') - parser.add_argument('--pu_ids', type=str, default='1', - help='gpu ids(npu ids): e.g. 0 0,1,2, 0,2. use -1 for CPU') - parser.add_argument('--dataroot', type=str, default='./datasets/maps', - help='path to images (should have subfolders trainA, trainB, valA, valB, etc)') - parser.add_argument('--name', type=str, default='maps_cycle_gan', - help='name of the experiment. It decides where to store samples and models') - - parser.add_argument('--checkpoints_dir', type=str, default='./checkpoints', help='models are saved here') - # model parameters - parser.add_argument('--model', type=str, default='cycle_gan', - help='chooses which model to use. [cycle_gan]') - parser.add_argument('--input_nc', type=int, default=3, - help='# of input image channels: 3 for RGB and 1 for grayscale') - parser.add_argument('--output_nc', type=int, default=3, - help='# of output image channels: 3 for RGB and 1 for grayscale') - parser.add_argument('--ngf', type=int, default=64, help='# of gen filters in the last conv layer') - parser.add_argument('--ndf', type=int, default=64, help='# of discrim filters in the first conv layer') - parser.add_argument('--netD', type=str, default='basic', - help='specify discriminator architecture [basic | n_layers | pixel]. ' - 'The basic model is a 70x70 PatchGAN. n_layers allows you to' - ' specify the layers in the discriminator') - parser.add_argument('--netG', type=str, default='resnet_9blocks', - help='specify generator architecture [resnet_9blocks | resnet_6blocks | unet_256 | unet_128]') - parser.add_argument('--n_layers_D', type=int, default=3, help='only used if netD==n_layers') - parser.add_argument('--norm', type=str, default='instance', - help='instance normalization or batch normalization [instance | batch | none]') - parser.add_argument('--init_type', type=str, default='normal', - help='network initialization [normal | xavier | kaiming | orthogonal]') - parser.add_argument('--init_gain', type=float, default=0.02, - help='scaling factor for normal, xavier and orthogonal.') - parser.add_argument('--no_dropout', action='store_true', help='no dropout for the generator') - parser.add_argument('--direction', type=str, default='AtoB', help='AtoB or BtoA') - parser.add_argument('--batch_size', type=int, default=1, - help='batch_size') - # additional parameters - parser.set_defaults(no_dropout=True) # default CycleGAN did not use dropout - parser.add_argument('--model_ga_path', type=str, - default='./checkpoints/maps_cycle_gan/latest_net_G_A.pth', - help='path for modelga') - parser.add_argument('--model_gb_path', type=str, - default='./checkpoints/maps_cycle_gan/latest_net_G_B.pth', - help='path for modelga') - parser.add_argument('--onnx_path', type=str, - default='./onnxmodel/', - help='path for modelga') - parser.add_argument('--model_ga_onnx_name', type=str, - default='model_Ga.onnx', - help='onnx name for modelga') - parser.add_argument('--model_gb_onnx_name', type=str, - default='model_Gb.onnx', - help='onnx for modelgb') - parser.add_argument('--gpuPerformance', type=str, - default='./gpuPerformance/', - help='file for t4 test result ') - parser.add_argument('--npu_bin_file', type=str, - default='./result/dumpOutput_device0/', - help='npu bin ') - parser.add_argument('--bin2img_fie', type=str, - default='./bin2imgfile/', - help='save bin2img ') - # rewrite devalue values - parser.set_defaults(model='test') - # To avoid cropping, the load_size should be the same as crop_size - parser.set_defaults(load_size=parser.get_default('crop_size')) - parser = parser.parse_args() - parser.process_device_map = self.device_id_to_process_device_map(parser.pu_ids) - return parser - - def device_id_to_process_device_map(self, device_list): - devices = device_list.split(",") - devices = [int(x) for x in devices] - devices.sort() - - process_device_map = dict() - for process_id, device_id in enumerate(devices): - process_device_map[process_id] = device_id - return process_device_map - - def change_parser(self, isTrain=True, isTest=False): - self.isTest = isTest - self.isTrain = isTrain - self.parser = None - return self.initialize() - - def printParser(self): - pasers = self.parser.parse_args() - message = '' - message += '----------------- Options ---------------\n' - for k, v in sorted(vars(pasers).items()): - comment = '' - default = self.parser.get_default(k) - # if v != default: - # comment = '\t[default: %s]' % str(default) - message += '{:>25}: {:<30}{}\n'.format(str(k), str(v), comment) - message += '----------------- End -------------------' - print(message) +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import argparse +import torch +import os + + +class parse_args(): + def __init__(self, isTrain=True, isTest=False): + self.isTrain = isTrain + self.isTest = isTest + self.parser = argparse.ArgumentParser(description='Pytorch CycleGAN training') + + def initialize(self): + parser = self.parser + parser.add_argument('--npu', default=False, help='whether to use npu to fastern training') + parser.add_argument('--pu_ids', type=str, default='1', + help='gpu ids(npu ids): e.g. 0 0,1,2, 0,2. use -1 for CPU') + parser.add_argument('--dataroot', type=str, default='./datasets/maps', + help='path to images (should have subfolders trainA, trainB, valA, valB, etc)') + parser.add_argument('--name', type=str, default='maps_cycle_gan', + help='name of the experiment. It decides where to store samples and models') + + parser.add_argument('--checkpoints_dir', type=str, default='./checkpoints', help='models are saved here') + # model parameters + parser.add_argument('--model', type=str, default='cycle_gan', + help='chooses which model to use. [cycle_gan]') + parser.add_argument('--input_nc', type=int, default=3, + help='# of input image channels: 3 for RGB and 1 for grayscale') + parser.add_argument('--output_nc', type=int, default=3, + help='# of output image channels: 3 for RGB and 1 for grayscale') + parser.add_argument('--ngf', type=int, default=64, help='# of gen filters in the last conv layer') + parser.add_argument('--ndf', type=int, default=64, help='# of discrim filters in the first conv layer') + parser.add_argument('--netD', type=str, default='basic', + help='specify discriminator architecture [basic | n_layers | pixel]. ' + 'The basic model is a 70x70 PatchGAN. n_layers allows you to' + ' specify the layers in the discriminator') + parser.add_argument('--netG', type=str, default='resnet_9blocks', + help='specify generator architecture [resnet_9blocks | resnet_6blocks | unet_256 | unet_128]') + parser.add_argument('--n_layers_D', type=int, default=3, help='only used if netD==n_layers') + parser.add_argument('--norm', type=str, default='instance', + help='instance normalization or batch normalization [instance | batch | none]') + parser.add_argument('--init_type', type=str, default='normal', + help='network initialization [normal | xavier | kaiming | orthogonal]') + parser.add_argument('--init_gain', type=float, default=0.02, + help='scaling factor for normal, xavier and orthogonal.') + parser.add_argument('--no_dropout', action='store_true', help='no dropout for the generator') + parser.add_argument('--direction', type=str, default='AtoB', help='AtoB or BtoA') + parser.add_argument('--batch_size', type=int, default=1, + help='batch_size') + # additional parameters + parser.set_defaults(no_dropout=True) # default CycleGAN did not use dropout + parser.add_argument('--model_ga_path', type=str, + default='./checkpoints/maps_cycle_gan/latest_net_G_A.pth', + help='path for modelga') + parser.add_argument('--model_gb_path', type=str, + default='./checkpoints/maps_cycle_gan/latest_net_G_B.pth', + help='path for modelga') + parser.add_argument('--onnx_path', type=str, + default='./onnxmodel/', + help='path for modelga') + parser.add_argument('--model_ga_onnx_name', type=str, + default='model_Ga.onnx', + help='onnx name for modelga') + parser.add_argument('--model_gb_onnx_name', type=str, + default='model_Gb.onnx', + help='onnx for modelgb') + parser.add_argument('--gpuPerformance', type=str, + default='./gpuPerformance/', + help='file for t4 test result ') + parser.add_argument('--npu_bin_file', type=str, + default='./result/dumpOutput_device0/', + help='npu bin ') + parser.add_argument('--bin2img_fie', type=str, + default='./bin2imgfile/', + help='save bin2img ') + # rewrite devalue values + parser.set_defaults(model='test') + # To avoid cropping, the load_size should be the same as crop_size + parser.set_defaults(load_size=parser.get_default('crop_size')) + parser = parser.parse_args() + parser.process_device_map = self.device_id_to_process_device_map(parser.pu_ids) + return parser + + def device_id_to_process_device_map(self, device_list): + devices = device_list.split(",") + devices = [int(x) for x in devices] + devices.sort() + + process_device_map = dict() + for process_id, device_id in enumerate(devices): + process_device_map[process_id] = device_id + return process_device_map + + def change_parser(self, isTrain=True, isTest=False): + self.isTest = isTest + self.isTrain = isTrain + self.parser = None + return self.initialize() + + def printParser(self): + pasers = self.parser.parse_args() + message = '' + message += '----------------- Options ---------------\n' + for k, v in sorted(vars(pasers).items()): + comment = '' + default = self.parser.get_default(k) + # if v != default: + # comment = '\t[default: %s]' % str(default) + message += '{:>25}: {:<30}{}\n'.format(str(k), str(v), comment) + message += '----------------- End -------------------' + print(message) diff --git a/ACL_PyTorch/contrib/cv/gan/DCGAN/README.md b/ACL_PyTorch/contrib/cv/gan/DCGAN/README.md index 51a5bcdee7..bc1071da1c 100644 --- a/ACL_PyTorch/contrib/cv/gan/DCGAN/README.md +++ b/ACL_PyTorch/contrib/cv/gan/DCGAN/README.md @@ -1,58 +1,58 @@ -# DCGAN模型PyTorch离线推理指导 -## 1 环境准备 -### 1.1 安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -``` -pip3.7 install -r requirements.txt -``` -### 1.2 获取,安装开源模型代码 -``` -git clone https://github.com/eriklindernoren/PyTorch-GAN.git -``` -使用patch文件更改开源代码仓源码 -``` -mv dcgan.patch PyTorch-GAN/ -cd PyTorch-GAN/ -git apply dcgan.patch -cd .. -``` -### 1.3 获取权重文件 -[DCGAN预训练权重文件](https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/GAN/DCGan/checkpoint-amp-epoch_200.pth) -``` -wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/GAN/DCGan/checkpoint-amp-epoch_200.pth -``` -### 1.4 数据集 -DCGAN的输入是随机噪声。当前目录下的`dcgan_preprocess.py`文件会随机生成输入噪声作为数据集。 -此脚本无需主动运行。 - -默认设置下,生成8192个噪声样本。 -### 1.5 [获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) -将benchmark.x86_64或benchmark.aarch64放到当前目录,并更改权限 -``` -chmod 777 benchmark.x86_64 -``` -## 2 离线推理 -### 2.1 性能测试 -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 -``` -bash test/pth2om.sh -bash test/eval_perf.sh -``` -### 2.2 精度测试 -由于开源代码仓并未提供合适的精度指标来衡量模型的生成精度。 -我们提供了图像像素差均值(mean)和图像余弦相似度(consine)作为精度指标以供参考。 - -因为npu的推理结果是以pth的生成结果为基准。 -所以两个指标的计算对象分别是pth模型在cpu上的生成集合和om模型在npu上的生成集合。 -除却均值指标与相似度指标外,还提供了一个精度指标(acc)。`acc=(cosine+1)/2`。目的是为了获得一个百分比值便于直观理解精度。 -``` -#直接执行acc验证脚本 -bash test/eval_acc.sh -``` - -结果分别保存在当前目录的`dcgan_acc_eval_bs1.log`与`dcgan_acc_eval_bs16.log`中。 -### 2.3 测评结果 -|模型|精度(mean)|精度(cosine)|精度(acc)|性能基准|310性能| -|----|----|----|----|----|----| -|DCGAN bs1|0.0004|1.0|100.0%|10174.65fps|11429.32fps| -|DCGAN bs16|0.0004|1.0|100.0%|46711.51fps|63607.60fps| - +# DCGAN模型PyTorch离线推理指导 +## 1 环境准备 +### 1.1 安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +``` +pip3.7 install -r requirements.txt +``` +### 1.2 获取,安装开源模型代码 +``` +git clone https://github.com/eriklindernoren/PyTorch-GAN.git +``` +使用patch文件更改开源代码仓源码 +``` +mv dcgan.patch PyTorch-GAN/ +cd PyTorch-GAN/ +git apply dcgan.patch +cd .. +``` +### 1.3 获取权重文件 +[DCGAN预训练权重文件](https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/GAN/DCGan/checkpoint-amp-epoch_200.pth) +``` +wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/GAN/DCGan/checkpoint-amp-epoch_200.pth +``` +### 1.4 数据集 +DCGAN的输入是随机噪声。当前目录下的`dcgan_preprocess.py`文件会随机生成输入噪声作为数据集。 +此脚本无需主动运行。 + +默认设置下,生成8192个噪声样本。 +### 1.5 [获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) +将benchmark.x86_64或benchmark.aarch64放到当前目录,并更改权限 +``` +chmod 777 benchmark.x86_64 +``` +## 2 离线推理 +### 2.1 性能测试 +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 +``` +bash test/pth2om.sh +bash test/eval_perf.sh +``` +### 2.2 精度测试 +由于开源代码仓并未提供合适的精度指标来衡量模型的生成精度。 +我们提供了图像像素差均值(mean)和图像余弦相似度(consine)作为精度指标以供参考。 + +因为npu的推理结果是以pth的生成结果为基准。 +所以两个指标的计算对象分别是pth模型在cpu上的生成集合和om模型在npu上的生成集合。 +除却均值指标与相似度指标外,还提供了一个精度指标(acc)。`acc=(cosine+1)/2`。目的是为了获得一个百分比值便于直观理解精度。 +``` +#直接执行acc验证脚本 +bash test/eval_acc.sh +``` + +结果分别保存在当前目录的`dcgan_acc_eval_bs1.log`与`dcgan_acc_eval_bs16.log`中。 +### 2.3 测评结果 +|模型|精度(mean)|精度(cosine)|精度(acc)|性能基准|310性能| +|----|----|----|----|----|----| +|DCGAN bs1|0.0004|1.0|100.0%|10174.65fps|11429.32fps| +|DCGAN bs16|0.0004|1.0|100.0%|46711.51fps|63607.60fps| + diff --git a/ACL_PyTorch/contrib/cv/gan/DCGAN/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/gan/DCGAN/modelzoo_level.txt index 9e95396651..27e6c78b37 100644 --- a/ACL_PyTorch/contrib/cv/gan/DCGAN/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/gan/DCGAN/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:POK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/gan/GAN/GAN_pth2onnx.py b/ACL_PyTorch/contrib/cv/gan/GAN/GAN_pth2onnx.py index 790cd62c5e..457cb19bd6 100644 --- a/ACL_PyTorch/contrib/cv/gan/GAN/GAN_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/gan/GAN/GAN_pth2onnx.py @@ -1,54 +1,54 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 torch -from models import Generator -from torch.autograd import Variable -import argparse -import numpy as np -from collections import OrderedDict - -def proc_nodes_module(checkpoint): - new_state_dict = OrderedDict() - for k, v in checkpoint.items(): - if "module." in k: - name = k.replace("module.", "") - else: - name = k - new_state_dict[name] = v - return new_state_dict - -def pth2onnx(input_file, output_file): - generator = Generator() - checkpoint = torch.load(input_file, map_location=torch.device('cpu')) - checkpoint = proc_nodes_module(checkpoint) - generator.load_state_dict(checkpoint) - input_names = ["Z"] - output_names = ["generateimg"] - dynamic_axes = {'Z': {0: '-1'}, 'generateimg': {0: '-1'}} - - Tensor = torch.FloatTensor - dummy_input = Variable(Tensor(np.random.normal(0, 1, (16, 100)))) - torch.onnx.export(generator, dummy_input, output_file, input_names = input_names, - output_names = output_names,dynamic_axes = dynamic_axes,opset_version=11, verbose=True) - - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('--input_file', type=str, required=True) - parser.add_argument('--output_file', type=str, required=True) - args = parser.parse_args() - - pth2onnx(args.input_file, args.output_file) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 torch +from models import Generator +from torch.autograd import Variable +import argparse +import numpy as np +from collections import OrderedDict + +def proc_nodes_module(checkpoint): + new_state_dict = OrderedDict() + for k, v in checkpoint.items(): + if "module." in k: + name = k.replace("module.", "") + else: + name = k + new_state_dict[name] = v + return new_state_dict + +def pth2onnx(input_file, output_file): + generator = Generator() + checkpoint = torch.load(input_file, map_location=torch.device('cpu')) + checkpoint = proc_nodes_module(checkpoint) + generator.load_state_dict(checkpoint) + input_names = ["Z"] + output_names = ["generateimg"] + dynamic_axes = {'Z': {0: '-1'}, 'generateimg': {0: '-1'}} + + Tensor = torch.FloatTensor + dummy_input = Variable(Tensor(np.random.normal(0, 1, (16, 100)))) + torch.onnx.export(generator, dummy_input, output_file, input_names = input_names, + output_names = output_names,dynamic_axes = dynamic_axes,opset_version=11, verbose=True) + + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('--input_file', type=str, required=True) + parser.add_argument('--output_file', type=str, required=True) + args = parser.parse_args() + + pth2onnx(args.input_file, args.output_file) diff --git a/ACL_PyTorch/contrib/cv/gan/GAN/GAN_testdata.py b/ACL_PyTorch/contrib/cv/gan/GAN/GAN_testdata.py index 6b33ec6b2d..86b6d85bdf 100644 --- a/ACL_PyTorch/contrib/cv/gan/GAN/GAN_testdata.py +++ b/ACL_PyTorch/contrib/cv/gan/GAN/GAN_testdata.py @@ -1,58 +1,58 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 os -import torch -from models import Generator -from torch.autograd import Variable -from torchvision.utils import save_image -import numpy as np -import argparse - -def main(args): - os.makedirs(args.online_path, exist_ok=True) - os.makedirs(args.offline_path, exist_ok=True) - generator = Generator() - pre = torch.load(args.pth_path,map_location='cpu') - - from collections import OrderedDict - - new_state_dict = OrderedDict() - for k, v in pre.items(): - name = k.replace("module.", "") - new_state_dict[name] = v - # load params - generator.load_state_dict(new_state_dict) - Tensor = torch.FloatTensor - for i in range(args.iters): - z = Variable(Tensor(np.random.normal(0, 1, (args.batch_size,100)))) - - if args.batch_size != 1: - gen = generator(z) - save_image(gen, args.online_path+"/%d.jpg" % i,normalize=True) - - z = z.numpy() - z.tofile(args.offline_path+"/%d.bin"% i) - - print("done!") - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('--online_path', type=str, required=True) - parser.add_argument('--offline_path', type=str, required=True) - parser.add_argument('--pth_path', type=str, required=True) - parser.add_argument('--iters', type=int, default=1) - parser.add_argument('--batch_size', type=int, default=1) - args = parser.parse_args() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 os +import torch +from models import Generator +from torch.autograd import Variable +from torchvision.utils import save_image +import numpy as np +import argparse + +def main(args): + os.makedirs(args.online_path, exist_ok=True) + os.makedirs(args.offline_path, exist_ok=True) + generator = Generator() + pre = torch.load(args.pth_path,map_location='cpu') + + from collections import OrderedDict + + new_state_dict = OrderedDict() + for k, v in pre.items(): + name = k.replace("module.", "") + new_state_dict[name] = v + # load params + generator.load_state_dict(new_state_dict) + Tensor = torch.FloatTensor + for i in range(args.iters): + z = Variable(Tensor(np.random.normal(0, 1, (args.batch_size,100)))) + + if args.batch_size != 1: + gen = generator(z) + save_image(gen, args.online_path+"/%d.jpg" % i,normalize=True) + + z = z.numpy() + z.tofile(args.offline_path+"/%d.bin"% i) + + print("done!") + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('--online_path', type=str, required=True) + parser.add_argument('--offline_path', type=str, required=True) + parser.add_argument('--pth_path', type=str, required=True) + parser.add_argument('--iters', type=int, default=1) + parser.add_argument('--batch_size', type=int, default=1) + args = parser.parse_args() main(args) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/gan/GAN/GAN_txt2jpg.py b/ACL_PyTorch/contrib/cv/gan/GAN/GAN_txt2jpg.py index 24ce1e8adb..a345e5fbf3 100644 --- a/ACL_PyTorch/contrib/cv/gan/GAN/GAN_txt2jpg.py +++ b/ACL_PyTorch/contrib/cv/gan/GAN/GAN_txt2jpg.py @@ -1,50 +1,50 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 argparse -import torch -import numpy as np -import os -from torchvision.utils import save_image - -def read_bin(filename): - - data = np.fromfile(filename,dtype=np.float32) - data = torch.Tensor(data) - data = data.view(-1,1,28,28) - return data - -def main(args): - old_path = os.listdir(args.txt_path) - os.makedirs(args.infer_results_path, exist_ok=True) - old_path.sort(reverse=True) - new_path = args.txt_path+'/'+old_path[0] - files = os.listdir(new_path) - for file in files: - filename = new_path + '/' + file - data = read_bin(filename) - if file[1]!='_': - save_path = args.infer_results_path + '/' + file[:2] + ".jpg" - else: - save_path = args.infer_results_path + '/' + file[0] + ".jpg" - - save_image(data, save_path,normalize=True) - print("done!") - -if __name__=='__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--txt_path', type=str, required=True) - parser.add_argument('--infer_results_path', type=str, required=True) - args = parser.parse_args() - main(args) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 argparse +import torch +import numpy as np +import os +from torchvision.utils import save_image + +def read_bin(filename): + + data = np.fromfile(filename,dtype=np.float32) + data = torch.Tensor(data) + data = data.view(-1,1,28,28) + return data + +def main(args): + old_path = os.listdir(args.txt_path) + os.makedirs(args.infer_results_path, exist_ok=True) + old_path.sort(reverse=True) + new_path = args.txt_path+'/'+old_path[0] + files = os.listdir(new_path) + for file in files: + filename = new_path + '/' + file + data = read_bin(filename) + if file[1]!='_': + save_path = args.infer_results_path + '/' + file[:2] + ".jpg" + else: + save_path = args.infer_results_path + '/' + file[0] + ".jpg" + + save_image(data, save_path,normalize=True) + print("done!") + +if __name__=='__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--txt_path', type=str, required=True) + parser.add_argument('--infer_results_path', type=str, required=True) + args = parser.parse_args() + main(args) diff --git a/ACL_PyTorch/contrib/cv/gan/GAN/LICENSE b/ACL_PyTorch/contrib/cv/gan/GAN/LICENSE index 29f81d812f..261eeb9e9f 100644 --- a/ACL_PyTorch/contrib/cv/gan/GAN/LICENSE +++ b/ACL_PyTorch/contrib/cv/gan/GAN/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/ACL_PyTorch/contrib/cv/gan/GAN/README.md b/ACL_PyTorch/contrib/cv/gan/GAN/README.md index db252fc460..0d61509917 100644 --- a/ACL_PyTorch/contrib/cv/gan/GAN/README.md +++ b/ACL_PyTorch/contrib/cv/gan/GAN/README.md @@ -1,222 +1,222 @@ -## GAN Onnx模型PyTorch端到端推理指导 - -### 1 模型概述 - -#### 1.1 论文地址 - -[GAN论文](https://arxiv.org/abs/1406.2661) - - - -#### 1.2 代码地址 - -[GAN代码](https://github.com/eriklindernoren/PyTorch-GAN/blob/master/implementations/gan/gan.py) - - - -### 2 环境说明 - -#### 2.1 深度学习框架 - -``` -CANN 5.0.2 -pytorch = 1.6.0 -torchvision = 0.6.0 -onnx = 1.8.0 -``` - - - -#### 2.2 python第三方库 - -``` -numpy == 1.21.1 -``` - -**说明:** - -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - - - -### 3 模型转换 - -#### 3.1 pth转onnx模型 - -1. 下载pth权重文件 - - [GAN预训练pth权重文件](https://wws.lanzoui.com/ikXFJvljkab) - 解压至当前工作目录 - - - - -2. 编写pth2onnx脚本GAN_pth2onnx.py - - -3. 执行pth2onnx脚本,生成onnx模型文件 - - ```py - python3.7 GAN_pth2onnx.py --input_file=generator_8p_0.0008_128.pth --output_file=GAN.onnx - ``` - - - -#### 3.2 onnx转om模型 - -1. 设置环境变量 - - ``` - source set_env.sh - ``` - -2. 使用atc将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.1 开发辅助工具指南 (推理) 01 - - ``` - atc --model=GAN.onnx --framework=5 --output=GAN_bs1 --input_format=NCHW --input_shape="Z:1,100" --log=error --soc_version=Ascend310 - ``` - 通过调节input_shape的第一个参数为16,64可以生成bs为16,64的om文件 - -### 4 数据准备 - -#### 4.1 生成输入数据并保存为.bin文件 -由于源代码中未提供测试数据,这里调用GAN_testdata.py来生成测试数据,保存在/vectors文件夹下 - ``` - python3.7 GAN_testdata.py --online_path=images --offline_path=vectors --pth_path=generator_8p_0.0008_128.pth --iters 100 --batch_size 64 - ``` - - - -### 5 离线推理 - -#### 5.1 msame工具概述 - -msame工具为华为自研的模型推理工具,输入.om模型和模型所需要的输入bin文件,输出模型的输出数据文件,支持多次推理(指对同一输入数据进行推理)。 - -模型必须是通过atc工具转换的om模型,输入bin文件需要符合模型的输入要求(支持模型多输入)。 - - - -#### 5.2 离线推理 - -``` -./msame --model "GAN_bs64.om" --input "./vectors" --output "out" -``` - -输出结果默认保存在当前目录out/下,为保存模型输入tensor数据的txt文件 - - - -### 6 精度对比 - -#### 6.1 离线推理精度 - -调用GAN_txt2jpg.py来进行后处理 - -```python -python3.7 GAN_txt2jpg.py --txt_path=out --infer_results_path=genimg -``` - -详细的结果输出在genimg文件夹中,可以和images文件夹下的在线推理结果做对比,看得出离线推理生成的图片质量更好 - - -#### 6.2 精度对比 - -源码中未有精度对比部分,这里以两种不同的方式对同一输入的输出结果对比为准。 - - - -### 7 性能对比 - -#### 7.1 npu性能数据 -运行下列命令 - -``` -source env.sh -atc --model=GAN.onnx --framework=5 --output=GAN_bs1 --input_format=NCHW --input_shape="Z:1,100" --log=error --soc_version=Ascend310 -``` - -得到size为1*100的om模型 - - - -**msame工具在整个数据集上推理获得性能数据** - -batch1的性能 - -``` -Inference average time : 0.43 ms -Inference average time without first time: 0.43 ms -``` - -Inference average time : 0.43 ms,1000/(0.43/4)既是batch1 310单卡吞吐率 - -bs1 310单卡吞吐率:9302.326fps - -batch16的性能 - -``` -Inference average time : 0.47 ms -Inference average time without first time: 0.47 ms -``` - -Inference average time : 0.51 ms,1000/(0.45/64)既是batch16 310单卡吞吐率 - -bs16 310单卡吞吐率:136170.213fps - -#### 7.2 T4性能数据 - -在装有T4卡的服务器上使用TensorRT测试gpu性能,测试过程请确保卡没有运行其他任务。 - -batch1性能: - -``` -./trtexec --onnx=GAN.onnx --fp16 --shapes=image:1x100 -``` - -gpu T4是4个device并行执行的结果,mean是时延(tensorrt的时延是batch个数据的推理时间),即吞吐率的倒数乘以batch - -``` -[11/11/2021-13:11:22] [I] min: 0.048584 ms -[11/11/2021-13:11:22] [I] max: 4.11572 ms -[11/11/2021-13:11:22] [I] median: 0.0817871 ms -[11/11/2021-13:11:22] [I] GPU Compute -[11/11/2021-13:11:22] [I] min: 0.048584 ms -[11/11/2021-13:11:22] [I] max: 4.13281 ms -[11/11/2021-13:11:22] [I] mean: 0.0826078 ms -[11/11/2021-13:11:22] [I] median: 0.0856934 ms -[11/11/2021-13:11:22] [I] percentile: 0.118164 ms at 99% -[11/11/2021-13:11:22] [I] total compute time: 1.82233 s -``` - -batch1 t4单卡吞吐率:1000/(0.0826078/1)=12105.394fps - -batch16性能: -``` -./trtexec --onnx=GAN.onnx --fp16 --shapes=image:1x100 -``` - -``` -[11/11/2021-13:18:27] [I] min: 0.0540771 ms -[11/11/2021-13:18:27] [I] max: 5.42334 ms -[11/11/2021-13:18:27] [I] median: 0.0800781 ms -[11/11/2021-13:18:27] [I] GPU Compute -[11/11/2021-13:18:27] [I] min: 0.0499878 ms -[11/11/2021-13:18:27] [I] max: 5.44055 ms -[11/11/2021-13:18:27] [I] mean: 0.0887248 ms -[11/11/2021-13:18:27] [I] median: 0.0830078 ms -[11/11/2021-13:18:27] [I] percentile: 0.145508 ms at 99% -[11/11/2021-13:18:27] [I] total compute time: 1.91122 s -``` - -batch16 t4单卡吞吐率:1000/(0.0887248/1)=180332.895fps - -#### 7.3 性能对比 - -batch1:8510.638fps > 12105.394×0.5 fps - -batch16:125490.196fps > 180332.895×0.5 fps - +## GAN Onnx模型PyTorch端到端推理指导 + +### 1 模型概述 + +#### 1.1 论文地址 + +[GAN论文](https://arxiv.org/abs/1406.2661) + + + +#### 1.2 代码地址 + +[GAN代码](https://github.com/eriklindernoren/PyTorch-GAN/blob/master/implementations/gan/gan.py) + + + +### 2 环境说明 + +#### 2.1 深度学习框架 + +``` +CANN 5.0.2 +pytorch = 1.6.0 +torchvision = 0.6.0 +onnx = 1.8.0 +``` + + + +#### 2.2 python第三方库 + +``` +numpy == 1.21.1 +``` + +**说明:** + +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + + + +### 3 模型转换 + +#### 3.1 pth转onnx模型 + +1. 下载pth权重文件 + + [GAN预训练pth权重文件](https://wws.lanzoui.com/ikXFJvljkab) + 解压至当前工作目录 + + + + +2. 编写pth2onnx脚本GAN_pth2onnx.py + + +3. 执行pth2onnx脚本,生成onnx模型文件 + + ```py + python3.7 GAN_pth2onnx.py --input_file=generator_8p_0.0008_128.pth --output_file=GAN.onnx + ``` + + + +#### 3.2 onnx转om模型 + +1. 设置环境变量 + + ``` + source set_env.sh + ``` + +2. 使用atc将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.1 开发辅助工具指南 (推理) 01 + + ``` + atc --model=GAN.onnx --framework=5 --output=GAN_bs1 --input_format=NCHW --input_shape="Z:1,100" --log=error --soc_version=Ascend310 + ``` + 通过调节input_shape的第一个参数为16,64可以生成bs为16,64的om文件 + +### 4 数据准备 + +#### 4.1 生成输入数据并保存为.bin文件 +由于源代码中未提供测试数据,这里调用GAN_testdata.py来生成测试数据,保存在/vectors文件夹下 + ``` + python3.7 GAN_testdata.py --online_path=images --offline_path=vectors --pth_path=generator_8p_0.0008_128.pth --iters 100 --batch_size 64 + ``` + + + +### 5 离线推理 + +#### 5.1 msame工具概述 + +msame工具为华为自研的模型推理工具,输入.om模型和模型所需要的输入bin文件,输出模型的输出数据文件,支持多次推理(指对同一输入数据进行推理)。 + +模型必须是通过atc工具转换的om模型,输入bin文件需要符合模型的输入要求(支持模型多输入)。 + + + +#### 5.2 离线推理 + +``` +./msame --model "GAN_bs64.om" --input "./vectors" --output "out" +``` + +输出结果默认保存在当前目录out/下,为保存模型输入tensor数据的txt文件 + + + +### 6 精度对比 + +#### 6.1 离线推理精度 + +调用GAN_txt2jpg.py来进行后处理 + +```python +python3.7 GAN_txt2jpg.py --txt_path=out --infer_results_path=genimg +``` + +详细的结果输出在genimg文件夹中,可以和images文件夹下的在线推理结果做对比,看得出离线推理生成的图片质量更好 + + +#### 6.2 精度对比 + +源码中未有精度对比部分,这里以两种不同的方式对同一输入的输出结果对比为准。 + + + +### 7 性能对比 + +#### 7.1 npu性能数据 +运行下列命令 + +``` +source env.sh +atc --model=GAN.onnx --framework=5 --output=GAN_bs1 --input_format=NCHW --input_shape="Z:1,100" --log=error --soc_version=Ascend310 +``` + +得到size为1*100的om模型 + + + +**msame工具在整个数据集上推理获得性能数据** + +batch1的性能 + +``` +Inference average time : 0.43 ms +Inference average time without first time: 0.43 ms +``` + +Inference average time : 0.43 ms,1000/(0.43/4)既是batch1 310单卡吞吐率 + +bs1 310单卡吞吐率:9302.326fps + +batch16的性能 + +``` +Inference average time : 0.47 ms +Inference average time without first time: 0.47 ms +``` + +Inference average time : 0.51 ms,1000/(0.45/64)既是batch16 310单卡吞吐率 + +bs16 310单卡吞吐率:136170.213fps + +#### 7.2 T4性能数据 + +在装有T4卡的服务器上使用TensorRT测试gpu性能,测试过程请确保卡没有运行其他任务。 + +batch1性能: + +``` +./trtexec --onnx=GAN.onnx --fp16 --shapes=image:1x100 +``` + +gpu T4是4个device并行执行的结果,mean是时延(tensorrt的时延是batch个数据的推理时间),即吞吐率的倒数乘以batch + +``` +[11/11/2021-13:11:22] [I] min: 0.048584 ms +[11/11/2021-13:11:22] [I] max: 4.11572 ms +[11/11/2021-13:11:22] [I] median: 0.0817871 ms +[11/11/2021-13:11:22] [I] GPU Compute +[11/11/2021-13:11:22] [I] min: 0.048584 ms +[11/11/2021-13:11:22] [I] max: 4.13281 ms +[11/11/2021-13:11:22] [I] mean: 0.0826078 ms +[11/11/2021-13:11:22] [I] median: 0.0856934 ms +[11/11/2021-13:11:22] [I] percentile: 0.118164 ms at 99% +[11/11/2021-13:11:22] [I] total compute time: 1.82233 s +``` + +batch1 t4单卡吞吐率:1000/(0.0826078/1)=12105.394fps + +batch16性能: +``` +./trtexec --onnx=GAN.onnx --fp16 --shapes=image:1x100 +``` + +``` +[11/11/2021-13:18:27] [I] min: 0.0540771 ms +[11/11/2021-13:18:27] [I] max: 5.42334 ms +[11/11/2021-13:18:27] [I] median: 0.0800781 ms +[11/11/2021-13:18:27] [I] GPU Compute +[11/11/2021-13:18:27] [I] min: 0.0499878 ms +[11/11/2021-13:18:27] [I] max: 5.44055 ms +[11/11/2021-13:18:27] [I] mean: 0.0887248 ms +[11/11/2021-13:18:27] [I] median: 0.0830078 ms +[11/11/2021-13:18:27] [I] percentile: 0.145508 ms at 99% +[11/11/2021-13:18:27] [I] total compute time: 1.91122 s +``` + +batch16 t4单卡吞吐率:1000/(0.0887248/1)=180332.895fps + +#### 7.3 性能对比 + +batch1:8510.638fps > 12105.394×0.5 fps + +batch16:125490.196fps > 180332.895×0.5 fps + 性能达到基准线一半 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/gan/GAN/models.py b/ACL_PyTorch/contrib/cv/gan/GAN/models.py index 54b22a3456..27da51bc82 100644 --- a/ACL_PyTorch/contrib/cv/gan/GAN/models.py +++ b/ACL_PyTorch/contrib/cv/gan/GAN/models.py @@ -1,67 +1,67 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 torch.nn as nn -import numpy as np - -channels = 1 -image_size = 28 -img_shape =(channels,image_size,image_size) -latent_dim = 100 - -class Generator(nn.Module): - def __init__(self): - super(Generator, self).__init__() - - def block(in_feat, out_feat, normalize=True): - layers = [nn.Linear(in_feat, out_feat)] - if normalize: - layers.append(nn.BatchNorm1d(out_feat, 0.8)) - layers.append(nn.LeakyReLU(0.2, inplace=True)) - return layers - - self.model = nn.Sequential( - *block(latent_dim, 128, normalize=False), - *block(128, 256), - *block(256, 512), - *block(512, 1024), - nn.Linear(1024, int(np.prod(img_shape))), - nn.Tanh() - ) - - def forward(self, z): - img = self.model(z) - img = img.view(img.size(0), *img_shape) - return img - -class Discriminator(nn.Module): - def __init__(self): - super(Discriminator, self).__init__() - - self.model = nn.Sequential( - nn.Linear(int(np.prod(img_shape)), 512), - nn.LeakyReLU(0.2, inplace=True), - nn.Linear(512, 256), - nn.LeakyReLU(0.2, inplace=True), - nn.Linear(256, 1), - nn.Sigmoid(), - ) - - def forward(self, img): - img_flat = img.view(img.size(0), -1) - validity = self.model(img_flat) - - return validity - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 torch.nn as nn +import numpy as np + +channels = 1 +image_size = 28 +img_shape =(channels,image_size,image_size) +latent_dim = 100 + +class Generator(nn.Module): + def __init__(self): + super(Generator, self).__init__() + + def block(in_feat, out_feat, normalize=True): + layers = [nn.Linear(in_feat, out_feat)] + if normalize: + layers.append(nn.BatchNorm1d(out_feat, 0.8)) + layers.append(nn.LeakyReLU(0.2, inplace=True)) + return layers + + self.model = nn.Sequential( + *block(latent_dim, 128, normalize=False), + *block(128, 256), + *block(256, 512), + *block(512, 1024), + nn.Linear(1024, int(np.prod(img_shape))), + nn.Tanh() + ) + + def forward(self, z): + img = self.model(z) + img = img.view(img.size(0), *img_shape) + return img + +class Discriminator(nn.Module): + def __init__(self): + super(Discriminator, self).__init__() + + self.model = nn.Sequential( + nn.Linear(int(np.prod(img_shape)), 512), + nn.LeakyReLU(0.2, inplace=True), + nn.Linear(512, 256), + nn.LeakyReLU(0.2, inplace=True), + nn.Linear(256, 1), + nn.Sigmoid(), + ) + + def forward(self, img): + img_flat = img.view(img.size(0), -1) + validity = self.model(img_flat) + + return validity + + diff --git a/ACL_PyTorch/contrib/cv/gan/GAN/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/gan/GAN/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/ACL_PyTorch/contrib/cv/gan/GAN/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/gan/GAN/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/gan/GAN/requirements.txt b/ACL_PyTorch/contrib/cv/gan/GAN/requirements.txt index 2b2fefefa7..63dcbcfad8 100644 --- a/ACL_PyTorch/contrib/cv/gan/GAN/requirements.txt +++ b/ACL_PyTorch/contrib/cv/gan/GAN/requirements.txt @@ -1,4 +1,4 @@ -torch == 1.5.0 -torchvision == 0.6.0 -onnx == 1.8.0 -numpy == 1.21.1 +torch == 1.5.0 +torchvision == 0.6.0 +onnx == 1.8.0 +numpy == 1.21.1 diff --git a/ACL_PyTorch/contrib/cv/gan/GAN/test/README.md b/ACL_PyTorch/contrib/cv/gan/GAN/test/README.md index d86591ab67..85ca35df04 100644 --- a/ACL_PyTorch/contrib/cv/gan/GAN/test/README.md +++ b/ACL_PyTorch/contrib/cv/gan/GAN/test/README.md @@ -1,38 +1,38 @@ -## GAN模型PyTorch离线推理指导 - -### 1 环境准备 - -1. 安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 - - ```python - pip3.7 install -r requirements.txt - ``` - -2. 数据集获取 - - 开源代码仓[点此进入](https://github.com/eriklindernoren/PyTorch-GAN/blob/master/implementations/gan/gan.py)没有提供模型测试相关的数据集和代码,这里采用自己设置的随机张量来测试模型的生成精度。 - - -3. 获取msame工具 - - 将编译好的msame工具放到当前目录 - -### 2 离线推理 - -310上执行,执行时使用npu-smi info查看设备状态,确保device空闲 - -``` -bash test/pth2om.sh -bash test/eval_acc.sh -bash test/eval_bs1_perf.sh -bash test/eval_bs16_perf.sh -``` - - - -**评测结果:** - -| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | -| :-----: | :---------: | :-------------: | :--------: | :-------: | -| GAN bs1 | - | - | fps:12105.394 | fps: 9302.326| -| GAN bs16 |- | - | fps:180332.895|fps: 136170.213| +## GAN模型PyTorch离线推理指导 + +### 1 环境准备 + +1. 安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 + + ```python + pip3.7 install -r requirements.txt + ``` + +2. 数据集获取 + + 开源代码仓[点此进入](https://github.com/eriklindernoren/PyTorch-GAN/blob/master/implementations/gan/gan.py)没有提供模型测试相关的数据集和代码,这里采用自己设置的随机张量来测试模型的生成精度。 + + +3. 获取msame工具 + + 将编译好的msame工具放到当前目录 + +### 2 离线推理 + +310上执行,执行时使用npu-smi info查看设备状态,确保device空闲 + +``` +bash test/pth2om.sh +bash test/eval_acc.sh +bash test/eval_bs1_perf.sh +bash test/eval_bs16_perf.sh +``` + + + +**评测结果:** + +| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | +| :-----: | :---------: | :-------------: | :--------: | :-------: | +| GAN bs1 | - | - | fps:12105.394 | fps: 9302.326| +| GAN bs16 |- | - | fps:180332.895|fps: 136170.213| diff --git a/ACL_PyTorch/contrib/cv/gan/Pix2Pix/README.md b/ACL_PyTorch/contrib/cv/gan/Pix2Pix/README.md index 7708fbc2e5..e2a449f73c 100644 --- a/ACL_PyTorch/contrib/cv/gan/Pix2Pix/README.md +++ b/ACL_PyTorch/contrib/cv/gan/Pix2Pix/README.md @@ -1,35 +1,35 @@ -# Pix2Pix - - -# 精度性能 - - | 模型 | 性能基准 | 310性能 | - | :------: | :------: | :------: | - | fsaf bs1 | 556 | 402 | - | fsaf bs16| 359 | 464 | -精度直接看生成效果 - - -# 自验报告 - - # 第1次验收测试 - # 验收结果 OK - # 验收环境: A + K / CANN 5.0.2 - - - # pth是否能正确转换为om - bash ./test/pth2om.sh --pth_path=./checkpoints/facades_label2photo_pretrained - # 验收结果: OK - # 备注: 成功生成om,无运行报错,报错日志xx 等 - - # 精度数据是否达标(需要显示官网pth精度与om模型的精度) - # npu性能数据(确保device空闲时测试,如果模型支持多batch,测试bs1与bs16,否则只测试bs1,性能数据以单卡吞吐率为标准) - bash ./test/eval_acc_perf.sh --datasets_path='./datasets/facades' - # 验收结果: 是 - # 备注: 验收310测试性能bs1:402FPS bs16:464FPS;无运行报错,报错日志xx 等 - - - # 310性能是否超过基准: 是 - bs1:310=402/556=0.723倍基准 - bs16:310=464/359=1.292倍基准 - +# Pix2Pix + + +# 精度性能 + + | 模型 | 性能基准 | 310性能 | + | :------: | :------: | :------: | + | fsaf bs1 | 556 | 402 | + | fsaf bs16| 359 | 464 | +精度直接看生成效果 + + +# 自验报告 + + # 第1次验收测试 + # 验收结果 OK + # 验收环境: A + K / CANN 5.0.2 + + + # pth是否能正确转换为om + bash ./test/pth2om.sh --pth_path=./checkpoints/facades_label2photo_pretrained + # 验收结果: OK + # 备注: 成功生成om,无运行报错,报错日志xx 等 + + # 精度数据是否达标(需要显示官网pth精度与om模型的精度) + # npu性能数据(确保device空闲时测试,如果模型支持多batch,测试bs1与bs16,否则只测试bs1,性能数据以单卡吞吐率为标准) + bash ./test/eval_acc_perf.sh --datasets_path='./datasets/facades' + # 验收结果: 是 + # 备注: 验收310测试性能bs1:402FPS bs16:464FPS;无运行报错,报错日志xx 等 + + + # 310性能是否超过基准: 是 + bs1:310=402/556=0.723倍基准 + bs16:310=464/359=1.292倍基准 + diff --git a/ACL_PyTorch/contrib/cv/gan/Pix2Pix/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/gan/Pix2Pix/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/ACL_PyTorch/contrib/cv/gan/Pix2Pix/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/gan/Pix2Pix/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/gan/Pix2Pix/precision.py b/ACL_PyTorch/contrib/cv/gan/Pix2Pix/precision.py index c14e8e8abc..99dc500223 100644 --- a/ACL_PyTorch/contrib/cv/gan/Pix2Pix/precision.py +++ b/ACL_PyTorch/contrib/cv/gan/Pix2Pix/precision.py @@ -1,198 +1,198 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -# Copyright (c) Soumith Chintala 2016, -# All rights reserved -# -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -# -*- coding: utf-8 -*- -"""用于精度比对 -""" - -import torch -import torch.nn as nn -import torchvision -import apex -from apex import amp -import copy -from models import networks - -##### 需自行改写部分 start ##### -# 获得模型 -def get_model(): - model = networks.define_G(3, 3, 64, 'unet_256', 'instance', - True, 'normal', 0.02, '[0]') - # model = networks.define_D(6, 64, 'basic', - # 3, 'instance','normal', 0.02, '[0]') - # 用于避免BN或者Dropout带来的影响,如果遇到无法evalbackward的现象,请注掉该行 - # model.eval() - - return model - -# 获得输入tensor -input_tensor = torch.randn(1, 3, 256, 256) -# input_tensor = torch.randn(1, 6, 256, 256) - -# 设置npu_device -npu_device = 'npu:0' - -# 设置amp -AMP_MODE = True - -# 设置NPU prof 文件输出 -NPU_PROF = True - -##### 需自行改写部分 end ##### - -def cri_func(x): - base_func = nn.CrossEntropyLoss() - shape_list = x.shape - N = shape_list[0] - R = 1 - if len(shape_list) > 1: - for r in shape_list[1:]: - R *= r - T = torch.randint(0,R, size=(N,)).to(x.device) - if str(T.device).startswith('npu'): - T = T.int() - return base_func(x.reshape(N, -1), T) - -# 设置hook -def hook_func(name, save_dict, module): - def hook_function(module, inputs, outputs): - inputs_key = name + '_inputs' - idx = 0 - while inputs_key in save_dict: - inputs_key = inputs_key.split('-')[0] + '-%d'%idx - idx +=1 - save_dict[inputs_key] = inputs - - outputs_key = name + '_outputs' - idx = 0 - while outputs_key in save_dict: - outputs_key = outputs_key.split('-')[0] + '-%d'%idx - idx +=1 - save_dict[outputs_key] = outputs - return hook_function - -##### CPU ##### -# CPU固定输入和权重 -model = get_model() -optimizer = torch.optim.SGD(model.parameters(), 0.1) -state_dict = copy.deepcopy(model.state_dict()) - -# CPU注册hook,cpu_dict用于存储对比对象 -cpu_dict = {} -for name, module in model.named_modules(): - module.register_forward_hook(hook_func('[forward]:' + name, cpu_dict, module)) - module.register_backward_hook(hook_func('[backward]:' + name, cpu_dict, module)) - -# CPU运行正反向,获取正反向每个module的输入输出和所有参数的grad -out = model(input_tensor) -loss = cri_func(out) -optimizer.zero_grad() -loss.backward() -optimizer.step() -for name, param in model.named_parameters(): - cpu_dict["[grad]:" + name] = param.grad - -##### NPU ##### -# 重新定义模型,清理模型状态,并加装权重,保持初始化一致 -model = get_model() -optimizer = torch.optim.SGD(model.parameters(), 0.1) -model.load_state_dict(state_dict) - -# NPU注册hook,npu_dict用于存储对比对象 -npu_dict = {} -for name, module in model.named_modules(): - module.register_forward_hook(hook_func('[forward]:' + name, npu_dict, module)) - module.register_backward_hook(hook_func('[backward]:' + name, npu_dict, module)) - -# 将model和input_tensor放到npu -torch.npu.set_device(npu_device) -model = model.npu() -input_tensor = input_tensor.npu() - -# amp可选项,不适用请注释 -if AMP_MODE: - optimizer = apex.optimizers.NpuFusedSGD(model.parameters(), 0.1) - model, optimizer = amp.initialize(model, optimizer, opt_level='O2', loss_scale=1.0, combine_grad=True) - -# NPU运行正反向,获取正反向每个module的输入输出和所有参数的grad -out = model(input_tensor) -loss = cri_func(out) -optimizer.zero_grad() -if AMP_MODE: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() -else: - loss.backward() -optimizer.step() -for name, param in model.named_parameters(): - npu_dict["[grad]:" + name] = param.grad - - -##### ComPare ##### -# 递归得到对比值 -def compare(x1, x2, prefix=''): - if isinstance(x1, tuple): - if x1: - for idx in range(len(x1)): - try: - compare(x1[idx], x2[idx], prefix=prefix + '.%d' % idx) - except Exception as e: - # print(str(e)) - print(prefix, 'failed.') - elif isinstance(x1, torch.Tensor) and isinstance(x2, torch.Tensor): - try: - l1_error = (x1.half().float() - x2.cpu()).abs().mean() - rel_error = l1_error / (x1.abs().mean()) - print(prefix, 'l1_error: ', l1_error, 'rel_error', rel_error) - if l1_error * rel_error > 10 : - print('\n###\n',prefix, 'should checked!','\n###\n') - except Exception as e: - # print(str(e)) - print(prefix, 'failed.') - -for k in cpu_dict: - compare(cpu_dict[k], npu_dict[k], prefix=k) - -# 需要profiling的时候额外输出一次 -if NPU_PROF: - with torch.autograd.profiler.profile(use_npu=True) as prof: - out = model(input_tensor) - loss = cri_func(out) - optimizer.zero_grad() - if AMP_MODE: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.step() - prof.export_chrome_trace("netD output.prof") # "output.prof"为输出文件地址 - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +# Copyright (c) Soumith Chintala 2016, +# All rights reserved +# +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +# -*- coding: utf-8 -*- +"""用于精度比对 +""" + +import torch +import torch.nn as nn +import torchvision +import apex +from apex import amp +import copy +from models import networks + +##### 需自行改写部分 start ##### +# 获得模型 +def get_model(): + model = networks.define_G(3, 3, 64, 'unet_256', 'instance', + True, 'normal', 0.02, '[0]') + # model = networks.define_D(6, 64, 'basic', + # 3, 'instance','normal', 0.02, '[0]') + # 用于避免BN或者Dropout带来的影响,如果遇到无法evalbackward的现象,请注掉该行 + # model.eval() + + return model + +# 获得输入tensor +input_tensor = torch.randn(1, 3, 256, 256) +# input_tensor = torch.randn(1, 6, 256, 256) + +# 设置npu_device +npu_device = 'npu:0' + +# 设置amp +AMP_MODE = True + +# 设置NPU prof 文件输出 +NPU_PROF = True + +##### 需自行改写部分 end ##### + +def cri_func(x): + base_func = nn.CrossEntropyLoss() + shape_list = x.shape + N = shape_list[0] + R = 1 + if len(shape_list) > 1: + for r in shape_list[1:]: + R *= r + T = torch.randint(0,R, size=(N,)).to(x.device) + if str(T.device).startswith('npu'): + T = T.int() + return base_func(x.reshape(N, -1), T) + +# 设置hook +def hook_func(name, save_dict, module): + def hook_function(module, inputs, outputs): + inputs_key = name + '_inputs' + idx = 0 + while inputs_key in save_dict: + inputs_key = inputs_key.split('-')[0] + '-%d'%idx + idx +=1 + save_dict[inputs_key] = inputs + + outputs_key = name + '_outputs' + idx = 0 + while outputs_key in save_dict: + outputs_key = outputs_key.split('-')[0] + '-%d'%idx + idx +=1 + save_dict[outputs_key] = outputs + return hook_function + +##### CPU ##### +# CPU固定输入和权重 +model = get_model() +optimizer = torch.optim.SGD(model.parameters(), 0.1) +state_dict = copy.deepcopy(model.state_dict()) + +# CPU注册hook,cpu_dict用于存储对比对象 +cpu_dict = {} +for name, module in model.named_modules(): + module.register_forward_hook(hook_func('[forward]:' + name, cpu_dict, module)) + module.register_backward_hook(hook_func('[backward]:' + name, cpu_dict, module)) + +# CPU运行正反向,获取正反向每个module的输入输出和所有参数的grad +out = model(input_tensor) +loss = cri_func(out) +optimizer.zero_grad() +loss.backward() +optimizer.step() +for name, param in model.named_parameters(): + cpu_dict["[grad]:" + name] = param.grad + +##### NPU ##### +# 重新定义模型,清理模型状态,并加装权重,保持初始化一致 +model = get_model() +optimizer = torch.optim.SGD(model.parameters(), 0.1) +model.load_state_dict(state_dict) + +# NPU注册hook,npu_dict用于存储对比对象 +npu_dict = {} +for name, module in model.named_modules(): + module.register_forward_hook(hook_func('[forward]:' + name, npu_dict, module)) + module.register_backward_hook(hook_func('[backward]:' + name, npu_dict, module)) + +# 将model和input_tensor放到npu +torch.npu.set_device(npu_device) +model = model.npu() +input_tensor = input_tensor.npu() + +# amp可选项,不适用请注释 +if AMP_MODE: + optimizer = apex.optimizers.NpuFusedSGD(model.parameters(), 0.1) + model, optimizer = amp.initialize(model, optimizer, opt_level='O2', loss_scale=1.0, combine_grad=True) + +# NPU运行正反向,获取正反向每个module的输入输出和所有参数的grad +out = model(input_tensor) +loss = cri_func(out) +optimizer.zero_grad() +if AMP_MODE: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() +else: + loss.backward() +optimizer.step() +for name, param in model.named_parameters(): + npu_dict["[grad]:" + name] = param.grad + + +##### ComPare ##### +# 递归得到对比值 +def compare(x1, x2, prefix=''): + if isinstance(x1, tuple): + if x1: + for idx in range(len(x1)): + try: + compare(x1[idx], x2[idx], prefix=prefix + '.%d' % idx) + except Exception as e: + # print(str(e)) + print(prefix, 'failed.') + elif isinstance(x1, torch.Tensor) and isinstance(x2, torch.Tensor): + try: + l1_error = (x1.half().float() - x2.cpu()).abs().mean() + rel_error = l1_error / (x1.abs().mean()) + print(prefix, 'l1_error: ', l1_error, 'rel_error', rel_error) + if l1_error * rel_error > 10 : + print('\n###\n',prefix, 'should checked!','\n###\n') + except Exception as e: + # print(str(e)) + print(prefix, 'failed.') + +for k in cpu_dict: + compare(cpu_dict[k], npu_dict[k], prefix=k) + +# 需要profiling的时候额外输出一次 +if NPU_PROF: + with torch.autograd.profiler.profile(use_npu=True) as prof: + out = model(input_tensor) + loss = cri_func(out) + optimizer.zero_grad() + if AMP_MODE: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + optimizer.step() + prof.export_chrome_trace("netD output.prof") # "output.prof"为输出文件地址 + + diff --git a/ACL_PyTorch/contrib/cv/gan/Pix2Pix/pytorch_prof.py b/ACL_PyTorch/contrib/cv/gan/Pix2Pix/pytorch_prof.py index afb06b4b97..d79a619de9 100644 --- a/ACL_PyTorch/contrib/cv/gan/Pix2Pix/pytorch_prof.py +++ b/ACL_PyTorch/contrib/cv/gan/Pix2Pix/pytorch_prof.py @@ -1,141 +1,141 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -# Copyright (c) Soumith Chintala 2016, -# All rights reserved -# -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -# -*- coding: utf-8 -*- -"""pytorch_prof.py -""" - -import torch -import torch.optim as optim -import torch.nn as nn -import time -import argparse -from models import networks - -def build_model(): - # 请自定义模型并加载预训练模型 - # import torchvision - # model = torchvision.models.resnet50(pretrained=True) - model = networks.define_G(3, 3, 64, 'unet_256', 'instance', - True, 'normal', 0.02, '[0]') - return model - - -def get_raw_data(): - # input_tensor = torch.randn(2, 3, 224, 224) - input_tensor = torch.randn(1, 3, 256, 256) - return input_tensor - - -def criterion(x): - base_func = nn.CrossEntropyLoss() - shape_list = x.shape - N = shape_list[0] - R = 1 - if len(shape_list) > 1: - for r in shape_list[1:]: - R *= r - T = torch.randint(0,R, size=(N,)).to(x.device) - if str(T.device).startswith('npu'): - T = T.int() - return base_func(x.reshape(N, -1), T) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='PyTorch Prof') - parser.add_argument('--device', type=str, default='cpu', - help='set which type of device used. Support cuda:0(device_id), npu:0(device_id).') - parser.add_argument('--amp', default=False, action='store_true', - help='use amp during prof') - parser.add_argument('--loss-scale', default=64.0, type=float, - help='loss scale using in amp, default 64.0, -1 means dynamic') - parser.add_argument('--opt-level', default='O2', type=str, - help='opt-level using in amp, default O2') - parser.add_argument('--FusedSGD', default=False, action='store_true', - help='use FusedSGD during prof') - - args = parser.parse_args() - - # 1.准备工作 - if args.device.startswith('cuda'): - torch.cuda.set_device(args.device) - prof_kwargs = {'use_cuda': True} - elif args.device.startswith('npu'): - torch.npu.set_device(args.device) - prof_kwargs = {'use_npu': True} - else: - prof_kwargs = {} - - # 2.构建模型 - model = build_model() - if args.FusedSGD: - from apex.optimizers import NpuFusedSGD - optimizer = NpuFusedSGD(model.parameters(), lr=0.01) - model = model.to(args.device) - if args.amp: - from apex import amp - model, optimizer = amp.initialize(model, optimizer, opt_level=args.opt_level, - loss_scale=None if args.loss_scale == -1 else args.loss_scale, - combine_grad=True) - else: - optimizer = optim.SGD(model.parameters(), lr=0.01) - model = model.to(args.device) - if args.amp: - from apex import amp - model, optimizer = amp.initialize(model, optimizer, opt_level=args.opt_level, - loss_scale=None if args.loss_scale == -1 else args.loss_scale) - - # 3.生成input - input_tensor = get_raw_data() - input_tensor = input_tensor.to(args.device) - - # 先运行一次,保证prof得到的性能是正确的 - def run(): - output_tensor = model(input_tensor) - loss = criterion(output_tensor) - optimizer.zero_grad() - if args.amp: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.step() - return loss - for i in range(5): - start_time = time.time() - loss = run() - print('iter: %d, loss: %.2f, time: %.2f'%(i, loss, (time.time() - start_time)*1000)) - - # 4. 执行forward+profiling - with torch.autograd.profiler.profile(**prof_kwargs) as prof: - run() - print(prof.key_averages().table()) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +# Copyright (c) Soumith Chintala 2016, +# All rights reserved +# +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +# -*- coding: utf-8 -*- +"""pytorch_prof.py +""" + +import torch +import torch.optim as optim +import torch.nn as nn +import time +import argparse +from models import networks + +def build_model(): + # 请自定义模型并加载预训练模型 + # import torchvision + # model = torchvision.models.resnet50(pretrained=True) + model = networks.define_G(3, 3, 64, 'unet_256', 'instance', + True, 'normal', 0.02, '[0]') + return model + + +def get_raw_data(): + # input_tensor = torch.randn(2, 3, 224, 224) + input_tensor = torch.randn(1, 3, 256, 256) + return input_tensor + + +def criterion(x): + base_func = nn.CrossEntropyLoss() + shape_list = x.shape + N = shape_list[0] + R = 1 + if len(shape_list) > 1: + for r in shape_list[1:]: + R *= r + T = torch.randint(0,R, size=(N,)).to(x.device) + if str(T.device).startswith('npu'): + T = T.int() + return base_func(x.reshape(N, -1), T) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='PyTorch Prof') + parser.add_argument('--device', type=str, default='cpu', + help='set which type of device used. Support cuda:0(device_id), npu:0(device_id).') + parser.add_argument('--amp', default=False, action='store_true', + help='use amp during prof') + parser.add_argument('--loss-scale', default=64.0, type=float, + help='loss scale using in amp, default 64.0, -1 means dynamic') + parser.add_argument('--opt-level', default='O2', type=str, + help='opt-level using in amp, default O2') + parser.add_argument('--FusedSGD', default=False, action='store_true', + help='use FusedSGD during prof') + + args = parser.parse_args() + + # 1.准备工作 + if args.device.startswith('cuda'): + torch.cuda.set_device(args.device) + prof_kwargs = {'use_cuda': True} + elif args.device.startswith('npu'): + torch.npu.set_device(args.device) + prof_kwargs = {'use_npu': True} + else: + prof_kwargs = {} + + # 2.构建模型 + model = build_model() + if args.FusedSGD: + from apex.optimizers import NpuFusedSGD + optimizer = NpuFusedSGD(model.parameters(), lr=0.01) + model = model.to(args.device) + if args.amp: + from apex import amp + model, optimizer = amp.initialize(model, optimizer, opt_level=args.opt_level, + loss_scale=None if args.loss_scale == -1 else args.loss_scale, + combine_grad=True) + else: + optimizer = optim.SGD(model.parameters(), lr=0.01) + model = model.to(args.device) + if args.amp: + from apex import amp + model, optimizer = amp.initialize(model, optimizer, opt_level=args.opt_level, + loss_scale=None if args.loss_scale == -1 else args.loss_scale) + + # 3.生成input + input_tensor = get_raw_data() + input_tensor = input_tensor.to(args.device) + + # 先运行一次,保证prof得到的性能是正确的 + def run(): + output_tensor = model(input_tensor) + loss = criterion(output_tensor) + optimizer.zero_grad() + if args.amp: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + optimizer.step() + return loss + for i in range(5): + start_time = time.time() + loss = run() + print('iter: %d, loss: %.2f, time: %.2f'%(i, loss, (time.time() - start_time)*1000)) + + # 4. 执行forward+profiling + with torch.autograd.profiler.profile(**prof_kwargs) as prof: + run() + print(prof.key_averages().table()) prof.export_chrome_trace("pytorch_prof_%s.prof" % args.device) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/gan/Pix2pixHD/datasets_deal.py b/ACL_PyTorch/contrib/cv/gan/Pix2pixHD/datasets_deal.py index 348f334701..1d8b167ef2 100644 --- a/ACL_PyTorch/contrib/cv/gan/Pix2pixHD/datasets_deal.py +++ b/ACL_PyTorch/contrib/cv/gan/Pix2pixHD/datasets_deal.py @@ -1,44 +1,44 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import glob -import shutil - -if __name__ == "__main__": - test_inst_dir = sys.argv[1] - test_label_dir = sys.argv[2] - test_original_gtfine_dir = sys.argv[3] - - if not os.path.exists(test_inst_dir): - os.mkdir(test_inst_dir) - if not os.path.exists(test_label_dir): - os.mkdir(test_label_dir) - - city_name_dir = os.listdir(test_original_gtfine_dir) - img_inst_number = 0 - img_label_number = 0 - - for city_name in city_name_dir: - temp_city_dir = os.path.join(test_original_gtfine_dir, city_name) - test_gtfine_list = glob.glob(os.path.join(temp_city_dir, "*.png")) - - for img in test_gtfine_list: - if img[-9:] == "ceIds.png": - img_inst_number += 1 - shutil.copy(img, test_inst_dir) - elif img[-9:] == "elIds.png": - img_label_number += 1 - shutil.copy(img, test_label_dir) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import glob +import shutil + +if __name__ == "__main__": + test_inst_dir = sys.argv[1] + test_label_dir = sys.argv[2] + test_original_gtfine_dir = sys.argv[3] + + if not os.path.exists(test_inst_dir): + os.mkdir(test_inst_dir) + if not os.path.exists(test_label_dir): + os.mkdir(test_label_dir) + + city_name_dir = os.listdir(test_original_gtfine_dir) + img_inst_number = 0 + img_label_number = 0 + + for city_name in city_name_dir: + temp_city_dir = os.path.join(test_original_gtfine_dir, city_name) + test_gtfine_list = glob.glob(os.path.join(temp_city_dir, "*.png")) + + for img in test_gtfine_list: + if img[-9:] == "ceIds.png": + img_inst_number += 1 + shutil.copy(img, test_inst_dir) + elif img[-9:] == "elIds.png": + img_label_number += 1 + shutil.copy(img, test_label_dir) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/gan/StarGAN/LICENSE b/ACL_PyTorch/contrib/cv/gan/StarGAN/LICENSE index 29f81d812f..261eeb9e9f 100644 --- a/ACL_PyTorch/contrib/cv/gan/StarGAN/LICENSE +++ b/ACL_PyTorch/contrib/cv/gan/StarGAN/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/ACL_PyTorch/contrib/cv/gan/StarGAN/README.md b/ACL_PyTorch/contrib/cv/gan/StarGAN/README.md index 36a385956b..f7f3a13e8f 100644 --- a/ACL_PyTorch/contrib/cv/gan/StarGAN/README.md +++ b/ACL_PyTorch/contrib/cv/gan/StarGAN/README.md @@ -1,160 +1,160 @@ -## StarGAN Onnx 模型 PyTorch 端到端推理指导 - -### 1 模型概述 - -- 论文地址 - -``` -https://arxiv.org/abs/1711.09020 -``` - -- 代码地址 - -``` -https://github.com/yunjey/stargan -``` - -- 数据集地址 - -``` -wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/dataset/celeba.zip -``` - - - -### 2 环境说明 - -``` -CANN = 5.0.2 -pytorch = 1.5.0 -torchvision = 0.6.0 -onnx = 1.8.0 -numpy = 1.21.1 -``` - -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - - - -### 3 pth 转 om 模型 - -- pth 权重文件默认路径为 `./models/200000-G.pth` -- 进入根目录 `./` 执行 `./test/pth2om` 脚本,自动生成生成 onnx 模型文件和om文件 - -```py -bash ./test/pth2om.sh './models/200000-G.pth' -``` - - - -### 4 生成输入数据并保存为.bin文件 - -- 数据集默认路径为 `./celeba.zip` ,使用脚本 `unzip_dataset.sh` 解压数据集。 - -``` -bash unzip_dataset.sh -``` - -- 使用脚本 `StarGAN_pre_processing.py` 获得二进制 bin 文件和基准的图片结果。 - -``` -source ./test/env_npu.sh -python3.7 StarGAN_pre_processing.py --mode test --selected_attrs Black_Hair Blond_Hair Brown_Hair Male Young \ - --model_save_dir './models' --result_dir './result_baseline' \ - --attr_path './data/celeba/images' --celeba_image_dir './data/celeba/list_attr_celeba.txt' -``` - - - -### 5 离线推理 - -#### 5.1 msame工具概述 - -msame 工具为华为自研的模型推理工具,输入 om 模型和模型所需要的输入 bin 文件,输出模型的输出数据文件。模型必须是通过 atc 工具转换的 om 模型,输入 bin 文件需要符合模型的输入要求,且支持模型多输入。 - -``` -chmod 777 msame -``` - -#### 5.2 离线推理 - -``` -bash ./test/eval_bs1_perf.sh -bash ./test/eval_bs16_perf.sh -``` - -输出数据默认保存在根目录的 `./StarGAN_[yourBatchSize].log` 中,可以看到时延和 FPS。输出图片默认保存在当前目录 `output_[yourBatchSize]/` 下,为保存模型输入高维张量数据的 txt 文件。 - - - -### 6 精度对比 - -调用 ` StarGAN_post_processing.py` 来进行后处理,把输出的 txt 文件转换为输出图像。 - -```python -python3.7 StarGAN_post_processing.py --folder_path './output_bs1/[YYYYMMDD_HHMMSS]' --batch_size 1 -python3.7 StarGAN_post_processing.py --folder_path './output_bs16/[YYYYMMDD_HHMMSS]' --batch_size 16 -``` - -详细的结果输出在 `./output_[yourBatchSize]/jpg` 文件夹中,可以和 `result_baseline` 文件夹下的在线推理结果做对比。可以发现各个 batchsize 的离线推理生成的图片与基准基本一致。 - - - -### 7 性能对比 - -#### 7.1 NPU 310 性能数据 -``` -(310 bs1) Inference average time: 21.04 ms -(310 bs1) FPS:190.114 -``` - -根据时延和核心数,计算得到 Batchsize = 1 时单卡吞吐率 190.114 FPS - -``` -(310 bs16) Inference average time: 313.39 ms -(310 bs16) FPS:204.218 -``` - -根据时延和核心数,计算得到 Batchsize = 16 时单卡吞吐率 204.218 FPS - -#### 7.2 GPU T4 性能数据 - -``` -&&&& RUNNING TensorRT.trtexec # trtexec --onnx=StarGAN.onnx --shapes=real_img:1x3x128x128,attr:1x5 -... -[11/10/2021-07:45:57] [I] GPU Compute -[11/10/2021-07:45:57] [I] min: 4.5766 ms -[11/10/2021-07:45:57] [I] max: 8.12921 ms -[11/10/2021-07:45:57] [I] mean: 5.34373 ms -[11/10/2021-07:45:57] [I] median: 5.32825 ms -[11/10/2021-07:45:57] [I] percentile: 6.91772 ms at 99% -[11/10/2021-07:45:57] [I] total compute time: 2.93371 s -``` - -根据时延和核心数,计算得到 Batchsize = 1 时单卡吞吐率 187.135 FPS - -``` -&&&& RUNNING TensorRT.trtexec # trtexec --onnx=StarGAN.onnx --shapes=real_img:16x3x128x128,attr:16x5 -... -[11/10/2021-08:03:49] [I] GPU Compute -[11/10/2021-08:03:49] [I] min: 65.5917 ms -[11/10/2021-08:03:49] [I] max: 76.011 ms -[11/10/2021-08:03:49] [I] mean: 67.8021 ms -[11/10/2021-08:03:49] [I] median: 67.15 ms -[11/10/2021-08:03:49] [I] percentile: 76.011 ms at 99% -[11/10/2021-08:03:49] [I] total compute time: 3.1189 s -``` - -根据时延和核心数,计算得到 Batchsize = 16 时单卡吞吐率 235.980 FPS - -#### 7.3 性能对比 - -| Batch Size | 310 (FPS/Card) | T4 (FPS/Card) | 310/T4 | -| ---------- | -------------- | ------------- | -------- | -| 1 | *189.753* | *187.135* | *101.4%* | -| 4 | *201.207* | *203.666* | *98.80%* | -| 8 | *199.913* | *219.700* | *91.00%* | -| 16 | *200.986* | *235.980* | *85.17%* | - +## StarGAN Onnx 模型 PyTorch 端到端推理指导 + +### 1 模型概述 + +- 论文地址 + +``` +https://arxiv.org/abs/1711.09020 +``` + +- 代码地址 + +``` +https://github.com/yunjey/stargan +``` + +- 数据集地址 + +``` +wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/dataset/celeba.zip +``` + + + +### 2 环境说明 + +``` +CANN = 5.0.2 +pytorch = 1.5.0 +torchvision = 0.6.0 +onnx = 1.8.0 +numpy = 1.21.1 +``` + +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + + + +### 3 pth 转 om 模型 + +- pth 权重文件默认路径为 `./models/200000-G.pth` +- 进入根目录 `./` 执行 `./test/pth2om` 脚本,自动生成生成 onnx 模型文件和om文件 + +```py +bash ./test/pth2om.sh './models/200000-G.pth' +``` + + + +### 4 生成输入数据并保存为.bin文件 + +- 数据集默认路径为 `./celeba.zip` ,使用脚本 `unzip_dataset.sh` 解压数据集。 + +``` +bash unzip_dataset.sh +``` + +- 使用脚本 `StarGAN_pre_processing.py` 获得二进制 bin 文件和基准的图片结果。 + +``` +source ./test/env_npu.sh +python3.7 StarGAN_pre_processing.py --mode test --selected_attrs Black_Hair Blond_Hair Brown_Hair Male Young \ + --model_save_dir './models' --result_dir './result_baseline' \ + --attr_path './data/celeba/images' --celeba_image_dir './data/celeba/list_attr_celeba.txt' +``` + + + +### 5 离线推理 + +#### 5.1 msame工具概述 + +msame 工具为华为自研的模型推理工具,输入 om 模型和模型所需要的输入 bin 文件,输出模型的输出数据文件。模型必须是通过 atc 工具转换的 om 模型,输入 bin 文件需要符合模型的输入要求,且支持模型多输入。 + +``` +chmod 777 msame +``` + +#### 5.2 离线推理 + +``` +bash ./test/eval_bs1_perf.sh +bash ./test/eval_bs16_perf.sh +``` + +输出数据默认保存在根目录的 `./StarGAN_[yourBatchSize].log` 中,可以看到时延和 FPS。输出图片默认保存在当前目录 `output_[yourBatchSize]/` 下,为保存模型输入高维张量数据的 txt 文件。 + + + +### 6 精度对比 + +调用 ` StarGAN_post_processing.py` 来进行后处理,把输出的 txt 文件转换为输出图像。 + +```python +python3.7 StarGAN_post_processing.py --folder_path './output_bs1/[YYYYMMDD_HHMMSS]' --batch_size 1 +python3.7 StarGAN_post_processing.py --folder_path './output_bs16/[YYYYMMDD_HHMMSS]' --batch_size 16 +``` + +详细的结果输出在 `./output_[yourBatchSize]/jpg` 文件夹中,可以和 `result_baseline` 文件夹下的在线推理结果做对比。可以发现各个 batchsize 的离线推理生成的图片与基准基本一致。 + + + +### 7 性能对比 + +#### 7.1 NPU 310 性能数据 +``` +(310 bs1) Inference average time: 21.04 ms +(310 bs1) FPS:190.114 +``` + +根据时延和核心数,计算得到 Batchsize = 1 时单卡吞吐率 190.114 FPS + +``` +(310 bs16) Inference average time: 313.39 ms +(310 bs16) FPS:204.218 +``` + +根据时延和核心数,计算得到 Batchsize = 16 时单卡吞吐率 204.218 FPS + +#### 7.2 GPU T4 性能数据 + +``` +&&&& RUNNING TensorRT.trtexec # trtexec --onnx=StarGAN.onnx --shapes=real_img:1x3x128x128,attr:1x5 +... +[11/10/2021-07:45:57] [I] GPU Compute +[11/10/2021-07:45:57] [I] min: 4.5766 ms +[11/10/2021-07:45:57] [I] max: 8.12921 ms +[11/10/2021-07:45:57] [I] mean: 5.34373 ms +[11/10/2021-07:45:57] [I] median: 5.32825 ms +[11/10/2021-07:45:57] [I] percentile: 6.91772 ms at 99% +[11/10/2021-07:45:57] [I] total compute time: 2.93371 s +``` + +根据时延和核心数,计算得到 Batchsize = 1 时单卡吞吐率 187.135 FPS + +``` +&&&& RUNNING TensorRT.trtexec # trtexec --onnx=StarGAN.onnx --shapes=real_img:16x3x128x128,attr:16x5 +... +[11/10/2021-08:03:49] [I] GPU Compute +[11/10/2021-08:03:49] [I] min: 65.5917 ms +[11/10/2021-08:03:49] [I] max: 76.011 ms +[11/10/2021-08:03:49] [I] mean: 67.8021 ms +[11/10/2021-08:03:49] [I] median: 67.15 ms +[11/10/2021-08:03:49] [I] percentile: 76.011 ms at 99% +[11/10/2021-08:03:49] [I] total compute time: 3.1189 s +``` + +根据时延和核心数,计算得到 Batchsize = 16 时单卡吞吐率 235.980 FPS + +#### 7.3 性能对比 + +| Batch Size | 310 (FPS/Card) | T4 (FPS/Card) | 310/T4 | +| ---------- | -------------- | ------------- | -------- | +| 1 | *189.753* | *187.135* | *101.4%* | +| 4 | *201.207* | *203.666* | *98.80%* | +| 8 | *199.913* | *219.700* | *91.00%* | +| 16 | *200.986* | *235.980* | *85.17%* | + diff --git a/ACL_PyTorch/contrib/cv/gan/StarGAN/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/gan/StarGAN/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/ACL_PyTorch/contrib/cv/gan/StarGAN/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/gan/StarGAN/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/gan/StarGAN/requirements.txt b/ACL_PyTorch/contrib/cv/gan/StarGAN/requirements.txt index bf70cf0b5e..1f9481f7e6 100644 --- a/ACL_PyTorch/contrib/cv/gan/StarGAN/requirements.txt +++ b/ACL_PyTorch/contrib/cv/gan/StarGAN/requirements.txt @@ -1,4 +1,4 @@ -torch==1.5.0 -torchvision==0.6.0 -onnx==1.8.0 -numpy==1.21.1 +torch==1.5.0 +torchvision==0.6.0 +onnx==1.8.0 +numpy==1.21.1 diff --git a/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/CSNLN_postprocess.py b/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/CSNLN_postprocess.py index 3738c2259f..5eb29d03a0 100644 --- a/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/CSNLN_postprocess.py +++ b/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/CSNLN_postprocess.py @@ -1,165 +1,165 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import numpy as np -import os -import argparse -import json -import math -import imageio - -parser = argparse.ArgumentParser(description='CSNLN post process script') -parser.add_argument('--res', default='', type=str, metavar='PATH', - help='om result path') -parser.add_argument('--hr', default='', type=str, metavar='PATH', - help='high res path') -parser.add_argument('--save_path', default='', type=str, metavar='PATH', - help='result image save path') -args = parser.parse_args() - - -with open("pad_info_56.json") as f: - pad_info = json.load(f) -scale = 4 - -def postprocess(hr_src_path, bin_path, save_path): - data = [] - if not os.path.isdir(save_path): - os.makedirs(save_path) - sr_list = merge(bin_path) - files = os.listdir(hr_src_path) - files.sort() - for i, img_file in enumerate(files): - img = sr_list[i] - img = quantize(img, 1) - hr = imageio.imread(os.path.join(hr_src_path, img_file)) - hr = torch.from_numpy(hr) - hr = hr / 255 - psnr = calc_psnr(img, hr, scale, 1) - data.append({"file": img_file, "psnr": psnr}) - - img = (img * 255).byte().cpu() - imageio.imwrite(os.path.join(save_path, img_file+".png"), img.numpy().astype(np.uint8).transpose(1, 2, 0)) - - data = eval_acc(data) - json_data = json.dumps( - data, indent=4, separators=(',', ': ')) - with open("result.json", 'w') as f: - f.write(json_data) - -def eval_acc(data): - acc = 0 - for item in data: - acc += item["psnr"] - acc /= len(data) - print("accuracy: ",acc) - return { - "accuracy": acc, - "data": data - } - - -def quantize(img, rgb_range): - pixel_range = 255 / rgb_range - return img.mul(pixel_range).clamp(0, 255).round().div(pixel_range) - - -def calc_psnr(sr, hr, scale, rgb_range): - sr = sr.unsqueeze(0) - hr = hr.permute(2, 0, 1).unsqueeze(0) - if hr.nelement() == 1: - return 0 - - diff = (sr - hr) / rgb_range - shave = 4 - if diff.size(1) > 1: - gray_coeffs = [65.738, 129.057, 25.064] - convert = diff.new_tensor(gray_coeffs).view(1, 3, 1, 1) / 256 - diff = diff.mul(convert).sum(dim=1) - - valid = diff[..., shave:-shave, shave:-shave] - mse = valid.pow(2).mean() - - return -10 * math.log10(mse) - -def merge(src_path): - min_list = [] - max_list = [] - for i, pad_meta in enumerate(pad_info): - if i % 5 == 0 and i < 16: - max_list.append(pad_meta) - else: - min_list.append(pad_meta) - h_half, w_half = -1, -1 - h_size, w_size = -1, -1 - h, w = -1, -1 - temp_img = None - sr_list = [] - sr = [] - files = os.listdir(src_path) - files.sort() - for i, file in enumerate(files): - array = np.fromfile(os.path.join(src_path, file), dtype=np.float32) - array = array.reshape( - 3, 56*4, 56*4) - img = torch.from_numpy(array) - pad_h, pad_w = min_list[i]['pad_h'], min_list[i]['pad_w'] - if pad_h == 0 and pad_w == 0: - img = img - elif pad_h == 0: - img = img[:, :, 0:-pad_w] - elif pad_w == 0: - img = img[:, 0:-pad_h, :] - else: - img = img[:, 0:-pad_h, 0:-pad_w] - if i % 4 == 0: - h_half, w_half = int(min_list[i]['h_half'] * scale), int(min_list[i]['w_half'] * scale) - h_size, w_size = min_list[i]['h_size'] * scale, min_list[i]['w_size'] * scale - h, w = h_half * 2, w_half * 2 - temp_img = torch.zeros(3, h, w) - temp_img[:, 0:h_half, 0:w_half] = img[:, 0:h_half, 0:w_half] - elif i % 4 == 1: - temp_img[:, 0:h_half, w_half:w] = img[:, 0:h_half, (w_size - w + w_half):w_size] - elif i % 4 == 2: - temp_img[:, h_half:h, 0:w_half] = img[:, (h_size - h + h_half):h_size, 0:w_half] - elif i % 4 == 3: - temp_img[:, h_half:h, w_half:w] = img[:, (h_size - h + h_half):h_size, (w_size - w + w_half):w_size] - sr_list.append(temp_img) - - h_half, w_half = max_list[0]['h_half'] * scale, max_list[0]['w_half'] * scale - h_size, w_size = max_list[0]['h_size'] * scale, max_list[0]['w_size'] * scale - h, w = h_half * 2, w_half * 2 - output = torch.zeros(3, h, w) - output[:, 0:h_half, 0:w_half] \ - = sr_list[0][:, 0:h_half, 0:w_half] - output[:, 0:h_half, w_half:w] \ - = sr_list[1][:, 0:h_half, (w_size - w + w_half):w_size] - output[:, h_half:h, 0:w_half] \ - = sr_list[2][:, (h_size - h + h_half):h_size, 0:w_half] - output[:, h_half:h, w_half:w] \ - = sr_list[3][:, (h_size - h + h_half):h_size, (w_size - w + w_half):w_size] - sr.append(output) - sr.append(sr_list[4]) - sr.append(sr_list[5]) - sr.append(sr_list[6]) - sr.append(sr_list[7]) - return sr - - -if __name__ == '__main__': - res = args.res - hr = args.hr - save_path = args.save_path +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import numpy as np +import os +import argparse +import json +import math +import imageio + +parser = argparse.ArgumentParser(description='CSNLN post process script') +parser.add_argument('--res', default='', type=str, metavar='PATH', + help='om result path') +parser.add_argument('--hr', default='', type=str, metavar='PATH', + help='high res path') +parser.add_argument('--save_path', default='', type=str, metavar='PATH', + help='result image save path') +args = parser.parse_args() + + +with open("pad_info_56.json") as f: + pad_info = json.load(f) +scale = 4 + +def postprocess(hr_src_path, bin_path, save_path): + data = [] + if not os.path.isdir(save_path): + os.makedirs(save_path) + sr_list = merge(bin_path) + files = os.listdir(hr_src_path) + files.sort() + for i, img_file in enumerate(files): + img = sr_list[i] + img = quantize(img, 1) + hr = imageio.imread(os.path.join(hr_src_path, img_file)) + hr = torch.from_numpy(hr) + hr = hr / 255 + psnr = calc_psnr(img, hr, scale, 1) + data.append({"file": img_file, "psnr": psnr}) + + img = (img * 255).byte().cpu() + imageio.imwrite(os.path.join(save_path, img_file+".png"), img.numpy().astype(np.uint8).transpose(1, 2, 0)) + + data = eval_acc(data) + json_data = json.dumps( + data, indent=4, separators=(',', ': ')) + with open("result.json", 'w') as f: + f.write(json_data) + +def eval_acc(data): + acc = 0 + for item in data: + acc += item["psnr"] + acc /= len(data) + print("accuracy: ",acc) + return { + "accuracy": acc, + "data": data + } + + +def quantize(img, rgb_range): + pixel_range = 255 / rgb_range + return img.mul(pixel_range).clamp(0, 255).round().div(pixel_range) + + +def calc_psnr(sr, hr, scale, rgb_range): + sr = sr.unsqueeze(0) + hr = hr.permute(2, 0, 1).unsqueeze(0) + if hr.nelement() == 1: + return 0 + + diff = (sr - hr) / rgb_range + shave = 4 + if diff.size(1) > 1: + gray_coeffs = [65.738, 129.057, 25.064] + convert = diff.new_tensor(gray_coeffs).view(1, 3, 1, 1) / 256 + diff = diff.mul(convert).sum(dim=1) + + valid = diff[..., shave:-shave, shave:-shave] + mse = valid.pow(2).mean() + + return -10 * math.log10(mse) + +def merge(src_path): + min_list = [] + max_list = [] + for i, pad_meta in enumerate(pad_info): + if i % 5 == 0 and i < 16: + max_list.append(pad_meta) + else: + min_list.append(pad_meta) + h_half, w_half = -1, -1 + h_size, w_size = -1, -1 + h, w = -1, -1 + temp_img = None + sr_list = [] + sr = [] + files = os.listdir(src_path) + files.sort() + for i, file in enumerate(files): + array = np.fromfile(os.path.join(src_path, file), dtype=np.float32) + array = array.reshape( + 3, 56*4, 56*4) + img = torch.from_numpy(array) + pad_h, pad_w = min_list[i]['pad_h'], min_list[i]['pad_w'] + if pad_h == 0 and pad_w == 0: + img = img + elif pad_h == 0: + img = img[:, :, 0:-pad_w] + elif pad_w == 0: + img = img[:, 0:-pad_h, :] + else: + img = img[:, 0:-pad_h, 0:-pad_w] + if i % 4 == 0: + h_half, w_half = int(min_list[i]['h_half'] * scale), int(min_list[i]['w_half'] * scale) + h_size, w_size = min_list[i]['h_size'] * scale, min_list[i]['w_size'] * scale + h, w = h_half * 2, w_half * 2 + temp_img = torch.zeros(3, h, w) + temp_img[:, 0:h_half, 0:w_half] = img[:, 0:h_half, 0:w_half] + elif i % 4 == 1: + temp_img[:, 0:h_half, w_half:w] = img[:, 0:h_half, (w_size - w + w_half):w_size] + elif i % 4 == 2: + temp_img[:, h_half:h, 0:w_half] = img[:, (h_size - h + h_half):h_size, 0:w_half] + elif i % 4 == 3: + temp_img[:, h_half:h, w_half:w] = img[:, (h_size - h + h_half):h_size, (w_size - w + w_half):w_size] + sr_list.append(temp_img) + + h_half, w_half = max_list[0]['h_half'] * scale, max_list[0]['w_half'] * scale + h_size, w_size = max_list[0]['h_size'] * scale, max_list[0]['w_size'] * scale + h, w = h_half * 2, w_half * 2 + output = torch.zeros(3, h, w) + output[:, 0:h_half, 0:w_half] \ + = sr_list[0][:, 0:h_half, 0:w_half] + output[:, 0:h_half, w_half:w] \ + = sr_list[1][:, 0:h_half, (w_size - w + w_half):w_size] + output[:, h_half:h, 0:w_half] \ + = sr_list[2][:, (h_size - h + h_half):h_size, 0:w_half] + output[:, h_half:h, w_half:w] \ + = sr_list[3][:, (h_size - h + h_half):h_size, (w_size - w + w_half):w_size] + sr.append(output) + sr.append(sr_list[4]) + sr.append(sr_list[5]) + sr.append(sr_list[6]) + sr.append(sr_list[7]) + return sr + + +if __name__ == '__main__': + res = args.res + hr = args.hr + save_path = args.save_path postprocess(hr, res, save_path) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/CSNLN_preprocess.py b/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/CSNLN_preprocess.py index 36a6c15a22..f9b24a91ea 100644 --- a/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/CSNLN_preprocess.py +++ b/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/CSNLN_preprocess.py @@ -1,106 +1,106 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 numpy as np -import PIL.Image as pil_image -from torch.serialization import save -import torchvision.transforms as transforms -import os -import argparse -import torch -import json -import math -import imageio - -parser = argparse.ArgumentParser(description='CSNLN preprocess script') -parser.add_argument('--s', default='', type=str, metavar='PATH', - help='path of source image files (default: none)') -parser.add_argument('--d', default='', type=str, metavar='PATH', - help='path of output (default: none)') -args = parser.parse_args() - - - -pad_info = [] -def chop(x, file_name="", save_path="", shave=10, min_size=3600): - scale = 4 - c, h, w = x.size() - h_half, w_half = h // 2, w // 2 - if h % 2 != 0: - temp_h_half = h_half + 0.5 - else: - temp_h_half = h_half - if w % 2 != 0: - temp_w_half = w_half + 0.5 - else: - temp_w_half = w_half - h_size, w_size = h_half + shave, w_half + shave - h_size += scale-h_size%scale - w_size += scale-w_size%scale - lr_list = [ - x[:, 0:h_size, 0:w_size], - x[:, 0:h_size, (w - w_size):w], - x[:, (h - h_size):h, 0:w_size], - x[:, (h - h_size):h, (w - w_size):w]] - if w_size * h_size < min_size: - for i in range(0, 4, 1): - final_fileName = file_name.split('.')[0] + "_" + str(i) - lr_batch = torch.cat(lr_list[i:(i + 1)], dim=0) - pad_h = 56-h_size - pad_w = 56-w_size - lr_batch = transforms.Compose([ - transforms.Pad(padding=(0, 0, 56-w_size, 56-h_size), padding_mode='edge') - ])(lr_batch) - - imageio.imsave(os.path.join(save_path, "png", final_fileName + ".png"), np.array( - lr_batch).astype(np.uint8).transpose(1, 2, 0)) - lr_batch = np.array(lr_batch).astype(np.float32)/255 - lr_batch.tofile(os.path.join( - save_path, "bin_56", final_fileName + ".bin")) - pad_info.append( - {"name":final_fileName, "h_half": temp_h_half, "w_half": temp_w_half, "h_size":h_size, "w_size":w_size, "pad_h":pad_h, "pad_w":pad_w}) - with open("pad_info_56.json", "w") as f: - f.write(json.dumps(pad_info, indent=4, separators=(',', ': '))) - - else: - count = 0 - for patch in lr_list: - temp_fileName = file_name.split('.')[0] + "_" + str(count) + ".png" - pad_info.append( - {"name":temp_fileName.split('.')[0], "h_half": h_half, "w_half": w_half, "h_size":h_size, "w_size":w_size}) - count = count + 1 - chop(patch, file_name=temp_fileName, save_path=save_path, shave=shave, min_size=min_size) - -def preprocess(src_path, save_path): - if not os.path.isdir(src_path): - os.makedirs(src_path) - if not os.path.isdir(save_path): - os.makedirs(save_path) - if not os.path.isdir(os.path.join(save_path, "bin_56")): - os.makedirs(os.path.join(save_path, "bin_56")) - if not os.path.isdir(os.path.join(save_path, "png")): - os.makedirs(os.path.join(save_path, "png")) - files = os.listdir(src_path) - files.sort() - for image_file in files: - image = imageio.imread(os.path.join( - src_path, image_file)) - np_transpose = np.ascontiguousarray(image.transpose((2, 0, 1))) - image = torch.from_numpy(np_transpose).float() - image.mul_(255 / 255) - chop(image, file_name=image_file, save_path=save_path) - - -if __name__ == '__main__': +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 numpy as np +import PIL.Image as pil_image +from torch.serialization import save +import torchvision.transforms as transforms +import os +import argparse +import torch +import json +import math +import imageio + +parser = argparse.ArgumentParser(description='CSNLN preprocess script') +parser.add_argument('--s', default='', type=str, metavar='PATH', + help='path of source image files (default: none)') +parser.add_argument('--d', default='', type=str, metavar='PATH', + help='path of output (default: none)') +args = parser.parse_args() + + + +pad_info = [] +def chop(x, file_name="", save_path="", shave=10, min_size=3600): + scale = 4 + c, h, w = x.size() + h_half, w_half = h // 2, w // 2 + if h % 2 != 0: + temp_h_half = h_half + 0.5 + else: + temp_h_half = h_half + if w % 2 != 0: + temp_w_half = w_half + 0.5 + else: + temp_w_half = w_half + h_size, w_size = h_half + shave, w_half + shave + h_size += scale-h_size%scale + w_size += scale-w_size%scale + lr_list = [ + x[:, 0:h_size, 0:w_size], + x[:, 0:h_size, (w - w_size):w], + x[:, (h - h_size):h, 0:w_size], + x[:, (h - h_size):h, (w - w_size):w]] + if w_size * h_size < min_size: + for i in range(0, 4, 1): + final_fileName = file_name.split('.')[0] + "_" + str(i) + lr_batch = torch.cat(lr_list[i:(i + 1)], dim=0) + pad_h = 56-h_size + pad_w = 56-w_size + lr_batch = transforms.Compose([ + transforms.Pad(padding=(0, 0, 56-w_size, 56-h_size), padding_mode='edge') + ])(lr_batch) + + imageio.imsave(os.path.join(save_path, "png", final_fileName + ".png"), np.array( + lr_batch).astype(np.uint8).transpose(1, 2, 0)) + lr_batch = np.array(lr_batch).astype(np.float32)/255 + lr_batch.tofile(os.path.join( + save_path, "bin_56", final_fileName + ".bin")) + pad_info.append( + {"name":final_fileName, "h_half": temp_h_half, "w_half": temp_w_half, "h_size":h_size, "w_size":w_size, "pad_h":pad_h, "pad_w":pad_w}) + with open("pad_info_56.json", "w") as f: + f.write(json.dumps(pad_info, indent=4, separators=(',', ': '))) + + else: + count = 0 + for patch in lr_list: + temp_fileName = file_name.split('.')[0] + "_" + str(count) + ".png" + pad_info.append( + {"name":temp_fileName.split('.')[0], "h_half": h_half, "w_half": w_half, "h_size":h_size, "w_size":w_size}) + count = count + 1 + chop(patch, file_name=temp_fileName, save_path=save_path, shave=shave, min_size=min_size) + +def preprocess(src_path, save_path): + if not os.path.isdir(src_path): + os.makedirs(src_path) + if not os.path.isdir(save_path): + os.makedirs(save_path) + if not os.path.isdir(os.path.join(save_path, "bin_56")): + os.makedirs(os.path.join(save_path, "bin_56")) + if not os.path.isdir(os.path.join(save_path, "png")): + os.makedirs(os.path.join(save_path, "png")) + files = os.listdir(src_path) + files.sort() + for image_file in files: + image = imageio.imread(os.path.join( + src_path, image_file)) + np_transpose = np.ascontiguousarray(image.transpose((2, 0, 1))) + image = torch.from_numpy(np_transpose).float() + image.mul_(255 / 255) + chop(image, file_name=image_file, save_path=save_path) + + +if __name__ == '__main__': preprocess(args.s, args.d) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/CSNLN_pth2onnx.py b/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/CSNLN_pth2onnx.py index bb065db2a5..016ba2f088 100644 --- a/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/CSNLN_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/CSNLN_pth2onnx.py @@ -1,37 +1,37 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import torch -sys.path.append(r"./Cross-Scale-Non-Local-Attention/src/") -from model.csnln import CSNLN -from option import args -from collections import OrderedDict - - -def pth2onnx(input_file, output_file): - model = CSNLN(args) - model.load_state_dict(torch.load( - input_file, map_location=torch.device('cpu')), strict=False) - - model.eval() - dummy_input = torch.randn(1, 3, 56, 56) - - torch.onnx.export(model, dummy_input, output_file, opset_version=11, verbose=False) - - -if __name__ == "__main__": - input_file = args.pre_train - output_file = args.save - pth2onnx(input_file, output_file) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import torch +sys.path.append(r"./Cross-Scale-Non-Local-Attention/src/") +from model.csnln import CSNLN +from option import args +from collections import OrderedDict + + +def pth2onnx(input_file, output_file): + model = CSNLN(args) + model.load_state_dict(torch.load( + input_file, map_location=torch.device('cpu')), strict=False) + + model.eval() + dummy_input = torch.randn(1, 3, 56, 56) + + torch.onnx.export(model, dummy_input, output_file, opset_version=11, verbose=False) + + +if __name__ == "__main__": + input_file = args.pre_train + output_file = args.save + pth2onnx(input_file, output_file) diff --git a/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/LICENSE b/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/LICENSE index b1fac45f02..989e2c59e9 100644 --- a/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/LICENSE +++ b/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/LICENSE @@ -1,201 +1,201 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/get_info.py b/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/get_info.py index 63799abe3d..5f5fac8622 100644 --- a/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/get_info.py +++ b/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/get_info.py @@ -1,58 +1,58 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = '56' - height = '56' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = '56' + height = '56' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/modelzoo_level.txt index 74147d2f27..0541ac3f6d 100644 --- a/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/modelzoo_level.txt @@ -1,3 +1,3 @@ -FunStatus:OK -PrecisionStatus:OK +FunStatus:OK +PrecisionStatus:OK PerfStatus:POK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/perf_softmax_transpose.py b/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/perf_softmax_transpose.py index 888c3b9350..527104a539 100644 --- a/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/perf_softmax_transpose.py +++ b/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/perf_softmax_transpose.py @@ -1,22 +1,22 @@ -import sys -import onnx - -if __name__ == '__main__': - model = onnx.load(sys.argv[1]) - graph = model.graph - node = graph.node - softmax_node_index = [] - del_group = [] - for i in range(len(node)): - if node[i].op_type == 'Softmax' and node[i].attribute[0].i == 3: - del_group.append((node[i-1], node[i], node[i+1], i)) - for g in del_group: - new_input = g[0].input - new_output = g[2].output - new_name = g[1].name - new_index = g[3] - new_node = onnx.helper.make_node("Softmax", new_input, new_output, new_name, axis=1) - for n in g[:-1]: - graph.node.remove(n) - graph.node.insert(new_index, new_node) - onnx.save(model, sys.argv[2]) +import sys +import onnx + +if __name__ == '__main__': + model = onnx.load(sys.argv[1]) + graph = model.graph + node = graph.node + softmax_node_index = [] + del_group = [] + for i in range(len(node)): + if node[i].op_type == 'Softmax' and node[i].attribute[0].i == 3: + del_group.append((node[i-1], node[i], node[i+1], i)) + for g in del_group: + new_input = g[0].input + new_output = g[2].output + new_name = g[1].name + new_index = g[3] + new_node = onnx.helper.make_node("Softmax", new_input, new_output, new_name, axis=1) + for n in g[:-1]: + graph.node.remove(n) + graph.node.insert(new_index, new_node) + onnx.save(model, sys.argv[2]) diff --git a/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/requirements.txt b/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/requirements.txt index cb70277708..94ae69e3e3 100644 --- a/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/requirements.txt +++ b/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/requirements.txt @@ -1,9 +1,9 @@ -torch==1.8.0 -torchvision==0.9.0 -onnx==1.9.0 -onnx-simplifier==0.3.6 -numpy==1.21.1 -Pillow == 7.2.0 -opencv-python==4.2.0.34 -pyyaml==5.3.1 +torch==1.8.0 +torchvision==0.9.0 +onnx==1.9.0 +onnx-simplifier==0.3.6 +numpy==1.21.1 +Pillow == 7.2.0 +opencv-python==4.2.0.34 +pyyaml==5.3.1 scikit-image==0.18.1 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/test/parse.py b/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/test/parse.py index 2a25918902..7a52798e54 100644 --- a/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/test/parse.py +++ b/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention/test/parse.py @@ -1,30 +1,30 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.log'): - result_log = sys.argv[1] - with open(result_log, 'r') as f: - content = f.read() - print(result_log[:-4].split('_')[1], content, end="") - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.log'): + result_log = sys.argv[1] + with open(result_log, 'r') as f: + content = f.read() + print(result_log[:-4].split('_')[1], content, end="") + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/image_process/DnCNN/READEME.md b/ACL_PyTorch/contrib/cv/image_process/DnCNN/READEME.md index 592f7f9936..992c40398a 100644 --- a/ACL_PyTorch/contrib/cv/image_process/DnCNN/READEME.md +++ b/ACL_PyTorch/contrib/cv/image_process/DnCNN/READEME.md @@ -1,267 +1,267 @@ -# DnCNN ONNX模型端到端推理指导 -- [1 模型概述](#1-模型概述) - - [1.1 论文地址](#11-论文地址) - - [1.2 代码地址](#12-代码地址) -- [2 环境说明](#2-环境说明) - - [2.1 深度学习框架](#21-深度学习框架) - - [2.2 python第三方库](#22-python第三方库) -- [3 模型转换](#3-模型转换) - - [3.1 pth转onnx模型](#31-pth转onnx模型) - - [3.2 onnx转om模型](#32-onnx转om模型) -- [4 数据集预处理](#4-数据集预处理) - - [4.1 数据集获取](#41-数据集获取) - - [4.2 数据集预处理](#42-数据集预处理) - - [4.3 生成数据集信息文件](#43-生成数据集信息文件) -- [5 离线推理](#5-离线推理) - - [5.1 benchmark工具概述](#51-benchmark工具概述) - - [5.2 离线推理](#52-离线推理) -- [6 精度对比](#6-精度对比) - - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) - - [6.2 开源TopN精度](#62-开源TopN精度) - - [6.3 精度对比](#63-精度对比) -- [7 性能对比](#7-性能对比) - - [7.1 npu性能数据](#71-npu性能数据) - - - -## 1 模型概述 - -- **[论文地址](#11-论文地址)** - -- **[代码地址](#12-代码地址)** - -### 1.1 论文地址 -[DnCNN论文](https://ieeexplore.ieee.org/document/7839189) - -### 1.2 代码地址 - -brach:master - -commit_id: 6b0804951484eadb7f1ea24e8e5c9ede9bea485b - -备注:commitid指的是值模型基于此版本代码做的推理 - -[DnCNN代码](https://github.com/SaoYan/DnCNN-PyTorch) - -## 2 环境说明 - -- **[深度学习框架](#21-深度学习框架)** - -- **[python第三方库](#22-python第三方库)** - -### 2.1 深度学习框架 -``` -CANN 5.0.1 -torch==1.8.0 -torchvision==0.9.0 -onnx==1.9.0 -``` - -### 2.2 python第三方库 - -``` -numpy==1.20.2 -opencv-python==4.5.2.52 -scikit-image==0.16.2 -``` - -**说明:** -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3 模型转换 - -- **[pth转onnx模型](#31-pth转onnx模型)** - -- **[onnx转om模型](#32-onnx转om模型)** - -### 3.1 pth转onnx模型 - -1.DnCNN模型代码下载 -``` -git clone https://github.com/SaoYan/DnCNN-PyTorch -cd DnCNN-PyTorch -``` -2.获取源码pth权重文件 -wget https://ascend-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/image_classification/DnCnn/net.pth -文件的MD5sum值是: 5703a29b082cc03401fa9d9fee12cb71 - -3.获取NPU训练pth文件,将net.pth文件移动到DnCNN目录下 - -4.编写pth2onnx脚本DnCNN_pth2onnx.py - - **说明:** ->注意目前ATC支持的onnx算子版本为11 - -5.执行pth2onnx脚本,生成onnx模型文件 -``` -python3.7 DnCNN_pth2onnx.py net.pth DnCNN-S-15.onnx -``` - - **模型转换要点:** ->此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 - -### 3.2 onnx转om模型 - -1.设置环境变量 -``` -source env.sh -``` -2.使用atc将onnx模型转换为om模型文件 -``` -atc --framework=5 --model=./DnCNN-S-15.onnx --input_format=NCHW --input_shape="actual_input_1:1,1,481,481" --output=DnCNN-S-15_bs1 --log=debug --soc_version=Ascend310 -``` - -## 4 数据集预处理 - -- **[数据集获取](#41-数据集获取)** - -- **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - -### 4.1 推理数据集获取 -存放路径为 https://github.com/SaoYan/DnCNN-PyTorch 的data目录 - -### 4.2 数据集预处理 -1.预处理脚本data_preprocess.py - -2.执行预处理脚本,生成数据集预处理后的bin文件 - -``` -python3.7 data_preprocess.py data ISource INoisy -``` -### 4.3 生成数据集信息文件 -1.生成数据集信息文件脚本get_info.py - -2.执行生成数据集信息脚本,生成数据集信息文件 -``` -python3.7 get_info.py bin INoisy DnCNN_bin.info 481 481 -``` -第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 -## 5 离线推理 - -- **[benchmark工具概述](#51-benchmark工具概述)** - -- **[离线推理](#52-离线推理)** - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程 -### 5.2 离线推理 -1.设置环境变量 -``` -source env.sh -``` -2.执行离线推理 -``` -./benchmark.x86_64 -model_type=vision -om_path=DnCNN-S-15.om -device_id=0 -batch_size=1 -input_text_path=DnCNN_bin.info -input_width=481 -input_height=481 -useDvpp=false -output_binary=true -``` -输出结果默认保存在当前目录result/dumpOutput_deviceX(X为对应的device_id),每个输入对应的输出对应一个_X.bin文件。 - -## 6 精度对比 - -- **[离线推理TopN精度](#61-离线推理TopN精度)** -- **[开源TopN精度](#62-开源TopN精度)** -- **[精度对比](#63-精度对比)** - -### 6.1 离线推理TopN精度统计 - -后处理统计TopN精度 - -调用postprocess.py脚本推理结果进行PSRN计算,结果会打印在屏幕上 -``` -python3.7 postprocess.py result/dumpOutput_device0/ -``` -第一个参数为benchmark输出目录 -查看输出结果: -``` -ISource/test064.bin PSNR 29.799832 -infering... -ISource/test065.bin PSNR 31.486418 -infering... -ISource/test066.bin PSNR 35.676752 -infering... -ISource/test067.bin PSNR 28.577475 -infering... -ISource/test068.bin PSNR 29.709767 - -PSNR on test data 31.526892 -``` -经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 - -### 6.2 开源PSNR精度 -``` -| Noise Level | DnCNN-S | DnCNN-B | DnCNN-S-PyTorch | DnCNN-B-PyTorch | -|:-----------:|:-------:|:-------:|:---------------:|:---------------:| -| 15 | 31.73 | 31.61 | 31.71 | 31.60 | -| 25 | 29.23 | 29.16 | 29.21 | 29.15 | -| 50 | 26.23 | 26.23 | 26.22 | 26.20 | -``` -### 6.3 精度对比 -将得到的om离线模型推理PSNR值与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 - **精度调试:** - ->没有遇到精度不达标的问题,故不需要进行精度调试 - -## 7 性能对比 - -- **[npu性能数据](#71-npu性能数据)** - -### 7.1 npu性能数据 -benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device。为快速获取性能数据,也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准。这里给出两种方式,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 -1.benchmark工具在整个数据集上推理获得性能数据 -batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: -``` -[e2e] throughputRate: 15.0465, latency: 4519.32 -[data read] throughputRate: 966.417, moduleLatency: 1.03475 -[preprocess] throughputRate: 525.539, moduleLatency: 1.90281 -[infer] throughputRate: 22.6328, Interface throughputRate: 23.7919, moduleLatency: 43.8903 -[post] throughputRate: 22.615, moduleLatency: 44.2185 -``` -Interface throughputRate: 23.7919,23.7919x4=95.176既是batch1 310单卡吞吐率 - -batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: -``` -[e2e] throughputRate: 15.3818, latency: 4420.81 -[data read] throughputRate: 1484.65, moduleLatency: 0.673559 -[preprocess] throughputRate: 316.273, moduleLatency: 3.16182 -[infer] throughputRate: 21.4529, Interface throughputRate: 22.2853, moduleLatency: 45.6179 -[post] throughputRate: 1.56798, moduleLatency: 637.764 -``` -Interface throughputRate: 22.2853,22.2853x4=89.1412既是batch16 310单卡吞吐率 - -batch4性能: -``` -[e2e] throughputRate: 15.5641, latency: 4369.02 -[data read] throughputRate: 1898.17, moduleLatency: 0.526824 -[preprocess] throughputRate: 523.883, moduleLatency: 1.90882 -[infer] throughputRate: 22.091, Interface throughputRate: 23.9045, moduleLatency: 44.5192 -[post] throughputRate: 5.50981, moduleLatency: 181.495 -``` -batch4 310单卡吞吐率 23.9045x4=95.618 - -batch8性能: -``` -[e2e] throughputRate: 15.5035, latency: 4386.1 -[data read] throughputRate: 1863.93, moduleLatency: 0.5365 -[preprocess] throughputRate: 461.471, moduleLatency: 2.16699 -[infer] throughputRate: 20.7804, Interface throughputRate: 22.2652, moduleLatency: 47.2831 -[post] throughputRate: 2.74035, moduleLatency: 364.917 -``` -batch8 310单卡吞吐率 22.2652x4=89.0608 - -batch32性能: -``` -[e2e] throughputRate: 12.4075, latency: 5480.54 -[data read] throughputRate: 1770.65, moduleLatency: 0.564765 -[preprocess] throughputRate: 242.944, moduleLatency: 4.11618 -[infer] throughputRate: 15.641, Interface throughputRate: 13.2648, moduleLatency: 62.7386 -[post] throughputRate: 0.68503, moduleLatency: 1459.79 -``` -batch32 310单卡吞吐率 13.2648x4=53.0592 - -**性能优化:** - +# DnCNN ONNX模型端到端推理指导 +- [1 模型概述](#1-模型概述) + - [1.1 论文地址](#11-论文地址) + - [1.2 代码地址](#12-代码地址) +- [2 环境说明](#2-环境说明) + - [2.1 深度学习框架](#21-深度学习框架) + - [2.2 python第三方库](#22-python第三方库) +- [3 模型转换](#3-模型转换) + - [3.1 pth转onnx模型](#31-pth转onnx模型) + - [3.2 onnx转om模型](#32-onnx转om模型) +- [4 数据集预处理](#4-数据集预处理) + - [4.1 数据集获取](#41-数据集获取) + - [4.2 数据集预处理](#42-数据集预处理) + - [4.3 生成数据集信息文件](#43-生成数据集信息文件) +- [5 离线推理](#5-离线推理) + - [5.1 benchmark工具概述](#51-benchmark工具概述) + - [5.2 离线推理](#52-离线推理) +- [6 精度对比](#6-精度对比) + - [6.1 离线推理TopN精度统计](#61-离线推理TopN精度统计) + - [6.2 开源TopN精度](#62-开源TopN精度) + - [6.3 精度对比](#63-精度对比) +- [7 性能对比](#7-性能对比) + - [7.1 npu性能数据](#71-npu性能数据) + + + +## 1 模型概述 + +- **[论文地址](#11-论文地址)** + +- **[代码地址](#12-代码地址)** + +### 1.1 论文地址 +[DnCNN论文](https://ieeexplore.ieee.org/document/7839189) + +### 1.2 代码地址 + +brach:master + +commit_id: 6b0804951484eadb7f1ea24e8e5c9ede9bea485b + +备注:commitid指的是值模型基于此版本代码做的推理 + +[DnCNN代码](https://github.com/SaoYan/DnCNN-PyTorch) + +## 2 环境说明 + +- **[深度学习框架](#21-深度学习框架)** + +- **[python第三方库](#22-python第三方库)** + +### 2.1 深度学习框架 +``` +CANN 5.0.1 +torch==1.8.0 +torchvision==0.9.0 +onnx==1.9.0 +``` + +### 2.2 python第三方库 + +``` +numpy==1.20.2 +opencv-python==4.5.2.52 +scikit-image==0.16.2 +``` + +**说明:** +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3 模型转换 + +- **[pth转onnx模型](#31-pth转onnx模型)** + +- **[onnx转om模型](#32-onnx转om模型)** + +### 3.1 pth转onnx模型 + +1.DnCNN模型代码下载 +``` +git clone https://github.com/SaoYan/DnCNN-PyTorch +cd DnCNN-PyTorch +``` +2.获取源码pth权重文件 +wget https://ascend-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/image_classification/DnCnn/net.pth +文件的MD5sum值是: 5703a29b082cc03401fa9d9fee12cb71 + +3.获取NPU训练pth文件,将net.pth文件移动到DnCNN目录下 + +4.编写pth2onnx脚本DnCNN_pth2onnx.py + + **说明:** +>注意目前ATC支持的onnx算子版本为11 + +5.执行pth2onnx脚本,生成onnx模型文件 +``` +python3.7 DnCNN_pth2onnx.py net.pth DnCNN-S-15.onnx +``` + + **模型转换要点:** +>此模型转换为onnx不需要修改开源代码仓代码,故不需要特殊说明 + +### 3.2 onnx转om模型 + +1.设置环境变量 +``` +source env.sh +``` +2.使用atc将onnx模型转换为om模型文件 +``` +atc --framework=5 --model=./DnCNN-S-15.onnx --input_format=NCHW --input_shape="actual_input_1:1,1,481,481" --output=DnCNN-S-15_bs1 --log=debug --soc_version=Ascend310 +``` + +## 4 数据集预处理 + +- **[数据集获取](#41-数据集获取)** + +- **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + +### 4.1 推理数据集获取 +存放路径为 https://github.com/SaoYan/DnCNN-PyTorch 的data目录 + +### 4.2 数据集预处理 +1.预处理脚本data_preprocess.py + +2.执行预处理脚本,生成数据集预处理后的bin文件 + +``` +python3.7 data_preprocess.py data ISource INoisy +``` +### 4.3 生成数据集信息文件 +1.生成数据集信息文件脚本get_info.py + +2.执行生成数据集信息脚本,生成数据集信息文件 +``` +python3.7 get_info.py bin INoisy DnCNN_bin.info 481 481 +``` +第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 +## 5 离线推理 + +- **[benchmark工具概述](#51-benchmark工具概述)** + +- **[离线推理](#52-离线推理)** + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程 +### 5.2 离线推理 +1.设置环境变量 +``` +source env.sh +``` +2.执行离线推理 +``` +./benchmark.x86_64 -model_type=vision -om_path=DnCNN-S-15.om -device_id=0 -batch_size=1 -input_text_path=DnCNN_bin.info -input_width=481 -input_height=481 -useDvpp=false -output_binary=true +``` +输出结果默认保存在当前目录result/dumpOutput_deviceX(X为对应的device_id),每个输入对应的输出对应一个_X.bin文件。 + +## 6 精度对比 + +- **[离线推理TopN精度](#61-离线推理TopN精度)** +- **[开源TopN精度](#62-开源TopN精度)** +- **[精度对比](#63-精度对比)** + +### 6.1 离线推理TopN精度统计 + +后处理统计TopN精度 + +调用postprocess.py脚本推理结果进行PSRN计算,结果会打印在屏幕上 +``` +python3.7 postprocess.py result/dumpOutput_device0/ +``` +第一个参数为benchmark输出目录 +查看输出结果: +``` +ISource/test064.bin PSNR 29.799832 +infering... +ISource/test065.bin PSNR 31.486418 +infering... +ISource/test066.bin PSNR 35.676752 +infering... +ISource/test067.bin PSNR 28.577475 +infering... +ISource/test068.bin PSNR 29.709767 + +PSNR on test data 31.526892 +``` +经过对bs1与bs16的om测试,本模型batch1的精度与batch16的精度没有差别,精度数据均如上 + +### 6.2 开源PSNR精度 +``` +| Noise Level | DnCNN-S | DnCNN-B | DnCNN-S-PyTorch | DnCNN-B-PyTorch | +|:-----------:|:-------:|:-------:|:---------------:|:---------------:| +| 15 | 31.73 | 31.61 | 31.71 | 31.60 | +| 25 | 29.23 | 29.16 | 29.21 | 29.15 | +| 50 | 26.23 | 26.23 | 26.22 | 26.20 | +``` +### 6.3 精度对比 +将得到的om离线模型推理PSNR值与该模型github代码仓上公布的精度对比,精度下降在1%范围之内,故精度达标。 + **精度调试:** + +>没有遇到精度不达标的问题,故不需要进行精度调试 + +## 7 性能对比 + +- **[npu性能数据](#71-npu性能数据)** + +### 7.1 npu性能数据 +benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device。为快速获取性能数据,也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准。这里给出两种方式,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 +1.benchmark工具在整个数据集上推理获得性能数据 +batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: +``` +[e2e] throughputRate: 15.0465, latency: 4519.32 +[data read] throughputRate: 966.417, moduleLatency: 1.03475 +[preprocess] throughputRate: 525.539, moduleLatency: 1.90281 +[infer] throughputRate: 22.6328, Interface throughputRate: 23.7919, moduleLatency: 43.8903 +[post] throughputRate: 22.615, moduleLatency: 44.2185 +``` +Interface throughputRate: 23.7919,23.7919x4=95.176既是batch1 310单卡吞吐率 + +batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: +``` +[e2e] throughputRate: 15.3818, latency: 4420.81 +[data read] throughputRate: 1484.65, moduleLatency: 0.673559 +[preprocess] throughputRate: 316.273, moduleLatency: 3.16182 +[infer] throughputRate: 21.4529, Interface throughputRate: 22.2853, moduleLatency: 45.6179 +[post] throughputRate: 1.56798, moduleLatency: 637.764 +``` +Interface throughputRate: 22.2853,22.2853x4=89.1412既是batch16 310单卡吞吐率 + +batch4性能: +``` +[e2e] throughputRate: 15.5641, latency: 4369.02 +[data read] throughputRate: 1898.17, moduleLatency: 0.526824 +[preprocess] throughputRate: 523.883, moduleLatency: 1.90882 +[infer] throughputRate: 22.091, Interface throughputRate: 23.9045, moduleLatency: 44.5192 +[post] throughputRate: 5.50981, moduleLatency: 181.495 +``` +batch4 310单卡吞吐率 23.9045x4=95.618 + +batch8性能: +``` +[e2e] throughputRate: 15.5035, latency: 4386.1 +[data read] throughputRate: 1863.93, moduleLatency: 0.5365 +[preprocess] throughputRate: 461.471, moduleLatency: 2.16699 +[infer] throughputRate: 20.7804, Interface throughputRate: 22.2652, moduleLatency: 47.2831 +[post] throughputRate: 2.74035, moduleLatency: 364.917 +``` +batch8 310单卡吞吐率 22.2652x4=89.0608 + +batch32性能: +``` +[e2e] throughputRate: 12.4075, latency: 5480.54 +[data read] throughputRate: 1770.65, moduleLatency: 0.564765 +[preprocess] throughputRate: 242.944, moduleLatency: 4.11618 +[infer] throughputRate: 15.641, Interface throughputRate: 13.2648, moduleLatency: 62.7386 +[post] throughputRate: 0.68503, moduleLatency: 1459.79 +``` +batch32 310单卡吞吐率 13.2648x4=53.0592 + +**性能优化:** + >batch32纯推理性能达标。 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/image_process/DnCNN/test/README.md b/ACL_PyTorch/contrib/cv/image_process/DnCNN/test/README.md index ab5da7a949..7991250288 100644 --- a/ACL_PyTorch/contrib/cv/image_process/DnCNN/test/README.md +++ b/ACL_PyTorch/contrib/cv/image_process/DnCNN/test/README.md @@ -1,31 +1,31 @@ -环境准备: - -1.获取数据集 -``` -git clone https://github.com/SaoYan/DnCNN-PyTorch -``` -开源代码仓的data目录下有数据集,将data复制到DnCNN目录下 - -2.进入工作目录 -``` -cd DnCNN -``` - -3.安装必要的依赖 -``` -pip3.7 install -r requirements.txt -``` - -4.获取训练提供的权重文件 -``` -wget https://ascend-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/image_classification/DnCnn/net.pth -``` - -5.获取benchmark工具 -将benchmark.x86_64 benchmark.aarch64放在当前目录 - -6.310上执行,执行时确保device空闲 -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=./data -``` +环境准备: + +1.获取数据集 +``` +git clone https://github.com/SaoYan/DnCNN-PyTorch +``` +开源代码仓的data目录下有数据集,将data复制到DnCNN目录下 + +2.进入工作目录 +``` +cd DnCNN +``` + +3.安装必要的依赖 +``` +pip3.7 install -r requirements.txt +``` + +4.获取训练提供的权重文件 +``` +wget https://ascend-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/image_classification/DnCnn/net.pth +``` + +5.获取benchmark工具 +将benchmark.x86_64 benchmark.aarch64放在当前目录 + +6.310上执行,执行时确保device空闲 +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=./data +``` diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/3DMPPE-ROOTNET_postprocess.py b/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/3DMPPE-ROOTNET_postprocess.py index dcd38a9917..e844f8baed 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/3DMPPE-ROOTNET_postprocess.py +++ b/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/3DMPPE-ROOTNET_postprocess.py @@ -1,50 +1,50 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import argparse -from pathlib import Path -import numpy as np -sys.path.append(r"./3DMPPE_ROOTNET_RELEASE") -from data.MuPoTS.MuPoTS import MuPoTS - -def evaluate(result_path, result_file, img_path, ann_path): - print('postprocessing') - bin_path = os.listdir(result_path)[0] - result_path = os.path.join(result_path, bin_path) - bin_list = os.listdir(result_path) - bin_list.sort(key=lambda x: int(x[:-13])) - preds = [] - for i,f in enumerate(bin_list): - bin_path = os.path.join(result_path, f) - coord_out = np.fromfile(bin_path, dtype=np.float32).reshape(-1, 3) - preds.append(coord_out) - # evaluate - preds = np.concatenate(preds, axis=0) - testset = MuPoTS('test', img_path, ann_path) - if not os.path.exists(result_file): - os.makedirs(result_file) - testset.evaluate(preds, result_file) - print('postprocess finised') - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='preprocess of 3D-ResNets') - parser.add_argument('--img_path', default='MuPoTS/MultiPersonTestSet',type=Path, help='Directory path of videos') - parser.add_argument('--ann_path', default='MuPoTS/MuPoTS-3D.json', type=Path, help='Annotation file path') - parser.add_argument('--input_path', default='out_bs1', type=Path, help='Directory path of videos') - parser.add_argument('--result_file', default='result_bs1', type=Path, help='Directory path of binary output data') - opt = parser.parse_args() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import argparse +from pathlib import Path +import numpy as np +sys.path.append(r"./3DMPPE_ROOTNET_RELEASE") +from data.MuPoTS.MuPoTS import MuPoTS + +def evaluate(result_path, result_file, img_path, ann_path): + print('postprocessing') + bin_path = os.listdir(result_path)[0] + result_path = os.path.join(result_path, bin_path) + bin_list = os.listdir(result_path) + bin_list.sort(key=lambda x: int(x[:-13])) + preds = [] + for i,f in enumerate(bin_list): + bin_path = os.path.join(result_path, f) + coord_out = np.fromfile(bin_path, dtype=np.float32).reshape(-1, 3) + preds.append(coord_out) + # evaluate + preds = np.concatenate(preds, axis=0) + testset = MuPoTS('test', img_path, ann_path) + if not os.path.exists(result_file): + os.makedirs(result_file) + testset.evaluate(preds, result_file) + print('postprocess finised') + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='preprocess of 3D-ResNets') + parser.add_argument('--img_path', default='MuPoTS/MultiPersonTestSet',type=Path, help='Directory path of videos') + parser.add_argument('--ann_path', default='MuPoTS/MuPoTS-3D.json', type=Path, help='Annotation file path') + parser.add_argument('--input_path', default='out_bs1', type=Path, help='Directory path of videos') + parser.add_argument('--result_file', default='result_bs1', type=Path, help='Directory path of binary output data') + opt = parser.parse_args() evaluate(opt.input_path, opt.result_file, opt.img_path, opt.ann_path) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/3DMPPE-ROOTNET_preprocess.py b/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/3DMPPE-ROOTNET_preprocess.py index 7f7ff43b73..a87187843b 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/3DMPPE-ROOTNET_preprocess.py +++ b/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/3DMPPE-ROOTNET_preprocess.py @@ -1,61 +1,61 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import argparse -from pathlib import Path -from tqdm import tqdm -import torch -import torchvision.transforms as transforms -from torch.utils.data import DataLoader -sys.path.append(r"./3DMPPE_ROOTNET_RELEASE") -from data.dataset import DatasetLoader -from data.MuPoTS.MuPoTS import MuPoTS - -def preprocess(inference_batch_size, save_path_imge, save_path_cam, img_path, ann_path): - print('preprocessing') - testset = MuPoTS('test', img_path, ann_path) - - testset_loader = DatasetLoader(testset, False, transforms.Compose([transforms.ToTensor(), - transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225))])) - batch_generator = DataLoader(dataset=testset_loader, batch_size=inference_batch_size, - shuffle=False, num_workers=8, pin_memory=True) - - if not os.path.exists(save_path_imge): - os.makedirs(save_path_imge) - if not os.path.exists(save_path_cam): - os.makedirs(save_path_cam) - cid = 0 - with torch.no_grad(): - for itr, (input_img, cam_param) in enumerate(tqdm(batch_generator)): - if(len(input_img) == inference_batch_size): - path_bin_image = str(save_path_imge) + '/' + str(cid) + '.bin' - path_bin_cam = str(save_path_cam) + '/' + str(cid) + '.bin' - cid = cid + 1 - input_img.cpu().numpy().tofile(path_bin_image) - cam_param.cpu().numpy().tofile(path_bin_cam) - print('preprocess finished') - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--img_path', default='MuPoTS/MultiPersonTestSet', - type=Path, help='Directory path of videos') - parser.add_argument('--ann_path', default='MuPoTS/MuPoTS-3D.json', type=Path, help='Annotation file path') - parser.add_argument('--inference_batch_size', default=1, type=int, help='Batch Size for inference. 0 means this is the same as batch_size.') - parser.add_argument('--save_path_image', default='0data_imge_bs1', type=Path, help='Directory path of binary output data') - parser.add_argument('--save_path_cam', default='0data_cam_bs1', type=Path, help='Directory path of binary output data') - opt = parser.parse_args() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import argparse +from pathlib import Path +from tqdm import tqdm +import torch +import torchvision.transforms as transforms +from torch.utils.data import DataLoader +sys.path.append(r"./3DMPPE_ROOTNET_RELEASE") +from data.dataset import DatasetLoader +from data.MuPoTS.MuPoTS import MuPoTS + +def preprocess(inference_batch_size, save_path_imge, save_path_cam, img_path, ann_path): + print('preprocessing') + testset = MuPoTS('test', img_path, ann_path) + + testset_loader = DatasetLoader(testset, False, transforms.Compose([transforms.ToTensor(), + transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225))])) + batch_generator = DataLoader(dataset=testset_loader, batch_size=inference_batch_size, + shuffle=False, num_workers=8, pin_memory=True) + + if not os.path.exists(save_path_imge): + os.makedirs(save_path_imge) + if not os.path.exists(save_path_cam): + os.makedirs(save_path_cam) + cid = 0 + with torch.no_grad(): + for itr, (input_img, cam_param) in enumerate(tqdm(batch_generator)): + if(len(input_img) == inference_batch_size): + path_bin_image = str(save_path_imge) + '/' + str(cid) + '.bin' + path_bin_cam = str(save_path_cam) + '/' + str(cid) + '.bin' + cid = cid + 1 + input_img.cpu().numpy().tofile(path_bin_image) + cam_param.cpu().numpy().tofile(path_bin_cam) + print('preprocess finished') + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--img_path', default='MuPoTS/MultiPersonTestSet', + type=Path, help='Directory path of videos') + parser.add_argument('--ann_path', default='MuPoTS/MuPoTS-3D.json', type=Path, help='Annotation file path') + parser.add_argument('--inference_batch_size', default=1, type=int, help='Batch Size for inference. 0 means this is the same as batch_size.') + parser.add_argument('--save_path_image', default='0data_imge_bs1', type=Path, help='Directory path of binary output data') + parser.add_argument('--save_path_cam', default='0data_cam_bs1', type=Path, help='Directory path of binary output data') + opt = parser.parse_args() preprocess(opt.inference_batch_size, opt.save_path_image, opt.save_path_cam, opt.img_path, opt.ann_path) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/3DMPPE-ROOTNET_pth2onnx.py b/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/3DMPPE-ROOTNET_pth2onnx.py index 8da7b5791d..fad0ab3a3d 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/3DMPPE-ROOTNET_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/3DMPPE-ROOTNET_pth2onnx.py @@ -1,47 +1,47 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import torch -from collections import OrderedDict -sys.path.append(r"./3DMPPE_ROOTNET_RELEASE") -from main.model import get_pose_net -from main.config import cfg - -def convert(pth_file_path,onnx_file_path): - model = get_pose_net(cfg, False) - ckpt = torch.load(pth_file_path, map_location=torch.device('cpu')) - new_state_dict = OrderedDict() - for k, v in ckpt['network'].items(): - if k[0:7] == "module.": - name = k[7:] # remove module. - else: - name = k[0:] - new_state_dict[name] = v - model.load_state_dict(new_state_dict) - model.eval() - - input_names = ["image", "cam_param"] - output_names = ["score"] - dynamic_axes = {'image': {0: '-1'}, 'cam_param': {0: '-1'}, 'score': {0: '-1'}} - dummy_input1 = torch.randn(1, 3, 256, 256) - dummy_input2 = torch.randn(1, 1) - torch.onnx.export(model, (dummy_input1, dummy_input2), onnx_file_path, input_names=input_names, dynamic_axes=dynamic_axes, - output_names=output_names, opset_version=11, verbose=True) - -if __name__ == "__main__": - # convert("snapshot_6.pth.tar", "3DMPPE-ROOTNET.onnx") - convert(sys.argv[1], sys.argv[2]) - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import torch +from collections import OrderedDict +sys.path.append(r"./3DMPPE_ROOTNET_RELEASE") +from main.model import get_pose_net +from main.config import cfg + +def convert(pth_file_path,onnx_file_path): + model = get_pose_net(cfg, False) + ckpt = torch.load(pth_file_path, map_location=torch.device('cpu')) + new_state_dict = OrderedDict() + for k, v in ckpt['network'].items(): + if k[0:7] == "module.": + name = k[7:] # remove module. + else: + name = k[0:] + new_state_dict[name] = v + model.load_state_dict(new_state_dict) + model.eval() + + input_names = ["image", "cam_param"] + output_names = ["score"] + dynamic_axes = {'image': {0: '-1'}, 'cam_param': {0: '-1'}, 'score': {0: '-1'}} + dummy_input1 = torch.randn(1, 3, 256, 256) + dummy_input2 = torch.randn(1, 1) + torch.onnx.export(model, (dummy_input1, dummy_input2), onnx_file_path, input_names=input_names, dynamic_axes=dynamic_axes, + output_names=output_names, opset_version=11, verbose=True) + +if __name__ == "__main__": + # convert("snapshot_6.pth.tar", "3DMPPE-ROOTNET.onnx") + convert(sys.argv[1], sys.argv[2]) + + diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/LICENSE b/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/LICENSE index df2c2f2c3e..c8ec075d5b 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/LICENSE +++ b/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/LICENSE @@ -1,203 +1,203 @@ -Copyright 2018-2019 Open-MMLab. All rights reserved. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018-2019 Open-MMLab. - - 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 +Copyright 2018-2019 Open-MMLab. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2019 Open-MMLab. + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/README.md b/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/README.md index d2b51af3ac..51e63ccddb 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/README.md +++ b/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/README.md @@ -1,43 +1,43 @@ -# 3DMPPE-ROOTNET模型PyTorch离线推理指导 - -### 环境准备 - -安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -``` -pip3.7 install -r requirements.txt -``` - -### 安装开源模型代码 -``` -git clone https://github.com/mks0601/3DMPPE_ROOTNET_RELEASE.git -cd 3DMPPE_ROOTNET_RELEASE -patch -p1 < ../3DMPPE_ROOTNET.patch -cd .. -``` -> branch: master - -> commit id: a199d50be5b0a9ba348679ad4d010130535a631d - -### 获取MuPoTS数据集 -下载 MuPoTS 解析数据 [[MuPoTS](https://github.com/mks0601/3DMPPE_ROOTNET_RELEASE)] - - -### 获取推理工具 -获取msame和benchmark工具 [[msame](https://gitee.com/ascend/tools/tree/master/msame)][[benchmark](https://gitee.com/ascend/cann-benchmark/tree/master/infer)] - -将msame和benchmark.x86_64(或benchmark.aarch64)放到当前目录 - -### 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets/ -``` - **评测结果:** -| 模型 | pth精度 | 310精度 | 性能基准 | 310性能 | -| :------: | :------: | :------: | :------: | :------: | -| 3DMPPE-ROOTNET bs1 | AP_root: 31.87 | AP_root: 31.90 | 639.656fps | 664.718fps | -| 3DMPPE-ROOTNET bs16 | AP_root: 31.87 | AP_root: 31.88 | 467.282fps | 817.480fps | - - +# 3DMPPE-ROOTNET模型PyTorch离线推理指导 + +### 环境准备 + +安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +``` +pip3.7 install -r requirements.txt +``` + +### 安装开源模型代码 +``` +git clone https://github.com/mks0601/3DMPPE_ROOTNET_RELEASE.git +cd 3DMPPE_ROOTNET_RELEASE +patch -p1 < ../3DMPPE_ROOTNET.patch +cd .. +``` +> branch: master + +> commit id: a199d50be5b0a9ba348679ad4d010130535a631d + +### 获取MuPoTS数据集 +下载 MuPoTS 解析数据 [[MuPoTS](https://github.com/mks0601/3DMPPE_ROOTNET_RELEASE)] + + +### 获取推理工具 +获取msame和benchmark工具 [[msame](https://gitee.com/ascend/tools/tree/master/msame)][[benchmark](https://gitee.com/ascend/cann-benchmark/tree/master/infer)] + +将msame和benchmark.x86_64(或benchmark.aarch64)放到当前目录 + +### 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets/ +``` + **评测结果:** +| 模型 | pth精度 | 310精度 | 性能基准 | 310性能 | +| :------: | :------: | :------: | :------: | :------: | +| 3DMPPE-ROOTNET bs1 | AP_root: 31.87 | AP_root: 31.90 | 639.656fps | 664.718fps | +| 3DMPPE-ROOTNET bs16 | AP_root: 31.87 | AP_root: 31.88 | 467.282fps | 817.480fps | + + diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/modelzoo_level.txt index 83689985f2..8c469d858a 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus:PERFECT \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/requirements.txt b/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/requirements.txt index a7d74b3118..fd36c96400 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/requirements.txt +++ b/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/requirements.txt @@ -1,9 +1,9 @@ -torch==1.5.0 -torchvision==0.6.0 -onnx == 1.7.0 -numpy==1.20.3 -opencv-python==4.5.3.56 -tqdm==4.62.1 -scipy==1.6.2 -pycocotools==2.0 +torch==1.5.0 +torchvision==0.6.0 +onnx == 1.7.0 +numpy==1.20.3 +opencv-python==4.5.3.56 +tqdm==4.62.1 +scipy==1.6.2 +pycocotools==2.0 scikit-learn==0.24.2 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/test/parse.py b/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/test/parse.py index a35b48d42a..6b1760f355 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/test/parse.py +++ b/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET/test/parse.py @@ -1,31 +1,31 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - result_json = result_json.split('_')[1] - result_json = result_json.split('/')[0] - print('om {} accuracy {}'.format(result_json, content)) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = content.split(' ') - fps = float(txt_data_list[2].replace('samples/s,', '')) * 4 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + result_json = result_json.split('_')[1] + result_json = result_json.split('/')[0] + print('om {} accuracy {}'.format(result_json, content)) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = content.split(' ') + fps = float(txt_data_list[2].replace('samples/s,', '')) * 4 print('310 {} fps:{}'.format(result_txt.split('_')[4], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/HigherHRNet/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/pose_estimation/HigherHRNet/modelzoo_level.txt index c80d660077..d5130dbf73 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/HigherHRNet/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/pose_estimation/HigherHRNet/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -ModelConvert:OK +FuncStatus:OK +PrecisionStatus:OK +ModelConvert:OK PerfStatus=OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/MSPN_postprocess.py b/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/MSPN_postprocess.py index 292c34384e..6d3f896bbf 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/MSPN_postprocess.py +++ b/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/MSPN_postprocess.py @@ -1,194 +1,194 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -sys.path.append('./exps/mspn.2xstg.coco/') -import argparse -from tqdm import tqdm -import numpy as np -import cv2 -import json -import time - -import torch -import torch.distributed as dist - -from cvpack.utils.logger import get_logger - -from config import cfg -from network import MSPN -from lib.utils.dataloader import get_test_loader -from lib.utils.comm import is_main_process, synchronize, all_gather -from lib.utils.transforms import flip_back -from dataset.COCO.coco import COCODataset - -def get_results(outputs, centers, scales, kernel=11, shifts=[0.25]): - scales *= 200 - nr_img = outputs.shape[0] - preds = np.zeros((nr_img, cfg.DATASET.KEYPOINT.NUM, 2)) - maxvals = np.zeros((nr_img, cfg.DATASET.KEYPOINT.NUM, 1)) - for i in range(nr_img): - score_map = outputs[i].copy() - score_map = score_map / 255 + 0.5 - kps = np.zeros((cfg.DATASET.KEYPOINT.NUM, 2)) - scores = np.zeros((cfg.DATASET.KEYPOINT.NUM, 1)) - border = 10 - dr = np.zeros((cfg.DATASET.KEYPOINT.NUM, - cfg.OUTPUT_SHAPE[0] + 2 * border, cfg.OUTPUT_SHAPE[1] + 2 * border)) - dr[:, border: -border, border: -border] = outputs[i].copy() - for w in range(cfg.DATASET.KEYPOINT.NUM): - dr[w] = cv2.GaussianBlur(dr[w], (kernel, kernel), 0) - for w in range(cfg.DATASET.KEYPOINT.NUM): - for j in range(len(shifts)): - if j == 0: - lb = dr[w].argmax() - y, x = np.unravel_index(lb, dr[w].shape) - dr[w, y, x] = 0 - x -= border - y -= border - lb = dr[w].argmax() - py, px = np.unravel_index(lb, dr[w].shape) - dr[w, py, px] = 0 - px -= border + x - py -= border + y - ln = (px ** 2 + py ** 2) ** 0.5 - if ln > 1e-3: - x += shifts[j] * px / ln - y += shifts[j] * py / ln - x = max(0, min(x, cfg.OUTPUT_SHAPE[1] - 1)) - y = max(0, min(y, cfg.OUTPUT_SHAPE[0] - 1)) - kps[w] = np.array([x * 4 + 2, y * 4 + 2]) - scores[w, 0] = score_map[w, int(round(y) + 1e-9), \ - int(round(x) + 1e-9)] - # aligned or not ... - kps[:, 0] = kps[:, 0] / cfg.INPUT_SHAPE[1] * scales[i][0] + \ - centers[i][0] - scales[i][0] * 0.5 - kps[:, 1] = kps[:, 1] / cfg.INPUT_SHAPE[0] * scales[i][1] + \ - centers[i][1] - scales[i][1] * 0.5 - preds[i] = kps - maxvals[i] = scores - - return preds, maxvals - - -def compute_on_dataset(data_loader, device="cpu"): - results = list() - cpu_device = torch.device("cpu") - - results = list() - data = tqdm(data_loader) if is_main_process() else data_loader - k = 0 - for _, batch in enumerate(data): - imgs, scores, centers, scales, img_ids = batch - output_name='img_%d_%d_1.bin' %(int(img_ids[0]), k) - output_path=os.path.join('result/dumpOutput_device0/',output_name) - outputs = np.fromfile(output_path, dtype=np.float32).reshape(1,17,64,48) - k += 1 - - centers = np.array(centers) - scales = np.array(scales) - preds, maxvals = get_results(outputs, centers, scales, - cfg.TEST.GAUSSIAN_KERNEL, cfg.TEST.SHIFT_RATIOS) - - kp_scores = maxvals.squeeze(-1).mean(axis=1) - preds = np.concatenate((preds, maxvals), axis=2) - - for i in range(preds.shape[0]): - keypoints = preds[i].reshape(-1).tolist() - score = scores[i] * kp_scores[i] - image_id = img_ids[i] - - results.append(dict(image_id=image_id, - category_id=1, - keypoints=keypoints, - score=score)) - return results - - -def _accumulate_predictions_from_multiple_gpus(predictions_per_gpu, logger): - if is_main_process(): - logger.info("Accumulating ...") - all_predictions = all_gather(predictions_per_gpu) - - if not is_main_process(): - return - - predictions = list() - for p in all_predictions: - predictions.extend(p) - - return predictions - - -def inference(data_loader, logger, device="cpu"): - predictions = compute_on_dataset(data_loader, device) - synchronize() - predictions = _accumulate_predictions_from_multiple_gpus( - predictions, logger) - - if not is_main_process(): - return - - return predictions - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("--local_rank", type=int, default=0) - parser.add_argument("--iter", "-i", type=int, default=-1) - parser.add_argument("--datasets_path",default="$MSPN_HOME/dataset/COCO") - args = parser.parse_args() - COCODataset.cur_dir=os.path.join(args.datasets_path) - num_gpus = int( - os.environ["WORLD_SIZE"]) if "WORLD_SIZE" in os.environ else 1 - distributed = num_gpus > 1 - - if distributed: - torch.cuda.set_device(args.local_rank) - dist.init_process_group(backend="nccl", init_method="env://") - synchronize() - - if is_main_process() and not os.path.exists(cfg.TEST_DIR): - os.mkdir(cfg.TEST_DIR) - logger = get_logger( - cfg.DATASET.NAME, cfg.TEST_DIR, args.local_rank, 'test_log.txt') - - if args.iter == -1: - logger.info("Please designate one iteration.") - - data_loader = get_test_loader(cfg, num_gpus, args.local_rank, 'val', - is_dist=distributed) - - device = 'cpu' - results = inference(data_loader, logger, device) - synchronize() - - if is_main_process(): - logger.info("Dumping results ...") - results.sort( - key=lambda res:(res['image_id'], res['score']), reverse=True) - results_path = os.path.join(cfg.TEST_DIR, 'results.json') - with open(results_path, 'w') as f: - json.dump(results, f) - logger.info("Get all results.") - - data_loader.ori_dataset.evaluate(results_path) - - -if __name__ == '__main__': - begin = time.time() - main() - end = time.time() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +sys.path.append('./exps/mspn.2xstg.coco/') +import argparse +from tqdm import tqdm +import numpy as np +import cv2 +import json +import time + +import torch +import torch.distributed as dist + +from cvpack.utils.logger import get_logger + +from config import cfg +from network import MSPN +from lib.utils.dataloader import get_test_loader +from lib.utils.comm import is_main_process, synchronize, all_gather +from lib.utils.transforms import flip_back +from dataset.COCO.coco import COCODataset + +def get_results(outputs, centers, scales, kernel=11, shifts=[0.25]): + scales *= 200 + nr_img = outputs.shape[0] + preds = np.zeros((nr_img, cfg.DATASET.KEYPOINT.NUM, 2)) + maxvals = np.zeros((nr_img, cfg.DATASET.KEYPOINT.NUM, 1)) + for i in range(nr_img): + score_map = outputs[i].copy() + score_map = score_map / 255 + 0.5 + kps = np.zeros((cfg.DATASET.KEYPOINT.NUM, 2)) + scores = np.zeros((cfg.DATASET.KEYPOINT.NUM, 1)) + border = 10 + dr = np.zeros((cfg.DATASET.KEYPOINT.NUM, + cfg.OUTPUT_SHAPE[0] + 2 * border, cfg.OUTPUT_SHAPE[1] + 2 * border)) + dr[:, border: -border, border: -border] = outputs[i].copy() + for w in range(cfg.DATASET.KEYPOINT.NUM): + dr[w] = cv2.GaussianBlur(dr[w], (kernel, kernel), 0) + for w in range(cfg.DATASET.KEYPOINT.NUM): + for j in range(len(shifts)): + if j == 0: + lb = dr[w].argmax() + y, x = np.unravel_index(lb, dr[w].shape) + dr[w, y, x] = 0 + x -= border + y -= border + lb = dr[w].argmax() + py, px = np.unravel_index(lb, dr[w].shape) + dr[w, py, px] = 0 + px -= border + x + py -= border + y + ln = (px ** 2 + py ** 2) ** 0.5 + if ln > 1e-3: + x += shifts[j] * px / ln + y += shifts[j] * py / ln + x = max(0, min(x, cfg.OUTPUT_SHAPE[1] - 1)) + y = max(0, min(y, cfg.OUTPUT_SHAPE[0] - 1)) + kps[w] = np.array([x * 4 + 2, y * 4 + 2]) + scores[w, 0] = score_map[w, int(round(y) + 1e-9), \ + int(round(x) + 1e-9)] + # aligned or not ... + kps[:, 0] = kps[:, 0] / cfg.INPUT_SHAPE[1] * scales[i][0] + \ + centers[i][0] - scales[i][0] * 0.5 + kps[:, 1] = kps[:, 1] / cfg.INPUT_SHAPE[0] * scales[i][1] + \ + centers[i][1] - scales[i][1] * 0.5 + preds[i] = kps + maxvals[i] = scores + + return preds, maxvals + + +def compute_on_dataset(data_loader, device="cpu"): + results = list() + cpu_device = torch.device("cpu") + + results = list() + data = tqdm(data_loader) if is_main_process() else data_loader + k = 0 + for _, batch in enumerate(data): + imgs, scores, centers, scales, img_ids = batch + output_name='img_%d_%d_1.bin' %(int(img_ids[0]), k) + output_path=os.path.join('result/dumpOutput_device0/',output_name) + outputs = np.fromfile(output_path, dtype=np.float32).reshape(1,17,64,48) + k += 1 + + centers = np.array(centers) + scales = np.array(scales) + preds, maxvals = get_results(outputs, centers, scales, + cfg.TEST.GAUSSIAN_KERNEL, cfg.TEST.SHIFT_RATIOS) + + kp_scores = maxvals.squeeze(-1).mean(axis=1) + preds = np.concatenate((preds, maxvals), axis=2) + + for i in range(preds.shape[0]): + keypoints = preds[i].reshape(-1).tolist() + score = scores[i] * kp_scores[i] + image_id = img_ids[i] + + results.append(dict(image_id=image_id, + category_id=1, + keypoints=keypoints, + score=score)) + return results + + +def _accumulate_predictions_from_multiple_gpus(predictions_per_gpu, logger): + if is_main_process(): + logger.info("Accumulating ...") + all_predictions = all_gather(predictions_per_gpu) + + if not is_main_process(): + return + + predictions = list() + for p in all_predictions: + predictions.extend(p) + + return predictions + + +def inference(data_loader, logger, device="cpu"): + predictions = compute_on_dataset(data_loader, device) + synchronize() + predictions = _accumulate_predictions_from_multiple_gpus( + predictions, logger) + + if not is_main_process(): + return + + return predictions + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--local_rank", type=int, default=0) + parser.add_argument("--iter", "-i", type=int, default=-1) + parser.add_argument("--datasets_path",default="$MSPN_HOME/dataset/COCO") + args = parser.parse_args() + COCODataset.cur_dir=os.path.join(args.datasets_path) + num_gpus = int( + os.environ["WORLD_SIZE"]) if "WORLD_SIZE" in os.environ else 1 + distributed = num_gpus > 1 + + if distributed: + torch.cuda.set_device(args.local_rank) + dist.init_process_group(backend="nccl", init_method="env://") + synchronize() + + if is_main_process() and not os.path.exists(cfg.TEST_DIR): + os.mkdir(cfg.TEST_DIR) + logger = get_logger( + cfg.DATASET.NAME, cfg.TEST_DIR, args.local_rank, 'test_log.txt') + + if args.iter == -1: + logger.info("Please designate one iteration.") + + data_loader = get_test_loader(cfg, num_gpus, args.local_rank, 'val', + is_dist=distributed) + + device = 'cpu' + results = inference(data_loader, logger, device) + synchronize() + + if is_main_process(): + logger.info("Dumping results ...") + results.sort( + key=lambda res:(res['image_id'], res['score']), reverse=True) + results_path = os.path.join(cfg.TEST_DIR, 'results.json') + with open(results_path, 'w') as f: + json.dump(results, f) + logger.info("Get all results.") + + data_loader.ori_dataset.evaluate(results_path) + + +if __name__ == '__main__': + begin = time.time() + main() + end = time.time() print('postprocess finished in', str(end - begin), 'seconds') \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/MSPN_preprocess.py b/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/MSPN_preprocess.py index 616cf39bf5..cdc9cbb898 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/MSPN_preprocess.py +++ b/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/MSPN_preprocess.py @@ -1,90 +1,90 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -sys.path.append('./exps/mspn.2xstg.coco/') -import numpy as np -import torch -import torchvision.transforms as transforms -from dataset.attribute import load_dataset -from config import cfg - -from dataset.attribute import load_dataset -from dataset.COCO.coco import COCODataset - - -def preprocess(save_path: str): - cpu_device = torch.device("cpu") - normalize = transforms.Normalize(mean=cfg.INPUT.MEANS, std=cfg.INPUT.STDS) - transform = transforms.Compose([transforms.ToTensor(), normalize]) - attr = load_dataset(cfg.DATASET.NAME) - stage='val' - if cfg.DATASET.NAME == 'COCO': - Dataset = COCODataset - dataset = Dataset(attr, stage, transform) - # -------- make data_loader -------- # - class BatchCollator(object): - def __init__(self, size_divisible): - self.size_divisible = size_divisible - def __call__(self, batch): - transposed_batch = list(zip(*batch)) - images = torch.stack(transposed_batch[0], dim=0) - scores = list(transposed_batch[1]) - centers = list(transposed_batch[2]) - scales = list(transposed_batch[3]) - image_ids = list(transposed_batch[4]) - - return images, scores, centers, scales, image_ids - - data_loader = torch.utils.data.DataLoader( - dataset,batch_size=1,collate_fn=BatchCollator(cfg.DATALOADER.SIZE_DIVISIBILITY), ) - data_loader.ori_dataset = dataset - - data=data_loader - i = 0 - for _, batch in enumerate(data): - imgs, scores, centers, scales, img_ids = batch - print("=========",img_ids) - id=[str(x)for x in img_ids] - idx="".join(id) - imgs = imgs.to(cpu_device).numpy() - imgs.tofile(os.path.join(save_path,'img_' + idx + '_' + str(i)+ ".bin")) - i += 1 - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--datasets_path",default="$MSPN_HOME/dataset/COCO") - args = parser.parse_args() - COCODataset.cur_dir=os.path.join(args.datasets_path) - save_path = "./pre_dataset" - if not os.path.exists(save_path): - os.makedirs(save_path) - preprocess(save_path) - - - - - - - - - - - - - - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +sys.path.append('./exps/mspn.2xstg.coco/') +import numpy as np +import torch +import torchvision.transforms as transforms +from dataset.attribute import load_dataset +from config import cfg + +from dataset.attribute import load_dataset +from dataset.COCO.coco import COCODataset + + +def preprocess(save_path: str): + cpu_device = torch.device("cpu") + normalize = transforms.Normalize(mean=cfg.INPUT.MEANS, std=cfg.INPUT.STDS) + transform = transforms.Compose([transforms.ToTensor(), normalize]) + attr = load_dataset(cfg.DATASET.NAME) + stage='val' + if cfg.DATASET.NAME == 'COCO': + Dataset = COCODataset + dataset = Dataset(attr, stage, transform) + # -------- make data_loader -------- # + class BatchCollator(object): + def __init__(self, size_divisible): + self.size_divisible = size_divisible + def __call__(self, batch): + transposed_batch = list(zip(*batch)) + images = torch.stack(transposed_batch[0], dim=0) + scores = list(transposed_batch[1]) + centers = list(transposed_batch[2]) + scales = list(transposed_batch[3]) + image_ids = list(transposed_batch[4]) + + return images, scores, centers, scales, image_ids + + data_loader = torch.utils.data.DataLoader( + dataset,batch_size=1,collate_fn=BatchCollator(cfg.DATALOADER.SIZE_DIVISIBILITY), ) + data_loader.ori_dataset = dataset + + data=data_loader + i = 0 + for _, batch in enumerate(data): + imgs, scores, centers, scales, img_ids = batch + print("=========",img_ids) + id=[str(x)for x in img_ids] + idx="".join(id) + imgs = imgs.to(cpu_device).numpy() + imgs.tofile(os.path.join(save_path,'img_' + idx + '_' + str(i)+ ".bin")) + i += 1 + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("--datasets_path",default="$MSPN_HOME/dataset/COCO") + args = parser.parse_args() + COCODataset.cur_dir=os.path.join(args.datasets_path) + save_path = "./pre_dataset" + if not os.path.exists(save_path): + os.makedirs(save_path) + preprocess(save_path) + + + + + + + + + + + + + + + diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/MSPN_pth2onnx.py b/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/MSPN_pth2onnx.py index 3624abdf8a..86e36f5f6c 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/MSPN_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/MSPN_pth2onnx.py @@ -1,53 +1,53 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -sys.path.append('./exps/mspn.2xstg.coco/') -import torch -from config import cfg -from network import MSPN -import torch.onnx - - -def main(): - - model = MSPN(cfg) - - model_file = os.path.join(cfg.OUTPUT_DIR, "mspn_2xstg_coco.pth") - if os.path.exists(model_file): - print('MSPN loaded') - state_dict = torch.load( - model_file, map_location=lambda storage, loc: storage) - state_dict = state_dict['model'] - model.load_state_dict(state_dict) - model.eval() - - dummy_input= torch.randn(32, 3, 256, 192) - dynamic_axes = {'input': {0: '-1'}, 'output': {0: '-1'}} - export_onnx_file = "MSPN.onnx" - torch.onnx.export(model, # model being run - dummy_input, # model input (or a tuple for multiple inputs) - export_onnx_file, # where to save the model (can be a file or file-like object) - export_params=True, # store the trained parameter weights inside the model file - opset_version=11, # the ONNX version to export the model to - do_constant_folding=True, # whether to execute constant folding for optimization - input_names = ['input'], # the model's input names - output_names = ['output'], # the model's output names - dynamic_axes=dynamic_axes, # variable lenght axes - ) - - -if __name__ == '__main__': - main() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +sys.path.append('./exps/mspn.2xstg.coco/') +import torch +from config import cfg +from network import MSPN +import torch.onnx + + +def main(): + + model = MSPN(cfg) + + model_file = os.path.join(cfg.OUTPUT_DIR, "mspn_2xstg_coco.pth") + if os.path.exists(model_file): + print('MSPN loaded') + state_dict = torch.load( + model_file, map_location=lambda storage, loc: storage) + state_dict = state_dict['model'] + model.load_state_dict(state_dict) + model.eval() + + dummy_input= torch.randn(32, 3, 256, 192) + dynamic_axes = {'input': {0: '-1'}, 'output': {0: '-1'}} + export_onnx_file = "MSPN.onnx" + torch.onnx.export(model, # model being run + dummy_input, # model input (or a tuple for multiple inputs) + export_onnx_file, # where to save the model (can be a file or file-like object) + export_params=True, # store the trained parameter weights inside the model file + opset_version=11, # the ONNX version to export the model to + do_constant_folding=True, # whether to execute constant folding for optimization + input_names = ['input'], # the model's input names + output_names = ['output'], # the model's output names + dynamic_axes=dynamic_axes, # variable lenght axes + ) + + +if __name__ == '__main__': + main() diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/README.md b/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/README.md index bbfc1e7e0c..230f66a204 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/README.md +++ b/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/README.md @@ -1,64 +1,64 @@ -# MSPN模型PyTorch离线推理指导 - -## 1 环境准备 - -1. 下载源代码 - -``` -git clone https://github.com/megvii-research/MSPN -b master -cd MSPN -``` - -1. 设置环境变量,将当前目录设置为程序运行的主目录 - - ``` - export MSPN_HOME=$(pwd) - export PYTHONPATH=$PYTHONPATH:$MSPN_HOME - ``` - -3. 配置环境要求 - - ``` - pip3 install -r requirements.txt - ``` - -4. 下载COCOAPI - - ``` - git clone https://github.com/cocodataset/cocoapi.git $MSPN_HOME/lib/COCOAPI - cd $MSPN_HOME/lib/COCOAPI/PythonAPI - make install - ``` - -5. 下载数据集 - -(1)下载COCO2014数据集[COCO website][1], 将 train2014/val2014文件夹分别放在“$MSPN_HOME/dataset/COCO/images/” 目录下. - -(2)下载测试结果[Detection result][2], 把它放在“ $MSPN_HOME/dataset/COCO/det_json/”目录下. - -(3)将预训练好的权重文件 “mspn_2xstg_coco.pth”放在当前目录 - -6.[获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer),将benchmark.x86_64或benchmark.aarch64放到当前工作目录 - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 - -``` -bash test/pth2om.sh -bash test/test.sh -bash test/performance_test.sh -``` - -**评测结果:** - -| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | -| --------- | ----------- | --------------- | ---------- | ---------- | -| MSPN bs1 | 74.5 | 74.1 | 372.45fps | 401.74fps | -| MSPN bs16 | 74.5 | 74.1 | 712.271fps | 436.868fps | - -## 相关链接 - -[1]: http://cocodataset.org/#download -[2]: https://drive.google.com/open?id=1MW27OY_4YetEZ4JiD4PltFGL_1-caECy - +# MSPN模型PyTorch离线推理指导 + +## 1 环境准备 + +1. 下载源代码 + +``` +git clone https://github.com/megvii-research/MSPN -b master +cd MSPN +``` + +1. 设置环境变量,将当前目录设置为程序运行的主目录 + + ``` + export MSPN_HOME=$(pwd) + export PYTHONPATH=$PYTHONPATH:$MSPN_HOME + ``` + +3. 配置环境要求 + + ``` + pip3 install -r requirements.txt + ``` + +4. 下载COCOAPI + + ``` + git clone https://github.com/cocodataset/cocoapi.git $MSPN_HOME/lib/COCOAPI + cd $MSPN_HOME/lib/COCOAPI/PythonAPI + make install + ``` + +5. 下载数据集 + +(1)下载COCO2014数据集[COCO website][1], 将 train2014/val2014文件夹分别放在“$MSPN_HOME/dataset/COCO/images/” 目录下. + +(2)下载测试结果[Detection result][2], 把它放在“ $MSPN_HOME/dataset/COCO/det_json/”目录下. + +(3)将预训练好的权重文件 “mspn_2xstg_coco.pth”放在当前目录 + +6.[获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer),将benchmark.x86_64或benchmark.aarch64放到当前工作目录 + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 + +``` +bash test/pth2om.sh +bash test/test.sh +bash test/performance_test.sh +``` + +**评测结果:** + +| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | +| --------- | ----------- | --------------- | ---------- | ---------- | +| MSPN bs1 | 74.5 | 74.1 | 372.45fps | 401.74fps | +| MSPN bs16 | 74.5 | 74.1 | 712.271fps | 436.868fps | + +## 相关链接 + +[1]: http://cocodataset.org/#download +[2]: https://drive.google.com/open?id=1MW27OY_4YetEZ4JiD4PltFGL_1-caECy + diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/gen_dataset_info.py index 85c04dfdfc..72ba5e05c5 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/gen_dataset_info.py @@ -1,37 +1,37 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_info = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, info in enumerate(bin_info): - content = ' '.join([str(index), info, width, height]) - file.write(content) - file.write('\n') - - - - -if __name__ == '__main__': - file_path = sys.argv[1] - info_name = sys.argv[2] - width =sys.argv[3] - height =sys.argv[4] - get_bin_info(file_path, info_name, width, height) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_info = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, info in enumerate(bin_info): + content = ' '.join([str(index), info, width, height]) + file.write(content) + file.write('\n') + + + + +if __name__ == '__main__': + file_path = sys.argv[1] + info_name = sys.argv[2] + width =sys.argv[3] + height =sys.argv[4] + get_bin_info(file_path, info_name, width, height) diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/modelzoo_level.txt index 9e95396651..27e6c78b37 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:POK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/test/perf_g.sh b/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/test/perf_g.sh index 0ebe93e395..047e1c6670 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/test/perf_g.sh +++ b/ACL_PyTorch/contrib/cv/pose_estimation/MSPN/test/perf_g.sh @@ -1,23 +1,23 @@ -#!/bin/bash - -rm -rf perf_bs1.log -trtexec --onnx=MSPN.onnx --fp16 --shapes='input:1x3x256x192' –-fp16 --dumpProfile > perf_bs1.log -perf_str=`grep "GPU.* mean.*ms$" perf_bs1.log` -if [ -n "$perf_str" ]; then - perf_num=`echo $perf_str | awk -F' ' '{print $16}'` -else - perf_str=`grep "mean.*ms$" perf_bs1.log` - perf_num=`echo $perf_str | awk -F' ' '{print $4}'` -fi -awk 'BEGIN{printf "t4 bs1 fps:%.3f\n", 1000*1/('$perf_num'/1)}' - -rm -rf perf_bs16.log -trtexec --onnx=MSPN.onnx --fp16 --shapes='input:16x3x256x192' > perf_bs16.log -perf_str=`grep "GPU.* mean.*ms$" perf_bs16.log` -if [ -n "$perf_str" ]; then - perf_num=`echo $perf_str | awk -F' ' '{print $16}'` -else - perf_str=`grep "mean.*ms$" perf_bs16.log` - perf_num=`echo $perf_str | awk -F' ' '{print $4}'` -fi -awk 'BEGIN{printf "t4 bs16 fps:%.3f\n", 1000*1/('$perf_num'/16)}' +#!/bin/bash + +rm -rf perf_bs1.log +trtexec --onnx=MSPN.onnx --fp16 --shapes='input:1x3x256x192' –-fp16 --dumpProfile > perf_bs1.log +perf_str=`grep "GPU.* mean.*ms$" perf_bs1.log` +if [ -n "$perf_str" ]; then + perf_num=`echo $perf_str | awk -F' ' '{print $16}'` +else + perf_str=`grep "mean.*ms$" perf_bs1.log` + perf_num=`echo $perf_str | awk -F' ' '{print $4}'` +fi +awk 'BEGIN{printf "t4 bs1 fps:%.3f\n", 1000*1/('$perf_num'/1)}' + +rm -rf perf_bs16.log +trtexec --onnx=MSPN.onnx --fp16 --shapes='input:16x3x256x192' > perf_bs16.log +perf_str=`grep "GPU.* mean.*ms$" perf_bs16.log` +if [ -n "$perf_str" ]; then + perf_num=`echo $perf_str | awk -F' ' '{print $16}'` +else + perf_str=`grep "mean.*ms$" perf_bs16.log` + perf_num=`echo $perf_str | awk -F' ' '{print $4}'` +fi +awk 'BEGIN{printf "t4 bs16 fps:%.3f\n", 1000*1/('$perf_num'/16)}' diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/TransPose/fusion_switch.cfg b/ACL_PyTorch/contrib/cv/pose_estimation/TransPose/fusion_switch.cfg index 7e5b78e80e..7635898ef0 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/TransPose/fusion_switch.cfg +++ b/ACL_PyTorch/contrib/cv/pose_estimation/TransPose/fusion_switch.cfg @@ -1,2 +1,2 @@ -ReshapeTransposeFusionPass:off +ReshapeTransposeFusionPass:off TransposeReshapeFusionPass:off \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/TransPose/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/pose_estimation/TransPose/modelzoo_level.txt index c80d660077..d5130dbf73 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/TransPose/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/pose_estimation/TransPose/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -ModelConvert:OK +FuncStatus:OK +PrecisionStatus:OK +ModelConvert:OK PerfStatus=OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/VideoPose3D/LISCENCE b/ACL_PyTorch/contrib/cv/pose_estimation/VideoPose3D/LISCENCE index df2c2f2c3e..c8ec075d5b 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/VideoPose3D/LISCENCE +++ b/ACL_PyTorch/contrib/cv/pose_estimation/VideoPose3D/LISCENCE @@ -1,203 +1,203 @@ -Copyright 2018-2019 Open-MMLab. All rights reserved. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018-2019 Open-MMLab. - - 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 +Copyright 2018-2019 Open-MMLab. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2019 Open-MMLab. + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/VideoPose3D/README.md b/ACL_PyTorch/contrib/cv/pose_estimation/VideoPose3D/README.md index 41d22e57ec..19035b4f89 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/VideoPose3D/README.md +++ b/ACL_PyTorch/contrib/cv/pose_estimation/VideoPose3D/README.md @@ -1,39 +1,39 @@ -# VideoPose3D 模型 Pytorch 离线推理 -## 1. 环境准备 -1. 必要的软件依赖 - - Pytorch == 1.5.0 - - torchvision == 0.5.0 - - msame 软件,安装在当前目录下 - - numpy -2. 获取、修改与安装开源软件代码 -在当前目录下,进行以下操作 -``` -git clone https://github.com/facebookresearch/VideoPose3D.git -cd VideoPose3D -git reset 1afb1ca0f1237776518469876342fc8669d3f6a9 --hard -patch -p1 < ../vp3d.patch -mkdir checkpoint -cd .. -``` -3. 获取权重文件 -将提供的 `model_best.bin` 文件放在 `.\VideoPose3D\checkpoint` 目录下 -4. 获取数据集 -将提供的 `data` 文件夹放在 `.\VideoPose3D` 目录下 -## 2. 离线推理 -310上执行,执行时使 `npu-smi info` 查看设备状态,确保 `device` 空闲 -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh -``` -### 评测结果 -| 模型 | 官网 pth 精度 | 310 离线推理精度 | 基准性能 | 310 性能 | -|:----:|:----:|:----:|:----:|:----:| -|VideoPose3D conv1d bs1| 46.8 mm| 46.5 mm | 584834 fps | 409776 fps | -|VideoPose3D conv2d bs1| - | 46.6 mm | 605179 fps | 580903 fps | - -备注: -- 310 离线推理使用的是我用单卡自行训练的 Model,效果好于官网 -- VideoPose3D 原本代码中全程使用 conv1d(以及相应的 batchnorm1d)。考虑到转 om 后 -的 conv1d 均由 conv2d 算子实现,因此我将源码中的 conv1d 以及相应操作全部替换为 conv2d -及其相应操作。这个修改使得在 Ascend 310 上的推理性能与原本代码在 GPU 上的推理性能持平 +# VideoPose3D 模型 Pytorch 离线推理 +## 1. 环境准备 +1. 必要的软件依赖 + - Pytorch == 1.5.0 + - torchvision == 0.5.0 + - msame 软件,安装在当前目录下 + - numpy +2. 获取、修改与安装开源软件代码 +在当前目录下,进行以下操作 +``` +git clone https://github.com/facebookresearch/VideoPose3D.git +cd VideoPose3D +git reset 1afb1ca0f1237776518469876342fc8669d3f6a9 --hard +patch -p1 < ../vp3d.patch +mkdir checkpoint +cd .. +``` +3. 获取权重文件 +将提供的 `model_best.bin` 文件放在 `.\VideoPose3D\checkpoint` 目录下 +4. 获取数据集 +将提供的 `data` 文件夹放在 `.\VideoPose3D` 目录下 +## 2. 离线推理 +310上执行,执行时使 `npu-smi info` 查看设备状态,确保 `device` 空闲 +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh +``` +### 评测结果 +| 模型 | 官网 pth 精度 | 310 离线推理精度 | 基准性能 | 310 性能 | +|:----:|:----:|:----:|:----:|:----:| +|VideoPose3D conv1d bs1| 46.8 mm| 46.5 mm | 584834 fps | 409776 fps | +|VideoPose3D conv2d bs1| - | 46.6 mm | 605179 fps | 580903 fps | + +备注: +- 310 离线推理使用的是我用单卡自行训练的 Model,效果好于官网 +- VideoPose3D 原本代码中全程使用 conv1d(以及相应的 batchnorm1d)。考虑到转 om 后 +的 conv1d 均由 conv2d 算子实现,因此我将源码中的 conv1d 以及相应操作全部替换为 conv2d +及其相应操作。这个修改使得在 Ascend 310 上的推理性能与原本代码在 GPU 上的推理性能持平 - 即便考虑到比较 conv2d 版本在 GPU 与 Acend310 上的性能,差距也小于二者在 conv1d 下的性能 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/pose_estimation/VideoPose3D/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/pose_estimation/VideoPose3D/modelzoo_level.txt index 38700fca05..2e42553460 100644 --- a/ACL_PyTorch/contrib/cv/pose_estimation/VideoPose3D/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/pose_estimation/VideoPose3D/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/ADNet_postprocess.py b/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/ADNet_postprocess.py index 811f555e4e..f21d0790ac 100644 --- a/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/ADNet_postprocess.py +++ b/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/ADNet_postprocess.py @@ -1,91 +1,91 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 math -import torch -import torch.nn as nn -import numpy as np -from skimage.measure.simple_metrics import compare_psnr -import os -import struct -from torch.autograd import Variable -import glob -import sys - -def batch_PSNR(img, imclean, data_range): - Img = img.data.cpu().numpy().astype(np.float32) - Iclean = imclean.data.cpu().numpy().astype(np.float32) - PSNR = 0 - for i in range(Img.shape[0]): - PSNR += compare_psnr(Iclean[i,:,:,:], Img[i,:,:,:], data_range=data_range) - return (PSNR/Img.shape[0]) - -def get_output_path(bin_folder,label_path): - result_paths = [] - target_paths = [] - print("result_bin_folder:", bin_folder) - files_source = glob.glob(os.path.join(bin_folder,'*.bin')) - files_source.sort() - for file in files_source: - if file.endswith('.bin'): - result_path = file - result_paths.append(result_path) - name = (result_path.split('/')[3]).split('_')[0] - target_path = os.path.join(label_path,name+'.bin') - target_paths.append(target_path) - return result_paths,target_paths - -def file2tensor(output_bin,target_bin): - size = os.path.getsize(output_bin) - res1 = [] - L = int(size / 4) - binfile = open(output_bin, 'rb') - for i in range(L): - data = binfile.read(4) - num = struct.unpack('f', data) - res1.append(num[0]) - binfile.close() - dim_res = np.array(res1).reshape(1, 1, 321, 481) - tensor_res = torch.tensor(dim_res, dtype=torch.float32) - - size = os.path.getsize(target_bin) - res2 = [] - L = int(size / 4) - binfile = open(target_bin, 'rb') - for i in range(L): - data = binfile.read(4) - num = struct.unpack('f', data) - res2.append(num[0]) - binfile.close() - dim_res = np.array(res2).reshape(1, 1, 321, 481) - tensor_tar = torch.tensor(dim_res, dtype=torch.float32) - return tensor_res,tensor_tar - -def post_process(result_path,target_path): - output_path, target_path= get_output_path(bin_folder=result_path,label_path=label_path) - psnr_val = 0 - for i in range(len(output_path)): - output,target = file2tensor(output_path[i],target_path[i]) - Out = torch.clamp(output, 0., 1.) - psnr = batch_PSNR(Out, target, 1.) - name = (output_path[i].split('/')[3]).split('_')[0] - print(name,batch_PSNR(output, target, 1.)) - psnr_val += psnr - psnr_val /= i - print('average psnr_val:',psnr_val) - -if __name__ == "__main__": - result_path = sys.argv[1] - label_path = sys.argv[2] - post_process(result_path = result_path, target_path = label_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 math +import torch +import torch.nn as nn +import numpy as np +from skimage.measure.simple_metrics import compare_psnr +import os +import struct +from torch.autograd import Variable +import glob +import sys + +def batch_PSNR(img, imclean, data_range): + Img = img.data.cpu().numpy().astype(np.float32) + Iclean = imclean.data.cpu().numpy().astype(np.float32) + PSNR = 0 + for i in range(Img.shape[0]): + PSNR += compare_psnr(Iclean[i,:,:,:], Img[i,:,:,:], data_range=data_range) + return (PSNR/Img.shape[0]) + +def get_output_path(bin_folder,label_path): + result_paths = [] + target_paths = [] + print("result_bin_folder:", bin_folder) + files_source = glob.glob(os.path.join(bin_folder,'*.bin')) + files_source.sort() + for file in files_source: + if file.endswith('.bin'): + result_path = file + result_paths.append(result_path) + name = (result_path.split('/')[3]).split('_')[0] + target_path = os.path.join(label_path,name+'.bin') + target_paths.append(target_path) + return result_paths,target_paths + +def file2tensor(output_bin,target_bin): + size = os.path.getsize(output_bin) + res1 = [] + L = int(size / 4) + binfile = open(output_bin, 'rb') + for i in range(L): + data = binfile.read(4) + num = struct.unpack('f', data) + res1.append(num[0]) + binfile.close() + dim_res = np.array(res1).reshape(1, 1, 321, 481) + tensor_res = torch.tensor(dim_res, dtype=torch.float32) + + size = os.path.getsize(target_bin) + res2 = [] + L = int(size / 4) + binfile = open(target_bin, 'rb') + for i in range(L): + data = binfile.read(4) + num = struct.unpack('f', data) + res2.append(num[0]) + binfile.close() + dim_res = np.array(res2).reshape(1, 1, 321, 481) + tensor_tar = torch.tensor(dim_res, dtype=torch.float32) + return tensor_res,tensor_tar + +def post_process(result_path,target_path): + output_path, target_path= get_output_path(bin_folder=result_path,label_path=label_path) + psnr_val = 0 + for i in range(len(output_path)): + output,target = file2tensor(output_path[i],target_path[i]) + Out = torch.clamp(output, 0., 1.) + psnr = batch_PSNR(Out, target, 1.) + name = (output_path[i].split('/')[3]).split('_')[0] + print(name,batch_PSNR(output, target, 1.)) + psnr_val += psnr + psnr_val /= i + print('average psnr_val:',psnr_val) + +if __name__ == "__main__": + result_path = sys.argv[1] + label_path = sys.argv[2] + post_process(result_path = result_path, target_path = label_path) #get_output_path(bin_folder = 'result/dumpOutput_device0') \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/ADNet_preprocess.py b/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/ADNet_preprocess.py index 39aca261a2..edfcfaae98 100644 --- a/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/ADNet_preprocess.py +++ b/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/ADNet_preprocess.py @@ -1,65 +1,65 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import os.path -import numpy as np -import random -import torch -import cv2 -import glob -import torch.utils.data as udata -from utils import data_augmentation -from torch.autograd import Variable -import sys - -def normalize(data): - return data/255. - -def preprocess(data_path = './data/BSD68',save_path='./prep_dataset'): - files_source = glob.glob(os.path.join(data_path, '*.png')) - files_source.sort() - # process data - psnr_test = 0 - for f in files_source: - # image - Img = cv2.imread(f) - H = Img.shape[0] - W = Img.shape[1] - if H > W: - Img= cv2.flip(cv2.transpose(Img), 1) - Img = normalize(np.float32(Img[:,:,0])) - Img = np.expand_dims(Img, 0) - Img = np.expand_dims(Img, 1) - ISource = torch.Tensor(Img) - # noise - torch.manual_seed(0) #set the seed - noise = torch.FloatTensor(ISource.size()).normal_(mean=0, std=25/255.) - # noisy image - INoisy = ISource + noise - ISource = Variable(ISource) - INoisy = Variable(INoisy) - print(f,'has benn transformed into binary file') - name = (f.split('/')[3]).split('.')[0] - ISource = np.array(ISource).astype(np.float32) - if not os.path.exists(os.path.join(save_path,'ISoure')): - os.makedirs(os.path.join(save_path,'ISoure')) - if not os.path.exists(os.path.join(save_path,'INoisy')): - os.makedirs(os.path.join(save_path,'INoisy')) - ISource.tofile(os.path.join(save_path,'ISoure',name+'.bin')) - INoisy = np.array(INoisy).astype(np.float32) - INoisy.tofile(os.path.join(save_path,'INoisy',name+'.bin')) -if __name__ == '__main__': - data_path = sys.argv[1] - save_path = sys.argv[2] - preprocess(data_path,save_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import os.path +import numpy as np +import random +import torch +import cv2 +import glob +import torch.utils.data as udata +from utils import data_augmentation +from torch.autograd import Variable +import sys + +def normalize(data): + return data/255. + +def preprocess(data_path = './data/BSD68',save_path='./prep_dataset'): + files_source = glob.glob(os.path.join(data_path, '*.png')) + files_source.sort() + # process data + psnr_test = 0 + for f in files_source: + # image + Img = cv2.imread(f) + H = Img.shape[0] + W = Img.shape[1] + if H > W: + Img= cv2.flip(cv2.transpose(Img), 1) + Img = normalize(np.float32(Img[:,:,0])) + Img = np.expand_dims(Img, 0) + Img = np.expand_dims(Img, 1) + ISource = torch.Tensor(Img) + # noise + torch.manual_seed(0) #set the seed + noise = torch.FloatTensor(ISource.size()).normal_(mean=0, std=25/255.) + # noisy image + INoisy = ISource + noise + ISource = Variable(ISource) + INoisy = Variable(INoisy) + print(f,'has benn transformed into binary file') + name = (f.split('/')[3]).split('.')[0] + ISource = np.array(ISource).astype(np.float32) + if not os.path.exists(os.path.join(save_path,'ISoure')): + os.makedirs(os.path.join(save_path,'ISoure')) + if not os.path.exists(os.path.join(save_path,'INoisy')): + os.makedirs(os.path.join(save_path,'INoisy')) + ISource.tofile(os.path.join(save_path,'ISoure',name+'.bin')) + INoisy = np.array(INoisy).astype(np.float32) + INoisy.tofile(os.path.join(save_path,'INoisy',name+'.bin')) +if __name__ == '__main__': + data_path = sys.argv[1] + save_path = sys.argv[2] + preprocess(data_path,save_path) diff --git a/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/ADNet_pth2onnx.py b/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/ADNet_pth2onnx.py index 6c9de26ee2..53f032df8e 100644 --- a/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/ADNet_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/ADNet_pth2onnx.py @@ -1,49 +1,49 @@ - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 models import ADNet -import torch -import torch.onnx -import sys -from collections import OrderedDict -def proc_nodes_module(checkpoint): - new_state_dict = OrderedDict() - for k, v in checkpoint.items(): - if "module." in k: - name = k.replace("module.", "") - else: - name = k - new_state_dict[name] = v - return new_state_dict - -def pth2onnx(path, output_file1): - net = ADNet(channels=1, num_of_layers=17) - model = net #model = nn.DataParallel(net, device_ids=device_ids).cuda() - checkpoint = torch.load(path, map_location='cpu') - checkpoint = proc_nodes_module(checkpoint) - model.load_state_dict(checkpoint) - model.eval() - input_names = ["image"] - output_names = ["output1"] - dynamic_axes = {'image': {0: '-1'}, 'output1': {0: '-1'}} - dummy_input1 = torch.randn(1, 1, 321, 481) - torch.onnx.export(model, dummy_input1, output_file1, input_names = input_names, dynamic_axes = dynamic_axes,output_names = output_names, opset_version=11, verbose=True) - print("ADNET onnx has transformed successfully and this model supports dynamic axes") - print('onnx export done.') - -if __name__ == "__main__": - path = sys.argv[1] - onnx_path = sys.argv[2] + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 models import ADNet +import torch +import torch.onnx +import sys +from collections import OrderedDict +def proc_nodes_module(checkpoint): + new_state_dict = OrderedDict() + for k, v in checkpoint.items(): + if "module." in k: + name = k.replace("module.", "") + else: + name = k + new_state_dict[name] = v + return new_state_dict + +def pth2onnx(path, output_file1): + net = ADNet(channels=1, num_of_layers=17) + model = net #model = nn.DataParallel(net, device_ids=device_ids).cuda() + checkpoint = torch.load(path, map_location='cpu') + checkpoint = proc_nodes_module(checkpoint) + model.load_state_dict(checkpoint) + model.eval() + input_names = ["image"] + output_names = ["output1"] + dynamic_axes = {'image': {0: '-1'}, 'output1': {0: '-1'}} + dummy_input1 = torch.randn(1, 1, 321, 481) + torch.onnx.export(model, dummy_input1, output_file1, input_names = input_names, dynamic_axes = dynamic_axes,output_names = output_names, opset_version=11, verbose=True) + print("ADNET onnx has transformed successfully and this model supports dynamic axes") + print('onnx export done.') + +if __name__ == "__main__": + path = sys.argv[1] + onnx_path = sys.argv[2] pth2onnx(path, onnx_path) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/README.md b/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/README.md index 53bb64a010..e01ab95242 100644 --- a/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/README.md +++ b/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/README.md @@ -1,296 +1,296 @@ -# ADNet推理说明 - -## 1 模型概述 - -- **[论文地址](https://www.sciencedirect.com/science/article/pii/S0893608019304241)** -- **[代码地址](https://github.com/hellloxiaotian/ADNet)** - -### 1.1 论文地址 - -[ADNet论文](https://www.sciencedirect.com/science/article/pii/S0893608019304241) - -### 1.2 代码地址 - -[ADNet代码](https://github.com/hellloxiaotian/ADNet) - -branch:master - -commitid:commit 997df8f0cd5cebe2d26a1468c866dd927512686f - - -## 2 环境说明 - -- 深度学习框架 -- python第三方库 - -### 2.1 深度学习框架 - -``` -python3.7.5 -CANN 5.0.2 - -pytorch == 1.5.0 -torchvision == 0.5.0 -onnx == 1.7.0 -onnx-simplifier == 0.3.6 -``` - -### 2.2 python第三方库 - -``` -numpy == 1.21.2 -Pillow == 8.3.0 -opencv-python == 4.5.3.56 -scikit-image==0.16.2 -``` - -## 3 模型转换 - -- pth转om模型 - -### 3.1 pth转om模型 - -1.获取pth权重文件 - -[pth权重文件](https://github.com/hellloxiaotian/ADNet/blob/master/gray/g25/model_70.pth -) md5sum:7a93fb1f437cbce0fd235daaa7b9cffd - -2.下载ADNet推理代码 - -``` -git clone https://gitee.com/wang-chaojiemayj/modelzoo.git -cd modelzoo -git checkout tuili -``` -进入ADNet目录 -``` -cd ./contrib/ACL_PyTorch/Research/cv/quality_enhancement/ADnet -``` -3.pth模型转onnx模型,onnx转成om模型 - -pth模型转onnx模型 -``` -python3.7.5 ADNet_pth2onnx.py model_70.pth ADNet.onnx -``` -onnx转出om -``` -source env.sh(注意,latest是一个软连接,请将服务器中的/usr/local/Ascend/ascend-toolkit/latest 指向5.0.2版本的CANN包) -# bs1 -atc --framework=5 --model=ADNet.onnx --output=ADNet_bs1 --input_format=NCHW --input_shape="image:1,1,321,481" --log=debug --soc_version=Ascend310 -#bs16 -atc --framework=5 --model=ADNet.onnx --output=ADNet_bs16 --input_format=NCHW --input_shape="image:16,1,321,481" --log=debug --soc_version=Ascend310 -``` - -## 4 数据集预处理 - -- 数据集获取 -- 数据预处理 -- 生成数据集信息文件 - -### 4.1 数据集获取 - -本模型支持BSD68数据集共68张数据集,可从百度云盘下载 - -链接:https://pan.baidu.com/s/1XiePOuutbAuKRRTV949FlQ -提取码:0315 - -文件结构如下 - -``` -|ADNet--test -| | |--pth2om.sh -| | |--perf_t4.sh -| | |--parse.py -| | |--eval_acc_perf.sh -| |--datset -| | |--BSD68 -| |--prep_dataset -| | |--ISoure -| | |--INoisy -| |--util.py -| |--requirements.tx -| |--models.py -| |--gen_dataset_info.py -| |--env.sh -| |--ADNet_pth2onnx.py -| |--ADNet_preprocess.py -| |--ADNet_postprocess.py -``` - - -### 4.2 数据集预处理 - -运行ADNet_preprocess.py -``` -python3.7.5 ADNet_preprocess.py ./dataset/BSD68 ./prep_dataset -``` -二进制文件将保存在./prep_dataset目录下 - -### 4.3 生成数据集信息文件 - -1.执行生成数据集信息脚本gen_dataset_info.py,生成数据集信息文件 - -``` -python3.7.5 gen_dataset_info.py ./prep_dataset/INoisy ADNet_prep_bin.info 481 321 -``` - -## 5 离线推理 - -- benchmark工具概述 -- 离线推理 - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN 5.0.1 推理benchmark工具用户指南 01 - -### 5.2 离线推理 - -1.设置环境变量 - -``` -source env.sh -``` - -2.执行离线推理 - -``` -bs1: -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=./ADNet_bs1.om -input_text_path=./ADNet_prep_bin.info -input_width=481 -input_height=321 -output_binary=True -useDvpp=False -bs16: -./benchmark.x86_64 -model_type=vision -device_id=1 -batch_size=16 -om_path=./ADNet_bs16.om -input_text_path=./ADNet_prep_bin.info -input_width=481 -input_height=321 -output_binary=True -useDvpp=False -``` - -输出结果分别保存在当前目录result/dumpOutput_device0和result/dumpOutput_device1中,模型的输出有三个,其中需要的是名为output1的输出,shape为(1,19,1024,2048)(NCHW),数据类型为FP16,每个输入对应的输出对应三个_x.bin(x代表1,2,3)文件。 - -## 6 精度对比 - -- 离线推理精度 -- 开源精度 -- 开源精度对比 - -### 6.1 离线推理精度统计 - -后处理统计PSNR精度 - -调用ADNet_postprocess.py脚本推理结果与label比对,获取PSNRj精度数据,结果保存在ADNet_bs1.log和ADNet_bs4.log - -``` -python3.7.5 -u ADNet_postprocess.py ./result/dumpOutput_device0 ./prep_dataset/ISoure ./out >ADNet_bs1.log -python3.7.5 -u ADNet_postprocess.py ./result/dumpOutput_device1 ./prep_dataset/ISoure ./out >ADNet_bs16.log -``` - -第一个为benchmark输出目录,第二个标签目录,第三个为重定向输出目录 - -``` -PSNR:29.68 -``` - -经过对bs1与bs6的om测试,本模型batch1的精度与batch4的精度一致,精度数据如上 -### 6.2 开源精度 - -pth精度 - -``` -Model 论文 开源pth文件 -ADNet 29.27 29.25 -``` - -### 6.3 精度对比 - -将得到的om模型离线推理精度与pth精度作比较,om模型精度高于pth模型精度,精度达标。 - -## 7 性能对比 - -- NPU性能数据 -- T4性能数据 -- 性能对比 - -### 7.1 npu性能数据 - -1.benchmark工具在整个数据集上推理获得性能数据。 -batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: - -``` ------------------Performance Summary------------------ -[e2e] throughputRate: 21.1584, latency: 3213.85 -[data read] throughputRate: 2267.5, moduleLatency: 0.441015 -[preprocess] throughputRate: 613.431, moduleLatency: 1.63018 -[inference] throughputRate: 33.8299, Interface throughputRate: 35.7852, moduleLatency: 29.1051 -[postprocess] throughputRate: 34.309, moduleLatency: 29.1469 - ------------------------------------------------------------ -``` - -Interface throughputRate: 35.7852,35.7852x4=143.1408即是batch1 310单卡吞吐率 - -batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: - -``` ------------------Performance Summary------------------ -[e2e] throughputRate: 19.8971, latency: 3417.58 -[data read] throughputRate: 2382.7, moduleLatency: 0.419691 -[preprocess] throughputRate: 405.505, moduleLatency: 2.46606 -[inference] throughputRate: 27.4387, Interface throughputRate: 29.3584, moduleLatency: 35.5952 -[postprocess] throughputRate: 2.40737, moduleLatency: 415.392 - ------------------------------------------------------------ -``` - -Interface throughputRate: 29.3584,29.3584x4=117.4336即是batch16 310单卡吞吐率 - - -### 7.2 T4性能数据 - -在装有T4卡的服务器上测试gpu性能,测试过程请确保卡没有运行其他任务,TensorRT版本:7.2.3.4,cuda版本:11.0,cudnn版本:8.2 -batch1性能: - -``` -trtexec --onnx=ADNet.onnx --fp16 --shapes=image:1x1x321x481 --threads -``` - -``` -[09/27/2021-11:20:55] [I] GPU Compute -[09/27/2021-11:20:55] [I] min: 7.94897 ms -[09/27/2021-11:20:55] [I] max: 12.2207 ms -[09/27/2021-11:20:55] [I] mean: 8.39391 ms -[09/27/2021-11:20:55] [I] median: 8.30371 ms -[09/27/2021-11:20:55] [I] percentile: 11.1882 ms at 99% -[09/27/2021-11:20:55] [I] total compute time: 3.01341 s -``` -batch1 t4单卡吞吐率:1000/(8.39391/1)=119.134fps - -batch16性能: - -``` -trtexec --onnx=ADNet.onnx --fp16 --shapes=image:16x1x321x481 --threads -``` - -``` -[09/27/2021-11:28:53] [I] GPU Compute -[09/27/2021-11:28:53] [I] min: 125.424 ms -[09/27/2021-11:28:53] [I] max: 138.322 ms -[09/27/2021-11:28:53] [I] mean: 128.206 ms -[09/27/2021-11:28:53] [I] median: 126.907 ms -[09/27/2021-11:28:53] [I] percentile: 138.322 ms at 99% -[09/27/2021-11:28:53] [I] total compute time: 3.33335 s -``` - -batch4 t4单卡吞吐率:1000/(128.206/16)=124.799fps - -### 7.3 性能对比 - -batch1:35.7852x4 > 1000/(8.39391/1) -batch16:29.3584x4 < 000/(128.206/16) -310单个device的吞吐率乘4即单卡吞吐率与比T4单卡相比,batch1的性能:310高于T4,batch16的性能:310是T4的0.954倍,略低于T4。该模型放在contrib/ACL_PyTorch/Research目录下。 - -310与T4同时使用纯推理对batch16进行性能测试,310性能如下: - -``` ------------------PureInfer Performance Summary------------------ -[INFO] ave_throughputRate: 36.1295samples/s, ave_latency: 27.6788ms ----------------------------------------------------------------- -``` - -batch16纯推理的性能为:36.1295x4=144.518fps - -144.518>124.799,在纯推理测试性能的情况下,310性能优于T4性能。 +# ADNet推理说明 + +## 1 模型概述 + +- **[论文地址](https://www.sciencedirect.com/science/article/pii/S0893608019304241)** +- **[代码地址](https://github.com/hellloxiaotian/ADNet)** + +### 1.1 论文地址 + +[ADNet论文](https://www.sciencedirect.com/science/article/pii/S0893608019304241) + +### 1.2 代码地址 + +[ADNet代码](https://github.com/hellloxiaotian/ADNet) + +branch:master + +commitid:commit 997df8f0cd5cebe2d26a1468c866dd927512686f + + +## 2 环境说明 + +- 深度学习框架 +- python第三方库 + +### 2.1 深度学习框架 + +``` +python3.7.5 +CANN 5.0.2 + +pytorch == 1.5.0 +torchvision == 0.5.0 +onnx == 1.7.0 +onnx-simplifier == 0.3.6 +``` + +### 2.2 python第三方库 + +``` +numpy == 1.21.2 +Pillow == 8.3.0 +opencv-python == 4.5.3.56 +scikit-image==0.16.2 +``` + +## 3 模型转换 + +- pth转om模型 + +### 3.1 pth转om模型 + +1.获取pth权重文件 + +[pth权重文件](https://github.com/hellloxiaotian/ADNet/blob/master/gray/g25/model_70.pth +) md5sum:7a93fb1f437cbce0fd235daaa7b9cffd + +2.下载ADNet推理代码 + +``` +git clone https://gitee.com/wang-chaojiemayj/modelzoo.git +cd modelzoo +git checkout tuili +``` +进入ADNet目录 +``` +cd ./contrib/ACL_PyTorch/Research/cv/quality_enhancement/ADnet +``` +3.pth模型转onnx模型,onnx转成om模型 + +pth模型转onnx模型 +``` +python3.7.5 ADNet_pth2onnx.py model_70.pth ADNet.onnx +``` +onnx转出om +``` +source env.sh(注意,latest是一个软连接,请将服务器中的/usr/local/Ascend/ascend-toolkit/latest 指向5.0.2版本的CANN包) +# bs1 +atc --framework=5 --model=ADNet.onnx --output=ADNet_bs1 --input_format=NCHW --input_shape="image:1,1,321,481" --log=debug --soc_version=Ascend310 +#bs16 +atc --framework=5 --model=ADNet.onnx --output=ADNet_bs16 --input_format=NCHW --input_shape="image:16,1,321,481" --log=debug --soc_version=Ascend310 +``` + +## 4 数据集预处理 + +- 数据集获取 +- 数据预处理 +- 生成数据集信息文件 + +### 4.1 数据集获取 + +本模型支持BSD68数据集共68张数据集,可从百度云盘下载 + +链接:https://pan.baidu.com/s/1XiePOuutbAuKRRTV949FlQ +提取码:0315 + +文件结构如下 + +``` +|ADNet--test +| | |--pth2om.sh +| | |--perf_t4.sh +| | |--parse.py +| | |--eval_acc_perf.sh +| |--datset +| | |--BSD68 +| |--prep_dataset +| | |--ISoure +| | |--INoisy +| |--util.py +| |--requirements.tx +| |--models.py +| |--gen_dataset_info.py +| |--env.sh +| |--ADNet_pth2onnx.py +| |--ADNet_preprocess.py +| |--ADNet_postprocess.py +``` + + +### 4.2 数据集预处理 + +运行ADNet_preprocess.py +``` +python3.7.5 ADNet_preprocess.py ./dataset/BSD68 ./prep_dataset +``` +二进制文件将保存在./prep_dataset目录下 + +### 4.3 生成数据集信息文件 + +1.执行生成数据集信息脚本gen_dataset_info.py,生成数据集信息文件 + +``` +python3.7.5 gen_dataset_info.py ./prep_dataset/INoisy ADNet_prep_bin.info 481 321 +``` + +## 5 离线推理 + +- benchmark工具概述 +- 离线推理 + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN 5.0.1 推理benchmark工具用户指南 01 + +### 5.2 离线推理 + +1.设置环境变量 + +``` +source env.sh +``` + +2.执行离线推理 + +``` +bs1: +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=./ADNet_bs1.om -input_text_path=./ADNet_prep_bin.info -input_width=481 -input_height=321 -output_binary=True -useDvpp=False +bs16: +./benchmark.x86_64 -model_type=vision -device_id=1 -batch_size=16 -om_path=./ADNet_bs16.om -input_text_path=./ADNet_prep_bin.info -input_width=481 -input_height=321 -output_binary=True -useDvpp=False +``` + +输出结果分别保存在当前目录result/dumpOutput_device0和result/dumpOutput_device1中,模型的输出有三个,其中需要的是名为output1的输出,shape为(1,19,1024,2048)(NCHW),数据类型为FP16,每个输入对应的输出对应三个_x.bin(x代表1,2,3)文件。 + +## 6 精度对比 + +- 离线推理精度 +- 开源精度 +- 开源精度对比 + +### 6.1 离线推理精度统计 + +后处理统计PSNR精度 + +调用ADNet_postprocess.py脚本推理结果与label比对,获取PSNRj精度数据,结果保存在ADNet_bs1.log和ADNet_bs4.log + +``` +python3.7.5 -u ADNet_postprocess.py ./result/dumpOutput_device0 ./prep_dataset/ISoure ./out >ADNet_bs1.log +python3.7.5 -u ADNet_postprocess.py ./result/dumpOutput_device1 ./prep_dataset/ISoure ./out >ADNet_bs16.log +``` + +第一个为benchmark输出目录,第二个标签目录,第三个为重定向输出目录 + +``` +PSNR:29.68 +``` + +经过对bs1与bs6的om测试,本模型batch1的精度与batch4的精度一致,精度数据如上 +### 6.2 开源精度 + +pth精度 + +``` +Model 论文 开源pth文件 +ADNet 29.27 29.25 +``` + +### 6.3 精度对比 + +将得到的om模型离线推理精度与pth精度作比较,om模型精度高于pth模型精度,精度达标。 + +## 7 性能对比 + +- NPU性能数据 +- T4性能数据 +- 性能对比 + +### 7.1 npu性能数据 + +1.benchmark工具在整个数据集上推理获得性能数据。 +batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: + +``` +-----------------Performance Summary------------------ +[e2e] throughputRate: 21.1584, latency: 3213.85 +[data read] throughputRate: 2267.5, moduleLatency: 0.441015 +[preprocess] throughputRate: 613.431, moduleLatency: 1.63018 +[inference] throughputRate: 33.8299, Interface throughputRate: 35.7852, moduleLatency: 29.1051 +[postprocess] throughputRate: 34.309, moduleLatency: 29.1469 + +----------------------------------------------------------- +``` + +Interface throughputRate: 35.7852,35.7852x4=143.1408即是batch1 310单卡吞吐率 + +batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: + +``` +-----------------Performance Summary------------------ +[e2e] throughputRate: 19.8971, latency: 3417.58 +[data read] throughputRate: 2382.7, moduleLatency: 0.419691 +[preprocess] throughputRate: 405.505, moduleLatency: 2.46606 +[inference] throughputRate: 27.4387, Interface throughputRate: 29.3584, moduleLatency: 35.5952 +[postprocess] throughputRate: 2.40737, moduleLatency: 415.392 + +----------------------------------------------------------- +``` + +Interface throughputRate: 29.3584,29.3584x4=117.4336即是batch16 310单卡吞吐率 + + +### 7.2 T4性能数据 + +在装有T4卡的服务器上测试gpu性能,测试过程请确保卡没有运行其他任务,TensorRT版本:7.2.3.4,cuda版本:11.0,cudnn版本:8.2 +batch1性能: + +``` +trtexec --onnx=ADNet.onnx --fp16 --shapes=image:1x1x321x481 --threads +``` + +``` +[09/27/2021-11:20:55] [I] GPU Compute +[09/27/2021-11:20:55] [I] min: 7.94897 ms +[09/27/2021-11:20:55] [I] max: 12.2207 ms +[09/27/2021-11:20:55] [I] mean: 8.39391 ms +[09/27/2021-11:20:55] [I] median: 8.30371 ms +[09/27/2021-11:20:55] [I] percentile: 11.1882 ms at 99% +[09/27/2021-11:20:55] [I] total compute time: 3.01341 s +``` +batch1 t4单卡吞吐率:1000/(8.39391/1)=119.134fps + +batch16性能: + +``` +trtexec --onnx=ADNet.onnx --fp16 --shapes=image:16x1x321x481 --threads +``` + +``` +[09/27/2021-11:28:53] [I] GPU Compute +[09/27/2021-11:28:53] [I] min: 125.424 ms +[09/27/2021-11:28:53] [I] max: 138.322 ms +[09/27/2021-11:28:53] [I] mean: 128.206 ms +[09/27/2021-11:28:53] [I] median: 126.907 ms +[09/27/2021-11:28:53] [I] percentile: 138.322 ms at 99% +[09/27/2021-11:28:53] [I] total compute time: 3.33335 s +``` + +batch4 t4单卡吞吐率:1000/(128.206/16)=124.799fps + +### 7.3 性能对比 + +batch1:35.7852x4 > 1000/(8.39391/1) +batch16:29.3584x4 < 000/(128.206/16) +310单个device的吞吐率乘4即单卡吞吐率与比T4单卡相比,batch1的性能:310高于T4,batch16的性能:310是T4的0.954倍,略低于T4。该模型放在contrib/ACL_PyTorch/Research目录下。 + +310与T4同时使用纯推理对batch16进行性能测试,310性能如下: + +``` +-----------------PureInfer Performance Summary------------------ +[INFO] ave_throughputRate: 36.1295samples/s, ave_latency: 27.6788ms +---------------------------------------------------------------- +``` + +batch16纯推理的性能为:36.1295x4=144.518fps + +144.518>124.799,在纯推理测试性能的情况下,310性能优于T4性能。 diff --git a/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/gen_dataset_info.py index 4230a0ef58..b3349fd478 100644 --- a/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/gen_dataset_info.py @@ -1,39 +1,39 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import argparse -import glob -import sys - -def get_bin_info(img_root_path='./prep_dataset/INoisy', - info_name='ADNet_prep_bin.info', width='481', height='321'): - img_path = [] - files_source = glob.glob(os.path.join(img_root_path,'*.bin')) - files_source.sort() - for file in files_source: - if file.endswith('.bin'): - imgpath = file - img_path.append(imgpath) - with open(info_name, 'w') as fp: - for index in range(len(img_path)): - content = ' '.join([str(index), img_path[index], width, height]) - fp.write(content) - fp.write('\n') - -if __name__ == '__main__': - dataset_bin = sys.argv[1] - info_name = sys.argv[2] - width = sys.argv[3] - height = sys.argv[4] - get_bin_info(img_root_path=dataset_bin, info_name=info_name, width=width, height=height) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import argparse +import glob +import sys + +def get_bin_info(img_root_path='./prep_dataset/INoisy', + info_name='ADNet_prep_bin.info', width='481', height='321'): + img_path = [] + files_source = glob.glob(os.path.join(img_root_path,'*.bin')) + files_source.sort() + for file in files_source: + if file.endswith('.bin'): + imgpath = file + img_path.append(imgpath) + with open(info_name, 'w') as fp: + for index in range(len(img_path)): + content = ' '.join([str(index), img_path[index], width, height]) + fp.write(content) + fp.write('\n') + +if __name__ == '__main__': + dataset_bin = sys.argv[1] + info_name = sys.argv[2] + width = sys.argv[3] + height = sys.argv[4] + get_bin_info(img_root_path=dataset_bin, info_name=info_name, width=width, height=height) diff --git a/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/test/parse.py b/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/test/parse.py index 1841a9747c..e071d8fecf 100644 --- a/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/test/parse.py +++ b/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet/test/parse.py @@ -1,39 +1,39 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import re - -def get_acc(filename): - with open(filename, 'r') as f: - lines = f.readlines() - last_line = lines[-1] - psnr = last_line.split(" ")[2] - print(filename.split('.')[0],"Average PSNR:", psnr) - - -def get_perf(filename): - with open(filename, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 - print('310 bs{} fps:{}'.format(filename.split('_')[3], fps)) - -if __name__ == "__main__": - - filename = sys.argv[1] - - if filename.endswith(".log"): - get_acc(filename) - elif filename.endswith(".txt"): +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import re + +def get_acc(filename): + with open(filename, 'r') as f: + lines = f.readlines() + last_line = lines[-1] + psnr = last_line.split(" ")[2] + print(filename.split('.')[0],"Average PSNR:", psnr) + + +def get_perf(filename): + with open(filename, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 + print('310 bs{} fps:{}'.format(filename.split('_')[3], fps)) + +if __name__ == "__main__": + + filename = sys.argv[1] + + if filename.endswith(".log"): + get_acc(filename) + elif filename.endswith(".txt"): get_perf(filename) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/3d_nested_unet_postprocess.py b/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/3d_nested_unet_postprocess.py index 023869fa0a..08233a7d90 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/3d_nested_unet_postprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/3d_nested_unet_postprocess.py @@ -1,39 +1,39 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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. - -# 3d_nested_unet_postprocess.py -import sys -import os -import time -import pdb -import argparse -from nnunet.inference import predict_simple2 - - -def main(): - # pdb.set_trace() - parser = argparse.ArgumentParser() - parser.add_argument('-fp', '--file_path', help='output bin files path', required=True) - args = parser.parse_args() - python_file = predict_simple2.__file__ # /home/hyp/UNetPlusPlus/pytorch/nnunet/inference/predict_simple2.py - file_path = args.file_path - pre_mode = 2 - command = 'python3 ' + str(python_file) + ' --pre_mode ' + str(pre_mode) + ' --file_path ' + str(file_path) - os.system(command) - - -if __name__ == "__main__": - main() - print('main end') - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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. + +# 3d_nested_unet_postprocess.py +import sys +import os +import time +import pdb +import argparse +from nnunet.inference import predict_simple2 + + +def main(): + # pdb.set_trace() + parser = argparse.ArgumentParser() + parser.add_argument('-fp', '--file_path', help='output bin files path', required=True) + args = parser.parse_args() + python_file = predict_simple2.__file__ # /home/hyp/UNetPlusPlus/pytorch/nnunet/inference/predict_simple2.py + file_path = args.file_path + pre_mode = 2 + command = 'python3 ' + str(python_file) + ' --pre_mode ' + str(pre_mode) + ' --file_path ' + str(file_path) + os.system(command) + + +if __name__ == "__main__": + main() + print('main end') + diff --git a/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/3d_nested_unet_preprocess.py b/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/3d_nested_unet_preprocess.py index 143fb939b1..f20ba2697b 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/3d_nested_unet_preprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/3d_nested_unet_preprocess.py @@ -1,39 +1,39 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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. - -# 3d_nested_unet_preprocess.py -import sys -import os -import time -import pdb -import argparse -from nnunet.inference import predict_simple2 - - -def main(): - # pdb.set_trace() - parser = argparse.ArgumentParser() - parser.add_argument('-fp', '--file_path', help='input bin files path', required=True) - args = parser.parse_args() - python_file = predict_simple2.__file__ # /home/hyp/UNetPlusPlus/pytorch/nnunet/inference/predict_simple2.py - file_path = args.file_path - pre_mode = 1 - command = 'python3 ' + str(python_file) + ' --pre_mode ' + str(pre_mode) + ' --file_path ' + str(file_path) - os.system(command) - - -if __name__ == "__main__": - main() - print('main end') - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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. + +# 3d_nested_unet_preprocess.py +import sys +import os +import time +import pdb +import argparse +from nnunet.inference import predict_simple2 + + +def main(): + # pdb.set_trace() + parser = argparse.ArgumentParser() + parser.add_argument('-fp', '--file_path', help='input bin files path', required=True) + args = parser.parse_args() + python_file = predict_simple2.__file__ # /home/hyp/UNetPlusPlus/pytorch/nnunet/inference/predict_simple2.py + file_path = args.file_path + pre_mode = 1 + command = 'python3 ' + str(python_file) + ' --pre_mode ' + str(pre_mode) + ' --file_path ' + str(file_path) + os.system(command) + + +if __name__ == "__main__": + main() + print('main end') + diff --git a/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/3d_nested_unet_pth2onnx.py b/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/3d_nested_unet_pth2onnx.py index 0d8e115f5b..4aaaa6d67a 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/3d_nested_unet_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/3d_nested_unet_pth2onnx.py @@ -1,57 +1,57 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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. - -# 3d_nested_unet_pth2onnx.py -import sys -import os -import time -import pdb -import argparse -from batchgenerators.utilities.file_and_folder_operations import join, isdir -from nnunet.paths import default_plans_identifier, network_training_output_dir, default_cascade_trainer, default_trainer -from nnunet.training.model_restore import load_model_and_checkpoint_files -from nnunet.inference.predict2 import pth2onnx - - -def main(): - # pdb.set_trace() - parser = argparse.ArgumentParser() - parser.add_argument('-fp', '--file_path', help='output onnx file path', required=True) - args = parser.parse_args() - fp = args.file_path - model = '3d_fullres' - task_name = 'Task003_Liver' - trainer = 'nnUNetPlusPlusTrainerV2' - plans_identifier = 'nnUNetPlansv2.1' - model_folder_name = join(network_training_output_dir, model, task_name, trainer + "__" + plans_identifier) - model = model_folder_name - folds = None # 如果文件存放路径正确,会自动识别到教程中的fold 0 - mixed_precision = True - checkpoint_name = 'model_final_checkpoint' - trainer, params = load_model_and_checkpoint_files(model, folds, mixed_precision=mixed_precision, checkpoint_name=checkpoint_name) - pre_mode = -1 - if int(pre_mode) == -1: - p = params[0] - trainer.load_checkpoint_ram(p, False) # nnUnetPlusPlusTrainerV2,实际函数在network_trainer里 - print('pth2onnx start') - pth2onnx(trainer.network, fp) - print('pth2onnx end') - print('onnx模型已经输出至:', fp) - - -if __name__ == "__main__": - main() - print('main end') - - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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. + +# 3d_nested_unet_pth2onnx.py +import sys +import os +import time +import pdb +import argparse +from batchgenerators.utilities.file_and_folder_operations import join, isdir +from nnunet.paths import default_plans_identifier, network_training_output_dir, default_cascade_trainer, default_trainer +from nnunet.training.model_restore import load_model_and_checkpoint_files +from nnunet.inference.predict2 import pth2onnx + + +def main(): + # pdb.set_trace() + parser = argparse.ArgumentParser() + parser.add_argument('-fp', '--file_path', help='output onnx file path', required=True) + args = parser.parse_args() + fp = args.file_path + model = '3d_fullres' + task_name = 'Task003_Liver' + trainer = 'nnUNetPlusPlusTrainerV2' + plans_identifier = 'nnUNetPlansv2.1' + model_folder_name = join(network_training_output_dir, model, task_name, trainer + "__" + plans_identifier) + model = model_folder_name + folds = None # 如果文件存放路径正确,会自动识别到教程中的fold 0 + mixed_precision = True + checkpoint_name = 'model_final_checkpoint' + trainer, params = load_model_and_checkpoint_files(model, folds, mixed_precision=mixed_precision, checkpoint_name=checkpoint_name) + pre_mode = -1 + if int(pre_mode) == -1: + p = params[0] + trainer.load_checkpoint_ram(p, False) # nnUnetPlusPlusTrainerV2,实际函数在network_trainer里 + print('pth2onnx start') + pth2onnx(trainer.network, fp) + print('pth2onnx end') + print('onnx模型已经输出至:', fp) + + +if __name__ == "__main__": + main() + print('main end') + + diff --git a/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/License b/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/License index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/License +++ b/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/License @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/change_infer_path.py b/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/change_infer_path.py index a46e74d40f..e030312b17 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/change_infer_path.py +++ b/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/change_infer_path.py @@ -1,61 +1,61 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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. - -# 3d_nested_unet_preprocess.py -import sys -import os -import time -import pdb -import argparse -from nnunet.inference import infer_path - - -def main(): - # pdb.set_trace() - parser = argparse.ArgumentParser() - parser.add_argument('-fp1', '--file_path1', help='INFERENCE_INPUT_FOLDER', required=True, default='/home/hyp/environment/input/') - parser.add_argument('-fp2', '--file_path2', help='INFERENCE_OUTPUT_FOLDER', required=True, default='/home/hyp/environment/output/') - parser.add_argument('-fp3', '--file_path3', help='INFERENCE_SHAPE_PATH', required=True, default='/home/hyp/environment/') - args = parser.parse_args() - python_file = infer_path.__file__ - fp1 = args.file_path1 - fp2 = args.file_path2 - fp3 = args.file_path3 - lines = [] - print('尝试读取:', python_file) - file = open(python_file, 'r', encoding='utf-8') - lines = file.readlines() - file.close() - print('尝试修改路径') - with open(python_file, 'w', encoding='utf-8') as f: - for line in lines: - if line.startswith('INFERENCE_INPUT_FOLDER'): - line = 'INFERENCE_INPUT_FOLDER = ' + '\'' + str(fp1) + '\'' + '\n' - if line.startswith('INFERENCE_OUTPUT_FOLDER'): - line = 'INFERENCE_OUTPUT_FOLDER = ' + '\'' + str(fp2) + '\'' + '\n' - if line.startswith('INFERENCE_SHAPE_PATH'): - line = 'INFERENCE_SHAPE_PATH = ' + '\'' + str(fp3) + '\'' + '\n' - f.write(line) - print('正在修改:', python_file) - print('INFERENCE_INPUT_FOLDER =', fp1) - print('INFERENCE_OUTPUT_FOLDER=', fp2) - print('INFERENCE_SHAPE_PATH =', fp3) - f.close() - print('修改完成') - - -if __name__ == "__main__": - main() - print('main end') - +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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. + +# 3d_nested_unet_preprocess.py +import sys +import os +import time +import pdb +import argparse +from nnunet.inference import infer_path + + +def main(): + # pdb.set_trace() + parser = argparse.ArgumentParser() + parser.add_argument('-fp1', '--file_path1', help='INFERENCE_INPUT_FOLDER', required=True, default='/home/hyp/environment/input/') + parser.add_argument('-fp2', '--file_path2', help='INFERENCE_OUTPUT_FOLDER', required=True, default='/home/hyp/environment/output/') + parser.add_argument('-fp3', '--file_path3', help='INFERENCE_SHAPE_PATH', required=True, default='/home/hyp/environment/') + args = parser.parse_args() + python_file = infer_path.__file__ + fp1 = args.file_path1 + fp2 = args.file_path2 + fp3 = args.file_path3 + lines = [] + print('尝试读取:', python_file) + file = open(python_file, 'r', encoding='utf-8') + lines = file.readlines() + file.close() + print('尝试修改路径') + with open(python_file, 'w', encoding='utf-8') as f: + for line in lines: + if line.startswith('INFERENCE_INPUT_FOLDER'): + line = 'INFERENCE_INPUT_FOLDER = ' + '\'' + str(fp1) + '\'' + '\n' + if line.startswith('INFERENCE_OUTPUT_FOLDER'): + line = 'INFERENCE_OUTPUT_FOLDER = ' + '\'' + str(fp2) + '\'' + '\n' + if line.startswith('INFERENCE_SHAPE_PATH'): + line = 'INFERENCE_SHAPE_PATH = ' + '\'' + str(fp3) + '\'' + '\n' + f.write(line) + print('正在修改:', python_file) + print('INFERENCE_INPUT_FOLDER =', fp1) + print('INFERENCE_OUTPUT_FOLDER=', fp2) + print('INFERENCE_SHAPE_PATH =', fp3) + f.close() + print('修改完成') + + +if __name__ == "__main__": + main() + print('main end') + diff --git a/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/gen_dataset_info.py index 68f13f27c3..54138faa7d 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/gen_dataset_info.py @@ -1,80 +1,80 @@ -""" - Copyright 2020 Huawei Technologies Co., Ltd - - 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. - Typical usage example: -""" -import os -import sys -from glob import glob -import pdb - - -def get_bin_info(file_path, info_name, shape, split4=True): - """ - @description: get given bin information - @param file_path bin file path - @param info_name given information name - @param shape image shape - @return - """ - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, shape[0], shape[1]]) - file.write(content) - file.write('\n') - print('共计.bin文件个数:', len(bin_images)) - print('info已写入:', os.path.abspath(info_name)) - if split4: # 是否切割为4卡的info - sths = ['sth1.info', 'sth2.info', 'sth3.info', 'sth4.info'] - length = len(bin_images) - step = length // 4 - b1 = bin_images[0: step] - b2 = bin_images[step: 2*step] - b3 = bin_images[2*step: 3*step] - b4 = bin_images[3*step:] - with open(sths[0], 'w') as file: - for index, img in enumerate(b1): - content = ' '.join([str(index), img, shape[0], shape[1]]) - file.write(content) - file.write('\n') - with open(sths[1], 'w') as file: - for index, img in enumerate(b2): - content = ' '.join([str(index), img, shape[0], shape[1]]) - file.write(content) - file.write('\n') - with open(sths[2], 'w') as file: - for index, img in enumerate(b3): - content = ' '.join([str(index), img, shape[0], shape[1]]) - file.write(content) - file.write('\n') - with open(sths[3], 'w') as file: - for index, img in enumerate(b4): - content = ' '.join([str(index), img, shape[0], shape[1]]) - file.write(content) - file.write('\n') - print('成功切分为四个子集', sths) - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - shape1 = sys.argv[4] - shape2 = sys.argv[5] - shape = [shape1, shape2] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, shape) +""" + Copyright 2020 Huawei Technologies Co., Ltd + + 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. + Typical usage example: +""" +import os +import sys +from glob import glob +import pdb + + +def get_bin_info(file_path, info_name, shape, split4=True): + """ + @description: get given bin information + @param file_path bin file path + @param info_name given information name + @param shape image shape + @return + """ + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, shape[0], shape[1]]) + file.write(content) + file.write('\n') + print('共计.bin文件个数:', len(bin_images)) + print('info已写入:', os.path.abspath(info_name)) + if split4: # 是否切割为4卡的info + sths = ['sth1.info', 'sth2.info', 'sth3.info', 'sth4.info'] + length = len(bin_images) + step = length // 4 + b1 = bin_images[0: step] + b2 = bin_images[step: 2*step] + b3 = bin_images[2*step: 3*step] + b4 = bin_images[3*step:] + with open(sths[0], 'w') as file: + for index, img in enumerate(b1): + content = ' '.join([str(index), img, shape[0], shape[1]]) + file.write(content) + file.write('\n') + with open(sths[1], 'w') as file: + for index, img in enumerate(b2): + content = ' '.join([str(index), img, shape[0], shape[1]]) + file.write(content) + file.write('\n') + with open(sths[2], 'w') as file: + for index, img in enumerate(b3): + content = ' '.join([str(index), img, shape[0], shape[1]]) + file.write(content) + file.write('\n') + with open(sths[3], 'w') as file: + for index, img in enumerate(b4): + content = ' '.join([str(index), img, shape[0], shape[1]]) + file.write(content) + file.write('\n') + print('成功切分为四个子集', sths) + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + shape1 = sys.argv[4] + shape2 = sys.argv[5] + shape = [shape1, shape2] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, shape) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/new.patch b/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/new.patch index 5307bdd0c2..bc6f3df5cc 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/new.patch +++ b/ACL_PyTorch/contrib/cv/segmentation/3D_Nested_Unet/new.patch @@ -4,206 +4,206 @@ index 0000000..2a17e8a --- /dev/null +++ b/pytorch/nnunet/evaluation/model_selection/figure_out_want_to_submit2.py @@ -0,0 +1,200 @@ -+# Copyright 2020 Division of Medical Image Computing, German Cancer Research Center (DKFZ), Heidelberg, Germany -+# -+# 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 itertools import combinations -+import nnunet -+from batchgenerators.utilities.file_and_folder_operations import * -+from nnunet.evaluation.add_mean_dice_to_json import foreground_mean -+from nnunet.evaluation.model_selection.ensemble import ensemble -+from nnunet.paths import network_training_output_dir -+import numpy as np -+from subprocess import call -+from nnunet.postprocessing.consolidate_postprocessing import consolidate_folds -+from nnunet.utilities.folder_names import get_output_folder_name -+from nnunet.paths import default_cascade_trainer, default_trainer, default_plans_identifier -+ -+ -+def find_task_name(folder, task_id): -+ candidates = subdirs(folder, prefix="Task%03.0d_" % task_id, join=False) -+ assert len(candidates) > 0, "no candidate for Task id %d found in folder %s" % (task_id, folder) -+ assert len(candidates) == 1, "more than one candidate for Task id %d found in folder %s" % (task_id, folder) -+ return candidates[0] -+ -+ -+def get_mean_foreground_dice(json_file): -+ results = load_json(json_file) -+ return get_foreground_mean(results) -+ -+ -+def get_foreground_mean(results): -+ results_mean = results['results']['mean'] -+ dice_scores = [results_mean[i]['Dice'] for i in results_mean.keys() if i != "0" and i != 'mean'] -+ return np.mean(dice_scores) -+ -+ -+def main(): -+ import argparse -+ parser = argparse.ArgumentParser(usage="This is intended to identify the best model based on the five fold " -+ "cross-validation. Running this script requires all models to have been run " -+ "already. This script will summarize the results of the five folds of all " -+ "models in one json each for easy interpretability") -+ -+ parser.add_argument("-m", '--models', nargs="+", required=False, default=['3d_fullres']) -+ parser.add_argument("-t", '--task_ids', nargs="+", required=False, default='003') -+ -+ parser.add_argument("-tr", type=str, required=False, default=default_trainer, -+ help="nnUNetTrainer class. Default: %s" % default_trainer) -+ parser.add_argument("-ctr", type=str, required=False, default=default_cascade_trainer, -+ help="nnUNetTrainer class for cascade model. Default: %s" % default_cascade_trainer) -+ parser.add_argument("-pl", type=str, required=False, default=default_plans_identifier, -+ help="plans name, Default: %s" % default_plans_identifier) -+ parser.add_argument('-f', '--folds', nargs='+', default=(0, 1, 2, 3, 4), help="use this if you have non-standard folds") -+ parser.add_argument("--strict", required=False, default=True, action="store_true", -+ help="set this flag if you want this script to crash of one of the models is missing") -+ -+ args = parser.parse_args() -+ tasks = [int(i) for i in args.task_ids] -+ -+ models = args.models -+ tr = args.tr -+ trc = args.ctr -+ strict = args.strict -+ pl = args.pl -+ folds = tuple(int(i) for i in args.folds) -+ -+ validation_folder = "validation_raw" -+ -+ # this script now acts independently from the summary jsons. That was unnecessary -+ id_task_mapping = {} -+ # for each task, run ensembling using all combinations of two models -+ for t in tasks: -+ # first collect pure model performance (postprocessed) -+ results = {} -+ all_results = {} -+ valid_models = [] -+ for m in models: -+ try: -+ if m == "3d_cascade_fullres": -+ trainer = trc -+ else: -+ trainer = tr -+ -+ if t not in id_task_mapping.keys(): -+ task_name = find_task_name(get_output_folder_name(m), t) -+ id_task_mapping[t] = task_name -+ -+ output_folder = get_output_folder_name(m, id_task_mapping[t], trainer, pl) -+ assert isdir(output_folder), "Output folder for model %s is missing, expected: %s" % (m, output_folder) -+ -+ # we need a postprocessing_json for inference, so that must be present -+ postprocessing_json = join(output_folder, "postprocessing.json") -+ # we need cv_niftis_postprocessed to know the single model performance -+ cv_niftis_folder = join(output_folder, "cv_niftis_raw") -+ if not isfile(postprocessing_json) or not isdir(cv_niftis_folder): -+ print("running missing postprocessing for %s and model %s" % (id_task_mapping[t], m)) -+ consolidate_folds(output_folder, folds=folds) -+ assert isfile(postprocessing_json), "Postprocessing json missing, expected: %s" % postprocessing_json -+ assert isdir(cv_niftis_folder), "Folder with niftis from CV missing, expected: %s" % cv_niftis_folder -+ -+ # obtain mean foreground dice -+ summary_file = join(cv_niftis_folder, "summary.json") -+ results[m] = get_mean_foreground_dice(summary_file) -+ foreground_mean(summary_file) -+ all_results[m] = load_json(summary_file)['results']['mean'] -+ valid_models.append(m) -+ -+ except Exception as e: -+ if strict: -+ raise e -+ else: -+ print("WARNING!") -+ print(e) -+ -+ # now run ensembling and add ensembling to results -+ print("\nFound the following valid models:\n", valid_models) -+ if len(valid_models) > 1: -+ for m1, m2 in combinations(valid_models, 2): -+ -+ trainer_m1 = trc if m1 == "3d_cascade_fullres" else tr -+ trainer_m2 = trc if m2 == "3d_cascade_fullres" else tr -+ -+ ensemble_name = "ensemble_" + m1 + "__" + trainer_m1 + "__" + pl + "--" + m2 + "__" + trainer_m2 + "__" + pl -+ output_folder_base = join(network_training_output_dir, "ensembles", id_task_mapping[t], ensemble_name) -+ maybe_mkdir_p(output_folder_base) -+ -+ network1_folder = get_output_folder_name(m1, id_task_mapping[t], trainer_m1, pl) -+ network2_folder = get_output_folder_name(m2, id_task_mapping[t], trainer_m2, pl) -+ -+ print("ensembling", network1_folder, network2_folder) -+ ensemble(network1_folder, network2_folder, output_folder_base, id_task_mapping[t], validation_folder, folds) -+ # ensembling will automatically do postprocessingget_foreground_mean -+ -+ # now get result of ensemble -+ results[ensemble_name] = get_mean_foreground_dice(join(output_folder_base, "ensembled_raw", "summary.json")) -+ summary_file = join(output_folder_base, "ensembled_raw", "summary.json") -+ foreground_mean(summary_file) -+ all_results[ensemble_name] = load_json(summary_file)['results']['mean'] -+ -+ # now print all mean foreground dice and highlight the best -+ foreground_dices = list(results.values()) -+ best = np.max(foreground_dices) -+ for k, v in results.items(): -+ print(k, v) -+ -+ predict_str = "" -+ best_model = None -+ for k, v in results.items(): -+ if v == best: -+ print("%s submit model %s" % (id_task_mapping[t], k), v) -+ best_model = k -+ print("\nHere is how you should predict test cases. Run in sequential order and replace all input and output folder names with your personalized ones\n") -+ if k.startswith("ensemble"): -+ tmp = k[len("ensemble_"):] -+ model1, model2 = tmp.split("--") -+ m1, t1, pl1 = model1.split("__") -+ m2, t2, pl2 = model2.split("__") -+ predict_str += "nnUNet_predict -i FOLDER_WITH_TEST_CASES -o OUTPUT_FOLDER_MODEL1 -tr " + tr + " -ctr " + trc + " -m " + m1 + " -p " + pl + " -t " + \ -+ id_task_mapping[t] + "\n" -+ predict_str += "nnUNet_predict -i FOLDER_WITH_TEST_CASES -o OUTPUT_FOLDER_MODEL2 -tr " + tr + " -ctr " + trc + " -m " + m2 + " -p " + pl + " -t " + \ -+ id_task_mapping[t] + "\n" -+ -+ predict_str += "nnUNet_ensemble -f OUTPUT_FOLDER_MODEL1 OUTPUT_FOLDER_MODEL2 -o OUTPUT_FOLDER -pp " + join(network_training_output_dir, "ensembles", id_task_mapping[t], k, "postprocessing.json") + "\n" -+ else: -+ predict_str += "nnUNet_predict -i FOLDER_WITH_TEST_CASES -o OUTPUT_FOLDER_MODEL1 -tr " + tr + " -ctr " + trc + " -m " + k + " -p " + pl + " -t " + \ -+ id_task_mapping[t] + "\n" -+ print(predict_str) -+ -+ summary_folder = join(network_training_output_dir, "ensembles", id_task_mapping[t]) -+ maybe_mkdir_p(summary_folder) -+ with open(join(summary_folder, "prediction_commands.txt"), 'w') as f: -+ f.write(predict_str) -+ -+ num_classes = len([i for i in all_results[best_model].keys() if i != 'mean']) -+ with open(join(summary_folder, "summary.csv"), 'w') as f: -+ f.write("model") -+ for c in range(1, num_classes): -+ f.write(",class%d" % c) -+ f.write(",average") -+ f.write("\n") -+ for m in all_results.keys(): -+ f.write(m) -+ for c in range(1, num_classes): -+ f.write(",%01.4f" % all_results[m][str(c)]["Dice"]) -+ f.write(",%01.4f" % all_results[m]['mean']["Dice"]) -+ f.write("\n") -+ -+ -+if __name__ == "__main__": -+ main() ++# Copyright 2020 Division of Medical Image Computing, German Cancer Research Center (DKFZ), Heidelberg, Germany ++# ++# 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 itertools import combinations ++import nnunet ++from batchgenerators.utilities.file_and_folder_operations import * ++from nnunet.evaluation.add_mean_dice_to_json import foreground_mean ++from nnunet.evaluation.model_selection.ensemble import ensemble ++from nnunet.paths import network_training_output_dir ++import numpy as np ++from subprocess import call ++from nnunet.postprocessing.consolidate_postprocessing import consolidate_folds ++from nnunet.utilities.folder_names import get_output_folder_name ++from nnunet.paths import default_cascade_trainer, default_trainer, default_plans_identifier ++ ++ ++def find_task_name(folder, task_id): ++ candidates = subdirs(folder, prefix="Task%03.0d_" % task_id, join=False) ++ assert len(candidates) > 0, "no candidate for Task id %d found in folder %s" % (task_id, folder) ++ assert len(candidates) == 1, "more than one candidate for Task id %d found in folder %s" % (task_id, folder) ++ return candidates[0] ++ ++ ++def get_mean_foreground_dice(json_file): ++ results = load_json(json_file) ++ return get_foreground_mean(results) ++ ++ ++def get_foreground_mean(results): ++ results_mean = results['results']['mean'] ++ dice_scores = [results_mean[i]['Dice'] for i in results_mean.keys() if i != "0" and i != 'mean'] ++ return np.mean(dice_scores) ++ ++ ++def main(): ++ import argparse ++ parser = argparse.ArgumentParser(usage="This is intended to identify the best model based on the five fold " ++ "cross-validation. Running this script requires all models to have been run " ++ "already. This script will summarize the results of the five folds of all " ++ "models in one json each for easy interpretability") ++ ++ parser.add_argument("-m", '--models', nargs="+", required=False, default=['3d_fullres']) ++ parser.add_argument("-t", '--task_ids', nargs="+", required=False, default='003') ++ ++ parser.add_argument("-tr", type=str, required=False, default=default_trainer, ++ help="nnUNetTrainer class. Default: %s" % default_trainer) ++ parser.add_argument("-ctr", type=str, required=False, default=default_cascade_trainer, ++ help="nnUNetTrainer class for cascade model. Default: %s" % default_cascade_trainer) ++ parser.add_argument("-pl", type=str, required=False, default=default_plans_identifier, ++ help="plans name, Default: %s" % default_plans_identifier) ++ parser.add_argument('-f', '--folds', nargs='+', default=(0, 1, 2, 3, 4), help="use this if you have non-standard folds") ++ parser.add_argument("--strict", required=False, default=True, action="store_true", ++ help="set this flag if you want this script to crash of one of the models is missing") ++ ++ args = parser.parse_args() ++ tasks = [int(i) for i in args.task_ids] ++ ++ models = args.models ++ tr = args.tr ++ trc = args.ctr ++ strict = args.strict ++ pl = args.pl ++ folds = tuple(int(i) for i in args.folds) ++ ++ validation_folder = "validation_raw" ++ ++ # this script now acts independently from the summary jsons. That was unnecessary ++ id_task_mapping = {} ++ # for each task, run ensembling using all combinations of two models ++ for t in tasks: ++ # first collect pure model performance (postprocessed) ++ results = {} ++ all_results = {} ++ valid_models = [] ++ for m in models: ++ try: ++ if m == "3d_cascade_fullres": ++ trainer = trc ++ else: ++ trainer = tr ++ ++ if t not in id_task_mapping.keys(): ++ task_name = find_task_name(get_output_folder_name(m), t) ++ id_task_mapping[t] = task_name ++ ++ output_folder = get_output_folder_name(m, id_task_mapping[t], trainer, pl) ++ assert isdir(output_folder), "Output folder for model %s is missing, expected: %s" % (m, output_folder) ++ ++ # we need a postprocessing_json for inference, so that must be present ++ postprocessing_json = join(output_folder, "postprocessing.json") ++ # we need cv_niftis_postprocessed to know the single model performance ++ cv_niftis_folder = join(output_folder, "cv_niftis_raw") ++ if not isfile(postprocessing_json) or not isdir(cv_niftis_folder): ++ print("running missing postprocessing for %s and model %s" % (id_task_mapping[t], m)) ++ consolidate_folds(output_folder, folds=folds) ++ assert isfile(postprocessing_json), "Postprocessing json missing, expected: %s" % postprocessing_json ++ assert isdir(cv_niftis_folder), "Folder with niftis from CV missing, expected: %s" % cv_niftis_folder ++ ++ # obtain mean foreground dice ++ summary_file = join(cv_niftis_folder, "summary.json") ++ results[m] = get_mean_foreground_dice(summary_file) ++ foreground_mean(summary_file) ++ all_results[m] = load_json(summary_file)['results']['mean'] ++ valid_models.append(m) ++ ++ except Exception as e: ++ if strict: ++ raise e ++ else: ++ print("WARNING!") ++ print(e) ++ ++ # now run ensembling and add ensembling to results ++ print("\nFound the following valid models:\n", valid_models) ++ if len(valid_models) > 1: ++ for m1, m2 in combinations(valid_models, 2): ++ ++ trainer_m1 = trc if m1 == "3d_cascade_fullres" else tr ++ trainer_m2 = trc if m2 == "3d_cascade_fullres" else tr ++ ++ ensemble_name = "ensemble_" + m1 + "__" + trainer_m1 + "__" + pl + "--" + m2 + "__" + trainer_m2 + "__" + pl ++ output_folder_base = join(network_training_output_dir, "ensembles", id_task_mapping[t], ensemble_name) ++ maybe_mkdir_p(output_folder_base) ++ ++ network1_folder = get_output_folder_name(m1, id_task_mapping[t], trainer_m1, pl) ++ network2_folder = get_output_folder_name(m2, id_task_mapping[t], trainer_m2, pl) ++ ++ print("ensembling", network1_folder, network2_folder) ++ ensemble(network1_folder, network2_folder, output_folder_base, id_task_mapping[t], validation_folder, folds) ++ # ensembling will automatically do postprocessingget_foreground_mean ++ ++ # now get result of ensemble ++ results[ensemble_name] = get_mean_foreground_dice(join(output_folder_base, "ensembled_raw", "summary.json")) ++ summary_file = join(output_folder_base, "ensembled_raw", "summary.json") ++ foreground_mean(summary_file) ++ all_results[ensemble_name] = load_json(summary_file)['results']['mean'] ++ ++ # now print all mean foreground dice and highlight the best ++ foreground_dices = list(results.values()) ++ best = np.max(foreground_dices) ++ for k, v in results.items(): ++ print(k, v) ++ ++ predict_str = "" ++ best_model = None ++ for k, v in results.items(): ++ if v == best: ++ print("%s submit model %s" % (id_task_mapping[t], k), v) ++ best_model = k ++ print("\nHere is how you should predict test cases. Run in sequential order and replace all input and output folder names with your personalized ones\n") ++ if k.startswith("ensemble"): ++ tmp = k[len("ensemble_"):] ++ model1, model2 = tmp.split("--") ++ m1, t1, pl1 = model1.split("__") ++ m2, t2, pl2 = model2.split("__") ++ predict_str += "nnUNet_predict -i FOLDER_WITH_TEST_CASES -o OUTPUT_FOLDER_MODEL1 -tr " + tr + " -ctr " + trc + " -m " + m1 + " -p " + pl + " -t " + \ ++ id_task_mapping[t] + "\n" ++ predict_str += "nnUNet_predict -i FOLDER_WITH_TEST_CASES -o OUTPUT_FOLDER_MODEL2 -tr " + tr + " -ctr " + trc + " -m " + m2 + " -p " + pl + " -t " + \ ++ id_task_mapping[t] + "\n" ++ ++ predict_str += "nnUNet_ensemble -f OUTPUT_FOLDER_MODEL1 OUTPUT_FOLDER_MODEL2 -o OUTPUT_FOLDER -pp " + join(network_training_output_dir, "ensembles", id_task_mapping[t], k, "postprocessing.json") + "\n" ++ else: ++ predict_str += "nnUNet_predict -i FOLDER_WITH_TEST_CASES -o OUTPUT_FOLDER_MODEL1 -tr " + tr + " -ctr " + trc + " -m " + k + " -p " + pl + " -t " + \ ++ id_task_mapping[t] + "\n" ++ print(predict_str) ++ ++ summary_folder = join(network_training_output_dir, "ensembles", id_task_mapping[t]) ++ maybe_mkdir_p(summary_folder) ++ with open(join(summary_folder, "prediction_commands.txt"), 'w') as f: ++ f.write(predict_str) ++ ++ num_classes = len([i for i in all_results[best_model].keys() if i != 'mean']) ++ with open(join(summary_folder, "summary.csv"), 'w') as f: ++ f.write("model") ++ for c in range(1, num_classes): ++ f.write(",class%d" % c) ++ f.write(",average") ++ f.write("\n") ++ for m in all_results.keys(): ++ f.write(m) ++ for c in range(1, num_classes): ++ f.write(",%01.4f" % all_results[m][str(c)]["Dice"]) ++ f.write(",%01.4f" % all_results[m]['mean']["Dice"]) ++ f.write("\n") ++ ++ ++if __name__ == "__main__": ++ main() diff --git a/pytorch/nnunet/experiment_planning/nnUNet_convert_decathlon_task.py b/pytorch/nnunet/experiment_planning/nnUNet_convert_decathlon_task.py index cf5285a..a0384f0 100644 --- a/pytorch/nnunet/experiment_planning/nnUNet_convert_decathlon_task.py @@ -269,41 +269,41 @@ index 0000000..5113f93 --- /dev/null +++ b/pytorch/nnunet/hyp_getnpz.py @@ -0,0 +1,36 @@ -+import numpy as np -+import os -+import nibabel as nib -+import pickle -+ -+ -+raw_data = '/data/yupeng/environment_variables/nnUNet_raw_data_base/nnUNet_raw_data/Task003_Liver/imagesTr/liver_0_0000.nii.gz' -+crop_data = '/data/yupeng/environment_variables/nnUNet_raw_data_base/nnUNet_cropped_data/Task003_Liver/liver_0.npz' -+crop_data = '/data/yupeng/environment_variables/nnUNet_preprocessed/Task003_Liver/nnUNetData_plans_v2.1_stage0/liver_0.npz' -+pickle_data = '/data/yupeng/environment_variables/nnUNet_preprocessed/Task003_Liver/nnUNetPlansv2.1_plans_3D.pkl' -+ -+print('start') -+ -+p_data = pickle.load(open(pickle_data, 'rb')) -+ -+ -+ -+c_data = np.load(crop_data) -+print(c_data.files) -+ -+r_data = nib.load(raw_data).get_data() -+r_data = r_data / np.amax(r_data) -+ -+min2 = min(r_data) -+ -+for i in range(512): -+ for j in range(512): -+ for k in range(75): -+ data1 = r_data[i][j][k] -+ data2 = c_data.f.data[0][k][i][j] -+ if data1 != data2: -+ print("wrong") -+ break -+ -+ ++import numpy as np ++import os ++import nibabel as nib ++import pickle ++ ++ ++raw_data = '/data/yupeng/environment_variables/nnUNet_raw_data_base/nnUNet_raw_data/Task003_Liver/imagesTr/liver_0_0000.nii.gz' ++crop_data = '/data/yupeng/environment_variables/nnUNet_raw_data_base/nnUNet_cropped_data/Task003_Liver/liver_0.npz' ++crop_data = '/data/yupeng/environment_variables/nnUNet_preprocessed/Task003_Liver/nnUNetData_plans_v2.1_stage0/liver_0.npz' ++pickle_data = '/data/yupeng/environment_variables/nnUNet_preprocessed/Task003_Liver/nnUNetPlansv2.1_plans_3D.pkl' ++ ++print('start') ++ ++p_data = pickle.load(open(pickle_data, 'rb')) ++ ++ ++ ++c_data = np.load(crop_data) ++print(c_data.files) ++ ++r_data = nib.load(raw_data).get_data() ++r_data = r_data / np.amax(r_data) ++ ++min2 = min(r_data) ++ ++for i in range(512): ++ for j in range(512): ++ for k in range(75): ++ data1 = r_data[i][j][k] ++ data2 = c_data.f.data[0][k][i][j] ++ if data1 != data2: ++ print("wrong") ++ break ++ ++ +print('end') \ No newline at end of file diff --git a/pytorch/nnunet/inference/copy_val_to_test.py b/pytorch/nnunet/inference/copy_val_to_test.py @@ -312,183 +312,183 @@ index 0000000..405345b --- /dev/null +++ b/pytorch/nnunet/inference/copy_val_to_test.py @@ -0,0 +1,19 @@ -+import os -+import shutil -+ -+# fold = 0 -+val_folder = '/root/heyupeng/environment/Task03_Liver/imagesTr/' -+test_folder = '/root/heyupeng/environment/nnUNet_raw_data_base/nnUNet_raw_data/Task003_Liver/imagesTs/' -+val_list = [101, 11, 112, 115, 12, 120, 128, 17, 19, 24, 25, 27, 3, 38, 40, 41, 42, 44, 5, 51, 52, 58, 64, 70, 75, 77, -+ 82] -+print('val_list:', val_list) -+for val in val_list: -+ source_file = 'liver_' + str(val) + '.nii.gz' -+ source_path = os.path.join(val_folder, source_file) -+ target_file = 'liver_' + str(val) + '_0000.nii.gz' -+ target_path = os.path.join(test_folder, target_file) -+ print('copy: ', source_path, '->', target_path) -+ shutil.copyfile(source_path, target_path) -+print('done') -+ -+ ++import os ++import shutil ++ ++# fold = 0 ++val_folder = '/root/heyupeng/environment/Task03_Liver/imagesTr/' ++test_folder = '/root/heyupeng/environment/nnUNet_raw_data_base/nnUNet_raw_data/Task003_Liver/imagesTs/' ++val_list = [101, 11, 112, 115, 12, 120, 128, 17, 19, 24, 25, 27, 3, 38, 40, 41, 42, 44, 5, 51, 52, 58, 64, 70, 75, 77, ++ 82] ++print('val_list:', val_list) ++for val in val_list: ++ source_file = 'liver_' + str(val) + '.nii.gz' ++ source_path = os.path.join(val_folder, source_file) ++ target_file = 'liver_' + str(val) + '_0000.nii.gz' ++ target_path = os.path.join(test_folder, target_file) ++ print('copy: ', source_path, '->', target_path) ++ shutil.copyfile(source_path, target_path) ++print('done') ++ ++ diff --git a/pytorch/nnunet/inference/create_testset.py b/pytorch/nnunet/inference/create_testset.py new file mode 100644 index 0000000..cd13c1e --- /dev/null +++ b/pytorch/nnunet/inference/create_testset.py @@ -0,0 +1,28 @@ -+import os -+import pdb -+import sys -+import shutil -+ -+ -+def main(input_path): -+ if input_path is None: -+ raise Exception('Parameter need to be filled in: input_path') -+ env_dist = os.environ -+ p1 = env_dist.get('nnUNet_raw_data_base') -+ val_list = [101, 11, 112, 115, 12, 120, 128, 17, 19, 24, 25, 27, 3, 38, 40, 41, 42, 44, 5, 51, 52, 58, 64, 70, 75, -+ 77, 82] # 数据集的验证集部分 -+ p2 = 'nnUNet_raw_data/Task003_Liver/imagesTr/' -+ target_path = os.path.join(p1, p2) -+ for v in val_list: -+ file_name = 'liver_' + str(v) + '_0000.nii.gz' -+ file_path = os.path.join(target_path, file_name) -+ # pdb.set_trace() -+ print('copy file:[', file_path, '] to folder:', input_path) -+ shutil.copy(file_path, input_path) -+ print('done') -+ -+ -+ -+if __name__ == "__main__": -+ input_path = sys.argv[1] -+ main(input_path) ++import os ++import pdb ++import sys ++import shutil ++ ++ ++def main(input_path): ++ if input_path is None: ++ raise Exception('Parameter need to be filled in: input_path') ++ env_dist = os.environ ++ p1 = env_dist.get('nnUNet_raw_data_base') ++ val_list = [101, 11, 112, 115, 12, 120, 128, 17, 19, 24, 25, 27, 3, 38, 40, 41, 42, 44, 5, 51, 52, 58, 64, 70, 75, ++ 77, 82] # 数据集的验证集部分 ++ p2 = 'nnUNet_raw_data/Task003_Liver/imagesTr/' ++ target_path = os.path.join(p1, p2) ++ for v in val_list: ++ file_name = 'liver_' + str(v) + '_0000.nii.gz' ++ file_path = os.path.join(target_path, file_name) ++ # pdb.set_trace() ++ print('copy file:[', file_path, '] to folder:', input_path) ++ shutil.copy(file_path, input_path) ++ print('done') ++ ++ ++ ++if __name__ == "__main__": ++ input_path = sys.argv[1] ++ main(input_path) diff --git a/pytorch/nnunet/inference/delete_other_data.py b/pytorch/nnunet/inference/delete_other_data.py new file mode 100644 index 0000000..b58367f --- /dev/null +++ b/pytorch/nnunet/inference/delete_other_data.py @@ -0,0 +1,30 @@ -+import os -+import pdb -+ -+ -+def listdir(path, list_name): -+ for file in os.listdir(path): -+ file_path = os.path.join(path, file) -+ if os.path.isdir(file_path): -+ listdir(file_path, list_name) -+ elif os.path.splitext(file_path)[1] == '.gz': -+ list_name.append(file_path) -+ return list_name -+ -+val_list = [101, 11, 112, 115, 12, 120, 128, 17, 19, 24, 25, 27, 3, 38, 40, 41, 42, 44, 5, 51, 52, 58, 64, 70, 75, 77, -+ 82] -+target_folder = ['imagesTr', 'labelsTr', 'imagesTs'] -+for i in range(len(target_folder)): -+ t = target_folder[i] -+ if i == 2: -+ val_list = [132] -+ p = os.path.join('./Task03_Liver/', t) -+ files = [] -+ files = listdir(p, files) -+ files = set(files) -+ for e in val_list: -+ str_e = './Task03_Liver/' + t + '/liver_' + str(e) + '.nii.gz' -+ files.remove(str_e) -+ for f in files: -+ os.remove(f) -+print('end') ++import os ++import pdb ++ ++ ++def listdir(path, list_name): ++ for file in os.listdir(path): ++ file_path = os.path.join(path, file) ++ if os.path.isdir(file_path): ++ listdir(file_path, list_name) ++ elif os.path.splitext(file_path)[1] == '.gz': ++ list_name.append(file_path) ++ return list_name ++ ++val_list = [101, 11, 112, 115, 12, 120, 128, 17, 19, 24, 25, 27, 3, 38, 40, 41, 42, 44, 5, 51, 52, 58, 64, 70, 75, 77, ++ 82] ++target_folder = ['imagesTr', 'labelsTr', 'imagesTs'] ++for i in range(len(target_folder)): ++ t = target_folder[i] ++ if i == 2: ++ val_list = [132] ++ p = os.path.join('./Task03_Liver/', t) ++ files = [] ++ files = listdir(p, files) ++ files = set(files) ++ for e in val_list: ++ str_e = './Task03_Liver/' + t + '/liver_' + str(e) + '.nii.gz' ++ files.remove(str_e) ++ for f in files: ++ os.remove(f) ++print('end') diff --git a/pytorch/nnunet/inference/gen_dataset_info.py b/pytorch/nnunet/inference/gen_dataset_info.py new file mode 100644 index 0000000..d1cb265 --- /dev/null +++ b/pytorch/nnunet/inference/gen_dataset_info.py @@ -0,0 +1,83 @@ -+""" -+ Copyright 2020 Huawei Technologies Co., Ltd -+ -+ 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. -+ Typical usage example: -+""" -+import os -+import sys -+from glob import glob -+import pdb -+ -+ -+def get_bin_info(file_path, info_name, shape, split4=True): -+ """ -+ @description: get given bin information -+ @param file_path bin file path -+ @param info_name given information name -+ @param shape image shape -+ @return -+ """ -+ bin_images = glob(os.path.join(file_path, '*.bin')) -+ with open(info_name, 'w') as file: -+ for index, img in enumerate(bin_images): -+ content = ' '.join([str(index), img, shape[0], shape[1]]) -+ file.write(content) -+ file.write('\n') -+ print('info已写入:', info_name) -+ if split4: # 是否切割为4卡的info -+ sths = ['sth1.info', 'sth2.info', 'sth3.info', 'sth4.info'] -+ for i in range(len(sths)): -+ s = sths[i] -+ s = os.path.join(info_name, '..', s) -+ sths[i] = s -+ length = len(bin_images) -+ step = length // 4 -+ b1 = bin_images[0: step] -+ b2 = bin_images[step: 2*step] -+ b3 = bin_images[2*step: 3*step] -+ b4 = bin_images[3*step:] -+ with open(sths[0], 'w') as file: -+ for index, img in enumerate(b1): -+ content = ' '.join([str(index), img, shape[0], shape[1]]) -+ file.write(content) -+ file.write('\n') -+ with open(sths[1], 'w') as file: -+ for index, img in enumerate(b2): -+ content = ' '.join([str(index), img, shape[0], shape[1]]) -+ file.write(content) -+ file.write('\n') -+ with open(sths[2], 'w') as file: -+ for index, img in enumerate(b3): -+ content = ' '.join([str(index), img, shape[0], shape[1]]) -+ file.write(content) -+ file.write('\n') -+ with open(sths[3], 'w') as file: -+ for index, img in enumerate(b4): -+ content = ' '.join([str(index), img, shape[0], shape[1]]) -+ file.write(content) -+ file.write('\n') -+ print('成功切分为四个子集', sths) -+ -+ -+if __name__ == '__main__': -+ file_type = sys.argv[1] -+ file_path = sys.argv[2] -+ info_name = sys.argv[3] -+ if file_type == 'bin': -+ shape1 = sys.argv[4] -+ shape2 = sys.argv[5] -+ shape = [shape1, shape2] -+ assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' -+ get_bin_info(file_path, info_name, shape) ++""" ++ Copyright 2020 Huawei Technologies Co., Ltd ++ ++ 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. ++ Typical usage example: ++""" ++import os ++import sys ++from glob import glob ++import pdb ++ ++ ++def get_bin_info(file_path, info_name, shape, split4=True): ++ """ ++ @description: get given bin information ++ @param file_path bin file path ++ @param info_name given information name ++ @param shape image shape ++ @return ++ """ ++ bin_images = glob(os.path.join(file_path, '*.bin')) ++ with open(info_name, 'w') as file: ++ for index, img in enumerate(bin_images): ++ content = ' '.join([str(index), img, shape[0], shape[1]]) ++ file.write(content) ++ file.write('\n') ++ print('info已写入:', info_name) ++ if split4: # 是否切割为4卡的info ++ sths = ['sth1.info', 'sth2.info', 'sth3.info', 'sth4.info'] ++ for i in range(len(sths)): ++ s = sths[i] ++ s = os.path.join(info_name, '..', s) ++ sths[i] = s ++ length = len(bin_images) ++ step = length // 4 ++ b1 = bin_images[0: step] ++ b2 = bin_images[step: 2*step] ++ b3 = bin_images[2*step: 3*step] ++ b4 = bin_images[3*step:] ++ with open(sths[0], 'w') as file: ++ for index, img in enumerate(b1): ++ content = ' '.join([str(index), img, shape[0], shape[1]]) ++ file.write(content) ++ file.write('\n') ++ with open(sths[1], 'w') as file: ++ for index, img in enumerate(b2): ++ content = ' '.join([str(index), img, shape[0], shape[1]]) ++ file.write(content) ++ file.write('\n') ++ with open(sths[2], 'w') as file: ++ for index, img in enumerate(b3): ++ content = ' '.join([str(index), img, shape[0], shape[1]]) ++ file.write(content) ++ file.write('\n') ++ with open(sths[3], 'w') as file: ++ for index, img in enumerate(b4): ++ content = ' '.join([str(index), img, shape[0], shape[1]]) ++ file.write(content) ++ file.write('\n') ++ print('成功切分为四个子集', sths) ++ ++ ++if __name__ == '__main__': ++ file_type = sys.argv[1] ++ file_path = sys.argv[2] ++ info_name = sys.argv[3] ++ if file_type == 'bin': ++ shape1 = sys.argv[4] ++ shape2 = sys.argv[5] ++ shape = [shape1, shape2] ++ assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' ++ get_bin_info(file_path, info_name, shape) + print('end main') \ No newline at end of file diff --git a/pytorch/nnunet/inference/infer_path.py b/pytorch/nnunet/inference/infer_path.py @@ -583,1302 +583,1302 @@ index 0000000..263dbd2 --- /dev/null +++ b/pytorch/nnunet/inference/predict2.py @@ -0,0 +1,845 @@ -+# Copyright 2020 Division of Medical Image Computing, German Cancer Research Center (DKFZ), Heidelberg, Germany -+# -+# 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 argparse -+from copy import deepcopy -+from typing import Tuple, Union, List -+ -+import numpy as np -+from batchgenerators.augmentations.utils import resize_segmentation -+from nnunet.inference.segmentation_export import save_segmentation_nifti_from_softmax, save_segmentation_nifti -+from batchgenerators.utilities.file_and_folder_operations import * -+from multiprocessing import Process, Queue -+import torch -+import SimpleITK as sitk -+import shutil -+from multiprocessing import Pool -+from nnunet.postprocessing.connected_components import load_remove_save, load_postprocessing -+from nnunet.training.model_restore import load_model_and_checkpoint_files -+from nnunet.training.network_training.nnUNetTrainer import nnUNetTrainer -+from nnunet.utilities.one_hot_encoding import to_one_hot -+from nnunet.utilities.to_torch import maybe_to_torch, to_cuda -+import pdb -+ -+ -+def preprocess_save_to_queue(preprocess_fn, q, list_of_lists, output_files, segs_from_prev_stage, classes, -+ transpose_forward): -+ # suppress output -+ # sys.stdout = open(os.devnull, 'w') -+ -+ errors_in = [] -+ for i, l in enumerate(list_of_lists): -+ try: -+ output_file = output_files[i] -+ print("preprocessing", output_file) -+ d, _, dct = preprocess_fn(l) -+ # print(output_file, dct) -+ if segs_from_prev_stage[i] is not None: -+ assert isfile(segs_from_prev_stage[i]) and segs_from_prev_stage[i].endswith( -+ ".nii.gz"), "segs_from_prev_stage" \ -+ " must point to a " \ -+ "segmentation file" -+ seg_prev = sitk.GetArrayFromImage(sitk.ReadImage(segs_from_prev_stage[i])) -+ # check to see if shapes match -+ img = sitk.GetArrayFromImage(sitk.ReadImage(l[0])) -+ assert all([i == j for i, j in zip(seg_prev.shape, img.shape)]), "image and segmentation from previous " \ -+ "stage don't have the same pixel array " \ -+ "shape! image: %s, seg_prev: %s" % \ -+ (l[0], segs_from_prev_stage[i]) -+ seg_prev = seg_prev.transpose(transpose_forward) -+ seg_reshaped = resize_segmentation(seg_prev, d.shape[1:], order=1, cval=0) -+ seg_reshaped = to_one_hot(seg_reshaped, classes) -+ d = np.vstack((d, seg_reshaped)).astype(np.float32) -+ """There is a problem with python process communication that prevents us from communicating obejcts -+ larger than 2 GB between processes (basically when the length of the pickle string that will be sent is -+ communicated by the multiprocessing.Pipe object then the placeholder (\%i I think) does not allow for long -+ enough strings (lol). This could be fixed by changing i to l (for long) but that would require manually -+ patching system python code. We circumvent that problem here by saving softmax_pred to a npy file that will -+ then be read (and finally deleted) by the Process. save_segmentation_nifti_from_softmax can take either -+ filename or np.ndarray and will handle this automatically""" -+ print(d.shape) -+ if np.prod(d.shape) > (2e9 / 4 * 0.85): # *0.85 just to be save, 4 because float32 is 4 bytes -+ print( -+ "This output is too large for python process-process communication. " -+ "Saving output temporarily to disk") -+ np.save(output_file[:-7] + ".npy", d) -+ d = output_file[:-7] + ".npy" -+ q.put((output_file, (d, dct))) -+ except KeyboardInterrupt: -+ raise KeyboardInterrupt -+ except Exception as e: -+ print("error in", l) -+ print(e) -+ q.put("end") -+ if len(errors_in) > 0: -+ print("There were some errors in the following cases:", errors_in) -+ print("These cases were ignored.") -+ else: -+ print("This worker has ended successfully, no errors to report") -+ # restore output -+ # sys.stdout = sys.__stdout__ -+ -+ -+def preprocess_multithreaded(trainer, list_of_lists, output_files, num_processes=2, segs_from_prev_stage=None): -+ if segs_from_prev_stage is None: -+ segs_from_prev_stage = [None] * len(list_of_lists) -+ -+ num_processes = min(len(list_of_lists), num_processes) -+ -+ classes = list(range(1, trainer.num_classes)) -+ assert isinstance(trainer, nnUNetTrainer) -+ q = Queue(1) -+ processes = [] -+ for i in range(num_processes): -+ pr = Process(target=preprocess_save_to_queue, args=(trainer.preprocess_patient, q, -+ list_of_lists[i::num_processes], -+ output_files[i::num_processes], -+ segs_from_prev_stage[i::num_processes], -+ classes, trainer.plans['transpose_forward'])) -+ pr.start() -+ processes.append(pr) -+ -+ try: -+ end_ctr = 0 -+ while end_ctr != num_processes: -+ item = q.get() -+ if item == "end": -+ end_ctr += 1 -+ continue -+ else: -+ yield item -+ -+ finally: -+ for p in processes: -+ if p.is_alive(): -+ p.terminate() # this should not happen but better safe than sorry right -+ p.join() -+ -+ q.close() -+ -+ -+def pth2onnx(model, output_file=r'/home/yupeng/HUAWEI/UNetPlusPlus/pytorch/nnunet/run/nnunetplusplus.onnx'): -+ # model = EfficientNet.from_pretrained('efficientnet-b0', weights_path=input_file) -+ # 调整模型为eval mode -+ model.eval() -+ # 输入节点名 -+ input_names = ["image"] -+ # 输出节点名 -+ output_names = ["class"] -+ dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} -+ dummy_input = torch.randn(1, 1, 128, 128, 128) -+ # dummy_input = to_cuda(dummy_input) -+ # verbose=True,支持打印onnx节点和对应的PyTorch代码行 -+ torch.onnx.export(model, dummy_input, output_file, input_names=input_names, dynamic_axes=dynamic_axes, -+ output_names=output_names, opset_version=11, verbose=True) -+ -+ -+def predict_cases(model, list_of_lists, output_filenames, folds, save_npz, num_threads_preprocessing, -+ num_threads_nifti_save, segs_from_prev_stage=None, do_tta=True, mixed_precision=True, overwrite_existing=False, -+ all_in_gpu=False, step_size=0.5, checkpoint_name="model_final_checkpoint", -+ segmentation_export_kwargs: dict = None, pre_mode=None, fp=None): -+ """ -+ :param segmentation_export_kwargs: -+ :param model: folder where the model is saved, must contain fold_x subfolders -+ :param list_of_lists: [[case0_0000.nii.gz, case0_0001.nii.gz], [case1_0000.nii.gz, case1_0001.nii.gz], ...] -+ :param output_filenames: [output_file_case0.nii.gz, output_file_case1.nii.gz, ...] -+ :param folds: default: (0, 1, 2, 3, 4) (but can also be 'all' or a subset of the five folds, for example use (0, ) -+ for using only fold_0 -+ :param save_npz: default: False -+ :param num_threads_preprocessing: -+ :param num_threads_nifti_save: -+ :param segs_from_prev_stage: -+ :param do_tta: default: True, can be set to False for a 8x speedup at the cost of a reduced segmentation quality -+ :param overwrite_existing: default: True -+ :param mixed_precision: if None then we take no action. If True/False we overwrite what the model has in its init -+ :return: -+ """ -+ assert len(list_of_lists) == len(output_filenames) -+ if segs_from_prev_stage is not None: assert len(segs_from_prev_stage) == len(output_filenames) -+ -+ pool = Pool(num_threads_nifti_save) -+ results = [] -+ -+ cleaned_output_files = [] -+ for o in output_filenames: -+ dr, f = os.path.split(o) -+ if len(dr) > 0: -+ maybe_mkdir_p(dr) -+ if not f.endswith(".nii.gz"): -+ f, _ = os.path.splitext(f) -+ f = f + ".nii.gz" -+ cleaned_output_files.append(join(dr, f)) -+ -+ if not overwrite_existing: -+ print("number of cases:", len(list_of_lists)) -+ not_done_idx = [i for i, j in enumerate(cleaned_output_files) if not isfile(j)] -+ -+ cleaned_output_files = [cleaned_output_files[i] for i in not_done_idx] -+ list_of_lists = [list_of_lists[i] for i in not_done_idx] -+ if segs_from_prev_stage is not None: -+ segs_from_prev_stage = [segs_from_prev_stage[i] for i in not_done_idx] -+ -+ print("number of cases that still need to be predicted:", len(cleaned_output_files)) -+ -+ print("emptying cuda cache") -+ torch.cuda.empty_cache() -+ ''' -+ model='/data/yupeng/environment_variables/RESULTS_FOLDER/nnUNet/3d_fullres/Task003_Liver/nnUNetPlusPlusTrainerV2__nnUNetPlansv2.1' -+ folds=None -+ mixed_precision=True -+ checkpoint_name='model_final_checkpoint' -+ trainer=class-nnUNetPlusPlusTrainerV2 -+ params=list 5 -> dict 6 -> epoch state_dict optimizer_state_dict lr_scheduler_state_dict plot_stuff amp_grad_scaler -+ ''' -+ print("loading parameters for folds,", folds) # 得到参数,实际还未加载进模型 -+ trainer, params = load_model_and_checkpoint_files(model, folds, mixed_precision=mixed_precision, checkpoint_name=checkpoint_name) -+ -+ if segmentation_export_kwargs is None: -+ if 'segmentation_export_params' in trainer.plans.keys(): -+ force_separate_z = trainer.plans['segmentation_export_params']['force_separate_z'] -+ interpolation_order = trainer.plans['segmentation_export_params']['interpolation_order'] -+ interpolation_order_z = trainer.plans['segmentation_export_params']['interpolation_order_z'] -+ else: # 走到这里 -+ force_separate_z = None -+ interpolation_order = 1 -+ interpolation_order_z = 0 -+ else: -+ force_separate_z = segmentation_export_kwargs['force_separate_z'] -+ interpolation_order = segmentation_export_kwargs['interpolation_order'] -+ interpolation_order_z = segmentation_export_kwargs['interpolation_order_z'] -+ -+ print("starting preprocessing generator") -+ preprocessing = preprocess_multithreaded(trainer, list_of_lists, cleaned_output_files, num_threads_preprocessing, -+ segs_from_prev_stage) -+ # unet++V2class, [['/data/yupeng/environment_variables/nnUNet_raw_data_base/nnUNet_raw_data/Task003_Liver/imagesTs/liver_132_0000.nii.gz']] -+ # ['/data/yupeng/environment_variables/output/liver_132.nii.gz'], 6, None -+ print("starting prediction...") -+ if int(pre_mode) == -1: -+ p = params[0] -+ trainer.load_checkpoint_ram(p, False) # nnUnetPlusPlusTrainerV2,实际函数在network_trainer里 -+ print('pth2onnx start') -+ pth2onnx(trainer.network, fp) -+ print('pth2onnx end') -+ print('onnx模型已经输出至:', fp) -+ import sys -+ sys.exit(0) -+ all_output_files = [] -+ for preprocessed in preprocessing: -+ output_filename, (d, dct) = preprocessed -+ print('output_filename, d, dct = ', output_filename, d, dct) -+ all_output_files.append(all_output_files) -+ if isinstance(d, str): -+ data = np.load(d) -+ os.remove(d) -+ d = data -+ print("predicting", output_filename) -+ softmax = [] -+ params = [params[0]] # 只求第一个模型的推理结果 -+ for p in params: -+ # trainer.load_checkpoint_ram(p, False) # nnUnetPlusPlusTrainerV2,实际函数在network_trainer里 -+ # output_filename = '/data/yupeng/environment_variables/output/liver_132.nii.gz' -+ ttttt = trainer.predict_preprocessed_data_return_seg_and_softmax(d, do_tta, trainer.data_aug_params[ -+ 'mirror_axes'], True, step_size=step_size, use_gaussian=True, all_in_gpu=all_in_gpu, -+ mixed_precision=mixed_precision, img_name=output_filename, pre_mode=pre_mode, fp=fp) # tuple(ndarray 489 500 500; 3 489 500 500) -+ softmax.append(ttttt[1][None]) # 扩充了1 3 489 500 500 -+ ''' -+ d= -+ do_tta= -+ step_size= -+ all_in_gpu= -+ mixed_precision= -+ softmax= -+ ''' -+ # softmax是list 5,每个元素是ndarray 1 3 489 500 500 -+ softmax = np.vstack(softmax) # 5 3 489 500 500 -+ softmax_mean = np.mean(softmax, 0) # 3 489 500 500 -+ -+ transpose_forward = trainer.plans.get('transpose_forward') # [0,1,2] -+ if transpose_forward is not None: -+ transpose_backward = trainer.plans.get('transpose_backward') -+ softmax_mean = softmax_mean.transpose([0] + [i + 1 for i in transpose_backward]) -+ -+ if save_npz: # False -+ npz_file = output_filename[:-7] + ".npz" -+ else: -+ npz_file = None -+ -+ if hasattr(trainer, 'regions_class_order'): # False -+ region_class_order = trainer.regions_class_order -+ else: -+ region_class_order = None -+ -+ """There is a problem with python process communication that prevents us from communicating obejcts -+ larger than 2 GB between processes (basically when the length of the pickle string that will be sent is -+ communicated by the multiprocessing.Pipe object then the placeholder (\%i I think) does not allow for long -+ enough strings (lol). This could be fixed by changing i to l (for long) but that would require manually -+ patching system python code. We circumvent that problem here by saving softmax_pred to a npy file that will -+ then be read (and finally deleted) by the Process. save_segmentation_nifti_from_softmax can take either -+ filename or np.ndarray and will handle this automatically""" -+ bytes_per_voxel = 4 -+ if all_in_gpu: -+ bytes_per_voxel = 2 # if all_in_gpu then the return value is half (float16) -+ if np.prod(softmax_mean.shape) > (2e9 / bytes_per_voxel * 0.85): # * 0.85 just to be save -+ print( -+ "This output is too large for python process-process communication. Saving output temporarily to disk") -+ np.save(output_filename[:-7] + ".npy", softmax_mean) -+ softmax_mean = output_filename[:-7] + ".npy" -+ -+ results.append(pool.starmap_async(save_segmentation_nifti_from_softmax, -+ ((softmax_mean, output_filename, dct, interpolation_order, region_class_order, -+ None, None, -+ npz_file, None, force_separate_z, interpolation_order_z),) -+ )) -+ -+ print("inference done. Now waiting for the segmentation export to finish...") -+ _ = [i.get() for i in results] -+ # now apply postprocessing -+ # first load the postprocessing properties if they are present. Else raise a well visible warning -+ results = [] -+ pp_file = join(model, "postprocessing.json") # '/data/yupeng/environment_variables/RESULTS_FOLDER/nnUNet/3d_fullres/Task003_Liver/nnUNetPlusPlusTrainerV2__nnUNetPlansv2.1/postprocessing.json' -+ if isfile(pp_file): -+ print("postprocessing...") -+ shutil.copy(pp_file, os.path.abspath(os.path.dirname(output_filenames[0]))) -+ # for_which_classes stores for which of the classes everything but the largest connected component needs to be -+ # removed -+ for_which_classes, min_valid_obj_size = load_postprocessing(pp_file) -+ results.append(pool.starmap_async(load_remove_save, -+ zip(output_filenames, output_filenames, -+ [for_which_classes] * len(output_filenames), -+ [min_valid_obj_size] * len(output_filenames)))) -+ _ = [i.get() for i in results] -+ else: -+ print("WARNING! Cannot run postprocessing because the postprocessing file is missing. Make sure to run " -+ "consolidate_folds in the output folder of the model first!\nThe folder you need to run this in is " -+ "%s" % model) -+ -+ pool.close() -+ pool.join() -+ -+def predict_cases_fast(model, list_of_lists, output_filenames, folds, num_threads_preprocessing, -+ num_threads_nifti_save, segs_from_prev_stage=None, do_tta=True, mixed_precision=True, -+ overwrite_existing=False, -+ all_in_gpu=False, step_size=0.5, checkpoint_name="model_final_checkpoint", -+ segmentation_export_kwargs: dict = None): -+ assert len(list_of_lists) == len(output_filenames) -+ if segs_from_prev_stage is not None: assert len(segs_from_prev_stage) == len(output_filenames) -+ -+ pool = Pool(num_threads_nifti_save) -+ results = [] -+ -+ cleaned_output_files = [] -+ for o in output_filenames: -+ dr, f = os.path.split(o) -+ if len(dr) > 0: -+ maybe_mkdir_p(dr) -+ if not f.endswith(".nii.gz"): -+ f, _ = os.path.splitext(f) -+ f = f + ".nii.gz" -+ cleaned_output_files.append(join(dr, f)) -+ -+ if not overwrite_existing: -+ print("number of cases:", len(list_of_lists)) -+ not_done_idx = [i for i, j in enumerate(cleaned_output_files) if not isfile(j)] -+ -+ cleaned_output_files = [cleaned_output_files[i] for i in not_done_idx] -+ list_of_lists = [list_of_lists[i] for i in not_done_idx] -+ if segs_from_prev_stage is not None: -+ segs_from_prev_stage = [segs_from_prev_stage[i] for i in not_done_idx] -+ -+ print("number of cases that still need to be predicted:", len(cleaned_output_files)) -+ -+ print("emptying cuda cache") -+ torch.cuda.empty_cache() -+ -+ print("loading parameters for folds,", folds) -+ trainer, params = load_model_and_checkpoint_files(model, folds, mixed_precision=mixed_precision, checkpoint_name=checkpoint_name) -+ -+ if segmentation_export_kwargs is None: -+ if 'segmentation_export_params' in trainer.plans.keys(): -+ force_separate_z = trainer.plans['segmentation_export_params']['force_separate_z'] -+ interpolation_order = trainer.plans['segmentation_export_params']['interpolation_order'] -+ interpolation_order_z = trainer.plans['segmentation_export_params']['interpolation_order_z'] -+ else: -+ force_separate_z = None -+ interpolation_order = 1 -+ interpolation_order_z = 0 -+ else: -+ force_separate_z = segmentation_export_kwargs['force_separate_z'] -+ interpolation_order = segmentation_export_kwargs['interpolation_order'] -+ interpolation_order_z = segmentation_export_kwargs['interpolation_order_z'] -+ -+ print("starting preprocessing generator") -+ preprocessing = preprocess_multithreaded(trainer, list_of_lists, cleaned_output_files, num_threads_preprocessing, -+ segs_from_prev_stage) -+ -+ print("starting prediction...") -+ for preprocessed in preprocessing: -+ print("getting data from preprocessor") -+ output_filename, (d, dct) = preprocessed -+ print("got something") -+ if isinstance(d, str): -+ print("what I got is a string, so I need to load a file") -+ data = np.load(d) -+ os.remove(d) -+ d = data -+ -+ # preallocate the output arrays -+ # same dtype as the return value in predict_preprocessed_data_return_seg_and_softmax (saves time) -+ softmax_aggr = None # np.zeros((trainer.num_classes, *d.shape[1:]), dtype=np.float16) -+ all_seg_outputs = np.zeros((len(params), *d.shape[1:]), dtype=int) -+ print("predicting", output_filename) -+ -+ for i, p in enumerate(params): -+ trainer.load_checkpoint_ram(p, False) -+ -+ res = trainer.predict_preprocessed_data_return_seg_and_softmax(d, do_tta, -+ trainer.data_aug_params['mirror_axes'], True, -+ step_size=step_size, use_gaussian=True, -+ all_in_gpu=all_in_gpu, -+ mixed_precision=mixed_precision) -+ -+ if len(params) > 1: -+ # otherwise we dont need this and we can save ourselves the time it takes to copy that -+ print("aggregating softmax") -+ if softmax_aggr is None: -+ softmax_aggr = res[1] -+ else: -+ softmax_aggr += res[1] -+ all_seg_outputs[i] = res[0] -+ -+ print("obtaining segmentation map") -+ if len(params) > 1: -+ # we dont need to normalize the softmax by 1 / len(params) because this would not change the outcome of the argmax -+ seg = softmax_aggr.argmax(0) -+ else: -+ seg = all_seg_outputs[0] -+ -+ print("applying transpose_backward") -+ transpose_forward = trainer.plans.get('transpose_forward') -+ if transpose_forward is not None: -+ transpose_backward = trainer.plans.get('transpose_backward') -+ seg = seg.transpose([i for i in transpose_backward]) -+ -+ print("initializing segmentation export") -+ results.append(pool.starmap_async(save_segmentation_nifti, -+ ((seg, output_filename, dct, interpolation_order, force_separate_z, -+ interpolation_order_z),) -+ )) -+ print("done") -+ -+ print("inference done. Now waiting for the segmentation export to finish...") -+ _ = [i.get() for i in results] -+ # now apply postprocessing -+ # first load the postprocessing properties if they are present. Else raise a well visible warning -+ results = [] -+ pp_file = join(model, "postprocessing.json") -+ if isfile(pp_file): -+ print("postprocessing...") -+ shutil.copy(pp_file, os.path.dirname(output_filenames[0])) -+ # for_which_classes stores for which of the classes everything but the largest connected component needs to be -+ # removed -+ for_which_classes, min_valid_obj_size = load_postprocessing(pp_file) -+ results.append(pool.starmap_async(load_remove_save, -+ zip(output_filenames, output_filenames, -+ [for_which_classes] * len(output_filenames), -+ [min_valid_obj_size] * len(output_filenames)))) -+ _ = [i.get() for i in results] -+ else: -+ print("WARNING! Cannot run postprocessing because the postprocessing file is missing. Make sure to run " -+ "consolidate_folds in the output folder of the model first!\nThe folder you need to run this in is " -+ "%s" % model) -+ -+ pool.close() -+ pool.join() -+ -+ -+def predict_cases_fastest(model, list_of_lists, output_filenames, folds, num_threads_preprocessing, -+ num_threads_nifti_save, segs_from_prev_stage=None, do_tta=True, mixed_precision=True, -+ overwrite_existing=False, all_in_gpu=True, step_size=0.5, -+ checkpoint_name="model_final_checkpoint"): -+ assert len(list_of_lists) == len(output_filenames) -+ if segs_from_prev_stage is not None: assert len(segs_from_prev_stage) == len(output_filenames) -+ -+ pool = Pool(num_threads_nifti_save) -+ results = [] -+ -+ cleaned_output_files = [] -+ for o in output_filenames: -+ dr, f = os.path.split(o) -+ if len(dr) > 0: -+ maybe_mkdir_p(dr) -+ if not f.endswith(".nii.gz"): -+ f, _ = os.path.splitext(f) -+ f = f + ".nii.gz" -+ cleaned_output_files.append(join(dr, f)) -+ -+ if not overwrite_existing: -+ print("number of cases:", len(list_of_lists)) -+ not_done_idx = [i for i, j in enumerate(cleaned_output_files) if not isfile(j)] -+ -+ cleaned_output_files = [cleaned_output_files[i] for i in not_done_idx] -+ list_of_lists = [list_of_lists[i] for i in not_done_idx] -+ if segs_from_prev_stage is not None: -+ segs_from_prev_stage = [segs_from_prev_stage[i] for i in not_done_idx] -+ -+ print("number of cases that still need to be predicted:", len(cleaned_output_files)) -+ -+ print("emptying cuda cache") -+ torch.cuda.empty_cache() -+ -+ print("loading parameters for folds,", folds) -+ trainer, params = load_model_and_checkpoint_files(model, folds, mixed_precision=mixed_precision, checkpoint_name=checkpoint_name) -+ -+ print("starting preprocessing generator") -+ preprocessing = preprocess_multithreaded(trainer, list_of_lists, cleaned_output_files, num_threads_preprocessing, -+ segs_from_prev_stage) -+ -+ print("starting prediction...") -+ for preprocessed in preprocessing: -+ print("getting data from preprocessor") -+ output_filename, (d, dct) = preprocessed -+ print("got something") -+ if isinstance(d, str): -+ print("what I got is a string, so I need to load a file") -+ data = np.load(d) -+ os.remove(d) -+ d = data -+ -+ # preallocate the output arrays -+ # same dtype as the return value in predict_preprocessed_data_return_seg_and_softmax (saves time) -+ all_softmax_outputs = np.zeros((len(params), trainer.num_classes, *d.shape[1:]), dtype=np.float16) -+ all_seg_outputs = np.zeros((len(params), *d.shape[1:]), dtype=int) -+ print("predicting", output_filename) -+ -+ for i, p in enumerate(params): -+ trainer.load_checkpoint_ram(p, False) -+ res = trainer.predict_preprocessed_data_return_seg_and_softmax(d, do_tta, -+ trainer.data_aug_params['mirror_axes'], True, -+ step_size=step_size, use_gaussian=True, -+ all_in_gpu=all_in_gpu, -+ mixed_precision=mixed_precision) -+ if len(params) > 1: -+ # otherwise we dont need this and we can save ourselves the time it takes to copy that -+ all_softmax_outputs[i] = res[1] -+ all_seg_outputs[i] = res[0] -+ -+ print("aggregating predictions") -+ if len(params) > 1: -+ softmax_mean = np.mean(all_softmax_outputs, 0) -+ seg = softmax_mean.argmax(0) -+ else: -+ seg = all_seg_outputs[0] -+ -+ print("applying transpose_backward") -+ transpose_forward = trainer.plans.get('transpose_forward') -+ if transpose_forward is not None: -+ transpose_backward = trainer.plans.get('transpose_backward') -+ seg = seg.transpose([i for i in transpose_backward]) -+ -+ print("initializing segmentation export") -+ results.append(pool.starmap_async(save_segmentation_nifti, -+ ((seg, output_filename, dct, 0, None),) -+ )) -+ print("done") -+ -+ print("inference done. Now waiting for the segmentation export to finish...") -+ _ = [i.get() for i in results] -+ # now apply postprocessing -+ # first load the postprocessing properties if they are present. Else raise a well visible warning -+ results = [] -+ pp_file = join(model, "postprocessing.json") -+ if isfile(pp_file): -+ print("postprocessing...") -+ shutil.copy(pp_file, os.path.dirname(output_filenames[0])) -+ # for_which_classes stores for which of the classes everything but the largest connected component needs to be -+ # removed -+ for_which_classes, min_valid_obj_size = load_postprocessing(pp_file) -+ results.append(pool.starmap_async(load_remove_save, -+ zip(output_filenames, output_filenames, -+ [for_which_classes] * len(output_filenames), -+ [min_valid_obj_size] * len(output_filenames)))) -+ _ = [i.get() for i in results] -+ else: -+ print("WARNING! Cannot run postprocessing because the postprocessing file is missing. Make sure to run " -+ "consolidate_folds in the output folder of the model first!\nThe folder you need to run this in is " -+ "%s" % model) -+ -+ pool.close() -+ pool.join() -+ -+ -+def check_input_folder_and_return_caseIDs(input_folder, expected_num_modalities): -+ print("This model expects %d input modalities for each image" % expected_num_modalities) -+ files = subfiles(input_folder, suffix=".nii.gz", join=False, sort=True) -+ -+ maybe_case_ids = np.unique([i[:-12] for i in files]) -+ -+ remaining = deepcopy(files) -+ missing = [] -+ -+ assert len(files) > 0, "input folder did not contain any images (expected to find .nii.gz file endings)" -+ -+ # now check if all required files are present and that no unexpected files are remaining -+ for c in maybe_case_ids: -+ for n in range(expected_num_modalities): -+ expected_output_file = c + "_%04.0d.nii.gz" % n -+ if not isfile(join(input_folder, expected_output_file)): -+ missing.append(expected_output_file) -+ else: -+ remaining.remove(expected_output_file) -+ -+ print("Found %d unique case ids, here are some examples:" % len(maybe_case_ids), -+ np.random.choice(maybe_case_ids, min(len(maybe_case_ids), 10))) -+ print("If they don't look right, make sure to double check your filenames. They must end with _0000.nii.gz etc") -+ -+ if len(remaining) > 0: -+ print("found %d unexpected remaining files in the folder. Here are some examples:" % len(remaining), -+ np.random.choice(remaining, min(len(remaining), 10))) -+ -+ if len(missing) > 0: -+ print("Some files are missing:") -+ print(missing) -+ raise RuntimeError("missing files in input_folder") -+ -+ return maybe_case_ids -+ -+ -+def predict_from_folder(model: str, input_folder: str, output_folder: str, folds: Union[Tuple[int], List[int]], -+ save_npz: bool, num_threads_preprocessing: int, num_threads_nifti_save: int, -+ lowres_segmentations: Union[str, None], -+ part_id: int, num_parts: int, tta: bool, mixed_precision: bool = True, -+ overwrite_existing: bool = True, mode: str = 'normal', overwrite_all_in_gpu: bool = None, -+ step_size: float = 0.5, checkpoint_name: str = "model_final_checkpoint", -+ segmentation_export_kwargs: dict = None, pre_mode=None, fp=None): -+ """ -+ here we use the standard naming scheme to generate list_of_lists and output_files needed by predict_cases -+ -+ :param model: -+ :param input_folder: -+ :param output_folder: -+ :param folds: -+ :param save_npz: -+ :param num_threads_preprocessing: -+ :param num_threads_nifti_save: -+ :param lowres_segmentations: -+ :param part_id: -+ :param num_parts: -+ :param tta: -+ :param mixed_precision: -+ :param overwrite_existing: if not None then it will be overwritten with whatever is in there. None is default (no overwrite) -+ :return: -+ """ -+ maybe_mkdir_p(output_folder) -+ shutil.copy(join(model, 'plans.pkl'), output_folder) -+ -+ assert isfile(join(model, "plans.pkl")), "Folder with saved model weights must contain a plans.pkl file" -+ expected_num_modalities = load_pickle(join(model, "plans.pkl"))['num_modalities'] -+ -+ # check input folder integrity -+ case_ids = check_input_folder_and_return_caseIDs(input_folder, expected_num_modalities) -+ -+ output_files = [join(output_folder, i + ".nii.gz") for i in case_ids] -+ all_files = subfiles(input_folder, suffix=".nii.gz", join=False, sort=True) -+ list_of_lists = [[join(input_folder, i) for i in all_files if i[:len(j)].startswith(j) and -+ len(i) == (len(j) + 12)] for j in case_ids] -+ -+ if lowres_segmentations is not None: -+ assert isdir(lowres_segmentations), "if lowres_segmentations is not None then it must point to a directory" -+ lowres_segmentations = [join(lowres_segmentations, i + ".nii.gz") for i in case_ids] -+ assert all([isfile(i) for i in lowres_segmentations]), "not all lowres_segmentations files are present. " \ -+ "(I was searching for case_id.nii.gz in that folder)" -+ lowres_segmentations = lowres_segmentations[part_id::num_parts] -+ else: -+ lowres_segmentations = None -+ -+ if mode == "normal": # step this -+ if overwrite_all_in_gpu is None: # True -+ all_in_gpu = False -+ else: -+ all_in_gpu = overwrite_all_in_gpu -+ -+ return predict_cases(model, list_of_lists[part_id::num_parts], output_files[part_id::num_parts], folds, -+ save_npz, num_threads_preprocessing, num_threads_nifti_save, lowres_segmentations, tta, -+ mixed_precision=mixed_precision, overwrite_existing=overwrite_existing, all_in_gpu=all_in_gpu, -+ step_size=step_size, checkpoint_name=checkpoint_name, -+ segmentation_export_kwargs=segmentation_export_kwargs, pre_mode=pre_mode, fp=fp) -+ elif mode == "fast": -+ if overwrite_all_in_gpu is None: -+ all_in_gpu = True -+ else: -+ all_in_gpu = overwrite_all_in_gpu -+ -+ assert save_npz is False -+ return predict_cases_fast(model, list_of_lists[part_id::num_parts], output_files[part_id::num_parts], folds, -+ num_threads_preprocessing, num_threads_nifti_save, lowres_segmentations, -+ tta, mixed_precision=mixed_precision, overwrite_existing=overwrite_existing, all_in_gpu=all_in_gpu, -+ step_size=step_size, checkpoint_name=checkpoint_name, -+ segmentation_export_kwargs=segmentation_export_kwargs) -+ elif mode == "fastest": -+ if overwrite_all_in_gpu is None: -+ all_in_gpu = True -+ else: -+ all_in_gpu = overwrite_all_in_gpu -+ -+ assert save_npz is False -+ return predict_cases_fastest(model, list_of_lists[part_id::num_parts], output_files[part_id::num_parts], folds, -+ num_threads_preprocessing, num_threads_nifti_save, lowres_segmentations, -+ tta, mixed_precision=mixed_precision, overwrite_existing=overwrite_existing, all_in_gpu=all_in_gpu, -+ step_size=step_size, checkpoint_name=checkpoint_name) -+ else: -+ raise ValueError("unrecognized mode. Must be normal, fast or fastest") -+ -+ -+if __name__ == "__main__": -+ parser = argparse.ArgumentParser() -+ parser.add_argument("-i", '--input_folder', help="Must contain all modalities for each patient in the correct" -+ " order (same as training). Files must be named " -+ "CASENAME_XXXX.nii.gz where XXXX is the modality " -+ "identifier (0000, 0001, etc)", required=True) -+ parser.add_argument('-o', "--output_folder", required=True, help="folder for saving predictions") -+ parser.add_argument('-m', '--model_output_folder', -+ help='model output folder. Will automatically discover the folds ' -+ 'that were ' -+ 'run and use those as an ensemble', required=True) -+ parser.add_argument('-f', '--folds', nargs='+', default='None', help="folds to use for prediction. Default is None " -+ "which means that folds will be detected " -+ "automatically in the model output folder") -+ parser.add_argument('-z', '--save_npz', required=False, action='store_true', help="use this if you want to ensemble" -+ " these predictions with those of" -+ " other models. Softmax " -+ "probabilities will be saved as " -+ "compresed numpy arrays in " -+ "output_folder and can be merged " -+ "between output_folders with " -+ "merge_predictions.py") -+ parser.add_argument('-l', '--lowres_segmentations', required=False, default='None', help="if model is the highres " -+ "stage of the cascade then you need to use -l to specify where the segmentations of the " -+ "corresponding lowres unet are. Here they are required to do a prediction") -+ parser.add_argument("--part_id", type=int, required=False, default=0, help="Used to parallelize the prediction of " -+ "the folder over several GPUs. If you " -+ "want to use n GPUs to predict this " -+ "folder you need to run this command " -+ "n times with --part_id=0, ... n-1 and " -+ "--num_parts=n (each with a different " -+ "GPU (for example via " -+ "CUDA_VISIBLE_DEVICES=X)") -+ parser.add_argument("--num_parts", type=int, required=False, default=1, -+ help="Used to parallelize the prediction of " -+ "the folder over several GPUs. If you " -+ "want to use n GPUs to predict this " -+ "folder you need to run this command " -+ "n times with --part_id=0, ... n-1 and " -+ "--num_parts=n (each with a different " -+ "GPU (via " -+ "CUDA_VISIBLE_DEVICES=X)") -+ parser.add_argument("--num_threads_preprocessing", required=False, default=6, type=int, help= -+ "Determines many background processes will be used for data preprocessing. Reduce this if you " -+ "run into out of memory (RAM) problems. Default: 6") -+ parser.add_argument("--num_threads_nifti_save", required=False, default=2, type=int, help= -+ "Determines many background processes will be used for segmentation export. Reduce this if you " -+ "run into out of memory (RAM) problems. Default: 2") -+ parser.add_argument("--tta", required=False, type=int, default=1, help="Set to 0 to disable test time data " -+ "augmentation (speedup of factor " -+ "4(2D)/8(3D)), " -+ "lower quality segmentations") -+ parser.add_argument("--overwrite_existing", required=False, type=int, default=1, help="Set this to 0 if you need " -+ "to resume a previous " -+ "prediction. Default: 1 " -+ "(=existing segmentations " -+ "in output_folder will be " -+ "overwritten)") -+ parser.add_argument("--mode", type=str, default="normal", required=False) -+ parser.add_argument("--all_in_gpu", type=str, default="None", required=False, help="can be None, False or True") -+ parser.add_argument("--step_size", type=float, default=0.5, required=False, help="don't touch") -+ # parser.add_argument("--interp_order", required=False, default=3, type=int, -+ # help="order of interpolation for segmentations, has no effect if mode=fastest") -+ # parser.add_argument("--interp_order_z", required=False, default=0, type=int, -+ # help="order of interpolation along z is z is done differently") -+ # parser.add_argument("--force_separate_z", required=False, default="None", type=str, -+ # help="force_separate_z resampling. Can be None, True or False, has no effect if mode=fastest") -+ parser.add_argument('--disable_mixed_precision', default=False, action='store_true', required=False, -+ help='Predictions are done with mixed precision by default. This improves speed and reduces ' -+ 'the required vram. If you want to disable mixed precision you can set this flag. Note ' -+ 'that yhis is not recommended (mixed precision is ~2x faster!)') -+ -+ args = parser.parse_args() -+ input_folder = args.input_folder -+ output_folder = args.output_folder -+ part_id = args.part_id -+ num_parts = args.num_parts -+ model = args.model_output_folder -+ folds = args.folds -+ save_npz = args.save_npz -+ lowres_segmentations = args.lowres_segmentations -+ num_threads_preprocessing = args.num_threads_preprocessing -+ num_threads_nifti_save = args.num_threads_nifti_save -+ tta = args.tta -+ step_size = args.step_size -+ -+ # interp_order = args.interp_order -+ # interp_order_z = args.interp_order_z -+ # force_separate_z = args.force_separate_z -+ -+ # if force_separate_z == "None": -+ # force_separate_z = None -+ # elif force_separate_z == "False": -+ # force_separate_z = False -+ # elif force_separate_z == "True": -+ # force_separate_z = True -+ # else: -+ # raise ValueError("force_separate_z must be None, True or False. Given: %s" % force_separate_z) -+ -+ overwrite = args.overwrite_existing -+ mode = args.mode -+ all_in_gpu = args.all_in_gpu -+ -+ if lowres_segmentations == "None": -+ lowres_segmentations = None -+ -+ if isinstance(folds, list): -+ if folds[0] == 'all' and len(folds) == 1: -+ pass -+ else: -+ folds = [int(i) for i in folds] -+ elif folds == "None": -+ folds = None -+ else: -+ raise ValueError("Unexpected value for argument folds") -+ -+ if tta == 0: -+ tta = False -+ elif tta == 1: -+ tta = True -+ else: -+ raise ValueError("Unexpected value for tta, Use 1 or 0") -+ -+ if overwrite == 0: -+ overwrite = False -+ elif overwrite == 1: -+ overwrite = True -+ else: -+ raise ValueError("Unexpected value for overwrite, Use 1 or 0") -+ -+ assert all_in_gpu in ['None', 'False', 'True'] -+ if all_in_gpu == "None": -+ all_in_gpu = None -+ elif all_in_gpu == "True": -+ all_in_gpu = True -+ elif all_in_gpu == "False": -+ all_in_gpu = False -+ -+ predict_from_folder(model, input_folder, output_folder, folds, save_npz, num_threads_preprocessing, -+ num_threads_nifti_save, lowres_segmentations, part_id, num_parts, tta, mixed_precision=not args.disable_mixed_precision, -+ overwrite_existing=overwrite, mode=mode, overwrite_all_in_gpu=all_in_gpu, step_size=step_size) -diff --git a/pytorch/nnunet/inference/predict_simple2.py b/pytorch/nnunet/inference/predict_simple2.py -new file mode 100644 -index 0000000..2af423e ---- /dev/null -+++ b/pytorch/nnunet/inference/predict_simple2.py -@@ -0,0 +1,238 @@ -+# Copyright 2020 Division of Medical Image Computing, German Cancer Research Center (DKFZ), Heidelberg, Germany -+# -+# 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 argparse -+import torch -+ -+from nnunet.inference.predict2 import predict_from_folder -+from nnunet.paths import default_plans_identifier, network_training_output_dir, default_cascade_trainer, default_trainer -+from batchgenerators.utilities.file_and_folder_operations import join, isdir -+from nnunet.utilities.task_name_id_conversion import convert_id_to_task_name -+from nnunet.inference.infer_path import INFERENCE_INPUT_FOLDER, INFERENCE_OUTPUT_FOLDER -+ -+ -+def main(): -+ parser = argparse.ArgumentParser() -+ parser.add_argument("-i", '--input_folder', help="Must contain all modalities for each patient in the correct" -+ " order (same as training). Files must be named " -+ "CASENAME_XXXX.nii.gz where XXXX is the modality " -+ "identifier (0000, 0001, etc)", required=False, -+ default=INFERENCE_INPUT_FOLDER) -+ parser.add_argument('-o', "--output_folder", required=False, -+ default=INFERENCE_OUTPUT_FOLDER, help="folder for saving predictions") -+ parser.add_argument('-t', '--task_name', help='task name or task ID, required.', -+ default="Task003_Liver", required=False) -+ parser.add_argument('-pm', '--pre_mode', help='predict mode', required=False, default=-1) -+ parser.add_argument('-fp', '--file_path', help='input or output file path for npu bin files', required=True) -+ parser.add_argument('-tr', '--trainer_class_name', -+ help='Name of the nnUNetTrainer used for 2D U-Net, full resolution 3D U-Net and low resolution ' -+ 'U-Net. The default is %s. If you are running inference with the cascade and the folder ' -+ 'pointed to by --lowres_segmentations does not contain the segmentation maps generated by ' -+ 'the low resolution U-Net then the low resolution segmentation maps will be automatically ' -+ 'generated. For this case, make sure to set the trainer class here that matches your ' -+ '--cascade_trainer_class_name (this part can be ignored if defaults are used).' -+ % default_trainer, -+ required=False, -+ default="nnUNetPlusPlusTrainerV2") -+ parser.add_argument('-ctr', '--cascade_trainer_class_name', -+ help="Trainer class name used for predicting the 3D full resolution U-Net part of the cascade." -+ "Default is %s" % default_cascade_trainer, required=False, -+ default=default_cascade_trainer) -+ -+ parser.add_argument('-m', '--model', help="2d, 3d_lowres, 3d_fullres or 3d_cascade_fullres. Default: 3d_fullres", -+ default="3d_fullres", required=False) -+ -+ parser.add_argument('-p', '--plans_identifier', help='do not touch this unless you know what you are doing', -+ default=default_plans_identifier, required=False) -+ -+ parser.add_argument('-f', '--folds', nargs='+', default="None", -+ help="folds to use for prediction. Default is None which means that folds will be detected " -+ "automatically in the model output folder") -+ -+ parser.add_argument('-z', '--save_npz', required=False, action='store_true', -+ help="use this if you want to ensemble these predictions with those of other models. Softmax " -+ "probabilities will be saved as compressed numpy arrays in output_folder and can be " -+ "merged between output_folders with nnUNet_ensemble_predictions") -+ -+ parser.add_argument('-l', '--lowres_segmentations', required=False, default='None', -+ help="if model is the highres stage of the cascade then you can use this folder to provide " -+ "predictions from the low resolution 3D U-Net. If this is left at default, the " -+ "predictions will be generated automatically (provided that the 3D low resolution U-Net " -+ "network weights are present") -+ -+ parser.add_argument("--part_id", type=int, required=False, default=0, help="Used to parallelize the prediction of " -+ "the folder over several GPUs. If you " -+ "want to use n GPUs to predict this " -+ "folder you need to run this command " -+ "n times with --part_id=0, ... n-1 and " -+ "--num_parts=n (each with a different " -+ "GPU (for example via " -+ "CUDA_VISIBLE_DEVICES=X)") -+ -+ parser.add_argument("--num_parts", type=int, required=False, default=1, -+ help="Used to parallelize the prediction of " -+ "the folder over several GPUs. If you " -+ "want to use n GPUs to predict this " -+ "folder you need to run this command " -+ "n times with --part_id=0, ... n-1 and " -+ "--num_parts=n (each with a different " -+ "GPU (via " -+ "CUDA_VISIBLE_DEVICES=X)") -+ -+ parser.add_argument("--num_threads_preprocessing", required=False, default=6, type=int, help= -+ "Determines many background processes will be used for data preprocessing. Reduce this if you " -+ "run into out of memory (RAM) problems. Default: 6") -+ -+ parser.add_argument("--num_threads_nifti_save", required=False, default=2, type=int, help= -+ "Determines many background processes will be used for segmentation export. Reduce this if you " -+ "run into out of memory (RAM) problems. Default: 2") -+ -+ parser.add_argument("--disable_tta", required=False, default=False, action="store_true", -+ help="set this flag to disable test time data augmentation via mirroring. Speeds up inference " -+ "by roughly factor 4 (2D) or 8 (3D)") -+ -+ parser.add_argument("--overwrite_existing", required=False, default=False, action="store_true", -+ help="Set this flag if the target folder contains predictions that you would like to overwrite") -+ -+ parser.add_argument("--mode", type=str, default="normal", required=False, help="Hands off!") -+ parser.add_argument("--all_in_gpu", type=str, default="None", required=False, help="can be None, False or True. " -+ "Do not touch.") -+ parser.add_argument("--step_size", type=float, default=0.5, required=False, help="don't touch") -+ # parser.add_argument("--interp_order", required=False, default=3, type=int, -+ # help="order of interpolation for segmentations, has no effect if mode=fastest. Do not touch this.") -+ # parser.add_argument("--interp_order_z", required=False, default=0, type=int, -+ # help="order of interpolation along z is z is done differently. Do not touch this.") -+ # parser.add_argument("--force_separate_z", required=False, default="None", type=str, -+ # help="force_separate_z resampling. Can be None, True or False, has no effect if mode=fastest. " -+ # "Do not touch this.") -+ parser.add_argument('-chk', -+ help='checkpoint name, default: model_final_checkpoint', -+ required=False, -+ default='model_final_checkpoint') -+ parser.add_argument('--disable_mixed_precision', default=False, action='store_true', required=False, -+ help='Predictions are done with mixed precision by default. This improves speed and reduces ' -+ 'the required vram. If you want to disable mixed precision you can set this flag. Note ' -+ 'that yhis is not recommended (mixed precision is ~2x faster!)') -+ -+ args = parser.parse_args() -+ print(args) -+ -+ input_folder = args.input_folder -+ output_folder = args.output_folder -+ part_id = args.part_id -+ # 推理模式 -+ pre_mode = args.pre_mode -+ fp = args.file_path -+ num_parts = args.num_parts -+ folds = args.folds -+ save_npz = args.save_npz -+ lowres_segmentations = args.lowres_segmentations -+ num_threads_preprocessing = args.num_threads_preprocessing -+ num_threads_nifti_save = args.num_threads_nifti_save -+ disable_tta = args.disable_tta -+ step_size = args.step_size -+ # interp_order = args.interp_order -+ # interp_order_z = args.interp_order_z -+ # force_separate_z = args.force_separate_z -+ overwrite_existing = args.overwrite_existing -+ mode = args.mode -+ all_in_gpu = args.all_in_gpu -+ model = args.model -+ trainer_class_name = args.trainer_class_name -+ cascade_trainer_class_name = args.cascade_trainer_class_name -+ -+ task_name = args.task_name -+ -+ if not task_name.startswith("Task"): -+ task_id = int(task_name) -+ task_name = convert_id_to_task_name(task_id) -+ -+ assert model in ["2d", "3d_lowres", "3d_fullres", "3d_cascade_fullres"], "-m must be 2d, 3d_lowres, 3d_fullres or " \ -+ "3d_cascade_fullres" -+ -+ # if force_separate_z == "None": -+ # force_separate_z = None -+ # elif force_separate_z == "False": -+ # force_separate_z = False -+ # elif force_separate_z == "True": -+ # force_separate_z = True -+ # else: -+ # raise ValueError("force_separate_z must be None, True or False. Given: %s" % force_separate_z) -+ -+ if lowres_segmentations == "None": -+ lowres_segmentations = None -+ -+ if isinstance(folds, list): -+ if folds[0] == 'all' and len(folds) == 1: -+ pass -+ else: -+ folds = [int(i) for i in folds] -+ elif folds == "None": -+ folds = None -+ else: -+ raise ValueError("Unexpected value for argument folds") -+ -+ assert all_in_gpu in ['None', 'False', 'True'] -+ if all_in_gpu == "None": -+ all_in_gpu = None -+ elif all_in_gpu == "True": -+ all_in_gpu = True -+ elif all_in_gpu == "False": -+ all_in_gpu = False -+ -+ # we need to catch the case where model is 3d cascade fullres and the low resolution folder has not been set. -+ # In that case we need to try and predict with 3d low res first -+ if model == "3d_cascade_fullres" and lowres_segmentations is None: -+ print("lowres_segmentations is None. Attempting to predict 3d_lowres first...") -+ assert part_id == 0 and num_parts == 1, "if you don't specify a --lowres_segmentations folder for the " \ -+ "inference of the cascade, custom values for part_id and num_parts " \ -+ "are not supported. If you wish to have multiple parts, please " \ -+ "run the 3d_lowres inference first (separately)" -+ model_folder_name = join(network_training_output_dir, "3d_lowres", task_name, trainer_class_name + "__" + -+ args.plans_identifier) -+ assert isdir(model_folder_name), "model output folder not found. Expected: %s" % model_folder_name -+ lowres_output_folder = join(output_folder, "3d_lowres_predictions") -+ predict_from_folder(model_folder_name, input_folder, lowres_output_folder, folds, False, -+ num_threads_preprocessing, num_threads_nifti_save, None, part_id, num_parts, not disable_tta, -+ overwrite_existing=overwrite_existing, mode=mode, overwrite_all_in_gpu=all_in_gpu, -+ mixed_precision=not args.disable_mixed_precision, -+ step_size=step_size) -+ lowres_segmentations = lowres_output_folder -+ torch.cuda.empty_cache() -+ print("3d_lowres done") -+ -+ if model == "3d_cascade_fullres": -+ trainer = cascade_trainer_class_name -+ else: -+ trainer = trainer_class_name -+ print(network_training_output_dir) -+ print(model) -+ print(task_name) -+ print(trainer) -+ print(args.plans_identifier) -+ model_folder_name = join(network_training_output_dir, model, task_name, trainer + "__" + -+ args.plans_identifier) -+ print("using model stored in ", model_folder_name) -+ assert isdir(model_folder_name), "model output folder not found. Expected: %s" % model_folder_name -+ -+ predict_from_folder(model_folder_name, input_folder, output_folder, folds, save_npz, num_threads_preprocessing, -+ num_threads_nifti_save, lowres_segmentations, part_id, num_parts, not disable_tta, -+ overwrite_existing=overwrite_existing, mode=mode, overwrite_all_in_gpu=all_in_gpu, -+ mixed_precision=not args.disable_mixed_precision, -+ step_size=step_size, checkpoint_name=args.chk, pre_mode=pre_mode, fp=fp) -+ -+ -+if __name__ == "__main__": -+ main() -diff --git a/pytorch/nnunet/inference/read_bin.py b/pytorch/nnunet/inference/read_bin.py -new file mode 100644 -index 0000000..972d940 ---- /dev/null -+++ b/pytorch/nnunet/inference/read_bin.py -@@ -0,0 +1,30 @@ -+import numpy -+import pdb -+import os -+ -+ -+def read_from_bin(file_name, folder_path='/root/heyupeng/result/dumpOutput_device0/'): -+ file = os.path.join(folder_path, file_name) -+ data = numpy.fromfile(file, dtype='float32') -+ data = data.reshape(3, 128, 128, 128) -+ return data -+ -+ -+def main(): -+ file = 'liver_132_0_128_0_128_0_128_1.bin' -+ print('ready to load:', file) -+ data = numpy.fromfile(file, dtype='float32') -+ data = data.reshape(3, 128, 128, 128) -+ pdb.set_trace() -+ print(data.shape) -+ for i in range(5): -+ print(data[0, 0, 0, i*7:(i+1)*7]) -+ print('-----') -+ for i in range(5): -+ print(data[0, 0, 0, i*7+50:(i+1)*7+50]) -+ pdb.set_trace() -+ print('end\n') -+ -+ -+if __name__ == "__main__": -+ main() -\ No newline at end of file -diff --git a/pytorch/nnunet/inference/read_pkl_file.py b/pytorch/nnunet/inference/read_pkl_file.py -new file mode 100644 -index 0000000..5dcc37b ---- /dev/null -+++ b/pytorch/nnunet/inference/read_pkl_file.py -@@ -0,0 +1,22 @@ -+import numpy -+import pdb -+import os -+import pickle -+ -+ -+def read_pkl(file_name, folder_path='/data/yupeng/environment_variables/nnUNet_preprocessed/Task003_Liver/'): -+ file = os.path.join(folder_path, file_name) -+ data = open(file, 'rb') -+ data = pickle.load(data) -+ return data -+ -+ -+def main(): -+ file = 'dataset_properties.pkl' -+ print('ready to load:', file) -+ data = read_pkl(file) -+ print('end\n') -+ -+ -+if __name__ == "__main__": -+ main() -\ No newline at end of file -diff --git a/pytorch/nnunet/inference/read_txt.py b/pytorch/nnunet/inference/read_txt.py -new file mode 100644 -index 0000000..37c94aa ---- /dev/null -+++ b/pytorch/nnunet/inference/read_txt.py -@@ -0,0 +1,29 @@ -+import numpy -+import pdb -+import os -+ -+ -+def read_from_bin(file_name, folder_path='/root/heyupeng/result/dumpOutput_device0/'): -+ file = os.path.join(folder_path, file_name) -+ data = numpy.loadtxt(file) -+ data = data.reshape(3, 128, 128, 128) -+ return data -+ -+ -+def main(): -+ file = 'liver_132_0_128_0_128_0_128_1.txt' -+ print('ready to load:', file) -+ data = numpy.loadtxt(file) -+ data = data.reshape(3, 128, 128, 128) -+ pdb.set_trace() -+ print(data.shape) -+ for i in range(5): -+ print(data[0, 0, 0, i*7:(i+1)*7]) -+ print('-----') -+ for i in range(5): -+ print(data[0, 0, 0, i*7+50:(i+1)*7+50]) -+ pdb.set_trace() -+ print('end\n') -+ -+if __name__ == "__main__": -+ main() -diff --git a/pytorch/nnunet/network_architecture/generic_UNetPlusPlus.py b/pytorch/nnunet/network_architecture/generic_UNetPlusPlus.py -index 5c2f816..5b831ea 100644 ---- a/pytorch/nnunet/network_architecture/generic_UNetPlusPlus.py -+++ b/pytorch/nnunet/network_architecture/generic_UNetPlusPlus.py -@@ -21,7 +21,8 @@ import numpy as np - from nnunet.network_architecture.initialization import InitWeights_He - from nnunet.network_architecture.neural_network import SegmentationNetwork - import torch.nn.functional -- -+import pdb -+# pdb.set_trace() - - class ConvDropoutNormNonlin(nn.Module): - """ -@@ -393,7 +394,7 @@ class Generic_UNetPlusPlus(SegmentationNetwork): - - def forward(self, x): - # skips = [] -- seg_outputs = [] -+ seg_outputs = [] # x是五维的 - x0_0 = self.conv_blocks_context[0](x) - x1_0 = self.conv_blocks_context[1](x0_0) - x0_1 = self.loc4[0](torch.cat([x0_0, self.up4[0](x1_0)], 1)) -@@ -425,7 +426,7 @@ class Generic_UNetPlusPlus(SegmentationNetwork): - x0_5 = self.loc0[4](torch.cat([x0_0, x0_1, x0_2, x0_3, x0_4, self.up0[4](x1_4)], 1)) - seg_outputs.append(self.final_nonlin(self.seg_outputs[-5](x0_5))) - -- if self._deep_supervision and self.do_ds: -+ if self._deep_supervision and self.do_ds: # False - return tuple([seg_outputs[-1]] + [i(j) for i, j in - zip(list(self.upscale_logits_ops)[::-1], seg_outputs[:-1][::-1])]) - else: -diff --git a/pytorch/nnunet/network_architecture/neural_network.py b/pytorch/nnunet/network_architecture/neural_network.py -index baa8a05..9425fe9 100644 ---- a/pytorch/nnunet/network_architecture/neural_network.py -+++ b/pytorch/nnunet/network_architecture/neural_network.py -@@ -21,8 +21,14 @@ from torch import nn - import torch - from scipy.ndimage.filters import gaussian_filter - from typing import Union, Tuple, List -+import os - - from torch.cuda.amp import autocast ++# Copyright 2020 Division of Medical Image Computing, German Cancer Research Center (DKFZ), Heidelberg, Germany ++# ++# 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 argparse ++from copy import deepcopy ++from typing import Tuple, Union, List ++ ++import numpy as np ++from batchgenerators.augmentations.utils import resize_segmentation ++from nnunet.inference.segmentation_export import save_segmentation_nifti_from_softmax, save_segmentation_nifti ++from batchgenerators.utilities.file_and_folder_operations import * ++from multiprocessing import Process, Queue ++import torch ++import SimpleITK as sitk ++import shutil ++from multiprocessing import Pool ++from nnunet.postprocessing.connected_components import load_remove_save, load_postprocessing ++from nnunet.training.model_restore import load_model_and_checkpoint_files ++from nnunet.training.network_training.nnUNetTrainer import nnUNetTrainer ++from nnunet.utilities.one_hot_encoding import to_one_hot ++from nnunet.utilities.to_torch import maybe_to_torch, to_cuda +import pdb -+from glob import glob -+import time -+from nnunet.inference.read_bin import read_from_bin -+from nnunet.inference.infer_path import INFERENCE_SHAPE_PATH, INFERENCE_BIN_INPUT_FOLDER, INFERENCE_BIN_OUTPUT_FOLDER - - - class NeuralNetwork(nn.Module): -@@ -75,7 +81,8 @@ class SegmentationNetwork(NeuralNetwork): - step_size: float = 0.5, patch_size: Tuple[int, ...] = None, regions_class_order: Tuple[int, ...] = None, - use_gaussian: bool = False, pad_border_mode: str = "constant", - pad_kwargs: dict = None, all_in_gpu: bool = False, -- verbose: bool = True, mixed_precision: bool = True) -> Tuple[np.ndarray, np.ndarray]: -+ verbose: bool = True, mixed_precision: bool = True, img_name=None, -+ pre_mode=None, fp=None) -> Tuple[np.ndarray, np.ndarray]: - """ - Use this function to predict a 3D image. It does not matter whether the network is a 2D or 3D U-Net, it will - detect that automatically and run the appropriate code. -@@ -133,7 +140,7 @@ class SegmentationNetwork(NeuralNetwork): - - assert len(x.shape) == 4, "data must have shape (c,x,y,z)" - -- if mixed_precision: -+ if mixed_precision: # True - context = autocast - else: - context = no_op -@@ -141,11 +148,11 @@ class SegmentationNetwork(NeuralNetwork): - with context(): - with torch.no_grad(): - if self.conv_op == nn.Conv3d: -- if use_sliding_window: -+ if use_sliding_window: # 走到这里 - res = self._internal_predict_3D_3Dconv_tiled(x, step_size, do_mirroring, mirror_axes, patch_size, - regions_class_order, use_gaussian, pad_border_mode, - pad_kwargs=pad_kwargs, all_in_gpu=all_in_gpu, -- verbose=verbose) -+ verbose=verbose, img_name=img_name, pre_mode=pre_mode, fp=fp) - else: - res = self._internal_predict_3D_3Dconv(x, patch_size, do_mirroring, mirror_axes, regions_class_order, - pad_border_mode, pad_kwargs=pad_kwargs, verbose=verbose) -@@ -284,19 +291,161 @@ class SegmentationNetwork(NeuralNetwork): - - return steps - -+ # def _internal_predict_3D_3Dconv_tiled(self, x: np.ndarray, step_size: float, do_mirroring: bool, mirror_axes: tuple, -+ # patch_size: tuple, regions_class_order: tuple, use_gaussian: bool, -+ # pad_border_mode: str, pad_kwargs: dict, all_in_gpu: bool, -+ # verbose: bool, img_name=None) -> Tuple[np.ndarray, np.ndarray]: -+ # # better safe than sorry -+ # assert len(x.shape) == 4, "x must be (c, x, y, z)" -+ # assert self.get_device() != "cpu" -+ # if verbose: print("step_size:", step_size) # 0.5 -+ # if verbose: print("do mirror:", do_mirroring) # True -+ # -+ # torch.cuda.empty_cache() -+ # -+ # assert patch_size is not None, "patch_size cannot be None for tiled prediction" # 128, 128, 128 -+ # -+ # # for sliding window inference the image must at least be as large as the patch size. It does not matter -+ # # whether the shape is divisible by 2**num_pool as long as the patch size is -+ # data, slicer = pad_nd_image(x, patch_size, pad_border_mode, pad_kwargs, True, None) -+ # data_shape = data.shape # still c, x, y, z ++ ++ ++def preprocess_save_to_queue(preprocess_fn, q, list_of_lists, output_files, segs_from_prev_stage, classes, ++ transpose_forward): ++ # suppress output ++ # sys.stdout = open(os.devnull, 'w') ++ ++ errors_in = [] ++ for i, l in enumerate(list_of_lists): ++ try: ++ output_file = output_files[i] ++ print("preprocessing", output_file) ++ d, _, dct = preprocess_fn(l) ++ # print(output_file, dct) ++ if segs_from_prev_stage[i] is not None: ++ assert isfile(segs_from_prev_stage[i]) and segs_from_prev_stage[i].endswith( ++ ".nii.gz"), "segs_from_prev_stage" \ ++ " must point to a " \ ++ "segmentation file" ++ seg_prev = sitk.GetArrayFromImage(sitk.ReadImage(segs_from_prev_stage[i])) ++ # check to see if shapes match ++ img = sitk.GetArrayFromImage(sitk.ReadImage(l[0])) ++ assert all([i == j for i, j in zip(seg_prev.shape, img.shape)]), "image and segmentation from previous " \ ++ "stage don't have the same pixel array " \ ++ "shape! image: %s, seg_prev: %s" % \ ++ (l[0], segs_from_prev_stage[i]) ++ seg_prev = seg_prev.transpose(transpose_forward) ++ seg_reshaped = resize_segmentation(seg_prev, d.shape[1:], order=1, cval=0) ++ seg_reshaped = to_one_hot(seg_reshaped, classes) ++ d = np.vstack((d, seg_reshaped)).astype(np.float32) ++ """There is a problem with python process communication that prevents us from communicating obejcts ++ larger than 2 GB between processes (basically when the length of the pickle string that will be sent is ++ communicated by the multiprocessing.Pipe object then the placeholder (\%i I think) does not allow for long ++ enough strings (lol). This could be fixed by changing i to l (for long) but that would require manually ++ patching system python code. We circumvent that problem here by saving softmax_pred to a npy file that will ++ then be read (and finally deleted) by the Process. save_segmentation_nifti_from_softmax can take either ++ filename or np.ndarray and will handle this automatically""" ++ print(d.shape) ++ if np.prod(d.shape) > (2e9 / 4 * 0.85): # *0.85 just to be save, 4 because float32 is 4 bytes ++ print( ++ "This output is too large for python process-process communication. " ++ "Saving output temporarily to disk") ++ np.save(output_file[:-7] + ".npy", d) ++ d = output_file[:-7] + ".npy" ++ q.put((output_file, (d, dct))) ++ except KeyboardInterrupt: ++ raise KeyboardInterrupt ++ except Exception as e: ++ print("error in", l) ++ print(e) ++ q.put("end") ++ if len(errors_in) > 0: ++ print("There were some errors in the following cases:", errors_in) ++ print("These cases were ignored.") ++ else: ++ print("This worker has ended successfully, no errors to report") ++ # restore output ++ # sys.stdout = sys.__stdout__ ++ ++ ++def preprocess_multithreaded(trainer, list_of_lists, output_files, num_processes=2, segs_from_prev_stage=None): ++ if segs_from_prev_stage is None: ++ segs_from_prev_stage = [None] * len(list_of_lists) ++ ++ num_processes = min(len(list_of_lists), num_processes) ++ ++ classes = list(range(1, trainer.num_classes)) ++ assert isinstance(trainer, nnUNetTrainer) ++ q = Queue(1) ++ processes = [] ++ for i in range(num_processes): ++ pr = Process(target=preprocess_save_to_queue, args=(trainer.preprocess_patient, q, ++ list_of_lists[i::num_processes], ++ output_files[i::num_processes], ++ segs_from_prev_stage[i::num_processes], ++ classes, trainer.plans['transpose_forward'])) ++ pr.start() ++ processes.append(pr) ++ ++ try: ++ end_ctr = 0 ++ while end_ctr != num_processes: ++ item = q.get() ++ if item == "end": ++ end_ctr += 1 ++ continue ++ else: ++ yield item ++ ++ finally: ++ for p in processes: ++ if p.is_alive(): ++ p.terminate() # this should not happen but better safe than sorry right ++ p.join() ++ ++ q.close() ++ ++ ++def pth2onnx(model, output_file=r'/home/yupeng/HUAWEI/UNetPlusPlus/pytorch/nnunet/run/nnunetplusplus.onnx'): ++ # model = EfficientNet.from_pretrained('efficientnet-b0', weights_path=input_file) ++ # 调整模型为eval mode ++ model.eval() ++ # 输入节点名 ++ input_names = ["image"] ++ # 输出节点名 ++ output_names = ["class"] ++ dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} ++ dummy_input = torch.randn(1, 1, 128, 128, 128) ++ # dummy_input = to_cuda(dummy_input) ++ # verbose=True,支持打印onnx节点和对应的PyTorch代码行 ++ torch.onnx.export(model, dummy_input, output_file, input_names=input_names, dynamic_axes=dynamic_axes, ++ output_names=output_names, opset_version=11, verbose=True) ++ ++ ++def predict_cases(model, list_of_lists, output_filenames, folds, save_npz, num_threads_preprocessing, ++ num_threads_nifti_save, segs_from_prev_stage=None, do_tta=True, mixed_precision=True, overwrite_existing=False, ++ all_in_gpu=False, step_size=0.5, checkpoint_name="model_final_checkpoint", ++ segmentation_export_kwargs: dict = None, pre_mode=None, fp=None): ++ """ ++ :param segmentation_export_kwargs: ++ :param model: folder where the model is saved, must contain fold_x subfolders ++ :param list_of_lists: [[case0_0000.nii.gz, case0_0001.nii.gz], [case1_0000.nii.gz, case1_0001.nii.gz], ...] ++ :param output_filenames: [output_file_case0.nii.gz, output_file_case1.nii.gz, ...] ++ :param folds: default: (0, 1, 2, 3, 4) (but can also be 'all' or a subset of the five folds, for example use (0, ) ++ for using only fold_0 ++ :param save_npz: default: False ++ :param num_threads_preprocessing: ++ :param num_threads_nifti_save: ++ :param segs_from_prev_stage: ++ :param do_tta: default: True, can be set to False for a 8x speedup at the cost of a reduced segmentation quality ++ :param overwrite_existing: default: True ++ :param mixed_precision: if None then we take no action. If True/False we overwrite what the model has in its init ++ :return: ++ """ ++ assert len(list_of_lists) == len(output_filenames) ++ if segs_from_prev_stage is not None: assert len(segs_from_prev_stage) == len(output_filenames) ++ ++ pool = Pool(num_threads_nifti_save) ++ results = [] ++ ++ cleaned_output_files = [] ++ for o in output_filenames: ++ dr, f = os.path.split(o) ++ if len(dr) > 0: ++ maybe_mkdir_p(dr) ++ if not f.endswith(".nii.gz"): ++ f, _ = os.path.splitext(f) ++ f = f + ".nii.gz" ++ cleaned_output_files.append(join(dr, f)) ++ ++ if not overwrite_existing: ++ print("number of cases:", len(list_of_lists)) ++ not_done_idx = [i for i, j in enumerate(cleaned_output_files) if not isfile(j)] ++ ++ cleaned_output_files = [cleaned_output_files[i] for i in not_done_idx] ++ list_of_lists = [list_of_lists[i] for i in not_done_idx] ++ if segs_from_prev_stage is not None: ++ segs_from_prev_stage = [segs_from_prev_stage[i] for i in not_done_idx] ++ ++ print("number of cases that still need to be predicted:", len(cleaned_output_files)) ++ ++ print("emptying cuda cache") ++ torch.cuda.empty_cache() ++ ''' ++ model='/data/yupeng/environment_variables/RESULTS_FOLDER/nnUNet/3d_fullres/Task003_Liver/nnUNetPlusPlusTrainerV2__nnUNetPlansv2.1' ++ folds=None ++ mixed_precision=True ++ checkpoint_name='model_final_checkpoint' ++ trainer=class-nnUNetPlusPlusTrainerV2 ++ params=list 5 -> dict 6 -> epoch state_dict optimizer_state_dict lr_scheduler_state_dict plot_stuff amp_grad_scaler ++ ''' ++ print("loading parameters for folds,", folds) # 得到参数,实际还未加载进模型 ++ trainer, params = load_model_and_checkpoint_files(model, folds, mixed_precision=mixed_precision, checkpoint_name=checkpoint_name) ++ ++ if segmentation_export_kwargs is None: ++ if 'segmentation_export_params' in trainer.plans.keys(): ++ force_separate_z = trainer.plans['segmentation_export_params']['force_separate_z'] ++ interpolation_order = trainer.plans['segmentation_export_params']['interpolation_order'] ++ interpolation_order_z = trainer.plans['segmentation_export_params']['interpolation_order_z'] ++ else: # 走到这里 ++ force_separate_z = None ++ interpolation_order = 1 ++ interpolation_order_z = 0 ++ else: ++ force_separate_z = segmentation_export_kwargs['force_separate_z'] ++ interpolation_order = segmentation_export_kwargs['interpolation_order'] ++ interpolation_order_z = segmentation_export_kwargs['interpolation_order_z'] ++ ++ print("starting preprocessing generator") ++ preprocessing = preprocess_multithreaded(trainer, list_of_lists, cleaned_output_files, num_threads_preprocessing, ++ segs_from_prev_stage) ++ # unet++V2class, [['/data/yupeng/environment_variables/nnUNet_raw_data_base/nnUNet_raw_data/Task003_Liver/imagesTs/liver_132_0000.nii.gz']] ++ # ['/data/yupeng/environment_variables/output/liver_132.nii.gz'], 6, None ++ print("starting prediction...") ++ if int(pre_mode) == -1: ++ p = params[0] ++ trainer.load_checkpoint_ram(p, False) # nnUnetPlusPlusTrainerV2,实际函数在network_trainer里 ++ print('pth2onnx start') ++ pth2onnx(trainer.network, fp) ++ print('pth2onnx end') ++ print('onnx模型已经输出至:', fp) ++ import sys ++ sys.exit(0) ++ all_output_files = [] ++ for preprocessed in preprocessing: ++ output_filename, (d, dct) = preprocessed ++ print('output_filename, d, dct = ', output_filename, d, dct) ++ all_output_files.append(all_output_files) ++ if isinstance(d, str): ++ data = np.load(d) ++ os.remove(d) ++ d = data ++ print("predicting", output_filename) ++ softmax = [] ++ params = [params[0]] # 只求第一个模型的推理结果 ++ for p in params: ++ # trainer.load_checkpoint_ram(p, False) # nnUnetPlusPlusTrainerV2,实际函数在network_trainer里 ++ # output_filename = '/data/yupeng/environment_variables/output/liver_132.nii.gz' ++ ttttt = trainer.predict_preprocessed_data_return_seg_and_softmax(d, do_tta, trainer.data_aug_params[ ++ 'mirror_axes'], True, step_size=step_size, use_gaussian=True, all_in_gpu=all_in_gpu, ++ mixed_precision=mixed_precision, img_name=output_filename, pre_mode=pre_mode, fp=fp) # tuple(ndarray 489 500 500; 3 489 500 500) ++ softmax.append(ttttt[1][None]) # 扩充了1 3 489 500 500 ++ ''' ++ d= ++ do_tta= ++ step_size= ++ all_in_gpu= ++ mixed_precision= ++ softmax= ++ ''' ++ # softmax是list 5,每个元素是ndarray 1 3 489 500 500 ++ softmax = np.vstack(softmax) # 5 3 489 500 500 ++ softmax_mean = np.mean(softmax, 0) # 3 489 500 500 ++ ++ transpose_forward = trainer.plans.get('transpose_forward') # [0,1,2] ++ if transpose_forward is not None: ++ transpose_backward = trainer.plans.get('transpose_backward') ++ softmax_mean = softmax_mean.transpose([0] + [i + 1 for i in transpose_backward]) ++ ++ if save_npz: # False ++ npz_file = output_filename[:-7] + ".npz" ++ else: ++ npz_file = None ++ ++ if hasattr(trainer, 'regions_class_order'): # False ++ region_class_order = trainer.regions_class_order ++ else: ++ region_class_order = None ++ ++ """There is a problem with python process communication that prevents us from communicating obejcts ++ larger than 2 GB between processes (basically when the length of the pickle string that will be sent is ++ communicated by the multiprocessing.Pipe object then the placeholder (\%i I think) does not allow for long ++ enough strings (lol). This could be fixed by changing i to l (for long) but that would require manually ++ patching system python code. We circumvent that problem here by saving softmax_pred to a npy file that will ++ then be read (and finally deleted) by the Process. save_segmentation_nifti_from_softmax can take either ++ filename or np.ndarray and will handle this automatically""" ++ bytes_per_voxel = 4 ++ if all_in_gpu: ++ bytes_per_voxel = 2 # if all_in_gpu then the return value is half (float16) ++ if np.prod(softmax_mean.shape) > (2e9 / bytes_per_voxel * 0.85): # * 0.85 just to be save ++ print( ++ "This output is too large for python process-process communication. Saving output temporarily to disk") ++ np.save(output_filename[:-7] + ".npy", softmax_mean) ++ softmax_mean = output_filename[:-7] + ".npy" ++ ++ results.append(pool.starmap_async(save_segmentation_nifti_from_softmax, ++ ((softmax_mean, output_filename, dct, interpolation_order, region_class_order, ++ None, None, ++ npz_file, None, force_separate_z, interpolation_order_z),) ++ )) ++ ++ print("inference done. Now waiting for the segmentation export to finish...") ++ _ = [i.get() for i in results] ++ # now apply postprocessing ++ # first load the postprocessing properties if they are present. Else raise a well visible warning ++ results = [] ++ pp_file = join(model, "postprocessing.json") # '/data/yupeng/environment_variables/RESULTS_FOLDER/nnUNet/3d_fullres/Task003_Liver/nnUNetPlusPlusTrainerV2__nnUNetPlansv2.1/postprocessing.json' ++ if isfile(pp_file): ++ print("postprocessing...") ++ shutil.copy(pp_file, os.path.abspath(os.path.dirname(output_filenames[0]))) ++ # for_which_classes stores for which of the classes everything but the largest connected component needs to be ++ # removed ++ for_which_classes, min_valid_obj_size = load_postprocessing(pp_file) ++ results.append(pool.starmap_async(load_remove_save, ++ zip(output_filenames, output_filenames, ++ [for_which_classes] * len(output_filenames), ++ [min_valid_obj_size] * len(output_filenames)))) ++ _ = [i.get() for i in results] ++ else: ++ print("WARNING! Cannot run postprocessing because the postprocessing file is missing. Make sure to run " ++ "consolidate_folds in the output folder of the model first!\nThe folder you need to run this in is " ++ "%s" % model) ++ ++ pool.close() ++ pool.join() ++ ++def predict_cases_fast(model, list_of_lists, output_filenames, folds, num_threads_preprocessing, ++ num_threads_nifti_save, segs_from_prev_stage=None, do_tta=True, mixed_precision=True, ++ overwrite_existing=False, ++ all_in_gpu=False, step_size=0.5, checkpoint_name="model_final_checkpoint", ++ segmentation_export_kwargs: dict = None): ++ assert len(list_of_lists) == len(output_filenames) ++ if segs_from_prev_stage is not None: assert len(segs_from_prev_stage) == len(output_filenames) ++ ++ pool = Pool(num_threads_nifti_save) ++ results = [] ++ ++ cleaned_output_files = [] ++ for o in output_filenames: ++ dr, f = os.path.split(o) ++ if len(dr) > 0: ++ maybe_mkdir_p(dr) ++ if not f.endswith(".nii.gz"): ++ f, _ = os.path.splitext(f) ++ f = f + ".nii.gz" ++ cleaned_output_files.append(join(dr, f)) ++ ++ if not overwrite_existing: ++ print("number of cases:", len(list_of_lists)) ++ not_done_idx = [i for i, j in enumerate(cleaned_output_files) if not isfile(j)] ++ ++ cleaned_output_files = [cleaned_output_files[i] for i in not_done_idx] ++ list_of_lists = [list_of_lists[i] for i in not_done_idx] ++ if segs_from_prev_stage is not None: ++ segs_from_prev_stage = [segs_from_prev_stage[i] for i in not_done_idx] ++ ++ print("number of cases that still need to be predicted:", len(cleaned_output_files)) ++ ++ print("emptying cuda cache") ++ torch.cuda.empty_cache() ++ ++ print("loading parameters for folds,", folds) ++ trainer, params = load_model_and_checkpoint_files(model, folds, mixed_precision=mixed_precision, checkpoint_name=checkpoint_name) ++ ++ if segmentation_export_kwargs is None: ++ if 'segmentation_export_params' in trainer.plans.keys(): ++ force_separate_z = trainer.plans['segmentation_export_params']['force_separate_z'] ++ interpolation_order = trainer.plans['segmentation_export_params']['interpolation_order'] ++ interpolation_order_z = trainer.plans['segmentation_export_params']['interpolation_order_z'] ++ else: ++ force_separate_z = None ++ interpolation_order = 1 ++ interpolation_order_z = 0 ++ else: ++ force_separate_z = segmentation_export_kwargs['force_separate_z'] ++ interpolation_order = segmentation_export_kwargs['interpolation_order'] ++ interpolation_order_z = segmentation_export_kwargs['interpolation_order_z'] ++ ++ print("starting preprocessing generator") ++ preprocessing = preprocess_multithreaded(trainer, list_of_lists, cleaned_output_files, num_threads_preprocessing, ++ segs_from_prev_stage) ++ ++ print("starting prediction...") ++ for preprocessed in preprocessing: ++ print("getting data from preprocessor") ++ output_filename, (d, dct) = preprocessed ++ print("got something") ++ if isinstance(d, str): ++ print("what I got is a string, so I need to load a file") ++ data = np.load(d) ++ os.remove(d) ++ d = data ++ ++ # preallocate the output arrays ++ # same dtype as the return value in predict_preprocessed_data_return_seg_and_softmax (saves time) ++ softmax_aggr = None # np.zeros((trainer.num_classes, *d.shape[1:]), dtype=np.float16) ++ all_seg_outputs = np.zeros((len(params), *d.shape[1:]), dtype=int) ++ print("predicting", output_filename) ++ ++ for i, p in enumerate(params): ++ trainer.load_checkpoint_ram(p, False) ++ ++ res = trainer.predict_preprocessed_data_return_seg_and_softmax(d, do_tta, ++ trainer.data_aug_params['mirror_axes'], True, ++ step_size=step_size, use_gaussian=True, ++ all_in_gpu=all_in_gpu, ++ mixed_precision=mixed_precision) ++ ++ if len(params) > 1: ++ # otherwise we dont need this and we can save ourselves the time it takes to copy that ++ print("aggregating softmax") ++ if softmax_aggr is None: ++ softmax_aggr = res[1] ++ else: ++ softmax_aggr += res[1] ++ all_seg_outputs[i] = res[0] ++ ++ print("obtaining segmentation map") ++ if len(params) > 1: ++ # we dont need to normalize the softmax by 1 / len(params) because this would not change the outcome of the argmax ++ seg = softmax_aggr.argmax(0) ++ else: ++ seg = all_seg_outputs[0] ++ ++ print("applying transpose_backward") ++ transpose_forward = trainer.plans.get('transpose_forward') ++ if transpose_forward is not None: ++ transpose_backward = trainer.plans.get('transpose_backward') ++ seg = seg.transpose([i for i in transpose_backward]) ++ ++ print("initializing segmentation export") ++ results.append(pool.starmap_async(save_segmentation_nifti, ++ ((seg, output_filename, dct, interpolation_order, force_separate_z, ++ interpolation_order_z),) ++ )) ++ print("done") ++ ++ print("inference done. Now waiting for the segmentation export to finish...") ++ _ = [i.get() for i in results] ++ # now apply postprocessing ++ # first load the postprocessing properties if they are present. Else raise a well visible warning ++ results = [] ++ pp_file = join(model, "postprocessing.json") ++ if isfile(pp_file): ++ print("postprocessing...") ++ shutil.copy(pp_file, os.path.dirname(output_filenames[0])) ++ # for_which_classes stores for which of the classes everything but the largest connected component needs to be ++ # removed ++ for_which_classes, min_valid_obj_size = load_postprocessing(pp_file) ++ results.append(pool.starmap_async(load_remove_save, ++ zip(output_filenames, output_filenames, ++ [for_which_classes] * len(output_filenames), ++ [min_valid_obj_size] * len(output_filenames)))) ++ _ = [i.get() for i in results] ++ else: ++ print("WARNING! Cannot run postprocessing because the postprocessing file is missing. Make sure to run " ++ "consolidate_folds in the output folder of the model first!\nThe folder you need to run this in is " ++ "%s" % model) ++ ++ pool.close() ++ pool.join() ++ ++ ++def predict_cases_fastest(model, list_of_lists, output_filenames, folds, num_threads_preprocessing, ++ num_threads_nifti_save, segs_from_prev_stage=None, do_tta=True, mixed_precision=True, ++ overwrite_existing=False, all_in_gpu=True, step_size=0.5, ++ checkpoint_name="model_final_checkpoint"): ++ assert len(list_of_lists) == len(output_filenames) ++ if segs_from_prev_stage is not None: assert len(segs_from_prev_stage) == len(output_filenames) ++ ++ pool = Pool(num_threads_nifti_save) ++ results = [] ++ ++ cleaned_output_files = [] ++ for o in output_filenames: ++ dr, f = os.path.split(o) ++ if len(dr) > 0: ++ maybe_mkdir_p(dr) ++ if not f.endswith(".nii.gz"): ++ f, _ = os.path.splitext(f) ++ f = f + ".nii.gz" ++ cleaned_output_files.append(join(dr, f)) ++ ++ if not overwrite_existing: ++ print("number of cases:", len(list_of_lists)) ++ not_done_idx = [i for i, j in enumerate(cleaned_output_files) if not isfile(j)] ++ ++ cleaned_output_files = [cleaned_output_files[i] for i in not_done_idx] ++ list_of_lists = [list_of_lists[i] for i in not_done_idx] ++ if segs_from_prev_stage is not None: ++ segs_from_prev_stage = [segs_from_prev_stage[i] for i in not_done_idx] ++ ++ print("number of cases that still need to be predicted:", len(cleaned_output_files)) ++ ++ print("emptying cuda cache") ++ torch.cuda.empty_cache() ++ ++ print("loading parameters for folds,", folds) ++ trainer, params = load_model_and_checkpoint_files(model, folds, mixed_precision=mixed_precision, checkpoint_name=checkpoint_name) ++ ++ print("starting preprocessing generator") ++ preprocessing = preprocess_multithreaded(trainer, list_of_lists, cleaned_output_files, num_threads_preprocessing, ++ segs_from_prev_stage) ++ ++ print("starting prediction...") ++ for preprocessed in preprocessing: ++ print("getting data from preprocessor") ++ output_filename, (d, dct) = preprocessed ++ print("got something") ++ if isinstance(d, str): ++ print("what I got is a string, so I need to load a file") ++ data = np.load(d) ++ os.remove(d) ++ d = data ++ ++ # preallocate the output arrays ++ # same dtype as the return value in predict_preprocessed_data_return_seg_and_softmax (saves time) ++ all_softmax_outputs = np.zeros((len(params), trainer.num_classes, *d.shape[1:]), dtype=np.float16) ++ all_seg_outputs = np.zeros((len(params), *d.shape[1:]), dtype=int) ++ print("predicting", output_filename) ++ ++ for i, p in enumerate(params): ++ trainer.load_checkpoint_ram(p, False) ++ res = trainer.predict_preprocessed_data_return_seg_and_softmax(d, do_tta, ++ trainer.data_aug_params['mirror_axes'], True, ++ step_size=step_size, use_gaussian=True, ++ all_in_gpu=all_in_gpu, ++ mixed_precision=mixed_precision) ++ if len(params) > 1: ++ # otherwise we dont need this and we can save ourselves the time it takes to copy that ++ all_softmax_outputs[i] = res[1] ++ all_seg_outputs[i] = res[0] ++ ++ print("aggregating predictions") ++ if len(params) > 1: ++ softmax_mean = np.mean(all_softmax_outputs, 0) ++ seg = softmax_mean.argmax(0) ++ else: ++ seg = all_seg_outputs[0] ++ ++ print("applying transpose_backward") ++ transpose_forward = trainer.plans.get('transpose_forward') ++ if transpose_forward is not None: ++ transpose_backward = trainer.plans.get('transpose_backward') ++ seg = seg.transpose([i for i in transpose_backward]) ++ ++ print("initializing segmentation export") ++ results.append(pool.starmap_async(save_segmentation_nifti, ++ ((seg, output_filename, dct, 0, None),) ++ )) ++ print("done") ++ ++ print("inference done. Now waiting for the segmentation export to finish...") ++ _ = [i.get() for i in results] ++ # now apply postprocessing ++ # first load the postprocessing properties if they are present. Else raise a well visible warning ++ results = [] ++ pp_file = join(model, "postprocessing.json") ++ if isfile(pp_file): ++ print("postprocessing...") ++ shutil.copy(pp_file, os.path.dirname(output_filenames[0])) ++ # for_which_classes stores for which of the classes everything but the largest connected component needs to be ++ # removed ++ for_which_classes, min_valid_obj_size = load_postprocessing(pp_file) ++ results.append(pool.starmap_async(load_remove_save, ++ zip(output_filenames, output_filenames, ++ [for_which_classes] * len(output_filenames), ++ [min_valid_obj_size] * len(output_filenames)))) ++ _ = [i.get() for i in results] ++ else: ++ print("WARNING! Cannot run postprocessing because the postprocessing file is missing. Make sure to run " ++ "consolidate_folds in the output folder of the model first!\nThe folder you need to run this in is " ++ "%s" % model) ++ ++ pool.close() ++ pool.join() ++ ++ ++def check_input_folder_and_return_caseIDs(input_folder, expected_num_modalities): ++ print("This model expects %d input modalities for each image" % expected_num_modalities) ++ files = subfiles(input_folder, suffix=".nii.gz", join=False, sort=True) ++ ++ maybe_case_ids = np.unique([i[:-12] for i in files]) ++ ++ remaining = deepcopy(files) ++ missing = [] ++ ++ assert len(files) > 0, "input folder did not contain any images (expected to find .nii.gz file endings)" ++ ++ # now check if all required files are present and that no unexpected files are remaining ++ for c in maybe_case_ids: ++ for n in range(expected_num_modalities): ++ expected_output_file = c + "_%04.0d.nii.gz" % n ++ if not isfile(join(input_folder, expected_output_file)): ++ missing.append(expected_output_file) ++ else: ++ remaining.remove(expected_output_file) ++ ++ print("Found %d unique case ids, here are some examples:" % len(maybe_case_ids), ++ np.random.choice(maybe_case_ids, min(len(maybe_case_ids), 10))) ++ print("If they don't look right, make sure to double check your filenames. They must end with _0000.nii.gz etc") ++ ++ if len(remaining) > 0: ++ print("found %d unexpected remaining files in the folder. Here are some examples:" % len(remaining), ++ np.random.choice(remaining, min(len(remaining), 10))) ++ ++ if len(missing) > 0: ++ print("Some files are missing:") ++ print(missing) ++ raise RuntimeError("missing files in input_folder") ++ ++ return maybe_case_ids ++ ++ ++def predict_from_folder(model: str, input_folder: str, output_folder: str, folds: Union[Tuple[int], List[int]], ++ save_npz: bool, num_threads_preprocessing: int, num_threads_nifti_save: int, ++ lowres_segmentations: Union[str, None], ++ part_id: int, num_parts: int, tta: bool, mixed_precision: bool = True, ++ overwrite_existing: bool = True, mode: str = 'normal', overwrite_all_in_gpu: bool = None, ++ step_size: float = 0.5, checkpoint_name: str = "model_final_checkpoint", ++ segmentation_export_kwargs: dict = None, pre_mode=None, fp=None): ++ """ ++ here we use the standard naming scheme to generate list_of_lists and output_files needed by predict_cases ++ ++ :param model: ++ :param input_folder: ++ :param output_folder: ++ :param folds: ++ :param save_npz: ++ :param num_threads_preprocessing: ++ :param num_threads_nifti_save: ++ :param lowres_segmentations: ++ :param part_id: ++ :param num_parts: ++ :param tta: ++ :param mixed_precision: ++ :param overwrite_existing: if not None then it will be overwritten with whatever is in there. None is default (no overwrite) ++ :return: ++ """ ++ maybe_mkdir_p(output_folder) ++ shutil.copy(join(model, 'plans.pkl'), output_folder) ++ ++ assert isfile(join(model, "plans.pkl")), "Folder with saved model weights must contain a plans.pkl file" ++ expected_num_modalities = load_pickle(join(model, "plans.pkl"))['num_modalities'] ++ ++ # check input folder integrity ++ case_ids = check_input_folder_and_return_caseIDs(input_folder, expected_num_modalities) ++ ++ output_files = [join(output_folder, i + ".nii.gz") for i in case_ids] ++ all_files = subfiles(input_folder, suffix=".nii.gz", join=False, sort=True) ++ list_of_lists = [[join(input_folder, i) for i in all_files if i[:len(j)].startswith(j) and ++ len(i) == (len(j) + 12)] for j in case_ids] ++ ++ if lowres_segmentations is not None: ++ assert isdir(lowres_segmentations), "if lowres_segmentations is not None then it must point to a directory" ++ lowres_segmentations = [join(lowres_segmentations, i + ".nii.gz") for i in case_ids] ++ assert all([isfile(i) for i in lowres_segmentations]), "not all lowres_segmentations files are present. " \ ++ "(I was searching for case_id.nii.gz in that folder)" ++ lowres_segmentations = lowres_segmentations[part_id::num_parts] ++ else: ++ lowres_segmentations = None ++ ++ if mode == "normal": # step this ++ if overwrite_all_in_gpu is None: # True ++ all_in_gpu = False ++ else: ++ all_in_gpu = overwrite_all_in_gpu ++ ++ return predict_cases(model, list_of_lists[part_id::num_parts], output_files[part_id::num_parts], folds, ++ save_npz, num_threads_preprocessing, num_threads_nifti_save, lowres_segmentations, tta, ++ mixed_precision=mixed_precision, overwrite_existing=overwrite_existing, all_in_gpu=all_in_gpu, ++ step_size=step_size, checkpoint_name=checkpoint_name, ++ segmentation_export_kwargs=segmentation_export_kwargs, pre_mode=pre_mode, fp=fp) ++ elif mode == "fast": ++ if overwrite_all_in_gpu is None: ++ all_in_gpu = True ++ else: ++ all_in_gpu = overwrite_all_in_gpu ++ ++ assert save_npz is False ++ return predict_cases_fast(model, list_of_lists[part_id::num_parts], output_files[part_id::num_parts], folds, ++ num_threads_preprocessing, num_threads_nifti_save, lowres_segmentations, ++ tta, mixed_precision=mixed_precision, overwrite_existing=overwrite_existing, all_in_gpu=all_in_gpu, ++ step_size=step_size, checkpoint_name=checkpoint_name, ++ segmentation_export_kwargs=segmentation_export_kwargs) ++ elif mode == "fastest": ++ if overwrite_all_in_gpu is None: ++ all_in_gpu = True ++ else: ++ all_in_gpu = overwrite_all_in_gpu ++ ++ assert save_npz is False ++ return predict_cases_fastest(model, list_of_lists[part_id::num_parts], output_files[part_id::num_parts], folds, ++ num_threads_preprocessing, num_threads_nifti_save, lowres_segmentations, ++ tta, mixed_precision=mixed_precision, overwrite_existing=overwrite_existing, all_in_gpu=all_in_gpu, ++ step_size=step_size, checkpoint_name=checkpoint_name) ++ else: ++ raise ValueError("unrecognized mode. Must be normal, fast or fastest") ++ ++ ++if __name__ == "__main__": ++ parser = argparse.ArgumentParser() ++ parser.add_argument("-i", '--input_folder', help="Must contain all modalities for each patient in the correct" ++ " order (same as training). Files must be named " ++ "CASENAME_XXXX.nii.gz where XXXX is the modality " ++ "identifier (0000, 0001, etc)", required=True) ++ parser.add_argument('-o', "--output_folder", required=True, help="folder for saving predictions") ++ parser.add_argument('-m', '--model_output_folder', ++ help='model output folder. Will automatically discover the folds ' ++ 'that were ' ++ 'run and use those as an ensemble', required=True) ++ parser.add_argument('-f', '--folds', nargs='+', default='None', help="folds to use for prediction. Default is None " ++ "which means that folds will be detected " ++ "automatically in the model output folder") ++ parser.add_argument('-z', '--save_npz', required=False, action='store_true', help="use this if you want to ensemble" ++ " these predictions with those of" ++ " other models. Softmax " ++ "probabilities will be saved as " ++ "compresed numpy arrays in " ++ "output_folder and can be merged " ++ "between output_folders with " ++ "merge_predictions.py") ++ parser.add_argument('-l', '--lowres_segmentations', required=False, default='None', help="if model is the highres " ++ "stage of the cascade then you need to use -l to specify where the segmentations of the " ++ "corresponding lowres unet are. Here they are required to do a prediction") ++ parser.add_argument("--part_id", type=int, required=False, default=0, help="Used to parallelize the prediction of " ++ "the folder over several GPUs. If you " ++ "want to use n GPUs to predict this " ++ "folder you need to run this command " ++ "n times with --part_id=0, ... n-1 and " ++ "--num_parts=n (each with a different " ++ "GPU (for example via " ++ "CUDA_VISIBLE_DEVICES=X)") ++ parser.add_argument("--num_parts", type=int, required=False, default=1, ++ help="Used to parallelize the prediction of " ++ "the folder over several GPUs. If you " ++ "want to use n GPUs to predict this " ++ "folder you need to run this command " ++ "n times with --part_id=0, ... n-1 and " ++ "--num_parts=n (each with a different " ++ "GPU (via " ++ "CUDA_VISIBLE_DEVICES=X)") ++ parser.add_argument("--num_threads_preprocessing", required=False, default=6, type=int, help= ++ "Determines many background processes will be used for data preprocessing. Reduce this if you " ++ "run into out of memory (RAM) problems. Default: 6") ++ parser.add_argument("--num_threads_nifti_save", required=False, default=2, type=int, help= ++ "Determines many background processes will be used for segmentation export. Reduce this if you " ++ "run into out of memory (RAM) problems. Default: 2") ++ parser.add_argument("--tta", required=False, type=int, default=1, help="Set to 0 to disable test time data " ++ "augmentation (speedup of factor " ++ "4(2D)/8(3D)), " ++ "lower quality segmentations") ++ parser.add_argument("--overwrite_existing", required=False, type=int, default=1, help="Set this to 0 if you need " ++ "to resume a previous " ++ "prediction. Default: 1 " ++ "(=existing segmentations " ++ "in output_folder will be " ++ "overwritten)") ++ parser.add_argument("--mode", type=str, default="normal", required=False) ++ parser.add_argument("--all_in_gpu", type=str, default="None", required=False, help="can be None, False or True") ++ parser.add_argument("--step_size", type=float, default=0.5, required=False, help="don't touch") ++ # parser.add_argument("--interp_order", required=False, default=3, type=int, ++ # help="order of interpolation for segmentations, has no effect if mode=fastest") ++ # parser.add_argument("--interp_order_z", required=False, default=0, type=int, ++ # help="order of interpolation along z is z is done differently") ++ # parser.add_argument("--force_separate_z", required=False, default="None", type=str, ++ # help="force_separate_z resampling. Can be None, True or False, has no effect if mode=fastest") ++ parser.add_argument('--disable_mixed_precision', default=False, action='store_true', required=False, ++ help='Predictions are done with mixed precision by default. This improves speed and reduces ' ++ 'the required vram. If you want to disable mixed precision you can set this flag. Note ' ++ 'that yhis is not recommended (mixed precision is ~2x faster!)') ++ ++ args = parser.parse_args() ++ input_folder = args.input_folder ++ output_folder = args.output_folder ++ part_id = args.part_id ++ num_parts = args.num_parts ++ model = args.model_output_folder ++ folds = args.folds ++ save_npz = args.save_npz ++ lowres_segmentations = args.lowres_segmentations ++ num_threads_preprocessing = args.num_threads_preprocessing ++ num_threads_nifti_save = args.num_threads_nifti_save ++ tta = args.tta ++ step_size = args.step_size ++ ++ # interp_order = args.interp_order ++ # interp_order_z = args.interp_order_z ++ # force_separate_z = args.force_separate_z ++ ++ # if force_separate_z == "None": ++ # force_separate_z = None ++ # elif force_separate_z == "False": ++ # force_separate_z = False ++ # elif force_separate_z == "True": ++ # force_separate_z = True ++ # else: ++ # raise ValueError("force_separate_z must be None, True or False. Given: %s" % force_separate_z) ++ ++ overwrite = args.overwrite_existing ++ mode = args.mode ++ all_in_gpu = args.all_in_gpu ++ ++ if lowres_segmentations == "None": ++ lowres_segmentations = None ++ ++ if isinstance(folds, list): ++ if folds[0] == 'all' and len(folds) == 1: ++ pass ++ else: ++ folds = [int(i) for i in folds] ++ elif folds == "None": ++ folds = None ++ else: ++ raise ValueError("Unexpected value for argument folds") ++ ++ if tta == 0: ++ tta = False ++ elif tta == 1: ++ tta = True ++ else: ++ raise ValueError("Unexpected value for tta, Use 1 or 0") ++ ++ if overwrite == 0: ++ overwrite = False ++ elif overwrite == 1: ++ overwrite = True ++ else: ++ raise ValueError("Unexpected value for overwrite, Use 1 or 0") ++ ++ assert all_in_gpu in ['None', 'False', 'True'] ++ if all_in_gpu == "None": ++ all_in_gpu = None ++ elif all_in_gpu == "True": ++ all_in_gpu = True ++ elif all_in_gpu == "False": ++ all_in_gpu = False ++ ++ predict_from_folder(model, input_folder, output_folder, folds, save_npz, num_threads_preprocessing, ++ num_threads_nifti_save, lowres_segmentations, part_id, num_parts, tta, mixed_precision=not args.disable_mixed_precision, ++ overwrite_existing=overwrite, mode=mode, overwrite_all_in_gpu=all_in_gpu, step_size=step_size) +diff --git a/pytorch/nnunet/inference/predict_simple2.py b/pytorch/nnunet/inference/predict_simple2.py +new file mode 100644 +index 0000000..2af423e +--- /dev/null ++++ b/pytorch/nnunet/inference/predict_simple2.py +@@ -0,0 +1,238 @@ ++# Copyright 2020 Division of Medical Image Computing, German Cancer Research Center (DKFZ), Heidelberg, Germany ++# ++# 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 argparse ++import torch ++ ++from nnunet.inference.predict2 import predict_from_folder ++from nnunet.paths import default_plans_identifier, network_training_output_dir, default_cascade_trainer, default_trainer ++from batchgenerators.utilities.file_and_folder_operations import join, isdir ++from nnunet.utilities.task_name_id_conversion import convert_id_to_task_name ++from nnunet.inference.infer_path import INFERENCE_INPUT_FOLDER, INFERENCE_OUTPUT_FOLDER ++ ++ ++def main(): ++ parser = argparse.ArgumentParser() ++ parser.add_argument("-i", '--input_folder', help="Must contain all modalities for each patient in the correct" ++ " order (same as training). Files must be named " ++ "CASENAME_XXXX.nii.gz where XXXX is the modality " ++ "identifier (0000, 0001, etc)", required=False, ++ default=INFERENCE_INPUT_FOLDER) ++ parser.add_argument('-o', "--output_folder", required=False, ++ default=INFERENCE_OUTPUT_FOLDER, help="folder for saving predictions") ++ parser.add_argument('-t', '--task_name', help='task name or task ID, required.', ++ default="Task003_Liver", required=False) ++ parser.add_argument('-pm', '--pre_mode', help='predict mode', required=False, default=-1) ++ parser.add_argument('-fp', '--file_path', help='input or output file path for npu bin files', required=True) ++ parser.add_argument('-tr', '--trainer_class_name', ++ help='Name of the nnUNetTrainer used for 2D U-Net, full resolution 3D U-Net and low resolution ' ++ 'U-Net. The default is %s. If you are running inference with the cascade and the folder ' ++ 'pointed to by --lowres_segmentations does not contain the segmentation maps generated by ' ++ 'the low resolution U-Net then the low resolution segmentation maps will be automatically ' ++ 'generated. For this case, make sure to set the trainer class here that matches your ' ++ '--cascade_trainer_class_name (this part can be ignored if defaults are used).' ++ % default_trainer, ++ required=False, ++ default="nnUNetPlusPlusTrainerV2") ++ parser.add_argument('-ctr', '--cascade_trainer_class_name', ++ help="Trainer class name used for predicting the 3D full resolution U-Net part of the cascade." ++ "Default is %s" % default_cascade_trainer, required=False, ++ default=default_cascade_trainer) ++ ++ parser.add_argument('-m', '--model', help="2d, 3d_lowres, 3d_fullres or 3d_cascade_fullres. Default: 3d_fullres", ++ default="3d_fullres", required=False) ++ ++ parser.add_argument('-p', '--plans_identifier', help='do not touch this unless you know what you are doing', ++ default=default_plans_identifier, required=False) ++ ++ parser.add_argument('-f', '--folds', nargs='+', default="None", ++ help="folds to use for prediction. Default is None which means that folds will be detected " ++ "automatically in the model output folder") ++ ++ parser.add_argument('-z', '--save_npz', required=False, action='store_true', ++ help="use this if you want to ensemble these predictions with those of other models. Softmax " ++ "probabilities will be saved as compressed numpy arrays in output_folder and can be " ++ "merged between output_folders with nnUNet_ensemble_predictions") ++ ++ parser.add_argument('-l', '--lowres_segmentations', required=False, default='None', ++ help="if model is the highres stage of the cascade then you can use this folder to provide " ++ "predictions from the low resolution 3D U-Net. If this is left at default, the " ++ "predictions will be generated automatically (provided that the 3D low resolution U-Net " ++ "network weights are present") ++ ++ parser.add_argument("--part_id", type=int, required=False, default=0, help="Used to parallelize the prediction of " ++ "the folder over several GPUs. If you " ++ "want to use n GPUs to predict this " ++ "folder you need to run this command " ++ "n times with --part_id=0, ... n-1 and " ++ "--num_parts=n (each with a different " ++ "GPU (for example via " ++ "CUDA_VISIBLE_DEVICES=X)") ++ ++ parser.add_argument("--num_parts", type=int, required=False, default=1, ++ help="Used to parallelize the prediction of " ++ "the folder over several GPUs. If you " ++ "want to use n GPUs to predict this " ++ "folder you need to run this command " ++ "n times with --part_id=0, ... n-1 and " ++ "--num_parts=n (each with a different " ++ "GPU (via " ++ "CUDA_VISIBLE_DEVICES=X)") ++ ++ parser.add_argument("--num_threads_preprocessing", required=False, default=6, type=int, help= ++ "Determines many background processes will be used for data preprocessing. Reduce this if you " ++ "run into out of memory (RAM) problems. Default: 6") ++ ++ parser.add_argument("--num_threads_nifti_save", required=False, default=2, type=int, help= ++ "Determines many background processes will be used for segmentation export. Reduce this if you " ++ "run into out of memory (RAM) problems. Default: 2") ++ ++ parser.add_argument("--disable_tta", required=False, default=False, action="store_true", ++ help="set this flag to disable test time data augmentation via mirroring. Speeds up inference " ++ "by roughly factor 4 (2D) or 8 (3D)") ++ ++ parser.add_argument("--overwrite_existing", required=False, default=False, action="store_true", ++ help="Set this flag if the target folder contains predictions that you would like to overwrite") ++ ++ parser.add_argument("--mode", type=str, default="normal", required=False, help="Hands off!") ++ parser.add_argument("--all_in_gpu", type=str, default="None", required=False, help="can be None, False or True. " ++ "Do not touch.") ++ parser.add_argument("--step_size", type=float, default=0.5, required=False, help="don't touch") ++ # parser.add_argument("--interp_order", required=False, default=3, type=int, ++ # help="order of interpolation for segmentations, has no effect if mode=fastest. Do not touch this.") ++ # parser.add_argument("--interp_order_z", required=False, default=0, type=int, ++ # help="order of interpolation along z is z is done differently. Do not touch this.") ++ # parser.add_argument("--force_separate_z", required=False, default="None", type=str, ++ # help="force_separate_z resampling. Can be None, True or False, has no effect if mode=fastest. " ++ # "Do not touch this.") ++ parser.add_argument('-chk', ++ help='checkpoint name, default: model_final_checkpoint', ++ required=False, ++ default='model_final_checkpoint') ++ parser.add_argument('--disable_mixed_precision', default=False, action='store_true', required=False, ++ help='Predictions are done with mixed precision by default. This improves speed and reduces ' ++ 'the required vram. If you want to disable mixed precision you can set this flag. Note ' ++ 'that yhis is not recommended (mixed precision is ~2x faster!)') ++ ++ args = parser.parse_args() ++ print(args) ++ ++ input_folder = args.input_folder ++ output_folder = args.output_folder ++ part_id = args.part_id ++ # 推理模式 ++ pre_mode = args.pre_mode ++ fp = args.file_path ++ num_parts = args.num_parts ++ folds = args.folds ++ save_npz = args.save_npz ++ lowres_segmentations = args.lowres_segmentations ++ num_threads_preprocessing = args.num_threads_preprocessing ++ num_threads_nifti_save = args.num_threads_nifti_save ++ disable_tta = args.disable_tta ++ step_size = args.step_size ++ # interp_order = args.interp_order ++ # interp_order_z = args.interp_order_z ++ # force_separate_z = args.force_separate_z ++ overwrite_existing = args.overwrite_existing ++ mode = args.mode ++ all_in_gpu = args.all_in_gpu ++ model = args.model ++ trainer_class_name = args.trainer_class_name ++ cascade_trainer_class_name = args.cascade_trainer_class_name ++ ++ task_name = args.task_name ++ ++ if not task_name.startswith("Task"): ++ task_id = int(task_name) ++ task_name = convert_id_to_task_name(task_id) ++ ++ assert model in ["2d", "3d_lowres", "3d_fullres", "3d_cascade_fullres"], "-m must be 2d, 3d_lowres, 3d_fullres or " \ ++ "3d_cascade_fullres" ++ ++ # if force_separate_z == "None": ++ # force_separate_z = None ++ # elif force_separate_z == "False": ++ # force_separate_z = False ++ # elif force_separate_z == "True": ++ # force_separate_z = True ++ # else: ++ # raise ValueError("force_separate_z must be None, True or False. Given: %s" % force_separate_z) ++ ++ if lowres_segmentations == "None": ++ lowres_segmentations = None ++ ++ if isinstance(folds, list): ++ if folds[0] == 'all' and len(folds) == 1: ++ pass ++ else: ++ folds = [int(i) for i in folds] ++ elif folds == "None": ++ folds = None ++ else: ++ raise ValueError("Unexpected value for argument folds") ++ ++ assert all_in_gpu in ['None', 'False', 'True'] ++ if all_in_gpu == "None": ++ all_in_gpu = None ++ elif all_in_gpu == "True": ++ all_in_gpu = True ++ elif all_in_gpu == "False": ++ all_in_gpu = False ++ ++ # we need to catch the case where model is 3d cascade fullres and the low resolution folder has not been set. ++ # In that case we need to try and predict with 3d low res first ++ if model == "3d_cascade_fullres" and lowres_segmentations is None: ++ print("lowres_segmentations is None. Attempting to predict 3d_lowres first...") ++ assert part_id == 0 and num_parts == 1, "if you don't specify a --lowres_segmentations folder for the " \ ++ "inference of the cascade, custom values for part_id and num_parts " \ ++ "are not supported. If you wish to have multiple parts, please " \ ++ "run the 3d_lowres inference first (separately)" ++ model_folder_name = join(network_training_output_dir, "3d_lowres", task_name, trainer_class_name + "__" + ++ args.plans_identifier) ++ assert isdir(model_folder_name), "model output folder not found. Expected: %s" % model_folder_name ++ lowres_output_folder = join(output_folder, "3d_lowres_predictions") ++ predict_from_folder(model_folder_name, input_folder, lowres_output_folder, folds, False, ++ num_threads_preprocessing, num_threads_nifti_save, None, part_id, num_parts, not disable_tta, ++ overwrite_existing=overwrite_existing, mode=mode, overwrite_all_in_gpu=all_in_gpu, ++ mixed_precision=not args.disable_mixed_precision, ++ step_size=step_size) ++ lowres_segmentations = lowres_output_folder ++ torch.cuda.empty_cache() ++ print("3d_lowres done") ++ ++ if model == "3d_cascade_fullres": ++ trainer = cascade_trainer_class_name ++ else: ++ trainer = trainer_class_name ++ print(network_training_output_dir) ++ print(model) ++ print(task_name) ++ print(trainer) ++ print(args.plans_identifier) ++ model_folder_name = join(network_training_output_dir, model, task_name, trainer + "__" + ++ args.plans_identifier) ++ print("using model stored in ", model_folder_name) ++ assert isdir(model_folder_name), "model output folder not found. Expected: %s" % model_folder_name ++ ++ predict_from_folder(model_folder_name, input_folder, output_folder, folds, save_npz, num_threads_preprocessing, ++ num_threads_nifti_save, lowres_segmentations, part_id, num_parts, not disable_tta, ++ overwrite_existing=overwrite_existing, mode=mode, overwrite_all_in_gpu=all_in_gpu, ++ mixed_precision=not args.disable_mixed_precision, ++ step_size=step_size, checkpoint_name=args.chk, pre_mode=pre_mode, fp=fp) ++ ++ ++if __name__ == "__main__": ++ main() +diff --git a/pytorch/nnunet/inference/read_bin.py b/pytorch/nnunet/inference/read_bin.py +new file mode 100644 +index 0000000..972d940 +--- /dev/null ++++ b/pytorch/nnunet/inference/read_bin.py +@@ -0,0 +1,30 @@ ++import numpy ++import pdb ++import os ++ ++ ++def read_from_bin(file_name, folder_path='/root/heyupeng/result/dumpOutput_device0/'): ++ file = os.path.join(folder_path, file_name) ++ data = numpy.fromfile(file, dtype='float32') ++ data = data.reshape(3, 128, 128, 128) ++ return data ++ ++ ++def main(): ++ file = 'liver_132_0_128_0_128_0_128_1.bin' ++ print('ready to load:', file) ++ data = numpy.fromfile(file, dtype='float32') ++ data = data.reshape(3, 128, 128, 128) ++ pdb.set_trace() ++ print(data.shape) ++ for i in range(5): ++ print(data[0, 0, 0, i*7:(i+1)*7]) ++ print('-----') ++ for i in range(5): ++ print(data[0, 0, 0, i*7+50:(i+1)*7+50]) ++ pdb.set_trace() ++ print('end\n') ++ ++ ++if __name__ == "__main__": ++ main() +\ No newline at end of file +diff --git a/pytorch/nnunet/inference/read_pkl_file.py b/pytorch/nnunet/inference/read_pkl_file.py +new file mode 100644 +index 0000000..5dcc37b +--- /dev/null ++++ b/pytorch/nnunet/inference/read_pkl_file.py +@@ -0,0 +1,22 @@ ++import numpy ++import pdb ++import os ++import pickle ++ ++ ++def read_pkl(file_name, folder_path='/data/yupeng/environment_variables/nnUNet_preprocessed/Task003_Liver/'): ++ file = os.path.join(folder_path, file_name) ++ data = open(file, 'rb') ++ data = pickle.load(data) ++ return data ++ ++ ++def main(): ++ file = 'dataset_properties.pkl' ++ print('ready to load:', file) ++ data = read_pkl(file) ++ print('end\n') ++ ++ ++if __name__ == "__main__": ++ main() +\ No newline at end of file +diff --git a/pytorch/nnunet/inference/read_txt.py b/pytorch/nnunet/inference/read_txt.py +new file mode 100644 +index 0000000..37c94aa +--- /dev/null ++++ b/pytorch/nnunet/inference/read_txt.py +@@ -0,0 +1,29 @@ ++import numpy ++import pdb ++import os ++ ++ ++def read_from_bin(file_name, folder_path='/root/heyupeng/result/dumpOutput_device0/'): ++ file = os.path.join(folder_path, file_name) ++ data = numpy.loadtxt(file) ++ data = data.reshape(3, 128, 128, 128) ++ return data ++ ++ ++def main(): ++ file = 'liver_132_0_128_0_128_0_128_1.txt' ++ print('ready to load:', file) ++ data = numpy.loadtxt(file) ++ data = data.reshape(3, 128, 128, 128) ++ pdb.set_trace() ++ print(data.shape) ++ for i in range(5): ++ print(data[0, 0, 0, i*7:(i+1)*7]) ++ print('-----') ++ for i in range(5): ++ print(data[0, 0, 0, i*7+50:(i+1)*7+50]) ++ pdb.set_trace() ++ print('end\n') ++ ++if __name__ == "__main__": ++ main() +diff --git a/pytorch/nnunet/network_architecture/generic_UNetPlusPlus.py b/pytorch/nnunet/network_architecture/generic_UNetPlusPlus.py +index 5c2f816..5b831ea 100644 +--- a/pytorch/nnunet/network_architecture/generic_UNetPlusPlus.py ++++ b/pytorch/nnunet/network_architecture/generic_UNetPlusPlus.py +@@ -21,7 +21,8 @@ import numpy as np + from nnunet.network_architecture.initialization import InitWeights_He + from nnunet.network_architecture.neural_network import SegmentationNetwork + import torch.nn.functional +- ++import pdb ++# pdb.set_trace() + + class ConvDropoutNormNonlin(nn.Module): + """ +@@ -393,7 +394,7 @@ class Generic_UNetPlusPlus(SegmentationNetwork): + + def forward(self, x): + # skips = [] +- seg_outputs = [] ++ seg_outputs = [] # x是五维的 + x0_0 = self.conv_blocks_context[0](x) + x1_0 = self.conv_blocks_context[1](x0_0) + x0_1 = self.loc4[0](torch.cat([x0_0, self.up4[0](x1_0)], 1)) +@@ -425,7 +426,7 @@ class Generic_UNetPlusPlus(SegmentationNetwork): + x0_5 = self.loc0[4](torch.cat([x0_0, x0_1, x0_2, x0_3, x0_4, self.up0[4](x1_4)], 1)) + seg_outputs.append(self.final_nonlin(self.seg_outputs[-5](x0_5))) + +- if self._deep_supervision and self.do_ds: ++ if self._deep_supervision and self.do_ds: # False + return tuple([seg_outputs[-1]] + [i(j) for i, j in + zip(list(self.upscale_logits_ops)[::-1], seg_outputs[:-1][::-1])]) + else: +diff --git a/pytorch/nnunet/network_architecture/neural_network.py b/pytorch/nnunet/network_architecture/neural_network.py +index baa8a05..9425fe9 100644 +--- a/pytorch/nnunet/network_architecture/neural_network.py ++++ b/pytorch/nnunet/network_architecture/neural_network.py +@@ -21,8 +21,14 @@ from torch import nn + import torch + from scipy.ndimage.filters import gaussian_filter + from typing import Union, Tuple, List ++import os + + from torch.cuda.amp import autocast ++import pdb ++from glob import glob ++import time ++from nnunet.inference.read_bin import read_from_bin ++from nnunet.inference.infer_path import INFERENCE_SHAPE_PATH, INFERENCE_BIN_INPUT_FOLDER, INFERENCE_BIN_OUTPUT_FOLDER + + + class NeuralNetwork(nn.Module): +@@ -75,7 +81,8 @@ class SegmentationNetwork(NeuralNetwork): + step_size: float = 0.5, patch_size: Tuple[int, ...] = None, regions_class_order: Tuple[int, ...] = None, + use_gaussian: bool = False, pad_border_mode: str = "constant", + pad_kwargs: dict = None, all_in_gpu: bool = False, +- verbose: bool = True, mixed_precision: bool = True) -> Tuple[np.ndarray, np.ndarray]: ++ verbose: bool = True, mixed_precision: bool = True, img_name=None, ++ pre_mode=None, fp=None) -> Tuple[np.ndarray, np.ndarray]: + """ + Use this function to predict a 3D image. It does not matter whether the network is a 2D or 3D U-Net, it will + detect that automatically and run the appropriate code. +@@ -133,7 +140,7 @@ class SegmentationNetwork(NeuralNetwork): + + assert len(x.shape) == 4, "data must have shape (c,x,y,z)" + +- if mixed_precision: ++ if mixed_precision: # True + context = autocast + else: + context = no_op +@@ -141,11 +148,11 @@ class SegmentationNetwork(NeuralNetwork): + with context(): + with torch.no_grad(): + if self.conv_op == nn.Conv3d: +- if use_sliding_window: ++ if use_sliding_window: # 走到这里 + res = self._internal_predict_3D_3Dconv_tiled(x, step_size, do_mirroring, mirror_axes, patch_size, + regions_class_order, use_gaussian, pad_border_mode, + pad_kwargs=pad_kwargs, all_in_gpu=all_in_gpu, +- verbose=verbose) ++ verbose=verbose, img_name=img_name, pre_mode=pre_mode, fp=fp) + else: + res = self._internal_predict_3D_3Dconv(x, patch_size, do_mirroring, mirror_axes, regions_class_order, + pad_border_mode, pad_kwargs=pad_kwargs, verbose=verbose) +@@ -284,19 +291,161 @@ class SegmentationNetwork(NeuralNetwork): + + return steps + ++ # def _internal_predict_3D_3Dconv_tiled(self, x: np.ndarray, step_size: float, do_mirroring: bool, mirror_axes: tuple, ++ # patch_size: tuple, regions_class_order: tuple, use_gaussian: bool, ++ # pad_border_mode: str, pad_kwargs: dict, all_in_gpu: bool, ++ # verbose: bool, img_name=None) -> Tuple[np.ndarray, np.ndarray]: ++ # # better safe than sorry ++ # assert len(x.shape) == 4, "x must be (c, x, y, z)" ++ # assert self.get_device() != "cpu" ++ # if verbose: print("step_size:", step_size) # 0.5 ++ # if verbose: print("do mirror:", do_mirroring) # True ++ # ++ # torch.cuda.empty_cache() ++ # ++ # assert patch_size is not None, "patch_size cannot be None for tiled prediction" # 128, 128, 128 ++ # ++ # # for sliding window inference the image must at least be as large as the patch size. It does not matter ++ # # whether the shape is divisible by 2**num_pool as long as the patch size is ++ # data, slicer = pad_nd_image(x, patch_size, pad_border_mode, pad_kwargs, True, None) ++ # data_shape = data.shape # still c, x, y, z + # + # # compute the steps for sliding window + # steps = self._compute_steps_for_sliding_window(patch_size, data_shape[1:], step_size) # 计算窗口 @@ -2277,1371 +2277,1371 @@ index baa8a05..9425fe9 100644 + if all_in_gpu: # False if verbose: print("copying results to CPU") - if regions_class_order is None: -@@ -419,7 +713,7 @@ class SegmentationNetwork(NeuralNetwork): + if regions_class_order is None: +@@ -419,7 +713,7 @@ class SegmentationNetwork(NeuralNetwork): + + class_probabilities = class_probabilities.detach().cpu().numpy() + +- if verbose: print("prediction done") ++ if verbose: print("prediction done") # True + return predicted_segmentation, class_probabilities + + def _internal_predict_2D_2Dconv(self, x: np.ndarray, min_size: Tuple[int, int], do_mirroring: bool, +@@ -504,54 +798,69 @@ class SegmentationNetwork(NeuralNetwork): + assert len(x.shape) == 5, 'x must be (b, c, x, y, z)' + # everything in here takes place on the GPU. If x and mult are not yet on GPU this will be taken care of here + # we now return a cuda tensor! Not numpy array! +- +- x = to_cuda(maybe_to_torch(x), gpu_id=self.get_device()) ++ def print_mytensor(data): ++ shape = data.shape[0] ++ for s in range(shape): ++ for i in range(3): ++ print(data[s, 0, 0, i * 3:(i + 1) * 3]) ++ for i in range(3): ++ print(data[s, 0, 0, i * 3 + 50:(i + 1) * 3 + 50]) ++ print('-----') ++ x = to_cuda(maybe_to_torch(x), gpu_id=self.get_device()) # ndarray, 1 1 128 128 128,之后变成tensor + result_torch = torch.zeros([1, self.num_classes] + list(x.shape[2:]), +- dtype=torch.float).cuda(self.get_device(), non_blocking=True) ++ dtype=torch.float).cuda(self.get_device(), non_blocking=True) # 1 3 128 128 128,全是0 + + if mult is not None: +- mult = to_cuda(maybe_to_torch(mult), gpu_id=self.get_device()) ++ mult = to_cuda(maybe_to_torch(mult), gpu_id=self.get_device()) # tensor, 128 128 128 + +- if do_mirroring: ++ if do_mirroring: # True + mirror_idx = 8 +- num_results = 2 ** len(mirror_axes) ++ num_results = 2 ** len(mirror_axes) # 8 + else: + mirror_idx = 1 + num_results = 1 + for m in range(mirror_idx): + if m == 0: +- pred = self.inference_apply_nonlin(self(x)) +- result_torch += 1 / num_results * pred ++ y = self(x) # tensor, 1 3 128 128 128 ++ pred = self.inference_apply_nonlin(y) # 1 3 128 128 128 ++ result_torch += 1 / num_results * pred # 1 3 128 128 128 + + if m == 1 and (2 in mirror_axes): +- pred = self.inference_apply_nonlin(self(torch.flip(x, (4, )))) ++ y = self(torch.flip(x, (4, ))) ++ pred = self.inference_apply_nonlin(y) + result_torch += 1 / num_results * torch.flip(pred, (4,)) + + if m == 2 and (1 in mirror_axes): +- pred = self.inference_apply_nonlin(self(torch.flip(x, (3, )))) ++ y = self(torch.flip(x, (3, ))) ++ pred = self.inference_apply_nonlin(y) + result_torch += 1 / num_results * torch.flip(pred, (3,)) + + if m == 3 and (2 in mirror_axes) and (1 in mirror_axes): +- pred = self.inference_apply_nonlin(self(torch.flip(x, (4, 3)))) ++ y = self(torch.flip(x, (4, 3))) ++ pred = self.inference_apply_nonlin(y) + result_torch += 1 / num_results * torch.flip(pred, (4, 3)) + + if m == 4 and (0 in mirror_axes): +- pred = self.inference_apply_nonlin(self(torch.flip(x, (2, )))) ++ y = self(torch.flip(x, (2, ))) ++ pred = self.inference_apply_nonlin(y) + result_torch += 1 / num_results * torch.flip(pred, (2,)) + + if m == 5 and (0 in mirror_axes) and (2 in mirror_axes): +- pred = self.inference_apply_nonlin(self(torch.flip(x, (4, 2)))) ++ y = self(torch.flip(x, (4, 2))) ++ pred = self.inference_apply_nonlin(y) + result_torch += 1 / num_results * torch.flip(pred, (4, 2)) + + if m == 6 and (0 in mirror_axes) and (1 in mirror_axes): +- pred = self.inference_apply_nonlin(self(torch.flip(x, (3, 2)))) ++ y = self(torch.flip(x, (3, 2))) ++ pred = self.inference_apply_nonlin(y) + result_torch += 1 / num_results * torch.flip(pred, (3, 2)) + + if m == 7 and (0 in mirror_axes) and (1 in mirror_axes) and (2 in mirror_axes): +- pred = self.inference_apply_nonlin(self(torch.flip(x, (4, 3, 2)))) ++ y = self(torch.flip(x, (4, 3, 2))) ++ pred = self.inference_apply_nonlin(y) + result_torch += 1 / num_results * torch.flip(pred, (4, 3, 2)) + +- if mult is not None: ++ if mult is not None: # True + result_torch[:, :] *= mult + + return result_torch +diff --git a/pytorch/nnunet/postprocessing/connected_components.py b/pytorch/nnunet/postprocessing/connected_components.py +index c69471e..45ff991 100644 +--- a/pytorch/nnunet/postprocessing/connected_components.py ++++ b/pytorch/nnunet/postprocessing/connected_components.py +@@ -175,7 +175,7 @@ def determine_postprocessing(base, gt_labels_folder, raw_subfolder_name="validat + pp_results['num_samples'] = len(validation_result_raw['all']) + validation_result_raw = validation_result_raw['mean'] + +- if advanced_postprocessing: ++ if advanced_postprocessing: # False + # first treat all foreground classes as one and remove all but the largest foreground connected component + results = [] + for f in fnames: +@@ -270,12 +270,12 @@ def determine_postprocessing(base, gt_labels_folder, raw_subfolder_name="validat + if len(classes) > 1: + # now depending on whether we do remove all but the largest foreground connected component we define the source dir + # for the next one to be the raw or the temp dir +- if do_fg_cc: ++ if do_fg_cc: # True + source = folder_all_classes_as_fg + else: + source = join(base, raw_subfolder_name) + +- if advanced_postprocessing: ++ if advanced_postprocessing: # False + # now run this for each class separately + results = [] + for f in fnames: +@@ -325,7 +325,7 @@ def determine_postprocessing(base, gt_labels_folder, raw_subfolder_name="validat + json_output_file=join(folder_per_class, "summary.json"), + json_author="Fabian", num_threads=processes) + +- if do_fg_cc: ++ if do_fg_cc: # True + old_res = deepcopy(validation_result_PP_test) + else: + old_res = validation_result_raw +@@ -350,7 +350,7 @@ def determine_postprocessing(base, gt_labels_folder, raw_subfolder_name="validat + else: + print("Only one class present, no need to do each class separately as this is covered in fg vs bg") + +- if not advanced_postprocessing: ++ if not advanced_postprocessing: # True + pp_results['min_valid_object_sizes'] = None + + print("done") +diff --git a/pytorch/nnunet/preprocessing/cropping.py b/pytorch/nnunet/preprocessing/cropping.py +index bb0a92a..95d07bc 100644 +--- a/pytorch/nnunet/preprocessing/cropping.py ++++ b/pytorch/nnunet/preprocessing/cropping.py +@@ -39,6 +39,7 @@ def get_bbox_from_mask(mask, outside_value=0): + maxxidx = int(np.max(mask_voxel_coords[1])) + 1 + minyidx = int(np.min(mask_voxel_coords[2])) + maxyidx = int(np.max(mask_voxel_coords[2])) + 1 ++ print(mask.shape, minzidx, maxzidx, minxidx, maxxidx, minyidx, maxyidx) + return [[minzidx, maxzidx], [minxidx, maxxidx], [minyidx, maxyidx]] + + +@@ -202,6 +203,7 @@ class ImageCropper(object): + list_of_args.append((case, case_identifier, overwrite_existing)) + + p = Pool(self.num_threads) ++ print('Pool', self.num_threads) + p.starmap(self.load_crop_save, list_of_args) + p.close() + p.join() +diff --git a/pytorch/nnunet/run/look_pkl.py b/pytorch/nnunet/run/look_pkl.py +new file mode 100644 +index 0000000..1a9d78a +--- /dev/null ++++ b/pytorch/nnunet/run/look_pkl.py +@@ -0,0 +1,18 @@ ++import numpy as np ++import pickle ++ ++inputfile = u'/data/yupeng/environment_variables/RESULTS_FOLDER/nnUNet/3d_fullres/Task003_Liver' \ ++ u'/nnUNetPlusPlusTrainerV2__nnUNetPlansv2.1/fold_0/model_final_checkpoint.model.pkl' ++# test = np.load('labels.npy', encoding = "latin1") ++# doc = open('1.txt', 'a') ++# print(test, file=doc) ++ ++ ++ ++fr = open(inputfile, 'rb') ++inf = pickle.load(fr) ++print('done') ++ ++ ++ ++print('end') +\ No newline at end of file +diff --git a/pytorch/nnunet/run/model_prof.py b/pytorch/nnunet/run/model_prof.py +new file mode 100644 +index 0000000..013df26 +--- /dev/null ++++ b/pytorch/nnunet/run/model_prof.py +@@ -0,0 +1,124 @@ ++# Copyright (c) Soumith Chintala 2016, ++# All rights reserved ++# ++# Copyright 2020 Huawei Technologies Co., Ltd ++# ++# Licensed under the BSD 3-Clause License (the "License"); ++# you may not use this file except in compliance with the License. ++# You may obtain a copy of the License at ++# ++# https://spdx.org/licenses/BSD-3-Clause.html ++# ++# 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. ++ ++# -*- coding: utf-8 -*- ++"""pytorch_prof.py ++""" ++ ++import torch ++import torch.optim as optim ++import torch.nn as nn ++import time ++import argparse ++ ++ ++def build_model(): ++ # 请自定义模型并加载预训练模型 ++ import torchvision ++ model = torchvision.models.resnet50(pretrained=True) ++ return model ++ ++ ++def get_raw_data(): ++ input_tensor = torch.randn(2, 3, 224, 224) ++ return input_tensor ++ ++ ++def criterion(x): ++ base_func = nn.CrossEntropyLoss() ++ shape_list = x.shape ++ N = shape_list[0] ++ R = 1 ++ if len(shape_list) > 1: ++ for r in shape_list[1:]: ++ R *= r ++ T = torch.randint(0,R, size=(N,)).to(x.device) ++ if str(T.device).startswith('npu'): ++ T = T.int() ++ return base_func(x.reshape(N, -1), T) ++ ++ ++if __name__ == '__main__': ++ parser = argparse.ArgumentParser(description='PyTorch Prof') ++ parser.add_argument('--device', type=str, default='cpu', ++ help='set which type of device used. Support cuda:0(device_id), npu:0(device_id).') ++ parser.add_argument('--amp', default=False, action='store_true', ++ help='use amp during prof') ++ parser.add_argument('--loss-scale', default=64.0, type=float, ++ help='loss scale using in amp, default 64.0, -1 means dynamic') ++ parser.add_argument('--opt-level', default='O2', type=str, ++ help='opt-level using in amp, default O2') ++ parser.add_argument('--FusedSGD', default=False, action='store_true', ++ help='use FusedSGD during prof') ++ ++ args = parser.parse_args() ++ ++ # 1.准备工作 ++ if args.device.startswith('cuda'): ++ torch.cuda.set_device(args.device) ++ prof_kwargs = {'use_cuda': True} ++ elif args.device.startswith('npu'): ++ torch.npu.set_device(args.device) ++ prof_kwargs = {'use_npu': True} ++ else: ++ prof_kwargs = {} ++ ++ # 2.构建模型 ++ model = build_model() ++ if args.FusedSGD: ++ from apex.optimizers import NpuFusedSGD ++ optimizer = NpuFusedSGD(model.parameters(), lr=0.01) ++ model = model.to(args.device) ++ if args.amp: ++ from apex import amp ++ model, optimizer = amp.initialize(model, optimizer, opt_level=args.opt_level, ++ loss_scale=None if args.loss_scale == -1 else args.loss_scale, ++ combine_grad=True) ++ else: ++ optimizer = optim.SGD(model.parameters(), lr=0.01) ++ model = model.to(args.device) ++ if args.amp: ++ from apex import amp ++ model, optimizer = amp.initialize(model, optimizer, opt_level=args.opt_level, ++ loss_scale=None if args.loss_scale == -1 else args.loss_scale) ++ ++ # 3.生成input ++ input_tensor = get_raw_data() ++ input_tensor = input_tensor.to(args.device) ++ ++ # 先运行一次,保证prof得到的性能是正确的 ++ def run(): ++ output_tensor = model(input_tensor) ++ optimizer.zero_grad() ++ loss = criterion(output_tensor) ++ if args.amp: ++ with amp.scale_loss(loss, optimizer) as scaled_loss: ++ scaled_loss.backward() ++ else: ++ loss.backward() ++ optimizer.step() ++ return loss ++ for i in range(5): ++ start_time = time.time() ++ loss = run() ++ print('iter: %d, loss: %.2f, time: %.2f' % (i, loss, (time.time() - start_time)*1000)) ++ ++ # 4. 执行forward+profiling ++ with torch.autograd.profiler.profile(**prof_kwargs) as prof: ++ run() ++ print(prof.key_averages().table()) ++ prof.export_chrome_trace("pytorch_prof_%s.prof" % args.device) +\ No newline at end of file +diff --git a/pytorch/nnunet/run/run_training.py b/pytorch/nnunet/run/run_training.py +index eb7ca2f..08214d6 100644 +--- a/pytorch/nnunet/run/run_training.py ++++ b/pytorch/nnunet/run/run_training.py +@@ -31,7 +31,7 @@ def main(): + parser.add_argument("task", help="can be task name or task id") + parser.add_argument("fold", help='0, 1, ..., 5 or \'all\'') + parser.add_argument("-val", "--validation_only", help="use this if you want to only run the validation", +- action="store_true") ++ action="store_true", default=True) + parser.add_argument("-w", required=False, default=None, help="Load pre-trained Models Genesis") + parser.add_argument("-c", "--continue_training", help="use this if you want to continue a training", + action="store_true") +@@ -134,8 +134,8 @@ def main(): + fp16=run_mixed_precision) + + trainer.initialize(not validation_only) +- +- if weights != None: ++ ++ if weights != None: + trainer.load_pretrained_encoder_weights(weights) + sys.stdout.flush() - class_probabilities = class_probabilities.detach().cpu().numpy() +diff --git a/pytorch/nnunet/run/run_training2.py b/pytorch/nnunet/run/run_training2.py +new file mode 100644 +index 0000000..372a4d4 +--- /dev/null ++++ b/pytorch/nnunet/run/run_training2.py +@@ -0,0 +1,172 @@ ++# Copyright 2020 Division of Medical Image Computing, German Cancer Research Center (DKFZ), Heidelberg, Germany ++# ++# 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 os ++import sys ++import argparse ++from batchgenerators.utilities.file_and_folder_operations import * ++from nnunet.run.default_configuration import get_default_configuration ++from nnunet.paths import default_plans_identifier ++from nnunet.training.cascade_stuff.predict_next_stage import predict_next_stage ++from nnunet.training.network_training.nnUNetTrainer import nnUNetTrainer ++from nnunet.training.network_training.nnUNetTrainerCascadeFullRes import nnUNetTrainerCascadeFullRes ++from nnunet.training.network_training.nnUNetTrainerV2_CascadeFullRes import nnUNetTrainerV2CascadeFullRes ++from nnunet.utilities.task_name_id_conversion import convert_id_to_task_name ++ ++ ++# import pdb ++# pdb.set_trace() ++ ++def main(): ++ parser = argparse.ArgumentParser() ++ parser.add_argument("-network", default="3d_fullres") ++ parser.add_argument("-network_trainer", default="nnUNetPlusPlusTrainerV2") ++ parser.add_argument("-task", default="003", help="can be task name or task id") ++ parser.add_argument("-fold", default="0", help='0, 1, ..., 5 or \'all\'') ++ parser.add_argument("-val", "--validation_only", default=False, ++ help="use this if you want to only run the validation", ++ action="store_true") ++ parser.add_argument("-w", required=False, default=None, help="Load pre-trained Models Genesis") ++ parser.add_argument("-c", "--continue_training", default=False, help="use this if you want to continue a training", ++ action="store_true") ++ parser.add_argument("-p", help="plans identifier. Only change this if you created a custom experiment planner", ++ default=default_plans_identifier, required=False) ++ parser.add_argument("--use_compressed_data", default=False, action="store_true", ++ help="If you set use_compressed_data, the training cases will not be decompressed. Reading compressed data " ++ "is much more CPU and RAM intensive and should only be used if you know what you are " ++ "doing", required=False) ++ parser.add_argument("--deterministic", ++ help="Makes training deterministic, but reduces training speed substantially. I (Fabian) think " ++ "this is not necessary. Deterministic training will make you overfit to some random seed. " ++ "Don't use that.", ++ required=False, default=False, action="store_true") ++ parser.add_argument("--npz", required=False, default=False, action="store_true", help="if set then nnUNet will " ++ "export npz files of " ++ "predicted segmentations " ++ "in the validation as well. " ++ "This is needed to run the " ++ "ensembling step so unless " ++ "you are developing nnUNet " ++ "you should enable this") ++ parser.add_argument("--find_lr", required=False, default=False, action="store_true", ++ help="not used here, just for fun") ++ parser.add_argument("--valbest", required=False, default=False, action="store_true", ++ help="hands off. This is not intended to be used") ++ parser.add_argument("--fp32", required=False, default=False, action="store_true", ++ help="disable mixed precision training and run old school fp32") ++ parser.add_argument("--val_folder", required=False, default="validation_raw", ++ help="name of the validation folder. No need to use this for most people") ++ # parser.add_argument("--interp_order", required=False, default=3, type=int, ++ # help="order of interpolation for segmentations. Testing purpose only. Hands off") ++ # parser.add_argument("--interp_order_z", required=False, default=0, type=int, ++ # help="order of interpolation along z if z is resampled separately. Testing purpose only. " ++ # "Hands off") ++ # parser.add_argument("--force_separate_z", required=False, default="None", type=str, ++ # help="force_separate_z resampling. Can be None, True or False. Testing purpose only. Hands off") ++ ++ args = parser.parse_args() ++ print('------------\n', args) ++ ++ task = args.task ++ fold = args.fold ++ network = args.network ++ network_trainer = args.network_trainer ++ weights = args.w ++ validation_only = args.validation_only ++ plans_identifier = args.p ++ find_lr = args.find_lr ++ ++ use_compressed_data = args.use_compressed_data ++ decompress_data = not use_compressed_data ++ ++ deterministic = args.deterministic ++ valbest = args.valbest ++ ++ fp32 = args.fp32 ++ run_mixed_precision = not fp32 ++ ++ val_folder = args.val_folder ++ # interp_order = args.interp_order ++ # interp_order_z = args.interp_order_z ++ # force_separate_z = args.force_separate_z ++ ++ if not task.startswith("Task"): ++ task_id = int(task) ++ task = convert_id_to_task_name(task_id) ++ ++ if fold == 'all': ++ pass ++ else: ++ fold = int(fold) ++ ++ # if force_separate_z == "None": ++ # force_separate_z = None ++ # elif force_separate_z == "False": ++ # force_separate_z = False ++ # elif force_separate_z == "True": ++ # force_separate_z = True ++ # else: ++ # raise ValueError("force_separate_z must be None, True or False. Given: %s" % force_separate_z) ++ ++ plans_file, output_folder_name, dataset_directory, batch_dice, stage, \ ++ trainer_class, domain = get_default_configuration(network, task, network_trainer, plans_identifier) ++ ++ if trainer_class is None: ++ raise RuntimeError("Could not find trainer class in nnunet.training.network_training") ++ ++ if network == "3d_cascade_fullres": ++ assert issubclass(trainer_class, (nnUNetTrainerCascadeFullRes, nnUNetTrainerV2CascadeFullRes)), \ ++ "If running 3d_cascade_fullres then your " \ ++ "trainer class must be derived from " \ ++ "nnUNetTrainerCascadeFullRes" ++ else: ++ assert issubclass(trainer_class, ++ nnUNetTrainer), "network_trainer was found but is not derived from nnUNetTrainer" ++ ++ trainer = trainer_class(plans_file, fold, output_folder=output_folder_name, dataset_directory=dataset_directory, ++ batch_dice=batch_dice, stage=stage, unpack_data=decompress_data, ++ deterministic=deterministic, ++ fp16=run_mixed_precision) ++ ++ trainer.initialize(not validation_only) ++ ++ if weights != None: ++ trainer.load_pretrained_encoder_weights(weights) ++ sys.stdout.flush() ++ ++ if find_lr: ++ trainer.find_lr() ++ else: ++ if not validation_only: ++ if args.continue_training: ++ trainer.load_latest_checkpoint() ++ trainer.run_training() ++ else: ++ if valbest: ++ trainer.load_best_checkpoint(train=False) ++ else: ++ trainer.load_latest_checkpoint(train=False) ++ ++ trainer.network.eval() ++ ++ # predict validation ++ trainer.validate(save_softmax=args.npz, validation_folder_name=val_folder) ++ ++ if network == '3d_lowres': ++ trainer.load_best_checkpoint(False) ++ print("predicting segmentations for the next stage of the cascade") ++ predict_next_stage(trainer, join(dataset_directory, trainer.plans['data_identifier'] + "_stage%d" % 1)) ++ ++ ++if __name__ == "__main__": ++ main() +diff --git a/pytorch/nnunet/run/run_training_DDP.py b/pytorch/nnunet/run/run_training_DDP.py +index 5ffcdcf..6ad3d5a 100644 +--- a/pytorch/nnunet/run/run_training_DDP.py ++++ b/pytorch/nnunet/run/run_training_DDP.py +@@ -27,13 +27,13 @@ from nnunet.utilities.task_name_id_conversion import convert_id_to_task_name -- if verbose: print("prediction done") -+ if verbose: print("prediction done") # True - return predicted_segmentation, class_probabilities + def main(): + parser = argparse.ArgumentParser() +- parser.add_argument("network") +- parser.add_argument("network_trainer") +- parser.add_argument("task", help="can be task name or task id") +- parser.add_argument("fold", help='0, 1, ..., 5 or \'all\'') ++ parser.add_argument("network", default='3d_fullres') ++ parser.add_argument("network_trainer", default='nnUNetTrainerV2_DDP') ++ parser.add_argument("task", help="can be task name or task id", default='003') ++ parser.add_argument("fold", help='0, 1, ..., 5 or \'all\'', default='0') + parser.add_argument("-val", "--validation_only", help="use this if you want to only run the validation", +- action="store_true") +- parser.add_argument("-c", "--continue_training", help="use this if you want to continue a training", ++ action="store_true", default=False) ++ parser.add_argument("-c", "--continue_training", default=False, help="use this if you want to continue a training", + action="store_true") + parser.add_argument("-p", help="plans identifier. Only change this if you created a custom experiment planner", + default=default_plans_identifier, required=False) +@@ -78,7 +78,7 @@ def main(): + # help="force_separate_z resampling. Can be None, True or False. Testing purpose only. Hands off") - def _internal_predict_2D_2Dconv(self, x: np.ndarray, min_size: Tuple[int, int], do_mirroring: bool, -@@ -504,54 +798,69 @@ class SegmentationNetwork(NeuralNetwork): - assert len(x.shape) == 5, 'x must be (b, c, x, y, z)' - # everything in here takes place on the GPU. If x and mult are not yet on GPU this will be taken care of here - # we now return a cuda tensor! Not numpy array! + args = parser.parse_args() - -- x = to_cuda(maybe_to_torch(x), gpu_id=self.get_device()) -+ def print_mytensor(data): -+ shape = data.shape[0] -+ for s in range(shape): -+ for i in range(3): -+ print(data[s, 0, 0, i * 3:(i + 1) * 3]) -+ for i in range(3): -+ print(data[s, 0, 0, i * 3 + 50:(i + 1) * 3 + 50]) -+ print('-----') -+ x = to_cuda(maybe_to_torch(x), gpu_id=self.get_device()) # ndarray, 1 1 128 128 128,之后变成tensor - result_torch = torch.zeros([1, self.num_classes] + list(x.shape[2:]), -- dtype=torch.float).cuda(self.get_device(), non_blocking=True) -+ dtype=torch.float).cuda(self.get_device(), non_blocking=True) # 1 3 128 128 128,全是0 - - if mult is not None: -- mult = to_cuda(maybe_to_torch(mult), gpu_id=self.get_device()) -+ mult = to_cuda(maybe_to_torch(mult), gpu_id=self.get_device()) # tensor, 128 128 128 ++ print('\n\n args=', args, '\n\n') + task = args.task + fold = args.fold + network = args.network +@@ -115,7 +115,7 @@ def main(): + # raise ValueError("force_separate_z must be None, True or False. Given: %s" % force_separate_z) -- if do_mirroring: -+ if do_mirroring: # True - mirror_idx = 8 -- num_results = 2 ** len(mirror_axes) -+ num_results = 2 ** len(mirror_axes) # 8 - else: - mirror_idx = 1 - num_results = 1 - for m in range(mirror_idx): - if m == 0: -- pred = self.inference_apply_nonlin(self(x)) -- result_torch += 1 / num_results * pred -+ y = self(x) # tensor, 1 3 128 128 128 -+ pred = self.inference_apply_nonlin(y) # 1 3 128 128 128 -+ result_torch += 1 / num_results * pred # 1 3 128 128 128 + plans_file, output_folder_name, dataset_directory, batch_dice, stage, \ +- trainer_class = get_default_configuration(network, task, network_trainer, plans_identifier) ++ trainer_class, _ = get_default_configuration(network, task, network_trainer, plans_identifier) - if m == 1 and (2 in mirror_axes): -- pred = self.inference_apply_nonlin(self(torch.flip(x, (4, )))) -+ y = self(torch.flip(x, (4, ))) -+ pred = self.inference_apply_nonlin(y) - result_torch += 1 / num_results * torch.flip(pred, (4,)) + if trainer_class is None: + raise RuntimeError("Could not find trainer class in meddec.model_training") +diff --git a/pytorch/nnunet/run/run_training_hypDDP.py b/pytorch/nnunet/run/run_training_hypDDP.py +new file mode 100644 +index 0000000..f50744c +--- /dev/null ++++ b/pytorch/nnunet/run/run_training_hypDDP.py +@@ -0,0 +1,164 @@ ++# Copyright 2020 Division of Medical Image Computing, German Cancer Research Center (DKFZ), Heidelberg, Germany ++# ++# 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 argparse ++ ++from batchgenerators.utilities.file_and_folder_operations import * ++from nnunet.run.default_configuration import get_default_configuration ++from nnunet.paths import default_plans_identifier ++from nnunet.training.cascade_stuff.predict_next_stage import predict_next_stage ++from nnunet.training.network_training.nnUNetTrainer import nnUNetTrainer ++from nnunet.training.network_training.nnUNetTrainerCascadeFullRes import nnUNetTrainerCascadeFullRes ++from nnunet.training.network_training.nnUNetTrainerV2_CascadeFullRes import nnUNetTrainerV2CascadeFullRes ++from nnunet.utilities.task_name_id_conversion import convert_id_to_task_name ++ ++ ++def main(): ++ parser = argparse.ArgumentParser() ++ parser.add_argument("network") ++ parser.add_argument("network_trainer") ++ parser.add_argument("task", help="can be task name or task id") ++ parser.add_argument("fold", help='0, 1, ..., 5 or \'all\'') ++ parser.add_argument("-val", "--validation_only", help="use this if you want to only run the validation", ++ action="store_true") ++ parser.add_argument("-c", "--continue_training", help="use this if you want to continue a training", ++ action="store_true") ++ parser.add_argument("-p", help="plans identifier. Only change this if you created a custom experiment planner", ++ default=default_plans_identifier, required=False) ++ parser.add_argument("--use_compressed_data", default=False, action="store_true", ++ help="If you set use_compressed_data, the training cases will not be decompressed. Reading compressed data " ++ "is much more CPU and RAM intensive and should only be used if you know what you are " ++ "doing", required=False) ++ parser.add_argument("--deterministic", ++ help="Makes training deterministic, but reduces training speed substantially. I (Fabian) think " ++ "this is not necessary. Deterministic training will make you overfit to some random seed. " ++ "Don't use that.", ++ required=False, default=False, action="store_true") ++ parser.add_argument("--local_rank", default=0, type=int) ++ parser.add_argument("--fp32", required=False, default=False, action="store_true", ++ help="disable mixed precision training and run old school fp32") ++ parser.add_argument("--dbs", required=False, default=False, action="store_true", help="distribute batch size. If " ++ "True then whatever " ++ "batch_size is in plans will " ++ "be distributed over DDP " ++ "models, if False then each " ++ "model will have batch_size " ++ "for a total of " ++ "GPUs*batch_size") ++ parser.add_argument("--npz", required=False, default=False, action="store_true", help="if set then nnUNet will " ++ "export npz files of " ++ "predicted segmentations " ++ "in the vlaidation as well. " ++ "This is needed to run the " ++ "ensembling step so unless " ++ "you are developing nnUNet " ++ "you should enable this") ++ parser.add_argument("--valbest", required=False, default=False, action="store_true", help="") ++ parser.add_argument("--find_lr", required=False, default=False, action="store_true", help="") ++ parser.add_argument("--val_folder", required=False, default="validation_raw", ++ help="name of the validation folder. No need to use this for most people") ++ # parser.add_argument("--interp_order", required=False, default=3, type=int, ++ # help="order of interpolation for segmentations. Testing purpose only. Hands off") ++ # parser.add_argument("--interp_order_z", required=False, default=0, type=int, ++ # help="order of interpolation along z if z is resampled separately. Testing purpose only. " ++ # "Hands off") ++ # parser.add_argument("--force_separate_z", required=False, default="None", type=str, ++ # help="force_separate_z resampling. Can be None, True or False. Testing purpose only. Hands off") ++ ++ args = parser.parse_args() ++ print('\n\n args=', args, '\n\n') ++ task = args.task ++ fold = args.fold ++ network = args.network ++ network_trainer = args.network_trainer ++ validation_only = args.validation_only ++ plans_identifier = args.p ++ use_compressed_data = args.use_compressed_data ++ decompress_data = not use_compressed_data ++ deterministic = args.deterministic ++ valbest = args.valbest ++ find_lr = args.find_lr ++ val_folder = args.val_folder ++ # interp_order = args.interp_order ++ # interp_order_z = args.interp_order_z ++ # force_separate_z = args.force_separate_z ++ fp32 = args.fp32 ++ ++ if not task.startswith("Task"): ++ task_id = int(task) ++ task = convert_id_to_task_name(task_id) ++ ++ if fold == 'all': ++ pass ++ else: ++ fold = int(fold) ++ # ++ # if force_separate_z == "None": ++ # force_separate_z = None ++ # elif force_separate_z == "False": ++ # force_separate_z = False ++ # elif force_separate_z == "True": ++ # force_separate_z = True ++ # else: ++ # raise ValueError("force_separate_z must be None, True or False. Given: %s" % force_separate_z) ++ ++ plans_file, output_folder_name, dataset_directory, batch_dice, stage, \ ++ trainer_class, _ = get_default_configuration(network, task, network_trainer, plans_identifier) ++ ++ if trainer_class is None: ++ raise RuntimeError("Could not find trainer class in meddec.model_training") ++ ++ if network == "3d_cascade_fullres": ++ assert issubclass(trainer_class, (nnUNetTrainerCascadeFullRes, nnUNetTrainerV2CascadeFullRes)), \ ++ "If running 3d_cascade_fullres then your " \ ++ "trainer class must be derived from " \ ++ "nnUNetTrainerCascadeFullRes" ++ else: ++ assert issubclass(trainer_class, ++ nnUNetTrainer), "network_trainer was found but is not derived from nnUNetTrainer" ++ ++ trainer = trainer_class(plans_file, fold, local_rank=args.local_rank, output_folder=output_folder_name, ++ dataset_directory=dataset_directory, batch_dice=batch_dice, stage=stage, ++ unpack_data=decompress_data, deterministic=deterministic, fp16=not fp32, ++ distribute_batch_size=args.dbs) ++ ++ trainer.initialize(not validation_only) ++ ++ if find_lr: ++ trainer.find_lr() ++ else: ++ if not validation_only: ++ if args.continue_training: ++ trainer.load_latest_checkpoint() ++ trainer.run_training() ++ else: ++ if valbest: ++ trainer.load_best_checkpoint(train=False) ++ else: ++ trainer.load_latest_checkpoint(train=False) ++ ++ trainer.network.eval() ++ ++ # predict validation ++ trainer.validate(save_softmax=args.npz, validation_folder_name=val_folder) ++ ++ if network == '3d_lowres': ++ trainer.load_best_checkpoint(False) ++ print("predicting segmentations for the next stage of the cascade") ++ predict_next_stage(trainer, join(dataset_directory, trainer.plans['data_identifier'] + "_stage%d" % 1)) ++ ++ ++if __name__ == "__main__": ++ main() +diff --git a/pytorch/nnunet/training/loss_functions/crossentropy.py b/pytorch/nnunet/training/loss_functions/crossentropy.py +index 6195437..0c782d9 100644 +--- a/pytorch/nnunet/training/loss_functions/crossentropy.py ++++ b/pytorch/nnunet/training/loss_functions/crossentropy.py +@@ -6,6 +6,15 @@ class RobustCrossEntropyLoss(nn.CrossEntropyLoss): + this is just a compatibility layer because my target tensor is float and has an extra dimension + """ + def forward(self, input: Tensor, target: Tensor) -> Tensor: ++ # i = 0 ++ # print('----------') ++ # print('input:', input.shape) ++ # for i in range(len(input)): ++ # print(i, input[i].shape) ++ # print('target') ++ # for i in range(len(target)): ++ # print(i, target[i].shape) ++ # print('\n----------') + if len(target.shape) == len(input.shape): + assert target.shape[1] == 1 + target = target[:, 0] +diff --git a/pytorch/nnunet/training/network_training/network_trainer.py b/pytorch/nnunet/training/network_training/network_trainer.py +index e920158..f0031d3 100644 +--- a/pytorch/nnunet/training/network_training/network_trainer.py ++++ b/pytorch/nnunet/training/network_training/network_trainer.py +@@ -37,6 +37,7 @@ from abc import abstractmethod + from datetime import datetime + from tqdm import trange + from nnunet.utilities.to_torch import maybe_to_torch, to_cuda ++import pdb - if m == 2 and (1 in mirror_axes): -- pred = self.inference_apply_nonlin(self(torch.flip(x, (3, )))) -+ y = self(torch.flip(x, (3, ))) -+ pred = self.inference_apply_nonlin(y) - result_torch += 1 / num_results * torch.flip(pred, (3,)) - if m == 3 and (2 in mirror_axes) and (1 in mirror_axes): -- pred = self.inference_apply_nonlin(self(torch.flip(x, (4, 3)))) -+ y = self(torch.flip(x, (4, 3))) -+ pred = self.inference_apply_nonlin(y) - result_torch += 1 / num_results * torch.flip(pred, (4, 3)) + class NetworkTrainer(object): +@@ -438,7 +439,8 @@ class NetworkTrainer(object): + self._maybe_init_amp() - if m == 4 and (0 in mirror_axes): -- pred = self.inference_apply_nonlin(self(torch.flip(x, (2, )))) -+ y = self(torch.flip(x, (2, ))) -+ pred = self.inference_apply_nonlin(y) - result_torch += 1 / num_results * torch.flip(pred, (2,)) + def _maybe_init_amp(self): +- if self.fp16 and self.amp_grad_scaler is None and torch.cuda.is_available(): ++ # if self.fp16 and self.amp_grad_scaler is None and torch.cuda.is_available(): ++ if self.fp16 and self.amp_grad_scaler is None: + self.amp_grad_scaler = GradScaler() - if m == 5 and (0 in mirror_axes) and (2 in mirror_axes): -- pred = self.inference_apply_nonlin(self(torch.flip(x, (4, 2)))) -+ y = self(torch.flip(x, (4, 2))) -+ pred = self.inference_apply_nonlin(y) - result_torch += 1 / num_results * torch.flip(pred, (4, 2)) + def plot_network_architecture(self): +diff --git a/pytorch/nnunet/training/network_training/nnUNetPlusPlusTrainerV2.py b/pytorch/nnunet/training/network_training/nnUNetPlusPlusTrainerV2.py +index e9aa611..9b97e8c 100644 +--- a/pytorch/nnunet/training/network_training/nnUNetPlusPlusTrainerV2.py ++++ b/pytorch/nnunet/training/network_training/nnUNetPlusPlusTrainerV2.py +@@ -13,6 +13,7 @@ + # limitations under the License. - if m == 6 and (0 in mirror_axes) and (1 in mirror_axes): -- pred = self.inference_apply_nonlin(self(torch.flip(x, (3, 2)))) -+ y = self(torch.flip(x, (3, 2))) -+ pred = self.inference_apply_nonlin(y) - result_torch += 1 / num_results * torch.flip(pred, (3, 2)) - if m == 7 and (0 in mirror_axes) and (1 in mirror_axes) and (2 in mirror_axes): -- pred = self.inference_apply_nonlin(self(torch.flip(x, (4, 3, 2)))) -+ y = self(torch.flip(x, (4, 3, 2))) -+ pred = self.inference_apply_nonlin(y) - result_torch += 1 / num_results * torch.flip(pred, (4, 3, 2)) ++import SimpleITK as sitk + from collections import OrderedDict + from typing import Tuple + import sys +@@ -35,12 +36,10 @@ from torch.cuda.amp import autocast + from nnunet.training.learning_rate.poly_lr import poly_lr + from batchgenerators.utilities.file_and_folder_operations import * -- if mult is not None: -+ if mult is not None: # True - result_torch[:, :] *= mult +- + class nnUNetPlusPlusTrainerV2(nnUNetTrainer): + """ + Info for Fabian: same as internal nnUNetTrainerV2_2 + """ +- + def __init__(self, plans_file, fold, output_folder=None, dataset_directory=None, batch_dice=True, stage=None, + unpack_data=True, deterministic=True, fp16=False): + super().__init__(plans_file, fold, output_folder, dataset_directory, batch_dice, stage, unpack_data, +@@ -66,7 +65,7 @@ class nnUNetPlusPlusTrainerV2(nnUNetTrainer): + maybe_mkdir_p(self.output_folder) - return result_torch -diff --git a/pytorch/nnunet/postprocessing/connected_components.py b/pytorch/nnunet/postprocessing/connected_components.py -index c69471e..45ff991 100644 ---- a/pytorch/nnunet/postprocessing/connected_components.py -+++ b/pytorch/nnunet/postprocessing/connected_components.py -@@ -175,7 +175,7 @@ def determine_postprocessing(base, gt_labels_folder, raw_subfolder_name="validat - pp_results['num_samples'] = len(validation_result_raw['all']) - validation_result_raw = validation_result_raw['mean'] + if force_load_plans or (self.plans is None): +- self.load_plans_file() ++ self.load_plans_file() # '/data/yupeng/environment_variables/nnUNet_preprocessed/Task003_Liver/nnUNetPlansv2.1_plans_3D.pkl' -- if advanced_postprocessing: -+ if advanced_postprocessing: # False - # first treat all foreground classes as one and remove all but the largest foreground connected component - results = [] - for f in fnames: -@@ -270,12 +270,12 @@ def determine_postprocessing(base, gt_labels_folder, raw_subfolder_name="validat - if len(classes) > 1: - # now depending on whether we do remove all but the largest foreground connected component we define the source dir - # for the next one to be the raw or the temp dir -- if do_fg_cc: -+ if do_fg_cc: # True - source = folder_all_classes_as_fg - else: - source = join(base, raw_subfolder_name) + self.process_plans(self.plans) -- if advanced_postprocessing: -+ if advanced_postprocessing: # False - # now run this for each class separately - results = [] - for f in fnames: -@@ -325,7 +325,7 @@ def determine_postprocessing(base, gt_labels_folder, raw_subfolder_name="validat - json_output_file=join(folder_per_class, "summary.json"), - json_author="Fabian", num_threads=processes) +@@ -189,6 +188,7 @@ class nnUNetPlusPlusTrainerV2(nnUNetTrainer): + """ + ds = self.network.do_ds + self.network.do_ds = False ++ overwrite = False # 不希望重新跑推理,不然太久了 + ret = super().validate(do_mirroring, use_sliding_window, step_size, save_softmax, use_gaussian, + overwrite, validation_folder_name, debug, all_in_gpu, segmentation_export_kwargs) -- if do_fg_cc: -+ if do_fg_cc: # True - old_res = deepcopy(validation_result_PP_test) - else: - old_res = validation_result_raw -@@ -350,7 +350,7 @@ def determine_postprocessing(base, gt_labels_folder, raw_subfolder_name="validat - else: - print("Only one class present, no need to do each class separately as this is covered in fg vs bg") +@@ -200,16 +200,18 @@ class nnUNetPlusPlusTrainerV2(nnUNetTrainer): + use_sliding_window: bool = True, step_size: float = 0.5, + use_gaussian: bool = True, pad_border_mode: str = 'constant', + pad_kwargs: dict = None, all_in_gpu: bool = True, +- verbose: bool = True, mixed_precision=True) -> Tuple[np.ndarray, np.ndarray]: ++ verbose: bool = True, mixed_precision=True, img_name=None, ++ pre_mode=None, fp=None) -> Tuple[np.ndarray, np.ndarray]: + """ + We need to wrap this because we need to enforce self.network.do_ds = False for prediction + """ +- ds = self.network.do_ds ++ ds = self.network.do_ds # ds = True + self.network.do_ds = False + ret = super().predict_preprocessed_data_return_seg_and_softmax(data, do_mirroring, mirror_axes, + use_sliding_window, step_size, use_gaussian, + pad_border_mode, pad_kwargs, all_in_gpu, verbose, +- mixed_precision=mixed_precision) ++ mixed_precision=mixed_precision, img_name=img_name, ++ pre_mode=pre_mode, fp=fp) + self.network.do_ds = ds + return ret -- if not advanced_postprocessing: -+ if not advanced_postprocessing: # True - pp_results['min_valid_object_sizes'] = None +@@ -225,7 +227,20 @@ class nnUNetPlusPlusTrainerV2(nnUNetTrainer): + data_dict = next(data_generator) + data = data_dict['data'] + target = data_dict['target'] +- ++ # i = 0 ++ # while True: ++ # i += 1 ++ # data_dict = next(data_generator) ++ # data = data_dict['data'] ++ # target = data_dict['target'] ++ # data_numpy_output = '/home/yupeng/save_data.nii.gz' ++ # data_numpy = data[0][0].numpy() ++ # target_numpy = target[0][0][0].numpy() ++ # data_1 = data_numpy.flatten() ++ # minm = np.argmin(data_1) ++ # maxm = np.argmax(data_1) ++ # out = sitk.GetImageFromArray(data_numpy) ++ # sitk.WriteImage(out, data_numpy_output) + data = maybe_to_torch(data) + target = maybe_to_torch(target) - print("done") -diff --git a/pytorch/nnunet/preprocessing/cropping.py b/pytorch/nnunet/preprocessing/cropping.py -index bb0a92a..95d07bc 100644 ---- a/pytorch/nnunet/preprocessing/cropping.py -+++ b/pytorch/nnunet/preprocessing/cropping.py -@@ -39,6 +39,7 @@ def get_bbox_from_mask(mask, outside_value=0): - maxxidx = int(np.max(mask_voxel_coords[1])) + 1 - minyidx = int(np.min(mask_voxel_coords[2])) - maxyidx = int(np.max(mask_voxel_coords[2])) + 1 -+ print(mask.shape, minzidx, maxzidx, minxidx, maxxidx, minyidx, maxyidx) - return [[minzidx, maxzidx], [minxidx, maxxidx], [minyidx, maxyidx]] +@@ -234,7 +249,6 @@ class nnUNetPlusPlusTrainerV2(nnUNetTrainer): + target = to_cuda(target) + self.optimizer.zero_grad() +- + if self.fp16: + with autocast(): + output = self.network(data) +@@ -261,7 +275,6 @@ class nnUNetPlusPlusTrainerV2(nnUNetTrainer): + self.run_online_evaluation(output, target) -@@ -202,6 +203,7 @@ class ImageCropper(object): - list_of_args.append((case, case_identifier, overwrite_existing)) + del target +- + return l.detach().cpu().numpy() - p = Pool(self.num_threads) -+ print('Pool', self.num_threads) - p.starmap(self.load_crop_save, list_of_args) - p.close() - p.join() -diff --git a/pytorch/nnunet/run/look_pkl.py b/pytorch/nnunet/run/look_pkl.py -new file mode 100644 -index 0000000..1a9d78a ---- /dev/null -+++ b/pytorch/nnunet/run/look_pkl.py -@@ -0,0 +1,18 @@ -+import numpy as np -+import pickle -+ -+inputfile = u'/data/yupeng/environment_variables/RESULTS_FOLDER/nnUNet/3d_fullres/Task003_Liver' \ -+ u'/nnUNetPlusPlusTrainerV2__nnUNetPlansv2.1/fold_0/model_final_checkpoint.model.pkl' -+# test = np.load('labels.npy', encoding = "latin1") -+# doc = open('1.txt', 'a') -+# print(test, file=doc) -+ -+ -+ -+fr = open(inputfile, 'rb') -+inf = pickle.load(fr) -+print('done') -+ -+ -+ -+print('end') -\ No newline at end of file -diff --git a/pytorch/nnunet/run/model_prof.py b/pytorch/nnunet/run/model_prof.py + def do_split(self): +diff --git a/pytorch/nnunet/training/network_training/nnUNetPlusPlusTrainerV2_DDP.py b/pytorch/nnunet/training/network_training/nnUNetPlusPlusTrainerV2_DDP.py new file mode 100644 -index 0000000..013df26 +index 0000000..e2ab2fa --- /dev/null -+++ b/pytorch/nnunet/run/model_prof.py -@@ -0,0 +1,124 @@ -+# Copyright (c) Soumith Chintala 2016, -+# All rights reserved -+# -+# Copyright 2020 Huawei Technologies Co., Ltd -+# -+# Licensed under the BSD 3-Clause License (the "License"); -+# you may not use this file except in compliance with the License. -+# You may obtain a copy of the License at -+# -+# https://spdx.org/licenses/BSD-3-Clause.html -+# -+# 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. -+ -+# -*- coding: utf-8 -*- -+"""pytorch_prof.py -+""" -+ -+import torch -+import torch.optim as optim -+import torch.nn as nn -+import time -+import argparse -+ -+ -+def build_model(): -+ # 请自定义模型并加载预训练模型 -+ import torchvision -+ model = torchvision.models.resnet50(pretrained=True) -+ return model -+ -+ -+def get_raw_data(): -+ input_tensor = torch.randn(2, 3, 224, 224) -+ return input_tensor -+ -+ -+def criterion(x): -+ base_func = nn.CrossEntropyLoss() -+ shape_list = x.shape -+ N = shape_list[0] -+ R = 1 -+ if len(shape_list) > 1: -+ for r in shape_list[1:]: -+ R *= r -+ T = torch.randint(0,R, size=(N,)).to(x.device) -+ if str(T.device).startswith('npu'): -+ T = T.int() -+ return base_func(x.reshape(N, -1), T) -+ -+ -+if __name__ == '__main__': -+ parser = argparse.ArgumentParser(description='PyTorch Prof') -+ parser.add_argument('--device', type=str, default='cpu', -+ help='set which type of device used. Support cuda:0(device_id), npu:0(device_id).') -+ parser.add_argument('--amp', default=False, action='store_true', -+ help='use amp during prof') -+ parser.add_argument('--loss-scale', default=64.0, type=float, -+ help='loss scale using in amp, default 64.0, -1 means dynamic') -+ parser.add_argument('--opt-level', default='O2', type=str, -+ help='opt-level using in amp, default O2') -+ parser.add_argument('--FusedSGD', default=False, action='store_true', -+ help='use FusedSGD during prof') -+ -+ args = parser.parse_args() -+ -+ # 1.准备工作 -+ if args.device.startswith('cuda'): -+ torch.cuda.set_device(args.device) -+ prof_kwargs = {'use_cuda': True} -+ elif args.device.startswith('npu'): -+ torch.npu.set_device(args.device) -+ prof_kwargs = {'use_npu': True} -+ else: -+ prof_kwargs = {} -+ -+ # 2.构建模型 -+ model = build_model() -+ if args.FusedSGD: -+ from apex.optimizers import NpuFusedSGD -+ optimizer = NpuFusedSGD(model.parameters(), lr=0.01) -+ model = model.to(args.device) -+ if args.amp: -+ from apex import amp -+ model, optimizer = amp.initialize(model, optimizer, opt_level=args.opt_level, -+ loss_scale=None if args.loss_scale == -1 else args.loss_scale, -+ combine_grad=True) -+ else: -+ optimizer = optim.SGD(model.parameters(), lr=0.01) -+ model = model.to(args.device) -+ if args.amp: -+ from apex import amp -+ model, optimizer = amp.initialize(model, optimizer, opt_level=args.opt_level, -+ loss_scale=None if args.loss_scale == -1 else args.loss_scale) -+ -+ # 3.生成input -+ input_tensor = get_raw_data() -+ input_tensor = input_tensor.to(args.device) -+ -+ # 先运行一次,保证prof得到的性能是正确的 -+ def run(): -+ output_tensor = model(input_tensor) -+ optimizer.zero_grad() -+ loss = criterion(output_tensor) -+ if args.amp: -+ with amp.scale_loss(loss, optimizer) as scaled_loss: -+ scaled_loss.backward() -+ else: -+ loss.backward() -+ optimizer.step() -+ return loss -+ for i in range(5): -+ start_time = time.time() -+ loss = run() -+ print('iter: %d, loss: %.2f, time: %.2f' % (i, loss, (time.time() - start_time)*1000)) -+ -+ # 4. 执行forward+profiling -+ with torch.autograd.profiler.profile(**prof_kwargs) as prof: -+ run() -+ print(prof.key_averages().table()) -+ prof.export_chrome_trace("pytorch_prof_%s.prof" % args.device) -\ No newline at end of file -diff --git a/pytorch/nnunet/run/run_training.py b/pytorch/nnunet/run/run_training.py -index eb7ca2f..08214d6 100644 ---- a/pytorch/nnunet/run/run_training.py -+++ b/pytorch/nnunet/run/run_training.py -@@ -31,7 +31,7 @@ def main(): - parser.add_argument("task", help="can be task name or task id") - parser.add_argument("fold", help='0, 1, ..., 5 or \'all\'') - parser.add_argument("-val", "--validation_only", help="use this if you want to only run the validation", -- action="store_true") -+ action="store_true", default=True) - parser.add_argument("-w", required=False, default=None, help="Load pre-trained Models Genesis") - parser.add_argument("-c", "--continue_training", help="use this if you want to continue a training", - action="store_true") -@@ -134,8 +134,8 @@ def main(): - fp16=run_mixed_precision) - - trainer.initialize(not validation_only) -- -- if weights != None: ++++ b/pytorch/nnunet/training/network_training/nnUNetPlusPlusTrainerV2_DDP.py +@@ -0,0 +1,483 @@ ++# Copyright 2020 Division of Medical Image Computing, German Cancer Research Center (DKFZ), Heidelberg, Germany ++# ++# 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 collections import OrderedDict ++from typing import Tuple ++import sys ++import time ++import numpy as np ++import torch ++import torch.distributed as dist ++from torch.cuda.amp import autocast ++from torch.nn.parallel import DistributedDataParallel as DDP ++from nnunet.training.loss_functions.deep_supervision import MultipleOutputLoss2 ++from nnunet.utilities.to_torch import maybe_to_torch, to_cuda ++from nnunet.training.data_augmentation.default_data_augmentation import get_moreDA_augmentation ++from nnunet.network_architecture.generic_UNetPlusPlus import Generic_UNetPlusPlus ++from nnunet.network_architecture.initialization import InitWeights_He ++from nnunet.network_architecture.neural_network import SegmentationNetwork ++from nnunet.training.data_augmentation.default_data_augmentation import default_2D_augmentation_params, \ ++ get_patch_size, default_3D_augmentation_params ++from nnunet.training.dataloading.dataset_loading import unpack_dataset ++from nnunet.training.network_training.nnUNetTrainer import nnUNetTrainer ++from nnunet.utilities.nd_softmax import softmax_helper ++from sklearn.model_selection import KFold ++from torch import nn ++from torch.cuda.amp import autocast ++from nnunet.training.learning_rate.poly_lr import poly_lr ++from batchgenerators.utilities.file_and_folder_operations import * ++ ++ ++class nnUNetPlusPlusTrainerV2_DDP(nnUNetTrainer): ++ """ ++ Info for Fabian: same as internal nnUNetTrainerV2_2 ++ """ ++ ++ def __init__(self, plans_file, fold, local_rank, output_folder=None, dataset_directory=None, batch_dice=True, ++ stage=None, ++ unpack_data=True, deterministic=True, fp16=False, distribute_batch_size=1): ++ super().__init__(plans_file, fold, output_folder, dataset_directory, batch_dice, stage, unpack_data, ++ deterministic, fp16) ++ self.init_args = ( ++ plans_file, fold, local_rank, output_folder, dataset_directory, batch_dice, stage, unpack_data, ++ deterministic, distribute_batch_size, fp16) ++ self.max_num_epochs = 1000 ++ self.initial_lr = 1e-2 ++ self.deep_supervision_scales = None ++ self.ds_loss_weights = None ++ self.distribute_batch_size = distribute_batch_size ++ np.random.seed(local_rank) ++ torch.manual_seed(local_rank) ++ self.local_rank = local_rank ++ if torch.cuda.is_available(): ++ torch.cuda.set_device(local_rank) ++ dist.init_process_group(backend='nccl', init_method='env://') ++ ++ self.pin_memory = True ++ ++ def initialize(self, training=True, force_load_plans=False): ++ """ ++ - replaced get_default_augmentation with get_moreDA_augmentation ++ - enforce to only run this code once ++ - loss function wrapper for deep supervision ++ ++ :param training: ++ :param force_load_plans: ++ :return: ++ """ ++ if not self.was_initialized: ++ maybe_mkdir_p(self.output_folder) ++ ++ if force_load_plans or (self.plans is None): ++ self.load_plans_file() ++ ++ self.process_plans(self.plans) ++ ++ self.setup_DA_params() ++ ++ ################# Here we wrap the loss for deep supervision ############ ++ # we need to know the number of outputs of the network ++ net_numpool = len(self.net_num_pool_op_kernel_sizes) ++ ++ # we give each output a weight which decreases exponentially (division by 2) as the resolution decreases ++ # this gives higher resolution outputs more weight in the loss ++ weights = np.array([1 / (2 ** i) for i in range(net_numpool)]) ++ ++ # we don't use the lowest 2 outputs. Normalize weights so that they sum to 1 ++ mask = np.array([True] + [True if i < net_numpool - 1 else False for i in range(1, net_numpool)]) ++ weights[~mask] = 0 ++ weights = weights / weights.sum() ++ # self.ds_loss_weights = weights ++ self.ds_loss_weights = None ++ # now wrap the loss ++ self.loss = MultipleOutputLoss2(self.loss, self.ds_loss_weights) ++ ################# END ################### ++ ++ self.folder_with_preprocessed_data = join(self.dataset_directory, self.plans['data_identifier'] + ++ "_stage%d" % self.stage) ++ if training: ++ self.dl_tr, self.dl_val = self.get_basic_generators() ++ if self.unpack_data: ++ if self.local_rank == 0: ++ print("unpacking dataset") ++ unpack_dataset(self.folder_with_preprocessed_data) ++ print("done") ++ else: ++ # we need to wait until worker 0 has finished unpacking ++ npz_files = subfiles(self.folder_with_preprocessed_data, suffix=".npz", join=False) ++ case_ids = [i[:-4] for i in npz_files] ++ all_present = all( ++ [isfile(join(self.folder_with_preprocessed_data, i + ".npy")) for i in case_ids]) ++ while not all_present: ++ print("worker", self.local_rank, "is waiting for unpacking") ++ time.sleep(3) ++ all_present = all( ++ [isfile(join(self.folder_with_preprocessed_data, i + ".npy")) for i in case_ids]) ++ # there is some slight chance that there may arise some error because dataloader are loading a file ++ # that is still being written by worker 0. We ignore this for now an address it only if it becomes ++ # relevant ++ # (this can occur because while worker 0 writes the file is technically present so the other workers ++ # will proceed and eventually try to read it) ++ else: ++ print( ++ "INFO: Not unpacking data! Training may be slow due to that. Pray you are not using 2d or you " ++ "will wait all winter for your model to finish!") + -+ if weights != None: - trainer.load_pretrained_encoder_weights(weights) - sys.stdout.flush() - -diff --git a/pytorch/nnunet/run/run_training2.py b/pytorch/nnunet/run/run_training2.py -new file mode 100644 -index 0000000..372a4d4 ---- /dev/null -+++ b/pytorch/nnunet/run/run_training2.py -@@ -0,0 +1,172 @@ -+# Copyright 2020 Division of Medical Image Computing, German Cancer Research Center (DKFZ), Heidelberg, Germany -+# -+# 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 os -+import sys -+import argparse -+from batchgenerators.utilities.file_and_folder_operations import * -+from nnunet.run.default_configuration import get_default_configuration -+from nnunet.paths import default_plans_identifier -+from nnunet.training.cascade_stuff.predict_next_stage import predict_next_stage -+from nnunet.training.network_training.nnUNetTrainer import nnUNetTrainer -+from nnunet.training.network_training.nnUNetTrainerCascadeFullRes import nnUNetTrainerCascadeFullRes -+from nnunet.training.network_training.nnUNetTrainerV2_CascadeFullRes import nnUNetTrainerV2CascadeFullRes -+from nnunet.utilities.task_name_id_conversion import convert_id_to_task_name ++ self.tr_gen, self.val_gen = get_moreDA_augmentation( ++ self.dl_tr, self.dl_val, ++ self.data_aug_params[ ++ 'patch_size_for_spatialtransform'], ++ self.data_aug_params, ++ deep_supervision_scales=self.deep_supervision_scales, ++ pin_memory=self.pin_memory ++ ) ++ self.print_to_log_file("TRAINING KEYS:\n %s" % (str(self.dataset_tr.keys())), ++ also_print_to_console=False) ++ self.print_to_log_file("VALIDATION KEYS:\n %s" % (str(self.dataset_val.keys())), ++ also_print_to_console=False) ++ else: ++ pass + ++ self.initialize_network() ++ self.initialize_optimizer_and_scheduler() + -+# import pdb -+# pdb.set_trace() ++ assert isinstance(self.network, (SegmentationNetwork, DDP)) ++ else: ++ self.print_to_log_file('self.was_initialized is True, not running self.initialize again') ++ self.was_initialized = True + -+def main(): -+ parser = argparse.ArgumentParser() -+ parser.add_argument("-network", default="3d_fullres") -+ parser.add_argument("-network_trainer", default="nnUNetPlusPlusTrainerV2") -+ parser.add_argument("-task", default="003", help="can be task name or task id") -+ parser.add_argument("-fold", default="0", help='0, 1, ..., 5 or \'all\'') -+ parser.add_argument("-val", "--validation_only", default=False, -+ help="use this if you want to only run the validation", -+ action="store_true") -+ parser.add_argument("-w", required=False, default=None, help="Load pre-trained Models Genesis") -+ parser.add_argument("-c", "--continue_training", default=False, help="use this if you want to continue a training", -+ action="store_true") -+ parser.add_argument("-p", help="plans identifier. Only change this if you created a custom experiment planner", -+ default=default_plans_identifier, required=False) -+ parser.add_argument("--use_compressed_data", default=False, action="store_true", -+ help="If you set use_compressed_data, the training cases will not be decompressed. Reading compressed data " -+ "is much more CPU and RAM intensive and should only be used if you know what you are " -+ "doing", required=False) -+ parser.add_argument("--deterministic", -+ help="Makes training deterministic, but reduces training speed substantially. I (Fabian) think " -+ "this is not necessary. Deterministic training will make you overfit to some random seed. " -+ "Don't use that.", -+ required=False, default=False, action="store_true") -+ parser.add_argument("--npz", required=False, default=False, action="store_true", help="if set then nnUNet will " -+ "export npz files of " -+ "predicted segmentations " -+ "in the validation as well. " -+ "This is needed to run the " -+ "ensembling step so unless " -+ "you are developing nnUNet " -+ "you should enable this") -+ parser.add_argument("--find_lr", required=False, default=False, action="store_true", -+ help="not used here, just for fun") -+ parser.add_argument("--valbest", required=False, default=False, action="store_true", -+ help="hands off. This is not intended to be used") -+ parser.add_argument("--fp32", required=False, default=False, action="store_true", -+ help="disable mixed precision training and run old school fp32") -+ parser.add_argument("--val_folder", required=False, default="validation_raw", -+ help="name of the validation folder. No need to use this for most people") -+ # parser.add_argument("--interp_order", required=False, default=3, type=int, -+ # help="order of interpolation for segmentations. Testing purpose only. Hands off") -+ # parser.add_argument("--interp_order_z", required=False, default=0, type=int, -+ # help="order of interpolation along z if z is resampled separately. Testing purpose only. " -+ # "Hands off") -+ # parser.add_argument("--force_separate_z", required=False, default="None", type=str, -+ # help="force_separate_z resampling. Can be None, True or False. Testing purpose only. Hands off") ++ def initialize_network(self): ++ """ ++ - momentum 0.99 ++ - SGD instead of Adam ++ - self.lr_scheduler = None because we do poly_lr ++ - deep supervision = True ++ - i am sure I forgot something here + -+ args = parser.parse_args() -+ print('------------\n', args) ++ Known issue: forgot to set neg_slope=0 in InitWeights_He; should not make a difference though ++ :return: ++ """ ++ if self.threeD: ++ conv_op = nn.Conv3d ++ dropout_op = nn.Dropout3d ++ norm_op = nn.InstanceNorm3d + -+ task = args.task -+ fold = args.fold -+ network = args.network -+ network_trainer = args.network_trainer -+ weights = args.w -+ validation_only = args.validation_only -+ plans_identifier = args.p -+ find_lr = args.find_lr ++ else: ++ conv_op = nn.Conv2d ++ dropout_op = nn.Dropout2d ++ norm_op = nn.InstanceNorm2d ++ norm_op_kwargs = {'eps': 1e-5, 'affine': True} ++ dropout_op_kwargs = {'p': 0, 'inplace': True} ++ net_nonlin = nn.LeakyReLU ++ net_nonlin_kwargs = {'negative_slope': 1e-2, 'inplace': True} ++ self.network = Generic_UNetPlusPlus(self.num_input_channels, self.base_num_features, self.num_classes, ++ len(self.net_num_pool_op_kernel_sizes), ++ self.conv_per_stage, 2, conv_op, norm_op, norm_op_kwargs, dropout_op, ++ dropout_op_kwargs, ++ net_nonlin, net_nonlin_kwargs, True, False, lambda x: x, ++ InitWeights_He(1e-2), ++ self.net_num_pool_op_kernel_sizes, self.net_conv_kernel_sizes, False, True, ++ True) ++ if torch.cuda.is_available(): ++ self.network.cuda() ++ self.network.inference_apply_nonlin = softmax_helper ++ self.network = DDP(self.network, device_ids=[self.local_rank], find_unused_parameters=True) + -+ use_compressed_data = args.use_compressed_data -+ decompress_data = not use_compressed_data ++ # self.network = DDP(self.network, device_ids=[self.local_rank], find_unused_parameters=True) + -+ deterministic = args.deterministic -+ valbest = args.valbest ++ def initialize_optimizer_and_scheduler(self): ++ assert self.network is not None, "self.initialize_network must be called first" ++ print('weight_decay: ', self.weight_decay) ++ sys.stdout.flush() ++ self.optimizer = torch.optim.SGD(self.network.parameters(), self.initial_lr, weight_decay=self.weight_decay, ++ momentum=0.99, nesterov=True) ++ self.lr_scheduler = None + -+ fp32 = args.fp32 -+ run_mixed_precision = not fp32 ++ def run_online_evaluation(self, output, target): ++ """ ++ due to deep supervision the return value and the reference are now lists of tensors. We only need the full ++ resolution output because this is what we are interested in in the end. The others are ignored ++ :param output: ++ :param target: ++ :return: ++ """ ++ target = target[0] ++ output = output[0] ++ return super().run_online_evaluation(output, target) + -+ val_folder = args.val_folder -+ # interp_order = args.interp_order -+ # interp_order_z = args.interp_order_z -+ # force_separate_z = args.force_separate_z ++ def validate(self, do_mirroring: bool = True, use_sliding_window: bool = True, ++ step_size: float = 0.5, save_softmax: bool = True, use_gaussian: bool = True, overwrite: bool = True, ++ validation_folder_name: str = 'validation_raw', debug: bool = False, all_in_gpu: bool = False, ++ segmentation_export_kwargs: dict = None): ++ """ ++ We need to wrap this because we need to enforce self.network.do_ds = False for prediction ++ """ ++ if self.local_rank == 0: ++ if isinstance(self.network, DDP): ++ net = self.network.module ++ else: ++ net = self.network ++ ds = self.network.do_ds ++ net.do_ds = False ++ ret = super().validate(do_mirroring, use_sliding_window, step_size, save_softmax, use_gaussian, ++ overwrite, validation_folder_name, debug, all_in_gpu, segmentation_export_kwargs) + -+ if not task.startswith("Task"): -+ task_id = int(task) -+ task = convert_id_to_task_name(task_id) ++ net.do_ds = ds ++ return ret + -+ if fold == 'all': -+ pass -+ else: -+ fold = int(fold) ++ def predict_preprocessed_data_return_seg_and_softmax(self, data: np.ndarray, do_mirroring: bool = True, ++ mirror_axes: Tuple[int] = None, ++ use_sliding_window: bool = True, step_size: float = 0.5, ++ use_gaussian: bool = True, pad_border_mode: str = 'constant', ++ pad_kwargs: dict = None, all_in_gpu: bool = True, ++ verbose: bool = True, mixed_precision=True) -> Tuple[ ++ np.ndarray, np.ndarray]: ++ """ ++ We need to wrap this because we need to enforce self.network.do_ds = False for prediction ++ """ ++ ds = self.network.do_ds ++ self.network.do_ds = False ++ ret = super().predict_preprocessed_data_return_seg_and_softmax(data, do_mirroring, mirror_axes, ++ use_sliding_window, step_size, use_gaussian, ++ pad_border_mode, pad_kwargs, all_in_gpu, verbose, ++ mixed_precision=mixed_precision) ++ self.network.do_ds = ds ++ return ret + -+ # if force_separate_z == "None": -+ # force_separate_z = None -+ # elif force_separate_z == "False": -+ # force_separate_z = False -+ # elif force_separate_z == "True": -+ # force_separate_z = True -+ # else: -+ # raise ValueError("force_separate_z must be None, True or False. Given: %s" % force_separate_z) ++ def run_iteration(self, data_generator, do_backprop=True, run_online_evaluation=False): ++ """ ++ gradient clipping improves training stability + -+ plans_file, output_folder_name, dataset_directory, batch_dice, stage, \ -+ trainer_class, domain = get_default_configuration(network, task, network_trainer, plans_identifier) ++ :param data_generator: ++ :param do_backprop: ++ :param run_online_evaluation: ++ :return: ++ """ ++ data_dict = next(data_generator) ++ data = data_dict['data'] ++ target = data_dict['target'] + -+ if trainer_class is None: -+ raise RuntimeError("Could not find trainer class in nnunet.training.network_training") ++ data = maybe_to_torch(data) ++ target = maybe_to_torch(target) + -+ if network == "3d_cascade_fullres": -+ assert issubclass(trainer_class, (nnUNetTrainerCascadeFullRes, nnUNetTrainerV2CascadeFullRes)), \ -+ "If running 3d_cascade_fullres then your " \ -+ "trainer class must be derived from " \ -+ "nnUNetTrainerCascadeFullRes" -+ else: -+ assert issubclass(trainer_class, -+ nnUNetTrainer), "network_trainer was found but is not derived from nnUNetTrainer" ++ if torch.cuda.is_available(): ++ data = to_cuda(data, gpu_id=None) ++ target = to_cuda(target, gpu_id=None) + -+ trainer = trainer_class(plans_file, fold, output_folder=output_folder_name, dataset_directory=dataset_directory, -+ batch_dice=batch_dice, stage=stage, unpack_data=decompress_data, -+ deterministic=deterministic, -+ fp16=run_mixed_precision) ++ self.optimizer.zero_grad() + -+ trainer.initialize(not validation_only) ++ if self.fp16: ++ with autocast(): ++ output = self.network(data) ++ del data ++ l = self.loss(output, target) + -+ if weights != None: -+ trainer.load_pretrained_encoder_weights(weights) -+ sys.stdout.flush() ++ if do_backprop: ++ self.amp_grad_scaler.scale(l).backward() ++ self.amp_grad_scaler.unscale_(self.optimizer) ++ torch.nn.utils.clip_grad_norm_(self.network.parameters(), 12) ++ self.amp_grad_scaler.step(self.optimizer) ++ self.amp_grad_scaler.update() ++ else: ++ output = self.network(data) ++ del data ++ l = self.loss(output, target) ++ ++ if do_backprop: ++ l.backward() ++ torch.nn.utils.clip_grad_norm_(self.network.parameters(), 12) ++ self.optimizer.step() ++ ++ if run_online_evaluation: ++ self.run_online_evaluation(output, target) ++ ++ del target ++ ++ return l.detach().cpu().numpy() ++ ++ def do_split(self): ++ """ ++ we now allow more than 5 splits. IMPORTANT: and fold > 4 will not be a real split but just another random ++ 80:20 split of the data. You cannot run X-fold cross-validation with this code. It will always be a 5-fold CV. ++ Folds > 4 will be independent from each other ++ :return: ++ """ ++ if self.fold == "all": ++ # if fold==all then we use all images for training and validation ++ tr_keys = val_keys = list(self.dataset.keys()) ++ else: ++ splits_file = join(self.dataset_directory, "splits_final.pkl") ++ ++ # if the split file does not exist we need to create it ++ if not isfile(splits_file): ++ self.print_to_log_file("Creating new split...") ++ splits = [] ++ all_keys_sorted = np.sort(list(self.dataset.keys())) ++ kfold = KFold(n_splits=5, shuffle=True, random_state=12345) ++ for i, (train_idx, test_idx) in enumerate(kfold.split(all_keys_sorted)): ++ train_keys = np.array(all_keys_sorted)[train_idx] ++ test_keys = np.array(all_keys_sorted)[test_idx] ++ splits.append(OrderedDict()) ++ splits[-1]['train'] = train_keys ++ splits[-1]['val'] = test_keys ++ save_pickle(splits, splits_file) ++ ++ splits = load_pickle(splits_file) ++ ++ if self.fold < len(splits): ++ tr_keys = splits[self.fold]['train'] ++ val_keys = splits[self.fold]['val'] ++ else: ++ self.print_to_log_file("INFO: Requested fold %d but split file only has %d folds. I am now creating a " ++ "random 80:20 split!" % (self.fold, len(splits))) ++ # if we request a fold that is not in the split file, create a random 80:20 split ++ rnd = np.random.RandomState(seed=12345 + self.fold) ++ keys = np.sort(list(self.dataset.keys())) ++ idx_tr = rnd.choice(len(keys), int(len(keys) * 0.8), replace=False) ++ idx_val = [i for i in range(len(keys)) if i not in idx_tr] ++ tr_keys = [keys[i] for i in idx_tr] ++ val_keys = [keys[i] for i in idx_val] ++ ++ tr_keys.sort() ++ val_keys.sort() ++ self.dataset_tr = OrderedDict() ++ for i in tr_keys: ++ self.dataset_tr[i] = self.dataset[i] ++ self.dataset_val = OrderedDict() ++ for i in val_keys: ++ self.dataset_val[i] = self.dataset[i] ++ ++ def setup_DA_params(self): ++ """ ++ - we increase roation angle from [-15, 15] to [-30, 30] ++ - scale range is now (0.7, 1.4), was (0.85, 1.25) ++ - we don't do elastic deformation anymore ++ ++ :return: ++ """ ++ ++ self.deep_supervision_scales = [[1, 1, 1]] + list(list(i) for i in 1 / np.cumprod( ++ np.vstack(self.net_num_pool_op_kernel_sizes), axis=0))[:-1] ++ ++ if self.threeD: ++ self.data_aug_params = default_3D_augmentation_params ++ self.data_aug_params['rotation_x'] = (-30. / 360 * 2. * np.pi, 30. / 360 * 2. * np.pi) ++ self.data_aug_params['rotation_y'] = (-30. / 360 * 2. * np.pi, 30. / 360 * 2. * np.pi) ++ self.data_aug_params['rotation_z'] = (-30. / 360 * 2. * np.pi, 30. / 360 * 2. * np.pi) ++ if self.do_dummy_2D_aug: ++ self.data_aug_params["dummy_2D"] = True ++ self.print_to_log_file("Using dummy2d data augmentation") ++ self.data_aug_params["elastic_deform_alpha"] = \ ++ default_2D_augmentation_params["elastic_deform_alpha"] ++ self.data_aug_params["elastic_deform_sigma"] = \ ++ default_2D_augmentation_params["elastic_deform_sigma"] ++ self.data_aug_params["rotation_x"] = default_2D_augmentation_params["rotation_x"] ++ else: ++ self.do_dummy_2D_aug = False ++ if max(self.patch_size) / min(self.patch_size) > 1.5: ++ default_2D_augmentation_params['rotation_x'] = (-15. / 360 * 2. * np.pi, 15. / 360 * 2. * np.pi) ++ self.data_aug_params = default_2D_augmentation_params ++ self.data_aug_params["mask_was_used_for_normalization"] = self.use_mask_for_norm ++ ++ if self.do_dummy_2D_aug: ++ self.basic_generator_patch_size = get_patch_size(self.patch_size[1:], ++ self.data_aug_params['rotation_x'], ++ self.data_aug_params['rotation_y'], ++ self.data_aug_params['rotation_z'], ++ self.data_aug_params['scale_range']) ++ self.basic_generator_patch_size = np.array([self.patch_size[0]] + list(self.basic_generator_patch_size)) ++ patch_size_for_spatialtransform = self.patch_size[1:] ++ else: ++ self.basic_generator_patch_size = get_patch_size(self.patch_size, self.data_aug_params['rotation_x'], ++ self.data_aug_params['rotation_y'], ++ self.data_aug_params['rotation_z'], ++ self.data_aug_params['scale_range']) ++ patch_size_for_spatialtransform = self.patch_size ++ ++ self.data_aug_params["scale_range"] = (0.7, 1.4) ++ self.data_aug_params["do_elastic"] = False ++ self.data_aug_params['selected_seg_channels'] = [0] ++ self.data_aug_params['patch_size_for_spatialtransform'] = patch_size_for_spatialtransform ++ ++ self.data_aug_params["num_cached_per_thread"] = 2 ++ ++ def maybe_update_lr(self, epoch=None): ++ """ ++ if epoch is not None we overwrite epoch. Else we use epoch = self.epoch + 1 + -+ if find_lr: -+ trainer.find_lr() -+ else: -+ if not validation_only: -+ if args.continue_training: -+ trainer.load_latest_checkpoint() -+ trainer.run_training() ++ (maybe_update_lr is called in on_epoch_end which is called before epoch is incremented. ++ herefore we need to do +1 here) ++ ++ :param epoch: ++ :return: ++ """ ++ if epoch is None: ++ ep = self.epoch + 1 + else: -+ if valbest: -+ trainer.load_best_checkpoint(train=False) -+ else: -+ trainer.load_latest_checkpoint(train=False) ++ ep = epoch ++ self.optimizer.param_groups[0]['lr'] = poly_lr(ep, self.max_num_epochs, self.initial_lr, 0.9) ++ self.print_to_log_file("lr:", np.round(self.optimizer.param_groups[0]['lr'], decimals=6)) + -+ trainer.network.eval() ++ def on_epoch_end(self): ++ """ ++ overwrite patient-based early stopping. Always run to 1000 epochs ++ :return: ++ """ ++ super().on_epoch_end() ++ continue_training = self.epoch < self.max_num_epochs + -+ # predict validation -+ trainer.validate(save_softmax=args.npz, validation_folder_name=val_folder) ++ # it can rarely happen that the momentum of nnUNetTrainerV2_plus is too high for some dataset. If at epoch 100 the ++ # estimated validation Dice is still 0 then we reduce the momentum from 0.99 to 0.95 ++ if self.epoch == 100: ++ if self.all_val_eval_metrics[-1] == 0: ++ self.optimizer.param_groups[0]["momentum"] = 0.95 ++ self.network.apply(InitWeights_He(1e-2)) ++ self.print_to_log_file("At epoch 100, the mean foreground Dice was 0. This can be caused by a too " ++ "high momentum. High momentum (0.99) is good for datasets where it works, but " ++ "sometimes causes issues such as this one. Momentum has now been reduced to " ++ "0.95 and network weights have been reinitialized") ++ return continue_training + -+ if network == '3d_lowres': -+ trainer.load_best_checkpoint(False) -+ print("predicting segmentations for the next stage of the cascade") -+ predict_next_stage(trainer, join(dataset_directory, trainer.plans['data_identifier'] + "_stage%d" % 1)) ++ def save_checkpoint(self, fname, save_optimizer=True): ++ if self.local_rank == 0: ++ super().save_checkpoint(fname, save_optimizer) + ++ def plot_progress(self): ++ if self.local_rank == 0: ++ super().plot_progress() + -+if __name__ == "__main__": -+ main() -diff --git a/pytorch/nnunet/run/run_training_DDP.py b/pytorch/nnunet/run/run_training_DDP.py -index 5ffcdcf..6ad3d5a 100644 ---- a/pytorch/nnunet/run/run_training_DDP.py -+++ b/pytorch/nnunet/run/run_training_DDP.py -@@ -27,13 +27,13 @@ from nnunet.utilities.task_name_id_conversion import convert_id_to_task_name - - def main(): - parser = argparse.ArgumentParser() -- parser.add_argument("network") -- parser.add_argument("network_trainer") -- parser.add_argument("task", help="can be task name or task id") -- parser.add_argument("fold", help='0, 1, ..., 5 or \'all\'') -+ parser.add_argument("network", default='3d_fullres') -+ parser.add_argument("network_trainer", default='nnUNetTrainerV2_DDP') -+ parser.add_argument("task", help="can be task name or task id", default='003') -+ parser.add_argument("fold", help='0, 1, ..., 5 or \'all\'', default='0') - parser.add_argument("-val", "--validation_only", help="use this if you want to only run the validation", -- action="store_true") -- parser.add_argument("-c", "--continue_training", help="use this if you want to continue a training", -+ action="store_true", default=False) -+ parser.add_argument("-c", "--continue_training", default=False, help="use this if you want to continue a training", - action="store_true") - parser.add_argument("-p", help="plans identifier. Only change this if you created a custom experiment planner", - default=default_plans_identifier, required=False) -@@ -78,7 +78,7 @@ def main(): - # help="force_separate_z resampling. Can be None, True or False. Testing purpose only. Hands off") - - args = parser.parse_args() -- -+ print('\n\n args=', args, '\n\n') - task = args.task - fold = args.fold - network = args.network -@@ -115,7 +115,7 @@ def main(): - # raise ValueError("force_separate_z must be None, True or False. Given: %s" % force_separate_z) - - plans_file, output_folder_name, dataset_directory, batch_dice, stage, \ -- trainer_class = get_default_configuration(network, task, network_trainer, plans_identifier) -+ trainer_class, _ = get_default_configuration(network, task, network_trainer, plans_identifier) - - if trainer_class is None: - raise RuntimeError("Could not find trainer class in meddec.model_training") -diff --git a/pytorch/nnunet/run/run_training_hypDDP.py b/pytorch/nnunet/run/run_training_hypDDP.py -new file mode 100644 -index 0000000..f50744c ---- /dev/null -+++ b/pytorch/nnunet/run/run_training_hypDDP.py -@@ -0,0 +1,164 @@ -+# Copyright 2020 Division of Medical Image Computing, German Cancer Research Center (DKFZ), Heidelberg, Germany -+# -+# 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 argparse -+ -+from batchgenerators.utilities.file_and_folder_operations import * -+from nnunet.run.default_configuration import get_default_configuration -+from nnunet.paths import default_plans_identifier -+from nnunet.training.cascade_stuff.predict_next_stage import predict_next_stage -+from nnunet.training.network_training.nnUNetTrainer import nnUNetTrainer -+from nnunet.training.network_training.nnUNetTrainerCascadeFullRes import nnUNetTrainerCascadeFullRes -+from nnunet.training.network_training.nnUNetTrainerV2_CascadeFullRes import nnUNetTrainerV2CascadeFullRes -+from nnunet.utilities.task_name_id_conversion import convert_id_to_task_name -+ -+ -+def main(): -+ parser = argparse.ArgumentParser() -+ parser.add_argument("network") -+ parser.add_argument("network_trainer") -+ parser.add_argument("task", help="can be task name or task id") -+ parser.add_argument("fold", help='0, 1, ..., 5 or \'all\'') -+ parser.add_argument("-val", "--validation_only", help="use this if you want to only run the validation", -+ action="store_true") -+ parser.add_argument("-c", "--continue_training", help="use this if you want to continue a training", -+ action="store_true") -+ parser.add_argument("-p", help="plans identifier. Only change this if you created a custom experiment planner", -+ default=default_plans_identifier, required=False) -+ parser.add_argument("--use_compressed_data", default=False, action="store_true", -+ help="If you set use_compressed_data, the training cases will not be decompressed. Reading compressed data " -+ "is much more CPU and RAM intensive and should only be used if you know what you are " -+ "doing", required=False) -+ parser.add_argument("--deterministic", -+ help="Makes training deterministic, but reduces training speed substantially. I (Fabian) think " -+ "this is not necessary. Deterministic training will make you overfit to some random seed. " -+ "Don't use that.", -+ required=False, default=False, action="store_true") -+ parser.add_argument("--local_rank", default=0, type=int) -+ parser.add_argument("--fp32", required=False, default=False, action="store_true", -+ help="disable mixed precision training and run old school fp32") -+ parser.add_argument("--dbs", required=False, default=False, action="store_true", help="distribute batch size. If " -+ "True then whatever " -+ "batch_size is in plans will " -+ "be distributed over DDP " -+ "models, if False then each " -+ "model will have batch_size " -+ "for a total of " -+ "GPUs*batch_size") -+ parser.add_argument("--npz", required=False, default=False, action="store_true", help="if set then nnUNet will " -+ "export npz files of " -+ "predicted segmentations " -+ "in the vlaidation as well. " -+ "This is needed to run the " -+ "ensembling step so unless " -+ "you are developing nnUNet " -+ "you should enable this") -+ parser.add_argument("--valbest", required=False, default=False, action="store_true", help="") -+ parser.add_argument("--find_lr", required=False, default=False, action="store_true", help="") -+ parser.add_argument("--val_folder", required=False, default="validation_raw", -+ help="name of the validation folder. No need to use this for most people") -+ # parser.add_argument("--interp_order", required=False, default=3, type=int, -+ # help="order of interpolation for segmentations. Testing purpose only. Hands off") -+ # parser.add_argument("--interp_order_z", required=False, default=0, type=int, -+ # help="order of interpolation along z if z is resampled separately. Testing purpose only. " -+ # "Hands off") -+ # parser.add_argument("--force_separate_z", required=False, default="None", type=str, -+ # help="force_separate_z resampling. Can be None, True or False. Testing purpose only. Hands off") -+ -+ args = parser.parse_args() -+ print('\n\n args=', args, '\n\n') -+ task = args.task -+ fold = args.fold -+ network = args.network -+ network_trainer = args.network_trainer -+ validation_only = args.validation_only -+ plans_identifier = args.p -+ use_compressed_data = args.use_compressed_data -+ decompress_data = not use_compressed_data -+ deterministic = args.deterministic -+ valbest = args.valbest -+ find_lr = args.find_lr -+ val_folder = args.val_folder -+ # interp_order = args.interp_order -+ # interp_order_z = args.interp_order_z -+ # force_separate_z = args.force_separate_z -+ fp32 = args.fp32 -+ -+ if not task.startswith("Task"): -+ task_id = int(task) -+ task = convert_id_to_task_name(task_id) -+ -+ if fold == 'all': -+ pass -+ else: -+ fold = int(fold) -+ # -+ # if force_separate_z == "None": -+ # force_separate_z = None -+ # elif force_separate_z == "False": -+ # force_separate_z = False -+ # elif force_separate_z == "True": -+ # force_separate_z = True -+ # else: -+ # raise ValueError("force_separate_z must be None, True or False. Given: %s" % force_separate_z) -+ -+ plans_file, output_folder_name, dataset_directory, batch_dice, stage, \ -+ trainer_class, _ = get_default_configuration(network, task, network_trainer, plans_identifier) -+ -+ if trainer_class is None: -+ raise RuntimeError("Could not find trainer class in meddec.model_training") -+ -+ if network == "3d_cascade_fullres": -+ assert issubclass(trainer_class, (nnUNetTrainerCascadeFullRes, nnUNetTrainerV2CascadeFullRes)), \ -+ "If running 3d_cascade_fullres then your " \ -+ "trainer class must be derived from " \ -+ "nnUNetTrainerCascadeFullRes" -+ else: -+ assert issubclass(trainer_class, -+ nnUNetTrainer), "network_trainer was found but is not derived from nnUNetTrainer" -+ -+ trainer = trainer_class(plans_file, fold, local_rank=args.local_rank, output_folder=output_folder_name, -+ dataset_directory=dataset_directory, batch_dice=batch_dice, stage=stage, -+ unpack_data=decompress_data, deterministic=deterministic, fp16=not fp32, -+ distribute_batch_size=args.dbs) -+ -+ trainer.initialize(not validation_only) -+ -+ if find_lr: -+ trainer.find_lr() -+ else: -+ if not validation_only: -+ if args.continue_training: -+ trainer.load_latest_checkpoint() -+ trainer.run_training() -+ else: -+ if valbest: -+ trainer.load_best_checkpoint(train=False) -+ else: -+ trainer.load_latest_checkpoint(train=False) -+ -+ trainer.network.eval() -+ -+ # predict validation -+ trainer.validate(save_softmax=args.npz, validation_folder_name=val_folder) -+ -+ if network == '3d_lowres': -+ trainer.load_best_checkpoint(False) -+ print("predicting segmentations for the next stage of the cascade") -+ predict_next_stage(trainer, join(dataset_directory, trainer.plans['data_identifier'] + "_stage%d" % 1)) -+ -+ -+if __name__ == "__main__": -+ main() -diff --git a/pytorch/nnunet/training/loss_functions/crossentropy.py b/pytorch/nnunet/training/loss_functions/crossentropy.py -index 6195437..0c782d9 100644 ---- a/pytorch/nnunet/training/loss_functions/crossentropy.py -+++ b/pytorch/nnunet/training/loss_functions/crossentropy.py -@@ -6,6 +6,15 @@ class RobustCrossEntropyLoss(nn.CrossEntropyLoss): - this is just a compatibility layer because my target tensor is float and has an extra dimension - """ - def forward(self, input: Tensor, target: Tensor) -> Tensor: -+ # i = 0 -+ # print('----------') -+ # print('input:', input.shape) -+ # for i in range(len(input)): -+ # print(i, input[i].shape) -+ # print('target') -+ # for i in range(len(target)): -+ # print(i, target[i].shape) -+ # print('\n----------') - if len(target.shape) == len(input.shape): - assert target.shape[1] == 1 - target = target[:, 0] -diff --git a/pytorch/nnunet/training/network_training/network_trainer.py b/pytorch/nnunet/training/network_training/network_trainer.py -index e920158..f0031d3 100644 ---- a/pytorch/nnunet/training/network_training/network_trainer.py -+++ b/pytorch/nnunet/training/network_training/network_trainer.py -@@ -37,6 +37,7 @@ from abc import abstractmethod - from datetime import datetime - from tqdm import trange - from nnunet.utilities.to_torch import maybe_to_torch, to_cuda -+import pdb - - - class NetworkTrainer(object): -@@ -438,7 +439,8 @@ class NetworkTrainer(object): - self._maybe_init_amp() - - def _maybe_init_amp(self): -- if self.fp16 and self.amp_grad_scaler is None and torch.cuda.is_available(): -+ # if self.fp16 and self.amp_grad_scaler is None and torch.cuda.is_available(): -+ if self.fp16 and self.amp_grad_scaler is None: - self.amp_grad_scaler = GradScaler() - - def plot_network_architecture(self): -diff --git a/pytorch/nnunet/training/network_training/nnUNetPlusPlusTrainerV2.py b/pytorch/nnunet/training/network_training/nnUNetPlusPlusTrainerV2.py -index e9aa611..9b97e8c 100644 ---- a/pytorch/nnunet/training/network_training/nnUNetPlusPlusTrainerV2.py -+++ b/pytorch/nnunet/training/network_training/nnUNetPlusPlusTrainerV2.py -@@ -13,6 +13,7 @@ - # limitations under the License. - - -+import SimpleITK as sitk - from collections import OrderedDict - from typing import Tuple - import sys -@@ -35,12 +36,10 @@ from torch.cuda.amp import autocast - from nnunet.training.learning_rate.poly_lr import poly_lr - from batchgenerators.utilities.file_and_folder_operations import * - -- - class nnUNetPlusPlusTrainerV2(nnUNetTrainer): - """ - Info for Fabian: same as internal nnUNetTrainerV2_2 - """ -- - def __init__(self, plans_file, fold, output_folder=None, dataset_directory=None, batch_dice=True, stage=None, - unpack_data=True, deterministic=True, fp16=False): - super().__init__(plans_file, fold, output_folder, dataset_directory, batch_dice, stage, unpack_data, -@@ -66,7 +65,7 @@ class nnUNetPlusPlusTrainerV2(nnUNetTrainer): - maybe_mkdir_p(self.output_folder) - - if force_load_plans or (self.plans is None): -- self.load_plans_file() -+ self.load_plans_file() # '/data/yupeng/environment_variables/nnUNet_preprocessed/Task003_Liver/nnUNetPlansv2.1_plans_3D.pkl' - - self.process_plans(self.plans) - -@@ -189,6 +188,7 @@ class nnUNetPlusPlusTrainerV2(nnUNetTrainer): - """ - ds = self.network.do_ds - self.network.do_ds = False -+ overwrite = False # 不希望重新跑推理,不然太久了 - ret = super().validate(do_mirroring, use_sliding_window, step_size, save_softmax, use_gaussian, - overwrite, validation_folder_name, debug, all_in_gpu, segmentation_export_kwargs) - -@@ -200,16 +200,18 @@ class nnUNetPlusPlusTrainerV2(nnUNetTrainer): - use_sliding_window: bool = True, step_size: float = 0.5, - use_gaussian: bool = True, pad_border_mode: str = 'constant', - pad_kwargs: dict = None, all_in_gpu: bool = True, -- verbose: bool = True, mixed_precision=True) -> Tuple[np.ndarray, np.ndarray]: -+ verbose: bool = True, mixed_precision=True, img_name=None, -+ pre_mode=None, fp=None) -> Tuple[np.ndarray, np.ndarray]: - """ - We need to wrap this because we need to enforce self.network.do_ds = False for prediction - """ -- ds = self.network.do_ds -+ ds = self.network.do_ds # ds = True - self.network.do_ds = False - ret = super().predict_preprocessed_data_return_seg_and_softmax(data, do_mirroring, mirror_axes, - use_sliding_window, step_size, use_gaussian, - pad_border_mode, pad_kwargs, all_in_gpu, verbose, -- mixed_precision=mixed_precision) -+ mixed_precision=mixed_precision, img_name=img_name, -+ pre_mode=pre_mode, fp=fp) - self.network.do_ds = ds - return ret - -@@ -225,7 +227,20 @@ class nnUNetPlusPlusTrainerV2(nnUNetTrainer): - data_dict = next(data_generator) - data = data_dict['data'] - target = data_dict['target'] -- -+ # i = 0 -+ # while True: -+ # i += 1 -+ # data_dict = next(data_generator) -+ # data = data_dict['data'] -+ # target = data_dict['target'] -+ # data_numpy_output = '/home/yupeng/save_data.nii.gz' -+ # data_numpy = data[0][0].numpy() -+ # target_numpy = target[0][0][0].numpy() -+ # data_1 = data_numpy.flatten() -+ # minm = np.argmin(data_1) -+ # maxm = np.argmax(data_1) -+ # out = sitk.GetImageFromArray(data_numpy) -+ # sitk.WriteImage(out, data_numpy_output) - data = maybe_to_torch(data) - target = maybe_to_torch(target) - -@@ -234,7 +249,6 @@ class nnUNetPlusPlusTrainerV2(nnUNetTrainer): - target = to_cuda(target) - - self.optimizer.zero_grad() -- - if self.fp16: - with autocast(): - output = self.network(data) -@@ -261,7 +275,6 @@ class nnUNetPlusPlusTrainerV2(nnUNetTrainer): - self.run_online_evaluation(output, target) - - del target -- - return l.detach().cpu().numpy() - - def do_split(self): -diff --git a/pytorch/nnunet/training/network_training/nnUNetPlusPlusTrainerV2_DDP.py b/pytorch/nnunet/training/network_training/nnUNetPlusPlusTrainerV2_DDP.py -new file mode 100644 -index 0000000..e2ab2fa ---- /dev/null -+++ b/pytorch/nnunet/training/network_training/nnUNetPlusPlusTrainerV2_DDP.py -@@ -0,0 +1,483 @@ -+# Copyright 2020 Division of Medical Image Computing, German Cancer Research Center (DKFZ), Heidelberg, Germany -+# -+# 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 collections import OrderedDict -+from typing import Tuple -+import sys -+import time -+import numpy as np -+import torch -+import torch.distributed as dist -+from torch.cuda.amp import autocast -+from torch.nn.parallel import DistributedDataParallel as DDP -+from nnunet.training.loss_functions.deep_supervision import MultipleOutputLoss2 -+from nnunet.utilities.to_torch import maybe_to_torch, to_cuda -+from nnunet.training.data_augmentation.default_data_augmentation import get_moreDA_augmentation -+from nnunet.network_architecture.generic_UNetPlusPlus import Generic_UNetPlusPlus -+from nnunet.network_architecture.initialization import InitWeights_He -+from nnunet.network_architecture.neural_network import SegmentationNetwork -+from nnunet.training.data_augmentation.default_data_augmentation import default_2D_augmentation_params, \ -+ get_patch_size, default_3D_augmentation_params -+from nnunet.training.dataloading.dataset_loading import unpack_dataset -+from nnunet.training.network_training.nnUNetTrainer import nnUNetTrainer -+from nnunet.utilities.nd_softmax import softmax_helper -+from sklearn.model_selection import KFold -+from torch import nn -+from torch.cuda.amp import autocast -+from nnunet.training.learning_rate.poly_lr import poly_lr -+from batchgenerators.utilities.file_and_folder_operations import * -+ -+ -+class nnUNetPlusPlusTrainerV2_DDP(nnUNetTrainer): -+ """ -+ Info for Fabian: same as internal nnUNetTrainerV2_2 -+ """ -+ -+ def __init__(self, plans_file, fold, local_rank, output_folder=None, dataset_directory=None, batch_dice=True, -+ stage=None, -+ unpack_data=True, deterministic=True, fp16=False, distribute_batch_size=1): -+ super().__init__(plans_file, fold, output_folder, dataset_directory, batch_dice, stage, unpack_data, -+ deterministic, fp16) -+ self.init_args = ( -+ plans_file, fold, local_rank, output_folder, dataset_directory, batch_dice, stage, unpack_data, -+ deterministic, distribute_batch_size, fp16) -+ self.max_num_epochs = 1000 -+ self.initial_lr = 1e-2 -+ self.deep_supervision_scales = None -+ self.ds_loss_weights = None -+ self.distribute_batch_size = distribute_batch_size -+ np.random.seed(local_rank) -+ torch.manual_seed(local_rank) -+ self.local_rank = local_rank -+ if torch.cuda.is_available(): -+ torch.cuda.set_device(local_rank) -+ dist.init_process_group(backend='nccl', init_method='env://') -+ -+ self.pin_memory = True -+ -+ def initialize(self, training=True, force_load_plans=False): -+ """ -+ - replaced get_default_augmentation with get_moreDA_augmentation -+ - enforce to only run this code once -+ - loss function wrapper for deep supervision -+ -+ :param training: -+ :param force_load_plans: -+ :return: -+ """ -+ if not self.was_initialized: -+ maybe_mkdir_p(self.output_folder) -+ -+ if force_load_plans or (self.plans is None): -+ self.load_plans_file() -+ -+ self.process_plans(self.plans) -+ -+ self.setup_DA_params() -+ -+ ################# Here we wrap the loss for deep supervision ############ -+ # we need to know the number of outputs of the network -+ net_numpool = len(self.net_num_pool_op_kernel_sizes) -+ -+ # we give each output a weight which decreases exponentially (division by 2) as the resolution decreases -+ # this gives higher resolution outputs more weight in the loss -+ weights = np.array([1 / (2 ** i) for i in range(net_numpool)]) -+ -+ # we don't use the lowest 2 outputs. Normalize weights so that they sum to 1 -+ mask = np.array([True] + [True if i < net_numpool - 1 else False for i in range(1, net_numpool)]) -+ weights[~mask] = 0 -+ weights = weights / weights.sum() -+ # self.ds_loss_weights = weights -+ self.ds_loss_weights = None -+ # now wrap the loss -+ self.loss = MultipleOutputLoss2(self.loss, self.ds_loss_weights) -+ ################# END ################### -+ -+ self.folder_with_preprocessed_data = join(self.dataset_directory, self.plans['data_identifier'] + -+ "_stage%d" % self.stage) -+ if training: -+ self.dl_tr, self.dl_val = self.get_basic_generators() -+ if self.unpack_data: -+ if self.local_rank == 0: -+ print("unpacking dataset") -+ unpack_dataset(self.folder_with_preprocessed_data) -+ print("done") -+ else: -+ # we need to wait until worker 0 has finished unpacking -+ npz_files = subfiles(self.folder_with_preprocessed_data, suffix=".npz", join=False) -+ case_ids = [i[:-4] for i in npz_files] -+ all_present = all( -+ [isfile(join(self.folder_with_preprocessed_data, i + ".npy")) for i in case_ids]) -+ while not all_present: -+ print("worker", self.local_rank, "is waiting for unpacking") -+ time.sleep(3) -+ all_present = all( -+ [isfile(join(self.folder_with_preprocessed_data, i + ".npy")) for i in case_ids]) -+ # there is some slight chance that there may arise some error because dataloader are loading a file -+ # that is still being written by worker 0. We ignore this for now an address it only if it becomes -+ # relevant -+ # (this can occur because while worker 0 writes the file is technically present so the other workers -+ # will proceed and eventually try to read it) -+ else: -+ print( -+ "INFO: Not unpacking data! Training may be slow due to that. Pray you are not using 2d or you " -+ "will wait all winter for your model to finish!") -+ -+ self.tr_gen, self.val_gen = get_moreDA_augmentation( -+ self.dl_tr, self.dl_val, -+ self.data_aug_params[ -+ 'patch_size_for_spatialtransform'], -+ self.data_aug_params, -+ deep_supervision_scales=self.deep_supervision_scales, -+ pin_memory=self.pin_memory -+ ) -+ self.print_to_log_file("TRAINING KEYS:\n %s" % (str(self.dataset_tr.keys())), -+ also_print_to_console=False) -+ self.print_to_log_file("VALIDATION KEYS:\n %s" % (str(self.dataset_val.keys())), -+ also_print_to_console=False) -+ else: -+ pass -+ -+ self.initialize_network() -+ self.initialize_optimizer_and_scheduler() -+ -+ assert isinstance(self.network, (SegmentationNetwork, DDP)) -+ else: -+ self.print_to_log_file('self.was_initialized is True, not running self.initialize again') -+ self.was_initialized = True -+ -+ def initialize_network(self): -+ """ -+ - momentum 0.99 -+ - SGD instead of Adam -+ - self.lr_scheduler = None because we do poly_lr -+ - deep supervision = True -+ - i am sure I forgot something here -+ -+ Known issue: forgot to set neg_slope=0 in InitWeights_He; should not make a difference though -+ :return: -+ """ -+ if self.threeD: -+ conv_op = nn.Conv3d -+ dropout_op = nn.Dropout3d -+ norm_op = nn.InstanceNorm3d -+ -+ else: -+ conv_op = nn.Conv2d -+ dropout_op = nn.Dropout2d -+ norm_op = nn.InstanceNorm2d -+ norm_op_kwargs = {'eps': 1e-5, 'affine': True} -+ dropout_op_kwargs = {'p': 0, 'inplace': True} -+ net_nonlin = nn.LeakyReLU -+ net_nonlin_kwargs = {'negative_slope': 1e-2, 'inplace': True} -+ self.network = Generic_UNetPlusPlus(self.num_input_channels, self.base_num_features, self.num_classes, -+ len(self.net_num_pool_op_kernel_sizes), -+ self.conv_per_stage, 2, conv_op, norm_op, norm_op_kwargs, dropout_op, -+ dropout_op_kwargs, -+ net_nonlin, net_nonlin_kwargs, True, False, lambda x: x, -+ InitWeights_He(1e-2), -+ self.net_num_pool_op_kernel_sizes, self.net_conv_kernel_sizes, False, True, -+ True) -+ if torch.cuda.is_available(): -+ self.network.cuda() -+ self.network.inference_apply_nonlin = softmax_helper -+ self.network = DDP(self.network, device_ids=[self.local_rank], find_unused_parameters=True) -+ -+ # self.network = DDP(self.network, device_ids=[self.local_rank], find_unused_parameters=True) -+ -+ def initialize_optimizer_and_scheduler(self): -+ assert self.network is not None, "self.initialize_network must be called first" -+ print('weight_decay: ', self.weight_decay) -+ sys.stdout.flush() -+ self.optimizer = torch.optim.SGD(self.network.parameters(), self.initial_lr, weight_decay=self.weight_decay, -+ momentum=0.99, nesterov=True) -+ self.lr_scheduler = None -+ -+ def run_online_evaluation(self, output, target): -+ """ -+ due to deep supervision the return value and the reference are now lists of tensors. We only need the full -+ resolution output because this is what we are interested in in the end. The others are ignored -+ :param output: -+ :param target: -+ :return: -+ """ -+ target = target[0] -+ output = output[0] -+ return super().run_online_evaluation(output, target) -+ -+ def validate(self, do_mirroring: bool = True, use_sliding_window: bool = True, -+ step_size: float = 0.5, save_softmax: bool = True, use_gaussian: bool = True, overwrite: bool = True, -+ validation_folder_name: str = 'validation_raw', debug: bool = False, all_in_gpu: bool = False, -+ segmentation_export_kwargs: dict = None): -+ """ -+ We need to wrap this because we need to enforce self.network.do_ds = False for prediction -+ """ -+ if self.local_rank == 0: -+ if isinstance(self.network, DDP): -+ net = self.network.module -+ else: -+ net = self.network -+ ds = self.network.do_ds -+ net.do_ds = False -+ ret = super().validate(do_mirroring, use_sliding_window, step_size, save_softmax, use_gaussian, -+ overwrite, validation_folder_name, debug, all_in_gpu, segmentation_export_kwargs) -+ -+ net.do_ds = ds -+ return ret -+ -+ def predict_preprocessed_data_return_seg_and_softmax(self, data: np.ndarray, do_mirroring: bool = True, -+ mirror_axes: Tuple[int] = None, -+ use_sliding_window: bool = True, step_size: float = 0.5, -+ use_gaussian: bool = True, pad_border_mode: str = 'constant', -+ pad_kwargs: dict = None, all_in_gpu: bool = True, -+ verbose: bool = True, mixed_precision=True) -> Tuple[ -+ np.ndarray, np.ndarray]: -+ """ -+ We need to wrap this because we need to enforce self.network.do_ds = False for prediction -+ """ -+ ds = self.network.do_ds -+ self.network.do_ds = False -+ ret = super().predict_preprocessed_data_return_seg_and_softmax(data, do_mirroring, mirror_axes, -+ use_sliding_window, step_size, use_gaussian, -+ pad_border_mode, pad_kwargs, all_in_gpu, verbose, -+ mixed_precision=mixed_precision) -+ self.network.do_ds = ds -+ return ret -+ -+ def run_iteration(self, data_generator, do_backprop=True, run_online_evaluation=False): -+ """ -+ gradient clipping improves training stability -+ -+ :param data_generator: -+ :param do_backprop: -+ :param run_online_evaluation: -+ :return: -+ """ -+ data_dict = next(data_generator) -+ data = data_dict['data'] -+ target = data_dict['target'] -+ -+ data = maybe_to_torch(data) -+ target = maybe_to_torch(target) -+ -+ if torch.cuda.is_available(): -+ data = to_cuda(data, gpu_id=None) -+ target = to_cuda(target, gpu_id=None) -+ -+ self.optimizer.zero_grad() -+ -+ if self.fp16: -+ with autocast(): -+ output = self.network(data) -+ del data -+ l = self.loss(output, target) -+ -+ if do_backprop: -+ self.amp_grad_scaler.scale(l).backward() -+ self.amp_grad_scaler.unscale_(self.optimizer) -+ torch.nn.utils.clip_grad_norm_(self.network.parameters(), 12) -+ self.amp_grad_scaler.step(self.optimizer) -+ self.amp_grad_scaler.update() -+ else: -+ output = self.network(data) -+ del data -+ l = self.loss(output, target) -+ -+ if do_backprop: -+ l.backward() -+ torch.nn.utils.clip_grad_norm_(self.network.parameters(), 12) -+ self.optimizer.step() -+ -+ if run_online_evaluation: -+ self.run_online_evaluation(output, target) -+ -+ del target -+ -+ return l.detach().cpu().numpy() -+ -+ def do_split(self): -+ """ -+ we now allow more than 5 splits. IMPORTANT: and fold > 4 will not be a real split but just another random -+ 80:20 split of the data. You cannot run X-fold cross-validation with this code. It will always be a 5-fold CV. -+ Folds > 4 will be independent from each other -+ :return: -+ """ -+ if self.fold == "all": -+ # if fold==all then we use all images for training and validation -+ tr_keys = val_keys = list(self.dataset.keys()) -+ else: -+ splits_file = join(self.dataset_directory, "splits_final.pkl") -+ -+ # if the split file does not exist we need to create it -+ if not isfile(splits_file): -+ self.print_to_log_file("Creating new split...") -+ splits = [] -+ all_keys_sorted = np.sort(list(self.dataset.keys())) -+ kfold = KFold(n_splits=5, shuffle=True, random_state=12345) -+ for i, (train_idx, test_idx) in enumerate(kfold.split(all_keys_sorted)): -+ train_keys = np.array(all_keys_sorted)[train_idx] -+ test_keys = np.array(all_keys_sorted)[test_idx] -+ splits.append(OrderedDict()) -+ splits[-1]['train'] = train_keys -+ splits[-1]['val'] = test_keys -+ save_pickle(splits, splits_file) -+ -+ splits = load_pickle(splits_file) -+ -+ if self.fold < len(splits): -+ tr_keys = splits[self.fold]['train'] -+ val_keys = splits[self.fold]['val'] -+ else: -+ self.print_to_log_file("INFO: Requested fold %d but split file only has %d folds. I am now creating a " -+ "random 80:20 split!" % (self.fold, len(splits))) -+ # if we request a fold that is not in the split file, create a random 80:20 split -+ rnd = np.random.RandomState(seed=12345 + self.fold) -+ keys = np.sort(list(self.dataset.keys())) -+ idx_tr = rnd.choice(len(keys), int(len(keys) * 0.8), replace=False) -+ idx_val = [i for i in range(len(keys)) if i not in idx_tr] -+ tr_keys = [keys[i] for i in idx_tr] -+ val_keys = [keys[i] for i in idx_val] -+ -+ tr_keys.sort() -+ val_keys.sort() -+ self.dataset_tr = OrderedDict() -+ for i in tr_keys: -+ self.dataset_tr[i] = self.dataset[i] -+ self.dataset_val = OrderedDict() -+ for i in val_keys: -+ self.dataset_val[i] = self.dataset[i] -+ -+ def setup_DA_params(self): -+ """ -+ - we increase roation angle from [-15, 15] to [-30, 30] -+ - scale range is now (0.7, 1.4), was (0.85, 1.25) -+ - we don't do elastic deformation anymore -+ -+ :return: -+ """ -+ -+ self.deep_supervision_scales = [[1, 1, 1]] + list(list(i) for i in 1 / np.cumprod( -+ np.vstack(self.net_num_pool_op_kernel_sizes), axis=0))[:-1] -+ -+ if self.threeD: -+ self.data_aug_params = default_3D_augmentation_params -+ self.data_aug_params['rotation_x'] = (-30. / 360 * 2. * np.pi, 30. / 360 * 2. * np.pi) -+ self.data_aug_params['rotation_y'] = (-30. / 360 * 2. * np.pi, 30. / 360 * 2. * np.pi) -+ self.data_aug_params['rotation_z'] = (-30. / 360 * 2. * np.pi, 30. / 360 * 2. * np.pi) -+ if self.do_dummy_2D_aug: -+ self.data_aug_params["dummy_2D"] = True -+ self.print_to_log_file("Using dummy2d data augmentation") -+ self.data_aug_params["elastic_deform_alpha"] = \ -+ default_2D_augmentation_params["elastic_deform_alpha"] -+ self.data_aug_params["elastic_deform_sigma"] = \ -+ default_2D_augmentation_params["elastic_deform_sigma"] -+ self.data_aug_params["rotation_x"] = default_2D_augmentation_params["rotation_x"] -+ else: -+ self.do_dummy_2D_aug = False -+ if max(self.patch_size) / min(self.patch_size) > 1.5: -+ default_2D_augmentation_params['rotation_x'] = (-15. / 360 * 2. * np.pi, 15. / 360 * 2. * np.pi) -+ self.data_aug_params = default_2D_augmentation_params -+ self.data_aug_params["mask_was_used_for_normalization"] = self.use_mask_for_norm -+ -+ if self.do_dummy_2D_aug: -+ self.basic_generator_patch_size = get_patch_size(self.patch_size[1:], -+ self.data_aug_params['rotation_x'], -+ self.data_aug_params['rotation_y'], -+ self.data_aug_params['rotation_z'], -+ self.data_aug_params['scale_range']) -+ self.basic_generator_patch_size = np.array([self.patch_size[0]] + list(self.basic_generator_patch_size)) -+ patch_size_for_spatialtransform = self.patch_size[1:] -+ else: -+ self.basic_generator_patch_size = get_patch_size(self.patch_size, self.data_aug_params['rotation_x'], -+ self.data_aug_params['rotation_y'], -+ self.data_aug_params['rotation_z'], -+ self.data_aug_params['scale_range']) -+ patch_size_for_spatialtransform = self.patch_size -+ -+ self.data_aug_params["scale_range"] = (0.7, 1.4) -+ self.data_aug_params["do_elastic"] = False -+ self.data_aug_params['selected_seg_channels'] = [0] -+ self.data_aug_params['patch_size_for_spatialtransform'] = patch_size_for_spatialtransform -+ -+ self.data_aug_params["num_cached_per_thread"] = 2 -+ -+ def maybe_update_lr(self, epoch=None): -+ """ -+ if epoch is not None we overwrite epoch. Else we use epoch = self.epoch + 1 -+ -+ (maybe_update_lr is called in on_epoch_end which is called before epoch is incremented. -+ herefore we need to do +1 here) -+ -+ :param epoch: -+ :return: -+ """ -+ if epoch is None: -+ ep = self.epoch + 1 -+ else: -+ ep = epoch -+ self.optimizer.param_groups[0]['lr'] = poly_lr(ep, self.max_num_epochs, self.initial_lr, 0.9) -+ self.print_to_log_file("lr:", np.round(self.optimizer.param_groups[0]['lr'], decimals=6)) -+ -+ def on_epoch_end(self): -+ """ -+ overwrite patient-based early stopping. Always run to 1000 epochs -+ :return: -+ """ -+ super().on_epoch_end() -+ continue_training = self.epoch < self.max_num_epochs -+ -+ # it can rarely happen that the momentum of nnUNetTrainerV2_plus is too high for some dataset. If at epoch 100 the -+ # estimated validation Dice is still 0 then we reduce the momentum from 0.99 to 0.95 -+ if self.epoch == 100: -+ if self.all_val_eval_metrics[-1] == 0: -+ self.optimizer.param_groups[0]["momentum"] = 0.95 -+ self.network.apply(InitWeights_He(1e-2)) -+ self.print_to_log_file("At epoch 100, the mean foreground Dice was 0. This can be caused by a too " -+ "high momentum. High momentum (0.99) is good for datasets where it works, but " -+ "sometimes causes issues such as this one. Momentum has now been reduced to " -+ "0.95 and network weights have been reinitialized") -+ return continue_training -+ -+ def save_checkpoint(self, fname, save_optimizer=True): -+ if self.local_rank == 0: -+ super().save_checkpoint(fname, save_optimizer) -+ -+ def plot_progress(self): -+ if self.local_rank == 0: -+ super().plot_progress() -+ -+ def print_to_log_file(self, *args, also_print_to_console=True): -+ if self.local_rank == 0: -+ super().print_to_log_file(*args, also_print_to_console=also_print_to_console) -+ -+ def run_training(self): -+ """ -+ if we run with -c then we need to set the correct lr for the first epoch, otherwise it will run the first -+ continued epoch with self.initial_lr -+ -+ we also need to make sure deep supervision in the network is enabled for training, thus the wrapper -+ :return: -+ """ -+ self.maybe_update_lr(self.epoch) # if we dont overwrite epoch then self.epoch+1 is used which is not what we -+ # want at the start of the training -+ if isinstance(self.network, DDP): -+ net = self.network.module -+ else: -+ net = self.network -+ ds = net.do_ds -+ net.do_ds = True -+ ret = super().run_training() -+ net.do_ds = ds -+ return ret ++ def print_to_log_file(self, *args, also_print_to_console=True): ++ if self.local_rank == 0: ++ super().print_to_log_file(*args, also_print_to_console=also_print_to_console) ++ ++ def run_training(self): ++ """ ++ if we run with -c then we need to set the correct lr for the first epoch, otherwise it will run the first ++ continued epoch with self.initial_lr ++ ++ we also need to make sure deep supervision in the network is enabled for training, thus the wrapper ++ :return: ++ """ ++ self.maybe_update_lr(self.epoch) # if we dont overwrite epoch then self.epoch+1 is used which is not what we ++ # want at the start of the training ++ if isinstance(self.network, DDP): ++ net = self.network.module ++ else: ++ net = self.network ++ ds = net.do_ds ++ net.do_ds = True ++ ret = super().run_training() ++ net.do_ds = ds ++ return ret diff --git a/pytorch/nnunet/training/network_training/nnUNetPlusPlusTrainerV2_hypDDP.py b/pytorch/nnunet/training/network_training/nnUNetPlusPlusTrainerV2_hypDDP.py new file mode 100644 index 0000000..aab27fe @@ -4219,11 +4219,11 @@ index 0000000..0abb8d5 --- /dev/null +++ b/pytorch/run.sh @@ -0,0 +1,5 @@ -+python nnunet/run/run_training.py 3d_fullres nnUNetPlusPlusTrainerV2_DDP Task003_Liver 0 -+ -+ -+python -m torch.distributed.launch --nproc_per_node 2 nnunet/run/run_training_DDP.py 3d_fullres nnUNetPlusPlusTrainerV2_DDP Task003_Liver 0 -+ ++python nnunet/run/run_training.py 3d_fullres nnUNetPlusPlusTrainerV2_DDP Task003_Liver 0 ++ ++ ++python -m torch.distributed.launch --nproc_per_node 2 nnunet/run/run_training_DDP.py 3d_fullres nnUNetPlusPlusTrainerV2_DDP Task003_Liver 0 ++ diff --git a/pytorch/setup.py b/pytorch/setup.py index 590a453..554f4e2 100644 --- a/pytorch/setup.py diff --git a/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/LICENSE b/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/LICENSE +++ b/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/README.md b/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/README.md index 79d756e61d..6991aba00b 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/README.md +++ b/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/README.md @@ -1,83 +1,83 @@ -# DeeplabV3 模型PyTorch离线推理指导 -## 推理 -### 环境配置 -```shell -pip install -r requirements.txt -pip install mmcv-full==1.3.15 -git clone https://github.com/open-mmlab/mmsegmentation.git -cd mmsegmentation -git checkout fa1554f1aaea9a2c58249b06e1ea48420091464d -pip install -e . -cd .. -``` - - -### 转ONNX -[下载权重](https://github.com/open-mmlab/mmsegmentation/tree/master/configs/deeplabv3) - -* README.md文件中配置第一行最后一列model - -#### 转onnx - -```shell -python mmsegmentation/tools/pytorch2onnx.py \ -mmsegmentation/configs/deeplabv3/deeplabv3_r50-d8_512x1024_40k_cityscapes.py \ ---checkpoint ./deeplabv3_r50-d8_512x1024_40k_cityscapes_20200605_022449-acadc2f8.pth \ ---output-file deeplabv3.onnx --shape 1024 2048 -``` - -#### 使用onnx-simplifier简化onnx - -```python -python -m onnxsim deeplabv3.onnx deeplabv3_sim_bs1.onnx --input-shape="1,3,1024,2048" --dynamic-input-shape -``` - -### 转OM - -```shell -source env_npu.sh -atc --framework=5 --model=deeplabv3_sim_bs1.onnx --output=deeplabv3_bs1 --input_format=NCHW \ ---input_shape="input:1,3,1024,2048" --log=debug --soc_version=Ascend310 --auto_tune_mode="RL,GA" -``` - - -### 数据预处理 -#### 前处理处理脚本 ./deeplabv3_torch_preprocess.py - -```shell -python ./deeplabv3_torch_preprocess.py /opt/npu/cityscapes/leftImg8bit/val ./prep_dataset -``` -读取./data/citiscapes/gtFine/val下的500张用于验证的图片,处理后保存为bin格式 - - -#### 获取数据集信息文件 - -```shell -python ./gen_dataset_info.py bin ./prep_dataset ./deeplabv3_prep_bin.info 1024 2048 -``` - -### 离线推理 - -将benchmark.x86_64放到目录 - -```shell -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=deeplabv3_bs1.om \ --input_text_path=./deeplabv3_prep_bin.info \ --input_width=1024 \ --input_height=2048 \ --output_binary=True \ --useDvpp=False -``` - -### 数据后处理 - -```shell -python ./deeplabv3_torch_postprocess.py --output_path=./result/dumpOutput_device0 --gt_path=/opt/npu/cityscapes/gtFine/val -``` - - -### 评测结果 - -| 模型 | 官网精度 | 310精度 | T4性能 | 310性能 | -| ---------- | --------------------- | -------------| --------- | --------- | +# DeeplabV3 模型PyTorch离线推理指导 +## 推理 +### 环境配置 +```shell +pip install -r requirements.txt +pip install mmcv-full==1.3.15 +git clone https://github.com/open-mmlab/mmsegmentation.git +cd mmsegmentation +git checkout fa1554f1aaea9a2c58249b06e1ea48420091464d +pip install -e . +cd .. +``` + + +### 转ONNX +[下载权重](https://github.com/open-mmlab/mmsegmentation/tree/master/configs/deeplabv3) + +* README.md文件中配置第一行最后一列model + +#### 转onnx + +```shell +python mmsegmentation/tools/pytorch2onnx.py \ +mmsegmentation/configs/deeplabv3/deeplabv3_r50-d8_512x1024_40k_cityscapes.py \ +--checkpoint ./deeplabv3_r50-d8_512x1024_40k_cityscapes_20200605_022449-acadc2f8.pth \ +--output-file deeplabv3.onnx --shape 1024 2048 +``` + +#### 使用onnx-simplifier简化onnx + +```python +python -m onnxsim deeplabv3.onnx deeplabv3_sim_bs1.onnx --input-shape="1,3,1024,2048" --dynamic-input-shape +``` + +### 转OM + +```shell +source env_npu.sh +atc --framework=5 --model=deeplabv3_sim_bs1.onnx --output=deeplabv3_bs1 --input_format=NCHW \ +--input_shape="input:1,3,1024,2048" --log=debug --soc_version=Ascend310 --auto_tune_mode="RL,GA" +``` + + +### 数据预处理 +#### 前处理处理脚本 ./deeplabv3_torch_preprocess.py + +```shell +python ./deeplabv3_torch_preprocess.py /opt/npu/cityscapes/leftImg8bit/val ./prep_dataset +``` +读取./data/citiscapes/gtFine/val下的500张用于验证的图片,处理后保存为bin格式 + + +#### 获取数据集信息文件 + +```shell +python ./gen_dataset_info.py bin ./prep_dataset ./deeplabv3_prep_bin.info 1024 2048 +``` + +### 离线推理 + +将benchmark.x86_64放到目录 + +```shell +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=deeplabv3_bs1.om \ +-input_text_path=./deeplabv3_prep_bin.info \ +-input_width=1024 \ +-input_height=2048 \ +-output_binary=True \ +-useDvpp=False +``` + +### 数据后处理 + +```shell +python ./deeplabv3_torch_postprocess.py --output_path=./result/dumpOutput_device0 --gt_path=/opt/npu/cityscapes/gtFine/val +``` + + +### 评测结果 + +| 模型 | 官网精度 | 310精度 | T4性能 | 310性能 | +| ---------- | --------------------- | -------------| --------- | --------- | | deeplabv3_bs1 | mIoU 79.09 | mIoU 79.06 | 5.7787FPS | 3.1675FPS | \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/deeplabv3_torch_postprocess.py b/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/deeplabv3_torch_postprocess.py index f5f2c83522..1b818b8cca 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/deeplabv3_torch_postprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/deeplabv3_torch_postprocess.py @@ -1,230 +1,230 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 numpy as np -import torch -import argparse -import os -from PIL import Image - - -class GTFineFile(object): - """ - directory: path to gtFine - suffix: suffix of the gtFine - :return path List of gtFine files - """ - def __init__(self, directory, suffix='_gtFine_labelTrainIds.png'): - gtFine_list = [] - for root, sub_dirs, files in os.walk(directory): - for special_file in files: - if special_file.endswith(suffix): - gtFine_list.append(os.path.join(root, special_file)) - self.gtFine_list = gtFine_list - - def get_file(self, filename): - """ return file path list """ - for file in self.gtFine_list: - if file.endswith(filename): - return file - - -def intersect_and_union(pred_label, - label, - num_classes, - ignore_index, - label_map=dict(), - reduce_zero_label=False): - """Calculate intersection and Union. - - Args: - pred_label (ndarray | str): Prediction segmentation map - or predict result filename. - label (ndarray): Ground truth segmentation map. - num_classes (int): Number of categories. - ignore_index (int): Index that will be ignored in evaluation. - label_map (dict): Mapping old labels to new labels. The parameter will - work only when label is str. Default: dict(). - reduce_zero_label (bool): Wether ignore zero label. The parameter will - work only when label is str. Default: False. - - Returns: - torch.Tensor: The intersection of prediction and ground truth - histogram on all classes. - torch.Tensor: The union of prediction and ground truth histogram on - all classes. - torch.Tensor: The prediction histogram on all classes. - torch.Tensor: The ground truth histogram on all classes. - """ - - if isinstance(pred_label, str): - pred_label = torch.from_numpy(np.load(pred_label)) - else: - pred_label = torch.from_numpy((pred_label)) - - label = torch.from_numpy(label) - - if label_map is not None: - for old_id, new_id in label_map.items(): - label[label == old_id] = new_id - if reduce_zero_label: - label[label == 0] = 255 - label = label - 1 - label[label == 254] = 255 - - mask = (label != ignore_index) - pred_label = pred_label[mask] - label = label[mask] - - intersect = pred_label[pred_label == label] - area_intersect = torch.histc( - intersect.float(), bins=(num_classes), min=0, max=num_classes - 1) - area_pred_label = torch.histc( - pred_label.float(), bins=(num_classes), min=0, max=num_classes - 1) - area_label = torch.histc( - label.float(), bins=(num_classes), min=0, max=num_classes - 1) - area_union = area_pred_label + area_label - area_intersect - return [area_intersect, area_union, area_pred_label, area_label] - - -class IntersectAndUnion(object): - """Calculate Total Intersection and Union. - - Args: - results (list[ndarray] | list[str]): List of prediction segmentation - maps or list of prediction result filenames. - gt_seg_maps (list[ndarray] | list[str]): list of ground truth - segmentation maps or list of label filenames. - num_classes (int): Number of categories. - ignore_index (int): Index that will be ignored in evaluation. - label_map (dict): Mapping old labels to new labels. Default: dict(). - reduce_zero_label (bool): Wether ignore zero label. Default: False. - - Returns: - iou - acc - """ - - def __init__(self, num_classes, ignore_index, label_map=dict(), reduce_zero_label=False): - self.num_classes = num_classes - self.ignore_index = ignore_index - self.label_map = label_map - self.reduce_zero_label = reduce_zero_label - self.total_area_intersect = torch.zeros((num_classes,), dtype=torch.float64) - self.total_area_union = torch.zeros((num_classes,), dtype=torch.float64) - self.total_area_pred_label = torch.zeros((num_classes,), dtype=torch.float64) - self.total_area_label = torch.zeros((num_classes,), dtype=torch.float64) - - def update(self, output, gt_seg_map): - """ update """ - [area_intersect, area_union, area_pred_label, area_label] = \ - intersect_and_union( - output, gt_seg_map, self.num_classes, self.ignore_index, - self.label_map, self.reduce_zero_label) - self.total_area_intersect += area_intersect.to(torch.float64) - self.total_area_union += area_union.to(torch.float64) - self.total_area_pred_label += area_pred_label.to(torch.float64) - self.total_area_label += area_label.to(torch.float64) - - def get(self): - """ get result """ - iou = self.total_area_intersect / self.total_area_union - acc = self.total_area_intersect / self.total_area_label - all_acc = self.total_area_intersect.sum() / self.total_area_label.sum() - mIoU = np.round(np.nanmean(iou) * 100, 2) - aAcc = np.round(np.nanmean(all_acc) * 100, 2) - return {'aAcc': aAcc, 'mIoU': mIoU} - - -def eval_metrics(output_path, - gt_path, - out_suffix='_leftImg8bit_1.bin', - gt_suffix='_gtFine_labelTrainIds.png', - result_path='./postprocess_result', - num_classes=19, - ignore_index=255, - label_map=None, - reduce_zero_label=False): - """Calculate evaluation metrics - Args: - results (list[ndarray] | list[str]): List of prediction segmentation - maps or list of prediction result filenames. - gt_seg_maps (list[ndarray] | list[str]): list of ground truth - segmentation maps or list of label filenames. - num_classes (int): Number of categories. - ignore_index (int): Index that will be ignored in evaluation. - metrics (list[str] | str): Metrics to be evaluated, 'mIoU' and 'mDice'. - nan_to_num (int, optional): If specified, NaN values will be replaced - by the numbers defined by the user. Default: None. - label_map (dict): Mapping old labels to new labels. Default: dict(). - reduce_zero_label (bool): Wether ignore zero label. Default: False. - Returns: - float: Overall accuracy on all images. - ndarray: Per category accuracy, shape (num_classes, ). - ndarray: Per category evaluation metrics, shape (num_classes, ). - """ - - # init metric - metric = IntersectAndUnion(num_classes, ignore_index, label_map, reduce_zero_label) - # init gtFine files list - fileFinder = GTFineFile(gt_path) - - for root, sub_dirs, files in os.walk(output_path): - files = [file for file in files if file.endswith('bin')] - len = str(files.__len__()) - for i, output_name in enumerate(files): - if not output_name.endswith('bin'): - continue - print('DeeplabV3 metric [' + str(i + 1) + '/' + len + '] on process: ' + output_name) - seg_map_name = output_name.replace(out_suffix, gt_suffix) - seg_map_path = fileFinder.get_file(seg_map_name) - if seg_map_name is not None: - seg_map = Image.open(seg_map_path) - seg_map = np.array(seg_map, dtype=np.uint8) - - output_path = os.path.realpath(os.path.join(root, output_name)) - output = np.fromfile(output_path, dtype=np.uint64).reshape(1024, 2048) - output = output.astype(np.uint8) - metric.update(output, seg_map) - else: - print("[ERROR] " + seg_map_name + " not find, check the file or make sure --out_suffix") - - # get result - result = metric.get() - print(result) - with open(result_path + '.txt', 'w') as f: - f.write('aAcc: {}\n'.format(result['aAcc'])) - f.write('mIoU: {}\n'.format(result['mIoU'])) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser('mIoU calculate') - parser.add_argument('--output_path', default="./result", - help='path to om/onnx output file, default ./result') - parser.add_argument('--gt_path', default="/opt/npu/cityscapes/gtFine/val", - help='path to gtFine/val, default /opt/npu/cityscapes/gtFine/val') - parser.add_argument('--out_suffix', default="_leftImg8bit_1.bin", - help='suffix of the om/onnx output, default "_leftImg8bit_1.bin"') - parser.add_argument('--result_path', default="./postprocess_result", - help='path to save the script result, default ./postprocess_result.txt') - - args = parser.parse_args() - - output_path = os.path.realpath(args.output_path) - gt_path = os.path.realpath(args.gt_path) - out_suffix = args.out_suffix - result_path = os.path.realpath(args.result_path) - print(output_path) - print(gt_path) - eval_metrics(output_path, gt_path, out_suffix=out_suffix, result_path=result_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 numpy as np +import torch +import argparse +import os +from PIL import Image + + +class GTFineFile(object): + """ + directory: path to gtFine + suffix: suffix of the gtFine + :return path List of gtFine files + """ + def __init__(self, directory, suffix='_gtFine_labelTrainIds.png'): + gtFine_list = [] + for root, sub_dirs, files in os.walk(directory): + for special_file in files: + if special_file.endswith(suffix): + gtFine_list.append(os.path.join(root, special_file)) + self.gtFine_list = gtFine_list + + def get_file(self, filename): + """ return file path list """ + for file in self.gtFine_list: + if file.endswith(filename): + return file + + +def intersect_and_union(pred_label, + label, + num_classes, + ignore_index, + label_map=dict(), + reduce_zero_label=False): + """Calculate intersection and Union. + + Args: + pred_label (ndarray | str): Prediction segmentation map + or predict result filename. + label (ndarray): Ground truth segmentation map. + num_classes (int): Number of categories. + ignore_index (int): Index that will be ignored in evaluation. + label_map (dict): Mapping old labels to new labels. The parameter will + work only when label is str. Default: dict(). + reduce_zero_label (bool): Wether ignore zero label. The parameter will + work only when label is str. Default: False. + + Returns: + torch.Tensor: The intersection of prediction and ground truth + histogram on all classes. + torch.Tensor: The union of prediction and ground truth histogram on + all classes. + torch.Tensor: The prediction histogram on all classes. + torch.Tensor: The ground truth histogram on all classes. + """ + + if isinstance(pred_label, str): + pred_label = torch.from_numpy(np.load(pred_label)) + else: + pred_label = torch.from_numpy((pred_label)) + + label = torch.from_numpy(label) + + if label_map is not None: + for old_id, new_id in label_map.items(): + label[label == old_id] = new_id + if reduce_zero_label: + label[label == 0] = 255 + label = label - 1 + label[label == 254] = 255 + + mask = (label != ignore_index) + pred_label = pred_label[mask] + label = label[mask] + + intersect = pred_label[pred_label == label] + area_intersect = torch.histc( + intersect.float(), bins=(num_classes), min=0, max=num_classes - 1) + area_pred_label = torch.histc( + pred_label.float(), bins=(num_classes), min=0, max=num_classes - 1) + area_label = torch.histc( + label.float(), bins=(num_classes), min=0, max=num_classes - 1) + area_union = area_pred_label + area_label - area_intersect + return [area_intersect, area_union, area_pred_label, area_label] + + +class IntersectAndUnion(object): + """Calculate Total Intersection and Union. + + Args: + results (list[ndarray] | list[str]): List of prediction segmentation + maps or list of prediction result filenames. + gt_seg_maps (list[ndarray] | list[str]): list of ground truth + segmentation maps or list of label filenames. + num_classes (int): Number of categories. + ignore_index (int): Index that will be ignored in evaluation. + label_map (dict): Mapping old labels to new labels. Default: dict(). + reduce_zero_label (bool): Wether ignore zero label. Default: False. + + Returns: + iou + acc + """ + + def __init__(self, num_classes, ignore_index, label_map=dict(), reduce_zero_label=False): + self.num_classes = num_classes + self.ignore_index = ignore_index + self.label_map = label_map + self.reduce_zero_label = reduce_zero_label + self.total_area_intersect = torch.zeros((num_classes,), dtype=torch.float64) + self.total_area_union = torch.zeros((num_classes,), dtype=torch.float64) + self.total_area_pred_label = torch.zeros((num_classes,), dtype=torch.float64) + self.total_area_label = torch.zeros((num_classes,), dtype=torch.float64) + + def update(self, output, gt_seg_map): + """ update """ + [area_intersect, area_union, area_pred_label, area_label] = \ + intersect_and_union( + output, gt_seg_map, self.num_classes, self.ignore_index, + self.label_map, self.reduce_zero_label) + self.total_area_intersect += area_intersect.to(torch.float64) + self.total_area_union += area_union.to(torch.float64) + self.total_area_pred_label += area_pred_label.to(torch.float64) + self.total_area_label += area_label.to(torch.float64) + + def get(self): + """ get result """ + iou = self.total_area_intersect / self.total_area_union + acc = self.total_area_intersect / self.total_area_label + all_acc = self.total_area_intersect.sum() / self.total_area_label.sum() + mIoU = np.round(np.nanmean(iou) * 100, 2) + aAcc = np.round(np.nanmean(all_acc) * 100, 2) + return {'aAcc': aAcc, 'mIoU': mIoU} + + +def eval_metrics(output_path, + gt_path, + out_suffix='_leftImg8bit_1.bin', + gt_suffix='_gtFine_labelTrainIds.png', + result_path='./postprocess_result', + num_classes=19, + ignore_index=255, + label_map=None, + reduce_zero_label=False): + """Calculate evaluation metrics + Args: + results (list[ndarray] | list[str]): List of prediction segmentation + maps or list of prediction result filenames. + gt_seg_maps (list[ndarray] | list[str]): list of ground truth + segmentation maps or list of label filenames. + num_classes (int): Number of categories. + ignore_index (int): Index that will be ignored in evaluation. + metrics (list[str] | str): Metrics to be evaluated, 'mIoU' and 'mDice'. + nan_to_num (int, optional): If specified, NaN values will be replaced + by the numbers defined by the user. Default: None. + label_map (dict): Mapping old labels to new labels. Default: dict(). + reduce_zero_label (bool): Wether ignore zero label. Default: False. + Returns: + float: Overall accuracy on all images. + ndarray: Per category accuracy, shape (num_classes, ). + ndarray: Per category evaluation metrics, shape (num_classes, ). + """ + + # init metric + metric = IntersectAndUnion(num_classes, ignore_index, label_map, reduce_zero_label) + # init gtFine files list + fileFinder = GTFineFile(gt_path) + + for root, sub_dirs, files in os.walk(output_path): + files = [file for file in files if file.endswith('bin')] + len = str(files.__len__()) + for i, output_name in enumerate(files): + if not output_name.endswith('bin'): + continue + print('DeeplabV3 metric [' + str(i + 1) + '/' + len + '] on process: ' + output_name) + seg_map_name = output_name.replace(out_suffix, gt_suffix) + seg_map_path = fileFinder.get_file(seg_map_name) + if seg_map_name is not None: + seg_map = Image.open(seg_map_path) + seg_map = np.array(seg_map, dtype=np.uint8) + + output_path = os.path.realpath(os.path.join(root, output_name)) + output = np.fromfile(output_path, dtype=np.uint64).reshape(1024, 2048) + output = output.astype(np.uint8) + metric.update(output, seg_map) + else: + print("[ERROR] " + seg_map_name + " not find, check the file or make sure --out_suffix") + + # get result + result = metric.get() + print(result) + with open(result_path + '.txt', 'w') as f: + f.write('aAcc: {}\n'.format(result['aAcc'])) + f.write('mIoU: {}\n'.format(result['mIoU'])) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser('mIoU calculate') + parser.add_argument('--output_path', default="./result", + help='path to om/onnx output file, default ./result') + parser.add_argument('--gt_path', default="/opt/npu/cityscapes/gtFine/val", + help='path to gtFine/val, default /opt/npu/cityscapes/gtFine/val') + parser.add_argument('--out_suffix', default="_leftImg8bit_1.bin", + help='suffix of the om/onnx output, default "_leftImg8bit_1.bin"') + parser.add_argument('--result_path', default="./postprocess_result", + help='path to save the script result, default ./postprocess_result.txt') + + args = parser.parse_args() + + output_path = os.path.realpath(args.output_path) + gt_path = os.path.realpath(args.gt_path) + out_suffix = args.out_suffix + result_path = os.path.realpath(args.result_path) + print(output_path) + print(gt_path) + eval_metrics(output_path, gt_path, out_suffix=out_suffix, result_path=result_path) diff --git a/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/deeplabv3_torch_preprocess.py b/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/deeplabv3_torch_preprocess.py index d722f4d333..d3a41c0d44 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/deeplabv3_torch_preprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/deeplabv3_torch_preprocess.py @@ -1,88 +1,88 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import os -import cv2 -import numpy as np -from torchvision import transforms - - -class Normalize(object): - def __init__(self, mean, std, to_rgb=True): - self.mean = np.array(mean, dtype=np.float32) - self.std = np.array(std, dtype=np.float32) - self.to_rgb = to_rgb - - def __call__(self, img): - img = img.copy().astype(np.float32) - # cv2 inplace normalization does not accept uint8 - assert img.dtype != np.uint8 - mean = np.float64(self.mean.reshape(1, -1)) - stdinv = 1 / np.float64(self.std.reshape(1, -1)) - if self.to_rgb: - cv2.cvtColor(img, cv2.COLOR_BGR2RGB, img) # inplace - cv2.subtract(img, mean, img) # inplace - cv2.multiply(img, stdinv, img) # inplace - return img - - -def preprocess(src_path, save_path): - """ - resnet50 pytorch preprocess - """ - preprocess = transforms.Compose([ - Normalize(mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True), - transforms.ToTensor(), - ]) - - root = src_path - - # 扫描文件夹下所有文件 - def _scandir(dir_path, suffix, recursive): - for entry in os.scandir(dir_path): - if not entry.name.startswith('.') and entry.is_file(): - rel_path = os.path.relpath(entry.path, root) - if suffix is None or rel_path.endswith(suffix): - yield rel_path - elif recursive and os.path.isdir(entry.path): - # scan recursively if entry.path is a directory - yield from _scandir( - entry.path, suffix=suffix, recursive=recursive) - - in_files = _scandir(src_path, '_leftImg8bit.png', True) - if not os.path.exists(save_path): - os.makedirs(save_path) - - i = 0 - for file in in_files: - i = i + 1 - print(file, "====", i) - input_image = cv2.imread(src_path + '/' + file) - input_tensor = preprocess(input_image) - # print(file.split('/')[-1].split('.')[0]) - # print(input_tensor) - img = np.array(input_tensor).astype(np.float32) - # print(img.shape) - img.tofile(os.path.join(save_path, file.split('/')[-1].split('.')[0] + ".bin")) - - -if __name__ == '__main__': - if len(sys.argv) < 3: - raise Exception("usage: python3 xxx.py [src_path] [save_path]") - src_path = sys.argv[1] - save_path = sys.argv[2] - src_path = os.path.realpath(src_path) - save_path = os.path.realpath(save_path) - preprocess(src_path, save_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import os +import cv2 +import numpy as np +from torchvision import transforms + + +class Normalize(object): + def __init__(self, mean, std, to_rgb=True): + self.mean = np.array(mean, dtype=np.float32) + self.std = np.array(std, dtype=np.float32) + self.to_rgb = to_rgb + + def __call__(self, img): + img = img.copy().astype(np.float32) + # cv2 inplace normalization does not accept uint8 + assert img.dtype != np.uint8 + mean = np.float64(self.mean.reshape(1, -1)) + stdinv = 1 / np.float64(self.std.reshape(1, -1)) + if self.to_rgb: + cv2.cvtColor(img, cv2.COLOR_BGR2RGB, img) # inplace + cv2.subtract(img, mean, img) # inplace + cv2.multiply(img, stdinv, img) # inplace + return img + + +def preprocess(src_path, save_path): + """ + resnet50 pytorch preprocess + """ + preprocess = transforms.Compose([ + Normalize(mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True), + transforms.ToTensor(), + ]) + + root = src_path + + # 扫描文件夹下所有文件 + def _scandir(dir_path, suffix, recursive): + for entry in os.scandir(dir_path): + if not entry.name.startswith('.') and entry.is_file(): + rel_path = os.path.relpath(entry.path, root) + if suffix is None or rel_path.endswith(suffix): + yield rel_path + elif recursive and os.path.isdir(entry.path): + # scan recursively if entry.path is a directory + yield from _scandir( + entry.path, suffix=suffix, recursive=recursive) + + in_files = _scandir(src_path, '_leftImg8bit.png', True) + if not os.path.exists(save_path): + os.makedirs(save_path) + + i = 0 + for file in in_files: + i = i + 1 + print(file, "====", i) + input_image = cv2.imread(src_path + '/' + file) + input_tensor = preprocess(input_image) + # print(file.split('/')[-1].split('.')[0]) + # print(input_tensor) + img = np.array(input_tensor).astype(np.float32) + # print(img.shape) + img.tofile(os.path.join(save_path, file.split('/')[-1].split('.')[0] + ".bin")) + + +if __name__ == '__main__': + if len(sys.argv) < 3: + raise Exception("usage: python3 xxx.py [src_path] [save_path]") + src_path = sys.argv[1] + save_path = sys.argv[2] + src_path = os.path.realpath(src_path) + save_path = os.path.realpath(save_path) + preprocess(src_path, save_path) diff --git a/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/gen_dataset_info.py index 11c25ce915..4f9793db1a 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/gen_dataset_info.py @@ -1,74 +1,74 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - """ - @description: get given bin information - @param file_path bin file path - @param info_name given information name - @param width image width - @param height image height - @return - """ - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - """ - @description: get given jpg information - @param file_path jpg file path - @param info_name given jpg information name - @return - """ - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' - get_jpg_info(file_path, info_name) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + """ + @description: get given bin information + @param file_path bin file path + @param info_name given information name + @param width image width + @param height image height + @return + """ + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + """ + @description: get given jpg information + @param file_path jpg file path + @param info_name given jpg information name + @return + """ + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' + get_jpg_info(file_path, info_name) diff --git a/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/modelzoo_level.txt index 38700fca05..2e42553460 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/requirements.txt b/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/requirements.txt index 4ebce316a2..099a8067cd 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/requirements.txt +++ b/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/requirements.txt @@ -1,7 +1,7 @@ -torch == 1.5.0 -torchvision == 0.6.0 -onnx == 1.7.0 -onnxruntime == 1.9.0 -numpy == 1.20.3 -opencv-python == 4.5.2.54 +torch == 1.5.0 +torchvision == 0.6.0 +onnx == 1.7.0 +onnxruntime == 1.9.0 +numpy == 1.20.3 +opencv-python == 4.5.2.54 onnx-simplifier == 0.3.6 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/test/parse.py b/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/test/parse.py index a119109c5d..6d5a129328 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/test/parse.py +++ b/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3/test/parse.py @@ -1,33 +1,33 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - #tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - #print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - print(content) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + #tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + #print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + print(content) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/ENet/ENet_postprocess.py b/ACL_PyTorch/contrib/cv/segmentation/ENet/ENet_postprocess.py index dbc4cc7763..25f6980879 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/ENet/ENet_postprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/ENet/ENet_postprocess.py @@ -1,93 +1,93 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -# -*- coding: utf-8 -*- -import sys -import os - -cur_path = os.path.abspath(os.path.dirname(__file__)) -root_path = os.path.split(cur_path)[0] -sys.path.append(root_path) - -import numpy as np -import argparse - -import torch -import torch.utils.data as data - -from torchvision import transforms -from cityscapes import CitySegmentation -from score import SegmentationMetric -from distributed import * - -def get_res(res_dir): - - output = [] - with open(res_dir) as res_f: - for line in res_f: - num_list = line.split() - for num in num_list: - output.append(float(num)) - output = torch.from_numpy(np.array(output).reshape((1, 19, 480, 480))) - ''' - with open(res_dir, 'rb') as res_f: - output = np.frombuffer(res_f.read(), np.float16) - output = torch.from_numpy(output.reshape((1, 19, 480, 480))) - ''' - return output - - -def postprocess(args): - input_transform = transforms.Compose([ - transforms.ToTensor(), - transforms.Normalize([.485, .456, .406], [.229, .224, .225]), - ]) - # dataset and dataloader - data_kwargs = {'transform': input_transform, 'base_size': 520, 'crop_size': 480} - val_dataset = CitySegmentation(root = args.src_path, split='val', mode='val', **data_kwargs) - - val_sampler = make_data_sampler(val_dataset, False, False) - val_batch_sampler = make_batch_data_sampler(val_sampler, args.batch_size) - - val_loader = data.DataLoader(dataset=val_dataset, - batch_sampler=val_batch_sampler, - num_workers=args.workers, - pin_memory=True) - - metric = SegmentationMetric(19) - for i, (image, target, filename) in enumerate(val_loader): - res_name = os.path.splitext(os.path.basename(filename[0]))[0] - res_dir = os.path.join(args.result_dir, res_name + '_1.txt') - #res_dir = os.path.join(args.result_dir, res_name + '_1.bin') - res = get_res(res_dir) - metric.update(res, target) - pixAcc, mIoU = metric.get() - print("Sample: {:d}, validation pixAcc: {:.3f}, mIoU: {:.3f}".format( - i + 1, pixAcc * 100, mIoU * 100)) - - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--src-path', type=str, required=True) - parser.add_argument('--result-dir', type=str, default='result/dumpOutput_device0') - parser.add_argument('--batch-size', type=int, default=1, metavar='N', - help='input batch size for training (default: 8)') - parser.add_argument('--workers', '-j', type=int, default=4, - metavar='N', help='dataloader threads') - args = parser.parse_args() - - postprocess(args) - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +# -*- coding: utf-8 -*- +import sys +import os + +cur_path = os.path.abspath(os.path.dirname(__file__)) +root_path = os.path.split(cur_path)[0] +sys.path.append(root_path) + +import numpy as np +import argparse + +import torch +import torch.utils.data as data + +from torchvision import transforms +from cityscapes import CitySegmentation +from score import SegmentationMetric +from distributed import * + +def get_res(res_dir): + + output = [] + with open(res_dir) as res_f: + for line in res_f: + num_list = line.split() + for num in num_list: + output.append(float(num)) + output = torch.from_numpy(np.array(output).reshape((1, 19, 480, 480))) + ''' + with open(res_dir, 'rb') as res_f: + output = np.frombuffer(res_f.read(), np.float16) + output = torch.from_numpy(output.reshape((1, 19, 480, 480))) + ''' + return output + + +def postprocess(args): + input_transform = transforms.Compose([ + transforms.ToTensor(), + transforms.Normalize([.485, .456, .406], [.229, .224, .225]), + ]) + # dataset and dataloader + data_kwargs = {'transform': input_transform, 'base_size': 520, 'crop_size': 480} + val_dataset = CitySegmentation(root = args.src_path, split='val', mode='val', **data_kwargs) + + val_sampler = make_data_sampler(val_dataset, False, False) + val_batch_sampler = make_batch_data_sampler(val_sampler, args.batch_size) + + val_loader = data.DataLoader(dataset=val_dataset, + batch_sampler=val_batch_sampler, + num_workers=args.workers, + pin_memory=True) + + metric = SegmentationMetric(19) + for i, (image, target, filename) in enumerate(val_loader): + res_name = os.path.splitext(os.path.basename(filename[0]))[0] + res_dir = os.path.join(args.result_dir, res_name + '_1.txt') + #res_dir = os.path.join(args.result_dir, res_name + '_1.bin') + res = get_res(res_dir) + metric.update(res, target) + pixAcc, mIoU = metric.get() + print("Sample: {:d}, validation pixAcc: {:.3f}, mIoU: {:.3f}".format( + i + 1, pixAcc * 100, mIoU * 100)) + + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--src-path', type=str, required=True) + parser.add_argument('--result-dir', type=str, default='result/dumpOutput_device0') + parser.add_argument('--batch-size', type=int, default=1, metavar='N', + help='input batch size for training (default: 8)') + parser.add_argument('--workers', '-j', type=int, default=4, + metavar='N', help='dataloader threads') + args = parser.parse_args() + + postprocess(args) + # python ENet_postprocess.py --src-path=/root/.torch/datasets/citys --result-dir result/dumpOutput_device0 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/ENet/ENet_preprocess.py b/ACL_PyTorch/contrib/cv/segmentation/ENet/ENet_preprocess.py index 413c310f77..02ce9a8940 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/ENet/ENet_preprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/ENet/ENet_preprocess.py @@ -1,108 +1,108 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# -*- coding: utf-8 -*- - -import argparse -import os -import sys -import numpy as np - -cur_path = os.path.abspath(os.path.dirname(__file__)) -root_path = os.path.split(cur_path)[0] -sys.path.append(root_path) - -from PIL import Image -from torchvision import transforms - - -def _val_sync_transform(img, mask): - outsize = 480 - short_size = outsize - w, h = img.size - if w > h: - oh = short_size - ow = int(1.0 * w * oh / h) - else: - ow = short_size - oh = int(1.0 * h * ow / w) - img = img.resize((ow, oh), Image.BILINEAR) - mask = mask.resize((ow, oh), Image.NEAREST) - # center crop - w, h = img.size - x1 = int(round((w - outsize) / 2.)) - y1 = int(round((h - outsize) / 2.)) - img = img.crop((x1, y1, x1 + outsize, y1 + outsize)) - mask = mask.crop((x1, y1, x1 + outsize, y1 + outsize)) - # final transform - img, mask = np.array(img), np.array(mask).astype('int32') - return img, mask - -def _get_city_pairs(folder, split='val'): - def get_path_pairs(img_folder, mask_folder): - img_paths = [] - mask_paths = [] - for root, _, files in os.walk(img_folder): - for filename in files: - if filename.endswith('.png'): - imgpath = os.path.join(root, filename) - foldername = os.path.basename(os.path.dirname(imgpath)) - maskname = filename.replace('leftImg8bit', 'gtFine_labelIds') - maskpath = os.path.join(mask_folder, foldername, maskname) - if os.path.isfile(imgpath) and os.path.isfile(maskpath): - img_paths.append(imgpath) - mask_paths.append(maskpath) - else: - print('cannot find the mask or image:', imgpath, maskpath) - print('Found {} images in the folder {}'.format(len(img_paths), img_folder)) - return img_paths, mask_paths - - if split in ('train', 'val'): - img_folder = os.path.join(folder, 'leftImg8bit/' + split) - mask_folder = os.path.join(folder, 'gtFine/' + split) - img_paths, mask_paths = get_path_pairs(img_folder, mask_folder) - return img_paths, mask_paths - -def preprocess(args): - input_transform = transforms.Compose([ - transforms.ToTensor(), - transforms.Normalize([.485, .456, .406], [.229, .224, .225]), - ]) - - images, mask_paths = _get_city_pairs(args.src_path, 'val') - - for i, image in enumerate(images): - img = Image.open(image).convert('RGB') - mask = Image.open(mask_paths[i]) - img, mask = _val_sync_transform(img, mask) - img = input_transform(img) - #img = np.asarray(img).astype(np.float16) - - img = np.asarray(img) - - filename = os.path.basename(image) - - img.tofile(os.path.join(args.save_path, os.path.splitext(filename)[0] + ".bin")) - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--src-path', type=str, required=True) - parser.add_argument('--save_path', type=str, default='prep_dataset') - - args = parser.parse_args() - - if not os.path.isdir(args.save_path): - os.makedirs(os.path.realpath(args.save_path)) - preprocess(args) - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# -*- coding: utf-8 -*- + +import argparse +import os +import sys +import numpy as np + +cur_path = os.path.abspath(os.path.dirname(__file__)) +root_path = os.path.split(cur_path)[0] +sys.path.append(root_path) + +from PIL import Image +from torchvision import transforms + + +def _val_sync_transform(img, mask): + outsize = 480 + short_size = outsize + w, h = img.size + if w > h: + oh = short_size + ow = int(1.0 * w * oh / h) + else: + ow = short_size + oh = int(1.0 * h * ow / w) + img = img.resize((ow, oh), Image.BILINEAR) + mask = mask.resize((ow, oh), Image.NEAREST) + # center crop + w, h = img.size + x1 = int(round((w - outsize) / 2.)) + y1 = int(round((h - outsize) / 2.)) + img = img.crop((x1, y1, x1 + outsize, y1 + outsize)) + mask = mask.crop((x1, y1, x1 + outsize, y1 + outsize)) + # final transform + img, mask = np.array(img), np.array(mask).astype('int32') + return img, mask + +def _get_city_pairs(folder, split='val'): + def get_path_pairs(img_folder, mask_folder): + img_paths = [] + mask_paths = [] + for root, _, files in os.walk(img_folder): + for filename in files: + if filename.endswith('.png'): + imgpath = os.path.join(root, filename) + foldername = os.path.basename(os.path.dirname(imgpath)) + maskname = filename.replace('leftImg8bit', 'gtFine_labelIds') + maskpath = os.path.join(mask_folder, foldername, maskname) + if os.path.isfile(imgpath) and os.path.isfile(maskpath): + img_paths.append(imgpath) + mask_paths.append(maskpath) + else: + print('cannot find the mask or image:', imgpath, maskpath) + print('Found {} images in the folder {}'.format(len(img_paths), img_folder)) + return img_paths, mask_paths + + if split in ('train', 'val'): + img_folder = os.path.join(folder, 'leftImg8bit/' + split) + mask_folder = os.path.join(folder, 'gtFine/' + split) + img_paths, mask_paths = get_path_pairs(img_folder, mask_folder) + return img_paths, mask_paths + +def preprocess(args): + input_transform = transforms.Compose([ + transforms.ToTensor(), + transforms.Normalize([.485, .456, .406], [.229, .224, .225]), + ]) + + images, mask_paths = _get_city_pairs(args.src_path, 'val') + + for i, image in enumerate(images): + img = Image.open(image).convert('RGB') + mask = Image.open(mask_paths[i]) + img, mask = _val_sync_transform(img, mask) + img = input_transform(img) + #img = np.asarray(img).astype(np.float16) + + img = np.asarray(img) + + filename = os.path.basename(image) + + img.tofile(os.path.join(args.save_path, os.path.splitext(filename)[0] + ".bin")) + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--src-path', type=str, required=True) + parser.add_argument('--save_path', type=str, default='prep_dataset') + + args = parser.parse_args() + + if not os.path.isdir(args.save_path): + os.makedirs(os.path.realpath(args.save_path)) + preprocess(args) + # python ENet_preprocess.py --src-path=/root/.torch/datasets/citys --save_path prep_dataset \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/ENet/ENet_pth2onnx.py b/ACL_PyTorch/contrib/cv/segmentation/ENet/ENet_pth2onnx.py index 9892c9c692..275ef0d62f 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/ENet/ENet_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/segmentation/ENet/ENet_pth2onnx.py @@ -1,83 +1,83 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# -*- coding: utf-8 -*- - -import os -import sys -import argparse - -cur_path = os.path.abspath(os.path.dirname(__file__)) -root_path = os.path.split(cur_path)[0] -sys.path.append(root_path) - -import torch -import torch.nn as nn -import torch.onnx - -from collections import OrderedDict -from enet import get_enet - - -def proc_nodes_module(checkpoint, AttrName): - new_state_dict = OrderedDict() - for k, v in checkpoint[AttrName].items(): - if (k[0:7] == "module."): - name = k[7:] - else: - name = k[0:] - new_state_dict[name] = v - return new_state_dict - -''' -def convert(pth_file_path, onnx_file_path, class_num): - checkpoint = torch.load(pth_file_path, map_location='cpu') - checkpoint['state_dict'] = proc_nodes_module(checkpoint, 'state_dict') - model = densenet121(pretrained=False, num_classes=class_num) - model.load_state_dict(checkpoint['state_dict']) - model.eval() - print(model) - - input_names = ["actual_input_1"] - output_names = ["output1"] - dummy_input = torch.randn(16, 3, 224, 224) - torch.onnx.export(model, dummy_input, onnx_file_path, input_names=input_names, output_names=output_names, - opset_version=11) -''' - -def pth2onnx(input_file, output_file, batch_size=1): - model = get_enet(model='enet', dataset='citys', aux=False, norm_layer=nn.BatchNorm2d) - checkpoint = {} - checkpoint['state_dict'] = torch.load(input_file, map_location='cpu') - checkpoint['state_dict'] = proc_nodes_module(checkpoint, 'state_dict') - model.load_state_dict(checkpoint['state_dict']) - - model.eval() - print(model) - - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.randn(batch_size, 3, 480, 480) - torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, opset_version=11, verbose=True) - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('--input-file', type=str, default='~/.torch/models/enet_citys.pth') - parser.add_argument('--output-file', type=str, default='model/enet_citys_910_bs1.onnx') - parser.add_argument('--batch-size', type=int, default=1) - args = parser.parse_args() - pth2onnx(args.input_file, args.output_file, batch_size=args.batch_size) - -# python ENet_pth2onnx.py --input-file models/enet_citys.pth --output-file models/enet_citys_910_bs1.onnx --batch-size 1 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# -*- coding: utf-8 -*- + +import os +import sys +import argparse + +cur_path = os.path.abspath(os.path.dirname(__file__)) +root_path = os.path.split(cur_path)[0] +sys.path.append(root_path) + +import torch +import torch.nn as nn +import torch.onnx + +from collections import OrderedDict +from enet import get_enet + + +def proc_nodes_module(checkpoint, AttrName): + new_state_dict = OrderedDict() + for k, v in checkpoint[AttrName].items(): + if (k[0:7] == "module."): + name = k[7:] + else: + name = k[0:] + new_state_dict[name] = v + return new_state_dict + +''' +def convert(pth_file_path, onnx_file_path, class_num): + checkpoint = torch.load(pth_file_path, map_location='cpu') + checkpoint['state_dict'] = proc_nodes_module(checkpoint, 'state_dict') + model = densenet121(pretrained=False, num_classes=class_num) + model.load_state_dict(checkpoint['state_dict']) + model.eval() + print(model) + + input_names = ["actual_input_1"] + output_names = ["output1"] + dummy_input = torch.randn(16, 3, 224, 224) + torch.onnx.export(model, dummy_input, onnx_file_path, input_names=input_names, output_names=output_names, + opset_version=11) +''' + +def pth2onnx(input_file, output_file, batch_size=1): + model = get_enet(model='enet', dataset='citys', aux=False, norm_layer=nn.BatchNorm2d) + checkpoint = {} + checkpoint['state_dict'] = torch.load(input_file, map_location='cpu') + checkpoint['state_dict'] = proc_nodes_module(checkpoint, 'state_dict') + model.load_state_dict(checkpoint['state_dict']) + + model.eval() + print(model) + + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.randn(batch_size, 3, 480, 480) + torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, opset_version=11, verbose=True) + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('--input-file', type=str, default='~/.torch/models/enet_citys.pth') + parser.add_argument('--output-file', type=str, default='model/enet_citys_910_bs1.onnx') + parser.add_argument('--batch-size', type=int, default=1) + args = parser.parse_args() + pth2onnx(args.input_file, args.output_file, batch_size=args.batch_size) + +# python ENet_pth2onnx.py --input-file models/enet_citys.pth --output-file models/enet_citys_910_bs1.onnx --batch-size 1 # python ENet_pth2onnx.py --input-file models/enet_citys.pth --output-file models/enet_citys_910_bs16.onnx --batch-size 16 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/ENet/test/parse.py b/ACL_PyTorch/contrib/cv/segmentation/ENet/test/parse.py index b9c74f41d7..82af69cd18 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/ENet/test/parse.py +++ b/ACL_PyTorch/contrib/cv/segmentation/ENet/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/LICENSE b/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/LICENSE index 7615b4e85f..72f817fb44 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/LICENSE +++ b/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/README.md b/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/README.md index 9aa8344a93..b4fa271e04 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/README.md +++ b/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/README.md @@ -1,356 +1,356 @@ -# 基于开源mmsegmentation预训练的fcn-8s Onnx模型端到端推理指导 -- [1 模型概述](#1-模型概述) - - [1.1 论文地址](#11-论文地址) - - [1.2 代码地址](#12-代码地址) -- [2 环境说明](#2-环境说明) - - [2.1 深度学习框架](#21-深度学习框架) - - [2.2 python第三方库](#22-python第三方库) -- [3 模型转换](#3-模型转换) - - [3.1 pth转onnx模型](#31-pth转onnx模型) - - [3.2 onnx转om模型](#32-onnx转om模型) -- [4 数据集预处理](#4-数据集预处理) - - [4.1 数据集获取](#41-数据集获取) - - [4.2 数据集预处理](#42-数据集预处理) - - [4.3 生成数据集信息文件](#43-生成数据集信息文件) -- [5 离线推理](#5-离线推理) - - [5.1 benchmark工具概述](#51-benchmark工具概述) - - [5.2 离线推理](#52-离线推理) -- [6 精度对比](#6-精度对比) - - [6.1 离线推理精度统计](#61-离线推理精度统计) - - [6.2 开源精度](#62-开源精度) - - [6.3 精度对比](#63-精度对比) -- [7 性能对比](#7-性能对比) - - [7.1 npu性能数据](#71-npu性能数据) - - - -## 1 模型概述 - -- **[论文地址](#11-论文地址)** - -- **[代码地址](#12-代码地址)** - -### 1.1 论文地址 -[fcn-8s论文](https://arxiv.org/abs/1411.4038) -论文提出 Fully Convolutional Networks(FCN)方法用于图像语义分割,将图像级别的分类扩展到像素级别的分类,获得 CVPR2015 的 best paper。 - - -### 1.2 代码地址 -[mmsegmentation框架fcn-8s代码](https://github.com/open-mmlab/mmsegmentation/tree/master/configs/fcn) -branch:master commit_id:e6a8791ab0a03c60c0a9abb8456cd4d804342e92 - -## 2 环境说明 - -- **[深度学习框架](#21-深度学习框架)** - -- **[python第三方库](#22-python第三方库)** - -### 2.1 深度学习框架 -``` -pytorch == 1.8.0 -torchvision == 0.9.0 -onnx == 1.9.0 -``` -**注意:** -> 转onnx的环境上pytorch需要安装1.8.0版本 - -### 2.2 python第三方库 -``` -numpy == 1.20.1 -opencv-python == 4.5.2.52 -``` - -**说明:** -> X86架构:opencv,pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:opencv,pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3 模型转换 - -- **[pth转onnx模型](#31-pth转onnx模型)** - -- **[onnx转om模型](#32-onnx转om模型)** - - -### 3.1 pth转onnx模型 - -1.获取pth权重文件 -[fcn-8s基于mmsegmentation预训练的npu权重文件](https://download.openmmlab.com/mmsegmentation/v0.5/fcn/fcn_r50-d8_512x512_20k_voc12aug/fcn_r50-d8_512x512_20k_voc12aug_20200617_010715-52dc5306.pth) -文件md5sum: 0b42f76eb2e3779a5f802acb5ded5eed - -2.mmsegmentation源码安装 -```shell -git clone https://github.com/open-mmlab/mmcv.git -cd mmcv -pip3.7 install -e . -cd .. -git clone https://github.com/open-mmlab/mmsegmentation.git -cd mmsegmentation -如果修改了模型代码,交付了{model_name}.diff -patch -p1 < ../{model_name}.diff -如果模型代码需要安装,则安装模型代码(如果没有安装脚本,pth2onnx等脚本需要引用模型代码的类或函数,可通过sys.path.append(r"./pytorch-nested-unet")添加搜索路径的方式) -pip3.7 install -e . # or "python3.7 setup.py develop" -cd .. -``` - - **说明:** -> 安装所需的依赖说明请参考mmsegmentation/docs/get_started.md - - -3.使用tools里的pytorch2onnx.py文件,运行如下命令,生成对应的onnx模型: -```shell -python3.7 mmsegmentation/tools/pytorch2onnx.py mmsegmentation/configs/fcn/fcn_r50-d8_512x512_20k_voc12aug.py --checkpoint fcn_r50-d8_512x512_20k_voc12aug_20200617_010715-52dc5306.pth --output-file fcn_r50-d8_512x512_20k_voc12aug.onnx --shape 500 500 --show -``` - **模型转换要点:** -> 虽然导出的onnx可以转换为多batch的om离线推理,但是在线推理与onnx目前还不支持多batch推理 - -### 3.2 onnx转om模型 - -1.设置环境变量 -```shell -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp -export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest/ -``` -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN 5.0.1 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373),如果存在多余输出节点,需要指定输出节点以去除无用输出,节点序号可能会因网络结构不同而不同,使用netron开源可视化工具查看具体的输出节点名: -```shell -atc --framework=5 --model=fcn_r50-d8_512x512_20k_voc12aug.onnx --output=fcn_r50-d8_512x512_20k_voc12aug_bs1 --input_format=NCHW --input_shape="input:1,3,500,500" --log=debug --soc_version=Ascend310 -``` - -## 4 数据集预处理 - -- **[数据集获取](#41-数据集获取)** - -- **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - -### 4.1 数据集获取 -该模型使用[VOC2012官网](http://host.robots.ox.ac.uk/pascal/VOC/voc2012/index.html)的VOC2012的1449张验证集进行测试,图片与对应ground truth分别存放在/opt/npu/VOCdevkit/VOC2012/JPEGImages/与/opt/npu/VOCdevkit/VOC2012/SegmentationClass/。 - -### 4.2 数据集预处理 -1.预处理脚本mmsegmentation_voc2012_preprocess.py - -2.执行预处理脚本,生成数据集预处理后的bin文件 -```shell -python3.7 mmsegmentation_voc2012_preprocess.py --image_folder_path=/opt/npu/VOCdevkit/VOC2012/JPEGImages/ --split=/opt/npu/VOCdevkit/VOC2012/ImageSets/Segmentation/val.txt --bin_folder_path=./voc12_bin/ -``` -### 4.3 生成数据集信息文件 -1.生成数据集信息文件脚本get_info.py - -2.执行生成数据集信息脚本,生成数据集信息文件 -```shell -python3.7 get_info.py bin ./voc12_bin voc12.info 500 500 -``` -第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 -## 5 离线推理 - -- **[benchmark工具概述](#51-benchmark工具概述)** - -- **[离线推理](#52-离线推理)** - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN 5.0.1 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) - -### 5.2 离线推理 - -1.设置环境变量 -```shell -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp -export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest/ -``` -2.执行离线推理 -```shell -./benchmark.${arch} -model_type=vision -om_path=fcn_r50-d8_512x512_20k_voc12aug_bs1.om -device_id=0 -batch_size=1 -input_text_path=voc12.info -input_width=500 -input_height=500 -useDvpp=false -output_binary=true -``` - **注意:** -> onnx的输出是int64,但是om的输出是int32 - -输出结果默认保存在当前目录result/dumpOutput_device0,模型有一个输出,每个输入对应的输出对应_1.bin文件 -``` -输出 shape 数据类型 数据含义 -output1 1 * 1 * 500 * 500 int32 8位图像 -``` - -## 6 精度对比 - -- **[离线推理精度](#61-离线推理精度)** -- **[开源精度](#62-开源精度)** -- **[精度对比](#63-精度对比)** - -### 6.1 离线推理精度统计 - -1.调用mmsegmentation_voc2012_postprocess.py评测bs1的mIoU精度: -```shell -python3.7 get_info.py jpg /opt/npu/VOCdevkit/VOC2012/JPEGImages/ voc12_jpg.info - -python3.7 mmsegmentation_voc2012_postprocess.py --bin_data_path=./result/dumpOutput_device0 --test_annotation=./voc12_jpg.info --img_dir=/opt/npu/VOCdevkit/VOC2012/JPEGImages --ann_dir=/opt/npu/VOCdevkit/VOC2012/SegmentationClass --split=/opt/npu/VOCdevkit/VOC2012/ImageSets/Segmentation/val.txt --net_input_width=500 --net_input_height=500 -``` -第一个参数为benchmark推理结果,第二个为原始图片信息文件,第三个为原始图片位置,第四个为验证图片位置,第五个图片的split,第六七个为网宽高 -执行完后会打印出精度: -``` -per class results: - -+-------------+-------+-------+ -| Class | IoU | Acc | -+-------------+-------+-------+ -| background | 92.84 | 97.27 | -| aeroplane | 81.0 | 90.2 | -| bicycle | 37.6 | 84.07 | -| bird | 80.3 | 87.49 | -| boat | 64.63 | 77.42 | -| bottle | 61.32 | 69.76 | -| bus | 87.31 | 91.7 | -| car | 79.48 | 89.74 | -| cat | 85.69 | 92.6 | -| chair | 30.69 | 44.66 | -| cow | 73.21 | 82.52 | -| diningtable | 43.5 | 48.95 | -| dog | 78.83 | 87.76 | -| horse | 74.5 | 82.18 | -| motorbike | 75.7 | 82.97 | -| person | 83.24 | 89.45 | -| pottedplant | 53.23 | 64.87 | -| sheep | 74.29 | 80.85 | -| sofa | 45.59 | 55.79 | -| train | 77.98 | 82.49 | -| tvmonitor | 68.21 | 74.91 | -+-------------+-------+-------+ -Summary: - -+--------+-------+-------+-------+ -| Scope | mIoU | mAcc | aAcc | -+--------+-------+-------+-------+ -| global | 69.01 | 78.94 | 93.04 | -+--------+-------+-------+-------+ - -``` - -2.调用mmsegmentation_voc2012_postprocess.py评测bs16的mIoU精度: -```shell -python3.7 get_info.py jpg /opt/npu/VOCdevkit/VOC2012/JPEGImages/ voc12_jpg.info - -python3.7 mmsegmentation_voc2012_postprocess.py --bin_data_path=./result/dumpOutput_device1 --test_annotation=./voc12_jpg.info --img_dir=/opt/npu/VOCdevkit/VOC2012/JPEGImages --ann_dir=/opt/npu/VOCdevkit/VOC2012/SegmentationClass --split=/opt/npu/VOCdevkit/VOC2012/ImageSets/Segmentation/val.txt --net_input_width=500 --net_input_height=500 -``` -第一个参数为benchmark推理结果,第二个为原始图片信息文件,第三个为原始图片位置,第四个为验证图片位置,第五个图片的split,第六七个为网宽高 -执行完后会打印出精度: -``` -per class results: - -+-------------+-------+-------+ -| Class | IoU | Acc | -+-------------+-------+-------+ -| background | 92.84 | 97.27 | -| aeroplane | 81.0 | 90.2 | -| bicycle | 37.6 | 84.07 | -| bird | 80.3 | 87.49 | -| boat | 64.63 | 77.42 | -| bottle | 61.32 | 69.76 | -| bus | 87.31 | 91.7 | -| car | 79.48 | 89.74 | -| cat | 85.69 | 92.6 | -| chair | 30.69 | 44.66 | -| cow | 73.21 | 82.52 | -| diningtable | 43.5 | 48.95 | -| dog | 78.83 | 87.76 | -| horse | 74.5 | 82.18 | -| motorbike | 75.7 | 82.97 | -| person | 83.24 | 89.45 | -| pottedplant | 53.23 | 64.87 | -| sheep | 74.29 | 80.85 | -| sofa | 45.59 | 55.79 | -| train | 77.98 | 82.49 | -| tvmonitor | 68.21 | 74.91 | -+-------------+-------+-------+ -Summary: - -+--------+-------+-------+-------+ -| Scope | mIoU | mAcc | aAcc | -+--------+-------+-------+-------+ -| global | 69.01 | 78.94 | 93.04 | -+--------+-------+-------+-------+ - -``` - **精度调试:** -> 1.在线推理前处理图片是一定格式的动态分辨率,onnx将分辨率固定为512x512会导致精度下降些。 -> 2.分辨率在512x512时onnx离线推理的精度与om精度相同,分辨率改为500x500可以提升精度,使得mask的精度与开源相比更高 -> 3.单图调试 -> ``` -> python3.7 mmsegmentation/tools/test.py mmsegmentation/configs/fcn/fcn_r50-d8_512x512_20k_voc12aug.py fcn_r50-d8_512x512_20k_voc12aug_20200617_010715-52dc5306.pth --show -> python3.7 mmsegmentation/tools/pytorch2onnx.py mmsegmentation/configs/fcn/fcn_r50-d8_512x512_20k_voc12aug.py --checkpoint fcn_r50-d8_512x512_20k_voc12aug_20200617_010715-52dc5306.pth --output-file fcn_r50-d8_512x512_20k_voc12aug.onnx --shape 500 500 --input-img 2011_003103.jpg --show --verify -> ``` - - -### 6.2 开源精度 -[官网精度](https://download.openmmlab.com/mmsegmentation/v0.5/fcn/fcn_r50-d8_512x512_20k_voc12aug/fcn_r50-d8_512x512_20k_voc12aug_20200617_010715.log.json) - -``` -{"mode": "val", "epoch": 31, "iter": 20000, "lr": 0.0001, "mIoU": 0.67085, "mAcc": 0.76958, "aAcc": 0.92709} -``` -### 6.3 精度对比 -om推理mIoU精度均为0.6901,开源mIoU精度为0.67085,om精度大于开源精度,精度达标 - - -## 7 性能对比 - -- **[npu性能数据](#71-npu性能数据)** - -### 7.1 npu性能数据 -1.benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 -由于在线推理与onnx推理还不支持多batch,所以仅测om bs1,bs16的性能。 -1.benchmark工具在整个数据集上推理获得性能数据 -batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: -``` -[e2e] throughputRate: 14.2564, latency: 101639 -[data read] throughputRate: 24.7255, moduleLatency: 40.444 -[preprocess] throughputRate: 22.102, moduleLatency: 45.2448 -[infer] throughputRate: 14.3682, Interface throughputRate: 16.2017, moduleLatency: 69.2286 -[post] throughputRate: 14.368, moduleLatency: 69.5993 -``` -Interface throughputRate: 16.2017,16.2017x4=64.8068即是batch1 310单卡吞吐率 - -batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: -``` -[[e2e] throughputRate: 13.459, latency: 107660 -[data read] throughputRate: 23.5047, moduleLatency: 42.5446 -[preprocess] throughputRate: 21.4117, moduleLatency: 46.7034 -[infer] throughputRate: 13.5517, Interface throughputRate: 15.4271, moduleLatency: 73.3405 -[post] throughputRate: 0.850975, moduleLatency: 1175.12 -``` -Interface throughputRate: 15.4271,15.4271x4=61.7084即是batch16 310单卡吞吐率 - -2.npu纯推理性能 -batch1的性能,执行20次纯推理取均值,统计吞吐率与其倒数时延(benchmark的时延是单个数据的推理时间),npu性能是一个device执行的结果 -``` -./benchmark.x86_64 -round=20 -om_path=fcn_r50-d8_512x512_20k_voc12aug_bs1.om -device_id=0 -batch_size=1 -``` -PureInfer_perf_of_fcn_r50-d8_512x512_20k_voc12aug_bs1_in_device_0.txt: -``` -[INFO] PureInfer result saved in ./result/PureInfer_perf_of_fcn_r50-d8_512x512_20k_voc12aug_bs1_in_device_0.txt ------------------PureInfer Performance Summary------------------ -[INFO] ave_throughputRate: 16.2574samples/s, ave_latency: 61.5162ms ----------------------------------------------------------------- -``` -batch16的性能,执行20次纯推理取均值,统计吞吐率与其倒数时延(benchmark的时延是单个数据的推理时间),npu性能是一个device执行的结果 -``` -./benchmark.x86_64 -round=20 -om_path=fcn_r50-d8_512x512_20k_voc12aug_bs16.om -device_id=0 -batch_size=16 -``` -PureInfer_perf_of_fcn_r50-d8_512x512_20k_voc12aug_bs16_in_device_0.txt: -``` -[INFO] PureInfer result saved in ./result/PureInfer_perf_of_fcn_r50-d8_512x512_20k_voc12aug_bs16_in_device_0.txt ------------------PureInfer Performance Summary------------------ -[INFO] ave_throughputRate: 15.5282samples/s, ave_latency: 64.4083ms ----------------------------------------------------------------- -``` - -**性能优化:** -> 没有遇到性能不达标的问题,故不需要进行性能优化 - +# 基于开源mmsegmentation预训练的fcn-8s Onnx模型端到端推理指导 +- [1 模型概述](#1-模型概述) + - [1.1 论文地址](#11-论文地址) + - [1.2 代码地址](#12-代码地址) +- [2 环境说明](#2-环境说明) + - [2.1 深度学习框架](#21-深度学习框架) + - [2.2 python第三方库](#22-python第三方库) +- [3 模型转换](#3-模型转换) + - [3.1 pth转onnx模型](#31-pth转onnx模型) + - [3.2 onnx转om模型](#32-onnx转om模型) +- [4 数据集预处理](#4-数据集预处理) + - [4.1 数据集获取](#41-数据集获取) + - [4.2 数据集预处理](#42-数据集预处理) + - [4.3 生成数据集信息文件](#43-生成数据集信息文件) +- [5 离线推理](#5-离线推理) + - [5.1 benchmark工具概述](#51-benchmark工具概述) + - [5.2 离线推理](#52-离线推理) +- [6 精度对比](#6-精度对比) + - [6.1 离线推理精度统计](#61-离线推理精度统计) + - [6.2 开源精度](#62-开源精度) + - [6.3 精度对比](#63-精度对比) +- [7 性能对比](#7-性能对比) + - [7.1 npu性能数据](#71-npu性能数据) + + + +## 1 模型概述 + +- **[论文地址](#11-论文地址)** + +- **[代码地址](#12-代码地址)** + +### 1.1 论文地址 +[fcn-8s论文](https://arxiv.org/abs/1411.4038) +论文提出 Fully Convolutional Networks(FCN)方法用于图像语义分割,将图像级别的分类扩展到像素级别的分类,获得 CVPR2015 的 best paper。 + + +### 1.2 代码地址 +[mmsegmentation框架fcn-8s代码](https://github.com/open-mmlab/mmsegmentation/tree/master/configs/fcn) +branch:master commit_id:e6a8791ab0a03c60c0a9abb8456cd4d804342e92 + +## 2 环境说明 + +- **[深度学习框架](#21-深度学习框架)** + +- **[python第三方库](#22-python第三方库)** + +### 2.1 深度学习框架 +``` +pytorch == 1.8.0 +torchvision == 0.9.0 +onnx == 1.9.0 +``` +**注意:** +> 转onnx的环境上pytorch需要安装1.8.0版本 + +### 2.2 python第三方库 +``` +numpy == 1.20.1 +opencv-python == 4.5.2.52 +``` + +**说明:** +> X86架构:opencv,pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:opencv,pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3 模型转换 + +- **[pth转onnx模型](#31-pth转onnx模型)** + +- **[onnx转om模型](#32-onnx转om模型)** + + +### 3.1 pth转onnx模型 + +1.获取pth权重文件 +[fcn-8s基于mmsegmentation预训练的npu权重文件](https://download.openmmlab.com/mmsegmentation/v0.5/fcn/fcn_r50-d8_512x512_20k_voc12aug/fcn_r50-d8_512x512_20k_voc12aug_20200617_010715-52dc5306.pth) +文件md5sum: 0b42f76eb2e3779a5f802acb5ded5eed + +2.mmsegmentation源码安装 +```shell +git clone https://github.com/open-mmlab/mmcv.git +cd mmcv +pip3.7 install -e . +cd .. +git clone https://github.com/open-mmlab/mmsegmentation.git +cd mmsegmentation +如果修改了模型代码,交付了{model_name}.diff +patch -p1 < ../{model_name}.diff +如果模型代码需要安装,则安装模型代码(如果没有安装脚本,pth2onnx等脚本需要引用模型代码的类或函数,可通过sys.path.append(r"./pytorch-nested-unet")添加搜索路径的方式) +pip3.7 install -e . # or "python3.7 setup.py develop" +cd .. +``` + + **说明:** +> 安装所需的依赖说明请参考mmsegmentation/docs/get_started.md + + +3.使用tools里的pytorch2onnx.py文件,运行如下命令,生成对应的onnx模型: +```shell +python3.7 mmsegmentation/tools/pytorch2onnx.py mmsegmentation/configs/fcn/fcn_r50-d8_512x512_20k_voc12aug.py --checkpoint fcn_r50-d8_512x512_20k_voc12aug_20200617_010715-52dc5306.pth --output-file fcn_r50-d8_512x512_20k_voc12aug.onnx --shape 500 500 --show +``` + **模型转换要点:** +> 虽然导出的onnx可以转换为多batch的om离线推理,但是在线推理与onnx目前还不支持多batch推理 + +### 3.2 onnx转om模型 + +1.设置环境变量 +```shell +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp +export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest/ +``` +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN 5.0.1 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373),如果存在多余输出节点,需要指定输出节点以去除无用输出,节点序号可能会因网络结构不同而不同,使用netron开源可视化工具查看具体的输出节点名: +```shell +atc --framework=5 --model=fcn_r50-d8_512x512_20k_voc12aug.onnx --output=fcn_r50-d8_512x512_20k_voc12aug_bs1 --input_format=NCHW --input_shape="input:1,3,500,500" --log=debug --soc_version=Ascend310 +``` + +## 4 数据集预处理 + +- **[数据集获取](#41-数据集获取)** + +- **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + +### 4.1 数据集获取 +该模型使用[VOC2012官网](http://host.robots.ox.ac.uk/pascal/VOC/voc2012/index.html)的VOC2012的1449张验证集进行测试,图片与对应ground truth分别存放在/opt/npu/VOCdevkit/VOC2012/JPEGImages/与/opt/npu/VOCdevkit/VOC2012/SegmentationClass/。 + +### 4.2 数据集预处理 +1.预处理脚本mmsegmentation_voc2012_preprocess.py + +2.执行预处理脚本,生成数据集预处理后的bin文件 +```shell +python3.7 mmsegmentation_voc2012_preprocess.py --image_folder_path=/opt/npu/VOCdevkit/VOC2012/JPEGImages/ --split=/opt/npu/VOCdevkit/VOC2012/ImageSets/Segmentation/val.txt --bin_folder_path=./voc12_bin/ +``` +### 4.3 生成数据集信息文件 +1.生成数据集信息文件脚本get_info.py + +2.执行生成数据集信息脚本,生成数据集信息文件 +```shell +python3.7 get_info.py bin ./voc12_bin voc12.info 500 500 +``` +第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 +## 5 离线推理 + +- **[benchmark工具概述](#51-benchmark工具概述)** + +- **[离线推理](#52-离线推理)** + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN 5.0.1 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) + +### 5.2 离线推理 + +1.设置环境变量 +```shell +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp +export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest/ +``` +2.执行离线推理 +```shell +./benchmark.${arch} -model_type=vision -om_path=fcn_r50-d8_512x512_20k_voc12aug_bs1.om -device_id=0 -batch_size=1 -input_text_path=voc12.info -input_width=500 -input_height=500 -useDvpp=false -output_binary=true +``` + **注意:** +> onnx的输出是int64,但是om的输出是int32 + +输出结果默认保存在当前目录result/dumpOutput_device0,模型有一个输出,每个输入对应的输出对应_1.bin文件 +``` +输出 shape 数据类型 数据含义 +output1 1 * 1 * 500 * 500 int32 8位图像 +``` + +## 6 精度对比 + +- **[离线推理精度](#61-离线推理精度)** +- **[开源精度](#62-开源精度)** +- **[精度对比](#63-精度对比)** + +### 6.1 离线推理精度统计 + +1.调用mmsegmentation_voc2012_postprocess.py评测bs1的mIoU精度: +```shell +python3.7 get_info.py jpg /opt/npu/VOCdevkit/VOC2012/JPEGImages/ voc12_jpg.info + +python3.7 mmsegmentation_voc2012_postprocess.py --bin_data_path=./result/dumpOutput_device0 --test_annotation=./voc12_jpg.info --img_dir=/opt/npu/VOCdevkit/VOC2012/JPEGImages --ann_dir=/opt/npu/VOCdevkit/VOC2012/SegmentationClass --split=/opt/npu/VOCdevkit/VOC2012/ImageSets/Segmentation/val.txt --net_input_width=500 --net_input_height=500 +``` +第一个参数为benchmark推理结果,第二个为原始图片信息文件,第三个为原始图片位置,第四个为验证图片位置,第五个图片的split,第六七个为网宽高 +执行完后会打印出精度: +``` +per class results: + ++-------------+-------+-------+ +| Class | IoU | Acc | ++-------------+-------+-------+ +| background | 92.84 | 97.27 | +| aeroplane | 81.0 | 90.2 | +| bicycle | 37.6 | 84.07 | +| bird | 80.3 | 87.49 | +| boat | 64.63 | 77.42 | +| bottle | 61.32 | 69.76 | +| bus | 87.31 | 91.7 | +| car | 79.48 | 89.74 | +| cat | 85.69 | 92.6 | +| chair | 30.69 | 44.66 | +| cow | 73.21 | 82.52 | +| diningtable | 43.5 | 48.95 | +| dog | 78.83 | 87.76 | +| horse | 74.5 | 82.18 | +| motorbike | 75.7 | 82.97 | +| person | 83.24 | 89.45 | +| pottedplant | 53.23 | 64.87 | +| sheep | 74.29 | 80.85 | +| sofa | 45.59 | 55.79 | +| train | 77.98 | 82.49 | +| tvmonitor | 68.21 | 74.91 | ++-------------+-------+-------+ +Summary: + ++--------+-------+-------+-------+ +| Scope | mIoU | mAcc | aAcc | ++--------+-------+-------+-------+ +| global | 69.01 | 78.94 | 93.04 | ++--------+-------+-------+-------+ + +``` + +2.调用mmsegmentation_voc2012_postprocess.py评测bs16的mIoU精度: +```shell +python3.7 get_info.py jpg /opt/npu/VOCdevkit/VOC2012/JPEGImages/ voc12_jpg.info + +python3.7 mmsegmentation_voc2012_postprocess.py --bin_data_path=./result/dumpOutput_device1 --test_annotation=./voc12_jpg.info --img_dir=/opt/npu/VOCdevkit/VOC2012/JPEGImages --ann_dir=/opt/npu/VOCdevkit/VOC2012/SegmentationClass --split=/opt/npu/VOCdevkit/VOC2012/ImageSets/Segmentation/val.txt --net_input_width=500 --net_input_height=500 +``` +第一个参数为benchmark推理结果,第二个为原始图片信息文件,第三个为原始图片位置,第四个为验证图片位置,第五个图片的split,第六七个为网宽高 +执行完后会打印出精度: +``` +per class results: + ++-------------+-------+-------+ +| Class | IoU | Acc | ++-------------+-------+-------+ +| background | 92.84 | 97.27 | +| aeroplane | 81.0 | 90.2 | +| bicycle | 37.6 | 84.07 | +| bird | 80.3 | 87.49 | +| boat | 64.63 | 77.42 | +| bottle | 61.32 | 69.76 | +| bus | 87.31 | 91.7 | +| car | 79.48 | 89.74 | +| cat | 85.69 | 92.6 | +| chair | 30.69 | 44.66 | +| cow | 73.21 | 82.52 | +| diningtable | 43.5 | 48.95 | +| dog | 78.83 | 87.76 | +| horse | 74.5 | 82.18 | +| motorbike | 75.7 | 82.97 | +| person | 83.24 | 89.45 | +| pottedplant | 53.23 | 64.87 | +| sheep | 74.29 | 80.85 | +| sofa | 45.59 | 55.79 | +| train | 77.98 | 82.49 | +| tvmonitor | 68.21 | 74.91 | ++-------------+-------+-------+ +Summary: + ++--------+-------+-------+-------+ +| Scope | mIoU | mAcc | aAcc | ++--------+-------+-------+-------+ +| global | 69.01 | 78.94 | 93.04 | ++--------+-------+-------+-------+ + +``` + **精度调试:** +> 1.在线推理前处理图片是一定格式的动态分辨率,onnx将分辨率固定为512x512会导致精度下降些。 +> 2.分辨率在512x512时onnx离线推理的精度与om精度相同,分辨率改为500x500可以提升精度,使得mask的精度与开源相比更高 +> 3.单图调试 +> ``` +> python3.7 mmsegmentation/tools/test.py mmsegmentation/configs/fcn/fcn_r50-d8_512x512_20k_voc12aug.py fcn_r50-d8_512x512_20k_voc12aug_20200617_010715-52dc5306.pth --show +> python3.7 mmsegmentation/tools/pytorch2onnx.py mmsegmentation/configs/fcn/fcn_r50-d8_512x512_20k_voc12aug.py --checkpoint fcn_r50-d8_512x512_20k_voc12aug_20200617_010715-52dc5306.pth --output-file fcn_r50-d8_512x512_20k_voc12aug.onnx --shape 500 500 --input-img 2011_003103.jpg --show --verify +> ``` + + +### 6.2 开源精度 +[官网精度](https://download.openmmlab.com/mmsegmentation/v0.5/fcn/fcn_r50-d8_512x512_20k_voc12aug/fcn_r50-d8_512x512_20k_voc12aug_20200617_010715.log.json) + +``` +{"mode": "val", "epoch": 31, "iter": 20000, "lr": 0.0001, "mIoU": 0.67085, "mAcc": 0.76958, "aAcc": 0.92709} +``` +### 6.3 精度对比 +om推理mIoU精度均为0.6901,开源mIoU精度为0.67085,om精度大于开源精度,精度达标 + + +## 7 性能对比 + +- **[npu性能数据](#71-npu性能数据)** + +### 7.1 npu性能数据 +1.benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 +由于在线推理与onnx推理还不支持多batch,所以仅测om bs1,bs16的性能。 +1.benchmark工具在整个数据集上推理获得性能数据 +batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: +``` +[e2e] throughputRate: 14.2564, latency: 101639 +[data read] throughputRate: 24.7255, moduleLatency: 40.444 +[preprocess] throughputRate: 22.102, moduleLatency: 45.2448 +[infer] throughputRate: 14.3682, Interface throughputRate: 16.2017, moduleLatency: 69.2286 +[post] throughputRate: 14.368, moduleLatency: 69.5993 +``` +Interface throughputRate: 16.2017,16.2017x4=64.8068即是batch1 310单卡吞吐率 + +batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: +``` +[[e2e] throughputRate: 13.459, latency: 107660 +[data read] throughputRate: 23.5047, moduleLatency: 42.5446 +[preprocess] throughputRate: 21.4117, moduleLatency: 46.7034 +[infer] throughputRate: 13.5517, Interface throughputRate: 15.4271, moduleLatency: 73.3405 +[post] throughputRate: 0.850975, moduleLatency: 1175.12 +``` +Interface throughputRate: 15.4271,15.4271x4=61.7084即是batch16 310单卡吞吐率 + +2.npu纯推理性能 +batch1的性能,执行20次纯推理取均值,统计吞吐率与其倒数时延(benchmark的时延是单个数据的推理时间),npu性能是一个device执行的结果 +``` +./benchmark.x86_64 -round=20 -om_path=fcn_r50-d8_512x512_20k_voc12aug_bs1.om -device_id=0 -batch_size=1 +``` +PureInfer_perf_of_fcn_r50-d8_512x512_20k_voc12aug_bs1_in_device_0.txt: +``` +[INFO] PureInfer result saved in ./result/PureInfer_perf_of_fcn_r50-d8_512x512_20k_voc12aug_bs1_in_device_0.txt +-----------------PureInfer Performance Summary------------------ +[INFO] ave_throughputRate: 16.2574samples/s, ave_latency: 61.5162ms +---------------------------------------------------------------- +``` +batch16的性能,执行20次纯推理取均值,统计吞吐率与其倒数时延(benchmark的时延是单个数据的推理时间),npu性能是一个device执行的结果 +``` +./benchmark.x86_64 -round=20 -om_path=fcn_r50-d8_512x512_20k_voc12aug_bs16.om -device_id=0 -batch_size=16 +``` +PureInfer_perf_of_fcn_r50-d8_512x512_20k_voc12aug_bs16_in_device_0.txt: +``` +[INFO] PureInfer result saved in ./result/PureInfer_perf_of_fcn_r50-d8_512x512_20k_voc12aug_bs16_in_device_0.txt +-----------------PureInfer Performance Summary------------------ +[INFO] ave_throughputRate: 15.5282samples/s, ave_latency: 64.4083ms +---------------------------------------------------------------- +``` + +**性能优化:** +> 没有遇到性能不达标的问题,故不需要进行性能优化 + diff --git a/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/get_info.py b/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/get_info.py index b76d6739bc..d5cab0450c 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/get_info.py +++ b/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/get_info.py @@ -1,60 +1,60 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/mmsegmentation_voc2012_postprocess.py b/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/mmsegmentation_voc2012_postprocess.py index 298799e007..350c508883 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/mmsegmentation_voc2012_postprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/mmsegmentation_voc2012_postprocess.py @@ -1,243 +1,243 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import os -import os.path as osp -import torch -import mmcv -import numpy as np -from terminaltables import AsciiTable - -CLASSES = ('background', 'aeroplane', 'bicycle', 'bird', 'boat', 'bottle', - 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', - 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', - 'train', 'tvmonitor') - -PALETTE = [[0, 0, 0], [128, 0, 0], [0, 128, 0], [128, 128, 0], [0, 0, 128], - [128, 0, 128], [0, 128, 128], [128, 128, 128], [64, 0, 0], - [192, 0, 0], [64, 128, 0], [192, 128, 0], [64, 0, 128], - [192, 0, 128], [64, 128, 128], [192, 128, 128], [0, 64, 0], - [128, 64, 0], [0, 192, 0], [128, 192, 0], [0, 64, 128]] - - -def load_annotations(img_dir, ann_dir, split): - img_suffix = '.jpg' - seg_map_suffix = '.png' - img_infos = [] - if split is not None: - with open(split) as f: - for line in f: - img_name = line.strip() - img_info = dict(filename=img_name + img_suffix) - if ann_dir is not None: - seg_map = img_name + seg_map_suffix - img_info['ann'] = dict(seg_map=seg_map) - img_infos.append(img_info) - else: - for img in mmcv.scandir(img_dir, img_suffix, recursive=True): - img_info = dict(filename=img) - if ann_dir is not None: - seg_map = img.replace(img_suffix, seg_map_suffix) - img_info['ann'] = dict(seg_map=seg_map) - img_infos.append(img_info) - - return img_infos - - -def get_gt_seg_maps(img_infos, ann_dir): - """Get ground truth segmentation maps for evaluation.""" - gt_seg_maps = [] - for img_info in img_infos: - seg_map = osp.join(ann_dir, img_info['ann']['seg_map']) - gt_seg_map = mmcv.imread( - seg_map, flag='unchanged', backend='pillow') - gt_seg_maps.append(gt_seg_map) - return gt_seg_maps - - -def voc2012_evaluation(results, gt_seg_maps): - metric = ['mIoU'] - eval_results = {} - - num_classes = len(CLASSES) - ignore_index = 255 - label_map = dict() - reduce_zero_label = False - - num_imgs = len(results) - assert len(gt_seg_maps) == num_imgs - total_area_intersect = torch.zeros((num_classes,), dtype=torch.float64) - total_area_union = torch.zeros((num_classes,), dtype=torch.float64) - total_area_pred_label = torch.zeros((num_classes,), dtype=torch.float64) - total_area_label = torch.zeros((num_classes,), dtype=torch.float64) - for i in range(num_imgs): - if isinstance(results[i], str): - pred_label = torch.from_numpy(np.load(results[i])) - else: - pred_label = torch.from_numpy((results[i])) - - if isinstance(gt_seg_maps[i], str): - label = torch.from_numpy( - mmcv.imread(gt_seg_maps[i], flag='unchanged', backend='pillow')) - else: - label = torch.from_numpy(gt_seg_maps[i]) - - if label_map is not None: - for old_id, new_id in label_map.items(): - label[label == old_id] = new_id - if reduce_zero_label: - label[label == 0] = 255 - label = label - 1 - label[label == 254] = 255 - - mask = (label != ignore_index) - pred_label = pred_label[mask] - label = label[mask] - - intersect = pred_label[pred_label == label] - area_intersect = torch.histc( - intersect.float(), bins=(num_classes), min=0, max=num_classes - 1) - area_pred_label = torch.histc( - pred_label.float(), bins=(num_classes), min=0, max=num_classes - 1) - area_label = torch.histc( - label.float(), bins=(num_classes), min=0, max=num_classes - 1) - area_union = area_pred_label + area_label - area_intersect - - total_area_intersect += area_intersect - total_area_union += area_union - total_area_pred_label += area_pred_label - total_area_label += area_label - all_acc = total_area_intersect.sum() / total_area_label.sum() - acc = total_area_intersect / total_area_label - ret_metrics = [all_acc, acc] - iou = total_area_intersect / total_area_union - ret_metrics.append(iou) - ret_metrics = [metric.numpy() for metric in ret_metrics] - - class_table_data = [['Class'] + [m[1:] for m in metric] + ['Acc']] - class_names = CLASSES - - ret_metrics_round = [ - np.round(ret_metric * 100, 2) for ret_metric in ret_metrics - ] - for i in range(num_classes): - class_table_data.append([class_names[i]] + - [m[i] for m in ret_metrics_round[2:]] + - [ret_metrics_round[1][i]]) - summary_table_data = [['Scope'] + - ['m' + head - for head in class_table_data[0][1:]] + ['aAcc']] - ret_metrics_mean = [ - np.round(np.nanmean(ret_metric) * 100, 2) - for ret_metric in ret_metrics - ] - summary_table_data.append(['global'] + ret_metrics_mean[2:] + - [ret_metrics_mean[1]] + - [ret_metrics_mean[0]]) - - print('per class results:') - table = AsciiTable(class_table_data) - print('\n' + table.table) - print('Summary:') - table = AsciiTable(summary_table_data) - print('\n' + table.table) - - for i in range(1, len(summary_table_data[0])): - eval_results[summary_table_data[0] - [i]] = summary_table_data[1][i] / 100.0 - for idx, sub_metric in enumerate(class_table_data[0][1:], 1): - for item in class_table_data[1:]: - eval_results[str(sub_metric) + '.' + - str(item[0])] = item[idx] / 100.0 - return eval_results - - -def postprocess_mask(mask, image_size, net_input_width, net_input_height): - w = image_size[0] - h = image_size[1] - scale = min(net_input_width / w, net_input_height / h) - - pad_w = net_input_width - w * scale - pad_h = net_input_height - h * scale - pad_left = (pad_w // 2) - pad_top = (pad_h // 2) - if pad_top < 0: - pad_top = 0 - if pad_left < 0: - pad_left = 0 - pad_left = int(pad_left) - pad_top = int(pad_top) - a = int(500 - pad_top) - b = int(500 - pad_left) - mask = mask[pad_top:a, pad_left:b] - import torch.nn.functional as F - mask = torch.from_numpy(mask).to(dtype=torch.float32) - mask = mask.expand((1, 1, mask.size(0), mask.size(1))) - mask = F.interpolate(mask, size=(int(h), int(w)), mode='bilinear', align_corners=False) - - mask = mask.squeeze().to(dtype=torch.int32).numpy() - return mask - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--bin_data_path", default="./result/dumpOutput_device0") - parser.add_argument("--test_annotation", default="./voc12_jpg.info") - parser.add_argument("--img_dir", default="/opt/npu/VOCdevkit/VOC2012/JPEGImages") - parser.add_argument("--ann_dir", default="/opt/npu/VOCdevkit/VOC2012/SegmentationClass") - parser.add_argument("--split", default="/opt/npu/VOCdevkit/VOC2012/ImageSets/Segmentation/val.txt") - parser.add_argument("--net_input_width", default=500) - parser.add_argument("--net_input_height", default=500) - args = parser.parse_args() - - # generate dict according to annotation file for query resolution - # load width and height of input images - img_size_dict = dict() - - with open(args.test_annotation)as f: - for line in f.readlines(): - temp = line.split(" ") - img_file_path = temp[1] - img_name = temp[1].split("/")[-1].split(".")[0] - img_width = int(temp[2]) - img_height = int(temp[3]) - img_size_dict[img_name] = (img_width, img_height, img_file_path) - - # read bin file for generate predict result - bin_path = args.bin_data_path - total_img = set([name[:name.rfind('_')]for name in os.listdir(bin_path) if "bin" in name]) - - res_buff = [] - for bin_file in sorted(total_img): - path_base = os.path.join(bin_path, bin_file) - # load all segected output tensor - - output = np.fromfile(path_base + "_" + str(1) + ".bin", dtype="int32") - output = np.reshape(output, [500, 500]) - current_img_size = img_size_dict[bin_file] - output = postprocess_mask(output, img_size_dict[bin_file], 500, 500) - res_buff.append(output) - - seg_result = res_buff - # ground truth - img_infos = load_annotations(args.img_dir, args.ann_dir, split=args.split) - gt_seg_maps = get_gt_seg_maps(img_infos, args.ann_dir) - seg_result = voc2012_evaluation(seg_result, gt_seg_maps) - - - with open('./voc_seg_result.txt', 'w') as f: - for key, value in seg_result.items(): - f.write(key + ': ' + str(value) + '\n') - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import os +import os.path as osp +import torch +import mmcv +import numpy as np +from terminaltables import AsciiTable + +CLASSES = ('background', 'aeroplane', 'bicycle', 'bird', 'boat', 'bottle', + 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', + 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', + 'train', 'tvmonitor') + +PALETTE = [[0, 0, 0], [128, 0, 0], [0, 128, 0], [128, 128, 0], [0, 0, 128], + [128, 0, 128], [0, 128, 128], [128, 128, 128], [64, 0, 0], + [192, 0, 0], [64, 128, 0], [192, 128, 0], [64, 0, 128], + [192, 0, 128], [64, 128, 128], [192, 128, 128], [0, 64, 0], + [128, 64, 0], [0, 192, 0], [128, 192, 0], [0, 64, 128]] + + +def load_annotations(img_dir, ann_dir, split): + img_suffix = '.jpg' + seg_map_suffix = '.png' + img_infos = [] + if split is not None: + with open(split) as f: + for line in f: + img_name = line.strip() + img_info = dict(filename=img_name + img_suffix) + if ann_dir is not None: + seg_map = img_name + seg_map_suffix + img_info['ann'] = dict(seg_map=seg_map) + img_infos.append(img_info) + else: + for img in mmcv.scandir(img_dir, img_suffix, recursive=True): + img_info = dict(filename=img) + if ann_dir is not None: + seg_map = img.replace(img_suffix, seg_map_suffix) + img_info['ann'] = dict(seg_map=seg_map) + img_infos.append(img_info) + + return img_infos + + +def get_gt_seg_maps(img_infos, ann_dir): + """Get ground truth segmentation maps for evaluation.""" + gt_seg_maps = [] + for img_info in img_infos: + seg_map = osp.join(ann_dir, img_info['ann']['seg_map']) + gt_seg_map = mmcv.imread( + seg_map, flag='unchanged', backend='pillow') + gt_seg_maps.append(gt_seg_map) + return gt_seg_maps + + +def voc2012_evaluation(results, gt_seg_maps): + metric = ['mIoU'] + eval_results = {} + + num_classes = len(CLASSES) + ignore_index = 255 + label_map = dict() + reduce_zero_label = False + + num_imgs = len(results) + assert len(gt_seg_maps) == num_imgs + total_area_intersect = torch.zeros((num_classes,), dtype=torch.float64) + total_area_union = torch.zeros((num_classes,), dtype=torch.float64) + total_area_pred_label = torch.zeros((num_classes,), dtype=torch.float64) + total_area_label = torch.zeros((num_classes,), dtype=torch.float64) + for i in range(num_imgs): + if isinstance(results[i], str): + pred_label = torch.from_numpy(np.load(results[i])) + else: + pred_label = torch.from_numpy((results[i])) + + if isinstance(gt_seg_maps[i], str): + label = torch.from_numpy( + mmcv.imread(gt_seg_maps[i], flag='unchanged', backend='pillow')) + else: + label = torch.from_numpy(gt_seg_maps[i]) + + if label_map is not None: + for old_id, new_id in label_map.items(): + label[label == old_id] = new_id + if reduce_zero_label: + label[label == 0] = 255 + label = label - 1 + label[label == 254] = 255 + + mask = (label != ignore_index) + pred_label = pred_label[mask] + label = label[mask] + + intersect = pred_label[pred_label == label] + area_intersect = torch.histc( + intersect.float(), bins=(num_classes), min=0, max=num_classes - 1) + area_pred_label = torch.histc( + pred_label.float(), bins=(num_classes), min=0, max=num_classes - 1) + area_label = torch.histc( + label.float(), bins=(num_classes), min=0, max=num_classes - 1) + area_union = area_pred_label + area_label - area_intersect + + total_area_intersect += area_intersect + total_area_union += area_union + total_area_pred_label += area_pred_label + total_area_label += area_label + all_acc = total_area_intersect.sum() / total_area_label.sum() + acc = total_area_intersect / total_area_label + ret_metrics = [all_acc, acc] + iou = total_area_intersect / total_area_union + ret_metrics.append(iou) + ret_metrics = [metric.numpy() for metric in ret_metrics] + + class_table_data = [['Class'] + [m[1:] for m in metric] + ['Acc']] + class_names = CLASSES + + ret_metrics_round = [ + np.round(ret_metric * 100, 2) for ret_metric in ret_metrics + ] + for i in range(num_classes): + class_table_data.append([class_names[i]] + + [m[i] for m in ret_metrics_round[2:]] + + [ret_metrics_round[1][i]]) + summary_table_data = [['Scope'] + + ['m' + head + for head in class_table_data[0][1:]] + ['aAcc']] + ret_metrics_mean = [ + np.round(np.nanmean(ret_metric) * 100, 2) + for ret_metric in ret_metrics + ] + summary_table_data.append(['global'] + ret_metrics_mean[2:] + + [ret_metrics_mean[1]] + + [ret_metrics_mean[0]]) + + print('per class results:') + table = AsciiTable(class_table_data) + print('\n' + table.table) + print('Summary:') + table = AsciiTable(summary_table_data) + print('\n' + table.table) + + for i in range(1, len(summary_table_data[0])): + eval_results[summary_table_data[0] + [i]] = summary_table_data[1][i] / 100.0 + for idx, sub_metric in enumerate(class_table_data[0][1:], 1): + for item in class_table_data[1:]: + eval_results[str(sub_metric) + '.' + + str(item[0])] = item[idx] / 100.0 + return eval_results + + +def postprocess_mask(mask, image_size, net_input_width, net_input_height): + w = image_size[0] + h = image_size[1] + scale = min(net_input_width / w, net_input_height / h) + + pad_w = net_input_width - w * scale + pad_h = net_input_height - h * scale + pad_left = (pad_w // 2) + pad_top = (pad_h // 2) + if pad_top < 0: + pad_top = 0 + if pad_left < 0: + pad_left = 0 + pad_left = int(pad_left) + pad_top = int(pad_top) + a = int(500 - pad_top) + b = int(500 - pad_left) + mask = mask[pad_top:a, pad_left:b] + import torch.nn.functional as F + mask = torch.from_numpy(mask).to(dtype=torch.float32) + mask = mask.expand((1, 1, mask.size(0), mask.size(1))) + mask = F.interpolate(mask, size=(int(h), int(w)), mode='bilinear', align_corners=False) + + mask = mask.squeeze().to(dtype=torch.int32).numpy() + return mask + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("--bin_data_path", default="./result/dumpOutput_device0") + parser.add_argument("--test_annotation", default="./voc12_jpg.info") + parser.add_argument("--img_dir", default="/opt/npu/VOCdevkit/VOC2012/JPEGImages") + parser.add_argument("--ann_dir", default="/opt/npu/VOCdevkit/VOC2012/SegmentationClass") + parser.add_argument("--split", default="/opt/npu/VOCdevkit/VOC2012/ImageSets/Segmentation/val.txt") + parser.add_argument("--net_input_width", default=500) + parser.add_argument("--net_input_height", default=500) + args = parser.parse_args() + + # generate dict according to annotation file for query resolution + # load width and height of input images + img_size_dict = dict() + + with open(args.test_annotation)as f: + for line in f.readlines(): + temp = line.split(" ") + img_file_path = temp[1] + img_name = temp[1].split("/")[-1].split(".")[0] + img_width = int(temp[2]) + img_height = int(temp[3]) + img_size_dict[img_name] = (img_width, img_height, img_file_path) + + # read bin file for generate predict result + bin_path = args.bin_data_path + total_img = set([name[:name.rfind('_')]for name in os.listdir(bin_path) if "bin" in name]) + + res_buff = [] + for bin_file in sorted(total_img): + path_base = os.path.join(bin_path, bin_file) + # load all segected output tensor + + output = np.fromfile(path_base + "_" + str(1) + ".bin", dtype="int32") + output = np.reshape(output, [500, 500]) + current_img_size = img_size_dict[bin_file] + output = postprocess_mask(output, img_size_dict[bin_file], 500, 500) + res_buff.append(output) + + seg_result = res_buff + # ground truth + img_infos = load_annotations(args.img_dir, args.ann_dir, split=args.split) + gt_seg_maps = get_gt_seg_maps(img_infos, args.ann_dir) + seg_result = voc2012_evaluation(seg_result, gt_seg_maps) + + + with open('./voc_seg_result.txt', 'w') as f: + for key, value in seg_result.items(): + f.write(key + ': ' + str(value) + '\n') + diff --git a/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/mmsegmentation_voc2012_preprocess.py b/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/mmsegmentation_voc2012_preprocess.py index e8e5074b82..22cd2b7b53 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/mmsegmentation_voc2012_preprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/mmsegmentation_voc2012_preprocess.py @@ -1,95 +1,95 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 numpy as np -import os -import cv2 -import argparse -import mmcv -import torch - - -dataset_config = { - 'mean': (123.675, 116.28, 103.53), - 'std': (58.395, 57.12, 57.375) -} - - -tensor_height = 500 -tensor_width = 500 - - -def resize(img, size): - old_h = img.shape[0] - old_w = img.shape[1] - scale_ratio = min(size[0] / old_w, size[1] / old_h) - new_w = int(np.floor(old_w * scale_ratio)) - new_h = int(np.floor(old_h * scale_ratio)) - resized_img = mmcv.imresize(img, (new_w, new_h), backend='cv2') - return resized_img - - -def voc2012_preprocess(input_image, output_bin_path): - img_name = input_image.split('/')[-1] - bin_name = img_name.split('.')[0] + ".bin" - bin_fl = os.path.join(output_bin_path, bin_name) - - one_img = mmcv.imread(os.path.join(input_image), backend='cv2') - one_img = resize(one_img, (tensor_width, tensor_height)) - - mean = np.array(dataset_config['mean'], dtype=np.float32) - std = np.array(dataset_config['std'], dtype=np.float32) - one_img = mmcv.imnormalize(one_img, mean, std) - - h = one_img.shape[0] - w = one_img.shape[1] - pad_left = (tensor_width - w) // 2 - pad_top = (tensor_height - h) // 2 - pad_right = tensor_width - pad_left - w - pad_bottom = tensor_height - pad_top - h - one_img = mmcv.impad(one_img, padding=(pad_left, pad_top, pad_right, pad_bottom), pad_val=0) - - one_img = one_img.transpose(2, 0, 1) - one_img.tofile(bin_fl) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='preprocess of FCN-8s pytorch model') - parser.add_argument("--image_folder_path", default="/opt/npu/VOCdevkit/VOC2012/JPEGImages/", - help='image of dataset') - parser.add_argument("--split", default="/opt/npu/VOCdevkit/VOC2012/ImageSets/Segmentation/val.txt") - parser.add_argument("--bin_folder_path", default="./voc12_bin/", help='Preprocessed image buffer') - flags = parser.parse_args() - - if not os.path.exists(flags.bin_folder_path): - os.makedirs(flags.bin_folder_path) - - split = flags.split - img_suffix = '.jpg' - img_infos = [] - if split is not None: - with open(split) as f: - for line in f: - img_name = line.strip() - img_info = img_name + img_suffix - img_infos.append(img_info) - - images = os.listdir(flags.image_folder_path) - for image_name in images: - - if not (image_name.endswith(".jpeg") or image_name.endswith(".JPEG") or image_name.endswith(".jpg") and image_name in img_infos): - continue - print("start to process image {}....".format(image_name)) - path_image = os.path.join(flags.image_folder_path, image_name) - voc2012_preprocess(path_image, flags.bin_folder_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 numpy as np +import os +import cv2 +import argparse +import mmcv +import torch + + +dataset_config = { + 'mean': (123.675, 116.28, 103.53), + 'std': (58.395, 57.12, 57.375) +} + + +tensor_height = 500 +tensor_width = 500 + + +def resize(img, size): + old_h = img.shape[0] + old_w = img.shape[1] + scale_ratio = min(size[0] / old_w, size[1] / old_h) + new_w = int(np.floor(old_w * scale_ratio)) + new_h = int(np.floor(old_h * scale_ratio)) + resized_img = mmcv.imresize(img, (new_w, new_h), backend='cv2') + return resized_img + + +def voc2012_preprocess(input_image, output_bin_path): + img_name = input_image.split('/')[-1] + bin_name = img_name.split('.')[0] + ".bin" + bin_fl = os.path.join(output_bin_path, bin_name) + + one_img = mmcv.imread(os.path.join(input_image), backend='cv2') + one_img = resize(one_img, (tensor_width, tensor_height)) + + mean = np.array(dataset_config['mean'], dtype=np.float32) + std = np.array(dataset_config['std'], dtype=np.float32) + one_img = mmcv.imnormalize(one_img, mean, std) + + h = one_img.shape[0] + w = one_img.shape[1] + pad_left = (tensor_width - w) // 2 + pad_top = (tensor_height - h) // 2 + pad_right = tensor_width - pad_left - w + pad_bottom = tensor_height - pad_top - h + one_img = mmcv.impad(one_img, padding=(pad_left, pad_top, pad_right, pad_bottom), pad_val=0) + + one_img = one_img.transpose(2, 0, 1) + one_img.tofile(bin_fl) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='preprocess of FCN-8s pytorch model') + parser.add_argument("--image_folder_path", default="/opt/npu/VOCdevkit/VOC2012/JPEGImages/", + help='image of dataset') + parser.add_argument("--split", default="/opt/npu/VOCdevkit/VOC2012/ImageSets/Segmentation/val.txt") + parser.add_argument("--bin_folder_path", default="./voc12_bin/", help='Preprocessed image buffer') + flags = parser.parse_args() + + if not os.path.exists(flags.bin_folder_path): + os.makedirs(flags.bin_folder_path) + + split = flags.split + img_suffix = '.jpg' + img_infos = [] + if split is not None: + with open(split) as f: + for line in f: + img_name = line.strip() + img_info = img_name + img_suffix + img_infos.append(img_info) + + images = os.listdir(flags.image_folder_path) + for image_name in images: + + if not (image_name.endswith(".jpeg") or image_name.endswith(".JPEG") or image_name.endswith(".jpg") and image_name in img_infos): + continue + print("start to process image {}....".format(image_name)) + path_image = os.path.join(flags.image_folder_path, image_name) + voc2012_preprocess(path_image, flags.bin_folder_path) diff --git a/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/requirements.txt b/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/requirements.txt index b61b7bcdad..f86ad403f3 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/requirements.txt +++ b/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/requirements.txt @@ -1,5 +1,5 @@ -torch == 1.8.0 -torchvision == 0.9.0 -onnx == 1.9.0 -numpy == 1.20.1 +torch == 1.8.0 +torchvision == 0.9.0 +onnx == 1.9.0 +numpy == 1.20.1 opencv-python == 4.5.2.52 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/test/README.md b/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/test/README.md index 127a2e645f..fa794daeac 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/test/README.md +++ b/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/test/README.md @@ -1,31 +1,31 @@ -环境准备: - -1.数据集路径 -数据集统一放在/root/datasets/或/opt/npu/ -本模型数据集放在/opt/npu/ - -2.进入工作目录 -cd fcn-8s - -3.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -pip3.7 install -r requirements.txt - -4.获取、修改和安装模型代码 -git clone https://github.com/open-mmlab/mmcv.git -cd mmcv -pip3.7 install -e . -cd .. -git clone https://github.com/open-mmlab/mmsegmentation.git -cd mmsegmentation -pip3.7 install -e . # or "python3.7 setup.py develop" -cd .. - -5.获取权重文件 -wget https://download.openmmlab.com/mmsegmentation/v0.5/fcn/fcn_r50-d8_512x512_20k_voc12aug/fcn_r50-d8_512x512_20k_voc12aug_20200617_010715-52dc5306.pth - -6.获取benchmark工具 -将将benchmark.x86_64,benchmark.aarch64放在当前目录 - -7.310上执行,执行时确保device空闲 -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/opt/npu/ +环境准备: + +1.数据集路径 +数据集统一放在/root/datasets/或/opt/npu/ +本模型数据集放在/opt/npu/ + +2.进入工作目录 +cd fcn-8s + +3.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +pip3.7 install -r requirements.txt + +4.获取、修改和安装模型代码 +git clone https://github.com/open-mmlab/mmcv.git +cd mmcv +pip3.7 install -e . +cd .. +git clone https://github.com/open-mmlab/mmsegmentation.git +cd mmsegmentation +pip3.7 install -e . # or "python3.7 setup.py develop" +cd .. + +5.获取权重文件 +wget https://download.openmmlab.com/mmsegmentation/v0.5/fcn/fcn_r50-d8_512x512_20k_voc12aug/fcn_r50-d8_512x512_20k_voc12aug_20200617_010715-52dc5306.pth + +6.获取benchmark工具 +将将benchmark.x86_64,benchmark.aarch64放在当前目录 + +7.310上执行,执行时确保device空闲 +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/opt/npu/ diff --git a/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/test/parse.py b/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/test/parse.py index a0f253b055..27eae0d0ac 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/test/parse.py +++ b/ACL_PyTorch/contrib/cv/segmentation/FCN-8s/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/Fast_SCNN_pth2onnx.py b/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/Fast_SCNN_pth2onnx.py index b8ec935d0b..f30505c1ae 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/Fast_SCNN_pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/Fast_SCNN_pth2onnx.py @@ -1,46 +1,46 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch -import torch.onnx -from collections import OrderedDict -import sys -sys.path.append('./SegmenTron') -from segmentron.models.model_zoo import get_segmentation_model -from segmentron.utils.options import parse_args -from segmentron.config import cfg -import ssl - - -def pth2onnx(): - model = get_segmentation_model() - checkpoint = torch.load(args.pth_path, map_location='cpu') - model.load_state_dict(checkpoint) - model.eval() - input_names = ["image"] - output_names = ["output1"] - dynamic_axes = {'image': {0: '-1'}, 'output1': {0: '-1'}} - dummy_input1 = torch.randn(args.batch_size, 3, 1024, 2048) - output_file1 = args.onnx_name + '.onnx' - torch.onnx.export(model, dummy_input1, output_file1, input_names = input_names, output_names = output_names, opset_version=11, verbose=True) - print(args.onnx_name,"batchsize",args.batch_size," onnx has transformed successfully") - print('onnx export done.') - -if __name__ == "__main__": - args = parse_args() - args.config_file = 'SegmenTron/configs/cityscapes_fast_scnn.yaml' - cfg.update_from_file(args.config_file) - cfg.update_from_list(args.opts) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch +import torch.onnx +from collections import OrderedDict +import sys +sys.path.append('./SegmenTron') +from segmentron.models.model_zoo import get_segmentation_model +from segmentron.utils.options import parse_args +from segmentron.config import cfg +import ssl + + +def pth2onnx(): + model = get_segmentation_model() + checkpoint = torch.load(args.pth_path, map_location='cpu') + model.load_state_dict(checkpoint) + model.eval() + input_names = ["image"] + output_names = ["output1"] + dynamic_axes = {'image': {0: '-1'}, 'output1': {0: '-1'}} + dummy_input1 = torch.randn(args.batch_size, 3, 1024, 2048) + output_file1 = args.onnx_name + '.onnx' + torch.onnx.export(model, dummy_input1, output_file1, input_names = input_names, output_names = output_names, opset_version=11, verbose=True) + print(args.onnx_name,"batchsize",args.batch_size," onnx has transformed successfully") + print('onnx export done.') + +if __name__ == "__main__": + args = parse_args() + args.config_file = 'SegmenTron/configs/cityscapes_fast_scnn.yaml' + cfg.update_from_file(args.config_file) + cfg.update_from_list(args.opts) pth2onnx() \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/README.md b/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/README.md index ddff64a5bc..ce5890527f 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/README.md +++ b/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/README.md @@ -1,369 +1,369 @@ -# FastSCNN推理说明 - -## 1 模型概述 - -- **[论文地址](https://arxiv.org/abs/1902.04502)** -- **[代码地址](https://gitee.com/wang-chaojiemayj/modelzoo/tree/master/contrib/PyTorch/Research/cv/image_segmentation/FastSCNN)** - -### 1.1 论文地址 - -[FastSCNN论文](https://arxiv.org/abs/1902.04502) - -### 1.2 代码地址 - -[FascSCNN代码](https://gitee.com/wang-chaojiemayj/modelzoo/tree/master/contrib/PyTorch/Research/cv/image_segmentation/FastSCNN) - -branch:master - -commitid:e86409484cf89467a569be43acee1b3f06b92305 - - -## 2 环境说明 - -- 深度学习框架 -- python第三方库 - -### 2.1 深度学习框架 - -``` -python3.7.5 -CANN 5.0.2 - -pytorch >= 1.5.0 -torchvision >= 0.6.0 -onnx == 1.7.0 -onnx-simplifier == 0.3.6 -``` - -### 2.2 python第三方库 - -``` -numpy == 1.21.1 -Pillow == 8.3.0 -opencv-python == 4.5.2.54 -``` - -## 3 模型转换 - -- pth转om模型 - -### 3.1 pth转om模型 - -1.获取pth权重文件 - -获取权重文件方法,可从Ascend modelzoo FastSCNN_ACL_Pytorch 模型压缩包获取 - -md5sum:efc7247270298f3f57e88375011b52ee - -2.FastSCNN模型已经上传至代码仓,使用git工具获取FastSCNN模型代码 -使用gitclone获取模型训练的代码,切换到tuili分支。 - -``` -git clone https://gitee.com/wang-chaojiemayj/modelzoo.git -cd modelzoo -git checkout tuili -``` - -进入FastSCNN目录 - -``` -cd ./contrib/ACL_PyTorch/Research/cv/segmentation/FastSCNN -``` - -使用gitclone下载模型代码 - -``` -git clone https://github.com/LikeLy-Journey/SegmenTron -``` - -由于onnx不支持AdaptiveAvgPool算子,需要使用module.patch修改module.py。 -将FastSCNN目录下的module.patch放到FastSCNN/SegmenTron目录下 -执行 - -``` -cd ./SegmenTron -git apply module.patch -cd .. -``` - -3.执行pth2om脚本,生成om模型文件 - -ascend-toolkit版本:5.0.2 -``` -bs1: -python3.7 Fast_SCNN_pth2onnx.py --pth_path best_model.pth --onnx_name fast_scnn_bs1 --batch_size 1 -bs16: -python3.7 Fast_SCNN_pth2onnx.py --pth_path best_model.pth --onnx_name fast_scnn_bs16 --batch_size 16 - **bs4:bs16无法导出时使用 -python3.7 Fast_SCNN_pth2onnx.py --pth_path best_model.pth --onnx_name fast_scnn_bs4 --batch_size 4** -``` -参数说明: ---pth_path:pth权重文件的路径,可自行设置,默认值为best_model.pth; ---onnx_name:需要转出的onnx模型的名称,可自行设置,默认值为fast_scnn_bs1(由于本模型不支持动态batch,推荐在模型名后加后缀,如‘_bs1’,用以区分不同batch_size的onnx模型); ---batch_size:导出的onnx模型的batch_size,可自行设置,默认值为1。 - -onnx转出om - -bs1: -``` -source env.sh(注意,latest是一个软连接,请将服务器中的/usr/local/Ascend/ascend-toolkit/latest 指向5.0.2版本的CANN包) -atc --framework=5 --model=fast_scnn_bs1.onnx --output=fast_scnn_bs1 --output_type=FP16 --input_format=NCHW --input_shape="image:1,3,1024,2048" --log=debug --soc_version=Ascend310 -``` -bs16: -``` -source env.sh -atc --framework=5 --model=fast_scnn_bs16.onnx --output=fast_scnn_bs16 --output_type=FP16 --input_format=NCHW --input_shape="image:16,3,1024,2048" --log=debug --soc_version=Ascend310 -``` -bs4:(bs16无法离线推理时使用) -``` -source env.sh -atc --framework=5 --model=fast_scnn_bs4.onnx --output=fast_scnn_bs4 --output_type=FP16 --input_format=NCHW --input_shape="image:4,3,1024,2048" --log=debug --soc_version=Ascend310 -``` - - -## 4 数据集预处理 - -- 数据集获取 -- 数据预处理 -- 生成数据集信息文件 - -### 4.1 数据集获取 - -本模型支持cityscapes leftImg8bit的500张验证集。用户需要下载[leftImg8bit_trainvaltest.zip](http://www.cityscapes-dataset.com/downloads)和[gtFine_trainvaltest.zip](http://www.cityscapes-dataset.com/downloads)数据集,解压,将两个数据集放在/opt/npu/datasets/cityscapes/目录下。推荐使用软连接,可以节省时间,数据集目录如下。 - -``` -|opt--npu--datasets -| |-- cityscapes -| | |-- gtFine -| | | |-- test -| | | |-- train -| | | |-- val -| | |-- leftImg8bit -| | |-- test -| | |-- train -| | |-- val -``` - - -### 4.2 数据集预处理 - -在modelzoo/contrib/ACL_PyTorch/Research /cv/segmentation/FastSCNN目录创建软连接 - -``` -ln -s /opt/npu/datasets datasets -``` - -运行Fast_SCNN_preprocess.py - -``` -python3.7 Fast_SCNN_preprocess.py -``` - -数据预处理的结果会保存在/opt/npu/prep_datset -预处理之后的二进制文件目录如下: -/opt/npu/prep_dataset/datasets/leftImg8bit/ -/opt/npu/prep_dataset/datasets/gtFine/ -在modelzoo/contrib/ACL_PyTorch/Research/cv/segmentation/FastSCNN目录下创建软连接 - -``` -ln -s /opt/npu/prep_dataset prep_dataset -``` - -### 4.3 生成数据集信息文件 - -1.生成数据集信息文件脚本gen_dataset_info.py - -2.执行生成数据集信息脚本,生成数据集信息文件 - -``` -python3.7 gen_dataset_info.py -``` - -## 5 离线推理 - -- benchmark工具概述 -- 离线推理 - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN 5.0.1 推理benchmark工具用户指南 01 - -### 5.2 离线推理 - -1.设置环境变量 - -``` -source env.sh -``` - -2.执行离线推理 -bs1: -``` -./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=fast_scnn_bs1.om -input_text_path=./fast_scnn_prep_bin.info -input_width=2048 -input_height=1024 -output_binary=True -useDvpp=False./benchmark.x86_64 -model_type=vision -device_id=1 -batch_size=4 -om_path=fast_scnn_bs4.om -input_text_path=./fast_scnn_prep_bin.info -input_width=2048 -input_height=1024 -output_binary=True -useDvpp=False -``` -bs16: -``` -./benchmark.x86_64 -model_type=vision -device_id=1 -batch_size=16 -om_path=./fast_scnn_bs16.om -input_text_path=./fast_scnn_prep_bin.info -input_width=2048 -input_height=1024 -output_binary=True -useDvpp=False -``` -bs4:(bs16无法离线推理时使用) -``` -./benchmark.x86_64 -model_type=vision -device_id=2 -batch_size=4 -om_path=fast_scnn_bs4.om -input_text_path=fast_scnn_prep_bin.info -input_width=2048 -input_height=1024 -output_binary=True -useDvpp=False -``` -``` -参数说明: -需要更改的参数 --device_id:使用的Ascend310处理器的卡号,可选0、1、2、3,尽量选择不同的卡号进行推理,若-device_id=0,离线推理结果会保存在./result/dumpOut -put_device0中,device0中的0代表卡号是0; --batch_size:om模型的batch_size; --om_path: 需要进行离线推理的om模型的路径; -不需要更改的参数: --input_text_path:om模型的二进制输入图片的路径信息文件的路径; --input_width:输入图片的宽度,FastSCNN模型是2048; --input_heigh:输入图片的高度,FastSCNN模型是1024; --output_binary:benchmark的输出是二进制文件还是txt文件,True代表输出为二进制文件; --useDvpp:是否使用Dvpp工具,FastSCNN模型不使用Dvpp工具,设置为False; -``` -## 6 精度对比 - -- 离线推理精度 -- 开源精度 -- 开源精度对比 - -### 6.1 离线推理精度统计 - -后处理统计mIoU - -调用cityscapes_acc_eval.py脚本推理结果与label比对,获取pixAcc和mIoU数据,结果保存在fast_scnn_bs1.log和fast_scnn_bs4.log - -``` -python3.7 cityscapes_acc_eval.py result/dumpOutput_device0/ ./out >fast_scnn_bs1.log -python3.7 cityscapes_acc_eval.py result/dumpOutput_device1/ ./out >fast_scnn_bs4.log -``` - -第一个为benchmark输出目录,第二个为输出重定向文件名 - -``` -pixAcc:94.29% mIoU:64.43 -``` - -经过对bs1与bs4的om测试,本模型batch1的精度与batch4的精度一致,精度数据如上 - -### 6.2 开源精度 - -pth精度 - -``` -Model pixAcc mIoU -FastSCNN 93.877% 64.46 -``` - -### 6.3 精度对比 - -将得到的om模型离线推理精度与pth精度作比较,精度下降不超过0.5%,故精度达标 - -## 7 性能对比 - -- NPU性能数据 -- T4性能数据 -- 性能对比 - -### 7.1 npu性能数据 - -1.benchmark工具在整个数据集上推理获得性能数据。 -batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: - -``` -[e2e] throughputRate: 0.99593, latency: 502043[data read] throughputRate: 1.62003, moduleLatency: 617.273[preprocess] throughputRate: 1.20942, moduleLatency: 826.844[inference] throughputRate: 1.02697, Interface throughputRate: 5.5718, moduleLatency: 973.739[postprocess] throughputRate: 0.999452, moduleLatency: 1000.55 -``` - -Interface throughputRate: 5.5718,5.5718x4=22.286既是batch1 310单卡吞吐率 - -batch4的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_4_device_1.txt: - -``` -[e2e] throughputRate: 0.429745, latency: 1.16348e+06[data read] throughputRate: 0.673692, moduleLatency: 1484.36[preprocess] throughputRate: 0.525523, moduleLatency: 1902.86[inference] throughputRate: 0.477698, Interface throughputRate: 5.59273, moduleLatency: 2100.2[postprocess] throughputRate: 0.107216, moduleLatency: 9327 -``` - -Interface throughputRate: 5.59273,5.59273x4=22.37092既是batch16 310单卡吞吐率 - - -### 7.2 T4性能数据 - -在装有T4卡的服务器上测试gpu性能,测试过程请确保卡没有运行其他任务,TensorRT版本:7.2.3.4,cuda版本:11.0,cudnn版本:8.2 -batch1性能: - -``` -trtexec --onnx=fast_scnn_bs1.onnx --fp16 --shapes=image:1x3x1024x2048 --threads -``` - -``` -[07/20/2021-01:49:12] [I] GPU Compute[07/20/2021-01:49:12] [I] min: 6.1626 ms[07/20/2021-01:49:12] [I] max: 6.18018 ms[07/20/2021-01:49:12] [I] mean: 6.17022 ms[07/20/2021-01:49:12] [I] median: 6.17062 ms[07/20/2021-01:49:12] [I] percentile: 6.18018 ms at 99%[07/20/2021-01:49:12] [I] total compute time: 0.265319 s -``` - -batch1 t4单卡吞吐率:1000/(6.17022/1)=162.068fps - -batch4性能: - -``` -trtexec --onnx=fast_scnn_bs4.onnx --fp16 --shapes=image:4x3x1024x2048 --threads -``` - -``` -[08/25/2021-05:18:21] [I] GPU Compute[08/25/2021-05:18:21] [I] min: 23.7666 ms[08/25/2021-05:18:21] [I] max: 24.3643 ms[08/25/2021-05:18:21] [I] mean: 24.0295 ms[08/25/2021-05:18:21] [I] median: 23.9731 ms[08/25/2021-05:18:21] [I] percentile: 24.3643 ms at 99%[08/25/2021-05:18:21] [I] total compute time: 0.288354 s -``` - -batch4 t4单卡吞吐率:1000/(24.0295/4)=166.46fps - -### 7.3 性能对比 - -batch1:5.5718x4 < 1000/(6.17022/1) -batch2:5.59273x4 <1000/(24.0295/4) -310单个device的吞吐率乘4即单卡吞吐率比T4单卡的吞吐率小,故310性能低于T4性能,性能不达标。 -对于batch1与batch4,310性能均低于T4性能,该模型放在contrib/ACL_PyTorch/Research目录下。 -**性能优化:** - -测试版本:CANN 5.0.2 - -目前可行的解决方案有三个: - -(1)优化TransData,修改five_2_four.py和four_2_five.py - -(2)输出节点由float32改为float16 - -(3)模型中Resize节点的mode由双线性为最近邻 - -具体优化方法如下: - -(1)修改five_2_four.py和four_2_five.py从profiling数据的op_statistic_0_1.csv看出影响性能的是TransData,ResizeBilinearV2D,AvgPoolV2算子。从op_summary_0_1.csv可以看出单个TransData的aicore耗时,确定可以可以优化。 - -``` -five_2_four.py:9928 修改如下: elif dst_format.lower() == "nchw" and dst_shape in [[2560, 512, 4, 26], [2560, 512, 1, 26], [2560, 256, 8, 25],[16, 240, 7, 7], [16, 120, 14, 14], [1, 128, 32, 64], [1, 19, 1024, 2048], [2, 128, 32, 64], [2, 19, 1024, 2048]]: -``` - -``` - four_2_five.py:1219 修改如下: if src_format.upper() == "NCHW" and shape_input in [[16, 240, 7, 7], [16, 120, 14, 14],[1, 1, 1024, 2048, 16], [1, 8, 32, 64, 16], [2, 1, 1024, 2048, 16], [2, 8, 32, 64, 16]] and dtype_input == "float16": -``` - -(2)指定输出为fp16: - -``` -atc --framework=5 --model=fast_scnn_bs1_sim.onnx --output=fast_scnn_bs1 --output_type=FP16 --input_format=NCHW --input_shape="image:1,3,1024,2048" --log=debug --soc_version=Ascend310python3.7.5 -m onnxsim --input-shape="2,3,1024,2048" fast_scnn_bs2.onnx fast_scnn_bs2_sim.onnx --skip-optimizationatc --framework=5 --model=fast_scnn_bs2_sim.onnx --output=fast_scnn_bs2 --output_type=FP16 --input_format=NCHW --input_shape="image:2,3,1024,2048" --log=debug --soc_version=Ascend310 -``` - -(3)模型中Resize节点的mode由双线性为最近邻 - -``` -newnode229 = onnx.helper.make_node( 'Resize', name='Resize_229', inputs=['549', '560', '561', '559'], outputs=['562'], coordinate_transformation_mode='align_corners', cubic_coeff_a=-0.75, mode='nearest', nearest_mode='floor')newnode245 = onnx.helper.make_node( 'Resize', name='Resize_245', inputs=['566', '577', '578', '576'], outputs=['579'], coordinate_transformation_mode='align_corners', cubic_coeff_a=-0.75, mode='nearest', nearest_mode='floor')graph.node.remove(model.graph.node[126])graph.node.insert(126,newnode126)graph.node.remove(model.graph.node[144])graph.node.insert(144,newnode144)graph.node.remove(model.graph.node[162])graph.node.insert(162,newnode162)graph.node.remove(model.graph.node[180])graph.node.insert(180,newnode180)graph.node.remove(model.graph.node[185])graph.node.insert(185,newnode185)graph.node.remove(model.graph.node[213])graph.node.insert(213,newnode213)graph.node.remove(model.graph.node[229])graph.node.insert(229,newnode229)graph.node.remove(model.graph.node[245])graph.node.insert(245,newnode245)onnx.checker.check_model(model)onnx.save(model, 'bs1_resized.onnx') -``` - -(4)性能、精度统计 - -| 方法 | 精度 | 性能 | -| ------------------------------------------------- | --------------------------- | --------------------------- | -| 未优化 | | | -| 优化TransData,修改five_2_four.py和four_2_five.py | bs1:mIoU64.46;bs2:mIoU64.46 | bs1:4.135fps;bs2:6.265fps | -| 输出节点由float32改为float16 | bs1:mIoU64.43;bs2:mIoU64.43 | bs1:22.518fps;bs2:22.694fps | -| 模型中Resize节点的mode由双线性为最近邻 | bs1:mIoU60.41;bs1:mIoU60.41 | bs1:7.747fps;bs2:14.046fps | - -8.本模型经过指定输出结点为fp16后,精度为64.43,pth精度为64.46,精度达标;性能提高到22fps左右,故本次pr提交的模型输出为结点fp16。 - +# FastSCNN推理说明 + +## 1 模型概述 + +- **[论文地址](https://arxiv.org/abs/1902.04502)** +- **[代码地址](https://gitee.com/wang-chaojiemayj/modelzoo/tree/master/contrib/PyTorch/Research/cv/image_segmentation/FastSCNN)** + +### 1.1 论文地址 + +[FastSCNN论文](https://arxiv.org/abs/1902.04502) + +### 1.2 代码地址 + +[FascSCNN代码](https://gitee.com/wang-chaojiemayj/modelzoo/tree/master/contrib/PyTorch/Research/cv/image_segmentation/FastSCNN) + +branch:master + +commitid:e86409484cf89467a569be43acee1b3f06b92305 + + +## 2 环境说明 + +- 深度学习框架 +- python第三方库 + +### 2.1 深度学习框架 + +``` +python3.7.5 +CANN 5.0.2 + +pytorch >= 1.5.0 +torchvision >= 0.6.0 +onnx == 1.7.0 +onnx-simplifier == 0.3.6 +``` + +### 2.2 python第三方库 + +``` +numpy == 1.21.1 +Pillow == 8.3.0 +opencv-python == 4.5.2.54 +``` + +## 3 模型转换 + +- pth转om模型 + +### 3.1 pth转om模型 + +1.获取pth权重文件 + +获取权重文件方法,可从Ascend modelzoo FastSCNN_ACL_Pytorch 模型压缩包获取 + +md5sum:efc7247270298f3f57e88375011b52ee + +2.FastSCNN模型已经上传至代码仓,使用git工具获取FastSCNN模型代码 +使用gitclone获取模型训练的代码,切换到tuili分支。 + +``` +git clone https://gitee.com/wang-chaojiemayj/modelzoo.git +cd modelzoo +git checkout tuili +``` + +进入FastSCNN目录 + +``` +cd ./contrib/ACL_PyTorch/Research/cv/segmentation/FastSCNN +``` + +使用gitclone下载模型代码 + +``` +git clone https://github.com/LikeLy-Journey/SegmenTron +``` + +由于onnx不支持AdaptiveAvgPool算子,需要使用module.patch修改module.py。 +将FastSCNN目录下的module.patch放到FastSCNN/SegmenTron目录下 +执行 + +``` +cd ./SegmenTron +git apply module.patch +cd .. +``` + +3.执行pth2om脚本,生成om模型文件 + +ascend-toolkit版本:5.0.2 +``` +bs1: +python3.7 Fast_SCNN_pth2onnx.py --pth_path best_model.pth --onnx_name fast_scnn_bs1 --batch_size 1 +bs16: +python3.7 Fast_SCNN_pth2onnx.py --pth_path best_model.pth --onnx_name fast_scnn_bs16 --batch_size 16 + **bs4:bs16无法导出时使用 +python3.7 Fast_SCNN_pth2onnx.py --pth_path best_model.pth --onnx_name fast_scnn_bs4 --batch_size 4** +``` +参数说明: +--pth_path:pth权重文件的路径,可自行设置,默认值为best_model.pth; +--onnx_name:需要转出的onnx模型的名称,可自行设置,默认值为fast_scnn_bs1(由于本模型不支持动态batch,推荐在模型名后加后缀,如‘_bs1’,用以区分不同batch_size的onnx模型); +--batch_size:导出的onnx模型的batch_size,可自行设置,默认值为1。 + +onnx转出om + +bs1: +``` +source env.sh(注意,latest是一个软连接,请将服务器中的/usr/local/Ascend/ascend-toolkit/latest 指向5.0.2版本的CANN包) +atc --framework=5 --model=fast_scnn_bs1.onnx --output=fast_scnn_bs1 --output_type=FP16 --input_format=NCHW --input_shape="image:1,3,1024,2048" --log=debug --soc_version=Ascend310 +``` +bs16: +``` +source env.sh +atc --framework=5 --model=fast_scnn_bs16.onnx --output=fast_scnn_bs16 --output_type=FP16 --input_format=NCHW --input_shape="image:16,3,1024,2048" --log=debug --soc_version=Ascend310 +``` +bs4:(bs16无法离线推理时使用) +``` +source env.sh +atc --framework=5 --model=fast_scnn_bs4.onnx --output=fast_scnn_bs4 --output_type=FP16 --input_format=NCHW --input_shape="image:4,3,1024,2048" --log=debug --soc_version=Ascend310 +``` + + +## 4 数据集预处理 + +- 数据集获取 +- 数据预处理 +- 生成数据集信息文件 + +### 4.1 数据集获取 + +本模型支持cityscapes leftImg8bit的500张验证集。用户需要下载[leftImg8bit_trainvaltest.zip](http://www.cityscapes-dataset.com/downloads)和[gtFine_trainvaltest.zip](http://www.cityscapes-dataset.com/downloads)数据集,解压,将两个数据集放在/opt/npu/datasets/cityscapes/目录下。推荐使用软连接,可以节省时间,数据集目录如下。 + +``` +|opt--npu--datasets +| |-- cityscapes +| | |-- gtFine +| | | |-- test +| | | |-- train +| | | |-- val +| | |-- leftImg8bit +| | |-- test +| | |-- train +| | |-- val +``` + + +### 4.2 数据集预处理 + +在modelzoo/contrib/ACL_PyTorch/Research /cv/segmentation/FastSCNN目录创建软连接 + +``` +ln -s /opt/npu/datasets datasets +``` + +运行Fast_SCNN_preprocess.py + +``` +python3.7 Fast_SCNN_preprocess.py +``` + +数据预处理的结果会保存在/opt/npu/prep_datset +预处理之后的二进制文件目录如下: +/opt/npu/prep_dataset/datasets/leftImg8bit/ +/opt/npu/prep_dataset/datasets/gtFine/ +在modelzoo/contrib/ACL_PyTorch/Research/cv/segmentation/FastSCNN目录下创建软连接 + +``` +ln -s /opt/npu/prep_dataset prep_dataset +``` + +### 4.3 生成数据集信息文件 + +1.生成数据集信息文件脚本gen_dataset_info.py + +2.执行生成数据集信息脚本,生成数据集信息文件 + +``` +python3.7 gen_dataset_info.py +``` + +## 5 离线推理 + +- benchmark工具概述 +- 离线推理 + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN 5.0.1 推理benchmark工具用户指南 01 + +### 5.2 离线推理 + +1.设置环境变量 + +``` +source env.sh +``` + +2.执行离线推理 +bs1: +``` +./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=fast_scnn_bs1.om -input_text_path=./fast_scnn_prep_bin.info -input_width=2048 -input_height=1024 -output_binary=True -useDvpp=False./benchmark.x86_64 -model_type=vision -device_id=1 -batch_size=4 -om_path=fast_scnn_bs4.om -input_text_path=./fast_scnn_prep_bin.info -input_width=2048 -input_height=1024 -output_binary=True -useDvpp=False +``` +bs16: +``` +./benchmark.x86_64 -model_type=vision -device_id=1 -batch_size=16 -om_path=./fast_scnn_bs16.om -input_text_path=./fast_scnn_prep_bin.info -input_width=2048 -input_height=1024 -output_binary=True -useDvpp=False +``` +bs4:(bs16无法离线推理时使用) +``` +./benchmark.x86_64 -model_type=vision -device_id=2 -batch_size=4 -om_path=fast_scnn_bs4.om -input_text_path=fast_scnn_prep_bin.info -input_width=2048 -input_height=1024 -output_binary=True -useDvpp=False +``` +``` +参数说明: +需要更改的参数 +-device_id:使用的Ascend310处理器的卡号,可选0、1、2、3,尽量选择不同的卡号进行推理,若-device_id=0,离线推理结果会保存在./result/dumpOut +put_device0中,device0中的0代表卡号是0; +-batch_size:om模型的batch_size; +-om_path: 需要进行离线推理的om模型的路径; +不需要更改的参数: +-input_text_path:om模型的二进制输入图片的路径信息文件的路径; +-input_width:输入图片的宽度,FastSCNN模型是2048; +-input_heigh:输入图片的高度,FastSCNN模型是1024; +-output_binary:benchmark的输出是二进制文件还是txt文件,True代表输出为二进制文件; +-useDvpp:是否使用Dvpp工具,FastSCNN模型不使用Dvpp工具,设置为False; +``` +## 6 精度对比 + +- 离线推理精度 +- 开源精度 +- 开源精度对比 + +### 6.1 离线推理精度统计 + +后处理统计mIoU + +调用cityscapes_acc_eval.py脚本推理结果与label比对,获取pixAcc和mIoU数据,结果保存在fast_scnn_bs1.log和fast_scnn_bs4.log + +``` +python3.7 cityscapes_acc_eval.py result/dumpOutput_device0/ ./out >fast_scnn_bs1.log +python3.7 cityscapes_acc_eval.py result/dumpOutput_device1/ ./out >fast_scnn_bs4.log +``` + +第一个为benchmark输出目录,第二个为输出重定向文件名 + +``` +pixAcc:94.29% mIoU:64.43 +``` + +经过对bs1与bs4的om测试,本模型batch1的精度与batch4的精度一致,精度数据如上 + +### 6.2 开源精度 + +pth精度 + +``` +Model pixAcc mIoU +FastSCNN 93.877% 64.46 +``` + +### 6.3 精度对比 + +将得到的om模型离线推理精度与pth精度作比较,精度下降不超过0.5%,故精度达标 + +## 7 性能对比 + +- NPU性能数据 +- T4性能数据 +- 性能对比 + +### 7.1 npu性能数据 + +1.benchmark工具在整个数据集上推理获得性能数据。 +batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: + +``` +[e2e] throughputRate: 0.99593, latency: 502043[data read] throughputRate: 1.62003, moduleLatency: 617.273[preprocess] throughputRate: 1.20942, moduleLatency: 826.844[inference] throughputRate: 1.02697, Interface throughputRate: 5.5718, moduleLatency: 973.739[postprocess] throughputRate: 0.999452, moduleLatency: 1000.55 +``` + +Interface throughputRate: 5.5718,5.5718x4=22.286既是batch1 310单卡吞吐率 + +batch4的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_4_device_1.txt: + +``` +[e2e] throughputRate: 0.429745, latency: 1.16348e+06[data read] throughputRate: 0.673692, moduleLatency: 1484.36[preprocess] throughputRate: 0.525523, moduleLatency: 1902.86[inference] throughputRate: 0.477698, Interface throughputRate: 5.59273, moduleLatency: 2100.2[postprocess] throughputRate: 0.107216, moduleLatency: 9327 +``` + +Interface throughputRate: 5.59273,5.59273x4=22.37092既是batch16 310单卡吞吐率 + + +### 7.2 T4性能数据 + +在装有T4卡的服务器上测试gpu性能,测试过程请确保卡没有运行其他任务,TensorRT版本:7.2.3.4,cuda版本:11.0,cudnn版本:8.2 +batch1性能: + +``` +trtexec --onnx=fast_scnn_bs1.onnx --fp16 --shapes=image:1x3x1024x2048 --threads +``` + +``` +[07/20/2021-01:49:12] [I] GPU Compute[07/20/2021-01:49:12] [I] min: 6.1626 ms[07/20/2021-01:49:12] [I] max: 6.18018 ms[07/20/2021-01:49:12] [I] mean: 6.17022 ms[07/20/2021-01:49:12] [I] median: 6.17062 ms[07/20/2021-01:49:12] [I] percentile: 6.18018 ms at 99%[07/20/2021-01:49:12] [I] total compute time: 0.265319 s +``` + +batch1 t4单卡吞吐率:1000/(6.17022/1)=162.068fps + +batch4性能: + +``` +trtexec --onnx=fast_scnn_bs4.onnx --fp16 --shapes=image:4x3x1024x2048 --threads +``` + +``` +[08/25/2021-05:18:21] [I] GPU Compute[08/25/2021-05:18:21] [I] min: 23.7666 ms[08/25/2021-05:18:21] [I] max: 24.3643 ms[08/25/2021-05:18:21] [I] mean: 24.0295 ms[08/25/2021-05:18:21] [I] median: 23.9731 ms[08/25/2021-05:18:21] [I] percentile: 24.3643 ms at 99%[08/25/2021-05:18:21] [I] total compute time: 0.288354 s +``` + +batch4 t4单卡吞吐率:1000/(24.0295/4)=166.46fps + +### 7.3 性能对比 + +batch1:5.5718x4 < 1000/(6.17022/1) +batch2:5.59273x4 <1000/(24.0295/4) +310单个device的吞吐率乘4即单卡吞吐率比T4单卡的吞吐率小,故310性能低于T4性能,性能不达标。 +对于batch1与batch4,310性能均低于T4性能,该模型放在contrib/ACL_PyTorch/Research目录下。 +**性能优化:** + +测试版本:CANN 5.0.2 + +目前可行的解决方案有三个: + +(1)优化TransData,修改five_2_four.py和four_2_five.py + +(2)输出节点由float32改为float16 + +(3)模型中Resize节点的mode由双线性为最近邻 + +具体优化方法如下: + +(1)修改five_2_four.py和four_2_five.py从profiling数据的op_statistic_0_1.csv看出影响性能的是TransData,ResizeBilinearV2D,AvgPoolV2算子。从op_summary_0_1.csv可以看出单个TransData的aicore耗时,确定可以可以优化。 + +``` +five_2_four.py:9928 修改如下: elif dst_format.lower() == "nchw" and dst_shape in [[2560, 512, 4, 26], [2560, 512, 1, 26], [2560, 256, 8, 25],[16, 240, 7, 7], [16, 120, 14, 14], [1, 128, 32, 64], [1, 19, 1024, 2048], [2, 128, 32, 64], [2, 19, 1024, 2048]]: +``` + +``` + four_2_five.py:1219 修改如下: if src_format.upper() == "NCHW" and shape_input in [[16, 240, 7, 7], [16, 120, 14, 14],[1, 1, 1024, 2048, 16], [1, 8, 32, 64, 16], [2, 1, 1024, 2048, 16], [2, 8, 32, 64, 16]] and dtype_input == "float16": +``` + +(2)指定输出为fp16: + +``` +atc --framework=5 --model=fast_scnn_bs1_sim.onnx --output=fast_scnn_bs1 --output_type=FP16 --input_format=NCHW --input_shape="image:1,3,1024,2048" --log=debug --soc_version=Ascend310python3.7.5 -m onnxsim --input-shape="2,3,1024,2048" fast_scnn_bs2.onnx fast_scnn_bs2_sim.onnx --skip-optimizationatc --framework=5 --model=fast_scnn_bs2_sim.onnx --output=fast_scnn_bs2 --output_type=FP16 --input_format=NCHW --input_shape="image:2,3,1024,2048" --log=debug --soc_version=Ascend310 +``` + +(3)模型中Resize节点的mode由双线性为最近邻 + +``` +newnode229 = onnx.helper.make_node( 'Resize', name='Resize_229', inputs=['549', '560', '561', '559'], outputs=['562'], coordinate_transformation_mode='align_corners', cubic_coeff_a=-0.75, mode='nearest', nearest_mode='floor')newnode245 = onnx.helper.make_node( 'Resize', name='Resize_245', inputs=['566', '577', '578', '576'], outputs=['579'], coordinate_transformation_mode='align_corners', cubic_coeff_a=-0.75, mode='nearest', nearest_mode='floor')graph.node.remove(model.graph.node[126])graph.node.insert(126,newnode126)graph.node.remove(model.graph.node[144])graph.node.insert(144,newnode144)graph.node.remove(model.graph.node[162])graph.node.insert(162,newnode162)graph.node.remove(model.graph.node[180])graph.node.insert(180,newnode180)graph.node.remove(model.graph.node[185])graph.node.insert(185,newnode185)graph.node.remove(model.graph.node[213])graph.node.insert(213,newnode213)graph.node.remove(model.graph.node[229])graph.node.insert(229,newnode229)graph.node.remove(model.graph.node[245])graph.node.insert(245,newnode245)onnx.checker.check_model(model)onnx.save(model, 'bs1_resized.onnx') +``` + +(4)性能、精度统计 + +| 方法 | 精度 | 性能 | +| ------------------------------------------------- | --------------------------- | --------------------------- | +| 未优化 | | | +| 优化TransData,修改five_2_four.py和four_2_five.py | bs1:mIoU64.46;bs2:mIoU64.46 | bs1:4.135fps;bs2:6.265fps | +| 输出节点由float32改为float16 | bs1:mIoU64.43;bs2:mIoU64.43 | bs1:22.518fps;bs2:22.694fps | +| 模型中Resize节点的mode由双线性为最近邻 | bs1:mIoU60.41;bs1:mIoU60.41 | bs1:7.747fps;bs2:14.046fps | + +8.本模型经过指定输出结点为fp16后,精度为64.43,pth精度为64.46,精度达标;性能提高到22fps左右,故本次pr提交的模型输出为结点fp16。 + diff --git a/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/gen_dataset_info.py index 2f15f923ba..cc42d73672 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/gen_dataset_info.py @@ -1,47 +1,47 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os - - -def get_bin_info(img_root_path='prep_dataset/datasets/leftImg8bit', - mask_folder='opt/npu/prep_dataset/datasets/cityscapes/gtFine', - info_name='fast_scnn_prep_bin.info', width='2048', height='1024'): - img_path = [] - mask_path = [] - for root, _, files in os.walk(img_root_path): - for filename in files: - if filename.startswith('._'): - continue - if filename.endswith('.bin'): - imgpath = os.path.join(root, filename) - img_path.append(imgpath) - foldername = os.path.basename(os.path.dirname(imgpath)) - maskname = filename.replace('leftImg8bit', 'gtFine_labelIds') - maskpath = os.path.join(mask_folder, foldername, maskname) - mask_path.append(maskpath) - - with open(info_name, 'w') as fp: - for index in range(len(img_path)): - content = ' '.join([str(index), img_path[index], width, height]) - fp.write(content) - fp.write('\n') - - -if __name__ == '__main__': - img_root_path = 'prep_dataset/datasets/leftImg8bit/' - mask_folder = '/opt/npu/prep_dataset/datasets/gtFine' - info_name = 'fast_scnn_prep_bin.info' - width = '2048' - height = '1024' - get_bin_info(img_root_path=img_root_path, mask_folder=mask_folder, info_name=info_name, width=width, height=height) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os + + +def get_bin_info(img_root_path='prep_dataset/datasets/leftImg8bit', + mask_folder='opt/npu/prep_dataset/datasets/cityscapes/gtFine', + info_name='fast_scnn_prep_bin.info', width='2048', height='1024'): + img_path = [] + mask_path = [] + for root, _, files in os.walk(img_root_path): + for filename in files: + if filename.startswith('._'): + continue + if filename.endswith('.bin'): + imgpath = os.path.join(root, filename) + img_path.append(imgpath) + foldername = os.path.basename(os.path.dirname(imgpath)) + maskname = filename.replace('leftImg8bit', 'gtFine_labelIds') + maskpath = os.path.join(mask_folder, foldername, maskname) + mask_path.append(maskpath) + + with open(info_name, 'w') as fp: + for index in range(len(img_path)): + content = ' '.join([str(index), img_path[index], width, height]) + fp.write(content) + fp.write('\n') + + +if __name__ == '__main__': + img_root_path = 'prep_dataset/datasets/leftImg8bit/' + mask_folder = '/opt/npu/prep_dataset/datasets/gtFine' + info_name = 'fast_scnn_prep_bin.info' + width = '2048' + height = '1024' + get_bin_info(img_root_path=img_root_path, mask_folder=mask_folder, info_name=info_name, width=width, height=height) diff --git a/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/test/README.md b/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/test/README.md index 94ddb7cc6c..bc1740a35c 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/test/README.md +++ b/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/test/README.md @@ -1,120 +1,120 @@ -环境准备: - -1.数据集路径 -本模型数据集放在/opt/npu/,具体文件路径为:opt/npu/datasets -本模型支持cityscapes leftImg8bit的500张验证集。用户需要下载[leftImg8bit_trainvaltest.zip](http://www.cityscapes-dataset.com/downloads)和[gtFine_trainvaltest.zip](http://www.cityscapes-dataset.com/downloads)数据集,解压,将两个数据集放在/opt/npu/datasets/cityscapes/目录下。推荐使用软连接,可以节省时间,数据集目录如下。 - -``` -|opt--npu--datasets -| |-- cityscapes -| | |-- gtFine -| | | |-- test -| | | |-- train -| | | |-- val -| | |-- leftImg8bit -| | |-- test -| | |-- train -| | |-- val -``` - -2.进入工作目录 -cd Fast_SCNN - -3.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -pip3.7.5 install -r requirements.txt - -4.获取,修改与安装开源模型代码 -使用gitclone获取模型训练的代码,切换到tuili分支。 - -``` -git clone https://gitee.com/wang-chaojiemayj/modelzoo.git -cd modelzoo -git checkout tuili -``` - -进入FastSCNN目录 - -``` -cd ./contrib/PyTorch/Research/cv/image_segmentation/Fast_SCNN/ -``` - -使用gitclone下载模型代码 - -``` -git clone https://github.com/LikeLy-Journey/SegmenTron -``` - -由于onnx不支持AdaptiveavgPool算子,需要使用module.patch修改Fast_SCNN/SegmenTron/module.py。 -将FastSCNN目录下的module.patch放到FastSCNN/SegmenTron目录下. -执行 - -``` -cd ./SegmenTron -git apply module.patch -cd .. -``` - -5.获取权重文件 -获取权重文件方法,可从Ascend modelzoo FastSCNN_ACL_Pytorch 模型压缩包获取 - - md5sum:efc7247270298f3f57e88375011b52ee - -6.数据预处理 -在modelzoo/contrib/ACL_PyTorch/Research /cv/segmentation/FastSCNN目录创建软连接 - -``` -ln -s /opt/npu/datasets datasets -``` - -运行Fast_SCNN_preprocess.py - -``` -python3.7.5 Fast_SCNN_preprocess.py -``` - -数据预处理的结果会保存在/opt/npu/prep_datset -预处理之后的二进制文件目录如下: -/opt/npu/prep_dataset/datasets/leftImg8bit/ -/opt/npu/prep_dataset/datasets/gtFine/ -在modelzoo/contrib/ACL_PyTorch/Research /cv/segmentation/FastSCNN目录下创建软连接 - -``` -ln -s /opt/npu/prep_dataset prep_dataset -``` - -运行gen_dataset_info.py获取二进制输入文件的info信息 - -``` -python3.7.5 gen_dataset_info.py -``` - -顺利运行会在当前目录下生成fast_scnn_prep_bin.info文件 - -6.获取benchmark工具 -将benchmark.x86_64和benchmark.aarch64放在当前目录 - -7.310上执行,执行时确保device空闲 - -ascend-toolkit版本:5.0.2 - -onnx转出om - -``` -source env.sh(注意,latest是一个软连接,请将服务器中的/usr/local/Ascend/ascend-toolkit/latest 指向5.0.2版本的CANN包) -bash test/pth2om.sh -成功运行会生成fast_scnn_bs1.onnx,fast_scnn_bs4.onnx,fast_scnn_bs8.onnx,fast_scnn_bs16.onnx,fast_scnn_bs32.onnx; -fast_scnn_bs1.om,fast_scnn_bs4.om,fast_scnn_bs8.om,fast_scnn_bs16.om,fast_scnn_bs32.om文件。 -(注意fast_scnn_bs32.onnx如果因为内存原因无法生成,也就无法导出fast_scnn_bs32.om。) -``` - -进行离线推理并进行精度、性能统计 - -``` -bash test/eval_acc_perf.sh -``` -会自动对fast_scnn_bs1.om、fast_scnn_bs16.om、fast_scnn_bs4.om进行精度、性能的统计。(fast_scnn_bs16.om可能会因为内存原因无法进行离线推理,运行报错后会自动跳过) - -8.在t4环境上将fast_scnn_bs1.onnx,fast_scnn_bs4.onnx,fast_scnn_bs8.onnx,fast_scnn_bs16.onnx,fast_scnn_bs32.onnx文件文件与perf_t4.sh放在同一目录 - -然后执行bash perf_t4.sh,执行时确保gpu空闲 - +环境准备: + +1.数据集路径 +本模型数据集放在/opt/npu/,具体文件路径为:opt/npu/datasets +本模型支持cityscapes leftImg8bit的500张验证集。用户需要下载[leftImg8bit_trainvaltest.zip](http://www.cityscapes-dataset.com/downloads)和[gtFine_trainvaltest.zip](http://www.cityscapes-dataset.com/downloads)数据集,解压,将两个数据集放在/opt/npu/datasets/cityscapes/目录下。推荐使用软连接,可以节省时间,数据集目录如下。 + +``` +|opt--npu--datasets +| |-- cityscapes +| | |-- gtFine +| | | |-- test +| | | |-- train +| | | |-- val +| | |-- leftImg8bit +| | |-- test +| | |-- train +| | |-- val +``` + +2.进入工作目录 +cd Fast_SCNN + +3.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +pip3.7.5 install -r requirements.txt + +4.获取,修改与安装开源模型代码 +使用gitclone获取模型训练的代码,切换到tuili分支。 + +``` +git clone https://gitee.com/wang-chaojiemayj/modelzoo.git +cd modelzoo +git checkout tuili +``` + +进入FastSCNN目录 + +``` +cd ./contrib/PyTorch/Research/cv/image_segmentation/Fast_SCNN/ +``` + +使用gitclone下载模型代码 + +``` +git clone https://github.com/LikeLy-Journey/SegmenTron +``` + +由于onnx不支持AdaptiveavgPool算子,需要使用module.patch修改Fast_SCNN/SegmenTron/module.py。 +将FastSCNN目录下的module.patch放到FastSCNN/SegmenTron目录下. +执行 + +``` +cd ./SegmenTron +git apply module.patch +cd .. +``` + +5.获取权重文件 +获取权重文件方法,可从Ascend modelzoo FastSCNN_ACL_Pytorch 模型压缩包获取 + + md5sum:efc7247270298f3f57e88375011b52ee + +6.数据预处理 +在modelzoo/contrib/ACL_PyTorch/Research /cv/segmentation/FastSCNN目录创建软连接 + +``` +ln -s /opt/npu/datasets datasets +``` + +运行Fast_SCNN_preprocess.py + +``` +python3.7.5 Fast_SCNN_preprocess.py +``` + +数据预处理的结果会保存在/opt/npu/prep_datset +预处理之后的二进制文件目录如下: +/opt/npu/prep_dataset/datasets/leftImg8bit/ +/opt/npu/prep_dataset/datasets/gtFine/ +在modelzoo/contrib/ACL_PyTorch/Research /cv/segmentation/FastSCNN目录下创建软连接 + +``` +ln -s /opt/npu/prep_dataset prep_dataset +``` + +运行gen_dataset_info.py获取二进制输入文件的info信息 + +``` +python3.7.5 gen_dataset_info.py +``` + +顺利运行会在当前目录下生成fast_scnn_prep_bin.info文件 + +6.获取benchmark工具 +将benchmark.x86_64和benchmark.aarch64放在当前目录 + +7.310上执行,执行时确保device空闲 + +ascend-toolkit版本:5.0.2 + +onnx转出om + +``` +source env.sh(注意,latest是一个软连接,请将服务器中的/usr/local/Ascend/ascend-toolkit/latest 指向5.0.2版本的CANN包) +bash test/pth2om.sh +成功运行会生成fast_scnn_bs1.onnx,fast_scnn_bs4.onnx,fast_scnn_bs8.onnx,fast_scnn_bs16.onnx,fast_scnn_bs32.onnx; +fast_scnn_bs1.om,fast_scnn_bs4.om,fast_scnn_bs8.om,fast_scnn_bs16.om,fast_scnn_bs32.om文件。 +(注意fast_scnn_bs32.onnx如果因为内存原因无法生成,也就无法导出fast_scnn_bs32.om。) +``` + +进行离线推理并进行精度、性能统计 + +``` +bash test/eval_acc_perf.sh +``` +会自动对fast_scnn_bs1.om、fast_scnn_bs16.om、fast_scnn_bs4.om进行精度、性能的统计。(fast_scnn_bs16.om可能会因为内存原因无法进行离线推理,运行报错后会自动跳过) + +8.在t4环境上将fast_scnn_bs1.onnx,fast_scnn_bs4.onnx,fast_scnn_bs8.onnx,fast_scnn_bs16.onnx,fast_scnn_bs32.onnx文件文件与perf_t4.sh放在同一目录 + +然后执行bash perf_t4.sh,执行时确保gpu空闲 + diff --git a/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/test/parse.py b/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/test/parse.py index f7ae934e8d..d432cbc56d 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/test/parse.py +++ b/ACL_PyTorch/contrib/cv/segmentation/FastSCNN/test/parse.py @@ -1,40 +1,40 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import re - -def get_acc(filename): - with open(filename, 'r') as f: - lines = f.readlines() - last_line = lines[-1] - mIoU = last_line.split(" ")[1] - pixAcc = last_line.split(" ")[8].replace('\n','') - print("mIoU:", mIoU, " pixAcc: ", pixAcc) - - -def get_perf(filename): - with open(filename, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 - print('310 bs{} fps:{}'.format(filename.split('_')[3], fps)) - -if __name__ == "__main__": - - filename = sys.argv[1] - - if filename.endswith(".log"): - get_acc(filename) - elif filename.endswith(".txt"): +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import re + +def get_acc(filename): + with open(filename, 'r') as f: + lines = f.readlines() + last_line = lines[-1] + mIoU = last_line.split(" ")[1] + pixAcc = last_line.split(" ")[8].replace('\n','') + print("mIoU:", mIoU, " pixAcc: ", pixAcc) + + +def get_perf(filename): + with open(filename, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 + print('310 bs{} fps:{}'.format(filename.split('_')[3], fps)) + +if __name__ == "__main__": + + filename = sys.argv[1] + + if filename.endswith(".log"): + get_acc(filename) + elif filename.endswith(".txt"): get_perf(filename) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/GCNet/README.md b/ACL_PyTorch/contrib/cv/segmentation/GCNet/README.md index 595ee6a8cb..3a1f420a26 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/GCNet/README.md +++ b/ACL_PyTorch/contrib/cv/segmentation/GCNet/README.md @@ -1,159 +1,159 @@ -# GCNet模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 - -``` -pip3.7 install -r requirements.txt -``` - - - -2.获取,修改与安装开源模型代码 - -``` -git clone https://github.com/open-mmlab/mmcv -cd mmcv -git reset --hard 643009e4458109cb88ba5e669eec61a5e54c83be -pip install -e . -cd .. -git clone https://github.com/open-mmlab/mmdetection -cd mmdetection -git reset --hard 6c1347d7c0fa220a7be99cb19d1a9e8b6cbf7544 -pip install -r requirements/build.txt -python setup.py develop -patch -p1 < GCNet.diff -``` - - - -3.获取权重文件 - -从[LINK](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet)中获取权重文件,将权重文件mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco_20200204-17235656.pth放到当前工作目录 (执行pth2onnx时会自动下载) - -4.数据集 - -使用COCO官网的coco2017的5千张验证集进行测试,请参考原始开源代码仓mmdetection中对公共数据集的设置 - -5.[获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) -将benchmark.x86_64或benchmark.aarch64放到当前工作目录 - - - -## 2 模型转换 - -1.pth转onnx模型 - -``` -python tools/deployment/pytorch2onnx.py configs/gcnet/mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco.py mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco_20200204-17235656.pth --output-file GCNet.onnx --input-img demo/demo.jpg --test-img tests/data/color.jpg --shape 800 1216 -``` - - - -2.onnx转om模型 - -``` -atc --framework=5 --model=GCNet.onnx --output=./GCNet_bs1 --input_shape="input:1,3,800,1216" --log=error --soc_version=Ascend310 -``` - - - -3.执行以下命令生成om模型文件 - -``` -bash test/pth2om.sh -``` - - - -## 3 离线推理 - -1.数据预处理 - -``` -python GCNet_preprocess.py --image_src_path=${datasets_path}/val2017 --bin_file_path=val2017_bin --model_input_height=800 --model_input_width=1216 -``` - - - -2.生成数据集信息文件 - -``` -python gen_dataset_info.py bin val2017_bin coco2017.info 1216 800 -python gen_dataset_info.py jpg val2017 coco2017_jpg.info -``` - - - -3.执行离线推理 - -``` -./benchmark.x86_64 -model_type=vision -device_id=1 -batch_size=1 -om_path=./GCNet_bs1.om -input_text_path=./coco2017.info -input_width=1216 -input_height=800 -output_binary=True -useDvpp=False -``` - - - -4.使用后处理脚本展示推理结果 - -``` -python GCNet_postprocess.py --bin_data_path=./result/dumpOutput_device1/ --test_annotation=coco2017_jpg.info --det_results_path=detection-results --annotations_path=annotations/instances_val2017.json --net_out_num=3 --net_input_height=800 --net_input_width=1216 -``` - - - -5.NPU精度测试 - -``` -python txt_to_json.py -python coco_eval.py -``` - - - -6.NPU性能测试 - -``` -./benchmark.x86_64 -round=20 -om_path=GCNet_bs1.om -device_id=1 -batch_size=1 -``` - - - -7.GPU性能测试 - -onnx包含自定义算子,因此不能使用开源TensorRT测试性能数据,故在T4机器上使用pth在线推理测试性能数据 - -测评T4精度与性能 - -``` -python tools/test.py configs/gcnet/mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco.py ./mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco_20200204-17235656.pth --eval bbox -python coco_eval.py -``` - - - -8.执行命令进行离线推理 - -``` -bash test/eval_acc_perf.sh -``` - - - - **评测结果:** - -| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | -| :-------: | :---------: | :-------------: | :------: | :------: | -| GCNet bs1 | mAP:0.613 | mAP:0.611 | 3.931fps | 8.144fps | - -备注: -1.GCNet的mmdetection实现不支持多batch。 - -2.onnx包含自定义算子,因此不能使用开源TensorRT测试性能数据,故在T4机器上使用pth在线推理测试性能数据。 - -说明: - -1.om推理box map50精度为0.611,T4推理box map50精度为0.613,精度下降在1个点之内,因此可视为精度达标。 - -2.batch1:2.036 * 4 fps > 3.931fps 即310单个device的吞吐率乘4即单卡吞吐率约为T4单卡的吞吐率2倍,故310性能高于T4性能,性能达标。 - +# GCNet模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 + +``` +pip3.7 install -r requirements.txt +``` + + + +2.获取,修改与安装开源模型代码 + +``` +git clone https://github.com/open-mmlab/mmcv +cd mmcv +git reset --hard 643009e4458109cb88ba5e669eec61a5e54c83be +pip install -e . +cd .. +git clone https://github.com/open-mmlab/mmdetection +cd mmdetection +git reset --hard 6c1347d7c0fa220a7be99cb19d1a9e8b6cbf7544 +pip install -r requirements/build.txt +python setup.py develop +patch -p1 < GCNet.diff +``` + + + +3.获取权重文件 + +从[LINK](https://github.com/open-mmlab/mmdetection/tree/master/configs/gcnet)中获取权重文件,将权重文件mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco_20200204-17235656.pth放到当前工作目录 (执行pth2onnx时会自动下载) + +4.数据集 + +使用COCO官网的coco2017的5千张验证集进行测试,请参考原始开源代码仓mmdetection中对公共数据集的设置 + +5.[获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) +将benchmark.x86_64或benchmark.aarch64放到当前工作目录 + + + +## 2 模型转换 + +1.pth转onnx模型 + +``` +python tools/deployment/pytorch2onnx.py configs/gcnet/mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco.py mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco_20200204-17235656.pth --output-file GCNet.onnx --input-img demo/demo.jpg --test-img tests/data/color.jpg --shape 800 1216 +``` + + + +2.onnx转om模型 + +``` +atc --framework=5 --model=GCNet.onnx --output=./GCNet_bs1 --input_shape="input:1,3,800,1216" --log=error --soc_version=Ascend310 +``` + + + +3.执行以下命令生成om模型文件 + +``` +bash test/pth2om.sh +``` + + + +## 3 离线推理 + +1.数据预处理 + +``` +python GCNet_preprocess.py --image_src_path=${datasets_path}/val2017 --bin_file_path=val2017_bin --model_input_height=800 --model_input_width=1216 +``` + + + +2.生成数据集信息文件 + +``` +python gen_dataset_info.py bin val2017_bin coco2017.info 1216 800 +python gen_dataset_info.py jpg val2017 coco2017_jpg.info +``` + + + +3.执行离线推理 + +``` +./benchmark.x86_64 -model_type=vision -device_id=1 -batch_size=1 -om_path=./GCNet_bs1.om -input_text_path=./coco2017.info -input_width=1216 -input_height=800 -output_binary=True -useDvpp=False +``` + + + +4.使用后处理脚本展示推理结果 + +``` +python GCNet_postprocess.py --bin_data_path=./result/dumpOutput_device1/ --test_annotation=coco2017_jpg.info --det_results_path=detection-results --annotations_path=annotations/instances_val2017.json --net_out_num=3 --net_input_height=800 --net_input_width=1216 +``` + + + +5.NPU精度测试 + +``` +python txt_to_json.py +python coco_eval.py +``` + + + +6.NPU性能测试 + +``` +./benchmark.x86_64 -round=20 -om_path=GCNet_bs1.om -device_id=1 -batch_size=1 +``` + + + +7.GPU性能测试 + +onnx包含自定义算子,因此不能使用开源TensorRT测试性能数据,故在T4机器上使用pth在线推理测试性能数据 + +测评T4精度与性能 + +``` +python tools/test.py configs/gcnet/mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco.py ./mask_rcnn_r50_fpn_r4_gcb_c3-c5_1x_coco_20200204-17235656.pth --eval bbox +python coco_eval.py +``` + + + +8.执行命令进行离线推理 + +``` +bash test/eval_acc_perf.sh +``` + + + + **评测结果:** + +| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | +| :-------: | :---------: | :-------------: | :------: | :------: | +| GCNet bs1 | mAP:0.613 | mAP:0.611 | 3.931fps | 8.144fps | + +备注: +1.GCNet的mmdetection实现不支持多batch。 + +2.onnx包含自定义算子,因此不能使用开源TensorRT测试性能数据,故在T4机器上使用pth在线推理测试性能数据。 + +说明: + +1.om推理box map50精度为0.611,T4推理box map50精度为0.613,精度下降在1个点之内,因此可视为精度达标。 + +2.batch1:2.036 * 4 fps > 3.931fps 即310单个device的吞吐率乘4即单卡吞吐率约为T4单卡的吞吐率2倍,故310性能高于T4性能,性能达标。 + diff --git a/ACL_PyTorch/contrib/cv/segmentation/IntraDA/gen_dataset_info.py b/ACL_PyTorch/contrib/cv/segmentation/IntraDA/gen_dataset_info.py index b3976a2b9e..297cdca7e2 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/IntraDA/gen_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/segmentation/IntraDA/gen_dataset_info.py @@ -1,99 +1,99 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - print(bin_images) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_png_info(image_names, info_name): - with open(info_name, 'w') as file: - for image_name in image_names: - print(image_name) - if len(image_names) == 0: - continue - else: - for index, png in enumerate(image_name): - img_cv = cv2.imread(png) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), png, str(width), str(height)]) - file.write(content) - file.write('\n') - -def get_city_pairs(folder, split='train'): - def get_path_pairs(img_folder, mask_folder): - img_paths = [] - mask_paths = [] - for root, _, files in os.walk(img_folder): - for filename in files: - if filename.endswith('.png'): - imgpath = os.path.join(root, filename) - foldername = os.path.basename(os.path.dirname(imgpath)) - maskname = filename.replace('leftImg8bit', 'gtFine_labelIds') - maskpath = os.path.join(mask_folder, foldername, maskname) - if os.path.isfile(imgpath) and os.path.isfile(maskpath): - img_paths.append(imgpath) - mask_paths.append(maskpath) - else: - print('cannot find the mask or image:', imgpath, maskpath) - print('Found {} images in the folder {}'.format(len(img_paths), img_folder)) - return img_paths, mask_paths - - if split in ('train', 'val'): - # "./Cityscapes/leftImg8bit/train" or "./Cityscapes/leftImg8bit/val" - img_folder = os.path.join(folder, 'leftImg8bit/' + split) - # "./Cityscapes/gtFine/train" or "./Cityscapes/gtFine/val" - mask_folder = os.path.join(folder, 'gtFine/' + split) - # img_paths与mask_paths的顺序是一一对应的 - img_paths, mask_paths = get_path_pairs(img_folder, mask_folder) - return img_paths, mask_paths - else: - assert split == 'trainval' - print('trainval set') - train_img_folder = os.path.join(folder, 'leftImg8bit/train') - train_mask_folder = os.path.join(folder, 'gtFine/train') - val_img_folder = os.path.join(folder, 'leftImg8bit/val') - val_mask_folder = os.path.join(folder, 'gtFine/val') - train_img_paths, train_mask_paths = get_path_pairs(train_img_folder, train_mask_folder) - val_img_paths, val_mask_paths = get_path_pairs(val_img_folder, val_mask_folder) - img_paths = train_img_paths + val_img_paths - mask_paths = train_mask_paths + val_mask_paths - - return img_paths, mask_paths - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - res = get_city_pairs(file_path) - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'png': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + print(bin_images) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_png_info(image_names, info_name): + with open(info_name, 'w') as file: + for image_name in image_names: + print(image_name) + if len(image_names) == 0: + continue + else: + for index, png in enumerate(image_name): + img_cv = cv2.imread(png) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), png, str(width), str(height)]) + file.write(content) + file.write('\n') + +def get_city_pairs(folder, split='train'): + def get_path_pairs(img_folder, mask_folder): + img_paths = [] + mask_paths = [] + for root, _, files in os.walk(img_folder): + for filename in files: + if filename.endswith('.png'): + imgpath = os.path.join(root, filename) + foldername = os.path.basename(os.path.dirname(imgpath)) + maskname = filename.replace('leftImg8bit', 'gtFine_labelIds') + maskpath = os.path.join(mask_folder, foldername, maskname) + if os.path.isfile(imgpath) and os.path.isfile(maskpath): + img_paths.append(imgpath) + mask_paths.append(maskpath) + else: + print('cannot find the mask or image:', imgpath, maskpath) + print('Found {} images in the folder {}'.format(len(img_paths), img_folder)) + return img_paths, mask_paths + + if split in ('train', 'val'): + # "./Cityscapes/leftImg8bit/train" or "./Cityscapes/leftImg8bit/val" + img_folder = os.path.join(folder, 'leftImg8bit/' + split) + # "./Cityscapes/gtFine/train" or "./Cityscapes/gtFine/val" + mask_folder = os.path.join(folder, 'gtFine/' + split) + # img_paths与mask_paths的顺序是一一对应的 + img_paths, mask_paths = get_path_pairs(img_folder, mask_folder) + return img_paths, mask_paths + else: + assert split == 'trainval' + print('trainval set') + train_img_folder = os.path.join(folder, 'leftImg8bit/train') + train_mask_folder = os.path.join(folder, 'gtFine/train') + val_img_folder = os.path.join(folder, 'leftImg8bit/val') + val_mask_folder = os.path.join(folder, 'gtFine/val') + train_img_paths, train_mask_paths = get_path_pairs(train_img_folder, train_mask_folder) + val_img_paths, val_mask_paths = get_path_pairs(val_img_folder, val_mask_folder) + img_paths = train_img_paths + val_img_paths + mask_paths = train_mask_paths + val_mask_paths + + return img_paths, mask_paths + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + res = get_city_pairs(file_path) + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'png': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_png_info(res, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/IntraDA/intrada_postprocess.py b/ACL_PyTorch/contrib/cv/segmentation/IntraDA/intrada_postprocess.py index 2ca1ae5a6f..3f3b79d13d 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/IntraDA/intrada_postprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/IntraDA/intrada_postprocess.py @@ -1,178 +1,178 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import time -import sys -import torch -import numpy as np -import torch.nn as nn -import struct -from PIL import Image - -def fast_hist(a, b, n): - k = (a >= 0) & (a < n) - return np.bincount(n * a[k].astype(int) + b[k], minlength=n ** 2).reshape(n, n) - - -def per_class_iu(hist): - return np.diag(hist) / (hist.sum(1) + hist.sum(0) - np.diag(hist)) - - -class Evaluator(object): - def __init__(self, cityscapes_path, folder_davinci_target, outdir): - - loc = "cpu" - self.device = torch.device(loc) - print("===device===:",self.device) - # get valid dataset images and targets - self.image_paths, self.mask_paths = _get_city_pairs(cityscapes_path, "val") - - self.annotation_file_path = folder_davinci_target - - self.outdir = outdir - - def eval(self): - - print("Start validation, Total sample: {:d}".format(len(self.image_paths))) - list_time = [] - - hist = np.zeros((19, 19)) - for i in range(len(self.image_paths)): - filename = os.path.basename(self.image_paths[i]) - annotation_file = os.path.join(self.annotation_file_path, filename.split('.')[0]) - - mask = Image.open(self.mask_paths[i]) # mask shape: (W,H) - mask = mask.resize((2048,1024),Image.NEAREST) - mask = self._mask_transform(mask) # mask shape: (H,w) - mask = mask.to(self.device) - - with torch.no_grad(): - start_time = time.time() - outputs = self.file2tensor(annotation_file).to(self.device) - end_time = time.time() - - outputs_ = outputs.numpy().squeeze().transpose(1, 2, 0) - outputs_ = np.argmax(outputs_, axis=2) - hist += fast_hist(mask.cpu().numpy().flatten(), outputs_.flatten(), 19) - inters_over_union_classes = per_class_iu(hist) - mIoU = np.nanmean(inters_over_union_classes) - step_time = end_time - start_time - - list_time.append(step_time) - - print("Sample: {:d}, mIoU: {:.3f}, time: {:.3f}s".format( - i + 1, mIoU * 100, step_time)) - - average_time = sum(list_time) / len(list_time) - print("Evaluate: Average mIoU: {:.3f}, Average time: {:.3f}" - .format(mIoU * 100, average_time)) - - def _mask_transform(self, mask): - mask = self._class_to_index(np.array(mask).astype('int32')) - return torch.LongTensor(np.array(mask).astype('int32')) - - def _class_to_index(self, mask): - # assert the value - values = np.unique(mask) - self._key = np.array([-1, -1, -1, -1, -1, -1, - -1, -1, 0, 1, -1, -1, - 2, 3, 4, -1, -1, -1, - 5, -1, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, - -1, -1, 16, 17, 18]) - self._mapping = np.array(range(-1, len(self._key) - 1)).astype('int32') - for value in values: - assert (value in self._mapping) - - index = np.digitize(mask.ravel(), self._mapping, right=True) - - return self._key[index].reshape(mask.shape) - - def file2tensor(self, annotation_file): - - filepath = annotation_file + '_2.bin' - size = os.path.getsize(filepath) - res = [] - L = int(size/4) - binfile = open(filepath, 'rb') - for i in range(L): - data = binfile.read(4) - num = struct.unpack('f', data) - res.append(num[0]) - binfile.close() - - dim_res = np.array(res).reshape(1,19,65,129) - tensor_res = torch.tensor(dim_res, dtype=torch.float32) - interp = nn.Upsample(size=(1024, 2048), mode='bilinear', align_corners=True) - tensor_res = interp(tensor_res) - print(filepath, tensor_res.dtype, tensor_res.shape) - - return tensor_res - - -def _get_city_pairs(folder, split='train'): - def get_path_pairs(img_folder, mask_folder): - img_paths = [] - mask_paths = [] - for root, _, files in os.walk(img_folder): - for filename in files: - if filename.endswith('.png'): - imgpath = os.path.join(root, filename) - foldername = os.path.basename(os.path.dirname(imgpath)) - maskname = filename.replace('leftImg8bit', 'gtFine_labelIds') - maskpath = os.path.join(mask_folder, foldername, maskname) - if os.path.isfile(imgpath) and os.path.isfile(maskpath): - img_paths.append(imgpath) - mask_paths.append(maskpath) - else: - print('cannot find the mask or image:', imgpath, maskpath) - print('Found {} images in the folder {}'.format(len(img_paths), img_folder)) - return img_paths, mask_paths - - if split in ('train', 'val'): - # "./Cityscapes/leftImg8bit/train" or "./Cityscapes/leftImg8bit/val" - img_folder = os.path.join(folder, 'leftImg8bit/' + split) - # "./Cityscapes/gtFine/train" or "./Cityscapes/gtFine/val" - mask_folder = os.path.join(folder, 'gtFine/' + split) - # img_paths mask_paths - img_paths, mask_paths = get_path_pairs(img_folder, mask_folder) - return img_paths, mask_paths - return img_paths, mask_paths - - -if __name__ == '__main__': - - try: - # dataset file path - cityscapes_path = sys.argv[1] - # txt file path - folder_davinci_target = sys.argv[2] - # the path to store the results json path - outdir = sys.argv[3] - - except IndexError: - print("Stopped!") - exit(1) - - if not (os.path.exists(cityscapes_path)): - print("config file folder does not exist.") - if not (os.path.exists(folder_davinci_target)): - print("target file folder does not exist.") - if not (os.path.exists(outdir)): - print("output file folder does not exist.") - os.makedirs(outdir) - - evaluator = Evaluator(cityscapes_path, folder_davinci_target, outdir) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import time +import sys +import torch +import numpy as np +import torch.nn as nn +import struct +from PIL import Image + +def fast_hist(a, b, n): + k = (a >= 0) & (a < n) + return np.bincount(n * a[k].astype(int) + b[k], minlength=n ** 2).reshape(n, n) + + +def per_class_iu(hist): + return np.diag(hist) / (hist.sum(1) + hist.sum(0) - np.diag(hist)) + + +class Evaluator(object): + def __init__(self, cityscapes_path, folder_davinci_target, outdir): + + loc = "cpu" + self.device = torch.device(loc) + print("===device===:",self.device) + # get valid dataset images and targets + self.image_paths, self.mask_paths = _get_city_pairs(cityscapes_path, "val") + + self.annotation_file_path = folder_davinci_target + + self.outdir = outdir + + def eval(self): + + print("Start validation, Total sample: {:d}".format(len(self.image_paths))) + list_time = [] + + hist = np.zeros((19, 19)) + for i in range(len(self.image_paths)): + filename = os.path.basename(self.image_paths[i]) + annotation_file = os.path.join(self.annotation_file_path, filename.split('.')[0]) + + mask = Image.open(self.mask_paths[i]) # mask shape: (W,H) + mask = mask.resize((2048,1024),Image.NEAREST) + mask = self._mask_transform(mask) # mask shape: (H,w) + mask = mask.to(self.device) + + with torch.no_grad(): + start_time = time.time() + outputs = self.file2tensor(annotation_file).to(self.device) + end_time = time.time() + + outputs_ = outputs.numpy().squeeze().transpose(1, 2, 0) + outputs_ = np.argmax(outputs_, axis=2) + hist += fast_hist(mask.cpu().numpy().flatten(), outputs_.flatten(), 19) + inters_over_union_classes = per_class_iu(hist) + mIoU = np.nanmean(inters_over_union_classes) + step_time = end_time - start_time + + list_time.append(step_time) + + print("Sample: {:d}, mIoU: {:.3f}, time: {:.3f}s".format( + i + 1, mIoU * 100, step_time)) + + average_time = sum(list_time) / len(list_time) + print("Evaluate: Average mIoU: {:.3f}, Average time: {:.3f}" + .format(mIoU * 100, average_time)) + + def _mask_transform(self, mask): + mask = self._class_to_index(np.array(mask).astype('int32')) + return torch.LongTensor(np.array(mask).astype('int32')) + + def _class_to_index(self, mask): + # assert the value + values = np.unique(mask) + self._key = np.array([-1, -1, -1, -1, -1, -1, + -1, -1, 0, 1, -1, -1, + 2, 3, 4, -1, -1, -1, + 5, -1, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, + -1, -1, 16, 17, 18]) + self._mapping = np.array(range(-1, len(self._key) - 1)).astype('int32') + for value in values: + assert (value in self._mapping) + + index = np.digitize(mask.ravel(), self._mapping, right=True) + + return self._key[index].reshape(mask.shape) + + def file2tensor(self, annotation_file): + + filepath = annotation_file + '_2.bin' + size = os.path.getsize(filepath) + res = [] + L = int(size/4) + binfile = open(filepath, 'rb') + for i in range(L): + data = binfile.read(4) + num = struct.unpack('f', data) + res.append(num[0]) + binfile.close() + + dim_res = np.array(res).reshape(1,19,65,129) + tensor_res = torch.tensor(dim_res, dtype=torch.float32) + interp = nn.Upsample(size=(1024, 2048), mode='bilinear', align_corners=True) + tensor_res = interp(tensor_res) + print(filepath, tensor_res.dtype, tensor_res.shape) + + return tensor_res + + +def _get_city_pairs(folder, split='train'): + def get_path_pairs(img_folder, mask_folder): + img_paths = [] + mask_paths = [] + for root, _, files in os.walk(img_folder): + for filename in files: + if filename.endswith('.png'): + imgpath = os.path.join(root, filename) + foldername = os.path.basename(os.path.dirname(imgpath)) + maskname = filename.replace('leftImg8bit', 'gtFine_labelIds') + maskpath = os.path.join(mask_folder, foldername, maskname) + if os.path.isfile(imgpath) and os.path.isfile(maskpath): + img_paths.append(imgpath) + mask_paths.append(maskpath) + else: + print('cannot find the mask or image:', imgpath, maskpath) + print('Found {} images in the folder {}'.format(len(img_paths), img_folder)) + return img_paths, mask_paths + + if split in ('train', 'val'): + # "./Cityscapes/leftImg8bit/train" or "./Cityscapes/leftImg8bit/val" + img_folder = os.path.join(folder, 'leftImg8bit/' + split) + # "./Cityscapes/gtFine/train" or "./Cityscapes/gtFine/val" + mask_folder = os.path.join(folder, 'gtFine/' + split) + # img_paths mask_paths + img_paths, mask_paths = get_path_pairs(img_folder, mask_folder) + return img_paths, mask_paths + return img_paths, mask_paths + + +if __name__ == '__main__': + + try: + # dataset file path + cityscapes_path = sys.argv[1] + # txt file path + folder_davinci_target = sys.argv[2] + # the path to store the results json path + outdir = sys.argv[3] + + except IndexError: + print("Stopped!") + exit(1) + + if not (os.path.exists(cityscapes_path)): + print("config file folder does not exist.") + if not (os.path.exists(folder_davinci_target)): + print("target file folder does not exist.") + if not (os.path.exists(outdir)): + print("output file folder does not exist.") + os.makedirs(outdir) + + evaluator = Evaluator(cityscapes_path, folder_davinci_target, outdir) evaluator.eval() \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/IntraDA/intrada_preprocess.py b/ACL_PyTorch/contrib/cv/segmentation/IntraDA/intrada_preprocess.py index f3f814586a..3f6cc3819e 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/IntraDA/intrada_preprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/IntraDA/intrada_preprocess.py @@ -1,67 +1,67 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import torch -import sys -import numpy as np -from PIL import Image -from tqdm import tqdm -from torchvision import transforms -from torchvision.transforms.functional import InterpolationMode - - -def get_img_path(img_folder): - img_paths = [] - for root, dirs, files in os.walk(img_folder): - for f in files: - if f.endswith('.png'): - print(os.path.join(root, f)) - img_paths.append(os.path.join(root, f)) - return img_paths - -def flip(x, dim): - xsize = x.size() - dim = x.dim() + dim if dim < 0 else dim - x = x.view(-1, *xsize[dim:]) - x = x.view(x.size(0), x.size(1), -1)[:, getattr(torch.arange(x.size(1)-1, - -1, -1), ('cpu','cuda')[x.is_cuda])().long(), :] - return x.view(xsize) - -def _img_transform(image): - image_transform = transforms.Compose([ - transforms.Resize((512,1024),InterpolationMode.BICUBIC), - transforms.ToTensor()]) - image = image_transform(image) - image *= 255. - image = flip(image, 0) - image -= np.array((104.00698793, 116.66876762, 122.67891434), dtype=np.float32).reshape(-1,1,1) - return image - -if __name__ == '__main__': - cityscapes_path = sys.argv[1] - bin_path = sys.argv[2] - if os.path.exists(bin_path) is False: - os.mkdir(bin_path) - - split = "val" - img_folder = os.path.join(cityscapes_path, 'leftImg8bit/' + split) - img_paths = get_img_path(img_folder) - - for i in tqdm(range(len(img_paths))): - filename = os.path.basename(img_paths[i]) - image = Image.open(img_paths[i]).convert('RGB') # image shape: (W,H,3) - image = _img_transform(image) # image shape: (3,H,W) [0,1] - image = torch.unsqueeze(image, 0) # image shape: (1,3,H,W) [0,1] - image = np.array(image).astype(np.float32) - image.tofile(os.path.join(bin_path, filename.split('.')[0] + '.bin')) # save bin +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import torch +import sys +import numpy as np +from PIL import Image +from tqdm import tqdm +from torchvision import transforms +from torchvision.transforms.functional import InterpolationMode + + +def get_img_path(img_folder): + img_paths = [] + for root, dirs, files in os.walk(img_folder): + for f in files: + if f.endswith('.png'): + print(os.path.join(root, f)) + img_paths.append(os.path.join(root, f)) + return img_paths + +def flip(x, dim): + xsize = x.size() + dim = x.dim() + dim if dim < 0 else dim + x = x.view(-1, *xsize[dim:]) + x = x.view(x.size(0), x.size(1), -1)[:, getattr(torch.arange(x.size(1)-1, + -1, -1), ('cpu','cuda')[x.is_cuda])().long(), :] + return x.view(xsize) + +def _img_transform(image): + image_transform = transforms.Compose([ + transforms.Resize((512,1024),InterpolationMode.BICUBIC), + transforms.ToTensor()]) + image = image_transform(image) + image *= 255. + image = flip(image, 0) + image -= np.array((104.00698793, 116.66876762, 122.67891434), dtype=np.float32).reshape(-1,1,1) + return image + +if __name__ == '__main__': + cityscapes_path = sys.argv[1] + bin_path = sys.argv[2] + if os.path.exists(bin_path) is False: + os.mkdir(bin_path) + + split = "val" + img_folder = os.path.join(cityscapes_path, 'leftImg8bit/' + split) + img_paths = get_img_path(img_folder) + + for i in tqdm(range(len(img_paths))): + filename = os.path.basename(img_paths[i]) + image = Image.open(img_paths[i]).convert('RGB') # image shape: (W,H,3) + image = _img_transform(image) # image shape: (3,H,W) [0,1] + image = torch.unsqueeze(image, 0) # image shape: (1,3,H,W) [0,1] + image = np.array(image).astype(np.float32) + image.tofile(os.path.join(bin_path, filename.split('.')[0] + '.bin')) # save bin diff --git a/ACL_PyTorch/contrib/cv/segmentation/IntraDA/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/segmentation/IntraDA/modelzoo_level.txt index d44ba5698b..70801afc42 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/IntraDA/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/segmentation/IntraDA/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/IntraDA/requirements.txt b/ACL_PyTorch/contrib/cv/segmentation/IntraDA/requirements.txt index 7b6bc2994b..f83a7c4267 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/IntraDA/requirements.txt +++ b/ACL_PyTorch/contrib/cv/segmentation/IntraDA/requirements.txt @@ -1,6 +1,6 @@ -torch == 1.8.0 -torchvision == 0.9.0 -onnx == 1.9.0 -numpy == 1.21.1 -opencv-python == 4.4.0.46 +torch == 1.8.0 +torchvision == 0.9.0 +onnx == 1.9.0 +numpy == 1.21.1 +opencv-python == 4.4.0.46 Pillow == 8.0.1 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/PSPnet/LICENSE b/ACL_PyTorch/contrib/cv/segmentation/PSPnet/LICENSE index 7615b4e85f..72f817fb44 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/PSPnet/LICENSE +++ b/ACL_PyTorch/contrib/cv/segmentation/PSPnet/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/PSPnet/README.md b/ACL_PyTorch/contrib/cv/segmentation/PSPnet/README.md index 4f07558723..2e6abee642 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/PSPnet/README.md +++ b/ACL_PyTorch/contrib/cv/segmentation/PSPnet/README.md @@ -1,406 +1,406 @@ -# 基于开源mmsegmentation预训练的PSPnet Onnx模型端到端推理指导 -- [1 模型概述](#1-模型概述) - - [1.1 论文地址](#11-论文地址) - - [1.2 代码地址](#12-代码地址) -- [2 环境说明](#2-环境说明) - - [2.1 深度学习框架](#21-深度学习框架) - - [2.2 python第三方库](#22-python第三方库) -- [3 模型转换](#3-模型转换) - - [3.1 pth转onnx模型](#31-pth转onnx模型) - - [3.2 onnx转om模型](#32-onnx转om模型) -- [4 数据集预处理](#4-数据集预处理) - - [4.1 数据集获取](#41-数据集获取) - - [4.2 数据集预处理](#42-数据集预处理) - - [4.3 生成数据集信息文件](#43-生成数据集信息文件) -- [5 离线推理](#5-离线推理) - - [5.1 benchmark工具概述](#51-benchmark工具概述) - - [5.2 离线推理](#52-离线推理) -- [6 精度对比](#6-精度对比) - - [6.1 离线推理精度统计](#61-离线推理精度统计) - - [6.2 开源精度](#62-开源精度) - - [6.3 精度对比](#63-精度对比) -- [7 性能对比](#7-性能对比) - - [7.1 npu性能数据](#71-npu性能数据) - - [7.2 T4性能数据](#72-T4性能数据) - - [7.3 性能对比](#73-性能对比) - - - -## 1 模型概述 - -- **[论文地址](#11-论文地址)** - -- **[代码地址](#12-代码地址)** - -### 1.1 论文地址 -[PSPnet论文](https://arxiv.org/abs/1612.01105) -论文使用PPM(pyramid pooling module)和提出的PSPNet(pyramid scene parsing network),实现了通过融合different-region-based context获取全局context信息的能力。同时,PSPNet在多个数据集上实现了SOTA,取得ImageNet scene parsing challenge 2016、PASCAL VOC 2012 benchmark和Cityscapes benchmark的第1名。 - -### 1.2 代码地址 -[mmsegmentation框架PSPnet代码](https://github.com/open-mmlab/mmsegmentation/tree/master/configs/pspnet) -branch:master commit_id:52b4fa5b9a3d65d0745d8bccb08ac0b88c9407fe - -## 2 环境说明 - -- **[深度学习框架](#21-深度学习框架)** - -- **[python第三方库](#22-python第三方库)** - -### 2.1 深度学习框架 -``` -pytorch == 1.8.0 -torchvision == 0.9.0 -onnx == 1.9.0 -``` -**注意:** -> 转onnx的环境上pytorch需要安装1.8.0版本 - -### 2.2 python第三方库 -``` -numpy == 1.20.1 -opencv-python == 4.5.2.52 -``` - -**说明:** -> X86架构:opencv,pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:opencv,pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3 模型转换 - -- **[pth转onnx模型](#31-pth转onnx模型)** - -- **[onnx转om模型](#32-onnx转om模型)** - - -### 3.1 pth转onnx模型 - -1.获取pth权重文件 -[PSPnet基于mmsegmentation预训练的npu权重文件](https://download.openmmlab.com/mmsegmentation/v0.5/pspnet/pspnet_r50-d8_512x512_20k_voc12aug/pspnet_r50-d8_512x512_20k_voc12aug_20200617_101958-ed5dfbd9.pth) -文件md5sum: c563f7683bab2a869fe095a9eb801f6c - -2.mmsegmentation源码安装 -```shell -pip3.7 install mmcv-full==1.3.10 -git clone https://github.com/open-mmlab/mmsegmentation.git -cd mmsegmentation -如果修改了模型代码,交付了{model_name}.diff -patch -p1 < ../{model_name}.diff -如果模型代码需要安装,则安装模型代码(如果没有安装脚本,pth2onnx等脚本需要引用模型代码的类或函数,可通过sys.path.append(r"./pytorch-nested-unet")添加搜索路径的方式) -pip3.7 install -e . # or "python3.7 setup.py develop" -cd .. -``` - - **说明:** -> 安装所需的依赖说明请参考mmsegmentation/docs/get_started.md - - -3.使用tools里的pytorch2onnx.py文件,运行如下命令,生成对应的onnx模型: -```shell -python3.7 mmsegmentation/tools/pytorch2onnx.py mmsegmentation/configs/pspnet/pspnet_r50-d8_512x512_20k_voc12aug.py --checkpoint pspnet_r50-d8_512x512_20k_voc12aug_20200617_101958-ed5dfbd9.pth --output-file pspnet_r50-d8_512x512_20k_voc12aug.onnx --shape 500 500 -``` -4.通过onnx simplifier简化onnx模型 -```shell -python3.7 -m onnxsim --input-shape="1,3,500,500" pspnet_r50-d8_512x512_20k_voc12aug.onnx pspnet_r50-d8_512x512_20k_voc12aug_sim.onnx -``` - **模型转换要点:** -> 导出的onnx为固定batch1,不是动态batch。 - -### 3.2 onnx转om模型 - -1.设置环境变量 -```shell -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp -export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest/ -``` -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN 5.0.2 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373),如果存在多余输出节点,需要指定输出节点以去除无用输出,节点序号可能会因网络结构不同而不同,使用netron开源可视化工具查看具体的输出节点名: -生成bs1的om模型: -```shell -atc --framework=5 --model=pspnet_r50-d8_512x512_20k_voc12aug_sim.onnx --output=pspnet_r50-d8_512x512_20k_voc12aug_sim_bs1 --input_format=NCHW --input_shape=" input:1,3,500,500" --log=debug --soc_version=Ascend310 --input_fp16_nodes=input -``` -生成bs16的om模型: -```shell -atc --framework=5 --model=pspnet_r50-d8_512x512_20k_voc12aug_sim.onnx --output=pspnet_r50-d8_512x512_20k_voc12aug_sim_bs16 --input_format=NCHW --input_shape=" input:16,3,500,500" --log=debug --soc_version=Ascend310 --input_fp16_nodes=input -``` - **模型转换要点:** -> 通过input_fp16_nodes将输入的数据精度改为fp16,提升性能。 - -## 4 数据集预处理 - -- **[数据集获取](#41-数据集获取)** - -- **[数据集预处理](#42-数据集预处理)** - -- **[生成数据集信息文件](#43-生成数据集信息文件)** - -### 4.1 数据集获取 -该模型使用[VOC2012官网](http://host.robots.ox.ac.uk/pascal/VOC/voc2012/index.html)的VOC2012的1449张验证集进行测试,图片与对应ground truth分别存放在/opt/npu/VOCdevkit/VOC2012/JPEGImages/与/opt/npu/VOCdevkit/VOC2012/SegmentationClass/。 - -### 4.2 数据集预处理 -1.预处理脚本mmsegmentation_voc2012_preprocess.py - -2.执行预处理脚本,生成数据集预处理后的bin文件 -```shell -python3.7 mmsegmentation_voc2012_preprocess.py --image_folder_path=/opt/npu/VOCdevkit/VOC2012/JPEGImages/ --split=/opt/npu/VOCdevkit/VOC2012/ImageSets/Segmentation/val.txt --bin_folder_path=./voc12_bin/ -``` -### 4.3 生成数据集信息文件 -1.生成数据集信息文件脚本get_info.py - -2.执行生成数据集信息脚本,生成数据集信息文件 -```shell -python3.7 get_info.py bin ./voc12_bin voc12.info 500 500 -``` -第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 -## 5 离线推理 - -- **[benchmark工具概述](#51-benchmark工具概述)** - -- **[离线推理](#52-离线推理)** - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN 5.0.2 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) - -### 5.2 离线推理 - -1.设置环境变量 -```shell -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp -export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest/ -``` -2.执行离线推理 -```shell -./benchmark.${arch} -model_type=vision -om_path=pspnet_r50-d8_512x512_20k_voc12aug_sim_fp16_bs1.om -device_id=0 -batch_size=1 -input_text_path=voc12.info -input_width=500 -input_height=500 -useDvpp=false -output_binary=true - -./benchmark.${arch} -model_type=vision -om_path=pspnet_r50-d8_512x512_20k_voc12aug_sim_fp16_bs16.om -device_id=1 -batch_size=16 -input_text_path=voc12.info -input_width=500 -input_height=500 -useDvpp=false -output_binary=true -``` - **注意:** -> onnx的输出是int64,但是om的输出是int32 - -输出结果默认保存在当前目录result/dumpOutput_device0,模型有一个输出,每个输入对应的输出对应_1.bin文件 -``` -输出 shape 数据类型 数据含义 -output1 1 * 1 * 500 * 500 int32 8位图像 -``` - -## 6 精度对比 - -- **[离线推理精度](#61-离线推理精度)** -- **[开源精度](#62-开源精度)** -- **[精度对比](#63-精度对比)** - -### 6.1 离线推理精度统计 - -1.调用mmsegmentation_voc2012_postprocess.py评测bs1的mIoU精度: -```shell -python3.7 get_info.py jpg /opt/npu/VOCdevkit/VOC2012/JPEGImages/ voc12_jpg.info - -python3.7 mmsegmentation_voc2012_postprocess.py --bin_data_path=./result/dumpOutput_device0 --test_annotation=./voc12_jpg.info --img_dir=/opt/npu/VOCdevkit/VOC2012/JPEGImages --ann_dir=/opt/npu/VOCdevkit/VOC2012/SegmentationClass --split=/opt/npu/VOCdevkit/VOC2012/ImageSets/Segmentation/val.txt --net_input_width=500 --net_input_height=500 -``` -第一个参数为benchmark推理结果,第二个为原始图片信息文件,第三个为原始图片位置,第四个为验证图片位置,第五个图片的split,第六七个为网宽高 -执行完后会打印出精度: -``` -per class results: - -+-------------+-------+-------+ -| Class | IoU | Acc | -+-------------+-------+-------+ -| background | 93.78 | 97.28 | -| aeroplane | 87.46 | 94.06 | -| bicycle | 41.32 | 88.9 | -| bird | 86.48 | 91.68 | -| boat | 70.01 | 83.3 | -| bottle | 76.2 | 84.19 | -| bus | 92.78 | 96.14 | -| car | 85.56 | 92.34 | -| cat | 91.47 | 96.61 | -| chair | 35.65 | 46.37 | -| cow | 89.62 | 93.35 | -| diningtable | 55.73 | 59.82 | -| dog | 86.24 | 92.88 | -| horse | 88.84 | 93.02 | -| motorbike | 83.75 | 92.17 | -| person | 83.81 | 91.12 | -| pottedplant | 60.77 | 67.82 | -| sheep | 87.55 | 91.34 | -| sofa | 49.2 | 59.29 | -| train | 85.96 | 91.59 | -| tvmonitor | 67.55 | 79.11 | -+-------------+-------+-------+ -Summary: - -+--------+-------+-------+-------+ -| Scope | mIoU | mAcc | aAcc | -+--------+-------+-------+-------+ -| global | 76.18 | 84.87 | 94.49 | -+--------+-------+-------+-------+ -``` - -2.调用mmsegmentation_voc2012_postprocess.py评测bs16的mIoU精度: -```shell -python3.7 get_info.py jpg /opt/npu/VOCdevkit/VOC2012/JPEGImages/ voc12_jpg.info - -python3.7 mmsegmentation_voc2012_postprocess.py --bin_data_path=./result/dumpOutput_device1 --test_annotation=./voc12_jpg.info --img_dir=/opt/npu/VOCdevkit/VOC2012/JPEGImages --ann_dir=/opt/npu/VOCdevkit/VOC2012/SegmentationClass --split=/opt/npu/VOCdevkit/VOC2012/ImageSets/Segmentation/val.txt --net_input_width=500 --net_input_height=500 -``` -第一个参数为benchmark推理结果,第二个为原始图片信息文件,第三个为原始图片位置,第四个为验证图片位置,第五个图片的split,第六七个为网宽高 -执行完后会打印出精度: -``` -per class results: - -+-------------+-------+-------+ -| Class | IoU | Acc | -+-------------+-------+-------+ -| background | 93.78 | 97.28 | -| aeroplane | 87.46 | 94.06 | -| bicycle | 41.32 | 88.9 | -| bird | 86.48 | 91.68 | -| boat | 70.01 | 83.3 | -| bottle | 76.2 | 84.19 | -| bus | 92.78 | 96.14 | -| car | 85.56 | 92.34 | -| cat | 91.47 | 96.61 | -| chair | 35.65 | 46.37 | -| cow | 89.62 | 93.35 | -| diningtable | 55.73 | 59.82 | -| dog | 86.24 | 92.88 | -| horse | 88.84 | 93.02 | -| motorbike | 83.75 | 92.17 | -| person | 83.81 | 91.12 | -| pottedplant | 60.77 | 67.82 | -| sheep | 87.55 | 91.34 | -| sofa | 49.2 | 59.29 | -| train | 85.96 | 91.59 | -| tvmonitor | 67.55 | 79.11 | -+-------------+-------+-------+ -Summary: - -+--------+-------+-------+-------+ -| Scope | mIoU | mAcc | aAcc | -+--------+-------+-------+-------+ -| global | 76.18 | 84.87 | 94.49 | -+--------+-------+-------+-------+ -``` - **精度调试:** -> 1.在线推理前处理图片是一定格式的动态分辨率,onnx将分辨率固定为512x512会导致精度下降些。 -> 2.分辨率在512x512时onnx离线推理的精度与om精度相同,分辨率改为500x500可以提升精度,使得mask的精度与开源相比更高 -> 3.单图调试 -> ``` -> python3.7 mmsegmentation/tools/test.py mmsegmentation/configs/pspnet/pspnet_r50-d8_512x512_20k_voc12aug.py pspnet_r50-d8_512x512_20k_voc12aug_20200617_101958-ed5dfbd9.pth --show -> python3.7 mmsegmentation/tools/pytorch2onnx.py mmsegmentation/configs/pspnet/pspnet_r50-d8_512x512_20k_voc12aug.py --checkpoint pspnet_r50-d8_512x512_20k_voc12aug_20200617_101958-ed5dfbd9.pth --output-file pspnet_r50-d8_512x512_20k_voc12aug.onnx --shape 500 500 --input-img 2011_003103.jpg --show --verify -> ``` - - -### 6.2 开源精度 -[官网精度](https://download.openmmlab.com/mmsegmentation/v0.5/pspnet/pspnet_r50-d8_512x512_20k_voc12aug/pspnet_r50-d8_512x512_20k_voc12aug_20200617_101958.log.json) - -``` -{"mode": "val", "epoch": 31, "iter": 20000, "lr": 0.0001, "mIoU": 0.76778, "mAcc": 0.85529, "aAcc": 0.94787} -``` -### 6.3 精度对比 -om推理bs1和bs16的mIoU精度均为0.7618,开源mIoU精度为0.76778,om精度下降小于1%,精度达标 - - -## 7 性能对比 - -- **[npu性能数据](#71-npu性能数据)** -- **[T4性能数据](#72-T4性能数据)** -- **[性能对比](#73-性能对比)** - -### 7.1 npu性能数据 -1.benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 -由于在线推理与onnx推理还不支持多batch,所以仅测om bs1,bs16的性能。 -1.benchmark工具在整个数据集上推理获得性能数据 -batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: -``` -[e2e] throughputRate: 7.85666, latency: 184430 -[data read] throughputRate: 37.4296, moduleLatency: 26.7168 -[preprocess] throughputRate: 28.1654, moduleLatency: 35.5045 -[infer] throughputRate: 7.91227, Interface throughputRate: 8.19018, moduleLatency: 126.139 -[post] throughputRate: 7.91221, moduleLatency: 126.387 -``` -Interface throughputRate: 7.91221,7.91221x4=31.64884即是batch1 310单卡吞吐率 - -batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: -``` -[e2e] throughputRate: 8.16118, latency: 177548 -[data read] throughputRate: 40.508, moduleLatency: 24.6865 -[preprocess] throughputRate: 29.1145, moduleLatency: 34.3472 -[infer] throughputRate: 8.21425, Interface throughputRate: 8.52684, moduleLatency: 121.508 -[post] throughputRate: 0.515815, moduleLatency: 1938.68 -``` -Interface throughputRate: 8.21425,8.21425x4=32.857即是batch16 310单卡吞吐率 - -2.npu纯推理性能 -batch1的性能,执行20次纯推理取均值,统计吞吐率与其倒数时延(benchmark的时延是单个数据的推理时间),npu性能是一个device执行的结果 -``` -./benchmark.x86_64 -round=20 -om_path=pspnet_r50-d8_512x512_20k_voc12aug_bs1.om -device_id=0 -batch_size=1 -``` -PureInfer_perf_of_pspnet_r50-d8_512x512_20k_voc12aug_bs1_in_device_0.txt: -``` -[INFO] PureInfer result saved in ./result/PureInfer_perf_of_pspnet_r50-d8_512x512_20k_voc12aug_bs1_in_device_0.txt ------------------PureInfer Performance Summary------------------ -[INFO] ave_throughputRate: 8.12674samples/s, ave_latency: 123.129ms ----------------------------------------------------------------- -``` - -batch6的性能,执行20次纯推理取均值,统计吞吐率与其倒数时延(benchmark的时延是单个数据的推理时间),npu性能是一个device执行的结果 -``` -./benchmark.x86_64 -round=20 -om_path=pspnet_r50-d8_512x512_20k_voc12aug_bs16.om -device_id=0 -batch_size=16 -``` -PureInfer_perf_of_pspnet_r50-d8_512x512_20k_voc12aug_bs16_in_device_0.txt: -``` -[INFO] PureInfer result saved in ./result/PureInfer_perf_of_pspnet_r50-d8_512x512_20k_voc12aug_bs16_in_device_0.txt ------------------PureInfer Performance Summary------------------ -[INFO] ave_throughputRate: 8.51957samples/s, ave_latency: 117.39ms ----------------------------------------------------------------- -``` -### 7.2 T4性能数据 -在装有T4卡的服务器上测试gpu性能,测试过程请确保卡没有运行其他任务,TensorRT版本:7.2.3.4,cuda版本:11.0,cudnn版本:8.2 -1.batch1性能: -``` -trtexec --onnx=pspnet_r50-d8_512x512_20k_voc12aug_sim.onnx --fp16 --shapes=input:1,3,500,500 -``` -gpu T4是4个device并行执行的结果,mean是时延(tensorrt的时延是batch个数据的推理时间),即吞吐率的倒数乘以batch。其中--fp16是算子精度,目前算子精度只测--fp16的。注意--shapes是onnx的输入节点名与shape,当onnx输入节点的batch为-1时,可以用同一个onnx文件测不同batch的性能,否则用固定batch的onnx测不同batch的性能不准。 -``` -[09/24/2021-04:17:29] [I] GPU Compute -[09/24/2021-04:17:29] [I] min: 15.829 ms -[09/24/2021-04:17:29] [I] max: 20.5302 ms -[09/24/2021-04:17:29] [I] mean: 16.2649 ms -[09/24/2021-04:17:29] [I] median: 16.0951 ms -[09/24/2021-04:17:29] [I] percentile: 19.1857 ms at 99% -[09/24/2021-04:17:29] [I] total compute time: 3.04154 s - -``` -batch1 t4单卡吞吐率:1000/(16.2649/1)=61.482fps - -2.batch16性能: -``` -trtexec --onnx=pspnet_r50-d8_512x512_20k_voc12aug_sim.onnx --fp16 --shapes=input:16,3,500,500 -``` -``` -[09/24/2021-04:25:43] [I] GPU Compute -[09/24/2021-04:25:43] [I] min: 15.7839 ms -[09/24/2021-04:25:43] [I] max: 20.8466 ms -[09/24/2021-04:25:43] [I] mean: 16.2072 ms -[09/24/2021-04:25:43] [I] median: 16.0396 ms -[09/24/2021-04:25:43] [I] percentile: 19.1329 ms at 99% -[09/24/2021-04:25:43] [I] total compute time: 3.03074 s -``` -batch16 t4单卡吞吐率:1000/(16.2072/1)=61.701fps - -### 7.3 性能对比 -batch1:7.91221x4 < 1000/(16.2649/1) -batch1:8.21425x4 < 1000/(16.2072/1) -310单个device的吞吐率乘4即单卡吞吐率比T4单卡的吞吐率小,故310性能低于T4性能,性能不达标。 - -**性能优化:** -> 由于onnx转om的过程中,两个avgpool算子的kernel size过大,导致被替换为aicpu算子,致使性能不足。需等优化底层算子后再进行测试。 - +# 基于开源mmsegmentation预训练的PSPnet Onnx模型端到端推理指导 +- [1 模型概述](#1-模型概述) + - [1.1 论文地址](#11-论文地址) + - [1.2 代码地址](#12-代码地址) +- [2 环境说明](#2-环境说明) + - [2.1 深度学习框架](#21-深度学习框架) + - [2.2 python第三方库](#22-python第三方库) +- [3 模型转换](#3-模型转换) + - [3.1 pth转onnx模型](#31-pth转onnx模型) + - [3.2 onnx转om模型](#32-onnx转om模型) +- [4 数据集预处理](#4-数据集预处理) + - [4.1 数据集获取](#41-数据集获取) + - [4.2 数据集预处理](#42-数据集预处理) + - [4.3 生成数据集信息文件](#43-生成数据集信息文件) +- [5 离线推理](#5-离线推理) + - [5.1 benchmark工具概述](#51-benchmark工具概述) + - [5.2 离线推理](#52-离线推理) +- [6 精度对比](#6-精度对比) + - [6.1 离线推理精度统计](#61-离线推理精度统计) + - [6.2 开源精度](#62-开源精度) + - [6.3 精度对比](#63-精度对比) +- [7 性能对比](#7-性能对比) + - [7.1 npu性能数据](#71-npu性能数据) + - [7.2 T4性能数据](#72-T4性能数据) + - [7.3 性能对比](#73-性能对比) + + + +## 1 模型概述 + +- **[论文地址](#11-论文地址)** + +- **[代码地址](#12-代码地址)** + +### 1.1 论文地址 +[PSPnet论文](https://arxiv.org/abs/1612.01105) +论文使用PPM(pyramid pooling module)和提出的PSPNet(pyramid scene parsing network),实现了通过融合different-region-based context获取全局context信息的能力。同时,PSPNet在多个数据集上实现了SOTA,取得ImageNet scene parsing challenge 2016、PASCAL VOC 2012 benchmark和Cityscapes benchmark的第1名。 + +### 1.2 代码地址 +[mmsegmentation框架PSPnet代码](https://github.com/open-mmlab/mmsegmentation/tree/master/configs/pspnet) +branch:master commit_id:52b4fa5b9a3d65d0745d8bccb08ac0b88c9407fe + +## 2 环境说明 + +- **[深度学习框架](#21-深度学习框架)** + +- **[python第三方库](#22-python第三方库)** + +### 2.1 深度学习框架 +``` +pytorch == 1.8.0 +torchvision == 0.9.0 +onnx == 1.9.0 +``` +**注意:** +> 转onnx的环境上pytorch需要安装1.8.0版本 + +### 2.2 python第三方库 +``` +numpy == 1.20.1 +opencv-python == 4.5.2.52 +``` + +**说明:** +> X86架构:opencv,pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:opencv,pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3 模型转换 + +- **[pth转onnx模型](#31-pth转onnx模型)** + +- **[onnx转om模型](#32-onnx转om模型)** + + +### 3.1 pth转onnx模型 + +1.获取pth权重文件 +[PSPnet基于mmsegmentation预训练的npu权重文件](https://download.openmmlab.com/mmsegmentation/v0.5/pspnet/pspnet_r50-d8_512x512_20k_voc12aug/pspnet_r50-d8_512x512_20k_voc12aug_20200617_101958-ed5dfbd9.pth) +文件md5sum: c563f7683bab2a869fe095a9eb801f6c + +2.mmsegmentation源码安装 +```shell +pip3.7 install mmcv-full==1.3.10 +git clone https://github.com/open-mmlab/mmsegmentation.git +cd mmsegmentation +如果修改了模型代码,交付了{model_name}.diff +patch -p1 < ../{model_name}.diff +如果模型代码需要安装,则安装模型代码(如果没有安装脚本,pth2onnx等脚本需要引用模型代码的类或函数,可通过sys.path.append(r"./pytorch-nested-unet")添加搜索路径的方式) +pip3.7 install -e . # or "python3.7 setup.py develop" +cd .. +``` + + **说明:** +> 安装所需的依赖说明请参考mmsegmentation/docs/get_started.md + + +3.使用tools里的pytorch2onnx.py文件,运行如下命令,生成对应的onnx模型: +```shell +python3.7 mmsegmentation/tools/pytorch2onnx.py mmsegmentation/configs/pspnet/pspnet_r50-d8_512x512_20k_voc12aug.py --checkpoint pspnet_r50-d8_512x512_20k_voc12aug_20200617_101958-ed5dfbd9.pth --output-file pspnet_r50-d8_512x512_20k_voc12aug.onnx --shape 500 500 +``` +4.通过onnx simplifier简化onnx模型 +```shell +python3.7 -m onnxsim --input-shape="1,3,500,500" pspnet_r50-d8_512x512_20k_voc12aug.onnx pspnet_r50-d8_512x512_20k_voc12aug_sim.onnx +``` + **模型转换要点:** +> 导出的onnx为固定batch1,不是动态batch。 + +### 3.2 onnx转om模型 + +1.设置环境变量 +```shell +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp +export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest/ +``` +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考[CANN 5.0.2 开发辅助工具指南 (推理) 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164868?idPath=23710424%7C251366513%7C22892968%7C251168373),如果存在多余输出节点,需要指定输出节点以去除无用输出,节点序号可能会因网络结构不同而不同,使用netron开源可视化工具查看具体的输出节点名: +生成bs1的om模型: +```shell +atc --framework=5 --model=pspnet_r50-d8_512x512_20k_voc12aug_sim.onnx --output=pspnet_r50-d8_512x512_20k_voc12aug_sim_bs1 --input_format=NCHW --input_shape=" input:1,3,500,500" --log=debug --soc_version=Ascend310 --input_fp16_nodes=input +``` +生成bs16的om模型: +```shell +atc --framework=5 --model=pspnet_r50-d8_512x512_20k_voc12aug_sim.onnx --output=pspnet_r50-d8_512x512_20k_voc12aug_sim_bs16 --input_format=NCHW --input_shape=" input:16,3,500,500" --log=debug --soc_version=Ascend310 --input_fp16_nodes=input +``` + **模型转换要点:** +> 通过input_fp16_nodes将输入的数据精度改为fp16,提升性能。 + +## 4 数据集预处理 + +- **[数据集获取](#41-数据集获取)** + +- **[数据集预处理](#42-数据集预处理)** + +- **[生成数据集信息文件](#43-生成数据集信息文件)** + +### 4.1 数据集获取 +该模型使用[VOC2012官网](http://host.robots.ox.ac.uk/pascal/VOC/voc2012/index.html)的VOC2012的1449张验证集进行测试,图片与对应ground truth分别存放在/opt/npu/VOCdevkit/VOC2012/JPEGImages/与/opt/npu/VOCdevkit/VOC2012/SegmentationClass/。 + +### 4.2 数据集预处理 +1.预处理脚本mmsegmentation_voc2012_preprocess.py + +2.执行预处理脚本,生成数据集预处理后的bin文件 +```shell +python3.7 mmsegmentation_voc2012_preprocess.py --image_folder_path=/opt/npu/VOCdevkit/VOC2012/JPEGImages/ --split=/opt/npu/VOCdevkit/VOC2012/ImageSets/Segmentation/val.txt --bin_folder_path=./voc12_bin/ +``` +### 4.3 生成数据集信息文件 +1.生成数据集信息文件脚本get_info.py + +2.执行生成数据集信息脚本,生成数据集信息文件 +```shell +python3.7 get_info.py bin ./voc12_bin voc12.info 500 500 +``` +第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 +## 5 离线推理 + +- **[benchmark工具概述](#51-benchmark工具概述)** + +- **[离线推理](#52-离线推理)** + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考[CANN 5.0.2 推理benchmark工具用户指南 01](https://support.huawei.com/enterprise/zh/doc/EDOC1100164874?idPath=23710424%7C251366513%7C22892968%7C251168373) + +### 5.2 离线推理 + +1.设置环境变量 +```shell +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp +export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest/ +``` +2.执行离线推理 +```shell +./benchmark.${arch} -model_type=vision -om_path=pspnet_r50-d8_512x512_20k_voc12aug_sim_fp16_bs1.om -device_id=0 -batch_size=1 -input_text_path=voc12.info -input_width=500 -input_height=500 -useDvpp=false -output_binary=true + +./benchmark.${arch} -model_type=vision -om_path=pspnet_r50-d8_512x512_20k_voc12aug_sim_fp16_bs16.om -device_id=1 -batch_size=16 -input_text_path=voc12.info -input_width=500 -input_height=500 -useDvpp=false -output_binary=true +``` + **注意:** +> onnx的输出是int64,但是om的输出是int32 + +输出结果默认保存在当前目录result/dumpOutput_device0,模型有一个输出,每个输入对应的输出对应_1.bin文件 +``` +输出 shape 数据类型 数据含义 +output1 1 * 1 * 500 * 500 int32 8位图像 +``` + +## 6 精度对比 + +- **[离线推理精度](#61-离线推理精度)** +- **[开源精度](#62-开源精度)** +- **[精度对比](#63-精度对比)** + +### 6.1 离线推理精度统计 + +1.调用mmsegmentation_voc2012_postprocess.py评测bs1的mIoU精度: +```shell +python3.7 get_info.py jpg /opt/npu/VOCdevkit/VOC2012/JPEGImages/ voc12_jpg.info + +python3.7 mmsegmentation_voc2012_postprocess.py --bin_data_path=./result/dumpOutput_device0 --test_annotation=./voc12_jpg.info --img_dir=/opt/npu/VOCdevkit/VOC2012/JPEGImages --ann_dir=/opt/npu/VOCdevkit/VOC2012/SegmentationClass --split=/opt/npu/VOCdevkit/VOC2012/ImageSets/Segmentation/val.txt --net_input_width=500 --net_input_height=500 +``` +第一个参数为benchmark推理结果,第二个为原始图片信息文件,第三个为原始图片位置,第四个为验证图片位置,第五个图片的split,第六七个为网宽高 +执行完后会打印出精度: +``` +per class results: + ++-------------+-------+-------+ +| Class | IoU | Acc | ++-------------+-------+-------+ +| background | 93.78 | 97.28 | +| aeroplane | 87.46 | 94.06 | +| bicycle | 41.32 | 88.9 | +| bird | 86.48 | 91.68 | +| boat | 70.01 | 83.3 | +| bottle | 76.2 | 84.19 | +| bus | 92.78 | 96.14 | +| car | 85.56 | 92.34 | +| cat | 91.47 | 96.61 | +| chair | 35.65 | 46.37 | +| cow | 89.62 | 93.35 | +| diningtable | 55.73 | 59.82 | +| dog | 86.24 | 92.88 | +| horse | 88.84 | 93.02 | +| motorbike | 83.75 | 92.17 | +| person | 83.81 | 91.12 | +| pottedplant | 60.77 | 67.82 | +| sheep | 87.55 | 91.34 | +| sofa | 49.2 | 59.29 | +| train | 85.96 | 91.59 | +| tvmonitor | 67.55 | 79.11 | ++-------------+-------+-------+ +Summary: + ++--------+-------+-------+-------+ +| Scope | mIoU | mAcc | aAcc | ++--------+-------+-------+-------+ +| global | 76.18 | 84.87 | 94.49 | ++--------+-------+-------+-------+ +``` + +2.调用mmsegmentation_voc2012_postprocess.py评测bs16的mIoU精度: +```shell +python3.7 get_info.py jpg /opt/npu/VOCdevkit/VOC2012/JPEGImages/ voc12_jpg.info + +python3.7 mmsegmentation_voc2012_postprocess.py --bin_data_path=./result/dumpOutput_device1 --test_annotation=./voc12_jpg.info --img_dir=/opt/npu/VOCdevkit/VOC2012/JPEGImages --ann_dir=/opt/npu/VOCdevkit/VOC2012/SegmentationClass --split=/opt/npu/VOCdevkit/VOC2012/ImageSets/Segmentation/val.txt --net_input_width=500 --net_input_height=500 +``` +第一个参数为benchmark推理结果,第二个为原始图片信息文件,第三个为原始图片位置,第四个为验证图片位置,第五个图片的split,第六七个为网宽高 +执行完后会打印出精度: +``` +per class results: + ++-------------+-------+-------+ +| Class | IoU | Acc | ++-------------+-------+-------+ +| background | 93.78 | 97.28 | +| aeroplane | 87.46 | 94.06 | +| bicycle | 41.32 | 88.9 | +| bird | 86.48 | 91.68 | +| boat | 70.01 | 83.3 | +| bottle | 76.2 | 84.19 | +| bus | 92.78 | 96.14 | +| car | 85.56 | 92.34 | +| cat | 91.47 | 96.61 | +| chair | 35.65 | 46.37 | +| cow | 89.62 | 93.35 | +| diningtable | 55.73 | 59.82 | +| dog | 86.24 | 92.88 | +| horse | 88.84 | 93.02 | +| motorbike | 83.75 | 92.17 | +| person | 83.81 | 91.12 | +| pottedplant | 60.77 | 67.82 | +| sheep | 87.55 | 91.34 | +| sofa | 49.2 | 59.29 | +| train | 85.96 | 91.59 | +| tvmonitor | 67.55 | 79.11 | ++-------------+-------+-------+ +Summary: + ++--------+-------+-------+-------+ +| Scope | mIoU | mAcc | aAcc | ++--------+-------+-------+-------+ +| global | 76.18 | 84.87 | 94.49 | ++--------+-------+-------+-------+ +``` + **精度调试:** +> 1.在线推理前处理图片是一定格式的动态分辨率,onnx将分辨率固定为512x512会导致精度下降些。 +> 2.分辨率在512x512时onnx离线推理的精度与om精度相同,分辨率改为500x500可以提升精度,使得mask的精度与开源相比更高 +> 3.单图调试 +> ``` +> python3.7 mmsegmentation/tools/test.py mmsegmentation/configs/pspnet/pspnet_r50-d8_512x512_20k_voc12aug.py pspnet_r50-d8_512x512_20k_voc12aug_20200617_101958-ed5dfbd9.pth --show +> python3.7 mmsegmentation/tools/pytorch2onnx.py mmsegmentation/configs/pspnet/pspnet_r50-d8_512x512_20k_voc12aug.py --checkpoint pspnet_r50-d8_512x512_20k_voc12aug_20200617_101958-ed5dfbd9.pth --output-file pspnet_r50-d8_512x512_20k_voc12aug.onnx --shape 500 500 --input-img 2011_003103.jpg --show --verify +> ``` + + +### 6.2 开源精度 +[官网精度](https://download.openmmlab.com/mmsegmentation/v0.5/pspnet/pspnet_r50-d8_512x512_20k_voc12aug/pspnet_r50-d8_512x512_20k_voc12aug_20200617_101958.log.json) + +``` +{"mode": "val", "epoch": 31, "iter": 20000, "lr": 0.0001, "mIoU": 0.76778, "mAcc": 0.85529, "aAcc": 0.94787} +``` +### 6.3 精度对比 +om推理bs1和bs16的mIoU精度均为0.7618,开源mIoU精度为0.76778,om精度下降小于1%,精度达标 + + +## 7 性能对比 + +- **[npu性能数据](#71-npu性能数据)** +- **[T4性能数据](#72-T4性能数据)** +- **[性能对比](#73-性能对比)** + +### 7.1 npu性能数据 +1.benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。模型的性能以使用benchmark工具在整个数据集上推理得到bs1与bs16的性能数据为准,对于使用benchmark工具测试的batch4,8,32的性能数据在README.md中如下作记录即可。 +由于在线推理与onnx推理还不支持多batch,所以仅测om bs1,bs16的性能。 +1.benchmark工具在整个数据集上推理获得性能数据 +batch1的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_1_device_0.txt: +``` +[e2e] throughputRate: 7.85666, latency: 184430 +[data read] throughputRate: 37.4296, moduleLatency: 26.7168 +[preprocess] throughputRate: 28.1654, moduleLatency: 35.5045 +[infer] throughputRate: 7.91227, Interface throughputRate: 8.19018, moduleLatency: 126.139 +[post] throughputRate: 7.91221, moduleLatency: 126.387 +``` +Interface throughputRate: 7.91221,7.91221x4=31.64884即是batch1 310单卡吞吐率 + +batch16的性能,benchmark工具在整个数据集上推理后生成result/perf_vision_batchsize_16_device_1.txt: +``` +[e2e] throughputRate: 8.16118, latency: 177548 +[data read] throughputRate: 40.508, moduleLatency: 24.6865 +[preprocess] throughputRate: 29.1145, moduleLatency: 34.3472 +[infer] throughputRate: 8.21425, Interface throughputRate: 8.52684, moduleLatency: 121.508 +[post] throughputRate: 0.515815, moduleLatency: 1938.68 +``` +Interface throughputRate: 8.21425,8.21425x4=32.857即是batch16 310单卡吞吐率 + +2.npu纯推理性能 +batch1的性能,执行20次纯推理取均值,统计吞吐率与其倒数时延(benchmark的时延是单个数据的推理时间),npu性能是一个device执行的结果 +``` +./benchmark.x86_64 -round=20 -om_path=pspnet_r50-d8_512x512_20k_voc12aug_bs1.om -device_id=0 -batch_size=1 +``` +PureInfer_perf_of_pspnet_r50-d8_512x512_20k_voc12aug_bs1_in_device_0.txt: +``` +[INFO] PureInfer result saved in ./result/PureInfer_perf_of_pspnet_r50-d8_512x512_20k_voc12aug_bs1_in_device_0.txt +-----------------PureInfer Performance Summary------------------ +[INFO] ave_throughputRate: 8.12674samples/s, ave_latency: 123.129ms +---------------------------------------------------------------- +``` + +batch6的性能,执行20次纯推理取均值,统计吞吐率与其倒数时延(benchmark的时延是单个数据的推理时间),npu性能是一个device执行的结果 +``` +./benchmark.x86_64 -round=20 -om_path=pspnet_r50-d8_512x512_20k_voc12aug_bs16.om -device_id=0 -batch_size=16 +``` +PureInfer_perf_of_pspnet_r50-d8_512x512_20k_voc12aug_bs16_in_device_0.txt: +``` +[INFO] PureInfer result saved in ./result/PureInfer_perf_of_pspnet_r50-d8_512x512_20k_voc12aug_bs16_in_device_0.txt +-----------------PureInfer Performance Summary------------------ +[INFO] ave_throughputRate: 8.51957samples/s, ave_latency: 117.39ms +---------------------------------------------------------------- +``` +### 7.2 T4性能数据 +在装有T4卡的服务器上测试gpu性能,测试过程请确保卡没有运行其他任务,TensorRT版本:7.2.3.4,cuda版本:11.0,cudnn版本:8.2 +1.batch1性能: +``` +trtexec --onnx=pspnet_r50-d8_512x512_20k_voc12aug_sim.onnx --fp16 --shapes=input:1,3,500,500 +``` +gpu T4是4个device并行执行的结果,mean是时延(tensorrt的时延是batch个数据的推理时间),即吞吐率的倒数乘以batch。其中--fp16是算子精度,目前算子精度只测--fp16的。注意--shapes是onnx的输入节点名与shape,当onnx输入节点的batch为-1时,可以用同一个onnx文件测不同batch的性能,否则用固定batch的onnx测不同batch的性能不准。 +``` +[09/24/2021-04:17:29] [I] GPU Compute +[09/24/2021-04:17:29] [I] min: 15.829 ms +[09/24/2021-04:17:29] [I] max: 20.5302 ms +[09/24/2021-04:17:29] [I] mean: 16.2649 ms +[09/24/2021-04:17:29] [I] median: 16.0951 ms +[09/24/2021-04:17:29] [I] percentile: 19.1857 ms at 99% +[09/24/2021-04:17:29] [I] total compute time: 3.04154 s + +``` +batch1 t4单卡吞吐率:1000/(16.2649/1)=61.482fps + +2.batch16性能: +``` +trtexec --onnx=pspnet_r50-d8_512x512_20k_voc12aug_sim.onnx --fp16 --shapes=input:16,3,500,500 +``` +``` +[09/24/2021-04:25:43] [I] GPU Compute +[09/24/2021-04:25:43] [I] min: 15.7839 ms +[09/24/2021-04:25:43] [I] max: 20.8466 ms +[09/24/2021-04:25:43] [I] mean: 16.2072 ms +[09/24/2021-04:25:43] [I] median: 16.0396 ms +[09/24/2021-04:25:43] [I] percentile: 19.1329 ms at 99% +[09/24/2021-04:25:43] [I] total compute time: 3.03074 s +``` +batch16 t4单卡吞吐率:1000/(16.2072/1)=61.701fps + +### 7.3 性能对比 +batch1:7.91221x4 < 1000/(16.2649/1) +batch1:8.21425x4 < 1000/(16.2072/1) +310单个device的吞吐率乘4即单卡吞吐率比T4单卡的吞吐率小,故310性能低于T4性能,性能不达标。 + +**性能优化:** +> 由于onnx转om的过程中,两个avgpool算子的kernel size过大,导致被替换为aicpu算子,致使性能不足。需等优化底层算子后再进行测试。 + diff --git a/ACL_PyTorch/contrib/cv/segmentation/PSPnet/get_info.py b/ACL_PyTorch/contrib/cv/segmentation/PSPnet/get_info.py index b76d6739bc..d5cab0450c 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/PSPnet/get_info.py +++ b/ACL_PyTorch/contrib/cv/segmentation/PSPnet/get_info.py @@ -1,60 +1,60 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/PSPnet/mmsegmentation_voc2012_preprocess.py b/ACL_PyTorch/contrib/cv/segmentation/PSPnet/mmsegmentation_voc2012_preprocess.py index eda09af31e..793ea70de1 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/PSPnet/mmsegmentation_voc2012_preprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/PSPnet/mmsegmentation_voc2012_preprocess.py @@ -1,95 +1,95 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import argparse -import numpy as np -import cv2 -import mmcv -import torch - - -dataset_config = { - 'mean': (123.675, 116.28, 103.53), - 'std': (58.395, 57.12, 57.375) -} - - -tensor_height = 500 -tensor_width = 500 - - -def resize(img, size): - old_h = img.shape[0] - old_w = img.shape[1] - scale_ratio = min(size[0] / old_w, size[1] / old_h) - new_w = int(np.floor(old_w * scale_ratio)) - new_h = int(np.floor(old_h * scale_ratio)) - resized_img = mmcv.imresize(img, (new_w, new_h), backend='cv2') - return resized_img - - -def voc2012_preprocess(input_image, output_bin_path): - img_name = input_image.split('/')[-1] - bin_name = img_name.split('.')[0] + ".bin" - bin_fl = os.path.join(output_bin_path, bin_name) - - one_img = mmcv.imread(os.path.join(input_image), backend='cv2') - one_img = resize(one_img, (tensor_width, tensor_height)) - mean = np.array(dataset_config['mean'], dtype=np.float16) - std = np.array(dataset_config['std'], dtype=np.float16) - one_img = mmcv.imnormalize(one_img, mean, std) - - h = one_img.shape[0] - w = one_img.shape[1] - pad_left = (tensor_width - w) // 2 - pad_top = (tensor_height - h) // 2 - pad_right = tensor_width - pad_left - w - pad_bottom = tensor_height - pad_top - h - one_img = mmcv.impad(one_img, padding=(pad_left, pad_top, pad_right, pad_bottom), pad_val=0) - one_img=one_img.astype(np.float16) - one_img = one_img.transpose(2, 0, 1) - one_img.tofile(bin_fl) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='preprocess of FCN-8s pytorch model') - parser.add_argument("--image_folder_path", default="/opt/npu/VOCdevkit/VOC2012/JPEGImages/", - help='image of dataset') - parser.add_argument("--split", default="/opt/npu/VOCdevkit/VOC2012/ImageSets/Segmentation/val.txt") - parser.add_argument("--bin_folder_path", default="./voc12_bin/", help='Preprocessed image buffer') - flags = parser.parse_args() - - if not os.path.exists(flags.bin_folder_path): - os.makedirs(flags.bin_folder_path) - - split = flags.split - img_suffix = '.jpg' - img_infos = [] - if split is not None: - with open(split) as f: - for line in f: - img_name = line.strip() - img_info = img_name + img_suffix - img_infos.append(img_info) - print(img_infos) - images = os.listdir(flags.image_folder_path) - - for image_name in images: - if not (image_name.endswith(".jpeg") or image_name.endswith(".JPEG") or image_name.endswith( - ".jpg") and image_name in img_infos): - continue - print("start to process image {}....".format(image_name)) - path_image = os.path.join(flags.image_folder_path, image_name) - voc2012_preprocess(path_image, flags.bin_folder_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import argparse +import numpy as np +import cv2 +import mmcv +import torch + + +dataset_config = { + 'mean': (123.675, 116.28, 103.53), + 'std': (58.395, 57.12, 57.375) +} + + +tensor_height = 500 +tensor_width = 500 + + +def resize(img, size): + old_h = img.shape[0] + old_w = img.shape[1] + scale_ratio = min(size[0] / old_w, size[1] / old_h) + new_w = int(np.floor(old_w * scale_ratio)) + new_h = int(np.floor(old_h * scale_ratio)) + resized_img = mmcv.imresize(img, (new_w, new_h), backend='cv2') + return resized_img + + +def voc2012_preprocess(input_image, output_bin_path): + img_name = input_image.split('/')[-1] + bin_name = img_name.split('.')[0] + ".bin" + bin_fl = os.path.join(output_bin_path, bin_name) + + one_img = mmcv.imread(os.path.join(input_image), backend='cv2') + one_img = resize(one_img, (tensor_width, tensor_height)) + mean = np.array(dataset_config['mean'], dtype=np.float16) + std = np.array(dataset_config['std'], dtype=np.float16) + one_img = mmcv.imnormalize(one_img, mean, std) + + h = one_img.shape[0] + w = one_img.shape[1] + pad_left = (tensor_width - w) // 2 + pad_top = (tensor_height - h) // 2 + pad_right = tensor_width - pad_left - w + pad_bottom = tensor_height - pad_top - h + one_img = mmcv.impad(one_img, padding=(pad_left, pad_top, pad_right, pad_bottom), pad_val=0) + one_img=one_img.astype(np.float16) + one_img = one_img.transpose(2, 0, 1) + one_img.tofile(bin_fl) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='preprocess of FCN-8s pytorch model') + parser.add_argument("--image_folder_path", default="/opt/npu/VOCdevkit/VOC2012/JPEGImages/", + help='image of dataset') + parser.add_argument("--split", default="/opt/npu/VOCdevkit/VOC2012/ImageSets/Segmentation/val.txt") + parser.add_argument("--bin_folder_path", default="./voc12_bin/", help='Preprocessed image buffer') + flags = parser.parse_args() + + if not os.path.exists(flags.bin_folder_path): + os.makedirs(flags.bin_folder_path) + + split = flags.split + img_suffix = '.jpg' + img_infos = [] + if split is not None: + with open(split) as f: + for line in f: + img_name = line.strip() + img_info = img_name + img_suffix + img_infos.append(img_info) + print(img_infos) + images = os.listdir(flags.image_folder_path) + + for image_name in images: + if not (image_name.endswith(".jpeg") or image_name.endswith(".JPEG") or image_name.endswith( + ".jpg") and image_name in img_infos): + continue + print("start to process image {}....".format(image_name)) + path_image = os.path.join(flags.image_folder_path, image_name) + voc2012_preprocess(path_image, flags.bin_folder_path) diff --git a/ACL_PyTorch/contrib/cv/segmentation/PSPnet/requirements.txt b/ACL_PyTorch/contrib/cv/segmentation/PSPnet/requirements.txt index b61b7bcdad..f86ad403f3 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/PSPnet/requirements.txt +++ b/ACL_PyTorch/contrib/cv/segmentation/PSPnet/requirements.txt @@ -1,5 +1,5 @@ -torch == 1.8.0 -torchvision == 0.9.0 -onnx == 1.9.0 -numpy == 1.20.1 +torch == 1.8.0 +torchvision == 0.9.0 +onnx == 1.9.0 +numpy == 1.20.1 opencv-python == 4.5.2.52 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/PSPnet/test/README.md b/ACL_PyTorch/contrib/cv/segmentation/PSPnet/test/README.md index c6363a7119..02d44da6c8 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/PSPnet/test/README.md +++ b/ACL_PyTorch/contrib/cv/segmentation/PSPnet/test/README.md @@ -1,31 +1,31 @@ -环境准备: - -1.数据集路径 -数据集统一放在/root/datasets/或/opt/npu/ -本模型数据集放在/opt/npu/ - -2.进入工作目录 -cd pspnet - -3.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -pip3.7 install -r requirements.txt - -4.获取、修改和安装模型代码 -pip3.7 install mmcv-full==1.3.10 -git clone https://github.com/open-mmlab/mmsegmentation.git -cd mmsegmentation -pip3.7 install -e . # or "python3.7 setup.py develop" -cd .. - -5.获取权重文件 -wget https://download.openmmlab.com/mmsegmentation/v0.5/pspnet/pspnet_r50-d8_512x512_20k_voc12aug/pspnet_r50-d8_512x512_20k_voc12aug_20200617_101958-ed5dfbd9.pth - -6.获取benchmark工具 -将benchmark.x86_64放在当前目录 - -7.310上执行,执行时确保device空闲 -bash test/pth2om.sh -bash test/eval_acc_perf.sh - -8.在t4环境上将onnx文件与perf_t4.sh放在同一目录 -然后执行bash perf_t4.sh,执行时确保gpu空闲 +环境准备: + +1.数据集路径 +数据集统一放在/root/datasets/或/opt/npu/ +本模型数据集放在/opt/npu/ + +2.进入工作目录 +cd pspnet + +3.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +pip3.7 install -r requirements.txt + +4.获取、修改和安装模型代码 +pip3.7 install mmcv-full==1.3.10 +git clone https://github.com/open-mmlab/mmsegmentation.git +cd mmsegmentation +pip3.7 install -e . # or "python3.7 setup.py develop" +cd .. + +5.获取权重文件 +wget https://download.openmmlab.com/mmsegmentation/v0.5/pspnet/pspnet_r50-d8_512x512_20k_voc12aug/pspnet_r50-d8_512x512_20k_voc12aug_20200617_101958-ed5dfbd9.pth + +6.获取benchmark工具 +将benchmark.x86_64放在当前目录 + +7.310上执行,执行时确保device空闲 +bash test/pth2om.sh +bash test/eval_acc_perf.sh + +8.在t4环境上将onnx文件与perf_t4.sh放在同一目录 +然后执行bash perf_t4.sh,执行时确保gpu空闲 diff --git a/ACL_PyTorch/contrib/cv/segmentation/PSPnet/test/parse.py b/ACL_PyTorch/contrib/cv/segmentation/PSPnet/test/parse.py index a0f253b055..27eae0d0ac 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/PSPnet/test/parse.py +++ b/ACL_PyTorch/contrib/cv/segmentation/PSPnet/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/README.md b/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/README.md index 5d027295ce..2213525e40 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/README.md +++ b/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/README.md @@ -1,67 +1,67 @@ -# SOLOV1模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -``` -pip install -r requirements.txt -``` -说明:PyTorch选用开源1.9.0版本 - - - -2.获取,修改与安装开源模型代码 -安装mmcv -``` -git clone https://github.com/open-mmlab/mmcv -b v0.2.16 -cd mmcv -python setup.py build_ext -python setup.py develop -cd .. -``` -获取SOLOv1代码 -``` -git clone https://github.com/WXinlong/SOLO.git -b master -cd SOLO -git reset --hard 95f3732d5fbb0d7c7044c7dd074f439d48a72ce5 -patch -p1 < ../MMDET.diff -patch -p1 < ../SOLOV1.diff -pip install -r requirements/build.txt -pip install -v -e . -cd .. -``` - - -3.获取权重文件 - -请从[原始开源代码仓](https://github.com/WXinlong/SOLO)下载SOLO_R50_1x模型的权重文件 - -4.数据集 - -数据集的获取请参考[原始开源代码仓](https://github.com/WXinlong/SOLO)的方式获取。请将val2017图片及其标注文件放入服务器/root/dataset/coco/文件夹,val2017目录存放coco数据集的验证集图片,annotations目录存放coco数据集的instances_val2017.json,文件目录结构如下: -``` -root -├── dataset -│ ├── coco -│ │ ├── annotations -│ │ ├── val2017 -``` - -5.[获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) -将benchmark.x86_64或benchmark.aarch64放到当前目录 - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 -``` -#启动脚本内1-2行为pth2onnx,3-4行为onnx2om,脚本执行完成后会生成SOLOV2.onnx、SOLOV2_sim.onnx、solov2.om三个文件。 -bash test/pth2om.sh -#启动脚本内9-21行为前处理,用以获取处理后的图片信息与bin文件;23-33为获取图片info文件,为推理做准备;35-42行为benchmark推理;44-51行为后处理,同时会输出模型测评的精度;57-63行为打印om推理性能。 -bash test/eval_acc_perf.sh --datasets_path=/root/datasets -``` - **评测结果:** -| 模型 | 在线推理精度 | 310离线推理精度 | 基准性能 | 310性能 | -| :------: | :------: | :------: | :------: | :------: | -| SOLOV1 bs1 | mAP:32.1% | mAP:32.1% | 5.1fps | 6.118fps | - +# SOLOV1模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +``` +pip install -r requirements.txt +``` +说明:PyTorch选用开源1.9.0版本 + + + +2.获取,修改与安装开源模型代码 +安装mmcv +``` +git clone https://github.com/open-mmlab/mmcv -b v0.2.16 +cd mmcv +python setup.py build_ext +python setup.py develop +cd .. +``` +获取SOLOv1代码 +``` +git clone https://github.com/WXinlong/SOLO.git -b master +cd SOLO +git reset --hard 95f3732d5fbb0d7c7044c7dd074f439d48a72ce5 +patch -p1 < ../MMDET.diff +patch -p1 < ../SOLOV1.diff +pip install -r requirements/build.txt +pip install -v -e . +cd .. +``` + + +3.获取权重文件 + +请从[原始开源代码仓](https://github.com/WXinlong/SOLO)下载SOLO_R50_1x模型的权重文件 + +4.数据集 + +数据集的获取请参考[原始开源代码仓](https://github.com/WXinlong/SOLO)的方式获取。请将val2017图片及其标注文件放入服务器/root/dataset/coco/文件夹,val2017目录存放coco数据集的验证集图片,annotations目录存放coco数据集的instances_val2017.json,文件目录结构如下: +``` +root +├── dataset +│ ├── coco +│ │ ├── annotations +│ │ ├── val2017 +``` + +5.[获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) +将benchmark.x86_64或benchmark.aarch64放到当前目录 + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 +``` +#启动脚本内1-2行为pth2onnx,3-4行为onnx2om,脚本执行完成后会生成SOLOV2.onnx、SOLOV2_sim.onnx、solov2.om三个文件。 +bash test/pth2om.sh +#启动脚本内9-21行为前处理,用以获取处理后的图片信息与bin文件;23-33为获取图片info文件,为推理做准备;35-42行为benchmark推理;44-51行为后处理,同时会输出模型测评的精度;57-63行为打印om推理性能。 +bash test/eval_acc_perf.sh --datasets_path=/root/datasets +``` + **评测结果:** +| 模型 | 在线推理精度 | 310离线推理精度 | 基准性能 | 310性能 | +| :------: | :------: | :------: | :------: | :------: | +| SOLOV1 bs1 | mAP:32.1% | mAP:32.1% | 5.1fps | 6.118fps | + 备注:离线模型不支持多batch。 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/get_info.py b/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/get_info.py index e0979bced8..fc3f14c7a3 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/get_info.py +++ b/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/get_info.py @@ -1,59 +1,59 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import mmcv -from mmdet.datasets import build_dataset -import pickle as pk - -ann_file = '/annotations/instances_val2017.json' -img_prefix = '/val2017/' - -if __name__ == '__main__': - image_src_path = sys.argv[1] - config_path = sys.argv[2] - bin_path = sys.argv[3] - meta_path = sys.argv[4] - info_name = sys.argv[5] - info_meta_name = sys.argv[6] - width = int(sys.argv[7]) - height = int(sys.argv[8]) - - cfg = mmcv.Config.fromfile(config_path) - cfg.data.test.ann_file = image_src_path + ann_file - cfg.data.test.img_prefix = image_src_path + img_prefix - - dataset = build_dataset(cfg.data.test) - - fp1 = open(info_name, "w") - fp2 = open(info_meta_name, "w") - - for idx in range(5000): - img_id = dataset.img_ids[idx] - fp1.write("{} {}/{:0>12d}.bin {} {}\n".format(idx, bin_path, img_id, width, height)) - fp_meta = open("%s/%012d.pk" % (meta_path, img_id), "rb") - meta = pk.load(fp_meta) - fp_meta.close() - fp2.write("{} {}/{:0>12d}.bin {} {} {} {}\n".format( - idx, - meta_path, - img_id, - meta['img_shape'][1], - meta['img_shape'][0], - meta['ori_shape'][1], - meta['ori_shape'][0] - )) - fp1.close() - fp2.close() - print("Get info done!") +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import mmcv +from mmdet.datasets import build_dataset +import pickle as pk + +ann_file = '/annotations/instances_val2017.json' +img_prefix = '/val2017/' + +if __name__ == '__main__': + image_src_path = sys.argv[1] + config_path = sys.argv[2] + bin_path = sys.argv[3] + meta_path = sys.argv[4] + info_name = sys.argv[5] + info_meta_name = sys.argv[6] + width = int(sys.argv[7]) + height = int(sys.argv[8]) + + cfg = mmcv.Config.fromfile(config_path) + cfg.data.test.ann_file = image_src_path + ann_file + cfg.data.test.img_prefix = image_src_path + img_prefix + + dataset = build_dataset(cfg.data.test) + + fp1 = open(info_name, "w") + fp2 = open(info_meta_name, "w") + + for idx in range(5000): + img_id = dataset.img_ids[idx] + fp1.write("{} {}/{:0>12d}.bin {} {}\n".format(idx, bin_path, img_id, width, height)) + fp_meta = open("%s/%012d.pk" % (meta_path, img_id), "rb") + meta = pk.load(fp_meta) + fp_meta.close() + fp2.write("{} {}/{:0>12d}.bin {} {} {} {}\n".format( + idx, + meta_path, + img_id, + meta['img_shape'][1], + meta['img_shape'][0], + meta['ori_shape'][1], + meta['ori_shape'][0] + )) + fp1.close() + fp2.close() + print("Get info done!") diff --git a/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/modelzoo_level.txt index bdc5dd889d..5a90c7c76e 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus: PERFECT \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/pth2onnx.py b/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/pth2onnx.py index 4fdf107ff0..2e2add1625 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/pth2onnx.py @@ -1,40 +1,40 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import argparse -import numpy as np -from mmdet.apis import init_detector - -input_names = ['input'] -output_names = ['seg_preds', 'cate_labels', 'cate_scores'] - - -def pth2onnx(args, fake_input): - model = init_detector(args.config, args.pth_path, device='cpu') - model.forward = model.simple_test - torch.onnx.export(model, fake_input, args.out, input_names=input_names, output_names=output_names, verbose=False, - opset_version=11) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--config', help='model config') - parser.add_argument('--out', help='onnx output name') - parser.add_argument('--pth_path', help='model pth path') - parser.add_argument('--shape', type=int, nargs='+', help='input image size hxw') - args = parser.parse_args() - assert len(args.shape) == 2 - fake_input = torch.randn(1, 3, args.shape[0], args.shape[1]) - pth2onnx(args, fake_input) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import argparse +import numpy as np +from mmdet.apis import init_detector + +input_names = ['input'] +output_names = ['seg_preds', 'cate_labels', 'cate_scores'] + + +def pth2onnx(args, fake_input): + model = init_detector(args.config, args.pth_path, device='cpu') + model.forward = model.simple_test + torch.onnx.export(model, fake_input, args.out, input_names=input_names, output_names=output_names, verbose=False, + opset_version=11) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--config', help='model config') + parser.add_argument('--out', help='onnx output name') + parser.add_argument('--pth_path', help='model pth path') + parser.add_argument('--shape', type=int, nargs='+', help='input image size hxw') + args = parser.parse_args() + assert len(args.shape) == 2 + fake_input = torch.randn(1, 3, args.shape[0], args.shape[1]) + pth2onnx(args, fake_input) diff --git a/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/requirements.txt b/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/requirements.txt index 565fab9665..3802263668 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/requirements.txt +++ b/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/requirements.txt @@ -1,6 +1,6 @@ -torch == 1.9.0 -torchvision == 0.10.0 -onnx == 1.9.0 -onnx-simplifier == 0.3.6 -onnxruntime == 1.8.0 +torch == 1.9.0 +torchvision == 0.10.0 +onnx == 1.9.0 +onnx-simplifier == 0.3.6 +onnxruntime == 1.8.0 numpy == 1.21.0 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/solov1_postprocess.py b/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/solov1_postprocess.py index 88bd4578dc..0caf6ee469 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/solov1_postprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/solov1_postprocess.py @@ -1,104 +1,104 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 mmcv -import numpy as np -import argparse -import torch -import torch.nn.functional as F -import pycocotools.mask as mask_util -from mmdet.core import coco_eval, results2json, results2json_segm -from mmdet.datasets import build_dataset - -ann_file = '/annotations/instances_val2017.json' -img_prefix = '/val2017/' - - -def get_masks(result, num_classes=80): - for cur_result in result: - masks = [[] for _ in range(num_classes)] - if cur_result is None: - return masks - seg_pred = cur_result[0].astype(np.uint8) - cate_label = cur_result[1].astype(np.int) - cate_score = cur_result[2].astype(np.float) - num_ins = seg_pred.shape[0] - for idx in range(num_ins): - cur_mask = seg_pred[idx, ...] - rle = mask_util.encode( - np.array(cur_mask[:, :, np.newaxis], order='F'))[0] - rst = (rle, cate_score[idx]) - masks[cate_label[idx]].append(rst) - return masks - - -def handle_seg(seg, img_shape, ori_shape, input_shape=(800, 1216), mask_thr=0.5): - seg = torch.tensor(seg) - h, w, = img_shape - pad_left = (input_shape[1] - w) // 2 - pad_top = (input_shape[0] - h) // 2 - seg = F.interpolate(seg.unsqueeze(0), - size=input_shape, - mode='bilinear')[:, :, pad_top:pad_top + h, pad_left:pad_left + w] - - seg = F.interpolate(seg, - size=ori_shape[:2], - mode='bilinear').squeeze(0) - seg = seg > mask_thr - return seg.numpy() - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--dataset_path') - parser.add_argument('--model_config') - parser.add_argument('--bin_data_path') - parser.add_argument('--meta_info') - parser.add_argument('--net_out_num', type=int) - parser.add_argument("--model_input_height", type=int, help='input tensor height') - parser.add_argument("--model_input_width", type=int, help='input tensor width') - - args = parser.parse_args() - - cfg = mmcv.Config.fromfile(args.model_config) - cfg.data.test.test_mode = True - cfg.data.test.ann_file = args.dataset_path + ann_file - cfg.data.test.img_prefix = args.dataset_path + img_prefix - dataset = build_dataset(cfg.data.test) - num_classes = len(dataset.CLASSES) - - results = [] - - fp = open(args.meta_info, "r") - for line in fp.readlines(): - _, file_path, img_w, img_h, ori_w, ori_h = line.split() - img_w = int(img_w) - img_h = int(img_h) - ori_w = int(ori_w) - ori_h = int(ori_h) - file_name = file_path.split("/")[1].replace(".bin", "") - result = [] - for idx in range(args.net_out_num): - if idx == 1: - result.append(np.fromfile("%s%s_%d.bin" % (args.bin_data_path, file_name, idx + 1), dtype=np.int32)) - else: - result.append(np.fromfile("%s%s_%d.bin" % (args.bin_data_path, file_name, idx + 1), dtype=np.float32)) - result[0].shape = (100, args.model_input_height // 4, args.model_input_width // 4) - result[0] = handle_seg(result[0], (img_h, img_w), (ori_h, ori_w), - (args.model_input_height, args.model_input_width)) - result = get_masks([result], num_classes) - results.append(result) - fp.close() - result_files = results2json_segm(dataset, results, "results_solo.pkl") - coco_eval(result_files, ["segm"], dataset.coco) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 mmcv +import numpy as np +import argparse +import torch +import torch.nn.functional as F +import pycocotools.mask as mask_util +from mmdet.core import coco_eval, results2json, results2json_segm +from mmdet.datasets import build_dataset + +ann_file = '/annotations/instances_val2017.json' +img_prefix = '/val2017/' + + +def get_masks(result, num_classes=80): + for cur_result in result: + masks = [[] for _ in range(num_classes)] + if cur_result is None: + return masks + seg_pred = cur_result[0].astype(np.uint8) + cate_label = cur_result[1].astype(np.int) + cate_score = cur_result[2].astype(np.float) + num_ins = seg_pred.shape[0] + for idx in range(num_ins): + cur_mask = seg_pred[idx, ...] + rle = mask_util.encode( + np.array(cur_mask[:, :, np.newaxis], order='F'))[0] + rst = (rle, cate_score[idx]) + masks[cate_label[idx]].append(rst) + return masks + + +def handle_seg(seg, img_shape, ori_shape, input_shape=(800, 1216), mask_thr=0.5): + seg = torch.tensor(seg) + h, w, = img_shape + pad_left = (input_shape[1] - w) // 2 + pad_top = (input_shape[0] - h) // 2 + seg = F.interpolate(seg.unsqueeze(0), + size=input_shape, + mode='bilinear')[:, :, pad_top:pad_top + h, pad_left:pad_left + w] + + seg = F.interpolate(seg, + size=ori_shape[:2], + mode='bilinear').squeeze(0) + seg = seg > mask_thr + return seg.numpy() + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--dataset_path') + parser.add_argument('--model_config') + parser.add_argument('--bin_data_path') + parser.add_argument('--meta_info') + parser.add_argument('--net_out_num', type=int) + parser.add_argument("--model_input_height", type=int, help='input tensor height') + parser.add_argument("--model_input_width", type=int, help='input tensor width') + + args = parser.parse_args() + + cfg = mmcv.Config.fromfile(args.model_config) + cfg.data.test.test_mode = True + cfg.data.test.ann_file = args.dataset_path + ann_file + cfg.data.test.img_prefix = args.dataset_path + img_prefix + dataset = build_dataset(cfg.data.test) + num_classes = len(dataset.CLASSES) + + results = [] + + fp = open(args.meta_info, "r") + for line in fp.readlines(): + _, file_path, img_w, img_h, ori_w, ori_h = line.split() + img_w = int(img_w) + img_h = int(img_h) + ori_w = int(ori_w) + ori_h = int(ori_h) + file_name = file_path.split("/")[1].replace(".bin", "") + result = [] + for idx in range(args.net_out_num): + if idx == 1: + result.append(np.fromfile("%s%s_%d.bin" % (args.bin_data_path, file_name, idx + 1), dtype=np.int32)) + else: + result.append(np.fromfile("%s%s_%d.bin" % (args.bin_data_path, file_name, idx + 1), dtype=np.float32)) + result[0].shape = (100, args.model_input_height // 4, args.model_input_width // 4) + result[0] = handle_seg(result[0], (img_h, img_w), (ori_h, ori_w), + (args.model_input_height, args.model_input_width)) + result = get_masks([result], num_classes) + results.append(result) + fp.close() + result_files = results2json_segm(dataset, results, "results_solo.pkl") + coco_eval(result_files, ["segm"], dataset.coco) diff --git a/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/solov1_preprocess.py b/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/solov1_preprocess.py index d82a93d367..448b1cc203 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/solov1_preprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/solov1_preprocess.py @@ -1,86 +1,86 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import argparse -import numpy as np -import cv2 -import mmcv -import torch -import pickle as pk -import multiprocessing - -flags = None - -def resize(img, size): - old_h = img.shape[0] - old_w = img.shape[1] - scale_ratio = min(size[0] / old_w, size[1] / old_h) - new_w = int(np.floor(old_w * scale_ratio)) - new_h = int(np.floor(old_h * scale_ratio)) - resized_img = mmcv.imresize(img, (new_w, new_h)) - return resized_img, scale_ratio - - -def gen_input_bin(file_batches, batch): - i = 0 - for file in file_batches[batch]: - i = i + 1 - print("batch", batch, file, "===", i) - - image = mmcv.imread(os.path.join(flags.image_src_path, file)) - ori_shape = image.shape - image, scale_factor = resize(image, (flags.model_input_width, flags.model_input_height)) - img_shape = image.shape - mean = np.array([123.675, 116.28, 103.53], dtype=np.float32) - std = np.array([58.395, 57.12, 57.375], dtype=np.float32) - image = mmcv.imnormalize(image, mean, std) - h = image.shape[0] - w = image.shape[1] - pad_left = (flags.model_input_width - w) // 2 - pad_top = (flags.model_input_height - h) // 2 - pad_right = flags.model_input_width - pad_left - w - pad_bottom = flags.model_input_height - pad_top - h - image = cv2.copyMakeBorder(image, pad_top, pad_bottom, pad_left, pad_right, cv2.BORDER_CONSTANT, value=0) - image = image.transpose(2, 0, 1) - image.tofile(os.path.join(flags.bin_file_path, file.split('.')[0] + ".bin")) - image_meta = {'img_shape': img_shape, 'scale_factor': scale_factor, 'ori_shape': ori_shape} - with open(os.path.join(flags.meta_file_path, file.split('.')[0] + ".pk"), "wb") as fp: - pk.dump(image_meta, fp) - - -def preprocess(): - files = os.listdir(flags.image_src_path) - file_batches = [files[i:i + 100] for i in range(0, 5000, 100) if files[i:i + 100] != []] - thread_pool = multiprocessing.Pool(len(file_batches)) - for batch in range(len(file_batches)): - thread_pool.apply_async(gen_input_bin, args=(file_batches, batch)) - thread_pool.close() - thread_pool.join() - print("in thread, except will not report! please ensure bin files generated.") - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='preprocess of MaskRCNN PyTorch model') - parser.add_argument("--image_src_path", default="/root/datasets/coco/val2017", help='image of dataset') - parser.add_argument("--bin_file_path", default="val2017_bin", help='Preprocessed image buffer') - parser.add_argument("--meta_file_path", default="val2017_bin_meta", help='Get image meta') - parser.add_argument("--model_input_height", default=800, type=int, help='input tensor height') - parser.add_argument("--model_input_width", default=1216, type=int, help='input tensor width') - flags = parser.parse_args() - if not os.path.exists(flags.bin_file_path): - os.makedirs(flags.bin_file_path) - if not os.path.exists(flags.meta_file_path): - os.makedirs(flags.meta_file_path) - preprocess() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import argparse +import numpy as np +import cv2 +import mmcv +import torch +import pickle as pk +import multiprocessing + +flags = None + +def resize(img, size): + old_h = img.shape[0] + old_w = img.shape[1] + scale_ratio = min(size[0] / old_w, size[1] / old_h) + new_w = int(np.floor(old_w * scale_ratio)) + new_h = int(np.floor(old_h * scale_ratio)) + resized_img = mmcv.imresize(img, (new_w, new_h)) + return resized_img, scale_ratio + + +def gen_input_bin(file_batches, batch): + i = 0 + for file in file_batches[batch]: + i = i + 1 + print("batch", batch, file, "===", i) + + image = mmcv.imread(os.path.join(flags.image_src_path, file)) + ori_shape = image.shape + image, scale_factor = resize(image, (flags.model_input_width, flags.model_input_height)) + img_shape = image.shape + mean = np.array([123.675, 116.28, 103.53], dtype=np.float32) + std = np.array([58.395, 57.12, 57.375], dtype=np.float32) + image = mmcv.imnormalize(image, mean, std) + h = image.shape[0] + w = image.shape[1] + pad_left = (flags.model_input_width - w) // 2 + pad_top = (flags.model_input_height - h) // 2 + pad_right = flags.model_input_width - pad_left - w + pad_bottom = flags.model_input_height - pad_top - h + image = cv2.copyMakeBorder(image, pad_top, pad_bottom, pad_left, pad_right, cv2.BORDER_CONSTANT, value=0) + image = image.transpose(2, 0, 1) + image.tofile(os.path.join(flags.bin_file_path, file.split('.')[0] + ".bin")) + image_meta = {'img_shape': img_shape, 'scale_factor': scale_factor, 'ori_shape': ori_shape} + with open(os.path.join(flags.meta_file_path, file.split('.')[0] + ".pk"), "wb") as fp: + pk.dump(image_meta, fp) + + +def preprocess(): + files = os.listdir(flags.image_src_path) + file_batches = [files[i:i + 100] for i in range(0, 5000, 100) if files[i:i + 100] != []] + thread_pool = multiprocessing.Pool(len(file_batches)) + for batch in range(len(file_batches)): + thread_pool.apply_async(gen_input_bin, args=(file_batches, batch)) + thread_pool.close() + thread_pool.join() + print("in thread, except will not report! please ensure bin files generated.") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='preprocess of MaskRCNN PyTorch model') + parser.add_argument("--image_src_path", default="/root/datasets/coco/val2017", help='image of dataset') + parser.add_argument("--bin_file_path", default="val2017_bin", help='Preprocessed image buffer') + parser.add_argument("--meta_file_path", default="val2017_bin_meta", help='Get image meta') + parser.add_argument("--model_input_height", default=800, type=int, help='input tensor height') + parser.add_argument("--model_input_width", default=1216, type=int, help='input tensor width') + flags = parser.parse_args() + if not os.path.exists(flags.bin_file_path): + os.makedirs(flags.bin_file_path) + if not os.path.exists(flags.meta_file_path): + os.makedirs(flags.meta_file_path) + preprocess() diff --git a/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/test/parse.py b/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/test/parse.py index b9c74f41d7..82af69cd18 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/test/parse.py +++ b/ACL_PyTorch/contrib/cv/segmentation/SOLOV1/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/README.md b/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/README.md index bc9a8f0bce..59d8bf9d7d 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/README.md +++ b/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/README.md @@ -1,67 +1,67 @@ -# SOLOV2模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -``` -pip install -r requirements.txt -``` -说明:PyTorch选用开源1.9.0版本 - - - -2.获取,修改与安装开源模型代码 -安装mmcv -``` -git clone https://github.com/open-mmlab/mmcv -b v0.2.16 -cd mmcv -python setup.py build_ext -python setup.py develop -cd .. -``` -获取SOLOv2代码 -``` -git clone https://github.com/WXinlong/SOLO.git -b master -cd SOLO -git reset --hard 95f3732d5fbb0d7c7044c7dd074f439d48a72ce5 -patch -p1 < ../MMDET.diff -patch -p1 < ../SOLOV2.diff -pip install -r requirements/build.txt -pip install -v -e . -cd .. -``` - - -3.获取权重文件 - -请从[原始开源代码仓](https://github.com/WXinlong/SOLO)下载SOLOv2_R50_1x模型的权重文件 - -4.数据集 - -数据集的获取请参考[原始开源代码仓](https://github.com/WXinlong/SOLO)的方式获取。请将val2017图片及其标注文件放入服务器/root/dataset/coco/文件夹,val2017目录存放coco数据集的验证集图片,annotations目录存放coco数据集的instances_val2017.json,文件目录结构如下: -``` -root -├── dataset -│ ├── coco -│ │ ├── annotations -│ │ ├── val2017 -``` - -5.[获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) -将benchmark.x86_64或benchmark.aarch64放到当前目录 - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 -``` -#启动脚本内1-2行为pth2onnx,3-4行为onnx2om,脚本执行完成后会生成SOLOV2.onnx、SOLOV2_sim.onnx、solov2.om三个文件。 -bash test/pth2om.sh -#启动脚本内9-21行为前处理,用以获取处理后的图片信息与bin文件;23-33为获取图片info文件,为推理做准备;35-42行为benchmark推理;44-51行为后处理,同时会输出模型测评的精度;57-63行为打印om推理性能。 -bash test/eval_acc_perf.sh --datasets_path=/root/datasets -``` - **评测结果:** -| 模型 | 在线推理精度 | 310离线推理精度 | 基准性能 | 310性能 | -| :------: | :------: | :------: | :------: | :------: | -| SOLOV2 bs1 | mAP:34.0% | mAP:34.0% | 7.58fps | 9.877fps | - -备注:离线模型不支持多batch。 +# SOLOV2模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +``` +pip install -r requirements.txt +``` +说明:PyTorch选用开源1.9.0版本 + + + +2.获取,修改与安装开源模型代码 +安装mmcv +``` +git clone https://github.com/open-mmlab/mmcv -b v0.2.16 +cd mmcv +python setup.py build_ext +python setup.py develop +cd .. +``` +获取SOLOv2代码 +``` +git clone https://github.com/WXinlong/SOLO.git -b master +cd SOLO +git reset --hard 95f3732d5fbb0d7c7044c7dd074f439d48a72ce5 +patch -p1 < ../MMDET.diff +patch -p1 < ../SOLOV2.diff +pip install -r requirements/build.txt +pip install -v -e . +cd .. +``` + + +3.获取权重文件 + +请从[原始开源代码仓](https://github.com/WXinlong/SOLO)下载SOLOv2_R50_1x模型的权重文件 + +4.数据集 + +数据集的获取请参考[原始开源代码仓](https://github.com/WXinlong/SOLO)的方式获取。请将val2017图片及其标注文件放入服务器/root/dataset/coco/文件夹,val2017目录存放coco数据集的验证集图片,annotations目录存放coco数据集的instances_val2017.json,文件目录结构如下: +``` +root +├── dataset +│ ├── coco +│ │ ├── annotations +│ │ ├── val2017 +``` + +5.[获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) +将benchmark.x86_64或benchmark.aarch64放到当前目录 + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 +``` +#启动脚本内1-2行为pth2onnx,3-4行为onnx2om,脚本执行完成后会生成SOLOV2.onnx、SOLOV2_sim.onnx、solov2.om三个文件。 +bash test/pth2om.sh +#启动脚本内9-21行为前处理,用以获取处理后的图片信息与bin文件;23-33为获取图片info文件,为推理做准备;35-42行为benchmark推理;44-51行为后处理,同时会输出模型测评的精度;57-63行为打印om推理性能。 +bash test/eval_acc_perf.sh --datasets_path=/root/datasets +``` + **评测结果:** +| 模型 | 在线推理精度 | 310离线推理精度 | 基准性能 | 310性能 | +| :------: | :------: | :------: | :------: | :------: | +| SOLOV2 bs1 | mAP:34.0% | mAP:34.0% | 7.58fps | 9.877fps | + +备注:离线模型不支持多batch。 diff --git a/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/get_info.py b/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/get_info.py index e0979bced8..fc3f14c7a3 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/get_info.py +++ b/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/get_info.py @@ -1,59 +1,59 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import mmcv -from mmdet.datasets import build_dataset -import pickle as pk - -ann_file = '/annotations/instances_val2017.json' -img_prefix = '/val2017/' - -if __name__ == '__main__': - image_src_path = sys.argv[1] - config_path = sys.argv[2] - bin_path = sys.argv[3] - meta_path = sys.argv[4] - info_name = sys.argv[5] - info_meta_name = sys.argv[6] - width = int(sys.argv[7]) - height = int(sys.argv[8]) - - cfg = mmcv.Config.fromfile(config_path) - cfg.data.test.ann_file = image_src_path + ann_file - cfg.data.test.img_prefix = image_src_path + img_prefix - - dataset = build_dataset(cfg.data.test) - - fp1 = open(info_name, "w") - fp2 = open(info_meta_name, "w") - - for idx in range(5000): - img_id = dataset.img_ids[idx] - fp1.write("{} {}/{:0>12d}.bin {} {}\n".format(idx, bin_path, img_id, width, height)) - fp_meta = open("%s/%012d.pk" % (meta_path, img_id), "rb") - meta = pk.load(fp_meta) - fp_meta.close() - fp2.write("{} {}/{:0>12d}.bin {} {} {} {}\n".format( - idx, - meta_path, - img_id, - meta['img_shape'][1], - meta['img_shape'][0], - meta['ori_shape'][1], - meta['ori_shape'][0] - )) - fp1.close() - fp2.close() - print("Get info done!") +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import mmcv +from mmdet.datasets import build_dataset +import pickle as pk + +ann_file = '/annotations/instances_val2017.json' +img_prefix = '/val2017/' + +if __name__ == '__main__': + image_src_path = sys.argv[1] + config_path = sys.argv[2] + bin_path = sys.argv[3] + meta_path = sys.argv[4] + info_name = sys.argv[5] + info_meta_name = sys.argv[6] + width = int(sys.argv[7]) + height = int(sys.argv[8]) + + cfg = mmcv.Config.fromfile(config_path) + cfg.data.test.ann_file = image_src_path + ann_file + cfg.data.test.img_prefix = image_src_path + img_prefix + + dataset = build_dataset(cfg.data.test) + + fp1 = open(info_name, "w") + fp2 = open(info_meta_name, "w") + + for idx in range(5000): + img_id = dataset.img_ids[idx] + fp1.write("{} {}/{:0>12d}.bin {} {}\n".format(idx, bin_path, img_id, width, height)) + fp_meta = open("%s/%012d.pk" % (meta_path, img_id), "rb") + meta = pk.load(fp_meta) + fp_meta.close() + fp2.write("{} {}/{:0>12d}.bin {} {} {} {}\n".format( + idx, + meta_path, + img_id, + meta['img_shape'][1], + meta['img_shape'][0], + meta['ori_shape'][1], + meta['ori_shape'][0] + )) + fp1.close() + fp2.close() + print("Get info done!") diff --git a/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/modelzoo_level.txt index bdc5dd889d..5a90c7c76e 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus: PERFECT \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/pth2onnx.py b/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/pth2onnx.py index 4fdf107ff0..2e2add1625 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/pth2onnx.py @@ -1,40 +1,40 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import argparse -import numpy as np -from mmdet.apis import init_detector - -input_names = ['input'] -output_names = ['seg_preds', 'cate_labels', 'cate_scores'] - - -def pth2onnx(args, fake_input): - model = init_detector(args.config, args.pth_path, device='cpu') - model.forward = model.simple_test - torch.onnx.export(model, fake_input, args.out, input_names=input_names, output_names=output_names, verbose=False, - opset_version=11) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--config', help='model config') - parser.add_argument('--out', help='onnx output name') - parser.add_argument('--pth_path', help='model pth path') - parser.add_argument('--shape', type=int, nargs='+', help='input image size hxw') - args = parser.parse_args() - assert len(args.shape) == 2 - fake_input = torch.randn(1, 3, args.shape[0], args.shape[1]) - pth2onnx(args, fake_input) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import argparse +import numpy as np +from mmdet.apis import init_detector + +input_names = ['input'] +output_names = ['seg_preds', 'cate_labels', 'cate_scores'] + + +def pth2onnx(args, fake_input): + model = init_detector(args.config, args.pth_path, device='cpu') + model.forward = model.simple_test + torch.onnx.export(model, fake_input, args.out, input_names=input_names, output_names=output_names, verbose=False, + opset_version=11) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--config', help='model config') + parser.add_argument('--out', help='onnx output name') + parser.add_argument('--pth_path', help='model pth path') + parser.add_argument('--shape', type=int, nargs='+', help='input image size hxw') + args = parser.parse_args() + assert len(args.shape) == 2 + fake_input = torch.randn(1, 3, args.shape[0], args.shape[1]) + pth2onnx(args, fake_input) diff --git a/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/requirements.txt b/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/requirements.txt index 565fab9665..3802263668 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/requirements.txt +++ b/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/requirements.txt @@ -1,6 +1,6 @@ -torch == 1.9.0 -torchvision == 0.10.0 -onnx == 1.9.0 -onnx-simplifier == 0.3.6 -onnxruntime == 1.8.0 +torch == 1.9.0 +torchvision == 0.10.0 +onnx == 1.9.0 +onnx-simplifier == 0.3.6 +onnxruntime == 1.8.0 numpy == 1.21.0 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/solov2_postprocess.py b/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/solov2_postprocess.py index 88bd4578dc..0caf6ee469 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/solov2_postprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/solov2_postprocess.py @@ -1,104 +1,104 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 mmcv -import numpy as np -import argparse -import torch -import torch.nn.functional as F -import pycocotools.mask as mask_util -from mmdet.core import coco_eval, results2json, results2json_segm -from mmdet.datasets import build_dataset - -ann_file = '/annotations/instances_val2017.json' -img_prefix = '/val2017/' - - -def get_masks(result, num_classes=80): - for cur_result in result: - masks = [[] for _ in range(num_classes)] - if cur_result is None: - return masks - seg_pred = cur_result[0].astype(np.uint8) - cate_label = cur_result[1].astype(np.int) - cate_score = cur_result[2].astype(np.float) - num_ins = seg_pred.shape[0] - for idx in range(num_ins): - cur_mask = seg_pred[idx, ...] - rle = mask_util.encode( - np.array(cur_mask[:, :, np.newaxis], order='F'))[0] - rst = (rle, cate_score[idx]) - masks[cate_label[idx]].append(rst) - return masks - - -def handle_seg(seg, img_shape, ori_shape, input_shape=(800, 1216), mask_thr=0.5): - seg = torch.tensor(seg) - h, w, = img_shape - pad_left = (input_shape[1] - w) // 2 - pad_top = (input_shape[0] - h) // 2 - seg = F.interpolate(seg.unsqueeze(0), - size=input_shape, - mode='bilinear')[:, :, pad_top:pad_top + h, pad_left:pad_left + w] - - seg = F.interpolate(seg, - size=ori_shape[:2], - mode='bilinear').squeeze(0) - seg = seg > mask_thr - return seg.numpy() - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--dataset_path') - parser.add_argument('--model_config') - parser.add_argument('--bin_data_path') - parser.add_argument('--meta_info') - parser.add_argument('--net_out_num', type=int) - parser.add_argument("--model_input_height", type=int, help='input tensor height') - parser.add_argument("--model_input_width", type=int, help='input tensor width') - - args = parser.parse_args() - - cfg = mmcv.Config.fromfile(args.model_config) - cfg.data.test.test_mode = True - cfg.data.test.ann_file = args.dataset_path + ann_file - cfg.data.test.img_prefix = args.dataset_path + img_prefix - dataset = build_dataset(cfg.data.test) - num_classes = len(dataset.CLASSES) - - results = [] - - fp = open(args.meta_info, "r") - for line in fp.readlines(): - _, file_path, img_w, img_h, ori_w, ori_h = line.split() - img_w = int(img_w) - img_h = int(img_h) - ori_w = int(ori_w) - ori_h = int(ori_h) - file_name = file_path.split("/")[1].replace(".bin", "") - result = [] - for idx in range(args.net_out_num): - if idx == 1: - result.append(np.fromfile("%s%s_%d.bin" % (args.bin_data_path, file_name, idx + 1), dtype=np.int32)) - else: - result.append(np.fromfile("%s%s_%d.bin" % (args.bin_data_path, file_name, idx + 1), dtype=np.float32)) - result[0].shape = (100, args.model_input_height // 4, args.model_input_width // 4) - result[0] = handle_seg(result[0], (img_h, img_w), (ori_h, ori_w), - (args.model_input_height, args.model_input_width)) - result = get_masks([result], num_classes) - results.append(result) - fp.close() - result_files = results2json_segm(dataset, results, "results_solo.pkl") - coco_eval(result_files, ["segm"], dataset.coco) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 mmcv +import numpy as np +import argparse +import torch +import torch.nn.functional as F +import pycocotools.mask as mask_util +from mmdet.core import coco_eval, results2json, results2json_segm +from mmdet.datasets import build_dataset + +ann_file = '/annotations/instances_val2017.json' +img_prefix = '/val2017/' + + +def get_masks(result, num_classes=80): + for cur_result in result: + masks = [[] for _ in range(num_classes)] + if cur_result is None: + return masks + seg_pred = cur_result[0].astype(np.uint8) + cate_label = cur_result[1].astype(np.int) + cate_score = cur_result[2].astype(np.float) + num_ins = seg_pred.shape[0] + for idx in range(num_ins): + cur_mask = seg_pred[idx, ...] + rle = mask_util.encode( + np.array(cur_mask[:, :, np.newaxis], order='F'))[0] + rst = (rle, cate_score[idx]) + masks[cate_label[idx]].append(rst) + return masks + + +def handle_seg(seg, img_shape, ori_shape, input_shape=(800, 1216), mask_thr=0.5): + seg = torch.tensor(seg) + h, w, = img_shape + pad_left = (input_shape[1] - w) // 2 + pad_top = (input_shape[0] - h) // 2 + seg = F.interpolate(seg.unsqueeze(0), + size=input_shape, + mode='bilinear')[:, :, pad_top:pad_top + h, pad_left:pad_left + w] + + seg = F.interpolate(seg, + size=ori_shape[:2], + mode='bilinear').squeeze(0) + seg = seg > mask_thr + return seg.numpy() + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--dataset_path') + parser.add_argument('--model_config') + parser.add_argument('--bin_data_path') + parser.add_argument('--meta_info') + parser.add_argument('--net_out_num', type=int) + parser.add_argument("--model_input_height", type=int, help='input tensor height') + parser.add_argument("--model_input_width", type=int, help='input tensor width') + + args = parser.parse_args() + + cfg = mmcv.Config.fromfile(args.model_config) + cfg.data.test.test_mode = True + cfg.data.test.ann_file = args.dataset_path + ann_file + cfg.data.test.img_prefix = args.dataset_path + img_prefix + dataset = build_dataset(cfg.data.test) + num_classes = len(dataset.CLASSES) + + results = [] + + fp = open(args.meta_info, "r") + for line in fp.readlines(): + _, file_path, img_w, img_h, ori_w, ori_h = line.split() + img_w = int(img_w) + img_h = int(img_h) + ori_w = int(ori_w) + ori_h = int(ori_h) + file_name = file_path.split("/")[1].replace(".bin", "") + result = [] + for idx in range(args.net_out_num): + if idx == 1: + result.append(np.fromfile("%s%s_%d.bin" % (args.bin_data_path, file_name, idx + 1), dtype=np.int32)) + else: + result.append(np.fromfile("%s%s_%d.bin" % (args.bin_data_path, file_name, idx + 1), dtype=np.float32)) + result[0].shape = (100, args.model_input_height // 4, args.model_input_width // 4) + result[0] = handle_seg(result[0], (img_h, img_w), (ori_h, ori_w), + (args.model_input_height, args.model_input_width)) + result = get_masks([result], num_classes) + results.append(result) + fp.close() + result_files = results2json_segm(dataset, results, "results_solo.pkl") + coco_eval(result_files, ["segm"], dataset.coco) diff --git a/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/solov2_preprocess.py b/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/solov2_preprocess.py index d82a93d367..448b1cc203 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/solov2_preprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/solov2_preprocess.py @@ -1,86 +1,86 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import argparse -import numpy as np -import cv2 -import mmcv -import torch -import pickle as pk -import multiprocessing - -flags = None - -def resize(img, size): - old_h = img.shape[0] - old_w = img.shape[1] - scale_ratio = min(size[0] / old_w, size[1] / old_h) - new_w = int(np.floor(old_w * scale_ratio)) - new_h = int(np.floor(old_h * scale_ratio)) - resized_img = mmcv.imresize(img, (new_w, new_h)) - return resized_img, scale_ratio - - -def gen_input_bin(file_batches, batch): - i = 0 - for file in file_batches[batch]: - i = i + 1 - print("batch", batch, file, "===", i) - - image = mmcv.imread(os.path.join(flags.image_src_path, file)) - ori_shape = image.shape - image, scale_factor = resize(image, (flags.model_input_width, flags.model_input_height)) - img_shape = image.shape - mean = np.array([123.675, 116.28, 103.53], dtype=np.float32) - std = np.array([58.395, 57.12, 57.375], dtype=np.float32) - image = mmcv.imnormalize(image, mean, std) - h = image.shape[0] - w = image.shape[1] - pad_left = (flags.model_input_width - w) // 2 - pad_top = (flags.model_input_height - h) // 2 - pad_right = flags.model_input_width - pad_left - w - pad_bottom = flags.model_input_height - pad_top - h - image = cv2.copyMakeBorder(image, pad_top, pad_bottom, pad_left, pad_right, cv2.BORDER_CONSTANT, value=0) - image = image.transpose(2, 0, 1) - image.tofile(os.path.join(flags.bin_file_path, file.split('.')[0] + ".bin")) - image_meta = {'img_shape': img_shape, 'scale_factor': scale_factor, 'ori_shape': ori_shape} - with open(os.path.join(flags.meta_file_path, file.split('.')[0] + ".pk"), "wb") as fp: - pk.dump(image_meta, fp) - - -def preprocess(): - files = os.listdir(flags.image_src_path) - file_batches = [files[i:i + 100] for i in range(0, 5000, 100) if files[i:i + 100] != []] - thread_pool = multiprocessing.Pool(len(file_batches)) - for batch in range(len(file_batches)): - thread_pool.apply_async(gen_input_bin, args=(file_batches, batch)) - thread_pool.close() - thread_pool.join() - print("in thread, except will not report! please ensure bin files generated.") - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='preprocess of MaskRCNN PyTorch model') - parser.add_argument("--image_src_path", default="/root/datasets/coco/val2017", help='image of dataset') - parser.add_argument("--bin_file_path", default="val2017_bin", help='Preprocessed image buffer') - parser.add_argument("--meta_file_path", default="val2017_bin_meta", help='Get image meta') - parser.add_argument("--model_input_height", default=800, type=int, help='input tensor height') - parser.add_argument("--model_input_width", default=1216, type=int, help='input tensor width') - flags = parser.parse_args() - if not os.path.exists(flags.bin_file_path): - os.makedirs(flags.bin_file_path) - if not os.path.exists(flags.meta_file_path): - os.makedirs(flags.meta_file_path) - preprocess() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import argparse +import numpy as np +import cv2 +import mmcv +import torch +import pickle as pk +import multiprocessing + +flags = None + +def resize(img, size): + old_h = img.shape[0] + old_w = img.shape[1] + scale_ratio = min(size[0] / old_w, size[1] / old_h) + new_w = int(np.floor(old_w * scale_ratio)) + new_h = int(np.floor(old_h * scale_ratio)) + resized_img = mmcv.imresize(img, (new_w, new_h)) + return resized_img, scale_ratio + + +def gen_input_bin(file_batches, batch): + i = 0 + for file in file_batches[batch]: + i = i + 1 + print("batch", batch, file, "===", i) + + image = mmcv.imread(os.path.join(flags.image_src_path, file)) + ori_shape = image.shape + image, scale_factor = resize(image, (flags.model_input_width, flags.model_input_height)) + img_shape = image.shape + mean = np.array([123.675, 116.28, 103.53], dtype=np.float32) + std = np.array([58.395, 57.12, 57.375], dtype=np.float32) + image = mmcv.imnormalize(image, mean, std) + h = image.shape[0] + w = image.shape[1] + pad_left = (flags.model_input_width - w) // 2 + pad_top = (flags.model_input_height - h) // 2 + pad_right = flags.model_input_width - pad_left - w + pad_bottom = flags.model_input_height - pad_top - h + image = cv2.copyMakeBorder(image, pad_top, pad_bottom, pad_left, pad_right, cv2.BORDER_CONSTANT, value=0) + image = image.transpose(2, 0, 1) + image.tofile(os.path.join(flags.bin_file_path, file.split('.')[0] + ".bin")) + image_meta = {'img_shape': img_shape, 'scale_factor': scale_factor, 'ori_shape': ori_shape} + with open(os.path.join(flags.meta_file_path, file.split('.')[0] + ".pk"), "wb") as fp: + pk.dump(image_meta, fp) + + +def preprocess(): + files = os.listdir(flags.image_src_path) + file_batches = [files[i:i + 100] for i in range(0, 5000, 100) if files[i:i + 100] != []] + thread_pool = multiprocessing.Pool(len(file_batches)) + for batch in range(len(file_batches)): + thread_pool.apply_async(gen_input_bin, args=(file_batches, batch)) + thread_pool.close() + thread_pool.join() + print("in thread, except will not report! please ensure bin files generated.") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='preprocess of MaskRCNN PyTorch model') + parser.add_argument("--image_src_path", default="/root/datasets/coco/val2017", help='image of dataset') + parser.add_argument("--bin_file_path", default="val2017_bin", help='Preprocessed image buffer') + parser.add_argument("--meta_file_path", default="val2017_bin_meta", help='Get image meta') + parser.add_argument("--model_input_height", default=800, type=int, help='input tensor height') + parser.add_argument("--model_input_width", default=1216, type=int, help='input tensor width') + flags = parser.parse_args() + if not os.path.exists(flags.bin_file_path): + os.makedirs(flags.bin_file_path) + if not os.path.exists(flags.meta_file_path): + os.makedirs(flags.meta_file_path) + preprocess() diff --git a/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/test/parse.py b/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/test/parse.py index b9c74f41d7..82af69cd18 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/test/parse.py +++ b/ACL_PyTorch/contrib/cv/segmentation/SOLOV2/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/SiamMask/LICENSE b/ACL_PyTorch/contrib/cv/segmentation/SiamMask/LICENSE index 29f81d812f..261eeb9e9f 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/SiamMask/LICENSE +++ b/ACL_PyTorch/contrib/cv/segmentation/SiamMask/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/ACL_PyTorch/contrib/cv/segmentation/Ultra-Fast-Lane-Detection/LICENSE b/ACL_PyTorch/contrib/cv/segmentation/Ultra-Fast-Lane-Detection/LICENSE index 29f81d812f..261eeb9e9f 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/Ultra-Fast-Lane-Detection/LICENSE +++ b/ACL_PyTorch/contrib/cv/segmentation/Ultra-Fast-Lane-Detection/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/ACL_PyTorch/contrib/cv/segmentation/Ultra-Fast-Lane-Detection/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/segmentation/Ultra-Fast-Lane-Detection/modelzoo_level.txt index 51b74557c1..5c956b09db 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/Ultra-Fast-Lane-Detection/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/segmentation/Ultra-Fast-Lane-Detection/modelzoo_level.txt @@ -1,6 +1,6 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK -PerfStatus:OK -ModelConvert:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK +PerfStatus:OK +ModelConvert:OK QuantStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/VNet/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/segmentation/VNet/modelzoo_level.txt index 403465b84e..ec6168981c 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/VNet/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/segmentation/VNet/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus:Perfect \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/Wseg/README.md b/ACL_PyTorch/contrib/cv/segmentation/Wseg/README.md index 7da4500570..61fd261750 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/Wseg/README.md +++ b/ACL_PyTorch/contrib/cv/segmentation/Wseg/README.md @@ -1,66 +1,66 @@ -# Wseg模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,并且安装以下可能已经安装过的需求包 -``` -pip3.7 install -r requirements.txt -``` - -2.获取开源模型的代码,并修改文件夹名称为wseg -``` -git clone https://github.com/visinf/1-stage-wseg -b master -git reset cfe5784f9905d656e0f15fba0e6eb76a3731d80f --hard -mv 1-stage-wseg wseg -``` - -3.获取权重文件 -1. 获取经过预训练的基础网络权重文件并且放在代码仓的以下路径中:`/models/weights/`. - - | Backbone | Initial Weights | - |:---:|:---:| - | WideResNet38 | [ilsvrc-cls_rna-a1_cls1000_ep-0001.pth (402M)](https://download.visinf.tu-darmstadt.de/data/2020-cvpr-araslanov-1-stage-wseg/models/ilsvrc-cls_rna-a1_cls1000_ep-0001.pth) | - -2. 获取功能网络权重(作者提供的pth模型)并放置于代码仓的以下路径中:(初始代码仓无snapshots文件夹,需要自己新建路径)`/snapshots/` - - | Backbone | Val | Link | - |:---:|:---:|---:| - | WideResNet38 | 62.7 | [model_enc_e020Xs0.928.pth (527M)](https://download.visinf.tu-darmstadt.de/data/2020-cvpr-araslanov-1-stage-wseg/models/model_enc_e020Xs0.928.pth) | - -3. 移动上述两个权重文件到代码仓指定位置,以待加载使用 -``` -mkdir ./models/weights -mv ilsvrc-cls_rna-a1_cls1000_ep-0001.pth ./models/weights -mkdir ./snapshots -mv model_enc_e020Xs0.928.pth ./snapshots -``` - -4.下载数据集,解压,将文件名改为voc,并将其放于代码仓中的以下路径: `/data/` -- VOC: [Training/Validation (2GB .tar file)](http://host.robots.ox.ac.uk/pascal/VOC/voc2012/VOCtrainval_11-May-2012.tar) - -``` -tar -zxvf VOCtrainval_11-May-2012.tar -mv VOCtrainval_11-May-2012 voc -mkdir ./data -mv voc ./data -``` - -5.[获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) -将benchmark.x86_64或benchmark.aarch64放到当前目录 - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=./data -``` - **评测结果:** - -| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | -| :------: | :------: | :------: | :------: | :------: | -| WideResNet38 bs1 | [IOU: 62.7](https://github.com/visinf/1-stage-wseg) | IOU:63.7 | 5.270fps | 3.496fps | -| WideResNet38 bs4 | [IOU: 62.7](https://github.com/visinf/1-stage-wseg) | IOU:63.7 | 5.460fps | 3.912fps | - - **备注:** +# Wseg模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,并且安装以下可能已经安装过的需求包 +``` +pip3.7 install -r requirements.txt +``` + +2.获取开源模型的代码,并修改文件夹名称为wseg +``` +git clone https://github.com/visinf/1-stage-wseg -b master +git reset cfe5784f9905d656e0f15fba0e6eb76a3731d80f --hard +mv 1-stage-wseg wseg +``` + +3.获取权重文件 +1. 获取经过预训练的基础网络权重文件并且放在代码仓的以下路径中:`/models/weights/`. + + | Backbone | Initial Weights | + |:---:|:---:| + | WideResNet38 | [ilsvrc-cls_rna-a1_cls1000_ep-0001.pth (402M)](https://download.visinf.tu-darmstadt.de/data/2020-cvpr-araslanov-1-stage-wseg/models/ilsvrc-cls_rna-a1_cls1000_ep-0001.pth) | + +2. 获取功能网络权重(作者提供的pth模型)并放置于代码仓的以下路径中:(初始代码仓无snapshots文件夹,需要自己新建路径)`/snapshots/` + + | Backbone | Val | Link | + |:---:|:---:|---:| + | WideResNet38 | 62.7 | [model_enc_e020Xs0.928.pth (527M)](https://download.visinf.tu-darmstadt.de/data/2020-cvpr-araslanov-1-stage-wseg/models/model_enc_e020Xs0.928.pth) | + +3. 移动上述两个权重文件到代码仓指定位置,以待加载使用 +``` +mkdir ./models/weights +mv ilsvrc-cls_rna-a1_cls1000_ep-0001.pth ./models/weights +mkdir ./snapshots +mv model_enc_e020Xs0.928.pth ./snapshots +``` + +4.下载数据集,解压,将文件名改为voc,并将其放于代码仓中的以下路径: `/data/` +- VOC: [Training/Validation (2GB .tar file)](http://host.robots.ox.ac.uk/pascal/VOC/voc2012/VOCtrainval_11-May-2012.tar) + +``` +tar -zxvf VOCtrainval_11-May-2012.tar +mv VOCtrainval_11-May-2012 voc +mkdir ./data +mv voc ./data +``` + +5.[获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) +将benchmark.x86_64或benchmark.aarch64放到当前目录 + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=./data +``` + **评测结果:** + +| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | +| :------: | :------: | :------: | :------: | :------: | +| WideResNet38 bs1 | [IOU: 62.7](https://github.com/visinf/1-stage-wseg) | IOU:63.7 | 5.270fps | 3.496fps | +| WideResNet38 bs4 | [IOU: 62.7](https://github.com/visinf/1-stage-wseg) | IOU:63.7 | 5.460fps | 3.912fps | + + **备注:** - 由于分辨率大内存使用多,故仅用bs1与bs4进行评测 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/Wseg/Wseg_postprocess.py b/ACL_PyTorch/contrib/cv/segmentation/Wseg/Wseg_postprocess.py index 6a70b18b44..6a4864b8ef 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/Wseg/Wseg_postprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/Wseg/Wseg_postprocess.py @@ -1,375 +1,375 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import numpy as np -import torch -import torchvision.transforms.functional as F -import torchvision.transforms as tf -import pydensecrf.densecrf as dcrf -import torch.nn.functional as Func -from PIL import Image, ImagePalette -from pydensecrf.utils import unary_from_softmax - -class Normalize(): - def __init__(self, mean = (0.485, 0.456, 0.406), std = (0.229, 0.224, 0.225)): - - self.mean = mean - self.std = std - - def undo(self, imgarr): - proc_img = imgarr.copy() - - proc_img[..., 0] = (self.std[0] * imgarr[..., 0] + self.mean[0]) * 255. - proc_img[..., 1] = (self.std[1] * imgarr[..., 1] + self.mean[1]) * 255. - proc_img[..., 2] = (self.std[2] * imgarr[..., 2] + self.mean[2]) * 255. - - return proc_img - - def __call__(self, img): - imgarr = np.asarray(img) - proc_img = np.empty_like(imgarr, np.float32) - - proc_img[..., 0] = (imgarr[..., 0] / 255. - self.mean[0]) / self.std[0] - proc_img[..., 1] = (imgarr[..., 1] / 255. - self.mean[1]) / self.std[1] - proc_img[..., 2] = (imgarr[..., 2] / 255. - self.mean[2]) / self.std[2] - - return proc_img - -def colormap(N=256): - def bitget(byteval, idx): - return ((byteval & (1 << idx)) != 0) - - dtype = 'uint8' - cmap = [] - for i in range(N): - r = g = b = 0 - c = i - for j in range(8): - r = r | (bitget(c, 0) << 7-j) - g = g | (bitget(c, 1) << 7-j) - b = b | (bitget(c, 2) << 7-j) - c = c >> 3 - - cmap.append((r, g, b)) - return cmap - -def get_palette(): - cmap = colormap() - palette = ImagePalette.ImagePalette() - for rgb in cmap: - palette.getcolor(rgb) - return palette - -def crf_inference(img, probs, t=10, scale_factor=1, labels=21): - - h, w = img.shape[:2] - n_labels = labels - - d = dcrf.DenseCRF2D(w, h, n_labels) - - unary = unary_from_softmax(probs) - unary = np.ascontiguousarray(unary) - - d.setUnaryEnergy(unary) - d.addPairwiseGaussian(sxy=3/scale_factor, compat=3) - d.addPairwiseBilateral(sxy=80/scale_factor, srgb=13, rgbim=np.copy(img), compat=10) - Q = d.inference(t) - - return np.array(Q).reshape((n_labels, h, w)) - -def _cut(x_chw, pads): - pad_h, pad_w, h, w = [int(p) for p in pads] - return x_chw[:, pad_h:(pad_h + h), pad_w:(pad_w + w)] - -def _mask_overlay(mask, image, alpha=0.3): - - mask_rgb = __mask2rgb(mask) - return alpha * image + (1 - alpha) * mask_rgb - -def __mask2rgb(mask): - im = Image.fromarray(mask).convert("P") - im.putpalette(get_palette()) - mask_rgb = np.array(im.convert("RGB"), dtype=np.float) - return mask_rgb / 255. - -def _merge_masks(masks, labels, pads, imsize_hw): - - mask_list = [] - for i, mask in enumerate(masks.split(1, dim=0)): - - # removing the padding - mask_cut = _cut(mask[0], pads[i]).unsqueeze(0) - # normalising the scale - mask_cut = Func.interpolate(mask_cut, imsize_hw, mode='bilinear', align_corners=False)[0] - - # flipping if necessary - if i % 2 == 1: - mask_cut = torch.flip(mask_cut, (-1, )) - - # getting the max response - mask_cut[1:, ::] *= labels[:, None, None] - mask_list.append(mask_cut) - - mean_mask = sum(mask_list).numpy() / len(mask_list) - - # discounting BG - mean_mask[0, ::] = np.power(mean_mask[0, ::], 3) - - return mean_mask - -def save(out_path, img_path, img_orig, all_masks, labels, pads, gt_mask): - - img_name = os.path.basename(img_path).rstrip(".jpg") - - # converting original image to [0, 255] - img_orig255 = np.round(255. * img_orig).astype(np.uint8) - img_orig255 = np.transpose(img_orig255, [1, 2, 0]) - img_orig255 = np.ascontiguousarray(img_orig255) - - merged_mask = _merge_masks(all_masks, pads, labels, img_orig255.shape[:2]) - pred = np.argmax(merged_mask, 0) - - # CRF - pred_crf = crf_inference(img_orig255, merged_mask, t=10, scale_factor=1, labels=21) - pred_crf = np.argmax(pred_crf, 0) - - filepath = os.path.join(out_path, img_name + '.png') - img_pred = Image.fromarray(pred.astype(np.uint8)) - img_pred.save(filepath) - - filepath = os.path.join(out_path, "crf", img_name + '.png') - img_pred_crf = Image.fromarray(pred_crf.astype(np.uint8)) - img_pred_crf.save(filepath) - mask_gt = gt_mask - masks_all = np.concatenate([pred, pred_crf, mask_gt], 1).astype(np.uint8) - images = np.concatenate([img_orig] * 3, 2) - images = np.transpose(images, [1, 2, 0]) - - overlay = _mask_overlay(masks_all, images) - filepath = os.path.join(out_path, "vis", img_name + '.png') - overlay255 = np.round(overlay * 255.).astype(np.uint8) - overlay255_crf = Image.fromarray(overlay255) - overlay255_crf.save(filepath) - -def load_img_name_list(dataset_path, index=0): - img_gt_name_list = open(dataset_path).read().splitlines() - img_name_list = [img_gt_name.split(' ')[index].strip('/') for img_gt_name in img_gt_name_list] - - return img_name_list - -def load_label_name_list(dataset_path): - return load_img_name_list(dataset_path, index=1) - -def pad(image,pad_size): - w, h = image.size - - pad_height = pad_size[0] - h - pad_width = pad_size[1] - w - - assert pad_height >= 0 and pad_width >= 0 - - pad_l = max(0, pad_width // 2) - pad_t = max(0, pad_height // 2) - - return [pad_t, pad_l] - -def imgread(imgpath): - fullpath = os.path.join(imgpath) - img = Image.open(fullpath).convert("RGB") - return fullpath, img - -def getitem(img_path,labelpath): - - name, img = imgread(img_path) - - # label_fullpath = self.label_list[idx] - assert len(labelpath) < 256, "Expected label path less than 256 for padding" - - mask = Image.open(labelpath) - mask = np.array(mask) - NUM_CLASS = 21 - labels = torch.zeros(NUM_CLASS - 1) - - # it will also be sorted - unique_labels = np.unique(mask) - - # ambigious - if unique_labels[-1] == CLASS_IDX['ambiguous']: - unique_labels = unique_labels[:-1] - - # background - if unique_labels[0] == CLASS_IDX['background']: - unique_labels = unique_labels[1:] - - assert unique_labels.size > 0, 'No labels found ' - unique_labels -= 1 # shifting since no BG class - labels[unique_labels.tolist()] = 1 - - return name, img, labels, mask.astype(np.int) - -def get_one_image(img_path,label_path): - - transform = tf.Compose([np.asarray, - Normalize()]) - pad_size = [1024, 1024] - scales = [1, 0.5, 1.5, 2.0] - batch_size = 8 - use_flips = True - - pad_batch = [] - - for i in range(batch_size): - - sub_idx = i % batch_size - scale = scales[sub_idx // (2 if use_flips else 1)] - flip = use_flips and sub_idx % 2 - - name, img, label, mask = getitem(img_path, label_path) - - target_size = (int(round(img.size[0] * scale)), - int(round(img.size[1] * scale))) - - s_img = img.resize(target_size, resample=Image.CUBIC) - - if flip: - s_img = F.hflip(s_img) - - w, h = s_img.size - pads_tl = pad(s_img,pad_size) - pad_t, pad_l = pads_tl - img = F.to_tensor(transform(img)) - pads = torch.Tensor([pad_t, pad_l, h, w]) - pad_batch.append(pads) - - return name, img, pad_batch, label, mask - -def check_dir(base_path, name): - - # create the directory - fullpath = os.path.join(base_path, name) - if not os.path.exists(fullpath): - os.makedirs(fullpath) - - return fullpath - -def bintonp(name,bin_path): - mask = [] - cls = [] - for i in range(8): - msk_name = bin_path + '/' + str(name) + '_' + str(i) + "_1.bin" - cls_name = bin_path + '/' + str(name) + '_' + str(i) + "_2.bin" - mask_i = np.fromfile(msk_name, dtype=np.float32) - mask_i.shape = 21,1024,1024 - cls_i = np.fromfile(cls_name, dtype=np.float32) - cls_i.shape = 20 - cls.append(cls_i) - mask.append(mask_i) - msk = np.array(mask) - clss = np.array(cls) - - return clss, msk - -def denorm(image): - - MEAN = (0.485, 0.456, 0.406) - STD = (0.229, 0.224, 0.225) - - if image.dim() == 3: - assert image.dim() == 3, "Expected image [CxHxW]" - assert image.size(0) == 3, "Expected RGB image [3xHxW]" - - for t, m, s in zip(image, MEAN, STD): - t.mul_(s).add_(m) - elif image.dim() == 4: - # batch mode - assert image.size(1) == 3, "Expected RGB image [3xHxW]" - - for t, m, s in zip((0,1,2), MEAN, STD): - image[:, t, :, :].mul_(s).add_(m) - - return image - -def postprocess(file_path, voc12_root,out_path, bin_path): - - img_name_list = load_img_name_list(file_path) - label_name_list = load_label_name_list(file_path) - - print("Start postprocess!") - print("total image number: ",len(img_name_list)) - - for i in range(len(img_name_list)): - - imgnm = img_name_list[i][33:-4] - print("==========> ", i, " ", imgnm) - img_path = voc12_root + '/' + img_name_list[i] - label_path = voc12_root + '/' + label_name_list[i] - print(img_path) - name, img, pad_batch, labels, gt_mask = get_one_image(img_path,label_path) - - with torch.no_grad(): - cls_raw, masks_pred = bintonp(imgnm,bin_path) - masks_pred = torch.from_numpy(masks_pred) - cls_raw = torch.from_numpy(cls_raw) - - cls_sigmoid = torch.sigmoid(cls_raw) - cls_sigmoid, _ = cls_sigmoid.max(0) - labels = (cls_sigmoid > 0.1) - - # saving the raw npy - image = denorm(img).numpy() - masks_pred = masks_pred.cpu() - labels = labels.type_as(masks_pred) - - save(out_path, name, image, masks_pred, pad_batch, labels, gt_mask) - - -if __name__ == '__main__': - - CLASS_IDX = { - 'background': 0, - 'aeroplane': 1, - 'bicycle': 2, - 'bird': 3, - 'boat': 4, - 'bottle': 5, - 'bus': 6, - 'car': 7, - 'cat': 8, - 'chair': 9, - 'cow': 10, - 'diningtable': 11, - 'dog': 12, - 'horse': 13, - 'motorbike': 14, - 'person': 15, - 'potted-plant': 16, - 'sheep': 17, - 'sofa': 18, - 'train': 19, - 'tv/monitor': 20, - 'ambiguous': 255 - } - - voc12_root_path = os.path.abspath(sys.argv[1]) - file_path = os.path.abspath(sys.argv[2]) - bin_path = os.path.abspath(sys.argv[3]) - out_path = os.path.abspath(sys.argv[4]) - - - check_dir(out_path, "vis") - check_dir(out_path, "crf") - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import numpy as np +import torch +import torchvision.transforms.functional as F +import torchvision.transforms as tf +import pydensecrf.densecrf as dcrf +import torch.nn.functional as Func +from PIL import Image, ImagePalette +from pydensecrf.utils import unary_from_softmax + +class Normalize(): + def __init__(self, mean = (0.485, 0.456, 0.406), std = (0.229, 0.224, 0.225)): + + self.mean = mean + self.std = std + + def undo(self, imgarr): + proc_img = imgarr.copy() + + proc_img[..., 0] = (self.std[0] * imgarr[..., 0] + self.mean[0]) * 255. + proc_img[..., 1] = (self.std[1] * imgarr[..., 1] + self.mean[1]) * 255. + proc_img[..., 2] = (self.std[2] * imgarr[..., 2] + self.mean[2]) * 255. + + return proc_img + + def __call__(self, img): + imgarr = np.asarray(img) + proc_img = np.empty_like(imgarr, np.float32) + + proc_img[..., 0] = (imgarr[..., 0] / 255. - self.mean[0]) / self.std[0] + proc_img[..., 1] = (imgarr[..., 1] / 255. - self.mean[1]) / self.std[1] + proc_img[..., 2] = (imgarr[..., 2] / 255. - self.mean[2]) / self.std[2] + + return proc_img + +def colormap(N=256): + def bitget(byteval, idx): + return ((byteval & (1 << idx)) != 0) + + dtype = 'uint8' + cmap = [] + for i in range(N): + r = g = b = 0 + c = i + for j in range(8): + r = r | (bitget(c, 0) << 7-j) + g = g | (bitget(c, 1) << 7-j) + b = b | (bitget(c, 2) << 7-j) + c = c >> 3 + + cmap.append((r, g, b)) + return cmap + +def get_palette(): + cmap = colormap() + palette = ImagePalette.ImagePalette() + for rgb in cmap: + palette.getcolor(rgb) + return palette + +def crf_inference(img, probs, t=10, scale_factor=1, labels=21): + + h, w = img.shape[:2] + n_labels = labels + + d = dcrf.DenseCRF2D(w, h, n_labels) + + unary = unary_from_softmax(probs) + unary = np.ascontiguousarray(unary) + + d.setUnaryEnergy(unary) + d.addPairwiseGaussian(sxy=3/scale_factor, compat=3) + d.addPairwiseBilateral(sxy=80/scale_factor, srgb=13, rgbim=np.copy(img), compat=10) + Q = d.inference(t) + + return np.array(Q).reshape((n_labels, h, w)) + +def _cut(x_chw, pads): + pad_h, pad_w, h, w = [int(p) for p in pads] + return x_chw[:, pad_h:(pad_h + h), pad_w:(pad_w + w)] + +def _mask_overlay(mask, image, alpha=0.3): + + mask_rgb = __mask2rgb(mask) + return alpha * image + (1 - alpha) * mask_rgb + +def __mask2rgb(mask): + im = Image.fromarray(mask).convert("P") + im.putpalette(get_palette()) + mask_rgb = np.array(im.convert("RGB"), dtype=np.float) + return mask_rgb / 255. + +def _merge_masks(masks, labels, pads, imsize_hw): + + mask_list = [] + for i, mask in enumerate(masks.split(1, dim=0)): + + # removing the padding + mask_cut = _cut(mask[0], pads[i]).unsqueeze(0) + # normalising the scale + mask_cut = Func.interpolate(mask_cut, imsize_hw, mode='bilinear', align_corners=False)[0] + + # flipping if necessary + if i % 2 == 1: + mask_cut = torch.flip(mask_cut, (-1, )) + + # getting the max response + mask_cut[1:, ::] *= labels[:, None, None] + mask_list.append(mask_cut) + + mean_mask = sum(mask_list).numpy() / len(mask_list) + + # discounting BG + mean_mask[0, ::] = np.power(mean_mask[0, ::], 3) + + return mean_mask + +def save(out_path, img_path, img_orig, all_masks, labels, pads, gt_mask): + + img_name = os.path.basename(img_path).rstrip(".jpg") + + # converting original image to [0, 255] + img_orig255 = np.round(255. * img_orig).astype(np.uint8) + img_orig255 = np.transpose(img_orig255, [1, 2, 0]) + img_orig255 = np.ascontiguousarray(img_orig255) + + merged_mask = _merge_masks(all_masks, pads, labels, img_orig255.shape[:2]) + pred = np.argmax(merged_mask, 0) + + # CRF + pred_crf = crf_inference(img_orig255, merged_mask, t=10, scale_factor=1, labels=21) + pred_crf = np.argmax(pred_crf, 0) + + filepath = os.path.join(out_path, img_name + '.png') + img_pred = Image.fromarray(pred.astype(np.uint8)) + img_pred.save(filepath) + + filepath = os.path.join(out_path, "crf", img_name + '.png') + img_pred_crf = Image.fromarray(pred_crf.astype(np.uint8)) + img_pred_crf.save(filepath) + mask_gt = gt_mask + masks_all = np.concatenate([pred, pred_crf, mask_gt], 1).astype(np.uint8) + images = np.concatenate([img_orig] * 3, 2) + images = np.transpose(images, [1, 2, 0]) + + overlay = _mask_overlay(masks_all, images) + filepath = os.path.join(out_path, "vis", img_name + '.png') + overlay255 = np.round(overlay * 255.).astype(np.uint8) + overlay255_crf = Image.fromarray(overlay255) + overlay255_crf.save(filepath) + +def load_img_name_list(dataset_path, index=0): + img_gt_name_list = open(dataset_path).read().splitlines() + img_name_list = [img_gt_name.split(' ')[index].strip('/') for img_gt_name in img_gt_name_list] + + return img_name_list + +def load_label_name_list(dataset_path): + return load_img_name_list(dataset_path, index=1) + +def pad(image,pad_size): + w, h = image.size + + pad_height = pad_size[0] - h + pad_width = pad_size[1] - w + + assert pad_height >= 0 and pad_width >= 0 + + pad_l = max(0, pad_width // 2) + pad_t = max(0, pad_height // 2) + + return [pad_t, pad_l] + +def imgread(imgpath): + fullpath = os.path.join(imgpath) + img = Image.open(fullpath).convert("RGB") + return fullpath, img + +def getitem(img_path,labelpath): + + name, img = imgread(img_path) + + # label_fullpath = self.label_list[idx] + assert len(labelpath) < 256, "Expected label path less than 256 for padding" + + mask = Image.open(labelpath) + mask = np.array(mask) + NUM_CLASS = 21 + labels = torch.zeros(NUM_CLASS - 1) + + # it will also be sorted + unique_labels = np.unique(mask) + + # ambigious + if unique_labels[-1] == CLASS_IDX['ambiguous']: + unique_labels = unique_labels[:-1] + + # background + if unique_labels[0] == CLASS_IDX['background']: + unique_labels = unique_labels[1:] + + assert unique_labels.size > 0, 'No labels found ' + unique_labels -= 1 # shifting since no BG class + labels[unique_labels.tolist()] = 1 + + return name, img, labels, mask.astype(np.int) + +def get_one_image(img_path,label_path): + + transform = tf.Compose([np.asarray, + Normalize()]) + pad_size = [1024, 1024] + scales = [1, 0.5, 1.5, 2.0] + batch_size = 8 + use_flips = True + + pad_batch = [] + + for i in range(batch_size): + + sub_idx = i % batch_size + scale = scales[sub_idx // (2 if use_flips else 1)] + flip = use_flips and sub_idx % 2 + + name, img, label, mask = getitem(img_path, label_path) + + target_size = (int(round(img.size[0] * scale)), + int(round(img.size[1] * scale))) + + s_img = img.resize(target_size, resample=Image.CUBIC) + + if flip: + s_img = F.hflip(s_img) + + w, h = s_img.size + pads_tl = pad(s_img,pad_size) + pad_t, pad_l = pads_tl + img = F.to_tensor(transform(img)) + pads = torch.Tensor([pad_t, pad_l, h, w]) + pad_batch.append(pads) + + return name, img, pad_batch, label, mask + +def check_dir(base_path, name): + + # create the directory + fullpath = os.path.join(base_path, name) + if not os.path.exists(fullpath): + os.makedirs(fullpath) + + return fullpath + +def bintonp(name,bin_path): + mask = [] + cls = [] + for i in range(8): + msk_name = bin_path + '/' + str(name) + '_' + str(i) + "_1.bin" + cls_name = bin_path + '/' + str(name) + '_' + str(i) + "_2.bin" + mask_i = np.fromfile(msk_name, dtype=np.float32) + mask_i.shape = 21,1024,1024 + cls_i = np.fromfile(cls_name, dtype=np.float32) + cls_i.shape = 20 + cls.append(cls_i) + mask.append(mask_i) + msk = np.array(mask) + clss = np.array(cls) + + return clss, msk + +def denorm(image): + + MEAN = (0.485, 0.456, 0.406) + STD = (0.229, 0.224, 0.225) + + if image.dim() == 3: + assert image.dim() == 3, "Expected image [CxHxW]" + assert image.size(0) == 3, "Expected RGB image [3xHxW]" + + for t, m, s in zip(image, MEAN, STD): + t.mul_(s).add_(m) + elif image.dim() == 4: + # batch mode + assert image.size(1) == 3, "Expected RGB image [3xHxW]" + + for t, m, s in zip((0,1,2), MEAN, STD): + image[:, t, :, :].mul_(s).add_(m) + + return image + +def postprocess(file_path, voc12_root,out_path, bin_path): + + img_name_list = load_img_name_list(file_path) + label_name_list = load_label_name_list(file_path) + + print("Start postprocess!") + print("total image number: ",len(img_name_list)) + + for i in range(len(img_name_list)): + + imgnm = img_name_list[i][33:-4] + print("==========> ", i, " ", imgnm) + img_path = voc12_root + '/' + img_name_list[i] + label_path = voc12_root + '/' + label_name_list[i] + print(img_path) + name, img, pad_batch, labels, gt_mask = get_one_image(img_path,label_path) + + with torch.no_grad(): + cls_raw, masks_pred = bintonp(imgnm,bin_path) + masks_pred = torch.from_numpy(masks_pred) + cls_raw = torch.from_numpy(cls_raw) + + cls_sigmoid = torch.sigmoid(cls_raw) + cls_sigmoid, _ = cls_sigmoid.max(0) + labels = (cls_sigmoid > 0.1) + + # saving the raw npy + image = denorm(img).numpy() + masks_pred = masks_pred.cpu() + labels = labels.type_as(masks_pred) + + save(out_path, name, image, masks_pred, pad_batch, labels, gt_mask) + + +if __name__ == '__main__': + + CLASS_IDX = { + 'background': 0, + 'aeroplane': 1, + 'bicycle': 2, + 'bird': 3, + 'boat': 4, + 'bottle': 5, + 'bus': 6, + 'car': 7, + 'cat': 8, + 'chair': 9, + 'cow': 10, + 'diningtable': 11, + 'dog': 12, + 'horse': 13, + 'motorbike': 14, + 'person': 15, + 'potted-plant': 16, + 'sheep': 17, + 'sofa': 18, + 'train': 19, + 'tv/monitor': 20, + 'ambiguous': 255 + } + + voc12_root_path = os.path.abspath(sys.argv[1]) + file_path = os.path.abspath(sys.argv[2]) + bin_path = os.path.abspath(sys.argv[3]) + out_path = os.path.abspath(sys.argv[4]) + + + check_dir(out_path, "vis") + check_dir(out_path, "crf") + postprocess(file_path,voc12_root_path,out_path,bin_path) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/Wseg/Wseg_preprocess.py b/ACL_PyTorch/contrib/cv/segmentation/Wseg/Wseg_preprocess.py index d053c79142..015b19101d 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/Wseg/Wseg_preprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/Wseg/Wseg_preprocess.py @@ -1,126 +1,126 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import numpy as np -from PIL import Image -import torchvision.transforms.functional as F -import torchvision.transforms as tf - - -class Normalize(): - def __init__(self, mean = (0.485, 0.456, 0.406), std = (0.229, 0.224, 0.225)): - - self.mean = mean - self.std = std - - def undo(self, imgarr): - proc_img = imgarr.copy() - - proc_img[..., 0] = (self.std[0] * imgarr[..., 0] + self.mean[0]) * 255. - proc_img[..., 1] = (self.std[1] * imgarr[..., 1] + self.mean[1]) * 255. - proc_img[..., 2] = (self.std[2] * imgarr[..., 2] + self.mean[2]) * 255. - - return proc_img - - def __call__(self, img): - imgarr = np.asarray(img) - proc_img = np.empty_like(imgarr, np.float32) - - proc_img[..., 0] = (imgarr[..., 0] / 255. - self.mean[0]) / self.std[0] - proc_img[..., 1] = (imgarr[..., 1] / 255. - self.mean[1]) / self.std[1] - proc_img[..., 2] = (imgarr[..., 2] / 255. - self.mean[2]) / self.std[2] - - return proc_img - -def load_img_name_list(file_path, index=0): - img_gt_name_list = open(file_path).read().splitlines() - img_name_list = [img_gt_name.split(' ')[index].strip('/') for img_gt_name in img_gt_name_list] - return img_name_list - -def pad(image,pad_size): - w, h = image.size - - pad_mask = Image.new("L", image.size) - pad_height = pad_size[0] - h - pad_width = pad_size[1] - w - - assert pad_height >= 0 and pad_width >= 0 - - pad_l = max(0, pad_width // 2) - pad_r = max(0, pad_width - pad_l) - pad_t = max(0, pad_height // 2) - pad_b = max(0, pad_height - pad_t) - - image = F.pad(image, (pad_l, pad_t, pad_r, pad_b), fill=0, padding_mode="constant") - pad_mask = F.pad(pad_mask, (pad_l, pad_t, pad_r, pad_b), fill=1, padding_mode="constant") - - return image, pad_mask - -def get_batch_bin(img,imgname): - - pad_size = [1024, 1024] - scales = [1, 0.5, 1.5, 2.0] - batch_size = 8 - use_flips = True - - transform = tf.Compose([np.asarray, - Normalize()]) - - for i in range(batch_size): - - sub_idx = i % batch_size - scale = scales[sub_idx // (2 if use_flips else 1)] - - flip = use_flips and sub_idx % 2 - - target_size = (int(round(img.size[0] * scale)), - int(round(img.size[1] * scale))) - - s_img = img.resize(target_size, resample=Image.CUBIC) - - if flip: - s_img = F.hflip(s_img) - im_msc, ignore = pad(s_img,pad_size) - im_msc = transform(im_msc) - ignore = np.array(ignore).astype(im_msc.dtype)[..., np.newaxis] - im_msc = F.to_tensor(im_msc * (1 - ignore)) - - imgnm = imgname + "_" + str(i) - im_msc = np.array(im_msc,dtype= np.float32) - - im_msc.tofile(os.path.join(bin_path, imgnm + '.bin')) - -def preprocess(file_path, voc12_root,bin_path): - - img_name_list = load_img_name_list(file_path) - print(img_name_list) - - if not os.path.exists(bin_path): - os.makedirs(bin_path) - - for i in range(len(img_name_list)): - print("===> ",i) - imgnm = img_name_list[i][33:-4] - img = Image.open(os.path.join(voc12_root, img_name_list[i])).convert('RGB') - - get_batch_bin(img,imgnm) - -if __name__ == "__main__": - - voc12_root_path = os.path.abspath(sys.argv[1]) - file_path = os.path.abspath(sys.argv[2]) - bin_path = os.path.abspath(sys.argv[3]) - - preprocess(file_path,voc12_root_path, bin_path) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import numpy as np +from PIL import Image +import torchvision.transforms.functional as F +import torchvision.transforms as tf + + +class Normalize(): + def __init__(self, mean = (0.485, 0.456, 0.406), std = (0.229, 0.224, 0.225)): + + self.mean = mean + self.std = std + + def undo(self, imgarr): + proc_img = imgarr.copy() + + proc_img[..., 0] = (self.std[0] * imgarr[..., 0] + self.mean[0]) * 255. + proc_img[..., 1] = (self.std[1] * imgarr[..., 1] + self.mean[1]) * 255. + proc_img[..., 2] = (self.std[2] * imgarr[..., 2] + self.mean[2]) * 255. + + return proc_img + + def __call__(self, img): + imgarr = np.asarray(img) + proc_img = np.empty_like(imgarr, np.float32) + + proc_img[..., 0] = (imgarr[..., 0] / 255. - self.mean[0]) / self.std[0] + proc_img[..., 1] = (imgarr[..., 1] / 255. - self.mean[1]) / self.std[1] + proc_img[..., 2] = (imgarr[..., 2] / 255. - self.mean[2]) / self.std[2] + + return proc_img + +def load_img_name_list(file_path, index=0): + img_gt_name_list = open(file_path).read().splitlines() + img_name_list = [img_gt_name.split(' ')[index].strip('/') for img_gt_name in img_gt_name_list] + return img_name_list + +def pad(image,pad_size): + w, h = image.size + + pad_mask = Image.new("L", image.size) + pad_height = pad_size[0] - h + pad_width = pad_size[1] - w + + assert pad_height >= 0 and pad_width >= 0 + + pad_l = max(0, pad_width // 2) + pad_r = max(0, pad_width - pad_l) + pad_t = max(0, pad_height // 2) + pad_b = max(0, pad_height - pad_t) + + image = F.pad(image, (pad_l, pad_t, pad_r, pad_b), fill=0, padding_mode="constant") + pad_mask = F.pad(pad_mask, (pad_l, pad_t, pad_r, pad_b), fill=1, padding_mode="constant") + + return image, pad_mask + +def get_batch_bin(img,imgname): + + pad_size = [1024, 1024] + scales = [1, 0.5, 1.5, 2.0] + batch_size = 8 + use_flips = True + + transform = tf.Compose([np.asarray, + Normalize()]) + + for i in range(batch_size): + + sub_idx = i % batch_size + scale = scales[sub_idx // (2 if use_flips else 1)] + + flip = use_flips and sub_idx % 2 + + target_size = (int(round(img.size[0] * scale)), + int(round(img.size[1] * scale))) + + s_img = img.resize(target_size, resample=Image.CUBIC) + + if flip: + s_img = F.hflip(s_img) + im_msc, ignore = pad(s_img,pad_size) + im_msc = transform(im_msc) + ignore = np.array(ignore).astype(im_msc.dtype)[..., np.newaxis] + im_msc = F.to_tensor(im_msc * (1 - ignore)) + + imgnm = imgname + "_" + str(i) + im_msc = np.array(im_msc,dtype= np.float32) + + im_msc.tofile(os.path.join(bin_path, imgnm + '.bin')) + +def preprocess(file_path, voc12_root,bin_path): + + img_name_list = load_img_name_list(file_path) + print(img_name_list) + + if not os.path.exists(bin_path): + os.makedirs(bin_path) + + for i in range(len(img_name_list)): + print("===> ",i) + imgnm = img_name_list[i][33:-4] + img = Image.open(os.path.join(voc12_root, img_name_list[i])).convert('RGB') + + get_batch_bin(img,imgnm) + +if __name__ == "__main__": + + voc12_root_path = os.path.abspath(sys.argv[1]) + file_path = os.path.abspath(sys.argv[2]) + bin_path = os.path.abspath(sys.argv[3]) + + preprocess(file_path,voc12_root_path, bin_path) diff --git a/ACL_PyTorch/contrib/cv/segmentation/Wseg/fix_softmax_transpose.py b/ACL_PyTorch/contrib/cv/segmentation/Wseg/fix_softmax_transpose.py index 1ad1841a20..9a28eca266 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/Wseg/fix_softmax_transpose.py +++ b/ACL_PyTorch/contrib/cv/segmentation/Wseg/fix_softmax_transpose.py @@ -1,36 +1,36 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import onnx - -if __name__ == '__main__': - model = onnx.load(sys.argv[1]) - graph = model.graph - node = graph.node - softmax_node_index = [] - del_group = [] - for i in range(len(node)): - if node[i].op_type == 'Softmax': - del_group.append((node[i-1], node[i], node[i+1], i)) - for g in del_group: - new_input = g[0].input - new_output = g[2].output - new_name = g[1].name - new_index = g[3] - new_node = onnx.helper.make_node("Softmax", new_input, new_output, new_name, axis=1) - for n in g[:-1]: - graph.node.remove(n) - graph.node.insert(new_index, new_node) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import onnx + +if __name__ == '__main__': + model = onnx.load(sys.argv[1]) + graph = model.graph + node = graph.node + softmax_node_index = [] + del_group = [] + for i in range(len(node)): + if node[i].op_type == 'Softmax': + del_group.append((node[i-1], node[i], node[i+1], i)) + for g in del_group: + new_input = g[0].input + new_output = g[2].output + new_name = g[1].name + new_index = g[3] + new_node = onnx.helper.make_node("Softmax", new_input, new_output, new_name, axis=1) + for n in g[:-1]: + graph.node.remove(n) + graph.node.insert(new_index, new_node) onnx.save(model, sys.argv[2]) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/Wseg/get_dateset_info.py b/ACL_PyTorch/contrib/cv/segmentation/Wseg/get_dateset_info.py index f2f482c10c..f09088e3bc 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/Wseg/get_dateset_info.py +++ b/ACL_PyTorch/contrib/cv/segmentation/Wseg/get_dateset_info.py @@ -1,60 +1,60 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - if file_type == 'bin': - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' - get_jpg_info(file_path, info_name) - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + if file_type == 'bin': + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' + get_jpg_info(file_path, info_name) + diff --git a/ACL_PyTorch/contrib/cv/segmentation/Wseg/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/segmentation/Wseg/modelzoo_level.txt index 282c3ff3b3..c5c4a9d800 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/Wseg/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/segmentation/Wseg/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus:POK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/Wseg/test/parse.py b/ACL_PyTorch/contrib/cv/segmentation/Wseg/test/parse.py index 24e62e8231..3b35884335 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/Wseg/test/parse.py +++ b/ACL_PyTorch/contrib/cv/segmentation/Wseg/test/parse.py @@ -1,33 +1,33 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.eval'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.readlines() - #tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - #print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - print("".join(content[-28:])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.eval'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.readlines() + #tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + #print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + print("".join(content[-28:])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/Wseg/val_voc.txt b/ACL_PyTorch/contrib/cv/segmentation/Wseg/val_voc.txt index 98c6a5540f..e910b33688 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/Wseg/val_voc.txt +++ b/ACL_PyTorch/contrib/cv/segmentation/Wseg/val_voc.txt @@ -1,300 +1,300 @@ -voc/VOCdevkit/VOC2012/JPEGImages/2007_007881.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_007881.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_006275.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_006275.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_006373.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_006373.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_000573.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000573.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_000572.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000572.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_001300.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_001300.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_007804.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007804.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_007378.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007378.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_002728.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_002728.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_000121.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000121.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_002470.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_002470.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_007392.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007392.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_006117.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_006117.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_009841.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_009841.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_002504.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_002504.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_000012.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000012.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_000013.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000013.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_003003.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003003.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_000479.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_000479.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_002094.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_002094.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_004538.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004538.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_007025.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007025.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_005828.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_005828.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_006028.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_006028.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_004324.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004324.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_002152.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_002152.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_003275.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003275.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_003276.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003276.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_001014.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001014.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_000309.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000309.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_002387.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_002387.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_004281.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004281.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_003477.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003477.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_004494.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004494.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_001988.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001988.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_002450.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002450.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_003187.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003187.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_003183.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003183.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_004255.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004255.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_003676.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003676.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_003473.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003473.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_000658.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_000658.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_001708.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001708.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_001529.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001529.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_001830.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001830.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_004789.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004789.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_004190.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004190.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_004193.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004193.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_003564.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003564.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_003569.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003569.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_003876.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003876.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_003874.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003874.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_003506.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003506.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_002900.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002900.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_008296.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_008296.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_002902.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002902.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_008746.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_008746.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_002568.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002568.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_001239.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_001239.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_000874.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_000874.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_003304.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003304.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_001908.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001908.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_003499.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003499.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_003492.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003492.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_002366.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002366.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_005118.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005118.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_000837.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_000837.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_004795.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_004795.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_000830.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_000830.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_000529.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_000529.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_005664.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005664.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_002415.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002415.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_002730.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_002730.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_000602.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_000602.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_002094.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002094.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_000636.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_000636.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_002097.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002097.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_005206.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005206.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_001692.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001692.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_001699.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001699.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_005038.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_005038.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_005097.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_005097.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_001640.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001640.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_005525.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_005525.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_009015.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_009015.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_000731.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_000731.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_005063.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005063.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_008127.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_008127.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_001768.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001768.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_004337.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_004337.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_003270.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003270.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_001767.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001767.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_001563.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001563.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_003137.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_003137.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_003134.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_003134.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_007165.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_007165.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_003131.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_003131.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_008708.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_008708.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_000961.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000961.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_009655.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_009655.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_009654.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_009654.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_007497.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007497.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_006560.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_006560.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_000156.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000156.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_003714.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_003714.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_007498.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007498.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_004612.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_004612.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_006143.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_006143.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_003711.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_003711.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_006364.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_006364.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_001314.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_001314.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_003915.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003915.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_007811.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007811.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_007814.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007814.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_002273.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_002273.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_001260.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001260.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_004825.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_004825.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_002719.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_002719.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_003621.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_003621.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_003369.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003369.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_003481.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003481.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_000573.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000573.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_004070.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004070.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_004072.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004072.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_003323.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003323.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_005857.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_005857.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_007031.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007031.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_002284.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_002284.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_000481.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_000481.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_000482.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_000482.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_002046.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_002046.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_006035.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_006035.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_003709.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003709.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_002445.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_002445.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_007143.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007143.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_001885.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001885.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_005107.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_005107.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_001287.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001287.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_001281.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001281.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_000201.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000201.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_000205.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000205.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_002863.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_002863.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_004856.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004856.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_004189.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004189.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_003773.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003773.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_003771.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003771.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_003576.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003576.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_002391.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_002391.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_002025.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002025.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_000929.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000929.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_003514.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003514.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_002864.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_002864.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_001601.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001601.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_001350.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001350.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_001607.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001607.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_002221.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002221.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_004241.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004241.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_002939.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002939.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_000120.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_000120.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_000123.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_000123.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_003311.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003311.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_001913.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001913.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_005637.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_005637.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_002644.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_002644.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_004687.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004687.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_002641.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_002641.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_004275.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004275.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_002336.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002336.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_002317.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002317.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_002480.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002480.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_005871.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005871.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_001351.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001351.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_005305.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005305.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_004783.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_004783.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_004789.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_004789.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_003406.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003406.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_000630.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_000630.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_005788.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005788.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_002150.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002150.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_001733.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_001733.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_001174.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001174.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_000174.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000174.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_008629.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_008629.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_000175.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_000175.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_000999.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_000999.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_002043.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_002043.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_002042.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002042.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_005644.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005644.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_000700.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_000700.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_003114.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_003114.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_005399.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_005399.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_005398.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_005398.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_004322.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_004322.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_004320.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_004320.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_001773.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001773.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_000318.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000318.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_000087.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000087.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_001579.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001579.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_000084.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000084.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_000083.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000083.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_003271.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_003271.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_001577.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001577.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_005899.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005899.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_001818.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_001818.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_004867.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004867.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_003197.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_003197.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_004432.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_004432.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_000952.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000952.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_000559.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000559.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_007527.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007527.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_000149.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000149.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_006159.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_006159.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_001363.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_001363.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_002467.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_002467.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_002464.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_002464.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_007195.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_007195.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_007196.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_007196.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_002269.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_002269.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_006554.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_006554.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_007828.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007828.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_001078.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001078.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_006036.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_006036.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_001070.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001070.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_003872.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_003872.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_001074.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001074.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_001076.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001076.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_007996.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_007996.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_000427.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000427.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_000426.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000426.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_001565.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_001565.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_000422.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000422.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_001768.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_001768.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_004497.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004497.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_001765.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_001765.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_000964.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000964.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_005844.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_005844.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_005845.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_005845.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_007048.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007048.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_005087.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_005087.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_003503.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_003503.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_003506.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_003506.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_000924.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000924.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_003733.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003733.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_002147.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002147.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_002903.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_002903.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_000747.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_000747.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_003854.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003854.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_000346.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_000346.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_002098.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_002098.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_001292.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001292.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_005114.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_005114.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_001895.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001895.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_004468.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004468.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_006647.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_006647.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_000219.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000219.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_003453.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003453.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_003325.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003325.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_001722.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001722.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_004552.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_004552.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_001726.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001726.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_004866.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004866.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_004649.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004649.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_004644.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004644.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_003542.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003542.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_005158.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_005158.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_003549.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003549.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_002030.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002030.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_003772.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003772.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_000254.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_000254.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_000622.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000622.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_001619.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001619.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_001341.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001341.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_001614.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001614.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_001613.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001613.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_001346.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001346.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_002238.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002238.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_002239.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002239.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_003895.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003895.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_000813.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_000813.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_001587.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_001587.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_002549.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002549.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_001966.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001966.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_002675.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_002675.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_001962.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001962.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_004140.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_004140.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_001478.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001478.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_002075.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_002075.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_002929.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_002929.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_004455.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004455.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_001367.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001367.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_005302.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_005302.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_005860.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005860.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_008434.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_008434.png -voc/VOCdevkit/VOC2012/JPEGImages/2008_001715.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001715.png -voc/VOCdevkit/VOC2012/JPEGImages/2011_002713.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_002713.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_002122.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002122.png -voc/VOCdevkit/VOC2012/JPEGImages/2009_003433.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003433.png -voc/VOCdevkit/VOC2012/JPEGImages/2007_000187.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_000187.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_002146.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002146.png -voc/VOCdevkit/VOC2012/JPEGImages/2010_002929.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002929.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_007881.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_007881.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_006275.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_006275.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_006373.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_006373.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_000573.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000573.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_000572.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000572.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_001300.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_001300.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_007804.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007804.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_007378.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007378.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_002728.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_002728.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_000121.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000121.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_002470.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_002470.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_007392.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007392.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_006117.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_006117.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_009841.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_009841.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_002504.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_002504.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_000012.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000012.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_000013.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000013.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_003003.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003003.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_000479.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_000479.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_002094.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_002094.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_004538.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004538.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_007025.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007025.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_005828.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_005828.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_006028.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_006028.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_004324.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004324.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_002152.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_002152.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_003275.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003275.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_003276.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003276.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_001014.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001014.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_000309.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000309.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_002387.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_002387.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_004281.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004281.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_003477.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003477.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_004494.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004494.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_001988.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001988.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_002450.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002450.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_003187.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003187.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_003183.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003183.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_004255.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004255.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_003676.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003676.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_003473.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003473.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_000658.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_000658.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_001708.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001708.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_001529.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001529.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_001830.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001830.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_004789.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004789.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_004190.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004190.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_004193.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004193.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_003564.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003564.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_003569.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003569.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_003876.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003876.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_003874.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003874.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_003506.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003506.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_002900.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002900.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_008296.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_008296.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_002902.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002902.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_008746.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_008746.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_002568.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002568.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_001239.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_001239.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_000874.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_000874.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_003304.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003304.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_001908.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001908.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_003499.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003499.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_003492.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003492.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_002366.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002366.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_005118.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005118.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_000837.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_000837.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_004795.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_004795.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_000830.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_000830.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_000529.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_000529.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_005664.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005664.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_002415.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002415.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_002730.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_002730.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_000602.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_000602.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_002094.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002094.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_000636.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_000636.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_002097.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002097.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_005206.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005206.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_001692.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001692.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_001699.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001699.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_005038.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_005038.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_005097.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_005097.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_001640.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001640.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_005525.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_005525.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_009015.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_009015.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_000731.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_000731.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_005063.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005063.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_008127.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_008127.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_001768.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001768.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_004337.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_004337.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_003270.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003270.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_001767.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001767.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_001563.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001563.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_003137.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_003137.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_003134.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_003134.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_007165.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_007165.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_003131.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_003131.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_008708.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_008708.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_000961.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000961.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_009655.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_009655.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_009654.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_009654.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_007497.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007497.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_006560.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_006560.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_000156.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000156.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_003714.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_003714.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_007498.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007498.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_004612.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_004612.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_006143.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_006143.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_003711.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_003711.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_006364.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_006364.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_001314.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_001314.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_003915.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003915.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_007811.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007811.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_007814.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007814.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_002273.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_002273.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_001260.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001260.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_004825.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_004825.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_002719.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_002719.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_003621.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_003621.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_003369.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003369.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_003481.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003481.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_000573.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000573.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_004070.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004070.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_004072.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004072.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_003323.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003323.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_005857.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_005857.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_007031.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007031.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_002284.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_002284.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_000481.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_000481.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_000482.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_000482.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_002046.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_002046.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_006035.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_006035.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_003709.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003709.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_002445.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_002445.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_007143.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007143.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_001885.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001885.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_005107.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_005107.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_001287.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001287.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_001281.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001281.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_000201.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000201.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_000205.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000205.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_002863.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_002863.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_004856.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004856.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_004189.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004189.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_003773.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003773.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_003771.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003771.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_003576.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003576.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_002391.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_002391.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_002025.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002025.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_000929.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000929.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_003514.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003514.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_002864.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_002864.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_001601.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001601.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_001350.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001350.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_001607.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001607.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_002221.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002221.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_004241.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004241.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_002939.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002939.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_000120.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_000120.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_000123.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_000123.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_003311.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003311.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_001913.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001913.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_005637.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_005637.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_002644.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_002644.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_004687.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004687.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_002641.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_002641.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_004275.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004275.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_002336.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002336.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_002317.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002317.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_002480.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002480.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_005871.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005871.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_001351.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001351.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_005305.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005305.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_004783.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_004783.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_004789.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_004789.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_003406.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003406.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_000630.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_000630.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_005788.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005788.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_002150.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002150.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_001733.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_001733.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_001174.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001174.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_000174.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000174.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_008629.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_008629.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_000175.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_000175.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_000999.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_000999.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_002043.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_002043.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_002042.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002042.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_005644.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005644.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_000700.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_000700.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_003114.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_003114.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_005399.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_005399.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_005398.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_005398.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_004322.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_004322.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_004320.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_004320.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_001773.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001773.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_000318.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000318.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_000087.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000087.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_001579.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001579.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_000084.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000084.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_000083.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000083.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_003271.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_003271.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_001577.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001577.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_005899.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005899.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_001818.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_001818.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_004867.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004867.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_003197.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_003197.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_004432.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_004432.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_000952.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000952.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_000559.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000559.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_007527.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007527.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_000149.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000149.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_006159.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_006159.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_001363.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_001363.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_002467.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_002467.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_002464.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_002464.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_007195.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_007195.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_007196.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_007196.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_002269.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_002269.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_006554.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_006554.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_007828.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007828.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_001078.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001078.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_006036.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_006036.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_001070.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001070.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_003872.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_003872.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_001074.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001074.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_001076.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001076.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_007996.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_007996.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_000427.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000427.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_000426.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000426.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_001565.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_001565.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_000422.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000422.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_001768.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_001768.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_004497.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004497.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_001765.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_001765.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_000964.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000964.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_005844.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_005844.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_005845.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_005845.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_007048.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_007048.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_005087.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_005087.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_003503.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_003503.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_003506.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_003506.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_000924.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000924.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_003733.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_003733.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_002147.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002147.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_002903.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_002903.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_000747.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_000747.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_003854.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003854.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_000346.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_000346.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_002098.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_002098.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_001292.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001292.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_005114.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_005114.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_001895.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001895.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_004468.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004468.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_006647.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_006647.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_000219.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_000219.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_003453.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003453.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_003325.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003325.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_001722.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001722.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_004552.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_004552.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_001726.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001726.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_004866.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004866.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_004649.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004649.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_004644.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_004644.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_003542.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003542.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_005158.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_005158.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_003549.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003549.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_002030.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002030.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_003772.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_003772.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_000254.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_000254.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_000622.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_000622.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_001619.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001619.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_001341.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001341.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_001614.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001614.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_001613.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001613.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_001346.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_001346.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_002238.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002238.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_002239.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002239.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_003895.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003895.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_000813.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_000813.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_001587.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_001587.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_002549.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002549.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_001966.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001966.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_002675.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_002675.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_001962.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001962.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_004140.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_004140.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_001478.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001478.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_002075.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_002075.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_002929.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_002929.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_004455.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_004455.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_001367.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_001367.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_005302.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_005302.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_005860.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_005860.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_008434.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_008434.png +voc/VOCdevkit/VOC2012/JPEGImages/2008_001715.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2008_001715.png +voc/VOCdevkit/VOC2012/JPEGImages/2011_002713.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2011_002713.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_002122.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_002122.png +voc/VOCdevkit/VOC2012/JPEGImages/2009_003433.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2009_003433.png +voc/VOCdevkit/VOC2012/JPEGImages/2007_000187.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2007_000187.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_002146.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002146.png +voc/VOCdevkit/VOC2012/JPEGImages/2010_002929.jpg voc/VOCdevkit/VOC2012/SegmentationClass/2010_002929.png diff --git a/ACL_PyTorch/contrib/cv/segmentation/YOLACT/README.md b/ACL_PyTorch/contrib/cv/segmentation/YOLACT/README.md index 7ef9506b23..c57fba11d1 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/YOLACT/README.md +++ b/ACL_PyTorch/contrib/cv/segmentation/YOLACT/README.md @@ -1,155 +1,155 @@ -# YOLACT模型PyTorch离线推理指导书 - -### 一、环境准备 - -#### 1、获取依赖库 - -```shell -pip3 install -r requirements.txt -``` - -其中,PyTorch建议使用1.8.0版本。 - -使用1.5.0版本PyTorch可以正常进行om导出,且om模型精度与性能正常;但导出的onnx模型文件无法使用trtexec在T4上进行测试。 - -使用1.8.0版本PyTorch则无以上问题。 - -#### 2、获取YOLACT源代码并更新 - -- 首先获取官方代码仓代码 - - ```bash - git clone https://github.com/dbolya/yolact.git - ``` - -- 将无关文件删除,保留以下文件 - - ``` - . - ├── backbone.py - ├── data - │   ├── coco.py - │   ├── config.py - │   └── __init__.py - ├── layers - │   ├── box_utils.py - │   ├── functions - │   │   ├── detection.py - │   │   └── __init__.py - │   ├── __init__.py - │   ├── interpolate.py - │   └── output_utils.py - ├── utils - │   ├── augmentations.py - │   ├── cython_nms.pyx - │   ├── functions.py - │   ├── __init__.py - │   └── timer.py - └── yolact.py - ``` - -- 将本仓库代码拷贝至yolact目录下,并使用补丁YOLACT.patch复原 - - ``` - patch -p1 < ./YOLACT.patch - ``` - - 复原后,文件目录如下 - - ``` - . - ├── backbone.py - ├── data - │   ├── coco.py - │   ├── config.py - │   └── __init__.py - ├── env.sh - ├── layers - │   ├── box_utils.py - │   ├── functions - │   │   ├── detection.py - │   │   └── __init__.py - │   ├── __init__.py - │   ├── interpolate.py - │   └── output_utils.py - ├── LICENSE - ├── modelzoo_level.txt - ├── README.md - ├── requirements.txt - ├── test - │   ├── eval_acc_perf.sh - │   ├── parse.py - │   ├── perf_g.sh - │   └── pth2om.sh - ├── utils - │   ├── augmentations.py - │   ├── cython_nms.pyx - │   ├── functions.py - │   ├── __init__.py - │   └── timer.py - ├── weights - │   └── pth2onnx.py - ├── YOLACT.patch - ├── YOLACT_postprocess.py - ├── YOLACT_preprocess.py - └── yolact.py - ``` - -#### 3、获取权重文件 - -获取训练完毕的权重文件,建议放于./weights目录下 - -#### 4、获取数据集 - -YOLACT模型使用Microsoft COCO 2017数据集进行训练及测试。 - -在离线推理中仅使用测试数据集,测试图像为val 2017, 对应的标注文件为instances_val2017.json - -#### 5、获取benchmark工具 - -获取benchmark.x86_64离线推理工具 - - - -### 二、离线推理 - -#### 1、执行离线推理前使用以下命令查看设备状态,确保device空闲 - -```bash -npu-smi info -``` - -#### 2、执行以下命令,生成om模型文件 - -```bash -cd test -./pth2om.sh pth权重文件的路径 生成onnx的文件名 生成om的文件名 输入batch_size -``` - -注意:此处pth权重文件的路径应设为相对路径 - -#### 3、执行以下命令,开始离线推理 - -```bash -./eval_acc_perf.sh 数据集图像路径 数据集标注路径 输入batch_size om文件路径 benchmark工具路径 -``` - -同时,benchmark工具会自动统计性能数据 - -#### 4、在T4环境中执行以下命令,获取T4推理性能 - -```bash -./perf_g.sh 输入batch_size onnx文件路径 -``` - -注意,如果使用1.5.0版本PyTorch,则导出的onnx可能无法使用trtexec工具进行性能测试。因此,这里建议使用1.8.0版本PyTroch。 - - - -### 三、评测结果 - -| 模型 | 官网精度 | 310精度 | T4性能 | 310性能 | -| ----------- | ----------------------- | ----------------------- | ---------- | --------- | -| YOLACT_bs1 | box: 32.07,mask: 29.73 | box: 32.07, mask: 29.72 | 75.797FPS | 84.014FPS | -| YOLACT_bs16 | box: 32.07,mask: 29.73 | box: 32.07, mask: 29.72 | 116.596FPS | 96.161FPS | - +# YOLACT模型PyTorch离线推理指导书 + +### 一、环境准备 + +#### 1、获取依赖库 + +```shell +pip3 install -r requirements.txt +``` + +其中,PyTorch建议使用1.8.0版本。 + +使用1.5.0版本PyTorch可以正常进行om导出,且om模型精度与性能正常;但导出的onnx模型文件无法使用trtexec在T4上进行测试。 + +使用1.8.0版本PyTorch则无以上问题。 + +#### 2、获取YOLACT源代码并更新 + +- 首先获取官方代码仓代码 + + ```bash + git clone https://github.com/dbolya/yolact.git + ``` + +- 将无关文件删除,保留以下文件 + + ``` + . + ├── backbone.py + ├── data + │   ├── coco.py + │   ├── config.py + │   └── __init__.py + ├── layers + │   ├── box_utils.py + │   ├── functions + │   │   ├── detection.py + │   │   └── __init__.py + │   ├── __init__.py + │   ├── interpolate.py + │   └── output_utils.py + ├── utils + │   ├── augmentations.py + │   ├── cython_nms.pyx + │   ├── functions.py + │   ├── __init__.py + │   └── timer.py + └── yolact.py + ``` + +- 将本仓库代码拷贝至yolact目录下,并使用补丁YOLACT.patch复原 + + ``` + patch -p1 < ./YOLACT.patch + ``` + + 复原后,文件目录如下 + + ``` + . + ├── backbone.py + ├── data + │   ├── coco.py + │   ├── config.py + │   └── __init__.py + ├── env.sh + ├── layers + │   ├── box_utils.py + │   ├── functions + │   │   ├── detection.py + │   │   └── __init__.py + │   ├── __init__.py + │   ├── interpolate.py + │   └── output_utils.py + ├── LICENSE + ├── modelzoo_level.txt + ├── README.md + ├── requirements.txt + ├── test + │   ├── eval_acc_perf.sh + │   ├── parse.py + │   ├── perf_g.sh + │   └── pth2om.sh + ├── utils + │   ├── augmentations.py + │   ├── cython_nms.pyx + │   ├── functions.py + │   ├── __init__.py + │   └── timer.py + ├── weights + │   └── pth2onnx.py + ├── YOLACT.patch + ├── YOLACT_postprocess.py + ├── YOLACT_preprocess.py + └── yolact.py + ``` + +#### 3、获取权重文件 + +获取训练完毕的权重文件,建议放于./weights目录下 + +#### 4、获取数据集 + +YOLACT模型使用Microsoft COCO 2017数据集进行训练及测试。 + +在离线推理中仅使用测试数据集,测试图像为val 2017, 对应的标注文件为instances_val2017.json + +#### 5、获取benchmark工具 + +获取benchmark.x86_64离线推理工具 + + + +### 二、离线推理 + +#### 1、执行离线推理前使用以下命令查看设备状态,确保device空闲 + +```bash +npu-smi info +``` + +#### 2、执行以下命令,生成om模型文件 + +```bash +cd test +./pth2om.sh pth权重文件的路径 生成onnx的文件名 生成om的文件名 输入batch_size +``` + +注意:此处pth权重文件的路径应设为相对路径 + +#### 3、执行以下命令,开始离线推理 + +```bash +./eval_acc_perf.sh 数据集图像路径 数据集标注路径 输入batch_size om文件路径 benchmark工具路径 +``` + +同时,benchmark工具会自动统计性能数据 + +#### 4、在T4环境中执行以下命令,获取T4推理性能 + +```bash +./perf_g.sh 输入batch_size onnx文件路径 +``` + +注意,如果使用1.5.0版本PyTorch,则导出的onnx可能无法使用trtexec工具进行性能测试。因此,这里建议使用1.8.0版本PyTroch。 + + + +### 三、评测结果 + +| 模型 | 官网精度 | 310精度 | T4性能 | 310性能 | +| ----------- | ----------------------- | ----------------------- | ---------- | --------- | +| YOLACT_bs1 | box: 32.07,mask: 29.73 | box: 32.07, mask: 29.72 | 75.797FPS | 84.014FPS | +| YOLACT_bs16 | box: 32.07,mask: 29.73 | box: 32.07, mask: 29.72 | 116.596FPS | 96.161FPS | + diff --git a/ACL_PyTorch/contrib/cv/segmentation/YOLACT/YOLACT_postprocess.py b/ACL_PyTorch/contrib/cv/segmentation/YOLACT/YOLACT_postprocess.py index 353af75e99..95e32b1ebd 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/YOLACT/YOLACT_postprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/YOLACT/YOLACT_postprocess.py @@ -1,564 +1,564 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -from layers import Detect -from data import COCODetection, get_label_map -from utils.augmentations import BaseTransform -from utils.functions import MovingAverage, ProgressBar -from layers.box_utils import jaccard, mask_iou -from utils import timer -from layers.output_utils import postprocess -import pycocotools -from data import cfg, set_cfg -import numpy as np -import torch -import argparse -import random -import pickle -import os -from collections import defaultdict -from collections import OrderedDict - -def str2bool(v): - if v.lower() in ('yes', 'true', 't', 'y', '1'): - return True - elif v.lower() in ('no', 'false', 'f', 'n', '0'): - return False - else: - raise argparse.ArgumentTypeError('Boolean value expected.') - -def parse_args(argv=None): - parser = argparse.ArgumentParser( - description='YOLACT COCO Evaluation') - parser.add_argument('--valid_images', default='/home/data/coco/images/', help='the path of validation images') - parser.add_argument('--valid_annotations', default='/home/data/coco/annotations/instances_val2017.json', help='the path of validation annotations') - parser.add_argument('--top_k', default=5, type=int, - help='Further restrict the number of predictions to parse') - parser.add_argument('--cuda', default=True, type=str2bool, - help='Use cuda to evaulate model') - parser.add_argument('--fast_nms', default=True, type=str2bool, - help='Whether to use a faster, but not entirely correct version of NMS.') - parser.add_argument('--shuffle', dest='shuffle', action='store_true', - help='Shuffles the images when displaying them. Doesn\'t have much of an effect when display is off though.') - parser.add_argument('--ap_data_file', default='results/ap_data.pkl', type=str, - help='In quantitative mode, the file to save detections before calculating mAP.') - parser.add_argument('--max_images', default=-1, type=int, - help='The maximum number of images from the dataset to consider. Use -1 for all.') - parser.add_argument('--output_coco_json', dest='output_coco_json', action='store_true', - help='If display is not set, instead of processing IoU values, this just dumps detections into the coco json file.') - parser.add_argument('--config', default=None, - help='The config object to use.') - parser.add_argument('--no_bar', dest='no_bar', action='store_true', - help='Do not output the status bar. This is useful for when piping to a file.') - parser.add_argument('--no_sort', default=False, dest='no_sort', action='store_true', - help='Do not sort images by hashed image ID.') - parser.add_argument('--seed', default=None, type=int, - help='The seed to pass into random.seed. Note: this is only really for the shuffle and does not (I think) affect cuda stuff.') - parser.add_argument('--mask_proto_debug', default=False, dest='mask_proto_debug', action='store_true', - help='Outputs stuff for scripts/compute_mask.py.') - parser.add_argument('--score_threshold', default=0, type=float, - help='Detections with a score under this threshold will not be considered. This currently only works in display mode.') - parser.add_argument('--dataset', default=None, type=str, - help='If specified, override the dataset specified in the config with this one (example: coco2017_dataset).') - parser.add_argument('--detect', default=False, dest='detect', action='store_true', - help='Don\'t evauluate the mask branch at all and only do object detection. This only works for --display and --benchmark.') - - parser.set_defaults(no_bar=False, output_coco_json=False, shuffle=False, - no_sort=False, mask_proto_debug=False, detect=False, crop=True) - - global args - args = parser.parse_args(argv) - - if args.seed is not None: - random.seed(args.seed) - -iou_thresholds = [x / 100 for x in range(50, 100, 5)] -coco_cats = {} # Call prep_coco_cats to fill this -coco_cats_inv = {} -color_cache = defaultdict(lambda: {}) - -def prep_coco_cats(): - """ Prepare inverted table for category id lookup given a coco cats object. """ - for coco_cat_id, transformed_cat_id_p1 in get_label_map().items(): - transformed_cat_id = transformed_cat_id_p1 - 1 - coco_cats[transformed_cat_id] = coco_cat_id - coco_cats_inv[coco_cat_id] = transformed_cat_id - -def get_coco_cat(transformed_cat_id): - """ transformed_cat_id is [0,80) as indices in cfg.dataset.class_names """ - return coco_cats[transformed_cat_id] - -def get_transformed_cat(coco_cat_id): - """ transformed_cat_id is [0,80) as indices in cfg.dataset.class_names """ - return coco_cats_inv[coco_cat_id] - -class Detections: - - def __init__(self): - self.bbox_data = [] - self.mask_data = [] - - def add_bbox(self, image_id:int, category_id:int, bbox:list, score:float): - """ Note that bbox should be a list or tuple of (x1, y1, x2, y2) """ - bbox = [bbox[0], bbox[1], bbox[2]-bbox[0], bbox[3]-bbox[1]] - - # Round to the nearest 10th to avoid huge file sizes, as COCO suggests - bbox = [round(float(x)*10)/10 for x in bbox] - - self.bbox_data.append({ - 'image_id': int(image_id), - 'category_id': get_coco_cat(int(category_id)), - 'bbox': bbox, - 'score': float(score) - }) - - def add_mask(self, image_id:int, category_id:int, segmentation:np.ndarray, score:float): - """ The segmentation should be the full mask, the size of the image and with size [h, w]. """ - rle = pycocotools.mask.encode(np.asfortranarray(segmentation.astype(np.uint8))) - rle['counts'] = rle['counts'].decode('ascii') # json.dump doesn't like bytes strings - - self.mask_data.append({ - 'image_id': int(image_id), - 'category_id': get_coco_cat(int(category_id)), - 'segmentation': rle, - 'score': float(score) - }) - -def _mask_iou(mask1, mask2, iscrowd=False): - with timer.env('Mask IoU'): - ret = mask_iou(mask1, mask2, iscrowd) - return ret.cpu() - -def _bbox_iou(bbox1, bbox2, iscrowd=False): - with timer.env('BBox IoU'): - ret = jaccard(bbox1, bbox2, iscrowd) - return ret.cpu() - -def prep_metrics(ap_data, dets, img, gt, gt_masks, h, w, num_crowd, image_id, detections:Detections=None): - """ Returns a list of APs for this image, with each element being for a class """ - if not args.output_coco_json: - with timer.env('Prepare gt'): - gt_boxes = torch.Tensor(gt[:, :4]) - gt_boxes[:, [0, 2]] *= w - gt_boxes[:, [1, 3]] *= h - gt_classes = list(gt[:, 4].astype(int)) - gt_masks = torch.Tensor(gt_masks).view(-1, h*w) - - if num_crowd > 0: - split = lambda x: (x[-num_crowd:], x[:-num_crowd]) - crowd_boxes , gt_boxes = split(gt_boxes) - crowd_masks , gt_masks = split(gt_masks) - crowd_classes, gt_classes = split(gt_classes) - - with timer.env('Postprocess'): - classes, scores, boxes, masks = postprocess(dets, w, h, crop_masks=args.crop, score_threshold=args.score_threshold) - - if classes.size(0) == 0: - return - - classes = list(classes.cpu().numpy().astype(int)) - if isinstance(scores, list): - box_scores = list(scores[0].cpu().numpy().astype(float)) - mask_scores = list(scores[1].cpu().numpy().astype(float)) - else: - scores = list(scores.cpu().numpy().astype(float)) - box_scores = scores - mask_scores = scores - masks = masks.view(-1, h*w) - - - if args.output_coco_json: - with timer.env('JSON Output'): - boxes = boxes.cpu().numpy() - masks = masks.view(-1, h, w).cpu().numpy() - for i in range(masks.shape[0]): - # Make sure that the bounding box actually makes sense and a mask was produced - if (boxes[i, 3] - boxes[i, 1]) * (boxes[i, 2] - boxes[i, 0]) > 0: - detections.add_bbox(image_id, classes[i], boxes[i,:], box_scores[i]) - detections.add_mask(image_id, classes[i], masks[i,:,:], mask_scores[i]) - return - - with timer.env('Eval Setup'): - num_pred = len(classes) - num_gt = len(gt_classes) - - mask_iou_cache = _mask_iou(masks, gt_masks) - bbox_iou_cache = _bbox_iou(boxes.float(), gt_boxes.float()) - - if num_crowd > 0: - crowd_mask_iou_cache = _mask_iou(masks, crowd_masks, iscrowd=True) - crowd_bbox_iou_cache = _bbox_iou(boxes.float(), crowd_boxes.float(), iscrowd=True) - else: - crowd_mask_iou_cache = None - crowd_bbox_iou_cache = None - - box_indices = sorted(range(num_pred), key=lambda i: -box_scores[i]) - mask_indices = sorted(box_indices, key=lambda i: -mask_scores[i]) - - iou_types = [ - ('box', lambda i,j: bbox_iou_cache[i, j].item(), - lambda i,j: crowd_bbox_iou_cache[i,j].item(), - lambda i: box_scores[i], box_indices), - ('mask', lambda i,j: mask_iou_cache[i, j].item(), - lambda i,j: crowd_mask_iou_cache[i,j].item(), - lambda i: mask_scores[i], mask_indices) - ] - - timer.start('Main loop') - for _class in set(classes + gt_classes): - ap_per_iou = [] - num_gt_for_class = sum([1 for x in gt_classes if x == _class]) - - for iouIdx in range(len(iou_thresholds)): - iou_threshold = iou_thresholds[iouIdx] - - for iou_type, iou_func, crowd_func, score_func, indices in iou_types: - gt_used = [False] * len(gt_classes) - - ap_obj = ap_data[iou_type][iouIdx][_class] - ap_obj.add_gt_positives(num_gt_for_class) - - for i in indices: - if classes[i] != _class: - continue - - max_iou_found = iou_threshold - max_match_idx = -1 - for j in range(num_gt): - if gt_used[j] or gt_classes[j] != _class: - continue - - iou = iou_func(i, j) - - if iou > max_iou_found: - max_iou_found = iou - max_match_idx = j - - if max_match_idx >= 0: - gt_used[max_match_idx] = True - ap_obj.push(score_func(i), True) - else: - # If the detection matches a crowd, we can just ignore it - matched_crowd = False - - if num_crowd > 0: - for j in range(len(crowd_classes)): - if crowd_classes[j] != _class: - continue - - iou = crowd_func(i, j) - - if iou > iou_threshold: - matched_crowd = True - break - - # All this crowd code so that we can make sure that our eval code gives the - # same result as COCOEval. There aren't even that many crowd annotations to - # begin with, but accuracy is of the utmost importance. - if not matched_crowd: - ap_obj.push(score_func(i), False) - timer.stop('Main loop') - -class APDataObject: - """ - Stores all the information necessary to calculate the AP for one IoU and one class. - Note: I type annotated this because why not. - """ - - def __init__(self): - self.data_points = [] - self.num_gt_positives = 0 - - def push(self, score:float, is_true:bool): - self.data_points.append((score, is_true)) - - def add_gt_positives(self, num_positives:int): - """ Call this once per image. """ - self.num_gt_positives += num_positives - - def is_empty(self) -> bool: - return len(self.data_points) == 0 and self.num_gt_positives == 0 - - def get_ap(self) -> float: - """ Warning: result not cached. """ - - if self.num_gt_positives == 0: - return 0 - - # Sort descending by score - self.data_points.sort(key=lambda x: -x[0]) - - precisions = [] - recalls = [] - num_true = 0 - num_false = 0 - - # Compute the precision-recall curve. The x axis is recalls and the y axis precisions. - for datum in self.data_points: - # datum[1] is whether the detection a true or false positive - if datum[1]: num_true += 1 - else: num_false += 1 - - precision = num_true / (num_true + num_false) - recall = num_true / self.num_gt_positives - - precisions.append(precision) - recalls.append(recall) - - # Smooth the curve by computing [max(precisions[i:]) for i in range(len(precisions))] - # Basically, remove any temporary dips from the curve. - # At least that's what I think, idk. COCOEval did it so I do too. - for i in range(len(precisions)-1, 0, -1): - if precisions[i] > precisions[i-1]: - precisions[i-1] = precisions[i] - - # Compute the integral of precision(recall) d_recall from recall=0->1 using fixed-length riemann summation with 101 bars. - y_range = [0] * 101 # idx 0 is recall == 0.0 and idx 100 is recall == 1.00 - x_range = np.array([x / 100 for x in range(101)]) - recalls = np.array(recalls) - - # I realize this is weird, but all it does is find the nearest precision(x) for a given x in x_range. - # Basically, if the closest recall we have to 0.01 is 0.009 this sets precision(0.01) = precision(0.009). - # I approximate the integral this way, because that's how COCOEval does it. - indices = np.searchsorted(recalls, x_range, side='left') - for bar_idx, precision_idx in enumerate(indices): - if precision_idx < len(precisions): - y_range[bar_idx] = precisions[precision_idx] - - # Finally compute the riemann sum to get our integral. - # avg([precision(x) for x in 0:0.01:1]) - return sum(y_range) / len(y_range) - -def badhash(x): - """ - Just a quick and dirty hash function for doing a deterministic shuffle based on image_id. - - Source: - https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key - """ - x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF - x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF - x = ((x >> 16) ^ x) & 0xFFFFFFFF - return x - -class InferResultFile(): - def __init__(self, path, fileName): - parts = fileName.split('_') - self.imgId = int(parts[2]) - self.outputId = int(parts[3][0]) - self.arrayValue = np.fromfile(path + fileName, dtype=np.float32) - - self.arrayDim = self.arrayValue.shape[0] - #print('finish read file :', fileName) - -def getAllFiles(path): - allFiles = os.listdir(path) - infoFiles = {} - for file in allFiles: - if '.bin' in file and 'coco_val' in file: - infoFile = InferResultFile(path, file) - if infoFile.imgId in infoFiles.keys(): - infoFiles[infoFile.imgId].append(infoFile) - else: - infoFiles[infoFile.imgId] = [infoFile] - return infoFiles - -class InferResultFileFetcher(): - def __init__(self, path): - self.path = path - - def getInferResult(self, image_idx): - resultDict = {} - for i in range(1, 5): - fileName = 'coco_val2017_' + str(image_idx) + '_' + str(i) + '.bin' - infoFile = InferResultFile(self.path, fileName) - if infoFile.arrayDim == 615936: - resultDict[0] = infoFile - elif infoFile.arrayDim == 1559088: - resultDict[1] = infoFile - elif infoFile.arrayDim == 76992: - resultDict[2] = infoFile - else: - resultDict[3] = infoFile - - return resultDict - -pred_priors = None - -def getPriorTensor(): - global pred_priors - if pred_priors is None: - from yolact import PredictionModule - cfg._tmp_img_h = 550 - cfg._tmp_img_w = 550 - pred_priors = PredictionModule.get_YOLACT_priors().numpy() - return pred_priors - else: - return pred_priors - -def evaluate(path, dataset): - cfg.mask_proto_debug = args.mask_proto_debug - inferResultFetcher = InferResultFileFetcher(path) - - frame_times = MovingAverage() - dataset_size = len(dataset) if args.max_images < 0 else min(args.max_images, len(dataset)) - progress_bar = ProgressBar(30, dataset_size) - - print() - - # For each class and iou, stores tuples (score, isPositive) - # Index ap_data[type][iouIdx][classIdx] - ap_data = { - 'box' : [[APDataObject() for _ in cfg.dataset.class_names] for _ in iou_thresholds], - 'mask': [[APDataObject() for _ in cfg.dataset.class_names] for _ in iou_thresholds] - } - detections = Detections() - - dataset_indices = list(range(len(dataset))) - - if args.shuffle: - random.shuffle(dataset_indices) - elif not args.no_sort: - # Do a deterministic shuffle based on the image ids - # - # I do this because on python 3.5 dictionary key order is *random*, while in 3.6 it's - # the order of insertion. That means on python 3.6, the images come in the order they are in - # in the annotations file. For some reason, the first images in the annotations file are - # the hardest. To combat this, I use a hard-coded hash function based on the image ids - # to shuffle the indices we use. That way, no matter what python version or how pycocotools - # handles the data, we get the same result every time. - hashed = [badhash(x) for x in dataset.ids] - dataset_indices.sort(key=lambda x: hashed[x]) - - dataset_indices = dataset_indices[:dataset_size] - - # Main eval loop - for it, image_idx in enumerate(dataset_indices): - timer.reset() - with timer.env('Load Data'): - img, gt, gt_masks, h, w, num_crowd = dataset.pull_item(image_idx) - # Test flag, do not upvote - with timer.env('Network Extra'): - imgId_Outputs = inferResultFetcher.getInferResult(image_idx) - - pred_mask = imgId_Outputs[0].arrayValue.reshape(1, 19248, 32) #output1 : pred_onnx[2] - pred_conf = imgId_Outputs[1].arrayValue.reshape(1, 19248, 81) #output2 : pred_onnx[1] - pred_loc = imgId_Outputs[2].arrayValue.reshape(1, 19248, 4) #output3 : pred_onnx[0] - pred_proto = imgId_Outputs[3].arrayValue.reshape(1, 138, 138, 32) #output4 : pred_onnx[4] - - detect = Detect(cfg.num_classes, bkg_label=0, top_k=200, conf_thresh=0.05, nms_thresh=0.5) - detect.use_fast_nms = args.fast_nms - preds = detect({'loc': torch.from_numpy(pred_loc), - 'conf': torch.from_numpy(pred_conf), - 'mask': torch.from_numpy(pred_mask), - 'priors': torch.from_numpy(getPriorTensor()), #????? - 'proto': torch.from_numpy(pred_proto)}) - - # Perform the meat of the operation here depending on our mode. - - prep_metrics(ap_data, preds, img, gt, gt_masks, h, w, num_crowd, dataset.ids[image_idx], detections) - # First couple of images take longer because we're constructing the graph. - # Since that's technically initialization, don't include those in the FPS calculations. - if it > 1: - frame_times.add(timer.total_time()) - if not args.no_bar: - if it > 1: fps = 1 / frame_times.get_avg() - else: fps = 0 - progress = (it+1) / dataset_size * 100 - progress_bar.set_val(it+1) - print('\rProcessing Output Results %s %6d / %6d (%5.2f%%) %5.2f fps ' - % (repr(progress_bar), it+1, dataset_size, progress, fps), end='') - - print() - print('Saving data...') - with open(args.ap_data_file, 'wb') as f: - pickle.dump(ap_data, f) - return calc_map(ap_data) - -def calc_map(ap_data): - print('Calculating mAP...') - aps = [{'box': [], 'mask': []} for _ in iou_thresholds] - - for _class in range(len(cfg.dataset.class_names)): - for iou_idx in range(len(iou_thresholds)): - for iou_type in ('box', 'mask'): - ap_obj = ap_data[iou_type][iou_idx][_class] - - if not ap_obj.is_empty(): - aps[iou_idx][iou_type].append(ap_obj.get_ap()) - - all_maps = {'box': OrderedDict(), 'mask': OrderedDict()} - - # Looking back at it, this code is really hard to read :/ - for iou_type in ('box', 'mask'): - all_maps[iou_type]['all'] = 0 # Make this first in the ordereddict - for i, threshold in enumerate(iou_thresholds): - mAP = sum(aps[i][iou_type]) / len(aps[i][iou_type]) * 100 if len(aps[i][iou_type]) > 0 else 0 - all_maps[iou_type][int(threshold*100)] = mAP - all_maps[iou_type]['all'] = (sum(all_maps[iou_type].values()) / (len(all_maps[iou_type].values())-1)) - - print_maps(all_maps) - - # Put in a prettier format so we can serialize it to json during training - all_maps = {k: {j: round(u, 2) for j, u in v.items()} for k, v in all_maps.items()} - return all_maps - -def print_maps(all_maps): - # Warning: hacky - make_row = lambda vals: (' %5s |' * len(vals)) % tuple(vals) - make_sep = lambda n: ('-------+' * n) - - print() - print(make_row([''] + [('.%d ' % x if isinstance(x, int) else x + ' ') for x in all_maps['box'].keys()])) - print(make_sep(len(all_maps['box']) + 1)) - for iou_type in ('box', 'mask'): - print(make_row([iou_type] + ['%.2f' % x if x < 100 else '%.1f' % x for x in all_maps[iou_type].values()])) - print(make_sep(len(all_maps['box']) + 1)) - print() - -if __name__ == '__main__': - path = './result/dumpOutput_device0/' - parse_args() - - if args.config is not None: - set_cfg(args.config) - - else: - args.config = 'yolact_base_config' - print('Config not specified. Parsed %s from the file name.\n' % args.config) - set_cfg(args.config) - - #if args.image is None and args.video is None and args.images is None: - dataset = COCODetection(args.valid_images, args.valid_annotations, - transform=BaseTransform(), has_gt=cfg.dataset.has_gt) - prep_coco_cats() - - evaluate(path, dataset) +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +from layers import Detect +from data import COCODetection, get_label_map +from utils.augmentations import BaseTransform +from utils.functions import MovingAverage, ProgressBar +from layers.box_utils import jaccard, mask_iou +from utils import timer +from layers.output_utils import postprocess +import pycocotools +from data import cfg, set_cfg +import numpy as np +import torch +import argparse +import random +import pickle +import os +from collections import defaultdict +from collections import OrderedDict + +def str2bool(v): + if v.lower() in ('yes', 'true', 't', 'y', '1'): + return True + elif v.lower() in ('no', 'false', 'f', 'n', '0'): + return False + else: + raise argparse.ArgumentTypeError('Boolean value expected.') + +def parse_args(argv=None): + parser = argparse.ArgumentParser( + description='YOLACT COCO Evaluation') + parser.add_argument('--valid_images', default='/home/data/coco/images/', help='the path of validation images') + parser.add_argument('--valid_annotations', default='/home/data/coco/annotations/instances_val2017.json', help='the path of validation annotations') + parser.add_argument('--top_k', default=5, type=int, + help='Further restrict the number of predictions to parse') + parser.add_argument('--cuda', default=True, type=str2bool, + help='Use cuda to evaulate model') + parser.add_argument('--fast_nms', default=True, type=str2bool, + help='Whether to use a faster, but not entirely correct version of NMS.') + parser.add_argument('--shuffle', dest='shuffle', action='store_true', + help='Shuffles the images when displaying them. Doesn\'t have much of an effect when display is off though.') + parser.add_argument('--ap_data_file', default='results/ap_data.pkl', type=str, + help='In quantitative mode, the file to save detections before calculating mAP.') + parser.add_argument('--max_images', default=-1, type=int, + help='The maximum number of images from the dataset to consider. Use -1 for all.') + parser.add_argument('--output_coco_json', dest='output_coco_json', action='store_true', + help='If display is not set, instead of processing IoU values, this just dumps detections into the coco json file.') + parser.add_argument('--config', default=None, + help='The config object to use.') + parser.add_argument('--no_bar', dest='no_bar', action='store_true', + help='Do not output the status bar. This is useful for when piping to a file.') + parser.add_argument('--no_sort', default=False, dest='no_sort', action='store_true', + help='Do not sort images by hashed image ID.') + parser.add_argument('--seed', default=None, type=int, + help='The seed to pass into random.seed. Note: this is only really for the shuffle and does not (I think) affect cuda stuff.') + parser.add_argument('--mask_proto_debug', default=False, dest='mask_proto_debug', action='store_true', + help='Outputs stuff for scripts/compute_mask.py.') + parser.add_argument('--score_threshold', default=0, type=float, + help='Detections with a score under this threshold will not be considered. This currently only works in display mode.') + parser.add_argument('--dataset', default=None, type=str, + help='If specified, override the dataset specified in the config with this one (example: coco2017_dataset).') + parser.add_argument('--detect', default=False, dest='detect', action='store_true', + help='Don\'t evauluate the mask branch at all and only do object detection. This only works for --display and --benchmark.') + + parser.set_defaults(no_bar=False, output_coco_json=False, shuffle=False, + no_sort=False, mask_proto_debug=False, detect=False, crop=True) + + global args + args = parser.parse_args(argv) + + if args.seed is not None: + random.seed(args.seed) + +iou_thresholds = [x / 100 for x in range(50, 100, 5)] +coco_cats = {} # Call prep_coco_cats to fill this +coco_cats_inv = {} +color_cache = defaultdict(lambda: {}) + +def prep_coco_cats(): + """ Prepare inverted table for category id lookup given a coco cats object. """ + for coco_cat_id, transformed_cat_id_p1 in get_label_map().items(): + transformed_cat_id = transformed_cat_id_p1 - 1 + coco_cats[transformed_cat_id] = coco_cat_id + coco_cats_inv[coco_cat_id] = transformed_cat_id + +def get_coco_cat(transformed_cat_id): + """ transformed_cat_id is [0,80) as indices in cfg.dataset.class_names """ + return coco_cats[transformed_cat_id] + +def get_transformed_cat(coco_cat_id): + """ transformed_cat_id is [0,80) as indices in cfg.dataset.class_names """ + return coco_cats_inv[coco_cat_id] + +class Detections: + + def __init__(self): + self.bbox_data = [] + self.mask_data = [] + + def add_bbox(self, image_id:int, category_id:int, bbox:list, score:float): + """ Note that bbox should be a list or tuple of (x1, y1, x2, y2) """ + bbox = [bbox[0], bbox[1], bbox[2]-bbox[0], bbox[3]-bbox[1]] + + # Round to the nearest 10th to avoid huge file sizes, as COCO suggests + bbox = [round(float(x)*10)/10 for x in bbox] + + self.bbox_data.append({ + 'image_id': int(image_id), + 'category_id': get_coco_cat(int(category_id)), + 'bbox': bbox, + 'score': float(score) + }) + + def add_mask(self, image_id:int, category_id:int, segmentation:np.ndarray, score:float): + """ The segmentation should be the full mask, the size of the image and with size [h, w]. """ + rle = pycocotools.mask.encode(np.asfortranarray(segmentation.astype(np.uint8))) + rle['counts'] = rle['counts'].decode('ascii') # json.dump doesn't like bytes strings + + self.mask_data.append({ + 'image_id': int(image_id), + 'category_id': get_coco_cat(int(category_id)), + 'segmentation': rle, + 'score': float(score) + }) + +def _mask_iou(mask1, mask2, iscrowd=False): + with timer.env('Mask IoU'): + ret = mask_iou(mask1, mask2, iscrowd) + return ret.cpu() + +def _bbox_iou(bbox1, bbox2, iscrowd=False): + with timer.env('BBox IoU'): + ret = jaccard(bbox1, bbox2, iscrowd) + return ret.cpu() + +def prep_metrics(ap_data, dets, img, gt, gt_masks, h, w, num_crowd, image_id, detections:Detections=None): + """ Returns a list of APs for this image, with each element being for a class """ + if not args.output_coco_json: + with timer.env('Prepare gt'): + gt_boxes = torch.Tensor(gt[:, :4]) + gt_boxes[:, [0, 2]] *= w + gt_boxes[:, [1, 3]] *= h + gt_classes = list(gt[:, 4].astype(int)) + gt_masks = torch.Tensor(gt_masks).view(-1, h*w) + + if num_crowd > 0: + split = lambda x: (x[-num_crowd:], x[:-num_crowd]) + crowd_boxes , gt_boxes = split(gt_boxes) + crowd_masks , gt_masks = split(gt_masks) + crowd_classes, gt_classes = split(gt_classes) + + with timer.env('Postprocess'): + classes, scores, boxes, masks = postprocess(dets, w, h, crop_masks=args.crop, score_threshold=args.score_threshold) + + if classes.size(0) == 0: + return + + classes = list(classes.cpu().numpy().astype(int)) + if isinstance(scores, list): + box_scores = list(scores[0].cpu().numpy().astype(float)) + mask_scores = list(scores[1].cpu().numpy().astype(float)) + else: + scores = list(scores.cpu().numpy().astype(float)) + box_scores = scores + mask_scores = scores + masks = masks.view(-1, h*w) + + + if args.output_coco_json: + with timer.env('JSON Output'): + boxes = boxes.cpu().numpy() + masks = masks.view(-1, h, w).cpu().numpy() + for i in range(masks.shape[0]): + # Make sure that the bounding box actually makes sense and a mask was produced + if (boxes[i, 3] - boxes[i, 1]) * (boxes[i, 2] - boxes[i, 0]) > 0: + detections.add_bbox(image_id, classes[i], boxes[i,:], box_scores[i]) + detections.add_mask(image_id, classes[i], masks[i,:,:], mask_scores[i]) + return + + with timer.env('Eval Setup'): + num_pred = len(classes) + num_gt = len(gt_classes) + + mask_iou_cache = _mask_iou(masks, gt_masks) + bbox_iou_cache = _bbox_iou(boxes.float(), gt_boxes.float()) + + if num_crowd > 0: + crowd_mask_iou_cache = _mask_iou(masks, crowd_masks, iscrowd=True) + crowd_bbox_iou_cache = _bbox_iou(boxes.float(), crowd_boxes.float(), iscrowd=True) + else: + crowd_mask_iou_cache = None + crowd_bbox_iou_cache = None + + box_indices = sorted(range(num_pred), key=lambda i: -box_scores[i]) + mask_indices = sorted(box_indices, key=lambda i: -mask_scores[i]) + + iou_types = [ + ('box', lambda i,j: bbox_iou_cache[i, j].item(), + lambda i,j: crowd_bbox_iou_cache[i,j].item(), + lambda i: box_scores[i], box_indices), + ('mask', lambda i,j: mask_iou_cache[i, j].item(), + lambda i,j: crowd_mask_iou_cache[i,j].item(), + lambda i: mask_scores[i], mask_indices) + ] + + timer.start('Main loop') + for _class in set(classes + gt_classes): + ap_per_iou = [] + num_gt_for_class = sum([1 for x in gt_classes if x == _class]) + + for iouIdx in range(len(iou_thresholds)): + iou_threshold = iou_thresholds[iouIdx] + + for iou_type, iou_func, crowd_func, score_func, indices in iou_types: + gt_used = [False] * len(gt_classes) + + ap_obj = ap_data[iou_type][iouIdx][_class] + ap_obj.add_gt_positives(num_gt_for_class) + + for i in indices: + if classes[i] != _class: + continue + + max_iou_found = iou_threshold + max_match_idx = -1 + for j in range(num_gt): + if gt_used[j] or gt_classes[j] != _class: + continue + + iou = iou_func(i, j) + + if iou > max_iou_found: + max_iou_found = iou + max_match_idx = j + + if max_match_idx >= 0: + gt_used[max_match_idx] = True + ap_obj.push(score_func(i), True) + else: + # If the detection matches a crowd, we can just ignore it + matched_crowd = False + + if num_crowd > 0: + for j in range(len(crowd_classes)): + if crowd_classes[j] != _class: + continue + + iou = crowd_func(i, j) + + if iou > iou_threshold: + matched_crowd = True + break + + # All this crowd code so that we can make sure that our eval code gives the + # same result as COCOEval. There aren't even that many crowd annotations to + # begin with, but accuracy is of the utmost importance. + if not matched_crowd: + ap_obj.push(score_func(i), False) + timer.stop('Main loop') + +class APDataObject: + """ + Stores all the information necessary to calculate the AP for one IoU and one class. + Note: I type annotated this because why not. + """ + + def __init__(self): + self.data_points = [] + self.num_gt_positives = 0 + + def push(self, score:float, is_true:bool): + self.data_points.append((score, is_true)) + + def add_gt_positives(self, num_positives:int): + """ Call this once per image. """ + self.num_gt_positives += num_positives + + def is_empty(self) -> bool: + return len(self.data_points) == 0 and self.num_gt_positives == 0 + + def get_ap(self) -> float: + """ Warning: result not cached. """ + + if self.num_gt_positives == 0: + return 0 + + # Sort descending by score + self.data_points.sort(key=lambda x: -x[0]) + + precisions = [] + recalls = [] + num_true = 0 + num_false = 0 + + # Compute the precision-recall curve. The x axis is recalls and the y axis precisions. + for datum in self.data_points: + # datum[1] is whether the detection a true or false positive + if datum[1]: num_true += 1 + else: num_false += 1 + + precision = num_true / (num_true + num_false) + recall = num_true / self.num_gt_positives + + precisions.append(precision) + recalls.append(recall) + + # Smooth the curve by computing [max(precisions[i:]) for i in range(len(precisions))] + # Basically, remove any temporary dips from the curve. + # At least that's what I think, idk. COCOEval did it so I do too. + for i in range(len(precisions)-1, 0, -1): + if precisions[i] > precisions[i-1]: + precisions[i-1] = precisions[i] + + # Compute the integral of precision(recall) d_recall from recall=0->1 using fixed-length riemann summation with 101 bars. + y_range = [0] * 101 # idx 0 is recall == 0.0 and idx 100 is recall == 1.00 + x_range = np.array([x / 100 for x in range(101)]) + recalls = np.array(recalls) + + # I realize this is weird, but all it does is find the nearest precision(x) for a given x in x_range. + # Basically, if the closest recall we have to 0.01 is 0.009 this sets precision(0.01) = precision(0.009). + # I approximate the integral this way, because that's how COCOEval does it. + indices = np.searchsorted(recalls, x_range, side='left') + for bar_idx, precision_idx in enumerate(indices): + if precision_idx < len(precisions): + y_range[bar_idx] = precisions[precision_idx] + + # Finally compute the riemann sum to get our integral. + # avg([precision(x) for x in 0:0.01:1]) + return sum(y_range) / len(y_range) + +def badhash(x): + """ + Just a quick and dirty hash function for doing a deterministic shuffle based on image_id. + + Source: + https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key + """ + x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF + x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF + x = ((x >> 16) ^ x) & 0xFFFFFFFF + return x + +class InferResultFile(): + def __init__(self, path, fileName): + parts = fileName.split('_') + self.imgId = int(parts[2]) + self.outputId = int(parts[3][0]) + self.arrayValue = np.fromfile(path + fileName, dtype=np.float32) + + self.arrayDim = self.arrayValue.shape[0] + #print('finish read file :', fileName) + +def getAllFiles(path): + allFiles = os.listdir(path) + infoFiles = {} + for file in allFiles: + if '.bin' in file and 'coco_val' in file: + infoFile = InferResultFile(path, file) + if infoFile.imgId in infoFiles.keys(): + infoFiles[infoFile.imgId].append(infoFile) + else: + infoFiles[infoFile.imgId] = [infoFile] + return infoFiles + +class InferResultFileFetcher(): + def __init__(self, path): + self.path = path + + def getInferResult(self, image_idx): + resultDict = {} + for i in range(1, 5): + fileName = 'coco_val2017_' + str(image_idx) + '_' + str(i) + '.bin' + infoFile = InferResultFile(self.path, fileName) + if infoFile.arrayDim == 615936: + resultDict[0] = infoFile + elif infoFile.arrayDim == 1559088: + resultDict[1] = infoFile + elif infoFile.arrayDim == 76992: + resultDict[2] = infoFile + else: + resultDict[3] = infoFile + + return resultDict + +pred_priors = None + +def getPriorTensor(): + global pred_priors + if pred_priors is None: + from yolact import PredictionModule + cfg._tmp_img_h = 550 + cfg._tmp_img_w = 550 + pred_priors = PredictionModule.get_YOLACT_priors().numpy() + return pred_priors + else: + return pred_priors + +def evaluate(path, dataset): + cfg.mask_proto_debug = args.mask_proto_debug + inferResultFetcher = InferResultFileFetcher(path) + + frame_times = MovingAverage() + dataset_size = len(dataset) if args.max_images < 0 else min(args.max_images, len(dataset)) + progress_bar = ProgressBar(30, dataset_size) + + print() + + # For each class and iou, stores tuples (score, isPositive) + # Index ap_data[type][iouIdx][classIdx] + ap_data = { + 'box' : [[APDataObject() for _ in cfg.dataset.class_names] for _ in iou_thresholds], + 'mask': [[APDataObject() for _ in cfg.dataset.class_names] for _ in iou_thresholds] + } + detections = Detections() + + dataset_indices = list(range(len(dataset))) + + if args.shuffle: + random.shuffle(dataset_indices) + elif not args.no_sort: + # Do a deterministic shuffle based on the image ids + # + # I do this because on python 3.5 dictionary key order is *random*, while in 3.6 it's + # the order of insertion. That means on python 3.6, the images come in the order they are in + # in the annotations file. For some reason, the first images in the annotations file are + # the hardest. To combat this, I use a hard-coded hash function based on the image ids + # to shuffle the indices we use. That way, no matter what python version or how pycocotools + # handles the data, we get the same result every time. + hashed = [badhash(x) for x in dataset.ids] + dataset_indices.sort(key=lambda x: hashed[x]) + + dataset_indices = dataset_indices[:dataset_size] + + # Main eval loop + for it, image_idx in enumerate(dataset_indices): + timer.reset() + with timer.env('Load Data'): + img, gt, gt_masks, h, w, num_crowd = dataset.pull_item(image_idx) + # Test flag, do not upvote + with timer.env('Network Extra'): + imgId_Outputs = inferResultFetcher.getInferResult(image_idx) + + pred_mask = imgId_Outputs[0].arrayValue.reshape(1, 19248, 32) #output1 : pred_onnx[2] + pred_conf = imgId_Outputs[1].arrayValue.reshape(1, 19248, 81) #output2 : pred_onnx[1] + pred_loc = imgId_Outputs[2].arrayValue.reshape(1, 19248, 4) #output3 : pred_onnx[0] + pred_proto = imgId_Outputs[3].arrayValue.reshape(1, 138, 138, 32) #output4 : pred_onnx[4] + + detect = Detect(cfg.num_classes, bkg_label=0, top_k=200, conf_thresh=0.05, nms_thresh=0.5) + detect.use_fast_nms = args.fast_nms + preds = detect({'loc': torch.from_numpy(pred_loc), + 'conf': torch.from_numpy(pred_conf), + 'mask': torch.from_numpy(pred_mask), + 'priors': torch.from_numpy(getPriorTensor()), #????? + 'proto': torch.from_numpy(pred_proto)}) + + # Perform the meat of the operation here depending on our mode. + + prep_metrics(ap_data, preds, img, gt, gt_masks, h, w, num_crowd, dataset.ids[image_idx], detections) + # First couple of images take longer because we're constructing the graph. + # Since that's technically initialization, don't include those in the FPS calculations. + if it > 1: + frame_times.add(timer.total_time()) + if not args.no_bar: + if it > 1: fps = 1 / frame_times.get_avg() + else: fps = 0 + progress = (it+1) / dataset_size * 100 + progress_bar.set_val(it+1) + print('\rProcessing Output Results %s %6d / %6d (%5.2f%%) %5.2f fps ' + % (repr(progress_bar), it+1, dataset_size, progress, fps), end='') + + print() + print('Saving data...') + with open(args.ap_data_file, 'wb') as f: + pickle.dump(ap_data, f) + return calc_map(ap_data) + +def calc_map(ap_data): + print('Calculating mAP...') + aps = [{'box': [], 'mask': []} for _ in iou_thresholds] + + for _class in range(len(cfg.dataset.class_names)): + for iou_idx in range(len(iou_thresholds)): + for iou_type in ('box', 'mask'): + ap_obj = ap_data[iou_type][iou_idx][_class] + + if not ap_obj.is_empty(): + aps[iou_idx][iou_type].append(ap_obj.get_ap()) + + all_maps = {'box': OrderedDict(), 'mask': OrderedDict()} + + # Looking back at it, this code is really hard to read :/ + for iou_type in ('box', 'mask'): + all_maps[iou_type]['all'] = 0 # Make this first in the ordereddict + for i, threshold in enumerate(iou_thresholds): + mAP = sum(aps[i][iou_type]) / len(aps[i][iou_type]) * 100 if len(aps[i][iou_type]) > 0 else 0 + all_maps[iou_type][int(threshold*100)] = mAP + all_maps[iou_type]['all'] = (sum(all_maps[iou_type].values()) / (len(all_maps[iou_type].values())-1)) + + print_maps(all_maps) + + # Put in a prettier format so we can serialize it to json during training + all_maps = {k: {j: round(u, 2) for j, u in v.items()} for k, v in all_maps.items()} + return all_maps + +def print_maps(all_maps): + # Warning: hacky + make_row = lambda vals: (' %5s |' * len(vals)) % tuple(vals) + make_sep = lambda n: ('-------+' * n) + + print() + print(make_row([''] + [('.%d ' % x if isinstance(x, int) else x + ' ') for x in all_maps['box'].keys()])) + print(make_sep(len(all_maps['box']) + 1)) + for iou_type in ('box', 'mask'): + print(make_row([iou_type] + ['%.2f' % x if x < 100 else '%.1f' % x for x in all_maps[iou_type].values()])) + print(make_sep(len(all_maps['box']) + 1)) + print() + +if __name__ == '__main__': + path = './result/dumpOutput_device0/' + parse_args() + + if args.config is not None: + set_cfg(args.config) + + else: + args.config = 'yolact_base_config' + print('Config not specified. Parsed %s from the file name.\n' % args.config) + set_cfg(args.config) + + #if args.image is None and args.video is None and args.images is None: + dataset = COCODetection(args.valid_images, args.valid_annotations, + transform=BaseTransform(), has_gt=cfg.dataset.has_gt) + prep_coco_cats() + + evaluate(path, dataset) diff --git a/ACL_PyTorch/contrib/cv/segmentation/YOLACT/YOLACT_preprocess.py b/ACL_PyTorch/contrib/cv/segmentation/YOLACT/YOLACT_preprocess.py index 1ae885bb88..3d0d49a691 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/YOLACT/YOLACT_preprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/YOLACT/YOLACT_preprocess.py @@ -1,174 +1,174 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -from data import COCODetection, get_label_map -from utils.augmentations import BaseTransform -from data import cfg, set_cfg -import numpy as np -from torch.autograd import Variable -import argparse -import random -import os -from collections import defaultdict - -def str2bool(v): - if v.lower() in ('yes', 'true', 't', 'y', '1'): - return True - elif v.lower() in ('no', 'false', 'f', 'n', '0'): - return False - else: - raise argparse.ArgumentTypeError('Boolean value expected.') - -def parse_args(argv=None): - parser = argparse.ArgumentParser( - description='YOLACT COCO Evaluation') - parser.add_argument('--valid_images', default='/home/data/coco/images/', help='the path of validation images') - parser.add_argument('--valid_annotations', default='/home/data/coco/annotations/instances_val2017.json', help='the path of validation annotations') - parser.add_argument('--saved_path', default='./', help='the path of binary data and info file') - parser.add_argument('--cuda', default=True, type=str2bool, - help='Use cuda to evaulate model') - parser.add_argument('--display', dest='display', action='store_true', - help='Display qualitative results instead of quantitative ones.') - parser.add_argument('--shuffle', dest='shuffle', action='store_true', - help='Shuffles the images when displaying them. Doesn\'t have much of an effect when display is off though.') - parser.add_argument('--resume', dest='resume', action='store_true', - help='If display not set, this resumes mAP calculations from the ap_data_file.') - parser.add_argument('--max_images', default=-1, type=int, - help='The maximum number of images from the dataset to consider. Use -1 for all.') - parser.add_argument('--config', default=None, - help='The config object to use.') - parser.add_argument('--no_sort', default=False, dest='no_sort', action='store_true', - help='Do not sort images by hashed image ID.') - parser.add_argument('--seed', default=None, type=int, - help='The seed to pass into random.seed. Note: this is only really for the shuffle and does not (I think) affect cuda stuff.') - parser.add_argument('--image', default=None, type=str, - help='A path to an image to use for display.') - parser.add_argument('--images', default=None, type=str, - help='An input folder of images and output folder to save detected images. Should be in the format input->output.') - parser.add_argument('--dataset', default=None, type=str, - help='If specified, override the dataset specified in the config with this one (example: coco2017_dataset).') - parser.set_defaults(display=False, resume=False, shuffle=False, - no_sort=False) - - global args - args = parser.parse_args(argv) - - if args.seed is not None: - random.seed(args.seed) - -iou_thresholds = [x / 100 for x in range(50, 100, 5)] -coco_cats = {} # Call prep_coco_cats to fill this -coco_cats_inv = {} -color_cache = defaultdict(lambda: {}) - -def prep_coco_cats(): - """ Prepare inverted table for category id lookup given a coco cats object. """ - for coco_cat_id, transformed_cat_id_p1 in get_label_map().items(): - transformed_cat_id = transformed_cat_id_p1 - 1 - coco_cats[transformed_cat_id] = coco_cat_id - coco_cats_inv[coco_cat_id] = transformed_cat_id - -def badhash(x): - """ - Just a quick and dirty hash function for doing a deterministic shuffle based on image_id. - - Source: - https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key - """ - x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF - x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF - x = ((x >> 16) ^ x) & 0xFFFFFFFF - return x - -def preprocess(dataset, save_path = None): - dataset_size = len(dataset) if args.max_images < 0 else min(args.max_images, len(dataset)) - print("dataset size is : ", dataset_size) - print() - - # For each class and iou, stores tuples (score, isPositive) - # Index ap_data[type][iouIdx][classIdx] - dataset_indices = list(range(len(dataset))) - print("dataset indices size is :", len(dataset_indices)) - if args.shuffle: - random.shuffle(dataset_indices) - elif not args.no_sort: - hashed = [badhash(x) for x in dataset.ids] - dataset_indices.sort(key=lambda x: hashed[x]) - - dataset_indices = dataset_indices[:dataset_size] - - if save_path is None: - save_path = os.path.join(args.saved_path, 'prep_dataset') - - if os.path.exists(save_path) == False: - os.mkdir(save_path) - else: - print('dir exist!') - - # Main eval loop - with open(os.path.join(args.saved_path, 'yolact_prep_bin.info'), 'w+') as f: - for it, image_idx in enumerate(dataset_indices): - img, gt, gt_masks, h, w, num_crowd = dataset.pull_item(image_idx) - # Test flag, do not upvote - batch = Variable(img.unsqueeze(0)) - batch_numpy = np.array(batch).astype(np.float32) - - binFileName = os.path.join(save_path, 'coco_val2017_' + str(image_idx) + '.bin') - - batch_numpy.tofile(binFileName) - - line = str(it) + ' ' + binFileName + ' ' + '550 550\n' - f.write(line) - if it % 100 == 0: - print('[INFO][PreProcess]', 'CurSampleNum:', it) - -if __name__ == '__main__': - parse_args() - - if args.config is not None: - set_cfg(args.config) - - else: - args.config = 'yolact_base_config' - print('Config not specified. Parsed %s from the file name.\n' % args.config) - set_cfg(args.config) - - if not os.path.exists('results'): - os.makedirs('results') - - #if args.image is None and args.video is None and args.images is None: - dataset = COCODetection(args.valid_images, args.valid_annotations, - transform=BaseTransform(), has_gt=cfg.dataset.has_gt) - prep_coco_cats() - - preprocess(dataset) - - +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +from data import COCODetection, get_label_map +from utils.augmentations import BaseTransform +from data import cfg, set_cfg +import numpy as np +from torch.autograd import Variable +import argparse +import random +import os +from collections import defaultdict + +def str2bool(v): + if v.lower() in ('yes', 'true', 't', 'y', '1'): + return True + elif v.lower() in ('no', 'false', 'f', 'n', '0'): + return False + else: + raise argparse.ArgumentTypeError('Boolean value expected.') + +def parse_args(argv=None): + parser = argparse.ArgumentParser( + description='YOLACT COCO Evaluation') + parser.add_argument('--valid_images', default='/home/data/coco/images/', help='the path of validation images') + parser.add_argument('--valid_annotations', default='/home/data/coco/annotations/instances_val2017.json', help='the path of validation annotations') + parser.add_argument('--saved_path', default='./', help='the path of binary data and info file') + parser.add_argument('--cuda', default=True, type=str2bool, + help='Use cuda to evaulate model') + parser.add_argument('--display', dest='display', action='store_true', + help='Display qualitative results instead of quantitative ones.') + parser.add_argument('--shuffle', dest='shuffle', action='store_true', + help='Shuffles the images when displaying them. Doesn\'t have much of an effect when display is off though.') + parser.add_argument('--resume', dest='resume', action='store_true', + help='If display not set, this resumes mAP calculations from the ap_data_file.') + parser.add_argument('--max_images', default=-1, type=int, + help='The maximum number of images from the dataset to consider. Use -1 for all.') + parser.add_argument('--config', default=None, + help='The config object to use.') + parser.add_argument('--no_sort', default=False, dest='no_sort', action='store_true', + help='Do not sort images by hashed image ID.') + parser.add_argument('--seed', default=None, type=int, + help='The seed to pass into random.seed. Note: this is only really for the shuffle and does not (I think) affect cuda stuff.') + parser.add_argument('--image', default=None, type=str, + help='A path to an image to use for display.') + parser.add_argument('--images', default=None, type=str, + help='An input folder of images and output folder to save detected images. Should be in the format input->output.') + parser.add_argument('--dataset', default=None, type=str, + help='If specified, override the dataset specified in the config with this one (example: coco2017_dataset).') + parser.set_defaults(display=False, resume=False, shuffle=False, + no_sort=False) + + global args + args = parser.parse_args(argv) + + if args.seed is not None: + random.seed(args.seed) + +iou_thresholds = [x / 100 for x in range(50, 100, 5)] +coco_cats = {} # Call prep_coco_cats to fill this +coco_cats_inv = {} +color_cache = defaultdict(lambda: {}) + +def prep_coco_cats(): + """ Prepare inverted table for category id lookup given a coco cats object. """ + for coco_cat_id, transformed_cat_id_p1 in get_label_map().items(): + transformed_cat_id = transformed_cat_id_p1 - 1 + coco_cats[transformed_cat_id] = coco_cat_id + coco_cats_inv[coco_cat_id] = transformed_cat_id + +def badhash(x): + """ + Just a quick and dirty hash function for doing a deterministic shuffle based on image_id. + + Source: + https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key + """ + x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF + x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF + x = ((x >> 16) ^ x) & 0xFFFFFFFF + return x + +def preprocess(dataset, save_path = None): + dataset_size = len(dataset) if args.max_images < 0 else min(args.max_images, len(dataset)) + print("dataset size is : ", dataset_size) + print() + + # For each class and iou, stores tuples (score, isPositive) + # Index ap_data[type][iouIdx][classIdx] + dataset_indices = list(range(len(dataset))) + print("dataset indices size is :", len(dataset_indices)) + if args.shuffle: + random.shuffle(dataset_indices) + elif not args.no_sort: + hashed = [badhash(x) for x in dataset.ids] + dataset_indices.sort(key=lambda x: hashed[x]) + + dataset_indices = dataset_indices[:dataset_size] + + if save_path is None: + save_path = os.path.join(args.saved_path, 'prep_dataset') + + if os.path.exists(save_path) == False: + os.mkdir(save_path) + else: + print('dir exist!') + + # Main eval loop + with open(os.path.join(args.saved_path, 'yolact_prep_bin.info'), 'w+') as f: + for it, image_idx in enumerate(dataset_indices): + img, gt, gt_masks, h, w, num_crowd = dataset.pull_item(image_idx) + # Test flag, do not upvote + batch = Variable(img.unsqueeze(0)) + batch_numpy = np.array(batch).astype(np.float32) + + binFileName = os.path.join(save_path, 'coco_val2017_' + str(image_idx) + '.bin') + + batch_numpy.tofile(binFileName) + + line = str(it) + ' ' + binFileName + ' ' + '550 550\n' + f.write(line) + if it % 100 == 0: + print('[INFO][PreProcess]', 'CurSampleNum:', it) + +if __name__ == '__main__': + parse_args() + + if args.config is not None: + set_cfg(args.config) + + else: + args.config = 'yolact_base_config' + print('Config not specified. Parsed %s from the file name.\n' % args.config) + set_cfg(args.config) + + if not os.path.exists('results'): + os.makedirs('results') + + #if args.image is None and args.video is None and args.images is None: + dataset = COCODetection(args.valid_images, args.valid_annotations, + transform=BaseTransform(), has_gt=cfg.dataset.has_gt) + prep_coco_cats() + + preprocess(dataset) + + diff --git a/ACL_PyTorch/contrib/cv/segmentation/YOLACT/test/eval_acc_perf.sh b/ACL_PyTorch/contrib/cv/segmentation/YOLACT/test/eval_acc_perf.sh old mode 100755 new mode 100644 diff --git a/ACL_PyTorch/contrib/cv/segmentation/YOLACT/test/parse.py b/ACL_PyTorch/contrib/cv/segmentation/YOLACT/test/parse.py index a0f253b055..27eae0d0ac 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/YOLACT/test/parse.py +++ b/ACL_PyTorch/contrib/cv/segmentation/YOLACT/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/YOLACT/test/perf_g.sh b/ACL_PyTorch/contrib/cv/segmentation/YOLACT/test/perf_g.sh old mode 100755 new mode 100644 diff --git a/ACL_PyTorch/contrib/cv/segmentation/YOLACT/test/pth2om.sh b/ACL_PyTorch/contrib/cv/segmentation/YOLACT/test/pth2om.sh old mode 100755 new mode 100644 diff --git a/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/LICENSE b/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/LICENSE +++ b/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/README.md b/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/README.md index ade13dfe13..4b9e18211f 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/README.md +++ b/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/README.md @@ -1,159 +1,159 @@ -# YOLACT模型PyTorch离线推理说明 - -### 一、环境准备 - -#### 1、获取依赖库 - -```shell -pip3 install -r requirements.txt -git clone -b pytorch_1.5 https://github.com/ifzhang/DCNv2.git -cd DCNv2 -python3.7 setup.py build develop -patch -p1 < ../dcnv2.diff -``` - -#### 2、获取YOLACT源代码并更新 - -- 首先获取官方代码仓代码 - - ```bash - git clone https://github.com/dbolya/yolact.git - ``` - -- 将无关文件删除,保留以下文件 - - ``` - . - ├── backbone.py - ├── data - │   ├── coco.py - │   ├── config.py - │   └── __init__.py - ├── layers - │   ├── box_utils.py - │   ├── functions - │   │   ├── detection.py - │   │   └── __init__.py - │   ├── __init__.py - │   ├── interpolate.py - │   └── output_utils.py - ├── utils - │   ├── augmentations.py - │   ├── cython_nms.pyx - │   ├── functions.py - │   ├── __init__.py - │   └── timer.py - └── yolact.py - ``` - -- 将本仓库代码拷贝至yolact目录下,并使用补丁YOLACT.patch复原 - - ``` - patch -p1 < ./YOLACT.patch - ``` - - - 复原后,文件目录如下 - - ``` - . - ├── backbone.py - ├── data - │   ├── coco.py - │   ├── config.py - │   └── __init__.py - ├── env.sh - ├── dcnv2.diff - ├── DCNv2 - ├── layers - │   ├── box_utils.py - │   ├── functions - │   │   ├── detection.py - │   │   └── __init__.py - │   ├── __init__.py - │   ├── interpolate.py - │   └── output_utils.py - ├── LICENSE - ├── modelzoo_level.txt - ├── README.md - ├── requirements.txt - ├── test - │   ├── eval_acc_perf.sh - │   ├── parse.py - │   ├── prior.bin - │   └── pth2om.sh - ├── utils - │   ├── augmentations.py - │   ├── cython_nms.pyx - │   ├── functions.py - │   ├── __init__.py - │   └── timer.py - ├── weights - │   └── pth2onnx.py - ├── YOLACT.patch - ├── YOLACT_postprocess.py - ├── YOLACT_preprocess.py - └── yolact.py - ``` - -#### 3、获取权重文件 - -官方训练完毕的权重文件:yolact_plus_resnet50_54_800000.pth - -训练完毕的权重文件放于./weights目录下 - -#### 4、获取数据集 - -YOLACT模型使用Microsoft COCO 2017数据集进行训练及测试,下载数据集命令如下: - -```bash -cd data/scripts -bash ./COCO.sh #获取测试数据集 -``` - -在离线推理中仅使用测试数据集,测试图像为val 2017, 对应的标注文件为instances_val2017.json - -#### 5、获取benchmark工具 - -获取benchmark.x86_64离线推理工具 - - - -### 二、离线推理 - -#### 1、执行离线推理前使用以下命令查看设备状态,确保device空闲 - -```bash -npu-smi info -``` - -#### 2、执行以下命令,生成om模型文件 - -```bash -bash test/pth2om.sh -``` - -注意:此处pth权重文件的路径应设为相对路径 - -#### 3、执行以下命令,开始离线推理 - -```bash -bash test/eval_acc_perf.sh -``` - -同时,benchmark工具会自动统计性能数据。 - -#### 4、在基准环境中执行以下命令,获取基准推理性能 - -onnx包含自定义算子,不能使用开源TensorRT测试性能数据,所以在基准服务器上在线推理测试性能数据。 - - - -### 三、评测结果 - -Yolact++不支持在bs16上离线推理,故在bs8上测试。 - -| 模型 | 在线推理精度 | 310离线推理精度 | 基准性能 | 310性能 | -| ----------- | ----------------------- | ----------------------- | ---------- | --------- | -| YOLACT bs1 | mAP: box 34.94, mask 33.69 | mAP: box 34.90, mask 33.71 | 19.693fps | 26.452fps | -| YOLACT bs8 | mAP: box 34.94, mask 33.69 | mAP: box 34.90, mask 33.71 | 16.377fps | 31.130fps | +# YOLACT模型PyTorch离线推理说明 + +### 一、环境准备 + +#### 1、获取依赖库 + +```shell +pip3 install -r requirements.txt +git clone -b pytorch_1.5 https://github.com/ifzhang/DCNv2.git +cd DCNv2 +python3.7 setup.py build develop +patch -p1 < ../dcnv2.diff +``` + +#### 2、获取YOLACT源代码并更新 + +- 首先获取官方代码仓代码 + + ```bash + git clone https://github.com/dbolya/yolact.git + ``` + +- 将无关文件删除,保留以下文件 + + ``` + . + ├── backbone.py + ├── data + │   ├── coco.py + │   ├── config.py + │   └── __init__.py + ├── layers + │   ├── box_utils.py + │   ├── functions + │   │   ├── detection.py + │   │   └── __init__.py + │   ├── __init__.py + │   ├── interpolate.py + │   └── output_utils.py + ├── utils + │   ├── augmentations.py + │   ├── cython_nms.pyx + │   ├── functions.py + │   ├── __init__.py + │   └── timer.py + └── yolact.py + ``` + +- 将本仓库代码拷贝至yolact目录下,并使用补丁YOLACT.patch复原 + + ``` + patch -p1 < ./YOLACT.patch + ``` + + + 复原后,文件目录如下 + + ``` + . + ├── backbone.py + ├── data + │   ├── coco.py + │   ├── config.py + │   └── __init__.py + ├── env.sh + ├── dcnv2.diff + ├── DCNv2 + ├── layers + │   ├── box_utils.py + │   ├── functions + │   │   ├── detection.py + │   │   └── __init__.py + │   ├── __init__.py + │   ├── interpolate.py + │   └── output_utils.py + ├── LICENSE + ├── modelzoo_level.txt + ├── README.md + ├── requirements.txt + ├── test + │   ├── eval_acc_perf.sh + │   ├── parse.py + │   ├── prior.bin + │   └── pth2om.sh + ├── utils + │   ├── augmentations.py + │   ├── cython_nms.pyx + │   ├── functions.py + │   ├── __init__.py + │   └── timer.py + ├── weights + │   └── pth2onnx.py + ├── YOLACT.patch + ├── YOLACT_postprocess.py + ├── YOLACT_preprocess.py + └── yolact.py + ``` + +#### 3、获取权重文件 + +官方训练完毕的权重文件:yolact_plus_resnet50_54_800000.pth + +训练完毕的权重文件放于./weights目录下 + +#### 4、获取数据集 + +YOLACT模型使用Microsoft COCO 2017数据集进行训练及测试,下载数据集命令如下: + +```bash +cd data/scripts +bash ./COCO.sh #获取测试数据集 +``` + +在离线推理中仅使用测试数据集,测试图像为val 2017, 对应的标注文件为instances_val2017.json + +#### 5、获取benchmark工具 + +获取benchmark.x86_64离线推理工具 + + + +### 二、离线推理 + +#### 1、执行离线推理前使用以下命令查看设备状态,确保device空闲 + +```bash +npu-smi info +``` + +#### 2、执行以下命令,生成om模型文件 + +```bash +bash test/pth2om.sh +``` + +注意:此处pth权重文件的路径应设为相对路径 + +#### 3、执行以下命令,开始离线推理 + +```bash +bash test/eval_acc_perf.sh +``` + +同时,benchmark工具会自动统计性能数据。 + +#### 4、在基准环境中执行以下命令,获取基准推理性能 + +onnx包含自定义算子,不能使用开源TensorRT测试性能数据,所以在基准服务器上在线推理测试性能数据。 + + + +### 三、评测结果 + +Yolact++不支持在bs16上离线推理,故在bs8上测试。 + +| 模型 | 在线推理精度 | 310离线推理精度 | 基准性能 | 310性能 | +| ----------- | ----------------------- | ----------------------- | ---------- | --------- | +| YOLACT bs1 | mAP: box 34.94, mask 33.69 | mAP: box 34.90, mask 33.71 | 19.693fps | 26.452fps | +| YOLACT bs8 | mAP: box 34.94, mask 33.69 | mAP: box 34.90, mask 33.71 | 16.377fps | 31.130fps | diff --git a/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/YOLACT_postprocess.py b/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/YOLACT_postprocess.py index 58d3a90d97..83de5b39dc 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/YOLACT_postprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/YOLACT_postprocess.py @@ -1,566 +1,566 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys - -from layers import Detect -from data import COCODetection, get_label_map, MEANS, COLORS -from yolact import Yolact -from utils.augmentations import BaseTransform, FastBaseTransform, Resize -from utils.functions import MovingAverage, ProgressBar -from layers.box_utils import jaccard, center_size, mask_iou -from utils import timer -from utils.functions import SavePath -from layers.output_utils import postprocess, undo_image_transformation -import pycocotools - -from data import cfg, set_cfg, set_dataset - -import numpy as np -import torch -import torch.backends.cudnn as cudnn -from torch.autograd import Variable -import argparse -import time -import random -import cProfile -import pickle -import json -import os -from collections import defaultdict -from pathlib import Path -from collections import OrderedDict -from PIL import Image - -import matplotlib.pyplot as plt -import cv2 - -def str2bool(v): - if v.lower() in ('yes', 'true', 't', 'y', '1'): - return True - elif v.lower() in ('no', 'false', 'f', 'n', '0'): - return False - else: - raise argparse.ArgumentTypeError('Boolean value expected.') - -def parse_args(argv=None): - parser = argparse.ArgumentParser( - description='YOLACT COCO Evaluation') - parser.add_argument('--valid_images', default='/home/data/coco/images/', help='the path of validation images') - parser.add_argument('--valid_annotations', default='/home/data/coco/annotations/instances_val2017.json', help='the path of validation annotations') - parser.add_argument('--top_k', default=5, type=int, - help='Further restrict the number of predictions to parse') - parser.add_argument('--cuda', default=True, type=str2bool, - help='Use cuda to evaulate model') - parser.add_argument('--fast_nms', default=True, type=str2bool, - help='Whether to use a faster, but not entirely correct version of NMS.') - parser.add_argument('--shuffle', dest='shuffle', action='store_true', - help='Shuffles the images when displaying them. Doesn\'t have much of an effect when display is off though.') - parser.add_argument('--ap_data_file', default='results/ap_data.pkl', type=str, - help='In quantitative mode, the file to save detections before calculating mAP.') - parser.add_argument('--max_images', default=-1, type=int, - help='The maximum number of images from the dataset to consider. Use -1 for all.') - parser.add_argument('--output_coco_json', dest='output_coco_json', action='store_true', - help='If display is not set, instead of processing IoU values, this just dumps detections into the coco json file.') - parser.add_argument('--config', default=None, - help='The config object to use.') - parser.add_argument('--no_bar', dest='no_bar', action='store_true', - help='Do not output the status bar. This is useful for when piping to a file.') - parser.add_argument('--no_sort', default=False, dest='no_sort', action='store_true', - help='Do not sort images by hashed image ID.') - parser.add_argument('--seed', default=None, type=int, - help='The seed to pass into random.seed. Note: this is only really for the shuffle and does not (I think) affect cuda stuff.') - parser.add_argument('--mask_proto_debug', default=False, dest='mask_proto_debug', action='store_true', - help='Outputs stuff for scripts/compute_mask.py.') - parser.add_argument('--score_threshold', default=0, type=float, - help='Detections with a score under this threshold will not be considered. This currently only works in display mode.') - parser.add_argument('--dataset', default=None, type=str, - help='If specified, override the dataset specified in the config with this one (example: coco2017_dataset).') - parser.add_argument('--detect', default=False, dest='detect', action='store_true', - help='Don\'t evauluate the mask branch at all and only do object detection. This only works for --display and --benchmark.') - parser.add_argument('--pthpath', type=str, - default='./weights/yolact_plus_resnet50_54_800000.pth', help='choose .pth module') - parser.add_argument('--device_id', type=int, - default=0, help='choose .pth module') - parser.set_defaults(no_bar=False, output_coco_json=False, shuffle=False, - no_sort=False, mask_proto_debug=False, detect=False, crop=True) - - global args - args = parser.parse_args(argv) - - if args.seed is not None: - random.seed(args.seed) - -iou_thresholds = [x / 100 for x in range(50, 100, 5)] -coco_cats = {} # Call prep_coco_cats to fill this -coco_cats_inv = {} -color_cache = defaultdict(lambda: {}) - -def prep_coco_cats(): - """ Prepare inverted table for category id lookup given a coco cats object. """ - for coco_cat_id, transformed_cat_id_p1 in get_label_map().items(): - transformed_cat_id = transformed_cat_id_p1 - 1 - coco_cats[transformed_cat_id] = coco_cat_id - coco_cats_inv[coco_cat_id] = transformed_cat_id - -def get_coco_cat(transformed_cat_id): - """ transformed_cat_id is [0,80) as indices in cfg.dataset.class_names """ - return coco_cats[transformed_cat_id] - -def get_transformed_cat(coco_cat_id): - """ transformed_cat_id is [0,80) as indices in cfg.dataset.class_names """ - return coco_cats_inv[coco_cat_id] - -class Detections: - - def __init__(self): - self.bbox_data = [] - self.mask_data = [] - - def add_bbox(self, image_id:int, category_id:int, bbox:list, score:float): - """ Note that bbox should be a list or tuple of (x1, y1, x2, y2) """ - bbox = [bbox[0], bbox[1], bbox[2]-bbox[0], bbox[3]-bbox[1]] - - # Round to the nearest 10th to avoid huge file sizes, as COCO suggests - bbox = [round(float(x)*10)/10 for x in bbox] - - self.bbox_data.append({ - 'image_id': int(image_id), - 'category_id': get_coco_cat(int(category_id)), - 'bbox': bbox, - 'score': float(score) - }) - - def add_mask(self, image_id:int, category_id:int, segmentation:np.ndarray, score:float): - """ The segmentation should be the full mask, the size of the image and with size [h, w]. """ - rle = pycocotools.mask.encode(np.asfortranarray(segmentation.astype(np.uint8))) - rle['counts'] = rle['counts'].decode('ascii') # json.dump doesn't like bytes strings - - self.mask_data.append({ - 'image_id': int(image_id), - 'category_id': get_coco_cat(int(category_id)), - 'segmentation': rle, - 'score': float(score) - }) - -def _mask_iou(mask1, mask2, iscrowd=False): - with timer.env('Mask IoU'): - ret = mask_iou(mask1, mask2, iscrowd) - return ret.cpu() - -def _bbox_iou(bbox1, bbox2, iscrowd=False): - with timer.env('BBox IoU'): - ret = jaccard(bbox1, bbox2, iscrowd) - return ret.cpu() - -def prep_metrics(ap_data, dets, img, gt, gt_masks, h, w, num_crowd, image_id, detections:Detections=None): - """ Returns a list of APs for this image, with each element being for a class """ - if not args.output_coco_json: - with timer.env('Prepare gt'): - gt_boxes = torch.Tensor(gt[:, :4]) - gt_boxes[:, [0, 2]] *= w - gt_boxes[:, [1, 3]] *= h - gt_classes = list(gt[:, 4].astype(int)) - gt_masks = torch.Tensor(gt_masks).view(-1, h*w) - - if num_crowd > 0: - split = lambda x: (x[-num_crowd:], x[:-num_crowd]) - crowd_boxes , gt_boxes = split(gt_boxes) - crowd_masks , gt_masks = split(gt_masks) - crowd_classes, gt_classes = split(gt_classes) - - with timer.env('Postprocess'): - classes, scores, boxes, masks = postprocess(dets, w, h, crop_masks=args.crop, score_threshold=args.score_threshold) - - if classes.size(0) == 0: - return - - classes = list(classes.cpu().numpy().astype(int)) - if isinstance(scores, list): - box_scores = list(scores[0].cpu().numpy().astype(float)) - mask_scores = list(scores[1].cpu().numpy().astype(float)) - else: - scores = list(scores.cpu().numpy().astype(float)) - box_scores = scores - mask_scores = scores - masks = masks.view(-1, h*w) - - - if args.output_coco_json: - with timer.env('JSON Output'): - boxes = boxes.cpu().numpy() - masks = masks.view(-1, h, w).cpu().numpy() - for i in range(masks.shape[0]): - # Make sure that the bounding box actually makes sense and a mask was produced - if (boxes[i, 3] - boxes[i, 1]) * (boxes[i, 2] - boxes[i, 0]) > 0: - detections.add_bbox(image_id, classes[i], boxes[i,:], box_scores[i]) - detections.add_mask(image_id, classes[i], masks[i,:,:], mask_scores[i]) - return - - with timer.env('Eval Setup'): - num_pred = len(classes) - num_gt = len(gt_classes) - - mask_iou_cache = _mask_iou(masks, gt_masks) - bbox_iou_cache = _bbox_iou(boxes.float(), gt_boxes.float()) - - if num_crowd > 0: - crowd_mask_iou_cache = _mask_iou(masks, crowd_masks, iscrowd=True) - crowd_bbox_iou_cache = _bbox_iou(boxes.float(), crowd_boxes.float(), iscrowd=True) - else: - crowd_mask_iou_cache = None - crowd_bbox_iou_cache = None - - box_indices = sorted(range(num_pred), key=lambda i: -box_scores[i]) - mask_indices = sorted(box_indices, key=lambda i: -mask_scores[i]) - iou_types = [ - ('box', lambda i,j: bbox_iou_cache[i, j].item(), - lambda i,j: crowd_bbox_iou_cache[i,j].item(), - lambda i: box_scores[i], box_indices), - ('mask', lambda i,j: mask_iou_cache[i, j].item(), - lambda i,j: crowd_mask_iou_cache[i,j].item(), - lambda i: mask_scores[i], mask_indices) - ] - - - timer.start('Main loop') - for _class in set(classes + gt_classes): - ap_per_iou = [] - num_gt_for_class = sum([1 for x in gt_classes if x == _class]) - - for iouIdx in range(len(iou_thresholds)): - iou_threshold = iou_thresholds[iouIdx] - - for iou_type, iou_func, crowd_func, score_func, indices in iou_types: - gt_used = [False] * len(gt_classes) - - ap_obj = ap_data[iou_type][iouIdx][_class] - ap_obj.add_gt_positives(num_gt_for_class) - - for i in indices: - if classes[i] != _class: - continue - - max_iou_found = iou_threshold - max_match_idx = -1 - for j in range(num_gt): - if gt_used[j] or gt_classes[j] != _class: - continue - - iou = iou_func(i, j) - - if iou > max_iou_found: - max_iou_found = iou - max_match_idx = j - - if max_match_idx >= 0: - gt_used[max_match_idx] = True - ap_obj.push(score_func(i), True) - else: - # If the detection matches a crowd, we can just ignore it - matched_crowd = False - - if num_crowd > 0: - for j in range(len(crowd_classes)): - if crowd_classes[j] != _class: - continue - - iou = crowd_func(i, j) - - if iou > iou_threshold: - matched_crowd = True - break - - # All this crowd code so that we can make sure that our eval code gives the - # same result as COCOEval. There aren't even that many crowd annotations to - # begin with, but accuracy is of the utmost importance. - if not matched_crowd: - ap_obj.push(score_func(i), False) - timer.stop('Main loop') - -class APDataObject: - """ - Stores all the information necessary to calculate the AP for one IoU and one class. - Note: I type annotated this because why not. - """ - - def __init__(self): - self.data_points = [] - self.num_gt_positives = 0 - - def push(self, score:float, is_true:bool): - self.data_points.append((score, is_true)) - - def add_gt_positives(self, num_positives:int): - """ Call this once per image. """ - self.num_gt_positives += num_positives - - def is_empty(self) -> bool: - return len(self.data_points) == 0 and self.num_gt_positives == 0 - - def get_ap(self) -> float: - """ Warning: result not cached. """ - - if self.num_gt_positives == 0: - return 0 - - # Sort descending by score - self.data_points.sort(key=lambda x: -x[0]) - - precisions = [] - recalls = [] - num_true = 0 - num_false = 0 - - # Compute the precision-recall curve. The x axis is recalls and the y axis precisions. - for datum in self.data_points: - # datum[1] is whether the detection a true or false positive - if datum[1]: num_true += 1 - else: num_false += 1 - - precision = num_true / (num_true + num_false) - recall = num_true / self.num_gt_positives - - precisions.append(precision) - recalls.append(recall) - - # Smooth the curve by computing [max(precisions[i:]) for i in range(len(precisions))] - # Basically, remove any temporary dips from the curve. - # At least that's what I think, idk. COCOEval did it so I do too. - for i in range(len(precisions)-1, 0, -1): - if precisions[i] > precisions[i-1]: - precisions[i-1] = precisions[i] - - # Compute the integral of precision(recall) d_recall from recall=0->1 using fixed-length riemann summation with 101 bars. - y_range = [0] * 101 # idx 0 is recall == 0.0 and idx 100 is recall == 1.00 - x_range = np.array([x / 100 for x in range(101)]) - recalls = np.array(recalls) - - # I realize this is weird, but all it does is find the nearest precision(x) for a given x in x_range. - # Basically, if the closest recall we have to 0.01 is 0.009 this sets precision(0.01) = precision(0.009). - # I approximate the integral this way, because that's how COCOEval does it. - indices = np.searchsorted(recalls, x_range, side='left') - for bar_idx, precision_idx in enumerate(indices): - if precision_idx < len(precisions): - y_range[bar_idx] = precisions[precision_idx] - - # Finally compute the riemann sum to get our integral. - # avg([precision(x) for x in 0:0.01:1]) - return sum(y_range) / len(y_range) - -def badhash(x): - """ - Just a quick and dirty hash function for doing a deterministic shuffle based on image_id. - - Source: - https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key - """ - x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF - x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF - x = ((x >> 16) ^ x) & 0xFFFFFFFF - return x - -class InferResultFile(): - def __init__(self, path, fileName): - parts = fileName.split('_') - self.imgId = int(parts[2]) - self.outputId = int(parts[3][0]) - self.arrayValue = np.fromfile(path + fileName, dtype=np.float32) - - self.arrayDim = self.arrayValue.shape[0] - #print('finish read file :', fileName) - -def getAllFiles(path): - allFiles = os.listdir(path) - infoFiles = {} - for file in allFiles: - if '.bin' in file and 'coco_val' in file: - infoFile = InferResultFile(path, file) - if infoFile.imgId in infoFiles.keys(): - infoFiles[infoFile.imgId].append(infoFile) - else: - infoFiles[infoFile.imgId] = [infoFile] - return infoFiles - -class InferResultFileFetcher(): - def __init__(self, path): - self.path = path - - def getInferResult(self, image_idx): - resultDict = {} - for i in range(1, 5): - fileName = 'coco_val2017_' + str(image_idx) + '_' + str(i) + '.bin' - infoFile = InferResultFile(self.path, fileName) - if infoFile.arrayDim == 1847808: - resultDict[0] = infoFile - elif infoFile.arrayDim == 4677264: - resultDict[1] = infoFile - elif infoFile.arrayDim == 230976: - resultDict[2] = infoFile - else: - resultDict[3] = infoFile - - return resultDict - -pred_priors = None - -def getPriorTensor(): - global pred_priors - if pred_priors is None: - pred_priors = np.fromfile('prior.bin', dtype=np.float32).reshape(57744, 4) - return pred_priors - else: - return pred_priors - -def evaluate(path, dataset): - cfg.mask_proto_debug = args.mask_proto_debug - inferResultFetcher = InferResultFileFetcher(path) - - frame_times = MovingAverage() - dataset_size = len(dataset) if args.max_images < 0 else min(args.max_images, len(dataset)) - progress_bar = ProgressBar(30, dataset_size) - - print() - - # For each class and iou, stores tuples (score, isPositive) - # Index ap_data[type][iouIdx][classIdx] - ap_data = { - 'box' : [[APDataObject() for _ in cfg.dataset.class_names] for _ in iou_thresholds], - 'mask': [[APDataObject() for _ in cfg.dataset.class_names] for _ in iou_thresholds] - } - detections = Detections() - - dataset_indices = list(range(len(dataset))) - - if args.shuffle: - random.shuffle(dataset_indices) - elif not args.no_sort: - # Do a deterministic shuffle based on the image ids - # - # I do this because on python 3.5 dictionary key order is *random*, while in 3.6 it's - # the order of insertion. That means on python 3.6, the images come in the order they are in - # in the annotations file. For some reason, the first images in the annotations file are - # the hardest. To combat this, I use a hard-coded hash function based on the image ids - # to shuffle the indices we use. That way, no matter what python version or how pycocotools - # handles the data, we get the same result every time. - hashed = [badhash(x) for x in dataset.ids] - dataset_indices.sort(key=lambda x: hashed[x]) - - dataset_indices = dataset_indices[:dataset_size] - - # Main eval loop - for it, image_idx in enumerate(dataset_indices): - timer.reset() - with timer.env('Load Data'): - img, gt, gt_masks, h, w, num_crowd = dataset.pull_item(image_idx) - # Test flag, do not upvote - with timer.env('Network Extra'): - imgId_Outputs = inferResultFetcher.getInferResult(image_idx) - pred_mask = imgId_Outputs[0].arrayValue.reshape(1, 57744, 32) #output1 : pred_onnx[2] - pred_conf = imgId_Outputs[1].arrayValue.reshape(1, 57744, 81) #output2 : pred_onnx[1] - pred_loc = imgId_Outputs[2].arrayValue.reshape(1, 57744, 4) #output3 : pred_onnx[0] - pred_proto = imgId_Outputs[3].arrayValue.reshape(1, 138, 138, 32) #output4 : pred_onnx[4] - - detect = Detect(cfg.num_classes, bkg_label=0, top_k=200, conf_thresh=0.05, nms_thresh=0.5) - detect.use_fast_nms = args.fast_nms - preds = detect({'loc': torch.from_numpy(pred_loc), - 'conf': torch.from_numpy(pred_conf), - 'mask': torch.from_numpy(pred_mask), - 'priors': torch.from_numpy(getPriorTensor()), #????? - 'proto': torch.from_numpy(pred_proto)}) - from yolact import Yolact - yolact_net = Yolact() - yolact_net.load_weights(args.pthpath, useCuda=False) - preds = {'net':yolact_net, 'detection':preds} - - # Perform the meat of the operation here depending on our mode. - - prep_metrics(ap_data, preds, img, gt, gt_masks, h, w, num_crowd, dataset.ids[image_idx], detections) - # First couple of images take longer because we're constructing the graph. - # Since that's technically initialization, don't include those in the FPS calculations. - if it > 1: - frame_times.add(timer.total_time()) - if not args.no_bar: - if it > 1: fps = 1 / frame_times.get_avg() - else: fps = 0 - progress = (it+1) / dataset_size * 100 - progress_bar.set_val(it+1) - print('\rProcessing Images %s %6d / %6d (%5.2f%%) %5.2f fps ' - % (repr(progress_bar), it+1, dataset_size, progress, fps), end='') - - print() - print('Saving data...') - with open(args.ap_data_file, 'wb') as f: - pickle.dump(ap_data, f) - return calc_map(ap_data) - -def calc_map(ap_data): - print('Calculating mAP...') - aps = [{'box': [], 'mask': []} for _ in iou_thresholds] - - for _class in range(len(cfg.dataset.class_names)): - for iou_idx in range(len(iou_thresholds)): - for iou_type in ('box', 'mask'): - ap_obj = ap_data[iou_type][iou_idx][_class] - - if not ap_obj.is_empty(): - aps[iou_idx][iou_type].append(ap_obj.get_ap()) - - all_maps = {'box': OrderedDict(), 'mask': OrderedDict()} - - # Looking back at it, this code is really hard to read :/ - for iou_type in ('box', 'mask'): - all_maps[iou_type]['all'] = 0 # Make this first in the ordereddict - for i, threshold in enumerate(iou_thresholds): - mAP = sum(aps[i][iou_type]) / len(aps[i][iou_type]) * 100 if len(aps[i][iou_type]) > 0 else 0 - all_maps[iou_type][int(threshold*100)] = mAP - all_maps[iou_type]['all'] = (sum(all_maps[iou_type].values()) / (len(all_maps[iou_type].values())-1)) - - print_maps(all_maps) - - # Put in a prettier format so we can serialize it to json during training - all_maps = {k: {j: round(u, 2) for j, u in v.items()} for k, v in all_maps.items()} - return all_maps - -def print_maps(all_maps): - # Warning: hacky - make_row = lambda vals: (' %5s |' * len(vals)) % tuple(vals) - make_sep = lambda n: ('-------+' * n) - - print() - print(make_row([''] + [('.%d ' % x if isinstance(x, int) else x + ' ') for x in all_maps['box'].keys()])) - print(make_sep(len(all_maps['box']) + 1)) - for iou_type in ('box', 'mask'): - print(make_row([iou_type] + ['%.2f' % x if x < 100 else '%.1f' % x for x in all_maps[iou_type].values()])) - print(make_sep(len(all_maps['box']) + 1)) - print() - -if __name__ == '__main__': - parse_args() - path = './result/dumpOutput_device{}/'.format(args.device_id) - - if args.config is not None: - set_cfg(args.config) - - else: - args.config = 'yolact_base_config' - print('Config not specified. Parsed %s from the file name.\n' % args.config) - set_cfg(args.config) - - #if args.image is None and args.video is None and args.images is None: - dataset = COCODetection(args.valid_images, args.valid_annotations, - transform=BaseTransform(), has_gt=cfg.dataset.has_gt) - prep_coco_cats() - - evaluate(path, dataset) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys + +from layers import Detect +from data import COCODetection, get_label_map, MEANS, COLORS +from yolact import Yolact +from utils.augmentations import BaseTransform, FastBaseTransform, Resize +from utils.functions import MovingAverage, ProgressBar +from layers.box_utils import jaccard, center_size, mask_iou +from utils import timer +from utils.functions import SavePath +from layers.output_utils import postprocess, undo_image_transformation +import pycocotools + +from data import cfg, set_cfg, set_dataset + +import numpy as np +import torch +import torch.backends.cudnn as cudnn +from torch.autograd import Variable +import argparse +import time +import random +import cProfile +import pickle +import json +import os +from collections import defaultdict +from pathlib import Path +from collections import OrderedDict +from PIL import Image + +import matplotlib.pyplot as plt +import cv2 + +def str2bool(v): + if v.lower() in ('yes', 'true', 't', 'y', '1'): + return True + elif v.lower() in ('no', 'false', 'f', 'n', '0'): + return False + else: + raise argparse.ArgumentTypeError('Boolean value expected.') + +def parse_args(argv=None): + parser = argparse.ArgumentParser( + description='YOLACT COCO Evaluation') + parser.add_argument('--valid_images', default='/home/data/coco/images/', help='the path of validation images') + parser.add_argument('--valid_annotations', default='/home/data/coco/annotations/instances_val2017.json', help='the path of validation annotations') + parser.add_argument('--top_k', default=5, type=int, + help='Further restrict the number of predictions to parse') + parser.add_argument('--cuda', default=True, type=str2bool, + help='Use cuda to evaulate model') + parser.add_argument('--fast_nms', default=True, type=str2bool, + help='Whether to use a faster, but not entirely correct version of NMS.') + parser.add_argument('--shuffle', dest='shuffle', action='store_true', + help='Shuffles the images when displaying them. Doesn\'t have much of an effect when display is off though.') + parser.add_argument('--ap_data_file', default='results/ap_data.pkl', type=str, + help='In quantitative mode, the file to save detections before calculating mAP.') + parser.add_argument('--max_images', default=-1, type=int, + help='The maximum number of images from the dataset to consider. Use -1 for all.') + parser.add_argument('--output_coco_json', dest='output_coco_json', action='store_true', + help='If display is not set, instead of processing IoU values, this just dumps detections into the coco json file.') + parser.add_argument('--config', default=None, + help='The config object to use.') + parser.add_argument('--no_bar', dest='no_bar', action='store_true', + help='Do not output the status bar. This is useful for when piping to a file.') + parser.add_argument('--no_sort', default=False, dest='no_sort', action='store_true', + help='Do not sort images by hashed image ID.') + parser.add_argument('--seed', default=None, type=int, + help='The seed to pass into random.seed. Note: this is only really for the shuffle and does not (I think) affect cuda stuff.') + parser.add_argument('--mask_proto_debug', default=False, dest='mask_proto_debug', action='store_true', + help='Outputs stuff for scripts/compute_mask.py.') + parser.add_argument('--score_threshold', default=0, type=float, + help='Detections with a score under this threshold will not be considered. This currently only works in display mode.') + parser.add_argument('--dataset', default=None, type=str, + help='If specified, override the dataset specified in the config with this one (example: coco2017_dataset).') + parser.add_argument('--detect', default=False, dest='detect', action='store_true', + help='Don\'t evauluate the mask branch at all and only do object detection. This only works for --display and --benchmark.') + parser.add_argument('--pthpath', type=str, + default='./weights/yolact_plus_resnet50_54_800000.pth', help='choose .pth module') + parser.add_argument('--device_id', type=int, + default=0, help='choose .pth module') + parser.set_defaults(no_bar=False, output_coco_json=False, shuffle=False, + no_sort=False, mask_proto_debug=False, detect=False, crop=True) + + global args + args = parser.parse_args(argv) + + if args.seed is not None: + random.seed(args.seed) + +iou_thresholds = [x / 100 for x in range(50, 100, 5)] +coco_cats = {} # Call prep_coco_cats to fill this +coco_cats_inv = {} +color_cache = defaultdict(lambda: {}) + +def prep_coco_cats(): + """ Prepare inverted table for category id lookup given a coco cats object. """ + for coco_cat_id, transformed_cat_id_p1 in get_label_map().items(): + transformed_cat_id = transformed_cat_id_p1 - 1 + coco_cats[transformed_cat_id] = coco_cat_id + coco_cats_inv[coco_cat_id] = transformed_cat_id + +def get_coco_cat(transformed_cat_id): + """ transformed_cat_id is [0,80) as indices in cfg.dataset.class_names """ + return coco_cats[transformed_cat_id] + +def get_transformed_cat(coco_cat_id): + """ transformed_cat_id is [0,80) as indices in cfg.dataset.class_names """ + return coco_cats_inv[coco_cat_id] + +class Detections: + + def __init__(self): + self.bbox_data = [] + self.mask_data = [] + + def add_bbox(self, image_id:int, category_id:int, bbox:list, score:float): + """ Note that bbox should be a list or tuple of (x1, y1, x2, y2) """ + bbox = [bbox[0], bbox[1], bbox[2]-bbox[0], bbox[3]-bbox[1]] + + # Round to the nearest 10th to avoid huge file sizes, as COCO suggests + bbox = [round(float(x)*10)/10 for x in bbox] + + self.bbox_data.append({ + 'image_id': int(image_id), + 'category_id': get_coco_cat(int(category_id)), + 'bbox': bbox, + 'score': float(score) + }) + + def add_mask(self, image_id:int, category_id:int, segmentation:np.ndarray, score:float): + """ The segmentation should be the full mask, the size of the image and with size [h, w]. """ + rle = pycocotools.mask.encode(np.asfortranarray(segmentation.astype(np.uint8))) + rle['counts'] = rle['counts'].decode('ascii') # json.dump doesn't like bytes strings + + self.mask_data.append({ + 'image_id': int(image_id), + 'category_id': get_coco_cat(int(category_id)), + 'segmentation': rle, + 'score': float(score) + }) + +def _mask_iou(mask1, mask2, iscrowd=False): + with timer.env('Mask IoU'): + ret = mask_iou(mask1, mask2, iscrowd) + return ret.cpu() + +def _bbox_iou(bbox1, bbox2, iscrowd=False): + with timer.env('BBox IoU'): + ret = jaccard(bbox1, bbox2, iscrowd) + return ret.cpu() + +def prep_metrics(ap_data, dets, img, gt, gt_masks, h, w, num_crowd, image_id, detections:Detections=None): + """ Returns a list of APs for this image, with each element being for a class """ + if not args.output_coco_json: + with timer.env('Prepare gt'): + gt_boxes = torch.Tensor(gt[:, :4]) + gt_boxes[:, [0, 2]] *= w + gt_boxes[:, [1, 3]] *= h + gt_classes = list(gt[:, 4].astype(int)) + gt_masks = torch.Tensor(gt_masks).view(-1, h*w) + + if num_crowd > 0: + split = lambda x: (x[-num_crowd:], x[:-num_crowd]) + crowd_boxes , gt_boxes = split(gt_boxes) + crowd_masks , gt_masks = split(gt_masks) + crowd_classes, gt_classes = split(gt_classes) + + with timer.env('Postprocess'): + classes, scores, boxes, masks = postprocess(dets, w, h, crop_masks=args.crop, score_threshold=args.score_threshold) + + if classes.size(0) == 0: + return + + classes = list(classes.cpu().numpy().astype(int)) + if isinstance(scores, list): + box_scores = list(scores[0].cpu().numpy().astype(float)) + mask_scores = list(scores[1].cpu().numpy().astype(float)) + else: + scores = list(scores.cpu().numpy().astype(float)) + box_scores = scores + mask_scores = scores + masks = masks.view(-1, h*w) + + + if args.output_coco_json: + with timer.env('JSON Output'): + boxes = boxes.cpu().numpy() + masks = masks.view(-1, h, w).cpu().numpy() + for i in range(masks.shape[0]): + # Make sure that the bounding box actually makes sense and a mask was produced + if (boxes[i, 3] - boxes[i, 1]) * (boxes[i, 2] - boxes[i, 0]) > 0: + detections.add_bbox(image_id, classes[i], boxes[i,:], box_scores[i]) + detections.add_mask(image_id, classes[i], masks[i,:,:], mask_scores[i]) + return + + with timer.env('Eval Setup'): + num_pred = len(classes) + num_gt = len(gt_classes) + + mask_iou_cache = _mask_iou(masks, gt_masks) + bbox_iou_cache = _bbox_iou(boxes.float(), gt_boxes.float()) + + if num_crowd > 0: + crowd_mask_iou_cache = _mask_iou(masks, crowd_masks, iscrowd=True) + crowd_bbox_iou_cache = _bbox_iou(boxes.float(), crowd_boxes.float(), iscrowd=True) + else: + crowd_mask_iou_cache = None + crowd_bbox_iou_cache = None + + box_indices = sorted(range(num_pred), key=lambda i: -box_scores[i]) + mask_indices = sorted(box_indices, key=lambda i: -mask_scores[i]) + iou_types = [ + ('box', lambda i,j: bbox_iou_cache[i, j].item(), + lambda i,j: crowd_bbox_iou_cache[i,j].item(), + lambda i: box_scores[i], box_indices), + ('mask', lambda i,j: mask_iou_cache[i, j].item(), + lambda i,j: crowd_mask_iou_cache[i,j].item(), + lambda i: mask_scores[i], mask_indices) + ] + + + timer.start('Main loop') + for _class in set(classes + gt_classes): + ap_per_iou = [] + num_gt_for_class = sum([1 for x in gt_classes if x == _class]) + + for iouIdx in range(len(iou_thresholds)): + iou_threshold = iou_thresholds[iouIdx] + + for iou_type, iou_func, crowd_func, score_func, indices in iou_types: + gt_used = [False] * len(gt_classes) + + ap_obj = ap_data[iou_type][iouIdx][_class] + ap_obj.add_gt_positives(num_gt_for_class) + + for i in indices: + if classes[i] != _class: + continue + + max_iou_found = iou_threshold + max_match_idx = -1 + for j in range(num_gt): + if gt_used[j] or gt_classes[j] != _class: + continue + + iou = iou_func(i, j) + + if iou > max_iou_found: + max_iou_found = iou + max_match_idx = j + + if max_match_idx >= 0: + gt_used[max_match_idx] = True + ap_obj.push(score_func(i), True) + else: + # If the detection matches a crowd, we can just ignore it + matched_crowd = False + + if num_crowd > 0: + for j in range(len(crowd_classes)): + if crowd_classes[j] != _class: + continue + + iou = crowd_func(i, j) + + if iou > iou_threshold: + matched_crowd = True + break + + # All this crowd code so that we can make sure that our eval code gives the + # same result as COCOEval. There aren't even that many crowd annotations to + # begin with, but accuracy is of the utmost importance. + if not matched_crowd: + ap_obj.push(score_func(i), False) + timer.stop('Main loop') + +class APDataObject: + """ + Stores all the information necessary to calculate the AP for one IoU and one class. + Note: I type annotated this because why not. + """ + + def __init__(self): + self.data_points = [] + self.num_gt_positives = 0 + + def push(self, score:float, is_true:bool): + self.data_points.append((score, is_true)) + + def add_gt_positives(self, num_positives:int): + """ Call this once per image. """ + self.num_gt_positives += num_positives + + def is_empty(self) -> bool: + return len(self.data_points) == 0 and self.num_gt_positives == 0 + + def get_ap(self) -> float: + """ Warning: result not cached. """ + + if self.num_gt_positives == 0: + return 0 + + # Sort descending by score + self.data_points.sort(key=lambda x: -x[0]) + + precisions = [] + recalls = [] + num_true = 0 + num_false = 0 + + # Compute the precision-recall curve. The x axis is recalls and the y axis precisions. + for datum in self.data_points: + # datum[1] is whether the detection a true or false positive + if datum[1]: num_true += 1 + else: num_false += 1 + + precision = num_true / (num_true + num_false) + recall = num_true / self.num_gt_positives + + precisions.append(precision) + recalls.append(recall) + + # Smooth the curve by computing [max(precisions[i:]) for i in range(len(precisions))] + # Basically, remove any temporary dips from the curve. + # At least that's what I think, idk. COCOEval did it so I do too. + for i in range(len(precisions)-1, 0, -1): + if precisions[i] > precisions[i-1]: + precisions[i-1] = precisions[i] + + # Compute the integral of precision(recall) d_recall from recall=0->1 using fixed-length riemann summation with 101 bars. + y_range = [0] * 101 # idx 0 is recall == 0.0 and idx 100 is recall == 1.00 + x_range = np.array([x / 100 for x in range(101)]) + recalls = np.array(recalls) + + # I realize this is weird, but all it does is find the nearest precision(x) for a given x in x_range. + # Basically, if the closest recall we have to 0.01 is 0.009 this sets precision(0.01) = precision(0.009). + # I approximate the integral this way, because that's how COCOEval does it. + indices = np.searchsorted(recalls, x_range, side='left') + for bar_idx, precision_idx in enumerate(indices): + if precision_idx < len(precisions): + y_range[bar_idx] = precisions[precision_idx] + + # Finally compute the riemann sum to get our integral. + # avg([precision(x) for x in 0:0.01:1]) + return sum(y_range) / len(y_range) + +def badhash(x): + """ + Just a quick and dirty hash function for doing a deterministic shuffle based on image_id. + + Source: + https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key + """ + x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF + x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF + x = ((x >> 16) ^ x) & 0xFFFFFFFF + return x + +class InferResultFile(): + def __init__(self, path, fileName): + parts = fileName.split('_') + self.imgId = int(parts[2]) + self.outputId = int(parts[3][0]) + self.arrayValue = np.fromfile(path + fileName, dtype=np.float32) + + self.arrayDim = self.arrayValue.shape[0] + #print('finish read file :', fileName) + +def getAllFiles(path): + allFiles = os.listdir(path) + infoFiles = {} + for file in allFiles: + if '.bin' in file and 'coco_val' in file: + infoFile = InferResultFile(path, file) + if infoFile.imgId in infoFiles.keys(): + infoFiles[infoFile.imgId].append(infoFile) + else: + infoFiles[infoFile.imgId] = [infoFile] + return infoFiles + +class InferResultFileFetcher(): + def __init__(self, path): + self.path = path + + def getInferResult(self, image_idx): + resultDict = {} + for i in range(1, 5): + fileName = 'coco_val2017_' + str(image_idx) + '_' + str(i) + '.bin' + infoFile = InferResultFile(self.path, fileName) + if infoFile.arrayDim == 1847808: + resultDict[0] = infoFile + elif infoFile.arrayDim == 4677264: + resultDict[1] = infoFile + elif infoFile.arrayDim == 230976: + resultDict[2] = infoFile + else: + resultDict[3] = infoFile + + return resultDict + +pred_priors = None + +def getPriorTensor(): + global pred_priors + if pred_priors is None: + pred_priors = np.fromfile('prior.bin', dtype=np.float32).reshape(57744, 4) + return pred_priors + else: + return pred_priors + +def evaluate(path, dataset): + cfg.mask_proto_debug = args.mask_proto_debug + inferResultFetcher = InferResultFileFetcher(path) + + frame_times = MovingAverage() + dataset_size = len(dataset) if args.max_images < 0 else min(args.max_images, len(dataset)) + progress_bar = ProgressBar(30, dataset_size) + + print() + + # For each class and iou, stores tuples (score, isPositive) + # Index ap_data[type][iouIdx][classIdx] + ap_data = { + 'box' : [[APDataObject() for _ in cfg.dataset.class_names] for _ in iou_thresholds], + 'mask': [[APDataObject() for _ in cfg.dataset.class_names] for _ in iou_thresholds] + } + detections = Detections() + + dataset_indices = list(range(len(dataset))) + + if args.shuffle: + random.shuffle(dataset_indices) + elif not args.no_sort: + # Do a deterministic shuffle based on the image ids + # + # I do this because on python 3.5 dictionary key order is *random*, while in 3.6 it's + # the order of insertion. That means on python 3.6, the images come in the order they are in + # in the annotations file. For some reason, the first images in the annotations file are + # the hardest. To combat this, I use a hard-coded hash function based on the image ids + # to shuffle the indices we use. That way, no matter what python version or how pycocotools + # handles the data, we get the same result every time. + hashed = [badhash(x) for x in dataset.ids] + dataset_indices.sort(key=lambda x: hashed[x]) + + dataset_indices = dataset_indices[:dataset_size] + + # Main eval loop + for it, image_idx in enumerate(dataset_indices): + timer.reset() + with timer.env('Load Data'): + img, gt, gt_masks, h, w, num_crowd = dataset.pull_item(image_idx) + # Test flag, do not upvote + with timer.env('Network Extra'): + imgId_Outputs = inferResultFetcher.getInferResult(image_idx) + pred_mask = imgId_Outputs[0].arrayValue.reshape(1, 57744, 32) #output1 : pred_onnx[2] + pred_conf = imgId_Outputs[1].arrayValue.reshape(1, 57744, 81) #output2 : pred_onnx[1] + pred_loc = imgId_Outputs[2].arrayValue.reshape(1, 57744, 4) #output3 : pred_onnx[0] + pred_proto = imgId_Outputs[3].arrayValue.reshape(1, 138, 138, 32) #output4 : pred_onnx[4] + + detect = Detect(cfg.num_classes, bkg_label=0, top_k=200, conf_thresh=0.05, nms_thresh=0.5) + detect.use_fast_nms = args.fast_nms + preds = detect({'loc': torch.from_numpy(pred_loc), + 'conf': torch.from_numpy(pred_conf), + 'mask': torch.from_numpy(pred_mask), + 'priors': torch.from_numpy(getPriorTensor()), #????? + 'proto': torch.from_numpy(pred_proto)}) + from yolact import Yolact + yolact_net = Yolact() + yolact_net.load_weights(args.pthpath, useCuda=False) + preds = {'net':yolact_net, 'detection':preds} + + # Perform the meat of the operation here depending on our mode. + + prep_metrics(ap_data, preds, img, gt, gt_masks, h, w, num_crowd, dataset.ids[image_idx], detections) + # First couple of images take longer because we're constructing the graph. + # Since that's technically initialization, don't include those in the FPS calculations. + if it > 1: + frame_times.add(timer.total_time()) + if not args.no_bar: + if it > 1: fps = 1 / frame_times.get_avg() + else: fps = 0 + progress = (it+1) / dataset_size * 100 + progress_bar.set_val(it+1) + print('\rProcessing Images %s %6d / %6d (%5.2f%%) %5.2f fps ' + % (repr(progress_bar), it+1, dataset_size, progress, fps), end='') + + print() + print('Saving data...') + with open(args.ap_data_file, 'wb') as f: + pickle.dump(ap_data, f) + return calc_map(ap_data) + +def calc_map(ap_data): + print('Calculating mAP...') + aps = [{'box': [], 'mask': []} for _ in iou_thresholds] + + for _class in range(len(cfg.dataset.class_names)): + for iou_idx in range(len(iou_thresholds)): + for iou_type in ('box', 'mask'): + ap_obj = ap_data[iou_type][iou_idx][_class] + + if not ap_obj.is_empty(): + aps[iou_idx][iou_type].append(ap_obj.get_ap()) + + all_maps = {'box': OrderedDict(), 'mask': OrderedDict()} + + # Looking back at it, this code is really hard to read :/ + for iou_type in ('box', 'mask'): + all_maps[iou_type]['all'] = 0 # Make this first in the ordereddict + for i, threshold in enumerate(iou_thresholds): + mAP = sum(aps[i][iou_type]) / len(aps[i][iou_type]) * 100 if len(aps[i][iou_type]) > 0 else 0 + all_maps[iou_type][int(threshold*100)] = mAP + all_maps[iou_type]['all'] = (sum(all_maps[iou_type].values()) / (len(all_maps[iou_type].values())-1)) + + print_maps(all_maps) + + # Put in a prettier format so we can serialize it to json during training + all_maps = {k: {j: round(u, 2) for j, u in v.items()} for k, v in all_maps.items()} + return all_maps + +def print_maps(all_maps): + # Warning: hacky + make_row = lambda vals: (' %5s |' * len(vals)) % tuple(vals) + make_sep = lambda n: ('-------+' * n) + + print() + print(make_row([''] + [('.%d ' % x if isinstance(x, int) else x + ' ') for x in all_maps['box'].keys()])) + print(make_sep(len(all_maps['box']) + 1)) + for iou_type in ('box', 'mask'): + print(make_row([iou_type] + ['%.2f' % x if x < 100 else '%.1f' % x for x in all_maps[iou_type].values()])) + print(make_sep(len(all_maps['box']) + 1)) + print() + +if __name__ == '__main__': + parse_args() + path = './result/dumpOutput_device{}/'.format(args.device_id) + + if args.config is not None: + set_cfg(args.config) + + else: + args.config = 'yolact_base_config' + print('Config not specified. Parsed %s from the file name.\n' % args.config) + set_cfg(args.config) + + #if args.image is None and args.video is None and args.images is None: + dataset = COCODetection(args.valid_images, args.valid_annotations, + transform=BaseTransform(), has_gt=cfg.dataset.has_gt) + prep_coco_cats() + + evaluate(path, dataset) diff --git a/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/YOLACT_preprocess.py b/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/YOLACT_preprocess.py index 5b7eb4e094..4b4f69590b 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/YOLACT_preprocess.py +++ b/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/YOLACT_preprocess.py @@ -1,156 +1,156 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 data import COCODetection, get_label_map -from utils.augmentations import BaseTransform -from data import cfg, set_cfg -import numpy as np -from torch.autograd import Variable -import argparse -import random -import os -from collections import defaultdict - -def str2bool(v): - if v.lower() in ('yes', 'true', 't', 'y', '1'): - return True - elif v.lower() in ('no', 'false', 'f', 'n', '0'): - return False - else: - raise argparse.ArgumentTypeError('Boolean value expected.') - -def parse_args(argv=None): - parser = argparse.ArgumentParser( - description='YOLACT COCO Evaluation') - parser.add_argument('--valid_images', default='/home/data/coco/images/', help='the path of validation images') - parser.add_argument('--valid_annotations', default='/home/data/coco/annotations/instances_val2017.json', help='the path of validation annotations') - parser.add_argument('--cuda', default=True, type=str2bool, - help='Use cuda to evaulate model') - parser.add_argument('--display', dest='display', action='store_true', - help='Display qualitative results instead of quantitative ones.') - parser.add_argument('--shuffle', dest='shuffle', action='store_true', - help='Shuffles the images when displaying them. Doesn\'t have much of an effect when display is off though.') - parser.add_argument('--resume', dest='resume', action='store_true', - help='If display not set, this resumes mAP calculations from the ap_data_file.') - parser.add_argument('--max_images', default=-1, type=int, - help='The maximum number of images from the dataset to consider. Use -1 for all.') - parser.add_argument('--config', default=None, - help='The config object to use.') - parser.add_argument('--no_sort', default=False, dest='no_sort', action='store_true', - help='Do not sort images by hashed image ID.') - parser.add_argument('--seed', default=None, type=int, - help='The seed to pass into random.seed. Note: this is only really for the shuffle and does not (I think) affect cuda stuff.') - parser.add_argument('--image', default=None, type=str, - help='A path to an image to use for display.') - parser.add_argument('--images', default=None, type=str, - help='An input folder of images and output folder to save detected images. Should be in the format input->output.') - parser.add_argument('--dataset', default=None, type=str, - help='If specified, override the dataset specified in the config with this one (example: coco2017_dataset).') - parser.set_defaults(display=False, resume=False, shuffle=False, - no_sort=False) - - global args - args = parser.parse_args(argv) - - if args.seed is not None: - random.seed(args.seed) - -iou_thresholds = [x / 100 for x in range(50, 100, 5)] -coco_cats = {} # Call prep_coco_cats to fill this -coco_cats_inv = {} -color_cache = defaultdict(lambda: {}) - -def prep_coco_cats(): - """ Prepare inverted table for category id lookup given a coco cats object. """ - for coco_cat_id, transformed_cat_id_p1 in get_label_map().items(): - transformed_cat_id = transformed_cat_id_p1 - 1 - coco_cats[transformed_cat_id] = coco_cat_id - coco_cats_inv[coco_cat_id] = transformed_cat_id - -def badhash(x): - """ - Just a quick and dirty hash function for doing a deterministic shuffle based on image_id. - - Source: - https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key - """ - x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF - x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF - x = ((x >> 16) ^ x) & 0xFFFFFFFF - return x - -def preprocess(dataset, save_path = None): - dataset_size = len(dataset) if args.max_images < 0 else min(args.max_images, len(dataset)) - print("dataset size is : ", dataset_size) - print() - - # For each class and iou, stores tuples (score, isPositive) - # Index ap_data[type][iouIdx][classIdx] - dataset_indices = list(range(len(dataset))) - print("dataset indices size is :", len(dataset_indices)) - if args.shuffle: - random.shuffle(dataset_indices) - elif not args.no_sort: - hashed = [badhash(x) for x in dataset.ids] - dataset_indices.sort(key=lambda x: hashed[x]) - - dataset_indices = dataset_indices[:dataset_size] - - if save_path is None: - save_path = './prep_dataset/' - - if os.path.exists(save_path) == False: - os.mkdir(save_path) - else: - print('dir exist!') - - # Main eval loop - with open('yolact_prep_bin.info', 'w+') as f: - for it, image_idx in enumerate(dataset_indices): - img, gt, gt_masks, h, w, num_crowd = dataset.pull_item(image_idx) - # Test flag, do not upvote - batch = Variable(img.unsqueeze(0)) - batch_numpy = np.array(batch).astype(np.float32) - - binFileName = os.path.join(save_path, 'coco_val2017_' + str(image_idx) + '.bin') - - batch_numpy.tofile(binFileName) - - line = str(it) + ' ' + binFileName + ' ' + '550 550\n' - f.write(line) - if it % 100 == 0: - print('[INFO][PreProcess]', 'CurSampleNum:', it) - -if __name__ == '__main__': - parse_args() - - if args.config is not None: - set_cfg(args.config) - - else: - args.config = 'yolact_base_config' - print('Config not specified. Parsed %s from the file name.\n' % args.config) - set_cfg(args.config) - - if not os.path.exists('results'): - os.makedirs('results') - - #if args.image is None and args.video is None and args.images is None: - dataset = COCODetection(args.valid_images, args.valid_annotations, - transform=BaseTransform(), has_gt=cfg.dataset.has_gt) - prep_coco_cats() - - preprocess(dataset) - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 data import COCODetection, get_label_map +from utils.augmentations import BaseTransform +from data import cfg, set_cfg +import numpy as np +from torch.autograd import Variable +import argparse +import random +import os +from collections import defaultdict + +def str2bool(v): + if v.lower() in ('yes', 'true', 't', 'y', '1'): + return True + elif v.lower() in ('no', 'false', 'f', 'n', '0'): + return False + else: + raise argparse.ArgumentTypeError('Boolean value expected.') + +def parse_args(argv=None): + parser = argparse.ArgumentParser( + description='YOLACT COCO Evaluation') + parser.add_argument('--valid_images', default='/home/data/coco/images/', help='the path of validation images') + parser.add_argument('--valid_annotations', default='/home/data/coco/annotations/instances_val2017.json', help='the path of validation annotations') + parser.add_argument('--cuda', default=True, type=str2bool, + help='Use cuda to evaulate model') + parser.add_argument('--display', dest='display', action='store_true', + help='Display qualitative results instead of quantitative ones.') + parser.add_argument('--shuffle', dest='shuffle', action='store_true', + help='Shuffles the images when displaying them. Doesn\'t have much of an effect when display is off though.') + parser.add_argument('--resume', dest='resume', action='store_true', + help='If display not set, this resumes mAP calculations from the ap_data_file.') + parser.add_argument('--max_images', default=-1, type=int, + help='The maximum number of images from the dataset to consider. Use -1 for all.') + parser.add_argument('--config', default=None, + help='The config object to use.') + parser.add_argument('--no_sort', default=False, dest='no_sort', action='store_true', + help='Do not sort images by hashed image ID.') + parser.add_argument('--seed', default=None, type=int, + help='The seed to pass into random.seed. Note: this is only really for the shuffle and does not (I think) affect cuda stuff.') + parser.add_argument('--image', default=None, type=str, + help='A path to an image to use for display.') + parser.add_argument('--images', default=None, type=str, + help='An input folder of images and output folder to save detected images. Should be in the format input->output.') + parser.add_argument('--dataset', default=None, type=str, + help='If specified, override the dataset specified in the config with this one (example: coco2017_dataset).') + parser.set_defaults(display=False, resume=False, shuffle=False, + no_sort=False) + + global args + args = parser.parse_args(argv) + + if args.seed is not None: + random.seed(args.seed) + +iou_thresholds = [x / 100 for x in range(50, 100, 5)] +coco_cats = {} # Call prep_coco_cats to fill this +coco_cats_inv = {} +color_cache = defaultdict(lambda: {}) + +def prep_coco_cats(): + """ Prepare inverted table for category id lookup given a coco cats object. """ + for coco_cat_id, transformed_cat_id_p1 in get_label_map().items(): + transformed_cat_id = transformed_cat_id_p1 - 1 + coco_cats[transformed_cat_id] = coco_cat_id + coco_cats_inv[coco_cat_id] = transformed_cat_id + +def badhash(x): + """ + Just a quick and dirty hash function for doing a deterministic shuffle based on image_id. + + Source: + https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key + """ + x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF + x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF + x = ((x >> 16) ^ x) & 0xFFFFFFFF + return x + +def preprocess(dataset, save_path = None): + dataset_size = len(dataset) if args.max_images < 0 else min(args.max_images, len(dataset)) + print("dataset size is : ", dataset_size) + print() + + # For each class and iou, stores tuples (score, isPositive) + # Index ap_data[type][iouIdx][classIdx] + dataset_indices = list(range(len(dataset))) + print("dataset indices size is :", len(dataset_indices)) + if args.shuffle: + random.shuffle(dataset_indices) + elif not args.no_sort: + hashed = [badhash(x) for x in dataset.ids] + dataset_indices.sort(key=lambda x: hashed[x]) + + dataset_indices = dataset_indices[:dataset_size] + + if save_path is None: + save_path = './prep_dataset/' + + if os.path.exists(save_path) == False: + os.mkdir(save_path) + else: + print('dir exist!') + + # Main eval loop + with open('yolact_prep_bin.info', 'w+') as f: + for it, image_idx in enumerate(dataset_indices): + img, gt, gt_masks, h, w, num_crowd = dataset.pull_item(image_idx) + # Test flag, do not upvote + batch = Variable(img.unsqueeze(0)) + batch_numpy = np.array(batch).astype(np.float32) + + binFileName = os.path.join(save_path, 'coco_val2017_' + str(image_idx) + '.bin') + + batch_numpy.tofile(binFileName) + + line = str(it) + ' ' + binFileName + ' ' + '550 550\n' + f.write(line) + if it % 100 == 0: + print('[INFO][PreProcess]', 'CurSampleNum:', it) + +if __name__ == '__main__': + parse_args() + + if args.config is not None: + set_cfg(args.config) + + else: + args.config = 'yolact_base_config' + print('Config not specified. Parsed %s from the file name.\n' % args.config) + set_cfg(args.config) + + if not os.path.exists('results'): + os.makedirs('results') + + #if args.image is None and args.video is None and args.images is None: + dataset = COCODetection(args.valid_images, args.valid_annotations, + transform=BaseTransform(), has_gt=cfg.dataset.has_gt) + prep_coco_cats() + + preprocess(dataset) + + diff --git a/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/dcnv2.diff b/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/dcnv2.diff index c1af4f32ce..f1d3a4edb9 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/dcnv2.diff +++ b/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/dcnv2.diff @@ -1,107 +1,107 @@ -diff --git a/dcn_v2.py b/dcn_v2.py -index 982bef5..db33229 100644 ---- a/dcn_v2.py -+++ b/dcn_v2.py - -@@ -14,16 +15,38 @@ import _ext as _backend - - - class _DCNv2(Function): -+ -+ @staticmethod -+ def symbolic(g, input, weight, offset, bias, stride, padding, -+ dilation, groups, defomable_groups): -+ if isinstance(stride, int): -+ stride = (stride, stride) -+ if isinstance(padding, int): -+ padding = (padding, padding) -+ if isinstance(dilation, int): -+ dilation = (dilation, dilation) -+ return g.op( -+ 'DeformableConv2D', -+ input, -+ weight, -+ offset, -+ bias, -+ strides_i=stride, -+ pads_i=padding, -+ dilations_i=dilation, -+ groups_i=groups, -+ defomable_groups_i=defomable_groups) - @staticmethod -- def forward(ctx, input, offset, mask, weight, bias, -- stride, padding, dilation, deformable_groups): -+ def forward(ctx, input, weight, offest, bias, -+ stride, padding, dilation, groups=1, deformable_groups=1): - ctx.stride = _pair(stride) - ctx.padding = _pair(padding) - ctx.dilation = _pair(dilation) - ctx.kernel_size = _pair(weight.shape[2:4]) - ctx.deformable_groups = deformable_groups -- output = _backend.dcn_v2_forward(input, weight, bias, -- offset, mask, -+ return torch.rand(_DCNv2._infer_shape(ctx, input, weight)).to(input.device) -+ output = _backend.dcn_v2_forward(input.float(), weight.float(), bias.float(), -+ offset.float(), mask.float(), - ctx.kernel_size[0], ctx.kernel_size[1], - ctx.stride[0], ctx.stride[1], - ctx.padding[0], ctx.padding[1], -@@ -31,15 +54,26 @@ class _DCNv2(Function): - ctx.deformable_groups) - ctx.save_for_backward(input, offset, mask, weight, bias) - return output -+ @staticmethod -+ def _infer_shape(ctx, input, weight): -+ n = input.size(0) -+ channels_out = weight.size(0) -+ height, width = input.shape[2:4] -+ kernel_h, kernel_w = weight.shape[2:4] -+ height_out = (height + 2 * ctx.padding[0] - -+ (ctx.dilation[0] * (kernel_h - 1) + 1)) // ctx.stride[0] + 1 -+ width_out = (width + 2 * ctx.padding[0] - -+ (ctx.dilation[0] * (kernel_w - 1) + 1)) // ctx.stride[0] + 1 -+ return n, channels_out, height_out, width_out - - @staticmethod - @once_differentiable - def backward(ctx, grad_output): - input, offset, mask, weight, bias = ctx.saved_tensors - grad_input, grad_offset, grad_mask, grad_weight, grad_bias = \ -- _backend.dcn_v2_backward(input, weight, -- bias, -- offset, mask, -+ _backend.dcn_v2_backward(input.float(), weight.float(), -+ bias.float(), -+ offset.float(), mask.float(), - grad_output, - ctx.kernel_size[0], ctx.kernel_size[1], - ctx.stride[0], ctx.stride[1], -@@ -120,11 +154,19 @@ class DCN(DCNv2): - o1, o2, mask = torch.chunk(out, 3, dim=1) - offset = torch.cat((o1, o2), dim=1) - mask = torch.sigmoid(mask) -- return dcn_v2_conv(input, offset, mask, -- self.weight, self.bias, -+ offset_y = offset.reshape(offset.shape[0], -1, 2, offset.shape[2], -+ offset.shape[3])[:, :, 0, ...].reshape(offset.shape[0], offset.shape[1] // 2, offset.shape[2], -+ offset.shape[3]) -+ offset_x = offset.reshape(offset.shape[0], -1, 2, offset.shape[2], -+ offset.shape[3])[:, :, 1, ...].reshape(offset.shape[0], offset.shape[1] // 2, offset.shape[2], -+ offset.shape[3]) -+ offset = torch.cat((offset_x, offset_y, mask), 1) -+ return dcn_v2_conv(input, -+ self.weight, offset, self.bias, - self.stride, - self.padding, - self.dilation, -+ 1, - self.deformable_groups) - - -@@ -300,4 +342,4 @@ class DCNPooling(DCNv2Pooling): - self.group_size, - self.part_size, - self.sample_per_part, -- self.trans_std) -+ self.trans_std) +diff --git a/dcn_v2.py b/dcn_v2.py +index 982bef5..db33229 100644 +--- a/dcn_v2.py ++++ b/dcn_v2.py + +@@ -14,16 +15,38 @@ import _ext as _backend + + + class _DCNv2(Function): ++ ++ @staticmethod ++ def symbolic(g, input, weight, offset, bias, stride, padding, ++ dilation, groups, defomable_groups): ++ if isinstance(stride, int): ++ stride = (stride, stride) ++ if isinstance(padding, int): ++ padding = (padding, padding) ++ if isinstance(dilation, int): ++ dilation = (dilation, dilation) ++ return g.op( ++ 'DeformableConv2D', ++ input, ++ weight, ++ offset, ++ bias, ++ strides_i=stride, ++ pads_i=padding, ++ dilations_i=dilation, ++ groups_i=groups, ++ defomable_groups_i=defomable_groups) + @staticmethod +- def forward(ctx, input, offset, mask, weight, bias, +- stride, padding, dilation, deformable_groups): ++ def forward(ctx, input, weight, offest, bias, ++ stride, padding, dilation, groups=1, deformable_groups=1): + ctx.stride = _pair(stride) + ctx.padding = _pair(padding) + ctx.dilation = _pair(dilation) + ctx.kernel_size = _pair(weight.shape[2:4]) + ctx.deformable_groups = deformable_groups +- output = _backend.dcn_v2_forward(input, weight, bias, +- offset, mask, ++ return torch.rand(_DCNv2._infer_shape(ctx, input, weight)).to(input.device) ++ output = _backend.dcn_v2_forward(input.float(), weight.float(), bias.float(), ++ offset.float(), mask.float(), + ctx.kernel_size[0], ctx.kernel_size[1], + ctx.stride[0], ctx.stride[1], + ctx.padding[0], ctx.padding[1], +@@ -31,15 +54,26 @@ class _DCNv2(Function): + ctx.deformable_groups) + ctx.save_for_backward(input, offset, mask, weight, bias) + return output ++ @staticmethod ++ def _infer_shape(ctx, input, weight): ++ n = input.size(0) ++ channels_out = weight.size(0) ++ height, width = input.shape[2:4] ++ kernel_h, kernel_w = weight.shape[2:4] ++ height_out = (height + 2 * ctx.padding[0] - ++ (ctx.dilation[0] * (kernel_h - 1) + 1)) // ctx.stride[0] + 1 ++ width_out = (width + 2 * ctx.padding[0] - ++ (ctx.dilation[0] * (kernel_w - 1) + 1)) // ctx.stride[0] + 1 ++ return n, channels_out, height_out, width_out + + @staticmethod + @once_differentiable + def backward(ctx, grad_output): + input, offset, mask, weight, bias = ctx.saved_tensors + grad_input, grad_offset, grad_mask, grad_weight, grad_bias = \ +- _backend.dcn_v2_backward(input, weight, +- bias, +- offset, mask, ++ _backend.dcn_v2_backward(input.float(), weight.float(), ++ bias.float(), ++ offset.float(), mask.float(), + grad_output, + ctx.kernel_size[0], ctx.kernel_size[1], + ctx.stride[0], ctx.stride[1], +@@ -120,11 +154,19 @@ class DCN(DCNv2): + o1, o2, mask = torch.chunk(out, 3, dim=1) + offset = torch.cat((o1, o2), dim=1) + mask = torch.sigmoid(mask) +- return dcn_v2_conv(input, offset, mask, +- self.weight, self.bias, ++ offset_y = offset.reshape(offset.shape[0], -1, 2, offset.shape[2], ++ offset.shape[3])[:, :, 0, ...].reshape(offset.shape[0], offset.shape[1] // 2, offset.shape[2], ++ offset.shape[3]) ++ offset_x = offset.reshape(offset.shape[0], -1, 2, offset.shape[2], ++ offset.shape[3])[:, :, 1, ...].reshape(offset.shape[0], offset.shape[1] // 2, offset.shape[2], ++ offset.shape[3]) ++ offset = torch.cat((offset_x, offset_y, mask), 1) ++ return dcn_v2_conv(input, ++ self.weight, offset, self.bias, + self.stride, + self.padding, + self.dilation, ++ 1, + self.deformable_groups) + + +@@ -300,4 +342,4 @@ class DCNPooling(DCNv2Pooling): + self.group_size, + self.part_size, + self.sample_per_part, +- self.trans_std) ++ self.trans_std) \ No newline at end of file \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/deform_conv.py b/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/deform_conv.py index 936bef9074..f6d7382141 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/deform_conv.py +++ b/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/deform_conv.py @@ -1,234 +1,234 @@ -# Copyright (c) 2020, Huawei Technologies.All rights reserved. -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 torch -import torch.nn as nn -from torch.autograd import Function -from torch.nn.modules.utils import _pair, _single -import math - - -class ModulatedDeformConv2dFunction(Function): - - @staticmethod - def forward(ctx, - input_tensor, - offset_ori, - mask, - weight, - bias=None, - with_bias=False, - stride=1, - padding=0, - dilation=1, - groups=1, - deformable_groups=1, - sort_index_for_npu_fp=None, - sort_index_for_npu_bp=None, - ): - - input_tensor = input_tensor.float() - offset_ori = offset_ori.float() - mask = mask.float() - - ctx.stride = stride - ctx.padding = padding - ctx.dilation = dilation - ctx.groups = groups - ctx.deformable_groups = deformable_groups - ctx.sort_index_for_npu_bp = sort_index_for_npu_bp - ctx.with_bias = with_bias - - offset = offset_ori.index_select(1, sort_index_for_npu_fp) - offset_all = torch.cat([offset, mask], dim=1) - output, offset_out = torch.npu_deformable_conv2d( - input_tensor, weight, offset_all, bias, - kernel_size=[weight.shape[3], weight.shape[2]], - stride=[1, 1, ctx.stride, ctx.stride], - padding=[ctx.padding, ctx.padding, ctx.padding, ctx.padding], - dilation=[1, 1, ctx.dilation, ctx.dilation], - groups=ctx.groups, deformable_groups=ctx.deformable_groups, - modulated=True) - if weight.requires_grad or mask.requires_grad or offset.requires_grad \ - or input_tensor.requires_grad: - ctx.save_for_backward(input_tensor, weight, offset_out, offset_all) - return output - - @staticmethod - def backward(ctx, grad_output): - input_tensor, weight, offset_out, offset_all = ctx.saved_tensors - grad_input, grad_weight, grad_offset_all, grad_bias = torch.npu_deformable_conv2dbk( - input_tensor, grad_output, offset_out, weight, offset_all, - kernel_size=[weight.shape[3], weight.shape[2]], - stride=[1, 1, ctx.stride, ctx.stride], - padding=[ctx.padding, ctx.padding, ctx.padding, ctx.padding], - dilation=[1, 1, ctx.dilation, ctx.dilation], - groups=ctx.groups, deformable_groups=ctx.deformable_groups, modulated=True) - grad_offset = grad_offset_all.index_select(1, ctx.sort_index_for_npu_bp) - grad_mask = grad_offset_all[:, grad_offset.shape[1]:, :, :] - if not ctx.with_bias: - grad_bias = None - - return (grad_input, grad_offset, grad_mask, grad_weight, grad_bias, - None, None, None, None, None, None, None, None) - - -class ModulatedDeformConv(nn.Module): - - def __init__(self, - in_channels, - out_channels, - kernel_size, - stride=1, - padding=0, - dilation=1, - groups=1, - deformable_groups=1, - bias=True, - pack=True, - ): - - r"""Applies an NPU based Modulated Deformable 2D convolution operation. - - Paper link: - [Deformable ConvNets v2: More Deformable, Better Results](https://arxiv.org/abs/1811.11168) - - Reference implementation link: - https://github.com/open-mmlab/mmcv/blob/master/mmcv/ops/modulated_deform_conv.py - - The implementation of this ModulatedDeformConv is mainly based - on the implementation of mmcv for design and reconstruction. - - In ModulatedDeformConvFunction, the forward and backward are customized, - and the input tensor is reconstructed ito match the NPU based function. - - It is worth mentioning that DeformConv(DCNv1) is also implemented - by setting modulated==False. Due to the difference between input - and initialization, there is no additional implementation here. - - .. note:: - ModulatedDeformConv only implements operations under fp32 data types. - Notice, weight and bias in conv_offset must be initialized to 0. - - Args: - in_channels (int): Number of channels in the input image. - out_channels (int): Number of channels produced by the convolution. - kernel_size(int, tuple): Size of the convolving kernel. - stride(int, tuple): Stride of the convolution. Default: 1. - padding (int or tuple): Zero-padding added to both sides of the input. - Default: 0. - dilation (int or tuple): Spacing between kernel elements. Default: 1. - groups (int): Number of blocked connections from input. - channels to output channels. Default: 1. - deform_groups (int): Number of deformable group partitions. - bias (bool): If True, adds a learnable bias to the output. Default: False. - pack (bool): If True, conv_offset and mask will be included in this module. Default: True. - - Examples:: - >>> m = ModulatedDeformConv(32, 32, 1) - >>> input_tensor = torch.randn(2, 32, 5, 5) - >>> output = m(input_tensor) - """ - - super(ModulatedDeformConv, self).__init__() - - self.in_channels = in_channels - self.out_channels = out_channels - self.kernel_size = _pair(kernel_size) - self.stride = stride - self.padding = padding - self.dilation = dilation - self.groups = groups - self.deformable_groups = deformable_groups - self.with_bias = bias - self.pack = pack - - self.weight = nn.Parameter( - torch.Tensor(out_channels, in_channels // groups, *self.kernel_size)) - if bias: - self.bias = nn.Parameter(torch.Tensor(out_channels)) - else: - self.bias = torch.zeros(self.weight.shape[0]) - - if self.pack: - self.conv_offset_mask = nn.Conv2d( - self.in_channels, - self.deformable_groups * 3 * self.kernel_size[0] * - self.kernel_size[1], - kernel_size=self.kernel_size, - stride=_pair(self.stride), - padding=_pair(self.padding), - bias=True) - - self.split_num = self.deformable_groups * 2 * self.kernel_size[0] * self.kernel_size[1] - sort_index_for_npu = list(range(self.split_num)) - sort_index_for_npu_fp = sort_index_for_npu[1::2] + sort_index_for_npu[::2] - sort_index_for_npu_bp_dict = {i: idx for idx, i in enumerate(sort_index_for_npu_fp)} - sort_index_for_npu_bp = [sort_index_for_npu_bp_dict[i] for i in sort_index_for_npu] - self.sort_index_for_npu_fp = torch.IntTensor(sort_index_for_npu_fp) - self.sort_index_for_npu_bp = torch.IntTensor(sort_index_for_npu_bp) - self.sort_index_for_npu_todevice = False - - self.init_param() - - def init_param(self): - n = self.in_channels - for k in self.kernel_size: - n *= k - stdv = 1. / math.sqrt(n) - self.weight.data.uniform_(-stdv, stdv) - if self.bias is not None: - self.bias.data.zero_() - - if self.pack: - self.conv_offset_mask.weight.data.zero_() - self.conv_offset_mask.bias.data.zero_() - - def forward(self, x): - if self.pack: - out = self.conv_offset_mask(x) - offset = out[:, :self.split_num, ...] - mask = torch.sigmoid(out[:, self.split_num:, ...]) - else: - x, offset, mask = x - - if not self.sort_index_for_npu_todevice: - self.sort_index_for_npu_fp = self.sort_index_for_npu_fp.to(x.device) - self.sort_index_for_npu_bp = self.sort_index_for_npu_bp.to(x.device) - self.bias = self.bias.to(x.device) - self.sort_index_for_npu_todevice = True - - return ModulatedDeformConv2dFunction.apply( - x, offset, mask, self.weight, self.bias, self.with_bias, - self.stride, self.padding, self.dilation, - self.groups, self.deformable_groups, - self.sort_index_for_npu_fp, - self.sort_index_for_npu_bp, - ) - - -DCNv2 = ModulatedDeformConv - -if __name__ == "__main__": - x = torch.randn(2, 32, 7, 7) - model = DCNv2(32, 32, 3, 2, 1) - - torch.npu.set_device(0) - x = x.npu() - model = model.npu() - - o = model(x) - l = o.sum() - l.backward() - print(l) +# Copyright (c) 2020, Huawei Technologies.All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 torch +import torch.nn as nn +from torch.autograd import Function +from torch.nn.modules.utils import _pair, _single +import math + + +class ModulatedDeformConv2dFunction(Function): + + @staticmethod + def forward(ctx, + input_tensor, + offset_ori, + mask, + weight, + bias=None, + with_bias=False, + stride=1, + padding=0, + dilation=1, + groups=1, + deformable_groups=1, + sort_index_for_npu_fp=None, + sort_index_for_npu_bp=None, + ): + + input_tensor = input_tensor.float() + offset_ori = offset_ori.float() + mask = mask.float() + + ctx.stride = stride + ctx.padding = padding + ctx.dilation = dilation + ctx.groups = groups + ctx.deformable_groups = deformable_groups + ctx.sort_index_for_npu_bp = sort_index_for_npu_bp + ctx.with_bias = with_bias + + offset = offset_ori.index_select(1, sort_index_for_npu_fp) + offset_all = torch.cat([offset, mask], dim=1) + output, offset_out = torch.npu_deformable_conv2d( + input_tensor, weight, offset_all, bias, + kernel_size=[weight.shape[3], weight.shape[2]], + stride=[1, 1, ctx.stride, ctx.stride], + padding=[ctx.padding, ctx.padding, ctx.padding, ctx.padding], + dilation=[1, 1, ctx.dilation, ctx.dilation], + groups=ctx.groups, deformable_groups=ctx.deformable_groups, + modulated=True) + if weight.requires_grad or mask.requires_grad or offset.requires_grad \ + or input_tensor.requires_grad: + ctx.save_for_backward(input_tensor, weight, offset_out, offset_all) + return output + + @staticmethod + def backward(ctx, grad_output): + input_tensor, weight, offset_out, offset_all = ctx.saved_tensors + grad_input, grad_weight, grad_offset_all, grad_bias = torch.npu_deformable_conv2dbk( + input_tensor, grad_output, offset_out, weight, offset_all, + kernel_size=[weight.shape[3], weight.shape[2]], + stride=[1, 1, ctx.stride, ctx.stride], + padding=[ctx.padding, ctx.padding, ctx.padding, ctx.padding], + dilation=[1, 1, ctx.dilation, ctx.dilation], + groups=ctx.groups, deformable_groups=ctx.deformable_groups, modulated=True) + grad_offset = grad_offset_all.index_select(1, ctx.sort_index_for_npu_bp) + grad_mask = grad_offset_all[:, grad_offset.shape[1]:, :, :] + if not ctx.with_bias: + grad_bias = None + + return (grad_input, grad_offset, grad_mask, grad_weight, grad_bias, + None, None, None, None, None, None, None, None) + + +class ModulatedDeformConv(nn.Module): + + def __init__(self, + in_channels, + out_channels, + kernel_size, + stride=1, + padding=0, + dilation=1, + groups=1, + deformable_groups=1, + bias=True, + pack=True, + ): + + r"""Applies an NPU based Modulated Deformable 2D convolution operation. + + Paper link: + [Deformable ConvNets v2: More Deformable, Better Results](https://arxiv.org/abs/1811.11168) + + Reference implementation link: + https://github.com/open-mmlab/mmcv/blob/master/mmcv/ops/modulated_deform_conv.py + + The implementation of this ModulatedDeformConv is mainly based + on the implementation of mmcv for design and reconstruction. + + In ModulatedDeformConvFunction, the forward and backward are customized, + and the input tensor is reconstructed ito match the NPU based function. + + It is worth mentioning that DeformConv(DCNv1) is also implemented + by setting modulated==False. Due to the difference between input + and initialization, there is no additional implementation here. + + .. note:: + ModulatedDeformConv only implements operations under fp32 data types. + Notice, weight and bias in conv_offset must be initialized to 0. + + Args: + in_channels (int): Number of channels in the input image. + out_channels (int): Number of channels produced by the convolution. + kernel_size(int, tuple): Size of the convolving kernel. + stride(int, tuple): Stride of the convolution. Default: 1. + padding (int or tuple): Zero-padding added to both sides of the input. + Default: 0. + dilation (int or tuple): Spacing between kernel elements. Default: 1. + groups (int): Number of blocked connections from input. + channels to output channels. Default: 1. + deform_groups (int): Number of deformable group partitions. + bias (bool): If True, adds a learnable bias to the output. Default: False. + pack (bool): If True, conv_offset and mask will be included in this module. Default: True. + + Examples:: + >>> m = ModulatedDeformConv(32, 32, 1) + >>> input_tensor = torch.randn(2, 32, 5, 5) + >>> output = m(input_tensor) + """ + + super(ModulatedDeformConv, self).__init__() + + self.in_channels = in_channels + self.out_channels = out_channels + self.kernel_size = _pair(kernel_size) + self.stride = stride + self.padding = padding + self.dilation = dilation + self.groups = groups + self.deformable_groups = deformable_groups + self.with_bias = bias + self.pack = pack + + self.weight = nn.Parameter( + torch.Tensor(out_channels, in_channels // groups, *self.kernel_size)) + if bias: + self.bias = nn.Parameter(torch.Tensor(out_channels)) + else: + self.bias = torch.zeros(self.weight.shape[0]) + + if self.pack: + self.conv_offset_mask = nn.Conv2d( + self.in_channels, + self.deformable_groups * 3 * self.kernel_size[0] * + self.kernel_size[1], + kernel_size=self.kernel_size, + stride=_pair(self.stride), + padding=_pair(self.padding), + bias=True) + + self.split_num = self.deformable_groups * 2 * self.kernel_size[0] * self.kernel_size[1] + sort_index_for_npu = list(range(self.split_num)) + sort_index_for_npu_fp = sort_index_for_npu[1::2] + sort_index_for_npu[::2] + sort_index_for_npu_bp_dict = {i: idx for idx, i in enumerate(sort_index_for_npu_fp)} + sort_index_for_npu_bp = [sort_index_for_npu_bp_dict[i] for i in sort_index_for_npu] + self.sort_index_for_npu_fp = torch.IntTensor(sort_index_for_npu_fp) + self.sort_index_for_npu_bp = torch.IntTensor(sort_index_for_npu_bp) + self.sort_index_for_npu_todevice = False + + self.init_param() + + def init_param(self): + n = self.in_channels + for k in self.kernel_size: + n *= k + stdv = 1. / math.sqrt(n) + self.weight.data.uniform_(-stdv, stdv) + if self.bias is not None: + self.bias.data.zero_() + + if self.pack: + self.conv_offset_mask.weight.data.zero_() + self.conv_offset_mask.bias.data.zero_() + + def forward(self, x): + if self.pack: + out = self.conv_offset_mask(x) + offset = out[:, :self.split_num, ...] + mask = torch.sigmoid(out[:, self.split_num:, ...]) + else: + x, offset, mask = x + + if not self.sort_index_for_npu_todevice: + self.sort_index_for_npu_fp = self.sort_index_for_npu_fp.to(x.device) + self.sort_index_for_npu_bp = self.sort_index_for_npu_bp.to(x.device) + self.bias = self.bias.to(x.device) + self.sort_index_for_npu_todevice = True + + return ModulatedDeformConv2dFunction.apply( + x, offset, mask, self.weight, self.bias, self.with_bias, + self.stride, self.padding, self.dilation, + self.groups, self.deformable_groups, + self.sort_index_for_npu_fp, + self.sort_index_for_npu_bp, + ) + + +DCNv2 = ModulatedDeformConv + +if __name__ == "__main__": + x = torch.randn(2, 32, 7, 7) + model = DCNv2(32, 32, 3, 2, 1) + + torch.npu.set_device(0) + x = x.npu() + model = model.npu() + + o = model(x) + l = o.sum() + l.backward() + print(l) diff --git a/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/modelzoo_level.txt index 282c3ff3b3..c5c4a9d800 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus:POK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/pth2onnx.py b/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/pth2onnx.py index 947bca196f..b357400674 100644 --- a/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus/pth2onnx.py @@ -1,180 +1,180 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -''' -YOLACT pth权重文件转为onnx权重文件 -''' -import sys -import os -sys.path.append('../') -import torch -import torch.onnx -import argparse -from data import * -from yolact import Yolact -# -set_cfg('yolact_plus_resnet50_config') -from torch.autograd import Variable - - -def str2bool(v): - return v.lower() in ("yes", "true", "t", "1") - - -parser_pth2onnx = argparse.ArgumentParser(description='Turn YOLACT .pth module to .onnx module') - -parser_pth2onnx.add_argument('--trained_model', type=str, - default='yolact_plus_resnet50_54_800000.pth', help='choose .pth module') - -parser_pth2onnx.add_argument('--outputName', type=str, - default='yolact_plus', help='the name of the output onnx module') - -parser_pth2onnx.add_argument('--dynamic', default=False, type=str2bool, - help='choose whether the output onnx module is dynamic or not') - -args_pth2onnx = parser_pth2onnx.parse_args() - -def removeAdd240Node(model): - addNodeNum = 1227 #1227, 344 - addNode = model.graph.node[addNodeNum] - model.graph.node.remove(addNode) - for node in model.graph.node: - if '1763' in node.input: - assert node.input[0] == '1763' #'1763','1005' - node.input[0] = '1761' #'1761','1003' - - -def optimSoftmax(model): - from onnx import helper - - findOldSoftmaxNode = False - for node in model.graph.node: - if 'Softmax' in node.name: - oldSoftmaxName = node.name - oldSoftmaxInput = node.input[0] - findOldSoftmaxNode = True - break - - assert node.output[0] == 'output1' - assert findOldSoftmaxNode - - model.graph.node.remove(node) - - TransposeNode_Pre = helper.make_node('Transpose', [oldSoftmaxInput], ['66666'], - perm=[0, 2, 1], name='Transpose_Pre') - - newSoftmax = helper.make_node("Softmax", axis=1, inputs=["66666"], - outputs=["88888"], name=oldSoftmaxName) - - TransposeNode_After = helper.make_node('Transpose', ['88888'], ['output1'], - perm=[0, 2, 1], name="Transpose_After") - - model.graph.node.append(TransposeNode_Pre) - model.graph.node.append(TransposeNode_After) - model.graph.node.append(newSoftmax) - - a = model.graph.output[1].type.tensor_type.shape.dim[1] - a.dim_param = '57744' # 57744, 19248 - b = model.graph.output[1].type.tensor_type.shape.dim[2] - b.dim_param = '81' - - -def ReplaceScales(ori_list, scales_name): - n_list = [] - for i, x in enumerate(ori_list): - if i < 2: - n_list.append(x) - if i == 3: - n_list.append(scales_name) - return n_list - -def optimresize(model): - # 替换Resize节点 - i = 1311 #429 - n = model.graph.node[i] - if n.op_type == "Resize": - print("Resize", i, n.input, n.output) - model.graph.initializer.append( - onnx.helper.make_tensor('scales{}'.format(i), onnx.TensorProto.FLOAT, [4], [1, 1, 2, 2]) - ) - newnode = onnx.helper.make_node( - 'Resize', - name=n.name, - inputs=ReplaceScales(n.input, 'scales{}'.format(i)), - outputs=n.output, - coordinate_transformation_mode='pytorch_half_pixel', - cubic_coeff_a=-0.75, - mode='linear', - nearest_mode='floor' - ) - model.graph.node.remove(n) - model.graph.node.insert(i, newnode) - print("replace {} index {}".format(n.name, i)) - # for i in range(401, 428): - # print('remove:', model.graph.node[401].name) - # model.graph.node.remove(model.graph.node[401]) - - -def convert(path, pthPath): - ''' - 转换pth模型为onnx模型 - :param path: onnx模型存储路径 - :param pthPath: pth模型路径 - :return: - ''' - yolact_net = Yolact() - yolact_net.load_weights(pthPath, useCuda=False) - yolact_net.exportOnnx = True - yolact_net.eval() - - input_names = ["input.1"] - - dummy_input = Variable( - torch.randn(1, 3, 550, 550)) - - output_names = ["output0", "output1", "output2", "output3", "output4"] - - if args_pth2onnx.dynamic: - dynamic_axes = { - 'input.1': {0: '-1'}, - 'output0': {0: '-1'}, - 'output1': {0: '-1'}, - 'output2': {0: '-1'}, - 'output3': {0: '-1'}, - 'output4': {0: '-1'} - } - torch.onnx.export(yolact_net, dummy_input, args_pth2onnx.outputName + ".onnx", - verbose=True, dynamic_axes=dynamic_axes, - input_names=input_names, - output_names=output_names, opset_version=11, enable_onnx_checker=False) - - else: - torch.onnx.export(yolact_net, dummy_input, - args_pth2onnx.outputName + '.onnx', - input_names=input_names, - output_names=output_names, - opset_version=11, verbose=True, enable_onnx_checker=False) - - -if __name__ == '__main__': - path = os.getcwd() - pthPath = os.getcwd() + '/' + args_pth2onnx.trained_model - convert(path, pthPath) - import onnx - - model = onnx.load('./' + args_pth2onnx.outputName + '.onnx') - removeAdd240Node(model) - optimSoftmax(model) - optimresize(model) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +''' +YOLACT pth权重文件转为onnx权重文件 +''' +import sys +import os +sys.path.append('../') +import torch +import torch.onnx +import argparse +from data import * +from yolact import Yolact +# +set_cfg('yolact_plus_resnet50_config') +from torch.autograd import Variable + + +def str2bool(v): + return v.lower() in ("yes", "true", "t", "1") + + +parser_pth2onnx = argparse.ArgumentParser(description='Turn YOLACT .pth module to .onnx module') + +parser_pth2onnx.add_argument('--trained_model', type=str, + default='yolact_plus_resnet50_54_800000.pth', help='choose .pth module') + +parser_pth2onnx.add_argument('--outputName', type=str, + default='yolact_plus', help='the name of the output onnx module') + +parser_pth2onnx.add_argument('--dynamic', default=False, type=str2bool, + help='choose whether the output onnx module is dynamic or not') + +args_pth2onnx = parser_pth2onnx.parse_args() + +def removeAdd240Node(model): + addNodeNum = 1227 #1227, 344 + addNode = model.graph.node[addNodeNum] + model.graph.node.remove(addNode) + for node in model.graph.node: + if '1763' in node.input: + assert node.input[0] == '1763' #'1763','1005' + node.input[0] = '1761' #'1761','1003' + + +def optimSoftmax(model): + from onnx import helper + + findOldSoftmaxNode = False + for node in model.graph.node: + if 'Softmax' in node.name: + oldSoftmaxName = node.name + oldSoftmaxInput = node.input[0] + findOldSoftmaxNode = True + break + + assert node.output[0] == 'output1' + assert findOldSoftmaxNode + + model.graph.node.remove(node) + + TransposeNode_Pre = helper.make_node('Transpose', [oldSoftmaxInput], ['66666'], + perm=[0, 2, 1], name='Transpose_Pre') + + newSoftmax = helper.make_node("Softmax", axis=1, inputs=["66666"], + outputs=["88888"], name=oldSoftmaxName) + + TransposeNode_After = helper.make_node('Transpose', ['88888'], ['output1'], + perm=[0, 2, 1], name="Transpose_After") + + model.graph.node.append(TransposeNode_Pre) + model.graph.node.append(TransposeNode_After) + model.graph.node.append(newSoftmax) + + a = model.graph.output[1].type.tensor_type.shape.dim[1] + a.dim_param = '57744' # 57744, 19248 + b = model.graph.output[1].type.tensor_type.shape.dim[2] + b.dim_param = '81' + + +def ReplaceScales(ori_list, scales_name): + n_list = [] + for i, x in enumerate(ori_list): + if i < 2: + n_list.append(x) + if i == 3: + n_list.append(scales_name) + return n_list + +def optimresize(model): + # 替换Resize节点 + i = 1311 #429 + n = model.graph.node[i] + if n.op_type == "Resize": + print("Resize", i, n.input, n.output) + model.graph.initializer.append( + onnx.helper.make_tensor('scales{}'.format(i), onnx.TensorProto.FLOAT, [4], [1, 1, 2, 2]) + ) + newnode = onnx.helper.make_node( + 'Resize', + name=n.name, + inputs=ReplaceScales(n.input, 'scales{}'.format(i)), + outputs=n.output, + coordinate_transformation_mode='pytorch_half_pixel', + cubic_coeff_a=-0.75, + mode='linear', + nearest_mode='floor' + ) + model.graph.node.remove(n) + model.graph.node.insert(i, newnode) + print("replace {} index {}".format(n.name, i)) + # for i in range(401, 428): + # print('remove:', model.graph.node[401].name) + # model.graph.node.remove(model.graph.node[401]) + + +def convert(path, pthPath): + ''' + 转换pth模型为onnx模型 + :param path: onnx模型存储路径 + :param pthPath: pth模型路径 + :return: + ''' + yolact_net = Yolact() + yolact_net.load_weights(pthPath, useCuda=False) + yolact_net.exportOnnx = True + yolact_net.eval() + + input_names = ["input.1"] + + dummy_input = Variable( + torch.randn(1, 3, 550, 550)) + + output_names = ["output0", "output1", "output2", "output3", "output4"] + + if args_pth2onnx.dynamic: + dynamic_axes = { + 'input.1': {0: '-1'}, + 'output0': {0: '-1'}, + 'output1': {0: '-1'}, + 'output2': {0: '-1'}, + 'output3': {0: '-1'}, + 'output4': {0: '-1'} + } + torch.onnx.export(yolact_net, dummy_input, args_pth2onnx.outputName + ".onnx", + verbose=True, dynamic_axes=dynamic_axes, + input_names=input_names, + output_names=output_names, opset_version=11, enable_onnx_checker=False) + + else: + torch.onnx.export(yolact_net, dummy_input, + args_pth2onnx.outputName + '.onnx', + input_names=input_names, + output_names=output_names, + opset_version=11, verbose=True, enable_onnx_checker=False) + + +if __name__ == '__main__': + path = os.getcwd() + pthPath = os.getcwd() + '/' + args_pth2onnx.trained_model + convert(path, pthPath) + import onnx + + model = onnx.load('./' + args_pth2onnx.outputName + '.onnx') + removeAdd240Node(model) + optimSoftmax(model) + optimresize(model) onnx.save_model(model, args_pth2onnx.outputName + '.onnx') \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/super_resolution/EDSR/LICENSE b/ACL_PyTorch/contrib/cv/super_resolution/EDSR/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/super_resolution/EDSR/LICENSE +++ b/ACL_PyTorch/contrib/cv/super_resolution/EDSR/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/super_resolution/EDSR/requirements.txt b/ACL_PyTorch/contrib/cv/super_resolution/EDSR/requirements.txt index 399dbfed08..fbd453de26 100644 --- a/ACL_PyTorch/contrib/cv/super_resolution/EDSR/requirements.txt +++ b/ACL_PyTorch/contrib/cv/super_resolution/EDSR/requirements.txt @@ -1,6 +1,6 @@ -torch == 1.5.0 -torchvision == 0.6.0 -onnx == 1.9.0 -numpy == 1.19.2 -Pillow == 8.2.0 +torch == 1.5.0 +torchvision == 0.6.0 +onnx == 1.9.0 +numpy == 1.19.2 +Pillow == 8.2.0 opencv-python == 4.5.2 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/super_resolution/RCAN/LICENSE b/ACL_PyTorch/contrib/cv/super_resolution/RCAN/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/super_resolution/RCAN/LICENSE +++ b/ACL_PyTorch/contrib/cv/super_resolution/RCAN/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git "a/ACL_PyTorch/contrib/cv/super_resolution/RCAN/RCAN_Onnx\347\253\257\345\210\260\347\253\257\346\216\250\347\220\206\346\214\207\345\257\274.md" "b/ACL_PyTorch/contrib/cv/super_resolution/RCAN/RCAN_Onnx\347\253\257\345\210\260\347\253\257\346\216\250\347\220\206\346\214\207\345\257\274.md" index f979b9dd8b..2bc1e9d7c2 100644 --- "a/ACL_PyTorch/contrib/cv/super_resolution/RCAN/RCAN_Onnx\347\253\257\345\210\260\347\253\257\346\216\250\347\220\206\346\214\207\345\257\274.md" +++ "b/ACL_PyTorch/contrib/cv/super_resolution/RCAN/RCAN_Onnx\347\253\257\345\210\260\347\253\257\346\216\250\347\220\206\346\214\207\345\257\274.md" @@ -1,241 +1,241 @@ -# RCAN Onnx 模型端到端推理指导 - -- [1. 模型概述](#1) - - [论文地址](#11) - - [代码地址](#12) -- [2. 环境说明](#2) - - [深度学习框架](#21) - - [python第三方库](#22) -- [3. 模型转换](#3) - - [pth转onnx模型](#31) -- [4. 数据预处理](#4) - - [数据集获取](#41) - - [数据集预处理](#42) - - [生成数据集信息文件](#43) -- [5. 离线推理](#5) - - [benchmark工具概述](#51) - - [离线推理](#52) -- [6. 精度对比](#6) -- [7. 性能对比](#7) - - [npu性能数据](#71) - - [T4性能数据](#72) - - [性能对比](#73) - -## 1. 模型概述 - -### 1.1 论文地址 - -[RCAB 论文](https://arxiv.org/abs/1807.02758) - -### 1.2 代码地址 - -[RCAN 代码](https://github.com/yulunzhang/RCAN) - -branck: master - -commit_id: 3339ebc59519c3bb2b5719b87dd36515ec7f3ba7 - -## 2. 环境说明 - -对于batch1与batch16,310性能均高于T4性能1.2倍,该模型放s在Benchmark/cv/classification目录下。 - -### 2.1 深度学习框架 - -``` -pytorch == 1.5.0 -torchvision == 0.6.0 -onnx == 1.9.0 -``` - -### 2.2 python第三方库 - -``` -numpy == 1.19.2 -Pillow == 8.2.0 -opencv-python == 4.5.2 -``` - -> **说明:** -> -> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 -> -> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 - -## 3. 模型转换 - -### 3.1 pth转onnx模型 - -1. 下载 pth 权重文,放入models目录下 - - [RCAN 预训练pth权重文件](https://pan.baidu.com/s/1bkoJKmdOcvLhOFXHVkFlKA) - - 文件名:RCAN_BIX2.pt - - md5sum:f567f8560fde71ba0973a7fe472a42f2 - -2. 克隆代码仓库代码 - - ```bash - git clone https://github.com/yulunzhang/RCAN.git - ``` - -3. 使用rcan_pth2onnx.py 脚本将pth转化为onnx - - ```bash - python3.7 rcan_pth2onnx.py --pth RCAN_BIX2.pt --onnx rcan.onnx - ``` - - RCAN_BIX2.pt 文件为步骤1中下载的预训练权重文件,该条指令将在运行处生成一个rcan.onnx文件,此文件即为目标onnx文件 - - -### 3.2 onnx转om模型 - -下列需要在具备华为Ascend系列芯片的机器上执行: - -1. 设置 atc 工作所需要的环境变量 - - ```bash - export install_path=/usr/local/Ascend/ascend-toolkit/latest - export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH - export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH - export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH - export ASCEND_OPP_PATH=${install_path}/opp - ``` - -2. 由于transpose算子对于某些shape不友好,需要进行优化,将如下内容写入switch.cfg中 - - ``` - TransposeReshapeFusionPass:off - ``` - - 经过Profiling分析,ConfusionTransposeD算子性能过低,故将其输入加入白名单。即在/usr/local/Ascend/ascend-toolkit/5.0.2.alpha003/x86_64-linux/opp/op_impl/built-in/ai_core/tbe/impl/dynamic/transpose.py里添加 Tranpose shape 白名单: - - ``` - 1,64,2,2,256,256 - ``` - - 以下是优化前后性能对比 - - | | 未任何优化前310(单卡吞吐率) | 优化后310(单卡吞吐率) | - | :--: | :---------------------------: | :---------------------: | - | bs1 | 0.7245 | 9.3220 | - -3. 使用atc工具将onnx模型转换为om模型,命令参考 - - ```bash - atc --framework=5 --model=rcan.onnx --output=rcan_1bs --input_format=NCHW --input_shape="image:1,3,256,256" --fusion_switch_file=switch.cfg --log=debug --soc_version=Ascend310 - ``` - - 此命令将在运行路径下生成一个rcan_1bs.om文件,此文件即为目标om模型文件 - -## 4. 数据预处理 - -### 4.1 数据集获取 - -该模型使用[Set5](https://github.com/yulunzhang/RCAN/tree/master/RCAN_TestCode/OriginalTestData/Set5)的5张验证集进行测试,图片数据放在/root/datasets/Set5。 - -### 4.2 数据集预处理 - -使用 rcan_preprocess.py 脚本进行数据预处理,脚本执行命令: - -``` -python3.7 rcan_preprocess.py -s /root/datasets/Set5/LR -d ./prep_data --size 256 -``` - -由于rcan模型支持动态输入,而atc工具需要指定输入大小,所以要在此对图像添加pad和进行缩放到同一大小,最终对推理产生的结果进行后处理恢复。以上命令将自动生成一个pad_info.json文件,此文件记录在数据预处理中对图像的pad和缩放信息,用于数据后处理时进行图像裁剪。 - -### 4.3 生成数据集信息文件 - -1. 生成数据集信息文件脚本 gen_dataset_info.py - -2. 执行生成数据集信息脚本,生成数据集信息文件 - - ```bash - python3.7 gen_dataset_info.py bin ./prep_data ./rcan_prep_bin.info 256 256 - ``` - - 第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 - -## 5. 离线推理 - -### 5.1 benchmark工具概述 - -benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN V100R020C10 推理benchmark工具用户指南 01 - -### 5.2 离线推理 - -1. 执行离线推理 - - ```bash - ./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=rcan_1bs.om -input_text_path=./rcan_prep_bin.info -input_width=256 -input_height=256 -output_binary=True -useDvpp=False - ``` - - 输出结果默认保存在当前目录result/dumpOutput_device{0},模型只有一个名为HR_image的输出,shape为bs * 512 * 512,数据类型为FP32,对应1个超分辨后的图像数据,每个输入对应的输出对应一个_x.bin文件。 - -2. 数据后处理 - - ```bash - python3.7 rcan_postprocess.py -s result/dumpOutput_device0/ -d post_data - ``` - - 由于在预处理中对图像进行了添加pad和缩放操作,故要对推理结果进行相应的裁剪和缩放 - -## 6. 精度对比 - -### 6.1 离线推理TopN精度 - -## 6. 精度对比 - -| | PSNR | SSIM | -| :----------------: | :---: | :----: | -| 原github仓库精度 | 38.27 | 0.9614 | -| om模型离线推理精度 | 38.25 | 0.9606 | - -## 7. 性能对比 - -### 7.1 npu性能数据 - -benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。由于模型不接受多 batch 输入,所以只统计在整个数据集上推理得到bs1的性能数据 - -使用benchmark工具在整个数据集上推理时获得的性能数据: - -``` -[e2e] throughputRate: 1.11943, latency: 4466.54 -[data read] throughputRate: 1253.13, moduleLatency: 0.798 -[preprocess] throughputRate: 5.22007, moduleLatency: 191.568 -[infer] throughputRate: 2.30086, Interface throughputRate: 2.32019, moduleLatency: 433.982 -[post] throughputRate: 2.29506, moduleLatency: 435.719 -``` - -Interface throughputRate: 2.32019,2.32019x4=9.28076fps 即是batch1 310单卡吞吐率 - -### 7.2 T4性能数据 - -在装有T4卡的服务器上测试gpu性能,测试过程请确保卡没有运行其他任务,TensorRT版本:7.2.3.4,cuda版本:11.0,cudnn版本:8.2 - -``` -trtexec --onnx=rcan.onnx --fp16 --shapes=image:1x3x256x256 -``` - -gpu T4是4个device并行执行的结果,mean是时延(tensorrt的时延是batch个数据的推理时间),即吞吐率的倒数乘以batch。其中--fp16是算子精度,目前算子精度只测--fp16的。 - -``` -[07/14/2021-10:48:26] [I] GPU Compute -[07/14/2021-10:48:26] [I] min: 150.203 ms -[07/14/2021-10:48:26] [I] max: 157.738 ms -[07/14/2021-10:48:26] [I] mean: 152.347 ms -[07/14/2021-10:48:26] [I] median: 151.781 ms -[07/14/2021-10:48:26] [I] percentile: 157.738 ms at 99% -[07/14/2021-10:48:26] [I] total compute time: 3.19929 s -``` - -batch1 t4单卡吞吐率:1000/(152.347/1)=6.5212fps - -### 7.3 性能对比 - -batch1: 9.28076fps > 6.5212fps - -310单个device的吞吐率乘4即单卡吞吐率比T4单卡的吞吐率大,故310性能高于T4性能,性能达标。 - -对于batch1,310性能高于T4性能1.2倍,该模型放在Benchmark/cv/classification目录下。 - +# RCAN Onnx 模型端到端推理指导 + +- [1. 模型概述](#1) + - [论文地址](#11) + - [代码地址](#12) +- [2. 环境说明](#2) + - [深度学习框架](#21) + - [python第三方库](#22) +- [3. 模型转换](#3) + - [pth转onnx模型](#31) +- [4. 数据预处理](#4) + - [数据集获取](#41) + - [数据集预处理](#42) + - [生成数据集信息文件](#43) +- [5. 离线推理](#5) + - [benchmark工具概述](#51) + - [离线推理](#52) +- [6. 精度对比](#6) +- [7. 性能对比](#7) + - [npu性能数据](#71) + - [T4性能数据](#72) + - [性能对比](#73) + +## 1. 模型概述 + +### 1.1 论文地址 + +[RCAB 论文](https://arxiv.org/abs/1807.02758) + +### 1.2 代码地址 + +[RCAN 代码](https://github.com/yulunzhang/RCAN) + +branck: master + +commit_id: 3339ebc59519c3bb2b5719b87dd36515ec7f3ba7 + +## 2. 环境说明 + +对于batch1与batch16,310性能均高于T4性能1.2倍,该模型放s在Benchmark/cv/classification目录下。 + +### 2.1 深度学习框架 + +``` +pytorch == 1.5.0 +torchvision == 0.6.0 +onnx == 1.9.0 +``` + +### 2.2 python第三方库 + +``` +numpy == 1.19.2 +Pillow == 8.2.0 +opencv-python == 4.5.2 +``` + +> **说明:** +> +> X86架构:pytorch,torchvision和onnx可以通过官方下载whl包安装,其它可以通过pip3.7 install 包名 安装 +> +> Arm架构:pytorch,torchvision和onnx可以通过源码编译安装,其它可以通过pip3.7 install 包名 安装 + +## 3. 模型转换 + +### 3.1 pth转onnx模型 + +1. 下载 pth 权重文,放入models目录下 + + [RCAN 预训练pth权重文件](https://pan.baidu.com/s/1bkoJKmdOcvLhOFXHVkFlKA) + + 文件名:RCAN_BIX2.pt + + md5sum:f567f8560fde71ba0973a7fe472a42f2 + +2. 克隆代码仓库代码 + + ```bash + git clone https://github.com/yulunzhang/RCAN.git + ``` + +3. 使用rcan_pth2onnx.py 脚本将pth转化为onnx + + ```bash + python3.7 rcan_pth2onnx.py --pth RCAN_BIX2.pt --onnx rcan.onnx + ``` + + RCAN_BIX2.pt 文件为步骤1中下载的预训练权重文件,该条指令将在运行处生成一个rcan.onnx文件,此文件即为目标onnx文件 + + +### 3.2 onnx转om模型 + +下列需要在具备华为Ascend系列芯片的机器上执行: + +1. 设置 atc 工作所需要的环境变量 + + ```bash + export install_path=/usr/local/Ascend/ascend-toolkit/latest + export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH + export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH + export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH + export ASCEND_OPP_PATH=${install_path}/opp + ``` + +2. 由于transpose算子对于某些shape不友好,需要进行优化,将如下内容写入switch.cfg中 + + ``` + TransposeReshapeFusionPass:off + ``` + + 经过Profiling分析,ConfusionTransposeD算子性能过低,故将其输入加入白名单。即在/usr/local/Ascend/ascend-toolkit/5.0.2.alpha003/x86_64-linux/opp/op_impl/built-in/ai_core/tbe/impl/dynamic/transpose.py里添加 Tranpose shape 白名单: + + ``` + 1,64,2,2,256,256 + ``` + + 以下是优化前后性能对比 + + | | 未任何优化前310(单卡吞吐率) | 优化后310(单卡吞吐率) | + | :--: | :---------------------------: | :---------------------: | + | bs1 | 0.7245 | 9.3220 | + +3. 使用atc工具将onnx模型转换为om模型,命令参考 + + ```bash + atc --framework=5 --model=rcan.onnx --output=rcan_1bs --input_format=NCHW --input_shape="image:1,3,256,256" --fusion_switch_file=switch.cfg --log=debug --soc_version=Ascend310 + ``` + + 此命令将在运行路径下生成一个rcan_1bs.om文件,此文件即为目标om模型文件 + +## 4. 数据预处理 + +### 4.1 数据集获取 + +该模型使用[Set5](https://github.com/yulunzhang/RCAN/tree/master/RCAN_TestCode/OriginalTestData/Set5)的5张验证集进行测试,图片数据放在/root/datasets/Set5。 + +### 4.2 数据集预处理 + +使用 rcan_preprocess.py 脚本进行数据预处理,脚本执行命令: + +``` +python3.7 rcan_preprocess.py -s /root/datasets/Set5/LR -d ./prep_data --size 256 +``` + +由于rcan模型支持动态输入,而atc工具需要指定输入大小,所以要在此对图像添加pad和进行缩放到同一大小,最终对推理产生的结果进行后处理恢复。以上命令将自动生成一个pad_info.json文件,此文件记录在数据预处理中对图像的pad和缩放信息,用于数据后处理时进行图像裁剪。 + +### 4.3 生成数据集信息文件 + +1. 生成数据集信息文件脚本 gen_dataset_info.py + +2. 执行生成数据集信息脚本,生成数据集信息文件 + + ```bash + python3.7 gen_dataset_info.py bin ./prep_data ./rcan_prep_bin.info 256 256 + ``` + + 第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,后面为宽高信息 + +## 5. 离线推理 + +### 5.1 benchmark工具概述 + +benchmark工具为华为自研的模型推理工具,支持多种模型的离线推理,能够迅速统计出模型在Ascend310上的性能,支持真实数据和纯推理两种模式,配合后处理脚本,可以实现诸多模型的端到端过程,获取工具及使用方法可以参考CANN V100R020C10 推理benchmark工具用户指南 01 + +### 5.2 离线推理 + +1. 执行离线推理 + + ```bash + ./benchmark.x86_64 -model_type=vision -device_id=0 -batch_size=1 -om_path=rcan_1bs.om -input_text_path=./rcan_prep_bin.info -input_width=256 -input_height=256 -output_binary=True -useDvpp=False + ``` + + 输出结果默认保存在当前目录result/dumpOutput_device{0},模型只有一个名为HR_image的输出,shape为bs * 512 * 512,数据类型为FP32,对应1个超分辨后的图像数据,每个输入对应的输出对应一个_x.bin文件。 + +2. 数据后处理 + + ```bash + python3.7 rcan_postprocess.py -s result/dumpOutput_device0/ -d post_data + ``` + + 由于在预处理中对图像进行了添加pad和缩放操作,故要对推理结果进行相应的裁剪和缩放 + +## 6. 精度对比 + +### 6.1 离线推理TopN精度 + +## 6. 精度对比 + +| | PSNR | SSIM | +| :----------------: | :---: | :----: | +| 原github仓库精度 | 38.27 | 0.9614 | +| om模型离线推理精度 | 38.25 | 0.9606 | + +## 7. 性能对比 + +### 7.1 npu性能数据 + +benchmark工具在整个数据集上推理时也会统计性能数据,但是推理整个数据集较慢,如果这么测性能那么整个推理期间需要确保独占device,使用npu-smi info可以查看device是否空闲。也可以使用benchmark纯推理功能测得性能数据,但是由于随机数不能模拟数据分布,纯推理功能测的有些模型性能数据可能不太准,benchmark纯推理功能测性能仅为快速获取大概的性能数据以便调试优化使用,可初步确认benchmark工具在整个数据集上推理时由于device也被其它推理任务使用了导致的性能不准的问题。由于模型不接受多 batch 输入,所以只统计在整个数据集上推理得到bs1的性能数据 + +使用benchmark工具在整个数据集上推理时获得的性能数据: + +``` +[e2e] throughputRate: 1.11943, latency: 4466.54 +[data read] throughputRate: 1253.13, moduleLatency: 0.798 +[preprocess] throughputRate: 5.22007, moduleLatency: 191.568 +[infer] throughputRate: 2.30086, Interface throughputRate: 2.32019, moduleLatency: 433.982 +[post] throughputRate: 2.29506, moduleLatency: 435.719 +``` + +Interface throughputRate: 2.32019,2.32019x4=9.28076fps 即是batch1 310单卡吞吐率 + +### 7.2 T4性能数据 + +在装有T4卡的服务器上测试gpu性能,测试过程请确保卡没有运行其他任务,TensorRT版本:7.2.3.4,cuda版本:11.0,cudnn版本:8.2 + +``` +trtexec --onnx=rcan.onnx --fp16 --shapes=image:1x3x256x256 +``` + +gpu T4是4个device并行执行的结果,mean是时延(tensorrt的时延是batch个数据的推理时间),即吞吐率的倒数乘以batch。其中--fp16是算子精度,目前算子精度只测--fp16的。 + +``` +[07/14/2021-10:48:26] [I] GPU Compute +[07/14/2021-10:48:26] [I] min: 150.203 ms +[07/14/2021-10:48:26] [I] max: 157.738 ms +[07/14/2021-10:48:26] [I] mean: 152.347 ms +[07/14/2021-10:48:26] [I] median: 151.781 ms +[07/14/2021-10:48:26] [I] percentile: 157.738 ms at 99% +[07/14/2021-10:48:26] [I] total compute time: 3.19929 s +``` + +batch1 t4单卡吞吐率:1000/(152.347/1)=6.5212fps + +### 7.3 性能对比 + +batch1: 9.28076fps > 6.5212fps + +310单个device的吞吐率乘4即单卡吞吐率比T4单卡的吞吐率大,故310性能高于T4性能,性能达标。 + +对于batch1,310性能高于T4性能1.2倍,该模型放在Benchmark/cv/classification目录下。 + diff --git a/ACL_PyTorch/contrib/cv/super_resolution/RCAN/test/README.md b/ACL_PyTorch/contrib/cv/super_resolution/RCAN/test/README.md index 9ac8ecec1d..895b5390a5 100644 --- a/ACL_PyTorch/contrib/cv/super_resolution/RCAN/test/README.md +++ b/ACL_PyTorch/contrib/cv/super_resolution/RCAN/test/README.md @@ -1,26 +1,26 @@ -环境准备: - -1.数据集路径 -数据集统一放在/root/datasets/或/opt/npu/ -本模型数据集放在/root/datasets/ - -2.进入工作目录 -cd RCAN - -3.安装必要的依赖 -pip3.7 install -r requirements.txt - -4.获取模型代码 -git clone https://github.com/yulunzhang/RCAN - -5.如果使用补丁文件修改了模型代码则将补丁打入模型代码,如果需要引用模型代码仓的类或函数通过sys.path.append()添加搜索路径。 - -5.获取权重文件 -[RCAN 预训练pth权重文件](https://pan.baidu.com/s/1bkoJKmdOcvLhOFXHVkFlKA) - -7.获取benchmark工具 -将benchmark.x86_64放在当前目录 - -8.310上执行,执行时确保device空闲 -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets +环境准备: + +1.数据集路径 +数据集统一放在/root/datasets/或/opt/npu/ +本模型数据集放在/root/datasets/ + +2.进入工作目录 +cd RCAN + +3.安装必要的依赖 +pip3.7 install -r requirements.txt + +4.获取模型代码 +git clone https://github.com/yulunzhang/RCAN + +5.如果使用补丁文件修改了模型代码则将补丁打入模型代码,如果需要引用模型代码仓的类或函数通过sys.path.append()添加搜索路径。 + +5.获取权重文件 +[RCAN 预训练pth权重文件](https://pan.baidu.com/s/1bkoJKmdOcvLhOFXHVkFlKA) + +7.获取benchmark工具 +将benchmark.x86_64放在当前目录 + +8.310上执行,执行时确保device空闲 +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets diff --git a/ACL_PyTorch/contrib/cv/super_resolution/RCAN/test/parse.py b/ACL_PyTorch/contrib/cv/super_resolution/RCAN/test/parse.py index 21ac0dab63..86e265cb06 100644 --- a/ACL_PyTorch/contrib/cv/super_resolution/RCAN/test/parse.py +++ b/ACL_PyTorch/contrib/cv/super_resolution/RCAN/test/parse.py @@ -1,33 +1,33 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as fp: - content = json.load(fp) - PSNR = content['PSNR'] - SSIM = content['SSIM'] - print('om {} PSNR:{} SSIM:{}'.format(result_json.split('_')[1].split('.')[0], PSNR, SSIM)) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as fp: + content = json.load(fp) + PSNR = content['PSNR'] + SSIM = content['SSIM'] + print('om {} PSNR:{} SSIM:{}'.format(result_json.split('_')[1].split('.')[0], PSNR, SSIM)) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/super_resolution/RDN/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/super_resolution/RDN/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/ACL_PyTorch/contrib/cv/super_resolution/RDN/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/super_resolution/RDN/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/super_resolution/RDN/test/README.md b/ACL_PyTorch/contrib/cv/super_resolution/RDN/test/README.md index f3fc08cb2b..bcf77d3efe 100644 --- a/ACL_PyTorch/contrib/cv/super_resolution/RDN/test/README.md +++ b/ACL_PyTorch/contrib/cv/super_resolution/RDN/test/README.md @@ -1,52 +1,52 @@ -## RDN模型PyTorch离线推理指导 - -### 1 环境准备 - -1. 安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 - - ```python - pip3.7 install -r requirements.txt - ``` - -2. 获取开源模型代码 - - ``` - git clone https://github.com/yjn870/RDN-pytorch -b master - ``` - - 开源模型代码仓没有安装脚本,可以通过sys.path.append(r"./RDN-pytorch")添加搜索路径,然后在pth2onnx脚本中就可以引用模型代码的函数或类 - -3. 获取权重文件 - - [RDN_x2预训练pth权重文件](https://www.dropbox.com/s/pd52pkmaik1ri0h/rdn_x2.pth?dl=0) - -4. 数据集 - - 开源代码仓只提供了h5格式的Set5数据集,由于代码仓评测精度的脚本采用png格式的图片作为输入,可通过[Set5](https://github.com/hengchuan/RDN-TensorFlow/tree/master/Test/Set5)下载png格式的Set5数据集,并将文件夹重命名为set5,数据集放在/root/datasets目录 - -5. 获取benchmark工具 - - 将benchmark.x86_64放到当前目录 - -6. TransposeD算子性能优化 - - 由于om模型中存在低性能的TransposeD算子,通过添加白名单使用高性能的Transpose算子。/usr/local/Ascend/ascend-toolkit/latest/x86_64-linux/opp/op_impl/built-in/ai_core/tbe/impl/dynamic/transpose.py里添加shape白名单:[1, 64, 2, 2, 114, 114] - -### 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 - -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/root/datasets -``` - - - -**评测结果:** - -| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | -| :-----: | :---------: | :-------------: | :--------: | :-------: | -| RDN bs1 | PSNR:38.18 | PSNR:38.27 | fps:25.393 | fps:29.577 | - +## RDN模型PyTorch离线推理指导 + +### 1 环境准备 + +1. 安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 + + ```python + pip3.7 install -r requirements.txt + ``` + +2. 获取开源模型代码 + + ``` + git clone https://github.com/yjn870/RDN-pytorch -b master + ``` + + 开源模型代码仓没有安装脚本,可以通过sys.path.append(r"./RDN-pytorch")添加搜索路径,然后在pth2onnx脚本中就可以引用模型代码的函数或类 + +3. 获取权重文件 + + [RDN_x2预训练pth权重文件](https://www.dropbox.com/s/pd52pkmaik1ri0h/rdn_x2.pth?dl=0) + +4. 数据集 + + 开源代码仓只提供了h5格式的Set5数据集,由于代码仓评测精度的脚本采用png格式的图片作为输入,可通过[Set5](https://github.com/hengchuan/RDN-TensorFlow/tree/master/Test/Set5)下载png格式的Set5数据集,并将文件夹重命名为set5,数据集放在/root/datasets目录 + +5. 获取benchmark工具 + + 将benchmark.x86_64放到当前目录 + +6. TransposeD算子性能优化 + + 由于om模型中存在低性能的TransposeD算子,通过添加白名单使用高性能的Transpose算子。/usr/local/Ascend/ascend-toolkit/latest/x86_64-linux/opp/op_impl/built-in/ai_core/tbe/impl/dynamic/transpose.py里添加shape白名单:[1, 64, 2, 2, 114, 114] + +### 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 + +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/root/datasets +``` + + + +**评测结果:** + +| 模型 | 官网pth精度 | 310离线推理精度 | 基准性能 | 310性能 | +| :-----: | :---------: | :-------------: | :--------: | :-------: | +| RDN bs1 | PSNR:38.18 | PSNR:38.27 | fps:25.393 | fps:29.577 | + - 因Set5数据集只有5张图片,因此仅使用了bs1进行评测。 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/README.md b/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/README.md index e37cba67a5..c3f42ecb9b 100644 --- a/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/README.md +++ b/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/README.md @@ -1,49 +1,49 @@ -# Real-ESRGAN-baseline模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 -``` -pip3.7 install -r requirements.txt -``` - -2.获取与安装开源模型代码 -``` -git clone https://github.com/xinntao/Real-ESRGAN.git -cd Real-ESRGAN -git reset c9023b3d7a5b711b0505a3e39671e3faab9de1fe --hard -``` - -3.获取权重文件 - -将权重文件[RealESRGAN_x4plus.pth](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth)放到experiments/pretrained_models/目录 -``` - mkdir -p experiments/pretrained_models - wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth -P experiments/pretrained_models -``` - -4.数据集 -获取推理数据集:推理数据集代码仓已提供,并且放置在代码仓./Real-ESRGAN/inputs目录 - -5.[获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) -将benchmark.x86_64或benchmark.aarch64放到当前工作目录 - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=./Real-ESRGAN -``` - **评测结果:** -| 模型 | 基准性能 | 310性能 | -| :------: | :------: | :------: | -| Real-ESRGAN bs1 | 55.132fps | 139.502fps | -| Real-ESRGAN bs16 | 72.923fps | 117.636fps | - -备注: -加上TEST.NECK_FEAT "('before')" TEST.FEAT_NORM "('no')"导出的onnx可以进行离线推理 -不加TEST.NECK_FEAT "('before')" TEST.FEAT_NORM "('no')"导出的onnx转换的om精度与官网精度一致 - - - +# Real-ESRGAN-baseline模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 +``` +pip3.7 install -r requirements.txt +``` + +2.获取与安装开源模型代码 +``` +git clone https://github.com/xinntao/Real-ESRGAN.git +cd Real-ESRGAN +git reset c9023b3d7a5b711b0505a3e39671e3faab9de1fe --hard +``` + +3.获取权重文件 + +将权重文件[RealESRGAN_x4plus.pth](https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth)放到experiments/pretrained_models/目录 +``` + mkdir -p experiments/pretrained_models + wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth -P experiments/pretrained_models +``` + +4.数据集 +获取推理数据集:推理数据集代码仓已提供,并且放置在代码仓./Real-ESRGAN/inputs目录 + +5.[获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) +将benchmark.x86_64或benchmark.aarch64放到当前工作目录 + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=./Real-ESRGAN +``` + **评测结果:** +| 模型 | 基准性能 | 310性能 | +| :------: | :------: | :------: | +| Real-ESRGAN bs1 | 55.132fps | 139.502fps | +| Real-ESRGAN bs16 | 72.923fps | 117.636fps | + +备注: +加上TEST.NECK_FEAT "('before')" TEST.FEAT_NORM "('no')"导出的onnx可以进行离线推理 +不加TEST.NECK_FEAT "('before')" TEST.FEAT_NORM "('no')"导出的onnx转换的om精度与官网精度一致 + + + diff --git a/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/Real-ESRGAN_postprocess.py b/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/Real-ESRGAN_postprocess.py index a420e1ef31..c27bc47051 100644 --- a/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/Real-ESRGAN_postprocess.py +++ b/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/Real-ESRGAN_postprocess.py @@ -1,16 +1,16 @@ -# Copyright 2021 Huawei Technologies Co., Ltd +# Copyright 2021 Huawei Technologies Co., Ltd # -# 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. +# 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 numpy as np import matplotlib diff --git a/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/Real-ESRGAN_preprocess.py b/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/Real-ESRGAN_preprocess.py index 7bd8d21b14..a6b0c71b97 100644 --- a/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/Real-ESRGAN_preprocess.py +++ b/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/Real-ESRGAN_preprocess.py @@ -1,17 +1,17 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os from PIL import Image from torchvision.transforms import transforms diff --git a/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/get_dataset_info.py b/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/get_dataset_info.py index 7ff00e26a9..3024744fe8 100644 --- a/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/get_dataset_info.py +++ b/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/get_dataset_info.py @@ -1,63 +1,63 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import cv2 -from glob import glob - - -def get_bin_info(file_path, info_name, width, height): - bin_images = glob(os.path.join(file_path, '*.bin')) - print(bin_images) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_images): - content = ' '.join([str(index), img, width, height]) - file.write(content) - file.write('\n') - - -def get_jpg_info(file_path, info_name): - extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] - image_names = [] - for extension in extensions: - image_names.append(glob(os.path.join(file_path, '*.' + extension))) - with open(info_name, 'w') as file: - for image_name in image_names: - if len(image_name) == 0: - continue - else: - for index, img in enumerate(image_name): - img_cv = cv2.imread(img) - shape = img_cv.shape - width, height = shape[1], shape[0] - content = ' '.join([str(index), img, str(width), str(height)]) - file.write(content) - file.write('\n') - - -if __name__ == '__main__': - file_type = sys.argv[1] - file_path = sys.argv[2] - info_name = sys.argv[3] - - if file_type == 'bin': - - width = sys.argv[4] - height = sys.argv[5] - assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' - get_bin_info(file_path, info_name, width, height) - elif file_type == 'jpg': - assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import cv2 +from glob import glob + + +def get_bin_info(file_path, info_name, width, height): + bin_images = glob(os.path.join(file_path, '*.bin')) + print(bin_images) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_images): + content = ' '.join([str(index), img, width, height]) + file.write(content) + file.write('\n') + + +def get_jpg_info(file_path, info_name): + extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] + image_names = [] + for extension in extensions: + image_names.append(glob(os.path.join(file_path, '*.' + extension))) + with open(info_name, 'w') as file: + for image_name in image_names: + if len(image_name) == 0: + continue + else: + for index, img in enumerate(image_name): + img_cv = cv2.imread(img) + shape = img_cv.shape + width, height = shape[1], shape[0] + content = ' '.join([str(index), img, str(width), str(height)]) + file.write(content) + file.write('\n') + + +if __name__ == '__main__': + file_type = sys.argv[1] + file_path = sys.argv[2] + info_name = sys.argv[3] + + if file_type == 'bin': + + width = sys.argv[4] + height = sys.argv[5] + assert len(sys.argv) == 6, 'The number of input parameters must be equal to 5' + get_bin_info(file_path, info_name, width, height) + elif file_type == 'jpg': + assert len(sys.argv) == 4, 'The number of input parameters must be equal to 3' get_jpg_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/modelzoo_level.txt index 9e95396651..27e6c78b37 100644 --- a/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:POK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/test/parse.py b/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/test/parse.py index c3cc8bf85b..83170a3707 100644 --- a/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/test/parse.py +++ b/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN/test/parse.py @@ -1,26 +1,26 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list=re.split('=|,',content) - fps = float(txt_data_list[1].replace('samples/s', '')) * 4 +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list=re.split('=|,',content) + fps = float(txt_data_list[1].replace('samples/s', '')) * 4 print('310 {} fps:{}'.format(re.split('-|_',result_txt)[4], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/super_resolution/SRCNN/LICENSE b/ACL_PyTorch/contrib/cv/super_resolution/SRCNN/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/ACL_PyTorch/contrib/cv/super_resolution/SRCNN/LICENSE +++ b/ACL_PyTorch/contrib/cv/super_resolution/SRCNN/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/super_resolution/SRCNN/requirements.txt b/ACL_PyTorch/contrib/cv/super_resolution/SRCNN/requirements.txt index 399dbfed08..fbd453de26 100644 --- a/ACL_PyTorch/contrib/cv/super_resolution/SRCNN/requirements.txt +++ b/ACL_PyTorch/contrib/cv/super_resolution/SRCNN/requirements.txt @@ -1,6 +1,6 @@ -torch == 1.5.0 -torchvision == 0.6.0 -onnx == 1.9.0 -numpy == 1.19.2 -Pillow == 8.2.0 +torch == 1.5.0 +torchvision == 0.6.0 +onnx == 1.9.0 +numpy == 1.19.2 +Pillow == 8.2.0 opencv-python == 4.5.2 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/super_resolution/SRCNN/test/parse.py b/ACL_PyTorch/contrib/cv/super_resolution/SRCNN/test/parse.py index b9c74f41d7..82af69cd18 100644 --- a/ACL_PyTorch/contrib/cv/super_resolution/SRCNN/test/parse.py +++ b/ACL_PyTorch/contrib/cv/super_resolution/SRCNN/test/parse.py @@ -1,32 +1,32 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] - print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + tops = [i.get('value') for i in json.loads(content).get('value') if 'Top' in i.get('key')] + print('om {} top1:{} top5:{}'.format(result_json.split('_')[1].split('.')[0], tops[0], tops[4])) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/tracking/SiamFC/LICENSE b/ACL_PyTorch/contrib/cv/tracking/SiamFC/LICENSE index b1fac45f02..989e2c59e9 100644 --- a/ACL_PyTorch/contrib/cv/tracking/SiamFC/LICENSE +++ b/ACL_PyTorch/contrib/cv/tracking/SiamFC/LICENSE @@ -1,201 +1,201 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/tracking/SiamFC/README.md b/ACL_PyTorch/contrib/cv/tracking/SiamFC/README.md index fcdb28c367..0e15dcde5c 100644 --- a/ACL_PyTorch/contrib/cv/tracking/SiamFC/README.md +++ b/ACL_PyTorch/contrib/cv/tracking/SiamFC/README.md @@ -1,50 +1,50 @@ -# SiamFC模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 - -``` -pip3.7 install -r requirements.txt -``` - -2.获取,修改与安装开源模型代码 -``` -代码地址:https://github.com/HonglinChu/SiamTrackers/tree/master/2-SiamFC/SiamFC-VID -论文地址:https://arxiv.org/pdf/1606.09549.pdf -``` -3.获取权重文件 - -采用Ascend910上训练得到的权重文件[siamfc.pth](https://pan.baidu.com/s/1N3Igj4ZgntjRevsGA5xOTQ),提取码:4i4l,放置于本代码仓./pth目录下 - -4.数据集 -[获取OTB2015数据集]([Visual Tracker Benchmark (hanyang.ac.kr)](http://cvlab.hanyang.ac.kr/tracker_benchmark/datasets.html)),并重命名为OTB,默认存放在/opt/npu目录下 - -5.[获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) -将benchmark.x86_64或benchmark.aarch64放到当前目录 - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh --datasets_path=/opt/npu -``` -> datasets_path参数根据数据集实际的存放位置而定,例如:OTB数据集存放位置为/opt/npu/OTB,则应设置参数--datasets_path=/opt/npu - - **评测结果:** - -| 模型 | pth在线推理精度 | 310离线推理精度 | -| :--------: | :------------------------------------------: | :------------------------------------------: | -| siamfc_bs1 | success_score: 0.576 precision_score: 0.767 | success_score: 0.571 precision_score: 0.760 | - -| 模型 | Benchmark性能 | 310性能 | -| :------: | :------: | :------: | -| exemplar_bs1 | 4240fps | 5677fps | -| search_bs1 | 738fps | 862fps | - -> 由于该模型无法进行常规的离线测试,因而改为对测试集的每一帧进行测试,exemplar_bs1和search_bs1分别对应模型中的两个分支,它们所进行的操作不同。 -> -> siamfc_bs1由exemplar_bs1和search_bs1这两部分组成,在评测精度时给出siamfc_bs1的精度,在评测性能时分别给出exemplar_bs1和search_bs1的性能。 - - +# SiamFC模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 + +``` +pip3.7 install -r requirements.txt +``` + +2.获取,修改与安装开源模型代码 +``` +代码地址:https://github.com/HonglinChu/SiamTrackers/tree/master/2-SiamFC/SiamFC-VID +论文地址:https://arxiv.org/pdf/1606.09549.pdf +``` +3.获取权重文件 + +采用Ascend910上训练得到的权重文件[siamfc.pth](https://pan.baidu.com/s/1N3Igj4ZgntjRevsGA5xOTQ),提取码:4i4l,放置于本代码仓./pth目录下 + +4.数据集 +[获取OTB2015数据集]([Visual Tracker Benchmark (hanyang.ac.kr)](http://cvlab.hanyang.ac.kr/tracker_benchmark/datasets.html)),并重命名为OTB,默认存放在/opt/npu目录下 + +5.[获取benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer) +将benchmark.x86_64或benchmark.aarch64放到当前目录 + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh --datasets_path=/opt/npu +``` +> datasets_path参数根据数据集实际的存放位置而定,例如:OTB数据集存放位置为/opt/npu/OTB,则应设置参数--datasets_path=/opt/npu + + **评测结果:** + +| 模型 | pth在线推理精度 | 310离线推理精度 | +| :--------: | :------------------------------------------: | :------------------------------------------: | +| siamfc_bs1 | success_score: 0.576 precision_score: 0.767 | success_score: 0.571 precision_score: 0.760 | + +| 模型 | Benchmark性能 | 310性能 | +| :------: | :------: | :------: | +| exemplar_bs1 | 4240fps | 5677fps | +| search_bs1 | 738fps | 862fps | + +> 由于该模型无法进行常规的离线测试,因而改为对测试集的每一帧进行测试,exemplar_bs1和search_bs1分别对应模型中的两个分支,它们所进行的操作不同。 +> +> siamfc_bs1由exemplar_bs1和search_bs1这两部分组成,在评测精度时给出siamfc_bs1的精度,在评测性能时分别给出exemplar_bs1和search_bs1的性能。 + + diff --git a/ACL_PyTorch/contrib/cv/tracking/SiamFC/get_perf_data.py b/ACL_PyTorch/contrib/cv/tracking/SiamFC/get_perf_data.py index c8c69d6b8b..c0d104efd2 100644 --- a/ACL_PyTorch/contrib/cv/tracking/SiamFC/get_perf_data.py +++ b/ACL_PyTorch/contrib/cv/tracking/SiamFC/get_perf_data.py @@ -1,64 +1,64 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import numpy as np -import torch -import sys - - -total = 5000 -exemplar_size = (1, 3, 127, 127) -search_size = (1, 9, 255, 255) - - -class ExperimentPerformance(object): - def __init__(self): - super(ExperimentPerformance, self).__init__() - - def run(self, savepath_e, savepath_s, infopath_e, infopath_s): - for i in range(total): - exemplar_input = torch.randn(exemplar_size) - exemplar_input = np.array(exemplar_input).astype(np.float32) - exemplar_name = "exemplar{}".format(i) - exemplar_path = os.path.join(savepath_e, exemplar_name + ".bin") - exemplar_input.tofile(exemplar_path) - with open(infopath_e, 'a') as file: - content = ' '.join([str(i), exemplar_path, str(127), str(127)]) - file.write(content) - file.write('\n') - - search_input = torch.randn(search_size) - search_input = np.array(search_input).astype(np.float32) - search_name = "search{}".format(i) - search_path = os.path.join(savepath_s, search_name + ".bin") - search_input.tofile(search_path) - with open(infopath_s, 'a') as file: - content = ' '.join([str(i), search_path, str(255), str(255)]) - file.write(content) - file.write('\n') - - -if __name__ == "__main__": - save_path_e = sys.argv[1] - save_path_s = sys.argv[2] - info_path_e = sys.argv[3] - info_path_s = sys.argv[4] - if not os.path.exists(save_path_e): - os.makedirs(save_path_e) - if not os.path.exists(save_path_s): - os.makedirs(save_path_s) - e = ExperimentPerformance() - e.run(save_path_e, save_path_s, info_path_e, info_path_s) - print("Data For Performance Ready.") +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import numpy as np +import torch +import sys + + +total = 5000 +exemplar_size = (1, 3, 127, 127) +search_size = (1, 9, 255, 255) + + +class ExperimentPerformance(object): + def __init__(self): + super(ExperimentPerformance, self).__init__() + + def run(self, savepath_e, savepath_s, infopath_e, infopath_s): + for i in range(total): + exemplar_input = torch.randn(exemplar_size) + exemplar_input = np.array(exemplar_input).astype(np.float32) + exemplar_name = "exemplar{}".format(i) + exemplar_path = os.path.join(savepath_e, exemplar_name + ".bin") + exemplar_input.tofile(exemplar_path) + with open(infopath_e, 'a') as file: + content = ' '.join([str(i), exemplar_path, str(127), str(127)]) + file.write(content) + file.write('\n') + + search_input = torch.randn(search_size) + search_input = np.array(search_input).astype(np.float32) + search_name = "search{}".format(i) + search_path = os.path.join(savepath_s, search_name + ".bin") + search_input.tofile(search_path) + with open(infopath_s, 'a') as file: + content = ' '.join([str(i), search_path, str(255), str(255)]) + file.write(content) + file.write('\n') + + +if __name__ == "__main__": + save_path_e = sys.argv[1] + save_path_s = sys.argv[2] + info_path_e = sys.argv[3] + info_path_s = sys.argv[4] + if not os.path.exists(save_path_e): + os.makedirs(save_path_e) + if not os.path.exists(save_path_s): + os.makedirs(save_path_s) + e = ExperimentPerformance() + e.run(save_path_e, save_path_s, info_path_e, info_path_s) + print("Data For Performance Ready.") diff --git a/ACL_PyTorch/contrib/cv/tracking/SiamFC/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/tracking/SiamFC/modelzoo_level.txt index 51b74557c1..5c956b09db 100644 --- a/ACL_PyTorch/contrib/cv/tracking/SiamFC/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/tracking/SiamFC/modelzoo_level.txt @@ -1,6 +1,6 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK -PerfStatus:OK -ModelConvert:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK +PerfStatus:OK +ModelConvert:OK QuantStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/tracking/SiamFC/prepostprocess.py b/ACL_PyTorch/contrib/cv/tracking/SiamFC/prepostprocess.py index e12937034e..930ab71b04 100644 --- a/ACL_PyTorch/contrib/cv/tracking/SiamFC/prepostprocess.py +++ b/ACL_PyTorch/contrib/cv/tracking/SiamFC/prepostprocess.py @@ -1,158 +1,158 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import cv2 -import torch -import torch.nn.functional as F -import numpy as np -from utils import ToTensor, get_exemplar_image, get_pyramid_instance_image -import struct - - -exemplar_size = 127 # exemplar size z -instance_size = 255 # instance size x -context_amount = 0.5 # context amount -num_scale = 3 # number of scales -scale_step = 1.0375 # scale step of instance image -scale_penalty = 0.9745 # scale penalty -scale_lr = 0.59 # scale learning rate -response_up_stride = 16 # response upsample stride -response_sz = 17 # response size -window_influence = 0.176 # window influence -total_stride = 8 # total stride of backbone - - -class PrePostProcess(object): - def __init__(self): - self.penalty = np.ones((num_scale)) * scale_penalty - self.penalty[num_scale // 2] = 1 # [0.9745, 1, 0.9745] - - # create cosine window upsample stride=2^4=16, heatmap 17x17 - self.interp_response_sz = response_up_stride * response_sz # 272=16x17 - self.cosine_window = self._cosine_window((self.interp_response_sz, self.interp_response_sz)) - - def _cosine_window(self, size): - """ - get the cosine window - """ - cos_window = np.hanning(int(size[0]))[:, np.newaxis].dot(np.hanning(int(size[1]))[np.newaxis, :]) - cos_window = cos_window.astype(np.float32) - cos_window /= np.sum(cos_window) - return cos_window - - def cropexemplar(self, frame, box, save_path, file_name): - """ - Args: - frame: an RGB image - box: one-based bounding box [x, y, width, height] - """ - self.bbox = (box[0] - 1, box[1] - 1, box[0] - 1 + box[2], box[1] - 1 + box[3]) # zero based x1,y1,x2,y2 - self.pos = np.array([box[0] - 1 + (box[2]) / 2, box[1] - 1 + (box[3]) / 2]) # zero based cx, cy, - self.target_sz = np.array([box[2], box[3]]) # zero based w, h - - # get exemplar img - self.img_mean = tuple(map(int, frame.mean(axis=(0, 1)))) - exemplar_img, scale_z, s_z = get_exemplar_image(frame, self.bbox, - exemplar_size, context_amount, self.img_mean) - - # create scales: 0.96, 1, 1.037 - self.scales = scale_step ** np.arange(np.ceil(num_scale / 2) - num_scale, - np.floor(num_scale / 2) + 1) - - # create s_x : instance is twice as large as exemplar - self.s_x = s_z + (instance_size - exemplar_size) / scale_z # s-x search_sz, s-z exemplar_sz - - # arbitrary scale saturation - self.min_s_x = 0.2 * self.s_x - self.max_s_x = 5 * self.s_x - - # get exemplar feature - # m1: use torchvision.transforms - # exemplar_img = self.transforms(exemplar_img)[None, :, :, :] # 1,3,127,127 - # m2: don't use torchvision.transforms - exemplar_img = ToTensor(exemplar_img) - img = np.array(exemplar_img).astype(np.float32) - path = os.path.join(save_path, file_name.split('.')[0].replace('/', '-') + ".bin") - img.tofile(path) - return path - - def cropsearch(self, frame, save_path, file_name): - size_x_scales = self.s_x * self.scales # multi-scale search - pyramid = get_pyramid_instance_image(frame, self.pos, instance_size, size_x_scales, self.img_mean) - # m1: use torchvision.transforms - # instance_imgs = torch.cat([self.transforms(x)[None, :, :, :] for x in pyramid], dim=0) # 3, 3, 255, 255 - # m2: don't use torchvision.transforms - instance_imgs = torch.cat([ToTensor(x) for x in pyramid], dim=1) # 3, 3, 255, 255 - img = np.array(instance_imgs).astype(np.float32) - path = os.path.join(save_path, file_name.split('.')[0].replace('/', '-') + ".bin") - img.tofile(path) - return path - - def postprocess(self, x_f, z_f): - # x_f:search z_f:exemplar - response_maps = F.conv2d(x_f, z_f, groups=3) - response_maps = response_maps.transpose(0, 1) - response_maps = response_maps.numpy().squeeze() # 3, 17, 17 - - response_maps_up = [cv2.resize(x, (self.interp_response_sz, self.interp_response_sz), cv2.INTER_CUBIC) - for x in response_maps] # upsample - - # get max score of each scale - max_score = np.array([x.max() for x in response_maps_up]) * self.penalty # penalty=[0.9745, 1, 0.9745] - - # penalty scale change - scale_idx = max_score.argmax() - response_map = response_maps_up[scale_idx] - response_map -= response_map.min() - response_map /= response_map.sum() - response_map = (1 - window_influence) * response_map + \ - window_influence * self.cosine_window - max_r, max_c = np.unravel_index(response_map.argmax(), response_map.shape) - # displacement in interpolation response - disp_response_interp = np.array([max_c, max_r]) - (self.interp_response_sz - 1) / 2. - # displacement in input, response_up_stride=16, total_stride=8 - disp_response_input = disp_response_interp * total_stride / response_up_stride - # displacement in frame - scale = self.scales[scale_idx] # - disp_response_frame = disp_response_input * (self.s_x * scale) / instance_size - # position in frame coordinates - self.pos += disp_response_frame - # scale damping and saturation - self.s_x *= ((1 - scale_lr) + scale_lr * scale) # update - self.s_x = max(self.min_s_x, min(self.max_s_x, self.s_x)) - self.target_sz = ((1 - scale_lr) + scale_lr * scale) * self.target_sz # update - - box = np.array([ - self.pos[0] + 1 - (self.target_sz[0]) / 2, - self.pos[1] + 1 - (self.target_sz[1]) / 2, - self.target_sz[0], self.target_sz[1]]) - - return box - - def file2tensor(self, filepath, shape): - size = os.path.getsize(filepath) - res = [] - L = int(size / 4) # float32, so 4bytes - binfile = open(filepath, 'rb') - for i in range(L): - data = binfile.read(4) - num = struct.unpack('f', data) - res.append(num[0]) - binfile.close() - - dim_res = np.array(res).reshape(shape) - tensor_res = torch.tensor(dim_res, dtype=torch.float32) - - return tensor_res +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import cv2 +import torch +import torch.nn.functional as F +import numpy as np +from utils import ToTensor, get_exemplar_image, get_pyramid_instance_image +import struct + + +exemplar_size = 127 # exemplar size z +instance_size = 255 # instance size x +context_amount = 0.5 # context amount +num_scale = 3 # number of scales +scale_step = 1.0375 # scale step of instance image +scale_penalty = 0.9745 # scale penalty +scale_lr = 0.59 # scale learning rate +response_up_stride = 16 # response upsample stride +response_sz = 17 # response size +window_influence = 0.176 # window influence +total_stride = 8 # total stride of backbone + + +class PrePostProcess(object): + def __init__(self): + self.penalty = np.ones((num_scale)) * scale_penalty + self.penalty[num_scale // 2] = 1 # [0.9745, 1, 0.9745] + + # create cosine window upsample stride=2^4=16, heatmap 17x17 + self.interp_response_sz = response_up_stride * response_sz # 272=16x17 + self.cosine_window = self._cosine_window((self.interp_response_sz, self.interp_response_sz)) + + def _cosine_window(self, size): + """ + get the cosine window + """ + cos_window = np.hanning(int(size[0]))[:, np.newaxis].dot(np.hanning(int(size[1]))[np.newaxis, :]) + cos_window = cos_window.astype(np.float32) + cos_window /= np.sum(cos_window) + return cos_window + + def cropexemplar(self, frame, box, save_path, file_name): + """ + Args: + frame: an RGB image + box: one-based bounding box [x, y, width, height] + """ + self.bbox = (box[0] - 1, box[1] - 1, box[0] - 1 + box[2], box[1] - 1 + box[3]) # zero based x1,y1,x2,y2 + self.pos = np.array([box[0] - 1 + (box[2]) / 2, box[1] - 1 + (box[3]) / 2]) # zero based cx, cy, + self.target_sz = np.array([box[2], box[3]]) # zero based w, h + + # get exemplar img + self.img_mean = tuple(map(int, frame.mean(axis=(0, 1)))) + exemplar_img, scale_z, s_z = get_exemplar_image(frame, self.bbox, + exemplar_size, context_amount, self.img_mean) + + # create scales: 0.96, 1, 1.037 + self.scales = scale_step ** np.arange(np.ceil(num_scale / 2) - num_scale, + np.floor(num_scale / 2) + 1) + + # create s_x : instance is twice as large as exemplar + self.s_x = s_z + (instance_size - exemplar_size) / scale_z # s-x search_sz, s-z exemplar_sz + + # arbitrary scale saturation + self.min_s_x = 0.2 * self.s_x + self.max_s_x = 5 * self.s_x + + # get exemplar feature + # m1: use torchvision.transforms + # exemplar_img = self.transforms(exemplar_img)[None, :, :, :] # 1,3,127,127 + # m2: don't use torchvision.transforms + exemplar_img = ToTensor(exemplar_img) + img = np.array(exemplar_img).astype(np.float32) + path = os.path.join(save_path, file_name.split('.')[0].replace('/', '-') + ".bin") + img.tofile(path) + return path + + def cropsearch(self, frame, save_path, file_name): + size_x_scales = self.s_x * self.scales # multi-scale search + pyramid = get_pyramid_instance_image(frame, self.pos, instance_size, size_x_scales, self.img_mean) + # m1: use torchvision.transforms + # instance_imgs = torch.cat([self.transforms(x)[None, :, :, :] for x in pyramid], dim=0) # 3, 3, 255, 255 + # m2: don't use torchvision.transforms + instance_imgs = torch.cat([ToTensor(x) for x in pyramid], dim=1) # 3, 3, 255, 255 + img = np.array(instance_imgs).astype(np.float32) + path = os.path.join(save_path, file_name.split('.')[0].replace('/', '-') + ".bin") + img.tofile(path) + return path + + def postprocess(self, x_f, z_f): + # x_f:search z_f:exemplar + response_maps = F.conv2d(x_f, z_f, groups=3) + response_maps = response_maps.transpose(0, 1) + response_maps = response_maps.numpy().squeeze() # 3, 17, 17 + + response_maps_up = [cv2.resize(x, (self.interp_response_sz, self.interp_response_sz), cv2.INTER_CUBIC) + for x in response_maps] # upsample + + # get max score of each scale + max_score = np.array([x.max() for x in response_maps_up]) * self.penalty # penalty=[0.9745, 1, 0.9745] + + # penalty scale change + scale_idx = max_score.argmax() + response_map = response_maps_up[scale_idx] + response_map -= response_map.min() + response_map /= response_map.sum() + response_map = (1 - window_influence) * response_map + \ + window_influence * self.cosine_window + max_r, max_c = np.unravel_index(response_map.argmax(), response_map.shape) + # displacement in interpolation response + disp_response_interp = np.array([max_c, max_r]) - (self.interp_response_sz - 1) / 2. + # displacement in input, response_up_stride=16, total_stride=8 + disp_response_input = disp_response_interp * total_stride / response_up_stride + # displacement in frame + scale = self.scales[scale_idx] # + disp_response_frame = disp_response_input * (self.s_x * scale) / instance_size + # position in frame coordinates + self.pos += disp_response_frame + # scale damping and saturation + self.s_x *= ((1 - scale_lr) + scale_lr * scale) # update + self.s_x = max(self.min_s_x, min(self.max_s_x, self.s_x)) + self.target_sz = ((1 - scale_lr) + scale_lr * scale) * self.target_sz # update + + box = np.array([ + self.pos[0] + 1 - (self.target_sz[0]) / 2, + self.pos[1] + 1 - (self.target_sz[1]) / 2, + self.target_sz[0], self.target_sz[1]]) + + return box + + def file2tensor(self, filepath, shape): + size = os.path.getsize(filepath) + res = [] + L = int(size / 4) # float32, so 4bytes + binfile = open(filepath, 'rb') + for i in range(L): + data = binfile.read(4) + num = struct.unpack('f', data) + res.append(num[0]) + binfile.close() + + dim_res = np.array(res).reshape(shape) + tensor_res = torch.tensor(dim_res, dtype=torch.float32) + + return tensor_res diff --git a/ACL_PyTorch/contrib/cv/tracking/SiamFC/pth2onnx.py b/ACL_PyTorch/contrib/cv/tracking/SiamFC/pth2onnx.py index d864e0ba06..e68b3bce6c 100644 --- a/ACL_PyTorch/contrib/cv/tracking/SiamFC/pth2onnx.py +++ b/ACL_PyTorch/contrib/cv/tracking/SiamFC/pth2onnx.py @@ -1,118 +1,118 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import torch -import torch.nn as nn -import torch.onnx -import torch.nn.functional as F - - -response_scale = 1e-3 - - -class SiameseAlexNet(nn.Module): - def __init__(self): - super(SiameseAlexNet, self).__init__() - self.features = nn.Sequential( - nn.Conv2d(3, 96, 11, 2), - nn.BatchNorm2d(96), - nn.ReLU(inplace=True), - nn.MaxPool2d(3, 2), - nn.Conv2d(96, 256, 5, 1, groups=2), - nn.BatchNorm2d(256), - nn.ReLU(inplace=True), - nn.MaxPool2d(3, 2), - nn.Conv2d(256, 384, 3, 1), - nn.BatchNorm2d(384), - nn.ReLU(inplace=True), - nn.Conv2d(384, 384, 3, 1, groups=2), - nn.BatchNorm2d(384), - nn.ReLU(inplace=True), - nn.Conv2d(384, 256, 3, 1, groups=2) - ) - self.corr_bias = nn.Parameter(torch.zeros(1)) - self.exemplar = None - - def init_weights(self): - for m in self.modules(): - if isinstance(m, nn.Conv2d): - nn.init.kaiming_normal_(m.weight.data, mode='fan_out', nonlinearity='relu') - elif isinstance(m, nn.BatchNorm2d): - m.weight.data.fill_(1) - m.bias.data.zero_() - - def forward(self, x): - exemplar, instance = x # x = ( exemplar, instance ) - # train - if exemplar is not None and instance is not None: # - batch_size = exemplar.shape[0] # - exemplar = self.features(exemplar) # batch, 256, 6, 6 - instance = self.features(instance) # batch, 256, 20, 20 - N, C, H, W = instance.shape - instance = instance.view(1, -1, H, W) - score = F.conv2d(instance, exemplar, groups=N) * response_scale + self.corr_bias - return score.transpose(0, 1) - # test(first frame) - elif exemplar is not None and instance is None: - self.exemplar = self.features(exemplar) # 1, 256, 6, 6 - self.exemplar = torch.cat([self.exemplar for _ in range(3)], dim=0) # 3, 256, 6, 6 - return self.exemplar - # test(not first frame) - else: - # inference used we don't need to scale the response or add bias - _, _, H, W = instance.shape - instance = instance.reshape(3, 3, H, W) - instance = self.features(instance) # 3 scale - N, C, H, W = instance.shape - instance = instance.view(1, N*C, H, W) # 1, NxC, H, W - # score = F.conv2d(instance, self.exemplar, groups=N) - # return score.transpose(0, 1) - return instance - - -def exemplar_convert(input_file, output_file): - model = SiameseAlexNet() - model.load_state_dict(torch.load(input_file, map_location='cpu')) - model.eval() - - input_names = ["actual_input_1"] - output_names = ["output1"] - input1 = torch.randn(1, 3, 127, 127) - input2 = None - dummy_input = [input1, input2] - torch.onnx.export(model, dummy_input, output_file, input_names=input_names, output_names=output_names, - opset_version=11) - - -def search_convert(input_file, output_file): - model = SiameseAlexNet() - model.load_state_dict(torch.load(input_file, map_location='cpu')) - model.eval() - - input_names = ["actual_input_1"] - output_names = ["output1"] - input1 = None - input2 = torch.randn(1, 9, 255, 255) - dummy_input = [input1, input2] - torch.onnx.export(model, dummy_input, output_file, input_names=input_names, output_names=output_names, - opset_version=11) - - -if __name__ == "__main__": - input_file = sys.argv[1] - output_file_exemplar = sys.argv[2] - output_file_search = sys.argv[3] - exemplar_convert(input_file, output_file_exemplar) - search_convert(input_file, output_file_search) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import torch +import torch.nn as nn +import torch.onnx +import torch.nn.functional as F + + +response_scale = 1e-3 + + +class SiameseAlexNet(nn.Module): + def __init__(self): + super(SiameseAlexNet, self).__init__() + self.features = nn.Sequential( + nn.Conv2d(3, 96, 11, 2), + nn.BatchNorm2d(96), + nn.ReLU(inplace=True), + nn.MaxPool2d(3, 2), + nn.Conv2d(96, 256, 5, 1, groups=2), + nn.BatchNorm2d(256), + nn.ReLU(inplace=True), + nn.MaxPool2d(3, 2), + nn.Conv2d(256, 384, 3, 1), + nn.BatchNorm2d(384), + nn.ReLU(inplace=True), + nn.Conv2d(384, 384, 3, 1, groups=2), + nn.BatchNorm2d(384), + nn.ReLU(inplace=True), + nn.Conv2d(384, 256, 3, 1, groups=2) + ) + self.corr_bias = nn.Parameter(torch.zeros(1)) + self.exemplar = None + + def init_weights(self): + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight.data, mode='fan_out', nonlinearity='relu') + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def forward(self, x): + exemplar, instance = x # x = ( exemplar, instance ) + # train + if exemplar is not None and instance is not None: # + batch_size = exemplar.shape[0] # + exemplar = self.features(exemplar) # batch, 256, 6, 6 + instance = self.features(instance) # batch, 256, 20, 20 + N, C, H, W = instance.shape + instance = instance.view(1, -1, H, W) + score = F.conv2d(instance, exemplar, groups=N) * response_scale + self.corr_bias + return score.transpose(0, 1) + # test(first frame) + elif exemplar is not None and instance is None: + self.exemplar = self.features(exemplar) # 1, 256, 6, 6 + self.exemplar = torch.cat([self.exemplar for _ in range(3)], dim=0) # 3, 256, 6, 6 + return self.exemplar + # test(not first frame) + else: + # inference used we don't need to scale the response or add bias + _, _, H, W = instance.shape + instance = instance.reshape(3, 3, H, W) + instance = self.features(instance) # 3 scale + N, C, H, W = instance.shape + instance = instance.view(1, N*C, H, W) # 1, NxC, H, W + # score = F.conv2d(instance, self.exemplar, groups=N) + # return score.transpose(0, 1) + return instance + + +def exemplar_convert(input_file, output_file): + model = SiameseAlexNet() + model.load_state_dict(torch.load(input_file, map_location='cpu')) + model.eval() + + input_names = ["actual_input_1"] + output_names = ["output1"] + input1 = torch.randn(1, 3, 127, 127) + input2 = None + dummy_input = [input1, input2] + torch.onnx.export(model, dummy_input, output_file, input_names=input_names, output_names=output_names, + opset_version=11) + + +def search_convert(input_file, output_file): + model = SiameseAlexNet() + model.load_state_dict(torch.load(input_file, map_location='cpu')) + model.eval() + + input_names = ["actual_input_1"] + output_names = ["output1"] + input1 = None + input2 = torch.randn(1, 9, 255, 255) + dummy_input = [input1, input2] + torch.onnx.export(model, dummy_input, output_file, input_names=input_names, output_names=output_names, + opset_version=11) + + +if __name__ == "__main__": + input_file = sys.argv[1] + output_file_exemplar = sys.argv[2] + output_file_search = sys.argv[3] + exemplar_convert(input_file, output_file_exemplar) + search_convert(input_file, output_file_search) diff --git a/ACL_PyTorch/contrib/cv/tracking/SiamFC/requirements.txt b/ACL_PyTorch/contrib/cv/tracking/SiamFC/requirements.txt index fb20cd3250..196f844119 100644 --- a/ACL_PyTorch/contrib/cv/tracking/SiamFC/requirements.txt +++ b/ACL_PyTorch/contrib/cv/tracking/SiamFC/requirements.txt @@ -1,8 +1,8 @@ -torch==1.9.0 -torchvision==0.10.0 -onnx==1.9.0 -numpy==1.19.2 -opencv-python==4.5.2.54 -pillow==8.2.0 -six==1.15.0 +torch==1.9.0 +torchvision==0.10.0 +onnx==1.9.0 +numpy==1.19.2 +opencv-python==4.5.2.54 +pillow==8.2.0 +six==1.15.0 tqdm==4.61.2 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/tracking/SiamFC/test/parse.py b/ACL_PyTorch/contrib/cv/tracking/SiamFC/test/parse.py index 7cf6d0faa4..e64ee7ea69 100644 --- a/ACL_PyTorch/contrib/cv/tracking/SiamFC/test/parse.py +++ b/ACL_PyTorch/contrib/cv/tracking/SiamFC/test/parse.py @@ -1,25 +1,25 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[7].replace('samples/s', '')) * 4 - print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[7].replace('samples/s', '')) * 4 + print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) diff --git a/ACL_PyTorch/contrib/cv/tracking/SiamFC/wholeprocess.py b/ACL_PyTorch/contrib/cv/tracking/SiamFC/wholeprocess.py index 2bd05d5958..9fd127d256 100644 --- a/ACL_PyTorch/contrib/cv/tracking/SiamFC/wholeprocess.py +++ b/ACL_PyTorch/contrib/cv/tracking/SiamFC/wholeprocess.py @@ -1,426 +1,426 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import glob -import numpy as np -import io -import six -from itertools import chain -import cv2 -import json -import sys -import multiprocessing -sys.path.append(os.getcwd()) -from prepostprocess import PrePostProcess -from utils import rect_iou, center_error - - -deviceid = 0 - - -class OTB(object): - r"""`OTB `_ Datasets. - - Publication: - ``Object Tracking Benchmark``, Y. Wu, J. Lim and M.-H. Yang, IEEE TPAMI 2015. - - Args: - root_dir (string): Root directory of dataset where sequence - folders exist. - version (integer or string): Specify the benchmark version, specify as one of - ``2013``, ``2015``, ``tb50`` and ``tb100``. - """ - __otb13_seqs = ['Basketball', 'Bolt', 'Boy', 'Car4', 'CarDark', - 'CarScale', 'Coke', 'Couple', 'Crossing', 'David', - 'David2', 'David3', 'Deer', 'Dog1', 'Doll', 'Dudek', - 'FaceOcc1', 'FaceOcc2', 'Fish', 'FleetFace', - 'Football', 'Football1', 'Freeman1', 'Freeman3', - 'Freeman4', 'Girl', 'Ironman', 'Jogging', 'Jumping', - 'Lemming', 'Liquor', 'Matrix', 'Mhyang', 'MotorRolling', - 'MountainBike', 'Shaking', 'Singer1', 'Singer2', - 'Skating1', 'Skiing', 'Soccer', 'Subway', 'Suv', - 'Sylvester', 'Tiger1', 'Tiger2', 'Trellis', 'Walking', - 'Walking2', 'Woman'] - - __tb50_seqs = ['Basketball', 'Biker', 'Bird1', 'BlurBody', 'BlurCar2', - 'BlurFace', 'BlurOwl', 'Bolt', 'Box', 'Car1', 'Car4', - 'CarDark', 'CarScale', 'ClifBar', 'Couple', 'Crowds', - 'David', 'Deer', 'Diving', 'DragonBaby', 'Dudek', - 'Football', 'Freeman4', 'Girl', 'Human3', 'Human4', - 'Human6', 'Human9', 'Ironman', 'Jump', 'Jumping', - 'Liquor', 'Matrix', 'MotorRolling', 'Panda', 'RedTeam', - 'Shaking', 'Singer2', 'Skating1', 'Skating2', 'Skiing', - 'Soccer', 'Surfer', 'Sylvester', 'Tiger2', 'Trellis', - 'Walking', 'Walking2', 'Woman'] - - __tb100_seqs = ['Bird2', 'BlurCar1', 'BlurCar3', 'BlurCar4', 'Board', - 'Bolt2', 'Boy', 'Car2', 'Car24', 'Coke', 'Coupon', - 'Crossing', 'Dancer', 'Dancer2', 'David2', 'David3', - 'Dog', 'Dog1', 'Doll', 'FaceOcc1', 'FaceOcc2', 'Fish', - 'FleetFace', 'Football1', 'Freeman1', 'Freeman3', - 'Girl2', 'Gym', 'Human2', 'Human5', 'Human7', 'Human8', - 'Jogging', 'KiteSurf', 'Lemming', 'Man', 'Mhyang', - 'MountainBike', 'Rubik', 'Singer1', 'Skater', - 'Skater2', 'Subway', 'Suv', 'Tiger1', 'Toy', 'Trans', - 'Twinnings', 'Vase'] + __tb50_seqs - - __otb15_seqs = __tb100_seqs - - __version_dict = { - 2013: __otb13_seqs, - 2015: __otb15_seqs, - 'otb2013': __otb13_seqs, - 'otb2015': __otb15_seqs, - 'tb50': __tb50_seqs, - 'tb100': __tb100_seqs} - - def __init__(self, root_dir, version=2015): - super(OTB, self).__init__() - assert version in self.__version_dict - - self.root_dir = root_dir - self.version = version - self._check_integrity(root_dir, version) - valid_seqs = self.__version_dict[version] - self.anno_files = sorted(list(chain.from_iterable(glob.glob( - os.path.join(root_dir, s, 'groundtruth*.txt')) for s in valid_seqs))) - # remove empty annotation files - # (e.g. groundtruth_rect.1.txt of Human4) - self.anno_files = self._filter_files(self.anno_files) - self.seq_dirs = [os.path.dirname(f) for f in self.anno_files] - self.seq_names = [os.path.basename(d) for d in self.seq_dirs] - # rename repeated sequence names - # (e.g. Jogging and Skating2) - self.seq_names = self._rename_seqs(self.seq_names) - - def __getitem__(self, index): - r""" - Args: - index (integer or string): Index or name of a sequence. - - Returns: - tuple: (img_files, anno), where ``img_files`` is a list of - file names and ``anno`` is a N x 4 (rectangles) numpy array. - """ - if isinstance(index, six.string_types): - if not index in self.seq_names: - raise Exception('Sequence {} not found.'.format(index)) - index = self.seq_names.index(index) - - img_files = sorted(glob.glob( - os.path.join(self.seq_dirs[index], 'img/*.jpg'))) - - # special sequences - seq_name = self.seq_names[index] - if seq_name.lower() == 'david': - img_files = img_files[300 - 1:770] - elif seq_name.lower() == 'football1': - img_files = img_files[:74] - elif seq_name.lower() == 'freeman3': - img_files = img_files[:460] - elif seq_name.lower() == 'freeman4': - img_files = img_files[:283] - elif seq_name.lower() == 'diving': - img_files = img_files[:215] - - # to deal with different delimeters - with open(self.anno_files[index], 'r') as f: - anno = np.loadtxt(io.StringIO(f.read().replace(',', ' '))) - assert len(img_files) == len(anno) - assert anno.shape[1] == 4 - - return img_files, anno - - def __len__(self): - return len(self.seq_names) - - def _filter_files(self, filenames): - filtered_files = [] - for filename in filenames: - with open(filename, 'r') as f: - if f.read().strip() == '': - print('Warning: %s is empty.' % filename) - else: - filtered_files.append(filename) - - return filtered_files - - def _rename_seqs(self, seq_names): - # in case some sequences may have multiple targets - renamed_seqs = [] - for i, seq_name in enumerate(seq_names): - if seq_names.count(seq_name) == 1: - renamed_seqs.append(seq_name) - else: - ind = seq_names[:i + 1].count(seq_name) - renamed_seqs.append('%s.%d' % (seq_name, ind)) - - return renamed_seqs - - def _check_integrity(self, root_dir, version): - assert version in self.__version_dict - seq_names = self.__version_dict[version] - - if os.path.isdir(root_dir) and len(os.listdir(root_dir)) > 0: - # check each sequence folder - for seq_name in seq_names: - seq_dir = os.path.join(root_dir, seq_name) - if not os.path.isdir(seq_dir): - print('Warning: sequence %s not exists.' % seq_name) - else: - # dataset not exists - raise Exception('Dataset not found or corrupted. ' + - 'You can use download=True to download it.') - - -class ExperimentOTB(object): - """Experiment pipeline and evaluation toolkit for OTB dataset. - - Args: - root_dir (string): Root directory of OTB dataset. - version (integer or string): Specify the benchmark version, specify as one of - ``2013``, ``2015``, ``tb50`` and ``tb100``. Default is ``2015``. - result_dir (string, optional): Directory for storing tracking - results. Default is ``./results``. - report_dir (string, optional): Directory for storing performance - evaluation results. Default is ``./reports``. - """ - def __init__(self, root_dir, version=2015, - result_dir='results', report_dir='reports'): - super(ExperimentOTB, self).__init__() - self.dataset = OTB(root_dir, version) - self.result_dir = os.path.join(result_dir, 'OTB' + str(version)) - self.report_dir = os.path.join(report_dir, 'OTB' + str(version)) - # as nbins_iou increases, the success score - # converges to the average overlap (AO) - self.nbins_iou = 21 - self.nbins_ce = 51 - - def getlendataset(self): - return len(self.dataset) - - def run(self, savepath, infopath, arch, idx): - # get the seq_name and information of files - img_files, anno = self.dataset[idx] - seq_name = self.dataset.seq_names[idx] - # generate directory for current seq - savepath = savepath + "/" + str(idx) - if not os.path.exists(savepath): - os.makedirs(savepath) - infopath = infopath + "/" + str(idx) + ".info" - # skip if result exist - record_file = os.path.join(self.result_dir, 'siamfc', '%s.txt' % seq_name) - if os.path.exists(record_file): - print('Found results of %s, skipping' % seq_name) - return - frame_num = len(img_files) - boxes = np.zeros((frame_num, 4)) - boxes[0] = anno[0, :] # x,y, w, h - times = np.zeros(frame_num) - - prepostpro = PrePostProcess() - for f, img_file in enumerate(img_files): - img = cv2.imread(img_file, cv2.IMREAD_COLOR) - if f == 0: - # Pre-process and generate bin - exemplar_path = prepostpro.cropexemplar(img, anno[0, :], savepath, img_file) - # get_info - with open(infopath, 'w') as file1: - content = ' '.join([str(0), '.'+exemplar_path, str(127), str(127)]) - file1.write(content) - file1.write('\n') - # infer - os.system('%s -model_type=vision -device_id=%d -batch_size=1 ' - '-om_path=s%/exemplar_bs1.om -input_text_path=%s ' - '-input_width=127 -input_height=127 -output_binary=True -useDvpp=False >/dev/null 2>&1' - % (benchmark_path, deviceid, om_path, infopath)) - # the exemplar has a result of 3*256*6*6 tensor - # read tensor from bin - filename = img_file.replace('/', '-').split('.')[0] + '_1.bin' - filename = 'result/dumpOutput_device' + str(deviceid) + '/' + filename - exemplar_feature = prepostpro.file2tensor(filename, (3, 256, 6, 6)) - else: - # Pre-process and generate bin - search_path = prepostpro.cropsearch(img, savepath, img_file) - # get_info - with open(infopath, 'w') as file2: - content = ' '.join([str(0), '.'+search_path, str(255), str(255)]) - file2.write(content) - file2.write('\n') - # infer - os.system('%s -model_type=vision -device_id=%d -batch_size=1 ' - '-om_path=%s/search_bs1.om -input_text_path=%s ' - '-input_width=255 -input_height=255 -output_binary=True -useDvpp=False >/dev/null 2>&1' - % (benchmark_path, deviceid, om_path, infopath)) - # the exemplar has a result of 1*768*22*22 tensor - # read tensor from bin - filename = img_file.replace('/', '-').split('.')[0] + '_1.bin' - filename = 'result/dumpOutput_device' + str(deviceid) + '/' + filename - search_feature = prepostpro.file2tensor(filename, (1, 768, 22, 22)) - # Post-process - boxes[f, :] = prepostpro.postprocess(search_feature, exemplar_feature) - times[f] = 1 - assert len(boxes) == len(anno) - # record results - self._record(record_file, boxes, times) - # delete useless data to save space - os.system('rm -rf %s/*' % savepath) - print("Results of %s finished!" % seq_name) - - def report(self, tracker_names): - - assert isinstance(tracker_names, (list, tuple)) # ‘SiamFC’ - - # assume tracker_names[0] is your tracker - report_dir = os.path.join(self.report_dir, tracker_names[0]) - - if not os.path.isdir(report_dir): - os.makedirs(report_dir) - - report_file = os.path.join(report_dir, 'performance.json') - - performance = {} - for name in tracker_names: - print('Evaluating', name) - seq_num = len(self.dataset) - succ_curve = np.zeros((seq_num, self.nbins_iou)) - prec_curve = np.zeros((seq_num, self.nbins_ce)) - speeds = np.zeros(seq_num) - # - performance.update({name: {'overall': {}, 'seq_wise': {}}}) - - for s, (_, anno) in enumerate(self.dataset): - - seq_name = self.dataset.seq_names[s] - - record_file = os.path.join(self.result_dir, name, '%s.txt' % seq_name) - - boxes = np.loadtxt(record_file, delimiter=',') - - boxes[0] = anno[0] - - assert len(boxes) == len(anno) - - ious, center_errors = self._calc_metrics(boxes, anno) - - succ_curve[s], prec_curve[s] = self._calc_curves(ious, center_errors) - - # calculate average tracking speed - time_file = os.path.join(self.result_dir, name, 'times/%s_time.txt' % seq_name) - - if os.path.isfile(time_file): - times = np.loadtxt(time_file) - times = times[times > 0] - if len(times) > 0: - speeds[s] = np.mean(1. / times) - # store sequence-wise performance - performance[name]['seq_wise'].update({seq_name: { - 'success_curve': succ_curve[s].tolist(), - 'precision_curve': prec_curve[s].tolist(), - 'success_score': np.mean(succ_curve[s]), - 'precision_score': prec_curve[s][20], - 'success_rate': succ_curve[s][self.nbins_iou // 2], - 'speed_fps': speeds[s] if speeds[s] > 0 else -1}}) - - succ_curve = np.mean(succ_curve, axis=0) - prec_curve = np.mean(prec_curve, axis=0) - succ_score = np.mean(succ_curve) - prec_score = prec_curve[20] - succ_rate = succ_curve[self.nbins_iou // 2] - if np.count_nonzero(speeds) > 0: - avg_speed = np.sum(speeds) / np.count_nonzero(speeds) - else: - avg_speed = -1 - - # store overall performance - performance[name]['overall'].update({ - 'success_curve': succ_curve.tolist(), - 'precision_curve': prec_curve.tolist(), - 'success_score': succ_score, - 'precision_score': prec_score, - 'success_rate': succ_rate, - 'speed_fps': avg_speed}) - # print('prec_score:%s --succ_score:%s --succ_rate:%s' % (prec_score,succ_score,succ_rate)) - # report the performance - with open(report_file, 'w') as f: - json.dump(performance, f, indent=4) - - return prec_score, succ_score, succ_rate - - def _record(self, record_file, boxes, times): - # record bounding boxes - record_dir = os.path.dirname(record_file) - if not os.path.isdir(record_dir): - os.makedirs(record_dir) - np.savetxt(record_file, boxes, fmt='%.3f', delimiter=',') - - # print(' Results recorded at', record_file) - - # record running times - time_dir = os.path.join(record_dir, 'times') - if not os.path.isdir(time_dir): - os.makedirs(time_dir) - time_file = os.path.join(time_dir, os.path.basename( - record_file).replace('.txt', '_time.txt')) - np.savetxt(time_file, times, fmt='%.8f') - - def _calc_metrics(self, boxes, anno): - # can be modified by children classes - ious = rect_iou(boxes, anno) - center_errors = center_error(boxes, anno) - return ious, center_errors - - def _calc_curves(self, ious, center_errors): - ious = np.asarray(ious, float)[:, np.newaxis] - center_errors = np.asarray(center_errors, float)[:, np.newaxis] - - thr_iou = np.linspace(0, 1, self.nbins_iou)[np.newaxis, :] - thr_ce = np.arange(0, self.nbins_ce)[np.newaxis, :] - - bin_iou = np.greater(ious, thr_iou) - bin_ce = np.less_equal(center_errors, thr_ce) - - succ_curve = np.mean(bin_iou, axis=0) - prec_curve = np.mean(bin_ce, axis=0) - - return succ_curve, prec_curve - - -if __name__ == "__main__": - data_path = sys.argv[1] - save_path = sys.argv[2] - info_path = sys.argv[3] - arch = sys.argv[4] - deviceid = int(sys.argv[5]) - benchmark_path = sys.argv[6] - om_path = sys.argv[7] - os.system('rm -rf %s' % save_path) - os.system('rm -rf %s' % info_path) - os.system('rm -rf ./result/dumpOutput_device%d' % deviceid) - if not os.path.exists(save_path): - os.makedirs(save_path) - if not os.path.exists(info_path): - os.makedirs(info_path) - e = ExperimentOTB(data_path, version=2015) - totallen = e.getlendataset() - pool = multiprocessing.Pool(processes=12) - for i in range(totallen): - pool.apply_async(e.run, (save_path, info_path, arch, i, )) - pool.close() - pool.join() - prec_score, succ_score, succ_rate = e.report(['siamfc']) - ss = '-prec_score:%.3f -succ_score:%.3f -succ_rate:%.3f' % (float(prec_score), float(succ_score), float(succ_rate)) - print("====accuracy data====") - print(ss) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import glob +import numpy as np +import io +import six +from itertools import chain +import cv2 +import json +import sys +import multiprocessing +sys.path.append(os.getcwd()) +from prepostprocess import PrePostProcess +from utils import rect_iou, center_error + + +deviceid = 0 + + +class OTB(object): + r"""`OTB `_ Datasets. + + Publication: + ``Object Tracking Benchmark``, Y. Wu, J. Lim and M.-H. Yang, IEEE TPAMI 2015. + + Args: + root_dir (string): Root directory of dataset where sequence + folders exist. + version (integer or string): Specify the benchmark version, specify as one of + ``2013``, ``2015``, ``tb50`` and ``tb100``. + """ + __otb13_seqs = ['Basketball', 'Bolt', 'Boy', 'Car4', 'CarDark', + 'CarScale', 'Coke', 'Couple', 'Crossing', 'David', + 'David2', 'David3', 'Deer', 'Dog1', 'Doll', 'Dudek', + 'FaceOcc1', 'FaceOcc2', 'Fish', 'FleetFace', + 'Football', 'Football1', 'Freeman1', 'Freeman3', + 'Freeman4', 'Girl', 'Ironman', 'Jogging', 'Jumping', + 'Lemming', 'Liquor', 'Matrix', 'Mhyang', 'MotorRolling', + 'MountainBike', 'Shaking', 'Singer1', 'Singer2', + 'Skating1', 'Skiing', 'Soccer', 'Subway', 'Suv', + 'Sylvester', 'Tiger1', 'Tiger2', 'Trellis', 'Walking', + 'Walking2', 'Woman'] + + __tb50_seqs = ['Basketball', 'Biker', 'Bird1', 'BlurBody', 'BlurCar2', + 'BlurFace', 'BlurOwl', 'Bolt', 'Box', 'Car1', 'Car4', + 'CarDark', 'CarScale', 'ClifBar', 'Couple', 'Crowds', + 'David', 'Deer', 'Diving', 'DragonBaby', 'Dudek', + 'Football', 'Freeman4', 'Girl', 'Human3', 'Human4', + 'Human6', 'Human9', 'Ironman', 'Jump', 'Jumping', + 'Liquor', 'Matrix', 'MotorRolling', 'Panda', 'RedTeam', + 'Shaking', 'Singer2', 'Skating1', 'Skating2', 'Skiing', + 'Soccer', 'Surfer', 'Sylvester', 'Tiger2', 'Trellis', + 'Walking', 'Walking2', 'Woman'] + + __tb100_seqs = ['Bird2', 'BlurCar1', 'BlurCar3', 'BlurCar4', 'Board', + 'Bolt2', 'Boy', 'Car2', 'Car24', 'Coke', 'Coupon', + 'Crossing', 'Dancer', 'Dancer2', 'David2', 'David3', + 'Dog', 'Dog1', 'Doll', 'FaceOcc1', 'FaceOcc2', 'Fish', + 'FleetFace', 'Football1', 'Freeman1', 'Freeman3', + 'Girl2', 'Gym', 'Human2', 'Human5', 'Human7', 'Human8', + 'Jogging', 'KiteSurf', 'Lemming', 'Man', 'Mhyang', + 'MountainBike', 'Rubik', 'Singer1', 'Skater', + 'Skater2', 'Subway', 'Suv', 'Tiger1', 'Toy', 'Trans', + 'Twinnings', 'Vase'] + __tb50_seqs + + __otb15_seqs = __tb100_seqs + + __version_dict = { + 2013: __otb13_seqs, + 2015: __otb15_seqs, + 'otb2013': __otb13_seqs, + 'otb2015': __otb15_seqs, + 'tb50': __tb50_seqs, + 'tb100': __tb100_seqs} + + def __init__(self, root_dir, version=2015): + super(OTB, self).__init__() + assert version in self.__version_dict + + self.root_dir = root_dir + self.version = version + self._check_integrity(root_dir, version) + valid_seqs = self.__version_dict[version] + self.anno_files = sorted(list(chain.from_iterable(glob.glob( + os.path.join(root_dir, s, 'groundtruth*.txt')) for s in valid_seqs))) + # remove empty annotation files + # (e.g. groundtruth_rect.1.txt of Human4) + self.anno_files = self._filter_files(self.anno_files) + self.seq_dirs = [os.path.dirname(f) for f in self.anno_files] + self.seq_names = [os.path.basename(d) for d in self.seq_dirs] + # rename repeated sequence names + # (e.g. Jogging and Skating2) + self.seq_names = self._rename_seqs(self.seq_names) + + def __getitem__(self, index): + r""" + Args: + index (integer or string): Index or name of a sequence. + + Returns: + tuple: (img_files, anno), where ``img_files`` is a list of + file names and ``anno`` is a N x 4 (rectangles) numpy array. + """ + if isinstance(index, six.string_types): + if not index in self.seq_names: + raise Exception('Sequence {} not found.'.format(index)) + index = self.seq_names.index(index) + + img_files = sorted(glob.glob( + os.path.join(self.seq_dirs[index], 'img/*.jpg'))) + + # special sequences + seq_name = self.seq_names[index] + if seq_name.lower() == 'david': + img_files = img_files[300 - 1:770] + elif seq_name.lower() == 'football1': + img_files = img_files[:74] + elif seq_name.lower() == 'freeman3': + img_files = img_files[:460] + elif seq_name.lower() == 'freeman4': + img_files = img_files[:283] + elif seq_name.lower() == 'diving': + img_files = img_files[:215] + + # to deal with different delimeters + with open(self.anno_files[index], 'r') as f: + anno = np.loadtxt(io.StringIO(f.read().replace(',', ' '))) + assert len(img_files) == len(anno) + assert anno.shape[1] == 4 + + return img_files, anno + + def __len__(self): + return len(self.seq_names) + + def _filter_files(self, filenames): + filtered_files = [] + for filename in filenames: + with open(filename, 'r') as f: + if f.read().strip() == '': + print('Warning: %s is empty.' % filename) + else: + filtered_files.append(filename) + + return filtered_files + + def _rename_seqs(self, seq_names): + # in case some sequences may have multiple targets + renamed_seqs = [] + for i, seq_name in enumerate(seq_names): + if seq_names.count(seq_name) == 1: + renamed_seqs.append(seq_name) + else: + ind = seq_names[:i + 1].count(seq_name) + renamed_seqs.append('%s.%d' % (seq_name, ind)) + + return renamed_seqs + + def _check_integrity(self, root_dir, version): + assert version in self.__version_dict + seq_names = self.__version_dict[version] + + if os.path.isdir(root_dir) and len(os.listdir(root_dir)) > 0: + # check each sequence folder + for seq_name in seq_names: + seq_dir = os.path.join(root_dir, seq_name) + if not os.path.isdir(seq_dir): + print('Warning: sequence %s not exists.' % seq_name) + else: + # dataset not exists + raise Exception('Dataset not found or corrupted. ' + + 'You can use download=True to download it.') + + +class ExperimentOTB(object): + """Experiment pipeline and evaluation toolkit for OTB dataset. + + Args: + root_dir (string): Root directory of OTB dataset. + version (integer or string): Specify the benchmark version, specify as one of + ``2013``, ``2015``, ``tb50`` and ``tb100``. Default is ``2015``. + result_dir (string, optional): Directory for storing tracking + results. Default is ``./results``. + report_dir (string, optional): Directory for storing performance + evaluation results. Default is ``./reports``. + """ + def __init__(self, root_dir, version=2015, + result_dir='results', report_dir='reports'): + super(ExperimentOTB, self).__init__() + self.dataset = OTB(root_dir, version) + self.result_dir = os.path.join(result_dir, 'OTB' + str(version)) + self.report_dir = os.path.join(report_dir, 'OTB' + str(version)) + # as nbins_iou increases, the success score + # converges to the average overlap (AO) + self.nbins_iou = 21 + self.nbins_ce = 51 + + def getlendataset(self): + return len(self.dataset) + + def run(self, savepath, infopath, arch, idx): + # get the seq_name and information of files + img_files, anno = self.dataset[idx] + seq_name = self.dataset.seq_names[idx] + # generate directory for current seq + savepath = savepath + "/" + str(idx) + if not os.path.exists(savepath): + os.makedirs(savepath) + infopath = infopath + "/" + str(idx) + ".info" + # skip if result exist + record_file = os.path.join(self.result_dir, 'siamfc', '%s.txt' % seq_name) + if os.path.exists(record_file): + print('Found results of %s, skipping' % seq_name) + return + frame_num = len(img_files) + boxes = np.zeros((frame_num, 4)) + boxes[0] = anno[0, :] # x,y, w, h + times = np.zeros(frame_num) + + prepostpro = PrePostProcess() + for f, img_file in enumerate(img_files): + img = cv2.imread(img_file, cv2.IMREAD_COLOR) + if f == 0: + # Pre-process and generate bin + exemplar_path = prepostpro.cropexemplar(img, anno[0, :], savepath, img_file) + # get_info + with open(infopath, 'w') as file1: + content = ' '.join([str(0), '.'+exemplar_path, str(127), str(127)]) + file1.write(content) + file1.write('\n') + # infer + os.system('%s -model_type=vision -device_id=%d -batch_size=1 ' + '-om_path=s%/exemplar_bs1.om -input_text_path=%s ' + '-input_width=127 -input_height=127 -output_binary=True -useDvpp=False >/dev/null 2>&1' + % (benchmark_path, deviceid, om_path, infopath)) + # the exemplar has a result of 3*256*6*6 tensor + # read tensor from bin + filename = img_file.replace('/', '-').split('.')[0] + '_1.bin' + filename = 'result/dumpOutput_device' + str(deviceid) + '/' + filename + exemplar_feature = prepostpro.file2tensor(filename, (3, 256, 6, 6)) + else: + # Pre-process and generate bin + search_path = prepostpro.cropsearch(img, savepath, img_file) + # get_info + with open(infopath, 'w') as file2: + content = ' '.join([str(0), '.'+search_path, str(255), str(255)]) + file2.write(content) + file2.write('\n') + # infer + os.system('%s -model_type=vision -device_id=%d -batch_size=1 ' + '-om_path=%s/search_bs1.om -input_text_path=%s ' + '-input_width=255 -input_height=255 -output_binary=True -useDvpp=False >/dev/null 2>&1' + % (benchmark_path, deviceid, om_path, infopath)) + # the exemplar has a result of 1*768*22*22 tensor + # read tensor from bin + filename = img_file.replace('/', '-').split('.')[0] + '_1.bin' + filename = 'result/dumpOutput_device' + str(deviceid) + '/' + filename + search_feature = prepostpro.file2tensor(filename, (1, 768, 22, 22)) + # Post-process + boxes[f, :] = prepostpro.postprocess(search_feature, exemplar_feature) + times[f] = 1 + assert len(boxes) == len(anno) + # record results + self._record(record_file, boxes, times) + # delete useless data to save space + os.system('rm -rf %s/*' % savepath) + print("Results of %s finished!" % seq_name) + + def report(self, tracker_names): + + assert isinstance(tracker_names, (list, tuple)) # ‘SiamFC’ + + # assume tracker_names[0] is your tracker + report_dir = os.path.join(self.report_dir, tracker_names[0]) + + if not os.path.isdir(report_dir): + os.makedirs(report_dir) + + report_file = os.path.join(report_dir, 'performance.json') + + performance = {} + for name in tracker_names: + print('Evaluating', name) + seq_num = len(self.dataset) + succ_curve = np.zeros((seq_num, self.nbins_iou)) + prec_curve = np.zeros((seq_num, self.nbins_ce)) + speeds = np.zeros(seq_num) + # + performance.update({name: {'overall': {}, 'seq_wise': {}}}) + + for s, (_, anno) in enumerate(self.dataset): + + seq_name = self.dataset.seq_names[s] + + record_file = os.path.join(self.result_dir, name, '%s.txt' % seq_name) + + boxes = np.loadtxt(record_file, delimiter=',') + + boxes[0] = anno[0] + + assert len(boxes) == len(anno) + + ious, center_errors = self._calc_metrics(boxes, anno) + + succ_curve[s], prec_curve[s] = self._calc_curves(ious, center_errors) + + # calculate average tracking speed + time_file = os.path.join(self.result_dir, name, 'times/%s_time.txt' % seq_name) + + if os.path.isfile(time_file): + times = np.loadtxt(time_file) + times = times[times > 0] + if len(times) > 0: + speeds[s] = np.mean(1. / times) + # store sequence-wise performance + performance[name]['seq_wise'].update({seq_name: { + 'success_curve': succ_curve[s].tolist(), + 'precision_curve': prec_curve[s].tolist(), + 'success_score': np.mean(succ_curve[s]), + 'precision_score': prec_curve[s][20], + 'success_rate': succ_curve[s][self.nbins_iou // 2], + 'speed_fps': speeds[s] if speeds[s] > 0 else -1}}) + + succ_curve = np.mean(succ_curve, axis=0) + prec_curve = np.mean(prec_curve, axis=0) + succ_score = np.mean(succ_curve) + prec_score = prec_curve[20] + succ_rate = succ_curve[self.nbins_iou // 2] + if np.count_nonzero(speeds) > 0: + avg_speed = np.sum(speeds) / np.count_nonzero(speeds) + else: + avg_speed = -1 + + # store overall performance + performance[name]['overall'].update({ + 'success_curve': succ_curve.tolist(), + 'precision_curve': prec_curve.tolist(), + 'success_score': succ_score, + 'precision_score': prec_score, + 'success_rate': succ_rate, + 'speed_fps': avg_speed}) + # print('prec_score:%s --succ_score:%s --succ_rate:%s' % (prec_score,succ_score,succ_rate)) + # report the performance + with open(report_file, 'w') as f: + json.dump(performance, f, indent=4) + + return prec_score, succ_score, succ_rate + + def _record(self, record_file, boxes, times): + # record bounding boxes + record_dir = os.path.dirname(record_file) + if not os.path.isdir(record_dir): + os.makedirs(record_dir) + np.savetxt(record_file, boxes, fmt='%.3f', delimiter=',') + + # print(' Results recorded at', record_file) + + # record running times + time_dir = os.path.join(record_dir, 'times') + if not os.path.isdir(time_dir): + os.makedirs(time_dir) + time_file = os.path.join(time_dir, os.path.basename( + record_file).replace('.txt', '_time.txt')) + np.savetxt(time_file, times, fmt='%.8f') + + def _calc_metrics(self, boxes, anno): + # can be modified by children classes + ious = rect_iou(boxes, anno) + center_errors = center_error(boxes, anno) + return ious, center_errors + + def _calc_curves(self, ious, center_errors): + ious = np.asarray(ious, float)[:, np.newaxis] + center_errors = np.asarray(center_errors, float)[:, np.newaxis] + + thr_iou = np.linspace(0, 1, self.nbins_iou)[np.newaxis, :] + thr_ce = np.arange(0, self.nbins_ce)[np.newaxis, :] + + bin_iou = np.greater(ious, thr_iou) + bin_ce = np.less_equal(center_errors, thr_ce) + + succ_curve = np.mean(bin_iou, axis=0) + prec_curve = np.mean(bin_ce, axis=0) + + return succ_curve, prec_curve + + +if __name__ == "__main__": + data_path = sys.argv[1] + save_path = sys.argv[2] + info_path = sys.argv[3] + arch = sys.argv[4] + deviceid = int(sys.argv[5]) + benchmark_path = sys.argv[6] + om_path = sys.argv[7] + os.system('rm -rf %s' % save_path) + os.system('rm -rf %s' % info_path) + os.system('rm -rf ./result/dumpOutput_device%d' % deviceid) + if not os.path.exists(save_path): + os.makedirs(save_path) + if not os.path.exists(info_path): + os.makedirs(info_path) + e = ExperimentOTB(data_path, version=2015) + totallen = e.getlendataset() + pool = multiprocessing.Pool(processes=12) + for i in range(totallen): + pool.apply_async(e.run, (save_path, info_path, arch, i, )) + pool.close() + pool.join() + prec_score, succ_score, succ_rate = e.report(['siamfc']) + ss = '-prec_score:%.3f -succ_score:%.3f -succ_rate:%.3f' % (float(prec_score), float(succ_score), float(succ_rate)) + print("====accuracy data====") + print(ss) diff --git a/ACL_PyTorch/contrib/cv/tracking/SiamRPN/LICENSE b/ACL_PyTorch/contrib/cv/tracking/SiamRPN/LICENSE index 29f81d812f..261eeb9e9f 100644 --- a/ACL_PyTorch/contrib/cv/tracking/SiamRPN/LICENSE +++ b/ACL_PyTorch/contrib/cv/tracking/SiamRPN/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/ACL_PyTorch/contrib/cv/tracking/SiamRPN/README.md b/ACL_PyTorch/contrib/cv/tracking/SiamRPN/README.md index 2b0cca5699..ec84757b74 100644 --- a/ACL_PyTorch/contrib/cv/tracking/SiamRPN/README.md +++ b/ACL_PyTorch/contrib/cv/tracking/SiamRPN/README.md @@ -1,97 +1,97 @@ -# SiamRPN模型PyTorch推理指导 - -## 1 环境准备 -1. 获取开源代码仓 -- 得到本项目代码后,将 SiamRPN 项目放置在/home目录下,进入/home/SiamRPN目录下,下载开源代码仓 -``` -git clone https://github.com/STVIR/pysot.git -``` - -- 确认获取的开源 pysot 项目文件存放在 /home/SiamRPN 目录下,进入 /home/SiamRPN/pysot 目录下执行 -``` -patch -N -p1 < ../SiamRPN.patch -``` - -2. 获取数据集 -- 将数据集VOT2016下载并放在 /root/datasets 目录下 -``` -wget -P /root/datasets https://ascend-pytorch-one-datasets.obs.cn-north-4.myhuaweicloud.com/train/zip/VOT2016.zip -cd // -cd /root/datasets -unzip VOT2016.zip -rm -rf VOT2016.zip -``` -- (备注:将获取的 VOT2016 数据集文件放在 /root/datasets 目录下) - - -3. 安装依赖 -- 进入 /home/SiamRPN 目录下 -```shell -cd // -cd /home/SiamRPN -pip install -r requirements.txt -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com -``` -- (备注:若有安装失败的请单独重新安装,若有需要,也可使用conda指令安装) - -4. 获取pth权重文件 - -``` -wget -P /home/SiamRPN/pysot/experiments/siamrpn_r50_l234_dwxcorr https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/tracking/SiamRPN/model.pth -``` - -- (备注:将 model.pth 权重文件要放在 ../siamrpn_r50_l234_dwxcorr 目录下) - -5. 运行setup.py -- 进入 /home/SiamRPN/pysot 目录下执行 -``` -export PYTHONPATH=/home/SiamRPN/pysot:$PYTHONPATH -python setup.py build_ext --inplace install -``` - - - -## 2 离线推理 - -310上执行,执行时使用 npu-smi info 查看设备状态,确保device空闲 - -```shell -# (j进入 /home/SiamRPN 下执行) -# 转成onnx -bash test/pth2onnx.sh -# 转成om -bash test/onnx2om.sh -# 进行评估 -bash test/eval_acc_perf.sh -``` - - -- 评测结果: - -- 310精度 -``` ------------------------------------------------------------- -|Tracker Name| Accuracy | Robustness | Average | EAO | ------------------------------------------------------------- -| VOT2016 | 0.639 | 0.177 | 42fps | 0.483 | ------------------------------------------------------------- -``` - -- 参考pth精度 -``` ------------------------------------------------------------- -|Tracker Name| Accuracy | Robustness | Average | EAO | ------------------------------------------------------------- -| VOT2016 | 0.642 | 0.196 | 35fps | 0.464 | ------------------------------------------------------------- -``` - - -- 性能计算方式: - fps计算方式为单位时间内处理的图片数量,即 图片数量 / 时间 。 - 根据310单device需乘以4之后再和T4对比,故310单卡性能理论计算为42×4=168fps。 - -- 备注: -- (1) 310精度相较于T4下降0.3%,但鲁棒性和EAO均有提升。310单device的实际平均性能为42fps。T4单卡平均性能为35fps,由于运行场景等干扰因素不同,会导致结果有所浮动,35fps为多次测量后平均近似值,供参考。 -- (2) 性能数据(speed)在推理过程中会展示,在推理结束后会展示平均性能(average speed)。 -- (3) 本推理为视频追踪,输入对象为视频,故不设置多batch。 - +# SiamRPN模型PyTorch推理指导 + +## 1 环境准备 +1. 获取开源代码仓 +- 得到本项目代码后,将 SiamRPN 项目放置在/home目录下,进入/home/SiamRPN目录下,下载开源代码仓 +``` +git clone https://github.com/STVIR/pysot.git +``` + +- 确认获取的开源 pysot 项目文件存放在 /home/SiamRPN 目录下,进入 /home/SiamRPN/pysot 目录下执行 +``` +patch -N -p1 < ../SiamRPN.patch +``` + +2. 获取数据集 +- 将数据集VOT2016下载并放在 /root/datasets 目录下 +``` +wget -P /root/datasets https://ascend-pytorch-one-datasets.obs.cn-north-4.myhuaweicloud.com/train/zip/VOT2016.zip +cd // +cd /root/datasets +unzip VOT2016.zip +rm -rf VOT2016.zip +``` +- (备注:将获取的 VOT2016 数据集文件放在 /root/datasets 目录下) + + +3. 安装依赖 +- 进入 /home/SiamRPN 目录下 +```shell +cd // +cd /home/SiamRPN +pip install -r requirements.txt -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com +``` +- (备注:若有安装失败的请单独重新安装,若有需要,也可使用conda指令安装) + +4. 获取pth权重文件 + +``` +wget -P /home/SiamRPN/pysot/experiments/siamrpn_r50_l234_dwxcorr https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/tracking/SiamRPN/model.pth +``` + +- (备注:将 model.pth 权重文件要放在 ../siamrpn_r50_l234_dwxcorr 目录下) + +5. 运行setup.py +- 进入 /home/SiamRPN/pysot 目录下执行 +``` +export PYTHONPATH=/home/SiamRPN/pysot:$PYTHONPATH +python setup.py build_ext --inplace install +``` + + + +## 2 离线推理 + +310上执行,执行时使用 npu-smi info 查看设备状态,确保device空闲 + +```shell +# (j进入 /home/SiamRPN 下执行) +# 转成onnx +bash test/pth2onnx.sh +# 转成om +bash test/onnx2om.sh +# 进行评估 +bash test/eval_acc_perf.sh +``` + + +- 评测结果: + +- 310精度 +``` +------------------------------------------------------------ +|Tracker Name| Accuracy | Robustness | Average | EAO | +------------------------------------------------------------ +| VOT2016 | 0.639 | 0.177 | 42fps | 0.483 | +------------------------------------------------------------ +``` + +- 参考pth精度 +``` +------------------------------------------------------------ +|Tracker Name| Accuracy | Robustness | Average | EAO | +------------------------------------------------------------ +| VOT2016 | 0.642 | 0.196 | 35fps | 0.464 | +------------------------------------------------------------ +``` + + +- 性能计算方式: + fps计算方式为单位时间内处理的图片数量,即 图片数量 / 时间 。 + 根据310单device需乘以4之后再和T4对比,故310单卡性能理论计算为42×4=168fps。 + +- 备注: +- (1) 310精度相较于T4下降0.3%,但鲁棒性和EAO均有提升。310单device的实际平均性能为42fps。T4单卡平均性能为35fps,由于运行场景等干扰因素不同,会导致结果有所浮动,35fps为多次测量后平均近似值,供参考。 +- (2) 性能数据(speed)在推理过程中会展示,在推理结束后会展示平均性能(average speed)。 +- (3) 本推理为视频追踪,输入对象为视频,故不设置多batch。 + diff --git a/ACL_PyTorch/contrib/cv/tracking/SiamRPN/acl_net.py b/ACL_PyTorch/contrib/cv/tracking/SiamRPN/acl_net.py index add3602f90..f3624527dc 100644 --- a/ACL_PyTorch/contrib/cv/tracking/SiamRPN/acl_net.py +++ b/ACL_PyTorch/contrib/cv/tracking/SiamRPN/acl_net.py @@ -1,239 +1,239 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 numpy as np -import acl -import functools - -# error code -ACL_ERROR_NONE = 0 - -# memory malloc code -ACL_MEM_MALLOC_HUGE_FIRST = 0 -ACL_MEM_MALLOC_HUGE_ONLY = 1 -ACL_MEM_MALLOC_NORMAL_ONLY = 2 - -# memory copy code -ACL_MEMCPY_HOST_TO_HOST = 0 -ACL_MEMCPY_HOST_TO_DEVICE = 1 -ACL_MEMCPY_DEVICE_TO_HOST = 2 -ACL_MEMCPY_DEVICE_TO_DEVICE = 3 - -ACL_DTYPE = { - 0: 'float32', - 1: 'float16', - 2: 'int8', - 3: 'int32', - 4: 'uint8', - 6: 'int16', - 7: 'uint16', - 8: 'uint32', - 9: 'int64', - 10: 'uint64', - 11: 'float64', - 12: 'bool', -} - -buffer_method = { - "in": acl.mdl.get_input_size_by_index, - "out": acl.mdl.get_output_size_by_index, - "outhost": acl.mdl.get_output_size_by_index -} - - -def check_ret(message, ret): - if ret != ACL_ERROR_NONE: - raise Exception("{} failed ret = {}".format(message, ret)) - - -class Net(object): - def __init__(self, context, model_path, device_id=0, first=True, config_path=None): - self.device_id = device_id - self.model_path = model_path - self.model_id = None - self.context = context - - self.input_data = [] - self.output_data = [] - self.output_data_host = [] - self.model_desc = None - self.load_input_dataset = None - self.load_output_dataset = None - - self._init_resource(first, config_path) - - def __call__(self, ori_data): - return self.forward(ori_data) - - def __del__(self): - ret = acl.mdl.unload(self.model_id) - check_ret("acl.mdl.unload", ret) - if self.model_desc: - acl.mdl.destroy_desc(self.model_desc) - self.model_desc = None - - while self.input_data: - item = self.input_data.pop() - ret = acl.rt.free(item["buffer"]) - check_ret("acl.rt.free", ret) - - while self.output_data: - item = self.output_data.pop() - ret = acl.rt.free(item["buffer"]) - check_ret("acl.rt.free", ret) - - def _init_resource(self, first=False, config_path=None): - # load_model - self.model_id, ret = acl.mdl.load_from_file(self.model_path) - check_ret("acl.mdl.load_from_file", ret) - - self.model_desc = acl.mdl.create_desc() - self._get_model_info() - - def _get_model_info(self, ): - ret = acl.mdl.get_desc(self.model_desc, self.model_id) - check_ret("acl.mdl.get_desc", ret) - input_size = acl.mdl.get_num_inputs(self.model_desc) - output_size = acl.mdl.get_num_outputs(self.model_desc) - self._gen_data_buffer(input_size, des="in") - self._gen_data_buffer(output_size, des="out") - self._gen_dataset_output_host(output_size, des="outhost") - - def _gen_data_buffer(self, size, des): - func = buffer_method[des] - for i in range(size): - temp_buffer_size = func(self.model_desc, i) - temp_buffer, ret = acl.rt.malloc( - temp_buffer_size, ACL_MEM_MALLOC_HUGE_FIRST) - check_ret("acl.rt.malloc", ret) - - if des == "in": - self.input_data.append({"buffer": temp_buffer, - "size": temp_buffer_size}) - elif des == "out": - self.output_data.append({"buffer": temp_buffer, - "size": temp_buffer_size}) - - def _gen_dataset_output_host(self, size, des): - func = buffer_method[des] - for i in range(size): - temp_buffer_size = func(self.model_desc, i) - temp_buffer, ret = acl.rt.malloc_host(temp_buffer_size) - check_ret("acl.rt.malloc_host", ret) - - self.output_data_host.append({"buffer": temp_buffer, - "size": temp_buffer_size}) - - def _data_interaction(self, dataset, policy=ACL_MEMCPY_HOST_TO_DEVICE): - temp_data_buffer = self.input_data \ - if policy == ACL_MEMCPY_HOST_TO_DEVICE \ - else self.output_data - output_malloc_cost = 0 - idx = 0 - - if len(dataset) == 0 and policy == ACL_MEMCPY_DEVICE_TO_HOST: - dataset = self.output_data_host - - for i, item in enumerate(temp_data_buffer): - if policy == ACL_MEMCPY_HOST_TO_DEVICE: - ptr = acl.util.numpy_to_ptr(dataset[i]) - ret = acl.rt.memcpy( - item["buffer"], item["size"], ptr, item["size"], policy) - check_ret("acl.rt.memcpy", ret) - - else: - ptr = dataset[i]["buffer"] - ret = acl.rt.memcpy( - ptr, item["size"], item["buffer"], item["size"], policy) - check_ret("acl.rt.memcpy", ret) - - def _gen_dataset(self, type_str="input"): - dataset = acl.mdl.create_dataset() - - temp_dataset = None - if type_str == "in": - self.load_input_dataset = dataset - temp_dataset = self.input_data - else: - self.load_output_dataset = dataset - temp_dataset = self.output_data - - for item in temp_dataset: - data = acl.create_data_buffer(item["buffer"], item["size"]) - if data is None: - ret = acl.destroy_data_buffer(dataset) - check_ret("acl.destroy_data_buffer", ret) - - _, ret = acl.mdl.add_dataset_buffer(dataset, data) - if ret != ACL_ERROR_NONE: - ret = acl.destroy_data_buffer(dataset) - check_ret("acl.destroy_data_buffer", ret) - - def _data_from_host_to_device(self, images): - self._data_interaction(images, ACL_MEMCPY_HOST_TO_DEVICE) - self._gen_dataset("in") - self._gen_dataset("out") - - def _data_from_device_to_host(self): - res = [] - self._data_interaction(res, ACL_MEMCPY_DEVICE_TO_HOST) - output = self.get_result(self.output_data_host) - return output - - def _destroy_databuffer(self): - for dataset in [self.load_input_dataset, self.load_output_dataset]: - if not dataset: - continue - - num = acl.mdl.get_dataset_num_buffers(dataset) - for i in range(num): - data_buf = acl.mdl.get_dataset_buffer(dataset, i) - if data_buf: - ret = acl.destroy_data_buffer(data_buf) - check_ret("acl.destroy_data_buffer", ret) - ret = acl.mdl.destroy_dataset(dataset) - check_ret("acl.mdl.destroy_dataset", ret) - - def forward(self, input_data): - if not isinstance(input_data, (list, tuple)): - input_data = [input_data] - - self._data_from_host_to_device(input_data) - ret = acl.mdl.execute( - self.model_id, self.load_input_dataset, self.load_output_dataset) - check_ret("acl.mdl.execute", ret) - - self._destroy_databuffer() - result = self._data_from_device_to_host() - return result - - def get_result(self, output_data): - dataset = [] - for i in range(len(output_data)): - dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) - check_ret("acl.mdl.get_cur_output_dims", ret) - - data_shape = dims.get("dims") - data_type = acl.mdl.get_output_data_type(self.model_desc, i) - data_len = functools.reduce(lambda x, y: x * y, data_shape) - ftype = np.dtype(ACL_DTYPE.get(data_type)) - - size = output_data[i]["size"] - ptr = output_data[i]["buffer"] - data = acl.util.ptr_to_numpy(ptr, (size,), 1) - np_array = np.frombuffer( - bytearray(data[:data_len * ftype.itemsize]), dtype=ftype, count=data_len) - np_array = np_array.reshape(data_shape) - dataset.append(np_array) - return dataset +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 numpy as np +import acl +import functools + +# error code +ACL_ERROR_NONE = 0 + +# memory malloc code +ACL_MEM_MALLOC_HUGE_FIRST = 0 +ACL_MEM_MALLOC_HUGE_ONLY = 1 +ACL_MEM_MALLOC_NORMAL_ONLY = 2 + +# memory copy code +ACL_MEMCPY_HOST_TO_HOST = 0 +ACL_MEMCPY_HOST_TO_DEVICE = 1 +ACL_MEMCPY_DEVICE_TO_HOST = 2 +ACL_MEMCPY_DEVICE_TO_DEVICE = 3 + +ACL_DTYPE = { + 0: 'float32', + 1: 'float16', + 2: 'int8', + 3: 'int32', + 4: 'uint8', + 6: 'int16', + 7: 'uint16', + 8: 'uint32', + 9: 'int64', + 10: 'uint64', + 11: 'float64', + 12: 'bool', +} + +buffer_method = { + "in": acl.mdl.get_input_size_by_index, + "out": acl.mdl.get_output_size_by_index, + "outhost": acl.mdl.get_output_size_by_index +} + + +def check_ret(message, ret): + if ret != ACL_ERROR_NONE: + raise Exception("{} failed ret = {}".format(message, ret)) + + +class Net(object): + def __init__(self, context, model_path, device_id=0, first=True, config_path=None): + self.device_id = device_id + self.model_path = model_path + self.model_id = None + self.context = context + + self.input_data = [] + self.output_data = [] + self.output_data_host = [] + self.model_desc = None + self.load_input_dataset = None + self.load_output_dataset = None + + self._init_resource(first, config_path) + + def __call__(self, ori_data): + return self.forward(ori_data) + + def __del__(self): + ret = acl.mdl.unload(self.model_id) + check_ret("acl.mdl.unload", ret) + if self.model_desc: + acl.mdl.destroy_desc(self.model_desc) + self.model_desc = None + + while self.input_data: + item = self.input_data.pop() + ret = acl.rt.free(item["buffer"]) + check_ret("acl.rt.free", ret) + + while self.output_data: + item = self.output_data.pop() + ret = acl.rt.free(item["buffer"]) + check_ret("acl.rt.free", ret) + + def _init_resource(self, first=False, config_path=None): + # load_model + self.model_id, ret = acl.mdl.load_from_file(self.model_path) + check_ret("acl.mdl.load_from_file", ret) + + self.model_desc = acl.mdl.create_desc() + self._get_model_info() + + def _get_model_info(self, ): + ret = acl.mdl.get_desc(self.model_desc, self.model_id) + check_ret("acl.mdl.get_desc", ret) + input_size = acl.mdl.get_num_inputs(self.model_desc) + output_size = acl.mdl.get_num_outputs(self.model_desc) + self._gen_data_buffer(input_size, des="in") + self._gen_data_buffer(output_size, des="out") + self._gen_dataset_output_host(output_size, des="outhost") + + def _gen_data_buffer(self, size, des): + func = buffer_method[des] + for i in range(size): + temp_buffer_size = func(self.model_desc, i) + temp_buffer, ret = acl.rt.malloc( + temp_buffer_size, ACL_MEM_MALLOC_HUGE_FIRST) + check_ret("acl.rt.malloc", ret) + + if des == "in": + self.input_data.append({"buffer": temp_buffer, + "size": temp_buffer_size}) + elif des == "out": + self.output_data.append({"buffer": temp_buffer, + "size": temp_buffer_size}) + + def _gen_dataset_output_host(self, size, des): + func = buffer_method[des] + for i in range(size): + temp_buffer_size = func(self.model_desc, i) + temp_buffer, ret = acl.rt.malloc_host(temp_buffer_size) + check_ret("acl.rt.malloc_host", ret) + + self.output_data_host.append({"buffer": temp_buffer, + "size": temp_buffer_size}) + + def _data_interaction(self, dataset, policy=ACL_MEMCPY_HOST_TO_DEVICE): + temp_data_buffer = self.input_data \ + if policy == ACL_MEMCPY_HOST_TO_DEVICE \ + else self.output_data + output_malloc_cost = 0 + idx = 0 + + if len(dataset) == 0 and policy == ACL_MEMCPY_DEVICE_TO_HOST: + dataset = self.output_data_host + + for i, item in enumerate(temp_data_buffer): + if policy == ACL_MEMCPY_HOST_TO_DEVICE: + ptr = acl.util.numpy_to_ptr(dataset[i]) + ret = acl.rt.memcpy( + item["buffer"], item["size"], ptr, item["size"], policy) + check_ret("acl.rt.memcpy", ret) + + else: + ptr = dataset[i]["buffer"] + ret = acl.rt.memcpy( + ptr, item["size"], item["buffer"], item["size"], policy) + check_ret("acl.rt.memcpy", ret) + + def _gen_dataset(self, type_str="input"): + dataset = acl.mdl.create_dataset() + + temp_dataset = None + if type_str == "in": + self.load_input_dataset = dataset + temp_dataset = self.input_data + else: + self.load_output_dataset = dataset + temp_dataset = self.output_data + + for item in temp_dataset: + data = acl.create_data_buffer(item["buffer"], item["size"]) + if data is None: + ret = acl.destroy_data_buffer(dataset) + check_ret("acl.destroy_data_buffer", ret) + + _, ret = acl.mdl.add_dataset_buffer(dataset, data) + if ret != ACL_ERROR_NONE: + ret = acl.destroy_data_buffer(dataset) + check_ret("acl.destroy_data_buffer", ret) + + def _data_from_host_to_device(self, images): + self._data_interaction(images, ACL_MEMCPY_HOST_TO_DEVICE) + self._gen_dataset("in") + self._gen_dataset("out") + + def _data_from_device_to_host(self): + res = [] + self._data_interaction(res, ACL_MEMCPY_DEVICE_TO_HOST) + output = self.get_result(self.output_data_host) + return output + + def _destroy_databuffer(self): + for dataset in [self.load_input_dataset, self.load_output_dataset]: + if not dataset: + continue + + num = acl.mdl.get_dataset_num_buffers(dataset) + for i in range(num): + data_buf = acl.mdl.get_dataset_buffer(dataset, i) + if data_buf: + ret = acl.destroy_data_buffer(data_buf) + check_ret("acl.destroy_data_buffer", ret) + ret = acl.mdl.destroy_dataset(dataset) + check_ret("acl.mdl.destroy_dataset", ret) + + def forward(self, input_data): + if not isinstance(input_data, (list, tuple)): + input_data = [input_data] + + self._data_from_host_to_device(input_data) + ret = acl.mdl.execute( + self.model_id, self.load_input_dataset, self.load_output_dataset) + check_ret("acl.mdl.execute", ret) + + self._destroy_databuffer() + result = self._data_from_device_to_host() + return result + + def get_result(self, output_data): + dataset = [] + for i in range(len(output_data)): + dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) + check_ret("acl.mdl.get_cur_output_dims", ret) + + data_shape = dims.get("dims") + data_type = acl.mdl.get_output_data_type(self.model_desc, i) + data_len = functools.reduce(lambda x, y: x * y, data_shape) + ftype = np.dtype(ACL_DTYPE.get(data_type)) + + size = output_data[i]["size"] + ptr = output_data[i]["buffer"] + data = acl.util.ptr_to_numpy(ptr, (size,), 1) + np_array = np.frombuffer( + bytearray(data[:data_len * ftype.itemsize]), dtype=ftype, count=data_len) + np_array = np_array.reshape(data_shape) + dataset.append(np_array) + return dataset diff --git a/ACL_PyTorch/contrib/cv/tracking/SiamRPN/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/tracking/SiamRPN/modelzoo_level.txt index d44ba5698b..70801afc42 100644 --- a/ACL_PyTorch/contrib/cv/tracking/SiamRPN/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/tracking/SiamRPN/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/video_understanding/I3D/acl_net.py b/ACL_PyTorch/contrib/cv/video_understanding/I3D/acl_net.py index 67ab2ec0ea..88c12ba316 100644 --- a/ACL_PyTorch/contrib/cv/video_understanding/I3D/acl_net.py +++ b/ACL_PyTorch/contrib/cv/video_understanding/I3D/acl_net.py @@ -1,245 +1,245 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 numpy as np -import acl -import functools - -# error code -ACL_ERROR_NONE = 0 - -# memory malloc code -ACL_MEM_MALLOC_HUGE_FIRST = 0 -ACL_MEM_MALLOC_HUGE_ONLY = 1 -ACL_MEM_MALLOC_NORMAL_ONLY = 2 - -# memory copy code -ACL_MEMCPY_HOST_TO_HOST = 0 -ACL_MEMCPY_HOST_TO_DEVICE = 1 -ACL_MEMCPY_DEVICE_TO_HOST = 2 -ACL_MEMCPY_DEVICE_TO_DEVICE = 3 - -ACL_DTYPE = { - 0: 'float32', - 1: 'float16', - 2: 'int8', - 3: 'int32', - 4: 'uint8', - 6: 'int16', - 7: 'uint16', - 8: 'uint32', - 9: 'int64', - 10: 'uint64', - 11: 'float64', - 12: 'bool', -} - -buffer_method = { - "in": acl.mdl.get_input_size_by_index, - "out": acl.mdl.get_output_size_by_index, - "outhost": acl.mdl.get_output_size_by_index -} - -def check_ret(message, ret): - if ret != ACL_ERROR_NONE: - raise Exception("{} failed ret = {}".format(message, ret)) - - -class Net(object): - def __init__(self, context, model_path, device_id=0, first=True, config_path=None): - self.device_id = device_id - self.model_path = model_path - self.model_id = None - self.context = context - - self.input_data = [] - self.output_data = [] - self.output_data_host = [] - self.model_desc = None - self.load_input_dataset = None - self.load_output_dataset = None - - self._init_resource(first, config_path) - - - def __call__(self, ori_data): - return self.forward(ori_data) - - - def __del__(self): - ret = acl.mdl.unload(self.model_id) - check_ret("acl.mdl.unload", ret) - if self.model_desc: - acl.mdl.destroy_desc(self.model_desc) - self.model_desc = None - - while self.input_data: - item = self.input_data.pop() - ret = acl.rt.free(item["buffer"]) - check_ret("acl.rt.free", ret) - - while self.output_data: - item = self.output_data.pop() - ret = acl.rt.free(item["buffer"]) - check_ret("acl.rt.free", ret) - - - def _init_resource(self, first=False, config_path=None): - # load_model - self.model_id, ret = acl.mdl.load_from_file(self.model_path) - check_ret("acl.mdl.load_from_file", ret) - - self.model_desc = acl.mdl.create_desc() - self._get_model_info() - - - def _get_model_info(self,): - ret = acl.mdl.get_desc(self.model_desc, self.model_id) - check_ret("acl.mdl.get_desc", ret) - input_size = acl.mdl.get_num_inputs(self.model_desc) - output_size = acl.mdl.get_num_outputs(self.model_desc) - self._gen_data_buffer(input_size, des="in") - self._gen_data_buffer(output_size, des="out") - self._gen_dataset_output_host(output_size, des="outhost") - - - def _gen_data_buffer(self, size, des): - func = buffer_method[des] - for i in range(size): - temp_buffer_size = func(self.model_desc, i) - temp_buffer, ret = acl.rt.malloc(temp_buffer_size, ACL_MEM_MALLOC_HUGE_FIRST) - check_ret("acl.rt.malloc", ret) - - if des == "in": - self.input_data.append({"buffer": temp_buffer, - "size": temp_buffer_size}) - elif des == "out": - self.output_data.append({"buffer": temp_buffer, - "size": temp_buffer_size}) - - - def _gen_dataset_output_host(self, size, des): - func = buffer_method[des] - for i in range(size): - temp_buffer_size = func(self.model_desc, i) - temp_buffer, ret = acl.rt.malloc_host(temp_buffer_size) - check_ret("acl.rt.malloc_host", ret) - - self.output_data_host.append({"buffer": temp_buffer, - "size": temp_buffer_size}) - - - def _data_interaction(self, dataset, policy=ACL_MEMCPY_HOST_TO_DEVICE): - temp_data_buffer = self.input_data \ - if policy == ACL_MEMCPY_HOST_TO_DEVICE \ - else self.output_data - output_malloc_cost = 0 - idx = 0 - - if len(dataset) == 0 and policy == ACL_MEMCPY_DEVICE_TO_HOST: - dataset = self.output_data_host - - for i, item in enumerate(temp_data_buffer): - if policy == ACL_MEMCPY_HOST_TO_DEVICE: - ptr = acl.util.numpy_to_ptr(dataset[i]) - ret = acl.rt.memcpy(item["buffer"], item["size"], ptr, item["size"], policy) - check_ret("acl.rt.memcpy", ret) - - else: - ptr = dataset[i]["buffer"] - ret = acl.rt.memcpy(ptr, item["size"], item["buffer"], item["size"], policy) - check_ret("acl.rt.memcpy", ret) - - - def _gen_dataset(self, type_str="input"): - dataset = acl.mdl.create_dataset() - - temp_dataset = None - if type_str == "in": - self.load_input_dataset = dataset - temp_dataset = self.input_data - else: - self.load_output_dataset = dataset - temp_dataset = self.output_data - - for item in temp_dataset: - data = acl.create_data_buffer(item["buffer"], item["size"]) - if data is None: - ret = acl.destroy_data_buffer(dataset) - check_ret("acl.destroy_data_buffer", ret) - - _, ret = acl.mdl.add_dataset_buffer(dataset, data) - if ret != ACL_ERROR_NONE: - ret = acl.destroy_data_buffer(dataset) - check_ret("acl.destroy_data_buffer", ret) - - - def _data_from_host_to_device(self, images): - self._data_interaction(images, ACL_MEMCPY_HOST_TO_DEVICE) - self._gen_dataset("in") - self._gen_dataset("out") - - - def _data_from_device_to_host(self): - res = [] - self._data_interaction(res, ACL_MEMCPY_DEVICE_TO_HOST) - output = self.get_result(self.output_data_host) - return output - - - def _destroy_databuffer(self): - for dataset in [self.load_input_dataset, self.load_output_dataset]: - if not dataset: - continue - - num = acl.mdl.get_dataset_num_buffers(dataset) - for i in range(num): - data_buf = acl.mdl.get_dataset_buffer(dataset, i) - if data_buf: - ret = acl.destroy_data_buffer(data_buf) - check_ret("acl.destroy_data_buffer", ret) - ret = acl.mdl.destroy_dataset(dataset) - check_ret("acl.mdl.destroy_dataset", ret) - - def forward(self, input_data): - if not isinstance(input_data, (list, tuple)): - input_data = [input_data] - - self._data_from_host_to_device(input_data) - ret = acl.mdl.execute(self.model_id, self.load_input_dataset, self.load_output_dataset) - check_ret("acl.mdl.execute", ret) - - self._destroy_databuffer() - result = self._data_from_device_to_host() - return result - - - def get_result(self, output_data): - dataset = [] - for i in range(len(output_data)): - dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) - check_ret("acl.mdl.get_cur_output_dims", ret) - - data_shape = dims.get("dims") - data_type = acl.mdl.get_output_data_type(self.model_desc, i) - data_len = functools.reduce(lambda x, y: x * y, data_shape) - ftype = np.dtype(ACL_DTYPE.get(data_type)) - - size = output_data[i]["size"] - ptr = output_data[i]["buffer"] - data = acl.util.ptr_to_numpy(ptr, (size,), 1) - np_array = np.frombuffer(bytearray(data[:data_len * ftype.itemsize]), dtype=ftype, count=data_len) - np_array = np_array.reshape(data_shape) - dataset.append(np_array) - return dataset +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 numpy as np +import acl +import functools + +# error code +ACL_ERROR_NONE = 0 + +# memory malloc code +ACL_MEM_MALLOC_HUGE_FIRST = 0 +ACL_MEM_MALLOC_HUGE_ONLY = 1 +ACL_MEM_MALLOC_NORMAL_ONLY = 2 + +# memory copy code +ACL_MEMCPY_HOST_TO_HOST = 0 +ACL_MEMCPY_HOST_TO_DEVICE = 1 +ACL_MEMCPY_DEVICE_TO_HOST = 2 +ACL_MEMCPY_DEVICE_TO_DEVICE = 3 + +ACL_DTYPE = { + 0: 'float32', + 1: 'float16', + 2: 'int8', + 3: 'int32', + 4: 'uint8', + 6: 'int16', + 7: 'uint16', + 8: 'uint32', + 9: 'int64', + 10: 'uint64', + 11: 'float64', + 12: 'bool', +} + +buffer_method = { + "in": acl.mdl.get_input_size_by_index, + "out": acl.mdl.get_output_size_by_index, + "outhost": acl.mdl.get_output_size_by_index +} + +def check_ret(message, ret): + if ret != ACL_ERROR_NONE: + raise Exception("{} failed ret = {}".format(message, ret)) + + +class Net(object): + def __init__(self, context, model_path, device_id=0, first=True, config_path=None): + self.device_id = device_id + self.model_path = model_path + self.model_id = None + self.context = context + + self.input_data = [] + self.output_data = [] + self.output_data_host = [] + self.model_desc = None + self.load_input_dataset = None + self.load_output_dataset = None + + self._init_resource(first, config_path) + + + def __call__(self, ori_data): + return self.forward(ori_data) + + + def __del__(self): + ret = acl.mdl.unload(self.model_id) + check_ret("acl.mdl.unload", ret) + if self.model_desc: + acl.mdl.destroy_desc(self.model_desc) + self.model_desc = None + + while self.input_data: + item = self.input_data.pop() + ret = acl.rt.free(item["buffer"]) + check_ret("acl.rt.free", ret) + + while self.output_data: + item = self.output_data.pop() + ret = acl.rt.free(item["buffer"]) + check_ret("acl.rt.free", ret) + + + def _init_resource(self, first=False, config_path=None): + # load_model + self.model_id, ret = acl.mdl.load_from_file(self.model_path) + check_ret("acl.mdl.load_from_file", ret) + + self.model_desc = acl.mdl.create_desc() + self._get_model_info() + + + def _get_model_info(self,): + ret = acl.mdl.get_desc(self.model_desc, self.model_id) + check_ret("acl.mdl.get_desc", ret) + input_size = acl.mdl.get_num_inputs(self.model_desc) + output_size = acl.mdl.get_num_outputs(self.model_desc) + self._gen_data_buffer(input_size, des="in") + self._gen_data_buffer(output_size, des="out") + self._gen_dataset_output_host(output_size, des="outhost") + + + def _gen_data_buffer(self, size, des): + func = buffer_method[des] + for i in range(size): + temp_buffer_size = func(self.model_desc, i) + temp_buffer, ret = acl.rt.malloc(temp_buffer_size, ACL_MEM_MALLOC_HUGE_FIRST) + check_ret("acl.rt.malloc", ret) + + if des == "in": + self.input_data.append({"buffer": temp_buffer, + "size": temp_buffer_size}) + elif des == "out": + self.output_data.append({"buffer": temp_buffer, + "size": temp_buffer_size}) + + + def _gen_dataset_output_host(self, size, des): + func = buffer_method[des] + for i in range(size): + temp_buffer_size = func(self.model_desc, i) + temp_buffer, ret = acl.rt.malloc_host(temp_buffer_size) + check_ret("acl.rt.malloc_host", ret) + + self.output_data_host.append({"buffer": temp_buffer, + "size": temp_buffer_size}) + + + def _data_interaction(self, dataset, policy=ACL_MEMCPY_HOST_TO_DEVICE): + temp_data_buffer = self.input_data \ + if policy == ACL_MEMCPY_HOST_TO_DEVICE \ + else self.output_data + output_malloc_cost = 0 + idx = 0 + + if len(dataset) == 0 and policy == ACL_MEMCPY_DEVICE_TO_HOST: + dataset = self.output_data_host + + for i, item in enumerate(temp_data_buffer): + if policy == ACL_MEMCPY_HOST_TO_DEVICE: + ptr = acl.util.numpy_to_ptr(dataset[i]) + ret = acl.rt.memcpy(item["buffer"], item["size"], ptr, item["size"], policy) + check_ret("acl.rt.memcpy", ret) + + else: + ptr = dataset[i]["buffer"] + ret = acl.rt.memcpy(ptr, item["size"], item["buffer"], item["size"], policy) + check_ret("acl.rt.memcpy", ret) + + + def _gen_dataset(self, type_str="input"): + dataset = acl.mdl.create_dataset() + + temp_dataset = None + if type_str == "in": + self.load_input_dataset = dataset + temp_dataset = self.input_data + else: + self.load_output_dataset = dataset + temp_dataset = self.output_data + + for item in temp_dataset: + data = acl.create_data_buffer(item["buffer"], item["size"]) + if data is None: + ret = acl.destroy_data_buffer(dataset) + check_ret("acl.destroy_data_buffer", ret) + + _, ret = acl.mdl.add_dataset_buffer(dataset, data) + if ret != ACL_ERROR_NONE: + ret = acl.destroy_data_buffer(dataset) + check_ret("acl.destroy_data_buffer", ret) + + + def _data_from_host_to_device(self, images): + self._data_interaction(images, ACL_MEMCPY_HOST_TO_DEVICE) + self._gen_dataset("in") + self._gen_dataset("out") + + + def _data_from_device_to_host(self): + res = [] + self._data_interaction(res, ACL_MEMCPY_DEVICE_TO_HOST) + output = self.get_result(self.output_data_host) + return output + + + def _destroy_databuffer(self): + for dataset in [self.load_input_dataset, self.load_output_dataset]: + if not dataset: + continue + + num = acl.mdl.get_dataset_num_buffers(dataset) + for i in range(num): + data_buf = acl.mdl.get_dataset_buffer(dataset, i) + if data_buf: + ret = acl.destroy_data_buffer(data_buf) + check_ret("acl.destroy_data_buffer", ret) + ret = acl.mdl.destroy_dataset(dataset) + check_ret("acl.mdl.destroy_dataset", ret) + + def forward(self, input_data): + if not isinstance(input_data, (list, tuple)): + input_data = [input_data] + + self._data_from_host_to_device(input_data) + ret = acl.mdl.execute(self.model_id, self.load_input_dataset, self.load_output_dataset) + check_ret("acl.mdl.execute", ret) + + self._destroy_databuffer() + result = self._data_from_device_to_host() + return result + + + def get_result(self, output_data): + dataset = [] + for i in range(len(output_data)): + dims, ret = acl.mdl.get_cur_output_dims(self.model_desc, i) + check_ret("acl.mdl.get_cur_output_dims", ret) + + data_shape = dims.get("dims") + data_type = acl.mdl.get_output_data_type(self.model_desc, i) + data_len = functools.reduce(lambda x, y: x * y, data_shape) + ftype = np.dtype(ACL_DTYPE.get(data_type)) + + size = output_data[i]["size"] + ptr = output_data[i]["buffer"] + data = acl.util.ptr_to_numpy(ptr, (size,), 1) + np_array = np.frombuffer(bytearray(data[:data_len * ftype.itemsize]), dtype=ftype, count=data_len) + np_array = np_array.reshape(data_shape) + dataset.append(np_array) + return dataset diff --git a/ACL_PyTorch/contrib/cv/video_understanding/I3D/i3d_inference.py b/ACL_PyTorch/contrib/cv/video_understanding/I3D/i3d_inference.py index 6fa45cf9b4..7b9e49a7b9 100644 --- a/ACL_PyTorch/contrib/cv/video_understanding/I3D/i3d_inference.py +++ b/ACL_PyTorch/contrib/cv/video_understanding/I3D/i3d_inference.py @@ -1,203 +1,203 @@ -# ============================================================================ -# Copyright 2018-2019 Open-MMLab. All rights reserved. -# Apache License -# Version 2.0, January 2004 -# http://www.apache.org/licenses/ -# -# TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -# 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. -# ============================================================================ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import os -import os.path as osp -import warnings -import numpy as np -from sys import path -path.append('/home/mmaction2-20') - -import mmcv -import torch -import torch.nn.functional as F -from mmcv import Config, DictAction -from mmcv.cnn import fuse_conv_bn -from mmcv.fileio.io import file_handlers -from mmcv.parallel import MMDataParallel, MMDistributedDataParallel -from mmcv.runner import get_dist_info, init_dist, load_checkpoint -from mmcv.runner.fp16_utils import wrap_fp16_model - -from mmaction.datasets import build_dataloader, build_dataset -from mmaction.models import build_model -from mmaction.utils import register_module_hooks - -from acl_net import Net -import acl - - - -def parse_args(): - parser = argparse.ArgumentParser( - description='i3d inference') - parser.add_argument('config', help='test config file path') - parser.add_argument( - '--out', - default=None, - help='output result file in pkl/yaml/json format') - parser.add_argument( - '--eval', - type=str, - nargs='+', - help='evaluation metrics, which depends on the dataset, e.g.,' - ' "top_k_accuracy", "mean_class_accuracy" for video dataset') - parser.add_argument( - '-bs', '--batch_size', type=int, default=1, - help='batch size') - parser.add_argument( - '--device_id', type=int, default=1, - help='device id') - parser.add_argument( - '--model', required=True, type=str, - help='i3d.om') - args = parser.parse_args() - - return args - -def check_ret(message, ret): - if ret != 0: - raise Exception("{} failed ret = {}".format(message, ret)) - - -class I3d(): - def __init__(self, device_id, model) -> None: - ret = acl.init() - check_ret("acl.init failed", ret) - ret = acl.rt.set_device(device_id) - check_ret("acl.rt.set_device failed", ret) - context, ret = acl.rt.create_context(device_id) - check_ret("acl.rt.create_context failed", ret) - self.device_id = device_id - - self.i3d_context = Net(context, model_path=model, device_id=device_id, first=True) - - def __del__(self): - del self.i3d_context - - ret = acl.rt.reset_device(self.device_id) - check_ret("acl.rt.reset_device failed", ret) - context, ret = acl.rt.get_context() - check_ret("acl.rt.get_context failed", ret) - ret = acl.rt.destroy_context(context) - check_ret("acl.rt.destroy_context failed", ret) - ret = acl.finalize() - check_ret("acl.finalize failed", ret) - - def inference(self, data_loader): - results = [] - dataset = data_loader.dataset - prog_bar = mmcv.ProgressBar(len(dataset)) - for data in data_loader: - input_data = np.array(data['imgs']) - result = self.i3d_context([input_data]) - result = torch.from_numpy(np.array(result)) - batch_size = result.shape[1] - result = result.view(result.shape[0], batch_size, -1) - result = F.softmax(result, dim=2).mean(dim=1) - result = result.numpy() - results.extend(result) - - batch_size = len(result) - for _ in range(batch_size): - prog_bar.update() - - return results - - - -def main(): - args = parse_args() - - cfg = Config.fromfile(args.config) - - # Load output_config from cfg - output_config = cfg.get('output_config', {}) - if args.out: - # Overwrite output_config from args.out - output_config = Config._merge_a_into_b( - dict(out=args.out), output_config) - - # Load eval_config from cfg - eval_config = cfg.get('eval_config', {}) - if args.eval: - # Overwrite eval_config from args.eval - eval_config = Config._merge_a_into_b( - dict(metrics=args.eval), eval_config) - - dataset_type = cfg.data.test.type - if output_config.get('out', None): - if 'output_format' in output_config: - # ugly workround to make recognition and localization the same - warnings.warn( - 'Skip checking `output_format` in localization task.') - else: - out = output_config['out'] - # make sure the dirname of the output path exists - mmcv.mkdir_or_exist(osp.dirname(out)) - _, suffix = osp.splitext(out) - if dataset_type == 'AVADataset': - assert suffix[1:] == 'csv', ('For AVADataset, the format of ' - 'the output file should be csv') - else: - assert suffix[1:] in file_handlers, ( - 'The format of the output ' - 'file should be json, pickle or yaml') - - cfg.data.test.test_mode = True - - # The flag is used to register module's hooks - cfg.setdefault('module_hooks', []) - - # build the dataloader - dataset = build_dataset(cfg.data.test, dict(test_mode=True)) - dataloader_setting = dict( - videos_per_gpu=args.batch_size, - workers_per_gpu=1, - dist=False, - shuffle=False) - dataloader_setting = dict(dataloader_setting, - **cfg.data.get('test_dataloader', {})) - data_loader = build_dataloader(dataset, **dataloader_setting) - - i3d = I3d(args.device_id, args.model) - outputs = i3d.inference(data_loader) - - rank, _ = get_dist_info() - if rank == 0: - if output_config.get('out', None): - out = output_config['out'] - print(f'\nwriting results to {out}') - dataset.dump_results(outputs, **output_config) - if eval_config: - eval_res = dataset.evaluate(outputs, **eval_config) - for name, val in eval_res.items(): - print(f'{name}: {val:.04f}') - - -if __name__ == '__main__': - main() +# ============================================================================ +# Copyright 2018-2019 Open-MMLab. All rights reserved. +# Apache License +# Version 2.0, January 2004 +# http://www.apache.org/licenses/ +# +# TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +# 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. +# ============================================================================ +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import os +import os.path as osp +import warnings +import numpy as np +from sys import path +path.append('/home/mmaction2-20') + +import mmcv +import torch +import torch.nn.functional as F +from mmcv import Config, DictAction +from mmcv.cnn import fuse_conv_bn +from mmcv.fileio.io import file_handlers +from mmcv.parallel import MMDataParallel, MMDistributedDataParallel +from mmcv.runner import get_dist_info, init_dist, load_checkpoint +from mmcv.runner.fp16_utils import wrap_fp16_model + +from mmaction.datasets import build_dataloader, build_dataset +from mmaction.models import build_model +from mmaction.utils import register_module_hooks + +from acl_net import Net +import acl + + + +def parse_args(): + parser = argparse.ArgumentParser( + description='i3d inference') + parser.add_argument('config', help='test config file path') + parser.add_argument( + '--out', + default=None, + help='output result file in pkl/yaml/json format') + parser.add_argument( + '--eval', + type=str, + nargs='+', + help='evaluation metrics, which depends on the dataset, e.g.,' + ' "top_k_accuracy", "mean_class_accuracy" for video dataset') + parser.add_argument( + '-bs', '--batch_size', type=int, default=1, + help='batch size') + parser.add_argument( + '--device_id', type=int, default=1, + help='device id') + parser.add_argument( + '--model', required=True, type=str, + help='i3d.om') + args = parser.parse_args() + + return args + +def check_ret(message, ret): + if ret != 0: + raise Exception("{} failed ret = {}".format(message, ret)) + + +class I3d(): + def __init__(self, device_id, model) -> None: + ret = acl.init() + check_ret("acl.init failed", ret) + ret = acl.rt.set_device(device_id) + check_ret("acl.rt.set_device failed", ret) + context, ret = acl.rt.create_context(device_id) + check_ret("acl.rt.create_context failed", ret) + self.device_id = device_id + + self.i3d_context = Net(context, model_path=model, device_id=device_id, first=True) + + def __del__(self): + del self.i3d_context + + ret = acl.rt.reset_device(self.device_id) + check_ret("acl.rt.reset_device failed", ret) + context, ret = acl.rt.get_context() + check_ret("acl.rt.get_context failed", ret) + ret = acl.rt.destroy_context(context) + check_ret("acl.rt.destroy_context failed", ret) + ret = acl.finalize() + check_ret("acl.finalize failed", ret) + + def inference(self, data_loader): + results = [] + dataset = data_loader.dataset + prog_bar = mmcv.ProgressBar(len(dataset)) + for data in data_loader: + input_data = np.array(data['imgs']) + result = self.i3d_context([input_data]) + result = torch.from_numpy(np.array(result)) + batch_size = result.shape[1] + result = result.view(result.shape[0], batch_size, -1) + result = F.softmax(result, dim=2).mean(dim=1) + result = result.numpy() + results.extend(result) + + batch_size = len(result) + for _ in range(batch_size): + prog_bar.update() + + return results + + + +def main(): + args = parse_args() + + cfg = Config.fromfile(args.config) + + # Load output_config from cfg + output_config = cfg.get('output_config', {}) + if args.out: + # Overwrite output_config from args.out + output_config = Config._merge_a_into_b( + dict(out=args.out), output_config) + + # Load eval_config from cfg + eval_config = cfg.get('eval_config', {}) + if args.eval: + # Overwrite eval_config from args.eval + eval_config = Config._merge_a_into_b( + dict(metrics=args.eval), eval_config) + + dataset_type = cfg.data.test.type + if output_config.get('out', None): + if 'output_format' in output_config: + # ugly workround to make recognition and localization the same + warnings.warn( + 'Skip checking `output_format` in localization task.') + else: + out = output_config['out'] + # make sure the dirname of the output path exists + mmcv.mkdir_or_exist(osp.dirname(out)) + _, suffix = osp.splitext(out) + if dataset_type == 'AVADataset': + assert suffix[1:] == 'csv', ('For AVADataset, the format of ' + 'the output file should be csv') + else: + assert suffix[1:] in file_handlers, ( + 'The format of the output ' + 'file should be json, pickle or yaml') + + cfg.data.test.test_mode = True + + # The flag is used to register module's hooks + cfg.setdefault('module_hooks', []) + + # build the dataloader + dataset = build_dataset(cfg.data.test, dict(test_mode=True)) + dataloader_setting = dict( + videos_per_gpu=args.batch_size, + workers_per_gpu=1, + dist=False, + shuffle=False) + dataloader_setting = dict(dataloader_setting, + **cfg.data.get('test_dataloader', {})) + data_loader = build_dataloader(dataset, **dataloader_setting) + + i3d = I3d(args.device_id, args.model) + outputs = i3d.inference(data_loader) + + rank, _ = get_dist_info() + if rank == 0: + if output_config.get('out', None): + out = output_config['out'] + print(f'\nwriting results to {out}') + dataset.dump_results(outputs, **output_config) + if eval_config: + eval_res = dataset.evaluate(outputs, **eval_config) + for name, val in eval_res.items(): + print(f'{name}: {val:.04f}') + + +if __name__ == '__main__': + main() diff --git a/ACL_PyTorch/contrib/cv/video_understanding/TSN/LICENSE b/ACL_PyTorch/contrib/cv/video_understanding/TSN/LICENSE index b57dcc3003..108309f324 100644 --- a/ACL_PyTorch/contrib/cv/video_understanding/TSN/LICENSE +++ b/ACL_PyTorch/contrib/cv/video_understanding/TSN/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +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. \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/video_understanding/TSN/README.md b/ACL_PyTorch/contrib/cv/video_understanding/TSN/README.md index 3b2bb4f94c..b8c6ccf3dd 100644 --- a/ACL_PyTorch/contrib/cv/video_understanding/TSN/README.md +++ b/ACL_PyTorch/contrib/cv/video_understanding/TSN/README.md @@ -1,96 +1,96 @@ -# 基于开源mmaction2预训练的TSN模型端到端推理指导 - -## 1 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 - -```shell -pip3.7 install -r requirements.txt -``` - -2.获取,修改与安装开源模型代码 - -```shell -git clone https://github.com/open-mmlab/mmaction2.git -cd mmaction2 -git checkout 9ab8c2af52c561e5c789ccaf7b62f4b7679c103c -pip install -r requirements/build.txt -pip install -v -e . -cd .. -``` - - -3.获取权重文件 - -需要获取tsn_r50_1x1x3_75e_ucf101_rgb/tsn_r50_1x1x3_75e_ucf101_rgb_20201023-d85ab600.pth文件,请参考文档。 - -4.数据集 - -该模型使用UCF101的验证集进行测试,数据集下载步骤如下 - -```shell -cd ./mmaction2/tools/data/ucf101 -bash download_annotations.sh -bash download_videos.sh -bash extract_rgb_frames_opencv.sh -bash generate_videos_filelist.sh -bash generate_rawframes_filelist.sh -``` - -(可选)本项目默认将数据集存放于/opt/npu/ - -```shell -cd .. -mv /ucf101 /opt/npu/ -``` - -5.[获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) - 将benchmark.x86_64或benchmark.aarch64放到当前目录 - -6.使用msame工具推理 -1.首先需要获取msame工具 - -```shell -git clone https://gitee.com/ascend/tools.git -``` - -2.而后安装msame工具 - -```shell -export DDK_PATH=/usr/local/Ascend/ascend-toolkit/latest -export NPU_HOST_LIB=/usr/local/Ascend/ascend-toolkit/latest/acllib/lib64/stub -cd ./tools/msame -./build.sh g++ ./ -cd ../.. -``` - -3.增加执行权限 - -```shell -chmod u+x ./tools/msame/out/msame -``` - - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 - -``` -#OM model generation -bash test/pth2om.sh - -#OM model inference -bash test/eval_acc_perf.sh --datasets_path=/root/datasets - -#gpu inference -bash test/perf_gpu.sh -``` - -**评测结果:** - -| 模型 | pth精度 | 310精度 | 性能基准 | 310性能 | -| :------: | :------: | :------: | :------: | :------: | -| TSN bs1 | top1:83.03%| top1:82.84%| 22.63fps | 23.43fps | -| TSN bs4 | top1:83.03%| top1:82.84%| 21.96fps | 24.41fps | -| TSN bs8 | top1:83.03%| top1:82.84%| 22.18fps | 24.68fps | - +# 基于开源mmaction2预训练的TSN模型端到端推理指导 + +## 1 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 + +```shell +pip3.7 install -r requirements.txt +``` + +2.获取,修改与安装开源模型代码 + +```shell +git clone https://github.com/open-mmlab/mmaction2.git +cd mmaction2 +git checkout 9ab8c2af52c561e5c789ccaf7b62f4b7679c103c +pip install -r requirements/build.txt +pip install -v -e . +cd .. +``` + + +3.获取权重文件 + +需要获取tsn_r50_1x1x3_75e_ucf101_rgb/tsn_r50_1x1x3_75e_ucf101_rgb_20201023-d85ab600.pth文件,请参考文档。 + +4.数据集 + +该模型使用UCF101的验证集进行测试,数据集下载步骤如下 + +```shell +cd ./mmaction2/tools/data/ucf101 +bash download_annotations.sh +bash download_videos.sh +bash extract_rgb_frames_opencv.sh +bash generate_videos_filelist.sh +bash generate_rawframes_filelist.sh +``` + +(可选)本项目默认将数据集存放于/opt/npu/ + +```shell +cd .. +mv /ucf101 /opt/npu/ +``` + +5.[获取benchmark工具](https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software/) + 将benchmark.x86_64或benchmark.aarch64放到当前目录 + +6.使用msame工具推理 +1.首先需要获取msame工具 + +```shell +git clone https://gitee.com/ascend/tools.git +``` + +2.而后安装msame工具 + +```shell +export DDK_PATH=/usr/local/Ascend/ascend-toolkit/latest +export NPU_HOST_LIB=/usr/local/Ascend/ascend-toolkit/latest/acllib/lib64/stub +cd ./tools/msame +./build.sh g++ ./ +cd ../.. +``` + +3.增加执行权限 + +```shell +chmod u+x ./tools/msame/out/msame +``` + + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 + +``` +#OM model generation +bash test/pth2om.sh + +#OM model inference +bash test/eval_acc_perf.sh --datasets_path=/root/datasets + +#gpu inference +bash test/perf_gpu.sh +``` + +**评测结果:** + +| 模型 | pth精度 | 310精度 | 性能基准 | 310性能 | +| :------: | :------: | :------: | :------: | :------: | +| TSN bs1 | top1:83.03%| top1:82.84%| 22.63fps | 23.43fps | +| TSN bs4 | top1:83.03%| top1:82.84%| 21.96fps | 24.41fps | +| TSN bs8 | top1:83.03%| top1:82.84%| 22.18fps | 24.68fps | + diff --git a/ACL_PyTorch/contrib/cv/video_understanding/TSN/modelzoo_level.txt b/ACL_PyTorch/contrib/cv/video_understanding/TSN/modelzoo_level.txt index 403465b84e..ec6168981c 100644 --- a/ACL_PyTorch/contrib/cv/video_understanding/TSN/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/cv/video_understanding/TSN/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus:Perfect \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/video_understanding/TSN/pytorch2onnx.py b/ACL_PyTorch/contrib/cv/video_understanding/TSN/pytorch2onnx.py index 0bf774f4a6..911dc55734 100644 --- a/ACL_PyTorch/contrib/cv/video_understanding/TSN/pytorch2onnx.py +++ b/ACL_PyTorch/contrib/cv/video_understanding/TSN/pytorch2onnx.py @@ -1,193 +1,193 @@ -""" -Copyright 2020 Huawei Technologies Co., Ltd - -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. -============================================================================ -""" -# !/usr/bin/env python -# -*- coding: utf-8 -*- - -import argparse - -import mmcv -import numpy as np -import torch -from mmcv.runner import load_checkpoint - -from mmaction.models import build_model - -try: - import onnx - import onnxruntime as rt -except ImportError as e: - raise ImportError(f'Please install onnx and onnxruntime first. {e}') - -try: - from mmcv.onnx.symbolic import register_extra_symbolics -except ModuleNotFoundError: - raise NotImplementedError('please update mmcv to version>=1.0.4') - - -def _convert_batchnorm(module): - """Convert the syncBNs into normal BN3ds.""" - module_output = module - if isinstance(module, torch.nn.SyncBatchNorm): - module_output = torch.nn.BatchNorm3d(module.num_features, module.eps, - module.momentum, module.affine, - module.track_running_stats) - if module.affine: - module_output.weight.data = module.weight.data.clone().detach() - module_output.bias.data = module.bias.data.clone().detach() - # keep requires_grad unchanged - module_output.weight.requires_grad = module.weight.requires_grad - module_output.bias.requires_grad = module.bias.requires_grad - module_output.running_mean = module.running_mean - module_output.running_var = module.running_var - module_output.num_batches_tracked = module.num_batches_tracked - for name, child in module.named_children(): - module_output.add_module(name, _convert_batchnorm(child)) - del module - return module_output - - -def pytorch2onnx(model, - input_shape, - opset_version=11, - show=False, - output_file='tmp.onnx', - verify=False): - """Convert pytorch model to onnx model. - - Args: - model (:obj:`nn.Module`): The pytorch model to be exported. - input_shape (tuple[int]): The input tensor shape of the model. - opset_version (int): Opset version of onnx used. Default: 11. - show (bool): Determines whether to print the onnx model architecture. - Default: False. - output_file (str): Output onnx model name. Default: 'tmp.onnx'. - verify (bool): Determines whether to verify the onnx model. - Default: False. - """ - model.cpu().eval() - - input_tensor = torch.randn(input_shape) - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - register_extra_symbolics(opset_version) - torch.onnx.export( - model, - input_tensor, - output_file, - input_names=input_names, - dynamic_axes=dynamic_axes, - output_names=output_names, - export_params=True, - keep_initializers_as_inputs=True, - verbose=show, - opset_version=11) - - print(f'Successfully exported ONNX model: {output_file}') - if verify: - # check by onnx - onnx_model = onnx.load(output_file) - onnx.checker.check_model(onnx_model) - - # check the numerical value - # get pytorch output - pytorch_result = model(input_tensor)[0].detach().numpy() - - # get onnx output - input_all = [node.name for node in onnx_model.graph.input] - input_initializer = [ - node.name for node in onnx_model.graph.initializer - ] - net_feed_input = list(set(input_all) - set(input_initializer)) - assert len(net_feed_input) == 1 - sess = rt.InferenceSession(output_file) - onnx_result = sess.run( - None, {net_feed_input[0]: input_tensor.detach().numpy()})[0] - # only compare part of results - random_class = np.random.randint(pytorch_result.shape[1]) - assert np.allclose( - pytorch_result[:, random_class], onnx_result[:, random_class] - ), 'The outputs are different between Pytorch and ONNX' - print('The numerical values are same between Pytorch and ONNX') - - -def parse_args(): - parser = argparse.ArgumentParser( - description='Convert MMAction2 models to ONNX') - parser.add_argument('config', help='test config file path', default='./mmaction2/configs/recognition/tsn/tsn_r50_1x1x3_75e_ucf101_rgb.py') - parser.add_argument('checkpoint', help='checkpoint file', default='./result_1p/tsn_r50_1x1x3_75e_ucf101_rgb.py') - parser.add_argument('--show', action='store_true', help='show onnx graph') - parser.add_argument('--output-file', type=str, default='tsn.onnx') - parser.add_argument('--opset-version', type=int, default=11) - parser.add_argument( - '--verify', - action='store_true', - help='verify the onnx model output against pytorch output') - parser.add_argument( - '--is-localizer', - action='store_true', - help='whether it is a localizer') - parser.add_argument( - '--shape', - type=int, - nargs='+', - default=[1, 75, 3, 256, 256], - help='input video size') - parser.add_argument( - '--softmax', - action='store_true', - help='wheter to add softmax layer at the end of recognizers') - args = parser.parse_args() - return args - - -if __name__ == '__main__': - args = parse_args() - - assert args.opset_version == 11, 'MMAction2 only supports opset 11 now' - - cfg = mmcv.Config.fromfile(args.config) - # import modules from string list. - - if not args.is_localizer: - cfg.model.backbone.pretrained = None - - # build the model - model = build_model( - cfg.model, train_cfg=None, test_cfg=cfg.get('test_cfg')) - model = _convert_batchnorm(model) - - # onnx.export does not support kwargs - if hasattr(model, 'forward_dummy'): - from functools import partial - model.forward = partial(model.forward_dummy, softmax=args.softmax) - elif hasattr(model, '_forward') and args.is_localizer: - model.forward = model._forward - else: - raise NotImplementedError( - 'Please implement the forward method for exporting.') - - checkpoint = load_checkpoint(model, args.checkpoint, map_location='cpu') - - # conver model to onnx file - pytorch2onnx( - model, - args.shape, - opset_version=args.opset_version, - show=args.show, - output_file=args.output_file, +""" +Copyright 2020 Huawei Technologies Co., Ltd + +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. +============================================================================ +""" +# !/usr/bin/env python +# -*- coding: utf-8 -*- + +import argparse + +import mmcv +import numpy as np +import torch +from mmcv.runner import load_checkpoint + +from mmaction.models import build_model + +try: + import onnx + import onnxruntime as rt +except ImportError as e: + raise ImportError(f'Please install onnx and onnxruntime first. {e}') + +try: + from mmcv.onnx.symbolic import register_extra_symbolics +except ModuleNotFoundError: + raise NotImplementedError('please update mmcv to version>=1.0.4') + + +def _convert_batchnorm(module): + """Convert the syncBNs into normal BN3ds.""" + module_output = module + if isinstance(module, torch.nn.SyncBatchNorm): + module_output = torch.nn.BatchNorm3d(module.num_features, module.eps, + module.momentum, module.affine, + module.track_running_stats) + if module.affine: + module_output.weight.data = module.weight.data.clone().detach() + module_output.bias.data = module.bias.data.clone().detach() + # keep requires_grad unchanged + module_output.weight.requires_grad = module.weight.requires_grad + module_output.bias.requires_grad = module.bias.requires_grad + module_output.running_mean = module.running_mean + module_output.running_var = module.running_var + module_output.num_batches_tracked = module.num_batches_tracked + for name, child in module.named_children(): + module_output.add_module(name, _convert_batchnorm(child)) + del module + return module_output + + +def pytorch2onnx(model, + input_shape, + opset_version=11, + show=False, + output_file='tmp.onnx', + verify=False): + """Convert pytorch model to onnx model. + + Args: + model (:obj:`nn.Module`): The pytorch model to be exported. + input_shape (tuple[int]): The input tensor shape of the model. + opset_version (int): Opset version of onnx used. Default: 11. + show (bool): Determines whether to print the onnx model architecture. + Default: False. + output_file (str): Output onnx model name. Default: 'tmp.onnx'. + verify (bool): Determines whether to verify the onnx model. + Default: False. + """ + model.cpu().eval() + + input_tensor = torch.randn(input_shape) + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + register_extra_symbolics(opset_version) + torch.onnx.export( + model, + input_tensor, + output_file, + input_names=input_names, + dynamic_axes=dynamic_axes, + output_names=output_names, + export_params=True, + keep_initializers_as_inputs=True, + verbose=show, + opset_version=11) + + print(f'Successfully exported ONNX model: {output_file}') + if verify: + # check by onnx + onnx_model = onnx.load(output_file) + onnx.checker.check_model(onnx_model) + + # check the numerical value + # get pytorch output + pytorch_result = model(input_tensor)[0].detach().numpy() + + # get onnx output + input_all = [node.name for node in onnx_model.graph.input] + input_initializer = [ + node.name for node in onnx_model.graph.initializer + ] + net_feed_input = list(set(input_all) - set(input_initializer)) + assert len(net_feed_input) == 1 + sess = rt.InferenceSession(output_file) + onnx_result = sess.run( + None, {net_feed_input[0]: input_tensor.detach().numpy()})[0] + # only compare part of results + random_class = np.random.randint(pytorch_result.shape[1]) + assert np.allclose( + pytorch_result[:, random_class], onnx_result[:, random_class] + ), 'The outputs are different between Pytorch and ONNX' + print('The numerical values are same between Pytorch and ONNX') + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Convert MMAction2 models to ONNX') + parser.add_argument('config', help='test config file path', default='./mmaction2/configs/recognition/tsn/tsn_r50_1x1x3_75e_ucf101_rgb.py') + parser.add_argument('checkpoint', help='checkpoint file', default='./result_1p/tsn_r50_1x1x3_75e_ucf101_rgb.py') + parser.add_argument('--show', action='store_true', help='show onnx graph') + parser.add_argument('--output-file', type=str, default='tsn.onnx') + parser.add_argument('--opset-version', type=int, default=11) + parser.add_argument( + '--verify', + action='store_true', + help='verify the onnx model output against pytorch output') + parser.add_argument( + '--is-localizer', + action='store_true', + help='whether it is a localizer') + parser.add_argument( + '--shape', + type=int, + nargs='+', + default=[1, 75, 3, 256, 256], + help='input video size') + parser.add_argument( + '--softmax', + action='store_true', + help='wheter to add softmax layer at the end of recognizers') + args = parser.parse_args() + return args + + +if __name__ == '__main__': + args = parse_args() + + assert args.opset_version == 11, 'MMAction2 only supports opset 11 now' + + cfg = mmcv.Config.fromfile(args.config) + # import modules from string list. + + if not args.is_localizer: + cfg.model.backbone.pretrained = None + + # build the model + model = build_model( + cfg.model, train_cfg=None, test_cfg=cfg.get('test_cfg')) + model = _convert_batchnorm(model) + + # onnx.export does not support kwargs + if hasattr(model, 'forward_dummy'): + from functools import partial + model.forward = partial(model.forward_dummy, softmax=args.softmax) + elif hasattr(model, '_forward') and args.is_localizer: + model.forward = model._forward + else: + raise NotImplementedError( + 'Please implement the forward method for exporting.') + + checkpoint = load_checkpoint(model, args.checkpoint, map_location='cpu') + + # conver model to onnx file + pytorch2onnx( + model, + args.shape, + opset_version=args.opset_version, + show=args.show, + output_file=args.output_file, verify=args.verify) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/video_understanding/TSN/requirements.txt b/ACL_PyTorch/contrib/cv/video_understanding/TSN/requirements.txt index bbd1fe6360..209cb57ec6 100644 --- a/ACL_PyTorch/contrib/cv/video_understanding/TSN/requirements.txt +++ b/ACL_PyTorch/contrib/cv/video_understanding/TSN/requirements.txt @@ -1,12 +1,12 @@ -einops==0.3.0 -mmcv==1.3.9 -numpy==1.21.0 -onnx==1.9.0 -onnx-simplifier==0.3.6 -onnxoptimizer==0.2.6 -onnxruntime==1.8.1 -opencv-contrib-python==4.5.3.56 -opencv-python==4.5.3.56 -scipy==1.7.0 -torch==1.5.0 +einops==0.3.0 +mmcv==1.3.9 +numpy==1.21.0 +onnx==1.9.0 +onnx-simplifier==0.3.6 +onnxoptimizer==0.2.6 +onnxruntime==1.8.1 +opencv-contrib-python==4.5.3.56 +opencv-python==4.5.3.56 +scipy==1.7.0 +torch==1.5.0 torchvision==0.10.0 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/video_understanding/TSN/test/eval_acc_perf.sh b/ACL_PyTorch/contrib/cv/video_understanding/TSN/test/eval_acc_perf.sh index 895c63c813..b1e35487f3 100644 --- a/ACL_PyTorch/contrib/cv/video_understanding/TSN/test/eval_acc_perf.sh +++ b/ACL_PyTorch/contrib/cv/video_understanding/TSN/test/eval_acc_perf.sh @@ -1,74 +1,74 @@ -#!/bin/bash - -datasets_path="/opt/npu/" - -for para in $* -do - if [[ $para == --datasets_path* ]]; then - datasets_path=`echo ${para#*=}` - fi -done - -python3.7 tsn_ucf101_preprocess.py --batch_size 1 --data_root ${datasets_path}/ucf101 --name out_bin_1 -if [ $? != 0 ]; then - echo "fail!" - exit -1 -fi -python3.7 tsn_ucf101_preprocess.py --batch_size 8 --data_root ${datasets_path}/ucf101 --name out_bin_8 -if [ $? != 0 ]; then - echo "fail!" - exit -1 -fi - -source env.sh -mkdir -p output/out_bs1 -rm -rf output/out_bs1/* -./tools/msame/out/msame --model ./om/tsn_1.om --input /opt/npu/ucf101/out_bin_1 --output ./output/out_bs1/ --outfmt TXT -if [ $? != 0 ]; then - echo "fail!" - exit -1 -fi -mkdir -p output/out_bs8 -rm -rf output/out_bs8/* -./tools/msame/out/msame --model ./om/tsn_8.om --input /opt/npu/ucf101/out_bin_8 --output ./output/out_bs8/ --outfmt TXT -if [ $? != 0 ]; then - echo "fail!" - exit -1 -fi - -mkdir -p result -./benchmark.x86_64 -round=20 -om_path=./om/tsn_1.om -device_id=0 -batch_size=1 -if [ $? != 0 ]; then - echo "fail!" - exit -1 -fi -./benchmark.x86_64 -round=20 -om_path=./om/tsn_8.om -device_id=0 -batch_size=8 -if [ $? != 0 ]; then - echo "fail!" - exit -1 -fi - -echo "====accuracy data====" -python3.7 tsn_ucf101_postprocess.py --result_path ./output/out_bs1 --info_path ${datasets_path}/ucf101/ucf101_1.info --batch_size 1 -if [ $? != 0 ]; then - echo "fail!" - exit -1 -fi -python3.7 tsn_ucf101_postprocess.py --result_path ./output/out_bs8 --info_path ${datasets_path}/ucf101/ucf101_8.info --batch_size 8 -if [ $? != 0 ]; then - echo "fail!" - exit -1 -fi - -echo "====performance data====" -python3.7 test/parse.py result/PureInfer_perf_of_tsn_1_in_device_0.txt -if [ $? != 0 ]; then - echo "fail!" - exit -1 -fi -python3.7 test/parse.py result/PureInfer_perf_of_tsn_8_in_device_0.txt -if [ $? != 0 ]; then - echo "fail!" - exit -1 -fi +#!/bin/bash + +datasets_path="/opt/npu/" + +for para in $* +do + if [[ $para == --datasets_path* ]]; then + datasets_path=`echo ${para#*=}` + fi +done + +python3.7 tsn_ucf101_preprocess.py --batch_size 1 --data_root ${datasets_path}/ucf101 --name out_bin_1 +if [ $? != 0 ]; then + echo "fail!" + exit -1 +fi +python3.7 tsn_ucf101_preprocess.py --batch_size 8 --data_root ${datasets_path}/ucf101 --name out_bin_8 +if [ $? != 0 ]; then + echo "fail!" + exit -1 +fi + +source env.sh +mkdir -p output/out_bs1 +rm -rf output/out_bs1/* +./tools/msame/out/msame --model ./om/tsn_1.om --input /opt/npu/ucf101/out_bin_1 --output ./output/out_bs1/ --outfmt TXT +if [ $? != 0 ]; then + echo "fail!" + exit -1 +fi +mkdir -p output/out_bs8 +rm -rf output/out_bs8/* +./tools/msame/out/msame --model ./om/tsn_8.om --input /opt/npu/ucf101/out_bin_8 --output ./output/out_bs8/ --outfmt TXT +if [ $? != 0 ]; then + echo "fail!" + exit -1 +fi + +mkdir -p result +./benchmark.x86_64 -round=20 -om_path=./om/tsn_1.om -device_id=0 -batch_size=1 +if [ $? != 0 ]; then + echo "fail!" + exit -1 +fi +./benchmark.x86_64 -round=20 -om_path=./om/tsn_8.om -device_id=0 -batch_size=8 +if [ $? != 0 ]; then + echo "fail!" + exit -1 +fi + +echo "====accuracy data====" +python3.7 tsn_ucf101_postprocess.py --result_path ./output/out_bs1 --info_path ${datasets_path}/ucf101/ucf101_1.info --batch_size 1 +if [ $? != 0 ]; then + echo "fail!" + exit -1 +fi +python3.7 tsn_ucf101_postprocess.py --result_path ./output/out_bs8 --info_path ${datasets_path}/ucf101/ucf101_8.info --batch_size 8 +if [ $? != 0 ]; then + echo "fail!" + exit -1 +fi + +echo "====performance data====" +python3.7 test/parse.py result/PureInfer_perf_of_tsn_1_in_device_0.txt +if [ $? != 0 ]; then + echo "fail!" + exit -1 +fi +python3.7 test/parse.py result/PureInfer_perf_of_tsn_8_in_device_0.txt +if [ $? != 0 ]; then + echo "fail!" + exit -1 +fi echo "success" \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/video_understanding/TSN/test/parse.py b/ACL_PyTorch/contrib/cv/video_understanding/TSN/test/parse.py index bc45f3df18..9a9507ebec 100644 --- a/ACL_PyTorch/contrib/cv/video_understanding/TSN/test/parse.py +++ b/ACL_PyTorch/contrib/cv/video_understanding/TSN/test/parse.py @@ -1,37 +1,37 @@ -""" -Copyright 2020 Huawei Technologies Co., Ltd - -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 sys -import re - -if __name__ == '__main__': - result_txt = sys.argv[1] - if 'PureInfer' in result_txt: # Pure Infer - with open(result_txt, 'r') as f: - content = f.read() - txt_data_list = [i.strip() for i in re.findall(r'=(.*?),', content.replace('\n', ',') + ',')] - fps = float(txt_data_list[0].replace('samples/s', '')) * 4 - print('310 {} fps:{}'.format(result_txt.split('_')[3], fps)) - else: # Infer based on dataset - with open(result_txt, 'r') as f: - lines = f.readlines() - for line in lines: - if 'infer' in line: - txt_data_list = [i.strip() for i in re.findall(r':(.*?),', line.replace('\n', ',') + ',')] - fps = float(txt_data_list[1]) * 4 - print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) +""" +Copyright 2020 Huawei Technologies Co., Ltd + +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 sys +import re + +if __name__ == '__main__': + result_txt = sys.argv[1] + if 'PureInfer' in result_txt: # Pure Infer + with open(result_txt, 'r') as f: + content = f.read() + txt_data_list = [i.strip() for i in re.findall(r'=(.*?),', content.replace('\n', ',') + ',')] + fps = float(txt_data_list[0].replace('samples/s', '')) * 4 + print('310 {} fps:{}'.format(result_txt.split('_')[3], fps)) + else: # Infer based on dataset + with open(result_txt, 'r') as f: + lines = f.readlines() + for line in lines: + if 'infer' in line: + txt_data_list = [i.strip() for i in re.findall(r':(.*?),', line.replace('\n', ',') + ',')] + fps = float(txt_data_list[1]) * 4 + print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) break \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/video_understanding/TSN/test/perf_gpu.sh b/ACL_PyTorch/contrib/cv/video_understanding/TSN/test/perf_gpu.sh index 41c7a98786..b182f1c43f 100644 --- a/ACL_PyTorch/contrib/cv/video_understanding/TSN/test/perf_gpu.sh +++ b/ACL_PyTorch/contrib/cv/video_understanding/TSN/test/perf_gpu.sh @@ -1,31 +1,31 @@ -#!/bin/bash -# GPU上执行: -trtexec --onnx=onnx_sim/tsn_1.onnx --fp16 --shapes=video:1x75x3x224x224 > tsn_1.log -perf_str=`grep "GPU.* mean.*ms$" tsn_bs1.log` -if [ -n "$perf_str" ]; then - perf_num=`echo $perf_str | awk -F' ' '{print $16}'` -else - perf_str=`grep "mean.*ms$" tsn_bs1.log` - perf_num=`echo $perf_str | awk -F' ' '{print $4}'` -fi -awk 'BEGIN{printf "t4 bs1 fps:%.3f\n", 1000*1/('$perf_num'/1)}' - -trtexec --onnx=onnx_sim/tsn_4.onnx --fp16 --shapes=video:4x75x3x224x224 > tsn_4.log -perf_str=`grep "GPU.* mean.*ms$" tsn_bs16.log` -if [ -n "$perf_str" ]; then - perf_num=`echo $perf_str | awk -F' ' '{print $16}'` -else - perf_str=`grep "mean.*ms$" tsn_bs16.log` - perf_num=`echo $perf_str | awk -F' ' '{print $4}'` -fi -awk 'BEGIN{printf "t4 bs4 fps:%.3f\n", 1000*1/('$perf_num'/16)}' - -trtexec --onnx=onnx_sim/tsn_8.onnx --fp16 --shapes=video:8x75x3x224x224 > tsn_8.log -perf_str=`grep "GPU.* mean.*ms$" tsn_bs16.log` -if [ -n "$perf_str" ]; then - perf_num=`echo $perf_str | awk -F' ' '{print $16}'` -else - perf_str=`grep "mean.*ms$" tsn_bs16.log` - perf_num=`echo $perf_str | awk -F' ' '{print $4}'` -fi +#!/bin/bash +# GPU上执行: +trtexec --onnx=onnx_sim/tsn_1.onnx --fp16 --shapes=video:1x75x3x224x224 > tsn_1.log +perf_str=`grep "GPU.* mean.*ms$" tsn_bs1.log` +if [ -n "$perf_str" ]; then + perf_num=`echo $perf_str | awk -F' ' '{print $16}'` +else + perf_str=`grep "mean.*ms$" tsn_bs1.log` + perf_num=`echo $perf_str | awk -F' ' '{print $4}'` +fi +awk 'BEGIN{printf "t4 bs1 fps:%.3f\n", 1000*1/('$perf_num'/1)}' + +trtexec --onnx=onnx_sim/tsn_4.onnx --fp16 --shapes=video:4x75x3x224x224 > tsn_4.log +perf_str=`grep "GPU.* mean.*ms$" tsn_bs16.log` +if [ -n "$perf_str" ]; then + perf_num=`echo $perf_str | awk -F' ' '{print $16}'` +else + perf_str=`grep "mean.*ms$" tsn_bs16.log` + perf_num=`echo $perf_str | awk -F' ' '{print $4}'` +fi +awk 'BEGIN{printf "t4 bs4 fps:%.3f\n", 1000*1/('$perf_num'/16)}' + +trtexec --onnx=onnx_sim/tsn_8.onnx --fp16 --shapes=video:8x75x3x224x224 > tsn_8.log +perf_str=`grep "GPU.* mean.*ms$" tsn_bs16.log` +if [ -n "$perf_str" ]; then + perf_num=`echo $perf_str | awk -F' ' '{print $16}'` +else + perf_str=`grep "mean.*ms$" tsn_bs16.log` + perf_num=`echo $perf_str | awk -F' ' '{print $4}'` +fi awk 'BEGIN{printf "t4 bs8 fps:%.3f\n", 1000*1/('$perf_num'/16)}' \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/video_understanding/TSN/test/pth2om.sh b/ACL_PyTorch/contrib/cv/video_understanding/TSN/test/pth2om.sh index 28d656c4d8..487fffdef7 100644 --- a/ACL_PyTorch/contrib/cv/video_understanding/TSN/test/pth2om.sh +++ b/ACL_PyTorch/contrib/cv/video_understanding/TSN/test/pth2om.sh @@ -1,13 +1,13 @@ -#!/bin/bash -source env.sh -python3.7 pytorch2onnx.py ./mmaction2/configs/recognition/tsn/tsn_r50_1x1x3_75e_ucf101_rgb.py ./tsn_r50_1x1x3_75e_ucf101_rgb_20201023-d85ab600.pth --verify - -mkdir -p om -atc --framework=5 --model=tsn.onnx --output=tsn_1 --input_format=NCDHW --input_shape="image:1,75,3,256,256" --log=debug --soc_version=Ascend310 --auto_tune_mode "RL,GA" -atc --framework=5 --model=tsn.onnx --output=tsn_4 --input_format=NCDHW --input_shape="image:4,75,3,256,256" --log=debug --soc_version=Ascend310 --auto_tune_mode "RL,GA" -atc --framework=5 --model=tsn.onnx --output=tsn_8 --input_format=NCDHW --input_shape="image:8,75,3,256,256" --log=debug --soc_version=Ascend310 --auto_tune_mode "RL,GA" -if [ -f "om/tsm_bs1.om" ] && [ -f "om/tsm_bs16.om" ]; then - echo "success" -else - echo "fail!" +#!/bin/bash +source env.sh +python3.7 pytorch2onnx.py ./mmaction2/configs/recognition/tsn/tsn_r50_1x1x3_75e_ucf101_rgb.py ./tsn_r50_1x1x3_75e_ucf101_rgb_20201023-d85ab600.pth --verify + +mkdir -p om +atc --framework=5 --model=tsn.onnx --output=tsn_1 --input_format=NCDHW --input_shape="image:1,75,3,256,256" --log=debug --soc_version=Ascend310 --auto_tune_mode "RL,GA" +atc --framework=5 --model=tsn.onnx --output=tsn_4 --input_format=NCDHW --input_shape="image:4,75,3,256,256" --log=debug --soc_version=Ascend310 --auto_tune_mode "RL,GA" +atc --framework=5 --model=tsn.onnx --output=tsn_8 --input_format=NCDHW --input_shape="image:8,75,3,256,256" --log=debug --soc_version=Ascend310 --auto_tune_mode "RL,GA" +if [ -f "om/tsm_bs1.om" ] && [ -f "om/tsm_bs16.om" ]; then + echo "success" +else + echo "fail!" fi \ No newline at end of file diff --git a/ACL_PyTorch/contrib/cv/video_understanding/TSN/tsn_ucf101_postprocess.py b/ACL_PyTorch/contrib/cv/video_understanding/TSN/tsn_ucf101_postprocess.py index bc538bd927..ee3c286110 100644 --- a/ACL_PyTorch/contrib/cv/video_understanding/TSN/tsn_ucf101_postprocess.py +++ b/ACL_PyTorch/contrib/cv/video_understanding/TSN/tsn_ucf101_postprocess.py @@ -1,59 +1,59 @@ -""" -Copyright 2020 Huawei Technologies Co., Ltd - -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. -============================================================================ -""" -# !/usr/bin/env python -# -*- coding: utf-8 -*- - -import os -import argparse -import numpy as np -from collections import OrderedDict -from mmaction.core import top_k_accuracy - - -def parse_args(): - parser = argparse.ArgumentParser(description='Dataset UCF101 Postprocessing') - parser.add_argument('--result_path', type=str) - parser.add_argument('--info_path', type=str) - parser.add_argument('--batch_size', type=int, default=1) - - args = parser.parse_args() - - return args - - -def main(): - args = parse_args() - with open(args.info_path,"r") as f: - l = list(map(lambda x:int(x.strip()), f.readlines())) - - num_samples = len(l) // args.batch_size - i = 0 - acc = 0 - while i < num_samples: - with open(args.result_path+str(i)+'_output_0.txt', 'r') as f: - lines = f.readlines() - lines = list(map(lambda x:x.strip().split(), lines)) - lines = np.array([[float(lines[m][n]) for n in range(101)]for m in range(args.batch_size)]).argmax(1) - for k in range(args.batch_size): - acc += int(lines[k] == l[i*args.batch_size + k]) - i += 1 - - print(acc / len(l)) - - -if __name__ == '__main__': +""" +Copyright 2020 Huawei Technologies Co., Ltd + +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. +============================================================================ +""" +# !/usr/bin/env python +# -*- coding: utf-8 -*- + +import os +import argparse +import numpy as np +from collections import OrderedDict +from mmaction.core import top_k_accuracy + + +def parse_args(): + parser = argparse.ArgumentParser(description='Dataset UCF101 Postprocessing') + parser.add_argument('--result_path', type=str) + parser.add_argument('--info_path', type=str) + parser.add_argument('--batch_size', type=int, default=1) + + args = parser.parse_args() + + return args + + +def main(): + args = parse_args() + with open(args.info_path,"r") as f: + l = list(map(lambda x:int(x.strip()), f.readlines())) + + num_samples = len(l) // args.batch_size + i = 0 + acc = 0 + while i < num_samples: + with open(args.result_path+str(i)+'_output_0.txt', 'r') as f: + lines = f.readlines() + lines = list(map(lambda x:x.strip().split(), lines)) + lines = np.array([[float(lines[m][n]) for n in range(101)]for m in range(args.batch_size)]).argmax(1) + for k in range(args.batch_size): + acc += int(lines[k] == l[i*args.batch_size + k]) + i += 1 + + print(acc / len(l)) + + +if __name__ == '__main__': main() \ No newline at end of file diff --git a/ACL_PyTorch/contrib/knowledge/RotatE/LICENSE b/ACL_PyTorch/contrib/knowledge/RotatE/LICENSE index 797bf40e85..04adf5cbc6 100644 --- a/ACL_PyTorch/contrib/knowledge/RotatE/LICENSE +++ b/ACL_PyTorch/contrib/knowledge/RotatE/LICENSE @@ -1,203 +1,203 @@ -Copyright 2018-2019 Open-MMLab. All rights reserved. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018-2019 Open-MMLab. - - 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. +Copyright 2018-2019 Open-MMLab. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2019 Open-MMLab. + + 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. diff --git a/ACL_PyTorch/contrib/knowledge/RotatE/ReadME.md b/ACL_PyTorch/contrib/knowledge/RotatE/ReadME.md index 0d027928ad..de6807b88d 100644 --- a/ACL_PyTorch/contrib/knowledge/RotatE/ReadME.md +++ b/ACL_PyTorch/contrib/knowledge/RotatE/ReadME.md @@ -1,41 +1,41 @@ -# RotatE模型PyTorch离线推理指导 - -## 1 环境准备 - -- **1.1 安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装** - -``` -pip3.7 install -r requirements.txt -``` - -- **1.2 获取,修改与安装开源模型代码** - -``` -git clone https://github.com/DeepGraphLearning/KnowledgeGraphEmbedding -b master -cd KnowledgeGraphEmbedding -git reset --hard 2e440e0f9c687314d5ff67ead68ce985dc446e3a -cd .. -``` -- **1.3 [获取权重文件](https://www.aliyundrive.com/drive/folder/616a7eb758db2df6ae8448e4b34fe570510ad216)** - -- **1.4 开源模型代码里包含有数据集** - -- **1.5 获取[msame工具](https://gitee.com/ascend/tools/tree/master/msame)和[benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer)** - -将msame和benchmark.x86_64(或benchmark.aarch64)放到当前目录 - -## 2 离线推理 - -- **310上执行,执行时使npu-smi info查看设备状态,确保device空闲** - -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh -``` - -- **评测结果:** - -| 模型 | pth精度 | 310精度 | 性能基准 | 310性能 | -| ----------- | ------------------------------------------------------------ | ------- | -------------- | --------------- | -| RotatE-head bs1
RotatE-tail bs1| [**MRR:0.337**](https://github.com/DeepGraphLearning/KnowledgeGraphEmbedding) | MRR:0.336 | 21.9065fps
21.9091fps | 99.3504fps
104.9432fps | -| RotatE-head bs16
RotatE-tail bs16 | [**MRR:0.337**](https://github.com/DeepGraphLearning/KnowledgeGraphEmbedding) | MRR:0.336 | 22.2017fps
22.1964fps | 119.9172fps
129.7252fps | +# RotatE模型PyTorch离线推理指导 + +## 1 环境准备 + +- **1.1 安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装** + +``` +pip3.7 install -r requirements.txt +``` + +- **1.2 获取,修改与安装开源模型代码** + +``` +git clone https://github.com/DeepGraphLearning/KnowledgeGraphEmbedding -b master +cd KnowledgeGraphEmbedding +git reset --hard 2e440e0f9c687314d5ff67ead68ce985dc446e3a +cd .. +``` +- **1.3 [获取权重文件](https://www.aliyundrive.com/drive/folder/616a7eb758db2df6ae8448e4b34fe570510ad216)** + +- **1.4 开源模型代码里包含有数据集** + +- **1.5 获取[msame工具](https://gitee.com/ascend/tools/tree/master/msame)和[benchmark工具](https://gitee.com/ascend/cann-benchmark/tree/master/infer)** + +将msame和benchmark.x86_64(或benchmark.aarch64)放到当前目录 + +## 2 离线推理 + +- **310上执行,执行时使npu-smi info查看设备状态,确保device空闲** + +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh +``` + +- **评测结果:** + +| 模型 | pth精度 | 310精度 | 性能基准 | 310性能 | +| ----------- | ------------------------------------------------------------ | ------- | -------------- | --------------- | +| RotatE-head bs1
RotatE-tail bs1| [**MRR:0.337**](https://github.com/DeepGraphLearning/KnowledgeGraphEmbedding) | MRR:0.336 | 21.9065fps
21.9091fps | 99.3504fps
104.9432fps | +| RotatE-head bs16
RotatE-tail bs16 | [**MRR:0.337**](https://github.com/DeepGraphLearning/KnowledgeGraphEmbedding) | MRR:0.336 | 22.2017fps
22.1964fps | 119.9172fps
129.7252fps | diff --git a/ACL_PyTorch/contrib/knowledge/RotatE/get_info.py b/ACL_PyTorch/contrib/knowledge/RotatE/get_info.py index 7900a12b52..07bf03fd84 100644 --- a/ACL_PyTorch/contrib/knowledge/RotatE/get_info.py +++ b/ACL_PyTorch/contrib/knowledge/RotatE/get_info.py @@ -1,33 +1,33 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import pdb -import sys -from glob import glob - - -def get_bin_info(file_path, info_name): - bin_files = glob(os.path.join(file_path, '*.npz')) - with open(info_name, 'w') as file: - for index, img in enumerate(bin_files): - # pdb.set_trace() - content = ' '.join([str(index), img]) - file.write(content) - file.write('\n') - -if __name__ == '__main__': - file_path = sys.argv[1] - info_name = sys.argv[2] - get_bin_info(file_path, info_name) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import pdb +import sys +from glob import glob + + +def get_bin_info(file_path, info_name): + bin_files = glob(os.path.join(file_path, '*.npz')) + with open(info_name, 'w') as file: + for index, img in enumerate(bin_files): + # pdb.set_trace() + content = ' '.join([str(index), img]) + file.write(content) + file.write('\n') + +if __name__ == '__main__': + file_path = sys.argv[1] + info_name = sys.argv[2] + get_bin_info(file_path, info_name) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/knowledge/RotatE/modelzoo_level.txt b/ACL_PyTorch/contrib/knowledge/RotatE/modelzoo_level.txt index 83689985f2..8c469d858a 100644 --- a/ACL_PyTorch/contrib/knowledge/RotatE/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/knowledge/RotatE/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus:PERFECT \ No newline at end of file diff --git a/ACL_PyTorch/contrib/knowledge/RotatE/requirements.txt b/ACL_PyTorch/contrib/knowledge/RotatE/requirements.txt index 41c2d7836f..a220c00791 100644 --- a/ACL_PyTorch/contrib/knowledge/RotatE/requirements.txt +++ b/ACL_PyTorch/contrib/knowledge/RotatE/requirements.txt @@ -1,5 +1,5 @@ -torch == 1.8.0 -torchvision == 0.9.0 -onnx == 1.9.0 -numpy == 1.20.3 +torch == 1.8.0 +torchvision == 0.9.0 +onnx == 1.9.0 +numpy == 1.20.3 scikit-learn >= 0.20.2 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/knowledge/RotatE/rotate_postprocess.py b/ACL_PyTorch/contrib/knowledge/RotatE/rotate_postprocess.py index eb60584558..2923c802bd 100644 --- a/ACL_PyTorch/contrib/knowledge/RotatE/rotate_postprocess.py +++ b/ACL_PyTorch/contrib/knowledge/RotatE/rotate_postprocess.py @@ -1,121 +1,121 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# 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 argparse -import pdb - -import torch -import os -import numpy as np - -def postProcesss(result_path, data_head, data_tail): - - data_mulu = os.listdir(result_path) - data_mulu.sort(key=lambda x: int(x.split('_')[1][0:])) - head_list_date = data_mulu[0] - head_mulu_path = os.path.join(result_path, head_list_date) - bin_head_list = os.listdir(head_mulu_path) - bin_head_list.sort(key=lambda x: int(x.split('-')[0][3:])) - - tail_list_date = data_mulu[1] - tail_mulu_path = os.path.join(result_path, tail_list_date) - bin_tail_list = os.listdir(tail_mulu_path) - bin_tail_list.sort(key=lambda x: int(x.split('-')[0][3:])) - head_ite_list = os.listdir(data_head+'/post') - tail_ite_list = os.listdir(data_tail+'/post') - - head_pos_list = os.listdir(data_head+'/possamp') - tail_pos_list = os.listdir(data_head + '/possamp') - head_ite_list.sort(key=lambda x: int(x.split('-')[0][3:])) - tail_ite_list.sort(key=lambda x: int(x.split('-')[0][3:])) - head_pos_list.sort(key=lambda x: int(x.split('-')[0][3:])) - tail_pos_list.sort(key=lambda x: int(x.split('-')[0][3:])) - - logs = [] - for i in range(len(bin_head_list)): - bin_path = os.path.join(head_mulu_path, bin_head_list[i]) - score = np.loadtxt(bin_path) - score = torch.from_numpy(score) - ite_path = os.path.join(data_head+'/post', head_ite_list[i]) - filter_bias = np.loadtxt(ite_path) - filter_bias = torch.from_numpy(filter_bias) - pos_path = os.path.join(data_head + '/possamp', head_pos_list[i]) - positive_sample = np.loadtxt(pos_path) - positive_sample = positive_sample.reshape(-1, 3) - score += filter_bias - score = torch.reshape(score, (-1, 14541)) - # Explicitly sort all the entities to ensure that there is no test exposure bias - argsort = torch.argsort(score, dim=1, descending=True) - positive_arg = positive_sample[:, 0] - - for i in range(len(score)): - # Notice that argsort is not ranking - ranking = (argsort[i, :] == positive_arg[i]).nonzero() - assert ranking.size(0) == 1 - # ranking + 1 is the true ranking used in evaluation metrics - ranking = 1 + ranking.item() - logs.append({ - 'MRR': 1.0 / ranking, - 'MR': float(ranking), - 'HITS@1': 1.0 if ranking <= 1 else 0.0, - 'HITS@3': 1.0 if ranking <= 3 else 0.0, - 'HITS@10': 1.0 if ranking <= 10 else 0.0, - }) - for i in range(len(bin_tail_list)): - bin_path = os.path.join(tail_mulu_path, bin_tail_list[i]) - score = np.loadtxt(bin_path) - score = torch.from_numpy(score) - ite_path = os.path.join(data_tail + '/post', tail_ite_list[i]) - filter_bias = np.loadtxt(ite_path) - filter_bias = torch.from_numpy(filter_bias) - pos_path = os.path.join(data_tail + '/possamp', tail_pos_list[i]) - positive_sample = np.loadtxt(pos_path) - positive_sample = positive_sample.reshape(-1,3) - score += filter_bias - score = torch.reshape(score,(-1,14541)) - - # Explicitly sort all the entities to ensure that there is no test exposure bias - argsort = torch.argsort(score, dim=1, descending=True) - positive_arg = positive_sample[:, 2] - - for i in range(len(score)): - # Notice that argsort is not ranking - ranking = (argsort[i, :] == positive_arg[i]).nonzero() - assert ranking.size(0) == 1 - # ranking + 1 is the true ranking used in evaluation metrics - ranking = 1 + ranking.item() - logs.append({ - 'MRR': 1.0 / ranking, - 'MR': float(ranking), - 'HITS@1': 1.0 if ranking <= 1 else 0.0, - 'HITS@3': 1.0 if ranking <= 3 else 0.0, - 'HITS@10': 1.0 if ranking <= 10 else 0.0, - }) - - metrics = {} - for metric in logs[0].keys(): - metrics[metric] = sum([log[metric] for log in logs]) / len(logs) - - return metrics - - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='postprocess of r2plus1d') - - parser.add_argument('--result_path', default=r'E:/huawei/KGE_inference/out') - parser.add_argument('--data_head', default=r'E:/huawei/KGE_inference/bin/head') - parser.add_argument('--data_tail', default=r'E:/huawei/KGE_inference/bin/tail') - opt = parser.parse_args() - metrics = postProcesss(opt.result_path, opt.data_head, opt.data_tail) - print(metrics) - +# Copyright 2021 Huawei Technologies Co., Ltd +# 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 argparse +import pdb + +import torch +import os +import numpy as np + +def postProcesss(result_path, data_head, data_tail): + + data_mulu = os.listdir(result_path) + data_mulu.sort(key=lambda x: int(x.split('_')[1][0:])) + head_list_date = data_mulu[0] + head_mulu_path = os.path.join(result_path, head_list_date) + bin_head_list = os.listdir(head_mulu_path) + bin_head_list.sort(key=lambda x: int(x.split('-')[0][3:])) + + tail_list_date = data_mulu[1] + tail_mulu_path = os.path.join(result_path, tail_list_date) + bin_tail_list = os.listdir(tail_mulu_path) + bin_tail_list.sort(key=lambda x: int(x.split('-')[0][3:])) + head_ite_list = os.listdir(data_head+'/post') + tail_ite_list = os.listdir(data_tail+'/post') + + head_pos_list = os.listdir(data_head+'/possamp') + tail_pos_list = os.listdir(data_head + '/possamp') + head_ite_list.sort(key=lambda x: int(x.split('-')[0][3:])) + tail_ite_list.sort(key=lambda x: int(x.split('-')[0][3:])) + head_pos_list.sort(key=lambda x: int(x.split('-')[0][3:])) + tail_pos_list.sort(key=lambda x: int(x.split('-')[0][3:])) + + logs = [] + for i in range(len(bin_head_list)): + bin_path = os.path.join(head_mulu_path, bin_head_list[i]) + score = np.loadtxt(bin_path) + score = torch.from_numpy(score) + ite_path = os.path.join(data_head+'/post', head_ite_list[i]) + filter_bias = np.loadtxt(ite_path) + filter_bias = torch.from_numpy(filter_bias) + pos_path = os.path.join(data_head + '/possamp', head_pos_list[i]) + positive_sample = np.loadtxt(pos_path) + positive_sample = positive_sample.reshape(-1, 3) + score += filter_bias + score = torch.reshape(score, (-1, 14541)) + # Explicitly sort all the entities to ensure that there is no test exposure bias + argsort = torch.argsort(score, dim=1, descending=True) + positive_arg = positive_sample[:, 0] + + for i in range(len(score)): + # Notice that argsort is not ranking + ranking = (argsort[i, :] == positive_arg[i]).nonzero() + assert ranking.size(0) == 1 + # ranking + 1 is the true ranking used in evaluation metrics + ranking = 1 + ranking.item() + logs.append({ + 'MRR': 1.0 / ranking, + 'MR': float(ranking), + 'HITS@1': 1.0 if ranking <= 1 else 0.0, + 'HITS@3': 1.0 if ranking <= 3 else 0.0, + 'HITS@10': 1.0 if ranking <= 10 else 0.0, + }) + for i in range(len(bin_tail_list)): + bin_path = os.path.join(tail_mulu_path, bin_tail_list[i]) + score = np.loadtxt(bin_path) + score = torch.from_numpy(score) + ite_path = os.path.join(data_tail + '/post', tail_ite_list[i]) + filter_bias = np.loadtxt(ite_path) + filter_bias = torch.from_numpy(filter_bias) + pos_path = os.path.join(data_tail + '/possamp', tail_pos_list[i]) + positive_sample = np.loadtxt(pos_path) + positive_sample = positive_sample.reshape(-1,3) + score += filter_bias + score = torch.reshape(score,(-1,14541)) + + # Explicitly sort all the entities to ensure that there is no test exposure bias + argsort = torch.argsort(score, dim=1, descending=True) + positive_arg = positive_sample[:, 2] + + for i in range(len(score)): + # Notice that argsort is not ranking + ranking = (argsort[i, :] == positive_arg[i]).nonzero() + assert ranking.size(0) == 1 + # ranking + 1 is the true ranking used in evaluation metrics + ranking = 1 + ranking.item() + logs.append({ + 'MRR': 1.0 / ranking, + 'MR': float(ranking), + 'HITS@1': 1.0 if ranking <= 1 else 0.0, + 'HITS@3': 1.0 if ranking <= 3 else 0.0, + 'HITS@10': 1.0 if ranking <= 10 else 0.0, + }) + + metrics = {} + for metric in logs[0].keys(): + metrics[metric] = sum([log[metric] for log in logs]) / len(logs) + + return metrics + + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='postprocess of r2plus1d') + + parser.add_argument('--result_path', default=r'E:/huawei/KGE_inference/out') + parser.add_argument('--data_head', default=r'E:/huawei/KGE_inference/bin/head') + parser.add_argument('--data_tail', default=r'E:/huawei/KGE_inference/bin/tail') + opt = parser.parse_args() + metrics = postProcesss(opt.result_path, opt.data_head, opt.data_tail) + print(metrics) + diff --git a/ACL_PyTorch/contrib/knowledge/RotatE/rotate_preprocess.py b/ACL_PyTorch/contrib/knowledge/RotatE/rotate_preprocess.py index a42480c8b3..92585dc289 100644 --- a/ACL_PyTorch/contrib/knowledge/RotatE/rotate_preprocess.py +++ b/ACL_PyTorch/contrib/knowledge/RotatE/rotate_preprocess.py @@ -1,227 +1,227 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# 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 argparse -import sys -sys.path.append(r'KnowledgeGraphEmbedding/codes/') -import logging -import os -import io -import pdb -import torch -import numpy as np - -import time -from torch.utils.data import DataLoader -import dataloader - -nowTime = time.strftime('%Y%m%d', time.localtime(time.time())) - -def parse_args(args=None): - parser = argparse.ArgumentParser( - description='Training and Testing Knowledge Graph Embedding Models', - usage='train.py [] [-h | --help]' - ) - - parser.add_argument('--data_path', type=str, default='./KnowledgeGraphEmbedding/data/FB15k-237') - parser.add_argument('--test_batch_size', default=6, type=int, help='valid/test batch size') - parser.add_argument('-cpu', '--cpu_num', default=10, type=int) - parser.add_argument('--output_path', default='bin/', type=str) - parser.add_argument('--output_head_post', default='head/post', type=str) - parser.add_argument('--output_tail_post', default='tail/post', type=str) - parser.add_argument('--output_head_pos', default='head/pos', type=str) - parser.add_argument('--output_head_neg', default='head/neg', type=str) - parser.add_argument('--output_head_mode', default='head/mode', type=str) - parser.add_argument('--output_head_pp', default='head/possamp', type=str) - parser.add_argument('--output_head_np', default='head/negsamp', type=str) - parser.add_argument('--output_tail_pos', default='tail/pos', type=str) - parser.add_argument('--output_tail_neg', default='tail/neg', type=str) - parser.add_argument('--output_tail_mode', default='tail/mode', type=str) - parser.add_argument('--output_tail_pp', default='tail/possamp', type=str) - parser.add_argument('--output_tail_np', default='tail/negsamp', type=str) - parser.add_argument('--nentity', type=int, default=0, help='DO NOT MANUALLY SET') - parser.add_argument('--nrelation', type=int, default=0, help='DO NOT MANUALLY SET') - arg = parser.parse_args(args) - arg.output_head_post = arg.output_path + arg.output_head_post - arg.output_tail_post = arg.output_path + arg.output_tail_post - arg.output_head_pos = arg.output_path + arg.output_head_pos - arg.output_head_neg = arg.output_path + arg.output_head_neg - arg.output_head_mode = arg.output_path + arg.output_head_mode - arg.output_head_pp = arg.output_path + arg.output_head_pp - arg.output_head_np = arg.output_path + arg.output_head_np - arg.output_tail_pos = arg.output_path + arg.output_tail_pos - arg.output_tail_neg = arg.output_path + arg.output_tail_neg - arg.output_tail_mode = arg.output_path + arg.output_tail_mode - arg.output_tail_pp = arg.output_path + arg.output_tail_pp - arg.output_tail_np = arg.output_path + arg.output_tail_np - return arg - -def read_triple(file_path, entity2id, relation2id): - ''' - Read triples and map them into ids. - ''' - triples = [] - with open(file_path) as fin: - for line in fin: - h, r, t = line.strip().split('\t') - triples.append((entity2id[h], relation2id[r], entity2id[t])) - return triples - -def to_numpy32(tensor): - return tensor.detach().cpu().numpy().astype(np.int32) if tensor.requires_grad else tensor.cpu().numpy().astype(np.int32) - -def to_numpy64(tensor): - return tensor.detach().cpu().numpy().astype(np.int64) if tensor.requires_grad else tensor.cpu().numpy().astype(np.int64) - -def main(args): - - with open(os.path.join(args.data_path, 'entities.dict')) as fin: - entity2id = dict() - for line in fin: - eid, entity = line.strip().split('\t') - entity2id[entity] = int(eid) - - with open(os.path.join(args.data_path, 'relations.dict')) as fin: - relation2id = dict() - for line in fin: - rid, relation = line.strip().split('\t') - relation2id[relation] = int(rid) - - - nentity = len(entity2id) - nrelation = len(relation2id) - - args.nentity = nentity - args.nrelation = nrelation - - - train_triples = read_triple(os.path.join(args.data_path, 'train.txt'), entity2id, relation2id) - logging.info('#train: %d' % len(train_triples)) - valid_triples = read_triple(os.path.join(args.data_path, 'valid.txt'), entity2id, relation2id) - logging.info('#valid: %d' % len(valid_triples)) - test_triples = read_triple(os.path.join(args.data_path, 'test.txt'), entity2id, relation2id) - logging.info('#test: %d' % len(test_triples)) - - # All true triples - all_true_triples = train_triples + valid_triples + test_triples - - test_dataloader_head = DataLoader( - dataloader.TestDataset( - test_triples, - all_true_triples, - args.nentity, - args.nrelation, - 'head-batch' - ), - batch_size=args.test_batch_size, - num_workers=max(1, args.cpu_num // 2), - collate_fn=dataloader.TestDataset.collate_fn - ) - - test_dataloader_tail = DataLoader( - dataloader.TestDataset( - test_triples, - all_true_triples, - args.nentity, - args.nrelation, - 'tail-batch' - ), - batch_size=args.test_batch_size, - num_workers=max(1, args.cpu_num // 2), - collate_fn=dataloader.TestDataset.collate_fn - ) - - test_dataset_list = [test_dataloader_head, test_dataloader_tail] - # test_dataset_list = [test_dataloader_tail] - for test_dataset in test_dataset_list: - for index, value in enumerate(test_dataset): - if(value[0].shape[0] == args.test_batch_size): - batch_pos = value[0] - batch_pos = to_numpy64(batch_pos) - - batch_neg = value[1] - batch_neg = to_numpy32(batch_neg) - batch_ite = value[2].numpy() - batch_mode = value[3] - - print('preprocessing ' + str(index)) - - if not os.path.exists(str(args.output_head_pos)): - os.makedirs(str(args.output_head_pos)) - if not os.path.exists(str(args.output_head_neg)): - os.makedirs(str(args.output_head_neg)) - if not os.path.exists(str(args.output_head_mode)): - os.makedirs(str(args.output_head_mode)) - if not os.path.exists(str(args.output_head_pp)): - os.makedirs(str(args.output_head_pp)) - if not os.path.exists(str(args.output_tail_pos)): - os.makedirs(str(args.output_tail_pos)) - if not os.path.exists(str(args.output_tail_neg)): - os.makedirs(str(args.output_tail_neg)) - if not os.path.exists(str(args.output_tail_mode)): - os.makedirs(str(args.output_tail_mode)) - if not os.path.exists(str(args.output_tail_pp)): - os.makedirs(str(args.output_tail_pp)) - - - if batch_mode == 'head-batch': - save_path_pos = str(args.output_head_pos) + '/bin' + str(int(args.test_batch_size) * index) + '-' + str( - int(args.test_batch_size) * (index + 1) - 1) + '.bin' - save_path_pos_txt = str(args.output_head_pp) + '/bin' + str(int(args.test_batch_size) * index) + '-' + str( - int(args.test_batch_size) * (index + 1) - 1) + '.txt' - batch_pos.tofile(str(save_path_pos)) - np.savetxt(save_path_pos_txt, batch_pos) - - save_path_neg = str(args.output_head_neg) + '/bin' + str(int(args.test_batch_size) * index) + '-' + str( - int(args.test_batch_size) * (index + 1) - 1) + '.bin' - batch_neg.tofile(str(save_path_neg)) - - save_post_dir = str(args.output_head_post) - if not os.path.exists(save_post_dir): - os.makedirs(save_post_dir) - save_path_post = save_post_dir + '/bin' + str(int(args.test_batch_size) * index) + '-' + str( - int(args.test_batch_size) * (index + 1) - 1) + '.txt' - np.savetxt(save_path_post, batch_ite) - print(index, str(save_path_post), "save done!") - print("----------------head---next-----------------------------") - - if batch_mode == 'tail-batch': - - save_path_pos = str(args.output_tail_pos) + '/bin' + str(int(args.test_batch_size) * index) + '-' + str( - int(args.test_batch_size) * (index + 1) - 1) + '.bin' - save_path_pos_txt = str(args.output_tail_pp) + '/bin' + str(int(args.test_batch_size) * index) + '-' + str( - int(args.test_batch_size) * (index + 1) - 1) + '.txt' - batch_pos.tofile(str(save_path_pos)) - np.savetxt(save_path_pos_txt, batch_pos) - - save_path_neg = str(args.output_tail_neg) + '/bin' + str(int(args.test_batch_size) * index) + '-' + str( - int(args.test_batch_size) * (index + 1) - 1) + '.bin' - batch_neg.tofile(str(save_path_neg)) - - print(index, str(save_path_neg), "save done!") - - save_post_dir = str(args.output_tail_post) - if not os.path.exists(save_post_dir): - os.makedirs(save_post_dir) - save_path_post = save_post_dir + '/bin' + str(int(args.test_batch_size) * index) + '-' + str( - int(args.test_batch_size) * (index + 1) - 1) + '.txt' - np.savetxt(save_path_post, batch_ite) - print(index, str(save_path_post), "save done!") - print("---------------tail----next-----------------------------") - - -if __name__ == '__main__': - main(parse_args()) +# Copyright 2021 Huawei Technologies Co., Ltd +# 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 argparse +import sys +sys.path.append(r'KnowledgeGraphEmbedding/codes/') +import logging +import os +import io +import pdb +import torch +import numpy as np + +import time +from torch.utils.data import DataLoader +import dataloader + +nowTime = time.strftime('%Y%m%d', time.localtime(time.time())) + +def parse_args(args=None): + parser = argparse.ArgumentParser( + description='Training and Testing Knowledge Graph Embedding Models', + usage='train.py [] [-h | --help]' + ) + + parser.add_argument('--data_path', type=str, default='./KnowledgeGraphEmbedding/data/FB15k-237') + parser.add_argument('--test_batch_size', default=6, type=int, help='valid/test batch size') + parser.add_argument('-cpu', '--cpu_num', default=10, type=int) + parser.add_argument('--output_path', default='bin/', type=str) + parser.add_argument('--output_head_post', default='head/post', type=str) + parser.add_argument('--output_tail_post', default='tail/post', type=str) + parser.add_argument('--output_head_pos', default='head/pos', type=str) + parser.add_argument('--output_head_neg', default='head/neg', type=str) + parser.add_argument('--output_head_mode', default='head/mode', type=str) + parser.add_argument('--output_head_pp', default='head/possamp', type=str) + parser.add_argument('--output_head_np', default='head/negsamp', type=str) + parser.add_argument('--output_tail_pos', default='tail/pos', type=str) + parser.add_argument('--output_tail_neg', default='tail/neg', type=str) + parser.add_argument('--output_tail_mode', default='tail/mode', type=str) + parser.add_argument('--output_tail_pp', default='tail/possamp', type=str) + parser.add_argument('--output_tail_np', default='tail/negsamp', type=str) + parser.add_argument('--nentity', type=int, default=0, help='DO NOT MANUALLY SET') + parser.add_argument('--nrelation', type=int, default=0, help='DO NOT MANUALLY SET') + arg = parser.parse_args(args) + arg.output_head_post = arg.output_path + arg.output_head_post + arg.output_tail_post = arg.output_path + arg.output_tail_post + arg.output_head_pos = arg.output_path + arg.output_head_pos + arg.output_head_neg = arg.output_path + arg.output_head_neg + arg.output_head_mode = arg.output_path + arg.output_head_mode + arg.output_head_pp = arg.output_path + arg.output_head_pp + arg.output_head_np = arg.output_path + arg.output_head_np + arg.output_tail_pos = arg.output_path + arg.output_tail_pos + arg.output_tail_neg = arg.output_path + arg.output_tail_neg + arg.output_tail_mode = arg.output_path + arg.output_tail_mode + arg.output_tail_pp = arg.output_path + arg.output_tail_pp + arg.output_tail_np = arg.output_path + arg.output_tail_np + return arg + +def read_triple(file_path, entity2id, relation2id): + ''' + Read triples and map them into ids. + ''' + triples = [] + with open(file_path) as fin: + for line in fin: + h, r, t = line.strip().split('\t') + triples.append((entity2id[h], relation2id[r], entity2id[t])) + return triples + +def to_numpy32(tensor): + return tensor.detach().cpu().numpy().astype(np.int32) if tensor.requires_grad else tensor.cpu().numpy().astype(np.int32) + +def to_numpy64(tensor): + return tensor.detach().cpu().numpy().astype(np.int64) if tensor.requires_grad else tensor.cpu().numpy().astype(np.int64) + +def main(args): + + with open(os.path.join(args.data_path, 'entities.dict')) as fin: + entity2id = dict() + for line in fin: + eid, entity = line.strip().split('\t') + entity2id[entity] = int(eid) + + with open(os.path.join(args.data_path, 'relations.dict')) as fin: + relation2id = dict() + for line in fin: + rid, relation = line.strip().split('\t') + relation2id[relation] = int(rid) + + + nentity = len(entity2id) + nrelation = len(relation2id) + + args.nentity = nentity + args.nrelation = nrelation + + + train_triples = read_triple(os.path.join(args.data_path, 'train.txt'), entity2id, relation2id) + logging.info('#train: %d' % len(train_triples)) + valid_triples = read_triple(os.path.join(args.data_path, 'valid.txt'), entity2id, relation2id) + logging.info('#valid: %d' % len(valid_triples)) + test_triples = read_triple(os.path.join(args.data_path, 'test.txt'), entity2id, relation2id) + logging.info('#test: %d' % len(test_triples)) + + # All true triples + all_true_triples = train_triples + valid_triples + test_triples + + test_dataloader_head = DataLoader( + dataloader.TestDataset( + test_triples, + all_true_triples, + args.nentity, + args.nrelation, + 'head-batch' + ), + batch_size=args.test_batch_size, + num_workers=max(1, args.cpu_num // 2), + collate_fn=dataloader.TestDataset.collate_fn + ) + + test_dataloader_tail = DataLoader( + dataloader.TestDataset( + test_triples, + all_true_triples, + args.nentity, + args.nrelation, + 'tail-batch' + ), + batch_size=args.test_batch_size, + num_workers=max(1, args.cpu_num // 2), + collate_fn=dataloader.TestDataset.collate_fn + ) + + test_dataset_list = [test_dataloader_head, test_dataloader_tail] + # test_dataset_list = [test_dataloader_tail] + for test_dataset in test_dataset_list: + for index, value in enumerate(test_dataset): + if(value[0].shape[0] == args.test_batch_size): + batch_pos = value[0] + batch_pos = to_numpy64(batch_pos) + + batch_neg = value[1] + batch_neg = to_numpy32(batch_neg) + batch_ite = value[2].numpy() + batch_mode = value[3] + + print('preprocessing ' + str(index)) + + if not os.path.exists(str(args.output_head_pos)): + os.makedirs(str(args.output_head_pos)) + if not os.path.exists(str(args.output_head_neg)): + os.makedirs(str(args.output_head_neg)) + if not os.path.exists(str(args.output_head_mode)): + os.makedirs(str(args.output_head_mode)) + if not os.path.exists(str(args.output_head_pp)): + os.makedirs(str(args.output_head_pp)) + if not os.path.exists(str(args.output_tail_pos)): + os.makedirs(str(args.output_tail_pos)) + if not os.path.exists(str(args.output_tail_neg)): + os.makedirs(str(args.output_tail_neg)) + if not os.path.exists(str(args.output_tail_mode)): + os.makedirs(str(args.output_tail_mode)) + if not os.path.exists(str(args.output_tail_pp)): + os.makedirs(str(args.output_tail_pp)) + + + if batch_mode == 'head-batch': + save_path_pos = str(args.output_head_pos) + '/bin' + str(int(args.test_batch_size) * index) + '-' + str( + int(args.test_batch_size) * (index + 1) - 1) + '.bin' + save_path_pos_txt = str(args.output_head_pp) + '/bin' + str(int(args.test_batch_size) * index) + '-' + str( + int(args.test_batch_size) * (index + 1) - 1) + '.txt' + batch_pos.tofile(str(save_path_pos)) + np.savetxt(save_path_pos_txt, batch_pos) + + save_path_neg = str(args.output_head_neg) + '/bin' + str(int(args.test_batch_size) * index) + '-' + str( + int(args.test_batch_size) * (index + 1) - 1) + '.bin' + batch_neg.tofile(str(save_path_neg)) + + save_post_dir = str(args.output_head_post) + if not os.path.exists(save_post_dir): + os.makedirs(save_post_dir) + save_path_post = save_post_dir + '/bin' + str(int(args.test_batch_size) * index) + '-' + str( + int(args.test_batch_size) * (index + 1) - 1) + '.txt' + np.savetxt(save_path_post, batch_ite) + print(index, str(save_path_post), "save done!") + print("----------------head---next-----------------------------") + + if batch_mode == 'tail-batch': + + save_path_pos = str(args.output_tail_pos) + '/bin' + str(int(args.test_batch_size) * index) + '-' + str( + int(args.test_batch_size) * (index + 1) - 1) + '.bin' + save_path_pos_txt = str(args.output_tail_pp) + '/bin' + str(int(args.test_batch_size) * index) + '-' + str( + int(args.test_batch_size) * (index + 1) - 1) + '.txt' + batch_pos.tofile(str(save_path_pos)) + np.savetxt(save_path_pos_txt, batch_pos) + + save_path_neg = str(args.output_tail_neg) + '/bin' + str(int(args.test_batch_size) * index) + '-' + str( + int(args.test_batch_size) * (index + 1) - 1) + '.bin' + batch_neg.tofile(str(save_path_neg)) + + print(index, str(save_path_neg), "save done!") + + save_post_dir = str(args.output_tail_post) + if not os.path.exists(save_post_dir): + os.makedirs(save_post_dir) + save_path_post = save_post_dir + '/bin' + str(int(args.test_batch_size) * index) + '-' + str( + int(args.test_batch_size) * (index + 1) - 1) + '.txt' + np.savetxt(save_path_post, batch_ite) + print(index, str(save_path_post), "save done!") + print("---------------tail----next-----------------------------") + + +if __name__ == '__main__': + main(parse_args()) diff --git a/ACL_PyTorch/contrib/knowledge/RotatE/rotate_pth2onnx.py b/ACL_PyTorch/contrib/knowledge/RotatE/rotate_pth2onnx.py index 8c36287bab..0f62a827eb 100644 --- a/ACL_PyTorch/contrib/knowledge/RotatE/rotate_pth2onnx.py +++ b/ACL_PyTorch/contrib/knowledge/RotatE/rotate_pth2onnx.py @@ -1,73 +1,73 @@ -# 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 pdb -import sys -sys.path.append(r'KnowledgeGraphEmbedding/codes/') -import numpy as np -import torch - -import argparse - -from model import KGEModel - -def to_numpy32(tensor): - return tensor.detach().cpu().numpy().astype(np.int32) if tensor.requires_grad else tensor.cpu().numpy().astype(np.int32) - -def to_numpy64(tensor): - return tensor.detach().cpu().numpy().astype(np.int64) if tensor.requires_grad else tensor.cpu().numpy().astype(np.int64) - -def pth2onnx(input_file, output_file, bs, mode): - kge_model = KGEModel( - model_name='RotatE', - nentity=14541, - nrelation=237, - hidden_dim=1000, - gamma=9.0, - double_entity_embedding=True, - double_relation_embedding=False - ) - - checkpoint = torch.load(input_file, map_location='cpu') - kge_model.load_state_dict(checkpoint['model_state_dict']) - for param_tensor in kge_model.state_dict(): - print(param_tensor, "\t", kge_model.state_dict()[param_tensor].size()) - input_names = ["pos", "neg"] - output_names = ["score"] - dynamic_axes = {'pos': {0: '-1'}, 'neg': {0: '-1'}} - # pdb.set_trace() - head = torch.randint(0, 14541, (bs, 1)) - relation = torch.randint(0, 233, (bs, 1)) - tail = torch.randint(0, 14541, (bs, 1)) - input1 = [] - for j in range(bs): - inp = [] - for i in range(14541): - inp.append(i) - input1.append(inp) - negative_sample = torch.from_numpy(np.array(input1)) - - positive_sample = torch.cat([head, relation, tail], dim=1) - positive_sample = torch.from_numpy(to_numpy64(positive_sample)) - negative_sample = torch.from_numpy(to_numpy32(negative_sample)) - - torch.onnx.export(kge_model, ((positive_sample, negative_sample), mode), output_file, input_names=input_names, dynamic_axes=dynamic_axes, - output_names=output_names, opset_version=11, verbose=True) - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='postprocess of r2plus1d') - parser.add_argument('--pth_path', default=r'./checkpoint') - parser.add_argument('--onnx_path', default=r'./kge_onnx_16_tail.onnx') - parser.add_argument('--batch_size', default=16, type=int) - parser.add_argument('--mode', default=r'tail-batch', help='select head-batch or tail-batch') - - args = parser.parse_args() +# 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 pdb +import sys +sys.path.append(r'KnowledgeGraphEmbedding/codes/') +import numpy as np +import torch + +import argparse + +from model import KGEModel + +def to_numpy32(tensor): + return tensor.detach().cpu().numpy().astype(np.int32) if tensor.requires_grad else tensor.cpu().numpy().astype(np.int32) + +def to_numpy64(tensor): + return tensor.detach().cpu().numpy().astype(np.int64) if tensor.requires_grad else tensor.cpu().numpy().astype(np.int64) + +def pth2onnx(input_file, output_file, bs, mode): + kge_model = KGEModel( + model_name='RotatE', + nentity=14541, + nrelation=237, + hidden_dim=1000, + gamma=9.0, + double_entity_embedding=True, + double_relation_embedding=False + ) + + checkpoint = torch.load(input_file, map_location='cpu') + kge_model.load_state_dict(checkpoint['model_state_dict']) + for param_tensor in kge_model.state_dict(): + print(param_tensor, "\t", kge_model.state_dict()[param_tensor].size()) + input_names = ["pos", "neg"] + output_names = ["score"] + dynamic_axes = {'pos': {0: '-1'}, 'neg': {0: '-1'}} + # pdb.set_trace() + head = torch.randint(0, 14541, (bs, 1)) + relation = torch.randint(0, 233, (bs, 1)) + tail = torch.randint(0, 14541, (bs, 1)) + input1 = [] + for j in range(bs): + inp = [] + for i in range(14541): + inp.append(i) + input1.append(inp) + negative_sample = torch.from_numpy(np.array(input1)) + + positive_sample = torch.cat([head, relation, tail], dim=1) + positive_sample = torch.from_numpy(to_numpy64(positive_sample)) + negative_sample = torch.from_numpy(to_numpy32(negative_sample)) + + torch.onnx.export(kge_model, ((positive_sample, negative_sample), mode), output_file, input_names=input_names, dynamic_axes=dynamic_axes, + output_names=output_names, opset_version=11, verbose=True) + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='postprocess of r2plus1d') + parser.add_argument('--pth_path', default=r'./checkpoint') + parser.add_argument('--onnx_path', default=r'./kge_onnx_16_tail.onnx') + parser.add_argument('--batch_size', default=16, type=int) + parser.add_argument('--mode', default=r'tail-batch', help='select head-batch or tail-batch') + + args = parser.parse_args() pth2onnx(args.pth_path, args.onnx_path, args.batch_size, args.mode) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/nlp/BertSum/BertSum-pth2onnx.py b/ACL_PyTorch/contrib/nlp/BertSum/BertSum-pth2onnx.py index bc730838ba..6fbbab39b1 100644 --- a/ACL_PyTorch/contrib/nlp/BertSum/BertSum-pth2onnx.py +++ b/ACL_PyTorch/contrib/nlp/BertSum/BertSum-pth2onnx.py @@ -1,119 +1,119 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 torch -import os -import sys -import argparse -import numpy as np -from pytorch_pretrained_bert import BertConfig -from models.model_builder import Summarizer - -model_flags = ['hidden_size', 'ff_size', 'heads', 'inter_layers','encoder','ff_actv', 'use_interval','rnn_size'] - -def str2bool(v): - if v.lower() in ('yes', 'true', 't', 'y', '1'): - return True - elif v.lower() in ('no', 'false', 'f', 'n', '0'): - return False - else: - raise argparse.ArgumentTypeError('Boolean value expected.') - -def main(args): - input_names=['src','segs','clss','mask','mask_cls'] - output_names = ["output"] - onnx_path = args.onnx_path - device = "cpu" if args.visible_gpus == '-1' else "cuda" - checkpoint = torch.load(args.path, map_location='cpu') - opt = vars(checkpoint['opt']) - for k in opt.keys(): - if (k in model_flags): - setattr(args, k, opt[k]) - config = BertConfig.from_json_file(args.bert_config_path) - model = Summarizer(args, device, load_pretrained_bert=False, bert_config = config) - model.load_cp(checkpoint) - model.eval() - cur_path = os.getcwd() - src = np.fromfile(f'{cur_path}/pre_data/src/data_1.bin', dtype=np.int64) - segs = np.fromfile(f'{cur_path}/pre_data/segs/data_1.bin', dtype=np.int64) - clss = np.fromfile(f'{cur_path}/pre_data/clss/data_1.bin', dtype=np.int64) - mask = np.fromfile(f'{cur_path}/pre_data/mask/data_1.bin', dtype=np.bool_) - mask_cls = np.fromfile(f'{cur_path}/pre_data/mask_cls/data_1.bin', dtype=np.bool_) - print(src.shape) - print(segs.shape) - print(clss.shape) - print(mask.shape) - print(mask_cls.shape) - #-----------------------------13000----------------------------- - dummy_input0 = torch.from_numpy(src).reshape(1,512) - dummy_input1 = torch.from_numpy(segs).reshape(1,512) - dummy_input2 = torch.from_numpy(clss).reshape(1,37) - dummy_input3 = torch.from_numpy(mask).reshape(1,512) - dummy_input4 = torch.from_numpy(mask_cls).reshape(1,37) - #--------------------------------------------------------------------''' - torch.onnx.export(model,(dummy_input0,dummy_input1,dummy_input2,dummy_input3,dummy_input4),onnx_path,input_names = input_names,output_names=output_names,verbose=True,opset_version=9) - -if __name__ =="__main__": - parser = argparse.ArgumentParser() - parser.add_argument("-encoder", default='classifier', type=str, choices=['classifier','transformer','rnn','baseline']) - parser.add_argument("-mode", default='train', type=str, choices=['train','validate','test']) - parser.add_argument("-bert_data_path", default='../bert_data') - parser.add_argument("-model_path", default='../models/') - parser.add_argument("-result_path", default='../results/cnndm') - parser.add_argument("-temp_dir", default='../temp') - parser.add_argument("-bert_config_path", default='../bert_config_uncased_base.json') - - parser.add_argument("-batch_size", default=1000, type=int) - - parser.add_argument("-use_interval", type=str2bool, nargs='?',const=True,default=True) - parser.add_argument("-hidden_size", default=128, type=int) - parser.add_argument("-ff_size", default=512, type=int) - parser.add_argument("-heads", default=4, type=int) - parser.add_argument("-inter_layers", default=2, type=int) - parser.add_argument("-rnn_size", default=512, type=int) - - parser.add_argument("-param_init", default=0, type=float) - parser.add_argument("-param_init_glorot", type=str2bool, nargs='?',const=True,default=True) - parser.add_argument("-dropout", default=0.1, type=float) - parser.add_argument("-optim", default='adam', type=str) - parser.add_argument("-lr", default=1, type=float) - parser.add_argument("-beta1", default= 0.9, type=float) - parser.add_argument("-beta2", default=0.999, type=float) - parser.add_argument("-decay_method", default='', type=str) - parser.add_argument("-warmup_steps", default=8000, type=int) - parser.add_argument("-max_grad_norm", default=0, type=float) - - parser.add_argument("-save_checkpoint_steps", default=5, type=int) - parser.add_argument("-accum_count", default=1, type=int) - parser.add_argument("-world_size", default=1, type=int) - parser.add_argument("-report_every", default=1, type=int) - parser.add_argument("-train_steps", default=1000, type=int) - parser.add_argument("-recall_eval", type=str2bool, nargs='?',const=True,default=False) - - - parser.add_argument('-visible_gpus', default='-1', type=str) - parser.add_argument('-gpu_ranks', default='0', type=str) - parser.add_argument('-log_file', default='../logs/cnndm.log') - parser.add_argument('-dataset', default='') - parser.add_argument('-seed', default=666, type=int) - - parser.add_argument("-test_all", type=str2bool, nargs='?',const=True,default=False) - parser.add_argument("-test_from", default='') - parser.add_argument("-train_from", default='') - parser.add_argument("-report_rouge", type=str2bool, nargs='?',const=True,default=True) - parser.add_argument("-block_trigram", type=str2bool, nargs='?', const=True, default=True) - parser.add_argument("-onnx_path", default="") - parser.add_argument("-path", default="") - - args = parser.parse_args() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 torch +import os +import sys +import argparse +import numpy as np +from pytorch_pretrained_bert import BertConfig +from models.model_builder import Summarizer + +model_flags = ['hidden_size', 'ff_size', 'heads', 'inter_layers','encoder','ff_actv', 'use_interval','rnn_size'] + +def str2bool(v): + if v.lower() in ('yes', 'true', 't', 'y', '1'): + return True + elif v.lower() in ('no', 'false', 'f', 'n', '0'): + return False + else: + raise argparse.ArgumentTypeError('Boolean value expected.') + +def main(args): + input_names=['src','segs','clss','mask','mask_cls'] + output_names = ["output"] + onnx_path = args.onnx_path + device = "cpu" if args.visible_gpus == '-1' else "cuda" + checkpoint = torch.load(args.path, map_location='cpu') + opt = vars(checkpoint['opt']) + for k in opt.keys(): + if (k in model_flags): + setattr(args, k, opt[k]) + config = BertConfig.from_json_file(args.bert_config_path) + model = Summarizer(args, device, load_pretrained_bert=False, bert_config = config) + model.load_cp(checkpoint) + model.eval() + cur_path = os.getcwd() + src = np.fromfile(f'{cur_path}/pre_data/src/data_1.bin', dtype=np.int64) + segs = np.fromfile(f'{cur_path}/pre_data/segs/data_1.bin', dtype=np.int64) + clss = np.fromfile(f'{cur_path}/pre_data/clss/data_1.bin', dtype=np.int64) + mask = np.fromfile(f'{cur_path}/pre_data/mask/data_1.bin', dtype=np.bool_) + mask_cls = np.fromfile(f'{cur_path}/pre_data/mask_cls/data_1.bin', dtype=np.bool_) + print(src.shape) + print(segs.shape) + print(clss.shape) + print(mask.shape) + print(mask_cls.shape) + #-----------------------------13000----------------------------- + dummy_input0 = torch.from_numpy(src).reshape(1,512) + dummy_input1 = torch.from_numpy(segs).reshape(1,512) + dummy_input2 = torch.from_numpy(clss).reshape(1,37) + dummy_input3 = torch.from_numpy(mask).reshape(1,512) + dummy_input4 = torch.from_numpy(mask_cls).reshape(1,37) + #--------------------------------------------------------------------''' + torch.onnx.export(model,(dummy_input0,dummy_input1,dummy_input2,dummy_input3,dummy_input4),onnx_path,input_names = input_names,output_names=output_names,verbose=True,opset_version=9) + +if __name__ =="__main__": + parser = argparse.ArgumentParser() + parser.add_argument("-encoder", default='classifier', type=str, choices=['classifier','transformer','rnn','baseline']) + parser.add_argument("-mode", default='train', type=str, choices=['train','validate','test']) + parser.add_argument("-bert_data_path", default='../bert_data') + parser.add_argument("-model_path", default='../models/') + parser.add_argument("-result_path", default='../results/cnndm') + parser.add_argument("-temp_dir", default='../temp') + parser.add_argument("-bert_config_path", default='../bert_config_uncased_base.json') + + parser.add_argument("-batch_size", default=1000, type=int) + + parser.add_argument("-use_interval", type=str2bool, nargs='?',const=True,default=True) + parser.add_argument("-hidden_size", default=128, type=int) + parser.add_argument("-ff_size", default=512, type=int) + parser.add_argument("-heads", default=4, type=int) + parser.add_argument("-inter_layers", default=2, type=int) + parser.add_argument("-rnn_size", default=512, type=int) + + parser.add_argument("-param_init", default=0, type=float) + parser.add_argument("-param_init_glorot", type=str2bool, nargs='?',const=True,default=True) + parser.add_argument("-dropout", default=0.1, type=float) + parser.add_argument("-optim", default='adam', type=str) + parser.add_argument("-lr", default=1, type=float) + parser.add_argument("-beta1", default= 0.9, type=float) + parser.add_argument("-beta2", default=0.999, type=float) + parser.add_argument("-decay_method", default='', type=str) + parser.add_argument("-warmup_steps", default=8000, type=int) + parser.add_argument("-max_grad_norm", default=0, type=float) + + parser.add_argument("-save_checkpoint_steps", default=5, type=int) + parser.add_argument("-accum_count", default=1, type=int) + parser.add_argument("-world_size", default=1, type=int) + parser.add_argument("-report_every", default=1, type=int) + parser.add_argument("-train_steps", default=1000, type=int) + parser.add_argument("-recall_eval", type=str2bool, nargs='?',const=True,default=False) + + + parser.add_argument('-visible_gpus', default='-1', type=str) + parser.add_argument('-gpu_ranks', default='0', type=str) + parser.add_argument('-log_file', default='../logs/cnndm.log') + parser.add_argument('-dataset', default='') + parser.add_argument('-seed', default=666, type=int) + + parser.add_argument("-test_all", type=str2bool, nargs='?',const=True,default=False) + parser.add_argument("-test_from", default='') + parser.add_argument("-train_from", default='') + parser.add_argument("-report_rouge", type=str2bool, nargs='?',const=True,default=True) + parser.add_argument("-block_trigram", type=str2bool, nargs='?', const=True, default=True) + parser.add_argument("-onnx_path", default="") + parser.add_argument("-path", default="") + + args = parser.parse_args() main(args) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/nlp/BertSum/BertSum_pth_postprocess.py b/ACL_PyTorch/contrib/nlp/BertSum/BertSum_pth_postprocess.py index 695e8abca8..67edaa1269 100644 --- a/ACL_PyTorch/contrib/nlp/BertSum/BertSum_pth_postprocess.py +++ b/ACL_PyTorch/contrib/nlp/BertSum/BertSum_pth_postprocess.py @@ -1,275 +1,275 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 torch -import os -import sys -import argparse -import glob -import numpy as np -from pytorch_pretrained_bert import BertConfig -from models.model_builder import Summarizer -from models import data_loader -from models.data_loader import load_dataset -from models.stats import Statistics -from others.utils import test_rouge -from others.logging import logger - -def str2bool(v): - if v.lower() in ('yes', 'true', 't', 'y', '1'): - return True - elif v.lower() in ('no', 'false', 'f', 'n', '0'): - return False - else: - raise argparse.ArgumentTypeError('Boolean value expected.') - -def rouge_results_to_str(results_dict): - return ">> ROUGE-F(1/2/3/l): {:.2f}/{:.2f}/{:.2f}\nROUGE-R(1/2/3/l): {:.2f}/{:.2f}/{:.2f}\n".format( - results_dict["rouge_1_f_score"] * 100, - results_dict["rouge_2_f_score"] * 100, - results_dict["rouge_l_f_score"] * 100, - results_dict["rouge_1_recall"] * 100, - results_dict["rouge_2_recall"] * 100, - results_dict["rouge_l_recall"] * 100 - ) - -def pre_postprocess(args): - File = os.listdir(args.path_1) - File1 = os.listdir(args.path_2) - list2 = [] - for file in File1: - list2.append(file) - Doc = [] - SENT_SCORES = [] - OUTPUT = [] - for file in sorted(File): - Doc.append(file[0:-6]) - Doc = list(set(Doc)) #grip repeated element - for i in range(len(Doc)): #deal after sorting - ff = 'data_'+str(i)+'_output' - sent_scores = np.fromfile(f'{args.path_1}/{ff}_0.bin', dtype=np.float32) - sent_scores = torch.tensor(sent_scores.reshape(1,sent_scores.shape[0])) - output = np.fromfile(f'{args.path_1}/{ff}_1.bin', dtype=np.bool_) - print(output.shape) - output = torch.tensor(output.reshape(1,37)) - document = ff+'_0.txt' - if document in list2: - doc = document[0:-6] - sent_scores1 = np.fromfile(f'{args.path_2}/{doc}_0.bin', dtype=np.float32) - sent_scores1 = torch.tensor(sent_scores1.reshape(1,sent_scores1.shape[0])) - #############add zero to keep same dimension############## - if sent_scores1.shape[1] > sent_scores.shape[1]: - add_zero = (torch.zeros([1,sent_scores1.shape[1]-sent_scores.shape[1]])) - sent_scores = torch.cat([sent_scores,add_zero],dim=1) - if sent_scores1.shape[1] < sent_scores.shape[1]: - add_zero = (torch.zeros([1,sent_scores.shape[1]-sent_scores1.shape[1]])) - sent_scores1 = torch.cat([sent_scores1,add_zero],dim=1) - ########################################################## - output1 = np.fromfile(f'{args.path_2}/{doc}_1.bin', dtype=np.bool_) - output1 = torch.tensor(output1.reshape(1,37)) - sent_scores = torch.cat([sent_scores,sent_scores1],dim=0) - output = torch.cat([output,output1],dim=0) - SENT_SCORES.append(sent_scores) - OUTPUT.append(output) - test_iter = data_loader.Dataloader(args, load_dataset(args, 'test', shuffle=False), - args.batch_size, device, - shuffle=False, is_test=True) - i=0 - for batch in test_iter: - labels = batch.labels - if SENT_SCORES[i].shape[0] == 1: - if SENT_SCORES[i].shape[1] > labels.shape[1]: - SENT_SCORES[i] = SENT_SCORES[i][:,0:labels.shape[1]] - OUTPUT[i] = OUTPUT[i][:,0:labels.shape[1]] - - if SENT_SCORES[i].shape[1] < labels.shape[1]: - add_zero = (torch.zeros([1,labels.shape[1]-SENT_SCORES[i].shape[1]])) - SENT_SCORES[i] = torch.cat([SENT_SCORES[i],add_zero]) - add_bool = torch.zeros([1,labels.shape[1]-SENT_SCORES[i].shape[1]],dtype=torch.bool) - OUTPUT[i] = torch.cat([OUTPUT[i],add_bool],dim=1) - - if SENT_SCORES[i].shape[0] == 2: - if SENT_SCORES[i].shape[1] > labels.shape[1]: - SENT_SCORES[i] = SENT_SCORES[i][:,0:labels.shape[1]] - OUTPUT[i] = OUTPUT[i][:,0:labels.shape[1]] - if SENT_SCORES[i].shape[1] < labels.shape[1]: - add_zero = (torch.zeros([2,labels.shape[1]-SENT_SCORES[i].shape[1]])) - SENT_SCORES[i] = torch.cat([SENT_SCORES[i],add_zero],dim=1) - add_bool = torch.zeros([2,labels.shape[1]-SENT_SCORES[i].shape[1]],dtype=torch.bool) - OUTPUT[i] = torch.cat([OUTPUT[i],add_bool],dim=1) - i=i+1 - return SENT_SCORES,OUTPUT - -def test(args, step, device, cal_lead=False, cal_oracle=False): - test_iter = data_loader.Dataloader(args, load_dataset(args, 'test', shuffle=False), - args.batch_size, device, - shuffle=False, is_test=True) - def _get_ngrams(n, text): - ngram_set = set() - text_length = len(text) - max_index_ngram_start = text_length - n - for i in range(max_index_ngram_start + 1): - ngram_set.add(tuple(text[i:i + n])) - return ngram_set - - def _block_tri(c, p): - tri_c = _get_ngrams(3, c.split()) - for s in p: - tri_s = _get_ngrams(3, s.split()) - if len(tri_c.intersection(tri_s))>0: - return True - return False - - stats = Statistics() - can_path = '%s_step%d.candidate'%(args.result_path,step) - gold_path = '%s_step%d.gold' % (args.result_path, step) - - sent,output = pre_postprocess(args) - Loss = torch.nn.BCELoss(reduction='none') - sum = 0 - k=0 - with open(can_path, 'w') as save_pred: - with open(gold_path, 'w') as save_gold: - with torch.no_grad(): - for batch in test_iter: - labels = batch.labels - - gold = [] - pred = [] - if (cal_lead): - selected_ids = [list(range(batch.clss.size(1)))] * batch.batch_size - elif (cal_oracle): - selected_ids = [[j for j in range(batch.clss.size(1)) if labels[i][j] == 1] for i in - range(batch.batch_size)] - else: - print(k) - print('sent_scores:',sent[k]) - - if labels.shape[0] != sent[k].shape[0]: - #labels = labels[sent[k].shape[0],:] - k = k + 1 - sum = sum + 1 - continue - - loss = Loss(sent[k], labels.float()) - - if loss.shape[1] != output[k].shape[1]: - k = k + 1 - continue - - loss = (loss * output[k].float()).sum() - batch_stats = Statistics(float(loss.cpu().data.numpy()), len(labels)) - stats.update(batch_stats) - - sent_scores = sent[k] + output[k].float() - sent_scores = sent_scores.cpu().data.numpy() - selected_ids = np.argsort(-sent_scores, 1) - print(selected_ids) - # selected_ids = np.sort(selected_ids,1) - for i, idx in enumerate(selected_ids): - _pred = [] - if(len(batch.src_str[i])==0): - continue - for j in selected_ids[i][:len(batch.src_str[i])]: - if(j>=len( batch.src_str[i])): - continue - candidate = batch.src_str[i][j].strip() - if(args.block_trigram): - if(not _block_tri(candidate,_pred)): - _pred.append(candidate) - else: - _pred.append(candidate) - - if ((not cal_oracle) and (not args.recall_eval) and len(_pred) == 3): - break - - _pred = ''.join(_pred) - if(args.recall_eval): - _pred = ' '.join(_pred.split()[:len(batch.tgt_str[i].split())]) - - pred.append(_pred) - gold.append(batch.tgt_str[i]) - - for i in range(len(gold)): - save_gold.write(gold[i].strip()+'\n') - for i in range(len(pred)): - save_pred.write(pred[i].strip()+'\n') - k = k + 1 - print(sum) - if(step!=-1 and args.report_rouge): - print(can_path) - print(gold_path) - rouges = test_rouge(args.temp_dir, can_path, gold_path) - logger.info('Rouges at step %d \n%s' % (step, rouge_results_to_str(rouges))) - #self._report_step(0, step, valid_stats=stats) - - return stats - -if __name__ =="__main__": - parser = argparse.ArgumentParser() - parser.add_argument("-encoder", default='classifier', type=str, choices=['classifier','transformer','rnn','baseline']) - parser.add_argument("-mode", default='train', type=str, choices=['train','validate','test']) - parser.add_argument("-bert_data_path", default='../bert_data/cnndm') - parser.add_argument("-model_path", default='../models/') - parser.add_argument("-result_path", default='../results/cnndm') - parser.add_argument("-temp_dir", default='../temp') - parser.add_argument("-bert_config_path", default='../bert_config_uncased_base.json') - - parser.add_argument("-batch_size", default=1000, type=int) - - parser.add_argument("-use_interval", type=str2bool, nargs='?',const=True,default=True) - parser.add_argument("-hidden_size", default=128, type=int) - parser.add_argument("-ff_size", default=512, type=int) - parser.add_argument("-heads", default=4, type=int) - parser.add_argument("-inter_layers", default=2, type=int) - parser.add_argument("-rnn_size", default=512, type=int) - - parser.add_argument("-param_init", default=0, type=float) - parser.add_argument("-param_init_glorot", type=str2bool, nargs='?',const=True,default=True) - parser.add_argument("-dropout", default=0.1, type=float) - parser.add_argument("-optim", default='adam', type=str) - parser.add_argument("-lr", default=1, type=float) - parser.add_argument("-beta1", default= 0.9, type=float) - parser.add_argument("-beta2", default=0.999, type=float) - parser.add_argument("-decay_method", default='', type=str) - parser.add_argument("-warmup_steps", default=8000, type=int) - parser.add_argument("-max_grad_norm", default=0, type=float) - - parser.add_argument("-save_checkpoint_steps", default=5, type=int) - parser.add_argument("-accum_count", default=1, type=int) - parser.add_argument("-world_size", default=1, type=int) - parser.add_argument("-report_every", default=1, type=int) - parser.add_argument("-train_steps", default=1000, type=int) - parser.add_argument("-recall_eval", type=str2bool, nargs='?',const=True,default=False) - - - parser.add_argument('-visible_gpus', default='-1', type=str) - parser.add_argument('-gpu_ranks', default='0', type=str) - parser.add_argument('-log_file', default='../logs/cnndm.log') - parser.add_argument('-dataset', default='') - parser.add_argument('-seed', default=666, type=int) - - parser.add_argument("-test_all", type=str2bool, nargs='?',const=True,default=False) - parser.add_argument("-test_from", default='') - parser.add_argument("-train_from", default='') - parser.add_argument("-report_rouge", type=str2bool, nargs='?',const=True,default=True) - parser.add_argument("-block_trigram", type=str2bool, nargs='?', const=True, default=True) - parser.add_argument("-path_1", default="") - parser.add_argument("-path_2", default="") - - args = parser.parse_args() - device = "cpu" if args.visible_gpus == '-1' else "cuda" - device_id = -1 if device == "cpu" else 0 - test(args,0,device) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 torch +import os +import sys +import argparse +import glob +import numpy as np +from pytorch_pretrained_bert import BertConfig +from models.model_builder import Summarizer +from models import data_loader +from models.data_loader import load_dataset +from models.stats import Statistics +from others.utils import test_rouge +from others.logging import logger + +def str2bool(v): + if v.lower() in ('yes', 'true', 't', 'y', '1'): + return True + elif v.lower() in ('no', 'false', 'f', 'n', '0'): + return False + else: + raise argparse.ArgumentTypeError('Boolean value expected.') + +def rouge_results_to_str(results_dict): + return ">> ROUGE-F(1/2/3/l): {:.2f}/{:.2f}/{:.2f}\nROUGE-R(1/2/3/l): {:.2f}/{:.2f}/{:.2f}\n".format( + results_dict["rouge_1_f_score"] * 100, + results_dict["rouge_2_f_score"] * 100, + results_dict["rouge_l_f_score"] * 100, + results_dict["rouge_1_recall"] * 100, + results_dict["rouge_2_recall"] * 100, + results_dict["rouge_l_recall"] * 100 + ) + +def pre_postprocess(args): + File = os.listdir(args.path_1) + File1 = os.listdir(args.path_2) + list2 = [] + for file in File1: + list2.append(file) + Doc = [] + SENT_SCORES = [] + OUTPUT = [] + for file in sorted(File): + Doc.append(file[0:-6]) + Doc = list(set(Doc)) #grip repeated element + for i in range(len(Doc)): #deal after sorting + ff = 'data_'+str(i)+'_output' + sent_scores = np.fromfile(f'{args.path_1}/{ff}_0.bin', dtype=np.float32) + sent_scores = torch.tensor(sent_scores.reshape(1,sent_scores.shape[0])) + output = np.fromfile(f'{args.path_1}/{ff}_1.bin', dtype=np.bool_) + print(output.shape) + output = torch.tensor(output.reshape(1,37)) + document = ff+'_0.txt' + if document in list2: + doc = document[0:-6] + sent_scores1 = np.fromfile(f'{args.path_2}/{doc}_0.bin', dtype=np.float32) + sent_scores1 = torch.tensor(sent_scores1.reshape(1,sent_scores1.shape[0])) + #############add zero to keep same dimension############## + if sent_scores1.shape[1] > sent_scores.shape[1]: + add_zero = (torch.zeros([1,sent_scores1.shape[1]-sent_scores.shape[1]])) + sent_scores = torch.cat([sent_scores,add_zero],dim=1) + if sent_scores1.shape[1] < sent_scores.shape[1]: + add_zero = (torch.zeros([1,sent_scores.shape[1]-sent_scores1.shape[1]])) + sent_scores1 = torch.cat([sent_scores1,add_zero],dim=1) + ########################################################## + output1 = np.fromfile(f'{args.path_2}/{doc}_1.bin', dtype=np.bool_) + output1 = torch.tensor(output1.reshape(1,37)) + sent_scores = torch.cat([sent_scores,sent_scores1],dim=0) + output = torch.cat([output,output1],dim=0) + SENT_SCORES.append(sent_scores) + OUTPUT.append(output) + test_iter = data_loader.Dataloader(args, load_dataset(args, 'test', shuffle=False), + args.batch_size, device, + shuffle=False, is_test=True) + i=0 + for batch in test_iter: + labels = batch.labels + if SENT_SCORES[i].shape[0] == 1: + if SENT_SCORES[i].shape[1] > labels.shape[1]: + SENT_SCORES[i] = SENT_SCORES[i][:,0:labels.shape[1]] + OUTPUT[i] = OUTPUT[i][:,0:labels.shape[1]] + + if SENT_SCORES[i].shape[1] < labels.shape[1]: + add_zero = (torch.zeros([1,labels.shape[1]-SENT_SCORES[i].shape[1]])) + SENT_SCORES[i] = torch.cat([SENT_SCORES[i],add_zero]) + add_bool = torch.zeros([1,labels.shape[1]-SENT_SCORES[i].shape[1]],dtype=torch.bool) + OUTPUT[i] = torch.cat([OUTPUT[i],add_bool],dim=1) + + if SENT_SCORES[i].shape[0] == 2: + if SENT_SCORES[i].shape[1] > labels.shape[1]: + SENT_SCORES[i] = SENT_SCORES[i][:,0:labels.shape[1]] + OUTPUT[i] = OUTPUT[i][:,0:labels.shape[1]] + if SENT_SCORES[i].shape[1] < labels.shape[1]: + add_zero = (torch.zeros([2,labels.shape[1]-SENT_SCORES[i].shape[1]])) + SENT_SCORES[i] = torch.cat([SENT_SCORES[i],add_zero],dim=1) + add_bool = torch.zeros([2,labels.shape[1]-SENT_SCORES[i].shape[1]],dtype=torch.bool) + OUTPUT[i] = torch.cat([OUTPUT[i],add_bool],dim=1) + i=i+1 + return SENT_SCORES,OUTPUT + +def test(args, step, device, cal_lead=False, cal_oracle=False): + test_iter = data_loader.Dataloader(args, load_dataset(args, 'test', shuffle=False), + args.batch_size, device, + shuffle=False, is_test=True) + def _get_ngrams(n, text): + ngram_set = set() + text_length = len(text) + max_index_ngram_start = text_length - n + for i in range(max_index_ngram_start + 1): + ngram_set.add(tuple(text[i:i + n])) + return ngram_set + + def _block_tri(c, p): + tri_c = _get_ngrams(3, c.split()) + for s in p: + tri_s = _get_ngrams(3, s.split()) + if len(tri_c.intersection(tri_s))>0: + return True + return False + + stats = Statistics() + can_path = '%s_step%d.candidate'%(args.result_path,step) + gold_path = '%s_step%d.gold' % (args.result_path, step) + + sent,output = pre_postprocess(args) + Loss = torch.nn.BCELoss(reduction='none') + sum = 0 + k=0 + with open(can_path, 'w') as save_pred: + with open(gold_path, 'w') as save_gold: + with torch.no_grad(): + for batch in test_iter: + labels = batch.labels + + gold = [] + pred = [] + if (cal_lead): + selected_ids = [list(range(batch.clss.size(1)))] * batch.batch_size + elif (cal_oracle): + selected_ids = [[j for j in range(batch.clss.size(1)) if labels[i][j] == 1] for i in + range(batch.batch_size)] + else: + print(k) + print('sent_scores:',sent[k]) + + if labels.shape[0] != sent[k].shape[0]: + #labels = labels[sent[k].shape[0],:] + k = k + 1 + sum = sum + 1 + continue + + loss = Loss(sent[k], labels.float()) + + if loss.shape[1] != output[k].shape[1]: + k = k + 1 + continue + + loss = (loss * output[k].float()).sum() + batch_stats = Statistics(float(loss.cpu().data.numpy()), len(labels)) + stats.update(batch_stats) + + sent_scores = sent[k] + output[k].float() + sent_scores = sent_scores.cpu().data.numpy() + selected_ids = np.argsort(-sent_scores, 1) + print(selected_ids) + # selected_ids = np.sort(selected_ids,1) + for i, idx in enumerate(selected_ids): + _pred = [] + if(len(batch.src_str[i])==0): + continue + for j in selected_ids[i][:len(batch.src_str[i])]: + if(j>=len( batch.src_str[i])): + continue + candidate = batch.src_str[i][j].strip() + if(args.block_trigram): + if(not _block_tri(candidate,_pred)): + _pred.append(candidate) + else: + _pred.append(candidate) + + if ((not cal_oracle) and (not args.recall_eval) and len(_pred) == 3): + break + + _pred = ''.join(_pred) + if(args.recall_eval): + _pred = ' '.join(_pred.split()[:len(batch.tgt_str[i].split())]) + + pred.append(_pred) + gold.append(batch.tgt_str[i]) + + for i in range(len(gold)): + save_gold.write(gold[i].strip()+'\n') + for i in range(len(pred)): + save_pred.write(pred[i].strip()+'\n') + k = k + 1 + print(sum) + if(step!=-1 and args.report_rouge): + print(can_path) + print(gold_path) + rouges = test_rouge(args.temp_dir, can_path, gold_path) + logger.info('Rouges at step %d \n%s' % (step, rouge_results_to_str(rouges))) + #self._report_step(0, step, valid_stats=stats) + + return stats + +if __name__ =="__main__": + parser = argparse.ArgumentParser() + parser.add_argument("-encoder", default='classifier', type=str, choices=['classifier','transformer','rnn','baseline']) + parser.add_argument("-mode", default='train', type=str, choices=['train','validate','test']) + parser.add_argument("-bert_data_path", default='../bert_data/cnndm') + parser.add_argument("-model_path", default='../models/') + parser.add_argument("-result_path", default='../results/cnndm') + parser.add_argument("-temp_dir", default='../temp') + parser.add_argument("-bert_config_path", default='../bert_config_uncased_base.json') + + parser.add_argument("-batch_size", default=1000, type=int) + + parser.add_argument("-use_interval", type=str2bool, nargs='?',const=True,default=True) + parser.add_argument("-hidden_size", default=128, type=int) + parser.add_argument("-ff_size", default=512, type=int) + parser.add_argument("-heads", default=4, type=int) + parser.add_argument("-inter_layers", default=2, type=int) + parser.add_argument("-rnn_size", default=512, type=int) + + parser.add_argument("-param_init", default=0, type=float) + parser.add_argument("-param_init_glorot", type=str2bool, nargs='?',const=True,default=True) + parser.add_argument("-dropout", default=0.1, type=float) + parser.add_argument("-optim", default='adam', type=str) + parser.add_argument("-lr", default=1, type=float) + parser.add_argument("-beta1", default= 0.9, type=float) + parser.add_argument("-beta2", default=0.999, type=float) + parser.add_argument("-decay_method", default='', type=str) + parser.add_argument("-warmup_steps", default=8000, type=int) + parser.add_argument("-max_grad_norm", default=0, type=float) + + parser.add_argument("-save_checkpoint_steps", default=5, type=int) + parser.add_argument("-accum_count", default=1, type=int) + parser.add_argument("-world_size", default=1, type=int) + parser.add_argument("-report_every", default=1, type=int) + parser.add_argument("-train_steps", default=1000, type=int) + parser.add_argument("-recall_eval", type=str2bool, nargs='?',const=True,default=False) + + + parser.add_argument('-visible_gpus', default='-1', type=str) + parser.add_argument('-gpu_ranks', default='0', type=str) + parser.add_argument('-log_file', default='../logs/cnndm.log') + parser.add_argument('-dataset', default='') + parser.add_argument('-seed', default=666, type=int) + + parser.add_argument("-test_all", type=str2bool, nargs='?',const=True,default=False) + parser.add_argument("-test_from", default='') + parser.add_argument("-train_from", default='') + parser.add_argument("-report_rouge", type=str2bool, nargs='?',const=True,default=True) + parser.add_argument("-block_trigram", type=str2bool, nargs='?', const=True, default=True) + parser.add_argument("-path_1", default="") + parser.add_argument("-path_2", default="") + + args = parser.parse_args() + device = "cpu" if args.visible_gpus == '-1' else "cuda" + device_id = -1 if device == "cpu" else 0 + test(args,0,device) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/nlp/BertSum/BertSum_pth_preprocess.py b/ACL_PyTorch/contrib/nlp/BertSum/BertSum_pth_preprocess.py index f3ddcfef2f..19a09793ce 100644 --- a/ACL_PyTorch/contrib/nlp/BertSum/BertSum_pth_preprocess.py +++ b/ACL_PyTorch/contrib/nlp/BertSum/BertSum_pth_preprocess.py @@ -1,179 +1,179 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 argparse -import os -import torch - -from models import data_loader -from models.data_loader import load_dataset -from models.trainer import build_trainer - -def str2bool(v): - if v.lower() in ('yes', 'true', 't', 'y', '1'): - return True - elif v.lower() in ('no', 'false', 'f', 'n', '0'): - return False - else: - raise argparse.ArgumentTypeError('Boolean value expected.') -def get_max_shape(test_iter): - max_shape_1=0 - max_shape_2=0 - for batch in test_iter: - if batch.src.shape[1] > max_shape_1: - max_shape_1 = batch.src.shape[1] - if batch.clss.shape[1] > max_shape_2: - max_shape_2 = batch.clss.shape[1] - #print(batch.src[0].shape) - return max_shape_1,max_shape_2 - -def preprocess(args,device): - test_iter =data_loader.Dataloader(args, load_dataset(args, 'test', shuffle=False), - args.batch_size, device, - shuffle=False, is_test=True) - test_iter1 =data_loader.Dataloader(args, load_dataset(args, 'test', shuffle=False), - args.batch_size, device, - shuffle=False, is_test=True) - cur_path = os.getcwd() - main_path = cur_path + '/pre_data' - main_path_1 = cur_path + '/pre_data_1' - i=0 - if not os.path.exists(os.path.join(cur_path,'pre_data')): ###########first inference - os.makedirs(os.path.join(cur_path,'pre_data')) - if not os.path.exists(os.path.join(main_path,'src')): - os.makedirs(os.path.join(main_path,'src')) - if not os.path.exists(os.path.join(main_path,'segs')): - os.makedirs(os.path.join(main_path,'segs')) - if not os.path.exists(os.path.join(main_path,'clss')): - os.makedirs(os.path.join(main_path,'clss')) - if not os.path.exists(os.path.join(main_path,'mask')): - os.makedirs(os.path.join(main_path,'mask')) - if not os.path.exists(os.path.join(main_path,'mask_cls')): - os.makedirs(os.path.join(main_path,'mask_cls')) - - if not os.path.exists(os.path.join(cur_path,'pre_data_1')): ###########second inference - os.makedirs(os.path.join(cur_path,'pre_data_1')) - if not os.path.exists(os.path.join(main_path_1,'src')): - os.makedirs(os.path.join(main_path_1,'src')) - if not os.path.exists(os.path.join(main_path_1,'segs')): - os.makedirs(os.path.join(main_path_1,'segs')) - if not os.path.exists(os.path.join(main_path_1,'clss')): - os.makedirs(os.path.join(main_path_1,'clss')) - if not os.path.exists(os.path.join(main_path_1,'mask')): - os.makedirs(os.path.join(main_path_1,'mask')) - if not os.path.exists(os.path.join(main_path_1,'mask_cls')): - os.makedirs(os.path.join(main_path_1,'mask_cls')) - max_shape_1,max_shape_2 = get_max_shape(test_iter) - print(max_shape_1,max_shape_2) - #############################above get max dimension ########################### - for batch in test_iter1: - if batch.src.shape[0]==2: - if batch.src[0].shape[0] < max_shape_1: - add_zero = (torch.zeros([batch.src.shape[0],max_shape_1-batch.src[0].shape[0]])).long() #######change to int64 - add_bool = torch.zeros([batch.src.shape[0],max_shape_1-batch.src[0].shape[0]],dtype=torch.bool) - batch.src = torch.cat([batch.src,add_zero],dim=1) - batch.segs = torch.cat([batch.segs,add_zero],dim=1) - batch.mask = torch.cat([batch.mask,add_bool],dim=1) - if batch.clss[0].shape[0] < max_shape_2: - add_zero = (torch.zeros([batch.clss.shape[0],max_shape_2-batch.clss[0].shape[0]])).long() #######change to int64 - add_bool = torch.zeros([batch.clss.shape[0],max_shape_2-batch.clss[0].shape[0]],dtype=torch.bool) - batch.clss = torch.cat([batch.clss,add_zero],dim=1) - batch.mask_cls = torch.cat([batch.mask_cls,add_bool],dim=1) - ##############first dimension - batch.src[0].numpy().tofile(os.path.join(main_path,'src','data_'+str(i)+'.bin')) - batch.segs[0].numpy().tofile(os.path.join(main_path,'segs','data_'+str(i)+'.bin')) - batch.clss[0].numpy().tofile(os.path.join(main_path,'clss','data_'+str(i)+'.bin')) - batch.mask[0].numpy().tofile(os.path.join(main_path,'mask','data_'+str(i)+'.bin')) - batch.mask_cls[0].numpy().tofile(os.path.join(main_path,'mask_cls','data_'+str(i)+'.bin')) - #############second dimension - batch.src[1].numpy().tofile(os.path.join(main_path_1,'src','data_'+str(i)+'.bin')) - batch.segs[1].numpy().tofile(os.path.join(main_path_1,'segs','data_'+str(i)+'.bin')) - batch.clss[1].numpy().tofile(os.path.join(main_path_1,'clss','data_'+str(i)+'.bin')) - batch.mask[1].numpy().tofile(os.path.join(main_path_1,'mask','data_'+str(i)+'.bin')) - batch.mask_cls[1].numpy().tofile(os.path.join(main_path_1,'mask_cls','data_'+str(i)+'.bin')) - else: - #print(batch.clss.dtype) - if batch.src[0].shape[0] < max_shape_1: - add_zero = (torch.zeros([batch.src.shape[0],max_shape_1-batch.src[0].shape[0]])).long() #######change to int64 - add_bool = torch.zeros([batch.src.shape[0],max_shape_1-batch.src[0].shape[0]],dtype=torch.bool) - batch.src = torch.cat([batch.src,add_zero],dim=1) - batch.segs = torch.cat([batch.segs,add_zero],dim=1) - batch.mask = torch.cat([batch.mask,add_bool],dim=1) - if batch.clss[0].shape[0] < max_shape_2: - add_zero = (torch.zeros([batch.clss.shape[0],max_shape_2-batch.clss[0].shape[0]])).long() #######change to int64 - add_bool = torch.zeros([batch.clss.shape[0],max_shape_2-batch.clss[0].shape[0]],dtype=torch.bool) - batch.clss = torch.cat([batch.clss,add_zero],dim=1) - batch.mask_cls = torch.cat([batch.mask_cls,add_bool],dim=1) - batch.src.numpy().tofile(os.path.join(main_path,'src','data_'+str(i)+'.bin')) - batch.segs.numpy().tofile(os.path.join(main_path,'segs','data_'+str(i)+'.bin')) - batch.clss.numpy().tofile(os.path.join(main_path,'clss','data_'+str(i)+'.bin')) - batch.mask.numpy().tofile(os.path.join(main_path,'mask','data_'+str(i)+'.bin')) - batch.mask_cls.numpy().tofile(os.path.join(main_path,'mask_cls','data_'+str(i)+'.bin')) - i = i+1 - -if __name__ =="__main__": - parser = argparse.ArgumentParser() - parser.add_argument("-encoder", default='classifier', type=str, choices=['classifier','transformer','rnn','baseline']) - parser.add_argument("-mode", default='train', type=str, choices=['train','validate','test']) - parser.add_argument("-bert_data_path", default='../bert_data') - parser.add_argument("-model_path", default='../models/') - parser.add_argument("-result_path", default='../results/cnndm') - parser.add_argument("-temp_dir", default='../temp') - parser.add_argument("-bert_config_path", default='../bert_config_uncased_base.json') - - parser.add_argument("-batch_size", default=1000, type=int) - - parser.add_argument("-use_interval", type=str2bool, nargs='?',const=True,default=True) - parser.add_argument("-hidden_size", default=128, type=int) - parser.add_argument("-ff_size", default=512, type=int) - parser.add_argument("-heads", default=4, type=int) - parser.add_argument("-inter_layers", default=2, type=int) - parser.add_argument("-rnn_size", default=512, type=int) - - parser.add_argument("-param_init", default=0, type=float) - parser.add_argument("-param_init_glorot", type=str2bool, nargs='?',const=True,default=True) - parser.add_argument("-dropout", default=0.1, type=float) - parser.add_argument("-optim", default='adam', type=str) - parser.add_argument("-lr", default=1, type=float) - parser.add_argument("-beta1", default= 0.9, type=float) - parser.add_argument("-beta2", default=0.999, type=float) - parser.add_argument("-decay_method", default='', type=str) - parser.add_argument("-warmup_steps", default=8000, type=int) - parser.add_argument("-max_grad_norm", default=0, type=float) - - parser.add_argument("-save_checkpoint_steps", default=5, type=int) - parser.add_argument("-accum_count", default=1, type=int) - parser.add_argument("-world_size", default=1, type=int) - parser.add_argument("-report_every", default=1, type=int) - parser.add_argument("-train_steps", default=1000, type=int) - parser.add_argument("-recall_eval", type=str2bool, nargs='?',const=True,default=False) - - parser.add_argument('-visible_gpus', default='-1', type=str) - parser.add_argument('-gpu_ranks', default='0', type=str) - parser.add_argument('-log_file', default='../logs/cnndm.log') - parser.add_argument('-dataset', default='') - parser.add_argument('-seed', default=666, type=int) - - parser.add_argument("-test_all", type=str2bool, nargs='?',const=True,default=False) - parser.add_argument("-test_from", default='') - parser.add_argument("-train_from", default='') - parser.add_argument("-report_rouge", type=str2bool, nargs='?',const=True,default=True) - parser.add_argument("-block_trigram", type=str2bool, nargs='?', const=True, default=True) - parser.add_argument("-onnx_path", default="") - parser.add_argument("-path", default="") - - args = parser.parse_args() - device = "cpu" if args.visible_gpus == '-1' else "cuda" - device_id = -1 if device == "cpu" else 0 - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 argparse +import os +import torch + +from models import data_loader +from models.data_loader import load_dataset +from models.trainer import build_trainer + +def str2bool(v): + if v.lower() in ('yes', 'true', 't', 'y', '1'): + return True + elif v.lower() in ('no', 'false', 'f', 'n', '0'): + return False + else: + raise argparse.ArgumentTypeError('Boolean value expected.') +def get_max_shape(test_iter): + max_shape_1=0 + max_shape_2=0 + for batch in test_iter: + if batch.src.shape[1] > max_shape_1: + max_shape_1 = batch.src.shape[1] + if batch.clss.shape[1] > max_shape_2: + max_shape_2 = batch.clss.shape[1] + #print(batch.src[0].shape) + return max_shape_1,max_shape_2 + +def preprocess(args,device): + test_iter =data_loader.Dataloader(args, load_dataset(args, 'test', shuffle=False), + args.batch_size, device, + shuffle=False, is_test=True) + test_iter1 =data_loader.Dataloader(args, load_dataset(args, 'test', shuffle=False), + args.batch_size, device, + shuffle=False, is_test=True) + cur_path = os.getcwd() + main_path = cur_path + '/pre_data' + main_path_1 = cur_path + '/pre_data_1' + i=0 + if not os.path.exists(os.path.join(cur_path,'pre_data')): ###########first inference + os.makedirs(os.path.join(cur_path,'pre_data')) + if not os.path.exists(os.path.join(main_path,'src')): + os.makedirs(os.path.join(main_path,'src')) + if not os.path.exists(os.path.join(main_path,'segs')): + os.makedirs(os.path.join(main_path,'segs')) + if not os.path.exists(os.path.join(main_path,'clss')): + os.makedirs(os.path.join(main_path,'clss')) + if not os.path.exists(os.path.join(main_path,'mask')): + os.makedirs(os.path.join(main_path,'mask')) + if not os.path.exists(os.path.join(main_path,'mask_cls')): + os.makedirs(os.path.join(main_path,'mask_cls')) + + if not os.path.exists(os.path.join(cur_path,'pre_data_1')): ###########second inference + os.makedirs(os.path.join(cur_path,'pre_data_1')) + if not os.path.exists(os.path.join(main_path_1,'src')): + os.makedirs(os.path.join(main_path_1,'src')) + if not os.path.exists(os.path.join(main_path_1,'segs')): + os.makedirs(os.path.join(main_path_1,'segs')) + if not os.path.exists(os.path.join(main_path_1,'clss')): + os.makedirs(os.path.join(main_path_1,'clss')) + if not os.path.exists(os.path.join(main_path_1,'mask')): + os.makedirs(os.path.join(main_path_1,'mask')) + if not os.path.exists(os.path.join(main_path_1,'mask_cls')): + os.makedirs(os.path.join(main_path_1,'mask_cls')) + max_shape_1,max_shape_2 = get_max_shape(test_iter) + print(max_shape_1,max_shape_2) + #############################above get max dimension ########################### + for batch in test_iter1: + if batch.src.shape[0]==2: + if batch.src[0].shape[0] < max_shape_1: + add_zero = (torch.zeros([batch.src.shape[0],max_shape_1-batch.src[0].shape[0]])).long() #######change to int64 + add_bool = torch.zeros([batch.src.shape[0],max_shape_1-batch.src[0].shape[0]],dtype=torch.bool) + batch.src = torch.cat([batch.src,add_zero],dim=1) + batch.segs = torch.cat([batch.segs,add_zero],dim=1) + batch.mask = torch.cat([batch.mask,add_bool],dim=1) + if batch.clss[0].shape[0] < max_shape_2: + add_zero = (torch.zeros([batch.clss.shape[0],max_shape_2-batch.clss[0].shape[0]])).long() #######change to int64 + add_bool = torch.zeros([batch.clss.shape[0],max_shape_2-batch.clss[0].shape[0]],dtype=torch.bool) + batch.clss = torch.cat([batch.clss,add_zero],dim=1) + batch.mask_cls = torch.cat([batch.mask_cls,add_bool],dim=1) + ##############first dimension + batch.src[0].numpy().tofile(os.path.join(main_path,'src','data_'+str(i)+'.bin')) + batch.segs[0].numpy().tofile(os.path.join(main_path,'segs','data_'+str(i)+'.bin')) + batch.clss[0].numpy().tofile(os.path.join(main_path,'clss','data_'+str(i)+'.bin')) + batch.mask[0].numpy().tofile(os.path.join(main_path,'mask','data_'+str(i)+'.bin')) + batch.mask_cls[0].numpy().tofile(os.path.join(main_path,'mask_cls','data_'+str(i)+'.bin')) + #############second dimension + batch.src[1].numpy().tofile(os.path.join(main_path_1,'src','data_'+str(i)+'.bin')) + batch.segs[1].numpy().tofile(os.path.join(main_path_1,'segs','data_'+str(i)+'.bin')) + batch.clss[1].numpy().tofile(os.path.join(main_path_1,'clss','data_'+str(i)+'.bin')) + batch.mask[1].numpy().tofile(os.path.join(main_path_1,'mask','data_'+str(i)+'.bin')) + batch.mask_cls[1].numpy().tofile(os.path.join(main_path_1,'mask_cls','data_'+str(i)+'.bin')) + else: + #print(batch.clss.dtype) + if batch.src[0].shape[0] < max_shape_1: + add_zero = (torch.zeros([batch.src.shape[0],max_shape_1-batch.src[0].shape[0]])).long() #######change to int64 + add_bool = torch.zeros([batch.src.shape[0],max_shape_1-batch.src[0].shape[0]],dtype=torch.bool) + batch.src = torch.cat([batch.src,add_zero],dim=1) + batch.segs = torch.cat([batch.segs,add_zero],dim=1) + batch.mask = torch.cat([batch.mask,add_bool],dim=1) + if batch.clss[0].shape[0] < max_shape_2: + add_zero = (torch.zeros([batch.clss.shape[0],max_shape_2-batch.clss[0].shape[0]])).long() #######change to int64 + add_bool = torch.zeros([batch.clss.shape[0],max_shape_2-batch.clss[0].shape[0]],dtype=torch.bool) + batch.clss = torch.cat([batch.clss,add_zero],dim=1) + batch.mask_cls = torch.cat([batch.mask_cls,add_bool],dim=1) + batch.src.numpy().tofile(os.path.join(main_path,'src','data_'+str(i)+'.bin')) + batch.segs.numpy().tofile(os.path.join(main_path,'segs','data_'+str(i)+'.bin')) + batch.clss.numpy().tofile(os.path.join(main_path,'clss','data_'+str(i)+'.bin')) + batch.mask.numpy().tofile(os.path.join(main_path,'mask','data_'+str(i)+'.bin')) + batch.mask_cls.numpy().tofile(os.path.join(main_path,'mask_cls','data_'+str(i)+'.bin')) + i = i+1 + +if __name__ =="__main__": + parser = argparse.ArgumentParser() + parser.add_argument("-encoder", default='classifier', type=str, choices=['classifier','transformer','rnn','baseline']) + parser.add_argument("-mode", default='train', type=str, choices=['train','validate','test']) + parser.add_argument("-bert_data_path", default='../bert_data') + parser.add_argument("-model_path", default='../models/') + parser.add_argument("-result_path", default='../results/cnndm') + parser.add_argument("-temp_dir", default='../temp') + parser.add_argument("-bert_config_path", default='../bert_config_uncased_base.json') + + parser.add_argument("-batch_size", default=1000, type=int) + + parser.add_argument("-use_interval", type=str2bool, nargs='?',const=True,default=True) + parser.add_argument("-hidden_size", default=128, type=int) + parser.add_argument("-ff_size", default=512, type=int) + parser.add_argument("-heads", default=4, type=int) + parser.add_argument("-inter_layers", default=2, type=int) + parser.add_argument("-rnn_size", default=512, type=int) + + parser.add_argument("-param_init", default=0, type=float) + parser.add_argument("-param_init_glorot", type=str2bool, nargs='?',const=True,default=True) + parser.add_argument("-dropout", default=0.1, type=float) + parser.add_argument("-optim", default='adam', type=str) + parser.add_argument("-lr", default=1, type=float) + parser.add_argument("-beta1", default= 0.9, type=float) + parser.add_argument("-beta2", default=0.999, type=float) + parser.add_argument("-decay_method", default='', type=str) + parser.add_argument("-warmup_steps", default=8000, type=int) + parser.add_argument("-max_grad_norm", default=0, type=float) + + parser.add_argument("-save_checkpoint_steps", default=5, type=int) + parser.add_argument("-accum_count", default=1, type=int) + parser.add_argument("-world_size", default=1, type=int) + parser.add_argument("-report_every", default=1, type=int) + parser.add_argument("-train_steps", default=1000, type=int) + parser.add_argument("-recall_eval", type=str2bool, nargs='?',const=True,default=False) + + parser.add_argument('-visible_gpus', default='-1', type=str) + parser.add_argument('-gpu_ranks', default='0', type=str) + parser.add_argument('-log_file', default='../logs/cnndm.log') + parser.add_argument('-dataset', default='') + parser.add_argument('-seed', default=666, type=int) + + parser.add_argument("-test_all", type=str2bool, nargs='?',const=True,default=False) + parser.add_argument("-test_from", default='') + parser.add_argument("-train_from", default='') + parser.add_argument("-report_rouge", type=str2bool, nargs='?',const=True,default=True) + parser.add_argument("-block_trigram", type=str2bool, nargs='?', const=True, default=True) + parser.add_argument("-onnx_path", default="") + parser.add_argument("-path", default="") + + args = parser.parse_args() + device = "cpu" if args.visible_gpus == '-1' else "cuda" + device_id = -1 if device == "cpu" else 0 + preprocess(args,device) \ No newline at end of file diff --git a/ACL_PyTorch/contrib/nlp/BertSum/README.md b/ACL_PyTorch/contrib/nlp/BertSum/README.md index 03d573f8d3..90d73c9361 100644 --- a/ACL_PyTorch/contrib/nlp/BertSum/README.md +++ b/ACL_PyTorch/contrib/nlp/BertSum/README.md @@ -1,285 +1,285 @@ - - -# BertSum Onnx模型端到端推理指导 - -- 1 模型概述 - - [1.1 代码地址](https://gitee.com/kghhkhkljl/pyramidbox.git) -- 2 环境说明 - - [2.1 深度学习框架](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#21-深度学习框架) - - [2.2 python第三方库](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#22-python第三方库) -- 3 模型转换 - - [3.1 pth转onnx模型](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#31-pth转onnx模型) - - [3.2 onnx转om模型](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#32-onnx转om模型) -- 4 数据集预处理 - - [4.1 数据集获取](https://www.graviti.cn/open-datasets/WIDER_FACE) - - [4.2 数据集预处理](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#42-数据集预处理) - - [4.3 生成数据集信息文件](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#43-生成数据集信息文件) -- 5 离线推理 - - [5.1 benchmark工具概述](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#51-benchmark工具概述) - - [5.2 离线推理](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#52-离线推理) -- 6 精度对比 - - [6.1 离线推理精度统计](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#61-离线推理精度统计) - - [6.2 开源精度](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#62-开源精度) - - [6.3 精度对比](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#63-精度对比) -- 7 性能对比 - - [7.1 npu性能数据](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#71-npu性能数据) - - [7.2 T4性能数据](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#72-T4性能数据) - - [7.3 性能对比](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#73-性能对比) - -## 1 模型概述 - -- **论文地址** -- **代码地址** - -### 1.1 论文地址 - -[Bertsum论文](https://arxiv.org/abs/1803.07737) - -### 1.2 代码地址 - -https://github.com/nlpyang/BertSum.git - -## 2 环境说明 - -- **深度学习框架** -- **python第三方库** - -### 2.1 深度学习框架 - -``` -python3.7.5 -CANN 5.0.3 - -pytorch >= 1.5.0 -torchvision >= 0.10.0 -onnx >= 1.7.0 - -说明:若是在conda环境下,直接采用python,不用python3.7 -``` - -### 2.2 python第三方库 - -``` -torch==1.7.1 -tensorboardX==2.4.1 -pyrouge==0.1.3 -pytorch-pretrained-bert==0.6.2 -onnx-simplifier==0.3.6 -``` - -### **2.3 环境配置** - -ROUGE配置参考博客: - -[(10条消息) Ubuntu安装配置ROUGE_BigSea-CSDN博客](https://blog.csdn.net/Hay54/article/details/78744912) - -pyrouge配置参考博客: - -[(10条消息) 在Ubuntu下配置pyrouge_MerryCao的博客-CSDN博客](https://blog.csdn.net/MerryCao/article/details/49174283) - -## 3 模型转换 - -- **pth转onnx模型** -- **onnx转om模型** - -### 3.1 pth转onnx模型 - -1.拉取代码仓库 (因为使用了开源代码模块,所以需要git clone一下) - -```shell -git clone https://github.com/nlpyang/BertSum.git -``` - -克隆下来源代码并解压,将pr中的代码放到解压之后的BertSum/src目录下面并对BertSum/src/models/data_loder.py进行一个更改: - -将31行的mask=1-(src==0)修改为mask=~(src==0) 将35行的mask=1-(clss==-1)修改为mask=~(clss==-1) - -2.下载pth权重文件 - -权重文件默认存放在**/home/BertSum/src**目录下 - -3.使用pth2onnx.py进行onnx的转换 - -``` -方法一:cd /home/BertSum/src/test -bash pth2onnx.sh -方法二:cd /home/BertSum/src -python BertSum-pth2onnx.py -mode test -bert_data_path ../bert_data/cnndm -model_path MODEL_PATH -visible_gpus -1 -gpu_ranks 0 -batch_size 1 -log_file LOG_FILE -result_path RESULT_PATH -test_all -block_trigram true -onnx_path bertsum_13000_9_bs1.onnx -path model_step_13000.pt -``` - -获得bertsum_13000_9_bs1.onnx文件 - -方法二种的-bert_data_path是数据集所在目录,-batch_size需设置为1,-onnx_path是onnx输出文件 - -### 3.2 onnx模型简化 - -由于存在expand算子导致转om不成功,所以需要使用onnx简化工具对onnx进行简化 - -使用pth2onnx.py进行onnx的转换 - -``` -方法一:cd /home/BertSum/src/test -bash simplify.sh -方法二:cd /home/BertSum/src -python -m onnxsim ./bertsum_13000_9_bs1.onnx ./bertsum_13000_9_sim_bs1.onnx -``` - -获得bertsum_13000_9_sim_bs1.onnx文件 - -### 3.3 onnx简化模型转om模型 - -1.设置环境变量 - -``` -source atc.sh -``` - -2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.3 开发辅助工具指南 (推理) 01 - -``` -方法一:cd /home/BertSum/src/test -bash onnxToom.sh -方法二:cd /home/BertSum/src -atc --input_format=ND --framework=5 --model=./bertsum_13000_9_sim_bs1.onnx --input_shape="src:1,512;segs:1,512;clss:1,37;mask:1,512;mask_cls:1,37" --output=bertsum_13000_9_sim_bs1 \ ---log=info --soc_version=Ascend310 --precision_mode=allow_mix_precision \ ---modify_mixlist=ops_info.json -``` - -方法二中的model是onnx模型的名字,input_shape是paper的shape,output为输出om的名字,--precision_mode表示采用混合精度 - -## 4 数据集预处理 - -- **数据集获取** -- **数据集预处理** -- **生成数据集信息文件** - -### 4.1 数据集获取 - -参考原代码仓 - -### 4.2 数据集预处理 - -1.预处理脚本BertSum_pth_preprocess.py - -2.执行预处理脚本,生成数据集预处理后的bin文件 - -``` -方法一:cd /home/BertSum/src/test -bash pre_deal.sh -方法二:cd /home/BertSum/src -python BertSum_pth_preprocess.py -mode test -bert_data_path ../bert_data/cnndm -model_path MODEL_PATH -visible_gpus -1 -gpu_ranks 0 -batch_size 600 -log_file LOG_FILE -result_path RESULT_PATH -test_all -block_trigram true -``` - --bert_data_path是数据集所在目录,后面的参数是固定的。 - -### 5 离线推理 - -- **msame工具** -- **离线推理** - -### 5.1 msame工具 - -获取msame工具(https://gitee.com/ascend/tools/tree/master/msame),并将得到的msame工具放在/home/BertSum-master/src下 - -### 5.2 离线推理 - -1.执行离线推理 - -benchmark工具暂不支持多输入,因此改用msame,首先要source环境变量 - -``` -source env.sh -``` - -2.使用msame将onnx模型转换为om模型文件,工具使用方法可以参考CANN - -然后运行如下命令: - -``` -方法一:cd /home/BertSum/src/test -bash infer.sh -方法二:cd /home/BertSum/src -./msame --model "./bertsum_13000_9_sim_bs1_1.om" --input "./pre_data/src,./pre_data/segs,./pre_data/clss,./pre_data/mask,./pre_data/mask_cls" --output "./result" --outfmt bin -./msame --model "./bertsum_13000_9_sim_bs1_1.om" --input "./pre_data_1/src,./pre_data_1/segs,./pre_data_1/clss,./pre_data_1/mask,./pre_data_1/mask_cls" --output "./result" --outfmt bin -``` - -要采用msema工具推理两次,因为有些paper的shape第一维为2,所以分两次进行推理。pre_data下存放的是shape为第一维为1的所有预处理之后的数据以及shape为2的部分预处理得到的数据。shape为2的另一部分数据存放在pre_data_1下面。--model是om文件,--input是预处理之后文件所在目录,--output为输出bin文件所在目录,--outfmt代表输出bin文件*。* - -输出的bin文件在/home/BertSum-master/src/result目录下,此目录下会存在两个文件,将其中一个时间小的命名为result_1,将另一个时间大的命名为result_2。 - -## 6 精度对比 - -- **离线推理精度** -- **开源精度** -- **精度对比** - -### 6.1 离线推理精度统计 - -1.后处理 - -``` -cd /home/BertSum/src -python BertSum_pth_postprocess.py -visible_gpus -1 -gpu_ranks 0 -batch_size 600 -log_file LOG_FILE -result_path RESULT_PATH -test_all -block_trigram true -path_1 ./result/result_1 -path_2 ./result/result_2 -``` - -``` - -path_1是推理得到的文件result_1,-path_2是推理得到的result_2 - 自验报告 - # 第X次验收测试 - # 验收结果 OK - # 验收环境: A + K / CANN 5.0.3 - # 关联issue: - - # pth是否能正确转换为om - bash test/onnx2om.sh - # 验收结果: OK - # 备注: 成功生成om,无运行报错,报错日志xx 等 - - # 精度数据是否达标(需要显示官网pth精度与om模型的精度) - # npu性能数据(由于msame工具不支持多batch,所以只测试了bs1的性能) - # 验收结果: 是 / 否 - # 备注: 目标pth精度42.96;bs1验收om精度42.92;精度下降不超过1%;无运行报错,报错日志xx 等 - # 备注: 验收310测试性能bs1:61.538FPS;无运行报错,报错日志xx 等 - - # 在t4上测试bs1性能 - bash perf.sh - # 验收结果: OK / Failed - # 备注: 验收基准测试性能bs1:94.281FPS;无运行报错,报错日志xx 等 - - # 310性能是否超过基准: 否 - t4:310=(94.281/61.538)1.53倍基准 -``` - -### 6.2 开源精度 - -BertSum在线训练精度: - -42.96% - -### 6.3 离线推理精度 - -42.95% - -### 6.3 精度对比 - -由于源码采用的是动态shape,而离线推理是通过加padding固定住shape进行推理的,所以精度会有损失,因此和同一分辨率下的在线推理进行对比。对比方式:三个尺度求和取平均。 - -## 7 性能对比 - -- **310性能数据** -- **T4性能数据** -- **性能对比** - -### 7.1 310性能数据 - -每张图片平均耗时:65.06ms,所以310吞吐率为:1000/65×4=61.538 - -说明:由于msame不支持多batch,所以此处只测了bs1的性能。 - -### 7.2 T4性能数据 - -T4性能为:94.281 - -### 7.3 性能对比 - + + +# BertSum Onnx模型端到端推理指导 + +- 1 模型概述 + - [1.1 代码地址](https://gitee.com/kghhkhkljl/pyramidbox.git) +- 2 环境说明 + - [2.1 深度学习框架](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#21-深度学习框架) + - [2.2 python第三方库](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#22-python第三方库) +- 3 模型转换 + - [3.1 pth转onnx模型](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#31-pth转onnx模型) + - [3.2 onnx转om模型](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#32-onnx转om模型) +- 4 数据集预处理 + - [4.1 数据集获取](https://www.graviti.cn/open-datasets/WIDER_FACE) + - [4.2 数据集预处理](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#42-数据集预处理) + - [4.3 生成数据集信息文件](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#43-生成数据集信息文件) +- 5 离线推理 + - [5.1 benchmark工具概述](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/ResNext50#51-benchmark工具概述) + - [5.2 离线推理](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#52-离线推理) +- 6 精度对比 + - [6.1 离线推理精度统计](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#61-离线推理精度统计) + - [6.2 开源精度](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#62-开源精度) + - [6.3 精度对比](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#63-精度对比) +- 7 性能对比 + - [7.1 npu性能数据](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#71-npu性能数据) + - [7.2 T4性能数据](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#72-T4性能数据) + - [7.3 性能对比](https://gitee.com/ascend/modelzoo/tree/master/built-in/ACL_PyTorch/Benchmark/cv/classification/Pyramidbox#73-性能对比) + +## 1 模型概述 + +- **论文地址** +- **代码地址** + +### 1.1 论文地址 + +[Bertsum论文](https://arxiv.org/abs/1803.07737) + +### 1.2 代码地址 + +https://github.com/nlpyang/BertSum.git + +## 2 环境说明 + +- **深度学习框架** +- **python第三方库** + +### 2.1 深度学习框架 + +``` +python3.7.5 +CANN 5.0.3 + +pytorch >= 1.5.0 +torchvision >= 0.10.0 +onnx >= 1.7.0 + +说明:若是在conda环境下,直接采用python,不用python3.7 +``` + +### 2.2 python第三方库 + +``` +torch==1.7.1 +tensorboardX==2.4.1 +pyrouge==0.1.3 +pytorch-pretrained-bert==0.6.2 +onnx-simplifier==0.3.6 +``` + +### **2.3 环境配置** + +ROUGE配置参考博客: + +[(10条消息) Ubuntu安装配置ROUGE_BigSea-CSDN博客](https://blog.csdn.net/Hay54/article/details/78744912) + +pyrouge配置参考博客: + +[(10条消息) 在Ubuntu下配置pyrouge_MerryCao的博客-CSDN博客](https://blog.csdn.net/MerryCao/article/details/49174283) + +## 3 模型转换 + +- **pth转onnx模型** +- **onnx转om模型** + +### 3.1 pth转onnx模型 + +1.拉取代码仓库 (因为使用了开源代码模块,所以需要git clone一下) + +```shell +git clone https://github.com/nlpyang/BertSum.git +``` + +克隆下来源代码并解压,将pr中的代码放到解压之后的BertSum/src目录下面并对BertSum/src/models/data_loder.py进行一个更改: + +将31行的mask=1-(src==0)修改为mask=~(src==0) 将35行的mask=1-(clss==-1)修改为mask=~(clss==-1) + +2.下载pth权重文件 + +权重文件默认存放在**/home/BertSum/src**目录下 + +3.使用pth2onnx.py进行onnx的转换 + +``` +方法一:cd /home/BertSum/src/test +bash pth2onnx.sh +方法二:cd /home/BertSum/src +python BertSum-pth2onnx.py -mode test -bert_data_path ../bert_data/cnndm -model_path MODEL_PATH -visible_gpus -1 -gpu_ranks 0 -batch_size 1 -log_file LOG_FILE -result_path RESULT_PATH -test_all -block_trigram true -onnx_path bertsum_13000_9_bs1.onnx -path model_step_13000.pt +``` + +获得bertsum_13000_9_bs1.onnx文件 + +方法二种的-bert_data_path是数据集所在目录,-batch_size需设置为1,-onnx_path是onnx输出文件 + +### 3.2 onnx模型简化 + +由于存在expand算子导致转om不成功,所以需要使用onnx简化工具对onnx进行简化 + +使用pth2onnx.py进行onnx的转换 + +``` +方法一:cd /home/BertSum/src/test +bash simplify.sh +方法二:cd /home/BertSum/src +python -m onnxsim ./bertsum_13000_9_bs1.onnx ./bertsum_13000_9_sim_bs1.onnx +``` + +获得bertsum_13000_9_sim_bs1.onnx文件 + +### 3.3 onnx简化模型转om模型 + +1.设置环境变量 + +``` +source atc.sh +``` + +2.使用atc将onnx模型转换为om模型文件,工具使用方法可以参考CANN 5.0.3 开发辅助工具指南 (推理) 01 + +``` +方法一:cd /home/BertSum/src/test +bash onnxToom.sh +方法二:cd /home/BertSum/src +atc --input_format=ND --framework=5 --model=./bertsum_13000_9_sim_bs1.onnx --input_shape="src:1,512;segs:1,512;clss:1,37;mask:1,512;mask_cls:1,37" --output=bertsum_13000_9_sim_bs1 \ +--log=info --soc_version=Ascend310 --precision_mode=allow_mix_precision \ +--modify_mixlist=ops_info.json +``` + +方法二中的model是onnx模型的名字,input_shape是paper的shape,output为输出om的名字,--precision_mode表示采用混合精度 + +## 4 数据集预处理 + +- **数据集获取** +- **数据集预处理** +- **生成数据集信息文件** + +### 4.1 数据集获取 + +参考原代码仓 + +### 4.2 数据集预处理 + +1.预处理脚本BertSum_pth_preprocess.py + +2.执行预处理脚本,生成数据集预处理后的bin文件 + +``` +方法一:cd /home/BertSum/src/test +bash pre_deal.sh +方法二:cd /home/BertSum/src +python BertSum_pth_preprocess.py -mode test -bert_data_path ../bert_data/cnndm -model_path MODEL_PATH -visible_gpus -1 -gpu_ranks 0 -batch_size 600 -log_file LOG_FILE -result_path RESULT_PATH -test_all -block_trigram true +``` + +-bert_data_path是数据集所在目录,后面的参数是固定的。 + +### 5 离线推理 + +- **msame工具** +- **离线推理** + +### 5.1 msame工具 + +获取msame工具(https://gitee.com/ascend/tools/tree/master/msame),并将得到的msame工具放在/home/BertSum-master/src下 + +### 5.2 离线推理 + +1.执行离线推理 + +benchmark工具暂不支持多输入,因此改用msame,首先要source环境变量 + +``` +source env.sh +``` + +2.使用msame将onnx模型转换为om模型文件,工具使用方法可以参考CANN + +然后运行如下命令: + +``` +方法一:cd /home/BertSum/src/test +bash infer.sh +方法二:cd /home/BertSum/src +./msame --model "./bertsum_13000_9_sim_bs1_1.om" --input "./pre_data/src,./pre_data/segs,./pre_data/clss,./pre_data/mask,./pre_data/mask_cls" --output "./result" --outfmt bin +./msame --model "./bertsum_13000_9_sim_bs1_1.om" --input "./pre_data_1/src,./pre_data_1/segs,./pre_data_1/clss,./pre_data_1/mask,./pre_data_1/mask_cls" --output "./result" --outfmt bin +``` + +要采用msema工具推理两次,因为有些paper的shape第一维为2,所以分两次进行推理。pre_data下存放的是shape为第一维为1的所有预处理之后的数据以及shape为2的部分预处理得到的数据。shape为2的另一部分数据存放在pre_data_1下面。--model是om文件,--input是预处理之后文件所在目录,--output为输出bin文件所在目录,--outfmt代表输出bin文件*。* + +输出的bin文件在/home/BertSum-master/src/result目录下,此目录下会存在两个文件,将其中一个时间小的命名为result_1,将另一个时间大的命名为result_2。 + +## 6 精度对比 + +- **离线推理精度** +- **开源精度** +- **精度对比** + +### 6.1 离线推理精度统计 + +1.后处理 + +``` +cd /home/BertSum/src +python BertSum_pth_postprocess.py -visible_gpus -1 -gpu_ranks 0 -batch_size 600 -log_file LOG_FILE -result_path RESULT_PATH -test_all -block_trigram true -path_1 ./result/result_1 -path_2 ./result/result_2 +``` + +``` + -path_1是推理得到的文件result_1,-path_2是推理得到的result_2 + 自验报告 + # 第X次验收测试 + # 验收结果 OK + # 验收环境: A + K / CANN 5.0.3 + # 关联issue: + + # pth是否能正确转换为om + bash test/onnx2om.sh + # 验收结果: OK + # 备注: 成功生成om,无运行报错,报错日志xx 等 + + # 精度数据是否达标(需要显示官网pth精度与om模型的精度) + # npu性能数据(由于msame工具不支持多batch,所以只测试了bs1的性能) + # 验收结果: 是 / 否 + # 备注: 目标pth精度42.96;bs1验收om精度42.92;精度下降不超过1%;无运行报错,报错日志xx 等 + # 备注: 验收310测试性能bs1:61.538FPS;无运行报错,报错日志xx 等 + + # 在t4上测试bs1性能 + bash perf.sh + # 验收结果: OK / Failed + # 备注: 验收基准测试性能bs1:94.281FPS;无运行报错,报错日志xx 等 + + # 310性能是否超过基准: 否 + t4:310=(94.281/61.538)1.53倍基准 +``` + +### 6.2 开源精度 + +BertSum在线训练精度: + +42.96% + +### 6.3 离线推理精度 + +42.95% + +### 6.3 精度对比 + +由于源码采用的是动态shape,而离线推理是通过加padding固定住shape进行推理的,所以精度会有损失,因此和同一分辨率下的在线推理进行对比。对比方式:三个尺度求和取平均。 + +## 7 性能对比 + +- **310性能数据** +- **T4性能数据** +- **性能对比** + +### 7.1 310性能数据 + +每张图片平均耗时:65.06ms,所以310吞吐率为:1000/65×4=61.538 + +说明:由于msame不支持多batch,所以此处只测了bs1的性能。 + +### 7.2 T4性能数据 + +T4性能为:94.281 + +### 7.3 性能对比 + batch1:94.281>61.538 \ No newline at end of file diff --git a/ACL_PyTorch/contrib/nlp/BertSum/modelzoo_level.txt b/ACL_PyTorch/contrib/nlp/BertSum/modelzoo_level.txt index 14ac5bd404..aeac4e1264 100644 --- a/ACL_PyTorch/contrib/nlp/BertSum/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/nlp/BertSum/modelzoo_level.txt @@ -1,6 +1,6 @@ -ModelConvert:OK -QuantStatus:OK -FuncStatus:OK -PrecisionStatus:OK -AutoTune:NOK +ModelConvert:OK +QuantStatus:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:NOK PerfStatus:POK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/nlp/BertSum/requirements.txt b/ACL_PyTorch/contrib/nlp/BertSum/requirements.txt index e7350f2bde..47c01fde52 100644 --- a/ACL_PyTorch/contrib/nlp/BertSum/requirements.txt +++ b/ACL_PyTorch/contrib/nlp/BertSum/requirements.txt @@ -1,5 +1,5 @@ -torch==1.10.0 -tensorboardX==2.4.1 -pyrouge==0.1.3 -pytorch_pretrained_bert==0.6.2 -onnx-simplifier==0.3.6 +torch==1.10.0 +tensorboardX==2.4.1 +pyrouge==0.1.3 +pytorch_pretrained_bert==0.6.2 +onnx-simplifier==0.3.6 diff --git a/ACL_PyTorch/contrib/nlp/TextCNN/LICENSE b/ACL_PyTorch/contrib/nlp/TextCNN/LICENSE index 29f81d812f..261eeb9e9f 100644 --- a/ACL_PyTorch/contrib/nlp/TextCNN/LICENSE +++ b/ACL_PyTorch/contrib/nlp/TextCNN/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/ACL_PyTorch/contrib/nlp/TextCNN/TextCNN.patch b/ACL_PyTorch/contrib/nlp/TextCNN/TextCNN.patch index 60d727642b..dd56597dfc 100644 --- a/ACL_PyTorch/contrib/nlp/TextCNN/TextCNN.patch +++ b/ACL_PyTorch/contrib/nlp/TextCNN/TextCNN.patch @@ -1,646 +1,646 @@ -二进制文件 Chinese-Text-Classification-Pytorch_back/.git/index 和 Chinese-Text-Classification-Pytorch/.git/index 不同 -diff -uprN Chinese-Text-Classification-Pytorch_back/models/DPCNN.py Chinese-Text-Classification-Pytorch/models/DPCNN.py ---- Chinese-Text-Classification-Pytorch_back/models/DPCNN.py 2021-08-13 20:49:45.263263000 +0800 -+++ Chinese-Text-Classification-Pytorch/models/DPCNN.py 1970-01-01 08:00:00.000000000 +0800 -@@ -1,89 +0,0 @@ --# coding: UTF-8 --import torch --import torch.nn as nn --import torch.nn.functional as F --import numpy as np -- -- --class Config(object): -- -- """配置参数""" -- def __init__(self, dataset, embedding): -- self.model_name = 'DPCNN' -- self.train_path = dataset + '/data/train.txt' # 训练集 -- self.dev_path = dataset + '/data/dev.txt' # 验证集 -- self.test_path = dataset + '/data/test.txt' # 测试集 -- self.class_list = [x.strip() for x in open( -- dataset + '/data/class.txt', encoding='utf-8').readlines()] # 类别名单 -- self.vocab_path = dataset + '/data/vocab.pkl' # 词表 -- self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt' # 模型训练结果 -- self.log_path = dataset + '/log/' + self.model_name -- self.embedding_pretrained = torch.tensor( -- np.load(dataset + '/data/' + embedding)["embeddings"].astype('float32'))\ -- if embedding != 'random' else None # 预训练词向量 -- self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 设备 -- -- self.dropout = 0.5 # 随机失活 -- self.require_improvement = 1000 # 若超过1000batch效果还没提升,则提前结束训练 -- self.num_classes = len(self.class_list) # 类别数 -- self.n_vocab = 0 # 词表大小,在运行时赋值 -- self.num_epochs = 20 # epoch数 -- self.batch_size = 128 # mini-batch大小 -- self.pad_size = 32 # 每句话处理成的长度(短填长切) -- self.learning_rate = 1e-3 # 学习率 -- self.embed = self.embedding_pretrained.size(1)\ -- if self.embedding_pretrained is not None else 300 # 字向量维度 -- self.num_filters = 250 # 卷积核数量(channels数) -- -- --'''Deep Pyramid Convolutional Neural Networks for Text Categorization''' -- -- --class Model(nn.Module): -- def __init__(self, config): -- super(Model, self).__init__() -- if config.embedding_pretrained is not None: -- self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False) -- else: -- self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1) -- self.conv_region = nn.Conv2d(1, config.num_filters, (3, config.embed), stride=1) -- self.conv = nn.Conv2d(config.num_filters, config.num_filters, (3, 1), stride=1) -- self.max_pool = nn.MaxPool2d(kernel_size=(3, 1), stride=2) -- self.padding1 = nn.ZeroPad2d((0, 0, 1, 1)) # top bottom -- self.padding2 = nn.ZeroPad2d((0, 0, 0, 1)) # bottom -- self.relu = nn.ReLU() -- self.fc = nn.Linear(config.num_filters, config.num_classes) -- -- def forward(self, x): -- x = x[0] -- x = self.embedding(x) -- x = x.unsqueeze(1) # [batch_size, 250, seq_len, 1] -- x = self.conv_region(x) # [batch_size, 250, seq_len-3+1, 1] -- -- x = self.padding1(x) # [batch_size, 250, seq_len, 1] -- x = self.relu(x) -- x = self.conv(x) # [batch_size, 250, seq_len-3+1, 1] -- x = self.padding1(x) # [batch_size, 250, seq_len, 1] -- x = self.relu(x) -- x = self.conv(x) # [batch_size, 250, seq_len-3+1, 1] -- while x.size()[2] > 2: -- x = self._block(x) -- x = x.squeeze() # [batch_size, num_filters(250)] -- x = self.fc(x) -- return x -- -- def _block(self, x): -- x = self.padding2(x) -- px = self.max_pool(x) -- -- x = self.padding1(px) -- x = F.relu(x) -- x = self.conv(x) -- -- x = self.padding1(x) -- x = F.relu(x) -- x = self.conv(x) -- -- # Short Cut -- x = x + px -- return x -diff -uprN Chinese-Text-Classification-Pytorch_back/models/FastText.py Chinese-Text-Classification-Pytorch/models/FastText.py ---- Chinese-Text-Classification-Pytorch_back/models/FastText.py 2021-08-13 20:49:45.263263000 +0800 -+++ Chinese-Text-Classification-Pytorch/models/FastText.py 1970-01-01 08:00:00.000000000 +0800 -@@ -1,69 +0,0 @@ --# coding: UTF-8 --import torch --import torch.nn as nn --import torch.nn.functional as F --import numpy as np -- -- --class Config(object): -- -- """配置参数""" -- def __init__(self, dataset, embedding): -- self.model_name = 'FastText' -- self.train_path = dataset + '/data/train.txt' # 训练集 -- self.dev_path = dataset + '/data/dev.txt' # 验证集 -- self.test_path = dataset + '/data/test.txt' # 测试集 -- self.class_list = [x.strip() for x in open( -- dataset + '/data/class.txt', encoding='utf-8').readlines()] # 类别名单 -- self.vocab_path = dataset + '/data/vocab.pkl' # 词表 -- self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt' # 模型训练结果 -- self.log_path = dataset + '/log/' + self.model_name -- self.embedding_pretrained = torch.tensor( -- np.load(dataset + '/data/' + embedding)["embeddings"].astype('float32'))\ -- if embedding != 'random' else None # 预训练词向量 -- self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 设备 -- -- self.dropout = 0.5 # 随机失活 -- self.require_improvement = 1000 # 若超过1000batch效果还没提升,则提前结束训练 -- self.num_classes = len(self.class_list) # 类别数 -- self.n_vocab = 0 # 词表大小,在运行时赋值 -- self.num_epochs = 20 # epoch数 -- self.batch_size = 128 # mini-batch大小 -- self.pad_size = 32 # 每句话处理成的长度(短填长切) -- self.learning_rate = 1e-3 # 学习率 -- self.embed = self.embedding_pretrained.size(1)\ -- if self.embedding_pretrained is not None else 300 # 字向量维度 -- self.hidden_size = 256 # 隐藏层大小 -- self.n_gram_vocab = 250499 # ngram 词表大小 -- -- --'''Bag of Tricks for Efficient Text Classification''' -- -- --class Model(nn.Module): -- def __init__(self, config): -- super(Model, self).__init__() -- if config.embedding_pretrained is not None: -- self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False) -- else: -- self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1) -- self.embedding_ngram2 = nn.Embedding(config.n_gram_vocab, config.embed) -- self.embedding_ngram3 = nn.Embedding(config.n_gram_vocab, config.embed) -- self.dropout = nn.Dropout(config.dropout) -- self.fc1 = nn.Linear(config.embed * 3, config.hidden_size) -- # self.dropout2 = nn.Dropout(config.dropout) -- self.fc2 = nn.Linear(config.hidden_size, config.num_classes) -- -- def forward(self, x): -- -- out_word = self.embedding(x[0]) -- out_bigram = self.embedding_ngram2(x[2]) -- out_trigram = self.embedding_ngram3(x[3]) -- out = torch.cat((out_word, out_bigram, out_trigram), -1) -- -- out = out.mean(dim=1) -- out = self.dropout(out) -- out = self.fc1(out) -- out = F.relu(out) -- out = self.fc2(out) -- return out -二进制文件 Chinese-Text-Classification-Pytorch_back/models/__pycache__/TextCNN.cpython-37.pyc 和 Chinese-Text-Classification-Pytorch/models/__pycache__/TextCNN.cpython-37.pyc 不同 -diff -uprN Chinese-Text-Classification-Pytorch_back/models/TextCNN.py Chinese-Text-Classification-Pytorch/models/TextCNN.py ---- Chinese-Text-Classification-Pytorch_back/models/TextCNN.py 2021-08-13 20:49:45.263263000 +0800 -+++ Chinese-Text-Classification-Pytorch/models/TextCNN.py 2021-09-07 21:23:07.218366753 +0800 -@@ -1,4 +1,6 @@ - # coding: UTF-8 -+import os.path -+ - import torch - import torch.nn as nn - import torch.nn.functional as F -@@ -13,10 +15,11 @@ class Config(object): - self.train_path = dataset + '/data/train.txt' # 训练集 - self.dev_path = dataset + '/data/dev.txt' # 验证集 - self.test_path = dataset + '/data/test.txt' # 测试集 -+ print('path', os.path.abspath(dataset+'/data/class.txt')) - self.class_list = [x.strip() for x in open( - dataset + '/data/class.txt', encoding='utf-8').readlines()] # 类别名单 - self.vocab_path = dataset + '/data/vocab.pkl' # 词表 -- self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt' # 模型训练结果 -+ self.save_path = dataset + '/saved_dict/' + self.model_name + '.pth' # 模型训练结果 - self.log_path = dataset + '/log/' + self.model_name - self.embedding_pretrained = torch.tensor( - np.load(dataset + '/data/' + embedding)["embeddings"].astype('float32'))\ -@@ -49,18 +52,21 @@ class Model(nn.Module): - self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1) - self.convs = nn.ModuleList( - [nn.Conv2d(1, config.num_filters, (k, config.embed)) for k in config.filter_sizes]) -+ self.pools = nn.ModuleList( -+ [nn.MaxPool1d(config.pad_size - k + 1) for k in config.filter_sizes]) - self.dropout = nn.Dropout(config.dropout) - self.fc = nn.Linear(config.num_filters * len(config.filter_sizes), config.num_classes) - -- def conv_and_pool(self, x, conv): -+ def conv_and_pool(self, x, conv, pool): - x = F.relu(conv(x)).squeeze(3) -- x = F.max_pool1d(x, x.size(2)).squeeze(2) -+ x = pool(x).squeeze(2) -+ # x = F.max_pool1d(x, x.size(2)).squeeze(2) - return x - - def forward(self, x): -- out = self.embedding(x[0]) -+ out = self.embedding(x) - out = out.unsqueeze(1) -- out = torch.cat([self.conv_and_pool(out, conv) for conv in self.convs], 1) -+ out = torch.cat([self.conv_and_pool(out, conv, pool) for conv, pool in zip(self.convs, self.pools)], 1) - out = self.dropout(out) - out = self.fc(out) - return out -diff -uprN Chinese-Text-Classification-Pytorch_back/models/TextRCNN.py Chinese-Text-Classification-Pytorch/models/TextRCNN.py ---- Chinese-Text-Classification-Pytorch_back/models/TextRCNN.py 2021-08-13 20:49:45.263263000 +0800 -+++ Chinese-Text-Classification-Pytorch/models/TextRCNN.py 1970-01-01 08:00:00.000000000 +0800 -@@ -1,64 +0,0 @@ --# coding: UTF-8 --import torch --import torch.nn as nn --import torch.nn.functional as F --import numpy as np -- -- --class Config(object): -- -- """配置参数""" -- def __init__(self, dataset, embedding): -- self.model_name = 'TextRCNN' -- self.train_path = dataset + '/data/train.txt' # 训练集 -- self.dev_path = dataset + '/data/dev.txt' # 验证集 -- self.test_path = dataset + '/data/test.txt' # 测试集 -- self.class_list = [x.strip() for x in open( -- dataset + '/data/class.txt', encoding='utf-8').readlines()] # 类别名单 -- self.vocab_path = dataset + '/data/vocab.pkl' # 词表 -- self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt' # 模型训练结果 -- self.log_path = dataset + '/log/' + self.model_name -- self.embedding_pretrained = torch.tensor( -- np.load(dataset + '/data/' + embedding)["embeddings"].astype('float32'))\ -- if embedding != 'random' else None # 预训练词向量 -- self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 设备 -- -- self.dropout = 1.0 # 随机失活 -- self.require_improvement = 1000 # 若超过1000batch效果还没提升,则提前结束训练 -- self.num_classes = len(self.class_list) # 类别数 -- self.n_vocab = 0 # 词表大小,在运行时赋值 -- self.num_epochs = 10 # epoch数 -- self.batch_size = 128 # mini-batch大小 -- self.pad_size = 32 # 每句话处理成的长度(短填长切) -- self.learning_rate = 1e-3 # 学习率 -- self.embed = self.embedding_pretrained.size(1)\ -- if self.embedding_pretrained is not None else 300 # 字向量维度, 若使用了预训练词向量,则维度统一 -- self.hidden_size = 256 # lstm隐藏层 -- self.num_layers = 1 # lstm层数 -- -- --'''Recurrent Convolutional Neural Networks for Text Classification''' -- -- --class Model(nn.Module): -- def __init__(self, config): -- super(Model, self).__init__() -- if config.embedding_pretrained is not None: -- self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False) -- else: -- self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1) -- self.lstm = nn.LSTM(config.embed, config.hidden_size, config.num_layers, -- bidirectional=True, batch_first=True, dropout=config.dropout) -- self.maxpool = nn.MaxPool1d(config.pad_size) -- self.fc = nn.Linear(config.hidden_size * 2 + config.embed, config.num_classes) -- -- def forward(self, x): -- x, _ = x -- embed = self.embedding(x) # [batch_size, seq_len, embeding]=[64, 32, 64] -- out, _ = self.lstm(embed) -- out = torch.cat((embed, out), 2) -- out = F.relu(out) -- out = out.permute(0, 2, 1) -- out = self.maxpool(out).squeeze() -- out = self.fc(out) -- return out -diff -uprN Chinese-Text-Classification-Pytorch_back/models/TextRNN_Att.py Chinese-Text-Classification-Pytorch/models/TextRNN_Att.py ---- Chinese-Text-Classification-Pytorch_back/models/TextRNN_Att.py 2021-08-13 20:49:45.263263000 +0800 -+++ Chinese-Text-Classification-Pytorch/models/TextRNN_Att.py 1970-01-01 08:00:00.000000000 +0800 -@@ -1,73 +0,0 @@ --# coding: UTF-8 --import torch --import torch.nn as nn --import torch.nn.functional as F --import numpy as np -- -- --class Config(object): -- -- """配置参数""" -- def __init__(self, dataset, embedding): -- self.model_name = 'TextRNN_Att' -- self.train_path = dataset + '/data/train.txt' # 训练集 -- self.dev_path = dataset + '/data/dev.txt' # 验证集 -- self.test_path = dataset + '/data/test.txt' # 测试集 -- self.class_list = [x.strip() for x in open( -- dataset + '/data/class.txt', encoding='utf-8').readlines()] # 类别名单 -- self.vocab_path = dataset + '/data/vocab.pkl' # 词表 -- self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt' # 模型训练结果 -- self.log_path = dataset + '/log/' + self.model_name -- self.embedding_pretrained = torch.tensor( -- np.load(dataset + '/data/' + embedding)["embeddings"].astype('float32'))\ -- if embedding != 'random' else None # 预训练词向量 -- self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 设备 -- -- self.dropout = 0.5 # 随机失活 -- self.require_improvement = 1000 # 若超过1000batch效果还没提升,则提前结束训练 -- self.num_classes = len(self.class_list) # 类别数 -- self.n_vocab = 0 # 词表大小,在运行时赋值 -- self.num_epochs = 10 # epoch数 -- self.batch_size = 128 # mini-batch大小 -- self.pad_size = 32 # 每句话处理成的长度(短填长切) -- self.learning_rate = 1e-3 # 学习率 -- self.embed = self.embedding_pretrained.size(1)\ -- if self.embedding_pretrained is not None else 300 # 字向量维度, 若使用了预训练词向量,则维度统一 -- self.hidden_size = 128 # lstm隐藏层 -- self.num_layers = 2 # lstm层数 -- self.hidden_size2 = 64 -- -- --'''Attention-Based Bidirectional Long Short-Term Memory Networks for Relation Classification''' -- -- --class Model(nn.Module): -- def __init__(self, config): -- super(Model, self).__init__() -- if config.embedding_pretrained is not None: -- self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False) -- else: -- self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1) -- self.lstm = nn.LSTM(config.embed, config.hidden_size, config.num_layers, -- bidirectional=True, batch_first=True, dropout=config.dropout) -- self.tanh1 = nn.Tanh() -- # self.u = nn.Parameter(torch.Tensor(config.hidden_size * 2, config.hidden_size * 2)) -- self.w = nn.Parameter(torch.zeros(config.hidden_size * 2)) -- self.tanh2 = nn.Tanh() -- self.fc1 = nn.Linear(config.hidden_size * 2, config.hidden_size2) -- self.fc = nn.Linear(config.hidden_size2, config.num_classes) -- -- def forward(self, x): -- x, _ = x -- emb = self.embedding(x) # [batch_size, seq_len, embeding]=[128, 32, 300] -- H, _ = self.lstm(emb) # [batch_size, seq_len, hidden_size * num_direction]=[128, 32, 256] -- -- M = self.tanh1(H) # [128, 32, 256] -- # M = torch.tanh(torch.matmul(H, self.u)) -- alpha = F.softmax(torch.matmul(M, self.w), dim=1).unsqueeze(-1) # [128, 32, 1] -- out = H * alpha # [128, 32, 256] -- out = torch.sum(out, 1) # [128, 256] -- out = F.relu(out) -- out = self.fc1(out) -- out = self.fc(out) # [128, 64] -- return out -diff -uprN Chinese-Text-Classification-Pytorch_back/models/TextRNN.py Chinese-Text-Classification-Pytorch/models/TextRNN.py ---- Chinese-Text-Classification-Pytorch_back/models/TextRNN.py 2021-08-13 20:49:45.263263000 +0800 -+++ Chinese-Text-Classification-Pytorch/models/TextRNN.py 1970-01-01 08:00:00.000000000 +0800 -@@ -1,75 +0,0 @@ --# coding: UTF-8 --import torch --import torch.nn as nn --import numpy as np -- -- --class Config(object): -- -- """配置参数""" -- def __init__(self, dataset, embedding): -- self.model_name = 'TextRNN' -- self.train_path = dataset + '/data/train.txt' # 训练集 -- self.dev_path = dataset + '/data/dev.txt' # 验证集 -- self.test_path = dataset + '/data/test.txt' # 测试集 -- self.class_list = [x.strip() for x in open( -- dataset + '/data/class.txt', encoding='utf-8').readlines()] # 类别名单 -- self.vocab_path = dataset + '/data/vocab.pkl' # 词表 -- self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt' # 模型训练结果 -- self.log_path = dataset + '/log/' + self.model_name -- self.embedding_pretrained = torch.tensor( -- np.load(dataset + '/data/' + embedding)["embeddings"].astype('float32'))\ -- if embedding != 'random' else None # 预训练词向量 -- self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 设备 -- -- self.dropout = 0.5 # 随机失活 -- self.require_improvement = 1000 # 若超过1000batch效果还没提升,则提前结束训练 -- self.num_classes = len(self.class_list) # 类别数 -- self.n_vocab = 0 # 词表大小,在运行时赋值 -- self.num_epochs = 10 # epoch数 -- self.batch_size = 128 # mini-batch大小 -- self.pad_size = 32 # 每句话处理成的长度(短填长切) -- self.learning_rate = 1e-3 # 学习率 -- self.embed = self.embedding_pretrained.size(1)\ -- if self.embedding_pretrained is not None else 300 # 字向量维度, 若使用了预训练词向量,则维度统一 -- self.hidden_size = 128 # lstm隐藏层 -- self.num_layers = 2 # lstm层数 -- -- --'''Recurrent Neural Network for Text Classification with Multi-Task Learning''' -- -- --class Model(nn.Module): -- def __init__(self, config): -- super(Model, self).__init__() -- if config.embedding_pretrained is not None: -- self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False) -- else: -- self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1) -- self.lstm = nn.LSTM(config.embed, config.hidden_size, config.num_layers, -- bidirectional=True, batch_first=True, dropout=config.dropout) -- self.fc = nn.Linear(config.hidden_size * 2, config.num_classes) -- -- def forward(self, x): -- x, _ = x -- out = self.embedding(x) # [batch_size, seq_len, embeding]=[128, 32, 300] -- out, _ = self.lstm(out) -- out = self.fc(out[:, -1, :]) # 句子最后时刻的 hidden state -- return out -- -- '''变长RNN,效果差不多,甚至还低了点...''' -- # def forward(self, x): -- # x, seq_len = x -- # out = self.embedding(x) -- # _, idx_sort = torch.sort(seq_len, dim=0, descending=True) # 长度从长到短排序(index) -- # _, idx_unsort = torch.sort(idx_sort) # 排序后,原序列的 index -- # out = torch.index_select(out, 0, idx_sort) -- # seq_len = list(seq_len[idx_sort]) -- # out = nn.utils.rnn.pack_padded_sequence(out, seq_len, batch_first=True) -- # # [batche_size, seq_len, num_directions * hidden_size] -- # out, (hn, _) = self.lstm(out) -- # out = torch.cat((hn[2], hn[3]), -1) -- # # out, _ = nn.utils.rnn.pad_packed_sequence(out, batch_first=True) -- # out = out.index_select(0, idx_unsort) -- # out = self.fc(out) -- # return out -diff -uprN Chinese-Text-Classification-Pytorch_back/models/Transformer.py Chinese-Text-Classification-Pytorch/models/Transformer.py ---- Chinese-Text-Classification-Pytorch_back/models/Transformer.py 2021-08-13 20:49:45.263263000 +0800 -+++ Chinese-Text-Classification-Pytorch/models/Transformer.py 1970-01-01 08:00:00.000000000 +0800 -@@ -1,178 +0,0 @@ --import torch --import torch.nn as nn --import torch.nn.functional as F --import numpy as np --import copy -- -- --class Config(object): -- -- """配置参数""" -- def __init__(self, dataset, embedding): -- self.model_name = 'Transformer' -- self.train_path = dataset + '/data/train.txt' # 训练集 -- self.dev_path = dataset + '/data/dev.txt' # 验证集 -- self.test_path = dataset + '/data/test.txt' # 测试集 -- self.class_list = [x.strip() for x in open( -- dataset + '/data/class.txt', encoding='utf-8').readlines()] # 类别名单 -- self.vocab_path = dataset + '/data/vocab.pkl' # 词表 -- self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt' # 模型训练结果 -- self.log_path = dataset + '/log/' + self.model_name -- self.embedding_pretrained = torch.tensor( -- np.load(dataset + '/data/' + embedding)["embeddings"].astype('float32'))\ -- if embedding != 'random' else None # 预训练词向量 -- self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 设备 -- -- self.dropout = 0.5 # 随机失活 -- self.require_improvement = 2000 # 若超过1000batch效果还没提升,则提前结束训练 -- self.num_classes = len(self.class_list) # 类别数 -- self.n_vocab = 0 # 词表大小,在运行时赋值 -- self.num_epochs = 20 # epoch数 -- self.batch_size = 128 # mini-batch大小 -- self.pad_size = 32 # 每句话处理成的长度(短填长切) -- self.learning_rate = 5e-4 # 学习率 -- self.embed = self.embedding_pretrained.size(1)\ -- if self.embedding_pretrained is not None else 300 # 字向量维度 -- self.dim_model = 300 -- self.hidden = 1024 -- self.last_hidden = 512 -- self.num_head = 5 -- self.num_encoder = 2 -- -- --'''Attention Is All You Need''' -- -- --class Model(nn.Module): -- def __init__(self, config): -- super(Model, self).__init__() -- if config.embedding_pretrained is not None: -- self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False) -- else: -- self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1) -- -- self.postion_embedding = Positional_Encoding(config.embed, config.pad_size, config.dropout, config.device) -- self.encoder = Encoder(config.dim_model, config.num_head, config.hidden, config.dropout) -- self.encoders = nn.ModuleList([ -- copy.deepcopy(self.encoder) -- # Encoder(config.dim_model, config.num_head, config.hidden, config.dropout) -- for _ in range(config.num_encoder)]) -- -- self.fc1 = nn.Linear(config.pad_size * config.dim_model, config.num_classes) -- # self.fc2 = nn.Linear(config.last_hidden, config.num_classes) -- # self.fc1 = nn.Linear(config.dim_model, config.num_classes) -- -- def forward(self, x): -- out = self.embedding(x[0]) -- out = self.postion_embedding(out) -- for encoder in self.encoders: -- out = encoder(out) -- out = out.view(out.size(0), -1) -- # out = torch.mean(out, 1) -- out = self.fc1(out) -- return out -- -- --class Encoder(nn.Module): -- def __init__(self, dim_model, num_head, hidden, dropout): -- super(Encoder, self).__init__() -- self.attention = Multi_Head_Attention(dim_model, num_head, dropout) -- self.feed_forward = Position_wise_Feed_Forward(dim_model, hidden, dropout) -- -- def forward(self, x): -- out = self.attention(x) -- out = self.feed_forward(out) -- return out -- -- --class Positional_Encoding(nn.Module): -- def __init__(self, embed, pad_size, dropout, device): -- super(Positional_Encoding, self).__init__() -- self.device = device -- self.pe = torch.tensor([[pos / (10000.0 ** (i // 2 * 2.0 / embed)) for i in range(embed)] for pos in range(pad_size)]) -- self.pe[:, 0::2] = np.sin(self.pe[:, 0::2]) -- self.pe[:, 1::2] = np.cos(self.pe[:, 1::2]) -- self.dropout = nn.Dropout(dropout) -- -- def forward(self, x): -- out = x + nn.Parameter(self.pe, requires_grad=False).to(self.device) -- out = self.dropout(out) -- return out -- -- --class Scaled_Dot_Product_Attention(nn.Module): -- '''Scaled Dot-Product Attention ''' -- def __init__(self): -- super(Scaled_Dot_Product_Attention, self).__init__() -- -- def forward(self, Q, K, V, scale=None): -- ''' -- Args: -- Q: [batch_size, len_Q, dim_Q] -- K: [batch_size, len_K, dim_K] -- V: [batch_size, len_V, dim_V] -- scale: 缩放因子 论文为根号dim_K -- Return: -- self-attention后的张量,以及attention张量 -- ''' -- attention = torch.matmul(Q, K.permute(0, 2, 1)) -- if scale: -- attention = attention * scale -- # if mask: # TODO change this -- # attention = attention.masked_fill_(mask == 0, -1e9) -- attention = F.softmax(attention, dim=-1) -- context = torch.matmul(attention, V) -- return context -- -- --class Multi_Head_Attention(nn.Module): -- def __init__(self, dim_model, num_head, dropout=0.0): -- super(Multi_Head_Attention, self).__init__() -- self.num_head = num_head -- assert dim_model % num_head == 0 -- self.dim_head = dim_model // self.num_head -- self.fc_Q = nn.Linear(dim_model, num_head * self.dim_head) -- self.fc_K = nn.Linear(dim_model, num_head * self.dim_head) -- self.fc_V = nn.Linear(dim_model, num_head * self.dim_head) -- self.attention = Scaled_Dot_Product_Attention() -- self.fc = nn.Linear(num_head * self.dim_head, dim_model) -- self.dropout = nn.Dropout(dropout) -- self.layer_norm = nn.LayerNorm(dim_model) -- -- def forward(self, x): -- batch_size = x.size(0) -- Q = self.fc_Q(x) -- K = self.fc_K(x) -- V = self.fc_V(x) -- Q = Q.view(batch_size * self.num_head, -1, self.dim_head) -- K = K.view(batch_size * self.num_head, -1, self.dim_head) -- V = V.view(batch_size * self.num_head, -1, self.dim_head) -- # if mask: # TODO -- # mask = mask.repeat(self.num_head, 1, 1) # TODO change this -- scale = K.size(-1) ** -0.5 # 缩放因子 -- context = self.attention(Q, K, V, scale) -- -- context = context.view(batch_size, -1, self.dim_head * self.num_head) -- out = self.fc(context) -- out = self.dropout(out) -- out = out + x # 残差连接 -- out = self.layer_norm(out) -- return out -- -- --class Position_wise_Feed_Forward(nn.Module): -- def __init__(self, dim_model, hidden, dropout=0.0): -- super(Position_wise_Feed_Forward, self).__init__() -- self.fc1 = nn.Linear(dim_model, hidden) -- self.fc2 = nn.Linear(hidden, dim_model) -- self.dropout = nn.Dropout(dropout) -- self.layer_norm = nn.LayerNorm(dim_model) -- -- def forward(self, x): -- out = self.fc1(x) -- out = F.relu(out) -- out = self.fc2(out) -- out = self.dropout(out) -- out = out + x # 残差连接 -- out = self.layer_norm(out) -- return out -diff -uprN Chinese-Text-Classification-Pytorch_back/utils.py Chinese-Text-Classification-Pytorch/utils.py ---- Chinese-Text-Classification-Pytorch_back/utils.py 2021-08-13 20:49:45.263263000 +0800 -+++ Chinese-Text-Classification-Pytorch/utils.py 2021-09-07 21:23:50.874085521 +0800 -@@ -60,7 +60,7 @@ def build_dataset(config, ues_word): - # word to id - for word in token: - words_line.append(vocab.get(word, vocab.get(UNK))) -- contents.append((words_line, int(label), seq_len)) -+ contents.append((words_line, int(label))) - return contents # [([...], 0), ([...], 1), ...] - train = load_dataset(config.train_path, config.pad_size) - dev = load_dataset(config.dev_path, config.pad_size) -@@ -83,9 +83,7 @@ class DatasetIterater(object): - x = torch.LongTensor([_[0] for _ in datas]).to(self.device) - y = torch.LongTensor([_[1] for _ in datas]).to(self.device) - -- # pad前的长度(超过pad_size的设为pad_size) -- seq_len = torch.LongTensor([_[2] for _ in datas]).to(self.device) -- return (x, seq_len), y -+ return x, y - - def __next__(self): - if self.residue and self.index == self.n_batches: +二进制文件 Chinese-Text-Classification-Pytorch_back/.git/index 和 Chinese-Text-Classification-Pytorch/.git/index 不同 +diff -uprN Chinese-Text-Classification-Pytorch_back/models/DPCNN.py Chinese-Text-Classification-Pytorch/models/DPCNN.py +--- Chinese-Text-Classification-Pytorch_back/models/DPCNN.py 2021-08-13 20:49:45.263263000 +0800 ++++ Chinese-Text-Classification-Pytorch/models/DPCNN.py 1970-01-01 08:00:00.000000000 +0800 +@@ -1,89 +0,0 @@ +-# coding: UTF-8 +-import torch +-import torch.nn as nn +-import torch.nn.functional as F +-import numpy as np +- +- +-class Config(object): +- +- """配置参数""" +- def __init__(self, dataset, embedding): +- self.model_name = 'DPCNN' +- self.train_path = dataset + '/data/train.txt' # 训练集 +- self.dev_path = dataset + '/data/dev.txt' # 验证集 +- self.test_path = dataset + '/data/test.txt' # 测试集 +- self.class_list = [x.strip() for x in open( +- dataset + '/data/class.txt', encoding='utf-8').readlines()] # 类别名单 +- self.vocab_path = dataset + '/data/vocab.pkl' # 词表 +- self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt' # 模型训练结果 +- self.log_path = dataset + '/log/' + self.model_name +- self.embedding_pretrained = torch.tensor( +- np.load(dataset + '/data/' + embedding)["embeddings"].astype('float32'))\ +- if embedding != 'random' else None # 预训练词向量 +- self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 设备 +- +- self.dropout = 0.5 # 随机失活 +- self.require_improvement = 1000 # 若超过1000batch效果还没提升,则提前结束训练 +- self.num_classes = len(self.class_list) # 类别数 +- self.n_vocab = 0 # 词表大小,在运行时赋值 +- self.num_epochs = 20 # epoch数 +- self.batch_size = 128 # mini-batch大小 +- self.pad_size = 32 # 每句话处理成的长度(短填长切) +- self.learning_rate = 1e-3 # 学习率 +- self.embed = self.embedding_pretrained.size(1)\ +- if self.embedding_pretrained is not None else 300 # 字向量维度 +- self.num_filters = 250 # 卷积核数量(channels数) +- +- +-'''Deep Pyramid Convolutional Neural Networks for Text Categorization''' +- +- +-class Model(nn.Module): +- def __init__(self, config): +- super(Model, self).__init__() +- if config.embedding_pretrained is not None: +- self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False) +- else: +- self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1) +- self.conv_region = nn.Conv2d(1, config.num_filters, (3, config.embed), stride=1) +- self.conv = nn.Conv2d(config.num_filters, config.num_filters, (3, 1), stride=1) +- self.max_pool = nn.MaxPool2d(kernel_size=(3, 1), stride=2) +- self.padding1 = nn.ZeroPad2d((0, 0, 1, 1)) # top bottom +- self.padding2 = nn.ZeroPad2d((0, 0, 0, 1)) # bottom +- self.relu = nn.ReLU() +- self.fc = nn.Linear(config.num_filters, config.num_classes) +- +- def forward(self, x): +- x = x[0] +- x = self.embedding(x) +- x = x.unsqueeze(1) # [batch_size, 250, seq_len, 1] +- x = self.conv_region(x) # [batch_size, 250, seq_len-3+1, 1] +- +- x = self.padding1(x) # [batch_size, 250, seq_len, 1] +- x = self.relu(x) +- x = self.conv(x) # [batch_size, 250, seq_len-3+1, 1] +- x = self.padding1(x) # [batch_size, 250, seq_len, 1] +- x = self.relu(x) +- x = self.conv(x) # [batch_size, 250, seq_len-3+1, 1] +- while x.size()[2] > 2: +- x = self._block(x) +- x = x.squeeze() # [batch_size, num_filters(250)] +- x = self.fc(x) +- return x +- +- def _block(self, x): +- x = self.padding2(x) +- px = self.max_pool(x) +- +- x = self.padding1(px) +- x = F.relu(x) +- x = self.conv(x) +- +- x = self.padding1(x) +- x = F.relu(x) +- x = self.conv(x) +- +- # Short Cut +- x = x + px +- return x +diff -uprN Chinese-Text-Classification-Pytorch_back/models/FastText.py Chinese-Text-Classification-Pytorch/models/FastText.py +--- Chinese-Text-Classification-Pytorch_back/models/FastText.py 2021-08-13 20:49:45.263263000 +0800 ++++ Chinese-Text-Classification-Pytorch/models/FastText.py 1970-01-01 08:00:00.000000000 +0800 +@@ -1,69 +0,0 @@ +-# coding: UTF-8 +-import torch +-import torch.nn as nn +-import torch.nn.functional as F +-import numpy as np +- +- +-class Config(object): +- +- """配置参数""" +- def __init__(self, dataset, embedding): +- self.model_name = 'FastText' +- self.train_path = dataset + '/data/train.txt' # 训练集 +- self.dev_path = dataset + '/data/dev.txt' # 验证集 +- self.test_path = dataset + '/data/test.txt' # 测试集 +- self.class_list = [x.strip() for x in open( +- dataset + '/data/class.txt', encoding='utf-8').readlines()] # 类别名单 +- self.vocab_path = dataset + '/data/vocab.pkl' # 词表 +- self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt' # 模型训练结果 +- self.log_path = dataset + '/log/' + self.model_name +- self.embedding_pretrained = torch.tensor( +- np.load(dataset + '/data/' + embedding)["embeddings"].astype('float32'))\ +- if embedding != 'random' else None # 预训练词向量 +- self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 设备 +- +- self.dropout = 0.5 # 随机失活 +- self.require_improvement = 1000 # 若超过1000batch效果还没提升,则提前结束训练 +- self.num_classes = len(self.class_list) # 类别数 +- self.n_vocab = 0 # 词表大小,在运行时赋值 +- self.num_epochs = 20 # epoch数 +- self.batch_size = 128 # mini-batch大小 +- self.pad_size = 32 # 每句话处理成的长度(短填长切) +- self.learning_rate = 1e-3 # 学习率 +- self.embed = self.embedding_pretrained.size(1)\ +- if self.embedding_pretrained is not None else 300 # 字向量维度 +- self.hidden_size = 256 # 隐藏层大小 +- self.n_gram_vocab = 250499 # ngram 词表大小 +- +- +-'''Bag of Tricks for Efficient Text Classification''' +- +- +-class Model(nn.Module): +- def __init__(self, config): +- super(Model, self).__init__() +- if config.embedding_pretrained is not None: +- self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False) +- else: +- self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1) +- self.embedding_ngram2 = nn.Embedding(config.n_gram_vocab, config.embed) +- self.embedding_ngram3 = nn.Embedding(config.n_gram_vocab, config.embed) +- self.dropout = nn.Dropout(config.dropout) +- self.fc1 = nn.Linear(config.embed * 3, config.hidden_size) +- # self.dropout2 = nn.Dropout(config.dropout) +- self.fc2 = nn.Linear(config.hidden_size, config.num_classes) +- +- def forward(self, x): +- +- out_word = self.embedding(x[0]) +- out_bigram = self.embedding_ngram2(x[2]) +- out_trigram = self.embedding_ngram3(x[3]) +- out = torch.cat((out_word, out_bigram, out_trigram), -1) +- +- out = out.mean(dim=1) +- out = self.dropout(out) +- out = self.fc1(out) +- out = F.relu(out) +- out = self.fc2(out) +- return out +二进制文件 Chinese-Text-Classification-Pytorch_back/models/__pycache__/TextCNN.cpython-37.pyc 和 Chinese-Text-Classification-Pytorch/models/__pycache__/TextCNN.cpython-37.pyc 不同 +diff -uprN Chinese-Text-Classification-Pytorch_back/models/TextCNN.py Chinese-Text-Classification-Pytorch/models/TextCNN.py +--- Chinese-Text-Classification-Pytorch_back/models/TextCNN.py 2021-08-13 20:49:45.263263000 +0800 ++++ Chinese-Text-Classification-Pytorch/models/TextCNN.py 2021-09-07 21:23:07.218366753 +0800 +@@ -1,4 +1,6 @@ + # coding: UTF-8 ++import os.path ++ + import torch + import torch.nn as nn + import torch.nn.functional as F +@@ -13,10 +15,11 @@ class Config(object): + self.train_path = dataset + '/data/train.txt' # 训练集 + self.dev_path = dataset + '/data/dev.txt' # 验证集 + self.test_path = dataset + '/data/test.txt' # 测试集 ++ print('path', os.path.abspath(dataset+'/data/class.txt')) + self.class_list = [x.strip() for x in open( + dataset + '/data/class.txt', encoding='utf-8').readlines()] # 类别名单 + self.vocab_path = dataset + '/data/vocab.pkl' # 词表 +- self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt' # 模型训练结果 ++ self.save_path = dataset + '/saved_dict/' + self.model_name + '.pth' # 模型训练结果 + self.log_path = dataset + '/log/' + self.model_name + self.embedding_pretrained = torch.tensor( + np.load(dataset + '/data/' + embedding)["embeddings"].astype('float32'))\ +@@ -49,18 +52,21 @@ class Model(nn.Module): + self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1) + self.convs = nn.ModuleList( + [nn.Conv2d(1, config.num_filters, (k, config.embed)) for k in config.filter_sizes]) ++ self.pools = nn.ModuleList( ++ [nn.MaxPool1d(config.pad_size - k + 1) for k in config.filter_sizes]) + self.dropout = nn.Dropout(config.dropout) + self.fc = nn.Linear(config.num_filters * len(config.filter_sizes), config.num_classes) + +- def conv_and_pool(self, x, conv): ++ def conv_and_pool(self, x, conv, pool): + x = F.relu(conv(x)).squeeze(3) +- x = F.max_pool1d(x, x.size(2)).squeeze(2) ++ x = pool(x).squeeze(2) ++ # x = F.max_pool1d(x, x.size(2)).squeeze(2) + return x + + def forward(self, x): +- out = self.embedding(x[0]) ++ out = self.embedding(x) + out = out.unsqueeze(1) +- out = torch.cat([self.conv_and_pool(out, conv) for conv in self.convs], 1) ++ out = torch.cat([self.conv_and_pool(out, conv, pool) for conv, pool in zip(self.convs, self.pools)], 1) + out = self.dropout(out) + out = self.fc(out) + return out +diff -uprN Chinese-Text-Classification-Pytorch_back/models/TextRCNN.py Chinese-Text-Classification-Pytorch/models/TextRCNN.py +--- Chinese-Text-Classification-Pytorch_back/models/TextRCNN.py 2021-08-13 20:49:45.263263000 +0800 ++++ Chinese-Text-Classification-Pytorch/models/TextRCNN.py 1970-01-01 08:00:00.000000000 +0800 +@@ -1,64 +0,0 @@ +-# coding: UTF-8 +-import torch +-import torch.nn as nn +-import torch.nn.functional as F +-import numpy as np +- +- +-class Config(object): +- +- """配置参数""" +- def __init__(self, dataset, embedding): +- self.model_name = 'TextRCNN' +- self.train_path = dataset + '/data/train.txt' # 训练集 +- self.dev_path = dataset + '/data/dev.txt' # 验证集 +- self.test_path = dataset + '/data/test.txt' # 测试集 +- self.class_list = [x.strip() for x in open( +- dataset + '/data/class.txt', encoding='utf-8').readlines()] # 类别名单 +- self.vocab_path = dataset + '/data/vocab.pkl' # 词表 +- self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt' # 模型训练结果 +- self.log_path = dataset + '/log/' + self.model_name +- self.embedding_pretrained = torch.tensor( +- np.load(dataset + '/data/' + embedding)["embeddings"].astype('float32'))\ +- if embedding != 'random' else None # 预训练词向量 +- self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 设备 +- +- self.dropout = 1.0 # 随机失活 +- self.require_improvement = 1000 # 若超过1000batch效果还没提升,则提前结束训练 +- self.num_classes = len(self.class_list) # 类别数 +- self.n_vocab = 0 # 词表大小,在运行时赋值 +- self.num_epochs = 10 # epoch数 +- self.batch_size = 128 # mini-batch大小 +- self.pad_size = 32 # 每句话处理成的长度(短填长切) +- self.learning_rate = 1e-3 # 学习率 +- self.embed = self.embedding_pretrained.size(1)\ +- if self.embedding_pretrained is not None else 300 # 字向量维度, 若使用了预训练词向量,则维度统一 +- self.hidden_size = 256 # lstm隐藏层 +- self.num_layers = 1 # lstm层数 +- +- +-'''Recurrent Convolutional Neural Networks for Text Classification''' +- +- +-class Model(nn.Module): +- def __init__(self, config): +- super(Model, self).__init__() +- if config.embedding_pretrained is not None: +- self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False) +- else: +- self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1) +- self.lstm = nn.LSTM(config.embed, config.hidden_size, config.num_layers, +- bidirectional=True, batch_first=True, dropout=config.dropout) +- self.maxpool = nn.MaxPool1d(config.pad_size) +- self.fc = nn.Linear(config.hidden_size * 2 + config.embed, config.num_classes) +- +- def forward(self, x): +- x, _ = x +- embed = self.embedding(x) # [batch_size, seq_len, embeding]=[64, 32, 64] +- out, _ = self.lstm(embed) +- out = torch.cat((embed, out), 2) +- out = F.relu(out) +- out = out.permute(0, 2, 1) +- out = self.maxpool(out).squeeze() +- out = self.fc(out) +- return out +diff -uprN Chinese-Text-Classification-Pytorch_back/models/TextRNN_Att.py Chinese-Text-Classification-Pytorch/models/TextRNN_Att.py +--- Chinese-Text-Classification-Pytorch_back/models/TextRNN_Att.py 2021-08-13 20:49:45.263263000 +0800 ++++ Chinese-Text-Classification-Pytorch/models/TextRNN_Att.py 1970-01-01 08:00:00.000000000 +0800 +@@ -1,73 +0,0 @@ +-# coding: UTF-8 +-import torch +-import torch.nn as nn +-import torch.nn.functional as F +-import numpy as np +- +- +-class Config(object): +- +- """配置参数""" +- def __init__(self, dataset, embedding): +- self.model_name = 'TextRNN_Att' +- self.train_path = dataset + '/data/train.txt' # 训练集 +- self.dev_path = dataset + '/data/dev.txt' # 验证集 +- self.test_path = dataset + '/data/test.txt' # 测试集 +- self.class_list = [x.strip() for x in open( +- dataset + '/data/class.txt', encoding='utf-8').readlines()] # 类别名单 +- self.vocab_path = dataset + '/data/vocab.pkl' # 词表 +- self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt' # 模型训练结果 +- self.log_path = dataset + '/log/' + self.model_name +- self.embedding_pretrained = torch.tensor( +- np.load(dataset + '/data/' + embedding)["embeddings"].astype('float32'))\ +- if embedding != 'random' else None # 预训练词向量 +- self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 设备 +- +- self.dropout = 0.5 # 随机失活 +- self.require_improvement = 1000 # 若超过1000batch效果还没提升,则提前结束训练 +- self.num_classes = len(self.class_list) # 类别数 +- self.n_vocab = 0 # 词表大小,在运行时赋值 +- self.num_epochs = 10 # epoch数 +- self.batch_size = 128 # mini-batch大小 +- self.pad_size = 32 # 每句话处理成的长度(短填长切) +- self.learning_rate = 1e-3 # 学习率 +- self.embed = self.embedding_pretrained.size(1)\ +- if self.embedding_pretrained is not None else 300 # 字向量维度, 若使用了预训练词向量,则维度统一 +- self.hidden_size = 128 # lstm隐藏层 +- self.num_layers = 2 # lstm层数 +- self.hidden_size2 = 64 +- +- +-'''Attention-Based Bidirectional Long Short-Term Memory Networks for Relation Classification''' +- +- +-class Model(nn.Module): +- def __init__(self, config): +- super(Model, self).__init__() +- if config.embedding_pretrained is not None: +- self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False) +- else: +- self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1) +- self.lstm = nn.LSTM(config.embed, config.hidden_size, config.num_layers, +- bidirectional=True, batch_first=True, dropout=config.dropout) +- self.tanh1 = nn.Tanh() +- # self.u = nn.Parameter(torch.Tensor(config.hidden_size * 2, config.hidden_size * 2)) +- self.w = nn.Parameter(torch.zeros(config.hidden_size * 2)) +- self.tanh2 = nn.Tanh() +- self.fc1 = nn.Linear(config.hidden_size * 2, config.hidden_size2) +- self.fc = nn.Linear(config.hidden_size2, config.num_classes) +- +- def forward(self, x): +- x, _ = x +- emb = self.embedding(x) # [batch_size, seq_len, embeding]=[128, 32, 300] +- H, _ = self.lstm(emb) # [batch_size, seq_len, hidden_size * num_direction]=[128, 32, 256] +- +- M = self.tanh1(H) # [128, 32, 256] +- # M = torch.tanh(torch.matmul(H, self.u)) +- alpha = F.softmax(torch.matmul(M, self.w), dim=1).unsqueeze(-1) # [128, 32, 1] +- out = H * alpha # [128, 32, 256] +- out = torch.sum(out, 1) # [128, 256] +- out = F.relu(out) +- out = self.fc1(out) +- out = self.fc(out) # [128, 64] +- return out +diff -uprN Chinese-Text-Classification-Pytorch_back/models/TextRNN.py Chinese-Text-Classification-Pytorch/models/TextRNN.py +--- Chinese-Text-Classification-Pytorch_back/models/TextRNN.py 2021-08-13 20:49:45.263263000 +0800 ++++ Chinese-Text-Classification-Pytorch/models/TextRNN.py 1970-01-01 08:00:00.000000000 +0800 +@@ -1,75 +0,0 @@ +-# coding: UTF-8 +-import torch +-import torch.nn as nn +-import numpy as np +- +- +-class Config(object): +- +- """配置参数""" +- def __init__(self, dataset, embedding): +- self.model_name = 'TextRNN' +- self.train_path = dataset + '/data/train.txt' # 训练集 +- self.dev_path = dataset + '/data/dev.txt' # 验证集 +- self.test_path = dataset + '/data/test.txt' # 测试集 +- self.class_list = [x.strip() for x in open( +- dataset + '/data/class.txt', encoding='utf-8').readlines()] # 类别名单 +- self.vocab_path = dataset + '/data/vocab.pkl' # 词表 +- self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt' # 模型训练结果 +- self.log_path = dataset + '/log/' + self.model_name +- self.embedding_pretrained = torch.tensor( +- np.load(dataset + '/data/' + embedding)["embeddings"].astype('float32'))\ +- if embedding != 'random' else None # 预训练词向量 +- self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 设备 +- +- self.dropout = 0.5 # 随机失活 +- self.require_improvement = 1000 # 若超过1000batch效果还没提升,则提前结束训练 +- self.num_classes = len(self.class_list) # 类别数 +- self.n_vocab = 0 # 词表大小,在运行时赋值 +- self.num_epochs = 10 # epoch数 +- self.batch_size = 128 # mini-batch大小 +- self.pad_size = 32 # 每句话处理成的长度(短填长切) +- self.learning_rate = 1e-3 # 学习率 +- self.embed = self.embedding_pretrained.size(1)\ +- if self.embedding_pretrained is not None else 300 # 字向量维度, 若使用了预训练词向量,则维度统一 +- self.hidden_size = 128 # lstm隐藏层 +- self.num_layers = 2 # lstm层数 +- +- +-'''Recurrent Neural Network for Text Classification with Multi-Task Learning''' +- +- +-class Model(nn.Module): +- def __init__(self, config): +- super(Model, self).__init__() +- if config.embedding_pretrained is not None: +- self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False) +- else: +- self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1) +- self.lstm = nn.LSTM(config.embed, config.hidden_size, config.num_layers, +- bidirectional=True, batch_first=True, dropout=config.dropout) +- self.fc = nn.Linear(config.hidden_size * 2, config.num_classes) +- +- def forward(self, x): +- x, _ = x +- out = self.embedding(x) # [batch_size, seq_len, embeding]=[128, 32, 300] +- out, _ = self.lstm(out) +- out = self.fc(out[:, -1, :]) # 句子最后时刻的 hidden state +- return out +- +- '''变长RNN,效果差不多,甚至还低了点...''' +- # def forward(self, x): +- # x, seq_len = x +- # out = self.embedding(x) +- # _, idx_sort = torch.sort(seq_len, dim=0, descending=True) # 长度从长到短排序(index) +- # _, idx_unsort = torch.sort(idx_sort) # 排序后,原序列的 index +- # out = torch.index_select(out, 0, idx_sort) +- # seq_len = list(seq_len[idx_sort]) +- # out = nn.utils.rnn.pack_padded_sequence(out, seq_len, batch_first=True) +- # # [batche_size, seq_len, num_directions * hidden_size] +- # out, (hn, _) = self.lstm(out) +- # out = torch.cat((hn[2], hn[3]), -1) +- # # out, _ = nn.utils.rnn.pad_packed_sequence(out, batch_first=True) +- # out = out.index_select(0, idx_unsort) +- # out = self.fc(out) +- # return out +diff -uprN Chinese-Text-Classification-Pytorch_back/models/Transformer.py Chinese-Text-Classification-Pytorch/models/Transformer.py +--- Chinese-Text-Classification-Pytorch_back/models/Transformer.py 2021-08-13 20:49:45.263263000 +0800 ++++ Chinese-Text-Classification-Pytorch/models/Transformer.py 1970-01-01 08:00:00.000000000 +0800 +@@ -1,178 +0,0 @@ +-import torch +-import torch.nn as nn +-import torch.nn.functional as F +-import numpy as np +-import copy +- +- +-class Config(object): +- +- """配置参数""" +- def __init__(self, dataset, embedding): +- self.model_name = 'Transformer' +- self.train_path = dataset + '/data/train.txt' # 训练集 +- self.dev_path = dataset + '/data/dev.txt' # 验证集 +- self.test_path = dataset + '/data/test.txt' # 测试集 +- self.class_list = [x.strip() for x in open( +- dataset + '/data/class.txt', encoding='utf-8').readlines()] # 类别名单 +- self.vocab_path = dataset + '/data/vocab.pkl' # 词表 +- self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt' # 模型训练结果 +- self.log_path = dataset + '/log/' + self.model_name +- self.embedding_pretrained = torch.tensor( +- np.load(dataset + '/data/' + embedding)["embeddings"].astype('float32'))\ +- if embedding != 'random' else None # 预训练词向量 +- self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 设备 +- +- self.dropout = 0.5 # 随机失活 +- self.require_improvement = 2000 # 若超过1000batch效果还没提升,则提前结束训练 +- self.num_classes = len(self.class_list) # 类别数 +- self.n_vocab = 0 # 词表大小,在运行时赋值 +- self.num_epochs = 20 # epoch数 +- self.batch_size = 128 # mini-batch大小 +- self.pad_size = 32 # 每句话处理成的长度(短填长切) +- self.learning_rate = 5e-4 # 学习率 +- self.embed = self.embedding_pretrained.size(1)\ +- if self.embedding_pretrained is not None else 300 # 字向量维度 +- self.dim_model = 300 +- self.hidden = 1024 +- self.last_hidden = 512 +- self.num_head = 5 +- self.num_encoder = 2 +- +- +-'''Attention Is All You Need''' +- +- +-class Model(nn.Module): +- def __init__(self, config): +- super(Model, self).__init__() +- if config.embedding_pretrained is not None: +- self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False) +- else: +- self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1) +- +- self.postion_embedding = Positional_Encoding(config.embed, config.pad_size, config.dropout, config.device) +- self.encoder = Encoder(config.dim_model, config.num_head, config.hidden, config.dropout) +- self.encoders = nn.ModuleList([ +- copy.deepcopy(self.encoder) +- # Encoder(config.dim_model, config.num_head, config.hidden, config.dropout) +- for _ in range(config.num_encoder)]) +- +- self.fc1 = nn.Linear(config.pad_size * config.dim_model, config.num_classes) +- # self.fc2 = nn.Linear(config.last_hidden, config.num_classes) +- # self.fc1 = nn.Linear(config.dim_model, config.num_classes) +- +- def forward(self, x): +- out = self.embedding(x[0]) +- out = self.postion_embedding(out) +- for encoder in self.encoders: +- out = encoder(out) +- out = out.view(out.size(0), -1) +- # out = torch.mean(out, 1) +- out = self.fc1(out) +- return out +- +- +-class Encoder(nn.Module): +- def __init__(self, dim_model, num_head, hidden, dropout): +- super(Encoder, self).__init__() +- self.attention = Multi_Head_Attention(dim_model, num_head, dropout) +- self.feed_forward = Position_wise_Feed_Forward(dim_model, hidden, dropout) +- +- def forward(self, x): +- out = self.attention(x) +- out = self.feed_forward(out) +- return out +- +- +-class Positional_Encoding(nn.Module): +- def __init__(self, embed, pad_size, dropout, device): +- super(Positional_Encoding, self).__init__() +- self.device = device +- self.pe = torch.tensor([[pos / (10000.0 ** (i // 2 * 2.0 / embed)) for i in range(embed)] for pos in range(pad_size)]) +- self.pe[:, 0::2] = np.sin(self.pe[:, 0::2]) +- self.pe[:, 1::2] = np.cos(self.pe[:, 1::2]) +- self.dropout = nn.Dropout(dropout) +- +- def forward(self, x): +- out = x + nn.Parameter(self.pe, requires_grad=False).to(self.device) +- out = self.dropout(out) +- return out +- +- +-class Scaled_Dot_Product_Attention(nn.Module): +- '''Scaled Dot-Product Attention ''' +- def __init__(self): +- super(Scaled_Dot_Product_Attention, self).__init__() +- +- def forward(self, Q, K, V, scale=None): +- ''' +- Args: +- Q: [batch_size, len_Q, dim_Q] +- K: [batch_size, len_K, dim_K] +- V: [batch_size, len_V, dim_V] +- scale: 缩放因子 论文为根号dim_K +- Return: +- self-attention后的张量,以及attention张量 +- ''' +- attention = torch.matmul(Q, K.permute(0, 2, 1)) +- if scale: +- attention = attention * scale +- # if mask: # TODO change this +- # attention = attention.masked_fill_(mask == 0, -1e9) +- attention = F.softmax(attention, dim=-1) +- context = torch.matmul(attention, V) +- return context +- +- +-class Multi_Head_Attention(nn.Module): +- def __init__(self, dim_model, num_head, dropout=0.0): +- super(Multi_Head_Attention, self).__init__() +- self.num_head = num_head +- assert dim_model % num_head == 0 +- self.dim_head = dim_model // self.num_head +- self.fc_Q = nn.Linear(dim_model, num_head * self.dim_head) +- self.fc_K = nn.Linear(dim_model, num_head * self.dim_head) +- self.fc_V = nn.Linear(dim_model, num_head * self.dim_head) +- self.attention = Scaled_Dot_Product_Attention() +- self.fc = nn.Linear(num_head * self.dim_head, dim_model) +- self.dropout = nn.Dropout(dropout) +- self.layer_norm = nn.LayerNorm(dim_model) +- +- def forward(self, x): +- batch_size = x.size(0) +- Q = self.fc_Q(x) +- K = self.fc_K(x) +- V = self.fc_V(x) +- Q = Q.view(batch_size * self.num_head, -1, self.dim_head) +- K = K.view(batch_size * self.num_head, -1, self.dim_head) +- V = V.view(batch_size * self.num_head, -1, self.dim_head) +- # if mask: # TODO +- # mask = mask.repeat(self.num_head, 1, 1) # TODO change this +- scale = K.size(-1) ** -0.5 # 缩放因子 +- context = self.attention(Q, K, V, scale) +- +- context = context.view(batch_size, -1, self.dim_head * self.num_head) +- out = self.fc(context) +- out = self.dropout(out) +- out = out + x # 残差连接 +- out = self.layer_norm(out) +- return out +- +- +-class Position_wise_Feed_Forward(nn.Module): +- def __init__(self, dim_model, hidden, dropout=0.0): +- super(Position_wise_Feed_Forward, self).__init__() +- self.fc1 = nn.Linear(dim_model, hidden) +- self.fc2 = nn.Linear(hidden, dim_model) +- self.dropout = nn.Dropout(dropout) +- self.layer_norm = nn.LayerNorm(dim_model) +- +- def forward(self, x): +- out = self.fc1(x) +- out = F.relu(out) +- out = self.fc2(out) +- out = self.dropout(out) +- out = out + x # 残差连接 +- out = self.layer_norm(out) +- return out +diff -uprN Chinese-Text-Classification-Pytorch_back/utils.py Chinese-Text-Classification-Pytorch/utils.py +--- Chinese-Text-Classification-Pytorch_back/utils.py 2021-08-13 20:49:45.263263000 +0800 ++++ Chinese-Text-Classification-Pytorch/utils.py 2021-09-07 21:23:50.874085521 +0800 +@@ -60,7 +60,7 @@ def build_dataset(config, ues_word): + # word to id + for word in token: + words_line.append(vocab.get(word, vocab.get(UNK))) +- contents.append((words_line, int(label), seq_len)) ++ contents.append((words_line, int(label))) + return contents # [([...], 0), ([...], 1), ...] + train = load_dataset(config.train_path, config.pad_size) + dev = load_dataset(config.dev_path, config.pad_size) +@@ -83,9 +83,7 @@ class DatasetIterater(object): + x = torch.LongTensor([_[0] for _ in datas]).to(self.device) + y = torch.LongTensor([_[1] for _ in datas]).to(self.device) + +- # pad前的长度(超过pad_size的设为pad_size) +- seq_len = torch.LongTensor([_[2] for _ in datas]).to(self.device) +- return (x, seq_len), y ++ return x, y + + def __next__(self): + if self.residue and self.index == self.n_batches: diff --git a/ACL_PyTorch/contrib/nlp/albert/0001-init.patch b/ACL_PyTorch/contrib/nlp/albert/0001-init.patch index 0fcc472b69..238f4906db 100644 --- a/ACL_PyTorch/contrib/nlp/albert/0001-init.patch +++ b/ACL_PyTorch/contrib/nlp/albert/0001-init.patch @@ -34,307 +34,307 @@ index 57543c3..555ffd1 100644 --- a/callback/lr_scheduler.py +++ b/callback/lr_scheduler.py @@ -12,6 +12,7 @@ __all__ = ['CustomDecayLR', - 'CosineLRWithRestarts', - ] - -+ - def get_constant_schedule(optimizer, last_epoch=-1): - """ Create a schedule with a constant learning rate. - """ + 'CosineLRWithRestarts', + ] + ++ + def get_constant_schedule(optimizer, last_epoch=-1): + """ Create a schedule with a constant learning rate. + """ @@ -22,6 +23,7 @@ def get_constant_schedule_with_warmup(optimizer, num_warmup_steps, last_epoch=-1 - """ Create a schedule with a constant learning rate preceded by a warmup - period during which the learning rate increases linearly between 0 and 1. - """ -+ - def lr_lambda(current_step): - if current_step < num_warmup_steps: - return float(current_step) / float(max(1.0, num_warmup_steps)) + """ Create a schedule with a constant learning rate preceded by a warmup + period during which the learning rate increases linearly between 0 and 1. + """ ++ + def lr_lambda(current_step): + if current_step < num_warmup_steps: + return float(current_step) / float(max(1.0, num_warmup_steps)) @@ -34,6 +36,7 @@ def get_linear_schedule_with_warmup(optimizer, num_warmup_steps, num_training_st - """ Create a schedule with a learning rate that decreases linearly after - linearly increasing during a warmup period. - """ -+ - def lr_lambda(current_step): - if current_step < num_warmup_steps: - return float(current_step) / float(max(1, num_warmup_steps)) + """ Create a schedule with a learning rate that decreases linearly after + linearly increasing during a warmup period. + """ ++ + def lr_lambda(current_step): + if current_step < num_warmup_steps: + return float(current_step) / float(max(1, num_warmup_steps)) @@ -47,6 +50,7 @@ def get_cosine_schedule_with_warmup(optimizer, num_warmup_steps, num_training_st - values of the cosine function between 0 and `pi * cycles` after a warmup - period during which it increases linearly between 0 and 1. - """ -+ - def lr_lambda(current_step): - if current_step < num_warmup_steps: - return float(current_step) / float(max(1, num_warmup_steps)) + values of the cosine function between 0 and `pi * cycles` after a warmup + period during which it increases linearly between 0 and 1. + """ ++ + def lr_lambda(current_step): + if current_step < num_warmup_steps: + return float(current_step) / float(max(1, num_warmup_steps)) @@ -56,11 +60,13 @@ def get_cosine_schedule_with_warmup(optimizer, num_warmup_steps, num_training_st - return LambdaLR(optimizer, lr_lambda, last_epoch) - - --def get_cosine_with_hard_restarts_schedule_with_warmup(optimizer, num_warmup_steps, num_training_steps, num_cycles=1., last_epoch=-1): -+def get_cosine_with_hard_restarts_schedule_with_warmup(optimizer, num_warmup_steps, num_training_steps, num_cycles=1., -+ last_epoch=-1): - """ Create a schedule with a learning rate that decreases following the - values of the cosine function with several hard restarts, after a warmup - period during which it increases linearly between 0 and 1. - """ -+ - def lr_lambda(current_step): - if current_step < num_warmup_steps: - return float(current_step) / float(max(1, num_warmup_steps)) + return LambdaLR(optimizer, lr_lambda, last_epoch) + + +-def get_cosine_with_hard_restarts_schedule_with_warmup(optimizer, num_warmup_steps, num_training_steps, num_cycles=1., last_epoch=-1): ++def get_cosine_with_hard_restarts_schedule_with_warmup(optimizer, num_warmup_steps, num_training_steps, num_cycles=1., ++ last_epoch=-1): + """ Create a schedule with a learning rate that decreases following the + values of the cosine function with several hard restarts, after a warmup + period during which it increases linearly between 0 and 1. + """ ++ + def lr_lambda(current_step): + if current_step < num_warmup_steps: + return float(current_step) / float(max(1, num_warmup_steps)) @@ -86,11 +92,12 @@ class CustomDecayLR(object): - >>> optimizer.step() - >>> validate(...) - ''' -- def __init__(self,optimizer,lr): -+ -+ def __init__(self, optimizer, lr): - self.optimizer = optimizer - self.lr = lr - -- def epoch_step(self,epoch): -+ def epoch_step(self, epoch): - lr = self.lr - if epoch > 12: - lr = lr / 1000 + >>> optimizer.step() + >>> validate(...) + ''' +- def __init__(self,optimizer,lr): ++ ++ def __init__(self, optimizer, lr): + self.optimizer = optimizer + self.lr = lr + +- def epoch_step(self,epoch): ++ def epoch_step(self, epoch): + lr = self.lr + if epoch > 12: + lr = lr / 1000 @@ -101,6 +108,7 @@ class CustomDecayLR(object): - for param_group in self.optimizer.param_groups: - param_group['lr'] = lr - -+ - class BertLR(object): - ''' - Bert模型内定的学习率变化机制 + for param_group in self.optimizer.param_groups: + param_group['lr'] = lr + ++ + class BertLR(object): + ''' + Bert模型内定的学习率变化机制 @@ -116,23 +124,25 @@ class BertLR(object): - >>> scheduler.batch_step() - >>> validate(...) - ''' -- def __init__(self,optimizer,learning_rate,t_total,warmup): -+ -+ def __init__(self, optimizer, learning_rate, t_total, warmup): - self.learning_rate = learning_rate - self.optimizer = optimizer - self.t_total = t_total - self.warmup = warmup - - # 线性预热方式 -- def warmup_linear(self,x, warmup=0.002): -+ def warmup_linear(self, x, warmup=0.002): - if x < warmup: - return x / warmup - return 1.0 - x - -- def batch_step(self,training_step): -- lr_this_step = self.learning_rate * self.warmup_linear(training_step / self.t_total,self.warmup) -+ def batch_step(self, training_step): -+ lr_this_step = self.learning_rate * self.warmup_linear(training_step / self.t_total, self.warmup) - for param_group in self.optimizer.param_groups: - param_group['lr'] = lr_this_step - -+ - class CyclicLR(object): - ''' - Cyclical learning rates for training neural networks + >>> scheduler.batch_step() + >>> validate(...) + ''' +- def __init__(self,optimizer,learning_rate,t_total,warmup): ++ ++ def __init__(self, optimizer, learning_rate, t_total, warmup): + self.learning_rate = learning_rate + self.optimizer = optimizer + self.t_total = t_total + self.warmup = warmup + + # 线性预热方式 +- def warmup_linear(self,x, warmup=0.002): ++ def warmup_linear(self, x, warmup=0.002): + if x < warmup: + return x / warmup + return 1.0 - x + +- def batch_step(self,training_step): +- lr_this_step = self.learning_rate * self.warmup_linear(training_step / self.t_total,self.warmup) ++ def batch_step(self, training_step): ++ lr_this_step = self.learning_rate * self.warmup_linear(training_step / self.t_total, self.warmup) + for param_group in self.optimizer.param_groups: + param_group['lr'] = lr_this_step + ++ + class CyclicLR(object): + ''' + Cyclical learning rates for training neural networks @@ -148,6 +158,7 @@ class CyclicLR(object): - >>> scheduler.batch_step() - >>> validate(...) - ''' -+ - def __init__(self, optimizer, base_lr=1e-3, max_lr=6e-3, - step_size=2000, mode='triangular', gamma=1., - scale_fn=None, scale_mode='cycle', last_batch_iteration=-1): + >>> scheduler.batch_step() + >>> validate(...) + ''' ++ + def __init__(self, optimizer, base_lr=1e-3, max_lr=6e-3, + step_size=2000, mode='triangular', gamma=1., + scale_fn=None, scale_mode='cycle', last_batch_iteration=-1): @@ -207,7 +218,7 @@ class CyclicLR(object): - return 1 / (2. ** (x - 1)) - - def _exp_range_scale_fn(self, x): -- return self.gamma**(x) -+ return self.gamma ** (x) - - def get_lr(self): - step_size = float(self.step_size) + return 1 / (2. ** (x - 1)) + + def _exp_range_scale_fn(self, x): +- return self.gamma**(x) ++ return self.gamma ** (x) + + def get_lr(self): + step_size = float(self.step_size) @@ -232,6 +243,7 @@ class CyclicLR(object): - for param_group, lr in zip(self.optimizer.param_groups, self.get_lr()): - param_group['lr'] = lr - -+ - class ReduceLROnPlateau(object): - """Reduce learning rate when a metric has stopped improving. - Models often benefit from reducing the learning rate by a factor + for param_group, lr in zip(self.optimizer.param_groups, self.get_lr()): + param_group['lr'] = lr + ++ + class ReduceLROnPlateau(object): + """Reduce learning rate when a metric has stopped improving. + Models often benefit from reducing the learning rate by a factor @@ -267,7 +279,7 @@ class ReduceLROnPlateau(object): - """ - - def __init__(self, optimizer, mode='min', factor=0.1, patience=10, -- verbose=0, epsilon=1e-4, cooldown=0, min_lr=0,eps=1e-8): -+ verbose=0, epsilon=1e-4, cooldown=0, min_lr=0, eps=1e-8): - - super(ReduceLROnPlateau, self).__init__() - assert isinstance(optimizer, Optimizer) + """ + + def __init__(self, optimizer, mode='min', factor=0.1, patience=10, +- verbose=0, epsilon=1e-4, cooldown=0, min_lr=0,eps=1e-8): ++ verbose=0, epsilon=1e-4, cooldown=0, min_lr=0, eps=1e-8): + + super(ReduceLROnPlateau, self).__init__() + assert isinstance(optimizer, Optimizer) @@ -335,6 +347,7 @@ class ReduceLROnPlateau(object): - def in_cooldown(self): - return self.cooldown_counter > 0 - -+ - class ReduceLRWDOnPlateau(ReduceLROnPlateau): - """Reduce learning rate and weight decay when a metric has stopped - improving. Models often benefit from reducing the learning rate by + def in_cooldown(self): + return self.cooldown_counter > 0 + ++ + class ReduceLRWDOnPlateau(ReduceLROnPlateau): + """Reduce learning rate and weight decay when a metric has stopped + improving. Models often benefit from reducing the learning rate by @@ -356,6 +369,7 @@ class ReduceLRWDOnPlateau(ReduceLROnPlateau): - >>> # Note that step should be called after validate() - >>> scheduler.epoch_step(val_loss) - """ -+ - def epoch_step(self, metrics, epoch): - current = metrics - if current is None: + >>> # Note that step should be called after validate() + >>> scheduler.epoch_step(val_loss) + """ ++ + def epoch_step(self, metrics, epoch): + current = metrics + if current is None: @@ -384,11 +398,13 @@ class ReduceLRWDOnPlateau(ReduceLROnPlateau): - if old_weight_decay > new_weight_decay + self.eps: - param_group['weight_decay'] = new_weight_decay - if self.verbose: -- print('\nEpoch {epoch}: reducing weight decay factor of group {i} to {new_weight_decay:.4e}.') -+ print( -+ '\nEpoch {epoch}: reducing weight decay factor of group {i} to {new_weight_decay:.4e}.') - self.cooldown_counter = self.cooldown - self.wait = 0 - self.wait += 1 - -+ - class CosineLRWithRestarts(object): - """Decays learning rate with cosine annealing, normalizes weight decay - hyperparameter value, implements restarts. + if old_weight_decay > new_weight_decay + self.eps: + param_group['weight_decay'] = new_weight_decay + if self.verbose: +- print('\nEpoch {epoch}: reducing weight decay factor of group {i} to {new_weight_decay:.4e}.') ++ print( ++ '\nEpoch {epoch}: reducing weight decay factor of group {i} to {new_weight_decay:.4e}.') + self.cooldown_counter = self.cooldown + self.wait = 0 + self.wait += 1 + ++ + class CosineLRWithRestarts(object): + """Decays learning rate with cosine annealing, normalizes weight decay + hyperparameter value, implements restarts. @@ -501,7 +517,7 @@ class CosineLRWithRestarts(object): - "training loop and while initializing " - "scheduler should be the same.") - -- for param_group, (lr, weight_decay) in zip(self.optimizer.param_groups,self.get_lr(t_cur)): -+ for param_group, (lr, weight_decay) in zip(self.optimizer.param_groups, self.get_lr(t_cur)): - param_group['lr'] = lr - param_group['weight_decay'] = weight_decay - + "training loop and while initializing " + "scheduler should be the same.") + +- for param_group, (lr, weight_decay) in zip(self.optimizer.param_groups,self.get_lr(t_cur)): ++ for param_group, (lr, weight_decay) in zip(self.optimizer.param_groups, self.get_lr(t_cur)): + param_group['lr'] = lr + param_group['weight_decay'] = weight_decay + @@ -522,18 +538,19 @@ class NoamLR(object): - >>> scheduler.batch_step(global_step) - >>> validate(...) - ''' -- def __init__(self,d_model,factor,warm_up,optimizer): -+ -+ def __init__(self, d_model, factor, warm_up, optimizer): - self.optimizer = optimizer - self.warm_up = warm_up - self.factor = factor - self.d_model = d_model - self._lr = 0 - -- def get_lr(self,step): -- lr = self.factor * (self.d_model ** (-0.5) * min(step ** (-0.5),step * self.warm_up ** (-1.5))) -+ def get_lr(self, step): -+ lr = self.factor * (self.d_model ** (-0.5) * min(step ** (-0.5), step * self.warm_up ** (-1.5))) - return lr - -- def batch_step(self,step): -+ def batch_step(self, step): - ''' - update parameters and rate - :return: + >>> scheduler.batch_step(global_step) + >>> validate(...) + ''' +- def __init__(self,d_model,factor,warm_up,optimizer): ++ ++ def __init__(self, d_model, factor, warm_up, optimizer): + self.optimizer = optimizer + self.warm_up = warm_up + self.factor = factor + self.d_model = d_model + self._lr = 0 + +- def get_lr(self,step): +- lr = self.factor * (self.d_model ** (-0.5) * min(step ** (-0.5),step * self.warm_up ** (-1.5))) ++ def get_lr(self, step): ++ lr = self.factor * (self.d_model ** (-0.5) * min(step ** (-0.5), step * self.warm_up ** (-1.5))) + return lr + +- def batch_step(self,step): ++ def batch_step(self, step): + ''' + update parameters and rate + :return: diff --git a/callback/modelcheckpoint.py b/callback/modelcheckpoint.py index b7f4ffa..20b0663 100644 --- a/callback/modelcheckpoint.py +++ b/callback/modelcheckpoint.py @@ -3,19 +3,21 @@ import numpy as np - import torch - from ..tools.common import logger - -+ - class ModelCheckpoint(object): - ''' - 模型保存,两种模式: - 1. 直接保存最好模型 - 2. 按照epoch频率保存模型 - ''' -+ - def __init__(self, checkpoint_dir, - monitor, -- arch,mode='min', -+ arch, mode='min', - epoch_freq=1, -- best = None, -- save_best_only = True): -- if isinstance(checkpoint_dir,Path): -+ best=None, -+ save_best_only=True): -+ if isinstance(checkpoint_dir, Path): - checkpoint_dir = checkpoint_dir - else: - checkpoint_dir = Path(checkpoint_dir) + import torch + from ..tools.common import logger + ++ + class ModelCheckpoint(object): + ''' + 模型保存,两种模式: + 1. 直接保存最好模型 + 2. 按照epoch频率保存模型 + ''' ++ + def __init__(self, checkpoint_dir, + monitor, +- arch,mode='min', ++ arch, mode='min', + epoch_freq=1, +- best = None, +- save_best_only = True): +- if isinstance(checkpoint_dir,Path): ++ best=None, ++ save_best_only=True): ++ if isinstance(checkpoint_dir, Path): + checkpoint_dir = checkpoint_dir + else: + checkpoint_dir = Path(checkpoint_dir) @@ -36,14 +38,14 @@ class ModelCheckpoint(object): - self.monitor_op = np.greater - self.best = -np.Inf - # 这里主要重新加载模型时候 -- #对best重新赋值 -+ # 对best重新赋值 - if best: - self.best = best - - if save_best_only: - self.model_name = f"BEST_{arch}_MODEL.pth" - -- def epoch_step(self, state,current): -+ def epoch_step(self, state, current): - ''' - 正常模型 - :param state: 需要保存的信息 + self.monitor_op = np.greater + self.best = -np.Inf + # 这里主要重新加载模型时候 +- #对best重新赋值 ++ # 对best重新赋值 + if best: + self.best = best + + if save_best_only: + self.model_name = f"BEST_{arch}_MODEL.pth" + +- def epoch_step(self, state,current): ++ def epoch_step(self, state, current): + ''' + 正常模型 + :param state: 需要保存的信息 @@ -56,7 +58,7 @@ class ModelCheckpoint(object): - logger.info(f"\nEpoch {state['epoch']}: {self.monitor} improved from {self.best:.5f} to {current:.5f}") - self.best = current - state['best'] = self.best -- best_path = self.base_path/ self.model_name -+ best_path = self.base_path / self.model_name - torch.save(state, str(best_path)) - # 每隔几个epoch保存下模型 - else: + logger.info(f"\nEpoch {state['epoch']}: {self.monitor} improved from {self.best:.5f} to {current:.5f}") + self.best = current + state['best'] = self.best +- best_path = self.base_path/ self.model_name ++ best_path = self.base_path / self.model_name + torch.save(state, str(best_path)) + # 每隔几个epoch保存下模型 + else: @@ -65,7 +67,7 @@ class ModelCheckpoint(object): - logger.info(f"\nEpoch {state['epoch']}: save model to disk.") - torch.save(state, str(filename)) - -- def bert_epoch_step(self, state,current): -+ def bert_epoch_step(self, state, current): - ''' - 适合bert类型模型,适合pytorch_transformer模块 - :param state: + logger.info(f"\nEpoch {state['epoch']}: save model to disk.") + torch.save(state, str(filename)) + +- def bert_epoch_step(self, state,current): ++ def bert_epoch_step(self, state, current): + ''' + 适合bert类型模型,适合pytorch_transformer模块 + :param state: @@ -83,7 +85,7 @@ class ModelCheckpoint(object): - with open(str(output_config_file), 'w') as f: - f.write(model_to_save.config.to_json_string()) - state.pop("model") -- torch.save(state,self.base_path / 'checkpoint_info.bin') -+ torch.save(state, self.base_path / 'checkpoint_info.bin') - else: - if state['epoch'] % self.epoch_freq == 0: - save_path = self.base_path / f"checkpoint-epoch-{state['epoch']}" + with open(str(output_config_file), 'w') as f: + f.write(model_to_save.config.to_json_string()) + state.pop("model") +- torch.save(state,self.base_path / 'checkpoint_info.bin') ++ torch.save(state, self.base_path / 'checkpoint_info.bin') + else: + if state['epoch'] % self.epoch_freq == 0: + save_path = self.base_path / f"checkpoint-epoch-{state['epoch']}" diff --git a/callback/progressbar.py b/callback/progressbar.py index 5e43b88..c9d9613 100644 --- a/callback/progressbar.py +++ b/callback/progressbar.py @@ -1,4 +1,6 @@ - import time -+ -+ - class ProgressBar(object): - ''' - custom progress bar + import time ++ ++ + class ProgressBar(object): + ''' + custom progress bar @@ -7,7 +9,8 @@ class ProgressBar(object): - >>> step = 2 - >>> pbar(step=step) - ''' -- def __init__(self, n_total,width=30,desc = 'Training'): -+ -+ def __init__(self, n_total, width=30, desc='Training'): - self.width = width - self.n_total = n_total - self.start_time = time.time() + >>> step = 2 + >>> pbar(step=step) + ''' +- def __init__(self, n_total,width=30,desc = 'Training'): ++ ++ def __init__(self, n_total, width=30, desc='Training'): + self.width = width + self.n_total = n_total + self.start_time = time.time() @@ -23,7 +26,7 @@ class ProgressBar(object): - prog_width = int(self.width * recv_per) - if prog_width > 0: - bar += '=' * (prog_width - 1) -- if current< self.n_total: -+ if current < self.n_total: - bar += ">" - else: - bar += '=' + prog_width = int(self.width * recv_per) + if prog_width > 0: + bar += '=' * (prog_width - 1) +- if current< self.n_total: ++ if current < self.n_total: + bar += ">" + else: + bar += '=' diff --git a/callback/trainingmonitor.py b/callback/trainingmonitor.py index 6aea128..cb78168 100644 --- a/callback/trainingmonitor.py @@ -373,258 +373,258 @@ index 679602d..c7afb77 100644 --- a/metrics/custom_metrics.py +++ b/metrics/custom_metrics.py @@ -1,4 +1,4 @@ --#encoding:utf-8 -+# encoding:utf-8 - import torch - from tqdm import tqdm - import numpy as np +-#encoding:utf-8 ++# encoding:utf-8 + import torch + from tqdm import tqdm + import numpy as np @@ -6,7 +6,8 @@ from collections import Counter - from sklearn.metrics import roc_auc_score - from sklearn.metrics import f1_score, classification_report - --__call__ = ['Accuracy','AUC','F1Score','EntityScore','ClassReport','MultiLabelReport','AccuracyThresh'] -+__call__ = ['Accuracy', 'AUC', 'F1Score', 'EntityScore', 'ClassReport', 'MultiLabelReport', 'AccuracyThresh'] -+ - - class Metric: - def __init__(self): + from sklearn.metrics import roc_auc_score + from sklearn.metrics import f1_score, classification_report + +-__call__ = ['Accuracy','AUC','F1Score','EntityScore','ClassReport','MultiLabelReport','AccuracyThresh'] ++__call__ = ['Accuracy', 'AUC', 'F1Score', 'EntityScore', 'ClassReport', 'MultiLabelReport', 'AccuracyThresh'] ++ + + class Metric: + def __init__(self): @@ -24,6 +25,7 @@ class Metric: - def name(self): - raise NotImplementedError - -+ - class Accuracy(Metric): - ''' - 计算准确度 + def name(self): + raise NotImplementedError + ++ + class Accuracy(Metric): + ''' + 计算准确度 @@ -37,8 +39,9 @@ class Accuracy(Metric): - >>> metrics(logits,target) - >>> print(metrics.name(),metrics.value()) - ''' -- def __init__(self,topK): -- super(Accuracy,self).__init__() -+ -+ def __init__(self, topK): -+ super(Accuracy, self).__init__() - self.topK = topK - self.reset() - + >>> metrics(logits,target) + >>> print(metrics.name(),metrics.value()) + ''' +- def __init__(self,topK): +- super(Accuracy,self).__init__() ++ ++ def __init__(self, topK): ++ super(Accuracy, self).__init__() + self.topK = topK + self.reset() + @@ -54,7 +57,7 @@ class Accuracy(Metric): - self.total = 0 - - def value(self): -- return float(self.correct_k) / self.total -+ return float(self.correct_k) / self.total - - def name(self): - return 'accuracy' + self.total = 0 + + def value(self): +- return float(self.correct_k) / self.total ++ return float(self.correct_k) / self.total + + def name(self): + return 'accuracy' @@ -73,8 +76,9 @@ class AccuracyThresh(Metric): - >>> metrics(logits,target) - >>> print(metrics.name(),metrics.value()) - ''' -- def __init__(self,thresh = 0.5): -- super(AccuracyThresh,self).__init__() -+ -+ def __init__(self, thresh=0.5): -+ super(AccuracyThresh, self).__init__() - self.thresh = thresh - self.reset() - + >>> metrics(logits,target) + >>> print(metrics.name(),metrics.value()) + ''' +- def __init__(self,thresh = 0.5): +- super(AccuracyThresh,self).__init__() ++ ++ def __init__(self, thresh=0.5): ++ super(AccuracyThresh, self).__init__() + self.thresh = thresh + self.reset() + @@ -88,7 +92,7 @@ class AccuracyThresh(Metric): - - def value(self): - data_size = self.y_pred.size(0) -- acc = np.mean(((self.y_pred>self.thresh)==self.y_true.byte()).float().cpu().numpy(), axis=1).sum() -+ acc = np.mean(((self.y_pred > self.thresh) == self.y_true.byte()).float().cpu().numpy(), axis=1).sum() - return acc / data_size - - def name(self): + + def value(self): + data_size = self.y_pred.size(0) +- acc = np.mean(((self.y_pred>self.thresh)==self.y_true.byte()).float().cpu().numpy(), axis=1).sum() ++ acc = np.mean(((self.y_pred > self.thresh) == self.y_true.byte()).float().cpu().numpy(), axis=1).sum() + return acc / data_size + + def name(self): @@ -119,16 +123,16 @@ class AUC(Metric): - >>> print(metrics.name(),metrics.value()) - ''' - -- def __init__(self,task_type = 'binary',average = 'binary'): -+ def __init__(self, task_type='binary', average='binary'): - super(AUC, self).__init__() - -- assert task_type in ['binary','multiclass'] -- assert average in ['binary','micro', 'macro', 'samples', 'weighted'] -+ assert task_type in ['binary', 'multiclass'] -+ assert average in ['binary', 'micro', 'macro', 'samples', 'weighted'] - - self.task_type = task_type - self.average = average - -- def __call__(self,logits,target): -+ def __call__(self, logits, target): - ''' - 计算整个结果 - ''' + >>> print(metrics.name(),metrics.value()) + ''' + +- def __init__(self,task_type = 'binary',average = 'binary'): ++ def __init__(self, task_type='binary', average='binary'): + super(AUC, self).__init__() + +- assert task_type in ['binary','multiclass'] +- assert average in ['binary','micro', 'macro', 'samples', 'weighted'] ++ assert task_type in ['binary', 'multiclass'] ++ assert average in ['binary', 'micro', 'macro', 'samples', 'weighted'] + + self.task_type = task_type + self.average = average + +- def __call__(self,logits,target): ++ def __call__(self, logits, target): + ''' + 计算整个结果 + ''' @@ -152,6 +156,7 @@ class AUC(Metric): - def name(self): - return 'auc' - -+ - class F1Score(Metric): - ''' - F1 Score + def name(self): + return 'auc' + ++ + class F1Score(Metric): + ''' + F1 Score @@ -178,18 +183,19 @@ class F1Score(Metric): - >>> metrics(logits,target) - >>> print(metrics.name(),metrics.value()) - ''' -- def __init__(self,thresh = 0.5, normalizate = True,task_type = 'binary',average = 'binary',search_thresh = False): -+ -+ def __init__(self, thresh=0.5, normalizate=True, task_type='binary', average='binary', search_thresh=False): - super(F1Score).__init__() -- assert task_type in ['binary','multiclass'] -- assert average in ['binary','micro', 'macro', 'samples', 'weighted'] -+ assert task_type in ['binary', 'multiclass'] -+ assert average in ['binary', 'micro', 'macro', 'samples', 'weighted'] - - self.thresh = thresh - self.task_type = task_type -- self.normalizate = normalizate -+ self.normalizate = normalizate - self.search_thresh = search_thresh - self.average = average - -- def thresh_search(self,y_prob): -+ def thresh_search(self, y_prob): - ''' - 对于f1评分的指标,一般我们需要对阈值进行调整,一般不会使用默认的0.5值,因此 - 这里我们队Thresh进行优化 + >>> metrics(logits,target) + >>> print(metrics.name(),metrics.value()) + ''' +- def __init__(self,thresh = 0.5, normalizate = True,task_type = 'binary',average = 'binary',search_thresh = False): ++ ++ def __init__(self, thresh=0.5, normalizate=True, task_type='binary', average='binary', search_thresh=False): + super(F1Score).__init__() +- assert task_type in ['binary','multiclass'] +- assert average in ['binary','micro', 'macro', 'samples', 'weighted'] ++ assert task_type in ['binary', 'multiclass'] ++ assert average in ['binary', 'micro', 'macro', 'samples', 'weighted'] + + self.thresh = thresh + self.task_type = task_type +- self.normalizate = normalizate ++ self.normalizate = normalizate + self.search_thresh = search_thresh + self.average = average + +- def thresh_search(self,y_prob): ++ def thresh_search(self, y_prob): + ''' + 对于f1评分的指标,一般我们需要对阈值进行调整,一般不会使用默认的0.5值,因此 + 这里我们队Thresh进行优化 @@ -203,9 +209,9 @@ class F1Score(Metric): - if score > best_score: - best_threshold = threshold - best_score = score -- return best_threshold,best_score -+ return best_threshold, best_score - -- def __call__(self,logits,target): -+ def __call__(self, logits, target): - ''' - 计算整个结果 - :return: + if score > best_score: + best_threshold = threshold + best_score = score +- return best_threshold,best_score ++ return best_threshold, best_score + +- def __call__(self,logits,target): ++ def __call__(self, logits, target): + ''' + 计算整个结果 + :return: @@ -220,10 +226,10 @@ class F1Score(Metric): - - if self.task_type == 'binary': - if self.thresh and self.search_thresh == False: -- self.y_pred = (y_prob > self.thresh ).astype(int) -+ self.y_pred = (y_prob > self.thresh).astype(int) - self.value() - else: -- thresh,f1 = self.thresh_search(y_prob = y_prob) -+ thresh, f1 = self.thresh_search(y_prob=y_prob) - print(f"Best thresh: {thresh:.4f} - F1 Score: {f1:.4f}") - - if self.task_type == 'multiclass': + + if self.task_type == 'binary': + if self.thresh and self.search_thresh == False: +- self.y_pred = (y_prob > self.thresh ).astype(int) ++ self.y_pred = (y_prob > self.thresh).astype(int) + self.value() + else: +- thresh,f1 = self.thresh_search(y_prob = y_prob) ++ thresh, f1 = self.thresh_search(y_prob=y_prob) + print(f"Best thresh: {thresh:.4f} - F1 Score: {f1:.4f}") + + if self.task_type == 'multiclass': @@ -247,11 +253,13 @@ class F1Score(Metric): - def name(self): - return 'f1' - -+ - class ClassReport(Metric): - ''' - class report - ''' -- def __init__(self,target_names = None): -+ -+ def __init__(self, target_names=None): - super(ClassReport).__init__() - self.target_names = target_names - + def name(self): + return 'f1' + ++ + class ClassReport(Metric): + ''' + class report + ''' +- def __init__(self,target_names = None): ++ ++ def __init__(self, target_names=None): + super(ClassReport).__init__() + self.target_names = target_names + @@ -263,10 +271,10 @@ class ClassReport(Metric): - ''' - 计算指标得分 - ''' -- score = classification_report(y_true = self.y_true, y_pred = self.y_pred, target_names=self.target_names) -+ score = classification_report(y_true=self.y_true, y_pred=self.y_pred, target_names=self.target_names) - print(f"\n\n classification report: {score}") - -- def __call__(self,logits,target): -+ def __call__(self, logits, target): - _, y_pred = torch.max(logits.data, 1) - self.y_pred = y_pred.cpu().numpy() - self.y_true = target.cpu().numpy() + ''' + 计算指标得分 + ''' +- score = classification_report(y_true = self.y_true, y_pred = self.y_pred, target_names=self.target_names) ++ score = classification_report(y_true=self.y_true, y_pred=self.y_pred, target_names=self.target_names) + print(f"\n\n classification report: {score}") + +- def __call__(self,logits,target): ++ def __call__(self, logits, target): + _, y_pred = torch.max(logits.data, 1) + self.y_pred = y_pred.cpu().numpy() + self.y_true = target.cpu().numpy() @@ -274,11 +282,13 @@ class ClassReport(Metric): - def name(self): - return "class_report" - -+ - class MultiLabelReport(Metric): - ''' - multi label report - ''' -- def __init__(self,id2label = None): -+ -+ def __init__(self, id2label=None): - super(MultiLabelReport).__init__() - self.id2label = id2label - + def name(self): + return "class_report" + ++ + class MultiLabelReport(Metric): + ''' + multi label report + ''' +- def __init__(self,id2label = None): ++ ++ def __init__(self, id2label=None): + super(MultiLabelReport).__init__() + self.id2label = id2label + @@ -286,8 +296,7 @@ class MultiLabelReport(Metric): - self.y_prob = 0 - self.y_true = 0 - -- def __call__(self,logits,target): -- -+ def __call__(self, logits, target): - self.y_prob = logits.sigmoid().data.cpu().detach().numpy() - self.y_true = target.cpu().numpy() - + self.y_prob = 0 + self.y_true = 0 + +- def __call__(self,logits,target): +- ++ def __call__(self, logits, target): + self.y_prob = logits.sigmoid().data.cpu().detach().numpy() + self.y_true = target.cpu().numpy() + @@ -304,12 +313,12 @@ class MultiLabelReport(Metric): - - - class LMAccuracy(Metric): -- def __init__(self,topK =1): -+ def __init__(self, topK=1): - super(LMAccuracy).__init__() - self.topK = topK - self.reset() - -- def __call__(self,logits,target): -+ def __call__(self, logits, target): - pred = torch.argmax(logits, 1) - active_acc = target.view(-1) != -1 - active_pred = pred[active_acc] + + + class LMAccuracy(Metric): +- def __init__(self,topK =1): ++ def __init__(self, topK=1): + super(LMAccuracy).__init__() + self.topK = topK + self.reset() + +- def __call__(self,logits,target): ++ def __call__(self, logits, target): + pred = torch.argmax(logits, 1) + active_acc = target.view(-1) != -1 + active_pred = pred[active_acc] @@ -328,5 +337,3 @@ class LMAccuracy(Metric): - - def name(self): - return 'accuracy' -- -- + + def name(self): + return 'accuracy' +- +- diff --git a/metrics/glue_compute_metrics.py b/metrics/glue_compute_metrics.py index dd9a7b2..7afb658 100644 --- a/metrics/glue_compute_metrics.py +++ b/metrics/glue_compute_metrics.py @@ -22,11 +22,13 @@ logger = logging.getLogger(__name__) - try: - from scipy.stats import pearsonr, spearmanr - from sklearn.metrics import matthews_corrcoef, f1_score -+ - _has_sklearn = True - except (AttributeError, ImportError) as e: - logger.warning("To use data.metrics please install scikit-learn. See https://scikit-learn.org/stable/index.html") - _has_sklearn = False - -+ - def simple_accuracy(preds, labels): - return (preds == labels).mean() - + try: + from scipy.stats import pearsonr, spearmanr + from sklearn.metrics import matthews_corrcoef, f1_score ++ + _has_sklearn = True + except (AttributeError, ImportError) as e: + logger.warning("To use data.metrics please install scikit-learn. See https://scikit-learn.org/stable/index.html") + _has_sklearn = False + ++ + def simple_accuracy(preds, labels): + return (preds == labels).mean() + @@ -40,6 +42,7 @@ def acc_and_f1(preds, labels): - "acc_and_f1": (acc + f1) / 2, - } - -+ - def pearson_and_spearman(preds, labels): - pearson_corr = pearsonr(preds, labels)[0] - spearman_corr = spearmanr(preds, labels)[0] + "acc_and_f1": (acc + f1) / 2, + } + ++ + def pearson_and_spearman(preds, labels): + pearson_corr = pearsonr(preds, labels)[0] + spearman_corr = spearmanr(preds, labels)[0] @@ -49,6 +52,7 @@ def pearson_and_spearman(preds, labels): - "corr": (pearson_corr + spearman_corr) / 2, - } - -+ - def compute_metrics(task_name, preds, labels): - assert len(preds) == len(labels) - if task_name == "cola": + "corr": (pearson_corr + spearman_corr) / 2, + } + ++ + def compute_metrics(task_name, preds, labels): + assert len(preds) == len(labels) + if task_name == "cola": diff --git a/model/configuration_albert.py b/model/configuration_albert.py index d8c8310..4968acb 100644 --- a/model/configuration_albert.py @@ -1182,127 +1182,127 @@ index 433db06..7c8dc1f 100644 --- a/model/modeling_albert_bright.py +++ b/model/modeling_albert_bright.py @@ -25,6 +25,8 @@ ALBERT_PRETRAINED_MODEL_ARCHIVE_MAP = { - 'albert-xlarge': "", - 'albert-xxlarge': "", - } -+ -+ - def load_tf_weights_in_albert(model, config, tf_checkpoint_path): - """ Load tf checkpoints in a pytorch model. - """ + 'albert-xlarge': "", + 'albert-xxlarge': "", + } ++ ++ + def load_tf_weights_in_albert(model, config, tf_checkpoint_path): + """ Load tf checkpoints in a pytorch model. + """ @@ -93,10 +95,14 @@ def load_tf_weights_in_albert(model, config, tf_checkpoint_path): - pointer.data = torch.from_numpy(array) - return model - -+ - AlbertLayerNorm = torch.nn.LayerNorm -+ -+ - class AlbertEmbeddings(nn.Module): - """Construct the embeddings from word, position and token_type embeddings. - """ -+ - def __init__(self, config): - super(AlbertEmbeddings, self).__init__() - self.word_embeddings = nn.Embedding(config.vocab_size, config.embedding_size, padding_idx=0) + pointer.data = torch.from_numpy(array) + return model + ++ + AlbertLayerNorm = torch.nn.LayerNorm ++ ++ + class AlbertEmbeddings(nn.Module): + """Construct the embeddings from word, position and token_type embeddings. + """ ++ + def __init__(self, config): + super(AlbertEmbeddings, self).__init__() + self.word_embeddings = nn.Embedding(config.vocab_size, config.embedding_size, padding_idx=0) @@ -108,7 +114,7 @@ class AlbertEmbeddings(nn.Module): - - # self.LayerNorm is not snake-cased to stick with TensorFlow model variable name and be able to load - # any TensorFlow checkpoint file -- self.LayerNorm =AlbertLayerNorm(config.hidden_size, eps=config.layer_norm_eps) -+ self.LayerNorm = AlbertLayerNorm(config.hidden_size, eps=config.layer_norm_eps) - self.dropout = nn.Dropout(config.hidden_dropout_prob) - - def forward(self, input_ids, token_type_ids=None, position_ids=None): + + # self.LayerNorm is not snake-cased to stick with TensorFlow model variable name and be able to load + # any TensorFlow checkpoint file +- self.LayerNorm =AlbertLayerNorm(config.hidden_size, eps=config.layer_norm_eps) ++ self.LayerNorm = AlbertLayerNorm(config.hidden_size, eps=config.layer_norm_eps) + self.dropout = nn.Dropout(config.hidden_dropout_prob) + + def forward(self, input_ids, token_type_ids=None, position_ids=None): @@ -130,6 +136,7 @@ class AlbertEmbeddings(nn.Module): - embeddings = self.dropout(embeddings) - return embeddings - -+ - class AlbertSelfOutput(nn.Module): - def __init__(self, config): - super(AlbertSelfOutput, self).__init__() + embeddings = self.dropout(embeddings) + return embeddings + ++ + class AlbertSelfOutput(nn.Module): + def __init__(self, config): + super(AlbertSelfOutput, self).__init__() @@ -182,6 +189,7 @@ class AlbertAttention(nn.Module): - outputs = (attention_output,) + self_outputs[1:] # add attentions if we output them - return outputs - -+ - class AlbertOutput(nn.Module): - def __init__(self, config): - super(AlbertOutput, self).__init__() + outputs = (attention_output,) + self_outputs[1:] # add attentions if we output them + return outputs + ++ + class AlbertOutput(nn.Module): + def __init__(self, config): + super(AlbertOutput, self).__init__() @@ -196,6 +204,7 @@ class AlbertOutput(nn.Module): - hidden_states = self.LayerNorm(hidden_states + input_tensor) - return hidden_states - -+ - class BertLayer(nn.Module): - def __init__(self, config): - super(BertLayer, self).__init__() + hidden_states = self.LayerNorm(hidden_states + input_tensor) + return hidden_states + ++ + class BertLayer(nn.Module): + def __init__(self, config): + super(BertLayer, self).__init__() @@ -213,6 +222,7 @@ class BertLayer(nn.Module): - outputs = (layer_output,) + attention_outputs[1:] # add attentions if we output them - return outputs - -+ - class AlbertEncoder(nn.Module): - def __init__(self, config): - super(AlbertEncoder, self).__init__() + outputs = (layer_output,) + attention_outputs[1:] # add attentions if we output them + return outputs + ++ + class AlbertEncoder(nn.Module): + def __init__(self, config): + super(AlbertEncoder, self).__init__() @@ -243,6 +253,7 @@ class AlbertEncoder(nn.Module): - outputs = outputs + (all_attentions,) - return outputs # last-layer hidden state, (all hidden states), (all attentions) - -+ - class AlbertLMPredictionHead(nn.Module): - def __init__(self, config): - super(AlbertLMPredictionHead, self).__init__() + outputs = outputs + (all_attentions,) + return outputs # last-layer hidden state, (all hidden states), (all attentions) + ++ + class AlbertLMPredictionHead(nn.Module): + def __init__(self, config): + super(AlbertLMPredictionHead, self).__init__() @@ -261,6 +272,7 @@ class AlbertLMPredictionHead(nn.Module): - hidden_states = self.decoder(hidden_states) + self.bias - return hidden_states - -+ - class AlbertOnlyMLMHead(nn.Module): - def __init__(self, config): - super(AlbertOnlyMLMHead, self).__init__() + hidden_states = self.decoder(hidden_states) + self.bias + return hidden_states + ++ + class AlbertOnlyMLMHead(nn.Module): + def __init__(self, config): + super(AlbertOnlyMLMHead, self).__init__() @@ -270,6 +282,7 @@ class AlbertOnlyMLMHead(nn.Module): - prediction_scores = self.predictions(sequence_output) - return prediction_scores - -+ - class AlbertOnlyNSPHead(nn.Module): - def __init__(self, config): - super(AlbertOnlyNSPHead, self).__init__() + prediction_scores = self.predictions(sequence_output) + return prediction_scores + ++ + class AlbertOnlyNSPHead(nn.Module): + def __init__(self, config): + super(AlbertOnlyNSPHead, self).__init__() @@ -279,6 +292,7 @@ class AlbertOnlyNSPHead(nn.Module): - seq_relationship_score = self.seq_relationship(pooled_output) - return seq_relationship_score - -+ - class AlbertPreTrainingHeads(nn.Module): - def __init__(self, config): - super(AlbertPreTrainingHeads, self).__init__() + seq_relationship_score = self.seq_relationship(pooled_output) + return seq_relationship_score + ++ + class AlbertPreTrainingHeads(nn.Module): + def __init__(self, config): + super(AlbertPreTrainingHeads, self).__init__() @@ -290,6 +304,7 @@ class AlbertPreTrainingHeads(nn.Module): - seq_relationship_score = self.seq_relationship(pooled_output) - return prediction_scores, seq_relationship_score - -+ - class AlbertPreTrainedModel(PreTrainedModel): - """ An abstract class to handle weights initialization and - a simple interface for dowloading and loading pretrained models. + seq_relationship_score = self.seq_relationship(pooled_output) + return prediction_scores, seq_relationship_score + ++ + class AlbertPreTrainedModel(PreTrainedModel): + """ An abstract class to handle weights initialization and + a simple interface for dowloading and loading pretrained models. @@ -311,6 +326,7 @@ class AlbertPreTrainedModel(PreTrainedModel): - if isinstance(module, nn.Linear) and module.bias is not None: - module.bias.data.zero_() - -+ - BERT_START_DOCSTRING = r""" The BERT model was proposed in - `BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding`_ - by Jacob Devlin, Ming-Wei Chang, Kenton Lee and Kristina Toutanova. It's a bidirectional transformer + if isinstance(module, nn.Linear) and module.bias is not None: + module.bias.data.zero_() + ++ + BERT_START_DOCSTRING = r""" The BERT model was proposed in + `BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding`_ + by Jacob Devlin, Ming-Wei Chang, Kenton Lee and Kristina Toutanova. It's a bidirectional transformer @@ -535,7 +551,7 @@ class AlbertForPreTraining(AlbertPreTrainedModel): - Export to TorchScript can't handle parameter sharing so we are cloning them instead. - """ - self._tie_or_clone_weights(self.cls.predictions.decoder, -- self.bert.embeddings.word_embeddings) -+ self.bert.embeddings.word_embeddings) - - def forward(self, input_ids, attention_mask=None, token_type_ids=None, position_ids=None, head_mask=None, - masked_lm_labels=None, next_sentence_label=None): + Export to TorchScript can't handle parameter sharing so we are cloning them instead. + """ + self._tie_or_clone_weights(self.cls.predictions.decoder, +- self.bert.embeddings.word_embeddings) ++ self.bert.embeddings.word_embeddings) + + def forward(self, input_ids, attention_mask=None, token_type_ids=None, position_ids=None, head_mask=None, + masked_lm_labels=None, next_sentence_label=None): diff --git a/model/modeling_bert.py b/model/modeling_bert.py index fecf1e4..1b593c6 100644 --- a/model/modeling_bert.py @@ -2886,164 +2886,164 @@ index bd4cd9f..ec8e30f 100644 --- a/tools/common.py +++ b/tools/common.py @@ -8,16 +8,19 @@ import torch.nn as nn - from collections import OrderedDict - from pathlib import Path - import logging -+from threading import Lock - -+lock = Lock() - logger = logging.getLogger() - -+ - def init_logger(log_file=None, log_file_level=logging.NOTSET): - ''' - Example: - >>> init_logger(log_file) - >>> logger.info("abc'") - ''' -- if isinstance(log_file,Path): -+ if isinstance(log_file, Path): - log_file = str(log_file) - - log_format = logging.Formatter(fmt='%(asctime)s - %(levelname)s - %(name)s - %(message)s', + from collections import OrderedDict + from pathlib import Path + import logging ++from threading import Lock + ++lock = Lock() + logger = logging.getLogger() + ++ + def init_logger(log_file=None, log_file_level=logging.NOTSET): + ''' + Example: + >>> init_logger(log_file) + >>> logger.info("abc'") + ''' +- if isinstance(log_file,Path): ++ if isinstance(log_file, Path): + log_file = str(log_file) + + log_format = logging.Formatter(fmt='%(asctime)s - %(levelname)s - %(name)s - %(message)s', @@ -34,6 +37,7 @@ def init_logger(log_file=None, log_file_level=logging.NOTSET): - logger.addHandler(file_handler) - return logger - -+ - def seed_everything(seed=1029): - ''' - 设置整个开发环境的seed + logger.addHandler(file_handler) + return logger + ++ + def seed_everything(seed=1029): + ''' + 设置整个开发环境的seed @@ -114,7 +118,7 @@ def restore_checkpoint(resume_path, model=None): - model.module.load_state_dict(states) - else: - model.load_state_dict(states) -- return [model,best,start_epoch] -+ return [model, best, start_epoch] - - - def save_pickle(data, file_path): + model.module.load_state_dict(states) + else: + model.load_state_dict(states) +- return [model,best,start_epoch] ++ return [model, best, start_epoch] + + + def save_pickle(data, file_path): @@ -172,6 +176,7 @@ def load_json(file_path): - data = json.load(f) - return data - -+ - def save_model(model, model_path): - """ 存储不含有显卡信息的state_dict或model - :param model: + data = json.load(f) + return data + ++ + def save_model(model, model_path): + """ 存储不含有显卡信息的state_dict或model + :param model: @@ -188,6 +193,7 @@ def save_model(model, model_path): - state_dict[key] = state_dict[key].cpu() - torch.save(state_dict, model_path) - -+ - def load_model(model, model_path): - ''' - 加载模型 + state_dict[key] = state_dict[key].cpu() + torch.save(state_dict, model_path) + ++ + def load_model(model, model_path): + ''' + 加载模型 diff --git a/tools/fps_counter.py b/tools/fps_counter.py new file mode 100644 index 0000000..4f637f3 --- /dev/null +++ b/tools/fps_counter.py @@ -0,0 +1,99 @@ -+# Copyright 2021 Huawei Technologies Co., Ltd -+# -+# 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 time -+from threading import Lock -+ -+ -+class FpsCounter: -+ """ -+how to use -+ -+fps=FpsCounter() -+fps.begin() -+code -+fps.end() -+print(fps.fps()) -+ -+ """ -+ def __init__(self): -+ self.step_sum = 0 -+ self.time_sum = 0 -+ self.t1 = 0 -+ self.on = False -+ -+ def begin(self): -+ assert self.on == False, "didnot end last time" -+ self.on = True -+ self.t1 = time.time_ns() -+ -+ def end(self): -+ t2 = time.time_ns() -+ assert self.on == True, "didnot begin" -+ self.time_sum += t2 - self.t1 -+ self.step_sum += 1 -+ self.on = False -+ -+ def reset(self): -+ self.step_sum = 0 -+ self.time_sum = 0 -+ self.t1 = 0 -+ self.on = False -+ -+ def fps(self, batch=1, n_device=1): -+ if self.step_sum == 0: return 0 -+ time_avg = self.time_sum / 1e9 / self.step_sum -+ return batch * n_device / time_avg -+ -+ -+class FpsCounter2: -+ def __init__(self, node_num=0): -+ self.node_num = node_num -+ self.lock = Lock() -+ self.step_sum = [0 for i in range(node_num)] -+ self.time_sum = [0 for i in range(node_num)] -+ self.t1 = [0 for i in range(node_num)] -+ self.on = [False for i in range(node_num)] -+ -+ def begin(self, node_idx=0): -+ assert self.on[node_idx] == False, "didnot end last time" -+ self.lock.acquire() -+ self.on[node_idx] = True -+ self.t1[node_idx] = time.time_ns() -+ self.lock.release() -+ -+ def end(self, node_idx=0): -+ t2 = time.time_ns() -+ assert self.on[node_idx] == True, "didnot begin" -+ self.lock.acquire() -+ self.time_sum[node_idx] += t2 - self.t1[node_idx] -+ self.step_sum[node_idx] += 1 -+ self.on[node_idx] = False -+ self.lock.release() -+ -+ def reset(self, node_idx=0): -+ self.lock.acquire() -+ self.step_sum[node_idx] = 0 -+ self.time_sum[node_idx] = 0 -+ self.t1[node_idx] = 0 -+ self.on[node_idx] = False -+ self.lock.release() -+ -+ def fps(self, batch=1, n_device=1, world_size=0): -+ fps = 0 -+ for i in range(world_size): -+ if self.step_sum[i] == 0: continue -+ time_avg = self.time_sum[i] / 1e9 / self.step_sum[i] -+ fps += batch * n_device / time_avg -+ return fps ++# Copyright 2021 Huawei Technologies Co., Ltd ++# ++# 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 time ++from threading import Lock ++ ++ ++class FpsCounter: ++ """ ++how to use ++ ++fps=FpsCounter() ++fps.begin() ++code ++fps.end() ++print(fps.fps()) ++ ++ """ ++ def __init__(self): ++ self.step_sum = 0 ++ self.time_sum = 0 ++ self.t1 = 0 ++ self.on = False ++ ++ def begin(self): ++ assert self.on == False, "didnot end last time" ++ self.on = True ++ self.t1 = time.time_ns() ++ ++ def end(self): ++ t2 = time.time_ns() ++ assert self.on == True, "didnot begin" ++ self.time_sum += t2 - self.t1 ++ self.step_sum += 1 ++ self.on = False ++ ++ def reset(self): ++ self.step_sum = 0 ++ self.time_sum = 0 ++ self.t1 = 0 ++ self.on = False ++ ++ def fps(self, batch=1, n_device=1): ++ if self.step_sum == 0: return 0 ++ time_avg = self.time_sum / 1e9 / self.step_sum ++ return batch * n_device / time_avg ++ ++ ++class FpsCounter2: ++ def __init__(self, node_num=0): ++ self.node_num = node_num ++ self.lock = Lock() ++ self.step_sum = [0 for i in range(node_num)] ++ self.time_sum = [0 for i in range(node_num)] ++ self.t1 = [0 for i in range(node_num)] ++ self.on = [False for i in range(node_num)] ++ ++ def begin(self, node_idx=0): ++ assert self.on[node_idx] == False, "didnot end last time" ++ self.lock.acquire() ++ self.on[node_idx] = True ++ self.t1[node_idx] = time.time_ns() ++ self.lock.release() ++ ++ def end(self, node_idx=0): ++ t2 = time.time_ns() ++ assert self.on[node_idx] == True, "didnot begin" ++ self.lock.acquire() ++ self.time_sum[node_idx] += t2 - self.t1[node_idx] ++ self.step_sum[node_idx] += 1 ++ self.on[node_idx] = False ++ self.lock.release() ++ ++ def reset(self, node_idx=0): ++ self.lock.acquire() ++ self.step_sum[node_idx] = 0 ++ self.time_sum[node_idx] = 0 ++ self.t1[node_idx] = 0 ++ self.on[node_idx] = False ++ self.lock.release() ++ ++ def fps(self, batch=1, n_device=1, world_size=0): ++ fps = 0 ++ for i in range(world_size): ++ if self.step_sum[i] == 0: continue ++ time_avg = self.time_sum[i] / 1e9 / self.step_sum[i] ++ fps += batch * n_device / time_avg ++ return fps -- 2.17.1 diff --git a/ACL_PyTorch/contrib/nlp/tinybert/TinyBERT_get_info.py b/ACL_PyTorch/contrib/nlp/tinybert/TinyBERT_get_info.py index c685f28e3b..0846eb47f4 100644 --- a/ACL_PyTorch/contrib/nlp/tinybert/TinyBERT_get_info.py +++ b/ACL_PyTorch/contrib/nlp/tinybert/TinyBERT_get_info.py @@ -1,47 +1,47 @@ -# coding=utf-8 -# Copyright (c) 2019 NVIDIA CORPORATION. All rights reserved. -# Copyright 2018 The Google AI Language Team Authors and The HugginFace Inc. team. -# 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. - -"""Run TinyBERT on SST-2.""" -import argparse - -def main(): - """output:info file""" - parser = argparse.ArgumentParser() - parser.add_argument("--batch_size", - default=1, - type=int, - required=True) - parser.add_argument("--output_path", - default='./bert_bin/', - type=str, - required=True, - help='The output dir of info file.') - args = parser.parse_args() - test_num = 872 - base_path = args.output_path - with open('./TinyBERT.info', 'w') as f: - for i in range(test_num): - ids_name = base_path + 'input_ids_{}.bin'.format(i) - segment_name = base_path + 'segment_ids_{}.bin'.format(i) - mask_name = base_path + 'input_mask_{}.bin'.format(i) - f.write(str(i) + ' ' + ids_name) - f.write('\n') - f.write(str(i) + ' ' + segment_name) - f.write('\n') - f.write(str(i) + ' ' + mask_name) - f.write('\n') - -if __name__ == "__main__": +# coding=utf-8 +# Copyright (c) 2019 NVIDIA CORPORATION. All rights reserved. +# Copyright 2018 The Google AI Language Team Authors and The HugginFace Inc. team. +# 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. + +"""Run TinyBERT on SST-2.""" +import argparse + +def main(): + """output:info file""" + parser = argparse.ArgumentParser() + parser.add_argument("--batch_size", + default=1, + type=int, + required=True) + parser.add_argument("--output_path", + default='./bert_bin/', + type=str, + required=True, + help='The output dir of info file.') + args = parser.parse_args() + test_num = 872 + base_path = args.output_path + with open('./TinyBERT.info', 'w') as f: + for i in range(test_num): + ids_name = base_path + 'input_ids_{}.bin'.format(i) + segment_name = base_path + 'segment_ids_{}.bin'.format(i) + mask_name = base_path + 'input_mask_{}.bin'.format(i) + f.write(str(i) + ' ' + ids_name) + f.write('\n') + f.write(str(i) + ' ' + segment_name) + f.write('\n') + f.write(str(i) + ' ' + mask_name) + f.write('\n') + +if __name__ == "__main__": main() \ No newline at end of file diff --git a/ACL_PyTorch/contrib/nlp/tinybert/TinyBERT_postprocess_data.py b/ACL_PyTorch/contrib/nlp/tinybert/TinyBERT_postprocess_data.py index 117bb7ea24..bff0fbfbc8 100644 --- a/ACL_PyTorch/contrib/nlp/tinybert/TinyBERT_postprocess_data.py +++ b/ACL_PyTorch/contrib/nlp/tinybert/TinyBERT_postprocess_data.py @@ -1,279 +1,279 @@ -# coding=utf-8 -# Copyright (c) 2019 NVIDIA CORPORATION. All rights reserved. -# Copyright 2018 The Google AI Language Team Authors and The HugginFace Inc. team. -# 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. - -"""Run TinyBERT on SST-2.""" - -from __future__ import absolute_import, division, print_function -import argparse -import os -import sys -import csv -import numpy as np -import io -from transformer.tokenization import BertTokenizer -import torch - - -class InputExample(object): - """A single training/test example for simple sequence classification.""" - - def __init__(self, guid, text_a, text_b=None, label=None): - """Constructs a InputExample. - - Args: - guid: Unique id for the example. - text_a: string. The untokenized text of the first sequence. For single - sequence tasks, only this sequence must be specified. - text_b: (Optional) string. The untokenized text of the second sequence. - Only must be specified for sequence pair tasks. - label: (Optional) string. The label of the example. This should be - specified for train and dev examples, but not for test examples. - """ - self.guid = guid - self.text_a = text_a - self.text_b = text_b - self.label = label - - -class InputFeatures(object): - """A single set of features of data.""" - - def __init__(self, input_ids, input_mask, segment_ids, label_id, seq_length=None): - self.input_ids = input_ids - self.input_mask = input_mask - self.segment_ids = segment_ids - self.seq_length = seq_length - self.label_id = label_id - - -class DataProcessor(object): - """Base class for data converters for sequence classification data sets.""" - - def get_train_examples(self, data_dir): - """Gets a collection of `InputExample`s for the train set.""" - raise NotImplementedError() - - def get_dev_examples(self, data_dir): - """Gets a collection of `InputExample`s for the dev set.""" - raise NotImplementedError() - - def get_labels(self): - """Gets the list of labels for this data set.""" - raise NotImplementedError() - - @classmethod - def _read_tsv(cls, input_file, quotechar=None): - """Reads a tab separated value file.""" - with io.open(input_file, "r", encoding="utf-8") as f: - reader = csv.reader(f, delimiter="\t", quotechar=quotechar) - lines = [] - for line in reader: - if sys.version_info[0] == 2: - line = list(unicode(cell, 'utf-8') for cell in line) - lines.append(line) - return lines - - -class Sst2Processor(DataProcessor): - """Processor for the SST-2 data set (GLUE version).""" - - def get_train_examples(self, data_dir): - """See base class.""" - return self._create_examples( - self._read_tsv(os.path.join(data_dir, "train.tsv")), "train") - - def get_dev_examples(self, data_dir): - """See base class.""" - return self._create_examples( - self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev") - - def get_aug_examples(self, data_dir): - """get the augmented examples""" - return self._create_examples( - self._read_tsv(os.path.join(data_dir, "train_aug.tsv")), "aug") - - def get_labels(self): - """See base class.""" - return ["0", "1"] - - def _create_examples(self, lines, set_type): - """Creates examples for the training and dev sets.""" - examples = [] - for (i, line) in enumerate(lines): - if i == 0: - continue - guid = "%s-%s" % (set_type, i) - text_a = line[0] - label = line[1] - examples.append( - InputExample(guid=guid, text_a=text_a, text_b=None, label=label)) - return examples - - -def _truncate_seq_pair(tokens_a, tokens_b, max_length): - """Truncates a sequence pair in place to the maximum length.""" - while True: - total_length = len(tokens_a) + len(tokens_b) - if total_length <= max_length: - break - if len(tokens_a) > len(tokens_b): - tokens_a.pop() - else: - tokens_b.pop() - - -def convert_examples_to_features(examples, label_list, max_seq_length, - tokenizer, output_mode): - """Loads a data file into a list of `InputBatch`s.""" - - label_map = {label: i for i, label in enumerate(label_list)} - - features = [] - for (ex_index, example) in enumerate(examples): - - tokens_a = tokenizer.tokenize(example.text_a) - - tokens_b = None - if example.text_b: - tokens_b = tokenizer.tokenize(example.text_b) - _truncate_seq_pair(tokens_a, tokens_b, max_seq_length - 3) - else: - if len(tokens_a) > max_seq_length - 2: - tokens_a = tokens_a[:(max_seq_length - 2)] - - tokens = ["[CLS]"] + tokens_a + ["[SEP]"] - segment_ids = [0] * len(tokens) - - if tokens_b: - tokens += tokens_b + ["[SEP]"] - segment_ids += [1] * (len(tokens_b) + 1) - - input_ids = tokenizer.convert_tokens_to_ids(tokens) - input_mask = [1] * len(input_ids) - seq_length = len(input_ids) - - padding = [0] * (max_seq_length - len(input_ids)) - input_ids += padding - input_mask += padding - segment_ids += padding - - assert len(input_ids) == max_seq_length - assert len(input_mask) == max_seq_length - assert len(segment_ids) == max_seq_length - - if output_mode == "classification": - label_id = label_map[example.label] - elif output_mode == "regression": - label_id = float(example.label) - else: - raise KeyError(output_mode) - - features.append( - InputFeatures(input_ids=input_ids, - input_mask=input_mask, - segment_ids=segment_ids, - label_id=label_id, - seq_length=seq_length)) - return features - - -def get_label_ids(features): - """get the label id""" - return torch.tensor([f.label_id for f in features], dtype=torch.long) - - -def simple_accuracy(preds, labels): - """calculate the accuracy""" - return (preds == labels).mean() - - -def bin2predlabel(test_num, args): - """(adapt to benchmark inference)change the bin files into logits""" - logit1 = [] - logit2 = [] - for i in range(test_num): - n1, n2 = np.fromfile('{}/Bert_{}_1.bin'.format(args.result_dir, i), dtype='float32') - logit1.append(n1) - logit2.append(n2) - logit = np.concatenate((np.array(logit1).reshape(1, -1), np.array(logit2).reshape(1, -1)), axis = 0) - pred_label = np.argmax(logit, axis = 0) - return pred_label - - -def txt2predlabel(test_num, args): - """(adapt to msame inference):change the txt files into logits""" - logit1 = [] - logit2 = [] - for i in range(test_num): - txtname = "input" + str(i) + "_output_0.txt" - dir = os.path.join(args.result_dir, txtname) - with open(dir, "r") as f: - line = f.readline() - n1, n2 = [float(i) for i in line.split()] - logit1.append(n1) - logit2.append(n2) - logit = np.concatenate((np.array(logit1).reshape(1, -1), np.array(logit2).reshape(1, -1)), axis = 0) - pred_label = np.argmax(logit, axis = 0) - return pred_label - - -def main(): - """postprocess the data and calculate the accuracy""" - parser = argparse.ArgumentParser() - parser.add_argument("--max_seq_length", - default=64, - type=int, - help="The maximum total input sequence length after WordPiece tokenization. \n" - "Sequences longer than this will be truncated, and sequences shorter \n" - "than this will be padded.") - parser.add_argument("--data_dir", - default=None, - type=str, - required=True, - help="The input data dir. Should contain the .tsv files (or other data files) for the task.") - parser.add_argument("--result_dir", - default=None, - type=str, - required=True, - help="NPU benchmark infer result path") - parser.add_argument("--model", - default=None, - type=str, - required=True, - help="The student model dir.") - parser.add_argument("--do_lower_case", - action='store_true', - help="Set this flag if you are using an uncased model.") - parser.add_argument("--inference_tool", type = str, - help = "inference tool:benchmark or msame") - args = parser.parse_args() - test_num = 872 - processor = Sst2Processor() - tokenizer = BertTokenizer.from_pretrained(args.model, do_lower_case=args.do_lower_case) - eval_examples = processor.get_dev_examples(args.data_dir) - label_list = ["0", "1"] - eval_features = convert_examples_to_features(eval_examples, label_list, args.max_seq_length, tokenizer, - output_mode="classification") - #data processing - eval_labels = get_label_ids(eval_features).numpy() - if args.inference_tool == "benchmark": - pred_labels = bin2predlabel(test_num, args) - elif args.inference_tool == "msame": - pred_labels = txt2predlabel(test_num, args) - result = simple_accuracy(pred_labels, eval_labels) - print("acc:{}".format(result)) - -if __name__ == '__main__': +# coding=utf-8 +# Copyright (c) 2019 NVIDIA CORPORATION. All rights reserved. +# Copyright 2018 The Google AI Language Team Authors and The HugginFace Inc. team. +# 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. + +"""Run TinyBERT on SST-2.""" + +from __future__ import absolute_import, division, print_function +import argparse +import os +import sys +import csv +import numpy as np +import io +from transformer.tokenization import BertTokenizer +import torch + + +class InputExample(object): + """A single training/test example for simple sequence classification.""" + + def __init__(self, guid, text_a, text_b=None, label=None): + """Constructs a InputExample. + + Args: + guid: Unique id for the example. + text_a: string. The untokenized text of the first sequence. For single + sequence tasks, only this sequence must be specified. + text_b: (Optional) string. The untokenized text of the second sequence. + Only must be specified for sequence pair tasks. + label: (Optional) string. The label of the example. This should be + specified for train and dev examples, but not for test examples. + """ + self.guid = guid + self.text_a = text_a + self.text_b = text_b + self.label = label + + +class InputFeatures(object): + """A single set of features of data.""" + + def __init__(self, input_ids, input_mask, segment_ids, label_id, seq_length=None): + self.input_ids = input_ids + self.input_mask = input_mask + self.segment_ids = segment_ids + self.seq_length = seq_length + self.label_id = label_id + + +class DataProcessor(object): + """Base class for data converters for sequence classification data sets.""" + + def get_train_examples(self, data_dir): + """Gets a collection of `InputExample`s for the train set.""" + raise NotImplementedError() + + def get_dev_examples(self, data_dir): + """Gets a collection of `InputExample`s for the dev set.""" + raise NotImplementedError() + + def get_labels(self): + """Gets the list of labels for this data set.""" + raise NotImplementedError() + + @classmethod + def _read_tsv(cls, input_file, quotechar=None): + """Reads a tab separated value file.""" + with io.open(input_file, "r", encoding="utf-8") as f: + reader = csv.reader(f, delimiter="\t", quotechar=quotechar) + lines = [] + for line in reader: + if sys.version_info[0] == 2: + line = list(unicode(cell, 'utf-8') for cell in line) + lines.append(line) + return lines + + +class Sst2Processor(DataProcessor): + """Processor for the SST-2 data set (GLUE version).""" + + def get_train_examples(self, data_dir): + """See base class.""" + return self._create_examples( + self._read_tsv(os.path.join(data_dir, "train.tsv")), "train") + + def get_dev_examples(self, data_dir): + """See base class.""" + return self._create_examples( + self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev") + + def get_aug_examples(self, data_dir): + """get the augmented examples""" + return self._create_examples( + self._read_tsv(os.path.join(data_dir, "train_aug.tsv")), "aug") + + def get_labels(self): + """See base class.""" + return ["0", "1"] + + def _create_examples(self, lines, set_type): + """Creates examples for the training and dev sets.""" + examples = [] + for (i, line) in enumerate(lines): + if i == 0: + continue + guid = "%s-%s" % (set_type, i) + text_a = line[0] + label = line[1] + examples.append( + InputExample(guid=guid, text_a=text_a, text_b=None, label=label)) + return examples + + +def _truncate_seq_pair(tokens_a, tokens_b, max_length): + """Truncates a sequence pair in place to the maximum length.""" + while True: + total_length = len(tokens_a) + len(tokens_b) + if total_length <= max_length: + break + if len(tokens_a) > len(tokens_b): + tokens_a.pop() + else: + tokens_b.pop() + + +def convert_examples_to_features(examples, label_list, max_seq_length, + tokenizer, output_mode): + """Loads a data file into a list of `InputBatch`s.""" + + label_map = {label: i for i, label in enumerate(label_list)} + + features = [] + for (ex_index, example) in enumerate(examples): + + tokens_a = tokenizer.tokenize(example.text_a) + + tokens_b = None + if example.text_b: + tokens_b = tokenizer.tokenize(example.text_b) + _truncate_seq_pair(tokens_a, tokens_b, max_seq_length - 3) + else: + if len(tokens_a) > max_seq_length - 2: + tokens_a = tokens_a[:(max_seq_length - 2)] + + tokens = ["[CLS]"] + tokens_a + ["[SEP]"] + segment_ids = [0] * len(tokens) + + if tokens_b: + tokens += tokens_b + ["[SEP]"] + segment_ids += [1] * (len(tokens_b) + 1) + + input_ids = tokenizer.convert_tokens_to_ids(tokens) + input_mask = [1] * len(input_ids) + seq_length = len(input_ids) + + padding = [0] * (max_seq_length - len(input_ids)) + input_ids += padding + input_mask += padding + segment_ids += padding + + assert len(input_ids) == max_seq_length + assert len(input_mask) == max_seq_length + assert len(segment_ids) == max_seq_length + + if output_mode == "classification": + label_id = label_map[example.label] + elif output_mode == "regression": + label_id = float(example.label) + else: + raise KeyError(output_mode) + + features.append( + InputFeatures(input_ids=input_ids, + input_mask=input_mask, + segment_ids=segment_ids, + label_id=label_id, + seq_length=seq_length)) + return features + + +def get_label_ids(features): + """get the label id""" + return torch.tensor([f.label_id for f in features], dtype=torch.long) + + +def simple_accuracy(preds, labels): + """calculate the accuracy""" + return (preds == labels).mean() + + +def bin2predlabel(test_num, args): + """(adapt to benchmark inference)change the bin files into logits""" + logit1 = [] + logit2 = [] + for i in range(test_num): + n1, n2 = np.fromfile('{}/Bert_{}_1.bin'.format(args.result_dir, i), dtype='float32') + logit1.append(n1) + logit2.append(n2) + logit = np.concatenate((np.array(logit1).reshape(1, -1), np.array(logit2).reshape(1, -1)), axis = 0) + pred_label = np.argmax(logit, axis = 0) + return pred_label + + +def txt2predlabel(test_num, args): + """(adapt to msame inference):change the txt files into logits""" + logit1 = [] + logit2 = [] + for i in range(test_num): + txtname = "input" + str(i) + "_output_0.txt" + dir = os.path.join(args.result_dir, txtname) + with open(dir, "r") as f: + line = f.readline() + n1, n2 = [float(i) for i in line.split()] + logit1.append(n1) + logit2.append(n2) + logit = np.concatenate((np.array(logit1).reshape(1, -1), np.array(logit2).reshape(1, -1)), axis = 0) + pred_label = np.argmax(logit, axis = 0) + return pred_label + + +def main(): + """postprocess the data and calculate the accuracy""" + parser = argparse.ArgumentParser() + parser.add_argument("--max_seq_length", + default=64, + type=int, + help="The maximum total input sequence length after WordPiece tokenization. \n" + "Sequences longer than this will be truncated, and sequences shorter \n" + "than this will be padded.") + parser.add_argument("--data_dir", + default=None, + type=str, + required=True, + help="The input data dir. Should contain the .tsv files (or other data files) for the task.") + parser.add_argument("--result_dir", + default=None, + type=str, + required=True, + help="NPU benchmark infer result path") + parser.add_argument("--model", + default=None, + type=str, + required=True, + help="The student model dir.") + parser.add_argument("--do_lower_case", + action='store_true', + help="Set this flag if you are using an uncased model.") + parser.add_argument("--inference_tool", type = str, + help = "inference tool:benchmark or msame") + args = parser.parse_args() + test_num = 872 + processor = Sst2Processor() + tokenizer = BertTokenizer.from_pretrained(args.model, do_lower_case=args.do_lower_case) + eval_examples = processor.get_dev_examples(args.data_dir) + label_list = ["0", "1"] + eval_features = convert_examples_to_features(eval_examples, label_list, args.max_seq_length, tokenizer, + output_mode="classification") + #data processing + eval_labels = get_label_ids(eval_features).numpy() + if args.inference_tool == "benchmark": + pred_labels = bin2predlabel(test_num, args) + elif args.inference_tool == "msame": + pred_labels = txt2predlabel(test_num, args) + result = simple_accuracy(pred_labels, eval_labels) + print("acc:{}".format(result)) + +if __name__ == '__main__': main() \ No newline at end of file diff --git a/ACL_PyTorch/contrib/nlp/tinybert/TinyBERT_preprocess_data.py b/ACL_PyTorch/contrib/nlp/tinybert/TinyBERT_preprocess_data.py index 5b90fd8710..2116c4ab3c 100644 --- a/ACL_PyTorch/contrib/nlp/tinybert/TinyBERT_preprocess_data.py +++ b/ACL_PyTorch/contrib/nlp/tinybert/TinyBERT_preprocess_data.py @@ -1,276 +1,276 @@ -# coding=utf-8 -# Copyright (c) 2019 NVIDIA CORPORATION. All rights reserved. -# Copyright 2018 The Google AI Language Team Authors and The HugginFace Inc. team. -# 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. - -"""Run TinyBERT on SST-2.""" - -from __future__ import absolute_import, division, print_function -import argparse -import os -import sys -import csv -import io -from transformer.tokenization import BertTokenizer -import torch -from torch.utils.data import (DataLoader, SequentialSampler, TensorDataset) - - -class InputExample(object): - """A single training/test example for simple sequence classification.""" - - def __init__(self, guid, text_a, text_b=None, label=None): - """Constructs a InputExample. - - Args: - guid: Unique id for the example. - text_a: string. The untokenized text of the first sequence. For single - sequence tasks, only this sequence must be specified. - text_b: (Optional) string. The untokenized text of the second sequence. - Only must be specified for sequence pair tasks. - label: (Optional) string. The label of the example. This should be - specified for train and dev examples, but not for test examples. - """ - self.guid = guid - self.text_a = text_a - self.text_b = text_b - self.label = label - - -class InputFeatures(object): - """A single set of features of data.""" - - def __init__(self, input_ids, input_mask, segment_ids, label_id, seq_length=None): - self.input_ids = input_ids - self.input_mask = input_mask - self.segment_ids = segment_ids - self.seq_length = seq_length - self.label_id = label_id - - -class DataProcessor(object): - """Base class for data converters for sequence classification data sets.""" - - def get_train_examples(self, data_dir): - """Gets a collection of `InputExample`s for the train set.""" - raise NotImplementedError() - - def get_dev_examples(self, data_dir): - """Gets a collection of `InputExample`s for the dev set.""" - raise NotImplementedError() - - def get_labels(self): - """Gets the list of labels for this data set.""" - raise NotImplementedError() - - @classmethod - def _read_tsv(cls, input_file, quotechar=None): - """Reads a tab separated value file.""" - with io.open(input_file, "r", encoding="utf-8") as f: - reader = csv.reader(f, delimiter="\t", quotechar=quotechar) - lines = [] - for line in reader: - if sys.version_info[0] == 2: - line = list(unicode(cell, 'utf-8') for cell in line) - lines.append(line) - return lines - - -class Sst2Processor(DataProcessor): - """Processor for the SST-2 data set (GLUE version).""" - - def get_train_examples(self, data_dir): - """See base class.""" - return self._create_examples( - self._read_tsv(os.path.join(data_dir, "train.tsv")), "train") - - def get_dev_examples(self, data_dir): - """See base class.""" - return self._create_examples( - self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev") - - def get_aug_examples(self, data_dir): - """get the augmented data""" - return self._create_examples( - self._read_tsv(os.path.join(data_dir, "train_aug.tsv")), "aug") - - def get_labels(self): - """See base class.""" - return ["0", "1"] - - def _create_examples(self, lines, set_type): - """Creates examples for the training and dev sets.""" - examples = [] - for (i, line) in enumerate(lines): - if i == 0: - continue - guid = "%s-%s" % (set_type, i) - text_a = line[0] - label = line[1] - examples.append( - InputExample(guid=guid, text_a=text_a, text_b=None, label=label)) - return examples - - -def _truncate_seq_pair(tokens_a, tokens_b, max_length): - """Truncates a sequence pair in place to the maximum length.""" - while True: - total_length = len(tokens_a) + len(tokens_b) - if total_length <= max_length: - break - if len(tokens_a) > len(tokens_b): - tokens_a.pop() - else: - tokens_b.pop() - - -def convert_examples_to_features(examples, label_list, max_seq_length, - tokenizer, output_mode): - """Loads a data file into a list of `InputBatch`s.""" - - label_map = {label: i for i, label in enumerate(label_list)} - - features = [] - for (ex_index, example) in enumerate(examples): - - tokens_a = tokenizer.tokenize(example.text_a) - - tokens_b = None - if example.text_b: - tokens_b = tokenizer.tokenize(example.text_b) - _truncate_seq_pair(tokens_a, tokens_b, max_seq_length - 3) - else: - if len(tokens_a) > max_seq_length - 2: - tokens_a = tokens_a[:(max_seq_length - 2)] - - tokens = ["[CLS]"] + tokens_a + ["[SEP]"] - segment_ids = [0] * len(tokens) - - if tokens_b: - tokens += tokens_b + ["[SEP]"] - segment_ids += [1] * (len(tokens_b) + 1) - - input_ids = tokenizer.convert_tokens_to_ids(tokens) - input_mask = [1] * len(input_ids) - seq_length = len(input_ids) - - padding = [0] * (max_seq_length - len(input_ids)) - input_ids += padding - input_mask += padding - segment_ids += padding - - assert len(input_ids) == max_seq_length - assert len(input_mask) == max_seq_length - assert len(segment_ids) == max_seq_length - - if output_mode == "classification": - label_id = label_map[example.label] - elif output_mode == "regression": - label_id = float(example.label) - else: - raise KeyError(output_mode) - - features.append( - InputFeatures(input_ids=input_ids, - input_mask=input_mask, - segment_ids=segment_ids, - label_id=label_id, - seq_length=seq_length)) - return features - - -def get_tensor_data(output_mode, features): - """get the data""" - if output_mode == "classification": - all_label_ids = torch.tensor([f.label_id for f in features], dtype=torch.long) - elif output_mode == "regression": - all_label_ids = torch.tensor([f.label_id for f in features], dtype=torch.float) - - all_seq_lengths = torch.tensor([f.seq_length for f in features], dtype=torch.long) - all_input_ids = torch.tensor([f.input_ids for f in features], dtype=torch.long) - all_input_mask = torch.tensor([f.input_mask for f in features], dtype=torch.long) - all_segment_ids = torch.tensor([f.segment_ids for f in features], dtype=torch.long) - tensor_data = TensorDataset(all_input_ids, all_input_mask, all_segment_ids, - all_label_ids, all_seq_lengths) - return tensor_data, all_label_ids - - -def data_main(): - """preprocess data""" - parser = argparse.ArgumentParser() - parser.add_argument("--model", - default=None, - type=str, - required=True, - help="The student model dir.") - parser.add_argument("--data_dir", - default=None, - type=str, - required=True, - help="The input data dir. Should contain the .tsv files (or other data files) for the task.") - parser.add_argument("--max_seq_length", - default=64, - type=int, - help="The maximum total input sequence length after WordPiece tokenization. \n" - "Sequences longer than this will be truncated, and sequences shorter \n" - "than this will be padded.") - parser.add_argument("--eval_batch_size", - default=1, - type=int, - help="Total batch size for eval.") - parser.add_argument("--do_lower_case", - action='store_true', - help="Set this flag if you are using an uncased model.") - parser.add_argument("--inference_tool", type = str, - help = "inference tool:benchmark or msame") - args = parser.parse_args() - processor = Sst2Processor() - tokenizer = BertTokenizer.from_pretrained(args.model, do_lower_case=args.do_lower_case) # for TinyBERT - - eval_examples = processor.get_dev_examples(args.data_dir) - label_list = ["0", "1"] - eval_features = convert_examples_to_features(eval_examples, label_list, args.max_seq_length, - tokenizer, output_mode = "classification") - - bin_path = "./bert_bin" - output_mode = 'classification' - eval_data, eval_labels = get_tensor_data(output_mode, eval_features) - print("eval_labels") - # Run prediction for full data - eval_sampler = SequentialSampler(eval_data) - eval_dataloader = DataLoader(eval_data, sampler=eval_sampler, drop_last = True, - batch_size = args.eval_batch_size, shuffle = False) - - if not os.path.exists(bin_path): - os.makedirs(bin_path) - i = -1 - for input_ids, input_mask, segment_ids, label_ids, seq_lengths in eval_dataloader: - i = i + 1 - print("[info] file", "===", i) - input_ids_np = input_ids.numpy() - input_mask_np = input_mask.numpy() - segment_ids_np = segment_ids.numpy() - if args.inference_tool == "msame": - path1 = bin_path + "/input_ids" - path2 = bin_path + "/segment_ids" - path3 = bin_path + "/input_mask" - input_ids_np.tofile(os.path.join(path1, "input" + str(i) + '.bin')) - segment_ids_np.tofile(os.path.join(path2, "input" + str(i) + '.bin')) - input_mask_np.tofile(os.path.join(path3, "input" + str(i) + '.bin')) - elif args.inference_tool == "benchmark": - input_ids_np.tofile(os.path.join(bin_path, "input_ids_" + str(i) + '.bin')) - segment_ids_np.tofile(os.path.join(bin_path, "segment_ids_" + str(i) + '.bin')) - input_mask_np.tofile(os.path.join(bin_path, "input_mask_" + str(i) + '.bin')) - -if __name__ == "__main__": +# coding=utf-8 +# Copyright (c) 2019 NVIDIA CORPORATION. All rights reserved. +# Copyright 2018 The Google AI Language Team Authors and The HugginFace Inc. team. +# 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. + +"""Run TinyBERT on SST-2.""" + +from __future__ import absolute_import, division, print_function +import argparse +import os +import sys +import csv +import io +from transformer.tokenization import BertTokenizer +import torch +from torch.utils.data import (DataLoader, SequentialSampler, TensorDataset) + + +class InputExample(object): + """A single training/test example for simple sequence classification.""" + + def __init__(self, guid, text_a, text_b=None, label=None): + """Constructs a InputExample. + + Args: + guid: Unique id for the example. + text_a: string. The untokenized text of the first sequence. For single + sequence tasks, only this sequence must be specified. + text_b: (Optional) string. The untokenized text of the second sequence. + Only must be specified for sequence pair tasks. + label: (Optional) string. The label of the example. This should be + specified for train and dev examples, but not for test examples. + """ + self.guid = guid + self.text_a = text_a + self.text_b = text_b + self.label = label + + +class InputFeatures(object): + """A single set of features of data.""" + + def __init__(self, input_ids, input_mask, segment_ids, label_id, seq_length=None): + self.input_ids = input_ids + self.input_mask = input_mask + self.segment_ids = segment_ids + self.seq_length = seq_length + self.label_id = label_id + + +class DataProcessor(object): + """Base class for data converters for sequence classification data sets.""" + + def get_train_examples(self, data_dir): + """Gets a collection of `InputExample`s for the train set.""" + raise NotImplementedError() + + def get_dev_examples(self, data_dir): + """Gets a collection of `InputExample`s for the dev set.""" + raise NotImplementedError() + + def get_labels(self): + """Gets the list of labels for this data set.""" + raise NotImplementedError() + + @classmethod + def _read_tsv(cls, input_file, quotechar=None): + """Reads a tab separated value file.""" + with io.open(input_file, "r", encoding="utf-8") as f: + reader = csv.reader(f, delimiter="\t", quotechar=quotechar) + lines = [] + for line in reader: + if sys.version_info[0] == 2: + line = list(unicode(cell, 'utf-8') for cell in line) + lines.append(line) + return lines + + +class Sst2Processor(DataProcessor): + """Processor for the SST-2 data set (GLUE version).""" + + def get_train_examples(self, data_dir): + """See base class.""" + return self._create_examples( + self._read_tsv(os.path.join(data_dir, "train.tsv")), "train") + + def get_dev_examples(self, data_dir): + """See base class.""" + return self._create_examples( + self._read_tsv(os.path.join(data_dir, "dev.tsv")), "dev") + + def get_aug_examples(self, data_dir): + """get the augmented data""" + return self._create_examples( + self._read_tsv(os.path.join(data_dir, "train_aug.tsv")), "aug") + + def get_labels(self): + """See base class.""" + return ["0", "1"] + + def _create_examples(self, lines, set_type): + """Creates examples for the training and dev sets.""" + examples = [] + for (i, line) in enumerate(lines): + if i == 0: + continue + guid = "%s-%s" % (set_type, i) + text_a = line[0] + label = line[1] + examples.append( + InputExample(guid=guid, text_a=text_a, text_b=None, label=label)) + return examples + + +def _truncate_seq_pair(tokens_a, tokens_b, max_length): + """Truncates a sequence pair in place to the maximum length.""" + while True: + total_length = len(tokens_a) + len(tokens_b) + if total_length <= max_length: + break + if len(tokens_a) > len(tokens_b): + tokens_a.pop() + else: + tokens_b.pop() + + +def convert_examples_to_features(examples, label_list, max_seq_length, + tokenizer, output_mode): + """Loads a data file into a list of `InputBatch`s.""" + + label_map = {label: i for i, label in enumerate(label_list)} + + features = [] + for (ex_index, example) in enumerate(examples): + + tokens_a = tokenizer.tokenize(example.text_a) + + tokens_b = None + if example.text_b: + tokens_b = tokenizer.tokenize(example.text_b) + _truncate_seq_pair(tokens_a, tokens_b, max_seq_length - 3) + else: + if len(tokens_a) > max_seq_length - 2: + tokens_a = tokens_a[:(max_seq_length - 2)] + + tokens = ["[CLS]"] + tokens_a + ["[SEP]"] + segment_ids = [0] * len(tokens) + + if tokens_b: + tokens += tokens_b + ["[SEP]"] + segment_ids += [1] * (len(tokens_b) + 1) + + input_ids = tokenizer.convert_tokens_to_ids(tokens) + input_mask = [1] * len(input_ids) + seq_length = len(input_ids) + + padding = [0] * (max_seq_length - len(input_ids)) + input_ids += padding + input_mask += padding + segment_ids += padding + + assert len(input_ids) == max_seq_length + assert len(input_mask) == max_seq_length + assert len(segment_ids) == max_seq_length + + if output_mode == "classification": + label_id = label_map[example.label] + elif output_mode == "regression": + label_id = float(example.label) + else: + raise KeyError(output_mode) + + features.append( + InputFeatures(input_ids=input_ids, + input_mask=input_mask, + segment_ids=segment_ids, + label_id=label_id, + seq_length=seq_length)) + return features + + +def get_tensor_data(output_mode, features): + """get the data""" + if output_mode == "classification": + all_label_ids = torch.tensor([f.label_id for f in features], dtype=torch.long) + elif output_mode == "regression": + all_label_ids = torch.tensor([f.label_id for f in features], dtype=torch.float) + + all_seq_lengths = torch.tensor([f.seq_length for f in features], dtype=torch.long) + all_input_ids = torch.tensor([f.input_ids for f in features], dtype=torch.long) + all_input_mask = torch.tensor([f.input_mask for f in features], dtype=torch.long) + all_segment_ids = torch.tensor([f.segment_ids for f in features], dtype=torch.long) + tensor_data = TensorDataset(all_input_ids, all_input_mask, all_segment_ids, + all_label_ids, all_seq_lengths) + return tensor_data, all_label_ids + + +def data_main(): + """preprocess data""" + parser = argparse.ArgumentParser() + parser.add_argument("--model", + default=None, + type=str, + required=True, + help="The student model dir.") + parser.add_argument("--data_dir", + default=None, + type=str, + required=True, + help="The input data dir. Should contain the .tsv files (or other data files) for the task.") + parser.add_argument("--max_seq_length", + default=64, + type=int, + help="The maximum total input sequence length after WordPiece tokenization. \n" + "Sequences longer than this will be truncated, and sequences shorter \n" + "than this will be padded.") + parser.add_argument("--eval_batch_size", + default=1, + type=int, + help="Total batch size for eval.") + parser.add_argument("--do_lower_case", + action='store_true', + help="Set this flag if you are using an uncased model.") + parser.add_argument("--inference_tool", type = str, + help = "inference tool:benchmark or msame") + args = parser.parse_args() + processor = Sst2Processor() + tokenizer = BertTokenizer.from_pretrained(args.model, do_lower_case=args.do_lower_case) # for TinyBERT + + eval_examples = processor.get_dev_examples(args.data_dir) + label_list = ["0", "1"] + eval_features = convert_examples_to_features(eval_examples, label_list, args.max_seq_length, + tokenizer, output_mode = "classification") + + bin_path = "./bert_bin" + output_mode = 'classification' + eval_data, eval_labels = get_tensor_data(output_mode, eval_features) + print("eval_labels") + # Run prediction for full data + eval_sampler = SequentialSampler(eval_data) + eval_dataloader = DataLoader(eval_data, sampler=eval_sampler, drop_last = True, + batch_size = args.eval_batch_size, shuffle = False) + + if not os.path.exists(bin_path): + os.makedirs(bin_path) + i = -1 + for input_ids, input_mask, segment_ids, label_ids, seq_lengths in eval_dataloader: + i = i + 1 + print("[info] file", "===", i) + input_ids_np = input_ids.numpy() + input_mask_np = input_mask.numpy() + segment_ids_np = segment_ids.numpy() + if args.inference_tool == "msame": + path1 = bin_path + "/input_ids" + path2 = bin_path + "/segment_ids" + path3 = bin_path + "/input_mask" + input_ids_np.tofile(os.path.join(path1, "input" + str(i) + '.bin')) + segment_ids_np.tofile(os.path.join(path2, "input" + str(i) + '.bin')) + input_mask_np.tofile(os.path.join(path3, "input" + str(i) + '.bin')) + elif args.inference_tool == "benchmark": + input_ids_np.tofile(os.path.join(bin_path, "input_ids_" + str(i) + '.bin')) + segment_ids_np.tofile(os.path.join(bin_path, "segment_ids_" + str(i) + '.bin')) + input_mask_np.tofile(os.path.join(bin_path, "input_mask_" + str(i) + '.bin')) + +if __name__ == "__main__": data_main() \ No newline at end of file diff --git a/ACL_PyTorch/contrib/nlp/tinybert/modelzoo_level.txt b/ACL_PyTorch/contrib/nlp/tinybert/modelzoo_level.txt index 62ed12347c..def2f63f1b 100644 --- a/ACL_PyTorch/contrib/nlp/tinybert/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/nlp/tinybert/modelzoo_level.txt @@ -1,6 +1,6 @@ -ModelConvert:OK -QuantStatus:OK -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +ModelConvert:OK +QuantStatus:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/nlp/tinybert/pth2onnx.py b/ACL_PyTorch/contrib/nlp/tinybert/pth2onnx.py index e30bda0a5d..696ebfaa5e 100644 --- a/ACL_PyTorch/contrib/nlp/tinybert/pth2onnx.py +++ b/ACL_PyTorch/contrib/nlp/tinybert/pth2onnx.py @@ -1,84 +1,84 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 os -import torch -import torch.onnx -import argparse -from transformer.modeling import TinyBertForSequenceClassification - - -def make_input(args): - """make the input data to create a model""" - eval_batch_size = args.eval_batch_size - max_seq_length = args.max_seq_length - org_input_ids = torch.ones(eval_batch_size, max_seq_length).long() - org_token_type_ids = torch.ones(eval_batch_size, max_seq_length).long() - org_input_mask = torch.ones(eval_batch_size, max_seq_length).long() - return (org_input_ids, org_token_type_ids, org_input_mask) - - -def convert(args): - """convert the files into data""" - model = TinyBertForSequenceClassification.from_pretrained(args.input_model, num_labels = 2) - model.eval() - org_input = make_input(args) - input_names = ['input_ids', 'segment_ids', 'input_mask'] - output_names = ['output'] - OPERATOR_EXPORT_TYPE = torch._C._onnx.OperatorExportTypes.ONNX - torch.onnx.export(model, org_input, args.output_file, export_params = True, - input_names=input_names, output_names=output_names, - operator_export_type=OPERATOR_EXPORT_TYPE, - opset_version=11, verbose=True) - - -def main(): - """change the pth files into onnx""" - #set the args list - parser = argparse.ArgumentParser() - parser.add_argument("--input_model", - default=None, - type=str, - required=True, - help="The model(e.g. SST-2 distilled model)dir.") - parser.add_argument("--output_file", - default=None, - type=str, - required=True, - help="The output file of onnx. File name or dir is available.") - parser.add_argument("--data_dir", - default=None, - type=str, - required=True, - help="The input data dir. Should contain the .tsv files (or other data files) for the task.") - parser.add_argument("--max_seq_length", - default=64, - type=int, - help="The maximum total input sequence length after WordPiece tokenization. \n" - "Sequences longer than this will be truncated, and sequences shorter \n" - "than this will be padded.") - parser.add_argument("--eval_batch_size", - default=1, - type=int, - help="Total batch size for eval.") - parser.add_argument("--do_lower_case", - action='store_true', - help="Set this flag if you are using an uncased model.") - args = parser.parse_args() - os.makedirs(os.path.dirname(args.output_file), exist_ok=True) - convert(args) - #add_cast(args) - -if __name__ == "__main__": - main() +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 os +import torch +import torch.onnx +import argparse +from transformer.modeling import TinyBertForSequenceClassification + + +def make_input(args): + """make the input data to create a model""" + eval_batch_size = args.eval_batch_size + max_seq_length = args.max_seq_length + org_input_ids = torch.ones(eval_batch_size, max_seq_length).long() + org_token_type_ids = torch.ones(eval_batch_size, max_seq_length).long() + org_input_mask = torch.ones(eval_batch_size, max_seq_length).long() + return (org_input_ids, org_token_type_ids, org_input_mask) + + +def convert(args): + """convert the files into data""" + model = TinyBertForSequenceClassification.from_pretrained(args.input_model, num_labels = 2) + model.eval() + org_input = make_input(args) + input_names = ['input_ids', 'segment_ids', 'input_mask'] + output_names = ['output'] + OPERATOR_EXPORT_TYPE = torch._C._onnx.OperatorExportTypes.ONNX + torch.onnx.export(model, org_input, args.output_file, export_params = True, + input_names=input_names, output_names=output_names, + operator_export_type=OPERATOR_EXPORT_TYPE, + opset_version=11, verbose=True) + + +def main(): + """change the pth files into onnx""" + #set the args list + parser = argparse.ArgumentParser() + parser.add_argument("--input_model", + default=None, + type=str, + required=True, + help="The model(e.g. SST-2 distilled model)dir.") + parser.add_argument("--output_file", + default=None, + type=str, + required=True, + help="The output file of onnx. File name or dir is available.") + parser.add_argument("--data_dir", + default=None, + type=str, + required=True, + help="The input data dir. Should contain the .tsv files (or other data files) for the task.") + parser.add_argument("--max_seq_length", + default=64, + type=int, + help="The maximum total input sequence length after WordPiece tokenization. \n" + "Sequences longer than this will be truncated, and sequences shorter \n" + "than this will be padded.") + parser.add_argument("--eval_batch_size", + default=1, + type=int, + help="Total batch size for eval.") + parser.add_argument("--do_lower_case", + action='store_true', + help="Set this flag if you are using an uncased model.") + args = parser.parse_args() + os.makedirs(os.path.dirname(args.output_file), exist_ok=True) + convert(args) + #add_cast(args) + +if __name__ == "__main__": + main() diff --git a/ACL_PyTorch/contrib/rl/DQN/env.sh b/ACL_PyTorch/contrib/rl/DQN/env.sh index 7e0a3deaa3..d9466cab92 100644 --- a/ACL_PyTorch/contrib/rl/DQN/env.sh +++ b/ACL_PyTorch/contrib/rl/DQN/env.sh @@ -1,8 +1,8 @@ -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH -export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp -source /usr/local/Ascend/ascend-toolkit/set_env.sh -export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest +export install_path=/usr/local/Ascend/ascend-toolkit/latest +export PATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH +export PYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATH +export LD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATH +export ASCEND_OPP_PATH=${install_path}/opp +source /usr/local/Ascend/ascend-toolkit/set_env.sh +export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest export REPEAT_TUNE=True \ No newline at end of file diff --git a/ACL_PyTorch/contrib/rl/DQN/modelzoo_level.txt b/ACL_PyTorch/contrib/rl/DQN/modelzoo_level.txt index 38700fca05..2e42553460 100644 --- a/ACL_PyTorch/contrib/rl/DQN/modelzoo_level.txt +++ b/ACL_PyTorch/contrib/rl/DQN/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:OK \ No newline at end of file diff --git a/ACL_PyTorch/contrib/rl/DQN/test/parse.py b/ACL_PyTorch/contrib/rl/DQN/test/parse.py index 26ec1439e9..f45e4ba7e1 100644 --- a/ACL_PyTorch/contrib/rl/DQN/test/parse.py +++ b/ACL_PyTorch/contrib/rl/DQN/test/parse.py @@ -1,34 +1,34 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import json -import re - -if __name__ == '__main__': - if sys.argv[1].endswith('.json'): - result_json = sys.argv[1] - with open(result_json, 'r') as f: - content = f.read() - print(content) - elif sys.argv[1].endswith('.txt'): - result_txt = sys.argv[1] - with open(result_txt, 'r') as f: - content = f.read() - - txt_data_list = [i.strip() for i in re.findall(r'=(.*?),', content.replace('\n', ',') + ',')] - print(txt_data_list) - fps = float(txt_data_list[0].replace('samples/s', '')) * 4 - print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import json +import re + +if __name__ == '__main__': + if sys.argv[1].endswith('.json'): + result_json = sys.argv[1] + with open(result_json, 'r') as f: + content = f.read() + print(content) + elif sys.argv[1].endswith('.txt'): + result_txt = sys.argv[1] + with open(result_txt, 'r') as f: + content = f.read() + + txt_data_list = [i.strip() for i in re.findall(r'=(.*?),', content.replace('\n', ',') + ',')] + print(txt_data_list) + fps = float(txt_data_list[0].replace('samples/s', '')) * 4 + print('310 bs{} fps:{}'.format(result_txt.split('_')[3], fps)) + diff --git a/PyTorch/built-in/cv/classification/3D_ResNet_ID0421_for_PyTorch/test/train_full_8p.sh b/PyTorch/built-in/cv/classification/3D_ResNet_ID0421_for_PyTorch/test/train_full_8p.sh index ad8e9d5e2a..a176b4a4df 100644 --- a/PyTorch/built-in/cv/classification/3D_ResNet_ID0421_for_PyTorch/test/train_full_8p.sh +++ b/PyTorch/built-in/cv/classification/3D_ResNet_ID0421_for_PyTorch/test/train_full_8p.sh @@ -1,201 +1,201 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd`/../ - -#集合通信参数,不需要修改 -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 - - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="3D_ResNet_ID0421_for_PyTorch" -#训练epoch -train_epochs=200 -#训练batch_size -batch_size=1024 -#训练step -train_steps= -#学习率 -learning_rate=0.08 - -#TF2.X独有,需要模型审视修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -#precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False -autotune=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_full_1p.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is False - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/test/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/test/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/test/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - fi -done - - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#进入训练脚本目录,需要模型审视修改 -cd $cur_path -##################创建日志输出目录,根据模型审视################## -# 模型采用非循环方式启动多卡训练,创建日志输出目录如下;采用循环方式启动多卡训练的模型,在循环中创建日志输出目录,可参考CRNN模型 -# 非循环方式下8卡训练日志输出路径中的ASCEND_DEVICE_ID默认为0,只是人为指定文件夹名称, 不涉及训练业务 -ASCEND_DEVICE_ID=0 -#创建DeviceID输出目录,不需要修改 -if [ -d ${cur_path}/test/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/test/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/test/output/$ASCEND_DEVICE_ID/ckpt -else - mkdir -p ${cur_path}/test/output/$ASCEND_DEVICE_ID/ckpt -fi -# 绑核,不需要的绑核的模型删除,需要的模型审视修改 -#let a=RANK_ID*12 -#let b=RANK_ID+1 -#let c=b*12-1 - -#执行训练脚本,以下传参不需要修改,其他需要模型审视修改 -#--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path - nohup python3 main.py \ - --video_path ${data_path}/hmdb51_jpg \ - --annotation_path ${data_path}/hmdb51_json/hmdb51_1.json \ - --result_path outputs \ - --dataset hmdb51 \ - --n_classes 51 \ - --n_pretrain_classes 700 \ - --pretrain_path ${data_path}/r3d18_K_200ep.pth \ - --ft_begin_module fc \ - --model resnet \ - --model_depth 18 \ - --batch_size 1024 \ - --n_threads 128 \ - --checkpoint 5 \ - --amp_cfg \ - --n_epochs ${train_epochs} \ - --opt_level O2 \ - --loss_scale_value 1024 \ - --distributed \ - --ngpus_per_node 8 \ - --device_list '0,1,2,3,4,5,6,7' \ - --manual_seed 1234 \ - --learning_rate ${learning_rate} \ - --tensorboard > ${cur_path}/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & - -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep Fps $cur_path/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|grep -v "\[1/" | grep -v "\[2/" | awk -F "Fps" '{print$2}' | awk '{print$1}' | awk '{sum+=$1} END {print"",sum/NR}'` -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - - -python3 main.py \ - --video_path ${data_path}/hmdb51_jpg \ - --annotation_path ${data_path}/hmdb51_json/hmdb51_1.json \ - --result_path outputs \ - --dataset hmdb51 \ - --resume_path outputs/save_200.pth \ - --model_depth 18 \ - --n_classes 51 \ - --n_threads 4 \ - --no_train \ - --no_val \ - --inference \ - --output_topk 5 \ - --inference_batch_size 1 \ - --device_list '0,1,2,3,4,5,6,7' - -python3 -m util_scripts.eval_accuracy ${data_path}/hmdb51_json/hmdb51_1.json outputs/val.json -k 1 --save --ignore >> ${cur_path}/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & -wait -#输出训练精度,需要模型审视修改 -train_accuracy=`grep "top-1 accuracy:" $cur_path/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F " " '{print$3}' ` - -#打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`echo "${batch_size} ${FPS}" | awk '{printf("%.2f",$1*1000/$2)}' ` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep "Fps" $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "Loss" '{print$2}' | awk '{print$1}' > $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd`/../ + +#集合通信参数,不需要修改 +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 + + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="3D_ResNet_ID0421_for_PyTorch" +#训练epoch +train_epochs=200 +#训练batch_size +batch_size=1024 +#训练step +train_steps= +#学习率 +learning_rate=0.08 + +#TF2.X独有,需要模型审视修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +#precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False +autotune=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_full_1p.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is False + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/test/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/test/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/test/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + fi +done + + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#进入训练脚本目录,需要模型审视修改 +cd $cur_path +##################创建日志输出目录,根据模型审视################## +# 模型采用非循环方式启动多卡训练,创建日志输出目录如下;采用循环方式启动多卡训练的模型,在循环中创建日志输出目录,可参考CRNN模型 +# 非循环方式下8卡训练日志输出路径中的ASCEND_DEVICE_ID默认为0,只是人为指定文件夹名称, 不涉及训练业务 +ASCEND_DEVICE_ID=0 +#创建DeviceID输出目录,不需要修改 +if [ -d ${cur_path}/test/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/test/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/test/output/$ASCEND_DEVICE_ID/ckpt +else + mkdir -p ${cur_path}/test/output/$ASCEND_DEVICE_ID/ckpt +fi +# 绑核,不需要的绑核的模型删除,需要的模型审视修改 +#let a=RANK_ID*12 +#let b=RANK_ID+1 +#let c=b*12-1 + +#执行训练脚本,以下传参不需要修改,其他需要模型审视修改 +#--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path + nohup python3 main.py \ + --video_path ${data_path}/hmdb51_jpg \ + --annotation_path ${data_path}/hmdb51_json/hmdb51_1.json \ + --result_path outputs \ + --dataset hmdb51 \ + --n_classes 51 \ + --n_pretrain_classes 700 \ + --pretrain_path ${data_path}/r3d18_K_200ep.pth \ + --ft_begin_module fc \ + --model resnet \ + --model_depth 18 \ + --batch_size 1024 \ + --n_threads 128 \ + --checkpoint 5 \ + --amp_cfg \ + --n_epochs ${train_epochs} \ + --opt_level O2 \ + --loss_scale_value 1024 \ + --distributed \ + --ngpus_per_node 8 \ + --device_list '0,1,2,3,4,5,6,7' \ + --manual_seed 1234 \ + --learning_rate ${learning_rate} \ + --tensorboard > ${cur_path}/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & + +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep Fps $cur_path/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|grep -v "\[1/" | grep -v "\[2/" | awk -F "Fps" '{print$2}' | awk '{print$1}' | awk '{sum+=$1} END {print"",sum/NR}'` +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + + +python3 main.py \ + --video_path ${data_path}/hmdb51_jpg \ + --annotation_path ${data_path}/hmdb51_json/hmdb51_1.json \ + --result_path outputs \ + --dataset hmdb51 \ + --resume_path outputs/save_200.pth \ + --model_depth 18 \ + --n_classes 51 \ + --n_threads 4 \ + --no_train \ + --no_val \ + --inference \ + --output_topk 5 \ + --inference_batch_size 1 \ + --device_list '0,1,2,3,4,5,6,7' + +python3 -m util_scripts.eval_accuracy ${data_path}/hmdb51_json/hmdb51_1.json outputs/val.json -k 1 --save --ignore >> ${cur_path}/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & +wait +#输出训练精度,需要模型审视修改 +train_accuracy=`grep "top-1 accuracy:" $cur_path/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F " " '{print$3}' ` + +#打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`echo "${batch_size} ${FPS}" | awk '{printf("%.2f",$1*1000/$2)}' ` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep "Fps" $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "Loss" '{print$2}' | awk '{print$1}' > $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/3D_ResNet_ID0421_for_PyTorch/test/train_performance_8p.sh b/PyTorch/built-in/cv/classification/3D_ResNet_ID0421_for_PyTorch/test/train_performance_8p.sh index d9adadf868..9c53ccd79a 100644 --- a/PyTorch/built-in/cv/classification/3D_ResNet_ID0421_for_PyTorch/test/train_performance_8p.sh +++ b/PyTorch/built-in/cv/classification/3D_ResNet_ID0421_for_PyTorch/test/train_performance_8p.sh @@ -1,180 +1,180 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd`/../ - -#集合通信参数,不需要修改 -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 - - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -export ASCEND_GLOBAL_LOG_LEVEL=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="3D_ResNet_ID0421_for_PyTorch" -#训练epoch -train_epochs=2 -#训练batch_size -batch_size=1024 -#训练step -train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.08 - -#TF2.X独有,需要模型审视修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -#precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_performance_1P.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is False - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/test/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/test/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/test/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#进入训练脚本目录,需要模型审视修改 -cd $cur_path - -echo "Device ID: $ASCEND_DEVICE_ID" -#export RANK_ID=$RANK_ID - -#创建DeviceID输出目录,不需要修改 -if [ -d ${cur_path}/test/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/test/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/test/output/$ASCEND_DEVICE_ID/ckpt -else - mkdir -p ${cur_path}/test/output/$ASCEND_DEVICE_ID/ckpt -fi -# 绑核,不需要的绑核的模型删除,需要的模型审视修改 -#let a=RANK_ID*12 -#let b=RANK_ID+1 -#let c=b*12-1 - -#执行训练脚本,以下传参不需要修改,其他需要模型审视修改 -#--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path -nohup python3 main.py \ - --video_path ${data_path}/hmdb51_jpg \ - --annotation_path ${data_path}/hmdb51_json/hmdb51_1.json \ - --result_path outputs \ - --dataset hmdb51 \ - --n_classes 51 \ - --n_pretrain_classes 700 \ - --pretrain_path ${data_path}/r3d18_K_200ep.pth \ - --ft_begin_module fc \ - --model resnet \ - --model_depth 18 \ - --batch_size $batch_size \ - --n_threads 128 \ - --checkpoint 5 \ - --amp_cfg \ - --n_epochs ${train_epochs} \ - --opt_level O2 \ - --loss_scale_value 1024 \ - --distributed \ - --ngpus_per_node 8 \ - --device_list '0,1,2,3,4,5,6,7' \ - --manual_seed 1234 \ - --learning_rate ${learning_rate} \ - --tensorboard > ${cur_path}/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep Fps $cur_path/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|grep -v "Epoch: \[1\]"|awk -F "Fps" '{print$2}'|awk '{print $1}'|awk '{sum+=$1} END {print sum/NR}'` -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep "Fps" $cur_path/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|tail -2|head -1|awk '{print $17}'|sed 's/[()]//g' ` -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`echo "${batch_size} ${FPS}" | awk '{printf("%.2f",$1*1000/$2)}' ` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep "Fps" $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "Loss" '{print$2}' | awk '{print$1}' > $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd`/../ + +#集合通信参数,不需要修改 +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 + + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +export ASCEND_GLOBAL_LOG_LEVEL=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="3D_ResNet_ID0421_for_PyTorch" +#训练epoch +train_epochs=2 +#训练batch_size +batch_size=1024 +#训练step +train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.08 + +#TF2.X独有,需要模型审视修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +#precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_performance_1P.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is False + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/test/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/test/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/test/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#进入训练脚本目录,需要模型审视修改 +cd $cur_path + +echo "Device ID: $ASCEND_DEVICE_ID" +#export RANK_ID=$RANK_ID + +#创建DeviceID输出目录,不需要修改 +if [ -d ${cur_path}/test/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/test/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/test/output/$ASCEND_DEVICE_ID/ckpt +else + mkdir -p ${cur_path}/test/output/$ASCEND_DEVICE_ID/ckpt +fi +# 绑核,不需要的绑核的模型删除,需要的模型审视修改 +#let a=RANK_ID*12 +#let b=RANK_ID+1 +#let c=b*12-1 + +#执行训练脚本,以下传参不需要修改,其他需要模型审视修改 +#--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path +nohup python3 main.py \ + --video_path ${data_path}/hmdb51_jpg \ + --annotation_path ${data_path}/hmdb51_json/hmdb51_1.json \ + --result_path outputs \ + --dataset hmdb51 \ + --n_classes 51 \ + --n_pretrain_classes 700 \ + --pretrain_path ${data_path}/r3d18_K_200ep.pth \ + --ft_begin_module fc \ + --model resnet \ + --model_depth 18 \ + --batch_size $batch_size \ + --n_threads 128 \ + --checkpoint 5 \ + --amp_cfg \ + --n_epochs ${train_epochs} \ + --opt_level O2 \ + --loss_scale_value 1024 \ + --distributed \ + --ngpus_per_node 8 \ + --device_list '0,1,2,3,4,5,6,7' \ + --manual_seed 1234 \ + --learning_rate ${learning_rate} \ + --tensorboard > ${cur_path}/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep Fps $cur_path/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|grep -v "Epoch: \[1\]"|awk -F "Fps" '{print$2}'|awk '{print $1}'|awk '{sum+=$1} END {print sum/NR}'` +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep "Fps" $cur_path/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|tail -2|head -1|awk '{print $17}'|sed 's/[()]//g' ` +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`echo "${batch_size} ${FPS}" | awk '{printf("%.2f",$1*1000/$2)}' ` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep "Fps" $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "Loss" '{print$2}' | awk '{print$1}' > $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log diff --git a/PyTorch/built-in/cv/classification/CRNN_for_PyTorch/modelzoo_level.txt b/PyTorch/built-in/cv/classification/CRNN_for_PyTorch/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/built-in/cv/classification/CRNN_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/built-in/cv/classification/CRNN_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/DeepMar_for_PyTorch/test/train_full_1p.sh b/PyTorch/built-in/cv/classification/DeepMar_for_PyTorch/test/train_full_1p.sh index d8778fcfb7..cd9fd128b8 100644 --- a/PyTorch/built-in/cv/classification/DeepMar_for_PyTorch/test/train_full_1p.sh +++ b/PyTorch/built-in/cv/classification/DeepMar_for_PyTorch/test/train_full_1p.sh @@ -1,165 +1,165 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -export ASCEND_SLOG_PRINT_TO_STDOUT=0 - -#集合通信参数,不需要修改 -export HCCL_WHITELIST_DISABLE=1 -export RANK_SIZE=1 -export JOB_ID=10087 -RANK_ID_START=0 -# source env.sh -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="DeepMar_ID0096_for_PyTorch" -#训练epoch -train_epochs=4 -#训练batch_size -batch_size=256 -#训练step -train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.045 - - - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_full_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --ci_cp* ]];then - ci_cp=`echo ${para#*=}` - fi -done - -if [[ $ci_cp == "1" ]];then - cp -r $data_path ${data_path}_bak -fi - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -# 绑核,不需要的绑核的模型删除,需要模型审视修改 -python3.7 ${cur_path}/../transform_peta.py \ - --save_dir=$data_path \ - --traintest_split_file=$data_path/peta_partition.pkl - -nohup python3.7 ${cur_path}/../train_deepmar_resnet50.py \ - --save_dir=$data_path \ - --workers=32 \ - --npu=$ASCEND_DEVICE_ID \ - --batch_size=$batch_size \ - --new_params_lr=0.01 \ - --finetuned_params_lr=0.01 \ - --total_epochs=100 \ - --steps_per_log=1 \ - --loss_scale 512 \ - --amp \ - --opt_level O2 > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep -v loss|awk '{print $NF}'|awk '{sum+=$1} END {print sum/NR}'` - -#输出训练精度,需要模型审视修改 -train_accuracy=`grep -a 'Acc' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "Acc" '{print $2}'|awk 'NR==1{max=$1;next}{max=max>$1?max:$1}END{print max}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#打印,不需要修改 -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep Step ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'loss:' '{print $2}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -if [[ $ci_cp == "1" ]];then - rm -rf $data_path - mv ${data_path}_bak $data_path +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +export ASCEND_SLOG_PRINT_TO_STDOUT=0 + +#集合通信参数,不需要修改 +export HCCL_WHITELIST_DISABLE=1 +export RANK_SIZE=1 +export JOB_ID=10087 +RANK_ID_START=0 +# source env.sh +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="DeepMar_ID0096_for_PyTorch" +#训练epoch +train_epochs=4 +#训练batch_size +batch_size=256 +#训练step +train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.045 + + + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_full_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --ci_cp* ]];then + ci_cp=`echo ${para#*=}` + fi +done + +if [[ $ci_cp == "1" ]];then + cp -r $data_path ${data_path}_bak +fi + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +# 绑核,不需要的绑核的模型删除,需要模型审视修改 +python3.7 ${cur_path}/../transform_peta.py \ + --save_dir=$data_path \ + --traintest_split_file=$data_path/peta_partition.pkl + +nohup python3.7 ${cur_path}/../train_deepmar_resnet50.py \ + --save_dir=$data_path \ + --workers=32 \ + --npu=$ASCEND_DEVICE_ID \ + --batch_size=$batch_size \ + --new_params_lr=0.01 \ + --finetuned_params_lr=0.01 \ + --total_epochs=100 \ + --steps_per_log=1 \ + --loss_scale 512 \ + --amp \ + --opt_level O2 > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep -v loss|awk '{print $NF}'|awk '{sum+=$1} END {print sum/NR}'` + +#输出训练精度,需要模型审视修改 +train_accuracy=`grep -a 'Acc' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "Acc" '{print $2}'|awk 'NR==1{max=$1;next}{max=max>$1?max:$1}END{print max}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#打印,不需要修改 +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep Step ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'loss:' '{print $2}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +if [[ $ci_cp == "1" ]];then + rm -rf $data_path + mv ${data_path}_bak $data_path fi \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/DeepMar_for_PyTorch/test/train_performance_1p.sh b/PyTorch/built-in/cv/classification/DeepMar_for_PyTorch/test/train_performance_1p.sh index 59d2e6627b..830ba688c9 100644 --- a/PyTorch/built-in/cv/classification/DeepMar_for_PyTorch/test/train_performance_1p.sh +++ b/PyTorch/built-in/cv/classification/DeepMar_for_PyTorch/test/train_performance_1p.sh @@ -1,162 +1,162 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -export ASCEND_SLOG_PRINT_TO_STDOUT=0 - -#集合通信参数,不需要修改 -export HCCL_WHITELIST_DISABLE=1 -export RANK_SIZE=1 -export JOB_ID=10087 -RANK_ID_START=0 -# source env.sh -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="DeepMar_ID0096_for_PyTorch" -#训练epoch -train_epochs=4 -#训练batch_size -batch_size=256 -#训练step -train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.045 - - - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --ci_cp* ]];then - ci_cp=`echo ${para#*=}` - fi -done - -if [[ $ci_cp == "1" ]];then - cp -r $data_path ${data_path}_bak -fi - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -# 绑核,不需要的绑核的模型删除,需要模型审视修改 -python3.7 ${cur_path}/../transform_peta.py \ - --save_dir=$data_path \ - --traintest_split_file=$data_path/peta_partition.pkl - -nohup python3.7 ${cur_path}/../train_deepmar_resnet50.py \ - --save_dir=$data_path \ - --workers=32 \ - --npu=$ASCEND_DEVICE_ID \ - --batch_size=$batch_size \ - --new_params_lr=0.01 \ - --finetuned_params_lr=0.01 \ - --total_epochs=10 \ - --steps_per_log=1 \ - --loss_scale 512 \ - --amp \ - --opt_level O2 > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep -v loss|awk '{print $NF}'|awk '{sum+=$1} END {print sum/NR}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#打印,不需要修改 -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep Step ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'loss:' '{print $2}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log - -if [[ $ci_cp == "1" ]];then - rm -rf $data_path - mv ${data_path}_bak $data_path +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +export ASCEND_SLOG_PRINT_TO_STDOUT=0 + +#集合通信参数,不需要修改 +export HCCL_WHITELIST_DISABLE=1 +export RANK_SIZE=1 +export JOB_ID=10087 +RANK_ID_START=0 +# source env.sh +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="DeepMar_ID0096_for_PyTorch" +#训练epoch +train_epochs=4 +#训练batch_size +batch_size=256 +#训练step +train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.045 + + + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --ci_cp* ]];then + ci_cp=`echo ${para#*=}` + fi +done + +if [[ $ci_cp == "1" ]];then + cp -r $data_path ${data_path}_bak +fi + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +# 绑核,不需要的绑核的模型删除,需要模型审视修改 +python3.7 ${cur_path}/../transform_peta.py \ + --save_dir=$data_path \ + --traintest_split_file=$data_path/peta_partition.pkl + +nohup python3.7 ${cur_path}/../train_deepmar_resnet50.py \ + --save_dir=$data_path \ + --workers=32 \ + --npu=$ASCEND_DEVICE_ID \ + --batch_size=$batch_size \ + --new_params_lr=0.01 \ + --finetuned_params_lr=0.01 \ + --total_epochs=10 \ + --steps_per_log=1 \ + --loss_scale 512 \ + --amp \ + --opt_level O2 > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep -v loss|awk '{print $NF}'|awk '{sum+=$1} END {print sum/NR}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#打印,不需要修改 +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep Step ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'loss:' '{print $2}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log + +if [[ $ci_cp == "1" ]];then + rm -rf $data_path + mv ${data_path}_bak $data_path fi \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/DeepMar_for_PyTorch/test/train_performance_8p.sh b/PyTorch/built-in/cv/classification/DeepMar_for_PyTorch/test/train_performance_8p.sh index 9b89fbe3eb..ecfa71f84b 100644 --- a/PyTorch/built-in/cv/classification/DeepMar_for_PyTorch/test/train_performance_8p.sh +++ b/PyTorch/built-in/cv/classification/DeepMar_for_PyTorch/test/train_performance_8p.sh @@ -1,175 +1,175 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -export ASCEND_SLOG_PRINT_TO_STDOUT=0 - -#集合通信参数,不需要修改 -export HCCL_WHITELIST_DISABLE=1 -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 -# source env.sh -RANK_SIZE=8 -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="DeepMar_ID0096_for_PyTorch" -#训练epoch -train_epochs=4 -#训练batch_size -batch_size=2048 -#训练step -train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.045 - - - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --ci_cp* ]];then - ci_cp=`echo ${para#*=}` - fi -done - -if [[ $ci_cp == "1" ]];then - cp -r $data_path ${data_path}_bak -fi - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -# 绑核,不需要的绑核的模型删除,需要模型审视修改 -python3.7 ${cur_path}/../transform_peta.py \ - --save_dir=$data_path \ - --traintest_split_file=$data_path/peta_partition.pkl - -corenum=`cat /proc/cpuinfo |grep "processor"|wc -l` -let a=RANK_ID*${corenum}/${RANK_SIZE} -let b=RANK_ID+1 -let c=b*${corenum}/${RANK_SIZE}-1 -nohup taskset -c $a-$c python3.7 ${cur_path}/../train_deepmar_resnet50_8p.py \ - --addr=$(hostname -I |awk '{print $1}') \ - --save_dir=$data_path \ - --exp_dir=$cur_path/output/$ASCEND_DEVICE_ID/ \ - --workers=64 \ - --batch_size=2048 \ - --new_params_lr=0.016 \ - --finetuned_params_lr=0.016 \ - --total_epochs=$train_epochs \ - --steps_per_log=1 \ - --loss_scale 512 \ - --amp \ - --opt_level O2 \ - --dist_url 'tcp://127.0.0.1:50000' \ - --dist_backend 'hccl' \ - --multiprocessing_distributed \ - --world_size 1 \ - --rank 0 \ - --epochs_per_val 40 > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -#FPS=`grep -a 'FPS' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F " " '{print $NF}'|awk 'END {print}'` -FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep npu|awk '{print $NF}'|awk '{sum+=$1} END {print sum/NR}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#打印,不需要修改 -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep Step ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'loss:' '{print $2}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log - -if [[ $ci_cp == "1" ]];then - rm -rf $data_path - mv ${data_path}_bak $data_path +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +export ASCEND_SLOG_PRINT_TO_STDOUT=0 + +#集合通信参数,不需要修改 +export HCCL_WHITELIST_DISABLE=1 +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 +# source env.sh +RANK_SIZE=8 +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="DeepMar_ID0096_for_PyTorch" +#训练epoch +train_epochs=4 +#训练batch_size +batch_size=2048 +#训练step +train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.045 + + + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --ci_cp* ]];then + ci_cp=`echo ${para#*=}` + fi +done + +if [[ $ci_cp == "1" ]];then + cp -r $data_path ${data_path}_bak +fi + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +# 绑核,不需要的绑核的模型删除,需要模型审视修改 +python3.7 ${cur_path}/../transform_peta.py \ + --save_dir=$data_path \ + --traintest_split_file=$data_path/peta_partition.pkl + +corenum=`cat /proc/cpuinfo |grep "processor"|wc -l` +let a=RANK_ID*${corenum}/${RANK_SIZE} +let b=RANK_ID+1 +let c=b*${corenum}/${RANK_SIZE}-1 +nohup taskset -c $a-$c python3.7 ${cur_path}/../train_deepmar_resnet50_8p.py \ + --addr=$(hostname -I |awk '{print $1}') \ + --save_dir=$data_path \ + --exp_dir=$cur_path/output/$ASCEND_DEVICE_ID/ \ + --workers=64 \ + --batch_size=2048 \ + --new_params_lr=0.016 \ + --finetuned_params_lr=0.016 \ + --total_epochs=$train_epochs \ + --steps_per_log=1 \ + --loss_scale 512 \ + --amp \ + --opt_level O2 \ + --dist_url 'tcp://127.0.0.1:50000' \ + --dist_backend 'hccl' \ + --multiprocessing_distributed \ + --world_size 1 \ + --rank 0 \ + --epochs_per_val 40 > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +#FPS=`grep -a 'FPS' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F " " '{print $NF}'|awk 'END {print}'` +FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep npu|awk '{print $NF}'|awk '{sum+=$1} END {print sum/NR}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#打印,不需要修改 +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep Step ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'loss:' '{print $2}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log + +if [[ $ci_cp == "1" ]];then + rm -rf $data_path + mv ${data_path}_bak $data_path fi \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/convert/densenet121_pt_aipp.config b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/convert/densenet121_pt_aipp.config index daf3d557a6..17cc1daafa 100644 --- a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/convert/densenet121_pt_aipp.config +++ b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/convert/densenet121_pt_aipp.config @@ -1,16 +1,16 @@ -aipp_op{ - aipp_mode:static - input_format : RGB888_U8 - csc_switch : false - rbuv_swap_switch : true - - mean_chn_0: 121 - mean_chn_1: 115 - mean_chn_2: 100 - min_chn_0 : 0.0 - min_chn_1 : 0.0 - min_chn_2 : 0.0 - var_reci_chn_0 : 0.0142857142857143 - var_reci_chn_1 : 0.0147058823529412 - var_reci_chn_2 : 0.0140845070422535 -} +aipp_op{ + aipp_mode:static + input_format : RGB888_U8 + csc_switch : false + rbuv_swap_switch : true + + mean_chn_0: 121 + mean_chn_1: 115 + mean_chn_2: 100 + min_chn_0 : 0.0 + min_chn_1 : 0.0 + min_chn_2 : 0.0 + var_reci_chn_0 : 0.0142857142857143 + var_reci_chn_1 : 0.0147058823529412 + var_reci_chn_2 : 0.0140845070422535 +} diff --git a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/mxbase_infer/CMakeLists.txt b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/mxbase_infer/CMakeLists.txt index 95cb9125d4..1c3a4f0ea6 100644 --- a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/mxbase_infer/CMakeLists.txt +++ b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/mxbase_infer/CMakeLists.txt @@ -1,49 +1,49 @@ -cmake_minimum_required(VERSION 3.14.0) -project(densenet121) - -set(TARGET densenet121) - -add_definitions(-DENABLE_DVPP_INTERFACE) -add_compile_options(-std=c++11 -fPIE -fstack-protector-all -fPIC -Wall) -add_link_options(-Wl,-z,relro,-z,now,-z,noexecstack -s -pie) - -# Check environment variable -if(NOT DEFINED ENV{ASCEND_HOME}) - message(FATAL_ERROR "please define environment variable:ASCEND_HOME") -endif() -if(NOT DEFINED ENV{ASCEND_VERSION}) - message(WARNING "please define environment variable:ASCEND_VERSION") -endif() -if(NOT DEFINED ENV{ARCH_PATTERN}) - message(WARNING "please define environment variable:ARCH_PATTERN") -endif() -set(ACL_INC_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/include) -set(ACL_LIB_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/lib64) - -set(MXBASE_ROOT_DIR ${PROJECT_SOURCE_DIR}/../../) -set(MXBASE_INC ${MXBASE_ROOT_DIR}/mxbase/include) -set(MXBASE_LIB_DIR ${MXBASE_ROOT_DIR}/dist/lib) -set(MXBASE_POST_LIB_DIR ${MXBASE_ROOT_DIR}/dist/lib/modelpostprocessors) -set(MXBASE_POST_PROCESS_DIR ${MXBASE_ROOT_DIR}/postprocess/include) -if(DEFINED ENV{MXSDK_OPENSOURCE_DIR}) - set(OPENSOURCE_DIR $ENV{MXSDK_OPENSOURCE_DIR}) -else() - set(OPENSOURCE_DIR ${MXBASE_ROOT_DIR}/opensource/dist) -endif() - -include_directories(${ACL_INC_DIR}) -include_directories(${OPENSOURCE_DIR}/include) -include_directories(${OPENSOURCE_DIR}/include/opencv4) - -include_directories(${MXBASE_INC}) -include_directories(${MXBASE_POST_PROCESS_DIR}) - -link_directories(${ACL_LIB_DIR}) -link_directories(${OPENSOURCE_DIR}/lib) -link_directories(${MXBASE_LIB_DIR}) -link_directories(${MXBASE_POST_LIB_DIR}) - -add_executable(${TARGET} main.cpp Densenet121Classify.cpp) -target_link_libraries(${TARGET} glog cpprest mxbase resnet50postprocess stdc++fs) - -install(TARGETS ${TARGET} RUNTIME DESTINATION ${PROJECT_SOURCE_DIR}/) +cmake_minimum_required(VERSION 3.14.0) +project(densenet121) + +set(TARGET densenet121) + +add_definitions(-DENABLE_DVPP_INTERFACE) +add_compile_options(-std=c++11 -fPIE -fstack-protector-all -fPIC -Wall) +add_link_options(-Wl,-z,relro,-z,now,-z,noexecstack -s -pie) + +# Check environment variable +if(NOT DEFINED ENV{ASCEND_HOME}) + message(FATAL_ERROR "please define environment variable:ASCEND_HOME") +endif() +if(NOT DEFINED ENV{ASCEND_VERSION}) + message(WARNING "please define environment variable:ASCEND_VERSION") +endif() +if(NOT DEFINED ENV{ARCH_PATTERN}) + message(WARNING "please define environment variable:ARCH_PATTERN") +endif() +set(ACL_INC_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/include) +set(ACL_LIB_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/lib64) + +set(MXBASE_ROOT_DIR ${PROJECT_SOURCE_DIR}/../../) +set(MXBASE_INC ${MXBASE_ROOT_DIR}/mxbase/include) +set(MXBASE_LIB_DIR ${MXBASE_ROOT_DIR}/dist/lib) +set(MXBASE_POST_LIB_DIR ${MXBASE_ROOT_DIR}/dist/lib/modelpostprocessors) +set(MXBASE_POST_PROCESS_DIR ${MXBASE_ROOT_DIR}/postprocess/include) +if(DEFINED ENV{MXSDK_OPENSOURCE_DIR}) + set(OPENSOURCE_DIR $ENV{MXSDK_OPENSOURCE_DIR}) +else() + set(OPENSOURCE_DIR ${MXBASE_ROOT_DIR}/opensource/dist) +endif() + +include_directories(${ACL_INC_DIR}) +include_directories(${OPENSOURCE_DIR}/include) +include_directories(${OPENSOURCE_DIR}/include/opencv4) + +include_directories(${MXBASE_INC}) +include_directories(${MXBASE_POST_PROCESS_DIR}) + +link_directories(${ACL_LIB_DIR}) +link_directories(${OPENSOURCE_DIR}/lib) +link_directories(${MXBASE_LIB_DIR}) +link_directories(${MXBASE_POST_LIB_DIR}) + +add_executable(${TARGET} main.cpp Densenet121Classify.cpp) +target_link_libraries(${TARGET} glog cpprest mxbase resnet50postprocess stdc++fs) + +install(TARGETS ${TARGET} RUNTIME DESTINATION ${PROJECT_SOURCE_DIR}/) diff --git a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/mxbase_infer/Densenet121Classify.cpp b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/mxbase_infer/Densenet121Classify.cpp index dcd612db9c..760265dbc1 100644 --- a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/mxbase_infer/Densenet121Classify.cpp +++ b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/mxbase_infer/Densenet121Classify.cpp @@ -1,256 +1,256 @@ -/* - * Copyright (c) 2021. Huawei Technologies Co., Ltd. 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. - */ - -#include -#include -#include "Densenet121Classify.h" -#include "MxBase/DeviceManager/DeviceManager.h" -#include "MxBase/Log/Log.h" - -using namespace MxBase; -namespace { -const uint32_t YUV_BYTE_NU = 3; -const uint32_t YUV_BYTE_DE = 2; -const uint32_t VPC_H_ALIGN = 2; -} - -APP_ERROR Densenet121Classify::Init(const InitParam &initParam) -{ - deviceId_ = initParam.deviceId; - APP_ERROR ret = MxBase::DeviceManager::GetInstance()->InitDevices(); - if (ret != APP_ERR_OK) { - LogError << "Init devices failed, ret=" << ret << "."; - return ret; - } - ret = MxBase::TensorContext::GetInstance()->SetContext(initParam.deviceId); - if (ret != APP_ERR_OK) { - LogError << "Set context failed, ret=" << ret << "."; - return ret; - } - dvppWrapper_ = std::make_shared(); - ret = dvppWrapper_->Init(); - if (ret != APP_ERR_OK) { - LogError << "DvppWrapper init failed, ret=" << ret << "."; - return ret; - } - model_ = std::make_shared(); - ret = model_->Init(initParam.modelPath, modelDesc_); - if (ret != APP_ERR_OK) { - LogError << "ModelInferenceProcessor init failed, ret=" << ret << "."; - return ret; - } - MxBase::ConfigData configData; - const std::string softmax = initParam.softmax ? "true" : "false"; - const std::string checkTensor = initParam.checkTensor ? "true" : "false"; - - configData.SetJsonValue("CLASS_NUM", std::to_string(initParam.classNum)); - configData.SetJsonValue("TOP_K", std::to_string(initParam.topk)); - configData.SetJsonValue("SOFTMAX", softmax); - configData.SetJsonValue("CHECK_MODEL", checkTensor); - - auto jsonStr = configData.GetCfgJson().serialize(); - std::map> config; - config["postProcessConfigContent"] = std::make_shared(jsonStr); - config["labelPath"] = std::make_shared(initParam.labelPath); - - post_ = std::make_shared(); - ret = post_->Init(config); - if (ret != APP_ERR_OK) { - LogError << "Resnet50PostProcess init failed, ret=" << ret << "."; - return ret; - } - return APP_ERR_OK; -} - -APP_ERROR Densenet121Classify::DeInit() -{ - dvppWrapper_->DeInit(); - model_->DeInit(); - post_->DeInit(); - MxBase::DeviceManager::GetInstance()->DestroyDevices(); - return APP_ERR_OK; -} - -APP_ERROR Densenet121Classify::ReadImage(const std::string &imgPath, MxBase::TensorBase &tensor) -{ - MxBase::DvppDataInfo output = {}; - APP_ERROR ret = dvppWrapper_->DvppJpegDecode(imgPath, output); - if (ret != APP_ERR_OK) { - LogError << "DvppWrapper DvppJpegDecode failed, ret=" << ret << "."; - return ret; - } - MxBase::MemoryData memoryData((void*)output.data, output.dataSize, MemoryData::MemoryType::MEMORY_DVPP, deviceId_); - if (output.heightStride % VPC_H_ALIGN != 0) { - LogError << "Output data height(" << output.heightStride << ") can't be divided by " << VPC_H_ALIGN << "."; - MemoryHelper::MxbsFree(memoryData); - return APP_ERR_COMM_INVALID_PARAM; - } - std::vector shape = {output.heightStride * YUV_BYTE_NU / YUV_BYTE_DE, output.widthStride}; - tensor = TensorBase(memoryData, false, shape, TENSOR_DTYPE_UINT8); - return APP_ERR_OK; -} - -APP_ERROR Densenet121Classify::Resize(const MxBase::TensorBase &inputTensor, MxBase::TensorBase &outputTensor) -{ - auto shape = inputTensor.GetShape(); - MxBase::DvppDataInfo input = {}; - input.height = (uint32_t)shape[0] * YUV_BYTE_DE / YUV_BYTE_NU; - input.width = shape[1]; - input.heightStride = (uint32_t)shape[0] * YUV_BYTE_DE / YUV_BYTE_NU; - input.widthStride = shape[1]; - input.dataSize = inputTensor.GetByteSize(); - input.data = (uint8_t*)inputTensor.GetBuffer(); - const uint32_t resizeHeight = 304; - const uint32_t resizeWidth = 304; - MxBase::ResizeConfig resize = {}; - resize.height = resizeHeight; - resize.width = resizeWidth; - MxBase::DvppDataInfo output = {}; - APP_ERROR ret = dvppWrapper_->VpcResize(input, output, resize); - if (ret != APP_ERR_OK) { - LogError << "VpcResize failed, ret=" << ret << "."; - return ret; - } - MxBase::MemoryData memoryData((void*)output.data, output.dataSize, MemoryData::MemoryType::MEMORY_DVPP, deviceId_); - if (output.heightStride % VPC_H_ALIGN != 0) { - LogError << "Output data height(" << output.heightStride << ") can't be divided by " << VPC_H_ALIGN << "."; - MemoryHelper::MxbsFree(memoryData); - MemoryHelper::MxbsFree(memoryData); - return APP_ERR_COMM_INVALID_PARAM; - } - shape = {output.heightStride * YUV_BYTE_NU / YUV_BYTE_DE, output.widthStride}; - outputTensor = TensorBase(memoryData, false, shape, TENSOR_DTYPE_UINT8); - return APP_ERR_OK; -} - -APP_ERROR Densenet121Classify::Inference(const std::vector &inputs, - std::vector &outputs) -{ - auto dtypes = model_->GetOutputDataType(); - for (size_t i = 0; i < modelDesc_.outputTensors.size(); ++i) { - std::vector shape = {}; - for (size_t j = 0; j < modelDesc_.outputTensors[i].tensorDims.size(); ++j) { - shape.push_back((uint32_t)modelDesc_.outputTensors[i].tensorDims[j]); - } - TensorBase tensor(shape, dtypes[i], MemoryData::MemoryType::MEMORY_DEVICE, deviceId_); - APP_ERROR ret = TensorBase::TensorBaseMalloc(tensor); - if (ret != APP_ERR_OK) { - LogError << "TensorBaseMalloc failed, ret=" << ret << "."; - return ret; - } - outputs.push_back(tensor); - } - DynamicInfo dynamicInfo = {}; - dynamicInfo.dynamicType = DynamicType::STATIC_BATCH; - auto startTime = std::chrono::high_resolution_clock::now(); // search for learning - APP_ERROR ret = model_->ModelInference(inputs, outputs, dynamicInfo); - auto endTime = std::chrono::high_resolution_clock::now(); - double costMs = std::chrono::duration(endTime - startTime).count(); - g_inferCost.push_back(costMs); - if (ret != APP_ERR_OK) { - LogError << "ModelInference failed, ret=" << ret << "."; - return ret; - } - return APP_ERR_OK; -} - -APP_ERROR Densenet121Classify::PostProcess(const std::vector &inputs, - std::vector> &clsInfos) -{ - APP_ERROR ret = post_->Process(inputs, clsInfos); - if (ret != APP_ERR_OK) { - LogError << "Process failed, ret=" << ret << "."; - return ret; - } - return APP_ERR_OK; -} - -APP_ERROR Densenet121Classify::GenerateInferResult(const std::string &imgPath, - std::vector> &BatchClsInfos) -{ - uint32_t batchIndex = 0; - LogInfo << "images path: " << imgPath; - std::string fileName = imgPath.substr(imgPath.find_last_of("/") + 1); - size_t dot = fileName.find_last_of("."); - - std::string resultPathName = "result"; - if (access(resultPathName.c_str(), 0) != 0) { - int ret = mkdir(resultPathName.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); - if (ret != 0) { - LogError << "Failed to create result directory: " << resultPathName << ", ret = " << ret; - return ret; - } - } - std::string resFileName = "result/" + fileName.substr(0, dot) + "_1.txt"; - LogInfo << "file path for saving result: " < inputs = {}; - std::vector outputs = {}; - inputs.push_back(resizeImage); - ret = Inference(inputs, outputs); - if (ret != APP_ERR_OK) { - LogError << "Inference failed, ret=" << ret << "."; - return ret; - } - std::vector> BatchClsInfos = {}; - ret = PostProcess(outputs, BatchClsInfos); - if (ret != APP_ERR_OK) { - LogError << "PostProcess failed, ret=" << ret << "."; - return ret; - } - ret = GenerateInferResult(imgPath, BatchClsInfos); - if (ret != APP_ERR_OK) { - LogError << "Generate infer result failed, ret=" << ret << "."; - return ret; - } - - return APP_ERR_OK; -} +/* + * Copyright (c) 2021. Huawei Technologies Co., Ltd. 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. + */ + +#include +#include +#include "Densenet121Classify.h" +#include "MxBase/DeviceManager/DeviceManager.h" +#include "MxBase/Log/Log.h" + +using namespace MxBase; +namespace { +const uint32_t YUV_BYTE_NU = 3; +const uint32_t YUV_BYTE_DE = 2; +const uint32_t VPC_H_ALIGN = 2; +} + +APP_ERROR Densenet121Classify::Init(const InitParam &initParam) +{ + deviceId_ = initParam.deviceId; + APP_ERROR ret = MxBase::DeviceManager::GetInstance()->InitDevices(); + if (ret != APP_ERR_OK) { + LogError << "Init devices failed, ret=" << ret << "."; + return ret; + } + ret = MxBase::TensorContext::GetInstance()->SetContext(initParam.deviceId); + if (ret != APP_ERR_OK) { + LogError << "Set context failed, ret=" << ret << "."; + return ret; + } + dvppWrapper_ = std::make_shared(); + ret = dvppWrapper_->Init(); + if (ret != APP_ERR_OK) { + LogError << "DvppWrapper init failed, ret=" << ret << "."; + return ret; + } + model_ = std::make_shared(); + ret = model_->Init(initParam.modelPath, modelDesc_); + if (ret != APP_ERR_OK) { + LogError << "ModelInferenceProcessor init failed, ret=" << ret << "."; + return ret; + } + MxBase::ConfigData configData; + const std::string softmax = initParam.softmax ? "true" : "false"; + const std::string checkTensor = initParam.checkTensor ? "true" : "false"; + + configData.SetJsonValue("CLASS_NUM", std::to_string(initParam.classNum)); + configData.SetJsonValue("TOP_K", std::to_string(initParam.topk)); + configData.SetJsonValue("SOFTMAX", softmax); + configData.SetJsonValue("CHECK_MODEL", checkTensor); + + auto jsonStr = configData.GetCfgJson().serialize(); + std::map> config; + config["postProcessConfigContent"] = std::make_shared(jsonStr); + config["labelPath"] = std::make_shared(initParam.labelPath); + + post_ = std::make_shared(); + ret = post_->Init(config); + if (ret != APP_ERR_OK) { + LogError << "Resnet50PostProcess init failed, ret=" << ret << "."; + return ret; + } + return APP_ERR_OK; +} + +APP_ERROR Densenet121Classify::DeInit() +{ + dvppWrapper_->DeInit(); + model_->DeInit(); + post_->DeInit(); + MxBase::DeviceManager::GetInstance()->DestroyDevices(); + return APP_ERR_OK; +} + +APP_ERROR Densenet121Classify::ReadImage(const std::string &imgPath, MxBase::TensorBase &tensor) +{ + MxBase::DvppDataInfo output = {}; + APP_ERROR ret = dvppWrapper_->DvppJpegDecode(imgPath, output); + if (ret != APP_ERR_OK) { + LogError << "DvppWrapper DvppJpegDecode failed, ret=" << ret << "."; + return ret; + } + MxBase::MemoryData memoryData((void*)output.data, output.dataSize, MemoryData::MemoryType::MEMORY_DVPP, deviceId_); + if (output.heightStride % VPC_H_ALIGN != 0) { + LogError << "Output data height(" << output.heightStride << ") can't be divided by " << VPC_H_ALIGN << "."; + MemoryHelper::MxbsFree(memoryData); + return APP_ERR_COMM_INVALID_PARAM; + } + std::vector shape = {output.heightStride * YUV_BYTE_NU / YUV_BYTE_DE, output.widthStride}; + tensor = TensorBase(memoryData, false, shape, TENSOR_DTYPE_UINT8); + return APP_ERR_OK; +} + +APP_ERROR Densenet121Classify::Resize(const MxBase::TensorBase &inputTensor, MxBase::TensorBase &outputTensor) +{ + auto shape = inputTensor.GetShape(); + MxBase::DvppDataInfo input = {}; + input.height = (uint32_t)shape[0] * YUV_BYTE_DE / YUV_BYTE_NU; + input.width = shape[1]; + input.heightStride = (uint32_t)shape[0] * YUV_BYTE_DE / YUV_BYTE_NU; + input.widthStride = shape[1]; + input.dataSize = inputTensor.GetByteSize(); + input.data = (uint8_t*)inputTensor.GetBuffer(); + const uint32_t resizeHeight = 304; + const uint32_t resizeWidth = 304; + MxBase::ResizeConfig resize = {}; + resize.height = resizeHeight; + resize.width = resizeWidth; + MxBase::DvppDataInfo output = {}; + APP_ERROR ret = dvppWrapper_->VpcResize(input, output, resize); + if (ret != APP_ERR_OK) { + LogError << "VpcResize failed, ret=" << ret << "."; + return ret; + } + MxBase::MemoryData memoryData((void*)output.data, output.dataSize, MemoryData::MemoryType::MEMORY_DVPP, deviceId_); + if (output.heightStride % VPC_H_ALIGN != 0) { + LogError << "Output data height(" << output.heightStride << ") can't be divided by " << VPC_H_ALIGN << "."; + MemoryHelper::MxbsFree(memoryData); + MemoryHelper::MxbsFree(memoryData); + return APP_ERR_COMM_INVALID_PARAM; + } + shape = {output.heightStride * YUV_BYTE_NU / YUV_BYTE_DE, output.widthStride}; + outputTensor = TensorBase(memoryData, false, shape, TENSOR_DTYPE_UINT8); + return APP_ERR_OK; +} + +APP_ERROR Densenet121Classify::Inference(const std::vector &inputs, + std::vector &outputs) +{ + auto dtypes = model_->GetOutputDataType(); + for (size_t i = 0; i < modelDesc_.outputTensors.size(); ++i) { + std::vector shape = {}; + for (size_t j = 0; j < modelDesc_.outputTensors[i].tensorDims.size(); ++j) { + shape.push_back((uint32_t)modelDesc_.outputTensors[i].tensorDims[j]); + } + TensorBase tensor(shape, dtypes[i], MemoryData::MemoryType::MEMORY_DEVICE, deviceId_); + APP_ERROR ret = TensorBase::TensorBaseMalloc(tensor); + if (ret != APP_ERR_OK) { + LogError << "TensorBaseMalloc failed, ret=" << ret << "."; + return ret; + } + outputs.push_back(tensor); + } + DynamicInfo dynamicInfo = {}; + dynamicInfo.dynamicType = DynamicType::STATIC_BATCH; + auto startTime = std::chrono::high_resolution_clock::now(); // search for learning + APP_ERROR ret = model_->ModelInference(inputs, outputs, dynamicInfo); + auto endTime = std::chrono::high_resolution_clock::now(); + double costMs = std::chrono::duration(endTime - startTime).count(); + g_inferCost.push_back(costMs); + if (ret != APP_ERR_OK) { + LogError << "ModelInference failed, ret=" << ret << "."; + return ret; + } + return APP_ERR_OK; +} + +APP_ERROR Densenet121Classify::PostProcess(const std::vector &inputs, + std::vector> &clsInfos) +{ + APP_ERROR ret = post_->Process(inputs, clsInfos); + if (ret != APP_ERR_OK) { + LogError << "Process failed, ret=" << ret << "."; + return ret; + } + return APP_ERR_OK; +} + +APP_ERROR Densenet121Classify::GenerateInferResult(const std::string &imgPath, + std::vector> &BatchClsInfos) +{ + uint32_t batchIndex = 0; + LogInfo << "images path: " << imgPath; + std::string fileName = imgPath.substr(imgPath.find_last_of("/") + 1); + size_t dot = fileName.find_last_of("."); + + std::string resultPathName = "result"; + if (access(resultPathName.c_str(), 0) != 0) { + int ret = mkdir(resultPathName.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); + if (ret != 0) { + LogError << "Failed to create result directory: " << resultPathName << ", ret = " << ret; + return ret; + } + } + std::string resFileName = "result/" + fileName.substr(0, dot) + "_1.txt"; + LogInfo << "file path for saving result: " < inputs = {}; + std::vector outputs = {}; + inputs.push_back(resizeImage); + ret = Inference(inputs, outputs); + if (ret != APP_ERR_OK) { + LogError << "Inference failed, ret=" << ret << "."; + return ret; + } + std::vector> BatchClsInfos = {}; + ret = PostProcess(outputs, BatchClsInfos); + if (ret != APP_ERR_OK) { + LogError << "PostProcess failed, ret=" << ret << "."; + return ret; + } + ret = GenerateInferResult(imgPath, BatchClsInfos); + if (ret != APP_ERR_OK) { + LogError << "Generate infer result failed, ret=" << ret << "."; + return ret; + } + + return APP_ERR_OK; +} diff --git a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/mxbase_infer/Densenet121Classify.h b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/mxbase_infer/Densenet121Classify.h index df1c7360e5..9f36834890 100644 --- a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/mxbase_infer/Densenet121Classify.h +++ b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/mxbase_infer/Densenet121Classify.h @@ -1,56 +1,56 @@ -/* - * Copyright (c) 2021. Huawei Technologies Co., Ltd. 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. - */ - -#ifndef MXBASE_DENSENET121CLASSIFY_H -#define MXBASE_DENSENET121CLASSIFY_H - -#include "MxBase/DvppWrapper/DvppWrapper.h" -#include "MxBase/ModelInfer/ModelInferenceProcessor.h" -#include "ClassPostProcessors/Resnet50PostProcess.h" -#include "MxBase/Tensor/TensorContext/TensorContext.h" - -extern std::vector g_inferCost; - -struct InitParam { - uint32_t deviceId; - std::string labelPath; - uint32_t classNum; - uint32_t topk; - bool softmax; - bool checkTensor; - std::string modelPath; -}; - -class Densenet121Classify { -public: - APP_ERROR Init(const InitParam &initParam); - APP_ERROR DeInit(); - APP_ERROR ReadImage(const std::string &imgPath, MxBase::TensorBase &tensor); - APP_ERROR Resize(const MxBase::TensorBase &input, MxBase::TensorBase &output); - APP_ERROR Inference(const std::vector &inputs, std::vector &outputs); - APP_ERROR PostProcess(const std::vector &inputs, - std::vector> &clsInfos); - APP_ERROR GenerateInferResult(const std::string &imgPath, - std::vector> &clsInfos); - APP_ERROR Process(const std::string &imgPath); -private: - std::shared_ptr dvppWrapper_; - std::shared_ptr model_; - std::shared_ptr post_; - MxBase::ModelDesc modelDesc_; - uint32_t deviceId_ = 0; -}; -#endif +/* + * Copyright (c) 2021. Huawei Technologies Co., Ltd. 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. + */ + +#ifndef MXBASE_DENSENET121CLASSIFY_H +#define MXBASE_DENSENET121CLASSIFY_H + +#include "MxBase/DvppWrapper/DvppWrapper.h" +#include "MxBase/ModelInfer/ModelInferenceProcessor.h" +#include "ClassPostProcessors/Resnet50PostProcess.h" +#include "MxBase/Tensor/TensorContext/TensorContext.h" + +extern std::vector g_inferCost; + +struct InitParam { + uint32_t deviceId; + std::string labelPath; + uint32_t classNum; + uint32_t topk; + bool softmax; + bool checkTensor; + std::string modelPath; +}; + +class Densenet121Classify { +public: + APP_ERROR Init(const InitParam &initParam); + APP_ERROR DeInit(); + APP_ERROR ReadImage(const std::string &imgPath, MxBase::TensorBase &tensor); + APP_ERROR Resize(const MxBase::TensorBase &input, MxBase::TensorBase &output); + APP_ERROR Inference(const std::vector &inputs, std::vector &outputs); + APP_ERROR PostProcess(const std::vector &inputs, + std::vector> &clsInfos); + APP_ERROR GenerateInferResult(const std::string &imgPath, + std::vector> &clsInfos); + APP_ERROR Process(const std::string &imgPath); +private: + std::shared_ptr dvppWrapper_; + std::shared_ptr model_; + std::shared_ptr post_; + MxBase::ModelDesc modelDesc_; + uint32_t deviceId_ = 0; +}; +#endif diff --git a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/mxbase_infer/main.cpp b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/mxbase_infer/main.cpp index ebf02aa12e..b4c3a9df05 100644 --- a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/mxbase_infer/main.cpp +++ b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/mxbase_infer/main.cpp @@ -1,69 +1,69 @@ -/* - * Copyright (c) 2021. Huawei Technologies Co., Ltd. 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. - */ -#include -#include -#include -#include "Densenet121Classify.h" -#include "MxBase/Log/Log.h" - -namespace fs = std::experimental::filesystem; -namespace { -const uint32_t CLASS_NUM = 1000; -} -std::vector g_inferCost; - -int main(int argc, char* argv[]) -{ - if (argc <= 3) { - LogWarn << "Please enter model path | image path | label path, such as './densenet121 " - "./models/densenet121_304.om ./imagenet_val/ ./models/imagenet1000_clsidx_to_labels.names"; - return APP_ERR_OK; - } - - InitParam initParam = {}; - initParam.deviceId = 0; - initParam.classNum = CLASS_NUM; - initParam.labelPath = argv[3]; - initParam.topk = 5; - initParam.softmax = false; - initParam.checkTensor = true; - initParam.modelPath = argv[1]; - auto densenet121 = std::make_shared(); - APP_ERROR ret = densenet121->Init(initParam); - if (ret != APP_ERR_OK) { - LogError << "Densenet121Classify init failed, ret=" << ret << "."; - return ret; - } - - std::string imgDir = argv[2]; - for (auto & entry : fs::directory_iterator(imgDir)) { - LogInfo << "read image path " << entry.path(); - ret = densenet121->Process(entry.path()); - if (ret != APP_ERR_OK) { - LogError << "Densenet121Classify process failed, ret=" << ret << "."; - densenet121->DeInit(); - return ret; - } - } - densenet121->DeInit(); - double costSum = 0; - for (unsigned int i = 0; i < g_inferCost.size(); i++) { - costSum += g_inferCost[i]; - } - LogInfo << "Infer images sum " << g_inferCost.size() << ", cost total time: " << costSum << " ms."; - LogInfo << "The throughout: " << g_inferCost.size() * 1000 / costSum << " images/sec."; - return APP_ERR_OK; -} +/* + * Copyright (c) 2021. Huawei Technologies Co., Ltd. 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. + */ +#include +#include +#include +#include "Densenet121Classify.h" +#include "MxBase/Log/Log.h" + +namespace fs = std::experimental::filesystem; +namespace { +const uint32_t CLASS_NUM = 1000; +} +std::vector g_inferCost; + +int main(int argc, char* argv[]) +{ + if (argc <= 3) { + LogWarn << "Please enter model path | image path | label path, such as './densenet121 " + "./models/densenet121_304.om ./imagenet_val/ ./models/imagenet1000_clsidx_to_labels.names"; + return APP_ERR_OK; + } + + InitParam initParam = {}; + initParam.deviceId = 0; + initParam.classNum = CLASS_NUM; + initParam.labelPath = argv[3]; + initParam.topk = 5; + initParam.softmax = false; + initParam.checkTensor = true; + initParam.modelPath = argv[1]; + auto densenet121 = std::make_shared(); + APP_ERROR ret = densenet121->Init(initParam); + if (ret != APP_ERR_OK) { + LogError << "Densenet121Classify init failed, ret=" << ret << "."; + return ret; + } + + std::string imgDir = argv[2]; + for (auto & entry : fs::directory_iterator(imgDir)) { + LogInfo << "read image path " << entry.path(); + ret = densenet121->Process(entry.path()); + if (ret != APP_ERR_OK) { + LogError << "Densenet121Classify process failed, ret=" << ret << "."; + densenet121->DeInit(); + return ret; + } + } + densenet121->DeInit(); + double costSum = 0; + for (unsigned int i = 0; i < g_inferCost.size(); i++) { + costSum += g_inferCost[i]; + } + LogInfo << "Infer images sum " << g_inferCost.size() << ", cost total time: " << costSum << " ms."; + LogInfo << "The throughout: " << g_inferCost.size() * 1000 / costSum << " images/sec."; + return APP_ERR_OK; +} diff --git a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/utils/classification_task_metric.py b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/utils/classification_task_metric.py index 9cbd93f243..afc34f0468 100644 --- a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/utils/classification_task_metric.py +++ b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/sdk_infer/utils/classification_task_metric.py @@ -1,187 +1,187 @@ -#coding = utf-8 -#Copyright 2020 Huawei Technologies Co., Ltd -# -#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 os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - img_name = temp[0].split(".")[0] - img_lab = temp[1] - img_gt_dict[img_name] = img_lab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, cls_ind in enumerate(temp): - data_vec[ind] = np.int(cls_ind) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - res_cnt = 0 - n_labels = "" - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - - ret = load_statistical_predict_result(filepath) - - prediction = ret[0] - n_labels = ret[1] - - gt = img_gt_dict[img_name] - if n_labels == 1000: - real_label = int(gt) - elif n_labels == 1001: - real_label = int(gt) + 1 - else: - real_label = int(gt) - - res_cnt = min(len(prediction), topn) - for i in range(res_cnt): - if str(real_label) == str(int(prediction[i])): - count_hit[i] += 1 - break - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(res_cnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Please enter target file folder | groud truth file | result folder | result json file name, such as" - "Such as: python3.7 classfication_task_metric.py result/ ./val_label.txt . ./result.json") - exit(1) - - if not os.path.exists(folder_davinci_target): - print("target file folder does not exist.") - exit() - - if not os.path.exists(annotation_file_path): - - print("Ground truth file does not exist.") - exit() - - if not os.path.exists(result_json_path): - print("Result folder doesn't exist.") - exit() - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) +#coding = utf-8 +#Copyright 2020 Huawei Technologies Co., Ltd +# +#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 os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + img_name = temp[0].split(".")[0] + img_lab = temp[1] + img_gt_dict[img_name] = img_lab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, cls_ind in enumerate(temp): + data_vec[ind] = np.int(cls_ind) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + res_cnt = 0 + n_labels = "" + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + + ret = load_statistical_predict_result(filepath) + + prediction = ret[0] + n_labels = ret[1] + + gt = img_gt_dict[img_name] + if n_labels == 1000: + real_label = int(gt) + elif n_labels == 1001: + real_label = int(gt) + 1 + else: + real_label = int(gt) + + res_cnt = min(len(prediction), topn) + for i in range(res_cnt): + if str(real_label) == str(int(prediction[i])): + count_hit[i] += 1 + break + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(res_cnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Please enter target file folder | groud truth file | result folder | result json file name, such as" + "Such as: python3.7 classfication_task_metric.py result/ ./val_label.txt . ./result.json") + exit(1) + + if not os.path.exists(folder_davinci_target): + print("target file folder does not exist.") + exit() + + if not os.path.exists(annotation_file_path): + + print("Ground truth file does not exist.") + exit() + + if not os.path.exists(result_json_path): + print("Result folder doesn't exist.") + exit() + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) diff --git a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/test/train_full_1p.sh b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/test/train_full_1p.sh index aee8cd7b4f..d8e17831e9 100644 --- a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/test/train_full_1p.sh +++ b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/test/train_full_1p.sh @@ -1,153 +1,153 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -#export ASCEND_SLOG_PRINT_TO_STDOUT=1 - -#集合通信参数,不需要修改 -export HCCL_WHITELIST_DISABLE=1 -export RANK_SIZE=1 -export JOB_ID=10087 -RANK_ID_START=0 -# source env.sh -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="Densenet121_ID0092_for_PyTorch" -#训练epoch -train_epochs=90 -#训练batch_size -batch_size=256 -#训练step -train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.045 - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - -#修改参数 -#sed -i "s|pass|break|g" ${cur_path}/../densenet121_1p_main.py -wait -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#训练 -nohup python3.7 ${cur_path}/../densenet121_1p_main.py \ - --workers 40 \ - --arch densenet121 \ - --npu $ASCEND_DEVICE_ID \ - --lr 0.1 \ - --momentum 0.9 \ - --amp \ - --print-freq 1 \ - --eval-freq 5 \ - --batch-size $batch_size \ - --epochs $train_epochs \ - --data $data_path > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) -#参数改回 -#sed -i "s|break|pass|g" ${cur_path}/../densenet121_1p_main.py -wait -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -#FPS=`grep -a 'FPS' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F " " '{print $NF}'|awk 'END {print}'` -FPS=`grep FPS $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F 'FPS@all' '{print $2}'|awk '{sum+=$1} END{print sum/NR}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -train_accuracy=`grep -a '* Acc@1' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "Acc@1" '{print $2}'|awk 'NR==1{max=$1;next}{max=max>$1?max:$1}END{print max}'` -` - -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +#export ASCEND_SLOG_PRINT_TO_STDOUT=1 + +#集合通信参数,不需要修改 +export HCCL_WHITELIST_DISABLE=1 +export RANK_SIZE=1 +export JOB_ID=10087 +RANK_ID_START=0 +# source env.sh +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="Densenet121_ID0092_for_PyTorch" +#训练epoch +train_epochs=90 +#训练batch_size +batch_size=256 +#训练step +train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.045 + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + +#修改参数 +#sed -i "s|pass|break|g" ${cur_path}/../densenet121_1p_main.py +wait +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#训练 +nohup python3.7 ${cur_path}/../densenet121_1p_main.py \ + --workers 40 \ + --arch densenet121 \ + --npu $ASCEND_DEVICE_ID \ + --lr 0.1 \ + --momentum 0.9 \ + --amp \ + --print-freq 1 \ + --eval-freq 5 \ + --batch-size $batch_size \ + --epochs $train_epochs \ + --data $data_path > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) +#参数改回 +#sed -i "s|break|pass|g" ${cur_path}/../densenet121_1p_main.py +wait +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +#FPS=`grep -a 'FPS' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F " " '{print $NF}'|awk 'END {print}'` +FPS=`grep FPS $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F 'FPS@all' '{print $2}'|awk '{sum+=$1} END{print sum/NR}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +train_accuracy=`grep -a '* Acc@1' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "Acc@1" '{print $2}'|awk 'NR==1{max=$1;next}{max=max>$1?max:$1}END{print max}'` +` + +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/test/train_full_8p.sh b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/test/train_full_8p.sh index 38d4c3f58f..bd734bf36d 100644 --- a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/test/train_full_8p.sh +++ b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/test/train_full_8p.sh @@ -1,168 +1,168 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` - - -#集合通信参数,不需要修改 -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 - - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -#export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="Densenet121_ID0092_for_PyTorch" -#训练epoch -train_epochs=90 -#训练batch_size -batch_size=2048 -#训练step -train_steps= -#学习率 -learning_rate= - - - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -##################创建日志输出目录,根据模型审视################## -# 模型采用非循环方式启动多卡训练,创建日志输出目录如下;采用循环方式启动多卡训练的模型,在循环中创建日志输出目录,可参考CRNN模型 -# 非循环方式下8卡训练日志输出路径中的ASCEND_DEVICE_ID默认为0,只是人为指定文件夹名称, 不涉及训练业务 -ASCEND_DEVICE_ID=0 -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi - - - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -# 绑核,不需要的绑核的模型删除,需要模型审视修改 -#let a=RANK_ID*${corenum}/${RANK_SIZE} -#let b=RANK_ID+1 -#let c=b*${corenum}/${RANK_SIZE}-1 - -#执行训练脚本,以下传参不需要修改,其他需要模型审视修改 -#--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path -for i in $(seq 0 7) -do - nohup python3.7 ${cur_path}/../densenet121_8p_main.py \ - --addr=$(hostname -I |awk '{print $1}') \ - --seed 49 \ - --workers 160 \ - --arch densenet121 \ - --lr 0.8 \ - --print-freq 1 \ - --eval-freq 5 \ - --batch-size 2048 \ - --epoch 90 \ - --dist-url 'tcp://127.0.0.1:50000' \ - --dist-backend 'hccl' \ - --multiprocessing-distributed \ - --world-size 1 \ - --rank 0 \ - --gpu $i \ - --device-list '0,1,2,3,4,5,6,7' \ - --amp \ - --benchmark 0 \ - --data $data_path > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -done -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep -a 'FPS' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F " " '{print $NF}'|awk 'END {print}'` -#FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk '{print $NF}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -train_accuracy=`grep -a '* Acc@1' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` - -#打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` + + +#集合通信参数,不需要修改 +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 + + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +#export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="Densenet121_ID0092_for_PyTorch" +#训练epoch +train_epochs=90 +#训练batch_size +batch_size=2048 +#训练step +train_steps= +#学习率 +learning_rate= + + + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +##################创建日志输出目录,根据模型审视################## +# 模型采用非循环方式启动多卡训练,创建日志输出目录如下;采用循环方式启动多卡训练的模型,在循环中创建日志输出目录,可参考CRNN模型 +# 非循环方式下8卡训练日志输出路径中的ASCEND_DEVICE_ID默认为0,只是人为指定文件夹名称, 不涉及训练业务 +ASCEND_DEVICE_ID=0 +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi + + + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +# 绑核,不需要的绑核的模型删除,需要模型审视修改 +#let a=RANK_ID*${corenum}/${RANK_SIZE} +#let b=RANK_ID+1 +#let c=b*${corenum}/${RANK_SIZE}-1 + +#执行训练脚本,以下传参不需要修改,其他需要模型审视修改 +#--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path +for i in $(seq 0 7) +do + nohup python3.7 ${cur_path}/../densenet121_8p_main.py \ + --addr=$(hostname -I |awk '{print $1}') \ + --seed 49 \ + --workers 160 \ + --arch densenet121 \ + --lr 0.8 \ + --print-freq 1 \ + --eval-freq 5 \ + --batch-size 2048 \ + --epoch 90 \ + --dist-url 'tcp://127.0.0.1:50000' \ + --dist-backend 'hccl' \ + --multiprocessing-distributed \ + --world-size 1 \ + --rank 0 \ + --gpu $i \ + --device-list '0,1,2,3,4,5,6,7' \ + --amp \ + --benchmark 0 \ + --data $data_path > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +done +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep -a 'FPS' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F " " '{print $NF}'|awk 'END {print}'` +#FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk '{print $NF}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +train_accuracy=`grep -a '* Acc@1' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` + +#打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/test/train_performance_1p.sh b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/test/train_performance_1p.sh index 12c3708f59..ed6cd11f6c 100644 --- a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/test/train_performance_1p.sh +++ b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/test/train_performance_1p.sh @@ -1,152 +1,152 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -#export ASCEND_SLOG_PRINT_TO_STDOUT=1 - -#集合通信参数,不需要修改 -export HCCL_WHITELIST_DISABLE=1 -export RANK_SIZE=1 -export JOB_ID=10087 -RANK_ID_START=0 -# source env.sh -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="Densenet121_ID0092_for_PyTorch" -#训练epoch -train_epochs=1 -#训练batch_size -batch_size=256 -#训练step -train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.045 - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - -#修改参数 -sed -i "s|pass|break|g" ${cur_path}/../densenet121_1p_main.py -wait -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#训练 -nohup python3.7 ${cur_path}/../densenet121_1p_main.py \ - --workers 40 \ - --arch densenet121 \ - --npu $ASCEND_DEVICE_ID \ - --lr 0.1 \ - --momentum 0.9 \ - --amp \ - --print-freq 1 \ - --eval-freq 5 \ - --batch-size $batch_size \ - --epochs $train_epochs \ - --stop-step-num 50 \ - --data $data_path > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) -#参数改回 -sed -i "s|break|pass|g" ${cur_path}/../densenet121_1p_main.py -wait -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -#FPS=`grep -a 'FPS' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F " " '{print $NF}'|awk 'END {print}'` -FPS=`grep FPS $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F 'FPS@all' '{print $2}'|awk '{sum+=$1} END{print sum/NR}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep -a '* Acc@1' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` - -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +#export ASCEND_SLOG_PRINT_TO_STDOUT=1 + +#集合通信参数,不需要修改 +export HCCL_WHITELIST_DISABLE=1 +export RANK_SIZE=1 +export JOB_ID=10087 +RANK_ID_START=0 +# source env.sh +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="Densenet121_ID0092_for_PyTorch" +#训练epoch +train_epochs=1 +#训练batch_size +batch_size=256 +#训练step +train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.045 + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + +#修改参数 +sed -i "s|pass|break|g" ${cur_path}/../densenet121_1p_main.py +wait +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#训练 +nohup python3.7 ${cur_path}/../densenet121_1p_main.py \ + --workers 40 \ + --arch densenet121 \ + --npu $ASCEND_DEVICE_ID \ + --lr 0.1 \ + --momentum 0.9 \ + --amp \ + --print-freq 1 \ + --eval-freq 5 \ + --batch-size $batch_size \ + --epochs $train_epochs \ + --stop-step-num 50 \ + --data $data_path > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) +#参数改回 +sed -i "s|break|pass|g" ${cur_path}/../densenet121_1p_main.py +wait +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +#FPS=`grep -a 'FPS' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F " " '{print $NF}'|awk 'END {print}'` +FPS=`grep FPS $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F 'FPS@all' '{print $2}'|awk '{sum+=$1} END{print sum/NR}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep -a '* Acc@1' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` + +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/test/train_performance_8p.sh b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/test/train_performance_8p.sh index 5684bec213..e2002aa81e 100644 --- a/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/test/train_performance_8p.sh +++ b/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch/test/train_performance_8p.sh @@ -1,172 +1,172 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -#export ASCEND_SLOG_PRINT_TO_STDOUT=1 - -export SOC_VERSION=Ascend910 -export HCCL_CONNECT_TIMEOUT=600 - -#集合通信参数,不需要修改 -export HCCL_WHITELIST_DISABLE=1 -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 -# source env.sh -RANK_SIZE=8 -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -# export ASCEND_GLOBAL_LOG_LEVEL_ETP_ETP_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="Densenet121_ID0092_for_PyTorch" -#训练epoch -train_epochs=1 -#训练batch_size -batch_size=2048 -#训练step -train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.045 - - - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - -#修改参数 -sed -i "s|pass|break|g" ${cur_path}/../densenet121_8p_main.py -wait -#训练开始时间,不需要修改 -start_time=$(date +%s) - -# 绑核,不需要的绑核的模型删除,需要模型审视修改 -corenum=`cat /proc/cpuinfo |grep "processor"|wc -l` -for i in $(seq 0 7) -do -let p_start=0+24*i -let p_end=23+24*i -nohup taskset -c $p_start-$p_end python3.7 ${cur_path}/../densenet121_8p_main.py \ - --addr=$(hostname -I |awk '{print $1}') \ - --seed 49 \ - --workers 160 \ - --arch densenet121 \ - --lr 0.8 \ - --print-freq 1 \ - --eval-freq 5 \ - --batch-size $batch_size \ - --epochs $train_epochs \ - --dist-url 'tcp://127.0.0.1:50000' \ - --dist-backend 'hccl' \ - --multiprocessing-distributed \ - --world-size 1 \ - --rank 0 \ - --gpu $i \ - --device-list '0,1,2,3,4,5,6,7' \ - --amp \ - --benchmark 0 \ - --data $data_path > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -done -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) -#参数改回 -sed -i "s|break|pass|g" ${cur_path}/../densenet121_8p_main.py -wait -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -#FPS=`grep -a 'FPS' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F " " '{print $NF}'|awk 'END {print}'` -FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk '{print $NF}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep -a '* Acc@1' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` - -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +#export ASCEND_SLOG_PRINT_TO_STDOUT=1 + +export SOC_VERSION=Ascend910 +export HCCL_CONNECT_TIMEOUT=600 + +#集合通信参数,不需要修改 +export HCCL_WHITELIST_DISABLE=1 +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 +# source env.sh +RANK_SIZE=8 +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +# export ASCEND_GLOBAL_LOG_LEVEL_ETP_ETP_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="Densenet121_ID0092_for_PyTorch" +#训练epoch +train_epochs=1 +#训练batch_size +batch_size=2048 +#训练step +train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.045 + + + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + +#修改参数 +sed -i "s|pass|break|g" ${cur_path}/../densenet121_8p_main.py +wait +#训练开始时间,不需要修改 +start_time=$(date +%s) + +# 绑核,不需要的绑核的模型删除,需要模型审视修改 +corenum=`cat /proc/cpuinfo |grep "processor"|wc -l` +for i in $(seq 0 7) +do +let p_start=0+24*i +let p_end=23+24*i +nohup taskset -c $p_start-$p_end python3.7 ${cur_path}/../densenet121_8p_main.py \ + --addr=$(hostname -I |awk '{print $1}') \ + --seed 49 \ + --workers 160 \ + --arch densenet121 \ + --lr 0.8 \ + --print-freq 1 \ + --eval-freq 5 \ + --batch-size $batch_size \ + --epochs $train_epochs \ + --dist-url 'tcp://127.0.0.1:50000' \ + --dist-backend 'hccl' \ + --multiprocessing-distributed \ + --world-size 1 \ + --rank 0 \ + --gpu $i \ + --device-list '0,1,2,3,4,5,6,7' \ + --amp \ + --benchmark 0 \ + --data $data_path > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +done +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) +#参数改回 +sed -i "s|break|pass|g" ${cur_path}/../densenet121_8p_main.py +wait +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +#FPS=`grep -a 'FPS' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F " " '{print $NF}'|awk 'END {print}'` +FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk '{print $NF}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep -a '* Acc@1' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` + +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/LICENSE b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/LICENSE index 75b52484ea..d645695673 100644 --- a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/LICENSE +++ b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/LICENSE @@ -1,202 +1,202 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/__init__.py b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/__init__.py index 1046fb2b29..d475531251 100644 --- a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/__init__.py +++ b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/__init__.py @@ -1,228 +1,228 @@ -# Apache License -# Version 2.0, January 2004 -# http://www.apache.org/licenses/ -# -# TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -# -# 1. Definitions. -# -# "License" shall mean the terms and conditions for use, reproduction, -# and distribution as defined by Sections 1 through 9 of this document. -# -# "Licensor" shall mean the copyright owner or entity authorized by -# the copyright owner that is granting the License. -# -# "Legal Entity" shall mean the union of the acting entity and all -# other entities that control, are controlled by, or are under common -# control with that entity. For the purposes of this definition, -# "control" means (i) the power, direct or indirect, to cause the -# direction or management of such entity, whether by contract or -# otherwise, or (ii) ownership of fifty percent (50%) or more of the -# outstanding shares, or (iii) beneficial ownership of such entity. -# -# "You" (or "Your") shall mean an individual or Legal Entity -# exercising permissions granted by this License. -# -# "Source" form shall mean the preferred form for making modifications, -# including but not limited to software source code, documentation -# source, and configuration files. -# -# "Object" form shall mean any form resulting from mechanical -# transformation or translation of a Source form, including but -# not limited to compiled object code, generated documentation, -# and conversions to other media types. -# -# "Work" shall mean the work of authorship, whether in Source or -# Object form, made available under the License, as indicated by a -# copyright notice that is included in or attached to the work -# (an example is provided in the Appendix below). -# -# "Derivative Works" shall mean any work, whether in Source or Object -# form, that is based on (or derived from) the Work and for which the -# editorial revisions, annotations, elaborations, or other modifications -# represent, as a whole, an original work of authorship. For the purposes -# of this License, Derivative Works shall not include works that remain -# separable from, or merely link (or bind by name) to the interfaces of, -# the Work and Derivative Works thereof. -# -# "Contribution" shall mean any work of authorship, including -# the original version of the Work and any modifications or additions -# to that Work or Derivative Works thereof, that is intentionally -# submitted to Licensor for inclusion in the Work by the copyright owner -# or by an individual or Legal Entity authorized to submit on behalf of -# the copyright owner. For the purposes of this definition, "submitted" -# means any form of electronic, verbal, or written communication sent -# to the Licensor or its representatives, including but not limited to -# communication on electronic mailing lists, source code control systems, -# and issue tracking systems that are managed by, or on behalf of, the -# Licensor for the purpose of discussing and improving the Work, but -# excluding communication that is conspicuously marked or otherwise -# designated in writing by the copyright owner as "Not a Contribution." -# -# "Contributor" shall mean Licensor and any individual or Legal Entity -# on behalf of whom a Contribution has been received by Licensor and -# subsequently incorporated within the Work. -# -# 2. Grant of Copyright License. Subject to the terms and conditions of -# this License, each Contributor hereby grants to You a perpetual, -# worldwide, non-exclusive, no-charge, royalty-free, irrevocable -# copyright license to reproduce, prepare Derivative Works of, -# publicly display, publicly perform, sublicense, and distribute the -# Work and such Derivative Works in Source or Object form. -# -# 3. Grant of Patent License. Subject to the terms and conditions of -# this License, each Contributor hereby grants to You a perpetual, -# worldwide, non-exclusive, no-charge, royalty-free, irrevocable -# (except as stated in this section) patent license to make, have made, -# use, offer to sell, sell, import, and otherwise transfer the Work, -# where such license applies only to those patent claims licensable -# by such Contributor that are necessarily infringed by their -# Contribution(s) alone or by combination of their Contribution(s) -# with the Work to which such Contribution(s) was submitted. If You -# institute patent litigation against any entity (including a -# cross-claim or counterclaim in a lawsuit) alleging that the Work -# or a Contribution incorporated within the Work constitutes direct -# or contributory patent infringement, then any patent licenses -# granted to You under this License for that Work shall terminate -# as of the date such litigation is filed. -# -# 4. Redistribution. You may reproduce and distribute copies of the -# Work or Derivative Works thereof in any medium, with or without -# modifications, and in Source or Object form, provided that You -# meet the following conditions: -# -# (a) You must give any other recipients of the Work or -# Derivative Works a copy of this License; and -# -# (b) You must cause any modified files to carry prominent notices -# stating that You changed the files; and -# -# (c) You must retain, in the Source form of any Derivative Works -# that You distribute, all copyright, patent, trademark, and -# attribution notices from the Source form of the Work, -# excluding those notices that do not pertain to any part of -# the Derivative Works; and -# -# (d) If the Work includes a "NOTICE" text file as part of its -# distribution, then any Derivative Works that You distribute must -# include a readable copy of the attribution notices contained -# within such NOTICE file, excluding those notices that do not -# pertain to any part of the Derivative Works, in at least one -# of the following places: within a NOTICE text file distributed -# as part of the Derivative Works; within the Source form or -# documentation, if provided along with the Derivative Works; or, -# within a display generated by the Derivative Works, if and -# wherever such third-party notices normally appear. The contents -# of the NOTICE file are for informational purposes only and -# do not modify the License. You may add Your own attribution -# notices within Derivative Works that You distribute, alongside -# or as an addendum to the NOTICE text from the Work, provided -# that such additional attribution notices cannot be construed -# as modifying the License. -# -# You may add Your own copyright statement to Your modifications and -# may provide additional or different license terms and conditions -# for use, reproduction, or distribution of Your modifications, or -# for any such Derivative Works as a whole, provided Your use, -# reproduction, and distribution of the Work otherwise complies with -# the conditions stated in this License. -# -# 5. Submission of Contributions. Unless You explicitly state otherwise, -# any Contribution intentionally submitted for inclusion in the Work -# by You to the Licensor shall be under the terms and conditions of -# this License, without any additional terms or conditions. -# Notwithstanding the above, nothing herein shall supersede or modify -# the terms of any separate license agreement you may have executed -# with Licensor regarding such Contributions. -# -# 6. Trademarks. This License does not grant permission to use the trade -# names, trademarks, service marks, or product names of the Licensor, -# except as required for reasonable and customary use in describing the -# origin of the Work and reproducing the content of the NOTICE file. -# -# 7. Disclaimer of Warranty. Unless required by applicable law or -# agreed to in writing, Licensor provides the Work (and each -# Contributor provides its Contributions) on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied, including, without limitation, any warranties or conditions -# of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -# PARTICULAR PURPOSE. You are solely responsible for determining the -# appropriateness of using or redistributing the Work and assume any -# risks associated with Your exercise of permissions under this License. -# -# 8. Limitation of Liability. In no event and under no legal theory, -# whether in tort (including negligence), contract, or otherwise, -# unless required by applicable law (such as deliberate and grossly -# negligent acts) or agreed to in writing, shall any Contributor be -# liable to You for damages, including any direct, indirect, special, -# incidental, or consequential damages of any character arising as a -# result of this License or out of the use or inability to use the -# Work (including but not limited to damages for loss of goodwill, -# work stoppage, computer failure or malfunction, or any and all -# other commercial damages or losses), even if such Contributor -# has been advised of the possibility of such damages. -# -# 9. Accepting Warranty or Additional Liability. While redistributing -# the Work or Derivative Works thereof, You may choose to offer, -# and charge a fee for, acceptance of support, warranty, indemnity, -# or other liability obligations and/or rights consistent with this -# License. However, in accepting such obligations, You may act only -# on Your own behalf and on Your sole responsibility, not on behalf -# of any other Contributor, and only if You agree to indemnify, -# defend, and hold each Contributor harmless for any liability -# incurred by, or claims asserted against, such Contributor by reason -# of your accepting any such warranty or additional liability. -# -# END OF TERMS AND CONDITIONS -# -# APPENDIX: How to apply the Apache License to your work. -# -# To apply the Apache License to your work, attach the following -# boilerplate notice, with the fields enclosed by brackets "[]" -# replaced with your own identifying information. (Don't include -# the brackets!) The text should be enclosed in the appropriate -# comment syntax for the file format. We also recommend that a -# file or class name and description of purpose be included on the -# same "printed page" as the copyright notice for easier -# identification within third-party archives. -# -# Copyright [yyyy] [name of copyright owner] -# -# 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. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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. - -__version__ = "0.7.0" -from .model import EfficientNet -from .utils import ( - GlobalParams, - BlockArgs, - BlockDecoder, - efficientnet, - get_model_params, -) -from .auto_augment import rand_augment_transform, augment_and_mix_transform, auto_augment_transform -from .rmsprop_tf import RMSpropTF - +# Apache License +# Version 2.0, January 2004 +# http://www.apache.org/licenses/ +# +# TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +# +# 1. Definitions. +# +# "License" shall mean the terms and conditions for use, reproduction, +# and distribution as defined by Sections 1 through 9 of this document. +# +# "Licensor" shall mean the copyright owner or entity authorized by +# the copyright owner that is granting the License. +# +# "Legal Entity" shall mean the union of the acting entity and all +# other entities that control, are controlled by, or are under common +# control with that entity. For the purposes of this definition, +# "control" means (i) the power, direct or indirect, to cause the +# direction or management of such entity, whether by contract or +# otherwise, or (ii) ownership of fifty percent (50%) or more of the +# outstanding shares, or (iii) beneficial ownership of such entity. +# +# "You" (or "Your") shall mean an individual or Legal Entity +# exercising permissions granted by this License. +# +# "Source" form shall mean the preferred form for making modifications, +# including but not limited to software source code, documentation +# source, and configuration files. +# +# "Object" form shall mean any form resulting from mechanical +# transformation or translation of a Source form, including but +# not limited to compiled object code, generated documentation, +# and conversions to other media types. +# +# "Work" shall mean the work of authorship, whether in Source or +# Object form, made available under the License, as indicated by a +# copyright notice that is included in or attached to the work +# (an example is provided in the Appendix below). +# +# "Derivative Works" shall mean any work, whether in Source or Object +# form, that is based on (or derived from) the Work and for which the +# editorial revisions, annotations, elaborations, or other modifications +# represent, as a whole, an original work of authorship. For the purposes +# of this License, Derivative Works shall not include works that remain +# separable from, or merely link (or bind by name) to the interfaces of, +# the Work and Derivative Works thereof. +# +# "Contribution" shall mean any work of authorship, including +# the original version of the Work and any modifications or additions +# to that Work or Derivative Works thereof, that is intentionally +# submitted to Licensor for inclusion in the Work by the copyright owner +# or by an individual or Legal Entity authorized to submit on behalf of +# the copyright owner. For the purposes of this definition, "submitted" +# means any form of electronic, verbal, or written communication sent +# to the Licensor or its representatives, including but not limited to +# communication on electronic mailing lists, source code control systems, +# and issue tracking systems that are managed by, or on behalf of, the +# Licensor for the purpose of discussing and improving the Work, but +# excluding communication that is conspicuously marked or otherwise +# designated in writing by the copyright owner as "Not a Contribution." +# +# "Contributor" shall mean Licensor and any individual or Legal Entity +# on behalf of whom a Contribution has been received by Licensor and +# subsequently incorporated within the Work. +# +# 2. Grant of Copyright License. Subject to the terms and conditions of +# this License, each Contributor hereby grants to You a perpetual, +# worldwide, non-exclusive, no-charge, royalty-free, irrevocable +# copyright license to reproduce, prepare Derivative Works of, +# publicly display, publicly perform, sublicense, and distribute the +# Work and such Derivative Works in Source or Object form. +# +# 3. Grant of Patent License. Subject to the terms and conditions of +# this License, each Contributor hereby grants to You a perpetual, +# worldwide, non-exclusive, no-charge, royalty-free, irrevocable +# (except as stated in this section) patent license to make, have made, +# use, offer to sell, sell, import, and otherwise transfer the Work, +# where such license applies only to those patent claims licensable +# by such Contributor that are necessarily infringed by their +# Contribution(s) alone or by combination of their Contribution(s) +# with the Work to which such Contribution(s) was submitted. If You +# institute patent litigation against any entity (including a +# cross-claim or counterclaim in a lawsuit) alleging that the Work +# or a Contribution incorporated within the Work constitutes direct +# or contributory patent infringement, then any patent licenses +# granted to You under this License for that Work shall terminate +# as of the date such litigation is filed. +# +# 4. Redistribution. You may reproduce and distribute copies of the +# Work or Derivative Works thereof in any medium, with or without +# modifications, and in Source or Object form, provided that You +# meet the following conditions: +# +# (a) You must give any other recipients of the Work or +# Derivative Works a copy of this License; and +# +# (b) You must cause any modified files to carry prominent notices +# stating that You changed the files; and +# +# (c) You must retain, in the Source form of any Derivative Works +# that You distribute, all copyright, patent, trademark, and +# attribution notices from the Source form of the Work, +# excluding those notices that do not pertain to any part of +# the Derivative Works; and +# +# (d) If the Work includes a "NOTICE" text file as part of its +# distribution, then any Derivative Works that You distribute must +# include a readable copy of the attribution notices contained +# within such NOTICE file, excluding those notices that do not +# pertain to any part of the Derivative Works, in at least one +# of the following places: within a NOTICE text file distributed +# as part of the Derivative Works; within the Source form or +# documentation, if provided along with the Derivative Works; or, +# within a display generated by the Derivative Works, if and +# wherever such third-party notices normally appear. The contents +# of the NOTICE file are for informational purposes only and +# do not modify the License. You may add Your own attribution +# notices within Derivative Works that You distribute, alongside +# or as an addendum to the NOTICE text from the Work, provided +# that such additional attribution notices cannot be construed +# as modifying the License. +# +# You may add Your own copyright statement to Your modifications and +# may provide additional or different license terms and conditions +# for use, reproduction, or distribution of Your modifications, or +# for any such Derivative Works as a whole, provided Your use, +# reproduction, and distribution of the Work otherwise complies with +# the conditions stated in this License. +# +# 5. Submission of Contributions. Unless You explicitly state otherwise, +# any Contribution intentionally submitted for inclusion in the Work +# by You to the Licensor shall be under the terms and conditions of +# this License, without any additional terms or conditions. +# Notwithstanding the above, nothing herein shall supersede or modify +# the terms of any separate license agreement you may have executed +# with Licensor regarding such Contributions. +# +# 6. Trademarks. This License does not grant permission to use the trade +# names, trademarks, service marks, or product names of the Licensor, +# except as required for reasonable and customary use in describing the +# origin of the Work and reproducing the content of the NOTICE file. +# +# 7. Disclaimer of Warranty. Unless required by applicable law or +# agreed to in writing, Licensor provides the Work (and each +# Contributor provides its Contributions) on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied, including, without limitation, any warranties or conditions +# of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +# PARTICULAR PURPOSE. You are solely responsible for determining the +# appropriateness of using or redistributing the Work and assume any +# risks associated with Your exercise of permissions under this License. +# +# 8. Limitation of Liability. In no event and under no legal theory, +# whether in tort (including negligence), contract, or otherwise, +# unless required by applicable law (such as deliberate and grossly +# negligent acts) or agreed to in writing, shall any Contributor be +# liable to You for damages, including any direct, indirect, special, +# incidental, or consequential damages of any character arising as a +# result of this License or out of the use or inability to use the +# Work (including but not limited to damages for loss of goodwill, +# work stoppage, computer failure or malfunction, or any and all +# other commercial damages or losses), even if such Contributor +# has been advised of the possibility of such damages. +# +# 9. Accepting Warranty or Additional Liability. While redistributing +# the Work or Derivative Works thereof, You may choose to offer, +# and charge a fee for, acceptance of support, warranty, indemnity, +# or other liability obligations and/or rights consistent with this +# License. However, in accepting such obligations, You may act only +# on Your own behalf and on Your sole responsibility, not on behalf +# of any other Contributor, and only if You agree to indemnify, +# defend, and hold each Contributor harmless for any liability +# incurred by, or claims asserted against, such Contributor by reason +# of your accepting any such warranty or additional liability. +# +# END OF TERMS AND CONDITIONS +# +# APPENDIX: How to apply the Apache License to your work. +# +# To apply the Apache License to your work, attach the following +# boilerplate notice, with the fields enclosed by brackets "[]" +# replaced with your own identifying information. (Don't include +# the brackets!) The text should be enclosed in the appropriate +# comment syntax for the file format. We also recommend that a +# file or class name and description of purpose be included on the +# same "printed page" as the copyright notice for easier +# identification within third-party archives. +# +# Copyright [yyyy] [name of copyright owner] +# +# 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. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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. + +__version__ = "0.7.0" +from .model import EfficientNet +from .utils import ( + GlobalParams, + BlockArgs, + BlockDecoder, + efficientnet, + get_model_params, +) +from .auto_augment import rand_augment_transform, augment_and_mix_transform, auto_augment_transform +from .rmsprop_tf import RMSpropTF + diff --git a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/auto_augment.py b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/auto_augment.py index e063d63e1a..071c49771c 100644 --- a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/auto_augment.py +++ b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/auto_augment.py @@ -1,813 +1,813 @@ -# Copyright [yyyy] [name of copyright owner] -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 random -import math -import re -from PIL import Image, ImageOps, ImageEnhance, ImageChops -import PIL -import numpy as np - - -_PIL_VER = tuple([int(x) for x in PIL.__version__.split('.')[:2]]) - -_FILL = (128, 128, 128) - -# This signifies the max integer that the controller RNN could predict for the -# augmentation scheme. -_MAX_LEVEL = 10. - -_HPARAMS_DEFAULT = dict( - translate_const=250, - img_mean=_FILL, -) - -_RANDOM_INTERPOLATION = (Image.BILINEAR, Image.BICUBIC) - - -def _interpolation(kwargs): - interpolation = kwargs.pop('resample', Image.BILINEAR) - if isinstance(interpolation, (list, tuple)): - return random.choice(interpolation) - else: - return interpolation - - -def _check_args_tf(kwargs): - if 'fillcolor' in kwargs and _PIL_VER < (5, 0): - kwargs.pop('fillcolor') - kwargs['resample'] = _interpolation(kwargs) - - -def shear_x(img, factor, **kwargs): - _check_args_tf(kwargs) - return img.transform(img.size, Image.AFFINE, (1, factor, 0, 0, 1, 0), **kwargs) - - -def shear_y(img, factor, **kwargs): - _check_args_tf(kwargs) - return img.transform(img.size, Image.AFFINE, (1, 0, 0, factor, 1, 0), **kwargs) - - -def translate_x_rel(img, pct, **kwargs): - pixels = pct * img.size[0] - _check_args_tf(kwargs) - return img.transform(img.size, Image.AFFINE, (1, 0, pixels, 0, 1, 0), **kwargs) - - -def translate_y_rel(img, pct, **kwargs): - pixels = pct * img.size[1] - _check_args_tf(kwargs) - return img.transform(img.size, Image.AFFINE, (1, 0, 0, 0, 1, pixels), **kwargs) - - -def translate_x_abs(img, pixels, **kwargs): - _check_args_tf(kwargs) - return img.transform(img.size, Image.AFFINE, (1, 0, pixels, 0, 1, 0), **kwargs) - - -def translate_y_abs(img, pixels, **kwargs): - _check_args_tf(kwargs) - return img.transform(img.size, Image.AFFINE, (1, 0, 0, 0, 1, pixels), **kwargs) - - -def rotate(img, degrees, **kwargs): - _check_args_tf(kwargs) - if _PIL_VER >= (5, 2): - return img.rotate(degrees, **kwargs) - elif _PIL_VER >= (5, 0): - w, h = img.size - post_trans = (0, 0) - rotn_center = (w / 2.0, h / 2.0) - angle = -math.radians(degrees) - matrix = [ - round(math.cos(angle), 15), - round(math.sin(angle), 15), - 0.0, - round(-math.sin(angle), 15), - round(math.cos(angle), 15), - 0.0, - ] - - def transform(x, y, matrix): - (a, b, c, d, e, f) = matrix - return a * x + b * y + c, d * x + e * y + f - - matrix[2], matrix[5] = transform( - -rotn_center[0] - post_trans[0], -rotn_center[1] - post_trans[1], matrix - ) - matrix[2] += rotn_center[0] - matrix[5] += rotn_center[1] - return img.transform(img.size, Image.AFFINE, matrix, **kwargs) - else: - return img.rotate(degrees, resample=kwargs['resample']) - - -def auto_contrast(img, **__): - return ImageOps.autocontrast(img) - - -def invert(img, **__): - return ImageOps.invert(img) - - -def equalize(img, **__): - return ImageOps.equalize(img) - - -def solarize(img, thresh, **__): - return ImageOps.solarize(img, thresh) - - -def solarize_add(img, add, thresh=128, **__): - lut = [] - for i in range(256): - if i < thresh: - lut.append(min(255, i + add)) - else: - lut.append(i) - if img.mode in ("L", "RGB"): - if img.mode == "RGB" and len(lut) == 256: - lut = lut + lut + lut - return img.point(lut) - else: - return img - - -def posterize(img, bits_to_keep, **__): - if bits_to_keep >= 8: - return img - return ImageOps.posterize(img, bits_to_keep) - - -def contrast(img, factor, **__): - return ImageEnhance.Contrast(img).enhance(factor) - - -def color(img, factor, **__): - return ImageEnhance.Color(img).enhance(factor) - - -def brightness(img, factor, **__): - return ImageEnhance.Brightness(img).enhance(factor) - - -def sharpness(img, factor, **__): - return ImageEnhance.Sharpness(img).enhance(factor) - - -def _randomly_negate(v): - """With 50% prob, negate the value""" - return -v if random.random() > 0.5 else v - - -def _rotate_level_to_arg(level, _hparams): - # range [-30, 30] - level = (level / _MAX_LEVEL) * 30. - level = _randomly_negate(level) - return level, - - -def _enhance_level_to_arg(level, _hparams): - # range [0.1, 1.9] - return (level / _MAX_LEVEL) * 1.8 + 0.1, - - -def _enhance_increasing_level_to_arg(level, _hparams): - # the 'no change' level is 1.0, moving away from that towards 0. or 2.0 increases the enhancement blend - # range [0.1, 1.9] - level = (level / _MAX_LEVEL) * .9 - level = 1.0 + _randomly_negate(level) - return level, - - -def _shear_level_to_arg(level, _hparams): - # range [-0.3, 0.3] - level = (level / _MAX_LEVEL) * 0.3 - level = _randomly_negate(level) - return level, - - -def _translate_abs_level_to_arg(level, hparams): - translate_const = hparams['translate_const'] - level = (level / _MAX_LEVEL) * float(translate_const) - level = _randomly_negate(level) - return level, - - -def _translate_rel_level_to_arg(level, hparams): - # default range [-0.45, 0.45] - translate_pct = hparams.get('translate_pct', 0.45) - level = (level / _MAX_LEVEL) * translate_pct - level = _randomly_negate(level) - return level, - - -def _posterize_level_to_arg(level, _hparams): - # As per Tensorflow TPU EfficientNet impl - # range [0, 4], 'keep 0 up to 4 MSB of original image' - # intensity/severity of augmentation decreases with level - return int((level / _MAX_LEVEL) * 4), - - -def _posterize_increasing_level_to_arg(level, hparams): - # As per Tensorflow models research and UDA impl - # range [4, 0], 'keep 4 down to 0 MSB of original image', - # intensity/severity of augmentation increases with level - return 4 - _posterize_level_to_arg(level, hparams)[0], - - -def _posterize_original_level_to_arg(level, _hparams): - # As per original AutoAugment paper description - # range [4, 8], 'keep 4 up to 8 MSB of image' - # intensity/severity of augmentation decreases with level - return int((level / _MAX_LEVEL) * 4) + 4, - - -def _solarize_level_to_arg(level, _hparams): - # range [0, 256] - # intensity/severity of augmentation decreases with level - return int((level / _MAX_LEVEL) * 256), - - -def _solarize_increasing_level_to_arg(level, _hparams): - # range [0, 256] - # intensity/severity of augmentation increases with level - return 256 - _solarize_level_to_arg(level, _hparams)[0], - - -def _solarize_add_level_to_arg(level, _hparams): - # range [0, 110] - return int((level / _MAX_LEVEL) * 110), - - -LEVEL_TO_ARG = { - 'AutoContrast': None, - 'Equalize': None, - 'Invert': None, - 'Rotate': _rotate_level_to_arg, - # There are several variations of the posterize level scaling in various Tensorflow/Google repositories/papers - 'Posterize': _posterize_level_to_arg, - 'PosterizeIncreasing': _posterize_increasing_level_to_arg, - 'PosterizeOriginal': _posterize_original_level_to_arg, - 'Solarize': _solarize_level_to_arg, - 'SolarizeIncreasing': _solarize_increasing_level_to_arg, - 'SolarizeAdd': _solarize_add_level_to_arg, - 'Color': _enhance_level_to_arg, - 'ColorIncreasing': _enhance_increasing_level_to_arg, - 'Contrast': _enhance_level_to_arg, - 'ContrastIncreasing': _enhance_increasing_level_to_arg, - 'Brightness': _enhance_level_to_arg, - 'BrightnessIncreasing': _enhance_increasing_level_to_arg, - 'Sharpness': _enhance_level_to_arg, - 'SharpnessIncreasing': _enhance_increasing_level_to_arg, - 'ShearX': _shear_level_to_arg, - 'ShearY': _shear_level_to_arg, - 'TranslateX': _translate_abs_level_to_arg, - 'TranslateY': _translate_abs_level_to_arg, - 'TranslateXRel': _translate_rel_level_to_arg, - 'TranslateYRel': _translate_rel_level_to_arg, -} - - -NAME_TO_OP = { - 'AutoContrast': auto_contrast, - 'Equalize': equalize, - 'Invert': invert, - 'Rotate': rotate, - 'Posterize': posterize, - 'PosterizeIncreasing': posterize, - 'PosterizeOriginal': posterize, - 'Solarize': solarize, - 'SolarizeIncreasing': solarize, - 'SolarizeAdd': solarize_add, - 'Color': color, - 'ColorIncreasing': color, - 'Contrast': contrast, - 'ContrastIncreasing': contrast, - 'Brightness': brightness, - 'BrightnessIncreasing': brightness, - 'Sharpness': sharpness, - 'SharpnessIncreasing': sharpness, - 'ShearX': shear_x, - 'ShearY': shear_y, - 'TranslateX': translate_x_abs, - 'TranslateY': translate_y_abs, - 'TranslateXRel': translate_x_rel, - 'TranslateYRel': translate_y_rel, -} - - -class AugmentOp: - - def __init__(self, name, prob=0.5, magnitude=10, hparams=None): - hparams = hparams or _HPARAMS_DEFAULT - self.aug_fn = NAME_TO_OP[name] - self.level_fn = LEVEL_TO_ARG[name] - self.prob = prob - self.magnitude = magnitude - self.hparams = hparams.copy() - self.kwargs = dict( - fillcolor=hparams['img_mean'] if 'img_mean' in hparams else _FILL, - resample=hparams['interpolation'] if 'interpolation' in hparams else _RANDOM_INTERPOLATION, - ) - - # If magnitude_std is > 0, we introduce some randomness - # in the usually fixed policy and sample magnitude from a normal distribution - # with mean `magnitude` and std-dev of `magnitude_std`. - # NOTE This is my own hack, being tested, not in papers or reference impls. - self.magnitude_std = self.hparams.get('magnitude_std', 0) - - def __call__(self, img): - if self.prob < 1.0 and random.random() > self.prob: - return img - magnitude = self.magnitude - if self.magnitude_std and self.magnitude_std > 0: - magnitude = random.gauss(magnitude, self.magnitude_std) - magnitude = min(_MAX_LEVEL, max(0, magnitude)) # clip to valid range - level_args = self.level_fn(magnitude, self.hparams) if self.level_fn is not None else tuple() - return self.aug_fn(img, *level_args, **self.kwargs) - - -def auto_augment_policy_v0(hparams): - # ImageNet v0 policy from TPU EfficientNet impl, cannot find a paper reference. - policy = [ - [('Equalize', 0.8, 1), ('ShearY', 0.8, 4)], - [('Color', 0.4, 9), ('Equalize', 0.6, 3)], - [('Color', 0.4, 1), ('Rotate', 0.6, 8)], - [('Solarize', 0.8, 3), ('Equalize', 0.4, 7)], - [('Solarize', 0.4, 2), ('Solarize', 0.6, 2)], - [('Color', 0.2, 0), ('Equalize', 0.8, 8)], - [('Equalize', 0.4, 8), ('SolarizeAdd', 0.8, 3)], - [('ShearX', 0.2, 9), ('Rotate', 0.6, 8)], - [('Color', 0.6, 1), ('Equalize', 1.0, 2)], - [('Invert', 0.4, 9), ('Rotate', 0.6, 0)], - [('Equalize', 1.0, 9), ('ShearY', 0.6, 3)], - [('Color', 0.4, 7), ('Equalize', 0.6, 0)], - [('Posterize', 0.4, 6), ('AutoContrast', 0.4, 7)], - [('Solarize', 0.6, 8), ('Color', 0.6, 9)], - [('Solarize', 0.2, 4), ('Rotate', 0.8, 9)], - [('Rotate', 1.0, 7), ('TranslateYRel', 0.8, 9)], - [('ShearX', 0.0, 0), ('Solarize', 0.8, 4)], - [('ShearY', 0.8, 0), ('Color', 0.6, 4)], - [('Color', 1.0, 0), ('Rotate', 0.6, 2)], - [('Equalize', 0.8, 4), ('Equalize', 0.0, 8)], - [('Equalize', 1.0, 4), ('AutoContrast', 0.6, 2)], - [('ShearY', 0.4, 7), ('SolarizeAdd', 0.6, 7)], - [('Posterize', 0.8, 2), ('Solarize', 0.6, 10)], # This results in black image with Tpu posterize - [('Solarize', 0.6, 8), ('Equalize', 0.6, 1)], - [('Color', 0.8, 6), ('Rotate', 0.4, 5)], - ] - pc = [[AugmentOp(*a, hparams=hparams) for a in sp] for sp in policy] - return pc - - -def auto_augment_policy_v0r(hparams): - # ImageNet v0 policy from TPU EfficientNet impl, with variation of Posterize used - # in Google research implementation (number of bits discarded increases with magnitude) - policy = [ - [('Equalize', 0.8, 1), ('ShearY', 0.8, 4)], - [('Color', 0.4, 9), ('Equalize', 0.6, 3)], - [('Color', 0.4, 1), ('Rotate', 0.6, 8)], - [('Solarize', 0.8, 3), ('Equalize', 0.4, 7)], - [('Solarize', 0.4, 2), ('Solarize', 0.6, 2)], - [('Color', 0.2, 0), ('Equalize', 0.8, 8)], - [('Equalize', 0.4, 8), ('SolarizeAdd', 0.8, 3)], - [('ShearX', 0.2, 9), ('Rotate', 0.6, 8)], - [('Color', 0.6, 1), ('Equalize', 1.0, 2)], - [('Invert', 0.4, 9), ('Rotate', 0.6, 0)], - [('Equalize', 1.0, 9), ('ShearY', 0.6, 3)], - [('Color', 0.4, 7), ('Equalize', 0.6, 0)], - [('PosterizeIncreasing', 0.4, 6), ('AutoContrast', 0.4, 7)], - [('Solarize', 0.6, 8), ('Color', 0.6, 9)], - [('Solarize', 0.2, 4), ('Rotate', 0.8, 9)], - [('Rotate', 1.0, 7), ('TranslateYRel', 0.8, 9)], - [('ShearX', 0.0, 0), ('Solarize', 0.8, 4)], - [('ShearY', 0.8, 0), ('Color', 0.6, 4)], - [('Color', 1.0, 0), ('Rotate', 0.6, 2)], - [('Equalize', 0.8, 4), ('Equalize', 0.0, 8)], - [('Equalize', 1.0, 4), ('AutoContrast', 0.6, 2)], - [('ShearY', 0.4, 7), ('SolarizeAdd', 0.6, 7)], - [('PosterizeIncreasing', 0.8, 2), ('Solarize', 0.6, 10)], - [('Solarize', 0.6, 8), ('Equalize', 0.6, 1)], - [('Color', 0.8, 6), ('Rotate', 0.4, 5)], - ] - pc = [[AugmentOp(*a, hparams=hparams) for a in sp] for sp in policy] - return pc - - -def auto_augment_policy_original(hparams): - # ImageNet policy from https://arxiv.org/abs/1805.09501 - policy = [ - [('PosterizeOriginal', 0.4, 8), ('Rotate', 0.6, 9)], - [('Solarize', 0.6, 5), ('AutoContrast', 0.6, 5)], - [('Equalize', 0.8, 8), ('Equalize', 0.6, 3)], - [('PosterizeOriginal', 0.6, 7), ('PosterizeOriginal', 0.6, 6)], - [('Equalize', 0.4, 7), ('Solarize', 0.2, 4)], - [('Equalize', 0.4, 4), ('Rotate', 0.8, 8)], - [('Solarize', 0.6, 3), ('Equalize', 0.6, 7)], - [('PosterizeOriginal', 0.8, 5), ('Equalize', 1.0, 2)], - [('Rotate', 0.2, 3), ('Solarize', 0.6, 8)], - [('Equalize', 0.6, 8), ('PosterizeOriginal', 0.4, 6)], - [('Rotate', 0.8, 8), ('Color', 0.4, 0)], - [('Rotate', 0.4, 9), ('Equalize', 0.6, 2)], - [('Equalize', 0.0, 7), ('Equalize', 0.8, 8)], - [('Invert', 0.6, 4), ('Equalize', 1.0, 8)], - [('Color', 0.6, 4), ('Contrast', 1.0, 8)], - [('Rotate', 0.8, 8), ('Color', 1.0, 2)], - [('Color', 0.8, 8), ('Solarize', 0.8, 7)], - [('Sharpness', 0.4, 7), ('Invert', 0.6, 8)], - [('ShearX', 0.6, 5), ('Equalize', 1.0, 9)], - [('Color', 0.4, 0), ('Equalize', 0.6, 3)], - [('Equalize', 0.4, 7), ('Solarize', 0.2, 4)], - [('Solarize', 0.6, 5), ('AutoContrast', 0.6, 5)], - [('Invert', 0.6, 4), ('Equalize', 1.0, 8)], - [('Color', 0.6, 4), ('Contrast', 1.0, 8)], - [('Equalize', 0.8, 8), ('Equalize', 0.6, 3)], - ] - pc = [[AugmentOp(*a, hparams=hparams) for a in sp] for sp in policy] - return pc - - -def auto_augment_policy_originalr(hparams): - # ImageNet policy from https://arxiv.org/abs/1805.09501 with research posterize variation - policy = [ - [('PosterizeIncreasing', 0.4, 8), ('Rotate', 0.6, 9)], - [('Solarize', 0.6, 5), ('AutoContrast', 0.6, 5)], - [('Equalize', 0.8, 8), ('Equalize', 0.6, 3)], - [('PosterizeIncreasing', 0.6, 7), ('PosterizeIncreasing', 0.6, 6)], - [('Equalize', 0.4, 7), ('Solarize', 0.2, 4)], - [('Equalize', 0.4, 4), ('Rotate', 0.8, 8)], - [('Solarize', 0.6, 3), ('Equalize', 0.6, 7)], - [('PosterizeIncreasing', 0.8, 5), ('Equalize', 1.0, 2)], - [('Rotate', 0.2, 3), ('Solarize', 0.6, 8)], - [('Equalize', 0.6, 8), ('PosterizeIncreasing', 0.4, 6)], - [('Rotate', 0.8, 8), ('Color', 0.4, 0)], - [('Rotate', 0.4, 9), ('Equalize', 0.6, 2)], - [('Equalize', 0.0, 7), ('Equalize', 0.8, 8)], - [('Invert', 0.6, 4), ('Equalize', 1.0, 8)], - [('Color', 0.6, 4), ('Contrast', 1.0, 8)], - [('Rotate', 0.8, 8), ('Color', 1.0, 2)], - [('Color', 0.8, 8), ('Solarize', 0.8, 7)], - [('Sharpness', 0.4, 7), ('Invert', 0.6, 8)], - [('ShearX', 0.6, 5), ('Equalize', 1.0, 9)], - [('Color', 0.4, 0), ('Equalize', 0.6, 3)], - [('Equalize', 0.4, 7), ('Solarize', 0.2, 4)], - [('Solarize', 0.6, 5), ('AutoContrast', 0.6, 5)], - [('Invert', 0.6, 4), ('Equalize', 1.0, 8)], - [('Color', 0.6, 4), ('Contrast', 1.0, 8)], - [('Equalize', 0.8, 8), ('Equalize', 0.6, 3)], - ] - pc = [[AugmentOp(*a, hparams=hparams) for a in sp] for sp in policy] - return pc - - -def auto_augment_policy(name='v0', hparams=None): - hparams = hparams or _HPARAMS_DEFAULT - if name == 'original': - return auto_augment_policy_original(hparams) - elif name == 'originalr': - return auto_augment_policy_originalr(hparams) - elif name == 'v0': - return auto_augment_policy_v0(hparams) - elif name == 'v0r': - return auto_augment_policy_v0r(hparams) - else: - assert False, 'Unknown AA policy (%s)' % name - - -class AutoAugment: - - def __init__(self, policy): - self.policy = policy - - def __call__(self, img): - sub_policy = random.choice(self.policy) - for op in sub_policy: - img = op(img) - return img - - -def auto_augment_transform(config_str, hparams): - """ - Create a AutoAugment transform - - :param config_str: String defining configuration of auto augmentation. Consists of multiple sections separated by - dashes ('-'). The first section defines the AutoAugment policy (one of 'v0', 'v0r', 'original', 'originalr'). - The remaining sections, not order sepecific determine - 'mstd' - float std deviation of magnitude noise applied - Ex 'original-mstd0.5' results in AutoAugment with original policy, magnitude_std 0.5 - - :param hparams: Other hparams (kwargs) for the AutoAugmentation scheme - - :return: A PyTorch compatible Transform - """ - config = config_str.split('-') - policy_name = config[0] - config = config[1:] - for c in config: - cs = re.split(r'(\d.*)', c) - if len(cs) < 2: - continue - key, val = cs[:2] - if key == 'mstd': - # noise param injected via hparams for now - hparams.setdefault('magnitude_std', float(val)) - else: - assert False, 'Unknown AutoAugment config section' - aa_policy = auto_augment_policy(policy_name, hparams=hparams) - return AutoAugment(aa_policy) - - -_RAND_TRANSFORMS = [ - 'AutoContrast', - 'Equalize', - 'Invert', - 'Rotate', - 'Posterize', - 'Solarize', - 'SolarizeAdd', - 'Color', - 'Contrast', - 'Brightness', - 'Sharpness', - 'ShearX', - 'ShearY', - 'TranslateXRel', - 'TranslateYRel', - #'Cutout' # NOTE I've implement this as random erasing separately -] - - -_RAND_INCREASING_TRANSFORMS = [ - 'AutoContrast', - 'Equalize', - 'Invert', - 'Rotate', - 'PosterizeIncreasing', - 'SolarizeIncreasing', - 'SolarizeAdd', - 'ColorIncreasing', - 'ContrastIncreasing', - 'BrightnessIncreasing', - 'SharpnessIncreasing', - 'ShearX', - 'ShearY', - 'TranslateXRel', - 'TranslateYRel', - #'Cutout' # NOTE I've implement this as random erasing separately -] - - - -# These experimental weights are based loosely on the relative improvements mentioned in paper. -# They may not result in increased performance, but could likely be tuned to so. -_RAND_CHOICE_WEIGHTS_0 = { - 'Rotate': 0.3, - 'ShearX': 0.2, - 'ShearY': 0.2, - 'TranslateXRel': 0.1, - 'TranslateYRel': 0.1, - 'Color': .025, - 'Sharpness': 0.025, - 'AutoContrast': 0.025, - 'Solarize': .005, - 'SolarizeAdd': .005, - 'Contrast': .005, - 'Brightness': .005, - 'Equalize': .005, - 'Posterize': 0, - 'Invert': 0, -} - - -def _select_rand_weights(weight_idx=0, transforms=None): - transforms = transforms or _RAND_TRANSFORMS - assert weight_idx == 0 # only one set of weights currently - rand_weights = _RAND_CHOICE_WEIGHTS_0 - probs = [rand_weights[k] for k in transforms] - probs /= np.sum(probs) - return probs - - -def rand_augment_ops(magnitude=10, hparams=None, transforms=None): - hparams = hparams or _HPARAMS_DEFAULT - transforms = transforms or _RAND_TRANSFORMS - return [AugmentOp( - name, prob=0.5, magnitude=magnitude, hparams=hparams) for name in transforms] - - -class RandAugment: - def __init__(self, ops, num_layers=2, choice_weights=None): - self.ops = ops - self.num_layers = num_layers - self.choice_weights = choice_weights - - def __call__(self, img): - # no replacement when using weighted choice - ops = np.random.choice( - self.ops, self.num_layers, replace=self.choice_weights is None, p=self.choice_weights) - for op in ops: - img = op(img) - return img - - -def rand_augment_transform(config_str, hparams): - """ - Create a RandAugment transform - - :param config_str: String defining configuration of random augmentation. Consists of multiple sections separated by - dashes ('-'). The first section defines the specific variant of rand augment (currently only 'rand'). The remaining - sections, not order sepecific determine - 'm' - integer magnitude of rand augment - 'n' - integer num layers (number of transform ops selected per image) - 'w' - integer probabiliy weight index (index of a set of weights to influence choice of op) - 'mstd' - float std deviation of magnitude noise applied - 'inc' - integer (bool), use augmentations that increase in severity with magnitude (default: 0) - Ex 'rand-m9-n3-mstd0.5' results in RandAugment with magnitude 9, num_layers 3, magnitude_std 0.5 - 'rand-mstd1-w0' results in magnitude_std 1.0, weights 0, default magnitude of 10 and num_layers 2 - - :param hparams: Other hparams (kwargs) for the RandAugmentation scheme - - :return: A PyTorch compatible Transform - """ - magnitude = _MAX_LEVEL # default to _MAX_LEVEL for magnitude (currently 10) - num_layers = 2 # default to 2 ops per image - weight_idx = None # default to no probability weights for op choice - transforms = _RAND_TRANSFORMS - config = config_str.split('-') - assert config[0] == 'rand' - config = config[1:] - for c in config: - cs = re.split(r'(\d.*)', c) - if len(cs) < 2: - continue - key, val = cs[:2] - if key == 'mstd': - # noise param injected via hparams for now - hparams.setdefault('magnitude_std', float(val)) - elif key == 'inc': - if bool(val): - transforms = _RAND_INCREASING_TRANSFORMS - elif key == 'm': - magnitude = int(val) - elif key == 'n': - num_layers = int(val) - elif key == 'w': - weight_idx = int(val) - else: - assert False, 'Unknown RandAugment config section' - ra_ops = rand_augment_ops(magnitude=magnitude, hparams=hparams, transforms=transforms) - choice_weights = None if weight_idx is None else _select_rand_weights(weight_idx) - return RandAugment(ra_ops, num_layers, choice_weights=choice_weights) - - -_AUGMIX_TRANSFORMS = [ - 'AutoContrast', - 'ColorIncreasing', # not in paper - 'ContrastIncreasing', # not in paper - 'BrightnessIncreasing', # not in paper - 'SharpnessIncreasing', # not in paper - 'Equalize', - 'Rotate', - 'PosterizeIncreasing', - 'SolarizeIncreasing', - 'ShearX', - 'ShearY', - 'TranslateXRel', - 'TranslateYRel', -] - - -def augmix_ops(magnitude=10, hparams=None, transforms=None): - hparams = hparams or _HPARAMS_DEFAULT - transforms = transforms or _AUGMIX_TRANSFORMS - return [AugmentOp( - name, prob=1.0, magnitude=magnitude, hparams=hparams) for name in transforms] - - -class AugMixAugment: - """ AugMix Transform - Adapted and improved from impl here: https://github.com/google-research/augmix/blob/master/imagenet.py - From paper: 'AugMix: A Simple Data Processing Method to Improve Robustness and Uncertainty - - https://arxiv.org/abs/1912.02781 - """ - def __init__(self, ops, alpha=1., width=3, depth=-1, blended=False): - self.ops = ops - self.alpha = alpha - self.width = width - self.depth = depth - self.blended = blended # blended mode is faster but not well tested - - def _calc_blended_weights(self, ws, m): - ws = ws * m - cump = 1. - rws = [] - for w in ws[::-1]: - alpha = w / cump - cump *= (1 - alpha) - rws.append(alpha) - return np.array(rws[::-1], dtype=np.float32) - - def _apply_blended(self, img, mixing_weights, m): - # This is my first crack and implementing a slightly faster mixed augmentation. Instead - # of accumulating the mix for each chain in a Numpy array and then blending with original, - # it recomputes the blending coefficients and applies one PIL image blend per chain. - # TODO the results appear in the right ballpark but they differ by more than rounding. - img_orig = img.copy() - ws = self._calc_blended_weights(mixing_weights, m) - for w in ws: - depth = self.depth if self.depth > 0 else np.random.randint(1, 4) - ops = np.random.choice(self.ops, depth, replace=True) - img_aug = img_orig # no ops are in-place, deep copy not necessary - for op in ops: - img_aug = op(img_aug) - img = Image.blend(img, img_aug, w) - return img - - def _apply_basic(self, img, mixing_weights, m): - # This is a literal adaptation of the paper/official implementation without normalizations and - # PIL <-> Numpy conversions between every op. It is still quite CPU compute heavy compared to the - # typical augmentation transforms, could use a GPU / Kornia implementation. - img_shape = img.size[0], img.size[1], len(img.getbands()) - mixed = np.zeros(img_shape, dtype=np.float32) - for mw in mixing_weights: - depth = self.depth if self.depth > 0 else np.random.randint(1, 4) - ops = np.random.choice(self.ops, depth, replace=True) - img_aug = img # no ops are in-place, deep copy not necessary - for op in ops: - img_aug = op(img_aug) - mixed += mw * np.asarray(img_aug, dtype=np.float32) - np.clip(mixed, 0, 255., out=mixed) - mixed = Image.fromarray(mixed.astype(np.uint8)) - return Image.blend(img, mixed, m) - - def __call__(self, img): - mixing_weights = np.float32(np.random.dirichlet([self.alpha] * self.width)) - m = np.float32(np.random.beta(self.alpha, self.alpha)) - if self.blended: - mixed = self._apply_blended(img, mixing_weights, m) - else: - mixed = self._apply_basic(img, mixing_weights, m) - return mixed - - -def augment_and_mix_transform(config_str, hparams): - """ Create AugMix PyTorch transform - - :param config_str: String defining configuration of random augmentation. Consists of multiple sections separated by - dashes ('-'). The first section defines the specific variant of rand augment (currently only 'rand'). The remaining - sections, not order sepecific determine - 'm' - integer magnitude (severity) of augmentation mix (default: 3) - 'w' - integer width of augmentation chain (default: 3) - 'd' - integer depth of augmentation chain (-1 is random [1, 3], default: -1) - 'b' - integer (bool), blend each branch of chain into end result without a final blend, less CPU (default: 0) - 'mstd' - float std deviation of magnitude noise applied (default: 0) - Ex 'augmix-m5-w4-d2' results in AugMix with severity 5, chain width 4, chain depth 2 - - :param hparams: Other hparams (kwargs) for the Augmentation transforms - - :return: A PyTorch compatible Transform - """ - magnitude = 3 - width = 3 - depth = -1 - alpha = 1. - blended = False - config = config_str.split('-') - assert config[0] == 'augmix' - config = config[1:] - for c in config: - cs = re.split(r'(\d.*)', c) - if len(cs) < 2: - continue - key, val = cs[:2] - if key == 'mstd': - # noise param injected via hparams for now - hparams.setdefault('magnitude_std', float(val)) - elif key == 'm': - magnitude = int(val) - elif key == 'w': - width = int(val) - elif key == 'd': - depth = int(val) - elif key == 'a': - alpha = float(val) - elif key == 'b': - blended = bool(val) - else: - assert False, 'Unknown AugMix config section' - ops = augmix_ops(magnitude=magnitude, hparams=hparams) +# Copyright [yyyy] [name of copyright owner] +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 random +import math +import re +from PIL import Image, ImageOps, ImageEnhance, ImageChops +import PIL +import numpy as np + + +_PIL_VER = tuple([int(x) for x in PIL.__version__.split('.')[:2]]) + +_FILL = (128, 128, 128) + +# This signifies the max integer that the controller RNN could predict for the +# augmentation scheme. +_MAX_LEVEL = 10. + +_HPARAMS_DEFAULT = dict( + translate_const=250, + img_mean=_FILL, +) + +_RANDOM_INTERPOLATION = (Image.BILINEAR, Image.BICUBIC) + + +def _interpolation(kwargs): + interpolation = kwargs.pop('resample', Image.BILINEAR) + if isinstance(interpolation, (list, tuple)): + return random.choice(interpolation) + else: + return interpolation + + +def _check_args_tf(kwargs): + if 'fillcolor' in kwargs and _PIL_VER < (5, 0): + kwargs.pop('fillcolor') + kwargs['resample'] = _interpolation(kwargs) + + +def shear_x(img, factor, **kwargs): + _check_args_tf(kwargs) + return img.transform(img.size, Image.AFFINE, (1, factor, 0, 0, 1, 0), **kwargs) + + +def shear_y(img, factor, **kwargs): + _check_args_tf(kwargs) + return img.transform(img.size, Image.AFFINE, (1, 0, 0, factor, 1, 0), **kwargs) + + +def translate_x_rel(img, pct, **kwargs): + pixels = pct * img.size[0] + _check_args_tf(kwargs) + return img.transform(img.size, Image.AFFINE, (1, 0, pixels, 0, 1, 0), **kwargs) + + +def translate_y_rel(img, pct, **kwargs): + pixels = pct * img.size[1] + _check_args_tf(kwargs) + return img.transform(img.size, Image.AFFINE, (1, 0, 0, 0, 1, pixels), **kwargs) + + +def translate_x_abs(img, pixels, **kwargs): + _check_args_tf(kwargs) + return img.transform(img.size, Image.AFFINE, (1, 0, pixels, 0, 1, 0), **kwargs) + + +def translate_y_abs(img, pixels, **kwargs): + _check_args_tf(kwargs) + return img.transform(img.size, Image.AFFINE, (1, 0, 0, 0, 1, pixels), **kwargs) + + +def rotate(img, degrees, **kwargs): + _check_args_tf(kwargs) + if _PIL_VER >= (5, 2): + return img.rotate(degrees, **kwargs) + elif _PIL_VER >= (5, 0): + w, h = img.size + post_trans = (0, 0) + rotn_center = (w / 2.0, h / 2.0) + angle = -math.radians(degrees) + matrix = [ + round(math.cos(angle), 15), + round(math.sin(angle), 15), + 0.0, + round(-math.sin(angle), 15), + round(math.cos(angle), 15), + 0.0, + ] + + def transform(x, y, matrix): + (a, b, c, d, e, f) = matrix + return a * x + b * y + c, d * x + e * y + f + + matrix[2], matrix[5] = transform( + -rotn_center[0] - post_trans[0], -rotn_center[1] - post_trans[1], matrix + ) + matrix[2] += rotn_center[0] + matrix[5] += rotn_center[1] + return img.transform(img.size, Image.AFFINE, matrix, **kwargs) + else: + return img.rotate(degrees, resample=kwargs['resample']) + + +def auto_contrast(img, **__): + return ImageOps.autocontrast(img) + + +def invert(img, **__): + return ImageOps.invert(img) + + +def equalize(img, **__): + return ImageOps.equalize(img) + + +def solarize(img, thresh, **__): + return ImageOps.solarize(img, thresh) + + +def solarize_add(img, add, thresh=128, **__): + lut = [] + for i in range(256): + if i < thresh: + lut.append(min(255, i + add)) + else: + lut.append(i) + if img.mode in ("L", "RGB"): + if img.mode == "RGB" and len(lut) == 256: + lut = lut + lut + lut + return img.point(lut) + else: + return img + + +def posterize(img, bits_to_keep, **__): + if bits_to_keep >= 8: + return img + return ImageOps.posterize(img, bits_to_keep) + + +def contrast(img, factor, **__): + return ImageEnhance.Contrast(img).enhance(factor) + + +def color(img, factor, **__): + return ImageEnhance.Color(img).enhance(factor) + + +def brightness(img, factor, **__): + return ImageEnhance.Brightness(img).enhance(factor) + + +def sharpness(img, factor, **__): + return ImageEnhance.Sharpness(img).enhance(factor) + + +def _randomly_negate(v): + """With 50% prob, negate the value""" + return -v if random.random() > 0.5 else v + + +def _rotate_level_to_arg(level, _hparams): + # range [-30, 30] + level = (level / _MAX_LEVEL) * 30. + level = _randomly_negate(level) + return level, + + +def _enhance_level_to_arg(level, _hparams): + # range [0.1, 1.9] + return (level / _MAX_LEVEL) * 1.8 + 0.1, + + +def _enhance_increasing_level_to_arg(level, _hparams): + # the 'no change' level is 1.0, moving away from that towards 0. or 2.0 increases the enhancement blend + # range [0.1, 1.9] + level = (level / _MAX_LEVEL) * .9 + level = 1.0 + _randomly_negate(level) + return level, + + +def _shear_level_to_arg(level, _hparams): + # range [-0.3, 0.3] + level = (level / _MAX_LEVEL) * 0.3 + level = _randomly_negate(level) + return level, + + +def _translate_abs_level_to_arg(level, hparams): + translate_const = hparams['translate_const'] + level = (level / _MAX_LEVEL) * float(translate_const) + level = _randomly_negate(level) + return level, + + +def _translate_rel_level_to_arg(level, hparams): + # default range [-0.45, 0.45] + translate_pct = hparams.get('translate_pct', 0.45) + level = (level / _MAX_LEVEL) * translate_pct + level = _randomly_negate(level) + return level, + + +def _posterize_level_to_arg(level, _hparams): + # As per Tensorflow TPU EfficientNet impl + # range [0, 4], 'keep 0 up to 4 MSB of original image' + # intensity/severity of augmentation decreases with level + return int((level / _MAX_LEVEL) * 4), + + +def _posterize_increasing_level_to_arg(level, hparams): + # As per Tensorflow models research and UDA impl + # range [4, 0], 'keep 4 down to 0 MSB of original image', + # intensity/severity of augmentation increases with level + return 4 - _posterize_level_to_arg(level, hparams)[0], + + +def _posterize_original_level_to_arg(level, _hparams): + # As per original AutoAugment paper description + # range [4, 8], 'keep 4 up to 8 MSB of image' + # intensity/severity of augmentation decreases with level + return int((level / _MAX_LEVEL) * 4) + 4, + + +def _solarize_level_to_arg(level, _hparams): + # range [0, 256] + # intensity/severity of augmentation decreases with level + return int((level / _MAX_LEVEL) * 256), + + +def _solarize_increasing_level_to_arg(level, _hparams): + # range [0, 256] + # intensity/severity of augmentation increases with level + return 256 - _solarize_level_to_arg(level, _hparams)[0], + + +def _solarize_add_level_to_arg(level, _hparams): + # range [0, 110] + return int((level / _MAX_LEVEL) * 110), + + +LEVEL_TO_ARG = { + 'AutoContrast': None, + 'Equalize': None, + 'Invert': None, + 'Rotate': _rotate_level_to_arg, + # There are several variations of the posterize level scaling in various Tensorflow/Google repositories/papers + 'Posterize': _posterize_level_to_arg, + 'PosterizeIncreasing': _posterize_increasing_level_to_arg, + 'PosterizeOriginal': _posterize_original_level_to_arg, + 'Solarize': _solarize_level_to_arg, + 'SolarizeIncreasing': _solarize_increasing_level_to_arg, + 'SolarizeAdd': _solarize_add_level_to_arg, + 'Color': _enhance_level_to_arg, + 'ColorIncreasing': _enhance_increasing_level_to_arg, + 'Contrast': _enhance_level_to_arg, + 'ContrastIncreasing': _enhance_increasing_level_to_arg, + 'Brightness': _enhance_level_to_arg, + 'BrightnessIncreasing': _enhance_increasing_level_to_arg, + 'Sharpness': _enhance_level_to_arg, + 'SharpnessIncreasing': _enhance_increasing_level_to_arg, + 'ShearX': _shear_level_to_arg, + 'ShearY': _shear_level_to_arg, + 'TranslateX': _translate_abs_level_to_arg, + 'TranslateY': _translate_abs_level_to_arg, + 'TranslateXRel': _translate_rel_level_to_arg, + 'TranslateYRel': _translate_rel_level_to_arg, +} + + +NAME_TO_OP = { + 'AutoContrast': auto_contrast, + 'Equalize': equalize, + 'Invert': invert, + 'Rotate': rotate, + 'Posterize': posterize, + 'PosterizeIncreasing': posterize, + 'PosterizeOriginal': posterize, + 'Solarize': solarize, + 'SolarizeIncreasing': solarize, + 'SolarizeAdd': solarize_add, + 'Color': color, + 'ColorIncreasing': color, + 'Contrast': contrast, + 'ContrastIncreasing': contrast, + 'Brightness': brightness, + 'BrightnessIncreasing': brightness, + 'Sharpness': sharpness, + 'SharpnessIncreasing': sharpness, + 'ShearX': shear_x, + 'ShearY': shear_y, + 'TranslateX': translate_x_abs, + 'TranslateY': translate_y_abs, + 'TranslateXRel': translate_x_rel, + 'TranslateYRel': translate_y_rel, +} + + +class AugmentOp: + + def __init__(self, name, prob=0.5, magnitude=10, hparams=None): + hparams = hparams or _HPARAMS_DEFAULT + self.aug_fn = NAME_TO_OP[name] + self.level_fn = LEVEL_TO_ARG[name] + self.prob = prob + self.magnitude = magnitude + self.hparams = hparams.copy() + self.kwargs = dict( + fillcolor=hparams['img_mean'] if 'img_mean' in hparams else _FILL, + resample=hparams['interpolation'] if 'interpolation' in hparams else _RANDOM_INTERPOLATION, + ) + + # If magnitude_std is > 0, we introduce some randomness + # in the usually fixed policy and sample magnitude from a normal distribution + # with mean `magnitude` and std-dev of `magnitude_std`. + # NOTE This is my own hack, being tested, not in papers or reference impls. + self.magnitude_std = self.hparams.get('magnitude_std', 0) + + def __call__(self, img): + if self.prob < 1.0 and random.random() > self.prob: + return img + magnitude = self.magnitude + if self.magnitude_std and self.magnitude_std > 0: + magnitude = random.gauss(magnitude, self.magnitude_std) + magnitude = min(_MAX_LEVEL, max(0, magnitude)) # clip to valid range + level_args = self.level_fn(magnitude, self.hparams) if self.level_fn is not None else tuple() + return self.aug_fn(img, *level_args, **self.kwargs) + + +def auto_augment_policy_v0(hparams): + # ImageNet v0 policy from TPU EfficientNet impl, cannot find a paper reference. + policy = [ + [('Equalize', 0.8, 1), ('ShearY', 0.8, 4)], + [('Color', 0.4, 9), ('Equalize', 0.6, 3)], + [('Color', 0.4, 1), ('Rotate', 0.6, 8)], + [('Solarize', 0.8, 3), ('Equalize', 0.4, 7)], + [('Solarize', 0.4, 2), ('Solarize', 0.6, 2)], + [('Color', 0.2, 0), ('Equalize', 0.8, 8)], + [('Equalize', 0.4, 8), ('SolarizeAdd', 0.8, 3)], + [('ShearX', 0.2, 9), ('Rotate', 0.6, 8)], + [('Color', 0.6, 1), ('Equalize', 1.0, 2)], + [('Invert', 0.4, 9), ('Rotate', 0.6, 0)], + [('Equalize', 1.0, 9), ('ShearY', 0.6, 3)], + [('Color', 0.4, 7), ('Equalize', 0.6, 0)], + [('Posterize', 0.4, 6), ('AutoContrast', 0.4, 7)], + [('Solarize', 0.6, 8), ('Color', 0.6, 9)], + [('Solarize', 0.2, 4), ('Rotate', 0.8, 9)], + [('Rotate', 1.0, 7), ('TranslateYRel', 0.8, 9)], + [('ShearX', 0.0, 0), ('Solarize', 0.8, 4)], + [('ShearY', 0.8, 0), ('Color', 0.6, 4)], + [('Color', 1.0, 0), ('Rotate', 0.6, 2)], + [('Equalize', 0.8, 4), ('Equalize', 0.0, 8)], + [('Equalize', 1.0, 4), ('AutoContrast', 0.6, 2)], + [('ShearY', 0.4, 7), ('SolarizeAdd', 0.6, 7)], + [('Posterize', 0.8, 2), ('Solarize', 0.6, 10)], # This results in black image with Tpu posterize + [('Solarize', 0.6, 8), ('Equalize', 0.6, 1)], + [('Color', 0.8, 6), ('Rotate', 0.4, 5)], + ] + pc = [[AugmentOp(*a, hparams=hparams) for a in sp] for sp in policy] + return pc + + +def auto_augment_policy_v0r(hparams): + # ImageNet v0 policy from TPU EfficientNet impl, with variation of Posterize used + # in Google research implementation (number of bits discarded increases with magnitude) + policy = [ + [('Equalize', 0.8, 1), ('ShearY', 0.8, 4)], + [('Color', 0.4, 9), ('Equalize', 0.6, 3)], + [('Color', 0.4, 1), ('Rotate', 0.6, 8)], + [('Solarize', 0.8, 3), ('Equalize', 0.4, 7)], + [('Solarize', 0.4, 2), ('Solarize', 0.6, 2)], + [('Color', 0.2, 0), ('Equalize', 0.8, 8)], + [('Equalize', 0.4, 8), ('SolarizeAdd', 0.8, 3)], + [('ShearX', 0.2, 9), ('Rotate', 0.6, 8)], + [('Color', 0.6, 1), ('Equalize', 1.0, 2)], + [('Invert', 0.4, 9), ('Rotate', 0.6, 0)], + [('Equalize', 1.0, 9), ('ShearY', 0.6, 3)], + [('Color', 0.4, 7), ('Equalize', 0.6, 0)], + [('PosterizeIncreasing', 0.4, 6), ('AutoContrast', 0.4, 7)], + [('Solarize', 0.6, 8), ('Color', 0.6, 9)], + [('Solarize', 0.2, 4), ('Rotate', 0.8, 9)], + [('Rotate', 1.0, 7), ('TranslateYRel', 0.8, 9)], + [('ShearX', 0.0, 0), ('Solarize', 0.8, 4)], + [('ShearY', 0.8, 0), ('Color', 0.6, 4)], + [('Color', 1.0, 0), ('Rotate', 0.6, 2)], + [('Equalize', 0.8, 4), ('Equalize', 0.0, 8)], + [('Equalize', 1.0, 4), ('AutoContrast', 0.6, 2)], + [('ShearY', 0.4, 7), ('SolarizeAdd', 0.6, 7)], + [('PosterizeIncreasing', 0.8, 2), ('Solarize', 0.6, 10)], + [('Solarize', 0.6, 8), ('Equalize', 0.6, 1)], + [('Color', 0.8, 6), ('Rotate', 0.4, 5)], + ] + pc = [[AugmentOp(*a, hparams=hparams) for a in sp] for sp in policy] + return pc + + +def auto_augment_policy_original(hparams): + # ImageNet policy from https://arxiv.org/abs/1805.09501 + policy = [ + [('PosterizeOriginal', 0.4, 8), ('Rotate', 0.6, 9)], + [('Solarize', 0.6, 5), ('AutoContrast', 0.6, 5)], + [('Equalize', 0.8, 8), ('Equalize', 0.6, 3)], + [('PosterizeOriginal', 0.6, 7), ('PosterizeOriginal', 0.6, 6)], + [('Equalize', 0.4, 7), ('Solarize', 0.2, 4)], + [('Equalize', 0.4, 4), ('Rotate', 0.8, 8)], + [('Solarize', 0.6, 3), ('Equalize', 0.6, 7)], + [('PosterizeOriginal', 0.8, 5), ('Equalize', 1.0, 2)], + [('Rotate', 0.2, 3), ('Solarize', 0.6, 8)], + [('Equalize', 0.6, 8), ('PosterizeOriginal', 0.4, 6)], + [('Rotate', 0.8, 8), ('Color', 0.4, 0)], + [('Rotate', 0.4, 9), ('Equalize', 0.6, 2)], + [('Equalize', 0.0, 7), ('Equalize', 0.8, 8)], + [('Invert', 0.6, 4), ('Equalize', 1.0, 8)], + [('Color', 0.6, 4), ('Contrast', 1.0, 8)], + [('Rotate', 0.8, 8), ('Color', 1.0, 2)], + [('Color', 0.8, 8), ('Solarize', 0.8, 7)], + [('Sharpness', 0.4, 7), ('Invert', 0.6, 8)], + [('ShearX', 0.6, 5), ('Equalize', 1.0, 9)], + [('Color', 0.4, 0), ('Equalize', 0.6, 3)], + [('Equalize', 0.4, 7), ('Solarize', 0.2, 4)], + [('Solarize', 0.6, 5), ('AutoContrast', 0.6, 5)], + [('Invert', 0.6, 4), ('Equalize', 1.0, 8)], + [('Color', 0.6, 4), ('Contrast', 1.0, 8)], + [('Equalize', 0.8, 8), ('Equalize', 0.6, 3)], + ] + pc = [[AugmentOp(*a, hparams=hparams) for a in sp] for sp in policy] + return pc + + +def auto_augment_policy_originalr(hparams): + # ImageNet policy from https://arxiv.org/abs/1805.09501 with research posterize variation + policy = [ + [('PosterizeIncreasing', 0.4, 8), ('Rotate', 0.6, 9)], + [('Solarize', 0.6, 5), ('AutoContrast', 0.6, 5)], + [('Equalize', 0.8, 8), ('Equalize', 0.6, 3)], + [('PosterizeIncreasing', 0.6, 7), ('PosterizeIncreasing', 0.6, 6)], + [('Equalize', 0.4, 7), ('Solarize', 0.2, 4)], + [('Equalize', 0.4, 4), ('Rotate', 0.8, 8)], + [('Solarize', 0.6, 3), ('Equalize', 0.6, 7)], + [('PosterizeIncreasing', 0.8, 5), ('Equalize', 1.0, 2)], + [('Rotate', 0.2, 3), ('Solarize', 0.6, 8)], + [('Equalize', 0.6, 8), ('PosterizeIncreasing', 0.4, 6)], + [('Rotate', 0.8, 8), ('Color', 0.4, 0)], + [('Rotate', 0.4, 9), ('Equalize', 0.6, 2)], + [('Equalize', 0.0, 7), ('Equalize', 0.8, 8)], + [('Invert', 0.6, 4), ('Equalize', 1.0, 8)], + [('Color', 0.6, 4), ('Contrast', 1.0, 8)], + [('Rotate', 0.8, 8), ('Color', 1.0, 2)], + [('Color', 0.8, 8), ('Solarize', 0.8, 7)], + [('Sharpness', 0.4, 7), ('Invert', 0.6, 8)], + [('ShearX', 0.6, 5), ('Equalize', 1.0, 9)], + [('Color', 0.4, 0), ('Equalize', 0.6, 3)], + [('Equalize', 0.4, 7), ('Solarize', 0.2, 4)], + [('Solarize', 0.6, 5), ('AutoContrast', 0.6, 5)], + [('Invert', 0.6, 4), ('Equalize', 1.0, 8)], + [('Color', 0.6, 4), ('Contrast', 1.0, 8)], + [('Equalize', 0.8, 8), ('Equalize', 0.6, 3)], + ] + pc = [[AugmentOp(*a, hparams=hparams) for a in sp] for sp in policy] + return pc + + +def auto_augment_policy(name='v0', hparams=None): + hparams = hparams or _HPARAMS_DEFAULT + if name == 'original': + return auto_augment_policy_original(hparams) + elif name == 'originalr': + return auto_augment_policy_originalr(hparams) + elif name == 'v0': + return auto_augment_policy_v0(hparams) + elif name == 'v0r': + return auto_augment_policy_v0r(hparams) + else: + assert False, 'Unknown AA policy (%s)' % name + + +class AutoAugment: + + def __init__(self, policy): + self.policy = policy + + def __call__(self, img): + sub_policy = random.choice(self.policy) + for op in sub_policy: + img = op(img) + return img + + +def auto_augment_transform(config_str, hparams): + """ + Create a AutoAugment transform + + :param config_str: String defining configuration of auto augmentation. Consists of multiple sections separated by + dashes ('-'). The first section defines the AutoAugment policy (one of 'v0', 'v0r', 'original', 'originalr'). + The remaining sections, not order sepecific determine + 'mstd' - float std deviation of magnitude noise applied + Ex 'original-mstd0.5' results in AutoAugment with original policy, magnitude_std 0.5 + + :param hparams: Other hparams (kwargs) for the AutoAugmentation scheme + + :return: A PyTorch compatible Transform + """ + config = config_str.split('-') + policy_name = config[0] + config = config[1:] + for c in config: + cs = re.split(r'(\d.*)', c) + if len(cs) < 2: + continue + key, val = cs[:2] + if key == 'mstd': + # noise param injected via hparams for now + hparams.setdefault('magnitude_std', float(val)) + else: + assert False, 'Unknown AutoAugment config section' + aa_policy = auto_augment_policy(policy_name, hparams=hparams) + return AutoAugment(aa_policy) + + +_RAND_TRANSFORMS = [ + 'AutoContrast', + 'Equalize', + 'Invert', + 'Rotate', + 'Posterize', + 'Solarize', + 'SolarizeAdd', + 'Color', + 'Contrast', + 'Brightness', + 'Sharpness', + 'ShearX', + 'ShearY', + 'TranslateXRel', + 'TranslateYRel', + #'Cutout' # NOTE I've implement this as random erasing separately +] + + +_RAND_INCREASING_TRANSFORMS = [ + 'AutoContrast', + 'Equalize', + 'Invert', + 'Rotate', + 'PosterizeIncreasing', + 'SolarizeIncreasing', + 'SolarizeAdd', + 'ColorIncreasing', + 'ContrastIncreasing', + 'BrightnessIncreasing', + 'SharpnessIncreasing', + 'ShearX', + 'ShearY', + 'TranslateXRel', + 'TranslateYRel', + #'Cutout' # NOTE I've implement this as random erasing separately +] + + + +# These experimental weights are based loosely on the relative improvements mentioned in paper. +# They may not result in increased performance, but could likely be tuned to so. +_RAND_CHOICE_WEIGHTS_0 = { + 'Rotate': 0.3, + 'ShearX': 0.2, + 'ShearY': 0.2, + 'TranslateXRel': 0.1, + 'TranslateYRel': 0.1, + 'Color': .025, + 'Sharpness': 0.025, + 'AutoContrast': 0.025, + 'Solarize': .005, + 'SolarizeAdd': .005, + 'Contrast': .005, + 'Brightness': .005, + 'Equalize': .005, + 'Posterize': 0, + 'Invert': 0, +} + + +def _select_rand_weights(weight_idx=0, transforms=None): + transforms = transforms or _RAND_TRANSFORMS + assert weight_idx == 0 # only one set of weights currently + rand_weights = _RAND_CHOICE_WEIGHTS_0 + probs = [rand_weights[k] for k in transforms] + probs /= np.sum(probs) + return probs + + +def rand_augment_ops(magnitude=10, hparams=None, transforms=None): + hparams = hparams or _HPARAMS_DEFAULT + transforms = transforms or _RAND_TRANSFORMS + return [AugmentOp( + name, prob=0.5, magnitude=magnitude, hparams=hparams) for name in transforms] + + +class RandAugment: + def __init__(self, ops, num_layers=2, choice_weights=None): + self.ops = ops + self.num_layers = num_layers + self.choice_weights = choice_weights + + def __call__(self, img): + # no replacement when using weighted choice + ops = np.random.choice( + self.ops, self.num_layers, replace=self.choice_weights is None, p=self.choice_weights) + for op in ops: + img = op(img) + return img + + +def rand_augment_transform(config_str, hparams): + """ + Create a RandAugment transform + + :param config_str: String defining configuration of random augmentation. Consists of multiple sections separated by + dashes ('-'). The first section defines the specific variant of rand augment (currently only 'rand'). The remaining + sections, not order sepecific determine + 'm' - integer magnitude of rand augment + 'n' - integer num layers (number of transform ops selected per image) + 'w' - integer probabiliy weight index (index of a set of weights to influence choice of op) + 'mstd' - float std deviation of magnitude noise applied + 'inc' - integer (bool), use augmentations that increase in severity with magnitude (default: 0) + Ex 'rand-m9-n3-mstd0.5' results in RandAugment with magnitude 9, num_layers 3, magnitude_std 0.5 + 'rand-mstd1-w0' results in magnitude_std 1.0, weights 0, default magnitude of 10 and num_layers 2 + + :param hparams: Other hparams (kwargs) for the RandAugmentation scheme + + :return: A PyTorch compatible Transform + """ + magnitude = _MAX_LEVEL # default to _MAX_LEVEL for magnitude (currently 10) + num_layers = 2 # default to 2 ops per image + weight_idx = None # default to no probability weights for op choice + transforms = _RAND_TRANSFORMS + config = config_str.split('-') + assert config[0] == 'rand' + config = config[1:] + for c in config: + cs = re.split(r'(\d.*)', c) + if len(cs) < 2: + continue + key, val = cs[:2] + if key == 'mstd': + # noise param injected via hparams for now + hparams.setdefault('magnitude_std', float(val)) + elif key == 'inc': + if bool(val): + transforms = _RAND_INCREASING_TRANSFORMS + elif key == 'm': + magnitude = int(val) + elif key == 'n': + num_layers = int(val) + elif key == 'w': + weight_idx = int(val) + else: + assert False, 'Unknown RandAugment config section' + ra_ops = rand_augment_ops(magnitude=magnitude, hparams=hparams, transforms=transforms) + choice_weights = None if weight_idx is None else _select_rand_weights(weight_idx) + return RandAugment(ra_ops, num_layers, choice_weights=choice_weights) + + +_AUGMIX_TRANSFORMS = [ + 'AutoContrast', + 'ColorIncreasing', # not in paper + 'ContrastIncreasing', # not in paper + 'BrightnessIncreasing', # not in paper + 'SharpnessIncreasing', # not in paper + 'Equalize', + 'Rotate', + 'PosterizeIncreasing', + 'SolarizeIncreasing', + 'ShearX', + 'ShearY', + 'TranslateXRel', + 'TranslateYRel', +] + + +def augmix_ops(magnitude=10, hparams=None, transforms=None): + hparams = hparams or _HPARAMS_DEFAULT + transforms = transforms or _AUGMIX_TRANSFORMS + return [AugmentOp( + name, prob=1.0, magnitude=magnitude, hparams=hparams) for name in transforms] + + +class AugMixAugment: + """ AugMix Transform + Adapted and improved from impl here: https://github.com/google-research/augmix/blob/master/imagenet.py + From paper: 'AugMix: A Simple Data Processing Method to Improve Robustness and Uncertainty - + https://arxiv.org/abs/1912.02781 + """ + def __init__(self, ops, alpha=1., width=3, depth=-1, blended=False): + self.ops = ops + self.alpha = alpha + self.width = width + self.depth = depth + self.blended = blended # blended mode is faster but not well tested + + def _calc_blended_weights(self, ws, m): + ws = ws * m + cump = 1. + rws = [] + for w in ws[::-1]: + alpha = w / cump + cump *= (1 - alpha) + rws.append(alpha) + return np.array(rws[::-1], dtype=np.float32) + + def _apply_blended(self, img, mixing_weights, m): + # This is my first crack and implementing a slightly faster mixed augmentation. Instead + # of accumulating the mix for each chain in a Numpy array and then blending with original, + # it recomputes the blending coefficients and applies one PIL image blend per chain. + # TODO the results appear in the right ballpark but they differ by more than rounding. + img_orig = img.copy() + ws = self._calc_blended_weights(mixing_weights, m) + for w in ws: + depth = self.depth if self.depth > 0 else np.random.randint(1, 4) + ops = np.random.choice(self.ops, depth, replace=True) + img_aug = img_orig # no ops are in-place, deep copy not necessary + for op in ops: + img_aug = op(img_aug) + img = Image.blend(img, img_aug, w) + return img + + def _apply_basic(self, img, mixing_weights, m): + # This is a literal adaptation of the paper/official implementation without normalizations and + # PIL <-> Numpy conversions between every op. It is still quite CPU compute heavy compared to the + # typical augmentation transforms, could use a GPU / Kornia implementation. + img_shape = img.size[0], img.size[1], len(img.getbands()) + mixed = np.zeros(img_shape, dtype=np.float32) + for mw in mixing_weights: + depth = self.depth if self.depth > 0 else np.random.randint(1, 4) + ops = np.random.choice(self.ops, depth, replace=True) + img_aug = img # no ops are in-place, deep copy not necessary + for op in ops: + img_aug = op(img_aug) + mixed += mw * np.asarray(img_aug, dtype=np.float32) + np.clip(mixed, 0, 255., out=mixed) + mixed = Image.fromarray(mixed.astype(np.uint8)) + return Image.blend(img, mixed, m) + + def __call__(self, img): + mixing_weights = np.float32(np.random.dirichlet([self.alpha] * self.width)) + m = np.float32(np.random.beta(self.alpha, self.alpha)) + if self.blended: + mixed = self._apply_blended(img, mixing_weights, m) + else: + mixed = self._apply_basic(img, mixing_weights, m) + return mixed + + +def augment_and_mix_transform(config_str, hparams): + """ Create AugMix PyTorch transform + + :param config_str: String defining configuration of random augmentation. Consists of multiple sections separated by + dashes ('-'). The first section defines the specific variant of rand augment (currently only 'rand'). The remaining + sections, not order sepecific determine + 'm' - integer magnitude (severity) of augmentation mix (default: 3) + 'w' - integer width of augmentation chain (default: 3) + 'd' - integer depth of augmentation chain (-1 is random [1, 3], default: -1) + 'b' - integer (bool), blend each branch of chain into end result without a final blend, less CPU (default: 0) + 'mstd' - float std deviation of magnitude noise applied (default: 0) + Ex 'augmix-m5-w4-d2' results in AugMix with severity 5, chain width 4, chain depth 2 + + :param hparams: Other hparams (kwargs) for the Augmentation transforms + + :return: A PyTorch compatible Transform + """ + magnitude = 3 + width = 3 + depth = -1 + alpha = 1. + blended = False + config = config_str.split('-') + assert config[0] == 'augmix' + config = config[1:] + for c in config: + cs = re.split(r'(\d.*)', c) + if len(cs) < 2: + continue + key, val = cs[:2] + if key == 'mstd': + # noise param injected via hparams for now + hparams.setdefault('magnitude_std', float(val)) + elif key == 'm': + magnitude = int(val) + elif key == 'w': + width = int(val) + elif key == 'd': + depth = int(val) + elif key == 'a': + alpha = float(val) + elif key == 'b': + blended = bool(val) + else: + assert False, 'Unknown AugMix config section' + ops = augmix_ops(magnitude=magnitude, hparams=hparams) return AugMixAugment(ops, alpha=alpha, width=width, depth=depth, blended=blended) \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/model.py b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/model.py index 4472a6a19f..6d180a0119 100644 --- a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/model.py +++ b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/model.py @@ -1,426 +1,426 @@ -# Copyright [yyyy] [name of copyright owner] -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch -from torch import nn -from torch.nn import functional as F -from .utils import ( - round_filters, - round_repeats, - drop_connect, - get_same_padding_conv2d, - get_model_params, - efficientnet_params, - load_pretrained_weights, - Swish, - MemoryEfficientSwish, - calculate_output_image_size -) - -class MBConvBlock(nn.Module): - """Mobile Inverted Residual Bottleneck Block. - - Args: - block_args (namedtuple): BlockArgs, defined in utils.py. - global_params (namedtuple): GlobalParam, defined in utils.py. - image_size (tuple or list): [image_height, image_width]. - - References: - [1] https://arxiv.org/abs/1704.04861 (MobileNet v1) - [2] https://arxiv.org/abs/1801.04381 (MobileNet v2) - [3] https://arxiv.org/abs/1905.02244 (MobileNet v3) - """ - - def __init__(self, block_args, global_params, image_size=None): - super().__init__() - self._block_args = block_args - self._bn_mom = 1 - global_params.batch_norm_momentum # pytorch's difference from tensorflow - self._bn_eps = global_params.batch_norm_epsilon - self.has_se = (self._block_args.se_ratio is not None) and (0 < self._block_args.se_ratio <= 1) - self.id_skip = block_args.id_skip # whether to use skip connection and drop connect - - # Expansion phase (Inverted Bottleneck) - inp = self._block_args.input_filters # number of input channels - oup = self._block_args.input_filters * self._block_args.expand_ratio # number of output channels - if self._block_args.expand_ratio != 1: - Conv2d = get_same_padding_conv2d(image_size=image_size) - self._expand_conv = Conv2d(in_channels=inp, out_channels=oup, kernel_size=1, bias=False) - self._bn0 = nn.BatchNorm2d(num_features=oup, momentum=self._bn_mom, eps=self._bn_eps) - # image_size = calculate_output_image_size(image_size, 1) <-- this wouldn't modify image_size - - # Depthwise convolution phase - k = self._block_args.kernel_size - s = self._block_args.stride - Conv2d = get_same_padding_conv2d(image_size=image_size) - self._depthwise_conv = Conv2d( - in_channels=oup, out_channels=oup, groups=oup, # groups makes it depthwise - kernel_size=k, stride=s, bias=False) - self._bn1 = nn.BatchNorm2d(num_features=oup, momentum=self._bn_mom, eps=self._bn_eps) - image_size = calculate_output_image_size(image_size, s) - - # Squeeze and Excitation layer, if desired - if self.has_se: - Conv2d = get_same_padding_conv2d(image_size=(1,1)) - num_squeezed_channels = max(1, int(self._block_args.input_filters * self._block_args.se_ratio)) - self._se_reduce = Conv2d(in_channels=oup, out_channels=num_squeezed_channels, kernel_size=1) - self._se_expand = Conv2d(in_channels=num_squeezed_channels, out_channels=oup, kernel_size=1) - # self._se_relu = torch.nn.ReLU() - # self._se_sigmoid = torch.nn.Sigmoid() - - # Pointwise convolution phase - final_oup = self._block_args.output_filters - Conv2d = get_same_padding_conv2d(image_size=image_size) - self._project_conv = Conv2d(in_channels=oup, out_channels=final_oup, kernel_size=1, bias=False) - self._bn2 = nn.BatchNorm2d(num_features=final_oup, momentum=self._bn_mom, eps=self._bn_eps) - self._swish = MemoryEfficientSwish() - - def forward(self, inputs, drop_connect_rate=None): - """MBConvBlock's forward function. - - Args: - inputs (tensor): Input tensor. - drop_connect_rate (bool): Drop connect rate (float, between 0 and 1). - - Returns: - Output of this block after processing. - """ - - # Expansion and Depthwise Convolution - x = inputs - if self._block_args.expand_ratio != 1: - x = self._expand_conv(inputs) - x = self._bn0(x) - x = self._swish(x) - - x = self._depthwise_conv(x) - x = self._bn1(x) - x = self._swish(x) - - # Squeeze and Excitation - if self.has_se: - x_squeezed = F.adaptive_avg_pool2d(x, 1) - # x_squeezed = torch.mean(x, [2, 3], keepdim=True) - - x_squeezed = self._se_reduce(x_squeezed) - - x_squeezed = self._swish(x_squeezed) - - x_squeezed = self._se_expand(x_squeezed) - - x = torch.sigmoid(x_squeezed) * x - - # Pointwise Convolution - x = self._project_conv(x) - x = self._bn2(x) - - # Skip connection and drop connect - input_filters, output_filters = self._block_args.input_filters, self._block_args.output_filters - if self.id_skip and self._block_args.stride == 1 and input_filters == output_filters: - # The combination of skip connection and drop connect brings about stochastic depth. - if drop_connect_rate: - x = drop_connect(x, p=drop_connect_rate, training=self.training) - x = x + inputs # skip connection - return x - - def set_swish(self, memory_efficient=True): - """Sets swish function as memory efficient (for training) or standard (for export). - - Args: - memory_efficient (bool): Whether to use memory-efficient version of swish. - """ - self._swish = MemoryEfficientSwish() if memory_efficient else Swish() - - -class EfficientNet(nn.Module): - """EfficientNet model. - Most easily loaded with the .from_name or .from_pretrained methods. - - Args: - blocks_args (list[namedtuple]): A list of BlockArgs to construct blocks. - global_params (namedtuple): A set of GlobalParams shared between blocks. - - References: - [1] https://arxiv.org/abs/1905.11946 (EfficientNet) - - Example: - >>> import torch - >>> from efficientnet.model import EfficientNet - >>> inputs = torch.rand(1, 3, 224, 224) - >>> model = EfficientNet.from_pretrained('efficientnet-b0') - >>> model.eval() - >>> outputs = model(inputs) - """ - - def __init__(self, blocks_args=None, global_params=None): - super().__init__() - assert isinstance(blocks_args, list), 'blocks_args should be a list' - assert len(blocks_args) > 0, 'block args must be greater than 0' - self._global_params = global_params - self._blocks_args = blocks_args - - # Batch norm parameters - bn_mom = 1 - self._global_params.batch_norm_momentum - bn_eps = self._global_params.batch_norm_epsilon - - # Get stem static or dynamic convolution depending on image size - image_size = global_params.image_size - Conv2d = get_same_padding_conv2d(image_size=image_size) - - # Stem - in_channels = 3 # rgb - out_channels = round_filters(32, self._global_params) # number of output channels - self._conv_stem = Conv2d(in_channels, out_channels, kernel_size=3, stride=2, bias=False) - self._bn0 = nn.BatchNorm2d(num_features=out_channels, momentum=bn_mom, eps=bn_eps) - image_size = calculate_output_image_size(image_size, 2) - - # Build blocks - self._blocks = nn.ModuleList([]) - for block_args in self._blocks_args: - - # Update block input and output filters based on depth multiplier. - block_args = block_args._replace( - input_filters=round_filters(block_args.input_filters, self._global_params), - output_filters=round_filters(block_args.output_filters, self._global_params), - num_repeat=round_repeats(block_args.num_repeat, self._global_params) - ) - - # The first block needs to take care of stride and filter size increase. - self._blocks.append(MBConvBlock(block_args, self._global_params, image_size=image_size)) - image_size = calculate_output_image_size(image_size, block_args.stride) - if block_args.num_repeat > 1: # modify block_args to keep same output size - block_args = block_args._replace(input_filters=block_args.output_filters, stride=1) - for _ in range(block_args.num_repeat - 1): - self._blocks.append(MBConvBlock(block_args, self._global_params, image_size=image_size)) - # image_size = calculate_output_image_size(image_size, block_args.stride) # stride = 1 - - # Head - in_channels = block_args.output_filters # output of final block - out_channels = round_filters(1280, self._global_params) - Conv2d = get_same_padding_conv2d(image_size=image_size) - self._conv_head = Conv2d(in_channels, out_channels, kernel_size=1, bias=False) - self._bn1 = nn.BatchNorm2d(num_features=out_channels, momentum=bn_mom, eps=bn_eps) - - # Final linear layer - self._avg_pooling = nn.AdaptiveAvgPool2d(1) - self._dropout = nn.Dropout(self._global_params.dropout_rate) - self._fc = nn.Linear(out_channels, self._global_params.num_classes) - self._swish = MemoryEfficientSwish() - - def set_swish(self, memory_efficient=True): - """Sets swish function as memory efficient (for training) or standard (for export). - - Args: - memory_efficient (bool): Whether to use memory-efficient version of swish. - - """ - self._swish = MemoryEfficientSwish() if memory_efficient else Swish() - for block in self._blocks: - block.set_swish(memory_efficient) - - def extract_endpoints(self, inputs): - """Use convolution layer to extract features - from reduction levels i in [1, 2, 3, 4, 5]. - - Args: - inputs (tensor): Input tensor. - - Returns: - Dictionary of last intermediate features - with reduction levels i in [1, 2, 3, 4, 5]. - Example: - >>> import torch - >>> from efficientnet.model import EfficientNet - >>> inputs = torch.rand(1, 3, 224, 224) - >>> model = EfficientNet.from_pretrained('efficientnet-b0') - >>> endpoints = model.extract_features(inputs) - >>> print(endpoints['reduction_1'].shape) # torch.Size([1, 16, 112, 112]) - >>> print(endpoints['reduction_2'].shape) # torch.Size([1, 24, 56, 56]) - >>> print(endpoints['reduction_3'].shape) # torch.Size([1, 40, 28, 28]) - >>> print(endpoints['reduction_4'].shape) # torch.Size([1, 112, 14, 14]) - >>> print(endpoints['reduction_5'].shape) # torch.Size([1, 1280, 7, 7]) - """ - endpoints = dict() - - # Stem - x = self._swish(self._bn0(self._conv_stem(inputs))) - # x = self._swish(self._conv_stem(inputs)) - prev_x = x - - # Blocks - for idx, block in enumerate(self._blocks): - drop_connect_rate = self._global_params.drop_connect_rate - if drop_connect_rate: - drop_connect_rate *= float(idx) / len(self._blocks) # scale drop connect_rate - x = block(x, drop_connect_rate=drop_connect_rate) - if prev_x.size(2) > x.size(2): - endpoints[f'reduction_{len(endpoints)+1}'] = prev_x - prev_x = x - - # Head - x = self._swish(self._bn1(self._conv_head(x))) - - endpoints[f'reduction_{len(endpoints)+1}'] = x - - return endpoints - - def extract_features(self, inputs): - """use convolution layer to extract feature . - - Args: - inputs (tensor): Input tensor. - - Returns: - Output of the final convolution - layer in the efficientnet model. - """ - # Stem - x = self._swish(self._bn0(self._conv_stem(inputs))) - - - # Blocks - for idx, block in enumerate(self._blocks): - drop_connect_rate = self._global_params.drop_connect_rate - if drop_connect_rate: - drop_connect_rate *= float(idx) / len(self._blocks) # scale drop connect_rate - x = block(x, drop_connect_rate=drop_connect_rate) - - # Head - x = self._swish(self._bn1(self._conv_head(x))) - - return x - - def forward(self, inputs): - """EfficientNet's forward function. - Calls extract_features to extract features, applies final linear layer, and returns logits. - - Args: - inputs (tensor): Input tensor. - - Returns: - Output of this model after processing. - """ - - # Convolution layers - x = self.extract_features(inputs) - - # Pooling and final linear layer - x = self._avg_pooling(x) - x = torch.flatten(x, start_dim=1) - x = self._dropout(x) - x = self._fc(x) - - return x - - @classmethod - def from_name(cls, model_name, in_channels=3, **override_params): - """create an efficientnet model according to name. - - Args: - model_name (str): Name for efficientnet. - in_channels (int): Input data's channel number. - override_params (other key word params): - Params to override model's global_params. - Optional key: - 'width_coefficient', 'depth_coefficient', - 'image_size', 'dropout_rate', - 'num_classes', 'batch_norm_momentum', - 'batch_norm_epsilon', 'drop_connect_rate', - 'depth_divisor', 'min_depth' - - Returns: - An efficientnet model. - """ - cls._check_model_name_is_valid(model_name) - blocks_args, global_params = get_model_params(model_name, override_params) - model = cls(blocks_args, global_params) - model._change_in_channels(in_channels) - return model - - @classmethod - def from_pretrained(cls, model_name, weights_path=None, advprop=False, - in_channels=3, num_classes=1000, **override_params): - """create an efficientnet model according to name. - - Args: - model_name (str): Name for efficientnet. - weights_path (None or str): - str: path to pretrained weights file on the local disk. - None: use pretrained weights downloaded from the Internet. - advprop (bool): - Whether to load pretrained weights - trained with advprop (valid when weights_path is None). - in_channels (int): Input data's channel number. - num_classes (int): - Number of categories for classification. - It controls the output size for final linear layer. - override_params (other key word params): - Params to override model's global_params. - Optional key: - 'width_coefficient', 'depth_coefficient', - 'image_size', 'dropout_rate', - 'num_classes', 'batch_norm_momentum', - 'batch_norm_epsilon', 'drop_connect_rate', - 'depth_divisor', 'min_depth' - - Returns: - A pretrained efficientnet model. - """ - model = cls.from_name(model_name, num_classes = num_classes, **override_params) - load_pretrained_weights(model, model_name, weights_path=weights_path, load_fc=(num_classes == 1000), advprop=advprop) - model._change_in_channels(in_channels) - return model - - @classmethod - def get_image_size(cls, model_name): - """Get the input image size for a given efficientnet model. - - Args: - model_name (str): Name for efficientnet. - - Returns: - Input image size (resolution). - """ - cls._check_model_name_is_valid(model_name) - _, _, res, _ = efficientnet_params(model_name) - return res - - @classmethod - def _check_model_name_is_valid(cls, model_name): - """Validates model name. - - Args: - model_name (str): Name for efficientnet. - - Returns: - bool: Is a valid name or not. - """ - valid_models = ['efficientnet-b'+str(i) for i in range(9)] - - # Support the construction of 'efficientnet-l2' without pretrained weights - valid_models += ['efficientnet-l2'] - - if model_name not in valid_models: - raise ValueError('model_name should be one of: ' + ', '.join(valid_models)) - - def _change_in_channels(self, in_channels): - """Adjust model's first convolution layer to in_channels, if in_channels not equals 3. - - Args: - in_channels (int): Input data's channel number. - """ - if in_channels != 3: - Conv2d = get_same_padding_conv2d(image_size = self._global_params.image_size) - out_channels = round_filters(32, self._global_params) - self._conv_stem = Conv2d(in_channels, out_channels, kernel_size=3, stride=2, bias=False) +# Copyright [yyyy] [name of copyright owner] +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch +from torch import nn +from torch.nn import functional as F +from .utils import ( + round_filters, + round_repeats, + drop_connect, + get_same_padding_conv2d, + get_model_params, + efficientnet_params, + load_pretrained_weights, + Swish, + MemoryEfficientSwish, + calculate_output_image_size +) + +class MBConvBlock(nn.Module): + """Mobile Inverted Residual Bottleneck Block. + + Args: + block_args (namedtuple): BlockArgs, defined in utils.py. + global_params (namedtuple): GlobalParam, defined in utils.py. + image_size (tuple or list): [image_height, image_width]. + + References: + [1] https://arxiv.org/abs/1704.04861 (MobileNet v1) + [2] https://arxiv.org/abs/1801.04381 (MobileNet v2) + [3] https://arxiv.org/abs/1905.02244 (MobileNet v3) + """ + + def __init__(self, block_args, global_params, image_size=None): + super().__init__() + self._block_args = block_args + self._bn_mom = 1 - global_params.batch_norm_momentum # pytorch's difference from tensorflow + self._bn_eps = global_params.batch_norm_epsilon + self.has_se = (self._block_args.se_ratio is not None) and (0 < self._block_args.se_ratio <= 1) + self.id_skip = block_args.id_skip # whether to use skip connection and drop connect + + # Expansion phase (Inverted Bottleneck) + inp = self._block_args.input_filters # number of input channels + oup = self._block_args.input_filters * self._block_args.expand_ratio # number of output channels + if self._block_args.expand_ratio != 1: + Conv2d = get_same_padding_conv2d(image_size=image_size) + self._expand_conv = Conv2d(in_channels=inp, out_channels=oup, kernel_size=1, bias=False) + self._bn0 = nn.BatchNorm2d(num_features=oup, momentum=self._bn_mom, eps=self._bn_eps) + # image_size = calculate_output_image_size(image_size, 1) <-- this wouldn't modify image_size + + # Depthwise convolution phase + k = self._block_args.kernel_size + s = self._block_args.stride + Conv2d = get_same_padding_conv2d(image_size=image_size) + self._depthwise_conv = Conv2d( + in_channels=oup, out_channels=oup, groups=oup, # groups makes it depthwise + kernel_size=k, stride=s, bias=False) + self._bn1 = nn.BatchNorm2d(num_features=oup, momentum=self._bn_mom, eps=self._bn_eps) + image_size = calculate_output_image_size(image_size, s) + + # Squeeze and Excitation layer, if desired + if self.has_se: + Conv2d = get_same_padding_conv2d(image_size=(1,1)) + num_squeezed_channels = max(1, int(self._block_args.input_filters * self._block_args.se_ratio)) + self._se_reduce = Conv2d(in_channels=oup, out_channels=num_squeezed_channels, kernel_size=1) + self._se_expand = Conv2d(in_channels=num_squeezed_channels, out_channels=oup, kernel_size=1) + # self._se_relu = torch.nn.ReLU() + # self._se_sigmoid = torch.nn.Sigmoid() + + # Pointwise convolution phase + final_oup = self._block_args.output_filters + Conv2d = get_same_padding_conv2d(image_size=image_size) + self._project_conv = Conv2d(in_channels=oup, out_channels=final_oup, kernel_size=1, bias=False) + self._bn2 = nn.BatchNorm2d(num_features=final_oup, momentum=self._bn_mom, eps=self._bn_eps) + self._swish = MemoryEfficientSwish() + + def forward(self, inputs, drop_connect_rate=None): + """MBConvBlock's forward function. + + Args: + inputs (tensor): Input tensor. + drop_connect_rate (bool): Drop connect rate (float, between 0 and 1). + + Returns: + Output of this block after processing. + """ + + # Expansion and Depthwise Convolution + x = inputs + if self._block_args.expand_ratio != 1: + x = self._expand_conv(inputs) + x = self._bn0(x) + x = self._swish(x) + + x = self._depthwise_conv(x) + x = self._bn1(x) + x = self._swish(x) + + # Squeeze and Excitation + if self.has_se: + x_squeezed = F.adaptive_avg_pool2d(x, 1) + # x_squeezed = torch.mean(x, [2, 3], keepdim=True) + + x_squeezed = self._se_reduce(x_squeezed) + + x_squeezed = self._swish(x_squeezed) + + x_squeezed = self._se_expand(x_squeezed) + + x = torch.sigmoid(x_squeezed) * x + + # Pointwise Convolution + x = self._project_conv(x) + x = self._bn2(x) + + # Skip connection and drop connect + input_filters, output_filters = self._block_args.input_filters, self._block_args.output_filters + if self.id_skip and self._block_args.stride == 1 and input_filters == output_filters: + # The combination of skip connection and drop connect brings about stochastic depth. + if drop_connect_rate: + x = drop_connect(x, p=drop_connect_rate, training=self.training) + x = x + inputs # skip connection + return x + + def set_swish(self, memory_efficient=True): + """Sets swish function as memory efficient (for training) or standard (for export). + + Args: + memory_efficient (bool): Whether to use memory-efficient version of swish. + """ + self._swish = MemoryEfficientSwish() if memory_efficient else Swish() + + +class EfficientNet(nn.Module): + """EfficientNet model. + Most easily loaded with the .from_name or .from_pretrained methods. + + Args: + blocks_args (list[namedtuple]): A list of BlockArgs to construct blocks. + global_params (namedtuple): A set of GlobalParams shared between blocks. + + References: + [1] https://arxiv.org/abs/1905.11946 (EfficientNet) + + Example: + >>> import torch + >>> from efficientnet.model import EfficientNet + >>> inputs = torch.rand(1, 3, 224, 224) + >>> model = EfficientNet.from_pretrained('efficientnet-b0') + >>> model.eval() + >>> outputs = model(inputs) + """ + + def __init__(self, blocks_args=None, global_params=None): + super().__init__() + assert isinstance(blocks_args, list), 'blocks_args should be a list' + assert len(blocks_args) > 0, 'block args must be greater than 0' + self._global_params = global_params + self._blocks_args = blocks_args + + # Batch norm parameters + bn_mom = 1 - self._global_params.batch_norm_momentum + bn_eps = self._global_params.batch_norm_epsilon + + # Get stem static or dynamic convolution depending on image size + image_size = global_params.image_size + Conv2d = get_same_padding_conv2d(image_size=image_size) + + # Stem + in_channels = 3 # rgb + out_channels = round_filters(32, self._global_params) # number of output channels + self._conv_stem = Conv2d(in_channels, out_channels, kernel_size=3, stride=2, bias=False) + self._bn0 = nn.BatchNorm2d(num_features=out_channels, momentum=bn_mom, eps=bn_eps) + image_size = calculate_output_image_size(image_size, 2) + + # Build blocks + self._blocks = nn.ModuleList([]) + for block_args in self._blocks_args: + + # Update block input and output filters based on depth multiplier. + block_args = block_args._replace( + input_filters=round_filters(block_args.input_filters, self._global_params), + output_filters=round_filters(block_args.output_filters, self._global_params), + num_repeat=round_repeats(block_args.num_repeat, self._global_params) + ) + + # The first block needs to take care of stride and filter size increase. + self._blocks.append(MBConvBlock(block_args, self._global_params, image_size=image_size)) + image_size = calculate_output_image_size(image_size, block_args.stride) + if block_args.num_repeat > 1: # modify block_args to keep same output size + block_args = block_args._replace(input_filters=block_args.output_filters, stride=1) + for _ in range(block_args.num_repeat - 1): + self._blocks.append(MBConvBlock(block_args, self._global_params, image_size=image_size)) + # image_size = calculate_output_image_size(image_size, block_args.stride) # stride = 1 + + # Head + in_channels = block_args.output_filters # output of final block + out_channels = round_filters(1280, self._global_params) + Conv2d = get_same_padding_conv2d(image_size=image_size) + self._conv_head = Conv2d(in_channels, out_channels, kernel_size=1, bias=False) + self._bn1 = nn.BatchNorm2d(num_features=out_channels, momentum=bn_mom, eps=bn_eps) + + # Final linear layer + self._avg_pooling = nn.AdaptiveAvgPool2d(1) + self._dropout = nn.Dropout(self._global_params.dropout_rate) + self._fc = nn.Linear(out_channels, self._global_params.num_classes) + self._swish = MemoryEfficientSwish() + + def set_swish(self, memory_efficient=True): + """Sets swish function as memory efficient (for training) or standard (for export). + + Args: + memory_efficient (bool): Whether to use memory-efficient version of swish. + + """ + self._swish = MemoryEfficientSwish() if memory_efficient else Swish() + for block in self._blocks: + block.set_swish(memory_efficient) + + def extract_endpoints(self, inputs): + """Use convolution layer to extract features + from reduction levels i in [1, 2, 3, 4, 5]. + + Args: + inputs (tensor): Input tensor. + + Returns: + Dictionary of last intermediate features + with reduction levels i in [1, 2, 3, 4, 5]. + Example: + >>> import torch + >>> from efficientnet.model import EfficientNet + >>> inputs = torch.rand(1, 3, 224, 224) + >>> model = EfficientNet.from_pretrained('efficientnet-b0') + >>> endpoints = model.extract_features(inputs) + >>> print(endpoints['reduction_1'].shape) # torch.Size([1, 16, 112, 112]) + >>> print(endpoints['reduction_2'].shape) # torch.Size([1, 24, 56, 56]) + >>> print(endpoints['reduction_3'].shape) # torch.Size([1, 40, 28, 28]) + >>> print(endpoints['reduction_4'].shape) # torch.Size([1, 112, 14, 14]) + >>> print(endpoints['reduction_5'].shape) # torch.Size([1, 1280, 7, 7]) + """ + endpoints = dict() + + # Stem + x = self._swish(self._bn0(self._conv_stem(inputs))) + # x = self._swish(self._conv_stem(inputs)) + prev_x = x + + # Blocks + for idx, block in enumerate(self._blocks): + drop_connect_rate = self._global_params.drop_connect_rate + if drop_connect_rate: + drop_connect_rate *= float(idx) / len(self._blocks) # scale drop connect_rate + x = block(x, drop_connect_rate=drop_connect_rate) + if prev_x.size(2) > x.size(2): + endpoints[f'reduction_{len(endpoints)+1}'] = prev_x + prev_x = x + + # Head + x = self._swish(self._bn1(self._conv_head(x))) + + endpoints[f'reduction_{len(endpoints)+1}'] = x + + return endpoints + + def extract_features(self, inputs): + """use convolution layer to extract feature . + + Args: + inputs (tensor): Input tensor. + + Returns: + Output of the final convolution + layer in the efficientnet model. + """ + # Stem + x = self._swish(self._bn0(self._conv_stem(inputs))) + + + # Blocks + for idx, block in enumerate(self._blocks): + drop_connect_rate = self._global_params.drop_connect_rate + if drop_connect_rate: + drop_connect_rate *= float(idx) / len(self._blocks) # scale drop connect_rate + x = block(x, drop_connect_rate=drop_connect_rate) + + # Head + x = self._swish(self._bn1(self._conv_head(x))) + + return x + + def forward(self, inputs): + """EfficientNet's forward function. + Calls extract_features to extract features, applies final linear layer, and returns logits. + + Args: + inputs (tensor): Input tensor. + + Returns: + Output of this model after processing. + """ + + # Convolution layers + x = self.extract_features(inputs) + + # Pooling and final linear layer + x = self._avg_pooling(x) + x = torch.flatten(x, start_dim=1) + x = self._dropout(x) + x = self._fc(x) + + return x + + @classmethod + def from_name(cls, model_name, in_channels=3, **override_params): + """create an efficientnet model according to name. + + Args: + model_name (str): Name for efficientnet. + in_channels (int): Input data's channel number. + override_params (other key word params): + Params to override model's global_params. + Optional key: + 'width_coefficient', 'depth_coefficient', + 'image_size', 'dropout_rate', + 'num_classes', 'batch_norm_momentum', + 'batch_norm_epsilon', 'drop_connect_rate', + 'depth_divisor', 'min_depth' + + Returns: + An efficientnet model. + """ + cls._check_model_name_is_valid(model_name) + blocks_args, global_params = get_model_params(model_name, override_params) + model = cls(blocks_args, global_params) + model._change_in_channels(in_channels) + return model + + @classmethod + def from_pretrained(cls, model_name, weights_path=None, advprop=False, + in_channels=3, num_classes=1000, **override_params): + """create an efficientnet model according to name. + + Args: + model_name (str): Name for efficientnet. + weights_path (None or str): + str: path to pretrained weights file on the local disk. + None: use pretrained weights downloaded from the Internet. + advprop (bool): + Whether to load pretrained weights + trained with advprop (valid when weights_path is None). + in_channels (int): Input data's channel number. + num_classes (int): + Number of categories for classification. + It controls the output size for final linear layer. + override_params (other key word params): + Params to override model's global_params. + Optional key: + 'width_coefficient', 'depth_coefficient', + 'image_size', 'dropout_rate', + 'num_classes', 'batch_norm_momentum', + 'batch_norm_epsilon', 'drop_connect_rate', + 'depth_divisor', 'min_depth' + + Returns: + A pretrained efficientnet model. + """ + model = cls.from_name(model_name, num_classes = num_classes, **override_params) + load_pretrained_weights(model, model_name, weights_path=weights_path, load_fc=(num_classes == 1000), advprop=advprop) + model._change_in_channels(in_channels) + return model + + @classmethod + def get_image_size(cls, model_name): + """Get the input image size for a given efficientnet model. + + Args: + model_name (str): Name for efficientnet. + + Returns: + Input image size (resolution). + """ + cls._check_model_name_is_valid(model_name) + _, _, res, _ = efficientnet_params(model_name) + return res + + @classmethod + def _check_model_name_is_valid(cls, model_name): + """Validates model name. + + Args: + model_name (str): Name for efficientnet. + + Returns: + bool: Is a valid name or not. + """ + valid_models = ['efficientnet-b'+str(i) for i in range(9)] + + # Support the construction of 'efficientnet-l2' without pretrained weights + valid_models += ['efficientnet-l2'] + + if model_name not in valid_models: + raise ValueError('model_name should be one of: ' + ', '.join(valid_models)) + + def _change_in_channels(self, in_channels): + """Adjust model's first convolution layer to in_channels, if in_channels not equals 3. + + Args: + in_channels (int): Input data's channel number. + """ + if in_channels != 3: + Conv2d = get_same_padding_conv2d(image_size = self._global_params.image_size) + out_channels = round_filters(32, self._global_params) + self._conv_stem = Conv2d(in_channels, out_channels, kernel_size=3, stride=2, bias=False) diff --git a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/rmsprop_tf.py b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/rmsprop_tf.py index 7873ed7393..3666cb6061 100644 --- a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/rmsprop_tf.py +++ b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/rmsprop_tf.py @@ -1,136 +1,136 @@ -# Copyright [yyyy] [name of copyright owner] -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch -from torch.optim import Optimizer - -class RMSpropTF(Optimizer): - """Implements RMSprop algorithm (TensorFlow style epsilon) - - NOTE: This is a direct cut-and-paste of PyTorch RMSprop with eps applied before sqrt - to closer match Tensorflow for matching hyper-params. - - Proposed by G. Hinton in his - `course `_. - - The centered version first appears in `Generating Sequences - With Recurrent Neural Networks `_. - - Arguments: - params (iterable): iterable of parameters to optimize or dicts defining - parameter groups - lr (float, optional): learning rate (default: 1e-2) - momentum (float, optional): momentum factor (default: 0) - alpha (float, optional): smoothing (decay) constant (default: 0.9) - eps (float, optional): term added to the denominator to improve - numerical stability (default: 1e-10) - centered (bool, optional) : if ``True``, compute the centered RMSProp, - the gradient is normalized by an estimation of its variance - weight_decay (float, optional): weight decay (L2 penalty) (default: 0) - decoupled_decay (bool, optional): decoupled weight decay as per https://arxiv.org/abs/1711.05101 - lr_in_momentum (bool, optional): learning rate scaling is included in the momentum buffer - update as per defaults in Tensorflow - - """ - - def __init__(self, params, lr=1e-2, alpha=0.9, eps=1e-10, weight_decay=0, momentum=0., centered=False, - decoupled_decay=False, lr_in_momentum=True): - if not 0.0 <= lr: - raise ValueError("Invalid learning rate: {}".format(lr)) - if not 0.0 <= eps: - raise ValueError("Invalid epsilon value: {}".format(eps)) - if not 0.0 <= momentum: - raise ValueError("Invalid momentum value: {}".format(momentum)) - if not 0.0 <= weight_decay: - raise ValueError("Invalid weight_decay value: {}".format(weight_decay)) - if not 0.0 <= alpha: - raise ValueError("Invalid alpha value: {}".format(alpha)) - - defaults = dict(lr=lr, momentum=momentum, alpha=alpha, eps=eps, centered=centered, weight_decay=weight_decay, - decoupled_decay=decoupled_decay, lr_in_momentum=lr_in_momentum) - super(RMSpropTF, self).__init__(params, defaults) - - def __setstate__(self, state): - super(RMSpropTF, self).__setstate__(state) - for group in self.param_groups: - group.setdefault('momentum', 0) - group.setdefault('centered', False) - - def step(self, closure=None): - """Performs a single optimization step. - - Arguments: - closure (callable, optional): A closure that reevaluates the model - and returns the loss. - """ - loss = None - if closure is not None: - loss = closure() - - for group in self.param_groups: - for p in group['params']: - if p.grad is None: - continue - grad = p.grad.data - if grad.is_sparse: - raise RuntimeError('RMSprop does not support sparse gradients') - state = self.state[p] - - # State initialization - if len(state) == 0: - state['step'] = 0 - state['square_avg'] = torch.ones_like(p.data) # PyTorch inits to zero - if group['momentum'] > 0: - state['momentum_buffer'] = torch.zeros_like(p.data) - if group['centered']: - state['grad_avg'] = torch.zeros_like(p.data) - - square_avg = state['square_avg'] - one_minus_alpha = 1. - group['alpha'] - - state['step'] += 1 - - if group['weight_decay'] != 0: - if 'decoupled_decay' in group and group['decoupled_decay']: - p.data.add_(-group['weight_decay'], p.data) - else: - grad = grad.add(group['weight_decay'], p.data) - - # Tensorflow order of ops for updating squared avg - square_avg.add_(one_minus_alpha, grad.pow(2) - square_avg) - # square_avg.mul_(alpha).addcmul_(1 - alpha, grad, grad) # PyTorch original - - if group['centered']: - grad_avg = state['grad_avg'] - grad_avg.add_(one_minus_alpha, grad - grad_avg) - # grad_avg.mul_(alpha).add_(1 - alpha, grad) # PyTorch original - avg = square_avg.addcmul(-1, grad_avg, grad_avg).add(group['eps']).sqrt_() # eps moved in sqrt - else: - avg = square_avg.add(group['eps']).sqrt_() # eps moved in sqrt - - if group['momentum'] > 0: - buf = state['momentum_buffer'] - # Tensorflow accumulates the LR scaling in the momentum buffer - if 'lr_in_momentum' in group and group['lr_in_momentum']: - buf.mul_(group['momentum']).addcdiv_(group['lr'], grad, avg) - p.data.add_(-buf) - else: - # PyTorch scales the param update by LR - buf.mul_(group['momentum']).addcdiv_(grad, avg) - p.data.add_(-group['lr'], buf) - else: - p.data.addcdiv_(-group['lr'], grad, avg) - +# Copyright [yyyy] [name of copyright owner] +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch +from torch.optim import Optimizer + +class RMSpropTF(Optimizer): + """Implements RMSprop algorithm (TensorFlow style epsilon) + + NOTE: This is a direct cut-and-paste of PyTorch RMSprop with eps applied before sqrt + to closer match Tensorflow for matching hyper-params. + + Proposed by G. Hinton in his + `course `_. + + The centered version first appears in `Generating Sequences + With Recurrent Neural Networks `_. + + Arguments: + params (iterable): iterable of parameters to optimize or dicts defining + parameter groups + lr (float, optional): learning rate (default: 1e-2) + momentum (float, optional): momentum factor (default: 0) + alpha (float, optional): smoothing (decay) constant (default: 0.9) + eps (float, optional): term added to the denominator to improve + numerical stability (default: 1e-10) + centered (bool, optional) : if ``True``, compute the centered RMSProp, + the gradient is normalized by an estimation of its variance + weight_decay (float, optional): weight decay (L2 penalty) (default: 0) + decoupled_decay (bool, optional): decoupled weight decay as per https://arxiv.org/abs/1711.05101 + lr_in_momentum (bool, optional): learning rate scaling is included in the momentum buffer + update as per defaults in Tensorflow + + """ + + def __init__(self, params, lr=1e-2, alpha=0.9, eps=1e-10, weight_decay=0, momentum=0., centered=False, + decoupled_decay=False, lr_in_momentum=True): + if not 0.0 <= lr: + raise ValueError("Invalid learning rate: {}".format(lr)) + if not 0.0 <= eps: + raise ValueError("Invalid epsilon value: {}".format(eps)) + if not 0.0 <= momentum: + raise ValueError("Invalid momentum value: {}".format(momentum)) + if not 0.0 <= weight_decay: + raise ValueError("Invalid weight_decay value: {}".format(weight_decay)) + if not 0.0 <= alpha: + raise ValueError("Invalid alpha value: {}".format(alpha)) + + defaults = dict(lr=lr, momentum=momentum, alpha=alpha, eps=eps, centered=centered, weight_decay=weight_decay, + decoupled_decay=decoupled_decay, lr_in_momentum=lr_in_momentum) + super(RMSpropTF, self).__init__(params, defaults) + + def __setstate__(self, state): + super(RMSpropTF, self).__setstate__(state) + for group in self.param_groups: + group.setdefault('momentum', 0) + group.setdefault('centered', False) + + def step(self, closure=None): + """Performs a single optimization step. + + Arguments: + closure (callable, optional): A closure that reevaluates the model + and returns the loss. + """ + loss = None + if closure is not None: + loss = closure() + + for group in self.param_groups: + for p in group['params']: + if p.grad is None: + continue + grad = p.grad.data + if grad.is_sparse: + raise RuntimeError('RMSprop does not support sparse gradients') + state = self.state[p] + + # State initialization + if len(state) == 0: + state['step'] = 0 + state['square_avg'] = torch.ones_like(p.data) # PyTorch inits to zero + if group['momentum'] > 0: + state['momentum_buffer'] = torch.zeros_like(p.data) + if group['centered']: + state['grad_avg'] = torch.zeros_like(p.data) + + square_avg = state['square_avg'] + one_minus_alpha = 1. - group['alpha'] + + state['step'] += 1 + + if group['weight_decay'] != 0: + if 'decoupled_decay' in group and group['decoupled_decay']: + p.data.add_(-group['weight_decay'], p.data) + else: + grad = grad.add(group['weight_decay'], p.data) + + # Tensorflow order of ops for updating squared avg + square_avg.add_(one_minus_alpha, grad.pow(2) - square_avg) + # square_avg.mul_(alpha).addcmul_(1 - alpha, grad, grad) # PyTorch original + + if group['centered']: + grad_avg = state['grad_avg'] + grad_avg.add_(one_minus_alpha, grad - grad_avg) + # grad_avg.mul_(alpha).add_(1 - alpha, grad) # PyTorch original + avg = square_avg.addcmul(-1, grad_avg, grad_avg).add(group['eps']).sqrt_() # eps moved in sqrt + else: + avg = square_avg.add(group['eps']).sqrt_() # eps moved in sqrt + + if group['momentum'] > 0: + buf = state['momentum_buffer'] + # Tensorflow accumulates the LR scaling in the momentum buffer + if 'lr_in_momentum' in group and group['lr_in_momentum']: + buf.mul_(group['momentum']).addcdiv_(group['lr'], grad, avg) + p.data.add_(-buf) + else: + # PyTorch scales the param update by LR + buf.mul_(group['momentum']).addcdiv_(grad, avg) + p.data.add_(-group['lr'], buf) + else: + p.data.addcdiv_(-group['lr'], grad, avg) + return loss \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/utils.py b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/utils.py index 2c562e625c..1dbf13b4a8 100644 --- a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/utils.py +++ b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/efficientnet_pytorch/utils.py @@ -1,636 +1,636 @@ -# Copyright [yyyy] [name of copyright owner] -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 re -import math -import collections -from functools import partial -import torch -from torch import nn -from torch.nn import functional as F -from torch.utils import model_zoo - -################################################################################ -### Help functions for model architecture -################################################################################ - -# GlobalParams and BlockArgs: Two namedtuples -# Swish and MemoryEfficientSwish: Two implementations of the method -# round_filters and round_repeats: -# Functions to calculate params for scaling model width and depth ! ! ! -# get_width_and_height_from_size and calculate_output_image_size -# drop_connect: A structural design -# get_same_padding_conv2d: -# Conv2dDynamicSamePadding -# Conv2dStaticSamePadding -# get_same_padding_maxPool2d: -# MaxPool2dDynamicSamePadding -# MaxPool2dStaticSamePadding -# It's an additional function, not used in EfficientNet, -# but can be used in other model (such as EfficientDet). -# Identity: An implementation of identical mapping - -# Parameters for the entire model (stem, all blocks, and head) -GlobalParams = collections.namedtuple('GlobalParams', [ - 'width_coefficient', 'depth_coefficient', 'image_size', 'dropout_rate', - 'num_classes', 'batch_norm_momentum', 'batch_norm_epsilon', - 'drop_connect_rate', 'depth_divisor', 'min_depth']) - -# Parameters for an individual model block -BlockArgs = collections.namedtuple('BlockArgs', [ - 'num_repeat', 'kernel_size', 'stride', 'expand_ratio', - 'input_filters', 'output_filters', 'se_ratio', 'id_skip']) - -# Set GlobalParams and BlockArgs's defaults -GlobalParams.__new__.__defaults__ = (None,) * len(GlobalParams._fields) -BlockArgs.__new__.__defaults__ = (None,) * len(BlockArgs._fields) - - -# An ordinary implementation of Swish function -class Swish(nn.Module): - def forward(self, x): - return x * torch.sigmoid(x) - -# A memory-efficient implementation of Swish function -class SwishImplementation(torch.autograd.Function): - @staticmethod - def forward(ctx, i): - result = i * torch.sigmoid(i) - ctx.save_for_backward(i) - return result - - @staticmethod - def backward(ctx, grad_output): - i = ctx.saved_tensors[0] - sigmoid_i = torch.sigmoid(i) - return grad_output * (sigmoid_i * (1 + i * (1 - sigmoid_i))) - -class MemoryEfficientSwish(nn.Module): - def forward(self, x): - return SwishImplementation.apply(x) - - -def round_filters(filters, global_params): - """Calculate and round number of filters based on width multiplier. - Use width_coefficient, depth_divisor and min_depth of global_params. - - Args: - filters (int): Filters number to be calculated. - global_params (namedtuple): Global params of the model. - - Returns: - new_filters: New filters number after calculating. - """ - multiplier = global_params.width_coefficient - if not multiplier: - return filters - # TODO: modify the params names. - # maybe the names (width_divisor,min_width) - # are more suitable than (depth_divisor,min_depth). - divisor = global_params.depth_divisor - min_depth = global_params.min_depth - filters *= multiplier - min_depth = min_depth or divisor # pay attention to this line when using min_depth - # follow the formula transferred from official TensorFlow implementation - new_filters = max(min_depth, int(filters + divisor / 2) // divisor * divisor) - if new_filters < 0.9 * filters: # prevent rounding by more than 10% - new_filters += divisor - return int(new_filters) - - -def round_repeats(repeats, global_params): - """Calculate module's repeat number of a block based on depth multiplier. - Use depth_coefficient of global_params. - - Args: - repeats (int): num_repeat to be calculated. - global_params (namedtuple): Global params of the model. - - Returns: - new repeat: New repeat number after calculating. - """ - multiplier = global_params.depth_coefficient - if not multiplier: - return repeats - # follow the formula transferred from official TensorFlow implementation - return int(math.ceil(multiplier * repeats)) - - -def drop_connect(inputs, p, training): - """Drop connect. - - Args: - inputs (tensor: BCWH): Input of this structure. - p (float: 0.0~1.0): Probability of drop connection. - training (bool): The running mode. - - Returns: - output: Output after drop connection. - """ - assert p >= 0 and p <= 1, 'p must be in range of [0,1]' - - if not training: - return inputs - - batch_size = inputs.shape[0] - keep_prob = 1 - p - - # generate binary_tensor mask according to probability (p for 0, 1-p for 1) - random_tensor = keep_prob - random_tensor += torch.rand([batch_size, 1, 1, 1], dtype=inputs.dtype, device=inputs.device) - binary_tensor = torch.floor(random_tensor) / keep_prob - - output = inputs * binary_tensor - return output - - -def get_width_and_height_from_size(x): - """Obtain height and width from x. - - Args: - x (int, tuple or list): Data size. - - Returns: - size: A tuple or list (H,W). - """ - if isinstance(x, int): - return x, x - if isinstance(x, list) or isinstance(x, tuple): - return x - else: - raise TypeError() - - -def calculate_output_image_size(input_image_size, stride): - """Calculates the output image size when using Conv2dSamePadding with a stride. - Necessary for static padding. Thanks to mannatsingh for pointing this out. - - Args: - input_image_size (int, tuple or list): Size of input image. - stride (int, tuple or list): Conv2d operation's stride. - - Returns: - output_image_size: A list [H,W]. - """ - if input_image_size is None: - return None - image_height, image_width = get_width_and_height_from_size(input_image_size) - stride = stride if isinstance(stride, int) else stride[0] - image_height = int(math.ceil(image_height / stride)) - image_width = int(math.ceil(image_width / stride)) - return [image_height, image_width] - - -# Note: -# The following 'SamePadding' functions make output size equal ceil(input size/stride). -# Only when stride equals 1, can the output size be the same as input size. -# Don't be confused by their function names ! ! ! - -def get_same_padding_conv2d(image_size=None): - """Chooses static padding if you have specified an image size, and dynamic padding otherwise. - Static padding is necessary for ONNX exporting of models. - - Args: - image_size (int or tuple): Size of the image. - - Returns: - Conv2dDynamicSamePadding or Conv2dStaticSamePadding. - """ - if image_size is None: - return Conv2dDynamicSamePadding - else: - return partial(Conv2dStaticSamePadding, image_size=image_size) - - -class Conv2dDynamicSamePadding(nn.Conv2d): - """2D Convolutions like TensorFlow, for a dynamic image size. - The padding is operated in forward function by calculating dynamically. - """ - - # Tips for 'SAME' mode padding. - # Given the following: - # i: width or height - # s: stride - # k: kernel size - # d: dilation - # p: padding - # Output after Conv2d: - # o = floor((i+p-((k-1)*d+1))/s+1) - # If o equals i, i = floor((i+p-((k-1)*d+1))/s+1), - # => p = (i-1)*s+((k-1)*d+1)-i - - def __init__(self, in_channels, out_channels, kernel_size, stride=1, dilation=1, groups=1, bias=True): - super().__init__(in_channels, out_channels, kernel_size, stride, 0, dilation, groups, bias) - self.stride = self.stride if len(self.stride) == 2 else [self.stride[0]] * 2 - - def forward(self, x): - ih, iw = x.size()[-2:] - kh, kw = self.weight.size()[-2:] - sh, sw = self.stride - oh, ow = math.ceil(ih / sh), math.ceil(iw / sw) # change the output size according to stride ! ! ! - pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0) - pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0) - if pad_h > 0 or pad_w > 0: - x = F.pad(x, [pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2]) - return F.conv2d(x, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups) - - -class Conv2dStaticSamePadding(nn.Conv2d): - """2D Convolutions like TensorFlow's 'SAME' mode, with the given input image size. - The padding mudule is calculated in construction function, then used in forward. - """ - - # With the same calculation as Conv2dDynamicSamePadding - - def __init__(self, in_channels, out_channels, kernel_size, stride=1, image_size=None, **kwargs): - super().__init__(in_channels, out_channels, kernel_size, stride, **kwargs) - self.stride = self.stride if len(self.stride) == 2 else [self.stride[0]] * 2 - - # Calculate padding based on image size and save it - assert image_size is not None - ih, iw = (image_size, image_size) if isinstance(image_size, int) else image_size - kh, kw = self.weight.size()[-2:] - sh, sw = self.stride - oh, ow = math.ceil(ih / sh), math.ceil(iw / sw) - pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0) - pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0) - if pad_h > 0 or pad_w > 0: - self.static_padding = nn.ZeroPad2d((pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2)) - if kh % 2 != 0: - self.padding = (kh - 1) // 2 - else: - self.padding = kh // 2 - else: - self.static_padding = Identity() - - def forward(self, x): - x = F.conv2d(x, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups) - return x - - -def get_same_padding_maxPool2d(image_size=None): - """Chooses static padding if you have specified an image size, and dynamic padding otherwise. - Static padding is necessary for ONNX exporting of models. - - Args: - image_size (int or tuple): Size of the image. - - Returns: - MaxPool2dDynamicSamePadding or MaxPool2dStaticSamePadding. - """ - if image_size is None: - return MaxPool2dDynamicSamePadding - else: - return partial(MaxPool2dStaticSamePadding, image_size=image_size) - - -class MaxPool2dDynamicSamePadding(nn.MaxPool2d): - """2D MaxPooling like TensorFlow's 'SAME' mode, with a dynamic image size. - The padding is operated in forward function by calculating dynamically. - """ - - def __init__(self, kernel_size, stride, padding=0, dilation=1, return_indices=False, ceil_mode=False): - super().__init__(kernel_size, stride, padding, dilation, return_indices, ceil_mode) - self.stride = [self.stride] * 2 if isinstance(self.stride, int) else self.stride - self.kernel_size = [self.kernel_size] * 2 if isinstance(self.kernel_size, int) else self.kernel_size - self.dilation = [self.dilation] * 2 if isinstance(self.dilation, int) else self.dilation - - def forward(self, x): - ih, iw = x.size()[-2:] - kh, kw = self.kernel_size - sh, sw = self.stride - oh, ow = math.ceil(ih / sh), math.ceil(iw / sw) - pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0) - pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0) - if pad_h > 0 or pad_w > 0: - x = F.pad(x, [pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2]) - return F.max_pool2d(x, self.kernel_size, self.stride, self.padding, - self.dilation, self.ceil_mode, self.return_indices) - -class MaxPool2dStaticSamePadding(nn.MaxPool2d): - """2D MaxPooling like TensorFlow's 'SAME' mode, with the given input image size. - The padding mudule is calculated in construction function, then used in forward. - """ - - def __init__(self, kernel_size, stride, image_size=None, **kwargs): - super().__init__(kernel_size, stride, **kwargs) - self.stride = [self.stride] * 2 if isinstance(self.stride, int) else self.stride - self.kernel_size = [self.kernel_size] * 2 if isinstance(self.kernel_size, int) else self.kernel_size - self.dilation = [self.dilation] * 2 if isinstance(self.dilation, int) else self.dilation - - # Calculate padding based on image size and save it - assert image_size is not None - ih, iw = (image_size, image_size) if isinstance(image_size, int) else image_size - kh, kw = self.kernel_size - sh, sw = self.stride - oh, ow = math.ceil(ih / sh), math.ceil(iw / sw) - pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0) - pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0) - if pad_h > 0 or pad_w > 0: - self.static_padding = nn.ZeroPad2d((pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2)) - else: - self.static_padding = Identity() - - def forward(self, x): - x = self.static_padding(x) - x = F.max_pool2d(x, self.kernel_size, self.stride, self.padding, - self.dilation, self.ceil_mode, self.return_indices) - return x - -class Identity(nn.Module): - """Identity mapping. - Send input to output directly. - """ - - def __init__(self): - super(Identity, self).__init__() - - def forward(self, input): - return input - - -################################################################################ -### Helper functions for loading model params -################################################################################ - -# BlockDecoder: A Class for encoding and decoding BlockArgs -# efficientnet_params: A function to query compound coefficient -# get_model_params and efficientnet: -# Functions to get BlockArgs and GlobalParams for efficientnet -# url_map and url_map_advprop: Dicts of url_map for pretrained weights -# load_pretrained_weights: A function to load pretrained weights - -class BlockDecoder(object): - """Block Decoder for readability, - straight from the official TensorFlow repository. - """ - - @staticmethod - def _decode_block_string(block_string): - """Get a block through a string notation of arguments. - - Args: - block_string (str): A string notation of arguments. - Examples: 'r1_k3_s11_e1_i32_o16_se0.25_noskip'. - - Returns: - BlockArgs: The namedtuple defined at the top of this file. - """ - assert isinstance(block_string, str) - - ops = block_string.split('_') - options = {} - for op in ops: - splits = re.split(r'(\d.*)', op) - if len(splits) >= 2: - key, value = splits[:2] - options[key] = value - - # Check stride - assert (('s' in options and len(options['s']) == 1) or - (len(options['s']) == 2 and options['s'][0] == options['s'][1])) - - return BlockArgs( - num_repeat=int(options['r']), - kernel_size=int(options['k']), - stride=[int(options['s'][0])], - expand_ratio=int(options['e']), - input_filters=int(options['i']), - output_filters=int(options['o']), - se_ratio=float(options['se']) if 'se' in options else None, - id_skip=('noskip' not in block_string)) - - @staticmethod - def _encode_block_string(block): - """Encode a block to a string. - - Args: - block (namedtuple): A BlockArgs type argument. - - Returns: - block_string: A String form of BlockArgs. - """ - args = [ - 'r%d' % block.num_repeat, - 'k%d' % block.kernel_size, - 's%d%d' % (block.strides[0], block.strides[1]), - 'e%s' % block.expand_ratio, - 'i%d' % block.input_filters, - 'o%d' % block.output_filters - ] - if 0 < block.se_ratio <= 1: - args.append('se%s' % block.se_ratio) - if block.id_skip is False: - args.append('noskip') - return '_'.join(args) - - @staticmethod - def decode(string_list): - """Decode a list of string notations to specify blocks inside the network. - - Args: - string_list (list[str]): A list of strings, each string is a notation of block. - - Returns: - blocks_args: A list of BlockArgs namedtuples of block args. - """ - assert isinstance(string_list, list) - blocks_args = [] - for block_string in string_list: - blocks_args.append(BlockDecoder._decode_block_string(block_string)) - return blocks_args - - @staticmethod - def encode(blocks_args): - """Encode a list of BlockArgs to a list of strings. - - Args: - blocks_args (list[namedtuples]): A list of BlockArgs namedtuples of block args. - - Returns: - block_strings: A list of strings, each string is a notation of block. - """ - block_strings = [] - for block in blocks_args: - block_strings.append(BlockDecoder._encode_block_string(block)) - return block_strings - - -def efficientnet_params(model_name): - """Map EfficientNet model name to parameter coefficients. - - Args: - model_name (str): Model name to be queried. - - Returns: - params_dict[model_name]: A (width,depth,res,dropout) tuple. - """ - params_dict = { - # Coefficients: width,depth,res,dropout - 'efficientnet-b0': (1.0, 1.0, 224, 0.2), - 'efficientnet-b1': (1.0, 1.1, 240, 0.2), - 'efficientnet-b2': (1.1, 1.2, 260, 0.3), - 'efficientnet-b3': (1.2, 1.4, 300, 0.3), - 'efficientnet-b4': (1.4, 1.8, 380, 0.4), - 'efficientnet-b5': (1.6, 2.2, 456, 0.4), - 'efficientnet-b6': (1.8, 2.6, 528, 0.5), - 'efficientnet-b7': (2.0, 3.1, 600, 0.5), - 'efficientnet-b8': (2.2, 3.6, 672, 0.5), - 'efficientnet-l2': (4.3, 5.3, 800, 0.5), - } - return params_dict[model_name] - - -def efficientnet(width_coefficient=None, depth_coefficient=None, image_size=None, - dropout_rate=0.2, drop_connect_rate=0.2, num_classes=1000): - """Create BlockArgs and GlobalParams for efficientnet model. - - Args: - width_coefficient (float) - depth_coefficient (float) - image_size (int) - dropout_rate (float) - drop_connect_rate (float) - num_classes (int) - - Meaning as the name suggests. - - Returns: - blocks_args, global_params. - """ - - # Blocks args for the whole model(efficientnet-b0 by default) - # It will be modified in the construction of EfficientNet Class according to model - blocks_args = [ - 'r1_k3_s11_e1_i32_o16_se0.25', - 'r2_k3_s22_e6_i16_o24_se0.25', - 'r2_k5_s22_e6_i24_o40_se0.25', - 'r3_k3_s22_e6_i40_o80_se0.25', - 'r3_k5_s11_e6_i80_o112_se0.25', - 'r4_k5_s22_e6_i112_o192_se0.25', - 'r1_k3_s11_e6_i192_o320_se0.25', - ] - - blocks_args = BlockDecoder.decode(blocks_args) - - global_params = GlobalParams( - width_coefficient=width_coefficient, - depth_coefficient=depth_coefficient, - image_size=image_size, - dropout_rate=dropout_rate, - - num_classes=num_classes, - batch_norm_momentum=0.99, - batch_norm_epsilon=1e-3, - drop_connect_rate=drop_connect_rate, - depth_divisor=8, - min_depth=None, - ) - - return blocks_args, global_params - - -def get_model_params(model_name, override_params): - """Get the block args and global params for a given model name. - - Args: - model_name (str): Model's name. - override_params (dict): A dict to modify global_params. - - Returns: - blocks_args, global_params - """ - if model_name.startswith('efficientnet'): - w, d, s, p = efficientnet_params(model_name) - # note: all models have drop connect rate = 0.2 - blocks_args, global_params = efficientnet( - width_coefficient=w, depth_coefficient=d, dropout_rate=p, image_size=s) - else: - raise NotImplementedError('model name is not pre-defined: %s' % model_name) - if override_params: - # ValueError will be raised here if override_params has fields not included in global_params. - global_params = global_params._replace(**override_params) - return blocks_args, global_params - - -# train with Standard methods -# check more details in paper(EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks) -url_map = { - 'efficientnet-b0': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b0-355c32eb.pth', - 'efficientnet-b1': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b1-f1951068.pth', - 'efficientnet-b2': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b2-8bb594d6.pth', - 'efficientnet-b3': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b3-5fb5a3c3.pth', - 'efficientnet-b4': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b4-6ed6700e.pth', - 'efficientnet-b5': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b5-b6417697.pth', - 'efficientnet-b6': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b6-c76e70fd.pth', - 'efficientnet-b7': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b7-dcc49843.pth', -} - -# train with Adversarial Examples(AdvProp) -# check more details in paper(Adversarial Examples Improve Image Recognition) -url_map_advprop = { - 'efficientnet-b0': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b0-b64d5a18.pth', - 'efficientnet-b1': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b1-0f3ce85a.pth', - 'efficientnet-b2': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b2-6e9d97e5.pth', - 'efficientnet-b3': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b3-cdd7c0f4.pth', - 'efficientnet-b4': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b4-44fb3a87.pth', - 'efficientnet-b5': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b5-86493f6b.pth', - 'efficientnet-b6': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b6-ac80338e.pth', - 'efficientnet-b7': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b7-4652b6dd.pth', - 'efficientnet-b8': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b8-22a8fe65.pth', -} - -# TODO: add the petrained weights url map of 'efficientnet-l2' - - -def load_pretrained_weights(model, model_name, weights_path=None, load_fc=True, advprop=False): - """Loads pretrained weights from weights path or download using url. - - Args: - model (Module): The whole model of efficientnet. - model_name (str): Model name of efficientnet. - weights_path (None or str): - str: path to pretrained weights file on the local disk. - None: use pretrained weights downloaded from the Internet. - load_fc (bool): Whether to load pretrained weights for fc layer at the end of the model. - advprop (bool): Whether to load pretrained weights - trained with advprop (valid when weights_path is None). - """ - if isinstance(weights_path,str): - state_dict = torch.load(weights_path, map_location='cpu') - else: - # AutoAugment or Advprop (different preprocessing) - url_map_ = url_map_advprop if advprop else url_map - state_dict = model_zoo.load_url(url_map_[model_name]) - if 'state_dict' in state_dict: - state_dict = state_dict['state_dict'] - if 'module.' in list(state_dict.keys())[0]: - state_dict_tmp = dict() - for k, v in state_dict.items(): - state_dict_tmp[k[7:]] = v - state_dict = state_dict_tmp - - if load_fc: - ret = model.load_state_dict(state_dict, strict=False) - assert not ret.missing_keys, f'Missing keys when loading pretrained weights: {ret.missing_keys}' - else: - state_dict.pop('_fc.weight') - state_dict.pop('_fc.bias') - ret = model.load_state_dict(state_dict, strict=False) - assert set(ret.missing_keys) == set( - ['_fc.weight', '_fc.bias']), f'Missing keys when loading pretrained weights: {ret.missing_keys}' - assert not ret.unexpected_keys, f'Missing keys when loading pretrained weights: {ret.unexpected_keys}' - - print('Loaded pretrained weights for {}'.format(model_name)) +# Copyright [yyyy] [name of copyright owner] +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 re +import math +import collections +from functools import partial +import torch +from torch import nn +from torch.nn import functional as F +from torch.utils import model_zoo + +################################################################################ +### Help functions for model architecture +################################################################################ + +# GlobalParams and BlockArgs: Two namedtuples +# Swish and MemoryEfficientSwish: Two implementations of the method +# round_filters and round_repeats: +# Functions to calculate params for scaling model width and depth ! ! ! +# get_width_and_height_from_size and calculate_output_image_size +# drop_connect: A structural design +# get_same_padding_conv2d: +# Conv2dDynamicSamePadding +# Conv2dStaticSamePadding +# get_same_padding_maxPool2d: +# MaxPool2dDynamicSamePadding +# MaxPool2dStaticSamePadding +# It's an additional function, not used in EfficientNet, +# but can be used in other model (such as EfficientDet). +# Identity: An implementation of identical mapping + +# Parameters for the entire model (stem, all blocks, and head) +GlobalParams = collections.namedtuple('GlobalParams', [ + 'width_coefficient', 'depth_coefficient', 'image_size', 'dropout_rate', + 'num_classes', 'batch_norm_momentum', 'batch_norm_epsilon', + 'drop_connect_rate', 'depth_divisor', 'min_depth']) + +# Parameters for an individual model block +BlockArgs = collections.namedtuple('BlockArgs', [ + 'num_repeat', 'kernel_size', 'stride', 'expand_ratio', + 'input_filters', 'output_filters', 'se_ratio', 'id_skip']) + +# Set GlobalParams and BlockArgs's defaults +GlobalParams.__new__.__defaults__ = (None,) * len(GlobalParams._fields) +BlockArgs.__new__.__defaults__ = (None,) * len(BlockArgs._fields) + + +# An ordinary implementation of Swish function +class Swish(nn.Module): + def forward(self, x): + return x * torch.sigmoid(x) + +# A memory-efficient implementation of Swish function +class SwishImplementation(torch.autograd.Function): + @staticmethod + def forward(ctx, i): + result = i * torch.sigmoid(i) + ctx.save_for_backward(i) + return result + + @staticmethod + def backward(ctx, grad_output): + i = ctx.saved_tensors[0] + sigmoid_i = torch.sigmoid(i) + return grad_output * (sigmoid_i * (1 + i * (1 - sigmoid_i))) + +class MemoryEfficientSwish(nn.Module): + def forward(self, x): + return SwishImplementation.apply(x) + + +def round_filters(filters, global_params): + """Calculate and round number of filters based on width multiplier. + Use width_coefficient, depth_divisor and min_depth of global_params. + + Args: + filters (int): Filters number to be calculated. + global_params (namedtuple): Global params of the model. + + Returns: + new_filters: New filters number after calculating. + """ + multiplier = global_params.width_coefficient + if not multiplier: + return filters + # TODO: modify the params names. + # maybe the names (width_divisor,min_width) + # are more suitable than (depth_divisor,min_depth). + divisor = global_params.depth_divisor + min_depth = global_params.min_depth + filters *= multiplier + min_depth = min_depth or divisor # pay attention to this line when using min_depth + # follow the formula transferred from official TensorFlow implementation + new_filters = max(min_depth, int(filters + divisor / 2) // divisor * divisor) + if new_filters < 0.9 * filters: # prevent rounding by more than 10% + new_filters += divisor + return int(new_filters) + + +def round_repeats(repeats, global_params): + """Calculate module's repeat number of a block based on depth multiplier. + Use depth_coefficient of global_params. + + Args: + repeats (int): num_repeat to be calculated. + global_params (namedtuple): Global params of the model. + + Returns: + new repeat: New repeat number after calculating. + """ + multiplier = global_params.depth_coefficient + if not multiplier: + return repeats + # follow the formula transferred from official TensorFlow implementation + return int(math.ceil(multiplier * repeats)) + + +def drop_connect(inputs, p, training): + """Drop connect. + + Args: + inputs (tensor: BCWH): Input of this structure. + p (float: 0.0~1.0): Probability of drop connection. + training (bool): The running mode. + + Returns: + output: Output after drop connection. + """ + assert p >= 0 and p <= 1, 'p must be in range of [0,1]' + + if not training: + return inputs + + batch_size = inputs.shape[0] + keep_prob = 1 - p + + # generate binary_tensor mask according to probability (p for 0, 1-p for 1) + random_tensor = keep_prob + random_tensor += torch.rand([batch_size, 1, 1, 1], dtype=inputs.dtype, device=inputs.device) + binary_tensor = torch.floor(random_tensor) / keep_prob + + output = inputs * binary_tensor + return output + + +def get_width_and_height_from_size(x): + """Obtain height and width from x. + + Args: + x (int, tuple or list): Data size. + + Returns: + size: A tuple or list (H,W). + """ + if isinstance(x, int): + return x, x + if isinstance(x, list) or isinstance(x, tuple): + return x + else: + raise TypeError() + + +def calculate_output_image_size(input_image_size, stride): + """Calculates the output image size when using Conv2dSamePadding with a stride. + Necessary for static padding. Thanks to mannatsingh for pointing this out. + + Args: + input_image_size (int, tuple or list): Size of input image. + stride (int, tuple or list): Conv2d operation's stride. + + Returns: + output_image_size: A list [H,W]. + """ + if input_image_size is None: + return None + image_height, image_width = get_width_and_height_from_size(input_image_size) + stride = stride if isinstance(stride, int) else stride[0] + image_height = int(math.ceil(image_height / stride)) + image_width = int(math.ceil(image_width / stride)) + return [image_height, image_width] + + +# Note: +# The following 'SamePadding' functions make output size equal ceil(input size/stride). +# Only when stride equals 1, can the output size be the same as input size. +# Don't be confused by their function names ! ! ! + +def get_same_padding_conv2d(image_size=None): + """Chooses static padding if you have specified an image size, and dynamic padding otherwise. + Static padding is necessary for ONNX exporting of models. + + Args: + image_size (int or tuple): Size of the image. + + Returns: + Conv2dDynamicSamePadding or Conv2dStaticSamePadding. + """ + if image_size is None: + return Conv2dDynamicSamePadding + else: + return partial(Conv2dStaticSamePadding, image_size=image_size) + + +class Conv2dDynamicSamePadding(nn.Conv2d): + """2D Convolutions like TensorFlow, for a dynamic image size. + The padding is operated in forward function by calculating dynamically. + """ + + # Tips for 'SAME' mode padding. + # Given the following: + # i: width or height + # s: stride + # k: kernel size + # d: dilation + # p: padding + # Output after Conv2d: + # o = floor((i+p-((k-1)*d+1))/s+1) + # If o equals i, i = floor((i+p-((k-1)*d+1))/s+1), + # => p = (i-1)*s+((k-1)*d+1)-i + + def __init__(self, in_channels, out_channels, kernel_size, stride=1, dilation=1, groups=1, bias=True): + super().__init__(in_channels, out_channels, kernel_size, stride, 0, dilation, groups, bias) + self.stride = self.stride if len(self.stride) == 2 else [self.stride[0]] * 2 + + def forward(self, x): + ih, iw = x.size()[-2:] + kh, kw = self.weight.size()[-2:] + sh, sw = self.stride + oh, ow = math.ceil(ih / sh), math.ceil(iw / sw) # change the output size according to stride ! ! ! + pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0) + pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0) + if pad_h > 0 or pad_w > 0: + x = F.pad(x, [pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2]) + return F.conv2d(x, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups) + + +class Conv2dStaticSamePadding(nn.Conv2d): + """2D Convolutions like TensorFlow's 'SAME' mode, with the given input image size. + The padding mudule is calculated in construction function, then used in forward. + """ + + # With the same calculation as Conv2dDynamicSamePadding + + def __init__(self, in_channels, out_channels, kernel_size, stride=1, image_size=None, **kwargs): + super().__init__(in_channels, out_channels, kernel_size, stride, **kwargs) + self.stride = self.stride if len(self.stride) == 2 else [self.stride[0]] * 2 + + # Calculate padding based on image size and save it + assert image_size is not None + ih, iw = (image_size, image_size) if isinstance(image_size, int) else image_size + kh, kw = self.weight.size()[-2:] + sh, sw = self.stride + oh, ow = math.ceil(ih / sh), math.ceil(iw / sw) + pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0) + pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0) + if pad_h > 0 or pad_w > 0: + self.static_padding = nn.ZeroPad2d((pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2)) + if kh % 2 != 0: + self.padding = (kh - 1) // 2 + else: + self.padding = kh // 2 + else: + self.static_padding = Identity() + + def forward(self, x): + x = F.conv2d(x, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups) + return x + + +def get_same_padding_maxPool2d(image_size=None): + """Chooses static padding if you have specified an image size, and dynamic padding otherwise. + Static padding is necessary for ONNX exporting of models. + + Args: + image_size (int or tuple): Size of the image. + + Returns: + MaxPool2dDynamicSamePadding or MaxPool2dStaticSamePadding. + """ + if image_size is None: + return MaxPool2dDynamicSamePadding + else: + return partial(MaxPool2dStaticSamePadding, image_size=image_size) + + +class MaxPool2dDynamicSamePadding(nn.MaxPool2d): + """2D MaxPooling like TensorFlow's 'SAME' mode, with a dynamic image size. + The padding is operated in forward function by calculating dynamically. + """ + + def __init__(self, kernel_size, stride, padding=0, dilation=1, return_indices=False, ceil_mode=False): + super().__init__(kernel_size, stride, padding, dilation, return_indices, ceil_mode) + self.stride = [self.stride] * 2 if isinstance(self.stride, int) else self.stride + self.kernel_size = [self.kernel_size] * 2 if isinstance(self.kernel_size, int) else self.kernel_size + self.dilation = [self.dilation] * 2 if isinstance(self.dilation, int) else self.dilation + + def forward(self, x): + ih, iw = x.size()[-2:] + kh, kw = self.kernel_size + sh, sw = self.stride + oh, ow = math.ceil(ih / sh), math.ceil(iw / sw) + pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0) + pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0) + if pad_h > 0 or pad_w > 0: + x = F.pad(x, [pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2]) + return F.max_pool2d(x, self.kernel_size, self.stride, self.padding, + self.dilation, self.ceil_mode, self.return_indices) + +class MaxPool2dStaticSamePadding(nn.MaxPool2d): + """2D MaxPooling like TensorFlow's 'SAME' mode, with the given input image size. + The padding mudule is calculated in construction function, then used in forward. + """ + + def __init__(self, kernel_size, stride, image_size=None, **kwargs): + super().__init__(kernel_size, stride, **kwargs) + self.stride = [self.stride] * 2 if isinstance(self.stride, int) else self.stride + self.kernel_size = [self.kernel_size] * 2 if isinstance(self.kernel_size, int) else self.kernel_size + self.dilation = [self.dilation] * 2 if isinstance(self.dilation, int) else self.dilation + + # Calculate padding based on image size and save it + assert image_size is not None + ih, iw = (image_size, image_size) if isinstance(image_size, int) else image_size + kh, kw = self.kernel_size + sh, sw = self.stride + oh, ow = math.ceil(ih / sh), math.ceil(iw / sw) + pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0) + pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0) + if pad_h > 0 or pad_w > 0: + self.static_padding = nn.ZeroPad2d((pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2)) + else: + self.static_padding = Identity() + + def forward(self, x): + x = self.static_padding(x) + x = F.max_pool2d(x, self.kernel_size, self.stride, self.padding, + self.dilation, self.ceil_mode, self.return_indices) + return x + +class Identity(nn.Module): + """Identity mapping. + Send input to output directly. + """ + + def __init__(self): + super(Identity, self).__init__() + + def forward(self, input): + return input + + +################################################################################ +### Helper functions for loading model params +################################################################################ + +# BlockDecoder: A Class for encoding and decoding BlockArgs +# efficientnet_params: A function to query compound coefficient +# get_model_params and efficientnet: +# Functions to get BlockArgs and GlobalParams for efficientnet +# url_map and url_map_advprop: Dicts of url_map for pretrained weights +# load_pretrained_weights: A function to load pretrained weights + +class BlockDecoder(object): + """Block Decoder for readability, + straight from the official TensorFlow repository. + """ + + @staticmethod + def _decode_block_string(block_string): + """Get a block through a string notation of arguments. + + Args: + block_string (str): A string notation of arguments. + Examples: 'r1_k3_s11_e1_i32_o16_se0.25_noskip'. + + Returns: + BlockArgs: The namedtuple defined at the top of this file. + """ + assert isinstance(block_string, str) + + ops = block_string.split('_') + options = {} + for op in ops: + splits = re.split(r'(\d.*)', op) + if len(splits) >= 2: + key, value = splits[:2] + options[key] = value + + # Check stride + assert (('s' in options and len(options['s']) == 1) or + (len(options['s']) == 2 and options['s'][0] == options['s'][1])) + + return BlockArgs( + num_repeat=int(options['r']), + kernel_size=int(options['k']), + stride=[int(options['s'][0])], + expand_ratio=int(options['e']), + input_filters=int(options['i']), + output_filters=int(options['o']), + se_ratio=float(options['se']) if 'se' in options else None, + id_skip=('noskip' not in block_string)) + + @staticmethod + def _encode_block_string(block): + """Encode a block to a string. + + Args: + block (namedtuple): A BlockArgs type argument. + + Returns: + block_string: A String form of BlockArgs. + """ + args = [ + 'r%d' % block.num_repeat, + 'k%d' % block.kernel_size, + 's%d%d' % (block.strides[0], block.strides[1]), + 'e%s' % block.expand_ratio, + 'i%d' % block.input_filters, + 'o%d' % block.output_filters + ] + if 0 < block.se_ratio <= 1: + args.append('se%s' % block.se_ratio) + if block.id_skip is False: + args.append('noskip') + return '_'.join(args) + + @staticmethod + def decode(string_list): + """Decode a list of string notations to specify blocks inside the network. + + Args: + string_list (list[str]): A list of strings, each string is a notation of block. + + Returns: + blocks_args: A list of BlockArgs namedtuples of block args. + """ + assert isinstance(string_list, list) + blocks_args = [] + for block_string in string_list: + blocks_args.append(BlockDecoder._decode_block_string(block_string)) + return blocks_args + + @staticmethod + def encode(blocks_args): + """Encode a list of BlockArgs to a list of strings. + + Args: + blocks_args (list[namedtuples]): A list of BlockArgs namedtuples of block args. + + Returns: + block_strings: A list of strings, each string is a notation of block. + """ + block_strings = [] + for block in blocks_args: + block_strings.append(BlockDecoder._encode_block_string(block)) + return block_strings + + +def efficientnet_params(model_name): + """Map EfficientNet model name to parameter coefficients. + + Args: + model_name (str): Model name to be queried. + + Returns: + params_dict[model_name]: A (width,depth,res,dropout) tuple. + """ + params_dict = { + # Coefficients: width,depth,res,dropout + 'efficientnet-b0': (1.0, 1.0, 224, 0.2), + 'efficientnet-b1': (1.0, 1.1, 240, 0.2), + 'efficientnet-b2': (1.1, 1.2, 260, 0.3), + 'efficientnet-b3': (1.2, 1.4, 300, 0.3), + 'efficientnet-b4': (1.4, 1.8, 380, 0.4), + 'efficientnet-b5': (1.6, 2.2, 456, 0.4), + 'efficientnet-b6': (1.8, 2.6, 528, 0.5), + 'efficientnet-b7': (2.0, 3.1, 600, 0.5), + 'efficientnet-b8': (2.2, 3.6, 672, 0.5), + 'efficientnet-l2': (4.3, 5.3, 800, 0.5), + } + return params_dict[model_name] + + +def efficientnet(width_coefficient=None, depth_coefficient=None, image_size=None, + dropout_rate=0.2, drop_connect_rate=0.2, num_classes=1000): + """Create BlockArgs and GlobalParams for efficientnet model. + + Args: + width_coefficient (float) + depth_coefficient (float) + image_size (int) + dropout_rate (float) + drop_connect_rate (float) + num_classes (int) + + Meaning as the name suggests. + + Returns: + blocks_args, global_params. + """ + + # Blocks args for the whole model(efficientnet-b0 by default) + # It will be modified in the construction of EfficientNet Class according to model + blocks_args = [ + 'r1_k3_s11_e1_i32_o16_se0.25', + 'r2_k3_s22_e6_i16_o24_se0.25', + 'r2_k5_s22_e6_i24_o40_se0.25', + 'r3_k3_s22_e6_i40_o80_se0.25', + 'r3_k5_s11_e6_i80_o112_se0.25', + 'r4_k5_s22_e6_i112_o192_se0.25', + 'r1_k3_s11_e6_i192_o320_se0.25', + ] + + blocks_args = BlockDecoder.decode(blocks_args) + + global_params = GlobalParams( + width_coefficient=width_coefficient, + depth_coefficient=depth_coefficient, + image_size=image_size, + dropout_rate=dropout_rate, + + num_classes=num_classes, + batch_norm_momentum=0.99, + batch_norm_epsilon=1e-3, + drop_connect_rate=drop_connect_rate, + depth_divisor=8, + min_depth=None, + ) + + return blocks_args, global_params + + +def get_model_params(model_name, override_params): + """Get the block args and global params for a given model name. + + Args: + model_name (str): Model's name. + override_params (dict): A dict to modify global_params. + + Returns: + blocks_args, global_params + """ + if model_name.startswith('efficientnet'): + w, d, s, p = efficientnet_params(model_name) + # note: all models have drop connect rate = 0.2 + blocks_args, global_params = efficientnet( + width_coefficient=w, depth_coefficient=d, dropout_rate=p, image_size=s) + else: + raise NotImplementedError('model name is not pre-defined: %s' % model_name) + if override_params: + # ValueError will be raised here if override_params has fields not included in global_params. + global_params = global_params._replace(**override_params) + return blocks_args, global_params + + +# train with Standard methods +# check more details in paper(EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks) +url_map = { + 'efficientnet-b0': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b0-355c32eb.pth', + 'efficientnet-b1': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b1-f1951068.pth', + 'efficientnet-b2': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b2-8bb594d6.pth', + 'efficientnet-b3': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b3-5fb5a3c3.pth', + 'efficientnet-b4': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b4-6ed6700e.pth', + 'efficientnet-b5': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b5-b6417697.pth', + 'efficientnet-b6': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b6-c76e70fd.pth', + 'efficientnet-b7': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/efficientnet-b7-dcc49843.pth', +} + +# train with Adversarial Examples(AdvProp) +# check more details in paper(Adversarial Examples Improve Image Recognition) +url_map_advprop = { + 'efficientnet-b0': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b0-b64d5a18.pth', + 'efficientnet-b1': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b1-0f3ce85a.pth', + 'efficientnet-b2': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b2-6e9d97e5.pth', + 'efficientnet-b3': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b3-cdd7c0f4.pth', + 'efficientnet-b4': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b4-44fb3a87.pth', + 'efficientnet-b5': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b5-86493f6b.pth', + 'efficientnet-b6': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b6-ac80338e.pth', + 'efficientnet-b7': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b7-4652b6dd.pth', + 'efficientnet-b8': 'https://github.com/lukemelas/EfficientNet-PyTorch/releases/download/1.0/adv-efficientnet-b8-22a8fe65.pth', +} + +# TODO: add the petrained weights url map of 'efficientnet-l2' + + +def load_pretrained_weights(model, model_name, weights_path=None, load_fc=True, advprop=False): + """Loads pretrained weights from weights path or download using url. + + Args: + model (Module): The whole model of efficientnet. + model_name (str): Model name of efficientnet. + weights_path (None or str): + str: path to pretrained weights file on the local disk. + None: use pretrained weights downloaded from the Internet. + load_fc (bool): Whether to load pretrained weights for fc layer at the end of the model. + advprop (bool): Whether to load pretrained weights + trained with advprop (valid when weights_path is None). + """ + if isinstance(weights_path,str): + state_dict = torch.load(weights_path, map_location='cpu') + else: + # AutoAugment or Advprop (different preprocessing) + url_map_ = url_map_advprop if advprop else url_map + state_dict = model_zoo.load_url(url_map_[model_name]) + if 'state_dict' in state_dict: + state_dict = state_dict['state_dict'] + if 'module.' in list(state_dict.keys())[0]: + state_dict_tmp = dict() + for k, v in state_dict.items(): + state_dict_tmp[k[7:]] = v + state_dict = state_dict_tmp + + if load_fc: + ret = model.load_state_dict(state_dict, strict=False) + assert not ret.missing_keys, f'Missing keys when loading pretrained weights: {ret.missing_keys}' + else: + state_dict.pop('_fc.weight') + state_dict.pop('_fc.bias') + ret = model.load_state_dict(state_dict, strict=False) + assert set(ret.missing_keys) == set( + ['_fc.weight', '_fc.bias']), f'Missing keys when loading pretrained weights: {ret.missing_keys}' + assert not ret.unexpected_keys, f'Missing keys when loading pretrained weights: {ret.unexpected_keys}' + + print('Loaded pretrained weights for {}'.format(model_name)) diff --git a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/examples/imagenet/README.md b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/examples/imagenet/README.md index 8f7f89b212..fcafce33a6 100644 --- a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/examples/imagenet/README.md +++ b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/examples/imagenet/README.md @@ -1,23 +1,23 @@ -### Imagenet - -This is a preliminary directory for evaluating the model on ImageNet. It is adapted from the standard PyTorch Imagenet script. - -For now, only evaluation is supported, but I am currently building scripts to assist with training new models on Imagenet. - -The evaluation results are slightly different from the original TensorFlow repository, due to differences in data preprocessing. For example, with the current preprocessing, `efficientnet-b3` gives a top-1 accuracy of `80.8`, rather than `81.1` in the paper. I am working on porting the TensorFlow preprocessing into PyTorch to address this issue. - -To run on Imagenet, place your `train` and `val` directories in `data`. - -Example commands: -```bash -# Evaluate small EfficientNet on CPU -python main.py data -e -a 'efficientnet-b0' --pretrained -``` -```bash -# Evaluate medium EfficientNet on GPU -python main.py data -e -a 'efficientnet-b3' --pretrained --gpu 0 --batch-size 128 -``` -```bash -# Evaluate ResNet-50 for comparison -python main.py data -e -a 'resnet50' --pretrained --gpu 0 -``` +### Imagenet + +This is a preliminary directory for evaluating the model on ImageNet. It is adapted from the standard PyTorch Imagenet script. + +For now, only evaluation is supported, but I am currently building scripts to assist with training new models on Imagenet. + +The evaluation results are slightly different from the original TensorFlow repository, due to differences in data preprocessing. For example, with the current preprocessing, `efficientnet-b3` gives a top-1 accuracy of `80.8`, rather than `81.1` in the paper. I am working on porting the TensorFlow preprocessing into PyTorch to address this issue. + +To run on Imagenet, place your `train` and `val` directories in `data`. + +Example commands: +```bash +# Evaluate small EfficientNet on CPU +python main.py data -e -a 'efficientnet-b0' --pretrained +``` +```bash +# Evaluate medium EfficientNet on GPU +python main.py data -e -a 'efficientnet-b3' --pretrained --gpu 0 --batch-size 128 +``` +```bash +# Evaluate ResNet-50 for comparison +python main.py data -e -a 'resnet50' --pretrained --gpu 0 +``` diff --git a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/examples/imagenet/data/README.md b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/examples/imagenet/data/README.md index 21a3317e9c..310c6e0df8 100644 --- a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/examples/imagenet/data/README.md +++ b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/examples/imagenet/data/README.md @@ -1,5 +1,5 @@ -### ImageNet - -Download ImageNet and place it into `train` and `val` folders here. - -More details may be found with the official PyTorch ImageNet example [here](https://github.com/pytorch/examples/blob/master/imagenet). +### ImageNet + +Download ImageNet and place it into `train` and `val` folders here. + +More details may be found with the official PyTorch ImageNet example [here](https://github.com/pytorch/examples/blob/master/imagenet). diff --git a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/examples/imagenet/main.py b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/examples/imagenet/main.py index fb92fc1ac2..154f75f062 100644 --- a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/examples/imagenet/main.py +++ b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/examples/imagenet/main.py @@ -1,545 +1,545 @@ -# Copyright [yyyy] [name of copyright owner] -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 argparse -import os -import re -import sys -import time -import PIL -import numpy as np - -import torch -import torch.nn as nn -import torch.nn.parallel -import torch.distributed as dist -import torch.optim -import torch.multiprocessing as mp -import torch.utils.data -import torch.utils.data.distributed -import torchvision.transforms as transforms -import torchvision.datasets as datasets -import torchvision.models as models - -from apex import amp - -sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)),'../../')) -from efficientnet_pytorch import EfficientNet -from efficientnet_pytorch import rand_augment_transform, augment_and_mix_transform, auto_augment_transform - -parser = argparse.ArgumentParser(description='PyTorch ImageNet Training') -parser.add_argument('--data', metavar='DIR', - help='path to dataset') -parser.add_argument('-a', '--arch', metavar='ARCH', default='resnet18', - help='model architecture (default: resnet18)') -parser.add_argument('-j', '--workers', default=64, type=int, metavar='N', - help='number of data loading workers (default: 4)') -parser.add_argument('--epochs', default=90, type=int, metavar='N', - help='number of total epochs to run') -parser.add_argument('--start-epoch', default=0, type=int, metavar='N', - help='manual epoch number (useful on restarts)') -parser.add_argument('-b', '--batch-size', default=256, type=int, - metavar='N', - help='mini-batch size (default: 256), this is the total ' - 'batch size of all GPUs on the current node when ' - 'using Data Parallel or Distributed Data Parallel') -parser.add_argument('--lr', '--learning-rate', default=0.1, type=float, - metavar='LR', help='initial learning rate', dest='lr') -parser.add_argument('--momentum', default=0.9, type=float, metavar='M', - help='momentum') -parser.add_argument('--wd', '--weight-decay', default=1e-5, type=float, - metavar='W', help='weight decay (default: 1e-4)', - dest='weight_decay') -parser.add_argument('-p', '--print-freq', default=10, type=int, - metavar='N', help='print frequency (default: 10)') -parser.add_argument('--resume', default='', type=str, metavar='PATH', - help='path to latest checkpoint (default: none)') -parser.add_argument('-e', '--evaluate', dest='evaluate', action='store_true', - help='evaluate model on validation set') -parser.add_argument('--pretrained', dest='pretrained', action='store_true', - help='use pre-trained model') -parser.add_argument('--pretrained_weight', default='', type=str, metavar='PATH', - help='path to pretrained weight') -parser.add_argument('--num_classes', default=1000, type=int, - help='number of class') -parser.add_argument('--world-size', default=-1, type=int, - help='number of nodes for distributed training') -parser.add_argument('--rank', default=-1, type=int, - help='node rank for distributed training') -parser.add_argument('--dist-url', default='tcp://224.66.41.62:23456', type=str, - help='url used to set up distributed training') -parser.add_argument('--dist-backend', default='hccl', type=str, - help='distributed backend') -parser.add_argument('--seed', default=None, type=int, - help='seed for initializing training. ') -parser.add_argument('--npu', default=None, type=str, - help='npu id to use.') -parser.add_argument('--image_size', default=224, type=int, - help='image size') -parser.add_argument('--advprop', default=False, action='store_true', - help='use advprop or not') -parser.add_argument('--multiprocessing-distributed', action='store_true', - help='Use multi-processing distributed training to launch ' - 'N processes per node, which has N GPUs. This is the ' - 'fastest way to use PyTorch for either single node or ' - 'multi node data parallel training') -parser.add_argument('--autoaug', action='store_true', help='use auto augment') -parser.add_argument('--amp', action='store_true', help='use apex') -parser.add_argument('--pm', '--precision-mode', default='O1', type=str, - help='precision mode to use for mix precision, only support O1, O2') -parser.add_argument('--loss_scale', default=1024, type=int, help='loss_scale for amp') -parser.add_argument('--addr', default='127.0.0.1', type=str, - help='npu id to use.') -parser.add_argument('--nnpus_per_node', default=None, type=int, - help='number of npus to use for distributed train on each node') -parser.add_argument('--val_feq', default=10, type=int, - help='validation frequency') -parser.add_argument('--device_list', default='0,1,2,3,4,5,6,7', type=str, help='device id list') -parser.add_argument('--stop-step-num', default=None, type=int, - help='after the stop-step, killing the training task') -cur_step = 0 - -# for servers to immediately record the logs -#def flush_print(func): - #def new_print(*args, **kwargs): - #func(*args, **kwargs) - #sys.stdout.flush() - #return new_print -#print = flush_print(print) - -def device_id_to_process_device_map(device_list): - devices = device_list.split(",") - devices = [int(x) for x in devices] - devices.sort() - - process_device_map = dict() - for process_id, device_id in enumerate(devices): - process_device_map[process_id] = device_id - - return process_device_map - - -def main(): - args = parser.parse_args() - - if args.dist_url == "env://" and args.world_size == -1: - args.world_size = int(os.environ["WORLD_SIZE"]) - - args.distributed = args.world_size > 1 or args.multiprocessing_distributed - - args.process_device_map = device_id_to_process_device_map(args.device_list) - nnpus_per_node = len(args.process_device_map) - - - if args.multiprocessing_distributed: - # Since we have ngpus_per_node processes per node, the total world_size - # needs to be adjusted accordingly - args.world_size = nnpus_per_node * args.world_size - # Use torch.multiprocessing.spawn to launch distributed processes: the - # main_worker process function - os.environ['MASTER_ADDR'] = args.addr - os.environ['MASTER_PORT'] = '29688' - mp.spawn(main_worker, nprocs=nnpus_per_node, args=(nnpus_per_node, args)) - else: - # Simply call main_worker function - main_worker(args.npu, nnpus_per_node, args) - -def main_worker(npu, nnpus_per_node, args): - args.npu = npu - global cur_step - if args.distributed: - args.npu = args.process_device_map[npu] - - if args.npu is not None: - print("Use npu: {} for training".format(args.npu)) - torch.npu.set_device('npu:' + str(args.npu)) - - if args.distributed: - if args.dist_url == "env://" and args.rank == -1: - args.rank = int(os.environ["RANK"]) - if args.multiprocessing_distributed: - # For multiprocessing distributed training, rank needs to be the - # global rank among all the processes - args.rank = args.rank * nnpus_per_node + int(npu) - - dist.init_process_group(backend=args.dist_backend, - world_size=args.world_size, rank=args.rank) - # create model - if 'efficientnet' in args.arch: # NEW - if args.pretrained: - model = EfficientNet.from_pretrained(args.arch, advprop=args.advprop, weights_path=args.pretrained_weight, num_classes=args.num_classes) - print("=> using pre-trained model '{}'".format(args.arch)) - else: - print("=> creating model '{}'".format(args.arch)) - model = EfficientNet.from_name(args.arch) - - else: - if args.pretrained: - print("=> using pre-trained model '{}'".format(args.arch)) - model = models.__dict__[args.arch](pretrained=True) - else: - print("=> creating model '{}'".format(args.arch)) - model = models.__dict__[args.arch]() - - criterion = nn.CrossEntropyLoss().to('npu:' + str(args.npu)) - - optimizer = torch.optim.SGD(model.parameters(), args.lr, - momentum=args.momentum, - weight_decay=args.weight_decay) - model = model.to('npu:' + str(args.npu)) - if args.amp: - print("=> use amp...") - if args.pm not in ['O1', 'O2']: - print('=>unsupported precision mode!') - exit() - opt_level = args.pm - model, optimizer = amp.initialize(model, optimizer, opt_level=opt_level, loss_scale=args.loss_scale) - - global total_batch_size - total_batch_size = args.batch_size - if args.distributed: - args.batch_size = int(args.batch_size / nnpus_per_node) - args.workers = int(args.workers / nnpus_per_node) - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.npu], broadcast_buffers=False) - - - - # optionally resume from a checkpoint - if args.resume: - if os.path.isfile(args.resume): - print("=> loading checkpoint '{}'".format(args.resume)) - checkpoint = torch.load(args.resume, map_location='npu:' + str(args.npu)) - args.start_epoch = checkpoint['epoch'] - if args.amp: - amp.load_state_dict(checkpoint['amp']) - model.load_state_dict(checkpoint['state_dict']) - optimizer.load_state_dict(checkpoint['optimizer']) - print("=> loaded checkpoint '{}' (epoch {})" - .format(args.resume, checkpoint['epoch'])) - else: - print("=> no checkpoint found at '{}'".format(args.resume)) - - # Data loading code - traindir = os.path.join(args.data, 'train') - valdir = os.path.join(args.data, 'val') - if args.advprop: - normalize = transforms.Lambda(lambda img: img * 2.0 - 1.0) - else: - normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], - std=[0.229, 0.224, 0.225]) - - if 'efficientnet' in args.arch: - image_size = EfficientNet.get_image_size(args.arch) - else: - image_size = args.image_size - - if args.autoaug: - print("=> use auto augment...") - train_dataset = datasets.ImageFolder( - traindir, - transforms.Compose([ - transforms.RandomResizedCrop(image_size), - auto_augment_wrapper(image_size), - transforms.ToTensor(), - normalize, - ])) - else: - train_dataset = datasets.ImageFolder( - traindir, - transforms.Compose([ - transforms.RandomResizedCrop(image_size), - transforms.RandomHorizontalFlip(), - transforms.ToTensor(), - normalize, - ])) - - if args.distributed: - train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset) - else: - train_sampler = None - - train_loader = torch.utils.data.DataLoader( - train_dataset, batch_size=args.batch_size, shuffle=(train_sampler is None), - num_workers=args.workers, pin_memory=True, sampler=train_sampler, drop_last=True) - - val_transforms = transforms.Compose([ - transforms.Resize(image_size, interpolation=PIL.Image.BICUBIC), - transforms.CenterCrop(image_size), - transforms.ToTensor(), - normalize, - ]) - print('npu:' + str(args.npu), ' optimizer params:', optimizer) - - val_loader = torch.utils.data.DataLoader( - datasets.ImageFolder(valdir, val_transforms), - batch_size=args.batch_size, shuffle=False, - num_workers=args.workers, pin_memory=True) - - if args.evaluate: - res = validate(val_loader, model, criterion, args, nnpus_per_node) - with open('res.txt', 'w') as f: - print(res, file=f) - return - - for epoch in range(args.start_epoch, args.epochs): - if args.distributed: - train_sampler.set_epoch(epoch) - - # train for one epoch - train(train_loader, model, criterion, optimizer, epoch, args, nnpus_per_node) - - # evaluate on validation set - if epoch % args.val_feq == 0 or epoch == args.epochs - 1: - validate(val_loader, model, criterion, args, nnpus_per_node) - - if epoch == args.epochs - 1: - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % nnpus_per_node == 0): - if not args.amp: - save_checkpoint({ - 'epoch': epoch + 1, - 'arch': args.arch, - 'state_dict': model.state_dict(), - 'optimizer': optimizer.state_dict(), - }) - else: - save_checkpoint({ - 'epoch': epoch + 1, - 'arch': args.arch, - 'state_dict': model.state_dict(), - 'optimizer': optimizer.state_dict(), - 'amp': amp.state_dict(), - }) - if args.stop_step_num is not None and cur_step >= args.stop_step_num: - break - -def train(train_loader, model, criterion, optimizer, epoch, args, nnpus_per_node): - global cur_step - batch_time = AverageMeter('Time', ':6.3f') - data_time = AverageMeter('Data', ':6.3f') - losses = AverageMeter('Loss', ':6.4f') - lr = AverageMeter('LR', ':6.4f') - top1 = AverageMeter('Acc@1', ':6.2f') - top5 = AverageMeter('Acc@5', ':6.2f') - fps_time = AverageMeter('FPS', ':6.1f') - progress = ProgressMeter(len(train_loader), fps_time, batch_time, data_time, losses, lr, top1, - top5, prefix="Epoch: [{}]".format(epoch)) - - # switch to train mode - model.train() - - end = time.time() - step_per_epoch = len(train_loader) - for i, (images, target) in enumerate(train_loader): - if i > 100: - pass - cur_step = epoch * step_per_epoch + i - adjust_learning_rate_fraction_epoch(optimizer, epoch, args) - - # measure data loading time - data_time.update(time.time() - end) - - optimizer.zero_grad() - - target = target.int() - images, target = images.to('npu:' + str(args.npu), non_blocking=True), target.to('npu:' + str(args.npu), non_blocking=True) - - # compute output - output = model(images) - - loss = criterion(output, target) - - # measure accuracy and record loss - acc1, acc5 = accuracy(output, target, topk=(1, 5)) - - losses.update(loss.item(), images.size(0)) - lr.update(optimizer.param_groups[0]['lr'], images.size(0)) - top1.update(acc1[0], images.size(0)) - top5.update(acc5[0], images.size(0)) - # compute gradient and do SGD step - - if args.amp: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.step() - - # measure elapsed time - fps_time.update(total_batch_size / (time.time() - end)) - batch_time.update(time.time() - end) - end = time.time() - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % nnpus_per_node == 0): - progress.print(i) - if args.stop_step_num is not None and cur_step >= args.stop_step_num: - break - - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % nnpus_per_node == 0): - fps = str(fps_time) - p1 = re.compile(r'[(](.*?)[)]', re.S) - FPS = re.findall(p1, fps)[0] - print(' * FPS@all {}'.format(FPS)) - -def validate(val_loader, model, criterion, args, nnpus_per_node): - batch_time = AverageMeter('Time', ':6.3f') - losses = AverageMeter('Loss', ':.4e') - top1 = AverageMeter('Acc@1', ':6.2f') - top5 = AverageMeter('Acc@5', ':6.2f') - progress = ProgressMeter(len(val_loader), batch_time, losses, top1, top5, - prefix='Test: ') - - # switch to evaluate mode - model.eval() - - with torch.no_grad(): - end = time.time() - for i, (images, target) in enumerate(val_loader): - if i > 10: - pass - target = target.int() - images, target = images.to('npu:' + str(args.npu), non_blocking=True), target.to('npu:' + str(args.npu), non_blocking=True) - - # compute output - output = model(images) - loss = criterion(output, target) - - # measure accuracy and record loss - acc1, acc5 = accuracy(output, target, topk=(1, 5)) - losses.update(loss.item(), images.size(0)) - top1.update(acc1[0], images.size(0)) - top5.update(acc5[0], images.size(0)) - - # measure elapsed time - batch_time.update(time.time() - end) - end = time.time() - - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % nnpus_per_node == 0): - progress.print(i) - - # TODO: this should also be done with the ProgressMeter - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % nnpus_per_node == 0): - - print(' * Acc@1 {top1.avg:.3f} Acc@5 {top5.avg:.3f}' - .format(top1=top1, top5=top5)) - - - return top1.avg - - -def save_checkpoint(state, filename='checkpoint.pth'): - torch.save(state, filename) - - -class AverageMeter(object): - """Computes and stores the average and current value""" - def __init__(self, name, fmt=':f'): - self.name = name - self.fmt = fmt - self.reset() - self.skip = 0 - - def reset(self): - self.val = 0 - self.avg = 0 - self.sum = 0 - self.count = 0 - self.skip = 0 - - def update(self, val, n=1): - self.val = val - # the first 5 value are not accumulated in the average stats - self.skip += 1 - if self.skip < 5: - return - self.sum += val * n - self.count += n - self.avg = self.sum / self.count - - def __str__(self): - fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' - return fmtstr.format(**self.__dict__) - - -class ProgressMeter(object): - def __init__(self, num_batches, *meters, prefix=""): - self.batch_fmtstr = self._get_batch_fmtstr(num_batches) - self.meters = meters - self.prefix = prefix - - def print(self, batch): - entries = [self.prefix + self.batch_fmtstr.format(batch)] - entries += [str(meter) for meter in self.meters] - print('\t'.join(entries)) - - def _get_batch_fmtstr(self, num_batches): - num_digits = len(str(num_batches // 1)) - fmt = '{:' + str(num_digits) + 'd}' - return '[' + fmt + '/' + fmt.format(num_batches) + ']' - - -def adjust_learning_rate(optimizer, epoch, args): - """Sets the learning rate to the initial LR decayed by 10 every 30 epochs""" - lr = args.lr * (0.1 ** (epoch // 30)) - for param_group in optimizer.param_groups: - param_group['lr'] = lr - - -def accuracy(output, target, topk=(1,)): - """Computes the accuracy over the k top predictions for the specified values of k""" - with torch.no_grad(): - maxk = max(topk) - batch_size = target.size(0) - - _, pred = output.topk(maxk, 1, True, True) - pred = pred.t() - correct = pred.eq(target.view(1, -1).expand_as(pred)) - - res = [] - for k in topk: - correct_k = correct[:k].view(-1).float().sum(0, keepdim=True) - res.append(correct_k.mul_(100.0 / batch_size)) - return res - -def auto_augment_wrapper(img_size, auto_augment='original-mstd0.5'): - IMAGENET_DEFAULT_MEAN = [0.485, 0.456, 0.406] - assert isinstance(auto_augment, str) - aa_params = dict( - translate_const=int(img_size * 0.45), - img_mean=tuple([min(255, round(255 * x)) for x in IMAGENET_DEFAULT_MEAN]), - ) - if auto_augment.startswith('rand'): - return rand_augment_transform(auto_augment, aa_params) - elif auto_augment.startswith('augmix'): - aa_params['translate_pct'] = 0.3 - return augment_and_mix_transform(auto_augment, aa_params) - else: - return auto_augment_transform(auto_augment, aa_params) - -def adjust_learning_rate_fraction_epoch(optimizer, epoch, args): - """Use the epoch cosine schedule""" - - alpha = 0 - cosine_decay = 0.5 * (1 + np.cos(np.pi * epoch / args.epochs)) - decayed = (1 - alpha) * cosine_decay + alpha - lr = args.lr * decayed - for param_group in optimizer.param_groups: - param_group['lr'] = lr - -if __name__ == '__main__': - main() +# Copyright [yyyy] [name of copyright owner] +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 argparse +import os +import re +import sys +import time +import PIL +import numpy as np + +import torch +import torch.nn as nn +import torch.nn.parallel +import torch.distributed as dist +import torch.optim +import torch.multiprocessing as mp +import torch.utils.data +import torch.utils.data.distributed +import torchvision.transforms as transforms +import torchvision.datasets as datasets +import torchvision.models as models + +from apex import amp + +sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)),'../../')) +from efficientnet_pytorch import EfficientNet +from efficientnet_pytorch import rand_augment_transform, augment_and_mix_transform, auto_augment_transform + +parser = argparse.ArgumentParser(description='PyTorch ImageNet Training') +parser.add_argument('--data', metavar='DIR', + help='path to dataset') +parser.add_argument('-a', '--arch', metavar='ARCH', default='resnet18', + help='model architecture (default: resnet18)') +parser.add_argument('-j', '--workers', default=64, type=int, metavar='N', + help='number of data loading workers (default: 4)') +parser.add_argument('--epochs', default=90, type=int, metavar='N', + help='number of total epochs to run') +parser.add_argument('--start-epoch', default=0, type=int, metavar='N', + help='manual epoch number (useful on restarts)') +parser.add_argument('-b', '--batch-size', default=256, type=int, + metavar='N', + help='mini-batch size (default: 256), this is the total ' + 'batch size of all GPUs on the current node when ' + 'using Data Parallel or Distributed Data Parallel') +parser.add_argument('--lr', '--learning-rate', default=0.1, type=float, + metavar='LR', help='initial learning rate', dest='lr') +parser.add_argument('--momentum', default=0.9, type=float, metavar='M', + help='momentum') +parser.add_argument('--wd', '--weight-decay', default=1e-5, type=float, + metavar='W', help='weight decay (default: 1e-4)', + dest='weight_decay') +parser.add_argument('-p', '--print-freq', default=10, type=int, + metavar='N', help='print frequency (default: 10)') +parser.add_argument('--resume', default='', type=str, metavar='PATH', + help='path to latest checkpoint (default: none)') +parser.add_argument('-e', '--evaluate', dest='evaluate', action='store_true', + help='evaluate model on validation set') +parser.add_argument('--pretrained', dest='pretrained', action='store_true', + help='use pre-trained model') +parser.add_argument('--pretrained_weight', default='', type=str, metavar='PATH', + help='path to pretrained weight') +parser.add_argument('--num_classes', default=1000, type=int, + help='number of class') +parser.add_argument('--world-size', default=-1, type=int, + help='number of nodes for distributed training') +parser.add_argument('--rank', default=-1, type=int, + help='node rank for distributed training') +parser.add_argument('--dist-url', default='tcp://224.66.41.62:23456', type=str, + help='url used to set up distributed training') +parser.add_argument('--dist-backend', default='hccl', type=str, + help='distributed backend') +parser.add_argument('--seed', default=None, type=int, + help='seed for initializing training. ') +parser.add_argument('--npu', default=None, type=str, + help='npu id to use.') +parser.add_argument('--image_size', default=224, type=int, + help='image size') +parser.add_argument('--advprop', default=False, action='store_true', + help='use advprop or not') +parser.add_argument('--multiprocessing-distributed', action='store_true', + help='Use multi-processing distributed training to launch ' + 'N processes per node, which has N GPUs. This is the ' + 'fastest way to use PyTorch for either single node or ' + 'multi node data parallel training') +parser.add_argument('--autoaug', action='store_true', help='use auto augment') +parser.add_argument('--amp', action='store_true', help='use apex') +parser.add_argument('--pm', '--precision-mode', default='O1', type=str, + help='precision mode to use for mix precision, only support O1, O2') +parser.add_argument('--loss_scale', default=1024, type=int, help='loss_scale for amp') +parser.add_argument('--addr', default='127.0.0.1', type=str, + help='npu id to use.') +parser.add_argument('--nnpus_per_node', default=None, type=int, + help='number of npus to use for distributed train on each node') +parser.add_argument('--val_feq', default=10, type=int, + help='validation frequency') +parser.add_argument('--device_list', default='0,1,2,3,4,5,6,7', type=str, help='device id list') +parser.add_argument('--stop-step-num', default=None, type=int, + help='after the stop-step, killing the training task') +cur_step = 0 + +# for servers to immediately record the logs +#def flush_print(func): + #def new_print(*args, **kwargs): + #func(*args, **kwargs) + #sys.stdout.flush() + #return new_print +#print = flush_print(print) + +def device_id_to_process_device_map(device_list): + devices = device_list.split(",") + devices = [int(x) for x in devices] + devices.sort() + + process_device_map = dict() + for process_id, device_id in enumerate(devices): + process_device_map[process_id] = device_id + + return process_device_map + + +def main(): + args = parser.parse_args() + + if args.dist_url == "env://" and args.world_size == -1: + args.world_size = int(os.environ["WORLD_SIZE"]) + + args.distributed = args.world_size > 1 or args.multiprocessing_distributed + + args.process_device_map = device_id_to_process_device_map(args.device_list) + nnpus_per_node = len(args.process_device_map) + + + if args.multiprocessing_distributed: + # Since we have ngpus_per_node processes per node, the total world_size + # needs to be adjusted accordingly + args.world_size = nnpus_per_node * args.world_size + # Use torch.multiprocessing.spawn to launch distributed processes: the + # main_worker process function + os.environ['MASTER_ADDR'] = args.addr + os.environ['MASTER_PORT'] = '29688' + mp.spawn(main_worker, nprocs=nnpus_per_node, args=(nnpus_per_node, args)) + else: + # Simply call main_worker function + main_worker(args.npu, nnpus_per_node, args) + +def main_worker(npu, nnpus_per_node, args): + args.npu = npu + global cur_step + if args.distributed: + args.npu = args.process_device_map[npu] + + if args.npu is not None: + print("Use npu: {} for training".format(args.npu)) + torch.npu.set_device('npu:' + str(args.npu)) + + if args.distributed: + if args.dist_url == "env://" and args.rank == -1: + args.rank = int(os.environ["RANK"]) + if args.multiprocessing_distributed: + # For multiprocessing distributed training, rank needs to be the + # global rank among all the processes + args.rank = args.rank * nnpus_per_node + int(npu) + + dist.init_process_group(backend=args.dist_backend, + world_size=args.world_size, rank=args.rank) + # create model + if 'efficientnet' in args.arch: # NEW + if args.pretrained: + model = EfficientNet.from_pretrained(args.arch, advprop=args.advprop, weights_path=args.pretrained_weight, num_classes=args.num_classes) + print("=> using pre-trained model '{}'".format(args.arch)) + else: + print("=> creating model '{}'".format(args.arch)) + model = EfficientNet.from_name(args.arch) + + else: + if args.pretrained: + print("=> using pre-trained model '{}'".format(args.arch)) + model = models.__dict__[args.arch](pretrained=True) + else: + print("=> creating model '{}'".format(args.arch)) + model = models.__dict__[args.arch]() + + criterion = nn.CrossEntropyLoss().to('npu:' + str(args.npu)) + + optimizer = torch.optim.SGD(model.parameters(), args.lr, + momentum=args.momentum, + weight_decay=args.weight_decay) + model = model.to('npu:' + str(args.npu)) + if args.amp: + print("=> use amp...") + if args.pm not in ['O1', 'O2']: + print('=>unsupported precision mode!') + exit() + opt_level = args.pm + model, optimizer = amp.initialize(model, optimizer, opt_level=opt_level, loss_scale=args.loss_scale) + + global total_batch_size + total_batch_size = args.batch_size + if args.distributed: + args.batch_size = int(args.batch_size / nnpus_per_node) + args.workers = int(args.workers / nnpus_per_node) + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.npu], broadcast_buffers=False) + + + + # optionally resume from a checkpoint + if args.resume: + if os.path.isfile(args.resume): + print("=> loading checkpoint '{}'".format(args.resume)) + checkpoint = torch.load(args.resume, map_location='npu:' + str(args.npu)) + args.start_epoch = checkpoint['epoch'] + if args.amp: + amp.load_state_dict(checkpoint['amp']) + model.load_state_dict(checkpoint['state_dict']) + optimizer.load_state_dict(checkpoint['optimizer']) + print("=> loaded checkpoint '{}' (epoch {})" + .format(args.resume, checkpoint['epoch'])) + else: + print("=> no checkpoint found at '{}'".format(args.resume)) + + # Data loading code + traindir = os.path.join(args.data, 'train') + valdir = os.path.join(args.data, 'val') + if args.advprop: + normalize = transforms.Lambda(lambda img: img * 2.0 - 1.0) + else: + normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]) + + if 'efficientnet' in args.arch: + image_size = EfficientNet.get_image_size(args.arch) + else: + image_size = args.image_size + + if args.autoaug: + print("=> use auto augment...") + train_dataset = datasets.ImageFolder( + traindir, + transforms.Compose([ + transforms.RandomResizedCrop(image_size), + auto_augment_wrapper(image_size), + transforms.ToTensor(), + normalize, + ])) + else: + train_dataset = datasets.ImageFolder( + traindir, + transforms.Compose([ + transforms.RandomResizedCrop(image_size), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + normalize, + ])) + + if args.distributed: + train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset) + else: + train_sampler = None + + train_loader = torch.utils.data.DataLoader( + train_dataset, batch_size=args.batch_size, shuffle=(train_sampler is None), + num_workers=args.workers, pin_memory=True, sampler=train_sampler, drop_last=True) + + val_transforms = transforms.Compose([ + transforms.Resize(image_size, interpolation=PIL.Image.BICUBIC), + transforms.CenterCrop(image_size), + transforms.ToTensor(), + normalize, + ]) + print('npu:' + str(args.npu), ' optimizer params:', optimizer) + + val_loader = torch.utils.data.DataLoader( + datasets.ImageFolder(valdir, val_transforms), + batch_size=args.batch_size, shuffle=False, + num_workers=args.workers, pin_memory=True) + + if args.evaluate: + res = validate(val_loader, model, criterion, args, nnpus_per_node) + with open('res.txt', 'w') as f: + print(res, file=f) + return + + for epoch in range(args.start_epoch, args.epochs): + if args.distributed: + train_sampler.set_epoch(epoch) + + # train for one epoch + train(train_loader, model, criterion, optimizer, epoch, args, nnpus_per_node) + + # evaluate on validation set + if epoch % args.val_feq == 0 or epoch == args.epochs - 1: + validate(val_loader, model, criterion, args, nnpus_per_node) + + if epoch == args.epochs - 1: + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % nnpus_per_node == 0): + if not args.amp: + save_checkpoint({ + 'epoch': epoch + 1, + 'arch': args.arch, + 'state_dict': model.state_dict(), + 'optimizer': optimizer.state_dict(), + }) + else: + save_checkpoint({ + 'epoch': epoch + 1, + 'arch': args.arch, + 'state_dict': model.state_dict(), + 'optimizer': optimizer.state_dict(), + 'amp': amp.state_dict(), + }) + if args.stop_step_num is not None and cur_step >= args.stop_step_num: + break + +def train(train_loader, model, criterion, optimizer, epoch, args, nnpus_per_node): + global cur_step + batch_time = AverageMeter('Time', ':6.3f') + data_time = AverageMeter('Data', ':6.3f') + losses = AverageMeter('Loss', ':6.4f') + lr = AverageMeter('LR', ':6.4f') + top1 = AverageMeter('Acc@1', ':6.2f') + top5 = AverageMeter('Acc@5', ':6.2f') + fps_time = AverageMeter('FPS', ':6.1f') + progress = ProgressMeter(len(train_loader), fps_time, batch_time, data_time, losses, lr, top1, + top5, prefix="Epoch: [{}]".format(epoch)) + + # switch to train mode + model.train() + + end = time.time() + step_per_epoch = len(train_loader) + for i, (images, target) in enumerate(train_loader): + if i > 100: + pass + cur_step = epoch * step_per_epoch + i + adjust_learning_rate_fraction_epoch(optimizer, epoch, args) + + # measure data loading time + data_time.update(time.time() - end) + + optimizer.zero_grad() + + target = target.int() + images, target = images.to('npu:' + str(args.npu), non_blocking=True), target.to('npu:' + str(args.npu), non_blocking=True) + + # compute output + output = model(images) + + loss = criterion(output, target) + + # measure accuracy and record loss + acc1, acc5 = accuracy(output, target, topk=(1, 5)) + + losses.update(loss.item(), images.size(0)) + lr.update(optimizer.param_groups[0]['lr'], images.size(0)) + top1.update(acc1[0], images.size(0)) + top5.update(acc5[0], images.size(0)) + # compute gradient and do SGD step + + if args.amp: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + optimizer.step() + + # measure elapsed time + fps_time.update(total_batch_size / (time.time() - end)) + batch_time.update(time.time() - end) + end = time.time() + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % nnpus_per_node == 0): + progress.print(i) + if args.stop_step_num is not None and cur_step >= args.stop_step_num: + break + + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % nnpus_per_node == 0): + fps = str(fps_time) + p1 = re.compile(r'[(](.*?)[)]', re.S) + FPS = re.findall(p1, fps)[0] + print(' * FPS@all {}'.format(FPS)) + +def validate(val_loader, model, criterion, args, nnpus_per_node): + batch_time = AverageMeter('Time', ':6.3f') + losses = AverageMeter('Loss', ':.4e') + top1 = AverageMeter('Acc@1', ':6.2f') + top5 = AverageMeter('Acc@5', ':6.2f') + progress = ProgressMeter(len(val_loader), batch_time, losses, top1, top5, + prefix='Test: ') + + # switch to evaluate mode + model.eval() + + with torch.no_grad(): + end = time.time() + for i, (images, target) in enumerate(val_loader): + if i > 10: + pass + target = target.int() + images, target = images.to('npu:' + str(args.npu), non_blocking=True), target.to('npu:' + str(args.npu), non_blocking=True) + + # compute output + output = model(images) + loss = criterion(output, target) + + # measure accuracy and record loss + acc1, acc5 = accuracy(output, target, topk=(1, 5)) + losses.update(loss.item(), images.size(0)) + top1.update(acc1[0], images.size(0)) + top5.update(acc5[0], images.size(0)) + + # measure elapsed time + batch_time.update(time.time() - end) + end = time.time() + + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % nnpus_per_node == 0): + progress.print(i) + + # TODO: this should also be done with the ProgressMeter + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % nnpus_per_node == 0): + + print(' * Acc@1 {top1.avg:.3f} Acc@5 {top5.avg:.3f}' + .format(top1=top1, top5=top5)) + + + return top1.avg + + +def save_checkpoint(state, filename='checkpoint.pth'): + torch.save(state, filename) + + +class AverageMeter(object): + """Computes and stores the average and current value""" + def __init__(self, name, fmt=':f'): + self.name = name + self.fmt = fmt + self.reset() + self.skip = 0 + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + self.skip = 0 + + def update(self, val, n=1): + self.val = val + # the first 5 value are not accumulated in the average stats + self.skip += 1 + if self.skip < 5: + return + self.sum += val * n + self.count += n + self.avg = self.sum / self.count + + def __str__(self): + fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' + return fmtstr.format(**self.__dict__) + + +class ProgressMeter(object): + def __init__(self, num_batches, *meters, prefix=""): + self.batch_fmtstr = self._get_batch_fmtstr(num_batches) + self.meters = meters + self.prefix = prefix + + def print(self, batch): + entries = [self.prefix + self.batch_fmtstr.format(batch)] + entries += [str(meter) for meter in self.meters] + print('\t'.join(entries)) + + def _get_batch_fmtstr(self, num_batches): + num_digits = len(str(num_batches // 1)) + fmt = '{:' + str(num_digits) + 'd}' + return '[' + fmt + '/' + fmt.format(num_batches) + ']' + + +def adjust_learning_rate(optimizer, epoch, args): + """Sets the learning rate to the initial LR decayed by 10 every 30 epochs""" + lr = args.lr * (0.1 ** (epoch // 30)) + for param_group in optimizer.param_groups: + param_group['lr'] = lr + + +def accuracy(output, target, topk=(1,)): + """Computes the accuracy over the k top predictions for the specified values of k""" + with torch.no_grad(): + maxk = max(topk) + batch_size = target.size(0) + + _, pred = output.topk(maxk, 1, True, True) + pred = pred.t() + correct = pred.eq(target.view(1, -1).expand_as(pred)) + + res = [] + for k in topk: + correct_k = correct[:k].view(-1).float().sum(0, keepdim=True) + res.append(correct_k.mul_(100.0 / batch_size)) + return res + +def auto_augment_wrapper(img_size, auto_augment='original-mstd0.5'): + IMAGENET_DEFAULT_MEAN = [0.485, 0.456, 0.406] + assert isinstance(auto_augment, str) + aa_params = dict( + translate_const=int(img_size * 0.45), + img_mean=tuple([min(255, round(255 * x)) for x in IMAGENET_DEFAULT_MEAN]), + ) + if auto_augment.startswith('rand'): + return rand_augment_transform(auto_augment, aa_params) + elif auto_augment.startswith('augmix'): + aa_params['translate_pct'] = 0.3 + return augment_and_mix_transform(auto_augment, aa_params) + else: + return auto_augment_transform(auto_augment, aa_params) + +def adjust_learning_rate_fraction_epoch(optimizer, epoch, args): + """Use the epoch cosine schedule""" + + alpha = 0 + cosine_decay = 0.5 * (1 + np.cos(np.pi * epoch / args.epochs)) + decayed = (1 - alpha) * cosine_decay + alpha + lr = args.lr * decayed + for param_group in optimizer.param_groups: + param_group['lr'] = lr + +if __name__ == '__main__': + main() diff --git a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/hubconf.py b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/hubconf.py index 614a7b61a8..bb4d80153d 100644 --- a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/hubconf.py +++ b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/hubconf.py @@ -1,58 +1,58 @@ -# Copyright [yyyy] [name of copyright owner] -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 efficientnet_pytorch import EfficientNet as _EfficientNet - -dependencies = ['torch'] - - -def _create_model_fn(model_name): - def _model_fn(num_classes=1000, in_channels=3, pretrained='imagenet'): - """Create Efficient Net. - - Described in detail here: https://arxiv.org/abs/1905.11946 - - Args: - num_classes (int, optional): Number of classes, default is 1000. - in_channels (int, optional): Number of input channels, default - is 3. - pretrained (str, optional): One of [None, 'imagenet', 'advprop'] - If None, no pretrained model is loaded. - If 'imagenet', models trained on imagenet dataset are loaded. - If 'advprop', models trained using adversarial training called - advprop are loaded. It is important to note that the - preprocessing required for the advprop pretrained models is - slightly different from normal ImageNet preprocessing - """ - model_name_ = model_name.replace('_', '-') - if pretrained is not None: - model = _EfficientNet.from_pretrained( - model_name=model_name_, - advprop=(pretrained == 'advprop'), - num_classes=num_classes, - in_channels=in_channels) - else: - model = _EfficientNet.from_name( - model_name=model_name_, - override_params={'num_classes': num_classes}, - ) - model._change_in_channels(in_channels) - - return model - - return _model_fn - -for model_name in ['efficientnet_b' + str(i) for i in range(9)]: - locals()[model_name] = _create_model_fn(model_name) +# Copyright [yyyy] [name of copyright owner] +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 efficientnet_pytorch import EfficientNet as _EfficientNet + +dependencies = ['torch'] + + +def _create_model_fn(model_name): + def _model_fn(num_classes=1000, in_channels=3, pretrained='imagenet'): + """Create Efficient Net. + + Described in detail here: https://arxiv.org/abs/1905.11946 + + Args: + num_classes (int, optional): Number of classes, default is 1000. + in_channels (int, optional): Number of input channels, default + is 3. + pretrained (str, optional): One of [None, 'imagenet', 'advprop'] + If None, no pretrained model is loaded. + If 'imagenet', models trained on imagenet dataset are loaded. + If 'advprop', models trained using adversarial training called + advprop are loaded. It is important to note that the + preprocessing required for the advprop pretrained models is + slightly different from normal ImageNet preprocessing + """ + model_name_ = model_name.replace('_', '-') + if pretrained is not None: + model = _EfficientNet.from_pretrained( + model_name=model_name_, + advprop=(pretrained == 'advprop'), + num_classes=num_classes, + in_channels=in_channels) + else: + model = _EfficientNet.from_name( + model_name=model_name_, + override_params={'num_classes': num_classes}, + ) + model._change_in_channels(in_channels) + + return model + + return _model_fn + +for model_name in ['efficientnet_b' + str(i) for i in range(9)]: + locals()[model_name] = _create_model_fn(model_name) diff --git a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/pthtar2onnx.py b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/pthtar2onnx.py index ae3cee8264..ae878c2d10 100644 --- a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/pthtar2onnx.py +++ b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/pthtar2onnx.py @@ -1,63 +1,63 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch -import torch.onnx - -from collections import OrderedDict -from efficientnet_pytorch.model import EfficientNet - - -def proc_node_module(checkpoint, attr_name): - """ - modify state_dict - :param checkpoint: loaded model file - :param attr_name: key state_dict - :return: new state_dict - """ - new_state_dict = OrderedDict() - for k, v in checkpoint[attr_name].items(): - if k[0:7] == "module.": - name = k[7:] - else: - name = k[0:] - new_state_dict[name] = v - return new_state_dict - - -def convert(pth_file_path, onnx_file_path, class_nums): - """ - convert pth file to onnx file and output onnx file - """ - checkpoint = torch.load(pth_file_path, map_location='cpu') - checkpoint['state_dict'] = proc_node_module(checkpoint, 'state_dict') - model = EfficientNet.from_name("efficientnet-b0", num_classes=class_nums) - model.set_swish(memory_efficient=False) - model.load_state_dict(checkpoint['state_dict']) - model.eval() - - input_names = ["actual_input_1"] - output_names = ["output1"] - dummy_input = torch.randn(16, 3, 224, 224) - torch.onnx.export(model, dummy_input, onnx_file_path, - input_names=input_names, output_names=output_names, - opset_version=11) - - -if __name__ == "__main__": - src_file_path = "./checkpoint.pth" - dst_file_path = "efficientnet_npu_16.onnx" - class_num = 1000 +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch +import torch.onnx + +from collections import OrderedDict +from efficientnet_pytorch.model import EfficientNet + + +def proc_node_module(checkpoint, attr_name): + """ + modify state_dict + :param checkpoint: loaded model file + :param attr_name: key state_dict + :return: new state_dict + """ + new_state_dict = OrderedDict() + for k, v in checkpoint[attr_name].items(): + if k[0:7] == "module.": + name = k[7:] + else: + name = k[0:] + new_state_dict[name] = v + return new_state_dict + + +def convert(pth_file_path, onnx_file_path, class_nums): + """ + convert pth file to onnx file and output onnx file + """ + checkpoint = torch.load(pth_file_path, map_location='cpu') + checkpoint['state_dict'] = proc_node_module(checkpoint, 'state_dict') + model = EfficientNet.from_name("efficientnet-b0", num_classes=class_nums) + model.set_swish(memory_efficient=False) + model.load_state_dict(checkpoint['state_dict']) + model.eval() + + input_names = ["actual_input_1"] + output_names = ["output1"] + dummy_input = torch.randn(16, 3, 224, 224) + torch.onnx.export(model, dummy_input, onnx_file_path, + input_names=input_names, output_names=output_names, + opset_version=11) + + +if __name__ == "__main__": + src_file_path = "./checkpoint.pth" + dst_file_path = "efficientnet_npu_16.onnx" + class_num = 1000 convert(src_file_path, dst_file_path, class_num) \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/run_to_onnx.sh b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/run_to_onnx.sh index 5e4f0b29b9..1d44866cc0 100644 --- a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/run_to_onnx.sh +++ b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/run_to_onnx.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash -source env_npu.sh - +#!/usr/bin/env bash +source env_npu.sh + python3.7 pthtar2onnx.py \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/setup.py b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/setup.py index fdad49e12a..1ee19f2fbd 100644 --- a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/setup.py +++ b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/setup.py @@ -1,138 +1,138 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Copyright [yyyy] [name of copyright owner] -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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. - -# Note: To use the 'upload' functionality of this file, you must: -# $ pipenv install twine --dev - -import io -import os -import sys -from shutil import rmtree - -from setuptools import find_packages, setup, Command - -# Package meta-data. -NAME = 'efficientnet_pytorch' -DESCRIPTION = 'EfficientNet implemented in PyTorch.' -URL = 'https://github.com/lukemelas/EfficientNet-PyTorch' -EMAIL = 'lmelaskyriazi@college.harvard.edu' -AUTHOR = 'Luke' -REQUIRES_PYTHON = '>=3.5.0' -VERSION = '0.7.0' - -# What packages are required for this module to be executed? -REQUIRED = [ - 'torch' -] - -# What packages are optional? -EXTRAS = { - # 'fancy feature': ['django'], -} - -# The rest you shouldn't have to touch too much :) -# ------------------------------------------------ -# Except, perhaps the License and Trove Classifiers! -# If you do change the License, remember to change the Trove Classifier for that! - -here = os.path.abspath(os.path.dirname(__file__)) - -# Import the README and use it as the long-description. -# Note: this will only work if 'README.md' is present in your MANIFEST.in file! -try: - with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f: - long_description = '\n' + f.read() -except FileNotFoundError: - long_description = DESCRIPTION - -# Load the package's __version__.py module as a dictionary. -about = {} -if not VERSION: - project_slug = NAME.lower().replace("-", "_").replace(" ", "_") - with open(os.path.join(here, project_slug, '__version__.py')) as f: - exec(f.read(), about) -else: - about['__version__'] = VERSION - - -class UploadCommand(Command): - """Support setup.py upload.""" - - description = 'Build and publish the package.' - user_options = [] - - @staticmethod - def status(s): - """Prints things in bold.""" - print('\033[1m{0}\033[0m'.format(s)) - - def initialize_options(self): - pass - - def finalize_options(self): - pass - - def run(self): - try: - self.status('Removing previous builds…') - rmtree(os.path.join(here, 'dist')) - except OSError: - pass - - self.status('Building Source and Wheel (universal) distribution…') - os.system('{0} setup.py sdist bdist_wheel --universal'.format(sys.executable)) - - self.status('Uploading the package to PyPI via Twine…') - os.system('twine upload dist/*') - - self.status('Pushing git tags…') - os.system('git tag v{0}'.format(about['__version__'])) - os.system('git push --tags') - - sys.exit() - - -# Where the magic happens: -setup( - name=NAME, - version=about['__version__'], - description=DESCRIPTION, - long_description=long_description, - long_description_content_type='text/markdown', - author=AUTHOR, - author_email=EMAIL, - python_requires=REQUIRES_PYTHON, - url=URL, - packages=find_packages(exclude=["tests", "*.tests", "*.tests.*", "tests.*"]), - # py_modules=['model'], # If your package is a single module, use this instead of 'packages' - install_requires=REQUIRED, - extras_require=EXTRAS, - include_package_data=True, - license='Apache', - classifiers=[ - # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers - 'License :: OSI Approved :: Apache Software License', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - ], - # $ setup.py publish support. - cmdclass={ - 'upload': UploadCommand, - }, -) +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright [yyyy] [name of copyright owner] +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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. + +# Note: To use the 'upload' functionality of this file, you must: +# $ pipenv install twine --dev + +import io +import os +import sys +from shutil import rmtree + +from setuptools import find_packages, setup, Command + +# Package meta-data. +NAME = 'efficientnet_pytorch' +DESCRIPTION = 'EfficientNet implemented in PyTorch.' +URL = 'https://github.com/lukemelas/EfficientNet-PyTorch' +EMAIL = 'lmelaskyriazi@college.harvard.edu' +AUTHOR = 'Luke' +REQUIRES_PYTHON = '>=3.5.0' +VERSION = '0.7.0' + +# What packages are required for this module to be executed? +REQUIRED = [ + 'torch' +] + +# What packages are optional? +EXTRAS = { + # 'fancy feature': ['django'], +} + +# The rest you shouldn't have to touch too much :) +# ------------------------------------------------ +# Except, perhaps the License and Trove Classifiers! +# If you do change the License, remember to change the Trove Classifier for that! + +here = os.path.abspath(os.path.dirname(__file__)) + +# Import the README and use it as the long-description. +# Note: this will only work if 'README.md' is present in your MANIFEST.in file! +try: + with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f: + long_description = '\n' + f.read() +except FileNotFoundError: + long_description = DESCRIPTION + +# Load the package's __version__.py module as a dictionary. +about = {} +if not VERSION: + project_slug = NAME.lower().replace("-", "_").replace(" ", "_") + with open(os.path.join(here, project_slug, '__version__.py')) as f: + exec(f.read(), about) +else: + about['__version__'] = VERSION + + +class UploadCommand(Command): + """Support setup.py upload.""" + + description = 'Build and publish the package.' + user_options = [] + + @staticmethod + def status(s): + """Prints things in bold.""" + print('\033[1m{0}\033[0m'.format(s)) + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + try: + self.status('Removing previous builds…') + rmtree(os.path.join(here, 'dist')) + except OSError: + pass + + self.status('Building Source and Wheel (universal) distribution…') + os.system('{0} setup.py sdist bdist_wheel --universal'.format(sys.executable)) + + self.status('Uploading the package to PyPI via Twine…') + os.system('twine upload dist/*') + + self.status('Pushing git tags…') + os.system('git tag v{0}'.format(about['__version__'])) + os.system('git push --tags') + + sys.exit() + + +# Where the magic happens: +setup( + name=NAME, + version=about['__version__'], + description=DESCRIPTION, + long_description=long_description, + long_description_content_type='text/markdown', + author=AUTHOR, + author_email=EMAIL, + python_requires=REQUIRES_PYTHON, + url=URL, + packages=find_packages(exclude=["tests", "*.tests", "*.tests.*", "tests.*"]), + # py_modules=['model'], # If your package is a single module, use this instead of 'packages' + install_requires=REQUIRED, + extras_require=EXTRAS, + include_package_data=True, + license='Apache', + classifiers=[ + # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers + 'License :: OSI Approved :: Apache Software License', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + ], + # $ setup.py publish support. + cmdclass={ + 'upload': UploadCommand, + }, +) diff --git a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/test/train_full_8p.sh b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/test/train_full_8p.sh index 5a841a3b88..e5def7ceab 100644 --- a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/test/train_full_8p.sh +++ b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/test/train_full_8p.sh @@ -1,174 +1,174 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -#export ASCEND_SLOG_PRINT_TO_STDOUT=1 - -#集合通信参数,不需要修改 -export HCCL_WHITELIST_DISABLE=1 -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 -# source env.sh -RANK_SIZE=8 -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -# export ASCEND_GLOBAL_LOG_LEVEL_ETP_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="EfficientNet_ID0097_for_PyTorch" -#训练epoch -train_epochs=100 -#训练batch_size -batch_size=4096 -#训练step -train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.045 - - - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -#add ASCEND_DEVICE_ID -ASCEND_DEVICE_ID=0 - -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - -#修改参数 -sed -i "s|pass|break|g" ${cur_path}/../examples/imagenet/main.py -wait - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -# 绑核,不需要的绑核的模型删除,需要模型审视修改 -corenum=`cat /proc/cpuinfo |grep "processor"|wc -l` -let a=RANK_ID*${corenum}/${RANK_SIZE} -let b=RANK_ID+1 -let c=b*${corenum}/${RANK_SIZE}-1 - - -nohup taskset -c $a-$c python3.7 ${cur_path}/../examples/imagenet/main.py \ - --data=$data_path \ - --arch=efficientnet-b0 --batch-size=$batch_size \ - --lr=1.6 \ - --momentum=0.9 \ - --epochs=100 \ - --autoaug \ - --amp \ - --pm=O1 \ - --loss_scale=32 \ - --val_feq=10 \ - --addr=$(hostname -I |awk '{print $1}') \ - --dist-backend=hccl \ - --multiprocessing-distributed \ - --world-size 1 \ - --rank 0 > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#参数改回 -#修改参数 -sed -i "s|break|pass|g" ${cur_path}/../examples/imagenet/main.py -wait - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|tail -1|awk '{print $NF}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep -a '* Acc@1' train_0.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` -train_accuracy=`grep -a '* Acc@1' ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` - -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +#export ASCEND_SLOG_PRINT_TO_STDOUT=1 + +#集合通信参数,不需要修改 +export HCCL_WHITELIST_DISABLE=1 +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 +# source env.sh +RANK_SIZE=8 +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +# export ASCEND_GLOBAL_LOG_LEVEL_ETP_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="EfficientNet_ID0097_for_PyTorch" +#训练epoch +train_epochs=100 +#训练batch_size +batch_size=4096 +#训练step +train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.045 + + + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +#add ASCEND_DEVICE_ID +ASCEND_DEVICE_ID=0 + +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + +#修改参数 +sed -i "s|pass|break|g" ${cur_path}/../examples/imagenet/main.py +wait + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +# 绑核,不需要的绑核的模型删除,需要模型审视修改 +corenum=`cat /proc/cpuinfo |grep "processor"|wc -l` +let a=RANK_ID*${corenum}/${RANK_SIZE} +let b=RANK_ID+1 +let c=b*${corenum}/${RANK_SIZE}-1 + + +nohup taskset -c $a-$c python3.7 ${cur_path}/../examples/imagenet/main.py \ + --data=$data_path \ + --arch=efficientnet-b0 --batch-size=$batch_size \ + --lr=1.6 \ + --momentum=0.9 \ + --epochs=100 \ + --autoaug \ + --amp \ + --pm=O1 \ + --loss_scale=32 \ + --val_feq=10 \ + --addr=$(hostname -I |awk '{print $1}') \ + --dist-backend=hccl \ + --multiprocessing-distributed \ + --world-size 1 \ + --rank 0 > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#参数改回 +#修改参数 +sed -i "s|break|pass|g" ${cur_path}/../examples/imagenet/main.py +wait + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|tail -1|awk '{print $NF}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep -a '* Acc@1' train_0.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` +train_accuracy=`grep -a '* Acc@1' ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` + +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/test/train_performance_1p.sh b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/test/train_performance_1p.sh index 4a5a6d5b4c..2ca641a5ea 100644 --- a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/test/train_performance_1p.sh +++ b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/test/train_performance_1p.sh @@ -1,160 +1,160 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -#export ASCEND_SLOG_PRINT_TO_STDOUT=1 - -#集合通信参数,不需要修改 -export HCCL_WHITELIST_DISABLE=1 -export RANK_SIZE=1 -export JOB_ID=10087 -RANK_ID_START=0 -# source env.sh -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -# export ASCEND_GLOBAL_LOG_LEVEL_ETP_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="EfficientNet_ID0097_for_PyTorch" -#训练epoch -train_epochs=1 -#训练batch_size -batch_size=512 -#训练step -train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.045 - - - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - -#修改参数 -sed -i "s|pass|break|g" ${cur_path}/../examples/imagenet/main.py -wait - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#训练 -nohup python3.7 ${cur_path}/../examples/imagenet/main.py \ - --data=$data_path \ - --arch=efficientnet-b0 \ - --batch-size=$batch_size \ - --lr=0.2 \ - --momentum=0.9 \ - --epochs=$train_epochs \ - --autoaug \ - --amp \ - --pm=O1 \ - --loss_scale=32 \ - --val_feq=10 \ - --stop-step-num=1000 \ - --npu=$ASCEND_DEVICE_ID > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#参数改回 -#修改参数 -sed -i "s|break|pass|g" ${cur_path}/../examples/imagenet/main.py -wait - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|tail -1|awk '{print $NF}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep -a '* Acc@1' train_0.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` - -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +#export ASCEND_SLOG_PRINT_TO_STDOUT=1 + +#集合通信参数,不需要修改 +export HCCL_WHITELIST_DISABLE=1 +export RANK_SIZE=1 +export JOB_ID=10087 +RANK_ID_START=0 +# source env.sh +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +# export ASCEND_GLOBAL_LOG_LEVEL_ETP_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="EfficientNet_ID0097_for_PyTorch" +#训练epoch +train_epochs=1 +#训练batch_size +batch_size=512 +#训练step +train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.045 + + + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + +#修改参数 +sed -i "s|pass|break|g" ${cur_path}/../examples/imagenet/main.py +wait + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#训练 +nohup python3.7 ${cur_path}/../examples/imagenet/main.py \ + --data=$data_path \ + --arch=efficientnet-b0 \ + --batch-size=$batch_size \ + --lr=0.2 \ + --momentum=0.9 \ + --epochs=$train_epochs \ + --autoaug \ + --amp \ + --pm=O1 \ + --loss_scale=32 \ + --val_feq=10 \ + --stop-step-num=1000 \ + --npu=$ASCEND_DEVICE_ID > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#参数改回 +#修改参数 +sed -i "s|break|pass|g" ${cur_path}/../examples/imagenet/main.py +wait + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|tail -1|awk '{print $NF}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep -a '* Acc@1' train_0.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` + +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/test/train_performance_8p.sh b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/test/train_performance_8p.sh index 5128dfcbb2..b19bd51007 100644 --- a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/test/train_performance_8p.sh +++ b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/test/train_performance_8p.sh @@ -1,173 +1,173 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -#export ASCEND_SLOG_PRINT_TO_STDOUT=1 -export SOC_VERSION=Ascend910 -export HCCL_CONNECT_TIMEOUT=600 - -#集合通信参数,不需要修改 -export HCCL_WHITELIST_DISABLE=1 -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 -# source env.sh -RANK_SIZE=8 -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -# export ASCEND_GLOBAL_LOG_LEVEL_ETP_ETP_ETP_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="EfficientNet_ID0097_for_PyTorch" -#训练epoch -train_epochs=1 -#训练batch_size -batch_size=4096 -#训练step -train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.045 - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - -#修改参数 -sed -i "s|pass|break|g" ${cur_path}/../examples/imagenet/main.py -wait - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -# 绑核,不需要的绑核的模型删除,需要模型审视修改 -#corenum=`cat /proc/cpuinfo |grep "processor"|wc -l` -#let a=RANK_ID*${corenum}/${RANK_SIZE} -#let b=RANK_ID+1 -#let c=b*${corenum}/${RANK_SIZE}-1 -export RANK_INDEX=0 -DEVICE_INDEX=$(( ASCEND_DEVICE_ID + RANK_INDEX * 8 )) -export DEVICE_INDEX=${DEVICE_INDEX} - -#nohup taskset -c $a-$c python3.7 ${cur_path}/../examples/imagenet/main.py -nohup python3.7 ${cur_path}/../examples/imagenet/main.py \ - --data=$data_path \ - --arch=efficientnet-b0 \ - --batch-size=$batch_size \ - --lr=1.6 \ - --momentum=0.9 \ - --epochs=1 \ - --autoaug \ - --amp \ - --pm=O1 \ - --loss_scale=32 \ - --val_feq=10 \ - --addr=$(hostname -I |awk '{print $1}') \ - --dist-backend=hccl \ - --multiprocessing-distributed \ - --world-size 1 \ - --rank 0 > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#参数改回 -#修改参数 -sed -i "s|break|pass|g" ${cur_path}/../examples/imagenet/main.py -wait - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|tail -1|awk '{print $NF}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep -a '* Acc@1' train_0.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` - -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +#export ASCEND_SLOG_PRINT_TO_STDOUT=1 +export SOC_VERSION=Ascend910 +export HCCL_CONNECT_TIMEOUT=600 + +#集合通信参数,不需要修改 +export HCCL_WHITELIST_DISABLE=1 +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 +# source env.sh +RANK_SIZE=8 +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +# export ASCEND_GLOBAL_LOG_LEVEL_ETP_ETP_ETP_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="EfficientNet_ID0097_for_PyTorch" +#训练epoch +train_epochs=1 +#训练batch_size +batch_size=4096 +#训练step +train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.045 + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + +#修改参数 +sed -i "s|pass|break|g" ${cur_path}/../examples/imagenet/main.py +wait + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +# 绑核,不需要的绑核的模型删除,需要模型审视修改 +#corenum=`cat /proc/cpuinfo |grep "processor"|wc -l` +#let a=RANK_ID*${corenum}/${RANK_SIZE} +#let b=RANK_ID+1 +#let c=b*${corenum}/${RANK_SIZE}-1 +export RANK_INDEX=0 +DEVICE_INDEX=$(( ASCEND_DEVICE_ID + RANK_INDEX * 8 )) +export DEVICE_INDEX=${DEVICE_INDEX} + +#nohup taskset -c $a-$c python3.7 ${cur_path}/../examples/imagenet/main.py +nohup python3.7 ${cur_path}/../examples/imagenet/main.py \ + --data=$data_path \ + --arch=efficientnet-b0 \ + --batch-size=$batch_size \ + --lr=1.6 \ + --momentum=0.9 \ + --epochs=1 \ + --autoaug \ + --amp \ + --pm=O1 \ + --loss_scale=32 \ + --val_feq=10 \ + --addr=$(hostname -I |awk '{print $1}') \ + --dist-backend=hccl \ + --multiprocessing-distributed \ + --world-size 1 \ + --rank 0 > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#参数改回 +#修改参数 +sed -i "s|break|pass|g" ${cur_path}/../examples/imagenet/main.py +wait + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|tail -1|awk '{print $NF}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep -a '* Acc@1' train_0.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` + +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/tests/test_model.py b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/tests/test_model.py index 936d91fdbc..7e0a8554cd 100644 --- a/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/tests/test_model.py +++ b/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch/tests/test_model.py @@ -1,139 +1,139 @@ -# Copyright [yyyy] [name of copyright owner] -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 collections import OrderedDict - -import pytest -import torch -import torch.nn as nn - -from efficientnet_pytorch import EfficientNet - - -# -- fixtures ------------------------------------------------------------------------------------- - -@pytest.fixture(scope='module', params=[x for x in range(4)]) -def model(request): - return 'efficientnet-b{}'.format(request.param) - - -@pytest.fixture(scope='module', params=[True, False]) -def pretrained(request): - return request.param - - -@pytest.fixture(scope='function') -def net(model, pretrained): - return EfficientNet.from_pretrained(model) if pretrained else EfficientNet.from_name(model) - - -# -- tests ---------------------------------------------------------------------------------------- - -@pytest.mark.parametrize('img_size', [224, 256, 512]) -def test_forward(net, img_size): - """Test `.forward()` doesn't throw an error""" - data = torch.zeros((1, 3, img_size, img_size)) - output = net(data) - assert not torch.isnan(output).any() - - -def test_dropout_training(net): - """Test dropout `.training` is set by `.train()` on parent `nn.module`""" - net.train() - assert net._dropout.training == True - - -def test_dropout_eval(net): - """Test dropout `.training` is set by `.eval()` on parent `nn.module`""" - net.eval() - assert net._dropout.training == False - - -def test_dropout_update(net): - """Test dropout `.training` is updated by `.train()` and `.eval()` on parent `nn.module`""" - net.train() - assert net._dropout.training == True - net.eval() - assert net._dropout.training == False - net.train() - assert net._dropout.training == True - net.eval() - assert net._dropout.training == False - - -@pytest.mark.parametrize('img_size', [224, 256, 512]) -def test_modify_dropout(net, img_size): - """Test ability to modify dropout and fc modules of network""" - dropout = nn.Sequential(OrderedDict([ - ('_bn2', nn.BatchNorm1d(net._bn1.num_features)), - ('_drop1', nn.Dropout(p=net._global_params.dropout_rate)), - ('_linear1', nn.Linear(net._bn1.num_features, 512)), - ('_relu', nn.ReLU()), - ('_bn3', nn.BatchNorm1d(512)), - ('_drop2', nn.Dropout(p=net._global_params.dropout_rate / 2)) - ])) - fc = nn.Linear(512, net._global_params.num_classes) - - net._dropout = dropout - net._fc = fc - - data = torch.zeros((2, 3, img_size, img_size)) - output = net(data) - assert not torch.isnan(output).any() - - -@pytest.mark.parametrize('img_size', [224, 256, 512]) -def test_modify_pool(net, img_size): - """Test ability to modify pooling module of network""" - - class AdaptiveMaxAvgPool(nn.Module): - - def __init__(self): - super().__init__() - self.ada_avgpool = nn.AdaptiveAvgPool2d(1) - self.ada_maxpool = nn.AdaptiveMaxPool2d(1) - - def forward(self, x): - avg_x = self.ada_avgpool(x) - max_x = self.ada_maxpool(x) - x = torch.cat((avg_x, max_x), dim=1) - return x - - avg_pooling = AdaptiveMaxAvgPool() - fc = nn.Linear(net._fc.in_features * 2, net._global_params.num_classes) - - net._avg_pooling = avg_pooling - net._fc = fc - - data = torch.zeros((2, 3, img_size, img_size)) - output = net(data) - assert not torch.isnan(output).any() - - -@pytest.mark.parametrize('img_size', [224, 256, 512]) -def test_extract_endpoints(net, img_size): - """Test `.extract_endpoints()` doesn't throw an error""" - data = torch.zeros((1, 3, img_size, img_size)) - endpoints = net.extract_endpoints(data) - assert not torch.isnan(endpoints['reduction_1']).any() - assert not torch.isnan(endpoints['reduction_2']).any() - assert not torch.isnan(endpoints['reduction_3']).any() - assert not torch.isnan(endpoints['reduction_4']).any() - assert not torch.isnan(endpoints['reduction_5']).any() - assert endpoints['reduction_1'].size(2) == img_size // 2 - assert endpoints['reduction_2'].size(2) == img_size // 4 - assert endpoints['reduction_3'].size(2) == img_size // 8 - assert endpoints['reduction_4'].size(2) == img_size // 16 - assert endpoints['reduction_5'].size(2) == img_size // 32 +# Copyright [yyyy] [name of copyright owner] +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 collections import OrderedDict + +import pytest +import torch +import torch.nn as nn + +from efficientnet_pytorch import EfficientNet + + +# -- fixtures ------------------------------------------------------------------------------------- + +@pytest.fixture(scope='module', params=[x for x in range(4)]) +def model(request): + return 'efficientnet-b{}'.format(request.param) + + +@pytest.fixture(scope='module', params=[True, False]) +def pretrained(request): + return request.param + + +@pytest.fixture(scope='function') +def net(model, pretrained): + return EfficientNet.from_pretrained(model) if pretrained else EfficientNet.from_name(model) + + +# -- tests ---------------------------------------------------------------------------------------- + +@pytest.mark.parametrize('img_size', [224, 256, 512]) +def test_forward(net, img_size): + """Test `.forward()` doesn't throw an error""" + data = torch.zeros((1, 3, img_size, img_size)) + output = net(data) + assert not torch.isnan(output).any() + + +def test_dropout_training(net): + """Test dropout `.training` is set by `.train()` on parent `nn.module`""" + net.train() + assert net._dropout.training == True + + +def test_dropout_eval(net): + """Test dropout `.training` is set by `.eval()` on parent `nn.module`""" + net.eval() + assert net._dropout.training == False + + +def test_dropout_update(net): + """Test dropout `.training` is updated by `.train()` and `.eval()` on parent `nn.module`""" + net.train() + assert net._dropout.training == True + net.eval() + assert net._dropout.training == False + net.train() + assert net._dropout.training == True + net.eval() + assert net._dropout.training == False + + +@pytest.mark.parametrize('img_size', [224, 256, 512]) +def test_modify_dropout(net, img_size): + """Test ability to modify dropout and fc modules of network""" + dropout = nn.Sequential(OrderedDict([ + ('_bn2', nn.BatchNorm1d(net._bn1.num_features)), + ('_drop1', nn.Dropout(p=net._global_params.dropout_rate)), + ('_linear1', nn.Linear(net._bn1.num_features, 512)), + ('_relu', nn.ReLU()), + ('_bn3', nn.BatchNorm1d(512)), + ('_drop2', nn.Dropout(p=net._global_params.dropout_rate / 2)) + ])) + fc = nn.Linear(512, net._global_params.num_classes) + + net._dropout = dropout + net._fc = fc + + data = torch.zeros((2, 3, img_size, img_size)) + output = net(data) + assert not torch.isnan(output).any() + + +@pytest.mark.parametrize('img_size', [224, 256, 512]) +def test_modify_pool(net, img_size): + """Test ability to modify pooling module of network""" + + class AdaptiveMaxAvgPool(nn.Module): + + def __init__(self): + super().__init__() + self.ada_avgpool = nn.AdaptiveAvgPool2d(1) + self.ada_maxpool = nn.AdaptiveMaxPool2d(1) + + def forward(self, x): + avg_x = self.ada_avgpool(x) + max_x = self.ada_maxpool(x) + x = torch.cat((avg_x, max_x), dim=1) + return x + + avg_pooling = AdaptiveMaxAvgPool() + fc = nn.Linear(net._fc.in_features * 2, net._global_params.num_classes) + + net._avg_pooling = avg_pooling + net._fc = fc + + data = torch.zeros((2, 3, img_size, img_size)) + output = net(data) + assert not torch.isnan(output).any() + + +@pytest.mark.parametrize('img_size', [224, 256, 512]) +def test_extract_endpoints(net, img_size): + """Test `.extract_endpoints()` doesn't throw an error""" + data = torch.zeros((1, 3, img_size, img_size)) + endpoints = net.extract_endpoints(data) + assert not torch.isnan(endpoints['reduction_1']).any() + assert not torch.isnan(endpoints['reduction_2']).any() + assert not torch.isnan(endpoints['reduction_3']).any() + assert not torch.isnan(endpoints['reduction_4']).any() + assert not torch.isnan(endpoints['reduction_5']).any() + assert endpoints['reduction_1'].size(2) == img_size // 2 + assert endpoints['reduction_2'].size(2) == img_size // 4 + assert endpoints['reduction_3'].size(2) == img_size // 8 + assert endpoints['reduction_4'].size(2) == img_size // 16 + assert endpoints['reduction_5'].size(2) == img_size // 32 diff --git a/PyTorch/built-in/cv/classification/MobileNetV2_for_PyTorch/test/train_full_1p.sh b/PyTorch/built-in/cv/classification/MobileNetV2_for_PyTorch/test/train_full_1p.sh index abbfc7ae80..55e29d1e09 100644 --- a/PyTorch/built-in/cv/classification/MobileNetV2_for_PyTorch/test/train_full_1p.sh +++ b/PyTorch/built-in/cv/classification/MobileNetV2_for_PyTorch/test/train_full_1p.sh @@ -1,158 +1,158 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` - - -#集合通信参数,不需要修改 -export HCCL_WHITELIST_DISABLE=1 -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 -# source env.sh -RANK_SIZE=8 -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="DeepMar_for_PyTorch" -#训练epoch -train_epochs=1 -#训练batch_size -batch_size=512 -#训练step -train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.045 - - - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -# 绑核,不需要的绑核的模型删除,需要模型审视修改 -python3.7 ${cur_path}/../train/mobilenetv2_8p_main_anycard.py \ - --addr=$(hostname -I |awk '{print $1}') \ - --seed 49 \ - --workers 128 \ - --lr 0.05 \ - --print-freq 1 \ - --eval-freq 1 \ - --dist-url 'tcp://127.0.0.1:50002' \ - --dist-backend 'hccl' \ - --multiprocessing-distributed \ - --world-size 1 \ - --class-nums 1000 \ - --batch-size 512 \ - --epochs $train_epochs \ - --rank 0 \ - --device-list '$ASCEND_DEVICE_ID' \ - --amp \ - --benchmark 0 \ - --data $data_path > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -#FPS=`grep -a 'FPS' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F " " '{print $NF}'|awk 'END {print}'` -FPS=`grep Epoch: ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep -v Test|awk -F "FPS" '{print $2}'|awk -F " " '{print $1}' | tail -n +2|awk '{sum+=$1} END {print sum/NR}' | sed s/[[]:space:]//g ` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -train_accuracy=`grep -a '* Acc@1' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` - -#打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep Epoch: $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep -v Test|awk -F "Loss" '{print $NF}' | awk -F " " '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` + + +#集合通信参数,不需要修改 +export HCCL_WHITELIST_DISABLE=1 +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 +# source env.sh +RANK_SIZE=8 +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="DeepMar_for_PyTorch" +#训练epoch +train_epochs=1 +#训练batch_size +batch_size=512 +#训练step +train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.045 + + + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +# 绑核,不需要的绑核的模型删除,需要模型审视修改 +python3.7 ${cur_path}/../train/mobilenetv2_8p_main_anycard.py \ + --addr=$(hostname -I |awk '{print $1}') \ + --seed 49 \ + --workers 128 \ + --lr 0.05 \ + --print-freq 1 \ + --eval-freq 1 \ + --dist-url 'tcp://127.0.0.1:50002' \ + --dist-backend 'hccl' \ + --multiprocessing-distributed \ + --world-size 1 \ + --class-nums 1000 \ + --batch-size 512 \ + --epochs $train_epochs \ + --rank 0 \ + --device-list '$ASCEND_DEVICE_ID' \ + --amp \ + --benchmark 0 \ + --data $data_path > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +#FPS=`grep -a 'FPS' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F " " '{print $NF}'|awk 'END {print}'` +FPS=`grep Epoch: ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep -v Test|awk -F "FPS" '{print $2}'|awk -F " " '{print $1}' | tail -n +2|awk '{sum+=$1} END {print sum/NR}' | sed s/[[]:space:]//g ` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +train_accuracy=`grep -a '* Acc@1' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` + +#打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep Epoch: $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep -v Test|awk -F "Loss" '{print $NF}' | awk -F " " '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/MobileNetV2_for_PyTorch/test/train_full_8p.sh b/PyTorch/built-in/cv/classification/MobileNetV2_for_PyTorch/test/train_full_8p.sh index 0073c1ce29..eeaad01239 100644 --- a/PyTorch/built-in/cv/classification/MobileNetV2_for_PyTorch/test/train_full_8p.sh +++ b/PyTorch/built-in/cv/classification/MobileNetV2_for_PyTorch/test/train_full_8p.sh @@ -1,157 +1,157 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` - -#集合通信参数,不需要修改 -export HCCL_WHITELIST_DISABLE=1 -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 -RANK_SIZE=8 -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="MobileNetV2_ID0098_for_PyTorch" -#训练epoch -train_epochs=500 -#train_epochs=10 -#训练batch_size -batch_size=4096 -#训练step -train_steps= -#学习率 -learning_rate= - - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -python3.7 ${cur_path}/../train/mobilenetv2_8p_main_anycard.py \ - --addr=$(hostname -I |awk '{print $1}') \ - --seed 49 \ - --workers 128 \ - --lr 0.4 \ - --print-freq 1 \ - --eval-freq 1 \ - --dist-url 'tcp://127.0.0.1:50002' \ - --dist-backend 'hccl' \ - --multiprocessing-distributed \ - --world-size 1 \ - --batch-size $batch_size \ - --epochs $train_epochs \ - --rank 0 \ - --device-list '0,1,2,3,4,5,6,7' \ - --amp \ - --benchmark 0 \ - --data $data_path > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -wait - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk '{print $NF}'|awk '{sum+=$1} END {print sum/NR}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -train_accuracy=`grep -a '* Acc@1' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` - -#打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}' |awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` + +#集合通信参数,不需要修改 +export HCCL_WHITELIST_DISABLE=1 +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 +RANK_SIZE=8 +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="MobileNetV2_ID0098_for_PyTorch" +#训练epoch +train_epochs=500 +#train_epochs=10 +#训练batch_size +batch_size=4096 +#训练step +train_steps= +#学习率 +learning_rate= + + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +python3.7 ${cur_path}/../train/mobilenetv2_8p_main_anycard.py \ + --addr=$(hostname -I |awk '{print $1}') \ + --seed 49 \ + --workers 128 \ + --lr 0.4 \ + --print-freq 1 \ + --eval-freq 1 \ + --dist-url 'tcp://127.0.0.1:50002' \ + --dist-backend 'hccl' \ + --multiprocessing-distributed \ + --world-size 1 \ + --batch-size $batch_size \ + --epochs $train_epochs \ + --rank 0 \ + --device-list '0,1,2,3,4,5,6,7' \ + --amp \ + --benchmark 0 \ + --data $data_path > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +wait + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk '{print $NF}'|awk '{sum+=$1} END {print sum/NR}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +train_accuracy=`grep -a '* Acc@1' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` + +#打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}' |awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/MobileNetV2_for_PyTorch/test/train_performance_1p.sh b/PyTorch/built-in/cv/classification/MobileNetV2_for_PyTorch/test/train_performance_1p.sh index d7d9c63c87..b807919c40 100644 --- a/PyTorch/built-in/cv/classification/MobileNetV2_for_PyTorch/test/train_performance_1p.sh +++ b/PyTorch/built-in/cv/classification/MobileNetV2_for_PyTorch/test/train_performance_1p.sh @@ -1,163 +1,163 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` - - -#集合通信参数,不需要修改 -export HCCL_WHITELIST_DISABLE=1 -export RANK_SIZE=1 -export JOB_ID=10087 -RANK_ID_START=0 -# source env.sh -#RANK_SIZE=8 -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="MobileNetV2_ID0098_for_PyTorch" -#训练epoch -train_epochs=1 -#训练batch_size -batch_size=512 -#训练step -train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.045 - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - -#参数修改 -sed -i "s|pass|break|g" ${cur_path}/../train/mobilenetv2_8p_main_anycard.py -wait - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -# 绑核,不需要的绑核的模型删除,需要模型审视修改 -python3.7 ${cur_path}/../train/mobilenetv2_8p_main_anycard.py \ - --addr=$(hostname -I |awk '{print $1}') \ - --seed 49 \ - --workers 128 \ - --lr 0.05 \ - --print-freq 1 \ - --eval-freq 1 \ - --dist-url 'tcp://127.0.0.1:50002' \ - --dist-backend 'hccl' \ - --multiprocessing-distributed \ - --world-size 1 \ - --class-nums 1000 \ - --batch-size $batch_size \ - --epochs $train_epochs \ - --rank 0 \ - --device-list $ASCEND_DEVICE_ID \ - --amp \ - --benchmark 0 \ - --data $data_path > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#参数改回 -sed -i "s|break|pass|g" ${cur_path}/../train/mobilenetv2_8p_main_anycard.py -wait - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk '{print $NF}'|awk '{sum+=$1} END {print sum/NR}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep -a '* Acc@1' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` - -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}' |awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` + + +#集合通信参数,不需要修改 +export HCCL_WHITELIST_DISABLE=1 +export RANK_SIZE=1 +export JOB_ID=10087 +RANK_ID_START=0 +# source env.sh +#RANK_SIZE=8 +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="MobileNetV2_ID0098_for_PyTorch" +#训练epoch +train_epochs=1 +#训练batch_size +batch_size=512 +#训练step +train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.045 + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + +#参数修改 +sed -i "s|pass|break|g" ${cur_path}/../train/mobilenetv2_8p_main_anycard.py +wait + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +# 绑核,不需要的绑核的模型删除,需要模型审视修改 +python3.7 ${cur_path}/../train/mobilenetv2_8p_main_anycard.py \ + --addr=$(hostname -I |awk '{print $1}') \ + --seed 49 \ + --workers 128 \ + --lr 0.05 \ + --print-freq 1 \ + --eval-freq 1 \ + --dist-url 'tcp://127.0.0.1:50002' \ + --dist-backend 'hccl' \ + --multiprocessing-distributed \ + --world-size 1 \ + --class-nums 1000 \ + --batch-size $batch_size \ + --epochs $train_epochs \ + --rank 0 \ + --device-list $ASCEND_DEVICE_ID \ + --amp \ + --benchmark 0 \ + --data $data_path > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#参数改回 +sed -i "s|break|pass|g" ${cur_path}/../train/mobilenetv2_8p_main_anycard.py +wait + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk '{print $NF}'|awk '{sum+=$1} END {print sum/NR}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep -a '* Acc@1' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` + +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}' |awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log diff --git a/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/CMakeLists.txt b/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/CMakeLists.txt index dccbd552fe..903f82d57a 100644 --- a/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/CMakeLists.txt +++ b/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/CMakeLists.txt @@ -1,49 +1,49 @@ -cmake_minimum_required(VERSION 3.14.0) -project(resnet50) - -set(TARGET resnet50) - -add_definitions(-DENABLE_DVPP_INTERFACE) -add_compile_options(-std=c++11 -fPIE -fstack-protector-all -fPIC -Wall) -add_link_options(-Wl,-z,relro,-z,now,-z,noexecstack -s -pie) - -# Check environment variable -if(NOT DEFINED ENV{ASCEND_HOME}) - message(FATAL_ERROR "please define environment variable:ASCEND_HOME") -endif() -if(NOT DEFINED ENV{ASCEND_VERSION}) - message(WARNING "please define environment variable:ASCEND_VERSION") -endif() -if(NOT DEFINED ENV{ARCH_PATTERN}) - message(WARNING "please define environment variable:ARCH_PATTERN") -endif() -set(ACL_INC_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/include) -set(ACL_LIB_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/lib64) - -set(MXBASE_ROOT_DIR ${PROJECT_SOURCE_DIR}/../../) -set(MXBASE_INC ${MXBASE_ROOT_DIR}/mxbase/include) -set(MXBASE_LIB_DIR ${MXBASE_ROOT_DIR}/dist/lib) -set(MXBASE_POST_LIB_DIR ${MXBASE_ROOT_DIR}/dist/lib/modelpostprocessors) -set(MXBASE_POST_PROCESS_DIR ${MXBASE_ROOT_DIR}/postprocess/include) -if(DEFINED ENV{MXSDK_OPENSOURCE_DIR}) - set(OPENSOURCE_DIR $ENV{MXSDK_OPENSOURCE_DIR}) -else() - set(OPENSOURCE_DIR ${MXBASE_ROOT_DIR}/opensource/dist) -endif() - -include_directories(${ACL_INC_DIR}) -include_directories(${OPENSOURCE_DIR}/include) -include_directories(${OPENSOURCE_DIR}/include/opencv4) - -include_directories(${MXBASE_INC}) -include_directories(${MXBASE_POST_PROCESS_DIR}) - -link_directories(${ACL_LIB_DIR}) -link_directories(${OPENSOURCE_DIR}/lib) -link_directories(${MXBASE_LIB_DIR}) -link_directories(${MXBASE_POST_LIB_DIR}) - -add_executable(${TARGET} main.cpp Resnet50Classify.cpp) -target_link_libraries(${TARGET} glog cpprest mxbase resnet50postprocess opencv_world stdc++fs) - +cmake_minimum_required(VERSION 3.14.0) +project(resnet50) + +set(TARGET resnet50) + +add_definitions(-DENABLE_DVPP_INTERFACE) +add_compile_options(-std=c++11 -fPIE -fstack-protector-all -fPIC -Wall) +add_link_options(-Wl,-z,relro,-z,now,-z,noexecstack -s -pie) + +# Check environment variable +if(NOT DEFINED ENV{ASCEND_HOME}) + message(FATAL_ERROR "please define environment variable:ASCEND_HOME") +endif() +if(NOT DEFINED ENV{ASCEND_VERSION}) + message(WARNING "please define environment variable:ASCEND_VERSION") +endif() +if(NOT DEFINED ENV{ARCH_PATTERN}) + message(WARNING "please define environment variable:ARCH_PATTERN") +endif() +set(ACL_INC_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/include) +set(ACL_LIB_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/lib64) + +set(MXBASE_ROOT_DIR ${PROJECT_SOURCE_DIR}/../../) +set(MXBASE_INC ${MXBASE_ROOT_DIR}/mxbase/include) +set(MXBASE_LIB_DIR ${MXBASE_ROOT_DIR}/dist/lib) +set(MXBASE_POST_LIB_DIR ${MXBASE_ROOT_DIR}/dist/lib/modelpostprocessors) +set(MXBASE_POST_PROCESS_DIR ${MXBASE_ROOT_DIR}/postprocess/include) +if(DEFINED ENV{MXSDK_OPENSOURCE_DIR}) + set(OPENSOURCE_DIR $ENV{MXSDK_OPENSOURCE_DIR}) +else() + set(OPENSOURCE_DIR ${MXBASE_ROOT_DIR}/opensource/dist) +endif() + +include_directories(${ACL_INC_DIR}) +include_directories(${OPENSOURCE_DIR}/include) +include_directories(${OPENSOURCE_DIR}/include/opencv4) + +include_directories(${MXBASE_INC}) +include_directories(${MXBASE_POST_PROCESS_DIR}) + +link_directories(${ACL_LIB_DIR}) +link_directories(${OPENSOURCE_DIR}/lib) +link_directories(${MXBASE_LIB_DIR}) +link_directories(${MXBASE_POST_LIB_DIR}) + +add_executable(${TARGET} main.cpp Resnet50Classify.cpp) +target_link_libraries(${TARGET} glog cpprest mxbase resnet50postprocess opencv_world stdc++fs) + install(TARGETS ${TARGET} RUNTIME DESTINATION ${PROJECT_SOURCE_DIR}/) \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/Resnet50Classify.cpp b/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/Resnet50Classify.cpp index 024a9c3ae1..6322732d10 100644 --- a/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/Resnet50Classify.cpp +++ b/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/Resnet50Classify.cpp @@ -1,261 +1,261 @@ -/* - * Copyright (c) 2021. Huawei Technologies Co., Ltd. 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. - */ - -#include -#include -#include "Resnet50Classify.h" -#include "MxBase/DeviceManager/DeviceManager.h" -#include "MxBase/Log/Log.h" - -using namespace MxBase; -namespace { -const uint32_t YUV_BYTE_NU = 3; -const uint32_t YUV_BYTE_DE = 2; -const uint32_t VPC_H_ALIGN = 2; -} - -APP_ERROR Resnet50Classify::Init(const InitParam &initParam) -{ - deviceId_ = initParam.deviceId; - APP_ERROR ret = MxBase::DeviceManager::GetInstance()->InitDevices(); - if (ret != APP_ERR_OK) { - LogError << "Init devices failed, ret=" << ret << "."; - return ret; - } - ret = MxBase::TensorContext::GetInstance()->SetContext(initParam.deviceId); - if (ret != APP_ERR_OK) { - LogError << "Set context failed, ret=" << ret << "."; - return ret; - } - dvppWrapper_ = std::make_shared(); - ret = dvppWrapper_->Init(); - if (ret != APP_ERR_OK) { - LogError << "DvppWrapper init failed, ret=" << ret << "."; - return ret; - } - model_ = std::make_shared(); - ret = model_->Init(initParam.modelPath, modelDesc_); - if (ret != APP_ERR_OK) { - LogError << "ModelInferenceProcessor init failed, ret=" << ret << "."; - return ret; - } - MxBase::ConfigData configData; - const std::string softmax = initParam.softmax ? "true" : "false"; - const std::string checkTensor = initParam.checkTensor ? "true" : "false"; - - configData.SetJsonValue("CLASS_NUM", std::to_string(initParam.classNum)); - configData.SetJsonValue("TOP_K", std::to_string(initParam.topk)); - configData.SetJsonValue("SOFTMAX", softmax); - configData.SetJsonValue("CHECK_MODEL", checkTensor); - - auto jsonStr = configData.GetCfgJson().serialize(); - std::map> config; - config["postProcessConfigContent"] = std::make_shared(jsonStr); - config["labelPath"] = std::make_shared(initParam.labelPath); - - post_ = std::make_shared(); - ret = post_->Init(config); - if (ret != APP_ERR_OK) { - LogError << "Resnet50PostProcess init failed, ret=" << ret << "."; - return ret; - } - return APP_ERR_OK; -} - -APP_ERROR Resnet50Classify::DeInit() -{ - dvppWrapper_->DeInit(); - model_->DeInit(); - post_->DeInit(); - MxBase::DeviceManager::GetInstance()->DestroyDevices(); - return APP_ERR_OK; -} - -APP_ERROR Resnet50Classify::ReadImage(const std::string &imgPath, cv::Mat &imageMat) -{ - imageMat = cv::imread(imgPath, cv::IMREAD_COLOR); - return APP_ERR_OK; -} - -APP_ERROR Resnet50Classify::CenterCropImage(cv::Mat &img, cv::Mat &cropImg) -{ - float central_fraction = 0.75; - int crop_x = img.cols * central_fraction; - int crop_y = img.rows * central_fraction; - int crop_x1 = (img.cols - crop_x) / 2; - int crop_y1 = (img.rows - crop_y) / 2; - - cv::Rect myROI(crop_x1, crop_y1, crop_x, crop_y); - LogInfo << "images crop_x1: " << crop_x1 << ", crop_x: " << crop_x << ", crop_y1: " << crop_y1 << ", crop_y: " << crop_y; - cropImg = img(myROI); - return APP_ERR_OK; -} - -APP_ERROR Resnet50Classify::Resize(const cv::Mat &srcImageMat, cv::Mat &dstImageMat) -{ - static constexpr uint32_t resizeHeight = 256; - static constexpr uint32_t resizeWidth = 256; - - cv::resize(srcImageMat, dstImageMat, cv::Size(resizeWidth, resizeHeight)); - return APP_ERR_OK; -} - -APP_ERROR Resnet50Classify::CVMatToTensorBase(const cv::Mat &imageMat, MxBase::TensorBase &tensorBase) -{ - const uint32_t dataSize = imageMat.cols * imageMat.rows * YUV444_RGB_WIDTH_NU; - MemoryData memoryDataDst(dataSize, MemoryData::MEMORY_DEVICE, deviceId_); - MemoryData memoryDataSrc(imageMat.data, dataSize, MemoryData::MEMORY_HOST_MALLOC); - - APP_ERROR ret = MemoryHelper::MxbsMallocAndCopy(memoryDataDst, memoryDataSrc); - if (ret != APP_ERR_OK) { - LogError << GetError(ret) << "Memory malloc failed."; - return ret; - } - std::vector shape = {imageMat.rows * YUV444_RGB_WIDTH_NU, static_cast(imageMat.cols)}; - tensorBase = TensorBase(memoryDataDst, false, shape, TENSOR_DTYPE_UINT8); - return APP_ERR_OK; -} - -APP_ERROR Resnet50Classify::Inference(const std::vector &inputs, - std::vector &outputs) -{ - auto dtypes = model_->GetOutputDataType(); - for (size_t i = 0; i < modelDesc_.outputTensors.size(); ++i) { - std::vector shape = {}; - for (size_t j = 0; j < modelDesc_.outputTensors[i].tensorDims.size(); ++j) { - shape.push_back((uint32_t)modelDesc_.outputTensors[i].tensorDims[j]); - } - TensorBase tensor(shape, dtypes[i], MemoryData::MemoryType::MEMORY_DEVICE, deviceId_); - APP_ERROR ret = TensorBase::TensorBaseMalloc(tensor); - if (ret != APP_ERR_OK) { - LogError << "TensorBaseMalloc failed, ret=" << ret << "."; - return ret; - } - outputs.push_back(tensor); - } - DynamicInfo dynamicInfo = {}; - dynamicInfo.dynamicType = DynamicType::STATIC_BATCH; - auto startTime = std::chrono::high_resolution_clock::now(); - APP_ERROR ret = model_->ModelInference(inputs, outputs, dynamicInfo); - auto endTime = std::chrono::high_resolution_clock::now(); - double costMs = std::chrono::duration(endTime - startTime).count(); - g_inferCost.push_back(costMs); - if (ret != APP_ERR_OK) { - LogError << "ModelInference failed, ret=" << ret << "."; - return ret; - } - return APP_ERR_OK; -} - -APP_ERROR Resnet50Classify::PostProcess(const std::vector &inputs, - std::vector> &clsInfos) -{ - APP_ERROR ret = post_->Process(inputs, clsInfos); - if (ret != APP_ERR_OK) { - LogError << "Process failed, ret=" << ret << "."; - return ret; - } - return APP_ERR_OK; -} - -APP_ERROR Resnet50Classify::SaveInferResult(const std::string &imagePath, std::vector> &batchClsInfos) -{ - uint32_t batchIndex = 0; - LogInfo << "image path: " << imagePath; - std::string fileName = imagePath.substr(imagePath.find_last_of("/") + 1); - size_t dot = fileName.find_last_of("."); - - std::string resultPathName = "result"; - if (access(resultPathName.c_str(), 0) != 0) { - APP_ERROR ret = mkdir(resultPathName.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); - if (ret != 0) { - LogError << "Failed to create result directory: " << resultPathName << ", ret = " << ret; - return APP_ERR_COMM_FAILURE; - } - } - std::string resFileName = "result/" + fileName.substr(0,dot) + "_1.txt"; - LogInfo << "file path for saving result: " << resFileName; - std::ofstream tfile(resFileName); - if (tfile.fail()) { - LogError << "Failed to open result file"; - return APP_ERR_COMM_FAILURE; - } - - for (auto clsInfos : batchClsInfos) { - std::string resultStr = ""; - for (auto clsInfo : clsInfos) { - LogDebug << "batchIndex: " << batchIndex << " className: " << clsInfo.className - << " confidence: " << clsInfo.confidence << " classIndex: " << clsInfo.classId; - resultStr += std::to_string(clsInfo.classId) + " "; - } - tfile << resultStr << std::endl; - batchIndex += 1; - } - tfile.close(); - return APP_ERR_OK; -} - -APP_ERROR Resnet50Classify::Process(const std::string &imgPath) -{ - cv::Mat imageMat; - APP_ERROR ret = ReadImage(imgPath, imageMat); - if (ret != APP_ERR_OK) { - LogError << "ReadImage failed, ret=" << ret << "."; - return ret; - } - - ret = CenterCropImage(imageMat, imageMat); - if (ret != APP_ERR_OK) { - LogError << "crop failed, ret=" << ret << "."; - return ret; - } - ret = Resize(imageMat, imageMat); - if (ret != APP_ERR_OK) { - LogError << "Resize failed, ret=" << ret << "."; - return ret; - } - - std::vector inputs = {}; - std::vector outputs = {}; - TensorBase tensorBase; - ret = CVMatToTensorBase(imageMat, tensorBase); - if (ret != APP_ERR_OK) { - LogError << "CVMatToTensorBase failed, ret=" << ret << "."; - return ret; - } - inputs.push_back(tensorBase); - ret = Inference(inputs, outputs); - if (ret != APP_ERR_OK) { - LogError << "Inference failed, ret=" << ret << "."; - return ret; - } - - std::vector> BatchClsInfos = {}; - ret = PostProcess(outputs, BatchClsInfos); - if (ret != APP_ERR_OK) { - LogError << "PostProcess failed, ret=" << ret << "."; - return ret; - } - - ret = SaveInferResult(imgPath, BatchClsInfos); - if (ret != APP_ERR_OK) { - LogError << "Save results failed, ret: " << ret << "."; - return ret; - } - - imageMat.release(); - return APP_ERR_OK; +/* + * Copyright (c) 2021. Huawei Technologies Co., Ltd. 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. + */ + +#include +#include +#include "Resnet50Classify.h" +#include "MxBase/DeviceManager/DeviceManager.h" +#include "MxBase/Log/Log.h" + +using namespace MxBase; +namespace { +const uint32_t YUV_BYTE_NU = 3; +const uint32_t YUV_BYTE_DE = 2; +const uint32_t VPC_H_ALIGN = 2; +} + +APP_ERROR Resnet50Classify::Init(const InitParam &initParam) +{ + deviceId_ = initParam.deviceId; + APP_ERROR ret = MxBase::DeviceManager::GetInstance()->InitDevices(); + if (ret != APP_ERR_OK) { + LogError << "Init devices failed, ret=" << ret << "."; + return ret; + } + ret = MxBase::TensorContext::GetInstance()->SetContext(initParam.deviceId); + if (ret != APP_ERR_OK) { + LogError << "Set context failed, ret=" << ret << "."; + return ret; + } + dvppWrapper_ = std::make_shared(); + ret = dvppWrapper_->Init(); + if (ret != APP_ERR_OK) { + LogError << "DvppWrapper init failed, ret=" << ret << "."; + return ret; + } + model_ = std::make_shared(); + ret = model_->Init(initParam.modelPath, modelDesc_); + if (ret != APP_ERR_OK) { + LogError << "ModelInferenceProcessor init failed, ret=" << ret << "."; + return ret; + } + MxBase::ConfigData configData; + const std::string softmax = initParam.softmax ? "true" : "false"; + const std::string checkTensor = initParam.checkTensor ? "true" : "false"; + + configData.SetJsonValue("CLASS_NUM", std::to_string(initParam.classNum)); + configData.SetJsonValue("TOP_K", std::to_string(initParam.topk)); + configData.SetJsonValue("SOFTMAX", softmax); + configData.SetJsonValue("CHECK_MODEL", checkTensor); + + auto jsonStr = configData.GetCfgJson().serialize(); + std::map> config; + config["postProcessConfigContent"] = std::make_shared(jsonStr); + config["labelPath"] = std::make_shared(initParam.labelPath); + + post_ = std::make_shared(); + ret = post_->Init(config); + if (ret != APP_ERR_OK) { + LogError << "Resnet50PostProcess init failed, ret=" << ret << "."; + return ret; + } + return APP_ERR_OK; +} + +APP_ERROR Resnet50Classify::DeInit() +{ + dvppWrapper_->DeInit(); + model_->DeInit(); + post_->DeInit(); + MxBase::DeviceManager::GetInstance()->DestroyDevices(); + return APP_ERR_OK; +} + +APP_ERROR Resnet50Classify::ReadImage(const std::string &imgPath, cv::Mat &imageMat) +{ + imageMat = cv::imread(imgPath, cv::IMREAD_COLOR); + return APP_ERR_OK; +} + +APP_ERROR Resnet50Classify::CenterCropImage(cv::Mat &img, cv::Mat &cropImg) +{ + float central_fraction = 0.75; + int crop_x = img.cols * central_fraction; + int crop_y = img.rows * central_fraction; + int crop_x1 = (img.cols - crop_x) / 2; + int crop_y1 = (img.rows - crop_y) / 2; + + cv::Rect myROI(crop_x1, crop_y1, crop_x, crop_y); + LogInfo << "images crop_x1: " << crop_x1 << ", crop_x: " << crop_x << ", crop_y1: " << crop_y1 << ", crop_y: " << crop_y; + cropImg = img(myROI); + return APP_ERR_OK; +} + +APP_ERROR Resnet50Classify::Resize(const cv::Mat &srcImageMat, cv::Mat &dstImageMat) +{ + static constexpr uint32_t resizeHeight = 256; + static constexpr uint32_t resizeWidth = 256; + + cv::resize(srcImageMat, dstImageMat, cv::Size(resizeWidth, resizeHeight)); + return APP_ERR_OK; +} + +APP_ERROR Resnet50Classify::CVMatToTensorBase(const cv::Mat &imageMat, MxBase::TensorBase &tensorBase) +{ + const uint32_t dataSize = imageMat.cols * imageMat.rows * YUV444_RGB_WIDTH_NU; + MemoryData memoryDataDst(dataSize, MemoryData::MEMORY_DEVICE, deviceId_); + MemoryData memoryDataSrc(imageMat.data, dataSize, MemoryData::MEMORY_HOST_MALLOC); + + APP_ERROR ret = MemoryHelper::MxbsMallocAndCopy(memoryDataDst, memoryDataSrc); + if (ret != APP_ERR_OK) { + LogError << GetError(ret) << "Memory malloc failed."; + return ret; + } + std::vector shape = {imageMat.rows * YUV444_RGB_WIDTH_NU, static_cast(imageMat.cols)}; + tensorBase = TensorBase(memoryDataDst, false, shape, TENSOR_DTYPE_UINT8); + return APP_ERR_OK; +} + +APP_ERROR Resnet50Classify::Inference(const std::vector &inputs, + std::vector &outputs) +{ + auto dtypes = model_->GetOutputDataType(); + for (size_t i = 0; i < modelDesc_.outputTensors.size(); ++i) { + std::vector shape = {}; + for (size_t j = 0; j < modelDesc_.outputTensors[i].tensorDims.size(); ++j) { + shape.push_back((uint32_t)modelDesc_.outputTensors[i].tensorDims[j]); + } + TensorBase tensor(shape, dtypes[i], MemoryData::MemoryType::MEMORY_DEVICE, deviceId_); + APP_ERROR ret = TensorBase::TensorBaseMalloc(tensor); + if (ret != APP_ERR_OK) { + LogError << "TensorBaseMalloc failed, ret=" << ret << "."; + return ret; + } + outputs.push_back(tensor); + } + DynamicInfo dynamicInfo = {}; + dynamicInfo.dynamicType = DynamicType::STATIC_BATCH; + auto startTime = std::chrono::high_resolution_clock::now(); + APP_ERROR ret = model_->ModelInference(inputs, outputs, dynamicInfo); + auto endTime = std::chrono::high_resolution_clock::now(); + double costMs = std::chrono::duration(endTime - startTime).count(); + g_inferCost.push_back(costMs); + if (ret != APP_ERR_OK) { + LogError << "ModelInference failed, ret=" << ret << "."; + return ret; + } + return APP_ERR_OK; +} + +APP_ERROR Resnet50Classify::PostProcess(const std::vector &inputs, + std::vector> &clsInfos) +{ + APP_ERROR ret = post_->Process(inputs, clsInfos); + if (ret != APP_ERR_OK) { + LogError << "Process failed, ret=" << ret << "."; + return ret; + } + return APP_ERR_OK; +} + +APP_ERROR Resnet50Classify::SaveInferResult(const std::string &imagePath, std::vector> &batchClsInfos) +{ + uint32_t batchIndex = 0; + LogInfo << "image path: " << imagePath; + std::string fileName = imagePath.substr(imagePath.find_last_of("/") + 1); + size_t dot = fileName.find_last_of("."); + + std::string resultPathName = "result"; + if (access(resultPathName.c_str(), 0) != 0) { + APP_ERROR ret = mkdir(resultPathName.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); + if (ret != 0) { + LogError << "Failed to create result directory: " << resultPathName << ", ret = " << ret; + return APP_ERR_COMM_FAILURE; + } + } + std::string resFileName = "result/" + fileName.substr(0,dot) + "_1.txt"; + LogInfo << "file path for saving result: " << resFileName; + std::ofstream tfile(resFileName); + if (tfile.fail()) { + LogError << "Failed to open result file"; + return APP_ERR_COMM_FAILURE; + } + + for (auto clsInfos : batchClsInfos) { + std::string resultStr = ""; + for (auto clsInfo : clsInfos) { + LogDebug << "batchIndex: " << batchIndex << " className: " << clsInfo.className + << " confidence: " << clsInfo.confidence << " classIndex: " << clsInfo.classId; + resultStr += std::to_string(clsInfo.classId) + " "; + } + tfile << resultStr << std::endl; + batchIndex += 1; + } + tfile.close(); + return APP_ERR_OK; +} + +APP_ERROR Resnet50Classify::Process(const std::string &imgPath) +{ + cv::Mat imageMat; + APP_ERROR ret = ReadImage(imgPath, imageMat); + if (ret != APP_ERR_OK) { + LogError << "ReadImage failed, ret=" << ret << "."; + return ret; + } + + ret = CenterCropImage(imageMat, imageMat); + if (ret != APP_ERR_OK) { + LogError << "crop failed, ret=" << ret << "."; + return ret; + } + ret = Resize(imageMat, imageMat); + if (ret != APP_ERR_OK) { + LogError << "Resize failed, ret=" << ret << "."; + return ret; + } + + std::vector inputs = {}; + std::vector outputs = {}; + TensorBase tensorBase; + ret = CVMatToTensorBase(imageMat, tensorBase); + if (ret != APP_ERR_OK) { + LogError << "CVMatToTensorBase failed, ret=" << ret << "."; + return ret; + } + inputs.push_back(tensorBase); + ret = Inference(inputs, outputs); + if (ret != APP_ERR_OK) { + LogError << "Inference failed, ret=" << ret << "."; + return ret; + } + + std::vector> BatchClsInfos = {}; + ret = PostProcess(outputs, BatchClsInfos); + if (ret != APP_ERR_OK) { + LogError << "PostProcess failed, ret=" << ret << "."; + return ret; + } + + ret = SaveInferResult(imgPath, BatchClsInfos); + if (ret != APP_ERR_OK) { + LogError << "Save results failed, ret: " << ret << "."; + return ret; + } + + imageMat.release(); + return APP_ERR_OK; } \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/Resnet50Classify.h b/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/Resnet50Classify.h index 02f3b59774..7d2ec48a2a 100644 --- a/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/Resnet50Classify.h +++ b/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/Resnet50Classify.h @@ -1,59 +1,59 @@ -/* - * Copyright (c) 2021. Huawei Technologies Co., Ltd. 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. - */ - -#ifndef RESNET50_CLASSIFY_H -#define RESNET50_CLASSIFY_H - -#include -#include "MxBase/DvppWrapper/DvppWrapper.h" -#include "MxBase/ModelInfer/ModelInferenceProcessor.h" -#include "ClassPostProcessors/Resnet50PostProcess.h" -#include "MxBase/Tensor/TensorContext/TensorContext.h" - -extern std::vector g_inferCost; - -struct InitParam { - uint32_t deviceId; - std::string labelPath; - uint32_t classNum; - uint32_t topk; - bool softmax; - bool checkTensor; - std::string modelPath; -}; - -class Resnet50Classify { -public: - APP_ERROR Init(const InitParam &initParam); - APP_ERROR DeInit(); - APP_ERROR ReadImage(const std::string &imgPath, cv::Mat &imageMat); - APP_ERROR Resize(const cv::Mat &srcImageMat, cv::Mat &dstImageMat); - APP_ERROR CenterCropImage(cv::Mat &img, cv::Mat &cropImg); - APP_ERROR CVMatToTensorBase(const cv::Mat &imageMat, MxBase::TensorBase &tensorBase); - APP_ERROR Inference(const std::vector &inputs, std::vector &outputs); - APP_ERROR PostProcess(const std::vector &inputs, - std::vector> &clsInfos); - APP_ERROR SaveInferResult(const std::string &imgPath, - std::vector> &batchClsInfos); - APP_ERROR Process(const std::string &imgPath); -private: - std::shared_ptr dvppWrapper_; - std::shared_ptr model_; - std::shared_ptr post_; - MxBase::ModelDesc modelDesc_; - uint32_t deviceId_ = 0; -}; +/* + * Copyright (c) 2021. Huawei Technologies Co., Ltd. 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. + */ + +#ifndef RESNET50_CLASSIFY_H +#define RESNET50_CLASSIFY_H + +#include +#include "MxBase/DvppWrapper/DvppWrapper.h" +#include "MxBase/ModelInfer/ModelInferenceProcessor.h" +#include "ClassPostProcessors/Resnet50PostProcess.h" +#include "MxBase/Tensor/TensorContext/TensorContext.h" + +extern std::vector g_inferCost; + +struct InitParam { + uint32_t deviceId; + std::string labelPath; + uint32_t classNum; + uint32_t topk; + bool softmax; + bool checkTensor; + std::string modelPath; +}; + +class Resnet50Classify { +public: + APP_ERROR Init(const InitParam &initParam); + APP_ERROR DeInit(); + APP_ERROR ReadImage(const std::string &imgPath, cv::Mat &imageMat); + APP_ERROR Resize(const cv::Mat &srcImageMat, cv::Mat &dstImageMat); + APP_ERROR CenterCropImage(cv::Mat &img, cv::Mat &cropImg); + APP_ERROR CVMatToTensorBase(const cv::Mat &imageMat, MxBase::TensorBase &tensorBase); + APP_ERROR Inference(const std::vector &inputs, std::vector &outputs); + APP_ERROR PostProcess(const std::vector &inputs, + std::vector> &clsInfos); + APP_ERROR SaveInferResult(const std::string &imgPath, + std::vector> &batchClsInfos); + APP_ERROR Process(const std::string &imgPath); +private: + std::shared_ptr dvppWrapper_; + std::shared_ptr model_; + std::shared_ptr post_; + MxBase::ModelDesc modelDesc_; + uint32_t deviceId_ = 0; +}; #endif \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/classification_task_metric.py b/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/classification_task_metric.py index da35817a4d..faa5f9d31c 100644 --- a/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/classification_task_metric.py +++ b/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/classification_task_metric.py @@ -1,174 +1,174 @@ -#coding = utf-8 -#Copyright 2020 Huawei Technologies Co., Ltd -# -#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 os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - """ - :param img_name:image file name contains file path - :return:image file name without file path - """ - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param gtfile_path: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param gtfile_path: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - img_name = temp[0].split(".")[0] - img_lab = temp[1] - img_gt_dict[img_name] = img_lab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - :param filepath: the result of model predict - :return probabilities, number of label, in_type, color: - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, cls_ind in enumerate(temp): - if cls_ind: - data_vec[ind] = np.int(cls_ind) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, n_labels, topn=5): - """ - :param prediction_file_path: the result of model predict - :param result_store_path: the root path to store result - :param json_file: json file to save result - :param img_gt_dict: the ground truth of imagenet - :param topn: classify model acc topk - :return:NA - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - res_cnt = 0 - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - gt = img_gt_dict[img_name] - real_label = int(gt) - res_cnt = min(len(prediction), topn) - for i in range(res_cnt): - if str(real_label) == str(int(prediction[i])): - count_hit[i] += 1 - break - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - - for i in range(res_cnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - print(table_dict) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Please enter right number of argmuments, expected 4!") - exit(1) - # class number - n_labels = 1000 - if not os.path.exists(folder_davinci_target): - print("target file folder does not exist.") - - if not os.path.exists(annotation_file_path): - print("Ground truth file does not exist.") - - if not os.path.exists(result_json_path): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, n_labels, topn=5) - - elapsed = time.time() - start +#coding = utf-8 +#Copyright 2020 Huawei Technologies Co., Ltd +# +#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 os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + """ + :param img_name:image file name contains file path + :return:image file name without file path + """ + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param gtfile_path: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param gtfile_path: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + img_name = temp[0].split(".")[0] + img_lab = temp[1] + img_gt_dict[img_name] = img_lab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + :param filepath: the result of model predict + :return probabilities, number of label, in_type, color: + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, cls_ind in enumerate(temp): + if cls_ind: + data_vec[ind] = np.int(cls_ind) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, n_labels, topn=5): + """ + :param prediction_file_path: the result of model predict + :param result_store_path: the root path to store result + :param json_file: json file to save result + :param img_gt_dict: the ground truth of imagenet + :param topn: classify model acc topk + :return:NA + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + res_cnt = 0 + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + gt = img_gt_dict[img_name] + real_label = int(gt) + res_cnt = min(len(prediction), topn) + for i in range(res_cnt): + if str(real_label) == str(int(prediction[i])): + count_hit[i] += 1 + break + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + + for i in range(res_cnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + print(table_dict) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Please enter right number of argmuments, expected 4!") + exit(1) + # class number + n_labels = 1000 + if not os.path.exists(folder_davinci_target): + print("target file folder does not exist.") + + if not os.path.exists(annotation_file_path): + print("Ground truth file does not exist.") + + if not os.path.exists(result_json_path): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, n_labels, topn=5) + + elapsed = time.time() - start diff --git a/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/main.cpp b/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/main.cpp index 137e934b96..1235200904 100644 --- a/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/main.cpp +++ b/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/mxbase/main.cpp @@ -1,69 +1,69 @@ -/* - * Copyright (c) 2021. Huawei Technologies Co., Ltd. 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. - */ - -#include -#include -#include -#include "Resnet50Classify.h" -#include "MxBase/Log/Log.h" - -namespace fs = std::experimental::filesystem; -namespace { -const uint32_t CLASS_NUM = 1000; -} -std::vector g_inferCost; - -int main(int argc, char* argv[]) -{ - if (argc <= 1) { - LogWarn << "Please input image path, such as './val_union/'."; - return APP_ERR_OK; - } - - InitParam initParam = {}; - initParam.deviceId = 0; - initParam.classNum = CLASS_NUM; - initParam.labelPath = "../models/imagenet1000_clsidx_to_labels.names"; - initParam.topk = 5; - initParam.softmax = true; - initParam.checkTensor = true; - initParam.modelPath = "../models/resnet50_pytorch.om"; - auto resnet50 = std::make_shared(); - APP_ERROR ret = resnet50->Init(initParam); - if (ret != APP_ERR_OK) { - LogError << "Resnet50Classify init failed, ret=" << ret << "."; - return ret; - } - - std::string imgDir = argv[1]; - for (auto & entry : fs::directory_iterator(imgDir)) { - LogInfo << "read image path " << entry.path(); - ret = resnet50->Process(entry.path()); - if (ret != APP_ERR_OK) { - LogError << "Resnet50Classify process failed, ret=" << ret << "."; - resnet50->DeInit(); - return ret; - } - } - resnet50->DeInit(); - double costSum = 0; - for (unsigned int i = 0; i < g_inferCost.size(); i++) { - costSum += g_inferCost[i]; - } - LogInfo << "Infer images sum " << g_inferCost.size() << ", cost total time: " << costSum << " ms."; - LogInfo << "The throughput: " << g_inferCost.size() * 1000 / costSum << " images/sec."; - return APP_ERR_OK; +/* + * Copyright (c) 2021. Huawei Technologies Co., Ltd. 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. + */ + +#include +#include +#include +#include "Resnet50Classify.h" +#include "MxBase/Log/Log.h" + +namespace fs = std::experimental::filesystem; +namespace { +const uint32_t CLASS_NUM = 1000; +} +std::vector g_inferCost; + +int main(int argc, char* argv[]) +{ + if (argc <= 1) { + LogWarn << "Please input image path, such as './val_union/'."; + return APP_ERR_OK; + } + + InitParam initParam = {}; + initParam.deviceId = 0; + initParam.classNum = CLASS_NUM; + initParam.labelPath = "../models/imagenet1000_clsidx_to_labels.names"; + initParam.topk = 5; + initParam.softmax = true; + initParam.checkTensor = true; + initParam.modelPath = "../models/resnet50_pytorch.om"; + auto resnet50 = std::make_shared(); + APP_ERROR ret = resnet50->Init(initParam); + if (ret != APP_ERR_OK) { + LogError << "Resnet50Classify init failed, ret=" << ret << "."; + return ret; + } + + std::string imgDir = argv[1]; + for (auto & entry : fs::directory_iterator(imgDir)) { + LogInfo << "read image path " << entry.path(); + ret = resnet50->Process(entry.path()); + if (ret != APP_ERR_OK) { + LogError << "Resnet50Classify process failed, ret=" << ret << "."; + resnet50->DeInit(); + return ret; + } + } + resnet50->DeInit(); + double costSum = 0; + for (unsigned int i = 0; i < g_inferCost.size(); i++) { + costSum += g_inferCost[i]; + } + LogInfo << "Infer images sum " << g_inferCost.size() << ", cost total time: " << costSum << " ms."; + LogInfo << "The throughput: " << g_inferCost.size() * 1000 / costSum << " images/sec."; + return APP_ERR_OK; } \ No newline at end of file diff --git a/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/sdk/classification_task_metric.py b/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/sdk/classification_task_metric.py index 2d383ae6cf..dc6d0328e0 100644 --- a/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/sdk/classification_task_metric.py +++ b/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/infer/sdk/classification_task_metric.py @@ -1,175 +1,175 @@ -#coding = utf-8 -#Copyright 2020 Huawei Technologies Co., Ltd -# -#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 os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - """ - :param: file path - :return: filename - """ - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - img_name = temp[0].split(".")[0] - img_lab = temp[1] - img_gt_dict[img_name] = img_lab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - :param filepath: the result of model predict - :return probabilities, number of label, in_type, color: - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, cls_ind in enumerate(temp): - if cls_ind: - data_vec[ind] = np.int(cls_ind) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, n_labels, topn=5): - """ - :param prediction_file_path: the result of model predict - :param result_store_path: the root path to store result - :param json_file: json file to save result - :param img_gt_dict: the ground truth of imagenet - :param topn: classify model acc topk - :param n_labels: class numbers - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - res_cnt = 0 - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - - ret = load_statistical_predict_result(filepath) - prediction = ret[0] - gt = img_gt_dict[img_name] - real_label = int(gt) - res_cnt = min(len(prediction), topn) - for i in range(res_cnt): - if str(real_label) == str(int(prediction[i])): - count_hit[i] += 1 - break - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - - for i in range(res_cnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - print(table_dict) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Please enter right number of argmuments, expected 4!") - exit(1) - # class number - n_labels = 1000 - if not os.path.exists(folder_davinci_target): - print("target file folder does not exist.") - - if not os.path.exists(annotation_file_path): - print("Ground truth file does not exist.") - - if not os.path.exists(result_json_path): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, n_labels, topn=5) - - elapsed = time.time() - start +#coding = utf-8 +#Copyright 2020 Huawei Technologies Co., Ltd +# +#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 os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + """ + :param: file path + :return: filename + """ + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + img_name = temp[0].split(".")[0] + img_lab = temp[1] + img_gt_dict[img_name] = img_lab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + :param filepath: the result of model predict + :return probabilities, number of label, in_type, color: + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, cls_ind in enumerate(temp): + if cls_ind: + data_vec[ind] = np.int(cls_ind) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, n_labels, topn=5): + """ + :param prediction_file_path: the result of model predict + :param result_store_path: the root path to store result + :param json_file: json file to save result + :param img_gt_dict: the ground truth of imagenet + :param topn: classify model acc topk + :param n_labels: class numbers + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + res_cnt = 0 + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + + ret = load_statistical_predict_result(filepath) + prediction = ret[0] + gt = img_gt_dict[img_name] + real_label = int(gt) + res_cnt = min(len(prediction), topn) + for i in range(res_cnt): + if str(real_label) == str(int(prediction[i])): + count_hit[i] += 1 + break + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + + for i in range(res_cnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + print(table_dict) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Please enter right number of argmuments, expected 4!") + exit(1) + # class number + n_labels = 1000 + if not os.path.exists(folder_davinci_target): + print("target file folder does not exist.") + + if not os.path.exists(annotation_file_path): + print("Ground truth file does not exist.") + + if not os.path.exists(result_json_path): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, n_labels, topn=5) + + elapsed = time.time() - start diff --git a/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/modelarts/train_start.py b/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/modelarts/train_start.py index 89e41a2e40..af51db50ad 100644 --- a/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/modelarts/train_start.py +++ b/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch/modelarts/train_start.py @@ -1,688 +1,688 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 argparse -import os -import glob -import random -import shutil -import sys -import time -import warnings -import math -import numpy as np - -import torch -import torch.nn as nn -import torch.nn.parallel -import torch.backends.cudnn as cudnn -import torch.distributed as dist -import torch.optim -import torch.multiprocessing as mp -import torch.utils.data -import torch.utils.data.distributed -import torchvision.transforms as transforms -import torchvision.datasets as datasets -import torchvision.models as models -import torch.npu - -sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '../')) -from pthtar2onx import convert -import DistributedResnet50.image_classification.resnet as nvmodels -from apex import amp -import moxing as mox - -BATCH_SIZE = 512 -EPOCHS_SIZE = 100 -TRAIN_STEP = 8000 -LOG_STEP = 1 - -CALCULATE_DEVICE = "npu:7" -PRINT_DEVICE = "cpu" -SOURCE_DIR = "/data/imagenet" - -model_names = sorted(name for name in models.__dict__ - if name.islower() and not name.startswith("__") - and callable(models.__dict__[name])) - -parser = argparse.ArgumentParser(description='PyTorch ImageNet Training') -parser.add_argument('--data_url', - metavar='DIR', - default='/cache/data_url', - help='path to dataset') -parser.add_argument('-a', '--arch', - metavar='ARCH', - default='resnet50', - choices=model_names, - help='model architecture: ' + - ' | '.join(model_names) + - ' (default: resnet18)') -parser.add_argument('-j', '--workers', - default=32, - type=int, - metavar='N', - help='number of data loading workers (default: 8)') -parser.add_argument('--epochs', - default=1, - type=int, - metavar='N', - help='number of total epochs to run') -parser.add_argument('--start-epoch', - default=0, - type=int, - metavar='N', - help='manual epoch number (useful on restarts)') -parser.add_argument('-b', '--batch-size', - default=BATCH_SIZE, - type=int, - metavar='N', - help='mini-batch size (default: 256), this is the total ' - 'batch size of all GPUs on the current node when ' - 'using Data Parallel or Distributed Data Parallel') -parser.add_argument('--lr', '--learning-rate', - default=0.2, - type=float, - metavar='LR', - help='initial learning rate', - dest='lr') -parser.add_argument('--momentum', - default=0.9, - type=float, - metavar='M', - help='momentum') -parser.add_argument('--wd', '--weight-decay', - default=1e-4, - type=float, - metavar='W', - help='weight decay (default: 1e-4)', - dest='weight_decay') -parser.add_argument('-p', '--print-freq', - default=10, - type=int, - metavar='N', - help='print frequency (default: 10)') -parser.add_argument('--resume', - default='', - type=str, - metavar='PATH', - help='path to latest checkpoint (default: none)') -parser.add_argument('-e', '--evaluate', - dest='evaluate', - action='store_true', - help='evaluate model on validation set') -parser.add_argument('--pretrained', - dest='pretrained', - action='store_true', - help='use pre-trained model') -parser.add_argument('--world-size', - default=-1, - type=int, - help='number of nodes for distributed training') -parser.add_argument('--rank', - default=-1, - type=int, - help='node rank for distributed training') -parser.add_argument('--dist-url', - default=None, - type=str, - help='url used to set up distributed training') -parser.add_argument('--dist-backend', - default='nccl', - type=str, - help='distributed backend') -parser.add_argument('--seed', - default=None, - type=int, - help='seed for initializing training. ') -parser.add_argument('--gpu', - default=None, - type=int, - help='GPU id to use.') -parser.add_argument('--npu', - default=None, - type=int, - help='NPU id to use.') -parser.add_argument('--multiprocessing-distributed', - action='store_true') -parser.add_argument('--warmup', - default=5, - type=int, - metavar='E', - help='number of warmup epochs') -parser.add_argument('--label-smoothing', - default=0.1, - type=float, - metavar='S', - help='label smoothing') -parser.add_argument('--optimizer-batch-size', - default=-1, - type=int, - metavar='N', - help= - 'size of a total batch size, for simulating bigger batches using gradient accumulation') -parser.add_argument('--static-loss-scale', - type=float, - default=1, - help= - 'Static loss scale, positive power of 2 values can improve fp16 convergence.') - -parser.add_argument('-t', '--fine-tuning', default=False, action='store_true', - help='transfer learning + fine tuning - train only the last FC layer') -parser.add_argument('--train_url', - default="/cache/training", - type=str, - help="setting dir of training output") -parser.add_argument('--pretrained_weight', default='', type=str, metavar='PATH', - help='path to pretrained weight') -parser.add_argument('--onnx', default=True, action='store_true', - help="convert pth model to onnx") - -CACHE_TRAINING_URL = "/cache/training" -best_acc1 = 0 - -def main(): - args = parser.parse_args() - if args.npu is None: - args.npu = 0 - global CALCULATE_DEVICE - CALCULATE_DEVICE = "npu:{}".format(args.npu) - torch.npu.set_device(CALCULATE_DEVICE) - print("use ", CALCULATE_DEVICE) - - if args.seed is not None: - random.seed(args.seed) - torch.manual_seed(args.seed) - cudnn.deterministic = True - warnings.warn('You have chosen to seed training. ' - 'This will turn on the CUDNN deterministic setting, ' - 'which can slow down your training considerably! ' - 'You may see unexpected behavior when restarting ' - 'from checkpoints.') - - if args.gpu is not None: - warnings.warn('You have chosen a specific GPU. This will completely ' - 'disable data parallelism.') - - if args.dist_url == "env://" and args.world_size == -1: - args.world_size = int(os.environ["WORLD_SIZE"]) - - args.distributed = args.world_size > 1 or args.multiprocessing_distributed - - ngpus_per_node = torch.cuda.device_count() - if args.multiprocessing_distributed: - # Since we have ngpus_per_node processes per node, the total world_size - # needs to be adjusted accordingly - args.world_size = ngpus_per_node * args.world_size - # Use torch.multiprocessing.spawn to launch distributed processes: the - # main_worker process function - mp.spawn(main_worker, nprocs=ngpus_per_node, args=(ngpus_per_node, args)) - else: - # Simply call main_worker function - main_worker(args.gpu, ngpus_per_node, args) - -def main_worker(gpu, ngpus_per_node, args): - global best_acc1 - args.gpu = gpu - - if args.gpu is not None: - print("Use GPU: {} for training".format(args.gpu)) - - if args.distributed: - if args.dist_url == "env://" and args.rank == -1: - args.rank = int(os.environ["RANK"]) - if args.multiprocessing_distributed: - # For multiprocessing distributed training, rank needs to be the - # global rank among all the processes - args.rank = args.rank * ngpus_per_node + gpu - dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url, - world_size=args.world_size, rank=args.rank) - # create model - if args.pretrained: - print("=> using pre-trained model '{}'".format(args.arch)) - model = nvmodels.build_resnet('resnet50', 'classic', True) - CACHE_MODEL_URL = "/cache/model" - os.makedirs(CACHE_MODEL_URL, exist_ok=True) - mox.file.copy_parallel(args.pretrained_weight, os.path.join(CACHE_MODEL_URL, "checkpoint.pth.tar")) - pretrained_weight = os.path.join(CACHE_MODEL_URL, "checkpoint.pth.tar") - pretrained_dict = torch.load(pretrained_weight)["state_dict"] - pretrained_dict.pop('module.fc.weight') - pretrained_dict.pop('module.fc.bias') - model.load_state_dict(pretrained_dict, strict=False) - else: - print("=> creating model '{}'".format(args.arch)) - model = models.__dict__[args.arch](zero_init_residual=True) - - if args.fine_tuning: - print("=> transfer-learning mode + fine-tuning (train only the last FC layer)") - # Freeze Previous Layers(now we are using them as features extractor) - # Fine Tuning the last layer for the new task - if args.arch == "resnet50": - model.classifier = nn.Linear(1024, 10) - model.classifier.parameters() - else: - print("Error: Fine-tuning is not supported on this architecture") - exit(-1) - else: - model.parameters() - - for layer in model.modules(): - if isinstance(layer, nn.Linear): - torch.nn.init.kaiming_normal_(layer.weight, a=math.sqrt(5), ) - if args.distributed: - # For multiprocessing distributed, DistributedDataParallel constructor - # should always set the single device scope, otherwise, - # DistributedDataParallel will use all available devices. - if args.gpu is not None: - torch.cuda.set_device(args.gpu) - model.cuda(args.gpu) - # When using a single GPU per process and per - # DistributedDataParallel, we need to divide the batch size - # ourselves based on the total number of GPUs we have - args.batch_size = int(args.batch_size / ngpus_per_node) - args.workers = int((args.workers + ngpus_per_node - 1) / ngpus_per_node) - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu]) - else: - model.cuda() - # DistributedDataParallel will divide and allocate batch_size to all - # available GPUs if device_ids are not set - model = torch.nn.parallel.DistributedDataParallel(model) - elif args.gpu is not None: - torch.cuda.set_device(args.gpu) - model = model.cuda(args.gpu) - else: - # DataParallel will divide and allocate batch_size to all available GPUs - if args.arch.startswith('alexnet') or args.arch.startswith('vgg'): - model.features = torch.nn.DataParallel(model.features) - model.cuda() - else: - model = model.to(CALCULATE_DEVICE) - - lr_policy = lr_cosine_policy(args.lr, - args.warmup, - args.epochs) - - - # define loss function (criterion) and optimizer - loss = nn.CrossEntropyLoss - if args.label_smoothing > 0.0: - loss = lambda: LabelSmoothing(args.label_smoothing) - criterion = loss().to(CALCULATE_DEVICE) - optimizer = torch.optim.SGD([ - {'params': [param for name, param in model.named_parameters() if name[-4:] == 'bias'], 'weight_decay': 0.0}, - {'params': [param for name, param in model.named_parameters() if name[-4:] != 'bias'], 'weight_decay': args.weight_decay}], - args.lr, - momentum=args.momentum) - - model, optimizer = amp.initialize(model, optimizer, opt_level="O2", loss_scale=1024, verbosity=1) - - # optionally resume from a checkpoint - if args.resume: - if os.path.isfile(args.resume): - print("=> loading checkpoint '{}'".format(args.resume)) - if args.npu is not None: - checkpoint = torch.load(args.resume) - elif args.gpu is None: - checkpoint = torch.load(args.resume) - else: - # Map model to be loaded to specified single gpu. - loc = 'cuda:{}'.format(args.gpu) - checkpoint = torch.load(args.resume, map_location=loc) - args.start_epoch = checkpoint['epoch'] - best_acc1 = checkpoint['best_acc1'] - if args.npu is not None: - best_acc1 = best_acc1.to("npu:{}".format(args.npu)) - elif args.gpu is not None: - # best_acc1 may be from a checkpoint from a different GPU - best_acc1 = best_acc1.to(args.gpu) - model.load_state_dict(checkpoint['state_dict']) - print("=> loaded checkpoint '{}' (epoch {})" - .format(args.resume, checkpoint['epoch'])) - else: - print("=> no checkpoint found at '{}'".format(args.resume)) - - cudnn.benchmark = True - - real_path = '/cache/data_url' - if not os.path.exists(real_path): - os.makedirs(real_path) - mox.file.copy_parallel(args.data_url, real_path) - print("training data finish copy to %s." % real_path) - - traindir = os.path.join(real_path, 'train') - valdir = os.path.join(real_path, 'val') - normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], - std=[0.229, 0.224, 0.225]) - - train_dataset = datasets.ImageFolder( - traindir, - transforms.Compose([ - transforms.RandomResizedCrop(224), - transforms.RandomHorizontalFlip(), - transforms.ToTensor(), - normalize, - ])) - - if args.distributed: - train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset) - else: - train_sampler = None - - train_loader = torch.utils.data.DataLoader( - train_dataset, batch_size=args.batch_size, shuffle=(train_sampler is None), - num_workers=args.workers, pin_memory=True, sampler=train_sampler, drop_last=True) - - val_loader = torch.utils.data.DataLoader( - datasets.ImageFolder(valdir, transforms.Compose([ - transforms.Resize(256), - transforms.CenterCrop(224), - transforms.ToTensor(), - normalize, - ])), - batch_size=args.batch_size, shuffle=True, - num_workers=args.workers, pin_memory=True) - - if args.evaluate: - validate(val_loader, model, criterion, args) - return - - for epoch in range(args.start_epoch, args.epochs): - if args.distributed: - train_sampler.set_epoch(epoch) - lr_policy(optimizer, 0, epoch) - # train for one epoch - train(train_loader, model, criterion, optimizer, epoch, args) - - # evaluate on validation set - acc1 = validate(val_loader, model, criterion, args) - - # remember best acc@1 and save checkpoint - is_best = acc1 > best_acc1 - best_acc1 = max(acc1, best_acc1) - file_name = "checkpoint_npu{}".format(args.npu) - modeltmp = model.cpu() - save_checkpoint({ - 'epoch': epoch + 1, - 'arch': args.arch, - 'state_dict': modeltmp.state_dict(), - 'best_acc1': best_acc1, - }, is_best, file_name) - modeltmp.to(CALCULATE_DEVICE) - - if args.onnx: - convert_pth_to_onnx(args) - - # --------------modelarts modification---------- - mox.file.copy_parallel(CACHE_TRAINING_URL, args.train_url) - # --------------modelarts modification end---------- - -def convert_pth_to_onnx(args): - pth_pattern = os.path.join(CACHE_TRAINING_URL, f"checkpoint_npu{args.npu}.pth.tar") - pth_file_list = glob.glob(pth_pattern) - if not pth_file_list: - print(f"can't find pth {pth_pattern}") - return - pth_file = pth_file_list[0] - onnx_path = pth_file.split(".")[0] + '.onnx' - convert(pth_file, onnx_path) - - -def train(train_loader, model, criterion, optimizer, epoch, args): - if args.optimizer_batch_size < 0: - batch_size_multiplier = 1 - else: - tbs = 1 * args.batch_size - if args.optimizer_batch_size % tbs != 0: - print( - "Warning: simulated batch size {} is not divisible by actual batch size {}" - .format(args.optimizer_batch_size, tbs)) - batch_size_multiplier = int(args.optimizer_batch_size / tbs) - print("BSM: {}".format(batch_size_multiplier)) - - batch_time = AverageMeter('Time', ':6.3f') - data_time = AverageMeter('Data', ':6.3f') - losses = AverageMeter('Loss', ':.4e') - top1 = AverageMeter('Acc@1', ':6.2f') - top5 = AverageMeter('Acc@5', ':6.2f') - progress = ProgressMeter( - len(train_loader), - [batch_time, data_time, losses, top1, top5], - prefix="Epoch: [{}]".format(epoch)) - - # switch to train mode - model.train() - optimizer.zero_grad() - end = time.time() - for i, (images, target) in enumerate(train_loader): - # measure data loading time - data_time.update(time.time() - end) - - if args.gpu is not None: - images = images.cuda(args.gpu, non_blocking=True) - - images = images.to(CALCULATE_DEVICE, non_blocking=True) - if args.label_smoothing == 0.0: - target = target.to(torch.int32).to(CALCULATE_DEVICE, non_blocking=True) - - # compute output - output = model(images) - loss = criterion(output, target) - - if args.label_smoothing > 0.0: - target = target.to(torch.int32).to(CALCULATE_DEVICE, non_blocking=True) - - # measure accuracy and record loss - acc1, acc5 = accuracy(output, target, topk=(1, 5)) - losses.update(loss.item(), images.size(0)) - top1.update(acc1[0], images.size(0)) - top5.update(acc5[0], images.size(0)) - - # compute gradient and do SGD step - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - optimizer_step = ((i + 1) % batch_size_multiplier) == 0 - if optimizer_step: - if batch_size_multiplier != 1: - for param_group in optimizer.param_groups: - for param in param_group['params']: - param.grad /= batch_size_multiplier - optimizer.step() - optimizer.zero_grad() - - # measure elapsed time - batch_time.update(time.time() - end) - end = time.time() - - if i % LOG_STEP == 0: - progress.display(i) - - if i == TRAIN_STEP: - break - - print("batch_size:", args.batch_size, 'Time: {:.3f}'.format(batch_time.avg), '* FPS@all {:.3f}'.format( - args.batch_size/(batch_time.avg+0.0001))) - -def validate(val_loader, model, criterion, args): - batch_time = AverageMeter('Time', ':6.3f') - losses = AverageMeter('Loss', ':.4e') - top1 = AverageMeter('Acc@1', ':6.2f') - top5 = AverageMeter('Acc@5', ':6.2f') - progress = ProgressMeter( - len(val_loader), - [batch_time, losses, top1, top5], - prefix='Test: ') - - # switch to evaluate mode - model.eval() - - with torch.no_grad(): - end = time.time() - for i, (images, target) in enumerate(val_loader): - if args.gpu is not None: - images = images.cuda(args.gpu, non_blocking=True) - images = images.to(CALCULATE_DEVICE, non_blocking=True) - if args.label_smoothing == 0.0: - target = target.to(torch.int32).to(CALCULATE_DEVICE, non_blocking=True) - - # compute output - output = model(images) - loss = criterion(output, target) - - if args.label_smoothing > 0.0: - target = target.to(torch.int32).to(CALCULATE_DEVICE, non_blocking=True) - - # measure accuracy and record loss - acc1, acc5 = accuracy(output, target, topk=(1, 5)) - losses.update(loss.item(), images.size(0)) - top1.update(acc1[0], images.size(0)) - top5.update(acc5[0], images.size(0)) - - # measure elapsed time - batch_time.update(time.time() - end) - end = time.time() - - if i % LOG_STEP == 0: - progress.display(i) - - print(' * Acc@1 {top1.avg:.3f} Acc@5 {top5.avg:.3f}' - .format(top1=top1, top5=top5)) - return top1.avg - -def save_checkpoint(state, is_best, filename='checkpoint'): - if not os.path.exists(CACHE_TRAINING_URL): - os.makedirs(CACHE_TRAINING_URL) - - filename2 = os.path.join(CACHE_TRAINING_URL, filename + ".pth.tar") - torch.save(state, filename2) - if is_best: - shutil.copyfile(filename2, os.path.join(CACHE_TRAINING_URL, filename + 'model_best.pth.tar')) - -class AverageMeter(object): - """Computes and stores the average and current value""" - def __init__(self, name, fmt=':f'): - self.name = name - self.fmt = fmt - self.reset() - self.start_count_index = 10 - - def reset(self): - self.val = 0 - self.avg = 0 - self.sum = 0 - self.count = 0 - - def update(self, val, n=1): - if self.count == 0: - self.batchsize = n - - self.val = val - self.count += n - if self.count > (self.start_count_index * self.batchsize): - self.sum += val * n - self.avg = self.sum / (self.count - self.start_count_index * self.batchsize) - - def __str__(self): - fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' - return fmtstr.format(**self.__dict__) - -class ProgressMeter(object): - def __init__(self, num_batches, meters, prefix=""): - self.batch_fmtstr = self._get_batch_fmtstr(num_batches) - self.meters = meters - self.prefix = prefix - - def display(self, batch): - entries = [self.prefix + self.batch_fmtstr.format(batch)] - entries += [str(meter) for meter in self.meters] - print('\t'.join(entries)) - - def _get_batch_fmtstr(self, num_batches): - num_digits = len(str(num_batches // 1)) - fmt = '{:' + str(num_digits) + 'd}' - return '[' + fmt + '/' + fmt.format(num_batches) + ']' - - -def adjust_learning_rate(optimizer, epoch, args): - """Sets the learning rate to the initial LR decayed by 10 every 30 epochs""" - lr = args.lr * (0.1 ** (epoch // 30)) - for param_group in optimizer.param_groups: - param_group['lr'] = lr - - -def accuracy(output, target, topk=(1,)): - """Computes the accuracy over the k top predictions for the specified values of k""" - with torch.no_grad(): - maxk = max(topk) - batch_size = target.size(0) - - _, pred = output.topk(maxk, 1, True, True) - pred = pred.t() - correct = pred.eq(target.view(1, -1).expand_as(pred)) - - res = [] - for k in topk: - correct_k = correct[:k].view(-1).float().sum(0, keepdim=True) - res.append(correct_k.mul_(100.0 / batch_size)) - return res - -class LabelSmoothing(nn.Module): - """ - NLL loss with label smoothing. - """ - def __init__(self, smoothing=0.0): - """ - Constructor for the LabelSmoothing module. - :param smoothing: label smoothing factor - """ - super(LabelSmoothing, self).__init__() - self.confidence = 1.0 - smoothing - self.smoothing = smoothing - - def forward(self, x, target): - logprobs = torch.nn.functional.log_softmax(x, dim=-1).to("cpu") - nll_loss = -logprobs.gather(dim=-1, index=target.unsqueeze(1)) - nll_loss = nll_loss.squeeze(1) - smooth_loss = -logprobs.mean(dim=-1) - loss = self.confidence * nll_loss + self.smoothing * smooth_loss - return loss.mean().to(CALCULATE_DEVICE) - -def lr_policy(lr_fn, logger=None): - if logger is not None: - logger.register_metric('lr', - log.LR_METER(), - verbosity=dllogger.Verbosity.VERBOSE) - - def _alr(optimizer, iteration, epoch): - lr = lr_fn(iteration, epoch) - - if logger is not None: - logger.log_metric('lr', lr) - for param_group in optimizer.param_groups: - param_group['lr'] = lr - - return _alr - -def lr_cosine_policy(base_lr, warmup_length, epochs, logger=None): - def _lr_fn(iteration, epoch): - if epoch < warmup_length: - lr = base_lr * (epoch + 1) / warmup_length - else: - e = epoch - warmup_length - es = epochs - warmup_length - lr = 0.5 * (1 + np.cos(np.pi * e / es)) * base_lr - return lr - - return lr_policy(_lr_fn, logger=logger) - -if __name__ == '__main__': - main() +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 argparse +import os +import glob +import random +import shutil +import sys +import time +import warnings +import math +import numpy as np + +import torch +import torch.nn as nn +import torch.nn.parallel +import torch.backends.cudnn as cudnn +import torch.distributed as dist +import torch.optim +import torch.multiprocessing as mp +import torch.utils.data +import torch.utils.data.distributed +import torchvision.transforms as transforms +import torchvision.datasets as datasets +import torchvision.models as models +import torch.npu + +sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '../')) +from pthtar2onx import convert +import DistributedResnet50.image_classification.resnet as nvmodels +from apex import amp +import moxing as mox + +BATCH_SIZE = 512 +EPOCHS_SIZE = 100 +TRAIN_STEP = 8000 +LOG_STEP = 1 + +CALCULATE_DEVICE = "npu:7" +PRINT_DEVICE = "cpu" +SOURCE_DIR = "/data/imagenet" + +model_names = sorted(name for name in models.__dict__ + if name.islower() and not name.startswith("__") + and callable(models.__dict__[name])) + +parser = argparse.ArgumentParser(description='PyTorch ImageNet Training') +parser.add_argument('--data_url', + metavar='DIR', + default='/cache/data_url', + help='path to dataset') +parser.add_argument('-a', '--arch', + metavar='ARCH', + default='resnet50', + choices=model_names, + help='model architecture: ' + + ' | '.join(model_names) + + ' (default: resnet18)') +parser.add_argument('-j', '--workers', + default=32, + type=int, + metavar='N', + help='number of data loading workers (default: 8)') +parser.add_argument('--epochs', + default=1, + type=int, + metavar='N', + help='number of total epochs to run') +parser.add_argument('--start-epoch', + default=0, + type=int, + metavar='N', + help='manual epoch number (useful on restarts)') +parser.add_argument('-b', '--batch-size', + default=BATCH_SIZE, + type=int, + metavar='N', + help='mini-batch size (default: 256), this is the total ' + 'batch size of all GPUs on the current node when ' + 'using Data Parallel or Distributed Data Parallel') +parser.add_argument('--lr', '--learning-rate', + default=0.2, + type=float, + metavar='LR', + help='initial learning rate', + dest='lr') +parser.add_argument('--momentum', + default=0.9, + type=float, + metavar='M', + help='momentum') +parser.add_argument('--wd', '--weight-decay', + default=1e-4, + type=float, + metavar='W', + help='weight decay (default: 1e-4)', + dest='weight_decay') +parser.add_argument('-p', '--print-freq', + default=10, + type=int, + metavar='N', + help='print frequency (default: 10)') +parser.add_argument('--resume', + default='', + type=str, + metavar='PATH', + help='path to latest checkpoint (default: none)') +parser.add_argument('-e', '--evaluate', + dest='evaluate', + action='store_true', + help='evaluate model on validation set') +parser.add_argument('--pretrained', + dest='pretrained', + action='store_true', + help='use pre-trained model') +parser.add_argument('--world-size', + default=-1, + type=int, + help='number of nodes for distributed training') +parser.add_argument('--rank', + default=-1, + type=int, + help='node rank for distributed training') +parser.add_argument('--dist-url', + default=None, + type=str, + help='url used to set up distributed training') +parser.add_argument('--dist-backend', + default='nccl', + type=str, + help='distributed backend') +parser.add_argument('--seed', + default=None, + type=int, + help='seed for initializing training. ') +parser.add_argument('--gpu', + default=None, + type=int, + help='GPU id to use.') +parser.add_argument('--npu', + default=None, + type=int, + help='NPU id to use.') +parser.add_argument('--multiprocessing-distributed', + action='store_true') +parser.add_argument('--warmup', + default=5, + type=int, + metavar='E', + help='number of warmup epochs') +parser.add_argument('--label-smoothing', + default=0.1, + type=float, + metavar='S', + help='label smoothing') +parser.add_argument('--optimizer-batch-size', + default=-1, + type=int, + metavar='N', + help= + 'size of a total batch size, for simulating bigger batches using gradient accumulation') +parser.add_argument('--static-loss-scale', + type=float, + default=1, + help= + 'Static loss scale, positive power of 2 values can improve fp16 convergence.') + +parser.add_argument('-t', '--fine-tuning', default=False, action='store_true', + help='transfer learning + fine tuning - train only the last FC layer') +parser.add_argument('--train_url', + default="/cache/training", + type=str, + help="setting dir of training output") +parser.add_argument('--pretrained_weight', default='', type=str, metavar='PATH', + help='path to pretrained weight') +parser.add_argument('--onnx', default=True, action='store_true', + help="convert pth model to onnx") + +CACHE_TRAINING_URL = "/cache/training" +best_acc1 = 0 + +def main(): + args = parser.parse_args() + if args.npu is None: + args.npu = 0 + global CALCULATE_DEVICE + CALCULATE_DEVICE = "npu:{}".format(args.npu) + torch.npu.set_device(CALCULATE_DEVICE) + print("use ", CALCULATE_DEVICE) + + if args.seed is not None: + random.seed(args.seed) + torch.manual_seed(args.seed) + cudnn.deterministic = True + warnings.warn('You have chosen to seed training. ' + 'This will turn on the CUDNN deterministic setting, ' + 'which can slow down your training considerably! ' + 'You may see unexpected behavior when restarting ' + 'from checkpoints.') + + if args.gpu is not None: + warnings.warn('You have chosen a specific GPU. This will completely ' + 'disable data parallelism.') + + if args.dist_url == "env://" and args.world_size == -1: + args.world_size = int(os.environ["WORLD_SIZE"]) + + args.distributed = args.world_size > 1 or args.multiprocessing_distributed + + ngpus_per_node = torch.cuda.device_count() + if args.multiprocessing_distributed: + # Since we have ngpus_per_node processes per node, the total world_size + # needs to be adjusted accordingly + args.world_size = ngpus_per_node * args.world_size + # Use torch.multiprocessing.spawn to launch distributed processes: the + # main_worker process function + mp.spawn(main_worker, nprocs=ngpus_per_node, args=(ngpus_per_node, args)) + else: + # Simply call main_worker function + main_worker(args.gpu, ngpus_per_node, args) + +def main_worker(gpu, ngpus_per_node, args): + global best_acc1 + args.gpu = gpu + + if args.gpu is not None: + print("Use GPU: {} for training".format(args.gpu)) + + if args.distributed: + if args.dist_url == "env://" and args.rank == -1: + args.rank = int(os.environ["RANK"]) + if args.multiprocessing_distributed: + # For multiprocessing distributed training, rank needs to be the + # global rank among all the processes + args.rank = args.rank * ngpus_per_node + gpu + dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url, + world_size=args.world_size, rank=args.rank) + # create model + if args.pretrained: + print("=> using pre-trained model '{}'".format(args.arch)) + model = nvmodels.build_resnet('resnet50', 'classic', True) + CACHE_MODEL_URL = "/cache/model" + os.makedirs(CACHE_MODEL_URL, exist_ok=True) + mox.file.copy_parallel(args.pretrained_weight, os.path.join(CACHE_MODEL_URL, "checkpoint.pth.tar")) + pretrained_weight = os.path.join(CACHE_MODEL_URL, "checkpoint.pth.tar") + pretrained_dict = torch.load(pretrained_weight)["state_dict"] + pretrained_dict.pop('module.fc.weight') + pretrained_dict.pop('module.fc.bias') + model.load_state_dict(pretrained_dict, strict=False) + else: + print("=> creating model '{}'".format(args.arch)) + model = models.__dict__[args.arch](zero_init_residual=True) + + if args.fine_tuning: + print("=> transfer-learning mode + fine-tuning (train only the last FC layer)") + # Freeze Previous Layers(now we are using them as features extractor) + # Fine Tuning the last layer for the new task + if args.arch == "resnet50": + model.classifier = nn.Linear(1024, 10) + model.classifier.parameters() + else: + print("Error: Fine-tuning is not supported on this architecture") + exit(-1) + else: + model.parameters() + + for layer in model.modules(): + if isinstance(layer, nn.Linear): + torch.nn.init.kaiming_normal_(layer.weight, a=math.sqrt(5), ) + if args.distributed: + # For multiprocessing distributed, DistributedDataParallel constructor + # should always set the single device scope, otherwise, + # DistributedDataParallel will use all available devices. + if args.gpu is not None: + torch.cuda.set_device(args.gpu) + model.cuda(args.gpu) + # When using a single GPU per process and per + # DistributedDataParallel, we need to divide the batch size + # ourselves based on the total number of GPUs we have + args.batch_size = int(args.batch_size / ngpus_per_node) + args.workers = int((args.workers + ngpus_per_node - 1) / ngpus_per_node) + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu]) + else: + model.cuda() + # DistributedDataParallel will divide and allocate batch_size to all + # available GPUs if device_ids are not set + model = torch.nn.parallel.DistributedDataParallel(model) + elif args.gpu is not None: + torch.cuda.set_device(args.gpu) + model = model.cuda(args.gpu) + else: + # DataParallel will divide and allocate batch_size to all available GPUs + if args.arch.startswith('alexnet') or args.arch.startswith('vgg'): + model.features = torch.nn.DataParallel(model.features) + model.cuda() + else: + model = model.to(CALCULATE_DEVICE) + + lr_policy = lr_cosine_policy(args.lr, + args.warmup, + args.epochs) + + + # define loss function (criterion) and optimizer + loss = nn.CrossEntropyLoss + if args.label_smoothing > 0.0: + loss = lambda: LabelSmoothing(args.label_smoothing) + criterion = loss().to(CALCULATE_DEVICE) + optimizer = torch.optim.SGD([ + {'params': [param for name, param in model.named_parameters() if name[-4:] == 'bias'], 'weight_decay': 0.0}, + {'params': [param for name, param in model.named_parameters() if name[-4:] != 'bias'], 'weight_decay': args.weight_decay}], + args.lr, + momentum=args.momentum) + + model, optimizer = amp.initialize(model, optimizer, opt_level="O2", loss_scale=1024, verbosity=1) + + # optionally resume from a checkpoint + if args.resume: + if os.path.isfile(args.resume): + print("=> loading checkpoint '{}'".format(args.resume)) + if args.npu is not None: + checkpoint = torch.load(args.resume) + elif args.gpu is None: + checkpoint = torch.load(args.resume) + else: + # Map model to be loaded to specified single gpu. + loc = 'cuda:{}'.format(args.gpu) + checkpoint = torch.load(args.resume, map_location=loc) + args.start_epoch = checkpoint['epoch'] + best_acc1 = checkpoint['best_acc1'] + if args.npu is not None: + best_acc1 = best_acc1.to("npu:{}".format(args.npu)) + elif args.gpu is not None: + # best_acc1 may be from a checkpoint from a different GPU + best_acc1 = best_acc1.to(args.gpu) + model.load_state_dict(checkpoint['state_dict']) + print("=> loaded checkpoint '{}' (epoch {})" + .format(args.resume, checkpoint['epoch'])) + else: + print("=> no checkpoint found at '{}'".format(args.resume)) + + cudnn.benchmark = True + + real_path = '/cache/data_url' + if not os.path.exists(real_path): + os.makedirs(real_path) + mox.file.copy_parallel(args.data_url, real_path) + print("training data finish copy to %s." % real_path) + + traindir = os.path.join(real_path, 'train') + valdir = os.path.join(real_path, 'val') + normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]) + + train_dataset = datasets.ImageFolder( + traindir, + transforms.Compose([ + transforms.RandomResizedCrop(224), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + normalize, + ])) + + if args.distributed: + train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset) + else: + train_sampler = None + + train_loader = torch.utils.data.DataLoader( + train_dataset, batch_size=args.batch_size, shuffle=(train_sampler is None), + num_workers=args.workers, pin_memory=True, sampler=train_sampler, drop_last=True) + + val_loader = torch.utils.data.DataLoader( + datasets.ImageFolder(valdir, transforms.Compose([ + transforms.Resize(256), + transforms.CenterCrop(224), + transforms.ToTensor(), + normalize, + ])), + batch_size=args.batch_size, shuffle=True, + num_workers=args.workers, pin_memory=True) + + if args.evaluate: + validate(val_loader, model, criterion, args) + return + + for epoch in range(args.start_epoch, args.epochs): + if args.distributed: + train_sampler.set_epoch(epoch) + lr_policy(optimizer, 0, epoch) + # train for one epoch + train(train_loader, model, criterion, optimizer, epoch, args) + + # evaluate on validation set + acc1 = validate(val_loader, model, criterion, args) + + # remember best acc@1 and save checkpoint + is_best = acc1 > best_acc1 + best_acc1 = max(acc1, best_acc1) + file_name = "checkpoint_npu{}".format(args.npu) + modeltmp = model.cpu() + save_checkpoint({ + 'epoch': epoch + 1, + 'arch': args.arch, + 'state_dict': modeltmp.state_dict(), + 'best_acc1': best_acc1, + }, is_best, file_name) + modeltmp.to(CALCULATE_DEVICE) + + if args.onnx: + convert_pth_to_onnx(args) + + # --------------modelarts modification---------- + mox.file.copy_parallel(CACHE_TRAINING_URL, args.train_url) + # --------------modelarts modification end---------- + +def convert_pth_to_onnx(args): + pth_pattern = os.path.join(CACHE_TRAINING_URL, f"checkpoint_npu{args.npu}.pth.tar") + pth_file_list = glob.glob(pth_pattern) + if not pth_file_list: + print(f"can't find pth {pth_pattern}") + return + pth_file = pth_file_list[0] + onnx_path = pth_file.split(".")[0] + '.onnx' + convert(pth_file, onnx_path) + + +def train(train_loader, model, criterion, optimizer, epoch, args): + if args.optimizer_batch_size < 0: + batch_size_multiplier = 1 + else: + tbs = 1 * args.batch_size + if args.optimizer_batch_size % tbs != 0: + print( + "Warning: simulated batch size {} is not divisible by actual batch size {}" + .format(args.optimizer_batch_size, tbs)) + batch_size_multiplier = int(args.optimizer_batch_size / tbs) + print("BSM: {}".format(batch_size_multiplier)) + + batch_time = AverageMeter('Time', ':6.3f') + data_time = AverageMeter('Data', ':6.3f') + losses = AverageMeter('Loss', ':.4e') + top1 = AverageMeter('Acc@1', ':6.2f') + top5 = AverageMeter('Acc@5', ':6.2f') + progress = ProgressMeter( + len(train_loader), + [batch_time, data_time, losses, top1, top5], + prefix="Epoch: [{}]".format(epoch)) + + # switch to train mode + model.train() + optimizer.zero_grad() + end = time.time() + for i, (images, target) in enumerate(train_loader): + # measure data loading time + data_time.update(time.time() - end) + + if args.gpu is not None: + images = images.cuda(args.gpu, non_blocking=True) + + images = images.to(CALCULATE_DEVICE, non_blocking=True) + if args.label_smoothing == 0.0: + target = target.to(torch.int32).to(CALCULATE_DEVICE, non_blocking=True) + + # compute output + output = model(images) + loss = criterion(output, target) + + if args.label_smoothing > 0.0: + target = target.to(torch.int32).to(CALCULATE_DEVICE, non_blocking=True) + + # measure accuracy and record loss + acc1, acc5 = accuracy(output, target, topk=(1, 5)) + losses.update(loss.item(), images.size(0)) + top1.update(acc1[0], images.size(0)) + top5.update(acc5[0], images.size(0)) + + # compute gradient and do SGD step + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + optimizer_step = ((i + 1) % batch_size_multiplier) == 0 + if optimizer_step: + if batch_size_multiplier != 1: + for param_group in optimizer.param_groups: + for param in param_group['params']: + param.grad /= batch_size_multiplier + optimizer.step() + optimizer.zero_grad() + + # measure elapsed time + batch_time.update(time.time() - end) + end = time.time() + + if i % LOG_STEP == 0: + progress.display(i) + + if i == TRAIN_STEP: + break + + print("batch_size:", args.batch_size, 'Time: {:.3f}'.format(batch_time.avg), '* FPS@all {:.3f}'.format( + args.batch_size/(batch_time.avg+0.0001))) + +def validate(val_loader, model, criterion, args): + batch_time = AverageMeter('Time', ':6.3f') + losses = AverageMeter('Loss', ':.4e') + top1 = AverageMeter('Acc@1', ':6.2f') + top5 = AverageMeter('Acc@5', ':6.2f') + progress = ProgressMeter( + len(val_loader), + [batch_time, losses, top1, top5], + prefix='Test: ') + + # switch to evaluate mode + model.eval() + + with torch.no_grad(): + end = time.time() + for i, (images, target) in enumerate(val_loader): + if args.gpu is not None: + images = images.cuda(args.gpu, non_blocking=True) + images = images.to(CALCULATE_DEVICE, non_blocking=True) + if args.label_smoothing == 0.0: + target = target.to(torch.int32).to(CALCULATE_DEVICE, non_blocking=True) + + # compute output + output = model(images) + loss = criterion(output, target) + + if args.label_smoothing > 0.0: + target = target.to(torch.int32).to(CALCULATE_DEVICE, non_blocking=True) + + # measure accuracy and record loss + acc1, acc5 = accuracy(output, target, topk=(1, 5)) + losses.update(loss.item(), images.size(0)) + top1.update(acc1[0], images.size(0)) + top5.update(acc5[0], images.size(0)) + + # measure elapsed time + batch_time.update(time.time() - end) + end = time.time() + + if i % LOG_STEP == 0: + progress.display(i) + + print(' * Acc@1 {top1.avg:.3f} Acc@5 {top5.avg:.3f}' + .format(top1=top1, top5=top5)) + return top1.avg + +def save_checkpoint(state, is_best, filename='checkpoint'): + if not os.path.exists(CACHE_TRAINING_URL): + os.makedirs(CACHE_TRAINING_URL) + + filename2 = os.path.join(CACHE_TRAINING_URL, filename + ".pth.tar") + torch.save(state, filename2) + if is_best: + shutil.copyfile(filename2, os.path.join(CACHE_TRAINING_URL, filename + 'model_best.pth.tar')) + +class AverageMeter(object): + """Computes and stores the average and current value""" + def __init__(self, name, fmt=':f'): + self.name = name + self.fmt = fmt + self.reset() + self.start_count_index = 10 + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + + def update(self, val, n=1): + if self.count == 0: + self.batchsize = n + + self.val = val + self.count += n + if self.count > (self.start_count_index * self.batchsize): + self.sum += val * n + self.avg = self.sum / (self.count - self.start_count_index * self.batchsize) + + def __str__(self): + fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' + return fmtstr.format(**self.__dict__) + +class ProgressMeter(object): + def __init__(self, num_batches, meters, prefix=""): + self.batch_fmtstr = self._get_batch_fmtstr(num_batches) + self.meters = meters + self.prefix = prefix + + def display(self, batch): + entries = [self.prefix + self.batch_fmtstr.format(batch)] + entries += [str(meter) for meter in self.meters] + print('\t'.join(entries)) + + def _get_batch_fmtstr(self, num_batches): + num_digits = len(str(num_batches // 1)) + fmt = '{:' + str(num_digits) + 'd}' + return '[' + fmt + '/' + fmt.format(num_batches) + ']' + + +def adjust_learning_rate(optimizer, epoch, args): + """Sets the learning rate to the initial LR decayed by 10 every 30 epochs""" + lr = args.lr * (0.1 ** (epoch // 30)) + for param_group in optimizer.param_groups: + param_group['lr'] = lr + + +def accuracy(output, target, topk=(1,)): + """Computes the accuracy over the k top predictions for the specified values of k""" + with torch.no_grad(): + maxk = max(topk) + batch_size = target.size(0) + + _, pred = output.topk(maxk, 1, True, True) + pred = pred.t() + correct = pred.eq(target.view(1, -1).expand_as(pred)) + + res = [] + for k in topk: + correct_k = correct[:k].view(-1).float().sum(0, keepdim=True) + res.append(correct_k.mul_(100.0 / batch_size)) + return res + +class LabelSmoothing(nn.Module): + """ + NLL loss with label smoothing. + """ + def __init__(self, smoothing=0.0): + """ + Constructor for the LabelSmoothing module. + :param smoothing: label smoothing factor + """ + super(LabelSmoothing, self).__init__() + self.confidence = 1.0 - smoothing + self.smoothing = smoothing + + def forward(self, x, target): + logprobs = torch.nn.functional.log_softmax(x, dim=-1).to("cpu") + nll_loss = -logprobs.gather(dim=-1, index=target.unsqueeze(1)) + nll_loss = nll_loss.squeeze(1) + smooth_loss = -logprobs.mean(dim=-1) + loss = self.confidence * nll_loss + self.smoothing * smooth_loss + return loss.mean().to(CALCULATE_DEVICE) + +def lr_policy(lr_fn, logger=None): + if logger is not None: + logger.register_metric('lr', + log.LR_METER(), + verbosity=dllogger.Verbosity.VERBOSE) + + def _alr(optimizer, iteration, epoch): + lr = lr_fn(iteration, epoch) + + if logger is not None: + logger.log_metric('lr', lr) + for param_group in optimizer.param_groups: + param_group['lr'] = lr + + return _alr + +def lr_cosine_policy(base_lr, warmup_length, epochs, logger=None): + def _lr_fn(iteration, epoch): + if epoch < warmup_length: + lr = base_lr * (epoch + 1) / warmup_length + else: + e = epoch - warmup_length + es = epochs - warmup_length + lr = 0.5 * (1 + np.cos(np.pi * e / es)) * base_lr + return lr + + return lr_policy(_lr_fn, logger=logger) + +if __name__ == '__main__': + main() diff --git a/PyTorch/built-in/cv/classification/Shufflenetv2_for_PyTorch/test/train_performance_1p.sh b/PyTorch/built-in/cv/classification/Shufflenetv2_for_PyTorch/test/train_performance_1p.sh index 295d88c2de..971514cdeb 100644 --- a/PyTorch/built-in/cv/classification/Shufflenetv2_for_PyTorch/test/train_performance_1p.sh +++ b/PyTorch/built-in/cv/classification/Shufflenetv2_for_PyTorch/test/train_performance_1p.sh @@ -1,178 +1,178 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` - -#集合通信参数,不需要修改 -#保证rank table file 文件rank_table_8p.json存放在和test同级的configs目录下 -export RANK_SIZE=1 - -#RANK_TABLE_FILE=${cur_path}/../configs/rank_table_8p.json -RANK_ID_START=0 - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -export ASCEND_GLOBAL_LOG_LEVEL=3 - -#基础参数 需要模型审视修改 -#网络名称,同目录名称 -Network="Shufflenetv2_ID0099_for_PyTorch" -#训练epoch -train_epochs=2 -#训练batch_size -batch_size=1536 - -#TF2.X独有,不需要修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False -autotune=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_full_8p.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is 0 - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --autotune whether to enable autotune, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --autotune* ]];then - autotune=`echo ${para#*=}` - export autotune=$autotune - mv $install_path/fwkacllib/data/rl/Ascend910/custom $install_path/fwkacllib/data/rl/Ascend910/custom_bak - mv $install_path/fwkacllib/data/tiling/Ascend910/custom $install_path/fwkacllib/data/tiling/Ascend910/custom_bak - autotune_dump_path=${cur_path}/output/autotune_dump - mkdir -p ${autotune_dump_path}/GA - mkdir -p ${autotune_dump_path}/rl - cp -rf $install_path/fwkacllib/data/tiling/Ascend910/custom ${autotune_dump_path}/GA/ - cp -rf $install_path/fwkacllib/data/rl/Ascend910/custom ${autotune_dump_path}/RL/ - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#进入训练脚本目录,需要模型审视修改 -cd $cur_path/../ -for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); -do - #设置环境变量,不需要修改 - echo "Device ID: $ASCEND_DEVICE_ID" - export RANK_ID=$RANK_ID - export DEVICE_ID=$RANK_ID - - #创建DeviceID输出目录,不需要修改 - if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - mkdir -p ${cur_path}/output/overflow_dump - else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - mkdir -p ${cur_path}/output/overflow_dump - fi - over_dump_path=${cur_path}/output/overflow_dump - - #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 - - python3 8p_main_med.py \ - --data=$data_path \ - --addr=$(hostname -I |awk '{print $1}') \ - --seed=49 \ - --workers=128 \ - --learning-rate=0.75 \ - --print-freq=10 \ - --eval-freq=5 \ - --arch=shufflenet_v2_x1_0 \ - --dist-url='tcp://127.0.0.1:50000' \ - --dist-backend='hccl' \ - --multiprocessing-distributed \ - --world-size=1 \ - --batch-size=1536 \ - --epochs=2 \ - --warm_up_epochs=1 \ - --rank=0 \ - --amp \ - --momentum=0 \ - --wd=3.0517578125e-05 \ - --device-list=0 \ - --benchmark 0 \ - > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & - -done -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) -echo "E2E Training Duration sec : $e2e_time" - -#cp -r ${cur_path}/train.log ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log - -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据 -FPS=`grep "FPS@all" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk 'END {print $7}'|tr -d ,| sed s/[[:space:]]//g` -ActualFPS=${FPS} - -temp1=`echo "1 * ${batch_size}"|bc` -TrainingTime=`echo "scale=2;${temp1} / ${ActualFPS}"|bc` - -ActualLoss=`grep "Loss" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk 'END {print $12}'` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` + +#集合通信参数,不需要修改 +#保证rank table file 文件rank_table_8p.json存放在和test同级的configs目录下 +export RANK_SIZE=1 + +#RANK_TABLE_FILE=${cur_path}/../configs/rank_table_8p.json +RANK_ID_START=0 + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +export ASCEND_GLOBAL_LOG_LEVEL=3 + +#基础参数 需要模型审视修改 +#网络名称,同目录名称 +Network="Shufflenetv2_ID0099_for_PyTorch" +#训练epoch +train_epochs=2 +#训练batch_size +batch_size=1536 + +#TF2.X独有,不需要修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False +autotune=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_full_8p.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is 0 + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --autotune whether to enable autotune, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --autotune* ]];then + autotune=`echo ${para#*=}` + export autotune=$autotune + mv $install_path/fwkacllib/data/rl/Ascend910/custom $install_path/fwkacllib/data/rl/Ascend910/custom_bak + mv $install_path/fwkacllib/data/tiling/Ascend910/custom $install_path/fwkacllib/data/tiling/Ascend910/custom_bak + autotune_dump_path=${cur_path}/output/autotune_dump + mkdir -p ${autotune_dump_path}/GA + mkdir -p ${autotune_dump_path}/rl + cp -rf $install_path/fwkacllib/data/tiling/Ascend910/custom ${autotune_dump_path}/GA/ + cp -rf $install_path/fwkacllib/data/rl/Ascend910/custom ${autotune_dump_path}/RL/ + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#进入训练脚本目录,需要模型审视修改 +cd $cur_path/../ +for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); +do + #设置环境变量,不需要修改 + echo "Device ID: $ASCEND_DEVICE_ID" + export RANK_ID=$RANK_ID + export DEVICE_ID=$RANK_ID + + #创建DeviceID输出目录,不需要修改 + if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + mkdir -p ${cur_path}/output/overflow_dump + else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + mkdir -p ${cur_path}/output/overflow_dump + fi + over_dump_path=${cur_path}/output/overflow_dump + + #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 + + python3 8p_main_med.py \ + --data=$data_path \ + --addr=$(hostname -I |awk '{print $1}') \ + --seed=49 \ + --workers=128 \ + --learning-rate=0.75 \ + --print-freq=10 \ + --eval-freq=5 \ + --arch=shufflenet_v2_x1_0 \ + --dist-url='tcp://127.0.0.1:50000' \ + --dist-backend='hccl' \ + --multiprocessing-distributed \ + --world-size=1 \ + --batch-size=1536 \ + --epochs=2 \ + --warm_up_epochs=1 \ + --rank=0 \ + --amp \ + --momentum=0 \ + --wd=3.0517578125e-05 \ + --device-list=0 \ + --benchmark 0 \ + > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & + +done +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) +echo "E2E Training Duration sec : $e2e_time" + +#cp -r ${cur_path}/train.log ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log + +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据 +FPS=`grep "FPS@all" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk 'END {print $7}'|tr -d ,| sed s/[[:space:]]//g` +ActualFPS=${FPS} + +temp1=`echo "1 * ${batch_size}"|bc` +TrainingTime=`echo "scale=2;${temp1} / ${ActualFPS}"|bc` + +ActualLoss=`grep "Loss" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk 'END {print $12}'` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log diff --git a/PyTorch/built-in/cv/classification/Shufflenetv2_for_PyTorch/test/train_performance_8p.sh b/PyTorch/built-in/cv/classification/Shufflenetv2_for_PyTorch/test/train_performance_8p.sh index de67f1ede4..39e8b6cd75 100644 --- a/PyTorch/built-in/cv/classification/Shufflenetv2_for_PyTorch/test/train_performance_8p.sh +++ b/PyTorch/built-in/cv/classification/Shufflenetv2_for_PyTorch/test/train_performance_8p.sh @@ -1,175 +1,175 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` - -#集合通信参数,不需要修改 -#保证rank table file 文件rank_table_8p.json存放在和test同级的configs目录下 -export RANK_SIZE=8 -batch_size=1024 -#RANK_TABLE_FILE=${cur_path}/../configs/rank_table_8p.json -RANK_ID_START=0 - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -export ASCEND_GLOBAL_LOG_LEVEL=3 - -#基础参数 需要模型审视修改 -#网络名称,同目录名称 -Network="Shufflenetv2_ID0099_for_PyTorch" -#训练epoch -train_epochs=2 -#device_id_list=0,1,2,3,4,5,6,7 -#TF2.X独有,不需要修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False -autotune=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_full_8p.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is 0 - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --autotune whether to enable autotune, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --autotune* ]];then - autotune=`echo ${para#*=}` - export autotune=$autotune - mv $install_path/fwkacllib/data/rl/Ascend910/custom $install_path/fwkacllib/data/rl/Ascend910/custom_bak - mv $install_path/fwkacllib/data/tiling/Ascend910/custom $install_path/fwkacllib/data/tiling/Ascend910/custom_bak - autotune_dump_path=${cur_path}/output/autotune_dump - mkdir -p ${autotune_dump_path}/GA - mkdir -p ${autotune_dump_path}/rl - cp -rf $install_path/fwkacllib/data/tiling/Ascend910/custom ${autotune_dump_path}/GA/ - cp -rf $install_path/fwkacllib/data/rl/Ascend910/custom ${autotune_dump_path}/RL/ - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#进入训练脚本目录 -export SIll=1 -cd $cur_path/../ -for((RANK_ID=$RANK_ID_START;RANK_ID<$((SIll+RANK_ID_START));RANK_ID++)); -do - #设置环境变量,不需要修改 - export RANK_ID=$RANK_ID - export DEVICE_ID=$RANK_ID - - #创建DeviceID输出目录,不需要修改 - if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - mkdir -p ${cur_path}/output/overflow_dump - else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - mkdir -p ${cur_path}/output/overflow_dump - fi - over_dump_path=${cur_path}/output/overflow_dump - - #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 - - python3 8p_main_med.py \ - --data=$data_path \ - --addr=$(hostname -I |awk '{print $1}') \ - --seed=49 \ - --workers=128 \ - --learning-rate=0.75 \ - --print-freq=10 \ - --eval-freq=5 \ - --arch=shufflenet_v2_x1_0 \ - --dist-url='tcp://127.0.0.1:50000' \ - --dist-backend='hccl' \ - --multiprocessing-distributed \ - --world-size=1 \ - --batch-size=1024 \ - --epochs=2 \ - --warm_up_epochs=1 \ - --rank=0 \ - --amp \ - --momentum=0 \ - --wd=3.0517578125e-05 \ - --device-list=0 \ - --benchmark 0 \ - > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & - -done -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) -echo "E2E Training Duration sec : $e2e_time" - -#稳定性精度看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}${name_bind}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据 - -FPS=`grep "FPS@all" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk 'END {print $7}'|tr -d ,` -ActualFPS=`echo "8 * ${FPS}"|bc` -temp1=`echo "8 * ${batch_size}"|bc` -TrainingTime=`echo "scale=2;${temp1} / ${ActualFPS}"|bc` - -ActualLoss=`grep "Loss" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk 'END {print $12}'` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` + +#集合通信参数,不需要修改 +#保证rank table file 文件rank_table_8p.json存放在和test同级的configs目录下 +export RANK_SIZE=8 +batch_size=1024 +#RANK_TABLE_FILE=${cur_path}/../configs/rank_table_8p.json +RANK_ID_START=0 + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +export ASCEND_GLOBAL_LOG_LEVEL=3 + +#基础参数 需要模型审视修改 +#网络名称,同目录名称 +Network="Shufflenetv2_ID0099_for_PyTorch" +#训练epoch +train_epochs=2 +#device_id_list=0,1,2,3,4,5,6,7 +#TF2.X独有,不需要修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False +autotune=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_full_8p.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is 0 + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --autotune whether to enable autotune, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --autotune* ]];then + autotune=`echo ${para#*=}` + export autotune=$autotune + mv $install_path/fwkacllib/data/rl/Ascend910/custom $install_path/fwkacllib/data/rl/Ascend910/custom_bak + mv $install_path/fwkacllib/data/tiling/Ascend910/custom $install_path/fwkacllib/data/tiling/Ascend910/custom_bak + autotune_dump_path=${cur_path}/output/autotune_dump + mkdir -p ${autotune_dump_path}/GA + mkdir -p ${autotune_dump_path}/rl + cp -rf $install_path/fwkacllib/data/tiling/Ascend910/custom ${autotune_dump_path}/GA/ + cp -rf $install_path/fwkacllib/data/rl/Ascend910/custom ${autotune_dump_path}/RL/ + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#进入训练脚本目录 +export SIll=1 +cd $cur_path/../ +for((RANK_ID=$RANK_ID_START;RANK_ID<$((SIll+RANK_ID_START));RANK_ID++)); +do + #设置环境变量,不需要修改 + export RANK_ID=$RANK_ID + export DEVICE_ID=$RANK_ID + + #创建DeviceID输出目录,不需要修改 + if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + mkdir -p ${cur_path}/output/overflow_dump + else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + mkdir -p ${cur_path}/output/overflow_dump + fi + over_dump_path=${cur_path}/output/overflow_dump + + #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 + + python3 8p_main_med.py \ + --data=$data_path \ + --addr=$(hostname -I |awk '{print $1}') \ + --seed=49 \ + --workers=128 \ + --learning-rate=0.75 \ + --print-freq=10 \ + --eval-freq=5 \ + --arch=shufflenet_v2_x1_0 \ + --dist-url='tcp://127.0.0.1:50000' \ + --dist-backend='hccl' \ + --multiprocessing-distributed \ + --world-size=1 \ + --batch-size=1024 \ + --epochs=2 \ + --warm_up_epochs=1 \ + --rank=0 \ + --amp \ + --momentum=0 \ + --wd=3.0517578125e-05 \ + --device-list=0 \ + --benchmark 0 \ + > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & + +done +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) +echo "E2E Training Duration sec : $e2e_time" + +#稳定性精度看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}${name_bind}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据 + +FPS=`grep "FPS@all" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk 'END {print $7}'|tr -d ,` +ActualFPS=`echo "8 * ${FPS}"|bc` +temp1=`echo "8 * ${batch_size}"|bc` +TrainingTime=`echo "scale=2;${temp1} / ${ActualFPS}"|bc` + +ActualLoss=`grep "Loss" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk 'END {print $12}'` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/LICENSE b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/LICENSE old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Base-RCNN-C4.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Base-RCNN-C4.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Base-RCNN-DilatedC5.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Base-RCNN-DilatedC5.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Base-RCNN-FPN.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Base-RCNN-FPN.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Base-RetinaNet.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Base-RetinaNet.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/fast_rcnn_R_50_FPN_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/fast_rcnn_R_50_FPN_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_101_C4_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_101_C4_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_101_DC5_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_101_DC5_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_101_FPN_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_101_FPN_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_50_C4_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_50_C4_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_50_C4_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_50_C4_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_50_DC5_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_50_DC5_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_50_DC5_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_50_DC5_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_50_FPN_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_50_FPN_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_50_FPN_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_R_50_FPN_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_X_101_32x8d_FPN_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/faster_rcnn_X_101_32x8d_FPN_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/retinanet_R_101_FPN_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/retinanet_R_101_FPN_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/retinanet_R_50_FPN_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/retinanet_R_50_FPN_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/retinanet_R_50_FPN_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/retinanet_R_50_FPN_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/rpn_R_50_C4_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/rpn_R_50_C4_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/rpn_R_50_FPN_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Detection/rpn_R_50_FPN_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_101_C4_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_101_C4_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_101_DC5_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_101_DC5_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_C4_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_C4_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_C4_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_C4_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_DC5_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_DC5_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_DC5_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_DC5_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x_giou.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_1x_giou.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_X_101_32x8d_FPN_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-InstanceSegmentation/mask_rcnn_X_101_32x8d_FPN_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Keypoints/Base-Keypoint-RCNN-FPN.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Keypoints/Base-Keypoint-RCNN-FPN.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Keypoints/keypoint_rcnn_R_101_FPN_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Keypoints/keypoint_rcnn_R_101_FPN_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Keypoints/keypoint_rcnn_R_50_FPN_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Keypoints/keypoint_rcnn_R_50_FPN_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Keypoints/keypoint_rcnn_R_50_FPN_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Keypoints/keypoint_rcnn_R_50_FPN_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Keypoints/keypoint_rcnn_X_101_32x8d_FPN_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-Keypoints/keypoint_rcnn_X_101_32x8d_FPN_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-PanopticSegmentation/Base-Panoptic-FPN.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-PanopticSegmentation/Base-Panoptic-FPN.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-PanopticSegmentation/panoptic_fpn_R_101_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-PanopticSegmentation/panoptic_fpn_R_101_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-PanopticSegmentation/panoptic_fpn_R_50_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-PanopticSegmentation/panoptic_fpn_R_50_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-PanopticSegmentation/panoptic_fpn_R_50_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/COCO-PanopticSegmentation/panoptic_fpn_R_50_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Cityscapes/mask_rcnn_R_50_FPN.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Cityscapes/mask_rcnn_R_50_FPN.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Detectron1-Comparisons/README.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Detectron1-Comparisons/README.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Detectron1-Comparisons/faster_rcnn_R_50_FPN_noaug_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Detectron1-Comparisons/faster_rcnn_R_50_FPN_noaug_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Detectron1-Comparisons/keypoint_rcnn_R_50_FPN_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Detectron1-Comparisons/keypoint_rcnn_R_50_FPN_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Detectron1-Comparisons/mask_rcnn_R_50_FPN_noaug_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Detectron1-Comparisons/mask_rcnn_R_50_FPN_noaug_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/LVISv0.5-InstanceSegmentation/mask_rcnn_R_101_FPN_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/LVISv0.5-InstanceSegmentation/mask_rcnn_R_101_FPN_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/LVISv0.5-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/LVISv0.5-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/LVISv0.5-InstanceSegmentation/mask_rcnn_X_101_32x8d_FPN_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/LVISv0.5-InstanceSegmentation/mask_rcnn_X_101_32x8d_FPN_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/LVISv1-InstanceSegmentation/mask_rcnn_R_101_FPN_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/LVISv1-InstanceSegmentation/mask_rcnn_R_101_FPN_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/LVISv1-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/LVISv1-InstanceSegmentation/mask_rcnn_R_50_FPN_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/LVISv1-InstanceSegmentation/mask_rcnn_X_101_32x8d_FPN_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/LVISv1-InstanceSegmentation/mask_rcnn_X_101_32x8d_FPN_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/cascade_mask_rcnn_R_50_FPN_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/cascade_mask_rcnn_R_50_FPN_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/cascade_mask_rcnn_R_50_FPN_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/cascade_mask_rcnn_R_50_FPN_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/cascade_mask_rcnn_X_152_32x8d_FPN_IN5k_gn_dconv.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/cascade_mask_rcnn_X_152_32x8d_FPN_IN5k_gn_dconv.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/mask_rcnn_R_50_FPN_1x_cls_agnostic.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/mask_rcnn_R_50_FPN_1x_cls_agnostic.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/mask_rcnn_R_50_FPN_1x_dconv_c3-c5.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/mask_rcnn_R_50_FPN_1x_dconv_c3-c5.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/mask_rcnn_R_50_FPN_3x_dconv_c3-c5.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/mask_rcnn_R_50_FPN_3x_dconv_c3-c5.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/mask_rcnn_R_50_FPN_3x_gn.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/mask_rcnn_R_50_FPN_3x_gn.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/mask_rcnn_R_50_FPN_3x_syncbn.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/mask_rcnn_R_50_FPN_3x_syncbn.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/panoptic_fpn_R_101_dconv_cascade_gn_3x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/panoptic_fpn_R_101_dconv_cascade_gn_3x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/scratch_mask_rcnn_R_50_FPN_3x_gn.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/scratch_mask_rcnn_R_50_FPN_3x_gn.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/scratch_mask_rcnn_R_50_FPN_9x_gn.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/scratch_mask_rcnn_R_50_FPN_9x_gn.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/scratch_mask_rcnn_R_50_FPN_9x_syncbn.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/scratch_mask_rcnn_R_50_FPN_9x_syncbn.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/semantic_R_50_FPN_1x.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/Misc/semantic_R_50_FPN_1x.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/PascalVOC-Detection/faster_rcnn_R_50_C4.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/PascalVOC-Detection/faster_rcnn_R_50_C4.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/PascalVOC-Detection/faster_rcnn_R_50_FPN.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/PascalVOC-Detection/faster_rcnn_R_50_FPN.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/README.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/README.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/cascade_mask_rcnn_R_50_FPN_inference_acc_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/cascade_mask_rcnn_R_50_FPN_inference_acc_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/cascade_mask_rcnn_R_50_FPN_instant_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/cascade_mask_rcnn_R_50_FPN_instant_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/fast_rcnn_R_50_FPN_inference_acc_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/fast_rcnn_R_50_FPN_inference_acc_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/fast_rcnn_R_50_FPN_instant_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/fast_rcnn_R_50_FPN_instant_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/keypoint_rcnn_R_50_FPN_inference_acc_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/keypoint_rcnn_R_50_FPN_inference_acc_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/keypoint_rcnn_R_50_FPN_instant_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/keypoint_rcnn_R_50_FPN_instant_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/keypoint_rcnn_R_50_FPN_normalized_training_acc_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/keypoint_rcnn_R_50_FPN_normalized_training_acc_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/keypoint_rcnn_R_50_FPN_training_acc_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/keypoint_rcnn_R_50_FPN_training_acc_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_C4_GCV_instant_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_C4_GCV_instant_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_C4_inference_acc_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_C4_inference_acc_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_C4_instant_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_C4_instant_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_C4_training_acc_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_C4_training_acc_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_DC5_inference_acc_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_DC5_inference_acc_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_FPN_inference_acc_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_FPN_inference_acc_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_FPN_instant_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_FPN_instant_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_FPN_pred_boxes_training_acc_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_FPN_pred_boxes_training_acc_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_FPN_training_acc_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/mask_rcnn_R_50_FPN_training_acc_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/panoptic_fpn_R_50_inference_acc_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/panoptic_fpn_R_50_inference_acc_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/panoptic_fpn_R_50_instant_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/panoptic_fpn_R_50_instant_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/panoptic_fpn_R_50_training_acc_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/panoptic_fpn_R_50_training_acc_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/retinanet_R_50_FPN_inference_acc_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/retinanet_R_50_FPN_inference_acc_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/retinanet_R_50_FPN_instant_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/retinanet_R_50_FPN_instant_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/rpn_R_50_FPN_inference_acc_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/rpn_R_50_FPN_inference_acc_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/rpn_R_50_FPN_instant_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/rpn_R_50_FPN_instant_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/semantic_R_50_FPN_inference_acc_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/semantic_R_50_FPN_inference_acc_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/semantic_R_50_FPN_instant_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/semantic_R_50_FPN_instant_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/semantic_R_50_FPN_training_acc_test.yaml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/configs/quick_schedules/semantic_R_50_FPN_training_acc_test.yaml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/datasets/README.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/datasets/README.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/datasets/prepare_cocofied_lvis.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/datasets/prepare_cocofied_lvis.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/datasets/prepare_for_tests.sh b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/datasets/prepare_for_tests.sh old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/datasets/prepare_panoptic_fpn.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/datasets/prepare_panoptic_fpn.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/demo/README.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/demo/README.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/demo/demo.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/demo/demo.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/demo/predictor.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/demo/predictor.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/checkpoint/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/checkpoint/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/checkpoint/c2_model_loading.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/checkpoint/c2_model_loading.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/checkpoint/catalog.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/checkpoint/catalog.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/checkpoint/detection_checkpoint.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/checkpoint/detection_checkpoint.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/config/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/config/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/config/compat.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/config/compat.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/config/config.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/config/config.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/config/defaults.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/config/defaults.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/build.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/build.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/catalog.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/catalog.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/common.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/common.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/dataset_mapper.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/dataset_mapper.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/README.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/README.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/builtin.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/builtin.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/builtin_meta.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/builtin_meta.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/cityscapes.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/cityscapes.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/coco.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/coco.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/lvis.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/lvis.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/lvis_v0_5_categories.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/lvis_v0_5_categories.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/lvis_v1_categories.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/lvis_v1_categories.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/pascal_voc.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/pascal_voc.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/register_coco.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/datasets/register_coco.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/detection_utils.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/detection_utils.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/samplers/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/samplers/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/samplers/distributed_sampler.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/samplers/distributed_sampler.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/samplers/grouped_batch_sampler.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/samplers/grouped_batch_sampler.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/transforms/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/transforms/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/transforms/augmentation.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/transforms/augmentation.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/transforms/augmentation_impl.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/transforms/augmentation_impl.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/transforms/transform.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/data/transforms/transform.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/engine/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/engine/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/engine/defaults.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/engine/defaults.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/engine/hooks.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/engine/hooks.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/engine/launch.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/engine/launch.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/engine/train_loop.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/engine/train_loop.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/cityscapes_evaluation.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/cityscapes_evaluation.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/coco_evaluation.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/coco_evaluation.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/evaluator.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/evaluator.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/fast_eval_api.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/fast_eval_api.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/lvis_evaluation.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/lvis_evaluation.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/panoptic_evaluation.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/panoptic_evaluation.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/pascal_voc_evaluation.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/pascal_voc_evaluation.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/rotated_coco_evaluation.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/rotated_coco_evaluation.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/sem_seg_evaluation.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/sem_seg_evaluation.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/testing.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/evaluation/testing.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/README.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/README.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/api.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/api.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/c10.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/c10.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/caffe2_export.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/caffe2_export.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/caffe2_inference.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/caffe2_inference.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/caffe2_modeling.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/caffe2_modeling.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/patcher.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/patcher.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/shared.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/shared.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/torchscript.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/export/torchscript.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/aspp.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/aspp.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/batch_norm.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/batch_norm.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/blocks.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/blocks.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/README.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/README.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/ROIAlign/ROIAlign.h b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/ROIAlign/ROIAlign.h old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/ROIAlign/ROIAlign_cpu.cpp b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/ROIAlign/ROIAlign_cpu.cpp old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/ROIAlign/ROIAlign_cuda.cu b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/ROIAlign/ROIAlign_cuda.cu old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/ROIAlignRotated/ROIAlignRotated.h b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/ROIAlignRotated/ROIAlignRotated.h old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/ROIAlignRotated/ROIAlignRotated_cpu.cpp b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/ROIAlignRotated/ROIAlignRotated_cpu.cpp old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/ROIAlignRotated/ROIAlignRotated_cuda.cu b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/ROIAlignRotated/ROIAlignRotated_cuda.cu old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/box_iou_rotated/box_iou_rotated.h b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/box_iou_rotated/box_iou_rotated.h old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/box_iou_rotated/box_iou_rotated_cpu.cpp b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/box_iou_rotated/box_iou_rotated_cpu.cpp old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/box_iou_rotated/box_iou_rotated_cuda.cu b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/box_iou_rotated/box_iou_rotated_cuda.cu old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/box_iou_rotated/box_iou_rotated_utils.h b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/box_iou_rotated/box_iou_rotated_utils.h old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/cocoeval/cocoeval.cpp b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/cocoeval/cocoeval.cpp old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/cocoeval/cocoeval.h b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/cocoeval/cocoeval.h old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/cuda_version.cu b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/cuda_version.cu old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/deformable/deform_conv.h b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/deformable/deform_conv.h old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/deformable/deform_conv_cuda.cu b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/deformable/deform_conv_cuda.cu old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/deformable/deform_conv_cuda_kernel.cu b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/deformable/deform_conv_cuda_kernel.cu old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/nms_rotated/nms_rotated.h b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/nms_rotated/nms_rotated.h old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/nms_rotated/nms_rotated_cpu.cpp b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/nms_rotated/nms_rotated_cpu.cpp old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/nms_rotated/nms_rotated_cuda.cu b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/nms_rotated/nms_rotated_cuda.cu old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/vision.cpp b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/csrc/vision.cpp old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/deform_conv.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/deform_conv.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/mask_ops.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/mask_ops.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/nms.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/nms.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/roi_align.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/roi_align.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/roi_align_rotated.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/roi_align_rotated.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/rotated_boxes.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/rotated_boxes.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/shape_spec.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/shape_spec.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/wrappers.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/layers/wrappers.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/model_zoo/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/model_zoo/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/model_zoo/model_zoo.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/model_zoo/model_zoo.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/anchor_generator.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/anchor_generator.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/backbone/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/backbone/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/backbone/backbone.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/backbone/backbone.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/backbone/build.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/backbone/build.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/backbone/fpn.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/backbone/fpn.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/backbone/resnet.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/backbone/resnet.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/box_regression.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/box_regression.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/matcher.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/matcher.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/meta_arch/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/meta_arch/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/meta_arch/build.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/meta_arch/build.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/meta_arch/panoptic_fpn.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/meta_arch/panoptic_fpn.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/meta_arch/rcnn.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/meta_arch/rcnn.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/meta_arch/retinanet.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/meta_arch/retinanet.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/meta_arch/semantic_seg.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/meta_arch/semantic_seg.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/poolers.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/poolers.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/postprocessing.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/postprocessing.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/proposal_generator/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/proposal_generator/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/proposal_generator/build.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/proposal_generator/build.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/proposal_generator/proposal_utils.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/proposal_generator/proposal_utils.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/proposal_generator/rpn.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/proposal_generator/rpn.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/proposal_generator/rrpn.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/proposal_generator/rrpn.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/box_head.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/box_head.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/cascade_rcnn.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/cascade_rcnn.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/fast_rcnn.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/fast_rcnn.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/keypoint_head.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/keypoint_head.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/mask_head.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/mask_head.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/roi_heads.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/roi_heads.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/rotated_fast_rcnn.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/roi_heads/rotated_fast_rcnn.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/sampling.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/sampling.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/test_time_augmentation.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/modeling/test_time_augmentation.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/solver/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/solver/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/solver/build.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/solver/build.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/solver/lr_scheduler.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/solver/lr_scheduler.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/boxes.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/boxes.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/image_list.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/image_list.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/instances.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/instances.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/keypoints.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/keypoints.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/masks.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/masks.py old mode 100755 new mode 100644 index a4d97d942e..3933471d08 --- a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/masks.py +++ b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/masks.py @@ -1,442 +1,442 @@ -# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 copy -import itertools -import numpy as np -from typing import Any, Iterator, List, Union -import pycocotools.mask as mask_util -import torch - -from detectron2.layers.roi_align import ROIAlign - -from .boxes import Boxes - - -def polygon_area(x, y): - # Using the shoelace formula - # https://stackoverflow.com/questions/24467972/calculate-area-of-polygon-given-x-y-coordinates - return 0.5 * np.abs(np.dot(x, np.roll(y, 1)) - np.dot(y, np.roll(x, 1))) - - -def polygons_to_bitmask(polygons: List[np.ndarray], height: int, width: int) -> np.ndarray: - """ - Args: - polygons (list[ndarray]): each array has shape (Nx2,) - height, width (int) - - Returns: - ndarray: a bool mask of shape (height, width) - """ - assert len(polygons) > 0, "COCOAPI does not support empty polygons" - rles = mask_util.frPyObjects(polygons, height, width) - rle = mask_util.merge(rles) - return mask_util.decode(rle).astype(np.bool) - - -def rasterize_polygons_within_box( - polygons: List[np.ndarray], box: np.ndarray, mask_size: int -) -> torch.Tensor: - """ - Rasterize the polygons into a mask image and - crop the mask content in the given box. - The cropped mask is resized to (mask_size, mask_size). - - This function is used when generating training targets for mask head in Mask R-CNN. - Given original ground-truth masks for an image, new ground-truth mask - training targets in the size of `mask_size x mask_size` - must be provided for each predicted box. This function will be called to - produce such targets. - - Args: - polygons (list[ndarray[float]]): a list of polygons, which represents an instance. - box: 4-element numpy array - mask_size (int): - - Returns: - Tensor: BoolTensor of shape (mask_size, mask_size) - """ - # 1. Shift the polygons w.r.t the boxes - w, h = box[2] - box[0], box[3] - box[1] - - polygons = copy.deepcopy(polygons) - for p in polygons: - p[0::2] = p[0::2] - box[0] - p[1::2] = p[1::2] - box[1] - - # 2. Rescale the polygons to the new box size - # max() to avoid division by small number - ratio_h = mask_size / max(h, 0.1) - ratio_w = mask_size / max(w, 0.1) - - if ratio_h == ratio_w: - for p in polygons: - p *= ratio_h - else: - for p in polygons: - p[0::2] *= ratio_w - p[1::2] *= ratio_h - - # 3. Rasterize the polygons with coco api - mask = polygons_to_bitmask(polygons, mask_size, mask_size) - mask = torch.from_numpy(mask) - return mask - - -class BitMasks: - """ - This class stores the segmentation masks for all objects in one image, in - the form of bitmaps. - - Attributes: - tensor: bool Tensor of N,H,W, representing N instances in the image. - """ - - def __init__(self, tensor: Union[torch.Tensor, np.ndarray]): - """ - Args: - tensor: bool Tensor of N,H,W, representing N instances in the image. - """ - device = tensor.device if isinstance(tensor, torch.Tensor) else torch.device("cpu") - tensor = torch.as_tensor(tensor, dtype=torch.bool, device=device) - assert tensor.dim() == 3, tensor.size() - self.image_size = tensor.shape[1:] - self.tensor = tensor - - def to(self, *args: Any, **kwargs: Any) -> "BitMasks": - return BitMasks(self.tensor.to(*args, **kwargs)) - - @property - def device(self) -> torch.device: - return self.tensor.device - - def __getitem__(self, item: Union[int, slice, torch.BoolTensor]) -> "BitMasks": - """ - Returns: - BitMasks: Create a new :class:`BitMasks` by indexing. - - The following usage are allowed: - - 1. `new_masks = masks[3]`: return a `BitMasks` which contains only one mask. - 2. `new_masks = masks[2:10]`: return a slice of masks. - 3. `new_masks = masks[vector]`, where vector is a torch.BoolTensor - with `length = len(masks)`. Nonzero elements in the vector will be selected. - - Note that the returned object might share storage with this object, - subject to Pytorch's indexing semantics. - """ - if isinstance(item, int): - return BitMasks(self.tensor[item].view(1, -1)) - - if item.dtype == torch.int32: - m = self.tensor[item.long()] - else: - m = self.tensor[item] - - assert m.dim() == 3, "Indexing on BitMasks with {} returns a tensor with shape {}!".format( - item, m.shape - ) - return BitMasks(m) - - def __iter__(self) -> torch.Tensor: - yield from self.tensor - - def __repr__(self) -> str: - s = self.__class__.__name__ + "(" - s += "num_instances={})".format(len(self.tensor)) - return s - - def __len__(self) -> int: - return self.tensor.shape[0] - - def nonempty(self) -> torch.Tensor: - """ - Find masks that are non-empty. - - Returns: - Tensor: a BoolTensor which represents - whether each mask is empty (False) or non-empty (True). - """ - return self.tensor.flatten(1).any(dim=1) - - @staticmethod - def from_polygon_masks( - polygon_masks: Union["PolygonMasks", List[List[np.ndarray]]], height: int, width: int - ) -> "BitMasks": - """ - Args: - polygon_masks (list[list[ndarray]] or PolygonMasks) - height, width (int) - """ - if isinstance(polygon_masks, PolygonMasks): - polygon_masks = polygon_masks.polygons - masks = [polygons_to_bitmask(p, height, width) for p in polygon_masks] - return BitMasks(torch.stack([torch.from_numpy(x) for x in masks])) - - def crop_and_resize(self, boxes: torch.Tensor, mask_size: int) -> torch.Tensor: - """ - Crop each bitmask by the given box, and resize results to (mask_size, mask_size). - This can be used to prepare training targets for Mask R-CNN. - It has less reconstruction error compared to rasterization with polygons. - However we observe no difference in accuracy, - but BitMasks requires more memory to store all the masks. - - Args: - boxes (Tensor): Nx4 tensor storing the boxes for each mask - mask_size (int): the size of the rasterized mask. - - Returns: - Tensor: - A bool tensor of shape (N, mask_size, mask_size), where - N is the number of predicted boxes for this image. - """ - assert len(boxes) == len(self), "{} != {}".format(len(boxes), len(self)) - device = self.tensor.device - - batch_inds = torch.arange(len(boxes), device=device).to(dtype=boxes.dtype)[:, None] - rois = torch.cat([batch_inds, boxes], dim=1) - bit_masks = self.tensor.to(dtype=torch.float32) - rois = rois.to(device=device) - - output = ( - ROIAlign((mask_size, mask_size), 1.0, 0, aligned=True) - .forward(bit_masks[:, None, :, :], rois) - .squeeze(1) - ) - output = output >= 0.5 - return output - - def get_bounding_boxes(self) -> None: - # not needed now - raise NotImplementedError - - @staticmethod - def cat(bitmasks_list: List["BitMasks"]) -> "BitMasks": - """ - Concatenates a list of BitMasks into a single BitMasks - - Arguments: - bitmasks_list (list[BitMasks]) - - Returns: - BitMasks: the concatenated BitMasks - """ - assert isinstance(bitmasks_list, (list, tuple)) - assert len(bitmasks_list) > 0 - assert all(isinstance(bitmask, BitMasks) for bitmask in bitmasks_list) - - cat_bitmasks = type(bitmasks_list[0])(torch.cat([bm.tensor for bm in bitmasks_list], dim=0)) - return cat_bitmasks - - -class PolygonMasks: - """ - This class stores the segmentation masks for all objects in one image, in the form of polygons. - - Attributes: - polygons: list[list[ndarray]]. Each ndarray is a float64 vector representing a polygon. - """ - - def __init__(self, polygons: List[List[Union[torch.Tensor, np.ndarray]]]): - """ - Arguments: - polygons (list[list[np.ndarray]]): The first - level of the list correspond to individual instances, - the second level to all the polygons that compose the - instance, and the third level to the polygon coordinates. - The third level array should have the format of - [x0, y0, x1, y1, ..., xn, yn] (n >= 3). - """ - assert isinstance(polygons, list), ( - "Cannot create PolygonMasks: Expect a list of list of polygons per image. " - "Got '{}' instead.".format(type(polygons)) - ) - - def _make_array(t: Union[torch.Tensor, np.ndarray]) -> np.ndarray: - # Use float64 for higher precision, because why not? - # Always put polygons on CPU (self.to is a no-op) since they - # are supposed to be small tensors. - # May need to change this assumption if GPU placement becomes useful - if isinstance(t, torch.Tensor): - t = t.cpu().numpy() - return np.asarray(t).astype("float64") - - def process_polygons( - polygons_per_instance: List[Union[torch.Tensor, np.ndarray]] - ) -> List[np.ndarray]: - assert isinstance(polygons_per_instance, list), ( - "Cannot create polygons: Expect a list of polygons per instance. " - "Got '{}' instead.".format(type(polygons_per_instance)) - ) - # transform the polygon to a tensor - polygons_per_instance = [_make_array(p) for p in polygons_per_instance] - for polygon in polygons_per_instance: - assert len(polygon) % 2 == 0 and len(polygon) >= 6 - return polygons_per_instance - - self.polygons: List[List[np.ndarray]] = [ - process_polygons(polygons_per_instance) for polygons_per_instance in polygons - ] - - def to(self, *args: Any, **kwargs: Any) -> "PolygonMasks": - return self - - @property - def device(self) -> torch.device: - return torch.device("cpu") - - def get_bounding_boxes(self) -> Boxes: - """ - Returns: - Boxes: tight bounding boxes around polygon masks. - """ - boxes = torch.zeros(len(self.polygons), 4, dtype=torch.float32) - for idx, polygons_per_instance in enumerate(self.polygons): - minxy = torch.as_tensor([float("inf"), float("inf")], dtype=torch.float32) - maxxy = torch.zeros(2, dtype=torch.float32) - for polygon in polygons_per_instance: - coords = torch.from_numpy(polygon).view(-1, 2).to(dtype=torch.float32) - minxy = torch.min(minxy, torch.min(coords, dim=0).values) - maxxy = torch.max(maxxy, torch.max(coords, dim=0).values) - boxes[idx, :2] = minxy - boxes[idx, 2:] = maxxy - return Boxes(boxes) - - def nonempty(self) -> torch.Tensor: - """ - Find masks that are non-empty. - - Returns: - Tensor: - a BoolTensor which represents whether each mask is empty (False) or not (True). - """ - keep = [1 if len(polygon) > 0 else 0 for polygon in self.polygons] - return torch.from_numpy(np.asarray(keep, dtype=np.bool)) - - def __getitem__(self, item: Union[int, slice, List[int], torch.BoolTensor]) -> "PolygonMasks": - """ - Support indexing over the instances and return a `PolygonMasks` object. - `item` can be: - - 1. An integer. It will return an object with only one instance. - 2. A slice. It will return an object with the selected instances. - 3. A list[int]. It will return an object with the selected instances, - correpsonding to the indices in the list. - 4. A vector mask of type BoolTensor, whose length is num_instances. - It will return an object with the instances whose mask is nonzero. - """ - if isinstance(item, int): - selected_polygons = [self.polygons[item]] - elif isinstance(item, slice): - selected_polygons = self.polygons[item] - elif isinstance(item, list): - selected_polygons = [self.polygons[i] for i in item] - elif isinstance(item, torch.Tensor): - # Polygons is a list, so we have to move the indices back to CPU. - if item.dtype == torch.bool: - assert item.dim() == 1, item.shape - item = item.nonzero().squeeze(1).cpu().numpy().tolist() - elif item.dtype in [torch.int32, torch.int64]: - item = item.cpu().numpy().tolist() - else: - raise ValueError("Unsupported tensor dtype={} for indexing!".format(item.dtype)) - selected_polygons = [self.polygons[i] for i in item] - return PolygonMasks(selected_polygons) - - def __iter__(self) -> Iterator[List[np.ndarray]]: - """ - Yields: - list[ndarray]: the polygons for one instance. - Each Tensor is a float64 vector representing a polygon. - """ - return iter(self.polygons) - - def __repr__(self) -> str: - s = self.__class__.__name__ + "(" - s += "num_instances={})".format(len(self.polygons)) - return s - - def __len__(self) -> int: - return len(self.polygons) - - def crop_and_resize(self, boxes: torch.Tensor, mask_size: int) -> torch.Tensor: - """ - Crop each mask by the given box, and resize results to (mask_size, mask_size). - This can be used to prepare training targets for Mask R-CNN. - - Args: - boxes (Tensor): Nx4 tensor storing the boxes for each mask - mask_size (int): the size of the rasterized mask. - - Returns: - Tensor: A bool tensor of shape (N, mask_size, mask_size), where - N is the number of predicted boxes for this image. - """ - assert len(boxes) == len(self), "{} != {}".format(len(boxes), len(self)) - - device = boxes.device - # Put boxes on the CPU, as the polygon representation is not efficient GPU-wise - # (several small tensors for representing a single instance mask) - boxes = boxes.to(torch.device("cpu")) - - results = [ - rasterize_polygons_within_box(poly, box.numpy(), mask_size) - for poly, box in zip(self.polygons, boxes) - ] - """ - poly: list[list[float]], the polygons for one instance - box: a tensor of shape (4,) - """ - if len(results) == 0: - return torch.empty(0, mask_size, mask_size, dtype=torch.bool, device=device) - return torch.stack(results, dim=0).to(device=device) - - def area(self): - """ - Computes area of the mask. - Only works with Polygons, using the shoelace formula: - https://stackoverflow.com/questions/24467972/calculate-area-of-polygon-given-x-y-coordinates - - Returns: - Tensor: a vector, area for each instance - """ - - area = [] - for polygons_per_instance in self.polygons: - area_per_instance = 0 - for p in polygons_per_instance: - area_per_instance += polygon_area(p[0::2], p[1::2]) - area.append(area_per_instance) - - return torch.tensor(area) - - @staticmethod - def cat(polymasks_list: List["PolygonMasks"]) -> "PolygonMasks": - """ - Concatenates a list of PolygonMasks into a single PolygonMasks - - Arguments: - polymasks_list (list[PolygonMasks]) - - Returns: - PolygonMasks: the concatenated PolygonMasks - """ - assert isinstance(polymasks_list, (list, tuple)) - assert len(polymasks_list) > 0 - assert all(isinstance(polymask, PolygonMasks) for polymask in polymasks_list) - - cat_polymasks = type(polymasks_list[0])( - list(itertools.chain.from_iterable(pm.polygons for pm in polymasks_list)) - ) - return cat_polymasks +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 copy +import itertools +import numpy as np +from typing import Any, Iterator, List, Union +import pycocotools.mask as mask_util +import torch + +from detectron2.layers.roi_align import ROIAlign + +from .boxes import Boxes + + +def polygon_area(x, y): + # Using the shoelace formula + # https://stackoverflow.com/questions/24467972/calculate-area-of-polygon-given-x-y-coordinates + return 0.5 * np.abs(np.dot(x, np.roll(y, 1)) - np.dot(y, np.roll(x, 1))) + + +def polygons_to_bitmask(polygons: List[np.ndarray], height: int, width: int) -> np.ndarray: + """ + Args: + polygons (list[ndarray]): each array has shape (Nx2,) + height, width (int) + + Returns: + ndarray: a bool mask of shape (height, width) + """ + assert len(polygons) > 0, "COCOAPI does not support empty polygons" + rles = mask_util.frPyObjects(polygons, height, width) + rle = mask_util.merge(rles) + return mask_util.decode(rle).astype(np.bool) + + +def rasterize_polygons_within_box( + polygons: List[np.ndarray], box: np.ndarray, mask_size: int +) -> torch.Tensor: + """ + Rasterize the polygons into a mask image and + crop the mask content in the given box. + The cropped mask is resized to (mask_size, mask_size). + + This function is used when generating training targets for mask head in Mask R-CNN. + Given original ground-truth masks for an image, new ground-truth mask + training targets in the size of `mask_size x mask_size` + must be provided for each predicted box. This function will be called to + produce such targets. + + Args: + polygons (list[ndarray[float]]): a list of polygons, which represents an instance. + box: 4-element numpy array + mask_size (int): + + Returns: + Tensor: BoolTensor of shape (mask_size, mask_size) + """ + # 1. Shift the polygons w.r.t the boxes + w, h = box[2] - box[0], box[3] - box[1] + + polygons = copy.deepcopy(polygons) + for p in polygons: + p[0::2] = p[0::2] - box[0] + p[1::2] = p[1::2] - box[1] + + # 2. Rescale the polygons to the new box size + # max() to avoid division by small number + ratio_h = mask_size / max(h, 0.1) + ratio_w = mask_size / max(w, 0.1) + + if ratio_h == ratio_w: + for p in polygons: + p *= ratio_h + else: + for p in polygons: + p[0::2] *= ratio_w + p[1::2] *= ratio_h + + # 3. Rasterize the polygons with coco api + mask = polygons_to_bitmask(polygons, mask_size, mask_size) + mask = torch.from_numpy(mask) + return mask + + +class BitMasks: + """ + This class stores the segmentation masks for all objects in one image, in + the form of bitmaps. + + Attributes: + tensor: bool Tensor of N,H,W, representing N instances in the image. + """ + + def __init__(self, tensor: Union[torch.Tensor, np.ndarray]): + """ + Args: + tensor: bool Tensor of N,H,W, representing N instances in the image. + """ + device = tensor.device if isinstance(tensor, torch.Tensor) else torch.device("cpu") + tensor = torch.as_tensor(tensor, dtype=torch.bool, device=device) + assert tensor.dim() == 3, tensor.size() + self.image_size = tensor.shape[1:] + self.tensor = tensor + + def to(self, *args: Any, **kwargs: Any) -> "BitMasks": + return BitMasks(self.tensor.to(*args, **kwargs)) + + @property + def device(self) -> torch.device: + return self.tensor.device + + def __getitem__(self, item: Union[int, slice, torch.BoolTensor]) -> "BitMasks": + """ + Returns: + BitMasks: Create a new :class:`BitMasks` by indexing. + + The following usage are allowed: + + 1. `new_masks = masks[3]`: return a `BitMasks` which contains only one mask. + 2. `new_masks = masks[2:10]`: return a slice of masks. + 3. `new_masks = masks[vector]`, where vector is a torch.BoolTensor + with `length = len(masks)`. Nonzero elements in the vector will be selected. + + Note that the returned object might share storage with this object, + subject to Pytorch's indexing semantics. + """ + if isinstance(item, int): + return BitMasks(self.tensor[item].view(1, -1)) + + if item.dtype == torch.int32: + m = self.tensor[item.long()] + else: + m = self.tensor[item] + + assert m.dim() == 3, "Indexing on BitMasks with {} returns a tensor with shape {}!".format( + item, m.shape + ) + return BitMasks(m) + + def __iter__(self) -> torch.Tensor: + yield from self.tensor + + def __repr__(self) -> str: + s = self.__class__.__name__ + "(" + s += "num_instances={})".format(len(self.tensor)) + return s + + def __len__(self) -> int: + return self.tensor.shape[0] + + def nonempty(self) -> torch.Tensor: + """ + Find masks that are non-empty. + + Returns: + Tensor: a BoolTensor which represents + whether each mask is empty (False) or non-empty (True). + """ + return self.tensor.flatten(1).any(dim=1) + + @staticmethod + def from_polygon_masks( + polygon_masks: Union["PolygonMasks", List[List[np.ndarray]]], height: int, width: int + ) -> "BitMasks": + """ + Args: + polygon_masks (list[list[ndarray]] or PolygonMasks) + height, width (int) + """ + if isinstance(polygon_masks, PolygonMasks): + polygon_masks = polygon_masks.polygons + masks = [polygons_to_bitmask(p, height, width) for p in polygon_masks] + return BitMasks(torch.stack([torch.from_numpy(x) for x in masks])) + + def crop_and_resize(self, boxes: torch.Tensor, mask_size: int) -> torch.Tensor: + """ + Crop each bitmask by the given box, and resize results to (mask_size, mask_size). + This can be used to prepare training targets for Mask R-CNN. + It has less reconstruction error compared to rasterization with polygons. + However we observe no difference in accuracy, + but BitMasks requires more memory to store all the masks. + + Args: + boxes (Tensor): Nx4 tensor storing the boxes for each mask + mask_size (int): the size of the rasterized mask. + + Returns: + Tensor: + A bool tensor of shape (N, mask_size, mask_size), where + N is the number of predicted boxes for this image. + """ + assert len(boxes) == len(self), "{} != {}".format(len(boxes), len(self)) + device = self.tensor.device + + batch_inds = torch.arange(len(boxes), device=device).to(dtype=boxes.dtype)[:, None] + rois = torch.cat([batch_inds, boxes], dim=1) + bit_masks = self.tensor.to(dtype=torch.float32) + rois = rois.to(device=device) + + output = ( + ROIAlign((mask_size, mask_size), 1.0, 0, aligned=True) + .forward(bit_masks[:, None, :, :], rois) + .squeeze(1) + ) + output = output >= 0.5 + return output + + def get_bounding_boxes(self) -> None: + # not needed now + raise NotImplementedError + + @staticmethod + def cat(bitmasks_list: List["BitMasks"]) -> "BitMasks": + """ + Concatenates a list of BitMasks into a single BitMasks + + Arguments: + bitmasks_list (list[BitMasks]) + + Returns: + BitMasks: the concatenated BitMasks + """ + assert isinstance(bitmasks_list, (list, tuple)) + assert len(bitmasks_list) > 0 + assert all(isinstance(bitmask, BitMasks) for bitmask in bitmasks_list) + + cat_bitmasks = type(bitmasks_list[0])(torch.cat([bm.tensor for bm in bitmasks_list], dim=0)) + return cat_bitmasks + + +class PolygonMasks: + """ + This class stores the segmentation masks for all objects in one image, in the form of polygons. + + Attributes: + polygons: list[list[ndarray]]. Each ndarray is a float64 vector representing a polygon. + """ + + def __init__(self, polygons: List[List[Union[torch.Tensor, np.ndarray]]]): + """ + Arguments: + polygons (list[list[np.ndarray]]): The first + level of the list correspond to individual instances, + the second level to all the polygons that compose the + instance, and the third level to the polygon coordinates. + The third level array should have the format of + [x0, y0, x1, y1, ..., xn, yn] (n >= 3). + """ + assert isinstance(polygons, list), ( + "Cannot create PolygonMasks: Expect a list of list of polygons per image. " + "Got '{}' instead.".format(type(polygons)) + ) + + def _make_array(t: Union[torch.Tensor, np.ndarray]) -> np.ndarray: + # Use float64 for higher precision, because why not? + # Always put polygons on CPU (self.to is a no-op) since they + # are supposed to be small tensors. + # May need to change this assumption if GPU placement becomes useful + if isinstance(t, torch.Tensor): + t = t.cpu().numpy() + return np.asarray(t).astype("float64") + + def process_polygons( + polygons_per_instance: List[Union[torch.Tensor, np.ndarray]] + ) -> List[np.ndarray]: + assert isinstance(polygons_per_instance, list), ( + "Cannot create polygons: Expect a list of polygons per instance. " + "Got '{}' instead.".format(type(polygons_per_instance)) + ) + # transform the polygon to a tensor + polygons_per_instance = [_make_array(p) for p in polygons_per_instance] + for polygon in polygons_per_instance: + assert len(polygon) % 2 == 0 and len(polygon) >= 6 + return polygons_per_instance + + self.polygons: List[List[np.ndarray]] = [ + process_polygons(polygons_per_instance) for polygons_per_instance in polygons + ] + + def to(self, *args: Any, **kwargs: Any) -> "PolygonMasks": + return self + + @property + def device(self) -> torch.device: + return torch.device("cpu") + + def get_bounding_boxes(self) -> Boxes: + """ + Returns: + Boxes: tight bounding boxes around polygon masks. + """ + boxes = torch.zeros(len(self.polygons), 4, dtype=torch.float32) + for idx, polygons_per_instance in enumerate(self.polygons): + minxy = torch.as_tensor([float("inf"), float("inf")], dtype=torch.float32) + maxxy = torch.zeros(2, dtype=torch.float32) + for polygon in polygons_per_instance: + coords = torch.from_numpy(polygon).view(-1, 2).to(dtype=torch.float32) + minxy = torch.min(minxy, torch.min(coords, dim=0).values) + maxxy = torch.max(maxxy, torch.max(coords, dim=0).values) + boxes[idx, :2] = minxy + boxes[idx, 2:] = maxxy + return Boxes(boxes) + + def nonempty(self) -> torch.Tensor: + """ + Find masks that are non-empty. + + Returns: + Tensor: + a BoolTensor which represents whether each mask is empty (False) or not (True). + """ + keep = [1 if len(polygon) > 0 else 0 for polygon in self.polygons] + return torch.from_numpy(np.asarray(keep, dtype=np.bool)) + + def __getitem__(self, item: Union[int, slice, List[int], torch.BoolTensor]) -> "PolygonMasks": + """ + Support indexing over the instances and return a `PolygonMasks` object. + `item` can be: + + 1. An integer. It will return an object with only one instance. + 2. A slice. It will return an object with the selected instances. + 3. A list[int]. It will return an object with the selected instances, + correpsonding to the indices in the list. + 4. A vector mask of type BoolTensor, whose length is num_instances. + It will return an object with the instances whose mask is nonzero. + """ + if isinstance(item, int): + selected_polygons = [self.polygons[item]] + elif isinstance(item, slice): + selected_polygons = self.polygons[item] + elif isinstance(item, list): + selected_polygons = [self.polygons[i] for i in item] + elif isinstance(item, torch.Tensor): + # Polygons is a list, so we have to move the indices back to CPU. + if item.dtype == torch.bool: + assert item.dim() == 1, item.shape + item = item.nonzero().squeeze(1).cpu().numpy().tolist() + elif item.dtype in [torch.int32, torch.int64]: + item = item.cpu().numpy().tolist() + else: + raise ValueError("Unsupported tensor dtype={} for indexing!".format(item.dtype)) + selected_polygons = [self.polygons[i] for i in item] + return PolygonMasks(selected_polygons) + + def __iter__(self) -> Iterator[List[np.ndarray]]: + """ + Yields: + list[ndarray]: the polygons for one instance. + Each Tensor is a float64 vector representing a polygon. + """ + return iter(self.polygons) + + def __repr__(self) -> str: + s = self.__class__.__name__ + "(" + s += "num_instances={})".format(len(self.polygons)) + return s + + def __len__(self) -> int: + return len(self.polygons) + + def crop_and_resize(self, boxes: torch.Tensor, mask_size: int) -> torch.Tensor: + """ + Crop each mask by the given box, and resize results to (mask_size, mask_size). + This can be used to prepare training targets for Mask R-CNN. + + Args: + boxes (Tensor): Nx4 tensor storing the boxes for each mask + mask_size (int): the size of the rasterized mask. + + Returns: + Tensor: A bool tensor of shape (N, mask_size, mask_size), where + N is the number of predicted boxes for this image. + """ + assert len(boxes) == len(self), "{} != {}".format(len(boxes), len(self)) + + device = boxes.device + # Put boxes on the CPU, as the polygon representation is not efficient GPU-wise + # (several small tensors for representing a single instance mask) + boxes = boxes.to(torch.device("cpu")) + + results = [ + rasterize_polygons_within_box(poly, box.numpy(), mask_size) + for poly, box in zip(self.polygons, boxes) + ] + """ + poly: list[list[float]], the polygons for one instance + box: a tensor of shape (4,) + """ + if len(results) == 0: + return torch.empty(0, mask_size, mask_size, dtype=torch.bool, device=device) + return torch.stack(results, dim=0).to(device=device) + + def area(self): + """ + Computes area of the mask. + Only works with Polygons, using the shoelace formula: + https://stackoverflow.com/questions/24467972/calculate-area-of-polygon-given-x-y-coordinates + + Returns: + Tensor: a vector, area for each instance + """ + + area = [] + for polygons_per_instance in self.polygons: + area_per_instance = 0 + for p in polygons_per_instance: + area_per_instance += polygon_area(p[0::2], p[1::2]) + area.append(area_per_instance) + + return torch.tensor(area) + + @staticmethod + def cat(polymasks_list: List["PolygonMasks"]) -> "PolygonMasks": + """ + Concatenates a list of PolygonMasks into a single PolygonMasks + + Arguments: + polymasks_list (list[PolygonMasks]) + + Returns: + PolygonMasks: the concatenated PolygonMasks + """ + assert isinstance(polymasks_list, (list, tuple)) + assert len(polymasks_list) > 0 + assert all(isinstance(polymask, PolygonMasks) for polymask in polymasks_list) + + cat_polymasks = type(polymasks_list[0])( + list(itertools.chain.from_iterable(pm.polygons for pm in polymasks_list)) + ) + return cat_polymasks diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/rotated_boxes.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/structures/rotated_boxes.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/README.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/README.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/analysis.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/analysis.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/collect_env.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/collect_env.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/colormap.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/colormap.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/comm.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/comm.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/env.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/env.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/events.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/events.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/logger.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/logger.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/memory.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/memory.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/registry.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/registry.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/serialize.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/serialize.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/video_visualizer.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/video_visualizer.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/visualizer.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/detectron2/utils/visualizer.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/README.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/README.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/linter.sh b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/linter.sh old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/packaging/README.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/packaging/README.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/packaging/build_all_wheels.sh b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/packaging/build_all_wheels.sh old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/packaging/build_wheel.sh b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/packaging/build_wheel.sh old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/packaging/gen_install_table.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/packaging/gen_install_table.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/packaging/gen_wheel_index.sh b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/packaging/gen_wheel_index.sh old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/packaging/pkg_helpers.bash b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/packaging/pkg_helpers.bash old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/parse_results.sh b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/parse_results.sh old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/run_inference_tests.sh b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/run_inference_tests.sh old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/run_instant_tests.sh b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/dev/run_instant_tests.sh old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docker/Dockerfile b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docker/Dockerfile old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docker/Dockerfile-circleci b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docker/Dockerfile-circleci old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docker/README.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docker/README.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docker/docker-compose.yml b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docker/docker-compose.yml old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/.gitignore b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/.gitignore old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/Makefile b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/Makefile old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/README.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/README.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/_static/css/custom.css b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/_static/css/custom.css old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/conf.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/conf.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/notes/benchmarks.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/notes/benchmarks.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/notes/changelog.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/notes/changelog.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/notes/compatibility.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/notes/compatibility.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/notes/contributing.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/notes/contributing.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/README.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/README.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/builtin_datasets.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/builtin_datasets.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/configs.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/configs.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/data_loading.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/data_loading.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/datasets.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/datasets.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/deployment.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/deployment.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/evaluation.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/evaluation.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/extend.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/extend.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/getting_started.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/getting_started.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/install.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/install.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/models.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/models.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/training.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/training.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/write-models.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/docs/tutorials/write-models.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/eval.sh b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/eval.sh old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/run.sh b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/run.sh old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/run8p.sh b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/run8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/run8p_for_faster_rcnn.sh b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/run8p_for_faster_rcnn.sh old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/run_for_faster_rcnn.sh b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/run_for_faster_rcnn.sh old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/setup.cfg b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/setup.cfg old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/setup.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/setup.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/test/train_full_1p.sh b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/test/train_full_1p.sh index b5f6264a8e..2d19be502a 100644 --- a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/test/train_full_1p.sh +++ b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/test/train_full_1p.sh @@ -1,181 +1,181 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd`/../ - -#集合通信参数,不需要修改 -export RANK_SIZE=1 -export JOB_ID=10087 -RANK_ID_START=0 - - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -export ASCEND_GLOBAL_LOG_LEVEL=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="Faster_Mask_RCNN_for_PyTorch" -#训练epoch -train_epochs=1 -#训练batch_size -batch_size=128 -#训练step -train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.01 - -#TF2.X独有,需要模型审视修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -#precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_performance_1P.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is False - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/test/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/test/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/test/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#进入训练脚本目录,需要模型审视修改 -cd $cur_path -for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); -do - #设置环境变量,不需要修改 - echo "Device ID: $ASCEND_DEVICE_ID" - export RANK_ID=$RANK_ID - - #创建DeviceID输出目录,不需要修改 - if [ -d ${cur_path}/test/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/test/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/test/output/$ASCEND_DEVICE_ID/ckpt - else - mkdir -p ${cur_path}/test/output/$ASCEND_DEVICE_ID/ckpt - fi - # 绑核,不需要的绑核的模型删除,需要的模型审视修改 - #let a=RANK_ID*12 - #let b=RANK_ID+1 - #let c=b*12-1 - - #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 - #--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path - nohup python3 main.py \ - --video_path ${data_path}/hmdb51_jpg \ - --annotation_path ${data_path}/hmdb51_json/hmdb51_1.json \ - --result_path outputs \ - --dataset hmdb51 \ - --n_classes 51 \ - --n_pretrain_classes 700 \ - --pretrain_path ${data_path}/r3d18_K_200ep.pth \ - --ft_begin_module fc \ - --model resnet \ - --model_depth 18 \ - --batch_size 128 \ - --n_threads 16 \ - --checkpoint 5 \ - --amp_cfg \ - --opt_level O2 \ - --loss_scale_value 1024 \ - --device_list ${ASCEND_DEVICE_ID} \ - --n_epochs 1 \ - --manual_seed 1234 \ - --learning_rate 0.01 \ - --tensorboard > ${cur_path}/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & -done -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep Fps $cur_path/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|grep -v "\[1/" | grep -v "\[2/" | awk -F "Fps" '{print$2}' | awk '{print$1}' | awk '{sum+=$1} END {print"",sum/NR}'` -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -train_accuracy=`grep "Fps" $cur_path/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|tail -2|head -1|awk '{print $17}'|sed 's/[()]//g' ` -#打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`echo "${batch_size} ${FPS}" | awk '{printf("%.2f",$1*1000/$2)}' ` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep "Fps" $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "Loss" '{print$2}' | awk '{print$1}' > $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd`/../ + +#集合通信参数,不需要修改 +export RANK_SIZE=1 +export JOB_ID=10087 +RANK_ID_START=0 + + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +export ASCEND_GLOBAL_LOG_LEVEL=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="Faster_Mask_RCNN_for_PyTorch" +#训练epoch +train_epochs=1 +#训练batch_size +batch_size=128 +#训练step +train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.01 + +#TF2.X独有,需要模型审视修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +#precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_performance_1P.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is False + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/test/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/test/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/test/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#进入训练脚本目录,需要模型审视修改 +cd $cur_path +for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); +do + #设置环境变量,不需要修改 + echo "Device ID: $ASCEND_DEVICE_ID" + export RANK_ID=$RANK_ID + + #创建DeviceID输出目录,不需要修改 + if [ -d ${cur_path}/test/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/test/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/test/output/$ASCEND_DEVICE_ID/ckpt + else + mkdir -p ${cur_path}/test/output/$ASCEND_DEVICE_ID/ckpt + fi + # 绑核,不需要的绑核的模型删除,需要的模型审视修改 + #let a=RANK_ID*12 + #let b=RANK_ID+1 + #let c=b*12-1 + + #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 + #--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path + nohup python3 main.py \ + --video_path ${data_path}/hmdb51_jpg \ + --annotation_path ${data_path}/hmdb51_json/hmdb51_1.json \ + --result_path outputs \ + --dataset hmdb51 \ + --n_classes 51 \ + --n_pretrain_classes 700 \ + --pretrain_path ${data_path}/r3d18_K_200ep.pth \ + --ft_begin_module fc \ + --model resnet \ + --model_depth 18 \ + --batch_size 128 \ + --n_threads 16 \ + --checkpoint 5 \ + --amp_cfg \ + --opt_level O2 \ + --loss_scale_value 1024 \ + --device_list ${ASCEND_DEVICE_ID} \ + --n_epochs 1 \ + --manual_seed 1234 \ + --learning_rate 0.01 \ + --tensorboard > ${cur_path}/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & +done +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep Fps $cur_path/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|grep -v "\[1/" | grep -v "\[2/" | awk -F "Fps" '{print$2}' | awk '{print$1}' | awk '{sum+=$1} END {print"",sum/NR}'` +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +train_accuracy=`grep "Fps" $cur_path/test/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|tail -2|head -1|awk '{print $17}'|sed 's/[()]//g' ` +#打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`echo "${batch_size} ${FPS}" | awk '{printf("%.2f",$1*1000/$2)}' ` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep "Fps" $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "Loss" '{print$2}' | awk '{print$1}' > $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/test/train_performance_1p.sh b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/test/train_performance_1p.sh index 701c864ccb..c097946c7c 100644 --- a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/test/train_performance_1p.sh +++ b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/test/train_performance_1p.sh @@ -1,171 +1,171 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` - -#集合通信参数,不需要修改 -export RANK_SIZE=1 -export JOB_ID=10087 -RANK_ID_START=0 - - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="Faster_Mask_RCNN_ID0101_for_PyTorch" -#训练epoch -train_epochs=1 -#训练batch_size -batch_size=8 -#训练step -train_steps=100 -#学习率 -learning_rate=0.01 - -#TF2.X独有,需要模型审视修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -#precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_performance_1P.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is False - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/test/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/test/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/test/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt -fi - - -#修改参数 -sed -i "s|\"coco_2017_train\": (\"coco/train2017\", \"coco/annotations/instances_train2017.json\")|\"coco_2017_train\": (\"$data_path/coco/train2017\", \"$data_path/coco/annotations/instances_train2017.json\")|g" $cur_path/../detectron2/data/datasets/builtin.py -sed -i "s|\"coco_2017_val\": (\"coco/val2017\", \"coco/annotations/instances_val2017.json\")|\"coco_2017_val\": (\"$data_path/coco/val2017\", \"$data_path/coco/annotations/instances_val2017.json\")|g" $cur_path/../detectron2/data/datasets/builtin.py -sed -i "s|WEIGHTS: \"detectron2://ImageNetPretrained/MSRA/R-101.pkl\"|WEIGHTS: \"$data_path/R-101.pkl\"|g" $cur_path/../configs/COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml -wait - -cd $cur_path/../ - -python3 setup.py build develop > $cur_path/../log.txt - -#训练开始时间,不需要修改 -start_time=$(date +%s) -nohup python3 tools/train_net.py \ - --config-file configs/COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml \ - AMP 1 \ - OPT_LEVEL O2 \ - LOSS_SCALE_VALUE 64 \ - MODEL.DEVICE npu:$ASCEND_DEVICE_ID \ - SOLVER.IMS_PER_BATCH $batch_size \ - SOLVER.MAX_ITER $train_steps \ - SEED 1234 \ - MODEL.RPN.NMS_THRESH 0.8 \ - MODEL.ROI_BOX_HEAD.POOLER_SAMPLING_RATIO 2 \ - MODEL.ROI_MASK_HEAD.POOLER_SAMPLING_RATIO 2 \ - DATALOADER.NUM_WORKERS 4 \ - SOLVER.BASE_LR 0.0025 > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -#Time=`grep total_loss $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F 'time: ' '{print $2}'|awk '{print $1}'|awk 'NR>1'|awk '{sum+=$1} END {print sum/NR}'|sed s/[[:space:]]//g` -#FPS=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'/'${Time}'}'` -FPS=`grep FPS $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk '{print $NF}'|awk '{sum+=$1} END {print sum/NR}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=None -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#稳定性精度看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据 -#吞吐量,不需要修改 -ActualFPS=${FPS} -#单迭代训练时长,不需要修改 -TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep total_loss $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'total_loss: ' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -#echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` + +#集合通信参数,不需要修改 +export RANK_SIZE=1 +export JOB_ID=10087 +RANK_ID_START=0 + + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="Faster_Mask_RCNN_ID0101_for_PyTorch" +#训练epoch +train_epochs=1 +#训练batch_size +batch_size=8 +#训练step +train_steps=100 +#学习率 +learning_rate=0.01 + +#TF2.X独有,需要模型审视修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +#precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_performance_1P.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is False + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/test/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/test/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/test/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt +fi + + +#修改参数 +sed -i "s|\"coco_2017_train\": (\"coco/train2017\", \"coco/annotations/instances_train2017.json\")|\"coco_2017_train\": (\"$data_path/coco/train2017\", \"$data_path/coco/annotations/instances_train2017.json\")|g" $cur_path/../detectron2/data/datasets/builtin.py +sed -i "s|\"coco_2017_val\": (\"coco/val2017\", \"coco/annotations/instances_val2017.json\")|\"coco_2017_val\": (\"$data_path/coco/val2017\", \"$data_path/coco/annotations/instances_val2017.json\")|g" $cur_path/../detectron2/data/datasets/builtin.py +sed -i "s|WEIGHTS: \"detectron2://ImageNetPretrained/MSRA/R-101.pkl\"|WEIGHTS: \"$data_path/R-101.pkl\"|g" $cur_path/../configs/COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml +wait + +cd $cur_path/../ + +python3 setup.py build develop > $cur_path/../log.txt + +#训练开始时间,不需要修改 +start_time=$(date +%s) +nohup python3 tools/train_net.py \ + --config-file configs/COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml \ + AMP 1 \ + OPT_LEVEL O2 \ + LOSS_SCALE_VALUE 64 \ + MODEL.DEVICE npu:$ASCEND_DEVICE_ID \ + SOLVER.IMS_PER_BATCH $batch_size \ + SOLVER.MAX_ITER $train_steps \ + SEED 1234 \ + MODEL.RPN.NMS_THRESH 0.8 \ + MODEL.ROI_BOX_HEAD.POOLER_SAMPLING_RATIO 2 \ + MODEL.ROI_MASK_HEAD.POOLER_SAMPLING_RATIO 2 \ + DATALOADER.NUM_WORKERS 4 \ + SOLVER.BASE_LR 0.0025 > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +#Time=`grep total_loss $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F 'time: ' '{print $2}'|awk '{print $1}'|awk 'NR>1'|awk '{sum+=$1} END {print sum/NR}'|sed s/[[:space:]]//g` +#FPS=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'/'${Time}'}'` +FPS=`grep FPS $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk '{print $NF}'|awk '{sum+=$1} END {print sum/NR}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=None +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#稳定性精度看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据 +#吞吐量,不需要修改 +ActualFPS=${FPS} +#单迭代训练时长,不需要修改 +TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep total_loss $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'total_loss: ' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/test/train_performance_8p.sh b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/test/train_performance_8p.sh index 448e69a2f2..162088573c 100644 --- a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/test/train_performance_8p.sh +++ b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/test/train_performance_8p.sh @@ -1,170 +1,170 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` - -#集合通信参数,不需要修改 -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="Faster_Mask_RCNN_ID0101_for_PyTorch" -#训练epoch -train_epochs=1 -#训练batch_size -batch_size=64 -#训练step -train_steps=100 -#学习率 -learning_rate=0.01 - -#TF2.X独有,需要模型审视修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -#precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_performance_1P.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is False - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/test/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/test/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/test/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt -fi - - -#修改参数 -sed -i "s|\"coco_2017_train\": (\"coco/train2017\", \"coco/annotations/instances_train2017.json\")|\"coco_2017_train\": (\"$data_path/coco/train2017\", \"$data_path/coco/annotations/instances_train2017.json\")|g" $cur_path/../detectron2/data/datasets/builtin.py -sed -i "s|\"coco_2017_val\": (\"coco/val2017\", \"coco/annotations/instances_val2017.json\")|\"coco_2017_val\": (\"$data_path/coco/val2017\", \"$data_path/coco/annotations/instances_val2017.json\")|g" $cur_path/../detectron2/data/datasets/builtin.py -sed -i "s|WEIGHTS: \"detectron2://ImageNetPretrained/MSRA/R-101.pkl\"|WEIGHTS: \"$data_path/R-101.pkl\"|g" $cur_path/../configs/COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml -wait - -cd $cur_path/../ - -python3 setup.py build develop > $cur_path/../log.txt - -#训练开始时间,不需要修改 -start_time=$(date +%s) -nohup python3 tools/train_net.py \ - --config-file configs/COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml \ - --device-ids 0 1 2 3 4 5 6 7 \ - --num-gpus 8 \ - AMP 1 \ - OPT_LEVEL O2 \ - LOSS_SCALE_VALUE 64 \ - SOLVER.IMS_PER_BATCH $batch_size \ - SOLVER.MAX_ITER $train_steps \ - SEED 1234 \ - MODEL.RPN.NMS_THRESH 0.8 \ - MODEL.ROI_BOX_HEAD.POOLER_SAMPLING_RATIO 2 \ - MODEL.ROI_MASK_HEAD.POOLER_SAMPLING_RATIO 2 \ - DATALOADER.NUM_WORKERS 8 \ - SOLVER.BASE_LR 0.02 > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -##Time=`grep total_loss $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F 'time: ' '{print $2}'|awk '{print $1}'|awk 'NR>1'|awk '{sum+=$1} END {print sum/NR}'|sed s/[[:space:]]//g` -#FPS=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'/'${Time}'}'` -FPS=`grep FPS $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk '{print $NF}'|awk '{sum+=$1} END {print sum/NR}'` -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=None -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#稳定性精度看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据 -#吞吐量,不需要修改 -ActualFPS=${FPS} -#单迭代训练时长,不需要修改 -TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep total_loss $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'total_loss: ' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -#echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` + +#集合通信参数,不需要修改 +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="Faster_Mask_RCNN_ID0101_for_PyTorch" +#训练epoch +train_epochs=1 +#训练batch_size +batch_size=64 +#训练step +train_steps=100 +#学习率 +learning_rate=0.01 + +#TF2.X独有,需要模型审视修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +#precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_performance_1P.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is False + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/test/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/test/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/test/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt +fi + + +#修改参数 +sed -i "s|\"coco_2017_train\": (\"coco/train2017\", \"coco/annotations/instances_train2017.json\")|\"coco_2017_train\": (\"$data_path/coco/train2017\", \"$data_path/coco/annotations/instances_train2017.json\")|g" $cur_path/../detectron2/data/datasets/builtin.py +sed -i "s|\"coco_2017_val\": (\"coco/val2017\", \"coco/annotations/instances_val2017.json\")|\"coco_2017_val\": (\"$data_path/coco/val2017\", \"$data_path/coco/annotations/instances_val2017.json\")|g" $cur_path/../detectron2/data/datasets/builtin.py +sed -i "s|WEIGHTS: \"detectron2://ImageNetPretrained/MSRA/R-101.pkl\"|WEIGHTS: \"$data_path/R-101.pkl\"|g" $cur_path/../configs/COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml +wait + +cd $cur_path/../ + +python3 setup.py build develop > $cur_path/../log.txt + +#训练开始时间,不需要修改 +start_time=$(date +%s) +nohup python3 tools/train_net.py \ + --config-file configs/COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml \ + --device-ids 0 1 2 3 4 5 6 7 \ + --num-gpus 8 \ + AMP 1 \ + OPT_LEVEL O2 \ + LOSS_SCALE_VALUE 64 \ + SOLVER.IMS_PER_BATCH $batch_size \ + SOLVER.MAX_ITER $train_steps \ + SEED 1234 \ + MODEL.RPN.NMS_THRESH 0.8 \ + MODEL.ROI_BOX_HEAD.POOLER_SAMPLING_RATIO 2 \ + MODEL.ROI_MASK_HEAD.POOLER_SAMPLING_RATIO 2 \ + DATALOADER.NUM_WORKERS 8 \ + SOLVER.BASE_LR 0.02 > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +##Time=`grep total_loss $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F 'time: ' '{print $2}'|awk '{print $1}'|awk 'NR>1'|awk '{sum+=$1} END {print sum/NR}'|sed s/[[:space:]]//g` +#FPS=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'/'${Time}'}'` +FPS=`grep FPS $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk '{print $NF}'|awk '{sum+=$1} END {print sum/NR}'` +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=None +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#稳定性精度看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据 +#吞吐量,不需要修改 +ActualFPS=${FPS} +#单迭代训练时长,不需要修改 +TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep total_loss $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'total_loss: ' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/README.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/README.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/test_coco.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/test_coco.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/test_coco_evaluation.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/test_coco_evaluation.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/test_detection_utils.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/test_detection_utils.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/test_rotation_transform.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/test_rotation_transform.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/test_sampler.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/test_sampler.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/test_transforms.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/data/test_transforms.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/layers/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/layers/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/layers/test_mask_ops.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/layers/test_mask_ops.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/layers/test_nms.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/layers/test_nms.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/layers/test_nms_rotated.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/layers/test_nms_rotated.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/layers/test_roi_align.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/layers/test_roi_align.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/layers/test_roi_align_rotated.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/layers/test_roi_align_rotated.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_anchor_generator.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_anchor_generator.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_box2box_transform.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_box2box_transform.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_fast_rcnn.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_fast_rcnn.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_matcher.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_matcher.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_model_e2e.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_model_e2e.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_roi_heads.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_roi_heads.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_roi_pooler.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_roi_pooler.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_rpn.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/modeling/test_rpn.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/structures/__init__.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/structures/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/structures/test_boxes.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/structures/test_boxes.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/structures/test_imagelist.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/structures/test_imagelist.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/structures/test_instances.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/structures/test_instances.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/structures/test_rotated_boxes.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/structures/test_rotated_boxes.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_checkpoint.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_checkpoint.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_config.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_config.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_engine.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_engine.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_export_caffe2.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_export_caffe2.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_model_analysis.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_model_analysis.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_model_zoo.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_model_zoo.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_visualizer.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tests/test_visualizer.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/README.md b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/README.md old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/analyze_model.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/analyze_model.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/benchmark.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/benchmark.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/convert-torchvision-to-d2.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/convert-torchvision-to-d2.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/plain_train_net.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/plain_train_net.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/train_net.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/train_net.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/visualize_data.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/visualize_data.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/visualize_json_results.py b/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch/tools/visualize_json_results.py old mode 100755 new mode 100644 diff --git a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/LICENSE b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/LICENSE index 4ba4fdcab3..a0e0310359 100644 --- a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/LICENSE +++ b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/LICENSE @@ -1,29 +1,29 @@ -BSD 3-Clause License - -Copyright (c) 2017, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +BSD 3-Clause License + +Copyright (c) 2017, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/NPU/src/README.md b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/NPU/src/README.md index 39f21344a2..9325120e10 100644 --- a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/NPU/src/README.md +++ b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/NPU/src/README.md @@ -1,61 +1,61 @@ -# Shape Robust Text Detection with Progressive Scale Expansion Network - -## Requirements -* NPU配套的run包安装(C20B030) -* Python 3.7.5 -* PyTorch(NPU版本) -* apex(NPU版本) -* pyclipper -* Polygon3 -* opencv-python 3.4 - -## 1P -1. 编辑 train_1p.sh device-list(NPU设备号) addr(本机ip地址) data-dir(数据集目录) remark(备注信息) -2. 运行 sh train_1p.sh -``` -python3 -W ignore train_8p_anycard.py \ - --lr 0.001\ - --dist-backend 'hccl' \ - --rank 0 \ - --workers 32 \ - --multiprocessing-distributed \ - --world-size 1 \ - --batch_size 16 \ - --device 'npu' \ - --opt-level 'O2' \ - --loss-scale 64 \ - --addr='XX.XXX.XXX.XXX' \ #修改本机ip地址 - --seed 16 \ - --n_epoch 600 \ - --data-dir '/home/w50015720/npu/PSENet_data' \ #修改数据集目录 - --port 8272 \ - --schedule 200 400 \ - --device-list '0' \ # 修改NPU设备号 - --remark 'test' # 修改备注信息 -``` -## 8P -1. 编辑 train_8p.sh device-list(NPU设备号) addr(本机ip地址) data-dir(数据集目录) remark(备注信息) -2. 运行 sh train_8p.sh - -``` -python3 -W ignore train_8p_anycard.py \ - --lr 0.008\ - --dist-backend 'hccl' \ - --rank 0 \ - --workers 32 \ - --multiprocessing-distributed \ - --world-size 1 \ - --batch_size 32 \ - --device 'npu' \ - --opt-level 'O2' \ - --loss-scale 64 \ - --addr='XX.XXX.XXX.XXX' \ #修改本机ip地址 - --seed 16 \ - --n_epoch 600 \ - --data-dir '/home/data/' \ #修改数据集目录 - --port 8271 \ - --schedule 200 400 \ - --device-list '0,1,2,3,4,5,6,7' \ # 修改NPU设备号 8卡 - --remark 'npu8pbatch32lr8' # 修改备注信息 -``` - +# Shape Robust Text Detection with Progressive Scale Expansion Network + +## Requirements +* NPU配套的run包安装(C20B030) +* Python 3.7.5 +* PyTorch(NPU版本) +* apex(NPU版本) +* pyclipper +* Polygon3 +* opencv-python 3.4 + +## 1P +1. 编辑 train_1p.sh device-list(NPU设备号) addr(本机ip地址) data-dir(数据集目录) remark(备注信息) +2. 运行 sh train_1p.sh +``` +python3 -W ignore train_8p_anycard.py \ + --lr 0.001\ + --dist-backend 'hccl' \ + --rank 0 \ + --workers 32 \ + --multiprocessing-distributed \ + --world-size 1 \ + --batch_size 16 \ + --device 'npu' \ + --opt-level 'O2' \ + --loss-scale 64 \ + --addr='XX.XXX.XXX.XXX' \ #修改本机ip地址 + --seed 16 \ + --n_epoch 600 \ + --data-dir '/home/w50015720/npu/PSENet_data' \ #修改数据集目录 + --port 8272 \ + --schedule 200 400 \ + --device-list '0' \ # 修改NPU设备号 + --remark 'test' # 修改备注信息 +``` +## 8P +1. 编辑 train_8p.sh device-list(NPU设备号) addr(本机ip地址) data-dir(数据集目录) remark(备注信息) +2. 运行 sh train_8p.sh + +``` +python3 -W ignore train_8p_anycard.py \ + --lr 0.008\ + --dist-backend 'hccl' \ + --rank 0 \ + --workers 32 \ + --multiprocessing-distributed \ + --world-size 1 \ + --batch_size 32 \ + --device 'npu' \ + --opt-level 'O2' \ + --loss-scale 64 \ + --addr='XX.XXX.XXX.XXX' \ #修改本机ip地址 + --seed 16 \ + --n_epoch 600 \ + --data-dir '/home/data/' \ #修改数据集目录 + --port 8271 \ + --schedule 200 400 \ + --device-list '0,1,2,3,4,5,6,7' \ # 修改NPU设备号 8卡 + --remark 'npu8pbatch32lr8' # 修改备注信息 +``` + diff --git a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/NPU/src/requirements.txt b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/NPU/src/requirements.txt index 3d66988238..fef5b96702 100644 --- a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/NPU/src/requirements.txt +++ b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/NPU/src/requirements.txt @@ -1,3 +1,3 @@ -pyclipper -Polygon3 +pyclipper +Polygon3 opencv-python \ No newline at end of file diff --git a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/NPU/src/train_ic15.py b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/NPU/src/train_ic15.py index 05dfb7a1ac..1255f04c8e 100644 --- a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/NPU/src/train_ic15.py +++ b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/NPU/src/train_ic15.py @@ -1,449 +1,449 @@ -# Copyright [yyyy] [name of copyright owner] -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 argparse -import os -import random -import sys -import time -import warnings - -import numpy as np -import torch -import torch.backends.cudnn as cudnn -import torch.distributed as dist -import torch.multiprocessing as mp -import torch.nn.parallel -import torch.npu -import torch.utils.data.distributed -from apex import amp - -import apex -import models -from data_loader import IC15Loader -from metrics import runningScore -from multi_epochs_dataloader import MultiEpochsDataLoader -from util import AverageMeter - - - -def ohem_single(score, gt_text, training_mask): - pos_num = (int)(np.sum(gt_text > 0.5)) - (int)(np.sum((gt_text > 0.5) & (training_mask <= 0.5))) - - if pos_num == 0: - selected_mask = training_mask - selected_mask = selected_mask.reshape(1, selected_mask.shape[0], selected_mask.shape[1]).astype('float32') - return selected_mask - - neg_num = (int)(np.sum(gt_text <= 0.5)) - neg_num = (int)(min(pos_num * 3, neg_num)) - - if neg_num == 0: - selected_mask = training_mask - selected_mask = selected_mask.reshape(1, selected_mask.shape[0], selected_mask.shape[1]).astype('float32') - return selected_mask - - neg_score = score[gt_text <= 0.5] - neg_score_sorted = np.sort(-neg_score) - threshold = -neg_score_sorted[neg_num - 1] - - selected_mask = ((score >= threshold) | (gt_text > 0.5)) & (training_mask > 0.5) - selected_mask = selected_mask.reshape(1, selected_mask.shape[0], selected_mask.shape[1]).astype('float32') - return selected_mask - - -def ohem_batch(scores, gt_texts, training_masks): - scores = scores.data.cpu().numpy() - gt_texts = gt_texts.data.cpu().numpy() - training_masks = training_masks.data.cpu().numpy() - selected_masks = [] - for i in range(scores.shape[0]): - selected_masks.append(ohem_single(scores[i, :, :], gt_texts[i, :, :], training_masks[i, :, :])) - selected_masks = np.concatenate(selected_masks, 0) - selected_masks = torch.from_numpy(selected_masks).float() - return selected_masks - - -def dice_loss(input, target, mask): - input = torch.sigmoid(input) - - input = input.reshape(input.size()[0], -1) - target = target.reshape(target.size()[0], -1) - mask = mask.reshape(mask.size()[0], -1) - - input = input * mask - target = target * mask - - a = torch.sum(input * target, 1) - b = torch.sum(input * input, 1) + 0.001 - c = torch.sum(target * target, 1) + 0.001 - d = (2 * a) / (b + c) - dice_loss = torch.mean(d) - return 1 - dice_loss - - -def cal_text_score(texts, gt_texts, training_masks, running_metric_text): - training_masks = training_masks.data.cpu().numpy() - pred_text = torch.sigmoid(texts).data.cpu().numpy() * training_masks - - pred_text[pred_text <= 0.5] = 0 - pred_text[pred_text > 0.5] = 1 - pred_text = pred_text.astype(np.int32) - gt_text = gt_texts.data.cpu().numpy() * training_masks - gt_text = gt_text.astype(np.int32) - running_metric_text.update(gt_text, pred_text) - score_text, _ = running_metric_text.get_scores() - return score_text - - -def cal_kernel_score(kernels, gt_kernels, gt_texts, training_masks, running_metric_kernel): - mask = (gt_texts * training_masks).data.cpu().numpy() - kernel = kernels[:, -1, :, :] - gt_kernel = gt_kernels[:, -1, :, :] - pred_kernel = torch.sigmoid(kernel).data.cpu().numpy() - pred_kernel[pred_kernel <= 0.5] = 0 - pred_kernel[pred_kernel > 0.5] = 1 - pred_kernel = (pred_kernel * mask).astype(np.int32) - gt_kernel = gt_kernel.data.cpu().numpy() - gt_kernel = (gt_kernel * mask).astype(np.int32) - running_metric_kernel.update(gt_kernel, pred_kernel) - score_kernel, _ = running_metric_kernel.get_scores() - return score_kernel - - -def train(train_loader, model, criterion, optimizer, epoch, args, npu_per_node): - model.train() - - losses = AverageMeter() - running_metric_text = runningScore(2) - running_metric_kernel = runningScore(2) - - epoch_time = time.time() - batch_time = time.time() - for batch_idx, (imgs, gt_texts, gt_kernels, training_masks) in enumerate(train_loader): - loc = 'npu:{}'.format(args.npu) - imgs = imgs.to(loc, non_blocking=True) - gt_texts = gt_texts.to(loc, non_blocking=True) - gt_kernels = gt_kernels.to(loc, non_blocking=True) - training_masks = training_masks.to(loc, non_blocking=True) - - outputs = model(imgs) - texts = torch.index_select(outputs, 1, torch.tensor([0]).to(loc)).squeeze() - kernels = torch.index_select(outputs, 1, torch.tensor([1, 2, 3, 4, 5, 6]).to(loc)) - - selected_masks = ohem_batch(texts, gt_texts, training_masks) - selected_masks = selected_masks.to(loc, non_blocking=True) - - loss_text = criterion(texts, gt_texts, selected_masks) - - loss_kernels = [] - mask0 = torch.sigmoid(texts).data.cpu().numpy() - mask1 = training_masks.data.cpu().numpy() - selected_masks = ((mask0 > 0.5) & (mask1 > 0.5)).astype('float32') - selected_masks = torch.from_numpy(selected_masks).float() - selected_masks = selected_masks.to(loc, non_blocking=True) - for i in range(6): - kernel_i = torch.index_select(kernels, 1, torch.tensor([i]).to(loc)).squeeze() - gt_kernel_i = torch.index_select(gt_kernels, 1, torch.tensor([i]).to(loc)).squeeze() - loss_kernel_i = criterion(kernel_i, gt_kernel_i, selected_masks) - loss_kernels.append(loss_kernel_i) - loss_kernel = sum(loss_kernels) / len(loss_kernels) - - loss = 0.7 * loss_text + 0.3 * loss_kernel - losses.update(loss.item(), imgs.size(0)) - - optimizer.zero_grad() - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - optimizer.step() - score_text = cal_text_score(texts, gt_texts, training_masks, running_metric_text) - score_kernel = cal_kernel_score(kernels, gt_kernels, gt_texts, training_masks, running_metric_kernel) - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % npu_per_node == 0): - batch_time = time.time() - batch_time - output_log = '(epoch: {epoch:0>3d} {batch:0>2d}/{size}) | FPS: {fps:5.3f} | Loss : {lossv:.4f} | Acc_t: {acc: .4f} | IOU_t: {iou_t: .4f} | IOU_k: {iou_k: .4f}'.format( - epoch=epoch + 1, - batch=batch_idx + 1, - size=len(train_loader), - fps=npu_per_node * args.batch_size / batch_time, - lossv=losses.val, - acc=score_text['Mean Acc'], - iou_t=score_text['Mean IoU'], - iou_k=score_kernel['Mean IoU']) - batch_time = time.time() - print(output_log) - epoch_time = time.time() - epoch_time - - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % npu_per_node == 0): - output_log = '{epoch:0>3d}/{n_epoch} | LR: {lr:.5f} | FPS: {fps:5.3f} | batch: {batch:.5f}s | Loss: {lossa:.4f} | Acc_t: {acc: .4f} | IOU_t: {iou_t: .4f} | IOU_k: {iou_k: .4f}'.format( - epoch=epoch + 1, - n_epoch=args.n_epoch, - lr=optimizer.param_groups[0]['lr'], - fps=npu_per_node * len(train_loader) * args.batch_size / epoch_time, - batch=epoch_time / len(train_loader), - lossa=losses.avg, - acc=score_text['Mean Acc'], - iou_t=score_text['Mean IoU'], - iou_k=score_kernel['Mean IoU']) - print(output_log) - sys.stdout.flush() - - return ( - losses.avg, score_text['Mean Acc'], score_kernel['Mean Acc'], score_text['Mean IoU'], score_kernel['Mean IoU']) - - -def adjust_learning_rate(args, optimizer, epoch): - global state - if epoch in args.schedule: - args.lr = args.lr * 0.1 - for param_group in optimizer.param_groups: - param_group['lr'] = args.lr - - -def save_checkpoint(state, checkpoint='checkpoint', filename='checkpoint.pth.tar'): - if not os.path.isdir(checkpoint): - os.makedirs(checkpoint) - filepath = os.path.join(checkpoint, filename) - torch.save(state, filepath) - - -def main(npu, npu_per_node, args): - args.npu = args.process_device_map[npu] - print("[npu id:", args.npu, "]", "+++++++++++++++++++++++++++ before set KERNEL_NAME_ID:", - os.environ['KERNEL_NAME_ID']) - os.environ['KERNEL_NAME_ID'] = str(npu) - print("[npu id:", args.npu, "]", "+++++++++++++++++++++++++++KERNEL_NAME_ID:", os.environ['KERNEL_NAME_ID']) - - if args.npu is not None: - print("[npu id:", args.npu, "]", "Use NPU: {} for training".format(args.npu)) - - if args.checkpoint == '': - args.checkpoint = "checkpoints/ic15_%s_bs_%d_ep_%d" % (args.arch, args.batch_size, args.n_epoch) - if args.pretrain: - if 'synth' in args.pretrain: - args.checkpoint += "_pretrain_synth" - else: - args.checkpoint += "_pretrain_ic17" - if args.distributed: - if args.multiprocessing_distributed: - args.rank = args.rank * npu_per_node + npu - if args.device == 'npu': - dist.init_process_group(backend=args.dist_backend, - world_size=args.world_size, rank=args.rank) - loc = 'npu:{}'.format(args.npu) - torch.npu.set_device(loc) - args.batch_size = int(args.batch_size / npu_per_node) - args.workers = int((args.workers + npu_per_node - 1) / npu_per_node) - - print("[npu id:", args.npu, "]", "===============main_worker()=================") - print("[npu id:", args.npu, "]", args) - print("[npu id:", args.npu, "]", "===============main_worker()=================") - - print('checkpoint path: %s' % args.checkpoint) - print('init lr: %.8f' % args.lr) - print('schedule: ', args.schedule) - sys.stdout.flush() - - if not os.path.isdir(args.checkpoint): - os.makedirs(args.checkpoint) - - kernel_num = 7 - min_scale = 0.4 - start_epoch = 0 - - my_data = IC15Loader(args=args, - is_transform=True, - img_size=args.img_size, - kernel_num=kernel_num, - min_scale=min_scale) - if args.distributed: - train_sampler = torch.utils.data.distributed.DistributedSampler(my_data) - else: - train_sampler = None - - train_loader = MultiEpochsDataLoader( - my_data, - batch_size=args.batch_size, - shuffle=(train_sampler is None), - num_workers=args.workers, - drop_last=True, - pin_memory=True, - sampler=train_sampler) - - print("[npu id:", args.npu, "]", "=> creating model '{}'".format(args.arch)) - if args.arch == "resnet50": - model = models.resnet50(pretrained=True, num_classes=kernel_num) - elif args.arch == "resnet101": - model = models.resnet101(pretrained=True, num_classes=kernel_num) - elif args.arch == "resnet152": - model = models.resnet152(pretrained=True, num_classes=kernel_num) - - model = model.to(loc) - - if args.combine_sgd: - optimizer = apex.optimizers.NpuFusedSGD(model.parameters(), lr=args.lr, momentum=0.99, weight_decay=5e-4) - else: - optimizer = torch.optim.SGD(model.parameters(), lr=args.lr, momentum=0.99, weight_decay=5e-4) - - model, optimizer = amp.initialize(model, optimizer, - opt_level=args.opt_level, - keep_batchnorm_fp32=args.keep_batchnorm_fp32, - loss_scale=args.loss_scale, - combine_grad=args.combine_grad) - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.npu], broadcast_buffers=False) - - if args.pretrain: - print('Using pretrained model.') - assert os.path.isfile(args.pretrain), 'Error: no checkpoint directory found!' - checkpoint = torch.load(args.pretrain) - model.load_state_dict(checkpoint['state_dict']) - elif args.resume: - print('Resuming from checkpoint.') - assert os.path.isfile(args.resume), 'Error: no checkpoint directory found!' - checkpoint = torch.load(args.resume) - start_epoch = checkpoint['epoch'] - model.load_state_dict(checkpoint['state_dict']) - optimizer.load_state_dict(checkpoint['optimizer']) - amp.load_state_dict(checkpoint['amp']) - else: - print('Training from scratch.') - cudnn.benchmark = True - - best_model = {'loss': 0, 'acc': 0, 'iou': 0} - - for epoch in range(start_epoch, args.n_epoch): - if args.distributed: - train_sampler.set_epoch(epoch) - adjust_learning_rate(args, optimizer, epoch) - - train_loss, train_te_acc, train_ke_acc, train_te_iou, train_ke_iou = train(train_loader, model, dice_loss, - optimizer, epoch, - args, npu_per_node) - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % npu_per_node == 0): - if epoch > args.n_epoch - 6: - best_path = f'{args.remark}_{train_loss:.4f}_{train_te_acc:.4f}_{train_ke_iou:.4f}_{train_te_iou:.4f}_{epoch}.pth.tar' - save_checkpoint({ - 'epoch': epoch + 1, - 'state_dict': model.state_dict(), - 'lr': args.lr, - 'optimizer': optimizer.state_dict(), - 'amp': amp.state_dict(), - }, checkpoint='best', filename=best_path) - best_model['acc'] = train_te_acc - best_model['iou'] = train_te_iou - - -def device_id_to_process_device_map(device_list): - devices = device_list.split(",") - devices = [int(x) for x in devices] - devices.sort() - - process_device_map = dict() - for process_id, device_id in enumerate(devices): - process_device_map[process_id] = device_id - - return process_device_map - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Hyperparams') - parser.add_argument('--data-dir', nargs='?', type=str, default='PSENet_data', - help='point to the root data path of ICDAR') - parser.add_argument('--train_data', nargs='?', type=str, default='ICDAR2015', - help='indicate which dataset was used, ICDAR2015 or ICDAR2017') - parser.add_argument('--arch', nargs='?', type=str, default='resnet50') - parser.add_argument('--img_size', nargs='?', type=int, default=640, - help='Height of the input image') - parser.add_argument('--n_epoch', nargs='?', type=int, default=600, - help='# of the epochs') - parser.add_argument('--schedule', type=int, nargs='+', default=[200, 400], - help='Decrease learning rate at these epochs.') - parser.add_argument('--batch_size', nargs='?', type=int, default=16, - help='Batch Size') - parser.add_argument('--lr', nargs='?', type=float, default=1e-3, - help='Learning Rate') - parser.add_argument('--resume', nargs='?', type=str, default=None, - help='Path to previous saved model to restart from') - parser.add_argument('--pretrain', nargs='?', type=str, default=None, - help='Path to previous saved model to restart from') - parser.add_argument('--checkpoint', default='', type=str, metavar='PATH', - help='path to save checkpoint (default: checkpoint)') - parser.add_argument('--opt-level', type=str) - parser.add_argument('--keep-batchnorm-fp32', type=str, default=None) - parser.add_argument('--loss-scale', type=str, default=64) - parser.add_argument('--world-size', default=-1, type=int, - help='number of nodes for distributed training') - parser.add_argument('--seed', default=None, type=int, - help='seed for initializing training. ') - parser.add_argument('--device-list', default='0,1,2,3,4,5,6,7', type=str, help='device id list') - parser.add_argument('--multiprocessing-distributed', action='store_true', - help='Use multi-processing distributed training to launch ' - 'N processes per node, which has N NPUs. This is the ' - 'fastest way to use PyTorch for either single node or ' - 'multi node data parallel training') - parser.add_argument('--device', default='npu', type=str, - help='npu or gpu') - parser.add_argument('--dist-backend', default='nccl', type=str, - help='distributed backend') - parser.add_argument('--rank', default=-1, type=int, - help='node rank for distributed training') - parser.add_argument('--addr', default='10.136.181.127', type=str, - help='master addr') - parser.add_argument('--dist-url', default='env://', type=str, - help='url used to set up distributed training') - parser.add_argument('--port', default='8888', type=str) - parser.add_argument('-j', '--workers', default=32, type=int, metavar='N', - help='number of data loading workers (default: 4)') - parser.add_argument('--remark', default='', type=str, - help='remark. ') - parser.add_argument('--combine_grad', action='store_true', - help='whether to combine grad in apex') - parser.add_argument('--combine_sgd', action='store_true', - help='whether to use combined sgd instead of sgd') - - args = parser.parse_args() - - - if args.seed is not None: - random.seed(args.seed) - os.environ['PYTHONHASHSEED'] = str(args.seed) - np.random.seed(args.seed) - torch.manual_seed(args.seed) - torch.cuda.manual_seed(args.seed) - torch.cuda.manual_seed_all(args.seed) - cudnn.deterministic = True - torch.backends.cudnn.deterministic = True - torch.backends.cudnn.benchmark = False - - - args.distributed = args.world_size > 1 or args.multiprocessing_distributed - args.process_device_map = device_id_to_process_device_map(args.device_list) - - if args.device == 'npu': - npu_per_node = len(args.process_device_map) - else: - npu_per_node = torch.cuda.device_count() - - os.environ['MASTER_ADDR'] = args.addr - os.environ['MASTER_PORT'] = args.port - os.environ['KERNEL_NAME_ID'] = str(0) - print("+++++++++++++++++++++KERNEL_NAME_ID:", os.environ['KERNEL_NAME_ID']) - - args.world_size = npu_per_node * args.world_size - mp.spawn(main, nprocs=npu_per_node, args=(npu_per_node, args)) - +# Copyright [yyyy] [name of copyright owner] +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 argparse +import os +import random +import sys +import time +import warnings + +import numpy as np +import torch +import torch.backends.cudnn as cudnn +import torch.distributed as dist +import torch.multiprocessing as mp +import torch.nn.parallel +import torch.npu +import torch.utils.data.distributed +from apex import amp + +import apex +import models +from data_loader import IC15Loader +from metrics import runningScore +from multi_epochs_dataloader import MultiEpochsDataLoader +from util import AverageMeter + + + +def ohem_single(score, gt_text, training_mask): + pos_num = (int)(np.sum(gt_text > 0.5)) - (int)(np.sum((gt_text > 0.5) & (training_mask <= 0.5))) + + if pos_num == 0: + selected_mask = training_mask + selected_mask = selected_mask.reshape(1, selected_mask.shape[0], selected_mask.shape[1]).astype('float32') + return selected_mask + + neg_num = (int)(np.sum(gt_text <= 0.5)) + neg_num = (int)(min(pos_num * 3, neg_num)) + + if neg_num == 0: + selected_mask = training_mask + selected_mask = selected_mask.reshape(1, selected_mask.shape[0], selected_mask.shape[1]).astype('float32') + return selected_mask + + neg_score = score[gt_text <= 0.5] + neg_score_sorted = np.sort(-neg_score) + threshold = -neg_score_sorted[neg_num - 1] + + selected_mask = ((score >= threshold) | (gt_text > 0.5)) & (training_mask > 0.5) + selected_mask = selected_mask.reshape(1, selected_mask.shape[0], selected_mask.shape[1]).astype('float32') + return selected_mask + + +def ohem_batch(scores, gt_texts, training_masks): + scores = scores.data.cpu().numpy() + gt_texts = gt_texts.data.cpu().numpy() + training_masks = training_masks.data.cpu().numpy() + selected_masks = [] + for i in range(scores.shape[0]): + selected_masks.append(ohem_single(scores[i, :, :], gt_texts[i, :, :], training_masks[i, :, :])) + selected_masks = np.concatenate(selected_masks, 0) + selected_masks = torch.from_numpy(selected_masks).float() + return selected_masks + + +def dice_loss(input, target, mask): + input = torch.sigmoid(input) + + input = input.reshape(input.size()[0], -1) + target = target.reshape(target.size()[0], -1) + mask = mask.reshape(mask.size()[0], -1) + + input = input * mask + target = target * mask + + a = torch.sum(input * target, 1) + b = torch.sum(input * input, 1) + 0.001 + c = torch.sum(target * target, 1) + 0.001 + d = (2 * a) / (b + c) + dice_loss = torch.mean(d) + return 1 - dice_loss + + +def cal_text_score(texts, gt_texts, training_masks, running_metric_text): + training_masks = training_masks.data.cpu().numpy() + pred_text = torch.sigmoid(texts).data.cpu().numpy() * training_masks + + pred_text[pred_text <= 0.5] = 0 + pred_text[pred_text > 0.5] = 1 + pred_text = pred_text.astype(np.int32) + gt_text = gt_texts.data.cpu().numpy() * training_masks + gt_text = gt_text.astype(np.int32) + running_metric_text.update(gt_text, pred_text) + score_text, _ = running_metric_text.get_scores() + return score_text + + +def cal_kernel_score(kernels, gt_kernels, gt_texts, training_masks, running_metric_kernel): + mask = (gt_texts * training_masks).data.cpu().numpy() + kernel = kernels[:, -1, :, :] + gt_kernel = gt_kernels[:, -1, :, :] + pred_kernel = torch.sigmoid(kernel).data.cpu().numpy() + pred_kernel[pred_kernel <= 0.5] = 0 + pred_kernel[pred_kernel > 0.5] = 1 + pred_kernel = (pred_kernel * mask).astype(np.int32) + gt_kernel = gt_kernel.data.cpu().numpy() + gt_kernel = (gt_kernel * mask).astype(np.int32) + running_metric_kernel.update(gt_kernel, pred_kernel) + score_kernel, _ = running_metric_kernel.get_scores() + return score_kernel + + +def train(train_loader, model, criterion, optimizer, epoch, args, npu_per_node): + model.train() + + losses = AverageMeter() + running_metric_text = runningScore(2) + running_metric_kernel = runningScore(2) + + epoch_time = time.time() + batch_time = time.time() + for batch_idx, (imgs, gt_texts, gt_kernels, training_masks) in enumerate(train_loader): + loc = 'npu:{}'.format(args.npu) + imgs = imgs.to(loc, non_blocking=True) + gt_texts = gt_texts.to(loc, non_blocking=True) + gt_kernels = gt_kernels.to(loc, non_blocking=True) + training_masks = training_masks.to(loc, non_blocking=True) + + outputs = model(imgs) + texts = torch.index_select(outputs, 1, torch.tensor([0]).to(loc)).squeeze() + kernels = torch.index_select(outputs, 1, torch.tensor([1, 2, 3, 4, 5, 6]).to(loc)) + + selected_masks = ohem_batch(texts, gt_texts, training_masks) + selected_masks = selected_masks.to(loc, non_blocking=True) + + loss_text = criterion(texts, gt_texts, selected_masks) + + loss_kernels = [] + mask0 = torch.sigmoid(texts).data.cpu().numpy() + mask1 = training_masks.data.cpu().numpy() + selected_masks = ((mask0 > 0.5) & (mask1 > 0.5)).astype('float32') + selected_masks = torch.from_numpy(selected_masks).float() + selected_masks = selected_masks.to(loc, non_blocking=True) + for i in range(6): + kernel_i = torch.index_select(kernels, 1, torch.tensor([i]).to(loc)).squeeze() + gt_kernel_i = torch.index_select(gt_kernels, 1, torch.tensor([i]).to(loc)).squeeze() + loss_kernel_i = criterion(kernel_i, gt_kernel_i, selected_masks) + loss_kernels.append(loss_kernel_i) + loss_kernel = sum(loss_kernels) / len(loss_kernels) + + loss = 0.7 * loss_text + 0.3 * loss_kernel + losses.update(loss.item(), imgs.size(0)) + + optimizer.zero_grad() + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + optimizer.step() + score_text = cal_text_score(texts, gt_texts, training_masks, running_metric_text) + score_kernel = cal_kernel_score(kernels, gt_kernels, gt_texts, training_masks, running_metric_kernel) + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % npu_per_node == 0): + batch_time = time.time() - batch_time + output_log = '(epoch: {epoch:0>3d} {batch:0>2d}/{size}) | FPS: {fps:5.3f} | Loss : {lossv:.4f} | Acc_t: {acc: .4f} | IOU_t: {iou_t: .4f} | IOU_k: {iou_k: .4f}'.format( + epoch=epoch + 1, + batch=batch_idx + 1, + size=len(train_loader), + fps=npu_per_node * args.batch_size / batch_time, + lossv=losses.val, + acc=score_text['Mean Acc'], + iou_t=score_text['Mean IoU'], + iou_k=score_kernel['Mean IoU']) + batch_time = time.time() + print(output_log) + epoch_time = time.time() - epoch_time + + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % npu_per_node == 0): + output_log = '{epoch:0>3d}/{n_epoch} | LR: {lr:.5f} | FPS: {fps:5.3f} | batch: {batch:.5f}s | Loss: {lossa:.4f} | Acc_t: {acc: .4f} | IOU_t: {iou_t: .4f} | IOU_k: {iou_k: .4f}'.format( + epoch=epoch + 1, + n_epoch=args.n_epoch, + lr=optimizer.param_groups[0]['lr'], + fps=npu_per_node * len(train_loader) * args.batch_size / epoch_time, + batch=epoch_time / len(train_loader), + lossa=losses.avg, + acc=score_text['Mean Acc'], + iou_t=score_text['Mean IoU'], + iou_k=score_kernel['Mean IoU']) + print(output_log) + sys.stdout.flush() + + return ( + losses.avg, score_text['Mean Acc'], score_kernel['Mean Acc'], score_text['Mean IoU'], score_kernel['Mean IoU']) + + +def adjust_learning_rate(args, optimizer, epoch): + global state + if epoch in args.schedule: + args.lr = args.lr * 0.1 + for param_group in optimizer.param_groups: + param_group['lr'] = args.lr + + +def save_checkpoint(state, checkpoint='checkpoint', filename='checkpoint.pth.tar'): + if not os.path.isdir(checkpoint): + os.makedirs(checkpoint) + filepath = os.path.join(checkpoint, filename) + torch.save(state, filepath) + + +def main(npu, npu_per_node, args): + args.npu = args.process_device_map[npu] + print("[npu id:", args.npu, "]", "+++++++++++++++++++++++++++ before set KERNEL_NAME_ID:", + os.environ['KERNEL_NAME_ID']) + os.environ['KERNEL_NAME_ID'] = str(npu) + print("[npu id:", args.npu, "]", "+++++++++++++++++++++++++++KERNEL_NAME_ID:", os.environ['KERNEL_NAME_ID']) + + if args.npu is not None: + print("[npu id:", args.npu, "]", "Use NPU: {} for training".format(args.npu)) + + if args.checkpoint == '': + args.checkpoint = "checkpoints/ic15_%s_bs_%d_ep_%d" % (args.arch, args.batch_size, args.n_epoch) + if args.pretrain: + if 'synth' in args.pretrain: + args.checkpoint += "_pretrain_synth" + else: + args.checkpoint += "_pretrain_ic17" + if args.distributed: + if args.multiprocessing_distributed: + args.rank = args.rank * npu_per_node + npu + if args.device == 'npu': + dist.init_process_group(backend=args.dist_backend, + world_size=args.world_size, rank=args.rank) + loc = 'npu:{}'.format(args.npu) + torch.npu.set_device(loc) + args.batch_size = int(args.batch_size / npu_per_node) + args.workers = int((args.workers + npu_per_node - 1) / npu_per_node) + + print("[npu id:", args.npu, "]", "===============main_worker()=================") + print("[npu id:", args.npu, "]", args) + print("[npu id:", args.npu, "]", "===============main_worker()=================") + + print('checkpoint path: %s' % args.checkpoint) + print('init lr: %.8f' % args.lr) + print('schedule: ', args.schedule) + sys.stdout.flush() + + if not os.path.isdir(args.checkpoint): + os.makedirs(args.checkpoint) + + kernel_num = 7 + min_scale = 0.4 + start_epoch = 0 + + my_data = IC15Loader(args=args, + is_transform=True, + img_size=args.img_size, + kernel_num=kernel_num, + min_scale=min_scale) + if args.distributed: + train_sampler = torch.utils.data.distributed.DistributedSampler(my_data) + else: + train_sampler = None + + train_loader = MultiEpochsDataLoader( + my_data, + batch_size=args.batch_size, + shuffle=(train_sampler is None), + num_workers=args.workers, + drop_last=True, + pin_memory=True, + sampler=train_sampler) + + print("[npu id:", args.npu, "]", "=> creating model '{}'".format(args.arch)) + if args.arch == "resnet50": + model = models.resnet50(pretrained=True, num_classes=kernel_num) + elif args.arch == "resnet101": + model = models.resnet101(pretrained=True, num_classes=kernel_num) + elif args.arch == "resnet152": + model = models.resnet152(pretrained=True, num_classes=kernel_num) + + model = model.to(loc) + + if args.combine_sgd: + optimizer = apex.optimizers.NpuFusedSGD(model.parameters(), lr=args.lr, momentum=0.99, weight_decay=5e-4) + else: + optimizer = torch.optim.SGD(model.parameters(), lr=args.lr, momentum=0.99, weight_decay=5e-4) + + model, optimizer = amp.initialize(model, optimizer, + opt_level=args.opt_level, + keep_batchnorm_fp32=args.keep_batchnorm_fp32, + loss_scale=args.loss_scale, + combine_grad=args.combine_grad) + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.npu], broadcast_buffers=False) + + if args.pretrain: + print('Using pretrained model.') + assert os.path.isfile(args.pretrain), 'Error: no checkpoint directory found!' + checkpoint = torch.load(args.pretrain) + model.load_state_dict(checkpoint['state_dict']) + elif args.resume: + print('Resuming from checkpoint.') + assert os.path.isfile(args.resume), 'Error: no checkpoint directory found!' + checkpoint = torch.load(args.resume) + start_epoch = checkpoint['epoch'] + model.load_state_dict(checkpoint['state_dict']) + optimizer.load_state_dict(checkpoint['optimizer']) + amp.load_state_dict(checkpoint['amp']) + else: + print('Training from scratch.') + cudnn.benchmark = True + + best_model = {'loss': 0, 'acc': 0, 'iou': 0} + + for epoch in range(start_epoch, args.n_epoch): + if args.distributed: + train_sampler.set_epoch(epoch) + adjust_learning_rate(args, optimizer, epoch) + + train_loss, train_te_acc, train_ke_acc, train_te_iou, train_ke_iou = train(train_loader, model, dice_loss, + optimizer, epoch, + args, npu_per_node) + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % npu_per_node == 0): + if epoch > args.n_epoch - 6: + best_path = f'{args.remark}_{train_loss:.4f}_{train_te_acc:.4f}_{train_ke_iou:.4f}_{train_te_iou:.4f}_{epoch}.pth.tar' + save_checkpoint({ + 'epoch': epoch + 1, + 'state_dict': model.state_dict(), + 'lr': args.lr, + 'optimizer': optimizer.state_dict(), + 'amp': amp.state_dict(), + }, checkpoint='best', filename=best_path) + best_model['acc'] = train_te_acc + best_model['iou'] = train_te_iou + + +def device_id_to_process_device_map(device_list): + devices = device_list.split(",") + devices = [int(x) for x in devices] + devices.sort() + + process_device_map = dict() + for process_id, device_id in enumerate(devices): + process_device_map[process_id] = device_id + + return process_device_map + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Hyperparams') + parser.add_argument('--data-dir', nargs='?', type=str, default='PSENet_data', + help='point to the root data path of ICDAR') + parser.add_argument('--train_data', nargs='?', type=str, default='ICDAR2015', + help='indicate which dataset was used, ICDAR2015 or ICDAR2017') + parser.add_argument('--arch', nargs='?', type=str, default='resnet50') + parser.add_argument('--img_size', nargs='?', type=int, default=640, + help='Height of the input image') + parser.add_argument('--n_epoch', nargs='?', type=int, default=600, + help='# of the epochs') + parser.add_argument('--schedule', type=int, nargs='+', default=[200, 400], + help='Decrease learning rate at these epochs.') + parser.add_argument('--batch_size', nargs='?', type=int, default=16, + help='Batch Size') + parser.add_argument('--lr', nargs='?', type=float, default=1e-3, + help='Learning Rate') + parser.add_argument('--resume', nargs='?', type=str, default=None, + help='Path to previous saved model to restart from') + parser.add_argument('--pretrain', nargs='?', type=str, default=None, + help='Path to previous saved model to restart from') + parser.add_argument('--checkpoint', default='', type=str, metavar='PATH', + help='path to save checkpoint (default: checkpoint)') + parser.add_argument('--opt-level', type=str) + parser.add_argument('--keep-batchnorm-fp32', type=str, default=None) + parser.add_argument('--loss-scale', type=str, default=64) + parser.add_argument('--world-size', default=-1, type=int, + help='number of nodes for distributed training') + parser.add_argument('--seed', default=None, type=int, + help='seed for initializing training. ') + parser.add_argument('--device-list', default='0,1,2,3,4,5,6,7', type=str, help='device id list') + parser.add_argument('--multiprocessing-distributed', action='store_true', + help='Use multi-processing distributed training to launch ' + 'N processes per node, which has N NPUs. This is the ' + 'fastest way to use PyTorch for either single node or ' + 'multi node data parallel training') + parser.add_argument('--device', default='npu', type=str, + help='npu or gpu') + parser.add_argument('--dist-backend', default='nccl', type=str, + help='distributed backend') + parser.add_argument('--rank', default=-1, type=int, + help='node rank for distributed training') + parser.add_argument('--addr', default='10.136.181.127', type=str, + help='master addr') + parser.add_argument('--dist-url', default='env://', type=str, + help='url used to set up distributed training') + parser.add_argument('--port', default='8888', type=str) + parser.add_argument('-j', '--workers', default=32, type=int, metavar='N', + help='number of data loading workers (default: 4)') + parser.add_argument('--remark', default='', type=str, + help='remark. ') + parser.add_argument('--combine_grad', action='store_true', + help='whether to combine grad in apex') + parser.add_argument('--combine_sgd', action='store_true', + help='whether to use combined sgd instead of sgd') + + args = parser.parse_args() + + + if args.seed is not None: + random.seed(args.seed) + os.environ['PYTHONHASHSEED'] = str(args.seed) + np.random.seed(args.seed) + torch.manual_seed(args.seed) + torch.cuda.manual_seed(args.seed) + torch.cuda.manual_seed_all(args.seed) + cudnn.deterministic = True + torch.backends.cudnn.deterministic = True + torch.backends.cudnn.benchmark = False + + + args.distributed = args.world_size > 1 or args.multiprocessing_distributed + args.process_device_map = device_id_to_process_device_map(args.device_list) + + if args.device == 'npu': + npu_per_node = len(args.process_device_map) + else: + npu_per_node = torch.cuda.device_count() + + os.environ['MASTER_ADDR'] = args.addr + os.environ['MASTER_PORT'] = args.port + os.environ['KERNEL_NAME_ID'] = str(0) + print("+++++++++++++++++++++KERNEL_NAME_ID:", os.environ['KERNEL_NAME_ID']) + + args.world_size = npu_per_node * args.world_size + mp.spawn(main, nprocs=npu_per_node, args=(npu_per_node, args)) + diff --git a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/NPU/src/train_ic15_8p.py b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/NPU/src/train_ic15_8p.py index 6b06a15d3d..1904aae875 100644 --- a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/NPU/src/train_ic15_8p.py +++ b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/NPU/src/train_ic15_8p.py @@ -1,453 +1,453 @@ -# Copyright [yyyy] [name of copyright owner] -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 argparse -import os -import random -import sys -import time -import warnings - -import numpy as np -import torch -import torch.backends.cudnn as cudnn -import torch.distributed as dist -import torch.multiprocessing as mp -import torch.nn.parallel -import torch.npu -import torch.utils.data.distributed -from apex import amp - -import apex -import models -from data_loader import IC15Loader -from metrics import runningScore -from multi_epochs_dataloader import MultiEpochsDataLoader -from util import AverageMeter - - - -def ohem_single(score, gt_text, training_mask): - pos_num = (int)(np.sum(gt_text > 0.5)) - (int)(np.sum((gt_text > 0.5) & (training_mask <= 0.5))) - - if pos_num == 0: - selected_mask = training_mask - selected_mask = selected_mask.reshape(1, selected_mask.shape[0], selected_mask.shape[1]).astype('float32') - return selected_mask - - neg_num = (int)(np.sum(gt_text <= 0.5)) - neg_num = (int)(min(pos_num * 3, neg_num)) - - if neg_num == 0: - selected_mask = training_mask - selected_mask = selected_mask.reshape(1, selected_mask.shape[0], selected_mask.shape[1]).astype('float32') - return selected_mask - - neg_score = score[gt_text <= 0.5] - neg_score_sorted = np.sort(-neg_score) - threshold = -neg_score_sorted[neg_num - 1] - - selected_mask = ((score >= threshold) | (gt_text > 0.5)) & (training_mask > 0.5) - selected_mask = selected_mask.reshape(1, selected_mask.shape[0], selected_mask.shape[1]).astype('float32') - return selected_mask - - -def ohem_batch(scores, gt_texts, training_masks): - scores = scores.data.cpu().numpy() - gt_texts = gt_texts.data.cpu().numpy() - training_masks = training_masks.data.cpu().numpy() - selected_masks = [] - for i in range(scores.shape[0]): - selected_masks.append(ohem_single(scores[i, :, :], gt_texts[i, :, :], training_masks[i, :, :])) - selected_masks = np.concatenate(selected_masks, 0) - selected_masks = torch.from_numpy(selected_masks).float() - return selected_masks - - -def dice_loss(input, target, mask): - input = torch.sigmoid(input) - - input = input.reshape(input.size()[0], -1) - target = target.reshape(target.size()[0], -1) - mask = mask.reshape(mask.size()[0], -1) - - input = input * mask - target = target * mask - - a = torch.sum(input * target, 1) - b = torch.sum(input * input, 1) + 0.001 - c = torch.sum(target * target, 1) + 0.001 - d = (2 * a) / (b + c) - dice_loss = torch.mean(d) - return 1 - dice_loss - - -def cal_text_score(texts, gt_texts, training_masks, running_metric_text): - training_masks = training_masks.data.cpu().numpy() - pred_text = torch.sigmoid(texts).data.cpu().numpy() * training_masks - - pred_text[pred_text <= 0.5] = 0 - pred_text[pred_text > 0.5] = 1 - pred_text = pred_text.astype(np.int32) - gt_text = gt_texts.data.cpu().numpy() * training_masks - gt_text = gt_text.astype(np.int32) - running_metric_text.update(gt_text, pred_text) - score_text, _ = running_metric_text.get_scores() - return score_text - - -def cal_kernel_score(kernels, gt_kernels, gt_texts, training_masks, running_metric_kernel): - mask = (gt_texts * training_masks).data.cpu().numpy() - kernel = kernels[:, -1, :, :] - gt_kernel = gt_kernels[:, -1, :, :] - pred_kernel = torch.sigmoid(kernel).data.cpu().numpy() - pred_kernel[pred_kernel <= 0.5] = 0 - pred_kernel[pred_kernel > 0.5] = 1 - pred_kernel = (pred_kernel * mask).astype(np.int32) - gt_kernel = gt_kernel.data.cpu().numpy() - gt_kernel = (gt_kernel * mask).astype(np.int32) - running_metric_kernel.update(gt_kernel, pred_kernel) - score_kernel, _ = running_metric_kernel.get_scores() - return score_kernel - - -def train(train_loader, model, criterion, optimizer, epoch, args, npu_per_node): - model.train() - - losses = AverageMeter() - running_metric_text = runningScore(2) - running_metric_kernel = runningScore(2) - - epoch_time = time.time() - batch_time = time.time() - for batch_idx, (imgs, gt_texts, gt_kernels, training_masks) in enumerate(train_loader): - loc = 'npu:{}'.format(args.npu) - imgs = imgs.to(loc, non_blocking=True) - gt_texts = gt_texts.to(loc, non_blocking=True) - gt_kernels = gt_kernels.to(loc, non_blocking=True) - training_masks = training_masks.to(loc, non_blocking=True) - - outputs = model(imgs) - texts = torch.index_select(outputs, 1, torch.tensor([0]).to(loc)).squeeze() - kernels = torch.index_select(outputs, 1, torch.tensor([1, 2, 3, 4, 5, 6]).to(loc)) - - selected_masks = ohem_batch(texts, gt_texts, training_masks) - selected_masks = selected_masks.to(loc, non_blocking=True) - - loss_text = criterion(texts, gt_texts, selected_masks) - - loss_kernels = [] - mask0 = torch.sigmoid(texts).data.cpu().numpy() - mask1 = training_masks.data.cpu().numpy() - selected_masks = ((mask0 > 0.5) & (mask1 > 0.5)).astype('float32') - selected_masks = torch.from_numpy(selected_masks).float() - selected_masks = selected_masks.to(loc, non_blocking=True) - for i in range(6): - kernel_i = torch.index_select(kernels, 1, torch.tensor([i]).to(loc)).squeeze() - gt_kernel_i = torch.index_select(gt_kernels, 1, torch.tensor([i]).to(loc)).squeeze() - loss_kernel_i = criterion(kernel_i, gt_kernel_i, selected_masks) - loss_kernels.append(loss_kernel_i) - loss_kernel = sum(loss_kernels) / len(loss_kernels) - - loss = 0.7 * loss_text + 0.3 * loss_kernel - losses.update(loss.item(), imgs.size(0)) - - optimizer.zero_grad() - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - optimizer.step() - score_text = cal_text_score(texts, gt_texts, training_masks, running_metric_text) - score_kernel = cal_kernel_score(kernels, gt_kernels, gt_texts, training_masks, running_metric_kernel) - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % npu_per_node == 0): - batch_time = time.time() - batch_time - output_log = '(epoch: {epoch:0>3d} {batch:0>2d}/{size}) | FPS: {fps:5.3f} | Loss : {lossv:.4f} | Acc_t: {acc: .4f} | IOU_t: {iou_t: .4f} | IOU_k: {iou_k: .4f}'.format( - epoch=epoch + 1, - batch=batch_idx + 1, - size=len(train_loader), - fps=npu_per_node * args.batch_size / batch_time, - lossv=losses.val, - acc=score_text['Mean Acc'], - iou_t=score_text['Mean IoU'], - iou_k=score_kernel['Mean IoU']) - batch_time = time.time() - print(output_log) - epoch_time = time.time() - epoch_time - - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % npu_per_node == 0): - output_log = '{epoch:0>3d}/{n_epoch} | LR: {lr:.5f} | FPS: {fps:.3f} | batch: {batch:.5f}s | Loss: {lossa:.4f} | Acc_t: {acc: .4f} | IOU_t: {iou_t: .4f} | IOU_k: {iou_k: .4f}'.format( - epoch=epoch + 1, - n_epoch=args.n_epoch, - lr=optimizer.param_groups[0]['lr'], - fps=npu_per_node * len(train_loader) * args.batch_size / epoch_time, - batch=epoch_time / len(train_loader), - lossa=losses.avg, - acc=score_text['Mean Acc'], - iou_t=score_text['Mean IoU'], - iou_k=score_kernel['Mean IoU']) - print(output_log) - sys.stdout.flush() - - return ( - losses.avg, score_text['Mean Acc'], score_kernel['Mean Acc'], score_text['Mean IoU'], score_kernel['Mean IoU']) - - -def adjust_learning_rate(args, optimizer, epoch): - warmup_length = 5 - if epoch < warmup_length: - lr = args.lr * (epoch + 1) / warmup_length - else: - e = epoch - warmup_length - es = args.n_epoch - warmup_length - lr = 0.5 * (1 + np.cos(np.pi * e / es)) * args.lr - for param_group in optimizer.param_groups: - param_group['lr'] = lr - - -def save_checkpoint(state, checkpoint='checkpoint', filename='checkpoint.pth.tar'): - if not os.path.isdir(checkpoint): - os.makedirs(checkpoint) - filepath = os.path.join(checkpoint, filename) - torch.save(state, filepath) - - -def main(npu, npu_per_node, args): - args.npu = args.process_device_map[npu] - print("[npu id:", args.npu, "]", "+++++++++++++++++++++++++++ before set KERNEL_NAME_ID:", - os.environ['KERNEL_NAME_ID']) - os.environ['KERNEL_NAME_ID'] = str(npu) - print("[npu id:", args.npu, "]", "+++++++++++++++++++++++++++KERNEL_NAME_ID:", os.environ['KERNEL_NAME_ID']) - - if args.npu is not None: - print("[npu id:", args.npu, "]", "Use NPU: {} for training".format(args.npu)) - - if args.checkpoint == '': - args.checkpoint = "checkpoints/ic15_%s_bs_%d_ep_%d" % (args.arch, args.batch_size, args.n_epoch) - if args.pretrain: - if 'synth' in args.pretrain: - args.checkpoint += "_pretrain_synth" - else: - args.checkpoint += "_pretrain_ic17" - if args.distributed: - if args.multiprocessing_distributed: - args.rank = args.rank * npu_per_node + npu - if args.device == 'npu': - dist.init_process_group(backend=args.dist_backend, - world_size=args.world_size, rank=args.rank) - loc = 'npu:{}'.format(args.npu) - torch.npu.set_device(loc) - args.batch_size = int(args.batch_size / npu_per_node) - args.workers = int((args.workers + npu_per_node - 1) / npu_per_node) - - print("[npu id:", args.npu, "]", "===============main_worker()=================") - print("[npu id:", args.npu, "]", args) - print("[npu id:", args.npu, "]", "===============main_worker()=================") - - print('checkpoint path: %s' % args.checkpoint) - print('init lr: %.8f' % args.lr) - print('schedule: ', args.schedule) - sys.stdout.flush() - - if not os.path.isdir(args.checkpoint): - os.makedirs(args.checkpoint) - - kernel_num = 7 - min_scale = 0.4 - start_epoch = 0 - - my_data = IC15Loader(args=args, - is_transform=True, - img_size=args.img_size, - kernel_num=kernel_num, - min_scale=min_scale) - if args.distributed: - train_sampler = torch.utils.data.distributed.DistributedSampler(my_data) - else: - train_sampler = None - - train_loader = MultiEpochsDataLoader( - my_data, - batch_size=args.batch_size, - shuffle=(train_sampler is None), - num_workers=args.workers, - drop_last=True, - pin_memory=True, - sampler=train_sampler) - - print("[npu id:", args.npu, "]", "=> creating model '{}'".format(args.arch)) - if args.arch == "resnet50": - model = models.resnet50(pretrained=True, num_classes=kernel_num) - elif args.arch == "resnet101": - model = models.resnet101(pretrained=True, num_classes=kernel_num) - elif args.arch == "resnet152": - model = models.resnet152(pretrained=True, num_classes=kernel_num) - - model = model.to(loc) - - if args.combine_sgd: - optimizer = apex.optimizers.NpuFusedSGD(model.parameters(), lr=args.lr, momentum=0.99, weight_decay=5e-4) - else: - optimizer = torch.optim.SGD(model.parameters(), lr=args.lr, momentum=0.99, weight_decay=5e-4) - - model, optimizer = amp.initialize(model, optimizer, - opt_level=args.opt_level, - keep_batchnorm_fp32=args.keep_batchnorm_fp32, - loss_scale=args.loss_scale, - combine_grad=args.combine_grad) - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.npu], broadcast_buffers=False) - - if args.pretrain: - print('Using pretrained model.') - assert os.path.isfile(args.pretrain), 'Error: no checkpoint directory found!' - checkpoint = torch.load(args.pretrain) - model.load_state_dict(checkpoint['state_dict']) - elif args.resume: - print('Resuming from checkpoint.') - assert os.path.isfile(args.resume), 'Error: no checkpoint directory found!' - checkpoint = torch.load(args.resume) - start_epoch = checkpoint['epoch'] - model.load_state_dict(checkpoint['state_dict']) - optimizer.load_state_dict(checkpoint['optimizer']) - amp.load_state_dict(checkpoint['amp']) - else: - print('Training from scratch.') - cudnn.benchmark = True - - best_model = {'loss': 0, 'acc': 0, 'iou': 0} - - for epoch in range(start_epoch, args.n_epoch): - if args.distributed: - train_sampler.set_epoch(epoch) - adjust_learning_rate(args, optimizer, epoch) - - train_loss, train_te_acc, train_ke_acc, train_te_iou, train_ke_iou = train(train_loader, model, dice_loss, - optimizer, epoch, - args, npu_per_node) - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % npu_per_node == 0): - if epoch > args.n_epoch - 6: - best_path = f'{args.remark}_{train_loss:.4f}_{train_te_acc:.4f}_{train_ke_iou:.4f}_{train_te_iou:.4f}_{epoch}.pth.tar' - save_checkpoint({ - 'epoch': epoch + 1, - 'state_dict': model.state_dict(), - 'lr': args.lr, - 'optimizer': optimizer.state_dict(), - 'amp': amp.state_dict(), - }, checkpoint='best', filename=best_path) - best_model['acc'] = train_te_acc - best_model['iou'] = train_te_iou - - -def device_id_to_process_device_map(device_list): - devices = device_list.split(",") - devices = [int(x) for x in devices] - devices.sort() - - process_device_map = dict() - for process_id, device_id in enumerate(devices): - process_device_map[process_id] = device_id - - return process_device_map - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Hyperparams') - parser.add_argument('--data-dir', nargs='?', type=str, default='PSENet_data', - help='point to the root data path of ICDAR') - parser.add_argument('--train_data', nargs='?', type=str, default='ICDAR2015', - help='indicate which dataset was used, ICDAR2015 or ICDAR2017') - parser.add_argument('--arch', nargs='?', type=str, default='resnet50') - parser.add_argument('--img_size', nargs='?', type=int, default=640, - help='Height of the input image') - parser.add_argument('--n_epoch', nargs='?', type=int, default=600, - help='# of the epochs') - parser.add_argument('--schedule', type=int, nargs='+', default=[200, 400], - help='Decrease learning rate at these epochs.') - parser.add_argument('--batch_size', nargs='?', type=int, default=16, - help='Batch Size') - parser.add_argument('--lr', nargs='?', type=float, default=1e-3, - help='Learning Rate') - parser.add_argument('--resume', nargs='?', type=str, default=None, - help='Path to previous saved model to restart from') - parser.add_argument('--pretrain', nargs='?', type=str, default=None, - help='Path to previous saved model to restart from') - parser.add_argument('--checkpoint', default='', type=str, metavar='PATH', - help='path to save checkpoint (default: checkpoint)') - parser.add_argument('--opt-level', type=str) - parser.add_argument('--keep-batchnorm-fp32', type=str, default=None) - parser.add_argument('--loss-scale', type=str, default=64) - parser.add_argument('--world-size', default=-1, type=int, - help='number of nodes for distributed training') - parser.add_argument('--seed', default=None, type=int, - help='seed for initializing training. ') - parser.add_argument('--device-list', default='0,1,2,3,4,5,6,7', type=str, help='device id list') - parser.add_argument('--multiprocessing-distributed', action='store_true', - help='Use multi-processing distributed training to launch ' - 'N processes per node, which has N NPUs. This is the ' - 'fastest way to use PyTorch for either single node or ' - 'multi node data parallel training') - parser.add_argument('--device', default='npu', type=str, - help='npu or gpu') - parser.add_argument('--dist-backend', default='nccl', type=str, - help='distributed backend') - parser.add_argument('--rank', default=-1, type=int, - help='node rank for distributed training') - parser.add_argument('--addr', default='10.136.181.127', type=str, - help='master addr') - parser.add_argument('--dist-url', default='env://', type=str, - help='url used to set up distributed training') - parser.add_argument('--port', default='8888', type=str) - parser.add_argument('-j', '--workers', default=32, type=int, metavar='N', - help='number of data loading workers (default: 4)') - parser.add_argument('--remark', default='', type=str, - help='remark. ') - parser.add_argument('--combine_grad', action='store_true', - help='whether to combine grad in apex') - parser.add_argument('--combine_sgd', action='store_true', - help='whether to use combined sgd instead of sgd') - - args = parser.parse_args() - - - if args.seed is not None: - random.seed(args.seed) - os.environ['PYTHONHASHSEED'] = str(args.seed) - np.random.seed(args.seed) - torch.manual_seed(args.seed) - torch.cuda.manual_seed(args.seed) - torch.cuda.manual_seed_all(args.seed) - cudnn.deterministic = True - torch.backends.cudnn.deterministic = True - torch.backends.cudnn.benchmark = False - - - args.distributed = args.world_size > 1 or args.multiprocessing_distributed - args.process_device_map = device_id_to_process_device_map(args.device_list) - - if args.device == 'npu': - npu_per_node = len(args.process_device_map) - else: - npu_per_node = torch.cuda.device_count() - - os.environ['MASTER_ADDR'] = args.addr - os.environ['MASTER_PORT'] = args.port - os.environ['KERNEL_NAME_ID'] = str(0) - print("+++++++++++++++++++++KERNEL_NAME_ID:", os.environ['KERNEL_NAME_ID']) - - args.world_size = npu_per_node * args.world_size - mp.spawn(main, nprocs=npu_per_node, args=(npu_per_node, args)) - +# Copyright [yyyy] [name of copyright owner] +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 argparse +import os +import random +import sys +import time +import warnings + +import numpy as np +import torch +import torch.backends.cudnn as cudnn +import torch.distributed as dist +import torch.multiprocessing as mp +import torch.nn.parallel +import torch.npu +import torch.utils.data.distributed +from apex import amp + +import apex +import models +from data_loader import IC15Loader +from metrics import runningScore +from multi_epochs_dataloader import MultiEpochsDataLoader +from util import AverageMeter + + + +def ohem_single(score, gt_text, training_mask): + pos_num = (int)(np.sum(gt_text > 0.5)) - (int)(np.sum((gt_text > 0.5) & (training_mask <= 0.5))) + + if pos_num == 0: + selected_mask = training_mask + selected_mask = selected_mask.reshape(1, selected_mask.shape[0], selected_mask.shape[1]).astype('float32') + return selected_mask + + neg_num = (int)(np.sum(gt_text <= 0.5)) + neg_num = (int)(min(pos_num * 3, neg_num)) + + if neg_num == 0: + selected_mask = training_mask + selected_mask = selected_mask.reshape(1, selected_mask.shape[0], selected_mask.shape[1]).astype('float32') + return selected_mask + + neg_score = score[gt_text <= 0.5] + neg_score_sorted = np.sort(-neg_score) + threshold = -neg_score_sorted[neg_num - 1] + + selected_mask = ((score >= threshold) | (gt_text > 0.5)) & (training_mask > 0.5) + selected_mask = selected_mask.reshape(1, selected_mask.shape[0], selected_mask.shape[1]).astype('float32') + return selected_mask + + +def ohem_batch(scores, gt_texts, training_masks): + scores = scores.data.cpu().numpy() + gt_texts = gt_texts.data.cpu().numpy() + training_masks = training_masks.data.cpu().numpy() + selected_masks = [] + for i in range(scores.shape[0]): + selected_masks.append(ohem_single(scores[i, :, :], gt_texts[i, :, :], training_masks[i, :, :])) + selected_masks = np.concatenate(selected_masks, 0) + selected_masks = torch.from_numpy(selected_masks).float() + return selected_masks + + +def dice_loss(input, target, mask): + input = torch.sigmoid(input) + + input = input.reshape(input.size()[0], -1) + target = target.reshape(target.size()[0], -1) + mask = mask.reshape(mask.size()[0], -1) + + input = input * mask + target = target * mask + + a = torch.sum(input * target, 1) + b = torch.sum(input * input, 1) + 0.001 + c = torch.sum(target * target, 1) + 0.001 + d = (2 * a) / (b + c) + dice_loss = torch.mean(d) + return 1 - dice_loss + + +def cal_text_score(texts, gt_texts, training_masks, running_metric_text): + training_masks = training_masks.data.cpu().numpy() + pred_text = torch.sigmoid(texts).data.cpu().numpy() * training_masks + + pred_text[pred_text <= 0.5] = 0 + pred_text[pred_text > 0.5] = 1 + pred_text = pred_text.astype(np.int32) + gt_text = gt_texts.data.cpu().numpy() * training_masks + gt_text = gt_text.astype(np.int32) + running_metric_text.update(gt_text, pred_text) + score_text, _ = running_metric_text.get_scores() + return score_text + + +def cal_kernel_score(kernels, gt_kernels, gt_texts, training_masks, running_metric_kernel): + mask = (gt_texts * training_masks).data.cpu().numpy() + kernel = kernels[:, -1, :, :] + gt_kernel = gt_kernels[:, -1, :, :] + pred_kernel = torch.sigmoid(kernel).data.cpu().numpy() + pred_kernel[pred_kernel <= 0.5] = 0 + pred_kernel[pred_kernel > 0.5] = 1 + pred_kernel = (pred_kernel * mask).astype(np.int32) + gt_kernel = gt_kernel.data.cpu().numpy() + gt_kernel = (gt_kernel * mask).astype(np.int32) + running_metric_kernel.update(gt_kernel, pred_kernel) + score_kernel, _ = running_metric_kernel.get_scores() + return score_kernel + + +def train(train_loader, model, criterion, optimizer, epoch, args, npu_per_node): + model.train() + + losses = AverageMeter() + running_metric_text = runningScore(2) + running_metric_kernel = runningScore(2) + + epoch_time = time.time() + batch_time = time.time() + for batch_idx, (imgs, gt_texts, gt_kernels, training_masks) in enumerate(train_loader): + loc = 'npu:{}'.format(args.npu) + imgs = imgs.to(loc, non_blocking=True) + gt_texts = gt_texts.to(loc, non_blocking=True) + gt_kernels = gt_kernels.to(loc, non_blocking=True) + training_masks = training_masks.to(loc, non_blocking=True) + + outputs = model(imgs) + texts = torch.index_select(outputs, 1, torch.tensor([0]).to(loc)).squeeze() + kernels = torch.index_select(outputs, 1, torch.tensor([1, 2, 3, 4, 5, 6]).to(loc)) + + selected_masks = ohem_batch(texts, gt_texts, training_masks) + selected_masks = selected_masks.to(loc, non_blocking=True) + + loss_text = criterion(texts, gt_texts, selected_masks) + + loss_kernels = [] + mask0 = torch.sigmoid(texts).data.cpu().numpy() + mask1 = training_masks.data.cpu().numpy() + selected_masks = ((mask0 > 0.5) & (mask1 > 0.5)).astype('float32') + selected_masks = torch.from_numpy(selected_masks).float() + selected_masks = selected_masks.to(loc, non_blocking=True) + for i in range(6): + kernel_i = torch.index_select(kernels, 1, torch.tensor([i]).to(loc)).squeeze() + gt_kernel_i = torch.index_select(gt_kernels, 1, torch.tensor([i]).to(loc)).squeeze() + loss_kernel_i = criterion(kernel_i, gt_kernel_i, selected_masks) + loss_kernels.append(loss_kernel_i) + loss_kernel = sum(loss_kernels) / len(loss_kernels) + + loss = 0.7 * loss_text + 0.3 * loss_kernel + losses.update(loss.item(), imgs.size(0)) + + optimizer.zero_grad() + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + optimizer.step() + score_text = cal_text_score(texts, gt_texts, training_masks, running_metric_text) + score_kernel = cal_kernel_score(kernels, gt_kernels, gt_texts, training_masks, running_metric_kernel) + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % npu_per_node == 0): + batch_time = time.time() - batch_time + output_log = '(epoch: {epoch:0>3d} {batch:0>2d}/{size}) | FPS: {fps:5.3f} | Loss : {lossv:.4f} | Acc_t: {acc: .4f} | IOU_t: {iou_t: .4f} | IOU_k: {iou_k: .4f}'.format( + epoch=epoch + 1, + batch=batch_idx + 1, + size=len(train_loader), + fps=npu_per_node * args.batch_size / batch_time, + lossv=losses.val, + acc=score_text['Mean Acc'], + iou_t=score_text['Mean IoU'], + iou_k=score_kernel['Mean IoU']) + batch_time = time.time() + print(output_log) + epoch_time = time.time() - epoch_time + + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % npu_per_node == 0): + output_log = '{epoch:0>3d}/{n_epoch} | LR: {lr:.5f} | FPS: {fps:.3f} | batch: {batch:.5f}s | Loss: {lossa:.4f} | Acc_t: {acc: .4f} | IOU_t: {iou_t: .4f} | IOU_k: {iou_k: .4f}'.format( + epoch=epoch + 1, + n_epoch=args.n_epoch, + lr=optimizer.param_groups[0]['lr'], + fps=npu_per_node * len(train_loader) * args.batch_size / epoch_time, + batch=epoch_time / len(train_loader), + lossa=losses.avg, + acc=score_text['Mean Acc'], + iou_t=score_text['Mean IoU'], + iou_k=score_kernel['Mean IoU']) + print(output_log) + sys.stdout.flush() + + return ( + losses.avg, score_text['Mean Acc'], score_kernel['Mean Acc'], score_text['Mean IoU'], score_kernel['Mean IoU']) + + +def adjust_learning_rate(args, optimizer, epoch): + warmup_length = 5 + if epoch < warmup_length: + lr = args.lr * (epoch + 1) / warmup_length + else: + e = epoch - warmup_length + es = args.n_epoch - warmup_length + lr = 0.5 * (1 + np.cos(np.pi * e / es)) * args.lr + for param_group in optimizer.param_groups: + param_group['lr'] = lr + + +def save_checkpoint(state, checkpoint='checkpoint', filename='checkpoint.pth.tar'): + if not os.path.isdir(checkpoint): + os.makedirs(checkpoint) + filepath = os.path.join(checkpoint, filename) + torch.save(state, filepath) + + +def main(npu, npu_per_node, args): + args.npu = args.process_device_map[npu] + print("[npu id:", args.npu, "]", "+++++++++++++++++++++++++++ before set KERNEL_NAME_ID:", + os.environ['KERNEL_NAME_ID']) + os.environ['KERNEL_NAME_ID'] = str(npu) + print("[npu id:", args.npu, "]", "+++++++++++++++++++++++++++KERNEL_NAME_ID:", os.environ['KERNEL_NAME_ID']) + + if args.npu is not None: + print("[npu id:", args.npu, "]", "Use NPU: {} for training".format(args.npu)) + + if args.checkpoint == '': + args.checkpoint = "checkpoints/ic15_%s_bs_%d_ep_%d" % (args.arch, args.batch_size, args.n_epoch) + if args.pretrain: + if 'synth' in args.pretrain: + args.checkpoint += "_pretrain_synth" + else: + args.checkpoint += "_pretrain_ic17" + if args.distributed: + if args.multiprocessing_distributed: + args.rank = args.rank * npu_per_node + npu + if args.device == 'npu': + dist.init_process_group(backend=args.dist_backend, + world_size=args.world_size, rank=args.rank) + loc = 'npu:{}'.format(args.npu) + torch.npu.set_device(loc) + args.batch_size = int(args.batch_size / npu_per_node) + args.workers = int((args.workers + npu_per_node - 1) / npu_per_node) + + print("[npu id:", args.npu, "]", "===============main_worker()=================") + print("[npu id:", args.npu, "]", args) + print("[npu id:", args.npu, "]", "===============main_worker()=================") + + print('checkpoint path: %s' % args.checkpoint) + print('init lr: %.8f' % args.lr) + print('schedule: ', args.schedule) + sys.stdout.flush() + + if not os.path.isdir(args.checkpoint): + os.makedirs(args.checkpoint) + + kernel_num = 7 + min_scale = 0.4 + start_epoch = 0 + + my_data = IC15Loader(args=args, + is_transform=True, + img_size=args.img_size, + kernel_num=kernel_num, + min_scale=min_scale) + if args.distributed: + train_sampler = torch.utils.data.distributed.DistributedSampler(my_data) + else: + train_sampler = None + + train_loader = MultiEpochsDataLoader( + my_data, + batch_size=args.batch_size, + shuffle=(train_sampler is None), + num_workers=args.workers, + drop_last=True, + pin_memory=True, + sampler=train_sampler) + + print("[npu id:", args.npu, "]", "=> creating model '{}'".format(args.arch)) + if args.arch == "resnet50": + model = models.resnet50(pretrained=True, num_classes=kernel_num) + elif args.arch == "resnet101": + model = models.resnet101(pretrained=True, num_classes=kernel_num) + elif args.arch == "resnet152": + model = models.resnet152(pretrained=True, num_classes=kernel_num) + + model = model.to(loc) + + if args.combine_sgd: + optimizer = apex.optimizers.NpuFusedSGD(model.parameters(), lr=args.lr, momentum=0.99, weight_decay=5e-4) + else: + optimizer = torch.optim.SGD(model.parameters(), lr=args.lr, momentum=0.99, weight_decay=5e-4) + + model, optimizer = amp.initialize(model, optimizer, + opt_level=args.opt_level, + keep_batchnorm_fp32=args.keep_batchnorm_fp32, + loss_scale=args.loss_scale, + combine_grad=args.combine_grad) + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.npu], broadcast_buffers=False) + + if args.pretrain: + print('Using pretrained model.') + assert os.path.isfile(args.pretrain), 'Error: no checkpoint directory found!' + checkpoint = torch.load(args.pretrain) + model.load_state_dict(checkpoint['state_dict']) + elif args.resume: + print('Resuming from checkpoint.') + assert os.path.isfile(args.resume), 'Error: no checkpoint directory found!' + checkpoint = torch.load(args.resume) + start_epoch = checkpoint['epoch'] + model.load_state_dict(checkpoint['state_dict']) + optimizer.load_state_dict(checkpoint['optimizer']) + amp.load_state_dict(checkpoint['amp']) + else: + print('Training from scratch.') + cudnn.benchmark = True + + best_model = {'loss': 0, 'acc': 0, 'iou': 0} + + for epoch in range(start_epoch, args.n_epoch): + if args.distributed: + train_sampler.set_epoch(epoch) + adjust_learning_rate(args, optimizer, epoch) + + train_loss, train_te_acc, train_ke_acc, train_te_iou, train_ke_iou = train(train_loader, model, dice_loss, + optimizer, epoch, + args, npu_per_node) + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % npu_per_node == 0): + if epoch > args.n_epoch - 6: + best_path = f'{args.remark}_{train_loss:.4f}_{train_te_acc:.4f}_{train_ke_iou:.4f}_{train_te_iou:.4f}_{epoch}.pth.tar' + save_checkpoint({ + 'epoch': epoch + 1, + 'state_dict': model.state_dict(), + 'lr': args.lr, + 'optimizer': optimizer.state_dict(), + 'amp': amp.state_dict(), + }, checkpoint='best', filename=best_path) + best_model['acc'] = train_te_acc + best_model['iou'] = train_te_iou + + +def device_id_to_process_device_map(device_list): + devices = device_list.split(",") + devices = [int(x) for x in devices] + devices.sort() + + process_device_map = dict() + for process_id, device_id in enumerate(devices): + process_device_map[process_id] = device_id + + return process_device_map + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Hyperparams') + parser.add_argument('--data-dir', nargs='?', type=str, default='PSENet_data', + help='point to the root data path of ICDAR') + parser.add_argument('--train_data', nargs='?', type=str, default='ICDAR2015', + help='indicate which dataset was used, ICDAR2015 or ICDAR2017') + parser.add_argument('--arch', nargs='?', type=str, default='resnet50') + parser.add_argument('--img_size', nargs='?', type=int, default=640, + help='Height of the input image') + parser.add_argument('--n_epoch', nargs='?', type=int, default=600, + help='# of the epochs') + parser.add_argument('--schedule', type=int, nargs='+', default=[200, 400], + help='Decrease learning rate at these epochs.') + parser.add_argument('--batch_size', nargs='?', type=int, default=16, + help='Batch Size') + parser.add_argument('--lr', nargs='?', type=float, default=1e-3, + help='Learning Rate') + parser.add_argument('--resume', nargs='?', type=str, default=None, + help='Path to previous saved model to restart from') + parser.add_argument('--pretrain', nargs='?', type=str, default=None, + help='Path to previous saved model to restart from') + parser.add_argument('--checkpoint', default='', type=str, metavar='PATH', + help='path to save checkpoint (default: checkpoint)') + parser.add_argument('--opt-level', type=str) + parser.add_argument('--keep-batchnorm-fp32', type=str, default=None) + parser.add_argument('--loss-scale', type=str, default=64) + parser.add_argument('--world-size', default=-1, type=int, + help='number of nodes for distributed training') + parser.add_argument('--seed', default=None, type=int, + help='seed for initializing training. ') + parser.add_argument('--device-list', default='0,1,2,3,4,5,6,7', type=str, help='device id list') + parser.add_argument('--multiprocessing-distributed', action='store_true', + help='Use multi-processing distributed training to launch ' + 'N processes per node, which has N NPUs. This is the ' + 'fastest way to use PyTorch for either single node or ' + 'multi node data parallel training') + parser.add_argument('--device', default='npu', type=str, + help='npu or gpu') + parser.add_argument('--dist-backend', default='nccl', type=str, + help='distributed backend') + parser.add_argument('--rank', default=-1, type=int, + help='node rank for distributed training') + parser.add_argument('--addr', default='10.136.181.127', type=str, + help='master addr') + parser.add_argument('--dist-url', default='env://', type=str, + help='url used to set up distributed training') + parser.add_argument('--port', default='8888', type=str) + parser.add_argument('-j', '--workers', default=32, type=int, metavar='N', + help='number of data loading workers (default: 4)') + parser.add_argument('--remark', default='', type=str, + help='remark. ') + parser.add_argument('--combine_grad', action='store_true', + help='whether to combine grad in apex') + parser.add_argument('--combine_sgd', action='store_true', + help='whether to use combined sgd instead of sgd') + + args = parser.parse_args() + + + if args.seed is not None: + random.seed(args.seed) + os.environ['PYTHONHASHSEED'] = str(args.seed) + np.random.seed(args.seed) + torch.manual_seed(args.seed) + torch.cuda.manual_seed(args.seed) + torch.cuda.manual_seed_all(args.seed) + cudnn.deterministic = True + torch.backends.cudnn.deterministic = True + torch.backends.cudnn.benchmark = False + + + args.distributed = args.world_size > 1 or args.multiprocessing_distributed + args.process_device_map = device_id_to_process_device_map(args.device_list) + + if args.device == 'npu': + npu_per_node = len(args.process_device_map) + else: + npu_per_node = torch.cuda.device_count() + + os.environ['MASTER_ADDR'] = args.addr + os.environ['MASTER_PORT'] = args.port + os.environ['KERNEL_NAME_ID'] = str(0) + print("+++++++++++++++++++++KERNEL_NAME_ID:", os.environ['KERNEL_NAME_ID']) + + args.world_size = npu_per_node * args.world_size + mp.spawn(main, nprocs=npu_per_node, args=(npu_per_node, args)) + diff --git a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/README.md b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/README.md index 4d75995acf..05b6553c12 100644 --- a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/README.md +++ b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/README.md @@ -1,22 +1,22 @@ -# Shape Robust Text Detection with Progressive Scale Expansion Network - -## 准备数据集 -1. 下载并解压训练集和测试集图片数据 -2. 按顺序对文件夹进行组织 -``` -./data_dir -./data_dir/ICDAR -./data_dir/ICDAR/Challenge -./data_dir/ICDAR/Challenge/ch4_training_images -./data_dir/ICDAR/Challenge/ch4_training_localization_transcription_gt -./data_dir/ICDAR/Challenge/ch4_test_images -./data_dir/ICDAR/Challenge/ch4_test_localization_transcription_gt -``` - - -## NPU -进入NPU/src目录,查看相关README文件 - -## 模型测试 -进入NPU/test目录,查看相关README文件 - +# Shape Robust Text Detection with Progressive Scale Expansion Network + +## 准备数据集 +1. 下载并解压训练集和测试集图片数据 +2. 按顺序对文件夹进行组织 +``` +./data_dir +./data_dir/ICDAR +./data_dir/ICDAR/Challenge +./data_dir/ICDAR/Challenge/ch4_training_images +./data_dir/ICDAR/Challenge/ch4_training_localization_transcription_gt +./data_dir/ICDAR/Challenge/ch4_test_images +./data_dir/ICDAR/Challenge/ch4_test_localization_transcription_gt +``` + + +## NPU +进入NPU/src目录,查看相关README文件 + +## 模型测试 +进入NPU/test目录,查看相关README文件 + diff --git a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/test/train_full_1p.sh b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/test/train_full_1p.sh index d6807a0811..19d0be5c36 100644 --- a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/test/train_full_1p.sh +++ b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/test/train_full_1p.sh @@ -1,161 +1,161 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -#export ASCEND_SLOG_PRINT_TO_STDOUT=1 - -#集合通信参数,不需要修改 -export HCCL_WHITELIST_DISABLE=1 -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 -# source env.sh -RANK_SIZE=8 -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="PSENet_for_PyTorch" -#训练epoch -train_epochs=1 -#训练batch_size -batch_size=16 -#训练step -train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.045 - - - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -python3 ${cur_path}/../NPU/src/train_ic15.py \ - --lr 0.001 \ - --dist-backend 'hccl' \ - --rank 0 \ - --workers 32 \ - --multiprocessing-distributed \ - --world-size 1 \ - --batch_size $batch_size \ - --device npu \ - --opt-level O2 \ - --loss-scale 64 \ - --addr=$(hostname -I |awk '{print $1}') \ - --seed 16 \ - --n_epoch $train_epochs \ - --data-dir $data_path \ - --port 8272 \ - --schedule 200 400 \ - --device-list $ASCEND_DEVICE_ID \ - --remark 1p \ - --combine_grad \ - --combine_sgd > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - - - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep 'epoch' ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'FPS:' '{print $2}'|awk '{print $1}'|awk 'NR>3'|awk '{sum+=$1} END {print sum/NR}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep -a '* Acc@1' train_0.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` - -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep 'epoch' $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}' |awk '{print $2}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +#export ASCEND_SLOG_PRINT_TO_STDOUT=1 + +#集合通信参数,不需要修改 +export HCCL_WHITELIST_DISABLE=1 +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 +# source env.sh +RANK_SIZE=8 +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="PSENet_for_PyTorch" +#训练epoch +train_epochs=1 +#训练batch_size +batch_size=16 +#训练step +train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.045 + + + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +python3 ${cur_path}/../NPU/src/train_ic15.py \ + --lr 0.001 \ + --dist-backend 'hccl' \ + --rank 0 \ + --workers 32 \ + --multiprocessing-distributed \ + --world-size 1 \ + --batch_size $batch_size \ + --device npu \ + --opt-level O2 \ + --loss-scale 64 \ + --addr=$(hostname -I |awk '{print $1}') \ + --seed 16 \ + --n_epoch $train_epochs \ + --data-dir $data_path \ + --port 8272 \ + --schedule 200 400 \ + --device-list $ASCEND_DEVICE_ID \ + --remark 1p \ + --combine_grad \ + --combine_sgd > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + + + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep 'epoch' ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'FPS:' '{print $2}'|awk '{print $1}'|awk 'NR>3'|awk '{sum+=$1} END {print sum/NR}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep -a '* Acc@1' train_0.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` + +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep 'epoch' $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}' |awk '{print $2}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/test/train_full_8p.sh b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/test/train_full_8p.sh index 28acc0d3be..a0155a3125 100644 --- a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/test/train_full_8p.sh +++ b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/test/train_full_8p.sh @@ -1,159 +1,159 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -#export ASCEND_SLOG_PRINT_TO_STDOUT=1 - -#集合通信参数,不需要修改 -export HCCL_WHITELIST_DISABLE=1 -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 -RANK_SIZE=8 -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="PSENet_ID0102_for_PyTorch" -#训练epoch -train_epochs=600 -#训练batch_size -batch_size=32 -#训练step -train_steps= -#学习率 -learning_rate=0.045 - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - - - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -python3 ${cur_path}/../NPU/src/train_ic15_8p.py \ - --lr 0.004 \ - --rank 0 \ - --dist-backend 'hccl' \ - --workers 32 \ - --multiprocessing-distributed \ - --world-size 1 \ - --batch_size $batch_size \ - --device npu \ - --opt-level O2 \ - --loss-scale 64 \ - --addr=$(hostname -I |awk '{print $1}') \ - --seed 16 \ - --n_epoch $train_epochs \ - --data-dir $data_path \ - --port 8272 \ - --remark 8p \ - --device-list '0,1,2,3,4,5,6,7' \ - --combine_grad \ - --combine_sgd > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - - - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep 'epoch:' ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'FPS:' '{print $2}'|awk '{print $1}'|awk 'NR>3'|awk '{sum+=$1} END {print sum/NR}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -train_accuracy=`grep -a 'Acc_t:' ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk 'END {print}'|awk -F "Acc_t:" '{print $NF}'|awk -F " " '{print $1}'` - -#打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep 'epoch:' $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}' |awk '{print $2}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +#export ASCEND_SLOG_PRINT_TO_STDOUT=1 + +#集合通信参数,不需要修改 +export HCCL_WHITELIST_DISABLE=1 +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 +RANK_SIZE=8 +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="PSENet_ID0102_for_PyTorch" +#训练epoch +train_epochs=600 +#训练batch_size +batch_size=32 +#训练step +train_steps= +#学习率 +learning_rate=0.045 + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + + + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +python3 ${cur_path}/../NPU/src/train_ic15_8p.py \ + --lr 0.004 \ + --rank 0 \ + --dist-backend 'hccl' \ + --workers 32 \ + --multiprocessing-distributed \ + --world-size 1 \ + --batch_size $batch_size \ + --device npu \ + --opt-level O2 \ + --loss-scale 64 \ + --addr=$(hostname -I |awk '{print $1}') \ + --seed 16 \ + --n_epoch $train_epochs \ + --data-dir $data_path \ + --port 8272 \ + --remark 8p \ + --device-list '0,1,2,3,4,5,6,7' \ + --combine_grad \ + --combine_sgd > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + + + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep 'epoch:' ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'FPS:' '{print $2}'|awk '{print $1}'|awk 'NR>3'|awk '{sum+=$1} END {print sum/NR}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +train_accuracy=`grep -a 'Acc_t:' ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk 'END {print}'|awk -F "Acc_t:" '{print $NF}'|awk -F " " '{print $1}'` + +#打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep 'epoch:' $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}' |awk '{print $2}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/test/train_performance_1p.sh b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/test/train_performance_1p.sh index 0bc1242e53..301da8cd34 100644 --- a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/test/train_performance_1p.sh +++ b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/test/train_performance_1p.sh @@ -1,160 +1,160 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -#export ASCEND_SLOG_PRINT_TO_STDOUT=1 - -#集合通信参数,不需要修改 -export HCCL_WHITELIST_DISABLE=1 -export RANK_SIZE=1 -export JOB_ID=10087 -RANK_ID_START=0 -# source env.sh -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="PSENet_ID0102_for_PyTorch" -#训练epoch -train_epochs=1 -#训练batch_size -batch_size=16 -#训练step -train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.045 - - - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -python3 ${cur_path}/../NPU/src/train_ic15.py \ - --lr 0.001 \ - --dist-backend 'hccl' \ - --rank 0 \ - --workers 32 \ - --multiprocessing-distributed \ - --world-size 1 \ - --batch_size $batch_size \ - --device npu \ - --opt-level O2 \ - --loss-scale 64 \ - --addr=$(hostname -I |awk '{print $1}') \ - --seed 16 \ - --n_epoch $train_epochs \ - --data-dir $data_path \ - --port 8272 \ - --schedule 200 400 \ - --device-list $ASCEND_DEVICE_ID \ - --remark 1p \ - --combine_grad \ - --combine_sgd > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - - - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep 'epoch' ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'FPS:' '{print $2}'|awk '{print $1}'|awk 'NR>3'|awk '{sum+=$1} END {print sum/NR}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep -a '* Acc@1' train_0.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` - -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep 'epoch' $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}' |awk '{print $2}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +#export ASCEND_SLOG_PRINT_TO_STDOUT=1 + +#集合通信参数,不需要修改 +export HCCL_WHITELIST_DISABLE=1 +export RANK_SIZE=1 +export JOB_ID=10087 +RANK_ID_START=0 +# source env.sh +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="PSENet_ID0102_for_PyTorch" +#训练epoch +train_epochs=1 +#训练batch_size +batch_size=16 +#训练step +train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.045 + + + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +python3 ${cur_path}/../NPU/src/train_ic15.py \ + --lr 0.001 \ + --dist-backend 'hccl' \ + --rank 0 \ + --workers 32 \ + --multiprocessing-distributed \ + --world-size 1 \ + --batch_size $batch_size \ + --device npu \ + --opt-level O2 \ + --loss-scale 64 \ + --addr=$(hostname -I |awk '{print $1}') \ + --seed 16 \ + --n_epoch $train_epochs \ + --data-dir $data_path \ + --port 8272 \ + --schedule 200 400 \ + --device-list $ASCEND_DEVICE_ID \ + --remark 1p \ + --combine_grad \ + --combine_sgd > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + + + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep 'epoch' ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'FPS:' '{print $2}'|awk '{print $1}'|awk 'NR>3'|awk '{sum+=$1} END {print sum/NR}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep -a '* Acc@1' train_0.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` + +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep 'epoch' $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}' |awk '{print $2}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log diff --git a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/test/train_performance_8p.sh b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/test/train_performance_8p.sh index fe8659d2df..e0e8b1d3b0 100644 --- a/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/test/train_performance_8p.sh +++ b/PyTorch/built-in/cv/detection/PSENet_for_PyTorch/test/train_performance_8p.sh @@ -1,158 +1,158 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -#export ASCEND_SLOG_PRINT_TO_STDOUT=1 - -#集合通信参数,不需要修改 -export HCCL_WHITELIST_DISABLE=1 -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 -# source env.sh -#RANK_SIZE=8 -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="PSENet_ID0102_for_PyTorch" -#训练epoch -train_epochs=1 -#训练batch_size -batch_size=32 -#训练step -train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.045 - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - - - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -python3 ${cur_path}/../NPU/src/train_ic15_8p.py \ - --lr 0.004 \ - --dist-backend 'hccl' \ - --rank 0 \ - --workers 32 \ - --multiprocessing-distributed \ - --world-size 1 \ - --batch_size $batch_size \ - --device npu \ - --opt-level O2 \ - --loss-scale 64 \ - --addr=$(hostname -I |awk '{print $1}') \ - --seed 16 \ - --n_epoch $train_epochs \ - --data-dir $data_path \ - --port 8272 \ - --remark 8p \ - --combine_grad \ - --combine_sgd > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - - - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep 'epoch:' ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'FPS:' '{print $2}'|awk '{print $1}'|awk 'NR>3'|awk '{sum+=$1} END {print sum/NR}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep -a '* Acc@1' train_0.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` - -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep 'epoch:' $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}' |awk '{print $2}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +#export ASCEND_SLOG_PRINT_TO_STDOUT=1 + +#集合通信参数,不需要修改 +export HCCL_WHITELIST_DISABLE=1 +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 +# source env.sh +#RANK_SIZE=8 +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="PSENet_ID0102_for_PyTorch" +#训练epoch +train_epochs=1 +#训练batch_size +batch_size=32 +#训练step +train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.045 + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + + + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +python3 ${cur_path}/../NPU/src/train_ic15_8p.py \ + --lr 0.004 \ + --dist-backend 'hccl' \ + --rank 0 \ + --workers 32 \ + --multiprocessing-distributed \ + --world-size 1 \ + --batch_size $batch_size \ + --device npu \ + --opt-level O2 \ + --loss-scale 64 \ + --addr=$(hostname -I |awk '{print $1}') \ + --seed 16 \ + --n_epoch $train_epochs \ + --data-dir $data_path \ + --port 8272 \ + --remark 8p \ + --combine_grad \ + --combine_sgd > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + + + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep 'epoch:' ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'FPS:' '{print $2}'|awk '{print $1}'|awk 'NR>3'|awk '{sum+=$1} END {print sum/NR}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep -a '* Acc@1' train_0.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` + +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep 'epoch:' $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}' |awk '{print $2}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log diff --git a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/_functions.py b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/_functions.py index ebbcee0394..219b7ecd4a 100644 --- a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/_functions.py +++ b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/_functions.py @@ -1,93 +1,93 @@ -# Copyright (c) Open-MMLab. All rights reserved. -# -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 torch -from torch.nn.parallel._functions import _get_stream - - -def scatter(input, devices, streams=None): - """Scatters tensor across multiple GPUs.""" - if streams is None: - streams = [None] * len(devices) - - if isinstance(input, list): - chunk_size = (len(input) - 1) // len(devices) + 1 - outputs = [ - scatter(input[i], [devices[i // chunk_size]], - [streams[i // chunk_size]]) for i in range(len(input)) - ] - return outputs - elif isinstance(input, torch.Tensor): - output = input.contiguous() - # TODO: copy to a pinned buffer first (if copying from CPU) - stream = streams[0] if output.numel() > 0 else None - if devices != [-1]: - with torch.cuda.device(devices[0]), torch.cuda.stream(stream): - output = output.cuda(devices[0], non_blocking=True) - else: - pass - - return output - else: - raise Exception(f'Unknown type {type(input)}.') - - -def synchronize_stream(output, devices, streams): - if isinstance(output, list): - chunk_size = len(output) // len(devices) - for i in range(len(devices)): - for j in range(chunk_size): - synchronize_stream(output[i * chunk_size + j], [devices[i]], - [streams[i]]) - elif isinstance(output, torch.Tensor): - if output.numel() != 0: - with torch.cuda.device(devices[0]): - main_stream = torch.cuda.current_stream() - main_stream.wait_stream(streams[0]) - output.record_stream(main_stream) - else: - raise Exception(f'Unknown type {type(output)}.') - - -def get_input_device(input): - if isinstance(input, list): - for item in input: - input_device = get_input_device(item) - if input_device != -1: - return input_device - return -1 - elif isinstance(input, torch.Tensor): - return input.get_device() if input.is_cuda else -1 - else: - raise Exception(f'Unknown type {type(input)}.') - - -class Scatter: - - @staticmethod - def forward(target_gpus, input): - input_device = get_input_device(input) - streams = None - if input_device == -1 and target_gpus != [-1]: - # Perform CPU to GPU copies in a background stream - streams = [_get_stream(device) for device in target_gpus] - - outputs = scatter(input, target_gpus, streams) - # Synchronize with the copy stream - if streams is not None: - synchronize_stream(outputs, target_gpus, streams) - +# Copyright (c) Open-MMLab. All rights reserved. +# +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 torch +from torch.nn.parallel._functions import _get_stream + + +def scatter(input, devices, streams=None): + """Scatters tensor across multiple GPUs.""" + if streams is None: + streams = [None] * len(devices) + + if isinstance(input, list): + chunk_size = (len(input) - 1) // len(devices) + 1 + outputs = [ + scatter(input[i], [devices[i // chunk_size]], + [streams[i // chunk_size]]) for i in range(len(input)) + ] + return outputs + elif isinstance(input, torch.Tensor): + output = input.contiguous() + # TODO: copy to a pinned buffer first (if copying from CPU) + stream = streams[0] if output.numel() > 0 else None + if devices != [-1]: + with torch.cuda.device(devices[0]), torch.cuda.stream(stream): + output = output.cuda(devices[0], non_blocking=True) + else: + pass + + return output + else: + raise Exception(f'Unknown type {type(input)}.') + + +def synchronize_stream(output, devices, streams): + if isinstance(output, list): + chunk_size = len(output) // len(devices) + for i in range(len(devices)): + for j in range(chunk_size): + synchronize_stream(output[i * chunk_size + j], [devices[i]], + [streams[i]]) + elif isinstance(output, torch.Tensor): + if output.numel() != 0: + with torch.cuda.device(devices[0]): + main_stream = torch.cuda.current_stream() + main_stream.wait_stream(streams[0]) + output.record_stream(main_stream) + else: + raise Exception(f'Unknown type {type(output)}.') + + +def get_input_device(input): + if isinstance(input, list): + for item in input: + input_device = get_input_device(item) + if input_device != -1: + return input_device + return -1 + elif isinstance(input, torch.Tensor): + return input.get_device() if input.is_cuda else -1 + else: + raise Exception(f'Unknown type {type(input)}.') + + +class Scatter: + + @staticmethod + def forward(target_gpus, input): + input_device = get_input_device(input) + streams = None + if input_device == -1 and target_gpus != [-1]: + # Perform CPU to GPU copies in a background stream + streams = [_get_stream(device) for device in target_gpus] + + outputs = scatter(input, target_gpus, streams) + # Synchronize with the copy stream + if streams is not None: + synchronize_stream(outputs, target_gpus, streams) + return tuple(outputs) \ No newline at end of file diff --git a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/builder.py b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/builder.py index f61945bc98..0ae11773f3 100644 --- a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/builder.py +++ b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/builder.py @@ -1,69 +1,69 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 copy -import inspect - -import torch -import apex - -from ...utils import Registry, build_from_cfg - -OPTIMIZERS = Registry('optimizer') -OPTIMIZER_BUILDERS = Registry('optimizer builder') - - -def register_torch_optimizers(): - torch_optimizers = [] - for module_name in dir(torch.optim): - if module_name.startswith('__'): - continue - _optim = getattr(torch.optim, module_name) - if inspect.isclass(_optim) and issubclass(_optim, - torch.optim.Optimizer): - OPTIMIZERS.register_module()(_optim) - torch_optimizers.append(module_name) - - # add npu optimizer from apex - for module_name in dir(apex.optimizers): - if module_name.startswith('__'): - continue - _optim = getattr(apex.optimizers, module_name) - if inspect.isclass(_optim) and issubclass(_optim, - torch.optim.Optimizer): - OPTIMIZERS.register_module()(_optim) - torch_optimizers.append(module_name) - - return torch_optimizers - - -TORCH_OPTIMIZERS = register_torch_optimizers() - - -def build_optimizer_constructor(cfg): - return build_from_cfg(cfg, OPTIMIZER_BUILDERS) - - -def build_optimizer(model, cfg): - optimizer_cfg = copy.deepcopy(cfg) - constructor_type = optimizer_cfg.pop('constructor', - 'DefaultOptimizerConstructor') - paramwise_cfg = optimizer_cfg.pop('paramwise_cfg', None) - optim_constructor = build_optimizer_constructor( - dict( - type=constructor_type, - optimizer_cfg=optimizer_cfg, - paramwise_cfg=paramwise_cfg)) - optimizer = optim_constructor(model) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 copy +import inspect + +import torch +import apex + +from ...utils import Registry, build_from_cfg + +OPTIMIZERS = Registry('optimizer') +OPTIMIZER_BUILDERS = Registry('optimizer builder') + + +def register_torch_optimizers(): + torch_optimizers = [] + for module_name in dir(torch.optim): + if module_name.startswith('__'): + continue + _optim = getattr(torch.optim, module_name) + if inspect.isclass(_optim) and issubclass(_optim, + torch.optim.Optimizer): + OPTIMIZERS.register_module()(_optim) + torch_optimizers.append(module_name) + + # add npu optimizer from apex + for module_name in dir(apex.optimizers): + if module_name.startswith('__'): + continue + _optim = getattr(apex.optimizers, module_name) + if inspect.isclass(_optim) and issubclass(_optim, + torch.optim.Optimizer): + OPTIMIZERS.register_module()(_optim) + torch_optimizers.append(module_name) + + return torch_optimizers + + +TORCH_OPTIMIZERS = register_torch_optimizers() + + +def build_optimizer_constructor(cfg): + return build_from_cfg(cfg, OPTIMIZER_BUILDERS) + + +def build_optimizer(model, cfg): + optimizer_cfg = copy.deepcopy(cfg) + constructor_type = optimizer_cfg.pop('constructor', + 'DefaultOptimizerConstructor') + paramwise_cfg = optimizer_cfg.pop('paramwise_cfg', None) + optim_constructor = build_optimizer_constructor( + dict( + type=constructor_type, + optimizer_cfg=optimizer_cfg, + paramwise_cfg=paramwise_cfg)) + optimizer = optim_constructor(model) return optimizer \ No newline at end of file diff --git a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/data_parallel.py b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/data_parallel.py index c9d1e953e2..b3b45fa9bc 100644 --- a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/data_parallel.py +++ b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/data_parallel.py @@ -1,104 +1,104 @@ -# Copyright (c) Open-MMLab. All rights reserved. -# -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 itertools import chain - -from torch.nn.parallel import DataParallel - -from .scatter_gather import scatter_kwargs - - -class MMDataParallel(DataParallel): - """The DataParallel module that supports DataContainer. - - MMDataParallel has two main differences with PyTorch DataParallel: - - - It supports a custom type :class:`DataContainer` which allows more - flexible control of input data during both GPU and CPU inference. - - It implement two more APIs ``train_step()`` and ``val_step()``. - - Args: - module (:class:`nn.Module`): Module to be encapsulated. - device_ids (list[int]): Device IDS of modules to be scattered to. - Defaults to None when GPU is not available. - output_device (str | int): Device ID for output. Defaults to None. - dim (int): Dimension used to scatter the data. Defaults to 0. - """ - - def __init__(self, *args, dim=0, **kwargs): - super(MMDataParallel, self).__init__(*args, dim=dim, **kwargs) - self.dim = dim - - def forward(self, *inputs, **kwargs): - """Override the original forward function. - - The main difference lies in the CPU inference where the datas in - :class:`DataContainers` will still be gathered. - """ - if not self.device_ids: - # We add the following line thus the module could gather and - # convert data containers as those in GPU inference - inputs, kwargs = self.scatter(inputs, kwargs, [-1]) - return self.module(*inputs[0], **kwargs[0]) - else: - return super().forward(*inputs, **kwargs) - - def scatter(self, inputs, kwargs, device_ids): - return scatter_kwargs(inputs, kwargs, device_ids, dim=self.dim) - - def train_step(self, *inputs, **kwargs): - if not self.device_ids: - # We add the following line thus the module could gather and - # convert data containers as those in GPU inference - inputs, kwargs = self.scatter(inputs, kwargs, [-1]) - return self.module.train_step(*inputs[0], **kwargs[0]) - - assert len(self.device_ids) == 1, \ - ('MMDataParallel only supports single GPU training, if you need to' - ' train with multiple GPUs, please use MMDistributedDataParallel' - 'instead.') - - for t in chain(self.module.parameters(), self.module.buffers()): - if t.device != self.src_device_obj: - raise RuntimeError( - 'module must have its parameters and buffers ' - f'on device {self.src_device_obj} (device_ids[0]) but ' - f'found one of them on device: {t.device}') - - inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids) - return self.module.train_step(*inputs[0], **kwargs[0]) - - def val_step(self, *inputs, **kwargs): - if not self.device_ids: - # We add the following line thus the module could gather and - # convert data containers as those in GPU inference - inputs, kwargs = self.scatter(inputs, kwargs, [-1]) - return self.module.val_step(*inputs, **kwargs) - - assert len(self.device_ids) == 1, \ - ('MMDataParallel only supports single GPU training, if you need to' - ' train with multiple GPUs, please use MMDistributedDataParallel' - ' instead.') - - for t in chain(self.module.parameters(), self.module.buffers()): - if t.device != self.src_device_obj: - raise RuntimeError( - 'module must have its parameters and buffers ' - f'on device {self.src_device_obj} (device_ids[0]) but ' - f'found one of them on device: {t.device}') - - inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids) - return self.module.val_step(*inputs[0], **kwargs[0]) +# Copyright (c) Open-MMLab. All rights reserved. +# +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 itertools import chain + +from torch.nn.parallel import DataParallel + +from .scatter_gather import scatter_kwargs + + +class MMDataParallel(DataParallel): + """The DataParallel module that supports DataContainer. + + MMDataParallel has two main differences with PyTorch DataParallel: + + - It supports a custom type :class:`DataContainer` which allows more + flexible control of input data during both GPU and CPU inference. + - It implement two more APIs ``train_step()`` and ``val_step()``. + + Args: + module (:class:`nn.Module`): Module to be encapsulated. + device_ids (list[int]): Device IDS of modules to be scattered to. + Defaults to None when GPU is not available. + output_device (str | int): Device ID for output. Defaults to None. + dim (int): Dimension used to scatter the data. Defaults to 0. + """ + + def __init__(self, *args, dim=0, **kwargs): + super(MMDataParallel, self).__init__(*args, dim=dim, **kwargs) + self.dim = dim + + def forward(self, *inputs, **kwargs): + """Override the original forward function. + + The main difference lies in the CPU inference where the datas in + :class:`DataContainers` will still be gathered. + """ + if not self.device_ids: + # We add the following line thus the module could gather and + # convert data containers as those in GPU inference + inputs, kwargs = self.scatter(inputs, kwargs, [-1]) + return self.module(*inputs[0], **kwargs[0]) + else: + return super().forward(*inputs, **kwargs) + + def scatter(self, inputs, kwargs, device_ids): + return scatter_kwargs(inputs, kwargs, device_ids, dim=self.dim) + + def train_step(self, *inputs, **kwargs): + if not self.device_ids: + # We add the following line thus the module could gather and + # convert data containers as those in GPU inference + inputs, kwargs = self.scatter(inputs, kwargs, [-1]) + return self.module.train_step(*inputs[0], **kwargs[0]) + + assert len(self.device_ids) == 1, \ + ('MMDataParallel only supports single GPU training, if you need to' + ' train with multiple GPUs, please use MMDistributedDataParallel' + 'instead.') + + for t in chain(self.module.parameters(), self.module.buffers()): + if t.device != self.src_device_obj: + raise RuntimeError( + 'module must have its parameters and buffers ' + f'on device {self.src_device_obj} (device_ids[0]) but ' + f'found one of them on device: {t.device}') + + inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids) + return self.module.train_step(*inputs[0], **kwargs[0]) + + def val_step(self, *inputs, **kwargs): + if not self.device_ids: + # We add the following line thus the module could gather and + # convert data containers as those in GPU inference + inputs, kwargs = self.scatter(inputs, kwargs, [-1]) + return self.module.val_step(*inputs, **kwargs) + + assert len(self.device_ids) == 1, \ + ('MMDataParallel only supports single GPU training, if you need to' + ' train with multiple GPUs, please use MMDistributedDataParallel' + ' instead.') + + for t in chain(self.module.parameters(), self.module.buffers()): + if t.device != self.src_device_obj: + raise RuntimeError( + 'module must have its parameters and buffers ' + f'on device {self.src_device_obj} (device_ids[0]) but ' + f'found one of them on device: {t.device}') + + inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids) + return self.module.val_step(*inputs[0], **kwargs[0]) diff --git a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/dist_utils.py b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/dist_utils.py index 091b646869..efe19f5018 100644 --- a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/dist_utils.py +++ b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/dist_utils.py @@ -1,185 +1,185 @@ -# Copyright (c) Open-MMLab. All rights reserved. -# -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 functools -import os -import subprocess -from collections import OrderedDict - -import torch -import torch.multiprocessing as mp -from torch import distributed as dist -from torch._utils import (_flatten_dense_tensors, _take_tensors, - _unflatten_dense_tensors) - -from mmcv.utils import TORCH_VERSION - - -def init_dist(launcher, backend='nccl', **kwargs): - if mp.get_start_method(allow_none=True) is None: - mp.set_start_method('spawn') - if launcher == 'pytorch': - _init_dist_pytorch(backend, **kwargs) - elif launcher == 'mpi': - _init_dist_mpi(backend, **kwargs) - elif launcher == 'slurm': - _init_dist_slurm(backend, **kwargs) - else: - raise ValueError(f'Invalid launcher type: {launcher}') - - -def _init_dist_pytorch(backend, **kwargs): - # TODO: use local_rank instead of rank % num_gpus - rank = int(os.environ['RANK']) - offset = 0 if os.getenv('NPUID', None) is None else int(os.environ['NPUID']) - num_gpus = int(os.environ['RANK_SIZE']) - torch.npu.set_device((rank + offset) % num_gpus) - dist.init_process_group(backend=backend, world_size=num_gpus, rank=rank) - - -def _init_dist_mpi(backend, **kwargs): - # TODO: use local_rank instead of rank % num_gpus - rank = int(os.environ['OMPI_COMM_WORLD_RANK']) - num_gpus = torch.cuda.device_count() - torch.cuda.set_device(rank % num_gpus) - dist.init_process_group(backend=backend, **kwargs) - - -def _init_dist_slurm(backend, port=None): - """Initialize slurm distributed training environment. - If argument ``port`` is not specified, then the master port will be system - environment variable ``MASTER_PORT``. If ``MASTER_PORT`` is not in system - environment variable, then a default port ``29500`` will be used. - Args: - backend (str): Backend of torch.distributed. - port (int, optional): Master port. Defaults to None. - """ - proc_id = int(os.environ['SLURM_PROCID']) - ntasks = int(os.environ['SLURM_NTASKS']) - node_list = os.environ['SLURM_NODELIST'] - num_gpus = torch.cuda.device_count() - torch.cuda.set_device(proc_id % num_gpus) - addr = subprocess.getoutput( - f'scontrol show hostname {node_list} | head -n1') - # specify master port - if port is not None: - os.environ['MASTER_PORT'] = str(port) - elif 'MASTER_PORT' in os.environ: - pass # use MASTER_PORT in the environment variable - else: - # 29500 is torch.distributed default port - os.environ['MASTER_PORT'] = '29500' - # use MASTER_ADDR in the environment variable if it already exists - if 'MASTER_ADDR' not in os.environ: - os.environ['MASTER_ADDR'] = addr - os.environ['WORLD_SIZE'] = str(ntasks) - os.environ['LOCAL_RANK'] = str(proc_id % num_gpus) - os.environ['RANK'] = str(proc_id) - dist.init_process_group(backend=backend) - - -def get_dist_info(): - if TORCH_VERSION < '1.0': - initialized = dist._initialized - else: - if dist.is_available(): - initialized = dist.is_initialized() - else: - initialized = False - if initialized: - rank = dist.get_rank() - world_size = dist.get_world_size() - else: - rank = 0 - world_size = 1 - return rank, world_size - - -def master_only(func): - - @functools.wraps(func) - def wrapper(*args, **kwargs): - rank, _ = get_dist_info() - if rank == 0: - return func(*args, **kwargs) - - return wrapper - - -def allreduce_params(params, coalesce=True, bucket_size_mb=-1): - """Allreduce parameters. - Args: - params (list[torch.Parameters]): List of parameters or buffers of a - model. - coalesce (bool, optional): Whether allreduce parameters as a whole. - Defaults to True. - bucket_size_mb (int, optional): Size of bucket, the unit is MB. - Defaults to -1. - """ - _, world_size = get_dist_info() - if world_size == 1: - return - params = [param.data for param in params] - if coalesce: - _allreduce_coalesced(params, world_size, bucket_size_mb) - else: - for tensor in params: - dist.all_reduce(tensor.div_(world_size)) - - -def allreduce_grads(params, coalesce=True, bucket_size_mb=-1): - """Allreduce gradients. - Args: - params (list[torch.Parameters]): List of parameters of a model - coalesce (bool, optional): Whether allreduce parameters as a whole. - Defaults to True. - bucket_size_mb (int, optional): Size of bucket, the unit is MB. - Defaults to -1. - """ - grads = [ - param.grad.data for param in params - if param.requires_grad and param.grad is not None - ] - _, world_size = get_dist_info() - if world_size == 1: - return - if coalesce: - _allreduce_coalesced(grads, world_size, bucket_size_mb) - else: - for tensor in grads: - dist.all_reduce(tensor.div_(world_size)) - - -def _allreduce_coalesced(tensors, world_size, bucket_size_mb=-1): - if bucket_size_mb > 0: - bucket_size_bytes = bucket_size_mb * 1024 * 1024 - buckets = _take_tensors(tensors, bucket_size_bytes) - else: - buckets = OrderedDict() - for tensor in tensors: - tp = tensor.type() - if tp not in buckets: - buckets[tp] = [] - buckets[tp].append(tensor) - buckets = buckets.values() - - for bucket in buckets: - flat_tensors = _flatten_dense_tensors(bucket) - dist.all_reduce(flat_tensors) - flat_tensors.div_(world_size) - for tensor, synced in zip( - bucket, _unflatten_dense_tensors(flat_tensors, bucket)): +# Copyright (c) Open-MMLab. All rights reserved. +# +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 functools +import os +import subprocess +from collections import OrderedDict + +import torch +import torch.multiprocessing as mp +from torch import distributed as dist +from torch._utils import (_flatten_dense_tensors, _take_tensors, + _unflatten_dense_tensors) + +from mmcv.utils import TORCH_VERSION + + +def init_dist(launcher, backend='nccl', **kwargs): + if mp.get_start_method(allow_none=True) is None: + mp.set_start_method('spawn') + if launcher == 'pytorch': + _init_dist_pytorch(backend, **kwargs) + elif launcher == 'mpi': + _init_dist_mpi(backend, **kwargs) + elif launcher == 'slurm': + _init_dist_slurm(backend, **kwargs) + else: + raise ValueError(f'Invalid launcher type: {launcher}') + + +def _init_dist_pytorch(backend, **kwargs): + # TODO: use local_rank instead of rank % num_gpus + rank = int(os.environ['RANK']) + offset = 0 if os.getenv('NPUID', None) is None else int(os.environ['NPUID']) + num_gpus = int(os.environ['RANK_SIZE']) + torch.npu.set_device((rank + offset) % num_gpus) + dist.init_process_group(backend=backend, world_size=num_gpus, rank=rank) + + +def _init_dist_mpi(backend, **kwargs): + # TODO: use local_rank instead of rank % num_gpus + rank = int(os.environ['OMPI_COMM_WORLD_RANK']) + num_gpus = torch.cuda.device_count() + torch.cuda.set_device(rank % num_gpus) + dist.init_process_group(backend=backend, **kwargs) + + +def _init_dist_slurm(backend, port=None): + """Initialize slurm distributed training environment. + If argument ``port`` is not specified, then the master port will be system + environment variable ``MASTER_PORT``. If ``MASTER_PORT`` is not in system + environment variable, then a default port ``29500`` will be used. + Args: + backend (str): Backend of torch.distributed. + port (int, optional): Master port. Defaults to None. + """ + proc_id = int(os.environ['SLURM_PROCID']) + ntasks = int(os.environ['SLURM_NTASKS']) + node_list = os.environ['SLURM_NODELIST'] + num_gpus = torch.cuda.device_count() + torch.cuda.set_device(proc_id % num_gpus) + addr = subprocess.getoutput( + f'scontrol show hostname {node_list} | head -n1') + # specify master port + if port is not None: + os.environ['MASTER_PORT'] = str(port) + elif 'MASTER_PORT' in os.environ: + pass # use MASTER_PORT in the environment variable + else: + # 29500 is torch.distributed default port + os.environ['MASTER_PORT'] = '29500' + # use MASTER_ADDR in the environment variable if it already exists + if 'MASTER_ADDR' not in os.environ: + os.environ['MASTER_ADDR'] = addr + os.environ['WORLD_SIZE'] = str(ntasks) + os.environ['LOCAL_RANK'] = str(proc_id % num_gpus) + os.environ['RANK'] = str(proc_id) + dist.init_process_group(backend=backend) + + +def get_dist_info(): + if TORCH_VERSION < '1.0': + initialized = dist._initialized + else: + if dist.is_available(): + initialized = dist.is_initialized() + else: + initialized = False + if initialized: + rank = dist.get_rank() + world_size = dist.get_world_size() + else: + rank = 0 + world_size = 1 + return rank, world_size + + +def master_only(func): + + @functools.wraps(func) + def wrapper(*args, **kwargs): + rank, _ = get_dist_info() + if rank == 0: + return func(*args, **kwargs) + + return wrapper + + +def allreduce_params(params, coalesce=True, bucket_size_mb=-1): + """Allreduce parameters. + Args: + params (list[torch.Parameters]): List of parameters or buffers of a + model. + coalesce (bool, optional): Whether allreduce parameters as a whole. + Defaults to True. + bucket_size_mb (int, optional): Size of bucket, the unit is MB. + Defaults to -1. + """ + _, world_size = get_dist_info() + if world_size == 1: + return + params = [param.data for param in params] + if coalesce: + _allreduce_coalesced(params, world_size, bucket_size_mb) + else: + for tensor in params: + dist.all_reduce(tensor.div_(world_size)) + + +def allreduce_grads(params, coalesce=True, bucket_size_mb=-1): + """Allreduce gradients. + Args: + params (list[torch.Parameters]): List of parameters of a model + coalesce (bool, optional): Whether allreduce parameters as a whole. + Defaults to True. + bucket_size_mb (int, optional): Size of bucket, the unit is MB. + Defaults to -1. + """ + grads = [ + param.grad.data for param in params + if param.requires_grad and param.grad is not None + ] + _, world_size = get_dist_info() + if world_size == 1: + return + if coalesce: + _allreduce_coalesced(grads, world_size, bucket_size_mb) + else: + for tensor in grads: + dist.all_reduce(tensor.div_(world_size)) + + +def _allreduce_coalesced(tensors, world_size, bucket_size_mb=-1): + if bucket_size_mb > 0: + bucket_size_bytes = bucket_size_mb * 1024 * 1024 + buckets = _take_tensors(tensors, bucket_size_bytes) + else: + buckets = OrderedDict() + for tensor in tensors: + tp = tensor.type() + if tp not in buckets: + buckets[tp] = [] + buckets[tp].append(tensor) + buckets = buckets.values() + + for bucket in buckets: + flat_tensors = _flatten_dense_tensors(bucket) + dist.all_reduce(flat_tensors) + flat_tensors.div_(world_size) + for tensor, synced in zip( + bucket, _unflatten_dense_tensors(flat_tensors, bucket)): tensor.copy_(synced) \ No newline at end of file diff --git a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/distributed.py b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/distributed.py index 86ca4b123e..1927a48073 100644 --- a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/distributed.py +++ b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/distributed.py @@ -1,119 +1,119 @@ -# Copyright (c) Open-MMLab. All rights reserved. -# -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 torch -from torch.nn.parallel.distributed import (DistributedDataParallel, - _find_tensors) - -from mmcv import print_log -from mmcv.utils import TORCH_VERSION -from .scatter_gather import scatter_kwargs - - -class MMDistributedDataParallel(DistributedDataParallel): - """The DDP module that supports DataContainer. - - MMDDP has two main differences with PyTorch DDP: - - - It supports a custom type :class:`DataContainer` which allows more - flexible control of input data. - - It implement two APIs ``train_step()`` and ``val_step()``. - """ - - def scatter(self, inputs, kwargs, device_ids): - return scatter_kwargs(inputs, kwargs, device_ids, dim=self.dim) - - def train_step(self, *inputs, **kwargs): - """train_step() API for module wrapped by DistributedDataParallel. - - This method is basically the same as - ``DistributedDataParallel.forward()``, while replacing - ``self.module.forward()`` with ``self.module.train_step()``. - It is compatible with PyTorch 1.1 - 1.5. - """ - - # In PyTorch >= 1.7, ``reducer._rebuild_buckets()`` is moved from the - # end of backward to the beginning of forward. - if (TORCH_VERSION >= '1.7' and 'parrots' - not in TORCH_VERSION) and self.reducer._rebuild_buckets(): - print_log( - 'Reducer buckets have been rebuilt in this iteration.', - logger='mmcv') - - if getattr(self, 'require_forward_param_sync', True): - self._sync_params() - if self.device_ids and False: - inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids) - if len(self.device_ids) == 1: - output = self.module.train_step(*inputs[0], **kwargs[0]) - else: - outputs = self.parallel_apply( - self._module_copies[:len(inputs)], inputs, kwargs) - output = self.gather(outputs, self.output_device) - else: - inputs, kwargs = self.scatter(inputs, kwargs, [-1]) - output = self.module.train_step(*inputs[0], **kwargs[0]) - - if torch.is_grad_enabled() and getattr( - self, 'require_backward_grad_sync', True): - if self.find_unused_parameters: - self.reducer.prepare_for_backward(list(_find_tensors(output))) - else: - self.reducer.prepare_for_backward([]) - else: - if TORCH_VERSION > '1.2': - self.require_forward_param_sync = False - return output - - def val_step(self, *inputs, **kwargs): - """val_step() API for module wrapped by DistributedDataParallel. - - This method is basically the same as - ``DistributedDataParallel.forward()``, while replacing - ``self.module.forward()`` with ``self.module.val_step()``. - It is compatible with PyTorch 1.1 - 1.5. - """ - # In PyTorch >= 1.7, ``reducer._rebuild_buckets()`` is moved from the - # end of backward to the beginning of forward. - if (TORCH_VERSION >= '1.7' and 'parrots' - not in TORCH_VERSION) and self.reducer._rebuild_buckets(): - print_log( - 'Reducer buckets have been rebuilt in this iteration.', - logger='mmcv') - - if getattr(self, 'require_forward_param_sync', True): - self._sync_params() - if self.device_ids: - inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids) - if len(self.device_ids) == 1: - output = self.module.val_step(*inputs[0], **kwargs[0]) - else: - outputs = self.parallel_apply( - self._module_copies[:len(inputs)], inputs, kwargs) - output = self.gather(outputs, self.output_device) - else: - output = self.module.val_step(*inputs, **kwargs) - - if torch.is_grad_enabled() and getattr( - self, 'require_backward_grad_sync', True): - if self.find_unused_parameters: - self.reducer.prepare_for_backward(list(_find_tensors(output))) - else: - self.reducer.prepare_for_backward([]) - else: - if TORCH_VERSION > '1.2': - self.require_forward_param_sync = False - return output +# Copyright (c) Open-MMLab. All rights reserved. +# +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 torch +from torch.nn.parallel.distributed import (DistributedDataParallel, + _find_tensors) + +from mmcv import print_log +from mmcv.utils import TORCH_VERSION +from .scatter_gather import scatter_kwargs + + +class MMDistributedDataParallel(DistributedDataParallel): + """The DDP module that supports DataContainer. + + MMDDP has two main differences with PyTorch DDP: + + - It supports a custom type :class:`DataContainer` which allows more + flexible control of input data. + - It implement two APIs ``train_step()`` and ``val_step()``. + """ + + def scatter(self, inputs, kwargs, device_ids): + return scatter_kwargs(inputs, kwargs, device_ids, dim=self.dim) + + def train_step(self, *inputs, **kwargs): + """train_step() API for module wrapped by DistributedDataParallel. + + This method is basically the same as + ``DistributedDataParallel.forward()``, while replacing + ``self.module.forward()`` with ``self.module.train_step()``. + It is compatible with PyTorch 1.1 - 1.5. + """ + + # In PyTorch >= 1.7, ``reducer._rebuild_buckets()`` is moved from the + # end of backward to the beginning of forward. + if (TORCH_VERSION >= '1.7' and 'parrots' + not in TORCH_VERSION) and self.reducer._rebuild_buckets(): + print_log( + 'Reducer buckets have been rebuilt in this iteration.', + logger='mmcv') + + if getattr(self, 'require_forward_param_sync', True): + self._sync_params() + if self.device_ids and False: + inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids) + if len(self.device_ids) == 1: + output = self.module.train_step(*inputs[0], **kwargs[0]) + else: + outputs = self.parallel_apply( + self._module_copies[:len(inputs)], inputs, kwargs) + output = self.gather(outputs, self.output_device) + else: + inputs, kwargs = self.scatter(inputs, kwargs, [-1]) + output = self.module.train_step(*inputs[0], **kwargs[0]) + + if torch.is_grad_enabled() and getattr( + self, 'require_backward_grad_sync', True): + if self.find_unused_parameters: + self.reducer.prepare_for_backward(list(_find_tensors(output))) + else: + self.reducer.prepare_for_backward([]) + else: + if TORCH_VERSION > '1.2': + self.require_forward_param_sync = False + return output + + def val_step(self, *inputs, **kwargs): + """val_step() API for module wrapped by DistributedDataParallel. + + This method is basically the same as + ``DistributedDataParallel.forward()``, while replacing + ``self.module.forward()`` with ``self.module.val_step()``. + It is compatible with PyTorch 1.1 - 1.5. + """ + # In PyTorch >= 1.7, ``reducer._rebuild_buckets()`` is moved from the + # end of backward to the beginning of forward. + if (TORCH_VERSION >= '1.7' and 'parrots' + not in TORCH_VERSION) and self.reducer._rebuild_buckets(): + print_log( + 'Reducer buckets have been rebuilt in this iteration.', + logger='mmcv') + + if getattr(self, 'require_forward_param_sync', True): + self._sync_params() + if self.device_ids: + inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids) + if len(self.device_ids) == 1: + output = self.module.val_step(*inputs[0], **kwargs[0]) + else: + outputs = self.parallel_apply( + self._module_copies[:len(inputs)], inputs, kwargs) + output = self.gather(outputs, self.output_device) + else: + output = self.module.val_step(*inputs, **kwargs) + + if torch.is_grad_enabled() and getattr( + self, 'require_backward_grad_sync', True): + if self.find_unused_parameters: + self.reducer.prepare_for_backward(list(_find_tensors(output))) + else: + self.reducer.prepare_for_backward([]) + else: + if TORCH_VERSION > '1.2': + self.require_forward_param_sync = False + return output diff --git a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/optimizer.py b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/optimizer.py index 9653c4e11b..5b574f66de 100644 --- a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/optimizer.py +++ b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/mmcv_need/optimizer.py @@ -1,162 +1,162 @@ -# Copyright (c) Open-MMLab. All rights reserved. -import copy -from collections import defaultdict -from itertools import chain - -from torch.nn.utils import clip_grad - -from ..dist_utils import allreduce_grads -from ..fp16_utils import LossScaler, wrap_fp16_model -from .hook import HOOKS, Hook -from apex import amp - -@HOOKS.register_module() -class OptimizerHook(Hook): - - def __init__(self, grad_clip=None): - self.grad_clip = grad_clip - - def clip_grads(self, params): - params = list( - filter(lambda p: p.requires_grad and p.grad is not None, params)) - if len(params) > 0: - return clip_grad.clip_grad_norm_(params, **self.grad_clip) - - def after_train_iter(self, runner): - runner.optimizer.zero_grad() - with amp.scale_loss(runner.outputs['loss'], runner.optimizer) as scaled_loss: - scaled_loss.backward() - if self.grad_clip is not None: - grad_norm = self.clip_grads(runner.model.parameters()) - if grad_norm is not None: - # Add grad norm to the logger - runner.log_buffer.update({'grad_norm': float(grad_norm)}, - runner.outputs['num_samples']) - runner.optimizer.step() - - -@HOOKS.register_module() -class Fp16OptimizerHook(OptimizerHook): - """FP16 optimizer hook. - - The steps of fp16 optimizer is as follows. - 1. Scale the loss value. - 2. BP in the fp16 model. - 2. Copy gradients from fp16 model to fp32 weights. - 3. Update fp32 weights. - 4. Copy updated parameters from fp32 weights to fp16 model. - - Refer to https://arxiv.org/abs/1710.03740 for more details. - - Args: - loss_scale (float | str | dict): Scale factor multiplied with loss. - If loss_scale is a float, static loss scaling will be used with - the specified scale. If loss_scale is a string, it must be - 'dynamic', then dynamic loss scaling will be used. - It can also be a dict containing arguments of LossScaler. - Defaults to 512. - """ - - def __init__(self, - grad_clip=None, - coalesce=True, - bucket_size_mb=-1, - loss_scale=512., - distributed=True): - self.grad_clip = grad_clip - self.coalesce = coalesce - self.bucket_size_mb = bucket_size_mb - self.distributed = distributed - if loss_scale == 'dynamic': - self.loss_scaler = LossScaler(mode='dynamic') - elif isinstance(loss_scale, float): - self.loss_scaler = LossScaler(init_scale=loss_scale, mode='static') - elif isinstance(loss_scale, dict): - self.loss_scaler = LossScaler(**loss_scale) - else: - raise ValueError('loss_scale must be of type float, dict, or ' - f'"dynamic", got {loss_scale}') - - def before_run(self, runner): - """Preparing steps before Mixed Precision Training. - - 1. Make a master copy of fp32 weights for optimization. - 2. Convert the main model from fp32 to fp16. - """ - # keep a copy of fp32 weights - old_groups = runner.optimizer.param_groups - runner.optimizer.param_groups = copy.deepcopy( - runner.optimizer.param_groups) - state = defaultdict(dict) - p_map = { - old_p: p - for old_p, p in zip( - chain(*(g['params'] for g in old_groups)), - chain(*(g['params'] for g in runner.optimizer.param_groups))) - } - for k, v in runner.optimizer.state.items(): - state[p_map[k]] = v - runner.optimizer.state = state - # convert model to fp16 - wrap_fp16_model(runner.model) - - def copy_grads_to_fp32(self, fp16_net, fp32_weights): - """Copy gradients from fp16 model to fp32 weight copy.""" - for fp32_param, fp16_param in zip(fp32_weights, fp16_net.parameters()): - if fp16_param.grad is not None: - if fp32_param.grad is None: - fp32_param.grad = fp32_param.data.new(fp32_param.size()) - fp32_param.grad.copy_(fp16_param.grad) - - def copy_params_to_fp16(self, fp16_net, fp32_weights): - """Copy updated params from fp32 weight copy to fp16 model.""" - for fp16_param, fp32_param in zip(fp16_net.parameters(), fp32_weights): - fp16_param.data.copy_(fp32_param.data) - - def after_train_iter(self, runner): - """Backward optimization steps for Mixed Precision Training. For - dynamic loss scaling, please refer `loss_scalar.py` - - 1. Scale the loss by a scale factor. - 2. Backward the loss to obtain the gradients (fp16). - 3. Copy gradients from the model to the fp32 weight copy. - 4. Scale the gradients back and update the fp32 weight copy. - 5. Copy back the params from fp32 weight copy to the fp16 model. - """ - # clear grads of last iteration - runner.model.zero_grad() - runner.optimizer.zero_grad() - # scale the loss value - scaled_loss = runner.outputs['loss'] * self.loss_scaler.loss_scale - scaled_loss.backward() - # copy fp16 grads in the model to fp32 params in the optimizer - - fp32_weights = [] - for param_group in runner.optimizer.param_groups: - fp32_weights += param_group['params'] - self.copy_grads_to_fp32(runner.model, fp32_weights) - # allreduce grads - if self.distributed: - allreduce_grads(fp32_weights, self.coalesce, self.bucket_size_mb) - - has_overflow = self.loss_scaler.has_overflow(fp32_weights) - # if has overflow, skip this iteration - if not has_overflow: - # scale the gradients back - for param in fp32_weights: - if param.grad is not None: - param.grad.div_(self.loss_scaler.loss_scale) - if self.grad_clip is not None: - grad_norm = self.clip_grads(fp32_weights) - if grad_norm is not None: - # Add grad norm to the logger - runner.log_buffer.update({'grad_norm': float(grad_norm)}, - runner.outputs['num_samples']) - # update fp32 params - runner.optimizer.step() - # copy fp32 params to the fp16 model - self.copy_params_to_fp16(runner.model, fp32_weights) - self.loss_scaler.update_scale(has_overflow) - if has_overflow: - runner.logger.warning('Check overflow, downscale loss scale ' - f'to {self.loss_scaler.cur_scale}') +# Copyright (c) Open-MMLab. All rights reserved. +import copy +from collections import defaultdict +from itertools import chain + +from torch.nn.utils import clip_grad + +from ..dist_utils import allreduce_grads +from ..fp16_utils import LossScaler, wrap_fp16_model +from .hook import HOOKS, Hook +from apex import amp + +@HOOKS.register_module() +class OptimizerHook(Hook): + + def __init__(self, grad_clip=None): + self.grad_clip = grad_clip + + def clip_grads(self, params): + params = list( + filter(lambda p: p.requires_grad and p.grad is not None, params)) + if len(params) > 0: + return clip_grad.clip_grad_norm_(params, **self.grad_clip) + + def after_train_iter(self, runner): + runner.optimizer.zero_grad() + with amp.scale_loss(runner.outputs['loss'], runner.optimizer) as scaled_loss: + scaled_loss.backward() + if self.grad_clip is not None: + grad_norm = self.clip_grads(runner.model.parameters()) + if grad_norm is not None: + # Add grad norm to the logger + runner.log_buffer.update({'grad_norm': float(grad_norm)}, + runner.outputs['num_samples']) + runner.optimizer.step() + + +@HOOKS.register_module() +class Fp16OptimizerHook(OptimizerHook): + """FP16 optimizer hook. + + The steps of fp16 optimizer is as follows. + 1. Scale the loss value. + 2. BP in the fp16 model. + 2. Copy gradients from fp16 model to fp32 weights. + 3. Update fp32 weights. + 4. Copy updated parameters from fp32 weights to fp16 model. + + Refer to https://arxiv.org/abs/1710.03740 for more details. + + Args: + loss_scale (float | str | dict): Scale factor multiplied with loss. + If loss_scale is a float, static loss scaling will be used with + the specified scale. If loss_scale is a string, it must be + 'dynamic', then dynamic loss scaling will be used. + It can also be a dict containing arguments of LossScaler. + Defaults to 512. + """ + + def __init__(self, + grad_clip=None, + coalesce=True, + bucket_size_mb=-1, + loss_scale=512., + distributed=True): + self.grad_clip = grad_clip + self.coalesce = coalesce + self.bucket_size_mb = bucket_size_mb + self.distributed = distributed + if loss_scale == 'dynamic': + self.loss_scaler = LossScaler(mode='dynamic') + elif isinstance(loss_scale, float): + self.loss_scaler = LossScaler(init_scale=loss_scale, mode='static') + elif isinstance(loss_scale, dict): + self.loss_scaler = LossScaler(**loss_scale) + else: + raise ValueError('loss_scale must be of type float, dict, or ' + f'"dynamic", got {loss_scale}') + + def before_run(self, runner): + """Preparing steps before Mixed Precision Training. + + 1. Make a master copy of fp32 weights for optimization. + 2. Convert the main model from fp32 to fp16. + """ + # keep a copy of fp32 weights + old_groups = runner.optimizer.param_groups + runner.optimizer.param_groups = copy.deepcopy( + runner.optimizer.param_groups) + state = defaultdict(dict) + p_map = { + old_p: p + for old_p, p in zip( + chain(*(g['params'] for g in old_groups)), + chain(*(g['params'] for g in runner.optimizer.param_groups))) + } + for k, v in runner.optimizer.state.items(): + state[p_map[k]] = v + runner.optimizer.state = state + # convert model to fp16 + wrap_fp16_model(runner.model) + + def copy_grads_to_fp32(self, fp16_net, fp32_weights): + """Copy gradients from fp16 model to fp32 weight copy.""" + for fp32_param, fp16_param in zip(fp32_weights, fp16_net.parameters()): + if fp16_param.grad is not None: + if fp32_param.grad is None: + fp32_param.grad = fp32_param.data.new(fp32_param.size()) + fp32_param.grad.copy_(fp16_param.grad) + + def copy_params_to_fp16(self, fp16_net, fp32_weights): + """Copy updated params from fp32 weight copy to fp16 model.""" + for fp16_param, fp32_param in zip(fp16_net.parameters(), fp32_weights): + fp16_param.data.copy_(fp32_param.data) + + def after_train_iter(self, runner): + """Backward optimization steps for Mixed Precision Training. For + dynamic loss scaling, please refer `loss_scalar.py` + + 1. Scale the loss by a scale factor. + 2. Backward the loss to obtain the gradients (fp16). + 3. Copy gradients from the model to the fp32 weight copy. + 4. Scale the gradients back and update the fp32 weight copy. + 5. Copy back the params from fp32 weight copy to the fp16 model. + """ + # clear grads of last iteration + runner.model.zero_grad() + runner.optimizer.zero_grad() + # scale the loss value + scaled_loss = runner.outputs['loss'] * self.loss_scaler.loss_scale + scaled_loss.backward() + # copy fp16 grads in the model to fp32 params in the optimizer + + fp32_weights = [] + for param_group in runner.optimizer.param_groups: + fp32_weights += param_group['params'] + self.copy_grads_to_fp32(runner.model, fp32_weights) + # allreduce grads + if self.distributed: + allreduce_grads(fp32_weights, self.coalesce, self.bucket_size_mb) + + has_overflow = self.loss_scaler.has_overflow(fp32_weights) + # if has overflow, skip this iteration + if not has_overflow: + # scale the gradients back + for param in fp32_weights: + if param.grad is not None: + param.grad.div_(self.loss_scaler.loss_scale) + if self.grad_clip is not None: + grad_norm = self.clip_grads(fp32_weights) + if grad_norm is not None: + # Add grad norm to the logger + runner.log_buffer.update({'grad_norm': float(grad_norm)}, + runner.outputs['num_samples']) + # update fp32 params + runner.optimizer.step() + # copy fp32 params to the fp16 model + self.copy_params_to_fp16(runner.model, fp32_weights) + self.loss_scaler.update_scale(has_overflow) + if has_overflow: + runner.logger.warning('Check overflow, downscale loss scale ' + f'to {self.loss_scaler.cur_scale}') diff --git a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/modelzoo_level.txt b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/test/train_performance_8p.sh b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/test/train_performance_8p.sh index db657d20a4..6eda17510e 100644 --- a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/test/train_performance_8p.sh +++ b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/test/train_performance_8p.sh @@ -1,180 +1,180 @@ -#!/bin/bash -#export DYNAMIC_OP='ADD#MUL' -#export PYTHONPATH=/autotest/CI_daily/PyTorch_retinanet_precision:$PYTHONPATH -export LANG=en_US.UTF-8 - -path=$(python3 -c "import sys;print(sys.path[-1])") -python_path=$(echo $path | awk -F 'lib' '{print $1}') -chmod -R 777 $python_path - -#当前路径,不需要修改 -cur_path=`pwd` - -#集合通信参数,不需要修改 -#保证rank table file 文件rank_table_8p.json存放在和test同级的configs目录下 -RANK_SIZE=8 -batch_size=64 -#RANK_TABLE_FILE=${cur_path}/../configs/rank_table_8p.json -RANK_ID_START=0 - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -export ASCEND_GLOBAL_LOG_LEVEL=3 - -#基础参数 需要模型审视修改 -#网络名称,同目录名称 -Network="RetinaNet_ID0427_for_PyTorch" -#训练epoch -train_epochs=2 - -#TF2.X独有,不需要修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False -autotune=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_full_8p.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is 0 - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --autotune whether to enable autotune, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --autotune* ]];then - autotune=`echo ${para#*=}` - export autotune=$autotune - mv $install_path/fwkacllib/data/rl/Ascend910/custom $install_path/fwkacllib/data/rl/Ascend910/custom_bak - mv $install_path/fwkacllib/data/tiling/Ascend910/custom $install_path/fwkacllib/data/tiling/Ascend910/custom_bak - autotune_dump_path=${cur_path}/output/autotune_dump - mkdir -p ${autotune_dump_path}/GA - mkdir -p ${autotune_dump_path}/rl - cp -rf $install_path/fwkacllib/data/tiling/Ascend910/custom ${autotune_dump_path}/GA/ - cp -rf $install_path/fwkacllib/data/rl/Ascend910/custom ${autotune_dump_path}/RL/ - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --bind_core* ]]; then - bind_core=`echo ${para#*=}` - name_bind="_bindcore" - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -#autotune时,先开启autotune执行单P训练,不需要修改 -if [[ $autotune == True ]]; then - train_full_1p.sh --autotune=$autotune --data_path=$data_path - wait - autotune=False - export autotune=$autotune -fi -mkdir -p $cur_path/../data -ln -snf $data_path/coco $cur_path/../data/ -cp train_retinanet_8p.sh $cur_path/../ - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#进入训练脚本目录 -cd $cur_path/../ -SIll=1 -for((RANK_ID=$RANK_ID_START;RANK_ID<$((SIll+RANK_ID_START));RANK_ID++)); -do - #设置环境变量,不需要修改 - echo "Device ID: $RANK_ID" - export RANK_ID=$RANK_ID - export ASCEND_DEVICE_ID=$RANK_ID - ASCEND_DEVICE_ID=$RANK_ID - - #创建DeviceID输出目录,不需要修改 - if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - fi - - #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 - bash train_retinanet_8p.sh > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 - - #python3 ./tools/train.py configs/retinanet/retinanet_r50_fpn_1x_coco.py \ - # --launcher pytorch \ - # --cfg-options optimizer.lr=0.038\ - # --seed 0 \ - # --gpu-ids 0 \ - # --no-validate \ - # --opt-level O1 \ - # > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & -done -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) -echo "E2E Training Duration sec : $e2e_time" - -#稳定性精度看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}${name_bind}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据 -grep "time:" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log > traintime.log -sed -i '1,10d' traintime.log -TrainingTime=`cat traintime.log | grep "time:" |awk '{sum+=$15} END {print sum/NR}'` -temp1=`echo "8 * ${batch_size}"|bc` -ActualFPS=`echo "scale=2;${temp1} / ${TrainingTime}"|bc` - -ActualLoss=`grep "loss:" traintime.log | awk 'END {print $23}'` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash +#export DYNAMIC_OP='ADD#MUL' +#export PYTHONPATH=/autotest/CI_daily/PyTorch_retinanet_precision:$PYTHONPATH +export LANG=en_US.UTF-8 + +path=$(python3 -c "import sys;print(sys.path[-1])") +python_path=$(echo $path | awk -F 'lib' '{print $1}') +chmod -R 777 $python_path + +#当前路径,不需要修改 +cur_path=`pwd` + +#集合通信参数,不需要修改 +#保证rank table file 文件rank_table_8p.json存放在和test同级的configs目录下 +RANK_SIZE=8 +batch_size=64 +#RANK_TABLE_FILE=${cur_path}/../configs/rank_table_8p.json +RANK_ID_START=0 + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +export ASCEND_GLOBAL_LOG_LEVEL=3 + +#基础参数 需要模型审视修改 +#网络名称,同目录名称 +Network="RetinaNet_ID0427_for_PyTorch" +#训练epoch +train_epochs=2 + +#TF2.X独有,不需要修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False +autotune=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_full_8p.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is 0 + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --autotune whether to enable autotune, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --autotune* ]];then + autotune=`echo ${para#*=}` + export autotune=$autotune + mv $install_path/fwkacllib/data/rl/Ascend910/custom $install_path/fwkacllib/data/rl/Ascend910/custom_bak + mv $install_path/fwkacllib/data/tiling/Ascend910/custom $install_path/fwkacllib/data/tiling/Ascend910/custom_bak + autotune_dump_path=${cur_path}/output/autotune_dump + mkdir -p ${autotune_dump_path}/GA + mkdir -p ${autotune_dump_path}/rl + cp -rf $install_path/fwkacllib/data/tiling/Ascend910/custom ${autotune_dump_path}/GA/ + cp -rf $install_path/fwkacllib/data/rl/Ascend910/custom ${autotune_dump_path}/RL/ + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --bind_core* ]]; then + bind_core=`echo ${para#*=}` + name_bind="_bindcore" + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +#autotune时,先开启autotune执行单P训练,不需要修改 +if [[ $autotune == True ]]; then + train_full_1p.sh --autotune=$autotune --data_path=$data_path + wait + autotune=False + export autotune=$autotune +fi +mkdir -p $cur_path/../data +ln -snf $data_path/coco $cur_path/../data/ +cp train_retinanet_8p.sh $cur_path/../ + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#进入训练脚本目录 +cd $cur_path/../ +SIll=1 +for((RANK_ID=$RANK_ID_START;RANK_ID<$((SIll+RANK_ID_START));RANK_ID++)); +do + #设置环境变量,不需要修改 + echo "Device ID: $RANK_ID" + export RANK_ID=$RANK_ID + export ASCEND_DEVICE_ID=$RANK_ID + ASCEND_DEVICE_ID=$RANK_ID + + #创建DeviceID输出目录,不需要修改 + if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + fi + + #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 + bash train_retinanet_8p.sh > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 + + #python3 ./tools/train.py configs/retinanet/retinanet_r50_fpn_1x_coco.py \ + # --launcher pytorch \ + # --cfg-options optimizer.lr=0.038\ + # --seed 0 \ + # --gpu-ids 0 \ + # --no-validate \ + # --opt-level O1 \ + # > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & +done +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) +echo "E2E Training Duration sec : $e2e_time" + +#稳定性精度看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}${name_bind}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据 +grep "time:" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log > traintime.log +sed -i '1,10d' traintime.log +TrainingTime=`cat traintime.log | grep "time:" |awk '{sum+=$15} END {print sum/NR}'` +temp1=`echo "8 * ${batch_size}"|bc` +ActualFPS=`echo "scale=2;${temp1} / ${TrainingTime}"|bc` + +ActualLoss=`grep "loss:" traintime.log | awk 'END {print $23}'` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log diff --git a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/test/train_retinanet_1p.sh b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/test/train_retinanet_1p.sh index e10b6ca629..e78d4cc0ff 100644 --- a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/test/train_retinanet_1p.sh +++ b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/test/train_retinanet_1p.sh @@ -1,29 +1,29 @@ -#source pt_set_env.sh -rm -rf kernel_meta/ -/usr/local/Ascend/driver/tools/msnpureport -d 0 -g error -/usr/local/Ascend/driver/tools/msnpureport -d 4 -g error -export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest - -export ASCEND_SLOG_PRINT_TO_STDOUT=0 -export ASCEND_GLOBAL_LOG_LEVEL=3 -export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest -export PTCOPY_ENABLE=1 -export TASK_QUEUE_ENABLE=1 -export DYNAMIC_OP="ADD#MUL" -export COMBINED_ENABLE=1 -export DYNAMIC_COMPILE_ENABLE=0 -export EXPERIMENTAL_DYNAMIC_PARTITION=0 -export ASCEND_GLOBAL_EVENT_ENABLE=0 -#export HCCL_WHITELIST_DISABLE=1 -#export SCALAR_TO_HOST_MEM=1 -#export RANK_SIZE=8 -PORT=29500 ./tools/dist_train.sh configs/retinanet/retinanet_r50_fpn_1x_coco.py 1 --cfg-options optimizer.lr=0.005 --seed 0 --gpu-ids 0 --no-validate --opt-level O1 - - -#export RANK=0 -#python3.7 ./tools/train.py configs/retinanet/retinanet_r50_fpn_1x_coco.py \ -# --cfg-options \ -# optimizer.lr=0.005 \ -# --seed 0 \ -# --gpu-ids 0 \ +#source pt_set_env.sh +rm -rf kernel_meta/ +/usr/local/Ascend/driver/tools/msnpureport -d 0 -g error +/usr/local/Ascend/driver/tools/msnpureport -d 4 -g error +export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest + +export ASCEND_SLOG_PRINT_TO_STDOUT=0 +export ASCEND_GLOBAL_LOG_LEVEL=3 +export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest +export PTCOPY_ENABLE=1 +export TASK_QUEUE_ENABLE=1 +export DYNAMIC_OP="ADD#MUL" +export COMBINED_ENABLE=1 +export DYNAMIC_COMPILE_ENABLE=0 +export EXPERIMENTAL_DYNAMIC_PARTITION=0 +export ASCEND_GLOBAL_EVENT_ENABLE=0 +#export HCCL_WHITELIST_DISABLE=1 +#export SCALAR_TO_HOST_MEM=1 +#export RANK_SIZE=8 +PORT=29500 ./tools/dist_train.sh configs/retinanet/retinanet_r50_fpn_1x_coco.py 1 --cfg-options optimizer.lr=0.005 --seed 0 --gpu-ids 0 --no-validate --opt-level O1 + + +#export RANK=0 +#python3.7 ./tools/train.py configs/retinanet/retinanet_r50_fpn_1x_coco.py \ +# --cfg-options \ +# optimizer.lr=0.005 \ +# --seed 0 \ +# --gpu-ids 0 \ # --opt-level O1 & \ No newline at end of file diff --git a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/test/train_retinanet_8p.sh b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/test/train_retinanet_8p.sh index 6bee47313b..888349cb6d 100644 --- a/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/test/train_retinanet_8p.sh +++ b/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch/test/train_retinanet_8p.sh @@ -1,47 +1,47 @@ -#source pt_set_env.sh -rm -rf kernel_meta/ -/usr/local/Ascend/driver/tools/msnpureport -d 0 -g error -/usr/local/Ascend/driver/tools/msnpureport -d 4 -g error -export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest - -export ASCEND_SLOG_PRINT_TO_STDOUT=0 -export ASCEND_GLOBAL_LOG_LEVEL=3 -export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest -export PTCOPY_ENABLE=1 -export TASK_QUEUE_ENABLE=1 -export DYNAMIC_OP="ADD#MUL" -export COMBINED_ENABLE=1 -export DYNAMIC_COMPILE_ENABLE=0 -export EXPERIMENTAL_DYNAMIC_PARTITION=0 -export ASCEND_GLOBAL_EVENT_ENABLE=0 -#export HCCL_WHITELIST_DISABLE=1 -#export SCALAR_TO_HOST_MEM=1 -#export RANK_SIZE=8 -PORT=29500 ./tools/dist_train.sh configs/retinanet/retinanet_r50_fpn_1x_coco.py 8 --cfg-options optimizer.lr=0.04 --seed 0 --gpu-ids 0 --no-validate --opt-level O1 - -#KERNEL_NUM=$(($(nproc)/8)) -#for((RANK_ID=0;RANK_ID 1: - mp.spawn(train_8p, nprocs=config.npus, args=(config.npus, config)) - else: - print("config.npus should be greater than 1.") - raise RuntimeError - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - - - # model hyper-parameters - parser.add_argument('--image_size', type=int, default=224) - parser.add_argument('--t', type=int, default=3, help='t for Recurrent step of R2U_Net or R2AttU_Net') - - # training hyper-parameters - parser.add_argument('--img_ch', type=int, default=3) - parser.add_argument('--output_ch', type=int, default=1) - parser.add_argument('--num_epochs', type=int, default=100) - parser.add_argument('--num_epochs_decay', type=int, default=70) - parser.add_argument('--batch_size', type=int, default=16) - parser.add_argument('--num_workers', type=int, default=8*8) - parser.add_argument('--lr', type=float, default=0.0002*8) - parser.add_argument('--beta1', type=float, default=0.5) # momentum1 in Adam - parser.add_argument('--beta2', type=float, default=0.999) # momentum2 in Adam - parser.add_argument('--augmentation_prob', type=float, default=0.4) - - parser.add_argument('--log_step', type=int, default=2) - parser.add_argument('--val_step', type=int, default=2) - - # misc - parser.add_argument('--mode', type=str, default='train') - parser.add_argument('--model_type', type=str, default='U_Net', help='U_Net/R2U_Net/AttU_Net/R2AttU_Net') - parser.add_argument('--data_path', type=str, default='./dataset/') - parser.add_argument('--result_path', type=str, default='./result_8p') - - parser.add_argument('--npus', type=int, default=8) - parser.add_argument('--use_apex', type=int, default=1) - parser.add_argument('--apex_level', type=str, default="O2") - parser.add_argument('--loss_scale', type=float, default=128.) - parser.add_argument('--seed', type=int, default=12345) - parser.add_argument('--world_size', type=int, default=1) - parser.add_argument('--dist_backend', type=str, default="hccl") - parser.add_argument('--display_freq', type=int, default=-1) - - config = parser.parse_args() - main(config) +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import argparse +import os +import random +import numpy as np +import torch.multiprocessing as mp +import torch +from solver_8p import train_8p + +def seed_everything(seed): + random.seed(seed) + os.environ["PYTHONHASHSEED"] = str(seed) + np.random.seed(seed) + torch.manual_seed(seed) + +def main(config): + if config.model_type not in ['U_Net','R2U_Net','AttU_Net','R2AttU_Net']: + print('ERROR!! model_type should be selected in U_Net/R2U_Net/AttU_Net/R2AttU_Net') + print('Your input for model_type was %s'%config.model_type) + return + + # Create directories if not exist + config.result_path = os.path.join(config.result_path,config.model_type) + if not os.path.exists(config.result_path): + os.makedirs(config.result_path) + + config.train_path = os.path.join(config.data_path, "train") + config.valid_path = os.path.join(config.data_path, "valid") + print(config) + + seed_everything(config.seed) + os.environ["MASTER_ADDR"] = "localhost" + os.environ["MASTER_PORT"] = "29504" + if config.npus > 1: + mp.spawn(train_8p, nprocs=config.npus, args=(config.npus, config)) + else: + print("config.npus should be greater than 1.") + raise RuntimeError + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + + + # model hyper-parameters + parser.add_argument('--image_size', type=int, default=224) + parser.add_argument('--t', type=int, default=3, help='t for Recurrent step of R2U_Net or R2AttU_Net') + + # training hyper-parameters + parser.add_argument('--img_ch', type=int, default=3) + parser.add_argument('--output_ch', type=int, default=1) + parser.add_argument('--num_epochs', type=int, default=100) + parser.add_argument('--num_epochs_decay', type=int, default=70) + parser.add_argument('--batch_size', type=int, default=16) + parser.add_argument('--num_workers', type=int, default=8*8) + parser.add_argument('--lr', type=float, default=0.0002*8) + parser.add_argument('--beta1', type=float, default=0.5) # momentum1 in Adam + parser.add_argument('--beta2', type=float, default=0.999) # momentum2 in Adam + parser.add_argument('--augmentation_prob', type=float, default=0.4) + + parser.add_argument('--log_step', type=int, default=2) + parser.add_argument('--val_step', type=int, default=2) + + # misc + parser.add_argument('--mode', type=str, default='train') + parser.add_argument('--model_type', type=str, default='U_Net', help='U_Net/R2U_Net/AttU_Net/R2AttU_Net') + parser.add_argument('--data_path', type=str, default='./dataset/') + parser.add_argument('--result_path', type=str, default='./result_8p') + + parser.add_argument('--npus', type=int, default=8) + parser.add_argument('--use_apex', type=int, default=1) + parser.add_argument('--apex_level', type=str, default="O2") + parser.add_argument('--loss_scale', type=float, default=128.) + parser.add_argument('--seed', type=int, default=12345) + parser.add_argument('--world_size', type=int, default=1) + parser.add_argument('--dist_backend', type=str, default="hccl") + parser.add_argument('--display_freq', type=int, default=-1) + + config = parser.parse_args() + main(config) diff --git a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/misc.py b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/misc.py index 8e4f3a65b1..73e81baaca 100644 --- a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/misc.py +++ b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/misc.py @@ -1,50 +1,50 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 100, fill = '█'): - """ - Call in a loop to create terminal progress bar - @params: - iteration - Required : current iteration (Int) - total - Required : total iterations (Int) - prefix - Optional : prefix string (Str) - suffix - Optional : suffix string (Str) - decimals - Optional : positive number of decimals in percent complete (Int) - length - Optional : character length of bar (Int) - fill - Optional : bar fill character (Str) - """ - percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total))) - filledLength = int(length * iteration // total) - bar = fill * filledLength + '-' * (length - filledLength) - print('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix), end = '\r') - # Print New Line on Complete - if iteration == total: +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 100, fill = '█'): + """ + Call in a loop to create terminal progress bar + @params: + iteration - Required : current iteration (Int) + total - Required : total iterations (Int) + prefix - Optional : prefix string (Str) + suffix - Optional : suffix string (Str) + decimals - Optional : positive number of decimals in percent complete (Int) + length - Optional : character length of bar (Int) + fill - Optional : bar fill character (Str) + """ + percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total))) + filledLength = int(length * iteration // total) + bar = fill * filledLength + '-' * (length - filledLength) + print('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix), end = '\r') + # Print New Line on Complete + if iteration == total: print() \ No newline at end of file diff --git a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/modelzoo_level.txt b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/network.py b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/network.py index eca56f5553..674e9bd583 100644 --- a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/network.py +++ b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/network.py @@ -1,456 +1,456 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -import torch -import torch.nn as nn -import torch.nn.functional as F -from torch.nn import init - -def init_weights(net, init_type='normal', gain=0.02): - def init_func(m): - classname = m.__class__.__name__ - if hasattr(m, 'weight') and (classname.find('Conv') != -1 or classname.find('Linear') != -1): - if init_type == 'normal': - init.normal_(m.weight.data, 0.0, gain) - elif init_type == 'xavier': - init.xavier_normal_(m.weight.data, gain=gain) - elif init_type == 'kaiming': - init.kaiming_normal_(m.weight.data, a=0, mode='fan_in') - elif init_type == 'orthogonal': - init.orthogonal_(m.weight.data, gain=gain) - else: - raise NotImplementedError('initialization method [%s] is not implemented' % init_type) - if hasattr(m, 'bias') and m.bias is not None: - init.constant_(m.bias.data, 0.0) - elif classname.find('BatchNorm2d') != -1: - init.normal_(m.weight.data, 1.0, gain) - init.constant_(m.bias.data, 0.0) - - print('initialize network with %s' % init_type) - net.apply(init_func) - -class conv_block(nn.Module): - def __init__(self,ch_in,ch_out): - super(conv_block,self).__init__() - self.conv = nn.Sequential( - nn.Conv2d(ch_in, ch_out, kernel_size=3,stride=1,padding=1,bias=True), - nn.BatchNorm2d(ch_out), - nn.ReLU(inplace=True), - nn.Conv2d(ch_out, ch_out, kernel_size=3,stride=1,padding=1,bias=True), - nn.BatchNorm2d(ch_out), - nn.ReLU(inplace=True) - ) - - - def forward(self,x): - x = self.conv(x) - return x - -class up_conv(nn.Module): - def __init__(self,ch_in,ch_out): - super(up_conv,self).__init__() - self.up = nn.Sequential( - nn.Upsample(scale_factor=2), - nn.Conv2d(ch_in,ch_out,kernel_size=3,stride=1,padding=1,bias=True), - nn.BatchNorm2d(ch_out), - nn.ReLU(inplace=True) - ) - - def forward(self,x): - x = self.up(x) - return x - -class Recurrent_block(nn.Module): - def __init__(self,ch_out,t=2): - super(Recurrent_block,self).__init__() - self.t = t - self.ch_out = ch_out - self.conv = nn.Sequential( - nn.Conv2d(ch_out,ch_out,kernel_size=3,stride=1,padding=1,bias=True), - nn.BatchNorm2d(ch_out), - nn.ReLU(inplace=True) - ) - - def forward(self,x): - for i in range(self.t): - - if i==0: - x1 = self.conv(x) - - x1 = self.conv(x+x1) - return x1 - -class RRCNN_block(nn.Module): - def __init__(self,ch_in,ch_out,t=2): - super(RRCNN_block,self).__init__() - self.RCNN = nn.Sequential( - Recurrent_block(ch_out,t=t), - Recurrent_block(ch_out,t=t) - ) - self.Conv_1x1 = nn.Conv2d(ch_in,ch_out,kernel_size=1,stride=1,padding=0) - - def forward(self,x): - x = self.Conv_1x1(x) - x1 = self.RCNN(x) - return x+x1 - - -class single_conv(nn.Module): - def __init__(self,ch_in,ch_out): - super(single_conv,self).__init__() - self.conv = nn.Sequential( - nn.Conv2d(ch_in, ch_out, kernel_size=3,stride=1,padding=1,bias=True), - nn.BatchNorm2d(ch_out), - nn.ReLU(inplace=True) - ) - - def forward(self,x): - x = self.conv(x) - return x - -class Attention_block(nn.Module): - def __init__(self,F_g,F_l,F_int): - super(Attention_block,self).__init__() - self.W_g = nn.Sequential( - nn.Conv2d(F_g, F_int, kernel_size=1,stride=1,padding=0,bias=True), - nn.BatchNorm2d(F_int) - ) - - self.W_x = nn.Sequential( - nn.Conv2d(F_l, F_int, kernel_size=1,stride=1,padding=0,bias=True), - nn.BatchNorm2d(F_int) - ) - - self.psi = nn.Sequential( - nn.Conv2d(F_int, 1, kernel_size=1,stride=1,padding=0,bias=True), - nn.BatchNorm2d(1), - nn.Sigmoid() - ) - - self.relu = nn.ReLU(inplace=True) - - def forward(self,g,x): - g1 = self.W_g(g) - x1 = self.W_x(x) - psi = self.relu(g1+x1) - psi = self.psi(psi) - - return x*psi - - -class U_Net(nn.Module): - def __init__(self,img_ch=3,output_ch=1): - super(U_Net,self).__init__() - - self.Maxpool = nn.MaxPool2d(kernel_size=2,stride=2) - - self.Conv1 = conv_block(ch_in=img_ch,ch_out=64) - self.Conv2 = conv_block(ch_in=64,ch_out=128) - self.Conv3 = conv_block(ch_in=128,ch_out=256) - self.Conv4 = conv_block(ch_in=256,ch_out=512) - self.Conv5 = conv_block(ch_in=512,ch_out=1024) - - self.Up5 = up_conv(ch_in=1024,ch_out=512) - self.Up_conv5 = conv_block(ch_in=1024, ch_out=512) - - self.Up4 = up_conv(ch_in=512,ch_out=256) - self.Up_conv4 = conv_block(ch_in=512, ch_out=256) - - self.Up3 = up_conv(ch_in=256,ch_out=128) - self.Up_conv3 = conv_block(ch_in=256, ch_out=128) - - self.Up2 = up_conv(ch_in=128,ch_out=64) - self.Up_conv2 = conv_block(ch_in=128, ch_out=64) - - self.Conv_1x1 = nn.Conv2d(64,output_ch,kernel_size=1,stride=1,padding=0) - - - def forward(self,x): - # encoding path - x1 = self.Conv1(x) - - x2 = self.Maxpool(x1) - x2 = self.Conv2(x2) - - x3 = self.Maxpool(x2) - x3 = self.Conv3(x3) - - x4 = self.Maxpool(x3) - x4 = self.Conv4(x4) - - x5 = self.Maxpool(x4) - x5 = self.Conv5(x5) - - # decoding + concat path - d5 = self.Up5(x5) - d5 = torch.cat((x4,d5),dim=1) - - d5 = self.Up_conv5(d5) - - d4 = self.Up4(d5) - d4 = torch.cat((x3,d4),dim=1) - d4 = self.Up_conv4(d4) - - d3 = self.Up3(d4) - d3 = torch.cat((x2,d3),dim=1) - d3 = self.Up_conv3(d3) - - d2 = self.Up2(d3) - d2 = torch.cat((x1,d2),dim=1) - d2 = self.Up_conv2(d2) - - d1 = self.Conv_1x1(d2) - - return d1 - - -class R2U_Net(nn.Module): - def __init__(self,img_ch=3,output_ch=1,t=2): - super(R2U_Net,self).__init__() - - self.Maxpool = nn.MaxPool2d(kernel_size=2,stride=2) - self.Upsample = nn.Upsample(scale_factor=2) - - self.RRCNN1 = RRCNN_block(ch_in=img_ch,ch_out=64,t=t) - - self.RRCNN2 = RRCNN_block(ch_in=64,ch_out=128,t=t) - - self.RRCNN3 = RRCNN_block(ch_in=128,ch_out=256,t=t) - - self.RRCNN4 = RRCNN_block(ch_in=256,ch_out=512,t=t) - - self.RRCNN5 = RRCNN_block(ch_in=512,ch_out=1024,t=t) - - - self.Up5 = up_conv(ch_in=1024,ch_out=512) - self.Up_RRCNN5 = RRCNN_block(ch_in=1024, ch_out=512,t=t) - - self.Up4 = up_conv(ch_in=512,ch_out=256) - self.Up_RRCNN4 = RRCNN_block(ch_in=512, ch_out=256,t=t) - - self.Up3 = up_conv(ch_in=256,ch_out=128) - self.Up_RRCNN3 = RRCNN_block(ch_in=256, ch_out=128,t=t) - - self.Up2 = up_conv(ch_in=128,ch_out=64) - self.Up_RRCNN2 = RRCNN_block(ch_in=128, ch_out=64,t=t) - - self.Conv_1x1 = nn.Conv2d(64,output_ch,kernel_size=1,stride=1,padding=0) - - - def forward(self,x): - # encoding path - x1 = self.RRCNN1(x) - - x2 = self.Maxpool(x1) - x2 = self.RRCNN2(x2) - - x3 = self.Maxpool(x2) - x3 = self.RRCNN3(x3) - - x4 = self.Maxpool(x3) - x4 = self.RRCNN4(x4) - - x5 = self.Maxpool(x4) - x5 = self.RRCNN5(x5) - - # decoding + concat path - d5 = self.Up5(x5) - d5 = torch.cat((x4,d5),dim=1) - d5 = self.Up_RRCNN5(d5) - - d4 = self.Up4(d5) - d4 = torch.cat((x3,d4),dim=1) - d4 = self.Up_RRCNN4(d4) - - d3 = self.Up3(d4) - d3 = torch.cat((x2,d3),dim=1) - d3 = self.Up_RRCNN3(d3) - - d2 = self.Up2(d3) - d2 = torch.cat((x1,d2),dim=1) - d2 = self.Up_RRCNN2(d2) - - d1 = self.Conv_1x1(d2) - - return d1 - - - -class AttU_Net(nn.Module): - def __init__(self,img_ch=3,output_ch=1): - super(AttU_Net,self).__init__() - - self.Maxpool = nn.MaxPool2d(kernel_size=2,stride=2) - - self.Conv1 = conv_block(ch_in=img_ch,ch_out=64) - self.Conv2 = conv_block(ch_in=64,ch_out=128) - self.Conv3 = conv_block(ch_in=128,ch_out=256) - self.Conv4 = conv_block(ch_in=256,ch_out=512) - self.Conv5 = conv_block(ch_in=512,ch_out=1024) - - self.Up5 = up_conv(ch_in=1024,ch_out=512) - self.Att5 = Attention_block(F_g=512,F_l=512,F_int=256) - self.Up_conv5 = conv_block(ch_in=1024, ch_out=512) - - self.Up4 = up_conv(ch_in=512,ch_out=256) - self.Att4 = Attention_block(F_g=256,F_l=256,F_int=128) - self.Up_conv4 = conv_block(ch_in=512, ch_out=256) - - self.Up3 = up_conv(ch_in=256,ch_out=128) - self.Att3 = Attention_block(F_g=128,F_l=128,F_int=64) - self.Up_conv3 = conv_block(ch_in=256, ch_out=128) - - self.Up2 = up_conv(ch_in=128,ch_out=64) - self.Att2 = Attention_block(F_g=64,F_l=64,F_int=32) - self.Up_conv2 = conv_block(ch_in=128, ch_out=64) - - self.Conv_1x1 = nn.Conv2d(64,output_ch,kernel_size=1,stride=1,padding=0) - - - def forward(self,x): - # encoding path - x1 = self.Conv1(x) - - x2 = self.Maxpool(x1) - x2 = self.Conv2(x2) - - x3 = self.Maxpool(x2) - x3 = self.Conv3(x3) - - x4 = self.Maxpool(x3) - x4 = self.Conv4(x4) - - x5 = self.Maxpool(x4) - x5 = self.Conv5(x5) - - # decoding + concat path - d5 = self.Up5(x5) - x4 = self.Att5(g=d5,x=x4) - d5 = torch.cat((x4,d5),dim=1) - d5 = self.Up_conv5(d5) - - d4 = self.Up4(d5) - x3 = self.Att4(g=d4,x=x3) - d4 = torch.cat((x3,d4),dim=1) - d4 = self.Up_conv4(d4) - - d3 = self.Up3(d4) - x2 = self.Att3(g=d3,x=x2) - d3 = torch.cat((x2,d3),dim=1) - d3 = self.Up_conv3(d3) - - d2 = self.Up2(d3) - x1 = self.Att2(g=d2,x=x1) - d2 = torch.cat((x1,d2),dim=1) - d2 = self.Up_conv2(d2) - - d1 = self.Conv_1x1(d2) - - return d1 - - -class R2AttU_Net(nn.Module): - def __init__(self,img_ch=3,output_ch=1,t=2): - super(R2AttU_Net,self).__init__() - - self.Maxpool = nn.MaxPool2d(kernel_size=2,stride=2) - self.Upsample = nn.Upsample(scale_factor=2) - - self.RRCNN1 = RRCNN_block(ch_in=img_ch,ch_out=64,t=t) - - self.RRCNN2 = RRCNN_block(ch_in=64,ch_out=128,t=t) - - self.RRCNN3 = RRCNN_block(ch_in=128,ch_out=256,t=t) - - self.RRCNN4 = RRCNN_block(ch_in=256,ch_out=512,t=t) - - self.RRCNN5 = RRCNN_block(ch_in=512,ch_out=1024,t=t) - - - self.Up5 = up_conv(ch_in=1024,ch_out=512) - self.Att5 = Attention_block(F_g=512,F_l=512,F_int=256) - self.Up_RRCNN5 = RRCNN_block(ch_in=1024, ch_out=512,t=t) - - self.Up4 = up_conv(ch_in=512,ch_out=256) - self.Att4 = Attention_block(F_g=256,F_l=256,F_int=128) - self.Up_RRCNN4 = RRCNN_block(ch_in=512, ch_out=256,t=t) - - self.Up3 = up_conv(ch_in=256,ch_out=128) - self.Att3 = Attention_block(F_g=128,F_l=128,F_int=64) - self.Up_RRCNN3 = RRCNN_block(ch_in=256, ch_out=128,t=t) - - self.Up2 = up_conv(ch_in=128,ch_out=64) - self.Att2 = Attention_block(F_g=64,F_l=64,F_int=32) - self.Up_RRCNN2 = RRCNN_block(ch_in=128, ch_out=64,t=t) - - self.Conv_1x1 = nn.Conv2d(64,output_ch,kernel_size=1,stride=1,padding=0) - - - def forward(self,x): - # encoding path - x1 = self.RRCNN1(x) - - x2 = self.Maxpool(x1) - x2 = self.RRCNN2(x2) - - x3 = self.Maxpool(x2) - x3 = self.RRCNN3(x3) - - x4 = self.Maxpool(x3) - x4 = self.RRCNN4(x4) - - x5 = self.Maxpool(x4) - x5 = self.RRCNN5(x5) - - # decoding + concat path - d5 = self.Up5(x5) - x4 = self.Att5(g=d5,x=x4) - d5 = torch.cat((x4,d5),dim=1) - d5 = self.Up_RRCNN5(d5) - - d4 = self.Up4(d5) - x3 = self.Att4(g=d4,x=x3) - d4 = torch.cat((x3,d4),dim=1) - d4 = self.Up_RRCNN4(d4) - - d3 = self.Up3(d4) - x2 = self.Att3(g=d3,x=x2) - d3 = torch.cat((x2,d3),dim=1) - d3 = self.Up_RRCNN3(d3) - - d2 = self.Up2(d3) - x1 = self.Att2(g=d2,x=x1) - d2 = torch.cat((x1,d2),dim=1) - d2 = self.Up_RRCNN2(d2) - - d1 = self.Conv_1x1(d2) - - return d1 +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.nn import init + +def init_weights(net, init_type='normal', gain=0.02): + def init_func(m): + classname = m.__class__.__name__ + if hasattr(m, 'weight') and (classname.find('Conv') != -1 or classname.find('Linear') != -1): + if init_type == 'normal': + init.normal_(m.weight.data, 0.0, gain) + elif init_type == 'xavier': + init.xavier_normal_(m.weight.data, gain=gain) + elif init_type == 'kaiming': + init.kaiming_normal_(m.weight.data, a=0, mode='fan_in') + elif init_type == 'orthogonal': + init.orthogonal_(m.weight.data, gain=gain) + else: + raise NotImplementedError('initialization method [%s] is not implemented' % init_type) + if hasattr(m, 'bias') and m.bias is not None: + init.constant_(m.bias.data, 0.0) + elif classname.find('BatchNorm2d') != -1: + init.normal_(m.weight.data, 1.0, gain) + init.constant_(m.bias.data, 0.0) + + print('initialize network with %s' % init_type) + net.apply(init_func) + +class conv_block(nn.Module): + def __init__(self,ch_in,ch_out): + super(conv_block,self).__init__() + self.conv = nn.Sequential( + nn.Conv2d(ch_in, ch_out, kernel_size=3,stride=1,padding=1,bias=True), + nn.BatchNorm2d(ch_out), + nn.ReLU(inplace=True), + nn.Conv2d(ch_out, ch_out, kernel_size=3,stride=1,padding=1,bias=True), + nn.BatchNorm2d(ch_out), + nn.ReLU(inplace=True) + ) + + + def forward(self,x): + x = self.conv(x) + return x + +class up_conv(nn.Module): + def __init__(self,ch_in,ch_out): + super(up_conv,self).__init__() + self.up = nn.Sequential( + nn.Upsample(scale_factor=2), + nn.Conv2d(ch_in,ch_out,kernel_size=3,stride=1,padding=1,bias=True), + nn.BatchNorm2d(ch_out), + nn.ReLU(inplace=True) + ) + + def forward(self,x): + x = self.up(x) + return x + +class Recurrent_block(nn.Module): + def __init__(self,ch_out,t=2): + super(Recurrent_block,self).__init__() + self.t = t + self.ch_out = ch_out + self.conv = nn.Sequential( + nn.Conv2d(ch_out,ch_out,kernel_size=3,stride=1,padding=1,bias=True), + nn.BatchNorm2d(ch_out), + nn.ReLU(inplace=True) + ) + + def forward(self,x): + for i in range(self.t): + + if i==0: + x1 = self.conv(x) + + x1 = self.conv(x+x1) + return x1 + +class RRCNN_block(nn.Module): + def __init__(self,ch_in,ch_out,t=2): + super(RRCNN_block,self).__init__() + self.RCNN = nn.Sequential( + Recurrent_block(ch_out,t=t), + Recurrent_block(ch_out,t=t) + ) + self.Conv_1x1 = nn.Conv2d(ch_in,ch_out,kernel_size=1,stride=1,padding=0) + + def forward(self,x): + x = self.Conv_1x1(x) + x1 = self.RCNN(x) + return x+x1 + + +class single_conv(nn.Module): + def __init__(self,ch_in,ch_out): + super(single_conv,self).__init__() + self.conv = nn.Sequential( + nn.Conv2d(ch_in, ch_out, kernel_size=3,stride=1,padding=1,bias=True), + nn.BatchNorm2d(ch_out), + nn.ReLU(inplace=True) + ) + + def forward(self,x): + x = self.conv(x) + return x + +class Attention_block(nn.Module): + def __init__(self,F_g,F_l,F_int): + super(Attention_block,self).__init__() + self.W_g = nn.Sequential( + nn.Conv2d(F_g, F_int, kernel_size=1,stride=1,padding=0,bias=True), + nn.BatchNorm2d(F_int) + ) + + self.W_x = nn.Sequential( + nn.Conv2d(F_l, F_int, kernel_size=1,stride=1,padding=0,bias=True), + nn.BatchNorm2d(F_int) + ) + + self.psi = nn.Sequential( + nn.Conv2d(F_int, 1, kernel_size=1,stride=1,padding=0,bias=True), + nn.BatchNorm2d(1), + nn.Sigmoid() + ) + + self.relu = nn.ReLU(inplace=True) + + def forward(self,g,x): + g1 = self.W_g(g) + x1 = self.W_x(x) + psi = self.relu(g1+x1) + psi = self.psi(psi) + + return x*psi + + +class U_Net(nn.Module): + def __init__(self,img_ch=3,output_ch=1): + super(U_Net,self).__init__() + + self.Maxpool = nn.MaxPool2d(kernel_size=2,stride=2) + + self.Conv1 = conv_block(ch_in=img_ch,ch_out=64) + self.Conv2 = conv_block(ch_in=64,ch_out=128) + self.Conv3 = conv_block(ch_in=128,ch_out=256) + self.Conv4 = conv_block(ch_in=256,ch_out=512) + self.Conv5 = conv_block(ch_in=512,ch_out=1024) + + self.Up5 = up_conv(ch_in=1024,ch_out=512) + self.Up_conv5 = conv_block(ch_in=1024, ch_out=512) + + self.Up4 = up_conv(ch_in=512,ch_out=256) + self.Up_conv4 = conv_block(ch_in=512, ch_out=256) + + self.Up3 = up_conv(ch_in=256,ch_out=128) + self.Up_conv3 = conv_block(ch_in=256, ch_out=128) + + self.Up2 = up_conv(ch_in=128,ch_out=64) + self.Up_conv2 = conv_block(ch_in=128, ch_out=64) + + self.Conv_1x1 = nn.Conv2d(64,output_ch,kernel_size=1,stride=1,padding=0) + + + def forward(self,x): + # encoding path + x1 = self.Conv1(x) + + x2 = self.Maxpool(x1) + x2 = self.Conv2(x2) + + x3 = self.Maxpool(x2) + x3 = self.Conv3(x3) + + x4 = self.Maxpool(x3) + x4 = self.Conv4(x4) + + x5 = self.Maxpool(x4) + x5 = self.Conv5(x5) + + # decoding + concat path + d5 = self.Up5(x5) + d5 = torch.cat((x4,d5),dim=1) + + d5 = self.Up_conv5(d5) + + d4 = self.Up4(d5) + d4 = torch.cat((x3,d4),dim=1) + d4 = self.Up_conv4(d4) + + d3 = self.Up3(d4) + d3 = torch.cat((x2,d3),dim=1) + d3 = self.Up_conv3(d3) + + d2 = self.Up2(d3) + d2 = torch.cat((x1,d2),dim=1) + d2 = self.Up_conv2(d2) + + d1 = self.Conv_1x1(d2) + + return d1 + + +class R2U_Net(nn.Module): + def __init__(self,img_ch=3,output_ch=1,t=2): + super(R2U_Net,self).__init__() + + self.Maxpool = nn.MaxPool2d(kernel_size=2,stride=2) + self.Upsample = nn.Upsample(scale_factor=2) + + self.RRCNN1 = RRCNN_block(ch_in=img_ch,ch_out=64,t=t) + + self.RRCNN2 = RRCNN_block(ch_in=64,ch_out=128,t=t) + + self.RRCNN3 = RRCNN_block(ch_in=128,ch_out=256,t=t) + + self.RRCNN4 = RRCNN_block(ch_in=256,ch_out=512,t=t) + + self.RRCNN5 = RRCNN_block(ch_in=512,ch_out=1024,t=t) + + + self.Up5 = up_conv(ch_in=1024,ch_out=512) + self.Up_RRCNN5 = RRCNN_block(ch_in=1024, ch_out=512,t=t) + + self.Up4 = up_conv(ch_in=512,ch_out=256) + self.Up_RRCNN4 = RRCNN_block(ch_in=512, ch_out=256,t=t) + + self.Up3 = up_conv(ch_in=256,ch_out=128) + self.Up_RRCNN3 = RRCNN_block(ch_in=256, ch_out=128,t=t) + + self.Up2 = up_conv(ch_in=128,ch_out=64) + self.Up_RRCNN2 = RRCNN_block(ch_in=128, ch_out=64,t=t) + + self.Conv_1x1 = nn.Conv2d(64,output_ch,kernel_size=1,stride=1,padding=0) + + + def forward(self,x): + # encoding path + x1 = self.RRCNN1(x) + + x2 = self.Maxpool(x1) + x2 = self.RRCNN2(x2) + + x3 = self.Maxpool(x2) + x3 = self.RRCNN3(x3) + + x4 = self.Maxpool(x3) + x4 = self.RRCNN4(x4) + + x5 = self.Maxpool(x4) + x5 = self.RRCNN5(x5) + + # decoding + concat path + d5 = self.Up5(x5) + d5 = torch.cat((x4,d5),dim=1) + d5 = self.Up_RRCNN5(d5) + + d4 = self.Up4(d5) + d4 = torch.cat((x3,d4),dim=1) + d4 = self.Up_RRCNN4(d4) + + d3 = self.Up3(d4) + d3 = torch.cat((x2,d3),dim=1) + d3 = self.Up_RRCNN3(d3) + + d2 = self.Up2(d3) + d2 = torch.cat((x1,d2),dim=1) + d2 = self.Up_RRCNN2(d2) + + d1 = self.Conv_1x1(d2) + + return d1 + + + +class AttU_Net(nn.Module): + def __init__(self,img_ch=3,output_ch=1): + super(AttU_Net,self).__init__() + + self.Maxpool = nn.MaxPool2d(kernel_size=2,stride=2) + + self.Conv1 = conv_block(ch_in=img_ch,ch_out=64) + self.Conv2 = conv_block(ch_in=64,ch_out=128) + self.Conv3 = conv_block(ch_in=128,ch_out=256) + self.Conv4 = conv_block(ch_in=256,ch_out=512) + self.Conv5 = conv_block(ch_in=512,ch_out=1024) + + self.Up5 = up_conv(ch_in=1024,ch_out=512) + self.Att5 = Attention_block(F_g=512,F_l=512,F_int=256) + self.Up_conv5 = conv_block(ch_in=1024, ch_out=512) + + self.Up4 = up_conv(ch_in=512,ch_out=256) + self.Att4 = Attention_block(F_g=256,F_l=256,F_int=128) + self.Up_conv4 = conv_block(ch_in=512, ch_out=256) + + self.Up3 = up_conv(ch_in=256,ch_out=128) + self.Att3 = Attention_block(F_g=128,F_l=128,F_int=64) + self.Up_conv3 = conv_block(ch_in=256, ch_out=128) + + self.Up2 = up_conv(ch_in=128,ch_out=64) + self.Att2 = Attention_block(F_g=64,F_l=64,F_int=32) + self.Up_conv2 = conv_block(ch_in=128, ch_out=64) + + self.Conv_1x1 = nn.Conv2d(64,output_ch,kernel_size=1,stride=1,padding=0) + + + def forward(self,x): + # encoding path + x1 = self.Conv1(x) + + x2 = self.Maxpool(x1) + x2 = self.Conv2(x2) + + x3 = self.Maxpool(x2) + x3 = self.Conv3(x3) + + x4 = self.Maxpool(x3) + x4 = self.Conv4(x4) + + x5 = self.Maxpool(x4) + x5 = self.Conv5(x5) + + # decoding + concat path + d5 = self.Up5(x5) + x4 = self.Att5(g=d5,x=x4) + d5 = torch.cat((x4,d5),dim=1) + d5 = self.Up_conv5(d5) + + d4 = self.Up4(d5) + x3 = self.Att4(g=d4,x=x3) + d4 = torch.cat((x3,d4),dim=1) + d4 = self.Up_conv4(d4) + + d3 = self.Up3(d4) + x2 = self.Att3(g=d3,x=x2) + d3 = torch.cat((x2,d3),dim=1) + d3 = self.Up_conv3(d3) + + d2 = self.Up2(d3) + x1 = self.Att2(g=d2,x=x1) + d2 = torch.cat((x1,d2),dim=1) + d2 = self.Up_conv2(d2) + + d1 = self.Conv_1x1(d2) + + return d1 + + +class R2AttU_Net(nn.Module): + def __init__(self,img_ch=3,output_ch=1,t=2): + super(R2AttU_Net,self).__init__() + + self.Maxpool = nn.MaxPool2d(kernel_size=2,stride=2) + self.Upsample = nn.Upsample(scale_factor=2) + + self.RRCNN1 = RRCNN_block(ch_in=img_ch,ch_out=64,t=t) + + self.RRCNN2 = RRCNN_block(ch_in=64,ch_out=128,t=t) + + self.RRCNN3 = RRCNN_block(ch_in=128,ch_out=256,t=t) + + self.RRCNN4 = RRCNN_block(ch_in=256,ch_out=512,t=t) + + self.RRCNN5 = RRCNN_block(ch_in=512,ch_out=1024,t=t) + + + self.Up5 = up_conv(ch_in=1024,ch_out=512) + self.Att5 = Attention_block(F_g=512,F_l=512,F_int=256) + self.Up_RRCNN5 = RRCNN_block(ch_in=1024, ch_out=512,t=t) + + self.Up4 = up_conv(ch_in=512,ch_out=256) + self.Att4 = Attention_block(F_g=256,F_l=256,F_int=128) + self.Up_RRCNN4 = RRCNN_block(ch_in=512, ch_out=256,t=t) + + self.Up3 = up_conv(ch_in=256,ch_out=128) + self.Att3 = Attention_block(F_g=128,F_l=128,F_int=64) + self.Up_RRCNN3 = RRCNN_block(ch_in=256, ch_out=128,t=t) + + self.Up2 = up_conv(ch_in=128,ch_out=64) + self.Att2 = Attention_block(F_g=64,F_l=64,F_int=32) + self.Up_RRCNN2 = RRCNN_block(ch_in=128, ch_out=64,t=t) + + self.Conv_1x1 = nn.Conv2d(64,output_ch,kernel_size=1,stride=1,padding=0) + + + def forward(self,x): + # encoding path + x1 = self.RRCNN1(x) + + x2 = self.Maxpool(x1) + x2 = self.RRCNN2(x2) + + x3 = self.Maxpool(x2) + x3 = self.RRCNN3(x3) + + x4 = self.Maxpool(x3) + x4 = self.RRCNN4(x4) + + x5 = self.Maxpool(x4) + x5 = self.RRCNN5(x5) + + # decoding + concat path + d5 = self.Up5(x5) + x4 = self.Att5(g=d5,x=x4) + d5 = torch.cat((x4,d5),dim=1) + d5 = self.Up_RRCNN5(d5) + + d4 = self.Up4(d5) + x3 = self.Att4(g=d4,x=x3) + d4 = torch.cat((x3,d4),dim=1) + d4 = self.Up_RRCNN4(d4) + + d3 = self.Up3(d4) + x2 = self.Att3(g=d3,x=x2) + d3 = torch.cat((x2,d3),dim=1) + d3 = self.Up_RRCNN3(d3) + + d2 = self.Up2(d3) + x1 = self.Att2(g=d2,x=x1) + d2 = torch.cat((x1,d2),dim=1) + d2 = self.Up_RRCNN2(d2) + + d1 = self.Conv_1x1(d2) + + return d1 diff --git a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/pthtar2onx.py b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/pthtar2onx.py index bee01bf744..07e9c58cda 100644 --- a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/pthtar2onx.py +++ b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/pthtar2onx.py @@ -1,56 +1,56 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch -import torch.onnx - -from collections import OrderedDict -from network import R2AttU_Net - - -def proc_nodes_module(checkpoint): - new_state_dict = OrderedDict() - for k, v in checkpoint.items(): - if (k[0:7] == "module."): - name = k[7:] - else: - name = k[0:] - new_state_dict[name] = v - return new_state_dict - - -def convert(pth_file_path, onnx_file_path): - checkpoint = torch.load(pth_file_path, map_location='cpu') - - model_checkpoint = checkpoint["model"] - if list(model_checkpoint.keys())[0].startswith("module."): - model_checkpoint = proc_nodes_module(model_checkpoint) - - model = R2AttU_Net(img_ch=3,output_ch=1,t=2) - model.load_state_dict(model_checkpoint) - model.eval() - print(model) - - input_names = ["actual_input_1"] - output_names = ["output1"] - dummy_input = torch.randn(4, 3, 224, 224) - torch.onnx.export(model, dummy_input, onnx_file_path, input_names=input_names, output_names=output_names, - opset_version=11) - - -if __name__ == "__main__": - src_file_path = "checkpoint.pkl" - dst_file_path = "R2AttU_Net.onnx" +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch +import torch.onnx + +from collections import OrderedDict +from network import R2AttU_Net + + +def proc_nodes_module(checkpoint): + new_state_dict = OrderedDict() + for k, v in checkpoint.items(): + if (k[0:7] == "module."): + name = k[7:] + else: + name = k[0:] + new_state_dict[name] = v + return new_state_dict + + +def convert(pth_file_path, onnx_file_path): + checkpoint = torch.load(pth_file_path, map_location='cpu') + + model_checkpoint = checkpoint["model"] + if list(model_checkpoint.keys())[0].startswith("module."): + model_checkpoint = proc_nodes_module(model_checkpoint) + + model = R2AttU_Net(img_ch=3,output_ch=1,t=2) + model.load_state_dict(model_checkpoint) + model.eval() + print(model) + + input_names = ["actual_input_1"] + output_names = ["output1"] + dummy_input = torch.randn(4, 3, 224, 224) + torch.onnx.export(model, dummy_input, onnx_file_path, input_names=input_names, output_names=output_names, + opset_version=11) + + +if __name__ == "__main__": + src_file_path = "checkpoint.pkl" + dst_file_path = "R2AttU_Net.onnx" convert(src_file_path, dst_file_path) \ No newline at end of file diff --git a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/solver_1p.py b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/solver_1p.py index e68a170a79..be64d4060c 100644 --- a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/solver_1p.py +++ b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/solver_1p.py @@ -1,355 +1,355 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -import os -import numpy as np -import time -import datetime -import torch -# import torchvision -from torch import optim -from torch.autograd import Variable -import torch.nn.functional as F -from evaluation import * -from network import U_Net,R2U_Net,AttU_Net,R2AttU_Net -from apex import amp -import apex - -class Solver(object): - def __init__(self, config, train_loader, valid_loader, test_loader): - - # Data loader - self.train_loader = train_loader - self.valid_loader = valid_loader - self.test_loader = test_loader - - # Models - self.unet = None - self.optimizer = None - self.img_ch = config.img_ch - self.output_ch = config.output_ch - self.criterion = torch.nn.BCELoss() - self.augmentation_prob = config.augmentation_prob - - # Hyper-parameters - self.lr = config.lr - self.beta1 = config.beta1 - self.beta2 = config.beta2 - - # Training settings - self.num_epochs = config.num_epochs - self.num_epochs_decay = config.num_epochs_decay - self.batch_size = config.batch_size - self.use_apex = config.use_apex - self.apex_level = config.apex_level - self.loss_scale = config.loss_scale - - # Step size - self.log_step = config.log_step - self.val_step = config.val_step - - # Path - self.result_path = config.result_path - self.mode = config.mode - - self.device = torch.device('npu' if torch.npu.is_available() else 'cpu') - self.model_type = config.model_type - self.test_model_path = config.test_model_path - self.t = config.t - self.pretrain = config.pretrain - self.pretrain_path = config.pretrain_path - self.build_model() - - def build_model(self): - """Build generator and discriminator.""" - if self.model_type =='U_Net': - self.unet = U_Net(img_ch=3,output_ch=1) - elif self.model_type =='R2U_Net': - self.unet = R2U_Net(img_ch=3,output_ch=1,t=self.t) - elif self.model_type =='AttU_Net': - self.unet = AttU_Net(img_ch=3,output_ch=1) - elif self.model_type == 'R2AttU_Net': - self.unet = R2AttU_Net(img_ch=3,output_ch=1,t=self.t) - - if self.pretrain: - self.unet.load_state_dict(torch.load(self.pretrain_path, map_location="cpu"), strict=False) - - self.unet.to(self.device) - if self.mode == "test": - return - # self.optimizer = optim.Adam(list(self.unet.parameters()), - # self.lr, [self.beta1, self.beta2]) - self.optimizer = apex.optimizers.NpuFusedAdam(list(self.unet.parameters()), - self.lr, [self.beta1, self.beta2]) - if self.use_apex: - self.unet, self.optimizer = amp.initialize(self.unet, self.optimizer, - opt_level=self.apex_level,loss_scale=self.loss_scale, combine_grad=True) - - # self.print_network(self.unet, self.model_type) - - def print_network(self, model, name): - """Print out the network information.""" - num_params = 0 - for p in model.parameters(): - num_params += p.numel() - print(model) - print(name) - print("The number of parameters: {}".format(num_params)) - - def to_data(self, x): - """Convert variable to tensor.""" - if torch.npu.is_available(): - x = x.cpu() - return x.data - - def update_lr(self, g_lr, d_lr): - for param_group in self.optimizer.param_groups: - param_group['lr'] = lr - - def reset_grad(self): - """Zero the gradient buffers.""" - self.unet.zero_grad() - - def compute_accuracy(self,SR,GT): - SR_flat = SR.view(-1) - GT_flat = GT.view(-1) - - acc = GT_flat.data.cpu()==(SR_flat.data.cpu()>0.5) - - def tensor2img(self,x): - img = (x[:,0,:,:]>x[:,1,:,:]).float() - img = img*255 - return img - - - def train(self): - """Train encoder, generator and discriminator.""" - - #====================================== Training ===========================================# - #===========================================================================================# - - unet_path = os.path.join(self.result_path, '%s-%d-%.4f-%d-%.4f.pkl' %(self.model_type,self.num_epochs,self.lr,self.num_epochs_decay,self.augmentation_prob)) - - # U-Net Train - # Train for Encoder - lr = self.lr - best_unet_score = 0. - - for epoch in range(self.num_epochs): - - self.unet.train(True) - epoch_loss = 0 - - acc = 0. # Accuracy - SE = 0. # Sensitivity (Recall) - SP = 0. # Specificity - PC = 0. # Precision - F1 = 0. # F1 Score - JS = 0. # Jaccard Similarity - DC = 0. # Dice Coefficient - length = 0 - threshold = 0.5 - steps = len(self.train_loader) - for i, (images, GT) in enumerate(self.train_loader): - # GT : Ground Truth - if i > 10: - start_time = time.time() - images = images.to(self.device) - GT = GT.to(self.device) - - # SR : Segmentation Result - SR = self.unet(images) - SR_probs = F.sigmoid(SR) - SR_flat = SR_probs.view(SR_probs.size(0),-1) - - GT_flat = GT.view(GT.size(0),-1) - loss = self.criterion(SR_flat,GT_flat) - epoch_loss += loss.item() - - # Backprop + optimize - self.reset_grad() - if self.use_apex: - with amp.scale_loss(loss, self.optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - self.optimizer.step() - - SR_ac = SR > threshold - GT_ac = GT == torch.max(GT) - acc += get_accuracy(SR_ac, GT_ac) - SE += get_sensitivity(SR_ac, GT_ac) - SP += get_specificity(SR_ac, GT_ac) - PC += get_precision(SR_ac, GT_ac) - F1 += get_F1(SR_ac, GT_ac) - JS += get_JS(SR_ac, GT_ac) - DC += get_DC(SR_ac, GT_ac) - length += 1 - - acc = acc/length - SE = SE/length - SP = SP/length - PC = PC/length - F1 = F1/length - JS = JS/length - DC = DC/length - - # Print the log info - print('Epoch [%d/%d], Loss: %.4f, [Training] Acc: %.4f, SE: %.4f, SP: %.4f, PC: %.4f, F1: %.4f, JS: %.4f, DC: %.4f, FPS: %.3f' % ( - epoch+1, self.num_epochs, \ - epoch_loss,acc,SE,SP,PC,F1,JS,DC, self.batch_size*(steps-10)/(time.time() - start_time))) - - - - # Decay learning rate - if (epoch+1) > (self.num_epochs - self.num_epochs_decay): - lr -= (self.lr / float(self.num_epochs_decay)) - for param_group in self.optimizer.param_groups: - param_group['lr'] = lr - print ('Decay learning rate to lr: {}.'.format(lr)) - - - #===================================== Validation ====================================# - self.unet.eval() - - acc = 0. # Accuracy - SE = 0. # Sensitivity (Recall) - SP = 0. # Specificity - PC = 0. # Precision - F1 = 0. # F1 Score - JS = 0. # Jaccard Similarity - DC = 0. # Dice Coefficient - length=0 - for i, (images, GT) in enumerate(self.valid_loader): - - images = images.to(self.device) - GT = GT.to(self.device) - SR = F.sigmoid(self.unet(images)) - - SR_ac = SR > threshold - GT_ac = GT == torch.max(GT) - acc += get_accuracy(SR_ac, GT_ac) - SE += get_sensitivity(SR_ac, GT_ac) - SP += get_specificity(SR_ac, GT_ac) - PC += get_precision(SR_ac, GT_ac) - F1 += get_F1(SR_ac, GT_ac) - JS += get_JS(SR_ac, GT_ac) - DC += get_DC(SR_ac, GT_ac) - - length += 1 - - acc = acc/length - SE = SE/length - SP = SP/length - PC = PC/length - F1 = F1/length - JS = JS/length - DC = DC/length - unet_score = JS + DC - - print('[Validation] Acc: %.4f, SE: %.4f, SP: %.4f, PC: %.4f, F1: %.4f, JS: %.4f, DC: %.4f'%(acc,SE,SP,PC,F1,JS,DC)) - - ''' - torchvision.utils.save_image(images.data.cpu(), - os.path.join(self.result_path, - '%s_valid_%d_image.png'%(self.model_type,epoch+1))) - torchvision.utils.save_image(SR.data.cpu(), - os.path.join(self.result_path, - '%s_valid_%d_SR.png'%(self.model_type,epoch+1))) - torchvision.utils.save_image(GT.data.cpu(), - os.path.join(self.result_path, - '%s_valid_%d_GT.png'%(self.model_type,epoch+1))) - ''' - - - # Save Best U-Net model - if unet_score > best_unet_score: - best_unet_score = unet_score - best_epoch = epoch - best_unet = self.unet.state_dict() - print('Best %s model score : %.4f'%(self.model_type,best_unet_score)) - torch.save(best_unet,unet_path) - - print("Validation Best ", [self.model_type,acc,SE,SP,PC,F1,JS,DC,self.lr,best_epoch,self.num_epochs,self.num_epochs_decay,self.augmentation_prob]) - - #===================================== Test ====================================# - def test(self): - threshold = 0.5 - pre_dict = torch.load(self.test_model_path) - new_dict = None - if list(pre_dict.keys())[0].startswith("module"): - for key, value in pre_dict.items(): - name = key[7:] - new_dict[name] = value - else: - new_dict = pre_dict - self.unet.load_state_dict(new_dict) - self.unet.eval() - - acc = 0. # Accuracy - SE = 0. # Sensitivity (Recall) - SP = 0. # Specificity - PC = 0. # Precision - F1 = 0. # F1 Score - JS = 0. # Jaccard Similarity - DC = 0. # Dice Coefficient - length=0 - for i, (images, GT) in enumerate(self.test_loader): - - images = images.to(self.device) - GT = GT.to(self.device) - SR = F.sigmoid(self.unet(images)) - SR_ac = SR > threshold - GT_ac = GT == torch.max(GT) - acc += get_accuracy(SR_ac, GT_ac) - SE += get_sensitivity(SR_ac, GT_ac) - SP += get_specificity(SR_ac, GT_ac) - PC += get_precision(SR_ac, GT_ac) - F1 += get_F1(SR_ac, GT_ac) - JS += get_JS(SR_ac, GT_ac) - DC += get_DC(SR_ac, GT_ac) - - length += 1 - - acc = acc/length - SE = SE/length - SP = SP/length - PC = PC/length - F1 = F1/length - JS = JS/length - DC = DC/length - unet_score = JS + DC - print("Test finished, model checkpoint name:",self.test_model_path, " and acc: %.3f " % (acc)) - - - - - +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import os +import numpy as np +import time +import datetime +import torch +# import torchvision +from torch import optim +from torch.autograd import Variable +import torch.nn.functional as F +from evaluation import * +from network import U_Net,R2U_Net,AttU_Net,R2AttU_Net +from apex import amp +import apex + +class Solver(object): + def __init__(self, config, train_loader, valid_loader, test_loader): + + # Data loader + self.train_loader = train_loader + self.valid_loader = valid_loader + self.test_loader = test_loader + + # Models + self.unet = None + self.optimizer = None + self.img_ch = config.img_ch + self.output_ch = config.output_ch + self.criterion = torch.nn.BCELoss() + self.augmentation_prob = config.augmentation_prob + + # Hyper-parameters + self.lr = config.lr + self.beta1 = config.beta1 + self.beta2 = config.beta2 + + # Training settings + self.num_epochs = config.num_epochs + self.num_epochs_decay = config.num_epochs_decay + self.batch_size = config.batch_size + self.use_apex = config.use_apex + self.apex_level = config.apex_level + self.loss_scale = config.loss_scale + + # Step size + self.log_step = config.log_step + self.val_step = config.val_step + + # Path + self.result_path = config.result_path + self.mode = config.mode + + self.device = torch.device('npu' if torch.npu.is_available() else 'cpu') + self.model_type = config.model_type + self.test_model_path = config.test_model_path + self.t = config.t + self.pretrain = config.pretrain + self.pretrain_path = config.pretrain_path + self.build_model() + + def build_model(self): + """Build generator and discriminator.""" + if self.model_type =='U_Net': + self.unet = U_Net(img_ch=3,output_ch=1) + elif self.model_type =='R2U_Net': + self.unet = R2U_Net(img_ch=3,output_ch=1,t=self.t) + elif self.model_type =='AttU_Net': + self.unet = AttU_Net(img_ch=3,output_ch=1) + elif self.model_type == 'R2AttU_Net': + self.unet = R2AttU_Net(img_ch=3,output_ch=1,t=self.t) + + if self.pretrain: + self.unet.load_state_dict(torch.load(self.pretrain_path, map_location="cpu"), strict=False) + + self.unet.to(self.device) + if self.mode == "test": + return + # self.optimizer = optim.Adam(list(self.unet.parameters()), + # self.lr, [self.beta1, self.beta2]) + self.optimizer = apex.optimizers.NpuFusedAdam(list(self.unet.parameters()), + self.lr, [self.beta1, self.beta2]) + if self.use_apex: + self.unet, self.optimizer = amp.initialize(self.unet, self.optimizer, + opt_level=self.apex_level,loss_scale=self.loss_scale, combine_grad=True) + + # self.print_network(self.unet, self.model_type) + + def print_network(self, model, name): + """Print out the network information.""" + num_params = 0 + for p in model.parameters(): + num_params += p.numel() + print(model) + print(name) + print("The number of parameters: {}".format(num_params)) + + def to_data(self, x): + """Convert variable to tensor.""" + if torch.npu.is_available(): + x = x.cpu() + return x.data + + def update_lr(self, g_lr, d_lr): + for param_group in self.optimizer.param_groups: + param_group['lr'] = lr + + def reset_grad(self): + """Zero the gradient buffers.""" + self.unet.zero_grad() + + def compute_accuracy(self,SR,GT): + SR_flat = SR.view(-1) + GT_flat = GT.view(-1) + + acc = GT_flat.data.cpu()==(SR_flat.data.cpu()>0.5) + + def tensor2img(self,x): + img = (x[:,0,:,:]>x[:,1,:,:]).float() + img = img*255 + return img + + + def train(self): + """Train encoder, generator and discriminator.""" + + #====================================== Training ===========================================# + #===========================================================================================# + + unet_path = os.path.join(self.result_path, '%s-%d-%.4f-%d-%.4f.pkl' %(self.model_type,self.num_epochs,self.lr,self.num_epochs_decay,self.augmentation_prob)) + + # U-Net Train + # Train for Encoder + lr = self.lr + best_unet_score = 0. + + for epoch in range(self.num_epochs): + + self.unet.train(True) + epoch_loss = 0 + + acc = 0. # Accuracy + SE = 0. # Sensitivity (Recall) + SP = 0. # Specificity + PC = 0. # Precision + F1 = 0. # F1 Score + JS = 0. # Jaccard Similarity + DC = 0. # Dice Coefficient + length = 0 + threshold = 0.5 + steps = len(self.train_loader) + for i, (images, GT) in enumerate(self.train_loader): + # GT : Ground Truth + if i > 10: + start_time = time.time() + images = images.to(self.device) + GT = GT.to(self.device) + + # SR : Segmentation Result + SR = self.unet(images) + SR_probs = F.sigmoid(SR) + SR_flat = SR_probs.view(SR_probs.size(0),-1) + + GT_flat = GT.view(GT.size(0),-1) + loss = self.criterion(SR_flat,GT_flat) + epoch_loss += loss.item() + + # Backprop + optimize + self.reset_grad() + if self.use_apex: + with amp.scale_loss(loss, self.optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + self.optimizer.step() + + SR_ac = SR > threshold + GT_ac = GT == torch.max(GT) + acc += get_accuracy(SR_ac, GT_ac) + SE += get_sensitivity(SR_ac, GT_ac) + SP += get_specificity(SR_ac, GT_ac) + PC += get_precision(SR_ac, GT_ac) + F1 += get_F1(SR_ac, GT_ac) + JS += get_JS(SR_ac, GT_ac) + DC += get_DC(SR_ac, GT_ac) + length += 1 + + acc = acc/length + SE = SE/length + SP = SP/length + PC = PC/length + F1 = F1/length + JS = JS/length + DC = DC/length + + # Print the log info + print('Epoch [%d/%d], Loss: %.4f, [Training] Acc: %.4f, SE: %.4f, SP: %.4f, PC: %.4f, F1: %.4f, JS: %.4f, DC: %.4f, FPS: %.3f' % ( + epoch+1, self.num_epochs, \ + epoch_loss,acc,SE,SP,PC,F1,JS,DC, self.batch_size*(steps-10)/(time.time() - start_time))) + + + + # Decay learning rate + if (epoch+1) > (self.num_epochs - self.num_epochs_decay): + lr -= (self.lr / float(self.num_epochs_decay)) + for param_group in self.optimizer.param_groups: + param_group['lr'] = lr + print ('Decay learning rate to lr: {}.'.format(lr)) + + + #===================================== Validation ====================================# + self.unet.eval() + + acc = 0. # Accuracy + SE = 0. # Sensitivity (Recall) + SP = 0. # Specificity + PC = 0. # Precision + F1 = 0. # F1 Score + JS = 0. # Jaccard Similarity + DC = 0. # Dice Coefficient + length=0 + for i, (images, GT) in enumerate(self.valid_loader): + + images = images.to(self.device) + GT = GT.to(self.device) + SR = F.sigmoid(self.unet(images)) + + SR_ac = SR > threshold + GT_ac = GT == torch.max(GT) + acc += get_accuracy(SR_ac, GT_ac) + SE += get_sensitivity(SR_ac, GT_ac) + SP += get_specificity(SR_ac, GT_ac) + PC += get_precision(SR_ac, GT_ac) + F1 += get_F1(SR_ac, GT_ac) + JS += get_JS(SR_ac, GT_ac) + DC += get_DC(SR_ac, GT_ac) + + length += 1 + + acc = acc/length + SE = SE/length + SP = SP/length + PC = PC/length + F1 = F1/length + JS = JS/length + DC = DC/length + unet_score = JS + DC + + print('[Validation] Acc: %.4f, SE: %.4f, SP: %.4f, PC: %.4f, F1: %.4f, JS: %.4f, DC: %.4f'%(acc,SE,SP,PC,F1,JS,DC)) + + ''' + torchvision.utils.save_image(images.data.cpu(), + os.path.join(self.result_path, + '%s_valid_%d_image.png'%(self.model_type,epoch+1))) + torchvision.utils.save_image(SR.data.cpu(), + os.path.join(self.result_path, + '%s_valid_%d_SR.png'%(self.model_type,epoch+1))) + torchvision.utils.save_image(GT.data.cpu(), + os.path.join(self.result_path, + '%s_valid_%d_GT.png'%(self.model_type,epoch+1))) + ''' + + + # Save Best U-Net model + if unet_score > best_unet_score: + best_unet_score = unet_score + best_epoch = epoch + best_unet = self.unet.state_dict() + print('Best %s model score : %.4f'%(self.model_type,best_unet_score)) + torch.save(best_unet,unet_path) + + print("Validation Best ", [self.model_type,acc,SE,SP,PC,F1,JS,DC,self.lr,best_epoch,self.num_epochs,self.num_epochs_decay,self.augmentation_prob]) + + #===================================== Test ====================================# + def test(self): + threshold = 0.5 + pre_dict = torch.load(self.test_model_path) + new_dict = None + if list(pre_dict.keys())[0].startswith("module"): + for key, value in pre_dict.items(): + name = key[7:] + new_dict[name] = value + else: + new_dict = pre_dict + self.unet.load_state_dict(new_dict) + self.unet.eval() + + acc = 0. # Accuracy + SE = 0. # Sensitivity (Recall) + SP = 0. # Specificity + PC = 0. # Precision + F1 = 0. # F1 Score + JS = 0. # Jaccard Similarity + DC = 0. # Dice Coefficient + length=0 + for i, (images, GT) in enumerate(self.test_loader): + + images = images.to(self.device) + GT = GT.to(self.device) + SR = F.sigmoid(self.unet(images)) + SR_ac = SR > threshold + GT_ac = GT == torch.max(GT) + acc += get_accuracy(SR_ac, GT_ac) + SE += get_sensitivity(SR_ac, GT_ac) + SP += get_specificity(SR_ac, GT_ac) + PC += get_precision(SR_ac, GT_ac) + F1 += get_F1(SR_ac, GT_ac) + JS += get_JS(SR_ac, GT_ac) + DC += get_DC(SR_ac, GT_ac) + + length += 1 + + acc = acc/length + SE = SE/length + SP = SP/length + PC = PC/length + F1 = F1/length + JS = JS/length + DC = DC/length + unet_score = JS + DC + print("Test finished, model checkpoint name:",self.test_model_path, " and acc: %.3f " % (acc)) + + + + + diff --git a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/solver_8p.py b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/solver_8p.py index 5bbd16284a..60b58da3ac 100644 --- a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/solver_8p.py +++ b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/solver_8p.py @@ -1,217 +1,217 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -import os -import numpy as np -import time -import datetime -import torch -# import torchvision -from torch import optim -from torch.autograd import Variable -import torch.nn.functional as F -from evaluation import * -from network import U_Net,R2U_Net,AttU_Net,R2AttU_Net -import torch.distributed as dist -from data_loader import get_dist_loader, get_loader,ImageFolder -from apex import amp -import apex - -def train_8p(rank, npus, config): - rank = rank - dist.init_process_group(backend=config.dist_backend, world_size=config.npus, rank=rank) - torch.npu.set_device(rank) - model_unet = R2AttU_Net(img_ch=3, output_ch=1,t=config.t) - model_unet = model_unet.to("npu") - # optimizer = optim.Adam(list(model_unet.parameters()), config.lr, [config.beta1, config.beta2]) - optimizer = apex.optimizers.NpuFusedAdam(list(model_unet.parameters()), config.lr, [config.beta1, config.beta2]) - - if config.use_apex: - model_unet, optimizer = amp.initialize(model_unet, optimizer, - opt_level=config.apex_level,loss_scale=config.loss_scale, combine_grad=True) - model_unet = torch.nn.parallel.DistributedDataParallel(model_unet, device_ids=[rank], - broadcast_buffers=False) - - train_loader = get_dist_loader(image_path=config.train_path, - image_size=config.image_size, - batch_size=config.batch_size, - num_workers=config.num_workers, - mode='train', - augmentation_prob=config.augmentation_prob) - valid_loader = get_loader(image_path=config.valid_path, - image_size=config.image_size, - batch_size=config.batch_size, - num_workers=config.num_workers, - mode='valid', - augmentation_prob=0.) - criterion = torch.nn.BCELoss() - - lr = config.lr - best_unet_score = 0. - unet_path = os.path.join(config.result_path, '%d-%s-%d-%.4f-%d-%.4f.pkl' %(rank, - config.model_type,config.num_epochs,config.lr,config.num_epochs_decay,config.augmentation_prob)) - - for epoch in range(config.num_epochs): - model_unet.train(True) - epoch_loss = 0. - acc = 0. # Accuracy - SE = 0. # Sensitivity (Recall) - SP = 0. # Specificity - PC = 0. # Precision - F1 = 0. # F1 Score - JS = 0. # Jaccard Similarity - DC = 0. # Dice Coefficient - length = 0 - threshold = 0.5 - steps = len(train_loader) - for i, (images, GT) in enumerate(train_loader): - # GT : Ground Truth - images = images.to("npu") - GT = GT.to("npu") - if i == 10: - start_time = time.time() - - # SR : Segmentation Result - SR = model_unet(images) - SR_probs = F.sigmoid(SR) - SR_flat = SR_probs.view(SR_probs.size(0),-1) - - GT_flat = GT.view(GT.size(0),-1) - loss = criterion(SR_flat,GT_flat) - epoch_loss += loss.item() - - # Backprop + optimize - model_unet.zero_grad() - if config.use_apex: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.step() - - SR_ac = SR > threshold - GT_ac = GT == torch.max(GT) - acc += get_accuracy(SR_ac, GT_ac) - SE += get_sensitivity(SR_ac, GT_ac) - SP += get_specificity(SR_ac, GT_ac) - PC += get_precision(SR_ac, GT_ac) - F1 += get_F1(SR_ac, GT_ac) - JS += get_JS(SR_ac, GT_ac) - DC += get_DC(SR_ac, GT_ac) - length += 1 - if config.display_freq > 0 and (i+1) % config.display_freq == 0 and rank == 0: - print('Rank %d , Epoch [%d/%d], Step: %d, Loss: %.4f, [Training] Acc: %.4f, FPS: %.2f' % ( - rank, epoch+1, config.num_epochs, i, loss.item(),acc/length, config.batch_size*(i-10)/(time.time() - start_time))) - acc = acc/length - SE = SE/length - SP = SP/length - PC = PC/length - F1 = F1/length - JS = JS/length - DC = DC/length - - # Print the log info - if rank == 0: - print('Rank %d , Epoch [%d/%d], Loss: %.4f, [Training] Acc: %.4f, SE: %.4f, SP: %.4f, PC: %.4f, F1: %.4f, JS: %.4f, DC: %.4f, FPS: %.2f' % ( - rank, epoch+1, config.num_epochs, epoch_loss, acc ,SE,SP,PC,F1,JS,DC, config.batch_size*(steps-10)/(time.time() - start_time))) - # Decay learning rate - # if (epoch+1) > (config.num_epochs - config.num_epochs_decay): - if (epoch+1) % 10 == 0: - lr = lr/2. - # lr -= (config.lr / float(config.num_epochs_decay)) - for param_group in optimizer.param_groups: - param_group['lr'] = lr - print ('Decay learning rate to lr: {}.'.format(lr)) - - - #===================================== Validation ====================================# - if rank == 0: - model_unet.eval() - - acc = 0. # Accuracy - SE = 0. # Sensitivity (Recall) - SP = 0. # Specificity - PC = 0. # Precision - F1 = 0. # F1 Score - JS = 0. # Jaccard Similarity - DC = 0. # Dice Coefficient - length=0 - for i, (images, GT) in enumerate(valid_loader): - - images = images.to("npu") - GT = GT.to("npu") - SR = F.sigmoid(model_unet(images)) - SR_ac = SR > threshold - GT_ac = GT == torch.max(GT) - acc += get_accuracy(SR_ac, GT_ac) - SE += get_sensitivity(SR_ac, GT_ac) - SP += get_specificity(SR_ac, GT_ac) - PC += get_precision(SR_ac, GT_ac) - F1 += get_F1(SR_ac, GT_ac) - JS += get_JS(SR_ac, GT_ac) - DC += get_DC(SR_ac, GT_ac) - - length += 1 - - acc = acc/length - SE = SE/length - SP = SP/length - PC = PC/length - F1 = F1/length - JS = JS/length - DC = DC/length - unet_score = acc#JS + DC - - print('[Validation] Rank: %d, Epoch %d,Acc: %.4f, SE: %.4f, SP: %.4f, PC: %.4f, F1: %.4f, JS: %.4f, DC: %.4f'%(rank, epoch, acc,SE,SP,PC,F1,JS,DC)) - - ''' - torchvision.utils.save_image(images.data.cpu(), - os.path.join(self.result_path, - '%s_valid_%d_image.png'%(self.model_type,epoch+1))) - torchvision.utils.save_image(SR.data.cpu(), - os.path.join(self.result_path, - '%s_valid_%d_SR.png'%(self.model_type,epoch+1))) - torchvision.utils.save_image(GT.data.cpu(), - os.path.join(self.result_path, - '%s_valid_%d_GT.png'%(self.model_type,epoch+1))) - ''' - - - # Save Best U-Net model - if unet_score > best_unet_score: - best_unet_score = unet_score - best_epoch = epoch - best_unet = model_unet.state_dict() - print('Best %s model score : %.4f'%(config.model_type,best_unet_score)) - torch.save(best_unet,unet_path) - print("Validation Best", [config.model_type,acc,SE,SP,PC,F1,JS,DC,config.lr,best_epoch,\ - config.num_epochs,config.num_epochs_decay,config.augmentation_prob]) +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import os +import numpy as np +import time +import datetime +import torch +# import torchvision +from torch import optim +from torch.autograd import Variable +import torch.nn.functional as F +from evaluation import * +from network import U_Net,R2U_Net,AttU_Net,R2AttU_Net +import torch.distributed as dist +from data_loader import get_dist_loader, get_loader,ImageFolder +from apex import amp +import apex + +def train_8p(rank, npus, config): + rank = rank + dist.init_process_group(backend=config.dist_backend, world_size=config.npus, rank=rank) + torch.npu.set_device(rank) + model_unet = R2AttU_Net(img_ch=3, output_ch=1,t=config.t) + model_unet = model_unet.to("npu") + # optimizer = optim.Adam(list(model_unet.parameters()), config.lr, [config.beta1, config.beta2]) + optimizer = apex.optimizers.NpuFusedAdam(list(model_unet.parameters()), config.lr, [config.beta1, config.beta2]) + + if config.use_apex: + model_unet, optimizer = amp.initialize(model_unet, optimizer, + opt_level=config.apex_level,loss_scale=config.loss_scale, combine_grad=True) + model_unet = torch.nn.parallel.DistributedDataParallel(model_unet, device_ids=[rank], + broadcast_buffers=False) + + train_loader = get_dist_loader(image_path=config.train_path, + image_size=config.image_size, + batch_size=config.batch_size, + num_workers=config.num_workers, + mode='train', + augmentation_prob=config.augmentation_prob) + valid_loader = get_loader(image_path=config.valid_path, + image_size=config.image_size, + batch_size=config.batch_size, + num_workers=config.num_workers, + mode='valid', + augmentation_prob=0.) + criterion = torch.nn.BCELoss() + + lr = config.lr + best_unet_score = 0. + unet_path = os.path.join(config.result_path, '%d-%s-%d-%.4f-%d-%.4f.pkl' %(rank, + config.model_type,config.num_epochs,config.lr,config.num_epochs_decay,config.augmentation_prob)) + + for epoch in range(config.num_epochs): + model_unet.train(True) + epoch_loss = 0. + acc = 0. # Accuracy + SE = 0. # Sensitivity (Recall) + SP = 0. # Specificity + PC = 0. # Precision + F1 = 0. # F1 Score + JS = 0. # Jaccard Similarity + DC = 0. # Dice Coefficient + length = 0 + threshold = 0.5 + steps = len(train_loader) + for i, (images, GT) in enumerate(train_loader): + # GT : Ground Truth + images = images.to("npu") + GT = GT.to("npu") + if i == 10: + start_time = time.time() + + # SR : Segmentation Result + SR = model_unet(images) + SR_probs = F.sigmoid(SR) + SR_flat = SR_probs.view(SR_probs.size(0),-1) + + GT_flat = GT.view(GT.size(0),-1) + loss = criterion(SR_flat,GT_flat) + epoch_loss += loss.item() + + # Backprop + optimize + model_unet.zero_grad() + if config.use_apex: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + optimizer.step() + + SR_ac = SR > threshold + GT_ac = GT == torch.max(GT) + acc += get_accuracy(SR_ac, GT_ac) + SE += get_sensitivity(SR_ac, GT_ac) + SP += get_specificity(SR_ac, GT_ac) + PC += get_precision(SR_ac, GT_ac) + F1 += get_F1(SR_ac, GT_ac) + JS += get_JS(SR_ac, GT_ac) + DC += get_DC(SR_ac, GT_ac) + length += 1 + if config.display_freq > 0 and (i+1) % config.display_freq == 0 and rank == 0: + print('Rank %d , Epoch [%d/%d], Step: %d, Loss: %.4f, [Training] Acc: %.4f, FPS: %.2f' % ( + rank, epoch+1, config.num_epochs, i, loss.item(),acc/length, config.batch_size*(i-10)/(time.time() - start_time))) + acc = acc/length + SE = SE/length + SP = SP/length + PC = PC/length + F1 = F1/length + JS = JS/length + DC = DC/length + + # Print the log info + if rank == 0: + print('Rank %d , Epoch [%d/%d], Loss: %.4f, [Training] Acc: %.4f, SE: %.4f, SP: %.4f, PC: %.4f, F1: %.4f, JS: %.4f, DC: %.4f, FPS: %.2f' % ( + rank, epoch+1, config.num_epochs, epoch_loss, acc ,SE,SP,PC,F1,JS,DC, config.batch_size*(steps-10)/(time.time() - start_time))) + # Decay learning rate + # if (epoch+1) > (config.num_epochs - config.num_epochs_decay): + if (epoch+1) % 10 == 0: + lr = lr/2. + # lr -= (config.lr / float(config.num_epochs_decay)) + for param_group in optimizer.param_groups: + param_group['lr'] = lr + print ('Decay learning rate to lr: {}.'.format(lr)) + + + #===================================== Validation ====================================# + if rank == 0: + model_unet.eval() + + acc = 0. # Accuracy + SE = 0. # Sensitivity (Recall) + SP = 0. # Specificity + PC = 0. # Precision + F1 = 0. # F1 Score + JS = 0. # Jaccard Similarity + DC = 0. # Dice Coefficient + length=0 + for i, (images, GT) in enumerate(valid_loader): + + images = images.to("npu") + GT = GT.to("npu") + SR = F.sigmoid(model_unet(images)) + SR_ac = SR > threshold + GT_ac = GT == torch.max(GT) + acc += get_accuracy(SR_ac, GT_ac) + SE += get_sensitivity(SR_ac, GT_ac) + SP += get_specificity(SR_ac, GT_ac) + PC += get_precision(SR_ac, GT_ac) + F1 += get_F1(SR_ac, GT_ac) + JS += get_JS(SR_ac, GT_ac) + DC += get_DC(SR_ac, GT_ac) + + length += 1 + + acc = acc/length + SE = SE/length + SP = SP/length + PC = PC/length + F1 = F1/length + JS = JS/length + DC = DC/length + unet_score = acc#JS + DC + + print('[Validation] Rank: %d, Epoch %d,Acc: %.4f, SE: %.4f, SP: %.4f, PC: %.4f, F1: %.4f, JS: %.4f, DC: %.4f'%(rank, epoch, acc,SE,SP,PC,F1,JS,DC)) + + ''' + torchvision.utils.save_image(images.data.cpu(), + os.path.join(self.result_path, + '%s_valid_%d_image.png'%(self.model_type,epoch+1))) + torchvision.utils.save_image(SR.data.cpu(), + os.path.join(self.result_path, + '%s_valid_%d_SR.png'%(self.model_type,epoch+1))) + torchvision.utils.save_image(GT.data.cpu(), + os.path.join(self.result_path, + '%s_valid_%d_GT.png'%(self.model_type,epoch+1))) + ''' + + + # Save Best U-Net model + if unet_score > best_unet_score: + best_unet_score = unet_score + best_epoch = epoch + best_unet = model_unet.state_dict() + print('Best %s model score : %.4f'%(config.model_type,best_unet_score)) + torch.save(best_unet,unet_path) + print("Validation Best", [config.model_type,acc,SE,SP,PC,F1,JS,DC,config.lr,best_epoch,\ + config.num_epochs,config.num_epochs_decay,config.augmentation_prob]) \ No newline at end of file diff --git a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/train.py b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/train.py index e605f787b4..0a1ebf8c6e 100644 --- a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/train.py +++ b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/train.py @@ -1,334 +1,334 @@ -# -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -#from __future__ import print_function -import datetime -import os -import time -import sys - -import torch -import torch.utils.data -from torch import nn -import random -import numpy as np -import utils -import argparse -try: - import apex - from apex import amp -except ImportError: - amp = None -from evaluation import * -from data_loader import get_dist_loader, get_loader -from network import R2AttU_Net - - -def train_one_epoch(model_unet, criterion, optimizer, data_loader, device, epoch, config): - model_unet.train() - metric_logger = utils.MetricLogger(delimiter=" ") - - epoch_loss = 0. - acc = 0. # Accuracy - SE = 0. # Sensitivity (Recall) - SP = 0. # Specificity - PC = 0. # Precision - F1 = 0. # F1 Score - JS = 0. # Jaccard Similarity - DC = 0. # Dice Coefficient - length = 0 - threshold = 0.5 - steps = len(data_loader) - for i, (images, GT) in enumerate(data_loader): - # GT : Ground Truth - images = images.to(device) - GT = GT.to(device) - if i == 5: - start_time = time.time() - - # SR : Segmentation Result - SR = model_unet(images) - SR_probs = torch.nn.functional.sigmoid(SR) - SR_flat = SR_probs.view(SR_probs.size(0),-1) - - GT_flat = GT.view(GT.size(0),-1) - loss = criterion(SR_flat,GT_flat) - epoch_loss += loss.item() - - # Backprop + optimize - model_unet.zero_grad() - if config.use_apex: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.step() - - SR_ac = SR > threshold - GT_ac = GT == torch.max(GT) - acc += get_accuracy(SR_ac, GT_ac) - SE += get_sensitivity(SR_ac, GT_ac) - SP += get_specificity(SR_ac, GT_ac) - PC += get_precision(SR_ac, GT_ac) - F1 += get_F1(SR_ac, GT_ac) - JS += get_JS(SR_ac, GT_ac) - DC += get_DC(SR_ac, GT_ac) - length += 1 - acc = acc/length - - batch_size = config.batch_size - fps = batch_size *(steps-5) / (time.time() - start_time) - metric_logger.update(loss=loss.item(), lr=optimizer.param_groups[0]["lr"]) - metric_logger.meters['acc'].update(acc, n=batch_size) - metric_logger.meters['img/s'].update(fps) - print("Traing, Epoch: %d, Loss: %.4f"%(epoch, loss.item())) - - return acc, fps - - -def evaluate(model_unet, criterion, valid_loader, device): - metric_logger = utils.MetricLogger(delimiter=" ") - model_unet.eval() - threshold = 0.5 - acc = 0. # Accuracy - SE = 0. # Sensitivity (Recall) - SP = 0. # Specificity - PC = 0. # Precision - F1 = 0. # F1 Score - JS = 0. # Jaccard Similarity - DC = 0. # Dice Coefficient - length=0 - for i, (images, GT) in enumerate(valid_loader): - - images = images.to(device) - GT = GT.to(device) - SR = torch.nn.functional.sigmoid(model_unet(images)) - SR_ac = SR > threshold - GT_ac = GT == torch.max(GT) - acc += get_accuracy(SR_ac, GT_ac) - SE += get_sensitivity(SR_ac, GT_ac) - SP += get_specificity(SR_ac, GT_ac) - PC += get_precision(SR_ac, GT_ac) - F1 += get_F1(SR_ac, GT_ac) - JS += get_JS(SR_ac, GT_ac) - DC += get_DC(SR_ac, GT_ac) - metric_logger.synchronize_between_processes(device) - - length += 1 - - acc = acc/length - SE = SE/length - SP = SP/length - PC = PC/length - F1 = F1/length - JS = JS/length - DC = DC/length - unet_score = acc#JS + DC - batch_size = images.shape[0] - metric_logger.meters['acc'].update(acc, n=batch_size) - return acc - -def init_distributed_mode(args): - if 'RANK_SIZE' in os.environ and 'RANK_ID' in os.environ: - args.rank_size = int(os.environ['RANK_SIZE']) - args.rank_id = int(os.environ['RANK_ID']) - args.device_id = args.rank_id - args.batch_size = int(args.batch_size / args.rank_size) - args.num_workers = int((args.num_workers) / args.rank_size) - else: - raise RuntimeError("init_distributed_mode failed.") - - torch.distributed.init_process_group(backend='hccl', - world_size=args.rank_size, rank=args.rank_id) -def main(config): - #设置环境变量 - os.environ['MASTER_ADDR'] = '127.0.0.1' - os.environ['MASTER_PORT'] = '29688' - - #设置seed - random.seed(1234) - np.random.seed(1234) - torch.manual_seed(1234) - os.environ['PYTHONHASHSEED'] = str(1234) - - if config.use_apex: - if sys.version_info < (3, 0): - raise RuntimeError("Apex currently only supports Python 3. Aborting.") - if amp is None: - raise RuntimeError("Failed to import apex. Please install apex from https://www.github.com/nvidia/apex " - "to enable mixed-precision training.") - - # Create directories if not exist - if not os.path.exists(config.result_path): - os.makedirs(config.result_path) - - if config.distributed: - init_distributed_mode(config) - - config.is_master_node = not config.distributed or config.device_id == 0 - if config.is_master_node: - print(config) - - device = torch.device(f'npu:'+str(config.device_id)) - torch.npu.set_device(device) - - # Data loading code - print("Loading data") - config.train_path = os.path.join(config.data_path, "train") - config.valid_path = os.path.join(config.data_path, "valid") - print("Creating data loaders") - if config.distributed: - train_loader = get_dist_loader(image_path=config.train_path, - image_size=config.image_size, - batch_size=config.batch_size, - num_workers=config.num_workers, - mode='train', - augmentation_prob=config.augmentation_prob) - valid_loader = get_loader(image_path=config.valid_path, - image_size=config.image_size, - batch_size=config.batch_size, - num_workers=config.num_workers, - mode='valid', - augmentation_prob=0.) - else: - train_loader = get_loader(image_path=config.train_path, - image_size=config.image_size, - batch_size=config.batch_size, - num_workers=config.num_workers, - mode='train', - augmentation_prob=config.augmentation_prob) - valid_loader = get_loader(image_path=config.valid_path, - image_size=config.image_size, - batch_size=config.batch_size, - num_workers=config.num_workers, - mode='valid', - augmentation_prob=0.) - model_unet = R2AttU_Net(img_ch=3, output_ch=1,t=config.t) - model_unet = model_unet.to(device) - - criterion = torch.nn.BCELoss() - optimizer = apex.optimizers.NpuFusedAdam(list(model_unet.parameters()), - config.lr, [config.beta1, config.beta2]) - if config.use_apex: - model_unet, optimizer = amp.initialize(model_unet, optimizer, - opt_level=config.apex_level,loss_scale=config.loss_scale, combine_grad=True) - - model_without_ddp = model_unet - if config.distributed: - model_unet = torch.nn.parallel.DistributedDataParallel(model_unet, device_ids=[config.device_id]) - model_without_ddp = model_unet.module - - if config.is_master_node: - print("Start training") - start_time = time.time() - best_unet_score = 0. - lr = config.lr - for epoch in range(config.num_epochs): - acc, fps = train_one_epoch(model_unet, criterion, optimizer, train_loader, device, epoch, config) - - unet_score = evaluate(model_unet, criterion, valid_loader, device=device) - if config.is_master_node: - print("Traing, Epoch: %d, Avgacc: %.3f, FPS: %.2f"%(epoch, acc, fps)) - print('Test, Acc: %.3f'%(unet_score)) - if config.is_master_node and config.result_path: - checkpoint = { - 'model': model_without_ddp.state_dict(), - 'optimizer': optimizer.state_dict(), - 'epoch': epoch, - 'args': config} - utils.save_on_master( - checkpoint, - os.path.join(config.result_path, 'model_{}.pth'.format(epoch))) - if unet_score > best_unet_score: - best_unet_score = unet_score - utils.save_on_master( - checkpoint, - os.path.join(config.result_path, 'checkpoint.pth')) - if (epoch+1) % 10 == 0: - lr = lr/2. - # lr -= (config.lr / float(config.num_epochs_decay)) - for param_group in optimizer.param_groups: - param_group['lr'] = lr - print ('Decay learning rate to lr: {}.'.format(lr)) - - total_time = time.time() - start_time - total_time_str = str(datetime.timedelta(seconds=int(total_time))) - if config.is_master_node: - print('Training time {}'.format(total_time_str)) - exit() - - -def parse_args(): - parser = argparse.ArgumentParser() - - - # model hyper-parameters - parser.add_argument('--image_size', type=int, default=224) - parser.add_argument('--t', type=int, default=3, help='t for Recurrent step of R2U_Net or R2AttU_Net') - - # training hyper-parameters - parser.add_argument('--img_ch', type=int, default=3) - parser.add_argument('--output_ch', type=int, default=1) - parser.add_argument('--num_epochs', type=int, default=100) - parser.add_argument('--num_epochs_decay', type=int, default=70) - parser.add_argument('--batch_size', type=int, default=16) - parser.add_argument('--num_workers', type=int, default=8) - parser.add_argument('--lr', type=float, default=0.0002) - parser.add_argument('--beta1', type=float, default=0.5) # momentum1 in Adam - parser.add_argument('--beta2', type=float, default=0.999) # momentum2 in Adam - parser.add_argument('--augmentation_prob', type=float, default=0.4) - - parser.add_argument('--log_step', type=int, default=2) - parser.add_argument('--val_step', type=int, default=2) - - # misc - parser.add_argument('--mode', type=str, default='train') - parser.add_argument('--model_type', type=str, default='U_Net', help='U_Net/R2U_Net/AttU_Net/R2AttU_Net') - parser.add_argument('--test_model_path', type=str, default='./models') - parser.add_argument('--data_path', type=str, default='./dataset/train/') - parser.add_argument('--result_path', type=str, default='./result_1p') - - parser.add_argument('--device_id', type=int, default=0) - parser.add_argument('--use_apex', type=int, default=1) - parser.add_argument('--apex_level', type=str, default="O2") - parser.add_argument('--loss_scale', type=float, default=128.) - - parser.add_argument('--world_size', type=int, default=8) - parser.add_argument('--distributed', type=int, default=0, - help='Use multi-processing distributed training to launch.') - - config = parser.parse_args() - main(config) - -if __name__ == "__main__": - args = parse_args() - main(args) +# +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +#from __future__ import print_function +import datetime +import os +import time +import sys + +import torch +import torch.utils.data +from torch import nn +import random +import numpy as np +import utils +import argparse +try: + import apex + from apex import amp +except ImportError: + amp = None +from evaluation import * +from data_loader import get_dist_loader, get_loader +from network import R2AttU_Net + + +def train_one_epoch(model_unet, criterion, optimizer, data_loader, device, epoch, config): + model_unet.train() + metric_logger = utils.MetricLogger(delimiter=" ") + + epoch_loss = 0. + acc = 0. # Accuracy + SE = 0. # Sensitivity (Recall) + SP = 0. # Specificity + PC = 0. # Precision + F1 = 0. # F1 Score + JS = 0. # Jaccard Similarity + DC = 0. # Dice Coefficient + length = 0 + threshold = 0.5 + steps = len(data_loader) + for i, (images, GT) in enumerate(data_loader): + # GT : Ground Truth + images = images.to(device) + GT = GT.to(device) + if i == 5: + start_time = time.time() + + # SR : Segmentation Result + SR = model_unet(images) + SR_probs = torch.nn.functional.sigmoid(SR) + SR_flat = SR_probs.view(SR_probs.size(0),-1) + + GT_flat = GT.view(GT.size(0),-1) + loss = criterion(SR_flat,GT_flat) + epoch_loss += loss.item() + + # Backprop + optimize + model_unet.zero_grad() + if config.use_apex: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + optimizer.step() + + SR_ac = SR > threshold + GT_ac = GT == torch.max(GT) + acc += get_accuracy(SR_ac, GT_ac) + SE += get_sensitivity(SR_ac, GT_ac) + SP += get_specificity(SR_ac, GT_ac) + PC += get_precision(SR_ac, GT_ac) + F1 += get_F1(SR_ac, GT_ac) + JS += get_JS(SR_ac, GT_ac) + DC += get_DC(SR_ac, GT_ac) + length += 1 + acc = acc/length + + batch_size = config.batch_size + fps = batch_size *(steps-5) / (time.time() - start_time) + metric_logger.update(loss=loss.item(), lr=optimizer.param_groups[0]["lr"]) + metric_logger.meters['acc'].update(acc, n=batch_size) + metric_logger.meters['img/s'].update(fps) + print("Traing, Epoch: %d, Loss: %.4f"%(epoch, loss.item())) + + return acc, fps + + +def evaluate(model_unet, criterion, valid_loader, device): + metric_logger = utils.MetricLogger(delimiter=" ") + model_unet.eval() + threshold = 0.5 + acc = 0. # Accuracy + SE = 0. # Sensitivity (Recall) + SP = 0. # Specificity + PC = 0. # Precision + F1 = 0. # F1 Score + JS = 0. # Jaccard Similarity + DC = 0. # Dice Coefficient + length=0 + for i, (images, GT) in enumerate(valid_loader): + + images = images.to(device) + GT = GT.to(device) + SR = torch.nn.functional.sigmoid(model_unet(images)) + SR_ac = SR > threshold + GT_ac = GT == torch.max(GT) + acc += get_accuracy(SR_ac, GT_ac) + SE += get_sensitivity(SR_ac, GT_ac) + SP += get_specificity(SR_ac, GT_ac) + PC += get_precision(SR_ac, GT_ac) + F1 += get_F1(SR_ac, GT_ac) + JS += get_JS(SR_ac, GT_ac) + DC += get_DC(SR_ac, GT_ac) + metric_logger.synchronize_between_processes(device) + + length += 1 + + acc = acc/length + SE = SE/length + SP = SP/length + PC = PC/length + F1 = F1/length + JS = JS/length + DC = DC/length + unet_score = acc#JS + DC + batch_size = images.shape[0] + metric_logger.meters['acc'].update(acc, n=batch_size) + return acc + +def init_distributed_mode(args): + if 'RANK_SIZE' in os.environ and 'RANK_ID' in os.environ: + args.rank_size = int(os.environ['RANK_SIZE']) + args.rank_id = int(os.environ['RANK_ID']) + args.device_id = args.rank_id + args.batch_size = int(args.batch_size / args.rank_size) + args.num_workers = int((args.num_workers) / args.rank_size) + else: + raise RuntimeError("init_distributed_mode failed.") + + torch.distributed.init_process_group(backend='hccl', + world_size=args.rank_size, rank=args.rank_id) +def main(config): + #设置环境变量 + os.environ['MASTER_ADDR'] = '127.0.0.1' + os.environ['MASTER_PORT'] = '29688' + + #设置seed + random.seed(1234) + np.random.seed(1234) + torch.manual_seed(1234) + os.environ['PYTHONHASHSEED'] = str(1234) + + if config.use_apex: + if sys.version_info < (3, 0): + raise RuntimeError("Apex currently only supports Python 3. Aborting.") + if amp is None: + raise RuntimeError("Failed to import apex. Please install apex from https://www.github.com/nvidia/apex " + "to enable mixed-precision training.") + + # Create directories if not exist + if not os.path.exists(config.result_path): + os.makedirs(config.result_path) + + if config.distributed: + init_distributed_mode(config) + + config.is_master_node = not config.distributed or config.device_id == 0 + if config.is_master_node: + print(config) + + device = torch.device(f'npu:'+str(config.device_id)) + torch.npu.set_device(device) + + # Data loading code + print("Loading data") + config.train_path = os.path.join(config.data_path, "train") + config.valid_path = os.path.join(config.data_path, "valid") + print("Creating data loaders") + if config.distributed: + train_loader = get_dist_loader(image_path=config.train_path, + image_size=config.image_size, + batch_size=config.batch_size, + num_workers=config.num_workers, + mode='train', + augmentation_prob=config.augmentation_prob) + valid_loader = get_loader(image_path=config.valid_path, + image_size=config.image_size, + batch_size=config.batch_size, + num_workers=config.num_workers, + mode='valid', + augmentation_prob=0.) + else: + train_loader = get_loader(image_path=config.train_path, + image_size=config.image_size, + batch_size=config.batch_size, + num_workers=config.num_workers, + mode='train', + augmentation_prob=config.augmentation_prob) + valid_loader = get_loader(image_path=config.valid_path, + image_size=config.image_size, + batch_size=config.batch_size, + num_workers=config.num_workers, + mode='valid', + augmentation_prob=0.) + model_unet = R2AttU_Net(img_ch=3, output_ch=1,t=config.t) + model_unet = model_unet.to(device) + + criterion = torch.nn.BCELoss() + optimizer = apex.optimizers.NpuFusedAdam(list(model_unet.parameters()), + config.lr, [config.beta1, config.beta2]) + if config.use_apex: + model_unet, optimizer = amp.initialize(model_unet, optimizer, + opt_level=config.apex_level,loss_scale=config.loss_scale, combine_grad=True) + + model_without_ddp = model_unet + if config.distributed: + model_unet = torch.nn.parallel.DistributedDataParallel(model_unet, device_ids=[config.device_id]) + model_without_ddp = model_unet.module + + if config.is_master_node: + print("Start training") + start_time = time.time() + best_unet_score = 0. + lr = config.lr + for epoch in range(config.num_epochs): + acc, fps = train_one_epoch(model_unet, criterion, optimizer, train_loader, device, epoch, config) + + unet_score = evaluate(model_unet, criterion, valid_loader, device=device) + if config.is_master_node: + print("Traing, Epoch: %d, Avgacc: %.3f, FPS: %.2f"%(epoch, acc, fps)) + print('Test, Acc: %.3f'%(unet_score)) + if config.is_master_node and config.result_path: + checkpoint = { + 'model': model_without_ddp.state_dict(), + 'optimizer': optimizer.state_dict(), + 'epoch': epoch, + 'args': config} + utils.save_on_master( + checkpoint, + os.path.join(config.result_path, 'model_{}.pth'.format(epoch))) + if unet_score > best_unet_score: + best_unet_score = unet_score + utils.save_on_master( + checkpoint, + os.path.join(config.result_path, 'checkpoint.pth')) + if (epoch+1) % 10 == 0: + lr = lr/2. + # lr -= (config.lr / float(config.num_epochs_decay)) + for param_group in optimizer.param_groups: + param_group['lr'] = lr + print ('Decay learning rate to lr: {}.'.format(lr)) + + total_time = time.time() - start_time + total_time_str = str(datetime.timedelta(seconds=int(total_time))) + if config.is_master_node: + print('Training time {}'.format(total_time_str)) + exit() + + +def parse_args(): + parser = argparse.ArgumentParser() + + + # model hyper-parameters + parser.add_argument('--image_size', type=int, default=224) + parser.add_argument('--t', type=int, default=3, help='t for Recurrent step of R2U_Net or R2AttU_Net') + + # training hyper-parameters + parser.add_argument('--img_ch', type=int, default=3) + parser.add_argument('--output_ch', type=int, default=1) + parser.add_argument('--num_epochs', type=int, default=100) + parser.add_argument('--num_epochs_decay', type=int, default=70) + parser.add_argument('--batch_size', type=int, default=16) + parser.add_argument('--num_workers', type=int, default=8) + parser.add_argument('--lr', type=float, default=0.0002) + parser.add_argument('--beta1', type=float, default=0.5) # momentum1 in Adam + parser.add_argument('--beta2', type=float, default=0.999) # momentum2 in Adam + parser.add_argument('--augmentation_prob', type=float, default=0.4) + + parser.add_argument('--log_step', type=int, default=2) + parser.add_argument('--val_step', type=int, default=2) + + # misc + parser.add_argument('--mode', type=str, default='train') + parser.add_argument('--model_type', type=str, default='U_Net', help='U_Net/R2U_Net/AttU_Net/R2AttU_Net') + parser.add_argument('--test_model_path', type=str, default='./models') + parser.add_argument('--data_path', type=str, default='./dataset/train/') + parser.add_argument('--result_path', type=str, default='./result_1p') + + parser.add_argument('--device_id', type=int, default=0) + parser.add_argument('--use_apex', type=int, default=1) + parser.add_argument('--apex_level', type=str, default="O2") + parser.add_argument('--loss_scale', type=float, default=128.) + + parser.add_argument('--world_size', type=int, default=8) + parser.add_argument('--distributed', type=int, default=0, + help='Use multi-processing distributed training to launch.') + + config = parser.parse_args() + main(config) + +if __name__ == "__main__": + args = parse_args() + main(args) diff --git a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/train_1p.sh b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/train_1p.sh index 34e21cc973..927445535b 100644 --- a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/train_1p.sh +++ b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/train_1p.sh @@ -1,3 +1,3 @@ -source ./npu_env.sh -a='R2AttU_Net' +source ./npu_env.sh +a='R2AttU_Net' python3 main_1p.py --model_type=$a --data_path="./dataset" \ No newline at end of file diff --git a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/train_8p.sh b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/train_8p.sh index 61941f8ffe..7266b39ebe 100644 --- a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/train_8p.sh +++ b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/train_8p.sh @@ -1,3 +1,3 @@ -source ./npu_env.sh -a='R2AttU_Net' +source ./npu_env.sh +a='R2AttU_Net' python3 main_8p.py --model_type=$a --data_path="./dataset" \ No newline at end of file diff --git a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/utils.py b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/utils.py index 1f4811a91a..e854750e9c 100644 --- a/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/utils.py +++ b/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch/utils.py @@ -1,262 +1,262 @@ -# -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -#from __future__ import print_function -from collections import defaultdict, deque -import datetime -import time -import torch -import torch.distributed as dist - -import errno -import os - - -class SmoothedValue(object): - """Track a series of values and provide access to smoothed values over a - window or the global series average. - """ - - def __init__(self, window_size=20, fmt=None): - if fmt is None: - fmt = "{median:.4f} ({global_avg:.4f})" - self.deque = deque(maxlen=window_size) - self.total = 0.0 - self.count = 0 - self.fmt = fmt - - def update(self, value, n=1): - self.deque.append(value) - self.count += n - self.total += value * n - - def synchronize_between_processes(self, npu_device): - """ - Warning: does not synchronize the deque! - """ - if not is_dist_avail_and_initialized(): - return - t = torch.tensor([self.count, self.total], dtype=torch.float32, device=npu_device) - dist.barrier() - dist.all_reduce(t) - t = t.tolist() - self.count = int(t[0]) - self.total = t[1] - - @property - def median(self): - d = torch.tensor(list(self.deque)) - return d.median().item() - - @property - def avg(self): - d = torch.tensor(list(self.deque), dtype=torch.float32) - return d.mean().item() - - @property - def global_avg(self): - return self.total / self.count - - @property - def max(self): - return max(self.deque) - - @property - def value(self): - return self.deque[-1] - - def __str__(self): - return self.fmt.format( - median=self.median, - avg=self.avg, - global_avg=self.global_avg, - max=self.max, - value=self.value) - - -class MetricLogger(object): - def __init__(self, delimiter="\t"): - self.meters = defaultdict(SmoothedValue) - self.delimiter = delimiter - - def update(self, **kwargs): - for k, v in kwargs.items(): - if isinstance(v, torch.Tensor): - v = v.item() - assert isinstance(v, (float, int)) - self.meters[k].update(v) - - def __getattr__(self, attr): - if attr in self.meters: - return self.meters[attr] - if attr in self.__dict__: - return self.__dict__[attr] - raise AttributeError("'{}' object has no attribute '{}'".format( - type(self).__name__, attr)) - - def __str__(self): - loss_str = [] - for name, meter in self.meters.items(): - loss_str.append( - "{}: {}".format(name, str(meter)) - ) - return self.delimiter.join(loss_str) - - def synchronize_between_processes(self, device): - for meter in self.meters.values(): - meter.synchronize_between_processes(device) - - def add_meter(self, name, meter): - self.meters[name] = meter - - def log_every(self, iterable, args, header=None): - i = 0 - if not header: - header = '' - start_time = time.time() - end = time.time() - iter_time = SmoothedValue(fmt='{avg:.4f}') - data_time = SmoothedValue(fmt='{avg:.4f}') - space_fmt = ':' + str(len(str(len(iterable)))) + 'd' - if torch.npu.is_available(): - log_msg = self.delimiter.join([ - header, - '[{0' + space_fmt + '}/{1}]', - 'eta: {eta}', - '{meters}', - 'time: {time}', - 'data: {data}', - 'max mem: {memory:.0f}' - ]) - else: - log_msg = self.delimiter.join([ - header, - '[{0' + space_fmt + '}/{1}]', - 'eta: {eta}', - '{meters}', - 'time: {time}', - 'data: {data}' - ]) - MB = 1024.0 * 1024.0 - for obj in iterable: - data_time.update(time.time() - end) - yield obj - iter_time.update(time.time() - end) - if args.is_master_node and i % args.print_freq == 0: - eta_seconds = iter_time.global_avg * (len(iterable) - i) - eta_string = str(datetime.timedelta(seconds=int(eta_seconds))) - if torch.npu.is_available(): - print(log_msg.format( - i, len(iterable), eta=eta_string, - meters=str(self), - time=str(iter_time), data=str(data_time), - memory=0)) - else: - print(log_msg.format( - i, len(iterable), eta=eta_string, - meters=str(self), - time=str(iter_time), data=str(data_time))) - i += 1 - end = time.time() - total_time = time.time() - start_time - total_time_str = str(datetime.timedelta(seconds=int(total_time))) - print('{} Total time: {}'.format(header, total_time_str)) - - -def accuracy(output, target, topk=(1,)): - """Computes the accuracy over the k top predictions for the specified values of k""" - with torch.no_grad(): - maxk = max(topk) - batch_size = target.size(0) - - _, pred = output.topk(maxk, 1, True, True) - pred = pred.t() - correct = pred.eq(target[None]) - - res = [] - for k in topk: - correct_k = correct[:k].flatten().sum(dtype=torch.float32) - res.append(correct_k * (100.0 / batch_size)) - return res - - -def mkdir(path): - try: - os.makedirs(path) - except OSError as e: - if e.errno != errno.EEXIST: - raise - - -def setup_for_distributed(is_master): - """ - This function disables printing when not in master process - """ - import builtins as __builtin__ - builtin_print = __builtin__.print - - def print(*args, **kwargs): - force = kwargs.pop('force', False) - if is_master or force: - builtin_print(*args, **kwargs) - - __builtin__.print = print - - -def is_dist_avail_and_initialized(): - if not dist.is_available(): - return False - if not dist.is_initialized(): - return False - return True - - -def get_world_size(): - if not is_dist_avail_and_initialized(): - return 1 - return dist.get_world_size() - - -def get_rank(): - if not is_dist_avail_and_initialized(): - return 0 - return dist.get_rank() - - -def is_main_process(): - return get_rank() == 0 - - -def save_on_master(*args, **kwargs): - torch.save(*args, **kwargs) - - +# +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +#from __future__ import print_function +from collections import defaultdict, deque +import datetime +import time +import torch +import torch.distributed as dist + +import errno +import os + + +class SmoothedValue(object): + """Track a series of values and provide access to smoothed values over a + window or the global series average. + """ + + def __init__(self, window_size=20, fmt=None): + if fmt is None: + fmt = "{median:.4f} ({global_avg:.4f})" + self.deque = deque(maxlen=window_size) + self.total = 0.0 + self.count = 0 + self.fmt = fmt + + def update(self, value, n=1): + self.deque.append(value) + self.count += n + self.total += value * n + + def synchronize_between_processes(self, npu_device): + """ + Warning: does not synchronize the deque! + """ + if not is_dist_avail_and_initialized(): + return + t = torch.tensor([self.count, self.total], dtype=torch.float32, device=npu_device) + dist.barrier() + dist.all_reduce(t) + t = t.tolist() + self.count = int(t[0]) + self.total = t[1] + + @property + def median(self): + d = torch.tensor(list(self.deque)) + return d.median().item() + + @property + def avg(self): + d = torch.tensor(list(self.deque), dtype=torch.float32) + return d.mean().item() + + @property + def global_avg(self): + return self.total / self.count + + @property + def max(self): + return max(self.deque) + + @property + def value(self): + return self.deque[-1] + + def __str__(self): + return self.fmt.format( + median=self.median, + avg=self.avg, + global_avg=self.global_avg, + max=self.max, + value=self.value) + + +class MetricLogger(object): + def __init__(self, delimiter="\t"): + self.meters = defaultdict(SmoothedValue) + self.delimiter = delimiter + + def update(self, **kwargs): + for k, v in kwargs.items(): + if isinstance(v, torch.Tensor): + v = v.item() + assert isinstance(v, (float, int)) + self.meters[k].update(v) + + def __getattr__(self, attr): + if attr in self.meters: + return self.meters[attr] + if attr in self.__dict__: + return self.__dict__[attr] + raise AttributeError("'{}' object has no attribute '{}'".format( + type(self).__name__, attr)) + + def __str__(self): + loss_str = [] + for name, meter in self.meters.items(): + loss_str.append( + "{}: {}".format(name, str(meter)) + ) + return self.delimiter.join(loss_str) + + def synchronize_between_processes(self, device): + for meter in self.meters.values(): + meter.synchronize_between_processes(device) + + def add_meter(self, name, meter): + self.meters[name] = meter + + def log_every(self, iterable, args, header=None): + i = 0 + if not header: + header = '' + start_time = time.time() + end = time.time() + iter_time = SmoothedValue(fmt='{avg:.4f}') + data_time = SmoothedValue(fmt='{avg:.4f}') + space_fmt = ':' + str(len(str(len(iterable)))) + 'd' + if torch.npu.is_available(): + log_msg = self.delimiter.join([ + header, + '[{0' + space_fmt + '}/{1}]', + 'eta: {eta}', + '{meters}', + 'time: {time}', + 'data: {data}', + 'max mem: {memory:.0f}' + ]) + else: + log_msg = self.delimiter.join([ + header, + '[{0' + space_fmt + '}/{1}]', + 'eta: {eta}', + '{meters}', + 'time: {time}', + 'data: {data}' + ]) + MB = 1024.0 * 1024.0 + for obj in iterable: + data_time.update(time.time() - end) + yield obj + iter_time.update(time.time() - end) + if args.is_master_node and i % args.print_freq == 0: + eta_seconds = iter_time.global_avg * (len(iterable) - i) + eta_string = str(datetime.timedelta(seconds=int(eta_seconds))) + if torch.npu.is_available(): + print(log_msg.format( + i, len(iterable), eta=eta_string, + meters=str(self), + time=str(iter_time), data=str(data_time), + memory=0)) + else: + print(log_msg.format( + i, len(iterable), eta=eta_string, + meters=str(self), + time=str(iter_time), data=str(data_time))) + i += 1 + end = time.time() + total_time = time.time() - start_time + total_time_str = str(datetime.timedelta(seconds=int(total_time))) + print('{} Total time: {}'.format(header, total_time_str)) + + +def accuracy(output, target, topk=(1,)): + """Computes the accuracy over the k top predictions for the specified values of k""" + with torch.no_grad(): + maxk = max(topk) + batch_size = target.size(0) + + _, pred = output.topk(maxk, 1, True, True) + pred = pred.t() + correct = pred.eq(target[None]) + + res = [] + for k in topk: + correct_k = correct[:k].flatten().sum(dtype=torch.float32) + res.append(correct_k * (100.0 / batch_size)) + return res + + +def mkdir(path): + try: + os.makedirs(path) + except OSError as e: + if e.errno != errno.EEXIST: + raise + + +def setup_for_distributed(is_master): + """ + This function disables printing when not in master process + """ + import builtins as __builtin__ + builtin_print = __builtin__.print + + def print(*args, **kwargs): + force = kwargs.pop('force', False) + if is_master or force: + builtin_print(*args, **kwargs) + + __builtin__.print = print + + +def is_dist_avail_and_initialized(): + if not dist.is_available(): + return False + if not dist.is_initialized(): + return False + return True + + +def get_world_size(): + if not is_dist_avail_and_initialized(): + return 1 + return dist.get_world_size() + + +def get_rank(): + if not is_dist_avail_and_initialized(): + return 0 + return dist.get_rank() + + +def is_main_process(): + return get_rank() == 0 + + +def save_on_master(*args, **kwargs): + torch.save(*args, **kwargs) + + diff --git a/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/LICENSE b/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/LICENSE index 4ba4fdcab3..a0e0310359 100644 --- a/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/LICENSE +++ b/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/LICENSE @@ -1,29 +1,29 @@ -BSD 3-Clause License - -Copyright (c) 2017, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +BSD 3-Clause License + +Copyright (c) 2017, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/evaluation.py b/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/evaluation.py index 51b3948ca5..e368a18647 100644 --- a/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/evaluation.py +++ b/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/evaluation.py @@ -1,115 +1,115 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -import torch - -# SR : Segmentation Result -# GT : Ground Truth - -def get_accuracy(SR,GT,threshold=0.5): - SR = SR > threshold - GT = GT == torch.max(GT) - corr = torch.sum(SR==GT) - tensor_size = SR.size(0)*SR.size(1)*SR.size(2)*SR.size(3) - acc = float(corr)/float(tensor_size) - - return acc - -def get_sensitivity(SR,GT,threshold=0.5): - # Sensitivity == Recall - # TP : True Positive - # FN : False Negative - SR = SR > threshold - GT = GT == torch.max(GT) - TP = SR & GT - FN = (~SR) & GT - - SE = float(torch.sum(TP))/(float(torch.sum(TP)+torch.sum(FN)) + 1e-6) - - return SE - -def get_specificity(SR,GT,threshold=0.5): - - # TN : True Negative - # FP : False Positive - SR = SR > threshold - GT = GT == torch.max(GT) - TN = (~SR) & (~GT) - FP = SR & (~GT) - - SP = float(torch.sum(TN))/(float(torch.sum(TN)+torch.sum(FP)) + 1e-6) - - return SP - -def get_precision(SR,GT,threshold=0.5): - - # TP : True Positive - # FP : False Positive - SR = SR > threshold - GT = GT == torch.max(GT) - TP = SR & GT - FP = SR & (~GT) - - PC = float(torch.sum(TP))/(float(torch.sum(TP)+torch.sum(FP)) + 1e-6) - - return PC - -def get_F1(SR,GT,threshold=0.5): - # Sensitivity == Recall - SE = get_sensitivity(SR,GT,threshold=threshold) - PC = get_precision(SR,GT,threshold=threshold) - - F1 = 2*SE*PC/(SE+PC + 1e-6) - - return F1 - -def get_JS(SR,GT,threshold=0.5): - # JS : Jaccard similarity - SR = SR > threshold - GT = GT == torch.max(GT) - Inter = torch.sum((SR & GT)) - Union = torch.sum((SR | GT)) - - JS = float(Inter)/(float(Union) + 1e-6) - - return JS - -def get_DC(SR,GT,threshold=0.5): - # DC : Dice Coefficient - SR = SR > threshold - GT = GT == torch.max(GT) - Inter = torch.sum((SR & GT)) - DC = float(2*Inter)/(float(torch.sum(SR)+torch.sum(GT)) + 1e-6) - - return DC - - - +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import torch + +# SR : Segmentation Result +# GT : Ground Truth + +def get_accuracy(SR,GT,threshold=0.5): + SR = SR > threshold + GT = GT == torch.max(GT) + corr = torch.sum(SR==GT) + tensor_size = SR.size(0)*SR.size(1)*SR.size(2)*SR.size(3) + acc = float(corr)/float(tensor_size) + + return acc + +def get_sensitivity(SR,GT,threshold=0.5): + # Sensitivity == Recall + # TP : True Positive + # FN : False Negative + SR = SR > threshold + GT = GT == torch.max(GT) + TP = SR & GT + FN = (~SR) & GT + + SE = float(torch.sum(TP))/(float(torch.sum(TP)+torch.sum(FN)) + 1e-6) + + return SE + +def get_specificity(SR,GT,threshold=0.5): + + # TN : True Negative + # FP : False Positive + SR = SR > threshold + GT = GT == torch.max(GT) + TN = (~SR) & (~GT) + FP = SR & (~GT) + + SP = float(torch.sum(TN))/(float(torch.sum(TN)+torch.sum(FP)) + 1e-6) + + return SP + +def get_precision(SR,GT,threshold=0.5): + + # TP : True Positive + # FP : False Positive + SR = SR > threshold + GT = GT == torch.max(GT) + TP = SR & GT + FP = SR & (~GT) + + PC = float(torch.sum(TP))/(float(torch.sum(TP)+torch.sum(FP)) + 1e-6) + + return PC + +def get_F1(SR,GT,threshold=0.5): + # Sensitivity == Recall + SE = get_sensitivity(SR,GT,threshold=threshold) + PC = get_precision(SR,GT,threshold=threshold) + + F1 = 2*SE*PC/(SE+PC + 1e-6) + + return F1 + +def get_JS(SR,GT,threshold=0.5): + # JS : Jaccard similarity + SR = SR > threshold + GT = GT == torch.max(GT) + Inter = torch.sum((SR & GT)) + Union = torch.sum((SR | GT)) + + JS = float(Inter)/(float(Union) + 1e-6) + + return JS + +def get_DC(SR,GT,threshold=0.5): + # DC : Dice Coefficient + SR = SR > threshold + GT = GT == torch.max(GT) + Inter = torch.sum((SR & GT)) + DC = float(2*Inter)/(float(torch.sum(SR)+torch.sum(GT)) + 1e-6) + + return DC + + + diff --git a/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/modelzoo_level.txt b/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/run_to_onnx.sh b/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/run_to_onnx.sh index 13cead0d88..89099c047a 100644 --- a/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/run_to_onnx.sh +++ b/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/run_to_onnx.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash -source env.sh - +#!/usr/bin/env bash +source env.sh + python3.7 pthtar2onx.py \ No newline at end of file diff --git a/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/utils.py b/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/utils.py index 1f4811a91a..e854750e9c 100644 --- a/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/utils.py +++ b/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch/utils.py @@ -1,262 +1,262 @@ -# -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -#from __future__ import print_function -from collections import defaultdict, deque -import datetime -import time -import torch -import torch.distributed as dist - -import errno -import os - - -class SmoothedValue(object): - """Track a series of values and provide access to smoothed values over a - window or the global series average. - """ - - def __init__(self, window_size=20, fmt=None): - if fmt is None: - fmt = "{median:.4f} ({global_avg:.4f})" - self.deque = deque(maxlen=window_size) - self.total = 0.0 - self.count = 0 - self.fmt = fmt - - def update(self, value, n=1): - self.deque.append(value) - self.count += n - self.total += value * n - - def synchronize_between_processes(self, npu_device): - """ - Warning: does not synchronize the deque! - """ - if not is_dist_avail_and_initialized(): - return - t = torch.tensor([self.count, self.total], dtype=torch.float32, device=npu_device) - dist.barrier() - dist.all_reduce(t) - t = t.tolist() - self.count = int(t[0]) - self.total = t[1] - - @property - def median(self): - d = torch.tensor(list(self.deque)) - return d.median().item() - - @property - def avg(self): - d = torch.tensor(list(self.deque), dtype=torch.float32) - return d.mean().item() - - @property - def global_avg(self): - return self.total / self.count - - @property - def max(self): - return max(self.deque) - - @property - def value(self): - return self.deque[-1] - - def __str__(self): - return self.fmt.format( - median=self.median, - avg=self.avg, - global_avg=self.global_avg, - max=self.max, - value=self.value) - - -class MetricLogger(object): - def __init__(self, delimiter="\t"): - self.meters = defaultdict(SmoothedValue) - self.delimiter = delimiter - - def update(self, **kwargs): - for k, v in kwargs.items(): - if isinstance(v, torch.Tensor): - v = v.item() - assert isinstance(v, (float, int)) - self.meters[k].update(v) - - def __getattr__(self, attr): - if attr in self.meters: - return self.meters[attr] - if attr in self.__dict__: - return self.__dict__[attr] - raise AttributeError("'{}' object has no attribute '{}'".format( - type(self).__name__, attr)) - - def __str__(self): - loss_str = [] - for name, meter in self.meters.items(): - loss_str.append( - "{}: {}".format(name, str(meter)) - ) - return self.delimiter.join(loss_str) - - def synchronize_between_processes(self, device): - for meter in self.meters.values(): - meter.synchronize_between_processes(device) - - def add_meter(self, name, meter): - self.meters[name] = meter - - def log_every(self, iterable, args, header=None): - i = 0 - if not header: - header = '' - start_time = time.time() - end = time.time() - iter_time = SmoothedValue(fmt='{avg:.4f}') - data_time = SmoothedValue(fmt='{avg:.4f}') - space_fmt = ':' + str(len(str(len(iterable)))) + 'd' - if torch.npu.is_available(): - log_msg = self.delimiter.join([ - header, - '[{0' + space_fmt + '}/{1}]', - 'eta: {eta}', - '{meters}', - 'time: {time}', - 'data: {data}', - 'max mem: {memory:.0f}' - ]) - else: - log_msg = self.delimiter.join([ - header, - '[{0' + space_fmt + '}/{1}]', - 'eta: {eta}', - '{meters}', - 'time: {time}', - 'data: {data}' - ]) - MB = 1024.0 * 1024.0 - for obj in iterable: - data_time.update(time.time() - end) - yield obj - iter_time.update(time.time() - end) - if args.is_master_node and i % args.print_freq == 0: - eta_seconds = iter_time.global_avg * (len(iterable) - i) - eta_string = str(datetime.timedelta(seconds=int(eta_seconds))) - if torch.npu.is_available(): - print(log_msg.format( - i, len(iterable), eta=eta_string, - meters=str(self), - time=str(iter_time), data=str(data_time), - memory=0)) - else: - print(log_msg.format( - i, len(iterable), eta=eta_string, - meters=str(self), - time=str(iter_time), data=str(data_time))) - i += 1 - end = time.time() - total_time = time.time() - start_time - total_time_str = str(datetime.timedelta(seconds=int(total_time))) - print('{} Total time: {}'.format(header, total_time_str)) - - -def accuracy(output, target, topk=(1,)): - """Computes the accuracy over the k top predictions for the specified values of k""" - with torch.no_grad(): - maxk = max(topk) - batch_size = target.size(0) - - _, pred = output.topk(maxk, 1, True, True) - pred = pred.t() - correct = pred.eq(target[None]) - - res = [] - for k in topk: - correct_k = correct[:k].flatten().sum(dtype=torch.float32) - res.append(correct_k * (100.0 / batch_size)) - return res - - -def mkdir(path): - try: - os.makedirs(path) - except OSError as e: - if e.errno != errno.EEXIST: - raise - - -def setup_for_distributed(is_master): - """ - This function disables printing when not in master process - """ - import builtins as __builtin__ - builtin_print = __builtin__.print - - def print(*args, **kwargs): - force = kwargs.pop('force', False) - if is_master or force: - builtin_print(*args, **kwargs) - - __builtin__.print = print - - -def is_dist_avail_and_initialized(): - if not dist.is_available(): - return False - if not dist.is_initialized(): - return False - return True - - -def get_world_size(): - if not is_dist_avail_and_initialized(): - return 1 - return dist.get_world_size() - - -def get_rank(): - if not is_dist_avail_and_initialized(): - return 0 - return dist.get_rank() - - -def is_main_process(): - return get_rank() == 0 - - -def save_on_master(*args, **kwargs): - torch.save(*args, **kwargs) - - +# +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +#from __future__ import print_function +from collections import defaultdict, deque +import datetime +import time +import torch +import torch.distributed as dist + +import errno +import os + + +class SmoothedValue(object): + """Track a series of values and provide access to smoothed values over a + window or the global series average. + """ + + def __init__(self, window_size=20, fmt=None): + if fmt is None: + fmt = "{median:.4f} ({global_avg:.4f})" + self.deque = deque(maxlen=window_size) + self.total = 0.0 + self.count = 0 + self.fmt = fmt + + def update(self, value, n=1): + self.deque.append(value) + self.count += n + self.total += value * n + + def synchronize_between_processes(self, npu_device): + """ + Warning: does not synchronize the deque! + """ + if not is_dist_avail_and_initialized(): + return + t = torch.tensor([self.count, self.total], dtype=torch.float32, device=npu_device) + dist.barrier() + dist.all_reduce(t) + t = t.tolist() + self.count = int(t[0]) + self.total = t[1] + + @property + def median(self): + d = torch.tensor(list(self.deque)) + return d.median().item() + + @property + def avg(self): + d = torch.tensor(list(self.deque), dtype=torch.float32) + return d.mean().item() + + @property + def global_avg(self): + return self.total / self.count + + @property + def max(self): + return max(self.deque) + + @property + def value(self): + return self.deque[-1] + + def __str__(self): + return self.fmt.format( + median=self.median, + avg=self.avg, + global_avg=self.global_avg, + max=self.max, + value=self.value) + + +class MetricLogger(object): + def __init__(self, delimiter="\t"): + self.meters = defaultdict(SmoothedValue) + self.delimiter = delimiter + + def update(self, **kwargs): + for k, v in kwargs.items(): + if isinstance(v, torch.Tensor): + v = v.item() + assert isinstance(v, (float, int)) + self.meters[k].update(v) + + def __getattr__(self, attr): + if attr in self.meters: + return self.meters[attr] + if attr in self.__dict__: + return self.__dict__[attr] + raise AttributeError("'{}' object has no attribute '{}'".format( + type(self).__name__, attr)) + + def __str__(self): + loss_str = [] + for name, meter in self.meters.items(): + loss_str.append( + "{}: {}".format(name, str(meter)) + ) + return self.delimiter.join(loss_str) + + def synchronize_between_processes(self, device): + for meter in self.meters.values(): + meter.synchronize_between_processes(device) + + def add_meter(self, name, meter): + self.meters[name] = meter + + def log_every(self, iterable, args, header=None): + i = 0 + if not header: + header = '' + start_time = time.time() + end = time.time() + iter_time = SmoothedValue(fmt='{avg:.4f}') + data_time = SmoothedValue(fmt='{avg:.4f}') + space_fmt = ':' + str(len(str(len(iterable)))) + 'd' + if torch.npu.is_available(): + log_msg = self.delimiter.join([ + header, + '[{0' + space_fmt + '}/{1}]', + 'eta: {eta}', + '{meters}', + 'time: {time}', + 'data: {data}', + 'max mem: {memory:.0f}' + ]) + else: + log_msg = self.delimiter.join([ + header, + '[{0' + space_fmt + '}/{1}]', + 'eta: {eta}', + '{meters}', + 'time: {time}', + 'data: {data}' + ]) + MB = 1024.0 * 1024.0 + for obj in iterable: + data_time.update(time.time() - end) + yield obj + iter_time.update(time.time() - end) + if args.is_master_node and i % args.print_freq == 0: + eta_seconds = iter_time.global_avg * (len(iterable) - i) + eta_string = str(datetime.timedelta(seconds=int(eta_seconds))) + if torch.npu.is_available(): + print(log_msg.format( + i, len(iterable), eta=eta_string, + meters=str(self), + time=str(iter_time), data=str(data_time), + memory=0)) + else: + print(log_msg.format( + i, len(iterable), eta=eta_string, + meters=str(self), + time=str(iter_time), data=str(data_time))) + i += 1 + end = time.time() + total_time = time.time() - start_time + total_time_str = str(datetime.timedelta(seconds=int(total_time))) + print('{} Total time: {}'.format(header, total_time_str)) + + +def accuracy(output, target, topk=(1,)): + """Computes the accuracy over the k top predictions for the specified values of k""" + with torch.no_grad(): + maxk = max(topk) + batch_size = target.size(0) + + _, pred = output.topk(maxk, 1, True, True) + pred = pred.t() + correct = pred.eq(target[None]) + + res = [] + for k in topk: + correct_k = correct[:k].flatten().sum(dtype=torch.float32) + res.append(correct_k * (100.0 / batch_size)) + return res + + +def mkdir(path): + try: + os.makedirs(path) + except OSError as e: + if e.errno != errno.EEXIST: + raise + + +def setup_for_distributed(is_master): + """ + This function disables printing when not in master process + """ + import builtins as __builtin__ + builtin_print = __builtin__.print + + def print(*args, **kwargs): + force = kwargs.pop('force', False) + if is_master or force: + builtin_print(*args, **kwargs) + + __builtin__.print = print + + +def is_dist_avail_and_initialized(): + if not dist.is_available(): + return False + if not dist.is_initialized(): + return False + return True + + +def get_world_size(): + if not is_dist_avail_and_initialized(): + return 1 + return dist.get_world_size() + + +def get_rank(): + if not is_dist_avail_and_initialized(): + return 0 + return dist.get_rank() + + +def is_main_process(): + return get_rank() == 0 + + +def save_on_master(*args, **kwargs): + torch.save(*args, **kwargs) + + diff --git a/PyTorch/built-in/nlp/Bert-Squad_ID0470_for_PyTorch/bert_base_config.json b/PyTorch/built-in/nlp/Bert-Squad_ID0470_for_PyTorch/bert_base_config.json index 3a28c2e648..d794ee04cc 100644 --- a/PyTorch/built-in/nlp/Bert-Squad_ID0470_for_PyTorch/bert_base_config.json +++ b/PyTorch/built-in/nlp/Bert-Squad_ID0470_for_PyTorch/bert_base_config.json @@ -1,13 +1,13 @@ -{ - "attention_probs_dropout_prob": 0.1, - "hidden_act": "gelu", - "hidden_dropout_prob": 0.1, - "hidden_size": 768, - "initializer_range": 0.02, - "intermediate_size": 3072, - "max_position_embeddings": 512, - "num_attention_heads": 12, - "num_hidden_layers": 12, - "type_vocab_size": 2, - "vocab_size": 30522 +{ + "attention_probs_dropout_prob": 0.1, + "hidden_act": "gelu", + "hidden_dropout_prob": 0.1, + "hidden_size": 768, + "initializer_range": 0.02, + "intermediate_size": 3072, + "max_position_embeddings": 512, + "num_attention_heads": 12, + "num_hidden_layers": 12, + "type_vocab_size": 2, + "vocab_size": 30522 } \ No newline at end of file diff --git a/PyTorch/built-in/nlp/Bert-Squad_ID0470_for_PyTorch/test/run_squad.py b/PyTorch/built-in/nlp/Bert-Squad_ID0470_for_PyTorch/test/run_squad.py index bd1a578b0c..c26a387a79 100644 --- a/PyTorch/built-in/nlp/Bert-Squad_ID0470_for_PyTorch/test/run_squad.py +++ b/PyTorch/built-in/nlp/Bert-Squad_ID0470_for_PyTorch/test/run_squad.py @@ -1,1282 +1,1282 @@ -# coding=utf-8 -# Copyright (c) 2019 NVIDIA CORPORATION. All rights reserved. -# Copyright 2018 The Google AI Language Team Authors and The HugginFace Inc. team. -# 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. - -"""Run BERT on SQuAD.""" - -from __future__ import absolute_import, division, print_function - -import argparse -import collections -import json -import logging -import math -import os -import random -import sys -from io import open - -import numpy as np -import torch -from torch.utils.data import (DataLoader, RandomSampler, SequentialSampler, - TensorDataset) -from torch.utils.data.distributed import DistributedSampler -# from tqdm import tqdm, trange - -from apex import amp -from schedulers import LinearWarmUpScheduler -from file_utils import PYTORCH_PRETRAINED_BERT_CACHE -import modeling -from optimization import BertAdam, warmup_linear -from tokenization import (BasicTokenizer, BertTokenizer, whitespace_tokenize) -from utils import is_main_process, format_step -import dllogger, time -from apex.optimizers import npu_fused_bert_adam, NpuFusedBertAdam - -# torch._C._jit_set_profiling_mode(False) -# torch._C._jit_set_profiling_executor(False) - -if sys.version_info[0] == 2: - import cPickle as pickle -else: - import pickle - -logging.basicConfig(format='%(asctime)s - %(levelname)s - %(name)s - %(message)s', - datefmt='%m/%d/%Y %H:%M:%S', - level=logging.INFO) -logger = logging.getLogger(__name__) - - -class NpuFusedBertAdamV2(NpuFusedBertAdam): - def _group_step(self, group_index): - group = self.param_groups[group_index] - - beta1, beta2 = group['b1'], group['b2'] - - stash = self._amp_stash - combined_group_params = stash.combined_params_indexed_by_group[group_index] - combined_group_grads = stash.combined_grads_indexed_by_group[group_index] - combined_group_param_states = stash.combined_param_states_indexed_by_group[group_index] - - for combined_param, combined_grad, combined_param_state in zip(combined_group_params, combined_group_grads, - combined_group_param_states): - if combined_param is None or combined_grad is None: - continue - exp_avg, exp_avg_sq = combined_param_state['exp_avg'], combined_param_state['exp_avg_sq'] - if group['t_total'] != -1: - scheduler_fct = npu_fused_bert_adam.SCHEDULES[group['schedule']] - lr_scheduled = group['lr'] * scheduler_fct(combined_param_state['step'] / group['t_total'], - group['warmup']) - else: - lr_scheduled = group['lr'] - combined_param.data, exp_avg, exp_avg_sq = torch.npu_bert_apply_adam(combined_param.data, exp_avg, - exp_avg_sq, lr_scheduled, beta1, beta2, - group['e'], combined_grad.data, - group['max_grad_norm'], 0, - group['weight_decay']) - combined_param_state['step'] += 1 - - -class SquadExample(object): - """ - A single training/test example for the Squad dataset. - For examples without an answer, the start and end position are -1. - """ - - def __init__(self, - qas_id, - question_text, - doc_tokens, - orig_answer_text=None, - start_position=None, - end_position=None, - is_impossible=None): - self.qas_id = qas_id - self.question_text = question_text - self.doc_tokens = doc_tokens - self.orig_answer_text = orig_answer_text - self.start_position = start_position - self.end_position = end_position - self.is_impossible = is_impossible - - def __str__(self): - return self.__repr__() - - def __repr__(self): - s = "" - s += "qas_id: %s" % (self.qas_id) - s += ", question_text: %s" % ( - self.question_text) - s += ", doc_tokens: [%s]" % (" ".join(self.doc_tokens)) - if self.start_position: - s += ", start_position: %d" % (self.start_position) - if self.end_position: - s += ", end_position: %d" % (self.end_position) - if self.is_impossible: - s += ", is_impossible: %r" % (self.is_impossible) - return s - - -class InputFeatures(object): - """A single set of features of data.""" - - def __init__(self, - unique_id, - example_index, - doc_span_index, - tokens, - token_to_orig_map, - token_is_max_context, - input_ids, - input_mask, - segment_ids, - start_position=None, - end_position=None, - is_impossible=None): - self.unique_id = unique_id - self.example_index = example_index - self.doc_span_index = doc_span_index - self.tokens = tokens - self.token_to_orig_map = token_to_orig_map - self.token_is_max_context = token_is_max_context - self.input_ids = input_ids - self.input_mask = input_mask - self.segment_ids = segment_ids - self.start_position = start_position - self.end_position = end_position - self.is_impossible = is_impossible - - -def read_squad_examples(input_file, is_training, version_2_with_negative): - """Read a SQuAD json file into a list of SquadExample.""" - with open(input_file, "r", encoding='utf-8') as reader: - input_data = json.load(reader)["data"] - - def is_whitespace(c): - if c == " " or c == "\t" or c == "\r" or c == "\n" or ord(c) == 0x202F: - return True - return False - - examples = [] - for entry in input_data: - for paragraph in entry["paragraphs"]: - paragraph_text = paragraph["context"] - doc_tokens = [] - char_to_word_offset = [] - prev_is_whitespace = True - for c in paragraph_text: - if is_whitespace(c): - prev_is_whitespace = True - else: - if prev_is_whitespace: - doc_tokens.append(c) - else: - doc_tokens[-1] += c - prev_is_whitespace = False - char_to_word_offset.append(len(doc_tokens) - 1) - - for qa in paragraph["qas"]: - qas_id = qa["id"] - question_text = qa["question"] - start_position = None - end_position = None - orig_answer_text = None - is_impossible = False - if is_training: - if version_2_with_negative: - is_impossible = qa["is_impossible"] - if (len(qa["answers"]) != 1) and (not is_impossible): - raise ValueError( - "For training, each question should have exactly 1 answer.") - if not is_impossible: - answer = qa["answers"][0] - orig_answer_text = answer["text"] - answer_offset = answer["answer_start"] - answer_length = len(orig_answer_text) - start_position = char_to_word_offset[answer_offset] - end_position = char_to_word_offset[answer_offset + answer_length - 1] - # Only add answers where the text can be exactly recovered from the - # document. If this CAN'T happen it's likely due to weird Unicode - # stuff so we will just skip the example. - # - # Note that this means for training mode, every example is NOT - # guaranteed to be preserved. - actual_text = " ".join(doc_tokens[start_position:(end_position + 1)]) - cleaned_answer_text = " ".join( - whitespace_tokenize(orig_answer_text)) - if actual_text.find(cleaned_answer_text) == -1: - logger.warning("Could not find answer: '%s' vs. '%s'", - actual_text, cleaned_answer_text) - continue - else: - start_position = -1 - end_position = -1 - orig_answer_text = "" - - example = SquadExample( - qas_id=qas_id, - question_text=question_text, - doc_tokens=doc_tokens, - orig_answer_text=orig_answer_text, - start_position=start_position, - end_position=end_position, - is_impossible=is_impossible) - examples.append(example) - return examples - - -def convert_examples_to_features(examples, tokenizer, max_seq_length, - doc_stride, max_query_length, is_training): - """Loads a data file into a list of `InputBatch`s.""" - - unique_id = 1000000000 - - features = [] - for (example_index, example) in enumerate(examples): - query_tokens = tokenizer.tokenize(example.question_text) - - if len(query_tokens) > max_query_length: - query_tokens = query_tokens[0:max_query_length] - - tok_to_orig_index = [] - orig_to_tok_index = [] - all_doc_tokens = [] - for (i, token) in enumerate(example.doc_tokens): - orig_to_tok_index.append(len(all_doc_tokens)) - sub_tokens = tokenizer.tokenize(token) - for sub_token in sub_tokens: - tok_to_orig_index.append(i) - all_doc_tokens.append(sub_token) - - tok_start_position = None - tok_end_position = None - if is_training and example.is_impossible: - tok_start_position = -1 - tok_end_position = -1 - if is_training and not example.is_impossible: - tok_start_position = orig_to_tok_index[example.start_position] - if example.end_position < len(example.doc_tokens) - 1: - tok_end_position = orig_to_tok_index[example.end_position + 1] - 1 - else: - tok_end_position = len(all_doc_tokens) - 1 - (tok_start_position, tok_end_position) = _improve_answer_span( - all_doc_tokens, tok_start_position, tok_end_position, tokenizer, - example.orig_answer_text) - - # The -3 accounts for [CLS], [SEP] and [SEP] - max_tokens_for_doc = max_seq_length - len(query_tokens) - 3 - - # We can have documents that are longer than the maximum sequence length. - # To deal with this we do a sliding window approach, where we take chunks - # of the up to our max length with a stride of `doc_stride`. - _DocSpan = collections.namedtuple( # pylint: disable=invalid-name - "DocSpan", ["start", "length"]) - doc_spans = [] - start_offset = 0 - while start_offset < len(all_doc_tokens): - length = len(all_doc_tokens) - start_offset - if length > max_tokens_for_doc: - length = max_tokens_for_doc - doc_spans.append(_DocSpan(start=start_offset, length=length)) - if start_offset + length == len(all_doc_tokens): - break - start_offset += min(length, doc_stride) - - for (doc_span_index, doc_span) in enumerate(doc_spans): - tokens = [] - token_to_orig_map = {} - token_is_max_context = {} - segment_ids = [] - tokens.append("[CLS]") - segment_ids.append(0) - for token in query_tokens: - tokens.append(token) - segment_ids.append(0) - tokens.append("[SEP]") - segment_ids.append(0) - - for i in range(doc_span.length): - split_token_index = doc_span.start + i - token_to_orig_map[len(tokens)] = tok_to_orig_index[split_token_index] - - is_max_context = _check_is_max_context(doc_spans, doc_span_index, - split_token_index) - token_is_max_context[len(tokens)] = is_max_context - tokens.append(all_doc_tokens[split_token_index]) - segment_ids.append(1) - tokens.append("[SEP]") - segment_ids.append(1) - - input_ids = tokenizer.convert_tokens_to_ids(tokens) - - # The mask has 1 for real tokens and 0 for padding tokens. Only real - # tokens are attended to. - input_mask = [1] * len(input_ids) - - # Zero-pad up to the sequence length. - while len(input_ids) < max_seq_length: - input_ids.append(0) - input_mask.append(0) - segment_ids.append(0) - - assert len(input_ids) == max_seq_length - assert len(input_mask) == max_seq_length - assert len(segment_ids) == max_seq_length - - start_position = None - end_position = None - if is_training and not example.is_impossible: - # For training, if our document chunk does not contain an annotation - # we throw it out, since there is nothing to predict. - doc_start = doc_span.start - doc_end = doc_span.start + doc_span.length - 1 - out_of_span = False - if not (tok_start_position >= doc_start and - tok_end_position <= doc_end): - out_of_span = True - if out_of_span: - start_position = 0 - end_position = 0 - else: - doc_offset = len(query_tokens) + 2 - start_position = tok_start_position - doc_start + doc_offset - end_position = tok_end_position - doc_start + doc_offset - if is_training and example.is_impossible: - start_position = 0 - end_position = 0 - - features.append( - InputFeatures( - unique_id=unique_id, - example_index=example_index, - doc_span_index=doc_span_index, - tokens=tokens, - token_to_orig_map=token_to_orig_map, - token_is_max_context=token_is_max_context, - input_ids=input_ids, - input_mask=input_mask, - segment_ids=segment_ids, - start_position=start_position, - end_position=end_position, - is_impossible=example.is_impossible)) - unique_id += 1 - - return features - - -def _improve_answer_span(doc_tokens, input_start, input_end, tokenizer, - orig_answer_text): - """Returns tokenized answer spans that better match the annotated answer.""" - - # The SQuAD annotations are character based. We first project them to - # whitespace-tokenized words. But then after WordPiece tokenization, we can - # often find a "better match". For example: - # - # Question: What year was John Smith born? - # Context: The leader was John Smith (1895-1943). - # Answer: 1895 - # - # The original whitespace-tokenized answer will be "(1895-1943).". However - # after tokenization, our tokens will be "( 1895 - 1943 ) .". So we can match - # the exact answer, 1895. - # - # However, this is not always possible. Consider the following: - # - # Question: What country is the top exporter of electornics? - # Context: The Japanese electronics industry is the lagest in the world. - # Answer: Japan - # - # In this case, the annotator chose "Japan" as a character sub-span of - # the word "Japanese". Since our WordPiece tokenizer does not split - # "Japanese", we just use "Japanese" as the annotation. This is fairly rare - # in SQuAD, but does happen. - tok_answer_text = " ".join(tokenizer.tokenize(orig_answer_text)) - - for new_start in range(input_start, input_end + 1): - for new_end in range(input_end, new_start - 1, -1): - text_span = " ".join(doc_tokens[new_start:(new_end + 1)]) - if text_span == tok_answer_text: - return (new_start, new_end) - - return (input_start, input_end) - - -def _check_is_max_context(doc_spans, cur_span_index, position): - """Check if this is the 'max context' doc span for the token.""" - - # Because of the sliding window approach taken to scoring documents, a single - # token can appear in multiple documents. E.g. - # Doc: the man went to the store and bought a gallon of milk - # Span A: the man went to the - # Span B: to the store and bought - # Span C: and bought a gallon of - # ... - # - # Now the word 'bought' will have two scores from spans B and C. We only - # want to consider the score with "maximum context", which we define as - # the *minimum* of its left and right context (the *sum* of left and - # right context will always be the same, of course). - # - # In the example the maximum context for 'bought' would be span C since - # it has 1 left context and 3 right context, while span B has 4 left context - # and 0 right context. - best_score = None - best_span_index = None - for (span_index, doc_span) in enumerate(doc_spans): - end = doc_span.start + doc_span.length - 1 - if position < doc_span.start: - continue - if position > end: - continue - num_left_context = position - doc_span.start - num_right_context = end - position - score = min(num_left_context, num_right_context) + 0.01 * doc_span.length - if best_score is None or score > best_score: - best_score = score - best_span_index = span_index - - return cur_span_index == best_span_index - - -RawResult = collections.namedtuple("RawResult", - ["unique_id", "start_logits", "end_logits"]) - - -def get_answers(examples, features, results, args): - predictions = collections.defaultdict(list) #it is possible that one example corresponds to multiple features - Prediction = collections.namedtuple('Prediction', ['text', 'start_logit', 'end_logit']) - - if args.version_2_with_negative: - null_vals = collections.defaultdict(lambda: (float("inf"),0,0)) - for ex, feat, result in match_results(examples, features, results): - start_indices = _get_best_indices(result.start_logits, args.n_best_size) - end_indices = _get_best_indices(result.end_logits, args.n_best_size) - prelim_predictions = get_valid_prelim_predictions(start_indices, end_indices, feat, result, args) - prelim_predictions = sorted( - prelim_predictions, - key=lambda x: (x.start_logit + x.end_logit), - reverse=True) - if args.version_2_with_negative: - score = result.start_logits[0] + result.end_logits[0] - if score < null_vals[ex.qas_id][0]: - null_vals[ex.qas_id] = (score, result.start_logits[0], result.end_logits[0]) - - curr_predictions = [] - seen_predictions = [] - for pred in prelim_predictions: - if len(curr_predictions) == args.n_best_size: - break - if pred.start_index > 0: # this is a non-null prediction TODO: this probably is irrelevant - final_text = get_answer_text(ex, feat, pred, args) - if final_text in seen_predictions: - continue - else: - final_text = "" - - seen_predictions.append(final_text) - curr_predictions.append(Prediction(final_text, pred.start_logit, pred.end_logit)) - predictions[ex.qas_id] += curr_predictions - - #Add empty prediction - if args.version_2_with_negative: - for qas_id in predictions.keys(): - predictions[qas_id].append(Prediction('', - null_vals[ex.qas_id][1], - null_vals[ex.qas_id][2])) - - - nbest_answers = collections.defaultdict(list) - answers = {} - for qas_id, preds in predictions.items(): - nbest = sorted( - preds, - key=lambda x: (x.start_logit + x.end_logit), - reverse=True)[:args.n_best_size] - - # In very rare edge cases we could only have single null prediction. - # So we just create a nonce prediction in this case to avoid failure. - if not nbest: - nbest.append(Prediction(text="empty", start_logit=0.0, end_logit=0.0)) - - total_scores = [] - best_non_null_entry = None - for entry in nbest: - total_scores.append(entry.start_logit + entry.end_logit) - if not best_non_null_entry and entry.text: - best_non_null_entry = entry - probs = _compute_softmax(total_scores) - for (i, entry) in enumerate(nbest): - output = collections.OrderedDict() - output["text"] = entry.text - output["probability"] = probs[i] - output["start_logit"] = entry.start_logit - output["end_logit"] = entry.end_logit - nbest_answers[qas_id].append(output) - if args.version_2_with_negative: - score_diff = null_vals[qas_id][0] - best_non_null_entry.start_logit - best_non_null_entry.end_logit - if score_diff > args.null_score_diff_threshold: - answers[qas_id] = "" - else: - answers[qas_id] = best_non_null_entry.text - else: - answers[qas_id] = nbest_answers[qas_id][0]['text'] - - return answers, nbest_answers - -def get_answer_text(example, feature, pred, args): - tok_tokens = feature.tokens[pred.start_index:(pred.end_index + 1)] - orig_doc_start = feature.token_to_orig_map[pred.start_index] - orig_doc_end = feature.token_to_orig_map[pred.end_index] - orig_tokens = example.doc_tokens[orig_doc_start:(orig_doc_end + 1)] - tok_text = " ".join(tok_tokens) - - # De-tokenize WordPieces that have been split off. - tok_text = tok_text.replace(" ##", "") - tok_text = tok_text.replace("##", "") - - # Clean whitespace - tok_text = tok_text.strip() - tok_text = " ".join(tok_text.split()) - orig_text = " ".join(orig_tokens) - - final_text = get_final_text(tok_text, orig_text, args.do_lower_case, args.verbose_logging) - return final_text - -def get_valid_prelim_predictions(start_indices, end_indices, feature, result, args): - - _PrelimPrediction = collections.namedtuple( - "PrelimPrediction", - ["start_index", "end_index", "start_logit", "end_logit"]) - prelim_predictions = [] - for start_index in start_indices: - for end_index in end_indices: - if start_index >= len(feature.tokens): - continue - if end_index >= len(feature.tokens): - continue - if start_index not in feature.token_to_orig_map: - continue - if end_index not in feature.token_to_orig_map: - continue - if not feature.token_is_max_context.get(start_index, False): - continue - if end_index < start_index: - continue - length = end_index - start_index + 1 - if length > args.max_answer_length: - continue - prelim_predictions.append( - _PrelimPrediction( - start_index=start_index, - end_index=end_index, - start_logit=result.start_logits[start_index], - end_logit=result.end_logits[end_index])) - return prelim_predictions - -def match_results(examples, features, results): - unique_f_ids = set([f.unique_id for f in features]) - unique_r_ids = set([r.unique_id for r in results]) - matching_ids = unique_f_ids & unique_r_ids - features = [f for f in features if f.unique_id in matching_ids] - results = [r for r in results if r.unique_id in matching_ids] - features.sort(key=lambda x: x.unique_id) - results.sort(key=lambda x: x.unique_id) - - for f, r in zip(features, results): #original code assumes strict ordering of examples. TODO: rewrite this - yield examples[f.example_index], f, r - -def get_final_text(pred_text, orig_text, do_lower_case, verbose_logging=False): - """Project the tokenized prediction back to the original text.""" - - # When we created the data, we kept track of the alignment between original - # (whitespace tokenized) tokens and our WordPiece tokenized tokens. So - # now `orig_text` contains the span of our original text corresponding to the - # span that we predicted. - # - # However, `orig_text` may contain extra characters that we don't want in - # our prediction. - # - # For example, let's say: - # pred_text = steve smith - # orig_text = Steve Smith's - # - # We don't want to return `orig_text` because it contains the extra "'s". - # - # We don't want to return `pred_text` because it's already been normalized - # (the SQuAD eval script also does punctuation stripping/lower casing but - # our tokenizer does additional normalization like stripping accent - # characters). - # - # What we really want to return is "Steve Smith". - # - # Therefore, we have to apply a semi-complicated alignment heruistic between - # `pred_text` and `orig_text` to get a character-to-charcter alignment. This - # can fail in certain cases in which case we just return `orig_text`. - - def _strip_spaces(text): - ns_chars = [] - ns_to_s_map = collections.OrderedDict() - for (i, c) in enumerate(text): - if c == " ": - continue - ns_to_s_map[len(ns_chars)] = i - ns_chars.append(c) - ns_text = "".join(ns_chars) - return (ns_text, ns_to_s_map) - - # We first tokenize `orig_text`, strip whitespace from the result - # and `pred_text`, and check if they are the same length. If they are - # NOT the same length, the heuristic has failed. If they are the same - # length, we assume the characters are one-to-one aligned. - - tokenizer = BasicTokenizer(do_lower_case=do_lower_case) - - tok_text = " ".join(tokenizer.tokenize(orig_text)) - - start_position = tok_text.find(pred_text) - if start_position == -1: - if verbose_logging: - logger.info( - "Unable to find text: '%s' in '%s'" % (pred_text, orig_text)) - return orig_text - end_position = start_position + len(pred_text) - 1 - - (orig_ns_text, orig_ns_to_s_map) = _strip_spaces(orig_text) - (tok_ns_text, tok_ns_to_s_map) = _strip_spaces(tok_text) - - if len(orig_ns_text) != len(tok_ns_text): - if verbose_logging: - logger.info("Length not equal after stripping spaces: '%s' vs '%s'", - orig_ns_text, tok_ns_text) - return orig_text - - # We then project the characters in `pred_text` back to `orig_text` using - # the character-to-character alignment. - tok_s_to_ns_map = {} - for (i, tok_index) in tok_ns_to_s_map.items(): - tok_s_to_ns_map[tok_index] = i - - orig_start_position = None - if start_position in tok_s_to_ns_map: - ns_start_position = tok_s_to_ns_map[start_position] - if ns_start_position in orig_ns_to_s_map: - orig_start_position = orig_ns_to_s_map[ns_start_position] - - if orig_start_position is None: - if verbose_logging: - logger.info("Couldn't map start position") - return orig_text - - orig_end_position = None - if end_position in tok_s_to_ns_map: - ns_end_position = tok_s_to_ns_map[end_position] - if ns_end_position in orig_ns_to_s_map: - orig_end_position = orig_ns_to_s_map[ns_end_position] - - if orig_end_position is None: - if verbose_logging: - logger.info("Couldn't map end position") - return orig_text - - output_text = orig_text[orig_start_position:(orig_end_position + 1)] - return output_text - - -def _get_best_indices(logits, n_best_size): - """Get the n-best logits from a list.""" - index_and_score = sorted(enumerate(logits), key=lambda x: x[1], reverse=True) - - best_indices = [] - for i in range(len(index_and_score)): - if i >= n_best_size: - break - best_indices.append(index_and_score[i][0]) - return best_indices - - -def _compute_softmax(scores): - """Compute softmax probability over raw logits.""" - if not scores: - return [] - - max_score = None - for score in scores: - if max_score is None or score > max_score: - max_score = score - - exp_scores = [] - total_sum = 0.0 - for score in scores: - x = math.exp(score - max_score) - exp_scores.append(x) - total_sum += x - - probs = [] - for score in exp_scores: - probs.append(score / total_sum) - return probs - - - -# from apex.multi_tensor_apply import multi_tensor_applier -# class GradientClipper: -# """ -# Clips gradient norm of an iterable of parameters. -# """ -# def __init__(self, max_grad_norm): -# self.max_norm = max_grad_norm -# if multi_tensor_applier.available: -# import amp_C -# self._overflow_buf = torch.cuda.IntTensor([0]) -# self.multi_tensor_l2norm = amp_C.multi_tensor_l2norm -# self.multi_tensor_scale = amp_C.multi_tensor_scale -# else: -# raise RuntimeError('Gradient clipping requires cuda extensions') -# -# def step(self, parameters): -# l = [p.grad for p in parameters if p.grad is not None] -# total_norm, _ = multi_tensor_applier(self.multi_tensor_l2norm, self._overflow_buf, [l], False) -# total_norm = total_norm.item() -# if (total_norm == float('inf')): return -# clip_coef = self.max_norm / (total_norm + 1e-6) -# if clip_coef < 1: -# multi_tensor_applier(self.multi_tensor_scale, self._overflow_buf, [l, l], clip_coef) - - -def main(): - parser = argparse.ArgumentParser() - - ## Required parameters - parser.add_argument("--bert_model", default=None, type=str, required=True, - help="Bert pre-trained model selected in the list: bert-base-uncased, " - "bert-large-uncased, bert-base-cased, bert-large-cased, bert-base-multilingual-uncased, " - "bert-base-multilingual-cased, bert-base-chinese.") - parser.add_argument("--output_dir", default=None, type=str, required=True, - help="The output directory where the model checkpoints and predictions will be written.") - parser.add_argument("--init_checkpoint", - default=None, - type=str, - required=True, - help="The checkpoint file from pretraining") - - ## Other parameters - parser.add_argument("--train_file", default=None, type=str, help="SQuAD json for training. E.g., train-v1.1.json") - parser.add_argument("--predict_file", default=None, type=str, - help="SQuAD json for predictions. E.g., dev-v1.1.json or test-v1.1.json") - parser.add_argument("--max_seq_length", default=384, type=int, - help="The maximum total input sequence length after WordPiece tokenization. Sequences " - "longer than this will be truncated, and sequences shorter than this will be padded.") - parser.add_argument("--doc_stride", default=128, type=int, - help="When splitting up a long document into chunks, how much stride to take between chunks.") - parser.add_argument("--max_query_length", default=64, type=int, - help="The maximum number of tokens for the question. Questions longer than this will " - "be truncated to this length.") - parser.add_argument("--do_train", action='store_true', help="Whether to run training.") - parser.add_argument("--do_predict", action='store_true', help="Whether to run eval on the dev set.") - parser.add_argument("--train_batch_size", default=32, type=int, help="Total batch size for training.") - parser.add_argument("--predict_batch_size", default=8, type=int, help="Total batch size for predictions.") - parser.add_argument("--learning_rate", default=5e-5, type=float, help="The initial learning rate for Adam.") - parser.add_argument("--num_train_epochs", default=3.0, type=float, - help="Total number of training epochs to perform.") - parser.add_argument("--max_steps", default=-1.0, type=float, - help="Total number of training steps to perform.") - parser.add_argument("--warmup_proportion", default=0.1, type=float, - help="Proportion of training to perform linear learning rate warmup for. E.g., 0.1 = 10%% " - "of training.") - parser.add_argument("--n_best_size", default=20, type=int, - help="The total number of n-best predictions to generate in the nbest_predictions.json " - "output file.") - parser.add_argument("--max_answer_length", default=30, type=int, - help="The maximum length of an answer that can be generated. This is needed because the start " - "and end predictions are not conditioned on one another.") - parser.add_argument("--verbose_logging", action='store_true', - help="If true, all of the warnings related to data processing will be printed. " - "A number of warnings are expected for a normal SQuAD evaluation.") - parser.add_argument("--no_cuda", - action='store_true', - help="Whether not to use CUDA when available") - parser.add_argument('--seed', - type=int, - default=42, - help="random seed for initialization") - parser.add_argument('--gradient_accumulation_steps', - type=int, - default=1, - help="Number of updates steps to accumulate before performing a backward/update pass.") - parser.add_argument("--do_lower_case", - action='store_true', - help="Whether to lower case the input text. True for uncased models, False for cased models.") - parser.add_argument("--local_rank", - type=int, - default=-1, - help="local_rank for distributed training on gpus") - parser.add_argument('--fp16', - default=False, - action='store_true', - help="Mixed precision training") - parser.add_argument('--amp', - default=False, - action='store_true', - help="Mixed precision training") - parser.add_argument('--loss_scale', - type=float, default=0, - help="Loss scaling to improve fp16 numeric stability. Only used when fp16 set to True.\n" - "0 (default value): dynamic loss scaling.\n" - "Positive power of 2: static loss scaling value.\n") - parser.add_argument('--version_2_with_negative', - action='store_true', - help='If true, the SQuAD examples contain some that do not have an answer.') - parser.add_argument('--null_score_diff_threshold', - type=float, default=0.0, - help="If null_score - best_non_null is greater than the threshold predict null.") - parser.add_argument('--vocab_file', - type=str, default=None, required=True, - help="Vocabulary mapping/file BERT was pretrainined on") - parser.add_argument("--config_file", - default=None, - type=str, - required=True, - help="The BERT model config") - parser.add_argument('--log_freq', - type=int, default=1, - help='frequency of logging loss.') - parser.add_argument('--json-summary', type=str, default="results/dllogger.json", - help='If provided, the json summary will be written to' - 'the specified file.') - parser.add_argument("--eval_script", - help="Script to evaluate squad predictions", - default="evaluate.py", - type=str) - parser.add_argument("--do_eval", - action='store_true', - help="Whether to use evaluate accuracy of predictions") - parser.add_argument("--use_env", - action='store_true', - help="Whether to read local rank from ENVVAR") - parser.add_argument('--skip_checkpoint', - default=False, - action='store_true', - help="Whether to save checkpoints") - parser.add_argument('--disable-progress-bar', - default=True, - action='store_true', - help='Disable tqdm progress bar') - parser.add_argument("--skip_cache", - default=False, - action='store_true', - help="Whether to cache train features") - parser.add_argument("--cache_dir", - default=None, - type=str, - help="Location to cache train feaures. Will default to the dataset directory") - parser.add_argument('--use_npu', - default=True, - action='store_true', - help='whether to use npu') - parser.add_argument('--npu_id', - type=int, default=0, - help='npu device id.') - parser.add_argument('--num_npu', - type=int, default=1, - help='number of npu devices to use.') - parser.add_argument("--addr", - default=None, - type=str, - help="addr used for distributed training") - - args = parser.parse_args() - args.fp16 = args.fp16 or args.amp - - if args.local_rank == -1 or args.no_cuda: - if args.use_npu: - torch.npu.set_device("npu:%d" % args.npu_id) - device = torch.device("npu:%d" % args.npu_id) - n_npu = 1 # this is the device number of one training process, usually one - else: - device = torch.device("cuda" if torch.cuda.is_available() and not args.no_cuda else "cpu") - n_npu = torch.cuda.device_count() - else: - if args.use_npu: - os.environ['MASTER_ADDR'] = args.addr - os.environ['MASTER_PORT'] = '29668' - torch.npu.set_device("npu:%d" % args.local_rank) - device = torch.device("npu:%d" % args.local_rank) - torch.distributed.init_process_group(backend='hccl', world_size=8, rank=args.local_rank) - n_npu = 1 - else: - torch.cuda.set_device(args.local_rank) - device = torch.device("cuda", args.local_rank) - # Initializes the distributed backend which will take care of sychronizing nodes/GPUs - torch.distributed.init_process_group(backend='nccl', init_method='env://') - n_npu = 1 - - if is_main_process(): - dllogger.init(backends=[dllogger.JSONStreamBackend(verbosity=dllogger.Verbosity.VERBOSE, - filename=args.json_summary), - dllogger.StdOutBackend(verbosity=dllogger.Verbosity.VERBOSE, step_format=format_step)]) - else: - dllogger.init(backends=[]) - - # print("device: {} n_npu: {}, distributed training: {}, 16-bits training: {}".format( - # device, n_npu, bool(args.local_rank != -1), args.fp16)) - print("train on device {}, rank {}".format(device, args.local_rank)) - - dllogger.log(step="PARAMETER", data={"Config": [str(args)]}) - - if args.gradient_accumulation_steps < 1: - raise ValueError("Invalid gradient_accumulation_steps parameter: {}, should be >= 1".format( - args.gradient_accumulation_steps)) - - args.train_batch_size = args.train_batch_size // args.gradient_accumulation_steps - - random.seed(args.seed) - np.random.seed(args.seed) - torch.manual_seed(args.seed) - dllogger.log(step="PARAMETER", data={"SEED": args.seed}) - - #if n_npu > 0: - # torch.cuda.manual_seed_all(args.seed) - - if not args.do_train and not args.do_predict: - raise ValueError("At least one of `do_train` or `do_predict` must be True.") - - if args.do_train: - if not args.train_file: - raise ValueError( - "If `do_train` is True, then `train_file` must be specified.") - if args.do_predict: - if not args.predict_file: - raise ValueError( - "If `do_predict` is True, then `predict_file` must be specified.") - - if os.path.exists(args.output_dir) and os.listdir(args.output_dir) and args.do_train and os.listdir(args.output_dir)!=['logfile.txt']: - print("WARNING: Output directory {} already exists and is not empty.".format(args.output_dir), os.listdir(args.output_dir)) - if not os.path.exists(args.output_dir) and is_main_process(): - os.makedirs(args.output_dir) - - tokenizer = BertTokenizer(args.vocab_file, do_lower_case=args.do_lower_case, max_len=512) # for bert large - # tokenizer = BertTokenizer.from_pretrained(args.bert_model, do_lower_case=args.do_lower_case) - - train_examples = None - num_train_optimization_steps = None - if args.do_train: - train_examples = read_squad_examples( - input_file=args.train_file, is_training=True, version_2_with_negative=args.version_2_with_negative) - num_train_optimization_steps = int( - len(train_examples) / args.train_batch_size / args.gradient_accumulation_steps) * args.num_train_epochs - if args.local_rank != -1: - num_train_optimization_steps = num_train_optimization_steps // torch.distributed.get_world_size() - - # Prepare model - config = modeling.BertConfig.from_json_file(args.config_file) - # Padding for divisibility by 8 - if config.vocab_size % 8 != 0: - config.vocab_size += 8 - (config.vocab_size % 8) - - - modeling.ACT2FN["bias_gelu"] = modeling.bias_gelu_training - model = modeling.BertForQuestionAnswering(config) - # model = modeling.BertForQuestionAnswering.from_pretrained(args.bert_model, - # cache_dir=os.path.join(str(PYTORCH_PRETRAINED_BERT_CACHE), 'distributed_{}'.format(args.local_rank))) - dllogger.log(step="PARAMETER", data={"loading_checkpoint": True}) - model.load_state_dict(torch.load(args.init_checkpoint, map_location='cpu')["model"], strict=False) - dllogger.log(step="PARAMETER", data={"loaded_checkpoint": True}) - model.to(device) - num_weights = sum([p.numel() for p in model.parameters() if p.requires_grad]) - dllogger.log(step="PARAMETER", data={"model_weights_num":num_weights}) - - # Prepare optimizer - param_optimizer = list(model.named_parameters()) - - # hack to remove pooler, which is not used - # thus it produce None grad that break apex - param_optimizer = [n for n in param_optimizer if 'pooler' not in n[0]] - - no_decay = ['bias', 'LayerNorm.bias', 'LayerNorm.weight'] - optimizer_grouped_parameters = [ - {'params': [p for n, p in param_optimizer if not any(nd in n for nd in no_decay)], 'weight_decay': 0.01}, - {'params': [p for n, p in param_optimizer if any(nd in n for nd in no_decay)], 'weight_decay': 0.0} - ] - if args.do_train: - if args.fp16: - # try: - # from apex.optimizers import NpuFusedAdam - # except ImportError: - # raise ImportError( - # "Please install apex from https://www.github.com/nvidia/apex to use distributed and fp16 training.") - # optimizer = NpuFusedAdam(optimizer_grouped_parameters, - # lr=args.learning_rate) - - optimizer = NpuFusedBertAdamV2(optimizer_grouped_parameters, - lr=args.learning_rate, - warmup=args.warmup_proportion, - t_total=num_train_optimization_steps) - - if args.loss_scale == 0: - model, optimizer = amp.initialize(model, optimizer, opt_level="O2", keep_batchnorm_fp32=False, - loss_scale="dynamic") - else: - model, optimizer = amp.initialize(model, optimizer, opt_level="O2", keep_batchnorm_fp32=False, loss_scale=args.loss_scale, combine_grad=True) - if args.do_train: - scheduler = LinearWarmUpScheduler(optimizer, warmup=args.warmup_proportion, total_steps=num_train_optimization_steps) - - else: - optimizer = BertAdam(optimizer_grouped_parameters, - lr=args.learning_rate, - warmup=args.warmup_proportion, - t_total=num_train_optimization_steps) - - #model.qa_outputs.bias.data = model.qa_outputs.bias.data.float() # for ascend910 special - if args.local_rank != -1: - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.local_rank], broadcast_buffers=False, find_unused_parameters=True) - elif n_npu > 1: - model = torch.nn.DataParallel(model) - - global_step = 0 - if args.do_train: - print("Doing train...") - if args.cache_dir is None: - cached_train_features_file = args.train_file + '_{0}_{1}_{2}_{3}'.format( - list(filter(None, args.bert_model.split('/'))).pop(), str(args.max_seq_length), str(args.doc_stride), - str(args.max_query_length)) - else: - cached_train_features_file = args.cache_dir.strip('/') + '/' + args.train_file.split('/')[-1] + '_{0}_{1}_{2}_{3}'.format( - list(filter(None, args.bert_model.split('/'))).pop(), str(args.max_seq_length), str(args.doc_stride), - str(args.max_query_length)) - - train_features = None - try: - with open(cached_train_features_file, "rb") as reader: - train_features = pickle.load(reader) - except: - train_features = convert_examples_to_features( - examples=train_examples, - tokenizer=tokenizer, - max_seq_length=args.max_seq_length, - doc_stride=args.doc_stride, - max_query_length=args.max_query_length, - is_training=True) - - if not args.skip_cache and is_main_process(): - dllogger.log(step="PARAMETER", data={"Cached_train features_file": cached_train_features_file}) - with open(cached_train_features_file, "wb") as writer: - pickle.dump(train_features, writer) - - dllogger.log(step="PARAMETER", data={"train_start": True}) - dllogger.log(step="PARAMETER", data={"training_samples": len(train_examples)}) - dllogger.log(step="PARAMETER", data={"training_features": len(train_features)}) - dllogger.log(step="PARAMETER", data={"train_batch_size":args.train_batch_size}) - dllogger.log(step="PARAMETER", data={"steps":num_train_optimization_steps}) - # all_input_ids = torch.tensor([f.input_ids for f in train_features], dtype=torch.long) - # all_input_mask = torch.tensor([f.input_mask for f in train_features], dtype=torch.long) - # all_segment_ids = torch.tensor([f.segment_ids for f in train_features], dtype=torch.long) - # all_start_positions = torch.tensor([f.start_position for f in train_features], dtype=torch.long) - # all_end_positions = torch.tensor([f.end_position for f in train_features], dtype=torch.long) - - all_input_ids = torch.tensor([f.input_ids for f in train_features], dtype=torch.int32) - all_input_mask = torch.tensor([f.input_mask for f in train_features], dtype=torch.int32) - all_segment_ids = torch.tensor([f.segment_ids for f in train_features], dtype=torch.int32) - all_start_positions = torch.tensor([f.start_position for f in train_features], dtype=torch.int32) - all_end_positions = torch.tensor([f.end_position for f in train_features], dtype=torch.int32) - - train_data = TensorDataset(all_input_ids, all_input_mask, all_segment_ids, - all_start_positions, all_end_positions) - if args.local_rank == -1: - train_sampler = RandomSampler(train_data) - else: - train_sampler = DistributedSampler(train_data) - train_dataloader = DataLoader(train_data, sampler=train_sampler, batch_size=args.train_batch_size * n_npu, num_workers=2, pin_memory=True, drop_last=True) - - model.train() - #gradClipper = GradientClipper(max_grad_norm=1.0) - final_loss = None - train_start = time.time() - for epoch in range(int(args.num_train_epochs)): - #train_iter = tqdm(train_dataloader, desc="Iteration", disable=args.disable_progress_bar) if is_main_process() else train_dataloader - train_iter = train_dataloader - step_start_time = time.time() - for step, batch in enumerate(train_iter): - torch.npu.enable_graph_mode() - # Terminate early for benchmarking - data_time = time.time() - step_start_time - if args.max_steps > 0 and global_step > args.max_steps: - break - - if n_npu == 1: - batch = tuple(t.to(device, non_blocking=True) for t in batch) # multi-gpu does scattering it-self - input_ids, input_mask, segment_ids, start_positions, end_positions = batch - start_logits, end_logits = model(input_ids, segment_ids, input_mask) - # If we are on multi-GPU, split add a dimension - if len(start_positions.size()) > 1: - start_positions = start_positions.squeeze(-1) - if len(end_positions.size()) > 1: - end_positions = end_positions.squeeze(-1) - # sometimes the start/end positions are outside our model inputs, we ignore these terms - ignored_index = start_logits.size(1) - start_positions.clamp_(0, ignored_index) - end_positions.clamp_(0, ignored_index) - - loss_fct = torch.nn.CrossEntropyLoss(ignore_index=ignored_index) - start_loss = loss_fct(start_logits, start_positions) - end_loss = loss_fct(end_logits, end_positions) - loss = (start_loss + end_loss) / 2 - if n_npu > 1: - loss = loss.mean() # mean() to average on multi-gpu. - if args.gradient_accumulation_steps > 1: - loss = loss / args.gradient_accumulation_steps - if args.fp16: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - - - if (step + 1) % args.gradient_accumulation_steps == 0: - if args.fp16 : - # modify learning rate with special warm up for BERT which FusedAdam doesn't do - scheduler.step() - optimizer.step() - optimizer.zero_grad() - global_step += 1 - torch.npu.launch_graph() - - final_loss = 0.0 - step_time = time.time() - step_start_time - if step % args.log_freq == 0: - # dllogger.log(step=(epoch, global_step,), data={"step_loss": final_loss, - # "learning_rate": optimizer.param_groups[0]['lr']}) - dllogger.log(step=(str(epoch) + '/' + str(int(args.num_train_epochs)), - str(global_step) + '/' + str(int(num_train_optimization_steps)),), - data={"step_time": round(step_time, 4), "data_time": round(data_time, 4), - "step_loss": round(final_loss, 4), - "learning_rate": round(optimizer.param_groups[0]['lr'], 10)}) - step_start_time = time.time() - torch.npu.disable_graph_mode() - - time_to_train = time.time() - train_start - - if args.do_train and is_main_process() and not args.skip_checkpoint: - # Save a trained model and the associated configuration - model_to_save = model.module if hasattr(model, 'module') else model # Only save the model it-self - output_model_file = os.path.join(args.output_dir, modeling.WEIGHTS_NAME) - torch.save({"model":model_to_save.state_dict()}, output_model_file) - output_config_file = os.path.join(args.output_dir, modeling.CONFIG_NAME) - with open(output_config_file, 'w') as f: - f.write(model_to_save.config.to_json_string()) - - if args.do_predict and (args.local_rank == -1 or is_main_process()): - print("Doing predict...") - if not args.do_train and args.fp16: - model.half() - - eval_examples = read_squad_examples( - input_file=args.predict_file, is_training=False, version_2_with_negative=args.version_2_with_negative) - eval_features = convert_examples_to_features( - examples=eval_examples, - tokenizer=tokenizer, - max_seq_length=args.max_seq_length, - doc_stride=args.doc_stride, - max_query_length=args.max_query_length, - is_training=False) - - dllogger.log(step="PARAMETER", data={"infer_start": True}) - dllogger.log(step="PARAMETER", data={"eval_samples": len(eval_examples)}) - dllogger.log(step="PARAMETER", data={"eval_features": len(eval_features)}) - dllogger.log(step="PARAMETER", data={"predict_batch_size": args.predict_batch_size}) - - all_input_ids = torch.tensor([f.input_ids for f in eval_features], dtype=torch.long) - all_input_mask = torch.tensor([f.input_mask for f in eval_features], dtype=torch.long) - all_segment_ids = torch.tensor([f.segment_ids for f in eval_features], dtype=torch.long) - # all_example_index = torch.arange(all_input_ids.size(0), dtype=torch.long) - all_example_index = torch.arange(all_input_ids.size(0), dtype=torch.int32) - eval_data = TensorDataset(all_input_ids, all_input_mask, all_segment_ids, all_example_index) - # Run prediction for full data - eval_sampler = SequentialSampler(eval_data) - eval_dataloader = DataLoader(eval_data, sampler=eval_sampler, batch_size=args.predict_batch_size) - - infer_start = time.time() - model.eval() - all_results = [] - dllogger.log(step="PARAMETER", data={"eval_start": True}) - # for input_ids, input_mask, segment_ids, example_indices in tqdm(eval_dataloader, desc="Evaluating", disable=args.disable_progress_bar): - for input_ids, input_mask, segment_ids, example_indices in eval_dataloader: - if len(all_results) % 1000 == 0: - dllogger.log(step="PARAMETER", data={"sample_number": len(all_results)}) - input_ids = input_ids.to(device) - input_mask = input_mask.to(device) - segment_ids = segment_ids.to(device) - with torch.no_grad(): - batch_start_logits, batch_end_logits = model(input_ids, segment_ids, input_mask) - for i, example_index in enumerate(example_indices): - start_logits = batch_start_logits[i].detach().cpu().tolist() - end_logits = batch_end_logits[i].detach().cpu().tolist() - eval_feature = eval_features[example_index.item()] - unique_id = int(eval_feature.unique_id) - all_results.append(RawResult(unique_id=unique_id, - start_logits=start_logits, - end_logits=end_logits)) - - time_to_infer = time.time() - infer_start - output_prediction_file = os.path.join(args.output_dir, "predictions.json") - output_nbest_file = os.path.join(args.output_dir, "nbest_predictions.json") - - answers, nbest_answers = get_answers(eval_examples, eval_features, all_results, args) - with open(output_prediction_file, "w") as f: - f.write(json.dumps(answers, indent=4) + "\n") - with open(output_nbest_file, "w") as f: - f.write(json.dumps(nbest_answers, indent=4) + "\n") - - # output_null_log_odds_file = os.path.join(args.output_dir, "null_odds.json") - # write_predictions(eval_examples, eval_features, all_results, - # args.n_best_size, args.max_answer_length, - # args.do_lower_case, output_prediction_file, - # output_nbest_file, output_null_log_odds_file, args.verbose_logging, - # args.version_2_with_negative, args.null_score_diff_threshold) - - if args.do_eval and is_main_process(): - import sys - import subprocess - eval_out = subprocess.check_output([sys.executable, args.eval_script, - args.predict_file, args.output_dir + "/predictions.json"]) - scores = str(eval_out).strip() - exact_match = float(scores.split(":")[1].split(",")[0]) - f1 = float(scores.split(":")[2].split("}")[0]) - - if args.do_train: - gpu_count = n_npu - if torch.distributed.is_initialized(): - gpu_count = torch.distributed.get_world_size() - - if args.max_steps == -1: - dllogger.log(step=tuple(), data={"e2e_train_time": time_to_train, - "training_sequences_per_second": len(train_features) * args.num_train_epochs / time_to_train, - "final_loss": final_loss}) - else: - dllogger.log(step=tuple(), data={"e2e_train_time": time_to_train, - "training_sequences_per_second": args.train_batch_size * args.gradient_accumulation_steps \ - * args.max_steps * gpu_count / time_to_train, - "final_loss": final_loss}) - if args.do_predict and is_main_process(): - dllogger.log(step=tuple(), data={"e2e_inference_time": time_to_infer, - "inference_sequences_per_second": len(eval_features) / time_to_infer}) - if args.do_eval and is_main_process(): - dllogger.log(step=tuple(), data={"exact_match": exact_match, "F1": f1}) - -if __name__ == "__main__": - option = {} - option["ACL_OP_SELECT_IMPL_MODE"] = "high_performance" - option["ACL_OPTYPELIST_FOR_IMPLMODE"] = "LayerNorm" - torch.npu.set_option(option) - main() - dllogger.flush() +# coding=utf-8 +# Copyright (c) 2019 NVIDIA CORPORATION. All rights reserved. +# Copyright 2018 The Google AI Language Team Authors and The HugginFace Inc. team. +# 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. + +"""Run BERT on SQuAD.""" + +from __future__ import absolute_import, division, print_function + +import argparse +import collections +import json +import logging +import math +import os +import random +import sys +from io import open + +import numpy as np +import torch +from torch.utils.data import (DataLoader, RandomSampler, SequentialSampler, + TensorDataset) +from torch.utils.data.distributed import DistributedSampler +# from tqdm import tqdm, trange + +from apex import amp +from schedulers import LinearWarmUpScheduler +from file_utils import PYTORCH_PRETRAINED_BERT_CACHE +import modeling +from optimization import BertAdam, warmup_linear +from tokenization import (BasicTokenizer, BertTokenizer, whitespace_tokenize) +from utils import is_main_process, format_step +import dllogger, time +from apex.optimizers import npu_fused_bert_adam, NpuFusedBertAdam + +# torch._C._jit_set_profiling_mode(False) +# torch._C._jit_set_profiling_executor(False) + +if sys.version_info[0] == 2: + import cPickle as pickle +else: + import pickle + +logging.basicConfig(format='%(asctime)s - %(levelname)s - %(name)s - %(message)s', + datefmt='%m/%d/%Y %H:%M:%S', + level=logging.INFO) +logger = logging.getLogger(__name__) + + +class NpuFusedBertAdamV2(NpuFusedBertAdam): + def _group_step(self, group_index): + group = self.param_groups[group_index] + + beta1, beta2 = group['b1'], group['b2'] + + stash = self._amp_stash + combined_group_params = stash.combined_params_indexed_by_group[group_index] + combined_group_grads = stash.combined_grads_indexed_by_group[group_index] + combined_group_param_states = stash.combined_param_states_indexed_by_group[group_index] + + for combined_param, combined_grad, combined_param_state in zip(combined_group_params, combined_group_grads, + combined_group_param_states): + if combined_param is None or combined_grad is None: + continue + exp_avg, exp_avg_sq = combined_param_state['exp_avg'], combined_param_state['exp_avg_sq'] + if group['t_total'] != -1: + scheduler_fct = npu_fused_bert_adam.SCHEDULES[group['schedule']] + lr_scheduled = group['lr'] * scheduler_fct(combined_param_state['step'] / group['t_total'], + group['warmup']) + else: + lr_scheduled = group['lr'] + combined_param.data, exp_avg, exp_avg_sq = torch.npu_bert_apply_adam(combined_param.data, exp_avg, + exp_avg_sq, lr_scheduled, beta1, beta2, + group['e'], combined_grad.data, + group['max_grad_norm'], 0, + group['weight_decay']) + combined_param_state['step'] += 1 + + +class SquadExample(object): + """ + A single training/test example for the Squad dataset. + For examples without an answer, the start and end position are -1. + """ + + def __init__(self, + qas_id, + question_text, + doc_tokens, + orig_answer_text=None, + start_position=None, + end_position=None, + is_impossible=None): + self.qas_id = qas_id + self.question_text = question_text + self.doc_tokens = doc_tokens + self.orig_answer_text = orig_answer_text + self.start_position = start_position + self.end_position = end_position + self.is_impossible = is_impossible + + def __str__(self): + return self.__repr__() + + def __repr__(self): + s = "" + s += "qas_id: %s" % (self.qas_id) + s += ", question_text: %s" % ( + self.question_text) + s += ", doc_tokens: [%s]" % (" ".join(self.doc_tokens)) + if self.start_position: + s += ", start_position: %d" % (self.start_position) + if self.end_position: + s += ", end_position: %d" % (self.end_position) + if self.is_impossible: + s += ", is_impossible: %r" % (self.is_impossible) + return s + + +class InputFeatures(object): + """A single set of features of data.""" + + def __init__(self, + unique_id, + example_index, + doc_span_index, + tokens, + token_to_orig_map, + token_is_max_context, + input_ids, + input_mask, + segment_ids, + start_position=None, + end_position=None, + is_impossible=None): + self.unique_id = unique_id + self.example_index = example_index + self.doc_span_index = doc_span_index + self.tokens = tokens + self.token_to_orig_map = token_to_orig_map + self.token_is_max_context = token_is_max_context + self.input_ids = input_ids + self.input_mask = input_mask + self.segment_ids = segment_ids + self.start_position = start_position + self.end_position = end_position + self.is_impossible = is_impossible + + +def read_squad_examples(input_file, is_training, version_2_with_negative): + """Read a SQuAD json file into a list of SquadExample.""" + with open(input_file, "r", encoding='utf-8') as reader: + input_data = json.load(reader)["data"] + + def is_whitespace(c): + if c == " " or c == "\t" or c == "\r" or c == "\n" or ord(c) == 0x202F: + return True + return False + + examples = [] + for entry in input_data: + for paragraph in entry["paragraphs"]: + paragraph_text = paragraph["context"] + doc_tokens = [] + char_to_word_offset = [] + prev_is_whitespace = True + for c in paragraph_text: + if is_whitespace(c): + prev_is_whitespace = True + else: + if prev_is_whitespace: + doc_tokens.append(c) + else: + doc_tokens[-1] += c + prev_is_whitespace = False + char_to_word_offset.append(len(doc_tokens) - 1) + + for qa in paragraph["qas"]: + qas_id = qa["id"] + question_text = qa["question"] + start_position = None + end_position = None + orig_answer_text = None + is_impossible = False + if is_training: + if version_2_with_negative: + is_impossible = qa["is_impossible"] + if (len(qa["answers"]) != 1) and (not is_impossible): + raise ValueError( + "For training, each question should have exactly 1 answer.") + if not is_impossible: + answer = qa["answers"][0] + orig_answer_text = answer["text"] + answer_offset = answer["answer_start"] + answer_length = len(orig_answer_text) + start_position = char_to_word_offset[answer_offset] + end_position = char_to_word_offset[answer_offset + answer_length - 1] + # Only add answers where the text can be exactly recovered from the + # document. If this CAN'T happen it's likely due to weird Unicode + # stuff so we will just skip the example. + # + # Note that this means for training mode, every example is NOT + # guaranteed to be preserved. + actual_text = " ".join(doc_tokens[start_position:(end_position + 1)]) + cleaned_answer_text = " ".join( + whitespace_tokenize(orig_answer_text)) + if actual_text.find(cleaned_answer_text) == -1: + logger.warning("Could not find answer: '%s' vs. '%s'", + actual_text, cleaned_answer_text) + continue + else: + start_position = -1 + end_position = -1 + orig_answer_text = "" + + example = SquadExample( + qas_id=qas_id, + question_text=question_text, + doc_tokens=doc_tokens, + orig_answer_text=orig_answer_text, + start_position=start_position, + end_position=end_position, + is_impossible=is_impossible) + examples.append(example) + return examples + + +def convert_examples_to_features(examples, tokenizer, max_seq_length, + doc_stride, max_query_length, is_training): + """Loads a data file into a list of `InputBatch`s.""" + + unique_id = 1000000000 + + features = [] + for (example_index, example) in enumerate(examples): + query_tokens = tokenizer.tokenize(example.question_text) + + if len(query_tokens) > max_query_length: + query_tokens = query_tokens[0:max_query_length] + + tok_to_orig_index = [] + orig_to_tok_index = [] + all_doc_tokens = [] + for (i, token) in enumerate(example.doc_tokens): + orig_to_tok_index.append(len(all_doc_tokens)) + sub_tokens = tokenizer.tokenize(token) + for sub_token in sub_tokens: + tok_to_orig_index.append(i) + all_doc_tokens.append(sub_token) + + tok_start_position = None + tok_end_position = None + if is_training and example.is_impossible: + tok_start_position = -1 + tok_end_position = -1 + if is_training and not example.is_impossible: + tok_start_position = orig_to_tok_index[example.start_position] + if example.end_position < len(example.doc_tokens) - 1: + tok_end_position = orig_to_tok_index[example.end_position + 1] - 1 + else: + tok_end_position = len(all_doc_tokens) - 1 + (tok_start_position, tok_end_position) = _improve_answer_span( + all_doc_tokens, tok_start_position, tok_end_position, tokenizer, + example.orig_answer_text) + + # The -3 accounts for [CLS], [SEP] and [SEP] + max_tokens_for_doc = max_seq_length - len(query_tokens) - 3 + + # We can have documents that are longer than the maximum sequence length. + # To deal with this we do a sliding window approach, where we take chunks + # of the up to our max length with a stride of `doc_stride`. + _DocSpan = collections.namedtuple( # pylint: disable=invalid-name + "DocSpan", ["start", "length"]) + doc_spans = [] + start_offset = 0 + while start_offset < len(all_doc_tokens): + length = len(all_doc_tokens) - start_offset + if length > max_tokens_for_doc: + length = max_tokens_for_doc + doc_spans.append(_DocSpan(start=start_offset, length=length)) + if start_offset + length == len(all_doc_tokens): + break + start_offset += min(length, doc_stride) + + for (doc_span_index, doc_span) in enumerate(doc_spans): + tokens = [] + token_to_orig_map = {} + token_is_max_context = {} + segment_ids = [] + tokens.append("[CLS]") + segment_ids.append(0) + for token in query_tokens: + tokens.append(token) + segment_ids.append(0) + tokens.append("[SEP]") + segment_ids.append(0) + + for i in range(doc_span.length): + split_token_index = doc_span.start + i + token_to_orig_map[len(tokens)] = tok_to_orig_index[split_token_index] + + is_max_context = _check_is_max_context(doc_spans, doc_span_index, + split_token_index) + token_is_max_context[len(tokens)] = is_max_context + tokens.append(all_doc_tokens[split_token_index]) + segment_ids.append(1) + tokens.append("[SEP]") + segment_ids.append(1) + + input_ids = tokenizer.convert_tokens_to_ids(tokens) + + # The mask has 1 for real tokens and 0 for padding tokens. Only real + # tokens are attended to. + input_mask = [1] * len(input_ids) + + # Zero-pad up to the sequence length. + while len(input_ids) < max_seq_length: + input_ids.append(0) + input_mask.append(0) + segment_ids.append(0) + + assert len(input_ids) == max_seq_length + assert len(input_mask) == max_seq_length + assert len(segment_ids) == max_seq_length + + start_position = None + end_position = None + if is_training and not example.is_impossible: + # For training, if our document chunk does not contain an annotation + # we throw it out, since there is nothing to predict. + doc_start = doc_span.start + doc_end = doc_span.start + doc_span.length - 1 + out_of_span = False + if not (tok_start_position >= doc_start and + tok_end_position <= doc_end): + out_of_span = True + if out_of_span: + start_position = 0 + end_position = 0 + else: + doc_offset = len(query_tokens) + 2 + start_position = tok_start_position - doc_start + doc_offset + end_position = tok_end_position - doc_start + doc_offset + if is_training and example.is_impossible: + start_position = 0 + end_position = 0 + + features.append( + InputFeatures( + unique_id=unique_id, + example_index=example_index, + doc_span_index=doc_span_index, + tokens=tokens, + token_to_orig_map=token_to_orig_map, + token_is_max_context=token_is_max_context, + input_ids=input_ids, + input_mask=input_mask, + segment_ids=segment_ids, + start_position=start_position, + end_position=end_position, + is_impossible=example.is_impossible)) + unique_id += 1 + + return features + + +def _improve_answer_span(doc_tokens, input_start, input_end, tokenizer, + orig_answer_text): + """Returns tokenized answer spans that better match the annotated answer.""" + + # The SQuAD annotations are character based. We first project them to + # whitespace-tokenized words. But then after WordPiece tokenization, we can + # often find a "better match". For example: + # + # Question: What year was John Smith born? + # Context: The leader was John Smith (1895-1943). + # Answer: 1895 + # + # The original whitespace-tokenized answer will be "(1895-1943).". However + # after tokenization, our tokens will be "( 1895 - 1943 ) .". So we can match + # the exact answer, 1895. + # + # However, this is not always possible. Consider the following: + # + # Question: What country is the top exporter of electornics? + # Context: The Japanese electronics industry is the lagest in the world. + # Answer: Japan + # + # In this case, the annotator chose "Japan" as a character sub-span of + # the word "Japanese". Since our WordPiece tokenizer does not split + # "Japanese", we just use "Japanese" as the annotation. This is fairly rare + # in SQuAD, but does happen. + tok_answer_text = " ".join(tokenizer.tokenize(orig_answer_text)) + + for new_start in range(input_start, input_end + 1): + for new_end in range(input_end, new_start - 1, -1): + text_span = " ".join(doc_tokens[new_start:(new_end + 1)]) + if text_span == tok_answer_text: + return (new_start, new_end) + + return (input_start, input_end) + + +def _check_is_max_context(doc_spans, cur_span_index, position): + """Check if this is the 'max context' doc span for the token.""" + + # Because of the sliding window approach taken to scoring documents, a single + # token can appear in multiple documents. E.g. + # Doc: the man went to the store and bought a gallon of milk + # Span A: the man went to the + # Span B: to the store and bought + # Span C: and bought a gallon of + # ... + # + # Now the word 'bought' will have two scores from spans B and C. We only + # want to consider the score with "maximum context", which we define as + # the *minimum* of its left and right context (the *sum* of left and + # right context will always be the same, of course). + # + # In the example the maximum context for 'bought' would be span C since + # it has 1 left context and 3 right context, while span B has 4 left context + # and 0 right context. + best_score = None + best_span_index = None + for (span_index, doc_span) in enumerate(doc_spans): + end = doc_span.start + doc_span.length - 1 + if position < doc_span.start: + continue + if position > end: + continue + num_left_context = position - doc_span.start + num_right_context = end - position + score = min(num_left_context, num_right_context) + 0.01 * doc_span.length + if best_score is None or score > best_score: + best_score = score + best_span_index = span_index + + return cur_span_index == best_span_index + + +RawResult = collections.namedtuple("RawResult", + ["unique_id", "start_logits", "end_logits"]) + + +def get_answers(examples, features, results, args): + predictions = collections.defaultdict(list) #it is possible that one example corresponds to multiple features + Prediction = collections.namedtuple('Prediction', ['text', 'start_logit', 'end_logit']) + + if args.version_2_with_negative: + null_vals = collections.defaultdict(lambda: (float("inf"),0,0)) + for ex, feat, result in match_results(examples, features, results): + start_indices = _get_best_indices(result.start_logits, args.n_best_size) + end_indices = _get_best_indices(result.end_logits, args.n_best_size) + prelim_predictions = get_valid_prelim_predictions(start_indices, end_indices, feat, result, args) + prelim_predictions = sorted( + prelim_predictions, + key=lambda x: (x.start_logit + x.end_logit), + reverse=True) + if args.version_2_with_negative: + score = result.start_logits[0] + result.end_logits[0] + if score < null_vals[ex.qas_id][0]: + null_vals[ex.qas_id] = (score, result.start_logits[0], result.end_logits[0]) + + curr_predictions = [] + seen_predictions = [] + for pred in prelim_predictions: + if len(curr_predictions) == args.n_best_size: + break + if pred.start_index > 0: # this is a non-null prediction TODO: this probably is irrelevant + final_text = get_answer_text(ex, feat, pred, args) + if final_text in seen_predictions: + continue + else: + final_text = "" + + seen_predictions.append(final_text) + curr_predictions.append(Prediction(final_text, pred.start_logit, pred.end_logit)) + predictions[ex.qas_id] += curr_predictions + + #Add empty prediction + if args.version_2_with_negative: + for qas_id in predictions.keys(): + predictions[qas_id].append(Prediction('', + null_vals[ex.qas_id][1], + null_vals[ex.qas_id][2])) + + + nbest_answers = collections.defaultdict(list) + answers = {} + for qas_id, preds in predictions.items(): + nbest = sorted( + preds, + key=lambda x: (x.start_logit + x.end_logit), + reverse=True)[:args.n_best_size] + + # In very rare edge cases we could only have single null prediction. + # So we just create a nonce prediction in this case to avoid failure. + if not nbest: + nbest.append(Prediction(text="empty", start_logit=0.0, end_logit=0.0)) + + total_scores = [] + best_non_null_entry = None + for entry in nbest: + total_scores.append(entry.start_logit + entry.end_logit) + if not best_non_null_entry and entry.text: + best_non_null_entry = entry + probs = _compute_softmax(total_scores) + for (i, entry) in enumerate(nbest): + output = collections.OrderedDict() + output["text"] = entry.text + output["probability"] = probs[i] + output["start_logit"] = entry.start_logit + output["end_logit"] = entry.end_logit + nbest_answers[qas_id].append(output) + if args.version_2_with_negative: + score_diff = null_vals[qas_id][0] - best_non_null_entry.start_logit - best_non_null_entry.end_logit + if score_diff > args.null_score_diff_threshold: + answers[qas_id] = "" + else: + answers[qas_id] = best_non_null_entry.text + else: + answers[qas_id] = nbest_answers[qas_id][0]['text'] + + return answers, nbest_answers + +def get_answer_text(example, feature, pred, args): + tok_tokens = feature.tokens[pred.start_index:(pred.end_index + 1)] + orig_doc_start = feature.token_to_orig_map[pred.start_index] + orig_doc_end = feature.token_to_orig_map[pred.end_index] + orig_tokens = example.doc_tokens[orig_doc_start:(orig_doc_end + 1)] + tok_text = " ".join(tok_tokens) + + # De-tokenize WordPieces that have been split off. + tok_text = tok_text.replace(" ##", "") + tok_text = tok_text.replace("##", "") + + # Clean whitespace + tok_text = tok_text.strip() + tok_text = " ".join(tok_text.split()) + orig_text = " ".join(orig_tokens) + + final_text = get_final_text(tok_text, orig_text, args.do_lower_case, args.verbose_logging) + return final_text + +def get_valid_prelim_predictions(start_indices, end_indices, feature, result, args): + + _PrelimPrediction = collections.namedtuple( + "PrelimPrediction", + ["start_index", "end_index", "start_logit", "end_logit"]) + prelim_predictions = [] + for start_index in start_indices: + for end_index in end_indices: + if start_index >= len(feature.tokens): + continue + if end_index >= len(feature.tokens): + continue + if start_index not in feature.token_to_orig_map: + continue + if end_index not in feature.token_to_orig_map: + continue + if not feature.token_is_max_context.get(start_index, False): + continue + if end_index < start_index: + continue + length = end_index - start_index + 1 + if length > args.max_answer_length: + continue + prelim_predictions.append( + _PrelimPrediction( + start_index=start_index, + end_index=end_index, + start_logit=result.start_logits[start_index], + end_logit=result.end_logits[end_index])) + return prelim_predictions + +def match_results(examples, features, results): + unique_f_ids = set([f.unique_id for f in features]) + unique_r_ids = set([r.unique_id for r in results]) + matching_ids = unique_f_ids & unique_r_ids + features = [f for f in features if f.unique_id in matching_ids] + results = [r for r in results if r.unique_id in matching_ids] + features.sort(key=lambda x: x.unique_id) + results.sort(key=lambda x: x.unique_id) + + for f, r in zip(features, results): #original code assumes strict ordering of examples. TODO: rewrite this + yield examples[f.example_index], f, r + +def get_final_text(pred_text, orig_text, do_lower_case, verbose_logging=False): + """Project the tokenized prediction back to the original text.""" + + # When we created the data, we kept track of the alignment between original + # (whitespace tokenized) tokens and our WordPiece tokenized tokens. So + # now `orig_text` contains the span of our original text corresponding to the + # span that we predicted. + # + # However, `orig_text` may contain extra characters that we don't want in + # our prediction. + # + # For example, let's say: + # pred_text = steve smith + # orig_text = Steve Smith's + # + # We don't want to return `orig_text` because it contains the extra "'s". + # + # We don't want to return `pred_text` because it's already been normalized + # (the SQuAD eval script also does punctuation stripping/lower casing but + # our tokenizer does additional normalization like stripping accent + # characters). + # + # What we really want to return is "Steve Smith". + # + # Therefore, we have to apply a semi-complicated alignment heruistic between + # `pred_text` and `orig_text` to get a character-to-charcter alignment. This + # can fail in certain cases in which case we just return `orig_text`. + + def _strip_spaces(text): + ns_chars = [] + ns_to_s_map = collections.OrderedDict() + for (i, c) in enumerate(text): + if c == " ": + continue + ns_to_s_map[len(ns_chars)] = i + ns_chars.append(c) + ns_text = "".join(ns_chars) + return (ns_text, ns_to_s_map) + + # We first tokenize `orig_text`, strip whitespace from the result + # and `pred_text`, and check if they are the same length. If they are + # NOT the same length, the heuristic has failed. If they are the same + # length, we assume the characters are one-to-one aligned. + + tokenizer = BasicTokenizer(do_lower_case=do_lower_case) + + tok_text = " ".join(tokenizer.tokenize(orig_text)) + + start_position = tok_text.find(pred_text) + if start_position == -1: + if verbose_logging: + logger.info( + "Unable to find text: '%s' in '%s'" % (pred_text, orig_text)) + return orig_text + end_position = start_position + len(pred_text) - 1 + + (orig_ns_text, orig_ns_to_s_map) = _strip_spaces(orig_text) + (tok_ns_text, tok_ns_to_s_map) = _strip_spaces(tok_text) + + if len(orig_ns_text) != len(tok_ns_text): + if verbose_logging: + logger.info("Length not equal after stripping spaces: '%s' vs '%s'", + orig_ns_text, tok_ns_text) + return orig_text + + # We then project the characters in `pred_text` back to `orig_text` using + # the character-to-character alignment. + tok_s_to_ns_map = {} + for (i, tok_index) in tok_ns_to_s_map.items(): + tok_s_to_ns_map[tok_index] = i + + orig_start_position = None + if start_position in tok_s_to_ns_map: + ns_start_position = tok_s_to_ns_map[start_position] + if ns_start_position in orig_ns_to_s_map: + orig_start_position = orig_ns_to_s_map[ns_start_position] + + if orig_start_position is None: + if verbose_logging: + logger.info("Couldn't map start position") + return orig_text + + orig_end_position = None + if end_position in tok_s_to_ns_map: + ns_end_position = tok_s_to_ns_map[end_position] + if ns_end_position in orig_ns_to_s_map: + orig_end_position = orig_ns_to_s_map[ns_end_position] + + if orig_end_position is None: + if verbose_logging: + logger.info("Couldn't map end position") + return orig_text + + output_text = orig_text[orig_start_position:(orig_end_position + 1)] + return output_text + + +def _get_best_indices(logits, n_best_size): + """Get the n-best logits from a list.""" + index_and_score = sorted(enumerate(logits), key=lambda x: x[1], reverse=True) + + best_indices = [] + for i in range(len(index_and_score)): + if i >= n_best_size: + break + best_indices.append(index_and_score[i][0]) + return best_indices + + +def _compute_softmax(scores): + """Compute softmax probability over raw logits.""" + if not scores: + return [] + + max_score = None + for score in scores: + if max_score is None or score > max_score: + max_score = score + + exp_scores = [] + total_sum = 0.0 + for score in scores: + x = math.exp(score - max_score) + exp_scores.append(x) + total_sum += x + + probs = [] + for score in exp_scores: + probs.append(score / total_sum) + return probs + + + +# from apex.multi_tensor_apply import multi_tensor_applier +# class GradientClipper: +# """ +# Clips gradient norm of an iterable of parameters. +# """ +# def __init__(self, max_grad_norm): +# self.max_norm = max_grad_norm +# if multi_tensor_applier.available: +# import amp_C +# self._overflow_buf = torch.cuda.IntTensor([0]) +# self.multi_tensor_l2norm = amp_C.multi_tensor_l2norm +# self.multi_tensor_scale = amp_C.multi_tensor_scale +# else: +# raise RuntimeError('Gradient clipping requires cuda extensions') +# +# def step(self, parameters): +# l = [p.grad for p in parameters if p.grad is not None] +# total_norm, _ = multi_tensor_applier(self.multi_tensor_l2norm, self._overflow_buf, [l], False) +# total_norm = total_norm.item() +# if (total_norm == float('inf')): return +# clip_coef = self.max_norm / (total_norm + 1e-6) +# if clip_coef < 1: +# multi_tensor_applier(self.multi_tensor_scale, self._overflow_buf, [l, l], clip_coef) + + +def main(): + parser = argparse.ArgumentParser() + + ## Required parameters + parser.add_argument("--bert_model", default=None, type=str, required=True, + help="Bert pre-trained model selected in the list: bert-base-uncased, " + "bert-large-uncased, bert-base-cased, bert-large-cased, bert-base-multilingual-uncased, " + "bert-base-multilingual-cased, bert-base-chinese.") + parser.add_argument("--output_dir", default=None, type=str, required=True, + help="The output directory where the model checkpoints and predictions will be written.") + parser.add_argument("--init_checkpoint", + default=None, + type=str, + required=True, + help="The checkpoint file from pretraining") + + ## Other parameters + parser.add_argument("--train_file", default=None, type=str, help="SQuAD json for training. E.g., train-v1.1.json") + parser.add_argument("--predict_file", default=None, type=str, + help="SQuAD json for predictions. E.g., dev-v1.1.json or test-v1.1.json") + parser.add_argument("--max_seq_length", default=384, type=int, + help="The maximum total input sequence length after WordPiece tokenization. Sequences " + "longer than this will be truncated, and sequences shorter than this will be padded.") + parser.add_argument("--doc_stride", default=128, type=int, + help="When splitting up a long document into chunks, how much stride to take between chunks.") + parser.add_argument("--max_query_length", default=64, type=int, + help="The maximum number of tokens for the question. Questions longer than this will " + "be truncated to this length.") + parser.add_argument("--do_train", action='store_true', help="Whether to run training.") + parser.add_argument("--do_predict", action='store_true', help="Whether to run eval on the dev set.") + parser.add_argument("--train_batch_size", default=32, type=int, help="Total batch size for training.") + parser.add_argument("--predict_batch_size", default=8, type=int, help="Total batch size for predictions.") + parser.add_argument("--learning_rate", default=5e-5, type=float, help="The initial learning rate for Adam.") + parser.add_argument("--num_train_epochs", default=3.0, type=float, + help="Total number of training epochs to perform.") + parser.add_argument("--max_steps", default=-1.0, type=float, + help="Total number of training steps to perform.") + parser.add_argument("--warmup_proportion", default=0.1, type=float, + help="Proportion of training to perform linear learning rate warmup for. E.g., 0.1 = 10%% " + "of training.") + parser.add_argument("--n_best_size", default=20, type=int, + help="The total number of n-best predictions to generate in the nbest_predictions.json " + "output file.") + parser.add_argument("--max_answer_length", default=30, type=int, + help="The maximum length of an answer that can be generated. This is needed because the start " + "and end predictions are not conditioned on one another.") + parser.add_argument("--verbose_logging", action='store_true', + help="If true, all of the warnings related to data processing will be printed. " + "A number of warnings are expected for a normal SQuAD evaluation.") + parser.add_argument("--no_cuda", + action='store_true', + help="Whether not to use CUDA when available") + parser.add_argument('--seed', + type=int, + default=42, + help="random seed for initialization") + parser.add_argument('--gradient_accumulation_steps', + type=int, + default=1, + help="Number of updates steps to accumulate before performing a backward/update pass.") + parser.add_argument("--do_lower_case", + action='store_true', + help="Whether to lower case the input text. True for uncased models, False for cased models.") + parser.add_argument("--local_rank", + type=int, + default=-1, + help="local_rank for distributed training on gpus") + parser.add_argument('--fp16', + default=False, + action='store_true', + help="Mixed precision training") + parser.add_argument('--amp', + default=False, + action='store_true', + help="Mixed precision training") + parser.add_argument('--loss_scale', + type=float, default=0, + help="Loss scaling to improve fp16 numeric stability. Only used when fp16 set to True.\n" + "0 (default value): dynamic loss scaling.\n" + "Positive power of 2: static loss scaling value.\n") + parser.add_argument('--version_2_with_negative', + action='store_true', + help='If true, the SQuAD examples contain some that do not have an answer.') + parser.add_argument('--null_score_diff_threshold', + type=float, default=0.0, + help="If null_score - best_non_null is greater than the threshold predict null.") + parser.add_argument('--vocab_file', + type=str, default=None, required=True, + help="Vocabulary mapping/file BERT was pretrainined on") + parser.add_argument("--config_file", + default=None, + type=str, + required=True, + help="The BERT model config") + parser.add_argument('--log_freq', + type=int, default=1, + help='frequency of logging loss.') + parser.add_argument('--json-summary', type=str, default="results/dllogger.json", + help='If provided, the json summary will be written to' + 'the specified file.') + parser.add_argument("--eval_script", + help="Script to evaluate squad predictions", + default="evaluate.py", + type=str) + parser.add_argument("--do_eval", + action='store_true', + help="Whether to use evaluate accuracy of predictions") + parser.add_argument("--use_env", + action='store_true', + help="Whether to read local rank from ENVVAR") + parser.add_argument('--skip_checkpoint', + default=False, + action='store_true', + help="Whether to save checkpoints") + parser.add_argument('--disable-progress-bar', + default=True, + action='store_true', + help='Disable tqdm progress bar') + parser.add_argument("--skip_cache", + default=False, + action='store_true', + help="Whether to cache train features") + parser.add_argument("--cache_dir", + default=None, + type=str, + help="Location to cache train feaures. Will default to the dataset directory") + parser.add_argument('--use_npu', + default=True, + action='store_true', + help='whether to use npu') + parser.add_argument('--npu_id', + type=int, default=0, + help='npu device id.') + parser.add_argument('--num_npu', + type=int, default=1, + help='number of npu devices to use.') + parser.add_argument("--addr", + default=None, + type=str, + help="addr used for distributed training") + + args = parser.parse_args() + args.fp16 = args.fp16 or args.amp + + if args.local_rank == -1 or args.no_cuda: + if args.use_npu: + torch.npu.set_device("npu:%d" % args.npu_id) + device = torch.device("npu:%d" % args.npu_id) + n_npu = 1 # this is the device number of one training process, usually one + else: + device = torch.device("cuda" if torch.cuda.is_available() and not args.no_cuda else "cpu") + n_npu = torch.cuda.device_count() + else: + if args.use_npu: + os.environ['MASTER_ADDR'] = args.addr + os.environ['MASTER_PORT'] = '29668' + torch.npu.set_device("npu:%d" % args.local_rank) + device = torch.device("npu:%d" % args.local_rank) + torch.distributed.init_process_group(backend='hccl', world_size=8, rank=args.local_rank) + n_npu = 1 + else: + torch.cuda.set_device(args.local_rank) + device = torch.device("cuda", args.local_rank) + # Initializes the distributed backend which will take care of sychronizing nodes/GPUs + torch.distributed.init_process_group(backend='nccl', init_method='env://') + n_npu = 1 + + if is_main_process(): + dllogger.init(backends=[dllogger.JSONStreamBackend(verbosity=dllogger.Verbosity.VERBOSE, + filename=args.json_summary), + dllogger.StdOutBackend(verbosity=dllogger.Verbosity.VERBOSE, step_format=format_step)]) + else: + dllogger.init(backends=[]) + + # print("device: {} n_npu: {}, distributed training: {}, 16-bits training: {}".format( + # device, n_npu, bool(args.local_rank != -1), args.fp16)) + print("train on device {}, rank {}".format(device, args.local_rank)) + + dllogger.log(step="PARAMETER", data={"Config": [str(args)]}) + + if args.gradient_accumulation_steps < 1: + raise ValueError("Invalid gradient_accumulation_steps parameter: {}, should be >= 1".format( + args.gradient_accumulation_steps)) + + args.train_batch_size = args.train_batch_size // args.gradient_accumulation_steps + + random.seed(args.seed) + np.random.seed(args.seed) + torch.manual_seed(args.seed) + dllogger.log(step="PARAMETER", data={"SEED": args.seed}) + + #if n_npu > 0: + # torch.cuda.manual_seed_all(args.seed) + + if not args.do_train and not args.do_predict: + raise ValueError("At least one of `do_train` or `do_predict` must be True.") + + if args.do_train: + if not args.train_file: + raise ValueError( + "If `do_train` is True, then `train_file` must be specified.") + if args.do_predict: + if not args.predict_file: + raise ValueError( + "If `do_predict` is True, then `predict_file` must be specified.") + + if os.path.exists(args.output_dir) and os.listdir(args.output_dir) and args.do_train and os.listdir(args.output_dir)!=['logfile.txt']: + print("WARNING: Output directory {} already exists and is not empty.".format(args.output_dir), os.listdir(args.output_dir)) + if not os.path.exists(args.output_dir) and is_main_process(): + os.makedirs(args.output_dir) + + tokenizer = BertTokenizer(args.vocab_file, do_lower_case=args.do_lower_case, max_len=512) # for bert large + # tokenizer = BertTokenizer.from_pretrained(args.bert_model, do_lower_case=args.do_lower_case) + + train_examples = None + num_train_optimization_steps = None + if args.do_train: + train_examples = read_squad_examples( + input_file=args.train_file, is_training=True, version_2_with_negative=args.version_2_with_negative) + num_train_optimization_steps = int( + len(train_examples) / args.train_batch_size / args.gradient_accumulation_steps) * args.num_train_epochs + if args.local_rank != -1: + num_train_optimization_steps = num_train_optimization_steps // torch.distributed.get_world_size() + + # Prepare model + config = modeling.BertConfig.from_json_file(args.config_file) + # Padding for divisibility by 8 + if config.vocab_size % 8 != 0: + config.vocab_size += 8 - (config.vocab_size % 8) + + + modeling.ACT2FN["bias_gelu"] = modeling.bias_gelu_training + model = modeling.BertForQuestionAnswering(config) + # model = modeling.BertForQuestionAnswering.from_pretrained(args.bert_model, + # cache_dir=os.path.join(str(PYTORCH_PRETRAINED_BERT_CACHE), 'distributed_{}'.format(args.local_rank))) + dllogger.log(step="PARAMETER", data={"loading_checkpoint": True}) + model.load_state_dict(torch.load(args.init_checkpoint, map_location='cpu')["model"], strict=False) + dllogger.log(step="PARAMETER", data={"loaded_checkpoint": True}) + model.to(device) + num_weights = sum([p.numel() for p in model.parameters() if p.requires_grad]) + dllogger.log(step="PARAMETER", data={"model_weights_num":num_weights}) + + # Prepare optimizer + param_optimizer = list(model.named_parameters()) + + # hack to remove pooler, which is not used + # thus it produce None grad that break apex + param_optimizer = [n for n in param_optimizer if 'pooler' not in n[0]] + + no_decay = ['bias', 'LayerNorm.bias', 'LayerNorm.weight'] + optimizer_grouped_parameters = [ + {'params': [p for n, p in param_optimizer if not any(nd in n for nd in no_decay)], 'weight_decay': 0.01}, + {'params': [p for n, p in param_optimizer if any(nd in n for nd in no_decay)], 'weight_decay': 0.0} + ] + if args.do_train: + if args.fp16: + # try: + # from apex.optimizers import NpuFusedAdam + # except ImportError: + # raise ImportError( + # "Please install apex from https://www.github.com/nvidia/apex to use distributed and fp16 training.") + # optimizer = NpuFusedAdam(optimizer_grouped_parameters, + # lr=args.learning_rate) + + optimizer = NpuFusedBertAdamV2(optimizer_grouped_parameters, + lr=args.learning_rate, + warmup=args.warmup_proportion, + t_total=num_train_optimization_steps) + + if args.loss_scale == 0: + model, optimizer = amp.initialize(model, optimizer, opt_level="O2", keep_batchnorm_fp32=False, + loss_scale="dynamic") + else: + model, optimizer = amp.initialize(model, optimizer, opt_level="O2", keep_batchnorm_fp32=False, loss_scale=args.loss_scale, combine_grad=True) + if args.do_train: + scheduler = LinearWarmUpScheduler(optimizer, warmup=args.warmup_proportion, total_steps=num_train_optimization_steps) + + else: + optimizer = BertAdam(optimizer_grouped_parameters, + lr=args.learning_rate, + warmup=args.warmup_proportion, + t_total=num_train_optimization_steps) + + #model.qa_outputs.bias.data = model.qa_outputs.bias.data.float() # for ascend910 special + if args.local_rank != -1: + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.local_rank], broadcast_buffers=False, find_unused_parameters=True) + elif n_npu > 1: + model = torch.nn.DataParallel(model) + + global_step = 0 + if args.do_train: + print("Doing train...") + if args.cache_dir is None: + cached_train_features_file = args.train_file + '_{0}_{1}_{2}_{3}'.format( + list(filter(None, args.bert_model.split('/'))).pop(), str(args.max_seq_length), str(args.doc_stride), + str(args.max_query_length)) + else: + cached_train_features_file = args.cache_dir.strip('/') + '/' + args.train_file.split('/')[-1] + '_{0}_{1}_{2}_{3}'.format( + list(filter(None, args.bert_model.split('/'))).pop(), str(args.max_seq_length), str(args.doc_stride), + str(args.max_query_length)) + + train_features = None + try: + with open(cached_train_features_file, "rb") as reader: + train_features = pickle.load(reader) + except: + train_features = convert_examples_to_features( + examples=train_examples, + tokenizer=tokenizer, + max_seq_length=args.max_seq_length, + doc_stride=args.doc_stride, + max_query_length=args.max_query_length, + is_training=True) + + if not args.skip_cache and is_main_process(): + dllogger.log(step="PARAMETER", data={"Cached_train features_file": cached_train_features_file}) + with open(cached_train_features_file, "wb") as writer: + pickle.dump(train_features, writer) + + dllogger.log(step="PARAMETER", data={"train_start": True}) + dllogger.log(step="PARAMETER", data={"training_samples": len(train_examples)}) + dllogger.log(step="PARAMETER", data={"training_features": len(train_features)}) + dllogger.log(step="PARAMETER", data={"train_batch_size":args.train_batch_size}) + dllogger.log(step="PARAMETER", data={"steps":num_train_optimization_steps}) + # all_input_ids = torch.tensor([f.input_ids for f in train_features], dtype=torch.long) + # all_input_mask = torch.tensor([f.input_mask for f in train_features], dtype=torch.long) + # all_segment_ids = torch.tensor([f.segment_ids for f in train_features], dtype=torch.long) + # all_start_positions = torch.tensor([f.start_position for f in train_features], dtype=torch.long) + # all_end_positions = torch.tensor([f.end_position for f in train_features], dtype=torch.long) + + all_input_ids = torch.tensor([f.input_ids for f in train_features], dtype=torch.int32) + all_input_mask = torch.tensor([f.input_mask for f in train_features], dtype=torch.int32) + all_segment_ids = torch.tensor([f.segment_ids for f in train_features], dtype=torch.int32) + all_start_positions = torch.tensor([f.start_position for f in train_features], dtype=torch.int32) + all_end_positions = torch.tensor([f.end_position for f in train_features], dtype=torch.int32) + + train_data = TensorDataset(all_input_ids, all_input_mask, all_segment_ids, + all_start_positions, all_end_positions) + if args.local_rank == -1: + train_sampler = RandomSampler(train_data) + else: + train_sampler = DistributedSampler(train_data) + train_dataloader = DataLoader(train_data, sampler=train_sampler, batch_size=args.train_batch_size * n_npu, num_workers=2, pin_memory=True, drop_last=True) + + model.train() + #gradClipper = GradientClipper(max_grad_norm=1.0) + final_loss = None + train_start = time.time() + for epoch in range(int(args.num_train_epochs)): + #train_iter = tqdm(train_dataloader, desc="Iteration", disable=args.disable_progress_bar) if is_main_process() else train_dataloader + train_iter = train_dataloader + step_start_time = time.time() + for step, batch in enumerate(train_iter): + torch.npu.enable_graph_mode() + # Terminate early for benchmarking + data_time = time.time() - step_start_time + if args.max_steps > 0 and global_step > args.max_steps: + break + + if n_npu == 1: + batch = tuple(t.to(device, non_blocking=True) for t in batch) # multi-gpu does scattering it-self + input_ids, input_mask, segment_ids, start_positions, end_positions = batch + start_logits, end_logits = model(input_ids, segment_ids, input_mask) + # If we are on multi-GPU, split add a dimension + if len(start_positions.size()) > 1: + start_positions = start_positions.squeeze(-1) + if len(end_positions.size()) > 1: + end_positions = end_positions.squeeze(-1) + # sometimes the start/end positions are outside our model inputs, we ignore these terms + ignored_index = start_logits.size(1) + start_positions.clamp_(0, ignored_index) + end_positions.clamp_(0, ignored_index) + + loss_fct = torch.nn.CrossEntropyLoss(ignore_index=ignored_index) + start_loss = loss_fct(start_logits, start_positions) + end_loss = loss_fct(end_logits, end_positions) + loss = (start_loss + end_loss) / 2 + if n_npu > 1: + loss = loss.mean() # mean() to average on multi-gpu. + if args.gradient_accumulation_steps > 1: + loss = loss / args.gradient_accumulation_steps + if args.fp16: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + + + if (step + 1) % args.gradient_accumulation_steps == 0: + if args.fp16 : + # modify learning rate with special warm up for BERT which FusedAdam doesn't do + scheduler.step() + optimizer.step() + optimizer.zero_grad() + global_step += 1 + torch.npu.launch_graph() + + final_loss = 0.0 + step_time = time.time() - step_start_time + if step % args.log_freq == 0: + # dllogger.log(step=(epoch, global_step,), data={"step_loss": final_loss, + # "learning_rate": optimizer.param_groups[0]['lr']}) + dllogger.log(step=(str(epoch) + '/' + str(int(args.num_train_epochs)), + str(global_step) + '/' + str(int(num_train_optimization_steps)),), + data={"step_time": round(step_time, 4), "data_time": round(data_time, 4), + "step_loss": round(final_loss, 4), + "learning_rate": round(optimizer.param_groups[0]['lr'], 10)}) + step_start_time = time.time() + torch.npu.disable_graph_mode() + + time_to_train = time.time() - train_start + + if args.do_train and is_main_process() and not args.skip_checkpoint: + # Save a trained model and the associated configuration + model_to_save = model.module if hasattr(model, 'module') else model # Only save the model it-self + output_model_file = os.path.join(args.output_dir, modeling.WEIGHTS_NAME) + torch.save({"model":model_to_save.state_dict()}, output_model_file) + output_config_file = os.path.join(args.output_dir, modeling.CONFIG_NAME) + with open(output_config_file, 'w') as f: + f.write(model_to_save.config.to_json_string()) + + if args.do_predict and (args.local_rank == -1 or is_main_process()): + print("Doing predict...") + if not args.do_train and args.fp16: + model.half() + + eval_examples = read_squad_examples( + input_file=args.predict_file, is_training=False, version_2_with_negative=args.version_2_with_negative) + eval_features = convert_examples_to_features( + examples=eval_examples, + tokenizer=tokenizer, + max_seq_length=args.max_seq_length, + doc_stride=args.doc_stride, + max_query_length=args.max_query_length, + is_training=False) + + dllogger.log(step="PARAMETER", data={"infer_start": True}) + dllogger.log(step="PARAMETER", data={"eval_samples": len(eval_examples)}) + dllogger.log(step="PARAMETER", data={"eval_features": len(eval_features)}) + dllogger.log(step="PARAMETER", data={"predict_batch_size": args.predict_batch_size}) + + all_input_ids = torch.tensor([f.input_ids for f in eval_features], dtype=torch.long) + all_input_mask = torch.tensor([f.input_mask for f in eval_features], dtype=torch.long) + all_segment_ids = torch.tensor([f.segment_ids for f in eval_features], dtype=torch.long) + # all_example_index = torch.arange(all_input_ids.size(0), dtype=torch.long) + all_example_index = torch.arange(all_input_ids.size(0), dtype=torch.int32) + eval_data = TensorDataset(all_input_ids, all_input_mask, all_segment_ids, all_example_index) + # Run prediction for full data + eval_sampler = SequentialSampler(eval_data) + eval_dataloader = DataLoader(eval_data, sampler=eval_sampler, batch_size=args.predict_batch_size) + + infer_start = time.time() + model.eval() + all_results = [] + dllogger.log(step="PARAMETER", data={"eval_start": True}) + # for input_ids, input_mask, segment_ids, example_indices in tqdm(eval_dataloader, desc="Evaluating", disable=args.disable_progress_bar): + for input_ids, input_mask, segment_ids, example_indices in eval_dataloader: + if len(all_results) % 1000 == 0: + dllogger.log(step="PARAMETER", data={"sample_number": len(all_results)}) + input_ids = input_ids.to(device) + input_mask = input_mask.to(device) + segment_ids = segment_ids.to(device) + with torch.no_grad(): + batch_start_logits, batch_end_logits = model(input_ids, segment_ids, input_mask) + for i, example_index in enumerate(example_indices): + start_logits = batch_start_logits[i].detach().cpu().tolist() + end_logits = batch_end_logits[i].detach().cpu().tolist() + eval_feature = eval_features[example_index.item()] + unique_id = int(eval_feature.unique_id) + all_results.append(RawResult(unique_id=unique_id, + start_logits=start_logits, + end_logits=end_logits)) + + time_to_infer = time.time() - infer_start + output_prediction_file = os.path.join(args.output_dir, "predictions.json") + output_nbest_file = os.path.join(args.output_dir, "nbest_predictions.json") + + answers, nbest_answers = get_answers(eval_examples, eval_features, all_results, args) + with open(output_prediction_file, "w") as f: + f.write(json.dumps(answers, indent=4) + "\n") + with open(output_nbest_file, "w") as f: + f.write(json.dumps(nbest_answers, indent=4) + "\n") + + # output_null_log_odds_file = os.path.join(args.output_dir, "null_odds.json") + # write_predictions(eval_examples, eval_features, all_results, + # args.n_best_size, args.max_answer_length, + # args.do_lower_case, output_prediction_file, + # output_nbest_file, output_null_log_odds_file, args.verbose_logging, + # args.version_2_with_negative, args.null_score_diff_threshold) + + if args.do_eval and is_main_process(): + import sys + import subprocess + eval_out = subprocess.check_output([sys.executable, args.eval_script, + args.predict_file, args.output_dir + "/predictions.json"]) + scores = str(eval_out).strip() + exact_match = float(scores.split(":")[1].split(",")[0]) + f1 = float(scores.split(":")[2].split("}")[0]) + + if args.do_train: + gpu_count = n_npu + if torch.distributed.is_initialized(): + gpu_count = torch.distributed.get_world_size() + + if args.max_steps == -1: + dllogger.log(step=tuple(), data={"e2e_train_time": time_to_train, + "training_sequences_per_second": len(train_features) * args.num_train_epochs / time_to_train, + "final_loss": final_loss}) + else: + dllogger.log(step=tuple(), data={"e2e_train_time": time_to_train, + "training_sequences_per_second": args.train_batch_size * args.gradient_accumulation_steps \ + * args.max_steps * gpu_count / time_to_train, + "final_loss": final_loss}) + if args.do_predict and is_main_process(): + dllogger.log(step=tuple(), data={"e2e_inference_time": time_to_infer, + "inference_sequences_per_second": len(eval_features) / time_to_infer}) + if args.do_eval and is_main_process(): + dllogger.log(step=tuple(), data={"exact_match": exact_match, "F1": f1}) + +if __name__ == "__main__": + option = {} + option["ACL_OP_SELECT_IMPL_MODE"] = "high_performance" + option["ACL_OPTYPELIST_FOR_IMPLMODE"] = "LayerNorm" + torch.npu.set_option(option) + main() + dllogger.flush() diff --git a/PyTorch/built-in/nlp/Bert-Squad_ID0470_for_PyTorch/test/train_performance_bert_8p.sh b/PyTorch/built-in/nlp/Bert-Squad_ID0470_for_PyTorch/test/train_performance_bert_8p.sh index f82c6f6fe2..a29b709428 100644 --- a/PyTorch/built-in/nlp/Bert-Squad_ID0470_for_PyTorch/test/train_performance_bert_8p.sh +++ b/PyTorch/built-in/nlp/Bert-Squad_ID0470_for_PyTorch/test/train_performance_bert_8p.sh @@ -1,189 +1,189 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` - -#集合通信参数,不需要修改 -export BMMV2_ENABLE=1 -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 - - -# 数据集路径,保持为空,不需要修改 -data_path="" -ckpt_path="" - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="Bert-Squad_ID0470_for_PyTorch" -#训练epoch -train_epochs=1 -#训练batch_size -batch_size=32 -#训练step -train_steps= -#学习率 -learning_rate=2e-4 - - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_fp32_to_fp16" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_performance_1P.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is False - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --ckpt_path* ]];then - ckpt_path=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cp run_squad.py $cur_path/../ -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#进入训练脚本目录,需要模型审视修改 -cd $cur_path/../ -for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); -do - #设置环境变量,不需要修改 - export ASCEND_DEVICE_ID=$RANK_ID - echo "Device ID: $ASCEND_DEVICE_ID" - export RANK_ID=$RANK_ID - - - - #创建DeviceID输出目录,不需要修改 - if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - fi - - - #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 - #--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path - nohup python3.7 run_squad.py \ - --init_checkpoint ${ckpt_path}/bert_large_pretrained_amp.pt \ - --bert_model bert-large-uncased \ - --do_train \ - --train_file ${data_path}/train-v1.1.json \ - --train_batch_size ${batch_size} \ - --do_predict \ - --predict_batch_size ${batch_size} \ - --predict_file ${data_path}/dev-v1.1.json \ - --learning_rate ${learning_rate} \ - --num_train_epochs ${train_epochs} \ - --seed 1 \ - --fp16 \ - --max_steps 100 \ - --use_npu \ - --loss_scale 4096 \ - --vocab_file "data/uncased_L-24_H-1024_A-16/vocab.txt" \ - --do_eval \ - --eval_script ${data_path}/evaluate-v1.1.py \ - --npu_id ${ASCEND_DEVICE_ID} \ - --do_lower_case \ - --output_dir ${cur_path}/../results \ - --config_file bert_config.json \ - --num_npu 8 \ - --json-summary ${cur_path}/output/${ASCEND_DEVICE_ID}/dllogger.json> ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & -done -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -step_time=`grep 'step_time : ' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print $13}'` - -FPS=`awk 'BEGIN{printf "%d\n", '$batch_size'/'$step_time'*'$RANK_SIZE'}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -train_accuracy=`grep 'F1 : ' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk '{print $10}'` -#打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p_bert'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep -r "step_loss :" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log | awk '{print $19}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -rm -rf ${data_path}/train-v1.1.json_bert-large-uncased_384_128_64 +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` + +#集合通信参数,不需要修改 +export BMMV2_ENABLE=1 +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 + + +# 数据集路径,保持为空,不需要修改 +data_path="" +ckpt_path="" + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="Bert-Squad_ID0470_for_PyTorch" +#训练epoch +train_epochs=1 +#训练batch_size +batch_size=32 +#训练step +train_steps= +#学习率 +learning_rate=2e-4 + + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_fp32_to_fp16" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_performance_1P.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is False + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --ckpt_path* ]];then + ckpt_path=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cp run_squad.py $cur_path/../ +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#进入训练脚本目录,需要模型审视修改 +cd $cur_path/../ +for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); +do + #设置环境变量,不需要修改 + export ASCEND_DEVICE_ID=$RANK_ID + echo "Device ID: $ASCEND_DEVICE_ID" + export RANK_ID=$RANK_ID + + + + #创建DeviceID输出目录,不需要修改 + if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + fi + + + #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 + #--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path + nohup python3.7 run_squad.py \ + --init_checkpoint ${ckpt_path}/bert_large_pretrained_amp.pt \ + --bert_model bert-large-uncased \ + --do_train \ + --train_file ${data_path}/train-v1.1.json \ + --train_batch_size ${batch_size} \ + --do_predict \ + --predict_batch_size ${batch_size} \ + --predict_file ${data_path}/dev-v1.1.json \ + --learning_rate ${learning_rate} \ + --num_train_epochs ${train_epochs} \ + --seed 1 \ + --fp16 \ + --max_steps 100 \ + --use_npu \ + --loss_scale 4096 \ + --vocab_file "data/uncased_L-24_H-1024_A-16/vocab.txt" \ + --do_eval \ + --eval_script ${data_path}/evaluate-v1.1.py \ + --npu_id ${ASCEND_DEVICE_ID} \ + --do_lower_case \ + --output_dir ${cur_path}/../results \ + --config_file bert_config.json \ + --num_npu 8 \ + --json-summary ${cur_path}/output/${ASCEND_DEVICE_ID}/dllogger.json> ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & +done +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +step_time=`grep 'step_time : ' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print $13}'` + +FPS=`awk 'BEGIN{printf "%d\n", '$batch_size'/'$step_time'*'$RANK_SIZE'}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +train_accuracy=`grep 'F1 : ' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk '{print $10}'` +#打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p_bert'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep -r "step_loss :" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log | awk '{print $19}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +rm -rf ${data_path}/train-v1.1.json_bert-large-uncased_384_128_64 export BMMV2_ENABLE=0 \ No newline at end of file diff --git a/PyTorch/built-in/nlp/CPM_Finetune_for_PyTorch/bpe_3w_new/readme.md b/PyTorch/built-in/nlp/CPM_Finetune_for_PyTorch/bpe_3w_new/readme.md index 37ff1ffc75..0b57ec0161 100644 --- a/PyTorch/built-in/nlp/CPM_Finetune_for_PyTorch/bpe_3w_new/readme.md +++ b/PyTorch/built-in/nlp/CPM_Finetune_for_PyTorch/bpe_3w_new/readme.md @@ -1,2 +1,2 @@ -由于文件较大已删除,如需使用请到如下地址下载相应文件 +由于文件较大已删除,如需使用请到如下地址下载相应文件 - https://github.com/TsinghuaAI/CPM-1-Generate/tree/main/bpe_3w_new \ No newline at end of file diff --git a/PyTorch/built-in/nlp/CPM_Finetune_for_PyTorch/test/eval_1p.sh b/PyTorch/built-in/nlp/CPM_Finetune_for_PyTorch/test/eval_1p.sh index ef05fefbef..64b5f1196a 100644 --- a/PyTorch/built-in/nlp/CPM_Finetune_for_PyTorch/test/eval_1p.sh +++ b/PyTorch/built-in/nlp/CPM_Finetune_for_PyTorch/test/eval_1p.sh @@ -1,116 +1,116 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -cur_path_last_dirname=${cur_path##*/} -if [ x"${cur_path_last_dirname}" == x"test" ];then - test_path_dir=${cur_path} - cd .. - cur_path=`pwd` -else - test_path_dir=${cur_path}/test -fi -source ${test_path_dir}/env_npu.sh -# 数据集路径,保持为空,不需要修改 -DATA_DIR="" -CHECKPOINT_PATH="" - -#网络名称,同目录名称 -Network="CPM_large_1p" -#训练batch_size -batch_size=1 -#集合通信参数 -RANK_SIZE=1 -MPSIZE=1 -RESULTS_DIR="../results/" -MODEL_NAME="zeroshot-test" -TOKENIZER_PATH="bpe_3w_new/" -NLAYERS=32 -NHIDDEN=2560 -NATT=32 -MAXSEQLEN=1024 -ASCEND_DEVICE_ID=0 - -#创建DeviceID输出目录,不需要修改 -if [ -d ${test_path_dir}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${test_path_dir}/output/${ASCEND_DEVICE_ID} - mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID/ -else - mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID/ -fi - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -taskset -c 0-25 python3.7 -m torch.distributed.launch --master_port ${1-1122} --nproc_per_node ${RANK_SIZE} zero-shot_chid.py \ - --data_dir ${DATA_DIR} \ - --model-parallel-size ${MPSIZE} \ - --num-layers ${NLAYERS} \ - --hidden-size ${NHIDDEN} \ - --load ${CHECKPOINT_PATH} \ - --num-attention-heads ${NATT} \ - --seq-length ${MAXSEQLEN} \ - --max-position-embeddings 1024 \ - --tokenizer-type GPT2BPETokenizer \ - --fp16 \ - --out-seq-length 512 \ - --tokenizer-path ${TOKENIZER_PATH} \ - --vocab-size 30000 \ - --batch-size ${batch_size} \ - --seed 23333 \ - --results_dir ${RESULTS_DIR} \ - --model_name ${MODEL_NAME}> ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & -wait - - - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" - -#输出性能FPS,需要模型审视修改 -FPS=`grep -a 'Test:' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk 'END {print}' |awk -F '[ ]' '{print $17}'` -FPS=${FPS#* } - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -train_accuracy=`grep -a 'Acc:' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |awk 'END {print}'|awk -F "Acc:" '{print $NF}'|awk -F " " '{print $1}'` -train_accuracy=${train_accuracy%*${train_accuracy:(-6)}} -#打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep -r "Test:" ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk -F 'Loss' '{print $NF}' | awk -F " " '{print $1}' >> ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" >> $test_path_dir/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $test_path_dir/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $test_path_dir/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $test_path_dir/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $test_path_dir/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $test_path_dir/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $test_path_dir/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}">> $test_path_dir/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $test_path_dir/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +cur_path_last_dirname=${cur_path##*/} +if [ x"${cur_path_last_dirname}" == x"test" ];then + test_path_dir=${cur_path} + cd .. + cur_path=`pwd` +else + test_path_dir=${cur_path}/test +fi +source ${test_path_dir}/env_npu.sh +# 数据集路径,保持为空,不需要修改 +DATA_DIR="" +CHECKPOINT_PATH="" + +#网络名称,同目录名称 +Network="CPM_large_1p" +#训练batch_size +batch_size=1 +#集合通信参数 +RANK_SIZE=1 +MPSIZE=1 +RESULTS_DIR="../results/" +MODEL_NAME="zeroshot-test" +TOKENIZER_PATH="bpe_3w_new/" +NLAYERS=32 +NHIDDEN=2560 +NATT=32 +MAXSEQLEN=1024 +ASCEND_DEVICE_ID=0 + +#创建DeviceID输出目录,不需要修改 +if [ -d ${test_path_dir}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${test_path_dir}/output/${ASCEND_DEVICE_ID} + mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID/ +else + mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID/ +fi + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +taskset -c 0-25 python3.7 -m torch.distributed.launch --master_port ${1-1122} --nproc_per_node ${RANK_SIZE} zero-shot_chid.py \ + --data_dir ${DATA_DIR} \ + --model-parallel-size ${MPSIZE} \ + --num-layers ${NLAYERS} \ + --hidden-size ${NHIDDEN} \ + --load ${CHECKPOINT_PATH} \ + --num-attention-heads ${NATT} \ + --seq-length ${MAXSEQLEN} \ + --max-position-embeddings 1024 \ + --tokenizer-type GPT2BPETokenizer \ + --fp16 \ + --out-seq-length 512 \ + --tokenizer-path ${TOKENIZER_PATH} \ + --vocab-size 30000 \ + --batch-size ${batch_size} \ + --seed 23333 \ + --results_dir ${RESULTS_DIR} \ + --model_name ${MODEL_NAME}> ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & +wait + + + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" + +#输出性能FPS,需要模型审视修改 +FPS=`grep -a 'Test:' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk 'END {print}' |awk -F '[ ]' '{print $17}'` +FPS=${FPS#* } + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +train_accuracy=`grep -a 'Acc:' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |awk 'END {print}'|awk -F "Acc:" '{print $NF}'|awk -F " " '{print $1}'` +train_accuracy=${train_accuracy%*${train_accuracy:(-6)}} +#打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep -r "Test:" ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk -F 'Loss' '{print $NF}' | awk -F " " '{print $1}' >> ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" >> $test_path_dir/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $test_path_dir/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $test_path_dir/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $test_path_dir/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $test_path_dir/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $test_path_dir/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $test_path_dir/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}">> $test_path_dir/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $test_path_dir/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $test_path_dir/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/built-in/nlp/GRU_for_PyTorch/test/train_full_8p.sh b/PyTorch/built-in/nlp/GRU_for_PyTorch/test/train_full_8p.sh index 7339a821a7..7044c327eb 100644 --- a/PyTorch/built-in/nlp/GRU_for_PyTorch/test/train_full_8p.sh +++ b/PyTorch/built-in/nlp/GRU_for_PyTorch/test/train_full_8p.sh @@ -1,178 +1,178 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -#export ASCEND_SLOG_PRINT_TO_STDOUT=1 - -#集合通信参数,不需要修改 -export HCCL_WHITELIST_DISABLE=1 -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 - - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="GRU_ID0104_for_PyTorch" -#训练epoch -train_epochs=10 -#训练batch_size -batch_size=4096 -#训练step -train_steps= -#学习率 -learning_rate= - - - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#执行训练脚本,以下传参不需要修改,其他需要模型审视修改 -#--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path -for i in $(seq 0 7) -do - python3 ${cur_path}/../gru_8p.py \ - --addr=$(hostname -I |awk '{print $1}') \ - --data-dir $data_path \ - --seed 123456 \ - --workers 160 \ - --print-freq 1 \ - --dist-url 'tcp://127.0.0.1:50000' \ - --dist-backend 'hccl' \ - --multiprocessing-distributed \ - --world-size 1 \ - --batch-size $batch_size \ - --epoch $train_epochs \ - --rank 0 \ - --npu $i \ - --device-list '0,1,2,3,4,5,6,7' \ - --amp \ - --bleu-npu 0 > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -done -wait - -###验证精度 -python3.7 ${cur_path}/../bleu_score.py \ - --workers 40 \ - --dist-url 'tcp://127.0.0.1:50000' \ - --data-dir $data_path \ - --world-size 1 \ - --npu 0 \ - --batch-size 512 \ - --epochs 10 \ - --rank 0 \ - --amp \ - --bleu-npu 0 \ - --ckptpath ./seq2seq-gru-model.pth.tar >> $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -#FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|tail -1|awk '{print $NF}'` -FPS=`grep -a 'FPS' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F " " '{print $NF}'|awk 'END {print}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -train_accuracy=`grep -a 'BLEU' ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk 'END {print $4}'` - -#打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}'|awk '{print $1}'| tr -s '\n' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +#export ASCEND_SLOG_PRINT_TO_STDOUT=1 + +#集合通信参数,不需要修改 +export HCCL_WHITELIST_DISABLE=1 +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 + + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="GRU_ID0104_for_PyTorch" +#训练epoch +train_epochs=10 +#训练batch_size +batch_size=4096 +#训练step +train_steps= +#学习率 +learning_rate= + + + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#执行训练脚本,以下传参不需要修改,其他需要模型审视修改 +#--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path +for i in $(seq 0 7) +do + python3 ${cur_path}/../gru_8p.py \ + --addr=$(hostname -I |awk '{print $1}') \ + --data-dir $data_path \ + --seed 123456 \ + --workers 160 \ + --print-freq 1 \ + --dist-url 'tcp://127.0.0.1:50000' \ + --dist-backend 'hccl' \ + --multiprocessing-distributed \ + --world-size 1 \ + --batch-size $batch_size \ + --epoch $train_epochs \ + --rank 0 \ + --npu $i \ + --device-list '0,1,2,3,4,5,6,7' \ + --amp \ + --bleu-npu 0 > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +done +wait + +###验证精度 +python3.7 ${cur_path}/../bleu_score.py \ + --workers 40 \ + --dist-url 'tcp://127.0.0.1:50000' \ + --data-dir $data_path \ + --world-size 1 \ + --npu 0 \ + --batch-size 512 \ + --epochs 10 \ + --rank 0 \ + --amp \ + --bleu-npu 0 \ + --ckptpath ./seq2seq-gru-model.pth.tar >> $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +#FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|tail -1|awk '{print $NF}'` +FPS=`grep -a 'FPS' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F " " '{print $NF}'|awk 'END {print}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +train_accuracy=`grep -a 'BLEU' ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk 'END {print $4}'` + +#打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'Loss' '{print $2}'|awk '{print $1}'| tr -s '\n' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/built-in/nlp/GRU_for_PyTorch/test/train_performance_1p.sh b/PyTorch/built-in/nlp/GRU_for_PyTorch/test/train_performance_1p.sh index 5ad15788e3..84eddb91f6 100644 --- a/PyTorch/built-in/nlp/GRU_for_PyTorch/test/train_performance_1p.sh +++ b/PyTorch/built-in/nlp/GRU_for_PyTorch/test/train_performance_1p.sh @@ -1,147 +1,147 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -#export ASCEND_SLOG_PRINT_TO_STDOUT=1 - -#集合通信参数,不需要修改 -export HCCL_WHITELIST_DISABLE=1 -export RANK_SIZE=1 -export JOB_ID=10087 -RANK_ID_START=0 -# source env.sh -#RANK_SIZE=8 -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="GRU_ID0104_for_PyTorch" -#训练epoch -train_epochs=4 -#训练batch_size -batch_size=1536 -#训练step -train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.045 - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -python3 ${cur_path}/../gru_1p.py \ - --data-dir $data_path \ - --workers 32 \ - --dist-url 'tcp://127.0.0.1:50000' \ - --world-size 1 \ - --npu $ASCEND_DEVICE_ID \ - --batch-size $batch_size \ - --epochs $train_epochs \ - --rank 0 \ - --amp > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk '{print $NF}'|awk '{sum+=$1} END {print sum/NR}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep -a '* Acc@1' train_0.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` - -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep npu|awk -F 'Loss' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +#export ASCEND_SLOG_PRINT_TO_STDOUT=1 + +#集合通信参数,不需要修改 +export HCCL_WHITELIST_DISABLE=1 +export RANK_SIZE=1 +export JOB_ID=10087 +RANK_ID_START=0 +# source env.sh +#RANK_SIZE=8 +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="GRU_ID0104_for_PyTorch" +#训练epoch +train_epochs=4 +#训练batch_size +batch_size=1536 +#训练step +train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.045 + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +python3 ${cur_path}/../gru_1p.py \ + --data-dir $data_path \ + --workers 32 \ + --dist-url 'tcp://127.0.0.1:50000' \ + --world-size 1 \ + --npu $ASCEND_DEVICE_ID \ + --batch-size $batch_size \ + --epochs $train_epochs \ + --rank 0 \ + --amp > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk '{print $NF}'|awk '{sum+=$1} END {print sum/NR}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep -a '* Acc@1' train_0.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` + +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep npu|awk -F 'Loss' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log diff --git a/PyTorch/built-in/nlp/GRU_for_PyTorch/test/train_performance_8p.sh b/PyTorch/built-in/nlp/GRU_for_PyTorch/test/train_performance_8p.sh index ddc94fbb5f..d941c6ce7b 100644 --- a/PyTorch/built-in/nlp/GRU_for_PyTorch/test/train_performance_8p.sh +++ b/PyTorch/built-in/nlp/GRU_for_PyTorch/test/train_performance_8p.sh @@ -1,181 +1,181 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -#export ASCEND_SLOG_PRINT_TO_STDOUT=1 - -#集合通信参数,不需要修改 -export HCCL_WHITELIST_DISABLE=1 -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 -# source env.sh -#RANK_SIZE=8 -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="GRU_ID0104_for_PyTorch" -#训练epoch -train_epochs=1 -#训练batch_size -batch_size=12288 -#训练step -train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.045 - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--amp" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -if [ $(uname -m) = "aarch64" ] -then - for i in $(seq 0 7) - do - let p_start=0+20*i - let p_end=19+20*i - taskset -c $p_start-$p_end python3 ${cur_path}/../gru_8p.py \ - --addr=$(hostname -I |awk '{print $1}') \ - --data-dir $data_path \ - --seed 123456 \ - --workers 20 \ - --print-freq 1 \ - --dist-url 'tcp://127.0.0.1:50000' \ - --dist-backend 'hccl' \ - --multiprocessing-distributed \ - --world-size 1 \ - --batch-size $batch_size \ - --epoch $train_epochs \ - --rank 0 \ - --npu $i \ - --device-list '0,1,2,3,4,5,6,7' \ - --amp > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & - done -else - for i in $(seq 0 7) - do - python3 ${cur_path}/../gru_8p.py \ - --addr=$(hostname -I |awk '{print $1}') \ - --data-dir $data_path \ - --seed 123456 \ - --workers 80 \ - --print-freq 1 \ - --dist-url 'tcp://127.0.0.1:50000' \ - --dist-backend 'hccl' \ - --multiprocessing-distributed \ - --world-size 1 \ - --batch-size 12288 \ - --epoch 10 \ - --rank 0 \ - --npu $i \ - --device-list '0,1,2,3,4,5,6,7' \ - --amp > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & - done -fi -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk '{print $NF}'|awk '{sum+=$1} END {print sum/NR}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep -a '* Acc@1' train_0.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` - -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep npu |awk -F 'Loss' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +#export ASCEND_SLOG_PRINT_TO_STDOUT=1 + +#集合通信参数,不需要修改 +export HCCL_WHITELIST_DISABLE=1 +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 +# source env.sh +#RANK_SIZE=8 +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +# export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="GRU_ID0104_for_PyTorch" +#训练epoch +train_epochs=1 +#训练batch_size +batch_size=12288 +#训练step +train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.045 + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--amp" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +if [ $(uname -m) = "aarch64" ] +then + for i in $(seq 0 7) + do + let p_start=0+20*i + let p_end=19+20*i + taskset -c $p_start-$p_end python3 ${cur_path}/../gru_8p.py \ + --addr=$(hostname -I |awk '{print $1}') \ + --data-dir $data_path \ + --seed 123456 \ + --workers 20 \ + --print-freq 1 \ + --dist-url 'tcp://127.0.0.1:50000' \ + --dist-backend 'hccl' \ + --multiprocessing-distributed \ + --world-size 1 \ + --batch-size $batch_size \ + --epoch $train_epochs \ + --rank 0 \ + --npu $i \ + --device-list '0,1,2,3,4,5,6,7' \ + --amp > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & + done +else + for i in $(seq 0 7) + do + python3 ${cur_path}/../gru_8p.py \ + --addr=$(hostname -I |awk '{print $1}') \ + --data-dir $data_path \ + --seed 123456 \ + --workers 80 \ + --print-freq 1 \ + --dist-url 'tcp://127.0.0.1:50000' \ + --dist-backend 'hccl' \ + --multiprocessing-distributed \ + --world-size 1 \ + --batch-size 12288 \ + --epoch 10 \ + --rank 0 \ + --npu $i \ + --device-list '0,1,2,3,4,5,6,7' \ + --amp > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & + done +fi +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep FPS ${cur_path}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk '{print $NF}'|awk '{sum+=$1} END {print sum/NR}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep -a '* Acc@1' train_0.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` + +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep Epoch $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep npu |awk -F 'Loss' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log diff --git a/PyTorch/built-in/nlp/Transformer_for_PyTorch/LICENSE b/PyTorch/built-in/nlp/Transformer_for_PyTorch/LICENSE index 8e39b8ee60..5dc227be93 100644 --- a/PyTorch/built-in/nlp/Transformer_for_PyTorch/LICENSE +++ b/PyTorch/built-in/nlp/Transformer_for_PyTorch/LICENSE @@ -1,32 +1,32 @@ -BSD License - -For fairseq software - -Copyright (c) 2017-present, Facebook, Inc. All rights reserved. -Copyright (c) 2019-present, NVIDIA CORPORATION. All rights reserved. -Copyright 2020 Huawei Technologies Co., Ltd - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name Facebook nor the names of its contributors may be used to - endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +BSD License + +For fairseq software + +Copyright (c) 2017-present, Facebook, Inc. All rights reserved. +Copyright (c) 2019-present, NVIDIA CORPORATION. All rights reserved. +Copyright 2020 Huawei Technologies Co., Ltd + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name Facebook nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/PyTorch/built-in/nlp/Transformer_for_PyTorch/PATENTS b/PyTorch/built-in/nlp/Transformer_for_PyTorch/PATENTS index 3e13bdabcb..1e75c56d30 100644 --- a/PyTorch/built-in/nlp/Transformer_for_PyTorch/PATENTS +++ b/PyTorch/built-in/nlp/Transformer_for_PyTorch/PATENTS @@ -1,33 +1,33 @@ -Additional Grant of Patent Rights Version 2 - -"Software" means the fairseq software distributed by Facebook, Inc. - -Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software -("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable -(subject to the termination provision below) license under any Necessary -Claims, to make, have made, use, sell, offer to sell, import, and otherwise -transfer the Software. For avoidance of doubt, no license is granted under -Facebook’s rights in any patent claims that are infringed by (i) modifications -to the Software made by you or any third party or (ii) the Software in -combination with any software or other technology. - -The license granted hereunder will terminate, automatically and without notice, -if you (or any of your subsidiaries, corporate affiliates or agents) initiate -directly or indirectly, or take a direct financial interest in, any Patent -Assertion: (i) against Facebook or any of its subsidiaries or corporate -affiliates, (ii) against any party if such Patent Assertion arises in whole or -in part from any software, technology, product or service of Facebook or any of -its subsidiaries or corporate affiliates, or (iii) against any party relating -to the Software. Notwithstanding the foregoing, if Facebook or any of its -subsidiaries or corporate affiliates files a lawsuit alleging patent -infringement against you in the first instance, and you respond by filing a -patent infringement counterclaim in that lawsuit against that party that is -unrelated to the Software, the license granted hereunder will not terminate -under section (i) of this paragraph due to such counterclaim. - -A "Necessary Claim" is a claim of a patent owned by Facebook that is -necessarily infringed by the Software standing alone. - -A "Patent Assertion" is any lawsuit or other action alleging direct, indirect, -or contributory infringement or inducement to infringe any patent, including a +Additional Grant of Patent Rights Version 2 + +"Software" means the fairseq software distributed by Facebook, Inc. + +Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software +("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable +(subject to the termination provision below) license under any Necessary +Claims, to make, have made, use, sell, offer to sell, import, and otherwise +transfer the Software. For avoidance of doubt, no license is granted under +Facebook’s rights in any patent claims that are infringed by (i) modifications +to the Software made by you or any third party or (ii) the Software in +combination with any software or other technology. + +The license granted hereunder will terminate, automatically and without notice, +if you (or any of your subsidiaries, corporate affiliates or agents) initiate +directly or indirectly, or take a direct financial interest in, any Patent +Assertion: (i) against Facebook or any of its subsidiaries or corporate +affiliates, (ii) against any party if such Patent Assertion arises in whole or +in part from any software, technology, product or service of Facebook or any of +its subsidiaries or corporate affiliates, or (iii) against any party relating +to the Software. Notwithstanding the foregoing, if Facebook or any of its +subsidiaries or corporate affiliates files a lawsuit alleging patent +infringement against you in the first instance, and you respond by filing a +patent infringement counterclaim in that lawsuit against that party that is +unrelated to the Software, the license granted hereunder will not terminate +under section (i) of this paragraph due to such counterclaim. + +A "Necessary Claim" is a claim of a patent owned by Facebook that is +necessarily infringed by the Software standing alone. + +A "Patent Assertion" is any lawsuit or other action alleging direct, indirect, +or contributory infringement or inducement to infringe any patent, including a cross-claim or counterclaim. \ No newline at end of file diff --git a/PyTorch/built-in/nlp/Transformer_for_PyTorch/README.md b/PyTorch/built-in/nlp/Transformer_for_PyTorch/README.md index 4a080bbc3e..ca56f84cfd 100644 --- a/PyTorch/built-in/nlp/Transformer_for_PyTorch/README.md +++ b/PyTorch/built-in/nlp/Transformer_for_PyTorch/README.md @@ -1,84 +1,84 @@ -# Machine Translation with Transformer - -## Requirements -* NPU配套的run包安装 -* Python 3.7.5 -* PyTorch(NPU版本) -* apex(NPU版本) -* dllogger - - -## Dataset Prepare -1. 运行sh run_preprocessing.sh下载数据集,并处理 - -## 1P -1. 编辑 train_1p.sh device-id(NPU设备号) DATA_DIR(数据集目录) MODELDIR(日志和模型保存目录) -2. 运行 sh train_1p.sh -``` -python3 -u train_1p.py \ - ./data/dataset/wmt14_en_de_joined_dict/ \ - --device-id 7\ - --arch transformer_wmt_en_de \ - --share-all-embeddings \ - --optimizer adam \ - --adam-beta1 0.9 \ - --adam-beta2 0.997 \ - --adam-eps "1e-9" \ - --clip-norm 0.0 \ - --lr-scheduler inverse_sqrt \ - --warmup-init-lr 0.0 \ - --warmup-updates 4000 \ - --lr 0.0006 \ - --min-lr 0.0 \ - --dropout 0.1 \ - --weight-decay 0.0 \ - --criterion label_smoothed_cross_entropy \ - --label-smoothing 0.1 \ - --max-sentences 128\ - --max-tokens 102400\ - --seed 1 \ - --save-dir $MODELDIR \ - --save-interval 1\ - --update-freq 8\ - --log-interval 1\ - --stat-file $STAT_FILE\ - --distributed-world-size 1\ - --amp\ - --amp-level O2 - -``` -## 8P -1. 编辑 train_8p.sh device-id(NPU设备号) DATA_DIR(数据集目录) MODELDIR(日志和模型保存目录) addr(本机设备ip) -2. 运行 sh train_8p.sh - -``` - -python3 train_np.py $DATA_DIR \ - --arch transformer_wmt_en_de \ - --share-all-embeddings \ - --optimizer adam \ - --adam-beta1 0.9 \ - --adam-beta2 0.997 \ - --addr 'XX.XXX.XXX.XXX' \ - --adam-eps "1e-9" \ - --clip-norm 0.0 \ - --lr-scheduler inverse_sqrt \ - --warmup-init-lr 0.0 \ - --warmup-updates 4000 \ - --lr 0.0006 \ - --min-lr 0.0 \ - --dropout 0.1 \ - --weight-decay 0.0 \ - --criterion label_smoothed_cross_entropy \ - --label-smoothing 0.1 \ - --max-sentences 128\ - --max-tokens 102400 \ - --seed 1 \ - --save-dir $MODELDIR \ - --stat-file $STAT_FILE\ - --log-interval 1\ - --amp\ - --amp-level O2 - -``` - +# Machine Translation with Transformer + +## Requirements +* NPU配套的run包安装 +* Python 3.7.5 +* PyTorch(NPU版本) +* apex(NPU版本) +* dllogger + + +## Dataset Prepare +1. 运行sh run_preprocessing.sh下载数据集,并处理 + +## 1P +1. 编辑 train_1p.sh device-id(NPU设备号) DATA_DIR(数据集目录) MODELDIR(日志和模型保存目录) +2. 运行 sh train_1p.sh +``` +python3 -u train_1p.py \ + ./data/dataset/wmt14_en_de_joined_dict/ \ + --device-id 7\ + --arch transformer_wmt_en_de \ + --share-all-embeddings \ + --optimizer adam \ + --adam-beta1 0.9 \ + --adam-beta2 0.997 \ + --adam-eps "1e-9" \ + --clip-norm 0.0 \ + --lr-scheduler inverse_sqrt \ + --warmup-init-lr 0.0 \ + --warmup-updates 4000 \ + --lr 0.0006 \ + --min-lr 0.0 \ + --dropout 0.1 \ + --weight-decay 0.0 \ + --criterion label_smoothed_cross_entropy \ + --label-smoothing 0.1 \ + --max-sentences 128\ + --max-tokens 102400\ + --seed 1 \ + --save-dir $MODELDIR \ + --save-interval 1\ + --update-freq 8\ + --log-interval 1\ + --stat-file $STAT_FILE\ + --distributed-world-size 1\ + --amp\ + --amp-level O2 + +``` +## 8P +1. 编辑 train_8p.sh device-id(NPU设备号) DATA_DIR(数据集目录) MODELDIR(日志和模型保存目录) addr(本机设备ip) +2. 运行 sh train_8p.sh + +``` + +python3 train_np.py $DATA_DIR \ + --arch transformer_wmt_en_de \ + --share-all-embeddings \ + --optimizer adam \ + --adam-beta1 0.9 \ + --adam-beta2 0.997 \ + --addr 'XX.XXX.XXX.XXX' \ + --adam-eps "1e-9" \ + --clip-norm 0.0 \ + --lr-scheduler inverse_sqrt \ + --warmup-init-lr 0.0 \ + --warmup-updates 4000 \ + --lr 0.0006 \ + --min-lr 0.0 \ + --dropout 0.1 \ + --weight-decay 0.0 \ + --criterion label_smoothed_cross_entropy \ + --label-smoothing 0.1 \ + --max-sentences 128\ + --max-tokens 102400 \ + --seed 1 \ + --save-dir $MODELDIR \ + --stat-file $STAT_FILE\ + --log-interval 1\ + --amp\ + --amp-level O2 + +``` + diff --git a/PyTorch/built-in/nlp/Transformer_for_PyTorch/docker_start.sh b/PyTorch/built-in/nlp/Transformer_for_PyTorch/docker_start.sh index d29feef439..f2f5cfcc8d 100644 --- a/PyTorch/built-in/nlp/Transformer_for_PyTorch/docker_start.sh +++ b/PyTorch/built-in/nlp/Transformer_for_PyTorch/docker_start.sh @@ -1,26 +1,26 @@ - -#!/bin/bash - -docker_image=$1 -data_dir=$2 -model_dir=$3 - -docker run -it --ipc=host \ - --device=/dev/davinci0 \ - --device=/dev/davinci1 \ - --device=/dev/davinci2 \ - --device=/dev/davinci3 \ - --device=/dev/davinci4 \ - --device=/dev/davinci5 \ - --device=/dev/davinci6 \ - --device=/dev/davinci7 \ - --device=/dev/davinci_manager \ - --device=/dev/devmm_svm --device=/dev/hisi_hdc \ - -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ - -v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \ - -v ${model_dir}:${model_dir} \ - -v ${data_dir}:${data_dir} \ - -v /var/log/npu/conf/slog/slog.conf:/var/log/npu/conf/slog/slog.conf \ - -v /var/log/npu/slog/:/var/log/npu/slog -v /var/log/npu/profiling/:/var/log/npu/profiling \ - -v /var/log/npu/dump/:/var/log/npu/dump -v /var/log/npu/:/usr/slog ${docker_image} \ + +#!/bin/bash + +docker_image=$1 +data_dir=$2 +model_dir=$3 + +docker run -it --ipc=host \ + --device=/dev/davinci0 \ + --device=/dev/davinci1 \ + --device=/dev/davinci2 \ + --device=/dev/davinci3 \ + --device=/dev/davinci4 \ + --device=/dev/davinci5 \ + --device=/dev/davinci6 \ + --device=/dev/davinci7 \ + --device=/dev/davinci_manager \ + --device=/dev/devmm_svm --device=/dev/hisi_hdc \ + -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ + -v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \ + -v ${model_dir}:${model_dir} \ + -v ${data_dir}:${data_dir} \ + -v /var/log/npu/conf/slog/slog.conf:/var/log/npu/conf/slog/slog.conf \ + -v /var/log/npu/slog/:/var/log/npu/slog -v /var/log/npu/profiling/:/var/log/npu/profiling \ + -v /var/log/npu/dump/:/var/log/npu/dump -v /var/log/npu/:/usr/slog ${docker_image} \ /bin/bash \ No newline at end of file diff --git a/PyTorch/built-in/nlp/Transformer_for_PyTorch/modelzoo_level.txt b/PyTorch/built-in/nlp/Transformer_for_PyTorch/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/built-in/nlp/Transformer_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/built-in/nlp/Transformer_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/built-in/nlp/Transformer_for_PyTorch/modules/multihead_attention.py b/PyTorch/built-in/nlp/Transformer_for_PyTorch/modules/multihead_attention.py index ba5e353d0e..9c2484f701 100644 --- a/PyTorch/built-in/nlp/Transformer_for_PyTorch/modules/multihead_attention.py +++ b/PyTorch/built-in/nlp/Transformer_for_PyTorch/modules/multihead_attention.py @@ -1,375 +1,375 @@ -# Copyright (c) 2017-present, Facebook, Inc. -# All rights reserved. -# Copyright 2020 Huawei Technologies Co., Ltd -# -# This source code is licensed under the license found in the LICENSE file in -# the root directory of this source tree. An additional grant of patent rights -# can be found in the PATENTS file in the same directory. -# -# ------------------------------------------------------------------------- -# -# Copyright (c) 2019, NVIDIA CORPORATION. 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 typing import Dict, Optional -import torch -from torch import nn, Tensor -from torch.nn import Parameter -import torch.nn.functional as F -from torch.autograd.variable import Variable -from utils import utils - -class QueryLinear(torch.autograd.Function): - @staticmethod - def forward(ctx, input, weights_q, scale_cpu, scale_npu): - - ctx.save_for_backward(input, weights_q, scale_cpu, scale_npu) - q = torch.addmm(input.view(input.size(0) * input.size(1), input.size(2)), - input.view(input.size(0) * input.size(1), input.size(2)), weights_q, beta=0.0, alpha=scale_cpu) - q = q.view(input.size(0), input.size(1), input.size(2)) - return q.detach() - - @staticmethod - def backward(ctx, q_grad): - input, weights_q, scale_cpu, scale_npu = ctx.saved_tensors - input = input.view(input.size(0) * input.size(1), input.size(2)).transpose(0, 1) - q = torch.addmm(q_grad.view(q_grad.size(0) * q_grad.size(1), q_grad.size(2)), - q_grad.view(q_grad.size(0) * q_grad.size(1), q_grad.size(2)), weights_q.transpose(0, 1), - beta=0.0, alpha=scale_cpu) - q = q.view(q_grad.size(0), q_grad.size(1), q_grad.size(2)) - q_grad = q_grad.view(q_grad.size(0) * q_grad.size(1), q_grad.size(2)) - weights_q_grad = scale_npu.type_as(input)*torch.mm(input, q_grad) - return q, weights_q_grad, None, None - - -class KeyValueLinears(torch.autograd.Function): - @staticmethod - def forward(ctx, input, weights_k, weights_v): - ctx.save_for_backward(input, weights_k, weights_v) - k = torch.addmm(input.view(input.size(0) * input.size(1), input.size(2)), - input.view(input.size(0) * input.size(1), input.size(2)), weights_k, beta=0.0, alpha=1.0) - k = k.view(input.size(0), input.size(1), input.size(2)) - v = torch.addmm(input.view(input.size(0) * input.size(1), input.size(2)), - input.view(input.size(0) * input.size(1), input.size(2)), weights_v, beta=0.0, alpha=1.0) - v = v.view(input.size(0), input.size(1), input.size(2)) - return k.detach(), v.detach() - - @staticmethod - def backward(ctx, k_grad, v_grad): - input, weights_k, weights_v = ctx.saved_tensors - input = input.view(input.size(0) * input.size(1), input.size(2)).transpose(0, 1) - k = torch.addmm(k_grad.view(k_grad.size(0) * k_grad.size(1), k_grad.size(2)), - k_grad.view(k_grad.size(0) * k_grad.size(1), k_grad.size(2)), weights_k.transpose(0, 1), - beta=0.0) - k_grad = k_grad.view(k_grad.size(0) * k_grad.size(1), k_grad.size(2)) - weights_k_grad = torch.mm(input, k_grad) - v = k.addmm_(v_grad.view(v_grad.size(0) * v_grad.size(1), v_grad.size(2)), weights_v.transpose(0, 1), beta=1.0) - v = v.view(v_grad.size(0), v_grad.size(1), v_grad.size(2)) - v_grad = v_grad.view(v_grad.size(0) * v_grad.size(1), v_grad.size(2)) - weights_v_grad = torch.mm(input, v_grad) - return v, weights_k_grad, weights_v_grad - - -class SelfAttentionLinears(torch.autograd.Function): - @staticmethod - def forward(ctx, input, weights_q, weights_k, weights_v, scale_cpu, scale_npu): - ctx.save_for_backward(input, weights_q, weights_k, weights_v, scale_cpu, scale_npu) - q = torch.addmm(input.contiguous().view(input.size(0) * input.size(1), input.size(2)), - input.contiguous().view(input.size(0) * input.size(1), input.size(2)), weights_q, beta=0.0, - alpha=scale_cpu) - q = q.view(input.size(0), input.size(1), input.size(2)) - k = torch.addmm(input.contiguous().view(input.size(0) * input.size(1), input.size(2)), - input.contiguous().view(input.size(0) * input.size(1), input.size(2)), weights_k, beta=0.0, - alpha=1.0) - k = k.view(input.size(0), input.size(1), input.size(2)) - v = torch.addmm(input.contiguous().view(input.size(0) * input.size(1), input.size(2)), - input.contiguous().view(input.size(0) * input.size(1), input.size(2)), weights_v, beta=0.0, - alpha=1.0) - v = v.view(input.size(0), input.size(1), input.size(2)) - return q.detach(), k.detach(), v.detach() - - @staticmethod - def backward(ctx, q_grad, k_grad, v_grad): - input, weights_q, weights_k, weights_v, scale_cpu, scale_npu = ctx.saved_tensors - input = input.contiguous().view(input.size(0) * input.size(1), input.size(2)).transpose(0, 1) - - q = torch.addmm(q_grad.view(q_grad.size(0) * q_grad.size(1), q_grad.size(2)), - q_grad.view(q_grad.size(0) * q_grad.size(1), q_grad.size(2)), weights_q.transpose(0, 1), - beta=0.0, alpha=scale_cpu) - q_grad = q_grad.view(q_grad.size(0) * q_grad.size(1), q_grad.size(2)) - weights_q_grad = scale_npu.type_as(input)*torch.mm(input,q_grad) - k = q.addmm_(k_grad.view(k_grad.size(0) * k_grad.size(1), k_grad.size(2)), weights_k.transpose(0, 1), beta=1.0) - k_grad = k_grad.view(k_grad.size(0) * k_grad.size(1), k_grad.size(2)) - weights_k_grad = torch.mm(input, k_grad) - v = k.addmm_(v_grad.view(v_grad.size(0) * v_grad.size(1), v_grad.size(2)), weights_v.transpose(0, 1), beta=1.0) - v = v.view(v_grad.size(0), v_grad.size(1), v_grad.size(2)) - v_grad = v_grad.view(v_grad.size(0) * v_grad.size(1), v_grad.size(2)) - weights_v_grad = torch.mm(input, v_grad) - return v, weights_q_grad, weights_k_grad, weights_v_grad, None, None - -class StridedBmm1Func(torch.autograd.Function): - @staticmethod - def forward(ctx, input1, input2): - ctx.save_for_backward(input1, input2) - output = torch.bmm(input1, input2) - return output.detach() - - @staticmethod - def backward(ctx, grad_output): - input1, input2 = ctx.saved_tensors - grad_output = grad_output.clone() - grad_input1 = torch.bmm(grad_output, input2.transpose(1, 2)) - grad_input2 = torch.bmm(grad_output.transpose(1, 2), input1).transpose(1, 2) - return grad_input1, grad_input2 - - -class StridedBmm2Func(torch.autograd.Function): - @staticmethod - def forward(ctx, input1, input2): - ctx.save_for_backward(input1, input2) - output = torch.bmm(input1, input2) - return output.detach() - - @staticmethod - def backward(ctx, grad_output): - input1, input2 = ctx.saved_tensors - grad_output = grad_output.clone() - grad_input1 = torch.bmm(grad_output, input2.transpose(1, 2)) - grad_input2 = torch.bmm(input1.transpose(1, 2), grad_output) - return grad_input1, grad_input2 - - -def query_linear(input: Tensor, weights_q: Tensor, scale_cpu: Tensor, scale_npu: Tensor): - return QueryLinear.apply(input, weights_q, scale_cpu, scale_npu) - -def key_value_linears(input: Tensor, weights_k: Tensor, weights_v: Tensor): - return KeyValueLinears.apply(input, weights_k, weights_v) - -def self_attn_linears(input: Tensor, weights_q: Tensor, weights_k: Tensor, weights_v: Tensor, scale_cpu: Tensor, scale_npu: Tensor): - return SelfAttentionLinears.apply(input, weights_q, weights_k, weights_v, scale_cpu, scale_npu) - -def strided_bmm1(input1: Tensor, input2: Tensor): - return StridedBmm1Func.apply(input1, input2) - -def strided_bmm2(input1: Tensor, input2: Tensor): - return StridedBmm2Func.apply(input1, input2) - -class MultiheadAttention(nn.Module): - """Multi-headed attention. - - See "Attention Is All You Need" for more details. - """ - - def __init__(self, embed_dim, num_heads, dropout=0., bias=False, seed=0): - super().__init__() - self.embed_dim = embed_dim - self.num_heads = num_heads - self.dropout = dropout - self.seed = seed - self.head_dim = embed_dim // num_heads - assert self.head_dim * num_heads == self.embed_dim, "embed_dim must be divisible by num_heads" - self.scaling = self.head_dim ** -0.5 - self.scaling_cpu = Variable(torch.tensor(self.scaling)) - self.scaling_npu = self.scaling_cpu.npu() - self._mask = torch.empty(0) - self.q_proj_weight = Parameter(torch.Tensor(embed_dim, embed_dim)) - self.k_proj_weight = Parameter(torch.Tensor(embed_dim, embed_dim)) - self.v_proj_weight = Parameter(torch.Tensor(embed_dim, embed_dim)) - if bias: - self.in_proj_bias_q = Parameter(torch.Tensor(embed_dim)) - self.in_proj_bias_k = Parameter(torch.Tensor(embed_dim)) - self.in_proj_bias_v = Parameter(torch.Tensor(embed_dim)) - else: - self.register_parameter('in_proj_bias_k', None) - self.register_parameter('in_proj_bias_q', None) - self.register_parameter('in_proj_bias_v', None) - - self.out_proj = nn.Linear(embed_dim, embed_dim, bias=bias) - - self.cache_id = str(id(self)) - self.reset_parameters() - - def reset_parameters(self): - nn.init.xavier_uniform_(self.q_proj_weight) - nn.init.xavier_uniform_(self.k_proj_weight) - nn.init.xavier_uniform_(self.v_proj_weight) - nn.init.xavier_uniform_(self.out_proj.weight) - if self.in_proj_bias_k is not None: - nn.init.constant_(self.in_proj_bias_q, 0.) - nn.init.constant_(self.in_proj_bias_k, 0.) - nn.init.constant_(self.in_proj_bias_v, 0.) - nn.init.constant_(self.out_proj.bias, 0.) - - def forward(self, query: Tensor, key: Tensor, value: Tensor, - mask_future_timesteps: bool, - key_padding_mask: Optional[Tensor], - incremental_state: Optional[Dict[str, Dict[str, Tensor]]], - need_weights: bool, - static_kv: bool): - """Input shape: Time x Batch x Channel - - Self-attention can be implemented by passing in the same arguments for - query, key and value. Future timesteps can be masked with the - `mask_future_timesteps` argument. Padding elements can be excluded from - the key by passing a binary ByteTensor (`key_padding_mask`) with shape: - batch x src_len, where padding elements are indicated by 1s. - """ - qkv_same, kv_same = self._fast_same_check(query, key, value) - - tgt_len, bsz, embed_dim = query.size() - assert embed_dim == self.embed_dim - assert list(query.size()) == [tgt_len, bsz, embed_dim] - assert key.size() == value.size() - - k = v = query.new_empty(0) - if incremental_state is not None: - saved_state = self._get_input_buffer(incremental_state) - else: - saved_state = None - - if qkv_same: - q, k, v = self_attn_linears(query, self.q_proj_weight,self.k_proj_weight, self.v_proj_weight, - self.scaling_cpu, self.scaling_npu) - elif kv_same: - q = query_linear(query, self.q_proj_weight, self.scaling_cpu, self.scaling_npu) - if not (saved_state is not None and 'prev_key' in saved_state and static_kv): - k, v = key_value_linears(key, self.k_proj_weight, self.v_proj_weight) - else: - q = torch.addmm(query.view(query.size(0) * query.size(1), query.size(2)), - query.view(query.size(0) * query.size(1), query.size(2)), self.q_proj_weight, beta=0.0, - alpha=self.scaling) - if not (saved_state is not None and 'prev_key' in saved_state and static_kv): - k = F.linear(key, self.k_proj_weight, self.in_proj_bias_k) - v = F.linear(value, self.v_proj_weight, self.in_proj_bias_v) - - if saved_state is not None: - if 'prev_key' in saved_state: - k = torch.cat((saved_state['prev_key'], k), dim=0) - if 'prev_value' in saved_state: - v = torch.cat((saved_state['prev_value'], v), dim=0) - saved_state['prev_key'] = k - saved_state['prev_value'] = v - self._set_input_buffer(incremental_state, saved_state) - - src_len = k.size(0) - - if key_padding_mask is not None: - assert key_padding_mask.size(0) == bsz - assert key_padding_mask.size(1) == src_len - - q = q.contiguous().view(tgt_len, bsz * self.num_heads, self.head_dim).clone().transpose(0, 1).contiguous() - k = k.contiguous().view(src_len, bsz * self.num_heads, self.head_dim).clone().transpose(0, 1).contiguous() - v = v.contiguous().view(src_len, bsz * self.num_heads, self.head_dim).clone().transpose(0, 1).contiguous() - - attn_weights = strided_bmm1(q, k.transpose(1, 2)) - - assert list(attn_weights.size()) == [bsz * self.num_heads, tgt_len, src_len] - - # only apply masking at training time (when incremental state is None) - if mask_future_timesteps and incremental_state is None: - assert query.size() == key.size(), \ - 'mask_future_timesteps only applies to self-attention' - attn_weights += self.buffered_mask(attn_weights).unsqueeze(0) - if key_padding_mask is not None: - # don't attend to padding symbols - attn_weights = attn_weights.view(bsz, self.num_heads, tgt_len, src_len) - - attn_weights = attn_weights.float().masked_fill( - key_padding_mask.unsqueeze(1).unsqueeze(2), - torch.finfo(torch.float32).min, - ).type_as(attn_weights) - - attn_weights = attn_weights.view(bsz * self.num_heads, tgt_len, src_len) - - attn_weights = F.softmax(attn_weights, dim=-1) - if self.training: - attn_weights, _, _ = torch.npu_dropoutV2(attn_weights, self.seed, p=self.dropout) - - attn = strided_bmm2(attn_weights, v) - assert list(attn.size()) == [bsz * self.num_heads, tgt_len, self.head_dim] - attn = attn.transpose(0, 1).contiguous().view(tgt_len, bsz, embed_dim) - - # linear - attn = self.out_proj(attn) - - if need_weights: - # average attention weights over heads - attn_weights = attn_weights.view(bsz, self.num_heads, tgt_len, src_len) - attn_weights = attn_weights.sum(dim=1) / self.num_heads - else: - attn_weights = attn_weights.new_empty(0) # Can't set to None because jit script reasons - - return attn, attn_weights - - - def in_proj_qkv(self, query): - return self._in_proj(query).chunk(3, dim=-1) - - def in_proj_kv(self, key): - return self._in_proj(key, start=self.embed_dim).chunk(2, dim=-1) - - def in_proj_q(self, query): - return self._in_proj(query, end=self.embed_dim) - - def in_proj_k(self, key): - return self._in_proj(key, start=self.embed_dim, end=2 * self.embed_dim) - - def in_proj_v(self, value): - return self._in_proj(value, start=2 * self.embed_dim) - - def _in_proj(self, input, start=None, end=None): - weight = self.in_proj_weight - bias = self.in_proj_bias - if end is not None: - weight = weight[:end, :] - if bias is not None: - bias = bias[:end] - if start is not None: - weight = weight[start:, :] - if bias is not None: - bias = bias[start:] - - res = F.linear(input, weight, bias) - return res - - def buffered_mask(self, tensor): - dim = tensor.size(-1) - if self._mask.size(0) == 0: - self._mask = torch.triu(utils.fill_with_neg_inf(tensor.new_empty(dim, dim)), 1) - if self._mask.size(0) < dim: - self._mask = torch.triu(utils.fill_with_neg_inf(self._mask.resize_(dim, dim)), 1) - return self._mask[:dim, :dim] - - def reorder_incremental_state(self, incremental_state, new_order): - """Reorder buffered internal state (for incremental generation).""" - input_buffer = self._get_input_buffer(incremental_state) - if input_buffer is not None: - for k in input_buffer.keys(): - input_buffer[k] = input_buffer[k].index_select(1, new_order) - self._set_input_buffer(incremental_state, input_buffer) - - def _get_input_buffer(self, incremental_state: Optional[Dict[str, Dict[str, Tensor]]]): - if incremental_state is None or self.cache_id not in incremental_state: - return {} - return incremental_state[self.cache_id] - - def _set_input_buffer(self, incremental_state: Optional[Dict[str, Dict[str, Tensor]]], buffer: Dict[str, Tensor]): - if incremental_state is not None: - incremental_state[self.cache_id] = buffer - - def _fast_same_check(self, q, k, v): - qkv_same = q.data_ptr() == k.data_ptr() == v.data_ptr() - kv_same = k.data_ptr() == v.data_ptr() - return qkv_same, kv_same - +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# Copyright 2020 Huawei Technologies Co., Ltd +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. +# +# ------------------------------------------------------------------------- +# +# Copyright (c) 2019, NVIDIA CORPORATION. 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 typing import Dict, Optional +import torch +from torch import nn, Tensor +from torch.nn import Parameter +import torch.nn.functional as F +from torch.autograd.variable import Variable +from utils import utils + +class QueryLinear(torch.autograd.Function): + @staticmethod + def forward(ctx, input, weights_q, scale_cpu, scale_npu): + + ctx.save_for_backward(input, weights_q, scale_cpu, scale_npu) + q = torch.addmm(input.view(input.size(0) * input.size(1), input.size(2)), + input.view(input.size(0) * input.size(1), input.size(2)), weights_q, beta=0.0, alpha=scale_cpu) + q = q.view(input.size(0), input.size(1), input.size(2)) + return q.detach() + + @staticmethod + def backward(ctx, q_grad): + input, weights_q, scale_cpu, scale_npu = ctx.saved_tensors + input = input.view(input.size(0) * input.size(1), input.size(2)).transpose(0, 1) + q = torch.addmm(q_grad.view(q_grad.size(0) * q_grad.size(1), q_grad.size(2)), + q_grad.view(q_grad.size(0) * q_grad.size(1), q_grad.size(2)), weights_q.transpose(0, 1), + beta=0.0, alpha=scale_cpu) + q = q.view(q_grad.size(0), q_grad.size(1), q_grad.size(2)) + q_grad = q_grad.view(q_grad.size(0) * q_grad.size(1), q_grad.size(2)) + weights_q_grad = scale_npu.type_as(input)*torch.mm(input, q_grad) + return q, weights_q_grad, None, None + + +class KeyValueLinears(torch.autograd.Function): + @staticmethod + def forward(ctx, input, weights_k, weights_v): + ctx.save_for_backward(input, weights_k, weights_v) + k = torch.addmm(input.view(input.size(0) * input.size(1), input.size(2)), + input.view(input.size(0) * input.size(1), input.size(2)), weights_k, beta=0.0, alpha=1.0) + k = k.view(input.size(0), input.size(1), input.size(2)) + v = torch.addmm(input.view(input.size(0) * input.size(1), input.size(2)), + input.view(input.size(0) * input.size(1), input.size(2)), weights_v, beta=0.0, alpha=1.0) + v = v.view(input.size(0), input.size(1), input.size(2)) + return k.detach(), v.detach() + + @staticmethod + def backward(ctx, k_grad, v_grad): + input, weights_k, weights_v = ctx.saved_tensors + input = input.view(input.size(0) * input.size(1), input.size(2)).transpose(0, 1) + k = torch.addmm(k_grad.view(k_grad.size(0) * k_grad.size(1), k_grad.size(2)), + k_grad.view(k_grad.size(0) * k_grad.size(1), k_grad.size(2)), weights_k.transpose(0, 1), + beta=0.0) + k_grad = k_grad.view(k_grad.size(0) * k_grad.size(1), k_grad.size(2)) + weights_k_grad = torch.mm(input, k_grad) + v = k.addmm_(v_grad.view(v_grad.size(0) * v_grad.size(1), v_grad.size(2)), weights_v.transpose(0, 1), beta=1.0) + v = v.view(v_grad.size(0), v_grad.size(1), v_grad.size(2)) + v_grad = v_grad.view(v_grad.size(0) * v_grad.size(1), v_grad.size(2)) + weights_v_grad = torch.mm(input, v_grad) + return v, weights_k_grad, weights_v_grad + + +class SelfAttentionLinears(torch.autograd.Function): + @staticmethod + def forward(ctx, input, weights_q, weights_k, weights_v, scale_cpu, scale_npu): + ctx.save_for_backward(input, weights_q, weights_k, weights_v, scale_cpu, scale_npu) + q = torch.addmm(input.contiguous().view(input.size(0) * input.size(1), input.size(2)), + input.contiguous().view(input.size(0) * input.size(1), input.size(2)), weights_q, beta=0.0, + alpha=scale_cpu) + q = q.view(input.size(0), input.size(1), input.size(2)) + k = torch.addmm(input.contiguous().view(input.size(0) * input.size(1), input.size(2)), + input.contiguous().view(input.size(0) * input.size(1), input.size(2)), weights_k, beta=0.0, + alpha=1.0) + k = k.view(input.size(0), input.size(1), input.size(2)) + v = torch.addmm(input.contiguous().view(input.size(0) * input.size(1), input.size(2)), + input.contiguous().view(input.size(0) * input.size(1), input.size(2)), weights_v, beta=0.0, + alpha=1.0) + v = v.view(input.size(0), input.size(1), input.size(2)) + return q.detach(), k.detach(), v.detach() + + @staticmethod + def backward(ctx, q_grad, k_grad, v_grad): + input, weights_q, weights_k, weights_v, scale_cpu, scale_npu = ctx.saved_tensors + input = input.contiguous().view(input.size(0) * input.size(1), input.size(2)).transpose(0, 1) + + q = torch.addmm(q_grad.view(q_grad.size(0) * q_grad.size(1), q_grad.size(2)), + q_grad.view(q_grad.size(0) * q_grad.size(1), q_grad.size(2)), weights_q.transpose(0, 1), + beta=0.0, alpha=scale_cpu) + q_grad = q_grad.view(q_grad.size(0) * q_grad.size(1), q_grad.size(2)) + weights_q_grad = scale_npu.type_as(input)*torch.mm(input,q_grad) + k = q.addmm_(k_grad.view(k_grad.size(0) * k_grad.size(1), k_grad.size(2)), weights_k.transpose(0, 1), beta=1.0) + k_grad = k_grad.view(k_grad.size(0) * k_grad.size(1), k_grad.size(2)) + weights_k_grad = torch.mm(input, k_grad) + v = k.addmm_(v_grad.view(v_grad.size(0) * v_grad.size(1), v_grad.size(2)), weights_v.transpose(0, 1), beta=1.0) + v = v.view(v_grad.size(0), v_grad.size(1), v_grad.size(2)) + v_grad = v_grad.view(v_grad.size(0) * v_grad.size(1), v_grad.size(2)) + weights_v_grad = torch.mm(input, v_grad) + return v, weights_q_grad, weights_k_grad, weights_v_grad, None, None + +class StridedBmm1Func(torch.autograd.Function): + @staticmethod + def forward(ctx, input1, input2): + ctx.save_for_backward(input1, input2) + output = torch.bmm(input1, input2) + return output.detach() + + @staticmethod + def backward(ctx, grad_output): + input1, input2 = ctx.saved_tensors + grad_output = grad_output.clone() + grad_input1 = torch.bmm(grad_output, input2.transpose(1, 2)) + grad_input2 = torch.bmm(grad_output.transpose(1, 2), input1).transpose(1, 2) + return grad_input1, grad_input2 + + +class StridedBmm2Func(torch.autograd.Function): + @staticmethod + def forward(ctx, input1, input2): + ctx.save_for_backward(input1, input2) + output = torch.bmm(input1, input2) + return output.detach() + + @staticmethod + def backward(ctx, grad_output): + input1, input2 = ctx.saved_tensors + grad_output = grad_output.clone() + grad_input1 = torch.bmm(grad_output, input2.transpose(1, 2)) + grad_input2 = torch.bmm(input1.transpose(1, 2), grad_output) + return grad_input1, grad_input2 + + +def query_linear(input: Tensor, weights_q: Tensor, scale_cpu: Tensor, scale_npu: Tensor): + return QueryLinear.apply(input, weights_q, scale_cpu, scale_npu) + +def key_value_linears(input: Tensor, weights_k: Tensor, weights_v: Tensor): + return KeyValueLinears.apply(input, weights_k, weights_v) + +def self_attn_linears(input: Tensor, weights_q: Tensor, weights_k: Tensor, weights_v: Tensor, scale_cpu: Tensor, scale_npu: Tensor): + return SelfAttentionLinears.apply(input, weights_q, weights_k, weights_v, scale_cpu, scale_npu) + +def strided_bmm1(input1: Tensor, input2: Tensor): + return StridedBmm1Func.apply(input1, input2) + +def strided_bmm2(input1: Tensor, input2: Tensor): + return StridedBmm2Func.apply(input1, input2) + +class MultiheadAttention(nn.Module): + """Multi-headed attention. + + See "Attention Is All You Need" for more details. + """ + + def __init__(self, embed_dim, num_heads, dropout=0., bias=False, seed=0): + super().__init__() + self.embed_dim = embed_dim + self.num_heads = num_heads + self.dropout = dropout + self.seed = seed + self.head_dim = embed_dim // num_heads + assert self.head_dim * num_heads == self.embed_dim, "embed_dim must be divisible by num_heads" + self.scaling = self.head_dim ** -0.5 + self.scaling_cpu = Variable(torch.tensor(self.scaling)) + self.scaling_npu = self.scaling_cpu.npu() + self._mask = torch.empty(0) + self.q_proj_weight = Parameter(torch.Tensor(embed_dim, embed_dim)) + self.k_proj_weight = Parameter(torch.Tensor(embed_dim, embed_dim)) + self.v_proj_weight = Parameter(torch.Tensor(embed_dim, embed_dim)) + if bias: + self.in_proj_bias_q = Parameter(torch.Tensor(embed_dim)) + self.in_proj_bias_k = Parameter(torch.Tensor(embed_dim)) + self.in_proj_bias_v = Parameter(torch.Tensor(embed_dim)) + else: + self.register_parameter('in_proj_bias_k', None) + self.register_parameter('in_proj_bias_q', None) + self.register_parameter('in_proj_bias_v', None) + + self.out_proj = nn.Linear(embed_dim, embed_dim, bias=bias) + + self.cache_id = str(id(self)) + self.reset_parameters() + + def reset_parameters(self): + nn.init.xavier_uniform_(self.q_proj_weight) + nn.init.xavier_uniform_(self.k_proj_weight) + nn.init.xavier_uniform_(self.v_proj_weight) + nn.init.xavier_uniform_(self.out_proj.weight) + if self.in_proj_bias_k is not None: + nn.init.constant_(self.in_proj_bias_q, 0.) + nn.init.constant_(self.in_proj_bias_k, 0.) + nn.init.constant_(self.in_proj_bias_v, 0.) + nn.init.constant_(self.out_proj.bias, 0.) + + def forward(self, query: Tensor, key: Tensor, value: Tensor, + mask_future_timesteps: bool, + key_padding_mask: Optional[Tensor], + incremental_state: Optional[Dict[str, Dict[str, Tensor]]], + need_weights: bool, + static_kv: bool): + """Input shape: Time x Batch x Channel + + Self-attention can be implemented by passing in the same arguments for + query, key and value. Future timesteps can be masked with the + `mask_future_timesteps` argument. Padding elements can be excluded from + the key by passing a binary ByteTensor (`key_padding_mask`) with shape: + batch x src_len, where padding elements are indicated by 1s. + """ + qkv_same, kv_same = self._fast_same_check(query, key, value) + + tgt_len, bsz, embed_dim = query.size() + assert embed_dim == self.embed_dim + assert list(query.size()) == [tgt_len, bsz, embed_dim] + assert key.size() == value.size() + + k = v = query.new_empty(0) + if incremental_state is not None: + saved_state = self._get_input_buffer(incremental_state) + else: + saved_state = None + + if qkv_same: + q, k, v = self_attn_linears(query, self.q_proj_weight,self.k_proj_weight, self.v_proj_weight, + self.scaling_cpu, self.scaling_npu) + elif kv_same: + q = query_linear(query, self.q_proj_weight, self.scaling_cpu, self.scaling_npu) + if not (saved_state is not None and 'prev_key' in saved_state and static_kv): + k, v = key_value_linears(key, self.k_proj_weight, self.v_proj_weight) + else: + q = torch.addmm(query.view(query.size(0) * query.size(1), query.size(2)), + query.view(query.size(0) * query.size(1), query.size(2)), self.q_proj_weight, beta=0.0, + alpha=self.scaling) + if not (saved_state is not None and 'prev_key' in saved_state and static_kv): + k = F.linear(key, self.k_proj_weight, self.in_proj_bias_k) + v = F.linear(value, self.v_proj_weight, self.in_proj_bias_v) + + if saved_state is not None: + if 'prev_key' in saved_state: + k = torch.cat((saved_state['prev_key'], k), dim=0) + if 'prev_value' in saved_state: + v = torch.cat((saved_state['prev_value'], v), dim=0) + saved_state['prev_key'] = k + saved_state['prev_value'] = v + self._set_input_buffer(incremental_state, saved_state) + + src_len = k.size(0) + + if key_padding_mask is not None: + assert key_padding_mask.size(0) == bsz + assert key_padding_mask.size(1) == src_len + + q = q.contiguous().view(tgt_len, bsz * self.num_heads, self.head_dim).clone().transpose(0, 1).contiguous() + k = k.contiguous().view(src_len, bsz * self.num_heads, self.head_dim).clone().transpose(0, 1).contiguous() + v = v.contiguous().view(src_len, bsz * self.num_heads, self.head_dim).clone().transpose(0, 1).contiguous() + + attn_weights = strided_bmm1(q, k.transpose(1, 2)) + + assert list(attn_weights.size()) == [bsz * self.num_heads, tgt_len, src_len] + + # only apply masking at training time (when incremental state is None) + if mask_future_timesteps and incremental_state is None: + assert query.size() == key.size(), \ + 'mask_future_timesteps only applies to self-attention' + attn_weights += self.buffered_mask(attn_weights).unsqueeze(0) + if key_padding_mask is not None: + # don't attend to padding symbols + attn_weights = attn_weights.view(bsz, self.num_heads, tgt_len, src_len) + + attn_weights = attn_weights.float().masked_fill( + key_padding_mask.unsqueeze(1).unsqueeze(2), + torch.finfo(torch.float32).min, + ).type_as(attn_weights) + + attn_weights = attn_weights.view(bsz * self.num_heads, tgt_len, src_len) + + attn_weights = F.softmax(attn_weights, dim=-1) + if self.training: + attn_weights, _, _ = torch.npu_dropoutV2(attn_weights, self.seed, p=self.dropout) + + attn = strided_bmm2(attn_weights, v) + assert list(attn.size()) == [bsz * self.num_heads, tgt_len, self.head_dim] + attn = attn.transpose(0, 1).contiguous().view(tgt_len, bsz, embed_dim) + + # linear + attn = self.out_proj(attn) + + if need_weights: + # average attention weights over heads + attn_weights = attn_weights.view(bsz, self.num_heads, tgt_len, src_len) + attn_weights = attn_weights.sum(dim=1) / self.num_heads + else: + attn_weights = attn_weights.new_empty(0) # Can't set to None because jit script reasons + + return attn, attn_weights + + + def in_proj_qkv(self, query): + return self._in_proj(query).chunk(3, dim=-1) + + def in_proj_kv(self, key): + return self._in_proj(key, start=self.embed_dim).chunk(2, dim=-1) + + def in_proj_q(self, query): + return self._in_proj(query, end=self.embed_dim) + + def in_proj_k(self, key): + return self._in_proj(key, start=self.embed_dim, end=2 * self.embed_dim) + + def in_proj_v(self, value): + return self._in_proj(value, start=2 * self.embed_dim) + + def _in_proj(self, input, start=None, end=None): + weight = self.in_proj_weight + bias = self.in_proj_bias + if end is not None: + weight = weight[:end, :] + if bias is not None: + bias = bias[:end] + if start is not None: + weight = weight[start:, :] + if bias is not None: + bias = bias[start:] + + res = F.linear(input, weight, bias) + return res + + def buffered_mask(self, tensor): + dim = tensor.size(-1) + if self._mask.size(0) == 0: + self._mask = torch.triu(utils.fill_with_neg_inf(tensor.new_empty(dim, dim)), 1) + if self._mask.size(0) < dim: + self._mask = torch.triu(utils.fill_with_neg_inf(self._mask.resize_(dim, dim)), 1) + return self._mask[:dim, :dim] + + def reorder_incremental_state(self, incremental_state, new_order): + """Reorder buffered internal state (for incremental generation).""" + input_buffer = self._get_input_buffer(incremental_state) + if input_buffer is not None: + for k in input_buffer.keys(): + input_buffer[k] = input_buffer[k].index_select(1, new_order) + self._set_input_buffer(incremental_state, input_buffer) + + def _get_input_buffer(self, incremental_state: Optional[Dict[str, Dict[str, Tensor]]]): + if incremental_state is None or self.cache_id not in incremental_state: + return {} + return incremental_state[self.cache_id] + + def _set_input_buffer(self, incremental_state: Optional[Dict[str, Dict[str, Tensor]]], buffer: Dict[str, Tensor]): + if incremental_state is not None: + incremental_state[self.cache_id] = buffer + + def _fast_same_check(self, q, k, v): + qkv_same = q.data_ptr() == k.data_ptr() == v.data_ptr() + kv_same = k.data_ptr() == v.data_ptr() + return qkv_same, kv_same + diff --git a/PyTorch/built-in/nlp/Transformer_for_PyTorch/optim/combined_adam_v3.py b/PyTorch/built-in/nlp/Transformer_for_PyTorch/optim/combined_adam_v3.py index 61f80b98e1..2b4edb0ab9 100644 --- a/PyTorch/built-in/nlp/Transformer_for_PyTorch/optim/combined_adam_v3.py +++ b/PyTorch/built-in/nlp/Transformer_for_PyTorch/optim/combined_adam_v3.py @@ -1,257 +1,257 @@ -# Copyright (c) 2017-present, Facebook, Inc. -# All rights reserved. -# Copyright 2020 Huawei Technologies Co., Ltd -# -# This source code is licensed under the license found in the LICENSE file in -# the root directory of this source tree. An additional grant of patent rights -# can be found in the PATENTS file in the same directory. -# -#------------------------------------------------------------------------- -# -# Copyright (c) 2019, NVIDIA CORPORATION. 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. - -import torch -import math -from torch.optim.optimizer import Optimizer, required -from change_data_ptr import change_data_ptr - - -def combine_tensor(list_of_tensor, copy_back=True): - total_numel = 0 - for tensor in list_of_tensor: - total_numel += tensor.storage().size() - combined_tensor = torch.randn(total_numel).npu().to(list_of_tensor[0].dtype) - - idx = 0 - if copy_back: - for tensor in list_of_tensor: - temp = tensor.clone() - temp.copy_(tensor) - change_data_ptr(tensor, combined_tensor, idx) - temp_data = tensor.data - temp_data.copy_(temp) - idx += temp.storage().size() - else: - for tensor in list_of_tensor: - change_data_ptr(tensor, combined_tensor, idx) - idx += tensor.storage().size() - return combined_tensor - - -def recombine_tensor(size, combined_tensor, index=0): - temp_grad = torch.zeros(size).npu().to(combined_tensor.dtype) - change_data_ptr(temp_grad, combined_tensor, index) - return temp_grad - - -class CombinedAdam(torch.optim.Optimizer): - def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), eps=1e-8, weight_decay=0, amsgrad=False, combine_grad=True): - if not 0.0 <= lr: - raise ValueError("Invalid learning rate: {}".format(lr)) - if not 0.0 <= eps: - raise ValueError("Invalid epsilon value: {}".format(eps)) - if not 0.0 <= betas[0] < 1.0: - raise ValueError("Invalid beta parameter at index 0".format(betas[0])) - if not 0.0 <= betas[1] < 1.0: - raise ValueError("Invalid beta parameter at index 1".format(betas[1])) - defaults = dict(lr=lr, betas=betas, eps=eps, - weight_decay=weight_decay, amsgrad=amsgrad) - super(CombinedAdam, self).__init__(params, defaults) - - self.combined = combine_grad - self.init_combine = False - self.first_init = True - self.opt_level_O2_has_bn = False - self.combined_grad = [] - self.combined_weight = [] - - def __setstate__(self, state): - super(CombinedAdam, self).__setstate__(state) - for group in self.param_groups: - group.setdefault('amsgrad', False) - - def split_combined_tensors(self, input_combined_grad_1, input_combined_grad_2=None): - if len(self.combined_weight) > 0: - # has big tensor before, release storage - for tensor in self.combined_weight: - tensor = None - self.first_init = False - self.combined_grad = [] - self.combined_weight = [] - - index_ops, index_bn = 0, 0 - for param_group in self.param_groups: - size_ops, size_bn = 0, 0 - ord_param_list = [] - spe_param_list = [] - check_param_size = 0 - for param in param_group["params"]: - if param.requires_grad and param.grad is not None: - temp_size = param.grad.storage().size() - check_param_size += param.storage().size() - if input_combined_grad_1.data_ptr() <= param.grad.data_ptr() < input_combined_grad_1.data_ptr() + input_combined_grad_1.numel() * input_combined_grad_1.element_size(): - size_ops += temp_size - ord_param_list.append(param) - else: - size_bn += temp_size - spe_param_list.append(param) - self.combined_grad.append(recombine_tensor(size_ops, input_combined_grad_1, index_ops)) - self.combined_weight.append(combine_tensor(ord_param_list, copy_back=True)) - - index_ops += size_ops - if input_combined_grad_2 is not None: - self.combined_grad.append(recombine_tensor(size_bn, input_combined_grad_2, index_bn)) - self.combined_weight.append(combine_tensor(spe_param_list, copy_back=True)) - index_bn += size_bn - - def _init_combined(self): - if not self.init_combine: - if hasattr(self, "_amp_stash"): - stash = self._amp_stash - if hasattr(stash, "all_fp32_params"): - if len(stash.grads_list) == 0: - raise RuntimeError("When use CombinedAdam, Apex O1 need to use combine_grad=True module!") - self.split_combined_tensors(stash.grads_list[-1]) - self.init_combine = True - elif hasattr(stash, "all_fp32_from_fp16_params"): - if len(stash.grads_list) == 0: - raise RuntimeError("When use CombinedAdam, Apex O2 need to usecombine_grad=True module!") - if stash.grads_list[1] is not None: - if stash.grads_list[2] is None: - self.split_combined_tensors(stash.grads_list[1]) - else: - self.split_combined_tensors(stash.grads_list[1], stash.grads_list[2]) - self.opt_level_O2_has_bn = True - else: - raise RuntimeError("Inapproperiate network which only have batchnorm layers!") - self.init_combine = True - else: - for param_group in self.param_groups: - lst_grad = [] - lst_weight = [] - for param in param_group["params"]: - if param.requires_grad and param.grad is not None: - lst_grad.append(param.grad) - lst_weight.append(param) - if len(lst_grad) > 0: - self.combined_grad.append(combine_tensor(lst_grad, True)) - self.combined_weight.append(combine_tensor(lst_weight, True)) - self.combined_momentum.append(torch.zeros_like(self.combined_grad[-1])) - self.init_combine = True - for idx, tensor in enumerate(self.combined_weight): - state = self.state[tensor] - if len(state) == 0: - state["step"] = 0 - state["exp_avg"] = torch.zeros_like(self.combined_weight[idx]) - state["exp_avg_sq"] = torch.zeros_like(self.combined_weight[idx]) - - def step_combined(self, idx, state, group): - combined_weight = self.combined_weight[idx] - combined_grad = self.combined_grad[idx] - exp_avg, exp_avg_sq = state["exp_avg"], state["exp_avg_sq"] - - amsgrad = group['amsgrad'] - if amsgrad: - if state["step"] == 0: - state["max_exp_avg_sq"] = torch.zeros_like(combined_weight) - beta1, beta2 = group['betas'] - - state["step"] += 1 - bias_correction1 = 1 - beta1 ** state["step"] - bias_correction2 = 1 - beta2 ** state["step"] - - exp_avg.mul_(beta1).add_(combined_grad, alpha=1-beta1) - exp_avg_sq.mul_(beta2).addcmul_(combined_grad, combined_grad, value=1-beta2) - - if amsgrad: - max_exp_avg_sq = state["max_exp_avg_sq"] - max_exp_avg_sq = torch.max(max_exp_avg_sq, exp_avg_sq) - denom = max_exp_avg_sq.sqrt().add_(group["eps"]) - else: - denom = exp_avg_sq.sqrt().add_(group["eps"]) - step_size = group["lr"] * math.sqrt(bias_correction2) / bias_correction1 - if group["weight_decay"] != 0: - combined_weight.data.add_(-group["weight_decay"] * group["lr"], combined_weight.data) - - combined_weight.data.addcdiv_(exp_avg, denom, value=-step_size) - - @torch.no_grad() - def step(self, closure=None, enable=True): - loss = None - if closure is not None: - with torch.enable_grad(): - loss = closure() - - idx = 0 - for group in self.param_groups: - if self.combined: - self._init_combined() - state = self.state[self.combined_weight[idx]] - self.step_combined(idx, state, group) - if self.opt_level_O2_has_bn: - idx += 1 - state = self.state[self.combined_weight[idx]] - self.step_combined(idx, state, group) - else: - for p in group['params']: - if p.grad is None: - continue - grad = p.grad.data - if grad.is_sparse: - raise RuntimeError('Adam does not support sparse gradients, please consider SparseAdam instead') - amsgrad = group['amsgrad'] - - state = self.state[p] - - # State initialization - if len(state) == 0: - state['step'] = 0 - # Exponential moving average of gradient values - state['exp_avg'] = torch.zeros_like(p.data) - # Exponential moving average of squared gradient values - state['exp_avg_sq'] = torch.zeros_like(p.data) - if amsgrad: - # Maintains max of all exp. moving avg. of sq. grad. values - state['max_exp_avg_sq'] = torch.zeros_like(p.data) - - exp_avg, exp_avg_sq = state['exp_avg'], state['exp_avg_sq'] - if amsgrad: - max_exp_avg_sq = state['max_exp_avg_sq'] - beta1, beta2 = group['betas'] - - state['step'] += 1 - - # Decay the first and second moment running average coefficient - exp_avg.mul_(beta1).add_(grad, alpha=1 - beta1) - exp_avg_sq.mul_(beta2).addcmul_(grad, grad, value=1 - beta2) - - if amsgrad: - # Maintains the maximum of all 2nd moment running avg. till now - max_exp_avg_sq = torch.max(max_exp_avg_sq, exp_avg_sq) - # Use the max. for normalizing running avg. of gradient - denom = max_exp_avg_sq.sqrt().add_(group['eps']) - else: - denom = exp_avg_sq.sqrt().add_(group['eps']) - - bias_correction1 = 1 - beta1 ** state['step'] - bias_correction2 = 1 - beta2 ** state['step'] - step_size = group['lr'] * math.sqrt(bias_correction2) / bias_correction1 - - if group['weight_decay'] != 0: - p.data.add_(-group['weight_decay'] * group['lr'], p.data) - - # p.data.addcdiv_(-step_size, exp_avg, denom) - p.data.addcdiv_(exp_avg, denom, value=-step_size) - idx += 1 +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# Copyright 2020 Huawei Technologies Co., Ltd +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. +# +#------------------------------------------------------------------------- +# +# Copyright (c) 2019, NVIDIA CORPORATION. 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. + +import torch +import math +from torch.optim.optimizer import Optimizer, required +from change_data_ptr import change_data_ptr + + +def combine_tensor(list_of_tensor, copy_back=True): + total_numel = 0 + for tensor in list_of_tensor: + total_numel += tensor.storage().size() + combined_tensor = torch.randn(total_numel).npu().to(list_of_tensor[0].dtype) + + idx = 0 + if copy_back: + for tensor in list_of_tensor: + temp = tensor.clone() + temp.copy_(tensor) + change_data_ptr(tensor, combined_tensor, idx) + temp_data = tensor.data + temp_data.copy_(temp) + idx += temp.storage().size() + else: + for tensor in list_of_tensor: + change_data_ptr(tensor, combined_tensor, idx) + idx += tensor.storage().size() + return combined_tensor + + +def recombine_tensor(size, combined_tensor, index=0): + temp_grad = torch.zeros(size).npu().to(combined_tensor.dtype) + change_data_ptr(temp_grad, combined_tensor, index) + return temp_grad + + +class CombinedAdam(torch.optim.Optimizer): + def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), eps=1e-8, weight_decay=0, amsgrad=False, combine_grad=True): + if not 0.0 <= lr: + raise ValueError("Invalid learning rate: {}".format(lr)) + if not 0.0 <= eps: + raise ValueError("Invalid epsilon value: {}".format(eps)) + if not 0.0 <= betas[0] < 1.0: + raise ValueError("Invalid beta parameter at index 0".format(betas[0])) + if not 0.0 <= betas[1] < 1.0: + raise ValueError("Invalid beta parameter at index 1".format(betas[1])) + defaults = dict(lr=lr, betas=betas, eps=eps, + weight_decay=weight_decay, amsgrad=amsgrad) + super(CombinedAdam, self).__init__(params, defaults) + + self.combined = combine_grad + self.init_combine = False + self.first_init = True + self.opt_level_O2_has_bn = False + self.combined_grad = [] + self.combined_weight = [] + + def __setstate__(self, state): + super(CombinedAdam, self).__setstate__(state) + for group in self.param_groups: + group.setdefault('amsgrad', False) + + def split_combined_tensors(self, input_combined_grad_1, input_combined_grad_2=None): + if len(self.combined_weight) > 0: + # has big tensor before, release storage + for tensor in self.combined_weight: + tensor = None + self.first_init = False + self.combined_grad = [] + self.combined_weight = [] + + index_ops, index_bn = 0, 0 + for param_group in self.param_groups: + size_ops, size_bn = 0, 0 + ord_param_list = [] + spe_param_list = [] + check_param_size = 0 + for param in param_group["params"]: + if param.requires_grad and param.grad is not None: + temp_size = param.grad.storage().size() + check_param_size += param.storage().size() + if input_combined_grad_1.data_ptr() <= param.grad.data_ptr() < input_combined_grad_1.data_ptr() + input_combined_grad_1.numel() * input_combined_grad_1.element_size(): + size_ops += temp_size + ord_param_list.append(param) + else: + size_bn += temp_size + spe_param_list.append(param) + self.combined_grad.append(recombine_tensor(size_ops, input_combined_grad_1, index_ops)) + self.combined_weight.append(combine_tensor(ord_param_list, copy_back=True)) + + index_ops += size_ops + if input_combined_grad_2 is not None: + self.combined_grad.append(recombine_tensor(size_bn, input_combined_grad_2, index_bn)) + self.combined_weight.append(combine_tensor(spe_param_list, copy_back=True)) + index_bn += size_bn + + def _init_combined(self): + if not self.init_combine: + if hasattr(self, "_amp_stash"): + stash = self._amp_stash + if hasattr(stash, "all_fp32_params"): + if len(stash.grads_list) == 0: + raise RuntimeError("When use CombinedAdam, Apex O1 need to use combine_grad=True module!") + self.split_combined_tensors(stash.grads_list[-1]) + self.init_combine = True + elif hasattr(stash, "all_fp32_from_fp16_params"): + if len(stash.grads_list) == 0: + raise RuntimeError("When use CombinedAdam, Apex O2 need to usecombine_grad=True module!") + if stash.grads_list[1] is not None: + if stash.grads_list[2] is None: + self.split_combined_tensors(stash.grads_list[1]) + else: + self.split_combined_tensors(stash.grads_list[1], stash.grads_list[2]) + self.opt_level_O2_has_bn = True + else: + raise RuntimeError("Inapproperiate network which only have batchnorm layers!") + self.init_combine = True + else: + for param_group in self.param_groups: + lst_grad = [] + lst_weight = [] + for param in param_group["params"]: + if param.requires_grad and param.grad is not None: + lst_grad.append(param.grad) + lst_weight.append(param) + if len(lst_grad) > 0: + self.combined_grad.append(combine_tensor(lst_grad, True)) + self.combined_weight.append(combine_tensor(lst_weight, True)) + self.combined_momentum.append(torch.zeros_like(self.combined_grad[-1])) + self.init_combine = True + for idx, tensor in enumerate(self.combined_weight): + state = self.state[tensor] + if len(state) == 0: + state["step"] = 0 + state["exp_avg"] = torch.zeros_like(self.combined_weight[idx]) + state["exp_avg_sq"] = torch.zeros_like(self.combined_weight[idx]) + + def step_combined(self, idx, state, group): + combined_weight = self.combined_weight[idx] + combined_grad = self.combined_grad[idx] + exp_avg, exp_avg_sq = state["exp_avg"], state["exp_avg_sq"] + + amsgrad = group['amsgrad'] + if amsgrad: + if state["step"] == 0: + state["max_exp_avg_sq"] = torch.zeros_like(combined_weight) + beta1, beta2 = group['betas'] + + state["step"] += 1 + bias_correction1 = 1 - beta1 ** state["step"] + bias_correction2 = 1 - beta2 ** state["step"] + + exp_avg.mul_(beta1).add_(combined_grad, alpha=1-beta1) + exp_avg_sq.mul_(beta2).addcmul_(combined_grad, combined_grad, value=1-beta2) + + if amsgrad: + max_exp_avg_sq = state["max_exp_avg_sq"] + max_exp_avg_sq = torch.max(max_exp_avg_sq, exp_avg_sq) + denom = max_exp_avg_sq.sqrt().add_(group["eps"]) + else: + denom = exp_avg_sq.sqrt().add_(group["eps"]) + step_size = group["lr"] * math.sqrt(bias_correction2) / bias_correction1 + if group["weight_decay"] != 0: + combined_weight.data.add_(-group["weight_decay"] * group["lr"], combined_weight.data) + + combined_weight.data.addcdiv_(exp_avg, denom, value=-step_size) + + @torch.no_grad() + def step(self, closure=None, enable=True): + loss = None + if closure is not None: + with torch.enable_grad(): + loss = closure() + + idx = 0 + for group in self.param_groups: + if self.combined: + self._init_combined() + state = self.state[self.combined_weight[idx]] + self.step_combined(idx, state, group) + if self.opt_level_O2_has_bn: + idx += 1 + state = self.state[self.combined_weight[idx]] + self.step_combined(idx, state, group) + else: + for p in group['params']: + if p.grad is None: + continue + grad = p.grad.data + if grad.is_sparse: + raise RuntimeError('Adam does not support sparse gradients, please consider SparseAdam instead') + amsgrad = group['amsgrad'] + + state = self.state[p] + + # State initialization + if len(state) == 0: + state['step'] = 0 + # Exponential moving average of gradient values + state['exp_avg'] = torch.zeros_like(p.data) + # Exponential moving average of squared gradient values + state['exp_avg_sq'] = torch.zeros_like(p.data) + if amsgrad: + # Maintains max of all exp. moving avg. of sq. grad. values + state['max_exp_avg_sq'] = torch.zeros_like(p.data) + + exp_avg, exp_avg_sq = state['exp_avg'], state['exp_avg_sq'] + if amsgrad: + max_exp_avg_sq = state['max_exp_avg_sq'] + beta1, beta2 = group['betas'] + + state['step'] += 1 + + # Decay the first and second moment running average coefficient + exp_avg.mul_(beta1).add_(grad, alpha=1 - beta1) + exp_avg_sq.mul_(beta2).addcmul_(grad, grad, value=1 - beta2) + + if amsgrad: + # Maintains the maximum of all 2nd moment running avg. till now + max_exp_avg_sq = torch.max(max_exp_avg_sq, exp_avg_sq) + # Use the max. for normalizing running avg. of gradient + denom = max_exp_avg_sq.sqrt().add_(group['eps']) + else: + denom = exp_avg_sq.sqrt().add_(group['eps']) + + bias_correction1 = 1 - beta1 ** state['step'] + bias_correction2 = 1 - beta2 ** state['step'] + step_size = group['lr'] * math.sqrt(bias_correction2) / bias_correction1 + + if group['weight_decay'] != 0: + p.data.add_(-group['weight_decay'] * group['lr'], p.data) + + # p.data.addcdiv_(-step_size, exp_avg, denom) + p.data.addcdiv_(exp_avg, denom, value=-step_size) + idx += 1 return loss \ No newline at end of file diff --git a/PyTorch/built-in/nlp/Transformer_for_PyTorch/preprocess.py b/PyTorch/built-in/nlp/Transformer_for_PyTorch/preprocess.py index 61358b94a0..29ce6f999e 100644 --- a/PyTorch/built-in/nlp/Transformer_for_PyTorch/preprocess.py +++ b/PyTorch/built-in/nlp/Transformer_for_PyTorch/preprocess.py @@ -1,201 +1,201 @@ -#!/usr/bin/env python3 -# Copyright (c) 2017-present, Facebook, Inc. -# All rights reserved. -# Copyright 2020 Huawei Technologies Co., Ltd -# -# This source code is licensed under the license found in the LICENSE file in -# the root directory of this source tree. An additional grant of patent rights -# can be found in the PATENTS file in the same directory. -# - -import argparse -from itertools import zip_longest -import os -import shutil - -from data import indexed_dataset, dictionary -from data.tokenizer import Tokenizer, tokenize_line - -def get_parser(): - parser = argparse.ArgumentParser( - description='Data pre-processing: Create dictionary and store data in binary format') - parser.add_argument('-s', '--source-lang', default=None, metavar='SRC', help='source language') - parser.add_argument('-t', '--target-lang', default=None, metavar='TARGET', help='target language') - parser.add_argument('--trainpref', metavar='FP', default=None, help='train file prefix') - parser.add_argument('--validpref', metavar='FP', default=None, help='comma separated, valid file prefixes') - parser.add_argument('--testpref', metavar='FP', default=None, help='comma separated, test file prefixes') - parser.add_argument('--destdir', metavar='DIR', default='data-bin', help='destination dir') - parser.add_argument('--thresholdtgt', metavar='N', default=0, type=int, - help='map words appearing less than threshold times to unknown') - parser.add_argument('--thresholdsrc', metavar='N', default=0, type=int, - help='map words appearing less than threshold times to unknown') - parser.add_argument('--tgtdict', metavar='FP', help='reuse given target dictionary') - parser.add_argument('--srcdict', metavar='FP', help='reuse given source dictionary') - parser.add_argument('--nwordstgt', metavar='N', default=-1, type=int, help='number of target words to retain') - parser.add_argument('--nwordssrc', metavar='N', default=-1, type=int, help='number of source words to retain') - parser.add_argument('--alignfile', metavar='ALIGN', default=None, help='an alignment file (optional)') - parser.add_argument('--output-format', metavar='FORMAT', default='binary', choices=['binary', 'raw'], - help='output format (optional)') - parser.add_argument('--joined-dictionary', action='store_true', help='Generate joined dictionary') - parser.add_argument('--only-source', action='store_true', help='Only process the source language') - parser.add_argument('--padding-factor', metavar='N', default=8, type=int, - help='Pad dictionary size to be multiple of N') - return parser - - -def main(args): - print(args) - os.makedirs(args.destdir, exist_ok=True) - target = not args.only_source - - def build_dictionary(filenames): - d = dictionary.Dictionary() - for filename in filenames: - Tokenizer.add_file_to_dictionary(filename, d, tokenize_line) - return d - - def train_path(lang): - return '{}{}'.format(args.trainpref, ('.' + lang) if lang else '') - - def file_name(prefix, lang): - fname = prefix - if lang is not None: - fname += f'.{lang}' - return fname - - def dest_path(prefix, lang): - return os.path.join(args.destdir, file_name(prefix, lang)) - - def dict_path(lang): - return dest_path('dict', lang) + '.txt' - - def dataset_dest_path(output_prefix, lang, extension): - base = f'{args.destdir}/{output_prefix}' - lang_part = f'.{args.source_lang}-{args.target_lang}.{lang}' if lang is not None else '' - return f'{base}{lang_part}.{extension}' - - if args.joined_dictionary: - assert not args.srcdict, 'cannot combine --srcdict and --joined-dictionary' - assert not args.tgtdict, 'cannot combine --tgtdict and --joined-dictionary' - src_dict = build_dictionary(set([ - train_path(lang) - for lang in [args.source_lang, args.target_lang] - ])) - tgt_dict = src_dict - else: - if args.srcdict: - src_dict = dictionary.Dictionary.load(args.srcdict) - else: - assert args.trainpref, "--trainpref must be set if --srcdict is not specified" - src_dict = build_dictionary([train_path(args.source_lang)]) - if target: - if args.tgtdict: - tgt_dict = dictionary.Dictionary.load(args.tgtdict) - else: - assert args.trainpref, "--trainpref must be set if --tgtdict is not specified" - tgt_dict = build_dictionary([train_path(args.target_lang)]) - - src_dict.finalize( - threshold=args.thresholdsrc, - nwords=args.nwordssrc, - padding_factor=args.padding_factor, - ) - src_dict.save(dict_path(args.source_lang)) - if target: - if not args.joined_dictionary: - tgt_dict.finalize( - threshold=args.thresholdtgt, - nwords=args.nwordstgt, - padding_factor=args.padding_factor, - ) - tgt_dict.save(dict_path(args.target_lang)) - - def make_binary_dataset(input_prefix, output_prefix, lang): - dict = dictionary.Dictionary.load(dict_path(lang)) - print('| [{}] Dictionary: {} types'.format(lang, len(dict) - 1)) - - ds = indexed_dataset.IndexedDatasetBuilder(dataset_dest_path(output_prefix, lang, 'bin')) - - def consumer(tensor): - ds.add_item(tensor) - - input_file = '{}{}'.format(input_prefix, ('.' + lang) if lang is not None else '') - res = Tokenizer.binarize(input_file, dict, consumer) - print('| [{}] {}: {} sents, {} tokens, {:.3}% replaced by {}'.format( - lang, input_file, res['nseq'], res['ntok'], - 100 * res['nunk'] / res['ntok'], dict.unk_word)) - ds.finalize(dataset_dest_path(output_prefix, lang, 'idx')) - - def make_dataset(input_prefix, output_prefix, lang): - if args.output_format == 'binary': - make_binary_dataset(input_prefix, output_prefix, lang) - elif args.output_format == 'raw': - # Copy original text file to destination folder - output_text_file = dest_path( - output_prefix + '.{}-{}'.format(args.source_lang, args.target_lang), - lang, - ) - shutil.copyfile(file_name(input_prefix, lang), output_text_file) - - def make_all(lang): - if args.trainpref: - make_dataset(args.trainpref, 'train', lang) - if args.validpref: - for k, validpref in enumerate(args.validpref.split(',')): - outprefix = 'valid{}'.format(k) if k > 0 else 'valid' - make_dataset(validpref, outprefix, lang) - if args.testpref: - for k, testpref in enumerate(args.testpref.split(',')): - outprefix = 'test{}'.format(k) if k > 0 else 'test' - make_dataset(testpref, outprefix, lang) - - make_all(args.source_lang) - if target: - make_all(args.target_lang) - - print('| Wrote preprocessed data to {}'.format(args.destdir)) - - if args.alignfile: - assert args.trainpref, "--trainpref must be set if --alignfile is specified" - src_file_name = train_path(args.source_lang) - tgt_file_name = train_path(args.target_lang) - src_dict = dictionary.Dictionary.load(dict_path(args.source_lang)) - tgt_dict = dictionary.Dictionary.load(dict_path(args.target_lang)) - freq_map = {} - with open(args.alignfile, 'r') as align_file: - with open(src_file_name, 'r') as src_file: - with open(tgt_file_name, 'r') as tgt_file: - for a, s, t in zip_longest(align_file, src_file, tgt_file): - si = Tokenizer.tokenize(s, src_dict, add_if_not_exist=False) - ti = Tokenizer.tokenize(t, tgt_dict, add_if_not_exist=False) - ai = list(map(lambda x: tuple(x.split('-')), a.split())) - for sai, tai in ai: - srcidx = si[int(sai)] - tgtidx = ti[int(tai)] - if srcidx != src_dict.unk() and tgtidx != tgt_dict.unk(): - assert srcidx != src_dict.pad() - assert srcidx != src_dict.eos() - assert tgtidx != tgt_dict.pad() - assert tgtidx != tgt_dict.eos() - - if srcidx not in freq_map: - freq_map[srcidx] = {} - if tgtidx not in freq_map[srcidx]: - freq_map[srcidx][tgtidx] = 1 - else: - freq_map[srcidx][tgtidx] += 1 - - align_dict = {} - for srcidx in freq_map.keys(): - align_dict[srcidx] = max(freq_map[srcidx], key=freq_map[srcidx].get) - - with open(os.path.join(args.destdir, 'alignment.{}-{}.txt'.format( - args.source_lang, args.target_lang)), 'w') as f: - for k, v in align_dict.items(): - print('{} {}'.format(src_dict[k], tgt_dict[v]), file=f) - - -if __name__ == '__main__': - parser = get_parser() - args = parser.parse_args() +#!/usr/bin/env python3 +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# Copyright 2020 Huawei Technologies Co., Ltd +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. +# + +import argparse +from itertools import zip_longest +import os +import shutil + +from data import indexed_dataset, dictionary +from data.tokenizer import Tokenizer, tokenize_line + +def get_parser(): + parser = argparse.ArgumentParser( + description='Data pre-processing: Create dictionary and store data in binary format') + parser.add_argument('-s', '--source-lang', default=None, metavar='SRC', help='source language') + parser.add_argument('-t', '--target-lang', default=None, metavar='TARGET', help='target language') + parser.add_argument('--trainpref', metavar='FP', default=None, help='train file prefix') + parser.add_argument('--validpref', metavar='FP', default=None, help='comma separated, valid file prefixes') + parser.add_argument('--testpref', metavar='FP', default=None, help='comma separated, test file prefixes') + parser.add_argument('--destdir', metavar='DIR', default='data-bin', help='destination dir') + parser.add_argument('--thresholdtgt', metavar='N', default=0, type=int, + help='map words appearing less than threshold times to unknown') + parser.add_argument('--thresholdsrc', metavar='N', default=0, type=int, + help='map words appearing less than threshold times to unknown') + parser.add_argument('--tgtdict', metavar='FP', help='reuse given target dictionary') + parser.add_argument('--srcdict', metavar='FP', help='reuse given source dictionary') + parser.add_argument('--nwordstgt', metavar='N', default=-1, type=int, help='number of target words to retain') + parser.add_argument('--nwordssrc', metavar='N', default=-1, type=int, help='number of source words to retain') + parser.add_argument('--alignfile', metavar='ALIGN', default=None, help='an alignment file (optional)') + parser.add_argument('--output-format', metavar='FORMAT', default='binary', choices=['binary', 'raw'], + help='output format (optional)') + parser.add_argument('--joined-dictionary', action='store_true', help='Generate joined dictionary') + parser.add_argument('--only-source', action='store_true', help='Only process the source language') + parser.add_argument('--padding-factor', metavar='N', default=8, type=int, + help='Pad dictionary size to be multiple of N') + return parser + + +def main(args): + print(args) + os.makedirs(args.destdir, exist_ok=True) + target = not args.only_source + + def build_dictionary(filenames): + d = dictionary.Dictionary() + for filename in filenames: + Tokenizer.add_file_to_dictionary(filename, d, tokenize_line) + return d + + def train_path(lang): + return '{}{}'.format(args.trainpref, ('.' + lang) if lang else '') + + def file_name(prefix, lang): + fname = prefix + if lang is not None: + fname += f'.{lang}' + return fname + + def dest_path(prefix, lang): + return os.path.join(args.destdir, file_name(prefix, lang)) + + def dict_path(lang): + return dest_path('dict', lang) + '.txt' + + def dataset_dest_path(output_prefix, lang, extension): + base = f'{args.destdir}/{output_prefix}' + lang_part = f'.{args.source_lang}-{args.target_lang}.{lang}' if lang is not None else '' + return f'{base}{lang_part}.{extension}' + + if args.joined_dictionary: + assert not args.srcdict, 'cannot combine --srcdict and --joined-dictionary' + assert not args.tgtdict, 'cannot combine --tgtdict and --joined-dictionary' + src_dict = build_dictionary(set([ + train_path(lang) + for lang in [args.source_lang, args.target_lang] + ])) + tgt_dict = src_dict + else: + if args.srcdict: + src_dict = dictionary.Dictionary.load(args.srcdict) + else: + assert args.trainpref, "--trainpref must be set if --srcdict is not specified" + src_dict = build_dictionary([train_path(args.source_lang)]) + if target: + if args.tgtdict: + tgt_dict = dictionary.Dictionary.load(args.tgtdict) + else: + assert args.trainpref, "--trainpref must be set if --tgtdict is not specified" + tgt_dict = build_dictionary([train_path(args.target_lang)]) + + src_dict.finalize( + threshold=args.thresholdsrc, + nwords=args.nwordssrc, + padding_factor=args.padding_factor, + ) + src_dict.save(dict_path(args.source_lang)) + if target: + if not args.joined_dictionary: + tgt_dict.finalize( + threshold=args.thresholdtgt, + nwords=args.nwordstgt, + padding_factor=args.padding_factor, + ) + tgt_dict.save(dict_path(args.target_lang)) + + def make_binary_dataset(input_prefix, output_prefix, lang): + dict = dictionary.Dictionary.load(dict_path(lang)) + print('| [{}] Dictionary: {} types'.format(lang, len(dict) - 1)) + + ds = indexed_dataset.IndexedDatasetBuilder(dataset_dest_path(output_prefix, lang, 'bin')) + + def consumer(tensor): + ds.add_item(tensor) + + input_file = '{}{}'.format(input_prefix, ('.' + lang) if lang is not None else '') + res = Tokenizer.binarize(input_file, dict, consumer) + print('| [{}] {}: {} sents, {} tokens, {:.3}% replaced by {}'.format( + lang, input_file, res['nseq'], res['ntok'], + 100 * res['nunk'] / res['ntok'], dict.unk_word)) + ds.finalize(dataset_dest_path(output_prefix, lang, 'idx')) + + def make_dataset(input_prefix, output_prefix, lang): + if args.output_format == 'binary': + make_binary_dataset(input_prefix, output_prefix, lang) + elif args.output_format == 'raw': + # Copy original text file to destination folder + output_text_file = dest_path( + output_prefix + '.{}-{}'.format(args.source_lang, args.target_lang), + lang, + ) + shutil.copyfile(file_name(input_prefix, lang), output_text_file) + + def make_all(lang): + if args.trainpref: + make_dataset(args.trainpref, 'train', lang) + if args.validpref: + for k, validpref in enumerate(args.validpref.split(',')): + outprefix = 'valid{}'.format(k) if k > 0 else 'valid' + make_dataset(validpref, outprefix, lang) + if args.testpref: + for k, testpref in enumerate(args.testpref.split(',')): + outprefix = 'test{}'.format(k) if k > 0 else 'test' + make_dataset(testpref, outprefix, lang) + + make_all(args.source_lang) + if target: + make_all(args.target_lang) + + print('| Wrote preprocessed data to {}'.format(args.destdir)) + + if args.alignfile: + assert args.trainpref, "--trainpref must be set if --alignfile is specified" + src_file_name = train_path(args.source_lang) + tgt_file_name = train_path(args.target_lang) + src_dict = dictionary.Dictionary.load(dict_path(args.source_lang)) + tgt_dict = dictionary.Dictionary.load(dict_path(args.target_lang)) + freq_map = {} + with open(args.alignfile, 'r') as align_file: + with open(src_file_name, 'r') as src_file: + with open(tgt_file_name, 'r') as tgt_file: + for a, s, t in zip_longest(align_file, src_file, tgt_file): + si = Tokenizer.tokenize(s, src_dict, add_if_not_exist=False) + ti = Tokenizer.tokenize(t, tgt_dict, add_if_not_exist=False) + ai = list(map(lambda x: tuple(x.split('-')), a.split())) + for sai, tai in ai: + srcidx = si[int(sai)] + tgtidx = ti[int(tai)] + if srcidx != src_dict.unk() and tgtidx != tgt_dict.unk(): + assert srcidx != src_dict.pad() + assert srcidx != src_dict.eos() + assert tgtidx != tgt_dict.pad() + assert tgtidx != tgt_dict.eos() + + if srcidx not in freq_map: + freq_map[srcidx] = {} + if tgtidx not in freq_map[srcidx]: + freq_map[srcidx][tgtidx] = 1 + else: + freq_map[srcidx][tgtidx] += 1 + + align_dict = {} + for srcidx in freq_map.keys(): + align_dict[srcidx] = max(freq_map[srcidx], key=freq_map[srcidx].get) + + with open(os.path.join(args.destdir, 'alignment.{}-{}.txt'.format( + args.source_lang, args.target_lang)), 'w') as f: + for k, v in align_dict.items(): + print('{} {}'.format(src_dict[k], tgt_dict[v]), file=f) + + +if __name__ == '__main__': + parser = get_parser() + args = parser.parse_args() main(args) \ No newline at end of file diff --git a/PyTorch/built-in/nlp/XLM_ID0740_for_PyTorch/test/train_full_1p.sh b/PyTorch/built-in/nlp/XLM_ID0740_for_PyTorch/test/train_full_1p.sh index b7d8c17f16..4abf4787ff 100644 --- a/PyTorch/built-in/nlp/XLM_ID0740_for_PyTorch/test/train_full_1p.sh +++ b/PyTorch/built-in/nlp/XLM_ID0740_for_PyTorch/test/train_full_1p.sh @@ -1,217 +1,217 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -export ASCEND_SLOG_PRINT_TO_STDOUT=1 -export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID - -#集合通信参数,不需要修改 -export RANK_SIZE=1 -export JOB_ID=10087 -RANK_ID_START=0 - - -export NNPU=1 - -export HCCL_WHITELIST_DISABLE=1 -export MASTER_ADDR=127.0.0.1 -export MASTER_PORT=23456 -export RANK=0 -export WORLD_SIZE=1 - - - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="XLM_ID0740_for_PyTorch" -#训练epoch -train_epochs=180 -#训练batch_size -batch_size=16 -#训练step -#train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.495 - -#TF2.X独有,不需要修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False -autotune=False - -# 帮助信息,不h需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_full_1p.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is False - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#进入训练脚本目录,需要模型审视修改 -cd $cur_path/../ - - -#sed -i "s|./data|$data_path|g" examples/cats_and_dogs.py -#sed -i "s|epochs = 20|epochs = 1|g" examples/cats_and_dogs.py -#sed -i "s|pass|break|g" train.py - -#python3 setup.py install -#mkdir -p checkpoints -#mkdir -p /root/.cache/torch/hub/checkpoints -#cp $data_path/fcn_* /root/.cache/torch/hub/checkpoints - -for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); -do - #设置环境变量,不需要修改 - echo "Device ID: $ASCEND_DEVICE_ID" - export RANK_ID=$RANK_ID - - - - #创建DeviceID输出目录,不需要修改 - if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - fi - - #绑核,不需要绑核的模型删除,需要绑核的模型根据实际修改 - #cpucount=`lscpu | grep "CPU(s):" | head -n 1 | awk '{print $2}'` - #cpustep=`expr $cpucount / 8` - #echo "taskset c steps:" $cpustep - #let a=RANK_ID*$cpustep - #let b=RANK_ID+1 - #let c=b*$cpustep-1 - nohup python3 train.py \ - --data_path $data_path/50k \ - --exp_name xlm_en_zh \ - --dump_path ./dumped \ - --lgs 'en-zh' \ - --clm_steps '' \ - --mlm_steps 'en,zh' \ - --emb_dim 1024 \ - --n_layers 12 \ - --n_heads 16 \ - --dropout 0.1 \ - --attention_dropout 0.1 \ - --gelu_activation true \ - --batch_size $batch_size \ - --bptt 256 \ - --optimizer npu_fused_adam_v2,lr=0.00005 \ - --epoch_size 300000 \ - --max_epoch $train_epochs \ - --validation_metrics _valid_mlm_ppl \ - --stopping_criterion _valid_mlm_ppl,8 \ - --fp16 true \ - --amp 2 \ - --seed 1 \ - --local_rank $ASCEND_DEVICE_ID \ - --max_epoch 1 > $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & - -done -wait - -#恢复参数 -#sed -i "s|break|pass|g" train.py - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep "sent/s" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "sent/s -" '{print $2}'|awk '{print $1}'|tail -n +2|awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` -#FPS=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'*'${perf}'}'` - - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep eval_accuracy $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|grep -v mlp_log|awk 'END {print $5}'| sed 's/,//g' |cut -c 1-5` -train_accuracy=`grep "vaild_en_mlm_acc" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "vaild_en_mlm_acc ->" '{print $2}'|awk 'NR==1{max=$1;next}{max=max>$1?max:$1}END{print max}'` -#打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#稳定性精度看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据 -#吞吐量,不需要修改 -ActualFPS=${FPS} -#单迭代训练时长,不需要修改 -TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep "sent/s" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "MLM-en: " '{print $2}'|awk '{print $1}' >> $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +export ASCEND_SLOG_PRINT_TO_STDOUT=1 +export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID + +#集合通信参数,不需要修改 +export RANK_SIZE=1 +export JOB_ID=10087 +RANK_ID_START=0 + + +export NNPU=1 + +export HCCL_WHITELIST_DISABLE=1 +export MASTER_ADDR=127.0.0.1 +export MASTER_PORT=23456 +export RANK=0 +export WORLD_SIZE=1 + + + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="XLM_ID0740_for_PyTorch" +#训练epoch +train_epochs=180 +#训练batch_size +batch_size=16 +#训练step +#train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.495 + +#TF2.X独有,不需要修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False +autotune=False + +# 帮助信息,不h需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_full_1p.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is False + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#进入训练脚本目录,需要模型审视修改 +cd $cur_path/../ + + +#sed -i "s|./data|$data_path|g" examples/cats_and_dogs.py +#sed -i "s|epochs = 20|epochs = 1|g" examples/cats_and_dogs.py +#sed -i "s|pass|break|g" train.py + +#python3 setup.py install +#mkdir -p checkpoints +#mkdir -p /root/.cache/torch/hub/checkpoints +#cp $data_path/fcn_* /root/.cache/torch/hub/checkpoints + +for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); +do + #设置环境变量,不需要修改 + echo "Device ID: $ASCEND_DEVICE_ID" + export RANK_ID=$RANK_ID + + + + #创建DeviceID输出目录,不需要修改 + if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + fi + + #绑核,不需要绑核的模型删除,需要绑核的模型根据实际修改 + #cpucount=`lscpu | grep "CPU(s):" | head -n 1 | awk '{print $2}'` + #cpustep=`expr $cpucount / 8` + #echo "taskset c steps:" $cpustep + #let a=RANK_ID*$cpustep + #let b=RANK_ID+1 + #let c=b*$cpustep-1 + nohup python3 train.py \ + --data_path $data_path/50k \ + --exp_name xlm_en_zh \ + --dump_path ./dumped \ + --lgs 'en-zh' \ + --clm_steps '' \ + --mlm_steps 'en,zh' \ + --emb_dim 1024 \ + --n_layers 12 \ + --n_heads 16 \ + --dropout 0.1 \ + --attention_dropout 0.1 \ + --gelu_activation true \ + --batch_size $batch_size \ + --bptt 256 \ + --optimizer npu_fused_adam_v2,lr=0.00005 \ + --epoch_size 300000 \ + --max_epoch $train_epochs \ + --validation_metrics _valid_mlm_ppl \ + --stopping_criterion _valid_mlm_ppl,8 \ + --fp16 true \ + --amp 2 \ + --seed 1 \ + --local_rank $ASCEND_DEVICE_ID \ + --max_epoch 1 > $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & + +done +wait + +#恢复参数 +#sed -i "s|break|pass|g" train.py + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep "sent/s" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "sent/s -" '{print $2}'|awk '{print $1}'|tail -n +2|awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` +#FPS=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'*'${perf}'}'` + + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep eval_accuracy $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|grep -v mlp_log|awk 'END {print $5}'| sed 's/,//g' |cut -c 1-5` +train_accuracy=`grep "vaild_en_mlm_acc" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "vaild_en_mlm_acc ->" '{print $2}'|awk 'NR==1{max=$1;next}{max=max>$1?max:$1}END{print max}'` +#打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#稳定性精度看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据 +#吞吐量,不需要修改 +ActualFPS=${FPS} +#单迭代训练时长,不需要修改 +TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep "sent/s" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "MLM-en: " '{print $2}'|awk '{print $1}' >> $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/built-in/nlp/XLM_ID0740_for_PyTorch/test/train_performance_1p.sh b/PyTorch/built-in/nlp/XLM_ID0740_for_PyTorch/test/train_performance_1p.sh index d155368b54..4e873e4c40 100644 --- a/PyTorch/built-in/nlp/XLM_ID0740_for_PyTorch/test/train_performance_1p.sh +++ b/PyTorch/built-in/nlp/XLM_ID0740_for_PyTorch/test/train_performance_1p.sh @@ -1,216 +1,216 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -export ASCEND_SLOG_PRINT_TO_STDOUT=1 -export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID - -#集合通信参数,不需要修改 -export RANK_SIZE=1 -export JOB_ID=10087 -RANK_ID_START=0 - - -export NNPU=1 - -export HCCL_WHITELIST_DISABLE=1 -export MASTER_ADDR=127.0.0.1 -export MASTER_PORT=23456 -export RANK=0 -export WORLD_SIZE=1 - - - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="XLM_ID0740_for_PyTorch" -#训练epoch -train_epochs=1 -#训练batch_size -batch_size=16 -#训练step -#train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.495 - -#TF2.X独有,不需要修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False -autotune=False - -# 帮助信息,不h需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_full_1p.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is False - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#进入训练脚本目录,需要模型审视修改 -cd $cur_path/../ - - -#sed -i "s|./data|$data_path|g" examples/cats_and_dogs.py -#sed -i "s|epochs = 20|epochs = 1|g" examples/cats_and_dogs.py -sed -i "s|pass|break|g" train.py - -#python3 setup.py install -#mkdir -p checkpoints -#mkdir -p /root/.cache/torch/hub/checkpoints -#cp $data_path/fcn_* /root/.cache/torch/hub/checkpoints - -for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); -do - #设置环境变量,不需要修改 - echo "Device ID: $ASCEND_DEVICE_ID" - export RANK_ID=$RANK_ID - - - - #创建DeviceID输出目录,不需要修改 - if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - fi - - #绑核,不需要绑核的模型删除,需要绑核的模型根据实际修改 - #cpucount=`lscpu | grep "CPU(s):" | head -n 1 | awk '{print $2}'` - #cpustep=`expr $cpucount / 8` - #echo "taskset c steps:" $cpustep - #let a=RANK_ID*$cpustep - #let b=RANK_ID+1 - #let c=b*$cpustep-1 - nohup python3 train.py \ - --data_path $data_path/50k \ - --exp_name xlm_en_zh \ - --dump_path ./dumped \ - --lgs 'en-zh' \ - --clm_steps '' \ - --mlm_steps 'en,zh' \ - --emb_dim 1024 \ - --n_layers 12 \ - --n_heads 16 \ - --dropout 0.1 \ - --attention_dropout 0.1 \ - --gelu_activation true \ - --batch_size $batch_size \ - --bptt 256 \ - --optimizer npu_fused_adam_v2,lr=0.00005 \ - --epoch_size 300000 \ - --max_epoch $train_epochs \ - --validation_metrics _valid_mlm_ppl \ - --stopping_criterion _valid_mlm_ppl,8 \ - --fp16 true \ - --amp 2 \ - --seed 1 \ - --local_rank $ASCEND_DEVICE_ID \ - --max_epoch 1 > $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & - -done -wait - -#恢复参数 -sed -i "s|break|pass|g" train.py - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep "sent/s" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "sent/s -" '{print $2}'|awk '{print $1}'|tail -n +2|awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` -#FPS=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'*'${perf}'}'` - - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep eval_accuracy $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|grep -v mlp_log|awk 'END {print $5}'| sed 's/,//g' |cut -c 1-5` -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -#echo "E2E Training Duration sec : $e2e_time" - -#稳定性精度看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据 -#吞吐量,不需要修改 -ActualFPS=${FPS} -#单迭代训练时长,不需要修改 -TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep "sent/s" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "MLM-en: " '{print $2}'|awk '{print $1}' >> $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -#echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +export ASCEND_SLOG_PRINT_TO_STDOUT=1 +export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID + +#集合通信参数,不需要修改 +export RANK_SIZE=1 +export JOB_ID=10087 +RANK_ID_START=0 + + +export NNPU=1 + +export HCCL_WHITELIST_DISABLE=1 +export MASTER_ADDR=127.0.0.1 +export MASTER_PORT=23456 +export RANK=0 +export WORLD_SIZE=1 + + + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="XLM_ID0740_for_PyTorch" +#训练epoch +train_epochs=1 +#训练batch_size +batch_size=16 +#训练step +#train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.495 + +#TF2.X独有,不需要修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False +autotune=False + +# 帮助信息,不h需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_full_1p.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is False + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#进入训练脚本目录,需要模型审视修改 +cd $cur_path/../ + + +#sed -i "s|./data|$data_path|g" examples/cats_and_dogs.py +#sed -i "s|epochs = 20|epochs = 1|g" examples/cats_and_dogs.py +sed -i "s|pass|break|g" train.py + +#python3 setup.py install +#mkdir -p checkpoints +#mkdir -p /root/.cache/torch/hub/checkpoints +#cp $data_path/fcn_* /root/.cache/torch/hub/checkpoints + +for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); +do + #设置环境变量,不需要修改 + echo "Device ID: $ASCEND_DEVICE_ID" + export RANK_ID=$RANK_ID + + + + #创建DeviceID输出目录,不需要修改 + if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + fi + + #绑核,不需要绑核的模型删除,需要绑核的模型根据实际修改 + #cpucount=`lscpu | grep "CPU(s):" | head -n 1 | awk '{print $2}'` + #cpustep=`expr $cpucount / 8` + #echo "taskset c steps:" $cpustep + #let a=RANK_ID*$cpustep + #let b=RANK_ID+1 + #let c=b*$cpustep-1 + nohup python3 train.py \ + --data_path $data_path/50k \ + --exp_name xlm_en_zh \ + --dump_path ./dumped \ + --lgs 'en-zh' \ + --clm_steps '' \ + --mlm_steps 'en,zh' \ + --emb_dim 1024 \ + --n_layers 12 \ + --n_heads 16 \ + --dropout 0.1 \ + --attention_dropout 0.1 \ + --gelu_activation true \ + --batch_size $batch_size \ + --bptt 256 \ + --optimizer npu_fused_adam_v2,lr=0.00005 \ + --epoch_size 300000 \ + --max_epoch $train_epochs \ + --validation_metrics _valid_mlm_ppl \ + --stopping_criterion _valid_mlm_ppl,8 \ + --fp16 true \ + --amp 2 \ + --seed 1 \ + --local_rank $ASCEND_DEVICE_ID \ + --max_epoch 1 > $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & + +done +wait + +#恢复参数 +sed -i "s|break|pass|g" train.py + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep "sent/s" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "sent/s -" '{print $2}'|awk '{print $1}'|tail -n +2|awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` +#FPS=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'*'${perf}'}'` + + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep eval_accuracy $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|grep -v mlp_log|awk 'END {print $5}'| sed 's/,//g' |cut -c 1-5` +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +#echo "E2E Training Duration sec : $e2e_time" + +#稳定性精度看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据 +#吞吐量,不需要修改 +ActualFPS=${FPS} +#单迭代训练时长,不需要修改 +TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep "sent/s" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "MLM-en: " '{print $2}'|awk '{print $1}' >> $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/built-in/nlp/mBART_ID2372_for_PyTorch/test/set_conda.sh b/PyTorch/built-in/nlp/mBART_ID2372_for_PyTorch/test/set_conda.sh index 55087d8622..febb0fa349 100644 --- a/PyTorch/built-in/nlp/mBART_ID2372_for_PyTorch/test/set_conda.sh +++ b/PyTorch/built-in/nlp/mBART_ID2372_for_PyTorch/test/set_conda.sh @@ -1,2 +1,2 @@ -export PATH=/home/anaconda3/bin:$PATH +export PATH=/home/anaconda3/bin:$PATH export LD_LIBRARY_PATH=/home/anaconda3/lib:$LD_LIBRARY_PATH \ No newline at end of file diff --git a/PyTorch/built-in/others/WDL_for_PyTorch/LICENSE b/PyTorch/built-in/others/WDL_for_PyTorch/LICENSE index deeea2d8cc..b09cd7856d 100644 --- a/PyTorch/built-in/others/WDL_for_PyTorch/LICENSE +++ b/PyTorch/built-in/others/WDL_for_PyTorch/LICENSE @@ -1,201 +1,201 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/PyTorch/built-in/others/WDL_for_PyTorch/criteo_preprocess.py b/PyTorch/built-in/others/WDL_for_PyTorch/criteo_preprocess.py index a1c942a427..ef2d419dcf 100644 --- a/PyTorch/built-in/others/WDL_for_PyTorch/criteo_preprocess.py +++ b/PyTorch/built-in/others/WDL_for_PyTorch/criteo_preprocess.py @@ -1,54 +1,54 @@ -# -*- coding: utf-8 -*- - -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 -# -# less 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 sys -import os -import pandas as pd -from sklearn.model_selection import train_test_split -from sklearn.preprocessing import LabelEncoder, MinMaxScaler - - -if __name__ == '__main__': - data_path = os.path.abspath(sys.argv[1]) - - SPARSE_FEATURES_NUM = 27 - DENSE_FEATURES_NUM = 14 - - sparse_features = ['C' + str(i) for i in range(1, SPARSE_FEATURES_NUM)] - dense_features = ['I' + str(i) for i in range(1, DENSE_FEATURES_NUM)] - target = ['label'] - - name_column = target + dense_features + sparse_features - - data = pd.read_csv(data_path, names=name_column, sep='\t') - data[sparse_features] = data[sparse_features].fillna('-1', ) - data[dense_features] = data[dense_features].fillna(0, ) - - for feat in sparse_features: - print(feat) - lbe = LabelEncoder() - data[feat] = lbe.fit_transform(data[feat]) - mms = MinMaxScaler(feature_range=(0, 1)) - data[dense_features] = mms.fit_transform(data[dense_features]) - train, test = train_test_split(data, test_size=0.1, random_state=2020) - - pd.DataFrame(train, columns=name_column).to_pickle(os.path.dirname(data_path) + '/wdl_trainval.pkl') - pd.DataFrame(test, columns=name_column).to_pickle(os.path.dirname(data_path) + '/wdl_test.pkl') - - # the val dataset for inferring - infer_column = target + sparse_features + dense_features - pd.DataFrame(test, columns=infer_column).to_csv(os.path.dirname(data_path) + '/wdl_infer.txt', index=False) +# -*- coding: utf-8 -*- + +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 +# +# less 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 sys +import os +import pandas as pd +from sklearn.model_selection import train_test_split +from sklearn.preprocessing import LabelEncoder, MinMaxScaler + + +if __name__ == '__main__': + data_path = os.path.abspath(sys.argv[1]) + + SPARSE_FEATURES_NUM = 27 + DENSE_FEATURES_NUM = 14 + + sparse_features = ['C' + str(i) for i in range(1, SPARSE_FEATURES_NUM)] + dense_features = ['I' + str(i) for i in range(1, DENSE_FEATURES_NUM)] + target = ['label'] + + name_column = target + dense_features + sparse_features + + data = pd.read_csv(data_path, names=name_column, sep='\t') + data[sparse_features] = data[sparse_features].fillna('-1', ) + data[dense_features] = data[dense_features].fillna(0, ) + + for feat in sparse_features: + print(feat) + lbe = LabelEncoder() + data[feat] = lbe.fit_transform(data[feat]) + mms = MinMaxScaler(feature_range=(0, 1)) + data[dense_features] = mms.fit_transform(data[dense_features]) + train, test = train_test_split(data, test_size=0.1, random_state=2020) + + pd.DataFrame(train, columns=name_column).to_pickle(os.path.dirname(data_path) + '/wdl_trainval.pkl') + pd.DataFrame(test, columns=name_column).to_pickle(os.path.dirname(data_path) + '/wdl_test.pkl') + + # the val dataset for inferring + infer_column = target + sparse_features + dense_features + pd.DataFrame(test, columns=infer_column).to_csv(os.path.dirname(data_path) + '/wdl_infer.txt', index=False) diff --git a/PyTorch/built-in/others/WDL_for_PyTorch/infer/Dockerfile b/PyTorch/built-in/others/WDL_for_PyTorch/infer/Dockerfile index 499c927d66..45963fec3c 100644 --- a/PyTorch/built-in/others/WDL_for_PyTorch/infer/Dockerfile +++ b/PyTorch/built-in/others/WDL_for_PyTorch/infer/Dockerfile @@ -1,30 +1,30 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 -# -# less 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. -# ============================================================================ - -ARG FROM_IMAGE_NAME -FROM $FROM_IMAGE_NAME - -ARG SDK_PKG - -RUN ln -s /usr/local/python3.7.5/bin/python3.7 /usr/bin/python - -COPY requirements.txt . -RUN pip3.7 install -r requirements.txt - -COPY $SDK_PKG . -RUN ls -hrlt -RUN chmod +x ${SDK_PKG} && \ - ./${SDK_PKG} --install-path=/home/run --install && \ - bash -c "source ~/.bashrc" +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 +# +# less 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. +# ============================================================================ + +ARG FROM_IMAGE_NAME +FROM $FROM_IMAGE_NAME + +ARG SDK_PKG + +RUN ln -s /usr/local/python3.7.5/bin/python3.7 /usr/bin/python + +COPY requirements.txt . +RUN pip3.7 install -r requirements.txt + +COPY $SDK_PKG . +RUN ls -hrlt +RUN chmod +x ${SDK_PKG} && \ + ./${SDK_PKG} --install-path=/home/run --install && \ + bash -c "source ~/.bashrc" diff --git a/PyTorch/built-in/others/WDL_for_PyTorch/infer/requirements.txt b/PyTorch/built-in/others/WDL_for_PyTorch/infer/requirements.txt index 614cfb822e..2377a25ade 100644 --- a/PyTorch/built-in/others/WDL_for_PyTorch/infer/requirements.txt +++ b/PyTorch/built-in/others/WDL_for_PyTorch/infer/requirements.txt @@ -1,4 +1,4 @@ -sklearn -pandas -tqdm +sklearn +pandas +tqdm numpy \ No newline at end of file diff --git a/PyTorch/built-in/others/WDL_for_PyTorch/modelzoo_level.txt b/PyTorch/built-in/others/WDL_for_PyTorch/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/built-in/others/WDL_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/built-in/others/WDL_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/built-in/others/WDL_for_PyTorch/requirements.txt b/PyTorch/built-in/others/WDL_for_PyTorch/requirements.txt index 0dda924569..83cfd38dfb 100644 --- a/PyTorch/built-in/others/WDL_for_PyTorch/requirements.txt +++ b/PyTorch/built-in/others/WDL_for_PyTorch/requirements.txt @@ -1,4 +1,4 @@ -sklearn -pandas==1.3.3 -tqdm +sklearn +pandas==1.3.3 +tqdm numpy \ No newline at end of file diff --git a/PyTorch/built-in/others/WDL_for_PyTorch/run_classification_criteo_wdl.py b/PyTorch/built-in/others/WDL_for_PyTorch/run_classification_criteo_wdl.py index 077ebd6ff9..57bc0ed23b 100644 --- a/PyTorch/built-in/others/WDL_for_PyTorch/run_classification_criteo_wdl.py +++ b/PyTorch/built-in/others/WDL_for_PyTorch/run_classification_criteo_wdl.py @@ -1,141 +1,141 @@ -# -*- coding: utf-8 -*- - -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 -# -# less 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 os -import time -import random -import argparse - -import numpy as np -import pandas as pd - -import sklearn -import torch - -from sklearn.metrics import log_loss, roc_auc_score - -from deepctr_torch.inputs import SparseFeat, DenseFeat, get_feature_names -from deepctr_torch.models import WDL - - -def args_parser(): - parser = argparse.ArgumentParser(description='Wide&Deep') - parser.add_argument('--seed', default=1234, type=int, - help='seed for initializing training.') - parser.add_argument('--device_id', default=0, type=int, help='device id') - parser.add_argument('--rank', default=0, type=int, help='node rank for distributed training') - parser.add_argument('--dist', default=False, action='store_true', help='8p distributed training') - parser.add_argument('--device_num', default=1, type=int, - help='num of npu device for training') - parser.add_argument('--amp', default=False, action='store_true', - help='use amp to train the model') - parser.add_argument('--loss_scale', default=1024, type=float, - help='loss scale using in amp, default -1 means dynamic') - parser.add_argument('--opt_level', default='O1', type=str, - help='apex opt level') - parser.add_argument('--data_path', required=True, type=str, help='train data, and is to be') - parser.add_argument('--resume', default='', type=str, metavar='PATH', - help='path to latest checkpoint (default: none)') - parser.add_argument('--checkpoint_save_path', default='./', type=str, metavar='PATH', - help='path to save latest checkpoint') - parser.add_argument('--lr', default=0.0001, type=float, help='learning rate for training') - parser.add_argument('--batch_size', default=1024, type=int, help='batch size for training') - parser.add_argument('--eval_batch_size', default=16000, type=int, help='batch size for testing') - parser.add_argument('--epochs', default=3, type=int, help='epochs for training') - parser.add_argument('--start_epoch', default=0, type=int, metavar='N', help='record of the start epoch to run') - parser.add_argument('--sparse_embed_dim', default=4, type=int, help='The embedding dims for sparse features') - parser.add_argument('--steps', default=0, type=int, help='steps for training') - - parser_args, _ = parser.parse_known_args() - return parser_args - - -def fix_random(seed): - torch.manual_seed(seed) - torch.cuda.manual_seed(seed) - torch.cuda.manual_seed_all(seed) - np.random.seed(seed) - random.seed(seed) - - -if __name__ == "__main__": - args = args_parser() - print(args) - - fix_random(args.seed) - - sparse_features = ['C' + str(i) for i in range(1, 27)] - dense_features = ['I' + str(i) for i in range(1, 14)] - target = ['label'] - - # count #unique features for each sparse field,and record dense feature field name - start_time = time.time() - - data_trainval = pd.read_pickle(os.path.join(args.data_path, 'wdl_trainval.pkl')) - data_test = pd.read_pickle(os.path.join(args.data_path, 'wdl_test.pkl')) - - print('Data loaded in {}s'.format(time.time() - start_time)) - - sparse_nunique = [1460, 583, 10131227, 2202608, 305, 24, 12517, 633, 3, 93145, 5683, 8351593, 3194, 27, 14992, - 5461306, 10, 5652, 2173, 4, 7046547, 18, 15, 286181, 105, 142572] - fixlen_feature_columns = [SparseFeat(feat, sparse_nunique[idx], embedding_dim=args.sparse_embed_dim) - for idx, feat in enumerate(sparse_features)] + [DenseFeat(feat, 1, ) - for feat in dense_features] - print(fixlen_feature_columns) - - dnn_feature_columns = fixlen_feature_columns - linear_feature_columns = fixlen_feature_columns - - feature_names = get_feature_names( - linear_feature_columns + dnn_feature_columns) - - # generate input data for model - print('Generating input data for model...') - start_time = time.time() - train_model_input = {name: data_trainval[name].astype(float) for name in feature_names} - test_model_input = {name: data_test[name].astype(float) for name in feature_names} - print('Input data generated in {}s'.format(time.time() - start_time)) - - # Define Model,train,predict and evaluate - args.device_num = int(os.environ["RANK_SIZE"]) - if args.dist: - os.environ['MASTER_ADDR'] = '127.0.0.1' - os.environ['MASTER_PORT'] = '29680' - - args.rank = args.device_id - torch.distributed.init_process_group(backend='hccl', world_size=args.device_num, rank=args.rank) - print('distributed train enabled') - - device = 'npu:' + str(args.device_id) - torch.npu.set_device(device) - print('train on: ', device) - - model = WDL(linear_feature_columns=linear_feature_columns, dnn_feature_columns=dnn_feature_columns, - task='binary', dnn_hidden_units=(512, 256, 128), dnn_dropout=0.5, device=device, l2_reg_linear=1e-4, - l2_reg_embedding=1e-4, dist=args.dist) - - model.compile("adam", "binary_crossentropy", - metrics=["binary_crossentropy", "auc"], lr=args.lr, args=args) - - history = model.fit(train_model_input, data_trainval[target].values, batch_size=args.batch_size, epochs=args.epochs, - verbose=2, - validation_split=0.3, args=args) - - pred_ans = model.predict(test_model_input, args.eval_batch_size) - print("test LogLoss", round(log_loss(data_test[target].values, pred_ans), 4)) - print("test AUC", round(roc_auc_score(data_test[target].values, pred_ans), 4)) +# -*- coding: utf-8 -*- + +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 +# +# less 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 os +import time +import random +import argparse + +import numpy as np +import pandas as pd + +import sklearn +import torch + +from sklearn.metrics import log_loss, roc_auc_score + +from deepctr_torch.inputs import SparseFeat, DenseFeat, get_feature_names +from deepctr_torch.models import WDL + + +def args_parser(): + parser = argparse.ArgumentParser(description='Wide&Deep') + parser.add_argument('--seed', default=1234, type=int, + help='seed for initializing training.') + parser.add_argument('--device_id', default=0, type=int, help='device id') + parser.add_argument('--rank', default=0, type=int, help='node rank for distributed training') + parser.add_argument('--dist', default=False, action='store_true', help='8p distributed training') + parser.add_argument('--device_num', default=1, type=int, + help='num of npu device for training') + parser.add_argument('--amp', default=False, action='store_true', + help='use amp to train the model') + parser.add_argument('--loss_scale', default=1024, type=float, + help='loss scale using in amp, default -1 means dynamic') + parser.add_argument('--opt_level', default='O1', type=str, + help='apex opt level') + parser.add_argument('--data_path', required=True, type=str, help='train data, and is to be') + parser.add_argument('--resume', default='', type=str, metavar='PATH', + help='path to latest checkpoint (default: none)') + parser.add_argument('--checkpoint_save_path', default='./', type=str, metavar='PATH', + help='path to save latest checkpoint') + parser.add_argument('--lr', default=0.0001, type=float, help='learning rate for training') + parser.add_argument('--batch_size', default=1024, type=int, help='batch size for training') + parser.add_argument('--eval_batch_size', default=16000, type=int, help='batch size for testing') + parser.add_argument('--epochs', default=3, type=int, help='epochs for training') + parser.add_argument('--start_epoch', default=0, type=int, metavar='N', help='record of the start epoch to run') + parser.add_argument('--sparse_embed_dim', default=4, type=int, help='The embedding dims for sparse features') + parser.add_argument('--steps', default=0, type=int, help='steps for training') + + parser_args, _ = parser.parse_known_args() + return parser_args + + +def fix_random(seed): + torch.manual_seed(seed) + torch.cuda.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + np.random.seed(seed) + random.seed(seed) + + +if __name__ == "__main__": + args = args_parser() + print(args) + + fix_random(args.seed) + + sparse_features = ['C' + str(i) for i in range(1, 27)] + dense_features = ['I' + str(i) for i in range(1, 14)] + target = ['label'] + + # count #unique features for each sparse field,and record dense feature field name + start_time = time.time() + + data_trainval = pd.read_pickle(os.path.join(args.data_path, 'wdl_trainval.pkl')) + data_test = pd.read_pickle(os.path.join(args.data_path, 'wdl_test.pkl')) + + print('Data loaded in {}s'.format(time.time() - start_time)) + + sparse_nunique = [1460, 583, 10131227, 2202608, 305, 24, 12517, 633, 3, 93145, 5683, 8351593, 3194, 27, 14992, + 5461306, 10, 5652, 2173, 4, 7046547, 18, 15, 286181, 105, 142572] + fixlen_feature_columns = [SparseFeat(feat, sparse_nunique[idx], embedding_dim=args.sparse_embed_dim) + for idx, feat in enumerate(sparse_features)] + [DenseFeat(feat, 1, ) + for feat in dense_features] + print(fixlen_feature_columns) + + dnn_feature_columns = fixlen_feature_columns + linear_feature_columns = fixlen_feature_columns + + feature_names = get_feature_names( + linear_feature_columns + dnn_feature_columns) + + # generate input data for model + print('Generating input data for model...') + start_time = time.time() + train_model_input = {name: data_trainval[name].astype(float) for name in feature_names} + test_model_input = {name: data_test[name].astype(float) for name in feature_names} + print('Input data generated in {}s'.format(time.time() - start_time)) + + # Define Model,train,predict and evaluate + args.device_num = int(os.environ["RANK_SIZE"]) + if args.dist: + os.environ['MASTER_ADDR'] = '127.0.0.1' + os.environ['MASTER_PORT'] = '29680' + + args.rank = args.device_id + torch.distributed.init_process_group(backend='hccl', world_size=args.device_num, rank=args.rank) + print('distributed train enabled') + + device = 'npu:' + str(args.device_id) + torch.npu.set_device(device) + print('train on: ', device) + + model = WDL(linear_feature_columns=linear_feature_columns, dnn_feature_columns=dnn_feature_columns, + task='binary', dnn_hidden_units=(512, 256, 128), dnn_dropout=0.5, device=device, l2_reg_linear=1e-4, + l2_reg_embedding=1e-4, dist=args.dist) + + model.compile("adam", "binary_crossentropy", + metrics=["binary_crossentropy", "auc"], lr=args.lr, args=args) + + history = model.fit(train_model_input, data_trainval[target].values, batch_size=args.batch_size, epochs=args.epochs, + verbose=2, + validation_split=0.3, args=args) + + pred_ans = model.predict(test_model_input, args.eval_batch_size) + print("test LogLoss", round(log_loss(data_test[target].values, pred_ans), 4)) + print("test AUC", round(roc_auc_score(data_test[target].values, pred_ans), 4)) diff --git a/PyTorch/contrib/CONTRIBUTING.md b/PyTorch/contrib/CONTRIBUTING.md index 886fae1007..dc9d11e8ea 100644 --- a/PyTorch/contrib/CONTRIBUTING.md +++ b/PyTorch/contrib/CONTRIBUTING.md @@ -1,314 +1,314 @@ - **介绍** - -Ascend ModelZoo,欢迎各位开发者 - - **贡献要求** - -开发者提交的模型包括源码、readme、参考模型license文件、测试用例和readme,并遵循以下标准 - -请贡献者在提交代码之前签署CLA协议,“个人签署”,[链接](https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZhc2NlbmQ=) - -如您完成签署,可在自己提交的PR评论区输入/check-cla进行核实校验 - - **一、源码** - -1、训练及在线推理请使用python代码实现,Ascend平台离线推理请使用C++或python代码,符合第四部分编码规范 - -2、参考[sample](https://gitee.com/ascend/modelzoo/tree/master/built-in/TensorFlow/Official/nlp/Transformer_for_TensorFlow) - -3、贡献者模型代码目录规则:"modelzoo/contrib/框架/Research/应用领域(nlp、cv、audio等)/网络名_IDxxx_for_TensorFlow"(以tf为例,社区管理团队会在贡献完成进行整合) - -4、从其他开源迁移的代码,请增加License声明 - - **二、License规则** - -* TensorFlow - - 迁移场景 - - 1、迁移TensorFlow模型中若源项目已包含License文件则必须拷贝引用,否则在模型顶层目录下添加TensorFlow Apache 2.0 License [TensorFlow License链接](https://github.com/tensorflow/tensorflow/blob/master/LICENSE) - - 2、迁移TensorFlow框架开发的模型,需要在模型目录下每个源文件附上源社区TensorFlow Apache 2.0 License头部声明,并在其下追加新增完整华为公司License声明 - - ``` - # Copyright 2017 The TensorFlow 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. - # ============================================================================ - # Copyright 2021 Huawei Technologies Co., Ltd - # - # 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. - ``` - 开发场景 - - 1、基于TensorFlow框架开发模型,需在模型项目顶层目录下添加TensorFlow Apache 2.0 License [TensorFlow License链接](https://github.com/tensorflow/tensorflow/blob/master/LICENSE) - - 2、基于TensorFlow框架开发模型,需要在模型目录下每个源文件附上源社区华为公司Apache 2.0 License头部声明 - ``` - # Copyright 2021 Huawei Technologies Co., Ltd - # - # 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. - ``` -* PyTorch - - 迁移场景 - - 1、迁移PyTorch模型中若源项目录已包含PyTorch License文件则必须拷贝引用,否则在模型顶层目录下添加PyTorch BSD-3 License [PyTorch License链接](https://github.com/pytorch/examples/blob/master/LICENSE) - - 2、迁移PyTorch第三方框架开发的模型,需要在模型目录下每个源文件附上源社区PyTorch BSD-3 License头部声明,并在其下追加新增一行华为公司License声明 - ``` - # BSD 3-Clause License - # - # Copyright (c) 2017 xxxx - # All rights reserved. - # Copyright 2021 Huawei Technologies Co., Ltd - # - # Redistribution and use in source and binary forms, with or without - # modification, are permitted provided that the following conditions are met: - # - # * Redistributions of source code must retain the above copyright notice, this - # list of conditions and the following disclaimer. - # - # * Redistributions in binary form must reproduce the above copyright notice, - # this list of conditions and the following disclaimer in the documentation - # and/or other materials provided with the distribution. - # - # * Neither the name of the copyright holder nor the names of its - # contributors may be used to endorse or promote products derived from - # this software without specific prior written permission. - # - # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - # ============================================================================ - ``` - - 开发场景 - - 1、基于PyTorch框架开发模型,需在模型项目下添加PyTorch BSD-3 License [PyTorch License链接](https://github.com/pytorch/examples/blob/master/LICENSE) - - 2、基于PyTorch框架开发模型,需要在模型目录下每个源文件附上源社区华为公司Apache 2.0 License头部声明 - ``` - # Copyright 2021 Huawei Technologies Co., Ltd - # - # Licensed under the BSD 3-Clause License (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at - # - # https://opensource.org/licenses/BSD-3-Clause - # - # 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. - ``` - -* MindSpore/ACL - - 1、迁移或开发场景下MindSpore/ACL模型顶层目录下需要包含华为公司 License [华为公司 License链接](https://gitee.com/mindspore/mindspore/blob/master/LICENSE) - - 2、迁移或开发场景下MindSpore/ACL模型,需要在模型目录下每个源文件中添加区华为公司Apache 2.0 License头部声明 - ``` - # Copyright 2021 Huawei Technologies Co., Ltd - # - # 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. - ``` - -> 关于License声明时间,应注意: 2021年新建的文件,应该是Copyright 2021 Huawei Technologies Co., Ltd 2020年创建年份,2020年修改年份,应该是Copyright 2020 Huawei Technologies Co., Ltd - - **三、readme** - -readme用于指导用户理解和部署样例,要包含如下内容: - -- 简介: - -1、模型的来源及原理; - -2、模型复现的步骤,含训练、eval、在线/离线推理等,入口请封装成`.sh`、`.py`; - -- 关键要求: - -1、模型的出处、对数据的要求、免责声明等,开源代码文件修改需要增加版权说明; - -2、模型转换得到的离线模型对输入数据的要求; - -3、环境变量设置,依赖的第三方软件包和库,以及安装方法; - -4、精度和性能达成要求:尽量达到原始模型水平; - -5、预训练checkpoint、结果checkpoint请提供归档OBS、网盘链接,如来自开源需明确来源地址 - -6、数据集说明 - -- [ ] 不允许直接提供数据集的下载链接,可使用词汇:用户自行准备好数据集,可选用“XXX”,“XXX”,“XXX” - - 例如:请用户自行准备好数据集,包含训练集和验证集两部分,可选用的数据集包括ImageNet2012,CIFAR10、Flower等,包含train和val两部分。 - -- [ ] 脚本中不允许提供链接下载数据集,如果开源脚本上存在对应的链接,请修改或者删除对应的脚本 - -训练ReadMe写作可参考下面两个链接: - -[Readme example1](https://gitee.com/ascend/modelzoo/blob/master/built-in/TensorFlow/Official/cv/image_classification/DenseNet121_ID0067_for_TensorFlow/README.md) - -[Readme example2](https://www.hiascend.com/zh/software/modelzoo/detail/C/093ed0219cb14f068af33784c62cf7ec) - -离线推理ReadMe写作可参考下面链接: - -[Readme example1](https://gitee.com/ascend/modelzoo/tree/master/contrib/ACL_TensorFlow/Research/cv/AdvancedEAST_ID0130_for_ACL/README.md) - - **四、自测试用例** - -提供模型的自测试用例和readme,提交PR需要门禁及模型测试用例通过,性能和精度检查通过 - -- 简介: - -1、不同于完整的训练过程和全量数据集的推理,自测试用例的目的是验证提交代码基本功能可用,执行时长控制在10min之内(推理或训练只需执行有限的图片或step); - -2、提交PR中训练用例入口`train_testcase.sh`, 在线推理用例入口`online_inference_testcase.sh`, 离线推理用例入口`offline_inference_testcase.sh`; - -3、提交PR后,会自动触发门禁流水,后台会根据用例入口shell,自动将代码分发到对应执行环境; - -4、Jenkins预置账号:登录账号请联系华为工程师/接口人获取,登录之后,可以查看到用例执行日志 - -5、如果提交失败,请查看日志,修复代码或其他问题后,在你当前的PR中,评论“compile”即可重新触发用例执行 - -- 关键要求: - -1、自测试用例命名严格按照上述简介2要求来书写,否则门禁会校验失败; - -2、用例应当包含功能、精度(Loss值)、性能检查,检查通过打印"Run testcase success!",失败则打印"Run testcase failed!"; - -3、执行环境已预装软件包和Python3.7.5环境,调用命令"python3"、"python3.7"、"python3.7.5"均可,安装第三方库依赖使用"pip3"、"pip3.7"均可; - -4、数据集和模型:小于500M的文件,建议使用`obsutil`命令下载(已预装),过大的文件,建议提交Issue,注明数据集和下载地址,会提前下载到执行环境上, - -已预置数据集&python第三方库: [Environments](https://gitee.com/ascend/modelzoo/blob/master/contrib/ENVIRONMENTS.md) - -5、环境和其他问题,请提交Issue跟踪; - -6、测试用例开发参考: -- [训练](https://gitee.com/ascend/modelzoo/tree/master/built-in/TensorFlow/Official/nlp/Transformer_for_TensorFlow) -- [离线推理](https://gitee.com/alexcheng88/modelzoo/tree/master/contrib/TensorFlow/Research/cv/efficientnet-b8/ATC_efficientnet-b8_tf_nkxiaolei) - - **五、PR提交** - -- 关键要求: - -1、请将modelzoo仓fork到个人分支,基于个人分支新增、修改和提交PR; - -2、PR标题:线上活动,请在标题注明[线上贡献];高校活动,请注明[xxx学校][高校贡献]; - -3、built-in用户根据网络状态必须配置modelzoo_level.txt文件,且文件内容包含三个关键字段:FuncStatus(OK-流程通过/ **NOK-流程失败,不允许模型代码提交主仓** );PerfStatus(OK-持平GPU/POK-0.5倍GPU/NOK-小于0.5倍GPU/PERFECT-1.2倍GPU);PrecisionStatus(OK-精度达标,POK-Loss拟合但精度未实施, **NOK-Loss不拟合,不允许模型代码提交主仓** );内容格式如下所示(注:“:”两侧无需空格,英文格式;): - -``` - FuncStatus:OK/NOK - PerfStatus:PERFECT/OK/POK/NOK - PrecisionStatus:OK/POK/NOK -``` -4、contrib用户根据网络状态必须配置modelzoo_level.txt文件,且文件内容包含关键字段:GPUStatus(OK-GPU复现/NOK-GPU未复现); NPUMigrationStatus(OK-自动迁移成功/POK-自动迁移失败, 手写规避成功/NOK-均失败); FuncStatus(OK-基础功能打通/NOK-基础功能失败,不允许模型代码提交到master); PrecisionStatus(OK-精度达标/POK-Loss拟合但精度未完全达标/NOK-精度不达标, 不允许模型代码提交到master); AutoTune(OK-性能持平或高于GPU/POK-性能有提升但低于GPU/NOK-性能无提升或者功能失败); PerfStatus(训练:PERFECT-性能1.2倍GPU/OK-性能持平GPU/POK-性能0.5倍GPU/NOK-性能小于0.5倍GPU;推理:OK-4*310单卡>GPU/NOK-其它); ModelConvert:OK/NOK(仅推理, OK-om转换成功/NOK-om转换失败); QuantStatus:OK/NOK(仅推理, OK-精度损失1%以内,性能有提升/POK-性能有提升但未达标/NOK-量化失败); - -样例:modelzoo_level.txt文件 - ------仅限训练----- - - -``` -GPUStatus:OK/NOK -NPUMigrationStatus:OK/POK/NOK -``` - - ------仅限推理----- - -``` -ModelConvert:OK/POK/NOK -QuantStatus:OK/POK/NOK -``` - ------通用部分----- - -``` -FuncStatus:OK/NOK -PrecisionStatus:OK/POK/NOK -AutoTune:OK/POK/NOK -PerfStatus:PERFECT/OK/POK/NOK -``` -5、网络名称命名规范:*_for_框架,注:*代表任意内容,如网络名称或网络名称+网络ID; - - **六、编程规范** - -- 规范标准 - -1、C++代码遵循google编程规范:Google C++ Coding Guidelines;单元测测试遵循规范: Googletest Primer。 - -2、Python代码遵循PEP8规范:Python PEP 8 Coding Style;单元测试遵循规范: pytest - -- 规范备注 - -1、优先使用string类型,避免使用char*; - -2、禁止使用printf,一律使用cout; - -3、内存管理尽量使用智能指针; - -4、不准在函数里调用exit; - -5、禁止使用IDE等工具自动生成代码; - -6、控制第三方库依赖,如果引入第三方依赖,则需要提供第三方依赖安装和使用指导书; - -7、一律使用英文注释,注释率30%--40%,鼓励自注释; - -8、函数头必须有注释,说明函数作用,入参、出参; - -9、统一错误码,通过错误码可以确认那个分支返回错误; - -10、禁止出现打印一堆无影响的错误级别的日志; + **介绍** + +Ascend ModelZoo,欢迎各位开发者 + + **贡献要求** + +开发者提交的模型包括源码、readme、参考模型license文件、测试用例和readme,并遵循以下标准 + +请贡献者在提交代码之前签署CLA协议,“个人签署”,[链接](https://clasign.osinfra.cn/sign/Z2l0ZWUlMkZhc2NlbmQ=) + +如您完成签署,可在自己提交的PR评论区输入/check-cla进行核实校验 + + **一、源码** + +1、训练及在线推理请使用python代码实现,Ascend平台离线推理请使用C++或python代码,符合第四部分编码规范 + +2、参考[sample](https://gitee.com/ascend/modelzoo/tree/master/built-in/TensorFlow/Official/nlp/Transformer_for_TensorFlow) + +3、贡献者模型代码目录规则:"modelzoo/contrib/框架/Research/应用领域(nlp、cv、audio等)/网络名_IDxxx_for_TensorFlow"(以tf为例,社区管理团队会在贡献完成进行整合) + +4、从其他开源迁移的代码,请增加License声明 + + **二、License规则** + +* TensorFlow + + 迁移场景 + + 1、迁移TensorFlow模型中若源项目已包含License文件则必须拷贝引用,否则在模型顶层目录下添加TensorFlow Apache 2.0 License [TensorFlow License链接](https://github.com/tensorflow/tensorflow/blob/master/LICENSE) + + 2、迁移TensorFlow框架开发的模型,需要在模型目录下每个源文件附上源社区TensorFlow Apache 2.0 License头部声明,并在其下追加新增完整华为公司License声明 + + ``` + # Copyright 2017 The TensorFlow 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. + # ============================================================================ + # Copyright 2021 Huawei Technologies Co., Ltd + # + # 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. + ``` + 开发场景 + + 1、基于TensorFlow框架开发模型,需在模型项目顶层目录下添加TensorFlow Apache 2.0 License [TensorFlow License链接](https://github.com/tensorflow/tensorflow/blob/master/LICENSE) + + 2、基于TensorFlow框架开发模型,需要在模型目录下每个源文件附上源社区华为公司Apache 2.0 License头部声明 + ``` + # Copyright 2021 Huawei Technologies Co., Ltd + # + # 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. + ``` +* PyTorch + + 迁移场景 + + 1、迁移PyTorch模型中若源项目录已包含PyTorch License文件则必须拷贝引用,否则在模型顶层目录下添加PyTorch BSD-3 License [PyTorch License链接](https://github.com/pytorch/examples/blob/master/LICENSE) + + 2、迁移PyTorch第三方框架开发的模型,需要在模型目录下每个源文件附上源社区PyTorch BSD-3 License头部声明,并在其下追加新增一行华为公司License声明 + ``` + # BSD 3-Clause License + # + # Copyright (c) 2017 xxxx + # All rights reserved. + # Copyright 2021 Huawei Technologies Co., Ltd + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions are met: + # + # * Redistributions of source code must retain the above copyright notice, this + # list of conditions and the following disclaimer. + # + # * Redistributions in binary form must reproduce the above copyright notice, + # this list of conditions and the following disclaimer in the documentation + # and/or other materials provided with the distribution. + # + # * Neither the name of the copyright holder nor the names of its + # contributors may be used to endorse or promote products derived from + # this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + # ============================================================================ + ``` + + 开发场景 + + 1、基于PyTorch框架开发模型,需在模型项目下添加PyTorch BSD-3 License [PyTorch License链接](https://github.com/pytorch/examples/blob/master/LICENSE) + + 2、基于PyTorch框架开发模型,需要在模型目录下每个源文件附上源社区华为公司Apache 2.0 License头部声明 + ``` + # Copyright 2021 Huawei Technologies Co., Ltd + # + # Licensed under the BSD 3-Clause License (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # https://opensource.org/licenses/BSD-3-Clause + # + # 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. + ``` + +* MindSpore/ACL + + 1、迁移或开发场景下MindSpore/ACL模型顶层目录下需要包含华为公司 License [华为公司 License链接](https://gitee.com/mindspore/mindspore/blob/master/LICENSE) + + 2、迁移或开发场景下MindSpore/ACL模型,需要在模型目录下每个源文件中添加区华为公司Apache 2.0 License头部声明 + ``` + # Copyright 2021 Huawei Technologies Co., Ltd + # + # 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. + ``` + +> 关于License声明时间,应注意: 2021年新建的文件,应该是Copyright 2021 Huawei Technologies Co., Ltd 2020年创建年份,2020年修改年份,应该是Copyright 2020 Huawei Technologies Co., Ltd + + **三、readme** + +readme用于指导用户理解和部署样例,要包含如下内容: + +- 简介: + +1、模型的来源及原理; + +2、模型复现的步骤,含训练、eval、在线/离线推理等,入口请封装成`.sh`、`.py`; + +- 关键要求: + +1、模型的出处、对数据的要求、免责声明等,开源代码文件修改需要增加版权说明; + +2、模型转换得到的离线模型对输入数据的要求; + +3、环境变量设置,依赖的第三方软件包和库,以及安装方法; + +4、精度和性能达成要求:尽量达到原始模型水平; + +5、预训练checkpoint、结果checkpoint请提供归档OBS、网盘链接,如来自开源需明确来源地址 + +6、数据集说明 + +- [ ] 不允许直接提供数据集的下载链接,可使用词汇:用户自行准备好数据集,可选用“XXX”,“XXX”,“XXX” + + 例如:请用户自行准备好数据集,包含训练集和验证集两部分,可选用的数据集包括ImageNet2012,CIFAR10、Flower等,包含train和val两部分。 + +- [ ] 脚本中不允许提供链接下载数据集,如果开源脚本上存在对应的链接,请修改或者删除对应的脚本 + +训练ReadMe写作可参考下面两个链接: + +[Readme example1](https://gitee.com/ascend/modelzoo/blob/master/built-in/TensorFlow/Official/cv/image_classification/DenseNet121_ID0067_for_TensorFlow/README.md) + +[Readme example2](https://www.hiascend.com/zh/software/modelzoo/detail/C/093ed0219cb14f068af33784c62cf7ec) + +离线推理ReadMe写作可参考下面链接: + +[Readme example1](https://gitee.com/ascend/modelzoo/tree/master/contrib/ACL_TensorFlow/Research/cv/AdvancedEAST_ID0130_for_ACL/README.md) + + **四、自测试用例** + +提供模型的自测试用例和readme,提交PR需要门禁及模型测试用例通过,性能和精度检查通过 + +- 简介: + +1、不同于完整的训练过程和全量数据集的推理,自测试用例的目的是验证提交代码基本功能可用,执行时长控制在10min之内(推理或训练只需执行有限的图片或step); + +2、提交PR中训练用例入口`train_testcase.sh`, 在线推理用例入口`online_inference_testcase.sh`, 离线推理用例入口`offline_inference_testcase.sh`; + +3、提交PR后,会自动触发门禁流水,后台会根据用例入口shell,自动将代码分发到对应执行环境; + +4、Jenkins预置账号:登录账号请联系华为工程师/接口人获取,登录之后,可以查看到用例执行日志 + +5、如果提交失败,请查看日志,修复代码或其他问题后,在你当前的PR中,评论“compile”即可重新触发用例执行 + +- 关键要求: + +1、自测试用例命名严格按照上述简介2要求来书写,否则门禁会校验失败; + +2、用例应当包含功能、精度(Loss值)、性能检查,检查通过打印"Run testcase success!",失败则打印"Run testcase failed!"; + +3、执行环境已预装软件包和Python3.7.5环境,调用命令"python3"、"python3.7"、"python3.7.5"均可,安装第三方库依赖使用"pip3"、"pip3.7"均可; + +4、数据集和模型:小于500M的文件,建议使用`obsutil`命令下载(已预装),过大的文件,建议提交Issue,注明数据集和下载地址,会提前下载到执行环境上, + +已预置数据集&python第三方库: [Environments](https://gitee.com/ascend/modelzoo/blob/master/contrib/ENVIRONMENTS.md) + +5、环境和其他问题,请提交Issue跟踪; + +6、测试用例开发参考: +- [训练](https://gitee.com/ascend/modelzoo/tree/master/built-in/TensorFlow/Official/nlp/Transformer_for_TensorFlow) +- [离线推理](https://gitee.com/alexcheng88/modelzoo/tree/master/contrib/TensorFlow/Research/cv/efficientnet-b8/ATC_efficientnet-b8_tf_nkxiaolei) + + **五、PR提交** + +- 关键要求: + +1、请将modelzoo仓fork到个人分支,基于个人分支新增、修改和提交PR; + +2、PR标题:线上活动,请在标题注明[线上贡献];高校活动,请注明[xxx学校][高校贡献]; + +3、built-in用户根据网络状态必须配置modelzoo_level.txt文件,且文件内容包含三个关键字段:FuncStatus(OK-流程通过/ **NOK-流程失败,不允许模型代码提交主仓** );PerfStatus(OK-持平GPU/POK-0.5倍GPU/NOK-小于0.5倍GPU/PERFECT-1.2倍GPU);PrecisionStatus(OK-精度达标,POK-Loss拟合但精度未实施, **NOK-Loss不拟合,不允许模型代码提交主仓** );内容格式如下所示(注:“:”两侧无需空格,英文格式;): + +``` + FuncStatus:OK/NOK + PerfStatus:PERFECT/OK/POK/NOK + PrecisionStatus:OK/POK/NOK +``` +4、contrib用户根据网络状态必须配置modelzoo_level.txt文件,且文件内容包含关键字段:GPUStatus(OK-GPU复现/NOK-GPU未复现); NPUMigrationStatus(OK-自动迁移成功/POK-自动迁移失败, 手写规避成功/NOK-均失败); FuncStatus(OK-基础功能打通/NOK-基础功能失败,不允许模型代码提交到master); PrecisionStatus(OK-精度达标/POK-Loss拟合但精度未完全达标/NOK-精度不达标, 不允许模型代码提交到master); AutoTune(OK-性能持平或高于GPU/POK-性能有提升但低于GPU/NOK-性能无提升或者功能失败); PerfStatus(训练:PERFECT-性能1.2倍GPU/OK-性能持平GPU/POK-性能0.5倍GPU/NOK-性能小于0.5倍GPU;推理:OK-4*310单卡>GPU/NOK-其它); ModelConvert:OK/NOK(仅推理, OK-om转换成功/NOK-om转换失败); QuantStatus:OK/NOK(仅推理, OK-精度损失1%以内,性能有提升/POK-性能有提升但未达标/NOK-量化失败); + +样例:modelzoo_level.txt文件 + +-----仅限训练----- + + +``` +GPUStatus:OK/NOK +NPUMigrationStatus:OK/POK/NOK +``` + + +-----仅限推理----- + +``` +ModelConvert:OK/POK/NOK +QuantStatus:OK/POK/NOK +``` + +-----通用部分----- + +``` +FuncStatus:OK/NOK +PrecisionStatus:OK/POK/NOK +AutoTune:OK/POK/NOK +PerfStatus:PERFECT/OK/POK/NOK +``` +5、网络名称命名规范:*_for_框架,注:*代表任意内容,如网络名称或网络名称+网络ID; + + **六、编程规范** + +- 规范标准 + +1、C++代码遵循google编程规范:Google C++ Coding Guidelines;单元测测试遵循规范: Googletest Primer。 + +2、Python代码遵循PEP8规范:Python PEP 8 Coding Style;单元测试遵循规范: pytest + +- 规范备注 + +1、优先使用string类型,避免使用char*; + +2、禁止使用printf,一律使用cout; + +3、内存管理尽量使用智能指针; + +4、不准在函数里调用exit; + +5、禁止使用IDE等工具自动生成代码; + +6、控制第三方库依赖,如果引入第三方依赖,则需要提供第三方依赖安装和使用指导书; + +7、一律使用英文注释,注释率30%--40%,鼓励自注释; + +8、函数头必须有注释,说明函数作用,入参、出参; + +9、统一错误码,通过错误码可以确认那个分支返回错误; + +10、禁止出现打印一堆无影响的错误级别的日志; diff --git a/PyTorch/contrib/audio/FastPitch/fastpitch/loss_function.py b/PyTorch/contrib/audio/FastPitch/fastpitch/loss_function.py index 9baf4a6c31..0fe133abd4 100644 --- a/PyTorch/contrib/audio/FastPitch/fastpitch/loss_function.py +++ b/PyTorch/contrib/audio/FastPitch/fastpitch/loss_function.py @@ -1,108 +1,108 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch -import torch.nn.functional as F -from torch import nn - -from common.utils import mask_from_lens -from fastpitch.attn_loss_function import AttentionCTCLoss - - -class FastPitchLoss(nn.Module): - def __init__(self, dur_predictor_loss_scale=1.0, - pitch_predictor_loss_scale=1.0, attn_loss_scale=1.0, - energy_predictor_loss_scale=0.1): - super(FastPitchLoss, self).__init__() - self.dur_predictor_loss_scale = dur_predictor_loss_scale - self.pitch_predictor_loss_scale = pitch_predictor_loss_scale - self.energy_predictor_loss_scale = energy_predictor_loss_scale - self.attn_loss_scale = attn_loss_scale - self.attn_ctc_loss = AttentionCTCLoss() - - def forward(self, model_out, targets, is_training=True, meta_agg='mean'): - (mel_out, dec_mask, dur_pred, log_dur_pred, pitch_pred, pitch_tgt, - energy_pred, energy_tgt, attn_soft, attn_hard, attn_dur, - attn_logprob) = model_out - - (mel_tgt, in_lens, out_lens) = targets - - dur_tgt = attn_dur - dur_lens = in_lens - - mel_tgt.requires_grad = False - # (B,H,T) => (B,T,H) - mel_tgt = mel_tgt.transpose(1, 2) - - dur_mask = mask_from_lens(dur_lens, max_len=dur_tgt.size(1)) - dur_mask_sum = dur_mask.sum() - - log_dur_tgt = torch.log(dur_tgt.float() + 1) - loss_fn = F.mse_loss - dur_pred_loss = loss_fn(log_dur_pred, log_dur_tgt, reduction='none') - dur_pred_loss = (dur_pred_loss * dur_mask).sum() / dur_mask_sum - - ldiff = mel_tgt.size(1) - mel_out.size(1) - mel_out = F.pad(mel_out, (0, 0, 0, ldiff, 0, 0), value=0.0) - - mel_mask = mel_tgt.ne(0).float() - mel_mask_sum = mel_mask.sum() - - loss_fn = F.mse_loss - mel_loss = loss_fn(mel_out, mel_tgt, reduction='none') - mel_loss = (mel_loss * mel_mask).sum() / mel_mask_sum - - ldiff = pitch_tgt.size(2) - pitch_pred.size(2) - pitch_pred = F.pad(pitch_pred, (0, ldiff, 0, 0, 0, 0), value=0.0) - pitch_loss = F.mse_loss(pitch_tgt, pitch_pred, reduction='none') - pitch_loss = (pitch_loss * dur_mask.unsqueeze(1)).sum() / dur_mask_sum - - if energy_pred is not None: - energy_pred = F.pad(energy_pred, (0, ldiff, 0, 0), value=0.0) - energy_loss = F.mse_loss(energy_tgt, energy_pred, reduction='none') - energy_loss = (energy_loss * dur_mask).sum() / dur_mask_sum - else: - energy_loss = 0 - - # Attention loss - attn_loss = self.attn_ctc_loss(attn_logprob, in_lens, out_lens) - - loss = (mel_loss - + dur_pred_loss * self.dur_predictor_loss_scale - + pitch_loss * self.pitch_predictor_loss_scale - + energy_loss * self.energy_predictor_loss_scale - + attn_loss * self.attn_loss_scale) - - meta = { - 'loss': loss.clone().detach(), - 'mel_loss': mel_loss.clone().detach(), - 'duration_predictor_loss': dur_pred_loss.clone().detach(), - 'pitch_loss': pitch_loss.clone().detach(), - 'energy_loss': energy_loss.clone().detach(), - 'attn_loss': attn_loss.clone().detach(), - 'dur_mask_sum': dur_mask_sum.clone().detach(), - 'mel_mask_sum': mel_mask_sum.clone().detach(), - 'dur_error': (torch.abs(dur_pred - dur_tgt).sum() - / dur_mask_sum).detach(), - } - - if energy_pred is not None: - meta['energy_loss'] = energy_loss.clone().detach() - - assert meta_agg in ('sum', 'mean') - if meta_agg == 'sum': - bsz = mel_out.size(0) - meta = {k: v * bsz for k, v in meta.items()} - return loss, meta +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch +import torch.nn.functional as F +from torch import nn + +from common.utils import mask_from_lens +from fastpitch.attn_loss_function import AttentionCTCLoss + + +class FastPitchLoss(nn.Module): + def __init__(self, dur_predictor_loss_scale=1.0, + pitch_predictor_loss_scale=1.0, attn_loss_scale=1.0, + energy_predictor_loss_scale=0.1): + super(FastPitchLoss, self).__init__() + self.dur_predictor_loss_scale = dur_predictor_loss_scale + self.pitch_predictor_loss_scale = pitch_predictor_loss_scale + self.energy_predictor_loss_scale = energy_predictor_loss_scale + self.attn_loss_scale = attn_loss_scale + self.attn_ctc_loss = AttentionCTCLoss() + + def forward(self, model_out, targets, is_training=True, meta_agg='mean'): + (mel_out, dec_mask, dur_pred, log_dur_pred, pitch_pred, pitch_tgt, + energy_pred, energy_tgt, attn_soft, attn_hard, attn_dur, + attn_logprob) = model_out + + (mel_tgt, in_lens, out_lens) = targets + + dur_tgt = attn_dur + dur_lens = in_lens + + mel_tgt.requires_grad = False + # (B,H,T) => (B,T,H) + mel_tgt = mel_tgt.transpose(1, 2) + + dur_mask = mask_from_lens(dur_lens, max_len=dur_tgt.size(1)) + dur_mask_sum = dur_mask.sum() + + log_dur_tgt = torch.log(dur_tgt.float() + 1) + loss_fn = F.mse_loss + dur_pred_loss = loss_fn(log_dur_pred, log_dur_tgt, reduction='none') + dur_pred_loss = (dur_pred_loss * dur_mask).sum() / dur_mask_sum + + ldiff = mel_tgt.size(1) - mel_out.size(1) + mel_out = F.pad(mel_out, (0, 0, 0, ldiff, 0, 0), value=0.0) + + mel_mask = mel_tgt.ne(0).float() + mel_mask_sum = mel_mask.sum() + + loss_fn = F.mse_loss + mel_loss = loss_fn(mel_out, mel_tgt, reduction='none') + mel_loss = (mel_loss * mel_mask).sum() / mel_mask_sum + + ldiff = pitch_tgt.size(2) - pitch_pred.size(2) + pitch_pred = F.pad(pitch_pred, (0, ldiff, 0, 0, 0, 0), value=0.0) + pitch_loss = F.mse_loss(pitch_tgt, pitch_pred, reduction='none') + pitch_loss = (pitch_loss * dur_mask.unsqueeze(1)).sum() / dur_mask_sum + + if energy_pred is not None: + energy_pred = F.pad(energy_pred, (0, ldiff, 0, 0), value=0.0) + energy_loss = F.mse_loss(energy_tgt, energy_pred, reduction='none') + energy_loss = (energy_loss * dur_mask).sum() / dur_mask_sum + else: + energy_loss = 0 + + # Attention loss + attn_loss = self.attn_ctc_loss(attn_logprob, in_lens, out_lens) + + loss = (mel_loss + + dur_pred_loss * self.dur_predictor_loss_scale + + pitch_loss * self.pitch_predictor_loss_scale + + energy_loss * self.energy_predictor_loss_scale + + attn_loss * self.attn_loss_scale) + + meta = { + 'loss': loss.clone().detach(), + 'mel_loss': mel_loss.clone().detach(), + 'duration_predictor_loss': dur_pred_loss.clone().detach(), + 'pitch_loss': pitch_loss.clone().detach(), + 'energy_loss': energy_loss.clone().detach(), + 'attn_loss': attn_loss.clone().detach(), + 'dur_mask_sum': dur_mask_sum.clone().detach(), + 'mel_mask_sum': mel_mask_sum.clone().detach(), + 'dur_error': (torch.abs(dur_pred - dur_tgt).sum() + / dur_mask_sum).detach(), + } + + if energy_pred is not None: + meta['energy_loss'] = energy_loss.clone().detach() + + assert meta_agg in ('sum', 'mean') + if meta_agg == 'sum': + bsz = mel_out.size(0) + meta = {k: v * bsz for k, v in meta.items()} + return loss, meta diff --git a/PyTorch/contrib/audio/baseline-rawnet/README.md b/PyTorch/contrib/audio/baseline-rawnet/README.md index ecd0232b7e..91569eb766 100644 --- a/PyTorch/contrib/audio/baseline-rawnet/README.md +++ b/PyTorch/contrib/audio/baseline-rawnet/README.md @@ -1,128 +1,128 @@ -# RawNet2 - -This implements training of RawNet2 on the VoxCeleb1&2 datasets of YouTube. - -- Reference implementation: - -``` -url=https://github.com/Jungjee/RawNet -dir=RawNet-master/python/RawNet2 -``` - -## Baseline-RawNet2 Detail - -As of the current date, Ascend-Pytorch is still inefficient for contiguous operations. Therefore, RawNet2 is re-implemented using semantics such as custom OP. - -## Requirements - -- Install PyTorch ([pytorch.org](http://pytorch.org)) -- `pip install -r requirements.txt` - -## DataSet - -``` -url: http://www.robots.ox.ac.uk/~vgg/data/voxceleb/ -``` - -- The training datasets are VoxCeleb2, the evaluation dataset is VoxCeleb1H & VoxCeleb1E. The datasets are large. Please ensure sufficient hard disk space when downloading and decompressing. -- Besides, the data in the VoxCeleb2 downloaded from the url above is in the format of .m4a. If you do not use the dataset which is converted already, you should firstly run the `m4a2wav.py`. -- You need to follow directory structure of the `data` as below. If you connect to the prepared data folder, you don't need to build the following directory. - -``` -${RawNet}/DB/VoxCeleb1/ -├── dev_wav -│   ├── id10001 -│   │   ├── 1zcIwhmdeo4 -│   │   │   ├── 00001.wav -│   │   │   ├── 00002.wav -│   │   │   └── 00003.wav -│   │   ├── 5ssVY9a5X-M -│   │   │   ├── 00001.wav -│   │   │   ├── 00002.wav -│   │   │   ├── 00003.wav -│   │   │   └── 00003.wav -│   └── ... -├── eval_wav -│   ├── id10270 -│   │   ├── 5r0dWxy17C8 -│   │   │   ├── 00001.wav -│   │   │   ├── 00002.wav -│   │   │   ├── 00003.wav -│   │   │   ├── 00004.wav -│   │   │   └── 00005.wav -│   └── ... -│   ├── _z_BR0ERa9g -│   ├── 00001.wav -│   ├── 00002.wav -│   └── 00003.wav -├── val_trial.txt -└── veri_test.txt - -${RawNet}/DB/VoxCeleb2/ -└── wav - ├── id00012 - │   ├── 21Uxsk56VDQ - │   │   ├── 00001.wav - │   │   ├── ... - │   │   └── 00059.wav - │   ├── 00-qODbtozw - │   │   ├── ... - │   │   ├── 00079.wav - │   │   └── 00080.wav - ├── ... - │   └── zw-4DTjqIA0 - │   ├── 00108.wav - │   └── 00109.wav - └── id09272 - └── u7VNkYraCw0 - ├── ... - └── 00027.wav -``` - -- You need to follow directory structure of the `output` as below. - -``` -${RawNet}/train/train_${device_count}P -|-- DNNS/${name}/ -| |-- models -| | |--best_opt_eval.pt ## The best perfomance model is saved here -| | |--TA_${epoch}_${eer}.pt ##The other model is saved here -| |-- results -| |-- log -| | |-- eval_epoch${epoch}.txt ## The training log is saved here -| |-- prof -| |-- eers.txt ##The eers is saved here -| |-- f_params.txt ##The params of the model are saved here -``` - -## Training # - -- Note that the `output` folder under the `test` directory will also save the code running log. -- To run the model, you should cd to the directory of test -- To train a model, run `train_1p.py` or `train_8p.py`: - -```bash -# 1p train perf -nohup bash train_performance_1p.sh --data_path=xxx & - -# 8p train perf -nohup bash train_performance_8p.sh --data_path=xxx & - -# 1p train full -nohup bash train_full_1p.sh --data_path=xxx & - -# 8p train full -nohup bash train_full_8p.sh --data_path=xxx & - -``` - -## RawNet2 training result - -| eer(percentage) | FPS(aver) | Npu_nums | Epochs | AMP_Type | -| :-------------------------: | :-------: | :------: | :----: | :------: | -| 0.14 | 7760 | 1 | 1 | O2 | -| 0.038(aver) and 0.035(high) | 8573 | 8 | 20 | O2 | - -### **Testing** - -The testing data in the paper is about the VoxCeleb1H and VoxCeleb1E. And here we use the dataset of the VoxCeleb1H, and the target of the eer in the paper is 0.0489. +# RawNet2 + +This implements training of RawNet2 on the VoxCeleb1&2 datasets of YouTube. + +- Reference implementation: + +``` +url=https://github.com/Jungjee/RawNet +dir=RawNet-master/python/RawNet2 +``` + +## Baseline-RawNet2 Detail + +As of the current date, Ascend-Pytorch is still inefficient for contiguous operations. Therefore, RawNet2 is re-implemented using semantics such as custom OP. + +## Requirements + +- Install PyTorch ([pytorch.org](http://pytorch.org)) +- `pip install -r requirements.txt` + +## DataSet + +``` +url: http://www.robots.ox.ac.uk/~vgg/data/voxceleb/ +``` + +- The training datasets are VoxCeleb2, the evaluation dataset is VoxCeleb1H & VoxCeleb1E. The datasets are large. Please ensure sufficient hard disk space when downloading and decompressing. +- Besides, the data in the VoxCeleb2 downloaded from the url above is in the format of .m4a. If you do not use the dataset which is converted already, you should firstly run the `m4a2wav.py`. +- You need to follow directory structure of the `data` as below. If you connect to the prepared data folder, you don't need to build the following directory. + +``` +${RawNet}/DB/VoxCeleb1/ +├── dev_wav +│   ├── id10001 +│   │   ├── 1zcIwhmdeo4 +│   │   │   ├── 00001.wav +│   │   │   ├── 00002.wav +│   │   │   └── 00003.wav +│   │   ├── 5ssVY9a5X-M +│   │   │   ├── 00001.wav +│   │   │   ├── 00002.wav +│   │   │   ├── 00003.wav +│   │   │   └── 00003.wav +│   └── ... +├── eval_wav +│   ├── id10270 +│   │   ├── 5r0dWxy17C8 +│   │   │   ├── 00001.wav +│   │   │   ├── 00002.wav +│   │   │   ├── 00003.wav +│   │   │   ├── 00004.wav +│   │   │   └── 00005.wav +│   └── ... +│   ├── _z_BR0ERa9g +│   ├── 00001.wav +│   ├── 00002.wav +│   └── 00003.wav +├── val_trial.txt +└── veri_test.txt + +${RawNet}/DB/VoxCeleb2/ +└── wav + ├── id00012 + │   ├── 21Uxsk56VDQ + │   │   ├── 00001.wav + │   │   ├── ... + │   │   └── 00059.wav + │   ├── 00-qODbtozw + │   │   ├── ... + │   │   ├── 00079.wav + │   │   └── 00080.wav + ├── ... + │   └── zw-4DTjqIA0 + │   ├── 00108.wav + │   └── 00109.wav + └── id09272 + └── u7VNkYraCw0 + ├── ... + └── 00027.wav +``` + +- You need to follow directory structure of the `output` as below. + +``` +${RawNet}/train/train_${device_count}P +|-- DNNS/${name}/ +| |-- models +| | |--best_opt_eval.pt ## The best perfomance model is saved here +| | |--TA_${epoch}_${eer}.pt ##The other model is saved here +| |-- results +| |-- log +| | |-- eval_epoch${epoch}.txt ## The training log is saved here +| |-- prof +| |-- eers.txt ##The eers is saved here +| |-- f_params.txt ##The params of the model are saved here +``` + +## Training # + +- Note that the `output` folder under the `test` directory will also save the code running log. +- To run the model, you should cd to the directory of test +- To train a model, run `train_1p.py` or `train_8p.py`: + +```bash +# 1p train perf +nohup bash train_performance_1p.sh --data_path=xxx & + +# 8p train perf +nohup bash train_performance_8p.sh --data_path=xxx & + +# 1p train full +nohup bash train_full_1p.sh --data_path=xxx & + +# 8p train full +nohup bash train_full_8p.sh --data_path=xxx & + +``` + +## RawNet2 training result + +| eer(percentage) | FPS(aver) | Npu_nums | Epochs | AMP_Type | +| :-------------------------: | :-------: | :------: | :----: | :------: | +| 0.14 | 7760 | 1 | 1 | O2 | +| 0.038(aver) and 0.035(high) | 8573 | 8 | 20 | O2 | + +### **Testing** + +The testing data in the paper is about the VoxCeleb1H and VoxCeleb1E. And here we use the dataset of the VoxCeleb1H, and the target of the eer in the paper is 0.0489. diff --git a/PyTorch/contrib/audio/baseline-rawnet/modelzoo_level.txt b/PyTorch/contrib/audio/baseline-rawnet/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/audio/baseline-rawnet/modelzoo_level.txt +++ b/PyTorch/contrib/audio/baseline-rawnet/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/audio/baseline-rawnet/requirements.txt b/PyTorch/contrib/audio/baseline-rawnet/requirements.txt index 3e7d7460a2..45427a860f 100644 --- a/PyTorch/contrib/audio/baseline-rawnet/requirements.txt +++ b/PyTorch/contrib/audio/baseline-rawnet/requirements.txt @@ -1,9 +1,9 @@ -torch==1.5.0+ascend.post3 -apex==0.1+ascend.20210930 -torchvision==0.2.2.post3 -numpy==1.21.2 -Pillow==8.3.2 -scikit-learn==1.0 -scipy==1.7.1 -tqdm==4.62.3 +torch==1.5.0+ascend.post3 +apex==0.1+ascend.20210930 +torchvision==0.2.2.post3 +numpy==1.21.2 +Pillow==8.3.2 +scikit-learn==1.0 +scipy==1.7.1 +tqdm==4.62.3 SoundFile==0.10.3.post1 \ No newline at end of file diff --git a/PyTorch/contrib/audio/deepspeech/README.md b/PyTorch/contrib/audio/deepspeech/README.md index 8e331e8923..dce744d657 100644 --- a/PyTorch/contrib/audio/deepspeech/README.md +++ b/PyTorch/contrib/audio/deepspeech/README.md @@ -1,89 +1,89 @@ - - -# deepspeech.pytorch - -This implements training of deepspeech on NPU mainly modified from [deepspeech.pytorch](https://github.com/SeanNaren/deepspeech.pytorch) - -## installation - -### From Source - -install this fork Warp-CTC bindings: - -```shell -### npu环境变量 -source {deepspeech_root}/scripts/env_new.sh -git clone https://github.com/SeanNaren/warp-ctc.git -cd warp-ctc -git checkout -b pytorch_bindings origin/pytorch_bindings -mkdir build; cd build; cmake ..; make -cd ../pytorch_binding && python3.7 setup.py install -``` - -install requirements - -```shell -pip3 install -r requirements.txt -``` - -If you plan to use Multi-GPU/Multi-node training, you'll need etcd. Below is the command to install on Ubuntu. - -```shell -sudo apt-get install etcd -sudo apt-get install sox -``` - -## Training - -### Download Dataset - -All you need is entering the data directory and execute the follow scripts - -```shell -cd data -python3.7 an4.py -``` - -### Training a Model - -#### 1p training - -```shell -# The result will be placed in the current directory 1p_train.log -bash run_1p.sh -``` - -#### 8p training - -```shell -# The result will be placed in the current directory 8p_train.log -bash run_8p.sh -``` - -### Performance - -```shell -### 1p performance, the log will be placed in the current directory 1p_train_performance.log -bash train_performance_1p.sh -### 8p performance, the log will be placed in the current directory 8p_train_performance.log -bash train_performance_8p.sh -``` - -## Testing/Inference - -To evaluate a trained model on a test set (has to be in the same format as the training set): - -```shell -# if you want to see the final precision, you can execute the follow scripts after execute 1p or 8p training scripts -bash eval.sh -``` - -## Result - -| | WER | CER | Epochs | APEX | FPS | -| :---: | :----: | :----: | :----: | :--: | :--: | -| NPU1P | 9.444 | 5.723 | 70 | O2 | 4 | -| NPU8P | 17.464 | 10.926 | 70 | O2 | 22 | -| GPU1P | 10.349 | 7.076 | 70 | O2 | 94 | -| GPU8P | 15.265 | 9.834 | 70 | O2 | 377 | - + + +# deepspeech.pytorch + +This implements training of deepspeech on NPU mainly modified from [deepspeech.pytorch](https://github.com/SeanNaren/deepspeech.pytorch) + +## installation + +### From Source + +install this fork Warp-CTC bindings: + +```shell +### npu环境变量 +source {deepspeech_root}/scripts/env_new.sh +git clone https://github.com/SeanNaren/warp-ctc.git +cd warp-ctc +git checkout -b pytorch_bindings origin/pytorch_bindings +mkdir build; cd build; cmake ..; make +cd ../pytorch_binding && python3.7 setup.py install +``` + +install requirements + +```shell +pip3 install -r requirements.txt +``` + +If you plan to use Multi-GPU/Multi-node training, you'll need etcd. Below is the command to install on Ubuntu. + +```shell +sudo apt-get install etcd +sudo apt-get install sox +``` + +## Training + +### Download Dataset + +All you need is entering the data directory and execute the follow scripts + +```shell +cd data +python3.7 an4.py +``` + +### Training a Model + +#### 1p training + +```shell +# The result will be placed in the current directory 1p_train.log +bash run_1p.sh +``` + +#### 8p training + +```shell +# The result will be placed in the current directory 8p_train.log +bash run_8p.sh +``` + +### Performance + +```shell +### 1p performance, the log will be placed in the current directory 1p_train_performance.log +bash train_performance_1p.sh +### 8p performance, the log will be placed in the current directory 8p_train_performance.log +bash train_performance_8p.sh +``` + +## Testing/Inference + +To evaluate a trained model on a test set (has to be in the same format as the training set): + +```shell +# if you want to see the final precision, you can execute the follow scripts after execute 1p or 8p training scripts +bash eval.sh +``` + +## Result + +| | WER | CER | Epochs | APEX | FPS | +| :---: | :----: | :----: | :----: | :--: | :--: | +| NPU1P | 9.444 | 5.723 | 70 | O2 | 4 | +| NPU8P | 17.464 | 10.926 | 70 | O2 | 22 | +| GPU1P | 10.349 | 7.076 | 70 | O2 | 94 | +| GPU8P | 15.265 | 9.834 | 70 | O2 | 377 | + diff --git a/PyTorch/contrib/audio/tdnn/README.md b/PyTorch/contrib/audio/tdnn/README.md index 83fd02c3f2..3598158ca6 100644 --- a/PyTorch/contrib/audio/tdnn/README.md +++ b/PyTorch/contrib/audio/tdnn/README.md @@ -1,144 +1,144 @@ - - -## 概述 - -ECAPA-TDNN基于传统TDNN模型进行了改进,主要有三个方面的优化,分别是:增加了一维SE残差模块(1-Dimensional Squeeze-Excitation Res2Block);多层特征融合(Multi-layer feature aggregation and summation);通道和上下文相关的统计池化(Channel- and context-dependent statistics pooling) - - - -- 参考实现: -[https://github.com/speechbrain/speechbrain/tree/develop/templates/speaker_id](https://gitee.com/link?target=https%3A%2F%2Fgithub.com%2Fspeechbrain%2Fspeechbrain%2Ftree%2Fdevelop%2Ftemplates%2Fspeaker_id) - - - - - -## 支持特性 - -| 特性列表 | 是否支持 | -| ---------- | -------- | -| 分布式训练 | 是 | -| 混合精度 | 是 | -| 并行数据 | 是 | - -## 混合精度训练 - -昇腾910 AI处理器提供自动混合精度功能,模型使用 opt_level="O1", loss_scale=128, combine_grad=True的配置进行amp.initialize - -脚本已默认开启混合精度,设置如下。 - - ``` - parser.add_argument( - "--auto_mix_prec", - action="store_true", - help="This flag enables training with automatic mixed-precision.", - ) - ``` - - -

训练环境准备

- -CANN版本:5.0.2 - -昇腾torch版本:1.5.0 - -#### speechbrain环境配置 - -(详情请参考speechbrain官方文档安装方法。) - -1. 安装torch 1.5.0 - -2. 安装torchaudio,npu安装方法请参考 - - https://e.gitee.com/HUAWEI-ASCEND/dashboard?issue=I48AZM - -3. cd tdnn - - pip install -r requirement.txt - - pip install --editable . - - -

快速上手

- -- 数据集准备 - -模型训练使用rirs_noises、train-clean-5数据集,数据集请用户自行获取。 - -- 模型训练 - -选择合适的下载方式下载源码包。 - -Before training, modify the data_folder in these scripts. - -```bash -# training 1p loss -bash ./test/train_full_1p.sh --data_folder="" - -# training 1p performance -bash ./test/train_performance_1p.sh --data_folder="" - -# training 8p loss -bash ./test/train_full_8p.sh --data_folder="" - -# training 8p performance -bash ./test/train_performance_8p.sh --data_folder="" -``` - -``` -Log path: - test/output/train_full_1p.log # 1p training result log - test/output/train_performance_1p.log # 1p training performance result log - test/output/train_full_8p.log # 8p training result log - test/output/train_performance_8p.log # 8p training performance result log -``` - -## 训练结果 - -| acc | FPS | Npu_nums | Epochs | AMP_Type | -| :--------: | :----: | :------: | :----: | :------: | -| - | 8.25 | 1 | 1 | O1 | -| 0.9062 | 43.863 | 8 | 5 | O1 | - -

高级参考

- -### 脚本和示例代码 - -``` -├── README.md //代码说明文档 -├── speechbrain //框架支持文件 -├── templates/speaker_id -│ ├──test //测试脚本 -│ ├──custom_model.py //简易TDNN模块 -| ├──mini_librispeech_prepare.py //数据清单文件 -│ ├──run_1p.sh //单卡运行启动脚本 -│ ├──run_8p.sh //8卡运行启动脚本 -│ ├──train.py //网络训练与测试代码 -│ ├──train.yaml //网络训练参数脚本 -``` - -### 脚本参数 - -``` ---seed 制作参数对象seed ---rank_size 使用NPU卡数量,默认:1 ---number_of_epochs 训练epoch次数,默认:5 ---data_folder 数据集路径,默认:./data ---output_folder 结果输出保存的文件路径,默认:./results/speaker_id/ ---batch_size 每个NPU的batch size,默认:64 -``` - - -## 训练过程 - -1. 通过“模型训练”中的训练指令启动单卡或者多卡训练。单卡和多卡通过运行不同脚本,支持单卡、8卡网络训练。 - -2. 参考脚本的模型存储路径为results//save,训练脚本log中包括如下信息。 - -``` -Epoch: 1, lr: 1.00e-03 - train loss: 2.70 - valid loss: 3.39, valid error: 9.47e-01 -Epoch loaded: 1 - test loss: 3.43, test error: 9.54e-01 -``` -## 注意事项 - + + +## 概述 + +ECAPA-TDNN基于传统TDNN模型进行了改进,主要有三个方面的优化,分别是:增加了一维SE残差模块(1-Dimensional Squeeze-Excitation Res2Block);多层特征融合(Multi-layer feature aggregation and summation);通道和上下文相关的统计池化(Channel- and context-dependent statistics pooling) + + + +- 参考实现: +[https://github.com/speechbrain/speechbrain/tree/develop/templates/speaker_id](https://gitee.com/link?target=https%3A%2F%2Fgithub.com%2Fspeechbrain%2Fspeechbrain%2Ftree%2Fdevelop%2Ftemplates%2Fspeaker_id) + + + + + +## 支持特性 + +| 特性列表 | 是否支持 | +| ---------- | -------- | +| 分布式训练 | 是 | +| 混合精度 | 是 | +| 并行数据 | 是 | + +## 混合精度训练 + +昇腾910 AI处理器提供自动混合精度功能,模型使用 opt_level="O1", loss_scale=128, combine_grad=True的配置进行amp.initialize + +脚本已默认开启混合精度,设置如下。 + + ``` + parser.add_argument( + "--auto_mix_prec", + action="store_true", + help="This flag enables training with automatic mixed-precision.", + ) + ``` + + +

训练环境准备

+ +CANN版本:5.0.2 + +昇腾torch版本:1.5.0 + +#### speechbrain环境配置 + +(详情请参考speechbrain官方文档安装方法。) + +1. 安装torch 1.5.0 + +2. 安装torchaudio,npu安装方法请参考 + + https://e.gitee.com/HUAWEI-ASCEND/dashboard?issue=I48AZM + +3. cd tdnn + + pip install -r requirement.txt + + pip install --editable . + + +

快速上手

+ +- 数据集准备 + +模型训练使用rirs_noises、train-clean-5数据集,数据集请用户自行获取。 + +- 模型训练 + +选择合适的下载方式下载源码包。 + +Before training, modify the data_folder in these scripts. + +```bash +# training 1p loss +bash ./test/train_full_1p.sh --data_folder="" + +# training 1p performance +bash ./test/train_performance_1p.sh --data_folder="" + +# training 8p loss +bash ./test/train_full_8p.sh --data_folder="" + +# training 8p performance +bash ./test/train_performance_8p.sh --data_folder="" +``` + +``` +Log path: + test/output/train_full_1p.log # 1p training result log + test/output/train_performance_1p.log # 1p training performance result log + test/output/train_full_8p.log # 8p training result log + test/output/train_performance_8p.log # 8p training performance result log +``` + +## 训练结果 + +| acc | FPS | Npu_nums | Epochs | AMP_Type | +| :--------: | :----: | :------: | :----: | :------: | +| - | 8.25 | 1 | 1 | O1 | +| 0.9062 | 43.863 | 8 | 5 | O1 | + +

高级参考

+ +### 脚本和示例代码 + +``` +├── README.md //代码说明文档 +├── speechbrain //框架支持文件 +├── templates/speaker_id +│ ├──test //测试脚本 +│ ├──custom_model.py //简易TDNN模块 +| ├──mini_librispeech_prepare.py //数据清单文件 +│ ├──run_1p.sh //单卡运行启动脚本 +│ ├──run_8p.sh //8卡运行启动脚本 +│ ├──train.py //网络训练与测试代码 +│ ├──train.yaml //网络训练参数脚本 +``` + +### 脚本参数 + +``` +--seed 制作参数对象seed +--rank_size 使用NPU卡数量,默认:1 +--number_of_epochs 训练epoch次数,默认:5 +--data_folder 数据集路径,默认:./data +--output_folder 结果输出保存的文件路径,默认:./results/speaker_id/ +--batch_size 每个NPU的batch size,默认:64 +``` + + +## 训练过程 + +1. 通过“模型训练”中的训练指令启动单卡或者多卡训练。单卡和多卡通过运行不同脚本,支持单卡、8卡网络训练。 + +2. 参考脚本的模型存储路径为results//save,训练脚本log中包括如下信息。 + +``` +Epoch: 1, lr: 1.00e-03 - train loss: 2.70 - valid loss: 3.39, valid error: 9.47e-01 +Epoch loaded: 1 - test loss: 3.43, test error: 9.54e-01 +``` +## 注意事项 + **该模型为了固定shape,修改了1、/speechbrain/dataio/dataio.py read_audio函数 2、/speechbrain/templates/speaker_id/train.py prepare_features函数 3、/speechbrain/core.py _train_loader_specifics里的sampler。其中第三个修改是因为数据集不足固定shape,实际使用模型务必还原回去。** \ No newline at end of file diff --git a/PyTorch/contrib/audio/tdnn/modelzoo_level.txt b/PyTorch/contrib/audio/tdnn/modelzoo_level.txt index 484664c239..55a9add9fa 100644 --- a/PyTorch/contrib/audio/tdnn/modelzoo_level.txt +++ b/PyTorch/contrib/audio/tdnn/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:POK \ No newline at end of file diff --git a/PyTorch/contrib/audio/tdnn/speechbrain/lobes/models/MetricGAN.py b/PyTorch/contrib/audio/tdnn/speechbrain/lobes/models/MetricGAN.py index a7af8cccaa..38c2b82d53 100644 --- a/PyTorch/contrib/audio/tdnn/speechbrain/lobes/models/MetricGAN.py +++ b/PyTorch/contrib/audio/tdnn/speechbrain/lobes/models/MetricGAN.py @@ -13,175 +13,175 @@ # limitations under the License. # -"""Generator and discriminator used in MetricGAN - -Authors: -* Szu-Wei Fu 2020 -""" -import torch -import speechbrain as sb -from torch import nn -from torch.nn.utils import spectral_norm - - -def xavier_init_layer( - in_size, out_size=None, spec_norm=True, layer_type=nn.Linear, **kwargs -): - "Create a layer with spectral norm, xavier uniform init and zero bias" - if out_size is None: - out_size = in_size - - layer = layer_type(in_size, out_size, **kwargs) - if spec_norm: - layer = spectral_norm(layer) - - # Perform initialization - nn.init.xavier_uniform_(layer.weight, gain=1.0) - nn.init.zeros_(layer.bias) - - return layer - - -def shifted_sigmoid(x): - return 1.2 / (1 + torch.exp(-(1 / 1.6) * x)) - - -class Learnable_sigmoid(nn.Module): - def __init__(self, in_features=257): - super().__init__() - self.slope = nn.Parameter(torch.ones(in_features)) - self.slope.requiresGrad = True # set requiresGrad to true! - - # self.scale = nn.Parameter(torch.ones(1)) - # self.scale.requiresGrad = True # set requiresGrad to true! - - def forward(self, x): - return 1.2 / (1 + torch.exp(-(self.slope) * x)) - - -class EnhancementGenerator(nn.Module): - """Simple LSTM for enhancement with custom initialization. - - Arguments - --------- - input_size : int - Size of the input tensor's last dimension. - hidden_size : int - Number of neurons to use in the LSTM layers. - num_layers : int - Number of layers to use in the LSTM. - dropout : int - Fraction of neurons to drop during training. - """ - - def __init__( - self, input_size=257, hidden_size=200, num_layers=2, dropout=0, - ): - super().__init__() - self.activation = nn.LeakyReLU(negative_slope=0.3) - - self.blstm = sb.nnet.RNN.LSTM( - input_size=input_size, - hidden_size=hidden_size, - num_layers=num_layers, - dropout=dropout, - bidirectional=True, - ) - """ - Use orthogonal init for recurrent layers, xavier uniform for input layers - Bias is 0 - """ - for name, param in self.blstm.named_parameters(): - if "bias" in name: - nn.init.zeros_(param) - elif "weight_ih" in name: - nn.init.xavier_uniform_(param) - elif "weight_hh" in name: - nn.init.orthogonal_(param) - - self.linear1 = xavier_init_layer(400, 300, spec_norm=False) - self.linear2 = xavier_init_layer(300, 257, spec_norm=False) - - self.Learnable_sigmoid = Learnable_sigmoid() - self.sigmoid = nn.Sigmoid() - - def forward(self, x, lengths): - out, _ = self.blstm(x, lengths=lengths) - - out = self.linear1(out) - out = self.activation(out) - - out = self.linear2(out) - out = self.Learnable_sigmoid(out) - - return out - - -class MetricDiscriminator(nn.Module): - """Metric estimator for enhancement training. - - Consists of: - * four 2d conv layers - * channel averaging - * three linear layers - - Arguments - --------- - kernel_size : tuple - The dimensions of the 2-d kernel used for convolution. - base_channels : int - Number of channels used in each conv layer. - """ - - def __init__( - self, kernel_size=(5, 5), base_channels=15, activation=nn.LeakyReLU, - ): - super().__init__() - - self.activation = activation(negative_slope=0.3) - - self.BN = nn.BatchNorm2d(num_features=2, momentum=0.01) - - self.conv1 = xavier_init_layer( - 2, base_channels, layer_type=nn.Conv2d, kernel_size=kernel_size - ) - self.conv2 = xavier_init_layer( - base_channels, layer_type=nn.Conv2d, kernel_size=kernel_size - ) - self.conv3 = xavier_init_layer( - base_channels, layer_type=nn.Conv2d, kernel_size=kernel_size - ) - self.conv4 = xavier_init_layer( - base_channels, layer_type=nn.Conv2d, kernel_size=kernel_size - ) - - self.Linear1 = xavier_init_layer(base_channels, out_size=50) - self.Linear2 = xavier_init_layer(in_size=50, out_size=10) - self.Linear3 = xavier_init_layer(in_size=10, out_size=1) - - def forward(self, x): - out = self.BN(x) - - out = self.conv1(out) - out = self.activation(out) - - out = self.conv2(out) - out = self.activation(out) - - out = self.conv3(out) - out = self.activation(out) - - out = self.conv4(out) - out = self.activation(out) - - out = torch.mean(out, (2, 3)) - - out = self.Linear1(out) - out = self.activation(out) - - out = self.Linear2(out) - out = self.activation(out) - - out = self.Linear3(out) - - return out +"""Generator and discriminator used in MetricGAN + +Authors: +* Szu-Wei Fu 2020 +""" +import torch +import speechbrain as sb +from torch import nn +from torch.nn.utils import spectral_norm + + +def xavier_init_layer( + in_size, out_size=None, spec_norm=True, layer_type=nn.Linear, **kwargs +): + "Create a layer with spectral norm, xavier uniform init and zero bias" + if out_size is None: + out_size = in_size + + layer = layer_type(in_size, out_size, **kwargs) + if spec_norm: + layer = spectral_norm(layer) + + # Perform initialization + nn.init.xavier_uniform_(layer.weight, gain=1.0) + nn.init.zeros_(layer.bias) + + return layer + + +def shifted_sigmoid(x): + return 1.2 / (1 + torch.exp(-(1 / 1.6) * x)) + + +class Learnable_sigmoid(nn.Module): + def __init__(self, in_features=257): + super().__init__() + self.slope = nn.Parameter(torch.ones(in_features)) + self.slope.requiresGrad = True # set requiresGrad to true! + + # self.scale = nn.Parameter(torch.ones(1)) + # self.scale.requiresGrad = True # set requiresGrad to true! + + def forward(self, x): + return 1.2 / (1 + torch.exp(-(self.slope) * x)) + + +class EnhancementGenerator(nn.Module): + """Simple LSTM for enhancement with custom initialization. + + Arguments + --------- + input_size : int + Size of the input tensor's last dimension. + hidden_size : int + Number of neurons to use in the LSTM layers. + num_layers : int + Number of layers to use in the LSTM. + dropout : int + Fraction of neurons to drop during training. + """ + + def __init__( + self, input_size=257, hidden_size=200, num_layers=2, dropout=0, + ): + super().__init__() + self.activation = nn.LeakyReLU(negative_slope=0.3) + + self.blstm = sb.nnet.RNN.LSTM( + input_size=input_size, + hidden_size=hidden_size, + num_layers=num_layers, + dropout=dropout, + bidirectional=True, + ) + """ + Use orthogonal init for recurrent layers, xavier uniform for input layers + Bias is 0 + """ + for name, param in self.blstm.named_parameters(): + if "bias" in name: + nn.init.zeros_(param) + elif "weight_ih" in name: + nn.init.xavier_uniform_(param) + elif "weight_hh" in name: + nn.init.orthogonal_(param) + + self.linear1 = xavier_init_layer(400, 300, spec_norm=False) + self.linear2 = xavier_init_layer(300, 257, spec_norm=False) + + self.Learnable_sigmoid = Learnable_sigmoid() + self.sigmoid = nn.Sigmoid() + + def forward(self, x, lengths): + out, _ = self.blstm(x, lengths=lengths) + + out = self.linear1(out) + out = self.activation(out) + + out = self.linear2(out) + out = self.Learnable_sigmoid(out) + + return out + + +class MetricDiscriminator(nn.Module): + """Metric estimator for enhancement training. + + Consists of: + * four 2d conv layers + * channel averaging + * three linear layers + + Arguments + --------- + kernel_size : tuple + The dimensions of the 2-d kernel used for convolution. + base_channels : int + Number of channels used in each conv layer. + """ + + def __init__( + self, kernel_size=(5, 5), base_channels=15, activation=nn.LeakyReLU, + ): + super().__init__() + + self.activation = activation(negative_slope=0.3) + + self.BN = nn.BatchNorm2d(num_features=2, momentum=0.01) + + self.conv1 = xavier_init_layer( + 2, base_channels, layer_type=nn.Conv2d, kernel_size=kernel_size + ) + self.conv2 = xavier_init_layer( + base_channels, layer_type=nn.Conv2d, kernel_size=kernel_size + ) + self.conv3 = xavier_init_layer( + base_channels, layer_type=nn.Conv2d, kernel_size=kernel_size + ) + self.conv4 = xavier_init_layer( + base_channels, layer_type=nn.Conv2d, kernel_size=kernel_size + ) + + self.Linear1 = xavier_init_layer(base_channels, out_size=50) + self.Linear2 = xavier_init_layer(in_size=50, out_size=10) + self.Linear3 = xavier_init_layer(in_size=10, out_size=1) + + def forward(self, x): + out = self.BN(x) + + out = self.conv1(out) + out = self.activation(out) + + out = self.conv2(out) + out = self.activation(out) + + out = self.conv3(out) + out = self.activation(out) + + out = self.conv4(out) + out = self.activation(out) + + out = torch.mean(out, (2, 3)) + + out = self.Linear1(out) + out = self.activation(out) + + out = self.Linear2(out) + out = self.activation(out) + + out = self.Linear3(out) + + return out diff --git a/PyTorch/contrib/audio/tdnn/speechbrain/nnet/loss/stoi_loss.py b/PyTorch/contrib/audio/tdnn/speechbrain/nnet/loss/stoi_loss.py index e98acf3a96..96e1fc5583 100644 --- a/PyTorch/contrib/audio/tdnn/speechbrain/nnet/loss/stoi_loss.py +++ b/PyTorch/contrib/audio/tdnn/speechbrain/nnet/loss/stoi_loss.py @@ -13,198 +13,198 @@ # limitations under the License. # -# ################################ -# From paper: "End-to-End Waveform Utterance Enhancement for Direct Evaluation -# Metrics Optimization by Fully Convolutional Neural Networks", TASLP, 2018 -# Authors: Szu-Wei, Fu 2020 -# ################################ - -import torch -import torchaudio -import numpy as np -from speechbrain.utils.torch_audio_backend import get_torchaudio_backend - -torchaudio_backend = get_torchaudio_backend() -torchaudio.set_audio_backend(torchaudio_backend) -smallVal = np.finfo("float").eps # To avoid divide by zero - - -def thirdoct(fs, nfft, num_bands, min_freq): - """Returns the 1/3 octave band matrix. - - Arguments - --------- - fs : int - Sampling rate. - nfft : int - FFT size. - num_bands : int - Number of 1/3 octave bands. - min_freq : int - Center frequency of the lowest 1/3 octave band. - - Returns - ------- - obm : tensor - Octave Band Matrix. - """ - - f = torch.linspace(0, fs, nfft + 1) - f = f[: int(nfft / 2) + 1] - k = torch.from_numpy(np.array(range(num_bands)).astype(float)) - cf = torch.pow(2.0 ** (1.0 / 3), k) * min_freq - freq_low = min_freq * torch.pow(2.0, (2 * k - 1) / 6) - freq_high = min_freq * torch.pow(2.0, (2 * k + 1) / 6) - obm = torch.zeros(num_bands, len(f)) # a verifier - - for i in range(len(cf)): - # Match 1/3 oct band freq with fft frequency bin - f_bin = torch.argmin(torch.square(f - freq_low[i])) - freq_low[i] = f[f_bin] - fl_ii = f_bin - f_bin = torch.argmin(torch.square(f - freq_high[i])) - freq_high[i] = f[f_bin] - fh_ii = f_bin - # Assign to the octave band matrix - obm[i, fl_ii:fh_ii] = 1 - return obm - - -def removeSilentFrames(x, y, dyn_range=40, N=256, K=128): - w = torch.unsqueeze(torch.from_numpy(np.hanning(256)), 0).to(torch.float) - - X1 = x[0 : int(x.shape[0]) // N * N].reshape(int(x.shape[0]) // N, N).T - X2 = ( - x[128 : (int(x.shape[0]) - 128) // N * N + 128] - .reshape((int(x.shape[0]) - 128) // N, N) - .T - ) - X = torch.zeros(N, X1.shape[1] + X2.shape[1]) - X[:, 0::2] = X1 - X[:, 1::2] = X2 - - energy = 20 * torch.log10( - torch.sqrt(torch.matmul(w ** 2, X ** 2)) / 16.0 + smallVal - ) - - Max_energy = torch.max(energy) - msk = torch.squeeze((energy - Max_energy + dyn_range > 0)) - - Y1 = y[0 : int(y.shape[0]) // N * N].reshape(int(y.shape[0]) // N, N).T - Y2 = ( - y[128 : (int(y.shape[0]) - 128) // N * N + 128] - .reshape((int(y.shape[0]) - 128) // N, N) - .T - ) - Y = torch.zeros(N, Y1.shape[1] + Y2.shape[1]) - Y[:, 0::2] = Y1 - Y[:, 1::2] = Y2 - - x_sil = w.T.repeat(1, X[:, msk].shape[-1]) * X[:, msk] - y_sil = w.T.repeat(1, X[:, msk].shape[-1]) * Y[:, msk] - - x_sil = torch.cat( - ( - x_sil[0:128, 0], - (x_sil[0:128, 1:] + x_sil[128:, 0:-1]).T.flatten(), - x_sil[128:256, -1], - ), - axis=0, - ) - y_sil = torch.cat( - ( - y_sil[0:128, 0], - (y_sil[0:128, 1:] + y_sil[128:, 0:-1]).T.flatten(), - y_sil[128:256, -1], - ), - axis=0, - ) - - return [x_sil, y_sil] - - -def stoi_loss(y_pred_batch, y_true_batch, lens, reduction="mean"): - """Compute the STOI score and return -1 * that score. - - This function can be used as a loss function for training - with SGD-based updates. - - Arguments - --------- - y_pred_batch : torch.Tensor - The degraded (enhanced) waveforms. - y_true_batch : torch.Tensor - The clean (reference) waveforms. - lens : torch.Tensor - The relative lengths of the waveforms within the batch. - reduction : str - The type of reduction ("mean" or "batch") to use. - - Example - ------- - >>> a = torch.sin(torch.arange(16000, dtype=torch.float32)).unsqueeze(0) - >>> b = a + 0.001 - >>> -stoi_loss(b, a, torch.ones(1)) - tensor(0.7...) - """ - - y_pred_batch = torch.squeeze(y_pred_batch, dim=-1) - y_true_batch = torch.squeeze(y_true_batch, dim=-1) - - batch_size = y_pred_batch.shape[0] - - fs = 16000 # Sampling rate - N = 30 # length of temporal envelope vectors - J = 15.0 # Number of one-third octave bands - - octave_band = thirdoct(fs=10000, nfft=512, num_bands=15, min_freq=150) - c = 5.62341325 # 10^(-Beta/20) with Beta = -15 - D = torch.zeros(batch_size) - resampler = torchaudio.transforms.Resample(fs, 10000) - for i in range(0, batch_size): # Run over mini-batches - y_true = y_true_batch[i, 0 : int(lens[i] * y_pred_batch.shape[1])] - y_pred = y_pred_batch[i, 0 : int(lens[i] * y_pred_batch.shape[1])] - - y_true, y_pred = resampler(y_true), resampler(y_pred) - - [y_sil_true, y_sil_pred] = removeSilentFrames(y_true, y_pred) - - stft_true = torchaudio.transforms.Spectrogram( - n_fft=512, win_length=256, hop_length=128, power=2 - )(y_sil_true) - stft_pred = torchaudio.transforms.Spectrogram( - n_fft=512, win_length=256, hop_length=128, power=2 - )(y_sil_pred) - - OCT_true = torch.sqrt(torch.matmul(octave_band, stft_true) + 1e-14) - OCT_pred = torch.sqrt(torch.matmul(octave_band, stft_pred) + 1e-14) - - M = int( - stft_pred.shape[-1] - (N - 1) - ) # number of temporal envelope vectors - - X = torch.zeros(15 * M, 30) - Y = torch.zeros(15 * M, 30) - for m in range(0, M): # Run over temporal envelope vectors - X[m * 15 : (m + 1) * 15, :] = OCT_true[:, m : m + N] - Y[m * 15 : (m + 1) * 15, :] = OCT_pred[:, m : m + N] - - alpha = torch.norm(X, dim=-1, keepdim=True) / ( - torch.norm(Y, dim=-1, keepdim=True) + smallVal - ) - - ay = Y * alpha - y = torch.min(ay, X + X * c) - - xn = X - torch.mean(X, dim=-1, keepdim=True) - xn = xn / (torch.norm(xn, dim=-1, keepdim=True) + smallVal) - - yn = y - torch.mean(y, dim=-1, keepdim=True) - yn = yn / (torch.norm(yn, dim=-1, keepdim=True) + smallVal) - d = torch.sum(xn * yn) - D[i] = d / (J * M) - - if reduction == "mean": - return -D.mean() - - return -D +# ################################ +# From paper: "End-to-End Waveform Utterance Enhancement for Direct Evaluation +# Metrics Optimization by Fully Convolutional Neural Networks", TASLP, 2018 +# Authors: Szu-Wei, Fu 2020 +# ################################ + +import torch +import torchaudio +import numpy as np +from speechbrain.utils.torch_audio_backend import get_torchaudio_backend + +torchaudio_backend = get_torchaudio_backend() +torchaudio.set_audio_backend(torchaudio_backend) +smallVal = np.finfo("float").eps # To avoid divide by zero + + +def thirdoct(fs, nfft, num_bands, min_freq): + """Returns the 1/3 octave band matrix. + + Arguments + --------- + fs : int + Sampling rate. + nfft : int + FFT size. + num_bands : int + Number of 1/3 octave bands. + min_freq : int + Center frequency of the lowest 1/3 octave band. + + Returns + ------- + obm : tensor + Octave Band Matrix. + """ + + f = torch.linspace(0, fs, nfft + 1) + f = f[: int(nfft / 2) + 1] + k = torch.from_numpy(np.array(range(num_bands)).astype(float)) + cf = torch.pow(2.0 ** (1.0 / 3), k) * min_freq + freq_low = min_freq * torch.pow(2.0, (2 * k - 1) / 6) + freq_high = min_freq * torch.pow(2.0, (2 * k + 1) / 6) + obm = torch.zeros(num_bands, len(f)) # a verifier + + for i in range(len(cf)): + # Match 1/3 oct band freq with fft frequency bin + f_bin = torch.argmin(torch.square(f - freq_low[i])) + freq_low[i] = f[f_bin] + fl_ii = f_bin + f_bin = torch.argmin(torch.square(f - freq_high[i])) + freq_high[i] = f[f_bin] + fh_ii = f_bin + # Assign to the octave band matrix + obm[i, fl_ii:fh_ii] = 1 + return obm + + +def removeSilentFrames(x, y, dyn_range=40, N=256, K=128): + w = torch.unsqueeze(torch.from_numpy(np.hanning(256)), 0).to(torch.float) + + X1 = x[0 : int(x.shape[0]) // N * N].reshape(int(x.shape[0]) // N, N).T + X2 = ( + x[128 : (int(x.shape[0]) - 128) // N * N + 128] + .reshape((int(x.shape[0]) - 128) // N, N) + .T + ) + X = torch.zeros(N, X1.shape[1] + X2.shape[1]) + X[:, 0::2] = X1 + X[:, 1::2] = X2 + + energy = 20 * torch.log10( + torch.sqrt(torch.matmul(w ** 2, X ** 2)) / 16.0 + smallVal + ) + + Max_energy = torch.max(energy) + msk = torch.squeeze((energy - Max_energy + dyn_range > 0)) + + Y1 = y[0 : int(y.shape[0]) // N * N].reshape(int(y.shape[0]) // N, N).T + Y2 = ( + y[128 : (int(y.shape[0]) - 128) // N * N + 128] + .reshape((int(y.shape[0]) - 128) // N, N) + .T + ) + Y = torch.zeros(N, Y1.shape[1] + Y2.shape[1]) + Y[:, 0::2] = Y1 + Y[:, 1::2] = Y2 + + x_sil = w.T.repeat(1, X[:, msk].shape[-1]) * X[:, msk] + y_sil = w.T.repeat(1, X[:, msk].shape[-1]) * Y[:, msk] + + x_sil = torch.cat( + ( + x_sil[0:128, 0], + (x_sil[0:128, 1:] + x_sil[128:, 0:-1]).T.flatten(), + x_sil[128:256, -1], + ), + axis=0, + ) + y_sil = torch.cat( + ( + y_sil[0:128, 0], + (y_sil[0:128, 1:] + y_sil[128:, 0:-1]).T.flatten(), + y_sil[128:256, -1], + ), + axis=0, + ) + + return [x_sil, y_sil] + + +def stoi_loss(y_pred_batch, y_true_batch, lens, reduction="mean"): + """Compute the STOI score and return -1 * that score. + + This function can be used as a loss function for training + with SGD-based updates. + + Arguments + --------- + y_pred_batch : torch.Tensor + The degraded (enhanced) waveforms. + y_true_batch : torch.Tensor + The clean (reference) waveforms. + lens : torch.Tensor + The relative lengths of the waveforms within the batch. + reduction : str + The type of reduction ("mean" or "batch") to use. + + Example + ------- + >>> a = torch.sin(torch.arange(16000, dtype=torch.float32)).unsqueeze(0) + >>> b = a + 0.001 + >>> -stoi_loss(b, a, torch.ones(1)) + tensor(0.7...) + """ + + y_pred_batch = torch.squeeze(y_pred_batch, dim=-1) + y_true_batch = torch.squeeze(y_true_batch, dim=-1) + + batch_size = y_pred_batch.shape[0] + + fs = 16000 # Sampling rate + N = 30 # length of temporal envelope vectors + J = 15.0 # Number of one-third octave bands + + octave_band = thirdoct(fs=10000, nfft=512, num_bands=15, min_freq=150) + c = 5.62341325 # 10^(-Beta/20) with Beta = -15 + D = torch.zeros(batch_size) + resampler = torchaudio.transforms.Resample(fs, 10000) + for i in range(0, batch_size): # Run over mini-batches + y_true = y_true_batch[i, 0 : int(lens[i] * y_pred_batch.shape[1])] + y_pred = y_pred_batch[i, 0 : int(lens[i] * y_pred_batch.shape[1])] + + y_true, y_pred = resampler(y_true), resampler(y_pred) + + [y_sil_true, y_sil_pred] = removeSilentFrames(y_true, y_pred) + + stft_true = torchaudio.transforms.Spectrogram( + n_fft=512, win_length=256, hop_length=128, power=2 + )(y_sil_true) + stft_pred = torchaudio.transforms.Spectrogram( + n_fft=512, win_length=256, hop_length=128, power=2 + )(y_sil_pred) + + OCT_true = torch.sqrt(torch.matmul(octave_band, stft_true) + 1e-14) + OCT_pred = torch.sqrt(torch.matmul(octave_band, stft_pred) + 1e-14) + + M = int( + stft_pred.shape[-1] - (N - 1) + ) # number of temporal envelope vectors + + X = torch.zeros(15 * M, 30) + Y = torch.zeros(15 * M, 30) + for m in range(0, M): # Run over temporal envelope vectors + X[m * 15 : (m + 1) * 15, :] = OCT_true[:, m : m + N] + Y[m * 15 : (m + 1) * 15, :] = OCT_pred[:, m : m + N] + + alpha = torch.norm(X, dim=-1, keepdim=True) / ( + torch.norm(Y, dim=-1, keepdim=True) + smallVal + ) + + ay = Y * alpha + y = torch.min(ay, X + X * c) + + xn = X - torch.mean(X, dim=-1, keepdim=True) + xn = xn / (torch.norm(xn, dim=-1, keepdim=True) + smallVal) + + yn = y - torch.mean(y, dim=-1, keepdim=True) + yn = yn / (torch.norm(yn, dim=-1, keepdim=True) + smallVal) + d = torch.sum(xn * yn) + D[i] = d / (J * M) + + if reduction == "mean": + return -D.mean() + + return -D diff --git a/PyTorch/contrib/audio/tdnn/templates/speaker_id/mini_librispeech_prepare.py b/PyTorch/contrib/audio/tdnn/templates/speaker_id/mini_librispeech_prepare.py index 7a59d8259d..adb9e51765 100644 --- a/PyTorch/contrib/audio/tdnn/templates/speaker_id/mini_librispeech_prepare.py +++ b/PyTorch/contrib/audio/tdnn/templates/speaker_id/mini_librispeech_prepare.py @@ -13,209 +13,209 @@ # limitations under the License. # -""" -Downloads and creates data manifest files for Mini LibriSpeech (spk-id). -For speaker-id, different sentences of the same speaker must appear in train, -validation, and test sets. In this case, these sets are thus derived from -splitting the original training set intothree chunks. - -Authors: - * Mirco Ravanelli, 2021 -""" - -import os -import json -import shutil -import random -import logging -from speechbrain.utils.data_utils import get_all_files, download_file -from speechbrain.dataio.dataio import read_audio - -logger = logging.getLogger(__name__) -MINILIBRI_TRAIN_URL = "http://www.openslr.org/resources/31/train-clean-5.tar.gz" -SAMPLERATE = 16000 - - -def prepare_mini_librispeech( - data_folder, - save_json_train, - save_json_valid, - save_json_test, - split_ratio=[80, 10, 10], - batch_size=32, -): - """ - Prepares the json files for the Mini Librispeech dataset. - - Downloads the dataset if it is not found in the `data_folder`. - - Arguments - --------- - data_folder : str - Path to the folder where the Mini Librispeech dataset is stored. - save_json_train : str - Path where the train data specification file will be saved. - save_json_valid : str - Path where the validation data specification file will be saved. - save_json_test : str - Path where the test data specification file will be saved. - split_ratio: list - List composed of three integers that sets split ratios for train, valid, - and test sets, respectively. For instance split_ratio=[80, 10, 10] will - assign 80% of the sentences to training, 10% for validation, and 10% - for test. - - Example - ------- - >>> data_folder = '/path/to/mini_librispeech' - >>> prepare_mini_librispeech(data_folder, 'train.json', 'valid.json', 'test.json') - """ - - # Check if this phase is already done (if so, skip it) - - if skip(save_json_train, save_json_valid, save_json_test): - logger.info("Preparation completed in previous run, skipping.") - return - - # If the dataset doesn't exist yet, download it - train_folder = os.path.join(data_folder, "LibriSpeech", "train-clean-5") - if not check_folders(train_folder): - download_mini_librispeech(data_folder) - - # List files and create manifest from list - logger.info( - f"Creating {save_json_train}, {save_json_valid}, and {save_json_test}" - ) - extension = [".flac"] - wav_list = get_all_files(train_folder, match_and=extension) - - # Random split the signal list into train, valid, and test sets. - data_split = split_sets(wav_list, split_ratio, batch_size) - - # Creating json files - create_json(data_split["train"], save_json_train) - create_json(data_split["valid"], save_json_valid) - create_json(data_split["test"], save_json_test) - - -def create_json(wav_list, json_file): - """ - Creates the json file given a list of wav files. - - Arguments - --------- - wav_list : list of str - The list of wav files. - json_file : str - The path of the output json file - """ - # Processing all the wav files in the list - json_dict = {} - for wav_file in wav_list: - - # Reading the signal (to retrieve duration in seconds) - signal = read_audio(wav_file) - duration = signal.shape[0] / SAMPLERATE - - # Manipulate path to get relative path and uttid - path_parts = wav_file.split(os.path.sep) - uttid, _ = os.path.splitext(path_parts[-1]) - relative_path = os.path.join("{data_root}", *path_parts[-5:]) - - # Getting speaker-id from utterance-id - spk_id = uttid.split("-")[0] - - # Create entry for this utterance - json_dict[uttid] = { - "wav": relative_path, - "length": duration, - "spk_id": spk_id, - } - - # Writing the dictionary to the json file - with open(json_file, mode="w") as json_f: - json.dump(json_dict, json_f, indent=2) - - logger.info(f"{json_file} successfully created!") - - -def skip(*filenames): - """ - Detects if the data preparation has been already done. - If the preparation has been done, we can skip it. - - Returns - ------- - bool - if True, the preparation phase can be skipped. - if False, it must be done. - """ - for filename in filenames: - if not os.path.isfile(filename): - return False - return True - - -def check_folders(*folders): - """Returns False if any passed folder does not exist.""" - for folder in folders: - if not os.path.exists(folder): - return False - return True - - -def split_sets(wav_list, split_ratio, batch_size): - """Randomly splits the wav list into training, validation, and test lists. - Note that a better approach is to make sure that all the classes have the - same proportion of samples (e.g, spk01 should have 80% of samples in - training, 10% validation, 10% test, the same for speaker2 etc.). This - is the approach followed in some recipes such as the Voxceleb one. For - simplicity, we here simply split the full list without necessarily respecting - the split ratio within each class. - - Arguments - --------- - wav_lst : list - list of all the signals in the dataset - split_ratio: list - List composed of three integers that sets split ratios for train, valid, - and test sets, respectively. For instance split_ratio=[80, 10, 10] will - assign 80% of the sentences to training, 10% for validation, and 10% - for test. - - Returns - ------ - dictionary containing train, valid, and test splits. - """ - # Random shuffle of the list - random.shuffle(wav_list) - tot_split = sum(split_ratio) - tot_snts = len(wav_list) - data_split = {} - splits = ["train", "valid"] - - # for i, split in enumerate(splits): - # n_snts = int(tot_snts * split_ratio[i] / tot_split) - # data_split[split] = wav_list[0:n_snts] - # del wav_list[0:n_snts] - # data_split["test"] = wav_list - - for i, split in enumerate(splits): - n_snts = int(tot_snts * split_ratio[i] / tot_split // batch_size * batch_size) - data_split[split] = wav_list[0:n_snts] - del wav_list[0:n_snts] - data_split["test"] = wav_list[0:n_snts] - return data_split - - -def download_mini_librispeech(destination): - """Download dataset and unpack it. - - Arguments - --------- - destination : str - Place to put dataset. - """ - train_archive = os.path.join(destination, "train-clean-5.tar.gz") - download_file(MINILIBRI_TRAIN_URL, train_archive) - shutil.unpack_archive(train_archive, destination) +""" +Downloads and creates data manifest files for Mini LibriSpeech (spk-id). +For speaker-id, different sentences of the same speaker must appear in train, +validation, and test sets. In this case, these sets are thus derived from +splitting the original training set intothree chunks. + +Authors: + * Mirco Ravanelli, 2021 +""" + +import os +import json +import shutil +import random +import logging +from speechbrain.utils.data_utils import get_all_files, download_file +from speechbrain.dataio.dataio import read_audio + +logger = logging.getLogger(__name__) +MINILIBRI_TRAIN_URL = "http://www.openslr.org/resources/31/train-clean-5.tar.gz" +SAMPLERATE = 16000 + + +def prepare_mini_librispeech( + data_folder, + save_json_train, + save_json_valid, + save_json_test, + split_ratio=[80, 10, 10], + batch_size=32, +): + """ + Prepares the json files for the Mini Librispeech dataset. + + Downloads the dataset if it is not found in the `data_folder`. + + Arguments + --------- + data_folder : str + Path to the folder where the Mini Librispeech dataset is stored. + save_json_train : str + Path where the train data specification file will be saved. + save_json_valid : str + Path where the validation data specification file will be saved. + save_json_test : str + Path where the test data specification file will be saved. + split_ratio: list + List composed of three integers that sets split ratios for train, valid, + and test sets, respectively. For instance split_ratio=[80, 10, 10] will + assign 80% of the sentences to training, 10% for validation, and 10% + for test. + + Example + ------- + >>> data_folder = '/path/to/mini_librispeech' + >>> prepare_mini_librispeech(data_folder, 'train.json', 'valid.json', 'test.json') + """ + + # Check if this phase is already done (if so, skip it) + + if skip(save_json_train, save_json_valid, save_json_test): + logger.info("Preparation completed in previous run, skipping.") + return + + # If the dataset doesn't exist yet, download it + train_folder = os.path.join(data_folder, "LibriSpeech", "train-clean-5") + if not check_folders(train_folder): + download_mini_librispeech(data_folder) + + # List files and create manifest from list + logger.info( + f"Creating {save_json_train}, {save_json_valid}, and {save_json_test}" + ) + extension = [".flac"] + wav_list = get_all_files(train_folder, match_and=extension) + + # Random split the signal list into train, valid, and test sets. + data_split = split_sets(wav_list, split_ratio, batch_size) + + # Creating json files + create_json(data_split["train"], save_json_train) + create_json(data_split["valid"], save_json_valid) + create_json(data_split["test"], save_json_test) + + +def create_json(wav_list, json_file): + """ + Creates the json file given a list of wav files. + + Arguments + --------- + wav_list : list of str + The list of wav files. + json_file : str + The path of the output json file + """ + # Processing all the wav files in the list + json_dict = {} + for wav_file in wav_list: + + # Reading the signal (to retrieve duration in seconds) + signal = read_audio(wav_file) + duration = signal.shape[0] / SAMPLERATE + + # Manipulate path to get relative path and uttid + path_parts = wav_file.split(os.path.sep) + uttid, _ = os.path.splitext(path_parts[-1]) + relative_path = os.path.join("{data_root}", *path_parts[-5:]) + + # Getting speaker-id from utterance-id + spk_id = uttid.split("-")[0] + + # Create entry for this utterance + json_dict[uttid] = { + "wav": relative_path, + "length": duration, + "spk_id": spk_id, + } + + # Writing the dictionary to the json file + with open(json_file, mode="w") as json_f: + json.dump(json_dict, json_f, indent=2) + + logger.info(f"{json_file} successfully created!") + + +def skip(*filenames): + """ + Detects if the data preparation has been already done. + If the preparation has been done, we can skip it. + + Returns + ------- + bool + if True, the preparation phase can be skipped. + if False, it must be done. + """ + for filename in filenames: + if not os.path.isfile(filename): + return False + return True + + +def check_folders(*folders): + """Returns False if any passed folder does not exist.""" + for folder in folders: + if not os.path.exists(folder): + return False + return True + + +def split_sets(wav_list, split_ratio, batch_size): + """Randomly splits the wav list into training, validation, and test lists. + Note that a better approach is to make sure that all the classes have the + same proportion of samples (e.g, spk01 should have 80% of samples in + training, 10% validation, 10% test, the same for speaker2 etc.). This + is the approach followed in some recipes such as the Voxceleb one. For + simplicity, we here simply split the full list without necessarily respecting + the split ratio within each class. + + Arguments + --------- + wav_lst : list + list of all the signals in the dataset + split_ratio: list + List composed of three integers that sets split ratios for train, valid, + and test sets, respectively. For instance split_ratio=[80, 10, 10] will + assign 80% of the sentences to training, 10% for validation, and 10% + for test. + + Returns + ------ + dictionary containing train, valid, and test splits. + """ + # Random shuffle of the list + random.shuffle(wav_list) + tot_split = sum(split_ratio) + tot_snts = len(wav_list) + data_split = {} + splits = ["train", "valid"] + + # for i, split in enumerate(splits): + # n_snts = int(tot_snts * split_ratio[i] / tot_split) + # data_split[split] = wav_list[0:n_snts] + # del wav_list[0:n_snts] + # data_split["test"] = wav_list + + for i, split in enumerate(splits): + n_snts = int(tot_snts * split_ratio[i] / tot_split // batch_size * batch_size) + data_split[split] = wav_list[0:n_snts] + del wav_list[0:n_snts] + data_split["test"] = wav_list[0:n_snts] + return data_split + + +def download_mini_librispeech(destination): + """Download dataset and unpack it. + + Arguments + --------- + destination : str + Place to put dataset. + """ + train_archive = os.path.join(destination, "train-clean-5.tar.gz") + download_file(MINILIBRI_TRAIN_URL, train_archive) + shutil.unpack_archive(train_archive, destination) diff --git a/PyTorch/contrib/audio/tdnn/templates/speaker_id/modelzoo_level.txt b/PyTorch/contrib/audio/tdnn/templates/speaker_id/modelzoo_level.txt index b8f3c5693d..c7d1879e5e 100644 --- a/PyTorch/contrib/audio/tdnn/templates/speaker_id/modelzoo_level.txt +++ b/PyTorch/contrib/audio/tdnn/templates/speaker_id/modelzoo_level.txt @@ -1,6 +1,6 @@ -GPUStatus:OK -NPUMigrationStatus:OK -FuncStatus:OK -PrecisionStatus:OK -AutoTune:NOK +GPUStatus:OK +NPUMigrationStatus:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:NOK PerfStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/audio/tdnn/templates/speaker_id/test/train_full_8p.sh b/PyTorch/contrib/audio/tdnn/templates/speaker_id/test/train_full_8p.sh index 702c19b5d9..d7f81cce38 100644 --- a/PyTorch/contrib/audio/tdnn/templates/speaker_id/test/train_full_8p.sh +++ b/PyTorch/contrib/audio/tdnn/templates/speaker_id/test/train_full_8p.sh @@ -1,159 +1,159 @@ -##################基础配置参数,需要模型审视修改################## -# 必选字段(必须在此处定义的参数): Network batch_size RANK_SIZE -# 删除之前结果 -rm -rf ../results - -#集合通信参数,不需要修改 -export RANK_SIZE=8 - -# 数据集路径,保持为空,不需要修改 -data_folder="" -#网络名称,同目录名称,需要模型审视修改 -Network="Tdnn" - -#训练batch_size,,需要模型审视修改 -batch_size=64 - -#训练epoch -train_epochs=15 -# 指定训练所使用的npu device卡id -device_id=0 - - -# 参数校验,data_folder为必传参数, 其他参数的增删由模型自身决定;此处若新增参数需在上面有定义并赋值; -for para in $* -do - if [[ $para == --workers* ]];then - workers=`echo ${para#*=}` - elif [[ $para == --data_folder* ]];then - data_folder=`echo ${para#*=}` - fi -done - -# 校验是否传入data_folder,不需要修改 -if [[ $data_folder == "" ]];then - echo "[Error] para \"data_folder\" must be config" - exit 1 -fi - -##################指定训练脚本执行路径################## -# cd到与test文件同层级目录下执行脚本,提高兼容性;test_path_dir为包含test文件夹的路径 -if [ $ASCEND_DEVICE_ID ];then - echo "device id is ${ASCEND_DEVICE_ID}" - ln -s source dest -elif [ ${device_id} ]; then - export ASCEND_DEVICE_ID=${device_id} - echo "device id is ${ASCEND_DEVICE_ID}" -else - echo "[Error] device id must be confing" - exit 1 -fi - - - -#################指定训练脚本执行路径################## -# cd到与test文件同层级目录下执行脚本,提高兼容性;test_path_dir为包含test文件夹的路径 -cur_path=`pwd` -cur_path_last_dirname=${cur_path##*/} -if [ x"${cur_path_last_dirname}" == x"test" ]; then - test_path_dir=${cur_path} - cd .. - cur_path=`pwd` -else - test_path_dir=${cur_path}/test -fi - -##################创建日志输出目录,不需要修改################## -ASCEND_DEVICE_ID=${device_id} -if [ -d ${test_path_dir}/output/$ASCEND_DEVICE_ID ];then - rm -rf ${test_path_dir}/output/$ASCEND_DEVICE_ID - mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID -else - mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID -fi - -##################启动训练脚本################## -# 训练开始时间,不需要修改 -start_time=$(date +%s) -# source 环境变量 -source ${test_path_dir}/env.sh -export WORLD_SIZE=8 -export MASTER_ADDR='127.0.0.1' -export MASTER_PORT='211225' - -for((RANK_ID=0;RANK_ID ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}_full_8p.log 2>&1 & - else - python3.7 train.py train.yaml \ - --distributed_launch \ - --distributed_backend=hccl \ - --local_rank ${RANK_ID} \ - --batch_size=$batch_size \ - --number_of_epochs=$train_epochs \ - --data_folder=$data_folder > ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}_full_8p.log 2>&1 & - fi -done -wait - - -##################获取训练数据################## -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -# 结果打印,不需要修改 -echo "------------------ Final result ------------------" -# 输出性能FPS,需要模型审视修改 -FPS=`grep -a 'FPS' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}_full_8p.log|awk -F " " '{print $NF}'|awk 'END {print}'|cut -d ")" -f1` -# 打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -# 输出训练精度,需要模型审视修改 -train_accuracy=`grep "Epoch loaded:" ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}_full_8p.log|awk -F "test error:" '{print $NF}'|awk '{printf("%0.4f\n",1-$1)}'` -# 打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -# 性能看护结果汇总 -# 训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -# 获取性能数据,不需要修改 -# 吞吐量 -ActualFPS=${FPS} -# 单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -# 从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep "npu id:" ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${ASCEND_DEVICE_ID}_full_8p.log|awk -F "Loss" '{print $NF}' | awk -F " " '{print $1}' >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -# 最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -# 关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log - +##################基础配置参数,需要模型审视修改################## +# 必选字段(必须在此处定义的参数): Network batch_size RANK_SIZE +# 删除之前结果 +rm -rf ../results + +#集合通信参数,不需要修改 +export RANK_SIZE=8 + +# 数据集路径,保持为空,不需要修改 +data_folder="" +#网络名称,同目录名称,需要模型审视修改 +Network="Tdnn" + +#训练batch_size,,需要模型审视修改 +batch_size=64 + +#训练epoch +train_epochs=15 +# 指定训练所使用的npu device卡id +device_id=0 + + +# 参数校验,data_folder为必传参数, 其他参数的增删由模型自身决定;此处若新增参数需在上面有定义并赋值; +for para in $* +do + if [[ $para == --workers* ]];then + workers=`echo ${para#*=}` + elif [[ $para == --data_folder* ]];then + data_folder=`echo ${para#*=}` + fi +done + +# 校验是否传入data_folder,不需要修改 +if [[ $data_folder == "" ]];then + echo "[Error] para \"data_folder\" must be config" + exit 1 +fi + +##################指定训练脚本执行路径################## +# cd到与test文件同层级目录下执行脚本,提高兼容性;test_path_dir为包含test文件夹的路径 +if [ $ASCEND_DEVICE_ID ];then + echo "device id is ${ASCEND_DEVICE_ID}" + ln -s source dest +elif [ ${device_id} ]; then + export ASCEND_DEVICE_ID=${device_id} + echo "device id is ${ASCEND_DEVICE_ID}" +else + echo "[Error] device id must be confing" + exit 1 +fi + + + +#################指定训练脚本执行路径################## +# cd到与test文件同层级目录下执行脚本,提高兼容性;test_path_dir为包含test文件夹的路径 +cur_path=`pwd` +cur_path_last_dirname=${cur_path##*/} +if [ x"${cur_path_last_dirname}" == x"test" ]; then + test_path_dir=${cur_path} + cd .. + cur_path=`pwd` +else + test_path_dir=${cur_path}/test +fi + +##################创建日志输出目录,不需要修改################## +ASCEND_DEVICE_ID=${device_id} +if [ -d ${test_path_dir}/output/$ASCEND_DEVICE_ID ];then + rm -rf ${test_path_dir}/output/$ASCEND_DEVICE_ID + mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID +else + mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID +fi + +##################启动训练脚本################## +# 训练开始时间,不需要修改 +start_time=$(date +%s) +# source 环境变量 +source ${test_path_dir}/env.sh +export WORLD_SIZE=8 +export MASTER_ADDR='127.0.0.1' +export MASTER_PORT='211225' + +for((RANK_ID=0;RANK_ID ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}_full_8p.log 2>&1 & + else + python3.7 train.py train.yaml \ + --distributed_launch \ + --distributed_backend=hccl \ + --local_rank ${RANK_ID} \ + --batch_size=$batch_size \ + --number_of_epochs=$train_epochs \ + --data_folder=$data_folder > ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}_full_8p.log 2>&1 & + fi +done +wait + + +##################获取训练数据################## +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +# 结果打印,不需要修改 +echo "------------------ Final result ------------------" +# 输出性能FPS,需要模型审视修改 +FPS=`grep -a 'FPS' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}_full_8p.log|awk -F " " '{print $NF}'|awk 'END {print}'|cut -d ")" -f1` +# 打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +# 输出训练精度,需要模型审视修改 +train_accuracy=`grep "Epoch loaded:" ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}_full_8p.log|awk -F "test error:" '{print $NF}'|awk '{printf("%0.4f\n",1-$1)}'` +# 打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +# 性能看护结果汇总 +# 训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +# 获取性能数据,不需要修改 +# 吞吐量 +ActualFPS=${FPS} +# 单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +# 从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep "npu id:" ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${ASCEND_DEVICE_ID}_full_8p.log|awk -F "Loss" '{print $NF}' | awk -F " " '{print $1}' >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +# 最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +# 关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log + diff --git a/PyTorch/contrib/audio/tdnn/templates/speaker_id/test/train_performance_8p.sh b/PyTorch/contrib/audio/tdnn/templates/speaker_id/test/train_performance_8p.sh index 3d8549d6cf..94bd08c5ac 100644 --- a/PyTorch/contrib/audio/tdnn/templates/speaker_id/test/train_performance_8p.sh +++ b/PyTorch/contrib/audio/tdnn/templates/speaker_id/test/train_performance_8p.sh @@ -1,154 +1,154 @@ -##################基础配置参数,需要模型审视修改################## -# 必选字段(必须在此处定义的参数): Network batch_size RANK_SIZE -# 删除之前结果 -rm -rf ../results - -#集合通信参数,不需要修改 -export RANK_SIZE=8 - -# 数据集路径,保持为空,不需要修改 -data_folder="" -#网络名称,同目录名称,需要模型审视修改 -Network="Tdnn" - -#训练batch_size,,需要模型审视修改 -batch_size=64 - -#训练epoch -train_epochs=2 -# 指定训练所使用的npu device卡id -device_id=0 - - -# 参数校验,data_folder为必传参数, 其他参数的增删由模型自身决定;此处若新增参数需在上面有定义并赋值; -for para in $* -do - if [[ $para == --workers* ]];then - workers=`echo ${para#*=}` - elif [[ $para == --data_folder* ]];then - data_folder=`echo ${para#*=}` - fi -done - -# 校验是否传入data_folder,不需要修改 -if [[ $data_folder == "" ]];then - echo "[Error] para \"data_folder\" must be config" - exit 1 -fi - -##################指定训练脚本执行路径################## -# cd到与test文件同层级目录下执行脚本,提高兼容性;test_path_dir为包含test文件夹的路径 -if [ $ASCEND_DEVICE_ID ];then - echo "device id is ${ASCEND_DEVICE_ID}" - ln -s source dest -elif [ ${device_id} ]; then - export ASCEND_DEVICE_ID=${device_id} - echo "device id is ${ASCEND_DEVICE_ID}" -else - echo "[Error] device id must be confing" - exit 1 -fi - - - -#################指定训练脚本执行路径################## -# cd到与test文件同层级目录下执行脚本,提高兼容性;test_path_dir为包含test文件夹的路径 -cur_path=`pwd` -cur_path_last_dirname=${cur_path##*/} -if [ x"${cur_path_last_dirname}" == x"test" ]; then - test_path_dir=${cur_path} - cd .. - cur_path=`pwd` -else - test_path_dir=${cur_path}/test -fi - -##################创建日志输出目录,不需要修改################## -ASCEND_DEVICE_ID=${device_id} -if [ -d ${test_path_dir}/output/$ASCEND_DEVICE_ID ];then - rm -rf ${test_path_dir}/output/$ASCEND_DEVICE_ID - mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID -else - mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID -fi - -##################启动训练脚本################## -# 训练开始时间,不需要修改 -start_time=$(date +%s) -# source 环境变量 -source ${test_path_dir}/env.sh -export WORLD_SIZE=8 -export MASTER_ADDR='127.0.0.1' -export MASTER_PORT='211225' - -for((RANK_ID=0;RANK_ID ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}_perf_8p.log 2>&1 & - else - python3.7 train.py train.yaml \ - --distributed_launch \ - --distributed_backend=hccl \ - --local_rank ${RANK_ID} \ - --batch_size=$batch_size \ - --number_of_epochs=$train_epochs \ - --data_folder=$data_folder > ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}_perf_8p.log 2>&1 & - fi -done -wait - - -##################获取训练数据################## -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -# 结果打印,不需要修改 -echo "------------------ Final result ------------------" -# 输出性能FPS,需要模型审视修改 -FPS=`grep -a 'FPS' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}_perf_8p.log|awk -F "(" '{print $NF}'|awk 'END {print}'|cut -d ")" -f1` -# 打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -echo "E2E Training Duration sec : $e2e_time" - -# 性能看护结果汇总 -# 训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -# 获取性能数据,不需要修改 -# 吞吐量 -ActualFPS=${FPS} -# 单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -# 从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep "npu id:" ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${ASCEND_DEVICE_ID}_perf_8p.log|awk -F "Loss" '{print $NF}' | awk -F " " '{print $1}' >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -# 最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -# 关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log - +##################基础配置参数,需要模型审视修改################## +# 必选字段(必须在此处定义的参数): Network batch_size RANK_SIZE +# 删除之前结果 +rm -rf ../results + +#集合通信参数,不需要修改 +export RANK_SIZE=8 + +# 数据集路径,保持为空,不需要修改 +data_folder="" +#网络名称,同目录名称,需要模型审视修改 +Network="Tdnn" + +#训练batch_size,,需要模型审视修改 +batch_size=64 + +#训练epoch +train_epochs=2 +# 指定训练所使用的npu device卡id +device_id=0 + + +# 参数校验,data_folder为必传参数, 其他参数的增删由模型自身决定;此处若新增参数需在上面有定义并赋值; +for para in $* +do + if [[ $para == --workers* ]];then + workers=`echo ${para#*=}` + elif [[ $para == --data_folder* ]];then + data_folder=`echo ${para#*=}` + fi +done + +# 校验是否传入data_folder,不需要修改 +if [[ $data_folder == "" ]];then + echo "[Error] para \"data_folder\" must be config" + exit 1 +fi + +##################指定训练脚本执行路径################## +# cd到与test文件同层级目录下执行脚本,提高兼容性;test_path_dir为包含test文件夹的路径 +if [ $ASCEND_DEVICE_ID ];then + echo "device id is ${ASCEND_DEVICE_ID}" + ln -s source dest +elif [ ${device_id} ]; then + export ASCEND_DEVICE_ID=${device_id} + echo "device id is ${ASCEND_DEVICE_ID}" +else + echo "[Error] device id must be confing" + exit 1 +fi + + + +#################指定训练脚本执行路径################## +# cd到与test文件同层级目录下执行脚本,提高兼容性;test_path_dir为包含test文件夹的路径 +cur_path=`pwd` +cur_path_last_dirname=${cur_path##*/} +if [ x"${cur_path_last_dirname}" == x"test" ]; then + test_path_dir=${cur_path} + cd .. + cur_path=`pwd` +else + test_path_dir=${cur_path}/test +fi + +##################创建日志输出目录,不需要修改################## +ASCEND_DEVICE_ID=${device_id} +if [ -d ${test_path_dir}/output/$ASCEND_DEVICE_ID ];then + rm -rf ${test_path_dir}/output/$ASCEND_DEVICE_ID + mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID +else + mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID +fi + +##################启动训练脚本################## +# 训练开始时间,不需要修改 +start_time=$(date +%s) +# source 环境变量 +source ${test_path_dir}/env.sh +export WORLD_SIZE=8 +export MASTER_ADDR='127.0.0.1' +export MASTER_PORT='211225' + +for((RANK_ID=0;RANK_ID ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}_perf_8p.log 2>&1 & + else + python3.7 train.py train.yaml \ + --distributed_launch \ + --distributed_backend=hccl \ + --local_rank ${RANK_ID} \ + --batch_size=$batch_size \ + --number_of_epochs=$train_epochs \ + --data_folder=$data_folder > ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}_perf_8p.log 2>&1 & + fi +done +wait + + +##################获取训练数据################## +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +# 结果打印,不需要修改 +echo "------------------ Final result ------------------" +# 输出性能FPS,需要模型审视修改 +FPS=`grep -a 'FPS' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}_perf_8p.log|awk -F "(" '{print $NF}'|awk 'END {print}'|cut -d ")" -f1` +# 打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +echo "E2E Training Duration sec : $e2e_time" + +# 性能看护结果汇总 +# 训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +# 获取性能数据,不需要修改 +# 吞吐量 +ActualFPS=${FPS} +# 单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +# 从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep "npu id:" ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${ASCEND_DEVICE_ID}_perf_8p.log|awk -F "Loss" '{print $NF}' | awk -F " " '{print $1}' >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +# 最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +# 关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log + diff --git a/PyTorch/contrib/cv/classification/3d_attention_net/train.py b/PyTorch/contrib/cv/classification/3d_attention_net/train.py index fa3c278640..30cb7368f2 100644 --- a/PyTorch/contrib/cv/classification/3d_attention_net/train.py +++ b/PyTorch/contrib/cv/classification/3d_attention_net/train.py @@ -1,236 +1,236 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 print_function, division -from apex import amp -from apex.optimizers import NpuFusedSGD -import torch -import argparse -import torch.nn as nn -import torch.optim as optim -from torch.autograd import Variable -from torch.utils.data import Dataset, DataLoader -import numpy as np -import torchvision -from torchvision import transforms, datasets, models -import os -import cv2 -import time -import torch.npu -import torch.utils.data.distributed -from collections import OrderedDict -from torch.nn.parallel import DistributedDataParallel -from model.residual_attention_network import ResidualAttentionModel_92_32input_update as ResidualAttentionModel - -device = None -args = None -log_file = None - -def parse_args(): - parser = argparse.ArgumentParser(description='3D Attention Net') - parser.add_argument('--device_type', type=str) - parser.add_argument('--device_id', type=int) - parser.add_argument('--device_num', type=int) - parser.add_argument('--total_epochs', type=int) - parser.add_argument('--is_train', type=str) - parser.add_argument('--is_pretrain', type=str) - parser.add_argument('--num_classes', type=int) - parser.add_argument('--dist_url', type=str) - parser.add_argument('--train_batch_size', type=int) - parser.add_argument('--test_batch_size', type=int) - args = parser.parse_args() - return args - -# for test -def test(model, test_loader): - # Test - classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck') - model.eval() - correct = 0 - total = 0 - class_correct = list(0. for i in range(10)) - class_total = list(0. for i in range(10)) - - for images, labels in test_loader: - images = Variable(images.to(device)) - labels = Variable(labels.to(device)) - outputs = model(images) - _, predicted = torch.max(outputs.data, 1) - total += labels.size(0) - correct += (predicted == labels.data).sum() - c = (predicted == labels.data).squeeze() - for i in range(len(labels.data)): - label = labels.data[i] - class_correct[label] += c[i] - class_total[label] += 1 - if args.device_id == 0: - print(f"Accuracy of the model(on device: {args.device_id}) on the test images: {100 * float(correct) / total} %") - write_log('Accuracy of the model on the test images: %d %%\n' % (100 * float(correct) / total)) - write_log(f'Accuracy of the model on the test images: {float(correct)/total} \n') - return float(correct) / total - -def write_log(output): - if log_file is not None: - log_file.write(output) - - -def main(): - global args - global device - args = parse_args() - print(args) - model_file = 'model_92_sgd.pkl' - train_batch_size = args.train_batch_size - test_batch_size = args.test_batch_size - lr = 0.1 - is_train = args.is_train == "True" - is_pretrain = args.is_pretrain == "True" - acc_best = 0 - total_epoch = args.total_epochs - distribute = args.device_num > 1 - if(args.device_type == "GPU"): - device = torch.device("cuda", args.device_id) - if distribute: - torch.cuda.set_device(args.device_id) - torch.distributed.init_process_group(backend="nccl", init_method=args.dist_url, world_size=args.device_num, rank=args.device_id) - else: - device = f"npu:{args.device_id}" - if distribute: - os.environ['MASTER_ADDR'] = '127.0.0.1' - os.environ['MASTER_PORT'] = '49876' - torch.npu.set_device(device) - print("rank:",args.device_id) - torch.distributed.init_process_group(backend="hccl", world_size=args.device_num, rank=args.device_id) - - # Image Preprocessing - transform = transforms.Compose([ - transforms.RandomHorizontalFlip(), - transforms.RandomCrop((32, 32), padding=4), - transforms.ToTensor() - ]) - test_transform = transforms.Compose([ - transforms.ToTensor() - ]) - - train_dataset = datasets.CIFAR10(root='./data/', train=True, transform=transform, download=False) - test_dataset = datasets.CIFAR10(root='./data/', train=False, transform=test_transform) - train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset) if distribute else None - train_loader = torch.utils.data.DataLoader(dataset=train_dataset, \ - batch_size=train_batch_size, \ - shuffle=(train_sampler is None), \ - num_workers=8, \ - pin_memory=False, \ - sampler = train_sampler if is_train else None, \ - drop_last = True) - test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=test_batch_size, shuffle=False) - - model = ResidualAttentionModel(args.num_classes).to(device) - criterion = nn.CrossEntropyLoss().to(device) - optimizer = None - if args.device_type == "GPU": - optimizer = optim.SGD(model.parameters(), lr=lr, momentum=0.9, nesterov=True, weight_decay=0.0001) - else: - optimizer = NpuFusedSGD(model.parameters(), lr=lr, momentum=0.9, nesterov=True, weight_decay=0.0001) - model, optimizer = amp.initialize(model, optimizer, opt_level="O2", loss_scale=128.0) - if distribute: - if args.device_type == "GPU": - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.device_id]) - else: - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.device_id], broadcast_buffers=False) - global log_file - if args.device_id == 0: - log_file = open("train_log_file" if is_train else "test_log_file", mode="w+") - if is_train is True: - if is_pretrain == True: - base_weights = torch.load(model_file, map_location="cpu") - print('Loading base network...') - new_state_dict = OrderedDict() - for k, v in base_weights.items(): - if(k[0: 7] == "module."): - name = k[7:] - else: - name = k[0:] - new_state_dict[name] = v - if "fc.weight" in new_state_dict: - print("pop fc layer weight") - new_state_dict.pop("fc.weight") - new_state_dict.pop("fc.bias") - model.load_state_dict(new_state_dict, strict=False) - - # Training - total_tims = 0 - total_samples = 0 - for epoch in range(total_epoch): - model.train() - tims = time.time() - epoch_samples = 0 - if train_sampler is not None: # is distributed - train_sampler.set_epoch(epoch) - for i, (images, labels) in enumerate(train_loader): - epoch_samples += images.shape[0] - if i == 5: - tims = time.time() - images = Variable(images.to(device)) - labels = Variable(labels.to(device)) - - # Forward + Backward + Optimize - optimizer.zero_grad() - outputs = model(images) - loss = criterion(outputs, labels) - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - optimizer.step() - - if (i+1) % 20 == 0 and args.device_id == 0: - print("Epoch [%d/%d], Iter [%d/%d] Loss: %.4f" %(epoch+1, total_epoch, i+1, len(train_loader), loss.item())) - write_log("Epoch [%d/%d], Iter [%d/%d] Loss: %.4f \n" %(epoch+1, total_epoch, i+1, len(train_loader), loss.item())) - total_tims += time.time() - tims - total_samples += epoch_samples - if args.device_id == 0: - print(f'the epoch {epoch+1} takes time:',time.time()-tims) - print(f"epoch {epoch+1} FPS: {(epoch_samples - 5 * train_batch_size)* args.device_num / (time.time()-tims)}") - print('evaluate test set:') - write_log(f'the epoch {epoch+1} takes time: {time.time()-tims} \n') - write_log(f"epoch {epoch+1} FPS: {(epoch_samples - 5 * train_batch_size)* args.device_num / (time.time()-tims)} \n") - acc = test(model, test_loader) - if acc > acc_best: - acc_best = acc - print('current best acc,', acc_best) - if args.device_id == 0: - torch.save(model.state_dict(), model_file) - # Decaying Learning Rate - if (epoch+1) / float(total_epoch) == 0.3 or (epoch+1) / float(total_epoch) == 0.6 or (epoch+1) / float(total_epoch) == 0.9: - lr /= 10 - print('reset learning rate to:', lr) - for param_group in optimizer.param_groups: - param_group['lr'] = lr - print(param_group['lr']) - # Save the Model - if args.device_id == 0: - torch.save(model.state_dict(), 'last_model_92_sgd.pkl') - elif args.device_id == 0: - base_weights = torch.load(model_file, map_location="cpu") - print('Loading base network...') - new_state_dict = OrderedDict() - for k, v in base_weights.items(): - if(k[0: 7] == "module."): - name = k[7:] - else: - name = k[0:] - new_state_dict[name] = v - model.load_state_dict(new_state_dict) - test(model, test_loader) - -if __name__ == "__main__": - main() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 print_function, division +from apex import amp +from apex.optimizers import NpuFusedSGD +import torch +import argparse +import torch.nn as nn +import torch.optim as optim +from torch.autograd import Variable +from torch.utils.data import Dataset, DataLoader +import numpy as np +import torchvision +from torchvision import transforms, datasets, models +import os +import cv2 +import time +import torch.npu +import torch.utils.data.distributed +from collections import OrderedDict +from torch.nn.parallel import DistributedDataParallel +from model.residual_attention_network import ResidualAttentionModel_92_32input_update as ResidualAttentionModel + +device = None +args = None +log_file = None + +def parse_args(): + parser = argparse.ArgumentParser(description='3D Attention Net') + parser.add_argument('--device_type', type=str) + parser.add_argument('--device_id', type=int) + parser.add_argument('--device_num', type=int) + parser.add_argument('--total_epochs', type=int) + parser.add_argument('--is_train', type=str) + parser.add_argument('--is_pretrain', type=str) + parser.add_argument('--num_classes', type=int) + parser.add_argument('--dist_url', type=str) + parser.add_argument('--train_batch_size', type=int) + parser.add_argument('--test_batch_size', type=int) + args = parser.parse_args() + return args + +# for test +def test(model, test_loader): + # Test + classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck') + model.eval() + correct = 0 + total = 0 + class_correct = list(0. for i in range(10)) + class_total = list(0. for i in range(10)) + + for images, labels in test_loader: + images = Variable(images.to(device)) + labels = Variable(labels.to(device)) + outputs = model(images) + _, predicted = torch.max(outputs.data, 1) + total += labels.size(0) + correct += (predicted == labels.data).sum() + c = (predicted == labels.data).squeeze() + for i in range(len(labels.data)): + label = labels.data[i] + class_correct[label] += c[i] + class_total[label] += 1 + if args.device_id == 0: + print(f"Accuracy of the model(on device: {args.device_id}) on the test images: {100 * float(correct) / total} %") + write_log('Accuracy of the model on the test images: %d %%\n' % (100 * float(correct) / total)) + write_log(f'Accuracy of the model on the test images: {float(correct)/total} \n') + return float(correct) / total + +def write_log(output): + if log_file is not None: + log_file.write(output) + + +def main(): + global args + global device + args = parse_args() + print(args) + model_file = 'model_92_sgd.pkl' + train_batch_size = args.train_batch_size + test_batch_size = args.test_batch_size + lr = 0.1 + is_train = args.is_train == "True" + is_pretrain = args.is_pretrain == "True" + acc_best = 0 + total_epoch = args.total_epochs + distribute = args.device_num > 1 + if(args.device_type == "GPU"): + device = torch.device("cuda", args.device_id) + if distribute: + torch.cuda.set_device(args.device_id) + torch.distributed.init_process_group(backend="nccl", init_method=args.dist_url, world_size=args.device_num, rank=args.device_id) + else: + device = f"npu:{args.device_id}" + if distribute: + os.environ['MASTER_ADDR'] = '127.0.0.1' + os.environ['MASTER_PORT'] = '49876' + torch.npu.set_device(device) + print("rank:",args.device_id) + torch.distributed.init_process_group(backend="hccl", world_size=args.device_num, rank=args.device_id) + + # Image Preprocessing + transform = transforms.Compose([ + transforms.RandomHorizontalFlip(), + transforms.RandomCrop((32, 32), padding=4), + transforms.ToTensor() + ]) + test_transform = transforms.Compose([ + transforms.ToTensor() + ]) + + train_dataset = datasets.CIFAR10(root='./data/', train=True, transform=transform, download=False) + test_dataset = datasets.CIFAR10(root='./data/', train=False, transform=test_transform) + train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset) if distribute else None + train_loader = torch.utils.data.DataLoader(dataset=train_dataset, \ + batch_size=train_batch_size, \ + shuffle=(train_sampler is None), \ + num_workers=8, \ + pin_memory=False, \ + sampler = train_sampler if is_train else None, \ + drop_last = True) + test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=test_batch_size, shuffle=False) + + model = ResidualAttentionModel(args.num_classes).to(device) + criterion = nn.CrossEntropyLoss().to(device) + optimizer = None + if args.device_type == "GPU": + optimizer = optim.SGD(model.parameters(), lr=lr, momentum=0.9, nesterov=True, weight_decay=0.0001) + else: + optimizer = NpuFusedSGD(model.parameters(), lr=lr, momentum=0.9, nesterov=True, weight_decay=0.0001) + model, optimizer = amp.initialize(model, optimizer, opt_level="O2", loss_scale=128.0) + if distribute: + if args.device_type == "GPU": + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.device_id]) + else: + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.device_id], broadcast_buffers=False) + global log_file + if args.device_id == 0: + log_file = open("train_log_file" if is_train else "test_log_file", mode="w+") + if is_train is True: + if is_pretrain == True: + base_weights = torch.load(model_file, map_location="cpu") + print('Loading base network...') + new_state_dict = OrderedDict() + for k, v in base_weights.items(): + if(k[0: 7] == "module."): + name = k[7:] + else: + name = k[0:] + new_state_dict[name] = v + if "fc.weight" in new_state_dict: + print("pop fc layer weight") + new_state_dict.pop("fc.weight") + new_state_dict.pop("fc.bias") + model.load_state_dict(new_state_dict, strict=False) + + # Training + total_tims = 0 + total_samples = 0 + for epoch in range(total_epoch): + model.train() + tims = time.time() + epoch_samples = 0 + if train_sampler is not None: # is distributed + train_sampler.set_epoch(epoch) + for i, (images, labels) in enumerate(train_loader): + epoch_samples += images.shape[0] + if i == 5: + tims = time.time() + images = Variable(images.to(device)) + labels = Variable(labels.to(device)) + + # Forward + Backward + Optimize + optimizer.zero_grad() + outputs = model(images) + loss = criterion(outputs, labels) + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + optimizer.step() + + if (i+1) % 20 == 0 and args.device_id == 0: + print("Epoch [%d/%d], Iter [%d/%d] Loss: %.4f" %(epoch+1, total_epoch, i+1, len(train_loader), loss.item())) + write_log("Epoch [%d/%d], Iter [%d/%d] Loss: %.4f \n" %(epoch+1, total_epoch, i+1, len(train_loader), loss.item())) + total_tims += time.time() - tims + total_samples += epoch_samples + if args.device_id == 0: + print(f'the epoch {epoch+1} takes time:',time.time()-tims) + print(f"epoch {epoch+1} FPS: {(epoch_samples - 5 * train_batch_size)* args.device_num / (time.time()-tims)}") + print('evaluate test set:') + write_log(f'the epoch {epoch+1} takes time: {time.time()-tims} \n') + write_log(f"epoch {epoch+1} FPS: {(epoch_samples - 5 * train_batch_size)* args.device_num / (time.time()-tims)} \n") + acc = test(model, test_loader) + if acc > acc_best: + acc_best = acc + print('current best acc,', acc_best) + if args.device_id == 0: + torch.save(model.state_dict(), model_file) + # Decaying Learning Rate + if (epoch+1) / float(total_epoch) == 0.3 or (epoch+1) / float(total_epoch) == 0.6 or (epoch+1) / float(total_epoch) == 0.9: + lr /= 10 + print('reset learning rate to:', lr) + for param_group in optimizer.param_groups: + param_group['lr'] = lr + print(param_group['lr']) + # Save the Model + if args.device_id == 0: + torch.save(model.state_dict(), 'last_model_92_sgd.pkl') + elif args.device_id == 0: + base_weights = torch.load(model_file, map_location="cpu") + print('Loading base network...') + new_state_dict = OrderedDict() + for k, v in base_weights.items(): + if(k[0: 7] == "module."): + name = k[7:] + else: + name = k[0:] + new_state_dict[name] = v + model.load_state_dict(new_state_dict) + test(model, test_loader) + +if __name__ == "__main__": + main() diff --git a/PyTorch/contrib/cv/classification/AlignedReID/modelzoo_level.txt b/PyTorch/contrib/cv/classification/AlignedReID/modelzoo_level.txt index 9e95396651..27e6c78b37 100644 --- a/PyTorch/contrib/cv/classification/AlignedReID/modelzoo_level.txt +++ b/PyTorch/contrib/cv/classification/AlignedReID/modelzoo_level.txt @@ -1,4 +1,4 @@ -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:POK \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/Deit_Small/mixup.py b/PyTorch/contrib/cv/classification/Deit_Small/mixup.py index 3e3b35b157..dbc166e4f5 100644 --- a/PyTorch/contrib/cv/classification/Deit_Small/mixup.py +++ b/PyTorch/contrib/cv/classification/Deit_Small/mixup.py @@ -1,330 +1,330 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ -""" Mixup and Cutmix - -Papers: -mixup: Beyond Empirical Risk Minimization (https://arxiv.org/abs/1710.09412) - -CutMix: Regularization Strategy to Train Strong Classifiers with Localizable Features (https://arxiv.org/abs/1905.04899) - -Code Reference: -CutMix: https://github.com/clovaai/CutMix-PyTorch - -Hacked together by / Copyright 2020 Ross Wightman -""" -import numpy as np -import torch - - -def one_hot(x, num_classes, on_value=1., off_value=0., device='cuda'): - x = x.long().view(-1, 1) - return torch.full((x.size()[0], num_classes), off_value, device=device).scatter_(1, x, on_value) - - -def mixup_target(target, num_classes, lam=1., smoothing=0.0, device='cuda'): - off_value = smoothing / num_classes - on_value = 1. - smoothing + off_value - y1 = one_hot(target, num_classes, on_value=on_value, off_value=off_value, device=device) - y2 = one_hot(target.flip(0), num_classes, on_value=on_value, off_value=off_value, device=device) - return y1 * lam + y2 * (1. - lam) - - -def rand_bbox(img_shape, lam, margin=0., count=None): - """ Standard CutMix bounding-box - Generates a random square bbox based on lambda value. This impl includes - support for enforcing a border margin as percent of bbox dimensions. - - Args: - img_shape (tuple): Image shape as tuple - lam (float): Cutmix lambda value - margin (float): Percentage of bbox dimension to enforce as margin (reduce amount of box outside image) - count (int): Number of bbox to generate - """ - ratio = np.sqrt(1 - lam) - img_h, img_w = img_shape[-2:] - cut_h, cut_w = int(img_h * ratio), int(img_w * ratio) - margin_y, margin_x = int(margin * cut_h), int(margin * cut_w) - cy = np.random.randint(0 + margin_y, img_h - margin_y, size=count) - cx = np.random.randint(0 + margin_x, img_w - margin_x, size=count) - yl = np.clip(cy - cut_h // 2, 0, img_h) - yh = np.clip(cy + cut_h // 2, 0, img_h) - xl = np.clip(cx - cut_w // 2, 0, img_w) - xh = np.clip(cx + cut_w // 2, 0, img_w) - return yl, yh, xl, xh - - -def rand_bbox_minmax(img_shape, minmax, count=None): - """ Min-Max CutMix bounding-box - Inspired by Darknet cutmix impl, generates a random rectangular bbox - based on min/max percent values applied to each dimension of the input image. - - Typical defaults for minmax are usually in the .2-.3 for min and .8-.9 range for max. - - Args: - img_shape (tuple): Image shape as tuple - minmax (tuple or list): Min and max bbox ratios (as percent of image size) - count (int): Number of bbox to generate - """ - assert len(minmax) == 2 - img_h, img_w = img_shape[-2:] - cut_h = np.random.randint(int(img_h * minmax[0]), int(img_h * minmax[1]), size=count) - cut_w = np.random.randint(int(img_w * minmax[0]), int(img_w * minmax[1]), size=count) - yl = np.random.randint(0, img_h - cut_h, size=count) - xl = np.random.randint(0, img_w - cut_w, size=count) - yu = yl + cut_h - xu = xl + cut_w - return yl, yu, xl, xu - - -def cutmix_bbox_and_lam(img_shape, lam, ratio_minmax=None, correct_lam=True, count=None): - """ Generate bbox and apply lambda correction. - """ - if ratio_minmax is not None: - yl, yu, xl, xu = rand_bbox_minmax(img_shape, ratio_minmax, count=count) - else: - yl, yu, xl, xu = rand_bbox(img_shape, lam, count=count) - if correct_lam or ratio_minmax is not None: - bbox_area = (yu - yl) * (xu - xl) - lam = 1. - bbox_area / float(img_shape[-2] * img_shape[-1]) - return (yl, yu, xl, xu), lam - - -class Mixup: - """ Mixup/Cutmix that applies different params to each element or whole batch - - Args: - mixup_alpha (float): mixup alpha value, mixup is active if > 0. - cutmix_alpha (float): cutmix alpha value, cutmix is active if > 0. - cutmix_minmax (List[float]): cutmix min/max image ratio, cutmix is active and uses this vs alpha if not None. - prob (float): probability of applying mixup or cutmix per batch or element - switch_prob (float): probability of switching to cutmix instead of mixup when both are active - mode (str): how to apply mixup/cutmix params (per 'batch', 'pair' (pair of elements), 'elem' (element) - correct_lam (bool): apply lambda correction when cutmix bbox clipped by image borders - label_smoothing (float): apply label smoothing to the mixed target tensor - num_classes (int): number of classes for target - """ - def __init__(self, mixup_alpha=1., cutmix_alpha=0., cutmix_minmax=None, prob=1.0, switch_prob=0.5, - mode='batch', correct_lam=True, label_smoothing=0.1, num_classes=1000): - self.mixup_alpha = mixup_alpha - self.cutmix_alpha = cutmix_alpha - self.cutmix_minmax = cutmix_minmax - if self.cutmix_minmax is not None: - assert len(self.cutmix_minmax) == 2 - # force cutmix alpha == 1.0 when minmax active to keep logic simple & safe - self.cutmix_alpha = 1.0 - self.mix_prob = prob - self.switch_prob = switch_prob - self.label_smoothing = label_smoothing - self.num_classes = num_classes - self.mode = mode - self.correct_lam = correct_lam # correct lambda based on clipped area for cutmix - self.mixup_enabled = True # set to false to disable mixing (intended tp be set by train loop) - - def _params_per_elem(self, batch_size): - lam = np.ones(batch_size, dtype=np.float32) - use_cutmix = np.zeros(batch_size, dtype=np.bool) - if self.mixup_enabled: - if self.mixup_alpha > 0. and self.cutmix_alpha > 0.: - use_cutmix = np.random.rand(batch_size) < self.switch_prob - lam_mix = np.where( - use_cutmix, - np.random.beta(self.cutmix_alpha, self.cutmix_alpha, size=batch_size), - np.random.beta(self.mixup_alpha, self.mixup_alpha, size=batch_size)) - elif self.mixup_alpha > 0.: - lam_mix = np.random.beta(self.mixup_alpha, self.mixup_alpha, size=batch_size) - elif self.cutmix_alpha > 0.: - use_cutmix = np.ones(batch_size, dtype=np.bool) - lam_mix = np.random.beta(self.cutmix_alpha, self.cutmix_alpha, size=batch_size) - else: - assert False, "One of mixup_alpha > 0., cutmix_alpha > 0., cutmix_minmax not None should be true." - lam = np.where(np.random.rand(batch_size) < self.mix_prob, lam_mix.astype(np.float32), lam) - return lam, use_cutmix - - def _params_per_batch(self): - lam = 1. - use_cutmix = False - if self.mixup_enabled and np.random.rand() < self.mix_prob: - if self.mixup_alpha > 0. and self.cutmix_alpha > 0.: - use_cutmix = np.random.rand() < self.switch_prob - lam_mix = np.random.beta(self.cutmix_alpha, self.cutmix_alpha) if use_cutmix else \ - np.random.beta(self.mixup_alpha, self.mixup_alpha) - elif self.mixup_alpha > 0.: - lam_mix = np.random.beta(self.mixup_alpha, self.mixup_alpha) - elif self.cutmix_alpha > 0.: - use_cutmix = True - lam_mix = np.random.beta(self.cutmix_alpha, self.cutmix_alpha) - else: - assert False, "One of mixup_alpha > 0., cutmix_alpha > 0., cutmix_minmax not None should be true." - lam = float(lam_mix) - return lam, use_cutmix - - def _mix_elem(self, x): - batch_size = len(x) - lam_batch, use_cutmix = self._params_per_elem(batch_size) - x_orig = x.clone() # need to keep an unmodified original for mixing source - for i in range(batch_size): - j = batch_size - i - 1 - lam = lam_batch[i] - if lam != 1.: - if use_cutmix[i]: - (yl, yh, xl, xh), lam = cutmix_bbox_and_lam( - x[i].shape, lam, ratio_minmax=self.cutmix_minmax, correct_lam=self.correct_lam) - x[i][:, yl:yh, xl:xh] = x_orig[j][:, yl:yh, xl:xh] - lam_batch[i] = lam - else: - x[i] = x[i] * lam + x_orig[j] * (1 - lam) - return torch.tensor(lam_batch, device=x.device, dtype=x.dtype).unsqueeze(1) - - def _mix_pair(self, x): - batch_size = len(x) - lam_batch, use_cutmix = self._params_per_elem(batch_size // 2) - x_orig = x.clone() # need to keep an unmodified original for mixing source - for i in range(batch_size // 2): - j = batch_size - i - 1 - lam = lam_batch[i] - if lam != 1.: - if use_cutmix[i]: - (yl, yh, xl, xh), lam = cutmix_bbox_and_lam( - x[i].shape, lam, ratio_minmax=self.cutmix_minmax, correct_lam=self.correct_lam) - x[i][:, yl:yh, xl:xh] = x_orig[j][:, yl:yh, xl:xh] - x[j][:, yl:yh, xl:xh] = x_orig[i][:, yl:yh, xl:xh] - lam_batch[i] = lam - else: - x[i] = x[i] * lam + x_orig[j] * (1 - lam) - x[j] = x[j] * lam + x_orig[i] * (1 - lam) - lam_batch = np.concatenate((lam_batch, lam_batch[::-1])) - return torch.tensor(lam_batch, device=x.device, dtype=x.dtype).unsqueeze(1) - - def _mix_batch(self, x): - lam, use_cutmix = self._params_per_batch() - if lam == 1.: - return 1. - if use_cutmix: - (yl, yh, xl, xh), lam = cutmix_bbox_and_lam( - x.shape, lam, ratio_minmax=self.cutmix_minmax, correct_lam=self.correct_lam) - x[:, :, yl:yh, xl:xh] = x.flip(0)[:, :, yl:yh, xl:xh] - else: - x_flipped = x.flip(0).mul_(1. - lam) - x.mul_(lam).add_(x_flipped) - return lam - - def __call__(self, x, target): - assert len(x) % 2 == 0, 'Batch size should be even when using this' - if self.mode == 'elem': - lam = self._mix_elem(x) - elif self.mode == 'pair': - lam = self._mix_pair(x) - else: - lam = self._mix_batch(x) - target = mixup_target(target, self.num_classes, lam, self.label_smoothing,device='npu') - return x, target - - -class FastCollateMixup(Mixup): - """ Fast Collate w/ Mixup/Cutmix that applies different params to each element or whole batch - - A Mixup impl that's performed while collating the batches. - """ - - def _mix_elem_collate(self, output, batch, half=False): - batch_size = len(batch) - num_elem = batch_size // 2 if half else batch_size - assert len(output) == num_elem - lam_batch, use_cutmix = self._params_per_elem(num_elem) - for i in range(num_elem): - j = batch_size - i - 1 - lam = lam_batch[i] - mixed = batch[i][0] - if lam != 1.: - if use_cutmix[i]: - if not half: - mixed = mixed.copy() - (yl, yh, xl, xh), lam = cutmix_bbox_and_lam( - output.shape, lam, ratio_minmax=self.cutmix_minmax, correct_lam=self.correct_lam) - mixed[:, yl:yh, xl:xh] = batch[j][0][:, yl:yh, xl:xh] - lam_batch[i] = lam - else: - mixed = mixed.astype(np.float32) * lam + batch[j][0].astype(np.float32) * (1 - lam) - np.rint(mixed, out=mixed) - output[i] += torch.from_numpy(mixed.astype(np.uint8)) - if half: - lam_batch = np.concatenate((lam_batch, np.ones(num_elem))) - return torch.tensor(lam_batch).unsqueeze(1) - - def _mix_pair_collate(self, output, batch): - batch_size = len(batch) - lam_batch, use_cutmix = self._params_per_elem(batch_size // 2) - for i in range(batch_size // 2): - j = batch_size - i - 1 - lam = lam_batch[i] - mixed_i = batch[i][0] - mixed_j = batch[j][0] - assert 0 <= lam <= 1.0 - if lam < 1.: - if use_cutmix[i]: - (yl, yh, xl, xh), lam = cutmix_bbox_and_lam( - output.shape, lam, ratio_minmax=self.cutmix_minmax, correct_lam=self.correct_lam) - patch_i = mixed_i[:, yl:yh, xl:xh].copy() - mixed_i[:, yl:yh, xl:xh] = mixed_j[:, yl:yh, xl:xh] - mixed_j[:, yl:yh, xl:xh] = patch_i - lam_batch[i] = lam - else: - mixed_temp = mixed_i.astype(np.float32) * lam + mixed_j.astype(np.float32) * (1 - lam) - mixed_j = mixed_j.astype(np.float32) * lam + mixed_i.astype(np.float32) * (1 - lam) - mixed_i = mixed_temp - np.rint(mixed_j, out=mixed_j) - np.rint(mixed_i, out=mixed_i) - output[i] += torch.from_numpy(mixed_i.astype(np.uint8)) - output[j] += torch.from_numpy(mixed_j.astype(np.uint8)) - lam_batch = np.concatenate((lam_batch, lam_batch[::-1])) - return torch.tensor(lam_batch).unsqueeze(1) - - def _mix_batch_collate(self, output, batch): - batch_size = len(batch) - lam, use_cutmix = self._params_per_batch() - if use_cutmix: - (yl, yh, xl, xh), lam = cutmix_bbox_and_lam( - output.shape, lam, ratio_minmax=self.cutmix_minmax, correct_lam=self.correct_lam) - for i in range(batch_size): - j = batch_size - i - 1 - mixed = batch[i][0] - if lam != 1.: - if use_cutmix: - mixed = mixed.copy() # don't want to modify the original while iterating - mixed[:, yl:yh, xl:xh] = batch[j][0][:, yl:yh, xl:xh] - else: - mixed = mixed.astype(np.float32) * lam + batch[j][0].astype(np.float32) * (1 - lam) - np.rint(mixed, out=mixed) - output[i] += torch.from_numpy(mixed.astype(np.uint8)) - return lam - - def __call__(self, batch, _=None): - batch_size = len(batch) - assert batch_size % 2 == 0, 'Batch size should be even when using this' - half = 'half' in self.mode - if half: - batch_size //= 2 - output = torch.zeros((batch_size, *batch[0][0].shape), dtype=torch.uint8) - if self.mode == 'elem' or self.mode == 'half': - lam = self._mix_elem_collate(output, batch, half=half) - elif self.mode == 'pair': - lam = self._mix_pair_collate(output, batch) - else: - lam = self._mix_batch_collate(output, batch) - target = torch.tensor([b[1] for b in batch], dtype=torch.int64) - target = mixup_target(target, self.num_classes, lam, self.label_smoothing, device='cpu') - target = target[:batch_size] - return output, target - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +""" Mixup and Cutmix + +Papers: +mixup: Beyond Empirical Risk Minimization (https://arxiv.org/abs/1710.09412) + +CutMix: Regularization Strategy to Train Strong Classifiers with Localizable Features (https://arxiv.org/abs/1905.04899) + +Code Reference: +CutMix: https://github.com/clovaai/CutMix-PyTorch + +Hacked together by / Copyright 2020 Ross Wightman +""" +import numpy as np +import torch + + +def one_hot(x, num_classes, on_value=1., off_value=0., device='cuda'): + x = x.long().view(-1, 1) + return torch.full((x.size()[0], num_classes), off_value, device=device).scatter_(1, x, on_value) + + +def mixup_target(target, num_classes, lam=1., smoothing=0.0, device='cuda'): + off_value = smoothing / num_classes + on_value = 1. - smoothing + off_value + y1 = one_hot(target, num_classes, on_value=on_value, off_value=off_value, device=device) + y2 = one_hot(target.flip(0), num_classes, on_value=on_value, off_value=off_value, device=device) + return y1 * lam + y2 * (1. - lam) + + +def rand_bbox(img_shape, lam, margin=0., count=None): + """ Standard CutMix bounding-box + Generates a random square bbox based on lambda value. This impl includes + support for enforcing a border margin as percent of bbox dimensions. + + Args: + img_shape (tuple): Image shape as tuple + lam (float): Cutmix lambda value + margin (float): Percentage of bbox dimension to enforce as margin (reduce amount of box outside image) + count (int): Number of bbox to generate + """ + ratio = np.sqrt(1 - lam) + img_h, img_w = img_shape[-2:] + cut_h, cut_w = int(img_h * ratio), int(img_w * ratio) + margin_y, margin_x = int(margin * cut_h), int(margin * cut_w) + cy = np.random.randint(0 + margin_y, img_h - margin_y, size=count) + cx = np.random.randint(0 + margin_x, img_w - margin_x, size=count) + yl = np.clip(cy - cut_h // 2, 0, img_h) + yh = np.clip(cy + cut_h // 2, 0, img_h) + xl = np.clip(cx - cut_w // 2, 0, img_w) + xh = np.clip(cx + cut_w // 2, 0, img_w) + return yl, yh, xl, xh + + +def rand_bbox_minmax(img_shape, minmax, count=None): + """ Min-Max CutMix bounding-box + Inspired by Darknet cutmix impl, generates a random rectangular bbox + based on min/max percent values applied to each dimension of the input image. + + Typical defaults for minmax are usually in the .2-.3 for min and .8-.9 range for max. + + Args: + img_shape (tuple): Image shape as tuple + minmax (tuple or list): Min and max bbox ratios (as percent of image size) + count (int): Number of bbox to generate + """ + assert len(minmax) == 2 + img_h, img_w = img_shape[-2:] + cut_h = np.random.randint(int(img_h * minmax[0]), int(img_h * minmax[1]), size=count) + cut_w = np.random.randint(int(img_w * minmax[0]), int(img_w * minmax[1]), size=count) + yl = np.random.randint(0, img_h - cut_h, size=count) + xl = np.random.randint(0, img_w - cut_w, size=count) + yu = yl + cut_h + xu = xl + cut_w + return yl, yu, xl, xu + + +def cutmix_bbox_and_lam(img_shape, lam, ratio_minmax=None, correct_lam=True, count=None): + """ Generate bbox and apply lambda correction. + """ + if ratio_minmax is not None: + yl, yu, xl, xu = rand_bbox_minmax(img_shape, ratio_minmax, count=count) + else: + yl, yu, xl, xu = rand_bbox(img_shape, lam, count=count) + if correct_lam or ratio_minmax is not None: + bbox_area = (yu - yl) * (xu - xl) + lam = 1. - bbox_area / float(img_shape[-2] * img_shape[-1]) + return (yl, yu, xl, xu), lam + + +class Mixup: + """ Mixup/Cutmix that applies different params to each element or whole batch + + Args: + mixup_alpha (float): mixup alpha value, mixup is active if > 0. + cutmix_alpha (float): cutmix alpha value, cutmix is active if > 0. + cutmix_minmax (List[float]): cutmix min/max image ratio, cutmix is active and uses this vs alpha if not None. + prob (float): probability of applying mixup or cutmix per batch or element + switch_prob (float): probability of switching to cutmix instead of mixup when both are active + mode (str): how to apply mixup/cutmix params (per 'batch', 'pair' (pair of elements), 'elem' (element) + correct_lam (bool): apply lambda correction when cutmix bbox clipped by image borders + label_smoothing (float): apply label smoothing to the mixed target tensor + num_classes (int): number of classes for target + """ + def __init__(self, mixup_alpha=1., cutmix_alpha=0., cutmix_minmax=None, prob=1.0, switch_prob=0.5, + mode='batch', correct_lam=True, label_smoothing=0.1, num_classes=1000): + self.mixup_alpha = mixup_alpha + self.cutmix_alpha = cutmix_alpha + self.cutmix_minmax = cutmix_minmax + if self.cutmix_minmax is not None: + assert len(self.cutmix_minmax) == 2 + # force cutmix alpha == 1.0 when minmax active to keep logic simple & safe + self.cutmix_alpha = 1.0 + self.mix_prob = prob + self.switch_prob = switch_prob + self.label_smoothing = label_smoothing + self.num_classes = num_classes + self.mode = mode + self.correct_lam = correct_lam # correct lambda based on clipped area for cutmix + self.mixup_enabled = True # set to false to disable mixing (intended tp be set by train loop) + + def _params_per_elem(self, batch_size): + lam = np.ones(batch_size, dtype=np.float32) + use_cutmix = np.zeros(batch_size, dtype=np.bool) + if self.mixup_enabled: + if self.mixup_alpha > 0. and self.cutmix_alpha > 0.: + use_cutmix = np.random.rand(batch_size) < self.switch_prob + lam_mix = np.where( + use_cutmix, + np.random.beta(self.cutmix_alpha, self.cutmix_alpha, size=batch_size), + np.random.beta(self.mixup_alpha, self.mixup_alpha, size=batch_size)) + elif self.mixup_alpha > 0.: + lam_mix = np.random.beta(self.mixup_alpha, self.mixup_alpha, size=batch_size) + elif self.cutmix_alpha > 0.: + use_cutmix = np.ones(batch_size, dtype=np.bool) + lam_mix = np.random.beta(self.cutmix_alpha, self.cutmix_alpha, size=batch_size) + else: + assert False, "One of mixup_alpha > 0., cutmix_alpha > 0., cutmix_minmax not None should be true." + lam = np.where(np.random.rand(batch_size) < self.mix_prob, lam_mix.astype(np.float32), lam) + return lam, use_cutmix + + def _params_per_batch(self): + lam = 1. + use_cutmix = False + if self.mixup_enabled and np.random.rand() < self.mix_prob: + if self.mixup_alpha > 0. and self.cutmix_alpha > 0.: + use_cutmix = np.random.rand() < self.switch_prob + lam_mix = np.random.beta(self.cutmix_alpha, self.cutmix_alpha) if use_cutmix else \ + np.random.beta(self.mixup_alpha, self.mixup_alpha) + elif self.mixup_alpha > 0.: + lam_mix = np.random.beta(self.mixup_alpha, self.mixup_alpha) + elif self.cutmix_alpha > 0.: + use_cutmix = True + lam_mix = np.random.beta(self.cutmix_alpha, self.cutmix_alpha) + else: + assert False, "One of mixup_alpha > 0., cutmix_alpha > 0., cutmix_minmax not None should be true." + lam = float(lam_mix) + return lam, use_cutmix + + def _mix_elem(self, x): + batch_size = len(x) + lam_batch, use_cutmix = self._params_per_elem(batch_size) + x_orig = x.clone() # need to keep an unmodified original for mixing source + for i in range(batch_size): + j = batch_size - i - 1 + lam = lam_batch[i] + if lam != 1.: + if use_cutmix[i]: + (yl, yh, xl, xh), lam = cutmix_bbox_and_lam( + x[i].shape, lam, ratio_minmax=self.cutmix_minmax, correct_lam=self.correct_lam) + x[i][:, yl:yh, xl:xh] = x_orig[j][:, yl:yh, xl:xh] + lam_batch[i] = lam + else: + x[i] = x[i] * lam + x_orig[j] * (1 - lam) + return torch.tensor(lam_batch, device=x.device, dtype=x.dtype).unsqueeze(1) + + def _mix_pair(self, x): + batch_size = len(x) + lam_batch, use_cutmix = self._params_per_elem(batch_size // 2) + x_orig = x.clone() # need to keep an unmodified original for mixing source + for i in range(batch_size // 2): + j = batch_size - i - 1 + lam = lam_batch[i] + if lam != 1.: + if use_cutmix[i]: + (yl, yh, xl, xh), lam = cutmix_bbox_and_lam( + x[i].shape, lam, ratio_minmax=self.cutmix_minmax, correct_lam=self.correct_lam) + x[i][:, yl:yh, xl:xh] = x_orig[j][:, yl:yh, xl:xh] + x[j][:, yl:yh, xl:xh] = x_orig[i][:, yl:yh, xl:xh] + lam_batch[i] = lam + else: + x[i] = x[i] * lam + x_orig[j] * (1 - lam) + x[j] = x[j] * lam + x_orig[i] * (1 - lam) + lam_batch = np.concatenate((lam_batch, lam_batch[::-1])) + return torch.tensor(lam_batch, device=x.device, dtype=x.dtype).unsqueeze(1) + + def _mix_batch(self, x): + lam, use_cutmix = self._params_per_batch() + if lam == 1.: + return 1. + if use_cutmix: + (yl, yh, xl, xh), lam = cutmix_bbox_and_lam( + x.shape, lam, ratio_minmax=self.cutmix_minmax, correct_lam=self.correct_lam) + x[:, :, yl:yh, xl:xh] = x.flip(0)[:, :, yl:yh, xl:xh] + else: + x_flipped = x.flip(0).mul_(1. - lam) + x.mul_(lam).add_(x_flipped) + return lam + + def __call__(self, x, target): + assert len(x) % 2 == 0, 'Batch size should be even when using this' + if self.mode == 'elem': + lam = self._mix_elem(x) + elif self.mode == 'pair': + lam = self._mix_pair(x) + else: + lam = self._mix_batch(x) + target = mixup_target(target, self.num_classes, lam, self.label_smoothing,device='npu') + return x, target + + +class FastCollateMixup(Mixup): + """ Fast Collate w/ Mixup/Cutmix that applies different params to each element or whole batch + + A Mixup impl that's performed while collating the batches. + """ + + def _mix_elem_collate(self, output, batch, half=False): + batch_size = len(batch) + num_elem = batch_size // 2 if half else batch_size + assert len(output) == num_elem + lam_batch, use_cutmix = self._params_per_elem(num_elem) + for i in range(num_elem): + j = batch_size - i - 1 + lam = lam_batch[i] + mixed = batch[i][0] + if lam != 1.: + if use_cutmix[i]: + if not half: + mixed = mixed.copy() + (yl, yh, xl, xh), lam = cutmix_bbox_and_lam( + output.shape, lam, ratio_minmax=self.cutmix_minmax, correct_lam=self.correct_lam) + mixed[:, yl:yh, xl:xh] = batch[j][0][:, yl:yh, xl:xh] + lam_batch[i] = lam + else: + mixed = mixed.astype(np.float32) * lam + batch[j][0].astype(np.float32) * (1 - lam) + np.rint(mixed, out=mixed) + output[i] += torch.from_numpy(mixed.astype(np.uint8)) + if half: + lam_batch = np.concatenate((lam_batch, np.ones(num_elem))) + return torch.tensor(lam_batch).unsqueeze(1) + + def _mix_pair_collate(self, output, batch): + batch_size = len(batch) + lam_batch, use_cutmix = self._params_per_elem(batch_size // 2) + for i in range(batch_size // 2): + j = batch_size - i - 1 + lam = lam_batch[i] + mixed_i = batch[i][0] + mixed_j = batch[j][0] + assert 0 <= lam <= 1.0 + if lam < 1.: + if use_cutmix[i]: + (yl, yh, xl, xh), lam = cutmix_bbox_and_lam( + output.shape, lam, ratio_minmax=self.cutmix_minmax, correct_lam=self.correct_lam) + patch_i = mixed_i[:, yl:yh, xl:xh].copy() + mixed_i[:, yl:yh, xl:xh] = mixed_j[:, yl:yh, xl:xh] + mixed_j[:, yl:yh, xl:xh] = patch_i + lam_batch[i] = lam + else: + mixed_temp = mixed_i.astype(np.float32) * lam + mixed_j.astype(np.float32) * (1 - lam) + mixed_j = mixed_j.astype(np.float32) * lam + mixed_i.astype(np.float32) * (1 - lam) + mixed_i = mixed_temp + np.rint(mixed_j, out=mixed_j) + np.rint(mixed_i, out=mixed_i) + output[i] += torch.from_numpy(mixed_i.astype(np.uint8)) + output[j] += torch.from_numpy(mixed_j.astype(np.uint8)) + lam_batch = np.concatenate((lam_batch, lam_batch[::-1])) + return torch.tensor(lam_batch).unsqueeze(1) + + def _mix_batch_collate(self, output, batch): + batch_size = len(batch) + lam, use_cutmix = self._params_per_batch() + if use_cutmix: + (yl, yh, xl, xh), lam = cutmix_bbox_and_lam( + output.shape, lam, ratio_minmax=self.cutmix_minmax, correct_lam=self.correct_lam) + for i in range(batch_size): + j = batch_size - i - 1 + mixed = batch[i][0] + if lam != 1.: + if use_cutmix: + mixed = mixed.copy() # don't want to modify the original while iterating + mixed[:, yl:yh, xl:xh] = batch[j][0][:, yl:yh, xl:xh] + else: + mixed = mixed.astype(np.float32) * lam + batch[j][0].astype(np.float32) * (1 - lam) + np.rint(mixed, out=mixed) + output[i] += torch.from_numpy(mixed.astype(np.uint8)) + return lam + + def __call__(self, batch, _=None): + batch_size = len(batch) + assert batch_size % 2 == 0, 'Batch size should be even when using this' + half = 'half' in self.mode + if half: + batch_size //= 2 + output = torch.zeros((batch_size, *batch[0][0].shape), dtype=torch.uint8) + if self.mode == 'elem' or self.mode == 'half': + lam = self._mix_elem_collate(output, batch, half=half) + elif self.mode == 'pair': + lam = self._mix_pair_collate(output, batch) + else: + lam = self._mix_batch_collate(output, batch) + target = torch.tensor([b[1] for b in batch], dtype=torch.int64) + target = mixup_target(target, self.num_classes, lam, self.label_smoothing, device='cpu') + target = target[:batch_size] + return output, target + diff --git a/PyTorch/contrib/cv/classification/Deit_Small/npu_fused_adamw.py b/PyTorch/contrib/cv/classification/Deit_Small/npu_fused_adamw.py index bd9f5d6a4d..d52d4e2d5e 100644 --- a/PyTorch/contrib/cv/classification/Deit_Small/npu_fused_adamw.py +++ b/PyTorch/contrib/cv/classification/Deit_Small/npu_fused_adamw.py @@ -1,257 +1,257 @@ -# Copyright (c) 2020, Huawei Technologies. -# Copyright (c) 2019, Facebook CORPORATION. -# All rights reserved. -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 math -from collections import defaultdict - -import torch -from torch.optim.optimizer import Optimizer - -from apex.contrib.combine_tensors import combine_npu - - -class NpuFusedAdamW(Optimizer): - """Implements AdamW algorithm. - - Currently NPU-only. Requires Apex to be installed via - ``pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--npu_float_status" ./``. - - This version of NPU fused AdamW implements 1 fusions. - - * A combine-tensor apply launch that batches the elementwise updates applied to all the model's parameters - into one or a few kernel launches. - - :class:`apex.optimizers.NpuFusedAdamW` may be used as a drop-in replacement for ``torch.optim.AdamW``:: - - opt = apex.optimizers.NpuFusedAdamW(model.parameters(), lr = ....) - ... - opt.step() - - :class:`apex.optimizers.FusedAdam` should be used with Amp. Currently, if you wish to use :class:`NpuFusedAdamW` - with Amp, only ``opt_level O1 and O2`` can be choosed:: - - opt = apex.optimizers.NpuFusedAdamW(model.parameters(), lr = ....) - model, opt = amp.initialize(model, opt, opt_level="O2") - ... - opt.step() - - - The original Adam algorithm was proposed in `Adam: A Method for Stochastic Optimization`_. - The AdamW variant was proposed in `Decoupled Weight Decay Regularization`_. - - Arguments: - params (iterable): iterable of parameters to optimize or dicts defining - parameter groups - lr (float, optional, default: 1e-3): learning rate - betas (Tuple[float, float], optional, default: (0.9, 0.999)): coefficients used - for computing running averages of gradient and its square - eps (float, optional, default: 1e-8): term added to the denominator to improve - numerical stability - weight_decay (float, optional, default: 1e-2): weight decay coefficient - amsgrad (boolean, optional, default: False): whether to use the AMSGrad variant of - this algorithm from the paper `On the Convergence of Adam and Beyond`_ - - .. _Adam\: A Method for Stochastic Optimization: - https://arxiv.org/abs/1412.6980 - .. _Decoupled Weight Decay Regularization: - https://arxiv.org/abs/1711.05101 - .. _On the Convergence of Adam and Beyond: - https://openreview.net/forum?id=ryQu7f-RZ - """ - - def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), eps=1e-8, - weight_decay=1e-2, amsgrad=False): - if lr < 0.0: - raise ValueError("Invalid learning rate: {}".format(lr)) - if eps < 0.0: - raise ValueError("Invalid epsilon value: {}".format(eps)) - if betas[0] < 0.0 or betas[0] >= 1.0: - raise ValueError("Invalid beta parameter at index 0: {}".format(betas[0])) - if betas[1] < 0.0 or betas[1] >= 1.0: - raise ValueError("Invalid beta parameter at index 1: {}".format(betas[1])) - if weight_decay < 0.0: - raise ValueError("Invalid weight_decay value: {}".format(weight_decay)) - defaults = dict(lr=lr, betas=betas, eps=eps, - weight_decay=weight_decay, amsgrad=amsgrad) - self.is_npu_fused_optimizer = True - super(NpuFusedAdamW, self).__init__(params, defaults) - - def __setstate__(self, state): - super(NpuFusedAdamW, self).__setstate__(state) - for group in self.param_groups: - group.setdefault('amsgrad', False) - - def _init_param_state(self, p, amsgrad): - state = self.state[p] - # State initialization - if len(state) == 0: - state['step'] = 0 - # Exponential moving average of gradient values - state['exp_avg'] = torch.zeros_like(p, memory_format=torch.preserve_format) - # Exponential moving average of squared gradient values - state['exp_avg_sq'] = torch.zeros_like(p, memory_format=torch.preserve_format) - if amsgrad: - # Maintains max of all exp. moving avg. of sq. grad. values - state['max_exp_avg_sq'] = torch.zeros_like(p, memory_format=torch.preserve_format) - else: - exp_avg_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) - exp_avg_tmp.copy_(state['exp_avg']) - state['exp_avg'] = exp_avg_tmp - - exp_avg_sq_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) - exp_avg_sq_tmp.copy_(state['exp_avg_sq']) - state['exp_avg_sq'] = exp_avg_sq_tmp - - if amsgrad: - max_exp_avg_sq_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) - max_exp_avg_sq_tmp.copy_(state['max_exp_avg_sq']) - state['max_exp_avg_sq'] = max_exp_avg_sq_tmp - - def _combine_group_param_states(self, group_index): - group = self.param_groups[group_index] - stash = self._amp_stash - group_params_list = stash.params_lists_indexed_by_group[group_index] - - amsgrad = group['amsgrad'] - - combined_param_states = [] - for params in group_params_list: - step_list = [] - exp_avg_list = [] - exp_avg_sq_list = [] - max_exp_avg_sq_list = [] - - for p in params: - if p.grad is None: - continue - grad = p.grad - if grad.is_sparse: - raise RuntimeError('NpuFusedAdamW does not support sparse gradients, ' - 'please consider SparseAdam instead') - - self._init_param_state(p, amsgrad) - state = self.state[p] - step_list.append(state['step']) - exp_avg_list.append(state['exp_avg']) - exp_avg_sq_list.append(state['exp_avg_sq']) - if amsgrad: - max_exp_avg_sq_list.append(state['max_exp_avg_sq']) - - combined_step = 0 - combined_exp_avg = None - combined_exp_avg_sq = None - combined_max_exp_avg_sq = None - - if len(exp_avg_list) > 0: - combined_step = step_list[0] - combined_exp_avg = combine_npu(exp_avg_list) - combined_exp_avg_sq = combine_npu(exp_avg_sq_list) - combined_max_exp_avg_sq = combine_npu(max_exp_avg_sq_list) - - combined_state = defaultdict(dict) - combined_state['step'] = combined_step - combined_state['exp_avg'] = combined_exp_avg - combined_state['exp_avg_sq'] = combined_exp_avg_sq - combined_state['max_exp_avg_sq'] = combined_max_exp_avg_sq - combined_param_states.append(combined_state) - stash.combined_param_states_indexed_by_group[group_index] = combined_param_states - - def _combine_param_states_by_group(self): - stash = self._amp_stash - if stash.param_states_are_combined_by_group: - return - - stash.combined_param_states_indexed_by_group = [] - for _ in self.param_groups: - stash.combined_param_states_indexed_by_group.append([]) - - for i, _ in enumerate(self.param_groups): - self._combine_group_param_states(i) - stash.param_states_are_combined_by_group = True - - def _group_step(self, group_index): - group = self.param_groups[group_index] - for p in group['params']: - if p.grad is None: - continue - - grad = p.grad - if grad.is_sparse: - raise RuntimeError('NpuFusedAdamW does not support sparse gradients, ' - 'please consider SparseAdam instead') - state_p = self.state[p] - state_p['step'] += 1 - - amsgrad = group['amsgrad'] - beta1, beta2 = group['betas'] - - stash = self._amp_stash - combined_group_params = stash.combined_params_indexed_by_group[group_index] - combined_group_grads = stash.combined_grads_indexed_by_group[group_index] - combined_group_param_states = stash.combined_param_states_indexed_by_group[group_index] - - for combined_param, combined_grad, combined_param_state in zip(combined_group_params, - combined_group_grads, - combined_group_param_states): - if combined_param is None or combined_grad is None: - continue - - # Perform stepweight decay. The fused method is used here to speed up the calculation - combined_param.mul_(1 - group['lr'] * group['weight_decay']) - - exp_avg, exp_avg_sq = combined_param_state['exp_avg'], combined_param_state['exp_avg_sq'] - if amsgrad: - max_exp_avg_sq = combined_param_state['max_exp_avg_sq'] - - combined_param_state['step'] += 1 - bias_correction1 = 1 - beta1 ** combined_param_state['step'] - bias_correction2 = 1 - beta2 ** combined_param_state['step'] - - # Decay the first and second moment running average coefficient - exp_avg.mul_(beta1).add_(combined_grad, alpha=1 - beta1) - exp_avg_sq.mul_(beta2).addcmul_(combined_grad, combined_grad, value=1 - beta2) - if amsgrad: - # Maintains the maximum of all 2nd moment running avg. till now - torch.max(max_exp_avg_sq, exp_avg_sq, out=max_exp_avg_sq) - # Use the max. for normalizing running avg. of gradient - denom = (max_exp_avg_sq.sqrt() / math.sqrt(bias_correction2)).add_(group['eps']) - else: - denom = (exp_avg_sq.sqrt() / math.sqrt(bias_correction2)).add_(group['eps']) - - step_size = group['lr'] / bias_correction1 - - combined_param.addcdiv_(exp_avg, denom, value=-step_size) - - @torch.no_grad() - def step(self, closure=None): - if not hasattr(self, "_amp_stash"): - raise RuntimeError('apex.optimizers.NpuFusedAdamW should be used with AMP.') - - self._check_already_combined_params_and_grads() - # combine params and grads first - self._combine_params_and_grads_by_group() - # then combine param states - self._combine_param_states_by_group() - - loss = None - if closure is not None: - with torch.enable_grad(): - loss = closure() - - for i, _ in enumerate(self.param_groups): - self._group_step(i) - - return loss +# Copyright (c) 2020, Huawei Technologies. +# Copyright (c) 2019, Facebook CORPORATION. +# All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 math +from collections import defaultdict + +import torch +from torch.optim.optimizer import Optimizer + +from apex.contrib.combine_tensors import combine_npu + + +class NpuFusedAdamW(Optimizer): + """Implements AdamW algorithm. + + Currently NPU-only. Requires Apex to be installed via + ``pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--npu_float_status" ./``. + + This version of NPU fused AdamW implements 1 fusions. + + * A combine-tensor apply launch that batches the elementwise updates applied to all the model's parameters + into one or a few kernel launches. + + :class:`apex.optimizers.NpuFusedAdamW` may be used as a drop-in replacement for ``torch.optim.AdamW``:: + + opt = apex.optimizers.NpuFusedAdamW(model.parameters(), lr = ....) + ... + opt.step() + + :class:`apex.optimizers.FusedAdam` should be used with Amp. Currently, if you wish to use :class:`NpuFusedAdamW` + with Amp, only ``opt_level O1 and O2`` can be choosed:: + + opt = apex.optimizers.NpuFusedAdamW(model.parameters(), lr = ....) + model, opt = amp.initialize(model, opt, opt_level="O2") + ... + opt.step() + + + The original Adam algorithm was proposed in `Adam: A Method for Stochastic Optimization`_. + The AdamW variant was proposed in `Decoupled Weight Decay Regularization`_. + + Arguments: + params (iterable): iterable of parameters to optimize or dicts defining + parameter groups + lr (float, optional, default: 1e-3): learning rate + betas (Tuple[float, float], optional, default: (0.9, 0.999)): coefficients used + for computing running averages of gradient and its square + eps (float, optional, default: 1e-8): term added to the denominator to improve + numerical stability + weight_decay (float, optional, default: 1e-2): weight decay coefficient + amsgrad (boolean, optional, default: False): whether to use the AMSGrad variant of + this algorithm from the paper `On the Convergence of Adam and Beyond`_ + + .. _Adam\: A Method for Stochastic Optimization: + https://arxiv.org/abs/1412.6980 + .. _Decoupled Weight Decay Regularization: + https://arxiv.org/abs/1711.05101 + .. _On the Convergence of Adam and Beyond: + https://openreview.net/forum?id=ryQu7f-RZ + """ + + def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), eps=1e-8, + weight_decay=1e-2, amsgrad=False): + if lr < 0.0: + raise ValueError("Invalid learning rate: {}".format(lr)) + if eps < 0.0: + raise ValueError("Invalid epsilon value: {}".format(eps)) + if betas[0] < 0.0 or betas[0] >= 1.0: + raise ValueError("Invalid beta parameter at index 0: {}".format(betas[0])) + if betas[1] < 0.0 or betas[1] >= 1.0: + raise ValueError("Invalid beta parameter at index 1: {}".format(betas[1])) + if weight_decay < 0.0: + raise ValueError("Invalid weight_decay value: {}".format(weight_decay)) + defaults = dict(lr=lr, betas=betas, eps=eps, + weight_decay=weight_decay, amsgrad=amsgrad) + self.is_npu_fused_optimizer = True + super(NpuFusedAdamW, self).__init__(params, defaults) + + def __setstate__(self, state): + super(NpuFusedAdamW, self).__setstate__(state) + for group in self.param_groups: + group.setdefault('amsgrad', False) + + def _init_param_state(self, p, amsgrad): + state = self.state[p] + # State initialization + if len(state) == 0: + state['step'] = 0 + # Exponential moving average of gradient values + state['exp_avg'] = torch.zeros_like(p, memory_format=torch.preserve_format) + # Exponential moving average of squared gradient values + state['exp_avg_sq'] = torch.zeros_like(p, memory_format=torch.preserve_format) + if amsgrad: + # Maintains max of all exp. moving avg. of sq. grad. values + state['max_exp_avg_sq'] = torch.zeros_like(p, memory_format=torch.preserve_format) + else: + exp_avg_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) + exp_avg_tmp.copy_(state['exp_avg']) + state['exp_avg'] = exp_avg_tmp + + exp_avg_sq_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) + exp_avg_sq_tmp.copy_(state['exp_avg_sq']) + state['exp_avg_sq'] = exp_avg_sq_tmp + + if amsgrad: + max_exp_avg_sq_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) + max_exp_avg_sq_tmp.copy_(state['max_exp_avg_sq']) + state['max_exp_avg_sq'] = max_exp_avg_sq_tmp + + def _combine_group_param_states(self, group_index): + group = self.param_groups[group_index] + stash = self._amp_stash + group_params_list = stash.params_lists_indexed_by_group[group_index] + + amsgrad = group['amsgrad'] + + combined_param_states = [] + for params in group_params_list: + step_list = [] + exp_avg_list = [] + exp_avg_sq_list = [] + max_exp_avg_sq_list = [] + + for p in params: + if p.grad is None: + continue + grad = p.grad + if grad.is_sparse: + raise RuntimeError('NpuFusedAdamW does not support sparse gradients, ' + 'please consider SparseAdam instead') + + self._init_param_state(p, amsgrad) + state = self.state[p] + step_list.append(state['step']) + exp_avg_list.append(state['exp_avg']) + exp_avg_sq_list.append(state['exp_avg_sq']) + if amsgrad: + max_exp_avg_sq_list.append(state['max_exp_avg_sq']) + + combined_step = 0 + combined_exp_avg = None + combined_exp_avg_sq = None + combined_max_exp_avg_sq = None + + if len(exp_avg_list) > 0: + combined_step = step_list[0] + combined_exp_avg = combine_npu(exp_avg_list) + combined_exp_avg_sq = combine_npu(exp_avg_sq_list) + combined_max_exp_avg_sq = combine_npu(max_exp_avg_sq_list) + + combined_state = defaultdict(dict) + combined_state['step'] = combined_step + combined_state['exp_avg'] = combined_exp_avg + combined_state['exp_avg_sq'] = combined_exp_avg_sq + combined_state['max_exp_avg_sq'] = combined_max_exp_avg_sq + combined_param_states.append(combined_state) + stash.combined_param_states_indexed_by_group[group_index] = combined_param_states + + def _combine_param_states_by_group(self): + stash = self._amp_stash + if stash.param_states_are_combined_by_group: + return + + stash.combined_param_states_indexed_by_group = [] + for _ in self.param_groups: + stash.combined_param_states_indexed_by_group.append([]) + + for i, _ in enumerate(self.param_groups): + self._combine_group_param_states(i) + stash.param_states_are_combined_by_group = True + + def _group_step(self, group_index): + group = self.param_groups[group_index] + for p in group['params']: + if p.grad is None: + continue + + grad = p.grad + if grad.is_sparse: + raise RuntimeError('NpuFusedAdamW does not support sparse gradients, ' + 'please consider SparseAdam instead') + state_p = self.state[p] + state_p['step'] += 1 + + amsgrad = group['amsgrad'] + beta1, beta2 = group['betas'] + + stash = self._amp_stash + combined_group_params = stash.combined_params_indexed_by_group[group_index] + combined_group_grads = stash.combined_grads_indexed_by_group[group_index] + combined_group_param_states = stash.combined_param_states_indexed_by_group[group_index] + + for combined_param, combined_grad, combined_param_state in zip(combined_group_params, + combined_group_grads, + combined_group_param_states): + if combined_param is None or combined_grad is None: + continue + + # Perform stepweight decay. The fused method is used here to speed up the calculation + combined_param.mul_(1 - group['lr'] * group['weight_decay']) + + exp_avg, exp_avg_sq = combined_param_state['exp_avg'], combined_param_state['exp_avg_sq'] + if amsgrad: + max_exp_avg_sq = combined_param_state['max_exp_avg_sq'] + + combined_param_state['step'] += 1 + bias_correction1 = 1 - beta1 ** combined_param_state['step'] + bias_correction2 = 1 - beta2 ** combined_param_state['step'] + + # Decay the first and second moment running average coefficient + exp_avg.mul_(beta1).add_(combined_grad, alpha=1 - beta1) + exp_avg_sq.mul_(beta2).addcmul_(combined_grad, combined_grad, value=1 - beta2) + if amsgrad: + # Maintains the maximum of all 2nd moment running avg. till now + torch.max(max_exp_avg_sq, exp_avg_sq, out=max_exp_avg_sq) + # Use the max. for normalizing running avg. of gradient + denom = (max_exp_avg_sq.sqrt() / math.sqrt(bias_correction2)).add_(group['eps']) + else: + denom = (exp_avg_sq.sqrt() / math.sqrt(bias_correction2)).add_(group['eps']) + + step_size = group['lr'] / bias_correction1 + + combined_param.addcdiv_(exp_avg, denom, value=-step_size) + + @torch.no_grad() + def step(self, closure=None): + if not hasattr(self, "_amp_stash"): + raise RuntimeError('apex.optimizers.NpuFusedAdamW should be used with AMP.') + + self._check_already_combined_params_and_grads() + # combine params and grads first + self._combine_params_and_grads_by_group() + # then combine param states + self._combine_param_states_by_group() + + loss = None + if closure is not None: + with torch.enable_grad(): + loss = closure() + + for i, _ in enumerate(self.param_groups): + self._group_step(i) + + return loss diff --git a/PyTorch/contrib/cv/classification/DnCNN/.keep b/PyTorch/contrib/cv/classification/DnCNN/.keep old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/Dockerfile b/PyTorch/contrib/cv/classification/DnCNN/Dockerfile old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/README.md b/PyTorch/contrib/cv/classification/DnCNN/README.md old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/dataset.py b/PyTorch/contrib/cv/classification/DnCNN/dataset.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/demo.py b/PyTorch/contrib/cv/classification/DnCNN/demo.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/docker_start.sh b/PyTorch/contrib/cv/classification/DnCNN/docker_start.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/evalOnePic.py b/PyTorch/contrib/cv/classification/DnCNN/evalOnePic.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/models.py b/PyTorch/contrib/cv/classification/DnCNN/models.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/modelzoo_level.txt b/PyTorch/contrib/cv/classification/DnCNN/modelzoo_level.txt old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/pth2onnx.py b/PyTorch/contrib/cv/classification/DnCNN/pth2onnx.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/requirements.txt b/PyTorch/contrib/cv/classification/DnCNN/requirements.txt old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/scripts/demo.sh b/PyTorch/contrib/cv/classification/DnCNN/scripts/demo.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/scripts/eval.sh b/PyTorch/contrib/cv/classification/DnCNN/scripts/eval.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/scripts/pth2onnx.sh b/PyTorch/contrib/cv/classification/DnCNN/scripts/pth2onnx.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/scripts/set_npu_env.sh b/PyTorch/contrib/cv/classification/DnCNN/scripts/set_npu_env.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/scripts/train_1p.sh b/PyTorch/contrib/cv/classification/DnCNN/scripts/train_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/scripts/train_8p.sh b/PyTorch/contrib/cv/classification/DnCNN/scripts/train_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/test/demo.sh b/PyTorch/contrib/cv/classification/DnCNN/test/demo.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/test/pth2onnx.sh b/PyTorch/contrib/cv/classification/DnCNN/test/pth2onnx.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/test/train_eval_8p.sh b/PyTorch/contrib/cv/classification/DnCNN/test/train_eval_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/test/train_full_1p.sh b/PyTorch/contrib/cv/classification/DnCNN/test/train_full_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/test/train_full_8p.sh b/PyTorch/contrib/cv/classification/DnCNN/test/train_full_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/test/train_performance_1p.sh b/PyTorch/contrib/cv/classification/DnCNN/test/train_performance_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/test/train_performance_8p.sh b/PyTorch/contrib/cv/classification/DnCNN/test/train_performance_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/train_1p.py b/PyTorch/contrib/cv/classification/DnCNN/train_1p.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/train_8p.py b/PyTorch/contrib/cv/classification/DnCNN/train_8p.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/DnCNN/utils.py b/PyTorch/contrib/cv/classification/DnCNN/utils.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Efficient-3DCNNs_ID1230_for_PyTorch/modelzoo_level.txt b/PyTorch/contrib/cv/classification/Efficient-3DCNNs_ID1230_for_PyTorch/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/classification/Efficient-3DCNNs_ID1230_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/contrib/cv/classification/Efficient-3DCNNs_ID1230_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/ImageNet_val_split.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/ImageNet_val_split.py index 60d468b73e..31376e467a 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/ImageNet_val_split.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/ImageNet_val_split.py @@ -1,61 +1,61 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 sys -import os -import scipy -import shutil - - -def move_valimg(val_dir='./val', devkit_dir='./ILSVRC2012_devkit_t12'): - """ - move valimg to correspongding folders. - val_id(start from 1) -> ILSVRC_ID(start from 1) -> WIND - organize like: - /val - /n01440764 - images - /n01443537 - images - ..... - """ - # load synset, val ground truth and val images list - synset = scipy.io.loadmat(os.path.join(devkit_dir, 'data', 'meta.mat')) - - ground_truth = open(os.path.join(devkit_dir, 'data', 'ILSVRC2012_validation_ground_truth.txt')) - lines = ground_truth.readlines() - labels = [int(line[:-1]) for line in lines] - - root, _, filenames = next(os.walk(val_dir)) - for filename in filenames: - # val image name -> ILSVRC ID -> WIND - val_id = int(filename.split('.')[0].split('_')[-1]) - ILSVRC_ID = labels[val_id-1] - WIND = synset['synsets'][ILSVRC_ID-1][0][1][0] - print("val_id:%d, ILSVRC_ID:%d, WIND:%s" % (val_id, ILSVRC_ID, WIND)) - - # move val images - output_dir = os.path.join(root, WIND) - if os.path.isdir(output_dir): - pass - else: - os.mkdir(output_dir) - shutil.move(os.path.join(root, filename), os.path.join(output_dir, filename)) - -def main(val_path, devkit_path): - move_valimg(val_path, devkit_path) - -if __name__ == '__main__': - val_path = sys.argv[1] - devkit_path = sys.argv[2] +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 sys +import os +import scipy +import shutil + + +def move_valimg(val_dir='./val', devkit_dir='./ILSVRC2012_devkit_t12'): + """ + move valimg to correspongding folders. + val_id(start from 1) -> ILSVRC_ID(start from 1) -> WIND + organize like: + /val + /n01440764 + images + /n01443537 + images + ..... + """ + # load synset, val ground truth and val images list + synset = scipy.io.loadmat(os.path.join(devkit_dir, 'data', 'meta.mat')) + + ground_truth = open(os.path.join(devkit_dir, 'data', 'ILSVRC2012_validation_ground_truth.txt')) + lines = ground_truth.readlines() + labels = [int(line[:-1]) for line in lines] + + root, _, filenames = next(os.walk(val_dir)) + for filename in filenames: + # val image name -> ILSVRC ID -> WIND + val_id = int(filename.split('.')[0].split('_')[-1]) + ILSVRC_ID = labels[val_id-1] + WIND = synset['synsets'][ILSVRC_ID-1][0][1][0] + print("val_id:%d, ILSVRC_ID:%d, WIND:%s" % (val_id, ILSVRC_ID, WIND)) + + # move val images + output_dir = os.path.join(root, WIND) + if os.path.isdir(output_dir): + pass + else: + os.mkdir(output_dir) + shutil.move(os.path.join(root, filename), os.path.join(output_dir, filename)) + +def main(val_path, devkit_path): + move_valimg(val_path, devkit_path) + +if __name__ == '__main__': + val_path = sys.argv[1] + devkit_path = sys.argv[2] main(val_path, devkit_path) \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/README.md b/PyTorch/contrib/cv/classification/EfficientNet-B1/README.md index 007a91b9f4..065d061eb2 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/README.md +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/README.md @@ -1,79 +1,79 @@ -# EfficientNet-B1 - -This implements training of Efficientnet-B1 on the ImageNet dataset, mainly modified from [pycls](https://github.com/facebookresearch/pycls). - -## EfficientNet-B1 Detail - -For details, see[pycls](https://github.com/facebookresearch/pycls). - - -## Requirements - -- Install PyTorch ([pytorch.org](http://pytorch.org)) -- apt install bc -- python3 -m pip install --upgrade Pillow -- git clone https://github.com/facebookresearch/pycls -- pip install -r requirements.txt -- Download the ImageNet2012 dataset - - train set:138GB - val set:6.3GB - ILSVRC2012_devkit_t12:2.45MB - - - Then, and move validation images to labeled subfolders, using ImageNet_val_split.py need download imageNet val and ILSVRC2012_devkit_t12 - - ```python - python3.7 ImageNet_val_split.py ./val ./ILSVRC2012_devkit_t12 - ``` - ``` - move valimg to correspongding folders. - official download the organize like: - /val - images - images - ...... - after the move the organize like: - - /val - /n01440764 - images - /n01443537 - images - ..... - ``` -## Training - -To train a model, run scripts with the desired model architecture and the path to the ImageNet dataset: - -```bash -# 1p training 1p -bash test/train_full_1p.sh --data_path=imageNet_root_path - -# 8p training 8p -bash test/train_full_8p.sh --data_path=imageNet_root_path - -# To ONNX -python3.7 Efficient-B1_pth2onnx.py ./Efficient-b1.onnx - -# eval default 8p, should support 1p -bash test/train_eval_8p.sh --data_path=imageNet_root_path - -# test performer -bash test/train_performance_1p.sh --data_path=imageNet_root_path -bash test/train_performance_8p.sh --data_path=imageNet_root_path - -# online inference demo -python3.7.5 demo.py - -``` - - -## EfficientNet-B1 training result - -| Acc@1 | FPS | Npu_nums | Epochs | AMP_Type | -| :----: | :--: | :------: | :----: | :------: | -| - | 451 | 1 | 100 | O2 | -| 74.445 | 2073 | 8 | 100 | O2 | - -FPS = BatchSize * num_devices / time_avg - +# EfficientNet-B1 + +This implements training of Efficientnet-B1 on the ImageNet dataset, mainly modified from [pycls](https://github.com/facebookresearch/pycls). + +## EfficientNet-B1 Detail + +For details, see[pycls](https://github.com/facebookresearch/pycls). + + +## Requirements + +- Install PyTorch ([pytorch.org](http://pytorch.org)) +- apt install bc +- python3 -m pip install --upgrade Pillow +- git clone https://github.com/facebookresearch/pycls +- pip install -r requirements.txt +- Download the ImageNet2012 dataset + + train set:138GB + val set:6.3GB + ILSVRC2012_devkit_t12:2.45MB + + - Then, and move validation images to labeled subfolders, using ImageNet_val_split.py need download imageNet val and ILSVRC2012_devkit_t12 + + ```python + python3.7 ImageNet_val_split.py ./val ./ILSVRC2012_devkit_t12 + ``` + ``` + move valimg to correspongding folders. + official download the organize like: + /val + images + images + ...... + after the move the organize like: + + /val + /n01440764 + images + /n01443537 + images + ..... + ``` +## Training + +To train a model, run scripts with the desired model architecture and the path to the ImageNet dataset: + +```bash +# 1p training 1p +bash test/train_full_1p.sh --data_path=imageNet_root_path + +# 8p training 8p +bash test/train_full_8p.sh --data_path=imageNet_root_path + +# To ONNX +python3.7 Efficient-B1_pth2onnx.py ./Efficient-b1.onnx + +# eval default 8p, should support 1p +bash test/train_eval_8p.sh --data_path=imageNet_root_path + +# test performer +bash test/train_performance_1p.sh --data_path=imageNet_root_path +bash test/train_performance_8p.sh --data_path=imageNet_root_path + +# online inference demo +python3.7.5 demo.py + +``` + + +## EfficientNet-B1 training result + +| Acc@1 | FPS | Npu_nums | Epochs | AMP_Type | +| :----: | :--: | :------: | :----: | :------: | +| - | 451 | 1 | 100 | O2 | +| 74.445 | 2073 | 8 | 100 | O2 | + +FPS = BatchSize * num_devices / time_avg + diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/anynet/R-110_nds_1gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/anynet/R-110_nds_1gpu.yaml index 74cdc86425..6eadd72f43 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/anynet/R-110_nds_1gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/anynet/R-110_nds_1gpu.yaml @@ -1,36 +1,36 @@ -MODEL: - TYPE: anynet - NUM_CLASSES: 10 -ANYNET: - STEM_TYPE: res_stem_cifar - STEM_W: 16 - BLOCK_TYPE: res_basic_block - DEPTHS: [18, 18, 18] - WIDTHS: [16, 32, 64] - STRIDES: [1, 2, 2] -BN: - USE_PRECISE_STATS: True - NUM_SAMPLES_PRECISE: 1024 -OPTIM: - BASE_LR: 0.1 - LR_POLICY: cos - MAX_EPOCH: 200 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0005 -TRAIN: - DATASET: cifar10 - SPLIT: train - BATCH_SIZE: 128 - IM_SIZE: 32 -TEST: - DATASET: cifar10 - SPLIT: test - BATCH_SIZE: 200 - IM_SIZE: 32 -NUM_GPUS: 1 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: False -OUT_DIR: . +MODEL: + TYPE: anynet + NUM_CLASSES: 10 +ANYNET: + STEM_TYPE: res_stem_cifar + STEM_W: 16 + BLOCK_TYPE: res_basic_block + DEPTHS: [18, 18, 18] + WIDTHS: [16, 32, 64] + STRIDES: [1, 2, 2] +BN: + USE_PRECISE_STATS: True + NUM_SAMPLES_PRECISE: 1024 +OPTIM: + BASE_LR: 0.1 + LR_POLICY: cos + MAX_EPOCH: 200 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0005 +TRAIN: + DATASET: cifar10 + SPLIT: train + BATCH_SIZE: 128 + IM_SIZE: 32 +TEST: + DATASET: cifar10 + SPLIT: test + BATCH_SIZE: 200 + IM_SIZE: 32 +NUM_GPUS: 1 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: False +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/anynet/R-56_nds_1gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/anynet/R-56_nds_1gpu.yaml index f03502a530..1052cf8da1 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/anynet/R-56_nds_1gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/anynet/R-56_nds_1gpu.yaml @@ -1,36 +1,36 @@ -MODEL: - TYPE: anynet - NUM_CLASSES: 10 -ANYNET: - STEM_TYPE: res_stem_cifar - STEM_W: 16 - BLOCK_TYPE: res_basic_block - DEPTHS: [9, 9, 9] - WIDTHS: [16, 32, 64] - STRIDES: [1, 2, 2] -BN: - USE_PRECISE_STATS: True - NUM_SAMPLES_PRECISE: 1024 -OPTIM: - BASE_LR: 0.1 - LR_POLICY: cos - MAX_EPOCH: 200 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0005 -TRAIN: - DATASET: cifar10 - SPLIT: train - BATCH_SIZE: 128 - IM_SIZE: 32 -TEST: - DATASET: cifar10 - SPLIT: test - BATCH_SIZE: 200 - IM_SIZE: 32 -NUM_GPUS: 1 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: False -OUT_DIR: . +MODEL: + TYPE: anynet + NUM_CLASSES: 10 +ANYNET: + STEM_TYPE: res_stem_cifar + STEM_W: 16 + BLOCK_TYPE: res_basic_block + DEPTHS: [9, 9, 9] + WIDTHS: [16, 32, 64] + STRIDES: [1, 2, 2] +BN: + USE_PRECISE_STATS: True + NUM_SAMPLES_PRECISE: 1024 +OPTIM: + BASE_LR: 0.1 + LR_POLICY: cos + MAX_EPOCH: 200 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0005 +TRAIN: + DATASET: cifar10 + SPLIT: train + BATCH_SIZE: 128 + IM_SIZE: 32 +TEST: + DATASET: cifar10 + SPLIT: test + BATCH_SIZE: 200 + IM_SIZE: 32 +NUM_GPUS: 1 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: False +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/anynet/V-56_nds_1gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/anynet/V-56_nds_1gpu.yaml index f360b943e2..615da0ba4e 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/anynet/V-56_nds_1gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/anynet/V-56_nds_1gpu.yaml @@ -1,36 +1,36 @@ -MODEL: - TYPE: anynet - NUM_CLASSES: 10 -ANYNET: - STEM_TYPE: res_stem_cifar - STEM_W: 16 - BLOCK_TYPE: vanilla_block - DEPTHS: [9, 9, 9] - WIDTHS: [16, 32, 64] - STRIDES: [1, 2, 2] -BN: - USE_PRECISE_STATS: True - NUM_SAMPLES_PRECISE: 1024 -OPTIM: - BASE_LR: 0.1 - LR_POLICY: cos - MAX_EPOCH: 200 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0005 -TRAIN: - DATASET: cifar10 - SPLIT: train - BATCH_SIZE: 128 - IM_SIZE: 32 -TEST: - DATASET: cifar10 - SPLIT: test - BATCH_SIZE: 200 - IM_SIZE: 32 -NUM_GPUS: 1 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: False -OUT_DIR: . +MODEL: + TYPE: anynet + NUM_CLASSES: 10 +ANYNET: + STEM_TYPE: res_stem_cifar + STEM_W: 16 + BLOCK_TYPE: vanilla_block + DEPTHS: [9, 9, 9] + WIDTHS: [16, 32, 64] + STRIDES: [1, 2, 2] +BN: + USE_PRECISE_STATS: True + NUM_SAMPLES_PRECISE: 1024 +OPTIM: + BASE_LR: 0.1 + LR_POLICY: cos + MAX_EPOCH: 200 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0005 +TRAIN: + DATASET: cifar10 + SPLIT: train + BATCH_SIZE: 128 + IM_SIZE: 32 +TEST: + DATASET: cifar10 + SPLIT: test + BATCH_SIZE: 200 + IM_SIZE: 32 +NUM_GPUS: 1 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: False +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/resnet/R-110_nds_1gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/resnet/R-110_nds_1gpu.yaml index b9ba81d33a..50948cbc4d 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/resnet/R-110_nds_1gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/resnet/R-110_nds_1gpu.yaml @@ -1,32 +1,32 @@ -MODEL: - TYPE: resnet - DEPTH: 110 - NUM_CLASSES: 10 -RESNET: - TRANS_FUN: basic_transform -BN: - USE_PRECISE_STATS: True - NUM_SAMPLES_PRECISE: 1024 -OPTIM: - BASE_LR: 0.1 - LR_POLICY: cos - MAX_EPOCH: 200 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0005 -TRAIN: - DATASET: cifar10 - SPLIT: train - BATCH_SIZE: 128 - IM_SIZE: 32 -TEST: - DATASET: cifar10 - SPLIT: test - BATCH_SIZE: 200 - IM_SIZE: 32 -NUM_GPUS: 1 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: False -OUT_DIR: . +MODEL: + TYPE: resnet + DEPTH: 110 + NUM_CLASSES: 10 +RESNET: + TRANS_FUN: basic_transform +BN: + USE_PRECISE_STATS: True + NUM_SAMPLES_PRECISE: 1024 +OPTIM: + BASE_LR: 0.1 + LR_POLICY: cos + MAX_EPOCH: 200 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0005 +TRAIN: + DATASET: cifar10 + SPLIT: train + BATCH_SIZE: 128 + IM_SIZE: 32 +TEST: + DATASET: cifar10 + SPLIT: test + BATCH_SIZE: 200 + IM_SIZE: 32 +NUM_GPUS: 1 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: False +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/resnet/R-56_nds_1gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/resnet/R-56_nds_1gpu.yaml index 8867c9ec38..afcf4901cf 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/resnet/R-56_nds_1gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/cifar/resnet/R-56_nds_1gpu.yaml @@ -1,32 +1,32 @@ -MODEL: - TYPE: resnet - DEPTH: 56 - NUM_CLASSES: 10 -RESNET: - TRANS_FUN: basic_transform -BN: - USE_PRECISE_STATS: True - NUM_SAMPLES_PRECISE: 1024 -OPTIM: - BASE_LR: 0.1 - LR_POLICY: cos - MAX_EPOCH: 200 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0005 -TRAIN: - DATASET: cifar10 - SPLIT: train - BATCH_SIZE: 128 - IM_SIZE: 32 -TEST: - DATASET: cifar10 - SPLIT: test - BATCH_SIZE: 200 - IM_SIZE: 32 -NUM_GPUS: 1 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: False -OUT_DIR: . +MODEL: + TYPE: resnet + DEPTH: 56 + NUM_CLASSES: 10 +RESNET: + TRANS_FUN: basic_transform +BN: + USE_PRECISE_STATS: True + NUM_SAMPLES_PRECISE: 1024 +OPTIM: + BASE_LR: 0.1 + LR_POLICY: cos + MAX_EPOCH: 200 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0005 +TRAIN: + DATASET: cifar10 + SPLIT: train + BATCH_SIZE: 128 + IM_SIZE: 32 +TEST: + DATASET: cifar10 + SPLIT: test + BATCH_SIZE: 200 + IM_SIZE: 32 +NUM_GPUS: 1 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: False +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-101-1x64d_step_1gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-101-1x64d_step_1gpu.yaml index cd102977a9..a1c05a9120 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-101-1x64d_step_1gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-101-1x64d_step_1gpu.yaml @@ -1,39 +1,39 @@ -MODEL: - TYPE: anynet - NUM_CLASSES: 1000 -ANYNET: - STEM_TYPE: res_stem_in - STEM_W: 64 - BLOCK_TYPE: res_bottleneck_block - DEPTHS: [3, 4, 23, 3] - WIDTHS: [256, 512, 1024, 2048] - STRIDES: [1, 2, 2, 2] - BOT_MULS: [0.25, 0.25, 0.25, 0.25] - GROUP_WS: [64, 128, 256, 512] -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.0125 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 32 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 25 - IM_SIZE: 256 -NUM_GPUS: 1 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: anynet + NUM_CLASSES: 1000 +ANYNET: + STEM_TYPE: res_stem_in + STEM_W: 64 + BLOCK_TYPE: res_bottleneck_block + DEPTHS: [3, 4, 23, 3] + WIDTHS: [256, 512, 1024, 2048] + STRIDES: [1, 2, 2, 2] + BOT_MULS: [0.25, 0.25, 0.25, 0.25] + GROUP_WS: [64, 128, 256, 512] +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.0125 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 32 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 25 + IM_SIZE: 256 +NUM_GPUS: 1 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-101-1x64d_step_2gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-101-1x64d_step_2gpu.yaml index e372857d2e..3ce5a54347 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-101-1x64d_step_2gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-101-1x64d_step_2gpu.yaml @@ -1,39 +1,39 @@ -MODEL: - TYPE: anynet - NUM_CLASSES: 1000 -ANYNET: - STEM_TYPE: res_stem_in - STEM_W: 64 - BLOCK_TYPE: res_bottleneck_block - DEPTHS: [3, 4, 23, 3] - WIDTHS: [256, 512, 1024, 2048] - STRIDES: [1, 2, 2, 2] - BOT_MULS: [0.25, 0.25, 0.25, 0.25] - GROUP_WS: [64, 128, 256, 512] -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.025 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 64 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 50 - IM_SIZE: 256 -NUM_GPUS: 2 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: anynet + NUM_CLASSES: 1000 +ANYNET: + STEM_TYPE: res_stem_in + STEM_W: 64 + BLOCK_TYPE: res_bottleneck_block + DEPTHS: [3, 4, 23, 3] + WIDTHS: [256, 512, 1024, 2048] + STRIDES: [1, 2, 2, 2] + BOT_MULS: [0.25, 0.25, 0.25, 0.25] + GROUP_WS: [64, 128, 256, 512] +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.025 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 64 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 50 + IM_SIZE: 256 +NUM_GPUS: 2 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-101-1x64d_step_8gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-101-1x64d_step_8gpu.yaml index bf6bfa173f..688dd1dc3e 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-101-1x64d_step_8gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-101-1x64d_step_8gpu.yaml @@ -1,39 +1,39 @@ -MODEL: - TYPE: anynet - NUM_CLASSES: 1000 -ANYNET: - STEM_TYPE: res_stem_in - STEM_W: 64 - BLOCK_TYPE: res_bottleneck_block - DEPTHS: [3, 4, 23, 3] - WIDTHS: [256, 512, 1024, 2048] - STRIDES: [1, 2, 2, 2] - BOT_MULS: [0.25, 0.25, 0.25, 0.25] - GROUP_WS: [64, 128, 256, 512] -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.1 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 256 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 200 - IM_SIZE: 256 -NUM_GPUS: 8 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: anynet + NUM_CLASSES: 1000 +ANYNET: + STEM_TYPE: res_stem_in + STEM_W: 64 + BLOCK_TYPE: res_bottleneck_block + DEPTHS: [3, 4, 23, 3] + WIDTHS: [256, 512, 1024, 2048] + STRIDES: [1, 2, 2, 2] + BOT_MULS: [0.25, 0.25, 0.25, 0.25] + GROUP_WS: [64, 128, 256, 512] +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.1 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 256 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 200 + IM_SIZE: 256 +NUM_GPUS: 8 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-50-1x64d_step_1gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-50-1x64d_step_1gpu.yaml index 993c43b5f4..a43a96606d 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-50-1x64d_step_1gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-50-1x64d_step_1gpu.yaml @@ -1,39 +1,39 @@ -MODEL: - TYPE: anynet - NUM_CLASSES: 1000 -ANYNET: - STEM_TYPE: res_stem_in - STEM_W: 64 - BLOCK_TYPE: res_bottleneck_block - DEPTHS: [3, 4, 6, 3] - WIDTHS: [256, 512, 1024, 2048] - STRIDES: [1, 2, 2, 2] - BOT_MULS: [0.25, 0.25, 0.25, 0.25] - GROUP_WS: [64, 128, 256, 512] -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.0125 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 32 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 25 - IM_SIZE: 256 -NUM_GPUS: 1 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: anynet + NUM_CLASSES: 1000 +ANYNET: + STEM_TYPE: res_stem_in + STEM_W: 64 + BLOCK_TYPE: res_bottleneck_block + DEPTHS: [3, 4, 6, 3] + WIDTHS: [256, 512, 1024, 2048] + STRIDES: [1, 2, 2, 2] + BOT_MULS: [0.25, 0.25, 0.25, 0.25] + GROUP_WS: [64, 128, 256, 512] +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.0125 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 32 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 25 + IM_SIZE: 256 +NUM_GPUS: 1 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-50-1x64d_step_2gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-50-1x64d_step_2gpu.yaml index 428e4cdb5d..064992f3a3 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-50-1x64d_step_2gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-50-1x64d_step_2gpu.yaml @@ -1,39 +1,39 @@ -MODEL: - TYPE: anynet - NUM_CLASSES: 1000 -ANYNET: - STEM_TYPE: res_stem_in - STEM_W: 64 - BLOCK_TYPE: res_bottleneck_block - DEPTHS: [3, 4, 6, 3] - WIDTHS: [256, 512, 1024, 2048] - STRIDES: [1, 2, 2, 2] - BOT_MULS: [0.25, 0.25, 0.25, 0.25] - GROUP_WS: [64, 128, 256, 512] -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.025 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 64 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 50 - IM_SIZE: 256 -NUM_GPUS: 2 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: anynet + NUM_CLASSES: 1000 +ANYNET: + STEM_TYPE: res_stem_in + STEM_W: 64 + BLOCK_TYPE: res_bottleneck_block + DEPTHS: [3, 4, 6, 3] + WIDTHS: [256, 512, 1024, 2048] + STRIDES: [1, 2, 2, 2] + BOT_MULS: [0.25, 0.25, 0.25, 0.25] + GROUP_WS: [64, 128, 256, 512] +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.025 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 64 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 50 + IM_SIZE: 256 +NUM_GPUS: 2 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-50-1x64d_step_8gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-50-1x64d_step_8gpu.yaml index adae774a74..abe4b8c9ee 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-50-1x64d_step_8gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/R-50-1x64d_step_8gpu.yaml @@ -1,39 +1,39 @@ -MODEL: - TYPE: anynet - NUM_CLASSES: 1000 -ANYNET: - STEM_TYPE: res_stem_in - STEM_W: 64 - BLOCK_TYPE: res_bottleneck_block - DEPTHS: [3, 4, 6, 3] - WIDTHS: [256, 512, 1024, 2048] - STRIDES: [1, 2, 2, 2] - BOT_MULS: [0.25, 0.25, 0.25, 0.25] - GROUP_WS: [64, 128, 256, 512] -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.1 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 256 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 200 - IM_SIZE: 256 -NUM_GPUS: 8 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: anynet + NUM_CLASSES: 1000 +ANYNET: + STEM_TYPE: res_stem_in + STEM_W: 64 + BLOCK_TYPE: res_bottleneck_block + DEPTHS: [3, 4, 6, 3] + WIDTHS: [256, 512, 1024, 2048] + STRIDES: [1, 2, 2, 2] + BOT_MULS: [0.25, 0.25, 0.25, 0.25] + GROUP_WS: [64, 128, 256, 512] +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.1 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 256 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 200 + IM_SIZE: 256 +NUM_GPUS: 8 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-101-32x4d_step_1gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-101-32x4d_step_1gpu.yaml index 845ea5fe30..26b7b1f64e 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-101-32x4d_step_1gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-101-32x4d_step_1gpu.yaml @@ -1,39 +1,39 @@ -MODEL: - TYPE: anynet - NUM_CLASSES: 1000 -ANYNET: - STEM_TYPE: res_stem_in - STEM_W: 64 - BLOCK_TYPE: res_bottleneck_block - DEPTHS: [3, 4, 23, 3] - WIDTHS: [256, 512, 1024, 2048] - STRIDES: [1, 2, 2, 2] - BOT_MULS: [0.5, 0.5, 0.5, 0.5] - GROUP_WS: [4, 8, 16, 32] -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.0125 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 32 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 25 - IM_SIZE: 256 -NUM_GPUS: 1 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: anynet + NUM_CLASSES: 1000 +ANYNET: + STEM_TYPE: res_stem_in + STEM_W: 64 + BLOCK_TYPE: res_bottleneck_block + DEPTHS: [3, 4, 23, 3] + WIDTHS: [256, 512, 1024, 2048] + STRIDES: [1, 2, 2, 2] + BOT_MULS: [0.5, 0.5, 0.5, 0.5] + GROUP_WS: [4, 8, 16, 32] +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.0125 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 32 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 25 + IM_SIZE: 256 +NUM_GPUS: 1 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-101-32x4d_step_2gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-101-32x4d_step_2gpu.yaml index c4e15b8dfc..317b4e88e2 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-101-32x4d_step_2gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-101-32x4d_step_2gpu.yaml @@ -1,39 +1,39 @@ -MODEL: - TYPE: anynet - NUM_CLASSES: 1000 -ANYNET: - STEM_TYPE: res_stem_in - STEM_W: 64 - BLOCK_TYPE: res_bottleneck_block - DEPTHS: [3, 4, 23, 3] - WIDTHS: [256, 512, 1024, 2048] - STRIDES: [1, 2, 2, 2] - BOT_MULS: [0.5, 0.5, 0.5, 0.5] - GROUP_WS: [4, 8, 16, 32] -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.025 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 64 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 50 - IM_SIZE: 256 -NUM_GPUS: 2 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: anynet + NUM_CLASSES: 1000 +ANYNET: + STEM_TYPE: res_stem_in + STEM_W: 64 + BLOCK_TYPE: res_bottleneck_block + DEPTHS: [3, 4, 23, 3] + WIDTHS: [256, 512, 1024, 2048] + STRIDES: [1, 2, 2, 2] + BOT_MULS: [0.5, 0.5, 0.5, 0.5] + GROUP_WS: [4, 8, 16, 32] +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.025 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 64 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 50 + IM_SIZE: 256 +NUM_GPUS: 2 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-101-32x4d_step_8gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-101-32x4d_step_8gpu.yaml index 8969c2270c..c4c0ff040b 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-101-32x4d_step_8gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-101-32x4d_step_8gpu.yaml @@ -1,39 +1,39 @@ -MODEL: - TYPE: anynet - NUM_CLASSES: 1000 -ANYNET: - STEM_TYPE: res_stem_in - STEM_W: 64 - BLOCK_TYPE: res_bottleneck_block - DEPTHS: [3, 4, 23, 3] - WIDTHS: [256, 512, 1024, 2048] - STRIDES: [1, 2, 2, 2] - BOT_MULS: [0.5, 0.5, 0.5, 0.5] - GROUP_WS: [4, 8, 16, 32] -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.1 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 256 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 200 - IM_SIZE: 256 -NUM_GPUS: 8 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: anynet + NUM_CLASSES: 1000 +ANYNET: + STEM_TYPE: res_stem_in + STEM_W: 64 + BLOCK_TYPE: res_bottleneck_block + DEPTHS: [3, 4, 23, 3] + WIDTHS: [256, 512, 1024, 2048] + STRIDES: [1, 2, 2, 2] + BOT_MULS: [0.5, 0.5, 0.5, 0.5] + GROUP_WS: [4, 8, 16, 32] +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.1 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 256 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 200 + IM_SIZE: 256 +NUM_GPUS: 8 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-50-32x4d_step_1gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-50-32x4d_step_1gpu.yaml index 042570a12e..2ad4222356 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-50-32x4d_step_1gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-50-32x4d_step_1gpu.yaml @@ -1,39 +1,39 @@ -MODEL: - TYPE: anynet - NUM_CLASSES: 1000 -ANYNET: - STEM_TYPE: res_stem_in - STEM_W: 64 - BLOCK_TYPE: res_bottleneck_block - DEPTHS: [3, 4, 6, 3] - WIDTHS: [256, 512, 1024, 2048] - STRIDES: [1, 2, 2, 2] - BOT_MULS: [0.5, 0.5, 0.5, 0.5] - GROUP_WS: [4, 8, 16, 32] -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.0125 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 32 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 25 - IM_SIZE: 256 -NUM_GPUS: 1 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: anynet + NUM_CLASSES: 1000 +ANYNET: + STEM_TYPE: res_stem_in + STEM_W: 64 + BLOCK_TYPE: res_bottleneck_block + DEPTHS: [3, 4, 6, 3] + WIDTHS: [256, 512, 1024, 2048] + STRIDES: [1, 2, 2, 2] + BOT_MULS: [0.5, 0.5, 0.5, 0.5] + GROUP_WS: [4, 8, 16, 32] +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.0125 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 32 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 25 + IM_SIZE: 256 +NUM_GPUS: 1 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-50-32x4d_step_2gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-50-32x4d_step_2gpu.yaml index df1123c51d..a899bb9513 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-50-32x4d_step_2gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-50-32x4d_step_2gpu.yaml @@ -1,39 +1,39 @@ -MODEL: - TYPE: anynet - NUM_CLASSES: 1000 -ANYNET: - STEM_TYPE: res_stem_in - STEM_W: 64 - BLOCK_TYPE: res_bottleneck_block - DEPTHS: [3, 4, 6, 3] - WIDTHS: [256, 512, 1024, 2048] - STRIDES: [1, 2, 2, 2] - BOT_MULS: [0.5, 0.5, 0.5, 0.5] - GROUP_WS: [4, 8, 16, 32] -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.025 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 64 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 50 - IM_SIZE: 256 -NUM_GPUS: 2 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: anynet + NUM_CLASSES: 1000 +ANYNET: + STEM_TYPE: res_stem_in + STEM_W: 64 + BLOCK_TYPE: res_bottleneck_block + DEPTHS: [3, 4, 6, 3] + WIDTHS: [256, 512, 1024, 2048] + STRIDES: [1, 2, 2, 2] + BOT_MULS: [0.5, 0.5, 0.5, 0.5] + GROUP_WS: [4, 8, 16, 32] +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.025 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 64 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 50 + IM_SIZE: 256 +NUM_GPUS: 2 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-50-32x4d_step_8gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-50-32x4d_step_8gpu.yaml index 9496b464c5..9746fac79a 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-50-32x4d_step_8gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/anynet/X-50-32x4d_step_8gpu.yaml @@ -1,39 +1,39 @@ -MODEL: - TYPE: anynet - NUM_CLASSES: 1000 -ANYNET: - STEM_TYPE: res_stem_in - STEM_W: 64 - BLOCK_TYPE: res_bottleneck_block - DEPTHS: [3, 4, 6, 3] - WIDTHS: [256, 512, 1024, 2048] - STRIDES: [1, 2, 2, 2] - BOT_MULS: [0.5, 0.5, 0.5, 0.5] - GROUP_WS: [4, 8, 16, 32] -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.1 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 256 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 200 - IM_SIZE: 256 -NUM_GPUS: 8 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: anynet + NUM_CLASSES: 1000 +ANYNET: + STEM_TYPE: res_stem_in + STEM_W: 64 + BLOCK_TYPE: res_bottleneck_block + DEPTHS: [3, 4, 6, 3] + WIDTHS: [256, 512, 1024, 2048] + STRIDES: [1, 2, 2, 2] + BOT_MULS: [0.5, 0.5, 0.5, 0.5] + GROUP_WS: [4, 8, 16, 32] +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.1 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 256 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 200 + IM_SIZE: 256 +NUM_GPUS: 8 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-101-1x64d_step_1gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-101-1x64d_step_1gpu.yaml index f8e3c54657..757d69e49d 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-101-1x64d_step_1gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-101-1x64d_step_1gpu.yaml @@ -1,36 +1,36 @@ -MODEL: - TYPE: resnet - DEPTH: 101 - NUM_CLASSES: 1000 -RESNET: - TRANS_FUN: bottleneck_transform - NUM_GROUPS: 1 - WIDTH_PER_GROUP: 64 - STRIDE_1X1: False -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.0125 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 32 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 25 - IM_SIZE: 256 -NUM_GPUS: 1 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: resnet + DEPTH: 101 + NUM_CLASSES: 1000 +RESNET: + TRANS_FUN: bottleneck_transform + NUM_GROUPS: 1 + WIDTH_PER_GROUP: 64 + STRIDE_1X1: False +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.0125 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 32 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 25 + IM_SIZE: 256 +NUM_GPUS: 1 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-101-1x64d_step_2gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-101-1x64d_step_2gpu.yaml index c48ce042f0..e31acbc146 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-101-1x64d_step_2gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-101-1x64d_step_2gpu.yaml @@ -1,36 +1,36 @@ -MODEL: - TYPE: resnet - DEPTH: 101 - NUM_CLASSES: 1000 -RESNET: - TRANS_FUN: bottleneck_transform - NUM_GROUPS: 1 - WIDTH_PER_GROUP: 64 - STRIDE_1X1: False -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.025 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 64 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 50 - IM_SIZE: 256 -NUM_GPUS: 2 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: resnet + DEPTH: 101 + NUM_CLASSES: 1000 +RESNET: + TRANS_FUN: bottleneck_transform + NUM_GROUPS: 1 + WIDTH_PER_GROUP: 64 + STRIDE_1X1: False +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.025 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 64 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 50 + IM_SIZE: 256 +NUM_GPUS: 2 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-101-1x64d_step_8gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-101-1x64d_step_8gpu.yaml index 5f6cfa8394..473a15b5fe 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-101-1x64d_step_8gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-101-1x64d_step_8gpu.yaml @@ -1,36 +1,36 @@ -MODEL: - TYPE: resnet - DEPTH: 101 - NUM_CLASSES: 1000 -RESNET: - TRANS_FUN: bottleneck_transform - NUM_GROUPS: 1 - WIDTH_PER_GROUP: 64 - STRIDE_1X1: False -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.1 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 256 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 200 - IM_SIZE: 256 -NUM_GPUS: 8 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: resnet + DEPTH: 101 + NUM_CLASSES: 1000 +RESNET: + TRANS_FUN: bottleneck_transform + NUM_GROUPS: 1 + WIDTH_PER_GROUP: 64 + STRIDE_1X1: False +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.1 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 256 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 200 + IM_SIZE: 256 +NUM_GPUS: 8 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-50-1x64d_step_1gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-50-1x64d_step_1gpu.yaml index b1c97d7ddc..327e5a5971 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-50-1x64d_step_1gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-50-1x64d_step_1gpu.yaml @@ -1,36 +1,36 @@ -MODEL: - TYPE: resnet - DEPTH: 50 - NUM_CLASSES: 1000 -RESNET: - TRANS_FUN: bottleneck_transform - NUM_GROUPS: 1 - WIDTH_PER_GROUP: 64 - STRIDE_1X1: False -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.0125 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 32 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 25 - IM_SIZE: 256 -NUM_GPUS: 1 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: resnet + DEPTH: 50 + NUM_CLASSES: 1000 +RESNET: + TRANS_FUN: bottleneck_transform + NUM_GROUPS: 1 + WIDTH_PER_GROUP: 64 + STRIDE_1X1: False +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.0125 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 32 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 25 + IM_SIZE: 256 +NUM_GPUS: 1 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-50-1x64d_step_2gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-50-1x64d_step_2gpu.yaml index 973c3ffd4e..1278d9c69c 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-50-1x64d_step_2gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-50-1x64d_step_2gpu.yaml @@ -1,36 +1,36 @@ -MODEL: - TYPE: resnet - DEPTH: 50 - NUM_CLASSES: 1000 -RESNET: - TRANS_FUN: bottleneck_transform - NUM_GROUPS: 1 - WIDTH_PER_GROUP: 64 - STRIDE_1X1: False -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.025 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 64 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 50 - IM_SIZE: 256 -NUM_GPUS: 2 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: resnet + DEPTH: 50 + NUM_CLASSES: 1000 +RESNET: + TRANS_FUN: bottleneck_transform + NUM_GROUPS: 1 + WIDTH_PER_GROUP: 64 + STRIDE_1X1: False +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.025 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 64 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 50 + IM_SIZE: 256 +NUM_GPUS: 2 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-50-1x64d_step_8gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-50-1x64d_step_8gpu.yaml index fabb4ec183..e6739d7cab 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-50-1x64d_step_8gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/R-50-1x64d_step_8gpu.yaml @@ -1,36 +1,36 @@ -MODEL: - TYPE: resnet - DEPTH: 50 - NUM_CLASSES: 1000 -RESNET: - TRANS_FUN: bottleneck_transform - NUM_GROUPS: 1 - WIDTH_PER_GROUP: 64 - STRIDE_1X1: False -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.1 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 256 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 200 - IM_SIZE: 256 -NUM_GPUS: 8 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: resnet + DEPTH: 50 + NUM_CLASSES: 1000 +RESNET: + TRANS_FUN: bottleneck_transform + NUM_GROUPS: 1 + WIDTH_PER_GROUP: 64 + STRIDE_1X1: False +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.1 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 256 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 200 + IM_SIZE: 256 +NUM_GPUS: 8 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-101-32x4d_step_1gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-101-32x4d_step_1gpu.yaml index def7d1561f..91604235f8 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-101-32x4d_step_1gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-101-32x4d_step_1gpu.yaml @@ -1,36 +1,36 @@ -MODEL: - TYPE: resnet - DEPTH: 101 - NUM_CLASSES: 1000 -RESNET: - TRANS_FUN: bottleneck_transform - NUM_GROUPS: 32 - WIDTH_PER_GROUP: 4 - STRIDE_1X1: False -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.0125 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 32 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 25 - IM_SIZE: 256 -NUM_GPUS: 1 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: resnet + DEPTH: 101 + NUM_CLASSES: 1000 +RESNET: + TRANS_FUN: bottleneck_transform + NUM_GROUPS: 32 + WIDTH_PER_GROUP: 4 + STRIDE_1X1: False +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.0125 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 32 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 25 + IM_SIZE: 256 +NUM_GPUS: 1 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-101-32x4d_step_2gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-101-32x4d_step_2gpu.yaml index 5b69a7b4e5..f051c81b25 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-101-32x4d_step_2gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-101-32x4d_step_2gpu.yaml @@ -1,36 +1,36 @@ -MODEL: - TYPE: resnet - DEPTH: 101 - NUM_CLASSES: 1000 -RESNET: - TRANS_FUN: bottleneck_transform - NUM_GROUPS: 32 - WIDTH_PER_GROUP: 4 - STRIDE_1X1: False -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.025 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 64 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 50 - IM_SIZE: 256 -NUM_GPUS: 2 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: resnet + DEPTH: 101 + NUM_CLASSES: 1000 +RESNET: + TRANS_FUN: bottleneck_transform + NUM_GROUPS: 32 + WIDTH_PER_GROUP: 4 + STRIDE_1X1: False +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.025 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 64 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 50 + IM_SIZE: 256 +NUM_GPUS: 2 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-101-32x4d_step_8gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-101-32x4d_step_8gpu.yaml index 60bcd42800..c34fedbb03 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-101-32x4d_step_8gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-101-32x4d_step_8gpu.yaml @@ -1,36 +1,36 @@ -MODEL: - TYPE: resnet - DEPTH: 101 - NUM_CLASSES: 1000 -RESNET: - TRANS_FUN: bottleneck_transform - NUM_GROUPS: 32 - WIDTH_PER_GROUP: 4 - STRIDE_1X1: False -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.1 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 256 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 200 - IM_SIZE: 256 -NUM_GPUS: 8 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: resnet + DEPTH: 101 + NUM_CLASSES: 1000 +RESNET: + TRANS_FUN: bottleneck_transform + NUM_GROUPS: 32 + WIDTH_PER_GROUP: 4 + STRIDE_1X1: False +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.1 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 256 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 200 + IM_SIZE: 256 +NUM_GPUS: 8 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-50-32x4d_step_1gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-50-32x4d_step_1gpu.yaml index a0449e8d8a..130b619512 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-50-32x4d_step_1gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-50-32x4d_step_1gpu.yaml @@ -1,36 +1,36 @@ -MODEL: - TYPE: resnet - DEPTH: 50 - NUM_CLASSES: 1000 -RESNET: - TRANS_FUN: bottleneck_transform - NUM_GROUPS: 32 - WIDTH_PER_GROUP: 4 - STRIDE_1X1: False -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.0125 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 32 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 25 - IM_SIZE: 256 -NUM_GPUS: 1 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: resnet + DEPTH: 50 + NUM_CLASSES: 1000 +RESNET: + TRANS_FUN: bottleneck_transform + NUM_GROUPS: 32 + WIDTH_PER_GROUP: 4 + STRIDE_1X1: False +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.0125 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 32 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 25 + IM_SIZE: 256 +NUM_GPUS: 1 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-50-32x4d_step_2gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-50-32x4d_step_2gpu.yaml index 717365d00f..621d9f3a72 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-50-32x4d_step_2gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-50-32x4d_step_2gpu.yaml @@ -1,36 +1,36 @@ -MODEL: - TYPE: resnet - DEPTH: 50 - NUM_CLASSES: 1000 -RESNET: - TRANS_FUN: bottleneck_transform - NUM_GROUPS: 32 - WIDTH_PER_GROUP: 4 - STRIDE_1X1: False -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.025 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 64 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 50 - IM_SIZE: 256 -NUM_GPUS: 2 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: resnet + DEPTH: 50 + NUM_CLASSES: 1000 +RESNET: + TRANS_FUN: bottleneck_transform + NUM_GROUPS: 32 + WIDTH_PER_GROUP: 4 + STRIDE_1X1: False +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.025 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 64 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 50 + IM_SIZE: 256 +NUM_GPUS: 2 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-50-32x4d_step_8gpu.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-50-32x4d_step_8gpu.yaml index 14cac7547c..2a64873219 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-50-32x4d_step_8gpu.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/archive/imagenet/resnet/X-50-32x4d_step_8gpu.yaml @@ -1,36 +1,36 @@ -MODEL: - TYPE: resnet - DEPTH: 50 - NUM_CLASSES: 1000 -RESNET: - TRANS_FUN: bottleneck_transform - NUM_GROUPS: 32 - WIDTH_PER_GROUP: 4 - STRIDE_1X1: False -BN: - ZERO_INIT_FINAL_GAMMA: True -OPTIM: - BASE_LR: 0.1 - LR_POLICY: steps - STEPS: [0, 30, 60, 90] - LR_MULT: 0.1 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - NESTEROV: True - WEIGHT_DECAY: 0.0001 -TRAIN: - DATASET: imagenet - SPLIT: train - BATCH_SIZE: 256 - IM_SIZE: 224 -TEST: - DATASET: imagenet - SPLIT: val - BATCH_SIZE: 200 - IM_SIZE: 256 -NUM_GPUS: 8 -DATA_LOADER: - NUM_WORKERS: 4 -CUDNN: - BENCHMARK: True -OUT_DIR: . +MODEL: + TYPE: resnet + DEPTH: 50 + NUM_CLASSES: 1000 +RESNET: + TRANS_FUN: bottleneck_transform + NUM_GROUPS: 32 + WIDTH_PER_GROUP: 4 + STRIDE_1X1: False +BN: + ZERO_INIT_FINAL_GAMMA: True +OPTIM: + BASE_LR: 0.1 + LR_POLICY: steps + STEPS: [0, 30, 60, 90] + LR_MULT: 0.1 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + NESTEROV: True + WEIGHT_DECAY: 0.0001 +TRAIN: + DATASET: imagenet + SPLIT: train + BATCH_SIZE: 256 + IM_SIZE: 224 +TEST: + DATASET: imagenet + SPLIT: val + BATCH_SIZE: 200 + IM_SIZE: 256 +NUM_GPUS: 8 +DATA_LOADER: + NUM_WORKERS: 4 +CUDNN: + BENCHMARK: True +OUT_DIR: . diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/dds_baselines/effnet/EN-B1_dds_1npu_full.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/dds_baselines/effnet/EN-B1_dds_1npu_full.yaml index c8580e9ccc..973db49bdc 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/dds_baselines/effnet/EN-B1_dds_1npu_full.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/dds_baselines/effnet/EN-B1_dds_1npu_full.yaml @@ -1,28 +1,28 @@ -MODEL: - TYPE: effnet - NUM_CLASSES: 1000 - ACTIVATION_FUN: silu -EN: - STEM_W: 32 - STRIDES: [1, 2, 2, 2, 1, 2, 1] - DEPTHS: [2, 3, 3, 4, 4, 5, 2] - WIDTHS: [16, 24, 40, 80, 112, 192, 320] - EXP_RATIOS: [1, 6, 6, 6, 6, 6, 6] - KERNELS: [3, 3, 5, 3, 5, 5, 3] - HEAD_W: 1280 -OPTIM: - LR_POLICY: cos - BASE_LR: 0.4 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - WEIGHT_DECAY: 1e-5 -TRAIN: - DATASET: imagenet - IM_SIZE: 240 - BATCH_SIZE: 256 -TEST: - DATASET: imagenet - IM_SIZE: 274 - BATCH_SIZE: 200 -NUM_GPUS: 1 +MODEL: + TYPE: effnet + NUM_CLASSES: 1000 + ACTIVATION_FUN: silu +EN: + STEM_W: 32 + STRIDES: [1, 2, 2, 2, 1, 2, 1] + DEPTHS: [2, 3, 3, 4, 4, 5, 2] + WIDTHS: [16, 24, 40, 80, 112, 192, 320] + EXP_RATIOS: [1, 6, 6, 6, 6, 6, 6] + KERNELS: [3, 3, 5, 3, 5, 5, 3] + HEAD_W: 1280 +OPTIM: + LR_POLICY: cos + BASE_LR: 0.4 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + WEIGHT_DECAY: 1e-5 +TRAIN: + DATASET: imagenet + IM_SIZE: 240 + BATCH_SIZE: 256 +TEST: + DATASET: imagenet + IM_SIZE: 274 + BATCH_SIZE: 200 +NUM_GPUS: 1 OUT_DIR: . \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/dds_baselines/effnet/EN-B1_dds_1npu_perf.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/dds_baselines/effnet/EN-B1_dds_1npu_perf.yaml index 33497cb51c..1cd1550453 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/dds_baselines/effnet/EN-B1_dds_1npu_perf.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/dds_baselines/effnet/EN-B1_dds_1npu_perf.yaml @@ -1,28 +1,28 @@ -MODEL: - TYPE: effnet - NUM_CLASSES: 1000 - ACTIVATION_FUN: silu -EN: - STEM_W: 32 - STRIDES: [1, 2, 2, 2, 1, 2, 1] - DEPTHS: [2, 3, 3, 4, 4, 5, 2] - WIDTHS: [16, 24, 40, 80, 112, 192, 320] - EXP_RATIOS: [1, 6, 6, 6, 6, 6, 6] - KERNELS: [3, 3, 5, 3, 5, 5, 3] - HEAD_W: 1280 -OPTIM: - LR_POLICY: cos - BASE_LR: 0.4 - MAX_EPOCH: 1 - MOMENTUM: 0.9 - WEIGHT_DECAY: 1e-5 -TRAIN: - DATASET: imagenet - IM_SIZE: 240 - BATCH_SIZE: 256 -TEST: - DATASET: imagenet - IM_SIZE: 274 - BATCH_SIZE: 200 -NUM_GPUS: 1 +MODEL: + TYPE: effnet + NUM_CLASSES: 1000 + ACTIVATION_FUN: silu +EN: + STEM_W: 32 + STRIDES: [1, 2, 2, 2, 1, 2, 1] + DEPTHS: [2, 3, 3, 4, 4, 5, 2] + WIDTHS: [16, 24, 40, 80, 112, 192, 320] + EXP_RATIOS: [1, 6, 6, 6, 6, 6, 6] + KERNELS: [3, 3, 5, 3, 5, 5, 3] + HEAD_W: 1280 +OPTIM: + LR_POLICY: cos + BASE_LR: 0.4 + MAX_EPOCH: 1 + MOMENTUM: 0.9 + WEIGHT_DECAY: 1e-5 +TRAIN: + DATASET: imagenet + IM_SIZE: 240 + BATCH_SIZE: 256 +TEST: + DATASET: imagenet + IM_SIZE: 274 + BATCH_SIZE: 200 +NUM_GPUS: 1 OUT_DIR: . \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/dds_baselines/effnet/EN-B1_dds_8npu_full.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/dds_baselines/effnet/EN-B1_dds_8npu_full.yaml index 989ace3885..22bbe5937e 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/dds_baselines/effnet/EN-B1_dds_8npu_full.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/dds_baselines/effnet/EN-B1_dds_8npu_full.yaml @@ -1,28 +1,28 @@ -MODEL: - TYPE: effnet - NUM_CLASSES: 1000 - ACTIVATION_FUN: silu -EN: - STEM_W: 32 - STRIDES: [1, 2, 2, 2, 1, 2, 1] - DEPTHS: [2, 3, 3, 4, 4, 5, 2] - WIDTHS: [16, 24, 40, 80, 112, 192, 320] - EXP_RATIOS: [1, 6, 6, 6, 6, 6, 6] - KERNELS: [3, 3, 5, 3, 5, 5, 3] - HEAD_W: 1280 -OPTIM: - LR_POLICY: cos - BASE_LR: 0.4 - MAX_EPOCH: 100 - MOMENTUM: 0.9 - WEIGHT_DECAY: 1e-5 -TRAIN: - DATASET: imagenet - IM_SIZE: 240 - BATCH_SIZE: 1280 -TEST: - DATASET: imagenet - IM_SIZE: 274 - BATCH_SIZE: 800 -NUM_GPUS: 8 +MODEL: + TYPE: effnet + NUM_CLASSES: 1000 + ACTIVATION_FUN: silu +EN: + STEM_W: 32 + STRIDES: [1, 2, 2, 2, 1, 2, 1] + DEPTHS: [2, 3, 3, 4, 4, 5, 2] + WIDTHS: [16, 24, 40, 80, 112, 192, 320] + EXP_RATIOS: [1, 6, 6, 6, 6, 6, 6] + KERNELS: [3, 3, 5, 3, 5, 5, 3] + HEAD_W: 1280 +OPTIM: + LR_POLICY: cos + BASE_LR: 0.4 + MAX_EPOCH: 100 + MOMENTUM: 0.9 + WEIGHT_DECAY: 1e-5 +TRAIN: + DATASET: imagenet + IM_SIZE: 240 + BATCH_SIZE: 1280 +TEST: + DATASET: imagenet + IM_SIZE: 274 + BATCH_SIZE: 800 +NUM_GPUS: 8 OUT_DIR: . \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/dds_baselines/effnet/EN-B1_dds_8npu_perf.yaml b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/dds_baselines/effnet/EN-B1_dds_8npu_perf.yaml index 434bdc23b4..91530e4977 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/dds_baselines/effnet/EN-B1_dds_8npu_perf.yaml +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/configs/dds_baselines/effnet/EN-B1_dds_8npu_perf.yaml @@ -1,28 +1,28 @@ -MODEL: - TYPE: effnet - NUM_CLASSES: 1000 - ACTIVATION_FUN: silu -EN: - STEM_W: 32 - STRIDES: [1, 2, 2, 2, 1, 2, 1] - DEPTHS: [2, 3, 3, 4, 4, 5, 2] - WIDTHS: [16, 24, 40, 80, 112, 192, 320] - EXP_RATIOS: [1, 6, 6, 6, 6, 6, 6] - KERNELS: [3, 3, 5, 3, 5, 5, 3] - HEAD_W: 1280 -OPTIM: - LR_POLICY: cos - BASE_LR: 0.4 - MAX_EPOCH: 1 - MOMENTUM: 0.9 - WEIGHT_DECAY: 1e-5 -TRAIN: - DATASET: imagenet - IM_SIZE: 240 - BATCH_SIZE: 1280 -TEST: - DATASET: imagenet - IM_SIZE: 274 - BATCH_SIZE: 800 -NUM_GPUS: 8 +MODEL: + TYPE: effnet + NUM_CLASSES: 1000 + ACTIVATION_FUN: silu +EN: + STEM_W: 32 + STRIDES: [1, 2, 2, 2, 1, 2, 1] + DEPTHS: [2, 3, 3, 4, 4, 5, 2] + WIDTHS: [16, 24, 40, 80, 112, 192, 320] + EXP_RATIOS: [1, 6, 6, 6, 6, 6, 6] + KERNELS: [3, 3, 5, 3, 5, 5, 3] + HEAD_W: 1280 +OPTIM: + LR_POLICY: cos + BASE_LR: 0.4 + MAX_EPOCH: 1 + MOMENTUM: 0.9 + WEIGHT_DECAY: 1e-5 +TRAIN: + DATASET: imagenet + IM_SIZE: 240 + BATCH_SIZE: 1280 +TEST: + DATASET: imagenet + IM_SIZE: 274 + BATCH_SIZE: 800 +NUM_GPUS: 8 OUT_DIR: . \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/demo.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/demo.py index ffbbd4b777..dcfc3292a7 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/demo.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/demo.py @@ -1,64 +1,64 @@ -#!/usr/bin/env python3 -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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 torch -import numpy as np -import pycls.core.config as config -from pycls.core.config import cfg -import pycls.datasets.transforms as transforms -from pycls.models.effnet import EffNet - - -def build_model(): - config.merge_from_file('configs/dds_baselines/effnet/EN-B1_dds_8npu.yaml') - cfg.freeze() - model = EffNet() - checkpoint = torch.load('result/model.pyth') - model.load_state_dict(checkpoint["model_state"], False) - model.eval() - return model - - -def get_raw_data(): - from PIL import Image - from urllib.request import urlretrieve - IMAGE_URL = 'https://bbs-img.huaweicloud.com/blogs/img/thumb/1591951315139_8989_1363.png' - urlretrieve(IMAGE_URL, 'tmp.jpg') - img = Image.open("tmp.jpg") - img = img.convert('RGB') - return img - - -def pre_process(raw_data): - from torchvision import transforms - normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], - std=[0.229, 0.224, 0.225]) - transforms_list = transforms.Compose([ - transforms.Resize(274), - transforms.CenterCrop(240), - transforms.ToTensor(), - normalize - ]) - input_data = transforms_list(raw_data) - return input_data.unsqueeze(0) - - -if __name__ == '__main__': - raw_data = get_raw_data() - model = build_model() - input_tensor = pre_process(raw_data) - output_tensor = model(input_tensor) - _, pred = output_tensor.topk(1, 1, True, True) +#!/usr/bin/env python3 +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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 torch +import numpy as np +import pycls.core.config as config +from pycls.core.config import cfg +import pycls.datasets.transforms as transforms +from pycls.models.effnet import EffNet + + +def build_model(): + config.merge_from_file('configs/dds_baselines/effnet/EN-B1_dds_8npu.yaml') + cfg.freeze() + model = EffNet() + checkpoint = torch.load('result/model.pyth') + model.load_state_dict(checkpoint["model_state"], False) + model.eval() + return model + + +def get_raw_data(): + from PIL import Image + from urllib.request import urlretrieve + IMAGE_URL = 'https://bbs-img.huaweicloud.com/blogs/img/thumb/1591951315139_8989_1363.png' + urlretrieve(IMAGE_URL, 'tmp.jpg') + img = Image.open("tmp.jpg") + img = img.convert('RGB') + return img + + +def pre_process(raw_data): + from torchvision import transforms + normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]) + transforms_list = transforms.Compose([ + transforms.Resize(274), + transforms.CenterCrop(240), + transforms.ToTensor(), + normalize + ]) + input_data = transforms_list(raw_data) + return input_data.unsqueeze(0) + + +if __name__ == '__main__': + raw_data = get_raw_data() + model = build_model() + input_tensor = pre_process(raw_data) + output_tensor = model(input_tensor) + _, pred = output_tensor.topk(1, 1, True, True) print("class: ", pred[0][0].item()) \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/benchmark.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/benchmark.py index 25b78e5cad..cbad898508 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/benchmark.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/benchmark.py @@ -1,167 +1,167 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - - - -"""Benchmarking functions.""" - -import pycls.core.logging as logging -import pycls.core.net as net -import pycls.datasets.loader as loader -import torch -from apex import amp -from pycls.core.config import cfg -from pycls.core.timer import Timer -import pycls.core.optimizer as optim -import torch.npu - -logger = logging.get_logger(__name__) - - -@torch.no_grad() -def compute_time_eval(model): - """Computes precise model forward test time using dummy data.""" - # Use eval mode - model.eval() - # Generate a dummy mini-batch and copy data to GPU - im_size, batch_size = cfg.TRAIN.IM_SIZE, int(cfg.TEST.BATCH_SIZE / cfg.NUM_GPUS) - #inputs = torch.zeros(batch_size, 3, im_size, im_size).cuda(non_blocking=False) - inputs = torch.zeros(batch_size, 3, im_size, im_size).npu() - inputs = inputs.to(non_blocking=False) - # Compute precise forward pass time - timer = Timer() - total_iter = cfg.PREC_TIME.NUM_ITER + cfg.PREC_TIME.WARMUP_ITER - for cur_iter in range(total_iter): - # Reset the timers after the warmup phase - if cur_iter == cfg.PREC_TIME.WARMUP_ITER: - timer.reset() - # Forward - timer.tic() - model(inputs) - torch.npu.synchronize() - timer.toc() - return timer.average_time - - -def compute_time_train(model, loss_fun): - """Computes precise model forward + backward time using dummy data.""" - # Use train mode - model.train() - # Generate a dummy mini-batch and copy data to GPU - im_size, batch_size = cfg.TRAIN.IM_SIZE, int(cfg.TRAIN.BATCH_SIZE / cfg.NUM_GPUS) - inputs = torch.rand(batch_size, 3, im_size, im_size).npu() - inputs = inputs.to(non_blocking=False) - labels = torch.zeros(batch_size, dtype=torch.int32) - labels_one_hot = net.smooth_one_hot_labels(labels) - labels_one_hot = labels_one_hot.npu() - labels_one_hot = labels_one_hot.to(non_blocking=False) - # Cache BatchNorm2D running stats - bns = [m for m in model.modules() if isinstance(m, torch.nn.BatchNorm2d)] - bn_stats = [[bn.running_mean.clone(), bn.running_var.clone()] for bn in bns] - # Create a GradScaler for mixed precision training - #scaler = ApexScaler() - # Compute precise forward backward pass time - fw_timer, bw_timer = Timer(), Timer() - total_iter = cfg.PREC_TIME.NUM_ITER + cfg.PREC_TIME.WARMUP_ITER - for cur_iter in range(total_iter): - # Reset the timers after the warmup phase - if cur_iter == cfg.PREC_TIME.WARMUP_ITER: - fw_timer.reset() - bw_timer.reset() - # Forward - fw_timer.tic() - preds = model(inputs) - loss = loss_fun(preds, labels_one_hot) - torch.npu.synchronize() - fw_timer.toc() - # Backward - bw_timer.tic() - loss.backward() - torch.npu.synchronize() - bw_timer.toc() - # Restore BatchNorm2D running stats - for bn, (mean, var) in zip(bns, bn_stats): - bn.running_mean, bn.running_var = mean, var - return fw_timer.average_time, bw_timer.average_time - - -def compute_time_loader(data_loader): - """Computes loader time.""" - timer = Timer() - loader.shuffle(data_loader, 0) - data_loader_iterator = iter(data_loader) - total_iter = cfg.PREC_TIME.NUM_ITER + cfg.PREC_TIME.WARMUP_ITER - total_iter = min(total_iter, len(data_loader)) - for cur_iter in range(total_iter): - if cur_iter == cfg.PREC_TIME.WARMUP_ITER: - timer.reset() - timer.tic() - next(data_loader_iterator) - timer.toc() - return timer.average_time - - -def compute_time_model(model, loss_fun): - """Times model.""" - logger.info("Computing model timings only...") - # Compute timings - test_fw_time = compute_time_eval(model) - train_fw_time, train_bw_time = compute_time_train(model, loss_fun) - train_fw_bw_time = train_fw_time + train_bw_time - # Output iter timing - iter_times = { - "test_fw_time": test_fw_time, - "train_fw_time": train_fw_time, - "train_bw_time": train_bw_time, - "train_fw_bw_time": train_fw_bw_time, - } - logger.info(logging.dump_log_data(iter_times, "iter_times")) - - -def compute_time_full(model, loss_fun, train_loader, test_loader): - """Times model and data loader.""" - logger.info("Computing model and loader timings...") - # Compute timings - test_fw_time = compute_time_eval(model) - train_fw_time, train_bw_time = compute_time_train(model, loss_fun) - train_fw_bw_time = train_fw_time + train_bw_time - train_loader_time = compute_time_loader(train_loader) - # Output iter timing - iter_times = { - "test_fw_time": test_fw_time, - "train_fw_time": train_fw_time, - "train_bw_time": train_bw_time, - "train_fw_bw_time": train_fw_bw_time, - "train_loader_time": train_loader_time, - } - logger.info(logging.dump_log_data(iter_times, "iter_times")) - # Output epoch timing - epoch_times = { - "test_fw_time": test_fw_time * len(test_loader), - "train_fw_time": train_fw_time * len(train_loader), - "train_bw_time": train_bw_time * len(train_loader), - "train_fw_bw_time": train_fw_bw_time * len(train_loader), - "train_loader_time": train_loader_time * len(train_loader), - } - logger.info(logging.dump_log_data(epoch_times, "epoch_times")) - # Compute data loader overhead (assuming DATA_LOADER.NUM_WORKERS>1) - overhead = max(0, train_loader_time - train_fw_bw_time) / train_fw_bw_time - logger.info("Overhead of data loader is {:.2f}%".format(overhead * 100)) +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + + + +"""Benchmarking functions.""" + +import pycls.core.logging as logging +import pycls.core.net as net +import pycls.datasets.loader as loader +import torch +from apex import amp +from pycls.core.config import cfg +from pycls.core.timer import Timer +import pycls.core.optimizer as optim +import torch.npu + +logger = logging.get_logger(__name__) + + +@torch.no_grad() +def compute_time_eval(model): + """Computes precise model forward test time using dummy data.""" + # Use eval mode + model.eval() + # Generate a dummy mini-batch and copy data to GPU + im_size, batch_size = cfg.TRAIN.IM_SIZE, int(cfg.TEST.BATCH_SIZE / cfg.NUM_GPUS) + #inputs = torch.zeros(batch_size, 3, im_size, im_size).cuda(non_blocking=False) + inputs = torch.zeros(batch_size, 3, im_size, im_size).npu() + inputs = inputs.to(non_blocking=False) + # Compute precise forward pass time + timer = Timer() + total_iter = cfg.PREC_TIME.NUM_ITER + cfg.PREC_TIME.WARMUP_ITER + for cur_iter in range(total_iter): + # Reset the timers after the warmup phase + if cur_iter == cfg.PREC_TIME.WARMUP_ITER: + timer.reset() + # Forward + timer.tic() + model(inputs) + torch.npu.synchronize() + timer.toc() + return timer.average_time + + +def compute_time_train(model, loss_fun): + """Computes precise model forward + backward time using dummy data.""" + # Use train mode + model.train() + # Generate a dummy mini-batch and copy data to GPU + im_size, batch_size = cfg.TRAIN.IM_SIZE, int(cfg.TRAIN.BATCH_SIZE / cfg.NUM_GPUS) + inputs = torch.rand(batch_size, 3, im_size, im_size).npu() + inputs = inputs.to(non_blocking=False) + labels = torch.zeros(batch_size, dtype=torch.int32) + labels_one_hot = net.smooth_one_hot_labels(labels) + labels_one_hot = labels_one_hot.npu() + labels_one_hot = labels_one_hot.to(non_blocking=False) + # Cache BatchNorm2D running stats + bns = [m for m in model.modules() if isinstance(m, torch.nn.BatchNorm2d)] + bn_stats = [[bn.running_mean.clone(), bn.running_var.clone()] for bn in bns] + # Create a GradScaler for mixed precision training + #scaler = ApexScaler() + # Compute precise forward backward pass time + fw_timer, bw_timer = Timer(), Timer() + total_iter = cfg.PREC_TIME.NUM_ITER + cfg.PREC_TIME.WARMUP_ITER + for cur_iter in range(total_iter): + # Reset the timers after the warmup phase + if cur_iter == cfg.PREC_TIME.WARMUP_ITER: + fw_timer.reset() + bw_timer.reset() + # Forward + fw_timer.tic() + preds = model(inputs) + loss = loss_fun(preds, labels_one_hot) + torch.npu.synchronize() + fw_timer.toc() + # Backward + bw_timer.tic() + loss.backward() + torch.npu.synchronize() + bw_timer.toc() + # Restore BatchNorm2D running stats + for bn, (mean, var) in zip(bns, bn_stats): + bn.running_mean, bn.running_var = mean, var + return fw_timer.average_time, bw_timer.average_time + + +def compute_time_loader(data_loader): + """Computes loader time.""" + timer = Timer() + loader.shuffle(data_loader, 0) + data_loader_iterator = iter(data_loader) + total_iter = cfg.PREC_TIME.NUM_ITER + cfg.PREC_TIME.WARMUP_ITER + total_iter = min(total_iter, len(data_loader)) + for cur_iter in range(total_iter): + if cur_iter == cfg.PREC_TIME.WARMUP_ITER: + timer.reset() + timer.tic() + next(data_loader_iterator) + timer.toc() + return timer.average_time + + +def compute_time_model(model, loss_fun): + """Times model.""" + logger.info("Computing model timings only...") + # Compute timings + test_fw_time = compute_time_eval(model) + train_fw_time, train_bw_time = compute_time_train(model, loss_fun) + train_fw_bw_time = train_fw_time + train_bw_time + # Output iter timing + iter_times = { + "test_fw_time": test_fw_time, + "train_fw_time": train_fw_time, + "train_bw_time": train_bw_time, + "train_fw_bw_time": train_fw_bw_time, + } + logger.info(logging.dump_log_data(iter_times, "iter_times")) + + +def compute_time_full(model, loss_fun, train_loader, test_loader): + """Times model and data loader.""" + logger.info("Computing model and loader timings...") + # Compute timings + test_fw_time = compute_time_eval(model) + train_fw_time, train_bw_time = compute_time_train(model, loss_fun) + train_fw_bw_time = train_fw_time + train_bw_time + train_loader_time = compute_time_loader(train_loader) + # Output iter timing + iter_times = { + "test_fw_time": test_fw_time, + "train_fw_time": train_fw_time, + "train_bw_time": train_bw_time, + "train_fw_bw_time": train_fw_bw_time, + "train_loader_time": train_loader_time, + } + logger.info(logging.dump_log_data(iter_times, "iter_times")) + # Output epoch timing + epoch_times = { + "test_fw_time": test_fw_time * len(test_loader), + "train_fw_time": train_fw_time * len(train_loader), + "train_bw_time": train_bw_time * len(train_loader), + "train_fw_bw_time": train_fw_bw_time * len(train_loader), + "train_loader_time": train_loader_time * len(train_loader), + } + logger.info(logging.dump_log_data(epoch_times, "epoch_times")) + # Compute data loader overhead (assuming DATA_LOADER.NUM_WORKERS>1) + overhead = max(0, train_loader_time - train_fw_bw_time) / train_fw_bw_time + logger.info("Overhead of data loader is {:.2f}%".format(overhead * 100)) diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/builders.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/builders.py index 8e2688e96a..a40983713d 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/builders.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/builders.py @@ -1,68 +1,68 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - - -"""Model and loss construction functions.""" - -from pycls.core.config import cfg -from pycls.core.net import SoftCrossEntropyLoss -from pycls.models.effnet import EffNet - - -# Supported models -_models = {"effnet": EffNet} - -# Supported loss functions -_loss_funs = {"cross_entropy": SoftCrossEntropyLoss} - - -def get_model(): - """Gets the model class specified in the config.""" - err_str = "Model type '{}' not supported" - assert cfg.MODEL.TYPE in _models.keys(), err_str.format(cfg.MODEL.TYPE) - return _models[cfg.MODEL.TYPE] - - -def get_loss_fun(): - """Gets the loss function class specified in the config.""" - err_str = "Loss function type '{}' not supported" - assert cfg.MODEL.LOSS_FUN in _loss_funs.keys(), err_str.format(cfg.TRAIN.LOSS) - return _loss_funs[cfg.MODEL.LOSS_FUN] - - -def build_model(): - """Builds the model.""" - return get_model()() - - -def build_loss_fun(): - """Build the loss function.""" - return get_loss_fun()() - - -def register_model(name, ctor): - """Registers a model dynamically.""" - _models[name] = ctor - - -def register_loss_fun(name, ctor): - """Registers a loss function dynamically.""" - _loss_funs[name] = ctor +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + + +"""Model and loss construction functions.""" + +from pycls.core.config import cfg +from pycls.core.net import SoftCrossEntropyLoss +from pycls.models.effnet import EffNet + + +# Supported models +_models = {"effnet": EffNet} + +# Supported loss functions +_loss_funs = {"cross_entropy": SoftCrossEntropyLoss} + + +def get_model(): + """Gets the model class specified in the config.""" + err_str = "Model type '{}' not supported" + assert cfg.MODEL.TYPE in _models.keys(), err_str.format(cfg.MODEL.TYPE) + return _models[cfg.MODEL.TYPE] + + +def get_loss_fun(): + """Gets the loss function class specified in the config.""" + err_str = "Loss function type '{}' not supported" + assert cfg.MODEL.LOSS_FUN in _loss_funs.keys(), err_str.format(cfg.TRAIN.LOSS) + return _loss_funs[cfg.MODEL.LOSS_FUN] + + +def build_model(): + """Builds the model.""" + return get_model()() + + +def build_loss_fun(): + """Build the loss function.""" + return get_loss_fun()() + + +def register_model(name, ctor): + """Registers a model dynamically.""" + _models[name] = ctor + + +def register_loss_fun(name, ctor): + """Registers a loss function dynamically.""" + _loss_funs[name] = ctor diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/distributed.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/distributed.py index 55a6652b47..3eb1dc083b 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/distributed.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/distributed.py @@ -1,186 +1,186 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - - -"""Distributed helpers.""" - -import multiprocessing -import os -import random -import signal -import threading -import traceback -import torch.npu -import torch -from pycls.core.config import cfg - - -# Make work w recent PyTorch versions (https://github.com/pytorch/pytorch/issues/37377) -os.environ["MKL_THREADING_LAYER"] = "GNU" - - -def is_master_proc(): - """Determines if the current process is the master process. - - Master process is responsible for logging, writing and loading checkpoints. In - the multi GPU setting, we assign the master role to the rank 0 process. When - training using a single GPU, there is a single process which is considered master. - """ - return cfg.NUM_GPUS == 1 or torch.distributed.get_rank() == 0 - - -def init_process_group(proc_rank, world_size, port='29588'): - """Initializes the default process group.""" - # Set the GPU to use - print("begin init_process_group") - torch.npu.set_device(proc_rank) - print("[npu id:", proc_rank, "]", "Use NPU: {} for training".format(proc_rank)) - - os.environ['MASTER_ADDR'] = '127.0.0.1' - os.environ['MASTER_PORT'] = '29588' - - - # Initialize the process group - torch.distributed.init_process_group( - backend=cfg.DIST_BACKEND, - world_size=world_size, - rank=proc_rank, - ) - print("after init_process_group") - - -def destroy_process_group(): - """Destroys the default process group.""" - torch.distributed.destroy_process_group() - - -def scaled_all_reduce(tensors): - """Performs the scaled all_reduce operation on the provided tensors. - - The input tensors are modified in-place. Currently supports only the sum - reduction operator. The reduced values are scaled by the inverse size of the - process group (equivalent to cfg.NUM_GPUS). - """ - # There is no need for reduction in the single-proc case - if cfg.NUM_GPUS == 1: - return tensors - # Queue the reductions - reductions = [] - for tensor in tensors: - reduction = torch.distributed.all_reduce(tensor, async_op=True) - reductions.append(reduction) - # Wait for reductions to finish - for reduction in reductions: - reduction.wait() - # Scale the results - for tensor in tensors: - tensor.mul_(1.0 / cfg.NUM_GPUS) - return tensors - - -class ChildException(Exception): - """Wraps an exception from a child process.""" - - def __init__(self, child_trace): - super(ChildException, self).__init__(child_trace) - - -class ErrorHandler(object): - """Multiprocessing error handler (based on fairseq's). - - Listens for errors in child processes and propagates the tracebacks to the parent. - """ - - def __init__(self, error_queue): - # Shared error queue - self.error_queue = error_queue - # Children processes sharing the error queue - self.children_pids = [] - # Start a thread listening to errors - self.error_listener = threading.Thread(target=self.listen, daemon=True) - self.error_listener.start() - # Register the signal handler - signal.signal(signal.SIGUSR1, self.signal_handler) - - def add_child(self, pid): - """Registers a child process.""" - self.children_pids.append(pid) - - def listen(self): - """Listens for errors in the error queue.""" - # Wait until there is an error in the queue - child_trace = self.error_queue.get() - # Put the error back for the signal handler - self.error_queue.put(child_trace) - # Invoke the signal handler - os.kill(os.getpid(), signal.SIGUSR1) - - def signal_handler(self, _sig_num, _stack_frame): - """Signal handler.""" - # Kill children processes - for pid in self.children_pids: - os.kill(pid, signal.SIGINT) - # Propagate the error from the child process - raise ChildException(self.error_queue.get()) - - -def run(proc_rank, world_size, port, error_queue, fun, fun_args, fun_kwargs): - """Runs a function from a child process.""" - try: - # Initialize the process group - init_process_group(proc_rank, world_size, port) - # Run the function - fun(*fun_args, **fun_kwargs) - except KeyboardInterrupt: - # Killed by the parent process - pass - except Exception: - # Propagate exception to the parent process - error_queue.put(traceback.format_exc()) - finally: - # Destroy the process group - destroy_process_group() - - -def multi_proc_run(num_proc, fun, fun_args=(), fun_kwargs=None): - """Runs a function in a multi-proc setting (unless num_proc == 1).""" - # There is no need for multi-proc in the single-proc case - fun_kwargs = fun_kwargs if fun_kwargs else {} - if num_proc == 1: - fun(*fun_args, **fun_kwargs) - return - # Handle errors from training subprocesses - error_queue = multiprocessing.SimpleQueue() - error_handler = ErrorHandler(error_queue) - # Get a random port to use (without using global random number generator) - port = random.Random().randint(cfg.PORT_RANGE[0], cfg.PORT_RANGE[1]) - # Run each training subprocess - ps = [] - for i in range(num_proc): - p_i = multiprocessing.Process( - target=run, args=(i, num_proc, port, error_queue, fun, fun_args, fun_kwargs) - ) - ps.append(p_i) - p_i.start() - error_handler.add_child(p_i.pid) - # Wait for each subprocess to finish - for p in ps: - p.join() +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + + +"""Distributed helpers.""" + +import multiprocessing +import os +import random +import signal +import threading +import traceback +import torch.npu +import torch +from pycls.core.config import cfg + + +# Make work w recent PyTorch versions (https://github.com/pytorch/pytorch/issues/37377) +os.environ["MKL_THREADING_LAYER"] = "GNU" + + +def is_master_proc(): + """Determines if the current process is the master process. + + Master process is responsible for logging, writing and loading checkpoints. In + the multi GPU setting, we assign the master role to the rank 0 process. When + training using a single GPU, there is a single process which is considered master. + """ + return cfg.NUM_GPUS == 1 or torch.distributed.get_rank() == 0 + + +def init_process_group(proc_rank, world_size, port='29588'): + """Initializes the default process group.""" + # Set the GPU to use + print("begin init_process_group") + torch.npu.set_device(proc_rank) + print("[npu id:", proc_rank, "]", "Use NPU: {} for training".format(proc_rank)) + + os.environ['MASTER_ADDR'] = '127.0.0.1' + os.environ['MASTER_PORT'] = '29588' + + + # Initialize the process group + torch.distributed.init_process_group( + backend=cfg.DIST_BACKEND, + world_size=world_size, + rank=proc_rank, + ) + print("after init_process_group") + + +def destroy_process_group(): + """Destroys the default process group.""" + torch.distributed.destroy_process_group() + + +def scaled_all_reduce(tensors): + """Performs the scaled all_reduce operation on the provided tensors. + + The input tensors are modified in-place. Currently supports only the sum + reduction operator. The reduced values are scaled by the inverse size of the + process group (equivalent to cfg.NUM_GPUS). + """ + # There is no need for reduction in the single-proc case + if cfg.NUM_GPUS == 1: + return tensors + # Queue the reductions + reductions = [] + for tensor in tensors: + reduction = torch.distributed.all_reduce(tensor, async_op=True) + reductions.append(reduction) + # Wait for reductions to finish + for reduction in reductions: + reduction.wait() + # Scale the results + for tensor in tensors: + tensor.mul_(1.0 / cfg.NUM_GPUS) + return tensors + + +class ChildException(Exception): + """Wraps an exception from a child process.""" + + def __init__(self, child_trace): + super(ChildException, self).__init__(child_trace) + + +class ErrorHandler(object): + """Multiprocessing error handler (based on fairseq's). + + Listens for errors in child processes and propagates the tracebacks to the parent. + """ + + def __init__(self, error_queue): + # Shared error queue + self.error_queue = error_queue + # Children processes sharing the error queue + self.children_pids = [] + # Start a thread listening to errors + self.error_listener = threading.Thread(target=self.listen, daemon=True) + self.error_listener.start() + # Register the signal handler + signal.signal(signal.SIGUSR1, self.signal_handler) + + def add_child(self, pid): + """Registers a child process.""" + self.children_pids.append(pid) + + def listen(self): + """Listens for errors in the error queue.""" + # Wait until there is an error in the queue + child_trace = self.error_queue.get() + # Put the error back for the signal handler + self.error_queue.put(child_trace) + # Invoke the signal handler + os.kill(os.getpid(), signal.SIGUSR1) + + def signal_handler(self, _sig_num, _stack_frame): + """Signal handler.""" + # Kill children processes + for pid in self.children_pids: + os.kill(pid, signal.SIGINT) + # Propagate the error from the child process + raise ChildException(self.error_queue.get()) + + +def run(proc_rank, world_size, port, error_queue, fun, fun_args, fun_kwargs): + """Runs a function from a child process.""" + try: + # Initialize the process group + init_process_group(proc_rank, world_size, port) + # Run the function + fun(*fun_args, **fun_kwargs) + except KeyboardInterrupt: + # Killed by the parent process + pass + except Exception: + # Propagate exception to the parent process + error_queue.put(traceback.format_exc()) + finally: + # Destroy the process group + destroy_process_group() + + +def multi_proc_run(num_proc, fun, fun_args=(), fun_kwargs=None): + """Runs a function in a multi-proc setting (unless num_proc == 1).""" + # There is no need for multi-proc in the single-proc case + fun_kwargs = fun_kwargs if fun_kwargs else {} + if num_proc == 1: + fun(*fun_args, **fun_kwargs) + return + # Handle errors from training subprocesses + error_queue = multiprocessing.SimpleQueue() + error_handler = ErrorHandler(error_queue) + # Get a random port to use (without using global random number generator) + port = random.Random().randint(cfg.PORT_RANGE[0], cfg.PORT_RANGE[1]) + # Run each training subprocess + ps = [] + for i in range(num_proc): + p_i = multiprocessing.Process( + target=run, args=(i, num_proc, port, error_queue, fun, fun_args, fun_kwargs) + ) + ps.append(p_i) + p_i.start() + error_handler.add_child(p_i.pid) + # Wait for each subprocess to finish + for p in ps: + p.join() diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/env.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/env.py index c0d31579a4..48a8164b31 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/env.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/env.py @@ -1,56 +1,56 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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 random - -import numpy as np -import pycls.core.config as config -import pycls.core.distributed as dist -import pycls.core.logging as logging -import torch -from iopath.common.file_io import g_pathmgr -from pycls.core.config import cfg - - -logger = logging.get_logger(__name__) - - -def setup_env(): - """Sets up environment for training or testing.""" - if dist.is_master_proc(): - # Ensure that the output dir exists - g_pathmgr.mkdirs(cfg.OUT_DIR) - # Save the config - config.dump_cfg() - # Setup logging - logging.setup_logging() - # Log torch, cuda, and cudnn versions - version = [torch.__version__, torch.version.cuda, torch.backends.cudnn.version()] - logger.info("PyTorch Version: torch={}, cuda={}, cudnn={}".format(*version)) - # Log the config as both human readable and as a json - logger.info("Config:\n{}".format(cfg)) if cfg.VERBOSE else () - logger.info(logging.dump_log_data(cfg, "cfg", None)) - # Fix the RNG seeds (see RNG comment in core/config.py for discussion) - np.random.seed(cfg.RNG_SEED) - torch.manual_seed(cfg.RNG_SEED) - random.seed(cfg.RNG_SEED) - # Configure the CUDNN backend - torch.backends.cudnn.benchmark = cfg.CUDNN.BENCHMARK +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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 random + +import numpy as np +import pycls.core.config as config +import pycls.core.distributed as dist +import pycls.core.logging as logging +import torch +from iopath.common.file_io import g_pathmgr +from pycls.core.config import cfg + + +logger = logging.get_logger(__name__) + + +def setup_env(): + """Sets up environment for training or testing.""" + if dist.is_master_proc(): + # Ensure that the output dir exists + g_pathmgr.mkdirs(cfg.OUT_DIR) + # Save the config + config.dump_cfg() + # Setup logging + logging.setup_logging() + # Log torch, cuda, and cudnn versions + version = [torch.__version__, torch.version.cuda, torch.backends.cudnn.version()] + logger.info("PyTorch Version: torch={}, cuda={}, cudnn={}".format(*version)) + # Log the config as both human readable and as a json + logger.info("Config:\n{}".format(cfg)) if cfg.VERBOSE else () + logger.info(logging.dump_log_data(cfg, "cfg", None)) + # Fix the RNG seeds (see RNG comment in core/config.py for discussion) + np.random.seed(cfg.RNG_SEED) + torch.manual_seed(cfg.RNG_SEED) + random.seed(cfg.RNG_SEED) + # Configure the CUDNN backend + torch.backends.cudnn.benchmark = cfg.CUDNN.BENCHMARK diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/io.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/io.py index 8bba8a2d45..51a1f82921 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/io.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/io.py @@ -1,93 +1,93 @@ -#!/usr/bin/env python3 - - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -"""IO utilities (adapted from Detectron)""" - -import logging -import os -import re -import sys -from urllib import request as urlrequest - -from iopath.common.file_io import g_pathmgr - - -logger = logging.getLogger(__name__) - -_PYCLS_BASE_URL = "https://dl.fbaipublicfiles.com/pycls" - - -def cache_url(url_or_file, cache_dir, base_url=_PYCLS_BASE_URL): - """Download the file specified by the URL to the cache_dir and return the path to - the cached file. If the argument is not a URL, simply return it as is. - """ - is_url = re.match(r"^(?:http)s?://", url_or_file, re.IGNORECASE) is not None - if not is_url: - return url_or_file - url = url_or_file - assert url.startswith(base_url), "url must start with: {}".format(base_url) - cache_file_path = url.replace(base_url, cache_dir) - if g_pathmgr.exists(cache_file_path): - return cache_file_path - cache_file_dir = os.path.dirname(cache_file_path) - if not g_pathmgr.exists(cache_file_dir): - g_pathmgr.mkdirs(cache_file_dir) - logger.info("Downloading remote file {} to {}".format(url, cache_file_path)) - download_url(url, cache_file_path) - return cache_file_path - - -def _progress_bar(count, total): - """Report download progress. Credit: - https://stackoverflow.com/questions/3173320/text-progress-bar-in-the-console/27871113 - """ - bar_len = 60 - filled_len = int(round(bar_len * count / float(total))) - percents = round(100.0 * count / float(total), 1) - bar = "=" * filled_len + "-" * (bar_len - filled_len) - sys.stdout.write( - " [{}] {}% of {:.1f}MB file \r".format(bar, percents, total / 1024 / 1024) - ) - sys.stdout.flush() - if count >= total: - sys.stdout.write("\n") - - -def download_url(url, dst_file_path, chunk_size=8192, progress_hook=_progress_bar): - """Download url and write it to dst_file_path. Credit: - https://stackoverflow.com/questions/2028517/python-urllib2-progress-hook - """ - req = urlrequest.Request(url) - response = urlrequest.urlopen(req) - total_size = response.info().get("Content-Length").strip() - total_size = int(total_size) - bytes_so_far = 0 - with g_pathmgr.open(dst_file_path, "wb") as f: - while 1: - chunk = response.read(chunk_size) - bytes_so_far += len(chunk) - if not chunk: - break - if progress_hook: - progress_hook(bytes_so_far, total_size) - f.write(chunk) - return bytes_so_far +#!/usr/bin/env python3 + + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +"""IO utilities (adapted from Detectron)""" + +import logging +import os +import re +import sys +from urllib import request as urlrequest + +from iopath.common.file_io import g_pathmgr + + +logger = logging.getLogger(__name__) + +_PYCLS_BASE_URL = "https://dl.fbaipublicfiles.com/pycls" + + +def cache_url(url_or_file, cache_dir, base_url=_PYCLS_BASE_URL): + """Download the file specified by the URL to the cache_dir and return the path to + the cached file. If the argument is not a URL, simply return it as is. + """ + is_url = re.match(r"^(?:http)s?://", url_or_file, re.IGNORECASE) is not None + if not is_url: + return url_or_file + url = url_or_file + assert url.startswith(base_url), "url must start with: {}".format(base_url) + cache_file_path = url.replace(base_url, cache_dir) + if g_pathmgr.exists(cache_file_path): + return cache_file_path + cache_file_dir = os.path.dirname(cache_file_path) + if not g_pathmgr.exists(cache_file_dir): + g_pathmgr.mkdirs(cache_file_dir) + logger.info("Downloading remote file {} to {}".format(url, cache_file_path)) + download_url(url, cache_file_path) + return cache_file_path + + +def _progress_bar(count, total): + """Report download progress. Credit: + https://stackoverflow.com/questions/3173320/text-progress-bar-in-the-console/27871113 + """ + bar_len = 60 + filled_len = int(round(bar_len * count / float(total))) + percents = round(100.0 * count / float(total), 1) + bar = "=" * filled_len + "-" * (bar_len - filled_len) + sys.stdout.write( + " [{}] {}% of {:.1f}MB file \r".format(bar, percents, total / 1024 / 1024) + ) + sys.stdout.flush() + if count >= total: + sys.stdout.write("\n") + + +def download_url(url, dst_file_path, chunk_size=8192, progress_hook=_progress_bar): + """Download url and write it to dst_file_path. Credit: + https://stackoverflow.com/questions/2028517/python-urllib2-progress-hook + """ + req = urlrequest.Request(url) + response = urlrequest.urlopen(req) + total_size = response.info().get("Content-Length").strip() + total_size = int(total_size) + bytes_so_far = 0 + with g_pathmgr.open(dst_file_path, "wb") as f: + while 1: + chunk = response.read(chunk_size) + bytes_so_far += len(chunk) + if not chunk: + break + if progress_hook: + progress_hook(bytes_so_far, total_size) + f.write(chunk) + return bytes_so_far diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/logging.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/logging.py index fc0f2aa70d..f5374e51c1 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/logging.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/logging.py @@ -1,153 +1,153 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -"""Logging.""" - -import builtins -import decimal -import logging -import os -import sys - -import pycls.core.distributed as dist -import simplejson -from iopath.common.file_io import g_pathmgr -from pycls.core.config import cfg - - -# Show filename and line number in logs -_FORMAT = "[%(filename)s: %(lineno)3d]: %(message)s" - -# Log file name (for cfg.LOG_DEST = 'file') -_LOG_FILE = "stdout.log" - -# Data output with dump_log_data(data, data_type) will be tagged w/ this -_TAG = "json_stats: " - -# Data output with dump_log_data(data, data_type) will have data[_TYPE]=data_type -_TYPE = "_type" - - -def _suppress_print(): - """Suppresses printing from the current process.""" - - def ignore(*_objects, _sep=" ", _end="\n", _file=sys.stdout, _flush=False): - pass - - builtins.print = ignore - - -def setup_logging(): - """Sets up the logging.""" - # Enable logging only for the master process - if dist.is_master_proc(): - # Clear the root logger to prevent any existing logging config - # (e.g. set by another module) from messing with our setup - logging.root.handlers = [] - # Construct logging configuration - logging_config = {"level": logging.INFO, "format": _FORMAT} - # Log either to stdout or to a file - if cfg.LOG_DEST == "stdout": - logging_config["stream"] = sys.stdout - else: - logging_config["filename"] = os.path.join(cfg.OUT_DIR, _LOG_FILE) - # Configure logging - logging.basicConfig(**logging_config) - else: - _suppress_print() - - -def get_logger(name): - """Retrieves the logger.""" - return logging.getLogger(name) - - -def dump_log_data(data, data_type, prec=4): - """Covert data (a dictionary) into tagged json string for logging.""" - data[_TYPE] = data_type - data = float_to_decimal(data, prec) - data_json = simplejson.dumps(data, sort_keys=True, use_decimal=True) - return "{:s}{:s}".format(_TAG, data_json) - - -def float_to_decimal(data, prec=4): - """Convert floats to decimals which allows for fixed width json.""" - if prec and isinstance(data, dict): - return {k: float_to_decimal(v, prec) for k, v in data.items()} - if prec and isinstance(data, float): - return decimal.Decimal(("{:." + str(prec) + "f}").format(data)) - else: - return data - - -def get_log_files(log_dir, name_filter="", log_file=_LOG_FILE): - """Get all log files in directory containing subdirs of trained models.""" - names = [n for n in sorted(g_pathmgr.ls(log_dir)) if name_filter in n] - files = [os.path.join(log_dir, n, log_file) for n in names] - f_n_ps = [(f, n) for (f, n) in zip(files, names) if g_pathmgr.exists(f)] - files, names = zip(*f_n_ps) if f_n_ps else ([], []) - return files, names - - -def load_log_data(log_file, data_types_to_skip=()): - """Loads log data into a dictionary of the form data[data_type][metric][index].""" - # Load log_file - assert g_pathmgr.exists(log_file), "Log file not found: {}".format(log_file) - with g_pathmgr.open(log_file, "r") as f: - lines = f.readlines() - # Extract and parse lines that start with _TAG and have a type specified - lines = [l[l.find(_TAG) + len(_TAG) :] for l in lines if _TAG in l] - lines = [simplejson.loads(l) for l in lines] - lines = [l for l in lines if _TYPE in l and not l[_TYPE] in data_types_to_skip] - # Generate data structure accessed by data[data_type][index][metric] - data_types = [l[_TYPE] for l in lines] - data = {t: [] for t in data_types} - for t, line in zip(data_types, lines): - del line[_TYPE] - data[t].append(line) - # Generate data structure accessed by data[data_type][metric][index] - for t in data: - metrics = sorted(data[t][0].keys()) - err_str = "Inconsistent metrics in log for _type={}: {}".format(t, metrics) - assert all(sorted(d.keys()) == metrics for d in data[t]), err_str - data[t] = {m: [d[m] for d in data[t]] for m in metrics} - return data - - -def sort_log_data(data): - """Sort each data[data_type][metric] by epoch or keep only first instance.""" - for t in data: - if "epoch" in data[t]: - assert "epoch_ind" not in data[t] and "epoch_max" not in data[t] - data[t]["epoch_ind"] = [int(e.split("/")[0]) for e in data[t]["epoch"]] - data[t]["epoch_max"] = [int(e.split("/")[1]) for e in data[t]["epoch"]] - epoch = data[t]["epoch_ind"] - if "iter" in data[t]: - assert "iter_ind" not in data[t] and "iter_max" not in data[t] - data[t]["iter_ind"] = [int(i.split("/")[0]) for i in data[t]["iter"]] - data[t]["iter_max"] = [int(i.split("/")[1]) for i in data[t]["iter"]] - itr = zip(epoch, data[t]["iter_ind"], data[t]["iter_max"]) - epoch = [e + (i_ind - 1) / i_max for e, i_ind, i_max in itr] - for m in data[t]: - data[t][m] = [v for _, v in sorted(zip(epoch, data[t][m]))] - else: - data[t] = {m: d[0] for m, d in data[t].items()} - return data +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +"""Logging.""" + +import builtins +import decimal +import logging +import os +import sys + +import pycls.core.distributed as dist +import simplejson +from iopath.common.file_io import g_pathmgr +from pycls.core.config import cfg + + +# Show filename and line number in logs +_FORMAT = "[%(filename)s: %(lineno)3d]: %(message)s" + +# Log file name (for cfg.LOG_DEST = 'file') +_LOG_FILE = "stdout.log" + +# Data output with dump_log_data(data, data_type) will be tagged w/ this +_TAG = "json_stats: " + +# Data output with dump_log_data(data, data_type) will have data[_TYPE]=data_type +_TYPE = "_type" + + +def _suppress_print(): + """Suppresses printing from the current process.""" + + def ignore(*_objects, _sep=" ", _end="\n", _file=sys.stdout, _flush=False): + pass + + builtins.print = ignore + + +def setup_logging(): + """Sets up the logging.""" + # Enable logging only for the master process + if dist.is_master_proc(): + # Clear the root logger to prevent any existing logging config + # (e.g. set by another module) from messing with our setup + logging.root.handlers = [] + # Construct logging configuration + logging_config = {"level": logging.INFO, "format": _FORMAT} + # Log either to stdout or to a file + if cfg.LOG_DEST == "stdout": + logging_config["stream"] = sys.stdout + else: + logging_config["filename"] = os.path.join(cfg.OUT_DIR, _LOG_FILE) + # Configure logging + logging.basicConfig(**logging_config) + else: + _suppress_print() + + +def get_logger(name): + """Retrieves the logger.""" + return logging.getLogger(name) + + +def dump_log_data(data, data_type, prec=4): + """Covert data (a dictionary) into tagged json string for logging.""" + data[_TYPE] = data_type + data = float_to_decimal(data, prec) + data_json = simplejson.dumps(data, sort_keys=True, use_decimal=True) + return "{:s}{:s}".format(_TAG, data_json) + + +def float_to_decimal(data, prec=4): + """Convert floats to decimals which allows for fixed width json.""" + if prec and isinstance(data, dict): + return {k: float_to_decimal(v, prec) for k, v in data.items()} + if prec and isinstance(data, float): + return decimal.Decimal(("{:." + str(prec) + "f}").format(data)) + else: + return data + + +def get_log_files(log_dir, name_filter="", log_file=_LOG_FILE): + """Get all log files in directory containing subdirs of trained models.""" + names = [n for n in sorted(g_pathmgr.ls(log_dir)) if name_filter in n] + files = [os.path.join(log_dir, n, log_file) for n in names] + f_n_ps = [(f, n) for (f, n) in zip(files, names) if g_pathmgr.exists(f)] + files, names = zip(*f_n_ps) if f_n_ps else ([], []) + return files, names + + +def load_log_data(log_file, data_types_to_skip=()): + """Loads log data into a dictionary of the form data[data_type][metric][index].""" + # Load log_file + assert g_pathmgr.exists(log_file), "Log file not found: {}".format(log_file) + with g_pathmgr.open(log_file, "r") as f: + lines = f.readlines() + # Extract and parse lines that start with _TAG and have a type specified + lines = [l[l.find(_TAG) + len(_TAG) :] for l in lines if _TAG in l] + lines = [simplejson.loads(l) for l in lines] + lines = [l for l in lines if _TYPE in l and not l[_TYPE] in data_types_to_skip] + # Generate data structure accessed by data[data_type][index][metric] + data_types = [l[_TYPE] for l in lines] + data = {t: [] for t in data_types} + for t, line in zip(data_types, lines): + del line[_TYPE] + data[t].append(line) + # Generate data structure accessed by data[data_type][metric][index] + for t in data: + metrics = sorted(data[t][0].keys()) + err_str = "Inconsistent metrics in log for _type={}: {}".format(t, metrics) + assert all(sorted(d.keys()) == metrics for d in data[t]), err_str + data[t] = {m: [d[m] for d in data[t]] for m in metrics} + return data + + +def sort_log_data(data): + """Sort each data[data_type][metric] by epoch or keep only first instance.""" + for t in data: + if "epoch" in data[t]: + assert "epoch_ind" not in data[t] and "epoch_max" not in data[t] + data[t]["epoch_ind"] = [int(e.split("/")[0]) for e in data[t]["epoch"]] + data[t]["epoch_max"] = [int(e.split("/")[1]) for e in data[t]["epoch"]] + epoch = data[t]["epoch_ind"] + if "iter" in data[t]: + assert "iter_ind" not in data[t] and "iter_max" not in data[t] + data[t]["iter_ind"] = [int(i.split("/")[0]) for i in data[t]["iter"]] + data[t]["iter_max"] = [int(i.split("/")[1]) for i in data[t]["iter"]] + itr = zip(epoch, data[t]["iter_ind"], data[t]["iter_max"]) + epoch = [e + (i_ind - 1) / i_max for e, i_ind, i_max in itr] + for m in data[t]: + data[t][m] = [v for _, v in sorted(zip(epoch, data[t][m]))] + else: + data[t] = {m: d[0] for m, d in data[t].items()} + return data diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/plotting.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/plotting.py index 608f6ee442..bf7c18a6de 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/plotting.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/plotting.py @@ -1,146 +1,146 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -"""Plotting functions.""" - -import colorlover as cl -import matplotlib.pyplot as plt -import plotly.graph_objs as go -import plotly.offline as offline -import pycls.core.logging as logging - - -def get_plot_colors(max_colors, color_format="pyplot"): - """Generate colors for plotting.""" - colors = cl.scales["11"]["qual"]["Paired"] - if max_colors > len(colors): - colors = cl.to_rgb(cl.interp(colors, max_colors)) - if color_format == "pyplot": - return [[j / 255.0 for j in c] for c in cl.to_numeric(colors)] - return colors - - -def prepare_plot_data(log_files, names, metric="top1_err"): - """Load logs and extract data for plotting error curves.""" - plot_data = [] - for file, name in zip(log_files, names): - d, data = {}, logging.sort_log_data(logging.load_log_data(file)) - for phase in ["train", "test"]: - x = data[phase + "_epoch"]["epoch_ind"] - y = data[phase + "_epoch"][metric] - d["x_" + phase], d["y_" + phase] = x, y - d[phase + "_label"] = "[{:5.2f}] ".format(min(y) if y else 0) + name - plot_data.append(d) - assert len(plot_data) > 0, "No data to plot" - return plot_data - - -def plot_error_curves_plotly(log_files, names, filename, metric="top1_err"): - """Plot error curves using plotly and save to file.""" - plot_data = prepare_plot_data(log_files, names, metric) - colors = get_plot_colors(len(plot_data), "plotly") - # Prepare data for plots (3 sets, train duplicated w and w/o legend) - data = [] - for i, d in enumerate(plot_data): - s = str(i) - line_train = {"color": colors[i], "dash": "dashdot", "width": 1.5} - line_test = {"color": colors[i], "dash": "solid", "width": 1.5} - data.append( - go.Scatter( - x=d["x_train"], - y=d["y_train"], - mode="lines", - name=d["train_label"], - line=line_train, - legendgroup=s, - visible=True, - showlegend=False, - ) - ) - data.append( - go.Scatter( - x=d["x_test"], - y=d["y_test"], - mode="lines", - name=d["test_label"], - line=line_test, - legendgroup=s, - visible=True, - showlegend=True, - ) - ) - data.append( - go.Scatter( - x=d["x_train"], - y=d["y_train"], - mode="lines", - name=d["train_label"], - line=line_train, - legendgroup=s, - visible=False, - showlegend=True, - ) - ) - # Prepare layout w ability to toggle 'all', 'train', 'test' - titlefont = {"size": 18, "color": "#7f7f7f"} - vis = [[True, True, False], [False, False, True], [False, True, False]] - buttons = zip(["all", "train", "test"], [[{"visible": v}] for v in vis]) - buttons = [{"label": b, "args": v, "method": "update"} for b, v in buttons] - layout = go.Layout( - title=metric + " vs. epoch
[dash=train, solid=test]", - xaxis={"title": "epoch", "titlefont": titlefont}, - yaxis={"title": metric, "titlefont": titlefont}, - showlegend=True, - hoverlabel={"namelength": -1}, - updatemenus=[ - { - "buttons": buttons, - "direction": "down", - "showactive": True, - "x": 1.02, - "xanchor": "left", - "y": 1.08, - "yanchor": "top", - } - ], - ) - # Create plotly plot - offline.plot({"data": data, "layout": layout}, filename=filename) - - -def plot_error_curves_pyplot(log_files, names, filename=None, metric="top1_err"): - """Plot error curves using matplotlib.pyplot and save to file.""" - plot_data = prepare_plot_data(log_files, names, metric) - colors = get_plot_colors(len(names)) - for ind, d in enumerate(plot_data): - c, lbl = colors[ind], d["test_label"] - plt.plot(d["x_train"], d["y_train"], "--", c=c, alpha=0.8) - plt.plot(d["x_test"], d["y_test"], "-", c=c, alpha=0.8, label=lbl) - plt.title(metric + " vs. epoch\n[dash=train, solid=test]", fontsize=14) - plt.xlabel("epoch", fontsize=14) - plt.ylabel(metric, fontsize=14) - plt.grid(alpha=0.4) - plt.legend() - if filename: - plt.savefig(filename) - plt.clf() - else: - plt.show() +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +"""Plotting functions.""" + +import colorlover as cl +import matplotlib.pyplot as plt +import plotly.graph_objs as go +import plotly.offline as offline +import pycls.core.logging as logging + + +def get_plot_colors(max_colors, color_format="pyplot"): + """Generate colors for plotting.""" + colors = cl.scales["11"]["qual"]["Paired"] + if max_colors > len(colors): + colors = cl.to_rgb(cl.interp(colors, max_colors)) + if color_format == "pyplot": + return [[j / 255.0 for j in c] for c in cl.to_numeric(colors)] + return colors + + +def prepare_plot_data(log_files, names, metric="top1_err"): + """Load logs and extract data for plotting error curves.""" + plot_data = [] + for file, name in zip(log_files, names): + d, data = {}, logging.sort_log_data(logging.load_log_data(file)) + for phase in ["train", "test"]: + x = data[phase + "_epoch"]["epoch_ind"] + y = data[phase + "_epoch"][metric] + d["x_" + phase], d["y_" + phase] = x, y + d[phase + "_label"] = "[{:5.2f}] ".format(min(y) if y else 0) + name + plot_data.append(d) + assert len(plot_data) > 0, "No data to plot" + return plot_data + + +def plot_error_curves_plotly(log_files, names, filename, metric="top1_err"): + """Plot error curves using plotly and save to file.""" + plot_data = prepare_plot_data(log_files, names, metric) + colors = get_plot_colors(len(plot_data), "plotly") + # Prepare data for plots (3 sets, train duplicated w and w/o legend) + data = [] + for i, d in enumerate(plot_data): + s = str(i) + line_train = {"color": colors[i], "dash": "dashdot", "width": 1.5} + line_test = {"color": colors[i], "dash": "solid", "width": 1.5} + data.append( + go.Scatter( + x=d["x_train"], + y=d["y_train"], + mode="lines", + name=d["train_label"], + line=line_train, + legendgroup=s, + visible=True, + showlegend=False, + ) + ) + data.append( + go.Scatter( + x=d["x_test"], + y=d["y_test"], + mode="lines", + name=d["test_label"], + line=line_test, + legendgroup=s, + visible=True, + showlegend=True, + ) + ) + data.append( + go.Scatter( + x=d["x_train"], + y=d["y_train"], + mode="lines", + name=d["train_label"], + line=line_train, + legendgroup=s, + visible=False, + showlegend=True, + ) + ) + # Prepare layout w ability to toggle 'all', 'train', 'test' + titlefont = {"size": 18, "color": "#7f7f7f"} + vis = [[True, True, False], [False, False, True], [False, True, False]] + buttons = zip(["all", "train", "test"], [[{"visible": v}] for v in vis]) + buttons = [{"label": b, "args": v, "method": "update"} for b, v in buttons] + layout = go.Layout( + title=metric + " vs. epoch
[dash=train, solid=test]", + xaxis={"title": "epoch", "titlefont": titlefont}, + yaxis={"title": metric, "titlefont": titlefont}, + showlegend=True, + hoverlabel={"namelength": -1}, + updatemenus=[ + { + "buttons": buttons, + "direction": "down", + "showactive": True, + "x": 1.02, + "xanchor": "left", + "y": 1.08, + "yanchor": "top", + } + ], + ) + # Create plotly plot + offline.plot({"data": data, "layout": layout}, filename=filename) + + +def plot_error_curves_pyplot(log_files, names, filename=None, metric="top1_err"): + """Plot error curves using matplotlib.pyplot and save to file.""" + plot_data = prepare_plot_data(log_files, names, metric) + colors = get_plot_colors(len(names)) + for ind, d in enumerate(plot_data): + c, lbl = colors[ind], d["test_label"] + plt.plot(d["x_train"], d["y_train"], "--", c=c, alpha=0.8) + plt.plot(d["x_test"], d["y_test"], "-", c=c, alpha=0.8, label=lbl) + plt.title(metric + " vs. epoch\n[dash=train, solid=test]", fontsize=14) + plt.xlabel("epoch", fontsize=14) + plt.ylabel(metric, fontsize=14) + plt.grid(alpha=0.4) + plt.legend() + if filename: + plt.savefig(filename) + plt.clf() + else: + plt.show() diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/sgd.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/sgd.py index d390654bc7..5f6800a198 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/sgd.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/sgd.py @@ -1,212 +1,212 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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 torch -from torch.optim.optimizer import Optimizer, required -from collections import defaultdict -from pycls.core.combine_tensors import combine_npu - -class NpuFusedSGD(Optimizer): - r"""Implements stochastic gradient descent (optionally with momentum). - - Currently NPU-only. Requires Apex to be installed via - ``pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--npu_float_status" ./``. - - This version of fused SGD implements 1 fusions. - - * A combine-tensor apply launch that batches the elementwise updates applied to all the model's parameters into one or a few kernel launches. - - :class:`apex.optimizers.NpuFusedSGD` may be used as a drop-in replacement for ``torch.optim.SGD``:: - - opt = apex.optimizers.NpuFusedSGD(model.parameters(), lr = ....) - ... - opt.step() - - :class:`apex.optimizers.FusedSGD` should be used with Amp. Currently, if you wish to use :class:`NpuFusedSGD` with Amp, - only ``opt_level O2`` can be choosed:: - - opt = apex.optimizers.NpuFusedSGD(model.parameters(), lr = ....) - model, opt = amp.initialize(model, opt, opt_level="O2") - ... - opt.step() - - Nesterov momentum is based on the formula from - `On the importance of initialization and momentum in deep learning`__. - - Args: - params (iterable): iterable of parameters to optimize or dicts defining - parameter groups - lr (float): learning rate - momentum (float, optional): momentum factor (default: 0) - weight_decay (float, optional): weight decay (L2 penalty) (default: 0) - dampening (float, optional): dampening for momentum (default: 0) - nesterov (bool, optional): enables Nesterov momentum (default: False) - - Example: - >>> optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9) - >>> optimizer.zero_grad() - >>> loss_fn(model(input), target).backward() - >>> optimizer.step() - - __ http://www.cs.toronto.edu/%7Ehinton/absps/momentum.pdf - - .. note:: - The implementation of SGD with Momentum/Nesterov subtly differs from - Sutskever et. al. and implementations in some other frameworks. - - Considering the specific case of Momentum, the update can be written as - - .. math:: - \begin{aligned} - v_{t+1} & = \mu * v_{t} + g_{t+1}, \\ - p_{t+1} & = p_{t} - \text{lr} * v_{t+1}, - \end{aligned} - - where :math:`p`, :math:`g`, :math:`v` and :math:`\mu` denote the - parameters, gradient, velocity, and momentum respectively. - - This is in contrast to Sutskever et. al. and - other frameworks which employ an update of the form - - .. math:: - \begin{aligned} - v_{t+1} & = \mu * v_{t} + \text{lr} * g_{t+1}, \\ - p_{t+1} & = p_{t} - v_{t+1}. - \end{aligned} - - The Nesterov version is analogously modified. - """ - - def __init__(self, params, lr=required, momentum=0, dampening=0, - weight_decay=0, nesterov=False): - if lr is not required and lr < 0.0: - raise ValueError("Invalid learning rate: {}".format(lr)) - if momentum < 0.0: - raise ValueError("Invalid momentum value: {}".format(momentum)) - if weight_decay < 0.0: - raise ValueError("Invalid weight_decay value: {}".format(weight_decay)) - - defaults = dict(lr=lr, momentum=momentum, dampening=dampening, - weight_decay=weight_decay, nesterov=nesterov) - if nesterov and (momentum <= 0 or dampening != 0): - raise ValueError("Nesterov momentum requires a momentum and zero dampening") - super(NpuFusedSGD, self).__init__(params, defaults) - - def __setstate__(self, state): - super(NpuFusedSGD, self).__setstate__(state) - for group in self.param_groups: - group.setdefault('nesterov', False) - - def combine_param_state_by_group(self, momentum_buffer_in_state_before): - if not hasattr(self, "_amp_stash"): - raise RuntimeError('apex.optimizers.NpuFusedSGD should be used with AMP.') - - momentum_buffer_in_state_before = True - - stash = self._amp_stash - if stash.param_state_combined: - return - - for group in self.param_groups: - weight_decay = group['weight_decay'] - momentum = group['momentum'] - if momentum == 0: - state_combined = defaultdict(dict) - state_combined['momentum_buffer'] = None - stash.param_state_combined_list.append(state_combined) - continue - - momentum_buffer_list = [] - for p in group['params']: - if p.grad is None: - continue - - d_p = p.grad - state = self.state[p] - if 'momentum_buffer' not in state: - momentum_buffer_in_state_before = False - if weight_decay != 0: - d_p = d_p.add(p, alpha=weight_decay) - state['momentum_buffer'] = torch.clone(d_p).detach() - else: - temp = torch.clone(d_p).detach() - temp.copy_(state['momentum_buffer']) - state['momentum_buffer'] = temp - - momentum_buffer_list.append(state['momentum_buffer']) - - momentum_buffer_combined = None - if len(momentum_buffer_list) > 0: - momentum_buffer_combined = combine_npu(momentum_buffer_list) - - state_combined = defaultdict(dict) - state_combined['momentum_buffer'] = momentum_buffer_combined - stash.param_state_combined_list.append(state_combined) - - stash.param_state_combined = True - - @torch.no_grad() - def step(self, closure=None): - """Performs a single optimization step. - - Arguments: - closure (callable, optional): A closure that reevaluates the model - and returns the loss. - """ - if not hasattr(self, "_amp_stash"): - raise RuntimeError('apex.optimizers.NpuFusedSGD should be used with AMP.') - - momentum_buffer_in_state_before = True - self._combine_params_and_grads_by_group() - self.combine_param_state_by_group(momentum_buffer_in_state_before) - - loss = None - if closure is not None: - with torch.enable_grad(): - loss = closure() - - stash = self._amp_stash - - for i, group in enumerate(self.param_groups): - weight_decay = group['weight_decay'] - momentum = group['momentum'] - dampening = group['dampening'] - nesterov = group['nesterov'] - - params_combined = stash.params_combined_list[i] - grads_combined = stash.grads_combined_list[i] - if params_combined is None or grads_combined is None: - continue - - if weight_decay != 0: - grads_combined = grads_combined.add(params_combined, alpha=weight_decay) - if momentum != 0: - param_state = stash.param_state_combined_list[i] - buf = param_state['momentum_buffer'] - if momentum_buffer_in_state_before: - buf.mul_(momentum).add_(grads_combined, alpha=1 - dampening) - - if nesterov: - grads_combined = grads_combined.add(buf, alpha=momentum) - else: - grads_combined = buf - - params_combined.add_(grads_combined, alpha=-group['lr']) - - return loss +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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 torch +from torch.optim.optimizer import Optimizer, required +from collections import defaultdict +from pycls.core.combine_tensors import combine_npu + +class NpuFusedSGD(Optimizer): + r"""Implements stochastic gradient descent (optionally with momentum). + + Currently NPU-only. Requires Apex to be installed via + ``pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--npu_float_status" ./``. + + This version of fused SGD implements 1 fusions. + + * A combine-tensor apply launch that batches the elementwise updates applied to all the model's parameters into one or a few kernel launches. + + :class:`apex.optimizers.NpuFusedSGD` may be used as a drop-in replacement for ``torch.optim.SGD``:: + + opt = apex.optimizers.NpuFusedSGD(model.parameters(), lr = ....) + ... + opt.step() + + :class:`apex.optimizers.FusedSGD` should be used with Amp. Currently, if you wish to use :class:`NpuFusedSGD` with Amp, + only ``opt_level O2`` can be choosed:: + + opt = apex.optimizers.NpuFusedSGD(model.parameters(), lr = ....) + model, opt = amp.initialize(model, opt, opt_level="O2") + ... + opt.step() + + Nesterov momentum is based on the formula from + `On the importance of initialization and momentum in deep learning`__. + + Args: + params (iterable): iterable of parameters to optimize or dicts defining + parameter groups + lr (float): learning rate + momentum (float, optional): momentum factor (default: 0) + weight_decay (float, optional): weight decay (L2 penalty) (default: 0) + dampening (float, optional): dampening for momentum (default: 0) + nesterov (bool, optional): enables Nesterov momentum (default: False) + + Example: + >>> optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9) + >>> optimizer.zero_grad() + >>> loss_fn(model(input), target).backward() + >>> optimizer.step() + + __ http://www.cs.toronto.edu/%7Ehinton/absps/momentum.pdf + + .. note:: + The implementation of SGD with Momentum/Nesterov subtly differs from + Sutskever et. al. and implementations in some other frameworks. + + Considering the specific case of Momentum, the update can be written as + + .. math:: + \begin{aligned} + v_{t+1} & = \mu * v_{t} + g_{t+1}, \\ + p_{t+1} & = p_{t} - \text{lr} * v_{t+1}, + \end{aligned} + + where :math:`p`, :math:`g`, :math:`v` and :math:`\mu` denote the + parameters, gradient, velocity, and momentum respectively. + + This is in contrast to Sutskever et. al. and + other frameworks which employ an update of the form + + .. math:: + \begin{aligned} + v_{t+1} & = \mu * v_{t} + \text{lr} * g_{t+1}, \\ + p_{t+1} & = p_{t} - v_{t+1}. + \end{aligned} + + The Nesterov version is analogously modified. + """ + + def __init__(self, params, lr=required, momentum=0, dampening=0, + weight_decay=0, nesterov=False): + if lr is not required and lr < 0.0: + raise ValueError("Invalid learning rate: {}".format(lr)) + if momentum < 0.0: + raise ValueError("Invalid momentum value: {}".format(momentum)) + if weight_decay < 0.0: + raise ValueError("Invalid weight_decay value: {}".format(weight_decay)) + + defaults = dict(lr=lr, momentum=momentum, dampening=dampening, + weight_decay=weight_decay, nesterov=nesterov) + if nesterov and (momentum <= 0 or dampening != 0): + raise ValueError("Nesterov momentum requires a momentum and zero dampening") + super(NpuFusedSGD, self).__init__(params, defaults) + + def __setstate__(self, state): + super(NpuFusedSGD, self).__setstate__(state) + for group in self.param_groups: + group.setdefault('nesterov', False) + + def combine_param_state_by_group(self, momentum_buffer_in_state_before): + if not hasattr(self, "_amp_stash"): + raise RuntimeError('apex.optimizers.NpuFusedSGD should be used with AMP.') + + momentum_buffer_in_state_before = True + + stash = self._amp_stash + if stash.param_state_combined: + return + + for group in self.param_groups: + weight_decay = group['weight_decay'] + momentum = group['momentum'] + if momentum == 0: + state_combined = defaultdict(dict) + state_combined['momentum_buffer'] = None + stash.param_state_combined_list.append(state_combined) + continue + + momentum_buffer_list = [] + for p in group['params']: + if p.grad is None: + continue + + d_p = p.grad + state = self.state[p] + if 'momentum_buffer' not in state: + momentum_buffer_in_state_before = False + if weight_decay != 0: + d_p = d_p.add(p, alpha=weight_decay) + state['momentum_buffer'] = torch.clone(d_p).detach() + else: + temp = torch.clone(d_p).detach() + temp.copy_(state['momentum_buffer']) + state['momentum_buffer'] = temp + + momentum_buffer_list.append(state['momentum_buffer']) + + momentum_buffer_combined = None + if len(momentum_buffer_list) > 0: + momentum_buffer_combined = combine_npu(momentum_buffer_list) + + state_combined = defaultdict(dict) + state_combined['momentum_buffer'] = momentum_buffer_combined + stash.param_state_combined_list.append(state_combined) + + stash.param_state_combined = True + + @torch.no_grad() + def step(self, closure=None): + """Performs a single optimization step. + + Arguments: + closure (callable, optional): A closure that reevaluates the model + and returns the loss. + """ + if not hasattr(self, "_amp_stash"): + raise RuntimeError('apex.optimizers.NpuFusedSGD should be used with AMP.') + + momentum_buffer_in_state_before = True + self._combine_params_and_grads_by_group() + self.combine_param_state_by_group(momentum_buffer_in_state_before) + + loss = None + if closure is not None: + with torch.enable_grad(): + loss = closure() + + stash = self._amp_stash + + for i, group in enumerate(self.param_groups): + weight_decay = group['weight_decay'] + momentum = group['momentum'] + dampening = group['dampening'] + nesterov = group['nesterov'] + + params_combined = stash.params_combined_list[i] + grads_combined = stash.grads_combined_list[i] + if params_combined is None or grads_combined is None: + continue + + if weight_decay != 0: + grads_combined = grads_combined.add(params_combined, alpha=weight_decay) + if momentum != 0: + param_state = stash.param_state_combined_list[i] + buf = param_state['momentum_buffer'] + if momentum_buffer_in_state_before: + buf.mul_(momentum).add_(grads_combined, alpha=1 - dampening) + + if nesterov: + grads_combined = grads_combined.add(buf, alpha=momentum) + else: + grads_combined = buf + + params_combined.add_(grads_combined, alpha=-group['lr']) + + return loss diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/timer.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/timer.py index f2c0c2284e..1478b7efaa 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/timer.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/core/timer.py @@ -1,53 +1,53 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -"""Timer.""" - -import time - - -class Timer(object): - """A simple timer (adapted from Detectron).""" - - def __init__(self): - self.total_time = None - self.calls = None - self.start_time = None - self.diff = None - self.average_time = None - self.reset() - - def tic(self): - # using time.time as time.clock does not normalize for multithreading - self.start_time = time.time() - - def toc(self): - self.diff = time.time() - self.start_time - self.total_time += self.diff - self.calls += 1 - self.average_time = self.total_time / self.calls - - def reset(self): - self.total_time = 0.0 - self.calls = 0 - self.start_time = 0.0 - self.diff = 0.0 - self.average_time = 0.0 +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +"""Timer.""" + +import time + + +class Timer(object): + """A simple timer (adapted from Detectron).""" + + def __init__(self): + self.total_time = None + self.calls = None + self.start_time = None + self.diff = None + self.average_time = None + self.reset() + + def tic(self): + # using time.time as time.clock does not normalize for multithreading + self.start_time = time.time() + + def toc(self): + self.diff = time.time() - self.start_time + self.total_time += self.diff + self.calls += 1 + self.average_time = self.total_time / self.calls + + def reset(self): + self.total_time = 0.0 + self.calls = 0 + self.start_time = 0.0 + self.diff = 0.0 + self.average_time = 0.0 diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/augment.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/augment.py index 4f29c66d77..ba5e1426ed 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/augment.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/augment.py @@ -1,248 +1,248 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -""" -Lightweight and simple implementation of AutoAugment and RandAugment. - -AutoAugment - https://arxiv.org/abs/1805.09501 -RandAugment - https://arxiv.org/abs/1909.13719 - -http://github.com/tensorflow/tpu/blob/master/models/official/efficientnet/autoaugment.py -Note that the official implementation varies substantially from the papers :-( - -Our AutoAugment policy should be fairly identical to the official AutoAugment policy. -The main difference is we set POSTERIZE_MIN = 1, which avoids degenerate (all 0) images. -Our RandAugment policy differs, and uses transforms that increase in intensity with -increasing magnitude. This allows for a more natural control of the magnitude. That is, -setting magnitude = 0 results in ops that leaves the image unchanged, if possible. -We also set the range of the magnitude to be 0 to 1 to avoid setting a "max level". - -Our implementation is inspired by and uses policies that are the similar to those in: -https://github.com/rwightman/pytorch-image-models/blob/master/timm/data/auto_augment.py -Specifically our implementation can be *numerically identical* as the implementation in -timm if using timm's "v0" policy for AutoAugment and "inc" transforms for RandAugment -and if we set POSTERIZE_MIN = 0 (although as noted our default is POSTERIZE_MIN = 1). -Note that magnitude in our code ranges from 0 to 1 (compared to 0 to 10 in timm). - -Specifically, given the same seeds, the functions from timm: - out_auto = auto_augment_transform("v0", {"interpolation": 2})(im) - out_rand = rand_augment_transform("rand-inc1-n2-m05", {"interpolation": 2})(im) -Are numerically equivalent to: - POSTERIZE_MIN = 0 - out_auto = auto_augment(im) - out_rand = rand_augment(im, prob=0.5, n_ops=2, magnitude=0.5) -Tested as of 10/07/2020. Can alter corresponding params for both and should match. - -Finally, the ops and augmentations can be visualized as follows: - from PIL import Image - import pycls.datasets.augment as augment - im = Image.open("scratch.jpg") - im_ops = augment.visualize_ops(im) - im_rand = augment.visualize_aug(im, augment=augment.rand_augment, magnitude=0.5) - im_auto = augment.visualize_aug(im, augment=augment.auto_augment) - im_ops.show() - im_auto.show() - im_rand.show() -""" - -import random - -import numpy as np -from PIL import Image, ImageEnhance, ImageOps - - -# Minimum value for posterize (0 in EfficientNet implementation) -POSTERIZE_MIN = 1 - -# Parameters for affine warping and rotation -WARP_PARAMS = {"fillcolor": (128, 128, 128), "resample": Image.BILINEAR} - - -def affine_warp(im, data): - """Applies affine transform to image.""" - return im.transform(im.size, Image.AFFINE, data, **WARP_PARAMS) - - -OP_FUNCTIONS = { - # Each op takes an image x and a level v and returns an augmented image. - "auto_contrast": lambda x, _: ImageOps.autocontrast(x), - "equalize": lambda x, _: ImageOps.equalize(x), - "invert": lambda x, _: ImageOps.invert(x), - "rotate": lambda x, v: x.rotate(v, **WARP_PARAMS), - "posterize": lambda x, v: ImageOps.posterize(x, max(POSTERIZE_MIN, int(v))), - "posterize_inc": lambda x, v: ImageOps.posterize(x, max(POSTERIZE_MIN, 4 - int(v))), - "solarize": lambda x, v: x.point(lambda i: i if i < int(v) else 255 - i), - "solarize_inc": lambda x, v: x.point(lambda i: i if i < 256 - v else 255 - i), - "solarize_add": lambda x, v: x.point(lambda i: min(255, v + i) if i < 128 else i), - "color": lambda x, v: ImageEnhance.Color(x).enhance(v), - "contrast": lambda x, v: ImageEnhance.Contrast(x).enhance(v), - "brightness": lambda x, v: ImageEnhance.Brightness(x).enhance(v), - "sharpness": lambda x, v: ImageEnhance.Sharpness(x).enhance(v), - "color_inc": lambda x, v: ImageEnhance.Color(x).enhance(1 + v), - "contrast_inc": lambda x, v: ImageEnhance.Contrast(x).enhance(1 + v), - "brightness_inc": lambda x, v: ImageEnhance.Brightness(x).enhance(1 + v), - "sharpness_inc": lambda x, v: ImageEnhance.Sharpness(x).enhance(1 + v), - "shear_x": lambda x, v: affine_warp(x, (1, v, 0, 0, 1, 0)), - "shear_y": lambda x, v: affine_warp(x, (1, 0, 0, v, 1, 0)), - "trans_x": lambda x, v: affine_warp(x, (1, 0, v * x.size[0], 0, 1, 0)), - "trans_y": lambda x, v: affine_warp(x, (1, 0, 0, 0, 1, v * x.size[1])), -} - - -OP_RANGES = { - # Ranges for each op in the form of a (min, max, negate). - "auto_contrast": (0, 1, False), - "equalize": (0, 1, False), - "invert": (0, 1, False), - "rotate": (0.0, 30.0, True), - "posterize": (0, 4, False), - "posterize_inc": (0, 4, False), - "solarize": (0, 256, False), - "solarize_inc": (0, 256, False), - "solarize_add": (0, 110, False), - "color": (0.1, 1.9, False), - "contrast": (0.1, 1.9, False), - "brightness": (0.1, 1.9, False), - "sharpness": (0.1, 1.9, False), - "color_inc": (0, 0.9, True), - "contrast_inc": (0, 0.9, True), - "brightness_inc": (0, 0.9, True), - "sharpness_inc": (0, 0.9, True), - "shear_x": (0.0, 0.3, True), - "shear_y": (0.0, 0.3, True), - "trans_x": (0.0, 0.45, True), - "trans_y": (0.0, 0.45, True), -} - - -AUTOAUG_POLICY = [ - # AutoAugment "policy_v0" in form of (op, prob, magnitude), where magnitude <= 1. - [("equalize", 0.8, 0.1), ("shear_y", 0.8, 0.4)], - [("color", 0.4, 0.9), ("equalize", 0.6, 0.3)], - [("color", 0.4, 0.1), ("rotate", 0.6, 0.8)], - [("solarize", 0.8, 0.3), ("equalize", 0.4, 0.7)], - [("solarize", 0.4, 0.2), ("solarize", 0.6, 0.2)], - [("color", 0.2, 0.0), ("equalize", 0.8, 0.8)], - [("equalize", 0.4, 0.8), ("solarize_add", 0.8, 0.3)], - [("shear_x", 0.2, 0.9), ("rotate", 0.6, 0.8)], - [("color", 0.6, 0.1), ("equalize", 1.0, 0.2)], - [("invert", 0.4, 0.9), ("rotate", 0.6, 0.0)], - [("equalize", 1.0, 0.9), ("shear_y", 0.6, 0.3)], - [("color", 0.4, 0.7), ("equalize", 0.6, 0.0)], - [("posterize", 0.4, 0.6), ("auto_contrast", 0.4, 0.7)], - [("solarize", 0.6, 0.8), ("color", 0.6, 0.9)], - [("solarize", 0.2, 0.4), ("rotate", 0.8, 0.9)], - [("rotate", 1.0, 0.7), ("trans_y", 0.8, 0.9)], - [("shear_x", 0.0, 0.0), ("solarize", 0.8, 0.4)], - [("shear_y", 0.8, 0.0), ("color", 0.6, 0.4)], - [("color", 1.0, 0.0), ("rotate", 0.6, 0.2)], - [("equalize", 0.8, 0.4), ("equalize", 0.0, 0.8)], - [("equalize", 1.0, 0.4), ("auto_contrast", 0.6, 0.2)], - [("shear_y", 0.4, 0.7), ("solarize_add", 0.6, 0.7)], - [("posterize", 0.8, 0.2), ("solarize", 0.6, 1.0)], - [("solarize", 0.6, 0.8), ("equalize", 0.6, 0.1)], - [("color", 0.8, 0.6), ("rotate", 0.4, 0.5)], -] - - -RANDAUG_OPS = [ - # RandAugment list of operations using "increasing" transforms. - "auto_contrast", - "equalize", - "invert", - "rotate", - "posterize_inc", - "solarize_inc", - "solarize_add", - "color_inc", - "contrast_inc", - "brightness_inc", - "sharpness_inc", - "shear_x", - "shear_y", - "trans_x", - "trans_y", -] - - -def apply_op(im, op, prob, magnitude): - """Apply the selected op to image with given probability and magnitude.""" - # The magnitude is converted to an absolute value v for an op (some ops use -v or v) - assert 0 <= magnitude <= 1 - assert op in OP_RANGES and op in OP_FUNCTIONS, "unknown op " + op - if prob < 1 and random.random() > prob: - return im - min_v, max_v, negate = OP_RANGES[op] - v = magnitude * (max_v - min_v) + min_v - v = -v if negate and random.random() > 0.5 else v - return OP_FUNCTIONS[op](im, v) - - -def rand_augment(im, magnitude, ops=None, n_ops=2, prob=1.0): - """Applies random augmentation to an image.""" - ops = ops if ops else RANDAUG_OPS - for op in np.random.choice(ops, int(n_ops)): - im = apply_op(im, op, prob, magnitude) - return im - - -def auto_augment(im, policy=None): - """Apply auto augmentation to an image.""" - policy = policy if policy else AUTOAUG_POLICY - for op, prob, magnitude in random.choice(policy): - im = apply_op(im, op, prob, magnitude) - return im - - -def make_augment(augment_str): - """Generate augmentation function from separated parameter string. - The parameter string augment_str may be either "AutoAugment" or "RandAugment". - Undocumented use allows for specifying extra params, e.g. "RandAugment_N2_M0.5".""" - params = augment_str.split("_") - names = {"N": "n_ops", "M": "magnitude", "P": "prob"} - assert params[0] in ["RandAugment", "AutoAugment"] - assert all(p[0] in names for p in params[1:]) - keys = [names[p[0]] for p in params[1:]] - vals = [float(p[1:]) for p in params[1:]] - augment = rand_augment if params[0] == "RandAugment" else auto_augment - return lambda im: augment(im, **dict(zip(keys, vals))) - - -def visualize_ops(im, ops=None, num_steps=10): - """Visualize ops by applying each op by varying amounts.""" - ops = ops if ops else RANDAUG_OPS - w, h, magnitudes = im.size[0], im.size[1], np.linspace(0, 1, num_steps) - output = Image.new("RGB", (w * num_steps, h * len(ops))) - for i, op in enumerate(ops): - for j, m in enumerate(magnitudes): - out = apply_op(im, op, prob=1.0, magnitude=m) - output.paste(out, (j * w, i * h)) - return output - - -def visualize_aug(im, augment=rand_augment, num_trials=10, **kwargs): - """Visualize augmentation by applying random augmentations.""" - w, h = im.size[0], im.size[1] - output = Image.new("RGB", (w * num_trials, h * num_trials)) - for i in range(num_trials): - for j in range(num_trials): - output.paste(augment(im, **kwargs), (j * w, i * h)) - return output +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +""" +Lightweight and simple implementation of AutoAugment and RandAugment. + +AutoAugment - https://arxiv.org/abs/1805.09501 +RandAugment - https://arxiv.org/abs/1909.13719 + +http://github.com/tensorflow/tpu/blob/master/models/official/efficientnet/autoaugment.py +Note that the official implementation varies substantially from the papers :-( + +Our AutoAugment policy should be fairly identical to the official AutoAugment policy. +The main difference is we set POSTERIZE_MIN = 1, which avoids degenerate (all 0) images. +Our RandAugment policy differs, and uses transforms that increase in intensity with +increasing magnitude. This allows for a more natural control of the magnitude. That is, +setting magnitude = 0 results in ops that leaves the image unchanged, if possible. +We also set the range of the magnitude to be 0 to 1 to avoid setting a "max level". + +Our implementation is inspired by and uses policies that are the similar to those in: +https://github.com/rwightman/pytorch-image-models/blob/master/timm/data/auto_augment.py +Specifically our implementation can be *numerically identical* as the implementation in +timm if using timm's "v0" policy for AutoAugment and "inc" transforms for RandAugment +and if we set POSTERIZE_MIN = 0 (although as noted our default is POSTERIZE_MIN = 1). +Note that magnitude in our code ranges from 0 to 1 (compared to 0 to 10 in timm). + +Specifically, given the same seeds, the functions from timm: + out_auto = auto_augment_transform("v0", {"interpolation": 2})(im) + out_rand = rand_augment_transform("rand-inc1-n2-m05", {"interpolation": 2})(im) +Are numerically equivalent to: + POSTERIZE_MIN = 0 + out_auto = auto_augment(im) + out_rand = rand_augment(im, prob=0.5, n_ops=2, magnitude=0.5) +Tested as of 10/07/2020. Can alter corresponding params for both and should match. + +Finally, the ops and augmentations can be visualized as follows: + from PIL import Image + import pycls.datasets.augment as augment + im = Image.open("scratch.jpg") + im_ops = augment.visualize_ops(im) + im_rand = augment.visualize_aug(im, augment=augment.rand_augment, magnitude=0.5) + im_auto = augment.visualize_aug(im, augment=augment.auto_augment) + im_ops.show() + im_auto.show() + im_rand.show() +""" + +import random + +import numpy as np +from PIL import Image, ImageEnhance, ImageOps + + +# Minimum value for posterize (0 in EfficientNet implementation) +POSTERIZE_MIN = 1 + +# Parameters for affine warping and rotation +WARP_PARAMS = {"fillcolor": (128, 128, 128), "resample": Image.BILINEAR} + + +def affine_warp(im, data): + """Applies affine transform to image.""" + return im.transform(im.size, Image.AFFINE, data, **WARP_PARAMS) + + +OP_FUNCTIONS = { + # Each op takes an image x and a level v and returns an augmented image. + "auto_contrast": lambda x, _: ImageOps.autocontrast(x), + "equalize": lambda x, _: ImageOps.equalize(x), + "invert": lambda x, _: ImageOps.invert(x), + "rotate": lambda x, v: x.rotate(v, **WARP_PARAMS), + "posterize": lambda x, v: ImageOps.posterize(x, max(POSTERIZE_MIN, int(v))), + "posterize_inc": lambda x, v: ImageOps.posterize(x, max(POSTERIZE_MIN, 4 - int(v))), + "solarize": lambda x, v: x.point(lambda i: i if i < int(v) else 255 - i), + "solarize_inc": lambda x, v: x.point(lambda i: i if i < 256 - v else 255 - i), + "solarize_add": lambda x, v: x.point(lambda i: min(255, v + i) if i < 128 else i), + "color": lambda x, v: ImageEnhance.Color(x).enhance(v), + "contrast": lambda x, v: ImageEnhance.Contrast(x).enhance(v), + "brightness": lambda x, v: ImageEnhance.Brightness(x).enhance(v), + "sharpness": lambda x, v: ImageEnhance.Sharpness(x).enhance(v), + "color_inc": lambda x, v: ImageEnhance.Color(x).enhance(1 + v), + "contrast_inc": lambda x, v: ImageEnhance.Contrast(x).enhance(1 + v), + "brightness_inc": lambda x, v: ImageEnhance.Brightness(x).enhance(1 + v), + "sharpness_inc": lambda x, v: ImageEnhance.Sharpness(x).enhance(1 + v), + "shear_x": lambda x, v: affine_warp(x, (1, v, 0, 0, 1, 0)), + "shear_y": lambda x, v: affine_warp(x, (1, 0, 0, v, 1, 0)), + "trans_x": lambda x, v: affine_warp(x, (1, 0, v * x.size[0], 0, 1, 0)), + "trans_y": lambda x, v: affine_warp(x, (1, 0, 0, 0, 1, v * x.size[1])), +} + + +OP_RANGES = { + # Ranges for each op in the form of a (min, max, negate). + "auto_contrast": (0, 1, False), + "equalize": (0, 1, False), + "invert": (0, 1, False), + "rotate": (0.0, 30.0, True), + "posterize": (0, 4, False), + "posterize_inc": (0, 4, False), + "solarize": (0, 256, False), + "solarize_inc": (0, 256, False), + "solarize_add": (0, 110, False), + "color": (0.1, 1.9, False), + "contrast": (0.1, 1.9, False), + "brightness": (0.1, 1.9, False), + "sharpness": (0.1, 1.9, False), + "color_inc": (0, 0.9, True), + "contrast_inc": (0, 0.9, True), + "brightness_inc": (0, 0.9, True), + "sharpness_inc": (0, 0.9, True), + "shear_x": (0.0, 0.3, True), + "shear_y": (0.0, 0.3, True), + "trans_x": (0.0, 0.45, True), + "trans_y": (0.0, 0.45, True), +} + + +AUTOAUG_POLICY = [ + # AutoAugment "policy_v0" in form of (op, prob, magnitude), where magnitude <= 1. + [("equalize", 0.8, 0.1), ("shear_y", 0.8, 0.4)], + [("color", 0.4, 0.9), ("equalize", 0.6, 0.3)], + [("color", 0.4, 0.1), ("rotate", 0.6, 0.8)], + [("solarize", 0.8, 0.3), ("equalize", 0.4, 0.7)], + [("solarize", 0.4, 0.2), ("solarize", 0.6, 0.2)], + [("color", 0.2, 0.0), ("equalize", 0.8, 0.8)], + [("equalize", 0.4, 0.8), ("solarize_add", 0.8, 0.3)], + [("shear_x", 0.2, 0.9), ("rotate", 0.6, 0.8)], + [("color", 0.6, 0.1), ("equalize", 1.0, 0.2)], + [("invert", 0.4, 0.9), ("rotate", 0.6, 0.0)], + [("equalize", 1.0, 0.9), ("shear_y", 0.6, 0.3)], + [("color", 0.4, 0.7), ("equalize", 0.6, 0.0)], + [("posterize", 0.4, 0.6), ("auto_contrast", 0.4, 0.7)], + [("solarize", 0.6, 0.8), ("color", 0.6, 0.9)], + [("solarize", 0.2, 0.4), ("rotate", 0.8, 0.9)], + [("rotate", 1.0, 0.7), ("trans_y", 0.8, 0.9)], + [("shear_x", 0.0, 0.0), ("solarize", 0.8, 0.4)], + [("shear_y", 0.8, 0.0), ("color", 0.6, 0.4)], + [("color", 1.0, 0.0), ("rotate", 0.6, 0.2)], + [("equalize", 0.8, 0.4), ("equalize", 0.0, 0.8)], + [("equalize", 1.0, 0.4), ("auto_contrast", 0.6, 0.2)], + [("shear_y", 0.4, 0.7), ("solarize_add", 0.6, 0.7)], + [("posterize", 0.8, 0.2), ("solarize", 0.6, 1.0)], + [("solarize", 0.6, 0.8), ("equalize", 0.6, 0.1)], + [("color", 0.8, 0.6), ("rotate", 0.4, 0.5)], +] + + +RANDAUG_OPS = [ + # RandAugment list of operations using "increasing" transforms. + "auto_contrast", + "equalize", + "invert", + "rotate", + "posterize_inc", + "solarize_inc", + "solarize_add", + "color_inc", + "contrast_inc", + "brightness_inc", + "sharpness_inc", + "shear_x", + "shear_y", + "trans_x", + "trans_y", +] + + +def apply_op(im, op, prob, magnitude): + """Apply the selected op to image with given probability and magnitude.""" + # The magnitude is converted to an absolute value v for an op (some ops use -v or v) + assert 0 <= magnitude <= 1 + assert op in OP_RANGES and op in OP_FUNCTIONS, "unknown op " + op + if prob < 1 and random.random() > prob: + return im + min_v, max_v, negate = OP_RANGES[op] + v = magnitude * (max_v - min_v) + min_v + v = -v if negate and random.random() > 0.5 else v + return OP_FUNCTIONS[op](im, v) + + +def rand_augment(im, magnitude, ops=None, n_ops=2, prob=1.0): + """Applies random augmentation to an image.""" + ops = ops if ops else RANDAUG_OPS + for op in np.random.choice(ops, int(n_ops)): + im = apply_op(im, op, prob, magnitude) + return im + + +def auto_augment(im, policy=None): + """Apply auto augmentation to an image.""" + policy = policy if policy else AUTOAUG_POLICY + for op, prob, magnitude in random.choice(policy): + im = apply_op(im, op, prob, magnitude) + return im + + +def make_augment(augment_str): + """Generate augmentation function from separated parameter string. + The parameter string augment_str may be either "AutoAugment" or "RandAugment". + Undocumented use allows for specifying extra params, e.g. "RandAugment_N2_M0.5".""" + params = augment_str.split("_") + names = {"N": "n_ops", "M": "magnitude", "P": "prob"} + assert params[0] in ["RandAugment", "AutoAugment"] + assert all(p[0] in names for p in params[1:]) + keys = [names[p[0]] for p in params[1:]] + vals = [float(p[1:]) for p in params[1:]] + augment = rand_augment if params[0] == "RandAugment" else auto_augment + return lambda im: augment(im, **dict(zip(keys, vals))) + + +def visualize_ops(im, ops=None, num_steps=10): + """Visualize ops by applying each op by varying amounts.""" + ops = ops if ops else RANDAUG_OPS + w, h, magnitudes = im.size[0], im.size[1], np.linspace(0, 1, num_steps) + output = Image.new("RGB", (w * num_steps, h * len(ops))) + for i, op in enumerate(ops): + for j, m in enumerate(magnitudes): + out = apply_op(im, op, prob=1.0, magnitude=m) + output.paste(out, (j * w, i * h)) + return output + + +def visualize_aug(im, augment=rand_augment, num_trials=10, **kwargs): + """Visualize augmentation by applying random augmentations.""" + w, h = im.size[0], im.size[1] + output = Image.new("RGB", (w * num_trials, h * num_trials)) + for i in range(num_trials): + for j in range(num_trials): + output.paste(augment(im, **kwargs), (j * w, i * h)) + return output diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/cifar10.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/cifar10.py index f2ed7434b2..9922ca032a 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/cifar10.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/cifar10.py @@ -1,95 +1,95 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -"""CIFAR10 dataset.""" - -import os -import pickle - -import numpy as np -import pycls.core.logging as logging -import torch.utils.data -from iopath.common.file_io import g_pathmgr -from pycls.core.config import cfg - - -logger = logging.get_logger(__name__) - -# Per-channel mean and standard deviation values on CIFAR -_MEAN = [125.3, 123.0, 113.9] -_STD = [63.0, 62.1, 66.7] - - -class Cifar10(torch.utils.data.Dataset): - """CIFAR-10 dataset.""" - - def __init__(self, data_path, split): - assert g_pathmgr.exists(data_path), "Data path '{}' not found".format(data_path) - splits = ["train", "test"] - assert split in splits, "Split '{}' not supported for cifar".format(split) - logger.info("Constructing CIFAR-10 {}...".format(split)) - self._im_size = cfg.TRAIN.IM_SIZE - self._data_path, self._split = data_path, split - self._inputs, self._labels = self._load_data() - - def _load_data(self): - """Loads data into memory.""" - logger.info("{} data path: {}".format(self._split, self._data_path)) - # Compute data batch names - if self._split == "train": - batch_names = ["data_batch_{}".format(i) for i in range(1, 6)] - else: - batch_names = ["test_batch"] - # Load data batches - inputs, labels = [], [] - for batch_name in batch_names: - batch_path = os.path.join(self._data_path, batch_name) - with g_pathmgr.open(batch_path, "rb") as f: - data = pickle.load(f, encoding="bytes") - inputs.append(data[b"data"]) - labels += data[b"labels"] - # Combine and reshape the inputs - inputs = np.vstack(inputs).astype(np.float32) - inputs = inputs.reshape((-1, 3, self._im_size, self._im_size)) - return inputs, labels - - def _prepare_im(self, im): - """Prepares the image for network input.""" - for i in range(3): - # Perform per-channel normalization on CHW image - im[i] = (im[i] - _MEAN[i]) / _STD[i] - if self._split == "train": - # Randomly flip and crop center patch from CHW image - size = self._im_size - im = im[:, :, ::-1] if np.random.uniform() < 0.5 else im - im = np.pad(im, ((0, 0), (4, 4), (4, 4)), mode="constant") - y = np.random.randint(0, im.shape[1] - size) - x = np.random.randint(0, im.shape[2] - size) - im = im[:, y : (y + size), x : (x + size)] - return im - - def __getitem__(self, index): - im, label = self._inputs[index, ...].copy(), self._labels[index] - im = self._prepare_im(im) - return im, label - - def __len__(self): - return self._inputs.shape[0] +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +"""CIFAR10 dataset.""" + +import os +import pickle + +import numpy as np +import pycls.core.logging as logging +import torch.utils.data +from iopath.common.file_io import g_pathmgr +from pycls.core.config import cfg + + +logger = logging.get_logger(__name__) + +# Per-channel mean and standard deviation values on CIFAR +_MEAN = [125.3, 123.0, 113.9] +_STD = [63.0, 62.1, 66.7] + + +class Cifar10(torch.utils.data.Dataset): + """CIFAR-10 dataset.""" + + def __init__(self, data_path, split): + assert g_pathmgr.exists(data_path), "Data path '{}' not found".format(data_path) + splits = ["train", "test"] + assert split in splits, "Split '{}' not supported for cifar".format(split) + logger.info("Constructing CIFAR-10 {}...".format(split)) + self._im_size = cfg.TRAIN.IM_SIZE + self._data_path, self._split = data_path, split + self._inputs, self._labels = self._load_data() + + def _load_data(self): + """Loads data into memory.""" + logger.info("{} data path: {}".format(self._split, self._data_path)) + # Compute data batch names + if self._split == "train": + batch_names = ["data_batch_{}".format(i) for i in range(1, 6)] + else: + batch_names = ["test_batch"] + # Load data batches + inputs, labels = [], [] + for batch_name in batch_names: + batch_path = os.path.join(self._data_path, batch_name) + with g_pathmgr.open(batch_path, "rb") as f: + data = pickle.load(f, encoding="bytes") + inputs.append(data[b"data"]) + labels += data[b"labels"] + # Combine and reshape the inputs + inputs = np.vstack(inputs).astype(np.float32) + inputs = inputs.reshape((-1, 3, self._im_size, self._im_size)) + return inputs, labels + + def _prepare_im(self, im): + """Prepares the image for network input.""" + for i in range(3): + # Perform per-channel normalization on CHW image + im[i] = (im[i] - _MEAN[i]) / _STD[i] + if self._split == "train": + # Randomly flip and crop center patch from CHW image + size = self._im_size + im = im[:, :, ::-1] if np.random.uniform() < 0.5 else im + im = np.pad(im, ((0, 0), (4, 4), (4, 4)), mode="constant") + y = np.random.randint(0, im.shape[1] - size) + x = np.random.randint(0, im.shape[2] - size) + im = im[:, y : (y + size), x : (x + size)] + return im + + def __getitem__(self, index): + im, label = self._inputs[index, ...].copy(), self._labels[index] + im = self._prepare_im(im) + return im, label + + def __len__(self): + return self._inputs.shape[0] diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/imagenet.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/imagenet.py index 8234ec4a40..31edfb723f 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/imagenet.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/imagenet.py @@ -1,116 +1,116 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -"""ImageNet dataset.""" - -import os -import re - -import cv2 -cv2.setNumThreads(1) -import numpy as np -import pycls.core.logging as logging -import pycls.datasets.transforms as transforms -import torch.utils.data -from pycls.core.config import cfg - - -logger = logging.get_logger(__name__) - -# Per-channel mean and standard deviation values on ImageNet (in RGB order) -# https://github.com/facebookarchive/fb.resnet.torch/blob/master/datasets/imagenet.lua -_MEAN = [0.485, 0.456, 0.406] -_STD = [0.229, 0.224, 0.225] - -# Constants for lighting normalization on ImageNet (in RGB order) -# https://github.com/facebookarchive/fb.resnet.torch/blob/master/datasets/imagenet.lua -_EIG_VALS = [[0.2175, 0.0188, 0.0045]] -_EIG_VECS = [ - [-0.5675, 0.7192, 0.4009], - [-0.5808, -0.0045, -0.8140], - [-0.5836, -0.6948, 0.4203], -] - - -class ImageNet(torch.utils.data.Dataset): - """ImageNet dataset.""" - - def __init__(self, data_path, split): - assert os.path.exists(data_path), "Data path '{}' not found".format(data_path) - splits = ["train", "val"] - assert split in splits, "Split '{}' not supported for ImageNet".format(split) - logger.info("Constructing ImageNet {}...".format(split)) - self._data_path, self._split = data_path, split - self._construct_imdb() - - def _construct_imdb(self): - """Constructs the imdb.""" - # Compile the split data path - split_path = os.path.join(self._data_path, self._split) - logger.info("{} data path: {}".format(self._split, split_path)) - # Images are stored per class in subdirs (format: n) - split_files = os.listdir(split_path) - self._class_ids = sorted(f for f in split_files if re.match(r"^n[0-9]+$", f)) - # Map ImageNet class ids to contiguous ids - self._class_id_cont_id = {v: i for i, v in enumerate(self._class_ids)} - # Construct the image db - self._imdb = [] - for class_id in self._class_ids: - cont_id = self._class_id_cont_id[class_id] - im_dir = os.path.join(split_path, class_id) - for im_name in os.listdir(im_dir): - im_path = os.path.join(im_dir, im_name) - self._imdb.append({"im_path": im_path, "class": cont_id}) - logger.info("Number of images: {}".format(len(self._imdb))) - logger.info("Number of classes: {}".format(len(self._class_ids))) - - def _prepare_im(self, im): - """Prepares the image for network input (HWC/BGR/int -> CHW/BGR/float).""" - # Convert HWC/BGR/int to HWC/RGB/float format for applying transforms - im = im[:, :, ::-1].astype(np.float32) / 255 - # Train and test setups differ - train_size, test_size = cfg.TRAIN.IM_SIZE, cfg.TEST.IM_SIZE - if self._split == "train": - # For training use random_sized_crop, horizontal_flip, augment, lighting - im = transforms.random_sized_crop(im, train_size) - im = transforms.horizontal_flip(im, prob=0.5) - im = transforms.augment(im, cfg.TRAIN.AUGMENT) - im = transforms.lighting(im, cfg.TRAIN.PCA_STD, _EIG_VALS, _EIG_VECS) - else: - # For testing use scale and center crop - im = transforms.scale_and_center_crop(im, test_size, train_size) - # For training and testing use color normalization - im = transforms.color_norm(im, _MEAN, _STD) - # Convert HWC/RGB/float to CHW/BGR/float format - im = np.ascontiguousarray(im[:, :, ::-1].transpose([2, 0, 1])) - return im - - def __getitem__(self, index): - # Load the image - im = cv2.imread(self._imdb[index]["im_path"]) - # Prepare the image for training / testing - im = self._prepare_im(im) - # Retrieve the label - label = self._imdb[index]["class"] - return im, label - - def __len__(self): - return len(self._imdb) +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +"""ImageNet dataset.""" + +import os +import re + +import cv2 +cv2.setNumThreads(1) +import numpy as np +import pycls.core.logging as logging +import pycls.datasets.transforms as transforms +import torch.utils.data +from pycls.core.config import cfg + + +logger = logging.get_logger(__name__) + +# Per-channel mean and standard deviation values on ImageNet (in RGB order) +# https://github.com/facebookarchive/fb.resnet.torch/blob/master/datasets/imagenet.lua +_MEAN = [0.485, 0.456, 0.406] +_STD = [0.229, 0.224, 0.225] + +# Constants for lighting normalization on ImageNet (in RGB order) +# https://github.com/facebookarchive/fb.resnet.torch/blob/master/datasets/imagenet.lua +_EIG_VALS = [[0.2175, 0.0188, 0.0045]] +_EIG_VECS = [ + [-0.5675, 0.7192, 0.4009], + [-0.5808, -0.0045, -0.8140], + [-0.5836, -0.6948, 0.4203], +] + + +class ImageNet(torch.utils.data.Dataset): + """ImageNet dataset.""" + + def __init__(self, data_path, split): + assert os.path.exists(data_path), "Data path '{}' not found".format(data_path) + splits = ["train", "val"] + assert split in splits, "Split '{}' not supported for ImageNet".format(split) + logger.info("Constructing ImageNet {}...".format(split)) + self._data_path, self._split = data_path, split + self._construct_imdb() + + def _construct_imdb(self): + """Constructs the imdb.""" + # Compile the split data path + split_path = os.path.join(self._data_path, self._split) + logger.info("{} data path: {}".format(self._split, split_path)) + # Images are stored per class in subdirs (format: n) + split_files = os.listdir(split_path) + self._class_ids = sorted(f for f in split_files if re.match(r"^n[0-9]+$", f)) + # Map ImageNet class ids to contiguous ids + self._class_id_cont_id = {v: i for i, v in enumerate(self._class_ids)} + # Construct the image db + self._imdb = [] + for class_id in self._class_ids: + cont_id = self._class_id_cont_id[class_id] + im_dir = os.path.join(split_path, class_id) + for im_name in os.listdir(im_dir): + im_path = os.path.join(im_dir, im_name) + self._imdb.append({"im_path": im_path, "class": cont_id}) + logger.info("Number of images: {}".format(len(self._imdb))) + logger.info("Number of classes: {}".format(len(self._class_ids))) + + def _prepare_im(self, im): + """Prepares the image for network input (HWC/BGR/int -> CHW/BGR/float).""" + # Convert HWC/BGR/int to HWC/RGB/float format for applying transforms + im = im[:, :, ::-1].astype(np.float32) / 255 + # Train and test setups differ + train_size, test_size = cfg.TRAIN.IM_SIZE, cfg.TEST.IM_SIZE + if self._split == "train": + # For training use random_sized_crop, horizontal_flip, augment, lighting + im = transforms.random_sized_crop(im, train_size) + im = transforms.horizontal_flip(im, prob=0.5) + im = transforms.augment(im, cfg.TRAIN.AUGMENT) + im = transforms.lighting(im, cfg.TRAIN.PCA_STD, _EIG_VALS, _EIG_VECS) + else: + # For testing use scale and center crop + im = transforms.scale_and_center_crop(im, test_size, train_size) + # For training and testing use color normalization + im = transforms.color_norm(im, _MEAN, _STD) + # Convert HWC/RGB/float to CHW/BGR/float format + im = np.ascontiguousarray(im[:, :, ::-1].transpose([2, 0, 1])) + return im + + def __getitem__(self, index): + # Load the image + im = cv2.imread(self._imdb[index]["im_path"]) + # Prepare the image for training / testing + im = self._prepare_im(im) + # Retrieve the label + label = self._imdb[index]["class"] + return im, label + + def __len__(self): + return len(self._imdb) diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/loader.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/loader.py index 72d411ddb1..6b772eccd4 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/loader.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/loader.py @@ -1,96 +1,96 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -"""Data loader.""" - -import os - -import torch -from pycls.core.config import cfg -from pycls.datasets.cifar10 import Cifar10 -from pycls.datasets.imagenet import ImageNet -from torch.utils.data.distributed import DistributedSampler -from torch.utils.data.sampler import RandomSampler - - -# Supported datasets -_DATASETS = {"cifar10": Cifar10, "imagenet": ImageNet} - -# Default data directory (/path/pycls/pycls/datasets/data) -_DATA_DIR = "./pycls/datasets/data" - -# Relative data paths to default data directory -_PATHS = {"cifar10": "cifar10", "imagenet": "imagenet"} - - -def _construct_loader(dataset_name, split, batch_size, shuffle, drop_last): - """Constructs the data loader for the given dataset.""" - err_str = "Dataset '{}' not supported".format(dataset_name) - assert dataset_name in _DATASETS and dataset_name in _PATHS, err_str - # Retrieve the data path for the dataset - data_path = os.path.join(_DATA_DIR, _PATHS[dataset_name]) - # Construct the dataset - dataset = _DATASETS[dataset_name](data_path, split) - # Create a sampler for multi-process training - sampler = DistributedSampler(dataset) if cfg.NUM_GPUS > 1 else None - # Create a loader - loader = torch.utils.data.DataLoader( - dataset, - batch_size=batch_size, - shuffle=(False if sampler else shuffle), - sampler=sampler, - num_workers=cfg.DATA_LOADER.NUM_WORKERS, - pin_memory=cfg.DATA_LOADER.PIN_MEMORY, - drop_last=drop_last, - ) - return loader - - -def construct_train_loader(): - """Train loader wrapper.""" - return _construct_loader( - dataset_name=cfg.TRAIN.DATASET, - split=cfg.TRAIN.SPLIT, - batch_size=int(cfg.TRAIN.BATCH_SIZE / cfg.NUM_GPUS), - shuffle=True, - drop_last=True, - ) - - -def construct_test_loader(): - """Test loader wrapper.""" - return _construct_loader( - dataset_name=cfg.TEST.DATASET, - split=cfg.TEST.SPLIT, - batch_size=int(cfg.TEST.BATCH_SIZE / cfg.NUM_GPUS), - shuffle=False, - drop_last=False, - ) - - -def shuffle(loader, cur_epoch): - """"Shuffles the data.""" - err_str = "Sampler type '{}' not supported".format(type(loader.sampler)) - assert isinstance(loader.sampler, (RandomSampler, DistributedSampler)), err_str - # RandomSampler handles shuffling automatically - if isinstance(loader.sampler, DistributedSampler): - # DistributedSampler shuffles data based on epoch - loader.sampler.set_epoch(cur_epoch) +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +"""Data loader.""" + +import os + +import torch +from pycls.core.config import cfg +from pycls.datasets.cifar10 import Cifar10 +from pycls.datasets.imagenet import ImageNet +from torch.utils.data.distributed import DistributedSampler +from torch.utils.data.sampler import RandomSampler + + +# Supported datasets +_DATASETS = {"cifar10": Cifar10, "imagenet": ImageNet} + +# Default data directory (/path/pycls/pycls/datasets/data) +_DATA_DIR = "./pycls/datasets/data" + +# Relative data paths to default data directory +_PATHS = {"cifar10": "cifar10", "imagenet": "imagenet"} + + +def _construct_loader(dataset_name, split, batch_size, shuffle, drop_last): + """Constructs the data loader for the given dataset.""" + err_str = "Dataset '{}' not supported".format(dataset_name) + assert dataset_name in _DATASETS and dataset_name in _PATHS, err_str + # Retrieve the data path for the dataset + data_path = os.path.join(_DATA_DIR, _PATHS[dataset_name]) + # Construct the dataset + dataset = _DATASETS[dataset_name](data_path, split) + # Create a sampler for multi-process training + sampler = DistributedSampler(dataset) if cfg.NUM_GPUS > 1 else None + # Create a loader + loader = torch.utils.data.DataLoader( + dataset, + batch_size=batch_size, + shuffle=(False if sampler else shuffle), + sampler=sampler, + num_workers=cfg.DATA_LOADER.NUM_WORKERS, + pin_memory=cfg.DATA_LOADER.PIN_MEMORY, + drop_last=drop_last, + ) + return loader + + +def construct_train_loader(): + """Train loader wrapper.""" + return _construct_loader( + dataset_name=cfg.TRAIN.DATASET, + split=cfg.TRAIN.SPLIT, + batch_size=int(cfg.TRAIN.BATCH_SIZE / cfg.NUM_GPUS), + shuffle=True, + drop_last=True, + ) + + +def construct_test_loader(): + """Test loader wrapper.""" + return _construct_loader( + dataset_name=cfg.TEST.DATASET, + split=cfg.TEST.SPLIT, + batch_size=int(cfg.TEST.BATCH_SIZE / cfg.NUM_GPUS), + shuffle=False, + drop_last=False, + ) + + +def shuffle(loader, cur_epoch): + """"Shuffles the data.""" + err_str = "Sampler type '{}' not supported".format(type(loader.sampler)) + assert isinstance(loader.sampler, (RandomSampler, DistributedSampler)), err_str + # RandomSampler handles shuffling automatically + if isinstance(loader.sampler, DistributedSampler): + # DistributedSampler shuffles data based on epoch + loader.sampler.set_epoch(cur_epoch) diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/transforms.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/transforms.py index 4af2bcddb7..cd63be489a 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/transforms.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/datasets/transforms.py @@ -1,94 +1,94 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -"""Image transformations on HWC float images with RGB channel order.""" - -from math import ceil, sqrt - -import cv2 -import numpy as np -from PIL import Image -from pycls.datasets.augment import make_augment - - -def scale_and_center_crop(im, scale_size, crop_size): - """Performs scaling and center cropping (used for testing).""" - h, w = im.shape[:2] - if w < h and w != scale_size: - w, h = scale_size, int(h / w * scale_size) - im = cv2.resize(im, (w, h), interpolation=cv2.INTER_LINEAR) - elif h <= w and h != scale_size: - w, h = int(w / h * scale_size), scale_size - im = cv2.resize(im, (w, h), interpolation=cv2.INTER_LINEAR) - x = ceil((w - crop_size) / 2) - y = ceil((h - crop_size) / 2) - return im[y : (y + crop_size), x : (x + crop_size), :] - - -def random_sized_crop(im, size, area_frac=0.08, max_iter=10): - """Performs Inception-style cropping (used for training).""" - h, w = im.shape[:2] - area = h * w - for _ in range(max_iter): - target_area = np.random.uniform(area_frac, 1.0) * area - aspect_ratio = np.random.uniform(3.0 / 4.0, 4.0 / 3.0) - w_crop = round(sqrt(target_area * aspect_ratio)) - h_crop = round(sqrt(target_area / aspect_ratio)) - if np.random.uniform() < 0.5: - w_crop, h_crop = h_crop, w_crop - if h_crop <= h and w_crop <= w: - y = 0 if h_crop == h else np.random.randint(0, h - h_crop) - x = 0 if w_crop == w else np.random.randint(0, w - w_crop) - im = im[y : (y + h_crop), x : (x + w_crop), :] - return cv2.resize(im, (size, size), interpolation=cv2.INTER_LINEAR) - return scale_and_center_crop(im, size, size) - - -def horizontal_flip(im, prob=0.5): - """Performs horizontal flip (used for training).""" - return im[:, ::-1, :] if np.random.uniform() < prob else im - - -def augment(im, augment_str): - """Augments image (used for training).""" - if augment_str: - im = Image.fromarray((im * 255).astype(np.uint8)) - im = make_augment(augment_str)(im) - im = np.asarray(im).astype(np.float32) / 255 - return im - - -def lighting(im, alpha_std, eig_val, eig_vec): - """Performs AlexNet-style PCA jitter (used for training).""" - alpha = np.random.normal(0, alpha_std, size=(1, 3)) - alpha = np.repeat(alpha, 3, axis=0) - eig_val = np.repeat(np.array(eig_val), 3, axis=0) - rgb = np.sum(np.array(eig_vec) * alpha * eig_val, axis=1) - for i in range(3): - im[:, :, i] = im[:, :, i] + rgb[i] - return im - - -def color_norm(im, mean, std): - """Performs per-channel normalization (used for training and testing).""" - for i in range(3): - im[:, :, i] = (im[:, :, i] - mean[i]) / std[i] - return im +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +"""Image transformations on HWC float images with RGB channel order.""" + +from math import ceil, sqrt + +import cv2 +import numpy as np +from PIL import Image +from pycls.datasets.augment import make_augment + + +def scale_and_center_crop(im, scale_size, crop_size): + """Performs scaling and center cropping (used for testing).""" + h, w = im.shape[:2] + if w < h and w != scale_size: + w, h = scale_size, int(h / w * scale_size) + im = cv2.resize(im, (w, h), interpolation=cv2.INTER_LINEAR) + elif h <= w and h != scale_size: + w, h = int(w / h * scale_size), scale_size + im = cv2.resize(im, (w, h), interpolation=cv2.INTER_LINEAR) + x = ceil((w - crop_size) / 2) + y = ceil((h - crop_size) / 2) + return im[y : (y + crop_size), x : (x + crop_size), :] + + +def random_sized_crop(im, size, area_frac=0.08, max_iter=10): + """Performs Inception-style cropping (used for training).""" + h, w = im.shape[:2] + area = h * w + for _ in range(max_iter): + target_area = np.random.uniform(area_frac, 1.0) * area + aspect_ratio = np.random.uniform(3.0 / 4.0, 4.0 / 3.0) + w_crop = round(sqrt(target_area * aspect_ratio)) + h_crop = round(sqrt(target_area / aspect_ratio)) + if np.random.uniform() < 0.5: + w_crop, h_crop = h_crop, w_crop + if h_crop <= h and w_crop <= w: + y = 0 if h_crop == h else np.random.randint(0, h - h_crop) + x = 0 if w_crop == w else np.random.randint(0, w - w_crop) + im = im[y : (y + h_crop), x : (x + w_crop), :] + return cv2.resize(im, (size, size), interpolation=cv2.INTER_LINEAR) + return scale_and_center_crop(im, size, size) + + +def horizontal_flip(im, prob=0.5): + """Performs horizontal flip (used for training).""" + return im[:, ::-1, :] if np.random.uniform() < prob else im + + +def augment(im, augment_str): + """Augments image (used for training).""" + if augment_str: + im = Image.fromarray((im * 255).astype(np.uint8)) + im = make_augment(augment_str)(im) + im = np.asarray(im).astype(np.float32) / 255 + return im + + +def lighting(im, alpha_std, eig_val, eig_vec): + """Performs AlexNet-style PCA jitter (used for training).""" + alpha = np.random.normal(0, alpha_std, size=(1, 3)) + alpha = np.repeat(alpha, 3, axis=0) + eig_val = np.repeat(np.array(eig_val), 3, axis=0) + rgb = np.sum(np.array(eig_vec) * alpha * eig_val, axis=1) + for i in range(3): + im[:, :, i] = im[:, :, i] + rgb[i] + return im + + +def color_norm(im, mean, std): + """Performs per-channel normalization (used for training and testing).""" + for i in range(3): + im[:, :, i] = (im[:, :, i] - mean[i]) / std[i] + return im diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/__init__.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/__init__.py index 1f38943d17..9995f91fe8 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/__init__.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/__init__.py @@ -1,10 +1,10 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -"""Expose model zoo constructors.""" - -from pycls.models.model_zoo import effnet, regnetx, regnety, resnet, resnext +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +"""Expose model zoo constructors.""" + +from pycls.models.model_zoo import effnet, regnetx, regnety, resnet, resnext diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/anynet.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/anynet.py index 3b34dc2c31..f25ef7fe22 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/anynet.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/anynet.py @@ -1,375 +1,375 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -"""AnyNet models.""" - -from pycls.core.config import cfg -from pycls.models.blocks import ( - SE, - activation, - conv2d, - conv2d_cx, - gap2d, - gap2d_cx, - init_weights, - linear, - linear_cx, - norm2d, - norm2d_cx, - pool2d, - pool2d_cx, -) -from torch.nn import Module - - -def get_stem_fun(stem_type): - """Retrieves the stem function by name.""" - stem_funs = { - "res_stem_cifar": ResStemCifar, - "res_stem_in": ResStem, - "simple_stem_in": SimpleStem, - } - err_str = "Stem type '{}' not supported" - assert stem_type in stem_funs.keys(), err_str.format(stem_type) - return stem_funs[stem_type] - - -def get_block_fun(block_type): - """Retrieves the block function by name.""" - block_funs = { - "vanilla_block": VanillaBlock, - "res_basic_block": ResBasicBlock, - "res_bottleneck_block": ResBottleneckBlock, - } - err_str = "Block type '{}' not supported" - assert block_type in block_funs.keys(), err_str.format(block_type) - return block_funs[block_type] - - -class AnyHead(Module): - """AnyNet head: AvgPool, 1x1.""" - - def __init__(self, w_in, num_classes): - super(AnyHead, self).__init__() - self.avg_pool = gap2d(w_in) - self.fc = linear(w_in, num_classes, bias=True) - - def forward(self, x): - x = self.avg_pool(x) - x = x.view(x.size(0), -1) - x = self.fc(x) - return x - - @staticmethod - def complexity(cx, w_in, num_classes): - cx = gap2d_cx(cx, w_in) - cx = linear_cx(cx, w_in, num_classes, bias=True) - return cx - - -class VanillaBlock(Module): - """Vanilla block: [3x3 conv, BN, Relu] x2.""" - - def __init__(self, w_in, w_out, stride, _params): - super(VanillaBlock, self).__init__() - self.a = conv2d(w_in, w_out, 3, stride=stride) - self.a_bn = norm2d(w_out) - self.a_af = activation() - self.b = conv2d(w_out, w_out, 3) - self.b_bn = norm2d(w_out) - self.b_af = activation() - - def forward(self, x): - for layer in self.children(): - x = layer(x) - return x - - @staticmethod - def complexity(cx, w_in, w_out, stride, _params): - cx = conv2d_cx(cx, w_in, w_out, 3, stride=stride) - cx = norm2d_cx(cx, w_out) - cx = conv2d_cx(cx, w_out, w_out, 3) - cx = norm2d_cx(cx, w_out) - return cx - - -class BasicTransform(Module): - """Basic transformation: [3x3 conv, BN, Relu] x2.""" - - def __init__(self, w_in, w_out, stride, _params): - super(BasicTransform, self).__init__() - self.a = conv2d(w_in, w_out, 3, stride=stride) - self.a_bn = norm2d(w_out) - self.a_af = activation() - self.b = conv2d(w_out, w_out, 3) - self.b_bn = norm2d(w_out) - self.b_bn.final_bn = True - - def forward(self, x): - for layer in self.children(): - x = layer(x) - return x - - @staticmethod - def complexity(cx, w_in, w_out, stride, _params): - cx = conv2d_cx(cx, w_in, w_out, 3, stride=stride) - cx = norm2d_cx(cx, w_out) - cx = conv2d_cx(cx, w_out, w_out, 3) - cx = norm2d_cx(cx, w_out) - return cx - - -class ResBasicBlock(Module): - """Residual basic block: x + f(x), f = basic transform.""" - - def __init__(self, w_in, w_out, stride, params): - super(ResBasicBlock, self).__init__() - self.proj, self.bn = None, None - if (w_in != w_out) or (stride != 1): - self.proj = conv2d(w_in, w_out, 1, stride=stride) - self.bn = norm2d(w_out) - self.f = BasicTransform(w_in, w_out, stride, params) - self.af = activation() - - def forward(self, x): - x_p = self.bn(self.proj(x)) if self.proj else x - return self.af(x_p + self.f(x)) - - @staticmethod - def complexity(cx, w_in, w_out, stride, params): - if (w_in != w_out) or (stride != 1): - h, w = cx["h"], cx["w"] - cx = conv2d_cx(cx, w_in, w_out, 1, stride=stride) - cx = norm2d_cx(cx, w_out) - cx["h"], cx["w"] = h, w - cx = BasicTransform.complexity(cx, w_in, w_out, stride, params) - return cx - - -class BottleneckTransform(Module): - """Bottleneck transformation: 1x1, 3x3 [+SE], 1x1.""" - - def __init__(self, w_in, w_out, stride, params): - super(BottleneckTransform, self).__init__() - w_b = int(round(w_out * params["bot_mul"])) - w_se = int(round(w_in * params["se_r"])) - groups = w_b // params["group_w"] - self.a = conv2d(w_in, w_b, 1) - self.a_bn = norm2d(w_b) - self.a_af = activation() - self.b = conv2d(w_b, w_b, 3, stride=stride, groups=groups) - self.b_bn = norm2d(w_b) - self.b_af = activation() - self.se = SE(w_b, w_se) if w_se else None - self.c = conv2d(w_b, w_out, 1) - self.c_bn = norm2d(w_out) - self.c_bn.final_bn = True - - def forward(self, x): - for layer in self.children(): - x = layer(x) - return x - - @staticmethod - def complexity(cx, w_in, w_out, stride, params): - w_b = int(round(w_out * params["bot_mul"])) - w_se = int(round(w_in * params["se_r"])) - groups = w_b // params["group_w"] - cx = conv2d_cx(cx, w_in, w_b, 1) - cx = norm2d_cx(cx, w_b) - cx = conv2d_cx(cx, w_b, w_b, 3, stride=stride, groups=groups) - cx = norm2d_cx(cx, w_b) - cx = SE.complexity(cx, w_b, w_se) if w_se else cx - cx = conv2d_cx(cx, w_b, w_out, 1) - cx = norm2d_cx(cx, w_out) - return cx - - -class ResBottleneckBlock(Module): - """Residual bottleneck block: x + f(x), f = bottleneck transform.""" - - def __init__(self, w_in, w_out, stride, params): - super(ResBottleneckBlock, self).__init__() - self.proj, self.bn = None, None - if (w_in != w_out) or (stride != 1): - self.proj = conv2d(w_in, w_out, 1, stride=stride) - self.bn = norm2d(w_out) - self.f = BottleneckTransform(w_in, w_out, stride, params) - self.af = activation() - - def forward(self, x): - x_p = self.bn(self.proj(x)) if self.proj else x - return self.af(x_p + self.f(x)) - - @staticmethod - def complexity(cx, w_in, w_out, stride, params): - if (w_in != w_out) or (stride != 1): - h, w = cx["h"], cx["w"] - cx = conv2d_cx(cx, w_in, w_out, 1, stride=stride) - cx = norm2d_cx(cx, w_out) - cx["h"], cx["w"] = h, w - cx = BottleneckTransform.complexity(cx, w_in, w_out, stride, params) - return cx - - -class ResStemCifar(Module): - """ResNet stem for CIFAR: 3x3, BN, AF.""" - - def __init__(self, w_in, w_out): - super(ResStemCifar, self).__init__() - self.conv = conv2d(w_in, w_out, 3) - self.bn = norm2d(w_out) - self.af = activation() - - def forward(self, x): - for layer in self.children(): - x = layer(x) - return x - - @staticmethod - def complexity(cx, w_in, w_out): - cx = conv2d_cx(cx, w_in, w_out, 3) - cx = norm2d_cx(cx, w_out) - return cx - - -class ResStem(Module): - """ResNet stem for ImageNet: 7x7, BN, AF, MaxPool.""" - - def __init__(self, w_in, w_out): - super(ResStem, self).__init__() - self.conv = conv2d(w_in, w_out, 7, stride=2) - self.bn = norm2d(w_out) - self.af = activation() - self.pool = pool2d(w_out, 3, stride=2) - - def forward(self, x): - for layer in self.children(): - x = layer(x) - return x - - @staticmethod - def complexity(cx, w_in, w_out): - cx = conv2d_cx(cx, w_in, w_out, 7, stride=2) - cx = norm2d_cx(cx, w_out) - cx = pool2d_cx(cx, w_out, 3, stride=2) - return cx - - -class SimpleStem(Module): - """Simple stem for ImageNet: 3x3, BN, AF.""" - - def __init__(self, w_in, w_out): - super(SimpleStem, self).__init__() - self.conv = conv2d(w_in, w_out, 3, stride=2) - self.bn = norm2d(w_out) - self.af = activation() - - def forward(self, x): - for layer in self.children(): - x = layer(x) - return x - - @staticmethod - def complexity(cx, w_in, w_out): - cx = conv2d_cx(cx, w_in, w_out, 3, stride=2) - cx = norm2d_cx(cx, w_out) - return cx - - -class AnyStage(Module): - """AnyNet stage (sequence of blocks w/ the same output shape).""" - - def __init__(self, w_in, w_out, stride, d, block_fun, params): - super(AnyStage, self).__init__() - for i in range(d): - block = block_fun(w_in, w_out, stride, params) - self.add_module("b{}".format(i + 1), block) - stride, w_in = 1, w_out - - def forward(self, x): - for block in self.children(): - x = block(x) - return x - - @staticmethod - def complexity(cx, w_in, w_out, stride, d, block_fun, params): - for _ in range(d): - cx = block_fun.complexity(cx, w_in, w_out, stride, params) - stride, w_in = 1, w_out - return cx - - -class AnyNet(Module): - """AnyNet model.""" - - @staticmethod - def get_params(): - nones = [None for _ in cfg.ANYNET.DEPTHS] - return { - "stem_type": cfg.ANYNET.STEM_TYPE, - "stem_w": cfg.ANYNET.STEM_W, - "block_type": cfg.ANYNET.BLOCK_TYPE, - "depths": cfg.ANYNET.DEPTHS, - "widths": cfg.ANYNET.WIDTHS, - "strides": cfg.ANYNET.STRIDES, - "bot_muls": cfg.ANYNET.BOT_MULS if cfg.ANYNET.BOT_MULS else nones, - "group_ws": cfg.ANYNET.GROUP_WS if cfg.ANYNET.GROUP_WS else nones, - "se_r": cfg.ANYNET.SE_R if cfg.ANYNET.SE_ON else 0, - "num_classes": cfg.MODEL.NUM_CLASSES, - } - - def __init__(self, params=None): - super(AnyNet, self).__init__() - p = AnyNet.get_params() if not params else params - stem_fun = get_stem_fun(p["stem_type"]) - block_fun = get_block_fun(p["block_type"]) - self.stem = stem_fun(3, p["stem_w"]) - prev_w = p["stem_w"] - keys = ["depths", "widths", "strides", "bot_muls", "group_ws"] - for i, (d, w, s, b, g) in enumerate(zip(*[p[k] for k in keys])): - params = {"bot_mul": b, "group_w": g, "se_r": p["se_r"]} - stage = AnyStage(prev_w, w, s, d, block_fun, params) - self.add_module("s{}".format(i + 1), stage) - prev_w = w - self.head = AnyHead(prev_w, p["num_classes"]) - self.apply(init_weights) - - def forward(self, x): - for module in self.children(): - x = module(x) - return x - - @staticmethod - def complexity(cx, params=None): - """Computes model complexity (if you alter the model, make sure to update).""" - p = AnyNet.get_params() if not params else params - stem_fun = get_stem_fun(p["stem_type"]) - block_fun = get_block_fun(p["block_type"]) - cx = stem_fun.complexity(cx, 3, p["stem_w"]) - prev_w = p["stem_w"] - keys = ["depths", "widths", "strides", "bot_muls", "group_ws"] - for d, w, s, b, g in zip(*[p[k] for k in keys]): - params = {"bot_mul": b, "group_w": g, "se_r": p["se_r"]} - cx = AnyStage.complexity(cx, prev_w, w, s, d, block_fun, params) - prev_w = w - cx = AnyHead.complexity(cx, prev_w, p["num_classes"]) - return cx +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +"""AnyNet models.""" + +from pycls.core.config import cfg +from pycls.models.blocks import ( + SE, + activation, + conv2d, + conv2d_cx, + gap2d, + gap2d_cx, + init_weights, + linear, + linear_cx, + norm2d, + norm2d_cx, + pool2d, + pool2d_cx, +) +from torch.nn import Module + + +def get_stem_fun(stem_type): + """Retrieves the stem function by name.""" + stem_funs = { + "res_stem_cifar": ResStemCifar, + "res_stem_in": ResStem, + "simple_stem_in": SimpleStem, + } + err_str = "Stem type '{}' not supported" + assert stem_type in stem_funs.keys(), err_str.format(stem_type) + return stem_funs[stem_type] + + +def get_block_fun(block_type): + """Retrieves the block function by name.""" + block_funs = { + "vanilla_block": VanillaBlock, + "res_basic_block": ResBasicBlock, + "res_bottleneck_block": ResBottleneckBlock, + } + err_str = "Block type '{}' not supported" + assert block_type in block_funs.keys(), err_str.format(block_type) + return block_funs[block_type] + + +class AnyHead(Module): + """AnyNet head: AvgPool, 1x1.""" + + def __init__(self, w_in, num_classes): + super(AnyHead, self).__init__() + self.avg_pool = gap2d(w_in) + self.fc = linear(w_in, num_classes, bias=True) + + def forward(self, x): + x = self.avg_pool(x) + x = x.view(x.size(0), -1) + x = self.fc(x) + return x + + @staticmethod + def complexity(cx, w_in, num_classes): + cx = gap2d_cx(cx, w_in) + cx = linear_cx(cx, w_in, num_classes, bias=True) + return cx + + +class VanillaBlock(Module): + """Vanilla block: [3x3 conv, BN, Relu] x2.""" + + def __init__(self, w_in, w_out, stride, _params): + super(VanillaBlock, self).__init__() + self.a = conv2d(w_in, w_out, 3, stride=stride) + self.a_bn = norm2d(w_out) + self.a_af = activation() + self.b = conv2d(w_out, w_out, 3) + self.b_bn = norm2d(w_out) + self.b_af = activation() + + def forward(self, x): + for layer in self.children(): + x = layer(x) + return x + + @staticmethod + def complexity(cx, w_in, w_out, stride, _params): + cx = conv2d_cx(cx, w_in, w_out, 3, stride=stride) + cx = norm2d_cx(cx, w_out) + cx = conv2d_cx(cx, w_out, w_out, 3) + cx = norm2d_cx(cx, w_out) + return cx + + +class BasicTransform(Module): + """Basic transformation: [3x3 conv, BN, Relu] x2.""" + + def __init__(self, w_in, w_out, stride, _params): + super(BasicTransform, self).__init__() + self.a = conv2d(w_in, w_out, 3, stride=stride) + self.a_bn = norm2d(w_out) + self.a_af = activation() + self.b = conv2d(w_out, w_out, 3) + self.b_bn = norm2d(w_out) + self.b_bn.final_bn = True + + def forward(self, x): + for layer in self.children(): + x = layer(x) + return x + + @staticmethod + def complexity(cx, w_in, w_out, stride, _params): + cx = conv2d_cx(cx, w_in, w_out, 3, stride=stride) + cx = norm2d_cx(cx, w_out) + cx = conv2d_cx(cx, w_out, w_out, 3) + cx = norm2d_cx(cx, w_out) + return cx + + +class ResBasicBlock(Module): + """Residual basic block: x + f(x), f = basic transform.""" + + def __init__(self, w_in, w_out, stride, params): + super(ResBasicBlock, self).__init__() + self.proj, self.bn = None, None + if (w_in != w_out) or (stride != 1): + self.proj = conv2d(w_in, w_out, 1, stride=stride) + self.bn = norm2d(w_out) + self.f = BasicTransform(w_in, w_out, stride, params) + self.af = activation() + + def forward(self, x): + x_p = self.bn(self.proj(x)) if self.proj else x + return self.af(x_p + self.f(x)) + + @staticmethod + def complexity(cx, w_in, w_out, stride, params): + if (w_in != w_out) or (stride != 1): + h, w = cx["h"], cx["w"] + cx = conv2d_cx(cx, w_in, w_out, 1, stride=stride) + cx = norm2d_cx(cx, w_out) + cx["h"], cx["w"] = h, w + cx = BasicTransform.complexity(cx, w_in, w_out, stride, params) + return cx + + +class BottleneckTransform(Module): + """Bottleneck transformation: 1x1, 3x3 [+SE], 1x1.""" + + def __init__(self, w_in, w_out, stride, params): + super(BottleneckTransform, self).__init__() + w_b = int(round(w_out * params["bot_mul"])) + w_se = int(round(w_in * params["se_r"])) + groups = w_b // params["group_w"] + self.a = conv2d(w_in, w_b, 1) + self.a_bn = norm2d(w_b) + self.a_af = activation() + self.b = conv2d(w_b, w_b, 3, stride=stride, groups=groups) + self.b_bn = norm2d(w_b) + self.b_af = activation() + self.se = SE(w_b, w_se) if w_se else None + self.c = conv2d(w_b, w_out, 1) + self.c_bn = norm2d(w_out) + self.c_bn.final_bn = True + + def forward(self, x): + for layer in self.children(): + x = layer(x) + return x + + @staticmethod + def complexity(cx, w_in, w_out, stride, params): + w_b = int(round(w_out * params["bot_mul"])) + w_se = int(round(w_in * params["se_r"])) + groups = w_b // params["group_w"] + cx = conv2d_cx(cx, w_in, w_b, 1) + cx = norm2d_cx(cx, w_b) + cx = conv2d_cx(cx, w_b, w_b, 3, stride=stride, groups=groups) + cx = norm2d_cx(cx, w_b) + cx = SE.complexity(cx, w_b, w_se) if w_se else cx + cx = conv2d_cx(cx, w_b, w_out, 1) + cx = norm2d_cx(cx, w_out) + return cx + + +class ResBottleneckBlock(Module): + """Residual bottleneck block: x + f(x), f = bottleneck transform.""" + + def __init__(self, w_in, w_out, stride, params): + super(ResBottleneckBlock, self).__init__() + self.proj, self.bn = None, None + if (w_in != w_out) or (stride != 1): + self.proj = conv2d(w_in, w_out, 1, stride=stride) + self.bn = norm2d(w_out) + self.f = BottleneckTransform(w_in, w_out, stride, params) + self.af = activation() + + def forward(self, x): + x_p = self.bn(self.proj(x)) if self.proj else x + return self.af(x_p + self.f(x)) + + @staticmethod + def complexity(cx, w_in, w_out, stride, params): + if (w_in != w_out) or (stride != 1): + h, w = cx["h"], cx["w"] + cx = conv2d_cx(cx, w_in, w_out, 1, stride=stride) + cx = norm2d_cx(cx, w_out) + cx["h"], cx["w"] = h, w + cx = BottleneckTransform.complexity(cx, w_in, w_out, stride, params) + return cx + + +class ResStemCifar(Module): + """ResNet stem for CIFAR: 3x3, BN, AF.""" + + def __init__(self, w_in, w_out): + super(ResStemCifar, self).__init__() + self.conv = conv2d(w_in, w_out, 3) + self.bn = norm2d(w_out) + self.af = activation() + + def forward(self, x): + for layer in self.children(): + x = layer(x) + return x + + @staticmethod + def complexity(cx, w_in, w_out): + cx = conv2d_cx(cx, w_in, w_out, 3) + cx = norm2d_cx(cx, w_out) + return cx + + +class ResStem(Module): + """ResNet stem for ImageNet: 7x7, BN, AF, MaxPool.""" + + def __init__(self, w_in, w_out): + super(ResStem, self).__init__() + self.conv = conv2d(w_in, w_out, 7, stride=2) + self.bn = norm2d(w_out) + self.af = activation() + self.pool = pool2d(w_out, 3, stride=2) + + def forward(self, x): + for layer in self.children(): + x = layer(x) + return x + + @staticmethod + def complexity(cx, w_in, w_out): + cx = conv2d_cx(cx, w_in, w_out, 7, stride=2) + cx = norm2d_cx(cx, w_out) + cx = pool2d_cx(cx, w_out, 3, stride=2) + return cx + + +class SimpleStem(Module): + """Simple stem for ImageNet: 3x3, BN, AF.""" + + def __init__(self, w_in, w_out): + super(SimpleStem, self).__init__() + self.conv = conv2d(w_in, w_out, 3, stride=2) + self.bn = norm2d(w_out) + self.af = activation() + + def forward(self, x): + for layer in self.children(): + x = layer(x) + return x + + @staticmethod + def complexity(cx, w_in, w_out): + cx = conv2d_cx(cx, w_in, w_out, 3, stride=2) + cx = norm2d_cx(cx, w_out) + return cx + + +class AnyStage(Module): + """AnyNet stage (sequence of blocks w/ the same output shape).""" + + def __init__(self, w_in, w_out, stride, d, block_fun, params): + super(AnyStage, self).__init__() + for i in range(d): + block = block_fun(w_in, w_out, stride, params) + self.add_module("b{}".format(i + 1), block) + stride, w_in = 1, w_out + + def forward(self, x): + for block in self.children(): + x = block(x) + return x + + @staticmethod + def complexity(cx, w_in, w_out, stride, d, block_fun, params): + for _ in range(d): + cx = block_fun.complexity(cx, w_in, w_out, stride, params) + stride, w_in = 1, w_out + return cx + + +class AnyNet(Module): + """AnyNet model.""" + + @staticmethod + def get_params(): + nones = [None for _ in cfg.ANYNET.DEPTHS] + return { + "stem_type": cfg.ANYNET.STEM_TYPE, + "stem_w": cfg.ANYNET.STEM_W, + "block_type": cfg.ANYNET.BLOCK_TYPE, + "depths": cfg.ANYNET.DEPTHS, + "widths": cfg.ANYNET.WIDTHS, + "strides": cfg.ANYNET.STRIDES, + "bot_muls": cfg.ANYNET.BOT_MULS if cfg.ANYNET.BOT_MULS else nones, + "group_ws": cfg.ANYNET.GROUP_WS if cfg.ANYNET.GROUP_WS else nones, + "se_r": cfg.ANYNET.SE_R if cfg.ANYNET.SE_ON else 0, + "num_classes": cfg.MODEL.NUM_CLASSES, + } + + def __init__(self, params=None): + super(AnyNet, self).__init__() + p = AnyNet.get_params() if not params else params + stem_fun = get_stem_fun(p["stem_type"]) + block_fun = get_block_fun(p["block_type"]) + self.stem = stem_fun(3, p["stem_w"]) + prev_w = p["stem_w"] + keys = ["depths", "widths", "strides", "bot_muls", "group_ws"] + for i, (d, w, s, b, g) in enumerate(zip(*[p[k] for k in keys])): + params = {"bot_mul": b, "group_w": g, "se_r": p["se_r"]} + stage = AnyStage(prev_w, w, s, d, block_fun, params) + self.add_module("s{}".format(i + 1), stage) + prev_w = w + self.head = AnyHead(prev_w, p["num_classes"]) + self.apply(init_weights) + + def forward(self, x): + for module in self.children(): + x = module(x) + return x + + @staticmethod + def complexity(cx, params=None): + """Computes model complexity (if you alter the model, make sure to update).""" + p = AnyNet.get_params() if not params else params + stem_fun = get_stem_fun(p["stem_type"]) + block_fun = get_block_fun(p["block_type"]) + cx = stem_fun.complexity(cx, 3, p["stem_w"]) + prev_w = p["stem_w"] + keys = ["depths", "widths", "strides", "bot_muls", "group_ws"] + for d, w, s, b, g in zip(*[p[k] for k in keys]): + params = {"bot_mul": b, "group_w": g, "se_r": p["se_r"]} + cx = AnyStage.complexity(cx, prev_w, w, s, d, block_fun, params) + prev_w = w + cx = AnyHead.complexity(cx, prev_w, p["num_classes"]) + return cx diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/blocks.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/blocks.py index 6c7773d188..eb14c7d707 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/blocks.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/blocks.py @@ -1,201 +1,201 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -"""Common model blocks.""" - -import numpy as np -import torch -import torch.nn as nn -from pycls.core.config import cfg -from torch.nn import Module - - -# ----------------------- Shortcuts for common torch.nn layers ----------------------- # - - -def conv2d(w_in, w_out, k, *, stride=1, groups=1, bias=False): - """Helper for building a conv2d layer.""" - assert k % 2 == 1, "Only odd size kernels supported to avoid padding issues." - s, p, g, b = stride, (k - 1) // 2, groups, bias - return nn.Conv2d(w_in, w_out, k, stride=s, padding=p, groups=g, bias=b) - - -def norm2d(w_in): - """Helper for building a norm2d layer.""" - return nn.BatchNorm2d(num_features=w_in, eps=cfg.BN.EPS, momentum=cfg.BN.MOM) - - -def pool2d(_w_in, k, *, stride=1): - """Helper for building a pool2d layer.""" - assert k % 2 == 1, "Only odd size kernels supported to avoid padding issues." - return nn.MaxPool2d(k, stride=stride, padding=(k - 1) // 2) - - -def gap2d(_w_in): - """Helper for building a gap2d layer.""" - return nn.AdaptiveAvgPool2d((1, 1)) - - -def linear(w_in, w_out, *, bias=False): - """Helper for building a linear layer.""" - return nn.Linear(w_in, w_out, bias=bias) - - -def activation(): - """Helper for building an activation layer.""" - activation_fun = cfg.MODEL.ACTIVATION_FUN.lower() - if activation_fun == "relu": - return nn.ReLU(inplace=cfg.MODEL.ACTIVATION_INPLACE) - elif activation_fun == "silu" or activation_fun == "swish": - try: - return torch.nn.SiLU() - except AttributeError: - return SiLU() - else: - raise AssertionError("Unknown MODEL.ACTIVATION_FUN: " + activation_fun) - - -# --------------------------- Complexity (cx) calculations --------------------------- # - - -def conv2d_cx(cx, w_in, w_out, k, *, stride=1, groups=1, bias=False): - """Accumulates complexity of conv2d into cx = (h, w, flops, params, acts).""" - assert k % 2 == 1, "Only odd size kernels supported to avoid padding issues." - h, w, flops, params, acts = cx["h"], cx["w"], cx["flops"], cx["params"], cx["acts"] - h, w = (h - 1) // stride + 1, (w - 1) // stride + 1 - flops += k * k * w_in * w_out * h * w // groups + (w_out if bias else 0) - params += k * k * w_in * w_out // groups + (w_out if bias else 0) - acts += w_out * h * w - return {"h": h, "w": w, "flops": flops, "params": params, "acts": acts} - - -def norm2d_cx(cx, w_in): - """Accumulates complexity of norm2d into cx = (h, w, flops, params, acts).""" - h, w, flops, params, acts = cx["h"], cx["w"], cx["flops"], cx["params"], cx["acts"] - params += 2 * w_in - return {"h": h, "w": w, "flops": flops, "params": params, "acts": acts} - - -def pool2d_cx(cx, w_in, k, *, stride=1): - """Accumulates complexity of pool2d into cx = (h, w, flops, params, acts).""" - assert k % 2 == 1, "Only odd size kernels supported to avoid padding issues." - h, w, flops, params, acts = cx["h"], cx["w"], cx["flops"], cx["params"], cx["acts"] - h, w = (h - 1) // stride + 1, (w - 1) // stride + 1 - acts += w_in * h * w - return {"h": h, "w": w, "flops": flops, "params": params, "acts": acts} - - -def gap2d_cx(cx, _w_in): - """Accumulates complexity of gap2d into cx = (h, w, flops, params, acts).""" - flops, params, acts = cx["flops"], cx["params"], cx["acts"] - return {"h": 1, "w": 1, "flops": flops, "params": params, "acts": acts} - - -def linear_cx(cx, w_in, w_out, *, bias=False): - """Accumulates complexity of linear into cx = (h, w, flops, params, acts).""" - h, w, flops, params, acts = cx["h"], cx["w"], cx["flops"], cx["params"], cx["acts"] - flops += w_in * w_out + (w_out if bias else 0) - params += w_in * w_out + (w_out if bias else 0) - acts += w_out - return {"h": h, "w": w, "flops": flops, "params": params, "acts": acts} - - -# ---------------------------------- Shared blocks ----------------------------------- # - - -class SiLU(Module): - """SiLU activation function (also known as Swish): x * sigmoid(x).""" - - # Note: will be part of Pytorch 1.7, at which point can remove this. - - def __init__(self): - super(SiLU, self).__init__() - - def forward(self, x): - return x * torch.sigmoid(x) - - -class SE(Module): - """Squeeze-and-Excitation (SE) block: AvgPool, FC, Act, FC, Sigmoid.""" - - def __init__(self, w_in, w_se): - super(SE, self).__init__() - self.avg_pool = gap2d(w_in) - self.f_ex = nn.Sequential( - conv2d(w_in, w_se, 1, bias=True), - activation(), - conv2d(w_se, w_in, 1, bias=True), - nn.Sigmoid(), - ) - - def forward(self, x): - return x * self.f_ex(self.avg_pool(x)) - - @staticmethod - def complexity(cx, w_in, w_se): - h, w = cx["h"], cx["w"] - cx = gap2d_cx(cx, w_in) - cx = conv2d_cx(cx, w_in, w_se, 1, bias=True) - cx = conv2d_cx(cx, w_se, w_in, 1, bias=True) - cx["h"], cx["w"] = h, w - return cx - - -# ---------------------------------- Miscellaneous ----------------------------------- # - - -def adjust_block_compatibility(ws, bs, gs): - """Adjusts the compatibility of widths, bottlenecks, and groups.""" - assert len(ws) == len(bs) == len(gs) - assert all(w > 0 and b > 0 and g > 0 for w, b, g in zip(ws, bs, gs)) - vs = [int(max(1, w * b)) for w, b in zip(ws, bs)] - gs = [int(min(g, v)) for g, v in zip(gs, vs)] - ms = [np.lcm(g, b) if b > 1 else g for g, b in zip(gs, bs)] - vs = [max(m, int(round(v / m) * m)) for v, m in zip(vs, ms)] - ws = [int(v / b) for v, b in zip(vs, bs)] - assert all(w * b % g == 0 for w, b, g in zip(ws, bs, gs)) - return ws, bs, gs - - -def init_weights(m): - """Performs ResNet-style weight initialization.""" - if isinstance(m, nn.Conv2d): - # Note that there is no bias due to BN - fan_out = m.kernel_size[0] * m.kernel_size[1] * m.out_channels - m.weight.data.normal_(mean=0.0, std=np.sqrt(2.0 / fan_out)) - elif isinstance(m, nn.BatchNorm2d): - zero_init_gamma = cfg.BN.ZERO_INIT_FINAL_GAMMA - zero_init_gamma = hasattr(m, "final_bn") and m.final_bn and zero_init_gamma - m.weight.data.fill_(0.0 if zero_init_gamma else 1.0) - m.bias.data.zero_() - elif isinstance(m, nn.Linear): - m.weight.data.normal_(mean=0.0, std=0.01) - m.bias.data.zero_() - - -def drop_connect(x, drop_ratio): - """Drop connect (adapted from DARTS).""" - keep_ratio = 1.0 - drop_ratio - mask = torch.empty([x.shape[0], 1, 1, 1], dtype=x.dtype, device=x.device) - mask.bernoulli_(keep_ratio) - x.div_(keep_ratio) - x.mul_(mask) - return x +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +"""Common model blocks.""" + +import numpy as np +import torch +import torch.nn as nn +from pycls.core.config import cfg +from torch.nn import Module + + +# ----------------------- Shortcuts for common torch.nn layers ----------------------- # + + +def conv2d(w_in, w_out, k, *, stride=1, groups=1, bias=False): + """Helper for building a conv2d layer.""" + assert k % 2 == 1, "Only odd size kernels supported to avoid padding issues." + s, p, g, b = stride, (k - 1) // 2, groups, bias + return nn.Conv2d(w_in, w_out, k, stride=s, padding=p, groups=g, bias=b) + + +def norm2d(w_in): + """Helper for building a norm2d layer.""" + return nn.BatchNorm2d(num_features=w_in, eps=cfg.BN.EPS, momentum=cfg.BN.MOM) + + +def pool2d(_w_in, k, *, stride=1): + """Helper for building a pool2d layer.""" + assert k % 2 == 1, "Only odd size kernels supported to avoid padding issues." + return nn.MaxPool2d(k, stride=stride, padding=(k - 1) // 2) + + +def gap2d(_w_in): + """Helper for building a gap2d layer.""" + return nn.AdaptiveAvgPool2d((1, 1)) + + +def linear(w_in, w_out, *, bias=False): + """Helper for building a linear layer.""" + return nn.Linear(w_in, w_out, bias=bias) + + +def activation(): + """Helper for building an activation layer.""" + activation_fun = cfg.MODEL.ACTIVATION_FUN.lower() + if activation_fun == "relu": + return nn.ReLU(inplace=cfg.MODEL.ACTIVATION_INPLACE) + elif activation_fun == "silu" or activation_fun == "swish": + try: + return torch.nn.SiLU() + except AttributeError: + return SiLU() + else: + raise AssertionError("Unknown MODEL.ACTIVATION_FUN: " + activation_fun) + + +# --------------------------- Complexity (cx) calculations --------------------------- # + + +def conv2d_cx(cx, w_in, w_out, k, *, stride=1, groups=1, bias=False): + """Accumulates complexity of conv2d into cx = (h, w, flops, params, acts).""" + assert k % 2 == 1, "Only odd size kernels supported to avoid padding issues." + h, w, flops, params, acts = cx["h"], cx["w"], cx["flops"], cx["params"], cx["acts"] + h, w = (h - 1) // stride + 1, (w - 1) // stride + 1 + flops += k * k * w_in * w_out * h * w // groups + (w_out if bias else 0) + params += k * k * w_in * w_out // groups + (w_out if bias else 0) + acts += w_out * h * w + return {"h": h, "w": w, "flops": flops, "params": params, "acts": acts} + + +def norm2d_cx(cx, w_in): + """Accumulates complexity of norm2d into cx = (h, w, flops, params, acts).""" + h, w, flops, params, acts = cx["h"], cx["w"], cx["flops"], cx["params"], cx["acts"] + params += 2 * w_in + return {"h": h, "w": w, "flops": flops, "params": params, "acts": acts} + + +def pool2d_cx(cx, w_in, k, *, stride=1): + """Accumulates complexity of pool2d into cx = (h, w, flops, params, acts).""" + assert k % 2 == 1, "Only odd size kernels supported to avoid padding issues." + h, w, flops, params, acts = cx["h"], cx["w"], cx["flops"], cx["params"], cx["acts"] + h, w = (h - 1) // stride + 1, (w - 1) // stride + 1 + acts += w_in * h * w + return {"h": h, "w": w, "flops": flops, "params": params, "acts": acts} + + +def gap2d_cx(cx, _w_in): + """Accumulates complexity of gap2d into cx = (h, w, flops, params, acts).""" + flops, params, acts = cx["flops"], cx["params"], cx["acts"] + return {"h": 1, "w": 1, "flops": flops, "params": params, "acts": acts} + + +def linear_cx(cx, w_in, w_out, *, bias=False): + """Accumulates complexity of linear into cx = (h, w, flops, params, acts).""" + h, w, flops, params, acts = cx["h"], cx["w"], cx["flops"], cx["params"], cx["acts"] + flops += w_in * w_out + (w_out if bias else 0) + params += w_in * w_out + (w_out if bias else 0) + acts += w_out + return {"h": h, "w": w, "flops": flops, "params": params, "acts": acts} + + +# ---------------------------------- Shared blocks ----------------------------------- # + + +class SiLU(Module): + """SiLU activation function (also known as Swish): x * sigmoid(x).""" + + # Note: will be part of Pytorch 1.7, at which point can remove this. + + def __init__(self): + super(SiLU, self).__init__() + + def forward(self, x): + return x * torch.sigmoid(x) + + +class SE(Module): + """Squeeze-and-Excitation (SE) block: AvgPool, FC, Act, FC, Sigmoid.""" + + def __init__(self, w_in, w_se): + super(SE, self).__init__() + self.avg_pool = gap2d(w_in) + self.f_ex = nn.Sequential( + conv2d(w_in, w_se, 1, bias=True), + activation(), + conv2d(w_se, w_in, 1, bias=True), + nn.Sigmoid(), + ) + + def forward(self, x): + return x * self.f_ex(self.avg_pool(x)) + + @staticmethod + def complexity(cx, w_in, w_se): + h, w = cx["h"], cx["w"] + cx = gap2d_cx(cx, w_in) + cx = conv2d_cx(cx, w_in, w_se, 1, bias=True) + cx = conv2d_cx(cx, w_se, w_in, 1, bias=True) + cx["h"], cx["w"] = h, w + return cx + + +# ---------------------------------- Miscellaneous ----------------------------------- # + + +def adjust_block_compatibility(ws, bs, gs): + """Adjusts the compatibility of widths, bottlenecks, and groups.""" + assert len(ws) == len(bs) == len(gs) + assert all(w > 0 and b > 0 and g > 0 for w, b, g in zip(ws, bs, gs)) + vs = [int(max(1, w * b)) for w, b in zip(ws, bs)] + gs = [int(min(g, v)) for g, v in zip(gs, vs)] + ms = [np.lcm(g, b) if b > 1 else g for g, b in zip(gs, bs)] + vs = [max(m, int(round(v / m) * m)) for v, m in zip(vs, ms)] + ws = [int(v / b) for v, b in zip(vs, bs)] + assert all(w * b % g == 0 for w, b, g in zip(ws, bs, gs)) + return ws, bs, gs + + +def init_weights(m): + """Performs ResNet-style weight initialization.""" + if isinstance(m, nn.Conv2d): + # Note that there is no bias due to BN + fan_out = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(mean=0.0, std=np.sqrt(2.0 / fan_out)) + elif isinstance(m, nn.BatchNorm2d): + zero_init_gamma = cfg.BN.ZERO_INIT_FINAL_GAMMA + zero_init_gamma = hasattr(m, "final_bn") and m.final_bn and zero_init_gamma + m.weight.data.fill_(0.0 if zero_init_gamma else 1.0) + m.bias.data.zero_() + elif isinstance(m, nn.Linear): + m.weight.data.normal_(mean=0.0, std=0.01) + m.bias.data.zero_() + + +def drop_connect(x, drop_ratio): + """Drop connect (adapted from DARTS).""" + keep_ratio = 1.0 - drop_ratio + mask = torch.empty([x.shape[0], 1, 1, 1], dtype=x.dtype, device=x.device) + mask.bernoulli_(keep_ratio) + x.div_(keep_ratio) + x.mul_(mask) + return x diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/effnet.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/effnet.py index 53826fdae7..f58649ccde 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/effnet.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/effnet.py @@ -1,211 +1,211 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -"""EfficientNet models.""" - -from pycls.core.config import cfg -from pycls.models.blocks import ( - SE, - activation, - conv2d, - conv2d_cx, - drop_connect, - gap2d, - gap2d_cx, - init_weights, - linear, - linear_cx, - norm2d, - norm2d_cx, -) -from torch.nn import Dropout, Module - - -class EffHead(Module): - """EfficientNet head: 1x1, BN, AF, AvgPool, Dropout, FC.""" - - def __init__(self, w_in, w_out, num_classes): - super(EffHead, self).__init__() - dropout_ratio = cfg.EN.DROPOUT_RATIO - self.conv = conv2d(w_in, w_out, 1) - self.conv_bn = norm2d(w_out) - self.conv_af = activation() - self.avg_pool = gap2d(w_out) - self.dropout = Dropout(p=dropout_ratio) if dropout_ratio > 0 else None - self.fc = linear(w_out, num_classes, bias=True) - - def forward(self, x): - x = self.conv_af(self.conv_bn(self.conv(x))) - x = self.avg_pool(x) - x = x.view(x.size(0), -1) - x = self.dropout(x) if self.dropout else x - x = self.fc(x) - return x - - @staticmethod - def complexity(cx, w_in, w_out, num_classes): - cx = conv2d_cx(cx, w_in, w_out, 1) - cx = norm2d_cx(cx, w_out) - cx = gap2d_cx(cx, w_out) - cx = linear_cx(cx, w_out, num_classes, bias=True) - return cx - - -class MBConv(Module): - """Mobile inverted bottleneck block with SE.""" - - def __init__(self, w_in, exp_r, k, stride, se_r, w_out): - # Expansion, kxk dwise, BN, AF, SE, 1x1, BN, skip_connection - super(MBConv, self).__init__() - self.exp = None - w_exp = int(w_in * exp_r) - if w_exp != w_in: - self.exp = conv2d(w_in, w_exp, 1) - self.exp_bn = norm2d(w_exp) - self.exp_af = activation() - self.dwise = conv2d(w_exp, w_exp, k, stride=stride, groups=w_exp) - self.dwise_bn = norm2d(w_exp) - self.dwise_af = activation() - self.se = SE(w_exp, int(w_in * se_r)) - self.lin_proj = conv2d(w_exp, w_out, 1) - self.lin_proj_bn = norm2d(w_out) - self.has_skip = stride == 1 and w_in == w_out - - def forward(self, x): - f_x = self.exp_af(self.exp_bn(self.exp(x))) if self.exp else x - f_x = self.dwise_af(self.dwise_bn(self.dwise(f_x))) - f_x = self.se(f_x) - f_x = self.lin_proj_bn(self.lin_proj(f_x)) - if self.has_skip: - if self.training and cfg.EN.DC_RATIO > 0.0: - f_x = drop_connect(f_x, cfg.EN.DC_RATIO) - f_x = x + f_x - return f_x - - @staticmethod - def complexity(cx, w_in, exp_r, k, stride, se_r, w_out): - w_exp = int(w_in * exp_r) - if w_exp != w_in: - cx = conv2d_cx(cx, w_in, w_exp, 1) - cx = norm2d_cx(cx, w_exp) - cx = conv2d_cx(cx, w_exp, w_exp, k, stride=stride, groups=w_exp) - cx = norm2d_cx(cx, w_exp) - cx = SE.complexity(cx, w_exp, int(w_in * se_r)) - cx = conv2d_cx(cx, w_exp, w_out, 1) - cx = norm2d_cx(cx, w_out) - return cx - - -class EffStage(Module): - """EfficientNet stage.""" - - def __init__(self, w_in, exp_r, k, stride, se_r, w_out, d): - super(EffStage, self).__init__() - for i in range(d): - block = MBConv(w_in, exp_r, k, stride, se_r, w_out) - self.add_module("b{}".format(i + 1), block) - stride, w_in = 1, w_out - - def forward(self, x): - for block in self.children(): - x = block(x) - return x - - @staticmethod - def complexity(cx, w_in, exp_r, k, stride, se_r, w_out, d): - for _ in range(d): - cx = MBConv.complexity(cx, w_in, exp_r, k, stride, se_r, w_out) - stride, w_in = 1, w_out - return cx - - -class StemIN(Module): - """EfficientNet stem for ImageNet: 3x3, BN, AF.""" - - def __init__(self, w_in, w_out): - super(StemIN, self).__init__() - self.conv = conv2d(w_in, w_out, 3, stride=2) - self.bn = norm2d(w_out) - self.af = activation() - - def forward(self, x): - for layer in self.children(): - x = layer(x) - return x - - @staticmethod - def complexity(cx, w_in, w_out): - cx = conv2d_cx(cx, w_in, w_out, 3, stride=2) - cx = norm2d_cx(cx, w_out) - return cx - - -class EffNet(Module): - """EfficientNet model.""" - - @staticmethod - def get_params(): - return { - "sw": cfg.EN.STEM_W, - "ds": cfg.EN.DEPTHS, - "ws": cfg.EN.WIDTHS, - "exp_rs": cfg.EN.EXP_RATIOS, - "se_r": cfg.EN.SE_R, - "ss": cfg.EN.STRIDES, - "ks": cfg.EN.KERNELS, - "hw": cfg.EN.HEAD_W, - "nc": cfg.MODEL.NUM_CLASSES, - } - - def __init__(self, params=None): - super(EffNet, self).__init__() - p = EffNet.get_params() if not params else params - vs = ["sw", "ds", "ws", "exp_rs", "se_r", "ss", "ks", "hw", "nc"] - sw, ds, ws, exp_rs, se_r, ss, ks, hw, nc = [p[v] for v in vs] - stage_params = list(zip(ds, ws, exp_rs, ss, ks)) - self.stem = StemIN(3, sw) - prev_w = sw - for i, (d, w, exp_r, stride, k) in enumerate(stage_params): - stage = EffStage(prev_w, exp_r, k, stride, se_r, w, d) - self.add_module("s{}".format(i + 1), stage) - prev_w = w - self.head = EffHead(prev_w, hw, nc) - self.apply(init_weights) - - def forward(self, x): - for module in self.children(): - x = module(x) - return x - - @staticmethod - def complexity(cx, params=None): - """Computes model complexity (if you alter the model, make sure to update).""" - p = EffNet.get_params() if not params else params - vs = ["sw", "ds", "ws", "exp_rs", "se_r", "ss", "ks", "hw", "nc"] - sw, ds, ws, exp_rs, se_r, ss, ks, hw, nc = [p[v] for v in vs] - stage_params = list(zip(ds, ws, exp_rs, ss, ks)) - cx = StemIN.complexity(cx, 3, sw) - prev_w = sw - for d, w, exp_r, stride, k in stage_params: - cx = EffStage.complexity(cx, prev_w, exp_r, k, stride, se_r, w, d) - prev_w = w - cx = EffHead.complexity(cx, prev_w, hw, nc) - return cx +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +"""EfficientNet models.""" + +from pycls.core.config import cfg +from pycls.models.blocks import ( + SE, + activation, + conv2d, + conv2d_cx, + drop_connect, + gap2d, + gap2d_cx, + init_weights, + linear, + linear_cx, + norm2d, + norm2d_cx, +) +from torch.nn import Dropout, Module + + +class EffHead(Module): + """EfficientNet head: 1x1, BN, AF, AvgPool, Dropout, FC.""" + + def __init__(self, w_in, w_out, num_classes): + super(EffHead, self).__init__() + dropout_ratio = cfg.EN.DROPOUT_RATIO + self.conv = conv2d(w_in, w_out, 1) + self.conv_bn = norm2d(w_out) + self.conv_af = activation() + self.avg_pool = gap2d(w_out) + self.dropout = Dropout(p=dropout_ratio) if dropout_ratio > 0 else None + self.fc = linear(w_out, num_classes, bias=True) + + def forward(self, x): + x = self.conv_af(self.conv_bn(self.conv(x))) + x = self.avg_pool(x) + x = x.view(x.size(0), -1) + x = self.dropout(x) if self.dropout else x + x = self.fc(x) + return x + + @staticmethod + def complexity(cx, w_in, w_out, num_classes): + cx = conv2d_cx(cx, w_in, w_out, 1) + cx = norm2d_cx(cx, w_out) + cx = gap2d_cx(cx, w_out) + cx = linear_cx(cx, w_out, num_classes, bias=True) + return cx + + +class MBConv(Module): + """Mobile inverted bottleneck block with SE.""" + + def __init__(self, w_in, exp_r, k, stride, se_r, w_out): + # Expansion, kxk dwise, BN, AF, SE, 1x1, BN, skip_connection + super(MBConv, self).__init__() + self.exp = None + w_exp = int(w_in * exp_r) + if w_exp != w_in: + self.exp = conv2d(w_in, w_exp, 1) + self.exp_bn = norm2d(w_exp) + self.exp_af = activation() + self.dwise = conv2d(w_exp, w_exp, k, stride=stride, groups=w_exp) + self.dwise_bn = norm2d(w_exp) + self.dwise_af = activation() + self.se = SE(w_exp, int(w_in * se_r)) + self.lin_proj = conv2d(w_exp, w_out, 1) + self.lin_proj_bn = norm2d(w_out) + self.has_skip = stride == 1 and w_in == w_out + + def forward(self, x): + f_x = self.exp_af(self.exp_bn(self.exp(x))) if self.exp else x + f_x = self.dwise_af(self.dwise_bn(self.dwise(f_x))) + f_x = self.se(f_x) + f_x = self.lin_proj_bn(self.lin_proj(f_x)) + if self.has_skip: + if self.training and cfg.EN.DC_RATIO > 0.0: + f_x = drop_connect(f_x, cfg.EN.DC_RATIO) + f_x = x + f_x + return f_x + + @staticmethod + def complexity(cx, w_in, exp_r, k, stride, se_r, w_out): + w_exp = int(w_in * exp_r) + if w_exp != w_in: + cx = conv2d_cx(cx, w_in, w_exp, 1) + cx = norm2d_cx(cx, w_exp) + cx = conv2d_cx(cx, w_exp, w_exp, k, stride=stride, groups=w_exp) + cx = norm2d_cx(cx, w_exp) + cx = SE.complexity(cx, w_exp, int(w_in * se_r)) + cx = conv2d_cx(cx, w_exp, w_out, 1) + cx = norm2d_cx(cx, w_out) + return cx + + +class EffStage(Module): + """EfficientNet stage.""" + + def __init__(self, w_in, exp_r, k, stride, se_r, w_out, d): + super(EffStage, self).__init__() + for i in range(d): + block = MBConv(w_in, exp_r, k, stride, se_r, w_out) + self.add_module("b{}".format(i + 1), block) + stride, w_in = 1, w_out + + def forward(self, x): + for block in self.children(): + x = block(x) + return x + + @staticmethod + def complexity(cx, w_in, exp_r, k, stride, se_r, w_out, d): + for _ in range(d): + cx = MBConv.complexity(cx, w_in, exp_r, k, stride, se_r, w_out) + stride, w_in = 1, w_out + return cx + + +class StemIN(Module): + """EfficientNet stem for ImageNet: 3x3, BN, AF.""" + + def __init__(self, w_in, w_out): + super(StemIN, self).__init__() + self.conv = conv2d(w_in, w_out, 3, stride=2) + self.bn = norm2d(w_out) + self.af = activation() + + def forward(self, x): + for layer in self.children(): + x = layer(x) + return x + + @staticmethod + def complexity(cx, w_in, w_out): + cx = conv2d_cx(cx, w_in, w_out, 3, stride=2) + cx = norm2d_cx(cx, w_out) + return cx + + +class EffNet(Module): + """EfficientNet model.""" + + @staticmethod + def get_params(): + return { + "sw": cfg.EN.STEM_W, + "ds": cfg.EN.DEPTHS, + "ws": cfg.EN.WIDTHS, + "exp_rs": cfg.EN.EXP_RATIOS, + "se_r": cfg.EN.SE_R, + "ss": cfg.EN.STRIDES, + "ks": cfg.EN.KERNELS, + "hw": cfg.EN.HEAD_W, + "nc": cfg.MODEL.NUM_CLASSES, + } + + def __init__(self, params=None): + super(EffNet, self).__init__() + p = EffNet.get_params() if not params else params + vs = ["sw", "ds", "ws", "exp_rs", "se_r", "ss", "ks", "hw", "nc"] + sw, ds, ws, exp_rs, se_r, ss, ks, hw, nc = [p[v] for v in vs] + stage_params = list(zip(ds, ws, exp_rs, ss, ks)) + self.stem = StemIN(3, sw) + prev_w = sw + for i, (d, w, exp_r, stride, k) in enumerate(stage_params): + stage = EffStage(prev_w, exp_r, k, stride, se_r, w, d) + self.add_module("s{}".format(i + 1), stage) + prev_w = w + self.head = EffHead(prev_w, hw, nc) + self.apply(init_weights) + + def forward(self, x): + for module in self.children(): + x = module(x) + return x + + @staticmethod + def complexity(cx, params=None): + """Computes model complexity (if you alter the model, make sure to update).""" + p = EffNet.get_params() if not params else params + vs = ["sw", "ds", "ws", "exp_rs", "se_r", "ss", "ks", "hw", "nc"] + sw, ds, ws, exp_rs, se_r, ss, ks, hw, nc = [p[v] for v in vs] + stage_params = list(zip(ds, ws, exp_rs, ss, ks)) + cx = StemIN.complexity(cx, 3, sw) + prev_w = sw + for d, w, exp_r, stride, k in stage_params: + cx = EffStage.complexity(cx, prev_w, exp_r, k, stride, se_r, w, d) + prev_w = w + cx = EffHead.complexity(cx, prev_w, hw, nc) + return cx diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/model_zoo.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/model_zoo.py index 301e3396de..1391e1d00a 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/model_zoo.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/model_zoo.py @@ -1,196 +1,196 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -"""Model zoo.""" - -import os - -import pycls.core.builders as builders -import pycls.core.checkpoint as cp -from pycls.core.config import cfg, reset_cfg -from pycls.core.io import cache_url - - -# URL prefix for pretrained models -_URL_WEIGHTS = "https://dl.fbaipublicfiles.com/pycls" - -# URL prefix for model config files -_URL_CONFIGS = "https://raw.githubusercontent.com/facebookresearch/pycls/master/configs" - -# Model weights download cache directory -_DOWNLOAD_CACHE = "/tmp/pycls-download-cache" - -# Predefined model config files -_MODEL_ZOO_CONFIGS = { - "RegNetX-200MF": "dds_baselines/regnetx/RegNetX-200MF_dds_8gpu.yaml", - "RegNetX-400MF": "dds_baselines/regnetx/RegNetX-400MF_dds_8gpu.yaml", - "RegNetX-600MF": "dds_baselines/regnetx/RegNetX-600MF_dds_8gpu.yaml", - "RegNetX-800MF": "dds_baselines/regnetx/RegNetX-800MF_dds_8gpu.yaml", - "RegNetX-1.6GF": "dds_baselines/regnetx/RegNetX-1.6GF_dds_8gpu.yaml", - "RegNetX-3.2GF": "dds_baselines/regnetx/RegNetX-3.2GF_dds_8gpu.yaml", - "RegNetX-4.0GF": "dds_baselines/regnetx/RegNetX-4.0GF_dds_8gpu.yaml", - "RegNetX-6.4GF": "dds_baselines/regnetx/RegNetX-6.4GF_dds_8gpu.yaml", - "RegNetX-8.0GF": "dds_baselines/regnetx/RegNetX-8.0GF_dds_8gpu.yaml", - "RegNetX-12GF": "dds_baselines/regnetx/RegNetX-12GF_dds_8gpu.yaml", - "RegNetX-16GF": "dds_baselines/regnetx/RegNetX-16GF_dds_8gpu.yaml", - "RegNetX-32GF": "dds_baselines/regnetx/RegNetX-32GF_dds_8gpu.yaml", - "RegNetY-200MF": "dds_baselines/regnety/RegNetY-200MF_dds_8gpu.yaml", - "RegNetY-400MF": "dds_baselines/regnety/RegNetY-400MF_dds_8gpu.yaml", - "RegNetY-600MF": "dds_baselines/regnety/RegNetY-600MF_dds_8gpu.yaml", - "RegNetY-800MF": "dds_baselines/regnety/RegNetY-800MF_dds_8gpu.yaml", - "RegNetY-1.6GF": "dds_baselines/regnety/RegNetY-1.6GF_dds_8gpu.yaml", - "RegNetY-3.2GF": "dds_baselines/regnety/RegNetY-3.2GF_dds_8gpu.yaml", - "RegNetY-4.0GF": "dds_baselines/regnety/RegNetY-4.0GF_dds_8gpu.yaml", - "RegNetY-6.4GF": "dds_baselines/regnety/RegNetY-6.4GF_dds_8gpu.yaml", - "RegNetY-8.0GF": "dds_baselines/regnety/RegNetY-8.0GF_dds_8gpu.yaml", - "RegNetY-12GF": "dds_baselines/regnety/RegNetY-12GF_dds_8gpu.yaml", - "RegNetY-16GF": "dds_baselines/regnety/RegNetY-16GF_dds_8gpu.yaml", - "RegNetY-32GF": "dds_baselines/regnety/RegNetY-32GF_dds_8gpu.yaml", - "ResNet-50": "dds_baselines/resnet/R-50-1x64d_dds_8gpu.yaml", - "ResNet-101": "dds_baselines/resnet/R-101-1x64d_dds_8gpu.yaml", - "ResNet-152": "dds_baselines/resnet/R-152-1x64d_dds_8gpu.yaml", - "ResNeXt-50": "dds_baselines/resnext/X-50-32x4d_dds_8gpu.yaml", - "ResNeXt-101": "dds_baselines/resnext/X-101-32x4d_dds_8gpu.yaml", - "ResNeXt-152": "dds_baselines/resnext/X-152-32x4d_dds_8gpu.yaml", - "EfficientNet-B0": "dds_baselines/effnet/EN-B0_dds_8gpu.yaml", - "EfficientNet-B1": "dds_baselines/effnet/EN-B1_dds_8gpu.yaml", - "EfficientNet-B2": "dds_baselines/effnet/EN-B2_dds_8gpu.yaml", - "EfficientNet-B3": "dds_baselines/effnet/EN-B3_dds_8gpu.yaml", - "EfficientNet-B4": "dds_baselines/effnet/EN-B4_dds_8gpu.yaml", - "EfficientNet-B5": "dds_baselines/effnet/EN-B5_dds_8gpu.yaml", -} - -# Predefined model weight files -_MODEL_ZOO_WEIGHTS = { - "RegNetX-200MF": "dds_baselines/160905981/RegNetX-200MF_dds_8gpu.pyth", - "RegNetX-400MF": "dds_baselines/160905967/RegNetX-400MF_dds_8gpu.pyth", - "RegNetX-600MF": "dds_baselines/160906442/RegNetX-600MF_dds_8gpu.pyth", - "RegNetX-800MF": "dds_baselines/160906036/RegNetX-800MF_dds_8gpu.pyth", - "RegNetX-1.6GF": "dds_baselines/160990626/RegNetX-1.6GF_dds_8gpu.pyth", - "RegNetX-3.2GF": "dds_baselines/160906139/RegNetX-3.2GF_dds_8gpu.pyth", - "RegNetX-4.0GF": "dds_baselines/160906383/RegNetX-4.0GF_dds_8gpu.pyth", - "RegNetX-6.4GF": "dds_baselines/161116590/RegNetX-6.4GF_dds_8gpu.pyth", - "RegNetX-8.0GF": "dds_baselines/161107726/RegNetX-8.0GF_dds_8gpu.pyth", - "RegNetX-12GF": "dds_baselines/160906020/RegNetX-12GF_dds_8gpu.pyth", - "RegNetX-16GF": "dds_baselines/158460855/RegNetX-16GF_dds_8gpu.pyth", - "RegNetX-32GF": "dds_baselines/158188473/RegNetX-32GF_dds_8gpu.pyth", - "RegNetY-200MF": "dds_baselines/176245422/RegNetY-200MF_dds_8gpu.pyth", - "RegNetY-400MF": "dds_baselines/160906449/RegNetY-400MF_dds_8gpu.pyth", - "RegNetY-600MF": "dds_baselines/160981443/RegNetY-600MF_dds_8gpu.pyth", - "RegNetY-800MF": "dds_baselines/160906567/RegNetY-800MF_dds_8gpu.pyth", - "RegNetY-1.6GF": "dds_baselines/160906681/RegNetY-1.6GF_dds_8gpu.pyth", - "RegNetY-3.2GF": "dds_baselines/160906834/RegNetY-3.2GF_dds_8gpu.pyth", - "RegNetY-4.0GF": "dds_baselines/160906838/RegNetY-4.0GF_dds_8gpu.pyth", - "RegNetY-6.4GF": "dds_baselines/160907112/RegNetY-6.4GF_dds_8gpu.pyth", - "RegNetY-8.0GF": "dds_baselines/161160905/RegNetY-8.0GF_dds_8gpu.pyth", - "RegNetY-12GF": "dds_baselines/160907100/RegNetY-12GF_dds_8gpu.pyth", - "RegNetY-16GF": "dds_baselines/161303400/RegNetY-16GF_dds_8gpu.pyth", - "RegNetY-32GF": "dds_baselines/161277763/RegNetY-32GF_dds_8gpu.pyth", - "ResNet-50": "dds_baselines/161235311/R-50-1x64d_dds_8gpu.pyth", - "ResNet-101": "dds_baselines/161167170/R-101-1x64d_dds_8gpu.pyth", - "ResNet-152": "dds_baselines/161167467/R-152-1x64d_dds_8gpu.pyth", - "ResNeXt-50": "dds_baselines/161167411/X-50-32x4d_dds_8gpu.pyth", - "ResNeXt-101": "dds_baselines/161167590/X-101-32x4d_dds_8gpu.pyth", - "ResNeXt-152": "dds_baselines/162471172/X-152-32x4d_dds_8gpu.pyth", - "EfficientNet-B0": "dds_baselines/161305613/EN-B0_dds_8gpu.pyth", - "EfficientNet-B1": "dds_baselines/161304979/EN-B1_dds_8gpu.pyth", - "EfficientNet-B2": "dds_baselines/161305015/EN-B2_dds_8gpu.pyth", - "EfficientNet-B3": "dds_baselines/161305060/EN-B3_dds_8gpu.pyth", - "EfficientNet-B4": "dds_baselines/161305098/EN-B4_dds_8gpu.pyth", - "EfficientNet-B5": "dds_baselines/161305138/EN-B5_dds_8gpu.pyth", -} - - -def get_model_list(): - """Get list of all valid models in model zoo.""" - return _MODEL_ZOO_WEIGHTS.keys() - - -def get_config_file(name): - """Get file with model config (downloads if necessary).""" - err_str = "Model {} not found in the model zoo.".format(name) - assert name in _MODEL_ZOO_CONFIGS.keys(), err_str - config_url = os.path.join(_URL_CONFIGS, _MODEL_ZOO_CONFIGS[name]) - return cache_url(config_url, _DOWNLOAD_CACHE, _URL_CONFIGS) - - -def get_weights_file(name): - """Get file with model weights (downloads if necessary).""" - err_str = "Model {} not found in the model zoo.".format(name) - assert name in _MODEL_ZOO_WEIGHTS.keys(), err_str - weights_url = os.path.join(_URL_WEIGHTS, _MODEL_ZOO_WEIGHTS[name]) - return cache_url(weights_url, _DOWNLOAD_CACHE, _URL_WEIGHTS) - - -def get_model_info(name): - """Return model info (useful for debugging).""" - config_url = _MODEL_ZOO_CONFIGS[name] - weight_url = _MODEL_ZOO_WEIGHTS[name] - model_id = weight_url.split("/")[1] - config_url_full = os.path.join(_URL_CONFIGS, _MODEL_ZOO_CONFIGS[name]) - weight_url_full = os.path.join(_URL_WEIGHTS, _MODEL_ZOO_WEIGHTS[name]) - return config_url, weight_url, model_id, config_url_full, weight_url_full - - -def build_model(name, pretrained=False, cfg_list=()): - """Constructs a predefined model (note: loads global config as well).""" - # Load the config - reset_cfg() - config_file = get_config_file(name) - cfg.merge_from_file(config_file) - cfg.merge_from_list(cfg_list) - # Construct model - model = builders.build_model() - # Load pretrained weights - if pretrained: - weights_file = get_weights_file(name) - cp.load_checkpoint(weights_file, model) - return model - - -def regnetx(name, pretrained=False, cfg_list=()): - """Constructs a RegNetX model (note: loads global config as well).""" - name = name if "RegNetX-" in name else "RegNetX-" + name - return build_model(name, pretrained, cfg_list) - - -def regnety(name, pretrained=False, cfg_list=()): - """Constructs a RegNetY model (note: loads global config as well).""" - name = name if "RegNetY-" in name else "RegNetY-" + name - return build_model(name, pretrained, cfg_list) - - -def resnet(name, pretrained=False, cfg_list=()): - """Constructs a ResNet model (note: loads global config as well).""" - name = name if "ResNet-" in name else "ResNet-" + name - return build_model(name, pretrained, cfg_list) - - -def resnext(name, pretrained=False, cfg_list=()): - """Constructs a ResNeXt model (note: loads global config as well).""" - name = name if "ResNeXt-" in name else "ResNeXt-" + name - return build_model(name, pretrained, cfg_list) - - -def effnet(name, pretrained=False, cfg_list=()): - """Constructs an EfficientNet model (note: loads global config as well).""" - name = name if "EfficientNet-" in name else "EfficientNet-" + name - return build_model(name, pretrained, cfg_list) +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +"""Model zoo.""" + +import os + +import pycls.core.builders as builders +import pycls.core.checkpoint as cp +from pycls.core.config import cfg, reset_cfg +from pycls.core.io import cache_url + + +# URL prefix for pretrained models +_URL_WEIGHTS = "https://dl.fbaipublicfiles.com/pycls" + +# URL prefix for model config files +_URL_CONFIGS = "https://raw.githubusercontent.com/facebookresearch/pycls/master/configs" + +# Model weights download cache directory +_DOWNLOAD_CACHE = "/tmp/pycls-download-cache" + +# Predefined model config files +_MODEL_ZOO_CONFIGS = { + "RegNetX-200MF": "dds_baselines/regnetx/RegNetX-200MF_dds_8gpu.yaml", + "RegNetX-400MF": "dds_baselines/regnetx/RegNetX-400MF_dds_8gpu.yaml", + "RegNetX-600MF": "dds_baselines/regnetx/RegNetX-600MF_dds_8gpu.yaml", + "RegNetX-800MF": "dds_baselines/regnetx/RegNetX-800MF_dds_8gpu.yaml", + "RegNetX-1.6GF": "dds_baselines/regnetx/RegNetX-1.6GF_dds_8gpu.yaml", + "RegNetX-3.2GF": "dds_baselines/regnetx/RegNetX-3.2GF_dds_8gpu.yaml", + "RegNetX-4.0GF": "dds_baselines/regnetx/RegNetX-4.0GF_dds_8gpu.yaml", + "RegNetX-6.4GF": "dds_baselines/regnetx/RegNetX-6.4GF_dds_8gpu.yaml", + "RegNetX-8.0GF": "dds_baselines/regnetx/RegNetX-8.0GF_dds_8gpu.yaml", + "RegNetX-12GF": "dds_baselines/regnetx/RegNetX-12GF_dds_8gpu.yaml", + "RegNetX-16GF": "dds_baselines/regnetx/RegNetX-16GF_dds_8gpu.yaml", + "RegNetX-32GF": "dds_baselines/regnetx/RegNetX-32GF_dds_8gpu.yaml", + "RegNetY-200MF": "dds_baselines/regnety/RegNetY-200MF_dds_8gpu.yaml", + "RegNetY-400MF": "dds_baselines/regnety/RegNetY-400MF_dds_8gpu.yaml", + "RegNetY-600MF": "dds_baselines/regnety/RegNetY-600MF_dds_8gpu.yaml", + "RegNetY-800MF": "dds_baselines/regnety/RegNetY-800MF_dds_8gpu.yaml", + "RegNetY-1.6GF": "dds_baselines/regnety/RegNetY-1.6GF_dds_8gpu.yaml", + "RegNetY-3.2GF": "dds_baselines/regnety/RegNetY-3.2GF_dds_8gpu.yaml", + "RegNetY-4.0GF": "dds_baselines/regnety/RegNetY-4.0GF_dds_8gpu.yaml", + "RegNetY-6.4GF": "dds_baselines/regnety/RegNetY-6.4GF_dds_8gpu.yaml", + "RegNetY-8.0GF": "dds_baselines/regnety/RegNetY-8.0GF_dds_8gpu.yaml", + "RegNetY-12GF": "dds_baselines/regnety/RegNetY-12GF_dds_8gpu.yaml", + "RegNetY-16GF": "dds_baselines/regnety/RegNetY-16GF_dds_8gpu.yaml", + "RegNetY-32GF": "dds_baselines/regnety/RegNetY-32GF_dds_8gpu.yaml", + "ResNet-50": "dds_baselines/resnet/R-50-1x64d_dds_8gpu.yaml", + "ResNet-101": "dds_baselines/resnet/R-101-1x64d_dds_8gpu.yaml", + "ResNet-152": "dds_baselines/resnet/R-152-1x64d_dds_8gpu.yaml", + "ResNeXt-50": "dds_baselines/resnext/X-50-32x4d_dds_8gpu.yaml", + "ResNeXt-101": "dds_baselines/resnext/X-101-32x4d_dds_8gpu.yaml", + "ResNeXt-152": "dds_baselines/resnext/X-152-32x4d_dds_8gpu.yaml", + "EfficientNet-B0": "dds_baselines/effnet/EN-B0_dds_8gpu.yaml", + "EfficientNet-B1": "dds_baselines/effnet/EN-B1_dds_8gpu.yaml", + "EfficientNet-B2": "dds_baselines/effnet/EN-B2_dds_8gpu.yaml", + "EfficientNet-B3": "dds_baselines/effnet/EN-B3_dds_8gpu.yaml", + "EfficientNet-B4": "dds_baselines/effnet/EN-B4_dds_8gpu.yaml", + "EfficientNet-B5": "dds_baselines/effnet/EN-B5_dds_8gpu.yaml", +} + +# Predefined model weight files +_MODEL_ZOO_WEIGHTS = { + "RegNetX-200MF": "dds_baselines/160905981/RegNetX-200MF_dds_8gpu.pyth", + "RegNetX-400MF": "dds_baselines/160905967/RegNetX-400MF_dds_8gpu.pyth", + "RegNetX-600MF": "dds_baselines/160906442/RegNetX-600MF_dds_8gpu.pyth", + "RegNetX-800MF": "dds_baselines/160906036/RegNetX-800MF_dds_8gpu.pyth", + "RegNetX-1.6GF": "dds_baselines/160990626/RegNetX-1.6GF_dds_8gpu.pyth", + "RegNetX-3.2GF": "dds_baselines/160906139/RegNetX-3.2GF_dds_8gpu.pyth", + "RegNetX-4.0GF": "dds_baselines/160906383/RegNetX-4.0GF_dds_8gpu.pyth", + "RegNetX-6.4GF": "dds_baselines/161116590/RegNetX-6.4GF_dds_8gpu.pyth", + "RegNetX-8.0GF": "dds_baselines/161107726/RegNetX-8.0GF_dds_8gpu.pyth", + "RegNetX-12GF": "dds_baselines/160906020/RegNetX-12GF_dds_8gpu.pyth", + "RegNetX-16GF": "dds_baselines/158460855/RegNetX-16GF_dds_8gpu.pyth", + "RegNetX-32GF": "dds_baselines/158188473/RegNetX-32GF_dds_8gpu.pyth", + "RegNetY-200MF": "dds_baselines/176245422/RegNetY-200MF_dds_8gpu.pyth", + "RegNetY-400MF": "dds_baselines/160906449/RegNetY-400MF_dds_8gpu.pyth", + "RegNetY-600MF": "dds_baselines/160981443/RegNetY-600MF_dds_8gpu.pyth", + "RegNetY-800MF": "dds_baselines/160906567/RegNetY-800MF_dds_8gpu.pyth", + "RegNetY-1.6GF": "dds_baselines/160906681/RegNetY-1.6GF_dds_8gpu.pyth", + "RegNetY-3.2GF": "dds_baselines/160906834/RegNetY-3.2GF_dds_8gpu.pyth", + "RegNetY-4.0GF": "dds_baselines/160906838/RegNetY-4.0GF_dds_8gpu.pyth", + "RegNetY-6.4GF": "dds_baselines/160907112/RegNetY-6.4GF_dds_8gpu.pyth", + "RegNetY-8.0GF": "dds_baselines/161160905/RegNetY-8.0GF_dds_8gpu.pyth", + "RegNetY-12GF": "dds_baselines/160907100/RegNetY-12GF_dds_8gpu.pyth", + "RegNetY-16GF": "dds_baselines/161303400/RegNetY-16GF_dds_8gpu.pyth", + "RegNetY-32GF": "dds_baselines/161277763/RegNetY-32GF_dds_8gpu.pyth", + "ResNet-50": "dds_baselines/161235311/R-50-1x64d_dds_8gpu.pyth", + "ResNet-101": "dds_baselines/161167170/R-101-1x64d_dds_8gpu.pyth", + "ResNet-152": "dds_baselines/161167467/R-152-1x64d_dds_8gpu.pyth", + "ResNeXt-50": "dds_baselines/161167411/X-50-32x4d_dds_8gpu.pyth", + "ResNeXt-101": "dds_baselines/161167590/X-101-32x4d_dds_8gpu.pyth", + "ResNeXt-152": "dds_baselines/162471172/X-152-32x4d_dds_8gpu.pyth", + "EfficientNet-B0": "dds_baselines/161305613/EN-B0_dds_8gpu.pyth", + "EfficientNet-B1": "dds_baselines/161304979/EN-B1_dds_8gpu.pyth", + "EfficientNet-B2": "dds_baselines/161305015/EN-B2_dds_8gpu.pyth", + "EfficientNet-B3": "dds_baselines/161305060/EN-B3_dds_8gpu.pyth", + "EfficientNet-B4": "dds_baselines/161305098/EN-B4_dds_8gpu.pyth", + "EfficientNet-B5": "dds_baselines/161305138/EN-B5_dds_8gpu.pyth", +} + + +def get_model_list(): + """Get list of all valid models in model zoo.""" + return _MODEL_ZOO_WEIGHTS.keys() + + +def get_config_file(name): + """Get file with model config (downloads if necessary).""" + err_str = "Model {} not found in the model zoo.".format(name) + assert name in _MODEL_ZOO_CONFIGS.keys(), err_str + config_url = os.path.join(_URL_CONFIGS, _MODEL_ZOO_CONFIGS[name]) + return cache_url(config_url, _DOWNLOAD_CACHE, _URL_CONFIGS) + + +def get_weights_file(name): + """Get file with model weights (downloads if necessary).""" + err_str = "Model {} not found in the model zoo.".format(name) + assert name in _MODEL_ZOO_WEIGHTS.keys(), err_str + weights_url = os.path.join(_URL_WEIGHTS, _MODEL_ZOO_WEIGHTS[name]) + return cache_url(weights_url, _DOWNLOAD_CACHE, _URL_WEIGHTS) + + +def get_model_info(name): + """Return model info (useful for debugging).""" + config_url = _MODEL_ZOO_CONFIGS[name] + weight_url = _MODEL_ZOO_WEIGHTS[name] + model_id = weight_url.split("/")[1] + config_url_full = os.path.join(_URL_CONFIGS, _MODEL_ZOO_CONFIGS[name]) + weight_url_full = os.path.join(_URL_WEIGHTS, _MODEL_ZOO_WEIGHTS[name]) + return config_url, weight_url, model_id, config_url_full, weight_url_full + + +def build_model(name, pretrained=False, cfg_list=()): + """Constructs a predefined model (note: loads global config as well).""" + # Load the config + reset_cfg() + config_file = get_config_file(name) + cfg.merge_from_file(config_file) + cfg.merge_from_list(cfg_list) + # Construct model + model = builders.build_model() + # Load pretrained weights + if pretrained: + weights_file = get_weights_file(name) + cp.load_checkpoint(weights_file, model) + return model + + +def regnetx(name, pretrained=False, cfg_list=()): + """Constructs a RegNetX model (note: loads global config as well).""" + name = name if "RegNetX-" in name else "RegNetX-" + name + return build_model(name, pretrained, cfg_list) + + +def regnety(name, pretrained=False, cfg_list=()): + """Constructs a RegNetY model (note: loads global config as well).""" + name = name if "RegNetY-" in name else "RegNetY-" + name + return build_model(name, pretrained, cfg_list) + + +def resnet(name, pretrained=False, cfg_list=()): + """Constructs a ResNet model (note: loads global config as well).""" + name = name if "ResNet-" in name else "ResNet-" + name + return build_model(name, pretrained, cfg_list) + + +def resnext(name, pretrained=False, cfg_list=()): + """Constructs a ResNeXt model (note: loads global config as well).""" + name = name if "ResNeXt-" in name else "ResNeXt-" + name + return build_model(name, pretrained, cfg_list) + + +def effnet(name, pretrained=False, cfg_list=()): + """Constructs an EfficientNet model (note: loads global config as well).""" + name = name if "EfficientNet-" in name else "EfficientNet-" + name + return build_model(name, pretrained, cfg_list) diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/regnet.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/regnet.py index 646336bbf5..271deeb4fa 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/regnet.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/regnet.py @@ -1,83 +1,83 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -"""RegNet models.""" - -import numpy as np -import pycls.models.blocks as bk -from pycls.core.config import cfg -from pycls.models.anynet import AnyNet - - -def generate_regnet(w_a, w_0, w_m, d, q=8): - """Generates per stage widths and depths from RegNet parameters.""" - assert w_a >= 0 and w_0 > 0 and w_m > 1 and w_0 % q == 0 - # Generate continuous per-block ws - ws_cont = np.arange(d) * w_a + w_0 - # Generate quantized per-block ws - ks = np.round(np.log(ws_cont / w_0) / np.log(w_m)) - ws_all = w_0 * np.power(w_m, ks) - ws_all = np.round(np.divide(ws_all, q)).astype(int) * q - # Generate per stage ws and ds (assumes ws_all are sorted) - ws, ds = np.unique(ws_all, return_counts=True) - # Compute number of actual stages and total possible stages - num_stages, total_stages = len(ws), ks.max() + 1 - # Convert numpy arrays to lists and return - ws, ds, ws_all, ws_cont = (x.tolist() for x in (ws, ds, ws_all, ws_cont)) - return ws, ds, num_stages, total_stages, ws_all, ws_cont - - -class RegNet(AnyNet): - """RegNet model.""" - - @staticmethod - def get_params(): - """Convert RegNet to AnyNet parameter format.""" - # Generates per stage ws, ds, gs, bs, and ss from RegNet parameters - w_a, w_0, w_m, d = cfg.REGNET.WA, cfg.REGNET.W0, cfg.REGNET.WM, cfg.REGNET.DEPTH - ws, ds = generate_regnet(w_a, w_0, w_m, d)[0:2] - ss = [cfg.REGNET.STRIDE for _ in ws] - bs = [cfg.REGNET.BOT_MUL for _ in ws] - gs = [cfg.REGNET.GROUP_W for _ in ws] - ws, bs, gs = bk.adjust_block_compatibility(ws, bs, gs) - # Get AnyNet arguments defining the RegNet - return { - "stem_type": cfg.REGNET.STEM_TYPE, - "stem_w": cfg.REGNET.STEM_W, - "block_type": cfg.REGNET.BLOCK_TYPE, - "depths": ds, - "widths": ws, - "strides": ss, - "bot_muls": bs, - "group_ws": gs, - "se_r": cfg.REGNET.SE_R if cfg.REGNET.SE_ON else 0, - "num_classes": cfg.MODEL.NUM_CLASSES, - } - - def __init__(self): - params = RegNet.get_params() - super(RegNet, self).__init__(params) - - @staticmethod - def complexity(cx, params=None): - """Computes model complexity (if you alter the model, make sure to update).""" - params = RegNet.get_params() if not params else params - return AnyNet.complexity(cx, params) +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +"""RegNet models.""" + +import numpy as np +import pycls.models.blocks as bk +from pycls.core.config import cfg +from pycls.models.anynet import AnyNet + + +def generate_regnet(w_a, w_0, w_m, d, q=8): + """Generates per stage widths and depths from RegNet parameters.""" + assert w_a >= 0 and w_0 > 0 and w_m > 1 and w_0 % q == 0 + # Generate continuous per-block ws + ws_cont = np.arange(d) * w_a + w_0 + # Generate quantized per-block ws + ks = np.round(np.log(ws_cont / w_0) / np.log(w_m)) + ws_all = w_0 * np.power(w_m, ks) + ws_all = np.round(np.divide(ws_all, q)).astype(int) * q + # Generate per stage ws and ds (assumes ws_all are sorted) + ws, ds = np.unique(ws_all, return_counts=True) + # Compute number of actual stages and total possible stages + num_stages, total_stages = len(ws), ks.max() + 1 + # Convert numpy arrays to lists and return + ws, ds, ws_all, ws_cont = (x.tolist() for x in (ws, ds, ws_all, ws_cont)) + return ws, ds, num_stages, total_stages, ws_all, ws_cont + + +class RegNet(AnyNet): + """RegNet model.""" + + @staticmethod + def get_params(): + """Convert RegNet to AnyNet parameter format.""" + # Generates per stage ws, ds, gs, bs, and ss from RegNet parameters + w_a, w_0, w_m, d = cfg.REGNET.WA, cfg.REGNET.W0, cfg.REGNET.WM, cfg.REGNET.DEPTH + ws, ds = generate_regnet(w_a, w_0, w_m, d)[0:2] + ss = [cfg.REGNET.STRIDE for _ in ws] + bs = [cfg.REGNET.BOT_MUL for _ in ws] + gs = [cfg.REGNET.GROUP_W for _ in ws] + ws, bs, gs = bk.adjust_block_compatibility(ws, bs, gs) + # Get AnyNet arguments defining the RegNet + return { + "stem_type": cfg.REGNET.STEM_TYPE, + "stem_w": cfg.REGNET.STEM_W, + "block_type": cfg.REGNET.BLOCK_TYPE, + "depths": ds, + "widths": ws, + "strides": ss, + "bot_muls": bs, + "group_ws": gs, + "se_r": cfg.REGNET.SE_R if cfg.REGNET.SE_ON else 0, + "num_classes": cfg.MODEL.NUM_CLASSES, + } + + def __init__(self): + params = RegNet.get_params() + super(RegNet, self).__init__(params) + + @staticmethod + def complexity(cx, params=None): + """Computes model complexity (if you alter the model, make sure to update).""" + params = RegNet.get_params() if not params else params + return AnyNet.complexity(cx, params) diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/resnet.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/resnet.py index 5f3dbdde7b..2a26bbe826 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/resnet.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/pycls/models/resnet.py @@ -1,301 +1,301 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -"""ResNe(X)t models.""" - -from pycls.core.config import cfg -from pycls.models.blocks import ( - activation, - conv2d, - conv2d_cx, - gap2d, - gap2d_cx, - init_weights, - linear, - linear_cx, - norm2d, - norm2d_cx, - pool2d, - pool2d_cx, -) -from torch.nn import Module - - -# Stage depths for ImageNet models -_IN_STAGE_DS = {50: (3, 4, 6, 3), 101: (3, 4, 23, 3), 152: (3, 8, 36, 3)} - - -def get_trans_fun(name): - """Retrieves the transformation function by name.""" - trans_funs = { - "basic_transform": BasicTransform, - "bottleneck_transform": BottleneckTransform, - } - err_str = "Transformation function '{}' not supported" - assert name in trans_funs.keys(), err_str.format(name) - return trans_funs[name] - - -class ResHead(Module): - """ResNet head: AvgPool, 1x1.""" - - def __init__(self, w_in, num_classes): - super(ResHead, self).__init__() - self.avg_pool = gap2d(w_in) - self.fc = linear(w_in, num_classes, bias=True) - - def forward(self, x): - x = self.avg_pool(x) - x = x.view(x.size(0), -1) - x = self.fc(x) - return x - - @staticmethod - def complexity(cx, w_in, num_classes): - cx = gap2d_cx(cx, w_in) - cx = linear_cx(cx, w_in, num_classes, bias=True) - return cx - - -class BasicTransform(Module): - """Basic transformation: 3x3, BN, AF, 3x3, BN.""" - - def __init__(self, w_in, w_out, stride, w_b=None, groups=1): - err_str = "Basic transform does not support w_b and groups options" - assert w_b is None and groups == 1, err_str - super(BasicTransform, self).__init__() - self.a = conv2d(w_in, w_out, 3, stride=stride) - self.a_bn = norm2d(w_out) - self.a_af = activation() - self.b = conv2d(w_out, w_out, 3) - self.b_bn = norm2d(w_out) - self.b_bn.final_bn = True - - def forward(self, x): - for layer in self.children(): - x = layer(x) - return x - - @staticmethod - def complexity(cx, w_in, w_out, stride, w_b=None, groups=1): - err_str = "Basic transform does not support w_b and groups options" - assert w_b is None and groups == 1, err_str - cx = conv2d_cx(cx, w_in, w_out, 3, stride=stride) - cx = norm2d_cx(cx, w_out) - cx = conv2d_cx(cx, w_out, w_out, 3) - cx = norm2d_cx(cx, w_out) - return cx - - -class BottleneckTransform(Module): - """Bottleneck transformation: 1x1, BN, AF, 3x3, BN, AF, 1x1, BN.""" - - def __init__(self, w_in, w_out, stride, w_b, groups): - super(BottleneckTransform, self).__init__() - # MSRA -> stride=2 is on 1x1; TH/C2 -> stride=2 is on 3x3 - (s1, s3) = (stride, 1) if cfg.RESNET.STRIDE_1X1 else (1, stride) - self.a = conv2d(w_in, w_b, 1, stride=s1) - self.a_bn = norm2d(w_b) - self.a_af = activation() - self.b = conv2d(w_b, w_b, 3, stride=s3, groups=groups) - self.b_bn = norm2d(w_b) - self.b_af = activation() - self.c = conv2d(w_b, w_out, 1) - self.c_bn = norm2d(w_out) - self.c_bn.final_bn = True - - def forward(self, x): - for layer in self.children(): - x = layer(x) - return x - - @staticmethod - def complexity(cx, w_in, w_out, stride, w_b, groups): - (s1, s3) = (stride, 1) if cfg.RESNET.STRIDE_1X1 else (1, stride) - cx = conv2d_cx(cx, w_in, w_b, 1, stride=s1) - cx = norm2d_cx(cx, w_b) - cx = conv2d_cx(cx, w_b, w_b, 3, stride=s3, groups=groups) - cx = norm2d_cx(cx, w_b) - cx = conv2d_cx(cx, w_b, w_out, 1) - cx = norm2d_cx(cx, w_out) - return cx - - -class ResBlock(Module): - """Residual block: x + f(x).""" - - def __init__(self, w_in, w_out, stride, trans_fun, w_b=None, groups=1): - super(ResBlock, self).__init__() - self.proj, self.bn = None, None - if (w_in != w_out) or (stride != 1): - self.proj = conv2d(w_in, w_out, 1, stride=stride) - self.bn = norm2d(w_out) - self.f = trans_fun(w_in, w_out, stride, w_b, groups) - self.af = activation() - - def forward(self, x): - x_p = self.bn(self.proj(x)) if self.proj else x - return self.af(x_p + self.f(x)) - - @staticmethod - def complexity(cx, w_in, w_out, stride, trans_fun, w_b, groups): - if (w_in != w_out) or (stride != 1): - h, w = cx["h"], cx["w"] - cx = conv2d_cx(cx, w_in, w_out, 1, stride=stride) - cx = norm2d_cx(cx, w_out) - cx["h"], cx["w"] = h, w - cx = trans_fun.complexity(cx, w_in, w_out, stride, w_b, groups) - return cx - - -class ResStage(Module): - """Stage of ResNet.""" - - def __init__(self, w_in, w_out, stride, d, w_b=None, groups=1): - super(ResStage, self).__init__() - for i in range(d): - b_stride = stride if i == 0 else 1 - b_w_in = w_in if i == 0 else w_out - trans_fun = get_trans_fun(cfg.RESNET.TRANS_FUN) - res_block = ResBlock(b_w_in, w_out, b_stride, trans_fun, w_b, groups) - self.add_module("b{}".format(i + 1), res_block) - - def forward(self, x): - for block in self.children(): - x = block(x) - return x - - @staticmethod - def complexity(cx, w_in, w_out, stride, d, w_b=None, groups=1): - for i in range(d): - b_stride = stride if i == 0 else 1 - b_w_in = w_in if i == 0 else w_out - trans_f = get_trans_fun(cfg.RESNET.TRANS_FUN) - cx = ResBlock.complexity(cx, b_w_in, w_out, b_stride, trans_f, w_b, groups) - return cx - - -class ResStemCifar(Module): - """ResNet stem for CIFAR: 3x3, BN, AF.""" - - def __init__(self, w_in, w_out): - super(ResStemCifar, self).__init__() - self.conv = conv2d(w_in, w_out, 3) - self.bn = norm2d(w_out) - self.af = activation() - - def forward(self, x): - for layer in self.children(): - x = layer(x) - return x - - @staticmethod - def complexity(cx, w_in, w_out): - cx = conv2d_cx(cx, w_in, w_out, 3) - cx = norm2d_cx(cx, w_out) - return cx - - -class ResStemIN(Module): - """ResNet stem for ImageNet: 7x7, BN, AF, MaxPool.""" - - def __init__(self, w_in, w_out): - super(ResStemIN, self).__init__() - self.conv = conv2d(w_in, w_out, 7, stride=2) - self.bn = norm2d(w_out) - self.af = activation() - self.pool = pool2d(w_out, 3, stride=2) - - def forward(self, x): - for layer in self.children(): - x = layer(x) - return x - - @staticmethod - def complexity(cx, w_in, w_out): - cx = conv2d_cx(cx, w_in, w_out, 7, stride=2) - cx = norm2d_cx(cx, w_out) - cx = pool2d_cx(cx, w_out, 3, stride=2) - return cx - - -class ResNet(Module): - """ResNet model.""" - - def __init__(self): - datasets = ["cifar10", "imagenet"] - err_str = "Dataset {} is not supported" - assert cfg.TRAIN.DATASET in datasets, err_str.format(cfg.TRAIN.DATASET) - assert cfg.TEST.DATASET in datasets, err_str.format(cfg.TEST.DATASET) - super(ResNet, self).__init__() - if "cifar" in cfg.TRAIN.DATASET: - self._construct_cifar() - else: - self._construct_imagenet() - self.apply(init_weights) - - def _construct_cifar(self): - err_str = "Model depth should be of the format 6n + 2 for cifar" - assert (cfg.MODEL.DEPTH - 2) % 6 == 0, err_str - d = int((cfg.MODEL.DEPTH - 2) / 6) - self.stem = ResStemCifar(3, 16) - self.s1 = ResStage(16, 16, stride=1, d=d) - self.s2 = ResStage(16, 32, stride=2, d=d) - self.s3 = ResStage(32, 64, stride=2, d=d) - self.head = ResHead(64, cfg.MODEL.NUM_CLASSES) - - def _construct_imagenet(self): - g, gw = cfg.RESNET.NUM_GROUPS, cfg.RESNET.WIDTH_PER_GROUP - (d1, d2, d3, d4) = _IN_STAGE_DS[cfg.MODEL.DEPTH] - w_b = gw * g - self.stem = ResStemIN(3, 64) - self.s1 = ResStage(64, 256, stride=1, d=d1, w_b=w_b, groups=g) - self.s2 = ResStage(256, 512, stride=2, d=d2, w_b=w_b * 2, groups=g) - self.s3 = ResStage(512, 1024, stride=2, d=d3, w_b=w_b * 4, groups=g) - self.s4 = ResStage(1024, 2048, stride=2, d=d4, w_b=w_b * 8, groups=g) - self.head = ResHead(2048, cfg.MODEL.NUM_CLASSES) - - def forward(self, x): - for module in self.children(): - x = module(x) - return x - - @staticmethod - def complexity(cx): - """Computes model complexity. If you alter the model, make sure to update.""" - if "cifar" in cfg.TRAIN.DATASET: - d = int((cfg.MODEL.DEPTH - 2) / 6) - cx = ResStemCifar.complexity(cx, 3, 16) - cx = ResStage.complexity(cx, 16, 16, stride=1, d=d) - cx = ResStage.complexity(cx, 16, 32, stride=2, d=d) - cx = ResStage.complexity(cx, 32, 64, stride=2, d=d) - cx = ResHead.complexity(cx, 64, cfg.MODEL.NUM_CLASSES) - else: - g, gw = cfg.RESNET.NUM_GROUPS, cfg.RESNET.WIDTH_PER_GROUP - (d1, d2, d3, d4) = _IN_STAGE_DS[cfg.MODEL.DEPTH] - w_b = gw * g - cx = ResStemIN.complexity(cx, 3, 64) - cx = ResStage.complexity(cx, 64, 256, 1, d=d1, w_b=w_b, groups=g) - cx = ResStage.complexity(cx, 256, 512, 2, d=d2, w_b=w_b * 2, groups=g) - cx = ResStage.complexity(cx, 512, 1024, 2, d=d3, w_b=w_b * 4, groups=g) - cx = ResStage.complexity(cx, 1024, 2048, 2, d=d4, w_b=w_b * 8, groups=g) - cx = ResHead.complexity(cx, 2048, cfg.MODEL.NUM_CLASSES) - return cx +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +"""ResNe(X)t models.""" + +from pycls.core.config import cfg +from pycls.models.blocks import ( + activation, + conv2d, + conv2d_cx, + gap2d, + gap2d_cx, + init_weights, + linear, + linear_cx, + norm2d, + norm2d_cx, + pool2d, + pool2d_cx, +) +from torch.nn import Module + + +# Stage depths for ImageNet models +_IN_STAGE_DS = {50: (3, 4, 6, 3), 101: (3, 4, 23, 3), 152: (3, 8, 36, 3)} + + +def get_trans_fun(name): + """Retrieves the transformation function by name.""" + trans_funs = { + "basic_transform": BasicTransform, + "bottleneck_transform": BottleneckTransform, + } + err_str = "Transformation function '{}' not supported" + assert name in trans_funs.keys(), err_str.format(name) + return trans_funs[name] + + +class ResHead(Module): + """ResNet head: AvgPool, 1x1.""" + + def __init__(self, w_in, num_classes): + super(ResHead, self).__init__() + self.avg_pool = gap2d(w_in) + self.fc = linear(w_in, num_classes, bias=True) + + def forward(self, x): + x = self.avg_pool(x) + x = x.view(x.size(0), -1) + x = self.fc(x) + return x + + @staticmethod + def complexity(cx, w_in, num_classes): + cx = gap2d_cx(cx, w_in) + cx = linear_cx(cx, w_in, num_classes, bias=True) + return cx + + +class BasicTransform(Module): + """Basic transformation: 3x3, BN, AF, 3x3, BN.""" + + def __init__(self, w_in, w_out, stride, w_b=None, groups=1): + err_str = "Basic transform does not support w_b and groups options" + assert w_b is None and groups == 1, err_str + super(BasicTransform, self).__init__() + self.a = conv2d(w_in, w_out, 3, stride=stride) + self.a_bn = norm2d(w_out) + self.a_af = activation() + self.b = conv2d(w_out, w_out, 3) + self.b_bn = norm2d(w_out) + self.b_bn.final_bn = True + + def forward(self, x): + for layer in self.children(): + x = layer(x) + return x + + @staticmethod + def complexity(cx, w_in, w_out, stride, w_b=None, groups=1): + err_str = "Basic transform does not support w_b and groups options" + assert w_b is None and groups == 1, err_str + cx = conv2d_cx(cx, w_in, w_out, 3, stride=stride) + cx = norm2d_cx(cx, w_out) + cx = conv2d_cx(cx, w_out, w_out, 3) + cx = norm2d_cx(cx, w_out) + return cx + + +class BottleneckTransform(Module): + """Bottleneck transformation: 1x1, BN, AF, 3x3, BN, AF, 1x1, BN.""" + + def __init__(self, w_in, w_out, stride, w_b, groups): + super(BottleneckTransform, self).__init__() + # MSRA -> stride=2 is on 1x1; TH/C2 -> stride=2 is on 3x3 + (s1, s3) = (stride, 1) if cfg.RESNET.STRIDE_1X1 else (1, stride) + self.a = conv2d(w_in, w_b, 1, stride=s1) + self.a_bn = norm2d(w_b) + self.a_af = activation() + self.b = conv2d(w_b, w_b, 3, stride=s3, groups=groups) + self.b_bn = norm2d(w_b) + self.b_af = activation() + self.c = conv2d(w_b, w_out, 1) + self.c_bn = norm2d(w_out) + self.c_bn.final_bn = True + + def forward(self, x): + for layer in self.children(): + x = layer(x) + return x + + @staticmethod + def complexity(cx, w_in, w_out, stride, w_b, groups): + (s1, s3) = (stride, 1) if cfg.RESNET.STRIDE_1X1 else (1, stride) + cx = conv2d_cx(cx, w_in, w_b, 1, stride=s1) + cx = norm2d_cx(cx, w_b) + cx = conv2d_cx(cx, w_b, w_b, 3, stride=s3, groups=groups) + cx = norm2d_cx(cx, w_b) + cx = conv2d_cx(cx, w_b, w_out, 1) + cx = norm2d_cx(cx, w_out) + return cx + + +class ResBlock(Module): + """Residual block: x + f(x).""" + + def __init__(self, w_in, w_out, stride, trans_fun, w_b=None, groups=1): + super(ResBlock, self).__init__() + self.proj, self.bn = None, None + if (w_in != w_out) or (stride != 1): + self.proj = conv2d(w_in, w_out, 1, stride=stride) + self.bn = norm2d(w_out) + self.f = trans_fun(w_in, w_out, stride, w_b, groups) + self.af = activation() + + def forward(self, x): + x_p = self.bn(self.proj(x)) if self.proj else x + return self.af(x_p + self.f(x)) + + @staticmethod + def complexity(cx, w_in, w_out, stride, trans_fun, w_b, groups): + if (w_in != w_out) or (stride != 1): + h, w = cx["h"], cx["w"] + cx = conv2d_cx(cx, w_in, w_out, 1, stride=stride) + cx = norm2d_cx(cx, w_out) + cx["h"], cx["w"] = h, w + cx = trans_fun.complexity(cx, w_in, w_out, stride, w_b, groups) + return cx + + +class ResStage(Module): + """Stage of ResNet.""" + + def __init__(self, w_in, w_out, stride, d, w_b=None, groups=1): + super(ResStage, self).__init__() + for i in range(d): + b_stride = stride if i == 0 else 1 + b_w_in = w_in if i == 0 else w_out + trans_fun = get_trans_fun(cfg.RESNET.TRANS_FUN) + res_block = ResBlock(b_w_in, w_out, b_stride, trans_fun, w_b, groups) + self.add_module("b{}".format(i + 1), res_block) + + def forward(self, x): + for block in self.children(): + x = block(x) + return x + + @staticmethod + def complexity(cx, w_in, w_out, stride, d, w_b=None, groups=1): + for i in range(d): + b_stride = stride if i == 0 else 1 + b_w_in = w_in if i == 0 else w_out + trans_f = get_trans_fun(cfg.RESNET.TRANS_FUN) + cx = ResBlock.complexity(cx, b_w_in, w_out, b_stride, trans_f, w_b, groups) + return cx + + +class ResStemCifar(Module): + """ResNet stem for CIFAR: 3x3, BN, AF.""" + + def __init__(self, w_in, w_out): + super(ResStemCifar, self).__init__() + self.conv = conv2d(w_in, w_out, 3) + self.bn = norm2d(w_out) + self.af = activation() + + def forward(self, x): + for layer in self.children(): + x = layer(x) + return x + + @staticmethod + def complexity(cx, w_in, w_out): + cx = conv2d_cx(cx, w_in, w_out, 3) + cx = norm2d_cx(cx, w_out) + return cx + + +class ResStemIN(Module): + """ResNet stem for ImageNet: 7x7, BN, AF, MaxPool.""" + + def __init__(self, w_in, w_out): + super(ResStemIN, self).__init__() + self.conv = conv2d(w_in, w_out, 7, stride=2) + self.bn = norm2d(w_out) + self.af = activation() + self.pool = pool2d(w_out, 3, stride=2) + + def forward(self, x): + for layer in self.children(): + x = layer(x) + return x + + @staticmethod + def complexity(cx, w_in, w_out): + cx = conv2d_cx(cx, w_in, w_out, 7, stride=2) + cx = norm2d_cx(cx, w_out) + cx = pool2d_cx(cx, w_out, 3, stride=2) + return cx + + +class ResNet(Module): + """ResNet model.""" + + def __init__(self): + datasets = ["cifar10", "imagenet"] + err_str = "Dataset {} is not supported" + assert cfg.TRAIN.DATASET in datasets, err_str.format(cfg.TRAIN.DATASET) + assert cfg.TEST.DATASET in datasets, err_str.format(cfg.TEST.DATASET) + super(ResNet, self).__init__() + if "cifar" in cfg.TRAIN.DATASET: + self._construct_cifar() + else: + self._construct_imagenet() + self.apply(init_weights) + + def _construct_cifar(self): + err_str = "Model depth should be of the format 6n + 2 for cifar" + assert (cfg.MODEL.DEPTH - 2) % 6 == 0, err_str + d = int((cfg.MODEL.DEPTH - 2) / 6) + self.stem = ResStemCifar(3, 16) + self.s1 = ResStage(16, 16, stride=1, d=d) + self.s2 = ResStage(16, 32, stride=2, d=d) + self.s3 = ResStage(32, 64, stride=2, d=d) + self.head = ResHead(64, cfg.MODEL.NUM_CLASSES) + + def _construct_imagenet(self): + g, gw = cfg.RESNET.NUM_GROUPS, cfg.RESNET.WIDTH_PER_GROUP + (d1, d2, d3, d4) = _IN_STAGE_DS[cfg.MODEL.DEPTH] + w_b = gw * g + self.stem = ResStemIN(3, 64) + self.s1 = ResStage(64, 256, stride=1, d=d1, w_b=w_b, groups=g) + self.s2 = ResStage(256, 512, stride=2, d=d2, w_b=w_b * 2, groups=g) + self.s3 = ResStage(512, 1024, stride=2, d=d3, w_b=w_b * 4, groups=g) + self.s4 = ResStage(1024, 2048, stride=2, d=d4, w_b=w_b * 8, groups=g) + self.head = ResHead(2048, cfg.MODEL.NUM_CLASSES) + + def forward(self, x): + for module in self.children(): + x = module(x) + return x + + @staticmethod + def complexity(cx): + """Computes model complexity. If you alter the model, make sure to update.""" + if "cifar" in cfg.TRAIN.DATASET: + d = int((cfg.MODEL.DEPTH - 2) / 6) + cx = ResStemCifar.complexity(cx, 3, 16) + cx = ResStage.complexity(cx, 16, 16, stride=1, d=d) + cx = ResStage.complexity(cx, 16, 32, stride=2, d=d) + cx = ResStage.complexity(cx, 32, 64, stride=2, d=d) + cx = ResHead.complexity(cx, 64, cfg.MODEL.NUM_CLASSES) + else: + g, gw = cfg.RESNET.NUM_GROUPS, cfg.RESNET.WIDTH_PER_GROUP + (d1, d2, d3, d4) = _IN_STAGE_DS[cfg.MODEL.DEPTH] + w_b = gw * g + cx = ResStemIN.complexity(cx, 3, 64) + cx = ResStage.complexity(cx, 64, 256, 1, d=d1, w_b=w_b, groups=g) + cx = ResStage.complexity(cx, 256, 512, 2, d=d2, w_b=w_b * 2, groups=g) + cx = ResStage.complexity(cx, 512, 1024, 2, d=d3, w_b=w_b * 4, groups=g) + cx = ResStage.complexity(cx, 1024, 2048, 2, d=d4, w_b=w_b * 8, groups=g) + cx = ResHead.complexity(cx, 2048, cfg.MODEL.NUM_CLASSES) + return cx diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/tools/test_net.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/tools/test_net.py index 626ee91bf4..c56c75efe7 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/tools/test_net.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/tools/test_net.py @@ -1,40 +1,40 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - - -"""Test a trained classification model.""" -import sys -sys.path.append("./") -import pycls.core.config as config -import pycls.core.distributed as dist -import pycls.core.trainer as trainer -from pycls.core.config import cfg - - -def main(): - config.load_cfg_fom_args("Test a trained classification model.") - config.assert_and_infer_cfg() - cfg.freeze() - dist.multi_proc_run(num_proc=cfg.NUM_GPUS, fun=trainer.test_model) - - -if __name__ == "__main__": - main() +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + + +"""Test a trained classification model.""" +import sys +sys.path.append("./") +import pycls.core.config as config +import pycls.core.distributed as dist +import pycls.core.trainer as trainer +from pycls.core.config import cfg + + +def main(): + config.load_cfg_fom_args("Test a trained classification model.") + config.assert_and_infer_cfg() + cfg.freeze() + dist.multi_proc_run(num_proc=cfg.NUM_GPUS, fun=trainer.test_model) + + +if __name__ == "__main__": + main() diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/tools/time_net.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/tools/time_net.py index ac6495a1db..6ae0388361 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/tools/time_net.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/tools/time_net.py @@ -1,39 +1,39 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - - -"""Compute model and loader timings.""" - -import pycls.core.config as config -import pycls.core.distributed as dist -import pycls.core.trainer as trainer -from pycls.core.config import cfg - - -def main(): - config.load_cfg_fom_args("Compute model and loader timings.") - config.assert_and_infer_cfg() - cfg.freeze() - dist.multi_proc_run(num_proc=cfg.NUM_GPUS, fun=trainer.time_model) - - -if __name__ == "__main__": - main() +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + + +"""Compute model and loader timings.""" + +import pycls.core.config as config +import pycls.core.distributed as dist +import pycls.core.trainer as trainer +from pycls.core.config import cfg + + +def main(): + config.load_cfg_fom_args("Compute model and loader timings.") + config.assert_and_infer_cfg() + cfg.freeze() + dist.multi_proc_run(num_proc=cfg.NUM_GPUS, fun=trainer.time_model) + + +if __name__ == "__main__": + main() diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B1/tools/train_net.py b/PyTorch/contrib/cv/classification/EfficientNet-B1/tools/train_net.py index 58be5ef711..b0277737d8 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B1/tools/train_net.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B1/tools/train_net.py @@ -1,106 +1,106 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - - - -"""Train a classification model.""" -import sys -sys.path.append("./") -import pycls.core.config as config -import pycls.core.distributed as dist -import pycls.core.trainer as trainer -from pycls.core.config import cfg -import argparse,sys,os,torch -import torch - -def init_process_group(proc_rank, world_size, device_type="npu", port="29588"): - """Initializes the default process group.""" - - # Initialize the process group - print("==================================") - print('Begin init_process_group') - os.environ['MASTER_ADDR'] = '127.0.0.1' - os.environ['MASTER_PORT'] = port - if device_type == "npu": - torch.distributed.init_process_group( - backend=cfg.DIST_BACKEND, - world_size=world_size, - rank=proc_rank - ) - elif device_type == "gpu": - torch.distributed.init_process_group( - backend=cfg.DIST_BACKEND, - init_method="tcp://{}:{}".format("127.0.0.1", port), - world_size=world_size, - rank=proc_rank - ) - - print("==================================") - print("Done init_process_group") - - # Set the GPU to use - #torch.cuda.set_device(proc_rank) - if device_type == "npu": - torch.npu.set_device(proc_rank) - elif device_type == "gpu": - torch.cuda.set_device(proc_rank) - print('Done set device', device_type, cfg.DIST_BACKEND, world_size, proc_rank) - -def main(): - """Load config from command line arguments and set any specified options.""" - parser = argparse.ArgumentParser(description="Config file options.") - parser.add_argument("--device", help="gpu or npu", default="npu", type=str) - parser.add_argument("--profperf", help="0 or 1", default=0, type=int) - help_s = "Config file location" - parser.add_argument("--cfg", dest="cfg_file", help=help_s, required=True, type=str) - parser.add_argument("--rank_id", dest="rank_id", default=0, type=int) - parser.add_argument("--device_id", dest="device_id", default=0, type=int) - help_s = "See pycls/core/config.py for all options" - parser.add_argument("opts", help=help_s, default=None, nargs=argparse.REMAINDER) - if len(sys.argv) == 1: - parser.print_help() - sys.exit(1) - args = parser.parse_args() - print(args) - - config.merge_from_file(args.cfg_file) - config._C.merge_from_list(args.opts) - config.assert_and_infer_cfg() - cfg.freeze() - - if cfg.NUM_GPUS > 1: - init_process_group(proc_rank=args.rank_id, world_size=cfg.NUM_GPUS, device_type=args.device) - elif args.device == "npu": - torch.npu.set_device(args.device_id) - elif args.device == "gpu": - torch.cuda.set_device(args.device_id) - - if args.device == "npu": - cur_device = torch.npu.current_device() - elif args.device == "gpu": - cur_device = torch.cuda.current_device() - print('cur_device: ', cur_device) - - trainer.train_model(args.device, args.profperf) - - -if __name__ == "__main__": - main() +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + + + +"""Train a classification model.""" +import sys +sys.path.append("./") +import pycls.core.config as config +import pycls.core.distributed as dist +import pycls.core.trainer as trainer +from pycls.core.config import cfg +import argparse,sys,os,torch +import torch + +def init_process_group(proc_rank, world_size, device_type="npu", port="29588"): + """Initializes the default process group.""" + + # Initialize the process group + print("==================================") + print('Begin init_process_group') + os.environ['MASTER_ADDR'] = '127.0.0.1' + os.environ['MASTER_PORT'] = port + if device_type == "npu": + torch.distributed.init_process_group( + backend=cfg.DIST_BACKEND, + world_size=world_size, + rank=proc_rank + ) + elif device_type == "gpu": + torch.distributed.init_process_group( + backend=cfg.DIST_BACKEND, + init_method="tcp://{}:{}".format("127.0.0.1", port), + world_size=world_size, + rank=proc_rank + ) + + print("==================================") + print("Done init_process_group") + + # Set the GPU to use + #torch.cuda.set_device(proc_rank) + if device_type == "npu": + torch.npu.set_device(proc_rank) + elif device_type == "gpu": + torch.cuda.set_device(proc_rank) + print('Done set device', device_type, cfg.DIST_BACKEND, world_size, proc_rank) + +def main(): + """Load config from command line arguments and set any specified options.""" + parser = argparse.ArgumentParser(description="Config file options.") + parser.add_argument("--device", help="gpu or npu", default="npu", type=str) + parser.add_argument("--profperf", help="0 or 1", default=0, type=int) + help_s = "Config file location" + parser.add_argument("--cfg", dest="cfg_file", help=help_s, required=True, type=str) + parser.add_argument("--rank_id", dest="rank_id", default=0, type=int) + parser.add_argument("--device_id", dest="device_id", default=0, type=int) + help_s = "See pycls/core/config.py for all options" + parser.add_argument("opts", help=help_s, default=None, nargs=argparse.REMAINDER) + if len(sys.argv) == 1: + parser.print_help() + sys.exit(1) + args = parser.parse_args() + print(args) + + config.merge_from_file(args.cfg_file) + config._C.merge_from_list(args.opts) + config.assert_and_infer_cfg() + cfg.freeze() + + if cfg.NUM_GPUS > 1: + init_process_group(proc_rank=args.rank_id, world_size=cfg.NUM_GPUS, device_type=args.device) + elif args.device == "npu": + torch.npu.set_device(args.device_id) + elif args.device == "gpu": + torch.cuda.set_device(args.device_id) + + if args.device == "npu": + cur_device = torch.npu.current_device() + elif args.device == "gpu": + cur_device = torch.cuda.current_device() + print('cur_device: ', cur_device) + + trainer.train_model(args.device, args.profperf) + + +if __name__ == "__main__": + main() diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B3/modelzoo_level.txt b/PyTorch/contrib/cv/classification/EfficientNet-B3/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B3/modelzoo_level.txt +++ b/PyTorch/contrib/cv/classification/EfficientNet-B3/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B5_ID1621_for_PyTorch/modelasrts/config.py b/PyTorch/contrib/cv/classification/EfficientNet-B5_ID1621_for_PyTorch/modelasrts/config.py index 8bef12be1a..5cfeb0d2ae 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B5_ID1621_for_PyTorch/modelasrts/config.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B5_ID1621_for_PyTorch/modelasrts/config.py @@ -1,429 +1,429 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -"""Configuration file (powered by YACS).""" - -import argparse,sys,os,torch -from iopath.common.file_io import g_pathmgr -from pycls.core.io import cache_url -from yacs.config import CfgNode as CfgNode - -# Global config object (example usage: from core.config import cfg) -_C = CfgNode() -cfg = _C - - -# ---------------------------------- Model options ----------------------------------- # -_C.MODEL = CfgNode() - -# Model type -_C.MODEL.TYPE = "" - -# Number of weight layers -_C.MODEL.DEPTH = 0 - -# Number of classes -_C.MODEL.NUM_CLASSES = 10 - -# Loss function (see pycls/models/loss.py for options) -_C.MODEL.LOSS_FUN = "cross_entropy" - -# Activation function (relu or silu/swish) -_C.MODEL.ACTIVATION_FUN = "relu" - -# Perform activation inplace if implemented -_C.MODEL.ACTIVATION_INPLACE = True - - -# ---------------------------------- ResNet options ---------------------------------- # -_C.RESNET = CfgNode() - -# Transformation function (see pycls/models/resnet.py for options) -_C.RESNET.TRANS_FUN = "basic_transform" - -# Number of groups to use (1 -> ResNet; > 1 -> ResNeXt) -_C.RESNET.NUM_GROUPS = 1 - -# Width of each group (64 -> ResNet; 4 -> ResNeXt) -_C.RESNET.WIDTH_PER_GROUP = 64 - -# Apply stride to 1x1 conv (True -> MSRA; False -> fb.torch) -_C.RESNET.STRIDE_1X1 = True - - -# ---------------------------------- AnyNet options ---------------------------------- # -_C.ANYNET = CfgNode() - -# Stem type -_C.ANYNET.STEM_TYPE = "simple_stem_in" - -# Stem width -_C.ANYNET.STEM_W = 32 - -# Block type -_C.ANYNET.BLOCK_TYPE = "res_bottleneck_block" - -# Depth for each stage (number of blocks in the stage) -_C.ANYNET.DEPTHS = [] - -# Width for each stage (width of each block in the stage) -_C.ANYNET.WIDTHS = [] - -# Strides for each stage (applies to the first block of each stage) -_C.ANYNET.STRIDES = [] - -# Bottleneck multipliers for each stage (applies to bottleneck block) -_C.ANYNET.BOT_MULS = [] - -# Group widths for each stage (applies to bottleneck block) -_C.ANYNET.GROUP_WS = [] - -# Whether SE is enabled for res_bottleneck_block -_C.ANYNET.SE_ON = False - -# SE ratio -_C.ANYNET.SE_R = 0.25 - - -# ---------------------------------- RegNet options ---------------------------------- # -_C.REGNET = CfgNode() - -# Stem type -_C.REGNET.STEM_TYPE = "simple_stem_in" - -# Stem width -_C.REGNET.STEM_W = 32 - -# Block type -_C.REGNET.BLOCK_TYPE = "res_bottleneck_block" - -# Stride of each stage -_C.REGNET.STRIDE = 2 - -# Squeeze-and-Excitation (RegNetY) -_C.REGNET.SE_ON = False -_C.REGNET.SE_R = 0.25 - -# Depth -_C.REGNET.DEPTH = 10 - -# Initial width -_C.REGNET.W0 = 32 - -# Slope -_C.REGNET.WA = 5.0 - -# Quantization -_C.REGNET.WM = 2.5 - -# Group width -_C.REGNET.GROUP_W = 16 - -# Bottleneck multiplier (bm = 1 / b from the paper) -_C.REGNET.BOT_MUL = 1.0 - - -# ------------------------------- EfficientNet options ------------------------------- # -_C.EN = CfgNode() - -# Stem width -_C.EN.STEM_W = 32 - -# Depth for each stage (number of blocks in the stage) -_C.EN.DEPTHS = [] - -# Width for each stage (width of each block in the stage) -_C.EN.WIDTHS = [] - -# Expansion ratios for MBConv blocks in each stage -_C.EN.EXP_RATIOS = [] - -# Squeeze-and-Excitation (SE) ratio -_C.EN.SE_R = 0.25 - -# Strides for each stage (applies to the first block of each stage) -_C.EN.STRIDES = [] - -# Kernel sizes for each stage -_C.EN.KERNELS = [] - -# Head width -_C.EN.HEAD_W = 1280 - -# Drop connect ratio -_C.EN.DC_RATIO = 0.0 - -# Dropout ratio -_C.EN.DROPOUT_RATIO = 0.0 - - -# -------------------------------- Batch norm options -------------------------------- # -_C.BN = CfgNode() - -# BN epsilon -_C.BN.EPS = 1e-5 - -# BN momentum (BN momentum in PyTorch = 1 - BN momentum in Caffe2) -_C.BN.MOM = 0.1 - -# Precise BN stats -_C.BN.USE_PRECISE_STATS = True -_C.BN.NUM_SAMPLES_PRECISE = 8192 - -# Initialize the gamma of the final BN of each block to zero -_C.BN.ZERO_INIT_FINAL_GAMMA = False - -# Use a different weight decay for BN layers -_C.BN.USE_CUSTOM_WEIGHT_DECAY = False -_C.BN.CUSTOM_WEIGHT_DECAY = 0.0 - - -# -------------------------------- Optimizer options --------------------------------- # -_C.OPTIM = CfgNode() - -# Learning rate ranges from BASE_LR to MIN_LR*BASE_LR according to the LR_POLICY -_C.OPTIM.BASE_LR = 0.1 -_C.OPTIM.MIN_LR = 0.0 - -# Learning rate policy select from {'cos', 'exp', 'lin', 'steps'} -_C.OPTIM.LR_POLICY = "cos" - -# Steps for 'steps' policy (in epochs) -_C.OPTIM.STEPS = [] - -# Learning rate multiplier for 'steps' policy -_C.OPTIM.LR_MULT = 0.1 - -# Maximal number of epochs -_C.OPTIM.MAX_EPOCH = 200 - -# Momentum -_C.OPTIM.MOMENTUM = 0.9 - -# Momentum dampening -_C.OPTIM.DAMPENING = 0.0 - -# Nesterov momentum -_C.OPTIM.NESTEROV = True - -# L2 regularization -_C.OPTIM.WEIGHT_DECAY = 5e-4 - -# Start the warm up from OPTIM.BASE_LR * OPTIM.WARMUP_FACTOR -_C.OPTIM.WARMUP_FACTOR = 0.1 - -# Gradually warm up the OPTIM.BASE_LR over this number of epochs -_C.OPTIM.WARMUP_EPOCHS = 0 - - -# --------------------------------- Training options --------------------------------- # -_C.TRAIN = CfgNode() - -# Dataset and split -_C.TRAIN.DATASET = "" -_C.TRAIN.SPLIT = "train" - -# Total mini-batch size -_C.TRAIN.BATCH_SIZE = 128 - -# Image size -_C.TRAIN.IM_SIZE = 224 - -# Resume training from the latest checkpoint in the output directory -_C.TRAIN.AUTO_RESUME = True - -# Weights to start training from -_C.TRAIN.WEIGHTS = "" -_C.TRAIN.PRETRAINED = "" - -# If True train using mixed precision -_C.TRAIN.MIXED_PRECISION = False - -# Label smoothing value in 0 to 1 where (0 gives no smoothing) -_C.TRAIN.LABEL_SMOOTHING = 0.0 - -# Batch mixup regularization value in 0 to 1 (0 gives no mixup) -_C.TRAIN.MIXUP_ALPHA = 0.0 - -# Standard deviation for AlexNet-style PCA jitter (0 gives no PCA jitter) -_C.TRAIN.PCA_STD = 0.1 - -# Data augmentation to use ("", "AutoAugment", "RandAugment_N2_M0.5", etc.) -_C.TRAIN.AUGMENT = "" - - -# --------------------------------- Testing options ---------------------------------- # -_C.TEST = CfgNode() - -# Dataset and split -_C.TEST.DATASET = "" -_C.TEST.SPLIT = "val" - -# Total mini-batch size -_C.TEST.BATCH_SIZE = 200 - -# Image size -_C.TEST.IM_SIZE = 256 - -# Weights to use for testing -_C.TEST.WEIGHTS = "" - - -# ------------------------------- Data loader options -------------------------------- # -_C.DATA_LOADER = CfgNode() - -# Number of data loader workers per process -_C.DATA_LOADER.NUM_WORKERS = 8 - -# Load data to pinned host memory -_C.DATA_LOADER.PIN_MEMORY = True - - -# ---------------------------------- CUDNN options ----------------------------------- # -_C.CUDNN = CfgNode() - -# Perform benchmarking to select fastest CUDNN algorithms (best for fixed input sizes) -_C.CUDNN.BENCHMARK = True - - -# ------------------------------- Precise time options ------------------------------- # -_C.PREC_TIME = CfgNode() - -# Number of iterations to warm up the caches -_C.PREC_TIME.WARMUP_ITER = 3 - -# Number of iterations to compute avg time -_C.PREC_TIME.NUM_ITER = 30 - - -# ----------------------------------- Misc options ----------------------------------- # -# Optional description of a config -_C.DESC = "" - -# If True output additional info to log -_C.VERBOSE = True - -# Number of GPUs to use (applies to both training and testing) -_C.NUM_GPUS = 1 - -# Output directory -_C.OUT_DIR = "/tmp" - -# Config destination (in OUT_DIR) -_C.CFG_DEST = "config.yaml" - -# Note that non-determinism is still be present due to non-deterministic GPU ops -_C.RNG_SEED = 1 - -# Log destination ('stdout' or 'file') -_C.LOG_DEST = "stdout" - -# Log period in iters -_C.LOG_PERIOD = 10 - -# Distributed backend -_C.DIST_BACKEND = "hccl" - -# Hostname and port range for multi-process groups (actual port selected randomly) -_C.HOST = "localhost" -_C.PORT_RANGE = [10000, 65000] - -# Models weights referred to by URL are downloaded to this local cache -_C.DOWNLOAD_CACHE = "/tmp/pycls-download-cache" - -# ---------------------------------- Default config ---------------------------------- # -_CFG_DEFAULT = _C.clone() -_CFG_DEFAULT.freeze() - - -# --------------------------------- Deprecated keys ---------------------------------- # -_C.register_deprecated_key("MEM") -_C.register_deprecated_key("MEM.RELU_INPLACE") -_C.register_deprecated_key("OPTIM.GAMMA") -_C.register_deprecated_key("PREC_TIME.BATCH_SIZE") -_C.register_deprecated_key("PREC_TIME.ENABLED") -_C.register_deprecated_key("PORT") -_C.register_deprecated_key("TRAIN.EVAL_PERIOD") -_C.register_deprecated_key("TRAIN.CHECKPOINT_PERIOD") - -# --------------------------------- Model Arts ---------------------------------- # -_C.data_url = "" -_C.train_url = "" - -def assert_and_infer_cfg(cache_urls=True): - """Checks config values invariants.""" - err_str = "The first lr step must start at 0" - assert not _C.OPTIM.STEPS or _C.OPTIM.STEPS[0] == 0, err_str - data_splits = ["train", "val", "test"] - err_str = "Data split '{}' not supported" - assert _C.TRAIN.SPLIT in data_splits, err_str.format(_C.TRAIN.SPLIT) - assert _C.TEST.SPLIT in data_splits, err_str.format(_C.TEST.SPLIT) - err_str = "Mini-batch size should be a multiple of NUM_GPUS." - assert _C.TRAIN.BATCH_SIZE % _C.NUM_GPUS == 0, err_str - assert _C.TEST.BATCH_SIZE % _C.NUM_GPUS == 0, err_str - err_str = "Log destination '{}' not supported" - assert _C.LOG_DEST in ["stdout", "file"], err_str.format(_C.LOG_DEST) - if cache_urls: - cache_cfg_urls() - - -def cache_cfg_urls(): - """Download URLs in config, cache them, and rewrite cfg to use cached file.""" - _C.TRAIN.WEIGHTS = cache_url(_C.TRAIN.WEIGHTS, _C.DOWNLOAD_CACHE) - _C.TEST.WEIGHTS = cache_url(_C.TEST.WEIGHTS, _C.DOWNLOAD_CACHE) - - -def merge_from_file(cfg_file): - with g_pathmgr.open(cfg_file, "r") as f: - cfg = _C.load_cfg(f) - _C.merge_from_other_cfg(cfg) - - -def dump_cfg(): - """Dumps the config to the output directory.""" - cfg_file = os.path.join(_C.OUT_DIR, _C.CFG_DEST) - with g_pathmgr.open(cfg_file, "w") as f: - _C.dump(stream=f) - - -def load_cfg(out_dir, cfg_dest="config.yaml"): - """Loads config from specified output directory.""" - cfg_file = os.path.join(out_dir, cfg_dest) - merge_from_file(cfg_file) - - -def reset_cfg(): - """Reset config to initial state.""" - cfg.merge_from_other_cfg(_CFG_DEFAULT) - - -def load_cfg_fom_args(description="Config file options."): - """Load config from command line arguments and set any specified options.""" - parser = argparse.ArgumentParser(description=description) - help_s = "Config file location" - parser.add_argument("--cfg", dest="cfg_file", help=help_s, required=True, type=str) - help_s = "See pycls/core/config.py for all options" - # modelarts modification - parser.add_argument('--train_url', - default="/cache/training", - type=str, - help="setting dir of training output") - parser.add_argument('--data_url', - metavar='DIR', - default='/cache/data_url', - help='path to dataset') - parser.add_argument('--onnx', default=True, action='store_true', - help="convert pth model to onnx") - parser.add_argument("opts", help=help_s, default=None, nargs=argparse.REMAINDER) - - if len(sys.argv) == 1: - parser.print_help() - sys.exit(1) - args = parser.parse_args() - merge_from_file(args.cfg_file) - _C.merge_from_list(args.opts) - +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +"""Configuration file (powered by YACS).""" + +import argparse,sys,os,torch +from iopath.common.file_io import g_pathmgr +from pycls.core.io import cache_url +from yacs.config import CfgNode as CfgNode + +# Global config object (example usage: from core.config import cfg) +_C = CfgNode() +cfg = _C + + +# ---------------------------------- Model options ----------------------------------- # +_C.MODEL = CfgNode() + +# Model type +_C.MODEL.TYPE = "" + +# Number of weight layers +_C.MODEL.DEPTH = 0 + +# Number of classes +_C.MODEL.NUM_CLASSES = 10 + +# Loss function (see pycls/models/loss.py for options) +_C.MODEL.LOSS_FUN = "cross_entropy" + +# Activation function (relu or silu/swish) +_C.MODEL.ACTIVATION_FUN = "relu" + +# Perform activation inplace if implemented +_C.MODEL.ACTIVATION_INPLACE = True + + +# ---------------------------------- ResNet options ---------------------------------- # +_C.RESNET = CfgNode() + +# Transformation function (see pycls/models/resnet.py for options) +_C.RESNET.TRANS_FUN = "basic_transform" + +# Number of groups to use (1 -> ResNet; > 1 -> ResNeXt) +_C.RESNET.NUM_GROUPS = 1 + +# Width of each group (64 -> ResNet; 4 -> ResNeXt) +_C.RESNET.WIDTH_PER_GROUP = 64 + +# Apply stride to 1x1 conv (True -> MSRA; False -> fb.torch) +_C.RESNET.STRIDE_1X1 = True + + +# ---------------------------------- AnyNet options ---------------------------------- # +_C.ANYNET = CfgNode() + +# Stem type +_C.ANYNET.STEM_TYPE = "simple_stem_in" + +# Stem width +_C.ANYNET.STEM_W = 32 + +# Block type +_C.ANYNET.BLOCK_TYPE = "res_bottleneck_block" + +# Depth for each stage (number of blocks in the stage) +_C.ANYNET.DEPTHS = [] + +# Width for each stage (width of each block in the stage) +_C.ANYNET.WIDTHS = [] + +# Strides for each stage (applies to the first block of each stage) +_C.ANYNET.STRIDES = [] + +# Bottleneck multipliers for each stage (applies to bottleneck block) +_C.ANYNET.BOT_MULS = [] + +# Group widths for each stage (applies to bottleneck block) +_C.ANYNET.GROUP_WS = [] + +# Whether SE is enabled for res_bottleneck_block +_C.ANYNET.SE_ON = False + +# SE ratio +_C.ANYNET.SE_R = 0.25 + + +# ---------------------------------- RegNet options ---------------------------------- # +_C.REGNET = CfgNode() + +# Stem type +_C.REGNET.STEM_TYPE = "simple_stem_in" + +# Stem width +_C.REGNET.STEM_W = 32 + +# Block type +_C.REGNET.BLOCK_TYPE = "res_bottleneck_block" + +# Stride of each stage +_C.REGNET.STRIDE = 2 + +# Squeeze-and-Excitation (RegNetY) +_C.REGNET.SE_ON = False +_C.REGNET.SE_R = 0.25 + +# Depth +_C.REGNET.DEPTH = 10 + +# Initial width +_C.REGNET.W0 = 32 + +# Slope +_C.REGNET.WA = 5.0 + +# Quantization +_C.REGNET.WM = 2.5 + +# Group width +_C.REGNET.GROUP_W = 16 + +# Bottleneck multiplier (bm = 1 / b from the paper) +_C.REGNET.BOT_MUL = 1.0 + + +# ------------------------------- EfficientNet options ------------------------------- # +_C.EN = CfgNode() + +# Stem width +_C.EN.STEM_W = 32 + +# Depth for each stage (number of blocks in the stage) +_C.EN.DEPTHS = [] + +# Width for each stage (width of each block in the stage) +_C.EN.WIDTHS = [] + +# Expansion ratios for MBConv blocks in each stage +_C.EN.EXP_RATIOS = [] + +# Squeeze-and-Excitation (SE) ratio +_C.EN.SE_R = 0.25 + +# Strides for each stage (applies to the first block of each stage) +_C.EN.STRIDES = [] + +# Kernel sizes for each stage +_C.EN.KERNELS = [] + +# Head width +_C.EN.HEAD_W = 1280 + +# Drop connect ratio +_C.EN.DC_RATIO = 0.0 + +# Dropout ratio +_C.EN.DROPOUT_RATIO = 0.0 + + +# -------------------------------- Batch norm options -------------------------------- # +_C.BN = CfgNode() + +# BN epsilon +_C.BN.EPS = 1e-5 + +# BN momentum (BN momentum in PyTorch = 1 - BN momentum in Caffe2) +_C.BN.MOM = 0.1 + +# Precise BN stats +_C.BN.USE_PRECISE_STATS = True +_C.BN.NUM_SAMPLES_PRECISE = 8192 + +# Initialize the gamma of the final BN of each block to zero +_C.BN.ZERO_INIT_FINAL_GAMMA = False + +# Use a different weight decay for BN layers +_C.BN.USE_CUSTOM_WEIGHT_DECAY = False +_C.BN.CUSTOM_WEIGHT_DECAY = 0.0 + + +# -------------------------------- Optimizer options --------------------------------- # +_C.OPTIM = CfgNode() + +# Learning rate ranges from BASE_LR to MIN_LR*BASE_LR according to the LR_POLICY +_C.OPTIM.BASE_LR = 0.1 +_C.OPTIM.MIN_LR = 0.0 + +# Learning rate policy select from {'cos', 'exp', 'lin', 'steps'} +_C.OPTIM.LR_POLICY = "cos" + +# Steps for 'steps' policy (in epochs) +_C.OPTIM.STEPS = [] + +# Learning rate multiplier for 'steps' policy +_C.OPTIM.LR_MULT = 0.1 + +# Maximal number of epochs +_C.OPTIM.MAX_EPOCH = 200 + +# Momentum +_C.OPTIM.MOMENTUM = 0.9 + +# Momentum dampening +_C.OPTIM.DAMPENING = 0.0 + +# Nesterov momentum +_C.OPTIM.NESTEROV = True + +# L2 regularization +_C.OPTIM.WEIGHT_DECAY = 5e-4 + +# Start the warm up from OPTIM.BASE_LR * OPTIM.WARMUP_FACTOR +_C.OPTIM.WARMUP_FACTOR = 0.1 + +# Gradually warm up the OPTIM.BASE_LR over this number of epochs +_C.OPTIM.WARMUP_EPOCHS = 0 + + +# --------------------------------- Training options --------------------------------- # +_C.TRAIN = CfgNode() + +# Dataset and split +_C.TRAIN.DATASET = "" +_C.TRAIN.SPLIT = "train" + +# Total mini-batch size +_C.TRAIN.BATCH_SIZE = 128 + +# Image size +_C.TRAIN.IM_SIZE = 224 + +# Resume training from the latest checkpoint in the output directory +_C.TRAIN.AUTO_RESUME = True + +# Weights to start training from +_C.TRAIN.WEIGHTS = "" +_C.TRAIN.PRETRAINED = "" + +# If True train using mixed precision +_C.TRAIN.MIXED_PRECISION = False + +# Label smoothing value in 0 to 1 where (0 gives no smoothing) +_C.TRAIN.LABEL_SMOOTHING = 0.0 + +# Batch mixup regularization value in 0 to 1 (0 gives no mixup) +_C.TRAIN.MIXUP_ALPHA = 0.0 + +# Standard deviation for AlexNet-style PCA jitter (0 gives no PCA jitter) +_C.TRAIN.PCA_STD = 0.1 + +# Data augmentation to use ("", "AutoAugment", "RandAugment_N2_M0.5", etc.) +_C.TRAIN.AUGMENT = "" + + +# --------------------------------- Testing options ---------------------------------- # +_C.TEST = CfgNode() + +# Dataset and split +_C.TEST.DATASET = "" +_C.TEST.SPLIT = "val" + +# Total mini-batch size +_C.TEST.BATCH_SIZE = 200 + +# Image size +_C.TEST.IM_SIZE = 256 + +# Weights to use for testing +_C.TEST.WEIGHTS = "" + + +# ------------------------------- Data loader options -------------------------------- # +_C.DATA_LOADER = CfgNode() + +# Number of data loader workers per process +_C.DATA_LOADER.NUM_WORKERS = 8 + +# Load data to pinned host memory +_C.DATA_LOADER.PIN_MEMORY = True + + +# ---------------------------------- CUDNN options ----------------------------------- # +_C.CUDNN = CfgNode() + +# Perform benchmarking to select fastest CUDNN algorithms (best for fixed input sizes) +_C.CUDNN.BENCHMARK = True + + +# ------------------------------- Precise time options ------------------------------- # +_C.PREC_TIME = CfgNode() + +# Number of iterations to warm up the caches +_C.PREC_TIME.WARMUP_ITER = 3 + +# Number of iterations to compute avg time +_C.PREC_TIME.NUM_ITER = 30 + + +# ----------------------------------- Misc options ----------------------------------- # +# Optional description of a config +_C.DESC = "" + +# If True output additional info to log +_C.VERBOSE = True + +# Number of GPUs to use (applies to both training and testing) +_C.NUM_GPUS = 1 + +# Output directory +_C.OUT_DIR = "/tmp" + +# Config destination (in OUT_DIR) +_C.CFG_DEST = "config.yaml" + +# Note that non-determinism is still be present due to non-deterministic GPU ops +_C.RNG_SEED = 1 + +# Log destination ('stdout' or 'file') +_C.LOG_DEST = "stdout" + +# Log period in iters +_C.LOG_PERIOD = 10 + +# Distributed backend +_C.DIST_BACKEND = "hccl" + +# Hostname and port range for multi-process groups (actual port selected randomly) +_C.HOST = "localhost" +_C.PORT_RANGE = [10000, 65000] + +# Models weights referred to by URL are downloaded to this local cache +_C.DOWNLOAD_CACHE = "/tmp/pycls-download-cache" + +# ---------------------------------- Default config ---------------------------------- # +_CFG_DEFAULT = _C.clone() +_CFG_DEFAULT.freeze() + + +# --------------------------------- Deprecated keys ---------------------------------- # +_C.register_deprecated_key("MEM") +_C.register_deprecated_key("MEM.RELU_INPLACE") +_C.register_deprecated_key("OPTIM.GAMMA") +_C.register_deprecated_key("PREC_TIME.BATCH_SIZE") +_C.register_deprecated_key("PREC_TIME.ENABLED") +_C.register_deprecated_key("PORT") +_C.register_deprecated_key("TRAIN.EVAL_PERIOD") +_C.register_deprecated_key("TRAIN.CHECKPOINT_PERIOD") + +# --------------------------------- Model Arts ---------------------------------- # +_C.data_url = "" +_C.train_url = "" + +def assert_and_infer_cfg(cache_urls=True): + """Checks config values invariants.""" + err_str = "The first lr step must start at 0" + assert not _C.OPTIM.STEPS or _C.OPTIM.STEPS[0] == 0, err_str + data_splits = ["train", "val", "test"] + err_str = "Data split '{}' not supported" + assert _C.TRAIN.SPLIT in data_splits, err_str.format(_C.TRAIN.SPLIT) + assert _C.TEST.SPLIT in data_splits, err_str.format(_C.TEST.SPLIT) + err_str = "Mini-batch size should be a multiple of NUM_GPUS." + assert _C.TRAIN.BATCH_SIZE % _C.NUM_GPUS == 0, err_str + assert _C.TEST.BATCH_SIZE % _C.NUM_GPUS == 0, err_str + err_str = "Log destination '{}' not supported" + assert _C.LOG_DEST in ["stdout", "file"], err_str.format(_C.LOG_DEST) + if cache_urls: + cache_cfg_urls() + + +def cache_cfg_urls(): + """Download URLs in config, cache them, and rewrite cfg to use cached file.""" + _C.TRAIN.WEIGHTS = cache_url(_C.TRAIN.WEIGHTS, _C.DOWNLOAD_CACHE) + _C.TEST.WEIGHTS = cache_url(_C.TEST.WEIGHTS, _C.DOWNLOAD_CACHE) + + +def merge_from_file(cfg_file): + with g_pathmgr.open(cfg_file, "r") as f: + cfg = _C.load_cfg(f) + _C.merge_from_other_cfg(cfg) + + +def dump_cfg(): + """Dumps the config to the output directory.""" + cfg_file = os.path.join(_C.OUT_DIR, _C.CFG_DEST) + with g_pathmgr.open(cfg_file, "w") as f: + _C.dump(stream=f) + + +def load_cfg(out_dir, cfg_dest="config.yaml"): + """Loads config from specified output directory.""" + cfg_file = os.path.join(out_dir, cfg_dest) + merge_from_file(cfg_file) + + +def reset_cfg(): + """Reset config to initial state.""" + cfg.merge_from_other_cfg(_CFG_DEFAULT) + + +def load_cfg_fom_args(description="Config file options."): + """Load config from command line arguments and set any specified options.""" + parser = argparse.ArgumentParser(description=description) + help_s = "Config file location" + parser.add_argument("--cfg", dest="cfg_file", help=help_s, required=True, type=str) + help_s = "See pycls/core/config.py for all options" + # modelarts modification + parser.add_argument('--train_url', + default="/cache/training", + type=str, + help="setting dir of training output") + parser.add_argument('--data_url', + metavar='DIR', + default='/cache/data_url', + help='path to dataset') + parser.add_argument('--onnx', default=True, action='store_true', + help="convert pth model to onnx") + parser.add_argument("opts", help=help_s, default=None, nargs=argparse.REMAINDER) + + if len(sys.argv) == 1: + parser.print_help() + sys.exit(1) + args = parser.parse_args() + merge_from_file(args.cfg_file) + _C.merge_from_list(args.opts) + diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B5_ID1621_for_PyTorch/modelasrts/loader.py b/PyTorch/contrib/cv/classification/EfficientNet-B5_ID1621_for_PyTorch/modelasrts/loader.py index b94e82d09f..4bf77a6c88 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B5_ID1621_for_PyTorch/modelasrts/loader.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B5_ID1621_for_PyTorch/modelasrts/loader.py @@ -1,98 +1,98 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -"""Data loader.""" - -import os - -import torch -from pycls.core.config import cfg -from pycls.datasets.cifar10 import Cifar10 -from pycls.datasets.imagenet import ImageNet -from torch.utils.data.distributed import DistributedSampler -from torch.utils.data.sampler import RandomSampler - -import argparse -import moxing as mox - -# Supported datasets -_DATASETS = {"cifar10": Cifar10, "imagenet2012": ImageNet} - -# Default data directory (/path/pycls/pycls/datasets/data) -#_DATA_DIR = os.path.join(os.path.dirname(__file__), "data") - -# Relative data paths to default data directory -_PATHS = {"cifar10": "cifar10", "imagenet2012": "imagenet2012"} - -def _construct_loader(args, dataset_name, split, batch_size, shuffle, drop_last): - """Constructs the data loader for the given dataset.""" - err_str = "Dataset '{}' not supported".format(dataset_name) - assert dataset_name in _DATASETS and dataset_name in _PATHS, err_str - # Retrieve the data path for the dataset - #data_path = os.path.join(_DATA_DIR, _PATHS[dataset_name]) - # modelarts modification - real_path = '/cache/data_url' - if not os.path.exists(real_path): - os.makedirs(real_path) - print(args) - mox.file.copy_parallel(args.data_url, real_path) - print("training data finish copy to %s." % real_path) - data_path = os.path.join(real_path, _PATHS[dataset_name]) - print("real_path:",real_path) - print("real_path 子文件:", os.listdir(real_path)) - print("data_path:",data_path) - print("data_path 子文件:", os.listdir(data_path)) - # modelarts modification - # Construct the dataset - dataset = _DATASETS[dataset_name](data_path, split) - # Create a sampler for multi-process training - sampler = DistributedSampler(dataset) if cfg.NUM_GPUS > 1 else None - # Create a loader - loader = torch.utils.data.DataLoader( - dataset, - batch_size=batch_size, - shuffle=(False if sampler else shuffle), - sampler=sampler, - num_workers=cfg.DATA_LOADER.NUM_WORKERS, - pin_memory=cfg.DATA_LOADER.PIN_MEMORY, - drop_last=drop_last, - ) - return loader - - -def construct_train_loader(args): - """Train loader wrapper.""" - return _construct_loader( - args, - dataset_name=cfg.TRAIN.DATASET, - split=cfg.TRAIN.SPLIT, - batch_size=int(cfg.TRAIN.BATCH_SIZE / cfg.NUM_GPUS), - shuffle=True, - drop_last=True, - ) - - -def construct_test_loader(args): - """Test loader wrapper.""" - return _construct_loader( - args, - dataset_name=cfg.TEST.DATASET, - split=cfg.TEST.SPLIT, - batch_size=int(cfg.TEST.BATCH_SIZE / cfg.NUM_GPUS), - shuffle=False, - drop_last=False, - ) - - -def shuffle(loader, cur_epoch): - """"Shuffles the data.""" - err_str = "Sampler type '{}' not supported".format(type(loader.sampler)) - assert isinstance(loader.sampler, (RandomSampler, DistributedSampler)), err_str - # RandomSampler handles shuffling automatically - if isinstance(loader.sampler, DistributedSampler): - # DistributedSampler shuffles data based on epoch - loader.sampler.set_epoch(cur_epoch) +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +"""Data loader.""" + +import os + +import torch +from pycls.core.config import cfg +from pycls.datasets.cifar10 import Cifar10 +from pycls.datasets.imagenet import ImageNet +from torch.utils.data.distributed import DistributedSampler +from torch.utils.data.sampler import RandomSampler + +import argparse +import moxing as mox + +# Supported datasets +_DATASETS = {"cifar10": Cifar10, "imagenet2012": ImageNet} + +# Default data directory (/path/pycls/pycls/datasets/data) +#_DATA_DIR = os.path.join(os.path.dirname(__file__), "data") + +# Relative data paths to default data directory +_PATHS = {"cifar10": "cifar10", "imagenet2012": "imagenet2012"} + +def _construct_loader(args, dataset_name, split, batch_size, shuffle, drop_last): + """Constructs the data loader for the given dataset.""" + err_str = "Dataset '{}' not supported".format(dataset_name) + assert dataset_name in _DATASETS and dataset_name in _PATHS, err_str + # Retrieve the data path for the dataset + #data_path = os.path.join(_DATA_DIR, _PATHS[dataset_name]) + # modelarts modification + real_path = '/cache/data_url' + if not os.path.exists(real_path): + os.makedirs(real_path) + print(args) + mox.file.copy_parallel(args.data_url, real_path) + print("training data finish copy to %s." % real_path) + data_path = os.path.join(real_path, _PATHS[dataset_name]) + print("real_path:",real_path) + print("real_path 子文件:", os.listdir(real_path)) + print("data_path:",data_path) + print("data_path 子文件:", os.listdir(data_path)) + # modelarts modification + # Construct the dataset + dataset = _DATASETS[dataset_name](data_path, split) + # Create a sampler for multi-process training + sampler = DistributedSampler(dataset) if cfg.NUM_GPUS > 1 else None + # Create a loader + loader = torch.utils.data.DataLoader( + dataset, + batch_size=batch_size, + shuffle=(False if sampler else shuffle), + sampler=sampler, + num_workers=cfg.DATA_LOADER.NUM_WORKERS, + pin_memory=cfg.DATA_LOADER.PIN_MEMORY, + drop_last=drop_last, + ) + return loader + + +def construct_train_loader(args): + """Train loader wrapper.""" + return _construct_loader( + args, + dataset_name=cfg.TRAIN.DATASET, + split=cfg.TRAIN.SPLIT, + batch_size=int(cfg.TRAIN.BATCH_SIZE / cfg.NUM_GPUS), + shuffle=True, + drop_last=True, + ) + + +def construct_test_loader(args): + """Test loader wrapper.""" + return _construct_loader( + args, + dataset_name=cfg.TEST.DATASET, + split=cfg.TEST.SPLIT, + batch_size=int(cfg.TEST.BATCH_SIZE / cfg.NUM_GPUS), + shuffle=False, + drop_last=False, + ) + + +def shuffle(loader, cur_epoch): + """"Shuffles the data.""" + err_str = "Sampler type '{}' not supported".format(type(loader.sampler)) + assert isinstance(loader.sampler, (RandomSampler, DistributedSampler)), err_str + # RandomSampler handles shuffling automatically + if isinstance(loader.sampler, DistributedSampler): + # DistributedSampler shuffles data based on epoch + loader.sampler.set_epoch(cur_epoch) diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B5_ID1621_for_PyTorch/modelasrts/train_net.py b/PyTorch/contrib/cv/classification/EfficientNet-B5_ID1621_for_PyTorch/modelasrts/train_net.py index 862b2d3ba8..14485f09e8 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B5_ID1621_for_PyTorch/modelasrts/train_net.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B5_ID1621_for_PyTorch/modelasrts/train_net.py @@ -1,106 +1,106 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -"""Train a classification model.""" -import argparse,sys,os,torch -sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '../')) - -import pycls.core.config as config -import pycls.core.distributed as dist -import pycls.core.trainer as trainer -import pycls.datasets.loader as data_loader - -from pycls.core.config import cfg - -def init_process_group(proc_rank, world_size, device_id, port='29588'): - """Initializes the default process group.""" - - # Initialize the process group - print('Initialize the process group') - os.environ['MASTER_ADDR'] = '127.0.0.1' - os.environ['MASTER_PORT'] = '29588' - torch.distributed.init_process_group( - backend=cfg.DIST_BACKEND, - #init_method="tcp://{}:{}".format(cfg.HOST, port), - world_size=world_size, - rank=proc_rank, - #rank=0 - ) - print("init_process_group done") - - # Set the GPU to use - #torch.cuda.set_device(proc_rank) - torch.npu.set_device(device_id) - print('set_device done.', cfg.DIST_BACKEND, world_size, proc_rank) - -def main(): - config.load_cfg_fom_args("Train a classification model.") - config.assert_and_infer_cfg() - cfg.freeze() - - dist.multi_proc_run(num_proc=cfg.NUM_GPUS, fun=trainer.train_model) - - -if __name__ == "__main__": - """Load config from command line arguments and set any specified options.""" - parser = argparse.ArgumentParser(description="Config file options.") - help_s = "Config file location" - parser.add_argument("--cfg", dest="cfg_file", help=help_s, required=True, type=str) - parser.add_argument("--rank_id", dest="rank_id", default=0, type=int) - parser.add_argument("--device_id", dest="device_id", default=0, type=int) - help_s = "See pycls/core/config.py for all options" - parser.add_argument("opts", help=help_s, default=None, nargs=argparse.REMAINDER) - print("===============1================") - # modelarts modification - parser.add_argument('--data_url', - metavar='DIR', - default='/cache/data_url', - help='path to dataset') - parser.add_argument('--train_url', - default="/cache/training", - type=str, - help="setting dir of training output") - parser.add_argument('--onnx', default=True, action='store_true', - help="convert pth model to onnx") - parser.add_argument('--npu', - default=None, - type=int, - help='NPU id to use.') - print("===============2================") - if len(sys.argv) == 1: - parser.print_help() - sys.exit(1) - args = parser.parse_args() - print(args) - print("args.data_url:",args.data_url) - print('cur dir:', os.listdir('./')) - config.merge_from_file(args.cfg_file) - config._C.merge_from_list(args.opts) - config.assert_and_infer_cfg() - cfg.freeze() - - init_process_group(proc_rank=args.rank_id, world_size=cfg.NUM_GPUS, device_id=args.device_id) - cur_device = torch.npu.current_device() - print('cur_device: ', cur_device) - - trainer.train_model(args) - trainer.convert_pth_to_onnx(args) - +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +"""Train a classification model.""" +import argparse,sys,os,torch +sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '../')) + +import pycls.core.config as config +import pycls.core.distributed as dist +import pycls.core.trainer as trainer +import pycls.datasets.loader as data_loader + +from pycls.core.config import cfg + +def init_process_group(proc_rank, world_size, device_id, port='29588'): + """Initializes the default process group.""" + + # Initialize the process group + print('Initialize the process group') + os.environ['MASTER_ADDR'] = '127.0.0.1' + os.environ['MASTER_PORT'] = '29588' + torch.distributed.init_process_group( + backend=cfg.DIST_BACKEND, + #init_method="tcp://{}:{}".format(cfg.HOST, port), + world_size=world_size, + rank=proc_rank, + #rank=0 + ) + print("init_process_group done") + + # Set the GPU to use + #torch.cuda.set_device(proc_rank) + torch.npu.set_device(device_id) + print('set_device done.', cfg.DIST_BACKEND, world_size, proc_rank) + +def main(): + config.load_cfg_fom_args("Train a classification model.") + config.assert_and_infer_cfg() + cfg.freeze() + + dist.multi_proc_run(num_proc=cfg.NUM_GPUS, fun=trainer.train_model) + + +if __name__ == "__main__": + """Load config from command line arguments and set any specified options.""" + parser = argparse.ArgumentParser(description="Config file options.") + help_s = "Config file location" + parser.add_argument("--cfg", dest="cfg_file", help=help_s, required=True, type=str) + parser.add_argument("--rank_id", dest="rank_id", default=0, type=int) + parser.add_argument("--device_id", dest="device_id", default=0, type=int) + help_s = "See pycls/core/config.py for all options" + parser.add_argument("opts", help=help_s, default=None, nargs=argparse.REMAINDER) + print("===============1================") + # modelarts modification + parser.add_argument('--data_url', + metavar='DIR', + default='/cache/data_url', + help='path to dataset') + parser.add_argument('--train_url', + default="/cache/training", + type=str, + help="setting dir of training output") + parser.add_argument('--onnx', default=True, action='store_true', + help="convert pth model to onnx") + parser.add_argument('--npu', + default=None, + type=int, + help='NPU id to use.') + print("===============2================") + if len(sys.argv) == 1: + parser.print_help() + sys.exit(1) + args = parser.parse_args() + print(args) + print("args.data_url:",args.data_url) + print('cur dir:', os.listdir('./')) + config.merge_from_file(args.cfg_file) + config._C.merge_from_list(args.opts) + config.assert_and_infer_cfg() + cfg.freeze() + + init_process_group(proc_rank=args.rank_id, world_size=cfg.NUM_GPUS, device_id=args.device_id) + cur_device = torch.npu.current_device() + print('cur_device: ', cur_device) + + trainer.train_model(args) + trainer.convert_pth_to_onnx(args) + diff --git a/PyTorch/contrib/cv/classification/EfficientNet-B5_ID1621_for_PyTorch/modelasrts/trainer.py b/PyTorch/contrib/cv/classification/EfficientNet-B5_ID1621_for_PyTorch/modelasrts/trainer.py index 8c838dce87..34c479386e 100644 --- a/PyTorch/contrib/cv/classification/EfficientNet-B5_ID1621_for_PyTorch/modelasrts/trainer.py +++ b/PyTorch/contrib/cv/classification/EfficientNet-B5_ID1621_for_PyTorch/modelasrts/trainer.py @@ -1,306 +1,306 @@ -#!/usr/bin/env python3 - -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -"""Tools for training and testing a model.""" -import numpy as np -import pycls.core.benchmark as benchmark -import pycls.core.builders as builders -import pycls.core.checkpoint as cp -import pycls.core.distributed as dist -import pycls.core.env as env -import pycls.core.logging as logging -import pycls.core.meters as meters -import pycls.core.net as net -import pycls.core.optimizer as optim -import pycls.datasets.loader as data_loader -import torch -import torch.npu - -from pycls.core.net import unwrap_model -import glob -from apex import amp -from pycls.core.config import cfg -from pycls.core.cuda import ApexScaler -import os -import shutil - -import moxing as mox - -import torch.onnx -from collections import OrderedDict -from pycls.models.effnet import EffNet -from iopath.common.file_io import g_pathmgr -import pycls.core.config as config - -logger = logging.get_logger(__name__) - -cur_step = 0 -CACHE_TRAINING_URL = "/cache/training/" -CACHE_DATA_URL = "/cache/data_url" -CACHE_MODEL_URL = "/cache/model" - -def setup_model(): - - """Sets up a model for training or testing and log the results.""" - # Build the model - model = builders.build_model() - logger.info("Model:\n{}".format(model)) if cfg.VERBOSE else () - # Log model complexity - logger.info(logging.dump_log_data(net.complexity(model), "complexity")) - # Transfer the model to the current GPU device - err_str = "Cannot use more GPU devices than available" - #assert cfg.NUM_GPUS <= torch.cuda.device_count(), err_str - assert cfg.NUM_GPUS <= torch.npu.device_count(), err_str - cur_device = torch.npu.current_device() - model = model.to(cur_device) - optimizer = optim.construct_optimizer(model) - model, optimizer = amp.initialize(model, optimizer, opt_level="O2", loss_scale=128) - if cfg.NUM_GPUS > 1: - #Make model replica operate on the current device - ddp = torch.nn.parallel.DistributedDataParallel - model = ddp(model, device_ids=[cur_device], broadcast_buffers=False) - - return model,optimizer - - -def train_epoch(loader, model, loss_fun, optimizer, scaler, meter, cur_epoch): - """Performs one epoch of training.""" - # Shuffle the data - data_loader.shuffle(loader, cur_epoch) - # Update the learning rate - lr = optim.get_epoch_lr(cur_epoch) - optim.set_lr(optimizer, lr) - # Enable training mode - model.train() - meter.reset() - meter.iter_tic() - for cur_iter, (inputs, labels) in enumerate(loader): - # Transfer the data to the current GPU device - inputs = inputs.npu() - labels = labels.to(torch.int32).npu() - labels = labels.to(non_blocking=False) - # Convert labels to smoothed one-hot vector - p_labels = labels[:] - labels_one_hot = net.smooth_one_hot_labels(labels).npu() - # Apply mixup to the batch (no effect if mixup alpha is 0) - inputs, labels_one_hot, labels = net.mixup(inputs, labels_one_hot) - # Perform the forward pass and compute the loss - preds = model(inputs) - loss = loss_fun(preds, labels_one_hot) - # Perform the backward pass and update the parameters - optimizer.zero_grad() - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - optimizer.step() - # Compute the errors - top1_err, top5_err = meters.topk_errors(preds, p_labels, [1, 5]) - # Combine the errors across the GPUs (no reduction if 1 GPU used) - # Combine the stats across the GPUs (no reduction if 1 GPU used) - # loss, top1_err, top5_err = dist.scaled_all_reduce([loss, top1_err, top5_err]) - # Copy the stats from GPU to CPU (sync point) - loss, top1_err, top5_err = loss.item(), top1_err.item(), top5_err.item() - meter.iter_toc() - # Update and log stats - mb_size = inputs.size(0) * cfg.NUM_GPUS - meter.update_stats(top1_err, top5_err, loss, lr, mb_size) - meter.log_iter_stats(cur_epoch, cur_iter) - meter.iter_tic() - # Log epoch stats - meter.log_epoch_stats(cur_epoch) - -@torch.no_grad() -def test_epoch(loader, model, meter, cur_epoch): - """Evaluates the model on the test set.""" - # Enable eval mode - model.eval() - meter.reset() - meter.iter_tic() - for cur_iter, (inputs, labels) in enumerate(loader): - # Transfer the data to the current GPU device - inputs = inputs.npu() - labels = labels.to(torch.int32).npu() - labels = labels.to(non_blocking=False) - # Compute the predictions - preds = model(inputs) - # Compute the errors - top1_err, top5_err = meters.topk_errors(preds, labels, [1, 5]) - # Combine the errors across the GPUs (no reduction if 1 GPU used) - top1_err, top5_err = dist.scaled_all_reduce([top1_err, top5_err]) - # Copy the errors from GPU to CPU (sync point) - top1_err, top5_err = top1_err.item(), top5_err.item() - meter.iter_toc() - # Update and log stats - meter.update_stats(top1_err, top5_err, inputs.size(0) * cfg.NUM_GPUS) - meter.log_iter_stats(cur_epoch, cur_iter) - meter.iter_tic() - # Log epoch stats - meter.log_epoch_stats(cur_epoch) - -def train_model(args): - """Trains the model.""" - # Setup training/testing environment - env.setup_env() - # Construct the model, loss_fun, and optimizer - model,optimizer = setup_model() - loss_fun = builders.build_loss_fun().npu() - # Load checkpoint or initial weights - start_epoch = 0 - if cfg.TRAIN.PRETRAINED: - cp.pretrained_load_checkpoint(cfg.TRAIN.PRETRAINED, model) - logger.info("Loaded pretrained initial weights from: {}".format(cfg.TRAIN.PRETRAINED)) - elif cfg.TRAIN.AUTO_RESUME and cp.has_checkpoint(): - file = cp.get_last_checkpoint() - epoch = cp.load_checkpoint(file, model, optimizer) - logger.info("Loaded checkpoint from: {}".format(file)) - start_epoch = epoch + 1 - elif cfg.TRAIN.WEIGHTS: - #cp.load_checkpoint(cfg.TRAIN.WEIGHTS, model) - CACHE_MODEL_URL = "/cache/model" - os.makedirs(CACHE_MODEL_URL, exist_ok=True) - mox.file.copy_parallel(cfg.TRAIN.WEIGHTS, os.path.join(CACHE_MODEL_URL, "model.pyth")) - pretrained_weight = os.path.join(CACHE_MODEL_URL, "model.pyth") - cp.load_checkpoint(pretrained_weight, model) - logger.info("Loaded initial weights from: {}".format(cfg.TRAIN.WEIGHTS)) - # Create data loaders and meters - train_loader = data_loader.construct_train_loader(args) - test_loader = data_loader.construct_test_loader(args) - # modelarts modification - ''' - real_path = '/cache/data_url' - if not os.path.exists(real_path): - os.makedirs(real_path) - mox.file.copy_parallel(args.data_url, real_path) - print("training data finish copy to %s." % real_path) - train_loader = os.path.join(args.data, 'train') - test_loader = os.path.join(real_path, 'val') - ''' - # modelarts modification - train_meter = meters.TrainMeter(len(train_loader)) - test_meter = meters.TestMeter(len(test_loader)) - # Create a GradScaler for mixed precision training - scaler = ApexScaler() - # Compute model and loader timings - if start_epoch == 0 and cfg.PREC_TIME.NUM_ITER > 0: - benchmark.compute_time_full(model, loss_fun, train_loader, test_loader) - # Perform the training loop - logger.info("Start epoch: {}".format(start_epoch + 1)) - best_err = np.inf - - for cur_epoch in range(start_epoch, cfg.OPTIM.MAX_EPOCH): - # Train for one epoch - params = (train_loader, model, loss_fun, optimizer, scaler, train_meter) - train_epoch(*params, cur_epoch) - # Compute precise BN stats - if cfg.BN.USE_PRECISE_STATS: - net.compute_precise_bn_stats(model, train_loader) - # Evaluate the model - test_epoch(test_loader, model, test_meter, cur_epoch) - # Check if checkpoint is best so far (note: should checkpoint meters as well) - stats = test_meter.get_epoch_stats(cur_epoch) - best = stats["top1_err"] <= best_err - best_err = min(stats["top1_err"], best_err) - # Save a checkpoint - file = cp.save_checkpoint(model, optimizer, cur_epoch, best) - logger.info("Wrote checkpoint to: {}".format(file)) - - # --------------modelarts modification---------- - if args.onnx: - convert_pth_to_onnx(args) - mox.file.copy_parallel(CACHE_TRAINING_URL, args.train_url) - # --------------modelarts modification end---------- - -def test_model(): - """Evaluates a trained model.""" - # Setup training/testing environment - env.setup_env() - # Construct the model - model,optimizer = setup_model() - # Load model weights - cp.load_checkpoint(cfg.TEST.WEIGHTS, model) - logger.info("Loaded model weights from: {}".format(cfg.TEST.WEIGHTS)) - # Create data loaders and meters - test_loader = data_loader.construct_test_loader() - test_meter = meters.TestMeter(len(test_loader)) - # Evaluate the model - test_epoch(test_loader, model, test_meter, 0) - - -def time_model(): - """Times model.""" - # Setup training/testing environment - env.setup_env() - # Construct the model and loss_fun - model = setup_model() - loss_fun = builders.build_loss_fun().npu() - # Compute model and loader timings - benchmark.compute_time_model(model, loss_fun) - - -def time_model_and_loader(): - """Times model and data loader.""" - # Setup training/testing environment - env.setup_env() - # Construct the model and loss_fun - model = setup_model() - loss_fun = builders.build_loss_fun().npu() - # Create data loaders - train_loader = data_loader.construct_train_loader() - test_loader = data_loader.construct_test_loader() - # Compute model and loader timings - benchmark.compute_time_full(model, loss_fun, train_loader, test_loader) - -def convert_pth_to_onnx(args): - os.makedirs(CACHE_TRAINING_URL, exist_ok=True) - shutil.copy(os.path.join(cfg.OUT_DIR, 'model.pyth'), CACHE_TRAINING_URL) - pth_pattern = os.path.join(CACHE_TRAINING_URL, 'model.pyth') - pth_file_list = glob.glob(pth_pattern) - if not pth_file_list: - print("can't find pth {pth_pattern}") - pth_file = pth_file_list[0] - onnx_path = pth_file.split(".")[0] + '.onnx' - convert(pth_file, onnx_path) - -def proc_node_module(checkpoint, attr_name): - new_model_state = OrderedDict() - for k, v in checkpoint[attr_name].items(): - if(k[0: 7] == "module."): - name = k[7:] - else: - name = k[0:] - new_model_state[name] = v - return new_model_state - -def convert(pth_file_path, onnx_file_path): - """Sets up a model for training or testing and log the results.""" - loc = 'cpu' - with g_pathmgr.open(pth_file_path, "rb") as f: - checkpoint = torch.load(f, map_location=loc) - cfg_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../configs/dds_baselines/effnet/EN-B5_dds_1npu_full.yaml") - config.merge_from_file(cfg_file) - cfg.freeze() - model = EffNet().to(loc) - checkpoint['model_state'] = proc_node_module(checkpoint, 'model_state') - model.load_state_dict(checkpoint["model_state"], False) - model = model.to(loc) - input_names = ["actual_input_1"] - output_names = ["output1"] - dummy_input = torch.randn(1, 3, 456, 456).to(loc) +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +"""Tools for training and testing a model.""" +import numpy as np +import pycls.core.benchmark as benchmark +import pycls.core.builders as builders +import pycls.core.checkpoint as cp +import pycls.core.distributed as dist +import pycls.core.env as env +import pycls.core.logging as logging +import pycls.core.meters as meters +import pycls.core.net as net +import pycls.core.optimizer as optim +import pycls.datasets.loader as data_loader +import torch +import torch.npu + +from pycls.core.net import unwrap_model +import glob +from apex import amp +from pycls.core.config import cfg +from pycls.core.cuda import ApexScaler +import os +import shutil + +import moxing as mox + +import torch.onnx +from collections import OrderedDict +from pycls.models.effnet import EffNet +from iopath.common.file_io import g_pathmgr +import pycls.core.config as config + +logger = logging.get_logger(__name__) + +cur_step = 0 +CACHE_TRAINING_URL = "/cache/training/" +CACHE_DATA_URL = "/cache/data_url" +CACHE_MODEL_URL = "/cache/model" + +def setup_model(): + + """Sets up a model for training or testing and log the results.""" + # Build the model + model = builders.build_model() + logger.info("Model:\n{}".format(model)) if cfg.VERBOSE else () + # Log model complexity + logger.info(logging.dump_log_data(net.complexity(model), "complexity")) + # Transfer the model to the current GPU device + err_str = "Cannot use more GPU devices than available" + #assert cfg.NUM_GPUS <= torch.cuda.device_count(), err_str + assert cfg.NUM_GPUS <= torch.npu.device_count(), err_str + cur_device = torch.npu.current_device() + model = model.to(cur_device) + optimizer = optim.construct_optimizer(model) + model, optimizer = amp.initialize(model, optimizer, opt_level="O2", loss_scale=128) + if cfg.NUM_GPUS > 1: + #Make model replica operate on the current device + ddp = torch.nn.parallel.DistributedDataParallel + model = ddp(model, device_ids=[cur_device], broadcast_buffers=False) + + return model,optimizer + + +def train_epoch(loader, model, loss_fun, optimizer, scaler, meter, cur_epoch): + """Performs one epoch of training.""" + # Shuffle the data + data_loader.shuffle(loader, cur_epoch) + # Update the learning rate + lr = optim.get_epoch_lr(cur_epoch) + optim.set_lr(optimizer, lr) + # Enable training mode + model.train() + meter.reset() + meter.iter_tic() + for cur_iter, (inputs, labels) in enumerate(loader): + # Transfer the data to the current GPU device + inputs = inputs.npu() + labels = labels.to(torch.int32).npu() + labels = labels.to(non_blocking=False) + # Convert labels to smoothed one-hot vector + p_labels = labels[:] + labels_one_hot = net.smooth_one_hot_labels(labels).npu() + # Apply mixup to the batch (no effect if mixup alpha is 0) + inputs, labels_one_hot, labels = net.mixup(inputs, labels_one_hot) + # Perform the forward pass and compute the loss + preds = model(inputs) + loss = loss_fun(preds, labels_one_hot) + # Perform the backward pass and update the parameters + optimizer.zero_grad() + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + optimizer.step() + # Compute the errors + top1_err, top5_err = meters.topk_errors(preds, p_labels, [1, 5]) + # Combine the errors across the GPUs (no reduction if 1 GPU used) + # Combine the stats across the GPUs (no reduction if 1 GPU used) + # loss, top1_err, top5_err = dist.scaled_all_reduce([loss, top1_err, top5_err]) + # Copy the stats from GPU to CPU (sync point) + loss, top1_err, top5_err = loss.item(), top1_err.item(), top5_err.item() + meter.iter_toc() + # Update and log stats + mb_size = inputs.size(0) * cfg.NUM_GPUS + meter.update_stats(top1_err, top5_err, loss, lr, mb_size) + meter.log_iter_stats(cur_epoch, cur_iter) + meter.iter_tic() + # Log epoch stats + meter.log_epoch_stats(cur_epoch) + +@torch.no_grad() +def test_epoch(loader, model, meter, cur_epoch): + """Evaluates the model on the test set.""" + # Enable eval mode + model.eval() + meter.reset() + meter.iter_tic() + for cur_iter, (inputs, labels) in enumerate(loader): + # Transfer the data to the current GPU device + inputs = inputs.npu() + labels = labels.to(torch.int32).npu() + labels = labels.to(non_blocking=False) + # Compute the predictions + preds = model(inputs) + # Compute the errors + top1_err, top5_err = meters.topk_errors(preds, labels, [1, 5]) + # Combine the errors across the GPUs (no reduction if 1 GPU used) + top1_err, top5_err = dist.scaled_all_reduce([top1_err, top5_err]) + # Copy the errors from GPU to CPU (sync point) + top1_err, top5_err = top1_err.item(), top5_err.item() + meter.iter_toc() + # Update and log stats + meter.update_stats(top1_err, top5_err, inputs.size(0) * cfg.NUM_GPUS) + meter.log_iter_stats(cur_epoch, cur_iter) + meter.iter_tic() + # Log epoch stats + meter.log_epoch_stats(cur_epoch) + +def train_model(args): + """Trains the model.""" + # Setup training/testing environment + env.setup_env() + # Construct the model, loss_fun, and optimizer + model,optimizer = setup_model() + loss_fun = builders.build_loss_fun().npu() + # Load checkpoint or initial weights + start_epoch = 0 + if cfg.TRAIN.PRETRAINED: + cp.pretrained_load_checkpoint(cfg.TRAIN.PRETRAINED, model) + logger.info("Loaded pretrained initial weights from: {}".format(cfg.TRAIN.PRETRAINED)) + elif cfg.TRAIN.AUTO_RESUME and cp.has_checkpoint(): + file = cp.get_last_checkpoint() + epoch = cp.load_checkpoint(file, model, optimizer) + logger.info("Loaded checkpoint from: {}".format(file)) + start_epoch = epoch + 1 + elif cfg.TRAIN.WEIGHTS: + #cp.load_checkpoint(cfg.TRAIN.WEIGHTS, model) + CACHE_MODEL_URL = "/cache/model" + os.makedirs(CACHE_MODEL_URL, exist_ok=True) + mox.file.copy_parallel(cfg.TRAIN.WEIGHTS, os.path.join(CACHE_MODEL_URL, "model.pyth")) + pretrained_weight = os.path.join(CACHE_MODEL_URL, "model.pyth") + cp.load_checkpoint(pretrained_weight, model) + logger.info("Loaded initial weights from: {}".format(cfg.TRAIN.WEIGHTS)) + # Create data loaders and meters + train_loader = data_loader.construct_train_loader(args) + test_loader = data_loader.construct_test_loader(args) + # modelarts modification + ''' + real_path = '/cache/data_url' + if not os.path.exists(real_path): + os.makedirs(real_path) + mox.file.copy_parallel(args.data_url, real_path) + print("training data finish copy to %s." % real_path) + train_loader = os.path.join(args.data, 'train') + test_loader = os.path.join(real_path, 'val') + ''' + # modelarts modification + train_meter = meters.TrainMeter(len(train_loader)) + test_meter = meters.TestMeter(len(test_loader)) + # Create a GradScaler for mixed precision training + scaler = ApexScaler() + # Compute model and loader timings + if start_epoch == 0 and cfg.PREC_TIME.NUM_ITER > 0: + benchmark.compute_time_full(model, loss_fun, train_loader, test_loader) + # Perform the training loop + logger.info("Start epoch: {}".format(start_epoch + 1)) + best_err = np.inf + + for cur_epoch in range(start_epoch, cfg.OPTIM.MAX_EPOCH): + # Train for one epoch + params = (train_loader, model, loss_fun, optimizer, scaler, train_meter) + train_epoch(*params, cur_epoch) + # Compute precise BN stats + if cfg.BN.USE_PRECISE_STATS: + net.compute_precise_bn_stats(model, train_loader) + # Evaluate the model + test_epoch(test_loader, model, test_meter, cur_epoch) + # Check if checkpoint is best so far (note: should checkpoint meters as well) + stats = test_meter.get_epoch_stats(cur_epoch) + best = stats["top1_err"] <= best_err + best_err = min(stats["top1_err"], best_err) + # Save a checkpoint + file = cp.save_checkpoint(model, optimizer, cur_epoch, best) + logger.info("Wrote checkpoint to: {}".format(file)) + + # --------------modelarts modification---------- + if args.onnx: + convert_pth_to_onnx(args) + mox.file.copy_parallel(CACHE_TRAINING_URL, args.train_url) + # --------------modelarts modification end---------- + +def test_model(): + """Evaluates a trained model.""" + # Setup training/testing environment + env.setup_env() + # Construct the model + model,optimizer = setup_model() + # Load model weights + cp.load_checkpoint(cfg.TEST.WEIGHTS, model) + logger.info("Loaded model weights from: {}".format(cfg.TEST.WEIGHTS)) + # Create data loaders and meters + test_loader = data_loader.construct_test_loader() + test_meter = meters.TestMeter(len(test_loader)) + # Evaluate the model + test_epoch(test_loader, model, test_meter, 0) + + +def time_model(): + """Times model.""" + # Setup training/testing environment + env.setup_env() + # Construct the model and loss_fun + model = setup_model() + loss_fun = builders.build_loss_fun().npu() + # Compute model and loader timings + benchmark.compute_time_model(model, loss_fun) + + +def time_model_and_loader(): + """Times model and data loader.""" + # Setup training/testing environment + env.setup_env() + # Construct the model and loss_fun + model = setup_model() + loss_fun = builders.build_loss_fun().npu() + # Create data loaders + train_loader = data_loader.construct_train_loader() + test_loader = data_loader.construct_test_loader() + # Compute model and loader timings + benchmark.compute_time_full(model, loss_fun, train_loader, test_loader) + +def convert_pth_to_onnx(args): + os.makedirs(CACHE_TRAINING_URL, exist_ok=True) + shutil.copy(os.path.join(cfg.OUT_DIR, 'model.pyth'), CACHE_TRAINING_URL) + pth_pattern = os.path.join(CACHE_TRAINING_URL, 'model.pyth') + pth_file_list = glob.glob(pth_pattern) + if not pth_file_list: + print("can't find pth {pth_pattern}") + pth_file = pth_file_list[0] + onnx_path = pth_file.split(".")[0] + '.onnx' + convert(pth_file, onnx_path) + +def proc_node_module(checkpoint, attr_name): + new_model_state = OrderedDict() + for k, v in checkpoint[attr_name].items(): + if(k[0: 7] == "module."): + name = k[7:] + else: + name = k[0:] + new_model_state[name] = v + return new_model_state + +def convert(pth_file_path, onnx_file_path): + """Sets up a model for training or testing and log the results.""" + loc = 'cpu' + with g_pathmgr.open(pth_file_path, "rb") as f: + checkpoint = torch.load(f, map_location=loc) + cfg_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../configs/dds_baselines/effnet/EN-B5_dds_1npu_full.yaml") + config.merge_from_file(cfg_file) + cfg.freeze() + model = EffNet().to(loc) + checkpoint['model_state'] = proc_node_module(checkpoint, 'model_state') + model.load_state_dict(checkpoint["model_state"], False) + model = model.to(loc) + input_names = ["actual_input_1"] + output_names = ["output1"] + dummy_input = torch.randn(1, 3, 456, 456).to(loc) torch.onnx.export(model, dummy_input, onnx_file_path, input_names = input_names, output_names = output_names, opset_version=11) \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/GENet_for_Pytorch/LICENSE b/PyTorch/contrib/cv/classification/GENet_for_Pytorch/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/PyTorch/contrib/cv/classification/GENet_for_Pytorch/LICENSE +++ b/PyTorch/contrib/cv/classification/GENet_for_Pytorch/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/GENet_for_Pytorch/README.md b/PyTorch/contrib/cv/classification/GENet_for_Pytorch/README.md index 3a09b50b40..05e2f31ba9 100644 --- a/PyTorch/contrib/cv/classification/GENet_for_Pytorch/README.md +++ b/PyTorch/contrib/cv/classification/GENet_for_Pytorch/README.md @@ -1,59 +1,59 @@ -# GENet - -This implements training of GENET on the cifar10 dataset, mainly modified from [pytorch/examples](https://github.com/BayesWatch/pytorch-GENet). - -## GENet Details - -The configuration process and operation method of GENet are described in detail below. - -## SoftWare Package -CANN 5.0.2 - -## Requirements - -- Install PyTorch ([pytorch.org](http://pytorch.org)) -- `pip install -r requirements.txt` -- Download the cifar10 dataset by referring the original [repository](https://github.com/BayesWatch/pytorch-GENet) - - You can also without downloading them in advance. The cifar10 interface provided by torchvision will automatically download them for you. - -## Training - -To train a model, run `train.py` with the desired model architecture and the path to the cifar10 dataset. -Note: assuming that your dataset path is:**/opt/gpu/cifar10-batches-py/**, the real_data_path should be **/opt/gpu/** - -```bash -# training 1p accuracy -bash ./test/train_full_1p.sh --data_path=real_data_path - -# training 1p performance -bash ./test/train_performance_1p.sh --data_path=real_data_path - -# training 1p with pretrained model -bash ./test/train_finetune_1p.sh --data_path=real_data_path - -# training 8p accuracy -bash ./test/train_full_8p.sh --data_path=real_data_path - -# training 8p performance -bash ./test/train_performance_8p.sh --data_path=real_data_path - -# evaluating 8p performance -bash ./test/train_eval_8p.sh --data_path=real_data_path -``` -### Remarks: -All bash instructions output log files correctly. - -### Log path: -**training detail log:** - test/output/devie_id/train_${device_id}.log -**8p training performance result log:** test/output/devie_id/GENet_bs128_8p_perf.log -**8p training accuracy result log :** test/output/devie_id/GENet_bs128_8p_acc.log - -## GENET training result - -| Acc@1 | FPS | Device Type| Device Nums | Epochs | AMP_Type | -| :------: | :------: | :------: | :------: | :------: |:------: -| 94.73 | 1894.827 | NPU | 1 | 300 | O2 | -| 95.23 | 7858.025 |NPU |8 | 300 | O2 | -| 94.76 | 1350.074 |GPU |1 | 300 | O2 | +# GENet + +This implements training of GENET on the cifar10 dataset, mainly modified from [pytorch/examples](https://github.com/BayesWatch/pytorch-GENet). + +## GENet Details + +The configuration process and operation method of GENet are described in detail below. + +## SoftWare Package +CANN 5.0.2 + +## Requirements + +- Install PyTorch ([pytorch.org](http://pytorch.org)) +- `pip install -r requirements.txt` +- Download the cifar10 dataset by referring the original [repository](https://github.com/BayesWatch/pytorch-GENet) + - You can also without downloading them in advance. The cifar10 interface provided by torchvision will automatically download them for you. + +## Training + +To train a model, run `train.py` with the desired model architecture and the path to the cifar10 dataset. +Note: assuming that your dataset path is:**/opt/gpu/cifar10-batches-py/**, the real_data_path should be **/opt/gpu/** + +```bash +# training 1p accuracy +bash ./test/train_full_1p.sh --data_path=real_data_path + +# training 1p performance +bash ./test/train_performance_1p.sh --data_path=real_data_path + +# training 1p with pretrained model +bash ./test/train_finetune_1p.sh --data_path=real_data_path + +# training 8p accuracy +bash ./test/train_full_8p.sh --data_path=real_data_path + +# training 8p performance +bash ./test/train_performance_8p.sh --data_path=real_data_path + +# evaluating 8p performance +bash ./test/train_eval_8p.sh --data_path=real_data_path +``` +### Remarks: +All bash instructions output log files correctly. + +### Log path: +**training detail log:** + test/output/devie_id/train_${device_id}.log +**8p training performance result log:** test/output/devie_id/GENet_bs128_8p_perf.log +**8p training accuracy result log :** test/output/devie_id/GENet_bs128_8p_acc.log + +## GENET training result + +| Acc@1 | FPS | Device Type| Device Nums | Epochs | AMP_Type | +| :------: | :------: | :------: | :------: | :------: |:------: +| 94.73 | 1894.827 | NPU | 1 | 300 | O2 | +| 95.23 | 7858.025 |NPU |8 | 300 | O2 | +| 94.76 | 1350.074 |GPU |1 | 300 | O2 | | 94.81 | 6536.289 |GPU |8 | 300 | O2 | \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/GENet_for_Pytorch/modelzoo_level.txt b/PyTorch/contrib/cv/classification/GENet_for_Pytorch/modelzoo_level.txt index 19bb24fce3..24cbc51bb9 100644 --- a/PyTorch/contrib/cv/classification/GENet_for_Pytorch/modelzoo_level.txt +++ b/PyTorch/contrib/cv/classification/GENet_for_Pytorch/modelzoo_level.txt @@ -1,6 +1,6 @@ -GPUStatus:OK -NPUMigrationStatus:OK -FuncStatus:OK -PrecisionStatus:POK -AutoTune:OK -PerfStatus:OK +GPUStatus:OK +NPUMigrationStatus:OK +FuncStatus:OK +PrecisionStatus:POK +AutoTune:OK +PerfStatus:OK diff --git a/PyTorch/contrib/cv/classification/GhostNet/LICENSE b/PyTorch/contrib/cv/classification/GhostNet/LICENSE index 4ba4fdcab3..a0e0310359 100644 --- a/PyTorch/contrib/cv/classification/GhostNet/LICENSE +++ b/PyTorch/contrib/cv/classification/GhostNet/LICENSE @@ -1,29 +1,29 @@ -BSD 3-Clause License - -Copyright (c) 2017, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +BSD 3-Clause License + +Copyright (c) 2017, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/GhostNet/ghostnet/ghostnet_pytorch/ghostnet.py b/PyTorch/contrib/cv/classification/GhostNet/ghostnet/ghostnet_pytorch/ghostnet.py index eaedf42a5a..887f6318e6 100644 --- a/PyTorch/contrib/cv/classification/GhostNet/ghostnet/ghostnet_pytorch/ghostnet.py +++ b/PyTorch/contrib/cv/classification/GhostNet/ghostnet/ghostnet_pytorch/ghostnet.py @@ -1,260 +1,260 @@ -# 2020.06.09-Changed for building GhostNet -# Huawei Technologies Co., Ltd. -""" -Creates a GhostNet Model as defined in: -GhostNet: More Features from Cheap Operations By Kai Han, Yunhe Wang, Qi Tian, Jianyuan Guo, Chunjing Xu, Chang Xu. -https://arxiv.org/abs/1911.11907 -Modified from https://github.com/d-li14/mobilenetv3.pytorch and https://github.com/rwightman/pytorch-image-models -""" -import torch -import torch.nn as nn -import torch.nn.functional as F -import math - - -__all__ = ['ghost_net'] - - -def _make_divisible(v, divisor, min_value=None): - """ - This function is taken from the original tf repo. - It ensures that all layers have a channel number that is divisible by 8 - It can be seen here: - https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py - """ - if min_value is None: - min_value = divisor - new_v = max(min_value, int(v + divisor / 2) // divisor * divisor) - # Make sure that round down does not go down by more than 10%. - if new_v < 0.9 * v: - new_v += divisor - return new_v - - -def hard_sigmoid(x, inplace: bool = False): - if inplace: - return x.add_(3.).clamp_(0., 6.).div_(6.) - else: - return F.relu6(x + 3.) / 6. - - -class SqueezeExcite(nn.Module): - def __init__(self, in_chs, se_ratio=0.25, reduced_base_chs=None, - act_layer=nn.ReLU, gate_fn=hard_sigmoid, divisor=4, **_): - super(SqueezeExcite, self).__init__() - self.gate_fn = gate_fn - reduced_chs = _make_divisible((reduced_base_chs or in_chs) * se_ratio, divisor) - self.avg_pool = nn.AdaptiveAvgPool2d(1) - self.conv_reduce = nn.Conv2d(in_chs, reduced_chs, 1, bias=True) - self.act1 = act_layer(inplace=True) - self.conv_expand = nn.Conv2d(reduced_chs, in_chs, 1, bias=True) - - def forward(self, x): - x_se = self.avg_pool(x) - x_se = self.conv_reduce(x_se) - x_se = self.act1(x_se) - x_se = self.conv_expand(x_se) - x = x * self.gate_fn(x_se) - return x - - -class ConvBnAct(nn.Module): - def __init__(self, in_chs, out_chs, kernel_size, - stride=1, act_layer=nn.ReLU): - super(ConvBnAct, self).__init__() - self.conv = nn.Conv2d(in_chs, out_chs, kernel_size, stride, kernel_size//2, bias=False) - self.bn1 = nn.BatchNorm2d(out_chs) - self.act1 = act_layer(inplace=True) - - def forward(self, x): - x = self.conv(x) - x = self.bn1(x) - x = self.act1(x) - return x - - -class GhostModule(nn.Module): - def __init__(self, inp, oup, kernel_size=1, ratio=2, dw_size=3, stride=1, relu=True): - super(GhostModule, self).__init__() - self.oup = oup - init_channels = math.ceil(oup / ratio) - new_channels = init_channels*(ratio-1) - - self.primary_conv = nn.Sequential( - nn.Conv2d(inp, init_channels, kernel_size, stride, kernel_size//2, bias=False), - nn.BatchNorm2d(init_channels), - nn.ReLU(inplace=True) if relu else nn.Sequential(), - ) - - self.cheap_operation = nn.Sequential( - nn.Conv2d(init_channels, new_channels, dw_size, 1, dw_size//2, groups=init_channels, bias=False), - nn.BatchNorm2d(new_channels), - nn.ReLU(inplace=True) if relu else nn.Sequential(), - ) - - def forward(self, x): - x1 = self.primary_conv(x) - x2 = self.cheap_operation(x1) - out = torch.cat([x1,x2], dim=1) - # For avoiding OOM, refine raw code now: return out[:,:self.oup,:,:] - return out - - -class GhostBottleneck(nn.Module): - """ Ghost bottleneck w/ optional SE""" - - def __init__(self, in_chs, mid_chs, out_chs, dw_kernel_size=3, - stride=1, act_layer=nn.ReLU, se_ratio=0.): - super(GhostBottleneck, self).__init__() - has_se = se_ratio is not None and se_ratio > 0. - self.stride = stride - - # Point-wise expansion - self.ghost1 = GhostModule(in_chs, mid_chs, relu=True) - - # Depth-wise convolution - if self.stride > 1: - self.conv_dw = nn.Conv2d(mid_chs, mid_chs, dw_kernel_size, stride=stride, - padding=(dw_kernel_size-1)//2, - groups=mid_chs, bias=False) - self.bn_dw = nn.BatchNorm2d(mid_chs) - - # Squeeze-and-excitation - if has_se: - self.se = SqueezeExcite(mid_chs, se_ratio=se_ratio) - else: - self.se = None - - # Point-wise linear projection - self.ghost2 = GhostModule(mid_chs, out_chs, relu=False) - - # shortcut - if (in_chs == out_chs and self.stride == 1): - self.shortcut = nn.Sequential() - else: - self.shortcut = nn.Sequential( - nn.Conv2d(in_chs, in_chs, dw_kernel_size, stride=stride, - padding=(dw_kernel_size-1)//2, groups=in_chs, bias=False), - nn.BatchNorm2d(in_chs), - nn.Conv2d(in_chs, out_chs, 1, stride=1, padding=0, bias=False), - nn.BatchNorm2d(out_chs), - ) - - - def forward(self, x): - residual = x - - # 1st ghost bottleneck - x = self.ghost1(x) - - # Depth-wise convolution - if self.stride > 1: - x = self.conv_dw(x) - x = self.bn_dw(x) - - # Squeeze-and-excitation - if self.se is not None: - x = self.se(x) - - # 2nd ghost bottleneck - x = self.ghost2(x) - - x += self.shortcut(residual) - return x - - -class GhostNet(nn.Module): - def __init__(self, cfgs, num_classes=1000, width=1.0, dropout=0.2): - super(GhostNet, self).__init__() - # setting of inverted residual blocks - self.cfgs = cfgs - self.dropout = dropout - - # building first layer - output_channel = _make_divisible(16 * width, 4) - self.conv_stem = nn.Conv2d(3, output_channel, 3, 2, 1, bias=False) - self.bn1 = nn.BatchNorm2d(output_channel) - self.act1 = nn.ReLU(inplace=True) - input_channel = output_channel - - # building inverted residual blocks - stages = [] - block = GhostBottleneck - for cfg in self.cfgs: - layers = [] - for k, exp_size, c, se_ratio, s in cfg: - output_channel = _make_divisible(c * width, 4) - hidden_channel = _make_divisible(exp_size * width, 4) - layers.append(block(input_channel, hidden_channel, output_channel, k, s, - se_ratio=se_ratio)) - input_channel = output_channel - stages.append(nn.Sequential(*layers)) - - output_channel = _make_divisible(exp_size * width, 4) - stages.append(nn.Sequential(ConvBnAct(input_channel, output_channel, 1))) - input_channel = output_channel - - self.blocks = nn.Sequential(*stages) - - # building last several layers - output_channel = 1280 - self.global_pool = nn.AdaptiveAvgPool2d((1, 1)) - self.conv_head = nn.Conv2d(input_channel, output_channel, 1, 1, 0, bias=True) - self.act2 = nn.ReLU(inplace=True) - self.classifier = nn.Linear(output_channel, num_classes) - - def forward(self, x): - x = self.conv_stem(x) - x = self.bn1(x) - x = self.act1(x) - x = self.blocks(x) - x = self.global_pool(x) - x = self.conv_head(x) - x = self.act2(x) - x = x.view(x.size(0), -1) - if self.dropout > 0.: - x = F.dropout(x, p=self.dropout, training=self.training) - x = self.classifier(x) - return x - - -def ghostnet(**kwargs): - """ - Constructs a GhostNet model - """ - cfgs = [ - # k, t, c, SE, s - # stage1 - [[3, 16, 16, 0, 1]], - # stage2 - [[3, 48, 24, 0, 2]], - [[3, 72, 24, 0, 1]], - # stage3 - [[5, 72, 40, 0.25, 2]], - [[5, 120, 40, 0.25, 1]], - # stage4 - [[3, 240, 80, 0, 2]], - [[3, 200, 80, 0, 1], - [3, 184, 80, 0, 1], - [3, 184, 80, 0, 1], - [3, 480, 112, 0.25, 1], - [3, 672, 112, 0.25, 1] - ], - # stage5 - [[5, 672, 160, 0.25, 2]], - [[5, 960, 160, 0, 1], - [5, 960, 160, 0.25, 1], - [5, 960, 160, 0, 1], - [5, 960, 160, 0.25, 1] - ] - ] - return GhostNet(cfgs, **kwargs) - - -if __name__=='__main__': - model = ghostnet() - model.eval() - print(model) - input = torch.randn(32,3,320,256) - y = model(input) +# 2020.06.09-Changed for building GhostNet +# Huawei Technologies Co., Ltd. +""" +Creates a GhostNet Model as defined in: +GhostNet: More Features from Cheap Operations By Kai Han, Yunhe Wang, Qi Tian, Jianyuan Guo, Chunjing Xu, Chang Xu. +https://arxiv.org/abs/1911.11907 +Modified from https://github.com/d-li14/mobilenetv3.pytorch and https://github.com/rwightman/pytorch-image-models +""" +import torch +import torch.nn as nn +import torch.nn.functional as F +import math + + +__all__ = ['ghost_net'] + + +def _make_divisible(v, divisor, min_value=None): + """ + This function is taken from the original tf repo. + It ensures that all layers have a channel number that is divisible by 8 + It can be seen here: + https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py + """ + if min_value is None: + min_value = divisor + new_v = max(min_value, int(v + divisor / 2) // divisor * divisor) + # Make sure that round down does not go down by more than 10%. + if new_v < 0.9 * v: + new_v += divisor + return new_v + + +def hard_sigmoid(x, inplace: bool = False): + if inplace: + return x.add_(3.).clamp_(0., 6.).div_(6.) + else: + return F.relu6(x + 3.) / 6. + + +class SqueezeExcite(nn.Module): + def __init__(self, in_chs, se_ratio=0.25, reduced_base_chs=None, + act_layer=nn.ReLU, gate_fn=hard_sigmoid, divisor=4, **_): + super(SqueezeExcite, self).__init__() + self.gate_fn = gate_fn + reduced_chs = _make_divisible((reduced_base_chs or in_chs) * se_ratio, divisor) + self.avg_pool = nn.AdaptiveAvgPool2d(1) + self.conv_reduce = nn.Conv2d(in_chs, reduced_chs, 1, bias=True) + self.act1 = act_layer(inplace=True) + self.conv_expand = nn.Conv2d(reduced_chs, in_chs, 1, bias=True) + + def forward(self, x): + x_se = self.avg_pool(x) + x_se = self.conv_reduce(x_se) + x_se = self.act1(x_se) + x_se = self.conv_expand(x_se) + x = x * self.gate_fn(x_se) + return x + + +class ConvBnAct(nn.Module): + def __init__(self, in_chs, out_chs, kernel_size, + stride=1, act_layer=nn.ReLU): + super(ConvBnAct, self).__init__() + self.conv = nn.Conv2d(in_chs, out_chs, kernel_size, stride, kernel_size//2, bias=False) + self.bn1 = nn.BatchNorm2d(out_chs) + self.act1 = act_layer(inplace=True) + + def forward(self, x): + x = self.conv(x) + x = self.bn1(x) + x = self.act1(x) + return x + + +class GhostModule(nn.Module): + def __init__(self, inp, oup, kernel_size=1, ratio=2, dw_size=3, stride=1, relu=True): + super(GhostModule, self).__init__() + self.oup = oup + init_channels = math.ceil(oup / ratio) + new_channels = init_channels*(ratio-1) + + self.primary_conv = nn.Sequential( + nn.Conv2d(inp, init_channels, kernel_size, stride, kernel_size//2, bias=False), + nn.BatchNorm2d(init_channels), + nn.ReLU(inplace=True) if relu else nn.Sequential(), + ) + + self.cheap_operation = nn.Sequential( + nn.Conv2d(init_channels, new_channels, dw_size, 1, dw_size//2, groups=init_channels, bias=False), + nn.BatchNorm2d(new_channels), + nn.ReLU(inplace=True) if relu else nn.Sequential(), + ) + + def forward(self, x): + x1 = self.primary_conv(x) + x2 = self.cheap_operation(x1) + out = torch.cat([x1,x2], dim=1) + # For avoiding OOM, refine raw code now: return out[:,:self.oup,:,:] + return out + + +class GhostBottleneck(nn.Module): + """ Ghost bottleneck w/ optional SE""" + + def __init__(self, in_chs, mid_chs, out_chs, dw_kernel_size=3, + stride=1, act_layer=nn.ReLU, se_ratio=0.): + super(GhostBottleneck, self).__init__() + has_se = se_ratio is not None and se_ratio > 0. + self.stride = stride + + # Point-wise expansion + self.ghost1 = GhostModule(in_chs, mid_chs, relu=True) + + # Depth-wise convolution + if self.stride > 1: + self.conv_dw = nn.Conv2d(mid_chs, mid_chs, dw_kernel_size, stride=stride, + padding=(dw_kernel_size-1)//2, + groups=mid_chs, bias=False) + self.bn_dw = nn.BatchNorm2d(mid_chs) + + # Squeeze-and-excitation + if has_se: + self.se = SqueezeExcite(mid_chs, se_ratio=se_ratio) + else: + self.se = None + + # Point-wise linear projection + self.ghost2 = GhostModule(mid_chs, out_chs, relu=False) + + # shortcut + if (in_chs == out_chs and self.stride == 1): + self.shortcut = nn.Sequential() + else: + self.shortcut = nn.Sequential( + nn.Conv2d(in_chs, in_chs, dw_kernel_size, stride=stride, + padding=(dw_kernel_size-1)//2, groups=in_chs, bias=False), + nn.BatchNorm2d(in_chs), + nn.Conv2d(in_chs, out_chs, 1, stride=1, padding=0, bias=False), + nn.BatchNorm2d(out_chs), + ) + + + def forward(self, x): + residual = x + + # 1st ghost bottleneck + x = self.ghost1(x) + + # Depth-wise convolution + if self.stride > 1: + x = self.conv_dw(x) + x = self.bn_dw(x) + + # Squeeze-and-excitation + if self.se is not None: + x = self.se(x) + + # 2nd ghost bottleneck + x = self.ghost2(x) + + x += self.shortcut(residual) + return x + + +class GhostNet(nn.Module): + def __init__(self, cfgs, num_classes=1000, width=1.0, dropout=0.2): + super(GhostNet, self).__init__() + # setting of inverted residual blocks + self.cfgs = cfgs + self.dropout = dropout + + # building first layer + output_channel = _make_divisible(16 * width, 4) + self.conv_stem = nn.Conv2d(3, output_channel, 3, 2, 1, bias=False) + self.bn1 = nn.BatchNorm2d(output_channel) + self.act1 = nn.ReLU(inplace=True) + input_channel = output_channel + + # building inverted residual blocks + stages = [] + block = GhostBottleneck + for cfg in self.cfgs: + layers = [] + for k, exp_size, c, se_ratio, s in cfg: + output_channel = _make_divisible(c * width, 4) + hidden_channel = _make_divisible(exp_size * width, 4) + layers.append(block(input_channel, hidden_channel, output_channel, k, s, + se_ratio=se_ratio)) + input_channel = output_channel + stages.append(nn.Sequential(*layers)) + + output_channel = _make_divisible(exp_size * width, 4) + stages.append(nn.Sequential(ConvBnAct(input_channel, output_channel, 1))) + input_channel = output_channel + + self.blocks = nn.Sequential(*stages) + + # building last several layers + output_channel = 1280 + self.global_pool = nn.AdaptiveAvgPool2d((1, 1)) + self.conv_head = nn.Conv2d(input_channel, output_channel, 1, 1, 0, bias=True) + self.act2 = nn.ReLU(inplace=True) + self.classifier = nn.Linear(output_channel, num_classes) + + def forward(self, x): + x = self.conv_stem(x) + x = self.bn1(x) + x = self.act1(x) + x = self.blocks(x) + x = self.global_pool(x) + x = self.conv_head(x) + x = self.act2(x) + x = x.view(x.size(0), -1) + if self.dropout > 0.: + x = F.dropout(x, p=self.dropout, training=self.training) + x = self.classifier(x) + return x + + +def ghostnet(**kwargs): + """ + Constructs a GhostNet model + """ + cfgs = [ + # k, t, c, SE, s + # stage1 + [[3, 16, 16, 0, 1]], + # stage2 + [[3, 48, 24, 0, 2]], + [[3, 72, 24, 0, 1]], + # stage3 + [[5, 72, 40, 0.25, 2]], + [[5, 120, 40, 0.25, 1]], + # stage4 + [[3, 240, 80, 0, 2]], + [[3, 200, 80, 0, 1], + [3, 184, 80, 0, 1], + [3, 184, 80, 0, 1], + [3, 480, 112, 0.25, 1], + [3, 672, 112, 0.25, 1] + ], + # stage5 + [[5, 672, 160, 0.25, 2]], + [[5, 960, 160, 0, 1], + [5, 960, 160, 0.25, 1], + [5, 960, 160, 0, 1], + [5, 960, 160, 0.25, 1] + ] + ] + return GhostNet(cfgs, **kwargs) + + +if __name__=='__main__': + model = ghostnet() + model.eval() + print(model) + input = torch.randn(32,3,320,256) + y = model(input) print(y.size()) \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/GhostNet/modelarts/train_start.py b/PyTorch/contrib/cv/classification/GhostNet/modelarts/train_start.py index 4335340a14..d0a33069ef 100644 --- a/PyTorch/contrib/cv/classification/GhostNet/modelarts/train_start.py +++ b/PyTorch/contrib/cv/classification/GhostNet/modelarts/train_start.py @@ -1,778 +1,778 @@ -#!/usr/bin/env python -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -""" ImageNet Training Script -This is intended to be a lean and easily modifiable ImageNet training script that reproduces ImageNet -training results with some of the latest networks and training techniques. It favours canonical PyTorch -and standard Python style over trying to be able to 'do it all.' That said, it offers quite a few speed -and training result improvements over the usual PyTorch example scripts. Repurpose as you see fit. -This script was started from an early version of the PyTorch ImageNet example -(https://github.com/pytorch/examples/tree/master/imagenet) -NVIDIA CUDA specific speedups adopted from NVIDIA Apex examples -(https://github.com/NVIDIA/apex/tree/master/examples/imagenet) -Hacked together by / Copyright 2020 Ross Wightman (https://github.com/rwightman) -""" -import argparse -import time -import yaml -import os -import logging -from collections import OrderedDict -from contextlib import suppress -from datetime import datetime -import glob -import shutil - -import torch -import torch.nn as nn -import torchvision.utils -from torch.nn.parallel import DistributedDataParallel as NativeDDP -import torch.onnx - -from timm.data import create_dataset, create_loader, resolve_data_config, Mixup, FastCollateMixup, AugMixDataset -from timm.data import create_loader, resolve_data_config, Mixup, FastCollateMixup, AugMixDataset -from timm.models import create_model, resume_checkpoint, load_checkpoint, convert_splitbn_model -from timm.utils import * -from timm.loss import LabelSmoothingCrossEntropy, SoftTargetCrossEntropy, JsdCrossEntropy -from timm.optim import create_optimizer -from timm.scheduler import create_scheduler -from timm.utils import ApexScaler, NativeScaler -from ghostnet.ghostnet_pytorch.ghostnet import ghostnet -import torch.npu - -# modelarts modification -import moxing as mox - -CALCULATE_DEVICE = "npu:0" - -try: - from apex import amp - from apex.parallel import DistributedDataParallel as ApexDDP - from apex.parallel import convert_syncbn_model - - has_apex = True -except ImportError: - has_apex = False - -has_native_amp = False -try: - if getattr(torch.cuda.amp, 'autocast') is not None: - has_native_amp = True -except AttributeError: - pass - -torch.backends.cudnn.benchmark = True -_logger = logging.getLogger('train') - -# The first arg parser parses out only the --config argument, this argument is used to -# load a yaml file containing key-values that override the defaults for the main parser below -config_parser = parser = argparse.ArgumentParser(description='Training Config', add_help=False) -parser.add_argument('-c', '--config', default='', type=str, metavar='FILE', - help='YAML config file specifying default arguments') -parser = argparse.ArgumentParser(description='PyTorch ImageNet Training') -# Dataset / Model parameters -parser.add_argument('data_dir', metavar='DIR', - help='path to dataset') -parser.add_argument('--dataset', '-d', metavar='NAME', default='', - help='dataset type (default: ImageFolder/ImageTar if empty)') -parser.add_argument('--train-split', metavar='NAME', default='train', - help='dataset train split (default: train)') -parser.add_argument('--val-split', metavar='NAME', default='validation', - help='dataset validation split (default: validation)') -parser.add_argument('--model', default='resnet101', type=str, metavar='MODEL', - help='Name of model to train (default: "countception"') -parser.add_argument('--pretrained', action='store_true', default=False, - help='Start with pretrained version of specified network (if avail)') -parser.add_argument('--initial-checkpoint', default='', type=str, metavar='PATH', - help='Initialize model from this checkpoint (default: none)') -parser.add_argument('--resume', default='', type=str, metavar='PATH', - help='Resume full model and optimizer state from checkpoint (default: none)') -parser.add_argument('--no-resume-opt', action='store_true', default=False, - help='prevent resume of optimizer state when resuming model') -parser.add_argument('--num-classes', type=int, default=None, metavar='N', - help='number of label classes (Model default if None)') -parser.add_argument('--gp', default=None, type=str, metavar='POOL', - help='Global pool type, one of (fast, avg, max, avgmax, avgmaxc). Model default if None.') -parser.add_argument('--img-size', type=int, default=None, metavar='N', - help='Image patch size (default: None => model default)') -parser.add_argument('--input-size', default=None, nargs=3, type=int, - metavar='N N N', - help='Input all image dimensions (d h w, e.g. --input-size 3 224 224), uses model default if empty') -parser.add_argument('--crop-pct', default=None, type=float, - metavar='N', help='Input image center crop percent (for validation only)') -parser.add_argument('--mean', type=float, nargs='+', default=None, metavar='MEAN', - help='Override mean pixel value of dataset') -parser.add_argument('--std', type=float, nargs='+', default=None, metavar='STD', - help='Override std deviation of of dataset') -parser.add_argument('--interpolation', default='', type=str, metavar='NAME', - help='Image resize interpolation type (overrides model)') -parser.add_argument('-b', '--batch-size', type=int, default=1024, metavar='N', - help='input batch size for training (default: 32)') -parser.add_argument('-vb', '--validation-batch-size-multiplier', type=int, default=1, metavar='N', - help='ratio of validation batch size to training batch size (default: 1)') - -# Optimizer parameters -parser.add_argument('--opt', default='sgd', type=str, metavar='OPTIMIZER', - help='Optimizer (default: "sgd"') -parser.add_argument('--opt-eps', default=None, type=float, metavar='EPSILON', - help='Optimizer Epsilon (default: None, use opt default)') -parser.add_argument('--opt-betas', default=None, type=float, nargs='+', metavar='BETA', - help='Optimizer Betas (default: None, use opt default)') -parser.add_argument('--momentum', type=float, default=0.9, metavar='M', - help='Optimizer momentum (default: 0.9)') -parser.add_argument('--weight-decay', type=float, default=0.0001, - help='weight decay (default: 0.0001)') -parser.add_argument('--clip-grad', type=float, default=None, metavar='NORM', - help='Clip gradient norm (default: None, no clipping)') - -# Learning rate schedule parameters -parser.add_argument('--sched', default='step', type=str, metavar='SCHEDULER', - help='LR scheduler (default: "step"') -parser.add_argument('--lr', type=float, default=0.4, metavar='LR', - help='learning rate (default: 0.01)') -parser.add_argument('--lr-noise', type=float, nargs='+', default=None, metavar='pct, pct', - help='learning rate noise on/off epoch percentages') -parser.add_argument('--lr-noise-pct', type=float, default=0.67, metavar='PERCENT', - help='learning rate noise limit percent (default: 0.67)') -parser.add_argument('--lr-noise-std', type=float, default=1.0, metavar='STDDEV', - help='learning rate noise std-dev (default: 1.0)') -parser.add_argument('--lr-cycle-mul', type=float, default=1.0, metavar='MULT', - help='learning rate cycle len multiplier (default: 1.0)') -parser.add_argument('--lr-cycle-limit', type=int, default=1, metavar='N', - help='learning rate cycle limit') -parser.add_argument('--warmup-lr', type=float, default=0.0001, metavar='LR', - help='warmup learning rate (default: 0.0001)') -parser.add_argument('--min-lr', type=float, default=1e-5, metavar='LR', - help='lower lr bound for cyclic schedulers that hit 0 (1e-5)') -parser.add_argument('--epochs', type=int, default=200, metavar='N', - help='number of epochs to train (default: 2)') -parser.add_argument('--start-epoch', default=None, type=int, metavar='N', - help='manual epoch number (useful on restarts)') -parser.add_argument('--decay-epochs', type=float, default=30, metavar='N', - help='epoch interval to decay LR') -parser.add_argument('--warmup-epochs', type=int, default=3, metavar='N', - help='epochs to warmup LR, if scheduler supports') -parser.add_argument('--cooldown-epochs', type=int, default=0, metavar='N', - help='epochs to cooldown LR at min_lr, after cyclic schedule ends') -parser.add_argument('--patience-epochs', type=int, default=0, metavar='N', - help='patience epochs for Plateau LR scheduler (default: 10') -parser.add_argument('--decay-rate', '--dr', type=float, default=0.1, metavar='RATE', - help='LR decay rate (default: 0.1)') - -# Augmentation & regularization parameters -parser.add_argument('--no-aug', action='store_true', default=False, - help='Disable all training augmentation, override other train aug args') -parser.add_argument('--scale', type=float, nargs='+', default=[0.08, 1.0], metavar='PCT', - help='Random resize scale (default: 0.08 1.0)') -parser.add_argument('--ratio', type=float, nargs='+', default=[3. / 4., 4. / 3.], metavar='RATIO', - help='Random resize aspect ratio (default: 0.75 1.33)') -parser.add_argument('--hflip', type=float, default=0.5, - help='Horizontal flip training aug probability') -parser.add_argument('--vflip', type=float, default=0., - help='Vertical flip training aug probability') -parser.add_argument('--color-jitter', type=float, default=0.4, metavar='PCT', - help='Color jitter factor (default: 0.4)') -parser.add_argument('--aug-splits', type=int, default=0, - help='Number of augmentation splits (default: 0, valid: 0 or >=2)') -parser.add_argument('--jsd', action='store_true', default=False, - help='Enable Jensen-Shannon Divergence + CE loss. Use with `--aug-splits`.') -parser.add_argument('--recount', type=int, default=1, - help='Random erase count (default: 1)') -parser.add_argument('--resplit', action='store_true', default=False, - help='Do not random erase first (clean) augmentation split') -parser.add_argument('--mixup', type=float, default=0.0, - help='mixup alpha, mixup enabled if > 0. (default: 0.)') -parser.add_argument('--cutmix', type=float, default=0.0, - help='cutmix alpha, cutmix enabled if > 0. (default: 0.)') -parser.add_argument('--cutmix-minmax', type=float, nargs='+', default=None, - help='cutmix min/max ratio, overrides alpha and enables cutmix if set (default: None)') -parser.add_argument('--mixup-prob', type=float, default=1.0, - help='Probability of performing mixup or cutmix when either/both is enabled') -parser.add_argument('--mixup-switch-prob', type=float, default=0.5, - help='Probability of switching to cutmix when both mixup and cutmix enabled') -parser.add_argument('--mixup-mode', type=str, default='batch', - help='How to apply mixup/cutmix params. Per "batch", "pair", or "elem"') -parser.add_argument('--mixup-off-epoch', default=0, type=int, metavar='N', - help='Turn off mixup after this epoch, disabled if 0 (default: 0)') -parser.add_argument('--smoothing', type=float, default=0.1, - help='Label smoothing (default: 0.1)') -parser.add_argument('--train-interpolation', type=str, default='random', - help='Training interpolation (random, bilinear, bicubic default: "random")') -parser.add_argument('--drop', type=float, default=0.2, metavar='PCT', - help='Dropout rate (default: 0.)') -parser.add_argument('--drop-path', type=float, default=None, metavar='PCT', - help='Drop path rate (default: None)') -parser.add_argument('--drop-block', type=float, default=None, metavar='PCT', - help='Drop block rate (default: None)') -parser.add_argument('--bn-tf', action='store_true', default=False, - help='Use Tensorflow BatchNorm defaults for models that support it (default: False)') -parser.add_argument('--bn-momentum', type=float, default=None, - help='BatchNorm momentum override (if not None)') -parser.add_argument('--bn-eps', type=float, default=None, - help='BatchNorm epsilon override (if not None)') -parser.add_argument('--sync-bn', action='store_true', - help='Enable NVIDIA Apex or Torch synchronized BatchNorm.') -parser.add_argument('--dist-bn', type=str, default='', - help='Distribute BatchNorm stats between nodes after each epoch ("broadcast", "reduce", or "")') -parser.add_argument('--split-bn', action='store_true', - help='Enable separate BN layers per augmentation split.') -# Misc -parser.add_argument('--seed', type=int, default=42, metavar='S', - help='random seed (default: 42)') -parser.add_argument('--log-interval', type=int, default=50, metavar='N', - help='how many batches to wait before logging training status') -parser.add_argument('--recovery-interval', type=int, default=0, metavar='N', - help='how many batches to wait before writing recovery checkpoint') -parser.add_argument('--checkpoint-hist', type=int, default=10, metavar='N', - help='number of checkpoints to keep (default: 10)') -parser.add_argument('-j', '--workers', type=int, default=4, metavar='N', - help='how many training processes to use (default: 1)') -parser.add_argument('--save-images', action='store_true', default=False, - help='save images of input bathes every log interval for debugging') -parser.add_argument('--amp', action='store_true', default=False, - help='use NVIDIA Apex AMP or Native AMP for mixed precision training') -parser.add_argument('--apex-amp', action='store_true', default=False, - help='Use NVIDIA Apex AMP mixed precision') -parser.add_argument('--native-amp', action='store_true', default=False, - help='Use Native Torch AMP mixed precision') -parser.add_argument('--channels-last', action='store_true', default=False, - help='Use channels_last memory layout') -parser.add_argument('--pin-mem', action='store_true', default=False, - help='Pin CPU memory in DataLoader for more efficient (sometimes) transfer to GPU.') -parser.add_argument('--no-prefetcher', action='store_true', default=True, - help='disable fast prefetcher') -parser.add_argument('--output', default='', type=str, metavar='PATH', - help='path to output folder (default: none, current dir)') -parser.add_argument('--eval-metric', default='top1', type=str, metavar='EVAL_METRIC', - help='Best metric (default: "top1"') -parser.add_argument('--tta', type=int, default=0, metavar='N', - help='Test/inference time augmentation (oversampling) factor. 0=None (default: 0)') -parser.add_argument("--local_rank", default=0, type=int) -parser.add_argument('--use-multi-epochs-loader', action='store_true', default=False, - help='use the multi-epochs-loader to save time at the beginning of every epoch') -parser.add_argument('--torchscript', dest='torchscript', action='store_true', - help='convert model torchscript for inference') -parser.add_argument('--width', type=float, default=1.0, - help='Width ratio (default: 1.0)') -parser.add_argument('--dist-url', default='tcp://127.0.0.1:50000', type=str, - help='url used to set up pretained training') -parser.add_argument('--dist-backend', default='nccl', type=str, - help='distributed backend') -parser.add_argument('--npu', default=None, type=int, - help='NPU id to use.') -#modelarts -parser.add_argument('--modelarts_mod', action='store_true', default=False, - help='Enable modelarts mode loss function to train') -parser.add_argument('--train_url', - default="/cache/training", - type=str, - help="setting dir of training output") -parser.add_argument('--pretrained_weight', default='', type=str, metavar='PATH', - help='path to pretrained weight') -parser.add_argument('--onnx', default=True, action='store_true', - help="convert pth model to onnx") -parser.add_argument('--data_url', - type=str, - default='/cache/data_url', - help='the training data') - -CACHE_TRAINING_URL = "/cache/training" -def _parse_args(): - # Do we have a config file to parse? - args_config, remaining = config_parser.parse_known_args() - if args_config.config: - with open(args_config.config, 'r') as f: - cfg = yaml.safe_load(f) - parser.set_defaults(**cfg) - # The main arg parser parses the rest of the args, the usual - # defaults will have been overridden if config file specified. - args = parser.parse_args(remaining) - print(args) - # Cache the args as a text string to save them in the output dir later - args_text = yaml.safe_dump(args.__dict__, default_flow_style=False) - return args, args_text - - -def main(): - setup_default_logging() - args, args_text = _parse_args() - - args.prefetcher = not args.no_prefetcher - args.distributed = False - if args.npu is None: - args.npu = 0 - CALCULATE_DEVICE = "npu:{}".format(args.npu) - torch.npu.set_device(CALCULATE_DEVICE) - print("use ", CALCULATE_DEVICE) - - if 'WORLD_SIZE' in os.environ: - args.distributed = int(os.environ['WORLD_SIZE']) > 1 - args.device = 'npu:0' - args.world_size = 1 - args.rank = 0 # global rank - _logger.info('Training with a single process on 1 NPUs.') - assert args.rank >= 0 - - # resolve AMP arguments based on PyTorch / Apex availability - use_amp = None - if args.amp: - # for backwards compat, `--amp` arg tries apex before native amp - if has_apex: - args.apex_amp = True - elif has_native_amp: - args.native_amp = True - if args.apex_amp and has_apex: - use_amp = 'apex' - elif args.native_amp and has_native_amp: - use_amp = 'native' - elif args.apex_amp or args.native_amp: - _logger.warning("Neither APEX or native Torch AMP is available, using float32. " - "Install NVIDA apex or upgrade to PyTorch 1.6") - - torch.manual_seed(args.seed + args.rank) - model = ghostnet(num_classes=args.num_classes, width=args.width, dropout=args.drop) - - if args.pretrained: - CACHE_MODEL_URL = "/cache/model" - os.makedirs(CACHE_MODEL_URL, exist_ok=True) - mox.file.copy_parallel(args.pretrained_weight, os.path.join(CACHE_MODEL_URL, "model_best.pth.tar")) - pretrained_weight = os.path.join(CACHE_MODEL_URL, "model_best.pth.tar") - pretrained_dict = torch.load(pretrained_weight)["state_dict"] - pretrained_model = {k.replace('module.', ''): v for k, v in pretrained_dict.items()} - if "classifier.weight" in pretrained_model: - pretrained_model.pop('classifier.weight') - pretrained_model.pop('classifier.bias') - model.load_state_dict(pretrained_model, strict=False) - - for param in model.parameters(): - param.requires_grad = False - - for param in model.classifier.parameters(): - param.requires_grad = True - - if args.num_classes is None: - assert hasattr(model, 'num_classes'), 'Model must have `num_classes` attr if not set on cmd line/config.' - args.num_classes = model.num_classes # FIXME handle model default vs config num_classes more elegantly - - if args.local_rank == 0: - _logger.info('Model %s created, param count: %d' % - (args.model, sum([m.numel() for m in model.parameters()]))) - - data_config = resolve_data_config(vars(args), model=model, verbose=args.local_rank == 0) - - # setup augmentation batch splits for contrastive loss or split bn - num_aug_splits = 0 - if args.aug_splits > 0: - assert args.aug_splits > 1, 'A split of 1 makes no sense' - num_aug_splits = args.aug_splits - - # enable split bn (separate bn stats per batch-portion) - if args.split_bn: - assert num_aug_splits > 1 or args.resplit - model = convert_splitbn_model(model, max(num_aug_splits, 2)) - - # move model to GPU, enable channels last layout if set - model = model.to(CALCULATE_DEVICE) - if args.channels_last: - model = model.to(memory_format=torch.channels_last) - - if args.torchscript: - assert not use_amp == 'apex', 'Cannot use APEX AMP with torchscripted model' - assert not args.sync_bn, 'Cannot use SyncBatchNorm with torchscripted model' - model = torch.jit.script(model) - - optimizer = create_optimizer(args, model) - - # setup automatic mixed-precision (AMP) loss scaling and op casting - amp_autocast = suppress # do nothing - loss_scaler = None - if use_amp == 'apex': - model, optimizer = amp.initialize(model, optimizer, opt_level='O2', loss_scale=128) - loss_scaler = ApexScaler() - if args.local_rank == 0: - _logger.info('Using NVIDIA APEX AMP. Training in mixed precision.') - elif use_amp == 'native': - amp_autocast = torch.cuda.amp.autocast - loss_scaler = NativeScaler() - if args.local_rank == 0: - _logger.info('Using native Torch AMP. Training in mixed precision.') - else: - if args.local_rank == 0: - _logger.info('AMP not enabled. Training in float32.') - - # optionally resume from a checkpoint - resume_epoch = None - if args.resume: - resume_epoch = resume_checkpoint( - model, args.resume, - optimizer=None if args.no_resume_opt else optimizer, - loss_scaler=None if args.no_resume_opt else loss_scaler, - log_info=args.local_rank == 0) - - # setup exponential moving average of model weights, SWA could be used here too - model_ema = None - # setup learning rate schedule and starting epoch - lr_scheduler, num_epochs = create_scheduler(args, optimizer) - start_epoch = 0 - if args.start_epoch is not None: - # a specified start_epoch will always override the resume epoch - start_epoch = args.start_epoch - elif resume_epoch is not None: - start_epoch = resume_epoch - if lr_scheduler is not None and start_epoch > 0: - lr_scheduler.step(start_epoch) - - if args.local_rank == 0: - _logger.info('Scheduled epochs: {}'.format(num_epochs)) - - # create the train and eval datasets - real_path = '/cache/data_url' - if not os.path.exists(real_path): - os.makedirs(real_path) - mox.file.copy_parallel(args.data_url, real_path) - print("training data finish copy to %s." % real_path) - dataset_train = create_dataset( - args.dataset, root=real_path, split=args.train_split, is_training=True, batch_size=args.batch_size) - dataset_eval = create_dataset( - args.dataset, root=real_path, split=args.val_split, is_training=False, batch_size=args.batch_size) - # setup mixup / cutmix - collate_fn = None - mixup_fn = None - mixup_active = args.mixup > 0 or args.cutmix > 0. or args.cutmix_minmax is not None - if mixup_active: - mixup_args = dict( - mixup_alpha=args.mixup, cutmix_alpha=args.cutmix, cutmix_minmax=args.cutmix_minmax, - prob=args.mixup_prob, switch_prob=args.mixup_switch_prob, mode=args.mixup_mode, - label_smoothing=args.smoothing, num_classes=args.num_classes) - if args.prefetcher: - assert not num_aug_splits # collate conflict (need to support deinterleaving in collate mixup) - collate_fn = FastCollateMixup(**mixup_args) - else: - mixup_fn = Mixup(**mixup_args) - - # wrap dataset in AugMix helper - if num_aug_splits > 1: - dataset_train = AugMixDataset(dataset_train, num_splits=num_aug_splits) - - # create data loaders w/ augmentation pipeiine - train_interpolation = args.train_interpolation - if args.no_aug or not train_interpolation: - train_interpolation = data_config['interpolation'] - loader_train = create_loader( - dataset_train, - input_size=data_config['input_size'], - batch_size=args.batch_size, - is_training=True, - use_prefetcher=not args.no_prefetcher, - no_aug=args.no_aug, - re_count=args.recount, - re_split=args.resplit, - scale=args.scale, - ratio=args.ratio, - hflip=args.hflip, - vflip=args.vflip, - color_jitter=args.color_jitter, - num_aug_splits=num_aug_splits, - interpolation=train_interpolation, - mean=data_config['mean'], - std=data_config['std'], - num_workers=args.workers, - collate_fn=collate_fn, - pin_memory=args.pin_mem, - use_multi_epochs_loader=args.use_multi_epochs_loader - ) - - loader_eval = create_loader( - dataset_eval, - input_size=data_config['input_size'], - batch_size=args.validation_batch_size_multiplier * args.batch_size, - is_training=False, - use_prefetcher=not args.no_prefetcher, - interpolation=data_config['interpolation'], - mean=data_config['mean'], - std=data_config['std'], - num_workers=args.workers, - crop_pct=data_config['crop_pct'], - pin_memory=args.pin_mem, - ) - - # setup loss function - if args.jsd: - #assert num_aug_splits > 1 # JSD only valid with aug splits set - train_loss_fn = JsdCrossEntropy(num_splits=num_aug_splits, smoothing=args.smoothing).to(CALCULATE_DEVICE) - elif mixup_active: - # smoothing is handled with mixup target transform - train_loss_fn = SoftTargetCrossEntropy().to(CALCULATE_DEVICE) - elif args.smoothing: - train_loss_fn = LabelSmoothingCrossEntropy(smoothing=args.smoothing).to(CALCULATE_DEVICE) - else: - train_loss_fn = nn.CrossEntropyLoss().to(CALCULATE_DEVICE) - if args.modelarts_mod: - train_loss_fn = nn.CrossEntropyLoss().to(CALCULATE_DEVICE) - - validate_loss_fn = nn.CrossEntropyLoss().to(CALCULATE_DEVICE) - # setup checkpoint saver and eval metric tracking - eval_metric = args.eval_metric - best_metric = None - best_epoch = None - saver = None - output_dir = '' - if args.local_rank == 0: - output_base = args.output if args.output else './output' - exp_name = '-'.join([ - datetime.now().strftime("%Y%m%d-%H%M%S"), - args.model, - str(data_config['input_size'][-1]) - ]) - output_dir = get_outdir(output_base, 'train', exp_name) - decreasing = True if eval_metric == 'loss' else False - saver = CheckpointSaver( - model=model, optimizer=optimizer, args=args, amp_scaler=loss_scaler, - checkpoint_dir=output_dir, recovery_dir=output_dir, decreasing=decreasing, max_history=args.checkpoint_hist) - - with open(os.path.join(output_dir, 'args.yaml'), 'w') as f: - f.write(args_text) - - try: - for epoch in range(start_epoch, num_epochs): - - train_metrics = train_one_epoch( - epoch, model, loader_train, optimizer, train_loss_fn, args, - lr_scheduler=lr_scheduler, saver=saver, output_dir=output_dir, - amp_autocast=amp_autocast, loss_scaler=loss_scaler, mixup_fn=mixup_fn) - - eval_metrics = validate(model, loader_eval, validate_loss_fn, args, amp_autocast=amp_autocast) - - if lr_scheduler is not None: - # step LR for next epoch - lr_scheduler.step(epoch + 1, eval_metrics[eval_metric]) - - update_summary( - epoch, train_metrics, eval_metrics, os.path.join(output_dir, 'summary.csv'), - write_header=best_metric is None) - - if saver is not None: - # save proper checkpoint with eval metric - save_metric = eval_metrics[eval_metric] - best_metric, best_epoch = saver.save_checkpoint(epoch, metric=save_metric) - - except KeyboardInterrupt: - pass - if best_metric is not None: - _logger.info('*** Best metric: {0} (epoch {1})'.format(best_metric, best_epoch)) - - if args.onnx: - os.makedirs(CACHE_TRAINING_URL, exist_ok=True) - print("abspath:",os.path.abspath(output_dir)) - print("output_dir:",os.listdir(output_dir)) - shutil.copy(os.path.join(os.path.abspath(output_dir), 'model_best.pth.tar'), CACHE_TRAINING_URL) - pth_pattern = os.path.join(CACHE_TRAINING_URL, 'model_best.pth.tar') - print("pth_pattern:",os.path.abspath(pth_pattern)) - pth_file_list = glob.glob(pth_pattern) - if not pth_file_list: - print(f"can't find pth {pth_pattern}") - pth_file = pth_file_list[0] - onnx_path = pth_file.split(".")[0] + '.onnx' - convert(pth_file, onnx_path) - # --------------modelarts modification---------- - mox.file.copy_parallel(CACHE_TRAINING_URL, args.train_url) - # --------------modelarts modification end---------- - print("CACHE_TRAINING_URL:",os.listdir(CACHE_TRAINING_URL)) - -def train_one_epoch( - epoch, model, loader, optimizer, loss_fn, args, - lr_scheduler=None, saver=None, output_dir='', amp_autocast=suppress, - loss_scaler=None, mixup_fn=None): - if args.mixup_off_epoch and epoch >= args.mixup_off_epoch: - if args.prefetcher and loader.mixup_enabled: - loader.mixup_enabled = False - elif mixup_fn is not None: - mixup_fn.mixup_enabled = False - - second_order = hasattr(optimizer, 'is_second_order') and optimizer.is_second_order - batch_time_m = AverageMeter() - data_time_m = AverageMeter() - losses_m = AverageMeter(start_count_index=0) - - model.train() - - end = time.time() - last_idx = len(loader) - 1 - num_updates = epoch * len(loader) - for batch_idx, (input, target) in enumerate(loader): - last_batch = batch_idx == last_idx - data_time_m.update(time.time() - end) - if not args.prefetcher: - input, target = input.npu(), target.npu() - if mixup_fn is not None: - input, target = mixup_fn(input, target) - if args.channels_last: - input = input.contiguous(memory_format=torch.channels_last) - - with amp_autocast(): - output = model(input) - target = target.to(torch.int32) - loss = loss_fn(output, target) - - losses_m.update(loss.item(), input.size(0)) - - optimizer.zero_grad() - if loss_scaler is not None: - loss_scaler( - loss, optimizer, clip_grad=args.clip_grad, parameters=model.parameters(), create_graph=second_order) - else: - loss.backward(create_graph=second_order) - if args.clip_grad is not None: - torch.nn.utils.clip_grad_norm_(model.parameters(), args.clip_grad) - optimizer.step() - - num_updates += 1 - batch_time_m.update(time.time() - end) - if last_batch or batch_idx % args.log_interval == 0: - lrl = [param_group['lr'] for param_group in optimizer.param_groups] - lr = sum(lrl) / len(lrl) - - if args.local_rank == 0: - if batch_time_m.avg > 0: - _logger.info( - 'Train: {} [{:>4d}/{} ({:>3.0f}%)] ' - 'Loss: {loss.val:>9.6f} ({loss.avg:>6.4f}) ' - 'Time: {batch_time.val:.3f}s, {rate:>7.2f}/s ' - '({batch_time.avg:.3f}s, {rate_avg:>7.2f}/s) ' - 'LR: {lr:.3e} ' - 'Data: {data_time.val:.3f} ({data_time.avg:.3f})' - 'fps: {fps:.3f} ' - 'Batch_Size:{batch_size:.1f} '.format( - epoch, - batch_idx, len(loader), - 100. * batch_idx / last_idx, - loss=losses_m, - batch_time=batch_time_m, - rate=input.size(0) * args.world_size / batch_time_m.val, - rate_avg=input.size(0) * args.world_size / batch_time_m.avg, - lr=lr, - data_time=data_time_m, - fps=args.batch_size / batch_time_m.avg, - batch_size=args.batch_size)) - - if args.save_images and output_dir: - torchvision.utils.save_image( - input, - os.path.join(output_dir, 'train-batch-%d.jpg' % batch_idx), - padding=0, - normalize=True) - - if saver is not None and args.recovery_interval and ( - last_batch or (batch_idx + 1) % args.recovery_interval == 0): - saver.save_recovery(epoch, batch_idx=batch_idx) - - if lr_scheduler is not None: - lr_scheduler.step_update(num_updates=num_updates, metric=losses_m.avg) - - end = time.time() - # end for - - if hasattr(optimizer, 'sync_lookahead'): - optimizer.sync_lookahead() - - return OrderedDict([('loss', losses_m.avg)]) - - -def validate(model, loader, loss_fn, args, amp_autocast=suppress, log_suffix=''): - batch_time_m = AverageMeter() - losses_m = AverageMeter(start_count_index=0) - top1_m = AverageMeter(start_count_index=0) - top5_m = AverageMeter(start_count_index=0) - model.eval() - - end = time.time() - last_idx = len(loader) - 1 - with torch.no_grad(): - for batch_idx, (input, target) in enumerate(loader): - last_batch = batch_idx == last_idx - if args.no_prefetcher: - input = input.npu() - target = target.npu() - if args.channels_last: - input = input.contiguous(memory_format=torch.channels_last) - - with amp_autocast(): - output = model(input) - if isinstance(output, (tuple, list)): - output = output[0] - - # augmentation reduction - reduce_factor = args.tta - if reduce_factor > 1: - output = output.unfold(0, reduce_factor, reduce_factor).mean(dim=2) - target = target[0:target.size(0):reduce_factor] - - target = target.to(torch.int32) - loss = loss_fn(output, target) - acc1, acc5 = accuracy(output, target, topk=(1, 5)) - - reduced_loss = loss.data - - losses_m.update(reduced_loss.item(), input.size(0)) - top1_m.update(acc1.item(), output.size(0)) - top5_m.update(acc5.item(), output.size(0)) - - batch_time_m.update(time.time() - end) - end = time.time() - if args.local_rank == 0 and (last_batch or batch_idx % args.log_interval == 0): - if batch_time_m.avg > 0: - log_name = 'Test' + log_suffix - _logger.info( - '{0}: [{1:>4d}/{2}] ' - 'Time: {batch_time.val:.3f} ({batch_time.avg:.3f}) ' - 'Loss: {loss.val:>7.4f} ({loss.avg:>6.4f}) ' - 'Acc@1: {top1.val:>7.4f} ({top1.avg:>7.4f}) ' - 'Acc@5: {top5.val:>7.4f} ({top5.avg:>7.4f})' - 'fps: {fps:.3f} ' - 'Batch_Size:{batch_size:.1f} '.format( - log_name, batch_idx, last_idx, batch_time=batch_time_m, - loss=losses_m, top1=top1_m, top5=top5_m, fps=args.batch_size / batch_time_m.avg, - batch_size=args.batch_size)) - - metrics = OrderedDict([('loss', losses_m.avg), ('top1', top1_m.avg), ('top5', top5_m.avg)]) - - return metrics - -def proc_node_module(checkpoint, attr_name): - new_model_state = OrderedDict() - for k, v in checkpoint[attr_name].items(): - if(k[0: 7] == "module."): - name = k[7:] - else: - name = k[0:] - new_model_state[name] = v - return new_model_state - -def convert(pth_file_path, onnx_file_path): - args, args_text = _parse_args() - checkpoint = torch.load(pth_file_path, map_location='cpu') - checkpoint['state_dict'] = proc_node_module(checkpoint, 'state_dict') - model = ghostnet(num_classes=args.num_classes, width=args.width, dropout=args.drop) - model.load_state_dict(checkpoint['state_dict'], False) - model.eval() - - input_names = ["image"] - output_names = ["output1"] - dummy_input = torch.randn(2, 3, 224, 224) - torch.onnx.export(model, dummy_input, onnx_file_path, input_names=input_names, output_names=output_names, opset_version=11) - -if __name__ == '__main__': - main() - +#!/usr/bin/env python +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +""" ImageNet Training Script +This is intended to be a lean and easily modifiable ImageNet training script that reproduces ImageNet +training results with some of the latest networks and training techniques. It favours canonical PyTorch +and standard Python style over trying to be able to 'do it all.' That said, it offers quite a few speed +and training result improvements over the usual PyTorch example scripts. Repurpose as you see fit. +This script was started from an early version of the PyTorch ImageNet example +(https://github.com/pytorch/examples/tree/master/imagenet) +NVIDIA CUDA specific speedups adopted from NVIDIA Apex examples +(https://github.com/NVIDIA/apex/tree/master/examples/imagenet) +Hacked together by / Copyright 2020 Ross Wightman (https://github.com/rwightman) +""" +import argparse +import time +import yaml +import os +import logging +from collections import OrderedDict +from contextlib import suppress +from datetime import datetime +import glob +import shutil + +import torch +import torch.nn as nn +import torchvision.utils +from torch.nn.parallel import DistributedDataParallel as NativeDDP +import torch.onnx + +from timm.data import create_dataset, create_loader, resolve_data_config, Mixup, FastCollateMixup, AugMixDataset +from timm.data import create_loader, resolve_data_config, Mixup, FastCollateMixup, AugMixDataset +from timm.models import create_model, resume_checkpoint, load_checkpoint, convert_splitbn_model +from timm.utils import * +from timm.loss import LabelSmoothingCrossEntropy, SoftTargetCrossEntropy, JsdCrossEntropy +from timm.optim import create_optimizer +from timm.scheduler import create_scheduler +from timm.utils import ApexScaler, NativeScaler +from ghostnet.ghostnet_pytorch.ghostnet import ghostnet +import torch.npu + +# modelarts modification +import moxing as mox + +CALCULATE_DEVICE = "npu:0" + +try: + from apex import amp + from apex.parallel import DistributedDataParallel as ApexDDP + from apex.parallel import convert_syncbn_model + + has_apex = True +except ImportError: + has_apex = False + +has_native_amp = False +try: + if getattr(torch.cuda.amp, 'autocast') is not None: + has_native_amp = True +except AttributeError: + pass + +torch.backends.cudnn.benchmark = True +_logger = logging.getLogger('train') + +# The first arg parser parses out only the --config argument, this argument is used to +# load a yaml file containing key-values that override the defaults for the main parser below +config_parser = parser = argparse.ArgumentParser(description='Training Config', add_help=False) +parser.add_argument('-c', '--config', default='', type=str, metavar='FILE', + help='YAML config file specifying default arguments') +parser = argparse.ArgumentParser(description='PyTorch ImageNet Training') +# Dataset / Model parameters +parser.add_argument('data_dir', metavar='DIR', + help='path to dataset') +parser.add_argument('--dataset', '-d', metavar='NAME', default='', + help='dataset type (default: ImageFolder/ImageTar if empty)') +parser.add_argument('--train-split', metavar='NAME', default='train', + help='dataset train split (default: train)') +parser.add_argument('--val-split', metavar='NAME', default='validation', + help='dataset validation split (default: validation)') +parser.add_argument('--model', default='resnet101', type=str, metavar='MODEL', + help='Name of model to train (default: "countception"') +parser.add_argument('--pretrained', action='store_true', default=False, + help='Start with pretrained version of specified network (if avail)') +parser.add_argument('--initial-checkpoint', default='', type=str, metavar='PATH', + help='Initialize model from this checkpoint (default: none)') +parser.add_argument('--resume', default='', type=str, metavar='PATH', + help='Resume full model and optimizer state from checkpoint (default: none)') +parser.add_argument('--no-resume-opt', action='store_true', default=False, + help='prevent resume of optimizer state when resuming model') +parser.add_argument('--num-classes', type=int, default=None, metavar='N', + help='number of label classes (Model default if None)') +parser.add_argument('--gp', default=None, type=str, metavar='POOL', + help='Global pool type, one of (fast, avg, max, avgmax, avgmaxc). Model default if None.') +parser.add_argument('--img-size', type=int, default=None, metavar='N', + help='Image patch size (default: None => model default)') +parser.add_argument('--input-size', default=None, nargs=3, type=int, + metavar='N N N', + help='Input all image dimensions (d h w, e.g. --input-size 3 224 224), uses model default if empty') +parser.add_argument('--crop-pct', default=None, type=float, + metavar='N', help='Input image center crop percent (for validation only)') +parser.add_argument('--mean', type=float, nargs='+', default=None, metavar='MEAN', + help='Override mean pixel value of dataset') +parser.add_argument('--std', type=float, nargs='+', default=None, metavar='STD', + help='Override std deviation of of dataset') +parser.add_argument('--interpolation', default='', type=str, metavar='NAME', + help='Image resize interpolation type (overrides model)') +parser.add_argument('-b', '--batch-size', type=int, default=1024, metavar='N', + help='input batch size for training (default: 32)') +parser.add_argument('-vb', '--validation-batch-size-multiplier', type=int, default=1, metavar='N', + help='ratio of validation batch size to training batch size (default: 1)') + +# Optimizer parameters +parser.add_argument('--opt', default='sgd', type=str, metavar='OPTIMIZER', + help='Optimizer (default: "sgd"') +parser.add_argument('--opt-eps', default=None, type=float, metavar='EPSILON', + help='Optimizer Epsilon (default: None, use opt default)') +parser.add_argument('--opt-betas', default=None, type=float, nargs='+', metavar='BETA', + help='Optimizer Betas (default: None, use opt default)') +parser.add_argument('--momentum', type=float, default=0.9, metavar='M', + help='Optimizer momentum (default: 0.9)') +parser.add_argument('--weight-decay', type=float, default=0.0001, + help='weight decay (default: 0.0001)') +parser.add_argument('--clip-grad', type=float, default=None, metavar='NORM', + help='Clip gradient norm (default: None, no clipping)') + +# Learning rate schedule parameters +parser.add_argument('--sched', default='step', type=str, metavar='SCHEDULER', + help='LR scheduler (default: "step"') +parser.add_argument('--lr', type=float, default=0.4, metavar='LR', + help='learning rate (default: 0.01)') +parser.add_argument('--lr-noise', type=float, nargs='+', default=None, metavar='pct, pct', + help='learning rate noise on/off epoch percentages') +parser.add_argument('--lr-noise-pct', type=float, default=0.67, metavar='PERCENT', + help='learning rate noise limit percent (default: 0.67)') +parser.add_argument('--lr-noise-std', type=float, default=1.0, metavar='STDDEV', + help='learning rate noise std-dev (default: 1.0)') +parser.add_argument('--lr-cycle-mul', type=float, default=1.0, metavar='MULT', + help='learning rate cycle len multiplier (default: 1.0)') +parser.add_argument('--lr-cycle-limit', type=int, default=1, metavar='N', + help='learning rate cycle limit') +parser.add_argument('--warmup-lr', type=float, default=0.0001, metavar='LR', + help='warmup learning rate (default: 0.0001)') +parser.add_argument('--min-lr', type=float, default=1e-5, metavar='LR', + help='lower lr bound for cyclic schedulers that hit 0 (1e-5)') +parser.add_argument('--epochs', type=int, default=200, metavar='N', + help='number of epochs to train (default: 2)') +parser.add_argument('--start-epoch', default=None, type=int, metavar='N', + help='manual epoch number (useful on restarts)') +parser.add_argument('--decay-epochs', type=float, default=30, metavar='N', + help='epoch interval to decay LR') +parser.add_argument('--warmup-epochs', type=int, default=3, metavar='N', + help='epochs to warmup LR, if scheduler supports') +parser.add_argument('--cooldown-epochs', type=int, default=0, metavar='N', + help='epochs to cooldown LR at min_lr, after cyclic schedule ends') +parser.add_argument('--patience-epochs', type=int, default=0, metavar='N', + help='patience epochs for Plateau LR scheduler (default: 10') +parser.add_argument('--decay-rate', '--dr', type=float, default=0.1, metavar='RATE', + help='LR decay rate (default: 0.1)') + +# Augmentation & regularization parameters +parser.add_argument('--no-aug', action='store_true', default=False, + help='Disable all training augmentation, override other train aug args') +parser.add_argument('--scale', type=float, nargs='+', default=[0.08, 1.0], metavar='PCT', + help='Random resize scale (default: 0.08 1.0)') +parser.add_argument('--ratio', type=float, nargs='+', default=[3. / 4., 4. / 3.], metavar='RATIO', + help='Random resize aspect ratio (default: 0.75 1.33)') +parser.add_argument('--hflip', type=float, default=0.5, + help='Horizontal flip training aug probability') +parser.add_argument('--vflip', type=float, default=0., + help='Vertical flip training aug probability') +parser.add_argument('--color-jitter', type=float, default=0.4, metavar='PCT', + help='Color jitter factor (default: 0.4)') +parser.add_argument('--aug-splits', type=int, default=0, + help='Number of augmentation splits (default: 0, valid: 0 or >=2)') +parser.add_argument('--jsd', action='store_true', default=False, + help='Enable Jensen-Shannon Divergence + CE loss. Use with `--aug-splits`.') +parser.add_argument('--recount', type=int, default=1, + help='Random erase count (default: 1)') +parser.add_argument('--resplit', action='store_true', default=False, + help='Do not random erase first (clean) augmentation split') +parser.add_argument('--mixup', type=float, default=0.0, + help='mixup alpha, mixup enabled if > 0. (default: 0.)') +parser.add_argument('--cutmix', type=float, default=0.0, + help='cutmix alpha, cutmix enabled if > 0. (default: 0.)') +parser.add_argument('--cutmix-minmax', type=float, nargs='+', default=None, + help='cutmix min/max ratio, overrides alpha and enables cutmix if set (default: None)') +parser.add_argument('--mixup-prob', type=float, default=1.0, + help='Probability of performing mixup or cutmix when either/both is enabled') +parser.add_argument('--mixup-switch-prob', type=float, default=0.5, + help='Probability of switching to cutmix when both mixup and cutmix enabled') +parser.add_argument('--mixup-mode', type=str, default='batch', + help='How to apply mixup/cutmix params. Per "batch", "pair", or "elem"') +parser.add_argument('--mixup-off-epoch', default=0, type=int, metavar='N', + help='Turn off mixup after this epoch, disabled if 0 (default: 0)') +parser.add_argument('--smoothing', type=float, default=0.1, + help='Label smoothing (default: 0.1)') +parser.add_argument('--train-interpolation', type=str, default='random', + help='Training interpolation (random, bilinear, bicubic default: "random")') +parser.add_argument('--drop', type=float, default=0.2, metavar='PCT', + help='Dropout rate (default: 0.)') +parser.add_argument('--drop-path', type=float, default=None, metavar='PCT', + help='Drop path rate (default: None)') +parser.add_argument('--drop-block', type=float, default=None, metavar='PCT', + help='Drop block rate (default: None)') +parser.add_argument('--bn-tf', action='store_true', default=False, + help='Use Tensorflow BatchNorm defaults for models that support it (default: False)') +parser.add_argument('--bn-momentum', type=float, default=None, + help='BatchNorm momentum override (if not None)') +parser.add_argument('--bn-eps', type=float, default=None, + help='BatchNorm epsilon override (if not None)') +parser.add_argument('--sync-bn', action='store_true', + help='Enable NVIDIA Apex or Torch synchronized BatchNorm.') +parser.add_argument('--dist-bn', type=str, default='', + help='Distribute BatchNorm stats between nodes after each epoch ("broadcast", "reduce", or "")') +parser.add_argument('--split-bn', action='store_true', + help='Enable separate BN layers per augmentation split.') +# Misc +parser.add_argument('--seed', type=int, default=42, metavar='S', + help='random seed (default: 42)') +parser.add_argument('--log-interval', type=int, default=50, metavar='N', + help='how many batches to wait before logging training status') +parser.add_argument('--recovery-interval', type=int, default=0, metavar='N', + help='how many batches to wait before writing recovery checkpoint') +parser.add_argument('--checkpoint-hist', type=int, default=10, metavar='N', + help='number of checkpoints to keep (default: 10)') +parser.add_argument('-j', '--workers', type=int, default=4, metavar='N', + help='how many training processes to use (default: 1)') +parser.add_argument('--save-images', action='store_true', default=False, + help='save images of input bathes every log interval for debugging') +parser.add_argument('--amp', action='store_true', default=False, + help='use NVIDIA Apex AMP or Native AMP for mixed precision training') +parser.add_argument('--apex-amp', action='store_true', default=False, + help='Use NVIDIA Apex AMP mixed precision') +parser.add_argument('--native-amp', action='store_true', default=False, + help='Use Native Torch AMP mixed precision') +parser.add_argument('--channels-last', action='store_true', default=False, + help='Use channels_last memory layout') +parser.add_argument('--pin-mem', action='store_true', default=False, + help='Pin CPU memory in DataLoader for more efficient (sometimes) transfer to GPU.') +parser.add_argument('--no-prefetcher', action='store_true', default=True, + help='disable fast prefetcher') +parser.add_argument('--output', default='', type=str, metavar='PATH', + help='path to output folder (default: none, current dir)') +parser.add_argument('--eval-metric', default='top1', type=str, metavar='EVAL_METRIC', + help='Best metric (default: "top1"') +parser.add_argument('--tta', type=int, default=0, metavar='N', + help='Test/inference time augmentation (oversampling) factor. 0=None (default: 0)') +parser.add_argument("--local_rank", default=0, type=int) +parser.add_argument('--use-multi-epochs-loader', action='store_true', default=False, + help='use the multi-epochs-loader to save time at the beginning of every epoch') +parser.add_argument('--torchscript', dest='torchscript', action='store_true', + help='convert model torchscript for inference') +parser.add_argument('--width', type=float, default=1.0, + help='Width ratio (default: 1.0)') +parser.add_argument('--dist-url', default='tcp://127.0.0.1:50000', type=str, + help='url used to set up pretained training') +parser.add_argument('--dist-backend', default='nccl', type=str, + help='distributed backend') +parser.add_argument('--npu', default=None, type=int, + help='NPU id to use.') +#modelarts +parser.add_argument('--modelarts_mod', action='store_true', default=False, + help='Enable modelarts mode loss function to train') +parser.add_argument('--train_url', + default="/cache/training", + type=str, + help="setting dir of training output") +parser.add_argument('--pretrained_weight', default='', type=str, metavar='PATH', + help='path to pretrained weight') +parser.add_argument('--onnx', default=True, action='store_true', + help="convert pth model to onnx") +parser.add_argument('--data_url', + type=str, + default='/cache/data_url', + help='the training data') + +CACHE_TRAINING_URL = "/cache/training" +def _parse_args(): + # Do we have a config file to parse? + args_config, remaining = config_parser.parse_known_args() + if args_config.config: + with open(args_config.config, 'r') as f: + cfg = yaml.safe_load(f) + parser.set_defaults(**cfg) + # The main arg parser parses the rest of the args, the usual + # defaults will have been overridden if config file specified. + args = parser.parse_args(remaining) + print(args) + # Cache the args as a text string to save them in the output dir later + args_text = yaml.safe_dump(args.__dict__, default_flow_style=False) + return args, args_text + + +def main(): + setup_default_logging() + args, args_text = _parse_args() + + args.prefetcher = not args.no_prefetcher + args.distributed = False + if args.npu is None: + args.npu = 0 + CALCULATE_DEVICE = "npu:{}".format(args.npu) + torch.npu.set_device(CALCULATE_DEVICE) + print("use ", CALCULATE_DEVICE) + + if 'WORLD_SIZE' in os.environ: + args.distributed = int(os.environ['WORLD_SIZE']) > 1 + args.device = 'npu:0' + args.world_size = 1 + args.rank = 0 # global rank + _logger.info('Training with a single process on 1 NPUs.') + assert args.rank >= 0 + + # resolve AMP arguments based on PyTorch / Apex availability + use_amp = None + if args.amp: + # for backwards compat, `--amp` arg tries apex before native amp + if has_apex: + args.apex_amp = True + elif has_native_amp: + args.native_amp = True + if args.apex_amp and has_apex: + use_amp = 'apex' + elif args.native_amp and has_native_amp: + use_amp = 'native' + elif args.apex_amp or args.native_amp: + _logger.warning("Neither APEX or native Torch AMP is available, using float32. " + "Install NVIDA apex or upgrade to PyTorch 1.6") + + torch.manual_seed(args.seed + args.rank) + model = ghostnet(num_classes=args.num_classes, width=args.width, dropout=args.drop) + + if args.pretrained: + CACHE_MODEL_URL = "/cache/model" + os.makedirs(CACHE_MODEL_URL, exist_ok=True) + mox.file.copy_parallel(args.pretrained_weight, os.path.join(CACHE_MODEL_URL, "model_best.pth.tar")) + pretrained_weight = os.path.join(CACHE_MODEL_URL, "model_best.pth.tar") + pretrained_dict = torch.load(pretrained_weight)["state_dict"] + pretrained_model = {k.replace('module.', ''): v for k, v in pretrained_dict.items()} + if "classifier.weight" in pretrained_model: + pretrained_model.pop('classifier.weight') + pretrained_model.pop('classifier.bias') + model.load_state_dict(pretrained_model, strict=False) + + for param in model.parameters(): + param.requires_grad = False + + for param in model.classifier.parameters(): + param.requires_grad = True + + if args.num_classes is None: + assert hasattr(model, 'num_classes'), 'Model must have `num_classes` attr if not set on cmd line/config.' + args.num_classes = model.num_classes # FIXME handle model default vs config num_classes more elegantly + + if args.local_rank == 0: + _logger.info('Model %s created, param count: %d' % + (args.model, sum([m.numel() for m in model.parameters()]))) + + data_config = resolve_data_config(vars(args), model=model, verbose=args.local_rank == 0) + + # setup augmentation batch splits for contrastive loss or split bn + num_aug_splits = 0 + if args.aug_splits > 0: + assert args.aug_splits > 1, 'A split of 1 makes no sense' + num_aug_splits = args.aug_splits + + # enable split bn (separate bn stats per batch-portion) + if args.split_bn: + assert num_aug_splits > 1 or args.resplit + model = convert_splitbn_model(model, max(num_aug_splits, 2)) + + # move model to GPU, enable channels last layout if set + model = model.to(CALCULATE_DEVICE) + if args.channels_last: + model = model.to(memory_format=torch.channels_last) + + if args.torchscript: + assert not use_amp == 'apex', 'Cannot use APEX AMP with torchscripted model' + assert not args.sync_bn, 'Cannot use SyncBatchNorm with torchscripted model' + model = torch.jit.script(model) + + optimizer = create_optimizer(args, model) + + # setup automatic mixed-precision (AMP) loss scaling and op casting + amp_autocast = suppress # do nothing + loss_scaler = None + if use_amp == 'apex': + model, optimizer = amp.initialize(model, optimizer, opt_level='O2', loss_scale=128) + loss_scaler = ApexScaler() + if args.local_rank == 0: + _logger.info('Using NVIDIA APEX AMP. Training in mixed precision.') + elif use_amp == 'native': + amp_autocast = torch.cuda.amp.autocast + loss_scaler = NativeScaler() + if args.local_rank == 0: + _logger.info('Using native Torch AMP. Training in mixed precision.') + else: + if args.local_rank == 0: + _logger.info('AMP not enabled. Training in float32.') + + # optionally resume from a checkpoint + resume_epoch = None + if args.resume: + resume_epoch = resume_checkpoint( + model, args.resume, + optimizer=None if args.no_resume_opt else optimizer, + loss_scaler=None if args.no_resume_opt else loss_scaler, + log_info=args.local_rank == 0) + + # setup exponential moving average of model weights, SWA could be used here too + model_ema = None + # setup learning rate schedule and starting epoch + lr_scheduler, num_epochs = create_scheduler(args, optimizer) + start_epoch = 0 + if args.start_epoch is not None: + # a specified start_epoch will always override the resume epoch + start_epoch = args.start_epoch + elif resume_epoch is not None: + start_epoch = resume_epoch + if lr_scheduler is not None and start_epoch > 0: + lr_scheduler.step(start_epoch) + + if args.local_rank == 0: + _logger.info('Scheduled epochs: {}'.format(num_epochs)) + + # create the train and eval datasets + real_path = '/cache/data_url' + if not os.path.exists(real_path): + os.makedirs(real_path) + mox.file.copy_parallel(args.data_url, real_path) + print("training data finish copy to %s." % real_path) + dataset_train = create_dataset( + args.dataset, root=real_path, split=args.train_split, is_training=True, batch_size=args.batch_size) + dataset_eval = create_dataset( + args.dataset, root=real_path, split=args.val_split, is_training=False, batch_size=args.batch_size) + # setup mixup / cutmix + collate_fn = None + mixup_fn = None + mixup_active = args.mixup > 0 or args.cutmix > 0. or args.cutmix_minmax is not None + if mixup_active: + mixup_args = dict( + mixup_alpha=args.mixup, cutmix_alpha=args.cutmix, cutmix_minmax=args.cutmix_minmax, + prob=args.mixup_prob, switch_prob=args.mixup_switch_prob, mode=args.mixup_mode, + label_smoothing=args.smoothing, num_classes=args.num_classes) + if args.prefetcher: + assert not num_aug_splits # collate conflict (need to support deinterleaving in collate mixup) + collate_fn = FastCollateMixup(**mixup_args) + else: + mixup_fn = Mixup(**mixup_args) + + # wrap dataset in AugMix helper + if num_aug_splits > 1: + dataset_train = AugMixDataset(dataset_train, num_splits=num_aug_splits) + + # create data loaders w/ augmentation pipeiine + train_interpolation = args.train_interpolation + if args.no_aug or not train_interpolation: + train_interpolation = data_config['interpolation'] + loader_train = create_loader( + dataset_train, + input_size=data_config['input_size'], + batch_size=args.batch_size, + is_training=True, + use_prefetcher=not args.no_prefetcher, + no_aug=args.no_aug, + re_count=args.recount, + re_split=args.resplit, + scale=args.scale, + ratio=args.ratio, + hflip=args.hflip, + vflip=args.vflip, + color_jitter=args.color_jitter, + num_aug_splits=num_aug_splits, + interpolation=train_interpolation, + mean=data_config['mean'], + std=data_config['std'], + num_workers=args.workers, + collate_fn=collate_fn, + pin_memory=args.pin_mem, + use_multi_epochs_loader=args.use_multi_epochs_loader + ) + + loader_eval = create_loader( + dataset_eval, + input_size=data_config['input_size'], + batch_size=args.validation_batch_size_multiplier * args.batch_size, + is_training=False, + use_prefetcher=not args.no_prefetcher, + interpolation=data_config['interpolation'], + mean=data_config['mean'], + std=data_config['std'], + num_workers=args.workers, + crop_pct=data_config['crop_pct'], + pin_memory=args.pin_mem, + ) + + # setup loss function + if args.jsd: + #assert num_aug_splits > 1 # JSD only valid with aug splits set + train_loss_fn = JsdCrossEntropy(num_splits=num_aug_splits, smoothing=args.smoothing).to(CALCULATE_DEVICE) + elif mixup_active: + # smoothing is handled with mixup target transform + train_loss_fn = SoftTargetCrossEntropy().to(CALCULATE_DEVICE) + elif args.smoothing: + train_loss_fn = LabelSmoothingCrossEntropy(smoothing=args.smoothing).to(CALCULATE_DEVICE) + else: + train_loss_fn = nn.CrossEntropyLoss().to(CALCULATE_DEVICE) + if args.modelarts_mod: + train_loss_fn = nn.CrossEntropyLoss().to(CALCULATE_DEVICE) + + validate_loss_fn = nn.CrossEntropyLoss().to(CALCULATE_DEVICE) + # setup checkpoint saver and eval metric tracking + eval_metric = args.eval_metric + best_metric = None + best_epoch = None + saver = None + output_dir = '' + if args.local_rank == 0: + output_base = args.output if args.output else './output' + exp_name = '-'.join([ + datetime.now().strftime("%Y%m%d-%H%M%S"), + args.model, + str(data_config['input_size'][-1]) + ]) + output_dir = get_outdir(output_base, 'train', exp_name) + decreasing = True if eval_metric == 'loss' else False + saver = CheckpointSaver( + model=model, optimizer=optimizer, args=args, amp_scaler=loss_scaler, + checkpoint_dir=output_dir, recovery_dir=output_dir, decreasing=decreasing, max_history=args.checkpoint_hist) + + with open(os.path.join(output_dir, 'args.yaml'), 'w') as f: + f.write(args_text) + + try: + for epoch in range(start_epoch, num_epochs): + + train_metrics = train_one_epoch( + epoch, model, loader_train, optimizer, train_loss_fn, args, + lr_scheduler=lr_scheduler, saver=saver, output_dir=output_dir, + amp_autocast=amp_autocast, loss_scaler=loss_scaler, mixup_fn=mixup_fn) + + eval_metrics = validate(model, loader_eval, validate_loss_fn, args, amp_autocast=amp_autocast) + + if lr_scheduler is not None: + # step LR for next epoch + lr_scheduler.step(epoch + 1, eval_metrics[eval_metric]) + + update_summary( + epoch, train_metrics, eval_metrics, os.path.join(output_dir, 'summary.csv'), + write_header=best_metric is None) + + if saver is not None: + # save proper checkpoint with eval metric + save_metric = eval_metrics[eval_metric] + best_metric, best_epoch = saver.save_checkpoint(epoch, metric=save_metric) + + except KeyboardInterrupt: + pass + if best_metric is not None: + _logger.info('*** Best metric: {0} (epoch {1})'.format(best_metric, best_epoch)) + + if args.onnx: + os.makedirs(CACHE_TRAINING_URL, exist_ok=True) + print("abspath:",os.path.abspath(output_dir)) + print("output_dir:",os.listdir(output_dir)) + shutil.copy(os.path.join(os.path.abspath(output_dir), 'model_best.pth.tar'), CACHE_TRAINING_URL) + pth_pattern = os.path.join(CACHE_TRAINING_URL, 'model_best.pth.tar') + print("pth_pattern:",os.path.abspath(pth_pattern)) + pth_file_list = glob.glob(pth_pattern) + if not pth_file_list: + print(f"can't find pth {pth_pattern}") + pth_file = pth_file_list[0] + onnx_path = pth_file.split(".")[0] + '.onnx' + convert(pth_file, onnx_path) + # --------------modelarts modification---------- + mox.file.copy_parallel(CACHE_TRAINING_URL, args.train_url) + # --------------modelarts modification end---------- + print("CACHE_TRAINING_URL:",os.listdir(CACHE_TRAINING_URL)) + +def train_one_epoch( + epoch, model, loader, optimizer, loss_fn, args, + lr_scheduler=None, saver=None, output_dir='', amp_autocast=suppress, + loss_scaler=None, mixup_fn=None): + if args.mixup_off_epoch and epoch >= args.mixup_off_epoch: + if args.prefetcher and loader.mixup_enabled: + loader.mixup_enabled = False + elif mixup_fn is not None: + mixup_fn.mixup_enabled = False + + second_order = hasattr(optimizer, 'is_second_order') and optimizer.is_second_order + batch_time_m = AverageMeter() + data_time_m = AverageMeter() + losses_m = AverageMeter(start_count_index=0) + + model.train() + + end = time.time() + last_idx = len(loader) - 1 + num_updates = epoch * len(loader) + for batch_idx, (input, target) in enumerate(loader): + last_batch = batch_idx == last_idx + data_time_m.update(time.time() - end) + if not args.prefetcher: + input, target = input.npu(), target.npu() + if mixup_fn is not None: + input, target = mixup_fn(input, target) + if args.channels_last: + input = input.contiguous(memory_format=torch.channels_last) + + with amp_autocast(): + output = model(input) + target = target.to(torch.int32) + loss = loss_fn(output, target) + + losses_m.update(loss.item(), input.size(0)) + + optimizer.zero_grad() + if loss_scaler is not None: + loss_scaler( + loss, optimizer, clip_grad=args.clip_grad, parameters=model.parameters(), create_graph=second_order) + else: + loss.backward(create_graph=second_order) + if args.clip_grad is not None: + torch.nn.utils.clip_grad_norm_(model.parameters(), args.clip_grad) + optimizer.step() + + num_updates += 1 + batch_time_m.update(time.time() - end) + if last_batch or batch_idx % args.log_interval == 0: + lrl = [param_group['lr'] for param_group in optimizer.param_groups] + lr = sum(lrl) / len(lrl) + + if args.local_rank == 0: + if batch_time_m.avg > 0: + _logger.info( + 'Train: {} [{:>4d}/{} ({:>3.0f}%)] ' + 'Loss: {loss.val:>9.6f} ({loss.avg:>6.4f}) ' + 'Time: {batch_time.val:.3f}s, {rate:>7.2f}/s ' + '({batch_time.avg:.3f}s, {rate_avg:>7.2f}/s) ' + 'LR: {lr:.3e} ' + 'Data: {data_time.val:.3f} ({data_time.avg:.3f})' + 'fps: {fps:.3f} ' + 'Batch_Size:{batch_size:.1f} '.format( + epoch, + batch_idx, len(loader), + 100. * batch_idx / last_idx, + loss=losses_m, + batch_time=batch_time_m, + rate=input.size(0) * args.world_size / batch_time_m.val, + rate_avg=input.size(0) * args.world_size / batch_time_m.avg, + lr=lr, + data_time=data_time_m, + fps=args.batch_size / batch_time_m.avg, + batch_size=args.batch_size)) + + if args.save_images and output_dir: + torchvision.utils.save_image( + input, + os.path.join(output_dir, 'train-batch-%d.jpg' % batch_idx), + padding=0, + normalize=True) + + if saver is not None and args.recovery_interval and ( + last_batch or (batch_idx + 1) % args.recovery_interval == 0): + saver.save_recovery(epoch, batch_idx=batch_idx) + + if lr_scheduler is not None: + lr_scheduler.step_update(num_updates=num_updates, metric=losses_m.avg) + + end = time.time() + # end for + + if hasattr(optimizer, 'sync_lookahead'): + optimizer.sync_lookahead() + + return OrderedDict([('loss', losses_m.avg)]) + + +def validate(model, loader, loss_fn, args, amp_autocast=suppress, log_suffix=''): + batch_time_m = AverageMeter() + losses_m = AverageMeter(start_count_index=0) + top1_m = AverageMeter(start_count_index=0) + top5_m = AverageMeter(start_count_index=0) + model.eval() + + end = time.time() + last_idx = len(loader) - 1 + with torch.no_grad(): + for batch_idx, (input, target) in enumerate(loader): + last_batch = batch_idx == last_idx + if args.no_prefetcher: + input = input.npu() + target = target.npu() + if args.channels_last: + input = input.contiguous(memory_format=torch.channels_last) + + with amp_autocast(): + output = model(input) + if isinstance(output, (tuple, list)): + output = output[0] + + # augmentation reduction + reduce_factor = args.tta + if reduce_factor > 1: + output = output.unfold(0, reduce_factor, reduce_factor).mean(dim=2) + target = target[0:target.size(0):reduce_factor] + + target = target.to(torch.int32) + loss = loss_fn(output, target) + acc1, acc5 = accuracy(output, target, topk=(1, 5)) + + reduced_loss = loss.data + + losses_m.update(reduced_loss.item(), input.size(0)) + top1_m.update(acc1.item(), output.size(0)) + top5_m.update(acc5.item(), output.size(0)) + + batch_time_m.update(time.time() - end) + end = time.time() + if args.local_rank == 0 and (last_batch or batch_idx % args.log_interval == 0): + if batch_time_m.avg > 0: + log_name = 'Test' + log_suffix + _logger.info( + '{0}: [{1:>4d}/{2}] ' + 'Time: {batch_time.val:.3f} ({batch_time.avg:.3f}) ' + 'Loss: {loss.val:>7.4f} ({loss.avg:>6.4f}) ' + 'Acc@1: {top1.val:>7.4f} ({top1.avg:>7.4f}) ' + 'Acc@5: {top5.val:>7.4f} ({top5.avg:>7.4f})' + 'fps: {fps:.3f} ' + 'Batch_Size:{batch_size:.1f} '.format( + log_name, batch_idx, last_idx, batch_time=batch_time_m, + loss=losses_m, top1=top1_m, top5=top5_m, fps=args.batch_size / batch_time_m.avg, + batch_size=args.batch_size)) + + metrics = OrderedDict([('loss', losses_m.avg), ('top1', top1_m.avg), ('top5', top5_m.avg)]) + + return metrics + +def proc_node_module(checkpoint, attr_name): + new_model_state = OrderedDict() + for k, v in checkpoint[attr_name].items(): + if(k[0: 7] == "module."): + name = k[7:] + else: + name = k[0:] + new_model_state[name] = v + return new_model_state + +def convert(pth_file_path, onnx_file_path): + args, args_text = _parse_args() + checkpoint = torch.load(pth_file_path, map_location='cpu') + checkpoint['state_dict'] = proc_node_module(checkpoint, 'state_dict') + model = ghostnet(num_classes=args.num_classes, width=args.width, dropout=args.drop) + model.load_state_dict(checkpoint['state_dict'], False) + model.eval() + + input_names = ["image"] + output_names = ["output1"] + dummy_input = torch.randn(2, 3, 224, 224) + torch.onnx.export(model, dummy_input, onnx_file_path, input_names=input_names, output_names=output_names, opset_version=11) + +if __name__ == '__main__': + main() + diff --git a/PyTorch/contrib/cv/classification/GhostNet/pthtar2onx.py b/PyTorch/contrib/cv/classification/GhostNet/pthtar2onx.py index bada64a75e..5d6c9459ad 100644 --- a/PyTorch/contrib/cv/classification/GhostNet/pthtar2onx.py +++ b/PyTorch/contrib/cv/classification/GhostNet/pthtar2onx.py @@ -1,47 +1,47 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 torch -import torch.onnx - -from collections import OrderedDict -from ghostnet.ghostnet_pytorch.ghostnet import ghostnet - -def proc_nodes_module(checkpoint, AttrName): - new_state_dict = OrderedDict() - for k, v in checkpoint[AttrName].items(): - if (k[0:7] == "module."): - name = k[7:] - else: - name = k[0:] - new_state_dict[name] = v - return new_state_dict - -def convert(): - checkpoint = torch.load("model_best.pth.tar", map_location='cpu') - checkpoint['state_dict'] = proc_nodes_module(checkpoint, 'state_dict') - - model = ghostnet() - model.load_state_dict(checkpoint['state_dict'], strict=False) - model.eval() - - input_names = ["image"] - output_names = ["output1"] - dummy_input = torch.randn(1, 3, 224, 224) - torch.onnx.export(model, dummy_input, "ghostnet_b.onnx", input_names=input_names, output_names=output_names, opset_version=11) - - -if __name__ == "__main__": - convert() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 torch +import torch.onnx + +from collections import OrderedDict +from ghostnet.ghostnet_pytorch.ghostnet import ghostnet + +def proc_nodes_module(checkpoint, AttrName): + new_state_dict = OrderedDict() + for k, v in checkpoint[AttrName].items(): + if (k[0:7] == "module."): + name = k[7:] + else: + name = k[0:] + new_state_dict[name] = v + return new_state_dict + +def convert(): + checkpoint = torch.load("model_best.pth.tar", map_location='cpu') + checkpoint['state_dict'] = proc_nodes_module(checkpoint, 'state_dict') + + model = ghostnet() + model.load_state_dict(checkpoint['state_dict'], strict=False) + model.eval() + + input_names = ["image"] + output_names = ["output1"] + dummy_input = torch.randn(1, 3, 224, 224) + torch.onnx.export(model, dummy_input, "ghostnet_b.onnx", input_names=input_names, output_names=output_names, opset_version=11) + + +if __name__ == "__main__": + convert() diff --git a/PyTorch/contrib/cv/classification/GhostNet/requirements.txt b/PyTorch/contrib/cv/classification/GhostNet/requirements.txt index 30a76bac06..2d29a27ced 100644 --- a/PyTorch/contrib/cv/classification/GhostNet/requirements.txt +++ b/PyTorch/contrib/cv/classification/GhostNet/requirements.txt @@ -1,3 +1,3 @@ -torch>=1.4.0 -torchvision>=0.5.0 -pyyaml +torch>=1.4.0 +torchvision>=0.5.0 +pyyaml diff --git a/PyTorch/contrib/cv/classification/GhostNet/setup.cfg b/PyTorch/contrib/cv/classification/GhostNet/setup.cfg index b1ddcb2b79..6289c6c3a1 100644 --- a/PyTorch/contrib/cv/classification/GhostNet/setup.cfg +++ b/PyTorch/contrib/cv/classification/GhostNet/setup.cfg @@ -1,5 +1,5 @@ -[dist_conda] - -conda_name_differences = 'torch:pytorch' -channels = pytorch -noarch = True +[dist_conda] + +conda_name_differences = 'torch:pytorch' +channels = pytorch +noarch = True diff --git a/PyTorch/contrib/cv/classification/GhostNet/setup.py b/PyTorch/contrib/cv/classification/GhostNet/setup.py index d0a9cfba3c..882ed467a3 100644 --- a/PyTorch/contrib/cv/classification/GhostNet/setup.py +++ b/PyTorch/contrib/cv/classification/GhostNet/setup.py @@ -1,48 +1,48 @@ -""" Setup -""" -from setuptools import setup, find_packages -from codecs import open -from os import path - -here = path.abspath(path.dirname(__file__)) - -# Get the long description from the README file -with open(path.join(here, 'README.md'), encoding='utf-8') as f: - long_description = f.read() - -exec(open('timm/version.py').read()) -setup( - name='timm', - version=__version__, - description='(Unofficial) PyTorch Image Models', - long_description=long_description, - long_description_content_type='text/markdown', - url='https://github.com/rwightman/pytorch-image-models', - author='Ross Wightman', - author_email='hello@rwightman.com', - classifiers=[ - # How mature is this project? Common values are - # 3 - Alpha - # 4 - Beta - # 5 - Production/Stable - 'Development Status :: 3 - Alpha', - 'Intended Audience :: Education', - 'Intended Audience :: Science/Research', - 'License :: OSI Approved :: Apache Software License', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Topic :: Scientific/Engineering', - 'Topic :: Scientific/Engineering :: Artificial Intelligence', - 'Topic :: Software Development', - 'Topic :: Software Development :: Libraries', - 'Topic :: Software Development :: Libraries :: Python Modules', - ], - - # Note that this is a string of words separated by whitespace, not a list. - keywords='pytorch pretrained models efficientnet mobilenetv3 mnasnet', - packages=find_packages(exclude=['convert', 'tests', 'results']), - include_package_data=True, - install_requires=['torch >= 1.4', 'torchvision'], - python_requires='>=3.6', -) +""" Setup +""" +from setuptools import setup, find_packages +from codecs import open +from os import path + +here = path.abspath(path.dirname(__file__)) + +# Get the long description from the README file +with open(path.join(here, 'README.md'), encoding='utf-8') as f: + long_description = f.read() + +exec(open('timm/version.py').read()) +setup( + name='timm', + version=__version__, + description='(Unofficial) PyTorch Image Models', + long_description=long_description, + long_description_content_type='text/markdown', + url='https://github.com/rwightman/pytorch-image-models', + author='Ross Wightman', + author_email='hello@rwightman.com', + classifiers=[ + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + 'Development Status :: 3 - Alpha', + 'Intended Audience :: Education', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: Apache Software License', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Topic :: Scientific/Engineering', + 'Topic :: Scientific/Engineering :: Artificial Intelligence', + 'Topic :: Software Development', + 'Topic :: Software Development :: Libraries', + 'Topic :: Software Development :: Libraries :: Python Modules', + ], + + # Note that this is a string of words separated by whitespace, not a list. + keywords='pytorch pretrained models efficientnet mobilenetv3 mnasnet', + packages=find_packages(exclude=['convert', 'tests', 'results']), + include_package_data=True, + install_requires=['torch >= 1.4', 'torchvision'], + python_requires='>=3.6', +) diff --git a/PyTorch/contrib/cv/classification/GhostNet/timm/loss/asymmetric_loss.py b/PyTorch/contrib/cv/classification/GhostNet/timm/loss/asymmetric_loss.py index 96a977882b..a8b10f9c79 100644 --- a/PyTorch/contrib/cv/classification/GhostNet/timm/loss/asymmetric_loss.py +++ b/PyTorch/contrib/cv/classification/GhostNet/timm/loss/asymmetric_loss.py @@ -1,97 +1,97 @@ -import torch -import torch.nn as nn - - -class AsymmetricLossMultiLabel(nn.Module): - def __init__(self, gamma_neg=4, gamma_pos=1, clip=0.05, eps=1e-8, disable_torch_grad_focal_loss=False): - super(AsymmetricLossMultiLabel, self).__init__() - - self.gamma_neg = gamma_neg - self.gamma_pos = gamma_pos - self.clip = clip - self.disable_torch_grad_focal_loss = disable_torch_grad_focal_loss - self.eps = eps - - def forward(self, x, y): - """" - Parameters - ---------- - x: input logits - y: targets (multi-label binarized vector) - """ - - # Calculating Probabilities - x_sigmoid = torch.sigmoid(x) - xs_pos = x_sigmoid - xs_neg = 1 - x_sigmoid - - # Asymmetric Clipping - if self.clip is not None and self.clip > 0: - xs_neg = (xs_neg + self.clip).clamp(max=1) - - # Basic CE calculation - los_pos = y * torch.log(xs_pos.clamp(min=self.eps)) - los_neg = (1 - y) * torch.log(xs_neg.clamp(min=self.eps)) - loss = los_pos + los_neg - - # Asymmetric Focusing - if self.gamma_neg > 0 or self.gamma_pos > 0: - if self.disable_torch_grad_focal_loss: - torch._C.set_grad_enabled(False) - pt0 = xs_pos * y - pt1 = xs_neg * (1 - y) # pt = p if t > 0 else 1-p - pt = pt0 + pt1 - one_sided_gamma = self.gamma_pos * y + self.gamma_neg * (1 - y) - one_sided_w = torch.pow(1 - pt, one_sided_gamma) - if self.disable_torch_grad_focal_loss: - torch._C.set_grad_enabled(True) - loss *= one_sided_w - - return -loss.sum() - - -class AsymmetricLossSingleLabel(nn.Module): - def __init__(self, gamma_pos=1, gamma_neg=4, eps: float = 0.1, reduction='mean'): - super(AsymmetricLossSingleLabel, self).__init__() - - self.eps = eps - self.logsoftmax = nn.LogSoftmax(dim=-1) - self.targets_classes = [] # prevent gpu repeated memory allocation - self.gamma_pos = gamma_pos - self.gamma_neg = gamma_neg - self.reduction = reduction - - def forward(self, inputs, target, reduction=None): - """" - Parameters - ---------- - x: input logits - y: targets (1-hot vector) - """ - - num_classes = inputs.size()[-1] - log_preds = self.logsoftmax(inputs) - self.targets_classes = torch.zeros_like(inputs).scatter_(1, target.long().unsqueeze(1), 1) - - # ASL weights - targets = self.targets_classes - anti_targets = 1 - targets - xs_pos = torch.exp(log_preds) - xs_neg = 1 - xs_pos - xs_pos = xs_pos * targets - xs_neg = xs_neg * anti_targets - asymmetric_w = torch.pow(1 - xs_pos - xs_neg, - self.gamma_pos * targets + self.gamma_neg * anti_targets) - log_preds = log_preds * asymmetric_w - - if self.eps > 0: # label smoothing - self.targets_classes.mul_(1 - self.eps).add_(self.eps / num_classes) - - # loss calculation - loss = - self.targets_classes.mul(log_preds) - - loss = loss.sum(dim=-1) - if self.reduction == 'mean': - loss = loss.mean() - - return loss +import torch +import torch.nn as nn + + +class AsymmetricLossMultiLabel(nn.Module): + def __init__(self, gamma_neg=4, gamma_pos=1, clip=0.05, eps=1e-8, disable_torch_grad_focal_loss=False): + super(AsymmetricLossMultiLabel, self).__init__() + + self.gamma_neg = gamma_neg + self.gamma_pos = gamma_pos + self.clip = clip + self.disable_torch_grad_focal_loss = disable_torch_grad_focal_loss + self.eps = eps + + def forward(self, x, y): + """" + Parameters + ---------- + x: input logits + y: targets (multi-label binarized vector) + """ + + # Calculating Probabilities + x_sigmoid = torch.sigmoid(x) + xs_pos = x_sigmoid + xs_neg = 1 - x_sigmoid + + # Asymmetric Clipping + if self.clip is not None and self.clip > 0: + xs_neg = (xs_neg + self.clip).clamp(max=1) + + # Basic CE calculation + los_pos = y * torch.log(xs_pos.clamp(min=self.eps)) + los_neg = (1 - y) * torch.log(xs_neg.clamp(min=self.eps)) + loss = los_pos + los_neg + + # Asymmetric Focusing + if self.gamma_neg > 0 or self.gamma_pos > 0: + if self.disable_torch_grad_focal_loss: + torch._C.set_grad_enabled(False) + pt0 = xs_pos * y + pt1 = xs_neg * (1 - y) # pt = p if t > 0 else 1-p + pt = pt0 + pt1 + one_sided_gamma = self.gamma_pos * y + self.gamma_neg * (1 - y) + one_sided_w = torch.pow(1 - pt, one_sided_gamma) + if self.disable_torch_grad_focal_loss: + torch._C.set_grad_enabled(True) + loss *= one_sided_w + + return -loss.sum() + + +class AsymmetricLossSingleLabel(nn.Module): + def __init__(self, gamma_pos=1, gamma_neg=4, eps: float = 0.1, reduction='mean'): + super(AsymmetricLossSingleLabel, self).__init__() + + self.eps = eps + self.logsoftmax = nn.LogSoftmax(dim=-1) + self.targets_classes = [] # prevent gpu repeated memory allocation + self.gamma_pos = gamma_pos + self.gamma_neg = gamma_neg + self.reduction = reduction + + def forward(self, inputs, target, reduction=None): + """" + Parameters + ---------- + x: input logits + y: targets (1-hot vector) + """ + + num_classes = inputs.size()[-1] + log_preds = self.logsoftmax(inputs) + self.targets_classes = torch.zeros_like(inputs).scatter_(1, target.long().unsqueeze(1), 1) + + # ASL weights + targets = self.targets_classes + anti_targets = 1 - targets + xs_pos = torch.exp(log_preds) + xs_neg = 1 - xs_pos + xs_pos = xs_pos * targets + xs_neg = xs_neg * anti_targets + asymmetric_w = torch.pow(1 - xs_pos - xs_neg, + self.gamma_pos * targets + self.gamma_neg * anti_targets) + log_preds = log_preds * asymmetric_w + + if self.eps > 0: # label smoothing + self.targets_classes.mul_(1 - self.eps).add_(self.eps / num_classes) + + # loss calculation + loss = - self.targets_classes.mul(log_preds) + + loss = loss.sum(dim=-1) + if self.reduction == 'mean': + loss = loss.mean() + + return loss diff --git a/PyTorch/contrib/cv/classification/GoogleNet_ID1623_for_PyTorch/modelzoo_level.txt b/PyTorch/contrib/cv/classification/GoogleNet_ID1623_for_PyTorch/modelzoo_level.txt index 484664c239..55a9add9fa 100644 --- a/PyTorch/contrib/cv/classification/GoogleNet_ID1623_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/contrib/cv/classification/GoogleNet_ID1623_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:POK \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/InceptionV4_ID1778_for_PyTorch/infer/README.md b/PyTorch/contrib/cv/classification/InceptionV4_ID1778_for_PyTorch/infer/README.md index 1d61885fec..543986bf79 100644 --- a/PyTorch/contrib/cv/classification/InceptionV4_ID1778_for_PyTorch/infer/README.md +++ b/PyTorch/contrib/cv/classification/InceptionV4_ID1778_for_PyTorch/infer/README.md @@ -1,381 +1,381 @@ -# 交付件基本信息 - -**发布者(Publisher)**:Huawei - -**应用领域(Application Domain)**:Image Classification - -**版本(Version)**:1.2 - -**修改时间(Modified)**:2021.09.10 - -**大小(Size)**:onnx/163MB \(om\) - -**框架(Framework)**:PyTorch (1.5.0) - -**模型格式(Model Format)**:pth.tar/onnx/om - -**精度(Precision)**:O2(训练)、FP16(推理) - -**处理器(Processor)**:昇腾910/昇腾310 - -**应用级别(Categories)**:Released - -**描述(Description):**基于Pytorch框架的InceptionV4图像分类网络模型训练并保存模型,通过ATC工具转换,可在昇腾AI设备上运行 - -**CANN 版本**: CANN 5.0.2 B058 - -**Python 版本**: Python 3.7.5 - -**操作系统版本**: Ubuntu 18.04 - -# 推理 - -### 操作步骤 - -1. 单击“下载模型脚本”和“下载模型”,下载所需软件包。 - - - - ![img](https://r.huaweistatic.com/s/ascendstatic/lst/modelZooImg/public_sys-resources/note_3.0-zh-cn.png) - - - 下载模型脚本:下载训练和推理的脚本文件。 - - 下载模型:下载模型文件。 - - - -2. 将源码上传至推理服务器任意目录并解压(如:“/home/test”)。 - - - - ``` - # 在环境上执行 - unzip InceptionV4_ID1778_for_PyTorch.zip - cd {code_unzip_path}/InceptionV4_ID1778_for_PyTorch/infer - ``` - - ![img](https://r.huaweistatic.com/s/ascendstatic/lst/modelZooImg/public_sys-resources/note_3.0-zh-cn.png) - - - code_unzip_path:代码解压目录,以“/home/test”为例。 - - version:为模型版本。 - - - - - -3. 数据准备。 - - - - 由于后续推理均在容器中进行,因此需要把用于推理的图片、数据集、模型文件、代码等均映射到容器中 - - ``` - /home/data - ├── imagenet_val # 推理图片用于精度测试的数据集 - │ ├── ILSVRC2012_val_00016652.JPEG - │ └── ILSVRC2012_val_00024989.JPEG - ``` - - - - - -4. 文件格式转换 - - ``` - find ./ -name "*.sh" | xargs dos2unix - ``` - - - -5. 启动容器 - - - 进入到代码根目录,执行以下命令,启动容器。 - - **bash scripts/docker_start_infer.sh** *infer_image* *data_path* - - | 参数 | 说明 | - | ------------- | ----------------------------- | - | *infer_image* | 推理镜像名称,根据实际写入。 | - | *data_path* | 数据路径。如:“/home/test/”。 | - - 启动容器时会将推理芯片和数据路径挂载到容器中。 - - ``` - # 切换到代码跟目录下 - cd /home/path/to/InceptionV4_ID1778_for_PyTorch/ - bash scripts/docker_start_infer.sh infer:21.0.1 /home/path/to/path - ``` - -## 模型转换 - -### 前提条件 - -已进入推理容器环境。具体操作请参见“准备容器环境”。 - -### 操作步骤 - -1. 准备onnx模型文件。 - - - - onnx模型为在昇腾910服务器上导出的模型,导出onnx模型的详细步骤请参见“模型训练”。 - - 将模型文件保存在/path/to/InceptionV4_ID1778_for_PyTorch/infer/data 路径下 - - - -2. 执行以下命令,进行模型转换。 - - - - 模型转换时,可选择不同的AIPP配置文件进行转换。转换详细信息可查看转换脚本和对应的AIPP配置文件,转换命令如下。 - - **bash convert/onnx2om.sh** model_path output_model_name - - | 参数 | 说明 | - | ----------------- | ------------------------------------------------- | - | model_path | 转换脚本onnx文件路径。 | - | output_model_name | 生成的OM文件名,转换脚本会在此基础上添加.om后缀。 | - - 转换示例如下所示。 - - ``` - bash convert/onnx2om.sh ./data/InceptionV4_npu_1.onnx data/InceptionV4-pt - ``` - -## mxBase推理 - -### 前提条件 - -已进入推理容器环境。具体操作请参见“准备容器环境”。 - -### 操作步骤 - -1. 配置环境变量。 - - ``` - export ASCEND_HOME=/usr/local/Ascend - export ASCEND_VERSION=nnrt/latest - export ARCH_PATTERN=. - export LD_LIBRARY_PATH=${MX_SDK_HOME}/lib/modelpostprocessors:${LD_LIBRARY_PATH} - ``` - - - -2. 修改配置文件。 - - - - 可根据实际情况修改,配置文件位于“mxbase/src/main.cpp”中,可修改参数如下。 - - 若使用迁移学习生成的模型进行推理,请修改CLASS_NUM为迁移学习训练任务数据集的类别数量。如:修改CLASS_NUM=1001;om的模型路径;labelPath的路径 - - ``` - ... - namespace { - - const uint32_t CLASS_NUM = 1001; // 推理类别总数 - } - int main(int argc, char* argv[]){ - .... - initParam.labelPath = "../data/imagenet1000_clsidx_to_labels.names"; - initParam.topk = 5; - initParam.softmax = false; - initParam.checkTensor = true; - initParam.modelPath = "../data/inception-pt.om"; - .... - } - ... - ``` - - - -3. 编译工程。 - - ``` - cd /home/path/to/InceptionV4_ID1778_for_PyTorch/infer/mxbase - bash build.sh - ``` - -4. 运行推理服务 - - - - **./build/inceptionv4 *image_path* - - | 参数 | 说明 | - | ---------- | ---------------------------------------------- | - | image_path | 推理图片所在文件的路径。如:“../data/images”。 | - - - -5. 观察结果。 - - 分类结果会以*.txt的格式保存在result文件中。 - - ![image-20210929155913474](./image/image-20210929155913474.png) - - - -## MindX SDK 推理 - -### 前提条件 - -已进入推理容器环境。具体操作请参见“准备容器环境”。 - -### 操作步骤 - -1. 修改配置文件。可根据实际情况修改pipeline文件。 - - ``` - vim ../data/inceptionv4_opencv.pipeline - ``` - - 以inceptionv4_opencv.pipeline文件为例,作简要说明。 - - ``` - { - "im_inceptionv4": { - "stream_config": { - "deviceId": "0" # 指定推理卡,要与挂载到容器中的卡一致 - }, - "appsrc0": { - "props": { - "blocksize": "409600" - }, - "factory": "appsrc", - "next": "mxpi_imagedecoder0" - }, - ""mxpi_imagedecoder0"": { - "props": { - "handleMethod": "opencv" - }, - "factory": "mxpi_imagedecoder", - "next": "mxpi_imageresize0" - }, - "mxpi_imageresize0": { - "props": { - "handleMethod": "opencv", - "resizeHeight": "355", - "resizeWidth": "355", - "resizeType": "Resizer_Stretch" - }, - "factory": "mxpi_imageresize", - "next": "mxpi_opencvcentercrop0" - }, - "mxpi_opencvcentercrop0": { - "props": { - "dataSource": "mxpi_imageresize0", - "cropHeight": "299", - "cropWidth": "299" - }, - "factory": "mxpi_opencvcentercrop", - "next": "mxpi_tensorinfer0" - }, - - "mxpi_tensorinfer0": { - "props": { - "dataSource": "mxpi_opencvcentercrop0", - "modelPath": "../data/inceptionV4_pt_cfg.om", #模型存放路径 - "waitingTime": "2000", - "outputDeviceId": "-1" - }, - "factory": "mxpi_tensorinfer", - "next": "mxpi_classpostprocessor0" - }, - "mxpi_classpostprocessor0": { - "props": { - "dataSource": "mxpi_tensorinfer0", - "postProcessConfigPath": "../data/inceptionv4_aipp.cfg", #后处理的配置文件 - "labelPath": "../data/imagenet1000_clsidx_to_labels.names", #标签路径 - "postProcessLibPath": "../../../../mxVision-2.0.2/lib/modelpostprocessors/libresnet50postprocess.so" #后处理模块 - }, - "factory": "mxpi_classpostprocessor", - "next": "mxpi_dataserialize0" - }, - - .... - } - } - ``` - - - -2. 运行推理服务。 - - ``` - cd infer/sdk - bash run.sh /path/to/testImageDir /path/to/saveResultDir - ``` - - setp 1、查看推理结果。 - - 若设置推理结果路径为“infer/sdk/result”,示例如下所示。 - - ``` - root@97a4c6ab6482:/home/path/to/InceptionV4_ID1778_for_PyTorch/infer/sdk/result# ll - -rw-r--r-- 1 root root 21 Aug 24 07:09 ILSVRC2012_val_00042663_1.txt - -rw-r--r-- 1 root root 21 Aug 24 07:09 ILSVRC2012_val_00042820_1.txt - -rw-r--r-- 1 root root 21 Aug 24 07:09 ILSVRC2012_val_00042855_1.txt - -rw-r--r-- 1 root root 21 Aug 24 07:09 ILSVRC2012_val_00043055_1.txt - -rw-r--r-- 1 root root 21 Aug 24 07:09 ILSVRC2012_val_00043439_1.txt - -rw-r--r-- 1 root root 21 Aug 24 07:09 ILSVRC2012_val_00044460_1.txt - ``` - -3. 性能统计 - - step 1、打开性能统计开关。将“enable_ps”参数设置为true,“ps_interval_time”参数设置为6 - - **vi** */home/HwHiAiUser/mxManufacture/config/sdk.conf* - - ``` - # MindX SDK configuration file - - # whether to enable performance statistics, default is false [dynamic config] - - enable_ps=true - ... - ps_interval_time=6 - ... - ``` - - step 2、执行run.sh脚本。 - - ``` - cd infer/sdk - bash run.sh /path/to/testImageDir /path/to/saveResultDir - ``` - - step 3、在日志目录 “/home/HwHiAiUser/mxManufacture/logs/” 查看性能统计结果。 - - ``` - performance—statistics.log.e2e.xxx - performance—statistics.log.plugin.xxx - performance—statistics.log.tpr.xxx - ``` - - 其中e2e日志统计端到端时间,plugin日志统计单插件时间。 - -4. 执行精度测试。 - - 精度结果是在imageNet上进行的,使用classification_task_metric.py 进行测试。修改classification_task_metric.py - -``` -python3.7 classfication_task_metric.py result/ ./val_label.txt . ./result.json" -``` - -参数 1 : prediction file path -参数 2 : ground truth file -参数 3 : result store path -参数 4 : json file name - -查看精度结果。 - -``` -cat result.json -``` - - - -![image-20210929111906059](./image/image-20210929111906059.png) +# 交付件基本信息 + +**发布者(Publisher)**:Huawei + +**应用领域(Application Domain)**:Image Classification + +**版本(Version)**:1.2 + +**修改时间(Modified)**:2021.09.10 + +**大小(Size)**:onnx/163MB \(om\) + +**框架(Framework)**:PyTorch (1.5.0) + +**模型格式(Model Format)**:pth.tar/onnx/om + +**精度(Precision)**:O2(训练)、FP16(推理) + +**处理器(Processor)**:昇腾910/昇腾310 + +**应用级别(Categories)**:Released + +**描述(Description):**基于Pytorch框架的InceptionV4图像分类网络模型训练并保存模型,通过ATC工具转换,可在昇腾AI设备上运行 + +**CANN 版本**: CANN 5.0.2 B058 + +**Python 版本**: Python 3.7.5 + +**操作系统版本**: Ubuntu 18.04 + +# 推理 + +### 操作步骤 + +1. 单击“下载模型脚本”和“下载模型”,下载所需软件包。 + + + + ![img](https://r.huaweistatic.com/s/ascendstatic/lst/modelZooImg/public_sys-resources/note_3.0-zh-cn.png) + + - 下载模型脚本:下载训练和推理的脚本文件。 + - 下载模型:下载模型文件。 + + + +2. 将源码上传至推理服务器任意目录并解压(如:“/home/test”)。 + + + + ``` + # 在环境上执行 + unzip InceptionV4_ID1778_for_PyTorch.zip + cd {code_unzip_path}/InceptionV4_ID1778_for_PyTorch/infer + ``` + + ![img](https://r.huaweistatic.com/s/ascendstatic/lst/modelZooImg/public_sys-resources/note_3.0-zh-cn.png) + + - code_unzip_path:代码解压目录,以“/home/test”为例。 + - version:为模型版本。 + + + + + +3. 数据准备。 + + + + 由于后续推理均在容器中进行,因此需要把用于推理的图片、数据集、模型文件、代码等均映射到容器中 + + ``` + /home/data + ├── imagenet_val # 推理图片用于精度测试的数据集 + │ ├── ILSVRC2012_val_00016652.JPEG + │ └── ILSVRC2012_val_00024989.JPEG + ``` + + + + + +4. 文件格式转换 + + ``` + find ./ -name "*.sh" | xargs dos2unix + ``` + + + +5. 启动容器 + + + 进入到代码根目录,执行以下命令,启动容器。 + + **bash scripts/docker_start_infer.sh** *infer_image* *data_path* + + | 参数 | 说明 | + | ------------- | ----------------------------- | + | *infer_image* | 推理镜像名称,根据实际写入。 | + | *data_path* | 数据路径。如:“/home/test/”。 | + + 启动容器时会将推理芯片和数据路径挂载到容器中。 + + ``` + # 切换到代码跟目录下 + cd /home/path/to/InceptionV4_ID1778_for_PyTorch/ + bash scripts/docker_start_infer.sh infer:21.0.1 /home/path/to/path + ``` + +## 模型转换 + +### 前提条件 + +已进入推理容器环境。具体操作请参见“准备容器环境”。 + +### 操作步骤 + +1. 准备onnx模型文件。 + + + + onnx模型为在昇腾910服务器上导出的模型,导出onnx模型的详细步骤请参见“模型训练”。 + + 将模型文件保存在/path/to/InceptionV4_ID1778_for_PyTorch/infer/data 路径下 + + + +2. 执行以下命令,进行模型转换。 + + + + 模型转换时,可选择不同的AIPP配置文件进行转换。转换详细信息可查看转换脚本和对应的AIPP配置文件,转换命令如下。 + + **bash convert/onnx2om.sh** model_path output_model_name + + | 参数 | 说明 | + | ----------------- | ------------------------------------------------- | + | model_path | 转换脚本onnx文件路径。 | + | output_model_name | 生成的OM文件名,转换脚本会在此基础上添加.om后缀。 | + + 转换示例如下所示。 + + ``` + bash convert/onnx2om.sh ./data/InceptionV4_npu_1.onnx data/InceptionV4-pt + ``` + +## mxBase推理 + +### 前提条件 + +已进入推理容器环境。具体操作请参见“准备容器环境”。 + +### 操作步骤 + +1. 配置环境变量。 + + ``` + export ASCEND_HOME=/usr/local/Ascend + export ASCEND_VERSION=nnrt/latest + export ARCH_PATTERN=. + export LD_LIBRARY_PATH=${MX_SDK_HOME}/lib/modelpostprocessors:${LD_LIBRARY_PATH} + ``` + + + +2. 修改配置文件。 + + + + 可根据实际情况修改,配置文件位于“mxbase/src/main.cpp”中,可修改参数如下。 + + 若使用迁移学习生成的模型进行推理,请修改CLASS_NUM为迁移学习训练任务数据集的类别数量。如:修改CLASS_NUM=1001;om的模型路径;labelPath的路径 + + ``` + ... + namespace { + + const uint32_t CLASS_NUM = 1001; // 推理类别总数 + } + int main(int argc, char* argv[]){ + .... + initParam.labelPath = "../data/imagenet1000_clsidx_to_labels.names"; + initParam.topk = 5; + initParam.softmax = false; + initParam.checkTensor = true; + initParam.modelPath = "../data/inception-pt.om"; + .... + } + ... + ``` + + + +3. 编译工程。 + + ``` + cd /home/path/to/InceptionV4_ID1778_for_PyTorch/infer/mxbase + bash build.sh + ``` + +4. 运行推理服务 + + + + **./build/inceptionv4 *image_path* + + | 参数 | 说明 | + | ---------- | ---------------------------------------------- | + | image_path | 推理图片所在文件的路径。如:“../data/images”。 | + + + +5. 观察结果。 + + 分类结果会以*.txt的格式保存在result文件中。 + + ![image-20210929155913474](./image/image-20210929155913474.png) + + + +## MindX SDK 推理 + +### 前提条件 + +已进入推理容器环境。具体操作请参见“准备容器环境”。 + +### 操作步骤 + +1. 修改配置文件。可根据实际情况修改pipeline文件。 + + ``` + vim ../data/inceptionv4_opencv.pipeline + ``` + + 以inceptionv4_opencv.pipeline文件为例,作简要说明。 + + ``` + { + "im_inceptionv4": { + "stream_config": { + "deviceId": "0" # 指定推理卡,要与挂载到容器中的卡一致 + }, + "appsrc0": { + "props": { + "blocksize": "409600" + }, + "factory": "appsrc", + "next": "mxpi_imagedecoder0" + }, + ""mxpi_imagedecoder0"": { + "props": { + "handleMethod": "opencv" + }, + "factory": "mxpi_imagedecoder", + "next": "mxpi_imageresize0" + }, + "mxpi_imageresize0": { + "props": { + "handleMethod": "opencv", + "resizeHeight": "355", + "resizeWidth": "355", + "resizeType": "Resizer_Stretch" + }, + "factory": "mxpi_imageresize", + "next": "mxpi_opencvcentercrop0" + }, + "mxpi_opencvcentercrop0": { + "props": { + "dataSource": "mxpi_imageresize0", + "cropHeight": "299", + "cropWidth": "299" + }, + "factory": "mxpi_opencvcentercrop", + "next": "mxpi_tensorinfer0" + }, + + "mxpi_tensorinfer0": { + "props": { + "dataSource": "mxpi_opencvcentercrop0", + "modelPath": "../data/inceptionV4_pt_cfg.om", #模型存放路径 + "waitingTime": "2000", + "outputDeviceId": "-1" + }, + "factory": "mxpi_tensorinfer", + "next": "mxpi_classpostprocessor0" + }, + "mxpi_classpostprocessor0": { + "props": { + "dataSource": "mxpi_tensorinfer0", + "postProcessConfigPath": "../data/inceptionv4_aipp.cfg", #后处理的配置文件 + "labelPath": "../data/imagenet1000_clsidx_to_labels.names", #标签路径 + "postProcessLibPath": "../../../../mxVision-2.0.2/lib/modelpostprocessors/libresnet50postprocess.so" #后处理模块 + }, + "factory": "mxpi_classpostprocessor", + "next": "mxpi_dataserialize0" + }, + + .... + } + } + ``` + + + +2. 运行推理服务。 + + ``` + cd infer/sdk + bash run.sh /path/to/testImageDir /path/to/saveResultDir + ``` + + setp 1、查看推理结果。 + + 若设置推理结果路径为“infer/sdk/result”,示例如下所示。 + + ``` + root@97a4c6ab6482:/home/path/to/InceptionV4_ID1778_for_PyTorch/infer/sdk/result# ll + -rw-r--r-- 1 root root 21 Aug 24 07:09 ILSVRC2012_val_00042663_1.txt + -rw-r--r-- 1 root root 21 Aug 24 07:09 ILSVRC2012_val_00042820_1.txt + -rw-r--r-- 1 root root 21 Aug 24 07:09 ILSVRC2012_val_00042855_1.txt + -rw-r--r-- 1 root root 21 Aug 24 07:09 ILSVRC2012_val_00043055_1.txt + -rw-r--r-- 1 root root 21 Aug 24 07:09 ILSVRC2012_val_00043439_1.txt + -rw-r--r-- 1 root root 21 Aug 24 07:09 ILSVRC2012_val_00044460_1.txt + ``` + +3. 性能统计 + + step 1、打开性能统计开关。将“enable_ps”参数设置为true,“ps_interval_time”参数设置为6 + + **vi** */home/HwHiAiUser/mxManufacture/config/sdk.conf* + + ``` + # MindX SDK configuration file + + # whether to enable performance statistics, default is false [dynamic config] + + enable_ps=true + ... + ps_interval_time=6 + ... + ``` + + step 2、执行run.sh脚本。 + + ``` + cd infer/sdk + bash run.sh /path/to/testImageDir /path/to/saveResultDir + ``` + + step 3、在日志目录 “/home/HwHiAiUser/mxManufacture/logs/” 查看性能统计结果。 + + ``` + performance—statistics.log.e2e.xxx + performance—statistics.log.plugin.xxx + performance—statistics.log.tpr.xxx + ``` + + 其中e2e日志统计端到端时间,plugin日志统计单插件时间。 + +4. 执行精度测试。 + + 精度结果是在imageNet上进行的,使用classification_task_metric.py 进行测试。修改classification_task_metric.py + +``` +python3.7 classfication_task_metric.py result/ ./val_label.txt . ./result.json" +``` + +参数 1 : prediction file path +参数 2 : ground truth file +参数 3 : result store path +参数 4 : json file name + +查看精度结果。 + +``` +cat result.json +``` + + + +![image-20210929111906059](./image/image-20210929111906059.png) diff --git a/PyTorch/contrib/cv/classification/InceptionV4_ID1778_for_PyTorch/infer/sdk/classification_task_metric.py b/PyTorch/contrib/cv/classification/InceptionV4_ID1778_for_PyTorch/infer/sdk/classification_task_metric.py index 22385f773a..3987002029 100644 --- a/PyTorch/contrib/cv/classification/InceptionV4_ID1778_for_PyTorch/infer/sdk/classification_task_metric.py +++ b/PyTorch/contrib/cv/classification/InceptionV4_ID1778_for_PyTorch/infer/sdk/classification_task_metric.py @@ -1,188 +1,188 @@ -#coding = utf-8 -#Copyright 2020 Huawei Technologies Co., Ltd -# -#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 os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - img_name = temp[0].split(".")[0] - img_lab = temp[1] - img_gt_dict[img_name] = img_lab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, cls_ind in enumerate(temp): - data_vec[ind] = np.int32(cls_ind) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - res_cnt = 0 - n_labels = "" - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - - ret = load_statistical_predict_result(filepath) - #print("img_name:{}, filepath:{}, ret:{} ".format(img_name, filepath, ret)) - prediction = ret[0] - n_labels = ret[1] - - gt = img_gt_dict[img_name] - #print("gt:", gt) - if n_labels == 1000: - real_label = int(gt) - elif n_labels == 1001: - real_label = int(gt) + 1 - else: - real_label = int(gt) - 1 - - res_cnt = min(len(prediction), topn) - for i in range(res_cnt): - if str(real_label) == str(int(prediction[i])): - count_hit[i] += 1 - break - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(res_cnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Please enter target file folder | groud truth file | result folder | result json file name, such as" - "Such as: python3.7 classfication_task_metric.py result/ ./val_label.txt . ./result.json") - exit(1) - - if not os.path.exists(folder_davinci_target): - print("target file folder does not exist.") - exit() - - if not os.path.exists(annotation_file_path): - - print("Ground truth file does not exist.") - exit() - - if not os.path.exists(result_json_path): - print("Result folder doesn't exist.") - exit() - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) +#coding = utf-8 +#Copyright 2020 Huawei Technologies Co., Ltd +# +#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 os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + img_name = temp[0].split(".")[0] + img_lab = temp[1] + img_gt_dict[img_name] = img_lab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, cls_ind in enumerate(temp): + data_vec[ind] = np.int32(cls_ind) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + res_cnt = 0 + n_labels = "" + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + + ret = load_statistical_predict_result(filepath) + #print("img_name:{}, filepath:{}, ret:{} ".format(img_name, filepath, ret)) + prediction = ret[0] + n_labels = ret[1] + + gt = img_gt_dict[img_name] + #print("gt:", gt) + if n_labels == 1000: + real_label = int(gt) + elif n_labels == 1001: + real_label = int(gt) + 1 + else: + real_label = int(gt) - 1 + + res_cnt = min(len(prediction), topn) + for i in range(res_cnt): + if str(real_label) == str(int(prediction[i])): + count_hit[i] += 1 + break + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(res_cnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Please enter target file folder | groud truth file | result folder | result json file name, such as" + "Such as: python3.7 classfication_task_metric.py result/ ./val_label.txt . ./result.json") + exit(1) + + if not os.path.exists(folder_davinci_target): + print("target file folder does not exist.") + exit() + + if not os.path.exists(annotation_file_path): + + print("Ground truth file does not exist.") + exit() + + if not os.path.exists(result_json_path): + print("Result folder doesn't exist.") + exit() + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) diff --git a/PyTorch/contrib/cv/classification/MGN/README.md b/PyTorch/contrib/cv/classification/MGN/README.md index 4cb4c8a500..65b55576c8 100644 --- a/PyTorch/contrib/cv/classification/MGN/README.md +++ b/PyTorch/contrib/cv/classification/MGN/README.md @@ -1,58 +1,58 @@ -# MGN - -This implements training of MGN on the Market-1501 dataset, mainly modified from [GNAYUOHZ/ReID-MGN](https://github.com/GNAYUOHZ/ReID-MGN). - -## MGN Detail - -As of the current date, Ascend-Pytorch is still inefficient for contiguous operations.Therefore, MGN is re-implemented using semantics such as custom OP. - - -## Requirements - -- Install PyTorch ([pytorch.org](http://pytorch.org)) - -- `pip install -r requirements.txt` - -- Download the Market-1501 dataset from https://paperswithcode.com/dataset/market-1501 - - - ~~~shell - unzip Market-1501-v15.09.15.zip - ~~~ - -## Training - -To train a model, run `main.py` with the desired model architecture and the path to the market dataset: - -```bash -# training 1p accuracy -bash test/train_full_1p.sh --data_path=real_data_path - -# training 1p performance -bash test/train_performance_1p.sh --data_path=real_data_path - -# training 8p accuracy -bash test/train_full_8p.sh --data_path=real_data_path - -# training 8p performance -bash test/train_performance_8p.sh --data_path=real_data_path - -# finetune -bash test/train_finetune_1p.sh --data_path=real_data_path --weights=real_weight_path - -# Online inference demo -python demo.py --data_path real_data_path - -# To ONNX -python pthtar2onnx.py -``` - -## MGN training result - - -| | mAP | AMP_Type | Epochs | FPS | -| :----: | :---: | :------: | :----: | :-----: | -| 1p-GPU | - | O2 | 1 | 71.408 | -| 1p-NPU | - | O2 | 1 | 29.408 | -| 8p-GPU | 93.35 | O2 | 500 | 771.818 | -| 8p-NPU | 93.83 | O2 | 500 | 200.024 | - +# MGN + +This implements training of MGN on the Market-1501 dataset, mainly modified from [GNAYUOHZ/ReID-MGN](https://github.com/GNAYUOHZ/ReID-MGN). + +## MGN Detail + +As of the current date, Ascend-Pytorch is still inefficient for contiguous operations.Therefore, MGN is re-implemented using semantics such as custom OP. + + +## Requirements + +- Install PyTorch ([pytorch.org](http://pytorch.org)) + +- `pip install -r requirements.txt` + +- Download the Market-1501 dataset from https://paperswithcode.com/dataset/market-1501 + + - ~~~shell + unzip Market-1501-v15.09.15.zip + ~~~ + +## Training + +To train a model, run `main.py` with the desired model architecture and the path to the market dataset: + +```bash +# training 1p accuracy +bash test/train_full_1p.sh --data_path=real_data_path + +# training 1p performance +bash test/train_performance_1p.sh --data_path=real_data_path + +# training 8p accuracy +bash test/train_full_8p.sh --data_path=real_data_path + +# training 8p performance +bash test/train_performance_8p.sh --data_path=real_data_path + +# finetune +bash test/train_finetune_1p.sh --data_path=real_data_path --weights=real_weight_path + +# Online inference demo +python demo.py --data_path real_data_path + +# To ONNX +python pthtar2onnx.py +``` + +## MGN training result + + +| | mAP | AMP_Type | Epochs | FPS | +| :----: | :---: | :------: | :----: | :-----: | +| 1p-GPU | - | O2 | 1 | 71.408 | +| 1p-NPU | - | O2 | 1 | 29.408 | +| 8p-GPU | 93.35 | O2 | 500 | 771.818 | +| 8p-NPU | 93.83 | O2 | 500 | 200.024 | + diff --git a/PyTorch/contrib/cv/classification/MnasNet/infer/convert/aipp.aipconfig b/PyTorch/contrib/cv/classification/MnasNet/infer/convert/aipp.aipconfig old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MnasNet/infer/convert/onnx2om.sh b/PyTorch/contrib/cv/classification/MnasNet/infer/convert/onnx2om.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MnasNet/infer/mxbase/CMakeLists.txt b/PyTorch/contrib/cv/classification/MnasNet/infer/mxbase/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MnasNet/infer/mxbase/Mnasnet.cpp b/PyTorch/contrib/cv/classification/MnasNet/infer/mxbase/Mnasnet.cpp old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MnasNet/infer/mxbase/Mnasnet.h b/PyTorch/contrib/cv/classification/MnasNet/infer/mxbase/Mnasnet.h old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MnasNet/infer/mxbase/build.sh b/PyTorch/contrib/cv/classification/MnasNet/infer/mxbase/build.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MnasNet/infer/mxbase/main.cpp b/PyTorch/contrib/cv/classification/MnasNet/infer/mxbase/main.cpp old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MnasNet/infer/mxbase/run.sh b/PyTorch/contrib/cv/classification/MnasNet/infer/mxbase/run.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MnasNet/infer/sdk/main.py b/PyTorch/contrib/cv/classification/MnasNet/infer/sdk/main.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MnasNet/infer/sdk/mnasnet_aipp.cfg b/PyTorch/contrib/cv/classification/MnasNet/infer/sdk/mnasnet_aipp.cfg old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MnasNet/infer/sdk/mnasnet_opencv.pipeline b/PyTorch/contrib/cv/classification/MnasNet/infer/sdk/mnasnet_opencv.pipeline old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MnasNet/infer/sdk/run.sh b/PyTorch/contrib/cv/classification/MnasNet/infer/sdk/run.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MnasNet/infer/util/classification_task_metric.py b/PyTorch/contrib/cv/classification/MnasNet/infer/util/classification_task_metric.py old mode 100755 new mode 100644 index 972b7fa0ec..089aee8a40 --- a/PyTorch/contrib/cv/classification/MnasNet/infer/util/classification_task_metric.py +++ b/PyTorch/contrib/cv/classification/MnasNet/infer/util/classification_task_metric.py @@ -1,186 +1,186 @@ -# coding = utf-8 -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import json -import numpy as np -import time - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def gen_file_name(img_name): - full_name = img_name.split('/')[-1] - index = full_name.rfind('.') - return full_name[:index] - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if (gtfile != LABEL_FILE): - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - ret = gt["image"]["annotations"][0]["category_id"] - img_gt_dict[gen_file_name(gtfile)] = ret - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - temp = line.strip().split(" ") - img_name = temp[0].split(".")[0] - img_lab = temp[1] - img_gt_dict[img_name] = img_lab - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label, in_type, color - """ - with open(filepath, 'r')as f: - data = f.readline() - temp = data.strip().split(" ") - n_label = len(temp) - data_vec = np.zeros((n_label), dtype=np.float32) - in_type = '' - color = '' - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, cls_ind in enumerate(temp): - data_vec[ind] = np.int32(cls_ind) - return data_vec, n_label, in_type, color - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - res_cnt = 0 - n_labels = "" - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - - ret = load_statistical_predict_result(filepath) - - prediction = ret[0] - n_labels = ret[1] - gt = img_gt_dict[img_name] - if n_labels == 1000: - real_label = int(gt) - elif n_labels == 1001: - real_label = int(gt) + 1 - else: - real_label = int(gt) - 1 - - res_cnt = min(len(prediction), topn) - for i in range(res_cnt): - if str(real_label) == str(int(prediction[i])): - count_hit[i] += 1 - break - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - if count == 0: - accuracy = 0 - else: - accuracy = np.cumsum(count_hit) / count - for i in range(res_cnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - start = time.time() - try: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - except IndexError: - print("Please enter target file folder | groud truth file | result folder | result json file name, such as" - "Such as: python3.7 classfication_task_metric.py result/ ./val_label.txt . ./result.json") - exit(1) - - if not os.path.exists(folder_davinci_target): - print("target file folder does not exist.") - exit() - - if not os.path.exists(annotation_file_path): - - print("Ground truth file does not exist.") - exit() - - if not os.path.exists(result_json_path): - print("Result folder doesn't exist.") - exit() - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - - elapsed = (time.time() - start) +# coding = utf-8 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import json +import numpy as np +import time + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def gen_file_name(img_name): + full_name = img_name.split('/')[-1] + index = full_name.rfind('.') + return full_name[:index] + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if (gtfile != LABEL_FILE): + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + ret = gt["image"]["annotations"][0]["category_id"] + img_gt_dict[gen_file_name(gtfile)] = ret + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + temp = line.strip().split(" ") + img_name = temp[0].split(".")[0] + img_lab = temp[1] + img_gt_dict[img_name] = img_lab + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label, in_type, color + """ + with open(filepath, 'r')as f: + data = f.readline() + temp = data.strip().split(" ") + n_label = len(temp) + data_vec = np.zeros((n_label), dtype=np.float32) + in_type = '' + color = '' + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, cls_ind in enumerate(temp): + data_vec[ind] = np.int32(cls_ind) + return data_vec, n_label, in_type, color + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + res_cnt = 0 + n_labels = "" + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + + ret = load_statistical_predict_result(filepath) + + prediction = ret[0] + n_labels = ret[1] + gt = img_gt_dict[img_name] + if n_labels == 1000: + real_label = int(gt) + elif n_labels == 1001: + real_label = int(gt) + 1 + else: + real_label = int(gt) - 1 + + res_cnt = min(len(prediction), topn) + for i in range(res_cnt): + if str(real_label) == str(int(prediction[i])): + count_hit[i] += 1 + break + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + if count == 0: + accuracy = 0 + else: + accuracy = np.cumsum(count_hit) / count + for i in range(res_cnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + start = time.time() + try: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + except IndexError: + print("Please enter target file folder | groud truth file | result folder | result json file name, such as" + "Such as: python3.7 classfication_task_metric.py result/ ./val_label.txt . ./result.json") + exit(1) + + if not os.path.exists(folder_davinci_target): + print("target file folder does not exist.") + exit() + + if not os.path.exists(annotation_file_path): + + print("Ground truth file does not exist.") + exit() + + if not os.path.exists(result_json_path): + print("Result folder doesn't exist.") + exit() + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + + elapsed = (time.time() - start) diff --git a/PyTorch/contrib/cv/classification/MnasNet/modelArts/pth2onnx.py b/PyTorch/contrib/cv/classification/MnasNet/modelArts/pth2onnx.py index 2dece3cb8d..f86ce4b281 100644 --- a/PyTorch/contrib/cv/classification/MnasNet/modelArts/pth2onnx.py +++ b/PyTorch/contrib/cv/classification/MnasNet/modelArts/pth2onnx.py @@ -1,98 +1,98 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 argparse -import os -import random -import shutil -import time -import warnings -import math -import glob -import numpy as np -import sys - -import torch -import torch.npu -import torch.nn as nn -from collections import OrderedDict -import torch.onnx -sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '../')) -import mnasnet - -# modelarts modification -import moxing as mox - - -CACHE_TRAINING_URL = "/cache/training" -CACHE_MODEL_URL = "/cache/model" - -def proc_node_module(checkpoint, AttrName): - new_state_dict = OrderedDict() - for k, v in checkpoint[AttrName].items(): - if k[0:7] == "module.": - name = k[7:] - else: - name = k[0:] - new_state_dict[name] = v - return new_state_dict - - -def convert(pth_file, onnx_path, class_num, train_url, npu): - - loc = 'npu:{}'.format(npu) - checkpoint = torch.load(pth_file, map_location=loc) - - checkpoint['state_dict'] = proc_node_module(checkpoint, 'state_dict') - model = mnasnet.mnasnet1_0(num_classes=class_num) - - model.to(loc) - model.load_state_dict(checkpoint['state_dict']) - model.eval() - input_names = ["actual_input_1"] - output_names = ["output1"] - dummy_input = torch.randn(16, 3, 224, 224) - dummy_input = dummy_input.to(loc, non_blocking=False) - torch.onnx.export(model, dummy_input, onnx_path, input_names=input_names, output_names=output_names, opset_version=11) - mox.file.copy_parallel(onnx_path, train_url + 'model.onnx') - -def convert_pth_to_onnx(config_args): - mox.file.copy_parallel(config_args.is_best_name, os.path.join(CACHE_MODEL_URL, "checkpoint.pth.tar")) - pth_pattern = os.path.join(CACHE_MODEL_URL, 'checkpoint.pth.tar') - pth_file_list = glob.glob(pth_pattern) - if not pth_file_list: - print(f"can't find pth {pth_pattern}") - return - pth_file = pth_file_list[0] - onnx_path = pth_file.split(".")[0] + '.onnx' - convert(pth_file, onnx_path, config_args.class_num, config_args.train_url, config_args.npu) -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='PyTorch ImageNet Training') - # modelarts - parser.add_argument('--data_url', metavar='DIR', default='/cache/data_url', help='path to dataset') - parser.add_argument('--train_url', default="/cache/training", - type=str, - help="setting dir of training output") - parser.add_argument('--onnx', default=True, action='store_true', - help="convert pth model to onnx") - parser.add_argument('--class_num', default=1000, type=int, - help='number of class') - parser.add_argument('-a', '--arch', metavar='ARCH', default='mnasnet1_0') - parser.add_argument('--is_best_name', dest='is_best_name', - help=' weight dir') - args = parser.parse_args() - print('===========================') - print(args) - print('===========================') +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 argparse +import os +import random +import shutil +import time +import warnings +import math +import glob +import numpy as np +import sys + +import torch +import torch.npu +import torch.nn as nn +from collections import OrderedDict +import torch.onnx +sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '../')) +import mnasnet + +# modelarts modification +import moxing as mox + + +CACHE_TRAINING_URL = "/cache/training" +CACHE_MODEL_URL = "/cache/model" + +def proc_node_module(checkpoint, AttrName): + new_state_dict = OrderedDict() + for k, v in checkpoint[AttrName].items(): + if k[0:7] == "module.": + name = k[7:] + else: + name = k[0:] + new_state_dict[name] = v + return new_state_dict + + +def convert(pth_file, onnx_path, class_num, train_url, npu): + + loc = 'npu:{}'.format(npu) + checkpoint = torch.load(pth_file, map_location=loc) + + checkpoint['state_dict'] = proc_node_module(checkpoint, 'state_dict') + model = mnasnet.mnasnet1_0(num_classes=class_num) + + model.to(loc) + model.load_state_dict(checkpoint['state_dict']) + model.eval() + input_names = ["actual_input_1"] + output_names = ["output1"] + dummy_input = torch.randn(16, 3, 224, 224) + dummy_input = dummy_input.to(loc, non_blocking=False) + torch.onnx.export(model, dummy_input, onnx_path, input_names=input_names, output_names=output_names, opset_version=11) + mox.file.copy_parallel(onnx_path, train_url + 'model.onnx') + +def convert_pth_to_onnx(config_args): + mox.file.copy_parallel(config_args.is_best_name, os.path.join(CACHE_MODEL_URL, "checkpoint.pth.tar")) + pth_pattern = os.path.join(CACHE_MODEL_URL, 'checkpoint.pth.tar') + pth_file_list = glob.glob(pth_pattern) + if not pth_file_list: + print(f"can't find pth {pth_pattern}") + return + pth_file = pth_file_list[0] + onnx_path = pth_file.split(".")[0] + '.onnx' + convert(pth_file, onnx_path, config_args.class_num, config_args.train_url, config_args.npu) +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='PyTorch ImageNet Training') + # modelarts + parser.add_argument('--data_url', metavar='DIR', default='/cache/data_url', help='path to dataset') + parser.add_argument('--train_url', default="/cache/training", + type=str, + help="setting dir of training output") + parser.add_argument('--onnx', default=True, action='store_true', + help="convert pth model to onnx") + parser.add_argument('--class_num', default=1000, type=int, + help='number of class') + parser.add_argument('-a', '--arch', metavar='ARCH', default='mnasnet1_0') + parser.add_argument('--is_best_name', dest='is_best_name', + help=' weight dir') + args = parser.parse_args() + print('===========================') + print(args) + print('===========================') convert_pth_to_onnx(args) \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/MnasNet/modelArts/train-modelarts.py b/PyTorch/contrib/cv/classification/MnasNet/modelArts/train-modelarts.py index 26ad841ce2..9f090b46b4 100644 --- a/PyTorch/contrib/cv/classification/MnasNet/modelArts/train-modelarts.py +++ b/PyTorch/contrib/cv/classification/MnasNet/modelArts/train-modelarts.py @@ -1,735 +1,735 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 argparse -import os -import random -import shutil -import time -import warnings -import math -import glob -import numpy as np -import sys - -import torch -import torch.npu -import torch.nn as nn -import torch.nn.parallel -import torch.backends.cudnn as cudnn -import torch.distributed as dist -import torch.nn.functional as F -import torch.optim -import torch.utils.data -import torch.utils.data.distributed -import torchvision.transforms as transforms -import torchvision.datasets as datasets -import torchvision.models as models -from collections import OrderedDict -import torch.onnx -import pth2onnx -sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '../')) -import mnasnet - -# modelarts modification -import moxing as mox - - -try: - from apex.parallel import DistributedDataParallel as DDP - from apex.fp16_utils import * - from apex import amp, optimizers -except ImportError: - raise ImportError("Please install apex from https://www.github.com/nvidia/apex to run this example.") - - -parser = argparse.ArgumentParser(description='PyTorch ImageNet Training') -parser.add_argument('--data', metavar='DIR', - help='path to dataset') -parser.add_argument('--device', default='npu', type=str, help='npu or gpu') -parser.add_argument('--device-list', default='0,1,2,3,4,5,6,7', type=str, help='device id list') -parser.add_argument('-a', '--arch', metavar='ARCH', default='resnet18') -parser.add_argument('-j', '--workers', default=4, type=int, metavar='N', - help='number of data loading workers (default: 4)') -parser.add_argument('--epochs', default=90, type=int, metavar='N', - help='number of total epochs to run') -parser.add_argument('--start-epoch', default=0, type=int, metavar='N', - help='manual epoch number (useful on restarts)') -parser.add_argument('-b', '--batch-size', default=256, type=int, - metavar='N', - help='mini-batch size (default: 256), this is the total ' - 'batch size of all NPUs on the current node when ' - 'using Data Parallel or Distributed Data Parallel') - -parser.add_argument('--label-smoothing', '--ls', default=0.1, type=float) - -parser.add_argument('--lr', '--learning-rate', default=0.1, type=float, - metavar='LR', help='initial learning rate', dest='lr') -parser.add_argument('--momentum', default=0.9, type=float, metavar='M', - help='momentum') -parser.add_argument('--wd', '--weight-decay', default=1e-4, type=float, - metavar='W', help='weight decay (default: 1e-4)', - dest='weight_decay') -parser.add_argument('-p', '--print-freq', default=10, type=int, - metavar='N', help='print frequency (default: 10)') -parser.add_argument('--resume', default='', type=str, metavar='PATH', - help='path to latest checkpoint (default: none)') -parser.add_argument('-e', '--evaluate', dest='evaluate', action='store_true', - help='evaluate model on validation set') -parser.add_argument('--pretrained', dest='pretrained', action='store_true', - help='use pre-trained model') -parser.add_argument('--world-size', default=-1, type=int, - help='number of nodes for distributed training') -parser.add_argument('--rank', default=-1, type=int, - help='node rank for distributed training') -parser.add_argument('--dist-url', default='tcp://224.66.41.62:23456', type=str, - help='url used to set up distributed training') -parser.add_argument('--dist-backend', default='nccl', type=str, - help='distributed backend') -parser.add_argument('--seed', default=1, type=int, - help='seed for initializing training. ') -parser.add_argument('--npu', default=0, type=int, - help='NPU id to use.') -parser.add_argument('--warmup', default=0, type=int, - help='Warmup epochs.') -parser.add_argument('--local_rank', default=0, type=int, - help="rank id of process") -parser.add_argument('--run-prof', action='store_true', help='only for prof') -parser.add_argument('--multiprocessing-distributed', action='store_true', - help='Use multi-processing distributed training to launch ' - 'N processes per node, which has N NPUs. This is the ' - 'fastest way to use PyTorch for either single node or ' - 'multi node data parallel training') - -parser.add_argument('--pretrained_weight', dest='pretrained_weight', - help='pretrained weight dir') - - -# modelarts -parser.add_argument('--data_url', metavar='DIR', default='/cache/data_url', help='path to dataset') -parser.add_argument('--train_url', default="/cache/training", - type=str, - help="setting dir of training output") -parser.add_argument('--onnx', default=True, action='store_true', - help="convert pth model to onnx") -parser.add_argument('--class_num', default=1000, type=int, - help='number of class') - - -best_acc1 = 0 -CALCULATE_DEVICE = "npu:0" -CACHE_TRAINING_URL = "/cache/training" -is_best_name = "checkpoint.pth.tar" -def main(): - args = parser.parse_args() - print('===========================') - print(args) - print('===========================') - - if args.npu is None: - args.npu = 0 - global CALCULATE_DEVICE - if 'npu' in CALCULATE_DEVICE: - torch.npu.set_device(CALCULATE_DEVICE) - - if args.seed is not None: - random.seed(args.seed) - torch.manual_seed(args.seed) - cudnn.deterministic = True - warnings.warn('You have chosen to seed training. ' - 'This will turn on the CUDNN deterministic setting, ' - 'which can slow down your training considerably! ' - 'You may see unexpected behavior when restarting ' - 'from checkpoints.') - - if args.npu is not None: - warnings.warn('You have chosen a specific NPU. This will completely ' - 'disable data parallelism.') - - if args.dist_url == "env://" and args.world_size == -1: - args.world_size = int(os.environ["WORLD_SIZE"]) - - args.distributed = args.world_size > 1 or args.multiprocessing_distributed - - # ngpus_per_node = torch.cuda.device_count() - args.process_device_map = device_id_to_process_device_map(args.device_list) - if args.device == 'npu': - ngpus_per_node = len(args.process_device_map) - else: - ngpus_per_node = torch.cuda.device_count() - - if args.multiprocessing_distributed: - # Since we have ngpus_per_node processes per node, the total world_size - # needs to be adjusted accordingly - args.world_size = ngpus_per_node * args.world_size - # Use torch.multiprocessing.spawn to launch distributed processes: the - # main_worker process function - main_worker(args.local_rank, ngpus_per_node, args) - else: - # Simply call main_worker function - main_worker(args.npu, ngpus_per_node, args) - - - -def main_worker(npu, ngpus_per_node, args): - global best_acc1 - # args.npu = npu - - # args.npu = args.process_device_map[npu] - - if args.npu is not None: - print("Use NPU: {} for training".format(args.npu)) - - if args.distributed: - if args.dist_url == "env://" and args.rank == -1: - args.rank = int(os.environ["RANK"]) - if args.multiprocessing_distributed: - # For multiprocessing distributed training, rank needs to be the - # global rank among all the processes - args.rank = args.rank * ngpus_per_node + npu - if args.device == 'npu': - os.environ['MASTER_ADDR'] = '127.0.0.1' # args.addr - os.environ['MASTER_PORT'] = '29688' - dist.init_process_group(backend=args.dist_backend, # init_method=args.dist_url, - world_size=args.world_size, rank=args.rank) - else: - dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url, - world_size=args.world_size, rank=args.rank) - # dist.init_process_group(backend=args.dist_backend, world_size=args.world_size, rank=args.rank) - # create model - if args.pretrained: - print("=> using pre-trained model '{}'".format(args.arch)) - CACHE_MODEL_URL = "/cache/model" - # ------------------modelarts modification---------------------- - os.makedirs(CACHE_MODEL_URL, exist_ok=True) - mox.file.copy_parallel(args.pretrained_weight, os.path.join(CACHE_MODEL_URL, "checkpoint.pth")) - # ------------------modelarts modification--------------------- - pth = os.path.join(CACHE_MODEL_URL, "checkpoint.pth") - - pretrained_dict = torch.load(pth, map_location="cpu") - - model = mnasnet.mnasnet1_0(num_classes=args.class_num) - if "classifier.1.weight" in pretrained_dict: - pretrained_dict.pop("classifier.1.weight") - pretrained_dict.pop("classifier.1.bias") - if "module.classifier.1.weight" in pretrained_dict: - pretrained_dict.pop("module.classifier.1.weight") - pretrained_dict.pop("module.classifier.1.bias") - model.load_state_dict(pretrained_dict, strict=False) - - else: - print("=> creating model '{}'".format('mansnet')) - model = mnasnet.mnasnet1_0(num_classes=args.class_num) - # model = models.__dict__[args.arch]() - - args.loss_scale = 128 - - loc = 'npu:{}'.format(args.npu) - torch.npu.set_device(loc) - - args.batch_size = int(args.batch_size / ngpus_per_node) - - - # -------modelarts modification------- - real_path = '/cache/data_url' - if not os.path.exists(real_path): - os.makedirs(real_path) - mox.file.copy_parallel(args.data_url, real_path) - print("training data finish copy to %s." % real_path) - # ---------modelarts modification----- - # Data loading code - traindir = os.path.join(real_path, 'train') - valdir = os.path.join(real_path, 'val') - normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], - std=[0.229, 0.224, 0.225]) - - train_dataset = datasets.ImageFolder( - traindir, - transforms.Compose([ - transforms.RandomResizedCrop(224), - transforms.RandomHorizontalFlip(), - transforms.ToTensor(), #Too slow - normalize, - ])) - val_dataset = datasets.ImageFolder(valdir, transforms.Compose([ - transforms.Resize(256), - transforms.CenterCrop(224), - transforms.ToTensor(), - normalize, - ])) - - train_sampler = None - val_sampler = None - if args.distributed: - train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset) - # val_sampler = torch.utils.data.distributed.DistributedSampler(val_dataset) - - train_loader = torch.utils.data.DataLoader( - train_dataset, batch_size=args.batch_size, shuffle=(train_sampler is None), - num_workers=args.workers, - pin_memory=False, - sampler=train_sampler, - # collate_fn=fast_collate, - drop_last=True) - - val_loader = torch.utils.data.DataLoader( - val_dataset, - batch_size=args.batch_size, shuffle=False, - num_workers=args.workers, pin_memory=False, - sampler=val_sampler, - # collate_fn=fast_collate, - drop_last=True) - - model = model.to(loc) - # define loss function (criterion) and optimizer - # criterion = nn.CrossEntropyLoss().to(loc) - criterion = LabelSmoothingCrossEntropy().to(loc) - - optimizer = torch.optim.SGD(model.parameters(), args.lr, - momentum=args.momentum, - weight_decay=args.weight_decay, - nesterov=True) - lr_schedule = CosineWithWarmup(optimizer, args.warmup, 0.1, args.epochs) - - model, optimizer = amp.initialize(model, optimizer, opt_level="O1", loss_scale=args.loss_scale) - if args.multiprocessing_distributed: - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.npu], broadcast_buffers=False) - - # optionally resume from a checkpoint - if args.resume: - if os.path.isfile(args.resume): - print("=> loading checkpoint '{}'".format(args.resume)) - checkpoint = torch.load(args.resume, map_location=loc) - args.start_epoch = checkpoint['epoch'] - best_acc1 = checkpoint['best_acc1'] - model.load_state_dict(checkpoint['state_dict']) - optimizer.load_state_dict(checkpoint['optimizer']) - amp.load_state_dict(checkpoint['amp']) - print("=> loaded checkpoint '{}' (epoch {})" - .format(args.resume, checkpoint['epoch'])) - else: - print("=> no checkpoint found at '{}'".format(args.resume)) - - cudnn.benchmark = True - - if args.evaluate: - validate(val_loader, model, criterion, args) - return - - for epoch in range(args.start_epoch, args.epochs): - if args.distributed: - train_sampler.set_epoch(epoch) - lr_schedule.step(epoch) - if args.rank == 0: - print('lr = ', lr_schedule.get_lr()[0]) - file = open('log.txt', 'a') - print('lr = ', lr_schedule.get_lr()[0], file=file) - file.close() - - if args.run_prof: - runprof(train_loader, model, criterion, optimizer, epoch, args) - print('output to output.prof') - return - - # train for one epoch - train(train_loader, model, criterion, optimizer, epoch, args) - - # evaluate on validation set - acc1 = validate(val_loader, model, criterion, args) - - # remember best acc@1 and save checkpoint - is_best = acc1 >= best_acc1 - best_acc1 = max(acc1, best_acc1) - - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % ngpus_per_node == 0): - save_checkpoint({ - 'epoch': epoch + 1, - 'arch': args.arch, - 'state_dict': model.state_dict(), - 'best_acc1': best_acc1, - 'optimizer': optimizer.state_dict(), - 'amp': amp.state_dict(), - }, is_best, args) - - if args.onnx: - pth2onnx.convert_pth_to_onnx(args) - # --------------modelarts modification---------- - mox.file.copy_parallel(CACHE_TRAINING_URL, args.train_url) - # --------------modelarts modification end---------- - -def train(train_loader, model, criterion, optimizer, epoch, args): - batch_time = AverageMeter('Time', ':6.3f') - data_time = AverageMeter('Data', ':6.3f') - losses = AverageMeter('Loss', ':.4e') - top1 = AverageMeter('Acc@1', ':6.2f') - top5 = AverageMeter('Acc@5', ':6.2f') - FPS = AverageMeter('FPS', ':6.2f') - progress = ProgressMeter( - len(train_loader), - [batch_time, data_time, losses, top1, top5, FPS], - prefix="Epoch: [{}]".format(epoch), - fpath='./log.txt') - - # switch to train mode - model.train() - - end = time.time() - # prefetcher = data_prefetcher(train_loader) - # images, target = prefetcher.next() - # i = -1 - # while images is not None: - for i, (images, target) in enumerate(train_loader): - # i += 1 - # measure data loading time - data_time.update(time.time() - end) - - loc = 'npu:{}'.format(args.npu) - target = target.to(torch.int32) - images, target = images.to(loc, non_blocking=False), target.to(loc, non_blocking=False) - - # compute output - output = model(images) - loss = criterion(output, target) - - # measure accuracy and record loss - acc1, acc5 = accuracy(output, target, topk=(1, 5)) - losses.update(loss.item(), images.size(0)) - top1.update(acc1[0], images.size(0)) - top5.update(acc5[0], images.size(0)) - - # compute gradient and do SGD step - optimizer.zero_grad() - #loss.backward() - - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - - optimizer.step() - # measure elapsed time - batch_time_nw = time.time() - end; - if i >= 5: - batch_time.update(batch_time_nw) - if i >= 2: - batch_size = images.size(0) - FPS.update(batch_size / batch_time_nw * args.world_size) - - end = time.time() - if i % args.print_freq == 0 and args.rank == 0: - progress.display(i) - # images, target = prefetcher.next() - print('NPU: {}, solve {} batchs'.format(args.rank, i)) - - -def validate(val_loader, model, criterion, args): - batch_time = AverageMeter('Time', ':6.3f') - losses = AverageMeter('Loss', ':.4e') - top1 = AverageMeter('Acc@1', ':6.2f') - top5 = AverageMeter('Acc@5', ':6.2f') - progress = ProgressMeter( - len(val_loader), - [batch_time, losses, top1, top5], - prefix='Test: ', - fpath='./log.txt') - - # switch to evaluate mode - model.eval() - - with torch.no_grad(): - end = time.time() - - # prefetcher = data_prefetcher(val_loader) - # images, target = prefetcher.next() - # i = -1 - # while images is not None: - for i, (images, target) in enumerate(val_loader): - # i += 1 - loc = 'npu:{}'.format(args.npu) - target = target.to(torch.int32) - images, target = images.to(loc, non_blocking=False), target.to(loc, non_blocking=False) - - # compute output - output = model(images) - loss = criterion(output, target) - - # measure accuracy and record loss - acc1, acc5 = accuracy(output, target, topk=(1, 5)) - losses.update(loss.item(), images.size(0)) - - top1.update(acc1[0], images.size(0)) - top5.update(acc5[0], images.size(0)) - - # measure elapsed time - batch_time.update(time.time() - end) - end = time.time() - - if i % args.print_freq == 0 and args.rank == 0: - progress.display(i) - # images, target = prefetcher.next() - - print(' * Acc@1 {top1.avg:.3f} Acc@5 {top5.avg:.3f}' - .format(top1=top1, top5=top5)) - file = open('log.txt', 'a') - print(' * Acc@1 {top1.avg:.3f} Acc@5 {top5.avg:.3f}' - .format(top1=top1, top5=top5), - file=file) - file.close() - return top1.avg - - -def runprof(train_loader, model, criterion, optimizer, epoch, args): - # switch to train mode - model.train() - prefetcher = data_prefetcher(train_loader) - images, target = prefetcher.next() - i = -1 - while images is not None: - i += 1 - if args.npu is not None: - images = images.cuda(args.npu, non_blocking=True) - - if 'npu' in CALCULATE_DEVICE: - target = target.to(torch.int32) - images, target = images.to(CALCULATE_DEVICE, non_blocking=True), target.to(CALCULATE_DEVICE, non_blocking=True) - - if i >= 5: - with torch.autograd.profiler.profile(use_cuda=True) as prof: - out = model(images) - loss = criterion(out, target) - optimizer.zero_grad() - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - optimizer.step() - prof.export_chrome_trace("output.prof") - return - else: - output = model(images) - loss = criterion(output, target) - optimizer.zero_grad() - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - optimizer.step() - images, target = prefetcher.next() - - -def save_checkpoint(state, is_best, args, filename='checkpoint.pth.tar'): - if not os.path.exists(CACHE_TRAINING_URL): - os.makedirs(CACHE_TRAINING_URL, 0o755) - - checkpoint_save_path = os.path.join(CACHE_TRAINING_URL, filename) - torch.save(state, checkpoint_save_path) - if is_best: - # shutil.copyfile(filename, 'model_best.pth.tar') - args.is_best_name = args.train_url + 'model_best_acc%.4f_epoch%d.pth.tar' % (state['best_acc1'], state['epoch']) - mox.file.copy_parallel(checkpoint_save_path, args.is_best_name) - - -class LabelSmoothingCrossEntropy(nn.Module): - def __init__(self, eps=0.1, reduction='mean'): - super(LabelSmoothingCrossEntropy, self).__init__() - self.eps = eps - self.reduction = reduction - - def forward(self, output, target): - c = output.size()[-1] - log_preds = F.log_softmax(output, dim=-1) - if self.reduction == 'sum': - loss = -log_preds.sum() - else: - loss = -log_preds.sum(dim=-1) - if self.reduction == 'mean': - loss = loss.mean() - return loss * self.eps / c + (1 - self.eps) * F.nll_loss(log_preds, target, reduction=self.reduction) - - -class AverageMeter(object): - """Computes and stores the average and current value""" - - def __init__(self, name, fmt=':f'): - self.name = name - self.fmt = fmt - self.reset() - - def reset(self): - self.val = 0 - self.avg = 0 - self.sum = 0 - self.count = 0 - - def update(self, val, n=1): - self.val = val - self.sum += val * n - self.count += n - self.avg = self.sum / self.count - - def __str__(self): - fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' - return fmtstr.format(**self.__dict__) - - -class ProgressMeter(object): - def __init__(self, num_batches, meters, prefix="", fpath=None): - self.batch_fmtstr = self._get_batch_fmtstr(num_batches) - self.meters = meters - self.prefix = prefix - if fpath is not None: - self.file = open(fpath, 'a') - - def display(self, batch): - entries = [self.prefix + self.batch_fmtstr.format(batch)] - entries += [str(meter) for meter in self.meters] - print('\t'.join(entries)) - if self.file is not None: - self.file.write('\t'.join(entries)) - self.file.write('\n') - self.file.flush() - - def _get_batch_fmtstr(self, num_batches): - num_digits = len(str(num_batches // 1)) - fmt = '{:' + str(num_digits) + 'd}' - return '[' + fmt + '/' + fmt.format(num_batches) + ']' - - def close(self): - if self.file is not None: - self.file.close() - - -class CosineWithWarmup(torch.optim.lr_scheduler._LRScheduler): - """ Implements a schedule where the first few epochs are linear warmup, and - then there's cosine annealing after that.""" - - def __init__(self, optimizer: torch.optim.Optimizer, warmup_len: int, - warmup_start_multiplier: float, max_epochs: int, - last_epoch: int = -1): - if warmup_len < 0: - raise ValueError("Warmup can't be less than 0.") - self.warmup_len = warmup_len - if not (0.0 <= warmup_start_multiplier <= 1.0): - raise ValueError( - "Warmup start multiplier must be within [0.0, 1.0].") - self.warmup_start_multiplier = warmup_start_multiplier - if max_epochs < 1 or max_epochs < warmup_len: - raise ValueError("Max epochs must be longer than warm-up.") - self.max_epochs = max_epochs - self.cosine_len = self.max_epochs - self.warmup_len - self.eta_min = 0.0 # Final LR multiplier of cosine annealing - super().__init__(optimizer, last_epoch) - - def get_lr(self): - if self.last_epoch > self.max_epochs: - raise ValueError( - "Epoch may not be greater than max_epochs={}.".format( - self.max_epochs)) - if self.last_epoch < self.warmup_len or self.cosine_len == 0: - # We're in warm-up, increase LR linearly. End multiplier is implicit 1.0. - slope = (1.0 - self.warmup_start_multiplier) / self.warmup_len - lr_multiplier = self.warmup_start_multiplier + slope * self.last_epoch - else: - # We're in the cosine annealing part. Note that the implementation - # is different from the paper in that there's no additive part and - # the "low" LR is not limited by eta_min. Instead, eta_min is - # treated as a multiplier as well. The paper implementation is - # designed for SGDR. - cosine_epoch = self.last_epoch - self.warmup_len - lr_multiplier = self.eta_min + (1.0 - self.eta_min) * ( - 1 + math.cos(math.pi * cosine_epoch / self.cosine_len)) / 2 - assert lr_multiplier >= 0.0 - return [base_lr * lr_multiplier for base_lr in self.base_lrs] - - -def accuracy(output, target, topk=(1,)): - """Computes the accuracy over the k top predictions for the specified values of k""" - with torch.no_grad(): - maxk = max(topk) - batch_size = target.size(0) - - _, pred = output.topk(maxk, 1, True, True) - pred = pred.t() - correct = pred.eq(target.view(1, -1).expand_as(pred)) - - res = [] - for k in topk: - correct_k = correct[:k].reshape(-1).float().sum(0, keepdim=True) - res.append(correct_k.mul_(100.0 / batch_size)) - return res - - -def device_id_to_process_device_map(device_list): - devices = device_list.split(",") - devices = [int(x) for x in devices] - devices.sort() - - process_device_map = dict() - for process_id, device_id in enumerate(devices): - process_device_map[process_id] = device_id - - return process_device_map - - -def fast_collate(batch): - imgs = [img[0] for img in batch] - targets = torch.tensor([target[1] for target in batch], dtype=torch.int64) - w = imgs[0].size[0] - h = imgs[0].size[1] - tensor = torch.zeros((len(imgs), 3, h, w), dtype=torch.uint8) - for i, img in enumerate(imgs): - nump_array = np.asarray(img, dtype=np.uint8) - tens = torch.from_numpy(nump_array) - if (nump_array.ndim < 3): - nump_array = np.expand_dims(nump_array, axis=-1) - nump_array = np.rollaxis(nump_array, 2) - - tensor[i] += torch.from_numpy(nump_array) - - return tensor, targets - - -class data_prefetcher(): - def __init__(self, loader): - self.loader = iter(loader) - self.stream = torch.npu.Stream() - self.mean = torch.tensor([0.485 * 255, 0.456 * 255, 0.406 * 255]).npu().view(1, 3, 1, 1) - self.std = torch.tensor([0.229 * 255, 0.224 * 255, 0.225 * 255]).npu().view(1, 3, 1, 1) - # With Amp, it isn't necessary to manually convert data to half. - # if args.fp16: - # self.mean = self.mean.half() - # self.std = self.std.half() - self.preload() - - def preload(self): - try: - self.next_input, self.next_target = next(self.loader) - except StopIteration: - self.next_input = None - self.next_target = None - return - with torch.npu.stream(self.stream): - self.next_input = self.next_input.npu(non_blocking=True) - self.next_target = self.next_target.npu(non_blocking=True) - # With Amp, it isn't necessary to manually convert data to half. - # if args.fp16: - # self.next_input = self.next_input.half() - # else: - self.next_input = self.next_input.float() - self.next_input = self.next_input.sub_(self.mean).div_(self.std) - - def next(self): - torch.npu.current_stream().wait_stream(self.stream) - input = self.next_input - target = self.next_target - self.preload() - return input, target - -if __name__ == '__main__': - main() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 argparse +import os +import random +import shutil +import time +import warnings +import math +import glob +import numpy as np +import sys + +import torch +import torch.npu +import torch.nn as nn +import torch.nn.parallel +import torch.backends.cudnn as cudnn +import torch.distributed as dist +import torch.nn.functional as F +import torch.optim +import torch.utils.data +import torch.utils.data.distributed +import torchvision.transforms as transforms +import torchvision.datasets as datasets +import torchvision.models as models +from collections import OrderedDict +import torch.onnx +import pth2onnx +sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '../')) +import mnasnet + +# modelarts modification +import moxing as mox + + +try: + from apex.parallel import DistributedDataParallel as DDP + from apex.fp16_utils import * + from apex import amp, optimizers +except ImportError: + raise ImportError("Please install apex from https://www.github.com/nvidia/apex to run this example.") + + +parser = argparse.ArgumentParser(description='PyTorch ImageNet Training') +parser.add_argument('--data', metavar='DIR', + help='path to dataset') +parser.add_argument('--device', default='npu', type=str, help='npu or gpu') +parser.add_argument('--device-list', default='0,1,2,3,4,5,6,7', type=str, help='device id list') +parser.add_argument('-a', '--arch', metavar='ARCH', default='resnet18') +parser.add_argument('-j', '--workers', default=4, type=int, metavar='N', + help='number of data loading workers (default: 4)') +parser.add_argument('--epochs', default=90, type=int, metavar='N', + help='number of total epochs to run') +parser.add_argument('--start-epoch', default=0, type=int, metavar='N', + help='manual epoch number (useful on restarts)') +parser.add_argument('-b', '--batch-size', default=256, type=int, + metavar='N', + help='mini-batch size (default: 256), this is the total ' + 'batch size of all NPUs on the current node when ' + 'using Data Parallel or Distributed Data Parallel') + +parser.add_argument('--label-smoothing', '--ls', default=0.1, type=float) + +parser.add_argument('--lr', '--learning-rate', default=0.1, type=float, + metavar='LR', help='initial learning rate', dest='lr') +parser.add_argument('--momentum', default=0.9, type=float, metavar='M', + help='momentum') +parser.add_argument('--wd', '--weight-decay', default=1e-4, type=float, + metavar='W', help='weight decay (default: 1e-4)', + dest='weight_decay') +parser.add_argument('-p', '--print-freq', default=10, type=int, + metavar='N', help='print frequency (default: 10)') +parser.add_argument('--resume', default='', type=str, metavar='PATH', + help='path to latest checkpoint (default: none)') +parser.add_argument('-e', '--evaluate', dest='evaluate', action='store_true', + help='evaluate model on validation set') +parser.add_argument('--pretrained', dest='pretrained', action='store_true', + help='use pre-trained model') +parser.add_argument('--world-size', default=-1, type=int, + help='number of nodes for distributed training') +parser.add_argument('--rank', default=-1, type=int, + help='node rank for distributed training') +parser.add_argument('--dist-url', default='tcp://224.66.41.62:23456', type=str, + help='url used to set up distributed training') +parser.add_argument('--dist-backend', default='nccl', type=str, + help='distributed backend') +parser.add_argument('--seed', default=1, type=int, + help='seed for initializing training. ') +parser.add_argument('--npu', default=0, type=int, + help='NPU id to use.') +parser.add_argument('--warmup', default=0, type=int, + help='Warmup epochs.') +parser.add_argument('--local_rank', default=0, type=int, + help="rank id of process") +parser.add_argument('--run-prof', action='store_true', help='only for prof') +parser.add_argument('--multiprocessing-distributed', action='store_true', + help='Use multi-processing distributed training to launch ' + 'N processes per node, which has N NPUs. This is the ' + 'fastest way to use PyTorch for either single node or ' + 'multi node data parallel training') + +parser.add_argument('--pretrained_weight', dest='pretrained_weight', + help='pretrained weight dir') + + +# modelarts +parser.add_argument('--data_url', metavar='DIR', default='/cache/data_url', help='path to dataset') +parser.add_argument('--train_url', default="/cache/training", + type=str, + help="setting dir of training output") +parser.add_argument('--onnx', default=True, action='store_true', + help="convert pth model to onnx") +parser.add_argument('--class_num', default=1000, type=int, + help='number of class') + + +best_acc1 = 0 +CALCULATE_DEVICE = "npu:0" +CACHE_TRAINING_URL = "/cache/training" +is_best_name = "checkpoint.pth.tar" +def main(): + args = parser.parse_args() + print('===========================') + print(args) + print('===========================') + + if args.npu is None: + args.npu = 0 + global CALCULATE_DEVICE + if 'npu' in CALCULATE_DEVICE: + torch.npu.set_device(CALCULATE_DEVICE) + + if args.seed is not None: + random.seed(args.seed) + torch.manual_seed(args.seed) + cudnn.deterministic = True + warnings.warn('You have chosen to seed training. ' + 'This will turn on the CUDNN deterministic setting, ' + 'which can slow down your training considerably! ' + 'You may see unexpected behavior when restarting ' + 'from checkpoints.') + + if args.npu is not None: + warnings.warn('You have chosen a specific NPU. This will completely ' + 'disable data parallelism.') + + if args.dist_url == "env://" and args.world_size == -1: + args.world_size = int(os.environ["WORLD_SIZE"]) + + args.distributed = args.world_size > 1 or args.multiprocessing_distributed + + # ngpus_per_node = torch.cuda.device_count() + args.process_device_map = device_id_to_process_device_map(args.device_list) + if args.device == 'npu': + ngpus_per_node = len(args.process_device_map) + else: + ngpus_per_node = torch.cuda.device_count() + + if args.multiprocessing_distributed: + # Since we have ngpus_per_node processes per node, the total world_size + # needs to be adjusted accordingly + args.world_size = ngpus_per_node * args.world_size + # Use torch.multiprocessing.spawn to launch distributed processes: the + # main_worker process function + main_worker(args.local_rank, ngpus_per_node, args) + else: + # Simply call main_worker function + main_worker(args.npu, ngpus_per_node, args) + + + +def main_worker(npu, ngpus_per_node, args): + global best_acc1 + # args.npu = npu + + # args.npu = args.process_device_map[npu] + + if args.npu is not None: + print("Use NPU: {} for training".format(args.npu)) + + if args.distributed: + if args.dist_url == "env://" and args.rank == -1: + args.rank = int(os.environ["RANK"]) + if args.multiprocessing_distributed: + # For multiprocessing distributed training, rank needs to be the + # global rank among all the processes + args.rank = args.rank * ngpus_per_node + npu + if args.device == 'npu': + os.environ['MASTER_ADDR'] = '127.0.0.1' # args.addr + os.environ['MASTER_PORT'] = '29688' + dist.init_process_group(backend=args.dist_backend, # init_method=args.dist_url, + world_size=args.world_size, rank=args.rank) + else: + dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url, + world_size=args.world_size, rank=args.rank) + # dist.init_process_group(backend=args.dist_backend, world_size=args.world_size, rank=args.rank) + # create model + if args.pretrained: + print("=> using pre-trained model '{}'".format(args.arch)) + CACHE_MODEL_URL = "/cache/model" + # ------------------modelarts modification---------------------- + os.makedirs(CACHE_MODEL_URL, exist_ok=True) + mox.file.copy_parallel(args.pretrained_weight, os.path.join(CACHE_MODEL_URL, "checkpoint.pth")) + # ------------------modelarts modification--------------------- + pth = os.path.join(CACHE_MODEL_URL, "checkpoint.pth") + + pretrained_dict = torch.load(pth, map_location="cpu") + + model = mnasnet.mnasnet1_0(num_classes=args.class_num) + if "classifier.1.weight" in pretrained_dict: + pretrained_dict.pop("classifier.1.weight") + pretrained_dict.pop("classifier.1.bias") + if "module.classifier.1.weight" in pretrained_dict: + pretrained_dict.pop("module.classifier.1.weight") + pretrained_dict.pop("module.classifier.1.bias") + model.load_state_dict(pretrained_dict, strict=False) + + else: + print("=> creating model '{}'".format('mansnet')) + model = mnasnet.mnasnet1_0(num_classes=args.class_num) + # model = models.__dict__[args.arch]() + + args.loss_scale = 128 + + loc = 'npu:{}'.format(args.npu) + torch.npu.set_device(loc) + + args.batch_size = int(args.batch_size / ngpus_per_node) + + + # -------modelarts modification------- + real_path = '/cache/data_url' + if not os.path.exists(real_path): + os.makedirs(real_path) + mox.file.copy_parallel(args.data_url, real_path) + print("training data finish copy to %s." % real_path) + # ---------modelarts modification----- + # Data loading code + traindir = os.path.join(real_path, 'train') + valdir = os.path.join(real_path, 'val') + normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]) + + train_dataset = datasets.ImageFolder( + traindir, + transforms.Compose([ + transforms.RandomResizedCrop(224), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), #Too slow + normalize, + ])) + val_dataset = datasets.ImageFolder(valdir, transforms.Compose([ + transforms.Resize(256), + transforms.CenterCrop(224), + transforms.ToTensor(), + normalize, + ])) + + train_sampler = None + val_sampler = None + if args.distributed: + train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset) + # val_sampler = torch.utils.data.distributed.DistributedSampler(val_dataset) + + train_loader = torch.utils.data.DataLoader( + train_dataset, batch_size=args.batch_size, shuffle=(train_sampler is None), + num_workers=args.workers, + pin_memory=False, + sampler=train_sampler, + # collate_fn=fast_collate, + drop_last=True) + + val_loader = torch.utils.data.DataLoader( + val_dataset, + batch_size=args.batch_size, shuffle=False, + num_workers=args.workers, pin_memory=False, + sampler=val_sampler, + # collate_fn=fast_collate, + drop_last=True) + + model = model.to(loc) + # define loss function (criterion) and optimizer + # criterion = nn.CrossEntropyLoss().to(loc) + criterion = LabelSmoothingCrossEntropy().to(loc) + + optimizer = torch.optim.SGD(model.parameters(), args.lr, + momentum=args.momentum, + weight_decay=args.weight_decay, + nesterov=True) + lr_schedule = CosineWithWarmup(optimizer, args.warmup, 0.1, args.epochs) + + model, optimizer = amp.initialize(model, optimizer, opt_level="O1", loss_scale=args.loss_scale) + if args.multiprocessing_distributed: + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.npu], broadcast_buffers=False) + + # optionally resume from a checkpoint + if args.resume: + if os.path.isfile(args.resume): + print("=> loading checkpoint '{}'".format(args.resume)) + checkpoint = torch.load(args.resume, map_location=loc) + args.start_epoch = checkpoint['epoch'] + best_acc1 = checkpoint['best_acc1'] + model.load_state_dict(checkpoint['state_dict']) + optimizer.load_state_dict(checkpoint['optimizer']) + amp.load_state_dict(checkpoint['amp']) + print("=> loaded checkpoint '{}' (epoch {})" + .format(args.resume, checkpoint['epoch'])) + else: + print("=> no checkpoint found at '{}'".format(args.resume)) + + cudnn.benchmark = True + + if args.evaluate: + validate(val_loader, model, criterion, args) + return + + for epoch in range(args.start_epoch, args.epochs): + if args.distributed: + train_sampler.set_epoch(epoch) + lr_schedule.step(epoch) + if args.rank == 0: + print('lr = ', lr_schedule.get_lr()[0]) + file = open('log.txt', 'a') + print('lr = ', lr_schedule.get_lr()[0], file=file) + file.close() + + if args.run_prof: + runprof(train_loader, model, criterion, optimizer, epoch, args) + print('output to output.prof') + return + + # train for one epoch + train(train_loader, model, criterion, optimizer, epoch, args) + + # evaluate on validation set + acc1 = validate(val_loader, model, criterion, args) + + # remember best acc@1 and save checkpoint + is_best = acc1 >= best_acc1 + best_acc1 = max(acc1, best_acc1) + + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % ngpus_per_node == 0): + save_checkpoint({ + 'epoch': epoch + 1, + 'arch': args.arch, + 'state_dict': model.state_dict(), + 'best_acc1': best_acc1, + 'optimizer': optimizer.state_dict(), + 'amp': amp.state_dict(), + }, is_best, args) + + if args.onnx: + pth2onnx.convert_pth_to_onnx(args) + # --------------modelarts modification---------- + mox.file.copy_parallel(CACHE_TRAINING_URL, args.train_url) + # --------------modelarts modification end---------- + +def train(train_loader, model, criterion, optimizer, epoch, args): + batch_time = AverageMeter('Time', ':6.3f') + data_time = AverageMeter('Data', ':6.3f') + losses = AverageMeter('Loss', ':.4e') + top1 = AverageMeter('Acc@1', ':6.2f') + top5 = AverageMeter('Acc@5', ':6.2f') + FPS = AverageMeter('FPS', ':6.2f') + progress = ProgressMeter( + len(train_loader), + [batch_time, data_time, losses, top1, top5, FPS], + prefix="Epoch: [{}]".format(epoch), + fpath='./log.txt') + + # switch to train mode + model.train() + + end = time.time() + # prefetcher = data_prefetcher(train_loader) + # images, target = prefetcher.next() + # i = -1 + # while images is not None: + for i, (images, target) in enumerate(train_loader): + # i += 1 + # measure data loading time + data_time.update(time.time() - end) + + loc = 'npu:{}'.format(args.npu) + target = target.to(torch.int32) + images, target = images.to(loc, non_blocking=False), target.to(loc, non_blocking=False) + + # compute output + output = model(images) + loss = criterion(output, target) + + # measure accuracy and record loss + acc1, acc5 = accuracy(output, target, topk=(1, 5)) + losses.update(loss.item(), images.size(0)) + top1.update(acc1[0], images.size(0)) + top5.update(acc5[0], images.size(0)) + + # compute gradient and do SGD step + optimizer.zero_grad() + #loss.backward() + + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + + optimizer.step() + # measure elapsed time + batch_time_nw = time.time() - end; + if i >= 5: + batch_time.update(batch_time_nw) + if i >= 2: + batch_size = images.size(0) + FPS.update(batch_size / batch_time_nw * args.world_size) + + end = time.time() + if i % args.print_freq == 0 and args.rank == 0: + progress.display(i) + # images, target = prefetcher.next() + print('NPU: {}, solve {} batchs'.format(args.rank, i)) + + +def validate(val_loader, model, criterion, args): + batch_time = AverageMeter('Time', ':6.3f') + losses = AverageMeter('Loss', ':.4e') + top1 = AverageMeter('Acc@1', ':6.2f') + top5 = AverageMeter('Acc@5', ':6.2f') + progress = ProgressMeter( + len(val_loader), + [batch_time, losses, top1, top5], + prefix='Test: ', + fpath='./log.txt') + + # switch to evaluate mode + model.eval() + + with torch.no_grad(): + end = time.time() + + # prefetcher = data_prefetcher(val_loader) + # images, target = prefetcher.next() + # i = -1 + # while images is not None: + for i, (images, target) in enumerate(val_loader): + # i += 1 + loc = 'npu:{}'.format(args.npu) + target = target.to(torch.int32) + images, target = images.to(loc, non_blocking=False), target.to(loc, non_blocking=False) + + # compute output + output = model(images) + loss = criterion(output, target) + + # measure accuracy and record loss + acc1, acc5 = accuracy(output, target, topk=(1, 5)) + losses.update(loss.item(), images.size(0)) + + top1.update(acc1[0], images.size(0)) + top5.update(acc5[0], images.size(0)) + + # measure elapsed time + batch_time.update(time.time() - end) + end = time.time() + + if i % args.print_freq == 0 and args.rank == 0: + progress.display(i) + # images, target = prefetcher.next() + + print(' * Acc@1 {top1.avg:.3f} Acc@5 {top5.avg:.3f}' + .format(top1=top1, top5=top5)) + file = open('log.txt', 'a') + print(' * Acc@1 {top1.avg:.3f} Acc@5 {top5.avg:.3f}' + .format(top1=top1, top5=top5), + file=file) + file.close() + return top1.avg + + +def runprof(train_loader, model, criterion, optimizer, epoch, args): + # switch to train mode + model.train() + prefetcher = data_prefetcher(train_loader) + images, target = prefetcher.next() + i = -1 + while images is not None: + i += 1 + if args.npu is not None: + images = images.cuda(args.npu, non_blocking=True) + + if 'npu' in CALCULATE_DEVICE: + target = target.to(torch.int32) + images, target = images.to(CALCULATE_DEVICE, non_blocking=True), target.to(CALCULATE_DEVICE, non_blocking=True) + + if i >= 5: + with torch.autograd.profiler.profile(use_cuda=True) as prof: + out = model(images) + loss = criterion(out, target) + optimizer.zero_grad() + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + optimizer.step() + prof.export_chrome_trace("output.prof") + return + else: + output = model(images) + loss = criterion(output, target) + optimizer.zero_grad() + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + optimizer.step() + images, target = prefetcher.next() + + +def save_checkpoint(state, is_best, args, filename='checkpoint.pth.tar'): + if not os.path.exists(CACHE_TRAINING_URL): + os.makedirs(CACHE_TRAINING_URL, 0o755) + + checkpoint_save_path = os.path.join(CACHE_TRAINING_URL, filename) + torch.save(state, checkpoint_save_path) + if is_best: + # shutil.copyfile(filename, 'model_best.pth.tar') + args.is_best_name = args.train_url + 'model_best_acc%.4f_epoch%d.pth.tar' % (state['best_acc1'], state['epoch']) + mox.file.copy_parallel(checkpoint_save_path, args.is_best_name) + + +class LabelSmoothingCrossEntropy(nn.Module): + def __init__(self, eps=0.1, reduction='mean'): + super(LabelSmoothingCrossEntropy, self).__init__() + self.eps = eps + self.reduction = reduction + + def forward(self, output, target): + c = output.size()[-1] + log_preds = F.log_softmax(output, dim=-1) + if self.reduction == 'sum': + loss = -log_preds.sum() + else: + loss = -log_preds.sum(dim=-1) + if self.reduction == 'mean': + loss = loss.mean() + return loss * self.eps / c + (1 - self.eps) * F.nll_loss(log_preds, target, reduction=self.reduction) + + +class AverageMeter(object): + """Computes and stores the average and current value""" + + def __init__(self, name, fmt=':f'): + self.name = name + self.fmt = fmt + self.reset() + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + + def update(self, val, n=1): + self.val = val + self.sum += val * n + self.count += n + self.avg = self.sum / self.count + + def __str__(self): + fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' + return fmtstr.format(**self.__dict__) + + +class ProgressMeter(object): + def __init__(self, num_batches, meters, prefix="", fpath=None): + self.batch_fmtstr = self._get_batch_fmtstr(num_batches) + self.meters = meters + self.prefix = prefix + if fpath is not None: + self.file = open(fpath, 'a') + + def display(self, batch): + entries = [self.prefix + self.batch_fmtstr.format(batch)] + entries += [str(meter) for meter in self.meters] + print('\t'.join(entries)) + if self.file is not None: + self.file.write('\t'.join(entries)) + self.file.write('\n') + self.file.flush() + + def _get_batch_fmtstr(self, num_batches): + num_digits = len(str(num_batches // 1)) + fmt = '{:' + str(num_digits) + 'd}' + return '[' + fmt + '/' + fmt.format(num_batches) + ']' + + def close(self): + if self.file is not None: + self.file.close() + + +class CosineWithWarmup(torch.optim.lr_scheduler._LRScheduler): + """ Implements a schedule where the first few epochs are linear warmup, and + then there's cosine annealing after that.""" + + def __init__(self, optimizer: torch.optim.Optimizer, warmup_len: int, + warmup_start_multiplier: float, max_epochs: int, + last_epoch: int = -1): + if warmup_len < 0: + raise ValueError("Warmup can't be less than 0.") + self.warmup_len = warmup_len + if not (0.0 <= warmup_start_multiplier <= 1.0): + raise ValueError( + "Warmup start multiplier must be within [0.0, 1.0].") + self.warmup_start_multiplier = warmup_start_multiplier + if max_epochs < 1 or max_epochs < warmup_len: + raise ValueError("Max epochs must be longer than warm-up.") + self.max_epochs = max_epochs + self.cosine_len = self.max_epochs - self.warmup_len + self.eta_min = 0.0 # Final LR multiplier of cosine annealing + super().__init__(optimizer, last_epoch) + + def get_lr(self): + if self.last_epoch > self.max_epochs: + raise ValueError( + "Epoch may not be greater than max_epochs={}.".format( + self.max_epochs)) + if self.last_epoch < self.warmup_len or self.cosine_len == 0: + # We're in warm-up, increase LR linearly. End multiplier is implicit 1.0. + slope = (1.0 - self.warmup_start_multiplier) / self.warmup_len + lr_multiplier = self.warmup_start_multiplier + slope * self.last_epoch + else: + # We're in the cosine annealing part. Note that the implementation + # is different from the paper in that there's no additive part and + # the "low" LR is not limited by eta_min. Instead, eta_min is + # treated as a multiplier as well. The paper implementation is + # designed for SGDR. + cosine_epoch = self.last_epoch - self.warmup_len + lr_multiplier = self.eta_min + (1.0 - self.eta_min) * ( + 1 + math.cos(math.pi * cosine_epoch / self.cosine_len)) / 2 + assert lr_multiplier >= 0.0 + return [base_lr * lr_multiplier for base_lr in self.base_lrs] + + +def accuracy(output, target, topk=(1,)): + """Computes the accuracy over the k top predictions for the specified values of k""" + with torch.no_grad(): + maxk = max(topk) + batch_size = target.size(0) + + _, pred = output.topk(maxk, 1, True, True) + pred = pred.t() + correct = pred.eq(target.view(1, -1).expand_as(pred)) + + res = [] + for k in topk: + correct_k = correct[:k].reshape(-1).float().sum(0, keepdim=True) + res.append(correct_k.mul_(100.0 / batch_size)) + return res + + +def device_id_to_process_device_map(device_list): + devices = device_list.split(",") + devices = [int(x) for x in devices] + devices.sort() + + process_device_map = dict() + for process_id, device_id in enumerate(devices): + process_device_map[process_id] = device_id + + return process_device_map + + +def fast_collate(batch): + imgs = [img[0] for img in batch] + targets = torch.tensor([target[1] for target in batch], dtype=torch.int64) + w = imgs[0].size[0] + h = imgs[0].size[1] + tensor = torch.zeros((len(imgs), 3, h, w), dtype=torch.uint8) + for i, img in enumerate(imgs): + nump_array = np.asarray(img, dtype=np.uint8) + tens = torch.from_numpy(nump_array) + if (nump_array.ndim < 3): + nump_array = np.expand_dims(nump_array, axis=-1) + nump_array = np.rollaxis(nump_array, 2) + + tensor[i] += torch.from_numpy(nump_array) + + return tensor, targets + + +class data_prefetcher(): + def __init__(self, loader): + self.loader = iter(loader) + self.stream = torch.npu.Stream() + self.mean = torch.tensor([0.485 * 255, 0.456 * 255, 0.406 * 255]).npu().view(1, 3, 1, 1) + self.std = torch.tensor([0.229 * 255, 0.224 * 255, 0.225 * 255]).npu().view(1, 3, 1, 1) + # With Amp, it isn't necessary to manually convert data to half. + # if args.fp16: + # self.mean = self.mean.half() + # self.std = self.std.half() + self.preload() + + def preload(self): + try: + self.next_input, self.next_target = next(self.loader) + except StopIteration: + self.next_input = None + self.next_target = None + return + with torch.npu.stream(self.stream): + self.next_input = self.next_input.npu(non_blocking=True) + self.next_target = self.next_target.npu(non_blocking=True) + # With Amp, it isn't necessary to manually convert data to half. + # if args.fp16: + # self.next_input = self.next_input.half() + # else: + self.next_input = self.next_input.float() + self.next_input = self.next_input.sub_(self.mean).div_(self.std) + + def next(self): + torch.npu.current_stream().wait_stream(self.stream) + input = self.next_input + target = self.next_target + self.preload() + return input, target + +if __name__ == '__main__': + main() diff --git a/PyTorch/contrib/cv/classification/MobileNet/Dockerfile b/PyTorch/contrib/cv/classification/MobileNet/Dockerfile old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/LICENSE b/PyTorch/contrib/cv/classification/MobileNet/LICENSE old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/README.md b/PyTorch/contrib/cv/classification/MobileNet/README.md old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/demo.py b/PyTorch/contrib/cv/classification/MobileNet/demo.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/docker_start.sh b/PyTorch/contrib/cv/classification/MobileNet/docker_start.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/mobilenet.py b/PyTorch/contrib/cv/classification/MobileNet/mobilenet.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/modelzoo_level.txt b/PyTorch/contrib/cv/classification/MobileNet/modelzoo_level.txt old mode 100755 new mode 100644 index 0b49b4fb26..31529da2e6 --- a/PyTorch/contrib/cv/classification/MobileNet/modelzoo_level.txt +++ b/PyTorch/contrib/cv/classification/MobileNet/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/MobileNet/pthtar2onnx.py b/PyTorch/contrib/cv/classification/MobileNet/pthtar2onnx.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/requirements.txt b/PyTorch/contrib/cv/classification/MobileNet/requirements.txt old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/scripts/eval.sh b/PyTorch/contrib/cv/classification/MobileNet/scripts/eval.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/scripts/run_2onnx.sh b/PyTorch/contrib/cv/classification/MobileNet/scripts/run_2onnx.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/scripts/run_demo.sh b/PyTorch/contrib/cv/classification/MobileNet/scripts/run_demo.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/scripts/train_1p.sh b/PyTorch/contrib/cv/classification/MobileNet/scripts/train_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/scripts/train_8p.sh b/PyTorch/contrib/cv/classification/MobileNet/scripts/train_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/test/env_npu.sh b/PyTorch/contrib/cv/classification/MobileNet/test/env_npu.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/test/run_2onnx.sh b/PyTorch/contrib/cv/classification/MobileNet/test/run_2onnx.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/test/run_demo.sh b/PyTorch/contrib/cv/classification/MobileNet/test/run_demo.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/test/train_eval_8p.sh b/PyTorch/contrib/cv/classification/MobileNet/test/train_eval_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/test/train_full_1p.sh b/PyTorch/contrib/cv/classification/MobileNet/test/train_full_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/test/train_full_8p.sh b/PyTorch/contrib/cv/classification/MobileNet/test/train_full_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/test/train_performance_1p.sh b/PyTorch/contrib/cv/classification/MobileNet/test/train_performance_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/MobileNet/test/train_performance_8p.sh b/PyTorch/contrib/cv/classification/MobileNet/test/train_performance_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/OSNet/README.md b/PyTorch/contrib/cv/classification/OSNet/README.md index 2528236875..d3978104b1 100644 --- a/PyTorch/contrib/cv/classification/OSNet/README.md +++ b/PyTorch/contrib/cv/classification/OSNet/README.md @@ -1,72 +1,72 @@ -# OSNet - -This implements training of OSNet on the Market-1501 dataset, mainly modified from [KaiyangZhou/deep-person-reid](https://github.com/KaiyangZhou/deep-person-reid). - -## OSNet Detail - -As of the current date, Ascend-Pytorch is still inefficient for contiguous operations.Therefore, OSNet is re-implemented using semantics such as custom OP. - - -## Requirements - -- Install PyTorch ([pytorch.org](http://pytorch.org)) - - -- `pip install -r requirements.txt` - -- Install torchreid - - - ~~~python - python setup.py develop - ~~~ - -- Download the Market-1501 dataset from https://paperswithcode.com/dataset/market-1501 - - - ~~~shell - unzip Market-1501-v15.09.15.zip - ~~~ - -- Move Market-1501 dataset to 'reid-data' path - - - ~~~shell - mkdir path_to_osnet/reid-data/ - mv Market-1501-v15.09.15 path_to_osnet/reid-data/market1501 - ~~~ -## Training - -To train a model, run `main.py` with the desired model architecture and the path to the ImageNet dataset: - -```bash -# training 1p accuracy -bash test/train_full_1p.sh - -# training 1p performance -bash test/train_performance_1p.sh - -# training 8p accuracy -bash test/train_full_8p.sh - -# training 8p performance -bash test/train_performance_8p.sh - -# finetuning -bash test/train_finetune_1p.sh --data_path=real_data_path --weight=real_weight_path - -# Online inference demo -python demo.py -## 备注: 识别前后图片保存到 `inference/` 文件夹下 - -# To ONNX -python pthtar2onnx.py -``` - -## OSNet training result - - -| | mAP | AMP_Type | Epochs | FPS | -| :----: | :--: | :------: | :----: | :------: | -| 1p-GPU | - | O2 | 1 | 371.383 | -| 1p-NPU | - | O2 | 1 | 366.464 | -| 8p-GPU | 80.3 | O2 | 350 | 1045.535 | -| 8p-NPU | 80.2 | O2 | 350 | 1091.358 | - +# OSNet + +This implements training of OSNet on the Market-1501 dataset, mainly modified from [KaiyangZhou/deep-person-reid](https://github.com/KaiyangZhou/deep-person-reid). + +## OSNet Detail + +As of the current date, Ascend-Pytorch is still inefficient for contiguous operations.Therefore, OSNet is re-implemented using semantics such as custom OP. + + +## Requirements + +- Install PyTorch ([pytorch.org](http://pytorch.org)) + + +- `pip install -r requirements.txt` + +- Install torchreid + + - ~~~python + python setup.py develop + ~~~ + +- Download the Market-1501 dataset from https://paperswithcode.com/dataset/market-1501 + + - ~~~shell + unzip Market-1501-v15.09.15.zip + ~~~ + +- Move Market-1501 dataset to 'reid-data' path + + - ~~~shell + mkdir path_to_osnet/reid-data/ + mv Market-1501-v15.09.15 path_to_osnet/reid-data/market1501 + ~~~ +## Training + +To train a model, run `main.py` with the desired model architecture and the path to the ImageNet dataset: + +```bash +# training 1p accuracy +bash test/train_full_1p.sh + +# training 1p performance +bash test/train_performance_1p.sh + +# training 8p accuracy +bash test/train_full_8p.sh + +# training 8p performance +bash test/train_performance_8p.sh + +# finetuning +bash test/train_finetune_1p.sh --data_path=real_data_path --weight=real_weight_path + +# Online inference demo +python demo.py +## 备注: 识别前后图片保存到 `inference/` 文件夹下 + +# To ONNX +python pthtar2onnx.py +``` + +## OSNet training result + + +| | mAP | AMP_Type | Epochs | FPS | +| :----: | :--: | :------: | :----: | :------: | +| 1p-GPU | - | O2 | 1 | 371.383 | +| 1p-NPU | - | O2 | 1 | 366.464 | +| 8p-GPU | 80.3 | O2 | 350 | 1045.535 | +| 8p-NPU | 80.2 | O2 | 350 | 1091.358 | + diff --git a/PyTorch/contrib/cv/classification/OSNet/main.py b/PyTorch/contrib/cv/classification/OSNet/main.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/OSNet/torchreid/metrics/rank_cylib/__init__.py b/PyTorch/contrib/cv/classification/OSNet/torchreid/metrics/rank_cylib/__init__.py index ec62d364d8..f3bbfaaf4f 100644 --- a/PyTorch/contrib/cv/classification/OSNet/torchreid/metrics/rank_cylib/__init__.py +++ b/PyTorch/contrib/cv/classification/OSNet/torchreid/metrics/rank_cylib/__init__.py @@ -1,47 +1,47 @@ -""" -BSD 3-Clause License - -Copyright (c) Soumith Chintala 2016, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - -Copyright 2020 Huawei Technologies Co., Ltd - -Licensed under the BSD 3-Clause License (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -https://spdx.org/licenses/BSD-3-Clause.html - -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. +""" +BSD 3-Clause License + +Copyright (c) Soumith Chintala 2016, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +Copyright 2020 Huawei Technologies Co., Ltd + +Licensed under the BSD 3-Clause License (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://spdx.org/licenses/BSD-3-Clause.html + +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. """ \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/PCB/README.md b/PyTorch/contrib/cv/classification/PCB/README.md index 1ea64639ba..5bbfba757e 100644 --- a/PyTorch/contrib/cv/classification/PCB/README.md +++ b/PyTorch/contrib/cv/classification/PCB/README.md @@ -1,61 +1,61 @@ -# PCB - -This implements training of PCB on the Market-1501 dataset, mainly modified from [syfafterzy/PCB_RPP_for_reID](https://github.com/syfafterzy/PCB_RPP_for_reID). - -## PCB Detail - -As of the current date, Ascend-Pytorch is still inefficient for contiguous operations.Therefore, PCB is re-implemented using semantics such as custom OP. - - -## Requirements - -- Install PyTorch ([pytorch.org](http://pytorch.org)) - - - ~~~ - PyTorch版本:CANN 5.0.T205 PT>=20210618 - ~~~ - -- `pip install -r requirements.txt` - -- Download the Market-1501 dataset from https://paperswithcode.com/dataset/market-1501 - - - ~~~shell - unzip Market-1501-v15.09.15.zip - ~~~ - -## Training - -To train a model, run `main.py` with the desired model architecture and the path to the ImageNet dataset: - -```bash -# training 1p accuracy -bash scripts/train_full_1p.sh --data_path=real_data_path - -# training 1p performance -bash scripts/train_performance_1p.sh --data_path=real_data_path - -# training 8p accuracy -bash scripts/train_full_8p.sh --data_path=real_data_path - -# training 8p performance -bash scripts/train_performance_8p.sh --data_path=real_data_path - -# Online inference demo -python demo.py --data_path real_data_path --device npu -## 备注: 识别前后图片保存到 `inference/` 文件夹下 - -# To ONNX -python pthtar2onnx.py - -``` - -## PCB training result - - -| | mAP | AMP_Type | Epochs | FPS | -| :----: | :--: | :------: | :----: | :------: | -| 1p-GPU | - | O2 | 1 | 568.431 | -| 1p-NPU | - | O2 | 1 | 571.723 | -| 8p-GPU | 77.2 | O2 | 60 | 3600.983 | -| 8p-NPU | 77.5 | O2 | 60 | 2750.401 | - +# PCB + +This implements training of PCB on the Market-1501 dataset, mainly modified from [syfafterzy/PCB_RPP_for_reID](https://github.com/syfafterzy/PCB_RPP_for_reID). + +## PCB Detail + +As of the current date, Ascend-Pytorch is still inefficient for contiguous operations.Therefore, PCB is re-implemented using semantics such as custom OP. + + +## Requirements + +- Install PyTorch ([pytorch.org](http://pytorch.org)) + + - ~~~ + PyTorch版本:CANN 5.0.T205 PT>=20210618 + ~~~ + +- `pip install -r requirements.txt` + +- Download the Market-1501 dataset from https://paperswithcode.com/dataset/market-1501 + + - ~~~shell + unzip Market-1501-v15.09.15.zip + ~~~ + +## Training + +To train a model, run `main.py` with the desired model architecture and the path to the ImageNet dataset: + +```bash +# training 1p accuracy +bash scripts/train_full_1p.sh --data_path=real_data_path + +# training 1p performance +bash scripts/train_performance_1p.sh --data_path=real_data_path + +# training 8p accuracy +bash scripts/train_full_8p.sh --data_path=real_data_path + +# training 8p performance +bash scripts/train_performance_8p.sh --data_path=real_data_path + +# Online inference demo +python demo.py --data_path real_data_path --device npu +## 备注: 识别前后图片保存到 `inference/` 文件夹下 + +# To ONNX +python pthtar2onnx.py + +``` + +## PCB training result + + +| | mAP | AMP_Type | Epochs | FPS | +| :----: | :--: | :------: | :----: | :------: | +| 1p-GPU | - | O2 | 1 | 568.431 | +| 1p-NPU | - | O2 | 1 | 571.723 | +| 8p-GPU | 77.2 | O2 | 60 | 3600.983 | +| 8p-NPU | 77.5 | O2 | 60 | 2750.401 | + diff --git a/PyTorch/contrib/cv/classification/PCB/README_raw.md b/PyTorch/contrib/cv/classification/PCB/README_raw.md index fb1ecd0cbc..4cad0051b7 100644 --- a/PyTorch/contrib/cv/classification/PCB/README_raw.md +++ b/PyTorch/contrib/cv/classification/PCB/README_raw.md @@ -1,51 +1,51 @@ -# Part-based Convolutional Baseline for Person Retrieval and the Refined Part Pooling - -Code for the paper [Beyond Part Models: Person Retrieval with Refined Part Pooling (and A Strong Convolutional Baseline)](https://arxiv.org/pdf/1711.09349.pdf). - -**This code is ONLY** released for academic use. - -## Preparation - - -**Prerequisite: Python 2.7 and Pytorch 0.3+** - -1. Install [Pytorch](https://pytorch.org/) - -2. Download dataset - a. Market-1501 [BaiduYun](https://pan.baidu.com/s/1ntIi2Op?errno=0&errmsg=Auth%20Login%20Sucess&&bduss=&ssnerror=0&traceid=) - b. DukeMTMC-reID[BaiduYun](https://pan.baidu.com/share/init?surl=jS0XM7Var5nQGcbf9xUztw) (password:bhbh) - c. Move them to ```~/datasets/Market-1501/(DukeMTMC-reID)``` - - -## train PCB - - -```sh train_PCB.sh``` -With Pytorch 0.4.0, we shall get about 93.0% rank-1 accuracy and 78.0% mAP on Market-1501. - - -## train RPP - - -```sh train_RPP.sh``` -With Pytorch 0.4.0, we shall get about 93.5% rank-1 accuracy and 81.5% mAP on Market-1501. - - -## Citiaion - - -Please cite this paper in your publications if it helps your research: - - -``` -@inproceedings{sun2018PCB, - author = {Yifan Sun and - Liang Zheng and - Yi Yang and - Qi Tian and - Shengjin Wang}, - title = {Beyond Part Models: Person Retrieval with Refined Part Pooling (and A Strong Convolutional Baseline)}, - booktitle = {ECCV}, - year = {2018}, -} -``` +# Part-based Convolutional Baseline for Person Retrieval and the Refined Part Pooling + +Code for the paper [Beyond Part Models: Person Retrieval with Refined Part Pooling (and A Strong Convolutional Baseline)](https://arxiv.org/pdf/1711.09349.pdf). + +**This code is ONLY** released for academic use. + +## Preparation + + +**Prerequisite: Python 2.7 and Pytorch 0.3+** + +1. Install [Pytorch](https://pytorch.org/) + +2. Download dataset + a. Market-1501 [BaiduYun](https://pan.baidu.com/s/1ntIi2Op?errno=0&errmsg=Auth%20Login%20Sucess&&bduss=&ssnerror=0&traceid=) + b. DukeMTMC-reID[BaiduYun](https://pan.baidu.com/share/init?surl=jS0XM7Var5nQGcbf9xUztw) (password:bhbh) + c. Move them to ```~/datasets/Market-1501/(DukeMTMC-reID)``` + + +## train PCB + + +```sh train_PCB.sh``` +With Pytorch 0.4.0, we shall get about 93.0% rank-1 accuracy and 78.0% mAP on Market-1501. + + +## train RPP + + +```sh train_RPP.sh``` +With Pytorch 0.4.0, we shall get about 93.5% rank-1 accuracy and 81.5% mAP on Market-1501. + + +## Citiaion + + +Please cite this paper in your publications if it helps your research: + + +``` +@inproceedings{sun2018PCB, + author = {Yifan Sun and + Liang Zheng and + Yi Yang and + Qi Tian and + Shengjin Wang}, + title = {Beyond Part Models: Person Retrieval with Refined Part Pooling (and A Strong Convolutional Baseline)}, + booktitle = {ECCV}, + year = {2018}, +} +``` diff --git a/PyTorch/contrib/cv/classification/RegNetY-1.6GF/utils/progress/setup.py b/PyTorch/contrib/cv/classification/RegNetY-1.6GF/utils/progress/setup.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/RegNetY-1.6GF/utils/progress/test_progress.py b/PyTorch/contrib/cv/classification/RegNetY-1.6GF/utils/progress/test_progress.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/RepVGG/arch.PNG b/PyTorch/contrib/cv/classification/RepVGG/arch.PNG deleted file mode 100644 index a17a7ac3926baf8c1108dee5bbcdaad2e2bf6a53..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52779 zcmcG$by!qyyZ0?BASKcaAxd`)EeO&`BPb050}LP`jUpH@)Bp}$k_spS($X@tv>-@# zcSy&3jq$tp{T_SocR$bjJb!qwT(Ig|Yn|8m{hZ%(1#4+25#iI|U$}6A=&rK-y$ctx z62QOAD>z`ynLHdD{J?U(rzCqJzl&}O{O7WbjJnK)3xyE`C+3)6;yEiDxL&w$wE^=F ztHmh?cHu(jm%H*Zx?ZNMZ?N@sZAV&KzKpsTdVV*tTx)i0>N2UKt&-5fs;a8`Br#ap zQ`$tOpnWHi#UI-|n93{R@NA-@JNZSzlp24R*3L=(O6_j)j&oPSPUHEK(M6nB^$+>g zE|Wnp3-N@kP(rZ44^e|rg9USFd@Da#Xn^sf%)tVp?IB~sL$DB4FOLA*QM0}ZMxs7H z-RCWH7-6LoaJkihAd=J7jdpJ2#}#oJN8%D+zoJC=%$(7Z`6`1HQoyqLiV`we4p?;vR`G)k@JJJ6Ug1oQ*F5z)-s5@s^5u;f zm4IAiGT6}$*ta>@2`Mx5^mu<^;TxZ6HMM0+xI($(SWktk&F*6FCD-|mdK8n=@ zMmF3#jIMKEDSXHLBO-{;_Uq2^^r*!tSfL1TEM@o#ud13_BYkL-tl$6xJ2e}FcrU8r*bFKU2#K;Kk%0Ql6mB$*t z`?9XDaUjb5?nZov^!drFk#eVo@$nR=pIV}v?z#6AUIlCHJ^ynu6P!@|vyJmJVqRX} zcp+O-vukg}T@mitRx)6xsm;zg5)R)#++Q3n)G2otv_vd05nG_W38v=ohan6uS7Mkm=&3O96s}COycS5BGCJn!|Y8 zlSKI#{455AAh%b(y;DW^3Cl%E!e8*N-AHSv5p^U~RaKRu4>lQWSv1hl&_MUOifoM6 z2#R%uQu2IVa4ob?M5YKkjZ01~&Et_lgqcb4cqhD(EBmQQqv2+sgGVb|2{g|)7zk4&F%+RD<=mMzIk~%2`YvYrbq-lTMNGS!s#a62)IjRR|S>4Btd0lsM6YIE6_KnsQTr?)JBbam$8|=z9y=Er zh71E`!cKk^ik1x02O)#7LTy{|z^|rjZ2Pjz!O)^1h+Ar~*;sdZR#Lqq(Z&+C_Y!)l zOey9LRW6HOQnF&1xJB&Mqx}p-ocCoLWQ;aBIo)q^ktHD6MuOF5W6t1WYk2n}(}gZ} z50uGOgfFD~L8EUj&#~@0Y2n4tTt&y~X^%q0X%w0#AY6fE3Snln=@a=8n_6}G){YUL z5AWnw=D>yNl1$IJXquzJiAlkWtvk^maQX`l;q_68B`UC9EEf%z-x=a|v0oGIc^{HIvoHx{x z)Z0vk$@o;^?opddS5_mc6?FTJ9@(YPO7nOTG*zoQFlK6|s0*KdyF!-0%>@lU_%w*M zzpEM$B+ia!r#aSn|Yjt zf|2F>1gll+1jN#8$iqS*#5qX3!kI zymfGm)^@17S0AGbFX0wi2Hd_{aWvWW@$2ho`T%vR3H01FO^3mH5WS9~c~j@HSf!iP zRi9Z4Wy-K}Hc|7Pff#C|+-r&Vl2w_u=BKq+KP836==p3Gv^ehC>f^dEvl}${{#ZGq z2;s4kBNmZ=hrQtzicIl-V1ATE!U{D|fJMqpx~*Qgx~`9PESJAoAxIFzVkKbLr%>%) z5hUyy+wi!B9BKHNY(Ijx>Eseag*=no?nu;+5^t^t;dueF>UUvpgM3^`lstc!uYcv* zJRH1Kbu6T-?(a^MF=6WIqpltR*SEzQx1~tX-SMi0)GSDTd3q*B9{BY9r8TYelxq&| zK>0cL8~Rr<==0F0_6UpRPUm;7?_){85VL8hEY3Cw^!1Vt(rQfaCAg7`**!j8dUixW z_h!the&eC^Lz1rJwup&0>k&{M&q-}Kcgmv;f9Mz=T7je5ZdlpAd5QNJ*9JFE<`N6a z+p|pC*RBwXJY3DZftVBqUNk3GoiKIT_r%AUt&Un8@+t@DqIOD#IkQ4>}`Anw3;V9eX z+KGrVX?^o5qYK7nw-?IwRSNa;uY^-w?>t=#=)F`pDB(`!IyPoy=RI(Y|0LS}RZLgm z!DadC0ZtgbzDgG(IFpO^ig7(4ld zpT8~s(#r}R_wCY`UZheE+53_hogW1sEp-Zd8QX*^_`u_MmUpG#rbAA`dwIn8%Gp=e z(WfzYUMzpzXfntOMG|Uj2x{GrBo;=j`MZ{=-GzNFd*7#gGP?J%=R19{t3$i_4>{>% z2ixE-z0A+9h0ZkE2>Tk}=I`U~{CkTG)x;^s#AcH-J61V5chGzi%7qtyenJbQjwLu` zoeKQN-hGL#R)^>pTjD97pvcB3SSC>7;jdoQoW+95>ROf9XBl(_}s5a{Y(#jU56mcL1w+y zyZ7OklFtJ?hKTaG<_!6z_n#TR1w^74Y zfYP1L_;VS_>&ep#e6lf?IuJ;0?P!F1wp3dK0-I5Vvo52GB}%0G9zoW98Q$A-4mg2> zg&(H+-jdw^{UD3)(n}!%rsm2V57PUYCC_ECH6Pn~^#?S(97KMS;9!Q+#Y5x1{QFb}!X(>TSS zhXs?@XI~!vR7vlE$UOO67AgNWZ8*HfRys`m5sp!XNsWj1A;?+^7{kkw`U9?_A@Jj0gPU*wX zl%3nn?7d6eXPH-0ml(+csdfxAHilI{msCn47rvdC{uZ>YL<`{>Ze0AMKk@swf5&nAsm>LMqiI2&8+jEKHBs zicGk08m!x#7?%lsb-NXE!@M@o5jCYI-u=W(F5;d$e;)__x~5*5N1N$~F{@;bY?8Sh zm>R4osI{>sJ}~y#;Pkh5-xsA%s86P)E!-Vch2E4A``tDUMMOqY`|(@|{>CqvY(yD( zv@*4NetE~9^3D)%6n}RXC392DbkU&Eqf*|BcMECY0}eD@A=$DT50m+m?D|;RrxsG% zGu#q1#5mu|K1Kzj9jYARA`b-~tvLv|k6Bg|M47qnM1WC>1u24j^XV36 ziIX^aUu;41?vT;rAqi7o9`=jtX7?JNoh3EOyAErKS_UCo0;L7AukI5yC$}*9P1VRY zjfb9{^O>5KDyj3H6H0I4Ins=`_g^|Mnq_W8c-1F8Rl@$($ejP|J-xvR)j?o0Bd;Xg zR><8Kcg;x1cPS9-GI`oCq4^>BXY8hT2!gQbCV5L5Z9yp z?`EW1wye(}(%~~AnsoWRuwJcRxg)VEF`k=WKng`5NYb2c~hBPgkS=+f$ zH&dBQLY?IOdn7xQ36b`_7Z+$}3|&=ODV*#zDR-E1VdO6>98U6 zXm&`qk1vcL)yByf70@$gVl9c;({*WILRwndsaDC}?5d9VW_i|~-rTB=pk{eQuo_K= z0_=*5&)#$s!Bi{Ij7*}e&@6BbYOrs2iX*>9A7e|$6+Cp|(k>!DukK)EX1@GJ!gHSL zQ6dvFboaDrx|v+D`c^W9RvvqL4XCtV1-C2_9 zt$o6%?&{Dul>??7P@z)i=3y>9SKjmfPlOK zM7F#K2pUi=>ka$ZH?3Dt>07sG1T!5A!)QgfO_Goue}(ms2@D=+Eg>N>6_g&_*eGvY z;etKkcYYg4Kl|O6(vp(NsV@dg3~ zUwgV%l08)Ax#7=*fP$-0dWAzYxwOQQjFL047AlRo9N4Tu-lO<-)>MX`G^RUMdIso4 zYAGMFIxdllw%W%tICW#hOe+9PV1Pn!@(t*0w&mgW9GXN9qX4xlT&(0374dC!Z$3_! z@pf@l7pztOXiJh(TrBwV)vL!l^Xeb<3tv((*btqdPbU(;`*cJsi-tORfXGF)8v(AhI6ZoJ(5*Dkr}Wg z#y883GzD{|YmAzx#t~ugCgEMmwRLLt;qpFMse7D^%PJ7Tu=i2Ss+g`1J~D z&q$vi5|3AVM>#U3g6$YR)RPiiXsJ3G$wKwYJs!$;+dA)R*Rfh31#~+y%B^QNP0KT6 zCctJ#6jl>O1gVIl4Jc^L$U>=}Aw_uJnG`nV+X}ieJ`(`^dC0OJ}8Z} zeRg6`nc%mzF3r|EA4vIQ%iuIIeu+w|Dj11wsnZAgdC}nL;J_ySYCwcv;ekNFTyblI z&k4af^z!z6Ti7}F>ePn{WAld=q0S>6$04E=hE?q+XYv!!ycl_=|3rI~`fJ(`X~SZ> zS6FC7vp#J#7=knqrVKL_`oK&ho%Jacmu*|ZJ_#f6`OQ#M+>1Pv-}(F*Lgtj_y!oc` zxvCQdP`!?7Fen2n6awCJ;T(<{uP1ukN#7f0Mcm!0)RuW?)YOD>u=~nx>}&i^^#&+R zJBu<~qxp=~gdEk(o45%u$0Q%Kve>f3w;%sRy249#W_9JGVQI+3x>SuKUNF9Uq5Uv2 z`F=vku16gGnhDMKg}RqdUlYs^as_Cxxq5gGWhzC;&wwF6?PzU5{t$LhBvYkMP zXC1wJ(qv9PG7WpY1;lU>#LN))wPE2V@|KcQtvcUR{zpIfk+h;$1+6=t=jHJXJ-tbzcF8!VokOhv77^ict*Vkpe)GnABWbX}Y(W9hXg&8eCjRzQ z5k70?hhNdcAmE$E@2w6s5JV;=(fVm3mi~!5*AhUiwmdo50)d!zdCcnk?3k|(2SFF# z%NlYChwx6e#+!o&?HLN8VD7>;)lzP)qpx20wuj1mU_#BZ=f9Ef885rQ#9aJiWV~Y~3a<$euF-1-jQb>9UN_q*8*{ZLLMp5hu z8MMgDa~pN%%{5Q=y|5U|d-^Xj_9lrvX1q!#_JyGT{A^!(ijVr}PsG5?AG+6?T3QH{ z2pxRdzeu~k8>@6D*qQH?!%T3_lXq&9I{V4+lznpUyRMIl*V-2tl{@<629Cd~Tw-Km z3V2N@@b{LF0n9YP0JftDr>^9mUxh9o-SSwa<`dCf)Zt=dXIK7gXBZh3bx8Rg0Hy;< z%F+^c9%-M0*QIX#e@D@S3S!vibG+vOrf32kb#o16H&DkalD2 za^rHI8{?gxd8ke8a+-HkuKxc@HQ@7Po$?lonuc zowE??+vau%18d4nT_%T#+S|3hr<}ObtFRWQ&rXkh%A6_QwS?GO9TJq{SsSYwWGB#24=5-ofLF(VgFmShZ;)3c8lHWOI<@0A zsi>b7aagyAsx%wGW;s(&62ViN$NjG2mv>Jc6YW@3&vW9Atqg0-YAsmQQpBa@KHjN+ zDdxT$z3JAFj)z4n@@TRpoRN{yzu15v;MfWi<4f&EQYy?SK}-a%EN;q8fefP|+L5yv zh`&Ws2%ct_K75|ky}U=ta2`Ln<0H1J!b~%{2)vQHMxoi`@K*2Bc=VH>^l);3y>-$! z9D32+A8~@!UNv{h*S+F+w2$gr94Rl@blU;9kY=6{+8?Mvu-*YEtBYV+>$Q?gUI5P@ zo(>m*fCjzJ3bl)W)p~Ncka}_zJ%5!9Qjs7FyP~P7={s-nz>Y@{)#er7nv<>#J9$&+ z0ypYEC?z>sJGw&rbH#3c&kGl)ntI$R@{hhIox5tZ%^)B!Fj&m}7^ikU3|(};AKH{_B*CAtAS8AaWD=JIFp8Ml z;M;cZo(pv0E~i|5@LaU*NjuyUF~PkKmJT@8|m`kJ+#8pJ8{3_@WoIh(9`= z6Wo&Ev^n#8?9{2HRs+d*wpr=l2+bITu=43~j3p|4vYBwZw4J$K9p|j)PfXCVw$`Bi;2t4;S&(NskQF_Op*mS=ZQtyvp)?L)@D`9iU-`ax z3n%_~cj;Dev&k`n9d1B(_+fZ@ej;R(<{Kh0K?NpMM`dGh2R4vr6lcYn@ZZ5HbH*qf z6CQ|D!3eeSG8?j%ODN(!CaYkMtcHJDXOhbGk7yZDwbaho)iowrk_A;B@6Aap-{UpW zGWRN)TSidxn_}WcLMrNBjBanVRMT(cD>Ju_cyT4m-fzghOKWF+3)Q=A3eIJ5zuNEI zRP3vhSwSsjOi+G{5iU{|AsMt##Q@UHopxvz|+#41?T+ z0)04J{)nw^m+-z@2%*ge9d5>(K8d={}~8 ztSh{Id!`B8(0-RJfrO7m4dwp>A`;*FR>l~X;XIO0n@FTjX!O)b&19c?13f!9dYU;E zL&{6J9?gI5(TwhL=y|$+i#xIW+Eq{4sW+so-_>}aLSHnEp7BQnPQytd`z^UWwR2i( zMzu73Hcm}e8(xQ{X;(h`-6h&TbRs3|w3Qn}LO0K+G&|li$=ppM@R}`Ht64lhpPsuf z(I0&hgkqDfS8sTla1X|7QrYO_7j?gf9ZIwFNNDus^u2}v#Vv~rfv}w4C7qrhk$6P) zQB+x@r7+_9MFDTjr?Z`U*L-W6+BRZ0abPwb8gV~uDmQ3DdjEl zeOHx94Tc#CPtSy{4qZk$snNDvMk9hu`e&8xNL!%sr>3UhgZX2kPSv)Lc9(etGXy|x z7KK;^qkUcj3cNpl{D}XV0t3}+MaO2!1kF^bEdpOqp5jVwy9HDPCeX=9lzj6zC(G&- zsL)Qg{Ad#2_Tu}O7ncgXcdSL!4K$Tuz9;WLVya%X=e0rOj5;;e4&0`-B61&FiDMN> zAS#}L#0>N0k$8lJNfIdu_A-;gB@S*qVlJKx|5lHPa21|za z)U3`PW-5W&mz1RUw!DzWZXxIW4?!t|RC5jAvn z5{*@PE7evCuZ$H3&0;=Q`UDlF-jri=ZrpdgTTwCKw?o7}!?Q2=0lLN(b zMaE2p`KC}RP}y$YnrSiE*Jpigz$hnJ3R2JZZo0R^S_#;tDS2D64{@WfWNd=3&*U|jl=A-HWva_0gG@DZ)y7xY-RW{7#SD2ZUp>(_T0%e*ount&2MD(|s#QRFA`{W_Tr(K`Vhpz5tv^TeH;*O+?Z z**^W(Se{S{t_PDVg9Wne4QawSx?i+d*|039BM*C6BQh1kre}_hH|mt?Ut;$b+i3b; z`sNfcO5rq8Mg+1+IgrRZgQS_zRzRzAdw+kybLqOMBOPA~a5ppo&2caw$n?jza0jkP zOjHZ%%P||AI>6=-0y6cC2YH4*VM4dHas%wbbYH#WC9R}lvUff|dlt=Y5XnFl927L! ztxc2WeiIl51f?IO6FMwJB`0&!y$i@Ut9e2Jw8JEU2Pxn10vB*ITrsCn7E4Y}{$$>O zI@5p{@ z{tG!z)4jH)IY$dI*f^~{_=CQTX{3XR3TD{%Vb{&)^j!YwYpm_wIpw&wBsW3OG>V|h+k zU-SoR23&=FcYgoL+=Ofhm&S(avGN>2_&y!M++tQhp%AN546%ao`O!*&VK$A9Cyly# zmhF@}hi-%tH96o0$Rv{7<3G>Ik4kqgX)+~9VJsn0K4-aC&OqY#GAWxyM6(gxW=i*4 z87$}cgEETIhajeMKsg@HpNew*Ep!NdSmw;V|C0OCCO}BWFvd@F5sl zB-)QodxO#m4p@0_uNC4*C+_0!l)#=gMh!m+`)3dSWghAE_tho3zBLDwU|(T6mKz!9 z+nxJGR5S5QUA{(hGdPWUG<|O+AgdzsJP3s7;-*L9SBAf4 z>%PC|lZ&vXA{D}pXMJ&UFcWdI3RUbv{L)5;ILi9)=Vb=P*40YtMc|Ftyj1?^E4=Gf z7NHJ7Om)J1*PA4>ElvA(05dW9Kb!@V*Dq_7jE*veU>CJGgW)lnA6Teb;mA0ZpE{c!vHoxD2+=xzlSpc#th=_WJU{o zI#elLt%NC3&q6pURD+u%I3CRu`JTw%a0Qn~xAP>p zIgI1c$)^WEK0rtlD8o20+pbR62cKBy%oAde5sT}{<6G-*-dMRvRC&^!ODfLaVeG4L zP{$nG;QLuZuo|lzqfSTBYxqe#ItyvnZU{x!5n>HP63Q&H>D~J*OWIxDsl><^*g}UT zqeO1OU{_0MJ#ru9$n|NRLh^S;*HX>t9v-(I!UHl4UNVV$5m&Jh17So(A{sk(w>8j#iKXk~6u` ztCKG4#|4~wTFBMs8C6J5irITfCtFcQj@#cgr|-msVC-(4iNe)s)S1GxR8%cho~$Gi zp6hgcYO{q=hTY7vyJ{+WAo7bn*=66j6nH2Ez5X{3fTSq7jlpDxl-E{R z+m03mS>^J+1LxvHKxU|Kxv`tQzd>^2aheyKpL{c-a(i*SKP1cX7U>OA20Mq&ROwXd zjj1WD1U1$ZY&o+(*I^#inzM6u`n2}Ojq=WZCk7G{@W{i23F!~moDxMHN5252IqH9E8At_jtCIMD5M37^g$6Pja7D<_IC`KueXG$*?$NeZ*m;Y>Vf*oh@oXbNMJUUmU^t z_rkM)cP`)p(ZvWl@kr0}_Es8dRakU7FE?i+2rr>PlcIqSFx56zyJyGNVff&t6I10U{`Gf)RE*u(#bvtcKE@M><0MF;6AG}7U>Lrb-58y; zucVGOV{=Q(PG9leO&lVcMuM~ob*+EpfP^x|k?=}x3O6C0Ak-F6m+S|?G1=ZC5lloh zVDsQ6!?kN)G^4Wi(}FJxA>dd4k|bc@!wT!|xv06^{ID-YFt+0w1iR!QlJe)bjuIqY zv38(*MDruVa>q{1u&yN@`(N*>B9UR3-_o~tZX;h~xDL;NZEhHOG+c-M^#{n)lt9+? zL#W?vd#R7DSFE>Xd9Z-*iD_J~4m{@4m=hC3;e-jfj0OA~&iYL4eygwtaOGz2s^vK;9QS6h0B{#!zHGiM~W zvIjm!q)ypt_qtUGKB~4W5s&s@5bq=?z+kR0ppN8aWiKKKA?R)?OE^esMv)xACaGs@ zsHSFOYk>Es4ghL>*ZS|v7zOrZ+(Lkyu(gw%QBEuLNq>$uT6^Gmuv#+)nuRgWY#?Lg zMlzZU!g`zrmArC*Gp@Wvf-Lnf3bSNASaPF1I#9E>fUvG=*)UJq!VZrjsf?>l8Qjz;HZg_T$*uNV0_ zTWg66X_G?oHsh3FRRB+32%W?0%4IX#Z>RpHHxHU}~M**91g(o?Z8!V#~Qw`|H zPmi6WW60$Kd8SR+0SvjE*P2B{JR}RfUjn>?se%KE3EQ@nzUIQL_rK+!?kESbQYMO=&_&-(^pSC{w8@ z1{2B{eeJuI`1c z3xcNJ@pszK&bU6~Ry_2rxwq(cFRx(qnDj}hVd$|PHmQMP2%(HdFPuKCVpaGZ!N1vc zswGAkSnPP}^Xf9U7VdFHFM7zlt5OqoU{8%pYO8E7snMgn22pV}u8Y=m5raAb_vi7H);!B>v$8naoyrM{%z+L5M056-`rUaI;W`^>3c@ zUm8vbQRxty*~>h+Ze}pnL?dXS*UI+wh*3s)E?ir+?h^ClSmahG071N|U^+0;0QR=EMD zl%+1*NkN)m%`*a21jk3iFvBOI9UG@OGhfHpAQq*|1EPtoJ_nmGJgxT@QvL94iYS?( z6Mkm$80+<=z%Yv{eoWza*nKt9d|Knsy1WE<%W^A)>wE93si-mgi-=5(ut z0plJY=i}1L3%~V~1{Ty?43}$ndLe=?DKBqvsymIfqBISWk@AP$>Jl7IFn@q)(r6{@ zj&FWm&9ywE9GZ^tp)kYQ0-qi4Z5fsMoSgt_v-O&56O>-J#|65R#T&|ByK;62X8r2F z7`hK@wVwdFR{#^D7M9hjMG)N>;4zdXDTi{$C+a_H- zsYp^tqP0d+lE?Ze1hh%W-MRDJnPuii`PY8K^nt#Etr_pa_O>yL#DB_Uln}$dJAyAe z3Mcu=K?v>qmMG!L%fOc;>eLJhmjPT^f#0wkWaMjul=VT1;;$OVYbDMX2l<;L6&1H$ zBcS4KjAGLSE);5^^*bi=C9g|iZISTd5)P3^Kc2U?D&O><(yG@m`qV?nQz`8peEaDh zcY}ZGgSk|(#}~oK&8JE~J8~PXeKzv3vcc_7G9SFk3(e2Z_o;8b7FhY-_w=XUxE1>6 z%HZMqPbJT8S5Wb4XI!2LcuN@kiuXlOP|z1Z+75ZyIe!2+77Vi6cpv`M#>jEcCpD_1KInP_n>LX5A0Ecq3&FWL-J3_GT(EoYG|2IcfmU$>>+YsJ-$1`QG$c8&IkjYKJ>TTCIceN zChCBe$Wp)28vZvWs{(VA@DiYF_)3J>z>zq+KlQD-(tYJ%;DWmVYO+V;s*rtz&uCwr zP?@=<`q!?>)G27AO^0e`X&6xAj{o!oM-_WLjr` z6j+BgH>c!`KRaWA#rYO{cp%PjmOtzD*V?%-v_GDHg$s*Ds#Ise(~PA>H8td44-+_2 z4`G(?=@A~doB(`^d#;r~v0I*oH;qwGX{E^q-~%r}VMuFF2lw!;AY?6%LzS$F?bm@) zdp%SBMYCI3oh-J=2tyg6hR{8UOxt5(u%4=o$>>WpOc^qsV&8Wxt8hwD58 zUt3fD4t{n}2k5`?@)Jbr!aoLNab`!BvB{#gR|~rE{(X)(80B8Il$gFu$9KRn zsP*yojg58jq;iiCw*BUxCjh*2pnm@o{KMI{ZyEP`ZKi~%KS)YKFictWK(@V9$PTmc5pC8Ig9fwN_Lm|Mf>e;-2_ z9w6jUhceCl{vEt3R5e*`2x5kmIYXin=N@C9NS%GEyjiMHS`$Swti~>T!6%e!p3SY2 zZ~_LonQGITCntuizxriLEnBYs>6d{!G^DFDIr|*LqedtLu}*f1NK3?-@)$*N;RLaY z?(LzNnEj29rG&v9k&rQYOy$?^jw>rPfiPHY=E;0f!hpneZ-<=?J86u9k@!jWbW zjL!Y1^{?6h|CR=-JM&qqvQ2IV^P>IIa#x;6ctpvR*U>Y4oxPKp2JVuOe zS4)*L5wn1!$HwSE*jy-w+_WDlNBWRw(S`2T;d! zKzc3&JevIS;>6dxe;d>sBryIPVf%qe;Q2Y|_B*re5rho?)yo>!ARod&z2ZK&vR94r zWcS`jPXwVZkJQ({n0W9O=mL%;mdGnT*B>{(T%X(6=ys~T8+!ZhCOhxl=gONoKixJb zWvZY2#NXQ5LYoPE`^N%O)!Nw9v?XkT@P(5>)WJMF4ZMIpgOE~Lc*JLnFVs>bYxyYS zG1Kz61mFM@Yl_{gJ?WPe!|8&7OK3~#@eg_8(|=}LDp0KH+8nbYJmr^%^{4al7@pj6 zoma!y?<{Y*CCA6J`|}eq!%LoBD=o?SE>{=8Nv#_s<-P469FFrhjEpHDD)m5W2IgB{ z&{?z$iUSV;*z*ykQYTE4IYVw&-}Uvse)~zI6OBq9_wuxa^W+6-g7BMvV+Y6<&d!dV ziYFTRYT{)984;l8+#D&fZ6IC@3=AaDgW_zzUS3>m?S9VGJ5=pmJVXF24!=4q!DRnq zWMrrKE%lM59bh$4SKvtuF3d_}w#-rxqP)5E{8G@9nhrW1eFi_gui7p8$K(iXD#c;L zrS@^=V^Hw`kfd0_10N+;KC-lIhAnxJvaxC5lNYA?d!@kIo7I0^!b1%> zdsVH0lg3a~t~+}xse|TiwhCU}SUShI5=XYosvYR1-xMPZIEw?j`Ikz;qth@j@Bmcy zG84_MW%8&$plDn>6+K@1*6AlNS_;vstyc49VtH8J5o`>n6MqQ`iZ(}xtP-if0jyqG zZI_8RG3h0|7-rGgm^lQx4@)3CAB2A~i+9fmZfWi0&HXENYJ~8=jv9&yK6}c!*6fT8n#si=Q?y52T z>{f1?Hf*<}7{5;xIPrfuFUG8{cZ+83C*yi`GXzdMZj1 z(O;qq?dCo1%^GzQOFQBD{w=8TR}CKr_;MrmBla^lx=HmthN6ZguRaM?_(?DoXmP0R zJ+Ath3mq6Rv$r?J&c%VaYSdVz1-%D@(-S*vICd4c_5TlBxE@!wpVcSG%=O6Mg_VS) zPNXgxWw~dC5I$S@SQMoFzs@I0###7iJ{|{kb56}{?S0daX1`6LCts-rRe`}JNE7oP zeGGUmj{Sxw;nTHbIs=+_tdb;^8adaTA}*5RZHtWKXKQ`mwEbhN31z_8YT&mAW?CWw zGCLGJRaqTU-chRMz9d!N7J1dMqL2AoOw-q|yUQqN0>eEnYnrBt{vrFg#M4$c^&Ed) zhBw}@f=U-!=&R3)8)$vILE9$*vcJNk7A%nBOgH!p?X|5=hNgRN=R4q&c}V>UH1F9 zf^RY=&)l%>;#S`cn=~i5&}d6({$?kQ3at3$YnACk&znA#mN)ggM{Mz``F4&;)0lEh zSxjl*?Ks(Rua4r>EaW$2coR%HvyqQ;nBVK{XOugey8EzIn2(9)f7V%NU{Fodaf}lQfi-Yw2ZlwXwi#^2fbwW(fzglDf zkA1yU2tG&Jc6hzc27UO8i;qP7oW9$HLXB@8L=Bj*s1NGh@I|Wms8*rNF z=6j9-A~`aQI-j&|lJlOtY3oFzFDitPlcYQn>+S8O2KImrf)wx1{R}Qpr7a#xQ7|hE z07FYawmm`~fu09xo*Xj8iV)=uzVWazF%M7zI^kmrSS={o1zfe9e~jGFc0pDi7yIuY zD6UKSuqT_tE@$l`@A6zQ?0eh(%it>KxjlQg7X#R*vc;P!^F_uUuhL zn8y^}R|_$%T{hGZbPS- z00`Zfs9V4#dA}EbUxZFb4}>A`5r9IkEeliQt~U~K95aqsSXk9xO6>>3HT_DW{44&} z`*cE(fq}Sn6)X-38ll{fgoyVF2y0uEtN1c0Qzmv8WX$4*H2*KTU6WaFKMac*Z#Vv( zF4m$z*N*RG4E{^dbz%XC%fbGHUqJ2zPN#o*DNb}fFcaTMwt}(hZVnF(O%0m)VG`m) zF({?(^Qd^WWHFRe=||8FRbO9^zTYRe6kBOw(-B`^uK(!KBQJBzcP+U5`JH~HF$qr3 z?GiyjbKbrb5Vr+vg!K<{9z$~Qg$h#Hcf{NJ-UplJZp;0_W;~sSyaty(sA-MHa^4R~ zbuI*k?AjhsN%^XvuOEL6`m86zAaPqYPuEa>WpeTY02EUnY;R&^KE9nO-&1I*baHmQ z@uS*X5NLq})hi^wbEr$&SCIPZvHmac8Az{N!5_S)77Ew}iuvRrC*A32>kn)YCO)J6>3mUYALuraG5CjUMK=Tyu=uXNgXEaIPTW<>)5viV7-m7>PCWUjVr% z)#@xN8sEe2J(5Nk|LOjE6Zn&`al^E>8_d*kye88M7@tLT{Od4!iP(bOo*y@P#;x9h zb_`4((gk+1K5`4IjCJ1nX3-BL6O)@$F|g3@PjOM* zD!G-2s!2PY(`9r0)!md%Id%X(ka3V-44iB^jpFVRZ*D)0bt36)M)lLHjOhxU6as7vp z)C;t}3U$HxJq9m&xanz}(ud@hF*?ucYqUTm6Fab3=sZ_KQrCBXyO$cPhL#IuGb(}C zXT4c){`>l7@dGzBz5B{Q6DVsJ0>$ggdJlY%=JDBy_f2vpwmY(dzz^t)10h29eWr78 zG6N?Ekl?!@9e1{Qcpo=QgwhP%Y1^Tce;6TQJud0yVE@+1Q-U7Cx-I*}M$lWey!5-sx#NnL{|(KhYG{n^3-(>uj_%fGI>Phr$$WY>Elj$R#$DexL?Lkx8Mx} z&xB1rx#thIqC~&!(s&EJ{YeHS*brtm!MJj0{Ha38o^^cvs@P>53e&8cX7jzd?1xSLz!x8V^v7}x| zz5SFm*=kldXHMnuSgs!56d_ag4w!(Yx@-q`ykjaA# zgxr5T_0uh-Bz+FF4j3AYy#Q~uZ=wdo`G5C&T7Ip#0NM>5G?Bv|jASt%gXKFQ7&{|{mB99&uVg@1O(wr%Ie=-4(o zcG9u!4sUFBoQ`eV=-77Bv8}oNedjk-Q#Dod->te;M|+>W*IDcHJnP;@?iV*|V(~=Z z*|*5rmmWfo!LeZG7c$Yi;f!T#F7U*ov!2`PQh%mMx8V)ZhqQ0jkTLvM5^eUjR1`qI zp<43htI>DTnCf4HgQKQ@G%cW^d38VpGJ5J}Fljn+y0Rl3Np#PtYB{s@teD)dMl@;z zn$4g{=cRg04r|t;HQrsl28Yi967F-osM5J3lkhD5v$MsW+&y6e$M9r>BWba?Iems~ z9>Uwy<=)Lnq*ElG-ECBC8sOMYTw3oq(|Wu9zTd zeG)R;0#U3Z@M83GmW;^X;fcjYi)Y_7J6^tAcnmt#n!>1vbqEX&o>RzWvcuCWb_u2N z&9=UsMbzuQWb$ng#a!lxyq;p`gbOPyw|mePO&Ngkdh;$<^1=)UN#-W7*M0q_V_J~c z^39%tvoji9fkrBHD`1gE&5Ghe0=5`qgzS3S4JCzJJc6pFn(HN3%Fj9zHj$KN8J1q# zKlbgr?Dg2sFvT0*2qJNcnzwUipCooAEGIDEQ2mgH&dj~5>qC&_$uvJRhW(D}FnS$A zyg?%o_?%BXf9oDZI1L9GSP^Js)E03Loq# z;?aBq!w^?Y7tMQ$Lgu7F-+??o_300_GzT&~rtg}+Wq|4)33xEX$oHbj55*+GW6vc= zX2;m;*(+Z#+wJ?ttNYx;ABR?I7nDsN-~sL#cLR`ofC-><%m?U zrNUG;_sN#9q$AeBtm9~52UQgg(GgQWuWb`Bv5GMett5$5STL$NA9w6q=D}YK{WS$!ct0_qj*y(Kzt}f4A#M) z6ghtQhI8M+AiBIDOrzXFi1bqK`!lUrv;M7??{Y+Bd%0eKDqNChD2Xl@sWd+3Lr_Y| z?ZsIk7lGo2DimWX_DB1^<1jgVet-u6rNfo+>f1@{GqG=9o8(adk4#-?4iKX5%=eNbY$O)2MTs&SqYX@ z_)|-lzzv2)Z2wod(ukn7(qzph8zKoei$Ef`$JRwCjdHIh!lrR9qq!UDzYFg80xCPh z;eT#sysz)(QQp$ZF`%-M;;88`tP>YIWKG^yq4w}40a>W!Jwb(a8k+C`$V znO_p7Xo5y2qVPUjdlgE#&N$x`f9ELvK@AOr}*-<%FWrRj{=nE65aKNp06nhem*fm z2?CNw_h3tT()Is1uwo!s_=>25*n84WO3M-RwB+{W+lzjIq`P^w@|8Z) zDed78b}=tk51AK|Mty7N3CTJQ>J6Fmmo8}*kJ>+Q&o^8{aOPF5RTQkdkCCGLg)uc1 z%`0cxtVYGFB%f2xxddhy)RdHk)4nfg%agc~lj`uj`8S%nFlry%LosvJ4h9LQ1H$c=S)DL9VJ-ZTP~cCRmWtmL_gPb+a&`qlb z9gBwR9Ji~jS~OZ$&}beN+XvP+0#ly5);ewVcidSgy8LbG0JCR7zwNkGg-o=I+yZV6 zpoOcDfkN;OXf^B5-zbkh-EPekrR7aXv_doMTroo7S0hO&tzL1f#2Avu*Oce{+Pdue z#Ee9&8T3_9TFK{$*a}h+Ec56SK{^`oO6}d*GeB(`uej5oZ?X(!ET%1#iMFv+%*UYw zI2NQ~bab(?+-c3rS-ll;n;q|XLQ_ME8{;(O6M#dAm*^ zVf}THYFI?p?~D8@6Q`yJePD60M^Q-GzhLTHZRAD>uQ^{o7?~vR98Fm42(zq544IJ? z+VK@LMCUz%#2+a8hDr+G9xRX&VmPr7^V?w6Xx)|PY#Cln4_&*svI zHd6SD|_j-t}39t^h^f+>UH>O>PP#+|nh~DJ%u+uS@f6vc%w6dU{b6Ps*g<>guNZ z!3KW=-x65U?!>MSq6mvWRnc)TKH%wl>s~oNq!bvk<>{d#Pn>IgPdqYVRlFSTz@uns z0}gWW%S=K?yOx!=zz&YO4zmfOp-p5&jK9Hfse$*pOZsXi<&@9nkCzrqj4MBxI4Dce z6}rjNlFQ4WwT-uEde(mtJSvMmwI}VHka$L(@2p;`i*XiDmIKkoF3IrW6|(&O=w-u z{p+MY5`>W=3pQHt&k+Y{i?M*cBUa{pkGM%$ZFfRciQ zilz85wE)et5Faj;2)PjSA`}Eij125m`XWl*=)(gCQc5r+vP~w`?|( zZ53C`CA>mu9wg+RjjUOrD<$l>S8&NVgv`8k=c~YptHjfv)M303OE zAO|-g>3zTgs`JBUkbe}iLQGWzA6k``jTTbn;l>V{B@RL5`0w+M-z|=oj{X3iYew7{irQDl^gphUcs?3%j6-%D{B=B(cIfAdxN<-olnX4Kk+5Pm;v z1Lh`uufh;m!{09MT2hC|HlTLyfl6+9Vwf>!vupJ|5TPRfd-f&ij~*Q1(b*vXC(ctQ zL3EjCOI>dt+JW{&KOtaGTH2H%WXA16ShuSIUDXdi8r+hckhJ(Uca-2d-O6jwyaQTc z>Ll!C0=n1j5m#5hAL5kCRiyuc&GFm+;w@azjx9S=w&WO(OS3Bdun}9eSbn8nKwCwu zJI6DRznNEBubZ%ohJt+(@OaT1HdhL(G9XS(V@7lTIvP(kKq8RU&G?EQyCkcVw{$IZ zL4O>3y{86X1ugkMV=uj1yd<4$NgNaM`%ud7%@VITw#jw%d7U3&B?Ck6;_o=V5bNpp zuPos2`~o{rVm~?%6MO0a*55)u(GT%pI#l+(>s8i{T}c5M1TZ!?^Kyyo1F_QsCmi~Q zu`gRa!sZE%Vdnl9P0ngS__*|1n`?Lg=~H1>fCP-JY9zkPY><)FbPE=)y$gKy3>o1; zJ{qv(vS^=Qy^9!z7D)I_7APF)LOv(GXqM+uEvZM@q7=PuS(kpb)FQAUkF|G4h0Oa? zpJ3X+Nn#y)CH9MlN(F!Rk2}E4s~sqX!k@Z8#)8dfbVo5r<_i+(y9HiYaL8v;LGc(} z4!Bt?8$reJz2^HFuxR2XaBeew2hVs9! zVpFXDFL&t%QpCVL`-N$<>gJ&p6TX*FlQay=IC8)8MM&>X*Wo~h2XKW-op4I>jNd8u zKI?EC?WMnP!O(F-pHUuBxpIJo)+cNeDiIz>5JyUSAt_xuI8@?z0qzQu(}aky9_CvR zi_qYtvNywnh42o2k@8P0kf5vhA;OTUq1o?Mj-3HJwEc^PlzVm_t@1!242LQ>9HAc} zZg-rYS5rqusbY?O`LZ=c5P4EUgWh`Cu0i;HR-NUdN>JaHC_1nHyw<`)M^mvitY_ae zn12IUdVZRFO6pG`-Z7A;rKi-rXO*eTkHJX)8GIrd+s`GviKnl^$<00dBy& zaZW>_7p?9k5L7z7WpX|+m+auY( z`f?WwN+-?uuJG)G;Y_;RS|~`IbO_~oewk{cC|-3Oa39<_K*1rhZ%^FRx{WozIPK=y zGTFCLR#TdWELV-VJ}?i}=mIuVMYK-Gq(%af@|BI~&&V#5Kx?dx9*Q86KvZn)D2#v| z;<$GCK}NaEdri48Y6B`~$K1ZkUZe>=2F)V$@Vf8ST@2fsL0CxSOeSDg-$*$!n_DC! zgVNL3dwkZSaS8d;%0pk_->Atcp{G}COjl~!R=8?3kQ9U=eu7;BC2L)u9g-$YD9>WC z0_trea=$VW-I;GF>DIowo|#0^8{pO(%!Y=%gvh=$U^RBxhwPEAcP9GQY@9$h2%!FA zY=$3A5X%(LAVb_I3#x9Jt@Mz|92Ot~-Xxm`#R4$nXUm z$fyC%6ed-@z6zq+l*6cSi=j!#kZR1%WGm(08CO`M^ckpPD(cqx~j1$KIixvEmr@|QQ%iG#J|bd5@!ql7uvA*0o4 z&msU;uMpY0fjnAxhlzerHnBZsW*6 z;tQril)Wfk$Ro96UPS?p-_|{WAMvD-u_s8UU_VHHso2t5Kzf5|0rtv!@$@uodb3@onp8s~U_90eh?M$D{Hnr|F=WOT9oFjx?@d0t(+m(r4d4=kF>=rAS6Pv%Seqj1@NXl-VLa->PR-(m^qSuq^Z!XZHDr1?-3Zassgnne6YtFt6c zs}s>TZBr2VMNPnhgCMckKQj{_F6Z{|%)KKgARmMw)8LUz5Y7Dk`*)C^xp*iJzcq*w z?wiAns)&@M+Kc{&^R1*sp`?T8wOsXfByRs(;ZV)tDt;qtYkIz{-jOyw-xmy!KY=93 zt!W12_qX}-a2`o1o3ed#Fb)GxZU7Ccr-2TDmM+b9*!!3hj8OY6@;rTnxsDNpK6*Ug zP=b{1A^+ej5a_mCV-%zXg0|9aK*~}ma_hvjv@npQF(1TbrSW;zX+*s+EtBx=?6P85>fQFbkZtL5I&&`?LHfE~P<5>jmtP8Dh;3LsjmM1-i?9V5 zd38fm=;59*M!_Z^RF$ak#YUP7)}y`wSG&qZeQkNxyNX8z8hE}RyYf!p6eBNpYwlZ1+O%LPVeotfyz>(;07NE|7*|3`;|1ajY0{<*t)&0W?D z(r=X~o5~=Spo<$o%sn*`@lj6QzYrw5if1~#a1!~X_?vcSN>JRLD5 z%R5l;3=iaQ^tzph5e^OS7c{Zi?%`m{Q1;FPQw)xV`eDkUeMtZF5dF~PVLzMZHHahT zMRIR1e(O4`0QSMtnT#B;(mlbXS?l&bO3?F#b;b7ex zA`$)KF%ah7QQTN*=h`e|N^&^pguS5|mUeZ<NoT-Ymi(V*{EfQ(iIQVSX5x3tN?1!7HP~*+q!N+9l%hi4M zv$D-D+W@6+-^qy?^C7Cnu);%MsJ0pNYWS=FtYk&ms9BvgYMl6INHRTfIfg?zB&G~V zkqssCU>*j^Q!U==bP!y8s#rEMg7SKd1NC`B-gbVU^jZ-gx|{N@YtwxkJXeqR+iJ_? zN|sYGo)n|2j8o7~}QMQ{HZ7RKHf?wcPWuJV*4bJrA?HVSx7P~dB;yR~2K z8bHX23CNuV&2`T`$;v4X8yC``+9hx>_I9W5Xu{N^sx*wRl8Jwd)}Z!9e@406a(0n7nX^)Z=|y&WI;oq-trW;?L(`+}u`x1A9+a~Ml{t+-8qmIYq$KfB z+4c-P^?tdoLkdu6{X#Pl{zuSwi>pVzfi?N8ivW{B@~498(n@6Mfs#=GJX*p=ZAT!b z#0V3~^||qzwiC?96P%c!cChr3D8kFd{~2K)dmtSop7DnFn2+O=!y!(l!MEJN0s*&M zN=>p&Kt+U?^+tSwvMG1h=1|Y>;EdCgk%xJFjDM+G1juynYR-tQ&%(j$YP+{@?w-1k z@|F^-`n*D^m=zAcAMy}{U-3XpZm;o{hA58)cDe?e9~LI=zkGNt4W6B6 zIK1l7Zk3Z*0jLzcf3Zp~`1}(umhM>72zp{h1=ocb;FbRnk|TUN}>&@T8I%`85j)PeoyJd;(eD0=a5g zA&4yzMyDRO$5pdUJuV4D3z=F(*ziHr)kN&*bTCq9SjW$Y%#jM0J&>O~WYK35vMmy{ z(>YG-NYcqCbl+gtrQoXA4;&&ZlysvTcs@s_qCA^`2n(avi1IdEsQ=b2*O8nSCb0Y@ zHYRt#0J@z3s@H3MDy0}1Rb+#49Xxx;iskDi4Ha#)@M|^+NjCk74^qBPt+55iDM{vA z;I)G?x)1d;(m@$lZ!X~_D$y180|E`C^v4Shs|nz6A}bu$7cc)It^Ed2r-@x*{RwaN zpc7T;?QZzo(2K+Ui5EEQQfWq9l2HMwzk|fan3I1=SRj~UVuZCuA1%6HIQjAuQ5@X3 z$FON)C-)AG?Jm*c)Y4<pAT8!cZ^B#eI}P%${OTY@N8Nfy}nZyPc)jg@ zH*0*~Y@HeYTPc`v(x)aexRmomAiGE?GdQfVy0w1967knq&QU$RzQU8%qk%TCunQ{e-E&x;<8>bG7eX2g2EK7AuX=-5l<*c3IO^*VRu73GnhU!9rM$M1%|!G_#jY z>pBMCMX?}{vVyLx?VcAA(WL$6iM$cAVf$P~<3o2Y@|$Q33i%}zG9r|_nxTedVymRvD&E+xo&34u0HhNGq9noEOd z3C5z1T-q%uA`H67Q{vTQp8H#EE}{*W^F$!vEB||E6He;~(p&d^JN!t#UX8gfIR@5l zLvQdz%Wm=siY(p(#_JDvA>|9N<0@Il1p`!Ym0)K}Z{5=|8jVKWHpGm;mARqZYF9$F zQgviZ*`}ddr2{%)ul@`y%YFDWg71*6lp)inZAED@JNKEcHE+0X(bmyp2W9zM%|>ag-grZIjS^XO>%89?!WV}{)aiD%+x*cY#Vxh*$PNyS!Q1&kC}i=SWSFfv@+;X=ftJ#d}pnAa!dN&0R$L^1bKa>cZolnW$B#58v&f2 zbfZ89u%)4g{#ufqaxwjV9Z!&>J)iDUqj010V|-CBiNr26w;G2!S;XL;V_|&zp?1sZ zwI~@tlbk8lt|AHDZ`b?douXA|rv=se1Geg+q?e!GK9c`Rot7hEr?Z|AkI_+@)}k*P5vQ-~J#l--pD(W>M4yk#-U{I%+Vqs9C{Jd(ewY&ZEVI_n(IC_FL_t}uXm z=A0K`qt1Y-s0JgzkCMgNIzAqC7rGQIJr2E5pks>0KeacKq4_NA1fg4P2kckC9vGdv zqJZS@**s`UV{_%P;rh0_iI4mQ6->f<$DvT66)4_h?Xa0q4n63-dxOQxpl=$vaMbbi zEB@|Oa(&e-*0x$?+sg@;N?{|48Z}9&$jxgSj5~@F2S)b72jgsmsD8) zK{E5gt+DXc8>-40>C(dErUW>!i_Rub>xx0D(6(M+x4&1vwJ;uRYCXQ8c{74@(Zq1d z+SgLXFID1q*NcEuZi=&m>UM*&pY#);U@4m!xZiIDs4#t?O zPcw{;YQAQ0RSY-%M$V%lyAy66(X{QgX0rG2_U_$SfPD?s%DYsr3R8gVA-`G*3VFO@v_h=|M#H)U(I_cWa9kuypa;2))?;rR zv%+eMm-&l$ZXBj6S-q&J*6u_qS>O!|Vnmlp&3AB9gPDs%O48TBqQ7_Tov0s^ z?9#npFa`uHkq1kK4{ea9=o(jqtJ~4$sBt;kxBfCB?LtY=obO9}pL{CQzbb1mO+fWA zLtB08B4`GQO!s^0ah6=^CcTD8Y5%~&TOWps|4#P6W)c^JSBZNoxjkv_g`E(~Ann{O~*n~ddsC}J#*%LzVlR(s54`oo!n(OyPVqMye zTI{MAX!25EF=5U3xQmd+KUt#VVU&g8Dz?h}Vn;s<1JyuW20Wn)u?2(s5>DH zBxV!_av+PCt!qJe!Z z2OFukx;Os~lTD&6goXJqA@JM1S^p{91rr;#Gxxjct>9bby9T?h)%ct;o_{gC06w{5 zWIlj3lh4bbzavzaCuP1TQ_?^c&Mf+wnTkNsJxVCLW8FLTJO=f5vC(mz^xvL$fb_@r z<%&!g)R0#bS?5PUL@yVH8K?p-5!T6VfxS>Eb zrsQ=`sdyY!Kv23{cle2O?n=|b{BMw5e63BuM}Mf%a!nr2{4m}^*X!2}Y11$aXlaRx$nP?l2ZFzG^7ajdT|6&v!D_pt$q@{seo4$#DZAAOwq z-zn8wUz3KoUxXc}SSlIZr*V+ku4(x4(b&1Lw76`*@dUnk(zUE}tQA!pF02g;i`J?`DibMldSo zh!(#mE3Nl|VYbQl50zgi5iN!})(MCFf_FFqfB#T)Xzvcb9HZgCU`gGlC9IHStYWtH zqtF~_fc5B(@PWV_zVenKP*hKvlLhW<~Mc+3ngMG zkZnpP_=^v1%yPB{gsqJb$N~-;{2v=mc8PudCeR$08W$DHuPO6w&C+qYcu#_S^+cUH<{_?`&BRP%mf+ zSjZQzdoxvs`lw^?(tiFF^UxE3TyiPV=V>1|4QuJ;$gzhbBNr1X8==@fpB;p_jNKdGVpH)=Uf^{@Ic6kR{^sKD~~*hpe&&p&y`{+4lM z4uWQFK7ZvXoxS=`DPZ%M6iw#pYD>lo!;?frJrpiDk6MhC6*_Lg{#|&@ck=TzIfzNs zfM2XXQXpdQ8yg~`7T@k-V;X*hjfA}`kndYg&@`HM1UdE>5j=i^Su}2{H;U)d6H|E_ zlT*iF5dw-}>>>;oH52L5g4tn)c`^61RbkaGE zd%EZYvAszW+5NJ1brXa7v=NeBhSkIP+{qtIJHbMCqRUEL5;K0wopp#OQyNoAwH~b3 z)E8U_67}E_7x3z2lMVY-^l+D;$X70Kijv`M4qnwwP{iR$4}q~v&ouuMA+)dnYOy5A zurw?j!63It)U@G{TF-JqitM)1Q=8Xn!;FQgwn9L@k}39@tGi&RxXOoyigmqns_EcD z-JGps{)6Tv4{@tdr(w&k!bX+&c7cwjR*`C#`oint2eeANQ*t`I?B5n6V#`S-bkzR#36e}qg#J@f?vF{gqSH!{A*55NZ#I&;ZDNAvfm2gjLcZE zR2=xH5``2tLsh|V$~`_}Op4ZN!=RJ-J&0=jmWuLK^iNdak3U1wOoiP^61_{3-aEPR zEyZa|&ZSo4!J_)yQc4Ruoo|GyL#FH7UET0qsTh(5l13*KORVVz0oI{h%Rd#%1Yx)U z&K#cN5=2z&qpfo7!Q%}Hcy4qi40R)1E%%|XH&78#4D+bxx6(>2N00@RU2^9)NsltV zks}TiUPkujzerVa2;Ka4SEa@HGLJNVQfPqND7}BVYI97l9*qc>t6RdFpLj*5`Y7DY z>Fc~LTU}>su}=c&vP$k!$E6+gCf%K-tXB6br4p2}qwhkoDL)Wx%C&OeDpGIoTpH}+ zr9Ijqx}ByfjU-JN;7masKjH0Lw8xsm{xIidC|mn^z3O^vt14y?wB0l;U%nObRibmm z??~OPMozNp)Hpz&y-~a|>pd&UnI?4B6x!*7oFtgKbTmRhJ8%AXBy9iZlS*Y=-hF9@ z!5bczPO7s(^yD&&0kYOcm%$g>zMyYSm94Cre7Tg_ zC3=xvQ1%}ntbck-8%}+Atjlh7{PQ)N^a(GOqI!Wo{;V~8s-sb(#bE+KOO{g|Oc3@n(0ulEljM?5v zgw<|bx%(GB_E7PzAnh_TZbIA(d)FL}f|&TSxs6A+rMZa*%<_ZXHNT4of^Ae4P~=~+ zRmNv{=ctoG+R?Fia5l42Jg*t&80SWei>+lOi8EUn!JM&kUrZPdslG z^115Zd13x;4GiD4AM$fOk8A;=n^-ND67{ zx?rV!7@DoywF&x(R1o1zAxbKi&P7m;MI$?r9k2J5iNyi*c`tr4l8yMOeCrkHtwR-2 z%oPW~Mj&_f4Vti$Wv@6}>I6o>XQHP58N@d*bPUmz9iETS&FAIhDg>)TgR*ZALhd5+ z*lmFbqRs;Hm8IrI6ntsZlMc7cw9LX!I4KVnVMHa?PzO>}b4v`~1gijJloM<{^l z}ELzJ-dOhdG&M*VjK7dC07-cvNprIIzOnH41(~-Qk zE zWwbBsX}~){$HNx)`jjpOiLcmGRGuwDT!z2` z;GL-kOHB{j4J0g-Z0*>CIO&t8i94~bFD;BhI=+UFS$^FF# zc@SrsJ~0@yI*E`}+j5L9etK3|zMEC(;;dlHmLK>&Y zNE0QtpD&c(7zD!$Ik2*y!=~MbS?VDx#U>+vaRPVBZ1pWVs3+yDW8hq&4X;ydH3dqM zLo3>1mAvA`{MT1`U?*C^M9E6SK4c&F>~b{^$#%E>92q4R@^SfepX&6OeP6*xjzkL%2$UCCm6Anv1N=T^+y zfhXO?eS=@fRHX!1!Vz609Ik`X#hcV4>Rfya&(ImpMOs=-#;}Qk&8X^AwIHPS$m$FB z>fGGD&)aC(@IcS1;1{%%v3?VeZz!cyWNN*`Ll*Ndj^WF?gFQWU zK8i#{*Pi!6JBo?4mdwNAk8L+!0nF9D3y1L;jOJgjHzDO5-7MlnaBzV=RoO*@WpXVxKTjzCmHByQiMgRjKJ((}vF#mU?kDSGN1!V?yz4 z7CD*`w_i%)s!~0z`-t-Go&W0MfPB5x2@lxB*gx&Y+0x&f_02Rq?8+5rPl2ha8yFiU zdrrL|gVy!p8>mszwR2B$Ob^!jYDr5sA4keLq9|aN{z|x$U44BPjola089XaHt0Cxf z11FyOf}Ai&K9J!ZqivNk1kpS98aYd3IV7Bd^VJ|$$l*Y7sL$8GTTvfI{q+m&h8cDj z2~Q8WfY%u>bu=twPQhKkYgb;5{_beGB23K8o@6ms2bdOtNQVzfHcf}GG51@b@tst+ z$^e9C-)rQmHWPUKAh2icvRr$o1T;8u*2b1|5T4pt*nvX#2!>>0w?;DVE08|nNI!v! z+!!+@xPVO&@>YXFWYz(oU*9-&^%X6*M7={{+~(D>kStF!6{RrU-Y#tqA#p2vfjyS0 zp<2B3!%8%kc!pv33k{~mT&rm_BEUyAw0AoCZ;xP5e0&(v8{2H8vbY4E2O58bR9v?g zS5$UAfsUK)uvh!HGV=#R5O;+dVK7((Uu6cyZ{XN8@k~LA!8vskL++i!^G^)qZKh6b^d6x@o}&&@jtD z6Lvg<5~|?I*ocNa+9$-<gZ`VH>$2Q`MmbbT1|XV~rArVs6Fq8Sv=X0N8D9M(ZpR*;|k1}2HWZ501uX+yIv zCs{AFh6Zv^bpyB%-qK5va3lyMkJj_P)AEA>sn(Cq_Xo{kq%WNmvne11{UJ<2647Oj{*VH%%^}z@s~Vx`b++D1I?OX$h)HvN z>qG+Sa1h5&c{ta;8TKC{YIdK~5J6FrUc4jS(G6};DjrMEh=m2u7h_z)7Lh1Zar9YPomPS(hK zkpb0f+Od(~k4$=J8M(X0WKhy6#JU6mIApPU-6lLoHfjxqu-XSTP22H~lJrRb9&f#q zeT!5q{OtGjQLVlJaHu=7kc}4}|5cY2&AT6mgZUe&}E% zmQn2nr|x~kQ9c_OQ%ps0<%R+u!oh5|{uVuB9XFHimJKuzM4ubIa}xN{bOfc`foXvS z8W;>L7M5R2j%fIBH{;DotQqcPOTx&fkiNV_+GLss8SSO+MO0r&dOgJ{(z99#yxl8c zOT&28V2|4#8J@W4*f@0nxrn-8V8XHdGSFbNbvN_vJ7HwM6ZR%DvBTj*PmSyHF*Wr+ zv0-W*!idTHGjk-ko4HmH92|d9) z=RI~=Q}waeY=`xXf|Ms7kCaex0rICh0Gu$W_;}LA$8S}HYf$asddiJIb#1Kvyvp8= zotC`fXcWW8C`D_%KrRh8_cjdI#!*4+#X1TK8-M$f>eG)Ztk7#>U??1YY1kN@2}!v- zR|G|)<_HCmIxB_57vhJBXWVGbmui>A9QmfBsU|taGVZ|0tW|GdhqpF&MPxkCrTG(Y zOUo!@y_SQMgC;nFEt@Q5OL-Y7i=p-CV;-Gzt~ILBof7JeK^Q!vz z>ErIjT`~64UT;el>mH(s(aQLWg^9w!oGcq48A&ESz5YR2vW(cdocj8XRU=HiXFT}iIb8rgvc|}(X<*`_5`TCV zMw&uop8(+yHTpTS>D4m#c>{ISF2h;Is{+PVEW@1jLr-+mjAiUX%}7C2jTvKZNyzP3 z`TnOYUsYde%SZGaDEVi#vG9B1y({$SPyHKlk2K^=H&A99kWHyBVRC4Se^;gsB~S1% z(8zw7%NuRU$a_bzYekH~$bzzjnT@l+VkrbcB#N40e-NUVCCd+>EVy8qTv z_mG~G59C6PO z|FtDb2vQYCi%;;NllVtltP`qWw4T_Z@@gML$-ru7wWK;L75*V9XtRGDPM7XvzDVOrxVvs9c0-$JeJy^nl72XR zciFc)AE8d6sMfPE(^4H}>csGCZ?#V)W8Hsv!cHDYx>`)3cfbe_M^AQnc2@-cZ>{A|vf;hH zYqGwKq_nm{Kp#_QGJih|jjt%PobFS}3(0UEm43T(`HVSb-ZyfNp1RJJW#cCI?$hZ* zE>Cw$KvO}2Gc{O#r00kaK;Qhc?!y7vixcMdEGP28vl3Rs?Qd@7Jie-__qnjBDyN;b zX<5@S)2&Vmv%LLlrL2~vntC#G*@NkY2Q)ra0^wrJbc_U%>zg|&27DcCtOP5Ooe@k7 zS$ffgV#*kp?7;j>MDf};TZaT6_P=+r)yMqoi5M?v#axX2%WYUPL?r!=WsumYh;IEk zpS@*!_@mkQt$n#LFPk#a5a;jR*ADths95*zLVtYQ^*c7kj4V4XzF`Dl9t72f-A`x#I&c=aD-r*$(oPvN!DIi)UMCV%N}j{!9lDKU&` zIUudZ=xnOr&2mdVwThJ0jn;Ul4ll+AWF^QNjWVVEc4*JohHIxo^I1CjF?Lp5qsq8{ zEgUXmlWM?0d}Aq2Re2*qA#SZL_=3(UC{@xVSkRDjC@xsQSzM7rHF;lOfqmwkGrS<_}ii5p!fgk z>n)?=3buCL;O_3wxI^R6KyZf;+zGD1-QA^;;O;I#gS!RS;O_3uVefC;JMOtwzv@@7 zF{*0LHTzvpy|W0`v;}wTANwKb0CjH7y2$9*TamT}=rTB|tA7zQrt2*Y6>C(Avgmmr zl&Alo)I4l4%J`huJRDERQk9wWvPCE!Du(-p>jgJfqPt&h7Bt&VX~7Pb@t-UTIh?gd zbQMOFd|b<;O9uc~!>;+GA%yWn8~;6^S9niFtaC_ZHA#wK z_UknJ+dks}j^;H^jgjRf9 zTo@1Wwngh1^1*|hbd`;9!vIg8(+V-CUzgKAra~OC}!678ItI{bATSh1|%MDvAoAHmun>reX5aO5)~21rc@s{ zzuBB$Kl_u_6R)tgQ4B!jp?0l)Sb3v))T(Y@4K@)njZOx>a^=rb10ya*7XLserxZRL zEwTW0k!%s>X{@>x=RNq>S3QIL0`D%HYq+kInRC+Llk2GV-qXd+$iJ`Eu}V@)7-8z3 z9A9kc`Tciy7I)oja?lcb1sy2vpvb3fVajD9je`MK(m@XS#v;3A0!TN0L?K9dSN1w; zNFI@HL%SPcTh6sJDT|c9iz)c9YqCe+DzRSedYk6mbOV0I?DW*}&qRU6CC9_s9mGQ^ zN5~G$Q3f9QJ}rixTyi8GV`jLu6)R^&W3Sg^2umoQ5O zOx$4;WLe6mDEV!Di++p?V>7;&p^FQWEAZax^I}yUoO{Ytw6_;^=;s%9oF@(&c_YaU zC)6q>eOUZ#K{*;?C$4LP`DXtxhtrOraoB;Kml9U6ZU?tjATofZt8TbyC9zAh-4}WM z*m=j!G7V2AXaJY_1lY4uhPdQi2(0M99@=Cycq9N!o}M^@zhfX}?tHDDG|rxoDENii zazPMS16rzz+&-t(gi+5b#01s zoTp+Dc-V%H*?Zf5r6b2&t8IdKco25(BPBH1T?ZatA%C(E8eDL#Ii4<l!b8R?RZ5bYzE>$ zX_SQ9Y=_~LzWZ1cBklJqSbIX`|9lui%N+jeOW!Z#Q!|Q*ed@tH(ER)<%C=tEh3F-f zLW8IG#q^I^$y6*nImL(JEPWnN-m}=<`I|Ac`B%fthc)`Ci$;*sBiaK*GBu@-t2Btv zz;1T?jY6!fkB!d}N-uSdd$YmKaxL1$!J%3@Q*`5WQoJ`GvEpp#=Lh_{@K*~ zdNHgBAzHR&Pde_*&gij}J=bXmA~UpX#^}ki&um&vemzKD?Z_h1aW^W6=DBKc9Jhwj z^1>y^5Iu6lfY*tl3oKz48XTwJvq3hPBqgFHG4Ixzm=rBw!9&K9kYwuBFI-|FxRS+>|4PJ z=cyk7y%ISCRrkpp^c*8qd-JaOt@aBtI1*GdzTw-BH^FK#&U4UZEl3v2BI536gh*)L zh%2*&o9Z@^_`>aAFTjSZHqzC)S7R|%OjaCS7U?ZK_jS?o4s^)?kk`^d;oFuVRN91rkgHYLc6zF?m;MAq7 zB@-jvnXwFPCOKvi{URgjNsz&=V198E2~(Te3pJ{EGV) zixrseJxmL;I*3cexLdF>Wrce$d>y)C%0>46PWs2MgbC7(Rzq%_wOuPWXr%(8@FRrhBikZ_lGan&_|4Bk|V9-TXGKzDp!~9#_sFXn?62hHgX;^=z=Z zXPv7+Ic&zcXE3$)hyiqDW^~crkz37qFKjFHCK2!38i9};Tx+HNQ}Vb{QcXT<66Uku z{5iYf0Qy!{IPLmT_+@q72#WE~hFcYz^#^6J{ejCbqz(W5^ZLS?OP?2HR$*95Zd=PV zTuaP^Lg4u%+HdRd<4OpBF*;3%+<1|R1~4Q8tClpS>78NFYmWY@6q#L+qx`^J-Ueve-5ePdE? z_ItM!HagtcXEx{IKS%PTnJ5Uao?j)IKTF?S%AC<{vCZ)!S_S&A0)J*xE&lzm`CLkg z>j2|5iM?zyDs%MzxQ$ZxkFnK)v8IZ4V zUqTQji`ov|X3Mh8%n#cqZNm2%^4a2X0L)|4$uM0ezr&E7>Be~idptbQOvbl_~*D?*TacL=Uu^-qG%j|LubDLC(bcyri56j>-*15L44%U5$Tj+6O@hZBWeQhC&RtWmXd8L^9s30%L30aU0O!p>F_I($C4OQ z?|iej2<{R6SI2iuN@MmSvgciCH;@-e{?MQ5=-%PIBuFigsIXAa-ETaH58GT{Ytk5b zesP+pM_eVinPI#ozDh*L3fpvZd>QyZ9he=X(&Y4fu!@B0jebPMkAqrt>zJz!!)9N8 zW&VkF(PN^Z=f-vm=}2(oyvngRy81eY^$OH#!jDPTczuLqnSKELin9RN{ME!q31jIa zpyZ7lT}Yil>)^y>bww3RUd6;db`dmf%lX^ivZu;06HdFt=1p#+B-C3$bZ?=j8AvvS zKU87sIRyY7`#za!bvL&>e}X@S$3a3p^QdakxE^)xpy~z$i9zfQUdDbRivNR6UVlLH zpncuB_ZnBc?8NBs?l-6VELX#^)b~(0ar%XN`g2+!=S_|nh>T=~Z+i!e(ing=%q8I# zp!7$^a#l}Drlw?y(LH3;4K;TUE@;6~0}RecdG*_|nwPAZ=Uk=NuL8dbl}xgyT%Rl1 z*uJ!WJ*aNQJuf~lV9Sql-@yn9E0DDZ+%VcCyB$z(>l-ah>IP_=IYzo^{-zyQ?2)9p zf+8+AD;`e$ler!46JoRYLM$002lwkFLgfY&#)iueK5X3W7sCskM_RIW-G{jr3BXY6U_5Ne;5$K1Tn&^=f+)Y zRME9s{v;1c)^I>^Ki;^;-?nTvbI6r^2e3GJ+cF~VwQhVi2l4~XD+>1Q53r=25bzPj z0)-oXZRd8G5JFopoXI;U6s3V+_lyTMRup4#)% zw{EvT%#!2;`+}zrqx8#r4mz5;lxe2%QWg`@J_c%6T%kJIeOsD52yj`og9lt!?B}D# zh-cv2dFwHoTm`PaE#-3RbzZgB5ZU_)FD$VRM$7!(wC_eJ`+2&v`EiQ8z`7oehY`@y z>_a+;oa3LY;iICn!T_KYi(b*Hq};fVO8IfN1$XU5{kV01zNcx_1*dqNQHr_h)Lv~D zn$-tuvtCQO5-XJSq4#+QTcZ2LNt4H#Gc?An8zxy)#K}|fwj=uPwQcFg3W`Dhqh8;> zX;jFC2hR261EiGta_`Rrv8TZ#`qa)$S=7#`s+;Fc^K*hCukp?GD6d5cBsTMM6iLP9 zh=*RmA_L*=1r{$GFC56l#4$F9V>3|1BiVL)wejyPC~li||GSmgZHk9Bmz1t_44kwE z-zVeQXWWCS^F%#i;U@-*tGAr{ENpu90M$9T4$!sZ*5Zbgarqkyv916#PD`ADOIhu> zyCeBT>`7#qxgbUgHf%`<7kDKfLp}268*_NHglWU+6x_~%yhu)Z1BVkmGOyf)Fv)b3b`ReckM8OiRUAJDyd9T=>dh2!AN4v$l z7>-fecGRxzdU5d(udS9w7^-Bv9ZP%s-mXZS(-P|U+58^7u0L^)@XNwlVILk_O!{X%Z7N>%*HSl-Jra94&*LHj4~2vZ^@obDZaI{H%T>NQi+7dhskVQ6vO_G z41BN#>$V{{4-YO20+ejSWZBhdb^rd5Qw>OMLp)#={!ps(l6N`JqAvZv(!fWy(G{~W zQoCd*{}F6C&kK%N{J0A8+T{Oc6#cPt5cIA;xlXJJb=~;TUgc#(zgne>1GQ2z3)L4v zEJ;N)gT1>-@o9-vOIyFV3B^xd{1;b5nwIJdEowBEo{tKimE` z7llCM9CRf_MKVE`Ji89KZjqK#ZTDSU4QseiWRGIOx3lB~GE$?9n0(J7kj1Et^OoT1 zgO!ta>;{WSNGcdw2ecRn4)rPIY&ZQe0HpK zz2v{Fi+{~u@fa9E_Nzd{QiLp zRz5$8?)Ero_l9**0>s(x{ZMv*K2`Jft?B#4VU&H{KWNhOkUr6o(vO(IIw|TA6^Z|& z#|;Fp61+H8(?SYJ z477NyDENoxM+lY?S^a3gcbBmvoEGQT2J(APCmxnuVV9lQ&3w&PZ5@@$tL9Yz6Mn$T zoqTk6{8tL=F!*bbx?+ymoS9c`Yz?-2qz5KyK52Br&4@ zY-^RL;gs>gmdu^_?U`8dcUwc?e|SH@!H>N^z4w@lkl(1#!R%?_Hw(Jjyu9#XCIC=(K{`&!z2i0V zgc`WKZ2*nZ`8XghS@EAlm9YMqr<}v1Q4MbM0R<;^;?no)0fQdQQ_s0%qBZ|=7ZIiY zR>mWlmI#S--#Hw1X|!nkIUmOfcN%l*`W>+PQUaMqPAGaZ#s=Qno}P!`YDE+&sLI*& zX%P<1Qc<1ikEeJ((?@>i!h5J(Ej4o@T)#aU5a0jgUJp~U6Sq1F*srx421UBQ>Ha@72|Q}-Zodn;aS>(i3#X5W)6BE_ zrT5DIXQ8kN&N@E^)@4v6c8eZ!7jZnU?6VCZ5_C~&Mdpuq+JEZq>yZ7&k-lB)r?P|4 zyC?8}Fuy+9WJ3ACMHF4!pTBnfNPmaM4rPYO)q1~}wn#9VgDU|*;-gE1niK;EL2*g1 z*NVJpye=jQlkeXBCtH5{PVI#}F%|$pW&)DVLkS%q>|;#|?2hI%Nan|FdoCv_cm{@XG9xq+`2wcVn&MpNZlF+q z$3d*oTNOZ%SCbu(!;`QXm(f&pnKeaHBxiCfH+joIJ5^^$I+w*o))n)|f6ASwvOF1X zpiOD;qEAum>S@OCe-@1%IFeU$DgQpb={Jj8)v4mlc&z+x^)+a?@NSHZ`tt*uZnKgr ziSPA1ykOq=L)Vf3f?p|l4B9hYe}_&eLjvTXs|1F}7Vj)S57oTJRU#VZ`mzHT>KXF^OfSLnOOcW1}`e*Waj)#@cvZnO$6xkNz= zzDY*G=W+b)?a#SSzt3%j5cZM{|3nzpP`!Y1wNZUSWFD;KF8CVhloo3DuAvp`W@TCl zd3MDL{XO?{$)lrGxX7+ZhZm?Z|Will4`D&hN;%ubk4a!bn1w+JL1tJA(DQGR9w zdo6bK3KcAPb=42jsyGKg;w9=>x%9W(m1Jx%g77S1EA@O`WR82Tk|zzozC&2Sur#>U zdw`BWs4X23S4aoDCjaJX$>zZ~5Fx(_!MWY5Q`9gR%;lRYjVKnks+8|gt7~yoniTn8 zk?u!5godlPrZUM!v(R8fH0fRqEN3|Ko`7lBtJ0>o@^~{Z-`u`$wpq^U)g^z;%4eZ0 z)4A;ZF;vzuOH|4U>8|QCbId~ps1 zMlLk!&p^6ZKWU;`qDEeMR6$W3QQvC`J>n~3`g0di@XlbY3<8;T^r;zI9GJ`%5z6($dH0 zJoEdQOcu1A?ivt=xka1et;6)hLDOw5hqW>R^4#zt^WIxT$zj305Ng7U)-i5wGfIdL z8m%c-=Hw<@Y-eMbH45tmn}f)8NJN+dyAj*hF4BWlwad-(g5<&jb~at(>l#Ex*~T!VSq5<}E4hr{tt9tb39-0LpyXq&N=y^nXCBw9_Q{ zJ-4omqiFJLPUPR9aoyD%b*83u5X;-bj*BXE_62E3`P_h&WlV^<5a4#r;jfKys#i{X zsihNsby8YmkvX+d&V+d1IUM-;iTKKE)?@0~iiV}cMA^>4$khpZyBEiT7Y5ECwEJLC z8~HWly_(Zk$AM)19j(?yo3+NO@OxWmnkr-&KZuuo8Bx01cP(=#pBz>_Z0?43u z0kf9zW3`8!YaQ!tZfab&-^ARY5bLrV>(y-z%k?(i?;pv%rPU10=7s5`p> z=q-NdkuHAqyj`1BP1$z@e=zU-@y@#0&i>w zD+sB(TQS{LLl`BMQ8#rdf3Z5(Z^z{12aLsG$9s@#zKI`<_^9N>OGy4_6fgY$Olmbv z<~$zkX**PJ-!7JKcYPf!lz-vGmG00w?1}gab~HJf4C?lu5oa$fLZDs#3BVor=Mm^f zW`whs7T)Sk3KFB) zj#rJVC^rSD;D&X(W#m;TftuI+5gLz1-bBm3&P<-;A9&$|t%arJ22N5{$rO%~G4Owu zd_`Kkk@S<+(g1azKvOTW4f&#TJFH}@!kPBlFVSmv-@V>ELg`QgLRUnldvUm2_-(gr zUpa%`tS`$uYLLH~?|8=}ErWBK9iq(Kv`Sfu5SD%~!RVDKq4J$)DCTS$93_vAN2cmB(7G4^U0-QHjO#6T&nt~UgY)f1l$yGEIgmmE0 z)g*spjipC0Q}Z60%G9@Bfr4iL<2d`ElY)OY>oM}5RY{OWvSmuu;pmLRT{Av@NZZ0x z9@86xZ`4S+D+afCN=L@Omq-m0x}wF+D>IZxWHBLBlso~N+5C|#wd9DMS&OX?BFXcL z2;pv~!Q`U`wnXiDUqXOWbd6$)7dn|6ehdddCywC9_PiY|B``+8)wvjZhhl;}VOSbz zX-fqQJiSdPx#I$0R%*Qv>=9}Z^}5a~&l;5Gd1WWEB zufxR*T%G8Pe3#^gD1UJdGlC)XZOK`j9OjpGFz)$+Of(;*RmSCn+9y`fx+oz}#?bhX zO6pYO%W(@R*m#@`My%`>Fas0-Am`vv*bqxvl<1yzo6~zSGEj;Gig@;O^?Yy%^hB_K zDXjUo$sUs!2MxnNmY>LCIyf_*u%F}A!+rWJ{xr!%8)De_avDBi+R1WiStT*u=d?tM z9=XDYzKc;p2Dw>Wztn?<_9=(^klM)V?5 z%YdxgL*09te{86^FAT<)9%Li`-Xcl2w`09$t88`JFtV_pHBBcPd^H(0#@os%WOgMZ z17Z^BT|tQlGX=ivT56(uBS$2&V^lz?nuPwi9}p+Tf8+n1f3!ss19;PjV(nXd@_Myo zgMFOryO_5NRRAOgkQ8zc4%)$Bz0UQ~x zn_`1qaej1)B?(ar3=Y%;M;rW}M3poQ_dnlcfdlOyK6+d>I*)AOf;mNH>xF@$+G#+*x zpC~WylW*?xczt2aUrlJ9_UbhUzg3S+RY}wP1R@d9a`*HqXrT#^VO zBLO&M$dW03r7Lq0L{@pbHcvtu8JG(`+=2Rv(!|(52wN?_^By$N@~v93|IGMn0`s=5 z@J+bYKPK@g_D`Wb8?2D2H2+qdUnA9!k2Ut{0ani=JNynm-Bhjt+e$NJ-K^|>2%!>- zP53C!RV41#C#(1+i2YVz8OKgOGG-3^6~MfFqX7_peF$>|@|p37;Dk$y8y;=}3@ z+o3HB?x#?c?ALvOSU=zl`4{g$@T6z&ixtLGutcH@HYw%)mW3?A+|#t?`4qY(<+`g-* z2{*8eD;9+06Lyk?Ie${wxE6X0;3|^(v1@Jt*#9d%kq_d5LiI7*!t?^S@YdlF-mW1F z>3AMnQtZmrDC&plBLe0ARdo5N1-w+eut6D)78zZ+qbpyXFQD#B9%HEm{iV#dzgi08 zBqUV>1fHUZhmzY`iHi@k5iQ3E>pYPt>|?n9aW^D$`exj3WWXc%pmn%#T96ggLgJ(5 zjy@OFp9#O623bu;2k^ZDm0|`N8qfoiyorg$2PH314DYmp8peI{EO@c!X7rg{zk7(R zB;cFanaBX<~UO7?Rr*{&n_Q9;Sug6 zrI-Y=0|mDDip_J)1)}o4L((SwlYIyFmY>n?gldcrX7|0#?PEbE&uRMP3$UyuLch5p z>6--3I-b^0Eko;(#(FE#q}&VJH`YSBX}l51r6J_>-|4{D440B!1hu{RZPf|k*?jK* z)`MCJc6Lr6&#*r!RvH?~)4T8D^pco485Q+_U=^1;@p9Z129F~u&TR>|$Q^ox%(N}< zDIJkTY@|C`yBMrY*EiR9a%P}fsgv>5n56LEL%Cp;sW;`N6#cCF0Bl$RWMSoGn`fhG zj>nIP!5v|@UwOYt6gbx%zoG@ZbW~!eT?=R~{6oF?sc^swEDrDQ{ONhFGAF&v2H&yj zy6J901sL%g@^dt=bR$Ar?{S|#!MKe&2*80A1B2~ZaU!zZ^}j_qIUT4t4T)W)zM=6+ zkx3v$^J(09rYlUENKa=eX#~DC2PjCKfSzL1ftH_tir#FmKWaAnTu#L+6RuY-&n?0x zRG^}(P0yCcc|}qD#ZUa}hU0rfRt?tDbcP~hIULR%RFj9LvrC%9_tE~Eh?@xjKVO)H zHjruhn>pcoLUkf0!|-in(lpfLlACy*7j+<1#*HE~PrXYY;<9sUKf|j-L$)ZTvXf?X zQm`@wMK{E_PNUe%{aNeB`d5`@1cjAcA3XD5s!M5UqA+w3-+%Rwv+`57CU%)nc$fTf5735KUIY5*lE$36-* z<%vP(D_ek)Ndv*sdX8?%Eb2M`5qk4r;>ND4mJHMDdQtO$fYH94huRr=D_&}}W&HDE5r3kLHmRYl0-YW z3-`D|kBf!2170y_Y|d`5j*~5YdtqXi$8%rK4)lf+4FuWlrOrK>!+%p>e#&=6mOS=X zpZ(dUJ|0d`qx}+@s)jDQYw&6)LnblDRZW;K)k=PcmxM{?rsb0iy8kgWEBeu#RKnFY z4F96?TewC%B}yzOUUbGAJC>+jM%5!D)QL9JXwW7O7`>1}`cqI-FI|fc?j* zGErB^Kfm3m!JTsjD;|019s|1!+37sCbK-5pk-L8YV5UT6eu-bv0K0?+ewdR(C{&;X z)4j{AlR;Ewf$=8q*lO>?KU1Flfb$cqNrx-UtEht>Z7@dE=gFSZ!TnWb(r@H?!ToZt zuCY=6S|?+Yy3%8^-*&6yD2W;+_(Z>t_O4bYyv=b;x9rW^B)F|DrT$M&fPSjmK`@$? z7RQ`&WK_NZHEBEUBD7oVV^cYf1}jW=q&!OZcm9siPijivY)8`1!q5hjfQuB&B_|f$ zW4B6+P2KsGgZD>NPs1cGIM2s%b5>)z^g@*B?SYecl38l|Sl?pq8R_qn70}mXv{Ci= zxz$gW;!=JvIMV&m*^8T2LgIb2B$qC z75BhKdC?+Y4QBQy#_UVvjk8q&owqjZmi{7MEjr?bZ*dEJTQNUY(heB%uf9?Ln0;}! zckKzDq60}Q4c>`$rfw2IJR__7dDYfAiSM0>SfbhEBye|3t}dSdDX^8%X29NW=-#yM zfIz-dcB8tQ#O#;7tIM;sWX3s~r1t==LVpHAwEjV=CQXFrfty^<7Q*|;LHpP#DFHM% zA@U(gK;MEQbG<7+_}x*QSDB=4NoEh`?V)e}zOZUyDkpZaO^?$L6JuN2V1qP*bXb9zL8eRW}ur9|@ z4ni3ie@3wiXsZWJ7m`TR4w|~1(C^-82JB8{Puo*X+5DyoB%jy)3bg_QWC5J!G{2mC#UZ*Hvw~S?d?HJrHQ1)#p^_y3jGtVaGzhg7IqvVj> zH%D}~M-V~Q8%Uz21ezdvPF*zOhf1{B0hH*^AhKmxfBn@&oje|TC3RXwWr2^N-%VJ@ zpI%yIpY+j_fxMqMMiP+VXcxAFt0s6(w77A&>GEc;=khu&j{SXk^Y(H1GH_F3Yb?parV(vytpX$}%vZ5HY%LQmVh=QaQj-`PKg@0NJObwSw=y5l zoh^jF7~?$}E9CMN$366R!hvcMW|JF|X#KP>6@%r)SOuDV&V+N~Y8m-Xp}%QFXD|-` z&GuezIiP~h@eyUAC0)@KV9#M+oZY8n;!7NV?fk}Kg>Rrp_7~|&4B%ssj`o)r;(g+oErWW=jWB8?t=lH1J6nBFAEu3+d@G ziFX1Q?I0Q%fkqY#xd0S(YTJRuYA>)>B2FIZcP)8jvdhls;p`X5xr6q2!6$_1VNU-y zt3LB-E~$}ZOZNihvD>`7u5Q(yfE1M7AHJHcV)oYvi-)w?rnehW{$*Q`yGJQV^F; zONV{KEBU$6yhIq&5J9oXy_p31@G%o!eCD4U{+q>cCy*Zh{n=*sLN(tyEa z(kIk23$LEG3wbE2O^=51bKImzeRhlc9BJBO|Bp$Z8TiTi@hQrE<766_l53w|ymF!< z0>-u!NfQT-`Nj=#5{vomh4TC(M45thi+}s(WGcu)fg-`^U0gBdeJjRv4lnMVu!3tD zXfhzR^*F-l9&fNXnDMzGzH_Lb>9S_`fOXSnGGAirEQc-VpH{9FWgnqb1BwfT+)i%L zA1bu6x*-fuC(o(5PS;sysz}J0^Yzwi$~|ucerEk zGs8Mt>Kl!#n}fSf9`Uf#H7F}}6M4ZNkCoiP*$fS3H>NA*@F0Gu5>a))?m-{?;R?R( zTFrvv)pyDrRe1H#*XTY7pXrt=foj>z_`2C@4uDwM*FeAK&w4nC@aoVH)kB-IQ8KJO zT-jo$Hu6e7PcaT}Vxy*Yv8TxUomr$F_sVe0P5%pbWOTgSUjvjI=6@AoFxi{I*TIeW z3&w=Vu7iF(npkjFQ>Ny5!=+d9T6<;2kxi-*-;sK={p`_CnK05$oaJ8rPyrc0@Tc#A z;-Thvri>me|9Nca+G}H;7<_`&Yg3`A@w2IY{$Xtc4CjI{~Uaue^ZF8 zKpj8>pw|zRB$hCLy{r?j{k6!SWIDJx%ui<1QY5}m#Kz>15vV0n(xcsqAxM}z;FkJ zBvmum+|;LhWd(YZzU_K`fY9X~f5KQ=6Iz<`eFyOLZG=USaSeS9%hSrvX1fr>#mSD} zfrEQA3^)*lK9A(auP_~s<_mNYBC?lD3z7RFx5;ga8>m>KVcT!5YVAxX1Bz@c6!N~< z35yrhSTa^K+4O#7c!WLu+Hhn@r_{ghFM%)R=4toDZpQpV>ieUMGET-A+yvHEy}cxE zf(zbuRfI%+9v^I1Sj^*;^?PTpV)hJoT7g3M6o5m3dt>ujr_n7jz^*7OZX8ZnTDm5Q zWrsU<~-Y@p?p*=3d} zj_#+`H_WpDKe|sf8sv4LJY}~=c;Uts_aJyw?nNY-n{%RAtA4P!IhIOu6jcGMB_+sa zw60v3R0byNAVx(wVHfB!IQn)J0!64-wU+ZxJsILx*1_w7NG0baQW-aKAd zGiGlG4(aSZ4{e!vLL^aJVfI<4D!ECYpHK2HC_D4fmtFNLW(@@em(R1&U2GQ+}<|GHJvnn8H{sGx3LZ)O|y5qj$?SlQY}=#{|wgX?(G9U zP9|HMihxL`Q;dS^y4ISOw@T(KA4bPv$VL1{bI=kr3sXOFc-K>;#pxCC3Vg;lx^%n_kp zv~WyOp54SB%G;)ouCxyBvq3nmuR-|Y6N_F@%~0huC>bvdQ}%}x+=||co@Vc#V8WB0 z7oC2Nkv)-U(9o8cVaZ{1QS-kag=2it?3BH{lkQlB&r11O2@dE3vfw;bLDkuOMGB| z1hQW?p$bM9=DmU!d9BrD!FIMV2hGc?eNLL*Y$wNU+;pKbYi20EXE*`-eq(5^2XQQg zE26W$X9f-qaEl*g2Hoop2UUa)&f#JQVkP~|ARIaIN^IgI7aw-`)yq+QcfU0Eqxm}H zyN8K798-7<%0?NdnTbMyG*fdg_|^Nelb9yV3M#@J2>JeMM#8$OXP1}K$^IQ6HZge8 z{4?mG4QyNpOHcG1FTx3{rhYIu2^h8WDk#u1mq%d}dS4!w(#%N=?8BF@u5i?`OL+By zOK|0X8-7l|iHJ_KF6!Q72F1}koAJ?LKJhcx-?tgvl0q!@%0fRYHDt{=pbx=<^RPDp z?d*UnHv7@v7@!@!_?0R1;yS}`{U_ujuPCHQ#NAY-;3<}0D zI;Y1JbijPlQ*V;Vga28%8Gu-9_s)M; zPMJ1&8_i1C<`#XSr3F_iMrsV!r%vJ!x{)4e5>E@w|8?5pOA|=8FS{<$L4MaG#Ns2O zNrfMEdx-{E;p`vMc(VyJH2{tlgksB5jQcx%D-2&!0Ii zzR8@4h75}_p%`E+vtp%hB7Sqo7lGU{)?ls+$9Yl*pK?70_OhhUe4ZSl9&~7M-TVw& zG}q6ty{`VaD8cnOA}YX3v$GF)Vb^DY+jmkD`s?q>Yc+dMP3ZbI#3 zPR~zI*zNE}$&E^kQ)Z4Kqhwe%jPDtU6#3UAHB{>57G084C3g*9spT(djALa#{#bb0 zRdz^(_(YwIw#6aFRS_V#xh`nJ4KA2Vw=ZAF&%|$m{ zt@RFU8Bd}X*aK?Tckv@1F``HD@Npc0t?4#hb>Blah$1Xp)lrq_mrMq}0gglp0(^|8 z|LyJx@2&tuHpai*2S)qJ8Y1kP=zjW+VQk`_sZhkFnqpSec-`9Ru}*-8Fs?#c%pG2i z~mUUK!*z_$2Ti-WMB|cfB+Lj7P1>t7|&mBnx zD|{h~7YfnV9;KI9`pDHt(Xq9?Qf%8UB)q6j1G>%U7S|8i z_*ZL+{kZR}vfIr)jVj3>-WhSfHjxEIJQx7KPzJ1be|MqiMT%YhYwqIfCV-D7UHgsy7>6Gg^!Z7E z`P$DQ?&;^o<}7L9BbP-`fPuomU(+@)U2f2FyVE7<48$2+^Z?`s7yNB@?3Mn@rGF=8 zv#(4w6kwOfhwKZ92P9V{JFjv1aPb z6tbSaRj;KBu2lI_=`DNvq3mEx3!BS&+G(-%I@UB-dVcq-gUCXuuFtxUX4}>?T4PB*$^idD^7ry(cF)P_T~K(k$lip!H(HCPFTk&s^D#5TT;QiJZW1 zbEIW4tAnInqh^+4M)0c$&nyi;z|-XV{U_fm&XotO>Fd_#g`R6c>CRVNW`emSr^=Of4>)>fh1hRf_o$ zmzXJGCpu3qaj+%ih;pt|zlu``yKFX{N;4-;s)jW_>!jJ?3}?i_0rqCa)hJNhO34x1 z;yE&Ik(z$VyR}mi_ zG(b{-d8^>SNoev#S?oyTV$}6B<&47+YQcd$uk;k^6IHLGeZwGRbzxlPHUXF2Sj0D- z`EaUpc3W3z_tBHb>iLchhbx0)!d%8rJ7A{@ZH==XxZJC7v;|%qcjvsn@!k9Vf5*^qjt-ya*=6mu=9+VEqII<&UMIgre(BPs>l*4R`j;+U z!GhnCq{QHFJ};H0g8y9h(0{0WscM*c4g7(~PDxAY(xvJ|ic{1z@MkhtbrX+Emu_?t zeqZi&d2M~^(nX1eijtwv(~VrRoKN2_F8Z^c6!Iw7{7s8euPNo>BrExbxe51ArKaaC zG30q{pIpbQZ&=S$d}RBU=Un+iJ&bMT@H{wgbx%qxzsX~3Xli{p*WYetq<2x)R(`PU zur_Z`dh76{Rp*W#ohsp1D$gst{{Q|znw$?t|G&R{{r|tebmM^K2cP?{jg=d`asTuF zyPv7*`N{0Xz*Q<))~h5pQnQ_#HSW92Y&d~IXuz<7Pxy3Xcf#YCrSxZfS6MXR@ZI{x z)6>0?-9C=QzQsfZ!3*$o>-#m2qivM$$)AR0G{e)RZ*PtL9l_Ww5oV-=VI))oQmZ)} zXaDxa7Lwh+Ju=qlOL9s z=ODVgqn>MLQfHqm{``mT!Pcx$@aaxu`E4;sy29Dt6mk2{iYvpp>y==%{dX3Wk%A^Q zDqdSNe*~Ij|9*a;rijO(I*UykoL7P+y*4sZc@5OKbn-R`|6GI8?_h&BQSKn4fwSiM zglM^0Q%wWs=xaTWOkq@L1E>39yhN6^HxG4MS&n2@d8OxEYq-9e$z7H=2d3~&FE>nkW#1Hd?C!w(q`A(R!}_`#FDzZi+}Ug%yZ)~I>9eud^8!t*u*rI-b%CY| zWVN#V(cD$vy-yM)F0&t2f(0Je+4sNJ%oJ5si@&w}jnjl8v_`)K4t~*d+^W7qeS>K1 z3F+X);l+8r32{QAXJhx(O!>g(iJqOqwXeMa4EuJhjo-Zg{DkhUd=f*c#uP3+6`rzz zff}m)Gj;c$FwApl+sB&BG`bb#`28;LDOp@CNq;ID7WDZ2Gw3yno0?*b>ak!B zp=q%~ACTJ8Yn<=6`u*-Z{p5tgQ-$}(dhZ5rRMPwIbTeo@S*5z3C1Mp}()%(`@z)Eh zkQ_0)1ZL?MeaHtC^n9EO=SM{ikrXGW5}v26jWl(H;kf7Gx~2_Uyqvyv9(4Bg#|k$0 z#nIiB^Q$YjpY`98b8&q3>rcMdPlp*yArJgtk|+CHep8AoI7GT&&9iTOP5*wsg}ThN ziaPxiuZ{l!|9$_$BKL4Mc(!5^hYD-pLL&s5x}q!x+b_-?f6Grj`Kaic=fBxRcv(}j z88?hfv8+Zbk%mJ}{o9*I%YDflGg)J=afWnIW=me!-JqlSr402^$}c88kKuv!K0B5i z>}Sqf8Yx^%gSI#r!mLe)cPQ2FVfl@R4Lb^S zQRO^v$u50lz4P?rp7`6V0?|yx$XAM&Q;g#2R7&7!m_+%1eUp6d-=BE*(;J)33zS6A z5j12c4d=sqpTsP~3zG4>nG$e|yW| zeua!43pRoe70qgGo2y8j8t2D}%T11F`v1OIm3njg;oZP7By;2qmaKvOc>f%l-(Z#7 zr`&p3cDotOeN0vAU1pt$*MBg#cfe#Q75xq->}>jy*ldmRbzkFNuzgMOxJ?H&#=H%; zsr!GH!@c2dx}T zw&jBF5z%9%vg!F%!&*)d8&5`hoU4VQO`~)F@prV|7xLlt-zfE{~a{r<{3Vc%S#I zuM98z=ru0xWg|V7=wGp&uZrP9dUcX;<_vE?ChX6aPfo8iW$foWeB@8xaOZ7%8KrI$HeAXG84>zdC60NloRbd9P8e4A z&-Yb6lw5qgK5x$t68S5$m@@p@o~u28MvyRDB+!(KI;O;X8#1zeac9K z-xxexnhkDap@+&6!m)}Li}NUxMM}GATel)={nEO2w#3W=pJFS&G=#S z)xA^XkuT`Iu*6syFS?1E?nwFNaZ0Np*%r!%fu@FOG1BmsRx?(Ipt1uym^p!uusv zm?S;)Dq%&0QT-KfayDL+Eg?htr>d_}l-|UIpik|7-!M)!Bup@Cx@FoSI5Ym?brLu+ zVS*O;UEi{txl~K-@`Y4pUg0uL4Y_42obrvjbo24#g_s49oiW?bf3WJ;SEz$9C08X& z0C|KI3Zsxh)0Qr&hcvmE|Es;H+bGzD!q_)x-A<0C72A?miW|;g+x_xzb80yT^MH^+ zNN);xb>`j)95XH8anJ+v%cQ~9FG+?-xfic*-r(Y^wyk>lrx{Ki#c3d9GRiXM(GO*R z*9r;9!aazby5z?)n9{ zd%^KyeswZYB$xYU3sqHzr4iQ0?k*&E<2Wxi#Ed1ee9JLI}d+`m*diwvpo_vs9+l@1APF8X$mHDz!f2P

NQ@)~{aIUHc;KTXT3V29rT}9dnys)BaJjCs;$b z|K?ARMYpvZOF?@{2kb-oPES3O#fDu4F&=57{Hys}f$Dk?T6!!zVeyyV_meKzbDw;= zZbBZh=7d$E-Rlh0q|y5dQmSOioe|}#);RrgOhauUCl?4z=Kh&BcDsB5_j$B)MQfqt z|2BGbrMfP3^diR774BKKA%TGNRke+4>CtKG{v53<|L@uAn^=CMiX>3i`#?>%`B~?% z8{8#&f^6}sq`W1rp69bbHbJlU47an`J1DW%^{pH?ga-JukGCx9#rjIm5P#DhLVndm zYJ0+8y{gl7GJY}OX{({p-7p(*$3~m22g4Lh2MviX!JUr#mi?@E;=efEOEkG7{o*wx zqj1M56#@%O-WyRcKR-WlnE*(HCNz^KJz$HBJBRgM(li?psAar}^yczk#5evL@ia00 z?`yVQ>}5;d1Dv(R#S2-E%CU%wwB7_?89ulr1c92UwbNm`|NQ?AdmG)XtbFUtg3tB| z;K3L1aiYN`f6BGHg&F z@RgBGyxQns^S@w3z|hNtmg3P{qqN+aE+U~1M}<==%|el$>*G>q?`3Q9^Ud+W$)Q9}teE(Ga|ogTZL zZUFX9sJ7U;:W@HK0Ve**}ANFtJI=J@PzwnQZwqK~ssI*ubFmwoED2IXM)KA96KKu4#^dX3o+fhm=l1>wv0zMF9XjGscQBdhnu5LG1t{jPkAy>t(Hx*+se z7TQ3_nh6h)cw=p;kGw9~Q0Nm}U5;<*|5A;HEI^Y~cjcdl-{I(#@!GH_p0Y?IvgD^p zzSz^M{C9q`mF?Nse8$QJfcUr}yWx|0c&P>7jK?sI!&u+GJZ}>@*gV%(JR}2M)@TqU zf`B)}%zhE0b+T7L#_nRr;xXdNRPsl!jum)$HJZKt@YxKcCUZPY$Vi@!>QhjsSrl;? z<+PfZYFF@77T1R?52owH(D7o-j-H2HxmFA|d**4m9;%$P*0)yuc$Ym_#_?96Sp)%R zMc}M+JUq(AJO@xlJZpO$R~PCMj#gUfV=(_OK#P+7XS%yOA_Q8td*eeGC}My+KVZR$ zer>kBz0PHJ#uPq38+?%_U|L_yXP4(&D!V^sP{Yxs$q!Dsq42cORgv=cG_$b(eKA}i zSAU$>I|D3YMs};0liOoO7jz-#jcPjVg9ysxnGes&{SP*h|Lw1H_i7~Ex(Ban8UFMp z)~DjpTP)Lyt4kkR&kiQz6)7W{@oBi@BdhO=;-E8B?q4J14|_6%MXSftGEI;;nm_+Y z9#GyZ<|R{up`n(^sSg^v%!7_?IK(BKr+zs>1vW&)7KcH!2zgJrMGoaieVtsmF^>97 zRn!~y1%%#`&nF9z5kq%3YT1wXVgq*2;4A(AeT5vsdh1QGf&QByC?`O6O@e_UmNAem z&;;BOT3fCiA_a$2{ojG72c67TD5jQ>N59;}KFl5c!FxS-SBO9LvoM9ugH`x@`-02! zaD0+Fe%A+7pYZVJlifj8zDJ|TW99^M#NEayQn&*APSuO3dK{5HZMxS$8^}}Xp6gS- z4*CAWphoS)lOt5!SobcCJPaddC!zA=Ps>rOqQMdsi#cVsk5vw4JZG@QTHMulnetuD zwau#4wMOH@6LXbYm&*vR60uStXW-(F0jFny0kjGW)i$w`*I)Og88?4D=95Y=V}n&I z*E>y)Yq}h4wrpkLry3+?18OIO z^LI#UMGuAE&N1@?bz=DMD;~EvFxDLN*?<)y^T-QV#fZfSnR;&T*>IT1BChi7zPDW7Nj52$X+(3O}$VpT9$SRQl zgXBSc^IR7GX8$2zNbEOAQRGd^NaE1G3caF;%;+oXtY-DkO_~5v@af`fsaA^Mljd+{ zmdrG8=8&I~5u%@A%K_{+vD-f#oyiOD25lShz)uMcQt0+VY*pjmI9d2Gt15SbTkD6yj;IzXb5sR?QLFTIyC}1D9%LL-Kgk~Dp9sj&8K|<3r%e6-`&U%zdna> zPiPfZ@wi2S`I9MKoI8^@`8@Xuy$c3R3bd8alO->aN}I5Y6;?Lq{%6KSPr{aj*F3dmt$O9=1O|JXu;w z>24AMr8`;(AT>BCV~0mK{pQO%#0NZNIsk|^e$2$jP4L1h9Dml8S3GGk0<4U{r>uKo zuN?Vc!9_qW%}s>UMYtSW;~|c%BgAYiZSxvcbXvDn_tUXzDA(V4O1lv&2VvN z$W`|J_1LkutEHU!kSx$|GreBSf5;$zeq<%J)w&^fNaG*;^`)roUU_sHF5FX_ zcO|vJme+pO@2+v>8~PN8H#lXflpRS1)rIOUURC=_8p!{6139~4W|w|+lgpWu zKu8X@z}=)rABm?cqjq6R@Rm%D%EG;nChEx@ElVUs?^O`J7&4QxXd zW#4@GRRby!=~lPJp56J#yIIR1{~J^_E|3#ysmTq_aXh52(c~kq%#i*t`!hTwD)&>i z@k1s)H#FF+e$KJ^jIu*y!dwbjqFY!=I|cZcH|4 zPg9PY^7hF;#ogNth`sO}h}LFuz@{dB=9S#jOm?htOJ{QUCBD(~sETLeB_V!jYXay5 z-blsJQWI)^6;4H0{{EIoznFO9)W5aLnV)?=-*}I6G547;m>AVqvvi;3fz6zSq0a`d zlVlVsJuc{=Si*XPI*%F7RUJrYn8?ZIlF|+!Aah%E34LmJ9*m1yKB$le>m3-B-f+*o zS*8SI;FSr5@^m2~We@If1f#Gd?n!SN4J`=~9sM%+oW|jYZm~8?nbLLn6{Tne!n@S) z5GAR<*#+f9B?4clv8_+-q?XA6_6Z4Zu^A|)PpfAYZ1LO!4OqoPur4a3v=(!|&nAt& zQbS1z@FEqbsiUiAfW(uR(YX(JfLwL0h+M;jM$_iw9_ z4o&DLAZ-M7%%aPFBMeq zkGR?6!b&jvr4xLtDdN8OQ|j;Dzv7-WeEU9lpiL*-%y!qkT3s@bkMQPe7!PW zP$ienYe2_VLqzs4=Qcv)2I5?w?-9hLQFkd;XllY&z4(K5H0ad&37s9BPU?kvv6~fL zT;J1Eum8OiPmgsy`h}8mIrY__&m^zeo6~l2`fHKZd!SuDpL$lIYj)%A%}kL8;pMU# zS(|p>1shfo{|c1CRIaQf8K>G4l4#*j0t@@2w=s3jm7d-?gpsn-U~wn;)B5Y(kKO0H zD3(9#mG#owB)u(@S@r{%E{oS-%JAm(TTvCJtCcT~{zxQ;T%FEIr;_8`U4J)2{9hv; zgSl4mgkQh8?)G?b*Y*G5QL^BTDWsl@{t2`kD> z*kTH{Fy4?w&@6udu}y%DIwAp>9NA==_Z(q>Qhm_9eWq8za4pA08hWa zz$y33UYzsm*V#W-S`%98lXdSpd0A+!S%F@D^XRR0R}_t?`;z+cucE}Iiz^iy?dSjA zQr?mM@qD({F0tXhWc%4cwk)8=M;lzsj{!B__WmQNj@A@olgoo7@7{?Jn|Y=+6hSBm zhg3Wqs(Fek)F_t!v+6LD^=s$<0oJ#sxc|Ngd!$>BV=;~`w8j7^4@F?rv+p}C&3z10 z)4g#^ypL{hv;?sXbO(u0NQg;;^K{aJI}j9B8eQ7Yyd1v0N!vSGO|~1&JXQhixj^f_ z(LdtL^#V^f{!~~4%9DfjF&=W~?4KU5cxw`Ds_wHXt=tFq0WxjhNf>YD0{`lpc{MU4 zsR{f6B}^h_fg6jjF@E<{bc&&>nxG8mqaEnXvcw(O7c&mV7Ms_rQd+h?Oq#+!fpTNh zAn|~neLv#1v+JD;j5{pcQI9YJNtTjVp6>-3`*T;#qW=q;EIh>d-!CpHhb4`ggJ8$D zdtbtsd}E}R89*44^1`CN5C)+CI;rpA&kPA2)CwT|t@ewca-ag#um%9VVfo+sv>8qN z>2B;E>1uMf{Q9S(oy8LOkWNZgH)*lmBUJp7ywsX<4kD6AIB_4h6Xv}NYh&z_6$d7>-Fw*Dg z#X-fYctw;5^Z`Jr3WsOB^!b%M>202w%vv$Snpc8Q8g5HTblx%KLzEr(y)lDLx+Kzp z7P%lr`1l+({H6Y!E*h8nAaFq3?=RVv@f&qIHXeV9)gdc*y|;wA$g%&nAs; z4xcZ+Y!twsfl!SO=@NBdOVd3+JzgGBxJZ2vc|#)_0*yPF9BmH{CcxpglDg;9&EJ+< z|0WVCxU%|q8-jE4$0Gh>fkMLL;k7c)TCrUok^hR*dtA7;QJa;!*@vCQ+cQ~x>LZpW zcwUZN_s_g=I-gaRS{`NNgxf3U^v_sg- zFVlAUf%PyXt^>v)yVbldXwu|fVsZ{-%VO2oo1&h-4Ud7Y_en7y{4=Ac!DpVeascYU z%|2Gh+;jA!fL9Pmu4-zmu=~6^uW-f7fMe4oDcY;(67m69#LRBIL~{|f|6l5z>lj^k zq3VR{*3~?JP5l@8*V)81!kv{ge${s18SmoY2Cp;J2(Ecy%mkQ(6|M=iG-m~eR-YyHECvEfT#LDf*Z6m2x%_kRu6Q}{eR*U ztrCl}9w9$uv3xwWmlr;7Ha!Hfsv_-0cf6}j@V%T>BMb^Ig?~!)UZ|gPrHvfp@rBq3@#crwAw3(xhY{Bt2cQQipyM4SN z=FKAU9q3!;i{9VOWKI_n^6b*ML^|-c?1_MH#7Z9`zt%O6W9{=t zt%{(nHg=MGx9XGky*9hMpfckxXtT)% za-;wxYTi*aC<7h43IPFkUAF3JoMB@T&nzJnhK-xpK)Zu`3nHnni(lh3Eu!AHZplj= zU>Ju4Ok1zR3khqq@RCIa=r7cn^ASnBCIo&3OtT3YgT_8$5wyl5oe-tCry zT4MWO4409Pg(0$Zg}~Ox`5*LEJ!z?1!sFXknfh*4H7XZ-*tsb6lM_O#wF}8EypMGZ-rfF=-i}e8majgBcvnUYv8Ue}9(_xSu{ymB8DSZ#O$n zOHX{NkgQ$_qf#NiIVO1kBZxCyvADXUYh0laRHnE6)7%1X?vI*sLq9r)#~n|`emGSW{f+h#Jyx*sR?mXFQafnv0IPYedfkW@;q1M1=?xZ;3A)p_F%ic_`|XeB3%h=1mlAzxN@yJ^5fVhbo^TwUpNoSi@Mr=>(trk!S*W(Rz6xjmtG>_wQGo zY|rhLY?pzqXj&V<2=q_B13mIFdpJE$a(Kyd?xU@~=)`=UC#9arVHa=K#d~+Y8ME8v zt#Mrh9zJm?fd~N|xF3S@{YCxJuQ9ik-elxM;EAR`YVhZKN1Mf-cs;Fx&R-4}E<`=0 z=Kz!TPu^gboU8O?^V$IvPdd=t`_s*XcnLha)CY^X+!Ig%mfwGWnxdm{Hs-TM9Y9$( z@T}$$Qo7yA{TcyS=oYF1@(9>Y9^OJcNf&%#-H(B;1lOMwxW9hd=GO;jr$IwuCmxxG zKBb{!x6O6#Z+Y@rLha_o@9cJ5b+(!K&^Gyl&rPWjFFJW^a*?wXkFoxaTnF@Tu{w1?_`}~{UphB#{}8mjHo*rg0Q!{UyZxJ~_Q{|hy*NLc3GO8kLRCI~uiT8blab3X zb#Cf5g(C{d5kHz;-V*XZ*h1bKpFK;LN=(twJc+mV)IzsvPr|pZ-)@SHc=z3<{#~%_ zgKQOUWGX}9&_aj=SM6&_JpUsl>ma}$S&i$zfA-DLsXLBIERH&0CDX3;UM~r@r^aS* zAU?c_sG}YnZa)OOhK5Fug*(8#*%xQbGG3a3AC49b*>A7~3`?zY#_B8Nd==%g@3X9V zg8Z!@-s?|zS|1zEWb@mT79aY|E%jjy&%wzfp)_=4%n+~zGvXvwU$(H zOroJr?~FFI{d?1(98F9Hg+*S!%|)efiZct`|F%*RQzwyV8p6QO*!lywhbVs!ymITP z>~P74cLOD^X--25unF!L42Ou(i;~TGKB;i?V9)6=PNU!r5v__mt#E!=wXjK$=jQwa z(CB`D>R%bK{gK2i*G!fR4-t8p)*sVnam_K1dQq{Cj1F5zMOx4B)aRq=BEcKOBx)Ts z(ctyxXX%+zs~oU0>6hz6ITp4IW2Nt4^_;g>rl-=o~ow=3H|E^W^5wmp| z@pVm7W7|0sKauBz*)6ydV$Yl&cCgezzWgn3{%%Q1c)RBx(y#M@%#R1A({z06r5rhE`8H9}> z7^Rgp@xVLV){i&vb^eo0+S}CKuaRX{T#6Tow7`Vn@ zX0aen^CkrNBzwc{k1I>C@7m9QHo<%`Vg;;b)voReR|*2H%#}aXWHr)YJ0qI*QN$6v zP!G;jT7;Lz1s;3OdE&C*kM+x9jP3nkdBb&|rGr?VP_in38GH&{O{n^EEL* ztpvl`TaVhbKj#+}h;rAHde3`)|FYnJJGFupg3{n)oSG~6HQDgaEw-0dgccji&{EW1 zne>-ooQmc5pN#iMXy_jrBkQT5^W^cy>Z?!2iVxThIq{<|)kLkfQG<$%pH)wKyI96| zf2~f~<=>kmqor8NcKIMO`C$)M%jkd%`dwZ&RC6~@;&~@|_P4Hh9Orw8X8}h?+9EgD zAdWviG!Mugz~Z}Dul1B6)rkiC8g+G#Po^mf`pWU6q6a6{YGyMBYfkRsyg?-7JbEwd zVA_j3-1!^LjA<}7Ga$Y$zFVah2w_?C;j{%JNJr=fGv%044n6q4QB3#>+h}`2NtBCva+)(f1wR zYdG+e;q^#+f^>eXH?WimvmE$2bk%6EKj2cl~hiMb6@NX;HYxm10rA&bEy zqb=kgkU?PlMo~H5d8SRGaEZ$>>uBXhJZ9vIS-8UYA@kD(mg-^Y(x5ul z6$ThGiLaXqk6}b~(X%JjL*VU{>9V5%Ds>DoO9)8OQ4 zu-9AAZKa17gOgNTQ~bR7J0B*PUv)8N`gRG4 zyChOWpT2O7!Q$WUeV*P2jd;kq1x_h^Nwn)<>Yc8+FZ1=n$mAa$2q4KV15@fQwhO7Y z)pqz4I3h_^EiXA$aPPy4@*hCwhXwGWkBJh7mAEiryaBfnxgy36c7CX(*ESq-b4@E6Qa7KDXI!;5g9-a4YNTq@%#`aHBEC| z2ul!kbk~H*;5cCIQXbNz>@i3HKo{hQz04qk|LWpao5WWJ@Z=1JVpVCl2gt#cRK!^e z?1{ZO#nr5vAXO4GbrsDk_Ns#Yoe~Kt4;P*_(6gmGq1AHF#?`f+FRl}~nx^xx_2um^ zsZ4iMnTLusfc+*mC$L@yVjLX>a^p?qT@KN{#p>QWVj_M7(`^{-cWYre?)ZJ)vK&j| zkk9kBSo+%!HOQHM4+2+cwhb$>kZUd)*_OZ}97^grN7&Ad|Z zWa=()w&*8UoK%a4v>P{U%`Dlg&u+&UPe>ot4;tNENs^k=Uu+x9WAFQ3T7IOfD-hWQ^m>gYCZvYX=|h}MkaA~mE^yzYKHGF58C}+ z1eMU=@hhS4q4frDlvORIgjz!2$SY~HP7TwxexruYaRHonk+A+xc*y-f)102Y-_pK5 z%oiNIFxv#@MD}hlOurx$IJ4uVw~hER*&ryUIKb|4cK*BZZuq*yl*QCEQjR9z{uZ0F ziwbA?cNlUI$)H*1J`~a<%A^?m<2u1V;2MQMX`JHr!)dW0!ofZ`>uM7X zX9le6T;JujQy^Rs_=?}bWrUETa`PW5(P4&!a-{b}pb_AB`aGN}4!=mc_*;9gje{EWLz(4aq5E-Nzny+YSzC_3 znSz6uL6pRY1?={7e=^UQ6Zc`dKJ&3~EkElfg41$D`;O9`f$UZ$wJ5FC#+6UmcG#Uu z)1YDK-@$hIidyCy$nrE8XXG2*`iNM3z>>gjY%p}<0St25efkXuFEV_)FzIf`7L`eQ@mC)Tj|9h zualR(vmA&>QNb;3yQ*|tjgK0Q4lzPVM$!Ahg>G9&n zv8w@*O{z%C_uZp|m-xwzmI>bVa9(S*mv#{&ET~RzF&!BrTLmOG^KH%_=7*9CagwGV zzTT0sx%Rb5`uSx2r>?`A1P}O#G|Tmc$H-9=E{Yxl9bf*`AwsTZxM}?PZg69j(Lx|& z?vZWW>VY9DQ$#2Dq>gFK<8ak`u)6riGUKC#@bBgffaWB4o^QU{mo`I1^Gmm>EbhR) z$OaGol&80$8ADjv9pt3cfb`|a(FO3V^{B{1_}|{EmY|`?mnb?4(`xE}ZyixGa6)A#sl;Oe3_owqF4BYni`=4B`2+i#|z)U}SF|O`E7& zUB9Yvc1SkDWa%{55i*mtSf-37Uy%u8(xpachPcMaY&Le9x+`g7;N)(a*~CLfDm5n{ zfoCjNaBZTOe}7AeakGwFmC_Y`2x8lII#bTSz9IFB-2GtuY=s)yX2qn|D&EllLzZE1 zL371yrszw>e$}B2Hoy=$&tI6SgHFFQ;<_!4-3SM$^i1U&1BnXfNVPb|`9Ji*OZQQ} z<0f_`5Ns5u%3Qp}%&$s~kUcJkKw&m?2m1!wkNaJVX~s`^(d6`^wIjzLe?a<#+D|PH zYBxQIIIq6%D-3o0JEGsqyd0kX9vFf)dZ)H!?W);7VH&`2 z?^Tig?mNvgd_|oH<@-gIq2!Il86b!QJjB;t6NCZGR&{`=Z9gN(IqS%}zW5f-bBv_s zLSqJd4N~O$a`-l<6AgXJyUSWHz!bZFCA(l~e#ULoUked&TTpR%cf_HOI-c^_{4-Jo zaWG;Ehl-@VAj0W`WMs}oqRH67%B-(o(r51uQt9n=Hiu%yH5b*TL812NX0u*Q6+WCq zp(FR6jrCD>TyDp;u2;3hsnQ*tf)*oJmW7+mnn5&MlQiQ>>O}g+5gM6Hjfc3{e+(tc z2M&ZdFdvOLGQom2|HG^qCNy~lgE891QrLMyk|47DJuhxJ^@sU9riDg!s_#6!>q+}o z%ug1H(8)?1Nb`tGV>LsOMfE9ek8a>w8Ol`nU}Wvx&lnxb4g2rCAeqEwLe_?gNfGV= zRgd4p;pu_`XQ7Rn{`|wHEZkU74@f}z>xUHrQeO8+lPK|Z__K2NuxrT=caAugU_WH6F z5`$pez6qLqaB(qvwmn%?CoQ@3-Musxk{4BLW`on-EjI@&@R(3~v9L7?S~RGe0Gh-L zC}rpK3$-Bp3&toBA5Pbl3)h*>M2$P=eS}n%23~QVsZ7vN)=CvSb+T^die8dzYWOR zoL<(yJ{R<(^X@iHtH)ChMjC*x)uIlGk4F#}$zpjj4~(46*8tw3fB&q6J|zU5lOgpI zV8$6Hv%I*U@6pGtBBC%crE-5Cz~zBWzS@3x`}*s}h8QW9=J=(e_{(G*uxeJB z!$&>#jK;QvQ17NU&Pbkb)vOSqRtPUC&isIEX6-)yO)4GHaa>T#BhMewW9j+j#+~4(-Lj&IKmYD)*qU`Vr+Aj;@)x)ZCURlgC_#$o5hEg>s$fNhL;r3G z={Hn0yeb9>b}&=S&hMh6BUaX;lUbn2qx?YT}jB)fD1^9#sg5DdF}WY3047iG_?p z+K~RgIYT*DN&5kvlyzCQ%cw@q{6hej5#$S6n3GIeY@V88Et1Zkvbma-D0-EXxc24V zrm*rf;q7QM*gI!TEG`q0<3b>J)4A`e@p1~xYTTdG-p7(D&mz^MV zvKIF%SZi5%%QYlpp&{M%pD763RI~%zwj_W$L$^Mh1kY+5+YKPX$gVGq1WIv#i^JS# zOjj48wiLW;`G0ZVGS*|5SzKoj6-TbHpsE5o`pU;p;zk4{w$$6nvn` zn03*R8w|heclgy zgQonmyW`D3PqfjbC)n`J&JUJnZmLF`gHY*mw;}m09GW41zj{OQArKw2bvFvQvWYAHHc{jJ$i_-#e3^uyz4G7UAwBQqxxUuqRFH8*gpNk$%d7Q!@U0E9yQztM&Lq544lR|mkxE%F1{58I`8 z`GD-mG%;PE2O_p4XECnpjajq!p3DEe62r>qt!uGCvqq!dNyBf5?1|`C(7I1HMw1p2 zI(id4!cKtMZl1XEedo4)BLk`)f+3tRHnJr)r?Ea$-76ZP=(xyHTj~#_3%RK2^?>-T zo?p`ACIMDC%rqXenkefEbi0rajL+hAG0VmmYonzJ9F$Qn z9_+|kA_*{@j2~8DtCf8DYU{Ob9YQy<1A6kT)--xPL*cf=&}$R};bgR}a+W}v{Xq-2 zur0$`A6$3hr0;Oo;^xRWxdn`Hin)j2ie(0qnSJ;oxWxgMxemuHqRhdfxlgR&qh*v<&zAvkF5;hN9xRN)B7Xs2)PU;XE3+bTP0@&DjB@UtkCO0kmpcQh)g zVJxl{Mc&)SzE|sxz49eo7VHf^k$=mqd z%7&>myV{Q)w?@FR-k55tEpNT5%J~)bDOcvZ>3|>T_Wy76Qs9#Kt64OoL+{XCH@Fw+ zAg~u_eAJ?JkJ%r(2kzyh0h7?UDI9gMF)`I)XxMYRs;mp_VH_ff9_Zk%x0AKc=k%9`yC zWS}VIg}LQocCI)wI~$wjAwN>{RBKk=6a<&K%<=(2lD!W6j(TE;Ua)cyIJZ!1RF5oP z&H_uHV}c8~nq!-#4a-IrnM59b8om=*vJ0+X=|Goot{5`3oe#n6_Sm>i0EuHw>&AGt z-j=<4Zp9k=@_ih;HPAoKmc)&i5h+|+ar9|^FOg3>Y;i-!fzZ9ZP>ZxxVHM!f+9;#VUHttaORr?ti@xnsZyOyZT#K>9f7yh2& zIcA~^k(jErqC|P}mK?%8@bU~E%`gq-AY9;Aen7z;Byh@JK|{C5QIyycL^@ZbD}g@Z zI>1z4Hmaj}cLapH%;xYo?uy#O^mU-2aC0bUG7`?CH7}i zMx^qvfh+O_zFgqej}y@hK(%&|4dcqk-+V4!UbY11+2e(t0bncO?lLhxOOmc5R!zkz z4m%WxpQs=PRDYb$=_bkD01LCZA?im{<()@Qf2Uh4k)qb7X#2C%`_J0w;ow}~q71Ez zm5dh>qAvkI^`Ly}2B0iTuISNXuaY!}j{4?(r7Qco^jg-Xx8f?|>Q>5ZbL4)Kr?~Ey zmrCBCO~nwdt%GHix;-0o;^flrw5<+3V2O^p`s$8FM;KZyj`+GB6XmU5WK^|11!AsI z1D~+H(o#KVOSEvk8iMqBDllZ&6X*l%6=KW|+MNo{Q<5nUkAUp}QSWsPG-A=8foQ6T zyk=bEL~?qqfa&?gU-Her>WWCw?FemJC)&c;A1VrzT?>t;J27S?<2zcooL5x%Pp z8-Kf9L30Q-rKJ-+WXEbUtRMfVt8;yKR-KmGjUbB0C8PRlBe%kl|I zW;X1$^yjo;MVVXK9Y{$tH!qg!bXcBSb-Hs;YhP^5JkbVDw!J2c;&fu3EEQ9v`%siy zc!t1;>|R_`)mliOqP=msemAm=2bn7=uh_*F+V~Xwq!0`M;9|wSBqA?9USr^-V6Au! z*lH@@yy_QdbGL5#l~y0MGbpwi`_XJ3NqlB)gtVl$W;sOrCvpp>mLxVu23F#h0@3N)_O@eFb6%L53<7?f-uJE+U{D)C+2TmWvm*O=J;G+EqIMVqek?{t z1h!rLA3%sYURs^Nonjr-dzZV44jaG_FZ!JgM@>#m zPDF-Pz1WbY9A@pl{yEC(UVZh8mx`V5Z&6xaqQM49{(s1N4|pp7_kTQl@0E4@AeS^8xM zTzd@|ca$q)!pUjYsPrceZ=S7fXKZ}dwA{E{$-zZ_iDF*3`%?SH_Sefn!Et+84 zfIQGlc*B&K^~gLma;?~uU}}ShG*-h~a&68-4dQlj(R2ElFo!gt!e-Qyo+HX`C3@Yr zVC+F5orQ9ux;)w;UhUOvic%7W@F^=x%SluU{_Mv!6CB$1=6Z+g_~oE4E)(_^aWg9O zN<_0Gaj60>@pY2YqohI4FtjHN-xzX`kJC4mgtSRVwc39LC@wgxOlHq%2iA4;&FVYozRJD`e15_=3nUyx%A&iNl@3wQ`MHGc>=%jpls^< zQ2g#jU^R1h%c&y9<+Nw1Sapr{of9lxvzcv_3N1K1WB*IozBM?Q?$wh^5E4`N_KLsi z!<+t5@+H^XljC=Y_w6*seV8EEQt7G)!a|H=3!}>ND`>3HYGaVUi(KD*GLLf5ruz%5 zHGnlMeTjG_h3CdKE;6F7bCla(6n4D4uDWkPbb+S{lW@C@2p{SagDk=s$}5fUS(1$~ zTs1r@x1z0U2wOVRC7Bc*l7?twh~JT`p#IdO^?RDPCp}S_tjd(=tnTJ-v2Bd|tVCY) z7b0n7mdCi?I`+7G;~7?!hvk3MxKz*WjC$!jbrpp9Wb0(}C@r)*ApnII7^EdL?UFpf zel0jUxq)crlogx12hn!}QlAg(LIR*KuDZaQ(-w!pJZ}p}%-enn=91vC4=TVi0R8(yaWJ4-UWBlW(4m5=@)#D2l3~pUoOO=7oeL zTIhCmH;~HI%M%)h{{9u%r$~5ty2(>^f}BK^T+!zC`F9ff%h>7J5vDU*ur z6ghOvFw2v-x4%ja#!V%+&a)Z}P5Ui25xOz-P(tLva65*RCy8MI{mmV}{&*r7tQhRr z&##mmDGuJ1Y3xX#wLeBW+;WjsC5Cam%2uc9mSmgyK~Es%G*c0XWJ_e)UuBzA%RF}> zN$Tq)S69*))q$|vu!1+@h0b=`d>a8l-2BO>DqJxjw#^A!10s2DK%6#ec|z#Wjcb*7 zm7K))g3bAR6dqBxHy2-xvJrTQjrQG%e&127>rUao@cdF!_DU}gH+I(u+kYW%DhSpwQg*@YU?&>Pp`inDtxD$ZZ-?D z(|gOl3=EGt;x2{i$hf_eZCl#!M>Q!o&Y;fzOw`V@6PFNWF*^;hXR8b&i$nY;!l!~# zitqgI+4@-VDb|i+sD|rYFJB)v)ry`rCUCwS5$@~YRN?Nk-}7ph*4C%3f(3n^L0;Cr z%@&u0UI;$U#jX1Qhv#T}9V|t7!Q7!|OHfEigTzO|5oE~pwb@pWg&26l>8blFG;FyX z@2rsw)?=a$d>{EM+xDtCI85J**H8U4#U;4jW75u;_wK>N&&`+#eIzJQJt0oalgvQS zX?_DAf|03Xsn$PqUIrs9*(y~{LDmy9*4-`hsSyMs<|uwyEZRJC!f+@?aBA@TP*2@O zR*^Z%{#UD~)<(v8J*$6eO%$`DT=2TnuJu0^G)eayiZm`dmR3LP3{i#1I}ODg&+hbG zgiwZlqN>sI04t-4K8JI694nb!B(rS1g64C-ChZ#W`W&umO_K@xA!{mmCTOg@_qpHO zK|n!anc*&8mR}NQ$9oocW4(pMp(jjJho-ID@3HLJ*6^ix>hMIT7e8Mv_qFn%T&YpT zvuvmy#fQD@Ukp<8CvKtld^ni=Sq&z%bAy?%w&TB0X}6ctO}-A_VkgJCM8wf=$F!N< zco+S*^2aHJDtF`jVee|(+ab_|qh=F1TX8y^9viuCD{B|&aTfKR(vn9%#)UBYE_G6M zpCLXM=WMPLB5_{5@03T}{=@ld1ExZ^j}#2X`g-g~Aq-~jI{ai%=%t8-Z=Rlx?RhgN zHfMwgJkPLx3xBw6I8`06eTzv$DScV?RH)rN`1x4A)HH0cU{Hg(!i;Oh;e1e zoE0A#ahHHFW3=R=Fyr6EOPYi<)Bb?3i`T=yYu|sW3 z9bZIVP?6px=`Fm!mUL1=_FnI|)^&_b!$oph>3s{>Zs9dyLDI$?eHai#c(>EL;*R{9_QQ?SR!$HE2FJChscJ z>a%!-h`o3=b$E&f8$tS*Q)i^AFJwtXNTicAo>jInbN`J_z7`ApG9JDw%nK(Q_zia_fpUERMOBV(;tfa88~nZ1JBx*E z3cJn?eglI4J|!rN_78%<#AJ=tu^ZUQg2n~P8;G>s1#blm+Y+#1J9SQ1_8#b}c4=Zf zd3v#88GG?MZ;6ux^5wh>8s@}h&hdUd=h_D)9xB3Jkgfd2)&Sb|_xXhqHoWoR)OgvWOZ%B_zZ z=As($(pE2Tc#ORacxn}^%MIx2t|}`G7Ywlaiw(VoIhe_dgPN2aScHvw7FPA<7 zyWEz(2ugm9h}d5`=%=lBW$*nno^w#vOM~paH&4MoY2F_&4p)wLKQQn@yapAyb_mNC zW)}S;+c(C&Te4!gLv*|Cu&bwkIg` z6c?;tN`0(vvTD!fzqkDu#0U(&BG8)Qk4?s5y>-nzPoadrpAJ1A+Rn(Pyq=5rhybtqiKucXOs-7&ySqo12E4N^%oE z=WB4z_@L=_%zSGkk?WXagit1KAF{8xG#zfKqn6EgN(*5^hWDMZPLcmCPVv6>jGh&? zc*OG!b{I7yMr@#YqoEw}tv|n{eD4Nko{{yQw1o+bMQz~7KQpUBHS4Z=G-(gOU&-D4 z*g?9Pgf^wfyRLCx>)ZXnnW2-#n39)@==LN}@FxO?p4FXcJNsSb&|ideYf`c4;M^*J)`ZjcJ8Ir7`!o?Q^9zd}nQXBU^I4XN$ETAiQ>E<-(*gjF-vO6yw3T1UV#lSDS@QAJaE`cx$~w1cWfdVAH28q2d!~+?LxF z^v$15cnwtkd4O&=f4?33XM1DUxTzR2-^aRi?J}L}<3AFMLnM_9V>ce6D7ZH1# z7kfW}%9RH`op}MnR_yQep8L*fdw}0Zj&_Dsng+yJChb#G>S>@4u?y?BNt5|^T)<;e z8O!`q%5o+;m>wJVTBsmcgEk{(Y!4j)q8suwu5&V$MkJwUuX z(|a3zXZtwU*1$UI0_<}AN307bs&F<%Tk}<4J?s9ywQr<=9afIsy}n$bbU6tx0&lIE zhySjoEU2AXIbEX>{;i3aXBcBC^;<=UT;NvO1 zN^N$I6cN9K9l7+uzBqNj7J*L`RlW;q@Enh`(?D7~vpp7Z(k|@BnOa&;R~`Vxq{k6E z6n5ocoHCg6E*X75CSLp8(V=mPpG#WN`DT{*)PHwB3-Vqy^$Ws>&g&>PEcFVYJ2<|% zez~u|hBb`o~c78dXgR<=WlJ^lq$}jR0bq zdUfcuck*8^U?95a`(K#?aTgY>o9??!gX%fE;9QsC%&DNrZ!$&md!?dT01*bOeaHsC<>Q(-0NzhK~<+&j~e*dI3o62iAYp3Q&x zzLGjbf?oKcPU=}~WtOPr{jJ-DlI5G`u{M3Tplpt{rFWd1(U)j8x30goBo>c2&NlY% zZLh9Y`c{hv|1<-?;-)&d?F1SQ+n}8&lF0--)K33~mzg-uYM+=J;m`cb-eQ;}WM`zl zI_(aU>)C*KQvyWy0^b&+v)GqigLTqF_5pHxxx2Z@!4UK%V5F2WGVXi~*RoIA?2NW9 z;V>SCw`>0h&e~pO$5`cx;G3XG=v!3=$(k$se!KMAUbWxnRUy{9!7agp+?aVN>a9Gt zGJ42z%*z{fSGff(aOLK@mbd;@5E<9V7E!`YOB01h6;=6Y#osM6)C%3&U}Z$)jYxF? zD%`uP1=$5BxBJXr>{s@dzF*Toq^jy#f~BoE!a)p)1Vou14LfJQV2~)qVW_<$nwhnUbm?e1M&cNApJ%?WJ-roB8WgIQO7%F45gK-J{ z`V81vKGAYO8?vFKjjs2}idFQ|JjZINil~r~vu)D!Dzc1X4DwE!7RTg9od!dRzk6w1 zndr^wGR)xGr#q%|@q8XJE)|!j<1{ATjcL-ftm zquTKGxZYpIiQ?%QMv6V?kNe|;d*LkD=}3-=lltuBytF{-&p0|*jhH;KJqeC}r(c+< z)dZmKlWVum-vYzy()jA2%pjhwzpXLIz5TsWtBhQ9{NePDz;B?4>BN?mB|xwWxvz)#iiD(@Xq02 zkvxh0dtlQGDYuaN{H2S4fOb_|0i)vhF+8W>*~q6yvc1K=U_XK z1R2bq=MS<8S#^fVtcwrsUKN4l6+ck6t$^&sT?F}OADv%~qxRNv{C9XbJCoR*W)8YX zj#qt>7R8j3M21Z6Y&!R+F#Be+NIsPf!nR(ZFE~O527jh4MU>-ILUfABNE~`myY#FP4lgi(Jb;fti zr~-=er@Pcm)4P`*B?1?*Qum+mp*N3USW=sd|M5MWkoFjgNo*ejm4io5x9JUK$xT{+ zwU+fx4%gN`C=ND@@xk(YWM#Yy0eqk044?1A8P>Y^27Z(#VmI0u3~xvsu$FWbeN z1wZ2Y)CeC@{)$j_?2oGZu{ClcUSxXjEpSbS!z`UIiS3@Ek{>m$k-vM=GU z8tw+qop9*U)g~p_(YF^#0cfY>Gq-&4AdLDt#dG*j%Kz^}63qgpFJ)Qj;k~3m0vt^b zyPT_bp|lb?rlgnJ07p;PNzGL8$ToNy)A@u2f`NELNx-0S=SL4Yku))mij#=%~*~9ed-g1;Uej( zEr=;f0-o0r&aJaxBrFmlBYY7sC~*Mj3)C1VVYoT!pazH3s7&efEO*vO!^o)97N9EhF6DJ zs{R+dV7z2eb;CT9|Di?2nuP!<7<#8`Jcej|($xJpyO9$;4EDb`2$F1@Jo37nc6iW? z!Sjqz^g_7xkHI%dY?}&rw@aFJlYkQ%A-G#9<)zOZ=3eKyb9~5|s`tZvjlrYl$h)L{ zE$8Ax{La%iN?-!$gZDou{`UFzf#3NL#Ak}>Yb{pBMF18ipgMmg;$U9v1!6E$Pr~W-!Ec*KDgA#985=t55(2-ySFgV|HdE=#d&L9w&(PHn zKMKz<%5TE#2#r{w9zrTf0%l)SN*Fdw`ej0Y-~yD#2sRxZ?zwU;Wv66A+%R-w5+~wV z{_A6@KHF+bpOhn>+}{?l%FN zpHsPl9y=x|8BNhU{U$ayAhMXINCB7*v*KNTJK(NzZwsgf&2U_GH*v2eoa@^c>U zkqRq*MAEa~8&1Fq9A&|)El0n{y^RmUsj9ptewC2C5n;clm~@TS;P&mhfY#dt8^ZB- zoM5^l8I&NW0-xXD1-{o~gtP4b6B*Q`nmuu;$qdl5djug>E4aV3shq4ZxS`jG{#)tG zP>5VI0*6{*B$WE?qi+7W%{!KsOM0~pHc4+Rg<$o1^6Kk7uNo}|;0qVzTp-5*bG1Ev zHDcFgu6}t&<>1%HjFzu-e6%BfV7otg14rwaKAQ>#?a20l{m}4CH=1-(peIp9y^vozDg%84-Br@9?xB)WJG-u^nkkvu#31sAVaV+~7Y%$W|B1Zr;GTz|YV|K#%d^GIgKTBCk|BeMF}v~Wr=;Ax zA@yNHqwpT+-7v8~@PLbIbA9jfXns`5+fhIi%^zQELu-pI-BP`|Gaajq{u442FVt7f z)Z($bQag||&%EsZ;Ec>ucv#q(YnUIYWZvBEPWx6FXZ&xb3pj^~$i*`b3>)_62*RL4Q=n97an` zT7*;X)yev_%rA`J_ja$7GES@LeEUqGM9r#ku||~@(JhSbpW<5u(A64T`93B2y znY|t#weu4CZT|aiW(g*yVEO8b_c=Q$_)Mv7`~lu-P5`-_>xZ1P*Y9&G2fwc%is2Xk z4lE@z#Dc2U3v$`=*Gi*Xls5v%_6}Q}o{%pG9fpfp0owTAH8?+YNyHZI zylUsI1&*NqLU1vqj9mY0jHs@qV5;?5g6f~^G5;4PXJk5F0VnvR#(zGDB<~OZ0x9?y ztwhd%`EJoi@8Wg-3qP3ALNkuM{kGex(d@$eJJUl3a)u6Efx|-T5g^n}rGKN#<0h5& zf$|2|1rFnXka^=Ka{WOG7I3OCQkZ833j{Mm-s_oMnOo4lq#G;%JQzp$ID#&?+HTS&_i1hb%%|B?F9iFxzQND0@yW^5W-_LiEY_H>%Y6FBPN01>ovA2Xfnn1KmhX(YE(KSWJk7&kPT|! z+}l)@5lu4)hl9$M{cox*K18hrH&K_wr8K<%3?}VN93aoarZH1)X>=;|V~roi?>7He zjRXG>=iFHgkVcrk*B7m((uhC(;AcG8XUgop6a##mdm*Dg40OOq60)ki-<5IkKPr$m zG!`bAsOSrPv&v0_&2_icp8TcE3+%;9eVNpH#}3#B#O^mp?w#p$kEz%OJxS^2-@A;Z2Az%R|%e4Cgue@TAO%KVfD3>-I)G` zxgfpC@yrcwfb1{SvxZx98iv&|oUK8~HyE1ylp*BGv5~OA50|G6?#7;Y?u@l%NtAiGIEs zs57wUWv_64sQvF&+D++T1s!Ubh=NYC=uoS7^R=Eb%KKL7+tz^)XS^@W!3#7Jw15!z zG-CXY-sFnQUuiPKZM+t*dWfNa4wswg^$S&-I8alc&C85fnSockXjt{#VvvH&vVBQTY_ zh^mC@Afo}=ag1NC7!%wKK^~kHkjBa^T_vP&opze@#d)$`yW%JAXB#TBW| z7X7Cr>v3m(0clBk_-u>KNrq3&VL{%)nAWcye|B4m=(>UBwp>YJ)I`yXL`dWjsuRYj z{)sN|w<&w^^9Cg)^J#liW|CRR()9vv5kcs6TIx1?kS@mp8`!8`z2v?4pJ@pJ0H15c zH;PAjw|(3iOSf_}6@y`%P!ty5inF=!3JoURl-`=-1dPast+Hj9t2av08+iIQdH0q#b z9C|)M(-zU>wHalGGHO5dBuvdhM=oyS^{rRiS1378E`Rht;IH7P(ML{tsaB6L1I|*G zv`EZO?_%M0U<$al{)KaaKFumEN?-d>8Dgc$G-qy6)HooS#C%o3covPfbn*4Dh%~%= zT)q#Ln^xH>c=yz;F8H&jPaVzgP{ZeAqEbEMj?49q%M)g&PH`-;s=~ zHrIq~x~}R<8%rh%er3A%r-diR{-UaS0 z_kU1}&)i3&Q&|Sn3vk4ma*OeT!xE_T2S4xfp6?4}!R8AM7PJYj((xVS>#+SEKjui*tjULBN3{n@l+J9bO)(@= zfXieae{E~i0JDoq_Zf;VQ53zJbCoFd-bo1aPVc_ehtMXYcb~RTZ z3h&O2({*`IEAFb~$S$=UQFwg9AJl!h_jFO&apy=W2&&c)W$IC+zzW{mnq1gkQ)cmv z8~aTr1NwBHe5Z{rv>lS@1tE4tD!uMOjLk&8IS_@(j_{g4{-@AZ42K_B(o<@l2Lhz( zSA$nNeODg02WskDv{8#D6>FmbELZypg$c92={qCB=>Gkty}RjSV;w_SoD6XWR|Vep z5E7SDW$CurXek9%G&Fx>@LP$scl{;rL&JWnKS?~WlXqfzUwqFLTDW=4NcEh*fVl*H zDmHKJpB>i2^LSlXBj)$3zUPM`H?Al`9I);SOrbA=1`yI-sZvM^4G%B7GSv7!5I{?y zaSs^k4x3T|?C5O3CEW>9H_1%;Pw0ykReq(eTxwZSCq4S7ucCGes~x=Ke}VL;x5GKd zB+qN>t85j=3g5i!{o1{;f;#JR;W@ zRD?mg;t)^5Au3DM1C8tcGi~4vBX{u#hqv~q6~Ft<4nBuC0>U(dY7+oKE;lKmm4~yX z8k!X-J(ZBSb^KSb0Y9obECFy-Yyp1a|L02!aldRtubVuDR0c6%MXFaN9kAD;;ey#X zYS+r=TFCbW{QG@(yQEk@iixZbKrO%jS9Y7}30O>{OnufKiPmB)g3JFNAog}kTgxN4 zOUJGkXo|gf>hrZ{Abu+p;-$%qG=O%hNjzO7!B`mSpx4k)eEI`o&IeC}ihBzg?B(IA z%c8IueMs-6+|JKQyq8Q?#E!^v5JX#crW&dc>iUTFeV~#|CVcqcA%vc4$WlnR`S%{Q zD9B(tDxPEYOUB(?D$Ond7^wU$U~#Ju{vf5smCMk`;9tX?)ml3Py|Ne=mVS#3>if~e**KVMEZhxH=(2vQ*fM9-x74)T9L zsu!l{Ds(k;=sHN^kTZI{zoEYwaoS-Qln^;3FK4?_vyocL5wsgD7JT?uIRZ|4&G!Ws zYka0P{0rKuB9Xp;I_2ou=2qQ=os(9lY4+y|BA)dH@ z^idS4;3IAN)EnmUeuuk@`T&JTd-cX+{O9wcufy*#gP?h(eJS=R3%JPL;6%rH!$tt} zaw^aN-TKw^JgN}hr{?91zfNe@4prKWptYi|>*F=-`oSBFki%5D8wSs<|x4Y&~E&BUn^Er4Xt=(MXuM~v;@pu7fLsKbU z2ntNRi#f)!h%ZmbN_7|f*`3H11FHLG-=L3(^7e%Pr0EP}5ctwO0H2VzHjF^B$o7yt zD7{#u0WgSA4-h0~0NVmQ{VezLl+O9yt$_CEi6kt z2#V4aq@yJAw|FAoMaooGofOVAD6w6-L(R?yX0sc^Ww!$|t!{!v2-`)DG#-irQyJT5evO1#X*alJ)pAJXImQ_lUIpoaD8nj>Z`*A3JA3f#$r4ausUY zL*msRcz6TX3QE;bqAF@lj))4Lfh)^Q`ZuM?gWt? zFpw)^6jKyc?Z#31Da=^e=SYEb;@0*TzcH8W3((bb5Py9VuwiXoUPW*;a}{Bu%5s4F zod>azOw?15Jo;LC5Jzj*fsU@Mcr%ekgub2Z_3i@4CeIb0Hj;9?i!-s1#|ex#c+2rM zS=GAway@N8G@Ygi{tm~6bKD9%Vlpv5O4y5~)z$0(0Vr=5ZB(JApXCfmqqvtMN1q8s zS$81kX}6ixz-Xjc4pOdPTLfN7$;6taEcs8w+|j%OLAx1_u@0xXOaoh7WH_W{^G0O6&pletj~LTkG{OlgIr+SytpzZ zEbhUNh&B;Yseuy1&VJh0OoG%VxstYr4hqmMl{lWz<8Tf>>KHuv^j$*1|4 z`lLN|)Y9AqkJOsL6a*qgjeLot?g+Sp+^8URba@-RhqwZI3 zFMtqJ3i`Ln^jE4gRF6T@wA9ePiJH08O?$kx=Ejn#cMn&Z%|mS(Z&)caU#cwx71e;K zQ5?b@NqZI0?Ea(MED8I!$F48UHbEGcqm7pK=i2USKLUDI^loA3U8jbOyBAO1HCu-T zeYSUufH3=cRNI5**-3OXLB7`abDqbF4O@5Yr|nFPo!!pq?AQVEVGalb+ruSlT_HgF zm`o3Q_UHEx&%?!YqLx*87wX8BuL#I@jk7+RLt8c$g2BmoJ7A$e+6;pvcg}@ME`hkw zJos0^i}=GyI@WyPunSTR1V=k9lu}?PquD5W*?!VcoeB`)65#=X%3hd%L8BWG5&p`1e=Y5+=gZONpAB5gXhm`xlOf{q2diPL%BT07re}vVVlf$~B_f zHgUwG;qLp_bqLlw_w3sa+P4y7)3VSvqbT&1DdV#2^G_+V9~$w{^n*cz{qIr-K9=~1 z8j^|p8z^_(tTl?8he*3H;VZA3cE1J=qTQy?;h*$0Kj5CX+6;^MhIbN7B$M|VzehA& z)5@+F91+}gY?Z!%fa*tdWo!-AcOp#+tZqsNrT%0h)O3$8KOyn7gEiZK>&^GR!$X|J z_jovdL-ea-1LFce*Y}3wxXFz4yKAmDuoJI%(=7@3gg5@FC8`qLqUF_%#3i3i-gB5% zkqV*u!948rUABddf#$qobFg3+mHr8%&~t}m8FoZJ=~T(->;yzjeFV{u$*r~_qYU+& zp|Vp>Nu4}J80F~nKCap!w?(6f?A=Q+RT@Ey?0&scM8AhuY!Ozm!)3`~6%#8p6;2{! z&!JY~SMesnkggd@fs?FkC&*epiP}9Npkl^G@;vvDta!z++|=@jmfTH~!$P_04U`+_ zuLDjZ8~V%LTX=73ln6p=j`g_MNGF|`9Wz~CP9oLwLJTG;Zczg}mk(kZaPNK}X3a)- z9)UhZ>PW_cWF&B*FUOS~hpML4m$q=zklQcj=Doev=T&4p!7*(TK1*OHGJy@Jw{FUi z-I4trIdv07A`7wg7NFTnw zcqe@NwPx|#*~xdgRflLSZGACI_%(J%7BS^36`LIQ94Xe<`bc%NC^?%G{=Q3Y!>A93~YhqXVKAIU0*Zy)DDA&fLTX)kyCJl17; z+jVl+8)Xe|q~ApAQghQtbtRAAaq2R3s-B@{V~)<)DNOj(UgvmOGUJwV>ka3|SJwr* zIoE%4DhM5JC(;!V4f~2c2I0!?bcbLP&t!KJPE!|Y@odA$l>0{E53fbS4woXOZEWk? ztZk?F57Z}3e=``Mt=+qq)EpRUX($I!i_wki(OuI>)I1Q~yvpiGY=!8`gFQ2Krw?W? z*U-FXkvNn;|DAr=tP45{|4LGej9SOjALuR=cKJE4w|i)i&HFkN{?jT!{5WN^Y%o74z`_!ZVp>dGr!=8L(JaVTKy%_k0aX>zx=uI_{fA7@nQe(epNik# zg9oQ;BdYlT6PLoDtW+gfzxOD-ZZ+ufhef@GBK2Rf)DARMP4#dq2ho>MK3Hazfxw7^ z46gTQFCO`$&Z3At1-a0wXw*`Z)l>8oN*Ik|ci{F6W+P{-9+A3;wtjj~^~0+=G-KhH zXIENeWvon&=o^mHO}!O2DUM;s6B_IptTdhc9P*u>RM^+<&}w95t6O}4`bTxkrqMU{ zt~a~(^fM8pKhYH(=?COn6nVV#iGrOa!Ge}}^u~kfdYl9c!E9ue58+|?PQ|5IG%B&~ zPe*TDiyA#mWV4+1o?~Rkr39a~SM8N7kp)kF^!x#G@xkMZHLq%n=~8G$2pr>0+8Xr< zEQuCpgE0J=FOJA@0KlD27R_76pGlG%WWu5uaBoShv&v&Yq@_${%dZm6vkhPODOJ{N z%+NJP@crY_ds9GfI3bro(tBz^JgOt%M2l#ic4ojeGrm|_(R{_0Gl>Muwl*!I6V`DI zzv|z7PxbE1GSK09Rq1$Jp1&$NlKb{Wsv8)yf%gjY!5%VD&%;yY7pxplicwQ{x92J1 z(QF*X$8Cg5Qs%itd_QMn>FC>eJ!!pzEpC)59t#_vQ|Vj&uDW%3+N z5=;I``WCh411I_8*Q3zEKOcvAtSqhYHm$s(yb*U0{j7%LyWTj1y8Xt_o!QNhf^Jpv zlGDX#T#|oy+s1d-Gsj8YTdt|AZE&xx%=*rT=s5qWji6t2lhHuW#vhIL&_)T$*iBt- zsJcmNEv5V6b(eDDbE30Oq(9iCYFR(aeO8EwGe@;~&OuSab`QM~60}zQ=gk&*k34jN z>pNz%*etCP<_Pt)V>)?$?t`_{XtgsnCCxk8h!ReN#`oiLq{ln1M=z~N|a zaC9UGUVQ8W7F`s#h_g__Gg~Nzh0pD8bP=Sv5-qc>MFA2j!)uE{>$-Ped%{J<_c>*F zE-ysAk_EFlJ2}HmRzNcIyXI;81v=ZShqUxQDsyE5^@)_Rq%n~Uft@0#7v_y;9VA(# zXcD+g;z;7}Om>QVNKDDT!_|A$-lb=KbN{njwo!qqc4h@BP~$;_K{Wl*&iqS>eC+_2vITUgMHtK>KOS8Em?7Y z(ih*Tcs9wP53k*!AeL%Rr&U<9ig~oP!t?l9^Ka|Th`?yH`e|!RdHV}nZs(^}7!{q{ z7(LH($m=8tw=qt25q@{k5W5zOp~b0wl`JC1cZ}mm6p7-TU#a$9Yv@H^KVK@IKvHs| z_>FfVi{i%f+CcU-T3cFmN;;BN%#@yQ@kyS^;uJyyy%BeeQVv>#}z^TjmRX-*dYQ!u9uphhfoiCE{Ig`_3hd;FR@K z0x+9VP8dC7`i+fUjv}>hbz_qre6271-W?`P&`DT?@ zUgX6a}zp0-IQ+(ht&J<$379_ zky$luB7fW0`f6$*{#(~%?#1i6sOguCW!TB;HR{qJZ~1}XCyOfz7)85+hZncZmA~XB zb)S&}m<|Cf^!~QQW7aZZ23i{eufY!{nUA4pjr{Qc{Goz)H_281_)@Zmng_!9GhBly zqcOW(R6Q>b%nUmDld7HzKhaI+ygF1|e7fABq)PRQ^Xcx!wxO7KLjHw^S;Kb%`Fyar z;Aq9viHfAYQv=R?&bslI00%OhKU6DoqRI<8M_)F;KY}hU2`iFz5s^7c67M2XI8&=+ z=^T33{_DF2S_4Tnqq<;&6VFbs69vn%<+crH36NQ(0r0G=s{h<&ptDgv6Z%hc)@TeSjhFo_xeJmP9~Fot*! zJUwU9Jw7lBr#>xqCNubyU4RoXJ~e)RJ|)TW4&6!aGY%JuH-gEC;=o{9>NbFiE29qB ztUf65D~R7C6wAbE8c3h{1T7(&&%_fsN}g!n0BUCjaNpnCBwRrpmY_d@JNjFlXaeJj zvTj3TwDiZj5!~N2BgfK!Vv$qXtr~H&sXenG+<~I+S4WbZUNAI*@ws>DcKPl-!i1%l zKF0jt=qVfR<2{{4loukm2Fm+Y3?9b%*juBNvd_}nY<%{7)&sbQo1I8R1+R>`_mec2R6AL#Nz^LNPM`_1%(Ev^! zXA@gY)cRobtkZzhAfV&WAfrPz*)J!7^&@R40wOKiP==n}dRc($(fRtS76GcUBtRajfVa%ieL`iCL$HRd|G z*7sB2X}+gIA;?nXBb8I#uk-nLd>(q$Z^>5Q0w}tvoM^1GPphf6sSxi$w4R5Oxh1@H zLMrlhzz-tvbAfPpxg~5_F{EY;PXgmo} zq7WNAC)t+tMy+GU@9JaOX4B(vCKVlD5akvg9$^ z$o6y>&yZ5W#rqctOhS0?5)|o_x)(W2`D3Xhn%=Jv-5{)ZKVL9Lni|&AjLSb31|q7U zNvUo6NJ`GaO6M1g_*Z_1=6CvN2DaDs%-`nm)8ug}1Ny6a&(qjRTdP;O3ohW)4`8T< zwN2&(k-yD&C;`FkIDs;dl*{xh$wFCw^EK`o3BxLrZ))o++s7A+oK5tE(rEeL=k(^v zJwsVP??!!0s}0~@rCT3`{@_Rm8K?@gKvo7L&ZYC6dZB&sTnUpU)Dg_sstwM??$oU* zadNDEL5#nS%#1g3pp>2SC(1>`>gsTXM@se|&bGJv)8xKMB#U|eDdibIp^4z;<)L`+ z>eMZ`3fd{Y6=0Y1Z>m<8+Ug(ramQ%-HZd=}srQP&ddQ&SY?R_MLYaBVha!fe)i~4- z-ku}EpXIWjYTUg{Ep+>MNeUS?5e&*Lc^$mKp6T}H0Weu64uDt{FAiYGOiY1DOoJT}mgjAK>XvY3n z5#HAtXUeB3W^QVp$BMrM;+$qd%Q=%GYxg{P<8h~LDt!@d5w@_tU-e_z+=_&2nPx^( z8Z`S}M}R}izwjlj`ttPI>#HZ2UT4@Tv+!(3=?#UeW{GSwGoYc3vzY?X_FYQWWimo$ zlhs1+9Mb1dn|6&5@lN@`&DPQrP#3j@aPk+g6|FlSsfk!rxQ8AjFg{zGFiRcnqx#J? zCov!kV|Q5zpz2bfrn=^&d>^fL%J{0J`598?Yl_W>f6{_76ccFWW-u=Yy~iHfQ3|4# zG|fhKifHX4_6`s%P2nAoW$*vEaajH|cy)jE^m~SS{GzC;0%9sv zcfx-^N+J6WwlE#xg)G-$Pps&FkfDE5SmW-?eoA}Ajd~(Op~9D+{lHo@*WX@gWGt|1 zm+N=!SHtG$qTBU%Xk`LU`p{Jy4MtAA_PbIcNvwH#>(N%t`-NSxyyxt;5v>oS9Xg|e zVmIlSv7E8DTr>Ni1m4#6R(D?An7PO)ETPetUNGE;gq{gJr>^qf`R4J5>L){JiFr)q zcyQa&t_9R<_Rg|}b^xcL+0B+M9A|HoBQ4m!&3_X`KJd{88i$F3%VaFD}uI@ek z?m*<;oA6)hm37Ax-GGQZcvEhhkWF4g>NuLNF*bb1==I6Agq^tvkw7XI@eu-s)b3x2 zb`#%LPU=GWi-~W|uBUm8c3u1;-Hc#0AF(Lc!1EtBh>C=V^kW|3l4?tAg)s}(T^Uw8YS z;pxPVVPEw3W9rM#WXcEV`(xhS2HS_gYIjm@nJwlmX|IsixnCQ8hD^y<;>b|F`=l1O z<2~B;8&<^6j$XZB3w}6y=K*!hpS0_o(U=b_6}1lPc`bD{gzbU*JL?Naz**JJdkMLAfWe-)v)_C^dL zl7b8ga0uIhB=YSyRNotz38hl&O|{}aP-(aR*`AeKI%6%TEH2uDqplEm!-C}`8i`4u z-f#Bi(g3~jD^xTgY`RriZFa#;BuYXkTnCFU zTcBL5xv5%A%obG$J)e#@9OFxw6w*kZ*n?oXgi_S#v!RzKzoOJ8zjo9nqXHSq4OC{5djH&Wa zt~AdCR}(UJwr;P#A|4nIi}Wekct|#&u&3j?85VcNcH-LR5vj%}Yn>=76hpBsS@_Ae z?p2!#APpFfrlt^&SewkSL~yx(`ASYFs<+Q~cSn^YV+1{9zEG!%{@{zWpWq_f@h~nt-&elw&Qut3*T_xIer;-`;;d?peP%ezt7# zb!|Oui3-pFa>hu9M#3FDw6eK$qjA4tMNC%T?>hUD^W=4RmYPXqidw!Sziea7@Z@}M zWMn%nR*B6)6I4V_HypCoYx4^|I)qi+(e(j>i#>TppV=%o2v7Olq#@hB?4^bsm zPNHh*@W<4_>*e&{NEn}cISH3H`Zm}+9^F+g&b~wVp>NlOg8$EBVun(*Lb-s?=J?xK z|EYz|ytcyJe2LS&$I#+3vlr5W{`MFH)`e{vvNu z^~=wcqW}P1CyO(;=`ku$9=j>G__mpcx$Wg9?jnvxpIGDnBk!&MntZ=M@RtE7NT?vv z(gGtSq(LM`2uL?bi*z$mNkMvy4waJb93c%G<>;=B0V78<;=A|f`zL&V{O+fF_v3MI z_Z8>5u5-@wJfBNUj}r7C0SbK@)_-pb-w>D@1djIWBAVB`HzfW$kG%J|H|l8dQ_H6i zrE(KEU?$r;TG-@!GVZ6fTFzf+%+@LcG6WBfx_t8ey+UYElN*<{8EfqK^PH={#>al5 zm*ouU@@9V}N6!UcKI{tp`D=95GkkwIS9&3Entb5v_mhCHew|`U9ZVSR_puv9y&N?m zF9?f28TG`d28F@%#wgU3&Hnn19~JbBpeepI9>c}mf*Z{(@Um!gE7MQ$%+(y*e?825 z>5Tu8zN8ilF^O7VTRr~fOn6G3sviH%C-jQKk(-e(W<^=HXLXL_E_HEzfS#p1FA9{%-{v(H+|C#(NO z;0JS(>^gY0zxP+49S`dI;I`F(c(6f`&r)MWxb`k0`ZH@I`HcI|fUIR{{^xn8#q+igiizjz8Aimxz7@HParUgs^D5i8pQp@+zwCmB<8~a z;qJ5sf));b-v9aAMwS@D=^pQsLHxinTqMC(L5zwY!a~KBs=l7F`-=MKz1qB{Z`iZU zkK1nT&Zgw;rb=`kaSrqp@w@N?f^KO`rueK4to%W4fE@pl{+GYLT3Q|z6xhap|26)j zsEJz{SpRR4brigTo_D{MA_91t`pE9f=Jmbr7Poe22>bJ2+Dp>!zk7uyN!sWPXR8y9 zm~HXmFg!b?%O;Lb>kc~*4s3w_18ss1YRdshOq0JhwU(%sESB;3=DY6lz&k_VUlUsO zFQiFMiKb;bdWf|p1_SvcJb&II8R`#s2S$%P_$F~q#kcRjz7dGJc|ED~UD_lByN{pt zB!)$d>(W5HT!W&Y4iU@#uK2ik;|lsb=A*rv`n5CR{rH2;=4So3(q`2XiI|9=HnNR4 zjL_mzIQOgT`#lt&9i7amUIw@xJkL8ep^FwrUtBU&K4n%1OtdsQKbv{Z`tXz!?X-Z$ zrJCUZ)w%;EHh8`VdSZV6PqDT>?-ZZG^m21dw{*{LU#hW-2n!f8mM?tJdPa(QaXw&Z zN8}ZLRR8dK?wrc%S0FoY?{^kH$RXb0k?(3(UGDZHfR$2u` z72RqNX28vhKfCvNe#>?UFuvPepEd{$i{Dzjn48!&|_ar${QuuGA0OJb1h`?ngt z+1<#$uKt)M52&LPPvO;YYn@4w_+#Y$q+SieM#V*-3MJp!22K@`sh~;=8eruo| zR<@WYq4Ajfe=w*2i=XKJ4`cLy*9rvxzq>i;V+pc3a1l>O^8UYl5U!X^KVN4+R+jo` zD5)K4Rn)-pA~hf_HpP6#3+%Gg%_Ayvo#7%It1@FoVUbDq8xE2P0!C&w{o`FM zSf1mWAS3}nTmfy~HLNPPS02@il*kTS(@KcU*c}^DyK9VWJnW49d11%`N#RUdO=oS) zy6#@>QF|1!=;P^TLp!R3y(OPz5o!~Da$*tX=#nfa)F|fa;1=(4t4z4OwXl*($CRXb zCrlcX3|E$@*V7L?D}4gp;BGk_ewN$`Yscb&i|^+CTFy0EMaI%i>dfbwXb`9Du;umr z*_I^xQ8*z#+hMxArKN%uTOUvPOF5_Va+IZBrAk4}Fq|X71k7*z>}9 z#XV%Hqf3f;kP9StZ}e~)oy2kqRXvbtQXa!VRf^xD;SQIJrv&^r?|eWjl(O^?hLv`X zb94X5>`(EXf4r`R&kXdnOp}p=l?~XTuUFcC1M;v)E*^t8Gqx;pWRb+-pWP(^gWS(% zFesr0m)9?;2Ei0T<>Ut@!6_MIzF=azJA}tvwL|U2`OWWIK~WFg+iYBI>`R}fdg;D^ zVD6IY6Hljs_dwlc7U#0uRr5Tn$IJk;_;Qf;Xd_h*0oWGWB*TkCLgmoPNjqW40r~w* zYst>Ep&p{4^f5eRnVP|LUC5M)pvRUDp3$9Lwa#k4VVKbpq#R7EtB$1s zTditB{%$jGH>&9bh_6iiI&%Prej77EcWSd3~y(GxH}|xm$31OvR(4f|6D(6>_Y?n|i^?GF~C^dWTzyz3F$RTYREn+!va^|r^Pz6gB ztM~6^FUNl=6|(AAY*QL5=aaUA){7tdiUqx}1ck z1T?V#M>c8?zB5!s$jn_FAIweGsXV+*=89W#%#iNJehmz;aBSJg3R?Cc-X>AY4Qnd& z#JShL(Zy@p9M4cXIK^AwiOz|3Z*?VJobHSmYr-;3c>yFUdr`n4J==Cn5@%kv_jB+ z{95O2mbsVfMNG>zDn1Xnsbp1%Y%x29wd*qsMxr~IS(&+7hbp=%Pp>AY3kQgk48<-U zuhubg2eB=CJJj)q=scVm045tuU1?Mvmmj{5Ct&NsTe8_Sp9M1}Co5~sQex&hK^@oT zSHfBwu%UVxeCb-tV+_$tCC2}E$b!F7jZH@R9p>Za;uqjKjESccjKVa+I)=X=xt)_o zeUQNc&t1W%JgI}Vry)bXKFIh2&u^J|I!*X6jr*RJ+Hb*L%8gZKd_2?kMU3Js(6=rr z(#w*$UWb~Ocz7uaT|xAF+765lhL!T>vnPtYUE9cODA8Uc$Hm1ZjY$4q`2QGyVC{_%7^()v0F=sde0w7&xm0i&sgp%!rn;L>%X_ zYF3eZ$j3V+&GksCjtK3jEb!$ND4sq`Zu&cf_~SgMilpbP2r zD%G2mj=zr{tk!dJ4s=>DrJ1TKGxamR=WFuo7RO{O7#!wn3cO2J?vI|eajJ!x6c1+p=>yto8*=O= z&$Tbf=_t~YC86GI71|mbGA^*IS+vL--xRk_I?roV?$7Fua_hY#hDe+6L0x0Y=h0=a zvdMawNQws!&C`@gi<9|%CrsyRtwK-!ph>pIOf+a$Zhl=S(XeMR;=2}n28%JcQpFfg z6$C?bJ;s8X22u7@N$;sLhuWE(iRTR&<^&CLcl0evXCy3)eRp1uj7n%>DP`2=Nz?i0 z!m_O+agt;2r)6*|wZ45kh$e5|68+AclQy(W3kq9Tp!|y%vAdjLqciS*^4%!|m*Q1s zVfH0w#aP1IiNii89Y~xvr9t>%<#TS1JZ3pjGBanLY%4#doX244GB)tCSh_>LcE2L3 z&}1ojGdCw_$-#7Vif_Ro(-;<#Fz4U9VkaKt>< zdh!6Y-{FENi1Ez%Q4iMiVMv^+I#0Z#Jd2;;DmD{WN+l94w#`lK#(v*5Jk5v=KytJ+ za~#MqfX-%mYB5l1RHSFnL7xgQ>geE%MmXi3=dJ3*BlbNr=Bg8C z-iFetG#}}MB%Di&=_t3hGPf|)K!(_#H3uga(Ck$Xikx&@P?Tu+!^e(&kqCBdNOr`L zCTsD>r{PQQVD*KPL7m>Zx5g)-i;K;Xx@G1%rKzYnI1i_2vtH4|ve)1UloA>oWqWh+ zR(mmbAbJEfm-m3D=_K5CGZ=T+npP-Z$ig*K=0+oqn$$r}!klePKQjdy$L~Q_@EY+Y z8@VY&{=P|-34C7hqd)|s5%xqK(Sdn)d6@9`!1m*s0?l|n*mU_<*`n9LI~sA9h?|}S%!Kl znWS}@H;ib7Uz$(cgj=tS+1n)@CG9x6a5nHhL$EE)RJ-TtB+4bZ#YBHFobj|k7wbL9 zgQ8v8TXa1S)OlJIDRwo(0$SVb*UmTgE-`8-e;NhSba~aJVZ_?S21MLWVfF7`XtxYI zXg7J=ZzCGNW$Qt~QeK+v5An2~9}OkQw_{~Il-90>y0NooRoPJ(j+S-Vh_);($%<;J zv*Nau8(nnwOwyVxNE5!cVzW-w=)nsR;d9~}Fzn#nQsJu6i7y8#a;(ItpK_}(#bnI+TtYW7#*B05 z%UD8)6Z$@lSEb~9saxHf+P8zAlrkBVsZj<)<2(DoAgpk*fhdzbYuaN$c0htNMAM~W zU#i!BaOA*Ac@8~Zh23m$A^dtDz0B$9>(Mq~Gtj2x0c_$Jn(0)&IYU%?I6L@a-qA=@ zCwTqQS(F3;I-|Jcdau=T3N|UcdJICwX00TVa*-EYUu`z*gI}O#Z#*$=h&M^Fg z|4C}MybEe+H&An!+%^Yop8DD#s>@Ix#(w*ZZrqXHlG)%xX4tK_Mgq3kvAbGk*jnB( z2SkZIk;D8x8O@t*`HbVsEbKdLO-j8^V83i&iSXx{vAMJ8KoR@Q*xkTZ=pK@eT~EJ4 zUKTDia%t+la=d1m=R2Pz=Nw_&!B@g)V84)e;Om=P(xz?Stj_9V7@Xy&=)r2-+#i8x z139*U*8LBR#d5wqW+-^yS1IVwAo^-^R>MeO%e2XoXYoV-L;aMJ@WP&&PMc|Gy+zNT z+1_b^4Lp~HZuppF&-I=>kIg5&b5WKC{F-jU%ZQ=5*S)#riVX}p7lkbf z7--**&Gro#-P4{kvcPm?U~%8@JO4@*ql?cV-?Txv(>sEEaz>e7IHIY8># zlnSGzZ1KORsVW*~UiOeckNFCVVkv`oLQvJQigrN*-B^IrfE0~))WkMmz+JLXImlt9 zx^~jVx9kbM#K$YIKVSqGw{Jt+o@;gYBt_J;dLkJWx9W^aS^IdGb**RDEAbhdI4;0Q zf4REe9owD>cY+1dw8_H&);x8_!Zy^wln2&t%vCY8%s8hk(a(>ZJXAg1(L@=9wV_e7fwuqBM1nOJgO(DxdsqAJUr-%5-#HSJ$8PD3q6TKb7zdd&h93sPw_2k&D zg9C`raN}2^%UKSZgZ67sj5(X;4f2eD%=J=VCZkU2jDsPmVN5vjzM?T4$y<^TG7~$R zJIl?UBfGrT?ld58XSN2k&6>#H{nr6r6t~RS6~AQ~O^l5|y_vh#4>-1hY|98af4a$a zMZVQkNZCHCxwcKXoISu=N&5!nVnyL6yd@U>233F!7r1B4$<>vZ$F-t~A>)-6W636? zZz*O?m}4vleszt&E~U6k*Emn0b`bG?9Z2svq@*G(tja&tbF3zi$!JxCdu=~YWbBst z@+j%c{@IRvuaJb88069uoq2j`(t(j`NVTqYzM9gO(0tm0JXIfxOSU{PKunY+!q1IX zNy$7r&=DkTvMYH_9kJ%rOzWb)KKZ^;|}WmmR98V6#drTkBJBJwPvi&q3I# z<%0AkDmZYqmoU?DZsYmfCR9wtq*%Eu)QN{jxSOTlro3@5r) zCPeK>x>ENqqVqTO&box>6V0yo7tM}so;<_#^t>cOf*57Ykcsw6m6=e1r^>ldp+pEk z^7>ToXLWcO52}P?dMgpAYH=Cq^r1thE5dfRlYzj}L1q3b)ztL+!I#%n1^Ut+s{>CF zvn@=v0fAtTisajr8Gaag_h8ath+9ylQL|H-^+u4r{Xfg zsZ#Bi`S{x}i`pFEj#Y!RS`SdISG|@6RH;O1GN1gN@iX4?66B|TE;+`)S^_}f_W+72 ztFq%o*Am9i9@*mKSN!e#ejD79sP-3aNKnBl`@yBTV8RUvavD2|Es7LWK2YKRoiW*tYdHT#=yn7nhH)}QGU11 zrs22}I&QH>hva$z(!#o%tCl2-jn5?Tf+fL_kB%kgbrnx;d^BP3K&QG7hrRRS`5~vd zn#G|ZDJd`e3ak?yJ-rr8L9Htcg4aEyqq!9Ow?-$slJ*S&x33(`+KcKLt}3b?Yv3`;RrfE{zt|zTF?n#I>=hsyP*Jo#3>ZWQ| zC6(CAqqakuM{w)TPBwIgwV3)q2!W$f>_1mN@_*qeKBD(`B4q9zXe-t4?d6MB<{JXW5U&~w?Ri}UGCo;q+P z>=q1_;95kdY{bM=X9vYCWB^w5%~^GDHMWs?FG)uu0u4J+w)&HfTM!GG(X?(ki13CaBk2qC9PBm9u>I3e3JEF1z@3&U;x|+#^u`EZP}ub0<)vefLOz z4g5kqSai(b%riZSbUtZ>+h`i*22RX4gcq_oC#l4>Kdib{6)>%3=@|pPT+lK2TZ_qu7YHn5YlPH#^BVnuBoR7?&LkCi1%K=~F-Tz!XaD{A zU>%4wb;T0wKp69!JlV7;ENO;ZfjWi~BB!zOZRDWBBRUgspA@~hw05R2?XyoyGJw0F zMW5O-nAve4!$dhp>4ED>gsm|mL}QMT%HYC+NlmmWEUS2Y&SOu=0**%ycAX97R!d!S z9ElT1CELIY`duy}d|lQYzNa`E7s+M)#I+RGNnNl{53$Wjw6vITPLaCojdtaC`@%Te zT@#z`5C8oYQFvTBy2Hnr;asfJsTeHTZ-LeDBz)<2lps_4+kHtoKP)<5^4InP^C)j7 zTV-{9d$|-y1G0R4a}FPfFF^=)p5t-s{wqn}sy{R;iQ)YA2bP2+R9fy|vWMJ$)xP+! zEyTYk`m*+eAtNM*XBoWKE})>wW0#>j9w*gwd)%gd{{+|RZ7WM@{c zRaQV_GZ5Ei|Cso5weMK+{&eype*^nvm2YO&VMNSLTEQcqthD3sBCL-Xl`Wo6ABb#< z-UC}p98gpC0!zZghj92-}^aZ+pBMh@mI$vin zmekLr^5JgCl1)V3D_}JG*Sw!TKfD)I5TiB3{mjsiuby8=t_68R@s^`lZg;ov;$lo^ z`ZPTWAMk@SVM8z58RzyjC15H;4l04{A?(`>Y(&M(JmIKs-hvGwtXyVSEFharj`Pe5 z)3u>)545g>U1;TmaY*R1{aZ34P5}8}YspQa);7Z9AFGfpI3Ss;QrM!WexifNq3sDx zjpmEl**={Bl3(?>&C^s>J)FwVBA76anu7!$n$~uZ?I3VAI6P|JnsO(_{#Jsum>B*5 zQ>1#QR9JYTm@xR^TyJmH1gR2%qnM9!6sLtTzkQJTi7j@6&qC$bLnITT6U=Jo}kdMZ_2>@BBAw2jg-b3ak?ft?$;R-a+=|1Pa|xx zi~41g+Aj~0LU)W>0VsdkV}VD_)*vxWgok!Ux=upv@o|fUAh(;_w}c*(RQQ-=*z_yQ z#J`n?q+@E*t^tJsotoPXxVf7e(_j`{N@7`ZpIQG4_+|SNnNo}Saj4T6+rJm7Kv7t4 zW7~LPA>7NJl?7cU&rFOjdkt~cT4_XBV@mzMjQ)$%dX9Z!B1^n56F9S=FeFPM6USW{DOf}8`` zOkgR^mfZSblq)^+O0j_@`(CnmP@C5EDD)D!Gk);F#^w}97i39u`#;kHoqY5#;~qF0 zOmIC*vok*tC3+V3H4TD_w||ZFl+?e8Tl|S z@E`kw!o)ROH8vl*AF>ryUkhQvQEQ~Ga0Uk4AP>)(vNl3XJdo{%&kP?DD3W?6U~~Mp zDF`K8$J^FV)rHhQ1R+lrI*6Cc7SD5@?D;_heHP_X-2ni5vz*)2oSr+#+MRooju8PS zgTV-wB8h0|g$PQ6C|wA<5l`K$<3956h!(=~o^fcsNacDluY~P?>&kwiWXwsT26WPJ zT9>ibO`k~KcoamB(~;R-kvG4b0+DwwtuXWC26awVY3+bh)Hf#He)upq-}@t)XUR76 zq3kYsVMu~OujDRe@@;Yg)IT*eh8li}8UsJgAUPrKvb;PvylY+oT2o$sODP@}GI?K_ zeQV&+lXM)83O4$@WE;1fIGKRC81Kd&5`u8?@dz}8s+N;WC7w|xIWP|KHBol#W=X1e zg~NiN>NN`bive{u7FcPC_G1#S`#Ki(G}}5P_?4*sVaEzrAD(nLdFAXeJTsw6#>KMb zpeze%6MWZ3jXHneh=ME!Ax~HCSE7?nv8pTfIwS76Co@rqIgG;F>}K|p)3|UzNJvn( z;9z~h+Kft))c@RFs7#BI%gNL|yv#cdqRP(vc&V5pA$&~PP{Jy>Jir;gd{PKf>Y1Pb z+VmWwTUPSWUM+h(V>%RnI}RdM2Nq<(45I-ps0I#mnN^(v^kO|kTQ$eKFwkGhTmL0} zQ?=C9!b{ijNSz(cM}u!5GDN9qR{zJlg6aK3+H}n(5M* z`j_C~zI5?M_Jl+Y3qy{fT-yy~C7o+pQl3lfV(D{2sEiY9#IVR9D}>4LMK25JL!$;1 zhB?aRXyShqxDgMlvffcM$F7r_ui*k?ssY|3yTYt23FS1lfM1t%@yU4)cDAc$&x%Yx z#q&yZdkjFAdv8ZuuB^X;eMVE4%^w&#k0&g*t0X&5Ncgu;OC>k?lV`Mz`Vx@eavv-$ zf21Y79xZF@UXuNhd&6*`s$;GAIohZw00Vs_3+GuKw5jpHO~tYQRVW8@N)~Taw>y#1f#Js~nHHbrgGHv%LQC?q zwHtd#YFWG$xsD?nlDT>N3mUt3EnWrDAAz~wzIll2U;>~)Z{|zFZP_}5yxOHaWS_{%@BJcMh_ z$+)K1mm=Qx`;pg0Yl-H*E9NV^NgP%~iA%FM=3y%}zx}W^R$VUG2%{0fvg}pva~m{P@}qJX%~81%ws7~ip^-N~kbGdtQ3u1U zHm-Zl#>AsNk_bl6Z!ZMJk@5dn*u6;#Kf$Brl8q!27n?134cw--`0JV$a+D_}jE&O< zS#9UrDFwn*W2%Qe*CPZkvi3&HHawgL46x%M0=6-gJ=?|B4K0Z2JhV+?_%Q-GGRZ2+ zx;BpeHsrv9)!k=hfFz z<&nPT>d3eazXQB~JqS-+P3fj4VwPLdQ4dET(bP67e2J#2pfu9 zV>Xf*FXD2a_N4{zcSxvn}A;!(jVa>yR(OWKTFn8Ma~R1InJSaH`Z>GGAp z_bwdNK6T{MSV{KevCG*a8l#xDGAm>E+8q#INU z4?4bi(H&NMy(Yx2`Kt)Ko0-BXZDc5Me%0NzGI*9ksMg`XCB?PcR<}1$p?2yLUd((3 zuVp?3OR5$emQ5Grm@b{FI+%5~v3l{SjeWh&aO|&F&L!Zwo0}P`p0S6mA9N;_^t29w z>}O5aK?T|vy288k0~<|k%G@fi?}mo^xLb#9?>+)^ewIRH*{nk4?rC^nJFB2W}lt2%=EOWutOYwUT!s3VGFIiEg zwB|8{CNVQ$I;9XQL0&mK@mkx)SO$*-)0x>20DD1j)2-mvP;~89)mKN5Q`v`hL>VQ| zS(0mLubu({TJiEK+T26$SV;Z)Bdi9M1Rix}U2+NFbGCMKN(&UNY%={g+Cs#spGqRR z1Q0d-XIN@b&YKe%Ol$L{pVHE(e4E!}qy<%=eKU>dP?s;!uKlCybo#aJ&M|!HV=?o* zU_kkk7PN#zHa-7F%Cpl#lRG&qvRCmLzQC4LNLR|^SG0vkXVag_owIDfG9Hf+a%v_1 z&%~m9`%{MfN<^3=sv=muFtjR^`P}RWt_Vi!`ZiKGyd~r$FUal=q`)WaV$eicF{Pes z(xyXpb6aYBt?1-cx?zOf=KMev_$xs28ijHS>NytF=E%kwti+SQv7@Zyt_Y z5So26K@T=ti32ZFr+7+~a;l<8B!@;sO_}4$3{vKEB4Ne1MA)r7!GK9#M7a~pox1d& zlD}--J0C_vP8~v1_J+WGB{k7~=7bPz)cM-5n?i7&jIzJkl4@x{{wi24;~0r`bWO9T zz5xj3c9=*^ofNfssxHTjpyqKF;3=ZB!CC_%*lFDEuC)f2TcfG>L7kxE@x9B94Nhe0 z^uBIY5weWi`QRlNldIIOROK-$iA2Y)7N%35>J{KpvnzE1ZS${*vjA|Y6OBDTZf0EI zvyk@5KvzD|!>a8;(N}gqe#6rFS*uFd3L|R@nq{B2v5=-C?8=iqXSaA~dY)74W?CzG zFv`616}|CM^(42Ek_LBhjBty0K^yi;4Lb;#Dws6NL6#_Ty$R$~soelOO2IF=5J8b+ zlPL~XhqsK^TDdm;)UKU@_CDaFjvwil5)KKMH^Z{U7DHDN{O~YQVfE7|5ZB1Kn}(SE`nBVQ9Uj6 z#=S*UtEzAr*FdBWZ>!|W4=letD&EVH#d4Qe_Sm**w=I(jUX{tl*$Ppq1lU}viK;Fk zZf{6br+D&G$1FN$w_j6(cc{-(n5)LXq?;T{8<)f*?$GYKSb2=CN1hMD_3F!9^%>Ae z(6uq}df5ha+E;8l`xjc^dmfKy^S2cLWtZsJksp9Or#eQKv14qA>Z*H^7_bZAX`YsE~rj7nDpk|rfD|%^F+e2?J`z9`O1BX z1>TX%DeEG>8n8k(bTt%IVAi=^>)&I1={_WtadQ+PcsWIl+O~Xvs$5gZNdkS(M<`vrkp>}!;n6VZ`5_ihc&PJvNyYE zT_H9C53dD5BP%6wrX(}E)S*QhA=_Kckiq3d*=#mkuo+;*RjR{Z0KT%qDrvj4E-vVM zRXLnm`c1HDc}# zi1rhbsumDYKv>ST+)7^Vl(E;^VZMEs#HXjuBMY%3p^(ua?{k?}&x-Puj7ICe8U_3u zQ3@o62f=N1F*=3wImbGEECrV5A6hDdtA4W9r6@3mbxEpLe*5;sAjjB@(Ui6%!Z?}? zXLI>y+T%-uq;2pORrPRNWycAE*lB13 zHD#|)<#}L-tDWN<| zNMpb4f@S->gg>h6H_|T|IW|MvdQ~tfQi5(bNRC!BxJZ&MQpq!Rp{3M`fuxl-j6#lg zCh^L5YASLFFNw7kbmtT~zFg>NpSZ!3gDt@wD+gz2(i|Ct_kSu#x*l#3pvJZR_|4SoM_HgU@ zPXz2PLe5Ynq-%b3jz28r`7y z-DSe{K#Bxns}_T7>^e~W{WB zShY1o_icwyM2cs8{=2;Zn=W^aQ?HAvJY?Nbg6f!>qgqBN1XamS)W#bP{})#^M1{%@ z(EHiA=y^@89DL=}CN+PoU1C=BQ@6u0`a0yS<32ZRmptGJC0$?t`=>PmAD=!I_^4$= z^+57J6H@~-{Ksobq}qCB|16<}5csY}>*DXb^;eIAPkxcPf9l8(AM;&F&+wIaNwowT zZDGu4a=Bh_Ifbr-ka7V*c9bqm#zag_jGw<)5spa`>_V!Z$O&rPPNr;SK5pd=_`P(L zh06He8uSPgxHz6)@_1P4;GO3_Jc-7eE^7MnZv{{%JstGk)Mmv0;${^(8HIhAZS>Zx zWT_Z|EU6RlJ@P1D2!0}(8=|n*By~^&crg%?Tf~+Jels=0Bnr9sgYXTpUZZTm*_ZdS z7Y0Wp#8RVc`dp>5TN~v)g>-bQTw(~-7k-w3IX7`ke<9<_3X2yEqtevt?r(7E#D{pg zjq4Y(vA#PoJ|iQajN2tX&k2f{XwVXdGC95e%$8AiXIrVf)-ZD zbh&{ZoGtOwC2n~(@0#I_8X^P!y*135j@okZE7>25rDt%|6R_NAdvgAL)>M`hTgCNy zU%E3tR&Jy2b0^_iScd>Be{^r2Ps6`%+&%12UT8f}IwE^0tl`dt1rZtf-!}8zCrrP^ zYJak!IUOiUKem{}Sa7Cvc0*Z}08skpzbf*o?kAkEXq^?uQ+W#bdNIj(GM^^ZER#yf zUz#2k$~Ku;J)!K+ESghVWlRu5V$Z{rL|BWpHNr&iQaHp}$Q?kP13 znu{6YxisFveQavR`@K*A&E>A_xi;Owee>KWc@%!z5@G&3v}Wee%|F;cLO$ z{1;Yxd6=3jbW8f%d5z?R(idUX7axY3Buk0`1it!bp^vke7^~h!(tm%St2)Y}aD;x8 zoiRkeU{Eo@y{M^k^7?x0ZaqQE*(k>;qN@Yre$p==4g{`k=NyYwFH=9D`_ZYQ9TweO zrFwXocXYs%Kb|_3q#qVkbGt<<^&~-QazaupEGk!}&lEVP8g(&_ zYWJ1trs#-g>SQq6Zk-A<3{JutP;{HNNkAWC&X&7?J-QT)zP2`+zCajI-wAf^DQtG8 zDE2QNP4`UgcR)+ksMSPkdvm_d1G|mi&o@5RGpAbFSa?~{H-+kGS4FLma)V{IocL?q zT;5R?k^1G-uXSJ%2rX26R*y6 z)#~`eA>2Q3rHNTIDvdjYJ?s??E6&t-w_CngSMNhg#mdd-Btzp)$EVJMS5FU{k`v@7*pu$?db)4z{%0Xw4S#ywuxJT-E$GR^KZq zFt1lTv6-&X>lQ)*zoX#R00?RPW-?1+6VH}^i^EaN50Lu8oRa~n2<=Pud@zQy@(Zul67IhMmY;#Kpd2(zFwVK+lhDmrc|j`CPjnc{kr z-=kPkyIBH*nZEg!D3%s;6Nd>5#a`tKT5-L<{Za8!J8vj~Tb_$srDvf2nKY%2WR!j` zIELPvL|UUAJnC+R?0x>w3;{CNg-CrI&o>o`E6O-(VWsE-vT zuB>Mv_j=^w>x@=(0ppZ@;xoLN1Y=FYJ7eTptq9~&?(UmJP1?_Y)U@JyJ*x12QcZ!) zMt;J>D%e~wnPfIF(MK}@q&Uy_fITx@Q#UlW`B7W!2L(PoqAR?0>6AnpA-o5Ed)N%L zE7=65zF$_fol}k_10n|kNj-GpvvpaZyB0ANzt~vGp7OIMrJHEnBH|5WR0S!hkDet( zx73@z3^gSFA+r(GD_QV`QuTp6oe4+3=tNY^ED3M4t?%ZNl(|W{Uq#oyFDCY(fd$I@ zmaubfEGu@>&OE&QE>1B>f}b)8S{OPA+1R_%_=EUNyg$@J9ek}Zt7i$fu6a3Dza+~F zlRNAueFWPKOr%)KdG_1!Ti<-=6Y(y(8s^to*P7IiK4xcp{gd`od2pIiE+U}~X`?)% zFJWcg{{BOxU0z8$8BY{`Q~;_yQQwu>kYAW{Lal5#6xM7N?$?UY*jtf!f|pr26v6G* zKjV1+#Tb_U^KHK&_%_|BG2np-QIcL`o! zdAVFEo+;}5mz!1PH0w9W6Kis;zXjbPz^>nY17^)5Fh!f6mCRg4??=f9>b-`MbZ5Vv zJe}WalF=S$NGxT@tQKJG0?t^q*0Fym^Bo|w_2j)4e&|g5Agi%`_3gjsVda?o7!_+T zMnQsL%zd}R!>9D(!BkbAG+l|zsbh7A`_1J369t*-o0YQ{VnC~K_!LBT?T+O_6evt- zQRebZ?wEXyA!)YTKvJN@UfzdUq9j1bB-Z?ze7U+&BQcmd`N8&D;#o8R| zB()$*N0w9m$$5fN{WVsn@Xgh*Y?R^t&#%=KM_s@gpH?A&dRaa${vrGO5uounM{JG5 z4|A92YvO~nr)B9s-OrG_$h{!hvlQx>KB+|I*Vp)UY%Y6sdCKf&z2j_~LipnU( z*M}Y^0O?xkhrM;uMe~ux3`+D@f8>Ugr4<(|`-5Wqe*6!7uGeRwIBa|{1J1scCG#7i#^$o+{%}- z|44%*e8SMK@Nu;Tk<@GYHmK(#M|;u;Qg;4EXp&)W)M1#=co?f}9HFa{AM=o$1IvAb zgm*YvgkuA)LP?-0MeLIpMwbAaNVw#CahMVRoPjF=4 z3n{}3=_tSyt6&qp0?CB5SZbV)JCyj5%)Y#ljD0NcGNMhJN ze)}`EYT@S~w5JyP`55Qix*RatAN{hg;qUM6*Ysw)F{AoEZs$gkRGz?J)_a+sx7+AN zoBK1A-Yn;(M}5n|^xTPOcqzs7IzF3*u?7f(?nxH%D z!X}8_f@cLXe^2~J-P}CdfAp{juYxuAkk!8BXOJs@`Fs$efyP|~*YvInbhE>6P(*bH z#;@GXjHVs-EEu@SX7&BuhD%qEc>ih!@Io5w9s2P181R!l;@L5yyNv#e1Xf1gfAg4! zGS$#e;Vqigl|*1s9d!Hm{1}$u_n*Hq+1*T1iIlj4C)K->h?8zROFnC)bo)%ur5>hj zY#il%>X)&eclgiL)btI`?>_5udf>bb63|?KKw6~-b>DL7OJ7Nk?CrY zUs!b>2_EQvF2ktdW>HVYSxK~Un*nkA3432@#4j1U5_SF!%GBb+L)m4}WEse_X}pm^ zZusoAg8t|KuI+BZD@8IK+gz}{+Tp)vvfd=NHEqwzU%VQT`hEUHjzQuerdM0{gckn- z9ur;wG8LxxS|^N8N_v9TIIWB#FIX8r&&`u?%2bmnr~lx@_zPe^?Zmd%e|+}Rkg2}W z7NWu=JgYYKQ4^rZ{zgoq@^Qe@!<*Y@X>u>-r!pwSE$+DxcC@K5|Q?rIN{W z!^~%#RnoQm_^;SMljkoH+*m=#Yx!Xf>edGeifT!j6+d38Uyf&nx$g)qz*mc3ZA}K3 z``F$jMKip(B8zNCd+bViKjnO@@s7x+z7e;19@|zkt{DZ9R|S~#EcM+V@sIm9woZ^P z)vF{pKPGYfY*@Bci;F7{08uW;n_M_Fy{lffvFz?j}zWS@3@QKiux7c0H3 z>$TDEg_m{jf6Q9YC`YrqyF8Cyl^!5Y?J$q_Ica#2ewR{avjewyxf5o0;%Rnd@WenB zPSIY;dP83Yw;MEN8Ei*Ir%E?>9zSiWBmeLPx?b+I!F+J$C;YS1GV*BATUjw-wMW8{ z0LV?FUfrKpOZ70saWkX8?me@PJUtLrm;RNtmMR>wm+r{BDT|7g*^&pSER{D{<<^)d z_$Kc@1*K&!syfa5AE;}+!9?+Wn867)c|@YY;|R5yVWe)X_=UAcZLJi zh^&SZ7NTW1dOzku7A~`V={D#DKmv696&7LJVKR;7f?Hv7-wUaN+i#v}%I~kvNA%2! z`HD$QSs!bSk#$5_uv$zj2#hz3hUd9eQ{$Fj)ICk_w@fGi2RH$s(9D?+l|oz*uW=In zH6HKUafD6M%ILer>iIv*_WaLK(GHgZ*F)2ibx+iC$WmD^r|&uaKcwAdP+Y;=Ao@UX zcbDMq?!nz{a2PDOy9IZb;2K;93&CY@3oaqJyIYVu`S1JgR_)%sU+$No=1?_E({fIC z|DLBeT2X)R&L!-4=jw$#1U0Io%2jdgo1~9R(x=gF^ar0QthYG8Cx}g1Txf(eeu4ad zyUn`Z^3qU{M1iX4#}CH@{_>0F`0EcqM3s*y8<=R7D~v;P;dn~ z;Y0V1Co@-~vcN8fVB{*@|meF7lrfW^C(ct_!{b2H7gauu3}iD5EJeQ4uLyFAKGh z%RPq`FWu1Bz{<%|-m}|UV`Rx`dPG@pB^_BkW?AG&P#!X-f(DiI#Tu_ts_=m1LLIUT zBQu`B9tp9O233k~ixZQ)G`P!cnOFH4rQTMTSr|70;9=(`{p8&_g}cb>xO|z*6-D_H zN98%;*M6apb|o;|mmKJt6Hni?7sWWw!^I{ynb8e-hJoDTNjq?s11QKQ&CR7XsZUT# zQj1@P0SC6I#6M8IS$U?uXUdwEU)D*$C|k)`8hGbPP|DUm$p`aG97hL}wT69W0cn+7 z2>wORyD4}0i5lu8$6PvQxo!=!_UDiG_bb5N*E#H}2{5Mw56J&ynrJKo8FGlg_QBSW zoE3|7VwXIpLR|&`FWeN4SaEWTqqmFTbNJl5~HlK&2(55smE>9S#{0JBg{x6pX08 z8`8c+>dWefB@vz?M8p{$^WoNg5GPxQaSZk{@r+sZ4L#+SRwwY+CPbnkc99~q-jaA< z#QwW$o~!oD=OzJz!8XdW&q#H?q>h0i!&1Gc>FRnn-j9JY4O3AaZmOLf3_1|iBeW{C zzezwKv^F9rpK~ja0N^7DI;|&C3ImAnp3zDEvWXx2hCd#f#7|oP-a{y7 zs)}3wBC$M4yQxzb*UE`O4g6sd*})*Q{);x@JHip&GidsfU+Aa6R-+szsZZ#9nUz}6 zD|Pqc8}+VtfeyxQm-r^0)2(HBMJ?ZmiXDFVQx$ba%rgL!R0qv6$E%Irr#0&ARwsOi z@TbvVEQF*7S`35Ezm1B{H6U?dt~8`Xi1CLTJ{2pLNS>lfx@mr0_J}kF$5ExW0ZR)e zhxuYG;|`zvC4pIqzsa=F+Zl6Nzr4>s$TQ2^Tqs)-FF*%!3VmpDnF)^>Um;T58!7Px z62@ftVk#bYMQ*C)wGWfb4fgFRP=U%)1>mMghm^v(?_}uz%oTacd&=ezigQw_Km8Cn zY!TAVWBszRe~iQQPFBVXtkZiGNmW_EgshZ_dtCdSl)6r7gi@jA*?0pPM&kR^mAeUc zIB=QJVRxQHJ;9A3U=3m4ft|ZyJvGn5ait zFu>JP!Kz&ct(asj_mlDO^$$CB){DSA$>SIil&jZH|q?C{xI$nzPc`NpI01wS)Fj$=E2`(Ohr}@HHH<%7im>m6L(H= zy7~{o6PumNCI;6nQKh0!b7gCA{e09J0&S-gx2%?nL0|g46qx%|`zx;|TvTZTUasPd zB-Qb}K1`K?0^M3(9m>E^Efl5OCurn&K_vKvZcRIAvDeQ#tRRDg(A{XVkHceLl)^ z%94NXyNqXTx{MZp{I=OLU7Q?6ftewV>TOev!RGjdsh|I3@cXawDQ?Vh4XHP)QGeZV zrD*l%W8G2TuBzAj?YnsS?;mHN?25HO>J%D@0&=`>nJA*=3sFT<)4MO}>~{ntV3;)v z_9>eO&glHCHsiSjKn8f{TEmaqo*%>RqKxxyA`7XW08|qNS$UBG${(AObnF(t+f*8{ zMEAs%-lNVqZ|bjE#z9JBm;lfyEOs&kAPq-MbR5q25)$V(`j(ZmJlTRZoD9l~{?)~& zjKQeoce=X3v7xRjdtve4A9zGsUB62YeU0yxggFtS$-sFeM7X+8RW)C*xBUpeWCl5p zaWJH$KDpdt>M#~lF{HC2HA{_&$H;}12F>q`*t{3Ywo9FmQkM%{eP1yi)wKs3OO}Jf z%Z9T?JbgafB>gq}+|x&&8VHUrUrg56q@n_ozgAx2@#ORm_2CW}o^G{o(i=0?7uHKL z!^(-C%Lqk9V1G(JAvIKz(`TCnpr;15A7`Z^q85u1z&89SVzta){5l@Z8!9>cT z*OVu6%*f|v!YA(bALrxf)5|G1BT#1sih<8+g$4iVOwK_0PZPZ@N2hXl^6|o|RC-&3 z&+}RPnB&84nNxn68|*Yo0vOa=7f|y`n0KOF?sl4_+J0whLay`^Z6O8VoRq2+CUjkD zcx`Y>RSA<=v{$2Us0fQ4Q6UqE`r3Id{#iy+31!#*7uWx+rmUckC5M-?XALRwv5az} zXna-1L@H8+^ZeD+86ljEQy)GaFHdqQ=9#H%$ZDh#w#l9m%+6)_^8hPl-oqrKz9rcnPoSD}6)2dmq4aFX=YuLSA#o>AxzlfGweu zOBph=Yx$Jc}*fagy99LsL|vMx~=|Vj!Z9ZBv?vJm_7fyu8J5e#hl5v0D-8Koq7=+e+h1=c04+iqgO892W?DpQ!l~ZGq(4S+ zrVj&%glQd$Nn%xAR;#3E4n;Hu-6eMxFoLHSPKMRkP|tTKnxfD0xx%$b>M?=?;4SM2 zZx?XKiAGytJL-e+3 zP#GyC&d=m$`OClsZMkyk{Kk9q1Aot6X-*s`>5Qb?pW(Hz6+;>ye$SYY2rc?!)!7DS zsX(4_E4_W+lnd43~$D^^kr|u!jE}jv-q@AOB~v> zv0S9tkiLUAI-=qOW@O;dMELJZr^YH9bZv}JF1lW{Jq{TZhANH<#*Gx=|Jkuw{Ds8j zWUd157S~qu8jU#XCR+*n;!4AS(r>{l3?=PJeKD^Uh&Xn+k8U#(TNl(#)zk0^?)l=4 zS-nC8>l=TLCv~Ck3)(hW5VrSeVu}k%NDaF^2{2mRPoS$Z!!Mq>fF~$sb>>mg2 zU!S7Jo9(~APKEdmHY#}a&A`d(i_0yKwocUv}!xwdPM zA?xozyon1b8tDoV=Z@Y@k}@NjLbE3INOyc>QSy|EC;vhEr_v5Aj@nhF`~`tRl=O74 zQo zKziY~x3-+MIMj}EQ_Z6h>BPJ7OLy#{P`al8J6QjYPBK}cte%yW(0TJLTq4(4%Jx2$ zO{-C(wBNx1psiM0SX2R@3%~svK?+;Cl4My~I~qKSfr53+o@{WSGev$4|O#u8Y?cAh(qmGwYbG#@ykJiz187RCj}#8 z?IcKVq~nKKv%wgm8mubj0dVLoa5cl&cWeUyUo~kVV3ylxbYA;6BS;`GYCnmu4?Mcg zNpY#GirVe398|eFIcB$d6rdb+B=vFqz*tc}AYURk6%e{O!@e%M{-#Z4>eiwx2k_D zv&|Y17j@^EGFGHA0CII7hN%ZRx7dk?wUPQmTgGFGnZa}Ueonb=5rAzw7$j12QzbzN zh=z}RW%n@Wci?^k{a%is8xuIJNf0`Txw3##q@JMNu3OXT&b1?}!L&&bFk5?TMj$LF z%~V6}%>DvgK@G@*Gk>fo*c5OnN7y#B*ycm3!rW zpWc?`2U8UU%aK&`H)s;eI%$&Cv`?aphdA9}|awjB} zi1~hO#O|=euoiHIl*sA?2CqA0<@IXW?!;s%K2YXj>q}zh&J4=T?UhwZ$%zSk^$_G; zei7F>kCCtjSrhz7<>D1++ZTroqg%?J4vvfZHVC}a(Ch< zK9-Ls!;>}b%4-{t)No+pZ&&@g1khb>`2^RThi8Hd?^1b>or3M}a`A zk4Ks=q_RdhLcXjpavg%{NA)j%epxLzV_rNB zU)XZ(5+Vxw4F4Vs3GTz51`-5{yh0aPn!uTvF+&HPO?$4}7B3w;|HQPBPLr-n4hz_6 zxe0q08*X?&cZzd%3C*Fo@x#p#Sa#$8&=FEeL4n!G+R-T9>99vBkw#@@PPcEQP3oe* z&3^}3k0}&vnXs3qQff=;r!evN?|$O4S3W83dB;}qALo>+!;CDW6dj%;e<%4JE7mF7 zJ2)9{Bx?Z6>vq5C+{+4My|)=bJeqokB)p$+oi4NOH9J~y)JzNlUd;?-;E3t>sb%8G{xcy~IG2u4%gHdPwe6E5R2 z{y}4#2n-2YoEoS|$c?F)g_E>m8;&sF;*r4ALVz zNVcAgA*rZN{CCp@6uPYIR_Cnv1$Z(Fo+~`)4AoGPj@VR{+K7IyGejwTj(EAesha~i z-rkxjtuEp~#L;lMw8(?M_~sUVi_`&Zwr;zB<+%4#82FmH1@*`6LzyHc?I6)VIr8Np}z!Tf6EK4tJWjS`Yj zRcLA`z4-CWr6$*uiNkaLOYq(DhO@f9__9PEPM>l8q8Sz%Q|%{?kq5H+!4Fr@j48+N z`C%e#uIl$k1Q9W^mdAp9V$2^4LZR80^!$$z=IEus=m z11hiig-&sOk##s~q%>6>d~fcx`Bqs39$g5(QzNet!;Sd9{a&tv&ZS4pIN=lLup=nX zm-MTW%y)7*TrFCSQC#{?T+u*h^=(0}SEK{EUx@o$B%v)Q5mWi0{;We-}iI0(ADszq?HF(wb z(?^hmWw5mw3X*gyIuPyt&~h$@tbyHTk<`(RZ%4vA!?3I3!xdHH5}IlGcBK}49^F}A z>>8)PAa5E?rIyh%74r^P2=sn`7Aa4O#-s`ryY&I~E@UFMcIEh)bfTs=pa zdf)lkafObAn9;aS9be_mYy=Z4gr|z)I4h@b!WL%#>7sw*FP~W-1`{Chb~xZCs>|vs zmf1S;OOq{J?lO(0yX{uUN;UeXx@|F0z_e`p`kTbxml?1|q^m9tZaxwpK}F~cc0Z4-wbPK<%GKqzxtN zJkjE3l3j4{Z7iSYUm#P4-VP9hjc_TF(ra51ZR%S`TL zV#`eyDNWgusaajD@m*S23cx+19-74>dE9_Na|H5!eS|t+Lx*gt3g5LRHjCTdnukf3 zNwj9#M0pcLd;!X40kQn@bVoX4O}O`5grg4Uot1$H+ExrI!An%}-5(@R)4eOXY-Tb>z{fX*Lll?f< z^~-Xnc^IaQ77{`99zHzzRmZ7XxOE7{w}p!=wtx=Ol5&$hd+sNvujD<*p4#5*gsyt+ z2HJ!Q8^FJZM{Un0|NS|P1kt6KGXCi7SmSI7Si%qHOFFHWy{+)Mca{**b%h|>3?m8u zyk(+7QumJZ-CFa<*Wp(9m=otP*eG<-Fd9kt{tFWoVP2}ZM<}y-cwCIq9SgAtK(=yV z;j0xfRUG?vb-x^Q5A-90E=N6AOKAZ|OlLdGuWmQ=+t!v~OJuJ3LVWED@J@|WWBbwX z(1MWa8^NZlUlm&TEUR8JiR-NmAbY4Lq6w?4yu{Lu&++Wrk>Tp(X%cDVAp+Zzm_~14 z;sI${j(!9x6a*^JivmV^+4d+y(4#L}Xo->6?V%XTPC#Jr`+1Xhg;nH55FDf)MFn7k zOjJ?ank65|UODVL(F3nG;+xQMWqtmAdW1ST|K^V7CV3`DCwjZrSxlXKWBBWc4PY|} zksP(*+cW~CP$Y5S*?&JFfA-%?Xs;Y|{C~fJTtWE%_v>y&;3(U~d;5X^2~r@%_3emh zDcd(p6O`gcXq@99=6f$VQKTD1R1%lZZ)zg%m8-%B0@RHUfBg_Q}DDYdfA;&WD@AJTr)!{(XH0z$eyn&!zYj3{Hr7w{MCK(O7jQC^NQ>H7o@|oQ7df9Q6 zP5Z#BYmeo?Q@H#fX00HsxKD(1LAFR_(=dNBL@GCr81_a2-QXkNFZ(VX_bX=3t+nzQ zYbJdDUQx)2Mi*pX_i`OYSmN?j?5%ja9k9P$5+*qA^ZYtL_{Ppl1BtkQ5@wLHB#dfz zLm|eGANY!Pr~b!P!1(o3-vugTWQ3FtZLuSHzaTl^?H5~Uu4$oP^>=AILR1-p-tC1n zZr2jHekAgh)R9?;5bH|6Z2058Vk|$cC?_Rgz!lLIBhXbK;z#Y6f6o-bOU|^h<_E|| zm{orYYYDJw-G>!gj7b1FY+m*9dYyfbr~fe2NlnTlUJ5p9c`xR<^VxX?C!wFbGO`L) z?#YDQIGj)gXSDdZUc2<)`kW7_?PnFA67|_1xDvd&!GaUror9lq?5iq<2~`aQ%>>p! zEtprfz!+GTEH5pPSV&A%d&MRXT75PY-I%lHhNHI6h=JwQ?;xl_Rs2F4mPBpSAnH=+ zVdEIJ%V&0-N#|mrH!Xu!PAtWbkHQ==MB0>Ybe7R@g55-Z#rzXf2bxJw?@S!{ea9K3K2{0(RSen4L1S~pJL zLIl(!`++}&N;F_ONGPm0A|dWc+3$1~>Quiv(L}vK7Kp{bxu)@T{wDv6T-^e>8zG_L zB-Zy$Fox!}A@W3fo{@ao`ANwCkg(Nj;1rof0hEgVX0G}hJn+~A0#eeeKmLEzDp?Gb z{8$-E_(*^UUe4m#U|wQGlDp{k4=>B^N_d|g>p{xBSWW(Pbu@P^~Hq+z8{; ziV~stnZ%~hKv(Lt+Aw2SRNF)7J>l@FPvw?9-5_sL(v z?!e-oX#9tb$^xC@^eAF9p?>lW7n9xP-VsS@2@d|f#-P5CRc&AI{s_zp!Y)y&>`a;W z5ZcDYF^+0(s$(x59|(QAg@@zO8Kd}o{g$tk?@r@HKM%dQ% zex-IsyJBuH1q(01LR9K3g7U9aK#Z&8=D#bJ)yaUW@DJoY(4d#C-;#7%3jb4vs`Gk) zH2`T5^Ac9Ynn?v=d>5i6Qf37DU$-Y{YVD>q1&st3e2d$K_5^Bc z#oT7WhNZkFgC1o|IUR?LN*mak-OIAtYZRu#l)1f@E{0#99T=haQBd>8hs9GiL?qPnQDJ!#0ZyC|eJVnUKeQz|#jsC^W< zF8g3)pW?`S`!^iTLnA*_OFJPX0-=VJBQjZK$C^};&o{UZ$LYwxInHg2D^9HF zpJ~dqkiI4SM(*95Tvxl3m0hBDv;Sq?5e6-QnuT_x?>BMB)lH`H7sD0`+VydnYgi}u zs;M;-uMx9fiVafXQG)FRb$PX>2j`)dO#48s;nj+jS;BFr?_>N*W@f@6iFJeS){2=r z7YU?@v(=V_^)3$6NJ_5FQY^*}Z5v~fqmi1I=L)r3<~LtB@cgKd<-^Cslj5!aS`QSZ z;?_88_{j}$2Iwrg2W+w?J=E~VN^!HldQk6?K6a6_6as4mYfX)DEy)61M6_XIW44!hVdcoJBNLh2Spwsu9K%yR|% zC%)5WyAwv^9;|Z^C*$W_FTH8#l{bk|*y?8GI6C1rWK4f(Op&To)i?E65vShzf$nQnI1EW^u{}x2`z|)8dO2CWA2XLg;-s zJst@B-UPAcaD+vv*w0d7Mus_8NYFH}v}d#4UB?vP(zgCIE;SihJrAhvRy z+sH<7w?wx3hc8F;SCjxwR|$1I&oA{_q1|LXq|UNgwmM(nG=8F1%b+oVb=|9UktlJ3 z_!CP*SNqnA=?sTe!wd=%4)>pkGw!P5?3l-k8_Gm95jm+cLQr5{TRx=H2pOLYIJ^Q; zJP8x!r%ulg78T{uyHPlVj1Grd?}L~Sg{UUlqGmisMR?$M=B;J8!t{y|E_1>Q+7~T0 zR^lalALS4Q!(Xe7^h&vc|45jiv_62Z^U9sCz%ojQy>(Eh-GmoE^ShYIWQFyMTb2<0 zO?7XO+zL#M(98Oj^ByP@{CX-7>iN*AeH>#zk)m?Et5GqeHexMJ}0k z|Czuy(?`?G7$gst9bdc@yb3l7W05*f^*9tK7SQCsh^M-vkWvABz*BZjJ3Xv%;3Iln z^$7j@!n539MJ8;2!m&YHc@&1c>1c~@wbt)%M+xs>y#q{X_8iBWHbv@cT7ePK36mRF z6i7>B#7>*&Lak? z$(ehzWL;f4W)E3R{I5$mfVt~lNwomwV`VIssQ$azHG9>-FBH!UR zzCZRU_q=HmK5MMYb5u&g+_~4E)#(%mKsCx9fcoe(M@nXd0ZQb3LgR~|w9{R-fgBG~ z^`>#(PE701Nnw&xHO2wM zzlGSkE_cX8vqrCYjig&cnucC-KKuTbt34iol=QSqg641&!DF|{g#WYV-gO?RoOiY|>B*}xjNZOD9AQwR(@YUAw2wC#YyLN8{~YK~m=5AUR~ zqBE>escaEjS4c<2m(|QMu>)RKPAkbu)spCZtv@uZheWWg#|2YQD-Vc@U$&PF1*T% z`uovKaMu&;Z&nFl5RRykOg)3cp$E2r;T}~|-0BfOP+r{VC(?x<2zvR$fLEBLehpCA z=!xCXO`8U>KyC5$Rz0Ws?^F%LviG$on{<=!2w_E$LM8aM492|1UmKS8Xm ziYJfE3s8zu7eHRI8Xq{jnjb;*`L^P{hQo(3y3uE>Bv8)I=}h7dhX;0hLk(Ihy!>wa133=D|+7 z6ow$kL-Le)KW68F_sZ-N(@aA5BJ@o`OaZ;r<$T2MkNo9=iC1WHkOAqIr~FY{gIO<4 zhEC7+{dhUTPd8M2G$-)dR$itufO?_nW^iliDK1$1GbY(n1Ds(nAY*fIcJY?yMC>Oi zjf5eD7%zF_Nm#-}ORjt4WjgPQL{_BzM>MwJ-B46YK;MB=I(fKYes{?ZxQ${;;fye} zFaDx)>J;7W`|zQQKwe5*OK_Ds&*2M{L_iMLhJz@+nX7`Hiaj9Fs>GQh@2|u5?Zbnt z$8i>;=Q52Lb2V%qaN^iGdGm1!!jVP62ttDNSSVl z(KCIfeV>y%Z#r#W|F!>e&`D;@$Gd9Q-Nmw9c%p-x3Mxdt@~=e%FX)feTsIS5(#*+z zu%U#vr?wy?_y(l27RaBSdBW}nXpoR&AWGco7q^z%g{rVtv z$Db5doJ6D9NDqFEW+to=fL>}j48#-5O2pd@93MQu1lu$vCBe5f=XwCX$Cn9X=*rPf zL6QfXiE2)nVIXL#nyR7RKi^`s*N(404rKePI-svK`<0poAY8K`xo^g57NTqY2#-{`f zk!Rp0WEMKkYquI_R6g?ZXW)W>taExFL&9#VP7 zFh6mPsc~*HMw>sIaHWzLA%&6pmlQMVzd28}^6WrFM$qz@V*}?vn8ECf+t`)Nn^n9H z7p~V$tm}oT0@Z#1UTneWp{os;5x_$d9P8SOSXxhgQvSO>Aq|AO=k&VL2ry&$AmA|fo>N~+i49!HL;q}bd?KTC^f?CT*K1vO ze}C>~f;3c7;Be=UzpT`*douAP#}m5lb-EN9s%T}hN|TT#qoFDl5uwvQDFj0ly{Fw; zL}XgbS)>Imz7BC0S27!d6Mp|>=T(MG1yzRGrS^iF0v@4aZmbV^oU>PCM+|r1!pC;_ zPh_4Mi9?6l6Y7j|@AYd;a;RvkR~#nfM#0wrZ?Il&FmkrXtYeAIBOWYT_61=8&@C z-|AHnnu`$sD%A=8sv!!=Q9 zC(NIVO)QAn=%fPl+PqO~8pk>H&#bHPGl53Z+>)?Z&z-!lkw0!A5FcAa9xKGbWQ^W3 zcx)O1?MeJ(nC&DckgsQ=wfHRaFrWIP7=nJWVBqDdk_tI76fJ$`7HAnlX^9n*r{*Lx zOZj*r^OF;vv7vwTHd1ATGhut%&M!wWD3W>^rqKH#_6OM{md#@k+~YHhU2WAnPH^GH z@|QG1e9V7}8|uzp zk^mWcCnmvolW_PHI883x`~d9KWfjzVD}1GuCyXQC${Jc=rH~25SOj0N!RDWDMp&j@ z;-1I)koGe6uf6;?P41@F7`U#e*@{4sVTS$R32Ez(SDI+cHwScIaADOP?8=rME=FS7 zmG`R)Z|rMw>^l(%XMZ!;1RoG5{FNYqBI#?1mdEg0wS=>q^GYevjYGA^ERQ}T1#PkR zmb-Y4PDx=fK*2XeiL7{>KZvj3<0!3{z^)3G91V*-fWXy-uGXh*CniVjDeNZPVKAI49!1^aIVi)%mnGQPaEix8G_zk zZNAKDy4dQYn62ueSo4XjI6n1uHa!yJwKVnG({R`_Af%x81+RZFOE}uT3oK0r%#D(K zJU}y-DbDt#N(<~Haa!{Fk34Rbs25Z}_;qt(R^@%Wpz3+c^S2necCPl@Sh6fCnA6<~ z5+OYU1TxHUy#5;u*xq@C=>;l}VQQ7RlT8+KyuwD1^n>$ny)rFkN0Fh>x!h0Hh!X%v zt|iWvscb{uN`qsPecs)Pq@b4+u*Q-vZsKj~!-MX+w-`H!IeK`n^#04T^QXmiWy?5R zYoY^1tZ@jfjgw5%V=E$p^%7q3uz)N|D9D?mw-5M^=t$v=?#ssruicvZxdxPKa&m6c znac82*$YFEA939`c#7hwiNoTFY|a+QSgVNnltYs`o&Pt9ntn(VgjvUd@~%k|Q>5b!4!Wi6*T&CoHIQk`WvN!YdmuIkGq%{CWwO#-rT#Y%>* z=2q0liCqaK$p`{`bj3gSu!P6``^heBBBI~-F_Qyhq|a(EV-2N`wCRpX1fQ6W=Dn?6 z%jL--U&5n|84W&HS^mJ1w@%)(tLYI6BB6Pe*$Te75l-D=(c9H5wfD_qDk9BK?IQz@ zy*P!WaM+0#}`x;BTR_+kqSR#$u5|2wv0J zv<~a-5ySN?q0L_9@Ab$;J~hJMJUkJuj8EDerp$nJz5sjrkD}Yq%bj}6{X37T1gndZ zR!I7UkBA*Jk)Doa&LX6-@J*||`w#TnjoMTf=N7cLYRbB~iqQkce}@R1zv@de<@wf% z9CHGleEN!qX~Qu!^G?D-^nvohiE$V~x8)hS^Y%!@@VY2&pvaSu67Rfnddm$l(ENV} zO(X~~Cf-=({bU?Y`iWju(gKBeDtcFy22#!GleyP|l-!}8~%bl_a z`raGu@JJI~`pJgeckY662q<20ov*6S&l{%~B_u!@HLKE}%!-aa=`Vpp9C8y6dOu!N z+CT^4eA-!*xFx(~3em19$F^D<&Ue#lBd=mm?aivg79vrb-C+ruu2ZZzNf;-}CHgq_ z`QGYUVPrW(ZI8P@WI2@Ss`kZi`^_7^Bi1Ms#Biuj#|`27*VKjpZn&ES znWE3sA%(g1^9gcl>cGn5uLvIO^#4`sF!Ia8`#DRtP!j2U1pRz*ef>h)9+y?omg}`E znS}IzN>#*@0*M28mE`jG8Tlf{Bqja6P-aLa3~G+wH;zTj510f4j`iz{xpUnuzGd;; zh(`f;AXap&)b_au2+85`HSd&_(-zbvv9oU+jQmIKj{Uq2*y_eAz)_+njQr?=rxooQ z${v|dxz%TD#El8hpkT}@ZTFltwM^;s3*u;V;!DbZsilybG$LL8ko0&CjM4f>cHxj| zF)YH(b}$rCR>$wr!fg13I`Q0s{^M)cegk_Ge^2EL0z-;)J&^wv*BMHqcg=)#Lt?i7 ziP8}KB~oP4pEW3))3?@Rr5OOEWa4(D1Wz~2ObsN_0=66lx8%!HN*(l;VFeIA?%sAj zAMW~hr03JrKSzqmQC>lu#L%m(K4o%`TA!0{`8ph9ztfT}lMm9cLtBJ9fHB6!mzm5& zHGq}O`LtrZUqyK;e0x3|eTioOs5=b0l4QZ#j`rV&iC(soMKQoNc$5X{sHH_$n=j93 zX&BpGG({Z{jLd?W0L#;4cKxM|ta59U=f6sMu|{mv%rI!1w&>|4htfFE`DDDnFpghv ziS+m{ln9esAGKZA;t`~sR83bVel8OblrPAm*(UpCEm)_dsVHVpctZRmI8d{ZG? zSed?0k@tJjHZ2_mr_;1J{0(Lsvt;f~n574mPw?IPQr(8e6Yv|<#e zx1=H1v*!aLn?MA!za3&HFSdzb8p}LIqciUClyCNO6l8)<(dizC{Yq>3b5Q$KtaH2a zOc((h4&$AwGfVPRJeQ}clKL=ESe~BNfx5GAM16>E>&aLSVuP9w;{E^ z;tfr0f;NZEgvK|NB8(R(>{G3@;s97%-3Nn6RX^#_!n(ns1A&?C9JzJw=U0whX%ko9 z{wd3t&HoQ&nKf80uq2#`iq*NFNrfM#oaRATXMbsF@Pt9UP1?~}GmE2EmZP7HwPkZNsPa}z2&MzA@52}>_9 zi!S$M_@hD%sulmdrDRQES*`b?*n*2kwP0Mgcdo?pLS#SA4jJk02(H20(du5D4jzLzkM@|da62c9VVI>gKDsC6=HVp(m3 znpj(jSeKWIk6>BnA+dIhY&P!1 z$Au<&(%bf(#n{&yX8Piw)lj4+2x0<{tQ4aDKrHD!K#}UG&66k3QxZ!djeqxJ0NCfK z#2pO4#}RwaLhV%2$Ww2tu$R+Gim28E2S-Hr9fMH3xY{-*`*_fK9c^v|8eMRt3Hi@@ z;o$04U^4zZ_uE`L$32f?W0y~aU8Hy{dz>TAT4YB{YT5nVib2tYr)tMp;8~z%wD)U41v?Z8{oXlZ->qVg zMI-7zSXA39h=YHUi%DU0-Wg1Q6P#ODd8M@ zlV=gvlSNLp_@8)2#Ljtxc=joXXJ?hgxOQwyb^@3WnxCI)F;G^juVkw%PsZofKpn42 zV*i_Q@oXoFf``4I-$Tv)-oHK|;J5t*+1*wzn@;5qAS~lf%-0GE%!mG4Z?yz13(5Jf z>Ug+kwPKc^clTDyegnAxoto2gH<#e*xV{0M_~|V4U?GlQKAX=MnRFp<)R4zL)1Bbr zM$_5hj^H+}CiGLKK78DzQG7sO?%=~b1C1TL95j=rY=}pGGd!E?_~p^E+USU^5nT|B ztg&qGwN1l;;F*r(R>wU|aqOcUI#RFU0qv~a{|;ceb`{Gb&@R{gkr|k)r+qq6|M5}s zUzNse6U(?&)HT5fu*pH@R;uTeKr-8A@>tRbRWo|bwDv{Gt)@4e{*>jBN88?acSVn% z*Y9lqT&A9XHX?-C#`ostsU{gCJdP_E}v=3imcs=U~M2g9oiRZ;n zD44E#r1k=g&5ZfcCXW)!z?ciRd>`_gtT*Z4?V8W`qfy_>=(AKP1u?zI0##T9z~8=? zg*I%vGW#iDKqbHamx>nnKUFj;^na`93~Zpl|J90~mwk-+pk(DyyrQ+1adB-IeGR?= zZ1E82*w?7a+uFiEWWBYq?0g!rz9Bb<^-H76BXaMHD#gF#X8$l=zM?2Wqh7h7W>O=9 zIY~w(3t`)IGBK(?>d94Je_<(pQfh=xgMzN)nyp9q(kGr(1~064)bwBQhILiG)`EF4 zQ|v_WdW@95-^dA+9kR^ZP@Z}K3usC4;Mwshcdh}8P%RlEP%?^I%ua&K)TH)bG8;>o zUie{d9pn0jEkkqcBo+neGUrL--z{wzH2b-8iDwXW#`nsTjtC0EY@n47rzK-5YZ~yR3$j}sL}n3N_y}Y!%MWE_Jppm zi0IY~8eVDB!08c5NXND>b(IpNTr>|F7?fJ%Op`Gm{|q_8@`N2R@@L;ddPrj0Z=uWB z@_6oR$@E3%tZOEfKzea;Fh@<6I*Chu zHRKCSOw_Og^Tj-0yU26!P=eF%Iij9C}cc%v%obF11q%3Z>Udw zl4BcHhuO6{l`876UqY!|j7mxNb-&hsF{sywLZZBSn8=@{(y7!c5g9sfOVpIKOL@^Z zubB4DMN&+8E=MZv2d6-b@sY8GNM2G>nEa3_qmXj>Z^df9Dpe{M>mAi_*c_v}WdnQs z^)F0VWQwtpJ)A-_`h?wR+ zvOzw;;dYe_NEeu)S?k{X*y{EKV%(}$Fk`~O%Kcaw8^`SZmfr_;1A zhLbY4zmtf0eq-ukhLPKnr6z)dHa;HEqEF0E-beCaitYbduWQK|25h{A`^0Nb)8DAk zQ(KC}ZqZhziFDT#>Vp~?`yNgKRAUG0Ws}a&FRzjv5qPE$*d8ewOo;S>W=xpG_)OvK z9-^CwzcZmBCybzo@h}>`KBS5hb1J3>Br`=8KR z0x*os76}K#+a`VAD(pZFTtkuH!NFrZ0O*S$3f)=Pgqh5%R=+PE{?syKuxo8IUq(`~T^=oDI%rl$O?nqZnMt2)4d;D2j^aYr;O@>_4Ag^Q5=c^V^+s3! zqQj-C1@Hjl>W@GM{V+y+Pcqk*hB7=|`cdje~?G+9)rehJ;x41A&Z?^|8E5#v40T)|S1XmjmU-Ekj z((ZS?Fht$)xeyz-jFb$;sAAZ;YyegpN<^6V1R6z!IX$_cT=k4$brs;flW5{b$=V0u z$&~)eFL(;~Ru4O8FtCuyNT6@V{-QE*deTrpjcNStoNtaZb`&b#1Yg!dC4C4)7 zF@882Xpyh1TWhg~!{`31yT2N0)QSm@#f3jvEc%t{bqa{nz&(cuh>`d6G3Y-PCuqLii!t2tI*WMuoatrJm<1NY zKGzQdHf{)D-q`>60s2d8|MNv4DzxAK+qVNXE)Xsits?(i6ZyfKLIvHu+nx9E2pv{X zxD!r3`sJ@5%1eM4IF+pe;-0^~eWR%PHnP;Rmjhy|ePP7hh6OYG;qiH@LO0CfsVONcgK+F5y7zHGZ(D3InqFJa1WRGJ6_|H8sJuPYZ zVl6r6)q!nSvLr$`5I&>nAK?<5%-SwMd!SFek z1+5tpQK(-4bQidi-W~C#zrH2s+fU<*xa%WOa->7on~>+KLoa!0AB&N{QFvy=>Afp z7&2=88xvLU3#idr3}AqrQu?)jxpP7)dIOD=(v{0S<6_d{O0bnWkE#O}3bkcjD<|ZE zAp@jWyodzafi!lrQ$E9u>hIzZy=v;q^M^h9@&iTB>%9#;V}Z{j<0q9f+z|CKU-Uv9 z72SqXI)H&)q}SEJDTXTZJHh5~`{21d782v39cD9If7zYs=D5M?g~ls>6$IsBV-U6R zB7AY!qruh_rlxh!peAOd=>Yrc1J3;G1Fl$T)&=np7~0+ z^VpbA|HxBWPtdwE+M|=RpSsQU&Wpa3xnlu4+8QvQ^Xd8~U$wpB(ZBIBi7I1s$?JD#PxoO`4SieYgMc?SD}xG|~(|)920$SaX~% zN(kaMk{nT9xA=JKgJ_vZ3Lg*dpmeMRT2qkQ!n&2voV6(_H-&4BDU;5-%~0y+a4NR| z`T$)J=oYF&i~3NTC$V+Ozl-5*Y$c)Kh4)p#-;>ENGRSEv|4S5Dg#3$n|14%Uqvn>` zG<&7Ikq_Boo0r}#pBFq?AR*=lL;Y5?f1jOb_xU3MiRh6XWb?z$^qKx7IDjadmK%1i zH~v#1dg#>H;}-TYF^z!A{zSut?HU|-v@Z(oPt{f0yD}36P@rX0>aaB@n}!szqn$A? zJ#XE*w{X~5IE%x47|zY-gG<=Rr=884JLoIBx@Egh=hUby6WqDD6tS{iXQ5FIEs_e|bbB;?9%AfT9rrPxVCJa8E#;6!}9Yc;`%f zJ^6}mE4|HI1_7_`Ppao6=xA}OC%7hE6bZniZG73_y1M1u<+1D_^tPvBYESZdZkUwJ zG|QWLX-pXC;;FAG2is{_m**;96u++NTzEq1ybtr@fx!)>Z~!$jd4EKn0=k&OSgZWH{yJ{7$ht{4g-E&QF43dX9g z9h6~2cWS*#gN4mHolaPL2W)`Z4rI>|pmOFftW>W$WYseAQ#q&$sDjN|6JOW0ihHQT z{VUwvAQQN!*Aw*?$yW201p2?6B4QM=>{IOn6#pi+9mKr)6y)gc?}xV2)I%j174-=f zxxTzwaVcKPIGtpBm7t}PVoEO0)R_S!Tbl*?XMGuN=&)nl6+blf{eiVaY>xjd=?(3x z%GfJtFvd-5uB>X0byd7Ifxi;Ch`qdHLcf+w9=IsNv22o_v9O>vB`&M_?iJTi{+v&s z6B+aYW4`j)<#8GZli606WWxgyKZF%>l0^XrYS9g|ffwuK*k_f+3iQwmeS^c;2d4}R zSvt!!6v{QJ5SP-Dh*8=Apw3Uyl_=re7%Al^2eWs1dSb*REs?w>&?5ax=rslPVT*%D zjSHcX6GCar0eRIn+PYPLTZIVl zBA%tMEYn})=2}h}u_d;vy%PVF!^Nmwc?>FLug~cMn3t*|$jH&-jHMH~e~j7_dC^5; z7$)*(x@J0BWVzywEuT790GSB%JTD>dnV2GF+{hXTW&ijmS$#tq>LB+od#r=+zwNPU zU^ns-DP_*5F9g(5+uEtOxZ>}T1l13-?Z4#sGRqMdnkk{nHb?e`JD!>>q)PlRvbxTd z>3A=C&Tj}`=z}ysR=4#y6aNP25Zb3scf+{Hhg44=-1-jO4$Z5L`M2{huH_vi0-q5<0HdYywT< zzzakSdmV*yA1j-9&Cb|V>k2IX1J$2sx#JRMf#0Do0}!@WHEZNUv#mJk38(dV4zSY` z2aEjBrFP6tU_9u$!{6t31Nl)-QM}-_oiT}wk9HxbA^g+5g25X66WuLa{Ci_@ZrM$= z?EK@3Mgh)1SCq=z=iMc=i~{jm)c&sQQk zZRYp+-1A~%$>SQ{WU5mBcU-PtcR};xxbS$T`2Wp#tXv@maMKx5(&(s-?vOthV)e>a z?AZL1ew;3-+SU02y`N`7JRauz(w#41nl*silm_`1`2N)SP4C$BIwe8Z8TZktS;gWF zY0T$=>C^yh!6*HIE^Uw=aT003gPCnu;s3Nn7X~IH7`iZdI~L6Qv7A<~R@QK^b*T4RueJ zF6h5-Xx7E3E!cnK(3^(uT7ufKZBD~}^T=;(hDD`L=E7g<+>W_c&L3I_Q*H6;SjT^5 z!;aBzG7>D9x35Bo8T&vc;jj-A)q2>Y7%*JYAtm%A=!YjahH;SW% z@ehKz>K_EN&?~_#C4GQ{ex-r>PV!m-^n2s{)TLN?g0L)rB}{{Luw{U*bmv^F=T?v5 zkeIW#dPrjQi)GBJURl-SC}!rfHGKJg_1Wa|Er~gO8SHb}( zd1J8~zGHjr1(=M1i>Yuuf&u)tAZ@R>ffDlPY{G{`QA1ge@7ak_8V9r4+}lNTR!Bc* zOqJM;N{k<|i`)Bv$ATwZi(YUs+i{xtY_tY@*Pte#!TW_!=91HuG~;6kpJaES<)}Yc z`aRmY^j)4m6CJo5Is(AF$(2&0X}9ol>#d2+Y3g6$dkYx5{%!=;7SX~the2}Dld&zgY}(Ko@BrG$EMGGXS`3I!;p&7VjCQVu2| z`SL6jLor`>_M5=NLw$H&xAKN4;G&g^XJiuG@NxyWRYCWBCFadRb%h72DZBl>$Ken2 zXwlv)h02TLD`sH>QC7xW(Y$!OFidM|4OmJv<&n(e`~tpiVrG1y_?*Kk3zyO5{v!eZ zfQm`DBR;0-31*wL!A{ule%`5aCVL7DII88Z?6ZOV?yyM4OgPY=UUN?-qCxi`OmPnu zz!cBd{bh;~=}Q{^Ld6opRmvs!q(TbV@I)@dxvx<1YGR-UTF@)vE3PSZ?rzGnlRlcB zDg-HC=>C}xtZ()M{x4AcJ#WDhc2Anl4GaDCqf65I#=u9lBJMXW@!#qGQpJQ1U``6x znsgMXSye{#rmN>}9*V3*5Fij?te2rTgAr2u7;RY2h=mZCn6aYD+`%5|G3E&T#>tg&4wHaFk4HQ}`fYJhF_iog|(jBSV{K~pc z&+*!#3g=Szpf2V8tZ}|u%8^BJ?;|zNW(Tp|;XH6Me2nl(5}55jsPlqPS2lQfhCRK6 z+GI_r^uwS(JavRA)G4<=WaMywK0HSt4y@&7R0!H_LCdNYLR2ryBQNyi>F$YgER1<< zQ3a)msB&oe`rMu{5+eAt8FHGzRvMVdl;3}*|EN%kpYCKKLRzr;1;Y&o@1~@lsnoN zc+i-gHS52v*SSLM(6~@={PbpZWD#tm<7DJfOTV)b7Oq8`2#QU|cHl!P<@WSCb3z1A}1*2Lh8#8K0e%9adpX z4AoTkcL9spvG-19MIK9dJ{roWCC7dl!z{v?JM|}{tgU)2AbB=))Dwa7p*80LDmO9T z(O7~r?OM16iWRZzjIS4VQD(v0Wk}sgIyd6+E#HPlt2_`Yl_j=oQ3R+#;@Q^X>{o() z3mV}-=16`T^(-Ll1=X2<^Jppk1gz%I$TdT?%27y(@lct^VYouFs3y8W|JlDyH#RHw zHzB_6C3d-5!JpZuPv~=H>43Wbg%&XZ<8UD{9U!eSj?0m~gfY29=k0$_Ke(10;lLm2 z$S8@zKrb%-u+mE{@75V9^Vjq{m%!e${V4U5g%Kp|taDj3oxP_dU-~Ur<6s$RB*odl zvtTbooi+C*BzT~^@e@s&;`O);Kk_xJBL$F)i4SnA26O{QHfV#um>JKe2g`e*Bc&zs zZ&&UoTsw({l1|1xCF`|g+C&d6Z0 zpjQn;Z@h44EoJgHSbg(4`xwj}PbScd*LH1g8$PFH|EQlgI)c42j1wZ@(86-yntao% zq`hVatCFel3i3|()x$#%67yh7qqgP39MoR-Bc-itV!+#f#piKecE!SYVv2bBMR+tRzGV)rHI`KgaTwH;j@fPn;gF79aDna8Cbdf+Iwz$(i$3y7 z)?PJ1j7xIwlA5e#28vysicGc0bd87XYtfpC8gLqEz8ZI_z&%{ky1C!vTS|SY@Hi;h zj8^5jIds1t_4YVnvL!kvQzVP97xrMH0n}8dAKOJOSptaK@d_uG&d26en)^jW>7B_c z3|ZpJ!1wbq!pVHTyvQ2+T<1p08;T)ZAzb&pMk$XxX}%JFDZtF=aS%%c1SkyLFxz+? znsZoS&sM1W{qYxbbf(U+ z!xbT#i7F@vAB|#^0swa7SxfD;%y z41#$$PcoTQh?h_ME8Vl|d06HMgN*AttAia`oFZOlX0>Z!dqa6Uu-0wx#~(DIn5D1& z-Cs7ip@jwFawlLdad)1~j*N*eV@!gk%#i@aEQS=er?uq#^)>J)+MD#uYL1d1Xd@hM zWw?JyW52`5QKCCtz<2f_{+Lr{#E#bp9#2%~_xh>I7N{wxF_rLBr*l3|lF}85H&6)E zk~ld&4&h78T(d=DSd@(_rA30Q17#Ti7ypQibWMyIIE<;$Jc`i){tcRiE^reANlpvd zKX=3_{@%peYY$6ExJkhp!A9SCf#1l@35S+{!`zch36cDe)e1Ue5{7C55px{Cv)@Pi z4a_ESVm#r$I&K3{M=Y4Zi3cG-7X$&QUPaz7<+;(vRGt8|w%yrg!k$f3kdWN|q3Dih4e-H&c>{JTUQRlb~`b`mC?#GicOOq{pOSu0uO3**L z!*-2q3TuC_U4FU>&FYUaa#I*unD_eCXam=W2k2y8xJvb;7n1?-_kKgpYG|Lfga9(g ztMc)b!7B3M!(ywlu2pTL?Ud6=?HM^$5G#APO8J=w7jhWkQFDcH%M#zhG?Ga#IHW&J z@ZFL~Dnu3;!6+JIKNlJCwydAHvTsYO+r;dW-Bz=*{+Rqif-#Rm8{oq@GOw+1!%Qv7y^Ujd zkDD0b-Wi!>?W4+Am#bTI;cSPR3MJ&43jUBc69ct(hf*N?IFQ6tL6iRTOF84Im^_)g zKF07+TcAZSp9Ni-;82AXQ1aNnmF8;kbZdP@V=-7r)zM-`q>rbnHa?ZNWeg93%xRva z(WHTv^1TIl@~iXMWkzESUE#zGy()m9DPIf~r(|&8&wirrkKnfh0tvVqdH8T4;@~gp z?*(+tgJxpe@5?~aq9>tZqA<_8uJxj>Z69H5lB2M=6gK{?Fi#)iXtXg z58gwqNp(rkHQfpI#=q>pGrO|)>wq>QeR6{RV@WmxFP%7kjX~;)%bKOSvi~t3qg$SH zHphYGM{;YdH7s;c*G%gE%7NVUK1m@}C*a+Ur2h40AD03uk&K=NdNl1ZU7U_+!Vn9J z;~I%<0ZQWMLc~3EB~o&S61%(f?A;C(Hv@L%Gw07w7|^mtUtPY4ktTk6C2fmdirxbR zYFG}Xsx~MJ@X0PcN?5T#+=dEy!Fg&Ll>qIc{~Oca@wh^QS2%ReW*x7x*<0cg(kQaz z80I1z=Qe83p22H>5A2D4+ghYhbz9KL3USvG zG$$4Sjm*tf5d`k2BEGtb7@%D=e#F47ZNIL;`v@p{U+=0iGn@ih9p61x=?%J7;sI-a zoZE}kYV=2kL>h&`htNecmy^Or?F!fA6-i@ zH5`3>R3&M}kK9P=H*r{(>id%v)}<%K4C2hR673cU1$^w-{(kdA6=3>RdC z{XUR}vio1u?4JmLnuYxR#}eC``=D>7z#9bpcp)A)`5`Kn(#@>ZDQ$ zyMfnlu#ts-mT;5H@yA;U1wqJE+@zNZkV7*gID}|jrno4P3cq5+MO{FE%a;QwWSZkJ zhU)@&d?RW+1I?J5SrP#yBkHdT0nx`~O!i)f#vB%&)IcdjXZ<+v6y#QQQH^ZXu3=`4 zt-;Iw^bZcU_}k8rSrPyMb-H1EjqgMU+jgUNwjWg=jv(eF*YloM za;kDKR$bt-9iD2bZV6j664uJDy7>D-&WezdPU|(gy(FL@C4GAQxYNTQovvDQGm^hVYiophstt`hQW~V zbL2@V9K0bzwf$EU!>0k@L5SmB%iWHK0bHc-t z?a1=4FB_~sH6=(^md0xY=$X};8_M9fS338i(J^|^OtV5*3yExff(pXPdzCctIrxnr zicyOX_TCepT%&aZIB$Olfb%}0ibCmP3C9LiMF|^lSunCniDzD{A z5(Y;J(=l5x@}QB+^ek=Er9PH9_1GC!lYM$>Jl>P*7=aY7w0f^4RmeA02(%`DL1^=P zm-!|>=fN0aLrQHFda#0+gOd%B@InK>OMt)Naq}BEo)%U&1tWFHuogq<6v_4zSaP0A zw<^lW=%El`LIT>2Lo9y_vad=+b2n?>`QFyYOZHb%ru62@FxJ`Dwqhb)AeR%Jg3B1| zBTtE|C--197A+aj#dc*uWyhA_p<<&5sgV zz7bzqA7_HS#eY#uz$T&QgGg#{XF9a$Jj>U2sa~86VcDq2J^Z7)JRMh^BSEJ^b`9~4 z!A)q1ttJyf<`NYZ&JuAJ-0u*s>Gjl~?&WCU{I@%%a^~L?TE(;$#3PpNXdYaP6TNoH zQ#E#UE)BLmu@B%|Jw!n$&YOO)=W6;)i~iYf(AQO+rIH3;egub-0)*M#D+c2btKeLM z_q+)mg=V(dkBD&Lfi8n2lY(pXOqqFM@d>h)R!ty9fI=vA6pwXJPb{ItPa=gsP#y>_ z^QBT)n42(7RA&oE1+U5(?G+o^(TabSIm1OzZ^7#QR2Lv`fLrvrpf_IK`ppxOsbmG5 zqtLmwU7pQfM%CuMbgCDMcUGFEznpYHEX8iVH2O-zL7R%9e& z?4bx9Tc!%*?%E(w09uty&6Acn8s;JNa$4MSLfs>ABdUY#k%7<(kv|%v0wx(|z<%~i z3n>pgg-oB~IfLgRQs%db=K3;tkpHIHaKLr=01FvXVchJXh%D#vPOn)KNIHJv?Xznl zMI7RG;B)Zm2i}jkUa%~AiuiulE=EQFX|COF&q8SgD@Bma_sGdqNtD|DhP{Q;!#=bM z!Rmcee;F5%gVXXpU{N=<^?zx34QZY~N;TF)jw$#2?y8`$pY+vBYajytH`U*r$2u=6?!COPH~^7qiQ zDVoL4h7mfy=rX*MU4boiFF>xtTCNz3CWKdxk;)?;jD$VVC@PKp+7mTf#HI!aWDQbC zIGf9I$`GQKchdNN~1Xwa+}$Juo0#n|K$Y} znsY!md{nMoGY z)68KAn8{|HR~U!Kk>O_?#*?_~hVf@k%8X79+>*Kf zOieVX;=7|uKNo4kYVaf7=on2~QF$(8e{w=4+82DAdblj&{={);ro=QCTs z^9M*t&mXxEtsHAY;iVOC1aK&qmpC}3!maUBMaT@Z`a7O->&+Qyp|MT7IAl0pCU?8a0YDYxmd zR?({PKSd{M%sZz?4DqGsMP<>7#q7b1Ks!&m4@x~TD!ScDrM{0Ac6`XU#3U6thVFE{ zL44Xah?-yF1#jq^ivK}HfBz3=6glZ%%;*EG;$`dZVuvgF&l<5zDKoF4&D$CWDthmT zEn3P>wWA{m7BFGN8pDTpN;ok79O!y<%)pH8-R0BQjnh9FRR*D$<>C)p-rPlKqFjw^ zX-O$&$`0BC)OffB*+kF3BODkA7G0yKXNw15Wwfeb6j|~iNVoacV*1E_)dT~Z+vBzy%g7KDm|EZV_x}y#( z;9m`P$m%U>toj!?yd3^7aCiq=Xy;c~%je%FAWNfQPyX;iR9@4uu;YLXt~)gP3x~4f zBT3G2%XDuvyFa{sZmozx4C%=oMSm!MDo-KG!(yVEKVy z7HbvB(!=eT^%qA79`Ex&BtB=ELK=%>7O0NwC*OE~SbS|(f*TvkK&cP9{f74^9(OwN z{uw@FLDqQtbymkKRTjTw$!ARGRqf_{bArD?9D;4q1DyDHC9jV^816UIb3W5$2)`?& zl5Y+-g~-T_{w?uT{f8LYMl+BE>)Mdd;e9rZbLwn=v9t!)=sQ(c+4c20Y-^5+fr~T- z3)K#SW$zY$4KRAVUweDn>{L(3I?p&10jIdhbcrHLWNPgjk49ww7r2IZ$;RnzoaNX_ z|5Px~N9n=Oj2nuO(bB0erjZGq*fQ2uY5A#Nq`-dsDGEP)wdRkf(c3@;~>G$&1FQ*P|Q=|YU+*G zGp45N-u)_nzTSl{Qe?GDB|?#Neq+gWvg#4I5avb`T0Rr3 z-G|}@UNei_plwnH5_KN`A8^gH3D9SbTj!*lkc?;-Nr%Dg$0d&5cY{$re(SOCB?i?i z;(+<=jYDms7DJ{pN7NTmY!XJaZ+Y%l{uR!{LB$_YWY8}a|4ELb3%Mq7fI)pFQ?B?} zl1_1s5OE2$p&_sla%E>1gvZ}nR&lXjg>uA4KP@w#^vH>SoMIbAl< zPC$H8)U!gci2E5GoWpT9AKpq)g6{T1pF1-XDmdC>pZ6kOFu+gz-wZFKQD1cb>6Crt z3)gUg70rEMR3%pI`!C2)ambK7ISDDxDf4ImBwaJqoO5i|8-t+uAbFJ^R*3V#ntN~Y zpIX%Rw~@Wo@q(|K)+4ZID}&EwR5KH-*i#6xkoO?|kfOQnvu8ekVEjMHMo$RrFw?@f zL^iFwAX`v|QQu`;#Fe^q0UsID6rv_x3< z+0UO|dHyFKc~1Yj!~e!3#jqj8j4c0)o(vTHfBSY4P&X%ip`epCk(d%tT>d7=^Crgb zjkh7cR1$&xOTedIMiH?KanEtu9u%EX_^wH3kr5|A=^3V=rU09i;v*9KFvj5<|EH>% zW;36O42MWyH}|N6{5`aYX*|;PgI#Y7L|%hiA@p@wQm6*JV&W5G%2)aU@*?D7?R<_K zO7+iXn*Re;^w#XwyH5uZ-*3xX3~zN6{9@s~?~;2!-{I}iJ5{vDV?%TqTg+!T-q|p! zKB3c#y+#{IX*Tpdg}|ulpbh~+oicR!+)!Pe&f+^Ce)LPqqBXO5cn?sT^uwJK-8I6} zO#P;B@E?BVW<()1^F;QAE29o#R^NKQ#V(Hq?&i?u0AsxOhReRl#ri8~Bl?mPx2Q>` z#0TTdHaZ`XA-HG7okxDJ>pbWFL)#kP%m!#%-D#I@f0X^s`P}7mV%8cf@Lex8z}%ya zdDs>sc!|we4vDp z=cA~xu6@km{0#*-6XAeoymN?LUUbC<6vM0-Jok@merdY|Nc@T%fOA-Q9(P2&(^O;# z(!2$i7g5XD>}(m?FwZ=qV{ZJhw9|;&O?T7%bdUlvhnPc!5_E@sUTQ||XasNjE(C9B z{9DV)k=%Om^XY4->G=$lh2(-H<|2_K35FPvXJzxS_`!9d{lR`v5Ay|k1!SDh&s-M- zJ6;1wkoxzJ=ED}pF%9kn2oyrk33XMKBf`h*eCwPRZ<@7JSx(7^3QqMy)tKs<4}Spe zSeNHn1VWG1*yQ{9yPN7n2-hi;$xr1P z1;s~ytYH2Eg_n;%LMc!ameo01ED3H_@9!Y8i0DNQ!n%rw%A&i}zbvf*yru_Q$4fK% z?MyA6IhFTU!e8t*0|GDQ{;UoviD)Hc$-f;uHkQ9J>!@XR)dbREm{5{F&GX;gl*$T7 z7yj&#Ck>)a&(m2>vy!WD?mUgVpjQYq7ia(wM1$Ev!~i)C?9%9M#plm_z#2b|Bi(P; zhSl_vh!+r;Tq;=IoWpQsmFG^wkHyEQS&AEjV>eeiM3OV3U=S?`h*oU;K=L`D@)N0_ zsGY;btv>kDJ6$i|uRF3V)npDYf?+_=C_Cuhwa$a{VCIV^LG+hxJ;pX*a3;E5DL8+( zf2vWO5qXDOO!v>T78?~Ir)s%!w-IJKG?FtFj&%TtSEW}CMhxCV_Nv;Dio~`O@$El( z^BCO=3nfO+$jwQ%&3C2xsKzi_At^%3EwLht0afR}*B=_|_gbFoHetmqG1#w)g#_e> zb}AsFZLpU8%=s=nq6{082cG){U&95-CfL#mg)F|mHQeJiB9T}|(r(Ti#*cUt)?%CH ze#eM9@atGBs)|L?h|EAvRqY^gP{G`nb-`_w`68V@?> z8%GfgwU@TcFC~UW%ZPg7h>%2c=p!+Jkaq2pB;=EAS#E!)u)^nXfd34GqDO!xOU@H& zMF|tjRti=RWYRa=kGp>OI&Dh$aPR{X%9SajwP6l_d4yR>`X76H3e2E|$EAUSQc&Rr zD>{=unf`UjqM*h}49@vOS`CL#5i!;y8y2b55-0l$6|^FWn|MNpCt|DrwX&LAjFzQ3 zC8{`;L>A*WNuHu6#8*0KmAsOP?msM*-o6&U#B{dIlJ-qO@R87r2_>5|}(fV4frxmN_tfWoIa;d>JJ=Ss7 z$r?Ay-?ozUzeQtvA^|g+@`6^Vw5ql3twP%aymc&cOMbILJ2-;gXsfM{k!XcNnhX*<^xiuQ438V^%-#R$JIj#2;kW1i*6ccW8GvT z7}7*@t3XxG8vp>8mzrJM?{C0@Cfy((`}35(nbb0Ib(gr_7nXvt%;;40N>GAgUY|tS zzZ|pqyq27n;VSi%P{+1@pWO>$bXg!F`_d#r-NQlyZK6;yuNIt9 zrT#64efiPbtE7S*lpmoxwKR-;!aq`FbVB7+u8U5em9iyPdNS5Uk^E?6Wbfh!kv{3e zT4Fe{#EIJTIePt5izg7|M}$&aLhqGR;>P;XZWaGn4FBDLnqLl<|8c^R!AcXO4&Oj$ z6B!B2cY=*}ZqN{ZVG2p|M9tYrBZ~XXc(&|L#o`^OI7%OF|0DV(Qz_@O7yUNo za%nsb=jy&l4<%F(RzKO@o|eql`asL;lf}4BYLOvUI!k?|R+_rW!8`(P4b84_x#Owo zXwDdVrsImEryu{Rbj?ISQN_LOdU6C$TFa=VhAfD`Hk_r~sUcQLy(@jt;^ zLM1f(AoT8OovqXVvpQkrhli6#D&yV`3@}F0_x1fI*)xLquvtmvQFuw=Sya2L%{}R) z@5pz*-NT(eO2q~=aJX#kGPg}OS_#XvrbKNctnR5~HFccC_DG;bwEibfi2g-Bseh04 z1>YzM4oLus3zngN>6E8iS;Tz z{-z$cz38iwyY8~)Mj)|N6+=R=ogI?-Q7SYq?0i;Ha%Nw%)pjx?F!qLX`J=3EATw4!-({*J2nzUjW*^{NNP zq8Z^JvJ}i<>i)P?BbjAInhbr5qCzNK zZycY+#(nD?w2N)-R4(f2DE_q^S!R9&YcEgSeTgFAQ(*W1C1!2BDluwi5IPUJ)Zi{A z7^Qdbc776RyxtG}oZVrlSvlO;Urh(iqg&iJHGk$qd$J1`=iu=1AbxZn-xEH^*+c~h z0LDFGz_OUPM)bsD?A#_{KcXU&{Qd{b>_2lk%S>ddXg!(jol=b|-MvNhg51J=ZP39D zn`RV~@fAgREbX-6rY%IL{<@&I8cuBdi{Rs`o<`jxVnyaNf^vD9*cRJupKw;Uc&GxX z9x{23j_HMD;I2Tw>rSk019uQ4XsAZ@?#XPUsDdr+^sIS^yDU$^Rh!4)vg{p>A$mb( zH_36FJH#bg`0MCxCQukC>B zwt=MIkEC(piJkqzxg*ygJmd0N<16d_NTk0-X@1^7>c|P`bniut9p(NjQyg37%2x_+ zHzVr5yr2%R z)X_@M$`~|Ez7II&1AFdL>+ph6(YdRv5nAl}JqY-W_7C-^qTTD~CS?B5h`v2>oiFS# z+;oqc&Bo}?WP+q4H3@~E5@{={ClI@}4*7g?2{!A&9lfk7Tp*ZPNSEt`qKLyPpz0Z* zjhHG+hAZEVkEY^LDkS*0_X9g`g40ZXE(H!cM=}MR^3e09x=UVgvgD7(@o*&KrOZ*) z=S4tDBVrGHGk;JcoRHwRYxBV`HPy z%{k;y&B4{$`tyI-a1$4ETRoHw<#uz~JWHu2+tRAzAFq;U6LGk?FN=l_hKmdm^Fdw8c=5a2 z3uzaqEpw=!Q@$*A;9&4wzvE-VYoPdcl(5?KtWI*PMc3{&fbgZSC-46y zgH=t zXRPBf72@6;1G6pRwwh-aZ~0WEb#t6pwWU1aPkSPci9ceuLu}kDQP6ld$9nYxh^O=Z zPX)YM_sP@kB?6&RDZ-+34HnSmOqbrMhlJNSvdq??CeCI|l<5!zplTwDPfrYBBAQBh z=|v2|I^tQJokkBas>R^7y-F5C6*6c4zNYWV5N-7Djz$~2sUEb9htKk zOy-*|07>olG-*8p>Nb%9T%RvXVoP{;+R7c5ldfvT-N8ah4=+$p!e;A`AIVKVFP5li zcB^62Of_I#W=qU}x2}b9KZxUZDKVlFz5gyr%z<2#|N{wio7r6I<1n^S@` zQ+_8Os>!VBj@MsE2t+E0VsGgt&MlA_kbUtgSn)Qcj{@)UWw0FFVGg@ZIh2 z@u(wt<{hzeva*Pmjyu(ak)>P*GB*V;&kEqMh+T7UJchkv0$+6EF=drL0v z>C>$)n_-Cb)OWS^vEq6-DHCGP~j_OxfOetCMG$ z>@jm8aFeow(W_|HDKta-oglm38gE38NBw%t@0xX)I%a3aB<{)pArnT5NjW>}#Emhc z@~FdBD6mdXF$bc_09-*q4Uyci?5=s1qluZ+XltkK&PA$hRc_9{UmH;q?l>HdSqltH z3arY0$HpJwkI&zpgjblQO!WRucQ%C=cVX@Q5Pw)Kgcl5a8aQ0HvV~|sn&28K2)y&` zjULj!)s4;l#C^y;bSp`NPXP8xIHe_tb^~fVbdTWQ6Q9Zw*Sp@DhG_f%3l4B$|0@~Z zbVqf=^@DQ#7YcPa<2Ezs&# zS=9Sf9;;Jbw)R4fY^nD0Q9V;KbTxnZN;)d`23Sij*vK$kmUBuh-6=0dEx`QC*t~8Z4`W!ki@YI*QLF8SKgEq(3_uAw)9< z#GqQ*>bjKfp7TK@(R{ZQ)I*M@YnTj!qO(cBP+-figcgP5?w;SJVDhXNP4oS_3_^0N zALS$q5lxtBR|mEG#mpTMr=V z?X?~iD`B)IvyEFBmMj@T{C7XDr&HkBC7Yh{Rs}Ggc#>Bka+z3)kgaS5pW9ndRd~|;lNQbGSWoz!I3`3%iHLzYs?s)^>>1QKmd*Sw_vO1{3xH99-gCk zJ@+T3?1Z^SDDs%?*x&+Un*I<3>5au$H<&D3PUD^#Pn_Io8M>fB*v#Gv^U|QM7jl|? zw%zq=)|x574`Mn{3QsCWAFT`)UsULzh>y9lZ6_*zZ57^^V)Rxcf?-w+`Ald@!%d=^ z5HC)Rx#z~`pw}CpKG$79;uH2&SpIlKuQ;qG6+-tG0VKd-YjkOzlI}~mp{C=e=4P|f zWpxozED+3TTJw72FHny9^G~e+rJpDMXO(_DIT3^Jv$@`iKwc9N1kZ$U zTy?=lcGbKiOaV^pg_^Y=ul|Pd`^dZ<7&9j(p`#iT(}nh@6^_RTowR;nwU0p;)IbMg z0A8`#52H18&@V_qT~fGEjU3q&pX%RE*HOY#iEEi4e))Zuzyce8BZ(!_p!qCy&un_n z!CZ>vEbkS$)o=8)1Jvxxzc>395+RUnr9q^5V@6QpRvyNYI5wU%U}M&ur6A6KP#Y!$ z;XQ~tGLR~qBf5&wZg}L3)LXrty{NcI`l)U`kCz^exydblF@m?wToXZoM(qo{Rj6s7 zv#M`_*QPAP@Ij{F^O$0>=!&urKKcL0+FJ(2(Y^h;c?jSWw*k7i)rn{!AZPx0wuKW6xLS@4kXdLT^ zp}OOHxViYHW`J^nJ4dv=uZwkQFhmM_Nm|!M>PSNHJ{R`j1t++NK0?$zj3oX? z!|7)|UR3Su)Xzoa+sq*tvFN72C(FDD>U|1@az9rSS6TJE`<0Jp*_1`W(}5%lpk$ulevg4u zzjl~~#Zprbs|6;4Lssl4wFky@bf`bfVXc^;RtN;xNO4VSZe% z`d8-?9ezw%t|^60@6)*Pn-7*{nTx^%%`r6vVp^?SJZfQCBKs^d%g1Ul(l* zOP3+!W>VCVmn(0cX?*#h#%1AVe83M5XE~Y@9Y-pbZ0+h^ciH+Go zUE$O36Uqgc$#Aym9DMa2eO_t;W{^=$VU?7hi;;2~{oOi$P{^m8+!g2}f<=jlz2>)^=R1k*L?fBsRe=VDpuDM2U80S>M z*|ELx3tuCQjCEQubyNK*lsjUTkfiyR;5u$#e{6&R(K@CJn@k?`7bQckl=r?K>mEGT5Q^#Bf&;Jy8y7-E`jckz7CJR z0G)seSmsC=BY%QotcqUHsFm~>)fZSLPLVy#yMW!2TefKRYc$(^hKrGv7L)Ehh!8O(`7^ z73RC%v%}mPa3O$M3=Q0JSHYpGWL7&HD7cg&hR94CD|dc-yK zpFz9F5wT0}?D}$r9})T#t`dC_IO=&zLY+O6QY9pDUp;arREp1R;bLDjHU}aI|3^K_ z)_`qg(ogL1fKU~|-#$6uYFULJu1A=c{X!b-I^VL(K-MbjKN}n1rjr^_wzCwk9SK&~ zPLerkD3gMIg<+AZg+yY(0wQF&oA&e~Hpk{CU9Bw`F#TUquMvnmQAa4qZ;iYk-llTj zg=C~&TMFhHlCEj7z?q6PDqF|;hnojC%q76(dye@<%x^u6UyJPtOJ;~ZhwMaitux}< z#`B>}p8GPX(ekU-kZk_<8>&L={$YACxLe1E)2M6~7;o zH%i9XEBdGOzlH_=6_aYHZ@(|^n3P)hW6}fhzXkN_$b4@6Wcr`RLgu3jM^E@4bo#ni zoy5o-A^TmjhYJnigp48yW3jy+9--~SQ)PD6jBfG>VOAuxi(%5} z7gH1e?}Tsxt^b`6&T=j}5=8p>P-K(FhzIy`@YO4II;P}%;F1o9BGh&QyV0l zQ=VEy?8CC6b%&(5SA{Tk(5@VMHurQ@h z31CB;yoM6S56WwPW0h}KyMO@nMCz##n|@&le59ZnE*?(YI z<}uRuZb%~YPCjWZq_uHc$bWmgU4PG9TK4v4ie^sKAA^AwhC$Ez$p=E5 z2bPcyUs&Bp;-q(WCDDwV5&2}f>S+{)hJi3rAIj2fq;FH>Lj@{O@nnZ<14*6H6H}`5 z9E;cdfQd3vZ{K+P0LZl8@!3q`iD}KxuoSt8{#d-R8PKzE1qc6Rf)~Z!1P67rFu-%^ zy1^C2K8%3sNkE;4nm+=_%@tVqb=Ko(j(M7fMR@;6y8}yHQr>HfZwaz;+1HNM5s%zP zC3rSe%T)!$IFX3_W9l{5o%yhS?=mZHg#1~rj%;PL>+dnF9FRn1pNQCbV+#EbVodPW zk4hVQyLSg-+#fmyAD7@PM&h|WN|e0w*>K5PhqF)Nu{KPdp_|rT(XJsG8T_6da-MAB zPULNO2sImK+WMT4{XOwxd93>;->y>+LV26Ax0i!PFEXa7C}>rp75YM@FlRY8 zM~!GJrNviU|3h}s8F18wC6DFU3)L_N@~#tkKAq(s|#=vQB=KSzkI5TFsA{+vz`VJg7UAM607WZt%O>;4V?T76?FSg(RM z6Co&uE#K%DH}X8`Cg?sUnjhm6=H{8PX=sq$qX+^sg zKaTsHi7o%YW30qNJV6YlG1>|nbY?iFHMNx_J}oMJL=GHIX`3h;tWZ4DMD3C_C_el| z5W_>rYuoy7zcRjAD%Vw(m+Dt>O`W*IK6r1sw>Ru&UzE)ItPcZet1-RX9l1m7;e+5C zE#M$#fJ^0HbxwOM1>lQSktFz8Fl!@AEu$>j#MHHTO5w^a2_(Kyn(NOT-G)px*cjL@ zV>B8M@YOft#ekXmnhp(PywGcuMRi8W#!x_H+$zqcvB(%F)?3}PMu{CF;nOFr@3$3N zF2ARS*MCTK*O#P^nK+Luf<8r+&5~%{uJxx)@9$E4B<`?5n-EpeWHlVnWB?A+vdh_B z(}_l@$kyaY{Y)y_d3Xs8Q(Zjx;rDq+Jpm^&O#aU4_)J=cUe^V?y=My>CZS{r49tcZ zH-DDUU`xzeP;U7H$ZJ1{kgOLBsi*4=eXnYMXX^-YeluY%n0}O-3 z1daPzF(~+65=%CnZ%WG0LhEIozC;UB4QpUIy+9N*AFl|dObc?*5zg~2;tH(%RE112`-T+hflp>65%R$9mKK$nJic~6Kdd{c{CGRuGDc}{ z2RMkd6gFW-c!E-wTEzA>v1lt*NOO5D>PIQ6(&F+FrJ0LuXKaTJ@9ve(SWRt(9igRS z-Z5eSiXDLbpWhQTiFwSY43ryfp;I>I#SL;ELbc{_&JSZKnSys%XY!0RP3@$oReTr+ ze@OE@&d0;lDNGNjqX(jbZ89^a5Z_~w)zaQutX}faXPTmVQi0kPBc$Dyq~T4v0?DjtoJf71WdG(b=BwM#-CB@JLCf&3i~VG4qlPLodxoyBRww0DrSL1x6E zJQhxx0b7`Kg5yl~&TFqtf!>L18ES$by{ss;yQZ)s5yMcl@~28wpcT0eQ8GSizgK~N zb7PK#waIjS*lt%GDqp<&M$XZ+EbdNc)hi>L8^`~@q z47A6|zN8UPgEtvwsa*%X`m;v{N)#sYviR85EAq{kE)&8svlQ{Jc8wQxpkl5cTVKh& z@17Ytw1s8KVY`d`1Dk|MA4|%Xl?1lwx;m9hd6b$lfUrw2D*PA4#W#hRg^*u@H;(1x zqR8R`8=#NT63)-!f^*nC_H$Mqz#?5GQ?tdsx6Pv`yAzyOa;_PU?=jvx(x1Q#U}!vZ zxG4I@PaMQavX{(wtIPrFg&&4yjh$amwZw(@6jL_EawG_il{B-niwH<~RI#>$3;XT; z42IdI{g+f#NO>^YsJ;><6(rI^t2tHWcE9UFa(BbAB${e57+?Ib6bV9I3lYMwghM#x zV{`Jt%rcE1MXv@zf1oO(f}sJ_N!}Oc{oC1;5(B?E)^hx2hLp^my$`Cw=J>EQ@M`_w zIrr~~32(Y%xwF;nlxLh=-)v=w>%$+v1PdbQrL3?J+VDhbuDCS@eSZ@_bohfv=-%8< z>q})tvWE7ufz+T}6!PzWG+)9tdO&qd1DJ==Sz^8}m6K*s*-hk~picfAq9~{kwf{lv zc$NisjzIQ8-wlZ<|JlqF<;M(R^;-_I{{R9;H9H&O$3|wb2HCYn19Lrs2l#YTtYfc$Gw@^##OVWr( zEk77R5yyLVz^J2>iO@TZW@mdm!j|Ry!ZZX?2Z9UFYstXfS<{?C1^7CX4eG?K@;m3a zBpTi$LekV9M zLQ1aRsegmm$nN}z%ofV^L)wItotca9_m;Vv-Tin8qfZe=g@0Y>08q{!kmM4gW=-pZ z6)ZzcHi84wlhp9^^%?UVeg$ugln^fza@!eJNj7Bsnq+YFn}SvRyiU`wIg=r0=wfIz zg%h-5{fhYv>OWdoNRtkO*!R|H`r8VBNl<9lZ)xQ z2>5Pxz75WH?2>i|_`#kW`2ry?6`4KUritIfREt)r)ocShd*7CK%4GNvcVtk-{$5*9 z4bGizAS9eB^)Us%w!JAXmbP@9;6#R@|7b3Sz`KQ zC{tF+bT;La#JKV z`63?6%7!N|NbNm$a?>8f$l?M;y$;GkD=BwTwe|dE}PC$tlCGzF8?T(9eJ!pTJzVoPI5|89g1JJ z%KOSc2zL`2=ldO%l-qyB{s+sr1VM5(uQuRSkJ|g`GPscK79DCwprMuR4o+7%&WsG_!Sfr zx)_hbTIl|E8H4cscZ!iS7e^1u1xHr_wYZi8V)6h>T9-5{KSu22J)x4J62O<5u=teB zC^&II?F@Rm|1EkIuQDGIau64rF@}8L_8m$Xs&7p23D2Lcija2JVKt4SVpzY4Gb{cJ zv|c>FshS=p!@42o)QbE-(ioR3Du7aDQvAvDHksyl#LI)YeWwYBG^FR|CRG0X;!*)M z9vay9#g8$9{+XX*XrvaKhy)Cu0Aw8x+7_i}BD&a$%jMhQhc!acD(rjeVdeCA&Xc{^ zX{n=?$rZZ5lBAK~!VjcihKxJN<%v6@(zOD1kbS)BNc_+Ad^RnqC?z5ks8(X5RAzP* z(IoBV$4Tu*!;t4<5$;lMJdh4fa$jX(ab6q-6N;-Qx=E33O$sCDsEZ}@XoR$-HeAhd z>&{#vL^JsfUqt@0w^rr$bOCKX(^4A8 zY*kF1o40J@=RVyEkY0VU?K5z*{PxL^4Kx<@1Aix1K;o|T$)kPx8G8Zh+Oo<4Qpw`N z7(i2Y#xz+M4v9vS%Wp$K0c5`@uuV$eb7ob4d9{{M54Pr5#hDmGXa5}h_UL?QB=24I znsbA!nTFL(H$2c4N@V`~o8FS!c@$xkSLrnQ`()!!XCU&V~Vw!!;A(1 zPcGR}MiY28{i{L+aawhiy@t#qOJm9w5e|7Ep zCWt!tb2lKK`e~yVAUH>8{H-Xr4)JEKlgyT1e8bynH-N-09{udi?evx3-x*7PX z$>iexmF$|=Jf^Uoi&C=dTOTO1T%*au@kB8$vwjpj?$E-!iQTu#1>%Rj__g{gY6=0QXv zB}vOFGv`>gX}3s#c@}vwzQT|?RUtmMDhwQN(6$1W!|rL;&pkV6tD9m2gwcw}j*?Eo zd8%F|e)7@D(w8?9EOrB>JV2J=SE5iNOz<~7GPm=!KmsBDbgb@Lv>H3S_DIuTkQp2g zVxFt7_mBQ)Ror4zxn=B+Uh6cPg>bcOMii#m?M-wGx?WW@uf(|Gh|WG-9^)=QqW^qq z_E8DZ5=dA)@(6nJ0nzJ4k=s(z`WuF8h<%${oTiv%63NQ|lZ+W&ci%S zfT&>Sr59)%TM+O24yv@i8KtK-w>SHVz7~=g6i>=jHX5<9xqTFWXlV=XteoZQ{r0Z) z2HJhMab4Calx$EESnZbpPU+&50!gmp>9<18HDVBPEOOXqBJjbNlK0@ z0W;;qKRIOFibMy%-`0sOl;M>}5s+15At+V;)#{>J@7Y8Bqd}VY&D=8{DT8kjiWI3X z-A{ ^IXa>uGWPAY{Si&69k2$iRAs6U_h<;RP7otQ*OQrhh`GH$A9Y>OPT=V36Wo@YoZ6 zm~=Olo0y%A;au8zYiaVLwxkDPWaND$V?26|3zO;#UU1t%XYbUb(T{JPLNQbWm_ORE zT8OX%bIK$v3`EXMt{(2R@e0@|nHU>npVEpiLbCs18^`Ep^mVYZHZBed!&_RaUG&`= zYabjS;@o95C``MzFqekSTJU$-+~qB3<`bc|qhxKqO`m zxG?4!-rA$L#V!9@LDKGg9Q{39WjcYH_kxKn`*g@*t2el=W|gqq#d)A!U)5&RMgJH5r%}bUV7xz=UbyaokbKRFcmYaRNpO5!Bk^kqJ<-Vhf-~x4LNZ? znfm+SLO#}D;w6Opykem@d(OgY{9@{hF<`l8!{%9W<<=z3YOdZo66ZRJWW0P4K6O@B+&;}NdA~C8d-X+mZ3O>=QV37``tca40NDmn z1Ur5~8pzCCdONlSZKA+gsAtz(FFh!0xB;(J56B`Ik?N#d1i+QnefIBj0uw zFoe9wRA~pDCzb=&I|IS}TxlE}({j8=xzyYZaR?M!&H0U19ON9~7Dpi3m$J}c)^O5U ztD?y3WM#lR=Xs+?CLV8P+7G`k!g>uL-j1c&vY6pNpT=^snL-X)MB45U#f6@kRWe-p z;;i^?NOGizh3Tas1FWS-WaZhO=@kE}>C;Y(Z+Y-@)tN?`z5e5@L_I-nf~9Aoo+ecO zqiNL4t9&_<7nB*eam`_$AI#FUYFe^yqOSqp7)!mKw}(&eo6l^;93lQg14Hml91FM% zw?ibD@A{SoXnG^B%zQy{wZGRnt>|zzwMtJ4XjEX;v;?1oOa^jJ&1Ry!ckW0`s^$Jm zJMJC!hc(=3)7Mt!hJwpko$1=eGz7y?!0c~<_}UuRKtpDXvh4`2RqE+JOC%&@A`=vH z4N&5Fe>n?Xc1jGbt08MFcL}(v*LT|1BWg0G7cW4k2Z zuLg1jy{wp7wU|#&Tj*aSD;u~1&l#%=*&dp>g471rpKuX8%F#8*gk4`tt^r3AWaOHb zh-^U^;h`~TZ$F@TBXM31n0lb}Ws7f494Yc;g;}MdnIS8BLCn69tYwe6S!o!_aUt&( zk1Gl`laWYyfVlc*9y!UM`4$Js$9upLOsNfeu>G z)y~j(w({lvnkAt%3`oe2T5yg-rc!prR$C@3F;niNBNtqoxuB4C)+_u!k~Q{UjmVpb z-j5yi-uSgriz9mra8;n(mG{>l4{g!aUR(;Cv}YIbCN1uUZ9Kz^d?XLS0uzY=`XbE& zs&`r1MSco&e&+H}6ND0+vk&YL=&s$l{|UC4x0w#e{X3!_sIaka1lEc@K4lMI3w#|% zvKU0ux$M^@jE*)Y0fiB-L7Hkw=pCKAvsz4GZyFz5;Ckk~Q|RB?Os8VM%LRW#dx_^L zZ`xKfN9D{)g<~t~ymP9Ja3UBy z>vL*~VAmz7tx`1udxbhebYMNg+rjP&#f>KmVHVKMV5Vg0l!ZA|itsY8eOxoRcHnbF zeI%a#rJ2xOW9u}B*N;72mCX33x=K33crS3X$j>UL^r-%<3qPw?LWu#?*R;xvJjD;A zEPXqUsn-q>X&=1fB%=f*mYrX}6GAlM%l5_S0k}190eu-{7;5X&as!Fn0=4N7Z`-X^8aX7R)yczl;$S=IE$LO<8>#`u?@N zmH0RGd(Yi#U%JEET{zqRCgoLt%t1CD{^Zr54c!6Y11lM9nhO6{kdv^M zejG_H2l_!@R=>*H{2ILG;HKLiOL%ut)>;RnMc3eV7W-zsgsv-^c5D{(|PQ4!E>H=iBOsocjYmx5mKgU1jFNw`gqOWi10F zFL4r?asZU<=Q`xmu5%=W9h^@IyY;%xF2C)OZ8KK~K4D#MOKS8!6msx!P*c_a9b>K7 zMFSU9i32qK$*_Q^Fzmh(?=CaFnorc2cs-j8B4!~(btLwIqnN>Kb}VF6+{movk;zoFHt|0G9{cK8%co3kv!}N z(h*ecDS;cGGyfDR$Of6#?2$}!D7Pdx34=YkgB-EbW1o<`BTkWJZR+^6N1qjEHh->? zTshy%YrzpqCV{OYVn$jv8<7Nza&uicA|C@z!|@0&YJX!Kjv3XF|8PD#b6VUks%R_j zAYdPsj(WrN!q^QB|JEqQ4Lj)B6idMra9}0<+DVk zFd#`fzx`R>fDcu$%2fo+}Td!;l${CdH_ELwj^J;{w7({Qpl z2-&(96BXTJPXTJa+0~2o{sHDasDJ=*X7`Pg%dgt2?PCxK8Y9f&3bW0bta;DzNv*~q znzp~$k)mdaO*1n>-0zxAKI-4PkJ$}8aPpi72>G5%E8jA9y`Y_`wAa6pZV_}EOMuYP zv-4_edt;VH@H7&<-rd?~*7v5UvBJj{v$=?+RE3$5I)4muRKaIqDlbDx6@5M(8LzQ0 zyguP4;h7Y1^=>_fB-?Yb>pL21vZ)gbYw{(OE{#H~`PhsFYbUNCwGVJf z)Bj+S%&1}Pu^L(FKQlw1A2``E#-^qOODb#GBxxmhnC$Kt_=tY;$W$I6m{#Bjmf0YK zynrR#jtaOBI1D%|-&wMu+5xo+d7i`4Z2H|$?FDr-!<7I>e#;?P8_@Pg)xAQXG4Nr#a<;&g=vp$vsr(ho#FoF8 zRHwPLyOG+5IX>^!UXa_QCXlekY_z-|J^XWjyUjw<%O&i*1|L;9kdGDn>k|~OdAWMo zeE;les60-xR2DFT*I7iz@%J(Ss#~eR2Y*m^A1Nh{2h>k;v-(f~S_ITNf3W+A2P!$a zC`CbW$*(laxU*DAf1-#%5bL4o9GtO)XiBeJmB;`-_&5wZ221;=gA3cc7lZS~)4;M3 z<=qX3qx&cmY0DFRXHRJaACyRHUzlp~u9L3xz=u1r0b8ui;VdUypZj_8Nvzf#qx)m) z>!(~fdJ8`iiCdenr!qBjvP(P z;A+O-RCYq|lf1R{O$GWAGYrJTmZZOU98(whhfC`Jb@f{ee`?!G%sBE12KQC)7VD?l zzAqAW=_5bZ9AFTC|w`4&nw4 zhdQ!;GT5EHXE*mbOTdaJ`CyhRB)2vIdFv2MCJp|t6Ww0T7X3`QF!ntl`uRH8$~|e% zTr?SNRM;Y?BUMG(;&wS}sgM}@pdGwt0j@6R-RIN{vdeqdRD5YjaP zGSEqdu4G;=VoD6(A&<1hC_WFZc56YWNp$*9e5WEYViBxs)3~q}nJ(#?-m9_r_~=mI z9A}wicBya{myE44F~Gv*htNJzoh)$g>t|7hFSbOr#!)|b3fxkB{&J57ANmocjb0!eoSII)S3^9>=M0>M_?ti<=SBB#Fyy@1_rQdlfs)6z1TvJexmzTM2<&cZNRFCI#YRKz(B?{lEfgX#eNZt2*$m zY4$toDg%w35_SBaYO(;O1gGCr2iXRK_`5rg@cV9DIHYPFim%)En-ER4Cj+Yy^Xjy; z9iu@VAyd6a%)t<+XuNM)h^RsPxg@X#E#^59iDjLF4B~!dlkq`=IN1B-!vCA#hax3Jt@x9><;X99|$`5bAVcHVV^XE_?<6NucI#*uq zE-F&nw+TfA_&LpJ z_Mg!7{Bccr9J-4|nz-`#MFI>%GP{^+4D|pHqSH1x*H^Hs_X4uL|1K!8JL85}X_r1j zJ>D%*)^TA-8$JuwTN>b8GaspDG-im|nH+QwMR<*n`UdmU(7aqbsp7}Ujpmu%s8ozy zX_=XEm%+(IsZ`1RdsS!L^nPK%#yk|nAPy}wKJZU*cJ)cEMzd13IuyR_p5WO4TsSb^+^`qz(!MfqJ|PKx z&>cshXag8d5o^IaLvz7}owk}*sAsj&7s4E05JZrZH0n zqDbPleCdZ4`~n27zfOrGasvtFp%-LU(eX$RgdP*w5jtwR;%^`Dbdn>x``5%hKdfTx z8u#`&%n}$1GY_>QGs$(kKkGV||Ki&t?pppWBv*0*)(@+W7Q5$Kfv8z!iV^AEKcGez zt?Lp6Mg<57CuW~ZMQs)IhH1Wh61^rvIF5g&C9oBqh}|==%OmZ$c#)pZdS7I|r#qSk zyw>UcD8h`gGf6RDotk&pNn}ucH-}bkev?m=RQ~Uq9Vvzc6590&aW1yRcCaZ|!p6Hr zJLjB{PJ1EHh~Bt<&w;7cW%3@PId@lf=0b&vO1vitK16fY#KOGq%z9mqEXbovx8xmt z_|v`H$qz?()_Mj-dG5q)X=Xcal+b)s1i8R${nF4_v#(8DS2y^G%_{t%rR@ zB)+XNY)BwA^Tw2F$Om@m8J`E~*N<#|Jndb=Y3D73xgpU+6N6}Wbu%(X`rODt0>M{% zfQYd&t%nvlT>y@OhK@p<*Hi!>^4FYLM|?8M7}~WvyB@IO=Wb@tZ`cz;2}Rk1fX0KL z!DWkgUcYC)PH2xkAGyv9sk2zu(zXlUVC-{V27xkJR10tuLO}z=cj*<+Sa-6j`EY_Xa=m*6HXM<0CaoXhEO^Ic`BF zNvK@IN%dBm9sP*Qd3WTpY5l;vo*p*QJW14+mvz@lTLAI6Mc& zlK!c=?{+>}Ckigl{OUvp>9aniOERgOQ7A$hA&-Gn*!Nv7Ndyx~yFUS^V|MOOe{i-N z`}ElU#qE@3lgdyeyBKW{RDF(L_VWwP^!x3* zlo#t9&|s^dm+axDFjW~=NS$GZVnU4BJCHHoCoN7X0(JYQzGh*k2Qk?~4SgId=^Dzl z%HOx8L$To&&zgT51f~deV%n#rp6xmS+f%%nzaNCabjHNG~ie?JHkd1vZK zbnRjg!Qf{QzM=vNF|7=!F9D#Q4c#Tx2M@+$2mcYl%x>{V{z9iNzfLVA@)U!0vLtF3 zIUk@O(LO;AUpv{rt%&DIuETyfuc`JIwV1{>56u|@6y(;5PhYaQRTH>u)IKA#HCx+& zBVsl5GEvYRpJmf*@7f=}ZEi|EjztGcV($V`$JYsRLQ?Yehv@1f#M;hno?rGu+>)xsG0(?bSug+Kcbqe=(6i{3S2{x)TLHj@=A+hWStf#2>vs*gu4?!r;_wrdzNj zv#%G5_abACEuAs|;MU(<*tz6+&DF?G1+M(Kv*jxgR8jBpnl|>4d8Km7pQBv-m6?m$ zkL|xPWjRFN1Gn9k(Xc%=OHIlDMuS;GZ-jxVgHm4p-1r|)eS0j9KM$#0S;Sewo8RFw zbrJyy%c2<%>IRvHXN&%jp<$8L+y;+8Ad}Ex<%an+MwFH*47$$BU@uDy~lrzjZFf( zAB~1G;XIq%1bq2R2-qVW8Ibza>)n?`xYK{W0ra8rM@88gv*+4-l874`%m6kjkQJDt zEk*NRA-cM@do4QD3w+Fqkb8Y2$>xAD@b>o!%eOYmJ^xhV4Fcob@%U^cP&ZzZ6iPkZ zubcirT}Ov`r$xA=*2BJ>+?DTqARGTGl?fGCP&+GI`u)qfp*1S#?ok?9Q{b7AeN^hd z`Q8M_vPD~BQ9_^X$lQ-M8>8kCfDp1$FV7iU(OhCMRhFAI^D8vXi8P&YC9V^zo3^tq$bH7S8lyf76t!iWl|!L79VR#-Fzf75tQIyktW z73+rRfSS8d{eojBF6n@lMl|@IB2vYeYKU%FO{yq)<~+-XYWNZAJj@3 zga5Bj^O_5{q#rI;v9(yDD>iicZ`>EKT`q)N*%l^e7w?pZ0{BqW2u#^n6F$V-!M+<$Ex`hZ6=tk(z*|f&fQizQuAElRjH8y# za3z2Jy_483QXIe3m93Cj$v1rPPQgD)wL)|vy86%dnwKaB>cDKUUk5m_C$)g>tDJ5^ z2vKa1)6>Lz8Tx&lOEP+9FCuU#edeXmUi%Ub9TT_g>5wGCwo#u1hSbF@{4Uvz3yIQ< z$)@wvw>59D=lwpE%%=l!+Mg~olX*TgtkMg|q4!TG`p*R9 z;hqSOeLvBy^s6o}&g%r9^tfm@2(%3;--7=|QPVVrw<%!gBylUzxjJ*A8qUAiq?ROX zmAU4>G^M!2zn?0>Y&(32HINy&x*G|zG^t#hV0{^ZFuY{KIt;pJdo&$X*A4dbCB2|k2!JjAJ`reOKJU)-o~?tMREjuZcm0= z#Dlo~*In*kA9Q;gaqv-PiMBmomrjHT-}_wcg*S@_4O*G)|fQ{g%TDV5%k z(5Ajv#9CP~Gvi-@o(2BHg4V3zkGxSb;w8^yf}E$m!mTkz1xT}=UE`pI7T(i6NE22_ z1;3m`FV|TElO-L*{hO0eSk5Ekl)994qngXexc^x3F^)fDSvR`{3At*@X!(u_;Rghk z8n`O*sDh>w+85C~I#C!*?@K;y`y9|FHD`60;W-p2-#-z=Q=hINjuAbZob5ZdhogUv zH~p4KcL_1@vO`8Y*f;N)nFn;a6Jh>pj~F~xx-Ly*IH%g0!WBTTw*`l|XLOf7sjF;U z6PZV1jKRwSmpZG>Q}@mO<`TamxzKyXN&^A|swJi8zyz%p!XIe}`=2?l=}?$}D6W37 z$gil8e0WVCC#tYx^i%I{yy^X+zS=1}-{&yMSL=}-ZrOp>TLFd$&+Omh2sih#I{|_~ zWP3vanIJ;rt<9tGZvsCx2Hs>SSWrz~Q8vJMTz!rFq#tbpDlsczunpeu3f0UHVnrsV z?wK{h4S8bEm9b)AENiYP8Fy2R#Z_L-p_M+;uTE5H6wvWi0r@g_lat>SZPck%xbUw| zsilJ#N&EFuCR)BpKs%hW!l8+$k6NmmkkVZ_&d_qdW3PFrK;^{W| zynmj~It4FuGp1&KZVv+1lYPHL_b|mlB@qA&Fg^|c8PAA4(fOOWJ&}n`85*o=Aht7F zx^Bg#%TbupUoU&x_;T=`8J4eWvK0|qL3@(d`o4P35$pD3EzrHJo$I?L(H!tRt#`#r zC`NYoD^4oUZm2`wW(a+id-dQ&eDBn1X(hz8ErtANB~}EvxOL2xqIy3K2Ljcq9W;o~rQQ}?@D|QvppriocLlPr zhIL=MXF1sq7yF99{ubUcQa=Hd;(bOC_WL$ljfVHChSjgP`TXxaIM0eeQG~U`H6lJv z;EZM(*qHn=DJ(9fX#ECQ$I>dLCbPGp^X!HpjQ93*^7)5S63wXe;Y3Sn^(J;6#I{85x_FNuz>f(b9fYJG>mwJn5!>MS)FD zDmfo&)>}hvNRX9oT=x;B2Az zK$fZo%T+nC{S5iU*U7Do|I)9DZeq7T%^zgbM90(=$7`lFvV9Mr2-=OtwFurTwuvRF zU&3-0^|;yHKB&V>{uc&j9;FH;zHIYx`6~}**aIb&qABYmP6#hBB9#2YxM8_6m<`8c znMpcC_5~-zWN5$Yt5ih&hJ5Zu>p?*Rf%;$1y`5WhG?y-teT47A@8{-a6~{1}1<&O& zLwrh}8>s9bn)i+HnzQ|sRmusW@3~3>gyfzME{RG%DWZEc3tBW4{rDRs)rYhA_IrSG zD{m^PdK)ymv_rZ(&o3`zatiH^I6j}Z%A_ZeM{*UjW^X^s59=~wiQvM3{8jl3ff9HC z5h}l8$KaCpo9WUw{?IFQ^a~k3j7f8nr4tLb8vdzcBBIOXUVGXaPoCUVG+Z z-q$clb;trp8whUsQ{8AP&&BD7Wb@dN-c(M*0t{*Aim4OjfMwq?&PX&&Pqah}!p%ij zMc@7T;*Yi{H+CKkqs0rv7Jw28BtmN`k+YM^fMjaxP_#_XL7i$>Tzaar(Lw=&jHB5C$)&f^pgowU1sAH9ZBQ%XqSr7yiKuA z_;dmLui;xzuCF-B%F$zdrMnRXk#2!? zfknEdWND;p>F$gh5RtP@He9uL>o zIg}iSoMi(p>2o>gm9=kQ9x~45#A_A8n}kSu#|O8)<@6(xef1f1ubf|HzVst)j)nc6 zGM-8Qs2c#?6M9*4=4pHF*WpPeKWn-Q7bR=nfj1qfDjz%z7Sb7XQ*u@WO=1tP(UbLP z2Jp8$9(1GAjPsUb>^Hg1lPR|zAo$IyD4Kx^>BA+@qM+*4eGXdmWVbbHQd|l}8Iv1p zaBdYvvx$miw+KbyYuPVrJWv#Cp;qQeOa8rmu7D1=86ebfJQl->v`-V7O%T7vyFuT0 zg7_U$gXdWRq?4}Qhcv^{_aLU>U@R0%fB!@@Uad%)S6orEswYK6OLx->rB#kV7k_(4B7cuS4(%U`UC{g#2^J9S;s^2&r4`VAYQ5vrK3-sy z$e;LJcxY>S-lXDsDMu`_??-W`<@%F{U+bOC-_IIXCc*%dU%o+}d9pJUG>He?Ckt*E zgoK3Rj<4&f47!@Xlh?SbgA14w%$gZ3ZKTNRnbS9C>zI|jJNtsV<G|J0)*y0$;3bJ_sa_Es`j~TXAnvTuN(14jp|-3S{FBYsk~dJ8Hm8B}Ta2V+=YhK- zJjT7herAntW;ysdmaY(|ibO3(1o_8>)9{3=mu1p8{GAVW_Rxv93mQL*b1pa)%|;Df z=)LLHurk?jJ_4;Yl)=SP%cs4+uI4BOx{aw*+4e30UNE{)H_YbW@3pbeHq;Zsz+@Tb zM*e;~5r}2UcC(Ee{Jsml^-)Wv-&+@6V`lW^lMr0WIondP?MB$`AW~uhm}%FagW`E^ zh{B;YN>=95;`{Ag81?84=2TraZqHriyD(3FZ?>WQcZZ9xStd{X8_vY5ab1`VT+f$C z(9vH#4;l)U{CTJJBpaZLrxkJ7C{9Y=TQ~5&Nb={w&!k`JOw;3VqFn)hOVl!UrTn1&(!&QQ1U=+B;X+VI$BuHYjNXR<`(~qy^UkH|n-(g!6S4sPt&DNB{_?1wx8n3?x zbH3=_j6Sbu$6K|XG^q40ga{|aL;jJ^25_J2E(~K$Fk-XOUT6a4P7plPd0P5Os8_BEe{T`eT00r4r}33D#fy!NV`YoC*Jl@>}Go7wQ0U_6eeYE zlihK+n4{?m-8*>=QEC-SBpz_7tsvaS?T4avROwGly1CGcNp^G>MQnWi?m#bR4$bGK zny+lFKTG*Kv5nImAC{Y5WK*lB1i$6%Ah}e^0Nl$z<6OBcdw^vwaU&^H<7qPc4xaiy zChPnkla(x{u*JEJ+-c6_Yh&ni?c=3&(9Yi(SbC!$P&+TZW)l0C3~!WXoAz_NXULdo z8_QmO!Jw{Z4n!33svp@Stajjr;2kW!+W611n&x<4f?Mg5u_p?rLw02j<$bXoLh}0O zBgVSt*ANDy?~7V>*KhOHXq z4*2}M;igN+N2PciRHVNc`pnC$G_F&tJ?YpfgkBoDv#tj*{JRn`%i@Xifj6$1j4l4t zwO^^E7J2n)6CUZ01wK42_Z4#@;TqC~i(l1$U!sX#wN^h!IR2LvK>~t`tUCf@z6$J#Ku%7-?HRxf`6T0dgCoZ&lY58q;WwWbgkw` z;@W@BL@##Zwxq_uDqQ7kan6MQ47|s}JaV8W=XQm}rEej&h>RvYTF9 z%tRH*mWd97&S`KDa}QcJ&#Pe54%)Z;_kQzjtB%Oa6sac}atW1WS>JrQgu5ik>6I=4 zhPtbY%<$OFme|5a;obDiXS6)pbJC8&8_Szd4=bCwL{Fd95;kosdHWhejH!G7364D=i4yeG#r6CzQ=lJz!RVV($rEYiP`rn?+Y?%C7mN*jHnJWNaWRh-C(1 z^q3IjOWIm#_tf;g!Ad%O75%7ttVRPIwOQk{(rG~G^Qcrx>};AWy`cul^Ohw+?ipX> z(K~j9K^|dMUU(B-$tc}Jn?wUzOmarXTCab$5~)Jt3DKPvr-_+WsNy5qvD<`0UbvWy zb@9E{Vc_C_gqa`gE!ZYUygkMUGwAtdm=5D78ElgL;d?JZ^-cu_R*{~>9cQ=TvGyvw z{1Iry9HYxq7-^@^RiAHv_9>(MgTkxL%Vk$w>xoIWFSCE>H6#J`?}pDXpTgdbV>}UA ze~kG4CVjt@#f*-XpCjh8H{-pL1 zbUv4kPOF1-jEbM>m77>XApa9BstnTpiz@Ly;-)z`34<;xbF7RPC^d$Ueriuut`N@7 zF=Npm;y!C~-yod9@na$`2tI|}U2?9CY>|1oAa-*Jm1=aMKlphes@;esU3`(na09iH zA0MKR7MMn08`DQ4M~Hi(N@t(+hc;_J-uIkbIF-StUgDgfmmxyLN0)GDD7ps@?B6Ox zg~qPThQ4}SvPk?D@4J!lUohR1e1>2*F-ivtY-!yBtUF5GjP4vNO$ohjI56!CLYu7Y ztO7Dof!^k--6M3YBX?k1ZxurDT0ru~rodJ|RePngzGbX$T1y=F|J18DmQ@x8Z?{c5B-CGm=>-A%@9OU%=D-?9hHc$=)!PK$`l^prpGpZLU)ZIga6+WmGMv-G1k`I%Q z=2S0`fiYj3AT!ER^ zMR#>_3V$9Pvus~;YKftA!Ns$;S17%?h#*VjwUx(FGJ-mniTm>%GI&KUNQ`rNIhKpl zn;bC|mn}%xR?C5+j5^hdXCl+}@=L)w==+3LkJ_d&%bTNBd6Y1;dbFr?vKm+->Jdqa zuR$|Q(e3)M(sJ}D$LlM~T4`1if`rd=cUCegn$)#)nWV8S?5`FBP;iauIVQmZnoJ~?1p5IU*Cc#iy~O@oTO@3 zaPBa~8*el`KL>uZ#DJubm<^|&2B5<$Eh%R54QI%+KL!@buzvF6l^v!XDgC@c{Yx29Q=PM#wI5?a4kS3SpJ8sI8%frffdhqJMKGXL%NV3Et;gT z7v<8Q_GT~*x07GH#AK-6;YDXD!6by~g)GvZ(00Hm>4phT=E0C_>3}1Hz{+5U!ULEI z+C^Wfysm4hf1x&E_i5HXxPLr;=iBZ!{%FcIb!3IUkFJ>Nu$n=n-IqWKE60SRny%ms z03Sr)MwBpg5fN)?|CF-x#GzW^euetwIQ+a(5j_9sf>u65KNVx8Xvj@%+LQK288M48 zc)t|gIDBmPq%pniyY*o2&HUJ_NDdLd0t?B-bD*)r!7jSvIGkS!?-|PU>5#X@adhlB z2#OB4dI8OHSDt_lF&Rk~kN?1#z(~aLw9;%=qo=oYM|R z(_}Tl)eEF)YE3K5n9!(cxBw>g95W4=!H1PZV`U6cvpT&wG@Q^eD3fJMZScI_>`Z>l z|47r~D8f@tu&cni9Dw$S+S`co!-&{`3_tij!~r_GcX5;W`wrUzC69+>KeL1P6&c&iP_~HYCGdy`vj} zUI`=a?G%AG@Yr7wzTgzih4CBS_AJTnMD1Wyv-1z0Kt^VmCwihl1J+%gKkx$_EM(`; z^sE*q!L6YKEu2zrj53W}sGJhyz#VL%Yr#yp^jWD=^lBPA(-vZes-!>9AuqtsUDKzRD=SLPxpOYz~~r04Q2Q_n2I9`SrLB zs`6-0GPdU=Z&yIy;49T1q&d;nEzUK8=XNP>?A8iuhd$bHvEON*7z(SSvC`n3U5~y{ zs@8GXsJxx8I@s(h67SlNcdF!Ho6y>TlG{g0rA+98ho z%KDBoRos+mo6*3upF53IX=wf8T0oO-K~DuNs@fwT(y)3?HctIk|4Hi$^Dq;X^5Y8F zVbW0^MkT2~{wPIc-J8j1lSso?Ro<^l(a{0M&q2f34t%v&vznRE9kVfjN+-z#ps=?z z9suCTZ-#&S=*gccrx@XWDHoEe0Q>q0y}vc1OS*R$`JS2vyM}?F0#<+#LE@ig3$Pq~ zK!lW3A8khfZP(;N33*nrMaL9jCLv8RF zAvoqb{3b&o%^maEYCAThF1tEeU5~r6bRVAPINiuKH5-0m_h%E!ao0e5C*W7DVPqPh zA&&iwl~MhmOO?e!8Qv^7Qdj_F`WZFP4M?ifoU1T2v z92;uR>V!TFpnX>@yc|scb=*~6i~JHUjYI~kH=RzoQPrw3gS3S#iH?IBXbLQxsM|bt z9Qt{rurs5v@B^+hQ(cW-%eK}(@!}yTV>)wHw#&36FS@=oa{0kWm8A`J_u`gc$olx6 zizx}XG^CvNhb*|PR^+_6DO)iOmc6bYn)}MKAUDIV0RDWQbSnlHSfxOkF?bt3eg2os zd9nXQW$;foMTQm#@G^{jhiFKm8oQHt^0(9v^bqk-=%D~85Db-&AHozSr3|xSW7jX& zMxC))6mGtFU^eEgd+K^0u-+F@e`SZxR|V+O11#ibtJ-8M3p;f8RLk)YcmYx^P59H+WG1_7$3dGV1Ucb{*jBhJiJ zTJ%$^@w5tk;$t?^oNv6N4h8^?(?32d#&n8tLTkQ^V%+3`ZZTQ}T0KhYfeo$Y*<%;i zqw$mRT#Z1on$2Wk&DYmU5tCbT`78;I0n5Uo&)D%7znhrkjEEtT5Ucsq?zp*S7n^v} zHuBbnrW=uyWo57Y`ko!&yb9N4d(yfpcaNIkZ;Yy*++>d6+nAYcFFt|_(Q1DF!F!P{ zKn4)lW7A3v8picG?4mQNr72JZ@Wl;1TNolU?$~}^3v1$pdcO0>k5Jz+#_yeAdKzK+8>#?ozr?EGu+QHu)SU~fnJchOLdY)It znVQ`j6WVKZui)G2c<^JU=t)!gNHG>pKE*|xH(DRe<$0x6=LwL1wU_NCL5o1 zGaS&r(7*XCh_mvOOtFptxs1Sh^r>f#mB{s@wJc^eG72Bk;hP`OZc19_mq zxN-<}pLhe=mYQmq4iX_@Tu%&AC_i%m-SR6P_NB(nm^mSGaC^nt&VDapnqKCI-7+0` z+>$T!c|S8`AyNzT&)`j^28_9Jcb2rHq+RP5bQ`XpWR(bykt$ImTlXQ|!SI8x6qV?L z5g5QfKE%WloQ?T?4sQ$ywxLoviEy?7X00SE&M|UXvj~+d{}rFKn}fbU>Qh9`9ZB~d zw43Q4Q;)F9Q)IrKx96imZZS9^ysWeX$sB{!de*BeaFZeccn$ z$rIqx2OlcU9rWs8#Zt+Y_cl=bCnxuYgpB1ZTw>8*l<_S*2@_b1ZiKfwOUWw#V?J}%V z4Pu-&v{cVIdaYXDodCX_#a4aR^-u4Ve5$c!UvxqO4hC!+ea)68xnK)^C*0cJTo0}r&a9B{voT0WebRq zM!)o*ZwNfFt$<(U{~fyLR;&&TLN^78s)-6(LyJ)sLIBR*P=@Ohtg9`84{Jnk?Y!}| z(x&`Ay3=(&l%SO&wv;+}P_&!1xjHiae%Qk8=g;_!?6$BDtA%_hr8&(6Z3MpzD0EiUXm=XSy{+hr`*X6x)_W<%fw5xE zx#1^w>OX>JCog}Q$nTovhgK%?TUkw0Z)e?DuTS?cwgyslEGI;ttP&|OXRvWuN?IJh zvN|U2@Rq6A2L*Aju-bBK1cVJMw7KsoU{PHBZqdH0P>)Y#zQ9BDZ>1R6zrWE_F)WIY zJS9V0BtWyW%3MBKLM(c6>ZideuASww0HRw$u%$LNE}EIkM-u%sWT+c6aqJ5_+#u4Xk_$ z%kjf_9YMIH01ExO-Nk`Rr6i4`qOdcziNxWVVoO<_FAZId#Zpm=&yK!mUg&+X4-g^v zw#JIOm5c0AS4vgAv*p$djB^-?l2GTNat*XZ$J^=gR(y^3t;XGs zF@nIre<^Kx+8EU6guj1LZt3^gc>ki@2HEcu`Tj+@iQxZ#|2o!#J9)y0d!QI_GxHGuBUGl!?e)q>Yb?UCF zsp-9IcFokDHQlS9etNYp`1SMno4u5l6Brm`-@nI~A-hr&FtCpzX)$3{H@(w0 zXiZg()q5l)n0w+u3s_1kRYiEr`O;EqmRhlJl6$>wTl!K>WHF^$f6W@oLA@G{*J&}; zn(F`<($}N*TXSlz{q%HKvzQz0wsB^*@zeA#ViO&{Lp^!pKkxNCE3I`8f3#JofD!(S zY(M}O!G9Zp|34Z9h+>ja?P)_{qp5XW*21J>ue$2bc#(@qkkksn zpB*U&?A$JedHvEasB?&v-xhy0VD!t)!vL&42yYUqGo!?9GT6+N*eL*Q?7n?@>bOba zIwdM48)=2mKdc_+WMDZFrgRRB&ZKufbFzy)Vd6 z#tanH;4Tp5S4P@f6TEnW@Okd}2I1)<+$20#`(_K^`Mn|(lTZp_f3grH5R>cAfAFj? zp1^8vI*cS3v@e>Gcp*4+dAAhDXxK#)*6q{e51L-V^_KkJ)4LzZa>7Nm>`ZR@a|sn9 z_OSeGa_wrDpb52?56qvl@e!Vf{vP0n; zZ7jp{QsMq0Y3&WTwb+5L{9@&iBew9nFe8%8mmy8u{|H1N^Vm7W5axC^z>s(#ip^bi zyw~2{!pwS|d+f1gAw*}Pk;FfNuvVrX3(uoA6zEyy7oC~n&3Ko?Geugz8RHr zND&oto$;mbZ-wXg55lX`T#DU36cepMT4#{VPcFFcQ4A_5a5xcqkGoWn9yOae5yVv)1O%g?7>?Gn}QL=!v0RDBZ7xQlpPyU$_;k*bZnJz^Jr1Z$5_ZTHVi&X z**Ll5)J??qzZg`0T6yC)|BgT6gSHCK2*enB- zG=j$;(4P*kj3HE(p~-Qx@S<8v3gmzmCc$BVE{Kf{J$wCj*e|ZM)j4#4vGF+WHNn&9 zr#YSN+6ThAB#H$_z;%KqqB!QlhAkXG>c}5u9QAcKr_!E+qbyvJRO{fW%!m4@gq2B~{tX$Yyl2k3rk1X#D(B ztmb-8{>GraT%Flt|=F$5qT7WW)ag|~0lz`aG+fa?u z;qlahW$g8m=k{7ey>-WA+FmE3PpUF;3dZ)t+1oPmBR&sH$rgtl$}15Z$?mX194v~H z4U*TrxIa&pW1(bb-+cq`m1DBn;(W_xM@l*8&DNyCg5BZqVl{~c27&S%MK7$W z=bY3|ZNnchIp2{L^L?2&L*|XR?6}WtrkP^bInIt)# zok!goyER1F-mx^hqe-I}#JA9H(->aN*5!PGzmmTl4&%j}gw-7T;jZRelqDOMamSJu{8PZ|h5^{?W@$<#_Jg^v{QWvU znjP$4?^H4)X;=6+w!lo5ujzvye^Wc(Z5x;~kAyO@+d2rvXqsz{`6`CrGk7QbL+y|! zGuOYQrhv1b?ne}jb<|#bXGUZIfwTS5gZXZxDzEp7eS-g!<;o4!k_jhh8*kgd(BB6y z+aG5xb$4NM8^n3Qyb*Vw`i-dfk0-w}R)jpg_<=hYygraHd>?gBP!mC0#p(9iTl`0k zqBu}WxAm{#GE4b}$#5GBbW9{s0`(%aWM*pD0L4X)f%N3tm{Qf_x+fCib4=e7I2v%Z zyjeN-g0FdIHFh++x4=o|7Unx82dTs>qbIv<6XbWUJ#KSL%E>l_q5PY0>eRj69xLs% zjE4ZG)xY!Nk^xb1x@kr>;QmjsxlXBH4ky=helHQSDshUebp~}i;xm?D3TeLjq7bsf zWtDnX5||qufopKPKEZC<`Ghd*o>7hn4Oh|BaFRd_5HSVvWXWE>hmRuZ8zr4wmG{UrY4gSDrV+c=jjF0ct%E85P)DlI=0YSIGlt~X8`;dsL=Bnq zn$aNgm%oXku=7f4s>f=oG&54v=6kMTITzz^M0+UhO?BBD3TA%l^C>n?>r*hI~iD zDl2P+Q99wx^N&U{O8$zxjiJlP`_qFVfZS3LN^`|1(a}#xLQnX9&$AINRlv_$Tib0d zn&M9OnEPCSuTt9laSZ|3Y!MN|jfrP-+~?uU?If^6uET@Ymy!y>?-28<0+KwwZp%8| zhq7b^Z-q4gT(W!XbR6bEd%sCBwnzVMbV>7!Wh9{4AZO<~iU5;Y(_TKCX>jtD;X`6>Ty5!couSA4UDK9P)GIxG+bY2kfN+SljyOi z%`VyQa6h_~qZ35Ds=P@(b@ok)nNiK|fdMhnjJ7Px5u2w? zmC}#M&3B9Gq$>hKuxoS+{(yL~q)A;8-Bjv)F}N;;EjbzCva~5HPBl0ruUt*CEVIJ}N`2`%GDXER+--Tf{n{Gas4~iA_d6 z>t+WUZzk^E^M%2ut6sQ+M12K~;`es`{?)zASjRX3$K!lD0vy8fx!OV8xXjfEH=GYE zbho&*BK(esf&8}GR!Sva<;1kGl=FL)@Q0XWMnJc%Dxa=mBo!3F*&yPps(8s(6oe&~ zCu9-Z8R-;H$c6Ni2O;?%mPvuP9NeZqGk4a*j9Tz01Xh?_)}_4X2XrnvA(Bp=xhJA` z>fnXamrZ1*k7hiemOzyG2vC?Zqj5td8zxjRNgFYG;xDJj7$L9NX;;P-vCz|(SK>M*Uf&vx+@z$}-3TVB4h|wTNd2L6%{!frhV)j-tf~u?vmR=` z(D%KU!AUNVQcmsa$pG?<(wR^pM74$J%8-ws>aNx#B|y6?)r~zi>Hv>-H>3{iIIDT@ z98xm@<;_-?tEiq|ikM0GwkLeNV7{2sp8wZ(nR22k?n8O_!rfyYByZ4#)lKO2p{BzrY91SpBlD?Zo4McI=@R;AKRZH*=>nZ;n986Gi7c^{w{laWhJ;te}>i) z?TN{fFwv?>6)1z5jUZYRY*yUc#adJcT~el)cZtN!QOInq73y((zqJ5^N8;r5Z%zZd zEJn~tR#sD98T}eoS%OM1iEsARPVIjo`u1g$D+&jdHf-i+uk3TsIG)?~yqbnymCLAe zCGlmRN>ZGRo^;N;@9F)L);~wqWa{zG`*PSD5p#@2yz_VldP*m|r?R$|!KqU~5;gY6 zc_xyX12|TMt%kNE>LQ& zS{B}retrfb-LL1&hGBq&%<=;fX$YZHNi7xh>v55#1e2*^ZUXtktIfy|r@73^u>KM< zK84JeA$XMn(8c>!Q>@^un+f0~t%ND{^wz&L9lei7>uLc4PDdWR-;E?pOoAFMUooj2 z1Grt#0N$*~Lw6KB{0{P28v565-pDWVi6W<`fkOL?{~eU59||FGq8q#Wf14CDV2~P# zYSdl0T)Jr?TDF`!VTyasJ-~ilwB^RkjtCe}ZEo#Dn0rfyW-&PuuA$m|c%lo9Mqt_a zc@F8HjuwECo^`W!ck6%L2u+}UMp7yWd3Zg%MaBg&U}V)T@vQPOH*DTCyJ~w%p~qHY zP^7q@bt*e5D;7$iNE?(Y{k(RlGUvkC>2t&YpTF}2TThbDwwDkB3RAInEJmZe;Etrz zsA3jOl_#@*6068PN0DK3a5QnM&#=cBUsepsyy?mpA9HBVEUC^aH_8RYmAyoFXmV6g z=>81|S!Xt!Fbq;zdLu96zL$l2zIm?nG@fllyR74)nA_vD-yjVB*jo?r{HQiuu%=IO zv-6LA`Tkwg1Hbl`ECkhL?VF!966*>E`v4dzq#=(o>qKO4CyR}t3_;|xB@YZ;wYjBS z-I@hjmhxJTL~;|}Yx#E!ct4MfemkgEMLLeSIxU130?+qJ!%<46o zXNDKtP;lm21wMZ!u{$4`voYQUlO)di(i+JRmI1ar78F(H@m;AVTk?K%9`jT=Tm*im zp?z^Gm|qom>29+-(99Wgf^trnqyD}Jhy@ci@2oxG%6q`~Q|+}CLuhORRWbE)bYMJ> zo8|Cpu0=?BWW5i2viMChKc{RPEU&WxfRAU3bx+jBtjmB78l1Z(hr#<2l-4ONy@*n8 z<7xFLP7hi5AMOO-@79Gszny2AmSTvMZF^1DovKH}as;&{OnV(4bcI9fr|o|CJtC@Dw7_Rl6d?h`Hy&iNK?Zlk9e zDk%k+kfCmc;d?n2`vpre(~iNB;CmneyMtypTsVfuwTj$I3;wr-QvEk&b^oL|vP;K2 zy=U~Txov9{;1NZTs*;I&GslDW0Ux{X4<;pnbjpbi=nF&stFaX_ZqH!|!BwQthd^)% z$mssk^ceZQ{b6YtVgEEaxgGFA)8ujtDMm)Il~q+3j8$yELTZF7=@#nh$#e%28WFRq zTCO*yV?dXxNR>#am!I+Kxh;O^O&T%yjA(+p`U1oHThM-M zdwcuIV(arf$%xo+6-64r1%5CpC*1Ux0*TDUYAWAn5OKAG{#}1LkMn2HP5pCg|X<#=cw#4PnlIteDKolbVf{39JcQTd4bkZXIyXX*lI=k+v z^IG^bbvY$zICpz1ai@uA^QZx@Pyz_{$B?{%=D=k0t1~i1ctO0@Q0&n z?^aT}kJFKHjy7FLVzLN-*P#bG!1c9i(0YVl zMsO=Ro`{yb#~3Oe9K%7 zS?m_r^Pz2L{fEzY|5))zY7ZuADE*yb+8ru^)0=u5uv^N=OcmZyJ4e{Ar1qSkIF8?p zs_?gAytypHxIB>W0nm=5(Hd#x^eqnSA16EkOc+9i%ggb<58ymFxSc>%=&}-xdBtq` zm)G(JlS3oL{_MAU2u^DP(gheVFT^D0J0ajyGfltbuns|Eq0wESWA9co%69~uWn0&n zRdRvb73Z^`0bV;6jV3Z0E)m;9$m_JzFKJ?)ssbN6eT6D{XfOu1RtSks3lPS}t~{#Q z_@k?q+)>w-p0<@En(KP1OtBTaT@K8r|_%TG9_d4Hw35pjPmDStbnM^M9J}}r_P&JK{z9x0x>BjTa z+au*nqg`UBUjwSQNENz#LfWAEqD@DQ@9DLW+D!ez6YsiMJHQ~q+n!@JLQNuj@L!&# zkul#xeY@1FJ(a6^OK+C9&k&d%1~f73hjKmTS7L?l?{>%=6I}G0IIu_d3L^UHU@j@o zI&I+?OBweWM|wA*xs0-2NMAc`vE(-+#YC*29A(JkBI~YpW^F4rQ3EpbHFcKju-SAq zc7-$<3$IbzJDbtybfw$u+9Onxb&rpEudjh(nX54kyg4Fi?ns{MlfCmToy~)|o7UA> z#wSW_F`E52&Ax7QoE5qOPh(#8d%~tUGa8Jx{lm?^*xFnb0|`%KTTXjl@TMS9PmWLy zYrN0o`7q3OHnNk`IGh>1s*8?ug4Iy6j_;rWnB2QE0To?HM!Nu4`e$zfm#ogv;UHC$ zy`-AEz6CDo8HfJ%Y3@wmQ&RTTa9?+9_e6H%4CwNP72jYTZN8Ba0iG$jBQe$NFG6poEPbd8e;{_Lr^kgfhAMtK;TuZl%oj||w;KPBa~dZ2 zz(Zt7`j!OwfCBs}^?Lu@ccIfFdI-%K7E3`~HY}U&_X3}^`IOU55B@gv*7*11YaN~E ziG=%;W}&wCgrohcjZ&(bUZbKJSDfC1hrzwyPspZ0221GHY1I7GCgjVaTlW-}%?_#Y zKZwO>bibGPe4qBY{Z7A9LnQe|na5zMb8=_0GJ2{?H}J4-z;%k9m1gSB#XRJ|LYVT| zgJTtK4aQv6+lV-o@LXOZ^rrve-I`VQ3+d3Q1-5YAXMG#Y`>JbTwg~4htvn3dTkHD6 zd?kM7_|P(~#f`uH04Yyy3m5*li>i&mgNBBjsQ7{AkMlXGJrCEeXX(U)s3)45d6@Ik!ETDQ-< zPBauBT04Sl^TlCBRFba4icySAR_oL6cs)|~VyNj~#v30nbl>2CwFqH;~GxOPw#G!H=QyGKoN8t-`@EV32^sGf2_}S__j!mHq_7CqA@!?-P$x z?OAt?i&aUYnsept(PWj5$DhUkpYzYHeEdBhS$ijyha*WUR(TNw#VJtA?vK8m%%%2^ zHOduXdGF80P+Rc>IBJxfQqeoEixV@~iu_$9M}G8y=ORfRFoj%R5itNR=U zFM-+3s6&QmC=r-*=WLCzv*@Q3HkQZsnOBCht6a3=p(5yANTL~W7ZY7WW>y(xlmHJS zQQ7|_O3XRF`g1pijSas&R|>5i-_E(`?9207v~gTDgzdjP`S=Z*AUFKgd)0otE;zay zf-CMKYJiW^(!eJ9&{0PIW+^wQfc}5on>({z-}$i{+qdNCugv%Da0pxbJ{p6@_0ss zO|was(8)kdY&{vc^q3DLTdWzMziOYYi4s9?NFiKsh5Js@bwroSskzIdB3bHsM_pl~ zaKFHSOhaDl1aO?q0SWyAsTK%QPvdHw?zG)K6B#35$lBXomso7MMU0?%yo9uZ6us#l zLg;X|5*(Y-16OHW>BJ@V^}Ox!3+O_X-bxV0SLOPk8m?_cyLoK6%x&x=5le`;g->Q* zlLFRvLeg#MVVLhv!d4S??cj`gz)9Y z2Anm_e*!wtZR9FyKn_s0&CvtG7=4e&5r{VCm6E{HR_btpu<%>svEmvB{z#M7%LQ}- z1Z{1be28s#_;N{!oOkIxEaw@T7Tzx@CVTDLsfL}LqlAVVsmC^|YQW~#mj-fKC0NF4 z7yp}H;viEjVxXfFgjnba_Op0s2E_-@xix#ER*dHp#&AayEWhV#jAuOreK1LWK|&4O z-EEdtcuf3VDUKxh-%1Nn0w+ODmG8L0q7{`y9LQxcpt$EE#z-__rRAo%VXaWvS)?6l z!BVH0nR@qwC_0vecl^+5yj6pz4lmWcjlS}1{>vABlCm$N&mqMi#Uzs12hZo800k)d zq3QPu5NPZ-Q5Z<|fSK}MuJt^GrA!#h!wkT2^Z21~ZuzRH??+j{SjSm{ZZg_60u_Kc zXV1ihn>{a8`lo5ODn&#OJA5_XB=%XXB;)O$l2p408ibxj^I$~{P~H=WHLx{_n02sT2Vo2vEYhIU<)UXg3+SP5zuiK=mh+ z6ZDKx8ppg?x!JA-(m5o@v^>8^;1DvLBQs6cz_*f9xZZs@#?JwCBG1|D%wv>z9y6g3ovAJzNuY# zKNeZTmR+BJ#iRqlB$1l>63wHr4+Uu_f6EYg4QUm#fT9XEpBvJ*WX^vBv$Rr$hJeRi83`psirgt?IZ(((^y&x;bhit9F0 z9v;X!+xl~?#RQWz5Th|wpZl!>eLN zw-+URw+rp(`a1@KtT)yyC>kRd%7&1fK#CWuL;uu$<*bqL7i?wn^ZavD?@&3V{kSpM zE0bSn88Em87R;Uyx$O9K9(SQrZ(@7s$)d^>K@kq-KiNnDV^>j?a7y)502o|D)z2P} z+*z;?nj>*~&b8F$CBa78(VP-G;)@?CjrF1|6lx5fN-PfbXB|}V2`UT65tu=Ww7jD! z{|i)xK>{dmlVzccP&8+R{h$I7^Xh(I2yd!GAP=9W1)1xc37-Cx8l0?2Vnfl5^PhmS zGB6f^JUtt=x((II1a3wARt~BL1-}bC#HXnQIZl90uX07$-!$E0m+gy_y3dGKoPK{- zCjqExwfq~(;*&di~Kip^dsjhBiXPoRh9Sg%b})L-CejtvTtd z2+~`G}gi8fHNuP~g?P%Z|=6XWT8!p$m!r8-rE!St`wK z{1@%v7wDz7a9rqL_(#$uVI%hb-3d!+btO$zsj9R22Hv)jo%Dk@32! zShK89G=uMDNTOLoy4iH+Mqsr;4@D)kN|AH9oz(Uw@rV}+K-5C)Ilt7)HowbHg(?$ z1gUZsP6Aq>35m(r;9qoYMudVhZ{ilXF_Od6*a)$I3O8D^f>}>W?)pYJ-(|s)fAuuj zqT2gY3{iUwM6c7!=@;=VXUOO_-2eKlq;}^KE+$;Za`%YM#AMm8^d)(PF3!!C<+x!FNLhtg)y8$bz9m&!=8Gg7q?m0E9;iWI((@C1tIj4lJy*+oBSY3pgzmemI%uBe=I*%VnW@0? zKGbyf%o-j*E~X^@vpDgxj|`_0A6K^VP6UPTKru0RHu2kjOA9cIrnjxNtgFNS0uA0l zX5|mS2Pe<*`}j2=E~8ji+4fny2(3r*>{-5Nw>^)DGW#LT0d1wQ?pv`_Kn;G&vh&Tgvx= zWfo&*p99vP0vKxh0Jd1zeBi71G8|m7Lca-@>*HxhnACQttAE&`E{VwVX6SZ<0f188 zC9rKuPbUi9$1fE|(8r2%?vti|1`D_z(CuFw!~buMs8~s$358UITNHZM6r(yZKPmc@ z6Oi%CWjwK{v@#^&iNK6&6wFgP1zd_gLLyi)RSS1gjP!8_Ky_#L1euk3l)vT z^NCdZM71q%N1#iUl%yEQ$^PP6*K;^B9_t2M>B$**^5aKX6AF_eU5T;cTZgB~etKA| zCrau^OmOEV>b`ltn04G3$)tjii7F{9upLN^g+a{oj6;fcLsEXw$1|9eEb$*nmg9pc zoS87TFWt0TfKmW_CO+@-iDbNy4f^m|q1OPO1*_X=Jd0MA&x?K-HfMMGC-3uwPsfSU z0)Vt|9nQ~sGo=RKqh-`nqwdwW#!yV*wVf2E1hJwQ^uCKy_)Kp(fQRou5aU4j;&8Br z;ud=r{RNJZR5V@Gboj#@LgMxnhb};VySsb_Bq$K(jo*Nb<(s?GL{b4*El}7btjSl; zN7n3ZRM5XYT_H@F*PhO5+LDt$Yx=|N22Mk0Ib)LU^4}!F%ca9^o_QnX(cP ze*r$5lYQQo6jOX`oxT9(eW!sHw(!Yci5-7s)p#(h8QQ7z8Nw)*apf~nfbywNxZFYXL& zxdCU7Z7CL`CSYh$pOOhJtS)-MNTom@Hz&$S-Be%EKnb=t<1Zd2EvOhIJH+2*OYuxo zLq|lXHIKq5Y`jKT9vGVPV$`d619lGv7J_zS8uK+-4a7_e;>(pVrDw`ygc}W^UVlZo zy!6OsSSZhz2Ux77f%S{}x};O0m!&B+>r(DUO6S=m%{Lj&MC!tN*H8~t`of=|_-+75 zvlk5W_C_@hctlSZf0Ak@@~c%RhnnadVswd@bvVTYHUYb5Mu{bd_tYPMW}-k4LyVQj zz?XTpeYym1O0@SbhvJ6>M#C~q9C1{~oUeDfuVGNd z_b_h1{7*JQ>98ahNC9zJ#QhJ*7CE)9@(XUIt*~}y%J*)BofZBdY%EukxGiH{>-?Jy z8c&#}DLKQFhm`(&0kJT>rOpV@@J+Sxe({jiTi4}1xtGkdQ5Rav?S(j3=8V`hMjLG) zzCx-`Af^1Fka&wQwwn6aaFSg8&Kp%XjD})^D>@@*9mnP8UY#v$kz(1KXQP@pof znQxCH4nt!5717Skv&HzT9BfUAYfnRz1i&V`WB*aZb)euBJhb7Nd?qv9AeiMKna_W? zjq+3HEGGCS#mL$o{w2V^2&6OS77e$WVtA0mbJ>z6wWp4?Vw^3~@jjf=YY*w3$f;TI z{0CFOmqy)nYZ6XvhTsCjVW`INiQ7wdWz6wX$F1V3H{17``#HvC#=j6!BszG8{7QR9 zYZ|?4!z4*7p&kkG0G!?Na!~MzRcdz1NZC_+yra_Su-kvJZo@OOgsQ36X#y}SFtYdk zvjz&@TWGMZu^szLK7*jeKNG(vzT@b}b>BWr@e~^I*HW|jh~5YznSrkN*Xm0x$t91Y zk$jK!2I-?9Ww?`wP0fE{Dvi^LWzlnDD2{3P0s*Q!hp^7k zGveePrX=P^j0SIL!74WEb5UZysGCcPdfWmDAOSw;G()6XN;jQ3(qVG~u`fnxL_4G% z&uOb!^H)Q;i-P0iHO6M>uXSd8W7@A=2i!(ieXM7l_a5y7WBOnc37KA$^`Y;%5H(dyC(|XENm=1tEkmmSeC&cU|}j#_AN}`I34WYH%Crai@LrB=ew^Vd1(yL zhA|Br%)%4IohYLow)l1Ly`6Rxw!5_|O@R~N-!M}w zP@xgZR>13kT9p|-0{~PV&kyMeIGjo>&o>Po+f#1!OKaGNR3(+4M`v#AB#@sH8GKun zb0{>!F|qt-r<|Z>xgP)POClUzxZv*mO5)6SU^qN2SqNk{%V+KBPo(&fg#_%_zJwZ& zr6Fp0;dLp=zFPy4-49Tn-_;_IeE;Os*iQi2SGC~w6;gMs{V4`F4661=ZYB*i$-V$= z@~aBahTUynO_Ptjd&GrFHx zPcB5ocB|-6P=)cD1%FTf=_+^7cpoPq=*sZ>6(N&Qyu0RQ-b|oSg-(FcC#p60=`j_j z#yCF%hrAY^6EWI*|9qzupv&jXrNbfDYzg+8T+ej(e@Ekh4|he^>zRHAUoO2RTgRpb z%(COZ9cf3sif;23`qdKT65i*nnDuUJCRzSw*0rFcGu3~KE(g_^evT`O%uq>`AlIm9 zt-8&nUo`qUh{5#0(D5bL?s?Qw};&1&bv$J=I>_o0Ao?M5zrm8@0SZgvqHW~7O!sa6;d;n;7RdBu7aZW&1C@5Q&mtT0TZm%A>3rb$9c#ns7IDavXPYDq^m zwBmcE-?bxZAzc3z|K{BW6;CdkEb!w?Y9-64yuPmNwG5K`J(-P^<-wWGUV_P<7$tz@6wpqN3r*En5*_>9M#mwg3VmX7>Wo3}K1_!Fn5(4a z>kfhE%t>=eqI)3{kAii>4CVS&7e@E^)#r8?Q#bAQ2vVx`+Eue5A;o<)VqLZP@szCPI37-aqJBLmt7AZA7 z-dC%|S+yBTKwbUY_*)0W(H>XTn`L-gc*^aT0#AUN=r54Y9wtG+ecF<;FFR@f&!cdU zfa)!e(AJ7UMaNV!Ce@zLd$0Ss7=BwMsFMm!rdvQdN;ny;rb3lz6o6m%>Z$oRd9N+y zkHO^)(S;U}m@ihiP=Do#$`XU%{C;HUi6jYyh==iQ4iXW1cKHHcG8Sb2_-Ktr!1{~; zvI=23`4#Uq%TvWMXaL`3x_lY!t~92~#3+S6S?>$@8u(RA2dE(e zv24Xna5+5z=WnHqL(u<7lEm>vWW$|=Jn!DB_xvPP051Qd2j2vbc;byI#A1{C^3KSd zndJ&97b?r!bKFS8qr|^dSH=Y%pw^!lKIsl9Ef@~VYr#oZhhMSz_vv3iT!Hd4N>`;^ z>Ofl3rJlidgcO#LSL(75&~$43aH-QmBrN~SToi9YJ@tu|u({jsje>YA(rXuT*!{uC z7*+Fe>oUOrY8O0@#5eDKkI&J`Jnqzj~_bbJ`Zi; z(wfULUeQ69BcEu#+rMRI(G_r2lWLaTKYUQhyiNOy&xD8j!y2w0-xcSUQI#bBVkTx@ zYfj(c&-Ex-pc(IpSQwsh88mI@04zXBHomS43CEr56L=s0m3TE{1H|K`sxY?=(OxM= zIr0-;XY6GIiP=7lU^fmV)-q%iyw-%e`oN(vN2vyOa56xS;h#$X zaZ?`mKDik{ZZPJLhW$S5jnfg3I7LCn-?K1#l#oHln$6lx1B$0k0bb(IJsn7P9GPOP z|GF%#i46U3E2ZPgD6L#Sn~(A#?Xq(Z;d=0{<%GhkaJCsCiPq2AiXcKc*nr` zr^$Th4w>$cMbxlo46_kUIZ?=bJQchSnu$~+%qYK+hdv1EJ`Ho3ZEt0e$})@9&MYjvIK!oZG;Y8kS{w4cNblA=TdDgmzcg&17jta_e4AVxFFoQCi$^ zi+8{BZY~G7Un>-UOSQu>Jx3%V<6k-EU68;C5X3YHr(P;+x&tlG`Q4CC!u1ykd;W?N zKK}LLZYM&g9;0H4=st+gGCbS~?mL_``WT(Teq43oqf@$tVYTi&j5g%=?O7o+cNpF^ zUq*Tugji|nLRA_?IMwBVXE zFQHA%8$+w=wxivRw)-y!KP)6fdN~g@$`L?vkB(uI<`2>Tp?IiBROzYE+lZ!DL$%Lo zvm14GS};&Pd~Ms;@v&5M%z-J}-qbzhO-V`5U**-Vw)tM(Pk;kPk(C~48(r3w=hGST zM;|hMf0)<{H3(;Me&11+yHX&OtEJlBs0<<_?ri+0?v;7eGuaz@t5K)bn<Un!ELX{g<$>!ks(;KJ`ZY6r)xi4>co>Q%$R7!Xl zg{e7Ct3v3KCZrmnw0T3_$EX@e{9(Kajpa!_s2@_-y70w z9V9>N*k_Y2ITnMzhCxLo|M6<$a1wKm!037LL+}|EhQbijQSM!P_P%Cc>H#nVCEQ7p zd=!YGeJ`@V^3o1*9!IydRguK=NEfUQY2I$k%^dAkf0A4jcM2RS#VZ?)&{dVpIYGT2 zQMdg-^u(Lb-5zm}lRmb{tWxBx!xZAfZZA-lCLZI`7z&P1mHUa(#PK5|t~hQlA+OOZ zRnCv|P9Bl6N}1VVzymQQgX!>2Bqk3Unc4iyy`n1Tvf&4u>Z`qNm44G?E2h+XNJ}M! zOI9U~_IXnBtCUiH0XlI@CGq5-atwki1NiG}eDbneI0s?eItx*s_2GeFDbHW9c`2jY z8#yt}iOHmNEI95N2d{&@I5!LayiBV5-u-PZh2)zZKG()gKQK*@!b;rrxSijJGoyUaL2>DMV{iu|R zcOHY5brH`k4Z+pNv+$1Fg2;W&C;N|(`n;h1;tBho*Xf4E-BGH%bSyvkQG4*eky_gk zT$vH%7j1+t z_|conTRI}rzle>$%R6S3PyA3v&-+INI0$ur{4~?s>YEQQ!GnL@+*F^db#w61n)6!)WOB&xscaU+;PE zb|0Ak{xJaJ1<@`t+0D_WTgDa2Kvo5$G)iobYqF~-!snjpEs_ITYe)yf@x}%}cDy`Z z_3j4`z*`;09ry04pbpFA4Sdy4JSf?ok~AGt!|L*+A;Q7=3xPg!^~z}>Vn26t4W01{ zFS4jP4PCtm(Emf)TL#t9wOyFFyE{RGy9IZL;O_1&!6CT2yF0<%-2)ulg1Zyk=OoYj zeqK{GHT>$LDf-mzZRg%=U2EV%!}l@SaUyq#rM~}=lWi?VFGlzB+4=(#M~&E(poSQv zAjx`}B}Q|mp(Z0%43Vlc!jJ-yS?bvDnuJVb`$il9<0-MBdhWd=k3O7*SuFf=(->;X={O$uAD6iOza`JI zdSKmV%UYKAsXV%2`F=vwYGL#-MCNa*XGf)?cKC7Ye8_s%kePWbDz0{fU=u>U-6@7% zKZBCU{EED2qT&u#5A7@37Htw^5wO`C<(B5!$0OrL5PQ(M<|^-yFAWlAmWw~s4}mwW zydEOpRjCB0P5^r@C~ZMP??on%x<5YrOFkzuXh@6UL5k&;@ zSJsUi^MT3Pn00EpkZZP4;WILv4?okBj8aDo1=B||&$+TA1?>wjrUDBq9hXa9J1H4<~~|9F}^{yw3jW&PbTY7^|R`F{Wd*q-yq4@qKdbPykcZ)#nv znT%9wl;$}@!{UiNQTQv>`;2`+bH%mbc{E}QO7sSJhh}Lx`?<|i59=&@8v&47zjI)e$WK)JO ztJ&@}lY?D+w9M8gI*)oXre-GlHFZmEm|P>CN4#T%r>_hoVk_l{A~i>&@B>?1gQzmq zMTx>GySPns?r;9fnHnK~T-Cxq)GBwrDtd1sejAAKw_?=XK%8{ci3&AE`>{42No<@Q zNKZi|PfAH1$mC5%Ku0%YKfs!lVBFQU7oAHtHoE;+@fkKCq#yO71(Il|-NZmCuXu04 z(9Kk-vzSW&xw8XCp6w9OmIuBVVouhR2UFbU$ve1k&nRK(&6M)+f`_zWNVSENrE;fg zo_7{3zT9j*xvs$@x|OSOHXujY{2?LbD!#$9`{aNa!4@7W%a%*p&QaKrm4xAo_|# z`RWuN9R{Y)4iEm|;1K9->(65lXz{WmpZxx(dSy z^;dz=rzty5IeeBd)WbC?G0DNOUlxJSiQmqAl$O?0qTZL>gu(Guzeu6# zc_>5KeOtcGm|gJBI+4IT?Z}o5PLRv`M^ZXt_rNIB|BYqV;&)`kDV4}}a(-EjVZl(E zyrX;AoWfMOpV8A}{?V@tIC0SK3||p0BSn$Y8txU=^O1rJv(40D~IVF(nK#6CKusI4rV&>~N)TV?Q9HnRd`l z*BE6+K)q)3eOo2HR+9J~#I&`M*Q29L-{yCLdeRb?+>Uq?QtX|38|`JF#pwV;n7O$ z6URYw2cj#;6I6cj_y)s%NyddaK0Fv$Ip<9H%sx$$Q1pglU|E@fZ6aCNWewc#B{8qQ zUs7v-C%Tf46T|?X4l|Tqy$TAL#i0utNnn8I3iWLB?iW{IzOrvuAv@hGo&w7KqcbLI zj*`FpGW(XPCsNenr)anlOYp&SWjHpzg}i2#c|za45Sl&1ijUxwArTN?k8Wu*k>Qxmony`o0dH!!o};4B(u?t18+3{@ z&SwRhxe#g=wXLSbiknKUK-HzOs=wlZq&l1vcSI*+Ze+8@AxWuVKs{S5qdv4-XzkPj z>m}S!(kXZQjDd0T!V1a%Ck4~cVKp{27bA~9q;H3=2cqT&AHuMf_Ej`bP6HVo&^d%U zUgFSJye!Y}yq*I+=16w z@o3A@_dk2`5C|^nUrV*_6xo{<9iWi*?32vge-i)!JLSl>+oR`SrtL({nBLzc*EsNE zZdBLLa2iLx*PV;`E;O_7`s60q3}|UrM#gk=FpR)o65TEYEDkJfv*4D~PUl_Ggk+}e zwxEbf%-7K`Y}if$>{g+g-t5<~zB?Bs(CB&QWqY`teO*xMW1k{1BEKLHl#Sd}z{O*4 zEfpaX83y>@CdMyr$X^?H5VMd`eP?^Y@U@W~H$0Cv-?nBl*ikK+^qkU1pL+hpcly(e zMS;|3x6?D&z}Cy@%+6o(Db^PNIOKh`6D!?gphzgEPX3Pjb52xdggjae%?Aa2O_@UR zkFXYgSX$RuTWMv!QNf^x_~iajc4qBaQEF2IV0fON*)F(pseyn=$d2qtA6CEz$k*ek zicvv?`PF>_hv5tK_Kq7000OBXQ`I|qJq%I$>)}zj)5Eg;3zYA}obpw2RTpB8%7{`| zHi}N|o`0uvh*GE4tq$SB2lmJ5qC|}SRJHYV9h7Pk4eg*?sEo~sL~7aOjqJoRoUl1E zu{nJT$o^dGF#Jz*TS<@(J_(sX*&oVJ=K)D3e)!4{UIoZqp3<16JBsY@!X&Fepn#CV9f%yf6z%c@8xx?V{a!Z+2 zTsn--+7;oq^_yQS0m>$uj6w2 z@^eDb-4D|Dx;0o^W|S*qwU0-Mgy-2PFGV!8nT}&1^(Kvyh25Mx%l0)_hd0)M2nn@# zv%ekmtCSDdw&?xG)`ddeF=2?xNb}fqUBwR&ihG_s-!Ss^PPABImeE2p`s@WF zdWt(N5B&I#MBM=bCI2P<`Qj?1D;0`X;LG3h;1noeUI_)s{aNPiRKw|lrxiC1fyJO; zf#k{_e)_snqAHB&>AEOEa;#qJ_sOFgR$SM_cAI+8aoL1SFw(M!&hyVA84^B)5$L3; z+A0CaEIcywR06J9n9|GHh zWIcfXrAT zZak>OpQy*fqtBM^)sgxFdweYD5ELt3vBR&h$J~wmpOBs=+8;y208F`@~U!tU-kqocG0$h z7UkSlhSI{i#TZ7OUhrU|a(SDB@LlC|_-21kEbi00wk$$tKr5SZ1$lf&4TJum#nTDRX5dW3zyJu*=Xx*Dv6Vgf3AcF_HYx0=qF zv9w?fww-kMoj#>oI%M}yc%B5Rz^J*PiI& zq8Nen;*TfBqiwvSG*0n~lQ!m5o}!_G7!Q-{b{4XbM0Yn$tgobSQcWpj+Y!Vis|sI! z(rvZAQsrR8ne13XS8g=a-AtNh-8v7|GOt}1sH`=s2>qXm(D8vx?^KL4fB&RI_c?zJ zS8h1X8hN99zJ1IM2qaoY!OCAfbnvC(-bgRH;Wj7{@xESP4j#xbWyUw{&O8Z_ev28JmB-(E1j0fPC_Uj z@ii0|yVEXwD6-|;HbqwUr(WfJ*;$o(yHg@^gHWz2|58a0*w{cd#+nLneKR}a^=3vA zpfyP-L96iLFuXl9$-QegxbTM_9Yq-MRo8w#DBb@*l(U6bAIYRvn>dZ^#Z$r0mf=FQ zHDr+$#8NadZ?ggKoxZ0VX^rO)oo7-nna%z;_oZPoc$6xdt*<+byFc}y43&I{@o#o5cf^w=31? zEKl(Y?q~5!1of9-YuZ|LI+ucgKF0g@Nn2>(hsGMZC% zIflkkKAey1rI5So>cDmJD@O^CH#*tmk;X&Px4Oz_tr?Mrk(|3Ug=FuNGYiCk$lf8 zqkUo`J~2tDjVQYn#8R`^CEze75$|#6lm`AQ;erHa#pxG)eCE7>-@jMI_L5CLkrabi z$v`^gH|d$iNt(nZUb1X-3u&P)Xo*^&51^psh)GvQG}|u3V-%C{Q>#m8Pbg$0hwbrN zxuVd|vxQ1V#^eE%j{wa-#l9Z^MxtRYZn)89y$S>JDpxp8*19Zp*RH69U@II;Shh%bJu8ZhUh(7jZa}ukU)O{dN$YdY( zKmfITZYY8?Kpw$UAJVkfjy@gty7ws24li$03^_VUM~cD8GBXaVFGY$ie=rsQmd6J8 zN7KKGxex!lnEM~UQIU5k3Uh?+kgU--@<+!X(Z z=c+SgUs4?x8J~+1J{sgbu(|U1JuaD?WXDnZTmV*M;(VeI8CN=i^on!ehj&iX|29m4 zSKZRaQ4fJgVqg7~55v}B*phxILx)aONrimlApEG*v^dyu6!2iQ@6{{$M>BiOFMDiJ zQ75T){)yH*!bh3Af8GH8`$H&Ds5%LWg;UsEV91VAytSI*I7u4jBOjp2+liLW1ondc z20{CLzUyhR=Eo@>Lm=fVzE#@S1?Z-J>Kx&=(JWgQ|6UWy5aegUVIGQVz8-S9oO3jP zh}~Mf4w9={?Qmfln6vBcC~=IT7I9QKaqX;ar6>m~+jAUBoCRgL^`Hy*@qts-^N3}7 zNn2tX?Cxv9aaQ(atg^~S&3XDc=%#7DTPqH`XOOs(vcTN9#QRsvsg^RK4!N zMcS4J9wS+dL2)E~R|IpD``)J|`qtqr2uwQn=TKpNMEA|l1Drd z>}Rt1t$m#nD9vqWf(%=U+{BBfs|^yMl$gZPg!up|;-(>=X&q8ITEaxucfm3^m$omD9azv9jIh zf1P3ER(-7<3M*DK`|%l29<~A{k%_Btrbi(21LoB~Tn>@1@2)_DQz`X`N{tokc7Qs1 zp`m#IhVg{h&S?)=Kj;beHEj~W5UMKT55&|`(WH|I^LLCK+t#MnN3%)ZVK1UarP<} zP^`@Wc=mzw`fS~KrR<$dbY=tHqTfm}M#%<3J<3~f(GTJ8sy(N1^&@EyrnV6=Ih;R8 zCWULjTz(B@z|W47bn@dH$IxQ2R)aQWeErcYJ`l-0v< z8=~_>Edq5r##0{=HV?47x`W5bH33yjaEEU018Wn6k?N3TI^%P@KdS|^VrByQHM+*Z zPr>C3oRO8Fva>aHY^Oc%?vo37`G95TnxUyuVUvxuz~qJ!qv}icGR^bEUCXO78S{a40h^vEpUmF0KFtl)BIAIGnJ%SofoQ(F>N z2iluNJNJdQ{G*!{JEf?C6d0^?bt zLUV@xkT;3#FXi;qN$iUaUBe2~_UTmkBzF1<@kg9Ga`fM8lg_fS2+!Ob8n^+p*Wa?*FyM8v z0sEDgbx*G8c8p&1t_mrr0lLanQadaov2YET9why|p}me{m`scNv@_xg#NZD~g|RHW zcSlhrd|;NWbdIkK%U|q5KX0GaA3{aSAwzUZ3OhNmBy0?C_2p9^U9YhZBdvb=V>%;$s1h>Dg_ayyqu4)lNp;(;LdU0!!KgYgnM|thTut^B7gHY3`VDpu6cp- zKZgeZSL%rlf3BEFO>JA%R^ydgABC@N=mQJk{hBNVf6jP${HTy2pyh7VM9&OhK?3-~cO9`$MqR(EEz8I+v~~{Tcmljq zO}9{z<5o@qSvltgR8^PrARPR4vZQ$^T>)QQ!-wq9sU}>43EB5)%Bpzz^zK))e*cxd zl5+1)uLG_tVapmB*$awgxlfYip{cR0_su@gOvQk?P2*5+*l++GBivQtUwZ3p|(o z8LZ2kP?)W$imO!J_p{TsE%3m4KxfgS?B6zsCZ7P6b9AJ?Ce=`^GA4BA=ULw4` z(RQb{_)iz7mS$pX?wXzuXv5g+9aps9^F%{?SK~_| ziY`-~IMa^ce4J;@#aw>8fK#r~_d&f?$Ee z)rJNlYdXZjpmZMl_h}jAM%K%iF7AXSXc}&8TCowTY5M`u!vdh^gl~;DM>(}o(r9^_ zn`d@Zvs6&~F@8Im16W@+tXi4-?lExsPBQQlon3 z1_zulWno+XpE|M}M0B=26R8Yv8yk1RKHQKq#0g;T&Fq%eDGNi&Ke|9@B!6jn+(#zJ zy$DN|PdoNk0~r43X%gsy!qB5=*wRgwXThc6HjzmZB_15SpC|kM4^M)A&TvYD!+_W{ z_8?v}@OePk%GOp8DLz$ncWdze7G!*W7}LBwFs>)lLJCSk+m$y!4;_%7^Qri9f}rIbkvz0k9zmw5RK zjFS#qgk4Gm>%8m$+xIrHGF)FNQ-N#;8haGw{pd9l5wt0`XB;haZqLrM%0+*(yfBn= zsh=g>1KM|XwVf#OEo6!sSmCZ52Nn%yxLn3ynQTC0HqFtBc-9rP8iBhATuzV=(g8{u zazEg<0#)*tLaCii=EG(Uf*r7cJDBT8P+f7C9wmbl5NLga$c1Xv`v!<3M`RGkNj{2pGnFRa81{ahO5>{!D~c5 zF~qXkn(J$rJ=Fj4<8CkRV~<|~!WpG#Q!5nIWYPS>1#ATqa8+cMlD$AY9)~Ty^Nrkc zBqI#T2R41OTdnI8D>$$#pR@t~G(NS&u`m4uJ@@txzn)d4Fpg4C+5QDxV?x zi;_vm&o$6T4mbtnY#BW(<=|#%fcso)``zX<(0cQr`nws&XI$Zw@=+T3I$)W!QEm&G zfzVUviRH+`84f}zL4p3|$0k9<(`C0EtQ|7$SxlVNtDF^zYwBEXQEl!Y2ky3=nbQ^A zW@_v%V>%C{F_8OufsjcSSg^k%yf~4|i17yak_Q01$&o(O1SC#k#NHOH&GAdRLX`)| zeR$o~ALJAdLr_I|%Ow-A|1uxA z)*e+nB*h4gdH=OU`KX=>GAk&ML-}mns#5j;+*~!@`#cnHI?Bx+6(yJ1x9?Q!kSsw* zN~rh!AW>ywjwC({Wd_^K#DT-zJZV)~d8hHlfv^)Kf83A*6YtE6+b2eZk4n~T63W7CFX|MoJI>d}*p6V_2zF6r)#mxF#tmgWiaeGlw}KTGOk z?qrA7H}GdR1d}tI+0J*&>}j*tLJUI3b+ua?R-#m=F<;J`;A=;%&x@loH^6Ftb6WK$ zVUytWHTQ4g^mMAoWzYdJol;2(Av%pSbt(ajZe`58aZ9sE2L?>aPEY7#YT6c5l# zP34OYp?us;P2Kvk5W+72KeEsHT=bod50^a)C}us=KA2zIobpA@+Z9ZRFz#v06R6p2 z|3YEQ1Ip;-L^lUy(>md+gXsVQ+h6BgKvD>iL}H}H#v(`^&34^A$%TKJTOOXpzP>yw7e3)f_+tnqc_Qi+b_|rn!ehDH z^&Pn0Y|pOY{qnsVW*?F<_|4J@yAeR0eZqV=Z-$Wq8KSn>1cvnCrAl5tas_{9hYY*5 z*hOi$2Ftjd_>IkW7h%(y^3JOvb!2-K!@B+Le`6!4=Feg)aJDt|a~yz+^@m5u4H5XU zrwz9QrksT7_T5-;ZRu)NIJlagfgbkOeMya|+9O&ihn%=MizM?oClSASK{_;(G_lc2 zExQfwkYrC6@`XqStLtVfWr=O;catFv!G!R&4S`*2R%fNu0cOKRmsZX@;aE`CT7mi? zOnNKGco7Yb9cweQtbo_hd;!0~EvIik(bs{H z18NNunxrA0)w!eYfo*hpY3eGHDo7_Iu*YrMNDa#3U#wZx>3_+@Rru>127edID|{Lo zuzh%cT&=(!X1E^4B6ge1s>K*F#*D=|9m5tMv`p6UN{9(EKt=#UDO!#NtGEe+tClG1 zW^&pOm;M}1l=binQ?-2|JYQSMKg_GskbM6AEjJivaogD?_YT@eJ|m=kZ#e#on3OqF z3%)b^_vfe86=YO6)VWc=_|K$+_Lp+az@!+7o+Ffs(@@*A!xjQet}#hk7N^TBy+@N8 zBa(DmlYY(#mtT7KP)q(*7@FZ@cwbgwlcqhD;NURev%=xyQdAd2x~AfjNmvhHb9#OT zN*0cWkj3OuQ8>!cJ65gAX6`CzyA~9AC5vfqWeEr<*fgo zE)cK@9r;mkAu-Ar3JqY;wiaaOlWXc4ujonjfC5y3UQVku#$O8L{qDR-HMcb7lCgqE zHw62ayzHe@Cn|rj2WH`Ee$>Rq-grs}S`*Z>!ky9X{#mQCa>ReU3VH}01eh&tB0a9 zW9a5?@HO~#rP3_GqQ}ard6s(C`7MNl#sEEuaInBK4i)xxiLxhSFxfB zv3skmzPw*<8%N3WnWkXw9CxpdQqPa0yf76PmOp1Ce-s~~60-2Xz7eLmqKuNWCp!@1 zSc|=nBP?T1+YJaED+8mf>fc(}QL??W-usXui7}Y%$0Cf=A@ArYX|Q=PdVU4wzjdPO z5`bUE00p%eP3Nh0RKNwgSj|f0DJM^kO=&Aafn8ZXxgR6gca;XPD zDF!@;Z)<@vY6D^n2Wt`**)uReD>fto$Huv_4`C?0?rHcatDue8LNoiL2ZN855H{W4 zs)~V}B!4i&k9FmIRR8Lis-oR47 z)r_RX5nv4I^`;E5Znr;!^g9*rsr;qYI%Ko_34Wqk(@4M$p8(xhz9CJ`I_03t6lI8scT&7u1kig5^C+Fo)#k37GyvZ}0dCZ6Km7#d% zWnp1swPmSF220mgYDS#_ZopV2YMypY%BHGM>r!xCmR@Yt)z3YCS)*YQ-+w7VvJvPI z@kHo8?X0^bwjxoBW=ZWC)-xZj=(-_ytGek3O8US_P-dHHCU*SKqAi7`NN(h$Q5~F1 zQ$B;sQY=ES;$hvu8ou5|WF5^`%x~WUoup{&)NjUbDJXjwLp%K`LutqDc+mZl*>UgB z&pUEe!!Rb22=Kx*93_|i z4-Kg2lp_4^oe_;ggUIlaM9IfEa@1~ABrL3>mTg?tIl8vk<6Kw+u5AY3W@HGwg>m`x zH-Tw6ny=Q0N>Ttm&oHYRn4I(0HhvJRxm#~>F$khpo6)gTLe&(+?o0p!6YFVkFFCad zmqDLM^$sMBzX zDO!XZFZtmGZ^Z?c3DHp`$AMHZnW(?2O=@ya=LoFE^U!$`dTxqyX3qmsn`J)?-^A5~ zwAx|MZxZcmaqn92?Wd*x2Gmke8>adgH)^BFb)y5(Oh{3sItrOQhB2Xx0aIB+NU13( zY-f;5#S`0Imk0sK^n%!|thaC`^mljrv}8<5E~DGA?+{V1f$ueHlH0WgSaH45dtNAn zt25y#2IJNNCudd2h@~xDU7;1V1%-2rT^TvoSvmXjz7>-$gJC!4MT_NkPxsD5f%6Oh zmO554{*^jbEr_V@^{=JbT8Fkhq*;T1&QF|KFQNrIDxwtXkGYiOW4)+?yUj7i6b;kb zghjMbA!HVF-~Y;8*^87(wVziN)uV_>h+44Jq~3;G)kU`oP%8Z!q69O#1Jlg#pCL-J zAc85rAopO-Ks+n1J2Qn2&@xV!N%$0g<=H?;EdnoFoa(!TLg?dY;es1>)&5Ubl+sIN z?0}Da#T0)iewPSvP^%Jpx2<)Y+^e3>es7*vXCO09qFI_N)=yk#N+Cp_hIJiD~MT?QdFGdPYdQ41KNhyu}cejiy+iw&=BzZy-q)%juioSGu72N>j>rZu!0*J ztyYaHisT-F8|1sRp&w-@G_X+iPJ{4`v```8`-Ze+_s$i^(&uHMHN5PxSba4De;0T9 zTvHCaIN~VIq`fQBGhp64f6^n$sq^YWD0W60SwD2b#HF|czWmeJP(wq<7JCQnWO8+` zQW3;Avax>DE{9Vj6DG-I-+;1=rbO zg7Xqvh0V=okgP(tvgvT8%&=MuTYK9z>-l05TT8*VsA$FUbAaJSZ9p=bxzkb7Za9<>e)c$6i6g3RpQ0opDwbw^qsta`%VB?eH)2~}$g z=4}e8Q74eg{z-x))KcpGa!=weH^Z>%NT&)RE}?^9y4x zB6GaZ6nEI_b3DX5Nmz_{7tq5EGi|KE2YU9JILdfZQ1}HYnjXB1FJ1Stgdy0nkh@@D zVFM~GhQzkKMQ2`Oc#z6}^8VqTBk-xWP;#ORN&WCEXICS=Y!%kF<1k`tG+!B7ED)BO z3~VBxNoMFk-yZ)&Q2hJQo~&RFR+ZV*`YUQpr)3)#?*BrVg+z#LK}R?cM99(=o6m-n=6x1h5HZFwXZ{g$XY=r^;sRe8Ta!Jup_B-4puaS zr7d56_f)0aKESjhw<2r@BS1({OheuO^G>g zsX15E4?03%%G(RSA4%wiu~FyBIxH9~rHWR$^9yj26~PGpy4yl!9};2wC4Y_*+)+m& zbc*j71U-R{LhomwERE=3NOcj>THmfISJ7T)Vwv?d#hatnkhk6?msLKS5hM_>X)u$o z!jT0$Lbw&H1ofB9dv0Yz?Km6d?^z2fbK)`ymaqL;4hw-8LYmf1@Z(?8t{YP`uGHg1 zE;YJuqd7DTUUa{!m_oc~=|%C~^7K3p88^kzgEE>i>N7(bS*RB@;t@;&1!rKIr&RAm0kX8BT zHPTgTrFyO@>9<8iDSqz9$B_}$zB-4aIF?qf?UCn$$&l~;G42SOZsl-Exw-6AgH|K}kP_P>RE8(WViKEn?{0_(0Qs}&p zU+Wpr()r_1M*>-@A$N9G|*=vf}B>ov^XMW{~> zyWXv`t5Gj)5dsOMH|yk$CHG5LGA_7nNPf?^f+8~7oL+jvksTdPsl{;nlC1@brIz*% zrgIkFa`(D56FLO$asHFFZw^hxIUx;$aSNp=$+&^6M1h8Xu$cykQxe$q1tL&HZ@Nq# z{*;}mF++KZdN9QkbV9?~Ag%X#ycd~9|3E>HVnoIpdhkr+QpF87)0!KX_`9b6D(JAv zf54IBZnf#-bw@?HNO}DU(8-g;AV0OTH@AtUSz3N)*3+9Un*gg&cWNpI-KSw=5T~UU zd7RC8e6ql!{bq9S?8)|ATP6)n%;;p?kG7OqvnQCa22q7 zaS(7JHdBxvkLPgF@>X~EXj8duch!(wu#q8 zX*&SR=vA)|q>$bZB{yU;Jp-G&iy_Tx3zUUrpmuWs>u&TuMMP~^MTNp>%H5zAa;0Pp zq>76;y8lBxySs|80INyR14+ST5MaGkqs!yqm1!M3!PrIdcMH}Ov}io~DSq@5<)&$; zPavDE_zm8u6c1%FM&56>xj0oT!L~~0n4<3Ba@f)NolN=eAdR$$mU8m##Lc4O;1i-} zS0J%zb%-~~g#1&nU}|YM#X^_}pJc==N^X*N^mAMxDP{Vgkg1Pzi`&AvYyV1$4i0f4 z++G2iO4*`+BZe4eNK?dL?OV+vn}DjDKu8OT`rD|KmYhq?&dvIJv%u z00n*jSE`4KZa_${WoYFzk&480M{1B^k4Z6X31i4oM#SPXPT9(ckhg%DHv0AG6O|mT>p0iI;>i4fh~;Gu@o4=MHV>noVgM z$pU>ww4nUiS{@!>2@WIWqyhOe=J>Kx9*Kw$^d;N;&R~)&*7DtMy^hZiE^Gfh3_(T2 zrS)rl<60q}wV=35wp_-E1HR z@p-Zlh$7qs4e)$(jN$@KTF;D<$LHL^@B&*s|ED>TtmIud&lOK4UCQD=a(Ay>jq&Mv zQez|5y)+gYpnZENO@>6_wa)eKRvNl#0VL*ex0J&^zi>DvE=hVwu^-g#L}NEEh01tA zZSR-P)c^E9VosnErFc8zo3)Xh*L*t~VZi^um49xB3>~;gUdvI9)U5#?3a(eiA1NGW z6Llga9<~}c9g3f|p@pLD!yeW5Oqq2b0DI$8FL2kSYO6kGQxHMuP)+2evil>YTr=|8 zPdVZWvukGakRQ!CLV*F`d>%f4l=}BS+k3F_uE8t(MU2zLWhzERe8~hz89JZF!?tvEL-1V#I|YdTD3xr|C-7h?VBtMoW+lad#Ej z%G4j)G|AR1wN3hX(onx6R}8eV=&G zsK=hFdhh!)ur|1$!ly?3F{p)*EZ*O?$6t8pW+x}EkfKOggOTwqrBMhn{9*@G3;LZEXQu?Vrd>wM>V44 z36-Lz9e1OGzC0LowD24-{vN!J-G=zX!o9s>L?eVlo&DfPsDYegcC5!=_qpFODpHs> z?L&rFeBR_dYXX_0lncr1K)%_v55dL5CZ_cBS5ljgK6WLeTvDly zonC+xKmt<}E5zDIiQ~hS+ohuxLn+f8B4~j8Aqx8j`$=pS6tU>{uY*^UMUWPw+q;O8yu<$R7ia9g$y zyRo|Q)%$E;-RT5~0u$OtuZBp{Uduu5vSY|1b5@c_yyG!Z2|=s6jMG*S*vXzvp{h|A zk}*ei<>H`+kzI#=2s_CE&xM+;VSSx5zLOc6Z}S)6uezSaLLMsR$5lOivm^K`D!%~$ z3)x_e1YMAB$`cB&E`(KI1qN<=WX4QL2q`HL0`(D+hl?dQ=J3rBp?4iBFr2n^TeaK< zo>TX4?FOYnuaq0)w_H9+rMGSp7C(+OVM3I2)qP2qG`QBCe6wUY_=YMt;|ZG+M;dP2 zvTfdiqM*K2Bqjy3whj)44xL5)iFmYlw1*3l9wOzj?}i2l;Aw3rB9!gUij*+jJALr9 zYyYRC6$)+2N_cquxV4wHHw?M_m>m8Xe%k3c_{D5`EM2A3hBjfwlRtpHn1-q(2vJ6f z=iPuXoz^K!)%S**D|EHb%k9`>J>HMqA2DfT^QB9Cai1Dzn>e&c1c?b9rLQwJQu5MJ z;}#iJE+rxEx|Yotm_y;&L_|1QRkzK~T1?x$A0R*ZyerH9x%%>9-K8%Qh+mnO2;43} zhgwoIJM!Q}7fuKhc=IIbPaabjqV6wC4_P1;rRqr}vF+hY_dyus;;8FUrpYlD!)IxD z^5j-~=LLHii;~E3#uH%2*h8_-z0!U6z1B!O(rPr_)ipES zb?Th@_Z8s7{zJkA_F7IT%FAsHv(`yTigM`UL@IpK0O9AeLDrPg=4m|1fq_C=b4Co* zFSKa)aOn9Qg40*-zfgoi09Shny?{za%zJaSJ3=8>Wuvy!@SB(J+)OtR{`72+5Ft8| z+0Dm?UhJ9ndSMT^sjC?)#yzP%UrtI8K#!gaSr`0CZN{F=#>bQ6p(OWu zOJIm8FFZC6>>%Vu;dChjOP^rQR@+1TF@OI&g5Dee5|Vzs+X6e)EpFHo*6iXbEGbYyfIn1rME!! zwI3R=PoY6XIK#AvEVlzyy$?C_I3Nh}d1quNys5a1RyK(ikc$E`g+|6VhS*X{mtX^nQC)6&>9+m9# z9VVDLVxTQA-hD1e|0(isOq<7ic_imN&3B-}UlI#$^!{fI5AP8;8U9wo4K4L(S2$sG zODIn<+<_0Bxbnf${n<`$mcQQG+@AbYs&AO)T`2?38=O_H1aPf+)Gx(CO6LTZnk-*M z#O((KNqAYDCEYbPJ|kn08WMb#;gb9>V-a=zMn)t;rVKSvdO0oA6y1kJcY?2O>3ZNtBR~ z0ravrCRPP$N_Ii<NqNtVvS?A>!?dH;#{ z&j^HF=;vNj>m6|3=|(zhgcPAsz@+=cXxdzFIhCb+rJSyf#a_KE8uxk1r52pxj`w65 z?VyXcz06UHHwVTy%8`WvH(%-Idi3zBJmhT|M7-kpr?h5_h$>Bq8dab9v)}COhPxg~ zBX7j1?ozOOo&_4nQPE3|*ec2HfTsbVkLR~?T0pU3jRi&BK*2=oEV0Z6lJ_uKHSM)D z^&f8NApZc*?w{Q6?8rM@X1SE8OF_%`-qePzdtwrJzZq-GRT6v%c-6cO273;GEo`H! zlQ{{!qzsQ~sM&;T3UYGEKZu`S5UU>60(?ii4b49|cs=IO33wV}9~Ry_yTB7(M+y)u zC7ds$xRG@yw!a9ah@?~$0M<_D;%O?sqLsBede(`%av=5uk`yXDxsDY0#*+{TpMd_cuff+o`)V(T-@FPEr7KkJXws972Xj(S)G`v5ZKM= z_IRTl*<0GGs4py%80;GxGdFibeMiY5B{^_$0F;}J@eqrEU;zA`^R=hFOQiZ+@^_8% z$?p}9Kh=O1=p%-ghB_Zn!2#lO>1c$*YOR};QPZl!8fJetV&W=ngJkMVA@d<=26ME3 zOQ_~ajVJYVSBJ($81+2YjcYL1c&~=($@olz#~7=PJ4T&9i{+=eoG%_<+foe>ADj(Z z_u=T_c!s?rQqfkCDZc;CkC8CWw~1z!D+kr=R&wip%im0{aaM=`gl8z~Azoao#NJxK z%^_Nn6hc%=KsN0{^keQ40jaK1-;#HgJ`7-CV%Fh$!k=k*Wpx1&&9t=(%1!a!>KvFp z##suqrJaF~vGo?_S_*N-1`x_1uS#>HWIn?gqLd^IN-){~le4q8l+}U0g3NDjI}*Zu z%nG7|(yAf;3I1?y*&F*Alg4IAF+;a4P$(u5V1|gs;=iT##Q2OL$RrSDQj+WyzM!M?yn*ZVqwrO~LRH z-YWf9=+noe$WxeKQWHK?w|Ac`@%N}2k-e66EHZis3kxoS*FRZdtw|8zlr0)Qw-Bso zHO7N+OUCOv1{2#*k_tUAxw&OK)%CkS$QS;!=R3Dru3`A#VZER1r}C60sAYRmTzwpd z^NPC>x94eE-@B%V;;@++j5JAMvsF>`JXZ+%%s}@0nm}oA+J@G?O!bw(-Q3H{-#tWgfJ5A!v%m;3I+xtt z5S3c#G`CcfgX{OG-L)5$CcGY0i9eeIB##NF2J7h4J?B9PKDX+t0ERpv@rv z>BYlU{R@R_p)v-|LhMI)$`5l(cGT4h<9;n4I7Yb(9E0s2kx-3V15-Iz*}o+a>zN5G zAxN7=%Rs`0)EHu#G-HguNEl3>QQ7>NeZRHq@59jBTe0$^{*p4leea=*bet@vIsaQ( za*7?^#EoY8Y=bu@osg|Ez|xplz|Ds6d_Le_h703_o!PPIc+*;P~-L4Sg~3E&J~UUHUHl`kJBeyXSH z;ChGc1s`s#{~n9o^F=@5ohD@#l;+&OQ_cdO3qLsj8)Vdsz;6CB9qR9|%S_{n8U&WV zmEP7CqJ4It$$pJ127|P36K6r<8Rx$p*+bd{YN#;h*?tJ)oY^n+9ljbXGPXW^y`2#Y z^Q+u4B)5@;sKfVGJ^La_78yE=j73jy3u9@5#jn7AmiL4>qJh1Str05W+_NiI%1GlI zux_PL+YP0W`>Xc&T|~JzkaSbG;Fg%H+PN@B9s7$;R-vxk<`p@If?N1}w!>7%IozSMEMND|-KyXg$W#+KHHk z{dmVZ^4z}y%AQOOYI)VI1k4K~=wOreZ5282C|7LYj51-nX#G?UN|YjQd-6XC-jdkG z>fn)5qlYM8v^ewmz@ntOoSCSwdyU<-A$A0Gg2^C;MR>kB;ds zlCGd6=z|ub&D9s916rPZ}d8o3Pc4 z;WYLo7-Oz&G0rWuuG1w3qeHMYi~fLzZfdhhItj~52%AT(py8y@0n1DAO;fN) zvK8nB{9rrnNQ{fsLEnBp*?Knr6SnL)qN@V3u8SaF8>3}9z(D0wF^p7KH=@0$_* z)T-pPnYaG-!^x5Q_@fT;kxAu^Kx>l{{9 zir9^4Mw8y?Q^^EBBe2kC7PZL(oS{zT z0>HLmM(&hsN=21pH1~Yu@dG=~1$ewjyY=!{uSaJq!NiwEeB?eG(>RWm^_CkGeId(&UY(9e=`{yoO^d{Qi2$r#%>B=24y249}U@>X}NS`S?jC<#LuIm+@zIfmA zh;_>CJbDh+UWMAVcCN1Ow!fB*qS2uD73dm}|6@mEduQbN)BaZvT zyHg6S%Zi_Kk2i-~Feq?i(o79vx|mq5*)s*4^%=MEbwiw^>?!s*<#{QDd6n%h*48Ut z5Ey~h@rTsjzF!Kp6JsqGzWF)+a90VRF{ECdLWewny7R*JV1#Ma5g1;D8>BN<`YKU1 zpTqR`66FU@(HlQO(43#AT(S$6Vfs`EwQm90Y;Qn5f@F;YcPOnw3R>iKbm{e~%kQ_) z^lppxu9C;jvE~oEk~6I6e)xFz}!P$q(!zmFumJVJ!x_0S*s85ja5gRl{f)&in1OyCyoh zS)ug>B}&q;vOmRxxl#x2einRVL*ITvn3hC+{^>WV8g+V@E&Lg}Bn`LT#uWnZblD=b z<#NlBGrF~cV||l9C5-?_8GN&sfk-?yqds0 zB(SEa>T)>tG5NIwY0)2O3XvaZ1fx2C^lpYexzQhNa>8{6lKA~$X^g~3UaTNhX zUbsQSg~>2}Lm;WF6KmVsOoL8fvzv<{5n2$CV7EFAFRTKLg{-pt$;?@MssJ0%PMQ}s zfJsd{b1_df1*vm5qum1%VcPkK)XR&vFCIfz-(`PD$|U%BqnTB;#|iV?iFc>Je@tki z&i3X+n*VvKd4&z8QOEv8cKrs;UcQRZ)3iZK2Kd`?ZOU(XNZlqa9=KyaidPR}g_cvL zpBJ{S`kJUoDrNZKWtvs>zkiM|<5+*HIKU-oLmQkqp`OXc?>`whr`-brWvBVZ3c)(h zAx4!2O_5G^;Yd*t&u4##B)Y=UWsMvd_2BOp4PyV*^mTdgfM14~rZaj2`Ubt!>3;_6 zDPL^YiW6_`Tv3+*S5J3L@!-;PBP8zQ-}e#5cq%$ zzU+^(<1S=DAvLGOS&&Q$n%mL&QpwXAUz*rC1QW*MxX)5VQ`7N_e<+J7{FFP3#HlEd z9IjQ3+wg7p4QbzW+npM~iY}fL5+`E~Jq0ivsmZ)I3Z{k`Y)IJ7(_c?8*^T|wxwn<3 zjV$y240#0-r!EmcznxF?pDy_$wh-_H#5hwL9zB!4gfbMZxAjzEy=xdsgrQ(xa}w~= z(;M(R5ipiUl1TN2Lu}zDzAL@jz+cpRqv%qKdxZ;9wo>G3a`)f8(V^cA-0A=1du8I* zbp1YS*jVRfP3-pCR^YGAD=UCL+C$YJ9-Ei`jdDgmthz@AxG@{$sCENcNlt);i z$N{&o;m7nYOvj0S&?xLlAbovdy?+r6Pyhf7hCH}ruMNM#T_k9@^EAuX=1-cUE}&I@ zede{)g)Nc|FO^W=r8-Yc%KO?eyBRrYg_&xC`Fu~U_I8h>yYu%qV!&OSRGO^#%OI3n z&@Y_lsvV^xdeMwmu9mk4{+G`OUe1^6k>g(~%w?m<^n$qoPA^?$sUiwS)6mj~;LO(m zf}Rs&94ciBP$adQtwU}jWOoB=Pw)|IiYL2-wUGl~(~x}Tr7f?y4?f%MazKs}hty_W z(t~Xr8OQyNrPW@ggD>}9Kin5d(wQSVzq&f|CRgL1(`DEAf zK@cVgu69?TA)He4_qsZe2z`tH<)G=P{>Gv=#h%SnW~M#xXpo0tX6(-08<~ zf6}-C(nNsEvRN_X%Ye#{wfH05{-qj5?p$q8)@5y+VAR6goA(9@Eh53=y>diQU~DNo zvekUIc?oT!r8?w7g9}_twFaMLrYmgAdZlmDnPns<4SvVF{gQ%`h4uPsB!fc_sKbXy zM)|r==*m<(lTbkXLTJ~(RJYxB2fpt5z93vpHj>GpJMS~5=>=g4@y|V9ItNcTx&#rI z9snkMpUt4Is`wU-LpRxj`TFM{f$Ps~FzvO_1_-uV=VSb|ZeCvZ*wLCCgqyqO z1_edrPy7Vc-Y7#t^vywbUP3Q?NhMfRj2xUI^c#uG(q6wt&_e3N;rz6t(-{RKT1Ao zfm6iAk}3{)yhv`n+d=hIp@&a^y+Fj#6Ed&3-dC>vxO_ZL-B8f_$%VHPom^wG7|27W35I6vSu7VQyo0sB5z{`{0n*EdW`@_g3ycNzZzrl8eDPKHGHSCp#(&W)4bI#L;4W2q8#~)xJ3RwB? z?tbAVac5Xl@WRy3br3teQ-hyVZZ>iss5ZA7QBRZBUouv!gI)+E`izfVWF22&-os>r zuGh;NXdH`pkShD4YB8o$(Rq;EjkjvTm>(ZK+y9wD$zVyD8N(fW(9=SO7P(? zfRV!24of+B2#&7aKtFk1&EQ-w5aN?nr>bm1)6k=SSAg&QM$vXoEF^+?`VnN;2`tkI zf_1z}!p!T7E}gl(-6t&?`R^8UY=?g0Tw)n__*@^UH6>wIjAi~XYPv`CA8l~*DSS=( zX!$@O?0BJO&(ljWs5e(*aZfEfLT)QAcR`@}!N*rcLSX7oQJYcA_8%s)Rx>J3#q+aR z#yM!+6b?K;NH~7lx28C(d^)$NJ~)yJcP$9xyFUPAz!O(1z|c`%?+M zH>1Fkx{5pgt{HM#^~3*MDf8wC1-Qco&8WAkw{~d1wVMVipznO{V*WEAo^b8i^C0;%9}!MI!NTFpIc1eb$ZG zaTsWsM^Ux2i#Fm`rj8Z8t2fwIuUj$7>#VH?ZA3mZRLVH4 zze6M^bzcm#GC#d`7#4SJjO_bV-z?}D!V+^3TXxup=B zxx;(X?^r*H{C7n7_#+2VK{KDP{+~!j^=aB5{Y}u((;!Bvl0KY|`m~>iMnHgIZEbD0 zhxyO(Jdtv>(b~x2d(@9m>*xS#*a(cL|NMeZf*=Vr9WfJ8(Gtqq$jycOuzP7?Sb{Bc zll{q9aMp*H>?M`r^k==;pgWlm`f?fPnu6Udzw%P zA6oLs9|xlsM51Hcn$GIP|N5S$F6#8)YB-liCf^yP+goqHkT|^H20JJ!dE2(lB&7a8%# zP?gVZhtn2J>G5Wg*uj|`gxy<(ir<0cbm76DOjmQJGlFe(HAoq}uX~O;5lnEJl#J1K zUt}KeQy5cXD0d-qrHO^aPXTRf+RVAj=U|}X%hKDZ&5BHY({?c{&O~&*bR^>=cg8Zi zziX&`3TgfSP+LCmKgBqRE{?bw_E-L#X`CTxuYy0Hh=PBc)3mTR|AvQWRWGJJs|dtU zNca(+7S)pm`2DRCED%UvJm!Is$&R(B&ByHcKx?ye1XYVdR(EJs5t>IO_P{R~?O+o* z;wt55?J`p3JbwFK6+a5iIm~!--xhj}8_KxkdQiL3=UpW5@?^AbsF}d)Mf{8_ETg2s zoD-ewVMqs_s1Amayu4&}-8@j-?1sa(P+}GcAum1>qfOL zv-NF-xSnt|h6S29S~uu3)ZIf^ZWZANqDfhwxWS}T+MG+GA{yM!PSy!hgS!t5Ad9Ea z;rRz--#Hc~4U)+7#o{c!-%zUtWVI>U;3{MBMG>yO=xGbeMMmSn&2OYYz4An2^;Jp_*)EAb2YycI7gA=dm&EgX3p0!}w>n2g{_6 zIq_iEHegh^D1pt$+J`~{sYI z*326=>=yzs9Q2+fPty#@L}!#bUkRCPX5Q>FRl^k#Fc;``Zm{8V7pRqi*l?L_8#ay7 z>i|iT=?<{CegQ8?0+K(|Rs(OGwKT^x(|nR+a3da0BtQ?{Jt76z%w0&o=g^lO7;m)Y zR@E3GsR_CvSd7_FWOquAusbDb9}1y~BiptT;;6)-*Fw5kSjJTL)<$v~tee-!B<@pX z?W+)d{B~U13LN6o@J5tOWojnvzzb~4Ra6<3Aes-5usC{Dw#rXePd~|=xe?)n){|2+f5-iFD6aMtt@m+T(IsWMIMsa z2fxQsYvAHXQNx9-hd1eEmA7Fp&pCAzS$&5bM|WUsO@q1Dt>bK=KvmWQnUo)pWqt;? zd+b?J;Dtic69evO@(z)b!+k`F4Wmsdjq)@eb|t$>w#=0QliwIZnv`7knSgOC%xLB| z9ed3ey@hWgq=_2$wZuiZ8^Bq%It_PG@(vAks~hDd4;08PQyc?tylWDhshLtVgkYZo4d%28klT_f~LnfRCRkwz+YT zPIkc8(pa-(BN(}k=qWACV|HsqV&2>T9r|g~&{~woGFk>1s+*FzC5K3}l$80mKOg;X zh*pX#?hHq!@r^SASItlace?|JaD$VBX?Q|VEGlY|zGgTL-XKTMO?6f(7+=O}sDS(Z zf(^D$pvuIbPN_wCgLn?4>eQ`~1MAOSU^$*gj{FTlcBShj%};-u8FkcF#9U7iYQ>M@y7 zgGr2)AKBcM^;z4FSvPAISSzi&4#ex-#d~R$oXeMnFW;nU_}O0R-z5z<>H=?uFBg%DSSy{U)3vtV11lUe;U3>w7+YF#eS?=IJng9L8C~7yL2R$ zm>Yd^^0s?y0Fxu8{?t?Qpch)z7-S$ep&K?nS#PTF#fQ>8pxISosyAC@MVpxq6w|X2 z608WbnTI}@Ia^?kO85X0V|KDrt|~*xZoQ%|Kad zY0`_-<`wF%v+)cVL|4n<9!%;@NT`{dac@UuE!K3#=l$JHF?O-!`6iVQTK^djUl^hD-3pW4f{J(9KM|=) zOB>bw>|q)diR)9CqNE;zSzC2+OHgDFZ>&>NT~N8QpA%WZw{(GtN?c zLQ968q#Mv*%|d?KR8ZTkY@%5@H(E7O0Okcw;5(T!jF(%?{mR1W6? zL12hovc^j?hadJGgZUPy1-^ZS7o6d8WECT@VZ8Q@uCJQqNBmy?3z9!Ea0~@MKc&zd zNGzu#a4MNpR}0lR%~?ry#=snpX+B52Hn;JK`OOa}5JLeY@)vQFjmGTnzocghEXgKf z2Y-H+*Om541Rikv2M=Qf5S_<%+ykuJ^yp<`s!lt(nU{0qCl8iKxj&hQuuS%3^^afg zm3^^m>dBlyo4>-s1Iej}htS8(GwgeY%#wVnKMe<0!?hpZ>0Ubd>vIY8GQaN}uoRLY zR48(t#p<3*_s9lNX`dJz_#!ZPgZA!@S3hBTYs2E=kTli$x*;rmTyi6pGbQ7=^tU&d zXMnh3Bsq*$kd@c&box^rAh!~~T$w3bJ|Sl{rSNE-N8!Wc3QpbSpM`SFC9#8HRt_O26rmiV~U_+I;qRyJ__%oId z{_Mm!Xnc*Jau<{A0?_;keN}FQh7+ITZiCT!M7l4+rWHsUOn)WK+%N z0td~HKb^WM`nJ+z(q=EaZ#3%Dlf1vaGo)Sf$4XLSh!YC%Pu5jLyq42~D+7^jDO7u^FYKv_vS|RnFh5KTalTDK%$IqZ^w0$M9Y}G@Tsm zzVpL#rwf6pF;lKB_w_A0DF~Vt+SqJ;>nsn`nL^MNDg`s0y@y8T>qq2(%%P0Ial zwzY{N>}*D8gmZMaLi722l(@Tys4#fS8$=o~cu26UP#4CCOpN=9-G|tC1E}g#Sy-U< z=nC&n*hZNoIuxeeJ6PX#W40TZMHj*k`j`|#PgLE{8i0v^bQQ?wvfr-y8Oh-Zsla}1zMY3 zm8L#A88;Al5V@u0H8YAOk+~ zx)Fsu?kzWAz7WWpP5uxdoU#f%ZX7VkQm-zOQ=^0J4D$w?st+hlx(V9qM>Mn?jXD2ShrF z)-ViRo}}R#B(pzWU_DLXj@~bYfX<%1S>7AU+_+Kg(1Nd>GaW)yZPzgcx$tyw0FDl$ z=naRrwcoIOQ7u63XC>Q7@eC*Upev}ov``7|qCjX+$r=&;NyM{r&*&g>Jf)rakZBl2dm2~Z!(#{#Q!D#u561Lk4Qy;W+?`+ zKZ_I@q7@l!-8h%XZyqU=`D-c7g@n+P1G097dXt)KsOZl?Y9Ns(#0MMx7-z+xRro9AYh;ru$mQ0myes2d%{B~9Mu7?6sHjIfCZv@lWE_xnR)PWP1Vz866`m(E?r1`-D(rK^3>Cc$Y-QzL;pf z3!@405hd}t96l?@^npl=YT5&#lA|Vu;Pr7p`mgRtQU=+<*D`LCazY=D=fuMV0NLQw zIXps|?wpcD|KPgpoFy~b-mP~gC?*Gr%E8|u0Ya`FHX9jum*$bl-fKve1|2Y=KrPJE z_(Mp7GLSjd^E^t=DTKN_Qr8y|)M6`Gx<>jz?Z&n5pNJNy75*FA`p-!=EGb6BQtyp6 ziT1&&wAf|LOVO_aYBs_fAK%t;!9?L6yP#^dP7|10)@Q5Bf?PwzYIGO;S=daCWg>4& z79t*DXZoX;6n>h>XCCHB`ZAI0J4%rV=2?SU#~+lC@F1{mD61dPDqp5w%6RD=J#<)} z#A3LF{KoExA>WGDz^P1;+c4 z-AyK#2#(fM)L5)8s(XSqC+oPC#DM91bc}kgb9p)t4X)t&2MA3I3CJ^-q^an_)k#E& zbY*F(K8@}T%>4lW`ubA2ud6 ztNk6T>!*j!Vib|yMPFgRoGg5KYxqHF^MwX%zg41(7q4@Jo4c{BgIV^5) z-}dVow>f;twYPN+Q+ES)SE}(K?Y&@uxn1{TKlVQtfB$mE|1$k~=DW1yL z7JVmuO&ogYks-!KNA)NItppx~gFV?LQm3!i4t_+Bam3c;qKeP*noHj^dJiyr zuwMsG-@;*7<6p51(=#o>W^pAV&7 zBvC68r}nA`pDs60qIG@6FS6w39Drz)P)76ci*hVYJQUFmQMehE6x{eq;O+M5B&153F&YLfUJfVxwRYTsLC*-oU$Y}klHJGaHs9r{-h`gG`p=JdPjZl-m z1iNGDrn*@Gp{YWK7qq-u%q~r@;@)aK%;xly@bXEQ(jv}stJ8pAyBT^b)$jg}Rll^# zy*_ZEuqM*k7*X3C4oJdOC{oRSUhpg6aE6!)%hWJI=D?b!U$GD0RwwL*JAPk}oHNVd zBMjRS7lwsx>DvhmSFg|N4o1ze{-~w|E7OQX4Cs98-Z8Zh-Y+du0As9xOf)x7r z&Ft7?%HRM+a<}a*BNdU9&Zk&V1T+is@PQn)94T9V(bk{%BjtFr2}Wbj>L!}pS2}3Z zSaeSy3Ms{~BwssnrAR}(vuU{S98H{jkd^7}u#m)RJr)@#MZ9dVaX1fQPcnAx+oKSh zLv*_M*8Qol9P#H)EqawsJ4oFhaG0phvfttg zS$hnfR(SYpz(S}rNuN3=bZ3ZVC*t%;j=?4414$r-P-el4kKdEKMNEZ`ToV2gqB0}M zF*w+2UR&_~^qosUc`L0zeU0@KwxRsGPUwWvvMqUtXaw2{Z2Gv-kuB;+Xrz$DWD7~# z&xB?xqc!tK7iwB7>#E-t>|uVEb0lAPFNx`Z^t=YQw+w4&yFudwRfb!R0(N*-3$h<_ zvQ}KkAEs7{S8h^Dmn0swy%Mu8*`;Ks7F=a&topbv_dE}*BziVy5*xM*xG{q~&KY)E zvkg>eJ$)&DI{~AO-wPd2rkqD?AY7mbNCHP!AZv#~Wut3Zi-@kpZr4=1A1C0MwdO4M zTkxH|m&u_Dzp3$0tK-_!d-g);_FTnUf>QE^BQZ2MHz2MuxCicHzmQtBO>~fmzj+d! z8L`|ZI;T0BhUAGfFF9RLiQwJxHi!L@(Ai#W$Sbtn_=Vv@Yi3of<+7sT+X9e;R7ZmiAa575uiuzNiqmLrUdbyQ1ZbW4SkBF# ztWAP@v>d2M=d!>eVlG9`R61~N$V#{O2uT3pdHo3Da0>Aagr<#p&KajD;Lhg=Tr{3d zD>0n1A4uBI>Z>Yfl5})`_b)znc)*<865vI*HRoav) z1WtVts_QHAr}05dh*A*z2)H#kz$EQeP`oA71|;77@k-ZK(u@xsNU8>vrxln0D1n9< z=3tr$=Oz0@aG@!+1N(@1$mc#fwVdfdubhukoa)+?_`Hx;c(;aiFimOha^Dq#kHh1} z^br`vz{ANXVTd`bliQ&F2AP?~J8-9lXmW_({WJ;D(uM0l)BV*x^b`>=?D1EE4v0Gw zsB=pz#8E-38QmSjlDff9#hXqBqP7%t(tp0}a!SS^5O<;18+1DXSq!D$@;_*25 zqZz0h6U$F>6gJt9c8uEn`>gK@l|KE2?MPklwMX5!1yL?~Uy}$UD0=iC;gfT8Qk)6U zt|aqLkD^{JhvU)7NnIMLRyJovJ`NBx{8JHN-!8B>=1?xmlZaynAN&R#QhNHyBvL-{ zFFIAf)m~`(?)$t zdp;!vY$PwK{3u3ovLdxTIcuIDl#CFJeM|>FD0V4W6`VmeRy`(T-Yo=n-%1TPo-4WA z#xNM8ra_8Rf&HM>x^QA#Q!qLZV+&#dRni0%-Heiyr11OfDT4@$pn@kYs_RAxGDwG$ z@@c?Pm!V~(7J@88#B^9QJnALDB}QB(cH%qz81d@2SEQ&FV3u4~loN{~+9;EC`N&0ovVNX59bxL?7Qp z!0#=5CY#q8uGIl_Oscow^Lr&%pV7rJAp%Gfps#m&PyPi~_fl$Yo&`ToKI{H3Y!w8l zo~M5n4T+M|GLENraP(sc!yEplI@*zx73X{xjzEVvE6(*5w#vDUidh(N5f$wEY3;s4 z9P_s;#YB`$uk6n|G7aov;SF$vW79Wj#L7@69)$p@d3>2PWcOXhXW;lF7hVJ=3>s;{dZb{WY zl(dWVXes%$x^hL&Y#IjCS;yZ5moL>=R`vGg+5q{!YimqHpVf}C^);A3e*KcK3%7Lt zg_-KTV0w_Xy?YYQHk7fc{x8h*aDiMOMSOp3s;12NBDnqI1O?UU>sJ}^!d4akd$-fj zX6XkmoZtir=07QeD~f`FBg7C^)f>gofv*tHa}k95mCE@WIC#e zfMAI0pDn}D#t{Q!=suVH)S3*j%6&};21~ip$`sPq93pXUPO*ay%-!YFXw8$vNw9GC zSHd@O?gGn$j>A`uInNay^3-4YEDIuU%v+OKogh5&&#cIoqB z1LhP@%AC>94`zOr=-hGOjR&kBlvZTiy>2rn#PB;W0dgb1Aeq?ZQ7p@b}o20 zf^wG!V27NiiZlw@*%CN=lSS0Bsgh{qW?hIwQH%9;$VRecF}fqFyqpDeR7>Sw(1)v5 zec=US+g*F&e#I#g_;KlGqrrhGck1(lEh?`tt|mjMb6*o@+ET8(GR1Uj=ysS2IZ44! zBQZp~@oL=jaRki@%2czh-G@bf=rE}}mH1-CW-W>JP|ja6k%}P1dNAiH6H_qZQ}9ZH zDAP@2JcU;zUvrgSeE$X~?awE4c_98!h}{5k;z+@$S~8o345|YN9MxzMgeGxMbH;Zw zCG)Fu9&vmj&n&HZxkKN>peZd8_SbD*VYM#77C1fB9c1S0OFk=)`X5MPMVAS3)R0zZ zH*0+wI)Q1CW$CU~(7IWn=Hrn{(@DrKSL=6iurM$_y|t|8EzU~hd|dh>&9;3OY=L5> zqFokDPV<&^GgZ;{UF!b{6dIZJ9p7XaZ5tyrem~wBtld$zoFY3tt*l)6=lL+!Lc6FK zUayy=Nj_0^@Fl<0Vl<>|MmHzpELPNGgji)+sG&$J6vNBu^7}vB6Adk2g#C?$CogrSxA< z;dq&1t!|#mpeca?c=kI`RWn-YMv2X?Y3hkdcHHvnbRZ399kH?0y;9qFCc{}Ou|LS2 z1$(*LDAs0Tt;oHiApVG|&Oz&%rJ`-R{1>znP5uY8)0rxe4~9?2;%7c1=gktE{-T@v zyoEbh%Zf%&L5x98mdzirB-`=#j9BU0U~PpQf{+sceWqR9L^E}d!<3<v%BFr+c`>vsPXB!6GhleceYj4#?v3c z>P1-@UthopD4J3<@A}JxO50a^q2UB#5RA*xORrcg`dLI9s!tPRNkferTOFafXFholy4xS_qeu}bS?T`Y;8sO}-5cJA#IM9eY@596N#GnA5Umjg z))DOCzM*LK4&N7eeq|S(sSY6jUIE$hI_*=NGwREE`oH0=vOQ>kFTcm8c~ER}T-k1v zwB>AWZzL5Cgd|KaxxV`m3#;_?al-o+ryCAof*kestW~Sp^gDecBH+k%Sqo#9)!w6)9{Op!^`OO!>9EheZ|EPUm| z?;;G$`)1A3fr6AWL-pg2FU}WVaV z<_Ms_%M&nsv7kzRFIswby zU$?0F@f!l;+MJEJTCN3Rwc}=ux^!LNJQNA@5JF?~$k6!uS9tIo^=k>qmg_76|8%0? z*&KIR=|%!0lU3LX1_rIswI-`P4c@!~6htW8b&x7&T5du5;1~&THy()2Nn87)#;{z1 zIG{Yk8>lxaS~A*qq%h?)(PDJI0UhsSHa%}5h-UVXFYe}?MgonGYIOprPE2`%uNLKZ z?f7QdyNqUuE40ls+uH4_$^VD7w+^afTi3l4+=IKjyG|^)y9Rf6cLD@=cXxL}a3}c0 zHMqM54cwWmz1BYG?0fHb|M)11>Y|{kNB5XLM!)axc^>b4!RMuFwzOTbFrNB!hB<-D zUnlr!B=!P<<{yUl4{*MZjO3>#t#;SHub~XdQD%8bcLdUa*61QjCBBP6nL%h|mlBHM zk)$@OX89xhEIh>z;PPg1%xXDV&ftpnJyIq~&vox=ecHA&7vPcYq8yQIg-Q?k<*R-K zDtelcpd^>oX3>0cXK5a}f6$(mvRi1g;{UVUm<^ai5)ha!;4}LGx1bG~pTD!u)8!-S zj|_iAFbG}tAW+|=v9v_z)BA$yBDVH_ZO(A$I8^DVR6?+10;X5bx89UY55LSAgW5Cg z7el&75K$gQGb-1*tV!*6ADy z2)HiNsFQ|!hd=8I=*%0I?s~^{6?#%ri0u^oRm~TKhVO#}y(JEOPw!m9z8HfIxS&o-pd*&* zjC$mktUcFO=7Hq5IMv|=*gHwM~{U%Uw|zE=jj)#zQWVuXFpe&32ZCP10(|A7$E zvuu76L(i`r8M_YcJ*YXMz&IKacYO-h^2!M&!q-B|{z)Xi%!K_oqZp@^v(ogj<9fw_ zBKeb=E{B|er6#-Zu%KX)wPspwjaDjYN1*9c6;NN}&w3wnaiofDWtH)PMM@f=Gq}|( z(FayEG(;w|nuVnbiJV>ZtYqd$m_XW(g8KB1sX&lKdl(;eyMtUbB$W8J7hcqVv<6j0 zUKRHZR<{|UU=2dFGhC!3V3OpTB`)=tP7hRzm{6!iW z^CAN;u(h{iVWPH2#cxV_**GewUKNEoOCckrNBNMfrJfWYA&Of97hjN;3vLV2A#HGA zB)jlYKz`rDvgC7LsV*-mC|HpFF+6GmT*arA&`Jt_@aRfUR^Wj`1iZOAm(dI29&pK< zn0HaiB-U%T+wzzAXy9!$;fHM?N#y4>A;n=3&%9wZov=c`>1c)uOk{7}b5Gqec^(-f zC10TcD)~=sYz#ygT5Pv)Dvkz)7)oRyi+D)VezbAy(@v-H%g><2xKfrw&7%nwKUlT8XX$vqq5s+cu(n zFuh$$uD#BhrT8vi3@xtVbVnO0--;&`Jx*-qg& zUk#uSc8;JrALtG|M&n$ac`$Rs-jn5Z1TX)b^9fQ&!HxRuU7^-F&X2%+ z8u8s@&ax6zm!k5}O_O<;9K%!k6pHD~lO>4ruNb9Z8uvd?i#j5LuMOLRq>8?J&0(*n zGYRArB}B?8rS*z@J|Q~;I>B1LQ+l&%F3E_QYA`!ai(kzG+V@QfcWAv4RGkfNHj%ir zL-nu=9e_@s0n5eYdlxIA+nihGTSVj>d4U*HT@qp+{|EBK>V)-lUQ0QZXP#51^uS(v zMUGHRzP=95@h%maMneG@`DsTH>9JrYdA{)AN|Cr^XGoDKd>3k>+5Ft&&*r=^czuZ| z^}_@~X86YD@JwR;?rO;E=}~6BNJ9O${>d^FL<&+*81z{UC|g$A6BP@pY(o0h`x=-o zAZnKRdq(KOnBC4*v%kZ`93r2>bmNsdDTtqXP25)u&g-{k!(MSkwR6^ua}YRBD5kFOm6rC8lA}JX z!R@$vueHJumK#}Q7Z}zpcu<-Bj+FsuvG&a=1JQOPnM`zPx8%W4aQ-thSh6eM;E{)i z1B(vsjlmB?+MiuT8In$O+A4B#kk#q>YQT7slT%{N_@|ow-Mys-s&@j3yge&zWcwQn zo0zQN|2p;goEX)xG7-CRn-w?kx~+6%)?S9Fn!zF(A{V!0sXkc+Pv;bgBXmXYEv&6GJEjMIBRYTzBtb9R>4PhuS(MXfNRIxCigrazlVcPY>gDWCG_d5k zOsJxUn9?R>97hxn>?R!JjQEB{Cs=gIq>QTalH$OH@mku$u*-$7{2m;kJJLt9w10tE zOS~WuE8PtEz2Evx$hj=T8&IST%H`Z~T?@nRrF-dpa`l?2HYTxCFgU-O!*`tTQ4myn zr{-J+7^q)b`G)zFHEu%7>st2ha**i0rx_&4@5+hae5`VifY(EG$^C|#86#HUv=@U5 zCUJ#l<8%%)rOgvJ0^xC$3U4za(26go4%5&UgjDQpH}fMb8WJ3Ts;@K>IDYJXs-78s zy`b9okq9(1FkGZB?Fz{}IPGBKPu#BjWF%%zoCi%^-66)`?QG0G)~1WhLlT&5-Nuds z^w4M(ip<&Ww4dG>{f9-O_;m2(3CLt#JS6M;*ckT4^N-`mNqfpEj&K?je9A>8f|;b? zhgvX-%_JJe@q+frm;AXbNz~7L%Y71GBbA7_MeP@Q^VR*oL#F>-e@?nf;qcW!qG-1c zym))H=(sTp+evpu0zXFV8M)R{#hqACRVfJNxT%B#6h*+f1yvWLA&t4VORg+}r?@3L zNQ_ZfNFxxryzcBPh81ki#w?$6b+4Jw);1WJAyRcOx-ip4T=u$?%QXg1DUwU|t)K7S zh!eIJKcuxtDcK`om=6<^*5{p)VkJ8BIt^@iNa$1HoabjxXrJBcU8de3I|8sa>oV?{q*qzE15;JFWRQrwjUJZ9~b8zEu9Hxgqh zj>fqU;{_drHh}T_R+o#5S909IkLIN3rShnH5b4QT=WlGy3|amS!^D}ZBZB?2m|ft2 z9UvKjUXJeHc%$wzA}wpOH-XOd>Mu7D`0$)8-|7;XJn|({X_g!faGqQVgMTQ6lsO2Z zHSa63px%G@h=|Ik-98zxp*}Nv!y6`X8~F`=?<^WuF0}%i_E7RMtYbSC2Wi(w)xB>< zKuY;oh81a(Hd}YzX*&L|iF{S$QSUCaoi@atmmYYS zm2L=QN;~lfe>II?JTC_m`Ka#`&{*m04%yjpC-PatoVHOgFs9`Bi-a+nxTGT+kpI+c z``|vrOI;_##~H52R;3h}ASH*#Wg-W2Ii@R8<;|JNaS#Bi(%)d6sUxefKRGHr#M#Lo zNbs9sxy<#Zi|}xBb9W()3m!V`EB@Z*)Ix!9i7cL^prD|gN)Rafm+Hlb;E#YPD5&4! zzZ{f;9U9BAH=WI#(u{~u>K6@@^_P6*I&Si}8j0M$kXB4f)juyb=@<4(Wcs{dbdLii z?J61h_-)oBUGK_R=~c^_UnG&`=A&ENEY+D$!fIY#d7#(LNXT5V-s0y4hTUx zo#0t}h}>U%-;&;NOVtrYta-KB@w%WdWb}!t!e;xBTY-=aUA6(e@ISW<_fz#PpR~{r zE!){~Kx?~9{64XXn{`u8C7)>=YsP6btBD?VG*rrHcYmYJ7uY?&!!e)@lG;ZRJ$8SM zs9R(~+579kn$OW`&o{^(x#6M0)9mk1O}^9wMRr0uS6R6R99(JcZOn~*EPwt__yM+t zmR3zJ@O58tHeFW`t#cy(_s~K>Rr|r()Y;kZw|tTlIkItop$&bj#)FYeWmyz|&<2kc zrf;z`sY8|!y=hCPfb(OP`?w@kQg;EXa@^ZyO57PYOW|9VP*%x!M`IGN)oTMm31{H6 zg?$qFX3t@6y^TMz@Hulg+TS(BJ)$SprgV`pU>p|1Ml$)oYL)en3ESU@d~H??DXgnF zAhri~(pY{F#VSL74~HKtAu;Ku_cAznp232?V^=)p`#0`T?ht|UZ3yM3N}s{#QRgj4 zr!sl^CEIa{7`UD(R>IQAXNxFuYc%)CN5BnyE2G8} z^Ma`_xlhY>6Yyvd1TztQT&T^S3!rF3!Y~ua3*@GLENe`;L1rv>8@MszR1Bff;n~j0 zI=|ufr>pE(Y(BZng!r_FQ5k_JGzxWX@JCwOyoSc*JXMD{>QO6-oFs)Swqw^A5=Whs#&@UW?d_2o*Hc+tMBI&DMMtV7K*ex#ZY>yxV9Xc?h53o6pD zF91GmgcanN-7tO!B6jfMq~wYcF@4ZOKxv{TH(c*Pj%l^p)37OTc7zFCq2GQx?LyS$ zr34co_XbTQ^C5~HvXtt>aEpaiFhqDjr-7O?a}2o@vDZl`VdonZzm?K0oc6xH5a%5M z=iwUp`!4cVX7Q!#9%}(Su0}~3Wdwj$iyRKG#6m^5;ffc49=AGNyiqp;dT$~h^c1}w zdh-5ORGg*ZDJ1c)GM}lKB?Txz{4f!8Uz0ayU-jyCU3-SoX7U+8sKIhvULzdJ;3+M5 ze>V^88PpS*x~WzT95jLJupZ?=B*U*u#BV8on1#k85>+6+w6V$WJ9^B5n&RSX-q_b4EVf5*Rhso+V`lAnx@Zy}>nI=5&q8As5LvdT zo+Ys&<5RQxqv+@$2rBNAyv+$$;x@|pT?DtUb5bA)Y*%X}flBsr>?LP2_|*1D3|{Sc zdVaA>@SWFzNEE`2?r>iWcQcQJV*EUn-gMK6@nv|m^2P5xxjpzHgrFCUT*wINvlYtL zo>`F#ENqB&0urV6>_m%G=5=X|y_=XdQ3X%@V3CLu8Psez+N$ z612-oUabD?4Nq9^VQzF+VjMQ-^3DZ{fVP!G=w4R~Ax{5GMo+%G9{XK_q!PnJ7%!EZ z@$>mk>)iwW(5l*SEHp=XCmjkZa*j=QQ1t!$vn?&A%N)ToD0gEwDkkS^99g2!3581*p*Uo zJWZu(Rl;McNa9C5R%b6DRO^sQqk{C{ntEv^O10}%HimFt5mhzX?)Tm0vH$ZR z3WCnwUZgwJlfLhivZ1TOzIZ)X@FGun@cY5m#zj2#EhgNJT=DjL@K=+OBpfPA+cKK< z`2oq>6;xIC7!>5IYn1I_*xj5I^01+Iw;{L8#%4U(n19UOkBWdrH-_K9g*GL^poccy zEq^j>c@g%Ym5d=|RX9|$ZU*k%zM|>1gYOrHj1)vE-<-~PI6F{DENE*t6L6Z#Ug1e2 zw&*S<$tMVIdlqUiY`tf=J6Z|>`^FfuILYgQh8Bd~(BX>{=u7u?=UX6{Xmx<{Aih?_ ziZPR1@ANCDMf)|!2*1c{=aI#Jo$N%Sk@&9jczy|UyB{TJ&Aw~=k%0w*Am_&N&FkG% zRoV^==N)M|AqQEZg%cv2(T)@Eny0N_QTV2QbxVTGV18INh-f$C3u%i;%>-U<0Lwv9 zC;D)Md%DgnW|N=D&BV4}#JOfF>qvF|{2{1l^ncAg!=DHJT9Ov3a$KGB%fgq(`Pgps za_oPlr(0DP#&Knh1hAUOuP9TW%Qdzir|PXn0lYp6$v8ZN-PZZDmcas6x@5w^b9H+b zHpC6WhSk4NRz^!EhoR#vn&nfdm8hj~n)V7s1}Kk!hP-dg6u}>8+4EBb#gr635Bg#1xbM)JM>v@S72fGDMqp&2PEE8OTk z;~eRq4!;)i-yMG7$~>onbwT{J1=74w@L4qKE(H~F|LI)$N<7^9&h!qp3A$SLFLl5NThQE~3tK9!Z zDIKl0lR``eAhb%X6oc!1PJJjkQ!})DuT0wScz?xfqNa4#+(eCbb>;Kp0^VXqNG7s( z3I%t6PZ6?-rnLDemLk}P!Bq2ut4nd=oBgP$k4d?AsTic(imQ|%;q}DhpmaLS3%%~e zY`R`@4OW8iCFE1tMkOYwfVSPlyL6|`G-tGt)Z&u$d1H~j@1e$3sj(hy?N?y@&tgc; zl-RPJ^+UbR+vrnqhvyr<98;y>3heN&KaIj08LV6~!oitt4*RIl{{L+CqtFQApFA&` z-Uy|b?Ko@(1(h#G&SXSwWnUJiBr?oDij0M>5E{MA9>(7kdp1qKR2BmbH0&uCBjnKNnm4R zb2!*iO(pEwQC%b7&M5yOV8ey!;T*1K=$oK%*gehw9;fpY$qt!|y7yB3V`IH7{FI^` z8-;~(aVAaz!j~H70MJgldj5DjeCIl_L^OHU0S!U0W2hSfi*Dbb>E2f+*TQl|sSjSWIJ9 zjunKVe=~&NlC)i1hyO}rE>E*fo|OSa#1rE)WjPTP{*aaUZWB^S`}*hcFnSI=wIsa--8v_wi$L>=TkryTzIW zKDK`u>#dEeCJDk-J2DH#4j(o*XnP|of^$N~YJ(N|{;GAm6mcz9USZja1A4!|t}(>M zGZ?*{6Jx5cf^3Yr?^i0KAt1mRAgx~jr$mb!yF>pk$beLt;Rt-MyQ1QMi2M;*^i z`|+;Ue+r9f3v?Wk%ya{W4T$)IVvz66SlA41Jmgp|>ieRiAS@SbZ3O!!VI?Z+Tf4nk zEw!sZF6;PFe*9X~hFrVg4{hDf!kt~9pDWslq!lqIB41~<3;WG;@dH6-YvJ`o`>}b% zLWy8XkuU<%VmA)S|N$UT0M^rD#In*lG<;*b;fzJ=O3E zh&+f?o}Y8bq&(b(?9Udp{|hTvNPv;j@C%i>&rfUgp@ag7a2R5pNEjl9x@fW$Yhw_P zU2po@ECu@lB3|yYHhl$@@;6}|ym2|gsh91};#3?9^)%Sj~VH3T0^;To#OE;AZ1XP1f9%}+5*tRMAW zJN2&^nsY@aNmXLc@DMR{o7vAGpg!FIy_RkHx_*8@%54icpwXgz#{jT!>?3(m4TWA6 z!b8r%58yu!V&2irdQS_@e+$ueJKR8@%jCnCdfRbg9I`fu_-d-5d9z~BT(7fsOzrW-(^mRsSmbx%bsS8BFQP6>a+BoN`~;1a-Gul zNJqz|9;~*Ui*R3sO>Rn9q{2Y$%Miib@4db1x#s^y7_ihS*^EMne(Q5v zr=SRE9+Y}pJzn`H>F70bi?#{otBYqBgNA)uu2Zj3Fnp9~&K_?xuE-1D(QKvep49M( ziyskKG<2^HG4_)+zz#ltI$Nj!33TNIV;!S$jn_uV%@BUrD9)=j_SWw^=+K-!sqFmn zl?uuaB3iG|nQwCivclw?_0;Z|8zcomR)5fRKRE z4i=efK-=xHQI|$Q5-8oeMO|^jc19>;OgrFtdN6=p{6rL%Ya{(Co_oe(Q~dv`w@q;e zQqO=D3OxTUxXs}In{+4=98^reh;D~2N%_%HD>zAHcm=r`+E&QeIf+|?HKt5P_r!=K z+x(l5xnr3WM7V~*x9+o?+$?S9V_|6IV^^9qYSTk z_5A`u?=O9ih$|$nV5O-5%~tw#TNj9_Aw&|>N9sTNSf*Z#R1697JD?C&_cFvmOipVu z8QI+${L7vZsM3vvU+qHGAn;QmQ0o^9Y?MNa(d5u`o~~iVp`rvH1iyb`8`tbNb)qa) zoLUV3Igxfox}ITPsygpyJN)iDZ1dsO{HIuGL-o5%ZcJ_7Md94UblFQ)2@E&@YcHBj zb|cFDJZ96iDhA@$tBa!~AJNSoT-jplWkf#|Rk{Y`*aK#+Wd=XK5(l*C{QskLR;gSS zqLnwX30MZw&MK|M6^?X%emy0Nm^^Swa}8`yTMqkVeo?(dTAFZgPL%BmmDmBpLdDsL zQSrg&4G_xx^z{)YhaW#P*PNJ&DpXI|?rjLFH3QpA+7KqZg6}mWX3!i>YMwzPoEQUz z>Y$g7TINQ~M0E710yfZqYe@^R#axVB8c%Ae|3Py_u8&}_bkgNGFY?MP8{FznP=5hC zZck^3S{pB_3UnQFge0P0TMvK1R{cPYh-xq&tMIpZix&ML4eRK%-a);m>iq7K*`i`ut`3O% z>+3}2|4I8={L*TCWldjtA3%>(xl}qU353HA1e^+d$C7vu%M?+N2&&QgyZCPMQ*(c( zx5~^yfDXZv6>-!6SBBx?52&Aa+qhPsdb97`9FVXI@P=Yeac9@{5=f`ut~m(q+*sO1(Cu*-LDb{>4{=iSquVZD zAn8B)YyV7(!!*UZnDy{9rp##Y)X+Mm)HwI1&5aZXF$|tl?nXLa-=`6Iycc>-H5eb5 zfGMT3x*Iis;s97E(Z|T11b5}|I==2xKrlW)?)da8mGA2^j9S`08Cwo;`tUl0?Husz^ZxUhZ92(WI{O5rW#1EoY1fdqG- z`X>w?a^xZNOG+M*6N`%aL23eTa{7-}HXT1{jHvZ}T@ubE(g!^yBM>Ac55YUaUccDL z-Q?7T-6SC65C#IFnUH_cXz#Go=u@=0%r_W;URbw8+D6gIF&5Nhl#(z)zlYsRaTDF?f_S9{LDgx{9zr|+30hpyT19pA(2FPe>bFzO*2g9Xy(h6fN zI%NJ=X{hN%=^raERUS~=1HG%?ajL}ztC2+fNms038EMGrx4V}`|4UGeEQBHB%^X(e zE}W7w##7uMqGPWNwcq;Bkv{Z)67c{0<~MKwIy23%CWVM+F-+fU{e*yDoI}+Ywd&`Z0yl zxZZ8mOZKsbv&)hPxtkzHc$uE!OTzd8ck?8{k28-tLfMgC+8FLf_M!NT8!d)f{Krfr zU62LiH&%v!oz{McapbV*xLz|s`%4G2(EzHBoZ72cIWrWNZ>dq!Ff9ZGzlb!-Y~Bds z23Tx(W4+ZgC~i#M3X0AacB^ScU-W_MA(#^d$NAidA;is?#I) zs&Oz&&hy9U&&IPuW!AkS(UXl1jGtz6BH{_RLyz>jmN4p2oc#&GF4(T1G9U|`m|ree z{B<=Lyx>7wJw5B#Z(`P%aJh^h*}U}ejNQ1|hUKQ88<)BaF@`t|XVjmw@>EbmeMM{! zFErGF(>0Yft&AF(dP~%8Ruo@gZY*LLGdJQy>&wbE?&fs>S+AM zcV>hGaBHDYyvrKvY-3&41ACA_#Ee3sF-^2*%hS73;ox4oU6vcaT@FxhquvK z4BYN8%~n;=kObouu!=vEA5rVz{T$ec!cBK0x~sPgO}6nhj{$++Wo)6ZsV?&rPWK9D z^}Q}YrQ4?$4`G2I7LHH*o%-Fyi5ywu= zN5RqMm1gmO_cj2jfA==xiSsWp7W~Z-+gVEUt+rE22m=$<$UH{fG5rWKdwv-3Y7^Re z+2S%h*M@I@pSMtv<2kg@aLtT}NaoK50Yt>Tf}CQ8a7^!OVw*(9D44!u)I?y{YxDLN zY|%f;G9*Bpk{%41ow}ms;GKc&m0mz&*b9t7Sk@Tok6E$1(RWlb+_$2o4)Ny9o27*$ z_(YgaCt1#^YcYE9J^hnlL( ze1*mQ-Z2m!PeDUB0vi_OOHYu)0A&j!;WR+l`XM90xG7OMq6sa?V8S}u^efTMieRYY z@sM*-(&QC|e9wP^A+DH|d0Bee!>`sKbwThplG@jDp!R%~jF_Fcx>R#G&K#;P2{ zz|Oa#VRe6~T_a-w#&)el@jI)u8S)y$LJ+J~RHH?5c)1ca7*)@I^l<^`$}c>tHf%W$ zo!tQ}FO#S~d1GoY5%Z{Tf|OE$CQ}#)%1Bin@_$EE%O6H56yiTpCnWJnqdG#MO~=;D z&=~ZwkAuB3k`eR~iAfhLbmZ1pk*35rSr#fn&~oe9-P5k4>VZz=)$DKE@mVudgZ_h! z+#~W}VOp@C>+pO?as=irE*QVf=W76`^N%?ZpOX0b)pqwka}#{{z!)N9OjyM$JGh>D zye5X~v$6r7(t)&ut>VS_1%}YP(2smrme~sUsBm1N<_%CLDM0$h0temxe(6%SOfhW^ zk^uF^jjgwK;V_e&sVY73ML!oVYleR9r5`?YJ1xj^DX*}iQaxX|O$YP<`)eeZHp8{p zg2w3h^kp;`8e4Xpk77UdbSAbmMgs*o^yE3*01utTZ>g|3hQqZxEXGOT^d9qDO~;I7 zwYXS_Ubg%{^$FU7V*cEg%G0AlQZBTj;O}9PJ^gtT*t1bOQw*sef7FaZY-z4c!*R4t z_4l5TzyRtn3-PWDj(ot(j8Qdu|1c%GuHUvetg_d9Mo(H%Ory~eLEbN|{Me$+uiYEL z9xUY#rSoK#HY~>*s!2tJ!uG3A7Sk0NTJgnV{BG?X_CT-OtI>Jb)LAt;6+_*c2)!kb zwqxapE3-s4fY-WkOcX>1mVfVH3VWDN4C%K+0?vdRvmH!fVFsBIZyS<>iIqFn=EkMn zHI$sMPQ+vZCxiNob$j!l$EKCjvtbqItWyt{{1Gia0062#D2w_`6{;iF_-K6EU?!@% zhV2m36ES=SveDY>eeWIDynHZs&MJ0>gK%*}%szuQ;xCIX^T&Zm4GvEdW(2jcnN+xl z_bxDlL_c>@IkUG~EJ*xZGebDuhJdl!GP6@gHmj5tGhaU8uGFnk1T-97_CKhGQz&HD zXib_QIwjxsk&+!(d=j;M+tne2)Xt1=B|#=$n!rqv4<+GpREZ{#S(0lL z>1snlYJL)VoyXT9G=Fn-7}$!>>x&0sd7wB{lsb!9#2JMg7mMp zLZ!id5h0=FeqEGbg_Oqzyqxu2|JDp^%G%@Pl#dm}F`n8b|rfa<m``0HS|5s`C>Cu!Rj|t9WN2h_0^O2wjL)P4>=74z?dKm z-x65TT6wZMAH>4=SrI#*yo?SWGh5MH-*rdbh_#Zqt3&>N=-WQ)%WE(|3SPs#m~+Qn zs}RV`eArS)e-2kyRlOHk64LVuTGvQHS0%Zc4QV zbu(@8$n%!!FzoAT=J((GHnsO4zy-87ILODWnoN*^?x-@wzq%S-NPpaBdwUJp|2Y_^J^U^WqKy+j z>kMXMqLL`Di;>lXO}RxpUZ)ql;eA&m9cLrLD*)hG@Dw3i&ZsC`)N9~^RqrcGkvxDY zJxVxPj;}6(S{L!fcPNGpZ$9r`Mn4vdeUFL_Wjrdge24;VB0=7-CC;OUk_gx?MVo?x z5rTe}(7cO#bPCEi|rv(A7Ld2FQ86uIfQ3(cQLbg-;}zL%>{;4o?PgbUGrg9L`4 zrsNBO^GnRu@!$mZLLO$@W0Lzyl1RemA3x|7hpSyi(?>t=?%mN;;V$61wM;PkOnC?Y zLMCINM~2tc+FZp9syEmWG4UG-rlIR;kM!@g{^&ectwKZ~;bE|UOXKidE*K(vGq_AW z2rC@0y@Zy=>w}MJ58pGyW6bQkpZOYK!3Q@xv) z=nwc1LH zT2?b&@)1@xyeY#NGxoV3TX&k4=c>IH^T4G4z^y)@Rj?g2#79`4rSaJf z9x77g&85pOipZxnLR;hNHl)q&E7b&^^FDM?yoIw}UT^W5bpAr?Y^!-k_C7hE`6ni$ z;MDZAS4o`kB`E8@SY0@nf&ybRJJuAdV0V_#rI7B&PfaKNZ^{@D3Zkh;?qgAj8Sx3y z_ecWAW!X-XO3v*ZpUumag>GTZ*G_`WZ_tpa8qSWlB_CYMV|$AeW#P{ID^1yCJL6R> z8Mx1WUm#ArGTQA^7(STgP$gGS2hCDkmnP5!3gmPy`=6Zv>R6T7Y7Yg}%+h+Ls4qci z%ty6sx1OyoN34PRrfjAnkdE7q<7wxy66IjK1HneKac!HQZhO>eo!Lprv(jVS5TE*D zueIu}CnBb3-;_<(G{e?g_?D)&0%K^HJ%BV`Eph5>V+U-;@w;0paBLq^*)55@<{Sow zl<$~muxX&Z3e;nLC0RdNVv(HpFgFo;R?GgRl;aISVQgec$ly9#b>vPaCsGCZf{DWMt&^=cUdTvjWYKl8ZL4LH&coDQRSda>gnhhj9CnA@LcH z=N}^&ev2E#x|LOOfk|Vl4swQOy5i4sVb{u@_Zm%=<18D|x0!KJt&LMLGi) zbn@GIGPaC|X)v=81k>6OPd`eTZu`m#FCVJ~Z9H9pQ`Qs(BgOJ?<5wxkJKsUq;St6t9o%a?ljr2%wO8}2ph;jGt+*jr$P#QAEOTn9tUn6 z(lGP_mp%i4z<8dCoI(;%bx3CSz|`xJI>P;Q$oKm24R59CBJ>f9S|JSKv9_fzc!szM zJJwX-eQPRBe$ZqY&0_qu2}hgerNLQKz3fNzTN_AmTLW)9i2rH2!b&{pA6(5?BsO9l za5d(G?7*b51F0(jij#FrMWdHuvPQHuryV*;uI{ZABq**RqLo`~ncSSm52y^OcvPLp z2iW9Uv83jS+##@Mh^T?k<3D|Xr~|QmOB;F*_7Ap8H$6KX{mi)rhX9P??+x<(-^`rp zONtm~*t4)juV=h)>;$_){E>3|q7P_rOFyzA<|@4o{@cnFWUDV5JRK-s7=Kgea->YJ zdx{vFe+GOo_xw;mZU&BDy~5IO%`WEAQioI3c4k<*Z%%GMkI%(?j$?@w*qOzAEJ;dZ zMt(OY2+UYSzsZ3ik@WZ?=zVFh@!rp8tMGEHqDSv;HOcGTl4vi1- z&eP37*PnpsvAngj2$BBupkWmJy@|FLdi?}p$KFHo0TXfA}LJk-p;sr5IQ7%jeZdVXIGh#gMRhCOXa-F_+ytsn^l9G&7~jVJa3%eXtxF5|-W-1hpO1vIce7UNRGbc6ox-IA!!F^iZF!43-U9Q|y<6-sO%Q8rVk1+}LNvOOzJu z>3>-gS=aPuN-Y}Q35WI;Drx>Wc5BC(RIe~EDqaua1aD21q(bqqmE={DBO-O zjJGxqjUC%57{srhY~$o(POF=G9_?3~sM&q$9KN z^{2e-WHQb=j8G7Gj;gaEaKJ(f)FDQxESMdH!t^CP*J?=!wGbXw&>tb#y zJj>|ZW8)r>nG3$O?&Kb5UNTqa753s+1X6qP4tZpeM`P^!H*#@~UL$vYntj% z5naMqLQqDRdPvj+8q{TMgI?NZ5cb*eN z?#Seom?P?%>K{i-(b+Ai6|m@lNti-mc)_bm6d^M@Wvhw=7|&;?Y zkiCS^KCl_^O*ZTLhKDy;uRZ;{&Obhf3MmEjZE!{6Tu&7&Qn|Jx!}sKLfREQVP!*{l zGX-{56*il&(<;9H7ody21_X3D<+M)?9Lo(Or`sb{L-5B97%N<8$?6KFSWTFHu4b%2 zFY%81tcdK3;hr#vfdqj3V3zlO>b*4?#t;k0>}`~q6eHURI5OO6d8br;;x;gP@hCDH z+gsU`5CNS%XZ&Cq(SW0z;0N2ynGYxA>Y_Cak^SO5tJtljVWaV?G|(X}k|M1jk&qiu zq>y_VuBRN|kCX+neW7lRJ-QpQZ+;2#t587Zd+){pwe9k$xUZG7%KKEj6Z36{oZnom=^&^KSQl!42=kFJ%C2s>-iv|sK0BFuqOZ9X|cGlfY;ti$X z++Z?^{50JAc`$xe%7SHFh`r2$B3XpLfBHrQE@3pVaj|4v<;5r+cX?stan=#U<+5&c z`O_5UXZ2dl0i^KSy;X$PFQnAFhijs7;l}+&WbqojMj`9RMa7>Me^F{q{nnJdpM@mg zUL%b)U(rrp>_MTcRPw|0Qnyg?{_Vr7!mgBu zJ2AtP)~~v!8R(*Jo*;@J)xC}9A%h3&g&!%!)R(kwsW5nd%r_l{Y)twJhgTsJ+1vDc zcsESiQTx;m6nsny9J^`Hr%aBaZ^r*o&lQ2*yzQZ*wLq}YVZYh&6HcH=U|8Uul3b2I z>h&3=fdaKC2VZ_wv^_>YJV=PDZn~PsL!Dsjh$xD@_$kh-w4Wg8mo%Lci!$Ss#Mg|| z*Lf!hTOo>ENo55i?vZx6#VgHU7thzhdg`C=Q(Jl~v1X%dPS`PLOXT{N@;j&NJJE)o zb;Sbvu-(=h&m8c$5mzVm2Ybb896tGA6kl+vgQRr%Z8mwdDI$SMMB#L=Y?~ji)qhyh zApM9C*85bPx2$JL4O->@C^spbUz1WeqY75mqN2A&Pl*(RbjYf=0K*@&xt@D2Hp#vZ zRz(~L|MAdl&{>xZ3PJ2?=r~y7slkI9|1c1o_e+!2jFdC<L_tItt~*fc9Sek|CGw$4_*g{mluEj~$X`x3YJRHpk|G&; zc=KqMBs1$0B#bgs_a*|+(ff)7oQf2nK(K;-{0gK-cFs}J@8Pk+sy;1GhN*D5@Hi2T z+sJn$x}Cie&cR%u<{W?WF^zhRr6oPu%&%{PT%BpvzC zWk($(N&YJrB;D6sG$QbJW=eoWZ7-P6(hyKUwBFO)ZXY+)W+%g1fWoADuN;UTd^GLh zv4eZwC1pI{O7T4`CUj*N-H2pHfaVdEbS=PlqjD{drnCtQeAFXj z5Zz#qvVUnshnD4Kqd~YH_ZgDguZ2n*VHufW*azPU(x?k9EDk*0-XBcZmik`TrjKEO z^XT(=nT-lNh_8ZEJ2<~+-B?iV&jwM=wdW4m(V+GAr?C=cvBSyO+6!W;(e|HmB_zK? zLeS$xugm|MUd_+E&a&G@#r(eqfndb#N$k7~gjs?a!IXETK;YitaYjRTP%}JVpKK^vv zUA)|Szy%f~hgVnw`GEs4)%VS0K5};Lc3ycm#6DnnU|F--7we@%++YAzj?GDxy!w%N z0=D;bp_(Q2s@g)FR&-oUUzXr3K<&MdM~d)-h-D78pGUMmETj7P;M(sz4;1NH`MzL8 zR9zp}RZdrxKzHr7x@2)WdUO0m`oD~Es>C%j@Ir!PQ~}-|KT6hci^JkwtiW)!ng)*> zsDxX5qA)&>(DI0$|otWb;F87LpP+Gu#+FbJ2qQV-Br5k%@aVsmY zH-S3Kuc)d@Gu7Ullz&}X)9-EH@FNulh;z|#q!t*)DfhmwKZp0Vj4SFhAOuO=FfP$E zG5^ur9>d9s&1AsOAgpOF;k6XiWE3(ShM_u`dGWFzo`g#5QDw04{)5G>Jd3eaUlgQj zE(BKN`*TOI7q3V`)rUE`TZvO*rqbQcG^sdL_u4d0S3Q%@)$RT<(`nhJ?%4^RNZ(MS zT1_z9iWoL{ND_|^9M)XQS~km6L)i-~WIuu9gL($lb17JsK0@=Lx(q?h3WX|xvz_?y z#plN@`m8~BE<#pK;4|b#J0ok z%;n$MVp0q#EL0AktB~4$cQ&tM&>1!9n)HK;_R43T}a_gL!0Q{f*g)z-l!GS=}yd<2LR* zl@C2;z%%PbQF>XHo6plx_&D^*kH1JzN15}d zz~(YiU&y72=&9py9?o#y0;gVlli6qPD{{;lBq8-l41{Tr;2NYl4oe#OZ>nRKP5h|j z&q_h^&b9t1m_E38L+li9tH!`U<1iEL3{Yf7&qxCF@5~Huwtq4+ite?M1>h0OrQ5VV zJn(Oc+#bDqQWkMr_~rQ7kqC$`QDt{8-Pb z6bTXjegovxA{`L`SAgu|VLN0rw3OpQY<<{9n157Zynh@duXm_ASGaKZhV`j|v_o?x zu&6vJo@#qcZs5BnQDuJUh77^uGvC}vg$xR*jg!hto#3Z$TqT&UmZr#EOM!kHamJ>< zqb_iSr}J=%JEQ~*{h4Gg0X8P+N9dp+i$+7Q&I)SKv<>xxGwTE`JO90LrHU2~SGHeS zn*ytEAk%IC{mvjjd}mUq&^AjkzKK!{JyK--#4#3ka%vV6BrONpPZ);lDF*E|VL)!0oMPO}ID4n?$lA4Sx4UE8?%1|Eww;d6j&0kvZ9D1McG9tJYgNCP-#h30*1u3kZDgk^ zN7X<*V_f%jo~%f(W)X$u1@XRZgl}E)l# z6-x!QuQBK4$s-2(p3Y}22h#G^G|T)j5oRj`?VhCEJS9LQ+6jJ90Kiv2Gm(d--g5t% zAuSgedcLfBSf;bUc_<1MgMj7}#Fs{2h(Vr3o#cJooKn}RPU0Mh(-k=wE(cqkZI51d z&L3f!Uij5iN(5p3{N8tikYv*wj^k_loh6*s_*Qfl=8WpG1m-Eus}75i4N5pyJF1V< z3uw&`Ec4rC+}?FkU5^6;k2}2gZ-5F48$Y$kOY(#)E_>3IU3A5D4K|wA0EZ`ops}v-hI5$ z^o5D-u~p!T>4(XEQ1C1h3vbi2-rDo}!`<>Fkt+uX~ud2)531KNf z#hF`;^JG7R+#DpULS@nLGnQS{q+!F=&8whwb(0)KUbZIyVX(u|zT5gxSAl9ok|bFn zD-l&dAb9-(TEs=Vd~rQak2MV7RF8f;<*{RC!3p!PRciyjVBzpJ-T{3o(ZwoQsHDTH zYla-?DpI&c@BuQXL#Z@meH4<_-vo39gAj|abgp)4Y}eLp`9!Fy>b=2w~rN8T&N?K+tXkpF=(0!aa2j7+KJve^B^ zwEUBi(v~5Af^~Xj=nsVbqX^F;!-RQ$1Ru(KI!J5D(Q7%){|bnu&EF&BoPVX(k7T_D z9EDAOjS<993;9%nKuSMJ34U8qA z|LV@`2picD1J)3aeCT653{rREhpvzR7~u22@Er^j6)akC=(`4Mi57o!Zgj$l91Pv% zE4rU#OCkthdSklD$20}Oqg;ff;TtQIzHM}S^rCw3&0)IXFlx&6ETS36l!{Y9-Ti7; z=#>@Zi6&m=M$S+*DNJeRu~x%YW44GGmb}u;*w|0*S;~h|&QkIBKwmt!y$JW?G(a$6;#5yC9m6X3bz;&4>V<&wvbDUV zL<*piq^C%=Og6jQsC5_AUJ6r~Oc~7T@1fdFKmkl~{27qmXGXXjmlga;h1It$0Nfio z8sDrAcRiMFIW?6rANZ3R0NHC!u^4~J)1JD(4_HueH@b5r&qI$J2Xv>8ZHJ;W9mW%- z_l``T=_;usto+|&miD#4)XK5!zf?GrfK^f*&K-u*|LDEaHwSRAS9*4KMH*yS#Qx$e z&0c~hD8l;?YDrg@Erag3!xA0}!@~k7O7nA(0tZ`%VEq;11i@@yXh}KeEEr*Vg8Zxr z4?iWcuSWl;6)a&Q18miHm3FXNQ z*!U%Ps54&JU=oql@zFOgLp;<%r|Jnk+BgsG_ud>*KPEe7QF@Khv7~Ej*y)$8tU^ti zb&HJY@QO5oSEd45CL;mgzdcm1b$HT(bYP{$zv-(@H^GYSE}+eYc}+qo-dzXv{c1Is z;BpBQvL!~n>3sPSz(ZHR-3W-%{{bg`vwv|{g9p<59+YN{eid_^HA{bQl)iKFKYq#Msu5e49Tl2b*8(at@A|9eH z*+_c(tk$q#Yw&>#i-bw|fAAx(_ZgbWDWm~DsCs-r^ALEu3Z4<|JpC1SR7Im-r;zF+UJ(jqfjJEs)TuBVeh-jQh++SMT`)47(_pw1 zFwW`7fU&SB?nkxc7FbR~4MT9#qX~@q9&Y&=i{5z5{?x7PS=t#zI7zb(xnnFq-eBXV z7kseLL}T$wJ7xy`iAJq0NOsjxEyEP473PD;-#`W$+x3HYF5q?J?TA;s;va4$;dr5H zXJ<>c=0K~Bnc(x6{P~UbGpBBsSX;q`5hp#qDnJ>=83ODz#naPyTnW0c2NE(w7~q-* zU)&tkE7di*Y`BzXGnKgsOaH-UNbUi~5F_zDs3!ue<5q5e^c_*VhHz`8CoOo3eHpQ; zfbylU8MXg4zZ2kYdT;kzJ8>9-WNqC;^y;vW_`BD&r_(-SG+}0w57#<}r@=yAu-S>G z&XN|2#ePhCS{mrsMv^8fW0ym9LXt?!mh?TpCK|+^Nb(GhadrnSeBtFU#Rs#=Nu%?>4!T={Y>;08L?g`3 zQwTy8en1e=(m}g%AOInu@4jL+SwgD^>+UvZQd1l^ihVs z0?>{;r$PPZ$O2@H{C{#}eU9hMvY7eyjI%kdp!Wb9e5oQsXWBaP)zDDvi=)F{H(azfZbJg5DDqB%0gk-DaD({9^TWaHWZ_xHyB zgE!lgKZw|;5Q;*HRvb6;duxmNMj~Sz2zYX;`ll~>W$}?pzm)-O6i`C zb;$E%o@)l&al-0s6t*O9z4+S<$?_S`A#2FE_|9vJF0QOVU}@J$rT=ZGVEu19MKR#M z>d!nE%j7L6GgB65o^J9niIo1Tnp$SKyP~947w~O1i<2>daRim|GCCDhiv6ic7Bul0 z8^bMR3uxMlRaRxdY$7P7+0z^O?@2@@O~54L58mICh<=Mk%;C(8F%+fuGrl4>Q-$@v zu2XfBW$5IY+NH|9)FEc7sQTg~wnpNbQ!%OchBYRWJcptkRxp^;Xbabb_los|6(RFL zGNe6ooH0F-2Hi<>cUT*yOrLolRb6#N?Ro#xOF<;|F>^#F&_+LMV)S2leMP!2b|6PnI|5+M6yrw~HO8s7*hlNUF z@Jh=-yY=`Wp~Q?VO@Mb$gG~6j*H86yCYcGDL+5xs39|GPC;&hur95~2A|N*A+8w+2 z8Ea2n4mhfgAYq9@F!@l}N8PRD?`D?IX%$H8GsT2iCBP22eH+BqyaW;<=2!FE)L7#B z$I)O=c_6|2*vwvn1NuB@mhO>1f-a}_-)IQ+o_P4u|CeM4Ye!=@vgtL=FRx)u#3 z?UyACUBI;^T~8f;!Izuw3JIv2>Vj^6#rgU&>_s6I+OIsOeQyNydOdF^Qi>5sP5 z)Q>Nfn8J$e!Z=!#!_EFB5n=(S&CpwrwP3ozSjP>j-bKga)l_&fFTak05Xy0iwsjOg zBUQ)y0@S#6CZTvjnat|>HM z&-=gOT&I8^u5as;LiL++?J9WKQcBtq=QA7OWzd-Y<{#R|%XABJxDxbO0LQ$6FXTc_Xo!O3feu%_?fBy)Pg>d)-YCpU@qya+`=K00`6 zJX6(<7w##FRp(8Uh3v9Q-$Fp7yokmVpm2S_3aq<@!DX*~Jy6}Kz;w1;oZ%B$Z8YqW z4R31T-%v=277vvxrx6D@f01IyR0P6!zgq8tzrID5cwgg92#td7SSNT0wzBCluPkCk z&hGP6tLri?F*l?_DNzOK5!CLwiVyvTXf3VZolB*G33aq9zJEg?xO#=IZ@}}#sY(cn zfQe#pEBPZIj7QUOhsF*;@aodfL|0-6Iu@09M>E&kl`xnr4>VS!4pIR&Mw0GoeQmncBSy&MWpcUAgs#E1GC11O#K4wEn^VLfMA`t6u zfw&ufUO8m`0M9&l*Us0-jQYX6oKvA58O|I}L=FA{lhG;_^id$IvCfR9zn?Cor%W_q zWiMctiNfLfOvonI!jQeLZH;$2$R+xX23=~k@P234dgRjz%8trM*n`=5btuxqteNG> zLS^z!6H1!LtM#Q^V!M(U%}?XiH9G4Rmh>)H_%IF4>PNFG9^Z%fc1p$y{|KyVa&=fiA#uz;AY=5{YpqktbNBhIjexoTKx3d*w zWxY9_&VO4f{uEWnW`vFe{&$M^RnA6i!v7myRpojxf#gg6D^|$xP@y(UbS{3!ZJmth zxPs@CjCyk9VGyhJ**R8zP33BAxJe(>d`Aerkgh8e?s{`zo7Ide^A8Ay+?^a2c7V0< z-#S55v2~?_LiQ~v(@JKZYo%Y5q4o{_Q-PthSiCmF8Xs8a9wwBMQ{+r=TD z65QWBY2<_J4U1#1&1nu7!c}l!n*Np9K{YHjnNj1AZay%F(RG?@&RLuSJ9X*gdmPEd z?hzh0v$m?xde}7~{Cek#GQK^T>lbZrK$A$fl*^ly#CA>*(GF+OC5jw74drN*PCoI% zB_Ke9uQp(E<-8NI3i_d1X5baahwcK**tXzPF{|;I1;;lO@QDgz4NLmXtv6>?J))LP z&68=uDm}QdzzT&GBdlR{L4U-l;Yw=M=kd%s-rW_4Uu@qlUHu^P+>uKaAZy0u!Oajq z2tEAWW%=76;T2@O42~4vz7+TkQg=+~Q5pv(O6fDWYvPw@9DY-po+f9V?NgWoLg;B+i`2)2VuIh@myFaw#+saF40aOUn8Ii^k{&YWUEh4Ne z#Jc5CkFsJ#^=ra5YC!WDJNk(#b;bWUDl*Ds`Ti}7qnP`bqoM_pR5RUQ0SU7w_sr}p zP=5ORW25o4y4x7FD`IC)5!7MHmP`9UGS0+UvFhzRRil+^K#f##{rniw;h`dj%D1F4 zC0Z)6pFY#P`pfV5{=alRNl!&0vMjEMg+gi1l) zMIz!g?hNR*j?%kN4YvjAT6mMsDxh`r)uN7Ztiy@K6e<=C;iHB$G@=^n)yVIC16V#l z7BR;T7* z`dtq(xibo-BF9A!XWZ1Ulz6!LIL#2`{~7fh5u*MpRP*OD_dHzc!;xHoyt;KFZGP4q zOta^fECJ=~@|fb5XuNM1m#5KRWd;dgExV|;rI*7XhDn>ZEG>cHfYwgcj>~H@YKJs! zMxm3M8ioqwG%b-mQKxbpmG@F0c@ud!@2~bZQVfCN~yb*So{)h%ZiEQ4Rt^&BI83XH1)tCz8 zpY)g#LCImRDjlk|UTGmorDcifI}7uZ2DvdexK#;Kk%DRZXPza?DD!uoHT{n~%OUQ6 zq!nw_zoiv(5XB2Xo-&W{9vt4CbI}||IxcV2Ctxqw0WamjAY0zs{^0?~y(m}_i zy?eivo*#+}COV+{iL%$8(qW7?o$`548rWAi3J*RtbuXbB{1s-|8UGHm$m{P-iH2l6 zBkeqYSmPTm=9bZtg|*mBcfdU>_O#xVe)=FGX}|*aBBpIbDDlr$$aziu(!sQ&q|j?Q zm#yG+h|E?apu-Fbx~;F4LOoEnS8;e3QHU*k`1bu0Pd@E+1CvqahLlGN+uy`#W{Be)zKZ72wpn?H@CANkT4vM9Mo{^^4m&*{93G|!R3W}fRb1y zBY!o~MOjC!^?wvr6es7d%*H?>I1ItS6rZiY{0uY>6%gOYwV$KRpe!7nm!YMCPW$3k z^o^(lYp9Y)(8^;vQw6DauhP;M;UNH}CHT!`vGKnnsER_{SOQvidee*rpEPN-`kbkD zxM$^_=RKuAC=fObAxwCZf`AU=+qJo#y~#jXZs01Qx`p7}WCd?FgVMtMY!Rh<5eIH< z4vk{qT>RdP2hL>+EK)qy5A?hvRVMuwdPxnuw`3?PQ}vakMa#^_=%Zg-Y4>3rsqt#J;3FVrF2q;#<2Qr@fB(Pnpn+;AV*v5#?dYmO0BfSP4= zJm?pkTb>8JpYG&M=)|HC?DrWxK0Z!`U1%R9zhM4*)9eP8<2Zgo8?aMkqoD#M(Igu? zRu1QfBZBbItluTraEvaV5c0)drg~>!A#=Sf?z zyg82SR|`mcXFo_!c{{ihP_uRTCpvli4|Fnbe~mf;|6m*{TEklBN9>e=bg>GD`Qn~u zW@YLh#5{rY?m;X6=8JjchG!gMQ~D7vI;io~Nq*J!54gV=3PW{{aIAjF#7T(qp+`7Rl{23rkwERjvEu~=jAJ03dqDB(ZV_$wN)s>hiG8&F-DND-=hyH@|b(1|n8@No?*lDmrC*uV}@x9a-j0sx68n1oi zs$!=sKzVRGZNH97fNNYr4Lk+<(IOGre0-Y2j|g0-wA*Y-xV3(R-Ihz)SVljrgHyL( z4Q(|$_KI*J{yy9ss7AePThd%FS6mo;0gjQ2L}a1ey5B$qC8~Hut-q+yEe4RC7I^XY^GvDN z&kg{9W0?Ss);#mC-=Jr?OKTP+d(5%;F5v#(UTe8Mx(~qkGVCDtYOUsTAo`ILN(kWc zaQF8JqpaT(7|zT*^8P+PX^`e`D>etW*l&jgEXe;uN&y|5kB{c=kyVz6>`Mz@(q5Mv z3LFqRAa#wCqo#^Y845d^Lv9&)JeI>Tty{wc`F!Rl4OF1D7k#NVI4rB!Cnzz3tL;r; zvwY}AW5Q-f#uw0C9IR7vK>Ulg#D7KoXAWn?+LDbHw_^HpTt3JdakEdVp@l zna-*O+kLx=vxHQ7VD--cYtt)gb!aVb4>-nQ^69u(1OL-hKhN>wo`L=E_Q~xyD!F7k z#mFu(2i2a=l|9J{AgBhhD<-;p&cmvXD^H|OG-28bOf_}4SA~@_vQspM zogXwP?bS0yuD|eG2NmZY$$8%C^E5!LPcc!7!6&rG(Kr?3IObY7{xZ2!lYk%1^vN|N zOrFioggsQ7wx}rP$R+wNSCj#PtB9CA`K)F;VB5kd%MUo~-d-P4?uEFy%AOtqo~s6` zaAV$>hDzQ!YomLxmXTO^B;~5!H~W6lI7SN-Cu~FS1RkxtvugOWK(yi3{&hbaLY&Nu zXtaYl%c;x#W#L_N>3^jQwjg&)p%3=q(LQ*ch}`D$zO$jCP*fFi)4_OLIkH%)VWbDS4+i%UWQ{ zqj81dE>TQor({pIME3%S{rI8kA~I@Q_M$u`dedRVCejNDVrx8DefwMNneneX(7p6U&m(7DY(`GZWcDJZSTDWBlHoQM*f1zugbq2y;E;a)u0+G!3= zT*B%Q(sJn`W2k za(V2E+Hob3!=w?ug&tFj-%84`5t*=*rGk`^Di9I#HGX5SNh7DzRl5tA{Pulu5BOn? zVU;AFvI&I-T4IXF>jr-ATz?~?bPmeK=~S&Vp$Keg)>lvk{SKHhZhv4!rBx45THm3! z-FAPp*og2`;fy=YUhOBuJ--5-vmKmSh)tl5#dR;T<0bTJTzuC;Z`piJ*B)pcGO@PL0Qpodbr!(`Fqb82nCtg^Q0`%fb6K`N6X=4-13 zlVkNNksQqWL#q{K$kjdR$%dx1fB#V|5Q(z~E$@{RXQr*uDsb!v%WFY+Km8+FoPQor z_PLxeU^=k_-{W1dWM^s}mjfJ07%(IXjIbQfSY%3aG(jkw(j@#vA<7tP3#M#~7LomC z8q)g#BQ3JNj6tOZOo#T@Q2n!)X>9wP2sm9O0n)P{-GeiJ{JAej!@V`sspmzJS}|KKz+zwC=NE{ETcS{;y6Kduf6Psy z-q8$k^1&5jEAvq?9nfu3-UPt<6I?wkb=CVmv!3+zSrs!eR_BDd z3#D@T&)Q`glf^!SOebLYUziaq3x3uD+0b~vhQwME7B!je*d2uneVIrLbgBzNR+wsnUf_nce-e3v!^H&BRtv_JYO1M zgmTzxl(^O7I`{Alea9vi=c~cBILyVke1^5Oa(MV4mI+j;gSMC8uH0MpO!kg{M@)#Q zWVpy!9OV+vGRg@B^dvvIB<+CeO2A>r$`!RWc!6%j<=4s@kP-7HD1 z{TjI%foHzbeTF#e=F(Y?)LIpxlQkg=%YocK%{diiduFfhzqZ~50DlC-H@TYBY?iEq zYAZ~|?D6_tOleo&>`_|0bwjpe0#$#nF(nEa%v^5}9Pkz1q&-7i^;Oc?lu1cs%qH=dc@gez6~bX0Ln44Ncis zp#2$!P^d8Qf2H6PyGDR6oe;R|9*oXa_r1Q*gT%4NHG|$R-OSJQ5+G_r=mS=2l&1j2HN{aqdinx-q^|czxJKu z@!hwUt4kGfP$dfUo$&w;9pz%|W2f}+NWjmJ*)k`kLB_jd0p`Ze$pq1mf>uP#8DvkAW%}?6CyWg?4*6XOTGX{U!4ZA*8 zsCk?6KJaDLj9yKaafymmUG~@PJ(hgFTf;o$v7@XcQM5%Vp2i-DmZ8`e#`*BS9z?0f zPW`!GJdZ7&w`@?lre})HbnZt3WC${vbG~EXUY}-yGMf1ZTimea^=is!&)l(iU2@8W z2C&%M`#LP5&JX!$c>ZMuDugYV`5o?(oEhPQFl&p?8vcFx9qSj%Aq`cn9?!Mnep~cz z5dlGfwsaIeYCeG!{>6wV1cMw6V(vOVO`YtSklMOVG3oAOe)NL5z5LS~D;prO`C|kN zImt>_Y01_EGA$249w3)2Oz?*VGVCACY1}b@v`;okC~we4NN1n(Mi$X&&{vS`OevF1 z8OC>Zf&X4vaO85~{YNaLL3fc&IL@~edvO&Zgj0Xa1I`pgr59zeckboh&M>u z{UsjG&KtTE=I0?e5K|p9pT|p?9hKx9u6Yg==ay!lZ?T zK^@Ol`hT1b{CdFnq7&tQ1hTH?;WFzib&7M z^t<&95N5p7@ddXV4A*3dj>*5a%Oq!o(^lbbZQalj(Q7re$I}K+$lW*k!aogbUmi~j zaKTCFmD{+8J|V&s6e(QVMc*p$Xc#D9c_FU*%L4OwMO2xttjwW`_@`SLaMu;e^JpYkQeq^NkYQ(9QTkvo z5w+7rs2@S(!)0hmP+F)L3ih2d5iGj{Me|9DD=08@+LO=8?Uiv2^n-F`(7v+Mv0(me z&RX%)`DCSdeFzq*!(DE_flR0cysH|0txUZ0mnHZ?1}lQ3m#b#*66s*|$U62s$9VrR zT>Kf+Q(U@idWLy~`o5#8{U*ul>yNF=(&RQsut^KktJP=eOA<#SevU_B8F_<<`w zxaym9di0GVS?pf>%kWL=Cs{tVnKc}V;VcYPs{1iF4KQTOFy*)4<6KNs`Ra3icMdEY zM$qNZ0^BtzH6@&5+0Ir!aB0q&QRuXV-xu6$JYWjXJPPb}@{P&f2Ab*_3R7jWz*auz zfxZaPr#pExc4bBrDA+DqYA_}BV1!eLdz8^Jej2SPzDfPLSMn-SsL6&tBu6C!{Vkg64G5@9iuv$C7PS$0g^J3pf(Xo0TT5`dyC?$q!47*m9)r!BL*Z$Mo;d7=ju)Q!c+I0!Si zRf8j82=JVmyxs2d2dPw^`g9Qva$^82rV5@%hwmKLx7g?X=>lBPtT40#^LvTr`s%)V z5e!?)G+nu?+_*b<0Sup*6$Lc+pQ-zjy%cu?G5BA)f~#1%1>HwFr4V#y4B6xpL3dMO z4mybBd!zS)Kqf>88sR5ZjjqrUh^x>{0`3pkJ#VogRHx-CTy*{tS(GK-iX*M>IC8SaX z(|7MnLW#}BlAvZ0b?Mx^^~%(IzHQT`6sA7xltHF;4weDI0^Hdr=e7mdNG%?437Sp= zX&SAuaxkPeq~JI~x&v|&wdCA`kkIdi+#hG^OYE-Qq*N_S^7QH}#wy1Yv&S=W*%bhm zruh#k!*3TRqBlKL5hj{K8HeyTp_0)RL84{_li*PGs&`uLECz;gcwZhiq;%=`#fRtj z!uTq9RVMpjNevP}Wk}V2){~ZqpeUJ+i0%bTC(@EIggLWlBa9i?BW#~n1qeLwR$ISm zK%eqJa{4k5P(AwYC~)Tdpk|yq+xMkre9oqR`kvS7sOrwBTsdX9a|CUMAZNRlN@&d) zK_T}we?2o~I4PNUxkM@KB;?||{|sUR=~Uhcv0dGa_PQKYu${9NYF4c#WcV89_Dhbykcu^%cF9=LGcG0&0%s zrS8fHw$lO+RKX#S2Q<{v7ymv^Ke>QbM;ECol%i%$W(@N5_c~OzeZOjEI^3*C$-eC6 z1B8O|&I6DTsry5wy`Q$lVD7~4!vT0TIVfOvMjZyq<0O}P)oqMm^BK6=dPX+a@b&o( zOkCKbIhU7G(UtI(2_BAyp^>e(MDgpD>H*A6z%Yq>DAFlHA_#of9#mP!5#JgFAUy~K zXZrc*_Ue05i>j_JFBqF&4{;FV9Wf!VYy>E+kH>o?)C&0K&L=hj(mJ3H84t4{Euo^6 zQ6=COZY%tdC~4wh!{Ey=FJ4QP4+Oa`wpXP2S^$ zaTwlEJn}*@&Hd7@y_T*~g(|EOUWn%$*8K6acMrT1K4xpZLUmfsNQHXDB?{-wlTep| zzt@KKaJ|M1cqqav2uo|iMB;jNXaxzc1VJm3c3^=hBbph{fKXhHf##OTrbgKcT16SS z<;vNq7iz*XqMN=pkQ4_WGRElTR2=6>wpdgKqM)Ws*>HS3d%aczE?*@uHUVR(gUJP#k|u##GkuAreqp6CZ^v`ZDfi zrN05|2OrkkCw%8lSNu8JA*Mm0YEKkg`=ur}9NUcjB{q4+jcL_brS(vhEHSfxy1P=n zfSEM{bkx>ERx6iqOhkN+w7s$Z_(H& z%HM(uLtte%vC`H-)4v|@e_nou!mf!nK0NzZ4T8~UvJ@V6koubHB=-@%l-;WaVhbi)-^ii(PW&=?H6g!GeZke_3p@eQUMwI;zhs*|97U zAf`Qo%FId+B)Q#)8F2sg8CdYZ=Y%)LC2b5jvZ=tB@NCpBJ$=ESC#kn2$Oh~Sd`42B zxkta3jFl1w=?vnm`CRA4(sB%YRUYft{OwVZQy1eUX|9M1`<`Ig=$L?y2o7I9MXRJMS+_{>giaE@e_u{z1KkHJlgn+_DY7f;~qMTx{F|T z83uer!<{#6Sh@p6Kfm4XLXO9nrTG?6S8eftVmjax^^vq01mI~l9jTE%Jf{K|rJ75G zmNG`O+fHCJWd+I?3qJ%LUw2oAw%uvKl7)(bqP&HiNj32#;2IH!{d%L)yFg3@yYw_L z^#Nr)zk|;1UY~;pc%AhW|16+nhubI!ct%ZIgyRHee=7m7>!%)5sk{L>-6@#b3x7=7 zJM&uG>oD8&n*4&%$||lD;?bhDki1|#w(IP>m4uky8pS-rEkf!e6&r%;`8vF+ea4-w zdR}|w{zKrZh9vAt-7}Nm2K5;$)q78Q!Xko%plIKy@OF`e>b5P| z+)hc)1u0#vgE3o`YUI%bWA%|4@LOvG-4n+^qiOg+ME`dn#{E`7vNTvuzpOpgp!j7a zv;a%KRm?XVg?;)6x4bc3mTd$i6=rZfo25z+3?ca{KSRLE4Fuz}b`F+1=8DM}GD}eI z-CS8=q2k$;Z@90Wm|bB4VBsAS$?uvdn5W4cz+wKw*LBpETkdnNUpN-JtkWl&lH2%2 zw0vB)wBDt2Xhh;O{Iy}0!2Vt1F<6Y{P9z;UOZ>_q3K+|4BQrbj>4X#!vtsAzt@Uo5 z{RC4pMgFE<-blSqjN=1Go1slDUw1pSeD>}2mk~}rhW%xK3SHJvH^ZwDA!VfY+7Jqf zVy;kbv(AfF-L$(`#RUchTV@=ZuVO#)Jy(W;D|pal-4?T_ub{hWPQ(QvbGSXfW8bzB zV=O_&95ZG$uI|s_hMm~Ly)ph+3hSLb0y{byA%hGO;kRP;;Q`i)FSn_HGmCBy`z@ z7+M|Gv?I(NNpx-l4KMeXEIsmGO?r2ESYfuaL6t(wA&&-d>f@+hpna619vQ6Z&T~2q zxsT}L+sj#mD{|%g3gj&NU|}|0UL1VtvpUM@N_7v{V-uC}?1j|tLKst=m^1Bk2HfhH zNYgRRpbE%gw7jG+3`OP$wVBidn+5M=S4;VbLoP?Yh0M=e;bU0XH&ki5TAwUYN=;NU zULeEN=LVa>#wcgv!PH(_(H#q7*Qw@wAyII&#$YVa*KkQD{)K5VmP3T+4 z@v&8HpJD3Wlcqb=_zB%DpdZ+PI^nK$4>RA>?Id>}M-j6aYfT5-eT z8lP`YXT+)MTY*NVpuDTv!a^2}5{y6&Obhw-(eh1geck=sS~82ONYZW(H3R!t0ytw<#Xt#Aw9)l2=Zo0~UN*$N(GY@BVp!M@~lLw}B| z85py}g&^wXO=eXAIH84nE*AE0OxWRfKKq)-U!?#Z`%H>d+;n@-roS1!*8H@Itjxxt zQ_wS*ya&a554`q7Z@Cv7pw(8r)(chSJ7e%LtCOYK;y8~vqkz_CW`s6ukg)KJ36pB{ z&gYp4%@@lR56q~E*dd$ZR5@!P&YHv#@~S{<((2oYAtzg_^Va5c?~>Ca&)50Rz)}%W zZomu)b}Ni(XkOF#W?w0Nay@r6LZ6=Fe7p|mh0o1Tj3tko&(amv{=MSNc*af0|JfK7r zQ%h|v*wE7t$p|mz-D?i#vckR{0o8q=LS9WbpoD)P?#kgGQGJD2ny>Bse5F$L`^H5V za3C$mleUenG?tNi$!B3_?r-Ip91nq??<$70!Y|ga@{FhlR;V+rzqg=6X=-eG@=8Aw z5JEvgjaGSYg~4Kg9vB!+b#mV(rU0$eaFWX>PfmcJ zXuyl0!q#GRtX;G1GzDC}1f>9fnR^~RKG=6=#q7i2Xfzv` z@9CU5S`{lMdW>Hb3Z=UJR9Ti{Au=hJ}C_f)X(y-O+Rx&V%XNq?Yq;VVroGY_TY^kbv?_JRr9Ow1 z9$m(L!w&ec@3s851W>rcgB4S1c$ZG8^9doQ(^umw=H{eEqYi0I>*WGM&w4*YZYgb2Ewm+% z8K5TTE9m=w$}|UF#Sco4Z#C0698vWhXbNmrUlsV8XVJakWWLF2OTtWG)P)y2MIhtv z@0vhs+kJ6*&72)vqic(`!gOhxkdtD`LVJdDD(HN*IMh)B55m=y z=h}p?qu~)D`g{oEP$&ih#66GxjE>BudOgfQ4#~boZ{*lhU;;F&sFrSz3o-1CM({fBjbKVpVgUcL zhja^u#gRb3NP*K?;#V1@?-qv{CDF-SNqb|wyZi0o7eZ-nwu|M+5NTXz!j0HaTZGzC zpGI~Q9#0r9*e>rGHBLXff$~pG&BFU!X*+>#e z-TSoEBO^Rbhnjf>rR|3hq$YAGcI4TEXDWYox-yo>GX`u8YV}-4c#4iTM-h}_R=qCX zj-1x>BGp0taM<4`m~FrYfk$iqxDw-bLqM#=X7CpPM2vpJ4+Bq{+b3X<_!r*z3N!# z2~U3n=2HFQl^EE7Eq47x(qm0RJ9xSRa@X|WBu5fta{k?;ervB7F<~FI&ASrPHqVBGYN&Ci13M&Y4fZCq-mSFHB+ zs5lV$nCQujM$6Nim|__2%r(7oC=)gyS#aI`l;F$u`)KAw_O_B#q>wy2(P3!5eV+kK zq0)4L`GEokvS(jzeWUHzr5}m1-jhKZn<#y%bY+(9qFg{Kd3j>Y_S&|PJf2S0wl^kB zyXd{|dJOF85kKc~bmc2J6VtDKHZtOtxLOI0@RxS?_YrkA3VMdRpQcZDfW5`#LQ^nMED+p!+YeTnMJ!z zE0`)#(Z2-5HlafQK2e%jN90>XVmYZ0WWVCEZJYQ(n6F{vajHmKOz<_F+tt{ty7(Kp zPj}PTaBc1kB8V(WszNypI8Qq0*;$MBayadb>LHQkxu{?h@SHAq01K58R#i{Y&@hKIinkW85|P#0CacYt>w{=I@zL zO{LaWn9A8%AoQ7xDl4Rg-H;XwulFMdd|k_8a3QK(HHW3=KCYt2K>vthJ0bM$?mDpk zMNGf8IhC4|g70$4w6!$Qh!kJQ24>smtzW@IMl__(6cG{>VA(+dRvA)1ddB%3anBx^ ztjD#PR;^lZ!b*mz2pc(RgVMP5C$rb^*70tdh6}jl^)GmJb2l~Pk+g4{X>TzjW54W9 zMR0^wxkCBFrjamJ=|#j8{cJHgj6;8{IZ6v5!)$xk{#3Iu% zRefB+)s;+(ZnF}vAxm|9WnNzc_hu{>rlJzfOGsJR%w!%zhp&oHny}BGT&^_W(j4DY z^rw5|OwTV}a|-hq>W`ot8~VI2XJT7zzK18R!ou+EADUK9yH$6A-Ah7(B-AuT_-g0X zN6?YTcY~R@2S#~QRA-KZKAA@qF)*=WJ^gi9&kHbH$q>;QzGD5|V0b;Y%=1^W@D(qW z-n|nj?f~7oO3PG|4-Lv`(W$uShw_$cL52<h2ES9tmNpuhbA1m_!x)LI(M?B)I}TT`t#evIz%vS4HwE3DHc`5>ia|f!}gb=MtW21q5DsFK2 z$vhSs5vL$YcTPn55*A%6%TA&5*1VwYXm#cTMJ1t60k&topNfgoTE_^lU{s}p0)h5jsAjN>ibaui7+vTjD0Dr$uD_x`WFt|Ak>0N+R*9&4khzQ;8mkfgEBoHl zho|NKlm63r1ft_({JA;3y36QxcSxKaN-pHZ zjYzEz%)51h@j*!N84ZoJve;4R%|MFiKB&H8tE{Vtm5D?OUW41EdUpYEG}MMxApw>_ zCx?B@p$8edL{cLr2ZuB)4G`$Yh00bvI|hr1L0$^g<5=!1ClQ{}=iP-to?IrpF8x$Z zWal`-MqoIk*2S7zw)nJYqve0K*r?PQk5A$8L{eHoA4!F|g^7{xsXC%Q2*1^FLlJP4 z`~e2}Wfx0rB_m&}xRvvXII>C>_3jV%d@kFavC73C0(9T? z%zj$eOV@KMonx-uW(Tp$zH&tm8Qs{p%Kq-8@Udh@f}IQ^RZyM`)&XyODCYC*zpCkP zN!*})AG3vbSpW!4!L9kHC+_!IPYJoTa`u=nfQf4IaT{(Y@ zBA;3D2~~=!a+TD6V=#G|nMBcwHLF2j{A{US3H`u;C)*D%>p3;$6abyb(BqFB&XAqA zR|5xusPF1zh*O)QK}g~|fXAD~iluF~pn_f^n> zSrK{Gd%wHrLX=LM4--MI|G=?~Ydd0IxZOd~R$Weh_;dI8H{BZD{i7&3H902LnYr}b zl~pYs&%+3zbWlZ3`o#)GA(r8e=~1VnMQP0Eb1Ftk+C7y>m8>cg&a9rNr_(>N;xM^A zS^*yjEJ9|``H-S2`Ec|9-U;2ww+Nhbktqz1;RZcc$%OQv$0`)^#E!hiWno~%BP=hf zTk@bu9zhDmSrFU@S>Jj9{p#s9OpM?UR8&LNuixrOt=qe*f34|$qDu64 zckAp(f9$IKrP%8$ofh)K3e_h9Byq2<1%3B>Qo8EM+=cPJ0pcC7FS1)rYd7pL>aI{s z!YY||ed)jmMs&AJ;UQCuQ)S;>>BUfn(Dt+Xkws#1phvq!0%Ulxq3JA=vqH2(+dnMz=DiSVwD>UmIeQsjC>;sItLLgTOR+fx``E>?Ck5MkI_0%e zNtcJN3!65zd&P}AP)jsPr+FWGO+Mcu4!X42)aaUg5F~Y&f(T+<(0!GBYh+yh75f=2o zS=kda=WkPbyKyK(O9Nhh{PZxP`YBTB$OQehRjqtJr{LVtDy=MU7h--JGYI)kO*d-Y zytLSoUs*k+=Rr`<*97XR_a-$Gm}DD6*QM*wbhTevh$Cap_asbZ%)E1ZxOK=Y4u^>; zxhHh0NV*?jnquLx0_J7M6G7tQ<1B*U;7)#^G%16VQADs{~GEn@yE|!mUQc=`HaE6}=-J z){P~8Y)IloPus1*n;p#Oj<0HE@i`6T&Q@tvdb4A88CwR-dBO8bLIFw0^be(GyR`~O zbj5O6&SZ>ZClvl^>ZWQ7!+vKAiHjKdJ{rQ+=~pI$?0Fdg7qCuVZCWfbGG zH;`%iN*pVBk*=SR2I)WN7B^7s7B?PGCf$Ar-VAx!zMsfwp>F1LOAM=qsu)<>o*$5v zN>v*cYq_uvcC=mh^5dX(mxS)1{ptG7rc5PA%|DC0PxRWrdaSb4h~-z=!xe$9ofeg` zg9DstkzwNH(A{%c0G=A0X7Ll$OEd-}7t@@sWs~YAYEd;dsab>8PDy>anq|&!9EHKS z>y=s6{YH`AY?oG!5mUa%n6d`OXi$J9q*ltgJf3ukswF#U)ChKkxv>OQ;8v4!l(mFU zAmA6b$_&IL5Q2{y6&^jjkjm!ZTd6%R!VPFdn_5s3f2(>{^v%?p+NZ2e>h=jpy(R!f zc%&n$OF4JR(BCJi(q@*b13!|6cHdR%2#wyS%AcfjucvSeU(a@JK8={03BThb57|Q@ zA!R{Ty^HQ!v#4;cr({PrFizP!XrVsqAQTe};zJ8M>ETq}p}+HWs^Y_}eg%xM;U)s!4%ZQ&Dm(EN;o<|k(RUzjP-@^8!p0AVJypR%}jT>3^HML~y` zCebdjbDy^p$#x-T9D%oYKRwaP@mAdUoAVwu5(i*xssCHbR0|YR->-ZtFqOiu4}HA- zB&xGE`Pk^$eN&CQ-Rk_G7}N1q#}jP5nw|um5;ig;Zg>uZVfYySbZjx)2NRbCF+=U? zCUM`jBzNwebt=cSXg4x^!xT}_WFYqfRzzss5>he0pO)=hX+(RwG+lse0C2--SuX5X zb;joRk$?*g@O$CU4UGAG9)s|3B|INem3LutK%wM*uXsLXI{D8kq6USMp3cCYaoV~0 zk|3KP97K()ql75uSe~$d*9= z-zm_O#u}2$z&M(V9-%oiZ5U@1aby3%h^?Av3A}MZ{#un*njOOLiB*HZ@i}b9Z<@d} zoZ|^f^u;#m%1UQY?uHe?6I#{?diw;6(H|SH{SA7Sm%A83bW0x(6jA1j`Orn#?hgk} z%bvK*hZ8Wq{1e^`=x7hjZ4Qb$^;dNy2Ps>AgWr=#=Hn3i>?#i?RO-wLN>ecY-+>xh zxmm6M2Go4<5B_|>+%iIxnc9J&3itnw)F^1GYj4GpALQD#;Q=cQ@N~aOzM_ERzilut znjnAUbP?A6S!?&3C#V2|i*b(7F@xoR$_gV57#j;{5GvGlMkbk>6rAdEthv}XUgK+n zBOP)liMw}Fvr(^HTm7Ef2#VB-y?;e&^R&Q+Zud>N)2^ov#cG_rhK1L$Mzjdd<_e0Y zu~i1@a-Dj={B~9T6H(dIA479M_IUpQ!Y_MuW%z12J^`1~m!fKx6BSjjX!Qqb-QA)R zoqy(3_gqnC&MP)7u!FVc^;Sz!o&be3KfcIj1V-s2N>_iWZ*qD-PH@Y#;N#PK;Df#o ziEf`3#cKs;5ae^ud(Ok-HEU-=D*p^CNShZ7VIBtaJIFSiD?)`sy24piOM4D0o3BCZ z#mbOBp(~h_Mo!g>h9KE|DtDAX_nW#L5;`#}1)iZ&DHC++rE-4TD^>rJ!HfaEe9x+? zIWjKAO;Ti!- zRxoUAkb(tF&t$^5=FgQB4vHtye~`uA#>fBtrU?|3Bmi1>7KWd#u-Jcu_*7XLtsSc($?MA;K^$XxL}Q`yp$3$runLm zAUVw^4tjlSZ9w|}fN21sTM6w~tf{m#)A}5ik-ZY>JcTwXAvO;kpuSYk;RUAR50%ef zQ!AHMda!AK!VQ_QrJgZRubc_c`uI=!@YsQ)%XA=2R)0tv_;1OEWyS_fB?fgBGL;af%r}#R>%`xiY-14FP*OUW@I!F}OSy|enuv#L_gFz(VJ&Cj z=J}?*XP5Zkl!}pT*aRe10{e~4e(CAho$1Z#V7{s{j$tjAIZFf>5PV5*x9 zqhHXBckHuhVoID`4d~+21mNEln|iC7Qo14QxNWIHd!5RW04;)#DCcK`BCWrTd`VF` z*HlkaF+yxaPiQ>Q@C#iQj_EVuLCTu|qAm8tHoacz(C^Zs5}@0;cW_PWnwO{qHlD}; zC5-bLxVV`X9n1~27a^8fClMcu^sr%Q!3?P$;TemIQ}A2M@&KAKhl#9Q%T-#Mf4!

4PL050O7S}cSkTLeu&VN#q}6*>J*+_`S{JTq zAFhd^YX6}vOhp0IVo}b9Ch#|Bv0`vg<{qiE7NCU>Y@n^FUWcPa&+5IU<1RZbLsx3B zV@GPYfbpSYpx=Q0(EztbsI2VdRQpxU+2-v;%&fPxcr$yf^8i{!-qH$=E%Q@l)#>L% z2BSD?sLDm&fs;_*o$);hw^W0)XeYgClm?2k1h=+n6cIkJ_*{$9#ttGnb9$~+u(3RX zOI7ze!(5J;qussOX8&0Gbw?ELH#M-VZ@;4n6RxE_zN;6(^_?@$BYZT9y$_PQ>*17X zixSJ}G?=p#@KNkb3qU&6@E|;z-(UjXaAw@P1E;!2GRZvtLJrcI9fu{Y>~(~OqS41# zTC4Ffiz(gj1b->yMA9J|Em~qJ^M7@Nh0&==+){JXoRyJNHQG%wBefrsh-T}-Jz%Eq zo@;{iPoR6vcAy+n$`{RbxQS2PxH5c&55-EtZIe^*S#hL<){~?_mk=B^hM8MdGZtS0 zq0d+vD($;V|79E*qJMN`}4Xkktas}T22GuAs5yu<8jT=`!{RkzgrGn)1 zMo8GYXmRb02i>t|7GM;?&NHKYx^MG;3mk3-VDaT}yUh<|$Znp7Bc_lry|`wG1>&A$ z*LX^vhCYj$bS8r|l9s8OPJixqbJ!m}8nrZiiK^l)gy-ORKRJ2!ng=Srv&#ZXk`^bc zd~>puy6)u@l1@hemSgocFdr0dLmb6cpmlyBQ!KO@k5Cgn{^AOs$j1#Zwu+4$xn^rc zQPRGTxLm2{!wyF1^B$o}@?cn40?$Oyd$byMR!$1;2Az{vx(BCU8eB;uxkPG5ZVqMH zqj@uu9HLjeD6RP697{B{hwNNvuJhF3v{ z8BH`4h@^jiFT!R4X#5vgz(mCtx<$S%6Y7e&ML@10`Cbw=j?{eY*2#jt=PaFV7X zZSWT(TNnDE2bsN2+23I?knP8c12M?KR35-@zpCteFfed3MxJBEl!QN*28t z*ll=XA94`Ptw$=7z3ZtE1+sPf^Y}vTwni*<2yOk#yycI6KPA)5r}7bWd1(6^@52eC zKX7)P9YV*HlAfE-9aM;xm|A36-VTzNLR8@VOKC>0Yb_dRDk$1PcInA#lfA98XJrslm%q+v>UH!wLAKcOF)J5|wQFZs z>ptEUjpX%J_Y>~K1T}A!=qV5^r1{bkjw@sL&LOR}_>;pOL&&ackb@YBSL1?SD5}I^ zd~od;tXIkzb})Y_zP?#FJM1ZL0aYGnk_if(1TcnfEnq?FCtns4X7MHZ9w$cWq^&?H z3{ff%k8KlWVsQ7`%ME_0483o}4|i%U0;Zz=CxNx_6`S&G;;&SvM;vHNM^L;hqOBL3 z>yKRfK1}z$Qb^|4Vw^0Li@pY%+~@avQAC&X$wnA_!0;Z|Oh3>yHYW-9j%dcB3_@V7jD9osQFudGuj6Z;T?HnRgC zHc9!mQH^fM{7Fc!^GP=w-f3@&s*O4xkB}eH#>U@}9zi0spgA8ewoR9!Phz3ZoVVQU zu@=&?yt3T#eN8;^+YiqW;VsO01S|Tee5u(3?c?u}L7p-*mE5e2s(mmGs%%_rjCLQn zoil>LTz}hNY?4H2y5ZNF=d~Q2$$A)59C99f@Y+FBNqZ*vx^2K%+S0G2^4@cb@ zz`xW|s|bjH)KXbiaezlj2}g!Ar!-0Zif<6{>M#|R>r(zL`!xPFnlcFn) z)Q>BY(xYlzbW0ejps0`YWm&bnA@?o0(z&tL4%B^eJPT~}u4lsC2+$)X8DRRczEpY| z4ik@o9&<4g(k=_9dd>puLng?o>gb~Gmk9z!nFWPPkp9Lr_k@#i()e?|Ez|(}dO;VE zLu2NTWXEs@x8m@x4EPXU?eCwth5Tp!+vg`H;rA+AH6E`N7mKG_6}p?&QJ+sFAkj%% zh_~9}{w9qOm>h~>ldJ3lA|x=@z4@j?;>jlJm2=cj?ZON!pgtvARXia*ik8)7;PJ0Y z2g}Sf82Mp$DT-0} z)fh4AYzF^cWYFOG)jf^P9P9K2J}7GenkuslJlZDvM_8XhaDES063r>jFTuiBqsct9 z<6af1m}r`@D#&6L!*4_`lQ%Yk z=gP?#u4QnAKX_tQW6lgtu=Tb{Rdw+=oE;7-z=ODuLGE$z`KE1Kmstj6XjHJcgd;wB zX?xq@fuWtXW{*g8T^N%q?~?}B#$ zg=P*nuO@hqv;=pPd1TaVZT_Q=jhQ0U^P$Dcc(|%5y72PF^DtYi8F^#()w15yqK6c; zU(#`inoH;dso-Oms{04RbVvq174W6UQe;wSyowhMChw_@D7**xzQz~>tPxgis2RB1 zIBkyiCrfQ3jH(RP+Mf?k(EI6#3-N^3xH#Es27Fduf?wa6Fw=2~ z*Zius!mrWk&=SDMOv3FN&a*(C)E_ofL@aSdSXhTo!h0IX6fvPfR50OYr=e{>&XO;M za8US}p1YO#!67Ihlu-|V#%)`rXpRyJxoJ4aOEa_1o2eHFq1KuDufUc-L3RYh!Oc!6PFswsCcaaF^T z+zY+otZ;8Ee-yENaiL7UDWAPKy+aJBhDqarD}4C~*c$FdJ1#=;AD!Zw))fTsM{l`;$%xZTg`V^v;ya-A&ypZ-V*1T9pP4S!X6bQnCz#m zGGk|x20xK)=*N_<`_~b;nzXByA^r1zrWGdB#RFH7r>$^*#zB1N4;+hKCl)GY+TXbY zQf$s=z^9keVm{!>^_X`eLw-Fj^YhUoLwfC(8f7Xy|MEB^(}qDj?)YJFL*5w2aqw%n z3MQ)_6~a9PHsRIdqTE`Cly&nZ(CehgXtnmsth$I7 zSZ=suY|s-|_DeANN`^BO1rSJHC$~ZMFxk z2tRe(JbXY3;?W&Q`Pmc7O+u1J3BhY99eKt+uqUkzLqq^562bQ{@^zj#xOwA<6Z-ls z5dHq<5-{m^w)31K>V#vE?UXr8L?b$SQdvWRKG1OS(d#+KRbwL|Eao*XK?sl*u%ul% z;w(G!&`tTZ6#qL-dCQNQzFfWOO}w%}_y+JF5g_@ZqucG-a*4Q85_cBMkmw5ZIuHJi zX{@j|DMHz5>y~?)#TN2@G12iH?b-@IWJ!V# zmW&&G)V2V=6x^D9b07=5Mjw|>-ERc6btMEYt4_Z=L{ykk5OaJ`p`!|&6x>yc$@7lt zDV-%uRgo^TU^oibX4)>SN2T(y4()-F$Z{-!g z;AV8FZ<9WCrq&&{%QNv#ZTJ_=JZQ*!zq{)rLu(GEA$Z-r@ptIUfK$}y_#$9}zCe)# zqH};iT7r^f;y1opU2Z%y(lCKYAyugh%gd((#3_dyV;XwyB>ILASEf*TG{rQKISN$q zHLX*{5n`d&$crnVZpp%yM+$yX;_p%&-_o!smel-$?y#Z)kTDNStC??wGG z+CfpC`35%Z!ZY6L5ZD}$x#xZ|inCL5j%%N_B4Yl2N2yV*TspId*8ajC{+`Q;*UbF4 zSYLIQxW5nQN26AVU~s8opKvVbIpbQwR5^*u)1NX9qo1)uC%z6sMUK+K>evy8sQ$eF zX#D9YIb1AM5iJ~59^)$~FBZ>R{-Iaej=;x#lo_Q+7>+6ZK|{rj5(fm;1ITAfo=|B; zjO{Utl8_5wLX4n+#B|i^pxuh3}<`~^U9`5|dVW}~a)&Zi? z-ui*S+If9mmP)7Q(O#qqTXR`aiF+dy^lyzZ88Gst-`BWkQ!`T;%(U_eCnZC2Ti*?` zO<2cabBnYhmZ(3Ag>`b_T7QS@S&yw#Y9j`!&*ag_l(h2=>d7c^R|>O9Unz7j&oseT zoDLaG(zv==YlUF$=thkxba?PL;qw~t082CDqriYF<*g$1Br``m)@h1 zoX;~Ye)0MuhYES;&vOA1aSy9c@uc%;c#{v8OX^N79JmXgElip7P4&lDTv1~$2nOon zcQ&!9-f~$5h9ROk*_a~gR>r;k)8RQwW+sst^q}l-FZuDh2uC_%bX#qbg>9(L3DcsR z3f2IP+R<|gy+RWDi91CdDrMrXlhPq!ukGGD)7IU}c%9BrlxopE1!w--lYzonz)5;R z;Y<2ct<4}}R@WYZb)>H$D13F5&zW{sahi7-DGa9oqeL~eh}89?5pAljb8?6-H{ zE57^@(3i_U1BwL+`YT)jdPvYXlIP4nQZMB_-qIs;!9>#$u22_LG5-)1OAq^uC;}*} zySB}>NyfqBK+jZWYjwo=0POuD8tg0Ka5bJ(uF`vI3+;jLk5*WYjz!^t`IlfL^Kd}ATO_RM^r0}%h~wUrx22}MAza*&~JDlhQ))ZkFx0PfrOlgQWLwt8B*Xy< zOa;D__-Pd@u^|M#YUrf#!9oR~#AhKxyjzPXW*CEK=x%(KiNfMM&JuwL*x1!d2aae1$JbBe}2KsM!sA2%Sj!+etJJO+%NEQ3Ke8Ur4z%_3Br%tlUzXm zGoLUy>{63m&%TOZkU?mNpn-})|yv|JL4w+V1-`_D##NCJib74R#7|PJ5-muVBx<;T;yclS-0YRS2zvCR1zaok5 z__0AzAh_Ob;4+Yd1`0y0;X&J5rfF;A1P9V?jb_~HVf}M1Oy-buj83F1wLr zt4%xHSlonaakVBQA0|(bhZ-aFem4%O<)`NEZzoYYaFC&oR6(S0p+utmtUReATgN0e zg<7Ugr1qnwGzB(V?F$aZ>wJe`Ib`aBbYaq+;Fy>qyuUOOKC!Y*l%QM;HKbnL=Xk0M z+Vj)9{vz}_rg=k>CJ3f-B-mCr&vE#3PlfHrCb6`$C-F6CMIfsMjTg$gfiWhjo$T2r zy?s0lbjV3b9z_rhQcx^5EG0Glc!|#?SS`+y2(zQzG}uf{BmOZ8dnfQ^zpwGAaN-LXG|HFZ;gsL zVT5apkGu<1eEY&Cjc0K;#d7=;xy)}fCWdytDBJCdNlY}x|Ar>D01QpnMLAJ5I1}yi z5AM2v*$d)o%Ylh?I+`JTD*7T8i+WWz6DXaOMJqh{f`9mcJ0g=Gg5@e=g9b$0y$NNx zI5CHlhq4`(#r9^Nj0%hSNeSvF)ZNzAGqYD{}7kRh;Q*kllP*U+kP$P)ZbI@R)yw$v0 z9|5HNOB&He<-sci*F}|{LMP^NV=RiziB_^6IczM$U&}5&DJ5pi79gYZFQ1tyz-eRT zf*}0C!`bTo1t&p#9VAiq4nYHr%?30!Iqv{wQ75go(F(Yd__e+DibF}IgF3C!Bp|_m zP$x@*93vVb{T=qd{HusKX7|5{lVd~wEl!RuQ^V`sjyIZ7@;oyF=C{w8NhR?hB?#Ys z!^H6T@im3=T}>$3ip&}vL_J^S#;&%Dm9Rca{;dav6mJ> z^@;SqlMK^PFtqizzfNyDya*6$EGbV0Mg+KjQ@x9AkJD&HKlmZ-w5#Z(S*atfiue!B zFyK7b`B2bDJL(O$RyI}O-=bmT5C1pOFijf)OoF|uhq2a|G8YtFoziypYET$Plg}Se z+85NgJR@PhxRi)!7>8CYSW}zJRXW3y7E1466JPo*kQ5t$rs!gW+}qS37X8Li2oExQ zBoI%}FbrZ}OfeBGe;tAK552QBYotSpD2f7&$xG?NAp?HnGe!yfB}~C@!c~>QKkb{U zA$LDiozOt>FEM80_0nlO! z3LUaEK}3ugZ$A$V=EmrDyVhYI4x*^+yqTK((br0Q`~SDvUi#6iAvZ_V+s;gwyj-MU z3vGB4o9OTO(C*CYwX-IK*}>siETsItej8Wt%Qy0?@2_Htdmt;Jo6IO99%I*}S0!|Y zP|(9kvZdpj*0|yq8$4dMhM8uvf?-KzIR+zK{!0CC(QW}u1+VlDkn&5*+CJz+IE=fY zt&cYmPFuy%X8NvJRf@LD)STv{iWjS8z1Hd*RL%&=d0!9)w#yey8kJ`Nh=6%&(2G$L zRF6?44AmRjSCTu550x4+Uv{BXeqBr|Us=wqmniIC4`-wfl`OgYpVmhJcN06$Q89lK2dKJLQ z0M80GG>)^wp*O&x%6L@nU^%}jNG0nY=1!mX=Y+03nEC1e(2tc)(na@HD z2}UU0$;~k6*F;F4K_{d}rX}$P>!n+WQtf^dGE_x1St{BzC8efrzf~dq;Rj~e3VJ^P z;?NbYC49IOgu)$5Mjg$As3aqW4~uOj0S!&_te{R$SdjP`t%TJCK#0kg*R!XVmJ?*V zr6ft4;tnJK{T%`gROdJZg_4p|s2?r3)rR4JDS5|!;QW`u-G9gj|C@e1!xH!3?Rx*oO z*?)G~Rh!T{z$$P482Bg`)&Ed3V}if{sF|=Z&k`~Jr@0UF;@{>zcQh%=NrlCDy>J5K zwhJ(kdgafbzUNLl*E6ADV#4>eB)3ax(edZ*H&HK79H(z5)i-mS5OXM2XfVRos`yV@1HAQZmi zyr!w7F+DNr-rX;J4Qxp=cpo#^^-txtk`D>Vf4Iqsc<`Law8wVYHebHF`u=B8(K6m>+695zcez zNl|6{@u733ua^Mx5T-bc=o}9ZciHGiOI*UYD{zmD#y&_XVm3igekuLErN=H4bT@{5 z8Zp$!c;Sm)h~y+a6h2xqkME@z#Y$nODiuavm>=z$8Nfc2x+0LT#JSHC{Z}$hg$06YSB(BZ@N`dasN$ARWWG2g? z;$Kf2s(Qd7R+wYSBa#R|e?oR9axp>XgVm5IC1OXst(mhkwkieQDmNES+F?>|izAf) zWbu0iM9dSB6@1iCF)1pu*}c1HDGV>Ru8vk0vX417s6S4Vlv*gLf%d*+-Ky}7SKi4U zVFI={VX^KA@h|Lbj;-x)CaK_aN=~R~|~JDAg;E z5^9q6Q!{9pi@3-ZaqwXTVnak(B74-(1B*7I9h?(2EE-Y+^8=T1>2_u(yJnjpNXG?8 zx*_0s{w+Q`2@OB=OL3MoQ88$EE^_OQBvDd21#)I<`)bz(%Z*6cYPA^A$pr!Zp8&a% z8A^OHJMPx=HZbItE~5Wv;M^@OuHt;f6zvW_Y&&MS}diN`YeO%YN^{zK81Gk;X+N{>?NjclfUC%@*3xL(&x zY-D^6uUU&CiT6V}C%9QI0D*;%uMR7qxY}O)_>Q!&0+?7?n3yjV8RG!z@c5VWNy3bg z>T)ZeL|X#4@;~sh0L~py<<Al zmMY{_mlH({oI|N{kjamnWyo(P4vSGUVZ>D!M4B-_qG@j9!IsiLx4s05V1u*Q@{~Ei zC??^DE#S*3R=%KQUSIWPC1x7mVi6N8cYc=Icz`$ogRNg z1z90+0xCi)iMT(B5*`KP?CRa#N~6n+`w%}|DyQ3_S%8+=@Sl6tzy$a6l*ec?5iU%0 z#qB*6Y+UM@OOjw&dh@*-Sprv9;{*W_5wWh-$jA|)lX*gsX6eJMD2Q3%~MWBq9PtJL_bV^-KcnSR^UuQ2Na5pzOX6RIpd zSWSszeXwy)@(evxQ9?g9^WFEB^3gy5qM7!+> z%cyglAl;+~uqg(D-fR)f%iTNYsOFLg{$hZ}DDDRjpCV&}$-G;{e|DI~%kC-9sGpvh zz{E%)zTRotcxkPza&th~NA(>}<%AE%>9gyV+L?i7qWiCzpo-eHjecvPuIK9SRN804 zy$b8sKoCOla&0%dJ6;%X`U@rZ|BaIQCA0I;z4`_wcs3d9uYz*Jiof!=zfxs5QUwxW zgq~>`6m^(bi2;fEHhjFJepMwHf7NDzoZu{a^uBgz!GHM>>?*RW_)H?y#7Ln5=IgPD5W1A`~1MBg7M$@Lu;;kL_)(M*UTJ%hcA1*pU6W4!b8|wKQ_91O`)} zQ9cF*Zt_0ln7ISjAN@fiT9UlKF0oL0By zLNjf7fOVUd{}F#Egzw^OexE~8!(`s;EwopJiTJPi3qlFzUUPviHLW6QDFydBug$OP z0QSzJL`O3QJ$eiO=N$s3YDvuPxxxDqp3{i$2d?O`@+OQA=opP9vG#~*>IJX@hQ@y! zHN?)(#J~cNciE0Ra3hKu%8miZMz)jU85ANl5Bb|Wup;@N#D==FM1s@ZJROKneRjHA zZa(4p#*^8|LYTWbnu9$rAm!NF{J<*)^(B`Uj+JO(3OLKhfCsvK036|I1r67;PS;=H zowh$=xyCZ|4cli!7YJl3pX1RKX^>LO_Vl^WKWNMHOEoV#L`y#@dmJe88!5mM;Zv$K zIOsrE>;Bx@a)uE?8C#YX0x{wlP@qGP;+q6xHhz%f%{cG z3NJATnbmPx3lf)*@Lhe>4|kKpQcFI3?rE;E^hXUDUxV;9xo?6L4~}(m0Rtwf)=vlAeVn;UCVJ!or`5WYc^9<%~HoG!zQ@2+`$l(c~YWhyOWO{y(Ot|9}4( zzAyyDBmH$EI+5;IwNE*b!yLBp!^S?TJYHYLy#w2bUU`s71fFPxh4bT;$bb)FFbT+G zs>w)g+4@q@j>xF5kOHvj8#tSeq*wdaB-G)MA@Wz#Kmt{0FFVqW%}Sj;I$7w!n>aw9 z%#^ZHSkUGHv{YsH@}Y(vErqw(rpc?InZ_3u_w6>_Pd*4JB*MtadB>ApyJVt7Uug1W z4OJMqH6J$3Mn4v}k#n!yixc9?VA&7bMou378bZ+hspTi)C&8!yX^^eVqyZo7| zh{v|*Q@pFo$$~3c1rC@X>5(9L76js=Ka{mdUmQtm0=PQW_EJ>roJOl;(C1uF@dYYYAG{I(b?)L)g<*R8lJWR5l6l0hAzKH?JkU<&3DErdBvV2B!;e~Ro;$hN1uXrR91V_%wf3}+6>%nb&N<7jrs7RB#7@8@q{*THSaQ(5#iK8PKyJCI_NkhZ}4IkdWY6H|C8TTd8aYP_Oe3TVru0RegInMyu{Wzj0{{6=N?ve?**WYaV@^nGNZ*EAw-_`xk z!riWAqN)zm`ANufF7mv|F$T9ZTt!gvVSa7rwGybp^|lxvRuOTNp!GxaFmje=a;uy8 z$0oT7g)z!BYXkgRhy=hXRRLB`bk%!VT|hcs{U^%(ET7ndQ@B?*cW6|4DQ~8uV6gb@ zAk?C@5Xa6oEKgc7ovGmPmQw&!3M*ltjYAN1%b5QIHwE1Vp?7cAMzh3!iaMzWCnT)OiF=?`6s=^4*tNy{z8X=$1U%$MQ)vXmbo zl;(ut0s}PWMDtk*^vB=dEG%GVk^D0aQB*t3I?X@go0iZt-{urkcg;6w&37>oH(WLQ zO7^K9?FNRZS!~|@Ee4x7(I%iSUKliR7y79NP%kCejF$-_7F(^SkJ4jUX7Z4~5ue`k zyScj?{fdC+yallPGJw*h9PhrddOZ!6F$kL>Jt9pUdOL(bc8)<@#?7-{^nFWa!^WDkT%kwnY&yNO`T=^ipzJZ;DxoRKG!8 z21?2NDUyl~{M?5&QiX4HGk?5S@$%N4Qjdieqb9U}uYr2=NQpSDcD-DRXti5$gAp?S zlmLm`(!7ye&?9Vh6Rwhpx=)@^R|~7nQQe!sw$AxL)2bn~PrUVH?q<98fg@I=rEacB zgB*i6wP54Cks*!Q6y4?56Qp?xEi%565L`CiZNNiU;BxZ=Gy??2j~p04isLMg9Q0si zXGZNiAEp#zOt160EZyoAv^~r(RkbMy50zp$xS1 z+0;5GFbNB3BdJ&Ka6cUcpVW-EvX&)Se#vyg9dRN6=}&}at?BHvVt&p*Y?^lT4o(g- zoz;TnG`b;Cj>h)252f1oTQX->lqH@dfS>I~EO8|yjSSqF&)1hsE5i0^l^mP1Y8a@rwairq$r({?V<&_uQBnBEkki;)A$WOH4J3`P+qHc0UKt3R@H#R# z!gSgZik=tB;#)jaSAj_?zw zGXbkM?PRPF-?#G!qVK5Q`PR78d-f&iq>u?n5SM}CC#p#5B5d{;WLx*2DCvISM}P8x z)U!T?GoB+@?g6li&1{igt$ZA>Vfi$4i^w}n(%ul({`{=d_KJj2xVaKQQDDsV8F8DX zXX1&lgO3Xlztpty?7-+w88hmwliK6#)sIN^X;7iR9*ot%M3g(im)DPz`(f*ja)JL# z4^?V%fruLp4+R_4PzkOJv$L|d*J#32p^U!n7Qcgd)^p-jkjHS=J0YE!=xoJ{(reO* z+qLhh2&RL=STf^P4g}!m9KHm)LU$Jf;AbPsg_9NUC<8YM!|Q=-$Q=-qs7-41_8?7d z2wE3$U|L0JdsG=UpYW@)#K@B-v>kD9@EpnszhWyu$LacVv=E)U9b(h+D;Wu?)YRm! z2t3;$i1!%)S|ss!|H)aPfq3uQvGammSWV_E6GCckY(%9)q`zNBKfv>FkBWwp>}ctubTKRw(szXs z-6OR*L@{r2Cqo|Zs4RLd@_9RpBE{bLHuVg{jsv`71O_w477!toX1Q*O9x6Cqm|ur7 z5-%}5Ux}rAxh#SJw(M^+_Jhq{MN4Lnk}r0sP`n5E<)szGiL$W6Q(~AM+ENc;)-glz z`U9fHe{4p-1Mey-m+MVq*Ib~RNeb)o_yRaH&lSXp*eQuPP}RhD#kp&#FP(|uX^Xj^ zFX+`YzYGKuM*l8INJD64q`#bvm@`kU*j9v2wBMWB81`N@*eUiZSjU35OiguoBI=$Z z{WWZlpj8DM|G5G$0rLN0>@9=h?7}tc;O_3wxCD0%?oM!bg1bX-clY2D9D=*M6WpzF zcbk6SbLPycnW^uaDtNGTke4yWq zC4FQhJ-f3vyt#!%AnxioJ+GE0n?(Yey1BxTY*Risjur7lF9d9*$L4haO*d<)pN*rE z;C6k`iuJ{q&;{G)P1#GD6h7@UZnci?77r6u%CrJJaoZTb;3amC`^SVVoJCd{ztV*B zNV)szR3Z(WhQu7-#rr3JQ|J-4zH$HhH;|YQ_^mZuVRjm38OV=6t^iF&dCOC>q|C(I z_k>ZK&w8x}elM%+0t}716GK*=hdcl~=J9S6L5b1Vt?EN)^ ziDOnETJ7tN+M0SV%*>{w;sl{LlU}5g14mtFV(4xIt2|-rsGTIUbd-J5H_{p6x9<@% zs|eK3t3I+8BbZI7`Bns8W3N@;6O|rXeS4wk(V2dCXdOL-Vf6)*-qEfHQ!}3U-RL_? zadM{=>6rM_arv%Bc?@6AfjI+Qx%onh^F5Mi*N}&$h_e7)-!u%t4!;+k0(3Fy?X$~5 zLL{=VRkkx4^B}l{9?EZ@5)Jd&(YXS_G&-S19HKwZCBK1XRr6-kN0Aty_KF};@c3%` zoFcuY)I0am8Z06G^9ppLdC}fds7YXe#s`e_kyn4X36%XHMr|t+3>8ET>Gx)R9iDIn zBbp``X7OUp~yw^=(M#M@h7ZA4+dFchXPlA|_T`obG z!Qx+My;@DjO8IG?0bopr?4g+nflAJ>v68IcB~*2jBan}U2~U0mQbif0WiK82_AC6r z6ubHLqghYM<4jcf4r;Az6Q-1{DU@Eid>2q~`kXoQ-9^l*I>sSu)+ z*t~P(8>E2QGV;YvqPbKZx-7BB>O~YL7XVS5rOQL=z9=dxmK2GscNb<<9L{ffZYx^N z0Y*1r!oEU8lt*KW`HFo=6eIIQ*$9YzbD64nE37-_d>}4qmVJ9|1!9dy+tex6{R9j> zk_o6Vyh=%m64BWDNr_uP>z82=$v>CeN=fSZ2$B~?KkF)krX=3M)vG!~aa)-YoOiF- zUOxd&%^cCAzzN0bL}!xNZ%ClK_1K*tl2(GhLx;FE9^euS%mEuaxah_kGtw^bLaq56 z5gjYs1}kA|RvJc%UNrY5FQj@jU${Kz+Y+6%+kHg>zKy7*zNBN&lr!-AteJ(SCS8)p zC@_<9TGnD6}>;)3%C_xFPk%+Hw94`)6n zGj}5hx)q|7Cja)M$3V0GkU=oba`6u(k;bb^%paT0v`ER-!qz(%nBgB-`f~;aKf)2n zd2j50UI8Basz1JEhks8^5h>Co3B@mhnY)zhn9DWUY2L%t$_vgvz|4l9Boo&UHH9Q& z0<`7Uq-K|bI6_+GUj( zPK0NqYMTc7Y<*J|kZJ#+=v8>nycibU2&D^Ye=bwKfp3=wPfDXibX4HL^rA&J`~!@! zD@N3Oj{50L=O^g(n2cdD6#7yLFMVlKXbJdzwpP#xF<{nH8qfacvkX|jh@D*_>Oi04 zA~=Vh&|k=FQzUrb9*cO$5c51Fcb&<-o&x{ijT{ zCkcx(IhlR^&3PJO%xKMMoT2d$R8%Ee0!<_SaUHVdAOXKlGBEr+>$2Qv zL^}J(4u(4AG`@ek#x;KAgPvFocr|dw8W3N)1(|~(P@3b!$wKxpv&R7gOlP?y9hWYZdfVwt~UrYpFe+s|p=*Nk!kl zx^l9>=;=DYuJ*ZYLo#GpgjD?D>$Mux@)>#YA3@-Yg{zXvFqv!VCDq_ppz@zq9GDkn ztSy&$$hsfSY!H^3L9EWdSfe0d3QB zUu!C+s|T%f(#3JU<3*i0prXpZ&`d1y=RO>MQ#`s{a0 ztKp&}_5s=16J%qekNGzV)gWCG(QF?@$C1HMKiR3uPyB48$ie2Yc9sT+l)s0#Ef4&g zly5zHNRHDQ8ZhC&WI7>OPy3}`0%3Bg(#%vj~}4zg)4R-vo4%_B1;!va{v2%RuE}e>niE$tcPwQn;Q&+ zYI-m;X9>0B`cxLgJxetp_4eocm1^+-t*@DbUkDlJSufRZgv zh@B3fZ)xn}ylPGGxK*EO7yrs%=iUUXbe|sYJl>a4S}4@ zR8PGmf*I+zJ8O_MfS`%3!>W(>wqLr;(nj0bwY&ObRpss$?IUv`^+6)BD&fJJY{DyU zk8QO-T@|9x?6(=VsAvv5ckl>2Ptfz<l!PV#|zYSrwNvwB`H`aMDHTiJ1G5g zdRdob&lH?nQzqvpF{y5$RQ=t8=O3eqm~H)vo?*XO@diH$X79xm`!m4m# z$yI163dqSn?~U16W>s8hf*ra4>haCyk9mDQ<{h|m(JRj0BJ=y?kQxgnpS$d8w#VQE3En2wsOrV55xT4^}Nhx$-O)TpF> zub%v`R=^*8<9PMQ-*#}$@Rq@x5!YzC`ex74n9zt0q9`I!Ar(D#__g~qGk_g>ktMtl zvFNf;95g!O+Bh=R(6&Gj3^X?Y$SipXN2x!kp96f01h$Rcb(2(yl~xjeb_}F(w_DS5 z)@TQEY#v?7Y%b>n=0$#HuZ6~(rW#$J=(W6tXq{`WmI;X%4-mb)uwi@c={MRqsqy){ z67LdUguIr>FQ2(Wb~$>6`}?5gW^ozKn==u5Vv1IL;Ye{p<7@KR@gV)PT~eUYs-o!j zwXZa`Pe~Cm*NtTBlCM8o6{<6q)h-mVuQINsZJa2pDV{xo^1ZjulAnJ+WHPI1yM~Wt z8%u0^85mmhO+&cU>a^DE(f7@?E#_oC8}YT@&Ll4lhkvQ6Csb5XSO^}~d}nV_k0PhZ zaA`v`@kdCwpVUoS(R^z61r0;gl;Q_WX|ru_+W~#uL62((?0Z1VfZG0zIE~D6_-h!5 z<=LQS>fagEtv(SlKBNjOgArek8Q}e@C#|I&ZY$^r?|fS^mQh9u*4zAGeEadZP1V_> zyyThQY6(NkLUk>38!8BhDI^DH%pvA|c+)_20X$abW{#7IoIA z=9Sv@(3?m4EZ4N(2I^)lrTTP==h-XQ>IojDds8B(3dO|MSAsa4Ee!J?1x6~8jB_Yh zM1)0{?anu%-!EIGyc{vBZ_SNoV{{KeLCLzMj_l9AFc+e1PW*?Z&5P{w}H_ zEt{aWy&M+pyPdz)=dkI$&BiqT>`2z(kRHb-FXbr?pUf zneMAU=PHgGOU1z#FSQ~51nhULfWJN5)4rubmm$ZQ|$%g?qacRFbx!;Dvuj z!H^2X-tK=%-Bu&|X_9RAWxkBy4^dR>c=PVS^G5pLNZqZmAT4-3Z+}5Ui}1LYSh2GF;6KdhVI$YOo>^k4K%u7xj;@BGC^5hCdYk zOFsleA}8w(y0T+l2odDq3}1pgYifTM)jbE7j-X+a9jt)QX=)kH1#z1?-2x@VR5Opd z-9@R{2nf-#hW38iA~ovYt7qG_GO@G^!eFa{rxVjyRpPL#r-R^X8$H45ZcnEO2`7~r zn)9i_8;#@=leYtVp9bu?XIXMO{0oknu+2o&j(dlK++5qgyijl|^<~B0hxD?wUijqX zytZNY)Jj*~yS^wtc3x4B@+l-KJ7`JMfwIB$h3q1}J=!96dzoJ{Am(R3{=^U$CR)O~ zrcpss++#(@OL<`z{~L%>zohrLzZa++MQqXI_8?0bl=e zBa9pK_<=Px5teH)(4zcCHu)A>=Zw$ftl&h2^Ln4gIZ9v>sm zUJo)TP?)3d@_vUya02}`jGD);n5FJ=BF;`RcI{nkNR3~lxu|}nY#2PLNb%~_{GF+8 zEFqFK$~`inNEuP!crIFehrjad#%Po0menDEZT$@3v%M-4agj;*cpI?bX6}cVDC&44 z5(fbo&q*m0i)%pNY4p~#yC#qco&(^mi_j$to8 zKxFtxrFC41s!uV3K0Lae(I^nAMecc&Ii{_=AM5Z%gd#T|am#C)@Q)@QPjzRv7uaTv zodUWqAa_O(3sAI$AG*a&RF~s8Ko7qa%0iGnloqTx`&&0cHNWJlTsYl{XbPDRRd_2i ztcK5z+Fx>D&yfl)192?2HKYTG8DfH9wQmIiP#|npkwP^wn#+I}vrLL_zf4P7oQgN5 zL4U{1Q~V84SRFQ?P@GI;kKj2=EAo`u1fpcmnR&zftK({OMcY1N(Q$}AchoW_OTR@- z`jOPvE@GT5IcI0a20HP@zD5srGw)#9NEbVHNScL)I)x(Y7QRKborNuTN&Q?F)f*Ln z`Po#Zk;+A>#K;T2-m8+`i}IoY6&VX%;|G#E3;9KkJGY=knp8a#MPLAHl~KD}V( z-{`Rb2rm|J1;w2>rF@qJP41-Uvz2MaESPTtEILl>AN5YdvPjQG$9`|=7(n}3t;1!R z)nJcRCb`MG%&B8VacdY}x^U!xM+ix1HHgwlADbLD@T{#7okXR-`(H7|N@;u$&2C2FL(Z~VuCu`36;v=^JU{gY&)B-q(9d2+6&7VmL?5yaCYSTR3Q|&=0`k3VDEvk ztNZqAHt>}BWBsT1Q_J__Dw>gePvzJ|i#w`NB+9R^yN{lw4sk5s+uVnszDjG#ohj~= z>b8R-rK>J$Dd*Ox+j+t5LomgO%OCIxVduY2BP3?Yx&>APREtR%S*M&^nMw-n{sgp8 zT|dnZ3A2lyg<87v3I|>CyN1ZE*HW9w(BTdqjmpyV3OV92woup!!ea5vCHz|dZLq?Y z6X;HVOk6v8eOc6N2{-?@q4qnO@5A=Y*Sf6g!-Uw(wgPKEmLZEF2>WqDUby5z7LG`u z8-`izR3&=7ZGarOpe zqBD!}^#d_eu&CE{b;jk91e29blki4qnouK;fU84Vx41h3ic)8|&>sYB(M@TBr1Zk8(i z%H2fNokNSNK%Rm={PZ_5t^6w#N{xkuveUB~MzOI)p(~w~YRv{C#KU!2(Vga;r%oAx zXiZ*hHoKA$j)e*_$*H7HwE|JC&e*W?f^Sx4N%6N%#P1G&F4+C8ykx{IZrG%y$vOu) zDM2wH22DZ<`!pqa$5$f5RVO6D88cRmR-l|86;@8|q%8=3Ba;=}Zq4kw!)xQR6S{N@p3GJyF3D&wqom>@7CxxMpY(bOr;v|Uj;T8GnYS0Ci=3k6!tQZTk3qD# zWD7K0#U~K_An{q9fhQ!_Ia8G*9e5IiiKIY1NrzMb#zY%rT26#K-Cs?N{Wsit+>z^zu+^0qzLvJ)wPyO zVBenY9u~Z7XlFR<)FH18(!IR2^dAvxZqP};Z&8fbVHFstzB-_AGKy{W)Ad2)NU&Ed zu{WFZbTFoRn_A(HioAhWb(=cPfB(l|$C$J>=A$Xo462|RW@vAxEZ;#!`X_!=W_)eN zU0(pr^%g<_%FOggn+=L+fK+&;yZ5$I(%oR#X0bsy4ZJ&bXG#UG6MYW*rj^vh=xqF< zRm%^1F-S`~A1QvwbwitTnTwTGq&#>?RQLkNp3Jw4dLknz0BpmiQJko}Q)hn5_yp5Y zr(PWKd&e~^FV+gw!f%AZ5zokoKhl)iufp09eH+s0|7M=SGTk!MF>5pAtVjpZ>}wjY z@yuwwsP5Sz6C;z@)K*Z+iCmN?%{Lajk*EQbJkNr2WfiCwAyfN4v5VlkJ_KPCMT%D|&0iW& z{7U9E(;d*8_B}3T%f|@RTwTSF-T>uz9mMC{i_AbdLN;D3(nCuU_A`ITJNGHiUd^r8 z!bW5 zjQZ4Y6uQ1rEjEg*vbQ`a_Dhf7gf7#<6(%LX4CL3o<&)*HZ^S*?a@mY-EfM=g z`X&7I%HI|GEoCx&{KfvTI1W7-@IE*Xq;iO-3Wm-27{3}mNgF|rh`;^8qwN$uYinJm z$uIpOM)E6n+NJlQ7Cbyy%cFT1j6<3j*^CZU*NUEbyfiIAyhd$ZLcWK|{j!lwPLelW zHMpBI{i|ZxItY4}Oqurgu)h(zT@^4&U60!6HlKXCX#j8Dtt)r|Jnzojp5Y`EKk<}{ zBxa*mi$b}@!`%tFvaI|I0*p<^J&{#jjo}{wt1r^V?rzTn2CSm8J2km+&A-o?cYXLV zBv@Zs1+hEzw%9U6^9O$OtCj&r{oW{ZNtRH%jBD^CZ@RX33#yqZJ6ku$6?cS=op`7x zdfH_#a1~zHlg56u!{PwKnc)&0thL#^4DPAAP4-i}cWhOOuyZ8)-<1KyUo=I7<4o2O zgK)CNXgKzjvJOF>W5OUWHEj*s(A@cl?a0!vqXs68gq>-yF`)iHNj{!yhZn}1pcBH! zLzA#;)D-Ud2W&*qoKqeX*6Wz+5p$N6D8YoFq68(B(3QihCOhD@;;jp|RG$(+3xw3= zRkgp;G#nYShLwE@B(MuIQkW`V@yDG0%QM==Xn@C=5j3

KL-}4_~Xui+ceAJj#q8c}<+P%JKbR=*r}~_W{ZHZQxCFVtenp>1QAWSWgLvRvo?OJ3A~9Y02ga)UJId96nOAH%(A(>X%r5$qk*>Q18!mspY21*|~Z24&G!^r^fKx z2Jw(y_I@;g5jY4i;Gt=x^`^=^W3 zUZSH)pGbA{%CkIIJUIvSk)$z)yhQ(;$1RMIQmUyyNVGH3X8U2_%Kq$2(e!qXly!m) zD?m*XA5{F=Q3>wI6a}J! zL@qy_p(Dkdu;b*DazG2QdCn2boBOa@^7-PUd8~7b4Vs}v6eLp1GHyXhU2jDol?svu zfX?tFfvDTg7&x&W#xI6AkW!`FGGW?Vo_{RI2yDe9IVek(q;iWOD~IneCUoRhe}!mt zho^-+m2o?K|4yOucaPj8zQh?krMlWOm@!KzzNo^O&FolG#ZHNsOhP14(>Qx>wA++InV9NUxQTX z8jzPJuHPR^aPd0V=XJvHANhmADh5?9MQ0Lf^_5pf`2_$r-i_Bgom5*hk6;lst(b(i z0#QQ_tI86j^c*feT(+lh-9S$?`f7oEqLC00OS*!x`5T#(TPK9O7WWJI8^2W?Z|Brl z?j^7 zPyestaG%?iM=BG!yhI3pJ@=M7l^l>vUw(#&CjcnkoUwCdElf`Cpfrzs5g$cbDNA2I z#&@U%`UAeRu{icY%H_60^VNhz2mz|UjDaqO{{yWB_Wuw$|2I+I|8MhIqBUab^VR|pj6_K(sX&NpDY9&hftzE0-Dx?)1y^+~ zD+yG4Yp@4s6KDjy|3Ne_Wre?+u9_z?0tgb5Bw?{6msHDx!NYOhJLxS>PlX2OW5F#;j}9DDIyi-6SF zafdTA3Xz%?lSEhF1y=j;3sru{bLZ-1&6vDEe+7o&9&^{()lsaY+?Sn+wggKHqtI1( zZ>Y`lL()6#vl{$lo;LsY4&Jy&^*TVLq%a2B$1pgd>SSN!=R6ZdIl3Rc+FlA-`o$ zDizz)iic5=*r#z)TCEeL&6jNz%_8!_hT#(~;JXn=dp|HK2nOonCvdOsNl-OJm3+x- zk{@`e1?XzJwEHc zrno8r)4s9g*o5qQgi@J)a4WEy4VYb6)?iGM$hiv4VbU35rC&(?vQx(>lIY4?xFwtl zW|;~<+z+%C`HPY5l6&egwxiUh^OggyJ8%r9)nlPG{G4L5w4@g-4$Viw8G-PN70TV8<)rw+; z^EGDiI1bROK@WV8NUe{DAdYzeRpZ}$JRyoKPI zqeGTY*IC?qd3aRz&keE}+R|~&p&jg;=5$`IH-gWH@*3_oeJPsp9FA0YCKa1oq)m5W zfzE4ohc1<2BK)e%;{l4zakDr*`+Nr}5c9eqnC8-*J)}JxJuo;u+e`+FcGA1{peVw| zpoICS_|(W#ny|fUx}tDPylEN6U=%4t{N%nUw95D9v3-PYCA8u$v~uv?WyS1~IH%uG zifk_NEuXf+(U%~F^bgp=qT-Npm_?CF4c-d;uG{Q~I89|7LbRS|jde+mP@uZ_(89_- z5q0D$L{;YEuUqv+d9ZQo9e|=nOQjDiV(fNy9Oe?1a?Wkzof4=?qA2%S$hZ0~2)?Fo z5iu|Mzf+EB-qVQ2#KQ=-WA^0wE0kSY1aVc9*gFIi=&P1^J}?XwKDu6aG+&-GS!YK( zUa2dbDolVIi0GZo+=qv;oz!tAYXvJ;KB}RY>NKErgh~UgV}W@zaaf_*bdqzfNx~jg zhtIbVMekY9PA^P1pIKp-F^=xBP(N{t6Y?UT^`D#+4PVo`$)qJodQu`x99cP&F0jVL zB*ox!5Gva|w=o2W`a~x(gp}J;AruDV8OHr#mM%8xjyt)JJ+|C--JSI6fUxlnX7His zA0jBFP<4{C^F_SSc`@XYnzOVx9$SuvjR?68;;2;F!=$Rn+EplIlVOl#tUh{%Tqg|1 z<@oAXV5iy%3B%}#mwkv&ZOcXrE1GRLSU#Fz>e(flfDA?&YLDyYx?kiRw!Hz;VOHF4 zyg7CbW%b{au>%W(eg~;qa5rsw#*rB089LhoRFIB#JeyzxgXz;*ZMcA5U&9AybE(P% zpBQ!_Psac9EnNV+jyqdKZo7<*E{j-b6hW7`WN&l)jV!FcmIBf1ekfo|ZpLd>B;f+aQCqwoqCPKvnoDN^NeeEC%rKW_ z<#Rs->UR7noS-tUa%R6|w;?Y-F+)G^H-BbJl>I$o-<9s9eK~{5(to`Un(Fx%?p%MU zqXGIbqLQap4xKFit~EV$aIs!TBM^-AM#vNkdmKbi-)|XA{=!;KE3MoDvzoByTGIV1 zjy^K>i`GsWb4?7ITzmVTo*kN?_sXxO50c#*ym|=P%QQhZRi(kK`3nYvV}nOr^y%xkcR=?VdZxc zL}85947p9iZcyJDG53|8Rg=H?UnW>e;Nv2f3Q7>a_a&F|L$-n10mpTP3OEKnr8>qJ&G!)h`Ns z27rudNp&A+D=OJ2F_$w326pVay4i3KXAG+A$vc=+QL>cj1!HM8)eV>|iAY3dH}3 zD~I89{%Iu-1g+dFg}}lro)#qdmxy+%DK+z?()t=tL@H#UneATRDF6i*@Gz+4elMEaGM6AJ~5K}7MUKdGrinC?IE^cPHt(eS7VhsTpR!kZApM_QQ%ZETgDP@&~C z#0z5YY=#tCVIj6)K?ohSS$3UORh~&JsW#nwWW;!Vw{cWar=bUC!~#O<;_B=R37Uwz z5t*!2*)4c~JloUE*7d?!dC-8AY91tLf>&Q`{( z>*z6ur&wz~w_qJ5ToP?%Nsfqz{;>%)2GPysnMJxd?^HG;-_^%69d~OKAMBXe(b@y@ z{ztb7lK_7LHA;kTu%^v_9`%}eP45AT0;UCzjk3T;p67;YW?WT;m>ApDiBb52VZ}3xrg!)!hmGTxe zGO69V0#)@V7HZ}n>syh>8n}^@=Tf;%Yk^82An1G0N|Do_4MMudCeT*kNGs*dlI6m? zYRu*f2qHyrq=h3W+CGla4+ai;-7+>!HwpPjJ_wsK7M)Qu%uf5OZhkyX(dkUW1wuD1Ucg_xIlCMZo)k~|X4t%DHwvTj zfCoLvUBp{sQR!JUvV%l{Xr9Ek1Zs@O(%4}R>HabW7tq9F?&Y-86lhc9n%$8+7w*nq z%J38;ORRZ|*y46&euhi4vaG*0bwL7%6Qd&Y-YI7<)rEI^+U4+8S?f@t!p zG+ht*;2Uy{81V)(S1bDqmwm3B3$`0vv8H^|}t*ac9ft-f?eN>tHhki>Q~anYwPpMy~QVO)Ee;QKkenns54*LQT^v!D*k=@@6Y9 zLK%MP`f(5lN57>|ab$FfZQu)ukK)xjh!!%zJM<(t(ghsz#c=e0F8Ay8K2O3mmxpqG zLU1;*pbK%4OWqnV0SZ8~BN?GFne~F}DM4G=cA#gTL?cTgzbppeBN(Y-Bti}(curr) zi}Bz0PudIEci%j%a`2y;h;#BCp_zlf*eRYAa?DZV${hck7Gb9X7}Y!}a6FCrXI3QOgBV5q9nMr&(BI#ezIqm{f%K zc*Z65YrpKlg>oFUX;XS>LIxW-vEdKs1ah9I(JP(HpQDegV?3b$i-^S}!z*X9uH5XP zW2Gf0c(!Gyg~+*JttGqyK1{>%!b@Rr^5gKNxeFfNQ;CM@Prg&tZwkZ;2eu8_fZPamf5;)1^Fyy$# z?Ys4q@^C|)*Gcd_M0V(Y$6KkqvP8MB+ugdI>58OnV{HHVm{C7~Q3Sa&u{*_FFxNhd zd-g$%)Y16G=0dS^RrVkNukC9~K%R@FYIx(%Nua&(Idzs67emW+gYHqfIBnXt;R>=_ z|Dn-dH97a$d7xiaCCmE+m-#*=Hj#p@x13%*RJ&Vc-xC_W16yi&_#5Q9&MMO4ajmmb z{|`WHNR%Y=*f_SU*w5r)>zP7qm_Ms)CQtiN>9!`w&c73uZ%7p$pOlY%T`@vcw+!Ra zw3k-+9A1C#HcItUGc7A^H7}k<<|DWn4?84of^71q+Z=?s^RaJwu6Np=&;fUnaZpeD zW)K+Y7hZZ{#=TQSxC%GF+U{)#{k;hEkq@_VU56rnlO){ju{3=MALt=Wa6iDq)pcEc zB)!;%6fcROeH#B4AwF(lg9V|6Jhv^R8n)HL-%sG9s3eGNC*i$5d5M&h|9FyZ-*gz>vU0EC+QLgrT>dq7Wb+hOKrp}wM2BO^? z0mCb|$w%ZtI+rJd1b6!m*v9Yt#7lvxn$ILZT@Z~I{#{bBukl!wWz*_Qn^tDLudib+ zg@V2z&w&QdujT{=E!684sqkqrfJmWH2orTUlm3XG2RO3-{3w4ITY>EL3B}Yo7M}^7n&Wd18iMz#C!i#we z>ng!Y|AnwuE7B_lj0{aP8C*3ayBdsOe4`kV{9%Krazn@C1|Y8A?cSX~$}6s+hfX%= z4hEs-lZ8AzI1H}OIY6b%NRYHV^;5V`A2`&+k;)#-mYZeU_Qc7OljLXdg^wn(OGd`Wx@nG-)%D}|L#C|#M z4gIeSOfrtx?Ejj9A$5i$n~@XY$bQ|YZXPTJwCft+?fy@PZGyrpCPG3Q1CRPm7MhVC zYgdO?aM*Nzyc(&We`?wd)GW`~W-%6s6o8;F;1v#<{Xxx}5*_fk)w-(Jsw>IEkU6h%ARAh_PtA+;`sE%NS);NYPOw8Kq z)x@}jcS6u?DdxN=E(L;erH;Lrh6BZ2o}{N89E24YesyJ1X4Nf1R&F$c?^RhBdXe+V z-Q7SnR2v+l9RS|?j9qHzx?ujuwcSo-!IsEt|L?+EMw|aH;jOAJLA0rz0#Iw>Pc@Wt zyEwPQJc?g4vdJP)zxH$s!M5ENyN0I(@;{8XVmiDtM%Mh;S?=v7Czl-8I#B_d4ph1i z;*If9-yT28K$;zs2uJGfC=H_-e8JtC=t3NBo7RuQ^;HXAfXrak?7a~KQj`aq9XD89 znRsrQ8E1!i@8B&dvNu!T6BpCKh0Jy%cJI-(9Um^vNFnH?<_T)P#9cn>HpZTMl>NP;E{RcE3lI8{bF?F2=9^gqZlnNd z=dI8W%&_D3p~i*VEyk2l!u3Rp3XSO>+X&m~bU-vG`jlhxHw6Oiy<)s^kQbbYie{P~ zF?C=O%8R%05`eq3-OQ#|J3FVyKi-*6G7~A+DEGIIvwN4(0s8!k>3Ba6)E7MEw{O^0 zwYAEj`7UlC*_nR?#i(GR0oV+A&X;x=>$uLn9OnKF$ z(!di9t(Af}kexqcE4b*ucu0c+2JAo71rsVPA+Q^!Ayld<-i65sZ@Af+%y|BK?NROS zqi)kUWXHx@qj2dF=6X$g^tbq~MnEb}j*Q4JRLpO8iciCr+!Bk2zs^&~(1`pdXywx1 zaH^G!sMiFxP?>wFuh5)-fKz?C$`dxXKW-BMuF(@k|2q_IYU}6gCeX+z4q+64^gOLA zs#vDzEI23h4$-|=C}mOgwW$omPo5*L86Jy5L&fQ*PFFkuSt+BN)4-H4osk+=7bOj9 zNJpwzzbE!7dAO8^^&agGK4-q8Gk#@YIadzV)iF;8D!SAY8`F?8pLY&GYtlUZu@im=iS+o<#{M%f0sf_1u8a7B#1g5EKM5>b) zMT?s7D!AdCsx=&i9`{~b9M>F7zef)UEs`gz5nH!{?{hSbAmF@bE~(MMp537gCROn} z5KGLQrs4_`FgqHL8>m*0uw-V6FDk(mo)AVSVT-<}T|qi5l>`Jl(4i%rvw>rORo@Zl z>|tr}ddmKCO}8)RMI)3ngpoIPQ zI}6Ar5k$EPT(MjWLil z3{XhKC{h&|1uqd$WJXxVXH22z)#^%@@?u=*I;5xQ;t>yT@5V;n`0VMscV?-5r8$Eg z3$EQph*dlfZu>K#)SQLTGyx210x_sgR*kMFHCsi}V@lahW|xYhckN1*DdmC}*4S8{ zRSH___q%#3y>?&K2_C+nGqHFEuUt!+%UE1QX_ZOp#i=6o6VnI~tXz*eg=oQ1iiJi0 zxQHt)?cx3p=W(J)A5SMTkG?Hzwd#0!R6S~kJ!{*a#=*vWdX^Gd9hdsLAiYb+<<|@; zknjBRL;I(19=fB21J;YaS*AX{!W5fa-C4~1LdDi|O6t5+F?xo z1Tq$EqND$_ng>jxPqBM^?(?yba+FD|unq*;=P@i5a%Rk}GS*`D5t*g5wIg0W=Xn0r zmAs*Z76m&?>9xgI+O?T2Z znw($qczVRs^}9ocli@=Od1}eW;=VWEDQ>*EM*Gvw#=V$x_3ctMuT7b@V1D9&4&0~4 z@HD+--yH){+l@G1E-v!Xm+35;r#4;e-igg|trs%8BgBW9eN$Ok7wOXgbAc4!Sdw8`_RKO`Q=@ z)iOe)CON)%5G6LL1B29AxFjal{?9;u(%td;j%1Rv_V%OK_6FayjTJpz^BvENqwMD( z+lh&s)-CVLiFHLZ;;$C`^sdY=ru8mPqw8yeSL>gFgo&*!N?`fq;hCW&od+_ovpSFu zWSz9FFPf30h!|(4ox&Ti37*uj`qeSg8LmCi5OMjeD6m(S*8V=ie^)AIA%kfsxv;`$ zgpg1~eReiOZNk25*mxD-nkIa^vZR0U7akj{K%)udEFQUYgbM6tpRI=i|q@*1vIR4sQ;!_4z8_mu1zzvUEm_CvuE7!Y(E(qCzMI?2X+ z7NGDPxn@Yv<6y((y!4m!YY9TCJ1c$Jq|q@N4A&c6e(|tme}@Iw=?!1xn;s?JS%jv+ z8{J^fCvXz1K(b!Ua+M|K zHQpZz+nIJga!{~s^|=(#zqp`#{i-i8p~C)kpfw!jRdui7Xi9IWvl6^W(m<)x?U=Es zVa)o`WdMAD#4Sx;+D-_yn}3Gz&`_7*h>Bfg53bjPy4yUlO#|Dn$pjC=npWTToaR02 z*cP_F#;Ewnh(h|&OguRDi}F0tHX$ijP~xA-DE-*jzZ|nB%Ba=BVY@RgbwxfEy$7Zx zcNk`9h0OGDj_x9LW`uj;Rsm)x2M`2_{QS$;0#s9YL7eLR3l9201SjYT@M3*&p*Y7p z3yvt{I<&q}o+xhHuMy77B{5hY9NBe;Lz0u*bsj*P_@5-_;$EDt+r%X%%!zlgg`HA0 z)vI%&`f1e>9;7jVxLAmwc>aT8c31 zA~vCA2o{Na^2QC6NeL{4A7oOxB9c={-j@TA4xX?(fa5-&!D?BZETag?5|U`h`?E8--~IdzxhYtXiU8{3_Z*2>y%Jz-sQO>d%PCb*G~x2^V7k!e&iRhLQnR0Pqs>Yp!(_1l;P}#SC%BG! zLPeZ@(#V!RwTUZB}Z9Np%g52cZs;x)vF?Fd)+YUa10DM%wSJh=2_Ku`C+EGGz~c zTEeP!qncv+lex4j^8271@0N}oQ5xTnsv^Hy$95WjVKA%g8j2X_Vuv{4VAB#uT@zeJ zORoz$qSW>h)fZ^6pdVv&Lq9fl2!`1?OzEr+Iey#6{buiT8Vin9`fl|on9cYa9~g*x z%mH(J*?c=&|8cMbZSu!-(^)gT{bUb0Z_4D0l@;4%Yw!qVzb98wiR>XqScp4ED6L=) z2`NU}wJzza2O7G9T|iu1oXg6c4s1~xl}iY6z2l3{iggFojV)kNVzYCLdF_-zMH*IG z=JraE5jToov{yHm&W|YkQrk83b&m3B)0gV+d%{of2;2;d;le*o_)(!ZJ(N-Ms?ppx z4-KM{4kpl3@cxDD=uy99R) z?hqV;yE_DjphIwX$>0vb-C=Nd2rh#J2oNj;cAn?m-S3=l_w3F;HQhaZrmMQH)UR&U zMMSib(6~k?U0*ft6C7TnmY5#qEO+4lRQph4n@Oc*(?r?56`+wPx-pB`0yoV>N|T%$ zL!`L^C|c4j<%$4Uz*wKj7LgSnTwDPmL40^8VHDE z^cz7BBF&?o)9p%iscS&n@TT7aGUHbIN$+nICLS*|Dmrr^XHnX%;u5Um!(niwuGHV9 z@r9b@sA!c~mwFU0wPRNT%h5HOQNZ?$?za%by?YJrfKRY|B<#K&No=gco{T4@qm^3z3gG~N;&PsQP4^g~qI&9K>T4iXyg?$nwx zS_<}QioOa^bdG=}2Y9~ihL84y)fDb<1|RXx*X^9SsajU@IBUK0(*_HkrIZ(uVqbz` z6jcn($D@X?2w0of(wZAD0)^!h*De;d7Tl9@=8=j`(`C=Xdb5RZ=?&Ajsf~c3=AWl# zLw0CC^ljhehO62sBI_hLF)SS@vZ(**c`%z1J&0CHY6^a1KWgG4V9$_$c)WM9Y}VjF zX8GN279|C9Na+$?Gg5V`mgrdQ-L{Z^n9UMNW9T+i1bO%b!Z~Ed5r5XcA)8AGD$1X( zuUkUJ4Tz__wPys>xKee)3pY`;AVYX^|C%2RlSPy@irP14zbT*rw~_cEvlyQDH991i z!8R`~*fSXj{_+JO%!*$^e&y96_TKPImUG^0>57lfE4k7g!sBKc^7E|L3vt{q`9k4! zl1EUKJq2@mc05tnH3=6l*UBU~MeS36oY3CNO15@zO|N zt}hbAE`=EzVLnyo%*(Tc_hLQB(PKKiB8oU}p4Jq%H>+PgR@f+a$}Ty~G@Isa*rx-d zl{$~VVXXD?=4R|){r0&M6kdps#{foU7lZc>_$Yc_igkaIh7+Ag%}#DqAOrPMZe8ifCt4~rrNnOJ+`tAKk6?(aW0t>E8#g;lLsX+dumtwTHWI`v!loUFLg08-$>_o$e}yjwiCx-ExPe;G=qF$wnok!0~xpJ|zB zBAGP>ACi02OBO#X<;e4iT+1N{!$g_yyrf2G?t#w`L+~OqH}OChD`SjIH1cy3p5=*u zshrKDE*Vct#(9n!(=VU&TM3WxB1L#^Cq0d42TS|9ZzGSia)wc{y1(Sdm%V|yV$4oZ zXyMMZh(46(;qBaEmq+`lMl8dYYWY!d5Cm25X#U-cL{3Uw?w0QOa=6$6IwXdj1cjojC_)9ANlrO2TA)tz;cJy zvs`cy-ow_8gpKv0#2Ro2KFp07G)Y44iu*tK|HO`9|*X&n6>!xSiMrvGi^pR!~9O2XAjUCjU9~wHJ(AItAu-2mG z(a*FzM#9UPA(*;m<0w0`S0)D42##{6p6oKnx7`(h)Abmyt>X9%e>AxjmwE3ysu10G z1U3n^S;Bp(JK*<66Q{oTEC7h7s%u^A(}zYi)|!v;dnvR}uOO2RBFb?#)Ux&Sd-=L% z&K!=hNsfcR6E#y~fp?R*Hf$E@9)7ogCcY{^x;YjLYQ=9k;g{|W<*u!g-H`hVDnzY{ zr1C^o&n~>;AGbnD8=6U+HfjHi2uv{E6LBq{j%Yy49(UP1Jry>~1+^A{ij@%qhD#jU zD1y-9Zkj)1$huSdk~<^7apzmhQoIUGhvN_B2NA&*(cKtN@b)wI?Q4m^Yr;elwatQJYf4GvImjwt z8`@GnkABYK7v5#ycwa+J;cd+7UB6iwuz^B@|D9K$1N}m%xLnp&+l~6rIBXidywy4%FOC|%2 zm?zDGk3Pa3&4xm*ezL5HaVRy~JnT73`9dJw=*pFq$wJDjPCmq z^J(wbwVKG9NWYS#QF((klYNNL__yG>HO6%@$-)pJIJD%(QE~iPRQf@50&56S*~@s{ zFg=ICj4+ZZrP82{<6dWGzag<&qi?$jX7N=1fhd^9={Y(=#J9{`;Rpf$()(B9kYN%> z|FXufZ9iw(vk>qoI*}>$n^^Rw)&hu?DS${Xve#6P*YcGy47Dgp|e`Q9CpxFR4mUfaXJiK*AKzKDnj=p1mbuuzJV4 zIKh_6Ga_DL<6B`vWW0n$O|GIhF#AhHBn$*hD>H%&;dR!F8Hp_wtkbZ z>=(=HzXNK{aeLmCdPsJkw{rzHQ2hDfXFfkedYCNcqU@}C2b=t@|IB?-!(t@4+0R&- zb8Cv}+kN!0$SEyWZAvZtd=Q*$L_-kLNh~djrKrM ze5GYzpG92NAH%-UrR;ATwfxnGRog)O+?odHl0x-1NeHVpIO%5P-AU0+cD&t)3PKvY zCrl)`qPUpX+-ylUBVbCLga`EEGOa!7Uiq~n&t`WNEsL1zwS{5b>t@8rof4&;4@AP@ zceJhlg#d$or{S64WUsB+R@VhyRmlMDQ>l~&Ia9DtzlRNNJ{>J(2tSDBu>7#>_h+3YArL*#jFLu>Ib4|sa9UPdW`v~UR9u2g~jgvth4|MnLU7a z8aTfBbh0sHd`Eo7M|AO>XkwX6y6LtM3q=4e^PlFQ{NcIrgVXkiFSipIUgBJPr6D$1 z>MVpub5_@G3+}$Kv@1d8abwFjUXK%W8a;#YgXb%+A&=tyMF819&zml~cH=Vnp(wsr zQVMEUDVS%HJ+)V&svloxujR+1keUW#_K;^^1?D` zJ~0vhLa`fNIL+6e1lspOnb;=#svc-99kxp=Cp`5cW*uCsX`>$O8gs^MW)y7$YPruC?<1Q6apri!ghw z^8c~du&t==ttV{&+EN;!o9B{omu^nwc=!R5wf+8EURjJXj1Q>}M;nK6VN2EH=7XuJ zsD1qI5i$`02c&LN#cfcy*Xb;K1@*YDUOhxcf1v}-Zak{t~V4kJ=f9*ZqyMtj6C0S5wl zK5E*yXWZ(FFbI~mqCk6)LMXG=CN?7>6kM>b%YvxW$ee?blA5JPxJcoS-e5jH_LZpkURNRuht$5B2SW~8Dbbr;WMOAv>Og!ggYHyQF7b|NG^B~;u1!9$# zNSRs}U05z*d8DZs$0RnCvG{!6ca!;q6%qC0f!FaIvfK1MdU|FA`KecbA5hu8tjHpBd4^0x$6jIjh9(V20GE?6Y6>*%Q@}~N!JK#BxbOX+&Ipfjl31Hj@6URVvHE=!i8sF897)z`$CLFK4J9(d7F#0}8j5>I*p>~pkk*4PS+tC5_ z@iDyc+NiSCAT?NO3Vg^35=-vw=fpPy&>4&;+)1(+leJ|m>APE(;}Kd@FXc(*5j~dv%~Bwy zGw30inNcGW0fLc)50t8!Vng0f<(H*3XTFO)l5q`oTk$$4^0^%IGoZ((wzq|ceSLWi z)|-hHjU6Fv`u&VF^@k)hlAu5%y3zj=IM-GqW~5|Y&uEde@^r~gf#=`w%mK$m@l65R zeX&yBEi&6XnD%B4Oj1@<7wlf)Uaj5oOk8uYh1e8IWHob6bvg*fRH+s|??2Ohx+XEd zAk)S)T837Jm=SuWCKtbPp;j}$yz3Tl`^z@1+9Vg}5_YAk6`c|Ev%k?puFW1YntHFr?}%?>wzi4RdRkC=#v17U-}tJ0!N_K)-bFS{_2Ve>gWRLnroi@5 z8sBHy5l#dvJ=4>9w2s2jrMpA=N2&31?C8gV;po+%kp9UyN_-VTXWCJ;LE1mrM4q4U zFCq>^>>U?y{ZrPIDkztcjCx%M)aEAf<&VlX)myW<Q0jt zACmM0EIFwK>^K{9w7oVsZrp4n(0DRk^@CzOIro-Zq`I-oO5%i$h#PK@RCmG4fg^Mk z#~fwNaFG{2?@HWFT+#AXoaSETv!4UTAV1sVZTa|7pHW3c)@mB*v!s+XuRs|LpJl~T z$ZSw%ehEBN>bL~k?yNf_6hflLJ8J!6%ZqnhomCwK(0_z5jE7bk{%g+c$vw*HI1&W4 zq89r?$`uBd#+<|g{wk==@*{J)=g}QUDjxCeMT)Gpc!iZ+lEa^Gd=1RN(e|cj$Yi{6 znWjFpjcIYtzxsjuB~bW&SEF$K=L$Xo%%uH@90LY#{6I20YVl|THsLwf8jm9dlys9f zh*}g2DWXKrQ|xrTCJ+gF5G1M z?BnmHG&DOFN*-7pj{61fiF8G`$Aq)OaihyekNv_*Sjl?2&!c;o;Q)~&*muf@J^Tl@ ztk9yT#VL{sbv#`1f&Re{OJ%3w)4|>UI4&P6#k3h<9p~S#BHH#oajs@KzL2U&G03--ePMj|vcoO^X=3+4A&017C-h|_6=N122h?=`ytv8>>b zxRv`i)%0+RrUS?37`Ydjoark|GpH+^I0{wo-O7;(_%X4-^=cYP6u%dsxPaATBlaX5 zgd*HoH*2>3*)ZBBw#fXdAkuU{D*d5y?Zf1TJ9(WRIsCkfKhHp%AzI1d>%HD>hM=n~e5QYRWn_GRx#?KfsKKT;qC0!q6&c}6 zRHLsltOU;$SB;}E2+I6#(jkf)rcSRCW;N>64uvR3svz=BFdx@DW-uKS@`BP!9>$nY zc(}Sl=dGw{p1#ySPU5!y-1!?-Qpkmhy>)TPR`q86{owmJZfZ<3%?{H$3=4V?P6`|) zj!UW)o%B=IR}BP-pXxSA74ne1<132O=;l^*A1yt{ghAvncHz zJL^^Dl0rNni7+b5J1J~(;)rs_2E%J97k|RsQ9SCyS-sd#*io}r@@xL;89OT*9gn5dBqT2)o;KXiOgA~c*8PR7 z`soFJ{=kIYuU=Y+x7WT_K#*E&tF-D!n436$5{w>k9~{}3!(J;gvFK;M^<1B=sI-8c zQ(lpUC9NvMonbMGl|e1ahfT7ugF?;OoP`!|H={c7w(wT`SEDyasG);HWc+t}6`JwH z33tw@+OM1wc5q9Af|Vt+g1coX|Gefg*v36I^qN$oh8xU{xKLNTzqQU*Z%#jZ>rX9? z5_8q(j~=A18pjt|4C(Xan`wT?WBHOe|u9u00+SRXwAD+1f zb6GrW-LX*r8^1m4|!z%$zNu`yaAeV z1HtZ^U>lE?sHZZA9SN%xT1E_?tdC9R%?1&vZ3!ls<}|xKU@4B;Q|M84C+L|)Aw${5JXRel_GjU=^Q~wj;CKS2iZJ?=<19E&1uEgzyKqN0&cuLm60aHB4#h={K z=zeD;2B^V1E_F;|mykifKRViRKx-H2yCOd$&EhG2QpV{t#5ejP!~E_^uV^{3$g~O9 zS66PZC4DovNM>%qWHyhOn;z)~E=3kD4vox<)O_ql#a8Z4yE}`&WKd60TF}S+XO{++ z_e&j;>CvQCxN6Z{Onm^1AsFzW6?O1S$ThElCon)T4?Bp2Jn~_nTZMOi;w)N4sJRgT zO-_XtR)n33Kh4Lvn#B)a%I#F}!QRcKG(T^lxA#{pG zCEIuWmL}%;uO`*vkDj&L>p?|(TBHWgzIC`bc0jjC?OBgzGx^;&dAN0TcQ+F4TWh;f zEGj~Mljt4DYQKR#;#<*JN~EUKEFHH6Nu>Jwwt3d<_TI9V}tS}zuv>^*7W-cyF3w|*r2 zu)g;%CEW%mzQ6Ut@$5h2m?R;OeVWCkrPPAEj58TxHtd1TY49W8O)EJ_S#B2f z!8m4S5M2`N(n$_2&qT)^P$x9Zk-|q#f^HMH1cqscwxRYXR;0o>Ex!b&Q%xg~J~8{2 z1Fzm%_5tyK0kOgl{{XS^VhE;Q=c7RWQ5VNnvA&}{vAZ^#9|x9D>FNiT*Q@LbE7(B5 zYPPFXO7$)?4f^4wh2oE}#v!l8%T!jmNjFOiL#1}wo+0g!b)r}_e8Gz``mswd|AGum--6G#`Vz(pKbXWdCV9=oeBuOWOfaN3shEdA)JFpJZc8Go}cmi|ZmSzK)m z_RdHwJ+$R4Zr6#Ip%6XX=_VaeG@dR)v=R$HzM}cva_X%J!9lj^JWn%vI}>4deMJ1% z$f@yQntq#HlSLqN(ZknP&(U&7i1#%dn26mQK}K%Oxj(NIQ#!>Ufuxq(EBPx}|;j zx^RJfKO|+pBO_E`ukL*Zw8|$aVR2%6)%@9AMBc1AKek4l8WJyWGp>e{4{?? z8%RJgJgD}Hc|u57rc!N69Kme6Wg z(7qKTqB-}eKNG^Pf_v@Df1G{@4L3igz}&Nrtait?+LpRHeW_0i>SZ%b2aW^=VoE}r zMM=!0Xj4m#K-&k#wm-HI_C?aoiY|qoc|7o*?#L3fdm*9h1T^<^Zq-k^a3|hbR0OXR zOjZUV1#bzDKAPEo(=u@0KZtznd0E}tkNK8)j(R3RWW!7+I!+un`)g%I2*h}!K*@Xh zz+!A58VvK?Zre@N23G2Hh#$j%97r-RrE11yV+X>?E6 zD7zEeD62ODNnN(f_Ldfq+QeB@rK$C z&f(&UI&>D3_Dof6e$XiksXd@ZK6<~tB~Vkjb7Ygc@?? z&>m3w{aGY?_31aOgnlAkcdQ;_9^$QDi1s*|)jvO)Q&~bLW5U5J6(7zkH}H87nh0&& zgpCYPOS-hcv#T$@8Ecje&625Cu7pl?{c|XEjG8&0EW#?G(UGKqjpd06<8~6(Ye5)8 zjMGygV*5f7!UD)-nyKT|mJyFTkT_7i3k+WJJdr1bQg@-g5Z?qQ>|YlcaCC*d@A$(= z|70nV8ruD%rkH!La%S|-H_^%09n~RHxWA{CM)o|oq=j74QX0YZtAj_tQUG$0kPi}t zSlLl3-p*k`Z@-5rcYuDGm{5Ff1ckL4=ua=ADRfdrfV7T{1b2U5#U$2o8!xW6>0O<* z%_N4x!Xs_Bg1p$y^D1I_>91mb%q0?)0d4DS{uI3S$QAY8^^Irfinh`=k81E_VRWre z+Z;dI|A9uCK?qqYH`Vb(1%<8V%c;J4je(c}qH^X34HF+pR+w@J_0=GZCGNX{&x>~s z4hK zLVpH%X6WertUpg5_{C1c?ugnk*<&^o9<^@o_~RfPof6*y&Sx`y21VzZz=nPWY39O2 zfVzN5J2?=es!Nrcs^A=7ov(Jra-lggm#&jFRDM7GXdHkXTj@QYZ99c@j#+;i z4wU*Xf53{+hvhk+Pb#d4fVc{1xN5ci@a=8dag6}wM#B7|8)nzZw1|4y}HOc?dDZpe1K4AI|Q zXlYewv>S@*K<|l14ky`PqhAiGiti5|e`ol>iG5-}80D)gJJ>VKbyA#LAZ6#rio^S3 zGAef+oejc8$)}#=uqi~s(Dlbq&udBcG~st;VY~Fo`H=M@KN{}exv@&BBjyBAY>m6b z?FP~WMKcNO9IsFD4}Z-B4ERIkQUkh*ZV>{6`T7rf-d zi-`k17#Wk@-W$gKHVAcN@njM4TcXDABqgXeM5#k)i5wa*Xk$CEEhMEtD#Wfbpf6>3~Bee)ppCm8<@U{?G z!Dd(a{d3jhZX1?|PontL>Dk_A0eWp~)@-IiC~+2mfA%=`tzUpLwOd{X^q%8=l~v1N z@#U)MBO)4Rqr9^^I3uv8kM~<34Cl(tP0$}0dxl}u;V+9FHhj4?oxDTSbbT=K>Z=ka z>Xj~|a(=Z$&-Vbvy5*S@3t*B(X!y3nVk1bF3F71`{IE(;dcSph8LVApr&5dP?IE9C z{Q0HxiDiQ4?b608^+H3m2iDO^ET^0m{Y)W*Wp~ISTIL>pROxGfov3fUJ4zC2!mWK} z1oc7qlyqRe=q8_Wf6nIpgTFqDo*-+Vk)291sH(_G-J#7|&1Uk};UG_gmV#IzG#O-l zQ%jYz`0W&|Y0TRq)G+&9_V`lQ{Kx6xmFHz#dLD!M*>Aj>vA^N}lLPOpdHxgXJS8TR zNNG=!eFq3%+%#m9sResAeT3GZR8Bw>^tI*;EwrGiCfk!la(}e;!C@w$*PWsDDD^bp zMp@l3kVEWx5Kd>P-0J!(+WcsvWDyFLefNiGx*ZWuJjKJ*6*Vlc02D-(c5_K+DrJxq zsb1?n9QQj0<*hJd47mzsXN9-P6k;;zx9DSX2U`AmFc-y0)988=$*E>zpV0T`7?JXs z-o0FuR@@YU&?H3xR(mgJyV>Adwj5F(0}R)X&Y3J>Iy)V^R5|+DqSvLn8LNu zSgOM2L~TsQ@@Bv@7!geV4T}bLR53^~W6cJ*0(=-Q)6(RU9Bj$nV+);k*gO5@tYXe~ zh%NUNSK4MBle)c*udiK$iwUiz6uHG(PH=)Z<|WLXqG9DH~Y<9t;ortD6G$_t7c!N{;|^mUbvZpG6gzJ%lZk zp&WRjDdyoZ48m!DR6$<$BZ21tGS#%ma? zyGFId)Rj;YzYJ~BZMAMUL@wm$R=_-;bL9?>q}DwaawmgTs|RTr^KdKXSZ0Cygi%M^LcFY6%R@(swXJF?&9H6_}O=! zn>eIKxuj3WS5Q*9NO&WNqYai6LmkhKsN%1g&JfU6+G7wupD~- zwo3_14EfE$ArNzpbknEDljFI8kauK_n1bKlv7EFqYqq3)HcvrVy2D(>+<_CJiU7?) zGY_2ojmGedmuJ(mf7-}VT6XUUx4sJaGTxRS2Frpo;M{cdXwYu9u&XO7fR;B9d{l&j zLiW?3bhyB|-#=0K<(W}JL8Rijie+&gJ)*6(oT<9=r&OhgXMU}NiX?=PU0zK7A?X2( zEqLNzJG8VYi45B${d$56=sOi)@}-wyDZ;B){3) zualR#14!SIhYvajihn}IpIIM`yyPcEH={0=d~Lh)QOIzYRT0e?`2rys0weZ|ZFZMuIY^B!K)OFev zI@SEw5#h~w(R&Fb7OKuO902#U)BXk?HGS@zB~vT5e^d;a{<$J@F?0gq=&Nm>q-Kub zL9`JroQjqclA~nA$3y}bRcO_26;jBmWyQ6Vb8}ivzG-US?;jV$QeaX?zB-p?UbTk` zxbU-yzfwHUESR#MfB1CU^7s4QfPtP5Y@tLNFBLkcMaZx}5KUgc8~8TkcgEGzUnyYjW_Um;`N&0d zzg!aXWtd!FybY)pSC@wImiBowC&Wgjx(UC`e{;Ukj+udj zHg;k|f9+x_TNMAGJux*|JF2~+P5M3FZ)xiYwxYwx^h0oU$e|<%=Gno^oM5_cy~@P` zh0tEG?Xq{RC2k$^c@u<7!P!2Z^iQ`pebXK*u2ee=0sLmTg&tL|y5MM-`%?znJ#u$& z1GdJlO>g|0n&wnImM<|e$GG`>CRsKUkJF@RU5k{h_5X>(qp>i)KFBML&7aPbf=8E@ zwRI1KG-5|=0~-Y}>&!2xC4>x(B4!0HETdu?l5Tkbbz5ka)6KcBA78j7LH`2ocmD;p z{{y-kBc@;fZolqszrOGrK_v-0W=o>k5fHNP?Xq!U*CsO9ccD;u*y#v1&x*Z?5ICd* o-p)txpu>OX 1 or args.multiprocessing_distributed - - args.process_device_map = device_id_to_process_device_map(args.device_list) - - if args.device == 'npu': - ngpus_per_node = len(args.process_device_map) - else: - if args.distributed: - ngpus_per_node = torch.cuda.device_count() - else: - ngpus_per_node = 1 - print('ngpus_per_node:', ngpus_per_node) - if args.multiprocessing_distributed: - # Since we have ngpus_per_node processes per node, the total world_size - # needs to be adjusted accordingly - args.world_size = ngpus_per_node * args.world_size - # Use torch.multiprocessing.spawn to launch distributed processes: the - # main_worker process function - #mp.spawn(main_worker, nprocs=ngpus_per_node, args=(ngpus_per_node, args)) - main_worker(args.gpu, ngpus_per_node, args) - - else: - # Simply call main_worker function - main_worker(args.gpu, ngpus_per_node, args) - - -def main_worker(gpu, ngpus_per_node, args): - global best_acc1 - args.gpu = args.process_device_map[gpu] - - if args.distributed: - args.gpu = args.rank - if args.dist_url == "env://" and args.rank == -1: - args.rank = int(os.environ["RANK"]) - if args.multiprocessing_distributed: - # For multiprocessing distributed training, rank needs to be the - # global rank among all the processes - args.rank = args.rank * ngpus_per_node + gpu - - if args.device == 'npu': - os.environ['MASTER_ADDR'] = '127.0.0.1' - os.environ['MASTER_PORT'] = '29688' - loc = 'npu:{}'.format(args.gpu) - torch.npu.set_device(loc) - dist.init_process_group(backend=args.dist_backend, # init_method=args.dist_url, - world_size=args.world_size, rank=args.rank) - else: - dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url, - world_size=args.world_size, rank=args.rank) - # create model - if args.pretrained: - print("=> using pre-trained model resnext101_32x8d") - model = resnet_0_6_0.resnext101_32x8d(pretrained=False, progress=True) - print("Load my train models...") - pretrained_dict = \ - torch.load("checkpoint.pth.tar", map_location="cpu")["state_dict"] - model.load_state_dict({k.replace('module.', ''): v for k, v in pretrained_dict.items()}, strict=False) - if "fc.weight" in pretrained_dict: - pretrained_dict.pop('fc.weight') - pretrained_dict.pop('fc.bias') - if "module.fc.weight" in pretrained_dict: - pretrained_dict.pop('module.fc.weight') - pretrained_dict.pop('module.fc.bias') - for param in model.parameters(): - param.requires_grad = False - model.fc = nn.Linear(2048, 1000) - model.load_state_dict(pretrained_dict, strict=False) - else: - print("=> creating model resnext101_32x8d") - model = resnet_0_6_0.resnext101_32x8d() - - if args.distributed: - # For multiprocessing distributed, DistributedDataParallel constructor - # should always set the single device scope, otherwise, - # DistributedDataParallel will use all available devices. - if args.gpu is not None: - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - model = model.to(loc) - else: - torch.cuda.set_device(args.gpu) - model.cuda(args.gpu) - - # When using a single GPU per process and per - # DistributedDataParallel, we need to divide the batch size - # ourselves based on the total number of GPUs we have - args.batch_size = int(args.batch_size / args.world_size) - args.workers = int((args.workers + ngpus_per_node - 1) / ngpus_per_node) - else: - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - model = model.to(loc) - else: - model.cuda() - # DistributedDataParallel will divide and allocate batch_size to all - # available GPUs if device_ids are not set - print("[gpu id:", args.gpu, "]", - "============================test args.gpu is not None else==========================") - elif args.gpu is not None: - print("[gpu id:", args.gpu, "]", - "============================test elif args.gpu is not None:==========================") - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - torch.npu.set_device(args.gpu) - model = model.to(loc) - else: - torch.cuda.set_device(args.gpu) - model = model.cuda(args.gpu) - - else: - # DataParallel will divide and allocate batch_size to all available GPUs - print("[gpu id:", args.gpu, "]", "============================test 1==========================") - print("[gpu id:", args.gpu, "]", "============================test 3==========================") - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - else: - print("before : model = torch.nn.DataParallel(model).cuda()") - - # define loss function (criterion) and optimizer - optimizer = apex.optimizers.NpuFusedSGD(model.parameters(), args.lr, - momentum=args.momentum, - weight_decay=args.weight_decay) - - - if args.amp: - model, optimizer = amp.initialize( - model, optimizer, opt_level=args.opt_level, loss_scale=args.loss_scale) - - if args.distributed: - # For multiprocessing distributed, DistributedDataParallel constructor - # should always set the single device scope, otherwise, - # DistributedDataParallel will use all available devices. - if args.gpu is not None: - # When using a single GPU per process and per - # DistributedDataParallel, we need to divide the batch size - # ourselves based on the total number of GPUs we have - if args.pretrained: - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu], broadcast_buffers=False, - find_unused_parameters=True) - else: - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu], broadcast_buffers=False) - else: - print("[gpu id:", args.gpu, "]", - "============================test args.gpu is not None else==========================") - model = torch.nn.parallel.DistributedDataParallel(model) - elif args.gpu is not None: - print("[gpu id:", args.gpu, "]", - "============================test elif args.gpu is not None:==========================") - else: - # DataParallel will divide and allocate batch_size to all available GPUs - print("[gpu id:", args.gpu, "]", "============================test 1==========================") - print("[gpu id:", args.gpu, "]", "============================test 3==========================") - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - model = torch.nn.DataParallel(model).to(loc) - else: - model = torch.nn.DataParallel(model).cuda() - print(torch.npu.synchronize(), "-- A 2.0 ------") - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - criterion = nn.CrossEntropyLoss().to(loc) - else: - criterion = nn.CrossEntropyLoss().cuda(args.gpu) - - # optionally resume from a checkpoint - if args.resume: - if os.path.isfile(args.resume): - print("=> loading checkpoint '{}'".format(args.resume)) - if args.gpu is None: - checkpoint = torch.load(args.resume) - else: - # Map model to be loaded to specified single gpu. - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - else: - loc = 'cuda:{}'.format(args.gpu) - checkpoint = torch.load(args.resume, map_location=loc) - args.start_epoch = checkpoint['epoch'] - best_acc1 = checkpoint['best_acc1'] - if args.gpu is not None: - # best_acc1 may be from a checkpoint from a different GPU - best_acc1 = best_acc1.to(args.gpu) - model.load_state_dict(checkpoint['state_dict']) - optimizer.load_state_dict(checkpoint['optimizer']) - if args.amp: - amp.load_state_dict(checkpoint['amp']) - print("=> loaded checkpoint '{}' (epoch {})" - .format(args.resume, checkpoint['epoch'])) - else: - print("=> no checkpoint found at '{}'".format(args.resume)) - - cudnn.benchmark = True - - # Data loading code - traindir = os.path.join(args.data, 'train') - valdir = os.path.join(args.data, 'val') - normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], - std=[0.229, 0.224, 0.225]) - - train_dataset = datasets.ImageFolder( - traindir, - transforms.Compose([ - transforms.RandomResizedCrop(224), - transforms.RandomHorizontalFlip(), - transforms.ToTensor(), - normalize, - ])) - - if args.distributed: - train_sampler = torch.utils.data.distributed.DistributedSampler( - train_dataset) - else: - train_sampler = None - - train_loader = torch.utils.data.DataLoader( - train_dataset, batch_size=args.batch_size, shuffle=( - train_sampler is None), - num_workers=args.workers, pin_memory=False, sampler=train_sampler, drop_last=True) - - val_loader = torch.utils.data.DataLoader( - datasets.ImageFolder(valdir, transforms.Compose([ - transforms.Resize(256), - transforms.CenterCrop(224), - transforms.ToTensor(), - normalize, - ])), - batch_size=args.batch_size, shuffle=True, - num_workers=args.workers, pin_memory=False, drop_last=True) - - if args.evaluate: - validate(val_loader, model, criterion, args, ngpus_per_node) - return - - if args.prof: - profiling(train_loader, model, criterion, optimizer, args) - return - - start_time = time.time() - for epoch in range(args.start_epoch, args.epochs): - if args.distributed: - train_sampler.set_epoch(epoch) - - adjust_learning_rate(optimizer, epoch, args) - - # train for one epoch - train(train_loader, model, criterion, optimizer, epoch, args, ngpus_per_node) - - # evaluate on validation set - acc1 = validate(val_loader, model, criterion, args, ngpus_per_node) - - # remember best acc@1 and save checkpoint - is_best = acc1 > best_acc1 - best_acc1 = max(acc1, best_acc1) - if args.device == 'npu' and args.gpu == 0 and epoch == 89: - print("Complete 90 epoch training, take time:{}h".format(round((time.time() - start_time) / 3600.0, 2))) - - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % ngpus_per_node == 0): - - ############## npu modify begin ############# - if args.amp: - save_checkpoint({ - 'epoch': epoch + 1, - 'arch': 'resnext101_32x8d', - 'state_dict': model.state_dict(), - 'best_acc1': best_acc1, - 'optimizer': optimizer.state_dict(), - 'amp': amp.state_dict(), - }, is_best) - else: - save_checkpoint({ - 'epoch': epoch + 1, - 'arch': 'resnext101_32x8d', - 'state_dict': model.state_dict(), - 'best_acc1': best_acc1, - 'optimizer': optimizer.state_dict(), - }, is_best) - ############## npu modify end ############# - - -def profiling(data_loader, model, criterion, optimizer, args): - # switch to train mode - model.train() - - def update(model, images, target, optimizer): - output = model(images) - loss = criterion(output, target) - if args.amp: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.zero_grad() - optimizer.step() - - for step, (images, target) in enumerate(data_loader): - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - images = images.to(loc, non_blocking=True).to(torch.float) - target = target.to(torch.int32).to(loc, non_blocking=True) - else: - images = images.cuda(args.gpu, non_blocking=True) - target = target.cuda(args.gpu, non_blocking=True) - - if step < 5: - update(model, images, target, optimizer) - else: - if args.device == 'npu': - with torch.autograd.profiler.profile(use_npu=True) as prof: - update(model, images, target, optimizer) - else: - with torch.autograd.profiler.profile(use_cuda=True) as prof: - update(model, images, target, optimizer) - break - - prof.export_chrome_trace("output.prof") - - -def train(train_loader, model, criterion, optimizer, epoch, args, ngpus_per_node): - batch_time = AverageMeter('Time', ':6.3f') - data_time = AverageMeter('Data', ':6.3f') - losses = AverageMeter('Loss', ':.4e') - top1 = AverageMeter('Acc@1', ':6.2f') - top5 = AverageMeter('Acc@5', ':6.2f') - progress = ProgressMeter( - len(train_loader), - [batch_time, data_time, losses, top1, top5], - prefix="Epoch: [{}]".format(epoch)) - - # switch to train mode - model.train() - - end = time.time() - for i, (images, target) in enumerate(train_loader): - # measure data loading time - data_time.update(time.time() - end) - - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - images = images.to(loc, non_blocking=True).to(torch.float) - target = target.to(torch.int32).to(loc, non_blocking=True) - else: - images = images.cuda(args.gpu, non_blocking=True) - target = target.cuda(args.gpu, non_blocking=True) - - # compute output - output = model(images) - loss = criterion(output, target) - - # measure accuracy and record loss - acc1, acc5 = accuracy(output, target, topk=(1, 5)) - losses.update(loss.item(), images.size(0)) - top1.update(acc1[0], images.size(0)) - top5.update(acc5[0], images.size(0)) - - # compute gradient and do SGD step - optimizer.zero_grad() - if args.amp: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.step() - if args.device == 'npu': - torch.npu.synchronize() - - # measure elapsed time - cost_time = time.time() - end - batch_time.update(cost_time) - end = time.time() - - if i % args.print_freq == 0: - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % ngpus_per_node == 0): - progress.display(i) - - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % ngpus_per_node == 0): - print("[npu id:", args.gpu, "]", "batch_size:", args.world_size * args.batch_size, - 'Time: {:.3f}'.format(batch_time.avg), '* FPS@all {:.3f}'.format( - args.batch_size * args.world_size / batch_time.avg)) - - -def validate(val_loader, model, criterion, args, ngpus_per_node): - batch_time = AverageMeter('Time', ':6.3f') - losses = AverageMeter('Loss', ':.4e') - top1 = AverageMeter('Acc@1', ':6.2f') - top5 = AverageMeter('Acc@5', ':6.2f') - progress = ProgressMeter( - len(val_loader), - [batch_time, losses, top1, top5], - prefix='Test: ') - - # switch to evaluate mode - model.eval() - - with torch.no_grad(): - end = time.time() - for i, (images, target) in enumerate(val_loader): - if args.gpu is not None: - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - images = images.to(loc).to(torch.float) - else: - images = images.cuda(args.gpu, non_blocking=True) - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - target = target.to(torch.int32).to(loc, non_blocking=True) - else: - target = target.cuda(args.gpu, non_blocking=True) - - # compute output - output = model(images) - loss = criterion(output, target) - - # measure accuracy and record loss - acc1, acc5 = accuracy(output, target, topk=(1, 5)) - losses.update(loss.item(), images.size(0)) - top1.update(acc1[0], images.size(0)) - top5.update(acc5[0], images.size(0)) - - # measure elapsed time - cost_time = time.time() - end - batch_time.update(cost_time) - end = time.time() - - if i % args.print_freq == 0: - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % ngpus_per_node == 0): - progress.display(i) - - if i % args.print_freq == 0: - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % ngpus_per_node == 0): - print("[gpu id:", args.gpu, "]", '[AVG-ACC] * Acc@1 {top1.avg:.3f} Acc@5 {top5.avg:.3f}' - .format(top1=top1, top5=top5)) - - return top1.avg - - -def save_checkpoint(state, is_best, filename='checkpoint.pth.tar'): - torch.save(state, filename) - if is_best: - shutil.copyfile(filename, 'model_best.pth.tar') - - -class AverageMeter(object): - """Computes and stores the average and current value""" - - def __init__(self, name, fmt=':f', start_count_index=2): - self.name = name - self.fmt = fmt - self.reset() - self.start_count_index = start_count_index - - def reset(self): - self.val = 0 - self.avg = 0 - self.sum = 0 - self.count = 0 - - def update(self, val, n=1): - if self.count == 0: - self.N = n - - self.val = val - self.count += n - if self.count > (self.start_count_index * self.N): - self.sum += val * n - self.avg = self.sum / (self.count - self.start_count_index * self.N) - - def __str__(self): - fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' - return fmtstr.format(**self.__dict__) - - -class ProgressMeter(object): - - def __init__(self, num_batches, meters, prefix=""): - self.batch_fmtstr = self._get_batch_fmtstr(num_batches) - self.meters = meters - self.prefix = prefix - - def display(self, batch): - entries = [self.prefix + self.batch_fmtstr.format(batch)] - entries += [str(meter) for meter in self.meters] - print('\t'.join(entries)) - - def _get_batch_fmtstr(self, num_batches): - num_digits = len(str(num_batches // 1)) - fmt = '{:' + str(num_digits) + 'd}' - return '[' + fmt + '/' + fmt.format(num_batches) + ']' - - -def adjust_learning_rate(optimizer, epoch, args): - """Sets the learning rate to the initial LR decayed by 10 every 30 epochs""" - # lr = args.lr * (0.1 ** (epoch // (args.epochs//3 - 3))) - - if args.warm_up_epochs > 0 and epoch < args.warm_up_epochs: - lr = args.lr * ((epoch + 1) / (args.warm_up_epochs + 1)) - else: - alpha = 0 - cosine_decay = 0.5 * ( - 1 + np.cos(np.pi * (epoch - args.warm_up_epochs) / (args.epochs - args.warm_up_epochs))) - decayed = (1 - alpha) * cosine_decay + alpha - lr = args.lr * decayed - - print("=> Epoch[%d] Setting lr: %.4f" % (epoch, lr)) - for param_group in optimizer.param_groups: - param_group['lr'] = lr - - -def accuracy(output, target, topk=(1,)): - """Computes the accuracy over the k top predictions for the specified values of k""" - with torch.no_grad(): - maxk = max(topk) - batch_size = target.size(0) - - _, pred = output.topk(maxk, 1, True, True) - pred = pred.t() - correct = pred.eq(target.view(1, -1).expand_as(pred)) - - res = [] - for k in topk: - correct_k = correct[:k].reshape(-1).float().sum(0, keepdim=True) - res.append(correct_k.mul_(100.0 / batch_size)) - return res - - -if __name__ == '__main__': - main() +# -*- coding: utf-8 -*- +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 warnings +import argparse +import os +import random +import shutil +import time +import warnings +import torch +import numpy as np +import apex +from apex import amp +import torch.nn as nn +import torch.nn.parallel +import torch.npu +import torch.backends.cudnn as cudnn +import torch.distributed as dist +import torch.optim +import torch.multiprocessing as mp +import torch.utils.data +import torch.utils.data.distributed +import torchvision.transforms as transforms +import torchvision.datasets as datasets +import models.resnet_0_6_0 as resnet_0_6_0 + +warnings.filterwarnings('ignore') +parser = argparse.ArgumentParser(description='PyTorch ImageNet Training') +parser.add_argument('data', metavar='DIR', + help='path to dataset') +parser.add_argument('-j', '--workers', default=4, type=int, metavar='N', + help='number of data loading workers (default: 4)') +parser.add_argument('--epochs', default=90, type=int, metavar='N', + help='number of total epochs to run') +parser.add_argument('--start-epoch', default=0, type=int, metavar='N', + help='manual epoch number (useful on restarts)') +parser.add_argument('-b', '--batch-size', default=256, type=int, + metavar='N', + help='mini-batch size (default: 256), this is the total ' + 'batch size of all GPUs on the current node when ' + 'using Data Parallel or Distributed Data Parallel') +parser.add_argument('--lr', '--learning-rate', default=0.1, type=float, + metavar='LR', help='initial learning rate', dest='lr') +parser.add_argument('--momentum', default=0.9, type=float, metavar='M', + help='momentum') +parser.add_argument('--wd', '--weight-decay', default=1e-4, type=float, + metavar='W', help='weight decay (default: 1e-4)', + dest='weight_decay') +parser.add_argument('-p', '--print-freq', default=10, type=int, + metavar='N', help='print frequency (default: 10)') +parser.add_argument('--resume', default=None, type=str, metavar='PATH', + help='path to latest checkpoint (default: none)') +parser.add_argument('-e', '--evaluate', dest='evaluate', action='store_true', + help='evaluate model on validation set') +parser.add_argument('--pretrained', dest='pretrained', action='store_true', + help='use pre-trained model') +parser.add_argument('--world-size', default=-1, type=int, + help='number of nodes for distributed training') +parser.add_argument('--rank', default=-1, type=int, + help='node rank for distributed training') +parser.add_argument('--dist-url', default='tcp://224.66.41.62:23456', type=str, + help='url used to set up distributed training') +parser.add_argument('--dist-backend', default='nccl', type=str, + help='distributed backend') +parser.add_argument('--seed', default=None, type=int, + help='seed for initializing training. ') +parser.add_argument('--gpu', default=None, type=int, + help='GPU id to use.') +parser.add_argument('--multiprocessing-distributed', action='store_true', + help='Use multi-processing distributed training to launch ' + 'N processes per node, which has N GPUs. This is the ' + 'fastest way to use PyTorch for either single node or ' + 'multi node data parallel training') +## for ascend 910 +parser.add_argument('--device', default='npu', type=str, help='npu or gpu') +parser.add_argument('--addr', default='10.136.181.115', + type=str, help='master addr') +parser.add_argument('--device_list', default='0,1,2,3,4,5,6,7', + type=str, help='device id list') +parser.add_argument('--amp', default=False, action='store_true', + help='use amp to train the model') +parser.add_argument('--loss-scale', default=1024., type=float, + help='loss scale using in amp, default -1 means dynamic') +parser.add_argument('--opt-level', default='O2', type=str, + help='loss scale using in amp, default -1 means dynamic') +parser.add_argument('--prof', default=False, action='store_true', + help='use profiling to evaluate the performance of model') +parser.add_argument('--warm_up_epochs', default=5, type=int, + help='warm up') +best_acc1 = 0 + + +def device_id_to_process_device_map(device_list): + devices = device_list.split(",") + devices = [int(x) for x in devices] + devices.sort() + + process_device_map = dict() + for process_id, device_id in enumerate(devices): + process_device_map[process_id] = device_id + + return process_device_map + + +def main(): + args = parser.parse_args() + + os.environ['MASTER_ADDR'] = args.addr + os.environ['MASTER_PORT'] = '29688' + + if args.seed is not None: + random.seed(args.seed) + torch.manual_seed(args.seed) + cudnn.deterministic = True + warnings.warn('You have chosen to seed training. ' + 'This will turn on the CUDNN deterministic setting, ' + 'which can slow down your training considerably! ' + 'You may see unexpected behavior when restarting ' + 'from checkpoints.') + + if args.gpu is not None: + warnings.warn('You have chosen a specific GPU. This will completely ' + 'disable data parallelism.') + + if args.dist_url == "env://" and args.world_size == -1: + args.world_size = int(os.environ["WORLD_SIZE"]) + + args.distributed = args.world_size > 1 or args.multiprocessing_distributed + + args.process_device_map = device_id_to_process_device_map(args.device_list) + + if args.device == 'npu': + ngpus_per_node = len(args.process_device_map) + else: + if args.distributed: + ngpus_per_node = torch.cuda.device_count() + else: + ngpus_per_node = 1 + print('ngpus_per_node:', ngpus_per_node) + if args.multiprocessing_distributed: + # Since we have ngpus_per_node processes per node, the total world_size + # needs to be adjusted accordingly + args.world_size = ngpus_per_node * args.world_size + # Use torch.multiprocessing.spawn to launch distributed processes: the + # main_worker process function + #mp.spawn(main_worker, nprocs=ngpus_per_node, args=(ngpus_per_node, args)) + main_worker(args.gpu, ngpus_per_node, args) + + else: + # Simply call main_worker function + main_worker(args.gpu, ngpus_per_node, args) + + +def main_worker(gpu, ngpus_per_node, args): + global best_acc1 + args.gpu = args.process_device_map[gpu] + + if args.distributed: + args.gpu = args.rank + if args.dist_url == "env://" and args.rank == -1: + args.rank = int(os.environ["RANK"]) + if args.multiprocessing_distributed: + # For multiprocessing distributed training, rank needs to be the + # global rank among all the processes + args.rank = args.rank * ngpus_per_node + gpu + + if args.device == 'npu': + os.environ['MASTER_ADDR'] = '127.0.0.1' + os.environ['MASTER_PORT'] = '29688' + loc = 'npu:{}'.format(args.gpu) + torch.npu.set_device(loc) + dist.init_process_group(backend=args.dist_backend, # init_method=args.dist_url, + world_size=args.world_size, rank=args.rank) + else: + dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url, + world_size=args.world_size, rank=args.rank) + # create model + if args.pretrained: + print("=> using pre-trained model resnext101_32x8d") + model = resnet_0_6_0.resnext101_32x8d(pretrained=False, progress=True) + print("Load my train models...") + pretrained_dict = \ + torch.load("checkpoint.pth.tar", map_location="cpu")["state_dict"] + model.load_state_dict({k.replace('module.', ''): v for k, v in pretrained_dict.items()}, strict=False) + if "fc.weight" in pretrained_dict: + pretrained_dict.pop('fc.weight') + pretrained_dict.pop('fc.bias') + if "module.fc.weight" in pretrained_dict: + pretrained_dict.pop('module.fc.weight') + pretrained_dict.pop('module.fc.bias') + for param in model.parameters(): + param.requires_grad = False + model.fc = nn.Linear(2048, 1000) + model.load_state_dict(pretrained_dict, strict=False) + else: + print("=> creating model resnext101_32x8d") + model = resnet_0_6_0.resnext101_32x8d() + + if args.distributed: + # For multiprocessing distributed, DistributedDataParallel constructor + # should always set the single device scope, otherwise, + # DistributedDataParallel will use all available devices. + if args.gpu is not None: + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + model = model.to(loc) + else: + torch.cuda.set_device(args.gpu) + model.cuda(args.gpu) + + # When using a single GPU per process and per + # DistributedDataParallel, we need to divide the batch size + # ourselves based on the total number of GPUs we have + args.batch_size = int(args.batch_size / args.world_size) + args.workers = int((args.workers + ngpus_per_node - 1) / ngpus_per_node) + else: + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + model = model.to(loc) + else: + model.cuda() + # DistributedDataParallel will divide and allocate batch_size to all + # available GPUs if device_ids are not set + print("[gpu id:", args.gpu, "]", + "============================test args.gpu is not None else==========================") + elif args.gpu is not None: + print("[gpu id:", args.gpu, "]", + "============================test elif args.gpu is not None:==========================") + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + torch.npu.set_device(args.gpu) + model = model.to(loc) + else: + torch.cuda.set_device(args.gpu) + model = model.cuda(args.gpu) + + else: + # DataParallel will divide and allocate batch_size to all available GPUs + print("[gpu id:", args.gpu, "]", "============================test 1==========================") + print("[gpu id:", args.gpu, "]", "============================test 3==========================") + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + else: + print("before : model = torch.nn.DataParallel(model).cuda()") + + # define loss function (criterion) and optimizer + optimizer = apex.optimizers.NpuFusedSGD(model.parameters(), args.lr, + momentum=args.momentum, + weight_decay=args.weight_decay) + + + if args.amp: + model, optimizer = amp.initialize( + model, optimizer, opt_level=args.opt_level, loss_scale=args.loss_scale) + + if args.distributed: + # For multiprocessing distributed, DistributedDataParallel constructor + # should always set the single device scope, otherwise, + # DistributedDataParallel will use all available devices. + if args.gpu is not None: + # When using a single GPU per process and per + # DistributedDataParallel, we need to divide the batch size + # ourselves based on the total number of GPUs we have + if args.pretrained: + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu], broadcast_buffers=False, + find_unused_parameters=True) + else: + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu], broadcast_buffers=False) + else: + print("[gpu id:", args.gpu, "]", + "============================test args.gpu is not None else==========================") + model = torch.nn.parallel.DistributedDataParallel(model) + elif args.gpu is not None: + print("[gpu id:", args.gpu, "]", + "============================test elif args.gpu is not None:==========================") + else: + # DataParallel will divide and allocate batch_size to all available GPUs + print("[gpu id:", args.gpu, "]", "============================test 1==========================") + print("[gpu id:", args.gpu, "]", "============================test 3==========================") + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + model = torch.nn.DataParallel(model).to(loc) + else: + model = torch.nn.DataParallel(model).cuda() + print(torch.npu.synchronize(), "-- A 2.0 ------") + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + criterion = nn.CrossEntropyLoss().to(loc) + else: + criterion = nn.CrossEntropyLoss().cuda(args.gpu) + + # optionally resume from a checkpoint + if args.resume: + if os.path.isfile(args.resume): + print("=> loading checkpoint '{}'".format(args.resume)) + if args.gpu is None: + checkpoint = torch.load(args.resume) + else: + # Map model to be loaded to specified single gpu. + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + else: + loc = 'cuda:{}'.format(args.gpu) + checkpoint = torch.load(args.resume, map_location=loc) + args.start_epoch = checkpoint['epoch'] + best_acc1 = checkpoint['best_acc1'] + if args.gpu is not None: + # best_acc1 may be from a checkpoint from a different GPU + best_acc1 = best_acc1.to(args.gpu) + model.load_state_dict(checkpoint['state_dict']) + optimizer.load_state_dict(checkpoint['optimizer']) + if args.amp: + amp.load_state_dict(checkpoint['amp']) + print("=> loaded checkpoint '{}' (epoch {})" + .format(args.resume, checkpoint['epoch'])) + else: + print("=> no checkpoint found at '{}'".format(args.resume)) + + cudnn.benchmark = True + + # Data loading code + traindir = os.path.join(args.data, 'train') + valdir = os.path.join(args.data, 'val') + normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]) + + train_dataset = datasets.ImageFolder( + traindir, + transforms.Compose([ + transforms.RandomResizedCrop(224), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + normalize, + ])) + + if args.distributed: + train_sampler = torch.utils.data.distributed.DistributedSampler( + train_dataset) + else: + train_sampler = None + + train_loader = torch.utils.data.DataLoader( + train_dataset, batch_size=args.batch_size, shuffle=( + train_sampler is None), + num_workers=args.workers, pin_memory=False, sampler=train_sampler, drop_last=True) + + val_loader = torch.utils.data.DataLoader( + datasets.ImageFolder(valdir, transforms.Compose([ + transforms.Resize(256), + transforms.CenterCrop(224), + transforms.ToTensor(), + normalize, + ])), + batch_size=args.batch_size, shuffle=True, + num_workers=args.workers, pin_memory=False, drop_last=True) + + if args.evaluate: + validate(val_loader, model, criterion, args, ngpus_per_node) + return + + if args.prof: + profiling(train_loader, model, criterion, optimizer, args) + return + + start_time = time.time() + for epoch in range(args.start_epoch, args.epochs): + if args.distributed: + train_sampler.set_epoch(epoch) + + adjust_learning_rate(optimizer, epoch, args) + + # train for one epoch + train(train_loader, model, criterion, optimizer, epoch, args, ngpus_per_node) + + # evaluate on validation set + acc1 = validate(val_loader, model, criterion, args, ngpus_per_node) + + # remember best acc@1 and save checkpoint + is_best = acc1 > best_acc1 + best_acc1 = max(acc1, best_acc1) + if args.device == 'npu' and args.gpu == 0 and epoch == 89: + print("Complete 90 epoch training, take time:{}h".format(round((time.time() - start_time) / 3600.0, 2))) + + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % ngpus_per_node == 0): + + ############## npu modify begin ############# + if args.amp: + save_checkpoint({ + 'epoch': epoch + 1, + 'arch': 'resnext101_32x8d', + 'state_dict': model.state_dict(), + 'best_acc1': best_acc1, + 'optimizer': optimizer.state_dict(), + 'amp': amp.state_dict(), + }, is_best) + else: + save_checkpoint({ + 'epoch': epoch + 1, + 'arch': 'resnext101_32x8d', + 'state_dict': model.state_dict(), + 'best_acc1': best_acc1, + 'optimizer': optimizer.state_dict(), + }, is_best) + ############## npu modify end ############# + + +def profiling(data_loader, model, criterion, optimizer, args): + # switch to train mode + model.train() + + def update(model, images, target, optimizer): + output = model(images) + loss = criterion(output, target) + if args.amp: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + optimizer.zero_grad() + optimizer.step() + + for step, (images, target) in enumerate(data_loader): + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + images = images.to(loc, non_blocking=True).to(torch.float) + target = target.to(torch.int32).to(loc, non_blocking=True) + else: + images = images.cuda(args.gpu, non_blocking=True) + target = target.cuda(args.gpu, non_blocking=True) + + if step < 5: + update(model, images, target, optimizer) + else: + if args.device == 'npu': + with torch.autograd.profiler.profile(use_npu=True) as prof: + update(model, images, target, optimizer) + else: + with torch.autograd.profiler.profile(use_cuda=True) as prof: + update(model, images, target, optimizer) + break + + prof.export_chrome_trace("output.prof") + + +def train(train_loader, model, criterion, optimizer, epoch, args, ngpus_per_node): + batch_time = AverageMeter('Time', ':6.3f') + data_time = AverageMeter('Data', ':6.3f') + losses = AverageMeter('Loss', ':.4e') + top1 = AverageMeter('Acc@1', ':6.2f') + top5 = AverageMeter('Acc@5', ':6.2f') + progress = ProgressMeter( + len(train_loader), + [batch_time, data_time, losses, top1, top5], + prefix="Epoch: [{}]".format(epoch)) + + # switch to train mode + model.train() + + end = time.time() + for i, (images, target) in enumerate(train_loader): + # measure data loading time + data_time.update(time.time() - end) + + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + images = images.to(loc, non_blocking=True).to(torch.float) + target = target.to(torch.int32).to(loc, non_blocking=True) + else: + images = images.cuda(args.gpu, non_blocking=True) + target = target.cuda(args.gpu, non_blocking=True) + + # compute output + output = model(images) + loss = criterion(output, target) + + # measure accuracy and record loss + acc1, acc5 = accuracy(output, target, topk=(1, 5)) + losses.update(loss.item(), images.size(0)) + top1.update(acc1[0], images.size(0)) + top5.update(acc5[0], images.size(0)) + + # compute gradient and do SGD step + optimizer.zero_grad() + if args.amp: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + optimizer.step() + if args.device == 'npu': + torch.npu.synchronize() + + # measure elapsed time + cost_time = time.time() - end + batch_time.update(cost_time) + end = time.time() + + if i % args.print_freq == 0: + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % ngpus_per_node == 0): + progress.display(i) + + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % ngpus_per_node == 0): + print("[npu id:", args.gpu, "]", "batch_size:", args.world_size * args.batch_size, + 'Time: {:.3f}'.format(batch_time.avg), '* FPS@all {:.3f}'.format( + args.batch_size * args.world_size / batch_time.avg)) + + +def validate(val_loader, model, criterion, args, ngpus_per_node): + batch_time = AverageMeter('Time', ':6.3f') + losses = AverageMeter('Loss', ':.4e') + top1 = AverageMeter('Acc@1', ':6.2f') + top5 = AverageMeter('Acc@5', ':6.2f') + progress = ProgressMeter( + len(val_loader), + [batch_time, losses, top1, top5], + prefix='Test: ') + + # switch to evaluate mode + model.eval() + + with torch.no_grad(): + end = time.time() + for i, (images, target) in enumerate(val_loader): + if args.gpu is not None: + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + images = images.to(loc).to(torch.float) + else: + images = images.cuda(args.gpu, non_blocking=True) + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + target = target.to(torch.int32).to(loc, non_blocking=True) + else: + target = target.cuda(args.gpu, non_blocking=True) + + # compute output + output = model(images) + loss = criterion(output, target) + + # measure accuracy and record loss + acc1, acc5 = accuracy(output, target, topk=(1, 5)) + losses.update(loss.item(), images.size(0)) + top1.update(acc1[0], images.size(0)) + top5.update(acc5[0], images.size(0)) + + # measure elapsed time + cost_time = time.time() - end + batch_time.update(cost_time) + end = time.time() + + if i % args.print_freq == 0: + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % ngpus_per_node == 0): + progress.display(i) + + if i % args.print_freq == 0: + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % ngpus_per_node == 0): + print("[gpu id:", args.gpu, "]", '[AVG-ACC] * Acc@1 {top1.avg:.3f} Acc@5 {top5.avg:.3f}' + .format(top1=top1, top5=top5)) + + return top1.avg + + +def save_checkpoint(state, is_best, filename='checkpoint.pth.tar'): + torch.save(state, filename) + if is_best: + shutil.copyfile(filename, 'model_best.pth.tar') + + +class AverageMeter(object): + """Computes and stores the average and current value""" + + def __init__(self, name, fmt=':f', start_count_index=2): + self.name = name + self.fmt = fmt + self.reset() + self.start_count_index = start_count_index + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + + def update(self, val, n=1): + if self.count == 0: + self.N = n + + self.val = val + self.count += n + if self.count > (self.start_count_index * self.N): + self.sum += val * n + self.avg = self.sum / (self.count - self.start_count_index * self.N) + + def __str__(self): + fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' + return fmtstr.format(**self.__dict__) + + +class ProgressMeter(object): + + def __init__(self, num_batches, meters, prefix=""): + self.batch_fmtstr = self._get_batch_fmtstr(num_batches) + self.meters = meters + self.prefix = prefix + + def display(self, batch): + entries = [self.prefix + self.batch_fmtstr.format(batch)] + entries += [str(meter) for meter in self.meters] + print('\t'.join(entries)) + + def _get_batch_fmtstr(self, num_batches): + num_digits = len(str(num_batches // 1)) + fmt = '{:' + str(num_digits) + 'd}' + return '[' + fmt + '/' + fmt.format(num_batches) + ']' + + +def adjust_learning_rate(optimizer, epoch, args): + """Sets the learning rate to the initial LR decayed by 10 every 30 epochs""" + # lr = args.lr * (0.1 ** (epoch // (args.epochs//3 - 3))) + + if args.warm_up_epochs > 0 and epoch < args.warm_up_epochs: + lr = args.lr * ((epoch + 1) / (args.warm_up_epochs + 1)) + else: + alpha = 0 + cosine_decay = 0.5 * ( + 1 + np.cos(np.pi * (epoch - args.warm_up_epochs) / (args.epochs - args.warm_up_epochs))) + decayed = (1 - alpha) * cosine_decay + alpha + lr = args.lr * decayed + + print("=> Epoch[%d] Setting lr: %.4f" % (epoch, lr)) + for param_group in optimizer.param_groups: + param_group['lr'] = lr + + +def accuracy(output, target, topk=(1,)): + """Computes the accuracy over the k top predictions for the specified values of k""" + with torch.no_grad(): + maxk = max(topk) + batch_size = target.size(0) + + _, pred = output.topk(maxk, 1, True, True) + pred = pred.t() + correct = pred.eq(target.view(1, -1).expand_as(pred)) + + res = [] + for k in topk: + correct_k = correct[:k].reshape(-1).float().sum(0, keepdim=True) + res.append(correct_k.mul_(100.0 / batch_size)) + return res + + +if __name__ == '__main__': + main() diff --git a/PyTorch/contrib/cv/classification/ResNeXt101_32x8d_for_PyTorch/modelzoo_level.txt b/PyTorch/contrib/cv/classification/ResNeXt101_32x8d_for_PyTorch/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/classification/ResNeXt101_32x8d_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/contrib/cv/classification/ResNeXt101_32x8d_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/ResNeXt101_32x8d_for_PyTorch/pthtar2onnx.py b/PyTorch/contrib/cv/classification/ResNeXt101_32x8d_for_PyTorch/pthtar2onnx.py index dca390378c..df34ce630f 100644 --- a/PyTorch/contrib/cv/classification/ResNeXt101_32x8d_for_PyTorch/pthtar2onnx.py +++ b/PyTorch/contrib/cv/classification/ResNeXt101_32x8d_for_PyTorch/pthtar2onnx.py @@ -1,49 +1,49 @@ -""" -Copyright 2020 Huawei Technologies Co., Ltd -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 torch -import torchvision -import models.resnet_0_6_0 as resnet_0_6_0 -import torch.onnx -from collections import OrderedDict - - -def proc_node_module(checkpoint, AttrName): - new_state_dict = OrderedDict() - for k, v in checkpoint[AttrName].items(): - if(k[0:7] == "module."): - name = k[7:] - else: - name = k[0:] - new_state_dict[name] = v - return new_state_dict - - -def convert(): - checkpoint = torch.load("./checkpoint.pth.tar", map_location='cpu') - checkpoint['state_dict'] = proc_node_module(checkpoint, 'state_dict') - model = resnet_0_6_0.resnext101_32x8d() - model.load_state_dict(checkpoint['state_dict']) - model.eval() - print(model) - - input_names = ["actual_input_1"] - output_names = ["output1"] - dummy_input = torch.randn(16, 3, 224, 224) - torch.onnx.export(model, dummy_input, "resnext101_32x8d_npu_16.onnx" - , input_names=input_names, output_names=output_names - , opset_version=11) - - -if __name__ == "__main__": - convert() +""" +Copyright 2020 Huawei Technologies Co., Ltd +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 torch +import torchvision +import models.resnet_0_6_0 as resnet_0_6_0 +import torch.onnx +from collections import OrderedDict + + +def proc_node_module(checkpoint, AttrName): + new_state_dict = OrderedDict() + for k, v in checkpoint[AttrName].items(): + if(k[0:7] == "module."): + name = k[7:] + else: + name = k[0:] + new_state_dict[name] = v + return new_state_dict + + +def convert(): + checkpoint = torch.load("./checkpoint.pth.tar", map_location='cpu') + checkpoint['state_dict'] = proc_node_module(checkpoint, 'state_dict') + model = resnet_0_6_0.resnext101_32x8d() + model.load_state_dict(checkpoint['state_dict']) + model.eval() + print(model) + + input_names = ["actual_input_1"] + output_names = ["output1"] + dummy_input = torch.randn(16, 3, 224, 224) + torch.onnx.export(model, dummy_input, "resnext101_32x8d_npu_16.onnx" + , input_names=input_names, output_names=output_names + , opset_version=11) + + +if __name__ == "__main__": + convert() diff --git a/PyTorch/contrib/cv/classification/ResNeXt101_32x8d_for_PyTorch/requirements.txt b/PyTorch/contrib/cv/classification/ResNeXt101_32x8d_for_PyTorch/requirements.txt index 7f2fa08f37..fcf0962883 100644 --- a/PyTorch/contrib/cv/classification/ResNeXt101_32x8d_for_PyTorch/requirements.txt +++ b/PyTorch/contrib/cv/classification/ResNeXt101_32x8d_for_PyTorch/requirements.txt @@ -1,4 +1,4 @@ -#torch==1.5.0 -#apex -torchvision==0.2.0 -onnx +#torch==1.5.0 +#apex +torchvision==0.2.0 +onnx diff --git a/PyTorch/contrib/cv/classification/ResNet101_ID1595_for_PyTorch/modelzoo_level.txt b/PyTorch/contrib/cv/classification/ResNet101_ID1595_for_PyTorch/modelzoo_level.txt index 484664c239..55a9add9fa 100644 --- a/PyTorch/contrib/cv/classification/ResNet101_ID1595_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/contrib/cv/classification/ResNet101_ID1595_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:POK \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/ResNet18_ID1593_for_PyTorch/modelzoo_level.txt b/PyTorch/contrib/cv/classification/ResNet18_ID1593_for_PyTorch/modelzoo_level.txt index 484664c239..55a9add9fa 100644 --- a/PyTorch/contrib/cv/classification/ResNet18_ID1593_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/contrib/cv/classification/ResNet18_ID1593_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:POK \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/ResNet34_ID1594_for_PyTorch/modelzoo_level.txt b/PyTorch/contrib/cv/classification/ResNet34_ID1594_for_PyTorch/modelzoo_level.txt index 484664c239..55a9add9fa 100644 --- a/PyTorch/contrib/cv/classification/ResNet34_ID1594_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/contrib/cv/classification/ResNet34_ID1594_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:POK \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/SE-ResNet-50/main.py b/PyTorch/contrib/cv/classification/SE-ResNet-50/main.py index 2e56931d84..4d87b412ee 100644 --- a/PyTorch/contrib/cv/classification/SE-ResNet-50/main.py +++ b/PyTorch/contrib/cv/classification/SE-ResNet-50/main.py @@ -1,655 +1,655 @@ -# -*- coding: utf-8 -*- -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 warnings -warnings.filterwarnings('ignore') -import argparse -import os -import random -import shutil -import time -import warnings -import torch -import numpy as np -import apex -from apex import amp -import torch.nn as nn -import torch.nn.parallel -import torch.npu -import torch.backends.cudnn as cudnn -import torch.distributed as dist -import torch.optim -import torch.multiprocessing as mp -import torch.utils.data -import torch.utils.data.distributed -import torchvision.transforms as transforms -import torchvision.datasets as datasets -import senet - -parser = argparse.ArgumentParser(description='PyTorch ImageNet Training') -parser.add_argument('data', metavar='DIR', - help='path to dataset') -parser.add_argument('-j', '--workers', default=4, type=int, metavar='N', - help='number of data loading workers (default: 4)') -parser.add_argument('--epochs', default=90, type=int, metavar='N', - help='number of total epochs to run') -parser.add_argument('--start-epoch', default=0, type=int, metavar='N', - help='manual epoch number (useful on restarts)') -parser.add_argument('-b', '--batch-size', default=256, type=int, - metavar='N', - help='mini-batch size (default: 256), this is the total ' - 'batch size of all GPUs on the current node when ' - 'using Data Parallel or Distributed Data Parallel') -parser.add_argument('--lr', '--learning-rate', default=0.1, type=float, - metavar='LR', help='initial learning rate', dest='lr') -parser.add_argument('--momentum', default=0.9, type=float, metavar='M', - help='momentum') -parser.add_argument('--wd', '--weight-decay', default=1e-4, type=float, - metavar='W', help='weight decay (default: 1e-4)', - dest='weight_decay') -parser.add_argument('-p', '--print-freq', default=10, type=int, - metavar='N', help='print frequency (default: 10)') -parser.add_argument('--resume', default='./checkpoint.pth.tar', type=str, metavar='PATH', - help='path to latest checkpoint (default: none)') -parser.add_argument('-e', '--evaluate', dest='evaluate', action='store_true', - help='evaluate model on validation set') -parser.add_argument('--pretrained', dest='pretrained', action='store_true', - help='use pre-trained model') -parser.add_argument('--world-size', default=-1, type=int, - help='number of nodes for distributed training') -parser.add_argument('--rank', default=-1, type=int, - help='node rank for distributed training') -parser.add_argument('--dist-url', default='tcp://224.66.41.62:23456', type=str, - help='url used to set up distributed training') -parser.add_argument('--dist-backend', default='nccl', type=str, - help='distributed backend') -parser.add_argument('--seed', default=None, type=int, - help='seed for initializing training. ') -parser.add_argument('--gpu', default=None, type=int, - help='GPU id to use.') -parser.add_argument('--multiprocessing-distributed', action='store_true', - help='Use multi-processing distributed training to launch ' - 'N processes per node, which has N GPUs. This is the ' - 'fastest way to use PyTorch for either single node or ' - 'multi node data parallel training') -## for ascend 910 -parser.add_argument('--device', default='npu', type=str, help='npu or gpu') -parser.add_argument('--addr', default='10.136.181.115', - type=str, help='master addr') -parser.add_argument('--device_list', default='0,1,2,3,4,5,6,7', - type=str, help='device id list') -parser.add_argument('--amp', default=False, action='store_true', - help='use amp to train the model') -parser.add_argument('--loss-scale', default=1024., type=float, - help='loss scale using in amp, default -1 means dynamic') -parser.add_argument('--opt-level', default='O2', type=str, - help='loss scale using in amp, default -1 means dynamic') -parser.add_argument('--prof', default=False, action='store_true', - help='use profiling to evaluate the performance of model') -parser.add_argument('--warm_up_epochs', default=5, type=int, - help='warm up') -best_acc1 = 0 - - -def device_id_to_process_device_map(device_list): - devices = device_list.split(",") - devices = [int(x) for x in devices] - devices.sort() - - process_device_map = dict() - for process_id, device_id in enumerate(devices): - process_device_map[process_id] = device_id - - return process_device_map - - -def main(): - args = parser.parse_args() - print(args.device_list) - - os.environ['MASTER_ADDR'] = args.addr - os.environ['MASTER_PORT'] = '29688' - - if args.seed is not None: - random.seed(args.seed) - torch.manual_seed(args.seed) - cudnn.deterministic = True - warnings.warn('You have chosen to seed training. ' - 'This will turn on the CUDNN deterministic setting, ' - 'which can slow down your training considerably! ' - 'You may see unexpected behavior when restarting ' - 'from checkpoints.') - - if args.gpu is not None: - warnings.warn('You have chosen a specific GPU. This will completely ' - 'disable data parallelism.') - - if args.dist_url == "env://" and args.world_size == -1: - args.world_size = int(os.environ["WORLD_SIZE"]) - - args.distributed = args.world_size > 1 or args.multiprocessing_distributed - - args.process_device_map = device_id_to_process_device_map(args.device_list) - - if args.device == 'npu': - ngpus_per_node = len(args.process_device_map) - else: - if args.distributed: - ngpus_per_node = torch.cuda.device_count() - else: - ngpus_per_node = 1 - print('ngpus_per_node:', ngpus_per_node) - if args.multiprocessing_distributed: - # Since we have ngpus_per_node processes per node, the total world_size - # needs to be adjusted accordingly - args.world_size = ngpus_per_node * args.world_size - # Use torch.multiprocessing.spawn to launch distributed processes: the - # main_worker process function - mp.spawn(main_worker, nprocs=ngpus_per_node, - args=(ngpus_per_node, args)) - else: - # Simply call main_worker function - main_worker(args.gpu, ngpus_per_node, args) - - -def main_worker(gpu, ngpus_per_node, args): - global best_acc1 - args.gpu = args.process_device_map[gpu] - - if args.gpu is not None: - print("Use GPU: {} for training".format(args.gpu)) - - if args.distributed: - if args.dist_url == "env://" and args.rank == -1: - args.rank = int(os.environ["RANK"]) - if args.multiprocessing_distributed: - # For multiprocessing distributed training, rank needs to be the - # global rank among all the processes - args.rank = args.rank * ngpus_per_node + gpu - - if args.device == 'npu': - dist.init_process_group(backend=args.dist_backend, # init_method=args.dist_url, - world_size=args.world_size, rank=args.rank) - else: - dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url, - world_size=args.world_size, rank=args.rank) - # create model - if args.pretrained: - print("=> using pre-trained model se_resnet50") - model = senet.se_resnet50(pretrained=True) - else: - print("=> creating model se_resnet50") - model = senet.se_resnet50() - - if args.distributed: - # For multiprocessing distributed, DistributedDataParallel constructor - # should always set the single device scope, otherwise, - # DistributedDataParallel will use all available devices. - if args.gpu is not None: - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - torch.npu.set_device(loc) - model = model.to(loc) - else: - torch.cuda.set_device(args.gpu) - model.cuda(args.gpu) - - # When using a single GPU per process and per - # DistributedDataParallel, we need to divide the batch size - # ourselves based on the total number of GPUs we have - args.batch_size = int(args.batch_size / args.world_size) - args.workers = int((args.workers + ngpus_per_node - 1) / ngpus_per_node) - else: - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - model = model.to(loc) - else: - model.cuda() - # DistributedDataParallel will divide and allocate batch_size to all - # available GPUs if device_ids are not set - print("[gpu id:", args.gpu, "]", - "============================test args.gpu is not None else==========================") - elif args.gpu is not None: - print("[gpu id:", args.gpu, "]", - "============================test elif args.gpu is not None:==========================") - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - torch.npu.set_device(args.gpu) - model = model.to(loc) - else: - torch.cuda.set_device(args.gpu) - model = model.cuda(args.gpu) - - else: - # DataParallel will divide and allocate batch_size to all available GPUs - print("[gpu id:", args.gpu, "]", "============================test 1==========================") - print("[gpu id:", args.gpu, "]", "============================test 3==========================") - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - else: - print("before : model = torch.nn.DataParallel(model).cuda()") - - # define loss function (criterion) and optimizer - optimizer = apex.optimizers.NpuFusedSGD(model.parameters(), args.lr, - momentum=args.momentum, - weight_decay=args.weight_decay) - - if args.amp: - model, optimizer = amp.initialize( - model, optimizer, opt_level=args.opt_level, loss_scale=args.loss_scale) - - if args.distributed: - # For multiprocessing distributed, DistributedDataParallel constructor - # should always set the single device scope, otherwise, - # DistributedDataParallel will use all available devices. - if args.gpu is not None: - # When using a single GPU per process and per - # DistributedDataParallel, we need to divide the batch size - # ourselves based on the total number of GPUs we have - if args.pretrained: - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu], broadcast_buffers=False, - find_unused_parameters=True) - else: - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu], broadcast_buffers=False) - else: - print("[gpu id:", args.gpu, "]", - "============================test args.gpu is not None else==========================") - model = torch.nn.parallel.DistributedDataParallel(model) - elif args.gpu is not None: - print("[gpu id:", args.gpu, "]", - "============================test elif args.gpu is not None:==========================") - else: - # DataParallel will divide and allocate batch_size to all available GPUs - print("[gpu id:", args.gpu, "]", "============================test 1==========================") - print("[gpu id:", args.gpu, "]", "============================test 3==========================") - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - model = torch.nn.DataParallel(model).to(loc) - else: - model = torch.nn.DataParallel(model).cuda() - - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - criterion = nn.CrossEntropyLoss().to(loc) - else: - criterion = nn.CrossEntropyLoss().cuda(args.gpu) - - # optionally resume from a checkpoint - if args.resume: - if os.path.isfile(args.resume): - print("=> loading checkpoint '{}'".format(args.resume)) - if args.gpu is None: - checkpoint = torch.load(args.resume) - else: - # Map model to be loaded to specified single gpu. - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - else: - loc = 'cuda:{}'.format(args.gpu) - checkpoint = torch.load(args.resume, map_location=loc) - args.start_epoch = checkpoint['epoch'] - best_acc1 = checkpoint['best_acc1'] - if args.gpu is not None: - # best_acc1 may be from a checkpoint from a different GPU - best_acc1 = best_acc1.to(args.gpu) - model.load_state_dict(checkpoint['state_dict']) - optimizer.load_state_dict(checkpoint['optimizer']) - if args.amp: - amp.load_state_dict(checkpoint['amp']) - print("=> loaded checkpoint '{}' (epoch {})" - .format(args.resume, checkpoint['epoch'])) - else: - print("=> no checkpoint found at '{}'".format(args.resume)) - - cudnn.benchmark = True - - # Data loading code - traindir = os.path.join(args.data, 'train') - valdir = os.path.join(args.data, 'val') - normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], - std=[0.229, 0.224, 0.225]) - - train_dataset = datasets.ImageFolder( - traindir, - transforms.Compose([ - transforms.RandomResizedCrop(224), - transforms.RandomHorizontalFlip(), - transforms.ToTensor(), - normalize, - ])) - - if args.distributed: - train_sampler = torch.utils.data.distributed.DistributedSampler( - train_dataset) - else: - train_sampler = None - - train_loader = torch.utils.data.DataLoader( - train_dataset, batch_size=args.batch_size, shuffle=( - train_sampler is None), - num_workers=args.workers, pin_memory=False, sampler=train_sampler, drop_last=True) - - val_loader = torch.utils.data.DataLoader( - datasets.ImageFolder(valdir, transforms.Compose([ - transforms.Resize(256), - transforms.CenterCrop(224), - transforms.ToTensor(), - normalize, - ])), - batch_size=args.batch_size, shuffle=True, - num_workers=args.workers, pin_memory=False, drop_last=True) - - if args.evaluate: - validate(val_loader, model, criterion, args, ngpus_per_node) - return - - if args.prof: - profiling(train_loader, model, criterion, optimizer, args) - return - - start_time = time.time() - for epoch in range(args.start_epoch, args.epochs): - if args.distributed: - train_sampler.set_epoch(epoch) - - adjust_learning_rate(optimizer, epoch, args) - - # train for one epoch - train(train_loader, model, criterion, optimizer, epoch, args, ngpus_per_node) - - # evaluate on validation set - acc1 = validate(val_loader, model, criterion, args, ngpus_per_node) - - # remember best acc@1 and save checkpoint - is_best = acc1 > best_acc1 - best_acc1 = max(acc1, best_acc1) - if args.device == 'npu' and args.gpu == 0 and epoch == 89: - print("Complete 90 epoch training, take time:{}h".format(round((time.time() - start_time) / 3600.0, 2))) - - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % ngpus_per_node == 0): - - ############## npu modify begin ############# - if args.amp: - save_checkpoint({ - 'epoch': epoch + 1, - 'arch': 'resnext101_32x8d', - 'state_dict': model.state_dict(), - 'best_acc1': best_acc1, - 'optimizer': optimizer.state_dict(), - 'amp': amp.state_dict(), - }, is_best) - else: - save_checkpoint({ - 'epoch': epoch + 1, - 'arch': 'resnext101_32x8d', - 'state_dict': model.state_dict(), - 'best_acc1': best_acc1, - 'optimizer': optimizer.state_dict(), - }, is_best) - ############## npu modify end ############# - - -def profiling(data_loader, model, criterion, optimizer, args): - # switch to train mode - model.train() - - def update(model, images, target, optimizer): - output = model(images) - loss = criterion(output, target) - if args.amp: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.zero_grad() - optimizer.step() - - for step, (images, target) in enumerate(data_loader): - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - images = images.to(loc, non_blocking=True).to(torch.float) - target = target.to(torch.int32).to(loc, non_blocking=True) - else: - images = images.cuda(args.gpu, non_blocking=True) - target = target.cuda(args.gpu, non_blocking=True) - - if step < 5: - update(model, images, target, optimizer) - else: - if args.device == 'npu': - with torch.autograd.profiler.profile(use_npu=True) as prof: - update(model, images, target, optimizer) - else: - with torch.autograd.profiler.profile(use_cuda=True) as prof: - update(model, images, target, optimizer) - break - - prof.export_chrome_trace("output.prof") - - -def train(train_loader, model, criterion, optimizer, epoch, args, ngpus_per_node): - batch_time = AverageMeter('Time', ':6.3f') - data_time = AverageMeter('Data', ':6.3f') - losses = AverageMeter('Loss', ':.4e') - top1 = AverageMeter('Acc@1', ':6.2f') - top5 = AverageMeter('Acc@5', ':6.2f') - progress = ProgressMeter( - len(train_loader), - [batch_time, data_time, losses, top1, top5], - prefix="Epoch: [{}]".format(epoch)) - - # switch to train mode - model.train() - - end = time.time() - for i, (images, target) in enumerate(train_loader): - # measure data loading time - data_time.update(time.time() - end) - - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - images = images.to(loc, non_blocking=True).to(torch.float) - target = target.to(torch.int32).to(loc, non_blocking=True) - else: - images = images.cuda(args.gpu, non_blocking=True) - target = target.cuda(args.gpu, non_blocking=True) - - # compute output - output = model(images) - loss = criterion(output, target) - - # measure accuracy and record loss - acc1, acc5 = accuracy(output, target, topk=(1, 5)) - losses.update(loss.item(), images.size(0)) - top1.update(acc1[0], images.size(0)) - top5.update(acc5[0], images.size(0)) - - # compute gradient and do SGD step - optimizer.zero_grad() - if args.amp: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.step() - if args.device == 'npu': - torch.npu.synchronize() - - # measure elapsed time - cost_time = time.time() - end - batch_time.update(cost_time) - end = time.time() - - if i % args.print_freq == 0: - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % ngpus_per_node == 0): - progress.display(i) - - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % ngpus_per_node == 0): - print("[npu id:", args.gpu, "]", "batch_size:", args.world_size * args.batch_size, - 'Time: {:.3f}'.format(batch_time.avg), '* FPS@all {:.3f}'.format( - args.batch_size * args.world_size / batch_time.avg)) - - -def validate(val_loader, model, criterion, args, ngpus_per_node): - batch_time = AverageMeter('Time', ':6.3f') - losses = AverageMeter('Loss', ':.4e') - top1 = AverageMeter('Acc@1', ':6.2f') - top5 = AverageMeter('Acc@5', ':6.2f') - progress = ProgressMeter( - len(val_loader), - [batch_time, losses, top1, top5], - prefix='Test: ') - - # switch to evaluate mode - model.eval() - - with torch.no_grad(): - end = time.time() - for i, (images, target) in enumerate(val_loader): - if args.gpu is not None: - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - images = images.to(loc).to(torch.float) - else: - images = images.cuda(args.gpu, non_blocking=True) - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - target = target.to(torch.int32).to(loc, non_blocking=True) - else: - target = target.cuda(args.gpu, non_blocking=True) - - # compute output - output = model(images) - loss = criterion(output, target) - - # measure accuracy and record loss - acc1, acc5 = accuracy(output, target, topk=(1, 5)) - losses.update(loss.item(), images.size(0)) - top1.update(acc1[0], images.size(0)) - top5.update(acc5[0], images.size(0)) - - # measure elapsed time - cost_time = time.time() - end - batch_time.update(cost_time) - end = time.time() - - if i % args.print_freq == 0: - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % ngpus_per_node == 0): - progress.display(i) - - if i % args.print_freq == 0: - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % ngpus_per_node == 0): - print("[gpu id:", args.gpu, "]", '[AVG-ACC] * Acc@1 {top1.avg:.3f} Acc@5 {top5.avg:.3f}' - .format(top1=top1, top5=top5)) - - return top1.avg - - -def save_checkpoint(state, is_best, filename='checkpoint.pth.tar'): - torch.save(state, filename) - if is_best: - shutil.copyfile(filename, 'model_best.pth.tar') - - -class AverageMeter(object): - """Computes and stores the average and current value""" - - def __init__(self, name, fmt=':f', start_count_index=2): - self.name = name - self.fmt = fmt - self.reset() - self.start_count_index = start_count_index - - def reset(self): - self.val = 0 - self.avg = 0 - self.sum = 0 - self.count = 0 - - def update(self, val, n=1): - if self.count == 0: - self.N = n - - self.val = val - self.count += n - if self.count > (self.start_count_index * self.N): - self.sum += val * n - self.avg = self.sum / (self.count - self.start_count_index * self.N) - - def __str__(self): - fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' - return fmtstr.format(**self.__dict__) - - -class ProgressMeter(object): - - def __init__(self, num_batches, meters, prefix=""): - self.batch_fmtstr = self._get_batch_fmtstr(num_batches) - self.meters = meters - self.prefix = prefix - - def display(self, batch): - entries = [self.prefix + self.batch_fmtstr.format(batch)] - entries += [str(meter) for meter in self.meters] - print('\t'.join(entries)) - - def _get_batch_fmtstr(self, num_batches): - num_digits = len(str(num_batches // 1)) - fmt = '{:' + str(num_digits) + 'd}' - return '[' + fmt + '/' + fmt.format(num_batches) + ']' - - -def adjust_learning_rate(optimizer, epoch, args): - """Sets the learning rate to the initial LR decayed by 10 every 30 epochs""" - # lr = args.lr * (0.1 ** (epoch // (args.epochs//3 - 3))) - - if args.warm_up_epochs > 0 and epoch < args.warm_up_epochs: - lr = args.lr * ((epoch + 1) / (args.warm_up_epochs + 1)) - else: - alpha = 0 - cosine_decay = 0.5 * ( - 1 + np.cos(np.pi * (epoch - args.warm_up_epochs) / (args.epochs - args.warm_up_epochs))) - decayed = (1 - alpha) * cosine_decay + alpha - lr = args.lr * decayed - - print("=> Epoch[%d] Setting lr: %.4f" % (epoch, lr)) - for param_group in optimizer.param_groups: - param_group['lr'] = lr - - -def accuracy(output, target, topk=(1,)): - """Computes the accuracy over the k top predictions for the specified values of k""" - with torch.no_grad(): - maxk = max(topk) - batch_size = target.size(0) - - _, pred = output.topk(maxk, 1, True, True) - pred = pred.t() - correct = pred.eq(target.view(1, -1).expand_as(pred)) - - res = [] - for k in topk: - correct_k = correct[:k].reshape(-1).float().sum(0, keepdim=True) - res.append(correct_k.mul_(100.0 / batch_size)) - return res - - -if __name__ == '__main__': - main() +# -*- coding: utf-8 -*- +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 warnings +warnings.filterwarnings('ignore') +import argparse +import os +import random +import shutil +import time +import warnings +import torch +import numpy as np +import apex +from apex import amp +import torch.nn as nn +import torch.nn.parallel +import torch.npu +import torch.backends.cudnn as cudnn +import torch.distributed as dist +import torch.optim +import torch.multiprocessing as mp +import torch.utils.data +import torch.utils.data.distributed +import torchvision.transforms as transforms +import torchvision.datasets as datasets +import senet + +parser = argparse.ArgumentParser(description='PyTorch ImageNet Training') +parser.add_argument('data', metavar='DIR', + help='path to dataset') +parser.add_argument('-j', '--workers', default=4, type=int, metavar='N', + help='number of data loading workers (default: 4)') +parser.add_argument('--epochs', default=90, type=int, metavar='N', + help='number of total epochs to run') +parser.add_argument('--start-epoch', default=0, type=int, metavar='N', + help='manual epoch number (useful on restarts)') +parser.add_argument('-b', '--batch-size', default=256, type=int, + metavar='N', + help='mini-batch size (default: 256), this is the total ' + 'batch size of all GPUs on the current node when ' + 'using Data Parallel or Distributed Data Parallel') +parser.add_argument('--lr', '--learning-rate', default=0.1, type=float, + metavar='LR', help='initial learning rate', dest='lr') +parser.add_argument('--momentum', default=0.9, type=float, metavar='M', + help='momentum') +parser.add_argument('--wd', '--weight-decay', default=1e-4, type=float, + metavar='W', help='weight decay (default: 1e-4)', + dest='weight_decay') +parser.add_argument('-p', '--print-freq', default=10, type=int, + metavar='N', help='print frequency (default: 10)') +parser.add_argument('--resume', default='./checkpoint.pth.tar', type=str, metavar='PATH', + help='path to latest checkpoint (default: none)') +parser.add_argument('-e', '--evaluate', dest='evaluate', action='store_true', + help='evaluate model on validation set') +parser.add_argument('--pretrained', dest='pretrained', action='store_true', + help='use pre-trained model') +parser.add_argument('--world-size', default=-1, type=int, + help='number of nodes for distributed training') +parser.add_argument('--rank', default=-1, type=int, + help='node rank for distributed training') +parser.add_argument('--dist-url', default='tcp://224.66.41.62:23456', type=str, + help='url used to set up distributed training') +parser.add_argument('--dist-backend', default='nccl', type=str, + help='distributed backend') +parser.add_argument('--seed', default=None, type=int, + help='seed for initializing training. ') +parser.add_argument('--gpu', default=None, type=int, + help='GPU id to use.') +parser.add_argument('--multiprocessing-distributed', action='store_true', + help='Use multi-processing distributed training to launch ' + 'N processes per node, which has N GPUs. This is the ' + 'fastest way to use PyTorch for either single node or ' + 'multi node data parallel training') +## for ascend 910 +parser.add_argument('--device', default='npu', type=str, help='npu or gpu') +parser.add_argument('--addr', default='10.136.181.115', + type=str, help='master addr') +parser.add_argument('--device_list', default='0,1,2,3,4,5,6,7', + type=str, help='device id list') +parser.add_argument('--amp', default=False, action='store_true', + help='use amp to train the model') +parser.add_argument('--loss-scale', default=1024., type=float, + help='loss scale using in amp, default -1 means dynamic') +parser.add_argument('--opt-level', default='O2', type=str, + help='loss scale using in amp, default -1 means dynamic') +parser.add_argument('--prof', default=False, action='store_true', + help='use profiling to evaluate the performance of model') +parser.add_argument('--warm_up_epochs', default=5, type=int, + help='warm up') +best_acc1 = 0 + + +def device_id_to_process_device_map(device_list): + devices = device_list.split(",") + devices = [int(x) for x in devices] + devices.sort() + + process_device_map = dict() + for process_id, device_id in enumerate(devices): + process_device_map[process_id] = device_id + + return process_device_map + + +def main(): + args = parser.parse_args() + print(args.device_list) + + os.environ['MASTER_ADDR'] = args.addr + os.environ['MASTER_PORT'] = '29688' + + if args.seed is not None: + random.seed(args.seed) + torch.manual_seed(args.seed) + cudnn.deterministic = True + warnings.warn('You have chosen to seed training. ' + 'This will turn on the CUDNN deterministic setting, ' + 'which can slow down your training considerably! ' + 'You may see unexpected behavior when restarting ' + 'from checkpoints.') + + if args.gpu is not None: + warnings.warn('You have chosen a specific GPU. This will completely ' + 'disable data parallelism.') + + if args.dist_url == "env://" and args.world_size == -1: + args.world_size = int(os.environ["WORLD_SIZE"]) + + args.distributed = args.world_size > 1 or args.multiprocessing_distributed + + args.process_device_map = device_id_to_process_device_map(args.device_list) + + if args.device == 'npu': + ngpus_per_node = len(args.process_device_map) + else: + if args.distributed: + ngpus_per_node = torch.cuda.device_count() + else: + ngpus_per_node = 1 + print('ngpus_per_node:', ngpus_per_node) + if args.multiprocessing_distributed: + # Since we have ngpus_per_node processes per node, the total world_size + # needs to be adjusted accordingly + args.world_size = ngpus_per_node * args.world_size + # Use torch.multiprocessing.spawn to launch distributed processes: the + # main_worker process function + mp.spawn(main_worker, nprocs=ngpus_per_node, + args=(ngpus_per_node, args)) + else: + # Simply call main_worker function + main_worker(args.gpu, ngpus_per_node, args) + + +def main_worker(gpu, ngpus_per_node, args): + global best_acc1 + args.gpu = args.process_device_map[gpu] + + if args.gpu is not None: + print("Use GPU: {} for training".format(args.gpu)) + + if args.distributed: + if args.dist_url == "env://" and args.rank == -1: + args.rank = int(os.environ["RANK"]) + if args.multiprocessing_distributed: + # For multiprocessing distributed training, rank needs to be the + # global rank among all the processes + args.rank = args.rank * ngpus_per_node + gpu + + if args.device == 'npu': + dist.init_process_group(backend=args.dist_backend, # init_method=args.dist_url, + world_size=args.world_size, rank=args.rank) + else: + dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url, + world_size=args.world_size, rank=args.rank) + # create model + if args.pretrained: + print("=> using pre-trained model se_resnet50") + model = senet.se_resnet50(pretrained=True) + else: + print("=> creating model se_resnet50") + model = senet.se_resnet50() + + if args.distributed: + # For multiprocessing distributed, DistributedDataParallel constructor + # should always set the single device scope, otherwise, + # DistributedDataParallel will use all available devices. + if args.gpu is not None: + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + torch.npu.set_device(loc) + model = model.to(loc) + else: + torch.cuda.set_device(args.gpu) + model.cuda(args.gpu) + + # When using a single GPU per process and per + # DistributedDataParallel, we need to divide the batch size + # ourselves based on the total number of GPUs we have + args.batch_size = int(args.batch_size / args.world_size) + args.workers = int((args.workers + ngpus_per_node - 1) / ngpus_per_node) + else: + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + model = model.to(loc) + else: + model.cuda() + # DistributedDataParallel will divide and allocate batch_size to all + # available GPUs if device_ids are not set + print("[gpu id:", args.gpu, "]", + "============================test args.gpu is not None else==========================") + elif args.gpu is not None: + print("[gpu id:", args.gpu, "]", + "============================test elif args.gpu is not None:==========================") + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + torch.npu.set_device(args.gpu) + model = model.to(loc) + else: + torch.cuda.set_device(args.gpu) + model = model.cuda(args.gpu) + + else: + # DataParallel will divide and allocate batch_size to all available GPUs + print("[gpu id:", args.gpu, "]", "============================test 1==========================") + print("[gpu id:", args.gpu, "]", "============================test 3==========================") + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + else: + print("before : model = torch.nn.DataParallel(model).cuda()") + + # define loss function (criterion) and optimizer + optimizer = apex.optimizers.NpuFusedSGD(model.parameters(), args.lr, + momentum=args.momentum, + weight_decay=args.weight_decay) + + if args.amp: + model, optimizer = amp.initialize( + model, optimizer, opt_level=args.opt_level, loss_scale=args.loss_scale) + + if args.distributed: + # For multiprocessing distributed, DistributedDataParallel constructor + # should always set the single device scope, otherwise, + # DistributedDataParallel will use all available devices. + if args.gpu is not None: + # When using a single GPU per process and per + # DistributedDataParallel, we need to divide the batch size + # ourselves based on the total number of GPUs we have + if args.pretrained: + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu], broadcast_buffers=False, + find_unused_parameters=True) + else: + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu], broadcast_buffers=False) + else: + print("[gpu id:", args.gpu, "]", + "============================test args.gpu is not None else==========================") + model = torch.nn.parallel.DistributedDataParallel(model) + elif args.gpu is not None: + print("[gpu id:", args.gpu, "]", + "============================test elif args.gpu is not None:==========================") + else: + # DataParallel will divide and allocate batch_size to all available GPUs + print("[gpu id:", args.gpu, "]", "============================test 1==========================") + print("[gpu id:", args.gpu, "]", "============================test 3==========================") + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + model = torch.nn.DataParallel(model).to(loc) + else: + model = torch.nn.DataParallel(model).cuda() + + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + criterion = nn.CrossEntropyLoss().to(loc) + else: + criterion = nn.CrossEntropyLoss().cuda(args.gpu) + + # optionally resume from a checkpoint + if args.resume: + if os.path.isfile(args.resume): + print("=> loading checkpoint '{}'".format(args.resume)) + if args.gpu is None: + checkpoint = torch.load(args.resume) + else: + # Map model to be loaded to specified single gpu. + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + else: + loc = 'cuda:{}'.format(args.gpu) + checkpoint = torch.load(args.resume, map_location=loc) + args.start_epoch = checkpoint['epoch'] + best_acc1 = checkpoint['best_acc1'] + if args.gpu is not None: + # best_acc1 may be from a checkpoint from a different GPU + best_acc1 = best_acc1.to(args.gpu) + model.load_state_dict(checkpoint['state_dict']) + optimizer.load_state_dict(checkpoint['optimizer']) + if args.amp: + amp.load_state_dict(checkpoint['amp']) + print("=> loaded checkpoint '{}' (epoch {})" + .format(args.resume, checkpoint['epoch'])) + else: + print("=> no checkpoint found at '{}'".format(args.resume)) + + cudnn.benchmark = True + + # Data loading code + traindir = os.path.join(args.data, 'train') + valdir = os.path.join(args.data, 'val') + normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]) + + train_dataset = datasets.ImageFolder( + traindir, + transforms.Compose([ + transforms.RandomResizedCrop(224), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + normalize, + ])) + + if args.distributed: + train_sampler = torch.utils.data.distributed.DistributedSampler( + train_dataset) + else: + train_sampler = None + + train_loader = torch.utils.data.DataLoader( + train_dataset, batch_size=args.batch_size, shuffle=( + train_sampler is None), + num_workers=args.workers, pin_memory=False, sampler=train_sampler, drop_last=True) + + val_loader = torch.utils.data.DataLoader( + datasets.ImageFolder(valdir, transforms.Compose([ + transforms.Resize(256), + transforms.CenterCrop(224), + transforms.ToTensor(), + normalize, + ])), + batch_size=args.batch_size, shuffle=True, + num_workers=args.workers, pin_memory=False, drop_last=True) + + if args.evaluate: + validate(val_loader, model, criterion, args, ngpus_per_node) + return + + if args.prof: + profiling(train_loader, model, criterion, optimizer, args) + return + + start_time = time.time() + for epoch in range(args.start_epoch, args.epochs): + if args.distributed: + train_sampler.set_epoch(epoch) + + adjust_learning_rate(optimizer, epoch, args) + + # train for one epoch + train(train_loader, model, criterion, optimizer, epoch, args, ngpus_per_node) + + # evaluate on validation set + acc1 = validate(val_loader, model, criterion, args, ngpus_per_node) + + # remember best acc@1 and save checkpoint + is_best = acc1 > best_acc1 + best_acc1 = max(acc1, best_acc1) + if args.device == 'npu' and args.gpu == 0 and epoch == 89: + print("Complete 90 epoch training, take time:{}h".format(round((time.time() - start_time) / 3600.0, 2))) + + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % ngpus_per_node == 0): + + ############## npu modify begin ############# + if args.amp: + save_checkpoint({ + 'epoch': epoch + 1, + 'arch': 'resnext101_32x8d', + 'state_dict': model.state_dict(), + 'best_acc1': best_acc1, + 'optimizer': optimizer.state_dict(), + 'amp': amp.state_dict(), + }, is_best) + else: + save_checkpoint({ + 'epoch': epoch + 1, + 'arch': 'resnext101_32x8d', + 'state_dict': model.state_dict(), + 'best_acc1': best_acc1, + 'optimizer': optimizer.state_dict(), + }, is_best) + ############## npu modify end ############# + + +def profiling(data_loader, model, criterion, optimizer, args): + # switch to train mode + model.train() + + def update(model, images, target, optimizer): + output = model(images) + loss = criterion(output, target) + if args.amp: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + optimizer.zero_grad() + optimizer.step() + + for step, (images, target) in enumerate(data_loader): + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + images = images.to(loc, non_blocking=True).to(torch.float) + target = target.to(torch.int32).to(loc, non_blocking=True) + else: + images = images.cuda(args.gpu, non_blocking=True) + target = target.cuda(args.gpu, non_blocking=True) + + if step < 5: + update(model, images, target, optimizer) + else: + if args.device == 'npu': + with torch.autograd.profiler.profile(use_npu=True) as prof: + update(model, images, target, optimizer) + else: + with torch.autograd.profiler.profile(use_cuda=True) as prof: + update(model, images, target, optimizer) + break + + prof.export_chrome_trace("output.prof") + + +def train(train_loader, model, criterion, optimizer, epoch, args, ngpus_per_node): + batch_time = AverageMeter('Time', ':6.3f') + data_time = AverageMeter('Data', ':6.3f') + losses = AverageMeter('Loss', ':.4e') + top1 = AverageMeter('Acc@1', ':6.2f') + top5 = AverageMeter('Acc@5', ':6.2f') + progress = ProgressMeter( + len(train_loader), + [batch_time, data_time, losses, top1, top5], + prefix="Epoch: [{}]".format(epoch)) + + # switch to train mode + model.train() + + end = time.time() + for i, (images, target) in enumerate(train_loader): + # measure data loading time + data_time.update(time.time() - end) + + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + images = images.to(loc, non_blocking=True).to(torch.float) + target = target.to(torch.int32).to(loc, non_blocking=True) + else: + images = images.cuda(args.gpu, non_blocking=True) + target = target.cuda(args.gpu, non_blocking=True) + + # compute output + output = model(images) + loss = criterion(output, target) + + # measure accuracy and record loss + acc1, acc5 = accuracy(output, target, topk=(1, 5)) + losses.update(loss.item(), images.size(0)) + top1.update(acc1[0], images.size(0)) + top5.update(acc5[0], images.size(0)) + + # compute gradient and do SGD step + optimizer.zero_grad() + if args.amp: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + optimizer.step() + if args.device == 'npu': + torch.npu.synchronize() + + # measure elapsed time + cost_time = time.time() - end + batch_time.update(cost_time) + end = time.time() + + if i % args.print_freq == 0: + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % ngpus_per_node == 0): + progress.display(i) + + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % ngpus_per_node == 0): + print("[npu id:", args.gpu, "]", "batch_size:", args.world_size * args.batch_size, + 'Time: {:.3f}'.format(batch_time.avg), '* FPS@all {:.3f}'.format( + args.batch_size * args.world_size / batch_time.avg)) + + +def validate(val_loader, model, criterion, args, ngpus_per_node): + batch_time = AverageMeter('Time', ':6.3f') + losses = AverageMeter('Loss', ':.4e') + top1 = AverageMeter('Acc@1', ':6.2f') + top5 = AverageMeter('Acc@5', ':6.2f') + progress = ProgressMeter( + len(val_loader), + [batch_time, losses, top1, top5], + prefix='Test: ') + + # switch to evaluate mode + model.eval() + + with torch.no_grad(): + end = time.time() + for i, (images, target) in enumerate(val_loader): + if args.gpu is not None: + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + images = images.to(loc).to(torch.float) + else: + images = images.cuda(args.gpu, non_blocking=True) + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + target = target.to(torch.int32).to(loc, non_blocking=True) + else: + target = target.cuda(args.gpu, non_blocking=True) + + # compute output + output = model(images) + loss = criterion(output, target) + + # measure accuracy and record loss + acc1, acc5 = accuracy(output, target, topk=(1, 5)) + losses.update(loss.item(), images.size(0)) + top1.update(acc1[0], images.size(0)) + top5.update(acc5[0], images.size(0)) + + # measure elapsed time + cost_time = time.time() - end + batch_time.update(cost_time) + end = time.time() + + if i % args.print_freq == 0: + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % ngpus_per_node == 0): + progress.display(i) + + if i % args.print_freq == 0: + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % ngpus_per_node == 0): + print("[gpu id:", args.gpu, "]", '[AVG-ACC] * Acc@1 {top1.avg:.3f} Acc@5 {top5.avg:.3f}' + .format(top1=top1, top5=top5)) + + return top1.avg + + +def save_checkpoint(state, is_best, filename='checkpoint.pth.tar'): + torch.save(state, filename) + if is_best: + shutil.copyfile(filename, 'model_best.pth.tar') + + +class AverageMeter(object): + """Computes and stores the average and current value""" + + def __init__(self, name, fmt=':f', start_count_index=2): + self.name = name + self.fmt = fmt + self.reset() + self.start_count_index = start_count_index + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + + def update(self, val, n=1): + if self.count == 0: + self.N = n + + self.val = val + self.count += n + if self.count > (self.start_count_index * self.N): + self.sum += val * n + self.avg = self.sum / (self.count - self.start_count_index * self.N) + + def __str__(self): + fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' + return fmtstr.format(**self.__dict__) + + +class ProgressMeter(object): + + def __init__(self, num_batches, meters, prefix=""): + self.batch_fmtstr = self._get_batch_fmtstr(num_batches) + self.meters = meters + self.prefix = prefix + + def display(self, batch): + entries = [self.prefix + self.batch_fmtstr.format(batch)] + entries += [str(meter) for meter in self.meters] + print('\t'.join(entries)) + + def _get_batch_fmtstr(self, num_batches): + num_digits = len(str(num_batches // 1)) + fmt = '{:' + str(num_digits) + 'd}' + return '[' + fmt + '/' + fmt.format(num_batches) + ']' + + +def adjust_learning_rate(optimizer, epoch, args): + """Sets the learning rate to the initial LR decayed by 10 every 30 epochs""" + # lr = args.lr * (0.1 ** (epoch // (args.epochs//3 - 3))) + + if args.warm_up_epochs > 0 and epoch < args.warm_up_epochs: + lr = args.lr * ((epoch + 1) / (args.warm_up_epochs + 1)) + else: + alpha = 0 + cosine_decay = 0.5 * ( + 1 + np.cos(np.pi * (epoch - args.warm_up_epochs) / (args.epochs - args.warm_up_epochs))) + decayed = (1 - alpha) * cosine_decay + alpha + lr = args.lr * decayed + + print("=> Epoch[%d] Setting lr: %.4f" % (epoch, lr)) + for param_group in optimizer.param_groups: + param_group['lr'] = lr + + +def accuracy(output, target, topk=(1,)): + """Computes the accuracy over the k top predictions for the specified values of k""" + with torch.no_grad(): + maxk = max(topk) + batch_size = target.size(0) + + _, pred = output.topk(maxk, 1, True, True) + pred = pred.t() + correct = pred.eq(target.view(1, -1).expand_as(pred)) + + res = [] + for k in topk: + correct_k = correct[:k].reshape(-1).float().sum(0, keepdim=True) + res.append(correct_k.mul_(100.0 / batch_size)) + return res + + +if __name__ == '__main__': + main() diff --git a/PyTorch/contrib/cv/classification/SE-ResNet-50/se_module.py b/PyTorch/contrib/cv/classification/SE-ResNet-50/se_module.py index b1638c0c67..8b066534e5 100644 --- a/PyTorch/contrib/cv/classification/SE-ResNet-50/se_module.py +++ b/PyTorch/contrib/cv/classification/SE-ResNet-50/se_module.py @@ -1,34 +1,34 @@ -# -*- coding: utf-8 -*- -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch import nn - - -class SELayer(nn.Module): - def __init__(self, channel, reduction=16): - super(SELayer, self).__init__() - self.avg_pool = nn.AdaptiveAvgPool2d(1) - self.fc = nn.Sequential( - nn.Linear(channel, channel // reduction, bias=False), - nn.ReLU(inplace=True), - nn.Linear(channel // reduction, channel, bias=False), - nn.Sigmoid() - ) - - def forward(self, x): - b, c, _, _ = x.size() - y = self.avg_pool(x).view(b, c) - y = self.fc(y).view(b, c, 1, 1) +# -*- coding: utf-8 -*- +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch import nn + + +class SELayer(nn.Module): + def __init__(self, channel, reduction=16): + super(SELayer, self).__init__() + self.avg_pool = nn.AdaptiveAvgPool2d(1) + self.fc = nn.Sequential( + nn.Linear(channel, channel // reduction, bias=False), + nn.ReLU(inplace=True), + nn.Linear(channel // reduction, channel, bias=False), + nn.Sigmoid() + ) + + def forward(self, x): + b, c, _, _ = x.size() + y = self.avg_pool(x).view(b, c) + y = self.fc(y).view(b, c, 1, 1) return x * y.expand_as(x) \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/SE-ResNet-50/senet.py b/PyTorch/contrib/cv/classification/SE-ResNet-50/senet.py index 01f3c76f3a..6dc5047cfc 100644 --- a/PyTorch/contrib/cv/classification/SE-ResNet-50/senet.py +++ b/PyTorch/contrib/cv/classification/SE-ResNet-50/senet.py @@ -1,300 +1,300 @@ -# -*- coding: utf-8 -*- -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch.nn as nn -from torch.hub import load_state_dict_from_url -from torchvision.models import ResNet -from se_module import SELayer - - -def conv3x3(in_planes, out_planes, stride=1): - return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, padding=1, bias=False) - - -class SEBasicBlock(nn.Module): - expansion = 1 - - def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1, - base_width=64, dilation=1, norm_layer=None, - *, reduction=16): - super(SEBasicBlock, self).__init__() - self.conv1 = conv3x3(inplanes, planes, stride) - self.bn1 = nn.BatchNorm2d(planes) - self.relu = nn.ReLU(inplace=True) - self.conv2 = conv3x3(planes, planes, 1) - self.bn2 = nn.BatchNorm2d(planes) - self.se = SELayer(planes, reduction) - self.downsample = downsample - self.stride = stride - - def forward(self, x): - residual = x - out = self.conv1(x) - out = self.bn1(out) - out = self.relu(out) - - out = self.conv2(out) - out = self.bn2(out) - out = self.se(out) - - if self.downsample is not None: - residual = self.downsample(x) - - out += residual - out = self.relu(out) - - return out - - -class SEBottleneck(nn.Module): - expansion = 4 - - def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1, - base_width=64, dilation=1, norm_layer=None, - *, reduction=16): - super(SEBottleneck, self).__init__() - self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) - self.bn1 = nn.BatchNorm2d(planes) - self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, - padding=1, bias=False) - self.bn2 = nn.BatchNorm2d(planes) - self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) - self.bn3 = nn.BatchNorm2d(planes * 4) - self.relu = nn.ReLU(inplace=True) - self.se = SELayer(planes * 4, reduction) - self.downsample = downsample - self.stride = stride - - def forward(self, x): - residual = x - - out = self.conv1(x) - out = self.bn1(out) - out = self.relu(out) - - out = self.conv2(out) - out = self.bn2(out) - out = self.relu(out) - - out = self.conv3(out) - out = self.bn3(out) - out = self.se(out) - - if self.downsample is not None: - residual = self.downsample(x) - - out += residual - out = self.relu(out) - - return out - - -def se_resnet18(num_classes=1_000): - """Constructs a ResNet-18 model. - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - """ - model = ResNet(SEBasicBlock, [2, 2, 2, 2], num_classes=num_classes) - model.avgpool = nn.AdaptiveAvgPool2d(1) - return model - - -def se_resnet34(num_classes=1_000): - """Constructs a ResNet-34 model. - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - """ - model = ResNet(SEBasicBlock, [3, 4, 6, 3], num_classes=num_classes) - model.avgpool = nn.AdaptiveAvgPool2d(1) - return model - - -def se_resnet50(num_classes=1_000, pretrained=False): - """Constructs a ResNet-50 model. - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - """ - model = ResNet(SEBottleneck, [3, 4, 6, 3], num_classes=num_classes) - model.avgpool = nn.AdaptiveAvgPool2d(1) - if pretrained: - model.load_state_dict(load_state_dict_from_url( - "https://github.com/moskomule/senet.pytorch/releases/download/archive/seresnet50-60a8950a85b2b.pkl")) - return model - - -def se_resnet101(num_classes=1_000): - """Constructs a ResNet-101 model. - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - """ - model = ResNet(SEBottleneck, [3, 4, 23, 3], num_classes=num_classes) - model.avgpool = nn.AdaptiveAvgPool2d(1) - return model - - -def se_resnet152(num_classes=1_000): - """Constructs a ResNet-152 model. - Args: - pretrained (bool): If True, returns a model pre-trained on ImageNet - """ - model = ResNet(SEBottleneck, [3, 8, 36, 3], num_classes=num_classes) - model.avgpool = nn.AdaptiveAvgPool2d(1) - return model - - -class CifarSEBasicBlock(nn.Module): - def __init__(self, inplanes, planes, stride=1, reduction=16): - super(CifarSEBasicBlock, self).__init__() - self.conv1 = conv3x3(inplanes, planes, stride) - self.bn1 = nn.BatchNorm2d(planes) - self.relu = nn.ReLU(inplace=True) - self.conv2 = conv3x3(planes, planes) - self.bn2 = nn.BatchNorm2d(planes) - self.se = SELayer(planes, reduction) - if inplanes != planes: - self.downsample = nn.Sequential(nn.Conv2d(inplanes, planes, kernel_size=1, stride=stride, bias=False), - nn.BatchNorm2d(planes)) - else: - self.downsample = lambda x: x - self.stride = stride - - def forward(self, x): - residual = self.downsample(x) - out = self.conv1(x) - out = self.bn1(out) - out = self.relu(out) - - out = self.conv2(out) - out = self.bn2(out) - out = self.se(out) - - out += residual - out = self.relu(out) - - return out - - -class CifarSEResNet(nn.Module): - def __init__(self, block, n_size, num_classes=10, reduction=16): - super(CifarSEResNet, self).__init__() - self.inplane = 16 - self.conv1 = nn.Conv2d( - 3, self.inplane, kernel_size=3, stride=1, padding=1, bias=False) - self.bn1 = nn.BatchNorm2d(self.inplane) - self.relu = nn.ReLU(inplace=True) - self.layer1 = self._make_layer( - block, 16, blocks=n_size, stride=1, reduction=reduction) - self.layer2 = self._make_layer( - block, 32, blocks=n_size, stride=2, reduction=reduction) - self.layer3 = self._make_layer( - block, 64, blocks=n_size, stride=2, reduction=reduction) - self.avgpool = nn.AdaptiveAvgPool2d(1) - self.fc = nn.Linear(64, num_classes) - self.initialize() - - def initialize(self): - for m in self.modules(): - if isinstance(m, nn.Conv2d): - nn.init.kaiming_normal_(m.weight) - elif isinstance(m, nn.BatchNorm2d): - nn.init.constant_(m.weight, 1) - nn.init.constant_(m.bias, 0) - - def _make_layer(self, block, planes, blocks, stride, reduction): - strides = [stride] + [1] * (blocks - 1) - layers = [] - for stride in strides: - layers.append(block(self.inplane, planes, stride, reduction)) - self.inplane = planes - - return nn.Sequential(*layers) - - def forward(self, x): - x = self.conv1(x) - x = self.bn1(x) - x = self.relu(x) - - x = self.layer1(x) - x = self.layer2(x) - x = self.layer3(x) - - x = self.avgpool(x) - x = x.view(x.size(0), -1) - x = self.fc(x) - - return x - - -class CifarSEPreActResNet(CifarSEResNet): - def __init__(self, block, n_size, num_classes=10, reduction=16): - super(CifarSEPreActResNet, self).__init__( - block, n_size, num_classes, reduction) - self.bn1 = nn.BatchNorm2d(self.inplane) - self.initialize() - - def forward(self, x): - x = self.conv1(x) - x = self.layer1(x) - x = self.layer2(x) - x = self.layer3(x) - - x = self.bn1(x) - x = self.relu(x) - - x = self.avgpool(x) - x = x.view(x.size(0), -1) - x = self.fc(x) - - -def se_resnet20(**kwargs): - """Constructs a ResNet-18 model. - """ - model = CifarSEResNet(CifarSEBasicBlock, 3, **kwargs) - return model - - -def se_resnet32(**kwargs): - """Constructs a ResNet-34 model. - """ - model = CifarSEResNet(CifarSEBasicBlock, 5, **kwargs) - return model - - -def se_resnet56(**kwargs): - """Constructs a ResNet-34 model. - """ - model = CifarSEResNet(CifarSEBasicBlock, 9, **kwargs) - return model - - -def se_preactresnet20(**kwargs): - """Constructs a ResNet-18 model. - """ - model = CifarSEPreActResNet(CifarSEBasicBlock, 3, **kwargs) - return model - - -def se_preactresnet32(**kwargs): - """Constructs a ResNet-34 model. - """ - model = CifarSEPreActResNet(CifarSEBasicBlock, 5, **kwargs) - return model - - -def se_preactresnet56(**kwargs): - """Constructs a ResNet-34 model. - """ - model = CifarSEPreActResNet(CifarSEBasicBlock, 9, **kwargs) +# -*- coding: utf-8 -*- +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch.nn as nn +from torch.hub import load_state_dict_from_url +from torchvision.models import ResNet +from se_module import SELayer + + +def conv3x3(in_planes, out_planes, stride=1): + return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, padding=1, bias=False) + + +class SEBasicBlock(nn.Module): + expansion = 1 + + def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1, + base_width=64, dilation=1, norm_layer=None, + *, reduction=16): + super(SEBasicBlock, self).__init__() + self.conv1 = conv3x3(inplanes, planes, stride) + self.bn1 = nn.BatchNorm2d(planes) + self.relu = nn.ReLU(inplace=True) + self.conv2 = conv3x3(planes, planes, 1) + self.bn2 = nn.BatchNorm2d(planes) + self.se = SELayer(planes, reduction) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.se(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class SEBottleneck(nn.Module): + expansion = 4 + + def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1, + base_width=64, dilation=1, norm_layer=None, + *, reduction=16): + super(SEBottleneck, self).__init__() + self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) + self.bn1 = nn.BatchNorm2d(planes) + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, + padding=1, bias=False) + self.bn2 = nn.BatchNorm2d(planes) + self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) + self.bn3 = nn.BatchNorm2d(planes * 4) + self.relu = nn.ReLU(inplace=True) + self.se = SELayer(planes * 4, reduction) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + out = self.se(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +def se_resnet18(num_classes=1_000): + """Constructs a ResNet-18 model. + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(SEBasicBlock, [2, 2, 2, 2], num_classes=num_classes) + model.avgpool = nn.AdaptiveAvgPool2d(1) + return model + + +def se_resnet34(num_classes=1_000): + """Constructs a ResNet-34 model. + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(SEBasicBlock, [3, 4, 6, 3], num_classes=num_classes) + model.avgpool = nn.AdaptiveAvgPool2d(1) + return model + + +def se_resnet50(num_classes=1_000, pretrained=False): + """Constructs a ResNet-50 model. + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(SEBottleneck, [3, 4, 6, 3], num_classes=num_classes) + model.avgpool = nn.AdaptiveAvgPool2d(1) + if pretrained: + model.load_state_dict(load_state_dict_from_url( + "https://github.com/moskomule/senet.pytorch/releases/download/archive/seresnet50-60a8950a85b2b.pkl")) + return model + + +def se_resnet101(num_classes=1_000): + """Constructs a ResNet-101 model. + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(SEBottleneck, [3, 4, 23, 3], num_classes=num_classes) + model.avgpool = nn.AdaptiveAvgPool2d(1) + return model + + +def se_resnet152(num_classes=1_000): + """Constructs a ResNet-152 model. + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(SEBottleneck, [3, 8, 36, 3], num_classes=num_classes) + model.avgpool = nn.AdaptiveAvgPool2d(1) + return model + + +class CifarSEBasicBlock(nn.Module): + def __init__(self, inplanes, planes, stride=1, reduction=16): + super(CifarSEBasicBlock, self).__init__() + self.conv1 = conv3x3(inplanes, planes, stride) + self.bn1 = nn.BatchNorm2d(planes) + self.relu = nn.ReLU(inplace=True) + self.conv2 = conv3x3(planes, planes) + self.bn2 = nn.BatchNorm2d(planes) + self.se = SELayer(planes, reduction) + if inplanes != planes: + self.downsample = nn.Sequential(nn.Conv2d(inplanes, planes, kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(planes)) + else: + self.downsample = lambda x: x + self.stride = stride + + def forward(self, x): + residual = self.downsample(x) + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.se(out) + + out += residual + out = self.relu(out) + + return out + + +class CifarSEResNet(nn.Module): + def __init__(self, block, n_size, num_classes=10, reduction=16): + super(CifarSEResNet, self).__init__() + self.inplane = 16 + self.conv1 = nn.Conv2d( + 3, self.inplane, kernel_size=3, stride=1, padding=1, bias=False) + self.bn1 = nn.BatchNorm2d(self.inplane) + self.relu = nn.ReLU(inplace=True) + self.layer1 = self._make_layer( + block, 16, blocks=n_size, stride=1, reduction=reduction) + self.layer2 = self._make_layer( + block, 32, blocks=n_size, stride=2, reduction=reduction) + self.layer3 = self._make_layer( + block, 64, blocks=n_size, stride=2, reduction=reduction) + self.avgpool = nn.AdaptiveAvgPool2d(1) + self.fc = nn.Linear(64, num_classes) + self.initialize() + + def initialize(self): + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight) + elif isinstance(m, nn.BatchNorm2d): + nn.init.constant_(m.weight, 1) + nn.init.constant_(m.bias, 0) + + def _make_layer(self, block, planes, blocks, stride, reduction): + strides = [stride] + [1] * (blocks - 1) + layers = [] + for stride in strides: + layers.append(block(self.inplane, planes, stride, reduction)) + self.inplane = planes + + return nn.Sequential(*layers) + + def forward(self, x): + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + + x = self.layer1(x) + x = self.layer2(x) + x = self.layer3(x) + + x = self.avgpool(x) + x = x.view(x.size(0), -1) + x = self.fc(x) + + return x + + +class CifarSEPreActResNet(CifarSEResNet): + def __init__(self, block, n_size, num_classes=10, reduction=16): + super(CifarSEPreActResNet, self).__init__( + block, n_size, num_classes, reduction) + self.bn1 = nn.BatchNorm2d(self.inplane) + self.initialize() + + def forward(self, x): + x = self.conv1(x) + x = self.layer1(x) + x = self.layer2(x) + x = self.layer3(x) + + x = self.bn1(x) + x = self.relu(x) + + x = self.avgpool(x) + x = x.view(x.size(0), -1) + x = self.fc(x) + + +def se_resnet20(**kwargs): + """Constructs a ResNet-18 model. + """ + model = CifarSEResNet(CifarSEBasicBlock, 3, **kwargs) + return model + + +def se_resnet32(**kwargs): + """Constructs a ResNet-34 model. + """ + model = CifarSEResNet(CifarSEBasicBlock, 5, **kwargs) + return model + + +def se_resnet56(**kwargs): + """Constructs a ResNet-34 model. + """ + model = CifarSEResNet(CifarSEBasicBlock, 9, **kwargs) + return model + + +def se_preactresnet20(**kwargs): + """Constructs a ResNet-18 model. + """ + model = CifarSEPreActResNet(CifarSEBasicBlock, 3, **kwargs) + return model + + +def se_preactresnet32(**kwargs): + """Constructs a ResNet-34 model. + """ + model = CifarSEPreActResNet(CifarSEBasicBlock, 5, **kwargs) + return model + + +def se_preactresnet56(**kwargs): + """Constructs a ResNet-34 model. + """ + model = CifarSEPreActResNet(CifarSEBasicBlock, 9, **kwargs) return model \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/SENet154/README.md b/PyTorch/contrib/cv/classification/SENet154/README.md old mode 100755 new mode 100644 index 3a719047ec..3b0c8b7ca8 --- a/PyTorch/contrib/cv/classification/SENet154/README.md +++ b/PyTorch/contrib/cv/classification/SENet154/README.md @@ -1,71 +1,71 @@ -# SENet154 - -This implements training of SENet154 on the ImageNet dataset. - -Code of SENet is mainly migrated and adjusted from [GitHub](https://github.com/Cadene/pretrained-models.pytorch#senet). - -## SENet154 Detail - -SENet involves group convolution, which may cause error on NPU platforms where group convolution is not well-supported. - -Label smoothing is required for qualified model accuracy. - -## Requirements -- pytorch_ascend, apex_ascend -- munch package, which can be installed via `pip install munch` -- Download the ImageNet dataset from http://www.image-net.org/ - - Then, and move validation images to labeled subfolders, using [the following shell script](https://raw.githubusercontent.com/soumith/imagenetloader.torch/master/valprep.sh) - -## Training - -### 单卡训练流程 -1. 安装环境 -2. 修改参数 - 1. `--data DIR`:ImageNet数据集的存储目录,训练集与验证集分别位于DIR/train和DIR/val - 1. `--log-file FILENAME`:自定义日志文件名 - 2. `--device DEVICE`:所使用的单卡训练设备,如cuda:0或npu:0 - 3. `--opt-level L`:apex混合精度优化等级,支持O2(默认)或O1 - 4. `--loss-scale S`:apex混合精度使用的loss scale,默认为128 - 5. `--scheduler`:训练使用的学习率调整器,支持`step`(对应StepLR)和`cosine`(对应CosineAnnealingLR) -3. 开始训练 - ``` - bash ./test/train_full_1p.sh --data_path=数据集路径 # 精度训练 - bash ./test/train_performance_1p.sh --data_path=数据集路径 # 性能训练 - ``` - -### 多卡训练流程 -1. 安装环境 -2. 修改参数 - 1. `--device DEVICE`:所使用的多卡训练设备类别,支持cuda和npu - 2. `--distributed`:开启分布式训练模式 - 3. `--num-devices N`:参与训练的设备个数,设备ID依次为DEVICE:0 ... DEVICE:(N-1) - 4. `--batch-size N`:分配个每个设备的batch大小 -3. 开始训练 - ``` - bash ./test/train_full_1p.sh --data_path=数据集路径 # 精度训练 - bash ./test/train_performance_1p.sh --data_path=数据集路径 # 性能训练 - ``` - -### 训练结果 -日志保存在 ./test/output/device-id 路径下 - -最终训练模型输出至./model.pth,训练过程中生成的存档点位于./models文件夹下 - -Profile结果输出至./output.prof - -## SENet154 Training Result -$E$为当前一轮的Epoch序号,从0开始 - -### GPU 8p -|Epochs|Learning rate |Optimization type|FPS |Acc@1 |Acc@5 | -|:----:|:------------------------------------:|:---------------:|:-----:|:----:|:----:| -|120 |$0.6\times 0.1^{\lfloor E/30 \rfloor}$|O2 |955.433|79.130|94.058| -|120 |$1\times 0.45^{\lfloor E/10 \rfloor}$ |O2 |954.725|78.341|93.945| -|120 |$0.6\times 0.93^{E}$ |O2 |949.309|78.100|94.010| -|120 |$0.3\times (1+\cos{\frac{E\pi}{120}})$|O2 |951.374|80.161|94.879| - -### NPU 8p -|Epochs|Learning rate |Optimization type|FPS |Acc@1 |Acc@5 | -|:----:|:------------------------------------:|:---------------:|:------:|:----:|:----:| -|120 |$0.6\times 0.1^{\lfloor E/30 \rfloor}$|O2 |1524.537|78.599|93.849| +# SENet154 + +This implements training of SENet154 on the ImageNet dataset. + +Code of SENet is mainly migrated and adjusted from [GitHub](https://github.com/Cadene/pretrained-models.pytorch#senet). + +## SENet154 Detail + +SENet involves group convolution, which may cause error on NPU platforms where group convolution is not well-supported. + +Label smoothing is required for qualified model accuracy. + +## Requirements +- pytorch_ascend, apex_ascend +- munch package, which can be installed via `pip install munch` +- Download the ImageNet dataset from http://www.image-net.org/ + - Then, and move validation images to labeled subfolders, using [the following shell script](https://raw.githubusercontent.com/soumith/imagenetloader.torch/master/valprep.sh) + +## Training + +### 单卡训练流程 +1. 安装环境 +2. 修改参数 + 1. `--data DIR`:ImageNet数据集的存储目录,训练集与验证集分别位于DIR/train和DIR/val + 1. `--log-file FILENAME`:自定义日志文件名 + 2. `--device DEVICE`:所使用的单卡训练设备,如cuda:0或npu:0 + 3. `--opt-level L`:apex混合精度优化等级,支持O2(默认)或O1 + 4. `--loss-scale S`:apex混合精度使用的loss scale,默认为128 + 5. `--scheduler`:训练使用的学习率调整器,支持`step`(对应StepLR)和`cosine`(对应CosineAnnealingLR) +3. 开始训练 + ``` + bash ./test/train_full_1p.sh --data_path=数据集路径 # 精度训练 + bash ./test/train_performance_1p.sh --data_path=数据集路径 # 性能训练 + ``` + +### 多卡训练流程 +1. 安装环境 +2. 修改参数 + 1. `--device DEVICE`:所使用的多卡训练设备类别,支持cuda和npu + 2. `--distributed`:开启分布式训练模式 + 3. `--num-devices N`:参与训练的设备个数,设备ID依次为DEVICE:0 ... DEVICE:(N-1) + 4. `--batch-size N`:分配个每个设备的batch大小 +3. 开始训练 + ``` + bash ./test/train_full_1p.sh --data_path=数据集路径 # 精度训练 + bash ./test/train_performance_1p.sh --data_path=数据集路径 # 性能训练 + ``` + +### 训练结果 +日志保存在 ./test/output/device-id 路径下 + +最终训练模型输出至./model.pth,训练过程中生成的存档点位于./models文件夹下 + +Profile结果输出至./output.prof + +## SENet154 Training Result +$E$为当前一轮的Epoch序号,从0开始 + +### GPU 8p +|Epochs|Learning rate |Optimization type|FPS |Acc@1 |Acc@5 | +|:----:|:------------------------------------:|:---------------:|:-----:|:----:|:----:| +|120 |$0.6\times 0.1^{\lfloor E/30 \rfloor}$|O2 |955.433|79.130|94.058| +|120 |$1\times 0.45^{\lfloor E/10 \rfloor}$ |O2 |954.725|78.341|93.945| +|120 |$0.6\times 0.93^{E}$ |O2 |949.309|78.100|94.010| +|120 |$0.3\times (1+\cos{\frac{E\pi}{120}})$|O2 |951.374|80.161|94.879| + +### NPU 8p +|Epochs|Learning rate |Optimization type|FPS |Acc@1 |Acc@5 | +|:----:|:------------------------------------:|:---------------:|:------:|:----:|:----:| +|120 |$0.6\times 0.1^{\lfloor E/30 \rfloor}$|O2 |1524.537|78.599|93.849| |120 |$0.3\times (1+\cos{\frac{E\pi}{120}})$|O2 |1522.120|80.048|94.799| \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/SENet154/checkpoint.py b/PyTorch/contrib/cv/classification/SENet154/checkpoint.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SENet154/data.py b/PyTorch/contrib/cv/classification/SENet154/data.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SENet154/demo.py b/PyTorch/contrib/cv/classification/SENet154/demo.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SENet154/lsr.py b/PyTorch/contrib/cv/classification/SENet154/lsr.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SENet154/modelzoo_level.txt b/PyTorch/contrib/cv/classification/SENet154/modelzoo_level.txt old mode 100755 new mode 100644 index 0b49b4fb26..31529da2e6 --- a/PyTorch/contrib/cv/classification/SENet154/modelzoo_level.txt +++ b/PyTorch/contrib/cv/classification/SENet154/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/SENet154/pth2onnx.py b/PyTorch/contrib/cv/classification/SENet154/pth2onnx.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SENet154/senet.py b/PyTorch/contrib/cv/classification/SENet154/senet.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SENet154/test/env_npu.sh b/PyTorch/contrib/cv/classification/SENet154/test/env_npu.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SENet154/test/run_2onnx.sh b/PyTorch/contrib/cv/classification/SENet154/test/run_2onnx.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SENet154/test/run_demo.sh b/PyTorch/contrib/cv/classification/SENet154/test/run_demo.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SENet154/test/train_eval_8p.sh b/PyTorch/contrib/cv/classification/SENet154/test/train_eval_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SENet154/test/train_full_1p.sh b/PyTorch/contrib/cv/classification/SENet154/test/train_full_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SENet154/test/train_full_8p.sh b/PyTorch/contrib/cv/classification/SENet154/test/train_full_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SENet154/test/train_performance_1p.sh b/PyTorch/contrib/cv/classification/SENet154/test/train_performance_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SENet154/test/train_performance_8p.sh b/PyTorch/contrib/cv/classification/SENet154/test/train_performance_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SENet154/train.py b/PyTorch/contrib/cv/classification/SENet154/train.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SENet154/utils.py b/PyTorch/contrib/cv/classification/SENet154/utils.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/Dockerfile b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/Dockerfile old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/LICENSE b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/LICENSE old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/README.md b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/README.md old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/demo.py b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/demo.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/docker_start.sh b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/docker_start.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/main.py b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/main.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/modelzoo_level.txt b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/modelzoo_level.txt old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/pthtar2onnx.py b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/pthtar2onnx.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/requirements.txt b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/requirements.txt old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/scripts/eval.sh b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/scripts/eval.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/scripts/npu_set_env.sh b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/scripts/npu_set_env.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/scripts/train_1p.sh b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/scripts/train_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/scripts/train_8p.sh b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/scripts/train_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/senet.py b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/senet.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/test/env_npu.sh b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/test/env_npu.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/test/train_eval_8p.sh b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/test/train_eval_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/test/train_full_1p.sh b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/test/train_full_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/test/train_full_8p.sh b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/test/train_full_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/test/train_performance_1p.sh b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/test/train_performance_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/test/train_performance_8p.sh b/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d/test/train_performance_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/ShuffleNetV1_ID1625_for_PyTorch/Dockerfile b/PyTorch/contrib/cv/classification/ShuffleNetV1_ID1625_for_PyTorch/Dockerfile index 7e712fe1a1..30a31af558 100644 --- a/PyTorch/contrib/cv/classification/ShuffleNetV1_ID1625_for_PyTorch/Dockerfile +++ b/PyTorch/contrib/cv/classification/ShuffleNetV1_ID1625_for_PyTorch/Dockerfile @@ -1,5 +1,5 @@ -ARG FROM_IMAGE_NAME -FROM $FROM_IMAGE_NAME - -COPY requirements.txt . +ARG FROM_IMAGE_NAME +FROM $FROM_IMAGE_NAME + +COPY requirements.txt . RUN pip3.7 install -r requirements.txt \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/ShuffleNetV1_ID1625_for_PyTorch/docker_start.sh b/PyTorch/contrib/cv/classification/ShuffleNetV1_ID1625_for_PyTorch/docker_start.sh index 46ce9a02ec..944bca3cda 100644 --- a/PyTorch/contrib/cv/classification/ShuffleNetV1_ID1625_for_PyTorch/docker_start.sh +++ b/PyTorch/contrib/cv/classification/ShuffleNetV1_ID1625_for_PyTorch/docker_start.sh @@ -1,25 +1,25 @@ -#!/bin/bash - -docker_image=$1 -data_dir=$2 -model_dir=$3 - -docker run -it --ipc=host \ - --device=/dev/davinci0 \ - --device=/dev/davinci1 \ - --device=/dev/davinci2 \ - --device=/dev/davinci3 \ - --device=/dev/davinci4 \ - --device=/dev/davinci5 \ - --device=/dev/davinci6 \ - --device=/dev/davinci7 \ - --device=/dev/davinci_manager \ - --device=/dev/devmm_svm --device=/dev/hisi_hdc \ - -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ - -v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \ - -v ${model_dir}:${model_dir} \ - -v ${data_dir}:${data_dir} \ - -v /var/log/npu/conf/slog/slog.conf:/var/log/npu/conf/slog/slog.conf \ - -v /var/log/npu/slog/:/var/log/npu/slog -v /var/log/npu/profiling/:/var/log/npu/profiling \ - -v /var/log/npu/dump/:/var/log/npu/dump -v /var/log/npu/:/usr/slog ${docker_image} \ +#!/bin/bash + +docker_image=$1 +data_dir=$2 +model_dir=$3 + +docker run -it --ipc=host \ + --device=/dev/davinci0 \ + --device=/dev/davinci1 \ + --device=/dev/davinci2 \ + --device=/dev/davinci3 \ + --device=/dev/davinci4 \ + --device=/dev/davinci5 \ + --device=/dev/davinci6 \ + --device=/dev/davinci7 \ + --device=/dev/davinci_manager \ + --device=/dev/devmm_svm --device=/dev/hisi_hdc \ + -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ + -v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \ + -v ${model_dir}:${model_dir} \ + -v ${data_dir}:${data_dir} \ + -v /var/log/npu/conf/slog/slog.conf:/var/log/npu/conf/slog/slog.conf \ + -v /var/log/npu/slog/:/var/log/npu/slog -v /var/log/npu/profiling/:/var/log/npu/profiling \ + -v /var/log/npu/dump/:/var/log/npu/dump -v /var/log/npu/:/usr/slog ${docker_image} \ /bin/bash \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/ShuffleNetV1_ID1625_for_PyTorch/modelzoo_level.txt b/PyTorch/contrib/cv/classification/ShuffleNetV1_ID1625_for_PyTorch/modelzoo_level.txt index 5afcef9188..3117fffc3b 100644 --- a/PyTorch/contrib/cv/classification/ShuffleNetV1_ID1625_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/contrib/cv/classification/ShuffleNetV1_ID1625_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:NOK +FuncStatus:OK +PerfStatus:NOK PrecisionStatus:POK \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/ShuffleNetV2Plus_ID1626_for_PyTorch/README.md b/PyTorch/contrib/cv/classification/ShuffleNetV2Plus_ID1626_for_PyTorch/README.md index 8e6c6f3a86..f9b639886e 100644 --- a/PyTorch/contrib/cv/classification/ShuffleNetV2Plus_ID1626_for_PyTorch/README.md +++ b/PyTorch/contrib/cv/classification/ShuffleNetV2Plus_ID1626_for_PyTorch/README.md @@ -1,56 +1,56 @@ -# ShuffleNetV2Plus (size=Small) - -## ImageNet training with PyTorch - -This implements training of ShuffleNetV1 on the ImageNet dataset, mainly modified from [Github](https://github.com/pytorch/examples/tree/master/imagenet). - -## ShuffleNetV2Plus Detail - -Base version of the model from [the paper author's code on Github](https://github.com/megvii-model/ShuffleNet-Series/tree/master/ShuffleNetV2%2B). -The training script is adapted from [the ShuffleNetV2 script on Gitee](https://gitee.com/ascend/modelzoo/tree/master/built-in/PyTorch/Official/cv/image_classification/Shufflenetv2_for_PyTorch). - -## Requirements - -- pytorch_ascend, apex_ascend, tochvision -- Download the ImageNet dataset from http://www.image-net.org/ - - Then, and move validation images to labeled subfolders, using [the following shell script](https://raw.githubusercontent.com/soumith/imagenetloader.torch/master/valprep.sh). - -## Training -一、训练流程: - -单卡训练流程: - - 1.安装环境 - 2.修改参数device_id(单卡训练所使用的device id),为训练配置device_id,比如device_id=0 - 3.开始训练 - bash ./test/train_full_1p.sh --data_path=数据集路径 # 精度训练 - bash ./test/train_performance_1p.sh --data_path=数据集路径 # 性能训练 - - -多卡训练流程 - - 1.安装环境 - 2.修改参数device_id_list(多卡训练所使用的device id列表),为训练配置device_id,例如device_id=0,1,2,3,4,5,6,7 - 3.执行train_full_8p.sh开始训练 - bash ./test/train_full_8p.sh --data_path=数据集路径 # 精度训练 - bash ./test/train_performance_8p.sh --data_path=数据集路径 # 性能训练 - -二、测试结果 - -训练日志路径:网络脚本test下output文件夹内。例如: - - test/output/devie_id/train_${device_id}.log # 训练脚本原生日志 - test/output/devie_id/ShuffleNetV1_bs8192_8p_perf.log # 8p性能训练结果日志 - test/output/devie_id/ShuffleNetV1_bs8192_8p_acc.log # 8p精度训练结果日志 - -训练模型:训练生成的模型默认会写入到和test文件同一目录下。当训练正常结束时,checkpoint.pth.tar为最终结果。 - - - -## ShufflenetV2Plus training result - -| Acc@1 | FPS | Npu_nums| Epochs | Type | -| :------: | :------: | :------ | :------: | :------: | -| 73.132 | 6306 | 8 | 360 | O2 | - +# ShuffleNetV2Plus (size=Small) + +## ImageNet training with PyTorch + +This implements training of ShuffleNetV1 on the ImageNet dataset, mainly modified from [Github](https://github.com/pytorch/examples/tree/master/imagenet). + +## ShuffleNetV2Plus Detail + +Base version of the model from [the paper author's code on Github](https://github.com/megvii-model/ShuffleNet-Series/tree/master/ShuffleNetV2%2B). +The training script is adapted from [the ShuffleNetV2 script on Gitee](https://gitee.com/ascend/modelzoo/tree/master/built-in/PyTorch/Official/cv/image_classification/Shufflenetv2_for_PyTorch). + +## Requirements + +- pytorch_ascend, apex_ascend, tochvision +- Download the ImageNet dataset from http://www.image-net.org/ + - Then, and move validation images to labeled subfolders, using [the following shell script](https://raw.githubusercontent.com/soumith/imagenetloader.torch/master/valprep.sh). + +## Training +一、训练流程: + +单卡训练流程: + + 1.安装环境 + 2.修改参数device_id(单卡训练所使用的device id),为训练配置device_id,比如device_id=0 + 3.开始训练 + bash ./test/train_full_1p.sh --data_path=数据集路径 # 精度训练 + bash ./test/train_performance_1p.sh --data_path=数据集路径 # 性能训练 + + +多卡训练流程 + + 1.安装环境 + 2.修改参数device_id_list(多卡训练所使用的device id列表),为训练配置device_id,例如device_id=0,1,2,3,4,5,6,7 + 3.执行train_full_8p.sh开始训练 + bash ./test/train_full_8p.sh --data_path=数据集路径 # 精度训练 + bash ./test/train_performance_8p.sh --data_path=数据集路径 # 性能训练 + +二、测试结果 + +训练日志路径:网络脚本test下output文件夹内。例如: + + test/output/devie_id/train_${device_id}.log # 训练脚本原生日志 + test/output/devie_id/ShuffleNetV1_bs8192_8p_perf.log # 8p性能训练结果日志 + test/output/devie_id/ShuffleNetV1_bs8192_8p_acc.log # 8p精度训练结果日志 + +训练模型:训练生成的模型默认会写入到和test文件同一目录下。当训练正常结束时,checkpoint.pth.tar为最终结果。 + + + +## ShufflenetV2Plus training result + +| Acc@1 | FPS | Npu_nums| Epochs | Type | +| :------: | :------: | :------ | :------: | :------: | +| 73.132 | 6306 | 8 | 360 | O2 | + 备注:由于模型开发中发现NPU上clamp算子反向错误,以上结果为使用自行编写的clamp函数训练获得。见blocks.py中的注释掉的函数clamp。 \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/ShuffleNetV2Plus_ID1626_for_PyTorch/blocks.py b/PyTorch/contrib/cv/classification/ShuffleNetV2Plus_ID1626_for_PyTorch/blocks.py index 5619d2624d..044cd05d70 100644 --- a/PyTorch/contrib/cv/classification/ShuffleNetV2Plus_ID1626_for_PyTorch/blocks.py +++ b/PyTorch/contrib/cv/classification/ShuffleNetV2Plus_ID1626_for_PyTorch/blocks.py @@ -1,249 +1,249 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ - - -import torch -import torch.nn as nn - -try: - from .channel_shuffle import ChannelShuffle -except: - from channel_shuffle import ChannelShuffle - -''' -def clamp(x, low=0, high=6): - low_mask = x < low - high_mask = x > high - keep_mask = ~(low_mask|high_mask) - out = x * keep_mask.to(x) + high * high_mask.to(x) + low * low_mask.to(x) - return out -''' - -class SELayer(nn.Module): - - def __init__(self, inplanes, isTensor=True): - super(SELayer, self).__init__() - if isTensor: - # if the input is (N, C, H, W) - self.SE_opr = nn.Sequential( - nn.AdaptiveAvgPool2d(1), - nn.Conv2d(inplanes, inplanes // 4, kernel_size=1, stride=1, bias=False), - nn.BatchNorm2d(inplanes // 4), - nn.ReLU(inplace=True), - nn.Conv2d(inplanes // 4, inplanes, kernel_size=1, stride=1, bias=False), - ) - else: - # if the input is (N, C) - self.SE_opr = nn.Sequential( - nn.AdaptiveAvgPool2d(1), - nn.Linear(inplanes, inplanes // 4, bias=False), - nn.BatchNorm1d(inplanes // 4), - nn.ReLU(inplace=True), - nn.Linear(inplanes // 4, inplanes, bias=False), - ) - - def forward(self, x): - atten = self.SE_opr(x) - #atten = clamp(atten + 3.0, 0.0, 6.0) / 6.0 - atten = torch.clamp(atten + 3, 0, 6) / 6 - return x * atten - - -class HS(nn.Module): - - def __init__(self): - super(HS, self).__init__() - - def forward(self, inputs): - clip = torch.clamp(inputs + 3, 0, 6) / 6 - #clip = clamp(inputs + 3.0, 0.0, 6.0) / 6.0 - return inputs * clip - - - -class Shufflenet(nn.Module): - - def __init__(self, inp, oup, base_mid_channels, *, ksize, stride, activation, useSE): - super(Shufflenet, self).__init__() - self.stride = stride - assert stride in [1, 2] - assert ksize in [3, 5, 7] - assert base_mid_channels == oup//2 - - self.base_mid_channel = base_mid_channels - self.ksize = ksize - pad = ksize // 2 - self.pad = pad - self.inp = inp - - outputs = oup - inp - - branch_main = [ - # pw - nn.Conv2d(inp, base_mid_channels, 1, 1, 0, bias=False), - nn.BatchNorm2d(base_mid_channels), - None, - # dw - nn.Conv2d(base_mid_channels, base_mid_channels, ksize, stride, pad, groups=base_mid_channels, bias=False), - nn.BatchNorm2d(base_mid_channels), - # pw-linear - nn.Conv2d(base_mid_channels, outputs, 1, 1, 0, bias=False), - nn.BatchNorm2d(outputs), - None, - ] - if activation == 'ReLU': - assert useSE == False - '''This model should not have SE with ReLU''' - branch_main[2] = nn.ReLU(inplace=True) - branch_main[-1] = nn.ReLU(inplace=True) - else: - branch_main[2] = HS() - branch_main[-1] = HS() - if useSE: - branch_main.append(SELayer(outputs)) - self.branch_main = nn.Sequential(*branch_main) - - if stride == 2: - branch_proj = [ - # dw - nn.Conv2d(inp, inp, ksize, stride, pad, groups=inp, bias=False), - nn.BatchNorm2d(inp), - # pw-linear - nn.Conv2d(inp, inp, 1, 1, 0, bias=False), - nn.BatchNorm2d(inp), - None, - ] - if activation == 'ReLU': - branch_proj[-1] = nn.ReLU(inplace=True) - else: - branch_proj[-1] = HS() - self.branch_proj = nn.Sequential(*branch_proj) - else: - self.branch_proj = None - - self.channel_shuffle = ChannelShuffle(inp*2) - - def forward(self, old_x): - if self.stride==1: - x_proj, x = self.channel_shuffle(old_x) - return torch.cat((x_proj, self.branch_main(x)), 1) - elif self.stride==2: - x_proj = old_x - x = old_x - - x1 = self.branch_proj(x_proj) - x2 = self.branch_main(x) - - return torch.cat((x1, x2), 1) - -class Shuffle_Xception(nn.Module): - - def __init__(self, inp, oup, base_mid_channels, *, stride, activation, useSE): - super(Shuffle_Xception, self).__init__() - - assert stride in [1, 2] - assert base_mid_channels == oup//2 - - self.base_mid_channel = base_mid_channels - self.stride = stride - self.ksize = 3 - self.pad = 1 - self.inp = inp - outputs = oup - inp - - branch_main = [ - # dw - nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False), - nn.BatchNorm2d(inp), - # pw - nn.Conv2d(inp, base_mid_channels, 1, 1, 0, bias=False), - nn.BatchNorm2d(base_mid_channels), - None, - # dw - nn.Conv2d(base_mid_channels, base_mid_channels, 3, stride, 1, groups=base_mid_channels, bias=False), - nn.BatchNorm2d(base_mid_channels), - # pw - nn.Conv2d(base_mid_channels, base_mid_channels, 1, 1, 0, bias=False), - nn.BatchNorm2d(base_mid_channels), - None, - # dw - nn.Conv2d(base_mid_channels, base_mid_channels, 3, stride, 1, groups=base_mid_channels, bias=False), - nn.BatchNorm2d(base_mid_channels), - # pw - nn.Conv2d(base_mid_channels, outputs, 1, 1, 0, bias=False), - nn.BatchNorm2d(outputs), - None, - ] - - if activation == 'ReLU': - branch_main[4] = nn.ReLU(inplace=True) - branch_main[9] = nn.ReLU(inplace=True) - branch_main[14] = nn.ReLU(inplace=True) - else: - branch_main[4] = HS() - branch_main[9] = HS() - branch_main[14] = HS() - assert None not in branch_main - - if useSE: - assert activation != 'ReLU' - branch_main.append(SELayer(outputs)) - - self.branch_main = nn.Sequential(*branch_main) - - if self.stride == 2: - branch_proj = [ - # dw - nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False), - nn.BatchNorm2d(inp), - # pw-linear - nn.Conv2d(inp, inp, 1, 1, 0, bias=False), - nn.BatchNorm2d(inp), - None, - ] - if activation == 'ReLU': - branch_proj[-1] = nn.ReLU(inplace=True) - else: - branch_proj[-1] = HS() - self.branch_proj = nn.Sequential(*branch_proj) - - self.channel_shuffle = ChannelShuffle(inp*2) - - def forward(self, old_x): - if self.stride==1: - x_proj, x = self.channel_shuffle(old_x) - return torch.cat((x_proj, self.branch_main(x)), 1) - elif self.stride==2: - x_proj = old_x - x = old_x - return torch.cat((self.branch_proj(x_proj), self.branch_main(x)), 1) - +# BSD 3-Clause License +# +# Copyright (c) 2017 +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ + + +import torch +import torch.nn as nn + +try: + from .channel_shuffle import ChannelShuffle +except: + from channel_shuffle import ChannelShuffle + +''' +def clamp(x, low=0, high=6): + low_mask = x < low + high_mask = x > high + keep_mask = ~(low_mask|high_mask) + out = x * keep_mask.to(x) + high * high_mask.to(x) + low * low_mask.to(x) + return out +''' + +class SELayer(nn.Module): + + def __init__(self, inplanes, isTensor=True): + super(SELayer, self).__init__() + if isTensor: + # if the input is (N, C, H, W) + self.SE_opr = nn.Sequential( + nn.AdaptiveAvgPool2d(1), + nn.Conv2d(inplanes, inplanes // 4, kernel_size=1, stride=1, bias=False), + nn.BatchNorm2d(inplanes // 4), + nn.ReLU(inplace=True), + nn.Conv2d(inplanes // 4, inplanes, kernel_size=1, stride=1, bias=False), + ) + else: + # if the input is (N, C) + self.SE_opr = nn.Sequential( + nn.AdaptiveAvgPool2d(1), + nn.Linear(inplanes, inplanes // 4, bias=False), + nn.BatchNorm1d(inplanes // 4), + nn.ReLU(inplace=True), + nn.Linear(inplanes // 4, inplanes, bias=False), + ) + + def forward(self, x): + atten = self.SE_opr(x) + #atten = clamp(atten + 3.0, 0.0, 6.0) / 6.0 + atten = torch.clamp(atten + 3, 0, 6) / 6 + return x * atten + + +class HS(nn.Module): + + def __init__(self): + super(HS, self).__init__() + + def forward(self, inputs): + clip = torch.clamp(inputs + 3, 0, 6) / 6 + #clip = clamp(inputs + 3.0, 0.0, 6.0) / 6.0 + return inputs * clip + + + +class Shufflenet(nn.Module): + + def __init__(self, inp, oup, base_mid_channels, *, ksize, stride, activation, useSE): + super(Shufflenet, self).__init__() + self.stride = stride + assert stride in [1, 2] + assert ksize in [3, 5, 7] + assert base_mid_channels == oup//2 + + self.base_mid_channel = base_mid_channels + self.ksize = ksize + pad = ksize // 2 + self.pad = pad + self.inp = inp + + outputs = oup - inp + + branch_main = [ + # pw + nn.Conv2d(inp, base_mid_channels, 1, 1, 0, bias=False), + nn.BatchNorm2d(base_mid_channels), + None, + # dw + nn.Conv2d(base_mid_channels, base_mid_channels, ksize, stride, pad, groups=base_mid_channels, bias=False), + nn.BatchNorm2d(base_mid_channels), + # pw-linear + nn.Conv2d(base_mid_channels, outputs, 1, 1, 0, bias=False), + nn.BatchNorm2d(outputs), + None, + ] + if activation == 'ReLU': + assert useSE == False + '''This model should not have SE with ReLU''' + branch_main[2] = nn.ReLU(inplace=True) + branch_main[-1] = nn.ReLU(inplace=True) + else: + branch_main[2] = HS() + branch_main[-1] = HS() + if useSE: + branch_main.append(SELayer(outputs)) + self.branch_main = nn.Sequential(*branch_main) + + if stride == 2: + branch_proj = [ + # dw + nn.Conv2d(inp, inp, ksize, stride, pad, groups=inp, bias=False), + nn.BatchNorm2d(inp), + # pw-linear + nn.Conv2d(inp, inp, 1, 1, 0, bias=False), + nn.BatchNorm2d(inp), + None, + ] + if activation == 'ReLU': + branch_proj[-1] = nn.ReLU(inplace=True) + else: + branch_proj[-1] = HS() + self.branch_proj = nn.Sequential(*branch_proj) + else: + self.branch_proj = None + + self.channel_shuffle = ChannelShuffle(inp*2) + + def forward(self, old_x): + if self.stride==1: + x_proj, x = self.channel_shuffle(old_x) + return torch.cat((x_proj, self.branch_main(x)), 1) + elif self.stride==2: + x_proj = old_x + x = old_x + + x1 = self.branch_proj(x_proj) + x2 = self.branch_main(x) + + return torch.cat((x1, x2), 1) + +class Shuffle_Xception(nn.Module): + + def __init__(self, inp, oup, base_mid_channels, *, stride, activation, useSE): + super(Shuffle_Xception, self).__init__() + + assert stride in [1, 2] + assert base_mid_channels == oup//2 + + self.base_mid_channel = base_mid_channels + self.stride = stride + self.ksize = 3 + self.pad = 1 + self.inp = inp + outputs = oup - inp + + branch_main = [ + # dw + nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False), + nn.BatchNorm2d(inp), + # pw + nn.Conv2d(inp, base_mid_channels, 1, 1, 0, bias=False), + nn.BatchNorm2d(base_mid_channels), + None, + # dw + nn.Conv2d(base_mid_channels, base_mid_channels, 3, stride, 1, groups=base_mid_channels, bias=False), + nn.BatchNorm2d(base_mid_channels), + # pw + nn.Conv2d(base_mid_channels, base_mid_channels, 1, 1, 0, bias=False), + nn.BatchNorm2d(base_mid_channels), + None, + # dw + nn.Conv2d(base_mid_channels, base_mid_channels, 3, stride, 1, groups=base_mid_channels, bias=False), + nn.BatchNorm2d(base_mid_channels), + # pw + nn.Conv2d(base_mid_channels, outputs, 1, 1, 0, bias=False), + nn.BatchNorm2d(outputs), + None, + ] + + if activation == 'ReLU': + branch_main[4] = nn.ReLU(inplace=True) + branch_main[9] = nn.ReLU(inplace=True) + branch_main[14] = nn.ReLU(inplace=True) + else: + branch_main[4] = HS() + branch_main[9] = HS() + branch_main[14] = HS() + assert None not in branch_main + + if useSE: + assert activation != 'ReLU' + branch_main.append(SELayer(outputs)) + + self.branch_main = nn.Sequential(*branch_main) + + if self.stride == 2: + branch_proj = [ + # dw + nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False), + nn.BatchNorm2d(inp), + # pw-linear + nn.Conv2d(inp, inp, 1, 1, 0, bias=False), + nn.BatchNorm2d(inp), + None, + ] + if activation == 'ReLU': + branch_proj[-1] = nn.ReLU(inplace=True) + else: + branch_proj[-1] = HS() + self.branch_proj = nn.Sequential(*branch_proj) + + self.channel_shuffle = ChannelShuffle(inp*2) + + def forward(self, old_x): + if self.stride==1: + x_proj, x = self.channel_shuffle(old_x) + return torch.cat((x_proj, self.branch_main(x)), 1) + elif self.stride==2: + x_proj = old_x + x = old_x + return torch.cat((self.branch_proj(x_proj), self.branch_main(x)), 1) + diff --git a/PyTorch/contrib/cv/classification/ShuffleNetV2Plus_ID1626_for_PyTorch/channel_shuffle.py b/PyTorch/contrib/cv/classification/ShuffleNetV2Plus_ID1626_for_PyTorch/channel_shuffle.py index bda735f26f..69d46a643a 100644 --- a/PyTorch/contrib/cv/classification/ShuffleNetV2Plus_ID1626_for_PyTorch/channel_shuffle.py +++ b/PyTorch/contrib/cv/classification/ShuffleNetV2Plus_ID1626_for_PyTorch/channel_shuffle.py @@ -1,156 +1,156 @@ -# Copyright (c) 2020, Huawei Technologies.All rights reserved. -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 numpy as np -import torch -import torch.nn as nn - - -class ChannelShuffle(nn.Module): - r"""Applies an NPU compatible channel shuffle operation. - - The origin implement is https://github.com/pytorch/vision/blob/master/torchvision/models/shufflenetv2.py#L21 - - In order to avoid contiguous operation which is not efficient on npu, we replaced the original operation - with a rewrite of the same semantics. Two discontinuous operations are replaced, transpose and chunk. - - .. note:: - Only group=2 is implemented, modify other group scenarios yourself. - - Args: - in_channels (int): The total number of channels in the input tensors - groups (int): The number of shuffle groups. Default: 2 - split_shuffle (bool): Whether to execute the chunk after shuffle. Default: True - - Shape: - - Input: :math:`(N, C_{in}, L_{in})`, `(N, C_{in}, L_{in})` - - Output: :math:`(N, C_{out}, L_{out})` - - Examples:: - >>> x1 = torch.randn(2,32,7,7) - >>> x2 = torch.randn(2,32,7,7) - >>> m = ChannelShuffle(64, split_shuffle=True) - >>> output = m(x1, x2) - - """ - - def __init__(self, in_channels, groups=2): - super(ChannelShuffle, self).__init__() - self.group_len = in_channels // groups - - # init out_channels - self.out_channels = np.array(list(range(in_channels))).reshape(groups, self.group_len).transpose(1, 0).flatten() - self.out_channels = torch.from_numpy(self.out_channels).long() - - # init index used in fp & bp - # Only group=2 is implemented, modify other group scenarios yourself. - self.fp_index1 = self.out_channels[:self.group_len] - self.fp_index2 = self.out_channels[self.group_len:] - self.bp_index = torch.tensor(list(range(0, in_channels, 2)) + list(range(1, in_channels, 2))) - - self.checked = False - - def check_self(self, x): - r"""Check device equipment between tensors. - """ - if self.bp_index.device == x.device: - self.checked = True - return - - device = x.device - if str(device).startswith('npu'): - self.fp_index1 = self.fp_index1.int() - self.fp_index2 = self.fp_index2.int() - self.bp_index = self.bp_index.int() - - self.fp_index1 = self.fp_index1.to(device) - self.fp_index2 = self.fp_index2.to(device) - self.bp_index = self.bp_index.to(device) - - - def forward(self, x): - if not self.checked: - self.check_self(x) - if self.training: - return IndexSelectHalfImplementation.apply(x, self.fp_index1, self.fp_index2, self.bp_index) - else: - return IndexSelectHalfImplementationForward(x, self.fp_index1, self.fp_index2, self.bp_index) - -def IndexSelectHalfImplementationForward(x, fp_index1, fp_index2, bp_index): - return x.index_select(1, fp_index1), x.index_select(1, fp_index2) - -class IndexSelectHalfImplementation(torch.autograd.Function): - @staticmethod - def forward(ctx, x, fp_index1, fp_index2, bp_index): - ctx.bp_index = bp_index - return x.index_select(1, fp_index1), x.index_select(1, fp_index2) - - @staticmethod - def backward(ctx, grad_output1, grad_output2): - grad_output = torch.cat([grad_output1, grad_output2], 1) - out = grad_output.index_select(1, ctx.bp_index) - return out, None, None, None, None - -def channel_shuffle_torchvision(x, groups=2): - # type: (torch.Tensor, int) -> torch.Tensor - batchsize, num_channels, height, width = x.data.size() - channels_per_group = num_channels // groups - - # reshape - x = x.view(batchsize, groups, - channels_per_group, height, width) - - x = torch.transpose(x, 1, 2).contiguous() - - # flatten - x = x.view(batchsize, -1, height, width) - - return x.chunk(2, 1) - -def channel_shuffle_megvii(x): - batchsize, num_channels, height, width = x.data.size() - assert (num_channels % 4 == 0) - x = x.reshape(batchsize * num_channels // 2, 2, height * width) - x = x.permute(1, 0, 2) - x = x.reshape(2, -1, num_channels // 2, height, width) - return x[0], x[1] - -if __name__ == '__main__': - device = 'cpu' - - if device.startswith('npu'): - torch.npu.set_device(device) - - channels = 8 - BZ = 2 - H = 1 - W = 1 - - # x = torch.randn(BZ, channels, H, W) - x = torch.arange(BZ*channels*H*W).reshape(BZ, channels, H, W) - print(x) - cs_model = ChannelShuffle(channels) - - x = x.to(device) - cs_model = cs_model.to(device) - - output1 = channel_shuffle_megvii(x) - print(output1[0]) - output2 = channel_shuffle_torchvision(x) - print(output2[0]) - output3 = cs_model(x) - print('output1-output2',sum((i-j).abs().sum() for i, j in zip(output1, output2))) - print('output2-output3',sum((i-j).abs().sum() for i, j in zip(output2, output3))) - print('output1-output3',sum((i-j).abs().sum() for i, j in zip(output1, output3))) - +# Copyright (c) 2020, Huawei Technologies.All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 numpy as np +import torch +import torch.nn as nn + + +class ChannelShuffle(nn.Module): + r"""Applies an NPU compatible channel shuffle operation. + + The origin implement is https://github.com/pytorch/vision/blob/master/torchvision/models/shufflenetv2.py#L21 + + In order to avoid contiguous operation which is not efficient on npu, we replaced the original operation + with a rewrite of the same semantics. Two discontinuous operations are replaced, transpose and chunk. + + .. note:: + Only group=2 is implemented, modify other group scenarios yourself. + + Args: + in_channels (int): The total number of channels in the input tensors + groups (int): The number of shuffle groups. Default: 2 + split_shuffle (bool): Whether to execute the chunk after shuffle. Default: True + + Shape: + - Input: :math:`(N, C_{in}, L_{in})`, `(N, C_{in}, L_{in})` + - Output: :math:`(N, C_{out}, L_{out})` + + Examples:: + >>> x1 = torch.randn(2,32,7,7) + >>> x2 = torch.randn(2,32,7,7) + >>> m = ChannelShuffle(64, split_shuffle=True) + >>> output = m(x1, x2) + + """ + + def __init__(self, in_channels, groups=2): + super(ChannelShuffle, self).__init__() + self.group_len = in_channels // groups + + # init out_channels + self.out_channels = np.array(list(range(in_channels))).reshape(groups, self.group_len).transpose(1, 0).flatten() + self.out_channels = torch.from_numpy(self.out_channels).long() + + # init index used in fp & bp + # Only group=2 is implemented, modify other group scenarios yourself. + self.fp_index1 = self.out_channels[:self.group_len] + self.fp_index2 = self.out_channels[self.group_len:] + self.bp_index = torch.tensor(list(range(0, in_channels, 2)) + list(range(1, in_channels, 2))) + + self.checked = False + + def check_self(self, x): + r"""Check device equipment between tensors. + """ + if self.bp_index.device == x.device: + self.checked = True + return + + device = x.device + if str(device).startswith('npu'): + self.fp_index1 = self.fp_index1.int() + self.fp_index2 = self.fp_index2.int() + self.bp_index = self.bp_index.int() + + self.fp_index1 = self.fp_index1.to(device) + self.fp_index2 = self.fp_index2.to(device) + self.bp_index = self.bp_index.to(device) + + + def forward(self, x): + if not self.checked: + self.check_self(x) + if self.training: + return IndexSelectHalfImplementation.apply(x, self.fp_index1, self.fp_index2, self.bp_index) + else: + return IndexSelectHalfImplementationForward(x, self.fp_index1, self.fp_index2, self.bp_index) + +def IndexSelectHalfImplementationForward(x, fp_index1, fp_index2, bp_index): + return x.index_select(1, fp_index1), x.index_select(1, fp_index2) + +class IndexSelectHalfImplementation(torch.autograd.Function): + @staticmethod + def forward(ctx, x, fp_index1, fp_index2, bp_index): + ctx.bp_index = bp_index + return x.index_select(1, fp_index1), x.index_select(1, fp_index2) + + @staticmethod + def backward(ctx, grad_output1, grad_output2): + grad_output = torch.cat([grad_output1, grad_output2], 1) + out = grad_output.index_select(1, ctx.bp_index) + return out, None, None, None, None + +def channel_shuffle_torchvision(x, groups=2): + # type: (torch.Tensor, int) -> torch.Tensor + batchsize, num_channels, height, width = x.data.size() + channels_per_group = num_channels // groups + + # reshape + x = x.view(batchsize, groups, + channels_per_group, height, width) + + x = torch.transpose(x, 1, 2).contiguous() + + # flatten + x = x.view(batchsize, -1, height, width) + + return x.chunk(2, 1) + +def channel_shuffle_megvii(x): + batchsize, num_channels, height, width = x.data.size() + assert (num_channels % 4 == 0) + x = x.reshape(batchsize * num_channels // 2, 2, height * width) + x = x.permute(1, 0, 2) + x = x.reshape(2, -1, num_channels // 2, height, width) + return x[0], x[1] + +if __name__ == '__main__': + device = 'cpu' + + if device.startswith('npu'): + torch.npu.set_device(device) + + channels = 8 + BZ = 2 + H = 1 + W = 1 + + # x = torch.randn(BZ, channels, H, W) + x = torch.arange(BZ*channels*H*W).reshape(BZ, channels, H, W) + print(x) + cs_model = ChannelShuffle(channels) + + x = x.to(device) + cs_model = cs_model.to(device) + + output1 = channel_shuffle_megvii(x) + print(output1[0]) + output2 = channel_shuffle_torchvision(x) + print(output2[0]) + output3 = cs_model(x) + print('output1-output2',sum((i-j).abs().sum() for i, j in zip(output1, output2))) + print('output2-output3',sum((i-j).abs().sum() for i, j in zip(output2, output3))) + print('output1-output3',sum((i-j).abs().sum() for i, j in zip(output1, output3))) + diff --git a/PyTorch/contrib/cv/classification/SkresNet50/scripts/eval.sh b/PyTorch/contrib/cv/classification/SkresNet50/scripts/eval.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SkresNet50/scripts/npu_setenv.sh b/PyTorch/contrib/cv/classification/SkresNet50/scripts/npu_setenv.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SkresNet50/scripts/train_1p.sh b/PyTorch/contrib/cv/classification/SkresNet50/scripts/train_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SkresNet50/scripts/train_8p.sh b/PyTorch/contrib/cv/classification/SkresNet50/scripts/train_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SkresNet50/utils/progress/setup.py b/PyTorch/contrib/cv/classification/SkresNet50/utils/progress/setup.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/SkresNet50/utils/progress/test_progress.py b/PyTorch/contrib/cv/classification/SkresNet50/utils/progress/test_progress.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/TNT/npu_fused_adamw.py b/PyTorch/contrib/cv/classification/TNT/npu_fused_adamw.py index 8a8e3f5a8d..df662e48c1 100644 --- a/PyTorch/contrib/cv/classification/TNT/npu_fused_adamw.py +++ b/PyTorch/contrib/cv/classification/TNT/npu_fused_adamw.py @@ -1,257 +1,257 @@ -# Copyright (c) 2020, Huawei Technologies. -# Copyright (c) 2019, Facebook CORPORATION. -# All rights reserved. -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 math -from collections import defaultdict - -import torch -from torch.optim.optimizer import Optimizer - -from apex.contrib.combine_tensors import combine_npu - - -class NpuFusedAdamW(Optimizer): - """Implements AdamW algorithm. - - Currently NPU-only. Requires Apex to be installed via - ``pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--npu_float_status" ./``. - - This version of NPU fused AdamW implements 1 fusions. - - * A combine-tensor apply launch that batches the elementwise updates applied to all the model's parameters - into one or a few kernel launches. - - :class:`apex.optimizers.NpuFusedAdamW` may be used as a drop-in replacement for ``torch.optim.AdamW``:: - - opt = apex.optimizers.NpuFusedAdamW(model.parameters(), lr = ....) - ... - opt.step() - - :class:`apex.optimizers.FusedAdamW` should be used with Amp. Currently, if you wish to use :class:`NpuFusedAdamW` - with Amp, only ``opt_level O1 and O2`` can be choosed:: - - opt = apex.optimizers.NpuFusedAdamW(model.parameters(), lr = ....) - model, opt = amp.initialize(model, opt, opt_level="O2") - ... - opt.step() - - - The original Adam algorithm was proposed in `Adam: A Method for Stochastic Optimization`_. - The AdamW variant was proposed in `Decoupled Weight Decay Regularization`_. - - Arguments: - params (iterable): iterable of parameters to optimize or dicts defining - parameter groups - lr (float, optional, default: 1e-3): learning rate - betas (Tuple[float, float], optional, default: (0.9, 0.999)): coefficients used - for computing running averages of gradient and its square - eps (float, optional, default: 1e-8): term added to the denominator to improve - numerical stability - weight_decay (float, optional, default: 1e-2): weight decay coefficient - amsgrad (boolean, optional, default: False): whether to use the AMSGrad variant of - this algorithm from the paper `On the Convergence of Adam and Beyond`_ - - .. _Adam\: A Method for Stochastic Optimization: - https://arxiv.org/abs/1412.6980 - .. _Decoupled Weight Decay Regularization: - https://arxiv.org/abs/1711.05101 - .. _On the Convergence of Adam and Beyond: - https://openreview.net/forum?id=ryQu7f-RZ - """ - - def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), eps=1e-8, - weight_decay=1e-2, amsgrad=False): - if lr < 0.0: - raise ValueError("Invalid learning rate: {}".format(lr)) - if eps < 0.0: - raise ValueError("Invalid epsilon value: {}".format(eps)) - if betas[0] < 0.0 or betas[0] >= 1.0: - raise ValueError("Invalid beta parameter at index 0: {}".format(betas[0])) - if betas[1] < 0.0 or betas[1] >= 1.0: - raise ValueError("Invalid beta parameter at index 1: {}".format(betas[1])) - if weight_decay < 0.0: - raise ValueError("Invalid weight_decay value: {}".format(weight_decay)) - defaults = dict(lr=lr, betas=betas, eps=eps, - weight_decay=weight_decay, amsgrad=amsgrad) - self.is_npu_fused_optimizer = True - super(NpuFusedAdamW, self).__init__(params, defaults) - - def __setstate__(self, state): - super(NpuFusedAdamW, self).__setstate__(state) - for group in self.param_groups: - group.setdefault('amsgrad', False) - - def _init_param_state(self, p, amsgrad): - state = self.state[p] - # State initialization - if len(state) == 0: - state['step'] = 0 - # Exponential moving average of gradient values - state['exp_avg'] = torch.zeros_like(p, memory_format=torch.preserve_format) - # Exponential moving average of squared gradient values - state['exp_avg_sq'] = torch.zeros_like(p, memory_format=torch.preserve_format) - if amsgrad: - # Maintains max of all exp. moving avg. of sq. grad. values - state['max_exp_avg_sq'] = torch.zeros_like(p, memory_format=torch.preserve_format) - else: - exp_avg_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) - exp_avg_tmp.copy_(state['exp_avg']) - state['exp_avg'] = exp_avg_tmp - - exp_avg_sq_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) - exp_avg_sq_tmp.copy_(state['exp_avg_sq']) - state['exp_avg_sq'] = exp_avg_sq_tmp - - if amsgrad: - max_exp_avg_sq_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) - max_exp_avg_sq_tmp.copy_(state['max_exp_avg_sq']) - state['max_exp_avg_sq'] = max_exp_avg_sq_tmp - - def _combine_group_param_states(self, group_index): - group = self.param_groups[group_index] - stash = self._amp_stash - group_params_list = stash.params_lists_indexed_by_group[group_index] - - amsgrad = group['amsgrad'] - - combined_param_states = [] - for params in group_params_list: - step_list = [] - exp_avg_list = [] - exp_avg_sq_list = [] - max_exp_avg_sq_list = [] - - for p in params: - if p.grad is None: - continue - grad = p.grad - if grad.is_sparse: - raise RuntimeError('NpuFusedAdamW does not support sparse gradients, ' - 'please consider SparseAdam instead') - - self._init_param_state(p, amsgrad) - state = self.state[p] - step_list.append(state['step']) - exp_avg_list.append(state['exp_avg']) - exp_avg_sq_list.append(state['exp_avg_sq']) - if amsgrad: - max_exp_avg_sq_list.append(state['max_exp_avg_sq']) - - combined_step = 0 - combined_exp_avg = None - combined_exp_avg_sq = None - combined_max_exp_avg_sq = None - - if len(exp_avg_list) > 0: - combined_step = step_list[0] - combined_exp_avg = combine_npu(exp_avg_list) - combined_exp_avg_sq = combine_npu(exp_avg_sq_list) - combined_max_exp_avg_sq = combine_npu(max_exp_avg_sq_list) - - combined_state = defaultdict(dict) - combined_state['step'] = combined_step - combined_state['exp_avg'] = combined_exp_avg - combined_state['exp_avg_sq'] = combined_exp_avg_sq - combined_state['max_exp_avg_sq'] = combined_max_exp_avg_sq - combined_param_states.append(combined_state) - stash.combined_param_states_indexed_by_group[group_index] = combined_param_states - - def _combine_param_states_by_group(self): - stash = self._amp_stash - if stash.param_states_are_combined_by_group: - return - - stash.combined_param_states_indexed_by_group = [] - for _ in self.param_groups: - stash.combined_param_states_indexed_by_group.append([]) - - for i, _ in enumerate(self.param_groups): - self._combine_group_param_states(i) - stash.param_states_are_combined_by_group = True - - def _group_step(self, group_index): - group = self.param_groups[group_index] - for p in group['params']: - if p.grad is None: - continue - - grad = p.grad - if grad.is_sparse: - raise RuntimeError('NpuFusedAdamW does not support sparse gradients, ' - 'please consider SparseAdam instead') - state_p = self.state[p] - state_p['step'] += 1 - - amsgrad = group['amsgrad'] - beta1, beta2 = group['betas'] - - stash = self._amp_stash - combined_group_params = stash.combined_params_indexed_by_group[group_index] - combined_group_grads = stash.combined_grads_indexed_by_group[group_index] - combined_group_param_states = stash.combined_param_states_indexed_by_group[group_index] - - for combined_param, combined_grad, combined_param_state in zip(combined_group_params, - combined_group_grads, - combined_group_param_states): - if combined_param is None or combined_grad is None: - continue - - # Perform stepweight decay. The fused method is used here to speed up the calculation - combined_param.mul_(1 - group['lr'] * group['weight_decay']) - - exp_avg, exp_avg_sq = combined_param_state['exp_avg'], combined_param_state['exp_avg_sq'] - if amsgrad: - max_exp_avg_sq = combined_param_state['max_exp_avg_sq'] - - combined_param_state['step'] += 1 - bias_correction1 = 1 - beta1 ** combined_param_state['step'] - bias_correction2 = 1 - beta2 ** combined_param_state['step'] - - # Decay the first and second moment running average coefficient - exp_avg.mul_(beta1).add_(combined_grad, alpha=1 - beta1) - exp_avg_sq.mul_(beta2).addcmul_(combined_grad, combined_grad, value=1 - beta2) - if amsgrad: - # Maintains the maximum of all 2nd moment running avg. till now - torch.max(max_exp_avg_sq, exp_avg_sq, out=max_exp_avg_sq) - # Use the max. for normalizing running avg. of gradient - denom = (max_exp_avg_sq.sqrt() / math.sqrt(bias_correction2)).add_(group['eps']) - else: - denom = (exp_avg_sq.sqrt() / math.sqrt(bias_correction2)).add_(group['eps']) - - step_size = group['lr'] / bias_correction1 - - combined_param.addcdiv_(exp_avg, denom, value=-step_size) - - @torch.no_grad() - def step(self, closure=None): - if not hasattr(self, "_amp_stash"): - raise RuntimeError('apex.optimizers.NpuFusedAdamW should be used with AMP.') - - self._check_already_combined_params_and_grads() - # combine params and grads first - self._combine_params_and_grads_by_group() - # then combine param states - self._combine_param_states_by_group() - - loss = None - if closure is not None: - with torch.enable_grad(): - loss = closure() - - for i, _ in enumerate(self.param_groups): - self._group_step(i) - - return loss +# Copyright (c) 2020, Huawei Technologies. +# Copyright (c) 2019, Facebook CORPORATION. +# All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 math +from collections import defaultdict + +import torch +from torch.optim.optimizer import Optimizer + +from apex.contrib.combine_tensors import combine_npu + + +class NpuFusedAdamW(Optimizer): + """Implements AdamW algorithm. + + Currently NPU-only. Requires Apex to be installed via + ``pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--npu_float_status" ./``. + + This version of NPU fused AdamW implements 1 fusions. + + * A combine-tensor apply launch that batches the elementwise updates applied to all the model's parameters + into one or a few kernel launches. + + :class:`apex.optimizers.NpuFusedAdamW` may be used as a drop-in replacement for ``torch.optim.AdamW``:: + + opt = apex.optimizers.NpuFusedAdamW(model.parameters(), lr = ....) + ... + opt.step() + + :class:`apex.optimizers.FusedAdamW` should be used with Amp. Currently, if you wish to use :class:`NpuFusedAdamW` + with Amp, only ``opt_level O1 and O2`` can be choosed:: + + opt = apex.optimizers.NpuFusedAdamW(model.parameters(), lr = ....) + model, opt = amp.initialize(model, opt, opt_level="O2") + ... + opt.step() + + + The original Adam algorithm was proposed in `Adam: A Method for Stochastic Optimization`_. + The AdamW variant was proposed in `Decoupled Weight Decay Regularization`_. + + Arguments: + params (iterable): iterable of parameters to optimize or dicts defining + parameter groups + lr (float, optional, default: 1e-3): learning rate + betas (Tuple[float, float], optional, default: (0.9, 0.999)): coefficients used + for computing running averages of gradient and its square + eps (float, optional, default: 1e-8): term added to the denominator to improve + numerical stability + weight_decay (float, optional, default: 1e-2): weight decay coefficient + amsgrad (boolean, optional, default: False): whether to use the AMSGrad variant of + this algorithm from the paper `On the Convergence of Adam and Beyond`_ + + .. _Adam\: A Method for Stochastic Optimization: + https://arxiv.org/abs/1412.6980 + .. _Decoupled Weight Decay Regularization: + https://arxiv.org/abs/1711.05101 + .. _On the Convergence of Adam and Beyond: + https://openreview.net/forum?id=ryQu7f-RZ + """ + + def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), eps=1e-8, + weight_decay=1e-2, amsgrad=False): + if lr < 0.0: + raise ValueError("Invalid learning rate: {}".format(lr)) + if eps < 0.0: + raise ValueError("Invalid epsilon value: {}".format(eps)) + if betas[0] < 0.0 or betas[0] >= 1.0: + raise ValueError("Invalid beta parameter at index 0: {}".format(betas[0])) + if betas[1] < 0.0 or betas[1] >= 1.0: + raise ValueError("Invalid beta parameter at index 1: {}".format(betas[1])) + if weight_decay < 0.0: + raise ValueError("Invalid weight_decay value: {}".format(weight_decay)) + defaults = dict(lr=lr, betas=betas, eps=eps, + weight_decay=weight_decay, amsgrad=amsgrad) + self.is_npu_fused_optimizer = True + super(NpuFusedAdamW, self).__init__(params, defaults) + + def __setstate__(self, state): + super(NpuFusedAdamW, self).__setstate__(state) + for group in self.param_groups: + group.setdefault('amsgrad', False) + + def _init_param_state(self, p, amsgrad): + state = self.state[p] + # State initialization + if len(state) == 0: + state['step'] = 0 + # Exponential moving average of gradient values + state['exp_avg'] = torch.zeros_like(p, memory_format=torch.preserve_format) + # Exponential moving average of squared gradient values + state['exp_avg_sq'] = torch.zeros_like(p, memory_format=torch.preserve_format) + if amsgrad: + # Maintains max of all exp. moving avg. of sq. grad. values + state['max_exp_avg_sq'] = torch.zeros_like(p, memory_format=torch.preserve_format) + else: + exp_avg_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) + exp_avg_tmp.copy_(state['exp_avg']) + state['exp_avg'] = exp_avg_tmp + + exp_avg_sq_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) + exp_avg_sq_tmp.copy_(state['exp_avg_sq']) + state['exp_avg_sq'] = exp_avg_sq_tmp + + if amsgrad: + max_exp_avg_sq_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) + max_exp_avg_sq_tmp.copy_(state['max_exp_avg_sq']) + state['max_exp_avg_sq'] = max_exp_avg_sq_tmp + + def _combine_group_param_states(self, group_index): + group = self.param_groups[group_index] + stash = self._amp_stash + group_params_list = stash.params_lists_indexed_by_group[group_index] + + amsgrad = group['amsgrad'] + + combined_param_states = [] + for params in group_params_list: + step_list = [] + exp_avg_list = [] + exp_avg_sq_list = [] + max_exp_avg_sq_list = [] + + for p in params: + if p.grad is None: + continue + grad = p.grad + if grad.is_sparse: + raise RuntimeError('NpuFusedAdamW does not support sparse gradients, ' + 'please consider SparseAdam instead') + + self._init_param_state(p, amsgrad) + state = self.state[p] + step_list.append(state['step']) + exp_avg_list.append(state['exp_avg']) + exp_avg_sq_list.append(state['exp_avg_sq']) + if amsgrad: + max_exp_avg_sq_list.append(state['max_exp_avg_sq']) + + combined_step = 0 + combined_exp_avg = None + combined_exp_avg_sq = None + combined_max_exp_avg_sq = None + + if len(exp_avg_list) > 0: + combined_step = step_list[0] + combined_exp_avg = combine_npu(exp_avg_list) + combined_exp_avg_sq = combine_npu(exp_avg_sq_list) + combined_max_exp_avg_sq = combine_npu(max_exp_avg_sq_list) + + combined_state = defaultdict(dict) + combined_state['step'] = combined_step + combined_state['exp_avg'] = combined_exp_avg + combined_state['exp_avg_sq'] = combined_exp_avg_sq + combined_state['max_exp_avg_sq'] = combined_max_exp_avg_sq + combined_param_states.append(combined_state) + stash.combined_param_states_indexed_by_group[group_index] = combined_param_states + + def _combine_param_states_by_group(self): + stash = self._amp_stash + if stash.param_states_are_combined_by_group: + return + + stash.combined_param_states_indexed_by_group = [] + for _ in self.param_groups: + stash.combined_param_states_indexed_by_group.append([]) + + for i, _ in enumerate(self.param_groups): + self._combine_group_param_states(i) + stash.param_states_are_combined_by_group = True + + def _group_step(self, group_index): + group = self.param_groups[group_index] + for p in group['params']: + if p.grad is None: + continue + + grad = p.grad + if grad.is_sparse: + raise RuntimeError('NpuFusedAdamW does not support sparse gradients, ' + 'please consider SparseAdam instead') + state_p = self.state[p] + state_p['step'] += 1 + + amsgrad = group['amsgrad'] + beta1, beta2 = group['betas'] + + stash = self._amp_stash + combined_group_params = stash.combined_params_indexed_by_group[group_index] + combined_group_grads = stash.combined_grads_indexed_by_group[group_index] + combined_group_param_states = stash.combined_param_states_indexed_by_group[group_index] + + for combined_param, combined_grad, combined_param_state in zip(combined_group_params, + combined_group_grads, + combined_group_param_states): + if combined_param is None or combined_grad is None: + continue + + # Perform stepweight decay. The fused method is used here to speed up the calculation + combined_param.mul_(1 - group['lr'] * group['weight_decay']) + + exp_avg, exp_avg_sq = combined_param_state['exp_avg'], combined_param_state['exp_avg_sq'] + if amsgrad: + max_exp_avg_sq = combined_param_state['max_exp_avg_sq'] + + combined_param_state['step'] += 1 + bias_correction1 = 1 - beta1 ** combined_param_state['step'] + bias_correction2 = 1 - beta2 ** combined_param_state['step'] + + # Decay the first and second moment running average coefficient + exp_avg.mul_(beta1).add_(combined_grad, alpha=1 - beta1) + exp_avg_sq.mul_(beta2).addcmul_(combined_grad, combined_grad, value=1 - beta2) + if amsgrad: + # Maintains the maximum of all 2nd moment running avg. till now + torch.max(max_exp_avg_sq, exp_avg_sq, out=max_exp_avg_sq) + # Use the max. for normalizing running avg. of gradient + denom = (max_exp_avg_sq.sqrt() / math.sqrt(bias_correction2)).add_(group['eps']) + else: + denom = (exp_avg_sq.sqrt() / math.sqrt(bias_correction2)).add_(group['eps']) + + step_size = group['lr'] / bias_correction1 + + combined_param.addcdiv_(exp_avg, denom, value=-step_size) + + @torch.no_grad() + def step(self, closure=None): + if not hasattr(self, "_amp_stash"): + raise RuntimeError('apex.optimizers.NpuFusedAdamW should be used with AMP.') + + self._check_already_combined_params_and_grads() + # combine params and grads first + self._combine_params_and_grads_by_group() + # then combine param states + self._combine_param_states_by_group() + + loss = None + if closure is not None: + with torch.enable_grad(): + loss = closure() + + for i, _ in enumerate(self.param_groups): + self._group_step(i) + + return loss diff --git a/PyTorch/contrib/cv/classification/VOLO/README.md b/PyTorch/contrib/cv/classification/VOLO/README.md index c752a0a804..1dfba0b42e 100644 --- a/PyTorch/contrib/cv/classification/VOLO/README.md +++ b/PyTorch/contrib/cv/classification/VOLO/README.md @@ -1,64 +1,64 @@ -# VOLO - -This implements training of volo_d1 on the ImageNet-2012 dataset and token labeling, mainly modified from [sail-sg/volo](https://github.com/sail-sg/volo). - -## VOLO Detail - -There is an error of Col2im operator on NPU, and make it compute with the CPU. - - Because lacking of Roi_align on NPU, the function is re-implemented . - -if there is an error about `OP:ROIAlign`, please modify `/usr/local/Ascend/ascend-toolkit/5.0.x/x-linux/opp/op_impl/built-in/ai_core/tbe/impl/roi_align.py:line 2287` - -``` -#ori -with tik_instance.for_range(0, pool_h) as p_h: - with tik_instance.for_range(0, pool_w, thread_num=2) as p_w: -#right -with tik_instance.for_range(0, pool_h) as p_h: - with tik_instance.for_range(0, pool_w, thread_num=min(2, pool_w)) as p_w: -``` - -## Requirements - -- Install PyTorch ([pytorch.org](http://pytorch.org)) -- `pip install -r requirements.txt` -- Download the Imagenet-2012 dataset. Refer to the original repository https://github.com/rwightman/pytorch-image-models -- Download the token label data, please refer to the [sail-sg/volo](https://github.com/sail-sg/volo). - - -## Training - -To train a model, run `main.py` with the desired model architecture and the path to the Imagenet-2012 dataset, and : - -```bash -Modify the data_dir path/to/imagenet and label path/to/label_top5_train_nfnet in the shell file. -# training 1p accuracy -bash test/train_full_1p.sh - -# training 1p performance -bash test/train_performance_1p.sh - -# training 8p accuracy -bash test/train_full_8p.sh - -# training 8p performance -bash test/train_performance_8p.sh - -# finetune -bash test/train_finetune_1p.sh - -# Online inference demo -python demo.py --checkpoint real_checkpoint_path -``` - -## Volo training result - - -| | top1 | AMP_Type | Epochs | FPS | -| :----: | :---: | :------: | :----: | :-----: | -| 1p-GPU | - | O2 | 1 | 152.37 | -| 1p-NPU | - | O2 | 1 | 23.26 | -| 8p-GPU | 82.83 | O2 | 100 | 1080.81 | -| 8p-NPU | 81.79 | O2 | 100 | 180.31 | - +# VOLO + +This implements training of volo_d1 on the ImageNet-2012 dataset and token labeling, mainly modified from [sail-sg/volo](https://github.com/sail-sg/volo). + +## VOLO Detail + +There is an error of Col2im operator on NPU, and make it compute with the CPU. + + Because lacking of Roi_align on NPU, the function is re-implemented . + +if there is an error about `OP:ROIAlign`, please modify `/usr/local/Ascend/ascend-toolkit/5.0.x/x-linux/opp/op_impl/built-in/ai_core/tbe/impl/roi_align.py:line 2287` + +``` +#ori +with tik_instance.for_range(0, pool_h) as p_h: + with tik_instance.for_range(0, pool_w, thread_num=2) as p_w: +#right +with tik_instance.for_range(0, pool_h) as p_h: + with tik_instance.for_range(0, pool_w, thread_num=min(2, pool_w)) as p_w: +``` + +## Requirements + +- Install PyTorch ([pytorch.org](http://pytorch.org)) +- `pip install -r requirements.txt` +- Download the Imagenet-2012 dataset. Refer to the original repository https://github.com/rwightman/pytorch-image-models +- Download the token label data, please refer to the [sail-sg/volo](https://github.com/sail-sg/volo). + + +## Training + +To train a model, run `main.py` with the desired model architecture and the path to the Imagenet-2012 dataset, and : + +```bash +Modify the data_dir path/to/imagenet and label path/to/label_top5_train_nfnet in the shell file. +# training 1p accuracy +bash test/train_full_1p.sh + +# training 1p performance +bash test/train_performance_1p.sh + +# training 8p accuracy +bash test/train_full_8p.sh + +# training 8p performance +bash test/train_performance_8p.sh + +# finetune +bash test/train_finetune_1p.sh + +# Online inference demo +python demo.py --checkpoint real_checkpoint_path +``` + +## Volo training result + + +| | top1 | AMP_Type | Epochs | FPS | +| :----: | :---: | :------: | :----: | :-----: | +| 1p-GPU | - | O2 | 1 | 152.37 | +| 1p-NPU | - | O2 | 1 | 23.26 | +| 8p-GPU | 82.83 | O2 | 100 | 1080.81 | +| 8p-NPU | 81.79 | O2 | 100 | 180.31 | + diff --git a/PyTorch/contrib/cv/classification/VOLO/demo.py b/PyTorch/contrib/cv/classification/VOLO/demo.py index 07041b9dfe..7175a52cb1 100644 --- a/PyTorch/contrib/cv/classification/VOLO/demo.py +++ b/PyTorch/contrib/cv/classification/VOLO/demo.py @@ -1,137 +1,137 @@ -""" -BSD 3-Clause License - -Copyright (c) Soumith Chintala 2016, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -Copyright 2020 Huawei Technologies Co., Ltd - -Licensed under the BSD 3-Clause License (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -https://spdx.org/licenses/BSD-3-Clause.html - -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 argparse -import torch -import torchvision -from torchvision import datasets, transforms -from collections import OrderedDict - -from timm.models import create_model -from timm.data.transforms import _pil_interp, RandomResizedCropAndInterpolation, ToNumpy, ToTensor - -DEFAULT_CROP_PCT = 0.875 - -parser = argparse.ArgumentParser(description='ImageNet Training') -parser.add_argument('--checkpoint', type=str, default='', - help='checkpoint path') -args = parser.parse_args() - -def proc_node_module(checkpoint, attr_name): - new_state_dict = OrderedDict() - for k, v in checkpoint[attr_name].items(): - if(k[0: 7] == "module."): - name = k[7:] - else: - name = k[0:] - new_state_dict[name] = v - return new_state_dict - -def get_raw_data(): - from PIL import Image - from urllib.request import urlretrieve - IMAGE_URL = 'https://bbs-img.huaweicloud.com/blogs/img/thumb/1591951315139_8989_1363.png' - urlretrieve(IMAGE_URL, 'tmp.jpg') - img = Image.open("tmp.jpg") - img = img.convert('RGB') - return img - -def test(): - loc = 'npu:0' - loc_cpu = 'cpu' - torch.npu.set_device(loc) - if args.checkpoint == '': - print("please give the checkpoint path using --checkpoint param") - exit(0) - checkpoint = torch.load(args.checkpoint, map_location=loc) - checkpoint['state_dict'] = proc_node_module(checkpoint, 'state_dict') - - model = create_model( - 'volo_d1', - pretrained=False, - num_classes=None, - drop_rate=0.0, - drop_connect_rate=None, # DEPRECATED, use drop_path - drop_path_rate=0.0, - drop_block_rate=None, - global_pool=None, - bn_tf=False, - bn_momentum=None, - bn_eps=None, - scriptable=False, - checkpoint_path='', - img_size=224) - - model = model.to(loc) - model.load_state_dict(checkpoint['state_dict']) - model.eval() - - crop_pct = DEFAULT_CROP_PCT - img_size = 224 - scale_size = int(math.floor(img_size / crop_pct)) - interpolation = 'bilinear' - tfl = [ - transforms.Resize(scale_size, _pil_interp(interpolation)), - transforms.CenterCrop(img_size), - ] - tfl += [ToNumpy()] - data_transfrom = transforms.Compose(tfl) - - rd = get_raw_data() - - inputs = data_transfrom(rd) - inputs = inputs.unsqueeze(0) - inputs = inputs.to(loc) - output = model(inputs) - output = output.to(loc_cpu) - - _, pred = output.topk(1, 1, True, True) - result = torch.argmax(output, 1) - print("class: ", pred[0][0].item()) - print(result) - -if __name__ == "__main__": +""" +BSD 3-Clause License + +Copyright (c) Soumith Chintala 2016, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Copyright 2020 Huawei Technologies Co., Ltd + +Licensed under the BSD 3-Clause License (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://spdx.org/licenses/BSD-3-Clause.html + +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 argparse +import torch +import torchvision +from torchvision import datasets, transforms +from collections import OrderedDict + +from timm.models import create_model +from timm.data.transforms import _pil_interp, RandomResizedCropAndInterpolation, ToNumpy, ToTensor + +DEFAULT_CROP_PCT = 0.875 + +parser = argparse.ArgumentParser(description='ImageNet Training') +parser.add_argument('--checkpoint', type=str, default='', + help='checkpoint path') +args = parser.parse_args() + +def proc_node_module(checkpoint, attr_name): + new_state_dict = OrderedDict() + for k, v in checkpoint[attr_name].items(): + if(k[0: 7] == "module."): + name = k[7:] + else: + name = k[0:] + new_state_dict[name] = v + return new_state_dict + +def get_raw_data(): + from PIL import Image + from urllib.request import urlretrieve + IMAGE_URL = 'https://bbs-img.huaweicloud.com/blogs/img/thumb/1591951315139_8989_1363.png' + urlretrieve(IMAGE_URL, 'tmp.jpg') + img = Image.open("tmp.jpg") + img = img.convert('RGB') + return img + +def test(): + loc = 'npu:0' + loc_cpu = 'cpu' + torch.npu.set_device(loc) + if args.checkpoint == '': + print("please give the checkpoint path using --checkpoint param") + exit(0) + checkpoint = torch.load(args.checkpoint, map_location=loc) + checkpoint['state_dict'] = proc_node_module(checkpoint, 'state_dict') + + model = create_model( + 'volo_d1', + pretrained=False, + num_classes=None, + drop_rate=0.0, + drop_connect_rate=None, # DEPRECATED, use drop_path + drop_path_rate=0.0, + drop_block_rate=None, + global_pool=None, + bn_tf=False, + bn_momentum=None, + bn_eps=None, + scriptable=False, + checkpoint_path='', + img_size=224) + + model = model.to(loc) + model.load_state_dict(checkpoint['state_dict']) + model.eval() + + crop_pct = DEFAULT_CROP_PCT + img_size = 224 + scale_size = int(math.floor(img_size / crop_pct)) + interpolation = 'bilinear' + tfl = [ + transforms.Resize(scale_size, _pil_interp(interpolation)), + transforms.CenterCrop(img_size), + ] + tfl += [ToNumpy()] + data_transfrom = transforms.Compose(tfl) + + rd = get_raw_data() + + inputs = data_transfrom(rd) + inputs = inputs.unsqueeze(0) + inputs = inputs.to(loc) + output = model(inputs) + output = output.to(loc_cpu) + + _, pred = output.topk(1, 1, True, True) + result = torch.argmax(output, 1) + print("class: ", pred[0][0].item()) + print(result) + +if __name__ == "__main__": test() \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/VOLO/loss/__init__.py b/PyTorch/contrib/cv/classification/VOLO/loss/__init__.py index 1eab72cf3a..658c84ebfa 100644 --- a/PyTorch/contrib/cv/classification/VOLO/loss/__init__.py +++ b/PyTorch/contrib/cv/classification/VOLO/loss/__init__.py @@ -1,47 +1,47 @@ -""" -BSD 3-Clause License - -Copyright (c) Soumith Chintala 2016, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -Copyright 2020 Huawei Technologies Co., Ltd - -Licensed under the BSD 3-Clause License (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -https://spdx.org/licenses/BSD-3-Clause.html - -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. -""" +""" +BSD 3-Clause License + +Copyright (c) Soumith Chintala 2016, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Copyright 2020 Huawei Technologies Co., Ltd + +Licensed under the BSD 3-Clause License (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://spdx.org/licenses/BSD-3-Clause.html + +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 .cross_entropy import TokenLabelGTCrossEntropy, TokenLabelSoftTargetCrossEntropy, TokenLabelCrossEntropy \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/VOLO/models/__init__.py b/PyTorch/contrib/cv/classification/VOLO/models/__init__.py index fb1a0823dc..658c948f34 100644 --- a/PyTorch/contrib/cv/classification/VOLO/models/__init__.py +++ b/PyTorch/contrib/cv/classification/VOLO/models/__init__.py @@ -1,48 +1,48 @@ - -""" -BSD 3-Clause License - -Copyright (c) Soumith Chintala 2016, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -Copyright 2020 Huawei Technologies Co., Ltd - -Licensed under the BSD 3-Clause License (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -https://spdx.org/licenses/BSD-3-Clause.html - -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. -""" + +""" +BSD 3-Clause License + +Copyright (c) Soumith Chintala 2016, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Copyright 2020 Huawei Technologies Co., Ltd + +Licensed under the BSD 3-Clause License (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://spdx.org/licenses/BSD-3-Clause.html + +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 .volo import * \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/VOLO/prof_demo.sh b/PyTorch/contrib/cv/classification/VOLO/prof_demo.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/VOLO/test/train_full_8p.sh b/PyTorch/contrib/cv/classification/VOLO/test/train_full_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/VOLO/test/train_performance_8p.sh b/PyTorch/contrib/cv/classification/VOLO/test/train_performance_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/VOLO/timm/loss/asymmetric_loss.py b/PyTorch/contrib/cv/classification/VOLO/timm/loss/asymmetric_loss.py index d3a0d8650f..726f9410e4 100644 --- a/PyTorch/contrib/cv/classification/VOLO/timm/loss/asymmetric_loss.py +++ b/PyTorch/contrib/cv/classification/VOLO/timm/loss/asymmetric_loss.py @@ -1,143 +1,143 @@ -""" -BSD 3-Clause License - -Copyright (c) Soumith Chintala 2016, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -Copyright 2020 Huawei Technologies Co., Ltd - -Licensed under the BSD 3-Clause License (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -https://spdx.org/licenses/BSD-3-Clause.html - -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 torch -import torch.nn as nn - - -class AsymmetricLossMultiLabel(nn.Module): - def __init__(self, gamma_neg=4, gamma_pos=1, clip=0.05, eps=1e-8, disable_torch_grad_focal_loss=False): - super(AsymmetricLossMultiLabel, self).__init__() - - self.gamma_neg = gamma_neg - self.gamma_pos = gamma_pos - self.clip = clip - self.disable_torch_grad_focal_loss = disable_torch_grad_focal_loss - self.eps = eps - - def forward(self, x, y): - """" - Parameters - ---------- - x: input logits - y: targets (multi-label binarized vector) - """ - - # Calculating Probabilities - x_sigmoid = torch.sigmoid(x) - xs_pos = x_sigmoid - xs_neg = 1 - x_sigmoid - - # Asymmetric Clipping - if self.clip is not None and self.clip > 0: - xs_neg = (xs_neg + self.clip).clamp(max=1) - - # Basic CE calculation - los_pos = y * torch.log(xs_pos.clamp(min=self.eps)) - los_neg = (1 - y) * torch.log(xs_neg.clamp(min=self.eps)) - loss = los_pos + los_neg - - # Asymmetric Focusing - if self.gamma_neg > 0 or self.gamma_pos > 0: - if self.disable_torch_grad_focal_loss: - torch._C.set_grad_enabled(False) - pt0 = xs_pos * y - pt1 = xs_neg * (1 - y) # pt = p if t > 0 else 1-p - pt = pt0 + pt1 - one_sided_gamma = self.gamma_pos * y + self.gamma_neg * (1 - y) - one_sided_w = torch.pow(1 - pt, one_sided_gamma) - if self.disable_torch_grad_focal_loss: - torch._C.set_grad_enabled(True) - loss *= one_sided_w - - return -loss.sum() - - -class AsymmetricLossSingleLabel(nn.Module): - def __init__(self, gamma_pos=1, gamma_neg=4, eps: float = 0.1, reduction='mean'): - super(AsymmetricLossSingleLabel, self).__init__() - - self.eps = eps - self.logsoftmax = nn.LogSoftmax(dim=-1) - self.targets_classes = [] # prevent gpu repeated memory allocation - self.gamma_pos = gamma_pos - self.gamma_neg = gamma_neg - self.reduction = reduction - - def forward(self, inputs, target, reduction=None): - """" - Parameters - ---------- - x: input logits - y: targets (1-hot vector) - """ - - num_classes = inputs.size()[-1] - log_preds = self.logsoftmax(inputs) - self.targets_classes = torch.zeros_like(inputs).scatter_(1, target.long().unsqueeze(1), 1) - - # ASL weights - targets = self.targets_classes - anti_targets = 1 - targets - xs_pos = torch.exp(log_preds) - xs_neg = 1 - xs_pos - xs_pos = xs_pos * targets - xs_neg = xs_neg * anti_targets - asymmetric_w = torch.pow(1 - xs_pos - xs_neg, - self.gamma_pos * targets + self.gamma_neg * anti_targets) - log_preds = log_preds * asymmetric_w - - if self.eps > 0: # label smoothing - self.targets_classes.mul_(1 - self.eps).add_(self.eps / num_classes) - - # loss calculation - loss = - self.targets_classes.mul(log_preds) - - loss = loss.sum(dim=-1) - if self.reduction == 'mean': - loss = loss.mean() - - return loss +""" +BSD 3-Clause License + +Copyright (c) Soumith Chintala 2016, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Copyright 2020 Huawei Technologies Co., Ltd + +Licensed under the BSD 3-Clause License (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://spdx.org/licenses/BSD-3-Clause.html + +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 torch +import torch.nn as nn + + +class AsymmetricLossMultiLabel(nn.Module): + def __init__(self, gamma_neg=4, gamma_pos=1, clip=0.05, eps=1e-8, disable_torch_grad_focal_loss=False): + super(AsymmetricLossMultiLabel, self).__init__() + + self.gamma_neg = gamma_neg + self.gamma_pos = gamma_pos + self.clip = clip + self.disable_torch_grad_focal_loss = disable_torch_grad_focal_loss + self.eps = eps + + def forward(self, x, y): + """" + Parameters + ---------- + x: input logits + y: targets (multi-label binarized vector) + """ + + # Calculating Probabilities + x_sigmoid = torch.sigmoid(x) + xs_pos = x_sigmoid + xs_neg = 1 - x_sigmoid + + # Asymmetric Clipping + if self.clip is not None and self.clip > 0: + xs_neg = (xs_neg + self.clip).clamp(max=1) + + # Basic CE calculation + los_pos = y * torch.log(xs_pos.clamp(min=self.eps)) + los_neg = (1 - y) * torch.log(xs_neg.clamp(min=self.eps)) + loss = los_pos + los_neg + + # Asymmetric Focusing + if self.gamma_neg > 0 or self.gamma_pos > 0: + if self.disable_torch_grad_focal_loss: + torch._C.set_grad_enabled(False) + pt0 = xs_pos * y + pt1 = xs_neg * (1 - y) # pt = p if t > 0 else 1-p + pt = pt0 + pt1 + one_sided_gamma = self.gamma_pos * y + self.gamma_neg * (1 - y) + one_sided_w = torch.pow(1 - pt, one_sided_gamma) + if self.disable_torch_grad_focal_loss: + torch._C.set_grad_enabled(True) + loss *= one_sided_w + + return -loss.sum() + + +class AsymmetricLossSingleLabel(nn.Module): + def __init__(self, gamma_pos=1, gamma_neg=4, eps: float = 0.1, reduction='mean'): + super(AsymmetricLossSingleLabel, self).__init__() + + self.eps = eps + self.logsoftmax = nn.LogSoftmax(dim=-1) + self.targets_classes = [] # prevent gpu repeated memory allocation + self.gamma_pos = gamma_pos + self.gamma_neg = gamma_neg + self.reduction = reduction + + def forward(self, inputs, target, reduction=None): + """" + Parameters + ---------- + x: input logits + y: targets (1-hot vector) + """ + + num_classes = inputs.size()[-1] + log_preds = self.logsoftmax(inputs) + self.targets_classes = torch.zeros_like(inputs).scatter_(1, target.long().unsqueeze(1), 1) + + # ASL weights + targets = self.targets_classes + anti_targets = 1 - targets + xs_pos = torch.exp(log_preds) + xs_neg = 1 - xs_pos + xs_pos = xs_pos * targets + xs_neg = xs_neg * anti_targets + asymmetric_w = torch.pow(1 - xs_pos - xs_neg, + self.gamma_pos * targets + self.gamma_neg * anti_targets) + log_preds = log_preds * asymmetric_w + + if self.eps > 0: # label smoothing + self.targets_classes.mul_(1 - self.eps).add_(self.eps / num_classes) + + # loss calculation + loss = - self.targets_classes.mul(log_preds) + + loss = loss.sum(dim=-1) + if self.reduction == 'mean': + loss = loss.mean() + + return loss diff --git a/PyTorch/contrib/cv/classification/VOLO/tlt/__init__.py b/PyTorch/contrib/cv/classification/VOLO/tlt/__init__.py index a53b3e9888..39dd95c737 100644 --- a/PyTorch/contrib/cv/classification/VOLO/tlt/__init__.py +++ b/PyTorch/contrib/cv/classification/VOLO/tlt/__init__.py @@ -1,47 +1,47 @@ -""" -BSD 3-Clause License - -Copyright (c) Soumith Chintala 2016, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -Copyright 2020 Huawei Technologies Co., Ltd - -Licensed under the BSD 3-Clause License (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -https://spdx.org/licenses/BSD-3-Clause.html - -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. -""" +""" +BSD 3-Clause License + +Copyright (c) Soumith Chintala 2016, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Copyright 2020 Huawei Technologies Co., Ltd + +Licensed under the BSD 3-Clause License (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://spdx.org/licenses/BSD-3-Clause.html + +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 .utils import load_pretrained_weights \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/VOLO/tlt/data/random_augment_label.py b/PyTorch/contrib/cv/classification/VOLO/tlt/data/random_augment_label.py index a6a95782e1..005494f160 100644 --- a/PyTorch/contrib/cv/classification/VOLO/tlt/data/random_augment_label.py +++ b/PyTorch/contrib/cv/classification/VOLO/tlt/data/random_augment_label.py @@ -1,606 +1,606 @@ -""" -BSD 3-Clause License - -Copyright (c) Soumith Chintala 2016, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -Copyright 2020 Huawei Technologies Co., Ltd - -Licensed under the BSD 3-Clause License (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -https://spdx.org/licenses/BSD-3-Clause.html - -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. -""" -""" -Adapted from https://github.com/rwightman/pytorch-image-models/blob/master/timm/data/auto_augment.py and modified for token labeling -AutoAugment, RandAugment -""" -import random -import math -import re -from PIL import Image, ImageOps, ImageEnhance, ImageChops -import PIL -import numpy as np -from scipy import ndimage -import torch - -_PIL_VER = tuple([int(x) for x in PIL.__version__.split('.')[:2]]) - -_FILL = (128, 128, 128) - - - -# This signifies the max integer that the controller RNN could predict for the -# augmentation scheme. -_MAX_LEVEL = 10. - -_HPARAMS_DEFAULT = dict( - translate_const=250, - img_mean=_FILL, -) - -_RANDOM_INTERPOLATION = (Image.BILINEAR, Image.BICUBIC) - - -def _interpolation(kwargs): - interpolation = kwargs.pop('resample', Image.BILINEAR) - if isinstance(interpolation, (list, tuple)): - return random.choice(interpolation) - else: - return interpolation - -def affine_label(label, matrix): - - # label: 2, k, H, W - # label[0] value, label[1] index - a,b,c,d,e,f = matrix - affine_matrix = [[1,0,0,0],[0,a,b,c],[0,d,e,f]] - value = ndimage.affine_transform(label[0],matrix=affine_matrix, order=0, mode="constant") - index = ndimage.affine_transform(label[1],matrix=affine_matrix, order=0, mode="nearest") - - return torch.from_numpy(np.stack([value, index],axis=0)) - -def _check_args_tf(kwargs): - if 'fillcolor' in kwargs and _PIL_VER < (5, 0): - kwargs.pop('fillcolor') - kwargs['resample'] = _interpolation(kwargs) - - -def shear_x(img, factor, **kwargs): - _check_args_tf(kwargs) - return img.transform(img.size, Image.AFFINE, (1, factor, 0, 0, 1, 0), **kwargs) - -def shear_y_label(label, factor): - return affine_label(label, (1, factor, 0, 0, 1, 0)) - - -def shear_y(img, factor, **kwargs): - _check_args_tf(kwargs) - return img.transform(img.size, Image.AFFINE, (1, 0, 0, factor, 1, 0), **kwargs) - -def shear_x_label(label, factor): - return affine_label(label, (1, 0, 0, factor, 1, 0)) - -def translate_x_rel(img, pct, **kwargs): - pixels = pct * img.size[0] - _check_args_tf(kwargs) - return img.transform(img.size, Image.AFFINE, (1, 0, pixels, 0, 1, 0), **kwargs) - -def translate_y_rel_label(label, pct): - pixels = pct * label.size(2) - return affine_label(label, (1, 0, pixels, 0, 1, 0)) - - -def translate_y_rel(img, pct, **kwargs): - pixels = pct * img.size[1] - _check_args_tf(kwargs) - return img.transform(img.size, Image.AFFINE, (1, 0, 0, 0, 1, pixels), **kwargs) - -def translate_x_rel_label(label, pct): - pixels = pct * label.size(3) - return affine_label(label, (1, 0, 0, 0, 1, pixels)) - - -def translate_x_abs(img, pixels, **kwargs): - _check_args_tf(kwargs) - return img.transform(img.size, Image.AFFINE, (1, 0, pixels, 0, 1, 0), **kwargs) - - -def translate_y_abs(img, pixels, **kwargs): - _check_args_tf(kwargs) - return img.transform(img.size, Image.AFFINE, (1, 0, 0, 0, 1, pixels), **kwargs) - - -def rotate(img, degrees, **kwargs): - _check_args_tf(kwargs) - if _PIL_VER >= (5, 2): - return img.rotate(degrees, **kwargs) - elif _PIL_VER >= (5, 0): - w, h = img.size - post_trans = (0, 0) - rotn_center = (w / 2.0, h / 2.0) - angle = -math.radians(degrees) - matrix = [ - round(math.cos(angle), 15), - round(math.sin(angle), 15), - 0.0, - round(-math.sin(angle), 15), - round(math.cos(angle), 15), - 0.0, - ] - - def transform(x, y, matrix): - (a, b, c, d, e, f) = matrix - return a * x + b * y + c, d * x + e * y + f - - matrix[2], matrix[5] = transform( - -rotn_center[0] - post_trans[0], -rotn_center[1] - post_trans[1], matrix - ) - matrix[2] += rotn_center[0] - matrix[5] += rotn_center[1] - return img.transform(img.size, Image.AFFINE, matrix, **kwargs) - else: - return img.rotate(degrees, resample=kwargs['resample']) - -def rotate_label(label, degrees): - _,_, w, h = label.size() - post_trans = (0, 0) - rotn_center = (w / 2.0, h / 2.0) - angle = math.radians(degrees) - matrix = [ - round(math.cos(angle), 15), - round(math.sin(angle), 15), - 0.0, - round(-math.sin(angle), 15), - round(math.cos(angle), 15), - 0.0, - ] - - def transform(x, y, matrix): - (a, b, c, d, e, f) = matrix - return a * x + b * y + c, d * x + e * y + f - - matrix[2], matrix[5] = transform( - -rotn_center[0] - post_trans[0], -rotn_center[1] - post_trans[1], matrix - ) - matrix[2] += rotn_center[0] - matrix[5] += rotn_center[1] - return affine_label(label, matrix) - - -def auto_contrast(img, **__): - return ImageOps.autocontrast(img) - - -def invert(img, **__): - return ImageOps.invert(img) - - -def equalize(img, **__): - return ImageOps.equalize(img) - - -def solarize(img, thresh, **__): - return ImageOps.solarize(img, thresh) - - -def solarize_add(img, add, thresh=128, **__): - lut = [] - for i in range(256): - if i < thresh: - lut.append(min(255, i + add)) - else: - lut.append(i) - if img.mode in ("L", "RGB"): - if img.mode == "RGB" and len(lut) == 256: - lut = lut + lut + lut - return img.point(lut) - else: - return img - - -def posterize(img, bits_to_keep, **__): - if bits_to_keep >= 8: - return img - return ImageOps.posterize(img, bits_to_keep) - - -def contrast(img, factor, **__): - return ImageEnhance.Contrast(img).enhance(factor) - - -def color(img, factor, **__): - return ImageEnhance.Color(img).enhance(factor) - - -def brightness(img, factor, **__): - return ImageEnhance.Brightness(img).enhance(factor) - - -def sharpness(img, factor, **__): - return ImageEnhance.Sharpness(img).enhance(factor) - - -def _randomly_negate(v): - """With 50% prob, negate the value""" - return -v if random.random() > 0.5 else v - - -def _rotate_level_to_arg(level, _hparams): - # range [-30, 30] - level = (level / _MAX_LEVEL) * 30. - level = _randomly_negate(level) - return level, - - -def _enhance_level_to_arg(level, _hparams): - # range [0.1, 1.9] - return (level / _MAX_LEVEL) * 1.8 + 0.1, - - -def _enhance_increasing_level_to_arg(level, _hparams): - # the 'no change' level is 1.0, moving away from that towards 0. or 2.0 increases the enhancement blend - # range [0.1, 1.9] - level = (level / _MAX_LEVEL) * .9 - level = 1.0 + _randomly_negate(level) - return level, - - -def _shear_level_to_arg(level, _hparams): - # range [-0.3, 0.3] - level = (level / _MAX_LEVEL) * 0.3 - level = _randomly_negate(level) - return level, - - -def _translate_abs_level_to_arg(level, hparams): - translate_const = hparams['translate_const'] - level = (level / _MAX_LEVEL) * float(translate_const) - level = _randomly_negate(level) - return level, - - -def _translate_rel_level_to_arg(level, hparams): - # default range [-0.45, 0.45] - translate_pct = hparams.get('translate_pct', 0.45) - level = (level / _MAX_LEVEL) * translate_pct - level = _randomly_negate(level) - return level, - - -def _posterize_level_to_arg(level, _hparams): - # As per Tensorflow TPU EfficientNet impl - # range [0, 4], 'keep 0 up to 4 MSB of original image' - # intensity/severity of augmentation decreases with level - return int((level / _MAX_LEVEL) * 4), - - -def _posterize_increasing_level_to_arg(level, hparams): - # As per Tensorflow models research and UDA impl - # range [4, 0], 'keep 4 down to 0 MSB of original image', - # intensity/severity of augmentation increases with level - return 4 - _posterize_level_to_arg(level, hparams)[0], - - -def _posterize_original_level_to_arg(level, _hparams): - # As per original AutoAugment paper description - # range [4, 8], 'keep 4 up to 8 MSB of image' - # intensity/severity of augmentation decreases with level - return int((level / _MAX_LEVEL) * 4) + 4, - - -def _solarize_level_to_arg(level, _hparams): - # range [0, 256] - # intensity/severity of augmentation decreases with level - return int((level / _MAX_LEVEL) * 256), - - -def _solarize_increasing_level_to_arg(level, _hparams): - # range [0, 256] - # intensity/severity of augmentation increases with level - return 256 - _solarize_level_to_arg(level, _hparams)[0], - - -def _solarize_add_level_to_arg(level, _hparams): - # range [0, 110] - return int((level / _MAX_LEVEL) * 110), - -class AugmentOp: - - def __init__(self, name, prob=0.5, magnitude=10, hparams=None): - hparams = hparams or _HPARAMS_DEFAULT - self.name = name - self.aug_fn = NAME_TO_OP[name] - self.label_fn = NAME_TO_LABELOP[name] - self.level_fn = LEVEL_TO_ARG[name] - self.prob = prob - self.magnitude = magnitude - self.hparams = hparams.copy() - self.kwargs = dict( - fillcolor=hparams['img_mean'] if 'img_mean' in hparams else _FILL, - resample=hparams['interpolation'] if 'interpolation' in hparams else _RANDOM_INTERPOLATION, - ) - - # If magnitude_std is > 0, we introduce some randomness - # in the usually fixed policy and sample magnitude from a normal distribution - # with mean `magnitude` and std-dev of `magnitude_std`. - # NOTE This is my own hack, being tested, not in papers or reference impls. - self.magnitude_std = self.hparams.get('magnitude_std', 0) - - def __call__(self, img, label): - if self.prob < 1.0 and random.random() > self.prob: - return img, label - magnitude = self.magnitude - if self.magnitude_std and self.magnitude_std > 0: - magnitude = random.gauss(magnitude, self.magnitude_std) - magnitude = min(_MAX_LEVEL, max(0, magnitude)) # clip to valid range - level_args = self.level_fn(magnitude, self.hparams) if self.level_fn is not None else tuple() - if self.label_fn is not None: - - aug_label = self.label_fn(label, *level_args) - else: - aug_label = label - return self.aug_fn(img, *level_args, **self.kwargs), aug_label - -LEVEL_TO_ARG = { - 'AutoContrast': None, - 'Equalize': None, - 'Invert': None, - 'Rotate': _rotate_level_to_arg, - # There are several variations of the posterize level scaling in various Tensorflow/Google repositories/papers - 'Posterize': _posterize_level_to_arg, - 'PosterizeIncreasing': _posterize_increasing_level_to_arg, - 'PosterizeOriginal': _posterize_original_level_to_arg, - 'Solarize': _solarize_level_to_arg, - 'SolarizeIncreasing': _solarize_increasing_level_to_arg, - 'SolarizeAdd': _solarize_add_level_to_arg, - 'Color': _enhance_level_to_arg, - 'ColorIncreasing': _enhance_increasing_level_to_arg, - 'Contrast': _enhance_level_to_arg, - 'ContrastIncreasing': _enhance_increasing_level_to_arg, - 'Brightness': _enhance_level_to_arg, - 'BrightnessIncreasing': _enhance_increasing_level_to_arg, - 'Sharpness': _enhance_level_to_arg, - 'SharpnessIncreasing': _enhance_increasing_level_to_arg, - 'ShearX': _shear_level_to_arg, - 'ShearY': _shear_level_to_arg, - 'TranslateX': _translate_abs_level_to_arg, - 'TranslateY': _translate_abs_level_to_arg, - 'TranslateXRel': _translate_rel_level_to_arg, - 'TranslateYRel': _translate_rel_level_to_arg, -} - - -NAME_TO_OP = { - 'AutoContrast': auto_contrast, - 'Equalize': equalize, - 'Invert': invert, - 'Rotate': rotate, - 'Posterize': posterize, - 'PosterizeIncreasing': posterize, - 'PosterizeOriginal': posterize, - 'Solarize': solarize, - 'SolarizeIncreasing': solarize, - 'SolarizeAdd': solarize_add, - 'Color': color, - 'ColorIncreasing': color, - 'Contrast': contrast, - 'ContrastIncreasing': contrast, - 'Brightness': brightness, - 'BrightnessIncreasing': brightness, - 'Sharpness': sharpness, - 'SharpnessIncreasing': sharpness, - 'ShearX': shear_x, - 'ShearY': shear_y, - 'TranslateX': translate_x_abs, - 'TranslateY': translate_y_abs, - 'TranslateXRel': translate_x_rel, - 'TranslateYRel': translate_y_rel, -} -# Remove TranslateX and TranslateY here since it is actually not used in random aug -# Only spatial op should be applied to the label map -NAME_TO_LABELOP = { - 'AutoContrast': None, - 'Equalize': None, - 'Invert': None, - 'Rotate': rotate_label, - 'Posterize': None, - 'PosterizeIncreasing': None, - 'PosterizeOriginal': None, - 'Solarize': None, - 'SolarizeIncreasing': None, - 'SolarizeAdd': None, - 'Color': None, - 'ColorIncreasing': None, - 'Contrast': None, - 'ContrastIncreasing': None, - 'Brightness': None, - 'BrightnessIncreasing': None, - 'Sharpness': None, - 'SharpnessIncreasing': None, - 'ShearX': shear_x_label, - 'ShearY': shear_y_label, - 'TranslateX': None, - 'TranslateY': None, - 'TranslateXRel': translate_x_rel_label, - 'TranslateYRel': translate_y_rel_label, -} - - -_RAND_TRANSFORMS = [ - 'AutoContrast', - 'Equalize', - 'Invert', - 'Rotate', - 'Posterize', - 'Solarize', - 'SolarizeAdd', - 'Color', - 'Contrast', - 'Brightness', - 'Sharpness', - 'ShearX', - 'ShearY', - 'TranslateXRel', - 'TranslateYRel', - #'Cutout' -] - - -_RAND_INCREASING_TRANSFORMS = [ - 'AutoContrast', - 'Equalize', - 'Invert', - 'Rotate', - 'PosterizeIncreasing', - 'SolarizeIncreasing', - 'SolarizeAdd', - 'ColorIncreasing', - 'ContrastIncreasing', - 'BrightnessIncreasing', - 'SharpnessIncreasing', - 'ShearX', - 'ShearY', - 'TranslateXRel', - 'TranslateYRel', - #'Cutout' -] - - - -# These experimental weights are based loosely on the relative improvements mentioned in paper. -# They may not result in increased performance, but could likely be tuned to so. -_RAND_CHOICE_WEIGHTS_0 = { - 'Rotate': 0.3, - 'ShearX': 0.2, - 'ShearY': 0.2, - 'TranslateXRel': 0.1, - 'TranslateYRel': 0.1, - 'Color': .025, - 'Sharpness': 0.025, - 'AutoContrast': 0.025, - 'Solarize': .005, - 'SolarizeAdd': .005, - 'Contrast': .005, - 'Brightness': .005, - 'Equalize': .005, - 'Posterize': 0, - 'Invert': 0, -} - - -def _select_rand_weights(weight_idx=0, transforms=None): - transforms = transforms or _RAND_TRANSFORMS - assert weight_idx == 0 # only one set of weights currently - rand_weights = _RAND_CHOICE_WEIGHTS_0 - probs = [rand_weights[k] for k in transforms] - probs /= np.sum(probs) - return probs - - -def rand_augment_ops(magnitude=10, hparams=None, transforms=None): - hparams = hparams or _HPARAMS_DEFAULT - transforms = transforms or _RAND_TRANSFORMS - return [AugmentOp( - name, prob=0.5, magnitude=magnitude, hparams=hparams) for name in transforms] - - -class RandAugment: - ''' - Apply RandAug on both image and dense label map - ''' - def __init__(self, ops, num_layers=2, choice_weights=None): - self.ops = ops - self.num_layers = num_layers - self.choice_weights = choice_weights - - def __call__(self, img, label): - # no replacement when using weighted choice - ops = np.random.choice( - self.ops, self.num_layers, replace=self.choice_weights is None, p=self.choice_weights) - for op in ops: - img, label = op(img, label) - return img, label - - -def rand_augment_transform(config_str, hparams): - """ - Create a RandAugment transform with label - :param config_str: String defining configuration of random augmentation. Consists of multiple sections separated by - dashes ('-'). The first section defines the specific variant of rand augment (currently only 'rand'). The remaining - sections, not order sepecific determine - 'm' - integer magnitude of rand augment - 'n' - integer num layers (number of transform ops selected per image) - 'w' - integer probabiliy weight index (index of a set of weights to influence choice of op) - 'mstd' - float std deviation of magnitude noise applied - 'inc' - integer (bool), use augmentations that increase in severity with magnitude (default: 0) - Ex 'rand-m9-n3-mstd0.5' results in RandAugment with magnitude 9, num_layers 3, magnitude_std 0.5 - 'rand-mstd1-w0' results in magnitude_std 1.0, weights 0, default magnitude of 10 and num_layers 2 - - :param hparams: Other hparams (kwargs) for the RandAugmentation scheme - - :return: A PyTorch compatible Transform - """ - magnitude = _MAX_LEVEL # default to _MAX_LEVEL for magnitude (currently 10) - num_layers = 2 # default to 2 ops per image - weight_idx = None # default to no probability weights for op choice - transforms = _RAND_TRANSFORMS - config = config_str.split('-') - assert config[0] == 'rand' - config = config[1:] - for c in config: - cs = re.split(r'(\d.*)', c) - if len(cs) < 2: - continue - key, val = cs[:2] - if key == 'mstd': - # noise param injected via hparams for now - hparams.setdefault('magnitude_std', float(val)) - elif key == 'inc': - if bool(val): - transforms = _RAND_INCREASING_TRANSFORMS - elif key == 'm': - magnitude = int(val) - elif key == 'n': - num_layers = int(val) - elif key == 'w': - weight_idx = int(val) - else: - assert False, 'Unknown RandAugment config section' - ra_ops = rand_augment_ops(magnitude=magnitude, hparams=hparams, transforms=transforms) - choice_weights = None if weight_idx is None else _select_rand_weights(weight_idx) - return RandAugment(ra_ops, num_layers, choice_weights=choice_weights) - +""" +BSD 3-Clause License + +Copyright (c) Soumith Chintala 2016, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Copyright 2020 Huawei Technologies Co., Ltd + +Licensed under the BSD 3-Clause License (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://spdx.org/licenses/BSD-3-Clause.html + +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. +""" +""" +Adapted from https://github.com/rwightman/pytorch-image-models/blob/master/timm/data/auto_augment.py and modified for token labeling +AutoAugment, RandAugment +""" +import random +import math +import re +from PIL import Image, ImageOps, ImageEnhance, ImageChops +import PIL +import numpy as np +from scipy import ndimage +import torch + +_PIL_VER = tuple([int(x) for x in PIL.__version__.split('.')[:2]]) + +_FILL = (128, 128, 128) + + + +# This signifies the max integer that the controller RNN could predict for the +# augmentation scheme. +_MAX_LEVEL = 10. + +_HPARAMS_DEFAULT = dict( + translate_const=250, + img_mean=_FILL, +) + +_RANDOM_INTERPOLATION = (Image.BILINEAR, Image.BICUBIC) + + +def _interpolation(kwargs): + interpolation = kwargs.pop('resample', Image.BILINEAR) + if isinstance(interpolation, (list, tuple)): + return random.choice(interpolation) + else: + return interpolation + +def affine_label(label, matrix): + + # label: 2, k, H, W + # label[0] value, label[1] index + a,b,c,d,e,f = matrix + affine_matrix = [[1,0,0,0],[0,a,b,c],[0,d,e,f]] + value = ndimage.affine_transform(label[0],matrix=affine_matrix, order=0, mode="constant") + index = ndimage.affine_transform(label[1],matrix=affine_matrix, order=0, mode="nearest") + + return torch.from_numpy(np.stack([value, index],axis=0)) + +def _check_args_tf(kwargs): + if 'fillcolor' in kwargs and _PIL_VER < (5, 0): + kwargs.pop('fillcolor') + kwargs['resample'] = _interpolation(kwargs) + + +def shear_x(img, factor, **kwargs): + _check_args_tf(kwargs) + return img.transform(img.size, Image.AFFINE, (1, factor, 0, 0, 1, 0), **kwargs) + +def shear_y_label(label, factor): + return affine_label(label, (1, factor, 0, 0, 1, 0)) + + +def shear_y(img, factor, **kwargs): + _check_args_tf(kwargs) + return img.transform(img.size, Image.AFFINE, (1, 0, 0, factor, 1, 0), **kwargs) + +def shear_x_label(label, factor): + return affine_label(label, (1, 0, 0, factor, 1, 0)) + +def translate_x_rel(img, pct, **kwargs): + pixels = pct * img.size[0] + _check_args_tf(kwargs) + return img.transform(img.size, Image.AFFINE, (1, 0, pixels, 0, 1, 0), **kwargs) + +def translate_y_rel_label(label, pct): + pixels = pct * label.size(2) + return affine_label(label, (1, 0, pixels, 0, 1, 0)) + + +def translate_y_rel(img, pct, **kwargs): + pixels = pct * img.size[1] + _check_args_tf(kwargs) + return img.transform(img.size, Image.AFFINE, (1, 0, 0, 0, 1, pixels), **kwargs) + +def translate_x_rel_label(label, pct): + pixels = pct * label.size(3) + return affine_label(label, (1, 0, 0, 0, 1, pixels)) + + +def translate_x_abs(img, pixels, **kwargs): + _check_args_tf(kwargs) + return img.transform(img.size, Image.AFFINE, (1, 0, pixels, 0, 1, 0), **kwargs) + + +def translate_y_abs(img, pixels, **kwargs): + _check_args_tf(kwargs) + return img.transform(img.size, Image.AFFINE, (1, 0, 0, 0, 1, pixels), **kwargs) + + +def rotate(img, degrees, **kwargs): + _check_args_tf(kwargs) + if _PIL_VER >= (5, 2): + return img.rotate(degrees, **kwargs) + elif _PIL_VER >= (5, 0): + w, h = img.size + post_trans = (0, 0) + rotn_center = (w / 2.0, h / 2.0) + angle = -math.radians(degrees) + matrix = [ + round(math.cos(angle), 15), + round(math.sin(angle), 15), + 0.0, + round(-math.sin(angle), 15), + round(math.cos(angle), 15), + 0.0, + ] + + def transform(x, y, matrix): + (a, b, c, d, e, f) = matrix + return a * x + b * y + c, d * x + e * y + f + + matrix[2], matrix[5] = transform( + -rotn_center[0] - post_trans[0], -rotn_center[1] - post_trans[1], matrix + ) + matrix[2] += rotn_center[0] + matrix[5] += rotn_center[1] + return img.transform(img.size, Image.AFFINE, matrix, **kwargs) + else: + return img.rotate(degrees, resample=kwargs['resample']) + +def rotate_label(label, degrees): + _,_, w, h = label.size() + post_trans = (0, 0) + rotn_center = (w / 2.0, h / 2.0) + angle = math.radians(degrees) + matrix = [ + round(math.cos(angle), 15), + round(math.sin(angle), 15), + 0.0, + round(-math.sin(angle), 15), + round(math.cos(angle), 15), + 0.0, + ] + + def transform(x, y, matrix): + (a, b, c, d, e, f) = matrix + return a * x + b * y + c, d * x + e * y + f + + matrix[2], matrix[5] = transform( + -rotn_center[0] - post_trans[0], -rotn_center[1] - post_trans[1], matrix + ) + matrix[2] += rotn_center[0] + matrix[5] += rotn_center[1] + return affine_label(label, matrix) + + +def auto_contrast(img, **__): + return ImageOps.autocontrast(img) + + +def invert(img, **__): + return ImageOps.invert(img) + + +def equalize(img, **__): + return ImageOps.equalize(img) + + +def solarize(img, thresh, **__): + return ImageOps.solarize(img, thresh) + + +def solarize_add(img, add, thresh=128, **__): + lut = [] + for i in range(256): + if i < thresh: + lut.append(min(255, i + add)) + else: + lut.append(i) + if img.mode in ("L", "RGB"): + if img.mode == "RGB" and len(lut) == 256: + lut = lut + lut + lut + return img.point(lut) + else: + return img + + +def posterize(img, bits_to_keep, **__): + if bits_to_keep >= 8: + return img + return ImageOps.posterize(img, bits_to_keep) + + +def contrast(img, factor, **__): + return ImageEnhance.Contrast(img).enhance(factor) + + +def color(img, factor, **__): + return ImageEnhance.Color(img).enhance(factor) + + +def brightness(img, factor, **__): + return ImageEnhance.Brightness(img).enhance(factor) + + +def sharpness(img, factor, **__): + return ImageEnhance.Sharpness(img).enhance(factor) + + +def _randomly_negate(v): + """With 50% prob, negate the value""" + return -v if random.random() > 0.5 else v + + +def _rotate_level_to_arg(level, _hparams): + # range [-30, 30] + level = (level / _MAX_LEVEL) * 30. + level = _randomly_negate(level) + return level, + + +def _enhance_level_to_arg(level, _hparams): + # range [0.1, 1.9] + return (level / _MAX_LEVEL) * 1.8 + 0.1, + + +def _enhance_increasing_level_to_arg(level, _hparams): + # the 'no change' level is 1.0, moving away from that towards 0. or 2.0 increases the enhancement blend + # range [0.1, 1.9] + level = (level / _MAX_LEVEL) * .9 + level = 1.0 + _randomly_negate(level) + return level, + + +def _shear_level_to_arg(level, _hparams): + # range [-0.3, 0.3] + level = (level / _MAX_LEVEL) * 0.3 + level = _randomly_negate(level) + return level, + + +def _translate_abs_level_to_arg(level, hparams): + translate_const = hparams['translate_const'] + level = (level / _MAX_LEVEL) * float(translate_const) + level = _randomly_negate(level) + return level, + + +def _translate_rel_level_to_arg(level, hparams): + # default range [-0.45, 0.45] + translate_pct = hparams.get('translate_pct', 0.45) + level = (level / _MAX_LEVEL) * translate_pct + level = _randomly_negate(level) + return level, + + +def _posterize_level_to_arg(level, _hparams): + # As per Tensorflow TPU EfficientNet impl + # range [0, 4], 'keep 0 up to 4 MSB of original image' + # intensity/severity of augmentation decreases with level + return int((level / _MAX_LEVEL) * 4), + + +def _posterize_increasing_level_to_arg(level, hparams): + # As per Tensorflow models research and UDA impl + # range [4, 0], 'keep 4 down to 0 MSB of original image', + # intensity/severity of augmentation increases with level + return 4 - _posterize_level_to_arg(level, hparams)[0], + + +def _posterize_original_level_to_arg(level, _hparams): + # As per original AutoAugment paper description + # range [4, 8], 'keep 4 up to 8 MSB of image' + # intensity/severity of augmentation decreases with level + return int((level / _MAX_LEVEL) * 4) + 4, + + +def _solarize_level_to_arg(level, _hparams): + # range [0, 256] + # intensity/severity of augmentation decreases with level + return int((level / _MAX_LEVEL) * 256), + + +def _solarize_increasing_level_to_arg(level, _hparams): + # range [0, 256] + # intensity/severity of augmentation increases with level + return 256 - _solarize_level_to_arg(level, _hparams)[0], + + +def _solarize_add_level_to_arg(level, _hparams): + # range [0, 110] + return int((level / _MAX_LEVEL) * 110), + +class AugmentOp: + + def __init__(self, name, prob=0.5, magnitude=10, hparams=None): + hparams = hparams or _HPARAMS_DEFAULT + self.name = name + self.aug_fn = NAME_TO_OP[name] + self.label_fn = NAME_TO_LABELOP[name] + self.level_fn = LEVEL_TO_ARG[name] + self.prob = prob + self.magnitude = magnitude + self.hparams = hparams.copy() + self.kwargs = dict( + fillcolor=hparams['img_mean'] if 'img_mean' in hparams else _FILL, + resample=hparams['interpolation'] if 'interpolation' in hparams else _RANDOM_INTERPOLATION, + ) + + # If magnitude_std is > 0, we introduce some randomness + # in the usually fixed policy and sample magnitude from a normal distribution + # with mean `magnitude` and std-dev of `magnitude_std`. + # NOTE This is my own hack, being tested, not in papers or reference impls. + self.magnitude_std = self.hparams.get('magnitude_std', 0) + + def __call__(self, img, label): + if self.prob < 1.0 and random.random() > self.prob: + return img, label + magnitude = self.magnitude + if self.magnitude_std and self.magnitude_std > 0: + magnitude = random.gauss(magnitude, self.magnitude_std) + magnitude = min(_MAX_LEVEL, max(0, magnitude)) # clip to valid range + level_args = self.level_fn(magnitude, self.hparams) if self.level_fn is not None else tuple() + if self.label_fn is not None: + + aug_label = self.label_fn(label, *level_args) + else: + aug_label = label + return self.aug_fn(img, *level_args, **self.kwargs), aug_label + +LEVEL_TO_ARG = { + 'AutoContrast': None, + 'Equalize': None, + 'Invert': None, + 'Rotate': _rotate_level_to_arg, + # There are several variations of the posterize level scaling in various Tensorflow/Google repositories/papers + 'Posterize': _posterize_level_to_arg, + 'PosterizeIncreasing': _posterize_increasing_level_to_arg, + 'PosterizeOriginal': _posterize_original_level_to_arg, + 'Solarize': _solarize_level_to_arg, + 'SolarizeIncreasing': _solarize_increasing_level_to_arg, + 'SolarizeAdd': _solarize_add_level_to_arg, + 'Color': _enhance_level_to_arg, + 'ColorIncreasing': _enhance_increasing_level_to_arg, + 'Contrast': _enhance_level_to_arg, + 'ContrastIncreasing': _enhance_increasing_level_to_arg, + 'Brightness': _enhance_level_to_arg, + 'BrightnessIncreasing': _enhance_increasing_level_to_arg, + 'Sharpness': _enhance_level_to_arg, + 'SharpnessIncreasing': _enhance_increasing_level_to_arg, + 'ShearX': _shear_level_to_arg, + 'ShearY': _shear_level_to_arg, + 'TranslateX': _translate_abs_level_to_arg, + 'TranslateY': _translate_abs_level_to_arg, + 'TranslateXRel': _translate_rel_level_to_arg, + 'TranslateYRel': _translate_rel_level_to_arg, +} + + +NAME_TO_OP = { + 'AutoContrast': auto_contrast, + 'Equalize': equalize, + 'Invert': invert, + 'Rotate': rotate, + 'Posterize': posterize, + 'PosterizeIncreasing': posterize, + 'PosterizeOriginal': posterize, + 'Solarize': solarize, + 'SolarizeIncreasing': solarize, + 'SolarizeAdd': solarize_add, + 'Color': color, + 'ColorIncreasing': color, + 'Contrast': contrast, + 'ContrastIncreasing': contrast, + 'Brightness': brightness, + 'BrightnessIncreasing': brightness, + 'Sharpness': sharpness, + 'SharpnessIncreasing': sharpness, + 'ShearX': shear_x, + 'ShearY': shear_y, + 'TranslateX': translate_x_abs, + 'TranslateY': translate_y_abs, + 'TranslateXRel': translate_x_rel, + 'TranslateYRel': translate_y_rel, +} +# Remove TranslateX and TranslateY here since it is actually not used in random aug +# Only spatial op should be applied to the label map +NAME_TO_LABELOP = { + 'AutoContrast': None, + 'Equalize': None, + 'Invert': None, + 'Rotate': rotate_label, + 'Posterize': None, + 'PosterizeIncreasing': None, + 'PosterizeOriginal': None, + 'Solarize': None, + 'SolarizeIncreasing': None, + 'SolarizeAdd': None, + 'Color': None, + 'ColorIncreasing': None, + 'Contrast': None, + 'ContrastIncreasing': None, + 'Brightness': None, + 'BrightnessIncreasing': None, + 'Sharpness': None, + 'SharpnessIncreasing': None, + 'ShearX': shear_x_label, + 'ShearY': shear_y_label, + 'TranslateX': None, + 'TranslateY': None, + 'TranslateXRel': translate_x_rel_label, + 'TranslateYRel': translate_y_rel_label, +} + + +_RAND_TRANSFORMS = [ + 'AutoContrast', + 'Equalize', + 'Invert', + 'Rotate', + 'Posterize', + 'Solarize', + 'SolarizeAdd', + 'Color', + 'Contrast', + 'Brightness', + 'Sharpness', + 'ShearX', + 'ShearY', + 'TranslateXRel', + 'TranslateYRel', + #'Cutout' +] + + +_RAND_INCREASING_TRANSFORMS = [ + 'AutoContrast', + 'Equalize', + 'Invert', + 'Rotate', + 'PosterizeIncreasing', + 'SolarizeIncreasing', + 'SolarizeAdd', + 'ColorIncreasing', + 'ContrastIncreasing', + 'BrightnessIncreasing', + 'SharpnessIncreasing', + 'ShearX', + 'ShearY', + 'TranslateXRel', + 'TranslateYRel', + #'Cutout' +] + + + +# These experimental weights are based loosely on the relative improvements mentioned in paper. +# They may not result in increased performance, but could likely be tuned to so. +_RAND_CHOICE_WEIGHTS_0 = { + 'Rotate': 0.3, + 'ShearX': 0.2, + 'ShearY': 0.2, + 'TranslateXRel': 0.1, + 'TranslateYRel': 0.1, + 'Color': .025, + 'Sharpness': 0.025, + 'AutoContrast': 0.025, + 'Solarize': .005, + 'SolarizeAdd': .005, + 'Contrast': .005, + 'Brightness': .005, + 'Equalize': .005, + 'Posterize': 0, + 'Invert': 0, +} + + +def _select_rand_weights(weight_idx=0, transforms=None): + transforms = transforms or _RAND_TRANSFORMS + assert weight_idx == 0 # only one set of weights currently + rand_weights = _RAND_CHOICE_WEIGHTS_0 + probs = [rand_weights[k] for k in transforms] + probs /= np.sum(probs) + return probs + + +def rand_augment_ops(magnitude=10, hparams=None, transforms=None): + hparams = hparams or _HPARAMS_DEFAULT + transforms = transforms or _RAND_TRANSFORMS + return [AugmentOp( + name, prob=0.5, magnitude=magnitude, hparams=hparams) for name in transforms] + + +class RandAugment: + ''' + Apply RandAug on both image and dense label map + ''' + def __init__(self, ops, num_layers=2, choice_weights=None): + self.ops = ops + self.num_layers = num_layers + self.choice_weights = choice_weights + + def __call__(self, img, label): + # no replacement when using weighted choice + ops = np.random.choice( + self.ops, self.num_layers, replace=self.choice_weights is None, p=self.choice_weights) + for op in ops: + img, label = op(img, label) + return img, label + + +def rand_augment_transform(config_str, hparams): + """ + Create a RandAugment transform with label + :param config_str: String defining configuration of random augmentation. Consists of multiple sections separated by + dashes ('-'). The first section defines the specific variant of rand augment (currently only 'rand'). The remaining + sections, not order sepecific determine + 'm' - integer magnitude of rand augment + 'n' - integer num layers (number of transform ops selected per image) + 'w' - integer probabiliy weight index (index of a set of weights to influence choice of op) + 'mstd' - float std deviation of magnitude noise applied + 'inc' - integer (bool), use augmentations that increase in severity with magnitude (default: 0) + Ex 'rand-m9-n3-mstd0.5' results in RandAugment with magnitude 9, num_layers 3, magnitude_std 0.5 + 'rand-mstd1-w0' results in magnitude_std 1.0, weights 0, default magnitude of 10 and num_layers 2 + + :param hparams: Other hparams (kwargs) for the RandAugmentation scheme + + :return: A PyTorch compatible Transform + """ + magnitude = _MAX_LEVEL # default to _MAX_LEVEL for magnitude (currently 10) + num_layers = 2 # default to 2 ops per image + weight_idx = None # default to no probability weights for op choice + transforms = _RAND_TRANSFORMS + config = config_str.split('-') + assert config[0] == 'rand' + config = config[1:] + for c in config: + cs = re.split(r'(\d.*)', c) + if len(cs) < 2: + continue + key, val = cs[:2] + if key == 'mstd': + # noise param injected via hparams for now + hparams.setdefault('magnitude_std', float(val)) + elif key == 'inc': + if bool(val): + transforms = _RAND_INCREASING_TRANSFORMS + elif key == 'm': + magnitude = int(val) + elif key == 'n': + num_layers = int(val) + elif key == 'w': + weight_idx = int(val) + else: + assert False, 'Unknown RandAugment config section' + ra_ops = rand_augment_ops(magnitude=magnitude, hparams=hparams, transforms=transforms) + choice_weights = None if weight_idx is None else _select_rand_weights(weight_idx) + return RandAugment(ra_ops, num_layers, choice_weights=choice_weights) + diff --git a/PyTorch/contrib/cv/classification/VOLO/tlt/loss/__init__.py b/PyTorch/contrib/cv/classification/VOLO/tlt/loss/__init__.py index 47166af5c8..e101959521 100644 --- a/PyTorch/contrib/cv/classification/VOLO/tlt/loss/__init__.py +++ b/PyTorch/contrib/cv/classification/VOLO/tlt/loss/__init__.py @@ -1,47 +1,47 @@ -""" -BSD 3-Clause License - -Copyright (c) Soumith Chintala 2016, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -Copyright 2020 Huawei Technologies Co., Ltd - -Licensed under the BSD 3-Clause License (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -https://spdx.org/licenses/BSD-3-Clause.html - -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. -""" +""" +BSD 3-Clause License + +Copyright (c) Soumith Chintala 2016, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Copyright 2020 Huawei Technologies Co., Ltd + +Licensed under the BSD 3-Clause License (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://spdx.org/licenses/BSD-3-Clause.html + +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 .cross_entropy import TokenLabelCrossEntropy,TokenLabelSoftTargetCrossEntropy \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/VOLO/tlt/utils/__init__.py b/PyTorch/contrib/cv/classification/VOLO/tlt/utils/__init__.py index a53b3e9888..39dd95c737 100644 --- a/PyTorch/contrib/cv/classification/VOLO/tlt/utils/__init__.py +++ b/PyTorch/contrib/cv/classification/VOLO/tlt/utils/__init__.py @@ -1,47 +1,47 @@ -""" -BSD 3-Clause License - -Copyright (c) Soumith Chintala 2016, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -Copyright 2020 Huawei Technologies Co., Ltd - -Licensed under the BSD 3-Clause License (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -https://spdx.org/licenses/BSD-3-Clause.html - -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. -""" +""" +BSD 3-Clause License + +Copyright (c) Soumith Chintala 2016, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Copyright 2020 Huawei Technologies Co., Ltd + +Licensed under the BSD 3-Clause License (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://spdx.org/licenses/BSD-3-Clause.html + +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 .utils import load_pretrained_weights \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/VOLO/utils/__init__.py b/PyTorch/contrib/cv/classification/VOLO/utils/__init__.py index a53b3e9888..39dd95c737 100644 --- a/PyTorch/contrib/cv/classification/VOLO/utils/__init__.py +++ b/PyTorch/contrib/cv/classification/VOLO/utils/__init__.py @@ -1,47 +1,47 @@ -""" -BSD 3-Clause License - -Copyright (c) Soumith Chintala 2016, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -Copyright 2020 Huawei Technologies Co., Ltd - -Licensed under the BSD 3-Clause License (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -https://spdx.org/licenses/BSD-3-Clause.html - -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. -""" +""" +BSD 3-Clause License + +Copyright (c) Soumith Chintala 2016, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Copyright 2020 Huawei Technologies Co., Ltd + +Licensed under the BSD 3-Clause License (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://spdx.org/licenses/BSD-3-Clause.html + +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 .utils import load_pretrained_weights \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/Vgg16_ID1630_for_PyTorch/modelzoo_level.txt b/PyTorch/contrib/cv/classification/Vgg16_ID1630_for_PyTorch/modelzoo_level.txt index 5afcef9188..3117fffc3b 100644 --- a/PyTorch/contrib/cv/classification/Vgg16_ID1630_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/contrib/cv/classification/Vgg16_ID1630_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:NOK +FuncStatus:OK +PerfStatus:NOK PrecisionStatus:POK \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/Vgg19_ID1631_for_PyTorch/modelzoo_level.txt b/PyTorch/contrib/cv/classification/Vgg19_ID1631_for_PyTorch/modelzoo_level.txt index 5afcef9188..3117fffc3b 100644 --- a/PyTorch/contrib/cv/classification/Vgg19_ID1631_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/contrib/cv/classification/Vgg19_ID1631_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:NOK +FuncStatus:OK +PerfStatus:NOK PrecisionStatus:POK \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/Vit_small_patch16_224/README.md b/PyTorch/contrib/cv/classification/Vit_small_patch16_224/README.md index 57d445ce4f..f2705c491b 100644 --- a/PyTorch/contrib/cv/classification/Vit_small_patch16_224/README.md +++ b/PyTorch/contrib/cv/classification/Vit_small_patch16_224/README.md @@ -1,55 +1,55 @@ -# Vit_small_patch16_224 - -This implements training of vit_small_patch16_224 on the ImageNet-2012 dataset, mainly modified from [rwightman/pytorch-image-models](https://github.com/rwightman/pytorch-image-models). - -## Vit_small_patch16_224 Detail - -As of the current date, Ascend-Pytorch is still inefficient for contiguous operations.Therefore, vit_small_patch16_224 is re-implemented using semantics such as custom OP. - - -## Requirements - -- Install PyTorch ([pytorch.org](http://pytorch.org)) - -- `pip install -r requirements.txt` - -- Download the Imagenet-2012 dataset. Refer to the original repository https://github.com/rwightman/pytorch-image-models - - -## Training - -To train a model, run `train.py` with the desired model architecture and the path to the Imagenet-2012 dataset: - -```bash -# training 1p accuracy -bash test/train_full_1p.sh --data_path=real_data_path - -# training 1p performance -bash test/train_performance_1p.sh --data_path=real_data_path - -# training 8p accuracy -bash test/train_full_8p.sh --data_path=real_data_path - -# training 8p performance -bash test/train_performance_8p.sh --data_path=real_data_path - -# finetune -bash test/train_finetune_1p.sh --data_path=real_data_path --weight=real_weight_path - -# Online inference demo -python demo.py --checkpoint real_checkpoint_path - -# To ONNX -python pthtar2onnx.py -``` - -## Vit_small_patch16_224 training result - - -| | top1 | AMP_Type | Epochs | FPS | -| :----: | :---: | :------: | :----: | :-----: | -| 1p-GPU | - | O2 | 1 | 586.67 | -| 1p-NPU | - | O2 | 1 | 304.06 | -| 8p-GPU | 67.65 | O2 | 100 | 4556.28 | -| 8p-NPU | 67.67 | O2 | 100 | 2373.80 | - +# Vit_small_patch16_224 + +This implements training of vit_small_patch16_224 on the ImageNet-2012 dataset, mainly modified from [rwightman/pytorch-image-models](https://github.com/rwightman/pytorch-image-models). + +## Vit_small_patch16_224 Detail + +As of the current date, Ascend-Pytorch is still inefficient for contiguous operations.Therefore, vit_small_patch16_224 is re-implemented using semantics such as custom OP. + + +## Requirements + +- Install PyTorch ([pytorch.org](http://pytorch.org)) + +- `pip install -r requirements.txt` + +- Download the Imagenet-2012 dataset. Refer to the original repository https://github.com/rwightman/pytorch-image-models + + +## Training + +To train a model, run `train.py` with the desired model architecture and the path to the Imagenet-2012 dataset: + +```bash +# training 1p accuracy +bash test/train_full_1p.sh --data_path=real_data_path + +# training 1p performance +bash test/train_performance_1p.sh --data_path=real_data_path + +# training 8p accuracy +bash test/train_full_8p.sh --data_path=real_data_path + +# training 8p performance +bash test/train_performance_8p.sh --data_path=real_data_path + +# finetune +bash test/train_finetune_1p.sh --data_path=real_data_path --weight=real_weight_path + +# Online inference demo +python demo.py --checkpoint real_checkpoint_path + +# To ONNX +python pthtar2onnx.py +``` + +## Vit_small_patch16_224 training result + + +| | top1 | AMP_Type | Epochs | FPS | +| :----: | :---: | :------: | :----: | :-----: | +| 1p-GPU | - | O2 | 1 | 586.67 | +| 1p-NPU | - | O2 | 1 | 304.06 | +| 8p-GPU | 67.65 | O2 | 100 | 4556.28 | +| 8p-NPU | 67.67 | O2 | 100 | 2373.80 | + diff --git a/PyTorch/contrib/cv/classification/Vit_small_patch16_224/demo.py b/PyTorch/contrib/cv/classification/Vit_small_patch16_224/demo.py index fcad4e7d2a..87fd6c849b 100644 --- a/PyTorch/contrib/cv/classification/Vit_small_patch16_224/demo.py +++ b/PyTorch/contrib/cv/classification/Vit_small_patch16_224/demo.py @@ -1,85 +1,85 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import torch -import torchvision -from torchvision import datasets, transforms -from collections import OrderedDict - -from timm.models import create_model - -parser = argparse.ArgumentParser(description='ImageNet Training') -parser.add_argument('--checkpoint', type=str, default='', - help='checkpoint path') -args = parser.parse_args() - -def proc_node_module(checkpoint, attr_name): - new_state_dict = OrderedDict() - for k, v in checkpoint[attr_name].items(): - if(k[0: 7] == "module."): - name = k[7:] - else: - name = k[0:] - new_state_dict[name] = v - return new_state_dict - -def get_raw_data(): - from PIL import Image - from urllib.request import urlretrieve - IMAGE_URL = 'https://bbs-img.huaweicloud.com/blogs/img/thumb/1591951315139_8989_1363.png' - urlretrieve(IMAGE_URL, 'tmp.jpg') - img = Image.open("tmp.jpg") - img = img.convert('RGB') - return img - -def test(): - loc = 'npu:0' - loc_cpu = 'cpu' - torch.npu.set_device(loc) - if args.checkpoint == '': - print("please give the checkpoint path using --checkpoint param") - exit(0) - checkpoint = torch.load(args.checkpoint, map_location=loc) - checkpoint['state_dict'] = proc_node_module(checkpoint, 'state_dict') - - model = create_model('vit_small_patch16_224', pretrained=False) - - model = model.to(loc) - model.load_state_dict(checkpoint['state_dict']) - model.eval() - - normalize = transforms.Normalize(mean=[0.5, 0.5, 0.5], - std=[0.5, 0.5, 0.5]) - rd = get_raw_data() - data_transfrom = transforms.Compose([ - transforms.RandomResizedCrop(224,interpolation=3), - transforms.RandomHorizontalFlip(), - transforms.ToTensor(), - normalize, - ]) - - inputs = data_transfrom(rd) - inputs = inputs.unsqueeze(0) - inputs = inputs.to(loc) - output = model(inputs) - output = output.to(loc_cpu) - - _, pred = output.topk(1, 1, True, True) - result = torch.argmax(output, 1) - print("class: ", pred[0][0].item()) - print(result) - -if __name__ == "__main__": +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import torch +import torchvision +from torchvision import datasets, transforms +from collections import OrderedDict + +from timm.models import create_model + +parser = argparse.ArgumentParser(description='ImageNet Training') +parser.add_argument('--checkpoint', type=str, default='', + help='checkpoint path') +args = parser.parse_args() + +def proc_node_module(checkpoint, attr_name): + new_state_dict = OrderedDict() + for k, v in checkpoint[attr_name].items(): + if(k[0: 7] == "module."): + name = k[7:] + else: + name = k[0:] + new_state_dict[name] = v + return new_state_dict + +def get_raw_data(): + from PIL import Image + from urllib.request import urlretrieve + IMAGE_URL = 'https://bbs-img.huaweicloud.com/blogs/img/thumb/1591951315139_8989_1363.png' + urlretrieve(IMAGE_URL, 'tmp.jpg') + img = Image.open("tmp.jpg") + img = img.convert('RGB') + return img + +def test(): + loc = 'npu:0' + loc_cpu = 'cpu' + torch.npu.set_device(loc) + if args.checkpoint == '': + print("please give the checkpoint path using --checkpoint param") + exit(0) + checkpoint = torch.load(args.checkpoint, map_location=loc) + checkpoint['state_dict'] = proc_node_module(checkpoint, 'state_dict') + + model = create_model('vit_small_patch16_224', pretrained=False) + + model = model.to(loc) + model.load_state_dict(checkpoint['state_dict']) + model.eval() + + normalize = transforms.Normalize(mean=[0.5, 0.5, 0.5], + std=[0.5, 0.5, 0.5]) + rd = get_raw_data() + data_transfrom = transforms.Compose([ + transforms.RandomResizedCrop(224,interpolation=3), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + normalize, + ]) + + inputs = data_transfrom(rd) + inputs = inputs.unsqueeze(0) + inputs = inputs.to(loc) + output = model(inputs) + output = output.to(loc_cpu) + + _, pred = output.topk(1, 1, True, True) + result = torch.argmax(output, 1) + print("class: ", pred[0][0].item()) + print(result) + +if __name__ == "__main__": test() \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/Vit_small_patch16_224/distributed_train.sh b/PyTorch/contrib/cv/classification/Vit_small_patch16_224/distributed_train.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Vit_small_patch16_224/distributed_train_npu.sh b/PyTorch/contrib/cv/classification/Vit_small_patch16_224/distributed_train_npu.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Vit_small_patch16_224/pthtar2onnx.py b/PyTorch/contrib/cv/classification/Vit_small_patch16_224/pthtar2onnx.py index d55c4c20c5..ad98950f30 100644 --- a/PyTorch/contrib/cv/classification/Vit_small_patch16_224/pthtar2onnx.py +++ b/PyTorch/contrib/cv/classification/Vit_small_patch16_224/pthtar2onnx.py @@ -1,62 +1,62 @@ -""" -BSD 3-Clause License - -Copyright (c) Soumith Chintala 2016, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -Copyright 2020 Huawei Technologies Co., Ltd - -Licensed under the BSD 3-Clause License (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -https://spdx.org/licenses/BSD-3-Clause.html - -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 torch -import timm - -def pth2onnx(model, output_file): - model.eval() - input_names = ["image"] - output_names = ["class"] - dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} - dummy_input = torch.randn(1, 3, 224, 224) - torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, opset_version=11, verbose=True) - print("save to %s" % output_file) - -if __name__ == "__main__": - model = timm.create_model('vit_small_patch16_224', pretrained=False) - pth2onnx(model, "vit_small_patch16_224.onnx") +""" +BSD 3-Clause License + +Copyright (c) Soumith Chintala 2016, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Copyright 2020 Huawei Technologies Co., Ltd + +Licensed under the BSD 3-Clause License (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://spdx.org/licenses/BSD-3-Clause.html + +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 torch +import timm + +def pth2onnx(model, output_file): + model.eval() + input_names = ["image"] + output_names = ["class"] + dynamic_axes = {'image': {0: '-1'}, 'class': {0: '-1'}} + dummy_input = torch.randn(1, 3, 224, 224) + torch.onnx.export(model, dummy_input, output_file, input_names = input_names, dynamic_axes = dynamic_axes, output_names = output_names, opset_version=11, verbose=True) + print("save to %s" % output_file) + +if __name__ == "__main__": + model = timm.create_model('vit_small_patch16_224', pretrained=False) + pth2onnx(model, "vit_small_patch16_224.onnx") diff --git a/PyTorch/contrib/cv/classification/Vit_small_patch16_224/timm/loss/asymmetric_loss.py b/PyTorch/contrib/cv/classification/Vit_small_patch16_224/timm/loss/asymmetric_loss.py index d3a0d8650f..726f9410e4 100644 --- a/PyTorch/contrib/cv/classification/Vit_small_patch16_224/timm/loss/asymmetric_loss.py +++ b/PyTorch/contrib/cv/classification/Vit_small_patch16_224/timm/loss/asymmetric_loss.py @@ -1,143 +1,143 @@ -""" -BSD 3-Clause License - -Copyright (c) Soumith Chintala 2016, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -Copyright 2020 Huawei Technologies Co., Ltd - -Licensed under the BSD 3-Clause License (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -https://spdx.org/licenses/BSD-3-Clause.html - -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 torch -import torch.nn as nn - - -class AsymmetricLossMultiLabel(nn.Module): - def __init__(self, gamma_neg=4, gamma_pos=1, clip=0.05, eps=1e-8, disable_torch_grad_focal_loss=False): - super(AsymmetricLossMultiLabel, self).__init__() - - self.gamma_neg = gamma_neg - self.gamma_pos = gamma_pos - self.clip = clip - self.disable_torch_grad_focal_loss = disable_torch_grad_focal_loss - self.eps = eps - - def forward(self, x, y): - """" - Parameters - ---------- - x: input logits - y: targets (multi-label binarized vector) - """ - - # Calculating Probabilities - x_sigmoid = torch.sigmoid(x) - xs_pos = x_sigmoid - xs_neg = 1 - x_sigmoid - - # Asymmetric Clipping - if self.clip is not None and self.clip > 0: - xs_neg = (xs_neg + self.clip).clamp(max=1) - - # Basic CE calculation - los_pos = y * torch.log(xs_pos.clamp(min=self.eps)) - los_neg = (1 - y) * torch.log(xs_neg.clamp(min=self.eps)) - loss = los_pos + los_neg - - # Asymmetric Focusing - if self.gamma_neg > 0 or self.gamma_pos > 0: - if self.disable_torch_grad_focal_loss: - torch._C.set_grad_enabled(False) - pt0 = xs_pos * y - pt1 = xs_neg * (1 - y) # pt = p if t > 0 else 1-p - pt = pt0 + pt1 - one_sided_gamma = self.gamma_pos * y + self.gamma_neg * (1 - y) - one_sided_w = torch.pow(1 - pt, one_sided_gamma) - if self.disable_torch_grad_focal_loss: - torch._C.set_grad_enabled(True) - loss *= one_sided_w - - return -loss.sum() - - -class AsymmetricLossSingleLabel(nn.Module): - def __init__(self, gamma_pos=1, gamma_neg=4, eps: float = 0.1, reduction='mean'): - super(AsymmetricLossSingleLabel, self).__init__() - - self.eps = eps - self.logsoftmax = nn.LogSoftmax(dim=-1) - self.targets_classes = [] # prevent gpu repeated memory allocation - self.gamma_pos = gamma_pos - self.gamma_neg = gamma_neg - self.reduction = reduction - - def forward(self, inputs, target, reduction=None): - """" - Parameters - ---------- - x: input logits - y: targets (1-hot vector) - """ - - num_classes = inputs.size()[-1] - log_preds = self.logsoftmax(inputs) - self.targets_classes = torch.zeros_like(inputs).scatter_(1, target.long().unsqueeze(1), 1) - - # ASL weights - targets = self.targets_classes - anti_targets = 1 - targets - xs_pos = torch.exp(log_preds) - xs_neg = 1 - xs_pos - xs_pos = xs_pos * targets - xs_neg = xs_neg * anti_targets - asymmetric_w = torch.pow(1 - xs_pos - xs_neg, - self.gamma_pos * targets + self.gamma_neg * anti_targets) - log_preds = log_preds * asymmetric_w - - if self.eps > 0: # label smoothing - self.targets_classes.mul_(1 - self.eps).add_(self.eps / num_classes) - - # loss calculation - loss = - self.targets_classes.mul(log_preds) - - loss = loss.sum(dim=-1) - if self.reduction == 'mean': - loss = loss.mean() - - return loss +""" +BSD 3-Clause License + +Copyright (c) Soumith Chintala 2016, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Copyright 2020 Huawei Technologies Co., Ltd + +Licensed under the BSD 3-Clause License (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://spdx.org/licenses/BSD-3-Clause.html + +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 torch +import torch.nn as nn + + +class AsymmetricLossMultiLabel(nn.Module): + def __init__(self, gamma_neg=4, gamma_pos=1, clip=0.05, eps=1e-8, disable_torch_grad_focal_loss=False): + super(AsymmetricLossMultiLabel, self).__init__() + + self.gamma_neg = gamma_neg + self.gamma_pos = gamma_pos + self.clip = clip + self.disable_torch_grad_focal_loss = disable_torch_grad_focal_loss + self.eps = eps + + def forward(self, x, y): + """" + Parameters + ---------- + x: input logits + y: targets (multi-label binarized vector) + """ + + # Calculating Probabilities + x_sigmoid = torch.sigmoid(x) + xs_pos = x_sigmoid + xs_neg = 1 - x_sigmoid + + # Asymmetric Clipping + if self.clip is not None and self.clip > 0: + xs_neg = (xs_neg + self.clip).clamp(max=1) + + # Basic CE calculation + los_pos = y * torch.log(xs_pos.clamp(min=self.eps)) + los_neg = (1 - y) * torch.log(xs_neg.clamp(min=self.eps)) + loss = los_pos + los_neg + + # Asymmetric Focusing + if self.gamma_neg > 0 or self.gamma_pos > 0: + if self.disable_torch_grad_focal_loss: + torch._C.set_grad_enabled(False) + pt0 = xs_pos * y + pt1 = xs_neg * (1 - y) # pt = p if t > 0 else 1-p + pt = pt0 + pt1 + one_sided_gamma = self.gamma_pos * y + self.gamma_neg * (1 - y) + one_sided_w = torch.pow(1 - pt, one_sided_gamma) + if self.disable_torch_grad_focal_loss: + torch._C.set_grad_enabled(True) + loss *= one_sided_w + + return -loss.sum() + + +class AsymmetricLossSingleLabel(nn.Module): + def __init__(self, gamma_pos=1, gamma_neg=4, eps: float = 0.1, reduction='mean'): + super(AsymmetricLossSingleLabel, self).__init__() + + self.eps = eps + self.logsoftmax = nn.LogSoftmax(dim=-1) + self.targets_classes = [] # prevent gpu repeated memory allocation + self.gamma_pos = gamma_pos + self.gamma_neg = gamma_neg + self.reduction = reduction + + def forward(self, inputs, target, reduction=None): + """" + Parameters + ---------- + x: input logits + y: targets (1-hot vector) + """ + + num_classes = inputs.size()[-1] + log_preds = self.logsoftmax(inputs) + self.targets_classes = torch.zeros_like(inputs).scatter_(1, target.long().unsqueeze(1), 1) + + # ASL weights + targets = self.targets_classes + anti_targets = 1 - targets + xs_pos = torch.exp(log_preds) + xs_neg = 1 - xs_pos + xs_pos = xs_pos * targets + xs_neg = xs_neg * anti_targets + asymmetric_w = torch.pow(1 - xs_pos - xs_neg, + self.gamma_pos * targets + self.gamma_neg * anti_targets) + log_preds = log_preds * asymmetric_w + + if self.eps > 0: # label smoothing + self.targets_classes.mul_(1 - self.eps).add_(self.eps / num_classes) + + # loss calculation + loss = - self.targets_classes.mul(log_preds) + + loss = loss.sum(dim=-1) + if self.reduction == 'mean': + loss = loss.mean() + + return loss diff --git a/PyTorch/contrib/cv/classification/Vit_small_patch16_224/timm/optim/npu_fused_adamp.py b/PyTorch/contrib/cv/classification/Vit_small_patch16_224/timm/optim/npu_fused_adamp.py index fc0bca28aa..7f6a8f0c2f 100644 --- a/PyTorch/contrib/cv/classification/Vit_small_patch16_224/timm/optim/npu_fused_adamp.py +++ b/PyTorch/contrib/cv/classification/Vit_small_patch16_224/timm/optim/npu_fused_adamp.py @@ -1,298 +1,298 @@ -""" -BSD 3-Clause License - -Copyright (c) Soumith Chintala 2016, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -Copyright 2020 Huawei Technologies Co., Ltd - -Licensed under the BSD 3-Clause License (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -https://spdx.org/licenses/BSD-3-Clause.html - -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 math -from collections import defaultdict - -import torch -from torch.optim.optimizer import Optimizer -from apex.contrib.combine_tensors import combine_npu - - -class NpuFusedAdamP(Optimizer): - """Implements AdamP algorithm. - - Currently NPU-only. Requires Apex to be installed via - ``pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--npu_float_status" ./``. - - This version of NPU fused AdamP implements 1 fusions. - - * A combine-tensor apply launch that batches the elementwise updates applied to all the model's parameters - into one or a few kernel launches. - - :class:`apex.optimizers.NpuFusedAdamP` may be used as a drop-in replacement for ``torch.optim.AdamP``:: - - opt = apex.optimizers.NpuFusedAdamP(model.parameters(), lr = ....) - ... - opt.step() - - :class:`apex.optimizers.FusedAdam` should be used with Amp. Currently, if you wish to use :class:`NpuFusedAdamP` - with Amp, only ``opt_level O1 and O2`` can be choosed:: - - opt = apex.optimizers.NpuFusedAdamP(model.parameters(), lr = ....) - model, opt = amp.initialize(model, opt, opt_level="O2") - ... - opt.step() - - - The original Adam algorithm was proposed in `Adam: A Method for Stochastic Optimization`_. - The AdamP variant was proposed in `Decoupled Weight Decay Regularization`_. - - Arguments: - params (iterable): iterable of parameters to optimize or dicts defining - parameter groups - lr (float, optional, default: 1e-3): learning rate - betas (Tuple[float, float], optional, default: (0.9, 0.999)): coefficients used - for computing running averages of gradient and its square - eps (float, optional, default: 1e-8): term added to the denominator to improve - numerical stability - weight_decay (float, optional, default: 1e-2): weight decay coefficient - amsgrad (boolean, optional, default: False): whether to use the AMSGrad variant of - this algorithm from the paper `On the Convergence of Adam and Beyond`_ - - .. _Adam\: A Method for Stochastic Optimization: - https://arxiv.org/abs/1412.6980 - .. _Decoupled Weight Decay Regularization: - https://arxiv.org/abs/1711.05101 - .. _On the Convergence of Adam and Beyond: - https://openreview.net/forum?id=ryQu7f-RZ - """ - - def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), eps=1e-8, - weight_decay=0, delta=0.1, wd_ratio=0.1, nesterov=False): - defaults = dict(lr=lr, betas=betas, eps=eps, weight_decay=weight_decay, - delta=delta, wd_ratio=wd_ratio, nesterov=nesterov) - self.is_npu_fused_optimizer = True - super(NpuFusedAdamP, self).__init__(params, defaults) - - def __setstate__(self, state): - super(NpuFusedAdamP, self).__setstate__(state) - for group in self.param_groups: - group.setdefault('nesterov', False) - - def _channel_view(self, x): - return x.view(x.size(0), -1) - - def _layer_view(self, x): - return x.view(1, -1) - - def _cosine_similarity(self, x, y, eps, view_func): - x = view_func(x) - y = view_func(y) - - x_norm = x.norm(dim=1).add_(eps) - y_norm = y.norm(dim=1).add_(eps) - dot = (x * y).sum(dim=1) - - return dot.abs() / x_norm / y_norm - - def _projection(self, p, grad, perturb, delta, wd_ratio, eps): - wd = 1 - expand_size = [-1] + [1] * (len(p.shape) - 1) - for view_func in [self._channel_view, self._layer_view]: - - cosine_sim = self._cosine_similarity(grad, p, eps, view_func) - - if cosine_sim.max() < delta / math.sqrt(view_func(p).size(1)): - p_n = p / view_func(p).norm(dim=1).view(expand_size).add_(eps) - perturb -= p_n * view_func(p_n * perturb).sum(dim=1).view(expand_size) - wd = wd_ratio - - return perturb, wd - - return perturb, wd - - def _init_param_state(self, p): - state = self.state[p] - # State initialization - if len(state) == 0: - state['step'] = 0 - # Exponential moving average of gradient values - state['exp_avg'] = torch.zeros_like(p, memory_format=torch.preserve_format) - # Exponential moving average of squared gradient values - state['exp_avg_sq'] = torch.zeros_like(p, memory_format=torch.preserve_format) - else: - exp_avg_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) - exp_avg_tmp.copy_(state['exp_avg']) - state['exp_avg'] = exp_avg_tmp - - exp_avg_sq_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) - exp_avg_sq_tmp.copy_(state['exp_avg_sq']) - state['exp_avg_sq'] = exp_avg_sq_tmp - - def _combine_group_param_states(self, group_index): - group = self.param_groups[group_index] - stash = self._amp_stash - group_params_list = stash.params_lists_indexed_by_group[group_index] - - combined_param_states = [] - for params in group_params_list: - step_list = [] - exp_avg_list = [] - exp_avg_sq_list = [] - max_exp_avg_sq_list = [] - - for p in params: - if p.grad is None: - continue - grad = p.grad - if grad.is_sparse: - raise RuntimeError('NpuFusedAdamP does not support sparse gradients, ' - 'please consider SparseAdam instead') - - self._init_param_state(p) - state = self.state[p] - step_list.append(state['step']) - exp_avg_list.append(state['exp_avg']) - exp_avg_sq_list.append(state['exp_avg_sq']) - - combined_step = 0 - combined_exp_avg = None - combined_exp_avg_sq = None - combined_max_exp_avg_sq = None - - if len(exp_avg_list) > 0: - combined_step = step_list[0] - combined_exp_avg = combine_npu(exp_avg_list) - combined_exp_avg_sq = combine_npu(exp_avg_sq_list) - combined_max_exp_avg_sq = combine_npu(max_exp_avg_sq_list) - - combined_state = defaultdict(dict) - combined_state['step'] = combined_step - combined_state['exp_avg'] = combined_exp_avg - combined_state['exp_avg_sq'] = combined_exp_avg_sq - combined_state['max_exp_avg_sq'] = combined_max_exp_avg_sq - combined_param_states.append(combined_state) - stash.combined_param_states_indexed_by_group[group_index] = combined_param_states - - def _combine_param_states_by_group(self): - stash = self._amp_stash - if stash.param_states_are_combined_by_group: - return - - stash.combined_param_states_indexed_by_group = [] - for _ in self.param_groups: - stash.combined_param_states_indexed_by_group.append([]) - - for i, _ in enumerate(self.param_groups): - self._combine_group_param_states(i) - stash.param_states_are_combined_by_group = True - - def _group_step(self, group_index): - group = self.param_groups[group_index] - for p in group['params']: - if p.grad is None: - continue - - grad = p.grad.data - state = self.state[p] - state['step'] += 1 - - - beta1, beta2 = group['betas'] - nesterov = group['nesterov'] - - stash = self._amp_stash - combined_group_params = stash.combined_params_indexed_by_group[group_index] - combined_group_grads = stash.combined_grads_indexed_by_group[group_index] - combined_group_param_states = stash.combined_param_states_indexed_by_group[group_index] - - for combined_param, combined_grad, combined_param_state in zip(combined_group_params, - combined_group_grads, - combined_group_param_states): - if combined_param is None or combined_grad is None: - continue - - exp_avg, exp_avg_sq = combined_param_state['exp_avg'], combined_param_state['exp_avg_sq'] - - combined_param_state['step'] += 1 - bias_correction1 = 1 - beta1 ** combined_param_state['step'] - bias_correction2 = 1 - beta2 ** combined_param_state['step'] - - # Decay the first and second moment running average coefficient - exp_avg.mul_(beta1).add_(combined_grad, alpha=1 - beta1) - exp_avg_sq.mul_(beta2).addcmul_(combined_grad, combined_grad, value=1 - beta2) - denom = (exp_avg_sq.sqrt() / math.sqrt(bias_correction2)).add_(group['eps']) - step_size = group['lr'] / bias_correction1 - - if nesterov: - perturb = (beta1 * exp_avg + (1 - beta1) * combined_grad) / denom - else: - perturb = exp_avg / denom - - # Projection - wd_ratio = 1 - if len(combined_param.shape) > 1: - perturb, wd_ratio = self._projection(combined_param, combined_grad, perturb, group['delta'], group['wd_ratio'], group['eps']) - - # Weight decay - if group['weight_decay'] > 0: - combined_param.mul_(1 - group['lr'] * group['weight_decay'] * wd_ratio) - - # Step - combined_param.add_(-step_size, perturb) - - @torch.no_grad() - def step(self, closure=None): - if not hasattr(self, "_amp_stash"): - raise RuntimeError('apex.optimizers.NpuFusedAdamP should be used with AMP.') - - self._check_already_combined_params_and_grads() - # combine params and grads first - self._combine_params_and_grads_by_group() - # then combine param states - self._combine_param_states_by_group() - - loss = None - if closure is not None: - with torch.enable_grad(): - loss = closure() - - for i, _ in enumerate(self.param_groups): - self._group_step(i) - - return loss +""" +BSD 3-Clause License + +Copyright (c) Soumith Chintala 2016, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Copyright 2020 Huawei Technologies Co., Ltd + +Licensed under the BSD 3-Clause License (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://spdx.org/licenses/BSD-3-Clause.html + +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 math +from collections import defaultdict + +import torch +from torch.optim.optimizer import Optimizer +from apex.contrib.combine_tensors import combine_npu + + +class NpuFusedAdamP(Optimizer): + """Implements AdamP algorithm. + + Currently NPU-only. Requires Apex to be installed via + ``pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--npu_float_status" ./``. + + This version of NPU fused AdamP implements 1 fusions. + + * A combine-tensor apply launch that batches the elementwise updates applied to all the model's parameters + into one or a few kernel launches. + + :class:`apex.optimizers.NpuFusedAdamP` may be used as a drop-in replacement for ``torch.optim.AdamP``:: + + opt = apex.optimizers.NpuFusedAdamP(model.parameters(), lr = ....) + ... + opt.step() + + :class:`apex.optimizers.FusedAdam` should be used with Amp. Currently, if you wish to use :class:`NpuFusedAdamP` + with Amp, only ``opt_level O1 and O2`` can be choosed:: + + opt = apex.optimizers.NpuFusedAdamP(model.parameters(), lr = ....) + model, opt = amp.initialize(model, opt, opt_level="O2") + ... + opt.step() + + + The original Adam algorithm was proposed in `Adam: A Method for Stochastic Optimization`_. + The AdamP variant was proposed in `Decoupled Weight Decay Regularization`_. + + Arguments: + params (iterable): iterable of parameters to optimize or dicts defining + parameter groups + lr (float, optional, default: 1e-3): learning rate + betas (Tuple[float, float], optional, default: (0.9, 0.999)): coefficients used + for computing running averages of gradient and its square + eps (float, optional, default: 1e-8): term added to the denominator to improve + numerical stability + weight_decay (float, optional, default: 1e-2): weight decay coefficient + amsgrad (boolean, optional, default: False): whether to use the AMSGrad variant of + this algorithm from the paper `On the Convergence of Adam and Beyond`_ + + .. _Adam\: A Method for Stochastic Optimization: + https://arxiv.org/abs/1412.6980 + .. _Decoupled Weight Decay Regularization: + https://arxiv.org/abs/1711.05101 + .. _On the Convergence of Adam and Beyond: + https://openreview.net/forum?id=ryQu7f-RZ + """ + + def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), eps=1e-8, + weight_decay=0, delta=0.1, wd_ratio=0.1, nesterov=False): + defaults = dict(lr=lr, betas=betas, eps=eps, weight_decay=weight_decay, + delta=delta, wd_ratio=wd_ratio, nesterov=nesterov) + self.is_npu_fused_optimizer = True + super(NpuFusedAdamP, self).__init__(params, defaults) + + def __setstate__(self, state): + super(NpuFusedAdamP, self).__setstate__(state) + for group in self.param_groups: + group.setdefault('nesterov', False) + + def _channel_view(self, x): + return x.view(x.size(0), -1) + + def _layer_view(self, x): + return x.view(1, -1) + + def _cosine_similarity(self, x, y, eps, view_func): + x = view_func(x) + y = view_func(y) + + x_norm = x.norm(dim=1).add_(eps) + y_norm = y.norm(dim=1).add_(eps) + dot = (x * y).sum(dim=1) + + return dot.abs() / x_norm / y_norm + + def _projection(self, p, grad, perturb, delta, wd_ratio, eps): + wd = 1 + expand_size = [-1] + [1] * (len(p.shape) - 1) + for view_func in [self._channel_view, self._layer_view]: + + cosine_sim = self._cosine_similarity(grad, p, eps, view_func) + + if cosine_sim.max() < delta / math.sqrt(view_func(p).size(1)): + p_n = p / view_func(p).norm(dim=1).view(expand_size).add_(eps) + perturb -= p_n * view_func(p_n * perturb).sum(dim=1).view(expand_size) + wd = wd_ratio + + return perturb, wd + + return perturb, wd + + def _init_param_state(self, p): + state = self.state[p] + # State initialization + if len(state) == 0: + state['step'] = 0 + # Exponential moving average of gradient values + state['exp_avg'] = torch.zeros_like(p, memory_format=torch.preserve_format) + # Exponential moving average of squared gradient values + state['exp_avg_sq'] = torch.zeros_like(p, memory_format=torch.preserve_format) + else: + exp_avg_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) + exp_avg_tmp.copy_(state['exp_avg']) + state['exp_avg'] = exp_avg_tmp + + exp_avg_sq_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) + exp_avg_sq_tmp.copy_(state['exp_avg_sq']) + state['exp_avg_sq'] = exp_avg_sq_tmp + + def _combine_group_param_states(self, group_index): + group = self.param_groups[group_index] + stash = self._amp_stash + group_params_list = stash.params_lists_indexed_by_group[group_index] + + combined_param_states = [] + for params in group_params_list: + step_list = [] + exp_avg_list = [] + exp_avg_sq_list = [] + max_exp_avg_sq_list = [] + + for p in params: + if p.grad is None: + continue + grad = p.grad + if grad.is_sparse: + raise RuntimeError('NpuFusedAdamP does not support sparse gradients, ' + 'please consider SparseAdam instead') + + self._init_param_state(p) + state = self.state[p] + step_list.append(state['step']) + exp_avg_list.append(state['exp_avg']) + exp_avg_sq_list.append(state['exp_avg_sq']) + + combined_step = 0 + combined_exp_avg = None + combined_exp_avg_sq = None + combined_max_exp_avg_sq = None + + if len(exp_avg_list) > 0: + combined_step = step_list[0] + combined_exp_avg = combine_npu(exp_avg_list) + combined_exp_avg_sq = combine_npu(exp_avg_sq_list) + combined_max_exp_avg_sq = combine_npu(max_exp_avg_sq_list) + + combined_state = defaultdict(dict) + combined_state['step'] = combined_step + combined_state['exp_avg'] = combined_exp_avg + combined_state['exp_avg_sq'] = combined_exp_avg_sq + combined_state['max_exp_avg_sq'] = combined_max_exp_avg_sq + combined_param_states.append(combined_state) + stash.combined_param_states_indexed_by_group[group_index] = combined_param_states + + def _combine_param_states_by_group(self): + stash = self._amp_stash + if stash.param_states_are_combined_by_group: + return + + stash.combined_param_states_indexed_by_group = [] + for _ in self.param_groups: + stash.combined_param_states_indexed_by_group.append([]) + + for i, _ in enumerate(self.param_groups): + self._combine_group_param_states(i) + stash.param_states_are_combined_by_group = True + + def _group_step(self, group_index): + group = self.param_groups[group_index] + for p in group['params']: + if p.grad is None: + continue + + grad = p.grad.data + state = self.state[p] + state['step'] += 1 + + + beta1, beta2 = group['betas'] + nesterov = group['nesterov'] + + stash = self._amp_stash + combined_group_params = stash.combined_params_indexed_by_group[group_index] + combined_group_grads = stash.combined_grads_indexed_by_group[group_index] + combined_group_param_states = stash.combined_param_states_indexed_by_group[group_index] + + for combined_param, combined_grad, combined_param_state in zip(combined_group_params, + combined_group_grads, + combined_group_param_states): + if combined_param is None or combined_grad is None: + continue + + exp_avg, exp_avg_sq = combined_param_state['exp_avg'], combined_param_state['exp_avg_sq'] + + combined_param_state['step'] += 1 + bias_correction1 = 1 - beta1 ** combined_param_state['step'] + bias_correction2 = 1 - beta2 ** combined_param_state['step'] + + # Decay the first and second moment running average coefficient + exp_avg.mul_(beta1).add_(combined_grad, alpha=1 - beta1) + exp_avg_sq.mul_(beta2).addcmul_(combined_grad, combined_grad, value=1 - beta2) + denom = (exp_avg_sq.sqrt() / math.sqrt(bias_correction2)).add_(group['eps']) + step_size = group['lr'] / bias_correction1 + + if nesterov: + perturb = (beta1 * exp_avg + (1 - beta1) * combined_grad) / denom + else: + perturb = exp_avg / denom + + # Projection + wd_ratio = 1 + if len(combined_param.shape) > 1: + perturb, wd_ratio = self._projection(combined_param, combined_grad, perturb, group['delta'], group['wd_ratio'], group['eps']) + + # Weight decay + if group['weight_decay'] > 0: + combined_param.mul_(1 - group['lr'] * group['weight_decay'] * wd_ratio) + + # Step + combined_param.add_(-step_size, perturb) + + @torch.no_grad() + def step(self, closure=None): + if not hasattr(self, "_amp_stash"): + raise RuntimeError('apex.optimizers.NpuFusedAdamP should be used with AMP.') + + self._check_already_combined_params_and_grads() + # combine params and grads first + self._combine_params_and_grads_by_group() + # then combine param states + self._combine_param_states_by_group() + + loss = None + if closure is not None: + with torch.enable_grad(): + loss = closure() + + for i, _ in enumerate(self.param_groups): + self._group_step(i) + + return loss diff --git a/PyTorch/contrib/cv/classification/Vit_small_patch16_224/timm/optim/npu_fused_adamw.py b/PyTorch/contrib/cv/classification/Vit_small_patch16_224/timm/optim/npu_fused_adamw.py index 043a281b31..87896fce40 100644 --- a/PyTorch/contrib/cv/classification/Vit_small_patch16_224/timm/optim/npu_fused_adamw.py +++ b/PyTorch/contrib/cv/classification/Vit_small_patch16_224/timm/optim/npu_fused_adamw.py @@ -1,289 +1,289 @@ -""" -BSD 3-Clause License - -Copyright (c) Soumith Chintala 2016, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -Copyright 2020 Huawei Technologies Co., Ltd - -Licensed under the BSD 3-Clause License (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -https://spdx.org/licenses/BSD-3-Clause.html - -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 math -from collections import defaultdict - -import torch -from torch.optim.optimizer import Optimizer - -from apex.contrib.combine_tensors import combine_npu - - -class NpuFusedAdamW(Optimizer): - """Implements AdamW algorithm. - - Currently NPU-only. Requires Apex to be installed via - ``pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--npu_float_status" ./``. - - This version of NPU fused AdamW implements 1 fusions. - - * A combine-tensor apply launch that batches the elementwise updates applied to all the model's parameters - into one or a few kernel launches. - - :class:`apex.optimizers.NpuFusedAdamW` may be used as a drop-in replacement for ``torch.optim.AdamW``:: - - opt = apex.optimizers.NpuFusedAdamW(model.parameters(), lr = ....) - ... - opt.step() - - :class:`apex.optimizers.FusedAdam` should be used with Amp. Currently, if you wish to use :class:`NpuFusedAdamW` - with Amp, only ``opt_level O1 and O2`` can be choosed:: - - opt = apex.optimizers.NpuFusedAdamW(model.parameters(), lr = ....) - model, opt = amp.initialize(model, opt, opt_level="O2") - ... - opt.step() - - - The original Adam algorithm was proposed in `Adam: A Method for Stochastic Optimization`_. - The AdamW variant was proposed in `Decoupled Weight Decay Regularization`_. - - Arguments: - params (iterable): iterable of parameters to optimize or dicts defining - parameter groups - lr (float, optional): learning rate (default: 1e-3) - betas (Tuple[float, float], optional): coefficients used for computing - running averages of gradient and its square (default: (0.9, 0.999)) - eps (float, optional): term added to the denominator to improve - numerical stability (default: 1e-8) - weight_decay (float, optional): weight decay coefficient (default: 1e-2) - amsgrad (boolean, optional): whether to use the AMSGrad variant of this - algorithm from the paper `On the Convergence of Adam and Beyond`_ - (default: False) - - .. _Adam\: A Method for Stochastic Optimization: - https://arxiv.org/abs/1412.6980 - .. _Decoupled Weight Decay Regularization: - https://arxiv.org/abs/1711.05101 - .. _On the Convergence of Adam and Beyond: - https://openreview.net/forum?id=ryQu7f-RZ - """ - - def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), eps=1e-8, - weight_decay=1e-2, amsgrad=False): - if lr < 0.0: - raise ValueError("Invalid learning rate: {}".format(lr)) - if eps < 0.0: - raise ValueError("Invalid epsilon value: {}".format(eps)) - if betas[0] < 0.0 or betas[0] >= 1.0: - raise ValueError("Invalid beta parameter at index 0: {}".format(betas[0])) - if betas[1] < 0.0 or betas[1] >= 1.0: - raise ValueError("Invalid beta parameter at index 1: {}".format(betas[1])) - if weight_decay < 0.0: - raise ValueError("Invalid weight_decay value: {}".format(weight_decay)) - defaults = dict(lr=lr, betas=betas, eps=eps, - weight_decay=weight_decay, amsgrad=amsgrad) - self.is_npu_fused_optimizer = True - super(NpuFusedAdamW, self).__init__(params, defaults) - - def __setstate__(self, state): - super(NpuFusedAdamW, self).__setstate__(state) - for group in self.param_groups: - group.setdefault('amsgrad', False) - - def _init_param_state(self, p, amsgrad): - state = self.state[p] - # State initialization - if len(state) == 0: - state['step'] = 0 - # Exponential moving average of gradient values - state['exp_avg'] = torch.zeros_like(p, memory_format=torch.preserve_format) - # Exponential moving average of squared gradient values - state['exp_avg_sq'] = torch.zeros_like(p, memory_format=torch.preserve_format) - if amsgrad: - # Maintains max of all exp. moving avg. of sq. grad. values - state['max_exp_avg_sq'] = torch.zeros_like(p, memory_format=torch.preserve_format) - else: - exp_avg_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) - exp_avg_tmp.copy_(state['exp_avg']) - state['exp_avg'] = exp_avg_tmp - - exp_avg_sq_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) - exp_avg_sq_tmp.copy_(state['exp_avg_sq']) - state['exp_avg_sq'] = exp_avg_sq_tmp - - if amsgrad: - max_exp_avg_sq_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) - max_exp_avg_sq_tmp.copy_(state['max_exp_avg_sq']) - state['max_exp_avg_sq'] = max_exp_avg_sq_tmp - - def _combine_group_param_states(self, group_index): - group = self.param_groups[group_index] - stash = self._amp_stash - group_params_list = stash.params_lists_indexed_by_group[group_index] - - amsgrad = group['amsgrad'] - - combined_param_states = [] - for params in group_params_list: - step_list = [] - exp_avg_list = [] - exp_avg_sq_list = [] - max_exp_avg_sq_list = [] - - for p in params: - if p.grad is None: - continue - grad = p.grad - if grad.is_sparse: - raise RuntimeError('NpuFusedAdamW does not support sparse gradients, ' - 'please consider SparseAdam instead') - - self._init_param_state(p, amsgrad) - state = self.state[p] - step_list.append(state['step']) - exp_avg_list.append(state['exp_avg']) - exp_avg_sq_list.append(state['exp_avg_sq']) - if amsgrad: - max_exp_avg_sq_list.append(state['max_exp_avg_sq']) - - combined_step = 0 - combined_exp_avg = None - combined_exp_avg_sq = None - combined_max_exp_avg_sq = None - - if len(exp_avg_list) > 0: - combined_step = step_list[0] - combined_exp_avg = combine_npu(exp_avg_list) - combined_exp_avg_sq = combine_npu(exp_avg_sq_list) - combined_max_exp_avg_sq = combine_npu(max_exp_avg_sq_list) - - combined_state = defaultdict(dict) - combined_state['step'] = combined_step - combined_state['exp_avg'] = combined_exp_avg - combined_state['exp_avg_sq'] = combined_exp_avg_sq - combined_state['max_exp_avg_sq'] = combined_max_exp_avg_sq - combined_param_states.append(combined_state) - stash.combined_param_states_indexed_by_group[group_index] = combined_param_states - - def _combine_param_states_by_group(self): - stash = self._amp_stash - if stash.param_states_are_combined_by_group: - return - - stash.combined_param_states_indexed_by_group = [] - for _ in self.param_groups: - stash.combined_param_states_indexed_by_group.append([]) - - for i, _ in enumerate(self.param_groups): - self._combine_group_param_states(i) - stash.param_states_are_combined_by_group = True - - def _group_step(self, group_index): - group = self.param_groups[group_index] - for p in group['params']: - if p.grad is None: - continue - - grad = p.grad - if grad.is_sparse: - raise RuntimeError('NpuFusedAdamW does not support sparse gradients, ' - 'please consider SparseAdam instead') - state_p = self.state[p] - state_p['step'] += 1 - - amsgrad = group['amsgrad'] - beta1, beta2 = group['betas'] - - stash = self._amp_stash - combined_group_params = stash.combined_params_indexed_by_group[group_index] - combined_group_grads = stash.combined_grads_indexed_by_group[group_index] - combined_group_param_states = stash.combined_param_states_indexed_by_group[group_index] - - for combined_param, combined_grad, combined_param_state in zip(combined_group_params, - combined_group_grads, - combined_group_param_states): - if combined_param is None or combined_grad is None: - continue - - # Perform stepweight decay. The fused method is used here to speed up the calculation - combined_param.mul_(1 - group['lr'] * group['weight_decay']) - - exp_avg, exp_avg_sq = combined_param_state['exp_avg'], combined_param_state['exp_avg_sq'] - if amsgrad: - max_exp_avg_sq = combined_param_state['max_exp_avg_sq'] - - combined_param_state['step'] += 1 - bias_correction1 = 1 - beta1 ** combined_param_state['step'] - bias_correction2 = 1 - beta2 ** combined_param_state['step'] - - # Decay the first and second moment running average coefficient - exp_avg.mul_(beta1).add_(combined_grad, alpha=1 - beta1) - exp_avg_sq.mul_(beta2).addcmul_(combined_grad, combined_grad, value=1 - beta2) - if amsgrad: - # Maintains the maximum of all 2nd moment running avg. till now - torch.max(max_exp_avg_sq, exp_avg_sq, out=max_exp_avg_sq) - # Use the max. for normalizing running avg. of gradient - denom = (max_exp_avg_sq.sqrt() / math.sqrt(bias_correction2)).add_(group['eps']) - else: - denom = (exp_avg_sq.sqrt() / math.sqrt(bias_correction2)).add_(group['eps']) - - step_size = group['lr'] / bias_correction1 - - combined_param.addcdiv_(exp_avg, denom, value=-step_size) - - @torch.no_grad() - def step(self, closure=None): - if not hasattr(self, "_amp_stash"): - raise RuntimeError('apex.optimizers.NpuFusedAdamW should be used with AMP.') - - self._check_already_combined_params_and_grads() - # combine params and grads first - self._combine_params_and_grads_by_group() - # then combine param states - self._combine_param_states_by_group() - - loss = None - if closure is not None: - with torch.enable_grad(): - loss = closure() - - for i, _ in enumerate(self.param_groups): - self._group_step(i) - - return loss +""" +BSD 3-Clause License + +Copyright (c) Soumith Chintala 2016, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Copyright 2020 Huawei Technologies Co., Ltd + +Licensed under the BSD 3-Clause License (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://spdx.org/licenses/BSD-3-Clause.html + +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 math +from collections import defaultdict + +import torch +from torch.optim.optimizer import Optimizer + +from apex.contrib.combine_tensors import combine_npu + + +class NpuFusedAdamW(Optimizer): + """Implements AdamW algorithm. + + Currently NPU-only. Requires Apex to be installed via + ``pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--npu_float_status" ./``. + + This version of NPU fused AdamW implements 1 fusions. + + * A combine-tensor apply launch that batches the elementwise updates applied to all the model's parameters + into one or a few kernel launches. + + :class:`apex.optimizers.NpuFusedAdamW` may be used as a drop-in replacement for ``torch.optim.AdamW``:: + + opt = apex.optimizers.NpuFusedAdamW(model.parameters(), lr = ....) + ... + opt.step() + + :class:`apex.optimizers.FusedAdam` should be used with Amp. Currently, if you wish to use :class:`NpuFusedAdamW` + with Amp, only ``opt_level O1 and O2`` can be choosed:: + + opt = apex.optimizers.NpuFusedAdamW(model.parameters(), lr = ....) + model, opt = amp.initialize(model, opt, opt_level="O2") + ... + opt.step() + + + The original Adam algorithm was proposed in `Adam: A Method for Stochastic Optimization`_. + The AdamW variant was proposed in `Decoupled Weight Decay Regularization`_. + + Arguments: + params (iterable): iterable of parameters to optimize or dicts defining + parameter groups + lr (float, optional): learning rate (default: 1e-3) + betas (Tuple[float, float], optional): coefficients used for computing + running averages of gradient and its square (default: (0.9, 0.999)) + eps (float, optional): term added to the denominator to improve + numerical stability (default: 1e-8) + weight_decay (float, optional): weight decay coefficient (default: 1e-2) + amsgrad (boolean, optional): whether to use the AMSGrad variant of this + algorithm from the paper `On the Convergence of Adam and Beyond`_ + (default: False) + + .. _Adam\: A Method for Stochastic Optimization: + https://arxiv.org/abs/1412.6980 + .. _Decoupled Weight Decay Regularization: + https://arxiv.org/abs/1711.05101 + .. _On the Convergence of Adam and Beyond: + https://openreview.net/forum?id=ryQu7f-RZ + """ + + def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), eps=1e-8, + weight_decay=1e-2, amsgrad=False): + if lr < 0.0: + raise ValueError("Invalid learning rate: {}".format(lr)) + if eps < 0.0: + raise ValueError("Invalid epsilon value: {}".format(eps)) + if betas[0] < 0.0 or betas[0] >= 1.0: + raise ValueError("Invalid beta parameter at index 0: {}".format(betas[0])) + if betas[1] < 0.0 or betas[1] >= 1.0: + raise ValueError("Invalid beta parameter at index 1: {}".format(betas[1])) + if weight_decay < 0.0: + raise ValueError("Invalid weight_decay value: {}".format(weight_decay)) + defaults = dict(lr=lr, betas=betas, eps=eps, + weight_decay=weight_decay, amsgrad=amsgrad) + self.is_npu_fused_optimizer = True + super(NpuFusedAdamW, self).__init__(params, defaults) + + def __setstate__(self, state): + super(NpuFusedAdamW, self).__setstate__(state) + for group in self.param_groups: + group.setdefault('amsgrad', False) + + def _init_param_state(self, p, amsgrad): + state = self.state[p] + # State initialization + if len(state) == 0: + state['step'] = 0 + # Exponential moving average of gradient values + state['exp_avg'] = torch.zeros_like(p, memory_format=torch.preserve_format) + # Exponential moving average of squared gradient values + state['exp_avg_sq'] = torch.zeros_like(p, memory_format=torch.preserve_format) + if amsgrad: + # Maintains max of all exp. moving avg. of sq. grad. values + state['max_exp_avg_sq'] = torch.zeros_like(p, memory_format=torch.preserve_format) + else: + exp_avg_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) + exp_avg_tmp.copy_(state['exp_avg']) + state['exp_avg'] = exp_avg_tmp + + exp_avg_sq_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) + exp_avg_sq_tmp.copy_(state['exp_avg_sq']) + state['exp_avg_sq'] = exp_avg_sq_tmp + + if amsgrad: + max_exp_avg_sq_tmp = torch.zeros_like(p, memory_format=torch.preserve_format) + max_exp_avg_sq_tmp.copy_(state['max_exp_avg_sq']) + state['max_exp_avg_sq'] = max_exp_avg_sq_tmp + + def _combine_group_param_states(self, group_index): + group = self.param_groups[group_index] + stash = self._amp_stash + group_params_list = stash.params_lists_indexed_by_group[group_index] + + amsgrad = group['amsgrad'] + + combined_param_states = [] + for params in group_params_list: + step_list = [] + exp_avg_list = [] + exp_avg_sq_list = [] + max_exp_avg_sq_list = [] + + for p in params: + if p.grad is None: + continue + grad = p.grad + if grad.is_sparse: + raise RuntimeError('NpuFusedAdamW does not support sparse gradients, ' + 'please consider SparseAdam instead') + + self._init_param_state(p, amsgrad) + state = self.state[p] + step_list.append(state['step']) + exp_avg_list.append(state['exp_avg']) + exp_avg_sq_list.append(state['exp_avg_sq']) + if amsgrad: + max_exp_avg_sq_list.append(state['max_exp_avg_sq']) + + combined_step = 0 + combined_exp_avg = None + combined_exp_avg_sq = None + combined_max_exp_avg_sq = None + + if len(exp_avg_list) > 0: + combined_step = step_list[0] + combined_exp_avg = combine_npu(exp_avg_list) + combined_exp_avg_sq = combine_npu(exp_avg_sq_list) + combined_max_exp_avg_sq = combine_npu(max_exp_avg_sq_list) + + combined_state = defaultdict(dict) + combined_state['step'] = combined_step + combined_state['exp_avg'] = combined_exp_avg + combined_state['exp_avg_sq'] = combined_exp_avg_sq + combined_state['max_exp_avg_sq'] = combined_max_exp_avg_sq + combined_param_states.append(combined_state) + stash.combined_param_states_indexed_by_group[group_index] = combined_param_states + + def _combine_param_states_by_group(self): + stash = self._amp_stash + if stash.param_states_are_combined_by_group: + return + + stash.combined_param_states_indexed_by_group = [] + for _ in self.param_groups: + stash.combined_param_states_indexed_by_group.append([]) + + for i, _ in enumerate(self.param_groups): + self._combine_group_param_states(i) + stash.param_states_are_combined_by_group = True + + def _group_step(self, group_index): + group = self.param_groups[group_index] + for p in group['params']: + if p.grad is None: + continue + + grad = p.grad + if grad.is_sparse: + raise RuntimeError('NpuFusedAdamW does not support sparse gradients, ' + 'please consider SparseAdam instead') + state_p = self.state[p] + state_p['step'] += 1 + + amsgrad = group['amsgrad'] + beta1, beta2 = group['betas'] + + stash = self._amp_stash + combined_group_params = stash.combined_params_indexed_by_group[group_index] + combined_group_grads = stash.combined_grads_indexed_by_group[group_index] + combined_group_param_states = stash.combined_param_states_indexed_by_group[group_index] + + for combined_param, combined_grad, combined_param_state in zip(combined_group_params, + combined_group_grads, + combined_group_param_states): + if combined_param is None or combined_grad is None: + continue + + # Perform stepweight decay. The fused method is used here to speed up the calculation + combined_param.mul_(1 - group['lr'] * group['weight_decay']) + + exp_avg, exp_avg_sq = combined_param_state['exp_avg'], combined_param_state['exp_avg_sq'] + if amsgrad: + max_exp_avg_sq = combined_param_state['max_exp_avg_sq'] + + combined_param_state['step'] += 1 + bias_correction1 = 1 - beta1 ** combined_param_state['step'] + bias_correction2 = 1 - beta2 ** combined_param_state['step'] + + # Decay the first and second moment running average coefficient + exp_avg.mul_(beta1).add_(combined_grad, alpha=1 - beta1) + exp_avg_sq.mul_(beta2).addcmul_(combined_grad, combined_grad, value=1 - beta2) + if amsgrad: + # Maintains the maximum of all 2nd moment running avg. till now + torch.max(max_exp_avg_sq, exp_avg_sq, out=max_exp_avg_sq) + # Use the max. for normalizing running avg. of gradient + denom = (max_exp_avg_sq.sqrt() / math.sqrt(bias_correction2)).add_(group['eps']) + else: + denom = (exp_avg_sq.sqrt() / math.sqrt(bias_correction2)).add_(group['eps']) + + step_size = group['lr'] / bias_correction1 + + combined_param.addcdiv_(exp_avg, denom, value=-step_size) + + @torch.no_grad() + def step(self, closure=None): + if not hasattr(self, "_amp_stash"): + raise RuntimeError('apex.optimizers.NpuFusedAdamW should be used with AMP.') + + self._check_already_combined_params_and_grads() + # combine params and grads first + self._combine_params_and_grads_by_group() + # then combine param states + self._combine_param_states_by_group() + + loss = None + if closure is not None: + with torch.enable_grad(): + loss = closure() + + for i, _ in enumerate(self.param_groups): + self._group_step(i) + + return loss diff --git a/PyTorch/contrib/cv/classification/Vit_small_patch16_224/train.py b/PyTorch/contrib/cv/classification/Vit_small_patch16_224/train.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/VoVNet39/test/train_eval_8p.sh b/PyTorch/contrib/cv/classification/VoVNet39/test/train_eval_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/VoVNet39/test/train_finetune_1p.sh b/PyTorch/contrib/cv/classification/VoVNet39/test/train_finetune_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/VoVNet39/test/train_full_8p.sh b/PyTorch/contrib/cv/classification/VoVNet39/test/train_full_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/VoVNet39/test/train_performance_1p.sh b/PyTorch/contrib/cv/classification/VoVNet39/test/train_performance_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/VoVNet39/test/train_performance_8p.sh b/PyTorch/contrib/cv/classification/VoVNet39/test/train_performance_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/Dockerfile b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/Dockerfile index 16a84a07a1..5889f35114 100644 --- a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/Dockerfile +++ b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/Dockerfile @@ -1,22 +1,22 @@ -ARG FROM_IMAGE_NAME -FROM ${FROM_IMAGE_NAME} - -ARG SDK_PKG - -RUN ln -s /usr/local/python3.7.5/bin/python3.7 /usr/bin/python - -RUN apt-get update && \ - apt-get install libglib2.0-dev -y || \ - rm -rf /var/lib/dpkg/info && \ - mkdir /var/lib/dpkg/info && \ - apt-get install libglib2.0-dev -y && \ - pip install pytest-runner==5.3.0 -COPY sdk/requirements.txt . -RUN pip3.7 install -r requirements.txt - -# pip install sdk_run -COPY $SDK_PKG . -RUN ls -hrlt -RUN chmod +x ${SDK_PKG} && \ - ./${SDK_PKG} --install && \ +ARG FROM_IMAGE_NAME +FROM ${FROM_IMAGE_NAME} + +ARG SDK_PKG + +RUN ln -s /usr/local/python3.7.5/bin/python3.7 /usr/bin/python + +RUN apt-get update && \ + apt-get install libglib2.0-dev -y || \ + rm -rf /var/lib/dpkg/info && \ + mkdir /var/lib/dpkg/info && \ + apt-get install libglib2.0-dev -y && \ + pip install pytest-runner==5.3.0 +COPY sdk/requirements.txt . +RUN pip3.7 install -r requirements.txt + +# pip install sdk_run +COPY $SDK_PKG . +RUN ls -hrlt +RUN chmod +x ${SDK_PKG} && \ + ./${SDK_PKG} --install && \ bash -c "source ~/.bashrc" \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/convert/xception_pt_aipp.config b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/convert/xception_pt_aipp.config index 5c8ab69380..649639850c 100644 --- a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/convert/xception_pt_aipp.config +++ b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/convert/xception_pt_aipp.config @@ -1,16 +1,16 @@ -aipp_op { - aipp_mode: static - input_format : RGB888_U8 - csc_switch : false - rbuv_swap_switch : true - - mean_chn_0 : 0 - mean_chn_1 : 0 - mean_chn_2 : 0 - min_chn_0 : 127.5 - min_chn_1 : 127.5 - min_chn_2 : 127.5 - var_reci_chn_0 : 0.007843137254902 - var_reci_chn_1 : 0.007843137254902 - var_reci_chn_2 : 0.007843137254902 -} +aipp_op { + aipp_mode: static + input_format : RGB888_U8 + csc_switch : false + rbuv_swap_switch : true + + mean_chn_0 : 0 + mean_chn_1 : 0 + mean_chn_2 : 0 + min_chn_0 : 127.5 + min_chn_1 : 127.5 + min_chn_2 : 127.5 + var_reci_chn_0 : 0.007843137254902 + var_reci_chn_1 : 0.007843137254902 + var_reci_chn_2 : 0.007843137254902 +} diff --git a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/models/xception_aipp.cfg b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/models/xception_aipp.cfg index d01feefc8e..75bba4acb3 100644 --- a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/models/xception_aipp.cfg +++ b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/models/xception_aipp.cfg @@ -1,3 +1,3 @@ -CLASS_NUM=1000 -SOFTMAX=True +CLASS_NUM=1000 +SOFTMAX=True TOP_K=5 \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/mxbase/CMakeLists.txt b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/mxbase/CMakeLists.txt index 53ff21c352..77b6604281 100644 --- a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/mxbase/CMakeLists.txt +++ b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/mxbase/CMakeLists.txt @@ -1,52 +1,52 @@ -cmake_minimum_required(VERSION 3.10.0) -project(xception) - -set(TARGET xception) - -add_definitions(-DENABLE_DVPP_INTERFACE) -add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) -add_definitions(-Dgoogle=mindxsdk_private) -add_compile_options(-std=c++11 -fPIE -fstack-protector-all -fPIC -Wall) -add_link_options(-Wl,-z,relro,-z,now,-z,noexecstack -s -pie) - -# Check environment variable -if(NOT DEFINED ENV{ASCEND_HOME}) - message(FATAL_ERROR "please define environment variable:ASCEND_HOME") -endif() -if(NOT DEFINED ENV{ASCEND_VERSION}) - message(WARNING "please define environment variable:ASCEND_VERSION") -endif() -if(NOT DEFINED ENV{ARCH_PATTERN}) - message(WARNING "please define environment variable:ARCH_PATTERN") -endif() -set(ACL_INC_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/include) -set(ACL_LIB_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/lib64) - -set(MXBASE_ROOT_DIR $ENV{MX_SDK_HOME}) -set(MXBASE_INC ${MXBASE_ROOT_DIR}/include) -set(MXBASE_LIB_DIR ${MXBASE_ROOT_DIR}/lib) -set(MXBASE_POST_LIB_DIR ${MXBASE_ROOT_DIR}/lib/modelpostprocessors) -set(MXBASE_POST_PROCESS_DIR ${MXBASE_ROOT_DIR}/include/MxBase/postprocess/include) - -if(DEFINED ENV{MXSDK_OPENSOURCE_DIR}) - set(OPENSOURCE_DIR $ENV{MXSDK_OPENSOURCE_DIR}) -else() - set(OPENSOURCE_DIR ${MXBASE_ROOT_DIR}/opensource) -endif() -include_directories(/home/data/ics_yu/mxVision-2.0.2/lib/modelpostprocessors/) -include_directories(${ACL_INC_DIR}) -include_directories(${OPENSOURCE_DIR}/include) -include_directories(${OPENSOURCE_DIR}/include/opencv4) - -include_directories(${MXBASE_INC}) -include_directories(${MXBASE_POST_PROCESS_DIR}) - -link_directories(${ACL_LIB_DIR}) -link_directories(${OPENSOURCE_DIR}/lib) -link_directories(${MXBASE_LIB_DIR}) -link_directories(${MXBASE_POST_LIB_DIR}) - -add_executable(${TARGET} main.cpp XceptionClassify.cpp) -target_link_libraries(${TARGET} glog cpprest mxbase resnet50postprocess opencv_world stdc++fs) - -install(TARGETS ${TARGET} RUNTIME DESTINATION ${PROJECT_SOURCE_DIR}/) +cmake_minimum_required(VERSION 3.10.0) +project(xception) + +set(TARGET xception) + +add_definitions(-DENABLE_DVPP_INTERFACE) +add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) +add_definitions(-Dgoogle=mindxsdk_private) +add_compile_options(-std=c++11 -fPIE -fstack-protector-all -fPIC -Wall) +add_link_options(-Wl,-z,relro,-z,now,-z,noexecstack -s -pie) + +# Check environment variable +if(NOT DEFINED ENV{ASCEND_HOME}) + message(FATAL_ERROR "please define environment variable:ASCEND_HOME") +endif() +if(NOT DEFINED ENV{ASCEND_VERSION}) + message(WARNING "please define environment variable:ASCEND_VERSION") +endif() +if(NOT DEFINED ENV{ARCH_PATTERN}) + message(WARNING "please define environment variable:ARCH_PATTERN") +endif() +set(ACL_INC_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/include) +set(ACL_LIB_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/lib64) + +set(MXBASE_ROOT_DIR $ENV{MX_SDK_HOME}) +set(MXBASE_INC ${MXBASE_ROOT_DIR}/include) +set(MXBASE_LIB_DIR ${MXBASE_ROOT_DIR}/lib) +set(MXBASE_POST_LIB_DIR ${MXBASE_ROOT_DIR}/lib/modelpostprocessors) +set(MXBASE_POST_PROCESS_DIR ${MXBASE_ROOT_DIR}/include/MxBase/postprocess/include) + +if(DEFINED ENV{MXSDK_OPENSOURCE_DIR}) + set(OPENSOURCE_DIR $ENV{MXSDK_OPENSOURCE_DIR}) +else() + set(OPENSOURCE_DIR ${MXBASE_ROOT_DIR}/opensource) +endif() +include_directories(/home/data/ics_yu/mxVision-2.0.2/lib/modelpostprocessors/) +include_directories(${ACL_INC_DIR}) +include_directories(${OPENSOURCE_DIR}/include) +include_directories(${OPENSOURCE_DIR}/include/opencv4) + +include_directories(${MXBASE_INC}) +include_directories(${MXBASE_POST_PROCESS_DIR}) + +link_directories(${ACL_LIB_DIR}) +link_directories(${OPENSOURCE_DIR}/lib) +link_directories(${MXBASE_LIB_DIR}) +link_directories(${MXBASE_POST_LIB_DIR}) + +add_executable(${TARGET} main.cpp XceptionClassify.cpp) +target_link_libraries(${TARGET} glog cpprest mxbase resnet50postprocess opencv_world stdc++fs) + +install(TARGETS ${TARGET} RUNTIME DESTINATION ${PROJECT_SOURCE_DIR}/) diff --git a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/mxbase/XceptionClassify.cpp b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/mxbase/XceptionClassify.cpp index 929bd67d85..61acb36242 100644 --- a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/mxbase/XceptionClassify.cpp +++ b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/mxbase/XceptionClassify.cpp @@ -1,250 +1,250 @@ -/* - * Copyright 2021 Huawei Technologies Co., Ltd. - * - * 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. - */ - -#include -#include -#include "XceptionClassify.h" -#include "MxBase/DeviceManager/DeviceManager.h" -#include "MxBase/Log/Log.h" - -using namespace MxBase; -namespace { -const uint32_t YUV_BYTE_NU = 3; -const uint32_t YUV_BYTE_DE = 2; -const uint32_t VPC_H_ALIGN = 2; -} - -APP_ERROR XceptionClassify::Init(const InitParam &initParam) -{ - deviceId_ = initParam.deviceId; - APP_ERROR ret = MxBase::DeviceManager::GetInstance()->InitDevices(); - if (ret != APP_ERR_OK) { - LogError << "Init devices failed, ret=" << ret << "."; - return ret; - } - ret = MxBase::TensorContext::GetInstance()->SetContext(initParam.deviceId); - if (ret != APP_ERR_OK) { - LogError << "Set context failed, ret=" << ret << "."; - return ret; - } - dvppWrapper_ = std::make_shared(); - ret = dvppWrapper_->Init(); - if (ret != APP_ERR_OK) { - LogError << "DvppWrapper init failed, ret=" << ret << "."; - return ret; - } - model_ = std::make_shared(); - ret = model_->Init(initParam.modelPath, modelDesc_); - if (ret != APP_ERR_OK) { - LogError << "ModelInferenceProcessor init failed, ret=" << ret << "."; - return ret; - } - MxBase::ConfigData configData; - const std::string softmax = initParam.softmax ? "true" : "false"; - const std::string checkTensor = initParam.checkTensor ? "true" : "false"; - - configData.SetJsonValue("CLASS_NUM", std::to_string(initParam.classNum)); - configData.SetJsonValue("TOP_K", std::to_string(initParam.topk)); - configData.SetJsonValue("SOFTMAX", softmax); - configData.SetJsonValue("CHECK_MODEL", checkTensor); - - auto jsonStr = configData.GetCfgJson().serialize(); - std::map> config; - config["postProcessConfigContent"] = std::make_shared(jsonStr); - config["labelPath"] = std::make_shared(initParam.labelPath); - - post_ = std::make_shared(); - ret = post_->Init(config); - if (ret != APP_ERR_OK) { - LogError << "Resnet50PostProcess init failed, ret=" << ret << "."; - return ret; - } - return APP_ERR_OK; -} - -APP_ERROR XceptionClassify::DeInit() -{ - dvppWrapper_->DeInit(); - model_->DeInit(); - post_->DeInit(); - MxBase::DeviceManager::GetInstance()->DestroyDevices(); - return APP_ERR_OK; -} - -void XceptionClassify::ReadImage(const std::string &imgPath, cv::Mat &imageMat) -{ - imageMat = cv::imread(imgPath, cv::IMREAD_COLOR); -} - -void XceptionClassify::CenterCropImage(cv::Mat &img, cv::Mat &cropImg) -{ - float central_fraction = 0.75; - int crop_x = img.cols * central_fraction; - int crop_y = img.rows * central_fraction; - int crop_x1 = (img.cols - crop_x) / 2; - int crop_y1 = (img.rows - crop_y) / 2; - - cv::Rect myROI(crop_x1, crop_y1, crop_x, crop_y); - LogInfo << "images crop_x1: " << crop_x1 << ", crop_x: " << crop_x << ", crop_y1: " << crop_y1 << ", crop_y: " << crop_y; - cropImg = img(myROI); -} - -void XceptionClassify::Resize(const cv::Mat &srcImageMat, cv::Mat &dstImageMat) -{ - static constexpr uint32_t resizeHeight = 299; - static constexpr uint32_t resizeWidth = 299; - - cv::resize(srcImageMat, dstImageMat, cv::Size(resizeWidth, resizeHeight)); -} - -APP_ERROR XceptionClassify::CVMatToTensorBase(const cv::Mat &imageMat, MxBase::TensorBase &tensorBase) -{ - const uint32_t dataSize = imageMat.cols * imageMat.rows * YUV444_RGB_WIDTH_NU; - MemoryData memoryDataDst(dataSize, MemoryData::MEMORY_DEVICE, deviceId_); - MemoryData memoryDataSrc(imageMat.data, dataSize, MemoryData::MEMORY_HOST_MALLOC); - - APP_ERROR ret = MemoryHelper::MxbsMallocAndCopy(memoryDataDst, memoryDataSrc); - if (ret != APP_ERR_OK) { - LogError << GetError(ret) << "Memory malloc failed."; - return ret; - } - std::vector shape = {imageMat.rows * YUV444_RGB_WIDTH_NU, static_cast(imageMat.cols)}; - tensorBase = TensorBase(memoryDataDst, false, shape, TENSOR_DTYPE_UINT8); - return APP_ERR_OK; -} - -APP_ERROR XceptionClassify::Inference(const std::vector &inputs, std::vector &outputs) -{ - auto dtypes = model_->GetOutputDataType(); - for (size_t i = 0; i < modelDesc_.outputTensors.size(); ++i) { - std::vector shape = {}; - for (size_t j = 0; j < modelDesc_.outputTensors[i].tensorDims.size(); ++j) { - shape.push_back((uint32_t)modelDesc_.outputTensors[i].tensorDims[j]); - } - TensorBase tensor(shape, dtypes[i], MemoryData::MemoryType::MEMORY_DEVICE, deviceId_); - APP_ERROR ret = TensorBase::TensorBaseMalloc(tensor); - if (ret != APP_ERR_OK) { - LogError << "TensorBaseMalloc failed, ret=" << ret << "."; - return ret; - } - outputs.push_back(tensor); - } - DynamicInfo dynamicInfo = {}; - dynamicInfo.dynamicType = DynamicType::STATIC_BATCH; - auto startTime = std::chrono::high_resolution_clock::now(); // search for learning - APP_ERROR ret = model_->ModelInference(inputs, outputs, dynamicInfo); - auto endTime = std::chrono::high_resolution_clock::now(); - double costMs = std::chrono::duration(endTime - startTime).count(); - g_inferCost.push_back(costMs); - if (ret != APP_ERR_OK) { - LogError << "ModelInference failed, ret=" << ret << "."; - return ret; - } - return APP_ERR_OK; -} - -APP_ERROR XceptionClassify::PostProcess(const std::vector &inputs, std::vector> &clsInfos) -{ - - APP_ERROR ret = post_->Process(inputs, clsInfos); - - if (ret != APP_ERR_OK) { - LogError << "Process failed, ret=" << ret << "."; - return ret; - } - return APP_ERR_OK; -} - -APP_ERROR XceptionClassify::SaveInferResult(const std::string &imagePath, std::vector> &batchClsInfos) -{ - uint32_t batchIndex = 0; - LogInfo << "image path: " << imagePath; - std::string fileName = imagePath.substr(imagePath.find_last_of("/") + 1); - size_t dot = fileName.find_last_of("."); - - std::string resultPathName = "result"; - if (access(resultPathName.c_str(), 0) != 0) { - APP_ERROR ret = mkdir(resultPathName.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); - if (ret != 0) { - LogError << "Failed to create result directory: " << resultPathName << ", ret = " << ret; - return APP_ERR_COMM_FAILURE; - } - } - std::string resFileName = "result/" + fileName.substr(0,dot) + "_1.txt"; - LogInfo << "file path for saving result: " << resFileName; - std::ofstream tfile(resFileName); - if (tfile.fail()) { - LogError << "Failed to open result file"; - return APP_ERR_COMM_FAILURE; - } - - for (auto clsInfos : batchClsInfos) { - std::string resultStr = ""; - for (auto clsInfo : clsInfos) { - LogDebug << "batchIndex: " << batchIndex << " className: " << clsInfo.className - << " confidence: " << clsInfo.confidence << " classIndex: " << clsInfo.classId; - resultStr += std::to_string(clsInfo.classId) + " "; - } - tfile << resultStr << std::endl; - batchIndex += 1; - } - tfile.close(); - return APP_ERR_OK; -} - -APP_ERROR XceptionClassify::Process(const std::string &imgPath) -{ - cv::Mat imageMat; - - ReadImage(imgPath, imageMat); - CenterCropImage(imageMat, imageMat); - Resize(imageMat, imageMat); - - std::vector inputs = {}; - std::vector outputs = {}; - TensorBase tensorBase; - - APP_ERROR ret = CVMatToTensorBase(imageMat, tensorBase); - if (ret != APP_ERR_OK) { - LogError << "CVMatToTensorBase failed, ret=" << ret << "."; - return ret; - } - - inputs.push_back(tensorBase); - - ret = Inference(inputs, outputs); - if (ret != APP_ERR_OK) { - LogError << "Inference failed, ret=" << ret << "."; - return ret; - } - - std::vector> BatchClsInfos = {}; - ret = PostProcess(outputs, BatchClsInfos); - if (ret != APP_ERR_OK) { - LogError << "PostProcess failed, ret=" << ret << "."; - return ret; - } - - ret = SaveInferResult(imgPath, BatchClsInfos); - if (ret != APP_ERR_OK) { - LogError << "Save results failed, ret: " << ret << "."; - return ret; - } - - imageMat.release(); - return APP_ERR_OK; -} - +/* + * Copyright 2021 Huawei Technologies Co., Ltd. + * + * 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. + */ + +#include +#include +#include "XceptionClassify.h" +#include "MxBase/DeviceManager/DeviceManager.h" +#include "MxBase/Log/Log.h" + +using namespace MxBase; +namespace { +const uint32_t YUV_BYTE_NU = 3; +const uint32_t YUV_BYTE_DE = 2; +const uint32_t VPC_H_ALIGN = 2; +} + +APP_ERROR XceptionClassify::Init(const InitParam &initParam) +{ + deviceId_ = initParam.deviceId; + APP_ERROR ret = MxBase::DeviceManager::GetInstance()->InitDevices(); + if (ret != APP_ERR_OK) { + LogError << "Init devices failed, ret=" << ret << "."; + return ret; + } + ret = MxBase::TensorContext::GetInstance()->SetContext(initParam.deviceId); + if (ret != APP_ERR_OK) { + LogError << "Set context failed, ret=" << ret << "."; + return ret; + } + dvppWrapper_ = std::make_shared(); + ret = dvppWrapper_->Init(); + if (ret != APP_ERR_OK) { + LogError << "DvppWrapper init failed, ret=" << ret << "."; + return ret; + } + model_ = std::make_shared(); + ret = model_->Init(initParam.modelPath, modelDesc_); + if (ret != APP_ERR_OK) { + LogError << "ModelInferenceProcessor init failed, ret=" << ret << "."; + return ret; + } + MxBase::ConfigData configData; + const std::string softmax = initParam.softmax ? "true" : "false"; + const std::string checkTensor = initParam.checkTensor ? "true" : "false"; + + configData.SetJsonValue("CLASS_NUM", std::to_string(initParam.classNum)); + configData.SetJsonValue("TOP_K", std::to_string(initParam.topk)); + configData.SetJsonValue("SOFTMAX", softmax); + configData.SetJsonValue("CHECK_MODEL", checkTensor); + + auto jsonStr = configData.GetCfgJson().serialize(); + std::map> config; + config["postProcessConfigContent"] = std::make_shared(jsonStr); + config["labelPath"] = std::make_shared(initParam.labelPath); + + post_ = std::make_shared(); + ret = post_->Init(config); + if (ret != APP_ERR_OK) { + LogError << "Resnet50PostProcess init failed, ret=" << ret << "."; + return ret; + } + return APP_ERR_OK; +} + +APP_ERROR XceptionClassify::DeInit() +{ + dvppWrapper_->DeInit(); + model_->DeInit(); + post_->DeInit(); + MxBase::DeviceManager::GetInstance()->DestroyDevices(); + return APP_ERR_OK; +} + +void XceptionClassify::ReadImage(const std::string &imgPath, cv::Mat &imageMat) +{ + imageMat = cv::imread(imgPath, cv::IMREAD_COLOR); +} + +void XceptionClassify::CenterCropImage(cv::Mat &img, cv::Mat &cropImg) +{ + float central_fraction = 0.75; + int crop_x = img.cols * central_fraction; + int crop_y = img.rows * central_fraction; + int crop_x1 = (img.cols - crop_x) / 2; + int crop_y1 = (img.rows - crop_y) / 2; + + cv::Rect myROI(crop_x1, crop_y1, crop_x, crop_y); + LogInfo << "images crop_x1: " << crop_x1 << ", crop_x: " << crop_x << ", crop_y1: " << crop_y1 << ", crop_y: " << crop_y; + cropImg = img(myROI); +} + +void XceptionClassify::Resize(const cv::Mat &srcImageMat, cv::Mat &dstImageMat) +{ + static constexpr uint32_t resizeHeight = 299; + static constexpr uint32_t resizeWidth = 299; + + cv::resize(srcImageMat, dstImageMat, cv::Size(resizeWidth, resizeHeight)); +} + +APP_ERROR XceptionClassify::CVMatToTensorBase(const cv::Mat &imageMat, MxBase::TensorBase &tensorBase) +{ + const uint32_t dataSize = imageMat.cols * imageMat.rows * YUV444_RGB_WIDTH_NU; + MemoryData memoryDataDst(dataSize, MemoryData::MEMORY_DEVICE, deviceId_); + MemoryData memoryDataSrc(imageMat.data, dataSize, MemoryData::MEMORY_HOST_MALLOC); + + APP_ERROR ret = MemoryHelper::MxbsMallocAndCopy(memoryDataDst, memoryDataSrc); + if (ret != APP_ERR_OK) { + LogError << GetError(ret) << "Memory malloc failed."; + return ret; + } + std::vector shape = {imageMat.rows * YUV444_RGB_WIDTH_NU, static_cast(imageMat.cols)}; + tensorBase = TensorBase(memoryDataDst, false, shape, TENSOR_DTYPE_UINT8); + return APP_ERR_OK; +} + +APP_ERROR XceptionClassify::Inference(const std::vector &inputs, std::vector &outputs) +{ + auto dtypes = model_->GetOutputDataType(); + for (size_t i = 0; i < modelDesc_.outputTensors.size(); ++i) { + std::vector shape = {}; + for (size_t j = 0; j < modelDesc_.outputTensors[i].tensorDims.size(); ++j) { + shape.push_back((uint32_t)modelDesc_.outputTensors[i].tensorDims[j]); + } + TensorBase tensor(shape, dtypes[i], MemoryData::MemoryType::MEMORY_DEVICE, deviceId_); + APP_ERROR ret = TensorBase::TensorBaseMalloc(tensor); + if (ret != APP_ERR_OK) { + LogError << "TensorBaseMalloc failed, ret=" << ret << "."; + return ret; + } + outputs.push_back(tensor); + } + DynamicInfo dynamicInfo = {}; + dynamicInfo.dynamicType = DynamicType::STATIC_BATCH; + auto startTime = std::chrono::high_resolution_clock::now(); // search for learning + APP_ERROR ret = model_->ModelInference(inputs, outputs, dynamicInfo); + auto endTime = std::chrono::high_resolution_clock::now(); + double costMs = std::chrono::duration(endTime - startTime).count(); + g_inferCost.push_back(costMs); + if (ret != APP_ERR_OK) { + LogError << "ModelInference failed, ret=" << ret << "."; + return ret; + } + return APP_ERR_OK; +} + +APP_ERROR XceptionClassify::PostProcess(const std::vector &inputs, std::vector> &clsInfos) +{ + + APP_ERROR ret = post_->Process(inputs, clsInfos); + + if (ret != APP_ERR_OK) { + LogError << "Process failed, ret=" << ret << "."; + return ret; + } + return APP_ERR_OK; +} + +APP_ERROR XceptionClassify::SaveInferResult(const std::string &imagePath, std::vector> &batchClsInfos) +{ + uint32_t batchIndex = 0; + LogInfo << "image path: " << imagePath; + std::string fileName = imagePath.substr(imagePath.find_last_of("/") + 1); + size_t dot = fileName.find_last_of("."); + + std::string resultPathName = "result"; + if (access(resultPathName.c_str(), 0) != 0) { + APP_ERROR ret = mkdir(resultPathName.c_str(), S_IRUSR | S_IWUSR | S_IXUSR); + if (ret != 0) { + LogError << "Failed to create result directory: " << resultPathName << ", ret = " << ret; + return APP_ERR_COMM_FAILURE; + } + } + std::string resFileName = "result/" + fileName.substr(0,dot) + "_1.txt"; + LogInfo << "file path for saving result: " << resFileName; + std::ofstream tfile(resFileName); + if (tfile.fail()) { + LogError << "Failed to open result file"; + return APP_ERR_COMM_FAILURE; + } + + for (auto clsInfos : batchClsInfos) { + std::string resultStr = ""; + for (auto clsInfo : clsInfos) { + LogDebug << "batchIndex: " << batchIndex << " className: " << clsInfo.className + << " confidence: " << clsInfo.confidence << " classIndex: " << clsInfo.classId; + resultStr += std::to_string(clsInfo.classId) + " "; + } + tfile << resultStr << std::endl; + batchIndex += 1; + } + tfile.close(); + return APP_ERR_OK; +} + +APP_ERROR XceptionClassify::Process(const std::string &imgPath) +{ + cv::Mat imageMat; + + ReadImage(imgPath, imageMat); + CenterCropImage(imageMat, imageMat); + Resize(imageMat, imageMat); + + std::vector inputs = {}; + std::vector outputs = {}; + TensorBase tensorBase; + + APP_ERROR ret = CVMatToTensorBase(imageMat, tensorBase); + if (ret != APP_ERR_OK) { + LogError << "CVMatToTensorBase failed, ret=" << ret << "."; + return ret; + } + + inputs.push_back(tensorBase); + + ret = Inference(inputs, outputs); + if (ret != APP_ERR_OK) { + LogError << "Inference failed, ret=" << ret << "."; + return ret; + } + + std::vector> BatchClsInfos = {}; + ret = PostProcess(outputs, BatchClsInfos); + if (ret != APP_ERR_OK) { + LogError << "PostProcess failed, ret=" << ret << "."; + return ret; + } + + ret = SaveInferResult(imgPath, BatchClsInfos); + if (ret != APP_ERR_OK) { + LogError << "Save results failed, ret: " << ret << "."; + return ret; + } + + imageMat.release(); + return APP_ERR_OK; +} + diff --git a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/mxbase/XceptionClassify.h b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/mxbase/XceptionClassify.h index 4a857b6813..6d37dae3c6 100644 --- a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/mxbase/XceptionClassify.h +++ b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/mxbase/XceptionClassify.h @@ -1,58 +1,58 @@ -/* - * Copyright 2021 Huawei Technologies Co., Ltd. - * - * 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. - */ - - -#ifndef MXBASE_XCEPTIONCLASSIFY_H -#define MXBASE_XCEPTIONCLASSIFY_H - -#include -#include "MxBase/DvppWrapper/DvppWrapper.h" -#include "MxBase/ModelInfer/ModelInferenceProcessor.h" -#include "ClassPostProcessors/Resnet50PostProcess.h" -#include "MxBase/Tensor/TensorContext/TensorContext.h" - -extern std::vector g_inferCost; - -struct InitParam { - uint32_t deviceId; - std::string labelPath; - uint32_t classNum; - uint32_t topk; - bool softmax; - bool checkTensor; - std::string modelPath; -}; - -class XceptionClassify { -public: - APP_ERROR Init(const InitParam &initParam); - APP_ERROR DeInit(); - void ReadImage(const std::string &imgPath, cv::Mat &imageMat); - void Resize(const cv::Mat &srcImageMat, cv::Mat &dstImageMat); - void CenterCropImage(cv::Mat &img, cv::Mat &cropImg); - APP_ERROR CVMatToTensorBase(const cv::Mat &imageMat, MxBase::TensorBase &tensorBase); - APP_ERROR Inference(const std::vector &inputs, std::vector &outputs); - APP_ERROR PostProcess(const std::vector &inputs,std::vector> &clsInfos); - APP_ERROR SaveInferResult(const std::string &imgPath,std::vector> &batchClsInfos); - APP_ERROR Process(const std::string &imgPath); -private: - std::shared_ptr dvppWrapper_; - std::shared_ptr model_; - std::shared_ptr post_; - MxBase::ModelDesc modelDesc_; - uint32_t deviceId_ = 0; -}; -#endif +/* + * Copyright 2021 Huawei Technologies Co., Ltd. + * + * 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. + */ + + +#ifndef MXBASE_XCEPTIONCLASSIFY_H +#define MXBASE_XCEPTIONCLASSIFY_H + +#include +#include "MxBase/DvppWrapper/DvppWrapper.h" +#include "MxBase/ModelInfer/ModelInferenceProcessor.h" +#include "ClassPostProcessors/Resnet50PostProcess.h" +#include "MxBase/Tensor/TensorContext/TensorContext.h" + +extern std::vector g_inferCost; + +struct InitParam { + uint32_t deviceId; + std::string labelPath; + uint32_t classNum; + uint32_t topk; + bool softmax; + bool checkTensor; + std::string modelPath; +}; + +class XceptionClassify { +public: + APP_ERROR Init(const InitParam &initParam); + APP_ERROR DeInit(); + void ReadImage(const std::string &imgPath, cv::Mat &imageMat); + void Resize(const cv::Mat &srcImageMat, cv::Mat &dstImageMat); + void CenterCropImage(cv::Mat &img, cv::Mat &cropImg); + APP_ERROR CVMatToTensorBase(const cv::Mat &imageMat, MxBase::TensorBase &tensorBase); + APP_ERROR Inference(const std::vector &inputs, std::vector &outputs); + APP_ERROR PostProcess(const std::vector &inputs,std::vector> &clsInfos); + APP_ERROR SaveInferResult(const std::string &imgPath,std::vector> &batchClsInfos); + APP_ERROR Process(const std::string &imgPath); +private: + std::shared_ptr dvppWrapper_; + std::shared_ptr model_; + std::shared_ptr post_; + MxBase::ModelDesc modelDesc_; + uint32_t deviceId_ = 0; +}; +#endif diff --git a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/mxbase/main.cpp b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/mxbase/main.cpp index 2f231330e2..b616fe2920 100644 --- a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/mxbase/main.cpp +++ b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/mxbase/main.cpp @@ -1,69 +1,69 @@ -/* - * Copyright 2021 Huawei Technologies Co., Ltd. - * - * 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. - */ - -#include -#include -#include -#include "XceptionClassify.h" -#include "MxBase/Log/Log.h" - -namespace fs = std::experimental::filesystem; -namespace { -const uint32_t CLASS_NUM = 1000; -} -std::vector g_inferCost; - -int main(int argc, char* argv[]) -{ - if (argc <= 1) { - LogWarn << "Please input image path, such as './build/xception ./image_dir'."; - return APP_ERR_OK; - } - - InitParam initParam = {}; - initParam.deviceId = 0; - initParam.classNum = CLASS_NUM; - initParam.labelPath = "../sdk/models/imagenet1000_clsidx_to_labels.names"; - initParam.topk = 5; - initParam.softmax = true; - initParam.checkTensor = true; - initParam.modelPath = "../sdk/models/xception_pt_pytorch.om"; - auto xception = std::make_shared(); - APP_ERROR ret = xception->Init(initParam); - if (ret != APP_ERR_OK) { - LogError << "XceptionClassify init failed, ret=" << ret << "."; - return ret; - } - - std::string imgDir = argv[1]; - for (auto & entry : fs::directory_iterator(imgDir)) { - LogInfo << "read image path " << entry.path(); - ret = xception->Process(entry.path()); - if (ret != APP_ERR_OK) { - LogError << "XceptionClassify process failed, ret=" << ret << "."; - xception->DeInit(); - return ret; - } - } - xception->DeInit(); - double costSum = 0; - for (unsigned int i = 0; i < g_inferCost.size(); i++) { - costSum += g_inferCost[i]; - } - LogInfo << "Infer images sum " << g_inferCost.size() << ", cost total time: " << costSum << " ms."; - LogInfo << "The throughput: " << g_inferCost.size() * 1000 / costSum << " images/sec."; - return APP_ERR_OK; -} +/* + * Copyright 2021 Huawei Technologies Co., Ltd. + * + * 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. + */ + +#include +#include +#include +#include "XceptionClassify.h" +#include "MxBase/Log/Log.h" + +namespace fs = std::experimental::filesystem; +namespace { +const uint32_t CLASS_NUM = 1000; +} +std::vector g_inferCost; + +int main(int argc, char* argv[]) +{ + if (argc <= 1) { + LogWarn << "Please input image path, such as './build/xception ./image_dir'."; + return APP_ERR_OK; + } + + InitParam initParam = {}; + initParam.deviceId = 0; + initParam.classNum = CLASS_NUM; + initParam.labelPath = "../sdk/models/imagenet1000_clsidx_to_labels.names"; + initParam.topk = 5; + initParam.softmax = true; + initParam.checkTensor = true; + initParam.modelPath = "../sdk/models/xception_pt_pytorch.om"; + auto xception = std::make_shared(); + APP_ERROR ret = xception->Init(initParam); + if (ret != APP_ERR_OK) { + LogError << "XceptionClassify init failed, ret=" << ret << "."; + return ret; + } + + std::string imgDir = argv[1]; + for (auto & entry : fs::directory_iterator(imgDir)) { + LogInfo << "read image path " << entry.path(); + ret = xception->Process(entry.path()); + if (ret != APP_ERR_OK) { + LogError << "XceptionClassify process failed, ret=" << ret << "."; + xception->DeInit(); + return ret; + } + } + xception->DeInit(); + double costSum = 0; + for (unsigned int i = 0; i < g_inferCost.size(); i++) { + costSum += g_inferCost[i]; + } + LogInfo << "Infer images sum " << g_inferCost.size() << ", cost total time: " << costSum << " ms."; + LogInfo << "The throughput: " << g_inferCost.size() * 1000 / costSum << " images/sec."; + return APP_ERR_OK; +} diff --git a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/sdk/main_xception_opencv.py b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/sdk/main_xception_opencv.py index 7b970e106c..3f88491da4 100644 --- a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/sdk/main_xception_opencv.py +++ b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/sdk/main_xception_opencv.py @@ -1,95 +1,95 @@ -# Copyright 2021 Huawei Technologies Co., Ltd. - -# 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 StreamManagerApi import StreamManagerApi, MxDataInput -import os -import cv2 -import json -import numpy as np -import MxpiDataType_pb2 as MxpiDataType -import datetime -import sys - -def run(): - # init stream manager - stream_manager_api = StreamManagerApi() - ret = stream_manager_api.InitManager() - if ret != 0: - print("Failed to init Stream manager, ret=%s" % str(ret)) - return - - # create streams by pipeline config file - with open("./pipeline/xception_opencv.pipeline", 'rb') as f: - pipeline_str = f.read() - ret = stream_manager_api.CreateMultipleStreams(pipeline_str) - - if ret != 0: - print("Failed to create Stream, ret=%s" % str(ret)) - return - - # Construct the input of the stream - data_input = MxDataInput() - - dir_name = './val_union/' - res_dir_name = 'xception_npu_result' - - file_list = os.listdir(dir_name) - if not os.path.exists(res_dir_name): - os.makedirs(res_dir_name) - for file_name in file_list: - print(file_name) - file_path = os.path.join(dir_name, file_name) - if not file_name.lower().endswith((".JPEG", ".jpeg", "JPG", "jpg")): - continue - portion = os.path.splitext(file_name) - with open(file_path, 'rb') as f: - data_input.data = f.read() - - empty_data = [] - - stream_name = b'im_xception' - in_plugin_id = 0 - uniqueId = stream_manager_api.SendData(stream_name, in_plugin_id, data_input) - if uniqueId < 0: - print("Failed to send data to stream.") - exit() - # Obtain the inference result by specifying stream_name and uniqueId. - start_time = datetime.datetime.now() - infer_result = stream_manager_api.GetResult(stream_name, uniqueId) - end_time = datetime.datetime.now() - print('sdk run time: {}'.format((end_time - start_time).microseconds)) - if infer_result.errorCode != 0: - print("GetResultWithUniqueId error. errorCode=%d, errorMsg=%s" % ( - infer_result.errorCode, infer_result.data.decode())) - exit() - # print the infer result - print(infer_result.data.decode()) - - load_dict = json.loads(infer_result.data.decode()) - if load_dict.get('MxpiClass') is None: - with open(res_dir_name + "/" + file_name[:-5] + '.txt', 'w') as f_write: - f_write.write("") - continue - res_vec = load_dict['MxpiClass'] - - with open(res_dir_name + "/" + file_name[:-5] + '_1.txt', 'w') as f_write: - list1 = [str(item.get("classId")) + " " for item in res_vec] - f_write.writelines(list1) - f_write.write('\n') - - # destroy streams - stream_manager_api.DestroyAllStreams() - -if __name__ == '__main__': - run() +# Copyright 2021 Huawei Technologies Co., Ltd. + +# 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 StreamManagerApi import StreamManagerApi, MxDataInput +import os +import cv2 +import json +import numpy as np +import MxpiDataType_pb2 as MxpiDataType +import datetime +import sys + +def run(): + # init stream manager + stream_manager_api = StreamManagerApi() + ret = stream_manager_api.InitManager() + if ret != 0: + print("Failed to init Stream manager, ret=%s" % str(ret)) + return + + # create streams by pipeline config file + with open("./pipeline/xception_opencv.pipeline", 'rb') as f: + pipeline_str = f.read() + ret = stream_manager_api.CreateMultipleStreams(pipeline_str) + + if ret != 0: + print("Failed to create Stream, ret=%s" % str(ret)) + return + + # Construct the input of the stream + data_input = MxDataInput() + + dir_name = './val_union/' + res_dir_name = 'xception_npu_result' + + file_list = os.listdir(dir_name) + if not os.path.exists(res_dir_name): + os.makedirs(res_dir_name) + for file_name in file_list: + print(file_name) + file_path = os.path.join(dir_name, file_name) + if not file_name.lower().endswith((".JPEG", ".jpeg", "JPG", "jpg")): + continue + portion = os.path.splitext(file_name) + with open(file_path, 'rb') as f: + data_input.data = f.read() + + empty_data = [] + + stream_name = b'im_xception' + in_plugin_id = 0 + uniqueId = stream_manager_api.SendData(stream_name, in_plugin_id, data_input) + if uniqueId < 0: + print("Failed to send data to stream.") + exit() + # Obtain the inference result by specifying stream_name and uniqueId. + start_time = datetime.datetime.now() + infer_result = stream_manager_api.GetResult(stream_name, uniqueId) + end_time = datetime.datetime.now() + print('sdk run time: {}'.format((end_time - start_time).microseconds)) + if infer_result.errorCode != 0: + print("GetResultWithUniqueId error. errorCode=%d, errorMsg=%s" % ( + infer_result.errorCode, infer_result.data.decode())) + exit() + # print the infer result + print(infer_result.data.decode()) + + load_dict = json.loads(infer_result.data.decode()) + if load_dict.get('MxpiClass') is None: + with open(res_dir_name + "/" + file_name[:-5] + '.txt', 'w') as f_write: + f_write.write("") + continue + res_vec = load_dict['MxpiClass'] + + with open(res_dir_name + "/" + file_name[:-5] + '_1.txt', 'w') as f_write: + list1 = [str(item.get("classId")) + " " for item in res_vec] + f_write.writelines(list1) + f_write.write('\n') + + # destroy streams + stream_manager_api.DestroyAllStreams() + +if __name__ == '__main__': + run() diff --git a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/sdk/pipeline/xception_opencv.pipeline b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/sdk/pipeline/xception_opencv.pipeline index 2944e83d02..e89cf88bc0 100644 --- a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/sdk/pipeline/xception_opencv.pipeline +++ b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/sdk/pipeline/xception_opencv.pipeline @@ -1,73 +1,73 @@ -{ - "im_xception": { - "stream_config": { - "deviceId": "0" - }, - "appsrc1": { - "props": { - "blocksize": "409600" - }, - "factory": "appsrc", - "next": "mxpi_imagedecoder0" - }, - "mxpi_imagedecoder0": { - "props": { - "handleMethod": "opencv" - }, - "factory": "mxpi_imagedecoder", - "next": "mxpi_imageresize0" - }, - "mxpi_imageresize0": { - "props": { - "handleMethod": "opencv", - "resizeType": "Resizer_Stretch", - "resizeHeight": "355", - "resizeWidth": "355" - }, - "factory": "mxpi_imageresize", - "next": "mxpi_opencvcentercrop0" - }, - "mxpi_opencvcentercrop0": { - "props": { - "dataSource": "mxpi_imageresize0", - "cropHeight": "299", - "cropWidth": "299" - }, - "factory": "mxpi_opencvcentercrop", - "next": "mxpi_tensorinfer0" - }, - "mxpi_tensorinfer0": { - "props": { - "dataSource": "mxpi_opencvcentercrop0", - "modelPath": "../models/xception_pt_pytorch.om", - "waitingTime": "2000", - "outputDeviceId": "-1" - }, - "factory": "mxpi_tensorinfer", - "next": "mxpi_classpostprocessor0" - }, - "mxpi_classpostprocessor0": { - "props": { - "dataSource": "mxpi_tensorinfer0", - "postProcessConfigPath": "../models/xception_aipp.cfg", - "labelPath": "../models/imagenet1000_clsidx_to_labels.names", - "postProcessLibPath": "/usr/local/sdk_home/mxManufacture/lib/modelpostprocessors/libresnet50postprocess.so" - }, - "factory": "mxpi_classpostprocessor", - "next": "mxpi_dataserialize0" - }, - "mxpi_dataserialize0": { - "props": { - "outputDataKeys": "mxpi_classpostprocessor0" - }, - "factory": "mxpi_dataserialize", - "next": "appsink0" - }, - "appsink0": { - "props": { - "blocksize": "4096000" - }, - "factory": "appsink" - } - } -} +{ + "im_xception": { + "stream_config": { + "deviceId": "0" + }, + "appsrc1": { + "props": { + "blocksize": "409600" + }, + "factory": "appsrc", + "next": "mxpi_imagedecoder0" + }, + "mxpi_imagedecoder0": { + "props": { + "handleMethod": "opencv" + }, + "factory": "mxpi_imagedecoder", + "next": "mxpi_imageresize0" + }, + "mxpi_imageresize0": { + "props": { + "handleMethod": "opencv", + "resizeType": "Resizer_Stretch", + "resizeHeight": "355", + "resizeWidth": "355" + }, + "factory": "mxpi_imageresize", + "next": "mxpi_opencvcentercrop0" + }, + "mxpi_opencvcentercrop0": { + "props": { + "dataSource": "mxpi_imageresize0", + "cropHeight": "299", + "cropWidth": "299" + }, + "factory": "mxpi_opencvcentercrop", + "next": "mxpi_tensorinfer0" + }, + "mxpi_tensorinfer0": { + "props": { + "dataSource": "mxpi_opencvcentercrop0", + "modelPath": "../models/xception_pt_pytorch.om", + "waitingTime": "2000", + "outputDeviceId": "-1" + }, + "factory": "mxpi_tensorinfer", + "next": "mxpi_classpostprocessor0" + }, + "mxpi_classpostprocessor0": { + "props": { + "dataSource": "mxpi_tensorinfer0", + "postProcessConfigPath": "../models/xception_aipp.cfg", + "labelPath": "../models/imagenet1000_clsidx_to_labels.names", + "postProcessLibPath": "/usr/local/sdk_home/mxManufacture/lib/modelpostprocessors/libresnet50postprocess.so" + }, + "factory": "mxpi_classpostprocessor", + "next": "mxpi_dataserialize0" + }, + "mxpi_dataserialize0": { + "props": { + "outputDataKeys": "mxpi_classpostprocessor0" + }, + "factory": "mxpi_dataserialize", + "next": "appsink0" + }, + "appsink0": { + "props": { + "blocksize": "4096000" + }, + "factory": "appsink" + } + } +} diff --git a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/utils/classification_task_metric.py b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/utils/classification_task_metric.py index 127542b272..a12fd3a1c1 100644 --- a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/utils/classification_task_metric.py +++ b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/infer/utils/classification_task_metric.py @@ -1,162 +1,162 @@ -# coding=utf-8 -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 json -import os -import sys - -import numpy as np - -np.set_printoptions(threshold=sys.maxsize) - -LABEL_FILE = "HiAI_label.json" - - -def cre_groundtruth_dict(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - for gtfile in os.listdir(gtfile_path): - if gtfile != LABEL_FILE: - with open(os.path.join(gtfile_path, gtfile), 'r') as f: - gt = json.load(f) - image_name = os.path.splitext(gtfile.split('/')[-1]) - img_gt_dict[image_name] = gt["image"]["annotations"][0]["category_id"] - return img_gt_dict - - -def cre_groundtruth_dict_fromtxt(gtfile_path): - """ - :param filename: file contains the imagename and label number - :return: dictionary key imagename, value is label number - """ - img_gt_dict = {} - with open(gtfile_path, 'r')as f: - for line in f.readlines(): - image_line_info = line.strip().split(" ") - img_name = image_line_info[0].split(".")[0] - img_gt_dict[img_name] = image_line_info[1] - return img_gt_dict - - -def load_statistical_predict_result(filepath): - """ - function: - the prediction esult file data extraction - input: - result file:filepath - output: - n_label:numble of label - data_vec: the probabilitie of prediction in the 1000 - :return: probabilities, numble of label - """ - with open(filepath, 'r')as f: - label_info = f.readline().strip().split(" ") - data_vec = np.zeros((len(label_info)), dtype=np.float32) - n_label = len(label_info) - if n_label == 0: - in_type = f.readline() - color = f.readline() - else: - for ind, cls_ind in enumerate(label_info): - data_vec[ind] = np.int(cls_ind) - return data_vec, n_label - - -def create_visualization_statistical_result(prediction_file_path, - result_store_path, json_file_name, - img_gt_dict, topn=5): - """ - :param prediction_file_path: - :param result_store_path: - :param json_file_name: - :param img_gt_dict: - :param topn: - :return: - """ - writer = open(os.path.join(result_store_path, json_file_name), 'w') - table_dict = {} - table_dict["title"] = "Overall statistical evaluation" - table_dict["value"] = [] - - count = 0 - res_cnt = 0 - n_labels = "" - count_hit = np.zeros(topn) - for tfile_name in os.listdir(prediction_file_path): - count += 1 - temp = tfile_name.split('.')[0] - index = temp.rfind('_') - img_name = temp[:index] - filepath = os.path.join(prediction_file_path, tfile_name) - prediction, n_labels = load_statistical_predict_result(filepath) - - if n_labels == 1001: - real_label = int(img_gt_dict[img_name]) + 1 - else: - real_label = int(img_gt_dict[img_name]) - - res_cnt = min(len(prediction), topn) - for i in range(res_cnt): - if real_label == int(prediction[i]): - count_hit[i] += 1 - break - if 'value' not in table_dict.keys(): - print("the item value does not exist!") - else: - table_dict["value"].extend( - [{"key": "Number of images", "value": str(count)}, - {"key": "Number of classes", "value": str(n_labels)}]) - accuracy = np.cumsum(count_hit) / count if count else 0 - for i in range(res_cnt): - table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", - "value": str( - round(accuracy[i] * 100, 2)) + '%'}) - json.dump(table_dict, writer) - writer.close() - - -if __name__ == '__main__': - if len(sys.argv) == 5: - # txt file path - folder_davinci_target = sys.argv[1] - # annotation files path, "val_label.txt" - annotation_file_path = sys.argv[2] - # the path to store the results json path - result_json_path = sys.argv[3] - # result json file name - json_file_name = sys.argv[4] - else: - print("Please enter target file result folder | ground truth label file | result json file folder | " - "result json file name, such as ./result val_label.txt . result.json") - exit(1) - - if not os.path.exists(folder_davinci_target): - print("Target file folder does not exist.") - - if not os.path.exists(annotation_file_path): - print("Ground truth file does not exist.") - - if not os.path.exists(result_json_path): - print("Result folder doesn't exist.") - - img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) - create_visualization_statistical_result(folder_davinci_target, - result_json_path, json_file_name, - img_label_dict, topn=5) - +# coding=utf-8 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 json +import os +import sys + +import numpy as np + +np.set_printoptions(threshold=sys.maxsize) + +LABEL_FILE = "HiAI_label.json" + + +def cre_groundtruth_dict(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + for gtfile in os.listdir(gtfile_path): + if gtfile != LABEL_FILE: + with open(os.path.join(gtfile_path, gtfile), 'r') as f: + gt = json.load(f) + image_name = os.path.splitext(gtfile.split('/')[-1]) + img_gt_dict[image_name] = gt["image"]["annotations"][0]["category_id"] + return img_gt_dict + + +def cre_groundtruth_dict_fromtxt(gtfile_path): + """ + :param filename: file contains the imagename and label number + :return: dictionary key imagename, value is label number + """ + img_gt_dict = {} + with open(gtfile_path, 'r')as f: + for line in f.readlines(): + image_line_info = line.strip().split(" ") + img_name = image_line_info[0].split(".")[0] + img_gt_dict[img_name] = image_line_info[1] + return img_gt_dict + + +def load_statistical_predict_result(filepath): + """ + function: + the prediction esult file data extraction + input: + result file:filepath + output: + n_label:numble of label + data_vec: the probabilitie of prediction in the 1000 + :return: probabilities, numble of label + """ + with open(filepath, 'r')as f: + label_info = f.readline().strip().split(" ") + data_vec = np.zeros((len(label_info)), dtype=np.float32) + n_label = len(label_info) + if n_label == 0: + in_type = f.readline() + color = f.readline() + else: + for ind, cls_ind in enumerate(label_info): + data_vec[ind] = np.int(cls_ind) + return data_vec, n_label + + +def create_visualization_statistical_result(prediction_file_path, + result_store_path, json_file_name, + img_gt_dict, topn=5): + """ + :param prediction_file_path: + :param result_store_path: + :param json_file_name: + :param img_gt_dict: + :param topn: + :return: + """ + writer = open(os.path.join(result_store_path, json_file_name), 'w') + table_dict = {} + table_dict["title"] = "Overall statistical evaluation" + table_dict["value"] = [] + + count = 0 + res_cnt = 0 + n_labels = "" + count_hit = np.zeros(topn) + for tfile_name in os.listdir(prediction_file_path): + count += 1 + temp = tfile_name.split('.')[0] + index = temp.rfind('_') + img_name = temp[:index] + filepath = os.path.join(prediction_file_path, tfile_name) + prediction, n_labels = load_statistical_predict_result(filepath) + + if n_labels == 1001: + real_label = int(img_gt_dict[img_name]) + 1 + else: + real_label = int(img_gt_dict[img_name]) + + res_cnt = min(len(prediction), topn) + for i in range(res_cnt): + if real_label == int(prediction[i]): + count_hit[i] += 1 + break + if 'value' not in table_dict.keys(): + print("the item value does not exist!") + else: + table_dict["value"].extend( + [{"key": "Number of images", "value": str(count)}, + {"key": "Number of classes", "value": str(n_labels)}]) + accuracy = np.cumsum(count_hit) / count if count else 0 + for i in range(res_cnt): + table_dict["value"].append({"key": "Top" + str(i + 1) + " accuracy", + "value": str( + round(accuracy[i] * 100, 2)) + '%'}) + json.dump(table_dict, writer) + writer.close() + + +if __name__ == '__main__': + if len(sys.argv) == 5: + # txt file path + folder_davinci_target = sys.argv[1] + # annotation files path, "val_label.txt" + annotation_file_path = sys.argv[2] + # the path to store the results json path + result_json_path = sys.argv[3] + # result json file name + json_file_name = sys.argv[4] + else: + print("Please enter target file result folder | ground truth label file | result json file folder | " + "result json file name, such as ./result val_label.txt . result.json") + exit(1) + + if not os.path.exists(folder_davinci_target): + print("Target file folder does not exist.") + + if not os.path.exists(annotation_file_path): + print("Ground truth file does not exist.") + + if not os.path.exists(result_json_path): + print("Result folder doesn't exist.") + + img_label_dict = cre_groundtruth_dict_fromtxt(annotation_file_path) + create_visualization_statistical_result(folder_davinci_target, + result_json_path, json_file_name, + img_label_dict, topn=5) + diff --git a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/modelarts/train_start_xception.py b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/modelarts/train_start_xception.py index 9da0dbeec1..3bac77ecee 100644 --- a/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/modelarts/train_start_xception.py +++ b/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch/modelarts/train_start_xception.py @@ -1,596 +1,596 @@ -# Copyright (c) 2021, -# All rights reserved. -# -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import os -import glob -import random -import shutil -import sys -import time -import warnings - -import torch -import numpy as np -from apex import amp - -import torch.nn as nn -import torch.nn.parallel -import torch.backends.cudnn as cudnn -import torch.distributed as dist -import torch.optim -import torch.multiprocessing as mp -import torch.utils.data -import torch.utils.data.distributed -import torchvision.transforms as transforms -import torchvision.datasets as datasets -import torchvision.models as models - -sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '../')) -from pthtar2onx import convert -from xception import xception -import moxing as mox - -model_names = sorted(name for name in models.__dict__ - if name.islower() and not name.startswith("__") - and callable(models.__dict__[name])) - -parser = argparse.ArgumentParser(description='PyTorch ImageNet Training') -parser.add_argument('--data_url', metavar='DIR', default='/cache/data_url', - help='path to dataset') -parser.add_argument('-a', '--arch', - metavar='ARCH', - default='xception', - choices=model_names, - help='model architecture: ' + - ' | '.join(model_names) + - ' (default: xception)') -parser.add_argument('-j', '--workers', default=4, type=int, metavar='N', - help='number of data loading workers (default: 4)') -parser.add_argument('--epochs', default=3, type=int, metavar='N', - help='number of total epochs to run') -parser.add_argument('--start-epoch', default=0, type=int, metavar='N', - help='manual epoch number (useful on restarts)') -parser.add_argument('-b', '--batch-size', default=64, type=int, - metavar='N', - help='mini-batch size (default: 256), this is the total ' - 'batch size of all GPUs on the current node when ' - 'using Data Parallel or Distributed Data Parallel') -parser.add_argument('--lr', '--learning-rate', default=0.1, type=float, - metavar='LR', help='initial learning rate', dest='lr') -parser.add_argument('--momentum', default=0.9, type=float, metavar='M', - help='momentum') -parser.add_argument('--wd', '--weight-decay', default=1e-4, type=float, - metavar='W', help='weight decay (default: 1e-4)', - dest='weight_decay') -parser.add_argument('-p', '--print-freq', default=10, type=int, - metavar='N', help='print frequency (default: 10)') -parser.add_argument('--resume', default='', type=str, metavar='PATH', - help='path to latest checkpoint (default: none)') -parser.add_argument('-e', '--evaluate', dest='evaluate', action='store_true', - help='evaluate model on validation set') -parser.add_argument('--pretrained', dest='pretrained', action='store_true', - help='use pre-trained model') -parser.add_argument('--pretrained_weight', default='', type=str, metavar='PATH', - help='path to pretrained weight') -parser.add_argument('--world-size', default=-1, type=int, - help='number of nodes for distributed training') -parser.add_argument('--rank', default=-1, type=int, - help='node rank for distributed training') -parser.add_argument('--dist-url', default='tcp://224.66.41.62:23456', type=str, - help='url used to set up distributed training') -parser.add_argument('--dist-backend', default='nccl', type=str, - help='distributed backend') -parser.add_argument('--seed', default=None, type=int, - help='seed for initializing training. ') -parser.add_argument('--gpu', default=None, type=int, - help='GPU id to use.') -parser.add_argument('--multiprocessing-distributed', action='store_true', - help='Use multi-processing distributed training to launch ' - 'N processes per node, which has N GPUs. This is the ' - 'fastest way to use PyTorch for either single node or ' - 'multi node data parallel training') -parser.add_argument('--npu', default=0, type=int, - help='NPU id to use.') -parser.add_argument('--addr', default='10.136.181.115', - type=str, help='master addr') -parser.add_argument('--device_list', default='0,1,2,3,4,5,6,7', - type=str, help='device id list') -parser.add_argument('--warm_up_epochs', default=0, type=int, - help='warm up') -parser.add_argument('--amp', default=False, action='store_true', - help='use amp to train the model') -parser.add_argument('--loss-scale', default=1024., type=float, - help='loss scale using in amp, default -1 means dynamic') -parser.add_argument('--opt-level', default='O2', type=str, - help='loss scale using in amp, default -1 means dynamic') -parser.add_argument('--prof', default=False, action='store_true', - help='use profiling to evaluate the performance of model') -parser.add_argument('--label-smoothing', - default=0.0, - type=float, - metavar='S', - help='label smoothing') -parser.add_argument('--train_url', - default="/cache/training", - type=str, - help="setting dir of training output") -parser.add_argument('--onnx', default=True, action='store_true', - help="convert pth model to onnx") - -best_acc1 = 0 -CACHE_TRAINING_URL = "/cache/training" - -def main(): - args = parser.parse_args() - print(args.device_list) - - os.environ['MASTER_ADDR'] = args.addr - os.environ['MASTER_PORT'] = '29688' - - if args.npu is None: - args.npu = 0 - global CALCULATE_DEVICE - global best_acc1 - - #-----modelarts modification----------------- - CALCULATE_DEVICE = "npu:{}".format(args.npu) - #-----modelarts modification----------------- - torch.npu.set_device(CALCULATE_DEVICE) - - if args.seed is not None: - random.seed(args.seed) - torch.manual_seed(args.seed) - cudnn.deterministic = True - warnings.warn('You have chosen to seed training. ' - 'This will turn on the CUDNN deterministic setting, ' - 'which can slow down your training considerably! ' - 'You may see unexpected behavior when restarting ' - 'from checkpoints.') - - if args.gpu is not None: - warnings.warn('You have chosen a specific GPU. This will completely ' - 'disable data parallelism.') - - if args.dist_url == "env://" and args.world_size == -1: - args.world_size = int(os.environ["WORLD_SIZE"]) - - args.distributed = args.world_size > 1 or args.multiprocessing_distributed - - ngpus_per_node = torch.npu.device_count() - - print('ngpus_per_node:',ngpus_per_node) - - - if args.multiprocessing_distributed: - # Since we have ngpus_per_node processes per node, the total world_size - # needs to be adjusted accordingly - args.world_size = ngpus_per_node * args.world_size - # Use torch.multiprocessing.spawn to launch distributed processes: the - # main_worker process function - mp.spawn(main_worker, nprocs=ngpus_per_node, - args=(ngpus_per_node, args)) - else: - # Simply call main_worker function - main_worker(args.gpu, ngpus_per_node, args) - - -def main_worker(gpu, ngpus_per_node, args): - global best_acc1 - args.gpu = gpu - - if args.gpu is not None: - print("Use NPU: {} for training".format(args.gpu)) - - if args.distributed: - if args.dist_url == "env://" and args.rank == -1: - args.rank = int(os.environ["RANK"]) - if args.multiprocessing_distributed: - # For multiprocessing distributed training, rank needs to be the - # global rank among all the processes - args.rank = args.rank * ngpus_per_node + gpu - - dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url, - world_size=args.world_size, rank=args.rank) - # create model - if args.pretrained: - print("=> using pre-trained model '{}'".format(args.arch)) - model = xception() - CACHE_MODEL_URL = "/cache/model" - # ------------------modelarts modification---------------------- - os.makedirs(CACHE_MODEL_URL, exist_ok=True) - mox.file.copy_parallel(args.pretrained_weight, os.path.join(CACHE_MODEL_URL, "checkpoint.pth.tar")) - # ------------------modelarts modification--------------------- - pretrained_weight = os.path.join(CACHE_MODEL_URL, "checkpoint.pth.tar") - pretrained_dict = torch.load(pretrained_weight, map_location="cpu")["state_dict"] - if "fc.weight" in pretrained_dict: - pretrained_dict.pop("fc.weight") - pretrained_dict.pop("fc.bias") - - model.load_state_dict(pretrained_dict, strict=False) - - else: - print("=> creating model '{}'".format(args.arch)) - model = xception() - - if args.distributed: - # For multiprocessing distributed, DistributedDataParallel constructor - # should always set the single device scope, otherwise, - # DistributedDataParallel will use all available devices. - if args.gpu is not None: - torch.cuda.set_device(args.gpu) - model.cuda(args.gpu) - - # When using a single GPU per process and per - # DistributedDataParallel, we need to divide the batch size - # ourselves based on the total number of GPUs we have - args.batch_size = int(args.batch_size / args.world_size) - args.workers = int((args.workers + ngpus_per_node - 1) / ngpus_per_node) - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu]) - else: - model.cuda() - # DistributedDataParallel will divide and allocate batch_size to all - # available GPUs if device_ids are not set - model = torch.nn.parallel.DistributedDataParallel(model) - elif args.gpu is not None: - torch.cuda.set_device(args.gpu) - model = model.cuda(args.gpu) - - else: - model = model.to(CALCULATE_DEVICE) - - # define loss function (criterion) and optimizer - criterion = nn.CrossEntropyLoss().to(CALCULATE_DEVICE) - - optimizer = torch.optim.SGD(model.parameters(), args.lr, - momentum=args.momentum, - weight_decay=args.weight_decay) - - if args.amp: - model, optimizer = amp.initialize(model, optimizer, opt_level=args.opt_level, loss_scale=args.loss_scale) - - # optionally resume from a checkpoint - if args.resume : - if os.path.isfile(args.resume): - print("=> loading checkpoint '{}'".format(args.resume)) - checkpoint = torch.load(args.resume, map_location=CALCULATE_DEVICE) - args.start_epoch = checkpoint['epoch'] - best_acc1 = checkpoint['best_acc1'] - model.load_state_dict(checkpoint['state_dict']) - optimizer.load_state_dict(checkpoint['optimizer']) - if args.amp: - amp.load_state_dict(checkpoint['amp']) - print("=> loaded checkpoint '{}' (epoch {})" - .format(args.resume, checkpoint['epoch'])) - else: - print("=> no checkpoint found at '{}'".format(args.resume)) - - cudnn.benchmark = True - - # -------modelarts modification------- - real_path = '/cache/data_url' - if not os.path.exists(real_path): - os.makedirs(real_path) - mox.file.copy_parallel(args.data_url, real_path) - print("training data finish copy to %s." % real_path) - # ---------modelarts modification----- - - # Data loading code - traindir = os.path.join(real_path, 'train') - valdir = os.path.join(real_path, 'val') - normalize = transforms.Normalize(mean=[0.5, 0.5, 0.5], - std=[0.5, 0.5, 0.5]) - - train_dataset = datasets.ImageFolder( - traindir, - transforms.Compose([ - transforms.RandomResizedCrop(299), - transforms.RandomHorizontalFlip(), - transforms.ToTensor(), - normalize, - ])) - - if args.distributed: - train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset) - else: - train_sampler = None - - train_loader = torch.utils.data.DataLoader( - train_dataset, batch_size=args.batch_size, shuffle=(train_sampler is None), - num_workers=args.workers, pin_memory=False, sampler=train_sampler, drop_last=True) - - val_loader = torch.utils.data.DataLoader( - datasets.ImageFolder(valdir, transforms.Compose([ - transforms.Resize(342), - transforms.CenterCrop(299), - transforms.ToTensor(), - normalize, - ])), - batch_size=args.batch_size, shuffle=True, - num_workers=args.workers, pin_memory=False, drop_last=True) - - if args.evaluate: - validate(val_loader, model, criterion, args) - return - - start_time = time.time() - for epoch in range(args.start_epoch, args.epochs): - if args.distributed: - train_sampler.set_epoch(epoch) - - adjust_learning_rate(optimizer, epoch, args) - - # train for one epoch - train(train_loader, model, criterion, optimizer, epoch, args) - - # evaluate on validation set - acc1 = validate(val_loader, model, criterion, args) - - # remember best acc@1 and save checkpoint - is_best = acc1 > best_acc1 - best_acc1 = max(acc1, best_acc1) - - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % ngpus_per_node == 0): - if args.amp: - save_checkpoint({ - 'epoch': epoch + 1, - 'arch': args.arch, - 'state_dict': model.state_dict(), - 'best_acc1': best_acc1, - 'optimizer': optimizer.state_dict(), - 'amp': amp.state_dict(), - }, is_best) - else: - save_checkpoint({ - 'epoch': epoch + 1, - 'arch': args.arch, - 'state_dict': model.state_dict(), - 'best_acc1': best_acc1, - 'optimizer': optimizer.state_dict(), - }, is_best) - - if args.onnx: - convert_pth_to_onnx(args) - - # --------------modelarts modification---------- - mox.file.copy_parallel(CACHE_TRAINING_URL, args.train_url) - # --------------modelarts modification end---------- - -def convert_pth_to_onnx(config_args): - pth_pattern = os.path.join(CACHE_TRAINING_URL, 'checkpoint.pth.tar') - pth_file_list = glob.glob(pth_pattern) - if not pth_file_list: - print(f"can't find pth {pth_pattern}") - return - pth_file = pth_file_list[0] - onnx_path = pth_file.split(".")[0] + '.onnx' - convert(pth_file, onnx_path) - -def train(train_loader, model, criterion, optimizer, epoch, args): - batch_time = AverageMeter('Time', ':6.3f') - data_time = AverageMeter('Data', ':6.3f') - losses = AverageMeter('Loss', ':.4e') - top1 = AverageMeter('Acc@1', ':6.2f') - top5 = AverageMeter('Acc@5', ':6.2f') - progress = ProgressMeter( - len(train_loader), - [batch_time, data_time, losses, top1, top5], - prefix="Epoch: [{}]".format(epoch)) - - # switch to train mode - model.train() - - end = time.time() - for i, (images, target) in enumerate(train_loader): - # measure data loading time - data_time.update(time.time() - end) - - images = images.to(CALCULATE_DEVICE, non_blocking=False).to(torch.float) - target = target.to(torch.int32).to(CALCULATE_DEVICE, non_blocking=False) - - # compute output - output = model(images) - loss = criterion(output, target) - - # measure accuracy and record loss - acc1, acc5 = accuracy(output, target, topk=(1, 5)) - losses.update(loss.item(), images.size(0)) - top1.update(acc1[0], images.size(0)) - top5.update(acc5[0], images.size(0)) - - # compute gradient and do SGD step - optimizer.zero_grad() - if args.amp: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.step() - - # torch.npu.synchronize() - - # measure elapsed time - cost_time = time.time() - end - batch_time.update(cost_time) - end = time.time() - - if i % args.print_freq == 0: - progress.display(i) - - print('* FPS@all {:.3f}'.format(args.batch_size / (batch_time.avg + 0.001))) - - -def validate(val_loader, model, criterion, args): - batch_time = AverageMeter('Time', ':6.3f') - losses = AverageMeter('Loss', ':.4e') - top1 = AverageMeter('Acc@1', ':6.2f') - top5 = AverageMeter('Acc@5', ':6.2f') - progress = ProgressMeter( - len(val_loader), - [batch_time, losses, top1, top5], - prefix='Test: ') - - # switch to evaluate mode - model.eval() - - with torch.no_grad(): - end = time.time() - for i, (images, target) in enumerate(val_loader): - - images = images.to(CALCULATE_DEVICE, non_blocking=False).to(torch.float) - target = target.to(torch.int32).to(CALCULATE_DEVICE, non_blocking=False) - - # compute output - output = model(images) - loss = criterion(output, target) - - # measure accuracy and record loss - acc1, acc5 = accuracy(output, target, topk=(1, 5)) - losses.update(loss.item(), images.size(0)) - top1.update(acc1[0], images.size(0)) - top5.update(acc5[0], images.size(0)) - - # measure elapsed time - cost_time = time.time() - end - batch_time.update(cost_time) - end = time.time() - - if i % args.print_freq == 0: - progress.display(i) - - print(' * Acc@1 {top1.avg:.3f} Acc@5 {top5.avg:.3f}'.format(top1=top1, top5=top5)) - - return top1.avg - - -def save_checkpoint(state, is_best, filename='checkpoint.pth.tar'): - if not os.path.exists(CACHE_TRAINING_URL): - os.makedirs(CACHE_TRAINING_URL, 0o755) - - checkpoint_save_path = os.path.join(CACHE_TRAINING_URL, filename) - torch.save(state, checkpoint_save_path) - if is_best: - shutil.copyfile(checkpoint_save_path, CACHE_TRAINING_URL + "/" + 'model_best_acc%.4f_epoch%d.pth.tar' % (state['best_acc1'], state['epoch'])) - - -class AverageMeter(object): - """Computes and stores the average and current value""" - - def __init__(self, name, fmt=':f', start_count_index=2): - self.name = name - self.fmt = fmt - self.reset() - self.start_count_index = start_count_index - - def reset(self): - self.val = 0 - self.avg = 0 - self.sum = 0 - self.count = 0 - - def update(self, val, n=1): - if self.count == 0: - self.N = n - - self.val = val - self.count += n - if self.count > (self.start_count_index * self.N): - self.sum += val * n - self.avg = self.sum / (self.count - self.start_count_index * self.N) - - def __str__(self): - fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' - return fmtstr.format(**self.__dict__) - -class ProgressMeter(object): - def __init__(self, num_batches, meters, prefix=""): - self.batch_fmtstr = self._get_batch_fmtstr(num_batches) - self.meters = meters - self.prefix = prefix - - def display(self, batch): - entries = [self.prefix + self.batch_fmtstr.format(batch)] - entries += [str(meter) for meter in self.meters] - print('\t'.join(entries)) - - def _get_batch_fmtstr(self, num_batches): - num_digits = len(str(num_batches // 1)) - fmt = '{:' + str(num_digits) + 'd}' - return '[' + fmt + '/' + fmt.format(num_batches) + ']' - - -def adjust_learning_rate(optimizer, epoch, args): - """Sets the learning rate to the initial LR decayed by 10 every 30 epochs""" - - if args.warm_up_epochs > 0 and epoch < args.warm_up_epochs: - lr = args.lr * ((epoch + 1) / (args.warm_up_epochs + 1)) - else: - alpha = 0 - cosine_decay = 0.5 * ( - 1 + np.cos(np.pi * (epoch - args.warm_up_epochs) / (args.epochs - args.warm_up_epochs))) - decayed = (1 - alpha) * cosine_decay + alpha - lr = args.lr * decayed - - print("=> Epoch[%d] Setting lr: %.4f" % (epoch, lr)) - for param_group in optimizer.param_groups: - param_group['lr'] = lr - - -def accuracy(output, target, topk=(1,)): - """Computes the accuracy over the k top predictions for the specified values of k""" - with torch.no_grad(): - maxk = max(topk) - batch_size = target.size(0) - - _, pred = output.topk(maxk, 1, True, True) - pred = pred.t() - correct = pred.eq(target.view(1, -1).expand_as(pred)) - - res = [] - for k in topk: - correct_k = correct[:k].reshape(-1).float().sum(0, keepdim=True) - res.append(correct_k.mul_(100.0 / batch_size)) - return res - -class LabelSmoothing(nn.Module): - """ - NLL loss with label smoothing. - """ - def __init__(self, loc, smoothing=0.0): - """ - Constructor for the LabelSmoothing module. - - :param smoothing: label smoothing factor - """ - super(LabelSmoothing, self).__init__() - self.confidence = 1.0 - smoothing - self.smoothing = smoothing - self.device = loc - - def forward(self, x, target): - target = target.to(torch.int64) - - logprobs = torch.nn.functional.log_softmax(x, dim=-1) - nll_loss = -logprobs.gather(dim=-1, index=target.unsqueeze(1).to(torch.int64)) - nll_loss = nll_loss.squeeze(1) - smooth_loss = -logprobs.mean(dim=-1) - loss = self.confidence * nll_loss + self.smoothing * smooth_loss - return loss.mean() - -if __name__ == '__main__': - main() +# Copyright (c) 2021, +# All rights reserved. +# +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import os +import glob +import random +import shutil +import sys +import time +import warnings + +import torch +import numpy as np +from apex import amp + +import torch.nn as nn +import torch.nn.parallel +import torch.backends.cudnn as cudnn +import torch.distributed as dist +import torch.optim +import torch.multiprocessing as mp +import torch.utils.data +import torch.utils.data.distributed +import torchvision.transforms as transforms +import torchvision.datasets as datasets +import torchvision.models as models + +sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '../')) +from pthtar2onx import convert +from xception import xception +import moxing as mox + +model_names = sorted(name for name in models.__dict__ + if name.islower() and not name.startswith("__") + and callable(models.__dict__[name])) + +parser = argparse.ArgumentParser(description='PyTorch ImageNet Training') +parser.add_argument('--data_url', metavar='DIR', default='/cache/data_url', + help='path to dataset') +parser.add_argument('-a', '--arch', + metavar='ARCH', + default='xception', + choices=model_names, + help='model architecture: ' + + ' | '.join(model_names) + + ' (default: xception)') +parser.add_argument('-j', '--workers', default=4, type=int, metavar='N', + help='number of data loading workers (default: 4)') +parser.add_argument('--epochs', default=3, type=int, metavar='N', + help='number of total epochs to run') +parser.add_argument('--start-epoch', default=0, type=int, metavar='N', + help='manual epoch number (useful on restarts)') +parser.add_argument('-b', '--batch-size', default=64, type=int, + metavar='N', + help='mini-batch size (default: 256), this is the total ' + 'batch size of all GPUs on the current node when ' + 'using Data Parallel or Distributed Data Parallel') +parser.add_argument('--lr', '--learning-rate', default=0.1, type=float, + metavar='LR', help='initial learning rate', dest='lr') +parser.add_argument('--momentum', default=0.9, type=float, metavar='M', + help='momentum') +parser.add_argument('--wd', '--weight-decay', default=1e-4, type=float, + metavar='W', help='weight decay (default: 1e-4)', + dest='weight_decay') +parser.add_argument('-p', '--print-freq', default=10, type=int, + metavar='N', help='print frequency (default: 10)') +parser.add_argument('--resume', default='', type=str, metavar='PATH', + help='path to latest checkpoint (default: none)') +parser.add_argument('-e', '--evaluate', dest='evaluate', action='store_true', + help='evaluate model on validation set') +parser.add_argument('--pretrained', dest='pretrained', action='store_true', + help='use pre-trained model') +parser.add_argument('--pretrained_weight', default='', type=str, metavar='PATH', + help='path to pretrained weight') +parser.add_argument('--world-size', default=-1, type=int, + help='number of nodes for distributed training') +parser.add_argument('--rank', default=-1, type=int, + help='node rank for distributed training') +parser.add_argument('--dist-url', default='tcp://224.66.41.62:23456', type=str, + help='url used to set up distributed training') +parser.add_argument('--dist-backend', default='nccl', type=str, + help='distributed backend') +parser.add_argument('--seed', default=None, type=int, + help='seed for initializing training. ') +parser.add_argument('--gpu', default=None, type=int, + help='GPU id to use.') +parser.add_argument('--multiprocessing-distributed', action='store_true', + help='Use multi-processing distributed training to launch ' + 'N processes per node, which has N GPUs. This is the ' + 'fastest way to use PyTorch for either single node or ' + 'multi node data parallel training') +parser.add_argument('--npu', default=0, type=int, + help='NPU id to use.') +parser.add_argument('--addr', default='10.136.181.115', + type=str, help='master addr') +parser.add_argument('--device_list', default='0,1,2,3,4,5,6,7', + type=str, help='device id list') +parser.add_argument('--warm_up_epochs', default=0, type=int, + help='warm up') +parser.add_argument('--amp', default=False, action='store_true', + help='use amp to train the model') +parser.add_argument('--loss-scale', default=1024., type=float, + help='loss scale using in amp, default -1 means dynamic') +parser.add_argument('--opt-level', default='O2', type=str, + help='loss scale using in amp, default -1 means dynamic') +parser.add_argument('--prof', default=False, action='store_true', + help='use profiling to evaluate the performance of model') +parser.add_argument('--label-smoothing', + default=0.0, + type=float, + metavar='S', + help='label smoothing') +parser.add_argument('--train_url', + default="/cache/training", + type=str, + help="setting dir of training output") +parser.add_argument('--onnx', default=True, action='store_true', + help="convert pth model to onnx") + +best_acc1 = 0 +CACHE_TRAINING_URL = "/cache/training" + +def main(): + args = parser.parse_args() + print(args.device_list) + + os.environ['MASTER_ADDR'] = args.addr + os.environ['MASTER_PORT'] = '29688' + + if args.npu is None: + args.npu = 0 + global CALCULATE_DEVICE + global best_acc1 + + #-----modelarts modification----------------- + CALCULATE_DEVICE = "npu:{}".format(args.npu) + #-----modelarts modification----------------- + torch.npu.set_device(CALCULATE_DEVICE) + + if args.seed is not None: + random.seed(args.seed) + torch.manual_seed(args.seed) + cudnn.deterministic = True + warnings.warn('You have chosen to seed training. ' + 'This will turn on the CUDNN deterministic setting, ' + 'which can slow down your training considerably! ' + 'You may see unexpected behavior when restarting ' + 'from checkpoints.') + + if args.gpu is not None: + warnings.warn('You have chosen a specific GPU. This will completely ' + 'disable data parallelism.') + + if args.dist_url == "env://" and args.world_size == -1: + args.world_size = int(os.environ["WORLD_SIZE"]) + + args.distributed = args.world_size > 1 or args.multiprocessing_distributed + + ngpus_per_node = torch.npu.device_count() + + print('ngpus_per_node:',ngpus_per_node) + + + if args.multiprocessing_distributed: + # Since we have ngpus_per_node processes per node, the total world_size + # needs to be adjusted accordingly + args.world_size = ngpus_per_node * args.world_size + # Use torch.multiprocessing.spawn to launch distributed processes: the + # main_worker process function + mp.spawn(main_worker, nprocs=ngpus_per_node, + args=(ngpus_per_node, args)) + else: + # Simply call main_worker function + main_worker(args.gpu, ngpus_per_node, args) + + +def main_worker(gpu, ngpus_per_node, args): + global best_acc1 + args.gpu = gpu + + if args.gpu is not None: + print("Use NPU: {} for training".format(args.gpu)) + + if args.distributed: + if args.dist_url == "env://" and args.rank == -1: + args.rank = int(os.environ["RANK"]) + if args.multiprocessing_distributed: + # For multiprocessing distributed training, rank needs to be the + # global rank among all the processes + args.rank = args.rank * ngpus_per_node + gpu + + dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url, + world_size=args.world_size, rank=args.rank) + # create model + if args.pretrained: + print("=> using pre-trained model '{}'".format(args.arch)) + model = xception() + CACHE_MODEL_URL = "/cache/model" + # ------------------modelarts modification---------------------- + os.makedirs(CACHE_MODEL_URL, exist_ok=True) + mox.file.copy_parallel(args.pretrained_weight, os.path.join(CACHE_MODEL_URL, "checkpoint.pth.tar")) + # ------------------modelarts modification--------------------- + pretrained_weight = os.path.join(CACHE_MODEL_URL, "checkpoint.pth.tar") + pretrained_dict = torch.load(pretrained_weight, map_location="cpu")["state_dict"] + if "fc.weight" in pretrained_dict: + pretrained_dict.pop("fc.weight") + pretrained_dict.pop("fc.bias") + + model.load_state_dict(pretrained_dict, strict=False) + + else: + print("=> creating model '{}'".format(args.arch)) + model = xception() + + if args.distributed: + # For multiprocessing distributed, DistributedDataParallel constructor + # should always set the single device scope, otherwise, + # DistributedDataParallel will use all available devices. + if args.gpu is not None: + torch.cuda.set_device(args.gpu) + model.cuda(args.gpu) + + # When using a single GPU per process and per + # DistributedDataParallel, we need to divide the batch size + # ourselves based on the total number of GPUs we have + args.batch_size = int(args.batch_size / args.world_size) + args.workers = int((args.workers + ngpus_per_node - 1) / ngpus_per_node) + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu]) + else: + model.cuda() + # DistributedDataParallel will divide and allocate batch_size to all + # available GPUs if device_ids are not set + model = torch.nn.parallel.DistributedDataParallel(model) + elif args.gpu is not None: + torch.cuda.set_device(args.gpu) + model = model.cuda(args.gpu) + + else: + model = model.to(CALCULATE_DEVICE) + + # define loss function (criterion) and optimizer + criterion = nn.CrossEntropyLoss().to(CALCULATE_DEVICE) + + optimizer = torch.optim.SGD(model.parameters(), args.lr, + momentum=args.momentum, + weight_decay=args.weight_decay) + + if args.amp: + model, optimizer = amp.initialize(model, optimizer, opt_level=args.opt_level, loss_scale=args.loss_scale) + + # optionally resume from a checkpoint + if args.resume : + if os.path.isfile(args.resume): + print("=> loading checkpoint '{}'".format(args.resume)) + checkpoint = torch.load(args.resume, map_location=CALCULATE_DEVICE) + args.start_epoch = checkpoint['epoch'] + best_acc1 = checkpoint['best_acc1'] + model.load_state_dict(checkpoint['state_dict']) + optimizer.load_state_dict(checkpoint['optimizer']) + if args.amp: + amp.load_state_dict(checkpoint['amp']) + print("=> loaded checkpoint '{}' (epoch {})" + .format(args.resume, checkpoint['epoch'])) + else: + print("=> no checkpoint found at '{}'".format(args.resume)) + + cudnn.benchmark = True + + # -------modelarts modification------- + real_path = '/cache/data_url' + if not os.path.exists(real_path): + os.makedirs(real_path) + mox.file.copy_parallel(args.data_url, real_path) + print("training data finish copy to %s." % real_path) + # ---------modelarts modification----- + + # Data loading code + traindir = os.path.join(real_path, 'train') + valdir = os.path.join(real_path, 'val') + normalize = transforms.Normalize(mean=[0.5, 0.5, 0.5], + std=[0.5, 0.5, 0.5]) + + train_dataset = datasets.ImageFolder( + traindir, + transforms.Compose([ + transforms.RandomResizedCrop(299), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + normalize, + ])) + + if args.distributed: + train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset) + else: + train_sampler = None + + train_loader = torch.utils.data.DataLoader( + train_dataset, batch_size=args.batch_size, shuffle=(train_sampler is None), + num_workers=args.workers, pin_memory=False, sampler=train_sampler, drop_last=True) + + val_loader = torch.utils.data.DataLoader( + datasets.ImageFolder(valdir, transforms.Compose([ + transforms.Resize(342), + transforms.CenterCrop(299), + transforms.ToTensor(), + normalize, + ])), + batch_size=args.batch_size, shuffle=True, + num_workers=args.workers, pin_memory=False, drop_last=True) + + if args.evaluate: + validate(val_loader, model, criterion, args) + return + + start_time = time.time() + for epoch in range(args.start_epoch, args.epochs): + if args.distributed: + train_sampler.set_epoch(epoch) + + adjust_learning_rate(optimizer, epoch, args) + + # train for one epoch + train(train_loader, model, criterion, optimizer, epoch, args) + + # evaluate on validation set + acc1 = validate(val_loader, model, criterion, args) + + # remember best acc@1 and save checkpoint + is_best = acc1 > best_acc1 + best_acc1 = max(acc1, best_acc1) + + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % ngpus_per_node == 0): + if args.amp: + save_checkpoint({ + 'epoch': epoch + 1, + 'arch': args.arch, + 'state_dict': model.state_dict(), + 'best_acc1': best_acc1, + 'optimizer': optimizer.state_dict(), + 'amp': amp.state_dict(), + }, is_best) + else: + save_checkpoint({ + 'epoch': epoch + 1, + 'arch': args.arch, + 'state_dict': model.state_dict(), + 'best_acc1': best_acc1, + 'optimizer': optimizer.state_dict(), + }, is_best) + + if args.onnx: + convert_pth_to_onnx(args) + + # --------------modelarts modification---------- + mox.file.copy_parallel(CACHE_TRAINING_URL, args.train_url) + # --------------modelarts modification end---------- + +def convert_pth_to_onnx(config_args): + pth_pattern = os.path.join(CACHE_TRAINING_URL, 'checkpoint.pth.tar') + pth_file_list = glob.glob(pth_pattern) + if not pth_file_list: + print(f"can't find pth {pth_pattern}") + return + pth_file = pth_file_list[0] + onnx_path = pth_file.split(".")[0] + '.onnx' + convert(pth_file, onnx_path) + +def train(train_loader, model, criterion, optimizer, epoch, args): + batch_time = AverageMeter('Time', ':6.3f') + data_time = AverageMeter('Data', ':6.3f') + losses = AverageMeter('Loss', ':.4e') + top1 = AverageMeter('Acc@1', ':6.2f') + top5 = AverageMeter('Acc@5', ':6.2f') + progress = ProgressMeter( + len(train_loader), + [batch_time, data_time, losses, top1, top5], + prefix="Epoch: [{}]".format(epoch)) + + # switch to train mode + model.train() + + end = time.time() + for i, (images, target) in enumerate(train_loader): + # measure data loading time + data_time.update(time.time() - end) + + images = images.to(CALCULATE_DEVICE, non_blocking=False).to(torch.float) + target = target.to(torch.int32).to(CALCULATE_DEVICE, non_blocking=False) + + # compute output + output = model(images) + loss = criterion(output, target) + + # measure accuracy and record loss + acc1, acc5 = accuracy(output, target, topk=(1, 5)) + losses.update(loss.item(), images.size(0)) + top1.update(acc1[0], images.size(0)) + top5.update(acc5[0], images.size(0)) + + # compute gradient and do SGD step + optimizer.zero_grad() + if args.amp: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + optimizer.step() + + # torch.npu.synchronize() + + # measure elapsed time + cost_time = time.time() - end + batch_time.update(cost_time) + end = time.time() + + if i % args.print_freq == 0: + progress.display(i) + + print('* FPS@all {:.3f}'.format(args.batch_size / (batch_time.avg + 0.001))) + + +def validate(val_loader, model, criterion, args): + batch_time = AverageMeter('Time', ':6.3f') + losses = AverageMeter('Loss', ':.4e') + top1 = AverageMeter('Acc@1', ':6.2f') + top5 = AverageMeter('Acc@5', ':6.2f') + progress = ProgressMeter( + len(val_loader), + [batch_time, losses, top1, top5], + prefix='Test: ') + + # switch to evaluate mode + model.eval() + + with torch.no_grad(): + end = time.time() + for i, (images, target) in enumerate(val_loader): + + images = images.to(CALCULATE_DEVICE, non_blocking=False).to(torch.float) + target = target.to(torch.int32).to(CALCULATE_DEVICE, non_blocking=False) + + # compute output + output = model(images) + loss = criterion(output, target) + + # measure accuracy and record loss + acc1, acc5 = accuracy(output, target, topk=(1, 5)) + losses.update(loss.item(), images.size(0)) + top1.update(acc1[0], images.size(0)) + top5.update(acc5[0], images.size(0)) + + # measure elapsed time + cost_time = time.time() - end + batch_time.update(cost_time) + end = time.time() + + if i % args.print_freq == 0: + progress.display(i) + + print(' * Acc@1 {top1.avg:.3f} Acc@5 {top5.avg:.3f}'.format(top1=top1, top5=top5)) + + return top1.avg + + +def save_checkpoint(state, is_best, filename='checkpoint.pth.tar'): + if not os.path.exists(CACHE_TRAINING_URL): + os.makedirs(CACHE_TRAINING_URL, 0o755) + + checkpoint_save_path = os.path.join(CACHE_TRAINING_URL, filename) + torch.save(state, checkpoint_save_path) + if is_best: + shutil.copyfile(checkpoint_save_path, CACHE_TRAINING_URL + "/" + 'model_best_acc%.4f_epoch%d.pth.tar' % (state['best_acc1'], state['epoch'])) + + +class AverageMeter(object): + """Computes and stores the average and current value""" + + def __init__(self, name, fmt=':f', start_count_index=2): + self.name = name + self.fmt = fmt + self.reset() + self.start_count_index = start_count_index + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + + def update(self, val, n=1): + if self.count == 0: + self.N = n + + self.val = val + self.count += n + if self.count > (self.start_count_index * self.N): + self.sum += val * n + self.avg = self.sum / (self.count - self.start_count_index * self.N) + + def __str__(self): + fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' + return fmtstr.format(**self.__dict__) + +class ProgressMeter(object): + def __init__(self, num_batches, meters, prefix=""): + self.batch_fmtstr = self._get_batch_fmtstr(num_batches) + self.meters = meters + self.prefix = prefix + + def display(self, batch): + entries = [self.prefix + self.batch_fmtstr.format(batch)] + entries += [str(meter) for meter in self.meters] + print('\t'.join(entries)) + + def _get_batch_fmtstr(self, num_batches): + num_digits = len(str(num_batches // 1)) + fmt = '{:' + str(num_digits) + 'd}' + return '[' + fmt + '/' + fmt.format(num_batches) + ']' + + +def adjust_learning_rate(optimizer, epoch, args): + """Sets the learning rate to the initial LR decayed by 10 every 30 epochs""" + + if args.warm_up_epochs > 0 and epoch < args.warm_up_epochs: + lr = args.lr * ((epoch + 1) / (args.warm_up_epochs + 1)) + else: + alpha = 0 + cosine_decay = 0.5 * ( + 1 + np.cos(np.pi * (epoch - args.warm_up_epochs) / (args.epochs - args.warm_up_epochs))) + decayed = (1 - alpha) * cosine_decay + alpha + lr = args.lr * decayed + + print("=> Epoch[%d] Setting lr: %.4f" % (epoch, lr)) + for param_group in optimizer.param_groups: + param_group['lr'] = lr + + +def accuracy(output, target, topk=(1,)): + """Computes the accuracy over the k top predictions for the specified values of k""" + with torch.no_grad(): + maxk = max(topk) + batch_size = target.size(0) + + _, pred = output.topk(maxk, 1, True, True) + pred = pred.t() + correct = pred.eq(target.view(1, -1).expand_as(pred)) + + res = [] + for k in topk: + correct_k = correct[:k].reshape(-1).float().sum(0, keepdim=True) + res.append(correct_k.mul_(100.0 / batch_size)) + return res + +class LabelSmoothing(nn.Module): + """ + NLL loss with label smoothing. + """ + def __init__(self, loc, smoothing=0.0): + """ + Constructor for the LabelSmoothing module. + + :param smoothing: label smoothing factor + """ + super(LabelSmoothing, self).__init__() + self.confidence = 1.0 - smoothing + self.smoothing = smoothing + self.device = loc + + def forward(self, x, target): + target = target.to(torch.int64) + + logprobs = torch.nn.functional.log_softmax(x, dim=-1) + nll_loss = -logprobs.gather(dim=-1, index=target.unsqueeze(1).to(torch.int64)) + nll_loss = nll_loss.squeeze(1) + smooth_loss = -logprobs.mean(dim=-1) + loss = self.confidence * nll_loss + self.smoothing * smooth_loss + return loss.mean() + +if __name__ == '__main__': + main() diff --git a/PyTorch/contrib/cv/classification/csp_resnext50-mish/benchmark.py b/PyTorch/contrib/cv/classification/csp_resnext50-mish/benchmark.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/csp_resnext50-mish/timm/loss/asymmetric_loss.py b/PyTorch/contrib/cv/classification/csp_resnext50-mish/timm/loss/asymmetric_loss.py index 96a977882b..a8b10f9c79 100644 --- a/PyTorch/contrib/cv/classification/csp_resnext50-mish/timm/loss/asymmetric_loss.py +++ b/PyTorch/contrib/cv/classification/csp_resnext50-mish/timm/loss/asymmetric_loss.py @@ -1,97 +1,97 @@ -import torch -import torch.nn as nn - - -class AsymmetricLossMultiLabel(nn.Module): - def __init__(self, gamma_neg=4, gamma_pos=1, clip=0.05, eps=1e-8, disable_torch_grad_focal_loss=False): - super(AsymmetricLossMultiLabel, self).__init__() - - self.gamma_neg = gamma_neg - self.gamma_pos = gamma_pos - self.clip = clip - self.disable_torch_grad_focal_loss = disable_torch_grad_focal_loss - self.eps = eps - - def forward(self, x, y): - """" - Parameters - ---------- - x: input logits - y: targets (multi-label binarized vector) - """ - - # Calculating Probabilities - x_sigmoid = torch.sigmoid(x) - xs_pos = x_sigmoid - xs_neg = 1 - x_sigmoid - - # Asymmetric Clipping - if self.clip is not None and self.clip > 0: - xs_neg = (xs_neg + self.clip).clamp(max=1) - - # Basic CE calculation - los_pos = y * torch.log(xs_pos.clamp(min=self.eps)) - los_neg = (1 - y) * torch.log(xs_neg.clamp(min=self.eps)) - loss = los_pos + los_neg - - # Asymmetric Focusing - if self.gamma_neg > 0 or self.gamma_pos > 0: - if self.disable_torch_grad_focal_loss: - torch._C.set_grad_enabled(False) - pt0 = xs_pos * y - pt1 = xs_neg * (1 - y) # pt = p if t > 0 else 1-p - pt = pt0 + pt1 - one_sided_gamma = self.gamma_pos * y + self.gamma_neg * (1 - y) - one_sided_w = torch.pow(1 - pt, one_sided_gamma) - if self.disable_torch_grad_focal_loss: - torch._C.set_grad_enabled(True) - loss *= one_sided_w - - return -loss.sum() - - -class AsymmetricLossSingleLabel(nn.Module): - def __init__(self, gamma_pos=1, gamma_neg=4, eps: float = 0.1, reduction='mean'): - super(AsymmetricLossSingleLabel, self).__init__() - - self.eps = eps - self.logsoftmax = nn.LogSoftmax(dim=-1) - self.targets_classes = [] # prevent gpu repeated memory allocation - self.gamma_pos = gamma_pos - self.gamma_neg = gamma_neg - self.reduction = reduction - - def forward(self, inputs, target, reduction=None): - """" - Parameters - ---------- - x: input logits - y: targets (1-hot vector) - """ - - num_classes = inputs.size()[-1] - log_preds = self.logsoftmax(inputs) - self.targets_classes = torch.zeros_like(inputs).scatter_(1, target.long().unsqueeze(1), 1) - - # ASL weights - targets = self.targets_classes - anti_targets = 1 - targets - xs_pos = torch.exp(log_preds) - xs_neg = 1 - xs_pos - xs_pos = xs_pos * targets - xs_neg = xs_neg * anti_targets - asymmetric_w = torch.pow(1 - xs_pos - xs_neg, - self.gamma_pos * targets + self.gamma_neg * anti_targets) - log_preds = log_preds * asymmetric_w - - if self.eps > 0: # label smoothing - self.targets_classes.mul_(1 - self.eps).add_(self.eps / num_classes) - - # loss calculation - loss = - self.targets_classes.mul(log_preds) - - loss = loss.sum(dim=-1) - if self.reduction == 'mean': - loss = loss.mean() - - return loss +import torch +import torch.nn as nn + + +class AsymmetricLossMultiLabel(nn.Module): + def __init__(self, gamma_neg=4, gamma_pos=1, clip=0.05, eps=1e-8, disable_torch_grad_focal_loss=False): + super(AsymmetricLossMultiLabel, self).__init__() + + self.gamma_neg = gamma_neg + self.gamma_pos = gamma_pos + self.clip = clip + self.disable_torch_grad_focal_loss = disable_torch_grad_focal_loss + self.eps = eps + + def forward(self, x, y): + """" + Parameters + ---------- + x: input logits + y: targets (multi-label binarized vector) + """ + + # Calculating Probabilities + x_sigmoid = torch.sigmoid(x) + xs_pos = x_sigmoid + xs_neg = 1 - x_sigmoid + + # Asymmetric Clipping + if self.clip is not None and self.clip > 0: + xs_neg = (xs_neg + self.clip).clamp(max=1) + + # Basic CE calculation + los_pos = y * torch.log(xs_pos.clamp(min=self.eps)) + los_neg = (1 - y) * torch.log(xs_neg.clamp(min=self.eps)) + loss = los_pos + los_neg + + # Asymmetric Focusing + if self.gamma_neg > 0 or self.gamma_pos > 0: + if self.disable_torch_grad_focal_loss: + torch._C.set_grad_enabled(False) + pt0 = xs_pos * y + pt1 = xs_neg * (1 - y) # pt = p if t > 0 else 1-p + pt = pt0 + pt1 + one_sided_gamma = self.gamma_pos * y + self.gamma_neg * (1 - y) + one_sided_w = torch.pow(1 - pt, one_sided_gamma) + if self.disable_torch_grad_focal_loss: + torch._C.set_grad_enabled(True) + loss *= one_sided_w + + return -loss.sum() + + +class AsymmetricLossSingleLabel(nn.Module): + def __init__(self, gamma_pos=1, gamma_neg=4, eps: float = 0.1, reduction='mean'): + super(AsymmetricLossSingleLabel, self).__init__() + + self.eps = eps + self.logsoftmax = nn.LogSoftmax(dim=-1) + self.targets_classes = [] # prevent gpu repeated memory allocation + self.gamma_pos = gamma_pos + self.gamma_neg = gamma_neg + self.reduction = reduction + + def forward(self, inputs, target, reduction=None): + """" + Parameters + ---------- + x: input logits + y: targets (1-hot vector) + """ + + num_classes = inputs.size()[-1] + log_preds = self.logsoftmax(inputs) + self.targets_classes = torch.zeros_like(inputs).scatter_(1, target.long().unsqueeze(1), 1) + + # ASL weights + targets = self.targets_classes + anti_targets = 1 - targets + xs_pos = torch.exp(log_preds) + xs_neg = 1 - xs_pos + xs_pos = xs_pos * targets + xs_neg = xs_neg * anti_targets + asymmetric_w = torch.pow(1 - xs_pos - xs_neg, + self.gamma_pos * targets + self.gamma_neg * anti_targets) + log_preds = log_preds * asymmetric_w + + if self.eps > 0: # label smoothing + self.targets_classes.mul_(1 - self.eps).add_(self.eps / num_classes) + + # loss calculation + loss = - self.targets_classes.mul(log_preds) + + loss = loss.sum(dim=-1) + if self.reduction == 'mean': + loss = loss.mean() + + return loss diff --git a/PyTorch/contrib/cv/classification/csp_resnext50-mish/train-1p.py b/PyTorch/contrib/cv/classification/csp_resnext50-mish/train-1p.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/csp_resnext50-mish/train-8p.py b/PyTorch/contrib/cv/classification/csp_resnext50-mish/train-8p.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/csp_resnext50-mish/validate.py b/PyTorch/contrib/cv/classification/csp_resnext50-mish/validate.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/classification/pointnetCNN/LICENSE b/PyTorch/contrib/cv/classification/pointnetCNN/LICENSE index 657549b860..dcc65541a1 100644 --- a/PyTorch/contrib/cv/classification/pointnetCNN/LICENSE +++ b/PyTorch/contrib/cv/classification/pointnetCNN/LICENSE @@ -1,30 +1,30 @@ -BSD 3-Clause License - -Copyright (c) 2017, -All rights reserved. -Copyright 2020 Huawei Technologies Co., Ltd - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +BSD 3-Clause License + +Copyright (c) 2017, +All rights reserved. +Copyright 2020 Huawei Technologies Co., Ltd + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/pointnetCNN/README.md b/PyTorch/contrib/cv/classification/pointnetCNN/README.md index 0199ef0f24..907e6f516e 100644 --- a/PyTorch/contrib/cv/classification/pointnetCNN/README.md +++ b/PyTorch/contrib/cv/classification/pointnetCNN/README.md @@ -1,48 +1,48 @@ -# PointNetCNN - -This implements training of PointNetCNN on the modelnet40_ply_hdf5_2048 dataset. - -## PointNetCNN Detail - - - -## Requirements - -- `pip install -r requirements.txt` -- Download the dataset from https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/classfication/PointNetCNN/modelnet40_ply_hdf5_2048.zip and unzip it to ./data - -## Training - -To train a model, run `train_pytorch.py` - -```bash -# training 1p accuracy -bash ./test/train_full_1p.sh --data_path=./data/modelnet40_ply_hdf5_2048/ - -# training 1p performance -bash ./test/train_performance_1p.sh --data_path=./data/modelnet40_ply_hdf5_2048/ - -# training 8p accuracy -bash ./test/train_full_8p.sh --data_path=./data/modelnet40_ply_hdf5_2048/ - -# training 8p performance -bash ./test/train_performance_8p.sh --data_path=./data/modelnet40_ply_hdf5_2048/ - - -# finetuning 1p -bash test/train_finetune_1p.sh --data_path=./data/modelnet40_ply_hdf5_2048/ -``` - -Log path: - ./test/output/1/train_1.log # 8p training performance and loss log - ./test/output/1/train_1.log # 1p training performance and loss log - - - - -## PointNetCNN training result - -| Acc@1 | FPS | Npu_nums | Epochs | AMP_Type | -| :------: | :------: | :------: | :------: | :------: | -| - | 20 | 1 | 1 | O1 | -| - | 160 | 8 | 250 | O1 | +# PointNetCNN + +This implements training of PointNetCNN on the modelnet40_ply_hdf5_2048 dataset. + +## PointNetCNN Detail + + + +## Requirements + +- `pip install -r requirements.txt` +- Download the dataset from https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E6%8E%A8%E7%90%86/cv/classfication/PointNetCNN/modelnet40_ply_hdf5_2048.zip and unzip it to ./data + +## Training + +To train a model, run `train_pytorch.py` + +```bash +# training 1p accuracy +bash ./test/train_full_1p.sh --data_path=./data/modelnet40_ply_hdf5_2048/ + +# training 1p performance +bash ./test/train_performance_1p.sh --data_path=./data/modelnet40_ply_hdf5_2048/ + +# training 8p accuracy +bash ./test/train_full_8p.sh --data_path=./data/modelnet40_ply_hdf5_2048/ + +# training 8p performance +bash ./test/train_performance_8p.sh --data_path=./data/modelnet40_ply_hdf5_2048/ + + +# finetuning 1p +bash test/train_finetune_1p.sh --data_path=./data/modelnet40_ply_hdf5_2048/ +``` + +Log path: + ./test/output/1/train_1.log # 8p training performance and loss log + ./test/output/1/train_1.log # 1p training performance and loss log + + + + +## PointNetCNN training result + +| Acc@1 | FPS | Npu_nums | Epochs | AMP_Type | +| :------: | :------: | :------: | :------: | :------: | +| - | 20 | 1 | 1 | O1 | +| - | 160 | 8 | 250 | O1 | diff --git a/PyTorch/contrib/cv/classification/pointnetCNN/modelzoo_level.txt b/PyTorch/contrib/cv/classification/pointnetCNN/modelzoo_level.txt index a17c8f95fa..a829ab59b9 100644 --- a/PyTorch/contrib/cv/classification/pointnetCNN/modelzoo_level.txt +++ b/PyTorch/contrib/cv/classification/pointnetCNN/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:NOK +FuncStatus:OK +PerfStatus:NOK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/pointnetCNN/requirements.txt b/PyTorch/contrib/cv/classification/pointnetCNN/requirements.txt index 366725ddde..04d04ad3fe 100644 --- a/PyTorch/contrib/cv/classification/pointnetCNN/requirements.txt +++ b/PyTorch/contrib/cv/classification/pointnetCNN/requirements.txt @@ -1,4 +1,4 @@ -torch == 1.5.0 -h5py -scipy -sklearn +torch == 1.5.0 +h5py +scipy +sklearn diff --git a/PyTorch/contrib/cv/classification/vit_base_patch32_224/LICENSE b/PyTorch/contrib/cv/classification/vit_base_patch32_224/LICENSE index 4ba4fdcab3..a0e0310359 100644 --- a/PyTorch/contrib/cv/classification/vit_base_patch32_224/LICENSE +++ b/PyTorch/contrib/cv/classification/vit_base_patch32_224/LICENSE @@ -1,29 +1,29 @@ -BSD 3-Clause License - -Copyright (c) 2017, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +BSD 3-Clause License + +Copyright (c) 2017, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/vit_base_patch32_224/README.md b/PyTorch/contrib/cv/classification/vit_base_patch32_224/README.md index 3a818ad9fb..34984ac0d0 100644 --- a/PyTorch/contrib/cv/classification/vit_base_patch32_224/README.md +++ b/PyTorch/contrib/cv/classification/vit_base_patch32_224/README.md @@ -1,31 +1,31 @@ -## Vit_base_patch32_224
-This implements training of Vit_base_patch32_224 on the ImageNet dataset
-## Vit_base_patch32_224 Detail
-This model is one of open-source models by rwightman. See the source code at https://github.com/rwightman/pytorch-image-models/tree/master/timm.
-The whole model has achieved the requirement of accuracy and performance.
-## requirement
-Install PyTorch
-```pip install timm```
-```torchvision==0.5.0(x86) && torchvision==0.2.0(arm)``` -Please prepare the dataset by yourself, including training set and verification set. The optional dataset includes imagenet2012, including train and val. -## Training
-To train a model, run ```vit_train.py``` with the desired model architecture and the path to the ImageNet dataset:
-```bash -# training 1p performance -bash test/train_performance_1p.sh --data_path=real_data_path - -# training 8p accuracy -bash test/train_full_8p.sh --data_path=real_data_path - -# training 8p performance -bash test/train_performance_8p.sh --data_path=real_data_path - -# finetuning 1p -bash test/train_finetune_1p.sh --data_path=real_data_path --model-path=real_pre_train_model_path -``` -Log path: output/devie_id/train_${device_id}.log
-## Vit_base_patch32_224 Detail
-| Acc@1 | FPS | Npu_nums | Epochs | AMP_Type | -| :------: | :------: | :------: | :------: | :------: | -| - | 96.8 | 1 | 1 | O1 | +## Vit_base_patch32_224
+This implements training of Vit_base_patch32_224 on the ImageNet dataset
+## Vit_base_patch32_224 Detail
+This model is one of open-source models by rwightman. See the source code at https://github.com/rwightman/pytorch-image-models/tree/master/timm.
+The whole model has achieved the requirement of accuracy and performance.
+## requirement
+Install PyTorch
+```pip install timm```
+```torchvision==0.5.0(x86) && torchvision==0.2.0(arm)``` +Please prepare the dataset by yourself, including training set and verification set. The optional dataset includes imagenet2012, including train and val. +## Training
+To train a model, run ```vit_train.py``` with the desired model architecture and the path to the ImageNet dataset:
+```bash +# training 1p performance +bash test/train_performance_1p.sh --data_path=real_data_path + +# training 8p accuracy +bash test/train_full_8p.sh --data_path=real_data_path + +# training 8p performance +bash test/train_performance_8p.sh --data_path=real_data_path + +# finetuning 1p +bash test/train_finetune_1p.sh --data_path=real_data_path --model-path=real_pre_train_model_path +``` +Log path: output/devie_id/train_${device_id}.log
+## Vit_base_patch32_224 Detail
+| Acc@1 | FPS | Npu_nums | Epochs | AMP_Type | +| :------: | :------: | :------: | :------: | :------: | +| - | 96.8 | 1 | 1 | O1 | | 80.64 | 2981 | 8 | 8 | O1 | \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/vit_base_patch32_224/modelzoo_level.txt b/PyTorch/contrib/cv/classification/vit_base_patch32_224/modelzoo_level.txt index 41bdc0f3b0..810a09268c 100644 --- a/PyTorch/contrib/cv/classification/vit_base_patch32_224/modelzoo_level.txt +++ b/PyTorch/contrib/cv/classification/vit_base_patch32_224/modelzoo_level.txt @@ -1,5 +1,5 @@ -GPUStatus:OK -NPUMigrationStatus:OK -FuncStatus:OK -PrecisionStatus:OK +GPUStatus:OK +NPUMigrationStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus:POK \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/vit_base_patch32_224/requirements.txt b/PyTorch/contrib/cv/classification/vit_base_patch32_224/requirements.txt index bd9dc1313f..c08eaabc34 100644 --- a/PyTorch/contrib/cv/classification/vit_base_patch32_224/requirements.txt +++ b/PyTorch/contrib/cv/classification/vit_base_patch32_224/requirements.txt @@ -1,5 +1,5 @@ -#torch=1.5.0 -#torchvision>=0.5.0 -#torchvision>=0.2.0 -pyyaml +#torch=1.5.0 +#torchvision>=0.5.0 +#torchvision>=0.2.0 +pyyaml timm \ No newline at end of file diff --git a/PyTorch/contrib/cv/classification/vit_base_patch32_224/vit_train.py b/PyTorch/contrib/cv/classification/vit_base_patch32_224/vit_train.py index 277732b7ab..86884921f9 100644 --- a/PyTorch/contrib/cv/classification/vit_base_patch32_224/vit_train.py +++ b/PyTorch/contrib/cv/classification/vit_base_patch32_224/vit_train.py @@ -1,903 +1,903 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 argparse -import os -import random -import shutil -import time -import warnings -import torch -import numpy as np -import apex -from apex import amp -import torch.nn as nn -import torch.nn.parallel -import torch.npu -import torch.backends.cudnn as cudnn -import torch.distributed as dist -import torch.optim -import torch.multiprocessing as mp -import torch.utils.data -import torch.utils.data.distributed -import torchvision.transforms as transforms -import torchvision.datasets as datasets -import timm -from timm.utils import ApexScaler -from timm.data import create_dataset,create_loader,resolve_data_config,Mixup, FastCollateMixup, AugMixDataset -from timm.models import model_parameters, create_model -from collections import OrderedDict - -parser = argparse.ArgumentParser(description='PyTorch ImageNet Training') -parser.add_argument('data_dir', metavar='DIR', - help='path to dataset') -parser.add_argument('--dataset', '-d', metavar='NAME', default='', - help='dataset type (default: ImageFolder/ImageTar if empty)') -parser.add_argument('-j', '--workers', default=4, type=int, metavar='N', - help='number of data loading workers (default: 4)') -parser.add_argument('--epochs', default=90, type=int, metavar='N', - help='number of total epochs to run') -parser.add_argument('--start-epoch', default=0, type=int, metavar='N', - help='manual epoch number (useful on restarts)') -parser.add_argument('-b', '--batch-size', default=256, type=int, - metavar='N', - help='mini-batch size (default: 256), this is the total ' - 'batch size of all GPUs on the current node when ' - 'using Data Parallel or Distributed Data Parallel') -parser.add_argument('--lr', '--learning-rate', default=0.1, type=float, - metavar='LR', help='initial learning rate', dest='lr') -parser.add_argument('--momentum', default=0.9, type=float, metavar='M', - help='momentum') -parser.add_argument('--wd', '--weight-decay', default=1e-4, type=float, - metavar='W', help='weight decay (default: 1e-4)', - dest='weight_decay') -parser.add_argument('-p', '--print-freq', default=10, type=int, - metavar='N', help='print frequency (default: 10)') -parser.add_argument('--resume', default='', type=str, metavar='PATH', - help='path to latest checkpoint (default: none)') -parser.add_argument('-e', '--evaluate', dest='evaluate', action='store_true', - help='evaluate model on validation set') -parser.add_argument('--pretrained', dest='pretrained', action='store_true', - help='use pre-trained model') -parser.add_argument('--world-size', default=-1, type=int, - help='number of nodes for distributed training') -parser.add_argument('--rank', default=-1, type=int, - help='node rank for distributed training') -parser.add_argument('--dist-url', default='tcp://224.66.41.62:23456', type=str, - help='url used to set up distributed training') -parser.add_argument('--dist-backend', default='nccl', type=str, - help='distributed backend') -parser.add_argument('--seed', default=None, type=int, - help='seed for initializing training. ') -parser.add_argument('--gpu', default=None, type=int, - help='GPU id to use.') -parser.add_argument('--multiprocessing-distributed', action='store_true', - help='Use multi-processing distributed training to launch ' - 'N processes per node, which has N GPUs. This is the ' - 'fastest way to use PyTorch for either single node or ' - 'multi node data parallel training') -parser.add_argument('--num-classes', default=1000, type=int, - help='The number of classes.') -## for ascend 910 -parser.add_argument('--device', default='npu', type=str, help='npu or gpu') -parser.add_argument('--addr', default='10.136.181.115', - type=str, help='master addr') -parser.add_argument('--device_list', default='0,1,2,3,4,5,6,7', - type=str, help='device id list') -parser.add_argument('--warm_up_epochs', default=0, type=int, - help='warm up') -parser.add_argument('--amp', default=False, action='store_true', - help='use amp to train the model') -parser.add_argument('--loss-scale', default=8, type=float, - help='loss scale using in amp, default -1 means dynamic') -parser.add_argument('--opt-level', default='O2', type=str, - help='loss scale using in amp, default -1 means dynamic') -parser.add_argument('--prof', default=False, action='store_true', - help='use profiling to evaluate the performance of model') - -#Additional parameters from author -parser.add_argument('--train-split', metavar='NAME', default='train', - help='dataset train split (default: train)') -parser.add_argument('--val-split', metavar='NAME', default='val', - help='dataset validation split (default: validation)') -parser.add_argument('--model', default='resnet50', type=str, metavar='MODEL', - help='Name of model to train (default: "resnet50"') -parser.add_argument('--initial-checkpoint', default='', type=str, metavar='PATH', - help='Initialize model from this checkpoint (default: none)') -parser.add_argument('--no-resume-opt', action='store_true', default=False, - help='prevent resume of optimizer state when resuming model') -parser.add_argument('--gp', default=None, type=str, metavar='POOL', - help='Global pool type, one of (fast, avg, max, avgmax, avgmaxc). Model default if None.') -parser.add_argument('--img-size', type=int, default=None, metavar='N', - help='Image patch size (default: None => model default)') -parser.add_argument('--input-size', default=None, nargs=3, type=int, - metavar='N N N', help='Input all image dimensions (d h w, e.g. --input-size 3 224 224), uses model default if empty') -parser.add_argument('--crop-pct', default=None, type=float, - metavar='N', help='Input image center crop percent (for validation only)') -parser.add_argument('--mean', type=float, nargs='+', default=None, metavar='MEAN', - help='Override mean pixel value of dataset') -parser.add_argument('--std', type=float, nargs='+', default=None, metavar='STD', - help='Override std deviation of of dataset') -parser.add_argument('--interpolation', default='', type=str, metavar='NAME', - help='Image resize interpolation type (overrides model)') -parser.add_argument('-vb', '--validation-batch-size', type=int, default=None, metavar='N', - help='validation batch size override (default: None)') - -# Optimizer parameters -parser.add_argument('--opt', default='sgd', type=str, metavar='OPTIMIZER', - help='Optimizer (default: "sgd"') -parser.add_argument('--opt-eps', default=None, type=float, metavar='EPSILON', - help='Optimizer Epsilon (default: None, use opt default)') -parser.add_argument('--opt-betas', default=None, type=float, nargs='+', metavar='BETA', - help='Optimizer Betas (default: None, use opt default)') -parser.add_argument('--clip-grad', type=float, default=None, metavar='NORM', - help='Clip gradient norm (default: None, no clipping)') -parser.add_argument('--clip-mode', type=str, default='norm', - help='Gradient clipping mode. One of ("norm", "value", "agc")') - - -# Learning rate schedule parameters -parser.add_argument('--sched', default='cosine', type=str, metavar='SCHEDULER', - help='LR scheduler (default: "step"') -parser.add_argument('--lr-noise', type=float, nargs='+', default=None, metavar='pct, pct', - help='learning rate noise on/off epoch percentages') -parser.add_argument('--lr-noise-pct', type=float, default=0.67, metavar='PERCENT', - help='learning rate noise limit percent (default: 0.67)') -parser.add_argument('--lr-noise-std', type=float, default=1.0, metavar='STDDEV', - help='learning rate noise std-dev (default: 1.0)') -parser.add_argument('--lr-cycle-mul', type=float, default=1.0, metavar='MULT', - help='learning rate cycle len multiplier (default: 1.0)') -parser.add_argument('--lr-cycle-decay', type=float, default=0.5, metavar='MULT', - help='amount to decay each learning rate cycle (default: 0.5)') -parser.add_argument('--lr-cycle-limit', type=int, default=1, metavar='N', - help='learning rate cycle limit, cycles enabled if > 1') -parser.add_argument('--lr-k-decay', type=float, default=1.0, - help='learning rate k-decay for cosine/poly (default: 1.0)') -parser.add_argument('--warmup-lr', type=float, default=0.0001, metavar='LR', - help='warmup learning rate (default: 0.0001)') -parser.add_argument('--min-lr', type=float, default=1e-6, metavar='LR', - help='lower lr bound for cyclic schedulers that hit 0 (1e-5)') -parser.add_argument('--epoch-repeats', type=float, default=0., metavar='N', - help='epoch repeat multiplier (number of times to repeat dataset epoch per train epoch).') -parser.add_argument('--decay-epochs', type=float, default=100, metavar='N', - help='epoch interval to decay LR') -parser.add_argument('--warmup-epochs', type=int, default=3, metavar='N', - help='epochs to warmup LR, if scheduler supports') -parser.add_argument('--cooldown-epochs', type=int, default=10, metavar='N', - help='epochs to cooldown LR at min_lr, after cyclic schedule ends') -parser.add_argument('--patience-epochs', type=int, default=10, metavar='N', - help='patience epochs for Plateau LR scheduler (default: 10') -parser.add_argument('--decay-rate', '--dr', type=float, default=0.1, metavar='RATE', - help='LR decay rate (default: 0.1)') - -# Augmentation & regularization parameters -parser.add_argument('--no-aug', action='store_true', default=False, - help='Disable all training augmentation, override other train aug args') -parser.add_argument('--scale', type=float, nargs='+', default=[0.08, 1.0], metavar='PCT', - help='Random resize scale (default: 0.08 1.0)') -parser.add_argument('--ratio', type=float, nargs='+', default=[3./4., 4./3.], metavar='RATIO', - help='Random resize aspect ratio (default: 0.75 1.33)') -parser.add_argument('--hflip', type=float, default=0.5, - help='Horizontal flip training aug probability') -parser.add_argument('--vflip', type=float, default=0., - help='Vertical flip training aug probability') -parser.add_argument('--color-jitter', type=float, default=0.4, metavar='PCT', - help='Color jitter factor (default: 0.4)') -parser.add_argument('--aa', type=str, default=None, metavar='NAME', - help='Use AutoAugment policy. "v0" or "original". (default: None)'), -parser.add_argument('--aug-repeats', type=int, default=0, - help='Number of augmentation repetitions (distributed training only) (default: 0)') -parser.add_argument('--aug-splits', type=int, default=0, - help='Number of augmentation splits (default: 0, valid: 0 or >=2)') -parser.add_argument('--jsd-loss', action='store_true', default=False, - help='Enable Jensen-Shannon Divergence + CE loss. Use with `--aug-splits`.') -parser.add_argument('--bce-loss', action='store_true', default=False, - help='Enable BCE loss w/ Mixup/CutMix use.') -parser.add_argument('--reprob', type=float, default=0., metavar='PCT', - help='Random erase prob (default: 0.)') -parser.add_argument('--remode', type=str, default='pixel', - help='Random erase mode (default: "pixel")') -parser.add_argument('--recount', type=int, default=1, - help='Random erase count (default: 1)') -parser.add_argument('--resplit', action='store_true', default=False, - help='Do not random erase first (clean) augmentation split') -parser.add_argument('--mixup', type=float, default=0.0, - help='mixup alpha, mixup enabled if > 0. (default: 0.)') -parser.add_argument('--cutmix', type=float, default=0.0, - help='cutmix alpha, cutmix enabled if > 0. (default: 0.)') -parser.add_argument('--cutmix-minmax', type=float, nargs='+', default=None, - help='cutmix min/max ratio, overrides alpha and enables cutmix if set (default: None)') -parser.add_argument('--mixup-prob', type=float, default=1.0, - help='Probability of performing mixup or cutmix when either/both is enabled') -parser.add_argument('--mixup-switch-prob', type=float, default=0.5, - help='Probability of switching to cutmix when both mixup and cutmix enabled') -parser.add_argument('--mixup-mode', type=str, default='batch', - help='How to apply mixup/cutmix params. Per "batch", "pair", or "elem"') -parser.add_argument('--mixup-off-epoch', default=0, type=int, metavar='N', - help='Turn off mixup after this epoch, disabled if 0 (default: 0)') -parser.add_argument('--smoothing', type=float, default=0.1, - help='Label smoothing (default: 0.1)') -parser.add_argument('--train-interpolation', type=str, default='random', - help='Training interpolation (random, bilinear, bicubic default: "random")') -parser.add_argument('--drop', type=float, default=0.0, metavar='PCT', - help='Dropout rate (default: 0.)') -parser.add_argument('--drop-connect', type=float, default=None, metavar='PCT', - help='Drop connect rate, DEPRECATED, use drop-path (default: None)') -parser.add_argument('--drop-path', type=float, default=None, metavar='PCT', - help='Drop path rate (default: None)') -parser.add_argument('--drop-block', type=float, default=None, metavar='PCT', - help='Drop block rate (default: None)') - -# Batch norm parameters (only works with gen_efficientnet based models currently) -parser.add_argument('--bn-tf', action='store_true', default=False, - help='Use Tensorflow BatchNorm defaults for models that support it (default: False)') -parser.add_argument('--bn-momentum', type=float, default=None, - help='BatchNorm momentum override (if not None)') -parser.add_argument('--bn-eps', type=float, default=None, - help='BatchNorm epsilon override (if not None)') -parser.add_argument('--sync-bn', action='store_true', - help='Enable NVIDIA Apex or Torch synchronized BatchNorm.') -parser.add_argument('--dist-bn', type=str, default='reduce', - help='Distribute BatchNorm stats between nodes after each epoch ("broadcast", "reduce", or "")') -parser.add_argument('--split-bn', action='store_true', - help='Enable separate BN layers per augmentation split.') - -# Model Exponential Moving Average -parser.add_argument('--model-ema', action='store_true', default=False, - help='Enable tracking moving average of model weights') -parser.add_argument('--model-ema-force-cpu', action='store_true', default=False, - help='Force ema to be tracked on CPU, rank=0 node only. Disables EMA validation.') -parser.add_argument('--model-ema-decay', type=float, default=0.9998, - help='decay factor for model weights moving average (default: 0.9998)') - -# Misc -parser.add_argument('--log-interval', type=int, default=50, metavar='N', - help='how many batches to wait before logging training status') -parser.add_argument('--recovery-interval', type=int, default=0, metavar='N', - help='how many batches to wait before writing recovery checkpoint') -parser.add_argument('--checkpoint-hist', type=int, default=10, metavar='N', - help='number of checkpoints to keep (default: 10)') -parser.add_argument('--save-images', action='store_true', default=False, - help='save images of input bathes every log interval for debugging') -parser.add_argument('--apex-amp', action='store_true', default=False, - help='Use NVIDIA Apex AMP mixed precision') -parser.add_argument('--native-amp', action='store_true', default=False, - help='Use Native Torch AMP mixed precision') -parser.add_argument('--channels-last', action='store_true', default=False, - help='Use channels_last memory layout') -parser.add_argument('--pin-mem', action='store_true', default=False, - help='Pin CPU memory in DataLoader for more efficient (sometimes) transfer to GPU.') -parser.add_argument('--no-prefetcher', action='store_true', default=False, - help='disable fast prefetcher') -parser.add_argument('--output', default='', type=str, metavar='PATH', - help='path to output folder (default: none, current dir)') -parser.add_argument('--experiment', default='', type=str, metavar='NAME', - help='name of train experiment, name of sub-folder for output') -parser.add_argument('--eval-metric', default='top1', type=str, metavar='EVAL_METRIC', - help='Best metric (default: "top1"') -parser.add_argument('--tta', type=int, default=0, metavar='N', - help='Test/inference time augmentation (oversampling) factor. 0=None (default: 0)') -parser.add_argument("--local_rank", default=0, type=int) -parser.add_argument('--use-multi-epochs-loader', action='store_true', default=False, - help='use the multi-epochs-loader to save time at the beginning of every epoch') -parser.add_argument('--torchscript', dest='torchscript', action='store_true', - help='convert model torchscript for inference') -parser.add_argument('--log-wandb', action='store_true', default=False, - help='log training and validation metrics to wandb') -parser.add_argument('--model-path',type=str) -best_acc1 = 0 - - -def device_id_to_process_device_map(device_list): - devices = device_list.split(",") - devices = [int(x) for x in devices] - devices.sort() - - process_device_map = dict() - for process_id, device_id in enumerate(devices): - process_device_map[process_id] = device_id - - return process_device_map - -def proc_nodes_module(checkpoint,AttrName): - new_state_dict = OrderedDict() - for k, v in checkpoint[AttrName].items(): - if "module." in k: - name = k.replace("module.", "") - else: - name = k - new_state_dict[name] = v - return new_state_dict - - -def main(): - - args = parser.parse_args() - print(args.device_list) - - os.environ['MASTER_ADDR'] = args.addr - os.environ['MASTER_PORT'] = '29688' - - if args.seed is not None: - random.seed(args.seed) - torch.manual_seed(args.seed) - cudnn.deterministic = True - warnings.warn('You have chosen to seed training. ' - 'This will turn on the CUDNN deterministic setting, ' - 'which can slow down your training considerably! ' - 'You may see unexpected behavior when restarting ' - 'from checkpoints.') - - if args.gpu is not None: - warnings.warn('You have chosen a specific GPU. This will completely ' - 'disable data parallelism.') - - if args.dist_url == "env://" and args.world_size == -1: - args.world_size = int(os.environ["WORLD_SIZE"]) - - args.distributed = args.world_size > 1 or args.multiprocessing_distributed - - args.process_device_map = device_id_to_process_device_map(args.device_list) - - if args.device == 'npu': - ngpus_per_node = len(args.process_device_map) - else: - if args.distributed: - ngpus_per_node = torch.cuda.device_count() - else: - ngpus_per_node = 1 - print('ngpus_per_node:', ngpus_per_node) - if args.multiprocessing_distributed: - # Since we have ngpus_per_node processes per node, the total world_size - # needs to be adjusted accordingly - args.world_size = ngpus_per_node * args.world_size - # Use torch.multiprocessing.spawn to launch distributed processes: the - # main_worker process function - mp.spawn(main_worker, nprocs=ngpus_per_node, - args=(ngpus_per_node, args)) - else: - # Simply call main_worker function - main_worker(args.gpu, ngpus_per_node, args) - - -def main_worker(gpu, ngpus_per_node, args): - global best_acc1 - args.gpu = args.process_device_map[gpu] - - if args.gpu is not None: - print("Use GPU: {} for training".format(args.gpu)) - print("Is distributed train available?",dist.is_available()) - if args.distributed: - if args.dist_url == "env://" and args.rank == -1: - print("According to url") - args.rank = int(os.environ["RANK"]) - print("endif") - if args.multiprocessing_distributed: - # For multiprocessing distributed training, rank needs to be the - # global rank among all the processes - args.rank = args.rank * ngpus_per_node + gpu - - if args.device == 'npu': - print("enter npu dis") - dist.init_process_group(backend=args.dist_backend, # init_method=args.dist_url, - world_size=args.world_size, rank=args.rank) - print("leave npu dist") - else: - dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url, - world_size=args.world_size, rank=args.rank) - # create model - if args.pretrained: - print("=> using pre-trained model vit_base_patch32") - model = create_model( - "vit_base_patch32_224_in21k", - pretrained=args.pretrained, - num_classes=1000, - drop_rate=args.drop, - drop_connect_rate=args.drop_connect, # DEPRECATED, use drop_path - drop_path_rate=args.drop_path, - drop_block_rate=args.drop_block, - global_pool=args.gp, - bn_tf=args.bn_tf, - bn_momentum=args.bn_momentum, - bn_eps=args.bn_eps, - scriptable=args.torchscript, - checkpoint_path=args.initial_checkpoint) - data_config = resolve_data_config(vars(args), model=model, verbose=args.local_rank == 0) - #model = timm.create_model("vit_base_patch32_224_in21k",pretrained=True,num_classes=1000) - #print("loading model of yours...") - #pretrained_dict = torch.load("./model_best.pth.tar", map_location="cpu")["state_dict"] - #model.load_state_dict({k.replace('module.',''):v for k, v in pretrained_dict.items()}) - #if "fc.weight" in pretrained_dict: - # pretrained_dict.pop('fc.weight') - # pretrained_dict.pop('fc.bias') - #model.load_state_dict(pretrained_dict, strict=False) - else: - print("=> creating model vit_base_patch32") - model = model = timm.create_model("vit_base_patch32_224",num_classes=1000) - pretrained_dict = torch.load(args.model_path, map_location="cpu") - pretrained_dict['state_dict']=proc_nodes_module(pretrained_dict,'state_dict') - model.load_state_dict(pretrained_dict['state_dict']) - model.head = nn.Linear(768, args.num_classes) if args.num_classes > 0 else nn.Identity() - - - if args.distributed: - # For multiprocessing distributed, DistributedDataParallel constructor - # should always set the single device scope, otherwise, - # DistributedDataParallel will use all available devices. - if args.gpu is not None: - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - torch.npu.set_device(loc) - model = model.to(loc) - else: - torch.cuda.set_device(args.gpu) - model.cuda(args.gpu) - - # When using a single GPU per process and per - # DistributedDataParallel, we need to divide the batch size - # ourselves based on the total number of GPUs we have - args.batch_size = int(args.batch_size / args.world_size) - args.workers = int((args.workers + ngpus_per_node - 1) / ngpus_per_node) - else: - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - model = model.to(loc) - else: - model.cuda() - # DistributedDataParallel will divide and allocate batch_size to all - # available GPUs if device_ids are not set - print("[gpu id:", args.gpu, "]", - "============================test args.gpu is not None else==========================") - elif args.gpu is not None: - print("[gpu id:", args.gpu, "]", - "============================test elif args.gpu is not None:==========================") - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - torch.npu.set_device(args.gpu) - model = model.to(loc) - else: - torch.cuda.set_device(args.gpu) - model = model.cuda(args.gpu) - - else: - # DataParallel will divide and allocate batch_size to all available GPUs - print("[gpu id:", args.gpu, "]", "============================test 1==========================") - print("[gpu id:", args.gpu, "]", "============================test 3==========================") - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - else: - print("before : model = torch.nn.DataParallel(model).cuda()") - - # define loss function (criterion) and optimizer - #optimizer = torch.optim.SGD(model.parameters(), lr=args.lr, - # momentum=args.momentum, - # weight_decay=args.weight_decay,nesterov=True) - optimizer = apex.optimizers.NpuFusedSGD(model.parameters(), args.lr, - momentum=args.momentum, - weight_decay=args.weight_decay) - - - if args.amp: - model, optimizer = amp.initialize( - model, optimizer, opt_level='O1',combine_grad=True) - loss_scaler=ApexScaler() - - if args.distributed: - # For multiprocessing distributed, DistributedDataParallel constructor - # should always set the single device scope, otherwise, - # DistributedDataParallel will use all available devices. - if args.gpu is not None: - # When using a single GPU per process and per - # DistributedDataParallel, we need to divide the batch size - # ourselves based on the total number of GPUs we have - if args.pretrained: - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu], broadcast_buffers=False, - find_unused_parameters=True) - else: - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu], broadcast_buffers=False) - else: - print("[gpu id:", args.gpu, "]", - "============================test args.gpu is not None else==========================") - model = torch.nn.parallel.DistributedDataParallel(model) - elif args.gpu is not None: - print("[gpu id:", args.gpu, "]", - "============================test elif args.gpu is not None:==========================") - else: - # DataParallel will divide and allocate batch_size to all available GPUs - print("[gpu id:", args.gpu, "]", "============================test 1==========================") - print("[gpu id:", args.gpu, "]", "============================test 3==========================") - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - model = torch.nn.DataParallel(model).to(loc) - else: - model = torch.nn.DataParallel(model).cuda() - - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - criterion = nn.CrossEntropyLoss().to(loc) - else: - criterion = nn.CrossEntropyLoss().cuda(args.gpu) - - # optionally resume from a checkpoint - if args.resume: - if os.path.isfile(args.resume): - print("=> loading checkpoint '{}'".format(args.resume)) - if args.gpu is None: - checkpoint = torch.load(args.resume) - else: - # Map model to be loaded to specified single gpu. - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - else: - loc = 'cuda:{}'.format(args.gpu) - checkpoint = torch.load(args.resume, map_location=loc) - args.start_epoch = checkpoint['epoch'] - best_acc1 = checkpoint['best_acc1'] - if args.gpu is not None: - # best_acc1 may be from a checkpoint from a different GPU - best_acc1 = best_acc1.to(args.gpu) - model.load_state_dict(checkpoint['state_dict']) - optimizer.load_state_dict(checkpoint['optimizer']) - if args.amp: - amp.load_state_dict(checkpoint['amp']) - print("=> loaded checkpoint '{}' (epoch {})" - .format(args.resume, checkpoint['epoch'])) - else: - print("=> no checkpoint found at '{}'".format(args.resume)) - - cudnn.benchmark = True - - # Data loading code - traindir = os.path.join(args.data_dir, 'train') - valdir = os.path.join(args.data_dir, 'val') - normalize = transforms.Normalize(mean=[0.5, 0.5, 0.5], - std=[0.5, 0.5, 0.5]) - - train_dataset = datasets.ImageFolder( - traindir, - transforms.Compose([ - transforms.RandomResizedCrop(224,interpolation=3), - transforms.RandomHorizontalFlip(), - transforms.ToTensor(), - normalize, - ])) - - if args.distributed: - train_sampler = torch.utils.data.distributed.DistributedSampler( - train_dataset) - else: - train_sampler = None - - train_loader = torch.utils.data.DataLoader( - train_dataset, batch_size=args.batch_size, shuffle=( - train_sampler is None), - num_workers=args.workers, pin_memory=False, sampler=train_sampler, drop_last=True) - - val_loader = torch.utils.data.DataLoader( - datasets.ImageFolder(valdir, transforms.Compose([ - transforms.Resize(256,interpolation=3), - transforms.CenterCrop(224), - transforms.ToTensor(), - normalize, - ])), - batch_size=args.batch_size, shuffle=True, - num_workers=args.workers, pin_memory=False, drop_last=True) - if args.evaluate: - validate(val_loader, model, criterion, args, ngpus_per_node) - return - - if args.prof: - profiling(train_loader, model, criterion, optimizer, args) - return - - start_time = time.time() - for epoch in range(args.start_epoch, args.epochs): - if args.distributed: - train_sampler.set_epoch(epoch) - # if args.distributed and hasattr(train_loader.sampler, 'set_epoch'): - # train_loader.sampler.set_epoch(epoch) - - adjust_learning_rate(optimizer, epoch, args) - - # train for one epoch - train(train_loader, model, criterion, optimizer, epoch, args, ngpus_per_node,loss_scaler) - - # evaluate on validation set - acc1 = validate(val_loader, model, criterion, args, ngpus_per_node) - - # remember best acc@1 and save checkpoint - is_best = acc1 > best_acc1 - best_acc1 = max(acc1, best_acc1) - if args.device == 'npu' and args.gpu == 0 and epoch == 89: - print("Complete 90 epoch training, take time:{}h".format(round((time.time() - start_time) / 3600.0, 2))) - - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % ngpus_per_node == 0): - - ############## npu modify begin ############# - if args.amp: - save_checkpoint({ - 'epoch': epoch + 1, - 'arch': 'wide_resnet50_2', - 'state_dict': model.state_dict(), - 'best_acc1': best_acc1, - 'optimizer': optimizer.state_dict(), - 'amp': amp.state_dict(), - }, is_best) - else: - save_checkpoint({ - 'epoch': epoch + 1, - 'arch': 'wide_resnet50_2', - 'state_dict': model.state_dict(), - 'best_acc1': best_acc1, - 'optimizer': optimizer.state_dict(), - }, is_best) - ############## npu modify end ############# - - -def profiling(data_loader, model, criterion, optimizer, args): - # switch to train mode - model.train() - - def update(model, images, target, optimizer): - output = model(images) - loss = criterion(output, target) - if args.amp: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.zero_grad() - optimizer.step() - - for step, (images, target) in enumerate(data_loader): - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - images = images.to(loc, non_blocking=True).to(torch.float) - target = target.to(torch.int32).to(loc, non_blocking=True) - else: - images = images.cuda(args.gpu, non_blocking=True) - target = target.cuda(args.gpu, non_blocking=True) - - if step < 5: - update(model, images, target, optimizer) - else: - if args.device == 'npu': - with torch.autograd.profiler.profile(use_npu=True) as prof: - update(model, images, target, optimizer) - else: - with torch.autograd.profiler.profile(use_cuda=True) as prof: - update(model, images, target, optimizer) - break - - prof.export_chrome_trace("output.prof") - - -def train(train_loader, model, criterion, optimizer, epoch, args, ngpus_per_node,loss_scaler): - batch_time = AverageMeter('Time', ':6.3f') - data_time = AverageMeter('Data', ':6.3f') - losses = AverageMeter('Loss', ':.4e') - top1 = AverageMeter('Acc@1', ':6.2f') - top5 = AverageMeter('Acc@5', ':6.2f') - progress = ProgressMeter( - len(train_loader), - [batch_time, data_time, losses, top1, top5], - prefix="Epoch: [{}]".format(epoch)) - second_order = hasattr(optimizer, 'is_second_order') and optimizer.is_second_order - # switch to train mode - model.train() - - end = time.time() - for i, (images, target) in enumerate(train_loader): - # measure data loading time - data_time.update(time.time() - end) - - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - images = images.to(loc, non_blocking=True).to(torch.float) - target = target.to(torch.int32).to(loc, non_blocking=True) - else: - images = images.cuda(args.gpu, non_blocking=True) - target = target.cuda(args.gpu, non_blocking=True) - - # compute output - output = model(images) - loss = criterion(output, target) - - # measure accuracy and record loss - acc1, acc5 = accuracy(output, target, topk=(1, 5)) - losses.update(loss.item(), images.size(0)) - top1.update(acc1[0], images.size(0)) - top5.update(acc5[0], images.size(0)) - - # compute gradient and do SGD step - optimizer.zero_grad() - if args.amp: - loss_scaler( - loss, optimizer, - clip_grad=args.clip_grad, clip_mode=args.clip_mode, - parameters=model_parameters(model, exclude_head='agc' in args.clip_mode), - create_graph=second_order) - else: - loss.backward() - optimizer.step() - if args.device == 'npu': - torch.npu.synchronize() - - # measure elapsed time - cost_time = time.time() - end - batch_time.update(cost_time) - end = time.time() - - if i % args.print_freq == 0: - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % ngpus_per_node == 0): - progress.display(i) - - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % ngpus_per_node == 0): - if batch_time.avg: - print("[npu id:", args.gpu, "]", "batch_size:", args.world_size * args.batch_size, - 'Time: {:.3f}'.format(batch_time.avg), '* FPS@all {:.3f}'.format( - args.batch_size * args.world_size / batch_time.avg)) - - -def validate(val_loader, model, criterion, args, ngpus_per_node): - batch_time = AverageMeter('Time', ':6.3f') - losses = AverageMeter('Loss', ':.4e') - top1 = AverageMeter('Acc@1', ':6.2f') - top5 = AverageMeter('Acc@5', ':6.2f') - progress = ProgressMeter( - len(val_loader), - [batch_time, losses, top1, top5], - prefix='Test: ') - - # switch to evaluate mode - model.eval() - - with torch.no_grad(): - end = time.time() - for i, (images, target) in enumerate(val_loader): - if args.gpu is not None: - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - images = images.to(loc).to(torch.float) - else: - images = images.cuda(args.gpu, non_blocking=True) - if args.device == 'npu': - loc = 'npu:{}'.format(args.gpu) - target = target.to(torch.int32).to(loc, non_blocking=True) - else: - target = target.cuda(args.gpu, non_blocking=True) - - # compute output - output = model(images) - loss = criterion(output, target) - - # measure accuracy and record loss - acc1, acc5 = accuracy(output, target, topk=(1, 5)) - losses.update(loss.item(), images.size(0)) - top1.update(acc1[0], images.size(0)) - top5.update(acc5[0], images.size(0)) - - # measure elapsed time - cost_time = time.time() - end - batch_time.update(cost_time) - end = time.time() - - if i % args.print_freq == 0: - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % ngpus_per_node == 0): - progress.display(i) - - if i % args.print_freq == 0: - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % ngpus_per_node == 0): - print("[gpu id:", args.gpu, "]", '[AVG-ACC] * Acc@1 {top1.avg:.3f} Acc@5 {top5.avg:.3f}' - .format(top1=top1, top5=top5)) - - return top1.avg - - -def save_checkpoint(state, is_best, filename='checkpoint.pth.tar'): - torch.save(state, filename) - if is_best: - shutil.copyfile(filename, 'model_best.pth.tar') - - -class AverageMeter(object): - """Computes and stores the average and current value""" - - def __init__(self, name, fmt=':f', start_count_index=2): - self.name = name - self.fmt = fmt - self.reset() - self.start_count_index = start_count_index - - def reset(self): - self.val = 0 - self.avg = 0 - self.sum = 0 - self.count = 0 - - def update(self, val, n=1): - if self.count == 0: - self.N = n - - self.val = val - self.count += n - if self.count > (self.start_count_index * self.N): - self.sum += val * n - self.avg = self.sum / (self.count - self.start_count_index * self.N) - - def __str__(self): - fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' - return fmtstr.format(**self.__dict__) - - -class ProgressMeter(object): - - def __init__(self, num_batches, meters, prefix=""): - self.batch_fmtstr = self._get_batch_fmtstr(num_batches) - self.meters = meters - self.prefix = prefix - - def display(self, batch): - entries = [self.prefix + self.batch_fmtstr.format(batch)] - entries += [str(meter) for meter in self.meters] - print('\t'.join(entries)) - - def _get_batch_fmtstr(self, num_batches): - num_digits = len(str(num_batches // 1)) - fmt = '{:' + str(num_digits) + 'd}' - return '[' + fmt + '/' + fmt.format(num_batches) + ']' - - -def adjust_learning_rate(optimizer, epoch, args): - """Sets the learning rate to the initial LR decayed by cosine method""" - - if args.warm_up_epochs > 0 and epoch < args.warm_up_epochs: - lr = args.lr * ((epoch + 1) / (args.warm_up_epochs + 1)) - else: - alpha = 0 - cosine_decay = 0.5 * ( - 1 + np.cos(np.pi * (epoch - args.warm_up_epochs) / (args.epochs - args.warm_up_epochs))) - decayed = (1 - alpha) * cosine_decay + alpha - lr = args.lr * decayed - - print("=> Epoch[%d] Setting lr: %.4f" % (epoch, lr)) - for param_group in optimizer.param_groups: - param_group['lr'] = lr - - -def accuracy(output, target, topk=(1,)): - """Computes the accuracy over the k top predictions for the specified values of k""" - with torch.no_grad(): - maxk = max(topk) - batch_size = target.size(0) - - _, pred = output.topk(maxk, 1, True, True) - pred = pred.t() - correct = pred.eq(target.view(1, -1).expand_as(pred)) - - res = [] - for k in topk: - correct_k = correct[:k].reshape(-1).float().sum(0, keepdim=True) - res.append(correct_k.mul_(100.0 / batch_size)) - return res - - -if __name__ == '__main__': - main() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 argparse +import os +import random +import shutil +import time +import warnings +import torch +import numpy as np +import apex +from apex import amp +import torch.nn as nn +import torch.nn.parallel +import torch.npu +import torch.backends.cudnn as cudnn +import torch.distributed as dist +import torch.optim +import torch.multiprocessing as mp +import torch.utils.data +import torch.utils.data.distributed +import torchvision.transforms as transforms +import torchvision.datasets as datasets +import timm +from timm.utils import ApexScaler +from timm.data import create_dataset,create_loader,resolve_data_config,Mixup, FastCollateMixup, AugMixDataset +from timm.models import model_parameters, create_model +from collections import OrderedDict + +parser = argparse.ArgumentParser(description='PyTorch ImageNet Training') +parser.add_argument('data_dir', metavar='DIR', + help='path to dataset') +parser.add_argument('--dataset', '-d', metavar='NAME', default='', + help='dataset type (default: ImageFolder/ImageTar if empty)') +parser.add_argument('-j', '--workers', default=4, type=int, metavar='N', + help='number of data loading workers (default: 4)') +parser.add_argument('--epochs', default=90, type=int, metavar='N', + help='number of total epochs to run') +parser.add_argument('--start-epoch', default=0, type=int, metavar='N', + help='manual epoch number (useful on restarts)') +parser.add_argument('-b', '--batch-size', default=256, type=int, + metavar='N', + help='mini-batch size (default: 256), this is the total ' + 'batch size of all GPUs on the current node when ' + 'using Data Parallel or Distributed Data Parallel') +parser.add_argument('--lr', '--learning-rate', default=0.1, type=float, + metavar='LR', help='initial learning rate', dest='lr') +parser.add_argument('--momentum', default=0.9, type=float, metavar='M', + help='momentum') +parser.add_argument('--wd', '--weight-decay', default=1e-4, type=float, + metavar='W', help='weight decay (default: 1e-4)', + dest='weight_decay') +parser.add_argument('-p', '--print-freq', default=10, type=int, + metavar='N', help='print frequency (default: 10)') +parser.add_argument('--resume', default='', type=str, metavar='PATH', + help='path to latest checkpoint (default: none)') +parser.add_argument('-e', '--evaluate', dest='evaluate', action='store_true', + help='evaluate model on validation set') +parser.add_argument('--pretrained', dest='pretrained', action='store_true', + help='use pre-trained model') +parser.add_argument('--world-size', default=-1, type=int, + help='number of nodes for distributed training') +parser.add_argument('--rank', default=-1, type=int, + help='node rank for distributed training') +parser.add_argument('--dist-url', default='tcp://224.66.41.62:23456', type=str, + help='url used to set up distributed training') +parser.add_argument('--dist-backend', default='nccl', type=str, + help='distributed backend') +parser.add_argument('--seed', default=None, type=int, + help='seed for initializing training. ') +parser.add_argument('--gpu', default=None, type=int, + help='GPU id to use.') +parser.add_argument('--multiprocessing-distributed', action='store_true', + help='Use multi-processing distributed training to launch ' + 'N processes per node, which has N GPUs. This is the ' + 'fastest way to use PyTorch for either single node or ' + 'multi node data parallel training') +parser.add_argument('--num-classes', default=1000, type=int, + help='The number of classes.') +## for ascend 910 +parser.add_argument('--device', default='npu', type=str, help='npu or gpu') +parser.add_argument('--addr', default='10.136.181.115', + type=str, help='master addr') +parser.add_argument('--device_list', default='0,1,2,3,4,5,6,7', + type=str, help='device id list') +parser.add_argument('--warm_up_epochs', default=0, type=int, + help='warm up') +parser.add_argument('--amp', default=False, action='store_true', + help='use amp to train the model') +parser.add_argument('--loss-scale', default=8, type=float, + help='loss scale using in amp, default -1 means dynamic') +parser.add_argument('--opt-level', default='O2', type=str, + help='loss scale using in amp, default -1 means dynamic') +parser.add_argument('--prof', default=False, action='store_true', + help='use profiling to evaluate the performance of model') + +#Additional parameters from author +parser.add_argument('--train-split', metavar='NAME', default='train', + help='dataset train split (default: train)') +parser.add_argument('--val-split', metavar='NAME', default='val', + help='dataset validation split (default: validation)') +parser.add_argument('--model', default='resnet50', type=str, metavar='MODEL', + help='Name of model to train (default: "resnet50"') +parser.add_argument('--initial-checkpoint', default='', type=str, metavar='PATH', + help='Initialize model from this checkpoint (default: none)') +parser.add_argument('--no-resume-opt', action='store_true', default=False, + help='prevent resume of optimizer state when resuming model') +parser.add_argument('--gp', default=None, type=str, metavar='POOL', + help='Global pool type, one of (fast, avg, max, avgmax, avgmaxc). Model default if None.') +parser.add_argument('--img-size', type=int, default=None, metavar='N', + help='Image patch size (default: None => model default)') +parser.add_argument('--input-size', default=None, nargs=3, type=int, + metavar='N N N', help='Input all image dimensions (d h w, e.g. --input-size 3 224 224), uses model default if empty') +parser.add_argument('--crop-pct', default=None, type=float, + metavar='N', help='Input image center crop percent (for validation only)') +parser.add_argument('--mean', type=float, nargs='+', default=None, metavar='MEAN', + help='Override mean pixel value of dataset') +parser.add_argument('--std', type=float, nargs='+', default=None, metavar='STD', + help='Override std deviation of of dataset') +parser.add_argument('--interpolation', default='', type=str, metavar='NAME', + help='Image resize interpolation type (overrides model)') +parser.add_argument('-vb', '--validation-batch-size', type=int, default=None, metavar='N', + help='validation batch size override (default: None)') + +# Optimizer parameters +parser.add_argument('--opt', default='sgd', type=str, metavar='OPTIMIZER', + help='Optimizer (default: "sgd"') +parser.add_argument('--opt-eps', default=None, type=float, metavar='EPSILON', + help='Optimizer Epsilon (default: None, use opt default)') +parser.add_argument('--opt-betas', default=None, type=float, nargs='+', metavar='BETA', + help='Optimizer Betas (default: None, use opt default)') +parser.add_argument('--clip-grad', type=float, default=None, metavar='NORM', + help='Clip gradient norm (default: None, no clipping)') +parser.add_argument('--clip-mode', type=str, default='norm', + help='Gradient clipping mode. One of ("norm", "value", "agc")') + + +# Learning rate schedule parameters +parser.add_argument('--sched', default='cosine', type=str, metavar='SCHEDULER', + help='LR scheduler (default: "step"') +parser.add_argument('--lr-noise', type=float, nargs='+', default=None, metavar='pct, pct', + help='learning rate noise on/off epoch percentages') +parser.add_argument('--lr-noise-pct', type=float, default=0.67, metavar='PERCENT', + help='learning rate noise limit percent (default: 0.67)') +parser.add_argument('--lr-noise-std', type=float, default=1.0, metavar='STDDEV', + help='learning rate noise std-dev (default: 1.0)') +parser.add_argument('--lr-cycle-mul', type=float, default=1.0, metavar='MULT', + help='learning rate cycle len multiplier (default: 1.0)') +parser.add_argument('--lr-cycle-decay', type=float, default=0.5, metavar='MULT', + help='amount to decay each learning rate cycle (default: 0.5)') +parser.add_argument('--lr-cycle-limit', type=int, default=1, metavar='N', + help='learning rate cycle limit, cycles enabled if > 1') +parser.add_argument('--lr-k-decay', type=float, default=1.0, + help='learning rate k-decay for cosine/poly (default: 1.0)') +parser.add_argument('--warmup-lr', type=float, default=0.0001, metavar='LR', + help='warmup learning rate (default: 0.0001)') +parser.add_argument('--min-lr', type=float, default=1e-6, metavar='LR', + help='lower lr bound for cyclic schedulers that hit 0 (1e-5)') +parser.add_argument('--epoch-repeats', type=float, default=0., metavar='N', + help='epoch repeat multiplier (number of times to repeat dataset epoch per train epoch).') +parser.add_argument('--decay-epochs', type=float, default=100, metavar='N', + help='epoch interval to decay LR') +parser.add_argument('--warmup-epochs', type=int, default=3, metavar='N', + help='epochs to warmup LR, if scheduler supports') +parser.add_argument('--cooldown-epochs', type=int, default=10, metavar='N', + help='epochs to cooldown LR at min_lr, after cyclic schedule ends') +parser.add_argument('--patience-epochs', type=int, default=10, metavar='N', + help='patience epochs for Plateau LR scheduler (default: 10') +parser.add_argument('--decay-rate', '--dr', type=float, default=0.1, metavar='RATE', + help='LR decay rate (default: 0.1)') + +# Augmentation & regularization parameters +parser.add_argument('--no-aug', action='store_true', default=False, + help='Disable all training augmentation, override other train aug args') +parser.add_argument('--scale', type=float, nargs='+', default=[0.08, 1.0], metavar='PCT', + help='Random resize scale (default: 0.08 1.0)') +parser.add_argument('--ratio', type=float, nargs='+', default=[3./4., 4./3.], metavar='RATIO', + help='Random resize aspect ratio (default: 0.75 1.33)') +parser.add_argument('--hflip', type=float, default=0.5, + help='Horizontal flip training aug probability') +parser.add_argument('--vflip', type=float, default=0., + help='Vertical flip training aug probability') +parser.add_argument('--color-jitter', type=float, default=0.4, metavar='PCT', + help='Color jitter factor (default: 0.4)') +parser.add_argument('--aa', type=str, default=None, metavar='NAME', + help='Use AutoAugment policy. "v0" or "original". (default: None)'), +parser.add_argument('--aug-repeats', type=int, default=0, + help='Number of augmentation repetitions (distributed training only) (default: 0)') +parser.add_argument('--aug-splits', type=int, default=0, + help='Number of augmentation splits (default: 0, valid: 0 or >=2)') +parser.add_argument('--jsd-loss', action='store_true', default=False, + help='Enable Jensen-Shannon Divergence + CE loss. Use with `--aug-splits`.') +parser.add_argument('--bce-loss', action='store_true', default=False, + help='Enable BCE loss w/ Mixup/CutMix use.') +parser.add_argument('--reprob', type=float, default=0., metavar='PCT', + help='Random erase prob (default: 0.)') +parser.add_argument('--remode', type=str, default='pixel', + help='Random erase mode (default: "pixel")') +parser.add_argument('--recount', type=int, default=1, + help='Random erase count (default: 1)') +parser.add_argument('--resplit', action='store_true', default=False, + help='Do not random erase first (clean) augmentation split') +parser.add_argument('--mixup', type=float, default=0.0, + help='mixup alpha, mixup enabled if > 0. (default: 0.)') +parser.add_argument('--cutmix', type=float, default=0.0, + help='cutmix alpha, cutmix enabled if > 0. (default: 0.)') +parser.add_argument('--cutmix-minmax', type=float, nargs='+', default=None, + help='cutmix min/max ratio, overrides alpha and enables cutmix if set (default: None)') +parser.add_argument('--mixup-prob', type=float, default=1.0, + help='Probability of performing mixup or cutmix when either/both is enabled') +parser.add_argument('--mixup-switch-prob', type=float, default=0.5, + help='Probability of switching to cutmix when both mixup and cutmix enabled') +parser.add_argument('--mixup-mode', type=str, default='batch', + help='How to apply mixup/cutmix params. Per "batch", "pair", or "elem"') +parser.add_argument('--mixup-off-epoch', default=0, type=int, metavar='N', + help='Turn off mixup after this epoch, disabled if 0 (default: 0)') +parser.add_argument('--smoothing', type=float, default=0.1, + help='Label smoothing (default: 0.1)') +parser.add_argument('--train-interpolation', type=str, default='random', + help='Training interpolation (random, bilinear, bicubic default: "random")') +parser.add_argument('--drop', type=float, default=0.0, metavar='PCT', + help='Dropout rate (default: 0.)') +parser.add_argument('--drop-connect', type=float, default=None, metavar='PCT', + help='Drop connect rate, DEPRECATED, use drop-path (default: None)') +parser.add_argument('--drop-path', type=float, default=None, metavar='PCT', + help='Drop path rate (default: None)') +parser.add_argument('--drop-block', type=float, default=None, metavar='PCT', + help='Drop block rate (default: None)') + +# Batch norm parameters (only works with gen_efficientnet based models currently) +parser.add_argument('--bn-tf', action='store_true', default=False, + help='Use Tensorflow BatchNorm defaults for models that support it (default: False)') +parser.add_argument('--bn-momentum', type=float, default=None, + help='BatchNorm momentum override (if not None)') +parser.add_argument('--bn-eps', type=float, default=None, + help='BatchNorm epsilon override (if not None)') +parser.add_argument('--sync-bn', action='store_true', + help='Enable NVIDIA Apex or Torch synchronized BatchNorm.') +parser.add_argument('--dist-bn', type=str, default='reduce', + help='Distribute BatchNorm stats between nodes after each epoch ("broadcast", "reduce", or "")') +parser.add_argument('--split-bn', action='store_true', + help='Enable separate BN layers per augmentation split.') + +# Model Exponential Moving Average +parser.add_argument('--model-ema', action='store_true', default=False, + help='Enable tracking moving average of model weights') +parser.add_argument('--model-ema-force-cpu', action='store_true', default=False, + help='Force ema to be tracked on CPU, rank=0 node only. Disables EMA validation.') +parser.add_argument('--model-ema-decay', type=float, default=0.9998, + help='decay factor for model weights moving average (default: 0.9998)') + +# Misc +parser.add_argument('--log-interval', type=int, default=50, metavar='N', + help='how many batches to wait before logging training status') +parser.add_argument('--recovery-interval', type=int, default=0, metavar='N', + help='how many batches to wait before writing recovery checkpoint') +parser.add_argument('--checkpoint-hist', type=int, default=10, metavar='N', + help='number of checkpoints to keep (default: 10)') +parser.add_argument('--save-images', action='store_true', default=False, + help='save images of input bathes every log interval for debugging') +parser.add_argument('--apex-amp', action='store_true', default=False, + help='Use NVIDIA Apex AMP mixed precision') +parser.add_argument('--native-amp', action='store_true', default=False, + help='Use Native Torch AMP mixed precision') +parser.add_argument('--channels-last', action='store_true', default=False, + help='Use channels_last memory layout') +parser.add_argument('--pin-mem', action='store_true', default=False, + help='Pin CPU memory in DataLoader for more efficient (sometimes) transfer to GPU.') +parser.add_argument('--no-prefetcher', action='store_true', default=False, + help='disable fast prefetcher') +parser.add_argument('--output', default='', type=str, metavar='PATH', + help='path to output folder (default: none, current dir)') +parser.add_argument('--experiment', default='', type=str, metavar='NAME', + help='name of train experiment, name of sub-folder for output') +parser.add_argument('--eval-metric', default='top1', type=str, metavar='EVAL_METRIC', + help='Best metric (default: "top1"') +parser.add_argument('--tta', type=int, default=0, metavar='N', + help='Test/inference time augmentation (oversampling) factor. 0=None (default: 0)') +parser.add_argument("--local_rank", default=0, type=int) +parser.add_argument('--use-multi-epochs-loader', action='store_true', default=False, + help='use the multi-epochs-loader to save time at the beginning of every epoch') +parser.add_argument('--torchscript', dest='torchscript', action='store_true', + help='convert model torchscript for inference') +parser.add_argument('--log-wandb', action='store_true', default=False, + help='log training and validation metrics to wandb') +parser.add_argument('--model-path',type=str) +best_acc1 = 0 + + +def device_id_to_process_device_map(device_list): + devices = device_list.split(",") + devices = [int(x) for x in devices] + devices.sort() + + process_device_map = dict() + for process_id, device_id in enumerate(devices): + process_device_map[process_id] = device_id + + return process_device_map + +def proc_nodes_module(checkpoint,AttrName): + new_state_dict = OrderedDict() + for k, v in checkpoint[AttrName].items(): + if "module." in k: + name = k.replace("module.", "") + else: + name = k + new_state_dict[name] = v + return new_state_dict + + +def main(): + + args = parser.parse_args() + print(args.device_list) + + os.environ['MASTER_ADDR'] = args.addr + os.environ['MASTER_PORT'] = '29688' + + if args.seed is not None: + random.seed(args.seed) + torch.manual_seed(args.seed) + cudnn.deterministic = True + warnings.warn('You have chosen to seed training. ' + 'This will turn on the CUDNN deterministic setting, ' + 'which can slow down your training considerably! ' + 'You may see unexpected behavior when restarting ' + 'from checkpoints.') + + if args.gpu is not None: + warnings.warn('You have chosen a specific GPU. This will completely ' + 'disable data parallelism.') + + if args.dist_url == "env://" and args.world_size == -1: + args.world_size = int(os.environ["WORLD_SIZE"]) + + args.distributed = args.world_size > 1 or args.multiprocessing_distributed + + args.process_device_map = device_id_to_process_device_map(args.device_list) + + if args.device == 'npu': + ngpus_per_node = len(args.process_device_map) + else: + if args.distributed: + ngpus_per_node = torch.cuda.device_count() + else: + ngpus_per_node = 1 + print('ngpus_per_node:', ngpus_per_node) + if args.multiprocessing_distributed: + # Since we have ngpus_per_node processes per node, the total world_size + # needs to be adjusted accordingly + args.world_size = ngpus_per_node * args.world_size + # Use torch.multiprocessing.spawn to launch distributed processes: the + # main_worker process function + mp.spawn(main_worker, nprocs=ngpus_per_node, + args=(ngpus_per_node, args)) + else: + # Simply call main_worker function + main_worker(args.gpu, ngpus_per_node, args) + + +def main_worker(gpu, ngpus_per_node, args): + global best_acc1 + args.gpu = args.process_device_map[gpu] + + if args.gpu is not None: + print("Use GPU: {} for training".format(args.gpu)) + print("Is distributed train available?",dist.is_available()) + if args.distributed: + if args.dist_url == "env://" and args.rank == -1: + print("According to url") + args.rank = int(os.environ["RANK"]) + print("endif") + if args.multiprocessing_distributed: + # For multiprocessing distributed training, rank needs to be the + # global rank among all the processes + args.rank = args.rank * ngpus_per_node + gpu + + if args.device == 'npu': + print("enter npu dis") + dist.init_process_group(backend=args.dist_backend, # init_method=args.dist_url, + world_size=args.world_size, rank=args.rank) + print("leave npu dist") + else: + dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url, + world_size=args.world_size, rank=args.rank) + # create model + if args.pretrained: + print("=> using pre-trained model vit_base_patch32") + model = create_model( + "vit_base_patch32_224_in21k", + pretrained=args.pretrained, + num_classes=1000, + drop_rate=args.drop, + drop_connect_rate=args.drop_connect, # DEPRECATED, use drop_path + drop_path_rate=args.drop_path, + drop_block_rate=args.drop_block, + global_pool=args.gp, + bn_tf=args.bn_tf, + bn_momentum=args.bn_momentum, + bn_eps=args.bn_eps, + scriptable=args.torchscript, + checkpoint_path=args.initial_checkpoint) + data_config = resolve_data_config(vars(args), model=model, verbose=args.local_rank == 0) + #model = timm.create_model("vit_base_patch32_224_in21k",pretrained=True,num_classes=1000) + #print("loading model of yours...") + #pretrained_dict = torch.load("./model_best.pth.tar", map_location="cpu")["state_dict"] + #model.load_state_dict({k.replace('module.',''):v for k, v in pretrained_dict.items()}) + #if "fc.weight" in pretrained_dict: + # pretrained_dict.pop('fc.weight') + # pretrained_dict.pop('fc.bias') + #model.load_state_dict(pretrained_dict, strict=False) + else: + print("=> creating model vit_base_patch32") + model = model = timm.create_model("vit_base_patch32_224",num_classes=1000) + pretrained_dict = torch.load(args.model_path, map_location="cpu") + pretrained_dict['state_dict']=proc_nodes_module(pretrained_dict,'state_dict') + model.load_state_dict(pretrained_dict['state_dict']) + model.head = nn.Linear(768, args.num_classes) if args.num_classes > 0 else nn.Identity() + + + if args.distributed: + # For multiprocessing distributed, DistributedDataParallel constructor + # should always set the single device scope, otherwise, + # DistributedDataParallel will use all available devices. + if args.gpu is not None: + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + torch.npu.set_device(loc) + model = model.to(loc) + else: + torch.cuda.set_device(args.gpu) + model.cuda(args.gpu) + + # When using a single GPU per process and per + # DistributedDataParallel, we need to divide the batch size + # ourselves based on the total number of GPUs we have + args.batch_size = int(args.batch_size / args.world_size) + args.workers = int((args.workers + ngpus_per_node - 1) / ngpus_per_node) + else: + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + model = model.to(loc) + else: + model.cuda() + # DistributedDataParallel will divide and allocate batch_size to all + # available GPUs if device_ids are not set + print("[gpu id:", args.gpu, "]", + "============================test args.gpu is not None else==========================") + elif args.gpu is not None: + print("[gpu id:", args.gpu, "]", + "============================test elif args.gpu is not None:==========================") + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + torch.npu.set_device(args.gpu) + model = model.to(loc) + else: + torch.cuda.set_device(args.gpu) + model = model.cuda(args.gpu) + + else: + # DataParallel will divide and allocate batch_size to all available GPUs + print("[gpu id:", args.gpu, "]", "============================test 1==========================") + print("[gpu id:", args.gpu, "]", "============================test 3==========================") + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + else: + print("before : model = torch.nn.DataParallel(model).cuda()") + + # define loss function (criterion) and optimizer + #optimizer = torch.optim.SGD(model.parameters(), lr=args.lr, + # momentum=args.momentum, + # weight_decay=args.weight_decay,nesterov=True) + optimizer = apex.optimizers.NpuFusedSGD(model.parameters(), args.lr, + momentum=args.momentum, + weight_decay=args.weight_decay) + + + if args.amp: + model, optimizer = amp.initialize( + model, optimizer, opt_level='O1',combine_grad=True) + loss_scaler=ApexScaler() + + if args.distributed: + # For multiprocessing distributed, DistributedDataParallel constructor + # should always set the single device scope, otherwise, + # DistributedDataParallel will use all available devices. + if args.gpu is not None: + # When using a single GPU per process and per + # DistributedDataParallel, we need to divide the batch size + # ourselves based on the total number of GPUs we have + if args.pretrained: + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu], broadcast_buffers=False, + find_unused_parameters=True) + else: + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu], broadcast_buffers=False) + else: + print("[gpu id:", args.gpu, "]", + "============================test args.gpu is not None else==========================") + model = torch.nn.parallel.DistributedDataParallel(model) + elif args.gpu is not None: + print("[gpu id:", args.gpu, "]", + "============================test elif args.gpu is not None:==========================") + else: + # DataParallel will divide and allocate batch_size to all available GPUs + print("[gpu id:", args.gpu, "]", "============================test 1==========================") + print("[gpu id:", args.gpu, "]", "============================test 3==========================") + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + model = torch.nn.DataParallel(model).to(loc) + else: + model = torch.nn.DataParallel(model).cuda() + + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + criterion = nn.CrossEntropyLoss().to(loc) + else: + criterion = nn.CrossEntropyLoss().cuda(args.gpu) + + # optionally resume from a checkpoint + if args.resume: + if os.path.isfile(args.resume): + print("=> loading checkpoint '{}'".format(args.resume)) + if args.gpu is None: + checkpoint = torch.load(args.resume) + else: + # Map model to be loaded to specified single gpu. + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + else: + loc = 'cuda:{}'.format(args.gpu) + checkpoint = torch.load(args.resume, map_location=loc) + args.start_epoch = checkpoint['epoch'] + best_acc1 = checkpoint['best_acc1'] + if args.gpu is not None: + # best_acc1 may be from a checkpoint from a different GPU + best_acc1 = best_acc1.to(args.gpu) + model.load_state_dict(checkpoint['state_dict']) + optimizer.load_state_dict(checkpoint['optimizer']) + if args.amp: + amp.load_state_dict(checkpoint['amp']) + print("=> loaded checkpoint '{}' (epoch {})" + .format(args.resume, checkpoint['epoch'])) + else: + print("=> no checkpoint found at '{}'".format(args.resume)) + + cudnn.benchmark = True + + # Data loading code + traindir = os.path.join(args.data_dir, 'train') + valdir = os.path.join(args.data_dir, 'val') + normalize = transforms.Normalize(mean=[0.5, 0.5, 0.5], + std=[0.5, 0.5, 0.5]) + + train_dataset = datasets.ImageFolder( + traindir, + transforms.Compose([ + transforms.RandomResizedCrop(224,interpolation=3), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + normalize, + ])) + + if args.distributed: + train_sampler = torch.utils.data.distributed.DistributedSampler( + train_dataset) + else: + train_sampler = None + + train_loader = torch.utils.data.DataLoader( + train_dataset, batch_size=args.batch_size, shuffle=( + train_sampler is None), + num_workers=args.workers, pin_memory=False, sampler=train_sampler, drop_last=True) + + val_loader = torch.utils.data.DataLoader( + datasets.ImageFolder(valdir, transforms.Compose([ + transforms.Resize(256,interpolation=3), + transforms.CenterCrop(224), + transforms.ToTensor(), + normalize, + ])), + batch_size=args.batch_size, shuffle=True, + num_workers=args.workers, pin_memory=False, drop_last=True) + if args.evaluate: + validate(val_loader, model, criterion, args, ngpus_per_node) + return + + if args.prof: + profiling(train_loader, model, criterion, optimizer, args) + return + + start_time = time.time() + for epoch in range(args.start_epoch, args.epochs): + if args.distributed: + train_sampler.set_epoch(epoch) + # if args.distributed and hasattr(train_loader.sampler, 'set_epoch'): + # train_loader.sampler.set_epoch(epoch) + + adjust_learning_rate(optimizer, epoch, args) + + # train for one epoch + train(train_loader, model, criterion, optimizer, epoch, args, ngpus_per_node,loss_scaler) + + # evaluate on validation set + acc1 = validate(val_loader, model, criterion, args, ngpus_per_node) + + # remember best acc@1 and save checkpoint + is_best = acc1 > best_acc1 + best_acc1 = max(acc1, best_acc1) + if args.device == 'npu' and args.gpu == 0 and epoch == 89: + print("Complete 90 epoch training, take time:{}h".format(round((time.time() - start_time) / 3600.0, 2))) + + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % ngpus_per_node == 0): + + ############## npu modify begin ############# + if args.amp: + save_checkpoint({ + 'epoch': epoch + 1, + 'arch': 'wide_resnet50_2', + 'state_dict': model.state_dict(), + 'best_acc1': best_acc1, + 'optimizer': optimizer.state_dict(), + 'amp': amp.state_dict(), + }, is_best) + else: + save_checkpoint({ + 'epoch': epoch + 1, + 'arch': 'wide_resnet50_2', + 'state_dict': model.state_dict(), + 'best_acc1': best_acc1, + 'optimizer': optimizer.state_dict(), + }, is_best) + ############## npu modify end ############# + + +def profiling(data_loader, model, criterion, optimizer, args): + # switch to train mode + model.train() + + def update(model, images, target, optimizer): + output = model(images) + loss = criterion(output, target) + if args.amp: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + optimizer.zero_grad() + optimizer.step() + + for step, (images, target) in enumerate(data_loader): + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + images = images.to(loc, non_blocking=True).to(torch.float) + target = target.to(torch.int32).to(loc, non_blocking=True) + else: + images = images.cuda(args.gpu, non_blocking=True) + target = target.cuda(args.gpu, non_blocking=True) + + if step < 5: + update(model, images, target, optimizer) + else: + if args.device == 'npu': + with torch.autograd.profiler.profile(use_npu=True) as prof: + update(model, images, target, optimizer) + else: + with torch.autograd.profiler.profile(use_cuda=True) as prof: + update(model, images, target, optimizer) + break + + prof.export_chrome_trace("output.prof") + + +def train(train_loader, model, criterion, optimizer, epoch, args, ngpus_per_node,loss_scaler): + batch_time = AverageMeter('Time', ':6.3f') + data_time = AverageMeter('Data', ':6.3f') + losses = AverageMeter('Loss', ':.4e') + top1 = AverageMeter('Acc@1', ':6.2f') + top5 = AverageMeter('Acc@5', ':6.2f') + progress = ProgressMeter( + len(train_loader), + [batch_time, data_time, losses, top1, top5], + prefix="Epoch: [{}]".format(epoch)) + second_order = hasattr(optimizer, 'is_second_order') and optimizer.is_second_order + # switch to train mode + model.train() + + end = time.time() + for i, (images, target) in enumerate(train_loader): + # measure data loading time + data_time.update(time.time() - end) + + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + images = images.to(loc, non_blocking=True).to(torch.float) + target = target.to(torch.int32).to(loc, non_blocking=True) + else: + images = images.cuda(args.gpu, non_blocking=True) + target = target.cuda(args.gpu, non_blocking=True) + + # compute output + output = model(images) + loss = criterion(output, target) + + # measure accuracy and record loss + acc1, acc5 = accuracy(output, target, topk=(1, 5)) + losses.update(loss.item(), images.size(0)) + top1.update(acc1[0], images.size(0)) + top5.update(acc5[0], images.size(0)) + + # compute gradient and do SGD step + optimizer.zero_grad() + if args.amp: + loss_scaler( + loss, optimizer, + clip_grad=args.clip_grad, clip_mode=args.clip_mode, + parameters=model_parameters(model, exclude_head='agc' in args.clip_mode), + create_graph=second_order) + else: + loss.backward() + optimizer.step() + if args.device == 'npu': + torch.npu.synchronize() + + # measure elapsed time + cost_time = time.time() - end + batch_time.update(cost_time) + end = time.time() + + if i % args.print_freq == 0: + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % ngpus_per_node == 0): + progress.display(i) + + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % ngpus_per_node == 0): + if batch_time.avg: + print("[npu id:", args.gpu, "]", "batch_size:", args.world_size * args.batch_size, + 'Time: {:.3f}'.format(batch_time.avg), '* FPS@all {:.3f}'.format( + args.batch_size * args.world_size / batch_time.avg)) + + +def validate(val_loader, model, criterion, args, ngpus_per_node): + batch_time = AverageMeter('Time', ':6.3f') + losses = AverageMeter('Loss', ':.4e') + top1 = AverageMeter('Acc@1', ':6.2f') + top5 = AverageMeter('Acc@5', ':6.2f') + progress = ProgressMeter( + len(val_loader), + [batch_time, losses, top1, top5], + prefix='Test: ') + + # switch to evaluate mode + model.eval() + + with torch.no_grad(): + end = time.time() + for i, (images, target) in enumerate(val_loader): + if args.gpu is not None: + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + images = images.to(loc).to(torch.float) + else: + images = images.cuda(args.gpu, non_blocking=True) + if args.device == 'npu': + loc = 'npu:{}'.format(args.gpu) + target = target.to(torch.int32).to(loc, non_blocking=True) + else: + target = target.cuda(args.gpu, non_blocking=True) + + # compute output + output = model(images) + loss = criterion(output, target) + + # measure accuracy and record loss + acc1, acc5 = accuracy(output, target, topk=(1, 5)) + losses.update(loss.item(), images.size(0)) + top1.update(acc1[0], images.size(0)) + top5.update(acc5[0], images.size(0)) + + # measure elapsed time + cost_time = time.time() - end + batch_time.update(cost_time) + end = time.time() + + if i % args.print_freq == 0: + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % ngpus_per_node == 0): + progress.display(i) + + if i % args.print_freq == 0: + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % ngpus_per_node == 0): + print("[gpu id:", args.gpu, "]", '[AVG-ACC] * Acc@1 {top1.avg:.3f} Acc@5 {top5.avg:.3f}' + .format(top1=top1, top5=top5)) + + return top1.avg + + +def save_checkpoint(state, is_best, filename='checkpoint.pth.tar'): + torch.save(state, filename) + if is_best: + shutil.copyfile(filename, 'model_best.pth.tar') + + +class AverageMeter(object): + """Computes and stores the average and current value""" + + def __init__(self, name, fmt=':f', start_count_index=2): + self.name = name + self.fmt = fmt + self.reset() + self.start_count_index = start_count_index + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + + def update(self, val, n=1): + if self.count == 0: + self.N = n + + self.val = val + self.count += n + if self.count > (self.start_count_index * self.N): + self.sum += val * n + self.avg = self.sum / (self.count - self.start_count_index * self.N) + + def __str__(self): + fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' + return fmtstr.format(**self.__dict__) + + +class ProgressMeter(object): + + def __init__(self, num_batches, meters, prefix=""): + self.batch_fmtstr = self._get_batch_fmtstr(num_batches) + self.meters = meters + self.prefix = prefix + + def display(self, batch): + entries = [self.prefix + self.batch_fmtstr.format(batch)] + entries += [str(meter) for meter in self.meters] + print('\t'.join(entries)) + + def _get_batch_fmtstr(self, num_batches): + num_digits = len(str(num_batches // 1)) + fmt = '{:' + str(num_digits) + 'd}' + return '[' + fmt + '/' + fmt.format(num_batches) + ']' + + +def adjust_learning_rate(optimizer, epoch, args): + """Sets the learning rate to the initial LR decayed by cosine method""" + + if args.warm_up_epochs > 0 and epoch < args.warm_up_epochs: + lr = args.lr * ((epoch + 1) / (args.warm_up_epochs + 1)) + else: + alpha = 0 + cosine_decay = 0.5 * ( + 1 + np.cos(np.pi * (epoch - args.warm_up_epochs) / (args.epochs - args.warm_up_epochs))) + decayed = (1 - alpha) * cosine_decay + alpha + lr = args.lr * decayed + + print("=> Epoch[%d] Setting lr: %.4f" % (epoch, lr)) + for param_group in optimizer.param_groups: + param_group['lr'] = lr + + +def accuracy(output, target, topk=(1,)): + """Computes the accuracy over the k top predictions for the specified values of k""" + with torch.no_grad(): + maxk = max(topk) + batch_size = target.size(0) + + _, pred = output.topk(maxk, 1, True, True) + pred = pred.t() + correct = pred.eq(target.view(1, -1).expand_as(pred)) + + res = [] + for k in topk: + correct_k = correct[:k].reshape(-1).float().sum(0, keepdim=True) + res.append(correct_k.mul_(100.0 / batch_size)) + return res + + +if __name__ == '__main__': + main() diff --git a/PyTorch/contrib/cv/detection/CascadedMaskRCNN/detectron2/structures/masks.py b/PyTorch/contrib/cv/detection/CascadedMaskRCNN/detectron2/structures/masks.py index a4d97d942e..3933471d08 100644 --- a/PyTorch/contrib/cv/detection/CascadedMaskRCNN/detectron2/structures/masks.py +++ b/PyTorch/contrib/cv/detection/CascadedMaskRCNN/detectron2/structures/masks.py @@ -1,442 +1,442 @@ -# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 copy -import itertools -import numpy as np -from typing import Any, Iterator, List, Union -import pycocotools.mask as mask_util -import torch - -from detectron2.layers.roi_align import ROIAlign - -from .boxes import Boxes - - -def polygon_area(x, y): - # Using the shoelace formula - # https://stackoverflow.com/questions/24467972/calculate-area-of-polygon-given-x-y-coordinates - return 0.5 * np.abs(np.dot(x, np.roll(y, 1)) - np.dot(y, np.roll(x, 1))) - - -def polygons_to_bitmask(polygons: List[np.ndarray], height: int, width: int) -> np.ndarray: - """ - Args: - polygons (list[ndarray]): each array has shape (Nx2,) - height, width (int) - - Returns: - ndarray: a bool mask of shape (height, width) - """ - assert len(polygons) > 0, "COCOAPI does not support empty polygons" - rles = mask_util.frPyObjects(polygons, height, width) - rle = mask_util.merge(rles) - return mask_util.decode(rle).astype(np.bool) - - -def rasterize_polygons_within_box( - polygons: List[np.ndarray], box: np.ndarray, mask_size: int -) -> torch.Tensor: - """ - Rasterize the polygons into a mask image and - crop the mask content in the given box. - The cropped mask is resized to (mask_size, mask_size). - - This function is used when generating training targets for mask head in Mask R-CNN. - Given original ground-truth masks for an image, new ground-truth mask - training targets in the size of `mask_size x mask_size` - must be provided for each predicted box. This function will be called to - produce such targets. - - Args: - polygons (list[ndarray[float]]): a list of polygons, which represents an instance. - box: 4-element numpy array - mask_size (int): - - Returns: - Tensor: BoolTensor of shape (mask_size, mask_size) - """ - # 1. Shift the polygons w.r.t the boxes - w, h = box[2] - box[0], box[3] - box[1] - - polygons = copy.deepcopy(polygons) - for p in polygons: - p[0::2] = p[0::2] - box[0] - p[1::2] = p[1::2] - box[1] - - # 2. Rescale the polygons to the new box size - # max() to avoid division by small number - ratio_h = mask_size / max(h, 0.1) - ratio_w = mask_size / max(w, 0.1) - - if ratio_h == ratio_w: - for p in polygons: - p *= ratio_h - else: - for p in polygons: - p[0::2] *= ratio_w - p[1::2] *= ratio_h - - # 3. Rasterize the polygons with coco api - mask = polygons_to_bitmask(polygons, mask_size, mask_size) - mask = torch.from_numpy(mask) - return mask - - -class BitMasks: - """ - This class stores the segmentation masks for all objects in one image, in - the form of bitmaps. - - Attributes: - tensor: bool Tensor of N,H,W, representing N instances in the image. - """ - - def __init__(self, tensor: Union[torch.Tensor, np.ndarray]): - """ - Args: - tensor: bool Tensor of N,H,W, representing N instances in the image. - """ - device = tensor.device if isinstance(tensor, torch.Tensor) else torch.device("cpu") - tensor = torch.as_tensor(tensor, dtype=torch.bool, device=device) - assert tensor.dim() == 3, tensor.size() - self.image_size = tensor.shape[1:] - self.tensor = tensor - - def to(self, *args: Any, **kwargs: Any) -> "BitMasks": - return BitMasks(self.tensor.to(*args, **kwargs)) - - @property - def device(self) -> torch.device: - return self.tensor.device - - def __getitem__(self, item: Union[int, slice, torch.BoolTensor]) -> "BitMasks": - """ - Returns: - BitMasks: Create a new :class:`BitMasks` by indexing. - - The following usage are allowed: - - 1. `new_masks = masks[3]`: return a `BitMasks` which contains only one mask. - 2. `new_masks = masks[2:10]`: return a slice of masks. - 3. `new_masks = masks[vector]`, where vector is a torch.BoolTensor - with `length = len(masks)`. Nonzero elements in the vector will be selected. - - Note that the returned object might share storage with this object, - subject to Pytorch's indexing semantics. - """ - if isinstance(item, int): - return BitMasks(self.tensor[item].view(1, -1)) - - if item.dtype == torch.int32: - m = self.tensor[item.long()] - else: - m = self.tensor[item] - - assert m.dim() == 3, "Indexing on BitMasks with {} returns a tensor with shape {}!".format( - item, m.shape - ) - return BitMasks(m) - - def __iter__(self) -> torch.Tensor: - yield from self.tensor - - def __repr__(self) -> str: - s = self.__class__.__name__ + "(" - s += "num_instances={})".format(len(self.tensor)) - return s - - def __len__(self) -> int: - return self.tensor.shape[0] - - def nonempty(self) -> torch.Tensor: - """ - Find masks that are non-empty. - - Returns: - Tensor: a BoolTensor which represents - whether each mask is empty (False) or non-empty (True). - """ - return self.tensor.flatten(1).any(dim=1) - - @staticmethod - def from_polygon_masks( - polygon_masks: Union["PolygonMasks", List[List[np.ndarray]]], height: int, width: int - ) -> "BitMasks": - """ - Args: - polygon_masks (list[list[ndarray]] or PolygonMasks) - height, width (int) - """ - if isinstance(polygon_masks, PolygonMasks): - polygon_masks = polygon_masks.polygons - masks = [polygons_to_bitmask(p, height, width) for p in polygon_masks] - return BitMasks(torch.stack([torch.from_numpy(x) for x in masks])) - - def crop_and_resize(self, boxes: torch.Tensor, mask_size: int) -> torch.Tensor: - """ - Crop each bitmask by the given box, and resize results to (mask_size, mask_size). - This can be used to prepare training targets for Mask R-CNN. - It has less reconstruction error compared to rasterization with polygons. - However we observe no difference in accuracy, - but BitMasks requires more memory to store all the masks. - - Args: - boxes (Tensor): Nx4 tensor storing the boxes for each mask - mask_size (int): the size of the rasterized mask. - - Returns: - Tensor: - A bool tensor of shape (N, mask_size, mask_size), where - N is the number of predicted boxes for this image. - """ - assert len(boxes) == len(self), "{} != {}".format(len(boxes), len(self)) - device = self.tensor.device - - batch_inds = torch.arange(len(boxes), device=device).to(dtype=boxes.dtype)[:, None] - rois = torch.cat([batch_inds, boxes], dim=1) - bit_masks = self.tensor.to(dtype=torch.float32) - rois = rois.to(device=device) - - output = ( - ROIAlign((mask_size, mask_size), 1.0, 0, aligned=True) - .forward(bit_masks[:, None, :, :], rois) - .squeeze(1) - ) - output = output >= 0.5 - return output - - def get_bounding_boxes(self) -> None: - # not needed now - raise NotImplementedError - - @staticmethod - def cat(bitmasks_list: List["BitMasks"]) -> "BitMasks": - """ - Concatenates a list of BitMasks into a single BitMasks - - Arguments: - bitmasks_list (list[BitMasks]) - - Returns: - BitMasks: the concatenated BitMasks - """ - assert isinstance(bitmasks_list, (list, tuple)) - assert len(bitmasks_list) > 0 - assert all(isinstance(bitmask, BitMasks) for bitmask in bitmasks_list) - - cat_bitmasks = type(bitmasks_list[0])(torch.cat([bm.tensor for bm in bitmasks_list], dim=0)) - return cat_bitmasks - - -class PolygonMasks: - """ - This class stores the segmentation masks for all objects in one image, in the form of polygons. - - Attributes: - polygons: list[list[ndarray]]. Each ndarray is a float64 vector representing a polygon. - """ - - def __init__(self, polygons: List[List[Union[torch.Tensor, np.ndarray]]]): - """ - Arguments: - polygons (list[list[np.ndarray]]): The first - level of the list correspond to individual instances, - the second level to all the polygons that compose the - instance, and the third level to the polygon coordinates. - The third level array should have the format of - [x0, y0, x1, y1, ..., xn, yn] (n >= 3). - """ - assert isinstance(polygons, list), ( - "Cannot create PolygonMasks: Expect a list of list of polygons per image. " - "Got '{}' instead.".format(type(polygons)) - ) - - def _make_array(t: Union[torch.Tensor, np.ndarray]) -> np.ndarray: - # Use float64 for higher precision, because why not? - # Always put polygons on CPU (self.to is a no-op) since they - # are supposed to be small tensors. - # May need to change this assumption if GPU placement becomes useful - if isinstance(t, torch.Tensor): - t = t.cpu().numpy() - return np.asarray(t).astype("float64") - - def process_polygons( - polygons_per_instance: List[Union[torch.Tensor, np.ndarray]] - ) -> List[np.ndarray]: - assert isinstance(polygons_per_instance, list), ( - "Cannot create polygons: Expect a list of polygons per instance. " - "Got '{}' instead.".format(type(polygons_per_instance)) - ) - # transform the polygon to a tensor - polygons_per_instance = [_make_array(p) for p in polygons_per_instance] - for polygon in polygons_per_instance: - assert len(polygon) % 2 == 0 and len(polygon) >= 6 - return polygons_per_instance - - self.polygons: List[List[np.ndarray]] = [ - process_polygons(polygons_per_instance) for polygons_per_instance in polygons - ] - - def to(self, *args: Any, **kwargs: Any) -> "PolygonMasks": - return self - - @property - def device(self) -> torch.device: - return torch.device("cpu") - - def get_bounding_boxes(self) -> Boxes: - """ - Returns: - Boxes: tight bounding boxes around polygon masks. - """ - boxes = torch.zeros(len(self.polygons), 4, dtype=torch.float32) - for idx, polygons_per_instance in enumerate(self.polygons): - minxy = torch.as_tensor([float("inf"), float("inf")], dtype=torch.float32) - maxxy = torch.zeros(2, dtype=torch.float32) - for polygon in polygons_per_instance: - coords = torch.from_numpy(polygon).view(-1, 2).to(dtype=torch.float32) - minxy = torch.min(minxy, torch.min(coords, dim=0).values) - maxxy = torch.max(maxxy, torch.max(coords, dim=0).values) - boxes[idx, :2] = minxy - boxes[idx, 2:] = maxxy - return Boxes(boxes) - - def nonempty(self) -> torch.Tensor: - """ - Find masks that are non-empty. - - Returns: - Tensor: - a BoolTensor which represents whether each mask is empty (False) or not (True). - """ - keep = [1 if len(polygon) > 0 else 0 for polygon in self.polygons] - return torch.from_numpy(np.asarray(keep, dtype=np.bool)) - - def __getitem__(self, item: Union[int, slice, List[int], torch.BoolTensor]) -> "PolygonMasks": - """ - Support indexing over the instances and return a `PolygonMasks` object. - `item` can be: - - 1. An integer. It will return an object with only one instance. - 2. A slice. It will return an object with the selected instances. - 3. A list[int]. It will return an object with the selected instances, - correpsonding to the indices in the list. - 4. A vector mask of type BoolTensor, whose length is num_instances. - It will return an object with the instances whose mask is nonzero. - """ - if isinstance(item, int): - selected_polygons = [self.polygons[item]] - elif isinstance(item, slice): - selected_polygons = self.polygons[item] - elif isinstance(item, list): - selected_polygons = [self.polygons[i] for i in item] - elif isinstance(item, torch.Tensor): - # Polygons is a list, so we have to move the indices back to CPU. - if item.dtype == torch.bool: - assert item.dim() == 1, item.shape - item = item.nonzero().squeeze(1).cpu().numpy().tolist() - elif item.dtype in [torch.int32, torch.int64]: - item = item.cpu().numpy().tolist() - else: - raise ValueError("Unsupported tensor dtype={} for indexing!".format(item.dtype)) - selected_polygons = [self.polygons[i] for i in item] - return PolygonMasks(selected_polygons) - - def __iter__(self) -> Iterator[List[np.ndarray]]: - """ - Yields: - list[ndarray]: the polygons for one instance. - Each Tensor is a float64 vector representing a polygon. - """ - return iter(self.polygons) - - def __repr__(self) -> str: - s = self.__class__.__name__ + "(" - s += "num_instances={})".format(len(self.polygons)) - return s - - def __len__(self) -> int: - return len(self.polygons) - - def crop_and_resize(self, boxes: torch.Tensor, mask_size: int) -> torch.Tensor: - """ - Crop each mask by the given box, and resize results to (mask_size, mask_size). - This can be used to prepare training targets for Mask R-CNN. - - Args: - boxes (Tensor): Nx4 tensor storing the boxes for each mask - mask_size (int): the size of the rasterized mask. - - Returns: - Tensor: A bool tensor of shape (N, mask_size, mask_size), where - N is the number of predicted boxes for this image. - """ - assert len(boxes) == len(self), "{} != {}".format(len(boxes), len(self)) - - device = boxes.device - # Put boxes on the CPU, as the polygon representation is not efficient GPU-wise - # (several small tensors for representing a single instance mask) - boxes = boxes.to(torch.device("cpu")) - - results = [ - rasterize_polygons_within_box(poly, box.numpy(), mask_size) - for poly, box in zip(self.polygons, boxes) - ] - """ - poly: list[list[float]], the polygons for one instance - box: a tensor of shape (4,) - """ - if len(results) == 0: - return torch.empty(0, mask_size, mask_size, dtype=torch.bool, device=device) - return torch.stack(results, dim=0).to(device=device) - - def area(self): - """ - Computes area of the mask. - Only works with Polygons, using the shoelace formula: - https://stackoverflow.com/questions/24467972/calculate-area-of-polygon-given-x-y-coordinates - - Returns: - Tensor: a vector, area for each instance - """ - - area = [] - for polygons_per_instance in self.polygons: - area_per_instance = 0 - for p in polygons_per_instance: - area_per_instance += polygon_area(p[0::2], p[1::2]) - area.append(area_per_instance) - - return torch.tensor(area) - - @staticmethod - def cat(polymasks_list: List["PolygonMasks"]) -> "PolygonMasks": - """ - Concatenates a list of PolygonMasks into a single PolygonMasks - - Arguments: - polymasks_list (list[PolygonMasks]) - - Returns: - PolygonMasks: the concatenated PolygonMasks - """ - assert isinstance(polymasks_list, (list, tuple)) - assert len(polymasks_list) > 0 - assert all(isinstance(polymask, PolygonMasks) for polymask in polymasks_list) - - cat_polymasks = type(polymasks_list[0])( - list(itertools.chain.from_iterable(pm.polygons for pm in polymasks_list)) - ) - return cat_polymasks +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 copy +import itertools +import numpy as np +from typing import Any, Iterator, List, Union +import pycocotools.mask as mask_util +import torch + +from detectron2.layers.roi_align import ROIAlign + +from .boxes import Boxes + + +def polygon_area(x, y): + # Using the shoelace formula + # https://stackoverflow.com/questions/24467972/calculate-area-of-polygon-given-x-y-coordinates + return 0.5 * np.abs(np.dot(x, np.roll(y, 1)) - np.dot(y, np.roll(x, 1))) + + +def polygons_to_bitmask(polygons: List[np.ndarray], height: int, width: int) -> np.ndarray: + """ + Args: + polygons (list[ndarray]): each array has shape (Nx2,) + height, width (int) + + Returns: + ndarray: a bool mask of shape (height, width) + """ + assert len(polygons) > 0, "COCOAPI does not support empty polygons" + rles = mask_util.frPyObjects(polygons, height, width) + rle = mask_util.merge(rles) + return mask_util.decode(rle).astype(np.bool) + + +def rasterize_polygons_within_box( + polygons: List[np.ndarray], box: np.ndarray, mask_size: int +) -> torch.Tensor: + """ + Rasterize the polygons into a mask image and + crop the mask content in the given box. + The cropped mask is resized to (mask_size, mask_size). + + This function is used when generating training targets for mask head in Mask R-CNN. + Given original ground-truth masks for an image, new ground-truth mask + training targets in the size of `mask_size x mask_size` + must be provided for each predicted box. This function will be called to + produce such targets. + + Args: + polygons (list[ndarray[float]]): a list of polygons, which represents an instance. + box: 4-element numpy array + mask_size (int): + + Returns: + Tensor: BoolTensor of shape (mask_size, mask_size) + """ + # 1. Shift the polygons w.r.t the boxes + w, h = box[2] - box[0], box[3] - box[1] + + polygons = copy.deepcopy(polygons) + for p in polygons: + p[0::2] = p[0::2] - box[0] + p[1::2] = p[1::2] - box[1] + + # 2. Rescale the polygons to the new box size + # max() to avoid division by small number + ratio_h = mask_size / max(h, 0.1) + ratio_w = mask_size / max(w, 0.1) + + if ratio_h == ratio_w: + for p in polygons: + p *= ratio_h + else: + for p in polygons: + p[0::2] *= ratio_w + p[1::2] *= ratio_h + + # 3. Rasterize the polygons with coco api + mask = polygons_to_bitmask(polygons, mask_size, mask_size) + mask = torch.from_numpy(mask) + return mask + + +class BitMasks: + """ + This class stores the segmentation masks for all objects in one image, in + the form of bitmaps. + + Attributes: + tensor: bool Tensor of N,H,W, representing N instances in the image. + """ + + def __init__(self, tensor: Union[torch.Tensor, np.ndarray]): + """ + Args: + tensor: bool Tensor of N,H,W, representing N instances in the image. + """ + device = tensor.device if isinstance(tensor, torch.Tensor) else torch.device("cpu") + tensor = torch.as_tensor(tensor, dtype=torch.bool, device=device) + assert tensor.dim() == 3, tensor.size() + self.image_size = tensor.shape[1:] + self.tensor = tensor + + def to(self, *args: Any, **kwargs: Any) -> "BitMasks": + return BitMasks(self.tensor.to(*args, **kwargs)) + + @property + def device(self) -> torch.device: + return self.tensor.device + + def __getitem__(self, item: Union[int, slice, torch.BoolTensor]) -> "BitMasks": + """ + Returns: + BitMasks: Create a new :class:`BitMasks` by indexing. + + The following usage are allowed: + + 1. `new_masks = masks[3]`: return a `BitMasks` which contains only one mask. + 2. `new_masks = masks[2:10]`: return a slice of masks. + 3. `new_masks = masks[vector]`, where vector is a torch.BoolTensor + with `length = len(masks)`. Nonzero elements in the vector will be selected. + + Note that the returned object might share storage with this object, + subject to Pytorch's indexing semantics. + """ + if isinstance(item, int): + return BitMasks(self.tensor[item].view(1, -1)) + + if item.dtype == torch.int32: + m = self.tensor[item.long()] + else: + m = self.tensor[item] + + assert m.dim() == 3, "Indexing on BitMasks with {} returns a tensor with shape {}!".format( + item, m.shape + ) + return BitMasks(m) + + def __iter__(self) -> torch.Tensor: + yield from self.tensor + + def __repr__(self) -> str: + s = self.__class__.__name__ + "(" + s += "num_instances={})".format(len(self.tensor)) + return s + + def __len__(self) -> int: + return self.tensor.shape[0] + + def nonempty(self) -> torch.Tensor: + """ + Find masks that are non-empty. + + Returns: + Tensor: a BoolTensor which represents + whether each mask is empty (False) or non-empty (True). + """ + return self.tensor.flatten(1).any(dim=1) + + @staticmethod + def from_polygon_masks( + polygon_masks: Union["PolygonMasks", List[List[np.ndarray]]], height: int, width: int + ) -> "BitMasks": + """ + Args: + polygon_masks (list[list[ndarray]] or PolygonMasks) + height, width (int) + """ + if isinstance(polygon_masks, PolygonMasks): + polygon_masks = polygon_masks.polygons + masks = [polygons_to_bitmask(p, height, width) for p in polygon_masks] + return BitMasks(torch.stack([torch.from_numpy(x) for x in masks])) + + def crop_and_resize(self, boxes: torch.Tensor, mask_size: int) -> torch.Tensor: + """ + Crop each bitmask by the given box, and resize results to (mask_size, mask_size). + This can be used to prepare training targets for Mask R-CNN. + It has less reconstruction error compared to rasterization with polygons. + However we observe no difference in accuracy, + but BitMasks requires more memory to store all the masks. + + Args: + boxes (Tensor): Nx4 tensor storing the boxes for each mask + mask_size (int): the size of the rasterized mask. + + Returns: + Tensor: + A bool tensor of shape (N, mask_size, mask_size), where + N is the number of predicted boxes for this image. + """ + assert len(boxes) == len(self), "{} != {}".format(len(boxes), len(self)) + device = self.tensor.device + + batch_inds = torch.arange(len(boxes), device=device).to(dtype=boxes.dtype)[:, None] + rois = torch.cat([batch_inds, boxes], dim=1) + bit_masks = self.tensor.to(dtype=torch.float32) + rois = rois.to(device=device) + + output = ( + ROIAlign((mask_size, mask_size), 1.0, 0, aligned=True) + .forward(bit_masks[:, None, :, :], rois) + .squeeze(1) + ) + output = output >= 0.5 + return output + + def get_bounding_boxes(self) -> None: + # not needed now + raise NotImplementedError + + @staticmethod + def cat(bitmasks_list: List["BitMasks"]) -> "BitMasks": + """ + Concatenates a list of BitMasks into a single BitMasks + + Arguments: + bitmasks_list (list[BitMasks]) + + Returns: + BitMasks: the concatenated BitMasks + """ + assert isinstance(bitmasks_list, (list, tuple)) + assert len(bitmasks_list) > 0 + assert all(isinstance(bitmask, BitMasks) for bitmask in bitmasks_list) + + cat_bitmasks = type(bitmasks_list[0])(torch.cat([bm.tensor for bm in bitmasks_list], dim=0)) + return cat_bitmasks + + +class PolygonMasks: + """ + This class stores the segmentation masks for all objects in one image, in the form of polygons. + + Attributes: + polygons: list[list[ndarray]]. Each ndarray is a float64 vector representing a polygon. + """ + + def __init__(self, polygons: List[List[Union[torch.Tensor, np.ndarray]]]): + """ + Arguments: + polygons (list[list[np.ndarray]]): The first + level of the list correspond to individual instances, + the second level to all the polygons that compose the + instance, and the third level to the polygon coordinates. + The third level array should have the format of + [x0, y0, x1, y1, ..., xn, yn] (n >= 3). + """ + assert isinstance(polygons, list), ( + "Cannot create PolygonMasks: Expect a list of list of polygons per image. " + "Got '{}' instead.".format(type(polygons)) + ) + + def _make_array(t: Union[torch.Tensor, np.ndarray]) -> np.ndarray: + # Use float64 for higher precision, because why not? + # Always put polygons on CPU (self.to is a no-op) since they + # are supposed to be small tensors. + # May need to change this assumption if GPU placement becomes useful + if isinstance(t, torch.Tensor): + t = t.cpu().numpy() + return np.asarray(t).astype("float64") + + def process_polygons( + polygons_per_instance: List[Union[torch.Tensor, np.ndarray]] + ) -> List[np.ndarray]: + assert isinstance(polygons_per_instance, list), ( + "Cannot create polygons: Expect a list of polygons per instance. " + "Got '{}' instead.".format(type(polygons_per_instance)) + ) + # transform the polygon to a tensor + polygons_per_instance = [_make_array(p) for p in polygons_per_instance] + for polygon in polygons_per_instance: + assert len(polygon) % 2 == 0 and len(polygon) >= 6 + return polygons_per_instance + + self.polygons: List[List[np.ndarray]] = [ + process_polygons(polygons_per_instance) for polygons_per_instance in polygons + ] + + def to(self, *args: Any, **kwargs: Any) -> "PolygonMasks": + return self + + @property + def device(self) -> torch.device: + return torch.device("cpu") + + def get_bounding_boxes(self) -> Boxes: + """ + Returns: + Boxes: tight bounding boxes around polygon masks. + """ + boxes = torch.zeros(len(self.polygons), 4, dtype=torch.float32) + for idx, polygons_per_instance in enumerate(self.polygons): + minxy = torch.as_tensor([float("inf"), float("inf")], dtype=torch.float32) + maxxy = torch.zeros(2, dtype=torch.float32) + for polygon in polygons_per_instance: + coords = torch.from_numpy(polygon).view(-1, 2).to(dtype=torch.float32) + minxy = torch.min(minxy, torch.min(coords, dim=0).values) + maxxy = torch.max(maxxy, torch.max(coords, dim=0).values) + boxes[idx, :2] = minxy + boxes[idx, 2:] = maxxy + return Boxes(boxes) + + def nonempty(self) -> torch.Tensor: + """ + Find masks that are non-empty. + + Returns: + Tensor: + a BoolTensor which represents whether each mask is empty (False) or not (True). + """ + keep = [1 if len(polygon) > 0 else 0 for polygon in self.polygons] + return torch.from_numpy(np.asarray(keep, dtype=np.bool)) + + def __getitem__(self, item: Union[int, slice, List[int], torch.BoolTensor]) -> "PolygonMasks": + """ + Support indexing over the instances and return a `PolygonMasks` object. + `item` can be: + + 1. An integer. It will return an object with only one instance. + 2. A slice. It will return an object with the selected instances. + 3. A list[int]. It will return an object with the selected instances, + correpsonding to the indices in the list. + 4. A vector mask of type BoolTensor, whose length is num_instances. + It will return an object with the instances whose mask is nonzero. + """ + if isinstance(item, int): + selected_polygons = [self.polygons[item]] + elif isinstance(item, slice): + selected_polygons = self.polygons[item] + elif isinstance(item, list): + selected_polygons = [self.polygons[i] for i in item] + elif isinstance(item, torch.Tensor): + # Polygons is a list, so we have to move the indices back to CPU. + if item.dtype == torch.bool: + assert item.dim() == 1, item.shape + item = item.nonzero().squeeze(1).cpu().numpy().tolist() + elif item.dtype in [torch.int32, torch.int64]: + item = item.cpu().numpy().tolist() + else: + raise ValueError("Unsupported tensor dtype={} for indexing!".format(item.dtype)) + selected_polygons = [self.polygons[i] for i in item] + return PolygonMasks(selected_polygons) + + def __iter__(self) -> Iterator[List[np.ndarray]]: + """ + Yields: + list[ndarray]: the polygons for one instance. + Each Tensor is a float64 vector representing a polygon. + """ + return iter(self.polygons) + + def __repr__(self) -> str: + s = self.__class__.__name__ + "(" + s += "num_instances={})".format(len(self.polygons)) + return s + + def __len__(self) -> int: + return len(self.polygons) + + def crop_and_resize(self, boxes: torch.Tensor, mask_size: int) -> torch.Tensor: + """ + Crop each mask by the given box, and resize results to (mask_size, mask_size). + This can be used to prepare training targets for Mask R-CNN. + + Args: + boxes (Tensor): Nx4 tensor storing the boxes for each mask + mask_size (int): the size of the rasterized mask. + + Returns: + Tensor: A bool tensor of shape (N, mask_size, mask_size), where + N is the number of predicted boxes for this image. + """ + assert len(boxes) == len(self), "{} != {}".format(len(boxes), len(self)) + + device = boxes.device + # Put boxes on the CPU, as the polygon representation is not efficient GPU-wise + # (several small tensors for representing a single instance mask) + boxes = boxes.to(torch.device("cpu")) + + results = [ + rasterize_polygons_within_box(poly, box.numpy(), mask_size) + for poly, box in zip(self.polygons, boxes) + ] + """ + poly: list[list[float]], the polygons for one instance + box: a tensor of shape (4,) + """ + if len(results) == 0: + return torch.empty(0, mask_size, mask_size, dtype=torch.bool, device=device) + return torch.stack(results, dim=0).to(device=device) + + def area(self): + """ + Computes area of the mask. + Only works with Polygons, using the shoelace formula: + https://stackoverflow.com/questions/24467972/calculate-area-of-polygon-given-x-y-coordinates + + Returns: + Tensor: a vector, area for each instance + """ + + area = [] + for polygons_per_instance in self.polygons: + area_per_instance = 0 + for p in polygons_per_instance: + area_per_instance += polygon_area(p[0::2], p[1::2]) + area.append(area_per_instance) + + return torch.tensor(area) + + @staticmethod + def cat(polymasks_list: List["PolygonMasks"]) -> "PolygonMasks": + """ + Concatenates a list of PolygonMasks into a single PolygonMasks + + Arguments: + polymasks_list (list[PolygonMasks]) + + Returns: + PolygonMasks: the concatenated PolygonMasks + """ + assert isinstance(polymasks_list, (list, tuple)) + assert len(polymasks_list) > 0 + assert all(isinstance(polymask, PolygonMasks) for polymask in polymasks_list) + + cat_polymasks = type(polymasks_list[0])( + list(itertools.chain.from_iterable(pm.polygons for pm in polymasks_list)) + ) + return cat_polymasks diff --git a/PyTorch/contrib/cv/detection/CenterFace/LICENSE b/PyTorch/contrib/cv/detection/CenterFace/LICENSE index 4ba4fdcab3..a0e0310359 100644 --- a/PyTorch/contrib/cv/detection/CenterFace/LICENSE +++ b/PyTorch/contrib/cv/detection/CenterFace/LICENSE @@ -1,29 +1,29 @@ -BSD 3-Clause License - -Copyright (c) 2017, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +BSD 3-Clause License + +Copyright (c) 2017, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/CenterFace/modelzoo_level.txt b/PyTorch/contrib/cv/detection/CenterFace/modelzoo_level.txt index 484664c239..55a9add9fa 100644 --- a/PyTorch/contrib/cv/detection/CenterFace/modelzoo_level.txt +++ b/PyTorch/contrib/cv/detection/CenterFace/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:POK \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/CenterFace/src/8p_npu_main.py b/PyTorch/contrib/cv/detection/CenterFace/src/8p_npu_main.py index 1244c6f2c8..4dc05e1ea2 100644 --- a/PyTorch/contrib/cv/detection/CenterFace/src/8p_npu_main.py +++ b/PyTorch/contrib/cv/detection/CenterFace/src/8p_npu_main.py @@ -1,127 +1,127 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 _init_paths - -import os - -import torch -import torch.utils.data -from opts_pose import opts -from models.model import create_model, load_model, save_model -from models.data_parallel import DataParallel -from datasets.dataset_factory import get_dataset -from trains.train_factory import train_factory -from datasets.sample.multi_pose import Multiposebatch -from apex import amp -import torch.npu -import torch.distributed as dist -from torch.nn.parallel import DistributedDataParallel as DDP - - -def main(opt, qtepoch=[0,]): - - torch.manual_seed(opt.seed) - torch.backends.cudnn.benchmark = not opt.not_cuda_benchmark and not opt.test - Dataset = get_dataset(opt.dataset, opt.task) - opt = opts().update_dataset_info_and_set_heads(opt, Dataset) - if opt.local_rank ==0: - print(opt) - os.environ['MASTER_ADDR'] = '127.0.0.1' - os.environ['MASTER_PORT'] = opt.port - device_id = int(opt.device_list.split(',')[int(opt.local_rank)]) - opt.device = 'npu:{}'.format(device_id) - - torch.npu.set_device(opt.device) - - dist.init_process_group(backend='hccl', world_size=opt.world_size, rank=opt.local_rank) - print('process{},device:{}'.format(opt.local_rank,opt.device)) - print('Creating model...') - model = create_model(opt.arch, opt.heads, opt.head_conv) - model = model.to(opt.device) - if opt.pretrained: - checkpoint = torch.load(opt.pretrained_weight_path, map_location='cpu') - if 'module.' in list(checkpoint['state_dict'].keys())[0]: - checkpoint['state_dict'] = {k.replace('module.', ''): v for k, v in checkpoint['state_dict'].items()} - model.load_state_dict(checkpoint['state_dict'], strict=False) - - optimizer = torch.optim.Adam(model.parameters(), opt.lr) - model, optimizer = amp.initialize(model, optimizer, opt_level="O1",loss_scale=19.0) - start_epoch = 0 - if opt.load_model != '': - model, optimizer, start_epoch = load_model( - model, opt.load_model, optimizer, opt.resume, opt.lr, opt.lr_step) - print('start_epoch:{}'.format(start_epoch)) - Trainer = train_factory[opt.task] - trainer = Trainer(opt, model, optimizer) - trainer.set_device(opt.device_list, opt.chunk_sizes, opt.device) - print('Setting up data...') - train_sampler = torch.utils.data.distributed.DistributedSampler(Dataset(opt, 'train')) - train_loader = torch.utils.data.DataLoader( - Dataset(opt, 'train'), - batch_size=opt.batch_size, - shuffle=(train_sampler is None), - num_workers=opt.num_workers, - sampler=train_sampler, - pin_memory=True, - drop_last=True, - collate_fn=Multiposebatch - ) - - print('Starting training...') - best = 1e10 - for epoch in range(start_epoch + 1, opt.num_epochs + 1): - qtepoch.append(epoch) - train_sampler.set_epoch(epoch) - mark = epoch if opt.save_all else 'last' - log_dict_train, _ = trainer.train(epoch, train_loader) - if opt.local_rank == 0: - str1 ='epoch:{}|'.format(epoch) - for k, v in log_dict_train.items(): - str2 ='{} {:8f}|'.format(k,v) - str1 = str1 +str2 - print(str1) - if opt.val_intervals > 0 and epoch % opt.val_intervals == 0: - save_model(os.path.join(opt.save_dir, 'model_{}.pth'.format(mark)), - epoch, model, optimizer) - - print('best:{} metric:{} epotchs:{}'.format(best,log_dict_train[opt.metric],epoch)) - - if log_dict_train[opt.metric] < best: - best = log_dict_train[opt.metric] - save_model(os.path.join(opt.save_dir, 'model_best.pth'), - epoch, model) - else: - save_model(os.path.join(opt.save_dir, 'model_last.pth'), - epoch, model, optimizer) - - - if epoch in opt.lr_step: - - if opt.local_rank == 0: - save_model(os.path.join(opt.save_dir, 'model_{}.pth'.format(epoch)), epoch, model, optimizer) - lr = opt.lr * (0.1 ** (opt.lr_step.index(epoch) + 1)) - if opt.local_rank == 0: - print('Drop LR to', lr) - for param_group in optimizer.param_groups: - param_group['lr'] = lr - - -if __name__ == '__main__': - opt = opts().parse() - main(opt) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 _init_paths + +import os + +import torch +import torch.utils.data +from opts_pose import opts +from models.model import create_model, load_model, save_model +from models.data_parallel import DataParallel +from datasets.dataset_factory import get_dataset +from trains.train_factory import train_factory +from datasets.sample.multi_pose import Multiposebatch +from apex import amp +import torch.npu +import torch.distributed as dist +from torch.nn.parallel import DistributedDataParallel as DDP + + +def main(opt, qtepoch=[0,]): + + torch.manual_seed(opt.seed) + torch.backends.cudnn.benchmark = not opt.not_cuda_benchmark and not opt.test + Dataset = get_dataset(opt.dataset, opt.task) + opt = opts().update_dataset_info_and_set_heads(opt, Dataset) + if opt.local_rank ==0: + print(opt) + os.environ['MASTER_ADDR'] = '127.0.0.1' + os.environ['MASTER_PORT'] = opt.port + device_id = int(opt.device_list.split(',')[int(opt.local_rank)]) + opt.device = 'npu:{}'.format(device_id) + + torch.npu.set_device(opt.device) + + dist.init_process_group(backend='hccl', world_size=opt.world_size, rank=opt.local_rank) + print('process{},device:{}'.format(opt.local_rank,opt.device)) + print('Creating model...') + model = create_model(opt.arch, opt.heads, opt.head_conv) + model = model.to(opt.device) + if opt.pretrained: + checkpoint = torch.load(opt.pretrained_weight_path, map_location='cpu') + if 'module.' in list(checkpoint['state_dict'].keys())[0]: + checkpoint['state_dict'] = {k.replace('module.', ''): v for k, v in checkpoint['state_dict'].items()} + model.load_state_dict(checkpoint['state_dict'], strict=False) + + optimizer = torch.optim.Adam(model.parameters(), opt.lr) + model, optimizer = amp.initialize(model, optimizer, opt_level="O1",loss_scale=19.0) + start_epoch = 0 + if opt.load_model != '': + model, optimizer, start_epoch = load_model( + model, opt.load_model, optimizer, opt.resume, opt.lr, opt.lr_step) + print('start_epoch:{}'.format(start_epoch)) + Trainer = train_factory[opt.task] + trainer = Trainer(opt, model, optimizer) + trainer.set_device(opt.device_list, opt.chunk_sizes, opt.device) + print('Setting up data...') + train_sampler = torch.utils.data.distributed.DistributedSampler(Dataset(opt, 'train')) + train_loader = torch.utils.data.DataLoader( + Dataset(opt, 'train'), + batch_size=opt.batch_size, + shuffle=(train_sampler is None), + num_workers=opt.num_workers, + sampler=train_sampler, + pin_memory=True, + drop_last=True, + collate_fn=Multiposebatch + ) + + print('Starting training...') + best = 1e10 + for epoch in range(start_epoch + 1, opt.num_epochs + 1): + qtepoch.append(epoch) + train_sampler.set_epoch(epoch) + mark = epoch if opt.save_all else 'last' + log_dict_train, _ = trainer.train(epoch, train_loader) + if opt.local_rank == 0: + str1 ='epoch:{}|'.format(epoch) + for k, v in log_dict_train.items(): + str2 ='{} {:8f}|'.format(k,v) + str1 = str1 +str2 + print(str1) + if opt.val_intervals > 0 and epoch % opt.val_intervals == 0: + save_model(os.path.join(opt.save_dir, 'model_{}.pth'.format(mark)), + epoch, model, optimizer) + + print('best:{} metric:{} epotchs:{}'.format(best,log_dict_train[opt.metric],epoch)) + + if log_dict_train[opt.metric] < best: + best = log_dict_train[opt.metric] + save_model(os.path.join(opt.save_dir, 'model_best.pth'), + epoch, model) + else: + save_model(os.path.join(opt.save_dir, 'model_last.pth'), + epoch, model, optimizer) + + + if epoch in opt.lr_step: + + if opt.local_rank == 0: + save_model(os.path.join(opt.save_dir, 'model_{}.pth'.format(epoch)), epoch, model, optimizer) + lr = opt.lr * (0.1 ** (opt.lr_step.index(epoch) + 1)) + if opt.local_rank == 0: + print('Drop LR to', lr) + for param_group in optimizer.param_groups: + param_group['lr'] = lr + + +if __name__ == '__main__': + opt = opts().parse() + main(opt) diff --git a/PyTorch/contrib/cv/detection/CenterFace/src/test/env_npu.sh b/PyTorch/contrib/cv/detection/CenterFace/src/test/env_npu.sh index 0ea66b3bc6..2b12ee99de 100644 --- a/PyTorch/contrib/cv/detection/CenterFace/src/test/env_npu.sh +++ b/PyTorch/contrib/cv/detection/CenterFace/src/test/env_npu.sh @@ -1,68 +1,68 @@ -#!/bin/bash -export install_path=/usr/local/Ascend - -if [ -d ${install_path}/toolkit ]; then - export LD_LIBRARY_PATH=/usr/include/hdf5/lib/:/usr/local/:/usr/local/lib/:/usr/lib/:${install_path}/fwkacllib/lib64/:${install_path}/driver/lib64/common/:${install_path}/driver/lib64/driver/:${install_path}/add-ons:${path_lib}:${LD_LIBRARY_PATH} - export PATH=${install_path}/fwkacllib/ccec_compiler/bin:${install_path}/fwkacllib/bin:$PATH - export PYTHONPATH=${install_path}/fwkacllib/python/site-packages:${install_path}/tfplugin/python/site-packages:${install_path}/toolkit/python/site-packages:$PYTHONPATH - export PYTHONPATH=/usr/local/python3.7.5/lib/python3.7/site-packages:$PYTHONPATH - export ASCEND_OPP_PATH=${install_path}/opp -else - if [ -d ${install_path}/nnae/latest ];then - export LD_LIBRARY_PATH=/usr/local/:/usr/local/python3.7.5/lib/:/usr/local/openblas/lib:/usr/local/lib/:/usr/lib64/:/usr/lib/:${install_path}/nnae/latest/fwkacllib/lib64/:${install_path}/driver/lib64/common/:${install_path}/driver/lib64/driver/:${install_path}/add-ons/:/usr/lib/aarch64_64-linux-gnu:$LD_LIBRARY_PATH - export PATH=$PATH:${install_path}/nnae/latest/fwkacllib/ccec_compiler/bin/:${install_path}/nnae/latest/toolkit/tools/ide_daemon/bin/ - export ASCEND_OPP_PATH=${install_path}/nnae/latest/opp/ - export OPTION_EXEC_EXTERN_PLUGIN_PATH=${install_path}/nnae/latest/fwkacllib/lib64/plugin/opskernel/libfe.so:${install_path}/nnae/latest/fwkacllib/lib64/plugin/opskernel/libaicpu_engine.so:${install_path}/nnae/latest/fwkacllib/lib64/plugin/opskernel/libge_local_engine.so - export PYTHONPATH=${install_path}/nnae/latest/fwkacllib/python/site-packages/:${install_path}/nnae/latest/fwkacllib/python/site-packages/auto_tune.egg/auto_tune:${install_path}/nnae/latest/fwkacllib/python/site-packages/schedule_search.egg:$PYTHONPATH - export ASCEND_AICPU_PATH=${install_path}/nnae/latest - else - export LD_LIBRARY_PATH=/usr/local/:/usr/local/lib/:/usr/lib64/:/usr/lib/:/usr/local/python3.7.5/lib/:/usr/local/openblas/lib:${install_path}/ascend-toolkit/latest/fwkacllib/lib64/:${install_path}/driver/lib64/common/:${install_path}/driver/lib64/driver/:${install_path}/add-ons/:/usr/lib/aarch64-linux-gnu:$LD_LIBRARY_PATH - export PATH=$PATH:${install_path}/ascend-toolkit/latest/fwkacllib/ccec_compiler/bin/:${install_path}/ascend-toolkit/latest/toolkit/tools/ide_daemon/bin/ - export ASCEND_OPP_PATH=${install_path}/ascend-toolkit/latest/opp/ - export OPTION_EXEC_EXTERN_PLUGIN_PATH=${install_path}/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libfe.so:${install_path}/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libaicpu_engine.so:${install_path}/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libge_local_engine.so - export PYTHONPATH=${install_path}/ascend-toolkit/latest/fwkacllib/python/site-packages/:${install_path}/ascend-toolkit/latest/fwkacllib/python/site-packages/auto_tune.egg/auto_tune:${install_path}/ascend-toolkit/latest/fwkacllib/python/site-packages/schedule_search.egg:$PYTHONPATH - export ASCEND_AICPU_PATH=${install_path}/ascend-toolkit/latest - fi -fi - - -#将Host日志输出到串口,0-关闭/1-开启 -export ASCEND_SLOG_PRINT_TO_STDOUT=0 -#设置默认日志级别,0-debug/1-info/2-warning/3-error -export ASCEND_GLOBAL_LOG_LEVEL=3 -#设置Event日志开启标志,0-关闭/1-开启 -export ASCEND_GLOBAL_EVENT_ENABLE=0 -#设置是否开启taskque,0-关闭/1-开启 -export TASK_QUEUE_ENABLE=1 -#设置是否开启PTCopy,0-关闭/1-开启 -export PTCOPY_ENABLE=1 -#设置是否开启combined标志,0-关闭/1-开启 -export COMBINED_ENABLE=1 -#设置特殊场景是否需要重新编译,不需要修改 -export DYNAMIC_OP="ADD#MUL" -#HCCL白名单开关,1-关闭/0-开启 -export HCCL_WHITELIST_DISABLE=1 -export HCCL_IF_IP=$(hostname -I |awk '{print $1}') - -ulimit -SHn 512000 - -path_lib=$(python3.7 -c """ -import sys -import re -result='' -for index in range(len(sys.path)): - match_sit = re.search('-packages', sys.path[index]) - if match_sit is not None: - match_lib = re.search('lib', sys.path[index]) - - if match_lib is not None: - end=match_lib.span()[1] - result += sys.path[index][0:end] + ':' - - result+=sys.path[index] + '/torch/lib:' -print(result)""" -) - -echo ${path_lib} - -export LD_LIBRARY_PATH=/usr/local/python3.7.5/lib/:${path_lib}:$LD_LIBRARY_PATH +#!/bin/bash +export install_path=/usr/local/Ascend + +if [ -d ${install_path}/toolkit ]; then + export LD_LIBRARY_PATH=/usr/include/hdf5/lib/:/usr/local/:/usr/local/lib/:/usr/lib/:${install_path}/fwkacllib/lib64/:${install_path}/driver/lib64/common/:${install_path}/driver/lib64/driver/:${install_path}/add-ons:${path_lib}:${LD_LIBRARY_PATH} + export PATH=${install_path}/fwkacllib/ccec_compiler/bin:${install_path}/fwkacllib/bin:$PATH + export PYTHONPATH=${install_path}/fwkacllib/python/site-packages:${install_path}/tfplugin/python/site-packages:${install_path}/toolkit/python/site-packages:$PYTHONPATH + export PYTHONPATH=/usr/local/python3.7.5/lib/python3.7/site-packages:$PYTHONPATH + export ASCEND_OPP_PATH=${install_path}/opp +else + if [ -d ${install_path}/nnae/latest ];then + export LD_LIBRARY_PATH=/usr/local/:/usr/local/python3.7.5/lib/:/usr/local/openblas/lib:/usr/local/lib/:/usr/lib64/:/usr/lib/:${install_path}/nnae/latest/fwkacllib/lib64/:${install_path}/driver/lib64/common/:${install_path}/driver/lib64/driver/:${install_path}/add-ons/:/usr/lib/aarch64_64-linux-gnu:$LD_LIBRARY_PATH + export PATH=$PATH:${install_path}/nnae/latest/fwkacllib/ccec_compiler/bin/:${install_path}/nnae/latest/toolkit/tools/ide_daemon/bin/ + export ASCEND_OPP_PATH=${install_path}/nnae/latest/opp/ + export OPTION_EXEC_EXTERN_PLUGIN_PATH=${install_path}/nnae/latest/fwkacllib/lib64/plugin/opskernel/libfe.so:${install_path}/nnae/latest/fwkacllib/lib64/plugin/opskernel/libaicpu_engine.so:${install_path}/nnae/latest/fwkacllib/lib64/plugin/opskernel/libge_local_engine.so + export PYTHONPATH=${install_path}/nnae/latest/fwkacllib/python/site-packages/:${install_path}/nnae/latest/fwkacllib/python/site-packages/auto_tune.egg/auto_tune:${install_path}/nnae/latest/fwkacllib/python/site-packages/schedule_search.egg:$PYTHONPATH + export ASCEND_AICPU_PATH=${install_path}/nnae/latest + else + export LD_LIBRARY_PATH=/usr/local/:/usr/local/lib/:/usr/lib64/:/usr/lib/:/usr/local/python3.7.5/lib/:/usr/local/openblas/lib:${install_path}/ascend-toolkit/latest/fwkacllib/lib64/:${install_path}/driver/lib64/common/:${install_path}/driver/lib64/driver/:${install_path}/add-ons/:/usr/lib/aarch64-linux-gnu:$LD_LIBRARY_PATH + export PATH=$PATH:${install_path}/ascend-toolkit/latest/fwkacllib/ccec_compiler/bin/:${install_path}/ascend-toolkit/latest/toolkit/tools/ide_daemon/bin/ + export ASCEND_OPP_PATH=${install_path}/ascend-toolkit/latest/opp/ + export OPTION_EXEC_EXTERN_PLUGIN_PATH=${install_path}/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libfe.so:${install_path}/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libaicpu_engine.so:${install_path}/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libge_local_engine.so + export PYTHONPATH=${install_path}/ascend-toolkit/latest/fwkacllib/python/site-packages/:${install_path}/ascend-toolkit/latest/fwkacllib/python/site-packages/auto_tune.egg/auto_tune:${install_path}/ascend-toolkit/latest/fwkacllib/python/site-packages/schedule_search.egg:$PYTHONPATH + export ASCEND_AICPU_PATH=${install_path}/ascend-toolkit/latest + fi +fi + + +#将Host日志输出到串口,0-关闭/1-开启 +export ASCEND_SLOG_PRINT_TO_STDOUT=0 +#设置默认日志级别,0-debug/1-info/2-warning/3-error +export ASCEND_GLOBAL_LOG_LEVEL=3 +#设置Event日志开启标志,0-关闭/1-开启 +export ASCEND_GLOBAL_EVENT_ENABLE=0 +#设置是否开启taskque,0-关闭/1-开启 +export TASK_QUEUE_ENABLE=1 +#设置是否开启PTCopy,0-关闭/1-开启 +export PTCOPY_ENABLE=1 +#设置是否开启combined标志,0-关闭/1-开启 +export COMBINED_ENABLE=1 +#设置特殊场景是否需要重新编译,不需要修改 +export DYNAMIC_OP="ADD#MUL" +#HCCL白名单开关,1-关闭/0-开启 +export HCCL_WHITELIST_DISABLE=1 +export HCCL_IF_IP=$(hostname -I |awk '{print $1}') + +ulimit -SHn 512000 + +path_lib=$(python3.7 -c """ +import sys +import re +result='' +for index in range(len(sys.path)): + match_sit = re.search('-packages', sys.path[index]) + if match_sit is not None: + match_lib = re.search('lib', sys.path[index]) + + if match_lib is not None: + end=match_lib.span()[1] + result += sys.path[index][0:end] + ':' + + result+=sys.path[index] + '/torch/lib:' +print(result)""" +) + +echo ${path_lib} + +export LD_LIBRARY_PATH=/usr/local/python3.7.5/lib/:${path_lib}:$LD_LIBRARY_PATH diff --git a/PyTorch/contrib/cv/detection/CenterNet/modelzoo_level.txt b/PyTorch/contrib/cv/detection/CenterNet/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/detection/CenterNet/modelzoo_level.txt +++ b/PyTorch/contrib/cv/detection/CenterNet/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/CenterNet/src/lib/detectors/base_detector.py b/PyTorch/contrib/cv/detection/CenterNet/src/lib/detectors/base_detector.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/CenterNet/src/lib/detectors/ctdet.py b/PyTorch/contrib/cv/detection/CenterNet/src/lib/detectors/ctdet.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/CenterNet/src/lib/detectors/ddd.py b/PyTorch/contrib/cv/detection/CenterNet/src/lib/detectors/ddd.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/CenterNet/src/lib/detectors/exdet.py b/PyTorch/contrib/cv/detection/CenterNet/src/lib/detectors/exdet.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/CenterNet/src/lib/detectors/multi_pose.py b/PyTorch/contrib/cv/detection/CenterNet/src/lib/detectors/multi_pose.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/CenterNet/src/lib/models/networks/DCNv2/make.sh b/PyTorch/contrib/cv/detection/CenterNet/src/lib/models/networks/DCNv2/make.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/CenterNet/src/lib/models/networks/dcn/modules/deform_conv.py b/PyTorch/contrib/cv/detection/CenterNet/src/lib/models/networks/dcn/modules/deform_conv.py index 7850c278e6..4c1f102339 100644 --- a/PyTorch/contrib/cv/detection/CenterNet/src/lib/models/networks/dcn/modules/deform_conv.py +++ b/PyTorch/contrib/cv/detection/CenterNet/src/lib/models/networks/dcn/modules/deform_conv.py @@ -1,235 +1,235 @@ -# Copyright (c) 2020, Huawei Technologies.All rights reserved. -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 torch -import torch.nn as nn -from torch.autograd import Function -from torch.nn.modules.utils import _pair, _single -import math - - -class ModulatedDeformConv2dFunction(Function): - - @staticmethod - def forward(ctx, - input_tensor, - offset_ori, - mask, - weight, - bias=None, - with_bias=False, - stride=1, - padding=0, - dilation=1, - groups=1, - deformable_groups=1, - sort_index_for_npu_fp=None, - sort_index_for_npu_bp=None, - ): - - input_tensor = input_tensor.float() - offset_ori = offset_ori.float() - mask = mask.float() - - ctx.stride = stride - ctx.padding = padding - ctx.dilation = dilation - ctx.groups = groups - ctx.deformable_groups = deformable_groups - ctx.sort_index_for_npu_bp = sort_index_for_npu_bp - ctx.with_bias = with_bias - - offset = offset_ori.index_select(1, sort_index_for_npu_fp) - offset_all = torch.cat([offset, mask], dim=1) - output, offset_out = torch.npu_deformable_conv2d( - input_tensor, weight, offset_all, bias, - kernel_size=[weight.shape[3], weight.shape[2]], - stride=[1, 1, ctx.stride, ctx.stride], - padding=[ctx.padding, ctx.padding, ctx.padding, ctx.padding], - dilation=[1, 1, ctx.dilation, ctx.dilation], - groups=ctx.groups, deformable_groups=ctx.deformable_groups, - modulated=True) - if weight.requires_grad or mask.requires_grad or offset.requires_grad \ - or input_tensor.requires_grad: - ctx.save_for_backward(input_tensor, weight, offset_out, offset_all) - return output - - @staticmethod - def backward(ctx, grad_output): - input_tensor, weight, offset_out, offset_all = ctx.saved_tensors - grad_input, grad_weight, grad_offset_all, grad_bias = torch.npu_deformable_conv2dbk( - input_tensor, grad_output, offset_out, weight, offset_all, - kernel_size=[weight.shape[3], weight.shape[2]], - stride=[1, 1, ctx.stride, ctx.stride], - padding=[ctx.padding, ctx.padding, ctx.padding, ctx.padding], - dilation=[1, 1, ctx.dilation, ctx.dilation], - groups=ctx.groups, deformable_groups=ctx.deformable_groups, modulated=True) - grad_offset = grad_offset_all.index_select(1, ctx.sort_index_for_npu_bp) - grad_mask = grad_offset_all[:, grad_offset.shape[1]:, :, :] - if not ctx.with_bias: - grad_bias = None - - return (grad_input, grad_offset, grad_mask, grad_weight, grad_bias, - None, None, None, None, None, None, None, None) - - -class ModulatedDeformConv(nn.Module): - - def __init__(self, - in_channels, - out_channels, - kernel_size, - stride=1, - padding=0, - dilation=1, - groups=1, - deformable_groups=1, - bias=True, - pack=True, - ): - - r"""Applies an NPU based Modulated Deformable 2D convolution operation. - - Paper link: - [Deformable ConvNets v2: More Deformable, Better Results](https://arxiv.org/abs/1811.11168) - - Reference implementation link: - https://github.com/open-mmlab/mmcv/blob/master/mmcv/ops/modulated_deform_conv.py - - The implementation of this ModulatedDeformConv is mainly based - on the implementation of mmcv for design and reconstruction. - Through the modular ModulatedDeformConvFunction, the forward and reverse are customized, - and the input is reconstructed in combination with the NPU underlying operator IR, - and finally the function is completed. - - It is worth mentioning that deformconv (DCNv1) is also implemented - by setting modulated = False. Due to the difference between input - and initialization, there is no additional implementation here. - - - .. note:: - ModulatedDeformConv only implements operations under fp32 data types. - Notice, conv_ Weight and bias of offset must be initialized to 0. - - Args: - in_channels (int): Number of channels in the input image. - out_channels (int): Number of channels produced by the convolution. - kernel_size(int, tuple): Size of the convolving kernel. - stride(int, tuple): Stride of the convolution. Default: 1. - padding (int or tuple): Zero-padding added to both sides of the input. - Default: 0. - dilation (int or tuple): Spacing between kernel elements. Default: 1. - groups (int): Number of blocked connections from input. - channels to output channels. Default: 1. - deform_groups (int): Number of deformable group partitions. - bias (bool): If True, adds a learnable bias to the output. Default: False. - pack (bool): If True, conv_offset and mask will be included in this module. Default: True. - - Examples:: - >>> m = ModulatedDeformConv(32, 32, 1) - >>> input_tensor = torch.randn(2, 32, 5, 5) - >>> output = m(input_tensor) - """ - - super(ModulatedDeformConv, self).__init__() - - self.in_channels = in_channels - self.out_channels = out_channels - self.kernel_size = _pair(kernel_size) - self.stride = stride - self.padding = padding - self.dilation = dilation - self.groups = groups - self.deformable_groups = deformable_groups - self.with_bias = bias - self.pack = pack - - self.weight = nn.Parameter( - torch.Tensor(out_channels, in_channels // groups, *self.kernel_size)) - if bias: - self.bias = nn.Parameter(torch.Tensor(out_channels)) - else: - self.bias = torch.zeros(self.weight.shape[0]) - - if self.pack: - self.conv_offset = nn.Conv2d( - self.in_channels, - self.deformable_groups * 3 * self.kernel_size[0] * - self.kernel_size[1], - kernel_size=self.kernel_size, - stride=_pair(self.stride), - padding=_pair(self.padding), - bias=True) - - self.split_num = self.deformable_groups * 2 * self.kernel_size[0] * self.kernel_size[1] - sort_index_for_npu = list(range(self.split_num)) - sort_index_for_npu_fp = sort_index_for_npu[1::2] + sort_index_for_npu[::2] - sort_index_for_npu_bp_dict = {i: idx for idx, i in enumerate(sort_index_for_npu_fp)} - sort_index_for_npu_bp = [sort_index_for_npu_bp_dict[i] for i in sort_index_for_npu] - self.sort_index_for_npu_fp = torch.IntTensor(sort_index_for_npu_fp) - self.sort_index_for_npu_bp = torch.IntTensor(sort_index_for_npu_bp) - self.sort_index_for_npu_todevice = False - - self.init_param() - - def init_param(self): - n = self.in_channels - for k in self.kernel_size: - n *= k - stdv = 1. / math.sqrt(n) - self.weight.data.uniform_(-stdv, stdv) - if self.bias is not None: - self.bias.data.zero_() - - if self.pack: - self.conv_offset.weight.data.zero_() - self.conv_offset.bias.data.zero_() - - def forward(self, x): - if self.pack: - out = self.conv_offset(x) - offset = out[:, :self.split_num, ...] - mask = torch.sigmoid(out[:, self.split_num:, ...]) - else: - x, offset, mask = x - - if not self.sort_index_for_npu_todevice: - self.sort_index_for_npu_fp = self.sort_index_for_npu_fp.to(x.device) - self.sort_index_for_npu_bp = self.sort_index_for_npu_bp.to(x.device) - self.bias = self.bias.to(x.device) - self.sort_index_for_npu_todevice = True - - return ModulatedDeformConv2dFunction.apply( - x, offset, mask, self.weight, self.bias, self.with_bias, - self.stride, self.padding, self.dilation, - self.groups, self.deformable_groups, - self.sort_index_for_npu_fp, - self.sort_index_for_npu_bp, - ) - - -DCNv2 = ModulatedDeformConv - -if __name__ == "__main__": - x = torch.randn(2, 32, 7, 7) - model = DCNv2(32, 32, 3, 2, 1) - - torch.npu.set_device(0) - x = x.npu() - model = model.npu() - - o = model(x) - l = o.sum() - l.backward() - print(l) +# Copyright (c) 2020, Huawei Technologies.All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 torch +import torch.nn as nn +from torch.autograd import Function +from torch.nn.modules.utils import _pair, _single +import math + + +class ModulatedDeformConv2dFunction(Function): + + @staticmethod + def forward(ctx, + input_tensor, + offset_ori, + mask, + weight, + bias=None, + with_bias=False, + stride=1, + padding=0, + dilation=1, + groups=1, + deformable_groups=1, + sort_index_for_npu_fp=None, + sort_index_for_npu_bp=None, + ): + + input_tensor = input_tensor.float() + offset_ori = offset_ori.float() + mask = mask.float() + + ctx.stride = stride + ctx.padding = padding + ctx.dilation = dilation + ctx.groups = groups + ctx.deformable_groups = deformable_groups + ctx.sort_index_for_npu_bp = sort_index_for_npu_bp + ctx.with_bias = with_bias + + offset = offset_ori.index_select(1, sort_index_for_npu_fp) + offset_all = torch.cat([offset, mask], dim=1) + output, offset_out = torch.npu_deformable_conv2d( + input_tensor, weight, offset_all, bias, + kernel_size=[weight.shape[3], weight.shape[2]], + stride=[1, 1, ctx.stride, ctx.stride], + padding=[ctx.padding, ctx.padding, ctx.padding, ctx.padding], + dilation=[1, 1, ctx.dilation, ctx.dilation], + groups=ctx.groups, deformable_groups=ctx.deformable_groups, + modulated=True) + if weight.requires_grad or mask.requires_grad or offset.requires_grad \ + or input_tensor.requires_grad: + ctx.save_for_backward(input_tensor, weight, offset_out, offset_all) + return output + + @staticmethod + def backward(ctx, grad_output): + input_tensor, weight, offset_out, offset_all = ctx.saved_tensors + grad_input, grad_weight, grad_offset_all, grad_bias = torch.npu_deformable_conv2dbk( + input_tensor, grad_output, offset_out, weight, offset_all, + kernel_size=[weight.shape[3], weight.shape[2]], + stride=[1, 1, ctx.stride, ctx.stride], + padding=[ctx.padding, ctx.padding, ctx.padding, ctx.padding], + dilation=[1, 1, ctx.dilation, ctx.dilation], + groups=ctx.groups, deformable_groups=ctx.deformable_groups, modulated=True) + grad_offset = grad_offset_all.index_select(1, ctx.sort_index_for_npu_bp) + grad_mask = grad_offset_all[:, grad_offset.shape[1]:, :, :] + if not ctx.with_bias: + grad_bias = None + + return (grad_input, grad_offset, grad_mask, grad_weight, grad_bias, + None, None, None, None, None, None, None, None) + + +class ModulatedDeformConv(nn.Module): + + def __init__(self, + in_channels, + out_channels, + kernel_size, + stride=1, + padding=0, + dilation=1, + groups=1, + deformable_groups=1, + bias=True, + pack=True, + ): + + r"""Applies an NPU based Modulated Deformable 2D convolution operation. + + Paper link: + [Deformable ConvNets v2: More Deformable, Better Results](https://arxiv.org/abs/1811.11168) + + Reference implementation link: + https://github.com/open-mmlab/mmcv/blob/master/mmcv/ops/modulated_deform_conv.py + + The implementation of this ModulatedDeformConv is mainly based + on the implementation of mmcv for design and reconstruction. + Through the modular ModulatedDeformConvFunction, the forward and reverse are customized, + and the input is reconstructed in combination with the NPU underlying operator IR, + and finally the function is completed. + + It is worth mentioning that deformconv (DCNv1) is also implemented + by setting modulated = False. Due to the difference between input + and initialization, there is no additional implementation here. + + + .. note:: + ModulatedDeformConv only implements operations under fp32 data types. + Notice, conv_ Weight and bias of offset must be initialized to 0. + + Args: + in_channels (int): Number of channels in the input image. + out_channels (int): Number of channels produced by the convolution. + kernel_size(int, tuple): Size of the convolving kernel. + stride(int, tuple): Stride of the convolution. Default: 1. + padding (int or tuple): Zero-padding added to both sides of the input. + Default: 0. + dilation (int or tuple): Spacing between kernel elements. Default: 1. + groups (int): Number of blocked connections from input. + channels to output channels. Default: 1. + deform_groups (int): Number of deformable group partitions. + bias (bool): If True, adds a learnable bias to the output. Default: False. + pack (bool): If True, conv_offset and mask will be included in this module. Default: True. + + Examples:: + >>> m = ModulatedDeformConv(32, 32, 1) + >>> input_tensor = torch.randn(2, 32, 5, 5) + >>> output = m(input_tensor) + """ + + super(ModulatedDeformConv, self).__init__() + + self.in_channels = in_channels + self.out_channels = out_channels + self.kernel_size = _pair(kernel_size) + self.stride = stride + self.padding = padding + self.dilation = dilation + self.groups = groups + self.deformable_groups = deformable_groups + self.with_bias = bias + self.pack = pack + + self.weight = nn.Parameter( + torch.Tensor(out_channels, in_channels // groups, *self.kernel_size)) + if bias: + self.bias = nn.Parameter(torch.Tensor(out_channels)) + else: + self.bias = torch.zeros(self.weight.shape[0]) + + if self.pack: + self.conv_offset = nn.Conv2d( + self.in_channels, + self.deformable_groups * 3 * self.kernel_size[0] * + self.kernel_size[1], + kernel_size=self.kernel_size, + stride=_pair(self.stride), + padding=_pair(self.padding), + bias=True) + + self.split_num = self.deformable_groups * 2 * self.kernel_size[0] * self.kernel_size[1] + sort_index_for_npu = list(range(self.split_num)) + sort_index_for_npu_fp = sort_index_for_npu[1::2] + sort_index_for_npu[::2] + sort_index_for_npu_bp_dict = {i: idx for idx, i in enumerate(sort_index_for_npu_fp)} + sort_index_for_npu_bp = [sort_index_for_npu_bp_dict[i] for i in sort_index_for_npu] + self.sort_index_for_npu_fp = torch.IntTensor(sort_index_for_npu_fp) + self.sort_index_for_npu_bp = torch.IntTensor(sort_index_for_npu_bp) + self.sort_index_for_npu_todevice = False + + self.init_param() + + def init_param(self): + n = self.in_channels + for k in self.kernel_size: + n *= k + stdv = 1. / math.sqrt(n) + self.weight.data.uniform_(-stdv, stdv) + if self.bias is not None: + self.bias.data.zero_() + + if self.pack: + self.conv_offset.weight.data.zero_() + self.conv_offset.bias.data.zero_() + + def forward(self, x): + if self.pack: + out = self.conv_offset(x) + offset = out[:, :self.split_num, ...] + mask = torch.sigmoid(out[:, self.split_num:, ...]) + else: + x, offset, mask = x + + if not self.sort_index_for_npu_todevice: + self.sort_index_for_npu_fp = self.sort_index_for_npu_fp.to(x.device) + self.sort_index_for_npu_bp = self.sort_index_for_npu_bp.to(x.device) + self.bias = self.bias.to(x.device) + self.sort_index_for_npu_todevice = True + + return ModulatedDeformConv2dFunction.apply( + x, offset, mask, self.weight, self.bias, self.with_bias, + self.stride, self.padding, self.dilation, + self.groups, self.deformable_groups, + self.sort_index_for_npu_fp, + self.sort_index_for_npu_bp, + ) + + +DCNv2 = ModulatedDeformConv + +if __name__ == "__main__": + x = torch.randn(2, 32, 7, 7) + model = DCNv2(32, 32, 3, 2, 1) + + torch.npu.set_device(0) + x = x.npu() + model = model.npu() + + o = model(x) + l = o.sum() + l.backward() + print(l) diff --git a/PyTorch/contrib/cv/detection/CenterNet/src/lib/opts.py b/PyTorch/contrib/cv/detection/CenterNet/src/lib/opts.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/CenterNet/src/lib/trains/base_trainer.py b/PyTorch/contrib/cv/detection/CenterNet/src/lib/trains/base_trainer.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/CenterNet/src/lib/trains/ctdet.py b/PyTorch/contrib/cv/detection/CenterNet/src/lib/trains/ctdet.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/CenterNet/src/lib/trains/ddd.py b/PyTorch/contrib/cv/detection/CenterNet/src/lib/trains/ddd.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/CenterNet/src/lib/trains/exdet.py b/PyTorch/contrib/cv/detection/CenterNet/src/lib/trains/exdet.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/CenterNet/src/lib/trains/multi_pose.py b/PyTorch/contrib/cv/detection/CenterNet/src/lib/trains/multi_pose.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/CenterNet/src/lib/utils/__init__.py b/PyTorch/contrib/cv/detection/CenterNet/src/lib/utils/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/CenterNet/src/lib/utils/image.py b/PyTorch/contrib/cv/detection/CenterNet/src/lib/utils/image.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/CenterNet/src/main.py b/PyTorch/contrib/cv/detection/CenterNet/src/main.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/CenterNet/src/test.py b/PyTorch/contrib/cv/detection/CenterNet/src/test.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/CenterNet/src/tools/reval.py b/PyTorch/contrib/cv/detection/CenterNet/src/tools/reval.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/CenterNet/test/modelzoo_level.txt b/PyTorch/contrib/cv/detection/CenterNet/test/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/detection/CenterNet/test/modelzoo_level.txt +++ b/PyTorch/contrib/cv/detection/CenterNet/test/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/FCOS/README_raw.md b/PyTorch/contrib/cv/detection/FCOS/README_raw.md index 7cdac786fa..bdbd3e957f 100644 --- a/PyTorch/contrib/cv/detection/FCOS/README_raw.md +++ b/PyTorch/contrib/cv/detection/FCOS/README_raw.md @@ -1,130 +1,130 @@ -# Fcos - -This implements training of Fcos on the Coco dataset, mainly modified from [pytorch/examples](https://github.com/open-mmlab/mmdetection). - -## Fcos Detail - -As of the current date, Ascend-Pytorch is still inefficient for contiguous operations. -Therefore, Fcos is re-implemented by changing mmdet and mmcv . - - -## Requirements - -- NPU配套的run包安装 -- Python 3.7.5 -- PyTorch(NPU版本) -- apex(NPU版本) - -### Document and data preparation -1. 下载压缩modelzoo\contrib\PyTorch\cv\image_object_detection\Fcos文件夹 -2. 于npu服务器解压Fcos压缩包 -3. 下载coco数据集 -4. 将coco数据集放于Fcos/data目录下 - -### Download and modify mmcv -1. 下载mmcv,最好是1.2.7版本的(版本要求是1.2.5以上,1.3.0以下) -``` -git clone -b v1.2.7 git://github.com/open-mmlab/mmcv.git -``` -2. 用mmcv_need里的文件替换mmcv中对应的文件 -``` -cp -f mmcv_need/_functions.py ../mmcv/mmcv/parallel/ -cp -f mmcv_need/builder.py ../mmcv/mmcv/runner/optimizer/ -cp -f mmcv_need/distributed.py ../mmcv/mmcv/parallel/ -cp -f mmcv_need/data_parallel.py ../mmcv/mmcv/parallel/ -cp -f mmcv_need/dist_utils.py ../mmcv/mmcv/runner/ -cp -f mmcv_need/optimizer.py ../mmcv/mmcv/runner/hooks/ -cp -f mmcv_need/checkpoint.py ../mmcv/mmcv/runner/ -``` -3. 以下三个文件的替换是为了在log中打印出FPS的信息,替换与否对模型训练无影响 -``` -cp -f mmcv_need/iter_timer.py ../mmcv/mmcv/runner/hooks/ -cp -f mmcv_need/base_runner.py ../mmcv/mmcv/runner/ -cp -f mmcv_need/epoch_based_runner.py ../mmcv/mmcv/runner/ -``` -### Configure the environment -1. 推荐使用conda管理 -``` -conda create -n fcos --clone env # 复制一个已经包含依赖包的环境 -conda activate fcos -``` -2. 配置安装mmcv -``` -cd mmcv -export MMCV_WITH_OPS=1 -export MAX_JOBS=8 -python3.7 setup.py build_ext -python3.7 setup.py develop -pip3 list | grep mmcv # 查看版本和路径 -``` -3. 配置安装mmdet -``` -cd Fcos -pip3 install -r requirements/build.txt -python3.7 setup.py develop -pip3 list | grep mmdet # 查看版本和路径 -``` -4. 修改apex中的113行,主要是为了支持O1,参考路径root/archiconda3/envs/fcos/lib/python3.7/site-packages/apex/amp/utils.py -``` -if cached_x.grad_fn.next_functions[1][0].variable is not x: -``` -改成 -``` -if cached_x.grad_fn.next_functions[0][0].variable is not x: -``` -## Train MODEL - -### 进入Fcos文件夹下 -``` -cd FCOS -``` - -### 1p -导入环境变量,修改train_1p.sh权限并运行 -``` -chmod +x ./scripts/train_1p.sh -bash ./scripts/train_1p.sh -``` - -### 8p -导入环境变量,修改train_8p.sh权限并运行 -``` -chmod +x ./scripts/train_8p.sh -bash ./scripts/train_8p.sh -``` - -### Eval -修改eval.sh权限并运行 -``` -chmod +x ./scripts/eval.sh -bash ./scripts/eval.sh -``` - -### 单p推理 -1. 运行demo.py -``` -python3.7 demo.py xxx.pth -``` - - -### 导出onnx -1. 下载mmdetection2.11,在文件夹下重新编译 -``` -git clone -b v2.11.0 https://github.com/open-mmlab/mmdetection.git -cd mmdetection -python3.7 setup.py develop -``` -2. 运行pthtar2onx.py -``` -python3.7 pthtar2onx.py -``` - - -## Fcos training result - -| Acc@1 | FPS | Npu/Gpu_nums | Epochs | AMP_Type | Loss_Scale | -| :------: | :------: | :------: | :------: | :------: | :------: | -| 12.6 | 19.2 | 1p Gpu | 1 | O1 | dynamic | -| 36.2 | 102.0 | 8p Gpu | 12 | O1 | dynamic | -| 16.4 | 6.8 | 1p Npu | 1 | O1 | 32.0 | -| 36.2 | 19.4 | 8p Npu | 12 | O1 | 32.0 | +# Fcos + +This implements training of Fcos on the Coco dataset, mainly modified from [pytorch/examples](https://github.com/open-mmlab/mmdetection). + +## Fcos Detail + +As of the current date, Ascend-Pytorch is still inefficient for contiguous operations. +Therefore, Fcos is re-implemented by changing mmdet and mmcv . + + +## Requirements + +- NPU配套的run包安装 +- Python 3.7.5 +- PyTorch(NPU版本) +- apex(NPU版本) + +### Document and data preparation +1. 下载压缩modelzoo\contrib\PyTorch\cv\image_object_detection\Fcos文件夹 +2. 于npu服务器解压Fcos压缩包 +3. 下载coco数据集 +4. 将coco数据集放于Fcos/data目录下 + +### Download and modify mmcv +1. 下载mmcv,最好是1.2.7版本的(版本要求是1.2.5以上,1.3.0以下) +``` +git clone -b v1.2.7 git://github.com/open-mmlab/mmcv.git +``` +2. 用mmcv_need里的文件替换mmcv中对应的文件 +``` +cp -f mmcv_need/_functions.py ../mmcv/mmcv/parallel/ +cp -f mmcv_need/builder.py ../mmcv/mmcv/runner/optimizer/ +cp -f mmcv_need/distributed.py ../mmcv/mmcv/parallel/ +cp -f mmcv_need/data_parallel.py ../mmcv/mmcv/parallel/ +cp -f mmcv_need/dist_utils.py ../mmcv/mmcv/runner/ +cp -f mmcv_need/optimizer.py ../mmcv/mmcv/runner/hooks/ +cp -f mmcv_need/checkpoint.py ../mmcv/mmcv/runner/ +``` +3. 以下三个文件的替换是为了在log中打印出FPS的信息,替换与否对模型训练无影响 +``` +cp -f mmcv_need/iter_timer.py ../mmcv/mmcv/runner/hooks/ +cp -f mmcv_need/base_runner.py ../mmcv/mmcv/runner/ +cp -f mmcv_need/epoch_based_runner.py ../mmcv/mmcv/runner/ +``` +### Configure the environment +1. 推荐使用conda管理 +``` +conda create -n fcos --clone env # 复制一个已经包含依赖包的环境 +conda activate fcos +``` +2. 配置安装mmcv +``` +cd mmcv +export MMCV_WITH_OPS=1 +export MAX_JOBS=8 +python3.7 setup.py build_ext +python3.7 setup.py develop +pip3 list | grep mmcv # 查看版本和路径 +``` +3. 配置安装mmdet +``` +cd Fcos +pip3 install -r requirements/build.txt +python3.7 setup.py develop +pip3 list | grep mmdet # 查看版本和路径 +``` +4. 修改apex中的113行,主要是为了支持O1,参考路径root/archiconda3/envs/fcos/lib/python3.7/site-packages/apex/amp/utils.py +``` +if cached_x.grad_fn.next_functions[1][0].variable is not x: +``` +改成 +``` +if cached_x.grad_fn.next_functions[0][0].variable is not x: +``` +## Train MODEL + +### 进入Fcos文件夹下 +``` +cd FCOS +``` + +### 1p +导入环境变量,修改train_1p.sh权限并运行 +``` +chmod +x ./scripts/train_1p.sh +bash ./scripts/train_1p.sh +``` + +### 8p +导入环境变量,修改train_8p.sh权限并运行 +``` +chmod +x ./scripts/train_8p.sh +bash ./scripts/train_8p.sh +``` + +### Eval +修改eval.sh权限并运行 +``` +chmod +x ./scripts/eval.sh +bash ./scripts/eval.sh +``` + +### 单p推理 +1. 运行demo.py +``` +python3.7 demo.py xxx.pth +``` + + +### 导出onnx +1. 下载mmdetection2.11,在文件夹下重新编译 +``` +git clone -b v2.11.0 https://github.com/open-mmlab/mmdetection.git +cd mmdetection +python3.7 setup.py develop +``` +2. 运行pthtar2onx.py +``` +python3.7 pthtar2onx.py +``` + + +## Fcos training result + +| Acc@1 | FPS | Npu/Gpu_nums | Epochs | AMP_Type | Loss_Scale | +| :------: | :------: | :------: | :------: | :------: | :------: | +| 12.6 | 19.2 | 1p Gpu | 1 | O1 | dynamic | +| 36.2 | 102.0 | 8p Gpu | 12 | O1 | dynamic | +| 16.4 | 6.8 | 1p Npu | 1 | O1 | 32.0 | +| 36.2 | 19.4 | 8p Npu | 12 | O1 | 32.0 | diff --git a/PyTorch/contrib/cv/detection/FCOS/infer/convert/fcos_aipp.cfg b/PyTorch/contrib/cv/detection/FCOS/infer/convert/fcos_aipp.cfg index 6ad5dc2c59..73eb52fe14 100644 --- a/PyTorch/contrib/cv/detection/FCOS/infer/convert/fcos_aipp.cfg +++ b/PyTorch/contrib/cv/detection/FCOS/infer/convert/fcos_aipp.cfg @@ -1,16 +1,16 @@ -aipp_op { - aipp_mode: static - input_format: RGB888_U8 - related_input_rank: 0 - csc_switch: false - rbuv_swap_switch: false - - mean_chn_0: 103 - mean_chn_1: 116 - mean_chn_2: 123 - var_reci_chn_0: 1.0 - var_reci_chn_1: 1.0 - var_reci_chn_2: 1.0 - - -} +aipp_op { + aipp_mode: static + input_format: RGB888_U8 + related_input_rank: 0 + csc_switch: false + rbuv_swap_switch: false + + mean_chn_0: 103 + mean_chn_1: 116 + mean_chn_2: 123 + var_reci_chn_0: 1.0 + var_reci_chn_1: 1.0 + var_reci_chn_2: 1.0 + + +} diff --git a/PyTorch/contrib/cv/detection/FCOS/infer/docker_start_infer.sh b/PyTorch/contrib/cv/detection/FCOS/infer/docker_start_infer.sh index 07b61defd1..022ff22296 100644 --- a/PyTorch/contrib/cv/detection/FCOS/infer/docker_start_infer.sh +++ b/PyTorch/contrib/cv/detection/FCOS/infer/docker_start_infer.sh @@ -1,48 +1,48 @@ -#!/bin/bash - -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -docker_image=$1 -data_dir=$2 - -function show_help() { - echo "Usage: docker_start.sh docker_image data_dir" -} - -function param_check() { - if [ -z "${docker_image}" ]; then - echo "please input docker_image" - show_help - exit 1 - fi - - if [ -z "${data_dir}" ]; then - echo "please input data_dir" - show_help - exit 1 - fi -} - -param_check - -docker run -it \ - --device=/dev/davinci0 \ - --device=/dev/davinci_manager \ - --device=/dev/devmm_svm \ - --device=/dev/hisi_hdc \ - -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ - -v ${data_dir}:${data_dir} \ - ${docker_image} \ +#!/bin/bash + +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +docker_image=$1 +data_dir=$2 + +function show_help() { + echo "Usage: docker_start.sh docker_image data_dir" +} + +function param_check() { + if [ -z "${docker_image}" ]; then + echo "please input docker_image" + show_help + exit 1 + fi + + if [ -z "${data_dir}" ]; then + echo "please input data_dir" + show_help + exit 1 + fi +} + +param_check + +docker run -it \ + --device=/dev/davinci0 \ + --device=/dev/davinci_manager \ + --device=/dev/devmm_svm \ + --device=/dev/hisi_hdc \ + -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ + -v ${data_dir}:${data_dir} \ + ${docker_image} \ /bin/bash \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/FCOS/infer/mxbase/CMakeLists.txt b/PyTorch/contrib/cv/detection/FCOS/infer/mxbase/CMakeLists.txt index a690071acc..732aa7ab6d 100644 --- a/PyTorch/contrib/cv/detection/FCOS/infer/mxbase/CMakeLists.txt +++ b/PyTorch/contrib/cv/detection/FCOS/infer/mxbase/CMakeLists.txt @@ -1,52 +1,52 @@ -cmake_minimum_required(VERSION 3.14.0) -project(fcos) -set(TARGET fcos) - -add_definitions(-DENABLE_DVPP_INTERFACE) -add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) -add_definitions(-Dgoogle=mindxsdk_private) -add_compile_options(-std=c++11 -fPIE -fstack-protector-all -fPIC -Wall) -add_link_options(-Wl,-z,relro,-z,now,-z,noexecstack -s -pie) - -# Check environment variable -if(NOT DEFINED ENV{ASCEND_HOME}) - message(FATAL_ERROR "please define environment variable:ASCEND_HOME") -endif() -if(NOT DEFINED ENV{ASCEND_VERSION}) - message(WARNING "please define environment variable:ASCEND_VERSION") -endif() -if(NOT DEFINED ENV{ARCH_PATTERN}) - message(WARNING "please define environment variable:ARCH_PATTERN") -endif() - -set(ACL_INC_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/include) -set(ACL_LIB_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/lib64) - -set(MXBASE_ROOT_DIR $ENV{MX_SDK_HOME}) -set(MXBASE_INC ${MXBASE_ROOT_DIR}/include) -set(MXBASE_LIB_DIR ${MXBASE_ROOT_DIR}/lib) -set(MXBASE_POST_LIB_DIR ${MXBASE_ROOT_DIR}/lib/modelpostprocessors) -set(MXBASE_POST_PROCESS_DIR ${MXBASE_ROOT_DIR}/include/MxBase/postprocess/include) - - -if(DEFINED ENV{MXSDK_OPENSOURCE_DIR}) - set(OPENSOURCE_DIR $ENV{MXSDK_OPENSOURCE_DIR}) -else() - set(OPENSOURCE_DIR ${MXBASE_ROOT_DIR}/opensource) -endif() -include_directories(${ACL_INC_DIR}) -include_directories(${OPENSOURCE_DIR}/include) -include_directories(${OPENSOURCE_DIR}/include/opencv4) - -include_directories(${MXBASE_INC}) -include_directories(${MXBASE_POST_PROCESS_DIR}) -link_directories(${ACL_LIB_DIR}) -link_directories(${OPENSOURCE_DIR}/lib) -link_directories(${MXBASE_LIB_DIR}) -link_directories(${MXBASE_POST_LIB_DIR}) - -add_executable(${TARGET} ./src/main.cpp ./src/fcos.cpp) - -target_link_libraries(${TARGET} glog cpprest mxbase opencv_world stdc++fs) - +cmake_minimum_required(VERSION 3.14.0) +project(fcos) +set(TARGET fcos) + +add_definitions(-DENABLE_DVPP_INTERFACE) +add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) +add_definitions(-Dgoogle=mindxsdk_private) +add_compile_options(-std=c++11 -fPIE -fstack-protector-all -fPIC -Wall) +add_link_options(-Wl,-z,relro,-z,now,-z,noexecstack -s -pie) + +# Check environment variable +if(NOT DEFINED ENV{ASCEND_HOME}) + message(FATAL_ERROR "please define environment variable:ASCEND_HOME") +endif() +if(NOT DEFINED ENV{ASCEND_VERSION}) + message(WARNING "please define environment variable:ASCEND_VERSION") +endif() +if(NOT DEFINED ENV{ARCH_PATTERN}) + message(WARNING "please define environment variable:ARCH_PATTERN") +endif() + +set(ACL_INC_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/include) +set(ACL_LIB_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/lib64) + +set(MXBASE_ROOT_DIR $ENV{MX_SDK_HOME}) +set(MXBASE_INC ${MXBASE_ROOT_DIR}/include) +set(MXBASE_LIB_DIR ${MXBASE_ROOT_DIR}/lib) +set(MXBASE_POST_LIB_DIR ${MXBASE_ROOT_DIR}/lib/modelpostprocessors) +set(MXBASE_POST_PROCESS_DIR ${MXBASE_ROOT_DIR}/include/MxBase/postprocess/include) + + +if(DEFINED ENV{MXSDK_OPENSOURCE_DIR}) + set(OPENSOURCE_DIR $ENV{MXSDK_OPENSOURCE_DIR}) +else() + set(OPENSOURCE_DIR ${MXBASE_ROOT_DIR}/opensource) +endif() +include_directories(${ACL_INC_DIR}) +include_directories(${OPENSOURCE_DIR}/include) +include_directories(${OPENSOURCE_DIR}/include/opencv4) + +include_directories(${MXBASE_INC}) +include_directories(${MXBASE_POST_PROCESS_DIR}) +link_directories(${ACL_LIB_DIR}) +link_directories(${OPENSOURCE_DIR}/lib) +link_directories(${MXBASE_LIB_DIR}) +link_directories(${MXBASE_POST_LIB_DIR}) + +add_executable(${TARGET} ./src/main.cpp ./src/fcos.cpp) + +target_link_libraries(${TARGET} glog cpprest mxbase opencv_world stdc++fs) + install(TARGETS ${TARGET} RUNTIME DESTINATION ${PROJECT_SOURCE_DIR}/) \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/FCOS/infer/mxbase/src/fcos.cpp b/PyTorch/contrib/cv/detection/FCOS/infer/mxbase/src/fcos.cpp index 9a35941158..7b88e02673 100644 --- a/PyTorch/contrib/cv/detection/FCOS/infer/mxbase/src/fcos.cpp +++ b/PyTorch/contrib/cv/detection/FCOS/infer/mxbase/src/fcos.cpp @@ -1,313 +1,313 @@ -/* - * Copyright 2021 Huawei Technologies Co., Ltd - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - - * 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. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "fcos.h" -#include "MxBase/DeviceManager/DeviceManager.h" -#include "MxBase/DvppWrapper/DvppWrapper.h" -#include "MxBase/Log/Log.h" - -using namespace MxBase; - -std::vector classes = {"person", "bicycle", "car", "motorcycle", "airplane", "bus", - "train", "truck", "boat", "traffic light", "fire hydrant", - "stop sign", "parking meter", "bench", "bird", "cat", "dog", - "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", - "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", - "skis", "snowboard", "sports ball", "kite", "baseball bat", - "baseball glove", "skateboard", "surfboard", "tennis racket", - "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", - "banana", "apple", "sandwich", "orange", "broccoli", "carrot", - "hot dog", "pizza", "donut", "cake", "chair", "couch", - "potted plant", "bed", "dining table", "toilet", "tv", "laptop", - "mouse", "remote", "keyboard", "cell phone", "microwave", - "oven", "toaster", "sink", "refrigerator", "book", "clock", - "vase", "scissors", "teddy bear", "hair drier", "toothbrush"}; - -APP_ERROR FCOS::Init(const InitParam& initParam) { - // Equipment initialization - APP_ERROR ret = MxBase::DeviceManager::GetInstance()->InitDevices(); - if (ret != APP_ERR_OK) { - LogError << "Init devices failed, ret=" << ret << "."; - return ret; - } - // Context initialization - ret = MxBase::TensorContext::GetInstance()->SetContext(initParam.deviceId); - if (ret != APP_ERR_OK) { - LogError << "Set context failed, ret=" << ret << "."; - return ret; - } - - // Load model - model_ = std::make_shared(); - ret = model_->Init(initParam.modelPath, modelDesc_); - if (ret != APP_ERR_OK) { - LogError << "ModelInferenceProcessor init failed, ret=" << ret << "."; - return ret; - } - return APP_ERR_OK; -} - -APP_ERROR FCOS::DeInit() { - model_->DeInit(); - MxBase::DeviceManager::GetInstance()->DestroyDevices(); - return APP_ERR_OK; -} - -std::vector FCOS::GetFileList(const std::string &dirPath) { - /* - This function is getting data from dataset on the path. - - :param dirpath: a string of dataset path - :return: a collection of file paths - - */ - struct dirent *ptr; - DIR *dir = opendir(dirPath.c_str()); - std::vector files; - while ((ptr = readdir(dir)) != NULL) { - if (ptr->d_name[0] == '.') continue; - files.push_back(ptr->d_name); - } - closedir(dir); - return files; -} - -APP_ERROR FCOS::ReadImage(const std::string& imgPath, cv::Mat& imageMat, int& height, int& width) { - imageMat = cv::imread(imgPath, cv::IMREAD_COLOR); - width = imageMat.cols; - height = imageMat.rows; - - return APP_ERR_OK; -} - -APP_ERROR FCOS::ResizeImage(const cv::Mat& srcImageMat, cv::Mat& dstImageMat) { - float resizeHeight = 800; - float resizeWidth = 1333; - float scale = std::min(resizeWidth / srcImageMat.cols, resizeHeight / srcImageMat.rows); - int new_width = srcImageMat.cols * scale; - int new_height = srcImageMat.rows * scale; - const int average = 2; - int pad_w = resizeWidth - new_width; - int pad_h = resizeHeight - new_height; - int pad_left = pad_w / average; - int pad_right = pad_w - pad_left; - int pad_top = pad_h / average; - int pad_bottom = pad_h - pad_top; - - cv::resize(srcImageMat, dstImageMat, cv::Size(new_width,new_height), 0, 0, cv::INTER_CUBIC); //指定常量像素填充 - cv::copyMakeBorder(dstImageMat, dstImageMat, pad_top, pad_bottom, pad_left, pad_right, - cv::BorderTypes::BORDER_CONSTANT, cv::Scalar(0, 0, 0)); - - return APP_ERR_OK; -} - -APP_ERROR FCOS::CVMatToTensorBase(const cv::Mat &imageMat, MxBase::TensorBase &tensorBase) -{ - const uint32_t dataSize = imageMat.cols * imageMat.rows * YUV444_RGB_WIDTH_NU; - MemoryData memoryDataDst(dataSize, MemoryData::MEMORY_DEVICE, deviceId_); - MemoryData memoryDataSrc(imageMat.data, dataSize, MemoryData::MEMORY_HOST_MALLOC); - - APP_ERROR ret = MemoryHelper::MxbsMallocAndCopy(memoryDataDst, memoryDataSrc); - if (ret != APP_ERR_OK) { - LogError << GetError(ret) << "Memory malloc failed."; - return ret; - } - - std::vector shape = {imageMat.rows * YUV444_RGB_WIDTH_NU, static_cast(imageMat.cols)}; - tensorBase = TensorBase(memoryDataDst, false, shape, TENSOR_DTYPE_UINT8); - return APP_ERR_OK; -} - - -APP_ERROR FCOS::Inference(const std::vector& inputs, std::vector& outputs) { - auto dtypes = model_->GetOutputDataType(); - for (size_t i = 0; i < modelDesc_.outputTensors.size(); ++i) { - std::vector shape = {}; - for (size_t j = 0; j < modelDesc_.outputTensors[i].tensorDims.size(); ++j) { - shape.push_back((uint32_t)modelDesc_.outputTensors[i].tensorDims[j]); - } - TensorBase tensor(shape, dtypes[i], MemoryData::MemoryType::MEMORY_DEVICE, deviceId_); - APP_ERROR ret = TensorBase::TensorBaseMalloc(tensor); - if (ret != APP_ERR_OK) { - LogError << "TensorBaseMalloc failed, ret=" << ret << "."; - return ret; - } - outputs.push_back(tensor); - } - DynamicInfo dynamicInfo = {}; - dynamicInfo.dynamicType = DynamicType::STATIC_BATCH; - APP_ERROR ret = model_->ModelInference(inputs, outputs, dynamicInfo); - if (ret != APP_ERR_OK) { - LogError << "ModelInference failed, ret=" << ret << "."; - return ret; - } - return APP_ERR_OK; -} - -APP_ERROR FCOS::PostProcess(const std::string& imgPath, std::vector& inputs, - const std::string &resultPath, int& height, int& width, const std::string& name, - std::string &showPath, float& PROB_THRES) { - MxBase::TensorBase& tensor = inputs[1]; //1*100 - int ret = tensor.ToHost(); - if (ret != APP_ERR_OK) { - LogError << GetError(ret) << "Tensor_1 deploy to host failed."; - return ret; - } - std::vector shape = tensor.GetShape(); - - auto labels = reinterpret_cast(tensor.GetBuffer()); //1*100 - - int label[100] = {0}; - for(int i = 0; i < 100; i++){ - label[i] = labels[i]; - } - - tensor = inputs[0]; //1*100*5 - ret = tensor.ToHost(); - if (ret != APP_ERR_OK) { - LogError << GetError(ret) << "Tensor_0 deploy to host failed."; - return ret; - } - - auto bbox = reinterpret_cast(tensor.GetBuffer()); - - // get infer coordinates - float image_size_w = width; - float image_size_h = height; - float net_input_width = 1333; - float net_input_height = 800; - float scale = std::min(net_input_width / image_size_w, net_input_height / image_size_h); - - int pad_w = net_input_width - image_size_w * scale; - int pad_h = net_input_height - image_size_h * scale; - int pad_left = pad_w / 2; - int pad_right = pad_w -pad_left; - int pad_top = pad_h / 2; - int pad_bottom = pad_h -pad_top; - - float prob_thres = PROB_THRES; - float ppbox[100][5] = {0}; - - for (int j = 0; j < 100; j++) { - ppbox[j][0] = (bbox[j][0]-pad_left)/scale; - ppbox[j][1] = (bbox[j][1]-pad_top)/scale; - ppbox[j][2] = (bbox[j][2]-pad_right)/scale; - ppbox[j][3] = (bbox[j][3]-pad_bottom)/scale; - ppbox[j][4] = bbox[j][4]; - - if (ppbox[j][0]<0) ppbox[j][0] = 0; - if (ppbox[j][1]<0) ppbox[j][1] = 0; - if (ppbox[j][2]>image_size_w) ppbox[j][2] = image_size_w; - if (ppbox[j][3]>image_size_h) ppbox[j][3] = image_size_h; - - } - - std::ofstream out(resultPath); - cv::Mat imgCur = cv::imread(imgPath); - for (int j = 0;j<100;j++) { - if (float(ppbox[j][4])80 ) { - continue; - } - - std::string class_name = classes[int(label[j])]; - std::string det_results_str = ""; - std::ostringstream oss; - oss< dirFileList = GetFileList(dirPath); - std::vector names, paths; - int i = 0; - for (auto imgFile : dirFileList) { - std::string imgPath = dirPath + "/" + imgFile; - std::string name = imgFile.substr(0, imgFile.find(".")); - std::string subresultPath = resultPath+"/"+name+".txt"; - cv::Mat imageMat; - int height, width; - APP_ERROR ret = ReadImage(imgPath, imageMat, height, width); - if (ret != APP_ERR_OK) { - LogError << "ReadImage failed, ret=" << ret << "."; - return ret; - } - ResizeImage(imageMat, imageMat); - TensorBase tensorBase; - ret = CVMatToTensorBase(imageMat, tensorBase); - if (ret != APP_ERR_OK) { - LogError << "CVMatToTensorBase failed, ret=" << ret << "."; - return ret; - } - std::vector inputs = {}; - std::vector outputs = {}; - inputs.push_back(tensorBase); - ret = Inference(inputs, outputs); - if (ret != APP_ERR_OK) { - LogError << "Inference failed, ret=" << ret << "."; - return ret; - } - ret = PostProcess(imgPath, outputs, subresultPath, height, width,name,showPath,PROB_THRES); - if (ret != APP_ERR_OK) { - LogError << "PostProcess failed, ret=" << ret << "."; - return ret; - } - i++; - LogInfo< +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "fcos.h" +#include "MxBase/DeviceManager/DeviceManager.h" +#include "MxBase/DvppWrapper/DvppWrapper.h" +#include "MxBase/Log/Log.h" + +using namespace MxBase; + +std::vector classes = {"person", "bicycle", "car", "motorcycle", "airplane", "bus", + "train", "truck", "boat", "traffic light", "fire hydrant", + "stop sign", "parking meter", "bench", "bird", "cat", "dog", + "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", + "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", + "skis", "snowboard", "sports ball", "kite", "baseball bat", + "baseball glove", "skateboard", "surfboard", "tennis racket", + "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", + "banana", "apple", "sandwich", "orange", "broccoli", "carrot", + "hot dog", "pizza", "donut", "cake", "chair", "couch", + "potted plant", "bed", "dining table", "toilet", "tv", "laptop", + "mouse", "remote", "keyboard", "cell phone", "microwave", + "oven", "toaster", "sink", "refrigerator", "book", "clock", + "vase", "scissors", "teddy bear", "hair drier", "toothbrush"}; + +APP_ERROR FCOS::Init(const InitParam& initParam) { + // Equipment initialization + APP_ERROR ret = MxBase::DeviceManager::GetInstance()->InitDevices(); + if (ret != APP_ERR_OK) { + LogError << "Init devices failed, ret=" << ret << "."; + return ret; + } + // Context initialization + ret = MxBase::TensorContext::GetInstance()->SetContext(initParam.deviceId); + if (ret != APP_ERR_OK) { + LogError << "Set context failed, ret=" << ret << "."; + return ret; + } + + // Load model + model_ = std::make_shared(); + ret = model_->Init(initParam.modelPath, modelDesc_); + if (ret != APP_ERR_OK) { + LogError << "ModelInferenceProcessor init failed, ret=" << ret << "."; + return ret; + } + return APP_ERR_OK; +} + +APP_ERROR FCOS::DeInit() { + model_->DeInit(); + MxBase::DeviceManager::GetInstance()->DestroyDevices(); + return APP_ERR_OK; +} + +std::vector FCOS::GetFileList(const std::string &dirPath) { + /* + This function is getting data from dataset on the path. + + :param dirpath: a string of dataset path + :return: a collection of file paths + + */ + struct dirent *ptr; + DIR *dir = opendir(dirPath.c_str()); + std::vector files; + while ((ptr = readdir(dir)) != NULL) { + if (ptr->d_name[0] == '.') continue; + files.push_back(ptr->d_name); + } + closedir(dir); + return files; +} + +APP_ERROR FCOS::ReadImage(const std::string& imgPath, cv::Mat& imageMat, int& height, int& width) { + imageMat = cv::imread(imgPath, cv::IMREAD_COLOR); + width = imageMat.cols; + height = imageMat.rows; + + return APP_ERR_OK; +} + +APP_ERROR FCOS::ResizeImage(const cv::Mat& srcImageMat, cv::Mat& dstImageMat) { + float resizeHeight = 800; + float resizeWidth = 1333; + float scale = std::min(resizeWidth / srcImageMat.cols, resizeHeight / srcImageMat.rows); + int new_width = srcImageMat.cols * scale; + int new_height = srcImageMat.rows * scale; + const int average = 2; + int pad_w = resizeWidth - new_width; + int pad_h = resizeHeight - new_height; + int pad_left = pad_w / average; + int pad_right = pad_w - pad_left; + int pad_top = pad_h / average; + int pad_bottom = pad_h - pad_top; + + cv::resize(srcImageMat, dstImageMat, cv::Size(new_width,new_height), 0, 0, cv::INTER_CUBIC); //指定常量像素填充 + cv::copyMakeBorder(dstImageMat, dstImageMat, pad_top, pad_bottom, pad_left, pad_right, + cv::BorderTypes::BORDER_CONSTANT, cv::Scalar(0, 0, 0)); + + return APP_ERR_OK; +} + +APP_ERROR FCOS::CVMatToTensorBase(const cv::Mat &imageMat, MxBase::TensorBase &tensorBase) +{ + const uint32_t dataSize = imageMat.cols * imageMat.rows * YUV444_RGB_WIDTH_NU; + MemoryData memoryDataDst(dataSize, MemoryData::MEMORY_DEVICE, deviceId_); + MemoryData memoryDataSrc(imageMat.data, dataSize, MemoryData::MEMORY_HOST_MALLOC); + + APP_ERROR ret = MemoryHelper::MxbsMallocAndCopy(memoryDataDst, memoryDataSrc); + if (ret != APP_ERR_OK) { + LogError << GetError(ret) << "Memory malloc failed."; + return ret; + } + + std::vector shape = {imageMat.rows * YUV444_RGB_WIDTH_NU, static_cast(imageMat.cols)}; + tensorBase = TensorBase(memoryDataDst, false, shape, TENSOR_DTYPE_UINT8); + return APP_ERR_OK; +} + + +APP_ERROR FCOS::Inference(const std::vector& inputs, std::vector& outputs) { + auto dtypes = model_->GetOutputDataType(); + for (size_t i = 0; i < modelDesc_.outputTensors.size(); ++i) { + std::vector shape = {}; + for (size_t j = 0; j < modelDesc_.outputTensors[i].tensorDims.size(); ++j) { + shape.push_back((uint32_t)modelDesc_.outputTensors[i].tensorDims[j]); + } + TensorBase tensor(shape, dtypes[i], MemoryData::MemoryType::MEMORY_DEVICE, deviceId_); + APP_ERROR ret = TensorBase::TensorBaseMalloc(tensor); + if (ret != APP_ERR_OK) { + LogError << "TensorBaseMalloc failed, ret=" << ret << "."; + return ret; + } + outputs.push_back(tensor); + } + DynamicInfo dynamicInfo = {}; + dynamicInfo.dynamicType = DynamicType::STATIC_BATCH; + APP_ERROR ret = model_->ModelInference(inputs, outputs, dynamicInfo); + if (ret != APP_ERR_OK) { + LogError << "ModelInference failed, ret=" << ret << "."; + return ret; + } + return APP_ERR_OK; +} + +APP_ERROR FCOS::PostProcess(const std::string& imgPath, std::vector& inputs, + const std::string &resultPath, int& height, int& width, const std::string& name, + std::string &showPath, float& PROB_THRES) { + MxBase::TensorBase& tensor = inputs[1]; //1*100 + int ret = tensor.ToHost(); + if (ret != APP_ERR_OK) { + LogError << GetError(ret) << "Tensor_1 deploy to host failed."; + return ret; + } + std::vector shape = tensor.GetShape(); + + auto labels = reinterpret_cast(tensor.GetBuffer()); //1*100 + + int label[100] = {0}; + for(int i = 0; i < 100; i++){ + label[i] = labels[i]; + } + + tensor = inputs[0]; //1*100*5 + ret = tensor.ToHost(); + if (ret != APP_ERR_OK) { + LogError << GetError(ret) << "Tensor_0 deploy to host failed."; + return ret; + } + + auto bbox = reinterpret_cast(tensor.GetBuffer()); + + // get infer coordinates + float image_size_w = width; + float image_size_h = height; + float net_input_width = 1333; + float net_input_height = 800; + float scale = std::min(net_input_width / image_size_w, net_input_height / image_size_h); + + int pad_w = net_input_width - image_size_w * scale; + int pad_h = net_input_height - image_size_h * scale; + int pad_left = pad_w / 2; + int pad_right = pad_w -pad_left; + int pad_top = pad_h / 2; + int pad_bottom = pad_h -pad_top; + + float prob_thres = PROB_THRES; + float ppbox[100][5] = {0}; + + for (int j = 0; j < 100; j++) { + ppbox[j][0] = (bbox[j][0]-pad_left)/scale; + ppbox[j][1] = (bbox[j][1]-pad_top)/scale; + ppbox[j][2] = (bbox[j][2]-pad_right)/scale; + ppbox[j][3] = (bbox[j][3]-pad_bottom)/scale; + ppbox[j][4] = bbox[j][4]; + + if (ppbox[j][0]<0) ppbox[j][0] = 0; + if (ppbox[j][1]<0) ppbox[j][1] = 0; + if (ppbox[j][2]>image_size_w) ppbox[j][2] = image_size_w; + if (ppbox[j][3]>image_size_h) ppbox[j][3] = image_size_h; + + } + + std::ofstream out(resultPath); + cv::Mat imgCur = cv::imread(imgPath); + for (int j = 0;j<100;j++) { + if (float(ppbox[j][4])80 ) { + continue; + } + + std::string class_name = classes[int(label[j])]; + std::string det_results_str = ""; + std::ostringstream oss; + oss< dirFileList = GetFileList(dirPath); + std::vector names, paths; + int i = 0; + for (auto imgFile : dirFileList) { + std::string imgPath = dirPath + "/" + imgFile; + std::string name = imgFile.substr(0, imgFile.find(".")); + std::string subresultPath = resultPath+"/"+name+".txt"; + cv::Mat imageMat; + int height, width; + APP_ERROR ret = ReadImage(imgPath, imageMat, height, width); + if (ret != APP_ERR_OK) { + LogError << "ReadImage failed, ret=" << ret << "."; + return ret; + } + ResizeImage(imageMat, imageMat); + TensorBase tensorBase; + ret = CVMatToTensorBase(imageMat, tensorBase); + if (ret != APP_ERR_OK) { + LogError << "CVMatToTensorBase failed, ret=" << ret << "."; + return ret; + } + std::vector inputs = {}; + std::vector outputs = {}; + inputs.push_back(tensorBase); + ret = Inference(inputs, outputs); + if (ret != APP_ERR_OK) { + LogError << "Inference failed, ret=" << ret << "."; + return ret; + } + ret = PostProcess(imgPath, outputs, subresultPath, height, width,name,showPath,PROB_THRES); + if (ret != APP_ERR_OK) { + LogError << "PostProcess failed, ret=" << ret << "."; + return ret; + } + i++; + LogInfo< -#include "MxBase/ModelInfer/ModelInferenceProcessor.h" -#include "MxBase/PostProcessBases/PostProcessDataType.h" -#include "MxBase/Tensor/TensorContext/TensorContext.h" - -struct InitParam { - uint32_t deviceId; - std::string modelPath; -}; - -class FCOS { -public: - - APP_ERROR Init(const InitParam &initParam); - APP_ERROR DeInit(); - APP_ERROR ReadImage(const std::string &imgPath, cv::Mat &imageMat, int& height, int& width); - APP_ERROR ResizeImage(const cv::Mat &srcImageMat, cv::Mat &dstImageMat); - APP_ERROR CVMatToTensorBase(const cv::Mat &imageMat, MxBase::TensorBase &tensorBase); - APP_ERROR VectorToTensorBase(int* transMat, MxBase::TensorBase& tensorBase); - APP_ERROR Inference(const std::vector &inputs, std::vector &outputs); - APP_ERROR PostProcess(const std::string& imgPath, std::vector &inputs, - const std::string &subresultPath,int& height, int& width,const std::string& name, - std::string &showPath,float& PROB_THRES); - APP_ERROR Process(const std::string &dirPath, std::string &resultPath,std::string &showPath,float& PROB_THRES); - -private: - std::shared_ptr model_; - std::vector GetFileList(const std::string &dirPath); - MxBase::ModelDesc modelDesc_; - const int device_id = 0; - uint32_t deviceId_ = device_id; -}; -#endif +/* + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + + * 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. + */ + +#ifndef FCOS_H +#define FCOS_H + +#include +#include "MxBase/ModelInfer/ModelInferenceProcessor.h" +#include "MxBase/PostProcessBases/PostProcessDataType.h" +#include "MxBase/Tensor/TensorContext/TensorContext.h" + +struct InitParam { + uint32_t deviceId; + std::string modelPath; +}; + +class FCOS { +public: + + APP_ERROR Init(const InitParam &initParam); + APP_ERROR DeInit(); + APP_ERROR ReadImage(const std::string &imgPath, cv::Mat &imageMat, int& height, int& width); + APP_ERROR ResizeImage(const cv::Mat &srcImageMat, cv::Mat &dstImageMat); + APP_ERROR CVMatToTensorBase(const cv::Mat &imageMat, MxBase::TensorBase &tensorBase); + APP_ERROR VectorToTensorBase(int* transMat, MxBase::TensorBase& tensorBase); + APP_ERROR Inference(const std::vector &inputs, std::vector &outputs); + APP_ERROR PostProcess(const std::string& imgPath, std::vector &inputs, + const std::string &subresultPath,int& height, int& width,const std::string& name, + std::string &showPath,float& PROB_THRES); + APP_ERROR Process(const std::string &dirPath, std::string &resultPath,std::string &showPath,float& PROB_THRES); + +private: + std::shared_ptr model_; + std::vector GetFileList(const std::string &dirPath); + MxBase::ModelDesc modelDesc_; + const int device_id = 0; + uint32_t deviceId_ = device_id; +}; +#endif diff --git a/PyTorch/contrib/cv/detection/FCOS/infer/mxbase/src/main.cpp b/PyTorch/contrib/cv/detection/FCOS/infer/mxbase/src/main.cpp index 6acf366700..d3a1d13c09 100644 --- a/PyTorch/contrib/cv/detection/FCOS/infer/mxbase/src/main.cpp +++ b/PyTorch/contrib/cv/detection/FCOS/infer/mxbase/src/main.cpp @@ -1,45 +1,45 @@ -/* - * Copyright 2021 Huawei Technologies Co., Ltd - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - - * 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. - */ - -#include "MxBase/Log/Log.h" -#include "fcos.h" - -int main() { - InitParam initParam = {}; - initParam.deviceId = 0; - initParam.modelPath = "../../data/model/fcos.om"; - FCOS fcos; - APP_ERROR ret = fcos.Init(initParam); - if (ret != APP_ERR_OK) { - LogError << "FCOS init failed, ret=" << ret << "."; - return ret; - } - - std::string imgPath = "../../data/input/COCO2017/val2017"; - std::string resultPath = "../data/infer_result"; - std::string showPath = "../data/show_result"; - float PROB_THRES = 0.05; - - ret = fcos.Process(imgPath,resultPath,showPath,PROB_THRES); - if (ret != APP_ERR_OK) { - LogError << "FCOS process failed, ret=" << ret << "."; - fcos.DeInit(); - return ret; - } - - fcos.DeInit(); - return APP_ERR_OK; -} +/* + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + + * 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. + */ + +#include "MxBase/Log/Log.h" +#include "fcos.h" + +int main() { + InitParam initParam = {}; + initParam.deviceId = 0; + initParam.modelPath = "../../data/model/fcos.om"; + FCOS fcos; + APP_ERROR ret = fcos.Init(initParam); + if (ret != APP_ERR_OK) { + LogError << "FCOS init failed, ret=" << ret << "."; + return ret; + } + + std::string imgPath = "../../data/input/COCO2017/val2017"; + std::string resultPath = "../data/infer_result"; + std::string showPath = "../data/show_result"; + float PROB_THRES = 0.05; + + ret = fcos.Process(imgPath,resultPath,showPath,PROB_THRES); + if (ret != APP_ERR_OK) { + LogError << "FCOS process failed, ret=" << ret << "."; + fcos.DeInit(); + return ret; + } + + fcos.DeInit(); + return APP_ERR_OK; +} diff --git a/PyTorch/contrib/cv/detection/FCOS/infer/sdk/fcos_opencv_all.py b/PyTorch/contrib/cv/detection/FCOS/infer/sdk/fcos_opencv_all.py index 2108426f9f..92551e0984 100644 --- a/PyTorch/contrib/cv/detection/FCOS/infer/sdk/fcos_opencv_all.py +++ b/PyTorch/contrib/cv/detection/FCOS/infer/sdk/fcos_opencv_all.py @@ -1,289 +1,289 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 argparse -import base64 -import json -import os - -import cv2 -import numpy as np -from StreamManagerApi import MxDataInput -from StreamManagerApi import StreamManagerApi -from skimage import io - - -def parse_arg(): - parser = argparse.ArgumentParser(description="FCOS infer") - parser.add_argument("--dataset", default="../data/input/COCO2017/val2017") - parser.add_argument("--pipeline", default="../data/config/fcos.pipeline") - parser.add_argument("--test_annotation", - default="../data/input/COCO2017/coco2017.info") - parser.add_argument("--det_results_path", default="./data/infer_result") - parser.add_argument("--show_results_path", default="./data/show_result") - parser.add_argument("--net_input_width", default=1333) - parser.add_argument("--net_input_height", default=800) - parser.add_argument("--prob_thres", default=0.05) - parser.add_argument( - "--ifShowDetObj", - default="True", - action="store_true", - help="if input the para means True, neither False.") - - flags = parser.parse_args() - return flags - - -def get_dataset(path): - """ - This function is getting data from dataset on the path. - - :param path: a string of dataset path - - """ - for root, dirs, files in os.walk(path): - for file_name in files: - if file_name.endswith('jpg') or file_name.endswith('JPG'): - yield os.path.join(path, file_name) - break - - -def get_stream_manager(pipeline_path): - """ - This function is using stream_manager_api. - - :param pipeline_path: a string of pipeline path - :return: a stream manager - - """ - stream_manager_api = StreamManagerApi() - ret = stream_manager_api.InitManager() - if ret != 0: - print("Failed to init Stream manager, ret=%s" % str(ret)) - exit() - - with open(pipeline_path, 'rb') as f: - pipeline_content = f.read() - - ret = stream_manager_api.CreateMultipleStreams(pipeline_content) - if ret != 0: - print("Failed to create stream, ret=%s" % str(ret)) - exit() - return stream_manager_api - - -def do_infer_image(stream_manager_api, image_path): - """ - This function is executing the inference of images. - - :param stream_manager_api: a stream manager - :param image_path: a string of image path - :return: bbox, labels - - bbox,labels: (1,100,5),(1,100) - The model has two output tensors: - bbox:(x0, y0, x1, y1,confidence) - #the upper left and lower right coordinates of the detection boxes - labels: probability of 80 classes - """ - stream_name = b'im_fcos' - data_input = MxDataInput() - with open(image_path, 'rb') as f: - data_input.data = f.read() - - unique_id = stream_manager_api.SendData(stream_name, 0, data_input) - if unique_id < 0: - print("Failed to send data to stream.") - exit() - - infer_result = stream_manager_api.GetResult(stream_name, unique_id) - if infer_result.errorCode != 0: - print(f"GetResult error. errorCode={infer_result.errorCode}," - f"errorMsg={infer_result.data.decode()}") - exit() - - infer_result_json = json.loads(infer_result.data.decode()) - content = json.loads(infer_result_json['metaData'][0]['content']) - # print the infer result - print(infer_result.data.decode()) - infer_result_json = json.loads(infer_result.data.decode()) - content = json.loads(infer_result_json['metaData'][0]['content']) - tensor_vec = content['tensorPackageVec'][0]['tensorVec'][0] - data_str = tensor_vec['dataStr'] - tensor_shape = tensor_vec['tensorShape'] - bbox = np.frombuffer(base64.b64decode(data_str), dtype=np.float32) - bbox = np.reshape(bbox, tensor_shape[1:]) - # [bbox,labels] (1,100,5);(1,100) - - print("---------------------------bbox---------------------------") - print(bbox) - print() - print(bbox.shape) - print("-----------------------------------------------------------------") - - tensor_vec = content['tensorPackageVec'][0]['tensorVec'][1] - data_str = tensor_vec['dataStr'] - tensor_shape = tensor_vec['tensorShape'] - labels = np.frombuffer(base64.b64decode(data_str), dtype=np.int64) - labels = np.reshape(labels, tensor_shape[1:]) - print("---------------------------labels---------------------------") - print(labels) - print() - print(labels.shape) - print("-----------------------------------------------------------------") - return bbox, labels - - -CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', - 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', - 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', - 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', - 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', - 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', - 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', - 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', - 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', - 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', - 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', - 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] - - -def coco_postprocess(bbox: np.ndarray, image_size, - net_input_width, net_input_height): - """ - This function is postprocessing for FCOS output. - - Before calling this function, reshape the raw output of FCOS to - following form - numpy.ndarray: - [x0, y0, x1, y1, confidence, probability of 80 classes] - shape: (100,) - The postprocessing restore the bounding rectangles of FCOS output - to origin scale and filter with non-maximum suppression. - - :param bbox: a numpy array of the FCOS output - :param image_path: a string of image path - :return: three list for best bound, class and score - """ - w = image_size[0] - h = image_size[1] - scale = min(net_input_width / w, net_input_height / h) - - pad_w = net_input_width - w * scale - pad_h = net_input_height - h * scale - pad_left = pad_w // 2 - pad_top = pad_h // 2 - - # cal predict box on the image src - pbox = bbox - - pbox[:, 0] = (bbox[:, 0] - pad_left) / scale - pbox[:, 1] = (bbox[:, 1] - pad_top) / scale - pbox[:, 2] = (bbox[:, 2] - pad_left) / scale - pbox[:, 3] = (bbox[:, 3] - pad_top) / scale - - # make pbboxes value in valid range - pbox[:, 0] = np.maximum(pbox[:, 0], 0) - pbox[:, 1] = np.maximum(pbox[:, 1], 0) - pbox[:, 2] = np.minimum(pbox[:, 2], w) - pbox[:, 3] = np.minimum(pbox[:, 3], h) - - return pbox - - -def main(args): - i = 0 - path = args.dataset - print(args.ifShowDetObj, type(args.ifShowDetObj)) - det_results_path = args.det_results_path - show_results_path = args.show_results_path - os.makedirs(det_results_path, exist_ok=True) - os.makedirs(show_results_path, exist_ok=True) - stream_manager_api = get_stream_manager(args.pipeline) - img_size_dict = dict() - with open(args.test_annotation)as f: - for line in f.readlines(): - temp = line.split(" ") - img_file_path = temp[1] - img_name = temp[1].split("/")[-1].split(".")[0] - img_width = int(temp[2]) - img_height = int(temp[3]) - img_size_dict[img_name] = (img_width, img_height, img_file_path) - - for img_path in get_dataset(path): - image_1 = io.imread(img_path) - if len(image_1.shape) == 3: - if image_1.shape[2] != 3: - continue - file_name1 = os.path.basename(img_path) - file_name = file_name1.split('.')[0] - print(file_name1) - delete_img_name = ['000000374551.jpg', '000000003661.jpg', - '000000309391.jpg', '000000070254.jpg'] - if file_name1 in delete_img_name: - continue - - bbox, labels = do_infer_image(stream_manager_api, img_path) - - res_buff = [] - res_buff.append(bbox) - labels = np.reshape(labels, [100, 1]) - res_buff.append(labels) - res_tensor = np.concatenate(res_buff, axis=1) - current_img_size = img_size_dict[file_name] - print("[TEST]---------------------------concat{} imgsize{}".format( - len(res_tensor), current_img_size)) - predbox = coco_postprocess( - res_tensor, current_img_size, args.net_input_width, args.net_input_height) - - if args.ifShowDetObj == True: - imgCur = cv2.imread(img_path) - - det_results_str = '' - for idx, class_ind in enumerate(predbox[:, 5]): - if float(predbox[idx][4]) < float(args.prob_thres): - continue - # skip negative class index - if class_ind < 0 or class_ind > 80: - continue - - class_name = CLASSES[int(class_ind)] - det_results_str += "{} {} {} {} {} {}\n".format(class_name, str(predbox[idx][4]), predbox[idx][0], - predbox[idx][1], predbox[idx][2], predbox[idx][3]) - if args.ifShowDetObj == True: - imgCur = cv2.rectangle(imgCur, (int(predbox[idx][0]), int(predbox[idx][1])), - (int(predbox[idx][2]), int(predbox[idx][3])), (0, 255, 0), 1) - imgCur = cv2.putText(imgCur, class_name+'|'+str(predbox[idx][4]), - (int(predbox[idx][0]), int(predbox[idx][1])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) - # Image, text content, coordinates, font, size, color and font thickness. - - if args.ifShowDetObj == True: - print(os.path.join(show_results_path, file_name + '.jpg')) - cv2.imwrite(os.path.join(show_results_path, file_name + - '.jpg'), imgCur, [int(cv2.IMWRITE_JPEG_QUALITY), 70]) - - det_results_file = os.path.join(det_results_path, file_name + ".txt") - with open(det_results_file, "w") as detf: - detf.write(det_results_str) - print(det_results_str) - i = i+1 - print(i) - - stream_manager_api.DestroyAllStreams() - - -if __name__ == "__main__": - args = parse_arg() - main(args) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 argparse +import base64 +import json +import os + +import cv2 +import numpy as np +from StreamManagerApi import MxDataInput +from StreamManagerApi import StreamManagerApi +from skimage import io + + +def parse_arg(): + parser = argparse.ArgumentParser(description="FCOS infer") + parser.add_argument("--dataset", default="../data/input/COCO2017/val2017") + parser.add_argument("--pipeline", default="../data/config/fcos.pipeline") + parser.add_argument("--test_annotation", + default="../data/input/COCO2017/coco2017.info") + parser.add_argument("--det_results_path", default="./data/infer_result") + parser.add_argument("--show_results_path", default="./data/show_result") + parser.add_argument("--net_input_width", default=1333) + parser.add_argument("--net_input_height", default=800) + parser.add_argument("--prob_thres", default=0.05) + parser.add_argument( + "--ifShowDetObj", + default="True", + action="store_true", + help="if input the para means True, neither False.") + + flags = parser.parse_args() + return flags + + +def get_dataset(path): + """ + This function is getting data from dataset on the path. + + :param path: a string of dataset path + + """ + for root, dirs, files in os.walk(path): + for file_name in files: + if file_name.endswith('jpg') or file_name.endswith('JPG'): + yield os.path.join(path, file_name) + break + + +def get_stream_manager(pipeline_path): + """ + This function is using stream_manager_api. + + :param pipeline_path: a string of pipeline path + :return: a stream manager + + """ + stream_manager_api = StreamManagerApi() + ret = stream_manager_api.InitManager() + if ret != 0: + print("Failed to init Stream manager, ret=%s" % str(ret)) + exit() + + with open(pipeline_path, 'rb') as f: + pipeline_content = f.read() + + ret = stream_manager_api.CreateMultipleStreams(pipeline_content) + if ret != 0: + print("Failed to create stream, ret=%s" % str(ret)) + exit() + return stream_manager_api + + +def do_infer_image(stream_manager_api, image_path): + """ + This function is executing the inference of images. + + :param stream_manager_api: a stream manager + :param image_path: a string of image path + :return: bbox, labels + + bbox,labels: (1,100,5),(1,100) + The model has two output tensors: + bbox:(x0, y0, x1, y1,confidence) + #the upper left and lower right coordinates of the detection boxes + labels: probability of 80 classes + """ + stream_name = b'im_fcos' + data_input = MxDataInput() + with open(image_path, 'rb') as f: + data_input.data = f.read() + + unique_id = stream_manager_api.SendData(stream_name, 0, data_input) + if unique_id < 0: + print("Failed to send data to stream.") + exit() + + infer_result = stream_manager_api.GetResult(stream_name, unique_id) + if infer_result.errorCode != 0: + print(f"GetResult error. errorCode={infer_result.errorCode}," + f"errorMsg={infer_result.data.decode()}") + exit() + + infer_result_json = json.loads(infer_result.data.decode()) + content = json.loads(infer_result_json['metaData'][0]['content']) + # print the infer result + print(infer_result.data.decode()) + infer_result_json = json.loads(infer_result.data.decode()) + content = json.loads(infer_result_json['metaData'][0]['content']) + tensor_vec = content['tensorPackageVec'][0]['tensorVec'][0] + data_str = tensor_vec['dataStr'] + tensor_shape = tensor_vec['tensorShape'] + bbox = np.frombuffer(base64.b64decode(data_str), dtype=np.float32) + bbox = np.reshape(bbox, tensor_shape[1:]) + # [bbox,labels] (1,100,5);(1,100) + + print("---------------------------bbox---------------------------") + print(bbox) + print() + print(bbox.shape) + print("-----------------------------------------------------------------") + + tensor_vec = content['tensorPackageVec'][0]['tensorVec'][1] + data_str = tensor_vec['dataStr'] + tensor_shape = tensor_vec['tensorShape'] + labels = np.frombuffer(base64.b64decode(data_str), dtype=np.int64) + labels = np.reshape(labels, tensor_shape[1:]) + print("---------------------------labels---------------------------") + print(labels) + print() + print(labels.shape) + print("-----------------------------------------------------------------") + return bbox, labels + + +CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', + 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', + 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', + 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', + 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', + 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', + 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', + 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', + 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', + 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', + 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', + 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] + + +def coco_postprocess(bbox: np.ndarray, image_size, + net_input_width, net_input_height): + """ + This function is postprocessing for FCOS output. + + Before calling this function, reshape the raw output of FCOS to + following form + numpy.ndarray: + [x0, y0, x1, y1, confidence, probability of 80 classes] + shape: (100,) + The postprocessing restore the bounding rectangles of FCOS output + to origin scale and filter with non-maximum suppression. + + :param bbox: a numpy array of the FCOS output + :param image_path: a string of image path + :return: three list for best bound, class and score + """ + w = image_size[0] + h = image_size[1] + scale = min(net_input_width / w, net_input_height / h) + + pad_w = net_input_width - w * scale + pad_h = net_input_height - h * scale + pad_left = pad_w // 2 + pad_top = pad_h // 2 + + # cal predict box on the image src + pbox = bbox + + pbox[:, 0] = (bbox[:, 0] - pad_left) / scale + pbox[:, 1] = (bbox[:, 1] - pad_top) / scale + pbox[:, 2] = (bbox[:, 2] - pad_left) / scale + pbox[:, 3] = (bbox[:, 3] - pad_top) / scale + + # make pbboxes value in valid range + pbox[:, 0] = np.maximum(pbox[:, 0], 0) + pbox[:, 1] = np.maximum(pbox[:, 1], 0) + pbox[:, 2] = np.minimum(pbox[:, 2], w) + pbox[:, 3] = np.minimum(pbox[:, 3], h) + + return pbox + + +def main(args): + i = 0 + path = args.dataset + print(args.ifShowDetObj, type(args.ifShowDetObj)) + det_results_path = args.det_results_path + show_results_path = args.show_results_path + os.makedirs(det_results_path, exist_ok=True) + os.makedirs(show_results_path, exist_ok=True) + stream_manager_api = get_stream_manager(args.pipeline) + img_size_dict = dict() + with open(args.test_annotation)as f: + for line in f.readlines(): + temp = line.split(" ") + img_file_path = temp[1] + img_name = temp[1].split("/")[-1].split(".")[0] + img_width = int(temp[2]) + img_height = int(temp[3]) + img_size_dict[img_name] = (img_width, img_height, img_file_path) + + for img_path in get_dataset(path): + image_1 = io.imread(img_path) + if len(image_1.shape) == 3: + if image_1.shape[2] != 3: + continue + file_name1 = os.path.basename(img_path) + file_name = file_name1.split('.')[0] + print(file_name1) + delete_img_name = ['000000374551.jpg', '000000003661.jpg', + '000000309391.jpg', '000000070254.jpg'] + if file_name1 in delete_img_name: + continue + + bbox, labels = do_infer_image(stream_manager_api, img_path) + + res_buff = [] + res_buff.append(bbox) + labels = np.reshape(labels, [100, 1]) + res_buff.append(labels) + res_tensor = np.concatenate(res_buff, axis=1) + current_img_size = img_size_dict[file_name] + print("[TEST]---------------------------concat{} imgsize{}".format( + len(res_tensor), current_img_size)) + predbox = coco_postprocess( + res_tensor, current_img_size, args.net_input_width, args.net_input_height) + + if args.ifShowDetObj == True: + imgCur = cv2.imread(img_path) + + det_results_str = '' + for idx, class_ind in enumerate(predbox[:, 5]): + if float(predbox[idx][4]) < float(args.prob_thres): + continue + # skip negative class index + if class_ind < 0 or class_ind > 80: + continue + + class_name = CLASSES[int(class_ind)] + det_results_str += "{} {} {} {} {} {}\n".format(class_name, str(predbox[idx][4]), predbox[idx][0], + predbox[idx][1], predbox[idx][2], predbox[idx][3]) + if args.ifShowDetObj == True: + imgCur = cv2.rectangle(imgCur, (int(predbox[idx][0]), int(predbox[idx][1])), + (int(predbox[idx][2]), int(predbox[idx][3])), (0, 255, 0), 1) + imgCur = cv2.putText(imgCur, class_name+'|'+str(predbox[idx][4]), + (int(predbox[idx][0]), int(predbox[idx][1])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) + # Image, text content, coordinates, font, size, color and font thickness. + + if args.ifShowDetObj == True: + print(os.path.join(show_results_path, file_name + '.jpg')) + cv2.imwrite(os.path.join(show_results_path, file_name + + '.jpg'), imgCur, [int(cv2.IMWRITE_JPEG_QUALITY), 70]) + + det_results_file = os.path.join(det_results_path, file_name + ".txt") + with open(det_results_file, "w") as detf: + detf.write(det_results_str) + print(det_results_str) + i = i+1 + print(i) + + stream_manager_api.DestroyAllStreams() + + +if __name__ == "__main__": + args = parse_arg() + main(args) diff --git a/PyTorch/contrib/cv/detection/FCOS/infer/util/coco_eval.py b/PyTorch/contrib/cv/detection/FCOS/infer/util/coco_eval.py index 9ffdd575d3..d5376996c9 100644 --- a/PyTorch/contrib/cv/detection/FCOS/infer/util/coco_eval.py +++ b/PyTorch/contrib/cv/detection/FCOS/infer/util/coco_eval.py @@ -1,96 +1,96 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 argparse - -import numpy as np -import argparse -from pycocotools.coco import COCO -from pycocotools.cocoeval import COCOeval - -CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', - 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', - 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', - 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', - 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', - 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', - 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', - 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', - 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', - 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', - 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', - 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] - -def coco_evaluation(annotation_json, result_json): - cocoGt = COCO(annotation_json) - cocoDt = cocoGt.loadRes(result_json) - iou_thrs = np.linspace(.5, 0.95, int(np.round((0.95 - .5) / .05)) + 1, endpoint=True) - iou_type = 'bbox' - - cocoEval = COCOeval(cocoGt, cocoDt, iou_type) - cocoEval.params.catIds = cocoGt.getCatIds(catNms=CLASSES) - cocoEval.params.imgIds = cocoGt.getImgIds() - delete_id=[3661,70254,309391,374551,190007] - for did in delete_id: - cocoEval.params.imgIds.remove(did) - - cocoEval.params.maxDets = [100, 300, 1000] # proposal number for evaluating recalls/mAPs. - cocoEval.params.iouThrs = iou_thrs - - cocoEval.evaluate() - cocoEval.accumulate() - cocoEval.summarize() - - # mapping of cocoEval.stats - coco_metric_names = { - 'mAP': 0, - 'mAP_50': 1, - 'mAP_75': 2, - 'mAP_s': 3, - 'mAP_m': 4, - 'mAP_l': 5, - 'AR@100': 6, - 'AR@300': 7, - 'AR@1000': 8, - 'AR_s@1000': 9, - 'AR_m@1000': 10, - 'AR_l@1000': 11 - } - - metric_items = ['mAP', 'mAP_50', 'mAP_75', 'mAP_s', 'mAP_m', 'mAP_l'] - eval_results = {} - - for metric_item in metric_items: - key = f'bbox_{metric_item}' - val = float( - f'{cocoEval.stats[coco_metric_names[metric_item]]:.3f}' - ) - eval_results[key] = val - ap = cocoEval.stats[:6] - eval_results['bbox_mAP_copypaste'] = ( - f'{ap[0]:.3f} {ap[1]:.3f} {ap[2]:.3f} {ap[3]:.3f} ' - f'{ap[4]:.3f} {ap[5]:.3f}') - - return eval_results - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--ground_truth", default="../data/input/COCO2017/annotations/instances_val2017.json") - parser.add_argument("--detection_result", default="coco_detection_result.json") - args = parser.parse_args() - result = coco_evaluation(args.ground_truth, args.detection_result) - print(result) - with open('./coco_detection_result.txt', 'w') as f: - for key, value in result.items(): +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 argparse + +import numpy as np +import argparse +from pycocotools.coco import COCO +from pycocotools.cocoeval import COCOeval + +CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', + 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', + 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', + 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', + 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', + 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', + 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', + 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', + 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', + 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', + 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', + 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] + +def coco_evaluation(annotation_json, result_json): + cocoGt = COCO(annotation_json) + cocoDt = cocoGt.loadRes(result_json) + iou_thrs = np.linspace(.5, 0.95, int(np.round((0.95 - .5) / .05)) + 1, endpoint=True) + iou_type = 'bbox' + + cocoEval = COCOeval(cocoGt, cocoDt, iou_type) + cocoEval.params.catIds = cocoGt.getCatIds(catNms=CLASSES) + cocoEval.params.imgIds = cocoGt.getImgIds() + delete_id=[3661,70254,309391,374551,190007] + for did in delete_id: + cocoEval.params.imgIds.remove(did) + + cocoEval.params.maxDets = [100, 300, 1000] # proposal number for evaluating recalls/mAPs. + cocoEval.params.iouThrs = iou_thrs + + cocoEval.evaluate() + cocoEval.accumulate() + cocoEval.summarize() + + # mapping of cocoEval.stats + coco_metric_names = { + 'mAP': 0, + 'mAP_50': 1, + 'mAP_75': 2, + 'mAP_s': 3, + 'mAP_m': 4, + 'mAP_l': 5, + 'AR@100': 6, + 'AR@300': 7, + 'AR@1000': 8, + 'AR_s@1000': 9, + 'AR_m@1000': 10, + 'AR_l@1000': 11 + } + + metric_items = ['mAP', 'mAP_50', 'mAP_75', 'mAP_s', 'mAP_m', 'mAP_l'] + eval_results = {} + + for metric_item in metric_items: + key = f'bbox_{metric_item}' + val = float( + f'{cocoEval.stats[coco_metric_names[metric_item]]:.3f}' + ) + eval_results[key] = val + ap = cocoEval.stats[:6] + eval_results['bbox_mAP_copypaste'] = ( + f'{ap[0]:.3f} {ap[1]:.3f} {ap[2]:.3f} {ap[3]:.3f} ' + f'{ap[4]:.3f} {ap[5]:.3f}') + + return eval_results + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("--ground_truth", default="../data/input/COCO2017/annotations/instances_val2017.json") + parser.add_argument("--detection_result", default="coco_detection_result.json") + args = parser.parse_args() + result = coco_evaluation(args.ground_truth, args.detection_result) + print(result) + with open('./coco_detection_result.txt', 'w') as f: + for key, value in result.items(): f.write(key + ': ' + str(value) + '\n') \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/FCOS/infer/util/txt_to_json.py b/PyTorch/contrib/cv/detection/FCOS/infer/util/txt_to_json.py index 9895c21565..5044a128f5 100644 --- a/PyTorch/contrib/cv/detection/FCOS/infer/util/txt_to_json.py +++ b/PyTorch/contrib/cv/detection/FCOS/infer/util/txt_to_json.py @@ -1,112 +1,112 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 glob -import os -import sys -import argparse -import mmcv - -CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', - 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', - 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', - 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', - 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', - 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', - 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', - 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', - 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', - 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', - 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', - 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] - -cat_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, -24, 25, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, -48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 70, -72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90] - -''' - 0,0 ------> x (width) - | - | (Left,Top) - | *_________ - | | | - | | - y |_________| - (height) * - (Right,Bottom) -''' - -def file_lines_to_list(path): - # open txt file lines to a list - with open(path) as f: - content = f.readlines() - # remove whitespace characters like `\n` at the end of each line - content = [x.strip() for x in content] - return content - - -def error(msg): - print(msg) - sys.exit(0) - - -def get_predict_list(file_path, gt_classes): - dr_files_list = glob.glob(file_path + '/*.txt') - dr_files_list.sort() - - bounding_boxes = [] - for txt_file in dr_files_list: - file_id = txt_file.split(".txt", 1)[0] - file_id = os.path.basename(os.path.normpath(file_id)) - lines = file_lines_to_list(txt_file) - for line in lines: - try: - sl = line.split() - if len(sl) > 6: - class_name = sl[0] + ' ' + sl[1] - scores, left, top, right, bottom = sl[2:] - else: - class_name, scores, left, top, right, bottom = sl - if float(scores) < 0.05: - continue - except ValueError: - error_msg = "Error: File " + txt_file + " wrong format.\n" - error_msg += " Expected: \n" - error_msg += " Received: " + line - error(error_msg) - - left = float(left) - right = float(right) - top = float(top) - bottom = float(bottom) - bbox = [left, top, right-left, bottom-top] - bounding_boxes.append({"image_id": int(file_id), "bbox": bbox, - "score": float(scores), "category_id": cat_ids[CLASSES.index(class_name)]}) - - return bounding_boxes - - - -if __name__ == '__main__': - parser = argparse.ArgumentParser('mAp calculate') - parser.add_argument('--npu_txt_path', default="../sdk/data/infer_result/", - help='the path of the predict result') - parser.add_argument("--json_output_file", default="coco_detection_result") - args = parser.parse_args() - - res_bbox = get_predict_list(args.npu_txt_path, CLASSES) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 glob +import os +import sys +import argparse +import mmcv + +CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', + 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', + 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', + 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', + 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', + 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', + 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', + 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', + 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', + 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', + 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', + 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] + +cat_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, +24, 25, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, +48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 70, +72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90] + +''' + 0,0 ------> x (width) + | + | (Left,Top) + | *_________ + | | | + | | + y |_________| + (height) * + (Right,Bottom) +''' + +def file_lines_to_list(path): + # open txt file lines to a list + with open(path) as f: + content = f.readlines() + # remove whitespace characters like `\n` at the end of each line + content = [x.strip() for x in content] + return content + + +def error(msg): + print(msg) + sys.exit(0) + + +def get_predict_list(file_path, gt_classes): + dr_files_list = glob.glob(file_path + '/*.txt') + dr_files_list.sort() + + bounding_boxes = [] + for txt_file in dr_files_list: + file_id = txt_file.split(".txt", 1)[0] + file_id = os.path.basename(os.path.normpath(file_id)) + lines = file_lines_to_list(txt_file) + for line in lines: + try: + sl = line.split() + if len(sl) > 6: + class_name = sl[0] + ' ' + sl[1] + scores, left, top, right, bottom = sl[2:] + else: + class_name, scores, left, top, right, bottom = sl + if float(scores) < 0.05: + continue + except ValueError: + error_msg = "Error: File " + txt_file + " wrong format.\n" + error_msg += " Expected: \n" + error_msg += " Received: " + line + error(error_msg) + + left = float(left) + right = float(right) + top = float(top) + bottom = float(bottom) + bbox = [left, top, right-left, bottom-top] + bounding_boxes.append({"image_id": int(file_id), "bbox": bbox, + "score": float(scores), "category_id": cat_ids[CLASSES.index(class_name)]}) + + return bounding_boxes + + + +if __name__ == '__main__': + parser = argparse.ArgumentParser('mAp calculate') + parser.add_argument('--npu_txt_path', default="../sdk/data/infer_result/", + help='the path of the predict result') + parser.add_argument("--json_output_file", default="coco_detection_result") + args = parser.parse_args() + + res_bbox = get_predict_list(args.npu_txt_path, CLASSES) mmcv.dump(res_bbox, args.json_output_file + '.json') \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/FCOS/mmcv_need/base_runner.py b/PyTorch/contrib/cv/detection/FCOS/mmcv_need/base_runner.py index 02c2d21c80..e7027b1a37 100644 --- a/PyTorch/contrib/cv/detection/FCOS/mmcv_need/base_runner.py +++ b/PyTorch/contrib/cv/detection/FCOS/mmcv_need/base_runner.py @@ -1,474 +1,474 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -import logging -import os.path as osp -import warnings -from abc import ABCMeta, abstractmethod - -import torch -from torch.optim import Optimizer - -import mmcv -from ..parallel import is_module_wrapper -from .checkpoint import load_checkpoint -from .dist_utils import get_dist_info -from .hooks import HOOKS, Hook, IterTimerHook -from .log_buffer import LogBuffer -from .priority import get_priority -from .utils import get_time_str - - -class BaseRunner(metaclass=ABCMeta): - """The base class of Runner, a training helper for PyTorch. - - All subclasses should implement the following APIs: - - - ``run()`` - - ``train()`` - - ``val()`` - - ``save_checkpoint()`` - - Args: - model (:obj:`torch.nn.Module`): The model to be run. - batch_processor (callable): A callable method that process a data - batch. The interface of this method should be - `batch_processor(model, data, train_mode) -> dict` - optimizer (dict or :obj:`torch.optim.Optimizer`): It can be either an - optimizer (in most cases) or a dict of optimizers (in models that - requires more than one optimizer, e.g., GAN). - work_dir (str, optional): The working directory to save checkpoints - and logs. Defaults to None. - logger (:obj:`logging.Logger`): Logger used during training. - Defaults to None. (The default value is just for backward - compatibility) - meta (dict | None): A dict records some import information such as - environment info and seed, which will be logged in logger hook. - Defaults to None. - max_epochs (int, optional): Total training epochs. - max_iters (int, optional): Total training iterations. - """ - - def __init__(self, - model, - batch_processor=None, - optimizer=None, - work_dir=None, - logger=None, - meta=None, - max_iters=None, - max_epochs=None, - samples_per_gpu=2, # added by jyl - num_of_gpus=8): # added by jyl - if batch_processor is not None: - if not callable(batch_processor): - raise TypeError('batch_processor must be callable, ' - f'but got {type(batch_processor)}') - warnings.warn('batch_processor is deprecated, please implement ' - 'train_step() and val_step() in the model instead.') - # raise an error is `batch_processor` is not None and - # `model.train_step()` exists. - if is_module_wrapper(model): - _model = model.module - else: - _model = model - if hasattr(_model, 'train_step') or hasattr(_model, 'val_step'): - raise RuntimeError( - 'batch_processor and model.train_step()/model.val_step() ' - 'cannot be both available.') - else: - assert hasattr(model, 'train_step') - - # check the type of `optimizer` - if isinstance(optimizer, dict): - for name, optim in optimizer.items(): - if not isinstance(optim, Optimizer): - raise TypeError( - f'optimizer must be a dict of torch.optim.Optimizers, ' - f'but optimizer["{name}"] is a {type(optim)}') - elif not isinstance(optimizer, Optimizer) and optimizer is not None: - raise TypeError( - f'optimizer must be a torch.optim.Optimizer object ' - f'or dict or None, but got {type(optimizer)}') - - # check the type of `logger` - if not isinstance(logger, logging.Logger): - raise TypeError(f'logger must be a logging.Logger object, ' - f'but got {type(logger)}') - - # check the type of `meta` - if meta is not None and not isinstance(meta, dict): - raise TypeError( - f'meta must be a dict or None, but got {type(meta)}') - - self.model = model - self.batch_processor = batch_processor - self.optimizer = optimizer - self.logger = logger - self.meta = meta - self.samples_per_gpu = samples_per_gpu # added by jyl - self.num_of_gpus = num_of_gpus # added by jyl - - # create work_dir - if mmcv.is_str(work_dir): - self.work_dir = osp.abspath(work_dir) - mmcv.mkdir_or_exist(self.work_dir) - elif work_dir is None: - self.work_dir = None - else: - raise TypeError('"work_dir" must be a str or None') - - # get model name from the model class - if hasattr(self.model, 'module'): - self._model_name = self.model.module.__class__.__name__ - else: - self._model_name = self.model.__class__.__name__ - - self._rank, self._world_size = get_dist_info() - self.timestamp = get_time_str() - self.mode = None - self._hooks = [] - self._epoch = 0 - self._iter = 0 - self._inner_iter = 0 - - if max_epochs is not None and max_iters is not None: - raise ValueError( - 'Only one of `max_epochs` or `max_iters` can be set.') - - self._max_epochs = max_epochs - self._max_iters = max_iters - # TODO: Redesign LogBuffer, it is not flexible and elegant enough - self.log_buffer = LogBuffer() - - self.iter_timer_hook = IterTimerHook() # added by jyl - - @property - def model_name(self): - """str: Name of the model, usually the module class name.""" - return self._model_name - - @property - def rank(self): - """int: Rank of current process. (distributed training)""" - return self._rank - - @property - def world_size(self): - """int: Number of processes participating in the job. - (distributed training)""" - return self._world_size - - @property - def hooks(self): - """list[:obj:`Hook`]: A list of registered hooks.""" - return self._hooks - - @property - def epoch(self): - """int: Current epoch.""" - return self._epoch - - @property - def iter(self): - """int: Current iteration.""" - return self._iter - - @property - def inner_iter(self): - """int: Iteration in an epoch.""" - return self._inner_iter - - @property - def max_epochs(self): - """int: Maximum training epochs.""" - return self._max_epochs - - @property - def max_iters(self): - """int: Maximum training iterations.""" - return self._max_iters - - @abstractmethod - def train(self): - pass - - @abstractmethod - def val(self): - pass - - @abstractmethod - def run(self, data_loaders, workflow, **kwargs): - pass - - @abstractmethod - def save_checkpoint(self, - out_dir, - filename_tmpl, - save_optimizer=True, - meta=None, - create_symlink=True): - pass - - def current_lr(self): - """Get current learning rates. - - Returns: - list[float] | dict[str, list[float]]: Current learning rates of all - param groups. If the runner has a dict of optimizers, this - method will return a dict. - """ - if isinstance(self.optimizer, torch.optim.Optimizer): - lr = [group['lr'] for group in self.optimizer.param_groups] - elif isinstance(self.optimizer, dict): - lr = dict() - for name, optim in self.optimizer.items(): - lr[name] = [group['lr'] for group in optim.param_groups] - else: - raise RuntimeError( - 'lr is not applicable because optimizer does not exist.') - return lr - - def current_momentum(self): - """Get current momentums. - - Returns: - list[float] | dict[str, list[float]]: Current momentums of all - param groups. If the runner has a dict of optimizers, this - method will return a dict. - """ - - def _get_momentum(optimizer): - momentums = [] - for group in optimizer.param_groups: - if 'momentum' in group.keys(): - momentums.append(group['momentum']) - elif 'betas' in group.keys(): - momentums.append(group['betas'][0]) - else: - momentums.append(0) - return momentums - - if self.optimizer is None: - raise RuntimeError( - 'momentum is not applicable because optimizer does not exist.') - elif isinstance(self.optimizer, torch.optim.Optimizer): - momentums = _get_momentum(self.optimizer) - elif isinstance(self.optimizer, dict): - momentums = dict() - for name, optim in self.optimizer.items(): - momentums[name] = _get_momentum(optim) - return momentums - - def register_hook(self, hook, priority='NORMAL'): - """Register a hook into the hook list. - - The hook will be inserted into a priority queue, with the specified - priority (See :class:`Priority` for details of priorities). - For hooks with the same priority, they will be triggered in the same - order as they are registered. - - Args: - hook (:obj:`Hook`): The hook to be registered. - priority (int or str or :obj:`Priority`): Hook priority. - Lower value means higher priority. - """ - assert isinstance(hook, Hook) - if hasattr(hook, 'priority'): - raise ValueError('"priority" is a reserved attribute for hooks') - priority = get_priority(priority) - hook.priority = priority - # insert the hook to a sorted list - inserted = False - for i in range(len(self._hooks) - 1, -1, -1): - if priority >= self._hooks[i].priority: - self._hooks.insert(i + 1, hook) - inserted = True - break - if not inserted: - self._hooks.insert(0, hook) - - def register_hook_from_cfg(self, hook_cfg): - """Register a hook from its cfg. - - Args: - hook_cfg (dict): Hook config. It should have at least keys 'type' - and 'priority' indicating its type and priority. - - Notes: - The specific hook class to register should not use 'type' and - 'priority' arguments during initialization. - """ - hook_cfg = hook_cfg.copy() - priority = hook_cfg.pop('priority', 'NORMAL') - hook = mmcv.build_from_cfg(hook_cfg, HOOKS) - self.register_hook(hook, priority=priority) - - def call_hook(self, fn_name): - """Call all hooks. - - Args: - fn_name (str): The function name in each hook to be called, such as - "before_train_epoch". - """ - for hook in self._hooks: - getattr(hook, fn_name)(self) - - def load_checkpoint(self, filename, map_location='cpu', strict=False): - self.logger.info('load checkpoint from %s', filename) - return load_checkpoint(self.model, filename, map_location, strict, - self.logger) - - def resume(self, - checkpoint, - resume_optimizer=True, - map_location='default'): - if map_location == 'default': - if torch.cuda.is_available(): - device_id = torch.cuda.current_device() - checkpoint = self.load_checkpoint( - checkpoint, - map_location=lambda storage, loc: storage.cuda(device_id)) - else: - checkpoint = self.load_checkpoint(checkpoint) - else: - checkpoint = self.load_checkpoint( - checkpoint, map_location=map_location) - - self._epoch = checkpoint['meta']['epoch'] - self._iter = checkpoint['meta']['iter'] - if 'optimizer' in checkpoint and resume_optimizer: - if isinstance(self.optimizer, Optimizer): - self.optimizer.load_state_dict(checkpoint['optimizer']) - elif isinstance(self.optimizer, dict): - for k in self.optimizer.keys(): - self.optimizer[k].load_state_dict( - checkpoint['optimizer'][k]) - else: - raise TypeError( - 'Optimizer should be dict or torch.optim.Optimizer ' - f'but got {type(self.optimizer)}') - - self.logger.info('resumed epoch %d, iter %d', self.epoch, self.iter) - - def register_lr_hook(self, lr_config): - if isinstance(lr_config, dict): - assert 'policy' in lr_config - policy_type = lr_config.pop('policy') - # If the type of policy is all in lower case, e.g., 'cyclic', - # then its first letter will be capitalized, e.g., to be 'Cyclic'. - # This is for the convenient usage of Lr updater. - # Since this is not applicable for ` - # CosineAnnealingLrUpdater`, - # the string will not be changed if it contains capital letters. - if policy_type == policy_type.lower(): - policy_type = policy_type.title() - hook_type = policy_type + 'LrUpdaterHook' - lr_config['type'] = hook_type - hook = mmcv.build_from_cfg(lr_config, HOOKS) - else: - hook = lr_config - self.register_hook(hook) - - def register_momentum_hook(self, momentum_config): - if momentum_config is None: - return - if isinstance(momentum_config, dict): - assert 'policy' in momentum_config - policy_type = momentum_config.pop('policy') - # If the type of policy is all in lower case, e.g., 'cyclic', - # then its first letter will be capitalized, e.g., to be 'Cyclic'. - # This is for the convenient usage of momentum updater. - # Since this is not applicable for - # `CosineAnnealingMomentumUpdater`, - # the string will not be changed if it contains capital letters. - if policy_type == policy_type.lower(): - policy_type = policy_type.title() - hook_type = policy_type + 'MomentumUpdaterHook' - momentum_config['type'] = hook_type - hook = mmcv.build_from_cfg(momentum_config, HOOKS) - else: - hook = momentum_config - self.register_hook(hook) - - def register_optimizer_hook(self, optimizer_config): - if optimizer_config is None: - return - if isinstance(optimizer_config, dict): - optimizer_config.setdefault('type', 'OptimizerHook') - hook = mmcv.build_from_cfg(optimizer_config, HOOKS) - else: - hook = optimizer_config - self.register_hook(hook) - - def register_checkpoint_hook(self, checkpoint_config): - if checkpoint_config is None: - return - if isinstance(checkpoint_config, dict): - checkpoint_config.setdefault('type', 'CheckpointHook') - hook = mmcv.build_from_cfg(checkpoint_config, HOOKS) - else: - hook = checkpoint_config - self.register_hook(hook) - - def register_logger_hooks(self, log_config): - if log_config is None: - return - log_interval = log_config['interval'] - for info in log_config['hooks']: - logger_hook = mmcv.build_from_cfg( - info, HOOKS, default_args=dict(interval=log_interval)) - self.register_hook(logger_hook, priority='VERY_LOW') - - def register_training_hooks(self, - lr_config, - optimizer_config=None, - checkpoint_config=None, - log_config=None, - momentum_config=None): - """Register default hooks for training. - - Default hooks include: - - - LrUpdaterHook - - MomentumUpdaterHook - - OptimizerStepperHook - - CheckpointSaverHook - - IterTimerHook - - LoggerHook(s) - """ - self.register_lr_hook(lr_config) - self.register_momentum_hook(momentum_config) - self.register_optimizer_hook(optimizer_config) - self.register_checkpoint_hook(checkpoint_config) - # self.register_hook(IterTimerHook()) # changed by jyl - self.register_hook(self.iter_timer_hook) - self.register_logger_hooks(log_config) +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import logging +import os.path as osp +import warnings +from abc import ABCMeta, abstractmethod + +import torch +from torch.optim import Optimizer + +import mmcv +from ..parallel import is_module_wrapper +from .checkpoint import load_checkpoint +from .dist_utils import get_dist_info +from .hooks import HOOKS, Hook, IterTimerHook +from .log_buffer import LogBuffer +from .priority import get_priority +from .utils import get_time_str + + +class BaseRunner(metaclass=ABCMeta): + """The base class of Runner, a training helper for PyTorch. + + All subclasses should implement the following APIs: + + - ``run()`` + - ``train()`` + - ``val()`` + - ``save_checkpoint()`` + + Args: + model (:obj:`torch.nn.Module`): The model to be run. + batch_processor (callable): A callable method that process a data + batch. The interface of this method should be + `batch_processor(model, data, train_mode) -> dict` + optimizer (dict or :obj:`torch.optim.Optimizer`): It can be either an + optimizer (in most cases) or a dict of optimizers (in models that + requires more than one optimizer, e.g., GAN). + work_dir (str, optional): The working directory to save checkpoints + and logs. Defaults to None. + logger (:obj:`logging.Logger`): Logger used during training. + Defaults to None. (The default value is just for backward + compatibility) + meta (dict | None): A dict records some import information such as + environment info and seed, which will be logged in logger hook. + Defaults to None. + max_epochs (int, optional): Total training epochs. + max_iters (int, optional): Total training iterations. + """ + + def __init__(self, + model, + batch_processor=None, + optimizer=None, + work_dir=None, + logger=None, + meta=None, + max_iters=None, + max_epochs=None, + samples_per_gpu=2, # added by jyl + num_of_gpus=8): # added by jyl + if batch_processor is not None: + if not callable(batch_processor): + raise TypeError('batch_processor must be callable, ' + f'but got {type(batch_processor)}') + warnings.warn('batch_processor is deprecated, please implement ' + 'train_step() and val_step() in the model instead.') + # raise an error is `batch_processor` is not None and + # `model.train_step()` exists. + if is_module_wrapper(model): + _model = model.module + else: + _model = model + if hasattr(_model, 'train_step') or hasattr(_model, 'val_step'): + raise RuntimeError( + 'batch_processor and model.train_step()/model.val_step() ' + 'cannot be both available.') + else: + assert hasattr(model, 'train_step') + + # check the type of `optimizer` + if isinstance(optimizer, dict): + for name, optim in optimizer.items(): + if not isinstance(optim, Optimizer): + raise TypeError( + f'optimizer must be a dict of torch.optim.Optimizers, ' + f'but optimizer["{name}"] is a {type(optim)}') + elif not isinstance(optimizer, Optimizer) and optimizer is not None: + raise TypeError( + f'optimizer must be a torch.optim.Optimizer object ' + f'or dict or None, but got {type(optimizer)}') + + # check the type of `logger` + if not isinstance(logger, logging.Logger): + raise TypeError(f'logger must be a logging.Logger object, ' + f'but got {type(logger)}') + + # check the type of `meta` + if meta is not None and not isinstance(meta, dict): + raise TypeError( + f'meta must be a dict or None, but got {type(meta)}') + + self.model = model + self.batch_processor = batch_processor + self.optimizer = optimizer + self.logger = logger + self.meta = meta + self.samples_per_gpu = samples_per_gpu # added by jyl + self.num_of_gpus = num_of_gpus # added by jyl + + # create work_dir + if mmcv.is_str(work_dir): + self.work_dir = osp.abspath(work_dir) + mmcv.mkdir_or_exist(self.work_dir) + elif work_dir is None: + self.work_dir = None + else: + raise TypeError('"work_dir" must be a str or None') + + # get model name from the model class + if hasattr(self.model, 'module'): + self._model_name = self.model.module.__class__.__name__ + else: + self._model_name = self.model.__class__.__name__ + + self._rank, self._world_size = get_dist_info() + self.timestamp = get_time_str() + self.mode = None + self._hooks = [] + self._epoch = 0 + self._iter = 0 + self._inner_iter = 0 + + if max_epochs is not None and max_iters is not None: + raise ValueError( + 'Only one of `max_epochs` or `max_iters` can be set.') + + self._max_epochs = max_epochs + self._max_iters = max_iters + # TODO: Redesign LogBuffer, it is not flexible and elegant enough + self.log_buffer = LogBuffer() + + self.iter_timer_hook = IterTimerHook() # added by jyl + + @property + def model_name(self): + """str: Name of the model, usually the module class name.""" + return self._model_name + + @property + def rank(self): + """int: Rank of current process. (distributed training)""" + return self._rank + + @property + def world_size(self): + """int: Number of processes participating in the job. + (distributed training)""" + return self._world_size + + @property + def hooks(self): + """list[:obj:`Hook`]: A list of registered hooks.""" + return self._hooks + + @property + def epoch(self): + """int: Current epoch.""" + return self._epoch + + @property + def iter(self): + """int: Current iteration.""" + return self._iter + + @property + def inner_iter(self): + """int: Iteration in an epoch.""" + return self._inner_iter + + @property + def max_epochs(self): + """int: Maximum training epochs.""" + return self._max_epochs + + @property + def max_iters(self): + """int: Maximum training iterations.""" + return self._max_iters + + @abstractmethod + def train(self): + pass + + @abstractmethod + def val(self): + pass + + @abstractmethod + def run(self, data_loaders, workflow, **kwargs): + pass + + @abstractmethod + def save_checkpoint(self, + out_dir, + filename_tmpl, + save_optimizer=True, + meta=None, + create_symlink=True): + pass + + def current_lr(self): + """Get current learning rates. + + Returns: + list[float] | dict[str, list[float]]: Current learning rates of all + param groups. If the runner has a dict of optimizers, this + method will return a dict. + """ + if isinstance(self.optimizer, torch.optim.Optimizer): + lr = [group['lr'] for group in self.optimizer.param_groups] + elif isinstance(self.optimizer, dict): + lr = dict() + for name, optim in self.optimizer.items(): + lr[name] = [group['lr'] for group in optim.param_groups] + else: + raise RuntimeError( + 'lr is not applicable because optimizer does not exist.') + return lr + + def current_momentum(self): + """Get current momentums. + + Returns: + list[float] | dict[str, list[float]]: Current momentums of all + param groups. If the runner has a dict of optimizers, this + method will return a dict. + """ + + def _get_momentum(optimizer): + momentums = [] + for group in optimizer.param_groups: + if 'momentum' in group.keys(): + momentums.append(group['momentum']) + elif 'betas' in group.keys(): + momentums.append(group['betas'][0]) + else: + momentums.append(0) + return momentums + + if self.optimizer is None: + raise RuntimeError( + 'momentum is not applicable because optimizer does not exist.') + elif isinstance(self.optimizer, torch.optim.Optimizer): + momentums = _get_momentum(self.optimizer) + elif isinstance(self.optimizer, dict): + momentums = dict() + for name, optim in self.optimizer.items(): + momentums[name] = _get_momentum(optim) + return momentums + + def register_hook(self, hook, priority='NORMAL'): + """Register a hook into the hook list. + + The hook will be inserted into a priority queue, with the specified + priority (See :class:`Priority` for details of priorities). + For hooks with the same priority, they will be triggered in the same + order as they are registered. + + Args: + hook (:obj:`Hook`): The hook to be registered. + priority (int or str or :obj:`Priority`): Hook priority. + Lower value means higher priority. + """ + assert isinstance(hook, Hook) + if hasattr(hook, 'priority'): + raise ValueError('"priority" is a reserved attribute for hooks') + priority = get_priority(priority) + hook.priority = priority + # insert the hook to a sorted list + inserted = False + for i in range(len(self._hooks) - 1, -1, -1): + if priority >= self._hooks[i].priority: + self._hooks.insert(i + 1, hook) + inserted = True + break + if not inserted: + self._hooks.insert(0, hook) + + def register_hook_from_cfg(self, hook_cfg): + """Register a hook from its cfg. + + Args: + hook_cfg (dict): Hook config. It should have at least keys 'type' + and 'priority' indicating its type and priority. + + Notes: + The specific hook class to register should not use 'type' and + 'priority' arguments during initialization. + """ + hook_cfg = hook_cfg.copy() + priority = hook_cfg.pop('priority', 'NORMAL') + hook = mmcv.build_from_cfg(hook_cfg, HOOKS) + self.register_hook(hook, priority=priority) + + def call_hook(self, fn_name): + """Call all hooks. + + Args: + fn_name (str): The function name in each hook to be called, such as + "before_train_epoch". + """ + for hook in self._hooks: + getattr(hook, fn_name)(self) + + def load_checkpoint(self, filename, map_location='cpu', strict=False): + self.logger.info('load checkpoint from %s', filename) + return load_checkpoint(self.model, filename, map_location, strict, + self.logger) + + def resume(self, + checkpoint, + resume_optimizer=True, + map_location='default'): + if map_location == 'default': + if torch.cuda.is_available(): + device_id = torch.cuda.current_device() + checkpoint = self.load_checkpoint( + checkpoint, + map_location=lambda storage, loc: storage.cuda(device_id)) + else: + checkpoint = self.load_checkpoint(checkpoint) + else: + checkpoint = self.load_checkpoint( + checkpoint, map_location=map_location) + + self._epoch = checkpoint['meta']['epoch'] + self._iter = checkpoint['meta']['iter'] + if 'optimizer' in checkpoint and resume_optimizer: + if isinstance(self.optimizer, Optimizer): + self.optimizer.load_state_dict(checkpoint['optimizer']) + elif isinstance(self.optimizer, dict): + for k in self.optimizer.keys(): + self.optimizer[k].load_state_dict( + checkpoint['optimizer'][k]) + else: + raise TypeError( + 'Optimizer should be dict or torch.optim.Optimizer ' + f'but got {type(self.optimizer)}') + + self.logger.info('resumed epoch %d, iter %d', self.epoch, self.iter) + + def register_lr_hook(self, lr_config): + if isinstance(lr_config, dict): + assert 'policy' in lr_config + policy_type = lr_config.pop('policy') + # If the type of policy is all in lower case, e.g., 'cyclic', + # then its first letter will be capitalized, e.g., to be 'Cyclic'. + # This is for the convenient usage of Lr updater. + # Since this is not applicable for ` + # CosineAnnealingLrUpdater`, + # the string will not be changed if it contains capital letters. + if policy_type == policy_type.lower(): + policy_type = policy_type.title() + hook_type = policy_type + 'LrUpdaterHook' + lr_config['type'] = hook_type + hook = mmcv.build_from_cfg(lr_config, HOOKS) + else: + hook = lr_config + self.register_hook(hook) + + def register_momentum_hook(self, momentum_config): + if momentum_config is None: + return + if isinstance(momentum_config, dict): + assert 'policy' in momentum_config + policy_type = momentum_config.pop('policy') + # If the type of policy is all in lower case, e.g., 'cyclic', + # then its first letter will be capitalized, e.g., to be 'Cyclic'. + # This is for the convenient usage of momentum updater. + # Since this is not applicable for + # `CosineAnnealingMomentumUpdater`, + # the string will not be changed if it contains capital letters. + if policy_type == policy_type.lower(): + policy_type = policy_type.title() + hook_type = policy_type + 'MomentumUpdaterHook' + momentum_config['type'] = hook_type + hook = mmcv.build_from_cfg(momentum_config, HOOKS) + else: + hook = momentum_config + self.register_hook(hook) + + def register_optimizer_hook(self, optimizer_config): + if optimizer_config is None: + return + if isinstance(optimizer_config, dict): + optimizer_config.setdefault('type', 'OptimizerHook') + hook = mmcv.build_from_cfg(optimizer_config, HOOKS) + else: + hook = optimizer_config + self.register_hook(hook) + + def register_checkpoint_hook(self, checkpoint_config): + if checkpoint_config is None: + return + if isinstance(checkpoint_config, dict): + checkpoint_config.setdefault('type', 'CheckpointHook') + hook = mmcv.build_from_cfg(checkpoint_config, HOOKS) + else: + hook = checkpoint_config + self.register_hook(hook) + + def register_logger_hooks(self, log_config): + if log_config is None: + return + log_interval = log_config['interval'] + for info in log_config['hooks']: + logger_hook = mmcv.build_from_cfg( + info, HOOKS, default_args=dict(interval=log_interval)) + self.register_hook(logger_hook, priority='VERY_LOW') + + def register_training_hooks(self, + lr_config, + optimizer_config=None, + checkpoint_config=None, + log_config=None, + momentum_config=None): + """Register default hooks for training. + + Default hooks include: + + - LrUpdaterHook + - MomentumUpdaterHook + - OptimizerStepperHook + - CheckpointSaverHook + - IterTimerHook + - LoggerHook(s) + """ + self.register_lr_hook(lr_config) + self.register_momentum_hook(momentum_config) + self.register_optimizer_hook(optimizer_config) + self.register_checkpoint_hook(checkpoint_config) + # self.register_hook(IterTimerHook()) # changed by jyl + self.register_hook(self.iter_timer_hook) + self.register_logger_hooks(log_config) diff --git a/PyTorch/contrib/cv/detection/FCOS/mmcv_need/epoch_based_runner.py b/PyTorch/contrib/cv/detection/FCOS/mmcv_need/epoch_based_runner.py index 33e5ab36f2..0700575b0f 100644 --- a/PyTorch/contrib/cv/detection/FCOS/mmcv_need/epoch_based_runner.py +++ b/PyTorch/contrib/cv/detection/FCOS/mmcv_need/epoch_based_runner.py @@ -1,223 +1,223 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ - -import os.path as osp -import platform -import shutil -import time -import warnings -import sys # myy add - -import torch - -import mmcv -from .base_runner import BaseRunner -from .builder import RUNNERS -from .checkpoint import save_checkpoint -from .utils import get_host_info - - -@RUNNERS.register_module() -class EpochBasedRunner(BaseRunner): - """Epoch-based Runner. - - This runner train models epoch by epoch. - """ - - def run_iter(self, data_batch, train_mode, **kwargs): - if self.batch_processor is not None: - outputs = self.batch_processor( - self.model, data_batch, train_mode=train_mode, **kwargs) - elif train_mode: - outputs = self.model.train_step(data_batch, self.optimizer, - **kwargs) - else: - outputs = self.model.val_step(data_batch, self.optimizer, **kwargs) - if not isinstance(outputs, dict): - raise TypeError('"batch_processor()" or "model.train_step()"' - 'and "model.val_step()" must return a dict') - if 'log_vars' in outputs: - self.log_buffer.update(outputs['log_vars'], outputs['num_samples']) - self.outputs = outputs - - def train(self, data_loader, **kwargs): - self.model.train() - self.mode = 'train' - self.data_loader = data_loader - self._max_iters = self._max_epochs * len(self.data_loader) - self.call_hook('before_train_epoch') - time.sleep(2) # Prevent possible deadlock during epoch transition - for i, data_batch in enumerate(self.data_loader): - self._inner_iter = i - # if i==50: - # with torch.autograd.profiler.profile(use_npu=True) as prof: - # self.call_hook('before_train_iter') - # self.run_iter(data_batch, train_mode=True) - # self.call_hook('after_train_iter') - # prof.export_chrome_trace("output.prof") - # else: - self.call_hook('before_train_iter') - self.run_iter(data_batch, train_mode=True) - self.call_hook('after_train_iter') - self._iter += 1 - # added by jyl - self.logger.info('FPS: ' + str(self.samples_per_gpu * self.num_of_gpus / self.iter_timer_hook.time_all * (len(self.data_loader) - 5))) - - self.call_hook('after_train_epoch') - self._epoch += 1 - - def val(self, data_loader, **kwargs): - self.model.eval() - self.mode = 'val' - self.data_loader = data_loader - self.call_hook('before_val_epoch') - time.sleep(2) # Prevent possible deadlock during epoch transition - for i, data_batch in enumerate(self.data_loader): - self._inner_iter = i - self.call_hook('before_val_iter') - with torch.no_grad(): - self.run_iter(data_batch, train_mode=False) - self.call_hook('after_val_iter') - - self.call_hook('after_val_epoch') - - def run(self, data_loaders, workflow, max_epochs=None, **kwargs): - """Start running. - - Args: - data_loaders (list[:obj:`DataLoader`]): Dataloaders for training - and validation. - workflow (list[tuple]): A list of (phase, epochs) to specify the - running order and epochs. E.g, [('train', 2), ('val', 1)] means - running 2 epochs for training and 1 epoch for validation, - iteratively. - """ - assert isinstance(data_loaders, list) - assert mmcv.is_list_of(workflow, tuple) - assert len(data_loaders) == len(workflow) - if max_epochs is not None: - warnings.warn( - 'setting max_epochs in run is deprecated, ' - 'please set max_epochs in runner_config', DeprecationWarning) - self._max_epochs = max_epochs - - assert self._max_epochs is not None, ( - 'max_epochs must be specified during instantiation') - - for i, flow in enumerate(workflow): - mode, epochs = flow - if mode == 'train': - self._max_iters = self._max_epochs * len(data_loaders[i]) - break - - work_dir = self.work_dir if self.work_dir is not None else 'NONE' - self.logger.info('Start running, host: %s, work_dir: %s', - get_host_info(), work_dir) - self.logger.info('workflow: %s, max: %d epochs', workflow, - self._max_epochs) - self.call_hook('before_run') - - while self.epoch < self._max_epochs: - for i, flow in enumerate(workflow): - mode, epochs = flow - if isinstance(mode, str): # self.train() - if not hasattr(self, mode): - raise ValueError( - f'runner has no method named "{mode}" to run an ' - 'epoch') - epoch_runner = getattr(self, mode) - else: - raise TypeError( - 'mode in workflow must be a str, but got {}'.format( - type(mode))) - - for _ in range(epochs): - if mode == 'train' and self.epoch >= self._max_epochs: - break - epoch_runner(data_loaders[i], **kwargs) - - time.sleep(1) # wait for some hooks like loggers to finish - self.call_hook('after_run') - - def save_checkpoint(self, - out_dir, - filename_tmpl='epoch_{}.pth', - save_optimizer=True, - meta=None, - create_symlink=True): - """Save the checkpoint. - - Args: - out_dir (str): The directory that checkpoints are saved. - filename_tmpl (str, optional): The checkpoint filename template, - which contains a placeholder for the epoch number. - Defaults to 'epoch_{}.pth'. - save_optimizer (bool, optional): Whether to save the optimizer to - the checkpoint. Defaults to True. - meta (dict, optional): The meta information to be saved in the - checkpoint. Defaults to None. - create_symlink (bool, optional): Whether to create a symlink - "latest.pth" to point to the latest checkpoint. - Defaults to True. - """ - if meta is None: - meta = dict(epoch=self.epoch + 1, iter=self.iter) - elif isinstance(meta, dict): - meta.update(epoch=self.epoch + 1, iter=self.iter) - else: - raise TypeError( - f'meta should be a dict or None, but got {type(meta)}') - if self.meta is not None: - meta.update(self.meta) - - filename = filename_tmpl.format(self.epoch + 1) - filepath = osp.join(out_dir, filename) - optimizer = self.optimizer if save_optimizer else None - save_checkpoint(self.model, filepath, optimizer=optimizer, meta=meta) - # in some environments, `os.symlink` is not supported, you may need to - # set `create_symlink` to False - if create_symlink: - dst_file = osp.join(out_dir, 'latest.pth') - if platform.system() != 'Windows': - mmcv.symlink(filename, dst_file) - else: - shutil.copy(filepath, dst_file) - - -@RUNNERS.register_module() -class Runner(EpochBasedRunner): - """Deprecated name of EpochBasedRunner.""" - - def __init__(self, *args, **kwargs): - warnings.warn( - 'Runner was deprecated, please use EpochBasedRunner instead') - super().__init__(*args, **kwargs) +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ + +import os.path as osp +import platform +import shutil +import time +import warnings +import sys # myy add + +import torch + +import mmcv +from .base_runner import BaseRunner +from .builder import RUNNERS +from .checkpoint import save_checkpoint +from .utils import get_host_info + + +@RUNNERS.register_module() +class EpochBasedRunner(BaseRunner): + """Epoch-based Runner. + + This runner train models epoch by epoch. + """ + + def run_iter(self, data_batch, train_mode, **kwargs): + if self.batch_processor is not None: + outputs = self.batch_processor( + self.model, data_batch, train_mode=train_mode, **kwargs) + elif train_mode: + outputs = self.model.train_step(data_batch, self.optimizer, + **kwargs) + else: + outputs = self.model.val_step(data_batch, self.optimizer, **kwargs) + if not isinstance(outputs, dict): + raise TypeError('"batch_processor()" or "model.train_step()"' + 'and "model.val_step()" must return a dict') + if 'log_vars' in outputs: + self.log_buffer.update(outputs['log_vars'], outputs['num_samples']) + self.outputs = outputs + + def train(self, data_loader, **kwargs): + self.model.train() + self.mode = 'train' + self.data_loader = data_loader + self._max_iters = self._max_epochs * len(self.data_loader) + self.call_hook('before_train_epoch') + time.sleep(2) # Prevent possible deadlock during epoch transition + for i, data_batch in enumerate(self.data_loader): + self._inner_iter = i + # if i==50: + # with torch.autograd.profiler.profile(use_npu=True) as prof: + # self.call_hook('before_train_iter') + # self.run_iter(data_batch, train_mode=True) + # self.call_hook('after_train_iter') + # prof.export_chrome_trace("output.prof") + # else: + self.call_hook('before_train_iter') + self.run_iter(data_batch, train_mode=True) + self.call_hook('after_train_iter') + self._iter += 1 + # added by jyl + self.logger.info('FPS: ' + str(self.samples_per_gpu * self.num_of_gpus / self.iter_timer_hook.time_all * (len(self.data_loader) - 5))) + + self.call_hook('after_train_epoch') + self._epoch += 1 + + def val(self, data_loader, **kwargs): + self.model.eval() + self.mode = 'val' + self.data_loader = data_loader + self.call_hook('before_val_epoch') + time.sleep(2) # Prevent possible deadlock during epoch transition + for i, data_batch in enumerate(self.data_loader): + self._inner_iter = i + self.call_hook('before_val_iter') + with torch.no_grad(): + self.run_iter(data_batch, train_mode=False) + self.call_hook('after_val_iter') + + self.call_hook('after_val_epoch') + + def run(self, data_loaders, workflow, max_epochs=None, **kwargs): + """Start running. + + Args: + data_loaders (list[:obj:`DataLoader`]): Dataloaders for training + and validation. + workflow (list[tuple]): A list of (phase, epochs) to specify the + running order and epochs. E.g, [('train', 2), ('val', 1)] means + running 2 epochs for training and 1 epoch for validation, + iteratively. + """ + assert isinstance(data_loaders, list) + assert mmcv.is_list_of(workflow, tuple) + assert len(data_loaders) == len(workflow) + if max_epochs is not None: + warnings.warn( + 'setting max_epochs in run is deprecated, ' + 'please set max_epochs in runner_config', DeprecationWarning) + self._max_epochs = max_epochs + + assert self._max_epochs is not None, ( + 'max_epochs must be specified during instantiation') + + for i, flow in enumerate(workflow): + mode, epochs = flow + if mode == 'train': + self._max_iters = self._max_epochs * len(data_loaders[i]) + break + + work_dir = self.work_dir if self.work_dir is not None else 'NONE' + self.logger.info('Start running, host: %s, work_dir: %s', + get_host_info(), work_dir) + self.logger.info('workflow: %s, max: %d epochs', workflow, + self._max_epochs) + self.call_hook('before_run') + + while self.epoch < self._max_epochs: + for i, flow in enumerate(workflow): + mode, epochs = flow + if isinstance(mode, str): # self.train() + if not hasattr(self, mode): + raise ValueError( + f'runner has no method named "{mode}" to run an ' + 'epoch') + epoch_runner = getattr(self, mode) + else: + raise TypeError( + 'mode in workflow must be a str, but got {}'.format( + type(mode))) + + for _ in range(epochs): + if mode == 'train' and self.epoch >= self._max_epochs: + break + epoch_runner(data_loaders[i], **kwargs) + + time.sleep(1) # wait for some hooks like loggers to finish + self.call_hook('after_run') + + def save_checkpoint(self, + out_dir, + filename_tmpl='epoch_{}.pth', + save_optimizer=True, + meta=None, + create_symlink=True): + """Save the checkpoint. + + Args: + out_dir (str): The directory that checkpoints are saved. + filename_tmpl (str, optional): The checkpoint filename template, + which contains a placeholder for the epoch number. + Defaults to 'epoch_{}.pth'. + save_optimizer (bool, optional): Whether to save the optimizer to + the checkpoint. Defaults to True. + meta (dict, optional): The meta information to be saved in the + checkpoint. Defaults to None. + create_symlink (bool, optional): Whether to create a symlink + "latest.pth" to point to the latest checkpoint. + Defaults to True. + """ + if meta is None: + meta = dict(epoch=self.epoch + 1, iter=self.iter) + elif isinstance(meta, dict): + meta.update(epoch=self.epoch + 1, iter=self.iter) + else: + raise TypeError( + f'meta should be a dict or None, but got {type(meta)}') + if self.meta is not None: + meta.update(self.meta) + + filename = filename_tmpl.format(self.epoch + 1) + filepath = osp.join(out_dir, filename) + optimizer = self.optimizer if save_optimizer else None + save_checkpoint(self.model, filepath, optimizer=optimizer, meta=meta) + # in some environments, `os.symlink` is not supported, you may need to + # set `create_symlink` to False + if create_symlink: + dst_file = osp.join(out_dir, 'latest.pth') + if platform.system() != 'Windows': + mmcv.symlink(filename, dst_file) + else: + shutil.copy(filepath, dst_file) + + +@RUNNERS.register_module() +class Runner(EpochBasedRunner): + """Deprecated name of EpochBasedRunner.""" + + def __init__(self, *args, **kwargs): + warnings.warn( + 'Runner was deprecated, please use EpochBasedRunner instead') + super().__init__(*args, **kwargs) diff --git a/PyTorch/contrib/cv/detection/FCOS/mmcv_need/iter_timer.py b/PyTorch/contrib/cv/detection/FCOS/mmcv_need/iter_timer.py index 0e89820c66..899293cb13 100644 --- a/PyTorch/contrib/cv/detection/FCOS/mmcv_need/iter_timer.py +++ b/PyTorch/contrib/cv/detection/FCOS/mmcv_need/iter_timer.py @@ -1,56 +1,56 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ - -import time - -from .hook import HOOKS, Hook - - -@HOOKS.register_module() -class IterTimerHook(Hook): - - def before_epoch(self, runner): - self.t = time.time() - self.skip_step = 0 # added by jyl - self.time_all = 0 # added by jyl - - def before_iter(self, runner): - runner.log_buffer.update({'data_time': time.time() - self.t}) - - def after_iter(self, runner): - # runner.log_buffer.update({'time': time.time() - self.t}) # annoated by jyl - cur_time = time.time() # added by jyl - runner.log_buffer.update({'time': cur_time - self.t}) # added by jyl - if self.skip_step >= 5: # added by jyl - self.time_all += cur_time - self.t # added by jyl - self.skip_step += 1 # added by jyl - self.t = time.time() +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ + +import time + +from .hook import HOOKS, Hook + + +@HOOKS.register_module() +class IterTimerHook(Hook): + + def before_epoch(self, runner): + self.t = time.time() + self.skip_step = 0 # added by jyl + self.time_all = 0 # added by jyl + + def before_iter(self, runner): + runner.log_buffer.update({'data_time': time.time() - self.t}) + + def after_iter(self, runner): + # runner.log_buffer.update({'time': time.time() - self.t}) # annoated by jyl + cur_time = time.time() # added by jyl + runner.log_buffer.update({'time': cur_time - self.t}) # added by jyl + if self.skip_step >= 5: # added by jyl + self.time_all += cur_time - self.t # added by jyl + self.skip_step += 1 # added by jyl + self.t = time.time() diff --git a/PyTorch/contrib/cv/detection/FCOS/modelarts/fcos_r50_caffe_fpn_4x4_1x_coco_new.py b/PyTorch/contrib/cv/detection/FCOS/modelarts/fcos_r50_caffe_fpn_4x4_1x_coco_new.py index b1acab0f43..917c30db91 100644 --- a/PyTorch/contrib/cv/detection/FCOS/modelarts/fcos_r50_caffe_fpn_4x4_1x_coco_new.py +++ b/PyTorch/contrib/cv/detection/FCOS/modelarts/fcos_r50_caffe_fpn_4x4_1x_coco_new.py @@ -1,138 +1,138 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -_base_ = [ - '../_base_/datasets/coco_detection.py', - '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' -] -# model settings -model = dict( - type='FCOS', - pretrained='open-mmlab://detectron/resnet50_caffe',#'open-mmlab://detectron/resnet50_caffe''torchvision://resnet50' myy change resnet50_caffe to resnet50 - backbone=dict( - type='ResNet', - depth=50, - num_stages=4, - out_indices=(0, 1, 2, 3), - frozen_stages=1, - norm_cfg=dict(type='BN', requires_grad=False), - norm_eval=True, - style='caffe'), - neck=dict( - type='FPN', - in_channels=[256, 512, 1024, 2048], - out_channels=256, - start_level=1, - add_extra_convs=True, - extra_convs_on_inputs=False, # use P5 - num_outs=5, - relu_before_extra_convs=True), - bbox_head=dict( - type='FCOSHead', - num_classes=5, #change class number - in_channels=256, - stacked_convs=4, - feat_channels=256, - strides=[8, 16, 32, 64, 128], - norm_cfg=None, - loss_cls=dict( - type='FocalLoss', - use_sigmoid=True, - gamma=2.0, - alpha=0.25, - loss_weight=1.0), - loss_bbox=dict(type='IoULoss', loss_weight=1.0), - loss_centerness=dict( - type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0))) - -classes = ('person', 'car', 'cat', 'dog', 'train') #change class name - -# training and testing settings -train_cfg = dict( - assigner=dict( - type='MaxIoUAssigner', - pos_iou_thr=0.5, - neg_iou_thr=0.4, - min_pos_iou=0, - ignore_iof_thr=-1), - allowed_border=-1, - pos_weight=-1, - debug=False) -test_cfg = dict( - nms_pre=1000, - min_bbox_size=0, - score_thr=0.05, - nms=dict(type='nms', iou_threshold=0.5), - max_per_img=100) -img_norm_cfg = dict( - mean=[102.9801, 115.9465, 122.7717], std=[1.0, 1.0, 1.0], to_rgb=False) -train_pipeline = [ - dict(type='LoadImageFromFile'), - dict(type='LoadAnnotations', with_bbox=True), - dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), - dict(type='RandomFlip', flip_ratio=0.5), - dict(type='Normalize', **img_norm_cfg), - dict(type='Pad', size_divisor=1344), # change 32 to 1344 - dict(type='DefaultFormatBundle'), - dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']), -] -test_pipeline = [ - dict(type='LoadImageFromFile'), - dict( - type='MultiScaleFlipAug', - img_scale=(1333, 800), - flip=False, - transforms=[ - dict(type='Resize', keep_ratio=True), - dict(type='RandomFlip'), - dict(type='Normalize', **img_norm_cfg), - dict(type='Pad', size_divisor=1344), # change 32 toto 1344 - dict(type='ImageToTensor', keys=['img']), - dict(type='Collect', keys=['img']), - ]) -] - -data = dict( - samples_per_gpu=2, # change 4 to 2 - workers_per_gpu=4, - train=dict(pipeline=train_pipeline,classes=classes), - val=dict(pipeline=test_pipeline,classes=classes), - test=dict(pipeline=test_pipeline,classes=classes)) -# optimizer -optimizer = dict( - lr=0.01, paramwise_cfg=dict(bias_lr_mult=2., bias_decay_mult=0.)) -optimizer_config = dict( - _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) -# learning policy -lr_config = dict( - policy='step', - warmup='constant', - warmup_iters=500, - warmup_ratio=1.0 / 3, - step=[8, 11]) -total_epochs = 12 -# add for print log -log_config = dict( - interval=50, - hooks=[ - dict(type='TextLoggerHook'), - # dict(type='TensorboardLoggerHook') -]) - -amp = True # add for apex -dist_params = dict(backend='hccl') # add for npu - - - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +_base_ = [ + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py' +] +# model settings +model = dict( + type='FCOS', + pretrained='open-mmlab://detectron/resnet50_caffe',#'open-mmlab://detectron/resnet50_caffe''torchvision://resnet50' myy change resnet50_caffe to resnet50 + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=False), + norm_eval=True, + style='caffe'), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + start_level=1, + add_extra_convs=True, + extra_convs_on_inputs=False, # use P5 + num_outs=5, + relu_before_extra_convs=True), + bbox_head=dict( + type='FCOSHead', + num_classes=5, #change class number + in_channels=256, + stacked_convs=4, + feat_channels=256, + strides=[8, 16, 32, 64, 128], + norm_cfg=None, + loss_cls=dict( + type='FocalLoss', + use_sigmoid=True, + gamma=2.0, + alpha=0.25, + loss_weight=1.0), + loss_bbox=dict(type='IoULoss', loss_weight=1.0), + loss_centerness=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0))) + +classes = ('person', 'car', 'cat', 'dog', 'train') #change class name + +# training and testing settings +train_cfg = dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.4, + min_pos_iou=0, + ignore_iof_thr=-1), + allowed_border=-1, + pos_weight=-1, + debug=False) +test_cfg = dict( + nms_pre=1000, + min_bbox_size=0, + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.5), + max_per_img=100) +img_norm_cfg = dict( + mean=[102.9801, 115.9465, 122.7717], std=[1.0, 1.0, 1.0], to_rgb=False) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict(type='Resize', img_scale=(1333, 800), keep_ratio=True), + dict(type='RandomFlip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=1344), # change 32 to 1344 + dict(type='DefaultFormatBundle'), + dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']), +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict( + type='MultiScaleFlipAug', + img_scale=(1333, 800), + flip=False, + transforms=[ + dict(type='Resize', keep_ratio=True), + dict(type='RandomFlip'), + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=1344), # change 32 toto 1344 + dict(type='ImageToTensor', keys=['img']), + dict(type='Collect', keys=['img']), + ]) +] + +data = dict( + samples_per_gpu=2, # change 4 to 2 + workers_per_gpu=4, + train=dict(pipeline=train_pipeline,classes=classes), + val=dict(pipeline=test_pipeline,classes=classes), + test=dict(pipeline=test_pipeline,classes=classes)) +# optimizer +optimizer = dict( + lr=0.01, paramwise_cfg=dict(bias_lr_mult=2., bias_decay_mult=0.)) +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) +# learning policy +lr_config = dict( + policy='step', + warmup='constant', + warmup_iters=500, + warmup_ratio=1.0 / 3, + step=[8, 11]) +total_epochs = 12 +# add for print log +log_config = dict( + interval=50, + hooks=[ + dict(type='TextLoggerHook'), + # dict(type='TensorboardLoggerHook') +]) + +amp = True # add for apex +dist_params = dict(backend='hccl') # add for npu + + + + diff --git a/PyTorch/contrib/cv/detection/FCOS/scripts/train_1p.sh b/PyTorch/contrib/cv/detection/FCOS/scripts/train_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/FCOS/scripts/train_8p.sh b/PyTorch/contrib/cv/detection/FCOS/scripts/train_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/FCOS/tools/dist_train.sh b/PyTorch/contrib/cv/detection/FCOS/tools/dist_train.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/FOTS/LICENSE b/PyTorch/contrib/cv/detection/FOTS/LICENSE index 185404d551..5b4cf39445 100644 --- a/PyTorch/contrib/cv/detection/FOTS/LICENSE +++ b/PyTorch/contrib/cv/detection/FOTS/LICENSE @@ -1,204 +1,204 @@ -Copyright 2018-2019 Open-MMLab. All rights reserved. -Copyright 2021 Huawei Technologies Co., Ltd - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018-2019 Open-MMLab. - - 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. +Copyright 2018-2019 Open-MMLab. All rights reserved. +Copyright 2021 Huawei Technologies Co., Ltd + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2019 Open-MMLab. + + 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. diff --git a/PyTorch/contrib/cv/detection/FOTS/README.md b/PyTorch/contrib/cv/detection/FOTS/README.md index e1dd7e515c..73e72d2fdd 100644 --- a/PyTorch/contrib/cv/detection/FOTS/README.md +++ b/PyTorch/contrib/cv/detection/FOTS/README.md @@ -1,60 +1,60 @@ -# FOTS: Fast Oriented Text Spotting with a Unified Network text detection branch reimplementation (PyTorch) -# − 参考实现: - ``` - url=https://github.com/Wovchena/text-detection-fots.pytorch - ``` - -## FOTS Detail - -A unified end-to-end trainable Fast Oriented TextSpotting (FOTS) network for simultaneous detection andrecognition, sharing computation and visual information among the two complementary tasks. - - -## Requirements - -- Install PyTorch ([pytorch.org](http://pytorch.org)) -- Install packages required -- Prepare dataset: 1. SynthText for pretrain - 2. ICDAR2015 for finetune - -## Training - -To train a model, run `train.py` with the desired model architecture -1. pretrain with SynthText for 9 epochs -2. finetune with ICDAR2015 for 583 epochs - -```bash -# training 1p pretrain accuracy -bash ./test/train_full_pretrain_1p.sh - -# training 1p finetune accuracy -bash ./test/train_full_finetune_1p.sh - -# training 1p performance -bash ./test/train_performance_1p.sh - -# training 8p pretrain accuracy -bash ./test/train_full_pretrain_8p.sh - -# training 8p finetune accuracy -bash ./test/train_full_finetune_8p.sh - -# training 8p performance -bash ./test/train_performance_8p.sh - -#test 8p accuracy -bash ./test/test_8p.sh - -#test 1p accuracy -bash ./test/test_1p.sh -``` - -Log path: - FOTS/*.log - - -## FOTS training result - -| Acc@1 | Recall | Hmean | FPS | Npu_nums | Epochs | AMP_Type | -| :------: | :------: | :------: | :------: | :------: | :------: | :------: | -| - | - | - | 16.101 | 1 | 20 | O2 | +# FOTS: Fast Oriented Text Spotting with a Unified Network text detection branch reimplementation (PyTorch) +# − 参考实现: + ``` + url=https://github.com/Wovchena/text-detection-fots.pytorch + ``` + +## FOTS Detail + +A unified end-to-end trainable Fast Oriented TextSpotting (FOTS) network for simultaneous detection andrecognition, sharing computation and visual information among the two complementary tasks. + + +## Requirements + +- Install PyTorch ([pytorch.org](http://pytorch.org)) +- Install packages required +- Prepare dataset: 1. SynthText for pretrain + 2. ICDAR2015 for finetune + +## Training + +To train a model, run `train.py` with the desired model architecture +1. pretrain with SynthText for 9 epochs +2. finetune with ICDAR2015 for 583 epochs + +```bash +# training 1p pretrain accuracy +bash ./test/train_full_pretrain_1p.sh + +# training 1p finetune accuracy +bash ./test/train_full_finetune_1p.sh + +# training 1p performance +bash ./test/train_performance_1p.sh + +# training 8p pretrain accuracy +bash ./test/train_full_pretrain_8p.sh + +# training 8p finetune accuracy +bash ./test/train_full_finetune_8p.sh + +# training 8p performance +bash ./test/train_performance_8p.sh + +#test 8p accuracy +bash ./test/test_8p.sh + +#test 1p accuracy +bash ./test/test_1p.sh +``` + +Log path: + FOTS/*.log + + +## FOTS training result + +| Acc@1 | Recall | Hmean | FPS | Npu_nums | Epochs | AMP_Type | +| :------: | :------: | :------: | :------: | :------: | :------: | :------: | +| - | - | - | 16.101 | 1 | 20 | O2 | | 85.046 | 78.864 | 81.838 | 77.614 | 8 | 583 | O2 | \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/FOTS/requirments.txt b/PyTorch/contrib/cv/detection/FOTS/requirments.txt index 1dadf1794e..b46f873769 100644 --- a/PyTorch/contrib/cv/detection/FOTS/requirments.txt +++ b/PyTorch/contrib/cv/detection/FOTS/requirments.txt @@ -1,5 +1,5 @@ -torch==1.5.0 -shapely==1.6.4.post2 -opencv-python==3.4.3.18 -tqdm==4.31.1 +torch==1.5.0 +shapely==1.6.4.post2 +opencv-python==3.4.3.18 +tqdm==4.31.1 Polygon3 \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/data/config/fsaf.pipeline b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/data/config/fsaf.pipeline old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/docker_start_infer.sh b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/docker_start_infer.sh index 07b61defd1..022ff22296 100644 --- a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/docker_start_infer.sh +++ b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/docker_start_infer.sh @@ -1,48 +1,48 @@ -#!/bin/bash - -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -docker_image=$1 -data_dir=$2 - -function show_help() { - echo "Usage: docker_start.sh docker_image data_dir" -} - -function param_check() { - if [ -z "${docker_image}" ]; then - echo "please input docker_image" - show_help - exit 1 - fi - - if [ -z "${data_dir}" ]; then - echo "please input data_dir" - show_help - exit 1 - fi -} - -param_check - -docker run -it \ - --device=/dev/davinci0 \ - --device=/dev/davinci_manager \ - --device=/dev/devmm_svm \ - --device=/dev/hisi_hdc \ - -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ - -v ${data_dir}:${data_dir} \ - ${docker_image} \ +#!/bin/bash + +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +docker_image=$1 +data_dir=$2 + +function show_help() { + echo "Usage: docker_start.sh docker_image data_dir" +} + +function param_check() { + if [ -z "${docker_image}" ]; then + echo "please input docker_image" + show_help + exit 1 + fi + + if [ -z "${data_dir}" ]; then + echo "please input data_dir" + show_help + exit 1 + fi +} + +param_check + +docker run -it \ + --device=/dev/davinci0 \ + --device=/dev/davinci_manager \ + --device=/dev/devmm_svm \ + --device=/dev/hisi_hdc \ + -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ + -v ${data_dir}:${data_dir} \ + ${docker_image} \ /bin/bash \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/CMakeLists.txt b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/CMakeLists.txt old mode 100755 new mode 100644 index d691679192..f03048071a --- a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/CMakeLists.txt +++ b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/CMakeLists.txt @@ -1,57 +1,57 @@ -cmake_minimum_required(VERSION 3.14.0) - -project(fsaf) - -set(TARGET fsaf) - -SET(CMAKE_BUILD_TYPE "Debug") -SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb") -SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall") - -add_definitions(-DENABLE_DVPP_INTERFACE) -add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) -add_definitions(-Dgoogle=mindxsdk_private) -add_compile_options(-std=c++11 -fPIE -fstack-protector-all -fPIC -Wall) -add_link_options(-Wl,-z,relro,-z,now,-z,noexecstack -s -pie) - -# Check environment variable -if(NOT DEFINED ENV{ASCEND_HOME}) - message(FATAL_ERROR "please define environment variable:ASCEND_HOME") -endif() -if(NOT DEFINED ENV{ASCEND_VERSION}) - message(WARNING "please define environment variable:ASCEND_VERSION") -endif() -if(NOT DEFINED ENV{ARCH_PATTERN}) - message(WARNING "please define environment variable:ARCH_PATTERN") -endif() - -set(ACL_INC_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/include) -set(ACL_LIB_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/lib64) - -set(MXBASE_ROOT_DIR $ENV{MX_SDK_HOME}) -set(MXBASE_INC ${MXBASE_ROOT_DIR}/include) -set(MXBASE_LIB_DIR ${MXBASE_ROOT_DIR}/lib) -set(MXBASE_POST_LIB_DIR ${MXBASE_ROOT_DIR}/lib/modelpostprocessors) -set(MXBASE_POST_PROCESS_DIR ${MXBASE_ROOT_DIR}/include/MxBase/postprocess/include) - - -if(DEFINED ENV{MXSDK_OPENSOURCE_DIR}) - set(OPENSOURCE_DIR $ENV{MXSDK_OPENSOURCE_DIR}) -else() - set(OPENSOURCE_DIR ${MXBASE_ROOT_DIR}/opensource) -endif() -include_directories(${ACL_INC_DIR}) -include_directories(${OPENSOURCE_DIR}/include) -include_directories(${OPENSOURCE_DIR}/include/opencv4) - -include_directories(${MXBASE_INC}) -include_directories(${MXBASE_POST_PROCESS_DIR}) -link_directories(${ACL_LIB_DIR}) -link_directories(${OPENSOURCE_DIR}/lib) -link_directories(${MXBASE_LIB_DIR}) -link_directories(${MXBASE_POST_LIB_DIR}) - -add_executable(${TARGET} ./src/main.cpp ./src/fsaf.cpp) -target_link_libraries(${TARGET} glog cpprest mxbase opencv_world stdc++fs) - -install(TARGETS ${TARGET} RUNTIME DESTINATION ${PROJECT_SOURCE_DIR}/) +cmake_minimum_required(VERSION 3.14.0) + +project(fsaf) + +set(TARGET fsaf) + +SET(CMAKE_BUILD_TYPE "Debug") +SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb") +SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall") + +add_definitions(-DENABLE_DVPP_INTERFACE) +add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) +add_definitions(-Dgoogle=mindxsdk_private) +add_compile_options(-std=c++11 -fPIE -fstack-protector-all -fPIC -Wall) +add_link_options(-Wl,-z,relro,-z,now,-z,noexecstack -s -pie) + +# Check environment variable +if(NOT DEFINED ENV{ASCEND_HOME}) + message(FATAL_ERROR "please define environment variable:ASCEND_HOME") +endif() +if(NOT DEFINED ENV{ASCEND_VERSION}) + message(WARNING "please define environment variable:ASCEND_VERSION") +endif() +if(NOT DEFINED ENV{ARCH_PATTERN}) + message(WARNING "please define environment variable:ARCH_PATTERN") +endif() + +set(ACL_INC_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/include) +set(ACL_LIB_DIR $ENV{ASCEND_HOME}/$ENV{ASCEND_VERSION}/$ENV{ARCH_PATTERN}/acllib/lib64) + +set(MXBASE_ROOT_DIR $ENV{MX_SDK_HOME}) +set(MXBASE_INC ${MXBASE_ROOT_DIR}/include) +set(MXBASE_LIB_DIR ${MXBASE_ROOT_DIR}/lib) +set(MXBASE_POST_LIB_DIR ${MXBASE_ROOT_DIR}/lib/modelpostprocessors) +set(MXBASE_POST_PROCESS_DIR ${MXBASE_ROOT_DIR}/include/MxBase/postprocess/include) + + +if(DEFINED ENV{MXSDK_OPENSOURCE_DIR}) + set(OPENSOURCE_DIR $ENV{MXSDK_OPENSOURCE_DIR}) +else() + set(OPENSOURCE_DIR ${MXBASE_ROOT_DIR}/opensource) +endif() +include_directories(${ACL_INC_DIR}) +include_directories(${OPENSOURCE_DIR}/include) +include_directories(${OPENSOURCE_DIR}/include/opencv4) + +include_directories(${MXBASE_INC}) +include_directories(${MXBASE_POST_PROCESS_DIR}) +link_directories(${ACL_LIB_DIR}) +link_directories(${OPENSOURCE_DIR}/lib) +link_directories(${MXBASE_LIB_DIR}) +link_directories(${MXBASE_POST_LIB_DIR}) + +add_executable(${TARGET} ./src/main.cpp ./src/fsaf.cpp) +target_link_libraries(${TARGET} glog cpprest mxbase opencv_world stdc++fs) + +install(TARGETS ${TARGET} RUNTIME DESTINATION ${PROJECT_SOURCE_DIR}/) diff --git a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/build.sh b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/build.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/src/fsaf.cpp b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/src/fsaf.cpp old mode 100755 new mode 100644 index 36b7c50fb8..7ad6a69510 --- a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/src/fsaf.cpp +++ b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/src/fsaf.cpp @@ -1,427 +1,427 @@ -/* - * Copyright 2021 Huawei Technologies Co., Ltd - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - - * 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. - */ - -#include "fsaf.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "MxBase/DeviceManager/DeviceManager.h" -#include "MxBase/DvppWrapper/DvppWrapper.h" -#include "MxBase/Log/Log.h" - -using namespace MxBase; - -// Complete all initialization work. When you are going to -// use FSAF class, you should invoke this method immediately. -// -// you need construct InitParam object for Init. -APP_ERROR FSAF::Init(const InitParam& initParam) { - // initialize device - APP_ERROR ret = MxBase::DeviceManager::GetInstance()->InitDevices(); - if (ret != APP_ERR_OK) { - LogError << "Init devices failed, ret=" << ret << "."; - return ret; - } - // initialize context - ret = MxBase::TensorContext::GetInstance()->SetContext(initParam.deviceId); - if (ret != APP_ERR_OK) { - LogError << "Set context failed, ret=" << ret << "."; - return ret; - } - - // load model - model_ = std::make_shared(); - ret = model_->Init(initParam.modelPath, modelDesc_); - if (ret != APP_ERR_OK) { - LogError << "ModelInferenceProcessor init failed, ret=" << ret << "."; - return ret; - } - - return APP_ERR_OK; -} - -APP_ERROR FSAF::DeInit() { - model_->DeInit(); - MxBase::DeviceManager::GetInstance()->DestroyDevices(); - return APP_ERR_OK; -} - -// Get all files under a directory. -// Parameters: -// dirPath: the directory path -// Return: -// a vector of filename, including the suffix. -std::vector FSAF::GetFileList(const std::string &dirPath) { - struct dirent *ptr; - DIR *dir = opendir(dirPath.c_str()); - std::vector files; - while ((ptr = readdir(dir)) != NULL) { - if (ptr->d_name[0] == '.') { - continue; - } - files.push_back(ptr->d_name); - } - closedir(dir); - return files; -} - -// Read image from a image path. -// Parameters: -// imgPath: string of image path -// imageMat: opencv Mat object, for storging image as matrix -// height: int, storge the image height -// width: int, storge the image width -// Return: -// APP_ERROR object, if read image successfully, return APP_ERR_OK. -APP_ERROR FSAF::ReadImage(const std::string& imgPath, cv::Mat& imageMat, int& height, int& width) { - imageMat = cv::imread(imgPath, cv::IMREAD_COLOR); - - // BGR -> RGB - cv::cvtColor(imageMat, imageMat, cv::COLOR_BGR2RGB); - - width = imageMat.cols; - height = imageMat.rows; - - return APP_ERR_OK; -} - -// Resize image to fix size. -// We use RightDown padding style. -// Parameters: -// srcImageMat: source opencv Mat object, image matrix -// dstImageMat: storge destination opencv Mat object -// resizedImageInfo: contain infomation about the image, including before and after scaling -//Return: -// APP_ERROR object, if resize image successfully, return APP_ERR_OK. -APP_ERROR FSAF::ResizeImage(const cv::Mat& srcImageMat, cv::Mat& dstImageMat, - MxBase::ResizedImageInfo& resizedImageInfo) { - float resizeHeight = 800; - float resizeWidth = 1216; - float scale = std::min(resizeWidth / srcImageMat.cols, resizeHeight / srcImageMat.rows); - int new_width = srcImageMat.cols * scale; - int new_height = srcImageMat.rows * scale; - - // calculate the padding - int pad_w = resizeWidth - new_width; - int pad_h = resizeHeight - new_height; - - resizedImageInfo.heightOriginal = srcImageMat.rows; - resizedImageInfo.heightResize = resizeHeight; - resizedImageInfo.widthOriginal = srcImageMat.cols; - resizedImageInfo.widthResize = resizeWidth; - resizedImageInfo.resizeType = RESIZER_MS_KEEP_ASPECT_RATIO; - - // invoke opencv method to resize and pad - cv::resize(srcImageMat, dstImageMat, cv::Size(new_width, new_height), 0, 0, cv::INTER_CUBIC); - cv::copyMakeBorder(dstImageMat, dstImageMat, 0, pad_h, 0, pad_w, - cv::BorderTypes::BORDER_CONSTANT, cv::Scalar(0, 0, 0)); - - return APP_ERR_OK; -} - -APP_ERROR FSAF::Normalize(const cv::Mat &srcImageMat, cv::Mat &dstImageMat) -{ - constexpr size_t ALPHA_AND_BETA_SIZE = 3; - cv::Mat float32Mat; - srcImageMat.convertTo(float32Mat, CV_32FC3); - - std::vector tmp; - cv::split(float32Mat, tmp); - - const std::vector mean = {103.53, 116.28, 123.675}; - const std::vector std = {57.375, 57.120, 58.395}; - for (size_t i = 0; i < ALPHA_AND_BETA_SIZE; ++i) { - tmp[i].convertTo(tmp[i], CV_32FC3, 1 / std[i], - mean[i] / std[i]); - } - cv::merge(tmp, dstImageMat); - return APP_ERR_OK; -} - -// Convert Mat to Tensor. -// Parameters: -// imageMat: input image matrix -// tensorBase: storge image as tensor -// Return: -// APP_ERROR object, if convert image successfully, return APP_ERR_OK. -APP_ERROR FSAF::CVMatToTensorBase(const cv::Mat &imageMat, MxBase::TensorBase &tensorBase) { - // calculate the data size: width * height * depth - const uint32_t dataSize = imageMat.cols * imageMat.rows * imageMat.channels(); - // allocate memory - MemoryData memoryDataDst(dataSize, MemoryData::MEMORY_DEVICE, deviceId_); - MemoryData memoryDataSrc(imageMat.data, dataSize, MemoryData::MEMORY_HOST_MALLOC); - - APP_ERROR ret = MemoryHelper::MxbsMallocAndCopy(memoryDataDst, memoryDataSrc); - if (ret != APP_ERR_OK) { - LogError << GetError(ret) << "Memory malloc failed."; - return ret; - } - // get tensor shape - // std::vector shape = {imageMat.rows * YUV444_RGB_WIDTH_NU, static_cast(imageMat.cols)}; - std::vector shape = { - static_cast(imageMat.rows), - static_cast(imageMat.cols), - static_cast(imageMat.channels())}; - - // tensorBase = TensorBase(memoryDataDst, false, shape, TENSOR_DTYPE_UINT8); - tensorBase = TensorBase(memoryDataDst, false, shape, TENSOR_DTYPE_FLOAT32); - return APP_ERR_OK; -} - -// Model inference. -// Parameters: -// inputs: input image tensor -// outputs: result tensor of inference result -// Return: -// APP_ERROR object, if convert image successfully, return APP_ERR_OK. -APP_ERROR FSAF::Inference(const std::vector& inputs, std::vector& outputs) { - auto dtypes = model_->GetOutputDataType(); - - // modelDesc_ get the output tensor size through Init() - for (size_t i = 0; i < modelDesc_.outputTensors.size(); ++i) { - std::vector shape = {}; - for (size_t j = 0; j < modelDesc_.outputTensors[i].tensorDims.size(); ++j) { - shape.push_back((uint32_t)modelDesc_.outputTensors[i].tensorDims[j]); - } - TensorBase tensor(shape, dtypes[i], MemoryData::MemoryType::MEMORY_DEVICE, deviceId_); - APP_ERROR ret = TensorBase::TensorBaseMalloc(tensor); - if (ret != APP_ERR_OK) { - LogError << "TensorBaseMalloc failed, ret=" << ret << "."; - return ret; - } - outputs.push_back(tensor); - } - - DynamicInfo dynamicInfo = {}; - dynamicInfo.dynamicType = DynamicType::STATIC_BATCH; - - // infer the result according to the input tensor - APP_ERROR ret = model_->ModelInference(inputs, outputs, dynamicInfo); - if (ret != APP_ERR_OK) { - LogError << "ModelInference failed, ret=" << ret << "."; - return ret; - } - - return APP_ERR_OK; -} - -// Post process for inference result. -// Scale the bbox to the origin image size. -// Parameters: -// imgPath: input image path -// inputs: tensor of image after inference -// resultPath: the path of storaging infer_result -// height, width: image's height and width -// name: image name, not including suffix -// showPath: the path of storaging visualizition result -// Return: -// APP_ERROR object, if post process image successfully, return APP_ERR_OK. -APP_ERROR FSAF::PostProcess(const std::string& imgPath, std::vector& inputs, - const std::string &resultPath, int& height, int& width, const std::string& name, std::string &showPath) { - // object num - int tensor_size = 100; - - MxBase::TensorBase& tensor = inputs[1]; // 1*100 - - int ret = tensor.ToHost(); - if (ret != APP_ERR_OK) { - LogError << GetError(ret) << "Tensor_1 deploy to host failed."; - return ret; - } - std::vector shape = tensor.GetShape(); - - auto labels = reinterpret_cast(tensor.GetBuffer()); // 1*100 - - std::cout << "---------------------------labels---------------------------" << std::endl; - int label[tensor_size] = {0}; - for(int i = 0; i < tensor_size; i++){ - std::cout << labels[i] << " "; - label[i] = labels[i]; - } - - tensor = inputs[0]; // 1*100*5 - ret = tensor.ToHost(); - if (ret != APP_ERR_OK) { - LogError << GetError(ret) << "Tensor_0 deploy to host failed."; - return ret; - } - - auto bbox = reinterpret_cast(tensor.GetBuffer()); - std::cout << "\n---------------------------bboxes--------------------------" << std::endl; - for(int i = 0; i < tensor_size; i++){ - std::cout << bbox[i][0] << ", " << bbox[i][1] << ", " << bbox[i][2] << ", " - << bbox[i][3] << ", " << bbox[i][4] << std::endl; - } - - // get infer coordinates - float image_size_w = width; - float image_size_h = height; - float net_input_width = 1216; - float net_input_height = 800; - float scale = std::min(net_input_width / (float)width, net_input_height / (float)height); - - int new_width = image_size_w * scale; - - float n_scale = (float)new_width / image_size_w; - - // probability threshold and all classes for label - float prob_thres = 0.05; - std::vector classes = {"person", "bicycle", "car", "motorcycle", "airplane", "bus", - "train", "truck", "boat", "traffic light", "fire hydrant", - "stop sign", "parking meter", "bench", "bird", "cat", "dog", - "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", - "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", - "skis", "snowboard", "sports ball", "kite", "baseball bat", - "baseball glove", "skateboard", "surfboard", "tennis racket", - "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", - "banana", "apple", "sandwich", "orange", "broccoli", "carrot", - "hot dog", "pizza", "donut", "cake", "chair", "couch", - "potted plant", "bed", "dining table", "toilet", "tv", "laptop", - "mouse", "remote", "keyboard", "cell phone", "microwave", - "oven", "toaster", "sink", "refrigerator", "book", "clock", - "vase", "scissors", "teddy bear", "hair drier", "toothbrush"}; - - // storge bbox after post processing - float ppbox[tensor_size][5] = {0}; - - for (int j = 0; j < tensor_size; ++j) { - // scale bbox - ppbox[j][0] = (bbox[j][0]) / n_scale; - ppbox[j][1] = (bbox[j][1]) / n_scale; - ppbox[j][2] = (bbox[j][2]) / n_scale; - ppbox[j][3] = (bbox[j][3]) / n_scale; - ppbox[j][4] = bbox[j][4]; - // limit bbox in a valid range - ppbox[j][0] = std::max((float)0, ppbox[j][0]); - ppbox[j][1] = std::max((float)0, ppbox[j][1]); - ppbox[j][2] = std::min(image_size_w, ppbox[j][2]); - ppbox[j][3] = std::min(image_size_h, ppbox[j][3]); - } - - std::ofstream out(resultPath); - cv::Mat imgCur = cv::imread(imgPath); - - for (int j = 0; j < tensor_size; ++j) { - if(float(ppbox[j][4]) < float(prob_thres)) { - continue; - } - if(label[j] < 0 || label[j] > 80) { - continue; - } - - // standard the output result - std::string class_name = classes[int(label[j])]; - std::string det_results_str = ""; - std::ostringstream oss; - oss << ppbox[j][4]; - std::string confidence(oss.str()); - char strff1[21], strff2[21], strff3[21], strff4[21], strff0[21]; - memset(strff1, 0, sizeof(strff1)); - memset(strff2, 0, sizeof(strff2)); - memset(strff3, 0, sizeof(strff3)); - memset(strff4, 0, sizeof(strff4)); - memset(strff0, 0, sizeof(strff0)); - // print ppbox to char* - sprintf(strff0, "%.8f", ppbox[j][0]); - sprintf(strff1, "%.8f", ppbox[j][1]); - sprintf(strff2, "%.8f", ppbox[j][2]); - sprintf(strff3, "%.8f", ppbox[j][3]); - sprintf(strff4, "%.8f", ppbox[j][4]); - det_results_str = det_results_str + class_name + " " + strff4 + " " + strff0 + " " + strff1 + " " - + strff2 + " " + strff3 + "\n"; - - out << det_results_str; - std::cout << det_results_str; - // visualization on the origin image - cv::Point p3((ppbox[j][0]), (ppbox[j][1])); - cv::Point p4((ppbox[j][2]), (ppbox[j][3])); - cv::Scalar colorRectangle1(0, 255, 1); - int thicknessRectangle1 = 1; - cv::rectangle(imgCur, p3, p4, colorRectangle1, thicknessRectangle1); - cv::putText(imgCur, class_name + "|" + confidence, p3, cv::FONT_HERSHEY_SIMPLEX, - 0.5, colorRectangle1, 1, 1, false); - } - out.close(); - cv::imwrite(showPath + "/" + name + ".jpg", imgCur); - - return APP_ERR_OK; -} - -// Primary method for process all images. -APP_ERROR FSAF::Process(const std::string &dirPath, std::string &resultPath, std::string &showPath) { - std::vector dirFileList = GetFileList(dirPath); - std::vector names, paths; - // for debug counting - int i = 0; - // process every image - for(auto imgFile : dirFileList) { - std::string imgPath = dirPath + "/" + imgFile; - std::string name = imgFile.substr(0, imgFile.find(".")); - std::string subresultPath = resultPath + "/" + name + ".txt"; - - cv::Mat imageMat; - int height = 0; - int width = 0; - // get image infomation - APP_ERROR ret = ReadImage(imgPath, imageMat, height, width); - if (ret != APP_ERR_OK) { - LogError << "ReadImage failed, ret=" << ret << "."; - return ret; - } - // resize image and pad it - ResizedImageInfo resizedImageInfo; - ResizeImage(imageMat, imageMat, resizedImageInfo); - - // convert image matrix to tensor - TensorBase tensorBase; - ret = CVMatToTensorBase(imageMat, tensorBase); - if (ret != APP_ERR_OK) { - LogError << "CVMatToTensorBase failed, ret=" << ret << "."; - return ret; - } - - std::vector inputs = {}; - std::vector outputs = {}; - inputs.push_back(tensorBase); - // infer and get output tensor - ret = Inference(inputs, outputs); - if (ret != APP_ERR_OK) { - LogError << "Inference failed, ret=" << ret << "."; - return ret; - } - // post process the bbox to the origin image, - // and implement visualizition. - ret = PostProcess(imgPath, outputs, subresultPath, height, width, name, showPath); - if (ret != APP_ERR_OK) { - LogError << "PostProcess failed, ret=" << ret << "."; - return ret; - } - // add count - i++; - std::cout << i << std::endl; - } - - return APP_ERR_OK; - -} +/* + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + + * 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. + */ + +#include "fsaf.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "MxBase/DeviceManager/DeviceManager.h" +#include "MxBase/DvppWrapper/DvppWrapper.h" +#include "MxBase/Log/Log.h" + +using namespace MxBase; + +// Complete all initialization work. When you are going to +// use FSAF class, you should invoke this method immediately. +// +// you need construct InitParam object for Init. +APP_ERROR FSAF::Init(const InitParam& initParam) { + // initialize device + APP_ERROR ret = MxBase::DeviceManager::GetInstance()->InitDevices(); + if (ret != APP_ERR_OK) { + LogError << "Init devices failed, ret=" << ret << "."; + return ret; + } + // initialize context + ret = MxBase::TensorContext::GetInstance()->SetContext(initParam.deviceId); + if (ret != APP_ERR_OK) { + LogError << "Set context failed, ret=" << ret << "."; + return ret; + } + + // load model + model_ = std::make_shared(); + ret = model_->Init(initParam.modelPath, modelDesc_); + if (ret != APP_ERR_OK) { + LogError << "ModelInferenceProcessor init failed, ret=" << ret << "."; + return ret; + } + + return APP_ERR_OK; +} + +APP_ERROR FSAF::DeInit() { + model_->DeInit(); + MxBase::DeviceManager::GetInstance()->DestroyDevices(); + return APP_ERR_OK; +} + +// Get all files under a directory. +// Parameters: +// dirPath: the directory path +// Return: +// a vector of filename, including the suffix. +std::vector FSAF::GetFileList(const std::string &dirPath) { + struct dirent *ptr; + DIR *dir = opendir(dirPath.c_str()); + std::vector files; + while ((ptr = readdir(dir)) != NULL) { + if (ptr->d_name[0] == '.') { + continue; + } + files.push_back(ptr->d_name); + } + closedir(dir); + return files; +} + +// Read image from a image path. +// Parameters: +// imgPath: string of image path +// imageMat: opencv Mat object, for storging image as matrix +// height: int, storge the image height +// width: int, storge the image width +// Return: +// APP_ERROR object, if read image successfully, return APP_ERR_OK. +APP_ERROR FSAF::ReadImage(const std::string& imgPath, cv::Mat& imageMat, int& height, int& width) { + imageMat = cv::imread(imgPath, cv::IMREAD_COLOR); + + // BGR -> RGB + cv::cvtColor(imageMat, imageMat, cv::COLOR_BGR2RGB); + + width = imageMat.cols; + height = imageMat.rows; + + return APP_ERR_OK; +} + +// Resize image to fix size. +// We use RightDown padding style. +// Parameters: +// srcImageMat: source opencv Mat object, image matrix +// dstImageMat: storge destination opencv Mat object +// resizedImageInfo: contain infomation about the image, including before and after scaling +//Return: +// APP_ERROR object, if resize image successfully, return APP_ERR_OK. +APP_ERROR FSAF::ResizeImage(const cv::Mat& srcImageMat, cv::Mat& dstImageMat, + MxBase::ResizedImageInfo& resizedImageInfo) { + float resizeHeight = 800; + float resizeWidth = 1216; + float scale = std::min(resizeWidth / srcImageMat.cols, resizeHeight / srcImageMat.rows); + int new_width = srcImageMat.cols * scale; + int new_height = srcImageMat.rows * scale; + + // calculate the padding + int pad_w = resizeWidth - new_width; + int pad_h = resizeHeight - new_height; + + resizedImageInfo.heightOriginal = srcImageMat.rows; + resizedImageInfo.heightResize = resizeHeight; + resizedImageInfo.widthOriginal = srcImageMat.cols; + resizedImageInfo.widthResize = resizeWidth; + resizedImageInfo.resizeType = RESIZER_MS_KEEP_ASPECT_RATIO; + + // invoke opencv method to resize and pad + cv::resize(srcImageMat, dstImageMat, cv::Size(new_width, new_height), 0, 0, cv::INTER_CUBIC); + cv::copyMakeBorder(dstImageMat, dstImageMat, 0, pad_h, 0, pad_w, + cv::BorderTypes::BORDER_CONSTANT, cv::Scalar(0, 0, 0)); + + return APP_ERR_OK; +} + +APP_ERROR FSAF::Normalize(const cv::Mat &srcImageMat, cv::Mat &dstImageMat) +{ + constexpr size_t ALPHA_AND_BETA_SIZE = 3; + cv::Mat float32Mat; + srcImageMat.convertTo(float32Mat, CV_32FC3); + + std::vector tmp; + cv::split(float32Mat, tmp); + + const std::vector mean = {103.53, 116.28, 123.675}; + const std::vector std = {57.375, 57.120, 58.395}; + for (size_t i = 0; i < ALPHA_AND_BETA_SIZE; ++i) { + tmp[i].convertTo(tmp[i], CV_32FC3, 1 / std[i], - mean[i] / std[i]); + } + cv::merge(tmp, dstImageMat); + return APP_ERR_OK; +} + +// Convert Mat to Tensor. +// Parameters: +// imageMat: input image matrix +// tensorBase: storge image as tensor +// Return: +// APP_ERROR object, if convert image successfully, return APP_ERR_OK. +APP_ERROR FSAF::CVMatToTensorBase(const cv::Mat &imageMat, MxBase::TensorBase &tensorBase) { + // calculate the data size: width * height * depth + const uint32_t dataSize = imageMat.cols * imageMat.rows * imageMat.channels(); + // allocate memory + MemoryData memoryDataDst(dataSize, MemoryData::MEMORY_DEVICE, deviceId_); + MemoryData memoryDataSrc(imageMat.data, dataSize, MemoryData::MEMORY_HOST_MALLOC); + + APP_ERROR ret = MemoryHelper::MxbsMallocAndCopy(memoryDataDst, memoryDataSrc); + if (ret != APP_ERR_OK) { + LogError << GetError(ret) << "Memory malloc failed."; + return ret; + } + // get tensor shape + // std::vector shape = {imageMat.rows * YUV444_RGB_WIDTH_NU, static_cast(imageMat.cols)}; + std::vector shape = { + static_cast(imageMat.rows), + static_cast(imageMat.cols), + static_cast(imageMat.channels())}; + + // tensorBase = TensorBase(memoryDataDst, false, shape, TENSOR_DTYPE_UINT8); + tensorBase = TensorBase(memoryDataDst, false, shape, TENSOR_DTYPE_FLOAT32); + return APP_ERR_OK; +} + +// Model inference. +// Parameters: +// inputs: input image tensor +// outputs: result tensor of inference result +// Return: +// APP_ERROR object, if convert image successfully, return APP_ERR_OK. +APP_ERROR FSAF::Inference(const std::vector& inputs, std::vector& outputs) { + auto dtypes = model_->GetOutputDataType(); + + // modelDesc_ get the output tensor size through Init() + for (size_t i = 0; i < modelDesc_.outputTensors.size(); ++i) { + std::vector shape = {}; + for (size_t j = 0; j < modelDesc_.outputTensors[i].tensorDims.size(); ++j) { + shape.push_back((uint32_t)modelDesc_.outputTensors[i].tensorDims[j]); + } + TensorBase tensor(shape, dtypes[i], MemoryData::MemoryType::MEMORY_DEVICE, deviceId_); + APP_ERROR ret = TensorBase::TensorBaseMalloc(tensor); + if (ret != APP_ERR_OK) { + LogError << "TensorBaseMalloc failed, ret=" << ret << "."; + return ret; + } + outputs.push_back(tensor); + } + + DynamicInfo dynamicInfo = {}; + dynamicInfo.dynamicType = DynamicType::STATIC_BATCH; + + // infer the result according to the input tensor + APP_ERROR ret = model_->ModelInference(inputs, outputs, dynamicInfo); + if (ret != APP_ERR_OK) { + LogError << "ModelInference failed, ret=" << ret << "."; + return ret; + } + + return APP_ERR_OK; +} + +// Post process for inference result. +// Scale the bbox to the origin image size. +// Parameters: +// imgPath: input image path +// inputs: tensor of image after inference +// resultPath: the path of storaging infer_result +// height, width: image's height and width +// name: image name, not including suffix +// showPath: the path of storaging visualizition result +// Return: +// APP_ERROR object, if post process image successfully, return APP_ERR_OK. +APP_ERROR FSAF::PostProcess(const std::string& imgPath, std::vector& inputs, + const std::string &resultPath, int& height, int& width, const std::string& name, std::string &showPath) { + // object num + int tensor_size = 100; + + MxBase::TensorBase& tensor = inputs[1]; // 1*100 + + int ret = tensor.ToHost(); + if (ret != APP_ERR_OK) { + LogError << GetError(ret) << "Tensor_1 deploy to host failed."; + return ret; + } + std::vector shape = tensor.GetShape(); + + auto labels = reinterpret_cast(tensor.GetBuffer()); // 1*100 + + std::cout << "---------------------------labels---------------------------" << std::endl; + int label[tensor_size] = {0}; + for(int i = 0; i < tensor_size; i++){ + std::cout << labels[i] << " "; + label[i] = labels[i]; + } + + tensor = inputs[0]; // 1*100*5 + ret = tensor.ToHost(); + if (ret != APP_ERR_OK) { + LogError << GetError(ret) << "Tensor_0 deploy to host failed."; + return ret; + } + + auto bbox = reinterpret_cast(tensor.GetBuffer()); + std::cout << "\n---------------------------bboxes--------------------------" << std::endl; + for(int i = 0; i < tensor_size; i++){ + std::cout << bbox[i][0] << ", " << bbox[i][1] << ", " << bbox[i][2] << ", " + << bbox[i][3] << ", " << bbox[i][4] << std::endl; + } + + // get infer coordinates + float image_size_w = width; + float image_size_h = height; + float net_input_width = 1216; + float net_input_height = 800; + float scale = std::min(net_input_width / (float)width, net_input_height / (float)height); + + int new_width = image_size_w * scale; + + float n_scale = (float)new_width / image_size_w; + + // probability threshold and all classes for label + float prob_thres = 0.05; + std::vector classes = {"person", "bicycle", "car", "motorcycle", "airplane", "bus", + "train", "truck", "boat", "traffic light", "fire hydrant", + "stop sign", "parking meter", "bench", "bird", "cat", "dog", + "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", + "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", + "skis", "snowboard", "sports ball", "kite", "baseball bat", + "baseball glove", "skateboard", "surfboard", "tennis racket", + "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", + "banana", "apple", "sandwich", "orange", "broccoli", "carrot", + "hot dog", "pizza", "donut", "cake", "chair", "couch", + "potted plant", "bed", "dining table", "toilet", "tv", "laptop", + "mouse", "remote", "keyboard", "cell phone", "microwave", + "oven", "toaster", "sink", "refrigerator", "book", "clock", + "vase", "scissors", "teddy bear", "hair drier", "toothbrush"}; + + // storge bbox after post processing + float ppbox[tensor_size][5] = {0}; + + for (int j = 0; j < tensor_size; ++j) { + // scale bbox + ppbox[j][0] = (bbox[j][0]) / n_scale; + ppbox[j][1] = (bbox[j][1]) / n_scale; + ppbox[j][2] = (bbox[j][2]) / n_scale; + ppbox[j][3] = (bbox[j][3]) / n_scale; + ppbox[j][4] = bbox[j][4]; + // limit bbox in a valid range + ppbox[j][0] = std::max((float)0, ppbox[j][0]); + ppbox[j][1] = std::max((float)0, ppbox[j][1]); + ppbox[j][2] = std::min(image_size_w, ppbox[j][2]); + ppbox[j][3] = std::min(image_size_h, ppbox[j][3]); + } + + std::ofstream out(resultPath); + cv::Mat imgCur = cv::imread(imgPath); + + for (int j = 0; j < tensor_size; ++j) { + if(float(ppbox[j][4]) < float(prob_thres)) { + continue; + } + if(label[j] < 0 || label[j] > 80) { + continue; + } + + // standard the output result + std::string class_name = classes[int(label[j])]; + std::string det_results_str = ""; + std::ostringstream oss; + oss << ppbox[j][4]; + std::string confidence(oss.str()); + char strff1[21], strff2[21], strff3[21], strff4[21], strff0[21]; + memset(strff1, 0, sizeof(strff1)); + memset(strff2, 0, sizeof(strff2)); + memset(strff3, 0, sizeof(strff3)); + memset(strff4, 0, sizeof(strff4)); + memset(strff0, 0, sizeof(strff0)); + // print ppbox to char* + sprintf(strff0, "%.8f", ppbox[j][0]); + sprintf(strff1, "%.8f", ppbox[j][1]); + sprintf(strff2, "%.8f", ppbox[j][2]); + sprintf(strff3, "%.8f", ppbox[j][3]); + sprintf(strff4, "%.8f", ppbox[j][4]); + det_results_str = det_results_str + class_name + " " + strff4 + " " + strff0 + " " + strff1 + " " + + strff2 + " " + strff3 + "\n"; + + out << det_results_str; + std::cout << det_results_str; + // visualization on the origin image + cv::Point p3((ppbox[j][0]), (ppbox[j][1])); + cv::Point p4((ppbox[j][2]), (ppbox[j][3])); + cv::Scalar colorRectangle1(0, 255, 1); + int thicknessRectangle1 = 1; + cv::rectangle(imgCur, p3, p4, colorRectangle1, thicknessRectangle1); + cv::putText(imgCur, class_name + "|" + confidence, p3, cv::FONT_HERSHEY_SIMPLEX, + 0.5, colorRectangle1, 1, 1, false); + } + out.close(); + cv::imwrite(showPath + "/" + name + ".jpg", imgCur); + + return APP_ERR_OK; +} + +// Primary method for process all images. +APP_ERROR FSAF::Process(const std::string &dirPath, std::string &resultPath, std::string &showPath) { + std::vector dirFileList = GetFileList(dirPath); + std::vector names, paths; + // for debug counting + int i = 0; + // process every image + for(auto imgFile : dirFileList) { + std::string imgPath = dirPath + "/" + imgFile; + std::string name = imgFile.substr(0, imgFile.find(".")); + std::string subresultPath = resultPath + "/" + name + ".txt"; + + cv::Mat imageMat; + int height = 0; + int width = 0; + // get image infomation + APP_ERROR ret = ReadImage(imgPath, imageMat, height, width); + if (ret != APP_ERR_OK) { + LogError << "ReadImage failed, ret=" << ret << "."; + return ret; + } + // resize image and pad it + ResizedImageInfo resizedImageInfo; + ResizeImage(imageMat, imageMat, resizedImageInfo); + + // convert image matrix to tensor + TensorBase tensorBase; + ret = CVMatToTensorBase(imageMat, tensorBase); + if (ret != APP_ERR_OK) { + LogError << "CVMatToTensorBase failed, ret=" << ret << "."; + return ret; + } + + std::vector inputs = {}; + std::vector outputs = {}; + inputs.push_back(tensorBase); + // infer and get output tensor + ret = Inference(inputs, outputs); + if (ret != APP_ERR_OK) { + LogError << "Inference failed, ret=" << ret << "."; + return ret; + } + // post process the bbox to the origin image, + // and implement visualizition. + ret = PostProcess(imgPath, outputs, subresultPath, height, width, name, showPath); + if (ret != APP_ERR_OK) { + LogError << "PostProcess failed, ret=" << ret << "."; + return ret; + } + // add count + i++; + std::cout << i << std::endl; + } + + return APP_ERR_OK; + +} diff --git a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/src/fsaf.h b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/src/fsaf.h old mode 100755 new mode 100644 index 8f20a8db67..571154919d --- a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/src/fsaf.h +++ b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/src/fsaf.h @@ -1,65 +1,65 @@ -/* - * Copyright 2021 Huawei Technologies Co., Ltd - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - - * 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. - */ - -#ifndef UNET_SEGMENTATION_H -#define UNET_SEGMENTATION_H - -#include - -#include "MxBase/ModelInfer/ModelInferenceProcessor.h" -#include "MxBase/PostProcessBases/PostProcessDataType.h" -#include "MxBase/Tensor/TensorContext/TensorContext.h" - -// parameters struct for initialize Model -struct InitParam { - // npu device id - uint32_t deviceId; - // model path of .om - std::string modelPath; -}; - -// FSAF Model class -// Example: -// ... -// FSAF fsaf; -// APP_ERROR ret = fsaf.Init(initParam); -// ret = fsaf.Process(imgPath,resultPath,showPath); -// ... -// fsaf.DeInit(); -class FSAF { -public: - APP_ERROR Init(const InitParam &initParam); - APP_ERROR DeInit(); - APP_ERROR ReadImage(const std::string &imgPath, cv::Mat &imageMat, int& height, int& width); - APP_ERROR ResizeImage(const cv::Mat &srcImageMat, cv::Mat &dstImageMat, - MxBase::ResizedImageInfo &resziedImageInfo); - APP_ERROR CVMatToTensorBase(const cv::Mat &imageMat, MxBase::TensorBase &tensorBase); - APP_ERROR VectorToTensorBase(int* transMat, MxBase::TensorBase& tensorBase); - APP_ERROR Inference(const std::vector &inputs, std::vector &outputs); - APP_ERROR PostProcess(const std::string& imgPath, std::vector &inputs, - const std::string &subresultPath,int& height, int& width,const std::string& name,std::string &showPath); - APP_ERROR Process(const std::string &dirPath, std::string &resultPath, std::string &showPath); - APP_ERROR Normalize(const cv::Mat &srcImageMat, cv::Mat &dstImageMat); - -private: - std::shared_ptr model_; - MxBase::ModelDesc modelDesc_; - uint32_t deviceId_ = 0; - - std::vector GetFileList(const std::string &dirPath); -}; - -#endif +/* + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + + * 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. + */ + +#ifndef UNET_SEGMENTATION_H +#define UNET_SEGMENTATION_H + +#include + +#include "MxBase/ModelInfer/ModelInferenceProcessor.h" +#include "MxBase/PostProcessBases/PostProcessDataType.h" +#include "MxBase/Tensor/TensorContext/TensorContext.h" + +// parameters struct for initialize Model +struct InitParam { + // npu device id + uint32_t deviceId; + // model path of .om + std::string modelPath; +}; + +// FSAF Model class +// Example: +// ... +// FSAF fsaf; +// APP_ERROR ret = fsaf.Init(initParam); +// ret = fsaf.Process(imgPath,resultPath,showPath); +// ... +// fsaf.DeInit(); +class FSAF { +public: + APP_ERROR Init(const InitParam &initParam); + APP_ERROR DeInit(); + APP_ERROR ReadImage(const std::string &imgPath, cv::Mat &imageMat, int& height, int& width); + APP_ERROR ResizeImage(const cv::Mat &srcImageMat, cv::Mat &dstImageMat, + MxBase::ResizedImageInfo &resziedImageInfo); + APP_ERROR CVMatToTensorBase(const cv::Mat &imageMat, MxBase::TensorBase &tensorBase); + APP_ERROR VectorToTensorBase(int* transMat, MxBase::TensorBase& tensorBase); + APP_ERROR Inference(const std::vector &inputs, std::vector &outputs); + APP_ERROR PostProcess(const std::string& imgPath, std::vector &inputs, + const std::string &subresultPath,int& height, int& width,const std::string& name,std::string &showPath); + APP_ERROR Process(const std::string &dirPath, std::string &resultPath, std::string &showPath); + APP_ERROR Normalize(const cv::Mat &srcImageMat, cv::Mat &dstImageMat); + +private: + std::shared_ptr model_; + MxBase::ModelDesc modelDesc_; + uint32_t deviceId_ = 0; + + std::vector GetFileList(const std::string &dirPath); +}; + +#endif diff --git a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/src/main.cpp b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/src/main.cpp old mode 100755 new mode 100644 index 141ab3f167..4d85ce5862 --- a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/src/main.cpp +++ b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/mxbase/src/main.cpp @@ -1,53 +1,53 @@ -/* - * Copyright 2021 Huawei Technologies Co., Ltd - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - - * 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. - */ - -#include "fsaf.h" - -#include "MxBase/Log/Log.h" - -int main() { - // config the parameters for fsaf model - InitParam initParam = {}; - initParam.deviceId = 0; - initParam.modelPath = "../../data/model/fsaf.om"; - - // declare and initialize the fsaf model - FSAF fsaf; - APP_ERROR ret = fsaf.Init(initParam); - if (ret != APP_ERR_OK) { - LogError << "FSAF init failed, ret=" << ret << "."; - return ret; - } - - // coco2017 validation set for object detection - std::string imgPath = "../../data/input/val2017"; - - // directories for saving result - std::string outputPath = "../output/"; - std::string resultPath = outputPath + "infer_result"; - std::string showPath = outputPath + "show_result"; - - // call the process of fsaf model - ret = fsaf.Process(imgPath, resultPath, showPath); - if (ret != APP_ERR_OK) { - LogError << "FSAF process failed, ret=" << ret << "."; - fsaf.DeInit(); - return ret; - } - - fsaf.DeInit(); - return APP_ERR_OK; -} +/* + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + + * 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. + */ + +#include "fsaf.h" + +#include "MxBase/Log/Log.h" + +int main() { + // config the parameters for fsaf model + InitParam initParam = {}; + initParam.deviceId = 0; + initParam.modelPath = "../../data/model/fsaf.om"; + + // declare and initialize the fsaf model + FSAF fsaf; + APP_ERROR ret = fsaf.Init(initParam); + if (ret != APP_ERR_OK) { + LogError << "FSAF init failed, ret=" << ret << "."; + return ret; + } + + // coco2017 validation set for object detection + std::string imgPath = "../../data/input/val2017"; + + // directories for saving result + std::string outputPath = "../output/"; + std::string resultPath = outputPath + "infer_result"; + std::string showPath = outputPath + "show_result"; + + // call the process of fsaf model + ret = fsaf.Process(imgPath, resultPath, showPath); + if (ret != APP_ERR_OK) { + LogError << "FSAF process failed, ret=" << ret << "."; + fsaf.DeInit(); + return ret; + } + + fsaf.DeInit(); + return APP_ERR_OK; +} diff --git a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/sdk/run.sh b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/sdk/run.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/util/coco_eval.py b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/util/coco_eval.py old mode 100755 new mode 100644 index 92e70605ac..47904787ce --- a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/util/coco_eval.py +++ b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/util/coco_eval.py @@ -1,97 +1,97 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 argparse - -import argparse -import numpy as np -from pycocotools.coco import COCO -from pycocotools.cocoeval import COCOeval - -CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', - 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', - 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', - 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', - 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', - 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', - 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', - 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', - 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', - 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', - 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', - 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] - -def coco_evaluation(annotation_json, result_json): - cocoGt = COCO(annotation_json) - cocoDt = cocoGt.loadRes(result_json) - iou_thrs = np.linspace(.5, 0.95, int(np.round((0.95 - .5) / .05)) + 1, endpoint=True) - iou_type = 'bbox' - - cocoEval = COCOeval(cocoGt, cocoDt, iou_type) - cocoEval.params.catIds = cocoGt.getCatIds(catNms=CLASSES) - cocoEval.params.imgIds = cocoGt.getImgIds() - delete_id=[3661,70254,309391,374551,190007] - for did in delete_id: - cocoEval.params.imgIds.remove(did) - - cocoEval.params.maxDets = [100, 300, 1000] # proposal number for evaluating recalls/mAPs. - cocoEval.params.iouThrs = iou_thrs - - cocoEval.evaluate() - cocoEval.accumulate() - cocoEval.summarize() - - # mapping of cocoEval.stats - coco_metric_names = { - 'mAP': 0, - 'mAP_50': 1, - 'mAP_75': 2, - 'mAP_s': 3, - 'mAP_m': 4, - 'mAP_l': 5, - 'AR@100': 6, - 'AR@300': 7, - 'AR@1000': 8, - 'AR_s@1000': 9, - 'AR_m@1000': 10, - 'AR_l@1000': 11 - } - - metric_items = ['mAP', 'mAP_50', 'mAP_75', 'mAP_s', 'mAP_m', 'mAP_l'] - eval_results = {} - - for metric_item in metric_items: - key = f'bbox_{metric_item}' - val = float( - f'{cocoEval.stats[coco_metric_names[metric_item]]:.3f}' - ) - eval_results[key] = val - ap = cocoEval.stats[:6] - eval_results['bbox_mAP_copypaste'] = ( - f'{ap[0]:.3f} {ap[1]:.3f} {ap[2]:.3f} {ap[3]:.3f} ' - f'{ap[4]:.3f} {ap[5]:.3f}') - - return eval_results - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--ground_truth_file", default="../data/input/annotations/instances_val2017.json") - parser.add_argument("--detection_result_file", default="../sdk/output/coco_detection_result.json") - parser.add_argument("--eval_result_file", default="../sdk/output/eval_map_result.txt") - args = parser.parse_args() - result = coco_evaluation(args.ground_truth_file, args.detection_result_file) - print(result) - with open(args.eval_result_file, 'w') as f: - for key, value in result.items(): +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 argparse + +import argparse +import numpy as np +from pycocotools.coco import COCO +from pycocotools.cocoeval import COCOeval + +CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', + 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', + 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', + 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', + 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', + 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', + 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', + 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', + 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', + 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', + 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', + 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] + +def coco_evaluation(annotation_json, result_json): + cocoGt = COCO(annotation_json) + cocoDt = cocoGt.loadRes(result_json) + iou_thrs = np.linspace(.5, 0.95, int(np.round((0.95 - .5) / .05)) + 1, endpoint=True) + iou_type = 'bbox' + + cocoEval = COCOeval(cocoGt, cocoDt, iou_type) + cocoEval.params.catIds = cocoGt.getCatIds(catNms=CLASSES) + cocoEval.params.imgIds = cocoGt.getImgIds() + delete_id=[3661,70254,309391,374551,190007] + for did in delete_id: + cocoEval.params.imgIds.remove(did) + + cocoEval.params.maxDets = [100, 300, 1000] # proposal number for evaluating recalls/mAPs. + cocoEval.params.iouThrs = iou_thrs + + cocoEval.evaluate() + cocoEval.accumulate() + cocoEval.summarize() + + # mapping of cocoEval.stats + coco_metric_names = { + 'mAP': 0, + 'mAP_50': 1, + 'mAP_75': 2, + 'mAP_s': 3, + 'mAP_m': 4, + 'mAP_l': 5, + 'AR@100': 6, + 'AR@300': 7, + 'AR@1000': 8, + 'AR_s@1000': 9, + 'AR_m@1000': 10, + 'AR_l@1000': 11 + } + + metric_items = ['mAP', 'mAP_50', 'mAP_75', 'mAP_s', 'mAP_m', 'mAP_l'] + eval_results = {} + + for metric_item in metric_items: + key = f'bbox_{metric_item}' + val = float( + f'{cocoEval.stats[coco_metric_names[metric_item]]:.3f}' + ) + eval_results[key] = val + ap = cocoEval.stats[:6] + eval_results['bbox_mAP_copypaste'] = ( + f'{ap[0]:.3f} {ap[1]:.3f} {ap[2]:.3f} {ap[3]:.3f} ' + f'{ap[4]:.3f} {ap[5]:.3f}') + + return eval_results + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("--ground_truth_file", default="../data/input/annotations/instances_val2017.json") + parser.add_argument("--detection_result_file", default="../sdk/output/coco_detection_result.json") + parser.add_argument("--eval_result_file", default="../sdk/output/eval_map_result.txt") + args = parser.parse_args() + result = coco_evaluation(args.ground_truth_file, args.detection_result_file) + print(result) + with open(args.eval_result_file, 'w') as f: + for key, value in result.items(): f.write(key + ': ' + str(value) + '\n') \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/util/txt_to_json.py b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/util/txt_to_json.py old mode 100755 new mode 100644 index f713ec1c85..31fe719e3c --- a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/util/txt_to_json.py +++ b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/infer/util/txt_to_json.py @@ -1,113 +1,113 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 argparse - -import glob -import os -import sys -import argparse -import mmcv - -''' - 0,0 ------> x (width) - | - | (Left,Top) - | *_________ - | | | - | | - y |_________| - (height) * - (Right,Bottom) -''' -CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', - 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', - 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', - 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', - 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', - 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', - 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', - 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', - 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', - 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', - 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', - 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] - -cat_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, -24, 25, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, -48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 70, -72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90] - - -def file_lines_to_list(path): - # open txt file lines to a list - with open(path) as f: - content = f.readlines() - # remove whitespace characters like `\n` at the end of each line - content = [x.strip() for x in content] - return content - - -def error(msg): - print(msg) - sys.exit(0) - - -def get_predict_list(file_path, gt_classes): - dr_files_list = glob.glob(file_path + '/*.txt') - dr_files_list.sort() - - bounding_boxes = [] - for txt_file in dr_files_list: - file_id = txt_file.split(".txt", 1)[0] - file_id = os.path.basename(os.path.normpath(file_id)) - lines = file_lines_to_list(txt_file) - for line in lines: - try: - sl = line.split() - if len(sl) > 6: - class_name = sl[0] + ' ' + sl[1] - scores, left, top, right, bottom = sl[2:] - else: - class_name, scores, left, top, right, bottom = sl - if float(scores) < 0.05: - continue - except ValueError: - error_msg = "Error: File " + txt_file + " wrong format.\n" - error_msg += " Expected: \n" - error_msg += " Received: " + line - error(error_msg) - - # bbox = left + " " + top + " " + right + " " + bottom - left = float(left) - right = float(right) - top = float(top) - bottom = float(bottom) - bbox = [left, top, right-left, bottom-top] - bounding_boxes.append({"image_id": int(file_id), "bbox": bbox, - "score": float(scores), "category_id": cat_ids[CLASSES.index(class_name)]}) - # sort detection-results by decreasing scores - # bounding_boxes.sort(key=lambda x: float(x['score']), reverse=True) - return bounding_boxes - - -if __name__ == '__main__': - parser = argparse.ArgumentParser('mAp calculate') - parser.add_argument('--infer_result_path', default="../sdk/output/infer_result/", - help='the path of the predict result') - parser.add_argument("--json_output_filename", default="../sdk/output/coco_detection_result") - args = parser.parse_args() - - res_bbox = get_predict_list(args.infer_result_path, CLASSES) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 argparse + +import glob +import os +import sys +import argparse +import mmcv + +''' + 0,0 ------> x (width) + | + | (Left,Top) + | *_________ + | | | + | | + y |_________| + (height) * + (Right,Bottom) +''' +CLASSES = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', + 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', + 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', + 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', + 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', + 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', + 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', + 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', + 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', + 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', + 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', + 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] + +cat_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, +24, 25, 27, 28, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, +48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 70, +72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90] + + +def file_lines_to_list(path): + # open txt file lines to a list + with open(path) as f: + content = f.readlines() + # remove whitespace characters like `\n` at the end of each line + content = [x.strip() for x in content] + return content + + +def error(msg): + print(msg) + sys.exit(0) + + +def get_predict_list(file_path, gt_classes): + dr_files_list = glob.glob(file_path + '/*.txt') + dr_files_list.sort() + + bounding_boxes = [] + for txt_file in dr_files_list: + file_id = txt_file.split(".txt", 1)[0] + file_id = os.path.basename(os.path.normpath(file_id)) + lines = file_lines_to_list(txt_file) + for line in lines: + try: + sl = line.split() + if len(sl) > 6: + class_name = sl[0] + ' ' + sl[1] + scores, left, top, right, bottom = sl[2:] + else: + class_name, scores, left, top, right, bottom = sl + if float(scores) < 0.05: + continue + except ValueError: + error_msg = "Error: File " + txt_file + " wrong format.\n" + error_msg += " Expected: \n" + error_msg += " Received: " + line + error(error_msg) + + # bbox = left + " " + top + " " + right + " " + bottom + left = float(left) + right = float(right) + top = float(top) + bottom = float(bottom) + bbox = [left, top, right-left, bottom-top] + bounding_boxes.append({"image_id": int(file_id), "bbox": bbox, + "score": float(scores), "category_id": cat_ids[CLASSES.index(class_name)]}) + # sort detection-results by decreasing scores + # bounding_boxes.sort(key=lambda x: float(x['score']), reverse=True) + return bounding_boxes + + +if __name__ == '__main__': + parser = argparse.ArgumentParser('mAp calculate') + parser.add_argument('--infer_result_path', default="../sdk/output/infer_result/", + help='the path of the predict result') + parser.add_argument("--json_output_filename", default="../sdk/output/coco_detection_result") + args = parser.parse_args() + + res_bbox = get_predict_list(args.infer_result_path, CLASSES) mmcv.dump(res_bbox, args.json_output_filename + '.json') \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/mmdetection/tools/dist_train.sh b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/mmdetection/tools/dist_train.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/mmdetection/tools/slurm_test.sh b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/mmdetection/tools/slurm_test.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/mmdetection/tools/slurm_train.sh b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/mmdetection/tools/slurm_train.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/scripts/train_8p.sh b/PyTorch/contrib/cv/detection/FSAF_for_Pytorch/scripts/train_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/FaceBoxes/README.md b/PyTorch/contrib/cv/detection/FaceBoxes/README.md index ef40a2e1a1..b3677532f3 100644 --- a/PyTorch/contrib/cv/detection/FaceBoxes/README.md +++ b/PyTorch/contrib/cv/detection/FaceBoxes/README.md @@ -1,117 +1,117 @@ -# FaceBoxes - -本项目实现了FaceBoxes从GPU到NPU上训练的迁移,源开源代码仓[FaceBoxes.Pytorch](https://github.com/zisianw/FaceBoxes.PyTorch) - -## FaceBoxes Detail - -本项目对于FaceBoxes.Pytorch做出了如下更改: - -1. 将设备从Nvidia GPU迁移到Huawei NPU上。 -2. 在源代码的基础上添加了Apex混合精度进行优化。 -3. 在模型迁移到NPU上后一些不支持或性能较低的算子放到CPU上进行规避。 -4. 针对测试结果添加了新的评估脚本。 - -## Requirements - -```bash -pip install -r requirements.txt -``` - -- NPU 配套的run包安装 -- Python3.7.5 -- PyTorch(NPU版本) -- Apex(NPU版本) - -### 导入环境变量 - -```bash -source scripts/npu_set_env.sh -``` - -### 编译 - -```bash -git clone https://github.com/Levi0223/FDDB_Evaluation.git -cd FDDB_Evaluation -python3 setup.py build_ext --inplace -mv ../convert.py ../split.py ./ -``` - -### 准备数据集 -数据集下载参考源代码仓 - -1. 下载[WIDER_FACE](https://github.com/zisianw/FaceBoxes.PyTorch)数据集,将图片放在这个目录下(数据集包含32203张图片): - - ```bash - $FaceBoxes_ROOT/data/WIDER_FACE/images/ - ``` - - 下载转换后的[标注文件](https://github.com/zisianw/FaceBoxes.PyTorch),将他们放在这个目录下: - - ```bash - $FaceBoxes_ROOT/data/WIDER_FACE/annotations/ - ``` - - 最终数据集目录结构如下: - - ![输入图片说明](https://images.gitee.com/uploads/images/2021/0927/121855_9a16b40b_6515416.png "屏幕截图.png") - -2. 下载[FDDB](https://github.com/zisianw/FaceBoxes.PyTorch)数据集,将图片放在这个目录下(数据集包含2845张图片): - - ```bash - $FaceBoxes_ROOT/data/FDDB/images/ - ``` - - 最终数据集目录结构如下: - - ![输入图片说明](https://images.gitee.com/uploads/images/2021/0927/121924_9f00b12c_6515416.png "屏幕截图.png") - -## Trainning - -### 单卡性能评估 - -```bash -### 输出单卡FPS -bash scripts/train_performance_1p.sh -``` - -### 单卡训练 - -```bash -### 单卡全量训练 -bash scripts/train_1p.sh -## 日志文件在当前目录下的1p_train.log -``` - -### 多卡性能评估 - -```bash -### 输出多卡FPS -bash scripts/train_performance_8p.sh -``` - -### 多卡训练 - -```bash -### 多卡全量训练 -bash scripts/train_8p.sh -## 日志文件在当前目录下的8p_train.log -``` - -### Test - -```bash -### 测试训练得到的权重文件,生成FDDB_dets.txt -bash test.sh -## 日志文件在当前目录下的test.log -### 解析FDDB_dets.txt文件,打印最终精度 -bash eval.sh -``` - -## Performance - -| | AP | APEX | lOSS_SCALE | EPOCH | -| :-----: | :----: | :--: | :--------: | :---: | -| **GPU** | 0.9440 | O2 | 128 | 300 | -| **NPU** | 0.9396 | O2 | 128 | 300 | - +# FaceBoxes + +本项目实现了FaceBoxes从GPU到NPU上训练的迁移,源开源代码仓[FaceBoxes.Pytorch](https://github.com/zisianw/FaceBoxes.PyTorch) + +## FaceBoxes Detail + +本项目对于FaceBoxes.Pytorch做出了如下更改: + +1. 将设备从Nvidia GPU迁移到Huawei NPU上。 +2. 在源代码的基础上添加了Apex混合精度进行优化。 +3. 在模型迁移到NPU上后一些不支持或性能较低的算子放到CPU上进行规避。 +4. 针对测试结果添加了新的评估脚本。 + +## Requirements + +```bash +pip install -r requirements.txt +``` + +- NPU 配套的run包安装 +- Python3.7.5 +- PyTorch(NPU版本) +- Apex(NPU版本) + +### 导入环境变量 + +```bash +source scripts/npu_set_env.sh +``` + +### 编译 + +```bash +git clone https://github.com/Levi0223/FDDB_Evaluation.git +cd FDDB_Evaluation +python3 setup.py build_ext --inplace +mv ../convert.py ../split.py ./ +``` + +### 准备数据集 +数据集下载参考源代码仓 + +1. 下载[WIDER_FACE](https://github.com/zisianw/FaceBoxes.PyTorch)数据集,将图片放在这个目录下(数据集包含32203张图片): + + ```bash + $FaceBoxes_ROOT/data/WIDER_FACE/images/ + ``` + + 下载转换后的[标注文件](https://github.com/zisianw/FaceBoxes.PyTorch),将他们放在这个目录下: + + ```bash + $FaceBoxes_ROOT/data/WIDER_FACE/annotations/ + ``` + + 最终数据集目录结构如下: + + ![输入图片说明](https://images.gitee.com/uploads/images/2021/0927/121855_9a16b40b_6515416.png "屏幕截图.png") + +2. 下载[FDDB](https://github.com/zisianw/FaceBoxes.PyTorch)数据集,将图片放在这个目录下(数据集包含2845张图片): + + ```bash + $FaceBoxes_ROOT/data/FDDB/images/ + ``` + + 最终数据集目录结构如下: + + ![输入图片说明](https://images.gitee.com/uploads/images/2021/0927/121924_9f00b12c_6515416.png "屏幕截图.png") + +## Trainning + +### 单卡性能评估 + +```bash +### 输出单卡FPS +bash scripts/train_performance_1p.sh +``` + +### 单卡训练 + +```bash +### 单卡全量训练 +bash scripts/train_1p.sh +## 日志文件在当前目录下的1p_train.log +``` + +### 多卡性能评估 + +```bash +### 输出多卡FPS +bash scripts/train_performance_8p.sh +``` + +### 多卡训练 + +```bash +### 多卡全量训练 +bash scripts/train_8p.sh +## 日志文件在当前目录下的8p_train.log +``` + +### Test + +```bash +### 测试训练得到的权重文件,生成FDDB_dets.txt +bash test.sh +## 日志文件在当前目录下的test.log +### 解析FDDB_dets.txt文件,打印最终精度 +bash eval.sh +``` + +## Performance + +| | AP | APEX | lOSS_SCALE | EPOCH | +| :-----: | :----: | :--: | :--------: | :---: | +| **GPU** | 0.9440 | O2 | 128 | 300 | +| **NPU** | 0.9396 | O2 | 128 | 300 | + diff --git a/PyTorch/contrib/cv/detection/FaceBoxes/README_raw.md b/PyTorch/contrib/cv/detection/FaceBoxes/README_raw.md index c36af43fb8..3ae1866b88 100644 --- a/PyTorch/contrib/cv/detection/FaceBoxes/README_raw.md +++ b/PyTorch/contrib/cv/detection/FaceBoxes/README_raw.md @@ -1,92 +1,92 @@ -# FaceBoxes in PyTorch - -[![License](https://img.shields.io/badge/license-BSD-blue.svg)](LICENSE) - -By [Zisian Wong](https://github.com/zisianw), [Shifeng Zhang](http://www.cbsr.ia.ac.cn/users/sfzhang/) - -A [PyTorch](https://pytorch.org/) implementation of [FaceBoxes: A CPU Real-time Face Detector with High Accuracy](https://arxiv.org/abs/1708.05234). The official code in Caffe can be found [here](https://github.com/sfzhang15/FaceBoxes). - -## Performance -| Dataset | Original Caffe | PyTorch Implementation | -|:-|:-:|:-:| -| AFW | 98.98 % | 98.55% | -| PASCAL | 96.77 % | 97.05% | -| FDDB | 95.90 % | 96.00% | - -## Citation -Please cite the paper in your publications if it helps your research: - - @inproceedings{zhang2017faceboxes, - title = {Faceboxes: A CPU Real-time Face Detector with High Accuracy}, - author = {Zhang, Shifeng and Zhu, Xiangyu and Lei, Zhen and Shi, Hailin and Wang, Xiaobo and Li, Stan Z.}, - booktitle = {IJCB}, - year = {2017} - } - -### Contents -- [Installation](#installation) -- [Training](#training) -- [Evaluation](#evaluation) -- [References](#references) - -## Installation -1. Install [PyTorch](https://pytorch.org/) >= v1.0.0 following official instruction. - -2. Clone this repository. We will call the cloned directory as `$FaceBoxes_ROOT`. -```Shell -git clone https://github.com/zisianw/FaceBoxes.PyTorch.git -``` - -3. Compile the nms: -```Shell -./make.sh -``` - -_Note: Codes are based on Python 3+._ - -## Training -1. Download [WIDER FACE](https://github.com/zisianw/FaceBoxes.PyTorch) dataset, place the images under this directory: - ```Shell - $FaceBoxes_ROOT/data/WIDER_FACE/images - ``` -2. Convert WIDER FACE annotations to VOC format or download [our converted annotations](https://github.com/zisianw/FaceBoxes.PyTorch), place them under this directory: - ```Shell - $FaceBoxes_ROOT/data/WIDER_FACE/annotations - ``` - -3. Train the model using WIDER FACE: - ```Shell - cd $FaceBoxes_ROOT/ - python3 train.py - ``` - -If you do not wish to train the model, you can download [our pre-trained model](https://github.com/zisianw/FaceBoxes.PyTorch) and save it in `$FaceBoxes_ROOT/weights`. - - -## Evaluation -1. Download the images of [AFW](https://github.com/zisianw/FaceBoxes.PyTorch), [PASCAL Face](https://github.com/zisianw/FaceBoxes.PyTorch) and [FDDB]( -https://github.com/zisianw/FaceBoxes.PyTorch) to: -```Shell -$FaceBoxes_ROOT/data/AFW/images/ -$FaceBoxes_ROOT/data/PASCAL/images/ -$FaceBoxes_ROOT/data/FDDB/images/ -``` - -2. Evaluate the trained model using: -```Shell -# dataset choices = ['AFW', 'PASCAL', 'FDDB'] -python3 test.py --dataset FDDB -# evaluate using cpu -python3 test.py --cpu -# visualize detection results -python3 test.py -s --vis_thres 0.3 -``` - -3. Download [eval_tool](https://github.com/sfzhang15/face-eval) to evaluate the performance. - -## References -- [Official release (Caffe)](https://github.com/sfzhang15/FaceBoxes) -- A huge thank you to SSD ports in PyTorch that have been helpful: - * [ssd.pytorch](https://github.com/amdegroot/ssd.pytorch), [RFBNet](https://github.com/ruinmessi/RFBNet) - - _Note: If you can not download the converted annotations, the provided images and the trained model through the above links, you can download them through [BaiduYun](https://pan.baidu.com/s/1HoW3wbldnbmgW2PS4i4Irw)._ +# FaceBoxes in PyTorch + +[![License](https://img.shields.io/badge/license-BSD-blue.svg)](LICENSE) + +By [Zisian Wong](https://github.com/zisianw), [Shifeng Zhang](http://www.cbsr.ia.ac.cn/users/sfzhang/) + +A [PyTorch](https://pytorch.org/) implementation of [FaceBoxes: A CPU Real-time Face Detector with High Accuracy](https://arxiv.org/abs/1708.05234). The official code in Caffe can be found [here](https://github.com/sfzhang15/FaceBoxes). + +## Performance +| Dataset | Original Caffe | PyTorch Implementation | +|:-|:-:|:-:| +| AFW | 98.98 % | 98.55% | +| PASCAL | 96.77 % | 97.05% | +| FDDB | 95.90 % | 96.00% | + +## Citation +Please cite the paper in your publications if it helps your research: + + @inproceedings{zhang2017faceboxes, + title = {Faceboxes: A CPU Real-time Face Detector with High Accuracy}, + author = {Zhang, Shifeng and Zhu, Xiangyu and Lei, Zhen and Shi, Hailin and Wang, Xiaobo and Li, Stan Z.}, + booktitle = {IJCB}, + year = {2017} + } + +### Contents +- [Installation](#installation) +- [Training](#training) +- [Evaluation](#evaluation) +- [References](#references) + +## Installation +1. Install [PyTorch](https://pytorch.org/) >= v1.0.0 following official instruction. + +2. Clone this repository. We will call the cloned directory as `$FaceBoxes_ROOT`. +```Shell +git clone https://github.com/zisianw/FaceBoxes.PyTorch.git +``` + +3. Compile the nms: +```Shell +./make.sh +``` + +_Note: Codes are based on Python 3+._ + +## Training +1. Download [WIDER FACE](https://github.com/zisianw/FaceBoxes.PyTorch) dataset, place the images under this directory: + ```Shell + $FaceBoxes_ROOT/data/WIDER_FACE/images + ``` +2. Convert WIDER FACE annotations to VOC format or download [our converted annotations](https://github.com/zisianw/FaceBoxes.PyTorch), place them under this directory: + ```Shell + $FaceBoxes_ROOT/data/WIDER_FACE/annotations + ``` + +3. Train the model using WIDER FACE: + ```Shell + cd $FaceBoxes_ROOT/ + python3 train.py + ``` + +If you do not wish to train the model, you can download [our pre-trained model](https://github.com/zisianw/FaceBoxes.PyTorch) and save it in `$FaceBoxes_ROOT/weights`. + + +## Evaluation +1. Download the images of [AFW](https://github.com/zisianw/FaceBoxes.PyTorch), [PASCAL Face](https://github.com/zisianw/FaceBoxes.PyTorch) and [FDDB]( +https://github.com/zisianw/FaceBoxes.PyTorch) to: +```Shell +$FaceBoxes_ROOT/data/AFW/images/ +$FaceBoxes_ROOT/data/PASCAL/images/ +$FaceBoxes_ROOT/data/FDDB/images/ +``` + +2. Evaluate the trained model using: +```Shell +# dataset choices = ['AFW', 'PASCAL', 'FDDB'] +python3 test.py --dataset FDDB +# evaluate using cpu +python3 test.py --cpu +# visualize detection results +python3 test.py -s --vis_thres 0.3 +``` + +3. Download [eval_tool](https://github.com/sfzhang15/face-eval) to evaluate the performance. + +## References +- [Official release (Caffe)](https://github.com/sfzhang15/FaceBoxes) +- A huge thank you to SSD ports in PyTorch that have been helpful: + * [ssd.pytorch](https://github.com/amdegroot/ssd.pytorch), [RFBNet](https://github.com/ruinmessi/RFBNet) + + _Note: If you can not download the converted annotations, the provided images and the trained model through the above links, you can download them through [BaiduYun](https://pan.baidu.com/s/1HoW3wbldnbmgW2PS4i4Irw)._ diff --git a/PyTorch/contrib/cv/detection/GFocalV2/test/train_finetune_1p.sh b/PyTorch/contrib/cv/detection/GFocalV2/test/train_finetune_1p.sh index 68fe36b8b3..cc995eaca3 100644 --- a/PyTorch/contrib/cv/detection/GFocalV2/test/train_finetune_1p.sh +++ b/PyTorch/contrib/cv/detection/GFocalV2/test/train_finetune_1p.sh @@ -1,136 +1,136 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` - -#集合通信参数,不需要修改 -export RANK_SIZE=1 - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#网络名称,同目录名称,需要模型审视修改 -Network="GFocal" - -#训练batch_size,,需要模型审视修改 -batch_size=8 -device_id=0 -checkpoint="./work_dirs/gfocal_r50_fpn_1x/latest.pth" -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --device_id* ]];then - device_id=`echo ${para#*=}` - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --checkpoint* ]];then - checkpoint=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -# 校验是否指定了device_id,分动态分配device_id与手动指定device_id,此处不需要修改 -if [ $ASCEND_DEVICE_ID ];then - echo "device id is ${ASCEND_DEVICE_ID}" -elif [ ${device_id} ];then - export ASCEND_DEVICE_ID=${device_id} - echo "device id is ${ASCEND_DEVICE_ID}" -else - "[Error] device id must be config" - exit 1 -fi - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#创建DeviceID输出目录,不需要修改 -if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID -else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID -fi - -#非平台场景时source 环境变量 -check_etp_flag=`env | grep etp_running_flag` -etp_flag=`echo ${check_etp_flag#*=}` -if [ x"${etp_flag}" != x"true" ];then - source ${cur_path}/test/env_npu.sh -fi - -#执行训练脚本,以下传参不需要修改,其他需要模型审视修改 -export NPUID=0 -export RANK=0 -python3.7 ./tools/train.py configs/gfocal/gfocal_r50_fpn_1x.py \ - --cfg-options \ - optimizer.lr=0.005 total_epochs=1 data_root=$data_path \ - --seed 0 \ - --gpu-ids 0 \ - --opt-level O1 \ - --checkpoint $checkpoint > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep -a 'FPS' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "FPS: " '{print $NF}'|awk 'NR==1{max=$1;next}{max=max>$1?max:$1}END{print max}'` -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -train_accuracy=`grep -a 'bbox_mAP' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "bbox_mAP: " '{print $NF}'|awk -F "," '{print $1}'|awk 'NR==1{max=$1;next}{max=max>$1?max:$1}END{print max}'` -#打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#稳定性精度看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要模型审视修改 -grep Epoch: $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep eta:|awk -F "loss: " '{print $NF}' | awk -F "," '{print $1}' >> $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` + +#集合通信参数,不需要修改 +export RANK_SIZE=1 + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#网络名称,同目录名称,需要模型审视修改 +Network="GFocal" + +#训练batch_size,,需要模型审视修改 +batch_size=8 +device_id=0 +checkpoint="./work_dirs/gfocal_r50_fpn_1x/latest.pth" +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --device_id* ]];then + device_id=`echo ${para#*=}` + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --checkpoint* ]];then + checkpoint=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +# 校验是否指定了device_id,分动态分配device_id与手动指定device_id,此处不需要修改 +if [ $ASCEND_DEVICE_ID ];then + echo "device id is ${ASCEND_DEVICE_ID}" +elif [ ${device_id} ];then + export ASCEND_DEVICE_ID=${device_id} + echo "device id is ${ASCEND_DEVICE_ID}" +else + "[Error] device id must be config" + exit 1 +fi + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#创建DeviceID输出目录,不需要修改 +if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID +else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID +fi + +#非平台场景时source 环境变量 +check_etp_flag=`env | grep etp_running_flag` +etp_flag=`echo ${check_etp_flag#*=}` +if [ x"${etp_flag}" != x"true" ];then + source ${cur_path}/test/env_npu.sh +fi + +#执行训练脚本,以下传参不需要修改,其他需要模型审视修改 +export NPUID=0 +export RANK=0 +python3.7 ./tools/train.py configs/gfocal/gfocal_r50_fpn_1x.py \ + --cfg-options \ + optimizer.lr=0.005 total_epochs=1 data_root=$data_path \ + --seed 0 \ + --gpu-ids 0 \ + --opt-level O1 \ + --checkpoint $checkpoint > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep -a 'FPS' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "FPS: " '{print $NF}'|awk 'NR==1{max=$1;next}{max=max>$1?max:$1}END{print max}'` +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +train_accuracy=`grep -a 'bbox_mAP' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "bbox_mAP: " '{print $NF}'|awk -F "," '{print $1}'|awk 'NR==1{max=$1;next}{max=max>$1?max:$1}END{print max}'` +#打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#稳定性精度看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要模型审视修改 +grep Epoch: $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep eta:|awk -F "loss: " '{print $NF}' | awk -F "," '{print $1}' >> $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/Pointnetplus/README.md b/PyTorch/contrib/cv/detection/Pointnetplus/README.md index 3885666ce3..74370c2a9b 100644 --- a/PyTorch/contrib/cv/detection/Pointnetplus/README.md +++ b/PyTorch/contrib/cv/detection/Pointnetplus/README.md @@ -1,49 +1,49 @@ -# Pointnetplus - -This implements training of Pointnetplus on the ImageNet dataset, mainly modified from [pytorch/examples](https://github.com/yanx27/Pointnet_Pointnet2_pytorch). - -## Pointnetplus Detail - -As of the current date, Ascend-Pytorch is still inefficient for contiguous operations.Therefore, Pointnetplus is re-implemented using semantics such as custom OP. - - -## Requirements - -- Install PyTorch ([pytorch.org](http://pytorch.org)) -- `pip3 install -r requirements.txt` -- Download the ImageNet dataset from (https://shapenet.cs.stanford.edu/media/modelnet40_normal_resampled.zip) - -## Training - -To train a model, run `train_classification_xP.py` with the desired model architecture and the path to the ImageNet dataset: - then add [24,512,32,3],[24,1,128,259] transpose op to white list .pth is "/usr/local/Ascend/ascend-toolkit/latest/arm64-linux/opp/op_impl/built-in/ai_core/tbe/impl/dynamic/transpose.py" -```bash -# training 1p accuracy -bash ./test/train_full_1p.sh --data=real_data_path - -# training 1p performance -bash ./test/train_performance_1p.sh --data=real_data_path - -# training 8p accuracy -bash ./test/train_full_8p.sh --data=real_data_path - -# training 8p performance -bash ./test/train_performance_8p.sh --data=real_data_path - -# finetuning 1p -bash test/train_finetune_1p.sh --data=real_data_path --model_pth=real_pre_train_model_path -``` - -Log path: - test/output/devie_id/train_${ASCEND_DEVICE_ID}_${Network}.log # training detail log - test/output/devie_id/train_${ASCEND_DEVICE_ID}_${Network}.log # 8p training performance result log - test/output/devie_id/Pointnetplus_bs24_1p_acc.log # 8p training accuracy result log - - - -## WideResnet50_2 training result - -| Acc@1 | FPS | Npu_nums | Epochs | AMP_Type | -| :------: | :------: | :------: | :------: | :------: | -| - | 10.04 | 1 | 1 | O2 | +# Pointnetplus + +This implements training of Pointnetplus on the ImageNet dataset, mainly modified from [pytorch/examples](https://github.com/yanx27/Pointnet_Pointnet2_pytorch). + +## Pointnetplus Detail + +As of the current date, Ascend-Pytorch is still inefficient for contiguous operations.Therefore, Pointnetplus is re-implemented using semantics such as custom OP. + + +## Requirements + +- Install PyTorch ([pytorch.org](http://pytorch.org)) +- `pip3 install -r requirements.txt` +- Download the ImageNet dataset from (https://shapenet.cs.stanford.edu/media/modelnet40_normal_resampled.zip) + +## Training + +To train a model, run `train_classification_xP.py` with the desired model architecture and the path to the ImageNet dataset: + then add [24,512,32,3],[24,1,128,259] transpose op to white list .pth is "/usr/local/Ascend/ascend-toolkit/latest/arm64-linux/opp/op_impl/built-in/ai_core/tbe/impl/dynamic/transpose.py" +```bash +# training 1p accuracy +bash ./test/train_full_1p.sh --data=real_data_path + +# training 1p performance +bash ./test/train_performance_1p.sh --data=real_data_path + +# training 8p accuracy +bash ./test/train_full_8p.sh --data=real_data_path + +# training 8p performance +bash ./test/train_performance_8p.sh --data=real_data_path + +# finetuning 1p +bash test/train_finetune_1p.sh --data=real_data_path --model_pth=real_pre_train_model_path +``` + +Log path: + test/output/devie_id/train_${ASCEND_DEVICE_ID}_${Network}.log # training detail log + test/output/devie_id/train_${ASCEND_DEVICE_ID}_${Network}.log # 8p training performance result log + test/output/devie_id/Pointnetplus_bs24_1p_acc.log # 8p training accuracy result log + + + +## WideResnet50_2 training result + +| Acc@1 | FPS | Npu_nums | Epochs | AMP_Type | +| :------: | :------: | :------: | :------: | :------: | +| - | 10.04 | 1 | 1 | O2 | | 92.0 | 64.1 | 8 | 200 | O2 | \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/Pointnetplus/finetune.py b/PyTorch/contrib/cv/detection/Pointnetplus/finetune.py index d429106fc7..ade55c9fb2 100644 --- a/PyTorch/contrib/cv/detection/Pointnetplus/finetune.py +++ b/PyTorch/contrib/cv/detection/Pointnetplus/finetune.py @@ -1,74 +1,74 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import sys -import torch -import numpy as np -import argparse -from tqdm import tqdm -import models.provider -from models.ModelNetDataLoader import ModelNetDataLoader -import models.pointnet2_cls_ssg as models - -def inplace_relu(m): - classname = m.__class__.__name__ - if classname.find('ReLU') != -1: - m.inplace=True - -def parse_args(): - '''PARAMETERS''' - parser = argparse.ArgumentParser('training') - parser.add_argument('--batch_size', type=int, default=24, help='batch size in training') - parser.add_argument('--num_category', default=40, type=int, choices=[10, 40], help='training on ModelNet10/40') - parser.add_argument('--epoch', default=2, type=int, help='number of epoch in training') - parser.add_argument('--num_points', type=int, default=1024, help='Point Number') - parser.add_argument('--use_normals', action='store_true', default=False, help='use normals') - parser.add_argument('--process_data', action='store_true', default=True, help='save data offline') - parser.add_argument('--use_uniform_sample', action='store_true', default=False, help='use uniform sampiling') - parser.add_argument('--device', type=str,default='cpu',help='which device to use') - parser.add_argument('--data',type=str, default='./modelnet40_normal_resampled', help='data_path') - parser.add_argument('--num_class',type=int,default=41,help='num of class') - parser.add_argument('--num_point', type=int, default=1024, help='Point Number') - parser.add_argument('--model_pth', type=str, default='./log/classification/pointnet2_cls_ssg/checkpoints/', help='Point Number') - parser.add_argument('--worker', type=int, default=1, help='number ofs workers') - - return parser.parse_args() - -def main(args): - test_dataset = ModelNetDataLoader(root=args.data, args=args, split='test', process_data=args.process_data) - testDataLoader = torch.utils.data.DataLoader(test_dataset, batch_size=args.batch_size, shuffle=False, num_workers=args.worker) - model_dict = torch.load(str(args.model_pth)+'best_model.pth', map_location='cpu')['model_state_dict'] - model_dict.pop('fc3.weight') - model_dict.pop('fc3.bias') - classifier = models.get_model(args.num_class, normal_channel=args.use_normals) - classifier.apply(inplace_relu) - if args.device !='cpu': - classifier = classifier.npu() - classifier.load_state_dict(model_dict, strict=False) - - for epoch in range(args.epoch): - for batch_id,(points, target) in tqdm(enumerate(testDataLoader, 0), total=len(testDataLoader)): - points = points.transpose(2, 1) - if args.device !='cpu': - points, target = points.npu(), target.npu() - pred, trans_feat = classifier(points) - pred_choice = pred.data.max(1)[1] - print("output class is",pred_choice) - -if __name__ == '__main__': - args = parse_args() - main(args) - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import sys +import torch +import numpy as np +import argparse +from tqdm import tqdm +import models.provider +from models.ModelNetDataLoader import ModelNetDataLoader +import models.pointnet2_cls_ssg as models + +def inplace_relu(m): + classname = m.__class__.__name__ + if classname.find('ReLU') != -1: + m.inplace=True + +def parse_args(): + '''PARAMETERS''' + parser = argparse.ArgumentParser('training') + parser.add_argument('--batch_size', type=int, default=24, help='batch size in training') + parser.add_argument('--num_category', default=40, type=int, choices=[10, 40], help='training on ModelNet10/40') + parser.add_argument('--epoch', default=2, type=int, help='number of epoch in training') + parser.add_argument('--num_points', type=int, default=1024, help='Point Number') + parser.add_argument('--use_normals', action='store_true', default=False, help='use normals') + parser.add_argument('--process_data', action='store_true', default=True, help='save data offline') + parser.add_argument('--use_uniform_sample', action='store_true', default=False, help='use uniform sampiling') + parser.add_argument('--device', type=str,default='cpu',help='which device to use') + parser.add_argument('--data',type=str, default='./modelnet40_normal_resampled', help='data_path') + parser.add_argument('--num_class',type=int,default=41,help='num of class') + parser.add_argument('--num_point', type=int, default=1024, help='Point Number') + parser.add_argument('--model_pth', type=str, default='./log/classification/pointnet2_cls_ssg/checkpoints/', help='Point Number') + parser.add_argument('--worker', type=int, default=1, help='number ofs workers') + + return parser.parse_args() + +def main(args): + test_dataset = ModelNetDataLoader(root=args.data, args=args, split='test', process_data=args.process_data) + testDataLoader = torch.utils.data.DataLoader(test_dataset, batch_size=args.batch_size, shuffle=False, num_workers=args.worker) + model_dict = torch.load(str(args.model_pth)+'best_model.pth', map_location='cpu')['model_state_dict'] + model_dict.pop('fc3.weight') + model_dict.pop('fc3.bias') + classifier = models.get_model(args.num_class, normal_channel=args.use_normals) + classifier.apply(inplace_relu) + if args.device !='cpu': + classifier = classifier.npu() + classifier.load_state_dict(model_dict, strict=False) + + for epoch in range(args.epoch): + for batch_id,(points, target) in tqdm(enumerate(testDataLoader, 0), total=len(testDataLoader)): + points = points.transpose(2, 1) + if args.device !='cpu': + points, target = points.npu(), target.npu() + pred, trans_feat = classifier(points) + pred_choice = pred.data.max(1)[1] + print("output class is",pred_choice) + +if __name__ == '__main__': + args = parse_args() + main(args) + + diff --git a/PyTorch/contrib/cv/detection/Pointnetplus/modelzoo_level.txt b/PyTorch/contrib/cv/detection/Pointnetplus/modelzoo_level.txt index dd917ea530..08016761e0 100644 --- a/PyTorch/contrib/cv/detection/Pointnetplus/modelzoo_level.txt +++ b/PyTorch/contrib/cv/detection/Pointnetplus/modelzoo_level.txt @@ -1,5 +1,5 @@ -GPUStatus:OK -NPUMigrationStatus:OK -FuncStatus:OK -PrecisionStatus:OK +GPUStatus:OK +NPUMigrationStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus:NOK \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/Pointnetplus/pointnetplus_pth2onnx.py b/PyTorch/contrib/cv/detection/Pointnetplus/pointnetplus_pth2onnx.py index bb92b279f8..4728535261 100644 --- a/PyTorch/contrib/cv/detection/Pointnetplus/pointnetplus_pth2onnx.py +++ b/PyTorch/contrib/cv/detection/Pointnetplus/pointnetplus_pth2onnx.py @@ -1,104 +1,104 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 collections import OrderedDict -import torch -import torch.onnx -import argparse -import sys -sys.path.append('./models/models') -import pointnet2_cls_ssg as pointnet2_cls -from pointnet2_utils import farthest_point_sample -from pointnet2_utils import sample_and_group - - -def parse_args(): - '''PARAMETERS''' - parser = argparse.ArgumentParser('off_line_pred') - parser.add_argument('--target_model', type=int, default=1, - required=True, help='target trans_models') - parser.add_argument('--pth_dir', type=str, default='', - required=False, help='target trans_models') - parser.add_argument('--batch_size', type=int, default=1, - required=False, help='batch size') - return parser.parse_args() - - -def proc_node_module(checkpoint, AttrName): - new_state_dict = OrderedDict() - for k, v in checkpoint[AttrName].items(): - if k[0:7] == "module.": - name = k[7:] - else: - name = k[0:] - new_state_dict[name] = v - return new_state_dict - - -def model_convert(dir): - experiment_dir = dir - dummy_input = torch.randn(args.batch_size, 3, 1024) - checkpoint = torch.load(str(experiment_dir) + '/best_model.pth',map_location = 'cpu') - checkpoint['model_state_dict'] = proc_node_module(checkpoint,'model_state_dict') - model = pointnet2_cls.get_model_part1(normal_channel=False) - model.load_state_dict(checkpoint['model_state_dict']) - model.eval() - npoint = 512 - radius = 0.2 - nsample = 32 - points = None - test_input = dummy_input.permute(0, 2, 1) - centroid = farthest_point_sample(test_input, npoint) - new_xyz, new_points = sample_and_group(npoint, radius, nsample, test_input, points, centroid) - new_points = new_points.permute(0, 3, 2, 1) - input_names = ["xyz", "samp_points"] - output_names = ["l1_xyz", "l1_point"] - torch.onnx.export(model, (new_xyz, new_points), - "Pointnetplus_part1_bs{}.onnx".format(args.batch_size), - input_names=input_names, verbose=True, output_names=output_names, opset_version=11) - - -def model_convert2(dir): - experiment_dir = dir - dummy_xyz_input = torch.randn(args.batch_size, 3, 512) - dummy_point_input = torch.randn(args.batch_size, 128, 512) - checkpoint = torch.load(str(experiment_dir) + '/best_model.pth',map_location = 'cpu') - checkpoint['model_state_dict'] = proc_node_module(checkpoint,'model_state_dict') - model = pointnet2_cls.get_model_part2(normal_channel=False) - model.load_state_dict(checkpoint['model_state_dict']) - model.eval() - npoint = 128 - radius = 0.4 - nsample = 64 - points = None - test_input = dummy_xyz_input.permute(0, 2, 1) - test_points = dummy_point_input.permute(0, 2, 1) - centroid = farthest_point_sample(test_input, npoint) - new_xyz, new_points = sample_and_group(npoint, radius, nsample, test_input, test_points, centroid) - new_points = new_points.permute(0, 3, 2, 1) - new_xyz = new_xyz.permute(0, 2, 1) - input_names = ["l1_xyz", "l1_points"] - output_names = ["class", "l3_point"] - - torch.onnx.export(model, (new_xyz, new_points), - "Pointnetplus_part2_bs{}.onnx".format(args.batch_size), - input_names=input_names, verbose=True, output_names=output_names, opset_version=11) - - -if __name__ == '__main__': - args = parse_args() - if(args.target_model == 1): - model_convert(args.pth_dir) - else: - model_convert2(args.pth_dir) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 collections import OrderedDict +import torch +import torch.onnx +import argparse +import sys +sys.path.append('./models/models') +import pointnet2_cls_ssg as pointnet2_cls +from pointnet2_utils import farthest_point_sample +from pointnet2_utils import sample_and_group + + +def parse_args(): + '''PARAMETERS''' + parser = argparse.ArgumentParser('off_line_pred') + parser.add_argument('--target_model', type=int, default=1, + required=True, help='target trans_models') + parser.add_argument('--pth_dir', type=str, default='', + required=False, help='target trans_models') + parser.add_argument('--batch_size', type=int, default=1, + required=False, help='batch size') + return parser.parse_args() + + +def proc_node_module(checkpoint, AttrName): + new_state_dict = OrderedDict() + for k, v in checkpoint[AttrName].items(): + if k[0:7] == "module.": + name = k[7:] + else: + name = k[0:] + new_state_dict[name] = v + return new_state_dict + + +def model_convert(dir): + experiment_dir = dir + dummy_input = torch.randn(args.batch_size, 3, 1024) + checkpoint = torch.load(str(experiment_dir) + '/best_model.pth',map_location = 'cpu') + checkpoint['model_state_dict'] = proc_node_module(checkpoint,'model_state_dict') + model = pointnet2_cls.get_model_part1(normal_channel=False) + model.load_state_dict(checkpoint['model_state_dict']) + model.eval() + npoint = 512 + radius = 0.2 + nsample = 32 + points = None + test_input = dummy_input.permute(0, 2, 1) + centroid = farthest_point_sample(test_input, npoint) + new_xyz, new_points = sample_and_group(npoint, radius, nsample, test_input, points, centroid) + new_points = new_points.permute(0, 3, 2, 1) + input_names = ["xyz", "samp_points"] + output_names = ["l1_xyz", "l1_point"] + torch.onnx.export(model, (new_xyz, new_points), + "Pointnetplus_part1_bs{}.onnx".format(args.batch_size), + input_names=input_names, verbose=True, output_names=output_names, opset_version=11) + + +def model_convert2(dir): + experiment_dir = dir + dummy_xyz_input = torch.randn(args.batch_size, 3, 512) + dummy_point_input = torch.randn(args.batch_size, 128, 512) + checkpoint = torch.load(str(experiment_dir) + '/best_model.pth',map_location = 'cpu') + checkpoint['model_state_dict'] = proc_node_module(checkpoint,'model_state_dict') + model = pointnet2_cls.get_model_part2(normal_channel=False) + model.load_state_dict(checkpoint['model_state_dict']) + model.eval() + npoint = 128 + radius = 0.4 + nsample = 64 + points = None + test_input = dummy_xyz_input.permute(0, 2, 1) + test_points = dummy_point_input.permute(0, 2, 1) + centroid = farthest_point_sample(test_input, npoint) + new_xyz, new_points = sample_and_group(npoint, radius, nsample, test_input, test_points, centroid) + new_points = new_points.permute(0, 3, 2, 1) + new_xyz = new_xyz.permute(0, 2, 1) + input_names = ["l1_xyz", "l1_points"] + output_names = ["class", "l3_point"] + + torch.onnx.export(model, (new_xyz, new_points), + "Pointnetplus_part2_bs{}.onnx".format(args.batch_size), + input_names=input_names, verbose=True, output_names=output_names, opset_version=11) + + +if __name__ == '__main__': + args = parse_args() + if(args.target_model == 1): + model_convert(args.pth_dir) + else: + model_convert2(args.pth_dir) diff --git a/PyTorch/contrib/cv/detection/Pointnetplus/requirements.txt b/PyTorch/contrib/cv/detection/Pointnetplus/requirements.txt index d9fdcd1a87..309763d470 100644 --- a/PyTorch/contrib/cv/detection/Pointnetplus/requirements.txt +++ b/PyTorch/contrib/cv/detection/Pointnetplus/requirements.txt @@ -1,6 +1,6 @@ -apex -numpy==4.62.3 -torch==1.5.0 -torchvision==0.6.0 -onnx +apex +numpy==4.62.3 +torch==1.5.0 +torchvision==0.6.0 +onnx tqdm==4.62.3 \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/README.md b/PyTorch/contrib/cv/detection/Pyramidbox/README.md index d11beb2f26..17b9e57acd 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/README.md +++ b/PyTorch/contrib/cv/detection/Pyramidbox/README.md @@ -1,138 +1,138 @@ -## Pyramidbox - -​ A Context-assisted Single Shot Face Detector. - - - -### Requirements - -``` -根据requirements.txt安装依赖环境 -- Download the WIDER_FACE dataset from http://shuoyang1213.me/WIDERFACE/ -``` - - - -在代码仓下创建WIDER_FACE目录,存放数据集文件 - -``` -|-WIDER_FACE - |-wider_face_split - |-wider_face_test.mat - |-wider_face_test_filelist.txt - |-wider_face_train.mat - |-wider_face_train_bbx_gt.txt - |-wider_face_val.mat - |-wider_face_val_bbx_gt.txt - |-WIDER_train - |-images - |-0--Parade - |-1--Handshaking - ... - |-WIDER_val - |-images - |-0--Parade - |-1--Handshaking - ... -``` - - - -参照原代码仓README下载vgg权重,放在weights目录下 - -``` -|-Pyramidbox - |-weights - |-vgg16_reducedfc.pth -``` - - - -### prepare - -运行prepare_wider_data.py - -``` -python prepare_wider_data.py --data_path='数据集路径' -``` - - - -### Training - -单卡训练 - -``` -python train.py --batch_size=8 --lr=5e-4 -``` - -多卡训练 - -``` -python -m torch.distributed.launch --nproc_per_node=8 train.py --world_size=8 --batch_size=8 --lr=5e-4 --multinpu=True --device_list='0,1,2,3,4,5,6,7' -``` - - - -### Test - -在运行wider_test.py前,应先做以下修改: - -``` -1、修改第53行 -sys.path.append("/home/wch/Pyramidbox/") #根据代码仓实际所在位置进行修改 -``` - -修改后,运行wider_test.py - -``` -python tools/wider_test.py --model="/home/wch/Pyramidbox/weights/pyramidbox.pth" --data_path='数据集路径' -#model参数根据模型权重文件保存位置进行修改 -``` - -运行以下脚本,评估精度 - -``` -cd evaluate -python setup.py build_ext --inplace -python evaluation.py --pred ../output/pyramidbox1_val/ --gt '数据集路径/wider_face_split' -``` - - - -### 启动脚本 - -8卡训练,并显示性能和精度 - -``` -bash ./test/train_full_8p.sh --data_path='数据集路径' -``` - -测试单卡训练性能 - -``` -bash ./test/train_performance_1p.sh --data_path='数据集路径' -``` - -测试多卡训练性能 - -``` -bash ./test/train_performance_8p.sh --data_path='数据集路径' -``` - -模型迁移脚本,注意脚本中的resume参数只能指定为保存的“pyramidbox_checkpoint.pth”权重 - -``` -bash ./test/train_finetune_1p.sh --data_path='数据集路径' -``` - -精度数据 - -``` -==================== Results ==================== -Easy Val AP: 0.9519612346942784 -Medium Val AP: 0.9446576258551937 -Hard Val AP: 0.9053749943031708 -================================================= -``` - +## Pyramidbox + +​ A Context-assisted Single Shot Face Detector. + + + +### Requirements + +``` +根据requirements.txt安装依赖环境 +- Download the WIDER_FACE dataset from http://shuoyang1213.me/WIDERFACE/ +``` + + + +在代码仓下创建WIDER_FACE目录,存放数据集文件 + +``` +|-WIDER_FACE + |-wider_face_split + |-wider_face_test.mat + |-wider_face_test_filelist.txt + |-wider_face_train.mat + |-wider_face_train_bbx_gt.txt + |-wider_face_val.mat + |-wider_face_val_bbx_gt.txt + |-WIDER_train + |-images + |-0--Parade + |-1--Handshaking + ... + |-WIDER_val + |-images + |-0--Parade + |-1--Handshaking + ... +``` + + + +参照原代码仓README下载vgg权重,放在weights目录下 + +``` +|-Pyramidbox + |-weights + |-vgg16_reducedfc.pth +``` + + + +### prepare + +运行prepare_wider_data.py + +``` +python prepare_wider_data.py --data_path='数据集路径' +``` + + + +### Training + +单卡训练 + +``` +python train.py --batch_size=8 --lr=5e-4 +``` + +多卡训练 + +``` +python -m torch.distributed.launch --nproc_per_node=8 train.py --world_size=8 --batch_size=8 --lr=5e-4 --multinpu=True --device_list='0,1,2,3,4,5,6,7' +``` + + + +### Test + +在运行wider_test.py前,应先做以下修改: + +``` +1、修改第53行 +sys.path.append("/home/wch/Pyramidbox/") #根据代码仓实际所在位置进行修改 +``` + +修改后,运行wider_test.py + +``` +python tools/wider_test.py --model="/home/wch/Pyramidbox/weights/pyramidbox.pth" --data_path='数据集路径' +#model参数根据模型权重文件保存位置进行修改 +``` + +运行以下脚本,评估精度 + +``` +cd evaluate +python setup.py build_ext --inplace +python evaluation.py --pred ../output/pyramidbox1_val/ --gt '数据集路径/wider_face_split' +``` + + + +### 启动脚本 + +8卡训练,并显示性能和精度 + +``` +bash ./test/train_full_8p.sh --data_path='数据集路径' +``` + +测试单卡训练性能 + +``` +bash ./test/train_performance_1p.sh --data_path='数据集路径' +``` + +测试多卡训练性能 + +``` +bash ./test/train_performance_8p.sh --data_path='数据集路径' +``` + +模型迁移脚本,注意脚本中的resume参数只能指定为保存的“pyramidbox_checkpoint.pth”权重 + +``` +bash ./test/train_finetune_1p.sh --data_path='数据集路径' +``` + +精度数据 + +``` +==================== Results ==================== +Easy Val AP: 0.9519612346942784 +Medium Val AP: 0.9446576258551937 +Hard Val AP: 0.9053749943031708 +================================================= +``` + diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/README_raw.md b/PyTorch/contrib/cv/detection/Pyramidbox/README_raw.md index 9adcd839ae..94496c1511 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/README_raw.md +++ b/PyTorch/contrib/cv/detection/Pyramidbox/README_raw.md @@ -1,72 +1,72 @@ -## PyramidBox: A Context-assisted Single Shot Face Detector.## -[A PyTorch Implementation of PyramidBox](https://arxiv.org/abs/1803.07737) - - -### Description -I train pyramidbox with pytorch and the result approaches the original paper result,the pretrained model can be downloaded in [vgg](https://pan.baidu.com/s/1Q-YqoxJyqvln6KTcIck1tQ),the final model can be downloaded in [Pyramidbox](https://pan.baidu.com/s/1VtzgB9srkJY4SUtVM3n8tw).the AP in WIDER FACE as following: - -| | Easy MAP | Medium MAP | hard MAP | -| -------- | ---------|------------| --------- | -| origin paper| 0.960 | 0.948 | 0.888 | -| this repo | 0.948 | 0.938 | 0.880 | - -the AP in AFW,PASCAL,FDDB as following: - -| AFW | PASCAL | FDDB | -| --------- |-----------| ---------| -| 99.65 | 99.02 | 0.983 | - -the gap is small with origin paper,I train 120k batch_size 4 which is different from paper,which maybe cause the gap,if you have more gpu ,the final result maybe better. - -### Requirement -* pytorch 0.3 -* opencv -* numpy -* easydict - -### Prepare data -1. download WIDER face dataset -2. modify data/config.py -3. ``` python prepare_wider_data.py``` - - -### Train -``` -python train.py --batch_size 4 - --lr 5e-4 -``` - -### Evalution -according to yourself dataset path,modify data/config.py -1. Evaluate on AFW. -``` -python tools/afw_test.py -``` -2. Evaluate on FDDB -``` -python tools/fddb_test.py -``` -3. Evaluate on PASCAL face -``` -python tools/pascal_test.py -``` -4. test on WIDER FACE -``` -python tools/wider_test.py -``` -### Demo -you can test yourself image -``` -python demo.py -``` - -### Result -
-demo -demo -
- -### References -* [PyramidBox: A Context-assisted Single Shot Face Detector](https://arxiv.org/abs/1803.07737) -* [PyramidBox model](https://github.com/PaddlePaddle/models/tree/develop/fluid/PaddleCV/face_detection) -* [ssd.pytorch](https://github.com/amdegroot/ssd.pytorch) +## PyramidBox: A Context-assisted Single Shot Face Detector.## +[A PyTorch Implementation of PyramidBox](https://arxiv.org/abs/1803.07737) + + +### Description +I train pyramidbox with pytorch and the result approaches the original paper result,the pretrained model can be downloaded in [vgg](https://pan.baidu.com/s/1Q-YqoxJyqvln6KTcIck1tQ),the final model can be downloaded in [Pyramidbox](https://pan.baidu.com/s/1VtzgB9srkJY4SUtVM3n8tw).the AP in WIDER FACE as following: + +| | Easy MAP | Medium MAP | hard MAP | +| -------- | ---------|------------| --------- | +| origin paper| 0.960 | 0.948 | 0.888 | +| this repo | 0.948 | 0.938 | 0.880 | + +the AP in AFW,PASCAL,FDDB as following: + +| AFW | PASCAL | FDDB | +| --------- |-----------| ---------| +| 99.65 | 99.02 | 0.983 | + +the gap is small with origin paper,I train 120k batch_size 4 which is different from paper,which maybe cause the gap,if you have more gpu ,the final result maybe better. + +### Requirement +* pytorch 0.3 +* opencv +* numpy +* easydict + +### Prepare data +1. download WIDER face dataset +2. modify data/config.py +3. ``` python prepare_wider_data.py``` + + +### Train +``` +python train.py --batch_size 4 + --lr 5e-4 +``` + +### Evalution +according to yourself dataset path,modify data/config.py +1. Evaluate on AFW. +``` +python tools/afw_test.py +``` +2. Evaluate on FDDB +``` +python tools/fddb_test.py +``` +3. Evaluate on PASCAL face +``` +python tools/pascal_test.py +``` +4. test on WIDER FACE +``` +python tools/wider_test.py +``` +### Demo +you can test yourself image +``` +python demo.py +``` + +### Result +
+demo +demo +
+ +### References +* [PyramidBox: A Context-assisted Single Shot Face Detector](https://arxiv.org/abs/1803.07737) +* [PyramidBox model](https://github.com/PaddlePaddle/models/tree/develop/fluid/PaddleCV/face_detection) +* [ssd.pytorch](https://github.com/amdegroot/ssd.pytorch) diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/data/config.py b/PyTorch/contrib/cv/detection/Pyramidbox/data/config.py index 10a42e3329..5cead837e5 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/data/config.py +++ b/PyTorch/contrib/cv/detection/Pyramidbox/data/config.py @@ -1,87 +1,87 @@ -#-*- coding:utf-8 -*- -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 division -from __future__ import absolute_import -from __future__ import print_function - -import os -from easydict import EasyDict -import numpy as np - - -_C = EasyDict() -cfg = _C -# data augument config -_C.expand_prob = 0.5 -_C.expand_max_ratio = 4 -_C.hue_prob = 0.5 -_C.hue_delta = 18 -_C.contrast_prob = 0.5 -_C.contrast_delta = 0.5 -_C.saturation_prob = 0.5 -_C.saturation_delta = 0.5 -_C.brightness_prob = 0.5 -_C.brightness_delta = 0.125 -_C.data_anchor_sampling_prob = 0.5 -_C.min_face_size = 6.0 -_C.apply_distort = True -_C.apply_expand = False -_C.img_mean = np.array([104., 117., 123.])[:, np.newaxis, np.newaxis].astype( - 'float32') -_C.resize_width = 640 -_C.resize_height = 640 -_C.scale = 1 / 127.0 -_C.anchor_sampling = True -_C.filter_min_face = True - -# train config -_C.LR_STEPS = (80000,100000,120000) -_C.MAX_STEPS = 150000 -_C.EPOCHES = 100 - -# anchor config -_C.FEATURE_MAPS = [160, 80, 40, 20, 10, 5] -_C.INPUT_SIZE = 640 -_C.STEPS = [4, 8, 16, 32, 64, 128] -_C.ANCHOR_SIZES = [16, 32, 64, 128, 256, 512] -_C.CLIP = False -_C.VARIANCE = [0.1, 0.2] - -# loss config -_C.NUM_CLASSES = 2 -_C.OVERLAP_THRESH = 0.35 -_C.NEG_POS_RATIOS = 3 - - -# detection config -_C.NMS_THRESH = 0.3 -_C.TOP_K = 5000 -_C.KEEP_TOP_K = 750 -_C.CONF_THRESH = 0.05 - - -# dataset config -#_C.HOME = '/home/wch/Pyramidbox/' - -# face config -_C.FACE = EasyDict() -_C.FACE.TRAIN_FILE = 'data/face_train.txt' -_C.FACE.VAL_FILE = 'data/face_val.txt' -_C.FACE.FDDB_DIR = '/home/data/lj/FDDB' -_C.FACE.WIDER_DIR = '/home/wch/Pyramidbox/WIDER_FACE/' -_C.FACE.AFW_DIR = '/home/data/lj/AFW' -_C.FACE.PASCAL_DIR = '/home/data/lj/PASCAL_FACE' -_C.FACE.OVERLAP_THRESH = 0.35 - +#-*- coding:utf-8 -*- +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 division +from __future__ import absolute_import +from __future__ import print_function + +import os +from easydict import EasyDict +import numpy as np + + +_C = EasyDict() +cfg = _C +# data augument config +_C.expand_prob = 0.5 +_C.expand_max_ratio = 4 +_C.hue_prob = 0.5 +_C.hue_delta = 18 +_C.contrast_prob = 0.5 +_C.contrast_delta = 0.5 +_C.saturation_prob = 0.5 +_C.saturation_delta = 0.5 +_C.brightness_prob = 0.5 +_C.brightness_delta = 0.125 +_C.data_anchor_sampling_prob = 0.5 +_C.min_face_size = 6.0 +_C.apply_distort = True +_C.apply_expand = False +_C.img_mean = np.array([104., 117., 123.])[:, np.newaxis, np.newaxis].astype( + 'float32') +_C.resize_width = 640 +_C.resize_height = 640 +_C.scale = 1 / 127.0 +_C.anchor_sampling = True +_C.filter_min_face = True + +# train config +_C.LR_STEPS = (80000,100000,120000) +_C.MAX_STEPS = 150000 +_C.EPOCHES = 100 + +# anchor config +_C.FEATURE_MAPS = [160, 80, 40, 20, 10, 5] +_C.INPUT_SIZE = 640 +_C.STEPS = [4, 8, 16, 32, 64, 128] +_C.ANCHOR_SIZES = [16, 32, 64, 128, 256, 512] +_C.CLIP = False +_C.VARIANCE = [0.1, 0.2] + +# loss config +_C.NUM_CLASSES = 2 +_C.OVERLAP_THRESH = 0.35 +_C.NEG_POS_RATIOS = 3 + + +# detection config +_C.NMS_THRESH = 0.3 +_C.TOP_K = 5000 +_C.KEEP_TOP_K = 750 +_C.CONF_THRESH = 0.05 + + +# dataset config +#_C.HOME = '/home/wch/Pyramidbox/' + +# face config +_C.FACE = EasyDict() +_C.FACE.TRAIN_FILE = 'data/face_train.txt' +_C.FACE.VAL_FILE = 'data/face_val.txt' +_C.FACE.FDDB_DIR = '/home/data/lj/FDDB' +_C.FACE.WIDER_DIR = '/home/wch/Pyramidbox/WIDER_FACE/' +_C.FACE.AFW_DIR = '/home/data/lj/AFW' +_C.FACE.PASCAL_DIR = '/home/data/lj/PASCAL_FACE' +_C.FACE.OVERLAP_THRESH = 0.35 + diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/data/widerface.py b/PyTorch/contrib/cv/detection/Pyramidbox/data/widerface.py index 5b6b67835f..e81a461df6 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/data/widerface.py +++ b/PyTorch/contrib/cv/detection/Pyramidbox/data/widerface.py @@ -1,172 +1,172 @@ -#-*- coding:utf-8 -*- -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -from PIL import Image, ImageDraw -import torch.utils.data as data -import numpy as np -import random -from utils.augmentations import preprocess - - -class WIDERDetection(data.Dataset): - """docstring for WIDERDetection""" - - def __init__(self, list_file, mode='train'): - super(WIDERDetection, self).__init__() - self.mode = mode - self.fnames = [] - self.boxes = [] - self.labels = [] - - with open(list_file) as f: - lines = f.readlines() - - for line in lines: - line = line.strip().split() - num_faces = int(line[1]) - box = [] - label = [] - for i in range(num_faces): - x = float(line[2 + 5 * i]) - y = float(line[3 + 5 * i]) - w = float(line[4 + 5 * i]) - h = float(line[5 + 5 * i]) - c = int(line[6 + 5 * i]) - if w <= 0 or h <= 0: - continue - box.append([x, y, x + w, y + h]) - label.append(c) - if len(box) > 0: - self.fnames.append(line[0]) - self.boxes.append(box) - self.labels.append(label) - - self.num_samples = len(self.boxes) - - def __len__(self): - return self.num_samples - - def __getitem__(self, index): - img, face_target,head_target = self.pull_item(index) - return img, face_target,head_target - - def pull_item(self, index): - while True: - image_path = self.fnames[index] - img = Image.open(image_path) - if img.mode == 'L': - img = img.convert('RGB') - - im_width, im_height = img.size - boxes = self.annotransform( - np.array(self.boxes[index]), im_width, im_height) - label = np.array(self.labels[index]) - bbox_labels = np.hstack((label[:, np.newaxis], boxes)).tolist() - img, sample_labels = preprocess( - img, bbox_labels, self.mode, image_path) - sample_labels = np.array(sample_labels) - if len(sample_labels) > 0: - face_target = np.hstack( - (sample_labels[:, 1:], sample_labels[:, 0][:, np.newaxis])) - - assert (face_target[:, 2] > face_target[:, 0]).any() - assert (face_target[:, 3] > face_target[:, 1]).any() - - #img = img.astype(np.float32) - face_box = face_target[:, :-1] - head_box = self.expand_bboxes(face_box) - head_target = np.hstack((head_box, face_target[ - :, -1][:, np.newaxis])) - break - else: - index = random.randrange(0, self.num_samples) - - - #img = Image.fromarray(img) - ''' - draw = ImageDraw.Draw(img) - w,h = img.size - for bbox in sample_labels: - bbox = (bbox[1:] * np.array([w, h, w, h])).tolist() - - draw.rectangle(bbox,outline='red') - img.save('image.jpg') - ''' - return torch.from_numpy(img), face_target, head_target - - - def annotransform(self, boxes, im_width, im_height): - boxes[:, 0] /= im_width - boxes[:, 1] /= im_height - boxes[:, 2] /= im_width - boxes[:, 3] /= im_height - return boxes - - def expand_bboxes(self, - bboxes, - expand_left=2., - expand_up=2., - expand_right=2., - expand_down=2.): - expand_bboxes = [] - for bbox in bboxes: - xmin = bbox[0] - ymin = bbox[1] - xmax = bbox[2] - ymax = bbox[3] - w = xmax - xmin - h = ymax - ymin - ex_xmin = max(xmin - w / expand_left, 0.) - ex_ymin = max(ymin - h / expand_up, 0.) - ex_xmax = max(xmax + w / expand_right, 0.) - ex_ymax = max(ymax + h / expand_down, 0.) - expand_bboxes.append([ex_xmin, ex_ymin, ex_xmax, ex_ymax]) - expand_bboxes = np.array(expand_bboxes) - return expand_bboxes - -def detection_collate(batch): - """Custom collate fn for dealing with batches of images that have a different - number of associated object annotations (bounding boxes). - - Arguments: - batch: (tuple) A tuple of tensor images and lists of annotations - - Return: - A tuple containing: - 1) (tensor) batch of images stacked on their 0 dim - 2) (list of tensors) annotations for a given image are stacked on - 0 dim - """ - face_targets = [] - head_targets = [] - - imgs = [] - for sample in batch: - imgs.append(sample[0]) - face_targets.append(torch.FloatTensor(sample[1])) - head_targets.append(torch.FloatTensor(sample[2])) - return torch.stack(imgs, 0), face_targets,head_targets - - - -if __name__ == '__main__': - from config import cfg - dataset = WIDERDetection(cfg.FACE.TRAIN_FILE) - #for i in range(len(dataset)): - dataset.pull_item(14) +#-*- coding:utf-8 -*- +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +from PIL import Image, ImageDraw +import torch.utils.data as data +import numpy as np +import random +from utils.augmentations import preprocess + + +class WIDERDetection(data.Dataset): + """docstring for WIDERDetection""" + + def __init__(self, list_file, mode='train'): + super(WIDERDetection, self).__init__() + self.mode = mode + self.fnames = [] + self.boxes = [] + self.labels = [] + + with open(list_file) as f: + lines = f.readlines() + + for line in lines: + line = line.strip().split() + num_faces = int(line[1]) + box = [] + label = [] + for i in range(num_faces): + x = float(line[2 + 5 * i]) + y = float(line[3 + 5 * i]) + w = float(line[4 + 5 * i]) + h = float(line[5 + 5 * i]) + c = int(line[6 + 5 * i]) + if w <= 0 or h <= 0: + continue + box.append([x, y, x + w, y + h]) + label.append(c) + if len(box) > 0: + self.fnames.append(line[0]) + self.boxes.append(box) + self.labels.append(label) + + self.num_samples = len(self.boxes) + + def __len__(self): + return self.num_samples + + def __getitem__(self, index): + img, face_target,head_target = self.pull_item(index) + return img, face_target,head_target + + def pull_item(self, index): + while True: + image_path = self.fnames[index] + img = Image.open(image_path) + if img.mode == 'L': + img = img.convert('RGB') + + im_width, im_height = img.size + boxes = self.annotransform( + np.array(self.boxes[index]), im_width, im_height) + label = np.array(self.labels[index]) + bbox_labels = np.hstack((label[:, np.newaxis], boxes)).tolist() + img, sample_labels = preprocess( + img, bbox_labels, self.mode, image_path) + sample_labels = np.array(sample_labels) + if len(sample_labels) > 0: + face_target = np.hstack( + (sample_labels[:, 1:], sample_labels[:, 0][:, np.newaxis])) + + assert (face_target[:, 2] > face_target[:, 0]).any() + assert (face_target[:, 3] > face_target[:, 1]).any() + + #img = img.astype(np.float32) + face_box = face_target[:, :-1] + head_box = self.expand_bboxes(face_box) + head_target = np.hstack((head_box, face_target[ + :, -1][:, np.newaxis])) + break + else: + index = random.randrange(0, self.num_samples) + + + #img = Image.fromarray(img) + ''' + draw = ImageDraw.Draw(img) + w,h = img.size + for bbox in sample_labels: + bbox = (bbox[1:] * np.array([w, h, w, h])).tolist() + + draw.rectangle(bbox,outline='red') + img.save('image.jpg') + ''' + return torch.from_numpy(img), face_target, head_target + + + def annotransform(self, boxes, im_width, im_height): + boxes[:, 0] /= im_width + boxes[:, 1] /= im_height + boxes[:, 2] /= im_width + boxes[:, 3] /= im_height + return boxes + + def expand_bboxes(self, + bboxes, + expand_left=2., + expand_up=2., + expand_right=2., + expand_down=2.): + expand_bboxes = [] + for bbox in bboxes: + xmin = bbox[0] + ymin = bbox[1] + xmax = bbox[2] + ymax = bbox[3] + w = xmax - xmin + h = ymax - ymin + ex_xmin = max(xmin - w / expand_left, 0.) + ex_ymin = max(ymin - h / expand_up, 0.) + ex_xmax = max(xmax + w / expand_right, 0.) + ex_ymax = max(ymax + h / expand_down, 0.) + expand_bboxes.append([ex_xmin, ex_ymin, ex_xmax, ex_ymax]) + expand_bboxes = np.array(expand_bboxes) + return expand_bboxes + +def detection_collate(batch): + """Custom collate fn for dealing with batches of images that have a different + number of associated object annotations (bounding boxes). + + Arguments: + batch: (tuple) A tuple of tensor images and lists of annotations + + Return: + A tuple containing: + 1) (tensor) batch of images stacked on their 0 dim + 2) (list of tensors) annotations for a given image are stacked on + 0 dim + """ + face_targets = [] + head_targets = [] + + imgs = [] + for sample in batch: + imgs.append(sample[0]) + face_targets.append(torch.FloatTensor(sample[1])) + head_targets.append(torch.FloatTensor(sample[2])) + return torch.stack(imgs, 0), face_targets,head_targets + + + +if __name__ == '__main__': + from config import cfg + dataset = WIDERDetection(cfg.FACE.TRAIN_FILE) + #for i in range(len(dataset)): + dataset.pull_item(14) diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/demo.py b/PyTorch/contrib/cv/detection/Pyramidbox/demo.py index 53ee7dbbd6..44a9271b12 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/demo.py +++ b/PyTorch/contrib/cv/detection/Pyramidbox/demo.py @@ -1,141 +1,141 @@ -#-*- coding:utf-8 -*- -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -from __future__ import division -from __future__ import absolute_import -from __future__ import print_function - - -import os -import argparse -import torch -import torch.nn as nn -import torch.backends.cudnn as cudnn -from torch.autograd import Variable - -import torch.npu -import cv2 -import time -import numpy as np -from PIL import Image - -from data.config import cfg -from pyramidbox import build_net -from utils.augmentations import to_chw_bgr - -parser = argparse.ArgumentParser(description='pyramidbox demo') -parser.add_argument('--save_dir', - type=str, default='tmp/', - help='Directory for detect result') -parser.add_argument('--model', - type=str, default='/home/wch/Pyramidbox.pytorch-master/weights/pyramidbox_120000_99.02.pth', - help='trained model') -parser.add_argument('--thresh', - default=0.4, type=float, - help='Final confidence threshold') -args = parser.parse_args() - - -if not os.path.exists(args.save_dir): - os.makedirs(args.save_dir) - -use_npu = torch.npu.is_available() - -if use_npu: - device=f'npu:0' - torch.npu.set_device(device) - - -def detect(net, img_path, thresh): - img = Image.open(img_path) - if img.mode == 'L': - img = img.convert('RGB') - - img = np.array(img) - height, width, _ = img.shape - max_im_shrink = np.sqrt( - 1200 * 1100 / (img.shape[0] * img.shape[1])) - image = cv2.resize(img, None, None, fx=max_im_shrink, - fy=max_im_shrink, interpolation=cv2.INTER_LINEAR) - - x = to_chw_bgr(image) - x = x.astype('float32') - x -= cfg.img_mean - x = x[[2, 1, 0], :, :] - #x = x * cfg.scale - - x = Variable(torch.from_numpy(x).unsqueeze(0)) - if use_npu: - x = x.npu() - t1 = time.time() - y = net(x) - detections = y.data - scale = torch.Tensor([img.shape[1], img.shape[0], - img.shape[1], img.shape[0]]) - - for i in range(detections.size(1)): - j = 0 - while detections[0, i, j, 0] >= thresh: - score = detections[0, i, j, 0] - pt = (detections[0, i, j, 1:] * scale).cpu().numpy().astype(int) - left_up, right_bottom = (pt[0], pt[1]), (pt[2], pt[3]) - j += 1 - cv2.rectangle(img, left_up, right_bottom, (0, 0, 255), 2) - conf = "{:.2f}".format(score) - text_size, baseline = cv2.getTextSize( - conf, cv2.FONT_HERSHEY_SIMPLEX, 0.3, 1) - p1 = (left_up[0], left_up[1] - text_size[1]) - cv2.rectangle(img, (p1[0] - 2 // 2, p1[1] - 2 - baseline), - (p1[0] + text_size[0], p1[1] + text_size[1]), [255, 0, 0], -1) - cv2.putText(img, conf, (p1[0], p1[ - 1] + baseline), cv2.FONT_HERSHEY_SIMPLEX, 0.3, (255, 255, 255), 1, 8) - - t2 = time.time() - print('detect:{} timer:{}'.format(img_path, t2 - t1)) - - cv2.imwrite(os.path.join(args.save_dir, os.path.basename(img_path)), img) - - -if __name__ == '__main__': - net = build_net('test', cfg.NUM_CLASSES) - net.load_state_dict(torch.load(args.model,map_location=lambda storage, loc: storage)) - net.eval() - - if use_npu: - net.npu() - cudnn.benckmark = True - - img_path = './img' - img_list = [os.path.join(img_path, x) - for x in os.listdir(img_path) if x.endswith('jpg')] - for path in img_list: - detect(net, path, args.thresh) +#-*- coding:utf-8 -*- +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +from __future__ import division +from __future__ import absolute_import +from __future__ import print_function + + +import os +import argparse +import torch +import torch.nn as nn +import torch.backends.cudnn as cudnn +from torch.autograd import Variable + +import torch.npu +import cv2 +import time +import numpy as np +from PIL import Image + +from data.config import cfg +from pyramidbox import build_net +from utils.augmentations import to_chw_bgr + +parser = argparse.ArgumentParser(description='pyramidbox demo') +parser.add_argument('--save_dir', + type=str, default='tmp/', + help='Directory for detect result') +parser.add_argument('--model', + type=str, default='/home/wch/Pyramidbox.pytorch-master/weights/pyramidbox_120000_99.02.pth', + help='trained model') +parser.add_argument('--thresh', + default=0.4, type=float, + help='Final confidence threshold') +args = parser.parse_args() + + +if not os.path.exists(args.save_dir): + os.makedirs(args.save_dir) + +use_npu = torch.npu.is_available() + +if use_npu: + device=f'npu:0' + torch.npu.set_device(device) + + +def detect(net, img_path, thresh): + img = Image.open(img_path) + if img.mode == 'L': + img = img.convert('RGB') + + img = np.array(img) + height, width, _ = img.shape + max_im_shrink = np.sqrt( + 1200 * 1100 / (img.shape[0] * img.shape[1])) + image = cv2.resize(img, None, None, fx=max_im_shrink, + fy=max_im_shrink, interpolation=cv2.INTER_LINEAR) + + x = to_chw_bgr(image) + x = x.astype('float32') + x -= cfg.img_mean + x = x[[2, 1, 0], :, :] + #x = x * cfg.scale + + x = Variable(torch.from_numpy(x).unsqueeze(0)) + if use_npu: + x = x.npu() + t1 = time.time() + y = net(x) + detections = y.data + scale = torch.Tensor([img.shape[1], img.shape[0], + img.shape[1], img.shape[0]]) + + for i in range(detections.size(1)): + j = 0 + while detections[0, i, j, 0] >= thresh: + score = detections[0, i, j, 0] + pt = (detections[0, i, j, 1:] * scale).cpu().numpy().astype(int) + left_up, right_bottom = (pt[0], pt[1]), (pt[2], pt[3]) + j += 1 + cv2.rectangle(img, left_up, right_bottom, (0, 0, 255), 2) + conf = "{:.2f}".format(score) + text_size, baseline = cv2.getTextSize( + conf, cv2.FONT_HERSHEY_SIMPLEX, 0.3, 1) + p1 = (left_up[0], left_up[1] - text_size[1]) + cv2.rectangle(img, (p1[0] - 2 // 2, p1[1] - 2 - baseline), + (p1[0] + text_size[0], p1[1] + text_size[1]), [255, 0, 0], -1) + cv2.putText(img, conf, (p1[0], p1[ + 1] + baseline), cv2.FONT_HERSHEY_SIMPLEX, 0.3, (255, 255, 255), 1, 8) + + t2 = time.time() + print('detect:{} timer:{}'.format(img_path, t2 - t1)) + + cv2.imwrite(os.path.join(args.save_dir, os.path.basename(img_path)), img) + + +if __name__ == '__main__': + net = build_net('test', cfg.NUM_CLASSES) + net.load_state_dict(torch.load(args.model,map_location=lambda storage, loc: storage)) + net.eval() + + if use_npu: + net.npu() + cudnn.benckmark = True + + img_path = './img' + img_list = [os.path.join(img_path, x) + for x in os.listdir(img_path) if x.endswith('jpg')] + for path in img_list: + detect(net, path, args.thresh) diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/layers/__init__.py b/PyTorch/contrib/cv/detection/Pyramidbox/layers/__init__.py index 1c1dae6697..f58076f3a3 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/layers/__init__.py +++ b/PyTorch/contrib/cv/detection/Pyramidbox/layers/__init__.py @@ -1,9 +1,9 @@ -#-*- coding:utf-8 -*- - -from __future__ import division -from __future__ import absolute_import -from __future__ import print_function - - -from .functions import * -from .modules import * +#-*- coding:utf-8 -*- + +from __future__ import division +from __future__ import absolute_import +from __future__ import print_function + + +from .functions import * +from .modules import * diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/layers/bbox_utils.py b/PyTorch/contrib/cv/detection/Pyramidbox/layers/bbox_utils.py index 6381fc9ea2..fb7a1987be 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/layers/bbox_utils.py +++ b/PyTorch/contrib/cv/detection/Pyramidbox/layers/bbox_utils.py @@ -1,339 +1,339 @@ -#-*- coding:utf-8 -*- -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 division -from __future__ import absolute_import -from __future__ import print_function - - -import torch -import torch.npu - -def point_form(boxes): - """ Convert prior_boxes to (xmin, ymin, xmax, ymax) - representation for comparison to point form ground truth data. - Args: - boxes: (tensor) center-size default boxes from priorbox layers. - Return: - boxes: (tensor) Converted xmin, ymin, xmax, ymax form of boxes. - """ - return torch.cat((boxes[:, :2] - boxes[:, 2:] / 2, # xmin, ymin - boxes[:, :2] + boxes[:, 2:] / 2), 1) # xmax, ymax - - -def center_size(boxes): - """ Convert prior_boxes to (cx, cy, w, h) - representation for comparison to center-size form ground truth data. - Args: - boxes: (tensor) point_form boxes - Return: - boxes: (tensor) Converted xmin, ymin, xmax, ymax form of boxes. - """ - return torch.cat([(boxes[:, 2:] + boxes[:, :2]) / 2, # cx, cy - boxes[:, 2:] - boxes[:, :2]], 1) # w, h - - -def intersect(box_a, box_b): - """ We resize both tensors to [A,B,2] without new malloc: - [A,2] -> [A,1,2] -> [A,B,2] - [B,2] -> [1,B,2] -> [A,B,2] - Then we compute the area of intersect between box_a and box_b. - Args: - box_a: (tensor) bounding boxes, Shape: [A,4]. - box_b: (tensor) bounding boxes, Shape: [B,4]. - Return: - (tensor) intersection area, Shape: [A,B]. - """ - A = box_a.size(0) - B = box_b.size(0) - max_xy = torch.min(box_a[:, 2:].unsqueeze(1).expand(A, B, 2), - box_b[:, 2:].unsqueeze(0).expand(A, B, 2)) - min_xy = torch.max(box_a[:, :2].unsqueeze(1).expand(A, B, 2), - box_b[:, :2].unsqueeze(0).expand(A, B, 2)) - inter = torch.clamp((max_xy - min_xy), min=0) - return inter[:, :, 0] * inter[:, :, 1] - - -def jaccard(box_a, box_b): - """Compute the jaccard overlap of two sets of boxes. The jaccard overlap - is simply the intersection over union of two boxes. Here we operate on - ground truth boxes and default boxes. - E.g.: - A ∩ B / A ∪ B = A ∩ B / (area(A) + area(B) - A ∩ B) - Args: - box_a: (tensor) Ground truth bounding boxes, Shape: [num_objects,4] - box_b: (tensor) Prior boxes from priorbox layers, Shape: [num_priors,4] - Return: - jaccard overlap: (tensor) Shape: [box_a.size(0), box_b.size(0)] - """ - #when run in npu ,box_b is still in cpu - #box_b = box_b.npu() - inter = intersect(box_a, box_b) - area_a = ((box_a[:, 2] - box_a[:, 0]) * - (box_a[:, 3] - box_a[:, 1])).unsqueeze(1).expand_as(inter) # [A,B] - area_b = ((box_b[:, 2] - box_b[:, 0]) * - (box_b[:, 3] - box_b[:, 1])).unsqueeze(0).expand_as(inter) # [A,B] - union = area_a + area_b - inter - return inter / union # [A,B] - - -def match(threshold, truths, priors, variances, labels, loc_t, conf_t, idx): - """Match each prior box with the ground truth box of the highest jaccard - overlap, encode the bounding boxes, then return the matched indices - corresponding to both confidence and location preds. - Args: - threshold: (float) The overlap threshold used when mathing boxes. - truths: (tensor) Ground truth boxes, Shape: [num_obj, num_priors]. - priors: (tensor) Prior boxes from priorbox layers, Shape: [n_priors,4]. - variances: (tensor) Variances corresponding to each prior coord, - Shape: [num_priors, 4]. - labels: (tensor) All the class labels for the image, Shape: [num_obj]. - loc_t: (tensor) Tensor to be filled w/ endcoded location targets. - conf_t: (tensor) Tensor to be filled w/ matched indices for conf preds. - idx: (int) current batch index - Return: - The matched indices corresponding to 1)location and 2)confidence preds. - """ - # jaccard index - overlaps = jaccard( - truths, - point_form(priors) - ) - # (Bipartite Matching) - # [1,num_objects] best prior for each ground truth - best_prior_overlap, best_prior_idx = overlaps.max(1, keepdim=True) - # [1,num_priors] best ground truth for each prior - best_truth_overlap, best_truth_idx = overlaps.max( - 0, keepdim=True) # 0-2000 - best_truth_idx.squeeze_(0) - best_truth_overlap.squeeze_(0) - best_prior_idx.squeeze_(1) - best_prior_overlap.squeeze_(1) - best_truth_overlap.index_fill_(0, best_prior_idx, 2) # ensure best prior - # TODO refactor: index best_prior_idx with long tensor - # ensure every gt matches with its prior of max overlap - for j in range(best_prior_idx.size(0)): - best_truth_idx[best_prior_idx[j]] = j - _th1, _th2, _th3 = threshold # _th1 = 0.1 ,_th2 = 0.35,_th3 = 0.5 - - N = (torch.sum(best_prior_overlap >= _th2) + - torch.sum(best_prior_overlap >= _th3)) // 2 - matches = truths[best_truth_idx] # Shape: [num_priors,4] - conf = labels[best_truth_idx] # Shape: [num_priors] - conf[best_truth_overlap < _th2] = 0 # label as background - - best_truth_overlap_clone = best_truth_overlap.clone() - add_idx = best_truth_overlap_clone.gt( - _th1).eq(best_truth_overlap_clone.lt(_th2)) - best_truth_overlap_clone[1 - add_idx] = 0 - stage2_overlap, stage2_idx = best_truth_overlap_clone.sort(descending=True) - - stage2_overlap = stage2_overlap.gt(_th1) - - if N > 0: - N = torch.sum(stage2_overlap[:N]) if torch.sum( - stage2_overlap[:N]) < N else N - conf[stage2_idx[:N]] += 1 - - loc = encode(matches, priors, variances) - loc_t[idx] = loc # [num_priors,4] encoded offsets to learn - conf_t[idx] = conf # [num_priors] top class label for each prior - - -def match_ssd(threshold, truths, priors, variances, labels, loc_t, conf_t, idx): - """Match each prior box with the ground truth box of the highest jaccard - overlap, encode the bounding boxes, then return the matched indices - corresponding to both confidence and location preds. - Args: - threshold: (float) The overlap threshold used when mathing boxes. - truths: (tensor) Ground truth boxes, Shape: [num_obj, num_priors]. - priors: (tensor) Prior boxes from priorbox layers, Shape: [n_priors,4]. - variances: (tensor) Variances corresponding to each prior coord, - Shape: [num_priors, 4]. - labels: (tensor) All the class labels for the image, Shape: [num_obj]. - loc_t: (tensor) Tensor to be filled w/ endcoded location targets. - conf_t: (tensor) Tensor to be filled w/ matched indices for conf preds. - idx: (int) current batch index - Return: - The matched indices corresponding to 1)location and 2)confidence preds. - """ - # jaccard index - overlaps = jaccard(truths,point_form(priors)) - # (Bipartite Matching) - # [1,num_objects] best prior for each ground truth - best_prior_overlap, best_prior_idx = overlaps.max(1, keepdim=True) - # [1,num_priors] best ground truth for each prior - best_truth_overlap, best_truth_idx = overlaps.max( - 0, keepdim=True) # 0-2000 - best_truth_idx.squeeze_(0) - best_truth_overlap.squeeze_(0) - best_prior_idx.squeeze_(1) - best_prior_overlap.squeeze_(1) - best_truth_overlap.index_fill_(0, best_prior_idx, 2) # ensure best prior - # TODO refactor: index best_prior_idx with long tensor - # ensure every gt matches with its prior of max overlap - for j in range(best_prior_idx.size(0)): - best_truth_idx[best_prior_idx[j]] = j - matches = truths[best_truth_idx] # Shape: [num_priors,4] - conf = labels[best_truth_idx] # Shape: [num_priors] - conf[best_truth_overlap < threshold] = 0 # label as background - loc = encode(matches, priors, variances) - loc_t[idx] = loc # [num_priors,4] encoded offsets to learn - conf_t[idx] = conf # [num_priors] top class label for each prior - - -def encode(matched, priors, variances): - """Encode the variances from the priorbox layers into the ground truth boxes - we have matched (based on jaccard overlap) with the prior boxes. - Args: - matched: (tensor) Coords of ground truth for each prior in point-form - Shape: [num_priors, 4]. - priors: (tensor) Prior boxes in center-offset form - Shape: [num_priors,4]. - variances: (list[float]) Variances of priorboxes - Return: - encoded boxes (tensor), Shape: [num_priors, 4] - """ - - # dist b/t match center and prior's center - g_cxcy = (matched[:, :2] + matched[:, 2:]) / 2 - priors[:, :2] - # encode variance - g_cxcy /= (variances[0] * priors[:, 2:]) - # match wh / prior wh - g_wh = (matched[:, 2:] - matched[:, :2]) / priors[:, 2:] - #g_wh = torch.log(g_wh) / variances[1] - g_wh = torch.log(g_wh) / variances[1] - # return target for smooth_l1_loss - return torch.cat([g_cxcy, g_wh], 1) # [num_priors,4] - - -# Adapted from https://github.com/Hakuyume/chainer-ssd -def decode(loc, priors, variances): - """Decode locations from predictions using priors to undo - the encoding we did for offset regression at train time. - Args: - loc (tensor): location predictions for loc layers, - Shape: [num_priors,4] - priors (tensor): Prior boxes in center-offset form. - Shape: [num_priors,4]. - variances: (list[float]) Variances of priorboxes - Return: - decoded bounding box predictions - """ - - boxes = torch.cat(( - priors[:, :2] + loc[:, :2] * variances[0] * priors[:, 2:], - priors[:, 2:] * torch.exp(loc[:, 2:] * variances[1])), 1) - boxes[:, :2] -= boxes[:, 2:] / 2 - boxes[:, 2:] += boxes[:, :2] - return boxes - - -def log_sum_exp(x): - """Utility function for computing log_sum_exp while determining - This will be used to determine unaveraged confidence loss across - all examples in a batch. - Args: - x (Variable(tensor)): conf_preds from conf layers - """ - x_max = x.data.max() - return torch.log(torch.sum(torch.exp(x - x_max), 1, keepdim=True)) + x_max - - -# Original author: Francisco Massa: -# https://github.com/fmassa/object-detection.torch -# Ported to PyTorch by Max deGroot (02/01/2017) -def nms(boxes, scores, overlap=0.5, top_k=200): - """Apply non-maximum suppression at test time to avoid detecting too many - overlapping bounding boxes for a given object. - Args: - boxes: (tensor) The location preds for the img, Shape: [num_priors,4]. - scores: (tensor) The class predscores for the img, Shape:[num_priors]. - overlap: (float) The overlap thresh for suppressing unnecessary boxes. - top_k: (int) The Maximum number of box preds to consider. - Return: - The indices of the kept boxes with respect to num_priors. - """ - - keep = scores.new(scores.size(0)).zero_().long() - if boxes.numel() == 0: - return keep - x1 = boxes[:, 0] - y1 = boxes[:, 1] - x2 = boxes[:, 2] - y2 = boxes[:, 3] - area = torch.mul(x2 - x1, y2 - y1) - v, idx = scores.sort(0) # sort in ascending order - # I = I[v >= 0.01] - idx = idx[-top_k:] # indices of the top-k largest vals - xx1 = boxes.new() - yy1 = boxes.new() - xx2 = boxes.new() - yy2 = boxes.new() - w = boxes.new() - h = boxes.new() - - # keep = torch.Tensor() - count = 0 - while idx.numel() > 0: - i = idx[-1] # index of current largest val - # keep.append(i) - keep[count] = i - count += 1 - if idx.size(0) == 1: - break - idx = idx[:-1] # remove kept element from view - #add code--------------------------------------- - idx= torch.autograd.Variable(idx, requires_grad=False) - idx = idx.data - x1 = torch.autograd.Variable(x1, requires_grad=False) - x1 = x1.data - y1 = torch.autograd.Variable(y1, requires_grad=False) - y1 = y1.data - x2 = torch.autograd.Variable(x2, requires_grad=False) - x2 = x2.data - y2 = torch.autograd.Variable(y2, requires_grad=False) - y2 = y2.data - #add code end-------------------------------------- - # load bboxes of next highest vals - torch.index_select(x1, 0, idx, out=xx1) - torch.index_select(y1, 0, idx, out=yy1) - torch.index_select(x2, 0, idx, out=xx2) - torch.index_select(y2, 0, idx, out=yy2) - # store element-wise max with next highest score - xx1 = torch.clamp(xx1, min=x1[i]) - yy1 = torch.clamp(yy1, min=y1[i]) - xx2 = torch.clamp(xx2, max=x2[i]) - yy2 = torch.clamp(yy2, max=y2[i]) - w.resize_as_(xx2) - h.resize_as_(yy2) - w = xx2 - xx1 - h = yy2 - yy1 - # check sizes of xx1 and xx2.. after each iteration - w = torch.clamp(w, min=0.0) - h = torch.clamp(h, min=0.0) - inter = w * h - #add code--------------------------------- - area = torch.autograd.Variable(area, requires_grad=False) - area = area.data - idx= torch.autograd.Variable(idx, requires_grad=False) - idx = idx.data - #add code end ----------------------------------- - # IoU = i / (area(a) + area(b) - i) - rem_areas = torch.index_select(area, 0, idx) # load remaining areas) - union = (rem_areas - inter) + area[i] - IoU = inter / union # store result in iou - # keep only elements with an IoU <= overlap - idx = idx[IoU.le(overlap)] - return keep, count +#-*- coding:utf-8 -*- +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 division +from __future__ import absolute_import +from __future__ import print_function + + +import torch +import torch.npu + +def point_form(boxes): + """ Convert prior_boxes to (xmin, ymin, xmax, ymax) + representation for comparison to point form ground truth data. + Args: + boxes: (tensor) center-size default boxes from priorbox layers. + Return: + boxes: (tensor) Converted xmin, ymin, xmax, ymax form of boxes. + """ + return torch.cat((boxes[:, :2] - boxes[:, 2:] / 2, # xmin, ymin + boxes[:, :2] + boxes[:, 2:] / 2), 1) # xmax, ymax + + +def center_size(boxes): + """ Convert prior_boxes to (cx, cy, w, h) + representation for comparison to center-size form ground truth data. + Args: + boxes: (tensor) point_form boxes + Return: + boxes: (tensor) Converted xmin, ymin, xmax, ymax form of boxes. + """ + return torch.cat([(boxes[:, 2:] + boxes[:, :2]) / 2, # cx, cy + boxes[:, 2:] - boxes[:, :2]], 1) # w, h + + +def intersect(box_a, box_b): + """ We resize both tensors to [A,B,2] without new malloc: + [A,2] -> [A,1,2] -> [A,B,2] + [B,2] -> [1,B,2] -> [A,B,2] + Then we compute the area of intersect between box_a and box_b. + Args: + box_a: (tensor) bounding boxes, Shape: [A,4]. + box_b: (tensor) bounding boxes, Shape: [B,4]. + Return: + (tensor) intersection area, Shape: [A,B]. + """ + A = box_a.size(0) + B = box_b.size(0) + max_xy = torch.min(box_a[:, 2:].unsqueeze(1).expand(A, B, 2), + box_b[:, 2:].unsqueeze(0).expand(A, B, 2)) + min_xy = torch.max(box_a[:, :2].unsqueeze(1).expand(A, B, 2), + box_b[:, :2].unsqueeze(0).expand(A, B, 2)) + inter = torch.clamp((max_xy - min_xy), min=0) + return inter[:, :, 0] * inter[:, :, 1] + + +def jaccard(box_a, box_b): + """Compute the jaccard overlap of two sets of boxes. The jaccard overlap + is simply the intersection over union of two boxes. Here we operate on + ground truth boxes and default boxes. + E.g.: + A ∩ B / A ∪ B = A ∩ B / (area(A) + area(B) - A ∩ B) + Args: + box_a: (tensor) Ground truth bounding boxes, Shape: [num_objects,4] + box_b: (tensor) Prior boxes from priorbox layers, Shape: [num_priors,4] + Return: + jaccard overlap: (tensor) Shape: [box_a.size(0), box_b.size(0)] + """ + #when run in npu ,box_b is still in cpu + #box_b = box_b.npu() + inter = intersect(box_a, box_b) + area_a = ((box_a[:, 2] - box_a[:, 0]) * + (box_a[:, 3] - box_a[:, 1])).unsqueeze(1).expand_as(inter) # [A,B] + area_b = ((box_b[:, 2] - box_b[:, 0]) * + (box_b[:, 3] - box_b[:, 1])).unsqueeze(0).expand_as(inter) # [A,B] + union = area_a + area_b - inter + return inter / union # [A,B] + + +def match(threshold, truths, priors, variances, labels, loc_t, conf_t, idx): + """Match each prior box with the ground truth box of the highest jaccard + overlap, encode the bounding boxes, then return the matched indices + corresponding to both confidence and location preds. + Args: + threshold: (float) The overlap threshold used when mathing boxes. + truths: (tensor) Ground truth boxes, Shape: [num_obj, num_priors]. + priors: (tensor) Prior boxes from priorbox layers, Shape: [n_priors,4]. + variances: (tensor) Variances corresponding to each prior coord, + Shape: [num_priors, 4]. + labels: (tensor) All the class labels for the image, Shape: [num_obj]. + loc_t: (tensor) Tensor to be filled w/ endcoded location targets. + conf_t: (tensor) Tensor to be filled w/ matched indices for conf preds. + idx: (int) current batch index + Return: + The matched indices corresponding to 1)location and 2)confidence preds. + """ + # jaccard index + overlaps = jaccard( + truths, + point_form(priors) + ) + # (Bipartite Matching) + # [1,num_objects] best prior for each ground truth + best_prior_overlap, best_prior_idx = overlaps.max(1, keepdim=True) + # [1,num_priors] best ground truth for each prior + best_truth_overlap, best_truth_idx = overlaps.max( + 0, keepdim=True) # 0-2000 + best_truth_idx.squeeze_(0) + best_truth_overlap.squeeze_(0) + best_prior_idx.squeeze_(1) + best_prior_overlap.squeeze_(1) + best_truth_overlap.index_fill_(0, best_prior_idx, 2) # ensure best prior + # TODO refactor: index best_prior_idx with long tensor + # ensure every gt matches with its prior of max overlap + for j in range(best_prior_idx.size(0)): + best_truth_idx[best_prior_idx[j]] = j + _th1, _th2, _th3 = threshold # _th1 = 0.1 ,_th2 = 0.35,_th3 = 0.5 + + N = (torch.sum(best_prior_overlap >= _th2) + + torch.sum(best_prior_overlap >= _th3)) // 2 + matches = truths[best_truth_idx] # Shape: [num_priors,4] + conf = labels[best_truth_idx] # Shape: [num_priors] + conf[best_truth_overlap < _th2] = 0 # label as background + + best_truth_overlap_clone = best_truth_overlap.clone() + add_idx = best_truth_overlap_clone.gt( + _th1).eq(best_truth_overlap_clone.lt(_th2)) + best_truth_overlap_clone[1 - add_idx] = 0 + stage2_overlap, stage2_idx = best_truth_overlap_clone.sort(descending=True) + + stage2_overlap = stage2_overlap.gt(_th1) + + if N > 0: + N = torch.sum(stage2_overlap[:N]) if torch.sum( + stage2_overlap[:N]) < N else N + conf[stage2_idx[:N]] += 1 + + loc = encode(matches, priors, variances) + loc_t[idx] = loc # [num_priors,4] encoded offsets to learn + conf_t[idx] = conf # [num_priors] top class label for each prior + + +def match_ssd(threshold, truths, priors, variances, labels, loc_t, conf_t, idx): + """Match each prior box with the ground truth box of the highest jaccard + overlap, encode the bounding boxes, then return the matched indices + corresponding to both confidence and location preds. + Args: + threshold: (float) The overlap threshold used when mathing boxes. + truths: (tensor) Ground truth boxes, Shape: [num_obj, num_priors]. + priors: (tensor) Prior boxes from priorbox layers, Shape: [n_priors,4]. + variances: (tensor) Variances corresponding to each prior coord, + Shape: [num_priors, 4]. + labels: (tensor) All the class labels for the image, Shape: [num_obj]. + loc_t: (tensor) Tensor to be filled w/ endcoded location targets. + conf_t: (tensor) Tensor to be filled w/ matched indices for conf preds. + idx: (int) current batch index + Return: + The matched indices corresponding to 1)location and 2)confidence preds. + """ + # jaccard index + overlaps = jaccard(truths,point_form(priors)) + # (Bipartite Matching) + # [1,num_objects] best prior for each ground truth + best_prior_overlap, best_prior_idx = overlaps.max(1, keepdim=True) + # [1,num_priors] best ground truth for each prior + best_truth_overlap, best_truth_idx = overlaps.max( + 0, keepdim=True) # 0-2000 + best_truth_idx.squeeze_(0) + best_truth_overlap.squeeze_(0) + best_prior_idx.squeeze_(1) + best_prior_overlap.squeeze_(1) + best_truth_overlap.index_fill_(0, best_prior_idx, 2) # ensure best prior + # TODO refactor: index best_prior_idx with long tensor + # ensure every gt matches with its prior of max overlap + for j in range(best_prior_idx.size(0)): + best_truth_idx[best_prior_idx[j]] = j + matches = truths[best_truth_idx] # Shape: [num_priors,4] + conf = labels[best_truth_idx] # Shape: [num_priors] + conf[best_truth_overlap < threshold] = 0 # label as background + loc = encode(matches, priors, variances) + loc_t[idx] = loc # [num_priors,4] encoded offsets to learn + conf_t[idx] = conf # [num_priors] top class label for each prior + + +def encode(matched, priors, variances): + """Encode the variances from the priorbox layers into the ground truth boxes + we have matched (based on jaccard overlap) with the prior boxes. + Args: + matched: (tensor) Coords of ground truth for each prior in point-form + Shape: [num_priors, 4]. + priors: (tensor) Prior boxes in center-offset form + Shape: [num_priors,4]. + variances: (list[float]) Variances of priorboxes + Return: + encoded boxes (tensor), Shape: [num_priors, 4] + """ + + # dist b/t match center and prior's center + g_cxcy = (matched[:, :2] + matched[:, 2:]) / 2 - priors[:, :2] + # encode variance + g_cxcy /= (variances[0] * priors[:, 2:]) + # match wh / prior wh + g_wh = (matched[:, 2:] - matched[:, :2]) / priors[:, 2:] + #g_wh = torch.log(g_wh) / variances[1] + g_wh = torch.log(g_wh) / variances[1] + # return target for smooth_l1_loss + return torch.cat([g_cxcy, g_wh], 1) # [num_priors,4] + + +# Adapted from https://github.com/Hakuyume/chainer-ssd +def decode(loc, priors, variances): + """Decode locations from predictions using priors to undo + the encoding we did for offset regression at train time. + Args: + loc (tensor): location predictions for loc layers, + Shape: [num_priors,4] + priors (tensor): Prior boxes in center-offset form. + Shape: [num_priors,4]. + variances: (list[float]) Variances of priorboxes + Return: + decoded bounding box predictions + """ + + boxes = torch.cat(( + priors[:, :2] + loc[:, :2] * variances[0] * priors[:, 2:], + priors[:, 2:] * torch.exp(loc[:, 2:] * variances[1])), 1) + boxes[:, :2] -= boxes[:, 2:] / 2 + boxes[:, 2:] += boxes[:, :2] + return boxes + + +def log_sum_exp(x): + """Utility function for computing log_sum_exp while determining + This will be used to determine unaveraged confidence loss across + all examples in a batch. + Args: + x (Variable(tensor)): conf_preds from conf layers + """ + x_max = x.data.max() + return torch.log(torch.sum(torch.exp(x - x_max), 1, keepdim=True)) + x_max + + +# Original author: Francisco Massa: +# https://github.com/fmassa/object-detection.torch +# Ported to PyTorch by Max deGroot (02/01/2017) +def nms(boxes, scores, overlap=0.5, top_k=200): + """Apply non-maximum suppression at test time to avoid detecting too many + overlapping bounding boxes for a given object. + Args: + boxes: (tensor) The location preds for the img, Shape: [num_priors,4]. + scores: (tensor) The class predscores for the img, Shape:[num_priors]. + overlap: (float) The overlap thresh for suppressing unnecessary boxes. + top_k: (int) The Maximum number of box preds to consider. + Return: + The indices of the kept boxes with respect to num_priors. + """ + + keep = scores.new(scores.size(0)).zero_().long() + if boxes.numel() == 0: + return keep + x1 = boxes[:, 0] + y1 = boxes[:, 1] + x2 = boxes[:, 2] + y2 = boxes[:, 3] + area = torch.mul(x2 - x1, y2 - y1) + v, idx = scores.sort(0) # sort in ascending order + # I = I[v >= 0.01] + idx = idx[-top_k:] # indices of the top-k largest vals + xx1 = boxes.new() + yy1 = boxes.new() + xx2 = boxes.new() + yy2 = boxes.new() + w = boxes.new() + h = boxes.new() + + # keep = torch.Tensor() + count = 0 + while idx.numel() > 0: + i = idx[-1] # index of current largest val + # keep.append(i) + keep[count] = i + count += 1 + if idx.size(0) == 1: + break + idx = idx[:-1] # remove kept element from view + #add code--------------------------------------- + idx= torch.autograd.Variable(idx, requires_grad=False) + idx = idx.data + x1 = torch.autograd.Variable(x1, requires_grad=False) + x1 = x1.data + y1 = torch.autograd.Variable(y1, requires_grad=False) + y1 = y1.data + x2 = torch.autograd.Variable(x2, requires_grad=False) + x2 = x2.data + y2 = torch.autograd.Variable(y2, requires_grad=False) + y2 = y2.data + #add code end-------------------------------------- + # load bboxes of next highest vals + torch.index_select(x1, 0, idx, out=xx1) + torch.index_select(y1, 0, idx, out=yy1) + torch.index_select(x2, 0, idx, out=xx2) + torch.index_select(y2, 0, idx, out=yy2) + # store element-wise max with next highest score + xx1 = torch.clamp(xx1, min=x1[i]) + yy1 = torch.clamp(yy1, min=y1[i]) + xx2 = torch.clamp(xx2, max=x2[i]) + yy2 = torch.clamp(yy2, max=y2[i]) + w.resize_as_(xx2) + h.resize_as_(yy2) + w = xx2 - xx1 + h = yy2 - yy1 + # check sizes of xx1 and xx2.. after each iteration + w = torch.clamp(w, min=0.0) + h = torch.clamp(h, min=0.0) + inter = w * h + #add code--------------------------------- + area = torch.autograd.Variable(area, requires_grad=False) + area = area.data + idx= torch.autograd.Variable(idx, requires_grad=False) + idx = idx.data + #add code end ----------------------------------- + # IoU = i / (area(a) + area(b) - i) + rem_areas = torch.index_select(area, 0, idx) # load remaining areas) + union = (rem_areas - inter) + area[i] + IoU = inter / union # store result in iou + # keep only elements with an IoU <= overlap + idx = idx[IoU.le(overlap)] + return keep, count diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/layers/functions/__init__.py b/PyTorch/contrib/cv/detection/Pyramidbox/layers/functions/__init__.py index 5d4c8d36bb..d8d93bae04 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/layers/functions/__init__.py +++ b/PyTorch/contrib/cv/detection/Pyramidbox/layers/functions/__init__.py @@ -1,5 +1,5 @@ -from .prior_box import PriorBox -from .detection import Detect - -__all__=['Detect','PriorBox'] - +from .prior_box import PriorBox +from .detection import Detect + +__all__=['Detect','PriorBox'] + diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/layers/functions/detection.py b/PyTorch/contrib/cv/detection/Pyramidbox/layers/functions/detection.py index a37ae6bb94..b68c7fb405 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/layers/functions/detection.py +++ b/PyTorch/contrib/cv/detection/Pyramidbox/layers/functions/detection.py @@ -1,82 +1,82 @@ -#-*- coding:utf-8 -*- -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 division -from __future__ import absolute_import -from __future__ import print_function - -import torch - -from ..bbox_utils import decode, nms -from torch.autograd import Function - - -class Detect(Function): - """At test time, Detect is the final layer of SSD. Decode location preds, - apply non-maximum suppression to location predictions based on conf - scores and threshold to a top_k number of output predictions for both - confidence score and locations. - """ - - def __init__(self, cfg): - self.num_classes = cfg.NUM_CLASSES - self.top_k = cfg.TOP_K - self.nms_thresh = cfg.NMS_THRESH - self.conf_thresh = cfg.CONF_THRESH - self.variance = cfg.VARIANCE - - def forward(self, loc_data, conf_data, prior_data): - """ - Args: - loc_data: (tensor) Loc preds from loc layers - Shape: [batch,num_priors*4] - conf_data: (tensor) Shape: Conf preds from conf layers - Shape: [batch*num_priors,num_classes] - prior_data: (tensor) Prior boxes and variances from priorbox layers - Shape: [1,num_priors,4] - """ - #print('loc_data device:{}'.format(loc_data.device)) - #print('conf_data device:{}'.format(conf_data.device)) - #print('prior_data device:{}'.format(prior_data.device)) - num = loc_data.size(0) - num_priors = prior_data.size(0) - - conf_preds = conf_data.view( - num, num_priors, self.num_classes).transpose(2, 1) - batch_priors = prior_data.view(-1, num_priors, - 4).expand(num, num_priors, 4) - batch_priors = batch_priors.contiguous().view(-1, 4) - - decoded_boxes = decode(loc_data.view(-1, 4), - batch_priors, self.variance) - decoded_boxes = decoded_boxes.view(num, num_priors, 4) - - output = torch.zeros(num, self.num_classes, self.top_k, 5) - - for i in range(num): - boxes = decoded_boxes[i].clone() - conf_scores = conf_preds[i].clone() - for cl in range(1, self.num_classes): - c_mask = conf_scores[cl].gt(self.conf_thresh) - scores = conf_scores[cl][c_mask] - #change code - if scores.numel() == 0: - continue - l_mask = c_mask.unsqueeze(1).expand_as(boxes) - boxes_ = boxes[l_mask].view(-1, 4) - ids, count = nms(boxes_, scores, self.nms_thresh, self.top_k) - output[i, cl, :count] = torch.cat((scores[ids[:count]].unsqueeze(1), - boxes_[ids[:count]]), 1) - - return output +#-*- coding:utf-8 -*- +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 division +from __future__ import absolute_import +from __future__ import print_function + +import torch + +from ..bbox_utils import decode, nms +from torch.autograd import Function + + +class Detect(Function): + """At test time, Detect is the final layer of SSD. Decode location preds, + apply non-maximum suppression to location predictions based on conf + scores and threshold to a top_k number of output predictions for both + confidence score and locations. + """ + + def __init__(self, cfg): + self.num_classes = cfg.NUM_CLASSES + self.top_k = cfg.TOP_K + self.nms_thresh = cfg.NMS_THRESH + self.conf_thresh = cfg.CONF_THRESH + self.variance = cfg.VARIANCE + + def forward(self, loc_data, conf_data, prior_data): + """ + Args: + loc_data: (tensor) Loc preds from loc layers + Shape: [batch,num_priors*4] + conf_data: (tensor) Shape: Conf preds from conf layers + Shape: [batch*num_priors,num_classes] + prior_data: (tensor) Prior boxes and variances from priorbox layers + Shape: [1,num_priors,4] + """ + #print('loc_data device:{}'.format(loc_data.device)) + #print('conf_data device:{}'.format(conf_data.device)) + #print('prior_data device:{}'.format(prior_data.device)) + num = loc_data.size(0) + num_priors = prior_data.size(0) + + conf_preds = conf_data.view( + num, num_priors, self.num_classes).transpose(2, 1) + batch_priors = prior_data.view(-1, num_priors, + 4).expand(num, num_priors, 4) + batch_priors = batch_priors.contiguous().view(-1, 4) + + decoded_boxes = decode(loc_data.view(-1, 4), + batch_priors, self.variance) + decoded_boxes = decoded_boxes.view(num, num_priors, 4) + + output = torch.zeros(num, self.num_classes, self.top_k, 5) + + for i in range(num): + boxes = decoded_boxes[i].clone() + conf_scores = conf_preds[i].clone() + for cl in range(1, self.num_classes): + c_mask = conf_scores[cl].gt(self.conf_thresh) + scores = conf_scores[cl][c_mask] + #change code + if scores.numel() == 0: + continue + l_mask = c_mask.unsqueeze(1).expand_as(boxes) + boxes_ = boxes[l_mask].view(-1, 4) + ids, count = nms(boxes_, scores, self.nms_thresh, self.top_k) + output[i, cl, :count] = torch.cat((scores[ids[:count]].unsqueeze(1), + boxes_[ids[:count]]), 1) + + return output diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/layers/functions/prior_box.py b/PyTorch/contrib/cv/detection/Pyramidbox/layers/functions/prior_box.py index 48bd01be69..b09f5707e0 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/layers/functions/prior_box.py +++ b/PyTorch/contrib/cv/detection/Pyramidbox/layers/functions/prior_box.py @@ -1,73 +1,73 @@ -#-*- coding:utf-8 -*- -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 division -from __future__ import absolute_import -from __future__ import print_function - -import torch -from itertools import product as product -import math - - -class PriorBox(object): - """Compute priorbox coordinates in center-offset form for each source - feature map. - """ - - def __init__(self, input_size, feature_maps,cfg): - super(PriorBox, self).__init__() - self.imh = input_size[0] - self.imw = input_size[1] - - # number of priors for feature map location (either 4 or 6) - self.variance = cfg.VARIANCE or [0.1] - #self.feature_maps = cfg.FEATURE_MAPS - self.min_sizes = cfg.ANCHOR_SIZES - self.steps = cfg.STEPS - self.clip = cfg.CLIP - for v in self.variance: - if v <= 0: - raise ValueError('Variances must be greater than 0') - self.feature_maps = feature_maps - - - def forward(self): - mean = [] - for k in range(len(self.feature_maps)): - feath = self.feature_maps[k][0] - featw = self.feature_maps[k][1] - for i, j in product(range(feath), range(featw)): - f_kw = self.imw / self.steps[k] - f_kh = self.imh / self.steps[k] - - cx = (j + 0.5) / f_kw - cy = (i + 0.5) / f_kh - - s_kw = self.min_sizes[k] / self.imw - s_kh = self.min_sizes[k] / self.imh - - mean += [cx, cy, s_kw, s_kh] - - output = torch.Tensor(mean).view(-1, 4) - if self.clip: - output.clamp_(max=1, min=0) - return output - - -if __name__ == '__main__': - from data.config import cfg - p = PriorBox([640, 640], cfg) - out = p.forward() - print(out.size()) +#-*- coding:utf-8 -*- +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 division +from __future__ import absolute_import +from __future__ import print_function + +import torch +from itertools import product as product +import math + + +class PriorBox(object): + """Compute priorbox coordinates in center-offset form for each source + feature map. + """ + + def __init__(self, input_size, feature_maps,cfg): + super(PriorBox, self).__init__() + self.imh = input_size[0] + self.imw = input_size[1] + + # number of priors for feature map location (either 4 or 6) + self.variance = cfg.VARIANCE or [0.1] + #self.feature_maps = cfg.FEATURE_MAPS + self.min_sizes = cfg.ANCHOR_SIZES + self.steps = cfg.STEPS + self.clip = cfg.CLIP + for v in self.variance: + if v <= 0: + raise ValueError('Variances must be greater than 0') + self.feature_maps = feature_maps + + + def forward(self): + mean = [] + for k in range(len(self.feature_maps)): + feath = self.feature_maps[k][0] + featw = self.feature_maps[k][1] + for i, j in product(range(feath), range(featw)): + f_kw = self.imw / self.steps[k] + f_kh = self.imh / self.steps[k] + + cx = (j + 0.5) / f_kw + cy = (i + 0.5) / f_kh + + s_kw = self.min_sizes[k] / self.imw + s_kh = self.min_sizes[k] / self.imh + + mean += [cx, cy, s_kw, s_kh] + + output = torch.Tensor(mean).view(-1, 4) + if self.clip: + output.clamp_(max=1, min=0) + return output + + +if __name__ == '__main__': + from data.config import cfg + p = PriorBox([640, 640], cfg) + out = p.forward() + print(out.size()) diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/layers/modules/__init__.py b/PyTorch/contrib/cv/detection/Pyramidbox/layers/modules/__init__.py index d1433bff7f..9abf8e1350 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/layers/modules/__init__.py +++ b/PyTorch/contrib/cv/detection/Pyramidbox/layers/modules/__init__.py @@ -1,12 +1,12 @@ -#-*- coding:utf-8 -*- - -from __future__ import division -from __future__ import absolute_import -from __future__ import print_function - - -from .l2norm import L2Norm -from .multibox_loss import MultiBoxLoss - -__all__ = ['L2Norm', 'MultiBoxLoss'] - +#-*- coding:utf-8 -*- + +from __future__ import division +from __future__ import absolute_import +from __future__ import print_function + + +from .l2norm import L2Norm +from .multibox_loss import MultiBoxLoss + +__all__ = ['L2Norm', 'MultiBoxLoss'] + diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/layers/modules/l2norm.py b/PyTorch/contrib/cv/detection/Pyramidbox/layers/modules/l2norm.py index 0c77185ed8..ca04e0bb3f 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/layers/modules/l2norm.py +++ b/PyTorch/contrib/cv/detection/Pyramidbox/layers/modules/l2norm.py @@ -1,48 +1,48 @@ -#-*- coding:utf-8 -*- -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 division -from __future__ import absolute_import -from __future__ import print_function - - -import torch -import torch.nn as nn -import torch.nn.init as init -from torch.autograd import Function -from torch.autograd import Variable - - - -class L2Norm(nn.Module): - def __init__(self,n_channels, scale): - super(L2Norm,self).__init__() - self.n_channels = n_channels - self.gamma = scale or None - self.eps = 1e-10 - self.weight = nn.Parameter(torch.Tensor(self.n_channels)) - self.reset_parameters() - - def reset_parameters(self): - init.constant_(self.weight,self.gamma) - - def forward(self, x): - norm = x.pow(2).sum(dim=1, keepdim=True).sqrt()+self.eps - #x /= norm - x = torch.div(x,norm) - out = self.weight.unsqueeze(0).unsqueeze(2).unsqueeze(3).expand_as(x) * x - return out - - +#-*- coding:utf-8 -*- +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 division +from __future__ import absolute_import +from __future__ import print_function + + +import torch +import torch.nn as nn +import torch.nn.init as init +from torch.autograd import Function +from torch.autograd import Variable + + + +class L2Norm(nn.Module): + def __init__(self,n_channels, scale): + super(L2Norm,self).__init__() + self.n_channels = n_channels + self.gamma = scale or None + self.eps = 1e-10 + self.weight = nn.Parameter(torch.Tensor(self.n_channels)) + self.reset_parameters() + + def reset_parameters(self): + init.constant_(self.weight,self.gamma) + + def forward(self, x): + norm = x.pow(2).sum(dim=1, keepdim=True).sqrt()+self.eps + #x /= norm + x = torch.div(x,norm) + out = self.weight.unsqueeze(0).unsqueeze(2).unsqueeze(3).expand_as(x) * x + return out + + \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/layers/modules/multibox_loss.py b/PyTorch/contrib/cv/detection/Pyramidbox/layers/modules/multibox_loss.py index 18d2ddff33..9b8b1d1078 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/layers/modules/multibox_loss.py +++ b/PyTorch/contrib/cv/detection/Pyramidbox/layers/modules/multibox_loss.py @@ -1,159 +1,159 @@ -#-*- coding:utf-8 -*- -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -from __future__ import division -from __future__ import absolute_import -from __future__ import print_function - -import math -import torch -import torch.nn as nn -import torch.nn.functional as F -from torch.autograd import Variable -import torch.npu - -from ..bbox_utils import match, log_sum_exp, match_ssd - - -class MultiBoxLoss(nn.Module): - """SSD Weighted Loss Function - Compute Targets: - 1) Produce Confidence Target Indices by matching ground truth boxes - with (default) 'priorboxes' that have jaccard index > threshold parameter - (default threshold: 0.5). - 2) Produce localization target by 'encoding' variance into offsets of ground - truth boxes and their matched 'priorboxes'. - 3) Hard negative mining to filter the excessive number of negative examples - that comes with using a large number of default bounding boxes. - (default negative:positive ratio 3:1) - Objective Loss: - L(x,c,l,g) = (Lconf(x, c) + αLloc(x,l,g)) / N - Where, Lconf is the CrossEntropy Loss and Lloc is the SmoothL1 Loss - weighted by α which is set to 1 by cross val. - Args: - c: class confidences, - l: predicted boxes, - g: ground truth boxes - N: number of matched default boxes - See: https://arxiv.org/pdf/1512.02325.pdf for more details. - """ - - def __init__(self, - cfg, - use_npu=True, - use_head_loss=False): - super(MultiBoxLoss, self).__init__() - self.use_npu = use_npu - self.num_classes = cfg.NUM_CLASSES - self.negpos_ratio = cfg.NEG_POS_RATIOS - self.variance = cfg.VARIANCE - self.use_head_loss = use_head_loss - self.threshold = cfg.FACE.OVERLAP_THRESH - self.match = match_ssd - - def forward(self, - predictions, - targets): - """Multibox Loss - Args: - predictions (tuple): A tuple containing loc preds, conf preds, - and prior boxes from SSD net. - conf shape: torch.size(batch_size,num_priors,num_classes) - loc shape: torch.size(batch_size,num_priors,4) - priors shape: torch.size(num_priors,4) - - targets (tensor): Ground truth boxes and labels for a batch, - shape: [batch_size,num_objs,5] (last idx is the label). - """ - if self.use_head_loss: - _, _, loc_data, conf_data, priors = predictions - else: - loc_data, conf_data, _, _, priors = predictions - loc_data = loc_data.cpu() - conf_data = conf_data.cpu() - priors = priors.cpu() - num = loc_data.size(0) - priors = priors[:loc_data.size(1), :] - num_priors = (priors.size(0)) - num_classes = self.num_classes - # match priors (default boxes) and ground truth boxes - loc_t = torch.Tensor(num, num_priors, 4) - conf_t = torch.LongTensor(num, num_priors) - for idx in range(num): - truths = targets[idx][:, :-1].data - labels = targets[idx][:, -1].data - defaults = priors.data - self.match(self.threshold, truths, defaults, self.variance, labels, - loc_t, conf_t, idx) - # wrap targets - loc_t = Variable(loc_t, requires_grad=False) - conf_t = Variable(conf_t, requires_grad=False) - - pos = conf_t > 0 - num_pos = pos.sum(dim=1, keepdim=True) - # Localization Loss (Smooth L1) - # Shape: [batch,num_priors,4] - pos_idx = pos.unsqueeze(pos.dim()).expand_as(loc_data) - loc_p = loc_data[pos_idx].view(-1, 4) - loc_t = loc_t[pos_idx].view(-1, 4) - loss_l = F.smooth_l1_loss(loc_p, loc_t, size_average=False) - batch_conf = conf_data.view(-1, self.num_classes) - loss_c = log_sum_exp(batch_conf) - \ - batch_conf.gather(1, conf_t.view(-1, 1)) - - # Hard Negative Mining - loss_c =loss_c.cpu() - pos1 = pos.view(-1,1) - loss_c[pos1] = 0 # filter out pos boxes for now - loss_c = loss_c.view(num, -1) - _, loss_idx = loss_c.sort(1, descending=True) - _, idx_rank = loss_idx.sort(1) - - num_pos = pos.long().sum(1, keepdim=True) - num_neg = torch.clamp(self.negpos_ratio * - num_pos, max=pos.size(1) - 1) - neg = idx_rank < num_neg.expand_as(idx_rank) - - # Confidence Loss Including Positive and Negative Examples - conf_data = conf_data.cpu() - pos_idx = pos.unsqueeze(2).expand_as(conf_data) - neg_idx = neg.unsqueeze(2).expand_as(conf_data) - conf_p = conf_data[(pos_idx + neg_idx).gt(0) - ].view(-1, self.num_classes) - targets_weighted = conf_t[(pos + neg).gt(0)] - loss_c = F.cross_entropy(conf_p, targets_weighted, size_average=False) - - # Sum of losses: L(x,c,l,g) = (Lconf(x, c) + αLloc(x,l,g)) / N - N = num_pos.data.sum() if num_pos.data.sum() > 0 else num - loss_l /= N - loss_c /= N - return loss_l, loss_c +#-*- coding:utf-8 -*- +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +from __future__ import division +from __future__ import absolute_import +from __future__ import print_function + +import math +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.autograd import Variable +import torch.npu + +from ..bbox_utils import match, log_sum_exp, match_ssd + + +class MultiBoxLoss(nn.Module): + """SSD Weighted Loss Function + Compute Targets: + 1) Produce Confidence Target Indices by matching ground truth boxes + with (default) 'priorboxes' that have jaccard index > threshold parameter + (default threshold: 0.5). + 2) Produce localization target by 'encoding' variance into offsets of ground + truth boxes and their matched 'priorboxes'. + 3) Hard negative mining to filter the excessive number of negative examples + that comes with using a large number of default bounding boxes. + (default negative:positive ratio 3:1) + Objective Loss: + L(x,c,l,g) = (Lconf(x, c) + αLloc(x,l,g)) / N + Where, Lconf is the CrossEntropy Loss and Lloc is the SmoothL1 Loss + weighted by α which is set to 1 by cross val. + Args: + c: class confidences, + l: predicted boxes, + g: ground truth boxes + N: number of matched default boxes + See: https://arxiv.org/pdf/1512.02325.pdf for more details. + """ + + def __init__(self, + cfg, + use_npu=True, + use_head_loss=False): + super(MultiBoxLoss, self).__init__() + self.use_npu = use_npu + self.num_classes = cfg.NUM_CLASSES + self.negpos_ratio = cfg.NEG_POS_RATIOS + self.variance = cfg.VARIANCE + self.use_head_loss = use_head_loss + self.threshold = cfg.FACE.OVERLAP_THRESH + self.match = match_ssd + + def forward(self, + predictions, + targets): + """Multibox Loss + Args: + predictions (tuple): A tuple containing loc preds, conf preds, + and prior boxes from SSD net. + conf shape: torch.size(batch_size,num_priors,num_classes) + loc shape: torch.size(batch_size,num_priors,4) + priors shape: torch.size(num_priors,4) + + targets (tensor): Ground truth boxes and labels for a batch, + shape: [batch_size,num_objs,5] (last idx is the label). + """ + if self.use_head_loss: + _, _, loc_data, conf_data, priors = predictions + else: + loc_data, conf_data, _, _, priors = predictions + loc_data = loc_data.cpu() + conf_data = conf_data.cpu() + priors = priors.cpu() + num = loc_data.size(0) + priors = priors[:loc_data.size(1), :] + num_priors = (priors.size(0)) + num_classes = self.num_classes + # match priors (default boxes) and ground truth boxes + loc_t = torch.Tensor(num, num_priors, 4) + conf_t = torch.LongTensor(num, num_priors) + for idx in range(num): + truths = targets[idx][:, :-1].data + labels = targets[idx][:, -1].data + defaults = priors.data + self.match(self.threshold, truths, defaults, self.variance, labels, + loc_t, conf_t, idx) + # wrap targets + loc_t = Variable(loc_t, requires_grad=False) + conf_t = Variable(conf_t, requires_grad=False) + + pos = conf_t > 0 + num_pos = pos.sum(dim=1, keepdim=True) + # Localization Loss (Smooth L1) + # Shape: [batch,num_priors,4] + pos_idx = pos.unsqueeze(pos.dim()).expand_as(loc_data) + loc_p = loc_data[pos_idx].view(-1, 4) + loc_t = loc_t[pos_idx].view(-1, 4) + loss_l = F.smooth_l1_loss(loc_p, loc_t, size_average=False) + batch_conf = conf_data.view(-1, self.num_classes) + loss_c = log_sum_exp(batch_conf) - \ + batch_conf.gather(1, conf_t.view(-1, 1)) + + # Hard Negative Mining + loss_c =loss_c.cpu() + pos1 = pos.view(-1,1) + loss_c[pos1] = 0 # filter out pos boxes for now + loss_c = loss_c.view(num, -1) + _, loss_idx = loss_c.sort(1, descending=True) + _, idx_rank = loss_idx.sort(1) + + num_pos = pos.long().sum(1, keepdim=True) + num_neg = torch.clamp(self.negpos_ratio * + num_pos, max=pos.size(1) - 1) + neg = idx_rank < num_neg.expand_as(idx_rank) + + # Confidence Loss Including Positive and Negative Examples + conf_data = conf_data.cpu() + pos_idx = pos.unsqueeze(2).expand_as(conf_data) + neg_idx = neg.unsqueeze(2).expand_as(conf_data) + conf_p = conf_data[(pos_idx + neg_idx).gt(0) + ].view(-1, self.num_classes) + targets_weighted = conf_t[(pos + neg).gt(0)] + loss_c = F.cross_entropy(conf_p, targets_weighted, size_average=False) + + # Sum of losses: L(x,c,l,g) = (Lconf(x, c) + αLloc(x,l,g)) / N + N = num_pos.data.sum() if num_pos.data.sum() > 0 else num + loss_l /= N + loss_c /= N + return loss_l, loss_c diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/modelzoo_level.txt b/PyTorch/contrib/cv/detection/Pyramidbox/modelzoo_level.txt index 7eeb8d729d..a3e2322b3a 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/modelzoo_level.txt +++ b/PyTorch/contrib/cv/detection/Pyramidbox/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PerfStatus:OK +PrecisionStatus:OK diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/prepare_wider_data.py b/PyTorch/contrib/cv/detection/Pyramidbox/prepare_wider_data.py index 59b5d3872b..03b9eec1eb 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/prepare_wider_data.py +++ b/PyTorch/contrib/cv/detection/Pyramidbox/prepare_wider_data.py @@ -1,121 +1,121 @@ -#-*- coding:utf-8 -*- -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -from __future__ import division -from __future__ import absolute_import -from __future__ import print_function - -import argparse -import os -from data.config import cfg -#import cv2 - -parser = argparse.ArgumentParser( - description='Pyramidbox face Detector Training With Pytorch') -parser.add_argument('--data_path', - default=None, type=str, - help='data_path') -args = parser.parse_args() - -train_list_file = os.path.join(args.data_path, 'wider_face_split', - 'wider_face_train_bbx_gt.txt') -val_list_file = os.path.join(args.data_path, 'wider_face_split', - 'wider_face_val_bbx_gt.txt') - -WIDER_TRAIN = os.path.join(args.data_path, 'WIDER_train', 'images') -WIDER_VAL = os.path.join(args.data_path, 'WIDER_val', 'images') - - -def parse_wider_file(root, file): - with open(file, 'r') as fr: - lines = fr.readlines() - face_count = [] - img_paths = [] - face_loc = [] - img_faces = [] - count = 0 - flag = False - for k, line in enumerate(lines): - line = line.strip().strip('\n') - if count > 0: - line = line.split(' ') - count -= 1 - loc = [int(line[0]), int(line[1]), int(line[2]), int(line[3])] - face_loc += [loc] - if flag: - face_count += [int(line)] - flag = False - count = int(line) - if 'jpg' in line: - img_paths += [os.path.join(root, line)] - flag = True - - total_face = 0 - for k in face_count: - face_ = [] - for x in range(total_face, total_face + k): - face_.append(face_loc[x]) - img_faces += [face_] - total_face += k - return img_paths, img_faces - - -def wider_data_file(): - img_paths, bbox = parse_wider_file(WIDER_TRAIN, train_list_file) - fw = open(cfg.FACE.TRAIN_FILE, 'w') - for index in range(len(img_paths)): - path = img_paths[index] - boxes = bbox[index] - fw.write(path) - fw.write(' {}'.format(len(boxes))) - for box in boxes: - data = ' {} {} {} {} {}'.format(box[0], box[1], box[2], box[3], 1) - fw.write(data) - fw.write('\n') - fw.close() - - img_paths, bbox = parse_wider_file(WIDER_VAL, val_list_file) - fw = open(cfg.FACE.VAL_FILE, 'w') - for index in range(len(img_paths)): - path = img_paths[index] - boxes = bbox[index] - fw.write(path) - fw.write(' {}'.format(len(boxes))) - for box in boxes: - data = ' {} {} {} {} {}'.format(box[0], box[1], box[2], box[3], 1) - fw.write(data) - fw.write('\n') - fw.close() - - -if __name__ == '__main__': - wider_data_file() +#-*- coding:utf-8 -*- +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +from __future__ import division +from __future__ import absolute_import +from __future__ import print_function + +import argparse +import os +from data.config import cfg +#import cv2 + +parser = argparse.ArgumentParser( + description='Pyramidbox face Detector Training With Pytorch') +parser.add_argument('--data_path', + default=None, type=str, + help='data_path') +args = parser.parse_args() + +train_list_file = os.path.join(args.data_path, 'wider_face_split', + 'wider_face_train_bbx_gt.txt') +val_list_file = os.path.join(args.data_path, 'wider_face_split', + 'wider_face_val_bbx_gt.txt') + +WIDER_TRAIN = os.path.join(args.data_path, 'WIDER_train', 'images') +WIDER_VAL = os.path.join(args.data_path, 'WIDER_val', 'images') + + +def parse_wider_file(root, file): + with open(file, 'r') as fr: + lines = fr.readlines() + face_count = [] + img_paths = [] + face_loc = [] + img_faces = [] + count = 0 + flag = False + for k, line in enumerate(lines): + line = line.strip().strip('\n') + if count > 0: + line = line.split(' ') + count -= 1 + loc = [int(line[0]), int(line[1]), int(line[2]), int(line[3])] + face_loc += [loc] + if flag: + face_count += [int(line)] + flag = False + count = int(line) + if 'jpg' in line: + img_paths += [os.path.join(root, line)] + flag = True + + total_face = 0 + for k in face_count: + face_ = [] + for x in range(total_face, total_face + k): + face_.append(face_loc[x]) + img_faces += [face_] + total_face += k + return img_paths, img_faces + + +def wider_data_file(): + img_paths, bbox = parse_wider_file(WIDER_TRAIN, train_list_file) + fw = open(cfg.FACE.TRAIN_FILE, 'w') + for index in range(len(img_paths)): + path = img_paths[index] + boxes = bbox[index] + fw.write(path) + fw.write(' {}'.format(len(boxes))) + for box in boxes: + data = ' {} {} {} {} {}'.format(box[0], box[1], box[2], box[3], 1) + fw.write(data) + fw.write('\n') + fw.close() + + img_paths, bbox = parse_wider_file(WIDER_VAL, val_list_file) + fw = open(cfg.FACE.VAL_FILE, 'w') + for index in range(len(img_paths)): + path = img_paths[index] + boxes = bbox[index] + fw.write(path) + fw.write(' {}'.format(len(boxes))) + for box in boxes: + data = ' {} {} {} {} {}'.format(box[0], box[1], box[2], box[3], 1) + fw.write(data) + fw.write('\n') + fw.close() + + +if __name__ == '__main__': + wider_data_file() diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/pyramidbox.py b/PyTorch/contrib/cv/detection/Pyramidbox/pyramidbox.py index 048fabf220..f8ebd2e0fd 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/pyramidbox.py +++ b/PyTorch/contrib/cv/detection/Pyramidbox/pyramidbox.py @@ -1,434 +1,434 @@ -#-*- coding:utf-8 -*- -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import time -import torch -import torch.nn as nn -import torch.nn.init as init -from torch.autograd import Function -import torch.nn.functional as F -from torch.autograd import Variable -import os -from layers import * -from data.config import cfg -import numpy as np -import torch.npu -class conv_bn(nn.Module): - """docstring for conv""" - - def __init__(self, - in_plane, - out_plane, - kernel_size, - stride, - padding): - super(conv_bn, self).__init__() - self.conv1 = nn.Conv2d(in_plane, out_plane, - kernel_size=kernel_size, stride=stride, padding=padding) - self.bn1 = nn.BatchNorm2d(out_plane) - - def forward(self, x): - x = self.conv1(x) - return self.bn1(x) - - - -class CPM(nn.Module): - """docstring for CPM""" - - def __init__(self, in_plane): - super(CPM, self).__init__() - self.branch1 = conv_bn(in_plane, 1024, 1, 1, 0) - self.branch2a = conv_bn(in_plane, 256, 1, 1, 0) - self.branch2b = conv_bn(256, 256, 3, 1, 1) - self.branch2c = conv_bn(256, 1024, 1, 1, 0) - - self.ssh_1 = nn.Conv2d(1024, 256, kernel_size=3, stride=1, padding=1) - self.ssh_dimred = nn.Conv2d( - 1024, 128, kernel_size=3, stride=1, padding=1) - self.ssh_2 = nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1) - self.ssh_3a = nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1) - self.ssh_3b = nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1) - - def forward(self, x): - out_residual = self.branch1(x) - x = F.relu(self.branch2a(x), inplace=True) - x = F.relu(self.branch2b(x), inplace=True) - x = self.branch2c(x) - rescomb = F.relu(x + out_residual, inplace=True) - ssh1 = self.ssh_1(rescomb) - ssh_dimred = F.relu(self.ssh_dimred(rescomb), inplace=True) - ssh_2 = self.ssh_2(ssh_dimred) - ssh_3a = F.relu(self.ssh_3a(ssh_dimred), inplace=True) - ssh_3b = self.ssh_3b(ssh_3a) - - ssh_out = torch.cat([ssh1, ssh_2, ssh_3b], dim=1) - ssh_out = F.relu(ssh_out, inplace=True) - return ssh_out - - -class PyramidBox(nn.Module): - """docstring for PyramidBox""" - - def __init__(self, - phase, - base, - extras, - lfpn_cpm, - head, - num_classes): - super(PyramidBox, self).__init__() - - self.vgg = nn.ModuleList(base) - self.extras = nn.ModuleList(extras) - self.bn64 = nn.BatchNorm2d(64) - self.L2Norm3_3 = L2Norm(256, 10) - self.L2Norm4_3 = L2Norm(512, 8) - self.L2Norm5_3 = L2Norm(512, 5) - - self.lfpn_topdown = nn.ModuleList(lfpn_cpm[0]) - self.lfpn_later = nn.ModuleList(lfpn_cpm[1]) - self.cpm = nn.ModuleList(lfpn_cpm[2]) - - self.loc_layers = nn.ModuleList(head[0]) - self.conf_layers = nn.ModuleList(head[1]) - - - - self.is_infer = False - if phase == 'test': - self.softmax = nn.Softmax(dim=-1) - self.detect = Detect(cfg) - self.is_infer = True - - def _upsample_prod(self, x, y): - _, _, H, W = y.size() - return F.interpolate(x, size=(H, W), mode='bilinear') * y - - def forward(self, x): - - use_npu = False - size = x.size()[2:] - bn_index = 0 - for k in range(16): - x = self.vgg[k](x) - if isinstance(self.vgg[k], nn.Conv2d): - if k == 2: - x = self.bn64(x) - conv3_3 = x - for k in range(16, 23): - x = self.vgg[k](x) - conv4_3 = x - for k in range(23, 30): - x = self.vgg[k](x) - - conv5_3 = x - - for k in range(30, len(self.vgg)): - x = self.vgg[k](x) - - convfc_7 = x - - for k in range(2): - x = F.relu(self.extras[k](x), inplace=True)#.npu() - conv6_2 = x - - for k in range(2, 4): - x = F.relu(self.extras[k](x), inplace=True)#.npu() - - conv7_2 = x - - x = F.relu(self.lfpn_topdown[0](convfc_7), inplace=True) - lfpn2_on_conv5 = F.relu(self._upsample_prod( - x, self.lfpn_later[0](conv5_3)), inplace=True) - - x = F.relu(self.lfpn_topdown[1](lfpn2_on_conv5), inplace=True) - lfpn1_on_conv4 = F.relu(self._upsample_prod( - x, self.lfpn_later[1](conv4_3)), inplace=True) - - - x = F.relu(self.lfpn_topdown[2](lfpn1_on_conv4), inplace=True) - lfpn0_on_conv3 = F.relu(self._upsample_prod( - x, self.lfpn_later[2](conv3_3)), inplace=True) - l2norm3 = self.L2Norm3_3(lfpn0_on_conv3) - l2norm4 = self.L2Norm4_3(lfpn1_on_conv4) - l2norm5 = self.L2Norm5_3(lfpn2_on_conv5) - - ssh_conv3_norm = self.cpm[0](l2norm3) - ssh_conv4_norm = self.cpm[1](l2norm4) - ssh_conv5_norm = self.cpm[2](l2norm5) - - ssh_convfc7 = self.cpm[3](convfc_7) - ssh_conv6 = self.cpm[4](conv6_2) - ssh_conv7 = self.cpm[5](conv7_2) - face_locs, face_confs = [], [] - head_locs, head_confs = [], [] - - N = ssh_conv3_norm.size(0) - - - mbox_loc = self.loc_layers[0](ssh_conv3_norm) - - face_loc, head_loc = torch.chunk(mbox_loc, 2, dim=1) - - face_loc = face_loc.permute(0, 2, 3, 1).contiguous().view(N, -1, 4) - if not self.is_infer: - head_loc = head_loc.permute(0, 2, 3, 1).contiguous().view(N, -1, 4) - - mbox_conf = self.conf_layers[0](ssh_conv3_norm) - - face_conf1 = mbox_conf[:, 3:4, :, :] - face_conf3_maxin, _ = torch.max(mbox_conf[:, 0:3, :, :], dim=1, keepdim=True) - - face_conf = torch.cat((face_conf3_maxin, face_conf1), dim=1) - face_conf = face_conf.permute(0, 2, 3, 1).contiguous().view(N, -1, 2) - if not self.is_infer: - head_conf3_maxin, _ = torch.max(mbox_conf[:, 4:7, :, :], dim=1, keepdim=True) - head_conf1 = mbox_conf[:, 7:, :, :] - - head_conf = torch.cat((head_conf3_maxin, head_conf1), dim=1) - head_conf = head_conf.permute(0, 2, 3, 1).contiguous().view(N, -1, 2) - - face_locs.append(face_loc) - face_confs.append(face_conf) - if not self.is_infer: - head_locs.append(head_loc) - head_confs.append(head_conf) - - - inputs = [ssh_conv4_norm, ssh_conv5_norm, - ssh_convfc7, ssh_conv6, ssh_conv7] - - feature_maps = [] - feat_size = ssh_conv3_norm.size()[2:] - feature_maps.append([feat_size[0], feat_size[1]]) - - for i, feat in enumerate(inputs): - - feat_size = feat.size()[2:] - feature_maps.append([feat_size[0], feat_size[1]]) - mbox_loc = self.loc_layers[i + 1](feat) - - face_loc, head_loc = torch.chunk(mbox_loc, 2, dim=1) - - face_loc = face_loc.permute(0, 2, 3, 1).contiguous().view(N, -1, 4) - if not self.is_infer: - head_loc = head_loc.permute(0, 2, 3, 1).contiguous().view(N, -1, 4) - - mbox_conf = self.conf_layers[i + 1](feat) - - face_conf1 = mbox_conf[:, 0:1, :, :] - face_conf3_maxin, _ = torch.max( - mbox_conf[:, 1:4, :, :], dim=1, keepdim=True) - - face_conf = torch.cat((face_conf1, face_conf3_maxin), dim=1) - - face_conf = face_conf.permute( - 0, 2, 3, 1).contiguous().view(N, -1, 2) - - if not self.is_infer: - head_conf = mbox_conf[:, 4:, :, :].permute( - 0, 2, 3, 1).contiguous().view(N, -1, 2) - - face_locs.append(face_loc) - face_confs.append(face_conf) - - if not self.is_infer: - head_locs.append(head_loc) - head_confs.append(head_conf) - - face_mbox_loc = torch.cat(face_locs, dim=1) - face_mbox_conf = torch.cat(face_confs, dim=1) - - if not self.is_infer: - head_mbox_loc = torch.cat(head_locs, dim=1) - head_mbox_conf = torch.cat(head_confs, dim=1) - - - priors_boxes = PriorBox(size, feature_maps, cfg) - with torch.no_grad(): - priors = Variable(priors_boxes.forward()) - - if not self.is_infer: - output = (face_mbox_loc, face_mbox_conf, - head_mbox_loc, head_mbox_conf, priors) - else: - face_mbox_loc = face_mbox_loc.cpu() - face_mbox_conf = face_mbox_conf.cpu() - output = self.detect.forward(face_mbox_loc, - self.softmax(face_mbox_conf), - priors).cpu() - return output - - def load_weights(self, base_file): - other, ext = os.path.splitext(base_file) - if ext == '.pkl' or '.pth': - print('Loading weights into state dict...') - mdata = torch.load(base_file, - map_location=lambda storage, loc: storage) - weights = mdata['weight'] - epoch = mdata['epoch'] - self.load_state_dict(weights) - print('Finished!') - else: - print('Sorry only .pth and .pkl files supported.') - return epoch - - def xavier(self, param): - with torch.no_grad(): - init.xavier_uniform(param) - - def weights_init(self, m): - if isinstance(m, nn.Conv2d): - - self.xavier(m.weight) - if 'bias' in m.state_dict().keys(): - m.bias.data.zero_() - - if isinstance(m, nn.ConvTranspose2d): - self.xavier(m.weight.data) - if 'bias' in m.state_dict().keys(): - m.bias.data.zero_() - - if isinstance(m, nn.BatchNorm2d): - m.weight.data[...] = 1 - m.bias.data.zero_() - - -vgg_cfg = [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', - 512, 512, 512, 'M'] - -extras_cfg = [256, 'S', 512, 128, 'S', 256] - -lfpn_cpm_cfg = [256, 512, 512, 1024, 512, 256] - -multibox_cfg = [512, 512, 512, 512, 512, 512] - - -def vgg(cfg, i, batch_norm=False): - layers = [] - in_channels = i - for v in cfg: - if v == 'M': - layers += [nn.MaxPool2d(kernel_size=2, stride=2)] - elif v == 'C': - layers += [nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)] - else: - conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1) - if batch_norm: - layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)] - else: - layers += [conv2d, nn.ReLU(inplace=True)] - in_channels = v - conv6 = nn.Conv2d(512, 1024, kernel_size=3, padding=6, dilation=6) - conv7 = nn.Conv2d(1024, 1024, kernel_size=1) - layers += [conv6, - nn.ReLU(inplace=True), conv7, nn.ReLU(inplace=True)] - return layers - - -def add_extras(cfg, i, batch_norm=False): - # Extra layers added to VGG for feature scaling - layers = [] - in_channels = i - flag = False - for k, v in enumerate(cfg): - if in_channels != 'S': - if v == 'S': - layers += [nn.Conv2d(in_channels, cfg[k + 1], - kernel_size=(1, 3)[flag], stride=2, padding=1)] - else: - layers += [nn.Conv2d(in_channels, v, kernel_size=(1, 3)[flag])] - flag = not flag - in_channels = v - return layers - - -def add_lfpn_cpm(cfg): - lfpn_topdown_layers = [] - lfpn_latlayer = [] - cpm_layers = [] - - for k, v in enumerate(cfg): - cpm_layers.append(CPM(v)) - - fpn_list = cfg[::-1][2:] - for k, v in enumerate(fpn_list[:-1]): - lfpn_latlayer.append(nn.Conv2d( - fpn_list[k + 1], fpn_list[k + 1], kernel_size=1, stride=1, padding=0)) - lfpn_topdown_layers.append(nn.Conv2d( - v, fpn_list[k + 1], kernel_size=1, stride=1, padding=0)) - - return (lfpn_topdown_layers, lfpn_latlayer, cpm_layers) - - -def multibox(vgg, extra_layers): - loc_layers = [] - conf_layers = [] - vgg_source = [21, 28, -2] - i = 0 - loc_layers += [nn.Conv2d(multibox_cfg[i], - 8, kernel_size=3, padding=1)] - conf_layers += [nn.Conv2d(multibox_cfg[i], - 8, kernel_size=3, padding=1)] - i += 1 - for k, v in enumerate(vgg_source): - loc_layers += [nn.Conv2d(multibox_cfg[i], - 8, kernel_size=3, padding=1)] - conf_layers += [nn.Conv2d(multibox_cfg[i], - 6, kernel_size=3, padding=1)] - i += 1 - for k, v in enumerate(extra_layers[1::2], 2): - loc_layers += [nn.Conv2d(multibox_cfg[i], - 8, kernel_size=3, padding=1)] - conf_layers += [nn.Conv2d(multibox_cfg[i], - 6, kernel_size=3, padding=1)] - i += 1 - return vgg, extra_layers, (loc_layers, conf_layers) - - -def build_net(phase, num_classes=2): - base_, extras_, head_ = multibox( - vgg(vgg_cfg, 3), add_extras((extras_cfg), 1024)) - lfpn_cpm = add_lfpn_cpm(lfpn_cpm_cfg) - return PyramidBox(phase, base_, extras_, lfpn_cpm, head_, num_classes) - - -if __name__ == '__main__': - inputs = Variable(torch.randn(1, 3, 640, 640)) - net = build_net('train', num_classes=2) - print(net) - out = net(inputs) +#-*- coding:utf-8 -*- +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import time +import torch +import torch.nn as nn +import torch.nn.init as init +from torch.autograd import Function +import torch.nn.functional as F +from torch.autograd import Variable +import os +from layers import * +from data.config import cfg +import numpy as np +import torch.npu +class conv_bn(nn.Module): + """docstring for conv""" + + def __init__(self, + in_plane, + out_plane, + kernel_size, + stride, + padding): + super(conv_bn, self).__init__() + self.conv1 = nn.Conv2d(in_plane, out_plane, + kernel_size=kernel_size, stride=stride, padding=padding) + self.bn1 = nn.BatchNorm2d(out_plane) + + def forward(self, x): + x = self.conv1(x) + return self.bn1(x) + + + +class CPM(nn.Module): + """docstring for CPM""" + + def __init__(self, in_plane): + super(CPM, self).__init__() + self.branch1 = conv_bn(in_plane, 1024, 1, 1, 0) + self.branch2a = conv_bn(in_plane, 256, 1, 1, 0) + self.branch2b = conv_bn(256, 256, 3, 1, 1) + self.branch2c = conv_bn(256, 1024, 1, 1, 0) + + self.ssh_1 = nn.Conv2d(1024, 256, kernel_size=3, stride=1, padding=1) + self.ssh_dimred = nn.Conv2d( + 1024, 128, kernel_size=3, stride=1, padding=1) + self.ssh_2 = nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1) + self.ssh_3a = nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1) + self.ssh_3b = nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1) + + def forward(self, x): + out_residual = self.branch1(x) + x = F.relu(self.branch2a(x), inplace=True) + x = F.relu(self.branch2b(x), inplace=True) + x = self.branch2c(x) + rescomb = F.relu(x + out_residual, inplace=True) + ssh1 = self.ssh_1(rescomb) + ssh_dimred = F.relu(self.ssh_dimred(rescomb), inplace=True) + ssh_2 = self.ssh_2(ssh_dimred) + ssh_3a = F.relu(self.ssh_3a(ssh_dimred), inplace=True) + ssh_3b = self.ssh_3b(ssh_3a) + + ssh_out = torch.cat([ssh1, ssh_2, ssh_3b], dim=1) + ssh_out = F.relu(ssh_out, inplace=True) + return ssh_out + + +class PyramidBox(nn.Module): + """docstring for PyramidBox""" + + def __init__(self, + phase, + base, + extras, + lfpn_cpm, + head, + num_classes): + super(PyramidBox, self).__init__() + + self.vgg = nn.ModuleList(base) + self.extras = nn.ModuleList(extras) + self.bn64 = nn.BatchNorm2d(64) + self.L2Norm3_3 = L2Norm(256, 10) + self.L2Norm4_3 = L2Norm(512, 8) + self.L2Norm5_3 = L2Norm(512, 5) + + self.lfpn_topdown = nn.ModuleList(lfpn_cpm[0]) + self.lfpn_later = nn.ModuleList(lfpn_cpm[1]) + self.cpm = nn.ModuleList(lfpn_cpm[2]) + + self.loc_layers = nn.ModuleList(head[0]) + self.conf_layers = nn.ModuleList(head[1]) + + + + self.is_infer = False + if phase == 'test': + self.softmax = nn.Softmax(dim=-1) + self.detect = Detect(cfg) + self.is_infer = True + + def _upsample_prod(self, x, y): + _, _, H, W = y.size() + return F.interpolate(x, size=(H, W), mode='bilinear') * y + + def forward(self, x): + + use_npu = False + size = x.size()[2:] + bn_index = 0 + for k in range(16): + x = self.vgg[k](x) + if isinstance(self.vgg[k], nn.Conv2d): + if k == 2: + x = self.bn64(x) + conv3_3 = x + for k in range(16, 23): + x = self.vgg[k](x) + conv4_3 = x + for k in range(23, 30): + x = self.vgg[k](x) + + conv5_3 = x + + for k in range(30, len(self.vgg)): + x = self.vgg[k](x) + + convfc_7 = x + + for k in range(2): + x = F.relu(self.extras[k](x), inplace=True)#.npu() + conv6_2 = x + + for k in range(2, 4): + x = F.relu(self.extras[k](x), inplace=True)#.npu() + + conv7_2 = x + + x = F.relu(self.lfpn_topdown[0](convfc_7), inplace=True) + lfpn2_on_conv5 = F.relu(self._upsample_prod( + x, self.lfpn_later[0](conv5_3)), inplace=True) + + x = F.relu(self.lfpn_topdown[1](lfpn2_on_conv5), inplace=True) + lfpn1_on_conv4 = F.relu(self._upsample_prod( + x, self.lfpn_later[1](conv4_3)), inplace=True) + + + x = F.relu(self.lfpn_topdown[2](lfpn1_on_conv4), inplace=True) + lfpn0_on_conv3 = F.relu(self._upsample_prod( + x, self.lfpn_later[2](conv3_3)), inplace=True) + l2norm3 = self.L2Norm3_3(lfpn0_on_conv3) + l2norm4 = self.L2Norm4_3(lfpn1_on_conv4) + l2norm5 = self.L2Norm5_3(lfpn2_on_conv5) + + ssh_conv3_norm = self.cpm[0](l2norm3) + ssh_conv4_norm = self.cpm[1](l2norm4) + ssh_conv5_norm = self.cpm[2](l2norm5) + + ssh_convfc7 = self.cpm[3](convfc_7) + ssh_conv6 = self.cpm[4](conv6_2) + ssh_conv7 = self.cpm[5](conv7_2) + face_locs, face_confs = [], [] + head_locs, head_confs = [], [] + + N = ssh_conv3_norm.size(0) + + + mbox_loc = self.loc_layers[0](ssh_conv3_norm) + + face_loc, head_loc = torch.chunk(mbox_loc, 2, dim=1) + + face_loc = face_loc.permute(0, 2, 3, 1).contiguous().view(N, -1, 4) + if not self.is_infer: + head_loc = head_loc.permute(0, 2, 3, 1).contiguous().view(N, -1, 4) + + mbox_conf = self.conf_layers[0](ssh_conv3_norm) + + face_conf1 = mbox_conf[:, 3:4, :, :] + face_conf3_maxin, _ = torch.max(mbox_conf[:, 0:3, :, :], dim=1, keepdim=True) + + face_conf = torch.cat((face_conf3_maxin, face_conf1), dim=1) + face_conf = face_conf.permute(0, 2, 3, 1).contiguous().view(N, -1, 2) + if not self.is_infer: + head_conf3_maxin, _ = torch.max(mbox_conf[:, 4:7, :, :], dim=1, keepdim=True) + head_conf1 = mbox_conf[:, 7:, :, :] + + head_conf = torch.cat((head_conf3_maxin, head_conf1), dim=1) + head_conf = head_conf.permute(0, 2, 3, 1).contiguous().view(N, -1, 2) + + face_locs.append(face_loc) + face_confs.append(face_conf) + if not self.is_infer: + head_locs.append(head_loc) + head_confs.append(head_conf) + + + inputs = [ssh_conv4_norm, ssh_conv5_norm, + ssh_convfc7, ssh_conv6, ssh_conv7] + + feature_maps = [] + feat_size = ssh_conv3_norm.size()[2:] + feature_maps.append([feat_size[0], feat_size[1]]) + + for i, feat in enumerate(inputs): + + feat_size = feat.size()[2:] + feature_maps.append([feat_size[0], feat_size[1]]) + mbox_loc = self.loc_layers[i + 1](feat) + + face_loc, head_loc = torch.chunk(mbox_loc, 2, dim=1) + + face_loc = face_loc.permute(0, 2, 3, 1).contiguous().view(N, -1, 4) + if not self.is_infer: + head_loc = head_loc.permute(0, 2, 3, 1).contiguous().view(N, -1, 4) + + mbox_conf = self.conf_layers[i + 1](feat) + + face_conf1 = mbox_conf[:, 0:1, :, :] + face_conf3_maxin, _ = torch.max( + mbox_conf[:, 1:4, :, :], dim=1, keepdim=True) + + face_conf = torch.cat((face_conf1, face_conf3_maxin), dim=1) + + face_conf = face_conf.permute( + 0, 2, 3, 1).contiguous().view(N, -1, 2) + + if not self.is_infer: + head_conf = mbox_conf[:, 4:, :, :].permute( + 0, 2, 3, 1).contiguous().view(N, -1, 2) + + face_locs.append(face_loc) + face_confs.append(face_conf) + + if not self.is_infer: + head_locs.append(head_loc) + head_confs.append(head_conf) + + face_mbox_loc = torch.cat(face_locs, dim=1) + face_mbox_conf = torch.cat(face_confs, dim=1) + + if not self.is_infer: + head_mbox_loc = torch.cat(head_locs, dim=1) + head_mbox_conf = torch.cat(head_confs, dim=1) + + + priors_boxes = PriorBox(size, feature_maps, cfg) + with torch.no_grad(): + priors = Variable(priors_boxes.forward()) + + if not self.is_infer: + output = (face_mbox_loc, face_mbox_conf, + head_mbox_loc, head_mbox_conf, priors) + else: + face_mbox_loc = face_mbox_loc.cpu() + face_mbox_conf = face_mbox_conf.cpu() + output = self.detect.forward(face_mbox_loc, + self.softmax(face_mbox_conf), + priors).cpu() + return output + + def load_weights(self, base_file): + other, ext = os.path.splitext(base_file) + if ext == '.pkl' or '.pth': + print('Loading weights into state dict...') + mdata = torch.load(base_file, + map_location=lambda storage, loc: storage) + weights = mdata['weight'] + epoch = mdata['epoch'] + self.load_state_dict(weights) + print('Finished!') + else: + print('Sorry only .pth and .pkl files supported.') + return epoch + + def xavier(self, param): + with torch.no_grad(): + init.xavier_uniform(param) + + def weights_init(self, m): + if isinstance(m, nn.Conv2d): + + self.xavier(m.weight) + if 'bias' in m.state_dict().keys(): + m.bias.data.zero_() + + if isinstance(m, nn.ConvTranspose2d): + self.xavier(m.weight.data) + if 'bias' in m.state_dict().keys(): + m.bias.data.zero_() + + if isinstance(m, nn.BatchNorm2d): + m.weight.data[...] = 1 + m.bias.data.zero_() + + +vgg_cfg = [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', + 512, 512, 512, 'M'] + +extras_cfg = [256, 'S', 512, 128, 'S', 256] + +lfpn_cpm_cfg = [256, 512, 512, 1024, 512, 256] + +multibox_cfg = [512, 512, 512, 512, 512, 512] + + +def vgg(cfg, i, batch_norm=False): + layers = [] + in_channels = i + for v in cfg: + if v == 'M': + layers += [nn.MaxPool2d(kernel_size=2, stride=2)] + elif v == 'C': + layers += [nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)] + else: + conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1) + if batch_norm: + layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)] + else: + layers += [conv2d, nn.ReLU(inplace=True)] + in_channels = v + conv6 = nn.Conv2d(512, 1024, kernel_size=3, padding=6, dilation=6) + conv7 = nn.Conv2d(1024, 1024, kernel_size=1) + layers += [conv6, + nn.ReLU(inplace=True), conv7, nn.ReLU(inplace=True)] + return layers + + +def add_extras(cfg, i, batch_norm=False): + # Extra layers added to VGG for feature scaling + layers = [] + in_channels = i + flag = False + for k, v in enumerate(cfg): + if in_channels != 'S': + if v == 'S': + layers += [nn.Conv2d(in_channels, cfg[k + 1], + kernel_size=(1, 3)[flag], stride=2, padding=1)] + else: + layers += [nn.Conv2d(in_channels, v, kernel_size=(1, 3)[flag])] + flag = not flag + in_channels = v + return layers + + +def add_lfpn_cpm(cfg): + lfpn_topdown_layers = [] + lfpn_latlayer = [] + cpm_layers = [] + + for k, v in enumerate(cfg): + cpm_layers.append(CPM(v)) + + fpn_list = cfg[::-1][2:] + for k, v in enumerate(fpn_list[:-1]): + lfpn_latlayer.append(nn.Conv2d( + fpn_list[k + 1], fpn_list[k + 1], kernel_size=1, stride=1, padding=0)) + lfpn_topdown_layers.append(nn.Conv2d( + v, fpn_list[k + 1], kernel_size=1, stride=1, padding=0)) + + return (lfpn_topdown_layers, lfpn_latlayer, cpm_layers) + + +def multibox(vgg, extra_layers): + loc_layers = [] + conf_layers = [] + vgg_source = [21, 28, -2] + i = 0 + loc_layers += [nn.Conv2d(multibox_cfg[i], + 8, kernel_size=3, padding=1)] + conf_layers += [nn.Conv2d(multibox_cfg[i], + 8, kernel_size=3, padding=1)] + i += 1 + for k, v in enumerate(vgg_source): + loc_layers += [nn.Conv2d(multibox_cfg[i], + 8, kernel_size=3, padding=1)] + conf_layers += [nn.Conv2d(multibox_cfg[i], + 6, kernel_size=3, padding=1)] + i += 1 + for k, v in enumerate(extra_layers[1::2], 2): + loc_layers += [nn.Conv2d(multibox_cfg[i], + 8, kernel_size=3, padding=1)] + conf_layers += [nn.Conv2d(multibox_cfg[i], + 6, kernel_size=3, padding=1)] + i += 1 + return vgg, extra_layers, (loc_layers, conf_layers) + + +def build_net(phase, num_classes=2): + base_, extras_, head_ = multibox( + vgg(vgg_cfg, 3), add_extras((extras_cfg), 1024)) + lfpn_cpm = add_lfpn_cpm(lfpn_cpm_cfg) + return PyramidBox(phase, base_, extras_, lfpn_cpm, head_, num_classes) + + +if __name__ == '__main__': + inputs = Variable(torch.randn(1, 3, 640, 640)) + net = build_net('train', num_classes=2) + print(net) + out = net(inputs) diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/requirements.txt b/PyTorch/contrib/cv/detection/Pyramidbox/requirements.txt index 570522f1db..cc42ce9b3f 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/requirements.txt +++ b/PyTorch/contrib/cv/detection/Pyramidbox/requirements.txt @@ -1,26 +1,26 @@ -apex 0.1+ascend.20210825 -backcall -certifi -Cython -easydict -ipython -matplotlib-inline -mpmath -numpy -opencv-python -parso -pexpect -pickleshare -Pillow -scipy -six -sympy -te -tensor-fused-plugin 0.1+ascend -topi 0.4.0 -torch 1.5.0+ascend.post3.20210825 -torchvision 0.6.0a0+b68adcf -tqdm -traitlets -urllib3 +apex 0.1+ascend.20210825 +backcall +certifi +Cython +easydict +ipython +matplotlib-inline +mpmath +numpy +opencv-python +parso +pexpect +pickleshare +Pillow +scipy +six +sympy +te +tensor-fused-plugin 0.1+ascend +topi 0.4.0 +torch 1.5.0+ascend.post3.20210825 +torchvision 0.6.0a0+b68adcf +tqdm +traitlets +urllib3 wcwidth \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/tools/afw_test.py b/PyTorch/contrib/cv/detection/Pyramidbox/tools/afw_test.py index 0402237e25..291c9342b9 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/tools/afw_test.py +++ b/PyTorch/contrib/cv/detection/Pyramidbox/tools/afw_test.py @@ -1,140 +1,140 @@ -#-*- coding:utf-8 -*- -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 division -from __future__ import absolute_import -from __future__ import print_function - -import os -import torch -import argparse -import torch.nn as nn -import torch.utils.data as data -import torch.backends.cudnn as cudnn -import torchvision.transforms as transforms -import os.path as osp - -import cv2 -import time -import numpy as np -from PIL import Image - -from data.config import cfg -from pyramidbox import build_net -from torch.autograd import Variable -from utils.augmentations import to_chw_bgr - - -parser = argparse.ArgumentParser(description='pyramidbox evaluatuon afw') -parser.add_argument('--model', - type=str,default='weights/pyramidbox.pth', help='trained model') -parser.add_argument('--thresh', - default=0.1, type=float, - help='Final confidence threshold') -args = parser.parse_args() - -use_cuda = torch.cuda.is_available() - -if use_cuda: - torch.set_default_tensor_type('torch.cuda.FloatTensor') -else: - torch.set_default_tensor_type('torch.FloatTensor') - -AFW_IMG_DIR = os.path.join(cfg.FACE.AFW_DIR, 'images') -AFW_RESULT_DIR = os.path.join(cfg.FACE.AFW_DIR, 'pyramidbox') -AFW_RESULT_IMG_DIR = os.path.join(AFW_RESULT_DIR, 'images') - -if not os.path.exists(AFW_RESULT_IMG_DIR): - os.makedirs(AFW_RESULT_IMG_DIR) - - -def detect_face(net, img, thresh): - height, width, _ = img.shape - im_shrink = 640.0 / max(height, width) - image = cv2.resize(img, None, None, fx=im_shrink, - fy=im_shrink, interpolation=cv2.INTER_LINEAR).copy() - - x = to_chw_bgr(image) - x = x.astype('float32') - x -= cfg.img_mean - x = x[[2, 1, 0], :, :] - - x = Variable(torch.from_numpy(x).unsqueeze(0)) - if use_cuda: - x = x.cuda() - - y = net(x) - detections = y.data - scale = torch.Tensor([img.shape[1], img.shape[0], - img.shape[1], img.shape[0]]) - - bboxes = [] - for i in range(detections.size(1)): - j = 0 - while detections[0, i, j, 0] >= thresh: - box = [] - score = detections[0, i, j, 0] - pt = (detections[0, i, j, 1:] * scale).cpu().numpy().astype(np.int) - j += 1 - box += [pt[0], pt[1], pt[2], pt[3], score] - box[1] += 0.2 * (box[3] - box[1] + 1) - bboxes += [box] - - return bboxes - - -if __name__ == '__main__': - net = build_net('test', cfg.NUM_CLASSES) - net.load_state_dict(torch.load(args.model)) - net.eval() - - if use_cuda: - net.cuda() - cudnn.benckmark = True - - #transform = S3FDBasicTransform(cfg.INPUT_SIZE, cfg.MEANS) - - counter = 0 - txt_out = os.path.join(AFW_RESULT_DIR, 'pyramidbox_dets.txt') - txt_in = os.path.join('./tools/afw_img_list.txt') - - fout = open(txt_out, 'w') - fin = open(txt_in, 'r') - - for line in fin.readlines(): - line = line.strip() - img_file = os.path.join(AFW_IMG_DIR, line + '.jpg') - out_file = os.path.join(AFW_RESULT_IMG_DIR, line + '.jpg') - counter += 1 - t1 = time.time() - #img = cv2.imread(img_file, cv2.IMREAD_COLOR) - img = Image.open(img_file) - if img.mode == 'L': - img = img.convert('RGB') - img = np.array(img) - bboxes = detect_face(net, img, args.thresh) - t2 = time.time() - print('Detect %04d th image costs %.4f' % (counter, t2 - t1)) - for bbox in bboxes: - x1, y1, x2, y2, score = bbox - fout.write('{:s} {:.3f} {:.1f} {:.1f} {:.1f} {:.1f}\n'.format( - line, score, x1, y1, x2, y2)) - for bbox in bboxes: - x1, y1, x2, y2, score = bbox - x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2) - cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) - cv2.imwrite(out_file, img) - - fout.close() - fin.close() +#-*- coding:utf-8 -*- +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 division +from __future__ import absolute_import +from __future__ import print_function + +import os +import torch +import argparse +import torch.nn as nn +import torch.utils.data as data +import torch.backends.cudnn as cudnn +import torchvision.transforms as transforms +import os.path as osp + +import cv2 +import time +import numpy as np +from PIL import Image + +from data.config import cfg +from pyramidbox import build_net +from torch.autograd import Variable +from utils.augmentations import to_chw_bgr + + +parser = argparse.ArgumentParser(description='pyramidbox evaluatuon afw') +parser.add_argument('--model', + type=str,default='weights/pyramidbox.pth', help='trained model') +parser.add_argument('--thresh', + default=0.1, type=float, + help='Final confidence threshold') +args = parser.parse_args() + +use_cuda = torch.cuda.is_available() + +if use_cuda: + torch.set_default_tensor_type('torch.cuda.FloatTensor') +else: + torch.set_default_tensor_type('torch.FloatTensor') + +AFW_IMG_DIR = os.path.join(cfg.FACE.AFW_DIR, 'images') +AFW_RESULT_DIR = os.path.join(cfg.FACE.AFW_DIR, 'pyramidbox') +AFW_RESULT_IMG_DIR = os.path.join(AFW_RESULT_DIR, 'images') + +if not os.path.exists(AFW_RESULT_IMG_DIR): + os.makedirs(AFW_RESULT_IMG_DIR) + + +def detect_face(net, img, thresh): + height, width, _ = img.shape + im_shrink = 640.0 / max(height, width) + image = cv2.resize(img, None, None, fx=im_shrink, + fy=im_shrink, interpolation=cv2.INTER_LINEAR).copy() + + x = to_chw_bgr(image) + x = x.astype('float32') + x -= cfg.img_mean + x = x[[2, 1, 0], :, :] + + x = Variable(torch.from_numpy(x).unsqueeze(0)) + if use_cuda: + x = x.cuda() + + y = net(x) + detections = y.data + scale = torch.Tensor([img.shape[1], img.shape[0], + img.shape[1], img.shape[0]]) + + bboxes = [] + for i in range(detections.size(1)): + j = 0 + while detections[0, i, j, 0] >= thresh: + box = [] + score = detections[0, i, j, 0] + pt = (detections[0, i, j, 1:] * scale).cpu().numpy().astype(np.int) + j += 1 + box += [pt[0], pt[1], pt[2], pt[3], score] + box[1] += 0.2 * (box[3] - box[1] + 1) + bboxes += [box] + + return bboxes + + +if __name__ == '__main__': + net = build_net('test', cfg.NUM_CLASSES) + net.load_state_dict(torch.load(args.model)) + net.eval() + + if use_cuda: + net.cuda() + cudnn.benckmark = True + + #transform = S3FDBasicTransform(cfg.INPUT_SIZE, cfg.MEANS) + + counter = 0 + txt_out = os.path.join(AFW_RESULT_DIR, 'pyramidbox_dets.txt') + txt_in = os.path.join('./tools/afw_img_list.txt') + + fout = open(txt_out, 'w') + fin = open(txt_in, 'r') + + for line in fin.readlines(): + line = line.strip() + img_file = os.path.join(AFW_IMG_DIR, line + '.jpg') + out_file = os.path.join(AFW_RESULT_IMG_DIR, line + '.jpg') + counter += 1 + t1 = time.time() + #img = cv2.imread(img_file, cv2.IMREAD_COLOR) + img = Image.open(img_file) + if img.mode == 'L': + img = img.convert('RGB') + img = np.array(img) + bboxes = detect_face(net, img, args.thresh) + t2 = time.time() + print('Detect %04d th image costs %.4f' % (counter, t2 - t1)) + for bbox in bboxes: + x1, y1, x2, y2, score = bbox + fout.write('{:s} {:.3f} {:.1f} {:.1f} {:.1f} {:.1f}\n'.format( + line, score, x1, y1, x2, y2)) + for bbox in bboxes: + x1, y1, x2, y2, score = bbox + x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2) + cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) + cv2.imwrite(out_file, img) + + fout.close() + fin.close() diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/tools/fddb_test.py b/PyTorch/contrib/cv/detection/Pyramidbox/tools/fddb_test.py index 4958a67eff..1fede8bd71 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/tools/fddb_test.py +++ b/PyTorch/contrib/cv/detection/Pyramidbox/tools/fddb_test.py @@ -1,156 +1,156 @@ -#-*- coding:utf-8 -*- -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 division -from __future__ import absolute_import -from __future__ import print_function - -import os -import sys -import torch -import argparse -import torch.nn as nn -import torch.utils.data as data -import torch.backends.cudnn as cudnn -import torchvision.transforms as transforms - -import cv2 -import time -import numpy as np -from PIL import Image - -from data.config import cfg -from pyramidbox import build_net -from torch.autograd import Variable -from utils.augmentations import to_chw_bgr - -parser = argparse.ArgumentParser(description='pyramidbox evaluatuon fddb') -parser.add_argument('--model', - type=str, - default='weights/pyramidbox.pth', help='trained model') -parser.add_argument('--thresh', - default=0.1, type=float, - help='Final confidence threshold') -args = parser.parse_args() - - -use_cuda = torch.cuda.is_available() - -if use_cuda: - torch.set_default_tensor_type('torch.cuda.FloatTensor') -else: - torch.set_default_tensor_type('torch.FloatTensor') - - -FDDB_IMG_DIR = os.path.join(cfg.FACE.FDDB_DIR, 'images') -FDDB_FOLD_DIR = os.path.join(cfg.FACE.FDDB_DIR, 'FDDB-folds') -FDDB_RESULT_DIR = os.path.join(cfg.FACE.FDDB_DIR, 'pyramidbox') -FDDB_RESULT_IMG_DIR = os.path.join(FDDB_RESULT_DIR, 'images') - -if not os.path.exists(FDDB_RESULT_IMG_DIR): - os.makedirs(FDDB_RESULT_IMG_DIR) - - -def detect_face(net, img, thresh): - height, width, _ = img.shape - x = to_chw_bgr(img) - x = x.astype('float32') - x -= cfg.img_mean - x = x[[2, 1, 0], :, :] - - x = Variable(torch.from_numpy(x).unsqueeze(0)) - if use_cuda: - x = x.cuda() - - y = net(x) - detections = y.data - scale = torch.Tensor([img.shape[1], img.shape[0], - img.shape[1], img.shape[0]]) - - bboxes = [] - for i in range(detections.size(1)): - j = 0 - while detections[0, i, j, 0] >= thresh: - box = [] - score = detections[0, i, j, 0] - pt = (detections[0, i, j, 1:] * scale).cpu().numpy().astype(np.int) - j += 1 - box += [pt[0], pt[1], pt[2] - pt[0], pt[3] - pt[1], score] - bboxes += [box] - - return bboxes - - -if __name__ == '__main__': - net = build_net('test', cfg.NUM_CLASSES) - net.load_state_dict(torch.load(args.model)) - net.eval() - - if use_cuda: - net.cuda() - cudnn.benckmark = True - - #transform = S3FDBasicTransform(cfg.INPUT_SIZE, cfg.MEANS) - - counter = 0 - - for i in range(10): - txt_in = os.path.join(FDDB_FOLD_DIR, 'FDDB-fold-%02d.txt' % (i + 1)) - txt_out = os.path.join(FDDB_RESULT_DIR, 'fold-%02d-out.txt' % (i + 1)) - answer_in = os.path.join( - FDDB_FOLD_DIR, 'FDDB-fold-%02d-ellipseList.txt' % (i + 1)) - with open(txt_in, 'r') as fr: - lines = fr.readlines() - fout = open(txt_out, 'w') - ain = open(answer_in, 'r') - for line in lines: - line = line.strip() - img_file = os.path.join(FDDB_IMG_DIR, line + '.jpg') - out_file = os.path.join( - FDDB_RESULT_IMG_DIR, line.replace('/', '_') + '.jpg') - counter += 1 - t1 = time.time() - #img = cv2.imread(img_file, cv2.IMREAD_COLOR) - img = Image.open(img_file) - if img.mode == 'L': - img = img.convert('RGB') - img = np.array(img) - bboxes = detect_face(net, img, args.thresh) - t2 = time.time() - print('Detect %04d th image costs %.4f' % (counter, t2 - t1)) - fout.write('%s\n' % line) - fout.write('%d\n' % len(bboxes)) - for bbox in bboxes: - x1, y1, w, h, score = bbox - fout.write('%d %d %d %d %lf\n' % (x1, y1, w, h, score)) - ain.readline() - n = int(ain.readline().strip()) - for i in range(n): - line = ain.readline().strip() - line_data = [float(_) for _ in line.split(' ')[:5]] - major_axis_radius, minor_axis_radius, angle, center_x, center_y = line_data - angle = angle / 3.1415926 * 180. - center_x, center_y = int(center_x), int(center_y) - major_axis_radius, minor_axis_radius = int( - major_axis_radius), int(minor_axis_radius) - cv2.ellipse(img, (center_x, center_y), (major_axis_radius, - minor_axis_radius), angle, 0, 360, (255, 0, 0), 2) - - for bbox in bboxes: - x1, y1, w, h, score = bbox - x1, y1, x2, y2 = int(x1), int(y1), int(x1 + w), int(y1 + h) - cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) - cv2.imwrite(out_file, img) - fout.close() - ain.close() +#-*- coding:utf-8 -*- +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 division +from __future__ import absolute_import +from __future__ import print_function + +import os +import sys +import torch +import argparse +import torch.nn as nn +import torch.utils.data as data +import torch.backends.cudnn as cudnn +import torchvision.transforms as transforms + +import cv2 +import time +import numpy as np +from PIL import Image + +from data.config import cfg +from pyramidbox import build_net +from torch.autograd import Variable +from utils.augmentations import to_chw_bgr + +parser = argparse.ArgumentParser(description='pyramidbox evaluatuon fddb') +parser.add_argument('--model', + type=str, + default='weights/pyramidbox.pth', help='trained model') +parser.add_argument('--thresh', + default=0.1, type=float, + help='Final confidence threshold') +args = parser.parse_args() + + +use_cuda = torch.cuda.is_available() + +if use_cuda: + torch.set_default_tensor_type('torch.cuda.FloatTensor') +else: + torch.set_default_tensor_type('torch.FloatTensor') + + +FDDB_IMG_DIR = os.path.join(cfg.FACE.FDDB_DIR, 'images') +FDDB_FOLD_DIR = os.path.join(cfg.FACE.FDDB_DIR, 'FDDB-folds') +FDDB_RESULT_DIR = os.path.join(cfg.FACE.FDDB_DIR, 'pyramidbox') +FDDB_RESULT_IMG_DIR = os.path.join(FDDB_RESULT_DIR, 'images') + +if not os.path.exists(FDDB_RESULT_IMG_DIR): + os.makedirs(FDDB_RESULT_IMG_DIR) + + +def detect_face(net, img, thresh): + height, width, _ = img.shape + x = to_chw_bgr(img) + x = x.astype('float32') + x -= cfg.img_mean + x = x[[2, 1, 0], :, :] + + x = Variable(torch.from_numpy(x).unsqueeze(0)) + if use_cuda: + x = x.cuda() + + y = net(x) + detections = y.data + scale = torch.Tensor([img.shape[1], img.shape[0], + img.shape[1], img.shape[0]]) + + bboxes = [] + for i in range(detections.size(1)): + j = 0 + while detections[0, i, j, 0] >= thresh: + box = [] + score = detections[0, i, j, 0] + pt = (detections[0, i, j, 1:] * scale).cpu().numpy().astype(np.int) + j += 1 + box += [pt[0], pt[1], pt[2] - pt[0], pt[3] - pt[1], score] + bboxes += [box] + + return bboxes + + +if __name__ == '__main__': + net = build_net('test', cfg.NUM_CLASSES) + net.load_state_dict(torch.load(args.model)) + net.eval() + + if use_cuda: + net.cuda() + cudnn.benckmark = True + + #transform = S3FDBasicTransform(cfg.INPUT_SIZE, cfg.MEANS) + + counter = 0 + + for i in range(10): + txt_in = os.path.join(FDDB_FOLD_DIR, 'FDDB-fold-%02d.txt' % (i + 1)) + txt_out = os.path.join(FDDB_RESULT_DIR, 'fold-%02d-out.txt' % (i + 1)) + answer_in = os.path.join( + FDDB_FOLD_DIR, 'FDDB-fold-%02d-ellipseList.txt' % (i + 1)) + with open(txt_in, 'r') as fr: + lines = fr.readlines() + fout = open(txt_out, 'w') + ain = open(answer_in, 'r') + for line in lines: + line = line.strip() + img_file = os.path.join(FDDB_IMG_DIR, line + '.jpg') + out_file = os.path.join( + FDDB_RESULT_IMG_DIR, line.replace('/', '_') + '.jpg') + counter += 1 + t1 = time.time() + #img = cv2.imread(img_file, cv2.IMREAD_COLOR) + img = Image.open(img_file) + if img.mode == 'L': + img = img.convert('RGB') + img = np.array(img) + bboxes = detect_face(net, img, args.thresh) + t2 = time.time() + print('Detect %04d th image costs %.4f' % (counter, t2 - t1)) + fout.write('%s\n' % line) + fout.write('%d\n' % len(bboxes)) + for bbox in bboxes: + x1, y1, w, h, score = bbox + fout.write('%d %d %d %d %lf\n' % (x1, y1, w, h, score)) + ain.readline() + n = int(ain.readline().strip()) + for i in range(n): + line = ain.readline().strip() + line_data = [float(_) for _ in line.split(' ')[:5]] + major_axis_radius, minor_axis_radius, angle, center_x, center_y = line_data + angle = angle / 3.1415926 * 180. + center_x, center_y = int(center_x), int(center_y) + major_axis_radius, minor_axis_radius = int( + major_axis_radius), int(minor_axis_radius) + cv2.ellipse(img, (center_x, center_y), (major_axis_radius, + minor_axis_radius), angle, 0, 360, (255, 0, 0), 2) + + for bbox in bboxes: + x1, y1, w, h, score = bbox + x1, y1, x2, y2 = int(x1), int(y1), int(x1 + w), int(y1 + h) + cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) + cv2.imwrite(out_file, img) + fout.close() + ain.close() diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/tools/pascal_test.py b/PyTorch/contrib/cv/detection/Pyramidbox/tools/pascal_test.py index c8f6a5429b..0a2f7b999a 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/tools/pascal_test.py +++ b/PyTorch/contrib/cv/detection/Pyramidbox/tools/pascal_test.py @@ -1,140 +1,140 @@ -#-*- coding:utf-8 -*- -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 division -from __future__ import absolute_import -from __future__ import print_function - -import os -import torch -import argparse -import torch.nn as nn -import torch.utils.data as data -import torch.backends.cudnn as cudnn -import torchvision.transforms as transforms -import os.path as osp - -import cv2 -import time -import numpy as np -from PIL import Image - -from data.config import cfg -from pyramidbox import build_net -from torch.autograd import Variable -from utils.augmentations import to_chw_bgr - -parser = argparse.ArgumentParser(description='pyramidbox evaluatuon pascal') -parser.add_argument('--model', - type=str,default='weights/pyramidbox.pth', - help='trained model') -parser.add_argument('--thresh', - default=0.1, type=float, - help='Final confidence threshold') -args = parser.parse_args() - -use_cuda = torch.cuda.is_available() - -if use_cuda: - torch.set_default_tensor_type('torch.cuda.FloatTensor') -else: - torch.set_default_tensor_type('torch.FloatTensor') - -PASCAL_IMG_DIR = os.path.join(cfg.FACE.PASCAL_DIR, 'images') -PASCAL_RESULT_DIR = os.path.join(cfg.FACE.PASCAL_DIR, 'pyramidbox') -PASCAL_RESULT_IMG_DIR = os.path.join(PASCAL_RESULT_DIR, 'images') - -if not os.path.exists(PASCAL_RESULT_IMG_DIR): - os.makedirs(PASCAL_RESULT_IMG_DIR) - - -def detect_face(net, img, thresh): - height, width, _ = img.shape - im_shrink = 640.0 / max(height, width) - image = cv2.resize(img, None, None, fx=im_shrink, - fy=im_shrink, interpolation=cv2.INTER_LINEAR).copy() - - x = to_chw_bgr(image) - x = x.astype('float32') - x -= cfg.img_mean - x = x[[2, 1, 0], :, :] - - x = Variable(torch.from_numpy(x).unsqueeze(0)) - if use_cuda: - x = x.cuda() - - y = net(x) - detections = y.data - scale = torch.Tensor([img.shape[1], img.shape[0], - img.shape[1], img.shape[0]]) - - bboxes = [] - for i in range(detections.size(1)): - j = 0 - while detections[0, i, j, 0] >= thresh: - box = [] - score = detections[0, i, j, 0] - pt = (detections[0, i, j, 1:] * scale).cpu().numpy().astype(np.int) - j += 1 - box += [pt[0], pt[1], pt[2], pt[3], score] - box[1] += 0.2 * (box[3] - box[1] + 1) - bboxes += [box] - - return bboxes - - -if __name__ == '__main__': - net = build_net('test', cfg.NUM_CLASSES) - net.load_state_dict(torch.load(args.model)) - net.eval() - - if use_cuda: - net.cuda() - cudnn.benckmark = True - - #transform = S3FDBasicTransform(cfg.INPUT_SIZE, cfg.MEANS) - - counter = 0 - txt_out = os.path.join(PASCAL_RESULT_DIR, 'pyramidbox_dets.txt') - txt_in = os.path.join('./tools/pascal_img_list.txt') - - fout = open(txt_out, 'w') - fin = open(txt_in, 'r') - - for line in fin.readlines(): - line = line.strip() - img_file = os.path.join(PASCAL_IMG_DIR, line) - out_file = os.path.join(PASCAL_RESULT_IMG_DIR, line) - counter += 1 - t1 = time.time() - #img = cv2.imread(img_file, cv2.IMREAD_COLOR) - img = Image.open(img_file) - if img.mode == 'L': - img = img.convert('RGB') - img = np.array(img) - bboxes = detect_face(net, img, args.thresh) - t2 = time.time() - print('Detect %04d th image costs %.4f' % (counter, t2 - t1)) - for bbox in bboxes: - x1, y1, x2, y2, score = bbox - fout.write('{:s} {:.3f} {:.1f} {:.1f} {:.1f} {:.1f}\n'.format( - line, score, x1, y1, x2, y2)) - for bbox in bboxes: - x1, y1, x2, y2, score = bbox - x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2) - cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) - cv2.imwrite(out_file, img) - - fout.close() - fin.close() +#-*- coding:utf-8 -*- +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 division +from __future__ import absolute_import +from __future__ import print_function + +import os +import torch +import argparse +import torch.nn as nn +import torch.utils.data as data +import torch.backends.cudnn as cudnn +import torchvision.transforms as transforms +import os.path as osp + +import cv2 +import time +import numpy as np +from PIL import Image + +from data.config import cfg +from pyramidbox import build_net +from torch.autograd import Variable +from utils.augmentations import to_chw_bgr + +parser = argparse.ArgumentParser(description='pyramidbox evaluatuon pascal') +parser.add_argument('--model', + type=str,default='weights/pyramidbox.pth', + help='trained model') +parser.add_argument('--thresh', + default=0.1, type=float, + help='Final confidence threshold') +args = parser.parse_args() + +use_cuda = torch.cuda.is_available() + +if use_cuda: + torch.set_default_tensor_type('torch.cuda.FloatTensor') +else: + torch.set_default_tensor_type('torch.FloatTensor') + +PASCAL_IMG_DIR = os.path.join(cfg.FACE.PASCAL_DIR, 'images') +PASCAL_RESULT_DIR = os.path.join(cfg.FACE.PASCAL_DIR, 'pyramidbox') +PASCAL_RESULT_IMG_DIR = os.path.join(PASCAL_RESULT_DIR, 'images') + +if not os.path.exists(PASCAL_RESULT_IMG_DIR): + os.makedirs(PASCAL_RESULT_IMG_DIR) + + +def detect_face(net, img, thresh): + height, width, _ = img.shape + im_shrink = 640.0 / max(height, width) + image = cv2.resize(img, None, None, fx=im_shrink, + fy=im_shrink, interpolation=cv2.INTER_LINEAR).copy() + + x = to_chw_bgr(image) + x = x.astype('float32') + x -= cfg.img_mean + x = x[[2, 1, 0], :, :] + + x = Variable(torch.from_numpy(x).unsqueeze(0)) + if use_cuda: + x = x.cuda() + + y = net(x) + detections = y.data + scale = torch.Tensor([img.shape[1], img.shape[0], + img.shape[1], img.shape[0]]) + + bboxes = [] + for i in range(detections.size(1)): + j = 0 + while detections[0, i, j, 0] >= thresh: + box = [] + score = detections[0, i, j, 0] + pt = (detections[0, i, j, 1:] * scale).cpu().numpy().astype(np.int) + j += 1 + box += [pt[0], pt[1], pt[2], pt[3], score] + box[1] += 0.2 * (box[3] - box[1] + 1) + bboxes += [box] + + return bboxes + + +if __name__ == '__main__': + net = build_net('test', cfg.NUM_CLASSES) + net.load_state_dict(torch.load(args.model)) + net.eval() + + if use_cuda: + net.cuda() + cudnn.benckmark = True + + #transform = S3FDBasicTransform(cfg.INPUT_SIZE, cfg.MEANS) + + counter = 0 + txt_out = os.path.join(PASCAL_RESULT_DIR, 'pyramidbox_dets.txt') + txt_in = os.path.join('./tools/pascal_img_list.txt') + + fout = open(txt_out, 'w') + fin = open(txt_in, 'r') + + for line in fin.readlines(): + line = line.strip() + img_file = os.path.join(PASCAL_IMG_DIR, line) + out_file = os.path.join(PASCAL_RESULT_IMG_DIR, line) + counter += 1 + t1 = time.time() + #img = cv2.imread(img_file, cv2.IMREAD_COLOR) + img = Image.open(img_file) + if img.mode == 'L': + img = img.convert('RGB') + img = np.array(img) + bboxes = detect_face(net, img, args.thresh) + t2 = time.time() + print('Detect %04d th image costs %.4f' % (counter, t2 - t1)) + for bbox in bboxes: + x1, y1, x2, y2, score = bbox + fout.write('{:s} {:.3f} {:.1f} {:.1f} {:.1f} {:.1f}\n'.format( + line, score, x1, y1, x2, y2)) + for bbox in bboxes: + x1, y1, x2, y2, score = bbox + x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2) + cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) + cv2.imwrite(out_file, img) + + fout.close() + fin.close() diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/tools/wider_test.py b/PyTorch/contrib/cv/detection/Pyramidbox/tools/wider_test.py index d79f4c8e08..942d87bb70 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/tools/wider_test.py +++ b/PyTorch/contrib/cv/detection/Pyramidbox/tools/wider_test.py @@ -1,283 +1,283 @@ -#-*- coding:utf-8 -*- -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -from __future__ import division -from __future__ import absolute_import -from __future__ import print_function - -import os -import torch -import argparse -import torch.nn as nn -import torch.utils.data as data -import torch.backends.cudnn as cudnn -import torchvision.transforms as transforms -import os.path as osp -import time -import cv2 -import time -import numpy as np -from PIL import Image -import scipy.io as sio - -import sys -#sys.path.append("/home/wch/Pyramidbox/") -from data.config import cfg -from pyramidbox import build_net -from torch.autograd import Variable -from utils.augmentations import to_chw_bgr -import torch.npu - -parser = argparse.ArgumentParser(description='pyramidbox evaluatuon wider') -parser.add_argument('--model', type=str, - default="weights/pyramidbox.pth", help='trained model') -parser.add_argument('--thresh', default=0.05, type=float, - help='Final confidence threshold') -parser.add_argument('--data_path', - default=None, type=str, - help='data_path') -args = parser.parse_args() - - -use_npu = torch.npu.is_available() - -def detect_face(net, img, shrink): - if shrink != 1: - img = cv2.resize(img, None, None, fx=shrink, fy=shrink, - interpolation=cv2.INTER_LINEAR) - - x = to_chw_bgr(img) - x = x.astype('float32') - x -= cfg.img_mean - x = x[[2, 1, 0], :, :] - image_x = x.shape[1] - image_y = x.shape[2] - if image_x <2500 and image_y<2500: - x0 = torch.Tensor(x[0]) - x1 = torch.Tensor(x[1]) - x2 = torch.Tensor(x[2]) - pad = nn.ZeroPad2d(padding=(0,2500-image_y,0,2500-image_x)) - x0 = pad(x0) - x1 = pad(x1) - x2 = pad(x2) - x0 =np.array(x0) - x1 =np.array(x1) - x2 =np.array(x2) - x = np.array([x0,x1,x2]) - x = Variable(torch.from_numpy(x).unsqueeze(0)) - - if use_npu: - x = x.npu() - y = net(x) - detections = y.data - detections = detections.cpu().numpy() - - det_conf = detections[0, 1, :, 0] - if image_x < 2500 and image_y < 2500: - det_xmin = 2500 * detections[0, 1, :, 1] / shrink - det_ymin = 2500 * detections[0, 1, :, 2] / shrink - det_xmax = 2500 * detections[0, 1, :, 3] / shrink - det_ymax = 2500 * detections[0, 1, :, 4] / shrink - else: - det_xmin = img.shape[1] * detections[0, 1, :, 1] / shrink - det_ymin = img.shape[0] * detections[0, 1, :, 2] / shrink - det_xmax = img.shape[1] * detections[0, 1, :, 3] / shrink - det_ymax = img.shape[0] * detections[0, 1, :, 4] / shrink - det = np.column_stack((det_xmin, det_ymin, det_xmax, det_ymax, det_conf)) - - keep_index = np.where(det[:, 4] >= args.thresh)[0] - det = det[keep_index, :] - return det - - -def flip_test(net, image, shrink): - image_f = cv2.flip(image, 1) - det_f = detect_face(net, image_f, shrink) - det_t = np.zeros(det_f.shape) - det_t[:, 0] = image.shape[1] - det_f[:, 2] - det_t[:, 1] = det_f[:, 1] - det_t[:, 2] = image.shape[1] - det_f[:, 0] - det_t[:, 3] = det_f[:, 3] - det_t[:, 4] = det_f[:, 4] - return det_t - - -def multi_scale_test(net, image, max_im_shrink): - # shrink detecting and shrink only detect big face - st = 0.5 if max_im_shrink >= 0.75 else 0.5 * max_im_shrink - det_s = detect_face(net, image, st) - index = np.where(np.maximum( - det_s[:, 2] - det_s[:, 0] + 1, det_s[:, 3] - det_s[:, 1] + 1) > 30)[0] - det_s = det_s[index, :] - - # enlarge one times - bt = min(2, max_im_shrink) if max_im_shrink > 1 else ( - st + max_im_shrink) / 2 - det_b = detect_face(net, image, bt) - - # enlarge small image x times for small face - if max_im_shrink > 2: - bt *= 2 - while bt < max_im_shrink: - det_b = np.row_stack((det_b, detect_face(net, image, bt))) - bt *= 2 - det_b = np.row_stack((det_b, detect_face(net, image, max_im_shrink))) - - # enlarge only detect small face - if bt > 1: - index = np.where(np.minimum( - det_b[:, 2] - det_b[:, 0] + 1, det_b[:, 3] - det_b[:, 1] + 1) < 100)[0] - det_b = det_b[index, :] - else: - index = np.where(np.maximum( - det_b[:, 2] - det_b[:, 0] + 1, det_b[:, 3] - det_b[:, 1] + 1) > 30)[0] - det_b = det_b[index, :] - - return det_s, det_b - - -def bbox_vote(det): - order = det[:, 4].ravel().argsort()[::-1] - det = det[order, :] - while det.shape[0] > 0: - # IOU - area = (det[:, 2] - det[:, 0] + 1) * (det[:, 3] - det[:, 1] + 1) - xx1 = np.maximum(det[0, 0], det[:, 0]) - yy1 = np.maximum(det[0, 1], det[:, 1]) - xx2 = np.minimum(det[0, 2], det[:, 2]) - yy2 = np.minimum(det[0, 3], det[:, 3]) - w = np.maximum(0.0, xx2 - xx1 + 1) - h = np.maximum(0.0, yy2 - yy1 + 1) - inter = w * h - o = inter / (area[0] + area[:] - inter) - - # get needed merge det and delete these det - merge_index = np.where(o >= 0.3)[0] - det_accu = det[merge_index, :] - det = np.delete(det, merge_index, 0) - - if merge_index.shape[0] <= 1: - continue - det_accu[:, 0:4] = det_accu[:, 0:4] * np.tile(det_accu[:, -1:], (1, 4)) - max_score = np.max(det_accu[:, 4]) - det_accu_sum = np.zeros((1, 5)) - det_accu_sum[:, 0:4] = np.sum( - det_accu[:, 0:4], axis=0) / np.sum(det_accu[:, -1:]) - det_accu_sum[:, 4] = max_score - try: - dets = np.row_stack((dets, det_accu_sum)) - except: - dets = det_accu_sum - - try: - dets = dets[0:750, :] - except: - dets = det - - return dets - - -def get_data(): - subset = 'val' - if subset is 'val': - wider_face = sio.loadmat(args.data_path+'wider_face_split/wider_face_val.mat') - else: - wider_face = sio.loadmat(args.data_path+'wider_face_split/wider_face_test.mat') - event_list = wider_face['event_list'] - file_list = wider_face['file_list'] - del wider_face - - imgs_path = os.path.join( - args.data_path, 'WIDER_{}'.format(subset), 'images') - save_path = 'output/pyramidbox1_{}'.format(subset) - - return event_list, file_list, imgs_path, save_path - -if __name__ == '__main__': - event_list, file_list, imgs_path, save_path = get_data() - cfg.USE_NMS = False - net = build_net('test', cfg.NUM_CLASSES) - net.load_state_dict(torch.load(args.model,map_location='cpu')) - - - net.eval() - - if use_npu: - net.npu() - cudnn.benckmark = True - - counter = 0 - print('start in ........') - for index, event in enumerate(event_list): - filelist = file_list[index][0] - path = os.path.join(save_path, str(event[0][0])) - if not os.path.exists(path): - os.makedirs(path) - - for num, file in enumerate(filelist): - im_name = file[0][0] - in_file = os.path.join(imgs_path, event[0][0], str(im_name[:]) + '.jpg') - img = Image.open(in_file) - if img.mode == 'L': - img = img.convert('RGB') - img = np.array(img) - max_im_shrink = np.sqrt( - 1700 * 1000 / (img.shape[0] * img.shape[1])) - - shrink = max_im_shrink if max_im_shrink < 1 else 1 - counter += 1 - - t1 = time.time() - det0 = detect_face(net, img, shrink) - det1 = flip_test(net, img, shrink) # flip test - [det2, det3] = multi_scale_test(net, img, max_im_shrink) - det = np.row_stack((det0, det1, det2, det3)) - if det.shape[0] ==1: - dets =det - else: - dets = bbox_vote(det) - - t2 = time.time() - print('Detect %04d th image costs %.4f' % (counter, t2 - t1)) - - fout = open(osp.join(save_path, str(event[0][ - 0]), im_name + '.txt'), 'w') - fout.write('{:s}\n'.format(str(event[0][0]) + '/' + im_name + '.jpg')) - fout.write('{:d}\n'.format(dets.shape[0])) - for i in range(dets.shape[0]): - xmin = dets[i][0] - ymin = dets[i][1] - xmax = dets[i][2] - ymax = dets[i][3] - score = dets[i][4] - fout.write('{:.1f} {:.1f} {:.1f} {:.1f} {:.3f}\n'. - format(xmin, ymin, (xmax - xmin + 1), (ymax - ymin + 1), score)) +#-*- coding:utf-8 -*- +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +from __future__ import division +from __future__ import absolute_import +from __future__ import print_function + +import os +import torch +import argparse +import torch.nn as nn +import torch.utils.data as data +import torch.backends.cudnn as cudnn +import torchvision.transforms as transforms +import os.path as osp +import time +import cv2 +import time +import numpy as np +from PIL import Image +import scipy.io as sio + +import sys +#sys.path.append("/home/wch/Pyramidbox/") +from data.config import cfg +from pyramidbox import build_net +from torch.autograd import Variable +from utils.augmentations import to_chw_bgr +import torch.npu + +parser = argparse.ArgumentParser(description='pyramidbox evaluatuon wider') +parser.add_argument('--model', type=str, + default="weights/pyramidbox.pth", help='trained model') +parser.add_argument('--thresh', default=0.05, type=float, + help='Final confidence threshold') +parser.add_argument('--data_path', + default=None, type=str, + help='data_path') +args = parser.parse_args() + + +use_npu = torch.npu.is_available() + +def detect_face(net, img, shrink): + if shrink != 1: + img = cv2.resize(img, None, None, fx=shrink, fy=shrink, + interpolation=cv2.INTER_LINEAR) + + x = to_chw_bgr(img) + x = x.astype('float32') + x -= cfg.img_mean + x = x[[2, 1, 0], :, :] + image_x = x.shape[1] + image_y = x.shape[2] + if image_x <2500 and image_y<2500: + x0 = torch.Tensor(x[0]) + x1 = torch.Tensor(x[1]) + x2 = torch.Tensor(x[2]) + pad = nn.ZeroPad2d(padding=(0,2500-image_y,0,2500-image_x)) + x0 = pad(x0) + x1 = pad(x1) + x2 = pad(x2) + x0 =np.array(x0) + x1 =np.array(x1) + x2 =np.array(x2) + x = np.array([x0,x1,x2]) + x = Variable(torch.from_numpy(x).unsqueeze(0)) + + if use_npu: + x = x.npu() + y = net(x) + detections = y.data + detections = detections.cpu().numpy() + + det_conf = detections[0, 1, :, 0] + if image_x < 2500 and image_y < 2500: + det_xmin = 2500 * detections[0, 1, :, 1] / shrink + det_ymin = 2500 * detections[0, 1, :, 2] / shrink + det_xmax = 2500 * detections[0, 1, :, 3] / shrink + det_ymax = 2500 * detections[0, 1, :, 4] / shrink + else: + det_xmin = img.shape[1] * detections[0, 1, :, 1] / shrink + det_ymin = img.shape[0] * detections[0, 1, :, 2] / shrink + det_xmax = img.shape[1] * detections[0, 1, :, 3] / shrink + det_ymax = img.shape[0] * detections[0, 1, :, 4] / shrink + det = np.column_stack((det_xmin, det_ymin, det_xmax, det_ymax, det_conf)) + + keep_index = np.where(det[:, 4] >= args.thresh)[0] + det = det[keep_index, :] + return det + + +def flip_test(net, image, shrink): + image_f = cv2.flip(image, 1) + det_f = detect_face(net, image_f, shrink) + det_t = np.zeros(det_f.shape) + det_t[:, 0] = image.shape[1] - det_f[:, 2] + det_t[:, 1] = det_f[:, 1] + det_t[:, 2] = image.shape[1] - det_f[:, 0] + det_t[:, 3] = det_f[:, 3] + det_t[:, 4] = det_f[:, 4] + return det_t + + +def multi_scale_test(net, image, max_im_shrink): + # shrink detecting and shrink only detect big face + st = 0.5 if max_im_shrink >= 0.75 else 0.5 * max_im_shrink + det_s = detect_face(net, image, st) + index = np.where(np.maximum( + det_s[:, 2] - det_s[:, 0] + 1, det_s[:, 3] - det_s[:, 1] + 1) > 30)[0] + det_s = det_s[index, :] + + # enlarge one times + bt = min(2, max_im_shrink) if max_im_shrink > 1 else ( + st + max_im_shrink) / 2 + det_b = detect_face(net, image, bt) + + # enlarge small image x times for small face + if max_im_shrink > 2: + bt *= 2 + while bt < max_im_shrink: + det_b = np.row_stack((det_b, detect_face(net, image, bt))) + bt *= 2 + det_b = np.row_stack((det_b, detect_face(net, image, max_im_shrink))) + + # enlarge only detect small face + if bt > 1: + index = np.where(np.minimum( + det_b[:, 2] - det_b[:, 0] + 1, det_b[:, 3] - det_b[:, 1] + 1) < 100)[0] + det_b = det_b[index, :] + else: + index = np.where(np.maximum( + det_b[:, 2] - det_b[:, 0] + 1, det_b[:, 3] - det_b[:, 1] + 1) > 30)[0] + det_b = det_b[index, :] + + return det_s, det_b + + +def bbox_vote(det): + order = det[:, 4].ravel().argsort()[::-1] + det = det[order, :] + while det.shape[0] > 0: + # IOU + area = (det[:, 2] - det[:, 0] + 1) * (det[:, 3] - det[:, 1] + 1) + xx1 = np.maximum(det[0, 0], det[:, 0]) + yy1 = np.maximum(det[0, 1], det[:, 1]) + xx2 = np.minimum(det[0, 2], det[:, 2]) + yy2 = np.minimum(det[0, 3], det[:, 3]) + w = np.maximum(0.0, xx2 - xx1 + 1) + h = np.maximum(0.0, yy2 - yy1 + 1) + inter = w * h + o = inter / (area[0] + area[:] - inter) + + # get needed merge det and delete these det + merge_index = np.where(o >= 0.3)[0] + det_accu = det[merge_index, :] + det = np.delete(det, merge_index, 0) + + if merge_index.shape[0] <= 1: + continue + det_accu[:, 0:4] = det_accu[:, 0:4] * np.tile(det_accu[:, -1:], (1, 4)) + max_score = np.max(det_accu[:, 4]) + det_accu_sum = np.zeros((1, 5)) + det_accu_sum[:, 0:4] = np.sum( + det_accu[:, 0:4], axis=0) / np.sum(det_accu[:, -1:]) + det_accu_sum[:, 4] = max_score + try: + dets = np.row_stack((dets, det_accu_sum)) + except: + dets = det_accu_sum + + try: + dets = dets[0:750, :] + except: + dets = det + + return dets + + +def get_data(): + subset = 'val' + if subset is 'val': + wider_face = sio.loadmat(args.data_path+'wider_face_split/wider_face_val.mat') + else: + wider_face = sio.loadmat(args.data_path+'wider_face_split/wider_face_test.mat') + event_list = wider_face['event_list'] + file_list = wider_face['file_list'] + del wider_face + + imgs_path = os.path.join( + args.data_path, 'WIDER_{}'.format(subset), 'images') + save_path = 'output/pyramidbox1_{}'.format(subset) + + return event_list, file_list, imgs_path, save_path + +if __name__ == '__main__': + event_list, file_list, imgs_path, save_path = get_data() + cfg.USE_NMS = False + net = build_net('test', cfg.NUM_CLASSES) + net.load_state_dict(torch.load(args.model,map_location='cpu')) + + + net.eval() + + if use_npu: + net.npu() + cudnn.benckmark = True + + counter = 0 + print('start in ........') + for index, event in enumerate(event_list): + filelist = file_list[index][0] + path = os.path.join(save_path, str(event[0][0])) + if not os.path.exists(path): + os.makedirs(path) + + for num, file in enumerate(filelist): + im_name = file[0][0] + in_file = os.path.join(imgs_path, event[0][0], str(im_name[:]) + '.jpg') + img = Image.open(in_file) + if img.mode == 'L': + img = img.convert('RGB') + img = np.array(img) + max_im_shrink = np.sqrt( + 1700 * 1000 / (img.shape[0] * img.shape[1])) + + shrink = max_im_shrink if max_im_shrink < 1 else 1 + counter += 1 + + t1 = time.time() + det0 = detect_face(net, img, shrink) + det1 = flip_test(net, img, shrink) # flip test + [det2, det3] = multi_scale_test(net, img, max_im_shrink) + det = np.row_stack((det0, det1, det2, det3)) + if det.shape[0] ==1: + dets =det + else: + dets = bbox_vote(det) + + t2 = time.time() + print('Detect %04d th image costs %.4f' % (counter, t2 - t1)) + + fout = open(osp.join(save_path, str(event[0][ + 0]), im_name + '.txt'), 'w') + fout.write('{:s}\n'.format(str(event[0][0]) + '/' + im_name + '.jpg')) + fout.write('{:d}\n'.format(dets.shape[0])) + for i in range(dets.shape[0]): + xmin = dets[i][0] + ymin = dets[i][1] + xmax = dets[i][2] + ymax = dets[i][3] + score = dets[i][4] + fout.write('{:.1f} {:.1f} {:.1f} {:.1f} {:.3f}\n'. + format(xmin, ymin, (xmax - xmin + 1), (ymax - ymin + 1), score)) diff --git a/PyTorch/contrib/cv/detection/Pyramidbox/train.py b/PyTorch/contrib/cv/detection/Pyramidbox/train.py index 65ba899793..6307c7210f 100644 --- a/PyTorch/contrib/cv/detection/Pyramidbox/train.py +++ b/PyTorch/contrib/cv/detection/Pyramidbox/train.py @@ -1,361 +1,361 @@ -#-*- coding:utf-8 -*- -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -from __future__ import division -from __future__ import absolute_import -from __future__ import print_function - - -import torch.nn as nn -import torch.optim as optim -import torch.nn.init as init -import torch.utils.data as data - -import os -import time -import torch -import argparse - -import numpy as np -from torch.autograd import Variable -import torch.backends.cudnn as cudnn -import torch.npu -from data.config import cfg -from pyramidbox import build_net -from layers.modules import MultiBoxLoss -from data.widerface import WIDERDetection, detection_collate -from torch.nn.parallel import DistributedDataParallel as DDP -import apex -from apex import amp -import torch.distributed as dist -import torch.multiprocessing as mp - -parser = argparse.ArgumentParser( - description='Pyramidbox face Detector Training With Pytorch') -train_set = parser.add_mutually_exclusive_group() -parser.add_argument('--basenet', - default='vgg16_reducedfc.pth', - help='Pretrained base model') -parser.add_argument('--batch_size', - default=16, type=int, - help='Batch size for training') -parser.add_argument('--resume', - default=None, type=str, - help='Checkpoint state_dict file to resume training from') -parser.add_argument('--num_workers', - default=4, type=int, - help='Number of workers used in dataloading') -parser.add_argument('--npu', - default=True, type=bool, - help='Use NPU to train model') -parser.add_argument('--performance', - default=False, type=bool, - help='performance to train') -parser.add_argument('--lr', '--learning-rate', - default=1e-3, type=float, - help='initial learning rate') -parser.add_argument('--momentum', - default=0.9, type=float, - help='Momentum value for optim') -parser.add_argument('--weight_decay', - default=5e-4, type=float, - help='Weight decay for SGD') -parser.add_argument('--gamma', - default=0.1, type=float, - help='Gamma update for SGD') -parser.add_argument('--multinpu', - default=False, type=bool, - help='Use mutil Gpu training') -parser.add_argument('--save_folder', - default='weights/', - help='Directory for saving checkpoint models') -parser.add_argument('--local_rank', - default=-1, type=int, - help='rank for current process') -parser.add_argument('--world_size', default=-1, type=int, - help='number of distributed processes') -parser.add_argument('--device_list', default='0', type=str, - help='NPU id to use.') -args = parser.parse_args() - -if args.npu: - if args.multinpu: - device_id = int(args.device_list.split(',')[args.local_rank]) - device = 'npu:{}'.format(device_id) - else: - device = 'npu:0' - torch.npu.set_device(device) - -if not os.path.exists(args.save_folder): - os.makedirs(args.save_folder) - -train_dataset = WIDERDetection(cfg.FACE.TRAIN_FILE, mode='train') - -val_dataset = WIDERDetection(cfg.FACE.VAL_FILE, mode='val') -val_batchsize = 1 -val_loader = data.DataLoader(val_dataset, val_batchsize, - num_workers=1, - shuffle=False, - collate_fn=detection_collate, - pin_memory=True) - -min_loss = np.inf -def train(): - # torch.set_num_threads(1) - iteration = 0 - start_epoch = 0 - step_index = 0 - per_epoch_size = len(train_dataset) // args.batch_size - if args.local_rank==0 or args.multinpu==False: - print('------build_net start-------') - pyramidbox = build_net('train', cfg.NUM_CLASSES) - if args.local_rank==0 or args.multinpu==False: - print('------build_net end-------') - net = pyramidbox - if args.multinpu: - train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset) - train_loader = torch.utils.data.DataLoader( - dataset=train_dataset, - batch_size=args.batch_size, - shuffle=(train_sampler is None), - num_workers=args.num_workers, - pin_memory=False, - sampler=train_sampler, - collate_fn=detection_collate, - drop_last=True) - else: - train_loader = data.DataLoader(train_dataset, args.batch_size, - num_workers=args.num_workers, - shuffle=False, - collate_fn=detection_collate, - pin_memory=True) - if args.resume: - print('Resuming training, loading {}...'.format(args.resume)) - start_epoch = net.load_weights(args.resume) - iteration = start_epoch * per_epoch_size - else: - vgg_weights = torch.load(args.save_folder + args.basenet) - if args.local_rank==0 or args.multinpu==False: - print('Load base network....') - net.vgg.load_state_dict(vgg_weights) - - if args.local_rank==0 or args.multinpu==False: - print('load base network end--------') - if not args.resume: - if args.local_rank==0 or args.multinpu==False: - print('Initializing weights...') - pyramidbox.bn64.apply(pyramidbox.weights_init) - pyramidbox.extras.apply(pyramidbox.weights_init) - pyramidbox.lfpn_topdown.apply(pyramidbox.weights_init) - pyramidbox.lfpn_later.apply(pyramidbox.weights_init) - pyramidbox.cpm.apply(pyramidbox.weights_init) - pyramidbox.loc_layers.apply(pyramidbox.weights_init) - pyramidbox.conf_layers.apply(pyramidbox.weights_init) - - optimizer = optim.SGD(net.parameters(), lr=args.lr, momentum=args.momentum, - weight_decay=args.weight_decay) - - if args.npu: - net.npu() - net, optimizer = amp.initialize(net, optimizer, opt_level="O1",loss_scale=64.0)#,combine_grad=True) - if args.multinpu: - device_id = int(args.device_list.split(',')[args.local_rank]) - device = 'npu:{}'.format(device_id) - net = DDP(net, device_ids=[device_id],broadcast_buffers=False) - cudnn.benckmark = True - criterion1 = MultiBoxLoss(cfg, args.npu) - criterion2 = MultiBoxLoss(cfg, args.npu, use_head_loss=True) - if args.local_rank==0 or args.multinpu==False: - print('Loading wider dataset...') - print('Using the specified args:') - print(args) - warmup_steps = 1000 - net.train() - if args.local_rank==0 or args.multinpu==False: - print('start train--------') - for epoch in range(start_epoch, cfg.EPOCHES): - if args.multinpu: - train_sampler.set_epoch(epoch) - losses = 0 - for batch_idx, (images, face_targets, head_targets) in enumerate(train_loader): - - if args.npu: - images = Variable(images.npu()) - with torch.no_grad(): - face_targets = [Variable(ann) for ann in face_targets] - head_targets = [Variable(ann) for ann in head_targets] - else: - images = Variable(images) - with torch.no_grad(): - face_targets = [Variable(ann) for ann in face_targets] - head_targets = [Variable(ann) for ann in head_targets] - adjust_learning_rate(optimizer,iteration,warmup_steps,15000) - t0 = time.time() - out = net(images) - optimizer.zero_grad() - face_loss_l, face_loss_c = criterion1(out, face_targets) - head_loss_l, head_loss_c = criterion2(out, head_targets) - loss = face_loss_l + face_loss_c + head_loss_l + head_loss_c - losses += loss.item() - if args.npu: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.step() - t1 = time.time() - face_loss = (face_loss_l + face_loss_c).item() - head_loss = (head_loss_l + head_loss_c).item() - - if args.performance: - if iteration == 50: - t50_0 = time.time() - if iteration == 100: - t100_0 = time.time() - if args.multinpu: - if args.local_rank==0: - print('cost time:{} batch_size:{} num_gpu:{} FPS:{}'.format(t100_0-t50_0,args.batch_size,args.world_size,(50*args.batch_size*args.world_size)/(t100_0-t50_0))) - else: - print('cost time:{} batch_size:{} FPS:{}'.format(t100_0-t50_0,args.batch_size,(50*args.batch_size)/(t100_0-t50_0))) - if iteration == 110: - break - iteration += 1 - continue - if iteration % 10 == 0 and (args.local_rank==0 or args.multinpu==False): - loss_ = losses / (batch_idx + 1) - print('Timer: {:.4f} sec.'.format(t1 - t0)) - print('epoch ' + repr(epoch) + ' iter ' + - repr(iteration) + ' || Loss:%.4f' % (loss_)) - print('->> face Loss: {:.4f} || head loss : {:.4f}'.format( - face_loss, head_loss)) - print('->> lr: {}'.format(optimizer.param_groups[0]['lr'])) - if args.multinpu: - print('iter:{} cost time:{} batch_size:{} num_gpu:{} FPS:{}'.format(iteration,t1-t0,args.batch_size,args.world_size,(args.batch_size*args.world_size)/(t1-t0))) - else: - print('iter:{} cost time:{} batch_size:{} FPS:{}'.format(iteration,t1-t0,args.batch_size,args.batch_size/(t1-t0))) - if iteration != 0 and iteration % 2000 == 0 and (args.local_rank==0 or args.multinpu==False): - print('Saving state, iter:', iteration) - file = 'pyramidbox_' + repr(iteration) + '.pth' - torch.save(pyramidbox.state_dict(), - os.path.join(args.save_folder, file)) - iteration += 1 - if args.performance: - break - if epoch>50 and epoch%5==0: - val(epoch, net, pyramidbox, criterion1, criterion2) - net.train() - -def val(epoch, - net, - pyramidbox, - criterion1, - criterion2): - net.eval() - face_losses = 0 - head_losses = 0 - step = 0 - t1 = time.time() - for batch_idx, (images, face_targets, head_targets) in enumerate(val_loader): - if args.npu: - images = Variable(images.npu()) - with torch.no_grad(): - face_targets = [Variable(ann) for ann in face_targets] - head_targets = [Variable(ann) for ann in head_targets] - - else: - images = Variable(images) - with torch.no_grad(): - face_targets = [Variable(ann) - for ann in face_targets] - head_targets = [Variable(ann) - for ann in head_targets] - - out = net(images) - face_loss_l, face_loss_c = criterion1(out, face_targets) - head_loss_l, head_loss_c = criterion2(out, head_targets) - - face_losses += (face_loss_l + face_loss_c).item() - head_losses += (head_loss_l + head_loss_c).item() - step += 1 - - tloss = face_losses / step - - t2 = time.time() - if args.local_rank==0: - print('test Timer:{:.4f} .sec'.format(t2 - t1)) - print('epoch ' + repr(epoch) + ' || Loss:%.4f' % (tloss)) - - global min_loss - if tloss < min_loss and args.local_rank==0: - print('Saving best state,epoch', epoch) - torch.save(pyramidbox.state_dict(), os.path.join( - args.save_folder, 'pyramidbox.pth')) - min_loss = tloss - - states = { - 'epoch': epoch, - 'weight': pyramidbox.state_dict(), - } - if args.local_rank==0: - torch.save(states, os.path.join( - args.save_folder, 'pyramidbox_checkpoint.pth')) - - -def lr_warmup(optimizer,step,base_lr,warmup_steps): - if not step > face Loss: {:.4f} || head loss : {:.4f}'.format( + face_loss, head_loss)) + print('->> lr: {}'.format(optimizer.param_groups[0]['lr'])) + if args.multinpu: + print('iter:{} cost time:{} batch_size:{} num_gpu:{} FPS:{}'.format(iteration,t1-t0,args.batch_size,args.world_size,(args.batch_size*args.world_size)/(t1-t0))) + else: + print('iter:{} cost time:{} batch_size:{} FPS:{}'.format(iteration,t1-t0,args.batch_size,args.batch_size/(t1-t0))) + if iteration != 0 and iteration % 2000 == 0 and (args.local_rank==0 or args.multinpu==False): + print('Saving state, iter:', iteration) + file = 'pyramidbox_' + repr(iteration) + '.pth' + torch.save(pyramidbox.state_dict(), + os.path.join(args.save_folder, file)) + iteration += 1 + if args.performance: + break + if epoch>50 and epoch%5==0: + val(epoch, net, pyramidbox, criterion1, criterion2) + net.train() + +def val(epoch, + net, + pyramidbox, + criterion1, + criterion2): + net.eval() + face_losses = 0 + head_losses = 0 + step = 0 + t1 = time.time() + for batch_idx, (images, face_targets, head_targets) in enumerate(val_loader): + if args.npu: + images = Variable(images.npu()) + with torch.no_grad(): + face_targets = [Variable(ann) for ann in face_targets] + head_targets = [Variable(ann) for ann in head_targets] + + else: + images = Variable(images) + with torch.no_grad(): + face_targets = [Variable(ann) + for ann in face_targets] + head_targets = [Variable(ann) + for ann in head_targets] + + out = net(images) + face_loss_l, face_loss_c = criterion1(out, face_targets) + head_loss_l, head_loss_c = criterion2(out, head_targets) + + face_losses += (face_loss_l + face_loss_c).item() + head_losses += (head_loss_l + head_loss_c).item() + step += 1 + + tloss = face_losses / step + + t2 = time.time() + if args.local_rank==0: + print('test Timer:{:.4f} .sec'.format(t2 - t1)) + print('epoch ' + repr(epoch) + ' || Loss:%.4f' % (tloss)) + + global min_loss + if tloss < min_loss and args.local_rank==0: + print('Saving best state,epoch', epoch) + torch.save(pyramidbox.state_dict(), os.path.join( + args.save_folder, 'pyramidbox.pth')) + min_loss = tloss + + states = { + 'epoch': epoch, + 'weight': pyramidbox.state_dict(), + } + if args.local_rank==0: + torch.save(states, os.path.join( + args.save_folder, 'pyramidbox_checkpoint.pth')) + + +def lr_warmup(optimizer,step,base_lr,warmup_steps): + if not step 0.5: - img = random_brightness(img) - img = random_contrast(img) - img = random_saturation(img) - img = random_hue(img) - else: - img = random_brightness(img) - img = random_saturation(img) - img = random_hue(img) - img = random_contrast(img) - return img - - -def meet_emit_constraint(src_bbox, sample_bbox): - center_x = (src_bbox.xmax + src_bbox.xmin) / 2 - center_y = (src_bbox.ymax + src_bbox.ymin) / 2 - if center_x >= sample_bbox.xmin and \ - center_x <= sample_bbox.xmax and \ - center_y >= sample_bbox.ymin and \ - center_y <= sample_bbox.ymax: - return True - return False - - -def project_bbox(object_bbox, sample_bbox): - if object_bbox.xmin >= sample_bbox.xmax or \ - object_bbox.xmax <= sample_bbox.xmin or \ - object_bbox.ymin >= sample_bbox.ymax or \ - object_bbox.ymax <= sample_bbox.ymin: - return False - else: - proj_bbox = bbox(0, 0, 0, 0) - sample_width = sample_bbox.xmax - sample_bbox.xmin - sample_height = sample_bbox.ymax - sample_bbox.ymin - proj_bbox.xmin = (object_bbox.xmin - sample_bbox.xmin) / sample_width - proj_bbox.ymin = (object_bbox.ymin - sample_bbox.ymin) / sample_height - proj_bbox.xmax = (object_bbox.xmax - sample_bbox.xmin) / sample_width - proj_bbox.ymax = (object_bbox.ymax - sample_bbox.ymin) / sample_height - proj_bbox = clip_bbox(proj_bbox) - if bbox_area(proj_bbox) > 0: - return proj_bbox - else: - return False - - -def transform_labels(bbox_labels, sample_bbox): - sample_labels = [] - for i in range(len(bbox_labels)): - sample_label = [] - object_bbox = bbox(bbox_labels[i][1], bbox_labels[i][2], - bbox_labels[i][3], bbox_labels[i][4]) - if not meet_emit_constraint(object_bbox, sample_bbox): - continue - proj_bbox = project_bbox(object_bbox, sample_bbox) - if proj_bbox: - sample_label.append(bbox_labels[i][0]) - sample_label.append(float(proj_bbox.xmin)) - sample_label.append(float(proj_bbox.ymin)) - sample_label.append(float(proj_bbox.xmax)) - sample_label.append(float(proj_bbox.ymax)) - sample_label = sample_label + bbox_labels[i][5:] - sample_labels.append(sample_label) - return sample_labels - - -def expand_image(img, bbox_labels, img_width, img_height): - prob = np.random.uniform(0, 1) - if prob < cfg.expand_prob: - if cfg.expand_max_ratio - 1 >= 0.01: - expand_ratio = np.random.uniform(1, cfg.expand_max_ratio) - height = int(img_height * expand_ratio) - width = int(img_width * expand_ratio) - h_off = math.floor(np.random.uniform(0, height - img_height)) - w_off = math.floor(np.random.uniform(0, width - img_width)) - expand_bbox = bbox(-w_off / img_width, -h_off / img_height, - (width - w_off) / img_width, - (height - h_off) / img_height) - expand_img = np.ones((height, width, 3)) - expand_img = np.uint8(expand_img * np.squeeze(cfg.img_mean)) - expand_img = Image.fromarray(expand_img) - expand_img.paste(img, (int(w_off), int(h_off))) - bbox_labels = transform_labels(bbox_labels, expand_bbox) - return expand_img, bbox_labels, width, height - return img, bbox_labels, img_width, img_height - - -def clip_bbox(src_bbox): - src_bbox.xmin = max(min(src_bbox.xmin, 1.0), 0.0) - src_bbox.ymin = max(min(src_bbox.ymin, 1.0), 0.0) - src_bbox.xmax = max(min(src_bbox.xmax, 1.0), 0.0) - src_bbox.ymax = max(min(src_bbox.ymax, 1.0), 0.0) - return src_bbox - - -def bbox_area(src_bbox): - if src_bbox.xmax < src_bbox.xmin or src_bbox.ymax < src_bbox.ymin: - return 0. - else: - width = src_bbox.xmax - src_bbox.xmin - height = src_bbox.ymax - src_bbox.ymin - return width * height - - -def intersect_bbox(bbox1, bbox2): - if bbox2.xmin > bbox1.xmax or bbox2.xmax < bbox1.xmin or \ - bbox2.ymin > bbox1.ymax or bbox2.ymax < bbox1.ymin: - intersection_box = bbox(0.0, 0.0, 0.0, 0.0) - else: - intersection_box = bbox( - max(bbox1.xmin, bbox2.xmin), - max(bbox1.ymin, bbox2.ymin), - min(bbox1.xmax, bbox2.xmax), min(bbox1.ymax, bbox2.ymax)) - return intersection_box - - -def bbox_coverage(bbox1, bbox2): - inter_box = intersect_bbox(bbox1, bbox2) - intersect_size = bbox_area(inter_box) - - if intersect_size > 0: - bbox1_size = bbox_area(bbox1) - return intersect_size / bbox1_size - else: - return 0. - - -def generate_batch_random_samples(batch_sampler, bbox_labels, image_width, - image_height, scale_array, resize_width, - resize_height): - sampled_bbox = [] - for sampler in batch_sampler: - found = 0 - for i in range(sampler.max_trial): - if found >= sampler.max_sample: - break - sample_bbox = data_anchor_sampling( - sampler, bbox_labels, image_width, image_height, scale_array, - resize_width, resize_height) - if sample_bbox == 0: - break - if satisfy_sample_constraint(sampler, sample_bbox, bbox_labels): - sampled_bbox.append(sample_bbox) - found = found + 1 - return sampled_bbox - - -def data_anchor_sampling(sampler, bbox_labels, image_width, image_height, - scale_array, resize_width, resize_height): - num_gt = len(bbox_labels) - # np.random.randint range: [low, high) - rand_idx = np.random.randint(0, num_gt) if num_gt != 0 else 0 - - if num_gt != 0: - norm_xmin = bbox_labels[rand_idx][1] - norm_ymin = bbox_labels[rand_idx][2] - norm_xmax = bbox_labels[rand_idx][3] - norm_ymax = bbox_labels[rand_idx][4] - - xmin = norm_xmin * image_width - ymin = norm_ymin * image_height - wid = image_width * (norm_xmax - norm_xmin) - hei = image_height * (norm_ymax - norm_ymin) - range_size = 0 - - area = wid * hei - for scale_ind in range(0, len(scale_array) - 1): - if area > scale_array[scale_ind] ** 2 and area < \ - scale_array[scale_ind + 1] ** 2: - range_size = scale_ind + 1 - break - - if area > scale_array[len(scale_array) - 2]**2: - range_size = len(scale_array) - 2 - scale_choose = 0.0 - if range_size == 0: - rand_idx_size = 0 - else: - # np.random.randint range: [low, high) - rng_rand_size = np.random.randint(0, range_size + 1) - rand_idx_size = rng_rand_size % (range_size + 1) - - if rand_idx_size == range_size: - min_resize_val = scale_array[rand_idx_size] / 2.0 - max_resize_val = min(2.0 * scale_array[rand_idx_size], - 2 * math.sqrt(wid * hei)) - scale_choose = random.uniform(min_resize_val, max_resize_val) - else: - min_resize_val = scale_array[rand_idx_size] / 2.0 - max_resize_val = 2.0 * scale_array[rand_idx_size] - scale_choose = random.uniform(min_resize_val, max_resize_val) - - sample_bbox_size = wid * resize_width / scale_choose - - w_off_orig = 0.0 - h_off_orig = 0.0 - if sample_bbox_size < max(image_height, image_width): - if wid <= sample_bbox_size: - w_off_orig = np.random.uniform(xmin + wid - sample_bbox_size, - xmin) - else: - w_off_orig = np.random.uniform(xmin, - xmin + wid - sample_bbox_size) - - if hei <= sample_bbox_size: - h_off_orig = np.random.uniform(ymin + hei - sample_bbox_size, - ymin) - else: - h_off_orig = np.random.uniform(ymin, - ymin + hei - sample_bbox_size) - - else: - w_off_orig = np.random.uniform(image_width - sample_bbox_size, 0.0) - h_off_orig = np.random.uniform( - image_height - sample_bbox_size, 0.0) - - w_off_orig = math.floor(w_off_orig) - h_off_orig = math.floor(h_off_orig) - - # Figure out top left coordinates. - w_off = 0.0 - h_off = 0.0 - w_off = float(w_off_orig / image_width) - h_off = float(h_off_orig / image_height) - - sampled_bbox = bbox(w_off, h_off, - w_off + float(sample_bbox_size / image_width), - h_off + float(sample_bbox_size / image_height)) - - return sampled_bbox - else: - return 0 - - -def jaccard_overlap(sample_bbox, object_bbox): - if sample_bbox.xmin >= object_bbox.xmax or \ - sample_bbox.xmax <= object_bbox.xmin or \ - sample_bbox.ymin >= object_bbox.ymax or \ - sample_bbox.ymax <= object_bbox.ymin: - return 0 - intersect_xmin = max(sample_bbox.xmin, object_bbox.xmin) - intersect_ymin = max(sample_bbox.ymin, object_bbox.ymin) - intersect_xmax = min(sample_bbox.xmax, object_bbox.xmax) - intersect_ymax = min(sample_bbox.ymax, object_bbox.ymax) - intersect_size = (intersect_xmax - intersect_xmin) * ( - intersect_ymax - intersect_ymin) - sample_bbox_size = bbox_area(sample_bbox) - object_bbox_size = bbox_area(object_bbox) - overlap = intersect_size / ( - sample_bbox_size + object_bbox_size - intersect_size) - return overlap - - -def satisfy_sample_constraint(sampler, sample_bbox, bbox_labels): - if sampler.min_jaccard_overlap == 0 and sampler.max_jaccard_overlap == 0: - has_jaccard_overlap = False - else: - has_jaccard_overlap = True - if sampler.min_object_coverage == 0 and sampler.max_object_coverage == 0: - has_object_coverage = False - else: - has_object_coverage = True - - if not has_jaccard_overlap and not has_object_coverage: - return True - found = False - for i in range(len(bbox_labels)): - object_bbox = bbox(bbox_labels[i][1], bbox_labels[i][2], - bbox_labels[i][3], bbox_labels[i][4]) - if has_jaccard_overlap: - overlap = jaccard_overlap(sample_bbox, object_bbox) - if sampler.min_jaccard_overlap != 0 and \ - overlap < sampler.min_jaccard_overlap: - continue - if sampler.max_jaccard_overlap != 0 and \ - overlap > sampler.max_jaccard_overlap: - continue - found = True - if has_object_coverage: - object_coverage = bbox_coverage(object_bbox, sample_bbox) - if sampler.min_object_coverage != 0 and \ - object_coverage < sampler.min_object_coverage: - continue - if sampler.max_object_coverage != 0 and \ - object_coverage > sampler.max_object_coverage: - continue - found = True - if found: - return True - return found - - -def crop_image_sampling(img, bbox_labels, sample_bbox, image_width, - image_height, resize_width, resize_height, - min_face_size): - # no clipping here - xmin = int(sample_bbox.xmin * image_width) - xmax = int(sample_bbox.xmax * image_width) - ymin = int(sample_bbox.ymin * image_height) - ymax = int(sample_bbox.ymax * image_height) - w_off = xmin - h_off = ymin - width = xmax - xmin - height = ymax - ymin - - cross_xmin = max(0.0, float(w_off)) - cross_ymin = max(0.0, float(h_off)) - cross_xmax = min(float(w_off + width - 1.0), float(image_width)) - cross_ymax = min(float(h_off + height - 1.0), float(image_height)) - cross_width = cross_xmax - cross_xmin - cross_height = cross_ymax - cross_ymin - - roi_xmin = 0 if w_off >= 0 else abs(w_off) - roi_ymin = 0 if h_off >= 0 else abs(h_off) - roi_width = cross_width - roi_height = cross_height - - roi_y1 = int(roi_ymin) - roi_y2 = int(roi_ymin + roi_height) - roi_x1 = int(roi_xmin) - roi_x2 = int(roi_xmin + roi_width) - - cross_y1 = int(cross_ymin) - cross_y2 = int(cross_ymin + cross_height) - cross_x1 = int(cross_xmin) - cross_x2 = int(cross_xmin + cross_width) - - sample_img = np.zeros((height, width, 3)) - # print(sample_img.shape) - sample_img[roi_y1 : roi_y2, roi_x1 : roi_x2] = \ - img[cross_y1: cross_y2, cross_x1: cross_x2] - sample_img = cv2.resize( - sample_img, (resize_width, resize_height), interpolation=cv2.INTER_AREA) - - resize_val = resize_width - sample_labels = transform_labels_sampling(bbox_labels, sample_bbox, - resize_val, min_face_size) - return sample_img, sample_labels - - -def transform_labels_sampling(bbox_labels, sample_bbox, resize_val, - min_face_size): - sample_labels = [] - for i in range(len(bbox_labels)): - sample_label = [] - object_bbox = bbox(bbox_labels[i][1], bbox_labels[i][2], - bbox_labels[i][3], bbox_labels[i][4]) - if not meet_emit_constraint(object_bbox, sample_bbox): - continue - proj_bbox = project_bbox(object_bbox, sample_bbox) - if proj_bbox: - real_width = float((proj_bbox.xmax - proj_bbox.xmin) * resize_val) - real_height = float((proj_bbox.ymax - proj_bbox.ymin) * resize_val) - if real_width * real_height < float(min_face_size * min_face_size): - continue - else: - sample_label.append(bbox_labels[i][0]) - sample_label.append(float(proj_bbox.xmin)) - sample_label.append(float(proj_bbox.ymin)) - sample_label.append(float(proj_bbox.xmax)) - sample_label.append(float(proj_bbox.ymax)) - sample_label = sample_label + bbox_labels[i][5:] - sample_labels.append(sample_label) - - return sample_labels - - -def generate_sample(sampler, image_width, image_height): - scale = np.random.uniform(sampler.min_scale, sampler.max_scale) - aspect_ratio = np.random.uniform(sampler.min_aspect_ratio, - sampler.max_aspect_ratio) - aspect_ratio = max(aspect_ratio, (scale**2.0)) - aspect_ratio = min(aspect_ratio, 1 / (scale**2.0)) - - bbox_width = scale * (aspect_ratio**0.5) - bbox_height = scale / (aspect_ratio**0.5) - - # guarantee a squared image patch after cropping - if sampler.use_square: - if image_height < image_width: - bbox_width = bbox_height * image_height / image_width - else: - bbox_height = bbox_width * image_width / image_height - - xmin_bound = 1 - bbox_width - ymin_bound = 1 - bbox_height - xmin = np.random.uniform(0, xmin_bound) - ymin = np.random.uniform(0, ymin_bound) - xmax = xmin + bbox_width - ymax = ymin + bbox_height - sampled_bbox = bbox(xmin, ymin, xmax, ymax) - return sampled_bbox - - -def generate_batch_samples(batch_sampler, bbox_labels, image_width, - image_height): - sampled_bbox = [] - for sampler in batch_sampler: - found = 0 - for i in range(sampler.max_trial): - if found >= sampler.max_sample: - break - sample_bbox = generate_sample(sampler, image_width, image_height) - if satisfy_sample_constraint(sampler, sample_bbox, bbox_labels): - sampled_bbox.append(sample_bbox) - found = found + 1 - return sampled_bbox - - -def crop_image(img, bbox_labels, sample_bbox, image_width, image_height, - resize_width, resize_height, min_face_size): - sample_bbox = clip_bbox(sample_bbox) - xmin = int(sample_bbox.xmin * image_width) - xmax = int(sample_bbox.xmax * image_width) - ymin = int(sample_bbox.ymin * image_height) - ymax = int(sample_bbox.ymax * image_height) - - sample_img = img[ymin:ymax, xmin:xmax] - resize_val = resize_width - sample_labels = transform_labels_sampling(bbox_labels, sample_bbox, - resize_val, min_face_size) - return sample_img, sample_labels - - -def to_chw_bgr(image): - """ - Transpose image from HWC to CHW and from RBG to BGR. - Args: - image (np.array): an image with HWC and RBG layout. - """ - # HWC to CHW - if len(image.shape) == 3: - image = np.swapaxes(image, 1, 2) - image = np.swapaxes(image, 1, 0) - # RBG to BGR - image = image[[2, 1, 0], :, :] - return image - - -def anchor_crop_image_sampling(img, - bbox_labels, - scale_array, - img_width, - img_height): - mean = np.array([104, 117, 123], dtype=np.float32) - maxSize = 12000 # max size - infDistance = 9999999 - bbox_labels = np.array(bbox_labels) - scale = np.array([img_width, img_height, img_width, img_height]) - - boxes = bbox_labels[:, 1:5] * scale - labels = bbox_labels[:, 0] - - boxArea = (boxes[:, 2] - boxes[:, 0] + 1) * (boxes[:, 3] - boxes[:, 1] + 1) - # argsort = np.argsort(boxArea) - # rand_idx = random.randint(min(len(argsort),6)) - # print('rand idx',rand_idx) - rand_idx = np.random.randint(len(boxArea)) - rand_Side = boxArea[rand_idx] ** 0.5 - # rand_Side = min(boxes[rand_idx,2] - boxes[rand_idx,0] + 1, - # boxes[rand_idx,3] - boxes[rand_idx,1] + 1) - - distance = infDistance - anchor_idx = 5 - for i, anchor in enumerate(scale_array): - if abs(anchor - rand_Side) < distance: - distance = abs(anchor - rand_Side) - anchor_idx = i - - target_anchor = random.choice(scale_array[0:min(anchor_idx + 1, 5) + 1]) - ratio = float(target_anchor) / rand_Side - ratio = ratio * (2**random.uniform(-1, 1)) - - if int(img_height * ratio * img_width * ratio) > maxSize * maxSize: - ratio = (maxSize * maxSize / (img_height * img_width))**0.5 - - interp_methods = [cv2.INTER_LINEAR, cv2.INTER_CUBIC, - cv2.INTER_AREA, cv2.INTER_NEAREST, cv2.INTER_LANCZOS4] - interp_method = random.choice(interp_methods) - image = cv2.resize(img, None, None, fx=ratio, - fy=ratio, interpolation=interp_method) - - boxes[:, 0] *= ratio - boxes[:, 1] *= ratio - boxes[:, 2] *= ratio - boxes[:, 3] *= ratio - - height, width, _ = image.shape - - sample_boxes = [] - - xmin = boxes[rand_idx, 0] - ymin = boxes[rand_idx, 1] - bw = (boxes[rand_idx, 2] - boxes[rand_idx, 0] + 1) - bh = (boxes[rand_idx, 3] - boxes[rand_idx, 1] + 1) - - w = h = 640 - - for _ in range(50): - if w < max(height, width): - if bw <= w: - w_off = random.uniform(xmin + bw - w, xmin) - else: - w_off = random.uniform(xmin, xmin + bw - w) - - if bh <= h: - h_off = random.uniform(ymin + bh - h, ymin) - else: - h_off = random.uniform(ymin, ymin + bh - h) - else: - w_off = random.uniform(width - w, 0) - h_off = random.uniform(height - h, 0) - - w_off = math.floor(w_off) - h_off = math.floor(h_off) - - # convert to integer rect x1,y1,x2,y2 - rect = np.array( - [int(w_off), int(h_off), int(w_off + w), int(h_off + h)]) - - # keep overlap with gt box IF center in sampled patch - centers = (boxes[:, :2] + boxes[:, 2:]) / 2.0 - # mask in all gt boxes that above and to the left of centers - m1 = (rect[0] <= boxes[:, 0]) * (rect[1] <= boxes[:, 1]) - # mask in all gt boxes that under and to the right of centers - m2 = (rect[2] >= boxes[:, 2]) * (rect[3] >= boxes[:, 3]) - # mask in that both m1 and m2 are true - mask = m1 * m2 - - overlap = jaccard_numpy(boxes, rect) - # have any valid boxes? try again if not - if not mask.any() and not overlap.max() > 0.7: - continue - else: - sample_boxes.append(rect) - - sampled_labels = [] - - if len(sample_boxes) > 0: - choice_idx = np.random.randint(len(sample_boxes)) - choice_box = sample_boxes[choice_idx] - # print('crop the box :',choice_box) - centers = (boxes[:, :2] + boxes[:, 2:]) / 2.0 - m1 = (choice_box[0] < centers[:, 0]) * \ - (choice_box[1] < centers[:, 1]) - m2 = (choice_box[2] > centers[:, 0]) * \ - (choice_box[3] > centers[:, 1]) - mask = m1 * m2 - current_boxes = boxes[mask, :].copy() - current_labels = labels[mask] - current_boxes[:, :2] -= choice_box[:2] - current_boxes[:, 2:] -= choice_box[:2] - - if choice_box[0] < 0 or choice_box[1] < 0: - new_img_width = width if choice_box[ - 0] >= 0 else width - choice_box[0] - new_img_height = height if choice_box[ - 1] >= 0 else height - choice_box[1] - image_pad = np.zeros( - (new_img_height, new_img_width, 3), dtype=float) - image_pad[:, :, :] = mean - start_left = 0 if choice_box[0] >= 0 else -choice_box[0] - start_top = 0 if choice_box[1] >= 0 else -choice_box[1] - image_pad[start_top:, start_left:, :] = image - - choice_box_w = choice_box[2] - choice_box[0] - choice_box_h = choice_box[3] - choice_box[1] - - start_left = choice_box[0] if choice_box[0] >= 0 else 0 - start_top = choice_box[1] if choice_box[1] >= 0 else 0 - end_right = start_left + choice_box_w - end_bottom = start_top + choice_box_h - current_image = image_pad[ - start_top:end_bottom, start_left:end_right, :].copy() - image_height, image_width, _ = current_image.shape - if cfg.filter_min_face: - bbox_w = current_boxes[:, 2] - current_boxes[:, 0] - bbox_h = current_boxes[:, 3] - current_boxes[:, 1] - bbox_area = bbox_w * bbox_h - mask = bbox_area > (cfg.min_face_size * cfg.min_face_size) - current_boxes = current_boxes[mask] - current_labels = current_labels[mask] - for i in range(len(current_boxes)): - sample_label = [] - sample_label.append(current_labels[i]) - sample_label.append(current_boxes[i][0] / image_width) - sample_label.append(current_boxes[i][1] / image_height) - sample_label.append(current_boxes[i][2] / image_width) - sample_label.append(current_boxes[i][3] / image_height) - sampled_labels += [sample_label] - sampled_labels = np.array(sampled_labels) - else: - current_boxes /= np.array([image_width, - image_height, image_width, image_height]) - sampled_labels = np.hstack( - (current_labels[:, np.newaxis], current_boxes)) - - return current_image, sampled_labels - - current_image = image[choice_box[1]:choice_box[ - 3], choice_box[0]:choice_box[2], :].copy() - image_height, image_width, _ = current_image.shape - - if cfg.filter_min_face: - bbox_w = current_boxes[:, 2] - current_boxes[:, 0] - bbox_h = current_boxes[:, 3] - current_boxes[:, 1] - bbox_area = bbox_w * bbox_h - mask = bbox_area > (cfg.min_face_size * cfg.min_face_size) - current_boxes = current_boxes[mask] - current_labels = current_labels[mask] - for i in range(len(current_boxes)): - sample_label = [] - sample_label.append(current_labels[i]) - sample_label.append(current_boxes[i][0] / image_width) - sample_label.append(current_boxes[i][1] / image_height) - sample_label.append(current_boxes[i][2] / image_width) - sample_label.append(current_boxes[i][3] / image_height) - sampled_labels += [sample_label] - sampled_labels = np.array(sampled_labels) - else: - current_boxes /= np.array([image_width, - image_height, image_width, image_height]) - sampled_labels = np.hstack( - (current_labels[:, np.newaxis], current_boxes)) - - return current_image, sampled_labels - else: - image_height, image_width, _ = image.shape - if cfg.filter_min_face: - bbox_w = boxes[:, 2] - boxes[:, 0] - bbox_h = boxes[:, 3] - boxes[:, 1] - bbox_area = bbox_w * bbox_h - mask = bbox_area > (cfg.min_face_size * cfg.min_face_size) - boxes = boxes[mask] - labels = labels[mask] - for i in range(len(boxes)): - sample_label = [] - sample_label.append(labels[i]) - sample_label.append(boxes[i][0] / image_width) - sample_label.append(boxes[i][1] / image_height) - sample_label.append(boxes[i][2] / image_width) - sample_label.append(boxes[i][3] / image_height) - sampled_labels += [sample_label] - sampled_labels = np.array(sampled_labels) - else: - boxes /= np.array([image_width, image_height, - image_width, image_height]) - sampled_labels = np.hstack( - (labels[:, np.newaxis], boxes)) - - return image, sampled_labels - - -def preprocess(img, bbox_labels, mode, image_path): - img_width, img_height = img.size - sampled_labels = bbox_labels - if mode == 'train': - if cfg.apply_distort: - img = distort_image(img) - if cfg.apply_expand: - img, bbox_labels, img_width, img_height = expand_image( - img, bbox_labels, img_width, img_height) - - batch_sampler = [] - prob = np.random.uniform(0., 1.) - if prob > cfg.data_anchor_sampling_prob and cfg.anchor_sampling: - scale_array = np.array([16, 32, 64, 128, 256, 512]) - ''' - batch_sampler.append( - sampler(1, 50, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.6, 0.0, True)) - sampled_bbox = generate_batch_random_samples( - batch_sampler, bbox_labels, img_width, img_height, scale_array, - cfg.resize_width, cfg.resize_height) - ''' - img = np.array(img) - img, sampled_labels = anchor_crop_image_sampling( - img, bbox_labels, scale_array, img_width, img_height) - ''' - if len(sampled_bbox) > 0: - idx = int(np.random.uniform(0, len(sampled_bbox))) - img, sampled_labels = crop_image_sampling( - img, bbox_labels, sampled_bbox[idx], img_width, img_height, - cfg.resize_width, cfg.resize_height, cfg.min_face_size) - ''' - img = img.astype('uint8') - img = Image.fromarray(img) - else: - batch_sampler.append(sampler(1, 50, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, - 0.0, True)) - batch_sampler.append(sampler(1, 50, 0.3, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, - 0.0, True)) - batch_sampler.append(sampler(1, 50, 0.3, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, - 0.0, True)) - batch_sampler.append(sampler(1, 50, 0.3, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, - 0.0, True)) - batch_sampler.append(sampler(1, 50, 0.3, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, - 0.0, True)) - sampled_bbox = generate_batch_samples( - batch_sampler, bbox_labels, img_width, img_height) - - img = np.array(img) - if len(sampled_bbox) > 0: - idx = int(np.random.uniform(0, len(sampled_bbox))) - img, sampled_labels = crop_image( - img, bbox_labels, sampled_bbox[idx], img_width, img_height, - cfg.resize_width, cfg.resize_height, cfg.min_face_size) - - img = Image.fromarray(img) - - interp_mode = [ - Image.BILINEAR, Image.HAMMING, Image.NEAREST, Image.BICUBIC, - Image.LANCZOS - ] - interp_indx = np.random.randint(0, 5) - - img = img.resize((cfg.resize_width, cfg.resize_height), - resample=interp_mode[interp_indx]) - - img = np.array(img) - - if mode == 'train': - mirror = int(np.random.uniform(0, 2)) - if mirror == 1: - img = img[:, ::-1, :] - for i in six.moves.xrange(len(sampled_labels)): - tmp = sampled_labels[i][1] - sampled_labels[i][1] = 1 - sampled_labels[i][3] - sampled_labels[i][3] = 1 - tmp - - #img = Image.fromarray(img) - img = to_chw_bgr(img) - img = img.astype('float32') - img -= cfg.img_mean - img = img[[2, 1, 0], :, :] # to RGB - #img = img * cfg.scale - - return img, sampled_labels +#-*- coding:utf-8 -*- +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +from torchvision import transforms +import cv2 +import numpy as np +import types +from PIL import Image, ImageEnhance, ImageDraw +import math +import six +from data.config import cfg +import random + + +class sampler(): + + def __init__(self, + max_sample, + max_trial, + min_scale, + max_scale, + min_aspect_ratio, + max_aspect_ratio, + min_jaccard_overlap, + max_jaccard_overlap, + min_object_coverage, + max_object_coverage, + use_square=False): + self.max_sample = max_sample + self.max_trial = max_trial + self.min_scale = min_scale + self.max_scale = max_scale + self.min_aspect_ratio = min_aspect_ratio + self.max_aspect_ratio = max_aspect_ratio + self.min_jaccard_overlap = min_jaccard_overlap + self.max_jaccard_overlap = max_jaccard_overlap + self.min_object_coverage = min_object_coverage + self.max_object_coverage = max_object_coverage + self.use_square = use_square + + +def intersect(box_a, box_b): + max_xy = np.minimum(box_a[:, 2:], box_b[2:]) + min_xy = np.maximum(box_a[:, :2], box_b[:2]) + inter = np.clip((max_xy - min_xy), a_min=0, a_max=np.inf) + return inter[:, 0] * inter[:, 1] + + +def jaccard_numpy(box_a, box_b): + """Compute the jaccard overlap of two sets of boxes. The jaccard overlap + is simply the intersection over union of two boxes. + E.g.: + A ∩ B / A ∪ B = A ∩ B / (area(A) + area(B) - A ∩ B) + Args: + box_a: Multiple bounding boxes, Shape: [num_boxes,4] + box_b: Single bounding box, Shape: [4] + Return: + jaccard overlap: Shape: [box_a.shape[0], box_a.shape[1]] + """ + inter = intersect(box_a, box_b) + area_a = ((box_a[:, 2] - box_a[:, 0]) * + (box_a[:, 3] - box_a[:, 1])) # [A,B] + area_b = ((box_b[2] - box_b[0]) * + (box_b[3] - box_b[1])) # [A,B] + union = area_a + area_b - inter + return inter / union # [A,B] + + +class bbox(): + + def __init__(self, xmin, ymin, xmax, ymax): + self.xmin = xmin + self.ymin = ymin + self.xmax = xmax + self.ymax = ymax + + +def random_brightness(img): + prob = np.random.uniform(0, 1) + if prob < cfg.brightness_prob: + delta = np.random.uniform(-cfg.brightness_delta, + cfg.brightness_delta) + 1 + img = ImageEnhance.Brightness(img).enhance(delta) + return img + + +def random_contrast(img): + prob = np.random.uniform(0, 1) + if prob < cfg.contrast_prob: + delta = np.random.uniform(-cfg.contrast_delta, + cfg.contrast_delta) + 1 + img = ImageEnhance.Contrast(img).enhance(delta) + return img + + +def random_saturation(img): + prob = np.random.uniform(0, 1) + if prob < cfg.saturation_prob: + delta = np.random.uniform(-cfg.saturation_delta, + cfg.saturation_delta) + 1 + img = ImageEnhance.Color(img).enhance(delta) + return img + + +def random_hue(img): + prob = np.random.uniform(0, 1) + if prob < cfg.hue_prob: + delta = np.random.uniform(-cfg.hue_delta, cfg.hue_delta) + img_hsv = np.array(img.convert('HSV')) + img_hsv[:, :, 0] = img_hsv[:, :, 0] + delta + img = Image.fromarray(img_hsv, mode='HSV').convert('RGB') + return img + + +def distort_image(img): + prob = np.random.uniform(0, 1) + # Apply different distort order + if prob > 0.5: + img = random_brightness(img) + img = random_contrast(img) + img = random_saturation(img) + img = random_hue(img) + else: + img = random_brightness(img) + img = random_saturation(img) + img = random_hue(img) + img = random_contrast(img) + return img + + +def meet_emit_constraint(src_bbox, sample_bbox): + center_x = (src_bbox.xmax + src_bbox.xmin) / 2 + center_y = (src_bbox.ymax + src_bbox.ymin) / 2 + if center_x >= sample_bbox.xmin and \ + center_x <= sample_bbox.xmax and \ + center_y >= sample_bbox.ymin and \ + center_y <= sample_bbox.ymax: + return True + return False + + +def project_bbox(object_bbox, sample_bbox): + if object_bbox.xmin >= sample_bbox.xmax or \ + object_bbox.xmax <= sample_bbox.xmin or \ + object_bbox.ymin >= sample_bbox.ymax or \ + object_bbox.ymax <= sample_bbox.ymin: + return False + else: + proj_bbox = bbox(0, 0, 0, 0) + sample_width = sample_bbox.xmax - sample_bbox.xmin + sample_height = sample_bbox.ymax - sample_bbox.ymin + proj_bbox.xmin = (object_bbox.xmin - sample_bbox.xmin) / sample_width + proj_bbox.ymin = (object_bbox.ymin - sample_bbox.ymin) / sample_height + proj_bbox.xmax = (object_bbox.xmax - sample_bbox.xmin) / sample_width + proj_bbox.ymax = (object_bbox.ymax - sample_bbox.ymin) / sample_height + proj_bbox = clip_bbox(proj_bbox) + if bbox_area(proj_bbox) > 0: + return proj_bbox + else: + return False + + +def transform_labels(bbox_labels, sample_bbox): + sample_labels = [] + for i in range(len(bbox_labels)): + sample_label = [] + object_bbox = bbox(bbox_labels[i][1], bbox_labels[i][2], + bbox_labels[i][3], bbox_labels[i][4]) + if not meet_emit_constraint(object_bbox, sample_bbox): + continue + proj_bbox = project_bbox(object_bbox, sample_bbox) + if proj_bbox: + sample_label.append(bbox_labels[i][0]) + sample_label.append(float(proj_bbox.xmin)) + sample_label.append(float(proj_bbox.ymin)) + sample_label.append(float(proj_bbox.xmax)) + sample_label.append(float(proj_bbox.ymax)) + sample_label = sample_label + bbox_labels[i][5:] + sample_labels.append(sample_label) + return sample_labels + + +def expand_image(img, bbox_labels, img_width, img_height): + prob = np.random.uniform(0, 1) + if prob < cfg.expand_prob: + if cfg.expand_max_ratio - 1 >= 0.01: + expand_ratio = np.random.uniform(1, cfg.expand_max_ratio) + height = int(img_height * expand_ratio) + width = int(img_width * expand_ratio) + h_off = math.floor(np.random.uniform(0, height - img_height)) + w_off = math.floor(np.random.uniform(0, width - img_width)) + expand_bbox = bbox(-w_off / img_width, -h_off / img_height, + (width - w_off) / img_width, + (height - h_off) / img_height) + expand_img = np.ones((height, width, 3)) + expand_img = np.uint8(expand_img * np.squeeze(cfg.img_mean)) + expand_img = Image.fromarray(expand_img) + expand_img.paste(img, (int(w_off), int(h_off))) + bbox_labels = transform_labels(bbox_labels, expand_bbox) + return expand_img, bbox_labels, width, height + return img, bbox_labels, img_width, img_height + + +def clip_bbox(src_bbox): + src_bbox.xmin = max(min(src_bbox.xmin, 1.0), 0.0) + src_bbox.ymin = max(min(src_bbox.ymin, 1.0), 0.0) + src_bbox.xmax = max(min(src_bbox.xmax, 1.0), 0.0) + src_bbox.ymax = max(min(src_bbox.ymax, 1.0), 0.0) + return src_bbox + + +def bbox_area(src_bbox): + if src_bbox.xmax < src_bbox.xmin or src_bbox.ymax < src_bbox.ymin: + return 0. + else: + width = src_bbox.xmax - src_bbox.xmin + height = src_bbox.ymax - src_bbox.ymin + return width * height + + +def intersect_bbox(bbox1, bbox2): + if bbox2.xmin > bbox1.xmax or bbox2.xmax < bbox1.xmin or \ + bbox2.ymin > bbox1.ymax or bbox2.ymax < bbox1.ymin: + intersection_box = bbox(0.0, 0.0, 0.0, 0.0) + else: + intersection_box = bbox( + max(bbox1.xmin, bbox2.xmin), + max(bbox1.ymin, bbox2.ymin), + min(bbox1.xmax, bbox2.xmax), min(bbox1.ymax, bbox2.ymax)) + return intersection_box + + +def bbox_coverage(bbox1, bbox2): + inter_box = intersect_bbox(bbox1, bbox2) + intersect_size = bbox_area(inter_box) + + if intersect_size > 0: + bbox1_size = bbox_area(bbox1) + return intersect_size / bbox1_size + else: + return 0. + + +def generate_batch_random_samples(batch_sampler, bbox_labels, image_width, + image_height, scale_array, resize_width, + resize_height): + sampled_bbox = [] + for sampler in batch_sampler: + found = 0 + for i in range(sampler.max_trial): + if found >= sampler.max_sample: + break + sample_bbox = data_anchor_sampling( + sampler, bbox_labels, image_width, image_height, scale_array, + resize_width, resize_height) + if sample_bbox == 0: + break + if satisfy_sample_constraint(sampler, sample_bbox, bbox_labels): + sampled_bbox.append(sample_bbox) + found = found + 1 + return sampled_bbox + + +def data_anchor_sampling(sampler, bbox_labels, image_width, image_height, + scale_array, resize_width, resize_height): + num_gt = len(bbox_labels) + # np.random.randint range: [low, high) + rand_idx = np.random.randint(0, num_gt) if num_gt != 0 else 0 + + if num_gt != 0: + norm_xmin = bbox_labels[rand_idx][1] + norm_ymin = bbox_labels[rand_idx][2] + norm_xmax = bbox_labels[rand_idx][3] + norm_ymax = bbox_labels[rand_idx][4] + + xmin = norm_xmin * image_width + ymin = norm_ymin * image_height + wid = image_width * (norm_xmax - norm_xmin) + hei = image_height * (norm_ymax - norm_ymin) + range_size = 0 + + area = wid * hei + for scale_ind in range(0, len(scale_array) - 1): + if area > scale_array[scale_ind] ** 2 and area < \ + scale_array[scale_ind + 1] ** 2: + range_size = scale_ind + 1 + break + + if area > scale_array[len(scale_array) - 2]**2: + range_size = len(scale_array) - 2 + scale_choose = 0.0 + if range_size == 0: + rand_idx_size = 0 + else: + # np.random.randint range: [low, high) + rng_rand_size = np.random.randint(0, range_size + 1) + rand_idx_size = rng_rand_size % (range_size + 1) + + if rand_idx_size == range_size: + min_resize_val = scale_array[rand_idx_size] / 2.0 + max_resize_val = min(2.0 * scale_array[rand_idx_size], + 2 * math.sqrt(wid * hei)) + scale_choose = random.uniform(min_resize_val, max_resize_val) + else: + min_resize_val = scale_array[rand_idx_size] / 2.0 + max_resize_val = 2.0 * scale_array[rand_idx_size] + scale_choose = random.uniform(min_resize_val, max_resize_val) + + sample_bbox_size = wid * resize_width / scale_choose + + w_off_orig = 0.0 + h_off_orig = 0.0 + if sample_bbox_size < max(image_height, image_width): + if wid <= sample_bbox_size: + w_off_orig = np.random.uniform(xmin + wid - sample_bbox_size, + xmin) + else: + w_off_orig = np.random.uniform(xmin, + xmin + wid - sample_bbox_size) + + if hei <= sample_bbox_size: + h_off_orig = np.random.uniform(ymin + hei - sample_bbox_size, + ymin) + else: + h_off_orig = np.random.uniform(ymin, + ymin + hei - sample_bbox_size) + + else: + w_off_orig = np.random.uniform(image_width - sample_bbox_size, 0.0) + h_off_orig = np.random.uniform( + image_height - sample_bbox_size, 0.0) + + w_off_orig = math.floor(w_off_orig) + h_off_orig = math.floor(h_off_orig) + + # Figure out top left coordinates. + w_off = 0.0 + h_off = 0.0 + w_off = float(w_off_orig / image_width) + h_off = float(h_off_orig / image_height) + + sampled_bbox = bbox(w_off, h_off, + w_off + float(sample_bbox_size / image_width), + h_off + float(sample_bbox_size / image_height)) + + return sampled_bbox + else: + return 0 + + +def jaccard_overlap(sample_bbox, object_bbox): + if sample_bbox.xmin >= object_bbox.xmax or \ + sample_bbox.xmax <= object_bbox.xmin or \ + sample_bbox.ymin >= object_bbox.ymax or \ + sample_bbox.ymax <= object_bbox.ymin: + return 0 + intersect_xmin = max(sample_bbox.xmin, object_bbox.xmin) + intersect_ymin = max(sample_bbox.ymin, object_bbox.ymin) + intersect_xmax = min(sample_bbox.xmax, object_bbox.xmax) + intersect_ymax = min(sample_bbox.ymax, object_bbox.ymax) + intersect_size = (intersect_xmax - intersect_xmin) * ( + intersect_ymax - intersect_ymin) + sample_bbox_size = bbox_area(sample_bbox) + object_bbox_size = bbox_area(object_bbox) + overlap = intersect_size / ( + sample_bbox_size + object_bbox_size - intersect_size) + return overlap + + +def satisfy_sample_constraint(sampler, sample_bbox, bbox_labels): + if sampler.min_jaccard_overlap == 0 and sampler.max_jaccard_overlap == 0: + has_jaccard_overlap = False + else: + has_jaccard_overlap = True + if sampler.min_object_coverage == 0 and sampler.max_object_coverage == 0: + has_object_coverage = False + else: + has_object_coverage = True + + if not has_jaccard_overlap and not has_object_coverage: + return True + found = False + for i in range(len(bbox_labels)): + object_bbox = bbox(bbox_labels[i][1], bbox_labels[i][2], + bbox_labels[i][3], bbox_labels[i][4]) + if has_jaccard_overlap: + overlap = jaccard_overlap(sample_bbox, object_bbox) + if sampler.min_jaccard_overlap != 0 and \ + overlap < sampler.min_jaccard_overlap: + continue + if sampler.max_jaccard_overlap != 0 and \ + overlap > sampler.max_jaccard_overlap: + continue + found = True + if has_object_coverage: + object_coverage = bbox_coverage(object_bbox, sample_bbox) + if sampler.min_object_coverage != 0 and \ + object_coverage < sampler.min_object_coverage: + continue + if sampler.max_object_coverage != 0 and \ + object_coverage > sampler.max_object_coverage: + continue + found = True + if found: + return True + return found + + +def crop_image_sampling(img, bbox_labels, sample_bbox, image_width, + image_height, resize_width, resize_height, + min_face_size): + # no clipping here + xmin = int(sample_bbox.xmin * image_width) + xmax = int(sample_bbox.xmax * image_width) + ymin = int(sample_bbox.ymin * image_height) + ymax = int(sample_bbox.ymax * image_height) + w_off = xmin + h_off = ymin + width = xmax - xmin + height = ymax - ymin + + cross_xmin = max(0.0, float(w_off)) + cross_ymin = max(0.0, float(h_off)) + cross_xmax = min(float(w_off + width - 1.0), float(image_width)) + cross_ymax = min(float(h_off + height - 1.0), float(image_height)) + cross_width = cross_xmax - cross_xmin + cross_height = cross_ymax - cross_ymin + + roi_xmin = 0 if w_off >= 0 else abs(w_off) + roi_ymin = 0 if h_off >= 0 else abs(h_off) + roi_width = cross_width + roi_height = cross_height + + roi_y1 = int(roi_ymin) + roi_y2 = int(roi_ymin + roi_height) + roi_x1 = int(roi_xmin) + roi_x2 = int(roi_xmin + roi_width) + + cross_y1 = int(cross_ymin) + cross_y2 = int(cross_ymin + cross_height) + cross_x1 = int(cross_xmin) + cross_x2 = int(cross_xmin + cross_width) + + sample_img = np.zeros((height, width, 3)) + # print(sample_img.shape) + sample_img[roi_y1 : roi_y2, roi_x1 : roi_x2] = \ + img[cross_y1: cross_y2, cross_x1: cross_x2] + sample_img = cv2.resize( + sample_img, (resize_width, resize_height), interpolation=cv2.INTER_AREA) + + resize_val = resize_width + sample_labels = transform_labels_sampling(bbox_labels, sample_bbox, + resize_val, min_face_size) + return sample_img, sample_labels + + +def transform_labels_sampling(bbox_labels, sample_bbox, resize_val, + min_face_size): + sample_labels = [] + for i in range(len(bbox_labels)): + sample_label = [] + object_bbox = bbox(bbox_labels[i][1], bbox_labels[i][2], + bbox_labels[i][3], bbox_labels[i][4]) + if not meet_emit_constraint(object_bbox, sample_bbox): + continue + proj_bbox = project_bbox(object_bbox, sample_bbox) + if proj_bbox: + real_width = float((proj_bbox.xmax - proj_bbox.xmin) * resize_val) + real_height = float((proj_bbox.ymax - proj_bbox.ymin) * resize_val) + if real_width * real_height < float(min_face_size * min_face_size): + continue + else: + sample_label.append(bbox_labels[i][0]) + sample_label.append(float(proj_bbox.xmin)) + sample_label.append(float(proj_bbox.ymin)) + sample_label.append(float(proj_bbox.xmax)) + sample_label.append(float(proj_bbox.ymax)) + sample_label = sample_label + bbox_labels[i][5:] + sample_labels.append(sample_label) + + return sample_labels + + +def generate_sample(sampler, image_width, image_height): + scale = np.random.uniform(sampler.min_scale, sampler.max_scale) + aspect_ratio = np.random.uniform(sampler.min_aspect_ratio, + sampler.max_aspect_ratio) + aspect_ratio = max(aspect_ratio, (scale**2.0)) + aspect_ratio = min(aspect_ratio, 1 / (scale**2.0)) + + bbox_width = scale * (aspect_ratio**0.5) + bbox_height = scale / (aspect_ratio**0.5) + + # guarantee a squared image patch after cropping + if sampler.use_square: + if image_height < image_width: + bbox_width = bbox_height * image_height / image_width + else: + bbox_height = bbox_width * image_width / image_height + + xmin_bound = 1 - bbox_width + ymin_bound = 1 - bbox_height + xmin = np.random.uniform(0, xmin_bound) + ymin = np.random.uniform(0, ymin_bound) + xmax = xmin + bbox_width + ymax = ymin + bbox_height + sampled_bbox = bbox(xmin, ymin, xmax, ymax) + return sampled_bbox + + +def generate_batch_samples(batch_sampler, bbox_labels, image_width, + image_height): + sampled_bbox = [] + for sampler in batch_sampler: + found = 0 + for i in range(sampler.max_trial): + if found >= sampler.max_sample: + break + sample_bbox = generate_sample(sampler, image_width, image_height) + if satisfy_sample_constraint(sampler, sample_bbox, bbox_labels): + sampled_bbox.append(sample_bbox) + found = found + 1 + return sampled_bbox + + +def crop_image(img, bbox_labels, sample_bbox, image_width, image_height, + resize_width, resize_height, min_face_size): + sample_bbox = clip_bbox(sample_bbox) + xmin = int(sample_bbox.xmin * image_width) + xmax = int(sample_bbox.xmax * image_width) + ymin = int(sample_bbox.ymin * image_height) + ymax = int(sample_bbox.ymax * image_height) + + sample_img = img[ymin:ymax, xmin:xmax] + resize_val = resize_width + sample_labels = transform_labels_sampling(bbox_labels, sample_bbox, + resize_val, min_face_size) + return sample_img, sample_labels + + +def to_chw_bgr(image): + """ + Transpose image from HWC to CHW and from RBG to BGR. + Args: + image (np.array): an image with HWC and RBG layout. + """ + # HWC to CHW + if len(image.shape) == 3: + image = np.swapaxes(image, 1, 2) + image = np.swapaxes(image, 1, 0) + # RBG to BGR + image = image[[2, 1, 0], :, :] + return image + + +def anchor_crop_image_sampling(img, + bbox_labels, + scale_array, + img_width, + img_height): + mean = np.array([104, 117, 123], dtype=np.float32) + maxSize = 12000 # max size + infDistance = 9999999 + bbox_labels = np.array(bbox_labels) + scale = np.array([img_width, img_height, img_width, img_height]) + + boxes = bbox_labels[:, 1:5] * scale + labels = bbox_labels[:, 0] + + boxArea = (boxes[:, 2] - boxes[:, 0] + 1) * (boxes[:, 3] - boxes[:, 1] + 1) + # argsort = np.argsort(boxArea) + # rand_idx = random.randint(min(len(argsort),6)) + # print('rand idx',rand_idx) + rand_idx = np.random.randint(len(boxArea)) + rand_Side = boxArea[rand_idx] ** 0.5 + # rand_Side = min(boxes[rand_idx,2] - boxes[rand_idx,0] + 1, + # boxes[rand_idx,3] - boxes[rand_idx,1] + 1) + + distance = infDistance + anchor_idx = 5 + for i, anchor in enumerate(scale_array): + if abs(anchor - rand_Side) < distance: + distance = abs(anchor - rand_Side) + anchor_idx = i + + target_anchor = random.choice(scale_array[0:min(anchor_idx + 1, 5) + 1]) + ratio = float(target_anchor) / rand_Side + ratio = ratio * (2**random.uniform(-1, 1)) + + if int(img_height * ratio * img_width * ratio) > maxSize * maxSize: + ratio = (maxSize * maxSize / (img_height * img_width))**0.5 + + interp_methods = [cv2.INTER_LINEAR, cv2.INTER_CUBIC, + cv2.INTER_AREA, cv2.INTER_NEAREST, cv2.INTER_LANCZOS4] + interp_method = random.choice(interp_methods) + image = cv2.resize(img, None, None, fx=ratio, + fy=ratio, interpolation=interp_method) + + boxes[:, 0] *= ratio + boxes[:, 1] *= ratio + boxes[:, 2] *= ratio + boxes[:, 3] *= ratio + + height, width, _ = image.shape + + sample_boxes = [] + + xmin = boxes[rand_idx, 0] + ymin = boxes[rand_idx, 1] + bw = (boxes[rand_idx, 2] - boxes[rand_idx, 0] + 1) + bh = (boxes[rand_idx, 3] - boxes[rand_idx, 1] + 1) + + w = h = 640 + + for _ in range(50): + if w < max(height, width): + if bw <= w: + w_off = random.uniform(xmin + bw - w, xmin) + else: + w_off = random.uniform(xmin, xmin + bw - w) + + if bh <= h: + h_off = random.uniform(ymin + bh - h, ymin) + else: + h_off = random.uniform(ymin, ymin + bh - h) + else: + w_off = random.uniform(width - w, 0) + h_off = random.uniform(height - h, 0) + + w_off = math.floor(w_off) + h_off = math.floor(h_off) + + # convert to integer rect x1,y1,x2,y2 + rect = np.array( + [int(w_off), int(h_off), int(w_off + w), int(h_off + h)]) + + # keep overlap with gt box IF center in sampled patch + centers = (boxes[:, :2] + boxes[:, 2:]) / 2.0 + # mask in all gt boxes that above and to the left of centers + m1 = (rect[0] <= boxes[:, 0]) * (rect[1] <= boxes[:, 1]) + # mask in all gt boxes that under and to the right of centers + m2 = (rect[2] >= boxes[:, 2]) * (rect[3] >= boxes[:, 3]) + # mask in that both m1 and m2 are true + mask = m1 * m2 + + overlap = jaccard_numpy(boxes, rect) + # have any valid boxes? try again if not + if not mask.any() and not overlap.max() > 0.7: + continue + else: + sample_boxes.append(rect) + + sampled_labels = [] + + if len(sample_boxes) > 0: + choice_idx = np.random.randint(len(sample_boxes)) + choice_box = sample_boxes[choice_idx] + # print('crop the box :',choice_box) + centers = (boxes[:, :2] + boxes[:, 2:]) / 2.0 + m1 = (choice_box[0] < centers[:, 0]) * \ + (choice_box[1] < centers[:, 1]) + m2 = (choice_box[2] > centers[:, 0]) * \ + (choice_box[3] > centers[:, 1]) + mask = m1 * m2 + current_boxes = boxes[mask, :].copy() + current_labels = labels[mask] + current_boxes[:, :2] -= choice_box[:2] + current_boxes[:, 2:] -= choice_box[:2] + + if choice_box[0] < 0 or choice_box[1] < 0: + new_img_width = width if choice_box[ + 0] >= 0 else width - choice_box[0] + new_img_height = height if choice_box[ + 1] >= 0 else height - choice_box[1] + image_pad = np.zeros( + (new_img_height, new_img_width, 3), dtype=float) + image_pad[:, :, :] = mean + start_left = 0 if choice_box[0] >= 0 else -choice_box[0] + start_top = 0 if choice_box[1] >= 0 else -choice_box[1] + image_pad[start_top:, start_left:, :] = image + + choice_box_w = choice_box[2] - choice_box[0] + choice_box_h = choice_box[3] - choice_box[1] + + start_left = choice_box[0] if choice_box[0] >= 0 else 0 + start_top = choice_box[1] if choice_box[1] >= 0 else 0 + end_right = start_left + choice_box_w + end_bottom = start_top + choice_box_h + current_image = image_pad[ + start_top:end_bottom, start_left:end_right, :].copy() + image_height, image_width, _ = current_image.shape + if cfg.filter_min_face: + bbox_w = current_boxes[:, 2] - current_boxes[:, 0] + bbox_h = current_boxes[:, 3] - current_boxes[:, 1] + bbox_area = bbox_w * bbox_h + mask = bbox_area > (cfg.min_face_size * cfg.min_face_size) + current_boxes = current_boxes[mask] + current_labels = current_labels[mask] + for i in range(len(current_boxes)): + sample_label = [] + sample_label.append(current_labels[i]) + sample_label.append(current_boxes[i][0] / image_width) + sample_label.append(current_boxes[i][1] / image_height) + sample_label.append(current_boxes[i][2] / image_width) + sample_label.append(current_boxes[i][3] / image_height) + sampled_labels += [sample_label] + sampled_labels = np.array(sampled_labels) + else: + current_boxes /= np.array([image_width, + image_height, image_width, image_height]) + sampled_labels = np.hstack( + (current_labels[:, np.newaxis], current_boxes)) + + return current_image, sampled_labels + + current_image = image[choice_box[1]:choice_box[ + 3], choice_box[0]:choice_box[2], :].copy() + image_height, image_width, _ = current_image.shape + + if cfg.filter_min_face: + bbox_w = current_boxes[:, 2] - current_boxes[:, 0] + bbox_h = current_boxes[:, 3] - current_boxes[:, 1] + bbox_area = bbox_w * bbox_h + mask = bbox_area > (cfg.min_face_size * cfg.min_face_size) + current_boxes = current_boxes[mask] + current_labels = current_labels[mask] + for i in range(len(current_boxes)): + sample_label = [] + sample_label.append(current_labels[i]) + sample_label.append(current_boxes[i][0] / image_width) + sample_label.append(current_boxes[i][1] / image_height) + sample_label.append(current_boxes[i][2] / image_width) + sample_label.append(current_boxes[i][3] / image_height) + sampled_labels += [sample_label] + sampled_labels = np.array(sampled_labels) + else: + current_boxes /= np.array([image_width, + image_height, image_width, image_height]) + sampled_labels = np.hstack( + (current_labels[:, np.newaxis], current_boxes)) + + return current_image, sampled_labels + else: + image_height, image_width, _ = image.shape + if cfg.filter_min_face: + bbox_w = boxes[:, 2] - boxes[:, 0] + bbox_h = boxes[:, 3] - boxes[:, 1] + bbox_area = bbox_w * bbox_h + mask = bbox_area > (cfg.min_face_size * cfg.min_face_size) + boxes = boxes[mask] + labels = labels[mask] + for i in range(len(boxes)): + sample_label = [] + sample_label.append(labels[i]) + sample_label.append(boxes[i][0] / image_width) + sample_label.append(boxes[i][1] / image_height) + sample_label.append(boxes[i][2] / image_width) + sample_label.append(boxes[i][3] / image_height) + sampled_labels += [sample_label] + sampled_labels = np.array(sampled_labels) + else: + boxes /= np.array([image_width, image_height, + image_width, image_height]) + sampled_labels = np.hstack( + (labels[:, np.newaxis], boxes)) + + return image, sampled_labels + + +def preprocess(img, bbox_labels, mode, image_path): + img_width, img_height = img.size + sampled_labels = bbox_labels + if mode == 'train': + if cfg.apply_distort: + img = distort_image(img) + if cfg.apply_expand: + img, bbox_labels, img_width, img_height = expand_image( + img, bbox_labels, img_width, img_height) + + batch_sampler = [] + prob = np.random.uniform(0., 1.) + if prob > cfg.data_anchor_sampling_prob and cfg.anchor_sampling: + scale_array = np.array([16, 32, 64, 128, 256, 512]) + ''' + batch_sampler.append( + sampler(1, 50, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.6, 0.0, True)) + sampled_bbox = generate_batch_random_samples( + batch_sampler, bbox_labels, img_width, img_height, scale_array, + cfg.resize_width, cfg.resize_height) + ''' + img = np.array(img) + img, sampled_labels = anchor_crop_image_sampling( + img, bbox_labels, scale_array, img_width, img_height) + ''' + if len(sampled_bbox) > 0: + idx = int(np.random.uniform(0, len(sampled_bbox))) + img, sampled_labels = crop_image_sampling( + img, bbox_labels, sampled_bbox[idx], img_width, img_height, + cfg.resize_width, cfg.resize_height, cfg.min_face_size) + ''' + img = img.astype('uint8') + img = Image.fromarray(img) + else: + batch_sampler.append(sampler(1, 50, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, + 0.0, True)) + batch_sampler.append(sampler(1, 50, 0.3, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, + 0.0, True)) + batch_sampler.append(sampler(1, 50, 0.3, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, + 0.0, True)) + batch_sampler.append(sampler(1, 50, 0.3, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, + 0.0, True)) + batch_sampler.append(sampler(1, 50, 0.3, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, + 0.0, True)) + sampled_bbox = generate_batch_samples( + batch_sampler, bbox_labels, img_width, img_height) + + img = np.array(img) + if len(sampled_bbox) > 0: + idx = int(np.random.uniform(0, len(sampled_bbox))) + img, sampled_labels = crop_image( + img, bbox_labels, sampled_bbox[idx], img_width, img_height, + cfg.resize_width, cfg.resize_height, cfg.min_face_size) + + img = Image.fromarray(img) + + interp_mode = [ + Image.BILINEAR, Image.HAMMING, Image.NEAREST, Image.BICUBIC, + Image.LANCZOS + ] + interp_indx = np.random.randint(0, 5) + + img = img.resize((cfg.resize_width, cfg.resize_height), + resample=interp_mode[interp_indx]) + + img = np.array(img) + + if mode == 'train': + mirror = int(np.random.uniform(0, 2)) + if mirror == 1: + img = img[:, ::-1, :] + for i in six.moves.xrange(len(sampled_labels)): + tmp = sampled_labels[i][1] + sampled_labels[i][1] = 1 - sampled_labels[i][3] + sampled_labels[i][3] = 1 - tmp + + #img = Image.fromarray(img) + img = to_chw_bgr(img) + img = img.astype('float32') + img -= cfg.img_mean + img = img[[2, 1, 0], :, :] # to RGB + #img = img * cfg.scale + + return img, sampled_labels diff --git a/PyTorch/contrib/cv/detection/RefineDet/README.md b/PyTorch/contrib/cv/detection/RefineDet/README.md index 9acc3e968d..b3fba97b02 100644 --- a/PyTorch/contrib/cv/detection/RefineDet/README.md +++ b/PyTorch/contrib/cv/detection/RefineDet/README.md @@ -1,49 +1,49 @@ -#RefineDet模型PyTorch 训练指导 - -## 1 环境准备 - -1.安装必要的依赖 - -pip install -r requirements.txt - -2.获取数据集 - -``` -sh data/scripts/VOC2007.sh -sh data/scripts/VOC2012.sh -``` -下载好的数据集位于 ./data/VOCdevkit - - -## 2 训练 - -路径要写到 VOCdevkit - -``` -# npu env -source test/env_npu.sh - -# 1p train perf -bash test/train_performance_1p.sh --data_path=xxx - -# 路径要写到 VOCdevkit -# 例如 - -bash test/train_performance_1p.sh --data_path=./data/VOCdevkit - -# 8p train perf -bash test/train_performance_8p.sh --data_path=xxx - -# 8p train full -bash test/train_full_8p.sh --data_path=xxx - -# 8p eval -bash test/train_eval_8p.sh --data_path=xxx - -# finetuning -bash test/train_finetune_1p.sh --data_path=xxx - -# online inference demo -python3.7 demo.py - +#RefineDet模型PyTorch 训练指导 + +## 1 环境准备 + +1.安装必要的依赖 + +pip install -r requirements.txt + +2.获取数据集 + +``` +sh data/scripts/VOC2007.sh +sh data/scripts/VOC2012.sh +``` +下载好的数据集位于 ./data/VOCdevkit + + +## 2 训练 + +路径要写到 VOCdevkit + +``` +# npu env +source test/env_npu.sh + +# 1p train perf +bash test/train_performance_1p.sh --data_path=xxx + +# 路径要写到 VOCdevkit +# 例如 + +bash test/train_performance_1p.sh --data_path=./data/VOCdevkit + +# 8p train perf +bash test/train_performance_8p.sh --data_path=xxx + +# 8p train full +bash test/train_full_8p.sh --data_path=xxx + +# 8p eval +bash test/train_eval_8p.sh --data_path=xxx + +# finetuning +bash test/train_finetune_1p.sh --data_path=xxx + +# online inference demo +python3.7 demo.py + ``` \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/RefineDet/demo.py b/PyTorch/contrib/cv/detection/RefineDet/demo.py index e1d12a5a1a..bce020fc36 100644 --- a/PyTorch/contrib/cv/detection/RefineDet/demo.py +++ b/PyTorch/contrib/cv/detection/RefineDet/demo.py @@ -1,22 +1,22 @@ -#!/bin/bash -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 torch -from models.refinedet import build_refinedet -torch.npu.set_device('npu:0') -net = build_refinedet('test', 320, 21, batch_norm=True).npu() -input = torch.randn(size=(1, 3, 320, 320)).npu() -out = net(input) +#!/bin/bash +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 torch +from models.refinedet import build_refinedet +torch.npu.set_device('npu:0') +net = build_refinedet('test', 320, 21, batch_norm=True).npu() +input = torch.randn(size=(1, 3, 320, 320)).npu() +out = net(input) print(out) \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/RefineDet/eval_refinedet.py b/PyTorch/contrib/cv/detection/RefineDet/eval_refinedet.py index 42bb8f17b2..e960f367b0 100644 --- a/PyTorch/contrib/cv/detection/RefineDet/eval_refinedet.py +++ b/PyTorch/contrib/cv/detection/RefineDet/eval_refinedet.py @@ -1,466 +1,466 @@ -#!/bin/bash -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -"""Adapted from: - @longcw faster_rcnn_pytorch: https://github.com/longcw/faster_rcnn_pytorch - @rbgirshick py-faster-rcnn https://github.com/rbgirshick/py-faster-rcnn - Licensed under The MIT License [see LICENSE for details] -""" - -from __future__ import print_function -import torch -import torch.nn as nn -import torch.backends.cudnn as cudnn -from torch.autograd import Variable -from data import VOCAnnotationTransform, VOCDetection, BaseTransform -from data import VOC_CLASSES as labelmap -from data import voc_refinedet, detection_collate_test -import torch.utils.data as data - -from models.refinedet import build_refinedet - -import sys -import os -import time -import argparse -import numpy as np -import pickle -import cv2 -from apex import amp - -cfg = voc_refinedet['320'] - -if sys.version_info[0] == 2: - import xml.etree.cElementTree as ET -else: - import xml.etree.ElementTree as ET - -def str2bool(v): - return v.lower() in ("yes", "true", "t", "1") - -class Timer(object): - """A simple timer.""" - def __init__(self): - self.total_time = 0. - self.calls = 0 - self.start_time = 0. - self.diff = 0. - self.average_time = 0. - - def tic(self): - self.start_time = time.time() - - def toc(self, average=True): - self.diff = time.time() - self.start_time - self.total_time += self.diff - self.calls += 1 - self.average_time = self.total_time / self.calls - if average: - return self.average_time - else: - return self.diff - - -def parse_rec(filename): - """ Parse a PASCAL VOC xml file """ - tree = ET.parse(filename) - objects = [] - for obj in tree.findall('object'): - obj_struct = {} - obj_struct['name'] = obj.find('name').text - obj_struct['pose'] = obj.find('pose').text - obj_struct['truncated'] = int(obj.find('truncated').text) - obj_struct['difficult'] = int(obj.find('difficult').text) - bbox = obj.find('bndbox') - obj_struct['bbox'] = [int(bbox.find('xmin').text) - 1, - int(bbox.find('ymin').text) - 1, - int(bbox.find('xmax').text) - 1, - int(bbox.find('ymax').text) - 1] - objects.append(obj_struct) - - return objects - - -def get_output_dir(name, phase): - """Return the directory where experimental artifacts are placed. - If the directory does not exist, it is created. - A canonical path is built using the name from an imdb and a network - (if not None). - """ - filedir = os.path.join(name, phase) - if not os.path.exists(filedir): - os.makedirs(filedir) - return filedir - - -def get_voc_results_file_template(image_set, cls): - filename = 'det_' + image_set + '_%s.txt' % (cls) - filedir = os.path.join(devkit_path, 'results') - if not os.path.exists(filedir): - os.makedirs(filedir) - path = os.path.join(filedir, filename) - return path - - -def write_voc_results_file(all_boxes, dataset, set_type='test'): - for cls_ind, cls in enumerate(labelmap): - print('Writing {:s} VOC results file'.format(cls)) - filename = get_voc_results_file_template(set_type, cls) - with open(filename, 'wt') as f: - for im_ind, index in enumerate(dataset.ids): - dets = all_boxes[cls_ind+1][im_ind] - if dets == []: - continue - # the VOCdevkit expects 1-based indices - for k in range(dets.shape[0]): - f.write('{:s} {:.3f} {:.1f} {:.1f} {:.1f} {:.1f}\n'. - format(index[1], dets[k, -1], - dets[k, 0] + 1, dets[k, 1] + 1, - dets[k, 2] + 1, dets[k, 3] + 1)) - - -def do_python_eval(output_dir='output', use_07=True, set_type='test'): - cachedir = os.path.join(devkit_path, 'annotations_cache') - aps = [] - # The PASCAL VOC metric changed in 2010 - use_07_metric = use_07 - print('VOC07 metric? ' + ('Yes' if use_07_metric else 'No')) - if not os.path.isdir(output_dir): - os.mkdir(output_dir) - for i, cls in enumerate(labelmap): - filename = get_voc_results_file_template(set_type, cls) - rec, prec, ap = voc_eval( - filename, annopath, imgsetpath.format(set_type), cls, cachedir, - ovthresh=0.5, use_07_metric=use_07_metric) - aps += [ap] - print('AP for {} = {:.4f}'.format(cls, ap)) - with open(os.path.join(output_dir, cls + '_pr.pkl'), 'wb') as f: - pickle.dump({'rec': rec, 'prec': prec, 'ap': ap}, f) - mAp = np.mean(aps) - print('Mean AP on ' + set_type + ' set = {:.4f}'.format(mAp)) - return mAp.item() - - -def voc_ap(rec, prec, use_07_metric=True): - """ ap = voc_ap(rec, prec, [use_07_metric]) - Compute VOC AP given precision and recall. - If use_07_metric is true, uses the - VOC 07 11 point method (default:True). - """ - if use_07_metric: - # 11 point metric - ap = 0. - for t in np.arange(0., 1.1, 0.1): - if np.sum(rec >= t) == 0: - p = 0 - else: - p = np.max(prec[rec >= t]) - ap = ap + p / 11. - else: - # correct AP calculation - # first append sentinel values at the end - mrec = np.concatenate(([0.], rec, [1.])) - mpre = np.concatenate(([0.], prec, [0.])) - - # compute the precision envelope - for i in range(mpre.size - 1, 0, -1): - mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i]) - - # to calculate area under PR curve, look for points - # where X axis (recall) changes value - i = np.where(mrec[1:] != mrec[:-1])[0] - - # and sum (\Delta recall) * prec - ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) - return ap - - -def voc_eval(detpath, - annopath, - imagesetfile, - classname, - cachedir, - ovthresh=0.5, - use_07_metric=True): - """rec, prec, ap = voc_eval(detpath, - annopath, - imagesetfile, - classname, - [ovthresh], - [use_07_metric]) -Top level function that does the PASCAL VOC evaluation. -detpath: Path to detections - detpath.format(classname) should produce the detection results file. -annopath: Path to annotations - annopath.format(imagename) should be the xml annotations file. -imagesetfile: Text file containing the list of images, one image per line. -classname: Category name (duh) -cachedir: Directory for caching the annotations -[ovthresh]: Overlap threshold (default = 0.5) -[use_07_metric]: Whether to use VOC07's 11 point AP computation - (default True) -""" -# assumes detections are in detpath.format(classname) -# assumes annotations are in annopath.format(imagename) -# assumes imagesetfile is a text file with each line an image name -# cachedir caches the annotations in a pickle file -# first load gt - if not os.path.isdir(cachedir): - os.mkdir(cachedir) - cachefile = os.path.join(cachedir, 'annots.pkl') - # read list of images - with open(imagesetfile, 'r') as f: - lines = f.readlines() - imagenames = [x.strip() for x in lines] - if not os.path.isfile(cachefile): - # load annots - recs = {} - for i, imagename in enumerate(imagenames): - recs[imagename] = parse_rec(annopath % (imagename)) - if i % 100 == 0: - print('Reading annotation for {:d}/{:d}'.format( - i + 1, len(imagenames))) - # save - print('Saving cached annotations to {:s}'.format(cachefile)) - with open(cachefile, 'wb') as f: - pickle.dump(recs, f) - else: - # load - with open(cachefile, 'rb') as f: - recs = pickle.load(f) - - # extract gt objects for this class - class_recs = {} - npos = 0 - for imagename in imagenames: - R = [obj for obj in recs[imagename] if obj['name'] == classname] - bbox = np.array([x['bbox'] for x in R]) - difficult = np.array([x['difficult'] for x in R]).astype(np.bool) - det = [False] * len(R) - npos = npos + sum(~difficult) - class_recs[imagename] = {'bbox': bbox, - 'difficult': difficult, - 'det': det} - - # read dets - detfile = detpath.format(classname) - with open(detfile, 'r') as f: - lines = f.readlines() - if any(lines) == 1: - - splitlines = [x.strip().split(' ') for x in lines] - image_ids = [x[0] for x in splitlines] - confidence = np.array([float(x[1]) for x in splitlines]) - BB = np.array([[float(z) for z in x[2:]] for x in splitlines]) - - # sort by confidence - sorted_ind = np.argsort(-confidence) - sorted_scores = np.sort(-confidence) - BB = BB[sorted_ind, :] - image_ids = [image_ids[x] for x in sorted_ind] - - # go down dets and mark TPs and FPs - nd = len(image_ids) - tp = np.zeros(nd) - fp = np.zeros(nd) - for d in range(nd): - R = class_recs[image_ids[d]] - bb = BB[d, :].astype(float) - ovmax = -np.inf - BBGT = R['bbox'].astype(float) - if BBGT.size > 0: - # compute overlaps - # intersection - ixmin = np.maximum(BBGT[:, 0], bb[0]) - iymin = np.maximum(BBGT[:, 1], bb[1]) - ixmax = np.minimum(BBGT[:, 2], bb[2]) - iymax = np.minimum(BBGT[:, 3], bb[3]) - iw = np.maximum(ixmax - ixmin, 0.) - ih = np.maximum(iymax - iymin, 0.) - inters = iw * ih - uni = ((bb[2] - bb[0]) * (bb[3] - bb[1]) + - (BBGT[:, 2] - BBGT[:, 0]) * - (BBGT[:, 3] - BBGT[:, 1]) - inters) - overlaps = inters / uni - ovmax = np.max(overlaps) - jmax = np.argmax(overlaps) - - if ovmax > ovthresh: - if not R['difficult'][jmax]: - if not R['det'][jmax]: - tp[d] = 1. - R['det'][jmax] = 1 - else: - fp[d] = 1. - else: - fp[d] = 1. - - # compute precision recall - fp = np.cumsum(fp) - tp = np.cumsum(tp) - rec = tp / float(npos) - # avoid divide by zero in case the first detection matches a difficult - # ground truth - prec = tp / np.maximum(tp + fp, np.finfo(np.float64).eps) - ap = voc_ap(rec, prec, use_07_metric) - else: - rec = -1. - prec = -1. - ap = -1. - - return rec, prec, ap - - -def test_net(save_folder, net, cuda, dataset, dataloador, transform, top_k, - im_size=300, thresh=0.05, set_type='test'): - num_images = len(dataset) - # all detections are collected into: - # all_boxes[cls][image] = N x 5 array of detections in - # (x1, y1, x2, y2, score) - all_boxes = [[[] for _ in range(num_images)] - for _ in range(len(labelmap)+1)] - - # timers - _t = {'im_detect': Timer(), 'misc': Timer()} - output_dir = get_output_dir('ssd300_120000', set_type) - det_file = os.path.join(output_dir, 'detections.pkl') - - detection_list, h_list, w_list = [], [], [] - for i, item in enumerate(dataloador): - # im, gt, h, w = dataset.pull_item(i) - # print(im.shape,h,w) - - x, _, h, w = item - bs, _, _, _ = x.size() - # print(x.size()) - # x = Variable(im.unsqueeze(0)) - if cfg['cuda']: - x = x.cuda() - elif cfg['npu']: - x = x.npu() - _t['im_detect'].tic() - detections = net(x).data - detect_time = _t['im_detect'].toc(average=False) - detection_list.append(detections.cpu()) - h_list.extend(h) - w_list.extend(w) - print('im_detect: {:d}/{:d} {:.3f}s'.format(i + 1, - len(dataloador), detect_time)) - # skip j = 0, because it's the background class - strat_time = time.time() - detections = torch.cat(detection_list, dim=0) - for idx in range(detections.size(0)): - h, w = h_list[idx], w_list[idx] - for j in range(1, detections.size(1)): - #dets = detections[0, j, :] - dets = detections[idx, j, :] - mask = dets[:, 0].gt(0.).expand(5, dets.size(0)).t() - dets = torch.masked_select(dets, mask).view(-1, 5) - if dets.size(0) == 0: - continue - boxes = dets[:, 1:] - boxes[:, 0] *= w - boxes[:, 2] *= w - boxes[:, 1] *= h - boxes[:, 3] *= h - scores = dets[:, 0].cpu().numpy() - cls_dets = np.hstack((boxes.cpu().numpy(), - scores[:, np.newaxis])).astype(np.float32, - copy=False) - # all_boxes[j][i] = cls_dets - all_boxes[j][idx] = cls_dets - end_time = time.time() - print('spend time: %.3fs'%(end_time-strat_time)) - - with open(det_file, 'wb') as f: - pickle.dump(all_boxes, f, pickle.HIGHEST_PROTOCOL) - - print('Evaluating detections') - mAp = evaluate_detections(all_boxes, output_dir, dataset, set_type=set_type) - return mAp - - -def evaluate_detections(box_list, output_dir, dataset, set_type='test'): - write_voc_results_file(box_list, dataset, set_type=set_type) - mAp = do_python_eval(output_dir, set_type=set_type) - return mAp - - - - -if __name__ == '__main__': - pth_path, data_path = sys.argv[1:3] - if not os.path.exists(cfg['save_folder']): - os.makedirs(cfg['save_folder']) - - if torch.cuda.is_available(): - if cfg['cuda']: - torch.set_default_tensor_type('torch.cuda.FloatTensor') - if not cfg['cuda']: - print("WARNING: It looks like you have a CUDA device, but aren't using \ - CUDA. Run with --cuda for optimal eval speed.") - torch.set_default_tensor_type('torch.FloatTensor') - else: - torch.set_default_tensor_type('torch.FloatTensor') - - annopath = os.path.join(data_path, 'VOC2007', 'Annotations', '%s.xml') - imgpath = os.path.join(data_path, 'VOC2007', 'JPEGImages', '%s.jpg') - imgsetpath = os.path.join(data_path, 'VOC2007', 'ImageSets', - 'Main', '{:s}.txt') - YEAR = '2007' - devkit_path = data_path + 'VOC' + YEAR - dataset_mean = (104, 117, 123) - # load net - num_classes = len(labelmap) + 1 # +1 for background - net = build_refinedet('test', int(cfg['input_size']), num_classes, batch_norm=True) # initialize SSD - - - - # load data - set_type = 'test' - dataset = VOCDetection(root=data_path, - image_sets=[('2007', set_type)], - transform=BaseTransform(int(cfg['input_size']), dataset_mean), - target_transform=VOCAnnotationTransform(), - dataset_name='VOC07test') - - if cfg['cuda']: - net = net.cuda() - cudnn.benchmark = True - elif cfg['npu']: - net = net.npu() - cudnn.benchmark = True - - if cfg['amp']: - net = amp.initialize(net, opt_level='O1', loss_scale=128) - - - net.eval() - data_loader = data.DataLoader(dataset, - batch_size=128, - num_workers=16, - shuffle=False, - collate_fn=detection_collate_test, - pin_memory=True) - save_path = './RefineDet320_bn/RefineDet320_VOC_231.pth' - save_path = pth_path - net.load_state_dict(torch.load(save_path, map_location='cpu')) - print('Finished loading model! ' + save_path) - - # evaluation - with torch.no_grad(): - mAp = test_net(cfg['save_folder'], net, cfg['cuda'], dataset, data_loader, - BaseTransform(int(cfg['input_size']), dataset_mean), cfg['top_k'], int(cfg['input_size']), - thresh=cfg['confidence_threshold']) +#!/bin/bash +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +"""Adapted from: + @longcw faster_rcnn_pytorch: https://github.com/longcw/faster_rcnn_pytorch + @rbgirshick py-faster-rcnn https://github.com/rbgirshick/py-faster-rcnn + Licensed under The MIT License [see LICENSE for details] +""" + +from __future__ import print_function +import torch +import torch.nn as nn +import torch.backends.cudnn as cudnn +from torch.autograd import Variable +from data import VOCAnnotationTransform, VOCDetection, BaseTransform +from data import VOC_CLASSES as labelmap +from data import voc_refinedet, detection_collate_test +import torch.utils.data as data + +from models.refinedet import build_refinedet + +import sys +import os +import time +import argparse +import numpy as np +import pickle +import cv2 +from apex import amp + +cfg = voc_refinedet['320'] + +if sys.version_info[0] == 2: + import xml.etree.cElementTree as ET +else: + import xml.etree.ElementTree as ET + +def str2bool(v): + return v.lower() in ("yes", "true", "t", "1") + +class Timer(object): + """A simple timer.""" + def __init__(self): + self.total_time = 0. + self.calls = 0 + self.start_time = 0. + self.diff = 0. + self.average_time = 0. + + def tic(self): + self.start_time = time.time() + + def toc(self, average=True): + self.diff = time.time() - self.start_time + self.total_time += self.diff + self.calls += 1 + self.average_time = self.total_time / self.calls + if average: + return self.average_time + else: + return self.diff + + +def parse_rec(filename): + """ Parse a PASCAL VOC xml file """ + tree = ET.parse(filename) + objects = [] + for obj in tree.findall('object'): + obj_struct = {} + obj_struct['name'] = obj.find('name').text + obj_struct['pose'] = obj.find('pose').text + obj_struct['truncated'] = int(obj.find('truncated').text) + obj_struct['difficult'] = int(obj.find('difficult').text) + bbox = obj.find('bndbox') + obj_struct['bbox'] = [int(bbox.find('xmin').text) - 1, + int(bbox.find('ymin').text) - 1, + int(bbox.find('xmax').text) - 1, + int(bbox.find('ymax').text) - 1] + objects.append(obj_struct) + + return objects + + +def get_output_dir(name, phase): + """Return the directory where experimental artifacts are placed. + If the directory does not exist, it is created. + A canonical path is built using the name from an imdb and a network + (if not None). + """ + filedir = os.path.join(name, phase) + if not os.path.exists(filedir): + os.makedirs(filedir) + return filedir + + +def get_voc_results_file_template(image_set, cls): + filename = 'det_' + image_set + '_%s.txt' % (cls) + filedir = os.path.join(devkit_path, 'results') + if not os.path.exists(filedir): + os.makedirs(filedir) + path = os.path.join(filedir, filename) + return path + + +def write_voc_results_file(all_boxes, dataset, set_type='test'): + for cls_ind, cls in enumerate(labelmap): + print('Writing {:s} VOC results file'.format(cls)) + filename = get_voc_results_file_template(set_type, cls) + with open(filename, 'wt') as f: + for im_ind, index in enumerate(dataset.ids): + dets = all_boxes[cls_ind+1][im_ind] + if dets == []: + continue + # the VOCdevkit expects 1-based indices + for k in range(dets.shape[0]): + f.write('{:s} {:.3f} {:.1f} {:.1f} {:.1f} {:.1f}\n'. + format(index[1], dets[k, -1], + dets[k, 0] + 1, dets[k, 1] + 1, + dets[k, 2] + 1, dets[k, 3] + 1)) + + +def do_python_eval(output_dir='output', use_07=True, set_type='test'): + cachedir = os.path.join(devkit_path, 'annotations_cache') + aps = [] + # The PASCAL VOC metric changed in 2010 + use_07_metric = use_07 + print('VOC07 metric? ' + ('Yes' if use_07_metric else 'No')) + if not os.path.isdir(output_dir): + os.mkdir(output_dir) + for i, cls in enumerate(labelmap): + filename = get_voc_results_file_template(set_type, cls) + rec, prec, ap = voc_eval( + filename, annopath, imgsetpath.format(set_type), cls, cachedir, + ovthresh=0.5, use_07_metric=use_07_metric) + aps += [ap] + print('AP for {} = {:.4f}'.format(cls, ap)) + with open(os.path.join(output_dir, cls + '_pr.pkl'), 'wb') as f: + pickle.dump({'rec': rec, 'prec': prec, 'ap': ap}, f) + mAp = np.mean(aps) + print('Mean AP on ' + set_type + ' set = {:.4f}'.format(mAp)) + return mAp.item() + + +def voc_ap(rec, prec, use_07_metric=True): + """ ap = voc_ap(rec, prec, [use_07_metric]) + Compute VOC AP given precision and recall. + If use_07_metric is true, uses the + VOC 07 11 point method (default:True). + """ + if use_07_metric: + # 11 point metric + ap = 0. + for t in np.arange(0., 1.1, 0.1): + if np.sum(rec >= t) == 0: + p = 0 + else: + p = np.max(prec[rec >= t]) + ap = ap + p / 11. + else: + # correct AP calculation + # first append sentinel values at the end + mrec = np.concatenate(([0.], rec, [1.])) + mpre = np.concatenate(([0.], prec, [0.])) + + # compute the precision envelope + for i in range(mpre.size - 1, 0, -1): + mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i]) + + # to calculate area under PR curve, look for points + # where X axis (recall) changes value + i = np.where(mrec[1:] != mrec[:-1])[0] + + # and sum (\Delta recall) * prec + ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) + return ap + + +def voc_eval(detpath, + annopath, + imagesetfile, + classname, + cachedir, + ovthresh=0.5, + use_07_metric=True): + """rec, prec, ap = voc_eval(detpath, + annopath, + imagesetfile, + classname, + [ovthresh], + [use_07_metric]) +Top level function that does the PASCAL VOC evaluation. +detpath: Path to detections + detpath.format(classname) should produce the detection results file. +annopath: Path to annotations + annopath.format(imagename) should be the xml annotations file. +imagesetfile: Text file containing the list of images, one image per line. +classname: Category name (duh) +cachedir: Directory for caching the annotations +[ovthresh]: Overlap threshold (default = 0.5) +[use_07_metric]: Whether to use VOC07's 11 point AP computation + (default True) +""" +# assumes detections are in detpath.format(classname) +# assumes annotations are in annopath.format(imagename) +# assumes imagesetfile is a text file with each line an image name +# cachedir caches the annotations in a pickle file +# first load gt + if not os.path.isdir(cachedir): + os.mkdir(cachedir) + cachefile = os.path.join(cachedir, 'annots.pkl') + # read list of images + with open(imagesetfile, 'r') as f: + lines = f.readlines() + imagenames = [x.strip() for x in lines] + if not os.path.isfile(cachefile): + # load annots + recs = {} + for i, imagename in enumerate(imagenames): + recs[imagename] = parse_rec(annopath % (imagename)) + if i % 100 == 0: + print('Reading annotation for {:d}/{:d}'.format( + i + 1, len(imagenames))) + # save + print('Saving cached annotations to {:s}'.format(cachefile)) + with open(cachefile, 'wb') as f: + pickle.dump(recs, f) + else: + # load + with open(cachefile, 'rb') as f: + recs = pickle.load(f) + + # extract gt objects for this class + class_recs = {} + npos = 0 + for imagename in imagenames: + R = [obj for obj in recs[imagename] if obj['name'] == classname] + bbox = np.array([x['bbox'] for x in R]) + difficult = np.array([x['difficult'] for x in R]).astype(np.bool) + det = [False] * len(R) + npos = npos + sum(~difficult) + class_recs[imagename] = {'bbox': bbox, + 'difficult': difficult, + 'det': det} + + # read dets + detfile = detpath.format(classname) + with open(detfile, 'r') as f: + lines = f.readlines() + if any(lines) == 1: + + splitlines = [x.strip().split(' ') for x in lines] + image_ids = [x[0] for x in splitlines] + confidence = np.array([float(x[1]) for x in splitlines]) + BB = np.array([[float(z) for z in x[2:]] for x in splitlines]) + + # sort by confidence + sorted_ind = np.argsort(-confidence) + sorted_scores = np.sort(-confidence) + BB = BB[sorted_ind, :] + image_ids = [image_ids[x] for x in sorted_ind] + + # go down dets and mark TPs and FPs + nd = len(image_ids) + tp = np.zeros(nd) + fp = np.zeros(nd) + for d in range(nd): + R = class_recs[image_ids[d]] + bb = BB[d, :].astype(float) + ovmax = -np.inf + BBGT = R['bbox'].astype(float) + if BBGT.size > 0: + # compute overlaps + # intersection + ixmin = np.maximum(BBGT[:, 0], bb[0]) + iymin = np.maximum(BBGT[:, 1], bb[1]) + ixmax = np.minimum(BBGT[:, 2], bb[2]) + iymax = np.minimum(BBGT[:, 3], bb[3]) + iw = np.maximum(ixmax - ixmin, 0.) + ih = np.maximum(iymax - iymin, 0.) + inters = iw * ih + uni = ((bb[2] - bb[0]) * (bb[3] - bb[1]) + + (BBGT[:, 2] - BBGT[:, 0]) * + (BBGT[:, 3] - BBGT[:, 1]) - inters) + overlaps = inters / uni + ovmax = np.max(overlaps) + jmax = np.argmax(overlaps) + + if ovmax > ovthresh: + if not R['difficult'][jmax]: + if not R['det'][jmax]: + tp[d] = 1. + R['det'][jmax] = 1 + else: + fp[d] = 1. + else: + fp[d] = 1. + + # compute precision recall + fp = np.cumsum(fp) + tp = np.cumsum(tp) + rec = tp / float(npos) + # avoid divide by zero in case the first detection matches a difficult + # ground truth + prec = tp / np.maximum(tp + fp, np.finfo(np.float64).eps) + ap = voc_ap(rec, prec, use_07_metric) + else: + rec = -1. + prec = -1. + ap = -1. + + return rec, prec, ap + + +def test_net(save_folder, net, cuda, dataset, dataloador, transform, top_k, + im_size=300, thresh=0.05, set_type='test'): + num_images = len(dataset) + # all detections are collected into: + # all_boxes[cls][image] = N x 5 array of detections in + # (x1, y1, x2, y2, score) + all_boxes = [[[] for _ in range(num_images)] + for _ in range(len(labelmap)+1)] + + # timers + _t = {'im_detect': Timer(), 'misc': Timer()} + output_dir = get_output_dir('ssd300_120000', set_type) + det_file = os.path.join(output_dir, 'detections.pkl') + + detection_list, h_list, w_list = [], [], [] + for i, item in enumerate(dataloador): + # im, gt, h, w = dataset.pull_item(i) + # print(im.shape,h,w) + + x, _, h, w = item + bs, _, _, _ = x.size() + # print(x.size()) + # x = Variable(im.unsqueeze(0)) + if cfg['cuda']: + x = x.cuda() + elif cfg['npu']: + x = x.npu() + _t['im_detect'].tic() + detections = net(x).data + detect_time = _t['im_detect'].toc(average=False) + detection_list.append(detections.cpu()) + h_list.extend(h) + w_list.extend(w) + print('im_detect: {:d}/{:d} {:.3f}s'.format(i + 1, + len(dataloador), detect_time)) + # skip j = 0, because it's the background class + strat_time = time.time() + detections = torch.cat(detection_list, dim=0) + for idx in range(detections.size(0)): + h, w = h_list[idx], w_list[idx] + for j in range(1, detections.size(1)): + #dets = detections[0, j, :] + dets = detections[idx, j, :] + mask = dets[:, 0].gt(0.).expand(5, dets.size(0)).t() + dets = torch.masked_select(dets, mask).view(-1, 5) + if dets.size(0) == 0: + continue + boxes = dets[:, 1:] + boxes[:, 0] *= w + boxes[:, 2] *= w + boxes[:, 1] *= h + boxes[:, 3] *= h + scores = dets[:, 0].cpu().numpy() + cls_dets = np.hstack((boxes.cpu().numpy(), + scores[:, np.newaxis])).astype(np.float32, + copy=False) + # all_boxes[j][i] = cls_dets + all_boxes[j][idx] = cls_dets + end_time = time.time() + print('spend time: %.3fs'%(end_time-strat_time)) + + with open(det_file, 'wb') as f: + pickle.dump(all_boxes, f, pickle.HIGHEST_PROTOCOL) + + print('Evaluating detections') + mAp = evaluate_detections(all_boxes, output_dir, dataset, set_type=set_type) + return mAp + + +def evaluate_detections(box_list, output_dir, dataset, set_type='test'): + write_voc_results_file(box_list, dataset, set_type=set_type) + mAp = do_python_eval(output_dir, set_type=set_type) + return mAp + + + + +if __name__ == '__main__': + pth_path, data_path = sys.argv[1:3] + if not os.path.exists(cfg['save_folder']): + os.makedirs(cfg['save_folder']) + + if torch.cuda.is_available(): + if cfg['cuda']: + torch.set_default_tensor_type('torch.cuda.FloatTensor') + if not cfg['cuda']: + print("WARNING: It looks like you have a CUDA device, but aren't using \ + CUDA. Run with --cuda for optimal eval speed.") + torch.set_default_tensor_type('torch.FloatTensor') + else: + torch.set_default_tensor_type('torch.FloatTensor') + + annopath = os.path.join(data_path, 'VOC2007', 'Annotations', '%s.xml') + imgpath = os.path.join(data_path, 'VOC2007', 'JPEGImages', '%s.jpg') + imgsetpath = os.path.join(data_path, 'VOC2007', 'ImageSets', + 'Main', '{:s}.txt') + YEAR = '2007' + devkit_path = data_path + 'VOC' + YEAR + dataset_mean = (104, 117, 123) + # load net + num_classes = len(labelmap) + 1 # +1 for background + net = build_refinedet('test', int(cfg['input_size']), num_classes, batch_norm=True) # initialize SSD + + + + # load data + set_type = 'test' + dataset = VOCDetection(root=data_path, + image_sets=[('2007', set_type)], + transform=BaseTransform(int(cfg['input_size']), dataset_mean), + target_transform=VOCAnnotationTransform(), + dataset_name='VOC07test') + + if cfg['cuda']: + net = net.cuda() + cudnn.benchmark = True + elif cfg['npu']: + net = net.npu() + cudnn.benchmark = True + + if cfg['amp']: + net = amp.initialize(net, opt_level='O1', loss_scale=128) + + + net.eval() + data_loader = data.DataLoader(dataset, + batch_size=128, + num_workers=16, + shuffle=False, + collate_fn=detection_collate_test, + pin_memory=True) + save_path = './RefineDet320_bn/RefineDet320_VOC_231.pth' + save_path = pth_path + net.load_state_dict(torch.load(save_path, map_location='cpu')) + print('Finished loading model! ' + save_path) + + # evaluation + with torch.no_grad(): + mAp = test_net(cfg['save_folder'], net, cfg['cuda'], dataset, data_loader, + BaseTransform(int(cfg['input_size']), dataset_mean), cfg['top_k'], int(cfg['input_size']), + thresh=cfg['confidence_threshold']) diff --git a/PyTorch/contrib/cv/detection/RefineDet/models/timeAcc.py b/PyTorch/contrib/cv/detection/RefineDet/models/timeAcc.py index 3c81c2329c..91507f0850 100644 --- a/PyTorch/contrib/cv/detection/RefineDet/models/timeAcc.py +++ b/PyTorch/contrib/cv/detection/RefineDet/models/timeAcc.py @@ -1,43 +1,43 @@ -#!/bin/bash -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -class AverageMeter(object): - """Computes and stores the average and current value""" - - def __init__(self, name, fmt=':f', start_count_index=20): - self.name = name - self.fmt = fmt - self.reset() - self.start_count_index = start_count_index - - def reset(self): - self.val = 0 - self.avg = 0 - self.sum = 0 - self.count = 0 - - def update(self, val, n=1): - if self.count == 0: - self.N = n - - self.val = val - self.count += n - if self.count > (self.start_count_index * self.N): - self.sum += val * n - self.avg = self.sum / (self.count - self.start_count_index * self.N) - - def __str__(self): - fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' +#!/bin/bash +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +class AverageMeter(object): + """Computes and stores the average and current value""" + + def __init__(self, name, fmt=':f', start_count_index=20): + self.name = name + self.fmt = fmt + self.reset() + self.start_count_index = start_count_index + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + + def update(self, val, n=1): + if self.count == 0: + self.N = n + + self.val = val + self.count += n + if self.count > (self.start_count_index * self.N): + self.sum += val * n + self.avg = self.sum / (self.count - self.start_count_index * self.N) + + def __str__(self): + fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' return fmtstr.format(**self.__dict__) \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/RefineDet/modelzoo_level.txt b/PyTorch/contrib/cv/detection/RefineDet/modelzoo_level.txt index a17c8f95fa..a829ab59b9 100644 --- a/PyTorch/contrib/cv/detection/RefineDet/modelzoo_level.txt +++ b/PyTorch/contrib/cv/detection/RefineDet/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:NOK +FuncStatus:OK +PerfStatus:NOK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/RefineDet/requirements.txt b/PyTorch/contrib/cv/detection/RefineDet/requirements.txt index 8b4a0d1903..9e1c0e6660 100644 --- a/PyTorch/contrib/cv/detection/RefineDet/requirements.txt +++ b/PyTorch/contrib/cv/detection/RefineDet/requirements.txt @@ -1,10 +1,10 @@ -torch==1.5.0+ascend.post3 -apex==0.1+ascend -future==0.18.2 -numpy==1.21.2 -opencv-python==4.5.3.56 -torchvision==0.2.2 -pillow==8.3.2 -six==1.16.0 -decorator==4.4.2 +torch==1.5.0+ascend.post3 +apex==0.1+ascend +future==0.18.2 +numpy==1.21.2 +opencv-python==4.5.3.56 +torchvision==0.2.2 +pillow==8.3.2 +six==1.16.0 +decorator==4.4.2 sympy==1.4 \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/RefineDet/train_1p.py b/PyTorch/contrib/cv/detection/RefineDet/train_1p.py index fcc73899b3..3a72f53785 100644 --- a/PyTorch/contrib/cv/detection/RefineDet/train_1p.py +++ b/PyTorch/contrib/cv/detection/RefineDet/train_1p.py @@ -1,284 +1,284 @@ -#!/bin/bash -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -# coding=utf-8 -from models.timeAcc import AverageMeter -from data import VOC_CLASSES as labelmap -from data import VOCAnnotationTransform, VOCDetection, BaseTransform -from data import * -from utils.augmentations import SSDAugmentation -from layers.modules import RefineDetMultiBoxLoss -from models.refinedet import build_refinedet -from apex import amp -import apex -import os -import sys -import time -import torch -import torch.nn as nn -import torch.optim as optim -import torch.backends.cudnn as cudnn -import torch.nn.init as init -import torch.utils.data as data -import numpy as np -import argparse -from utils.logging import Logger -from torch.hub import load_state_dict_from_url -import torch.npu -CALCULATE_DEVICE = "npu" - -def str2bool(v): - return v.lower() in ("yes", "true", "t", "1") - -if sys.version_info[0] == 2: - import xml.etree.cElementTree as ET -else: - import xml.etree.ElementTree as ET -parser = argparse.ArgumentParser( - description='Single Shot MultiBox Detector Training With Pytorch') -train_set = parser.add_mutually_exclusive_group() -parser.add_argument('--dataset', default='VOC', choices=['VOC', 'COCO'], - type=str, help='VOC or COCO') -parser.add_argument('--input_size', default='320', choices=['320', '512'], - type=str, help='RefineDet320 or RefineDet512') -parser.add_argument('--dataset_root', default='/home/ljh/refinedet/data/VOCdevkit/', - help='Dataset root directory path') -parser.add_argument('--basenet', default='weights/vgg16_reducedfc.pth', - help='Pretrained base model') -parser.add_argument('--batch_size', default=32, type=int, - help='Batch size for training') -parser.add_argument('--resume', default=None, type=str, - help='Checkpoint state_dict file to resume training from') -parser.add_argument('--start_epoch', default=0, type=int, - help='Resume training at this epoch') -parser.add_argument('--num_epochs', default=232, type=int, - help='Total train epoch') -parser.add_argument('--num_workers', default=14, type=int, - help='Number of workers used in dataloading') -parser.add_argument('--cuda', default=False, type=str2bool, - help='Use CUDA to train model') -parser.add_argument('--npu', default=True, type=str2bool, - help='Use NPU to train model') -parser.add_argument('--lr', '--learning-rate', default=0.00095, type=float, - help='initial learning rate') -parser.add_argument('--momentum', default=0.9, type=float, - help='Momentum value for optim') -parser.add_argument('--weight_decay', default=5e-4, type=float, - help='Weight decay for SGD') -parser.add_argument('--gamma', default=0.1, type=float, - help='Gamma update for SGD') -parser.add_argument('--visdom', default=False, type=str2bool, - help='Use visdom for loss visualization') -parser.add_argument('--save_folder', default='weights/', - help='Directory for saving checkpoint models') -parser.add_argument('--local_rank', default=-1, type=int, - help='node rank for distributed training') -parser.add_argument('--finetune', default=None, type=str, - help='pretrained weight path') -parser.add_argument('--train_1p', default=False, type=str2bool, - help='node rank for distributed training') -parser.add_argument('--device_id', default=0, type=str, - help='device_id') -parser.add_argument('--amp', default=True, type=str2bool, - help='whether to use amp') -parser.add_argument('--num_classes', default=-1, type=int, - help='num classes') -args = parser.parse_args() - - -if torch.cuda.is_available(): - if args.cuda: - torch.set_default_tensor_type('torch.cuda.FloatTensor') - if not args.cuda: - print("WARNING: It looks like you have a CUDA device, but aren't " + - "using CUDA.\nRun with --cuda for optimal training speed.") - torch.set_default_tensor_type('torch.FloatTensor') -else: - torch.set_default_tensor_type('torch.FloatTensor') - -if not os.path.exists(args.save_folder): - os.mkdir(args.save_folder) - -sys.stdout = Logger(os.path.join(args.save_folder, 'log.txt')) - -def train(): - torch.npu.set_device('npu:' + str(args.device_id)) - - if args.dataset == 'VOC': - '''if args.dataset_root == COCO_ROOT: - parser.error('Must specify dataset if specifying dataset_root')''' - cfg = voc_refinedet[args.input_size] - dataset = VOCDetection(root=args.dataset_root, - transform=SSDAugmentation(cfg['min_dim'], MEANS)) # cfg['min_dim'] = 320 - - if args.finetune: - print('finetune numclass %d'%args.num_classes) - refinedet_net = build_refinedet('train', cfg['min_dim'], args.num_classes, batch_norm=True) - else: - refinedet_net = build_refinedet('train', cfg['min_dim'], cfg['num_classes'], batch_norm=True) - net = refinedet_net - if args.cuda: - net = net.cuda() - if args.npu: - net = net.npu() - if args.resume: - print('Resuming training, loading {}...'.format(args.resume)) - refinedet_net.load_weights(args.resume) - else: - print('Loading vgg...') - vgg_weights = load_state_dict_from_url('https://download.pytorch.org/models/vgg16_bn-6c64b313.pth', - progress=True) - from collections import OrderedDict - new_vgg_weights = OrderedDict() - for k, v in vgg_weights.items(): - fc, num, wb = k.split('.') - if fc == 'classifier': - continue - new_k = num + '.' + wb - new_vgg_weights[new_k] = v - refinedet_net.vgg.load_state_dict(new_vgg_weights, strict=False) - if not args.resume: - print('Initializing weights...') - refinedet_net.extras.apply(weights_init) - refinedet_net.arm_loc.apply(weights_init) - refinedet_net.arm_conf.apply(weights_init) - refinedet_net.odm_loc.apply(weights_init) - refinedet_net.odm_conf.apply(weights_init) - refinedet_net.tcb0.apply(weights_init) - refinedet_net.tcb1.apply(weights_init) - refinedet_net.tcb2.apply(weights_init) - optimizer = apex.optimizers.NpuFusedSGD(net.parameters(), lr=args.lr, momentum=args.momentum, - weight_decay=args.weight_decay) - arm_criterion = RefineDetMultiBoxLoss(2, 0.5, True, 0, True, 3, 0.5, - False, args.cuda, npu_device=CALCULATE_DEVICE) - if args.finetune: - stat_dict = torch.load(args.finetune, map_location='cpu') - for k in stat_dict.keys(): - if 'odm_conf' in k: - stat_dict.pop(k) - net.load_state_dict(stat_dict, strict=False) - odm_criterion = RefineDetMultiBoxLoss(args.num_classes, 0.5, True, 0, True, 3, 0.5, - False, args.cuda, use_ARM=True, npu_device=CALCULATE_DEVICE) - else: - odm_criterion = RefineDetMultiBoxLoss(cfg['num_classes'], 0.5, True, 0, True, 3, 0.5, - False, args.cuda, use_ARM=True, npu_device=CALCULATE_DEVICE) - if args.amp: - net, optimizer = amp.initialize(net, optimizer, opt_level='O1', loss_scale=128, combine_grad=True) - if args.cuda: - net = torch.nn.DataParallel(refinedet_net) - cudnn.benchmark = True - net.train() - arm_loc_loss = 0 - arm_conf_loss = 0 - odm_loc_loss = 0 - odm_conf_loss = 0 - print('Loading the dataset...') - epoch_size = len(dataset) // args.batch_size - if len(dataset) % args.batch_size != 0: - epoch_size += 1 - print('Training RefineDet on:', dataset.name) - print('Using the specified args:') - print(args) - step_index = 0 - data_loader = data.DataLoader(dataset, args.batch_size, - num_workers=args.num_workers, - shuffle=True, collate_fn=detection_collate, - pin_memory=True, - drop_last=True) - - if args.resume: - strat_iter = args.start_epoch * epoch_size - for step in cfg['lr_steps']: - if strat_iter > step: - step_index += 1 - adjust_learning_rate(optimizer, args.gamma, step_index) - - for epoch in range(args.start_epoch, args.num_epochs): - avg_time = AverageMeter('iter_time') - print('\n' + 'epoch ' + str(epoch)) - print('================================train model on trainval set================================') - for iteration, (images, targets) in zip(range(epoch * epoch_size, (epoch + 1) * epoch_size), data_loader): - if iteration in cfg['lr_steps']: - step_index += 1 - adjust_learning_rate(optimizer, args.gamma, step_index) - - if args.cuda: - images = images.cuda() - targets = [ann.cuda() for ann in targets] - elif args.npu: - images = images.to(CALCULATE_DEVICE) - targets = [ann.to(CALCULATE_DEVICE) for ann in targets] - else: - images = images - targets = [ann for ann in targets] - t0 = time.time() - out = net(images) - optimizer.zero_grad() - arm_loss_l, arm_loss_c = arm_criterion(out, targets) - odm_loss_l, odm_loss_c = odm_criterion(out, targets) - arm_loss = arm_loss_l + arm_loss_c - odm_loss = odm_loss_l + odm_loss_c - loss = arm_loss + odm_loss - if args.amp: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.step() - t1 = time.time() - arm_loc_loss += arm_loss_l.item() - arm_conf_loss += arm_loss_c.item() - odm_loc_loss += odm_loss_l.item() - odm_conf_loss += odm_loss_c.item() - avg_time.update(t1 - t0) - if iteration % 10 == 0: - print('iter ' + repr( \ - iteration) + ' || ARM_L Loss: %.4f ARM_C Loss: %.4f ODM_L Loss: %.4f ODM_C Loss: %.4f ||' \ - % (arm_loss_l.item(), arm_loss_c.item(), odm_loss_l.item(), odm_loss_c.item()), end=' ') - print('timer: %.4f sec.' % (t1 - t0)) - - print('batch_size = ' + str(args.batch_size) + ' || num_devices = ' + '1' + ' || time_avg = %.4f' % avg_time.avg) - print('FPS = %.4f' % (args.batch_size / avg_time.avg)) - print('Saving state, iter:' + str(epoch_size * (epoch + 1) - 1) + ' , epoch:' + str(epoch)) - save_path = args.save_folder + '/RefineDet{}_{}_{}.pth'.format(args.input_size, args.dataset, epoch) - torch.save(refinedet_net.state_dict(), save_path) - -def adjust_learning_rate(optimizer, gamma, step): - """Sets the learning rate to the initial LR decayed by 10 at every - specified step - # Adapted from PyTorch Imagenet example: - # https://github.com/pytorch/examples/blob/master/imagenet/main.py - """ - lr = args.lr * (gamma ** (step)) - for param_group in optimizer.param_groups: - param_group['lr'] = lr - -def xavier(param): - init.xavier_uniform_(param) - -def weights_init(m): - if isinstance(m, nn.Conv2d): - with torch.no_grad(): - init.xavier_uniform_(m.weight) - with torch.no_grad(): - m.bias.zero_() - elif isinstance(m, nn.ConvTranspose2d): - xavier(m.weight.data) - with torch.no_grad(): - m.bias.zero_() -if __name__ == '__main__': - train() - - +#!/bin/bash +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +# coding=utf-8 +from models.timeAcc import AverageMeter +from data import VOC_CLASSES as labelmap +from data import VOCAnnotationTransform, VOCDetection, BaseTransform +from data import * +from utils.augmentations import SSDAugmentation +from layers.modules import RefineDetMultiBoxLoss +from models.refinedet import build_refinedet +from apex import amp +import apex +import os +import sys +import time +import torch +import torch.nn as nn +import torch.optim as optim +import torch.backends.cudnn as cudnn +import torch.nn.init as init +import torch.utils.data as data +import numpy as np +import argparse +from utils.logging import Logger +from torch.hub import load_state_dict_from_url +import torch.npu +CALCULATE_DEVICE = "npu" + +def str2bool(v): + return v.lower() in ("yes", "true", "t", "1") + +if sys.version_info[0] == 2: + import xml.etree.cElementTree as ET +else: + import xml.etree.ElementTree as ET +parser = argparse.ArgumentParser( + description='Single Shot MultiBox Detector Training With Pytorch') +train_set = parser.add_mutually_exclusive_group() +parser.add_argument('--dataset', default='VOC', choices=['VOC', 'COCO'], + type=str, help='VOC or COCO') +parser.add_argument('--input_size', default='320', choices=['320', '512'], + type=str, help='RefineDet320 or RefineDet512') +parser.add_argument('--dataset_root', default='/home/ljh/refinedet/data/VOCdevkit/', + help='Dataset root directory path') +parser.add_argument('--basenet', default='weights/vgg16_reducedfc.pth', + help='Pretrained base model') +parser.add_argument('--batch_size', default=32, type=int, + help='Batch size for training') +parser.add_argument('--resume', default=None, type=str, + help='Checkpoint state_dict file to resume training from') +parser.add_argument('--start_epoch', default=0, type=int, + help='Resume training at this epoch') +parser.add_argument('--num_epochs', default=232, type=int, + help='Total train epoch') +parser.add_argument('--num_workers', default=14, type=int, + help='Number of workers used in dataloading') +parser.add_argument('--cuda', default=False, type=str2bool, + help='Use CUDA to train model') +parser.add_argument('--npu', default=True, type=str2bool, + help='Use NPU to train model') +parser.add_argument('--lr', '--learning-rate', default=0.00095, type=float, + help='initial learning rate') +parser.add_argument('--momentum', default=0.9, type=float, + help='Momentum value for optim') +parser.add_argument('--weight_decay', default=5e-4, type=float, + help='Weight decay for SGD') +parser.add_argument('--gamma', default=0.1, type=float, + help='Gamma update for SGD') +parser.add_argument('--visdom', default=False, type=str2bool, + help='Use visdom for loss visualization') +parser.add_argument('--save_folder', default='weights/', + help='Directory for saving checkpoint models') +parser.add_argument('--local_rank', default=-1, type=int, + help='node rank for distributed training') +parser.add_argument('--finetune', default=None, type=str, + help='pretrained weight path') +parser.add_argument('--train_1p', default=False, type=str2bool, + help='node rank for distributed training') +parser.add_argument('--device_id', default=0, type=str, + help='device_id') +parser.add_argument('--amp', default=True, type=str2bool, + help='whether to use amp') +parser.add_argument('--num_classes', default=-1, type=int, + help='num classes') +args = parser.parse_args() + + +if torch.cuda.is_available(): + if args.cuda: + torch.set_default_tensor_type('torch.cuda.FloatTensor') + if not args.cuda: + print("WARNING: It looks like you have a CUDA device, but aren't " + + "using CUDA.\nRun with --cuda for optimal training speed.") + torch.set_default_tensor_type('torch.FloatTensor') +else: + torch.set_default_tensor_type('torch.FloatTensor') + +if not os.path.exists(args.save_folder): + os.mkdir(args.save_folder) + +sys.stdout = Logger(os.path.join(args.save_folder, 'log.txt')) + +def train(): + torch.npu.set_device('npu:' + str(args.device_id)) + + if args.dataset == 'VOC': + '''if args.dataset_root == COCO_ROOT: + parser.error('Must specify dataset if specifying dataset_root')''' + cfg = voc_refinedet[args.input_size] + dataset = VOCDetection(root=args.dataset_root, + transform=SSDAugmentation(cfg['min_dim'], MEANS)) # cfg['min_dim'] = 320 + + if args.finetune: + print('finetune numclass %d'%args.num_classes) + refinedet_net = build_refinedet('train', cfg['min_dim'], args.num_classes, batch_norm=True) + else: + refinedet_net = build_refinedet('train', cfg['min_dim'], cfg['num_classes'], batch_norm=True) + net = refinedet_net + if args.cuda: + net = net.cuda() + if args.npu: + net = net.npu() + if args.resume: + print('Resuming training, loading {}...'.format(args.resume)) + refinedet_net.load_weights(args.resume) + else: + print('Loading vgg...') + vgg_weights = load_state_dict_from_url('https://download.pytorch.org/models/vgg16_bn-6c64b313.pth', + progress=True) + from collections import OrderedDict + new_vgg_weights = OrderedDict() + for k, v in vgg_weights.items(): + fc, num, wb = k.split('.') + if fc == 'classifier': + continue + new_k = num + '.' + wb + new_vgg_weights[new_k] = v + refinedet_net.vgg.load_state_dict(new_vgg_weights, strict=False) + if not args.resume: + print('Initializing weights...') + refinedet_net.extras.apply(weights_init) + refinedet_net.arm_loc.apply(weights_init) + refinedet_net.arm_conf.apply(weights_init) + refinedet_net.odm_loc.apply(weights_init) + refinedet_net.odm_conf.apply(weights_init) + refinedet_net.tcb0.apply(weights_init) + refinedet_net.tcb1.apply(weights_init) + refinedet_net.tcb2.apply(weights_init) + optimizer = apex.optimizers.NpuFusedSGD(net.parameters(), lr=args.lr, momentum=args.momentum, + weight_decay=args.weight_decay) + arm_criterion = RefineDetMultiBoxLoss(2, 0.5, True, 0, True, 3, 0.5, + False, args.cuda, npu_device=CALCULATE_DEVICE) + if args.finetune: + stat_dict = torch.load(args.finetune, map_location='cpu') + for k in stat_dict.keys(): + if 'odm_conf' in k: + stat_dict.pop(k) + net.load_state_dict(stat_dict, strict=False) + odm_criterion = RefineDetMultiBoxLoss(args.num_classes, 0.5, True, 0, True, 3, 0.5, + False, args.cuda, use_ARM=True, npu_device=CALCULATE_DEVICE) + else: + odm_criterion = RefineDetMultiBoxLoss(cfg['num_classes'], 0.5, True, 0, True, 3, 0.5, + False, args.cuda, use_ARM=True, npu_device=CALCULATE_DEVICE) + if args.amp: + net, optimizer = amp.initialize(net, optimizer, opt_level='O1', loss_scale=128, combine_grad=True) + if args.cuda: + net = torch.nn.DataParallel(refinedet_net) + cudnn.benchmark = True + net.train() + arm_loc_loss = 0 + arm_conf_loss = 0 + odm_loc_loss = 0 + odm_conf_loss = 0 + print('Loading the dataset...') + epoch_size = len(dataset) // args.batch_size + if len(dataset) % args.batch_size != 0: + epoch_size += 1 + print('Training RefineDet on:', dataset.name) + print('Using the specified args:') + print(args) + step_index = 0 + data_loader = data.DataLoader(dataset, args.batch_size, + num_workers=args.num_workers, + shuffle=True, collate_fn=detection_collate, + pin_memory=True, + drop_last=True) + + if args.resume: + strat_iter = args.start_epoch * epoch_size + for step in cfg['lr_steps']: + if strat_iter > step: + step_index += 1 + adjust_learning_rate(optimizer, args.gamma, step_index) + + for epoch in range(args.start_epoch, args.num_epochs): + avg_time = AverageMeter('iter_time') + print('\n' + 'epoch ' + str(epoch)) + print('================================train model on trainval set================================') + for iteration, (images, targets) in zip(range(epoch * epoch_size, (epoch + 1) * epoch_size), data_loader): + if iteration in cfg['lr_steps']: + step_index += 1 + adjust_learning_rate(optimizer, args.gamma, step_index) + + if args.cuda: + images = images.cuda() + targets = [ann.cuda() for ann in targets] + elif args.npu: + images = images.to(CALCULATE_DEVICE) + targets = [ann.to(CALCULATE_DEVICE) for ann in targets] + else: + images = images + targets = [ann for ann in targets] + t0 = time.time() + out = net(images) + optimizer.zero_grad() + arm_loss_l, arm_loss_c = arm_criterion(out, targets) + odm_loss_l, odm_loss_c = odm_criterion(out, targets) + arm_loss = arm_loss_l + arm_loss_c + odm_loss = odm_loss_l + odm_loss_c + loss = arm_loss + odm_loss + if args.amp: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + optimizer.step() + t1 = time.time() + arm_loc_loss += arm_loss_l.item() + arm_conf_loss += arm_loss_c.item() + odm_loc_loss += odm_loss_l.item() + odm_conf_loss += odm_loss_c.item() + avg_time.update(t1 - t0) + if iteration % 10 == 0: + print('iter ' + repr( \ + iteration) + ' || ARM_L Loss: %.4f ARM_C Loss: %.4f ODM_L Loss: %.4f ODM_C Loss: %.4f ||' \ + % (arm_loss_l.item(), arm_loss_c.item(), odm_loss_l.item(), odm_loss_c.item()), end=' ') + print('timer: %.4f sec.' % (t1 - t0)) + + print('batch_size = ' + str(args.batch_size) + ' || num_devices = ' + '1' + ' || time_avg = %.4f' % avg_time.avg) + print('FPS = %.4f' % (args.batch_size / avg_time.avg)) + print('Saving state, iter:' + str(epoch_size * (epoch + 1) - 1) + ' , epoch:' + str(epoch)) + save_path = args.save_folder + '/RefineDet{}_{}_{}.pth'.format(args.input_size, args.dataset, epoch) + torch.save(refinedet_net.state_dict(), save_path) + +def adjust_learning_rate(optimizer, gamma, step): + """Sets the learning rate to the initial LR decayed by 10 at every + specified step + # Adapted from PyTorch Imagenet example: + # https://github.com/pytorch/examples/blob/master/imagenet/main.py + """ + lr = args.lr * (gamma ** (step)) + for param_group in optimizer.param_groups: + param_group['lr'] = lr + +def xavier(param): + init.xavier_uniform_(param) + +def weights_init(m): + if isinstance(m, nn.Conv2d): + with torch.no_grad(): + init.xavier_uniform_(m.weight) + with torch.no_grad(): + m.bias.zero_() + elif isinstance(m, nn.ConvTranspose2d): + xavier(m.weight.data) + with torch.no_grad(): + m.bias.zero_() +if __name__ == '__main__': + train() + + diff --git a/PyTorch/contrib/cv/detection/RefineDet/train_8p.py b/PyTorch/contrib/cv/detection/RefineDet/train_8p.py index b18c84cf9b..94aeb97265 100644 --- a/PyTorch/contrib/cv/detection/RefineDet/train_8p.py +++ b/PyTorch/contrib/cv/detection/RefineDet/train_8p.py @@ -1,294 +1,294 @@ -#!/bin/bash -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -# coding=utf-8 -import torchvision -from models.timeAcc import AverageMeter -from data import VOC_CLASSES as labelmap -from data import VOCAnnotationTransform, VOCDetection, BaseTransform -from data import * -from utils.augmentations import SSDAugmentation -from layers.modules import RefineDetMultiBoxLoss -from models.refinedet import build_refinedet -from apex import amp -import apex -from torch.hub import load_state_dict_from_url -import os -import sys -import time -import torch -import torch.nn as nn -import torch.optim as optim -import torch.backends.cudnn as cudnn -import torch.nn.init as init -import torch.utils.data as data -import numpy as np -import argparse -from utils.logging import Logger -import torch.npu -import torch.distributed as dist -import torch.multiprocessing as mp -CALCULATE_DEVICE = "npu" -def str2bool(v): - return v.lower() in ("yes", "true", "t", "1") -if sys.version_info[0] == 2: - import xml.etree.cElementTree as ET -else: - import xml.etree.ElementTree as ET -parser = argparse.ArgumentParser( - description='Single Shot MultiBox Detector Training With Pytorch') -train_set = parser.add_mutually_exclusive_group() -parser.add_argument('--dataset', default='VOC', choices=['VOC', 'COCO'], - type=str, help='VOC or COCO') -parser.add_argument('--input_size', default='320', choices=['320', '512'], - type=str, help='RefineDet320 or RefineDet512') -parser.add_argument('--data_path', default='./data/VOCdevkit', - help='Dataset root directory path') -parser.add_argument('--dataset_root', default='./data/VOCdevkit', - help='Dataset root directory path') -parser.add_argument('--basenet', default='weights/vgg16_reducedfc.pth', - help='Pretrained base model') -parser.add_argument('--batch_size', default=32, type=int, - help='Batch size for training') -parser.add_argument('--resume', default=None, type=str, - help='Checkpoint state_dict file to resume training from') -parser.add_argument('--start_epoch', default=0, type=int, - help='Resume training at this epoch') -parser.add_argument('--num_epochs', default=232, type=int, - help='Total train epoch') -parser.add_argument('--num_workers', default=8, type=int, - help='Number of workers used in dataloading') -parser.add_argument('--cuda', default=False, type=str2bool, - help='Use CUDA to train model') -parser.add_argument('--npu', default=True, type=str2bool, - help='Use NPU to train model') -parser.add_argument('--lr', '--learning-rate', default=0.00095, type=float, - help='initial learning rate') -parser.add_argument('--momentum', default=0.9, type=float, - help='Momentum value for optim') -parser.add_argument('--weight_decay', default=5e-4, type=float, - help='Weight decay for SGD') -parser.add_argument('--gamma', default=0.1, type=float, - help='Gamma update for SGD') -parser.add_argument('--visdom', default=False, type=str2bool, - help='Use visdom for loss visualization') -parser.add_argument('--save_folder', default='weights/', - help='Directory for saving checkpoint models') -parser.add_argument('--local_rank', default=0, type=int, - help='node rank for distributed training') -parser.add_argument('--world_size', default=8, type=int) -parser.add_argument('--bn', default=False, type=str2bool, - help='whether to use BN') -parser.add_argument('--amp', default=True, type=str2bool, - help='whether to use amp') -args = parser.parse_args() - -if torch.cuda.is_available(): - if args.cuda: - torch.set_default_tensor_type('torch.cuda.FloatTensor') - if not args.cuda: - print("WARNING: It looks like you have a CUDA device, but aren't " + - "using CUDA.\nRun with --cuda for optimal training speed.") - torch.set_default_tensor_type('torch.FloatTensor') -else: - torch.set_default_tensor_type('torch.FloatTensor') - -if args.local_rank == 0 and os.path.exists(args.save_folder)==False: - os.mkdir(args.save_folder) - -sys.stdout = Logger(os.path.join(args.save_folder, 'log.txt')) - - - -def init_dist(backend='hccl', **kwargs): - os.environ['MASTER_ADDR'] = "127.0.0.1" - os.environ['MASTER_PORT'] = '29530' - rank = int(args.local_rank) - num_npus = torch.npu.device_count() - dist.init_process_group(backend=backend, world_size=args.world_size, rank=rank) - print(args.world_size, rank) - torch.npu.set_device(rank % num_npus) - torch.backends.cudnn.benchmark = True - args.lr = args.lr * 8 - print('lr = ', args.lr) - -def train(): - import warnings - warnings.filterwarnings('ignore', category=Warning) - init_dist() - if args.dataset == 'VOC': - '''if args.dataset_root == COCO_ROOT: - parser.error('Must specify dataset if specifying dataset_root')''' - cfg = voc_refinedet[args.input_size] - dataset = VOCDetection(root=args.dataset_root, - transform=SSDAugmentation(cfg['min_dim'], - MEANS)) - refinedet_net = build_refinedet('train', cfg['min_dim'], cfg['num_classes'], batch_norm=args.bn) - net = refinedet_net - if args.npu: - net = net.npu() - optimizer = apex.optimizers.NpuFusedSGD(net.parameters(), lr=args.lr, momentum=args.momentum, - weight_decay=args.weight_decay) - arm_criterion = RefineDetMultiBoxLoss(2, 0.5, True, 0, True, 3, 0.5, - False, args.cuda, npu_device=CALCULATE_DEVICE) - odm_criterion = RefineDetMultiBoxLoss(cfg['num_classes'], 0.5, True, 0, True, 3, 0.5, - False, args.cuda, use_ARM=True, npu_device=CALCULATE_DEVICE) - if args.amp: - net, optimizer = amp.initialize(net, optimizer, opt_level='O1', loss_scale=128, combine_grad=True) - if torch.npu.device_count() > 1: - print('ddp') - net = nn.parallel.DistributedDataParallel(net, device_ids=[args.local_rank], broadcast_buffers=False) - if args.resume: - print('Resuming training, loading {}...'.format(args.resume)) - refinedet_net.load_weights(args.resume) - else: - print('Loading vgg...') - vgg_weights = load_state_dict_from_url('https://download.pytorch.org/models/vgg16_bn-6c64b313.pth', - progress=True) - from collections import OrderedDict - new_vgg_weights = OrderedDict() - for k, v in vgg_weights.items(): - fc, num, wb = k.split('.') - if fc == 'classifier': - continue - new_k = num + '.' + wb - new_vgg_weights[new_k] = v - refinedet_net.vgg.load_state_dict(new_vgg_weights, strict=False) - if not args.resume: - print('Initializing weights...') - refinedet_net.extras.apply(weights_init) - refinedet_net.arm_loc.apply(weights_init) - refinedet_net.arm_conf.apply(weights_init) - refinedet_net.odm_loc.apply(weights_init) - refinedet_net.odm_conf.apply(weights_init) - refinedet_net.tcb0.apply(weights_init) - refinedet_net.tcb1.apply(weights_init) - refinedet_net.tcb2.apply(weights_init) - - net.train() - arm_loc_loss = 0 - arm_conf_loss = 0 - odm_loc_loss = 0 - odm_conf_loss = 0 - epoch_size = len(dataset) // args.batch_size // args.world_size - if args.local_rank == 0: - print('Training RefineDet on:', dataset.name) - print('Using the specified args:') - print(args) - step_index = 0 - train_sampler = torch.utils.data.DistributedSampler(dataset) - data_loader = data.DataLoader(dataset=dataset, - batch_size=args.batch_size, - shuffle=False, - num_workers=args.num_workers, - pin_memory=False, - sampler=train_sampler, - collate_fn=detection_collate, - drop_last=True) - iteration = 0 - if args.resume: - iteration = args.start_epoch * epoch_size - for epoch_step in cfg['lr_step_epoch']: - if args.start_epoch > epoch_step: - step_index += 1 - adjust_learning_rate(optimizer, args.gamma, step_index) - for epoch in range(args.start_epoch, args.num_epochs): - train_sampler.set_epoch(epoch) - if epoch in cfg['lr_step_epoch']: - step_index += 1 - adjust_learning_rate(optimizer, args.gamma, step_index) - avg_time = AverageMeter('iter_time') - if args.local_rank == 0: - print('\n' + 'epoch ' + str(epoch)) - print('================================train model on trainval set================================') - for images, targets in data_loader: - if args.cuda: - images = images.cuda() - targets = [ann.cuda() for ann in targets] - elif args.npu: - images = images.to(CALCULATE_DEVICE) - targets = [ann.to(CALCULATE_DEVICE) for ann in targets] - else: - images = images - targets = [ann for ann in targets] - - t0 = time.time() - out = net(images) - optimizer.zero_grad() - arm_loss_l, arm_loss_c = arm_criterion(out, targets) - odm_loss_l, odm_loss_c = odm_criterion(out, targets) - arm_loss = arm_loss_l + arm_loss_c - odm_loss = odm_loss_l + odm_loss_c - loss = arm_loss + odm_loss - if args.amp: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.step() - t1 = time.time() - arm_loc_loss += arm_loss_l.item() - arm_conf_loss += arm_loss_c.item() - odm_loc_loss += odm_loss_l.item() - odm_conf_loss += odm_loss_c.item() - avg_time.update(t1 - t0) - if iteration % 10 == 0 and args.local_rank == 0: - print('iter ' + repr( - iteration) + ' || ARM_L Loss: %.4f ARM_C Loss: %.4f ODM_L Loss: %.4f ODM_C Loss: %.4f ||'\ - % (arm_loss_l.item(), arm_loss_c.item(), odm_loss_l.item(), odm_loss_c.item()), end=' ') - print('timer: %.4f sec.' % (t1 - t0)) - iteration += 1 - if args.local_rank == 0: - print('batch_size = ' + str(args.batch_size) + ' || num_devices = ' + str( - torch.npu.device_count()) + ' || time_avg = %.4f' % avg_time.avg) - print('FPS = %.4f' % (args.batch_size * torch.npu.device_count() / avg_time.avg)) - print('Saving state, iter:' + str(iteration) + ' , epoch:' + str(epoch)) - save_path = args.save_folder + '/RefineDet{}_{}_{}.pth'.format(args.input_size, args.dataset, epoch) - torch.save(refinedet_net.state_dict(), save_path) - - -def adjust_learning_rate(optimizer, gamma, step): - """Sets the learning rate to the initial LR decayed by 10 at every - specified step - # Adapted from PyTorch Imagenet example: - # https://github.com/pytorch/examples/blob/master/imagenet/main.py - """ - lr = args.lr * (gamma ** (step)) - for param_group in optimizer.param_groups: - param_group['lr'] = lr - - -def xavier(param): - init.xavier_uniform_(param) - - -def weights_init(m): - if isinstance(m, nn.Conv2d): - with torch.no_grad(): - init.xavier_uniform_(m.weight) - with torch.no_grad(): - m.bias.zero_() - - - elif isinstance(m, nn.ConvTranspose2d): - xavier(m.weight.data) - with torch.no_grad(): - m.bias.zero_() - -if __name__ == '__main__': - - train() - - +#!/bin/bash +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +# coding=utf-8 +import torchvision +from models.timeAcc import AverageMeter +from data import VOC_CLASSES as labelmap +from data import VOCAnnotationTransform, VOCDetection, BaseTransform +from data import * +from utils.augmentations import SSDAugmentation +from layers.modules import RefineDetMultiBoxLoss +from models.refinedet import build_refinedet +from apex import amp +import apex +from torch.hub import load_state_dict_from_url +import os +import sys +import time +import torch +import torch.nn as nn +import torch.optim as optim +import torch.backends.cudnn as cudnn +import torch.nn.init as init +import torch.utils.data as data +import numpy as np +import argparse +from utils.logging import Logger +import torch.npu +import torch.distributed as dist +import torch.multiprocessing as mp +CALCULATE_DEVICE = "npu" +def str2bool(v): + return v.lower() in ("yes", "true", "t", "1") +if sys.version_info[0] == 2: + import xml.etree.cElementTree as ET +else: + import xml.etree.ElementTree as ET +parser = argparse.ArgumentParser( + description='Single Shot MultiBox Detector Training With Pytorch') +train_set = parser.add_mutually_exclusive_group() +parser.add_argument('--dataset', default='VOC', choices=['VOC', 'COCO'], + type=str, help='VOC or COCO') +parser.add_argument('--input_size', default='320', choices=['320', '512'], + type=str, help='RefineDet320 or RefineDet512') +parser.add_argument('--data_path', default='./data/VOCdevkit', + help='Dataset root directory path') +parser.add_argument('--dataset_root', default='./data/VOCdevkit', + help='Dataset root directory path') +parser.add_argument('--basenet', default='weights/vgg16_reducedfc.pth', + help='Pretrained base model') +parser.add_argument('--batch_size', default=32, type=int, + help='Batch size for training') +parser.add_argument('--resume', default=None, type=str, + help='Checkpoint state_dict file to resume training from') +parser.add_argument('--start_epoch', default=0, type=int, + help='Resume training at this epoch') +parser.add_argument('--num_epochs', default=232, type=int, + help='Total train epoch') +parser.add_argument('--num_workers', default=8, type=int, + help='Number of workers used in dataloading') +parser.add_argument('--cuda', default=False, type=str2bool, + help='Use CUDA to train model') +parser.add_argument('--npu', default=True, type=str2bool, + help='Use NPU to train model') +parser.add_argument('--lr', '--learning-rate', default=0.00095, type=float, + help='initial learning rate') +parser.add_argument('--momentum', default=0.9, type=float, + help='Momentum value for optim') +parser.add_argument('--weight_decay', default=5e-4, type=float, + help='Weight decay for SGD') +parser.add_argument('--gamma', default=0.1, type=float, + help='Gamma update for SGD') +parser.add_argument('--visdom', default=False, type=str2bool, + help='Use visdom for loss visualization') +parser.add_argument('--save_folder', default='weights/', + help='Directory for saving checkpoint models') +parser.add_argument('--local_rank', default=0, type=int, + help='node rank for distributed training') +parser.add_argument('--world_size', default=8, type=int) +parser.add_argument('--bn', default=False, type=str2bool, + help='whether to use BN') +parser.add_argument('--amp', default=True, type=str2bool, + help='whether to use amp') +args = parser.parse_args() + +if torch.cuda.is_available(): + if args.cuda: + torch.set_default_tensor_type('torch.cuda.FloatTensor') + if not args.cuda: + print("WARNING: It looks like you have a CUDA device, but aren't " + + "using CUDA.\nRun with --cuda for optimal training speed.") + torch.set_default_tensor_type('torch.FloatTensor') +else: + torch.set_default_tensor_type('torch.FloatTensor') + +if args.local_rank == 0 and os.path.exists(args.save_folder)==False: + os.mkdir(args.save_folder) + +sys.stdout = Logger(os.path.join(args.save_folder, 'log.txt')) + + + +def init_dist(backend='hccl', **kwargs): + os.environ['MASTER_ADDR'] = "127.0.0.1" + os.environ['MASTER_PORT'] = '29530' + rank = int(args.local_rank) + num_npus = torch.npu.device_count() + dist.init_process_group(backend=backend, world_size=args.world_size, rank=rank) + print(args.world_size, rank) + torch.npu.set_device(rank % num_npus) + torch.backends.cudnn.benchmark = True + args.lr = args.lr * 8 + print('lr = ', args.lr) + +def train(): + import warnings + warnings.filterwarnings('ignore', category=Warning) + init_dist() + if args.dataset == 'VOC': + '''if args.dataset_root == COCO_ROOT: + parser.error('Must specify dataset if specifying dataset_root')''' + cfg = voc_refinedet[args.input_size] + dataset = VOCDetection(root=args.dataset_root, + transform=SSDAugmentation(cfg['min_dim'], + MEANS)) + refinedet_net = build_refinedet('train', cfg['min_dim'], cfg['num_classes'], batch_norm=args.bn) + net = refinedet_net + if args.npu: + net = net.npu() + optimizer = apex.optimizers.NpuFusedSGD(net.parameters(), lr=args.lr, momentum=args.momentum, + weight_decay=args.weight_decay) + arm_criterion = RefineDetMultiBoxLoss(2, 0.5, True, 0, True, 3, 0.5, + False, args.cuda, npu_device=CALCULATE_DEVICE) + odm_criterion = RefineDetMultiBoxLoss(cfg['num_classes'], 0.5, True, 0, True, 3, 0.5, + False, args.cuda, use_ARM=True, npu_device=CALCULATE_DEVICE) + if args.amp: + net, optimizer = amp.initialize(net, optimizer, opt_level='O1', loss_scale=128, combine_grad=True) + if torch.npu.device_count() > 1: + print('ddp') + net = nn.parallel.DistributedDataParallel(net, device_ids=[args.local_rank], broadcast_buffers=False) + if args.resume: + print('Resuming training, loading {}...'.format(args.resume)) + refinedet_net.load_weights(args.resume) + else: + print('Loading vgg...') + vgg_weights = load_state_dict_from_url('https://download.pytorch.org/models/vgg16_bn-6c64b313.pth', + progress=True) + from collections import OrderedDict + new_vgg_weights = OrderedDict() + for k, v in vgg_weights.items(): + fc, num, wb = k.split('.') + if fc == 'classifier': + continue + new_k = num + '.' + wb + new_vgg_weights[new_k] = v + refinedet_net.vgg.load_state_dict(new_vgg_weights, strict=False) + if not args.resume: + print('Initializing weights...') + refinedet_net.extras.apply(weights_init) + refinedet_net.arm_loc.apply(weights_init) + refinedet_net.arm_conf.apply(weights_init) + refinedet_net.odm_loc.apply(weights_init) + refinedet_net.odm_conf.apply(weights_init) + refinedet_net.tcb0.apply(weights_init) + refinedet_net.tcb1.apply(weights_init) + refinedet_net.tcb2.apply(weights_init) + + net.train() + arm_loc_loss = 0 + arm_conf_loss = 0 + odm_loc_loss = 0 + odm_conf_loss = 0 + epoch_size = len(dataset) // args.batch_size // args.world_size + if args.local_rank == 0: + print('Training RefineDet on:', dataset.name) + print('Using the specified args:') + print(args) + step_index = 0 + train_sampler = torch.utils.data.DistributedSampler(dataset) + data_loader = data.DataLoader(dataset=dataset, + batch_size=args.batch_size, + shuffle=False, + num_workers=args.num_workers, + pin_memory=False, + sampler=train_sampler, + collate_fn=detection_collate, + drop_last=True) + iteration = 0 + if args.resume: + iteration = args.start_epoch * epoch_size + for epoch_step in cfg['lr_step_epoch']: + if args.start_epoch > epoch_step: + step_index += 1 + adjust_learning_rate(optimizer, args.gamma, step_index) + for epoch in range(args.start_epoch, args.num_epochs): + train_sampler.set_epoch(epoch) + if epoch in cfg['lr_step_epoch']: + step_index += 1 + adjust_learning_rate(optimizer, args.gamma, step_index) + avg_time = AverageMeter('iter_time') + if args.local_rank == 0: + print('\n' + 'epoch ' + str(epoch)) + print('================================train model on trainval set================================') + for images, targets in data_loader: + if args.cuda: + images = images.cuda() + targets = [ann.cuda() for ann in targets] + elif args.npu: + images = images.to(CALCULATE_DEVICE) + targets = [ann.to(CALCULATE_DEVICE) for ann in targets] + else: + images = images + targets = [ann for ann in targets] + + t0 = time.time() + out = net(images) + optimizer.zero_grad() + arm_loss_l, arm_loss_c = arm_criterion(out, targets) + odm_loss_l, odm_loss_c = odm_criterion(out, targets) + arm_loss = arm_loss_l + arm_loss_c + odm_loss = odm_loss_l + odm_loss_c + loss = arm_loss + odm_loss + if args.amp: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + optimizer.step() + t1 = time.time() + arm_loc_loss += arm_loss_l.item() + arm_conf_loss += arm_loss_c.item() + odm_loc_loss += odm_loss_l.item() + odm_conf_loss += odm_loss_c.item() + avg_time.update(t1 - t0) + if iteration % 10 == 0 and args.local_rank == 0: + print('iter ' + repr( + iteration) + ' || ARM_L Loss: %.4f ARM_C Loss: %.4f ODM_L Loss: %.4f ODM_C Loss: %.4f ||'\ + % (arm_loss_l.item(), arm_loss_c.item(), odm_loss_l.item(), odm_loss_c.item()), end=' ') + print('timer: %.4f sec.' % (t1 - t0)) + iteration += 1 + if args.local_rank == 0: + print('batch_size = ' + str(args.batch_size) + ' || num_devices = ' + str( + torch.npu.device_count()) + ' || time_avg = %.4f' % avg_time.avg) + print('FPS = %.4f' % (args.batch_size * torch.npu.device_count() / avg_time.avg)) + print('Saving state, iter:' + str(iteration) + ' , epoch:' + str(epoch)) + save_path = args.save_folder + '/RefineDet{}_{}_{}.pth'.format(args.input_size, args.dataset, epoch) + torch.save(refinedet_net.state_dict(), save_path) + + +def adjust_learning_rate(optimizer, gamma, step): + """Sets the learning rate to the initial LR decayed by 10 at every + specified step + # Adapted from PyTorch Imagenet example: + # https://github.com/pytorch/examples/blob/master/imagenet/main.py + """ + lr = args.lr * (gamma ** (step)) + for param_group in optimizer.param_groups: + param_group['lr'] = lr + + +def xavier(param): + init.xavier_uniform_(param) + + +def weights_init(m): + if isinstance(m, nn.Conv2d): + with torch.no_grad(): + init.xavier_uniform_(m.weight) + with torch.no_grad(): + m.bias.zero_() + + + elif isinstance(m, nn.ConvTranspose2d): + xavier(m.weight.data) + with torch.no_grad(): + m.bias.zero_() + +if __name__ == '__main__': + + train() + + diff --git a/PyTorch/contrib/cv/detection/RefineDet/utils/augmentations.py b/PyTorch/contrib/cv/detection/RefineDet/utils/augmentations.py index d84874a863..dfbb0e36d4 100644 --- a/PyTorch/contrib/cv/detection/RefineDet/utils/augmentations.py +++ b/PyTorch/contrib/cv/detection/RefineDet/utils/augmentations.py @@ -1,433 +1,433 @@ -#!/bin/bash -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 torch -from torchvision import transforms -import cv2 -import numpy as np -import types -from numpy import random -np.warnings.filterwarnings('ignore', category=np.VisibleDeprecationWarning) - - -def intersect(box_a, box_b): - max_xy = np.minimum(box_a[:, 2:], box_b[2:]) - min_xy = np.maximum(box_a[:, :2], box_b[:2]) - inter = np.clip((max_xy - min_xy), a_min=0, a_max=np.inf) - return inter[:, 0] * inter[:, 1] - - -def jaccard_numpy(box_a, box_b): - """Compute the jaccard overlap of two sets of boxes. The jaccard overlap - is simply the intersection over union of two boxes. - E.g.: - A ∩ B / A ∪ B = A ∩ B / (area(A) + area(B) - A ∩ B) - Args: - box_a: Multiple bounding boxes, Shape: [num_boxes,4] - box_b: Single bounding box, Shape: [4] - Return: - jaccard overlap: Shape: [box_a.shape[0], box_a.shape[1]] - """ - inter = intersect(box_a, box_b) - area_a = ((box_a[:, 2]-box_a[:, 0]) * - (box_a[:, 3]-box_a[:, 1])) # [A,B] - area_b = ((box_b[2]-box_b[0]) * - (box_b[3]-box_b[1])) # [A,B] - union = area_a + area_b - inter - return inter / union # [A,B] - - -class Compose(object): - """Composes several augmentations together. - Args: - transforms (List[Transform]): list of transforms to compose. - Example: - >>> augmentations.Compose([ - >>> transforms.CenterCrop(10), - >>> transforms.ToTensor(), - >>> ]) - """ - - def __init__(self, transforms): - self.transforms = transforms - - def __call__(self, img, boxes=None, labels=None): - for t in self.transforms: - img, boxes, labels = t(img, boxes, labels) - return img, boxes, labels - - -class Lambda(object): - """Applies a lambda as a transform.""" - - def __init__(self, lambd): - assert isinstance(lambd, types.LambdaType) - self.lambd = lambd - - def __call__(self, img, boxes=None, labels=None): - return self.lambd(img, boxes, labels) - - -class ConvertFromInts(object): - def __call__(self, image, boxes=None, labels=None): - return image.astype(np.float32), boxes, labels - - -class SubtractMeans(object): - def __init__(self, mean): - self.mean = np.array(mean, dtype=np.float32) - - def __call__(self, image, boxes=None, labels=None): - image = image.astype(np.float32) - image -= self.mean - return image.astype(np.float32), boxes, labels - - -class ToAbsoluteCoords(object): - def __call__(self, image, boxes=None, labels=None): - height, width, channels = image.shape - boxes[:, 0] *= width - boxes[:, 2] *= width - boxes[:, 1] *= height - boxes[:, 3] *= height - - return image, boxes, labels - - -class ToPercentCoords(object): - def __call__(self, image, boxes=None, labels=None): - height, width, channels = image.shape - boxes[:, 0] /= width - boxes[:, 2] /= width - boxes[:, 1] /= height - boxes[:, 3] /= height - - return image, boxes, labels - - -class Resize(object): - def __init__(self, size=300): - self.size = size - - def __call__(self, image, boxes=None, labels=None): - image = cv2.resize(image, (self.size, - self.size)) - return image, boxes, labels - - -class RandomSaturation(object): - def __init__(self, lower=0.5, upper=1.5): - self.lower = lower - self.upper = upper - assert self.upper >= self.lower, "contrast upper must be >= lower." - assert self.lower >= 0, "contrast lower must be non-negative." - - def __call__(self, image, boxes=None, labels=None): - if random.randint(2): - image[:, :, 1] *= random.uniform(self.lower, self.upper) - - return image, boxes, labels - - -class RandomHue(object): - def __init__(self, delta=18.0): - assert delta >= 0.0 and delta <= 360.0 - self.delta = delta - - def __call__(self, image, boxes=None, labels=None): - if random.randint(2): - image[:, :, 0] += random.uniform(-self.delta, self.delta) - image[:, :, 0][image[:, :, 0] > 360.0] -= 360.0 - image[:, :, 0][image[:, :, 0] < 0.0] += 360.0 - return image, boxes, labels - - -class RandomLightingNoise(object): - def __init__(self): - self.perms = ((0, 1, 2), (0, 2, 1), - (1, 0, 2), (1, 2, 0), - (2, 0, 1), (2, 1, 0)) - - def __call__(self, image, boxes=None, labels=None): - if random.randint(2): - swap = self.perms[random.randint(len(self.perms))] - shuffle = SwapChannels(swap) # shuffle channels - image = shuffle(image) - return image, boxes, labels - - -class ConvertColor(object): - def __init__(self, current='BGR', transform='HSV'): - self.transform = transform - self.current = current - - def __call__(self, image, boxes=None, labels=None): - if self.current == 'BGR' and self.transform == 'HSV': - image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) - elif self.current == 'HSV' and self.transform == 'BGR': - image = cv2.cvtColor(image, cv2.COLOR_HSV2BGR) - else: - raise NotImplementedError - return image, boxes, labels - - -class RandomContrast(object): - def __init__(self, lower=0.5, upper=1.5): - self.lower = lower - self.upper = upper - assert self.upper >= self.lower, "contrast upper must be >= lower." - assert self.lower >= 0, "contrast lower must be non-negative." - - # expects float image - def __call__(self, image, boxes=None, labels=None): - if random.randint(2): - alpha = random.uniform(self.lower, self.upper) - image *= alpha - return image, boxes, labels - - -class RandomBrightness(object): - def __init__(self, delta=32): - assert delta >= 0.0 - assert delta <= 255.0 - self.delta = delta - - def __call__(self, image, boxes=None, labels=None): - if random.randint(2): - delta = random.uniform(-self.delta, self.delta) - image += delta - return image, boxes, labels - - -class ToCV2Image(object): - def __call__(self, tensor, boxes=None, labels=None): - return tensor.cpu().numpy().astype(np.float32).transpose((1, 2, 0)), boxes, labels - - -class ToTensor(object): - def __call__(self, cvimage, boxes=None, labels=None): - return torch.from_numpy(cvimage.astype(np.float32)).permute(2, 0, 1), boxes, labels - - -class RandomSampleCrop(object): - """Crop - Arguments: - img (Image): the image being input during training - boxes (Tensor): the original bounding boxes in pt form - labels (Tensor): the class labels for each bbox - mode (float tuple): the min and max jaccard overlaps - Return: - (img, boxes, classes) - img (Image): the cropped image - boxes (Tensor): the adjusted bounding boxes in pt form - labels (Tensor): the class labels for each bbox - """ - def __init__(self): - self.sample_options = ( - # using entire original input image - None, - # sample a patch s.t. MIN jaccard w/ obj in .1,.3,.4,.7,.9 - (0.1, None), - (0.3, None), - (0.7, None), - (0.9, None), - # randomly sample a patch - (None, None), - ) - - def __call__(self, image, boxes=None, labels=None): - height, width, _ = image.shape - while True: - # randomly choose a mode - mode = random.choice(self.sample_options) - if mode is None: - return image, boxes, labels - - min_iou, max_iou = mode - if min_iou is None: - min_iou = float('-inf') - if max_iou is None: - max_iou = float('inf') - - # max trails (50) - for _ in range(50): - current_image = image - - w = random.uniform(0.3 * width, width) - h = random.uniform(0.3 * height, height) - - # aspect ratio constraint b/t .5 & 2 - if h / w < 0.5 or h / w > 2: - continue - - left = random.uniform(width - w) - top = random.uniform(height - h) - - # convert to integer rect x1,y1,x2,y2 - rect = np.array([int(left), int(top), int(left+w), int(top+h)]) - - # calculate IoU (jaccard overlap) b/t the cropped and gt boxes - overlap = jaccard_numpy(boxes, rect) # boxes tensor x,y的绝对坐标 rect 剪裁的 x,y 坐标 - - # is min and max overlap constraint satisfied? if not try again - if overlap.min() < min_iou and max_iou < overlap.max(): - continue - - # cut the crop from the image - current_image = current_image[rect[1]:rect[3], rect[0]:rect[2], - :] - - # keep overlap with gt box IF center in sampled patch - centers = (boxes[:, :2] + boxes[:, 2:]) / 2.0 - - # mask in all gt boxes that above and to the left of centers - m1 = (rect[0] < centers[:, 0]) * (rect[1] < centers[:, 1]) - - # mask in all gt boxes that under and to the right of centers - m2 = (rect[2] > centers[:, 0]) * (rect[3] > centers[:, 1]) - - # mask in that both m1 and m2 are true - mask = m1 * m2 - - # have any valid boxes? try again if not - if not mask.any(): - continue - - # take only matching gt boxes - current_boxes = boxes[mask, :].copy() - - # take only matching gt labels - current_labels = labels[mask] - - # should we use the box left and top corner or the crop's - current_boxes[:, :2] = np.maximum(current_boxes[:, :2], - rect[:2]) - # adjust to crop (by substracting crop's left,top) - current_boxes[:, :2] -= rect[:2] - - current_boxes[:, 2:] = np.minimum(current_boxes[:, 2:], - rect[2:]) - # adjust to crop (by substracting crop's left,top) - current_boxes[:, 2:] -= rect[:2] - - return current_image, current_boxes, current_labels - - -class Expand(object): - def __init__(self, mean): - self.mean = mean - - def __call__(self, image, boxes, labels): - if random.randint(2): - return image, boxes, labels - - height, width, depth = image.shape - ratio = random.uniform(1, 4) - left = random.uniform(0, width*ratio - width) - top = random.uniform(0, height*ratio - height) - - expand_image = np.zeros( - (int(height*ratio), int(width*ratio), depth), - dtype=image.dtype) - expand_image[:, :, :] = self.mean - expand_image[int(top):int(top + height), - int(left):int(left + width)] = image - image = expand_image - - boxes = boxes.copy() - boxes[:, :2] += (int(left), int(top)) - boxes[:, 2:] += (int(left), int(top)) - - return image, boxes, labels - - -class RandomMirror(object): - def __call__(self, image, boxes, classes): - _, width, _ = image.shape - if random.randint(2): - image = image[:, ::-1] - boxes = boxes.copy() - boxes[:, 0::2] = width - boxes[:, 2::-2] - return image, boxes, classes - - -class SwapChannels(object): - """Transforms a tensorized image by swapping the channels in the order - specified in the swap tuple. - Args: - swaps (int triple): final order of channels - eg: (2, 1, 0) - """ - - def __init__(self, swaps): - self.swaps = swaps - - def __call__(self, image): - """ - Args: - image (Tensor): image tensor to be transformed - Return: - a tensor with channels swapped according to swap - """ - # if torch.is_tensor(image): - # image = image.data.cpu().numpy() - # else: - # image = np.array(image) - image = image[:, :, self.swaps] - return image - - -class PhotometricDistort(object): - def __init__(self): - self.pd = [ - RandomContrast(), - ConvertColor(transform='HSV'), - RandomSaturation(), - RandomHue(), - ConvertColor(current='HSV', transform='BGR'), - RandomContrast() - ] - self.rand_brightness = RandomBrightness() - self.rand_light_noise = RandomLightingNoise() - - def __call__(self, image, boxes, labels): - im = image.copy() - im, boxes, labels = self.rand_brightness(im, boxes, labels) - if random.randint(2): - distort = Compose(self.pd[:-1]) - else: - distort = Compose(self.pd[1:]) - im, boxes, labels = distort(im, boxes, labels) - return self.rand_light_noise(im, boxes, labels) - - -class SSDAugmentation(object): - def __init__(self, size=300, mean=(104, 117, 123)): - self.mean = mean - self.size = size - self.augment = Compose([ - ConvertFromInts(), # int 转化为 float32 - ToAbsoluteCoords(), - PhotometricDistort(), - Expand(self.mean), - RandomSampleCrop(), - RandomMirror(), - ToPercentCoords(), - Resize(self.size), - SubtractMeans(self.mean) - ]) - - def __call__(self, img, boxes, labels): - return self.augment(img, boxes, labels) +#!/bin/bash +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 torch +from torchvision import transforms +import cv2 +import numpy as np +import types +from numpy import random +np.warnings.filterwarnings('ignore', category=np.VisibleDeprecationWarning) + + +def intersect(box_a, box_b): + max_xy = np.minimum(box_a[:, 2:], box_b[2:]) + min_xy = np.maximum(box_a[:, :2], box_b[:2]) + inter = np.clip((max_xy - min_xy), a_min=0, a_max=np.inf) + return inter[:, 0] * inter[:, 1] + + +def jaccard_numpy(box_a, box_b): + """Compute the jaccard overlap of two sets of boxes. The jaccard overlap + is simply the intersection over union of two boxes. + E.g.: + A ∩ B / A ∪ B = A ∩ B / (area(A) + area(B) - A ∩ B) + Args: + box_a: Multiple bounding boxes, Shape: [num_boxes,4] + box_b: Single bounding box, Shape: [4] + Return: + jaccard overlap: Shape: [box_a.shape[0], box_a.shape[1]] + """ + inter = intersect(box_a, box_b) + area_a = ((box_a[:, 2]-box_a[:, 0]) * + (box_a[:, 3]-box_a[:, 1])) # [A,B] + area_b = ((box_b[2]-box_b[0]) * + (box_b[3]-box_b[1])) # [A,B] + union = area_a + area_b - inter + return inter / union # [A,B] + + +class Compose(object): + """Composes several augmentations together. + Args: + transforms (List[Transform]): list of transforms to compose. + Example: + >>> augmentations.Compose([ + >>> transforms.CenterCrop(10), + >>> transforms.ToTensor(), + >>> ]) + """ + + def __init__(self, transforms): + self.transforms = transforms + + def __call__(self, img, boxes=None, labels=None): + for t in self.transforms: + img, boxes, labels = t(img, boxes, labels) + return img, boxes, labels + + +class Lambda(object): + """Applies a lambda as a transform.""" + + def __init__(self, lambd): + assert isinstance(lambd, types.LambdaType) + self.lambd = lambd + + def __call__(self, img, boxes=None, labels=None): + return self.lambd(img, boxes, labels) + + +class ConvertFromInts(object): + def __call__(self, image, boxes=None, labels=None): + return image.astype(np.float32), boxes, labels + + +class SubtractMeans(object): + def __init__(self, mean): + self.mean = np.array(mean, dtype=np.float32) + + def __call__(self, image, boxes=None, labels=None): + image = image.astype(np.float32) + image -= self.mean + return image.astype(np.float32), boxes, labels + + +class ToAbsoluteCoords(object): + def __call__(self, image, boxes=None, labels=None): + height, width, channels = image.shape + boxes[:, 0] *= width + boxes[:, 2] *= width + boxes[:, 1] *= height + boxes[:, 3] *= height + + return image, boxes, labels + + +class ToPercentCoords(object): + def __call__(self, image, boxes=None, labels=None): + height, width, channels = image.shape + boxes[:, 0] /= width + boxes[:, 2] /= width + boxes[:, 1] /= height + boxes[:, 3] /= height + + return image, boxes, labels + + +class Resize(object): + def __init__(self, size=300): + self.size = size + + def __call__(self, image, boxes=None, labels=None): + image = cv2.resize(image, (self.size, + self.size)) + return image, boxes, labels + + +class RandomSaturation(object): + def __init__(self, lower=0.5, upper=1.5): + self.lower = lower + self.upper = upper + assert self.upper >= self.lower, "contrast upper must be >= lower." + assert self.lower >= 0, "contrast lower must be non-negative." + + def __call__(self, image, boxes=None, labels=None): + if random.randint(2): + image[:, :, 1] *= random.uniform(self.lower, self.upper) + + return image, boxes, labels + + +class RandomHue(object): + def __init__(self, delta=18.0): + assert delta >= 0.0 and delta <= 360.0 + self.delta = delta + + def __call__(self, image, boxes=None, labels=None): + if random.randint(2): + image[:, :, 0] += random.uniform(-self.delta, self.delta) + image[:, :, 0][image[:, :, 0] > 360.0] -= 360.0 + image[:, :, 0][image[:, :, 0] < 0.0] += 360.0 + return image, boxes, labels + + +class RandomLightingNoise(object): + def __init__(self): + self.perms = ((0, 1, 2), (0, 2, 1), + (1, 0, 2), (1, 2, 0), + (2, 0, 1), (2, 1, 0)) + + def __call__(self, image, boxes=None, labels=None): + if random.randint(2): + swap = self.perms[random.randint(len(self.perms))] + shuffle = SwapChannels(swap) # shuffle channels + image = shuffle(image) + return image, boxes, labels + + +class ConvertColor(object): + def __init__(self, current='BGR', transform='HSV'): + self.transform = transform + self.current = current + + def __call__(self, image, boxes=None, labels=None): + if self.current == 'BGR' and self.transform == 'HSV': + image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) + elif self.current == 'HSV' and self.transform == 'BGR': + image = cv2.cvtColor(image, cv2.COLOR_HSV2BGR) + else: + raise NotImplementedError + return image, boxes, labels + + +class RandomContrast(object): + def __init__(self, lower=0.5, upper=1.5): + self.lower = lower + self.upper = upper + assert self.upper >= self.lower, "contrast upper must be >= lower." + assert self.lower >= 0, "contrast lower must be non-negative." + + # expects float image + def __call__(self, image, boxes=None, labels=None): + if random.randint(2): + alpha = random.uniform(self.lower, self.upper) + image *= alpha + return image, boxes, labels + + +class RandomBrightness(object): + def __init__(self, delta=32): + assert delta >= 0.0 + assert delta <= 255.0 + self.delta = delta + + def __call__(self, image, boxes=None, labels=None): + if random.randint(2): + delta = random.uniform(-self.delta, self.delta) + image += delta + return image, boxes, labels + + +class ToCV2Image(object): + def __call__(self, tensor, boxes=None, labels=None): + return tensor.cpu().numpy().astype(np.float32).transpose((1, 2, 0)), boxes, labels + + +class ToTensor(object): + def __call__(self, cvimage, boxes=None, labels=None): + return torch.from_numpy(cvimage.astype(np.float32)).permute(2, 0, 1), boxes, labels + + +class RandomSampleCrop(object): + """Crop + Arguments: + img (Image): the image being input during training + boxes (Tensor): the original bounding boxes in pt form + labels (Tensor): the class labels for each bbox + mode (float tuple): the min and max jaccard overlaps + Return: + (img, boxes, classes) + img (Image): the cropped image + boxes (Tensor): the adjusted bounding boxes in pt form + labels (Tensor): the class labels for each bbox + """ + def __init__(self): + self.sample_options = ( + # using entire original input image + None, + # sample a patch s.t. MIN jaccard w/ obj in .1,.3,.4,.7,.9 + (0.1, None), + (0.3, None), + (0.7, None), + (0.9, None), + # randomly sample a patch + (None, None), + ) + + def __call__(self, image, boxes=None, labels=None): + height, width, _ = image.shape + while True: + # randomly choose a mode + mode = random.choice(self.sample_options) + if mode is None: + return image, boxes, labels + + min_iou, max_iou = mode + if min_iou is None: + min_iou = float('-inf') + if max_iou is None: + max_iou = float('inf') + + # max trails (50) + for _ in range(50): + current_image = image + + w = random.uniform(0.3 * width, width) + h = random.uniform(0.3 * height, height) + + # aspect ratio constraint b/t .5 & 2 + if h / w < 0.5 or h / w > 2: + continue + + left = random.uniform(width - w) + top = random.uniform(height - h) + + # convert to integer rect x1,y1,x2,y2 + rect = np.array([int(left), int(top), int(left+w), int(top+h)]) + + # calculate IoU (jaccard overlap) b/t the cropped and gt boxes + overlap = jaccard_numpy(boxes, rect) # boxes tensor x,y的绝对坐标 rect 剪裁的 x,y 坐标 + + # is min and max overlap constraint satisfied? if not try again + if overlap.min() < min_iou and max_iou < overlap.max(): + continue + + # cut the crop from the image + current_image = current_image[rect[1]:rect[3], rect[0]:rect[2], + :] + + # keep overlap with gt box IF center in sampled patch + centers = (boxes[:, :2] + boxes[:, 2:]) / 2.0 + + # mask in all gt boxes that above and to the left of centers + m1 = (rect[0] < centers[:, 0]) * (rect[1] < centers[:, 1]) + + # mask in all gt boxes that under and to the right of centers + m2 = (rect[2] > centers[:, 0]) * (rect[3] > centers[:, 1]) + + # mask in that both m1 and m2 are true + mask = m1 * m2 + + # have any valid boxes? try again if not + if not mask.any(): + continue + + # take only matching gt boxes + current_boxes = boxes[mask, :].copy() + + # take only matching gt labels + current_labels = labels[mask] + + # should we use the box left and top corner or the crop's + current_boxes[:, :2] = np.maximum(current_boxes[:, :2], + rect[:2]) + # adjust to crop (by substracting crop's left,top) + current_boxes[:, :2] -= rect[:2] + + current_boxes[:, 2:] = np.minimum(current_boxes[:, 2:], + rect[2:]) + # adjust to crop (by substracting crop's left,top) + current_boxes[:, 2:] -= rect[:2] + + return current_image, current_boxes, current_labels + + +class Expand(object): + def __init__(self, mean): + self.mean = mean + + def __call__(self, image, boxes, labels): + if random.randint(2): + return image, boxes, labels + + height, width, depth = image.shape + ratio = random.uniform(1, 4) + left = random.uniform(0, width*ratio - width) + top = random.uniform(0, height*ratio - height) + + expand_image = np.zeros( + (int(height*ratio), int(width*ratio), depth), + dtype=image.dtype) + expand_image[:, :, :] = self.mean + expand_image[int(top):int(top + height), + int(left):int(left + width)] = image + image = expand_image + + boxes = boxes.copy() + boxes[:, :2] += (int(left), int(top)) + boxes[:, 2:] += (int(left), int(top)) + + return image, boxes, labels + + +class RandomMirror(object): + def __call__(self, image, boxes, classes): + _, width, _ = image.shape + if random.randint(2): + image = image[:, ::-1] + boxes = boxes.copy() + boxes[:, 0::2] = width - boxes[:, 2::-2] + return image, boxes, classes + + +class SwapChannels(object): + """Transforms a tensorized image by swapping the channels in the order + specified in the swap tuple. + Args: + swaps (int triple): final order of channels + eg: (2, 1, 0) + """ + + def __init__(self, swaps): + self.swaps = swaps + + def __call__(self, image): + """ + Args: + image (Tensor): image tensor to be transformed + Return: + a tensor with channels swapped according to swap + """ + # if torch.is_tensor(image): + # image = image.data.cpu().numpy() + # else: + # image = np.array(image) + image = image[:, :, self.swaps] + return image + + +class PhotometricDistort(object): + def __init__(self): + self.pd = [ + RandomContrast(), + ConvertColor(transform='HSV'), + RandomSaturation(), + RandomHue(), + ConvertColor(current='HSV', transform='BGR'), + RandomContrast() + ] + self.rand_brightness = RandomBrightness() + self.rand_light_noise = RandomLightingNoise() + + def __call__(self, image, boxes, labels): + im = image.copy() + im, boxes, labels = self.rand_brightness(im, boxes, labels) + if random.randint(2): + distort = Compose(self.pd[:-1]) + else: + distort = Compose(self.pd[1:]) + im, boxes, labels = distort(im, boxes, labels) + return self.rand_light_noise(im, boxes, labels) + + +class SSDAugmentation(object): + def __init__(self, size=300, mean=(104, 117, 123)): + self.mean = mean + self.size = size + self.augment = Compose([ + ConvertFromInts(), # int 转化为 float32 + ToAbsoluteCoords(), + PhotometricDistort(), + Expand(self.mean), + RandomSampleCrop(), + RandomMirror(), + ToPercentCoords(), + Resize(self.size), + SubtractMeans(self.mean) + ]) + + def __call__(self, img, boxes, labels): + return self.augment(img, boxes, labels) diff --git a/PyTorch/contrib/cv/detection/RefineDet/utils/logging.py b/PyTorch/contrib/cv/detection/RefineDet/utils/logging.py index 50e75733a1..838d1cf260 100644 --- a/PyTorch/contrib/cv/detection/RefineDet/utils/logging.py +++ b/PyTorch/contrib/cv/detection/RefineDet/utils/logging.py @@ -1,54 +1,54 @@ -#!/bin/bash -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 -import os -import sys - -from .osutils import mkdir_if_missing - - -class Logger(object): - def __init__(self, fpath=None): - self.console = sys.stdout - self.file = None - if fpath is not None: - mkdir_if_missing(os.path.dirname(fpath)) - self.file = open(fpath, 'w') - - def __del__(self): - self.close() - - def __enter__(self): - pass - - def __exit__(self, *args): - self.close() - - def write(self, msg): - self.console.write(msg) - if self.file is not None: - self.file.write(msg) - - def flush(self): - self.console.flush() - if self.file is not None: - self.file.flush() - os.fsync(self.file.fileno()) - - def close(self): - self.console.close() - if self.file is not None: - self.file.close() +#!/bin/bash +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 +import os +import sys + +from .osutils import mkdir_if_missing + + +class Logger(object): + def __init__(self, fpath=None): + self.console = sys.stdout + self.file = None + if fpath is not None: + mkdir_if_missing(os.path.dirname(fpath)) + self.file = open(fpath, 'w') + + def __del__(self): + self.close() + + def __enter__(self): + pass + + def __exit__(self, *args): + self.close() + + def write(self, msg): + self.console.write(msg) + if self.file is not None: + self.file.write(msg) + + def flush(self): + self.console.flush() + if self.file is not None: + self.file.flush() + os.fsync(self.file.fileno()) + + def close(self): + self.console.close() + if self.file is not None: + self.file.close() diff --git a/PyTorch/contrib/cv/detection/RefineDet/utils/osutils.py b/PyTorch/contrib/cv/detection/RefineDet/utils/osutils.py index b91a51f7b3..d1537c4e52 100644 --- a/PyTorch/contrib/cv/detection/RefineDet/utils/osutils.py +++ b/PyTorch/contrib/cv/detection/RefineDet/utils/osutils.py @@ -1,26 +1,26 @@ -#!/bin/bash -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 -import os -import errno - - -def mkdir_if_missing(dir_path): - try: - os.makedirs(dir_path) - except OSError as e: - if e.errno != errno.EEXIST: - raise +#!/bin/bash +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 +import os +import errno + + +def mkdir_if_missing(dir_path): + try: + os.makedirs(dir_path) + except OSError as e: + if e.errno != errno.EEXIST: + raise diff --git a/PyTorch/contrib/cv/detection/Retinaface/modelzoo_level.txt b/PyTorch/contrib/cv/detection/Retinaface/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/detection/Retinaface/modelzoo_level.txt +++ b/PyTorch/contrib/cv/detection/Retinaface/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/SOLOv1/mmcv/README.rst b/PyTorch/contrib/cv/detection/SOLOv1/mmcv/README.rst deleted file mode 100644 index 663f6677e1..0000000000 --- a/PyTorch/contrib/cv/detection/SOLOv1/mmcv/README.rst +++ /dev/null @@ -1,54 +0,0 @@ -MMCV -==== - -.. image:: https://travis-ci.com/open-mmlab/mmcv.svg?branch=master - :target: https://travis-ci.com/open-mmlab/mmcv - -.. image:: https://codecov.io/gh/open-mmlab/mmcv/branch/master/graph/badge.svg - :target: https://codecov.io/gh/open-mmlab/mmcv - -.. image:: https://img.shields.io/github/license/open-mmlab/mmcv.svg - :target: https://github.com/open-mmlab/mmcv/blob/master/LICENSE - - -Introduction ------------- - -MMCV is a foundational python library for computer vision research and supports many -research projects in MMLAB, such as `MMDetection `_ -and `MMAction `_. - -It provides the following functionalities. - -- Universal IO APIs -- Image processing -- Video processing -- Image and annotation visualization -- Useful utilities (progress bar, timer, ...) -- PyTorch runner with hooking mechanism -- Various CNN architectures - -See the `documentation `_ for more features and usage. - - -Installation ------------- - -Try and start with - -.. code:: - - pip install mmcv - - -or install from source - -.. code:: - - git clone https://github.com/open-mmlab/mmcv.git - cd mmcv - pip install -e . - -Note: If you would like to use :code:`opencv-python-headless` instead of :code:`opencv-python`, -e.g., in a minimum container environment or servers without GUI, -you can first install it before installing MMCV to skip the installation of :code:`opencv-python`. \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/SOLOv2/mmcv/README.rst b/PyTorch/contrib/cv/detection/SOLOv2/mmcv/README.rst deleted file mode 100644 index 663f6677e1..0000000000 --- a/PyTorch/contrib/cv/detection/SOLOv2/mmcv/README.rst +++ /dev/null @@ -1,54 +0,0 @@ -MMCV -==== - -.. image:: https://travis-ci.com/open-mmlab/mmcv.svg?branch=master - :target: https://travis-ci.com/open-mmlab/mmcv - -.. image:: https://codecov.io/gh/open-mmlab/mmcv/branch/master/graph/badge.svg - :target: https://codecov.io/gh/open-mmlab/mmcv - -.. image:: https://img.shields.io/github/license/open-mmlab/mmcv.svg - :target: https://github.com/open-mmlab/mmcv/blob/master/LICENSE - - -Introduction ------------- - -MMCV is a foundational python library for computer vision research and supports many -research projects in MMLAB, such as `MMDetection `_ -and `MMAction `_. - -It provides the following functionalities. - -- Universal IO APIs -- Image processing -- Video processing -- Image and annotation visualization -- Useful utilities (progress bar, timer, ...) -- PyTorch runner with hooking mechanism -- Various CNN architectures - -See the `documentation `_ for more features and usage. - - -Installation ------------- - -Try and start with - -.. code:: - - pip install mmcv - - -or install from source - -.. code:: - - git clone https://github.com/open-mmlab/mmcv.git - cd mmcv - pip install -e . - -Note: If you would like to use :code:`opencv-python-headless` instead of :code:`opencv-python`, -e.g., in a minimum container environment or servers without GUI, -you can first install it before installing MMCV to skip the installation of :code:`opencv-python`. \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/Dockerfile b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/Dockerfile old mode 100755 new mode 100644 index 7e712fe1a1..30a31af558 --- a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/Dockerfile +++ b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/Dockerfile @@ -1,5 +1,5 @@ -ARG FROM_IMAGE_NAME -FROM $FROM_IMAGE_NAME - -COPY requirements.txt . +ARG FROM_IMAGE_NAME +FROM $FROM_IMAGE_NAME + +COPY requirements.txt . RUN pip3.7 install -r requirements.txt \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/LICENSE b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/LICENSE old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/README.md b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/README.md old mode 100755 new mode 100644 index 9eeb1a53ab..87658addb0 --- a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/README.md +++ b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/README.md @@ -1,88 +1,88 @@ -## Requirements -```angular2html -pytorch==1.5 -apex -pandas -opencv-python -``` - -## 下载数据集 -```angular2html -wget http://pjreddie.com/media/files/VOCtrainval_11-May-2012.tar -wget http://pjreddie.com/media/files/VOCtrainval_06-Nov-2007.tar -wget http://pjreddie.com/media/files/VOCtest_06-Nov-2007.tar - -将3个数据集放在目录 VOC0712下,目录结构为: - VOC0712 - | - |———————— VOC2007_trainval - | |——————Annotations - | |——————ImageSets - | |——————JPEGImages - | |——————SegmentationClass - | |——————SegmentationObject - |———————— VOC2012_trainval - | |——————Annotations - | |——————ImageSets - | |——————JPEGImages - | |——————SegmentationClass - | |——————SegmentationObject - |———————— VOC2007_test - |——————Annotations - |——————ImageSets - |——————JPEGImages - |——————SegmentationClass - |——————SegmentationObject -``` -## 下载预训练模型到 models 目录下 -``` -wget -P models https://storage.googleapis.com/models-hao/mb2-imagenet-71_8.pth -``` -## 训练 -```angular2html -# 1p train perf -# 是否正确输出了性能log文件 -bash test/train_performance_1p.sh --data_path xxx - -# 1p train full -# 是否正确输出了性能精度log文件,是否正确保存了模型文件 -bash test/train_full_1p.sh --data_path xxx - -# 8p train perf -# 是否正确输出了性能log文件 -bash test/train_performance_8p.sh --data_path xxx - -# 8p train full -# 是否正确输出了性能精度log文件,是否正确保存了模型文件 -bash test/train_full_8p.sh --data_path xxx - -# finetuning -# 是否正确执行迁移学习 -bash test/train_finetune_1p.sh --data_path xxx - -# online inference demo -# 是否正确输出预测结果,请确保输入固定tensor多次运行的输出结果一致 -python3.7.5 demo.py -``` -### 一些参数说明 -```angular2html ---data_path 数据集路径 ---base_net 预训练模型存放路径 ---num_epochs 训练epoch ---validation_epochs 验证epoch ---checkpoint_folder 模型保存路径 ---eval_dir 模型验证时产生文件的存放路径 ---device 使用的设备,npu或gpu ---gpu 设备卡号,单卡时使用 ---device_list 默认为 '0,1,2,3,4,5,6,7',多卡时使用 -``` -## evaluate -```angular2html -bash scripts/eval.sh -``` -### 一些参数说明 -```angular2html ---dataset 测试数据集 ---eval_dir 模型验证时产生文件的存放路径 ---lable_file 类别文件,训练时会在模型保存文件夹生成 -``` +## Requirements +```angular2html +pytorch==1.5 +apex +pandas +opencv-python +``` + +## 下载数据集 +```angular2html +wget http://pjreddie.com/media/files/VOCtrainval_11-May-2012.tar +wget http://pjreddie.com/media/files/VOCtrainval_06-Nov-2007.tar +wget http://pjreddie.com/media/files/VOCtest_06-Nov-2007.tar + +将3个数据集放在目录 VOC0712下,目录结构为: + VOC0712 + | + |———————— VOC2007_trainval + | |——————Annotations + | |——————ImageSets + | |——————JPEGImages + | |——————SegmentationClass + | |——————SegmentationObject + |———————— VOC2012_trainval + | |——————Annotations + | |——————ImageSets + | |——————JPEGImages + | |——————SegmentationClass + | |——————SegmentationObject + |———————— VOC2007_test + |——————Annotations + |——————ImageSets + |——————JPEGImages + |——————SegmentationClass + |——————SegmentationObject +``` +## 下载预训练模型到 models 目录下 +``` +wget -P models https://storage.googleapis.com/models-hao/mb2-imagenet-71_8.pth +``` +## 训练 +```angular2html +# 1p train perf +# 是否正确输出了性能log文件 +bash test/train_performance_1p.sh --data_path xxx + +# 1p train full +# 是否正确输出了性能精度log文件,是否正确保存了模型文件 +bash test/train_full_1p.sh --data_path xxx + +# 8p train perf +# 是否正确输出了性能log文件 +bash test/train_performance_8p.sh --data_path xxx + +# 8p train full +# 是否正确输出了性能精度log文件,是否正确保存了模型文件 +bash test/train_full_8p.sh --data_path xxx + +# finetuning +# 是否正确执行迁移学习 +bash test/train_finetune_1p.sh --data_path xxx + +# online inference demo +# 是否正确输出预测结果,请确保输入固定tensor多次运行的输出结果一致 +python3.7.5 demo.py +``` +### 一些参数说明 +```angular2html +--data_path 数据集路径 +--base_net 预训练模型存放路径 +--num_epochs 训练epoch +--validation_epochs 验证epoch +--checkpoint_folder 模型保存路径 +--eval_dir 模型验证时产生文件的存放路径 +--device 使用的设备,npu或gpu +--gpu 设备卡号,单卡时使用 +--device_list 默认为 '0,1,2,3,4,5,6,7',多卡时使用 +``` +## evaluate +```angular2html +bash scripts/eval.sh +``` +### 一些参数说明 +```angular2html +--dataset 测试数据集 +--eval_dir 模型验证时产生文件的存放路径 +--lable_file 类别文件,训练时会在模型保存文件夹生成 +``` diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/README_raw.md b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/README_raw.md old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/convert_to_caffe2_models.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/convert_to_caffe2_models.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/demo.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/demo.py old mode 100755 new mode 100644 index 582d0d536e..f082419b38 --- a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/demo.py +++ b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/demo.py @@ -1,103 +1,103 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import sys -import torch -import cv2 - -from vision.utils.misc import Timer -from vision.ssd.vgg_ssd import create_vgg_ssd, create_vgg_ssd_predictor -from vision.ssd.mobilenetv1_ssd import create_mobilenetv1_ssd, create_mobilenetv1_ssd_predictor -from vision.ssd.mobilenetv1_ssd_lite import create_mobilenetv1_ssd_lite, create_mobilenetv1_ssd_lite_predictor -from vision.ssd.squeezenet_ssd_lite import create_squeezenet_ssd_lite, create_squeezenet_ssd_lite_predictor -from vision.ssd.mobilenet_v2_ssd_lite import create_mobilenetv2_ssd_lite, create_mobilenetv2_ssd_lite_predictor -from vision.ssd.mobilenetv3_ssd_lite import create_mobilenetv3_large_ssd_lite, create_mobilenetv3_small_ssd_lite - -parser = argparse.ArgumentParser() -parser.add_argument('--net', default="mb2-ssd-lite", - help="The network architecture, it should be of mb1-ssd, mb1-ssd-lite, mb2-ssd-lite or vgg16-ssd.") -parser.add_argument("--trained_model", default="models/1p/mb2-ssd-lite-Epoch-0-Loss-12.09216200136671.pth", type=str) -parser.add_argument('--img', default="demo.jpg", help="image file") -parser.add_argument("--label_file", default="models/1p/voc-model-labels.txt", type=str, help="The label file path.") -parser.add_argument('--device', default='npu', type=str, help='npu or gpu') -parser.add_argument('--gpu', default=0, type=int, - help='GPU id to use.') -parser.add_argument("--nms_method", type=str, default="hard") -parser.add_argument('--mb2_width_mult', default=1.0, type=float, - help='Width Multiplifier for MobilenetV2') -timer = Timer() -if __name__ == '__main__': - args = parser.parse_args() - if args.device == 'npu': - args.device = 'npu:{}'.format(args.gpu) - torch.npu.set_device(args.device) - elif args.device == 'gpu': - args.device = 'cuda:{}'.format(args.gpu) - torch.backends.cudnn.benchmark = True - - if args.net == 'vgg16-ssd': - create_net = create_vgg_ssd - create_predictor = lambda net: create_vgg_ssd_predictor(net, nms_method=args.nms_method, device=args.device) - elif args.net == 'mb1-ssd': - create_net = create_mobilenetv1_ssd - create_predictor = lambda net: create_mobilenetv1_ssd_predictor(net, nms_method=args.nms_method, - device=args.device) - elif args.net == 'mb1-ssd-lite': - create_net = create_mobilenetv1_ssd_lite - create_predictor = lambda net: create_mobilenetv1_ssd_lite_predictor(net, nms_method=args.nms_method, - device=args.device) - elif args.net == 'sq-ssd-lite': - create_net = create_squeezenet_ssd_lite - create_predictor = lambda net: create_squeezenet_ssd_lite_predictor(net, nms_method=args.nms_method, - device=args.device) - elif args.net == 'mb2-ssd-lite': - create_net = lambda num: create_mobilenetv2_ssd_lite(num, width_mult=args.mb2_width_mult, device=args.device) - create_predictor = lambda net: create_mobilenetv2_ssd_lite_predictor(net, nms_method=args.nms_method, - device=args.device) - elif args.net == 'mb3-large-ssd-lite': - create_net = lambda num: create_mobilenetv3_large_ssd_lite(num) - create_predictor = lambda net: create_mobilenetv2_ssd_lite_predictor(net, nms_method=args.nms_method, - device=args.device) - elif args.net == 'mb3-small-ssd-lite': - create_net = lambda num: create_mobilenetv3_small_ssd_lite(num) - create_predictor = lambda net: create_mobilenetv2_ssd_lite_predictor(net, nms_method=args.nms_method, - device=args.device) - else: - parser.print_help(sys.stderr) - sys.exit(1) - - # create model - class_names = [name.strip() for name in open(args.label_file).readlines()] - net = create_net(len(class_names)) - timer.start("Load Model") - pretrained_dic = torch.load(args.trained_model, map_location='cpu')['state_dict'] - pretrained_dic = {k.replace('module.', ''): v for k, v in pretrained_dic.items()} - net.load_state_dict(pretrained_dic) - - net = net.to(args.device) - print(f'It took {timer.end("Load Model")} seconds to load the model.') - - # create predictor - predictor = create_predictor(net) - - # load imge - image = cv2.imread(args.img) - image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) - boxes, labels, probs = predictor.predict(image) - print('\n') - print('boxes: ', boxes) - print('lables: ', labels) - print('probs: ', probs) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import sys +import torch +import cv2 + +from vision.utils.misc import Timer +from vision.ssd.vgg_ssd import create_vgg_ssd, create_vgg_ssd_predictor +from vision.ssd.mobilenetv1_ssd import create_mobilenetv1_ssd, create_mobilenetv1_ssd_predictor +from vision.ssd.mobilenetv1_ssd_lite import create_mobilenetv1_ssd_lite, create_mobilenetv1_ssd_lite_predictor +from vision.ssd.squeezenet_ssd_lite import create_squeezenet_ssd_lite, create_squeezenet_ssd_lite_predictor +from vision.ssd.mobilenet_v2_ssd_lite import create_mobilenetv2_ssd_lite, create_mobilenetv2_ssd_lite_predictor +from vision.ssd.mobilenetv3_ssd_lite import create_mobilenetv3_large_ssd_lite, create_mobilenetv3_small_ssd_lite + +parser = argparse.ArgumentParser() +parser.add_argument('--net', default="mb2-ssd-lite", + help="The network architecture, it should be of mb1-ssd, mb1-ssd-lite, mb2-ssd-lite or vgg16-ssd.") +parser.add_argument("--trained_model", default="models/1p/mb2-ssd-lite-Epoch-0-Loss-12.09216200136671.pth", type=str) +parser.add_argument('--img', default="demo.jpg", help="image file") +parser.add_argument("--label_file", default="models/1p/voc-model-labels.txt", type=str, help="The label file path.") +parser.add_argument('--device', default='npu', type=str, help='npu or gpu') +parser.add_argument('--gpu', default=0, type=int, + help='GPU id to use.') +parser.add_argument("--nms_method", type=str, default="hard") +parser.add_argument('--mb2_width_mult', default=1.0, type=float, + help='Width Multiplifier for MobilenetV2') +timer = Timer() +if __name__ == '__main__': + args = parser.parse_args() + if args.device == 'npu': + args.device = 'npu:{}'.format(args.gpu) + torch.npu.set_device(args.device) + elif args.device == 'gpu': + args.device = 'cuda:{}'.format(args.gpu) + torch.backends.cudnn.benchmark = True + + if args.net == 'vgg16-ssd': + create_net = create_vgg_ssd + create_predictor = lambda net: create_vgg_ssd_predictor(net, nms_method=args.nms_method, device=args.device) + elif args.net == 'mb1-ssd': + create_net = create_mobilenetv1_ssd + create_predictor = lambda net: create_mobilenetv1_ssd_predictor(net, nms_method=args.nms_method, + device=args.device) + elif args.net == 'mb1-ssd-lite': + create_net = create_mobilenetv1_ssd_lite + create_predictor = lambda net: create_mobilenetv1_ssd_lite_predictor(net, nms_method=args.nms_method, + device=args.device) + elif args.net == 'sq-ssd-lite': + create_net = create_squeezenet_ssd_lite + create_predictor = lambda net: create_squeezenet_ssd_lite_predictor(net, nms_method=args.nms_method, + device=args.device) + elif args.net == 'mb2-ssd-lite': + create_net = lambda num: create_mobilenetv2_ssd_lite(num, width_mult=args.mb2_width_mult, device=args.device) + create_predictor = lambda net: create_mobilenetv2_ssd_lite_predictor(net, nms_method=args.nms_method, + device=args.device) + elif args.net == 'mb3-large-ssd-lite': + create_net = lambda num: create_mobilenetv3_large_ssd_lite(num) + create_predictor = lambda net: create_mobilenetv2_ssd_lite_predictor(net, nms_method=args.nms_method, + device=args.device) + elif args.net == 'mb3-small-ssd-lite': + create_net = lambda num: create_mobilenetv3_small_ssd_lite(num) + create_predictor = lambda net: create_mobilenetv2_ssd_lite_predictor(net, nms_method=args.nms_method, + device=args.device) + else: + parser.print_help(sys.stderr) + sys.exit(1) + + # create model + class_names = [name.strip() for name in open(args.label_file).readlines()] + net = create_net(len(class_names)) + timer.start("Load Model") + pretrained_dic = torch.load(args.trained_model, map_location='cpu')['state_dict'] + pretrained_dic = {k.replace('module.', ''): v for k, v in pretrained_dic.items()} + net.load_state_dict(pretrained_dic) + + net = net.to(args.device) + print(f'It took {timer.end("Load Model")} seconds to load the model.') + + # create predictor + predictor = create_predictor(net) + + # load imge + image = cv2.imread(args.img) + image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) + boxes, labels, probs = predictor.predict(image) + print('\n') + print('boxes: ', boxes) + print('lables: ', labels) + print('probs: ', probs) diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/docker_start.sh b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/docker_start.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/draw_eval_results.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/draw_eval_results.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/eval_ssd.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/eval_ssd.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/extract_tf_weights.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/extract_tf_weights.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/modelzoo_level.txt b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/modelzoo_level.txt old mode 100755 new mode 100644 index 405b26618a..c45626e398 --- a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/modelzoo_level.txt +++ b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:POK +FuncStatus:OK +PerfStatus:POK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/open_images_downloader.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/open_images_downloader.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/prune_alexnet.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/prune_alexnet.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/requirements.txt b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/requirements.txt old mode 100755 new mode 100644 index 3828115134..9f9c71f54c --- a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/requirements.txt +++ b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/requirements.txt @@ -1,5 +1,5 @@ -torch==1.5.0 -apex -torchvision==0.6.0 -Pandas +torch==1.5.0 +apex +torchvision==0.6.0 +Pandas opencv-python \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/run_ssd_example.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/run_ssd_example.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/run_ssd_live_caffe2.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/run_ssd_live_caffe2.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/run_ssd_live_demo.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/run_ssd_live_demo.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/scripts/eval.sh b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/scripts/eval.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/scripts/set_npu_env.sh b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/scripts/set_npu_env.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/scripts/train_1p.sh b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/scripts/train_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/scripts/train_8p.sh b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/scripts/train_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/test/env_npu.sh b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/test/env_npu.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/test/train_finetune_1p.sh b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/test/train_finetune_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/test/train_full_1p.sh b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/test/train_full_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/test/train_full_8p.sh b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/test/train_full_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/test/train_performance_1p.sh b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/test/train_performance_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/test/train_performance_8p.sh b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/test/train_performance_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/train_ssd.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/train_ssd.py old mode 100755 new mode 100644 index 248d41ef27..5da35feb70 --- a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/train_ssd.py +++ b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/train_ssd.py @@ -1,493 +1,493 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import os -import logging -import pathlib -import sys -import itertools -import apex -import torch -from torch.utils.data import DataLoader, ConcatDataset -from torch.optim.lr_scheduler import CosineAnnealingLR, MultiStepLR, LambdaLR - -from vision.utils.misc import Timer, freeze_net_layers, store_labels -from vision.ssd.ssd import MatchPrior -from vision.ssd.mobilenetv3_ssd_lite import create_mobilenetv3_large_ssd_lite, create_mobilenetv3_small_ssd_lite -from vision.ssd.mobilenetv1_ssd import create_mobilenetv1_ssd, create_mobilenetv1_ssd_predictor -from vision.ssd.mobilenetv1_ssd_lite import create_mobilenetv1_ssd_lite, create_mobilenetv1_ssd_lite_predictor -from vision.ssd.squeezenet_ssd_lite import create_squeezenet_ssd_lite, create_squeezenet_ssd_lite_predictor -from vision.ssd.mobilenet_v2_ssd_lite import create_mobilenetv2_ssd_lite, create_mobilenetv2_ssd_lite_predictor -from vision.ssd.vgg_ssd import create_vgg_ssd, create_vgg_ssd_predictor -from vision.datasets.voc_dataset import VOCDataset -from vision.datasets.open_images import OpenImagesDataset -from vision.nn.multibox_loss import MultiboxLoss -from vision.ssd.config import vgg_ssd_config -from vision.ssd.config import mobilenetv1_ssd_config -from vision.ssd.config import squeezenet_ssd_config -from vision.ssd.data_preprocessing import TrainAugmentation, TestTransform -from eval_ssd import predicate -from vision.utils.misc import str2bool -from apex import amp - -parser = argparse.ArgumentParser( - description='Single Shot MultiBox Detector Training With Pytorch') - -# dataset setting -parser.add_argument("--dataset_type", default="voc", type=str, - help='Specify dataset type. Currently support voc and open_images.') -parser.add_argument('--data_path', default='') -parser.add_argument('--datasets', default=[], help='Dataset directory path') -parser.add_argument('--validation_dataset', help='Dataset directory path') -parser.add_argument('--balance_data', action='store_true', - help="Balance training data by down-sampling more frequent labels.") - -# Params for loading pretrained basenet or checkpoints. -parser.add_argument('--base_net', default='', - help='Pretrained base model') -parser.add_argument('--pretrained_ssd', default='', help='Pre-trained base model') -parser.add_argument('--resume', default=None, type=str, - help='Checkpoint state_dict file to resume training from') -parser.add_argument('--net', default="vgg16-ssd", - help="The network architecture, it can be mb1-ssd, mb1-lite-ssd, mb2-ssd-lite, mb3-large-ssd-lite, mb3-small-ssd-lite or vgg16-ssd.") -parser.add_argument('--freeze_base_net', action='store_true', - help="Freeze base net layers.") -parser.add_argument('--freeze_net', action='store_true', - help="Freeze all the layers except the prediction head.") -parser.add_argument('--mb2_width_mult', default=1.0, type=float, - help='Width Multiplifier for MobilenetV2') - -# Params for SGD -parser.add_argument('--lr', '--learning-rate', default=1e-3, type=float, - help='initial learning rate') -parser.add_argument('--momentum', default=0.9, type=float, - help='Momentum value for optim') -parser.add_argument('--weight_decay', default=5e-4, type=float, - help='Weight decay for SGD') -parser.add_argument('--gamma', default=0.1, type=float, - help='Gamma update for SGD') -parser.add_argument('--base_net_lr', default=None, type=float, - help='initial learning rate for base net.') -parser.add_argument('--extra_layers_lr', default=None, type=float, - help='initial learning rate for the layers not in base net and prediction heads.') - -# Scheduler -parser.add_argument('--scheduler', default="multi-step", type=str, - help="Scheduler for SGD. It can one of multi-step and cosine") - -# Params for Multi-step Scheduler -parser.add_argument('--milestones', default="80,100", type=str, - help="milestones for MultiStepLR") - -# Params for Cosine Annealing -parser.add_argument('--t_max', default=120, type=float, - help='T_max value for Cosine Annealing Scheduler.') - -# Train params -parser.add_argument('--batch_size', default=32, type=int, - help='Batch size for training') -parser.add_argument('--num_epochs', default=120, type=int, - help='the number epochs') -parser.add_argument('--num_workers', default=4, type=int, - help='Number of workers used in dataloading') -parser.add_argument('--validation_epochs', default=5, type=int, - help='the number epochs') -parser.add_argument('--debug_steps', default=100, type=int, - help='Set the debug log output frequency.') -parser.add_argument('--checkpoint_folder', default='models/', - help='Directory for saving checkpoint models') -# eval params -parser.add_argument("--nms_method", type=str, default="hard") -parser.add_argument("--use_2007_metric", type=str2bool, default=True) -parser.add_argument("--iou_threshold", type=float, default=0.5, help="The threshold of Intersection over Union.") -parser.add_argument("--eval_dir", default="eval_results", type=str, help="The directory to store evaluation results.") - -# distributed setting -parser.add_argument('--distributed', default=False, action='store_true', - help='Use multi-processing distributed training to launch ') -parser.add_argument('--seed', default=None, type=int, - help='seed for initializing training. ') -parser.add_argument('--device', default='gpu', type=str, help='npu or gpu') -parser.add_argument('--gpu', default=0, type=int, - help='GPU id to use.') -parser.add_argument('--device_list', default='0,1,2,3,4,5,6,7', type=str, help='device id list') -parser.add_argument('--world_size', default=-1, type=int, - help='number of nodes for distributed training') -parser.add_argument('--rank', default=-1, type=int, - help='node rank for distributed training') -parser.add_argument('--dist_url', default='', type=str, - help='url used to set up distributed training') -parser.add_argument('--dist_backend', default='nccl', type=str, - help='distributed backend, nccl for GPU, hccl for NPU') -parser.add_argument('--addr', default='127.0.0.1', type=str, help='master addr') -parser.add_argument('--port', default='29688', type=str, help='master port') - -# apex setting -parser.add_argument('--amp', default=False, action='store_true', - help='use amp to train the model') -parser.add_argument('--opt_level', default='O2', type=str, help='apex optimize level') -parser.add_argument('--loss_scale_value', default=128.0, type=int, help='static loss scale value') - -# learning rate setting -parser.add_argument('--warm_up', default=False, action='store_true', help='use warm_up or not') -parser.add_argument('--warm_up_epochs', default=5, type=int, help='warm up epochs') -parser.add_argument('--stay_lr', default=-1, type=int, help='Epoch with constant learning rate') - -logging.basicConfig(stream=sys.stdout, level=logging.INFO, - format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') - - -def device_id_to_process_device_map(device_list): - devices = device_list.split(",") - devices = [int(x) for x in devices] - devices.sort() - - process_device_map = dict() - for process_id, device_id in enumerate(devices): - process_device_map[process_id] = device_id - - return process_device_map - - -def train(loader, net, criterion, optimizer, args, timer, debug_steps=100, epoch=-1): - net.train(True) - running_loss = 0.0 - running_regression_loss = 0.0 - running_classification_loss = 0.0 - timer.start('batch_time') - timer.start('multi_step_time') - multi_step = 0 - for i, data in enumerate(loader): - images, boxes, labels = data - boxes, labels = boxes.to(args.device), labels.to(args.device) - optimizer.zero_grad() - confidence, locations = net.forward(images) - regression_loss, classification_loss = criterion(confidence, locations, labels, boxes) # TODO CHANGE BOXES - loss = (regression_loss + classification_loss) - if args.amp: - with amp.scale_loss(loss, optimizer) as scale_loss: - scale_loss.backward() - else: - loss.backward() - optimizer.step() - - running_loss += loss.item() - running_regression_loss += regression_loss.item() - running_classification_loss += classification_loss.item() - multi_step += 1 - if (i % debug_steps == 0 or i == len(loader) - 1) and (not args.distributed or args.rank == 0): - avg_loss = running_loss / (i + 1) - avg_reg_loss = running_regression_loss / (i + 1) - avg_clf_loss = running_classification_loss / (i + 1) - multi_step_time = timer.end('multi_step_time') - logging.info( - f"Epoch: {epoch}, Step: {i}, " + - f"multi_step_time: {multi_step_time:.4f}, " + - f"step_avg_time: {multi_step_time / multi_step:.4f}, " + - f"Average Regression Loss {avg_reg_loss:.4f}, " + - f"Average Classification Loss: {avg_clf_loss:.4f}, " + - f"Average Loss: {avg_loss:.4f}" - ) - multi_step = 0 - timer.start('multi_step_time') - if not args.distributed or args.rank == 0: - batch_time = timer.end('batch_time') - logging.info(f"Epoch: {epoch}, " + - f"batch_time: {batch_time:.4f}, " + - f"FPS: {args.batch_size * args.ngpu * len(loader) / batch_time:.4f} ") - - -def test(loader, net, criterion, args, epoch=-1): - net.eval() - running_loss = 0.0 - running_regression_loss = 0.0 - running_classification_loss = 0.0 - num = 0 - for i, data in enumerate(loader): - images, boxes, labels = data - num += 1 - with torch.no_grad(): - confidence, locations = net(images) - regression_loss, classification_loss = criterion(confidence.cpu(), locations.cpu(), labels, boxes) - loss = regression_loss + classification_loss - running_loss += loss.item() - running_regression_loss += regression_loss.item() - running_classification_loss += classification_loss.item() - if not args.distributed or args.rank == 0: - logging.info( - f"Epoch: {epoch}, Step: {i}, " + - f"Average Regression Loss {running_regression_loss / (i + 1):.4f}, " + - f"Average Classification Loss: {running_classification_loss / (i + 1):.4f}, " + - f"Average Loss: {running_loss / (i + 1):.4f}" - ) - return running_loss / num, running_regression_loss / num, running_classification_loss / num - - -def main_worker(gpu, timer, args): - args.gpu = args.process_device_map[gpu] - print(args.gpu) - if args.distributed: - if args.device == 'npu': - torch.distributed.init_process_group(backend=args.dist_backend, - world_size=args.ngpu, - rank=args.rank) - else: - torch.distributed.init_process_group(backend=args.dist_backend, - init_method="env://", - world_size=args.ngpu, - rank=args.rank) - if args.device == 'npu': - args.device = 'npu:{}'.format(args.gpu) - print(args.device) - torch.npu.set_device(args.device) - logging.info('use NPU, {}'.format(args.device)) - elif args.device == 'gpu': - args.device = 'cuda:{}'.format(args.gpu) - torch.backends.cudnn.benchmark = True - logging.info('use GPU, {}'.format(args.device)) - - if args.net == 'vgg16-ssd': - create_net = create_vgg_ssd - create_predictor = lambda net: create_vgg_ssd_predictor(net, nms_method=args.nms_method, device=args.device) - config = vgg_ssd_config - elif args.net == 'mb1-ssd': - create_net = create_mobilenetv1_ssd - create_predictor = lambda net: create_mobilenetv1_ssd_predictor(net, nms_method=args.nms_method, - device=args.device) - config = mobilenetv1_ssd_config - elif args.net == 'mb1-ssd-lite': - create_net = create_mobilenetv1_ssd_lite - create_predictor = lambda net: create_mobilenetv1_ssd_lite_predictor(net, nms_method=args.nms_method, - device=args.device) - config = mobilenetv1_ssd_config - elif args.net == 'sq-ssd-lite': - create_net = create_squeezenet_ssd_lite - create_predictor = lambda net: create_squeezenet_ssd_lite_predictor(net, nms_method=args.nms_method, - device=args.device) - config = squeezenet_ssd_config - elif args.net == 'mb2-ssd-lite': - create_net = lambda num: create_mobilenetv2_ssd_lite(num, width_mult=args.mb2_width_mult, device=args.device) - create_predictor = lambda net: create_mobilenetv2_ssd_lite_predictor(net, nms_method=args.nms_method, - device=args.device) - config = mobilenetv1_ssd_config - elif args.net == 'mb3-large-ssd-lite': - create_net = lambda num: create_mobilenetv3_large_ssd_lite(num) - create_predictor = lambda net: create_mobilenetv2_ssd_lite_predictor(net, nms_method=args.nms_method, - device=args.device) - config = mobilenetv1_ssd_config - elif args.net == 'mb3-small-ssd-lite': - create_net = lambda num: create_mobilenetv3_small_ssd_lite(num) - create_predictor = lambda net: create_mobilenetv2_ssd_lite_predictor(net, nms_method=args.nms_method, - device=args.device) - config = mobilenetv1_ssd_config - else: - logging.fatal("The net type is wrong.") - parser.print_help(sys.stderr) - sys.exit(1) - train_transform = TrainAugmentation(config.image_size, config.image_mean, config.image_std) - target_transform = MatchPrior(config.priors, config.center_variance, - config.size_variance, 0.5) - - test_transform = TestTransform(config.image_size, config.image_mean, config.image_std) - logging.info("Prepare training datasets.") - datasets = [] - for dataset_path in args.datasets: - if args.dataset_type == 'voc': - dataset = VOCDataset(dataset_path, transform=train_transform, - target_transform=target_transform) - label_file = os.path.join(args.checkpoint_folder, "voc-model-labels.txt") - store_labels(label_file, dataset.class_names) - num_classes = len(dataset.class_names) - elif args.dataset_type == 'open_images': - dataset = OpenImagesDataset(dataset_path, - transform=train_transform, target_transform=target_transform, - dataset_type="train", balance_data=args.balance_data) - label_file = os.path.join(args.checkpoint_folder, "open-images-model-labels.txt") - store_labels(label_file, dataset.class_names) - logging.info(dataset) - num_classes = len(dataset.class_names) - - else: - raise ValueError(f"Dataset type {args.dataset_type} is not supported.") - datasets.append(dataset) - logging.info(f"Stored labels into file {label_file}.") - train_dataset = ConcatDataset(datasets) - logging.info("Train dataset size: {}".format(len(train_dataset))) - - if args.distributed: - train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset) - train_loader = DataLoader(train_dataset, - args.batch_size, - num_workers=args.num_workers, - sampler=train_sampler if args.distributed else None, - shuffle=False if args.distributed else True) - logging.info("Prepare Validation datasets.") - if args.dataset_type == "voc": - val_dataset = VOCDataset(args.validation_dataset, transform=test_transform, - target_transform=target_transform, is_test=True) - elif args.dataset_type == 'open_images': - val_dataset = OpenImagesDataset(dataset_path, - transform=test_transform, target_transform=target_transform, - dataset_type="test") - logging.info(val_dataset) - logging.info("validation dataset size: {}".format(len(val_dataset))) - - val_loader = DataLoader(val_dataset, args.batch_size, - num_workers=args.num_workers, - shuffle=False) - - logging.info("Build network.") - net = create_net(num_classes) - min_loss = -10000.0 - last_epoch = -1 - - base_net_lr = args.base_net_lr if args.base_net_lr is not None else args.lr - extra_layers_lr = args.extra_layers_lr if args.extra_layers_lr is not None else args.lr - if args.freeze_base_net: - logging.info("Freeze base net.") - freeze_net_layers(net.base_net) - params = itertools.chain(net.source_layer_add_ons.parameters(), net.extras.parameters(), - net.regression_headers.parameters(), net.classification_headers.parameters()) - params = [ - {'params': itertools.chain( - net.source_layer_add_ons.parameters(), - net.extras.parameters() - ), 'lr': extra_layers_lr}, - {'params': itertools.chain( - net.regression_headers.parameters(), - net.classification_headers.parameters() - )} - ] - elif args.freeze_net: - freeze_net_layers(net.base_net) - freeze_net_layers(net.source_layer_add_ons) - freeze_net_layers(net.extras) - params = itertools.chain(net.regression_headers.parameters(), net.classification_headers.parameters()) - logging.info("Freeze all the layers except prediction heads.") - else: - params = [ - {'params': net.base_net.parameters(), 'lr': base_net_lr}, - {'params': itertools.chain( - net.source_layer_add_ons.parameters(), - net.extras.parameters() - ), 'lr': extra_layers_lr}, - {'params': itertools.chain( - net.regression_headers.parameters(), - net.classification_headers.parameters() - )} - ] - net.to(args.device) - criterion = MultiboxLoss(config.priors, iou_threshold=0.5, neg_pos_ratio=3, - center_variance=0.1, size_variance=0.2, device=args.device) - # npu: NpuFusedSGD - if 'npu' in args.device: - optimizer = apex.optimizers.NpuFusedSGD(params, lr=args.lr, momentum=args.momentum, - weight_decay=args.weight_decay) - else: - optimizer = torch.optim.SGD(params, lr=args.lr, momentum=args.momentum, - weight_decay=args.weight_decay) - timer.start("Load Model") - if args.resume: - logging.info(f"Resume from the model {args.resume}") - checkpoint = torch.load(args.resume, map_location='cpu') - pretrained_dic = {k.replace('module.', ''): v for k, v in checkpoint['state_dict'].items()} - net.load_state_dict(pretrained_dic) - optimizer.load_state_dict(checkpoint['optimizer']) - last_epoch = checkpoint['epoch'] - elif args.base_net: - logging.info(f"Init from base net {args.base_net}") - net.init_from_base_net(args.base_net) - elif args.pretrained_ssd: - logging.info(f"Init from pretrained ssd {args.pretrained_ssd}") - net.init_from_pretrained_ssd(args.pretrained_ssd) - logging.info(f'Took {timer.end("Load Model"):.2f} seconds to load the model.') - - if args.amp: - net, optimizer = amp.initialize(net, optimizer, opt_level=args.opt_level, loss_scale=args.loss_scale_value) - if args.distributed: - net = torch.nn.parallel.DistributedDataParallel(net, device_ids=[args.rank], - broadcast_buffers=False if 'npu' in args.device else True) - logging.info(f"Learning rate: {args.lr}, Base net learning rate: {base_net_lr}, " - + f"Extra Layers learning rate: {extra_layers_lr}.") - - if args.scheduler == 'multi-step': - logging.info("Uses MultiStepLR scheduler.") - milestones = [int(v.strip()) for v in args.milestones.split(",")] - scheduler = MultiStepLR(optimizer, milestones=milestones, - gamma=0.1, last_epoch=last_epoch) - elif args.scheduler == 'cosine': - logging.info("Uses CosineAnnealingLR scheduler.") - scheduler = CosineAnnealingLR(optimizer, args.t_max, last_epoch=last_epoch) - else: - logging.fatal(f"Unsupported Scheduler: {args.scheduler}.") - parser.print_help(sys.stderr) - sys.exit(1) - if args.warm_up: - warm_up_scheduler = LambdaLR(optimizer, lr_lambda=lambda epoch: epoch / args.warm_up_epochs) - - logging.info(f"Start training from epoch {last_epoch + 1}.") - for epoch in range(last_epoch + 1, args.num_epochs): - if args.distributed: - train_sampler.set_epoch(epoch) - if args.warm_up and epoch < args.warm_up_epochs: - warm_up_scheduler.step() - else: - scheduler.step() - train(train_loader, net, criterion, optimizer, args, timer, - debug_steps=args.debug_steps, epoch=epoch) - if (epoch % args.validation_epochs == 0 or epoch == args.num_epochs - 1) and ( - not args.distributed or args.rank == 0): - val_loss, val_regression_loss, val_classification_loss = test(val_loader, net, criterion, args, epoch) - logging.info( - f"Epoch: {epoch}, " + - f"Validation Regression Loss {val_regression_loss:.4f}, " + - f"Validation Classification Loss: {val_classification_loss:.4f}, " + - f"Validation Loss: {val_loss:.4f}" - ) - model_path = os.path.join(args.checkpoint_folder, f"{args.net}-Epoch-{epoch}-Loss-{val_loss}.pth") - torch.save({'state_dict': net.state_dict(), 'epoch': epoch, 'optimizer': optimizer.state_dict()}, - model_path) - logging.info(f"Saved model {model_path}") - - # 默认只测最后一轮的精度 - predictor = create_predictor(net) - val_dataset = VOCDataset(args.validation_dataset, is_test=True) - accuracy = predicate(val_dataset, predictor, args, dataset.class_names) - logging.info(f'epoch: {epoch}, accuracy: {accuracy}') - - -if __name__ == '__main__': - timer = Timer() - args = parser.parse_args() - if args.device == 'npu': - os.environ['MASTER_ADDR'] = args.addr - os.environ['MASTER_PORT'] = args.port - - logging.info(args) - args.process_device_map = device_id_to_process_device_map(args.device_list) - - if not os.path.exists(args.eval_dir): - os.makedirs(args.eval_dir) - if not os.path.exists(args.checkpoint_folder): - os.makedirs(args.checkpoint_folder) - args.datasets = [os.path.join(args.data_path, 'VOC2007_trainval'), os.path.join(args.data_path, 'VOC2012_trainval')] - args.validation_dataset = os.path.join(args.data_path, 'VOC2007_test') - if args.distributed: - args.ngpu = int(os.environ['RANK_SIZE']) - main_worker(args.rank, timer, args) - else: - args.ngpu = 1 - main_worker(args.gpu, timer, args) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import os +import logging +import pathlib +import sys +import itertools +import apex +import torch +from torch.utils.data import DataLoader, ConcatDataset +from torch.optim.lr_scheduler import CosineAnnealingLR, MultiStepLR, LambdaLR + +from vision.utils.misc import Timer, freeze_net_layers, store_labels +from vision.ssd.ssd import MatchPrior +from vision.ssd.mobilenetv3_ssd_lite import create_mobilenetv3_large_ssd_lite, create_mobilenetv3_small_ssd_lite +from vision.ssd.mobilenetv1_ssd import create_mobilenetv1_ssd, create_mobilenetv1_ssd_predictor +from vision.ssd.mobilenetv1_ssd_lite import create_mobilenetv1_ssd_lite, create_mobilenetv1_ssd_lite_predictor +from vision.ssd.squeezenet_ssd_lite import create_squeezenet_ssd_lite, create_squeezenet_ssd_lite_predictor +from vision.ssd.mobilenet_v2_ssd_lite import create_mobilenetv2_ssd_lite, create_mobilenetv2_ssd_lite_predictor +from vision.ssd.vgg_ssd import create_vgg_ssd, create_vgg_ssd_predictor +from vision.datasets.voc_dataset import VOCDataset +from vision.datasets.open_images import OpenImagesDataset +from vision.nn.multibox_loss import MultiboxLoss +from vision.ssd.config import vgg_ssd_config +from vision.ssd.config import mobilenetv1_ssd_config +from vision.ssd.config import squeezenet_ssd_config +from vision.ssd.data_preprocessing import TrainAugmentation, TestTransform +from eval_ssd import predicate +from vision.utils.misc import str2bool +from apex import amp + +parser = argparse.ArgumentParser( + description='Single Shot MultiBox Detector Training With Pytorch') + +# dataset setting +parser.add_argument("--dataset_type", default="voc", type=str, + help='Specify dataset type. Currently support voc and open_images.') +parser.add_argument('--data_path', default='') +parser.add_argument('--datasets', default=[], help='Dataset directory path') +parser.add_argument('--validation_dataset', help='Dataset directory path') +parser.add_argument('--balance_data', action='store_true', + help="Balance training data by down-sampling more frequent labels.") + +# Params for loading pretrained basenet or checkpoints. +parser.add_argument('--base_net', default='', + help='Pretrained base model') +parser.add_argument('--pretrained_ssd', default='', help='Pre-trained base model') +parser.add_argument('--resume', default=None, type=str, + help='Checkpoint state_dict file to resume training from') +parser.add_argument('--net', default="vgg16-ssd", + help="The network architecture, it can be mb1-ssd, mb1-lite-ssd, mb2-ssd-lite, mb3-large-ssd-lite, mb3-small-ssd-lite or vgg16-ssd.") +parser.add_argument('--freeze_base_net', action='store_true', + help="Freeze base net layers.") +parser.add_argument('--freeze_net', action='store_true', + help="Freeze all the layers except the prediction head.") +parser.add_argument('--mb2_width_mult', default=1.0, type=float, + help='Width Multiplifier for MobilenetV2') + +# Params for SGD +parser.add_argument('--lr', '--learning-rate', default=1e-3, type=float, + help='initial learning rate') +parser.add_argument('--momentum', default=0.9, type=float, + help='Momentum value for optim') +parser.add_argument('--weight_decay', default=5e-4, type=float, + help='Weight decay for SGD') +parser.add_argument('--gamma', default=0.1, type=float, + help='Gamma update for SGD') +parser.add_argument('--base_net_lr', default=None, type=float, + help='initial learning rate for base net.') +parser.add_argument('--extra_layers_lr', default=None, type=float, + help='initial learning rate for the layers not in base net and prediction heads.') + +# Scheduler +parser.add_argument('--scheduler', default="multi-step", type=str, + help="Scheduler for SGD. It can one of multi-step and cosine") + +# Params for Multi-step Scheduler +parser.add_argument('--milestones', default="80,100", type=str, + help="milestones for MultiStepLR") + +# Params for Cosine Annealing +parser.add_argument('--t_max', default=120, type=float, + help='T_max value for Cosine Annealing Scheduler.') + +# Train params +parser.add_argument('--batch_size', default=32, type=int, + help='Batch size for training') +parser.add_argument('--num_epochs', default=120, type=int, + help='the number epochs') +parser.add_argument('--num_workers', default=4, type=int, + help='Number of workers used in dataloading') +parser.add_argument('--validation_epochs', default=5, type=int, + help='the number epochs') +parser.add_argument('--debug_steps', default=100, type=int, + help='Set the debug log output frequency.') +parser.add_argument('--checkpoint_folder', default='models/', + help='Directory for saving checkpoint models') +# eval params +parser.add_argument("--nms_method", type=str, default="hard") +parser.add_argument("--use_2007_metric", type=str2bool, default=True) +parser.add_argument("--iou_threshold", type=float, default=0.5, help="The threshold of Intersection over Union.") +parser.add_argument("--eval_dir", default="eval_results", type=str, help="The directory to store evaluation results.") + +# distributed setting +parser.add_argument('--distributed', default=False, action='store_true', + help='Use multi-processing distributed training to launch ') +parser.add_argument('--seed', default=None, type=int, + help='seed for initializing training. ') +parser.add_argument('--device', default='gpu', type=str, help='npu or gpu') +parser.add_argument('--gpu', default=0, type=int, + help='GPU id to use.') +parser.add_argument('--device_list', default='0,1,2,3,4,5,6,7', type=str, help='device id list') +parser.add_argument('--world_size', default=-1, type=int, + help='number of nodes for distributed training') +parser.add_argument('--rank', default=-1, type=int, + help='node rank for distributed training') +parser.add_argument('--dist_url', default='', type=str, + help='url used to set up distributed training') +parser.add_argument('--dist_backend', default='nccl', type=str, + help='distributed backend, nccl for GPU, hccl for NPU') +parser.add_argument('--addr', default='127.0.0.1', type=str, help='master addr') +parser.add_argument('--port', default='29688', type=str, help='master port') + +# apex setting +parser.add_argument('--amp', default=False, action='store_true', + help='use amp to train the model') +parser.add_argument('--opt_level', default='O2', type=str, help='apex optimize level') +parser.add_argument('--loss_scale_value', default=128.0, type=int, help='static loss scale value') + +# learning rate setting +parser.add_argument('--warm_up', default=False, action='store_true', help='use warm_up or not') +parser.add_argument('--warm_up_epochs', default=5, type=int, help='warm up epochs') +parser.add_argument('--stay_lr', default=-1, type=int, help='Epoch with constant learning rate') + +logging.basicConfig(stream=sys.stdout, level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') + + +def device_id_to_process_device_map(device_list): + devices = device_list.split(",") + devices = [int(x) for x in devices] + devices.sort() + + process_device_map = dict() + for process_id, device_id in enumerate(devices): + process_device_map[process_id] = device_id + + return process_device_map + + +def train(loader, net, criterion, optimizer, args, timer, debug_steps=100, epoch=-1): + net.train(True) + running_loss = 0.0 + running_regression_loss = 0.0 + running_classification_loss = 0.0 + timer.start('batch_time') + timer.start('multi_step_time') + multi_step = 0 + for i, data in enumerate(loader): + images, boxes, labels = data + boxes, labels = boxes.to(args.device), labels.to(args.device) + optimizer.zero_grad() + confidence, locations = net.forward(images) + regression_loss, classification_loss = criterion(confidence, locations, labels, boxes) # TODO CHANGE BOXES + loss = (regression_loss + classification_loss) + if args.amp: + with amp.scale_loss(loss, optimizer) as scale_loss: + scale_loss.backward() + else: + loss.backward() + optimizer.step() + + running_loss += loss.item() + running_regression_loss += regression_loss.item() + running_classification_loss += classification_loss.item() + multi_step += 1 + if (i % debug_steps == 0 or i == len(loader) - 1) and (not args.distributed or args.rank == 0): + avg_loss = running_loss / (i + 1) + avg_reg_loss = running_regression_loss / (i + 1) + avg_clf_loss = running_classification_loss / (i + 1) + multi_step_time = timer.end('multi_step_time') + logging.info( + f"Epoch: {epoch}, Step: {i}, " + + f"multi_step_time: {multi_step_time:.4f}, " + + f"step_avg_time: {multi_step_time / multi_step:.4f}, " + + f"Average Regression Loss {avg_reg_loss:.4f}, " + + f"Average Classification Loss: {avg_clf_loss:.4f}, " + + f"Average Loss: {avg_loss:.4f}" + ) + multi_step = 0 + timer.start('multi_step_time') + if not args.distributed or args.rank == 0: + batch_time = timer.end('batch_time') + logging.info(f"Epoch: {epoch}, " + + f"batch_time: {batch_time:.4f}, " + + f"FPS: {args.batch_size * args.ngpu * len(loader) / batch_time:.4f} ") + + +def test(loader, net, criterion, args, epoch=-1): + net.eval() + running_loss = 0.0 + running_regression_loss = 0.0 + running_classification_loss = 0.0 + num = 0 + for i, data in enumerate(loader): + images, boxes, labels = data + num += 1 + with torch.no_grad(): + confidence, locations = net(images) + regression_loss, classification_loss = criterion(confidence.cpu(), locations.cpu(), labels, boxes) + loss = regression_loss + classification_loss + running_loss += loss.item() + running_regression_loss += regression_loss.item() + running_classification_loss += classification_loss.item() + if not args.distributed or args.rank == 0: + logging.info( + f"Epoch: {epoch}, Step: {i}, " + + f"Average Regression Loss {running_regression_loss / (i + 1):.4f}, " + + f"Average Classification Loss: {running_classification_loss / (i + 1):.4f}, " + + f"Average Loss: {running_loss / (i + 1):.4f}" + ) + return running_loss / num, running_regression_loss / num, running_classification_loss / num + + +def main_worker(gpu, timer, args): + args.gpu = args.process_device_map[gpu] + print(args.gpu) + if args.distributed: + if args.device == 'npu': + torch.distributed.init_process_group(backend=args.dist_backend, + world_size=args.ngpu, + rank=args.rank) + else: + torch.distributed.init_process_group(backend=args.dist_backend, + init_method="env://", + world_size=args.ngpu, + rank=args.rank) + if args.device == 'npu': + args.device = 'npu:{}'.format(args.gpu) + print(args.device) + torch.npu.set_device(args.device) + logging.info('use NPU, {}'.format(args.device)) + elif args.device == 'gpu': + args.device = 'cuda:{}'.format(args.gpu) + torch.backends.cudnn.benchmark = True + logging.info('use GPU, {}'.format(args.device)) + + if args.net == 'vgg16-ssd': + create_net = create_vgg_ssd + create_predictor = lambda net: create_vgg_ssd_predictor(net, nms_method=args.nms_method, device=args.device) + config = vgg_ssd_config + elif args.net == 'mb1-ssd': + create_net = create_mobilenetv1_ssd + create_predictor = lambda net: create_mobilenetv1_ssd_predictor(net, nms_method=args.nms_method, + device=args.device) + config = mobilenetv1_ssd_config + elif args.net == 'mb1-ssd-lite': + create_net = create_mobilenetv1_ssd_lite + create_predictor = lambda net: create_mobilenetv1_ssd_lite_predictor(net, nms_method=args.nms_method, + device=args.device) + config = mobilenetv1_ssd_config + elif args.net == 'sq-ssd-lite': + create_net = create_squeezenet_ssd_lite + create_predictor = lambda net: create_squeezenet_ssd_lite_predictor(net, nms_method=args.nms_method, + device=args.device) + config = squeezenet_ssd_config + elif args.net == 'mb2-ssd-lite': + create_net = lambda num: create_mobilenetv2_ssd_lite(num, width_mult=args.mb2_width_mult, device=args.device) + create_predictor = lambda net: create_mobilenetv2_ssd_lite_predictor(net, nms_method=args.nms_method, + device=args.device) + config = mobilenetv1_ssd_config + elif args.net == 'mb3-large-ssd-lite': + create_net = lambda num: create_mobilenetv3_large_ssd_lite(num) + create_predictor = lambda net: create_mobilenetv2_ssd_lite_predictor(net, nms_method=args.nms_method, + device=args.device) + config = mobilenetv1_ssd_config + elif args.net == 'mb3-small-ssd-lite': + create_net = lambda num: create_mobilenetv3_small_ssd_lite(num) + create_predictor = lambda net: create_mobilenetv2_ssd_lite_predictor(net, nms_method=args.nms_method, + device=args.device) + config = mobilenetv1_ssd_config + else: + logging.fatal("The net type is wrong.") + parser.print_help(sys.stderr) + sys.exit(1) + train_transform = TrainAugmentation(config.image_size, config.image_mean, config.image_std) + target_transform = MatchPrior(config.priors, config.center_variance, + config.size_variance, 0.5) + + test_transform = TestTransform(config.image_size, config.image_mean, config.image_std) + logging.info("Prepare training datasets.") + datasets = [] + for dataset_path in args.datasets: + if args.dataset_type == 'voc': + dataset = VOCDataset(dataset_path, transform=train_transform, + target_transform=target_transform) + label_file = os.path.join(args.checkpoint_folder, "voc-model-labels.txt") + store_labels(label_file, dataset.class_names) + num_classes = len(dataset.class_names) + elif args.dataset_type == 'open_images': + dataset = OpenImagesDataset(dataset_path, + transform=train_transform, target_transform=target_transform, + dataset_type="train", balance_data=args.balance_data) + label_file = os.path.join(args.checkpoint_folder, "open-images-model-labels.txt") + store_labels(label_file, dataset.class_names) + logging.info(dataset) + num_classes = len(dataset.class_names) + + else: + raise ValueError(f"Dataset type {args.dataset_type} is not supported.") + datasets.append(dataset) + logging.info(f"Stored labels into file {label_file}.") + train_dataset = ConcatDataset(datasets) + logging.info("Train dataset size: {}".format(len(train_dataset))) + + if args.distributed: + train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset) + train_loader = DataLoader(train_dataset, + args.batch_size, + num_workers=args.num_workers, + sampler=train_sampler if args.distributed else None, + shuffle=False if args.distributed else True) + logging.info("Prepare Validation datasets.") + if args.dataset_type == "voc": + val_dataset = VOCDataset(args.validation_dataset, transform=test_transform, + target_transform=target_transform, is_test=True) + elif args.dataset_type == 'open_images': + val_dataset = OpenImagesDataset(dataset_path, + transform=test_transform, target_transform=target_transform, + dataset_type="test") + logging.info(val_dataset) + logging.info("validation dataset size: {}".format(len(val_dataset))) + + val_loader = DataLoader(val_dataset, args.batch_size, + num_workers=args.num_workers, + shuffle=False) + + logging.info("Build network.") + net = create_net(num_classes) + min_loss = -10000.0 + last_epoch = -1 + + base_net_lr = args.base_net_lr if args.base_net_lr is not None else args.lr + extra_layers_lr = args.extra_layers_lr if args.extra_layers_lr is not None else args.lr + if args.freeze_base_net: + logging.info("Freeze base net.") + freeze_net_layers(net.base_net) + params = itertools.chain(net.source_layer_add_ons.parameters(), net.extras.parameters(), + net.regression_headers.parameters(), net.classification_headers.parameters()) + params = [ + {'params': itertools.chain( + net.source_layer_add_ons.parameters(), + net.extras.parameters() + ), 'lr': extra_layers_lr}, + {'params': itertools.chain( + net.regression_headers.parameters(), + net.classification_headers.parameters() + )} + ] + elif args.freeze_net: + freeze_net_layers(net.base_net) + freeze_net_layers(net.source_layer_add_ons) + freeze_net_layers(net.extras) + params = itertools.chain(net.regression_headers.parameters(), net.classification_headers.parameters()) + logging.info("Freeze all the layers except prediction heads.") + else: + params = [ + {'params': net.base_net.parameters(), 'lr': base_net_lr}, + {'params': itertools.chain( + net.source_layer_add_ons.parameters(), + net.extras.parameters() + ), 'lr': extra_layers_lr}, + {'params': itertools.chain( + net.regression_headers.parameters(), + net.classification_headers.parameters() + )} + ] + net.to(args.device) + criterion = MultiboxLoss(config.priors, iou_threshold=0.5, neg_pos_ratio=3, + center_variance=0.1, size_variance=0.2, device=args.device) + # npu: NpuFusedSGD + if 'npu' in args.device: + optimizer = apex.optimizers.NpuFusedSGD(params, lr=args.lr, momentum=args.momentum, + weight_decay=args.weight_decay) + else: + optimizer = torch.optim.SGD(params, lr=args.lr, momentum=args.momentum, + weight_decay=args.weight_decay) + timer.start("Load Model") + if args.resume: + logging.info(f"Resume from the model {args.resume}") + checkpoint = torch.load(args.resume, map_location='cpu') + pretrained_dic = {k.replace('module.', ''): v for k, v in checkpoint['state_dict'].items()} + net.load_state_dict(pretrained_dic) + optimizer.load_state_dict(checkpoint['optimizer']) + last_epoch = checkpoint['epoch'] + elif args.base_net: + logging.info(f"Init from base net {args.base_net}") + net.init_from_base_net(args.base_net) + elif args.pretrained_ssd: + logging.info(f"Init from pretrained ssd {args.pretrained_ssd}") + net.init_from_pretrained_ssd(args.pretrained_ssd) + logging.info(f'Took {timer.end("Load Model"):.2f} seconds to load the model.') + + if args.amp: + net, optimizer = amp.initialize(net, optimizer, opt_level=args.opt_level, loss_scale=args.loss_scale_value) + if args.distributed: + net = torch.nn.parallel.DistributedDataParallel(net, device_ids=[args.rank], + broadcast_buffers=False if 'npu' in args.device else True) + logging.info(f"Learning rate: {args.lr}, Base net learning rate: {base_net_lr}, " + + f"Extra Layers learning rate: {extra_layers_lr}.") + + if args.scheduler == 'multi-step': + logging.info("Uses MultiStepLR scheduler.") + milestones = [int(v.strip()) for v in args.milestones.split(",")] + scheduler = MultiStepLR(optimizer, milestones=milestones, + gamma=0.1, last_epoch=last_epoch) + elif args.scheduler == 'cosine': + logging.info("Uses CosineAnnealingLR scheduler.") + scheduler = CosineAnnealingLR(optimizer, args.t_max, last_epoch=last_epoch) + else: + logging.fatal(f"Unsupported Scheduler: {args.scheduler}.") + parser.print_help(sys.stderr) + sys.exit(1) + if args.warm_up: + warm_up_scheduler = LambdaLR(optimizer, lr_lambda=lambda epoch: epoch / args.warm_up_epochs) + + logging.info(f"Start training from epoch {last_epoch + 1}.") + for epoch in range(last_epoch + 1, args.num_epochs): + if args.distributed: + train_sampler.set_epoch(epoch) + if args.warm_up and epoch < args.warm_up_epochs: + warm_up_scheduler.step() + else: + scheduler.step() + train(train_loader, net, criterion, optimizer, args, timer, + debug_steps=args.debug_steps, epoch=epoch) + if (epoch % args.validation_epochs == 0 or epoch == args.num_epochs - 1) and ( + not args.distributed or args.rank == 0): + val_loss, val_regression_loss, val_classification_loss = test(val_loader, net, criterion, args, epoch) + logging.info( + f"Epoch: {epoch}, " + + f"Validation Regression Loss {val_regression_loss:.4f}, " + + f"Validation Classification Loss: {val_classification_loss:.4f}, " + + f"Validation Loss: {val_loss:.4f}" + ) + model_path = os.path.join(args.checkpoint_folder, f"{args.net}-Epoch-{epoch}-Loss-{val_loss}.pth") + torch.save({'state_dict': net.state_dict(), 'epoch': epoch, 'optimizer': optimizer.state_dict()}, + model_path) + logging.info(f"Saved model {model_path}") + + # 默认只测最后一轮的精度 + predictor = create_predictor(net) + val_dataset = VOCDataset(args.validation_dataset, is_test=True) + accuracy = predicate(val_dataset, predictor, args, dataset.class_names) + logging.info(f'epoch: {epoch}, accuracy: {accuracy}') + + +if __name__ == '__main__': + timer = Timer() + args = parser.parse_args() + if args.device == 'npu': + os.environ['MASTER_ADDR'] = args.addr + os.environ['MASTER_PORT'] = args.port + + logging.info(args) + args.process_device_map = device_id_to_process_device_map(args.device_list) + + if not os.path.exists(args.eval_dir): + os.makedirs(args.eval_dir) + if not os.path.exists(args.checkpoint_folder): + os.makedirs(args.checkpoint_folder) + args.datasets = [os.path.join(args.data_path, 'VOC2007_trainval'), os.path.join(args.data_path, 'VOC2012_trainval')] + args.validation_dataset = os.path.join(args.data_path, 'VOC2007_test') + if args.distributed: + args.ngpu = int(os.environ['RANK_SIZE']) + main_worker(args.rank, timer, args) + else: + args.ngpu = 1 + main_worker(args.gpu, timer, args) diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/translate_tf_mobilenetv1.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/translate_tf_mobilenetv1.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/datasets/collation.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/datasets/collation.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/datasets/generate_vocdata.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/datasets/generate_vocdata.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/datasets/open_images.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/datasets/open_images.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/datasets/voc_dataset.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/datasets/voc_dataset.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/alexnet.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/alexnet.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/mobilenet.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/mobilenet.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/mobilenet_v2.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/mobilenet_v2.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/mobilenetv3.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/mobilenetv3.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/multibox_loss.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/multibox_loss.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/scaled_l2_norm.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/scaled_l2_norm.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/squeezenet.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/squeezenet.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/vgg.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/nn/vgg.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/prunning/prunner.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/prunning/prunner.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/config/mobilenetv1_ssd_config.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/config/mobilenetv1_ssd_config.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/config/squeezenet_ssd_config.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/config/squeezenet_ssd_config.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/config/vgg_ssd_config.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/config/vgg_ssd_config.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/data_preprocessing.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/data_preprocessing.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/fpn_mobilenetv1_ssd.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/fpn_mobilenetv1_ssd.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/fpn_ssd.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/fpn_ssd.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/mobilenet_v2_ssd_lite.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/mobilenet_v2_ssd_lite.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/mobilenetv1_ssd.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/mobilenetv1_ssd.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/mobilenetv1_ssd_lite.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/mobilenetv1_ssd_lite.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/mobilenetv3_ssd_lite.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/mobilenetv3_ssd_lite.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/predictor.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/predictor.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/squeezenet_ssd_lite.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/squeezenet_ssd_lite.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/ssd.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/ssd.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/vgg_ssd.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/ssd/vgg_ssd.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/test/test_vgg_ssd.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/test/test_vgg_ssd.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/transforms/transforms.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/transforms/transforms.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/utils/__init__.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/utils/__init__.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/utils/box_utils.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/utils/box_utils.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/utils/box_utils_numpy.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/utils/box_utils_numpy.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/utils/measurements.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/utils/measurements.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/utils/misc.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/utils/misc.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/utils/model_book.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/vision/utils/model_book.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-MobilenetV2/visual_tf_models.py b/PyTorch/contrib/cv/detection/SSD-MobilenetV2/visual_tf_models.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD-Resnet/README.md b/PyTorch/contrib/cv/detection/SSD-Resnet/README.md index aab3735567..96ba50816f 100644 --- a/PyTorch/contrib/cv/detection/SSD-Resnet/README.md +++ b/PyTorch/contrib/cv/detection/SSD-Resnet/README.md @@ -1,61 +1,61 @@ -# #SSD-Resnet34 - -This implements training of SSD-Resnet34 on the 2017 COCO dataset. - - - -## #SSD-Resnet34 Detail - -On the basis of resnet34, a part of the feature layer is added for single target detection. - -## Requirements - -* Install Pytorch==1.5.0 and torchvision - -* Install requirements.txt - -* Steps to download pretrain-pth - - ``` - wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E8%AE%AD%E7%BB%83/cv/image_object_detection/SSD-ResNet34/resnet34-333f7ec4.pth - ``` - -* Steps to download data - - ``` - source download_dataset.sh - ``` - - - -# Training - -### To train a model, run `training.py` with the desired model architecture and the path to the coco dataset: - -``` -# training 1p accuracy -cd ./test -bash train_full_1p.sh --data_path=real_data_path -# training 1p performance -cd ./test -bash train_performance_1p.sh --data_path=real_data_path -# training 8p accuracy -cd ./test -bash train_full_8p.sh --data_path=real_data_path -# training 8p performance -cd ./test -bash train_performance_8p.sh --data_path=real_data_path -#test 8p accuracy -bash test/train_eval_8p.sh --data_path=real_data_path --checkpoint_path=real_pre_train_model_path -``` - -Log path: -test/output/{device_id}/train_{device_id}.log -test/output/{device_id}/train_performance_{device_id}.log - -## SSD-Resnet34 training result - -| Acc@1 | FPS | Npu_nums | Epochs | AMP_Type | -| ------ | ---- | -------- | ------ | -------- | -| - | 265 | 1 | 1 | O2 | +# #SSD-Resnet34 + +This implements training of SSD-Resnet34 on the 2017 COCO dataset. + + + +## #SSD-Resnet34 Detail + +On the basis of resnet34, a part of the feature layer is added for single target detection. + +## Requirements + +* Install Pytorch==1.5.0 and torchvision + +* Install requirements.txt + +* Steps to download pretrain-pth + + ``` + wget https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E9%AA%8C%E6%94%B6-%E8%AE%AD%E7%BB%83/cv/image_object_detection/SSD-ResNet34/resnet34-333f7ec4.pth + ``` + +* Steps to download data + + ``` + source download_dataset.sh + ``` + + + +# Training + +### To train a model, run `training.py` with the desired model architecture and the path to the coco dataset: + +``` +# training 1p accuracy +cd ./test +bash train_full_1p.sh --data_path=real_data_path +# training 1p performance +cd ./test +bash train_performance_1p.sh --data_path=real_data_path +# training 8p accuracy +cd ./test +bash train_full_8p.sh --data_path=real_data_path +# training 8p performance +cd ./test +bash train_performance_8p.sh --data_path=real_data_path +#test 8p accuracy +bash test/train_eval_8p.sh --data_path=real_data_path --checkpoint_path=real_pre_train_model_path +``` + +Log path: +test/output/{device_id}/train_{device_id}.log +test/output/{device_id}/train_performance_{device_id}.log + +## SSD-Resnet34 training result + +| Acc@1 | FPS | Npu_nums | Epochs | AMP_Type | +| ------ | ---- | -------- | ------ | -------- | +| - | 265 | 1 | 1 | O2 | | 0.2301 | 1700 | 8 | 90 | O2 | \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/SSD-Resnet/demo.py b/PyTorch/contrib/cv/detection/SSD-Resnet/demo.py index 5b2972956b..4ac02fdea4 100644 --- a/PyTorch/contrib/cv/detection/SSD-Resnet/demo.py +++ b/PyTorch/contrib/cv/detection/SSD-Resnet/demo.py @@ -1,489 +1,489 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 base_model import Loss -import sys -import os -from opt_loss import OptLoss -from mlperf_logger import configure_logger, log_start, log_end, log_event, set_seeds, get_rank, barrier -from mlperf_logging.mllog import constants -import torch -from torch.autograd import Variable -import time -import numpy as np -import io -from bisect import bisect # for lr_scheduler -from apex import amp -from ssd300 import SSD300 -from master_params import create_flat_master -from parse_config import parse_args, validate_arguments, validate_group_bn -from data.build_pipeline import prebuild_pipeline, build_pipeline -from box_coder import dboxes300_coco, build_ssd300_coder -from async_evaluator import AsyncEvaluator -from eval import coco_eval -from apex.optimizers import NpuFusedSGD -import gc -from torch.nn.parallel import DistributedDataParallel -# necessary pytorch imports -import torch.utils.data.distributed -import torch.distributed as dist - -# Apex imports -try: - import apex_C - import apex - from apex.parallel.LARC import LARC - from apex.parallel import DistributedDataParallel as DDP - from apex.fp16_utils import * - from apex.multi_tensor_apply import multi_tensor_applier - #import amp_C -except ImportError: - raise ImportError("Please install APEX from https://github.com/nvidia/apex") - -from contextlib import redirect_stdout - -import logging - - -class Logger(object): - logfile = "" - - def __init__(self, filename=""): - self.logfile = filename - self.terminal = sys.stdout - # self.log = open(filename, "a") - return - - def write(self, message): - self.terminal.write(message) - if self.logfile != "": - try: - self.log = open(self.logfile, "a") - self.log.write(message) - self.log.close() - except: - pass - - def flush(self): - pass - - -def print_message(rank, *print_args): - if rank == 0: - print(*print_args) - -def load_checkpoint(model, checkpoint): - print("loading model checkpoint", checkpoint) - od = torch.load(checkpoint) - # remove proceeding 'module' from checkpoint - saved_model = od["model"] - for k in list(saved_model.keys()): - if k.startswith('module.'): - saved_model[k[7:]] = saved_model.pop(k) - if k.startswith('mbox.'): - saved_model.pop(k) - model.load_state_dict(saved_model,strict=False) - -def check_async_evals(args, evaluator, threshold): - finished = 0 - # Note: only one rank does COCOEval, so we need to check there if we've - # finished -- we'll broadcast that to a "finished" tensor to determine - # if we should stop - # Note2: ssd_print contains a barrier() call, implemented with all_reduce - # If we conditional on rank 0, then an ssd_print all_reduce matches with - # the finished all_reduce and all hell breaks loose. - if args.rank == 0: - for epoch, current_accuracy in evaluator.finished_tasks().items(): - # Note: Move to per-iter check - # EVAL_START should be prior to the accuracy/score evaluation but adding the missing EVAL_START here for now - log_start(key=constants.EVAL_START, metadata={'epoch_num' : epoch}) - log_event(key=constants.EVAL_ACCURACY, - value=current_accuracy, - metadata={'epoch_num' : epoch}) - log_end(key=constants.EVAL_STOP, metadata={'epoch_num' : epoch}) - if current_accuracy >= threshold: - finished = 1 - - # handle the non-distributed case -- don't need to bcast, just take local result - if not args.distributed: - return finished == 1 - - # Now we know from all ranks if they're done - reduce result - # Note: Already caught the non-distributed case above, can assume broadcast is available - with torch.no_grad(): - finish_tensor = torch.tensor([finished], dtype=torch.int32, device=torch.device('npu')) - # torch.distributed.all_reduce(finish_tensor) - torch.distributed.broadcast(finish_tensor, src=0) - - # >= 1 ranks has seen final accuracy - if finish_tensor.item() >= 1: - return True - - # Default case: No results, or no accuracte enough results - return False - -def lr_warmup(optim, warmup_iter, iter_num, epoch, base_lr, args): - if iter_num < warmup_iter: - warmup_step = base_lr / (warmup_iter * (2 ** args.warmup_factor)) - new_lr = base_lr - (warmup_iter - iter_num) * warmup_step - - for param_group in optim.param_groups: - param_group['lr'] = new_lr - -def setup_distributed(args): - # Setup multi-GPU if necessary - - args.distributed = False - if 'WORLD_SIZE' in os.environ: - args.distributed = int(os.environ['WORLD_SIZE']) > 1 - os.environ['MASTER_ADDR'] = '127.0.0.1' - os.environ['MASTER_PORT'] = '29688' - if args.distributed: - torch.npu.set_device(args.local_rank) - torch.distributed.init_process_group(backend='hccl', - world_size=int(os.environ['WORLD_SIZE']), - rank=args.local_rank, - ) - args.local_seed = set_seeds(args) - # start timing here - if args.distributed: - args.N_gpu = torch.distributed.get_world_size() - args.rank = torch.distributed.get_rank() - else: - args.N_gpu = 1 - args.rank = 0 - - validate_group_bn(args.bn_group) - - return args - -def train300_mlperf_coco(args): - - - args = setup_distributed(args) - - # Build the model - model_options = { - 'use_nhwc' : args.nhwc, - 'pad_input' : args.pad_input, - 'bn_group' : args.bn_group, - } - - ssd300 = SSD300(args, args.num_classes, **model_options) - if args.checkpoint is not None: - load_checkpoint(ssd300, args.checkpoint) - - ssd300.train() - ssd300.npu() - dboxes = dboxes300_coco() - # Note: No reason not to use optimised loss - #loss_func = OptLoss() - loss_func = Loss(dboxes) - loss_func.npu() - - # Create optimizer. This must also be done after network_to_half. - global_batch_size = (args.N_gpu * args.batch_size) - log_event(key=constants.MODEL_BN_SPAN, value=args.bn_group*args.batch_size) - log_event(key=constants.GLOBAL_BATCH_SIZE, value=global_batch_size) - - # mlperf only allows base_lr scaled by an integer - base_lr = 2.5e-3 - requested_lr_multiplier = args.lr / base_lr - adjusted_multiplier = max(1, round(requested_lr_multiplier * global_batch_size / 32)) - - current_lr = base_lr * adjusted_multiplier - current_momentum = 0.9 - current_weight_decay = args.wd - static_loss_scale = args.loss_scale - - - optim = apex.optimizers.NpuFusedSGD(ssd300.parameters(), - lr=current_lr, - momentum=current_momentum, - weight_decay=current_weight_decay) - ssd300, optim = amp.initialize(ssd300, optim, opt_level='O2', loss_scale=static_loss_scale,combine_grad=True) - # Parallelize. Need to do this after network_to_half. - if args.distributed: - if args.delay_allreduce: - print_message(args.local_rank, "Delaying allreduces to the end of backward()") - ssd300 = DistributedDataParallel(ssd300, device_ids=[args.local_rank]) - - log_event(key=constants.OPT_BASE_LR, value=current_lr) - log_event(key=constants.OPT_LR_DECAY_BOUNDARY_EPOCHS, value=args.lr_decay_epochs) - log_event(key=constants.OPT_LR_DECAY_STEPS, value=args.lr_decay_epochs) - log_event(key=constants.OPT_WEIGHT_DECAY, value=current_weight_decay) - if args.warmup is not None: - log_event(key=constants.OPT_LR_WARMUP_STEPS, value=args.warmup) - log_event(key=constants.OPT_LR_WARMUP_FACTOR, value=args.warmup_factor) - - # Model is completely finished -- need to create separate copies, preserve parameters across - # them, and jit - ssd300_eval = SSD300(args, args.num_classes, **model_options).npu() - - if args.use_fp16: - convert_network(ssd300_eval, torch.half) - - # Get the existant state from the train model - # * if we use distributed, then we want .module - train_model = ssd300.module if args.distributed else ssd300 - ssd300_eval.load_state_dict(train_model.state_dict()) - ssd300_eval.eval() - - - print_message(args.local_rank, "epoch", "nbatch", "loss") - - iter_num = args.iteration - avg_loss = 0.0 - - start_elapsed_time = time.time() - last_printed_iter = args.iteration - num_elapsed_samples = 0 - - input_c = 4 if args.pad_input else 3 - example_shape = [args.batch_size, 300, 300, input_c] if args.nhwc else [args.batch_size, input_c, 300, 300] - example_input = torch.randn(*example_shape).npu() - - if args.use_fp16: - example_input = example_input.half() - - if args.jit: - # DDP has some Python-side control flow. If we JIT the entire DDP-wrapped module, - # the resulting ScriptModule will elide this control flow, resulting in allreduce - # hooks not being called. If we're running distributed, we need to extract and JIT - # the wrapped .module. - # Replacing a DDP-ed ssd300 with a script_module might also cause the AccumulateGrad hooks - # to go out of scope, and therefore silently disappear. - module_to_jit = ssd300.module if args.distributed else ssd300 - if args.distributed: - ssd300.module = torch.jit.trace(module_to_jit, example_input, check_trace=False) - else: - ssd300 = torch.jit.trace(module_to_jit, example_input, check_trace=False) - # JIT the eval model too - ssd300_eval = torch.jit.trace(ssd300_eval, example_input, check_trace=False) - - # do a dummy fprop & bprop to make sure cudnnFind etc. are timed here - ploc, plabel = ssd300(example_input) - - # produce a single dummy "loss" to make things easier - loss = ploc[0,0,0] + plabel[0,0,0] - dloss = torch.randn_like(loss) - # Cause cudnnFind for dgrad, wgrad to run - loss.backward(dloss) - - # Necessary import in init - #from pycocotools.coco import COCO - - encoder = build_ssd300_coder() - - evaluator = AsyncEvaluator(num_threads=1) - - log_end(key=constants.INIT_STOP) - - ##### END INIT - - # This is the first place we touch anything related to data - ##### START DATA TOUCHING - barrier() - log_start(key=constants.RUN_START) - barrier() - - train_pipe = prebuild_pipeline(args) - - train_loader, epoch_size = build_pipeline(args, training=True, pipe=train_pipe) - if args.rank == 0: - print("epoch size is: ", epoch_size, " images") - - val_loader, inv_map, cocoGt = build_pipeline(args, training=False) - if args.profile_gc_off: - gc.disable() - gc.collect() - - ##### END DATA TOUCHING - i_eval = 0 - block_start_epoch = 1 - log_start(key=constants.BLOCK_START, - metadata={'first_epoch_num': block_start_epoch, - 'epoch_count': args.evaluation[i_eval]}) - for epoch in range(args.epochs): - optim.zero_grad() - - - if epoch in args.evaluation: - # Get the existant state from the train model - # * if we use distributed, then we want .module - train_model = ssd300.module if args.distributed else ssd300 - - if args.distributed and args.allreduce_running_stats: - if args.rank == 0: print("averaging bn running means and vars") - # make sure every node has the same running bn stats before - # using them to evaluate, or saving the model for inference - world_size = float(torch.distributed.get_world_size()) - for bn_name, bn_buf in train_model.named_buffers(recurse=True): - if ('running_mean' in bn_name) or ('running_var' in bn_name): - torch.distributed.all_reduce(bn_buf, op=dist.ReduceOp.SUM) - bn_buf /= world_size - - if args.rank == 0: - if args.save: - print("saving model...") - if not os.path.isdir('./models'): - os.mkdir('./models') - torch.save({"model" : ssd300.state_dict()}, "./models/iter_{}.pt".format(iter_num)) - - ssd300_eval.load_state_dict(train_model.state_dict()) - # Note: No longer returns, evaluation is abstracted away inside evaluator - coco_eval(args, - ssd300_eval, - val_loader, - cocoGt, - encoder, - inv_map, - epoch, - iter_num, - evaluator=evaluator) - log_end(key=constants.BLOCK_STOP, metadata={'first_epoch_num': block_start_epoch}) - if epoch != max(args.evaluation): - i_eval += 1 - block_start_epoch = epoch + 1 - log_start(key=constants.BLOCK_START, - metadata={'first_epoch_num': block_start_epoch, - 'epoch_count': (args.evaluation[i_eval] - - args.evaluation[i_eval - 1])}) - - if epoch in args.lr_decay_epochs: - current_lr *= args.lr_decay_factor - print_message(args.rank, "lr decay step #" + str(bisect(args.lr_decay_epochs, epoch))) - for param_group in optim.param_groups: - param_group['lr'] = current_lr - - log_start(key=constants.EPOCH_START, - metadata={'epoch_num': epoch + 1, - 'current_iter_nufm': iter_num}) - - for i, data in enumerate(train_loader): - (img, bbox, label, _) = data - img = img.npu() - bbox = bbox.npu() - label = label.npu() - if args.profile_start is not None and iter_num == args.profile_start: - torch.npu.profiler.start() - torch.npu.synchronize() - if args.profile_nvtx: - torch.autograd._enable_profiler(torch.autograd.ProfilerState.NVTX) - - if args.profile is not None and iter_num == args.profile: - if args.profile_start is not None and iter_num >=args.profile_start: - # we turned npu and nvtx profiling on, better turn it off too - if args.profile_nvtx: - torch.autograd._disable_profiler() - torch.npu.profiler.stop() - return - - if args.warmup is not None: - lr_warmup(optim, args.warmup, iter_num, epoch, current_lr, args) - - if (img is None) or (bbox is None) or (label is None): - print("No labels in batch") - continue - - ploc, plabel = ssd300(img) - ploc, plabel = ploc.float(), plabel.float() - - N = img.shape[0] - bbox.requires_grad = False - label.requires_grad = False - # reshape (N*8732X4 -> Nx8732x4) and transpose (Nx8732x4 -> Nx4x8732) - bbox = bbox.view(N, -1, 4).transpose(1,2).contiguous() - # reshape (N*8732 -> Nx8732) and cast to Long - label = label.view(N, -1).long() - loss = loss_func(ploc, plabel, bbox, label) - - if np.isfinite(loss.item()): - avg_loss = 0.999*avg_loss + 0.001*loss.item() - else: - print("model exploded (corrupted by Inf or Nan)") - sys.exit() - - num_elapsed_samples += N - # if args.rank == 0 and iter_num % args.print_interval == 0: - if args.rank == 0 and iter_num % args.print_interval == 0: - end_elapsed_time = time.time() - elapsed_time = end_elapsed_time - start_elapsed_time - - avg_samples_per_sec = num_elapsed_samples * args.N_gpu / elapsed_time - - print("Epoch:{:4d}, Iteration: {:6d}, Loss function: {:5.3f}, Average Loss: {:.3f}, avg. samples / sec: {:.2f}"\ - .format(epoch, iter_num, loss.item(), avg_loss, avg_samples_per_sec), end="\n") - - last_printed_iter = iter_num - start_elapsed_time = time.time() - num_elapsed_samples = 0 - - - with amp.scale_loss(loss, optim) as scaled_loss: - scaled_loss.backward() - - - optim.step() - - - # Likely a decent skew here, let's take this opportunity to set the - # gradients to None. After DALI integration, playing with the - # placement of this is worth trying. - - optim.zero_grad() - - # Don't check every iteration due to cost of broadcast - if iter_num % 20 == 0: - finished = check_async_evals(args, evaluator, args.threshold) - - if finished: - return True - - iter_num += 1 - - #train_loader.reset() - log_end(key=constants.EPOCH_STOP, metadata={'epoch_num': epoch + 1}) - - return False - -def main(): - # torch.multiprocessing.set_start_method('spawn') - configure_logger(constants.SSD) - log_start(key=constants.INIT_START, log_all_ranks=True) - args = parse_args() - sys.stdout = Logger("test/output/%s/%s_%s.log"%(args.device_id,args.tag,args.device_id)) - sys.stderr = Logger("test/output/%s/%s_%s.log"%(args.device_id,args.tag,args.device_id))#1p - if args.local_rank == 0: - print(args) - - # make sure the epoch lists are in sorted order - args.evaluation.sort() - args.lr_decay_epochs.sort() - - validate_arguments(args) - - torch.set_num_threads(1) - torch.backends.cudnn.benchmark = not args.profile_cudnn_get - - success = train300_mlperf_coco(args) - status = 'success' if success else 'aborted' - - # end timing here - log_end(key=constants.RUN_STOP, metadata={'status': status}) - - -if __name__ == "__main__": - - main() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 base_model import Loss +import sys +import os +from opt_loss import OptLoss +from mlperf_logger import configure_logger, log_start, log_end, log_event, set_seeds, get_rank, barrier +from mlperf_logging.mllog import constants +import torch +from torch.autograd import Variable +import time +import numpy as np +import io +from bisect import bisect # for lr_scheduler +from apex import amp +from ssd300 import SSD300 +from master_params import create_flat_master +from parse_config import parse_args, validate_arguments, validate_group_bn +from data.build_pipeline import prebuild_pipeline, build_pipeline +from box_coder import dboxes300_coco, build_ssd300_coder +from async_evaluator import AsyncEvaluator +from eval import coco_eval +from apex.optimizers import NpuFusedSGD +import gc +from torch.nn.parallel import DistributedDataParallel +# necessary pytorch imports +import torch.utils.data.distributed +import torch.distributed as dist + +# Apex imports +try: + import apex_C + import apex + from apex.parallel.LARC import LARC + from apex.parallel import DistributedDataParallel as DDP + from apex.fp16_utils import * + from apex.multi_tensor_apply import multi_tensor_applier + #import amp_C +except ImportError: + raise ImportError("Please install APEX from https://github.com/nvidia/apex") + +from contextlib import redirect_stdout + +import logging + + +class Logger(object): + logfile = "" + + def __init__(self, filename=""): + self.logfile = filename + self.terminal = sys.stdout + # self.log = open(filename, "a") + return + + def write(self, message): + self.terminal.write(message) + if self.logfile != "": + try: + self.log = open(self.logfile, "a") + self.log.write(message) + self.log.close() + except: + pass + + def flush(self): + pass + + +def print_message(rank, *print_args): + if rank == 0: + print(*print_args) + +def load_checkpoint(model, checkpoint): + print("loading model checkpoint", checkpoint) + od = torch.load(checkpoint) + # remove proceeding 'module' from checkpoint + saved_model = od["model"] + for k in list(saved_model.keys()): + if k.startswith('module.'): + saved_model[k[7:]] = saved_model.pop(k) + if k.startswith('mbox.'): + saved_model.pop(k) + model.load_state_dict(saved_model,strict=False) + +def check_async_evals(args, evaluator, threshold): + finished = 0 + # Note: only one rank does COCOEval, so we need to check there if we've + # finished -- we'll broadcast that to a "finished" tensor to determine + # if we should stop + # Note2: ssd_print contains a barrier() call, implemented with all_reduce + # If we conditional on rank 0, then an ssd_print all_reduce matches with + # the finished all_reduce and all hell breaks loose. + if args.rank == 0: + for epoch, current_accuracy in evaluator.finished_tasks().items(): + # Note: Move to per-iter check + # EVAL_START should be prior to the accuracy/score evaluation but adding the missing EVAL_START here for now + log_start(key=constants.EVAL_START, metadata={'epoch_num' : epoch}) + log_event(key=constants.EVAL_ACCURACY, + value=current_accuracy, + metadata={'epoch_num' : epoch}) + log_end(key=constants.EVAL_STOP, metadata={'epoch_num' : epoch}) + if current_accuracy >= threshold: + finished = 1 + + # handle the non-distributed case -- don't need to bcast, just take local result + if not args.distributed: + return finished == 1 + + # Now we know from all ranks if they're done - reduce result + # Note: Already caught the non-distributed case above, can assume broadcast is available + with torch.no_grad(): + finish_tensor = torch.tensor([finished], dtype=torch.int32, device=torch.device('npu')) + # torch.distributed.all_reduce(finish_tensor) + torch.distributed.broadcast(finish_tensor, src=0) + + # >= 1 ranks has seen final accuracy + if finish_tensor.item() >= 1: + return True + + # Default case: No results, or no accuracte enough results + return False + +def lr_warmup(optim, warmup_iter, iter_num, epoch, base_lr, args): + if iter_num < warmup_iter: + warmup_step = base_lr / (warmup_iter * (2 ** args.warmup_factor)) + new_lr = base_lr - (warmup_iter - iter_num) * warmup_step + + for param_group in optim.param_groups: + param_group['lr'] = new_lr + +def setup_distributed(args): + # Setup multi-GPU if necessary + + args.distributed = False + if 'WORLD_SIZE' in os.environ: + args.distributed = int(os.environ['WORLD_SIZE']) > 1 + os.environ['MASTER_ADDR'] = '127.0.0.1' + os.environ['MASTER_PORT'] = '29688' + if args.distributed: + torch.npu.set_device(args.local_rank) + torch.distributed.init_process_group(backend='hccl', + world_size=int(os.environ['WORLD_SIZE']), + rank=args.local_rank, + ) + args.local_seed = set_seeds(args) + # start timing here + if args.distributed: + args.N_gpu = torch.distributed.get_world_size() + args.rank = torch.distributed.get_rank() + else: + args.N_gpu = 1 + args.rank = 0 + + validate_group_bn(args.bn_group) + + return args + +def train300_mlperf_coco(args): + + + args = setup_distributed(args) + + # Build the model + model_options = { + 'use_nhwc' : args.nhwc, + 'pad_input' : args.pad_input, + 'bn_group' : args.bn_group, + } + + ssd300 = SSD300(args, args.num_classes, **model_options) + if args.checkpoint is not None: + load_checkpoint(ssd300, args.checkpoint) + + ssd300.train() + ssd300.npu() + dboxes = dboxes300_coco() + # Note: No reason not to use optimised loss + #loss_func = OptLoss() + loss_func = Loss(dboxes) + loss_func.npu() + + # Create optimizer. This must also be done after network_to_half. + global_batch_size = (args.N_gpu * args.batch_size) + log_event(key=constants.MODEL_BN_SPAN, value=args.bn_group*args.batch_size) + log_event(key=constants.GLOBAL_BATCH_SIZE, value=global_batch_size) + + # mlperf only allows base_lr scaled by an integer + base_lr = 2.5e-3 + requested_lr_multiplier = args.lr / base_lr + adjusted_multiplier = max(1, round(requested_lr_multiplier * global_batch_size / 32)) + + current_lr = base_lr * adjusted_multiplier + current_momentum = 0.9 + current_weight_decay = args.wd + static_loss_scale = args.loss_scale + + + optim = apex.optimizers.NpuFusedSGD(ssd300.parameters(), + lr=current_lr, + momentum=current_momentum, + weight_decay=current_weight_decay) + ssd300, optim = amp.initialize(ssd300, optim, opt_level='O2', loss_scale=static_loss_scale,combine_grad=True) + # Parallelize. Need to do this after network_to_half. + if args.distributed: + if args.delay_allreduce: + print_message(args.local_rank, "Delaying allreduces to the end of backward()") + ssd300 = DistributedDataParallel(ssd300, device_ids=[args.local_rank]) + + log_event(key=constants.OPT_BASE_LR, value=current_lr) + log_event(key=constants.OPT_LR_DECAY_BOUNDARY_EPOCHS, value=args.lr_decay_epochs) + log_event(key=constants.OPT_LR_DECAY_STEPS, value=args.lr_decay_epochs) + log_event(key=constants.OPT_WEIGHT_DECAY, value=current_weight_decay) + if args.warmup is not None: + log_event(key=constants.OPT_LR_WARMUP_STEPS, value=args.warmup) + log_event(key=constants.OPT_LR_WARMUP_FACTOR, value=args.warmup_factor) + + # Model is completely finished -- need to create separate copies, preserve parameters across + # them, and jit + ssd300_eval = SSD300(args, args.num_classes, **model_options).npu() + + if args.use_fp16: + convert_network(ssd300_eval, torch.half) + + # Get the existant state from the train model + # * if we use distributed, then we want .module + train_model = ssd300.module if args.distributed else ssd300 + ssd300_eval.load_state_dict(train_model.state_dict()) + ssd300_eval.eval() + + + print_message(args.local_rank, "epoch", "nbatch", "loss") + + iter_num = args.iteration + avg_loss = 0.0 + + start_elapsed_time = time.time() + last_printed_iter = args.iteration + num_elapsed_samples = 0 + + input_c = 4 if args.pad_input else 3 + example_shape = [args.batch_size, 300, 300, input_c] if args.nhwc else [args.batch_size, input_c, 300, 300] + example_input = torch.randn(*example_shape).npu() + + if args.use_fp16: + example_input = example_input.half() + + if args.jit: + # DDP has some Python-side control flow. If we JIT the entire DDP-wrapped module, + # the resulting ScriptModule will elide this control flow, resulting in allreduce + # hooks not being called. If we're running distributed, we need to extract and JIT + # the wrapped .module. + # Replacing a DDP-ed ssd300 with a script_module might also cause the AccumulateGrad hooks + # to go out of scope, and therefore silently disappear. + module_to_jit = ssd300.module if args.distributed else ssd300 + if args.distributed: + ssd300.module = torch.jit.trace(module_to_jit, example_input, check_trace=False) + else: + ssd300 = torch.jit.trace(module_to_jit, example_input, check_trace=False) + # JIT the eval model too + ssd300_eval = torch.jit.trace(ssd300_eval, example_input, check_trace=False) + + # do a dummy fprop & bprop to make sure cudnnFind etc. are timed here + ploc, plabel = ssd300(example_input) + + # produce a single dummy "loss" to make things easier + loss = ploc[0,0,0] + plabel[0,0,0] + dloss = torch.randn_like(loss) + # Cause cudnnFind for dgrad, wgrad to run + loss.backward(dloss) + + # Necessary import in init + #from pycocotools.coco import COCO + + encoder = build_ssd300_coder() + + evaluator = AsyncEvaluator(num_threads=1) + + log_end(key=constants.INIT_STOP) + + ##### END INIT + + # This is the first place we touch anything related to data + ##### START DATA TOUCHING + barrier() + log_start(key=constants.RUN_START) + barrier() + + train_pipe = prebuild_pipeline(args) + + train_loader, epoch_size = build_pipeline(args, training=True, pipe=train_pipe) + if args.rank == 0: + print("epoch size is: ", epoch_size, " images") + + val_loader, inv_map, cocoGt = build_pipeline(args, training=False) + if args.profile_gc_off: + gc.disable() + gc.collect() + + ##### END DATA TOUCHING + i_eval = 0 + block_start_epoch = 1 + log_start(key=constants.BLOCK_START, + metadata={'first_epoch_num': block_start_epoch, + 'epoch_count': args.evaluation[i_eval]}) + for epoch in range(args.epochs): + optim.zero_grad() + + + if epoch in args.evaluation: + # Get the existant state from the train model + # * if we use distributed, then we want .module + train_model = ssd300.module if args.distributed else ssd300 + + if args.distributed and args.allreduce_running_stats: + if args.rank == 0: print("averaging bn running means and vars") + # make sure every node has the same running bn stats before + # using them to evaluate, or saving the model for inference + world_size = float(torch.distributed.get_world_size()) + for bn_name, bn_buf in train_model.named_buffers(recurse=True): + if ('running_mean' in bn_name) or ('running_var' in bn_name): + torch.distributed.all_reduce(bn_buf, op=dist.ReduceOp.SUM) + bn_buf /= world_size + + if args.rank == 0: + if args.save: + print("saving model...") + if not os.path.isdir('./models'): + os.mkdir('./models') + torch.save({"model" : ssd300.state_dict()}, "./models/iter_{}.pt".format(iter_num)) + + ssd300_eval.load_state_dict(train_model.state_dict()) + # Note: No longer returns, evaluation is abstracted away inside evaluator + coco_eval(args, + ssd300_eval, + val_loader, + cocoGt, + encoder, + inv_map, + epoch, + iter_num, + evaluator=evaluator) + log_end(key=constants.BLOCK_STOP, metadata={'first_epoch_num': block_start_epoch}) + if epoch != max(args.evaluation): + i_eval += 1 + block_start_epoch = epoch + 1 + log_start(key=constants.BLOCK_START, + metadata={'first_epoch_num': block_start_epoch, + 'epoch_count': (args.evaluation[i_eval] - + args.evaluation[i_eval - 1])}) + + if epoch in args.lr_decay_epochs: + current_lr *= args.lr_decay_factor + print_message(args.rank, "lr decay step #" + str(bisect(args.lr_decay_epochs, epoch))) + for param_group in optim.param_groups: + param_group['lr'] = current_lr + + log_start(key=constants.EPOCH_START, + metadata={'epoch_num': epoch + 1, + 'current_iter_nufm': iter_num}) + + for i, data in enumerate(train_loader): + (img, bbox, label, _) = data + img = img.npu() + bbox = bbox.npu() + label = label.npu() + if args.profile_start is not None and iter_num == args.profile_start: + torch.npu.profiler.start() + torch.npu.synchronize() + if args.profile_nvtx: + torch.autograd._enable_profiler(torch.autograd.ProfilerState.NVTX) + + if args.profile is not None and iter_num == args.profile: + if args.profile_start is not None and iter_num >=args.profile_start: + # we turned npu and nvtx profiling on, better turn it off too + if args.profile_nvtx: + torch.autograd._disable_profiler() + torch.npu.profiler.stop() + return + + if args.warmup is not None: + lr_warmup(optim, args.warmup, iter_num, epoch, current_lr, args) + + if (img is None) or (bbox is None) or (label is None): + print("No labels in batch") + continue + + ploc, plabel = ssd300(img) + ploc, plabel = ploc.float(), plabel.float() + + N = img.shape[0] + bbox.requires_grad = False + label.requires_grad = False + # reshape (N*8732X4 -> Nx8732x4) and transpose (Nx8732x4 -> Nx4x8732) + bbox = bbox.view(N, -1, 4).transpose(1,2).contiguous() + # reshape (N*8732 -> Nx8732) and cast to Long + label = label.view(N, -1).long() + loss = loss_func(ploc, plabel, bbox, label) + + if np.isfinite(loss.item()): + avg_loss = 0.999*avg_loss + 0.001*loss.item() + else: + print("model exploded (corrupted by Inf or Nan)") + sys.exit() + + num_elapsed_samples += N + # if args.rank == 0 and iter_num % args.print_interval == 0: + if args.rank == 0 and iter_num % args.print_interval == 0: + end_elapsed_time = time.time() + elapsed_time = end_elapsed_time - start_elapsed_time + + avg_samples_per_sec = num_elapsed_samples * args.N_gpu / elapsed_time + + print("Epoch:{:4d}, Iteration: {:6d}, Loss function: {:5.3f}, Average Loss: {:.3f}, avg. samples / sec: {:.2f}"\ + .format(epoch, iter_num, loss.item(), avg_loss, avg_samples_per_sec), end="\n") + + last_printed_iter = iter_num + start_elapsed_time = time.time() + num_elapsed_samples = 0 + + + with amp.scale_loss(loss, optim) as scaled_loss: + scaled_loss.backward() + + + optim.step() + + + # Likely a decent skew here, let's take this opportunity to set the + # gradients to None. After DALI integration, playing with the + # placement of this is worth trying. + + optim.zero_grad() + + # Don't check every iteration due to cost of broadcast + if iter_num % 20 == 0: + finished = check_async_evals(args, evaluator, args.threshold) + + if finished: + return True + + iter_num += 1 + + #train_loader.reset() + log_end(key=constants.EPOCH_STOP, metadata={'epoch_num': epoch + 1}) + + return False + +def main(): + # torch.multiprocessing.set_start_method('spawn') + configure_logger(constants.SSD) + log_start(key=constants.INIT_START, log_all_ranks=True) + args = parse_args() + sys.stdout = Logger("test/output/%s/%s_%s.log"%(args.device_id,args.tag,args.device_id)) + sys.stderr = Logger("test/output/%s/%s_%s.log"%(args.device_id,args.tag,args.device_id))#1p + if args.local_rank == 0: + print(args) + + # make sure the epoch lists are in sorted order + args.evaluation.sort() + args.lr_decay_epochs.sort() + + validate_arguments(args) + + torch.set_num_threads(1) + torch.backends.cudnn.benchmark = not args.profile_cudnn_get + + success = train300_mlperf_coco(args) + status = 'success' if success else 'aborted' + + # end timing here + log_end(key=constants.RUN_STOP, metadata={'status': status}) + + +if __name__ == "__main__": + + main() diff --git a/PyTorch/contrib/cv/detection/SSD-Resnet/new.py b/PyTorch/contrib/cv/detection/SSD-Resnet/new.py index adebc268d6..72f9d053b5 100644 --- a/PyTorch/contrib/cv/detection/SSD-Resnet/new.py +++ b/PyTorch/contrib/cv/detection/SSD-Resnet/new.py @@ -1,52 +1,52 @@ -# Copyright 2021 Huawei Technologies Co., Ltd - -# 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 sys -#sys.path.append('/share/home/litaotao/yzc/training_results_v0.7-master/NVIDIA/benchmarks/ssd/implementations/pytorch/')# -import os -#from base_model import Loss -from opt_loss import OptLoss -from mlperf_logger import configure_logger, log_start, log_end, log_event, set_seeds, get_rank, barrier -from mlperf_logging.mllog import constants -import torch -from torch.autograd import Variable -import time -import numpy as np -import io -from bisect import bisect # for lr_scheduler - -from ssd300 import SSD300 -from master_params import create_flat_master -from parse_config import parse_args, validate_arguments, validate_group_bn - -from async_evaluator import AsyncEvaluator -from eval import coco_eval - -#import sys -import gc -from data.native_pipeline import build_train_pipe -# necessary pytorch imports -import torch.utils.data.distributed -import torch.distributed as dist -configure_logger(constants.SSD) -log_start(key=constants.INIT_START, log_all_ranks=True) -args = parse_args() -# make sure the epoch lists are in sorted order -args.evaluation.sort() -args.lr_decay_epochs.sort() - -validate_arguments(args) - -torch.set_num_threads(1) -torch.backends.cudnn.benchmark = not args.profile_cudnn_get +# Copyright 2021 Huawei Technologies Co., Ltd + +# 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 sys +#sys.path.append('/share/home/litaotao/yzc/training_results_v0.7-master/NVIDIA/benchmarks/ssd/implementations/pytorch/')# +import os +#from base_model import Loss +from opt_loss import OptLoss +from mlperf_logger import configure_logger, log_start, log_end, log_event, set_seeds, get_rank, barrier +from mlperf_logging.mllog import constants +import torch +from torch.autograd import Variable +import time +import numpy as np +import io +from bisect import bisect # for lr_scheduler + +from ssd300 import SSD300 +from master_params import create_flat_master +from parse_config import parse_args, validate_arguments, validate_group_bn + +from async_evaluator import AsyncEvaluator +from eval import coco_eval + +#import sys +import gc +from data.native_pipeline import build_train_pipe +# necessary pytorch imports +import torch.utils.data.distributed +import torch.distributed as dist +configure_logger(constants.SSD) +log_start(key=constants.INIT_START, log_all_ranks=True) +args = parse_args() +# make sure the epoch lists are in sorted order +args.evaluation.sort() +args.lr_decay_epochs.sort() + +validate_arguments(args) + +torch.set_num_threads(1) +torch.backends.cudnn.benchmark = not args.profile_cudnn_get build_train_pipe(args) \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/SSD-Resnet/nms.py b/PyTorch/contrib/cv/detection/SSD-Resnet/nms.py index b6aa557721..7a81227046 100644 --- a/PyTorch/contrib/cv/detection/SSD-Resnet/nms.py +++ b/PyTorch/contrib/cv/detection/SSD-Resnet/nms.py @@ -1,146 +1,146 @@ -# Copyright (c) 2020, Huawei Technologies.All rights reserved. -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 torch - - -def npu_multiclass_nms(multi_bboxes, - multi_scores, - score_thr=0.05, - nms_thr=0.45, - max_num=50, - score_factors=None): - """NMS for multi-class bboxes using npu api. - - Origin implement from mmdetection is - https://github.com/open-mmlab/mmdetection/blob/master/mmdet/core/post_processing/bbox_nms.py#L7 - - This interface is similar to the original interface, but not exactly the same. - - Args: - multi_bboxes (Tensor): shape (n, #class, 4) or (n, 4) - multi_scores (Tensor): shape (n, #class+1), where the last column - contains scores of the background class, but this will be ignored. - On npu, in order to keep the semantics unblocked, we will unify the dimensions - score_thr (float): bbox threshold, bboxes with scores lower than it - will not be considered. - nms_thr (float): NMS IoU threshold. In the original implementation, a dictionary of {"iou_threshold": 0.45} - was passed, which is simplified here. - max_num (int): if there are more than max_num bboxes after NMS, - only top max_num will be kept; if there are less than max_num bboxes after NMS, - the output will zero pad to max_num. On the NPU, the memory needs to be requested in advance, - so the current max_num cannot be set to -1 at present - score_factors (Tensor): The factors multiplied to scores before applying NMS - - Returns: - tuple: (bboxes, labels), tensors of shape (k, 5) and (k, 1). Labels are 0-based. - """ - - num_classes = multi_scores.size(1) - 1 - num_boxes = multi_scores.size(0) - if score_factors is not None: - multi_scores = multi_scores[:, :-1] * score_factors[:, None] - else: - multi_scores = multi_scores[:, :-1] - multi_bboxes = multi_bboxes.reshape(1, num_boxes, multi_bboxes.numel() // 4 // num_boxes, 4) - multi_scores = multi_scores.reshape(1, num_boxes, num_classes) - - nmsed_boxes, nmsed_scores, nmsed_classes, nmsed_num = torch.npu_batch_nms(multi_bboxes.half(), multi_scores.half(), - score_thr, nms_thr, - max_num, max_num) - - nmsed_boxes = nmsed_boxes.reshape(nmsed_boxes.shape[1:]) - nmsed_scores = nmsed_scores.reshape(nmsed_scores.shape[1]) - nmsed_classes = nmsed_classes.reshape(nmsed_classes.shape[1]) - - return torch.cat([nmsed_boxes, nmsed_scores[:, None]], -1), nmsed_classes - - -def npu_batched_multiclass_nms( - multi_bboxes, - multi_scores, - score_thr=0.05, - nms_thr=0.45, - max_num=50, - score_factors=None): - """NMS for batched multi-class bboxes using npu api. - - Origin implement from mmdetection is - https://github.com/open-mmlab/mmdetection/blob/master/mmdet/core/post_processing/bbox_nms.py#L7 - - This interface is similar to the original interface, but not exactly the same. - This interface implements the nms method under batch. - - Args: - multi_bboxes (Tensor): shape (bs, n, #class, 4) or (bs, n, 4) - multi_scores (Tensor): shape (bs, n, #class+1), where the last column - contains scores of the background class, but this will be ignored. - On npu, in order to keep the semantics unblocked, we will unify the dimensions - score_thr (float): bbox threshold, bboxes with scores lower than it - will not be considered. - nms_thr (float): NMS IoU threshold. In the original implementation, a dictionary of {"iou_threshold": 0.45} - was passed, which is simplified here. - max_num (int): if there are more than max_num bboxes after NMS, - only top max_num will be kept; if there are less than max_num bboxes after NMS, - the output will zero pad to max_num. On the NPU, the memory needs to be requested in advance, - so the current max_num cannot be set to -1 at present - score_factors (Tensor): The factors multiplied to scores before applying NMS - - Returns: - tuple: (bboxes, labels), tensors of shape (bs, k, 5) and (bs, k, 1). Labels are 0-based. - """ - - num_classes = multi_scores.size(2) - 1 - num_boxes = multi_scores.size(1) - batch_size = multi_scores.size(0) - if score_factors is not None: - multi_scores = multi_scores[..., :-1] * score_factors[..., None] - else: - multi_scores = multi_scores[..., :-1] - multi_bboxes = multi_bboxes.reshape(batch_size, num_boxes, multi_bboxes.numel() // 4 // num_boxes // batch_size, 4) - multi_scores = multi_scores.reshape(batch_size, num_boxes, num_classes) - - nmsed_boxes, nmsed_scores, nmsed_classes, nmsed_num = torch.npu_batch_nms(multi_bboxes.half(), multi_scores.half(), - score_thr, nms_thr, - max_num, max_num) - - return torch.cat([nmsed_boxes, nmsed_scores[..., None]], -1), nmsed_classes - - -if __name__ == '__main__': - print('test npu_multiclass_nms') - boxes = torch.randint(1, 255, size=(1000, 4)) - scores = torch.randn(1000, 81) - - torch.npu.set_device(0) - boxes = boxes.npu().half() - scores = scores.npu().half() - - det_bboxes, det_labels = npu_multiclass_nms(boxes, scores) - print(det_bboxes.shape) - print(det_labels.shape) - - - print('test npu_batched_multiclass_nms') - boxes = torch.randint(1, 255, size=(4, 200, 80, 4)) - scores = torch.randn(4, 200, 81) - - torch.npu.set_device(0) - boxes = boxes.npu().half() - scores = scores.npu().half() - - det_bboxes, det_labels = npu_batched_multiclass_nms(boxes, scores) - print(det_bboxes.shape) - print(det_labels.shape) - +# Copyright (c) 2020, Huawei Technologies.All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 torch + + +def npu_multiclass_nms(multi_bboxes, + multi_scores, + score_thr=0.05, + nms_thr=0.45, + max_num=50, + score_factors=None): + """NMS for multi-class bboxes using npu api. + + Origin implement from mmdetection is + https://github.com/open-mmlab/mmdetection/blob/master/mmdet/core/post_processing/bbox_nms.py#L7 + + This interface is similar to the original interface, but not exactly the same. + + Args: + multi_bboxes (Tensor): shape (n, #class, 4) or (n, 4) + multi_scores (Tensor): shape (n, #class+1), where the last column + contains scores of the background class, but this will be ignored. + On npu, in order to keep the semantics unblocked, we will unify the dimensions + score_thr (float): bbox threshold, bboxes with scores lower than it + will not be considered. + nms_thr (float): NMS IoU threshold. In the original implementation, a dictionary of {"iou_threshold": 0.45} + was passed, which is simplified here. + max_num (int): if there are more than max_num bboxes after NMS, + only top max_num will be kept; if there are less than max_num bboxes after NMS, + the output will zero pad to max_num. On the NPU, the memory needs to be requested in advance, + so the current max_num cannot be set to -1 at present + score_factors (Tensor): The factors multiplied to scores before applying NMS + + Returns: + tuple: (bboxes, labels), tensors of shape (k, 5) and (k, 1). Labels are 0-based. + """ + + num_classes = multi_scores.size(1) - 1 + num_boxes = multi_scores.size(0) + if score_factors is not None: + multi_scores = multi_scores[:, :-1] * score_factors[:, None] + else: + multi_scores = multi_scores[:, :-1] + multi_bboxes = multi_bboxes.reshape(1, num_boxes, multi_bboxes.numel() // 4 // num_boxes, 4) + multi_scores = multi_scores.reshape(1, num_boxes, num_classes) + + nmsed_boxes, nmsed_scores, nmsed_classes, nmsed_num = torch.npu_batch_nms(multi_bboxes.half(), multi_scores.half(), + score_thr, nms_thr, + max_num, max_num) + + nmsed_boxes = nmsed_boxes.reshape(nmsed_boxes.shape[1:]) + nmsed_scores = nmsed_scores.reshape(nmsed_scores.shape[1]) + nmsed_classes = nmsed_classes.reshape(nmsed_classes.shape[1]) + + return torch.cat([nmsed_boxes, nmsed_scores[:, None]], -1), nmsed_classes + + +def npu_batched_multiclass_nms( + multi_bboxes, + multi_scores, + score_thr=0.05, + nms_thr=0.45, + max_num=50, + score_factors=None): + """NMS for batched multi-class bboxes using npu api. + + Origin implement from mmdetection is + https://github.com/open-mmlab/mmdetection/blob/master/mmdet/core/post_processing/bbox_nms.py#L7 + + This interface is similar to the original interface, but not exactly the same. + This interface implements the nms method under batch. + + Args: + multi_bboxes (Tensor): shape (bs, n, #class, 4) or (bs, n, 4) + multi_scores (Tensor): shape (bs, n, #class+1), where the last column + contains scores of the background class, but this will be ignored. + On npu, in order to keep the semantics unblocked, we will unify the dimensions + score_thr (float): bbox threshold, bboxes with scores lower than it + will not be considered. + nms_thr (float): NMS IoU threshold. In the original implementation, a dictionary of {"iou_threshold": 0.45} + was passed, which is simplified here. + max_num (int): if there are more than max_num bboxes after NMS, + only top max_num will be kept; if there are less than max_num bboxes after NMS, + the output will zero pad to max_num. On the NPU, the memory needs to be requested in advance, + so the current max_num cannot be set to -1 at present + score_factors (Tensor): The factors multiplied to scores before applying NMS + + Returns: + tuple: (bboxes, labels), tensors of shape (bs, k, 5) and (bs, k, 1). Labels are 0-based. + """ + + num_classes = multi_scores.size(2) - 1 + num_boxes = multi_scores.size(1) + batch_size = multi_scores.size(0) + if score_factors is not None: + multi_scores = multi_scores[..., :-1] * score_factors[..., None] + else: + multi_scores = multi_scores[..., :-1] + multi_bboxes = multi_bboxes.reshape(batch_size, num_boxes, multi_bboxes.numel() // 4 // num_boxes // batch_size, 4) + multi_scores = multi_scores.reshape(batch_size, num_boxes, num_classes) + + nmsed_boxes, nmsed_scores, nmsed_classes, nmsed_num = torch.npu_batch_nms(multi_bboxes.half(), multi_scores.half(), + score_thr, nms_thr, + max_num, max_num) + + return torch.cat([nmsed_boxes, nmsed_scores[..., None]], -1), nmsed_classes + + +if __name__ == '__main__': + print('test npu_multiclass_nms') + boxes = torch.randint(1, 255, size=(1000, 4)) + scores = torch.randn(1000, 81) + + torch.npu.set_device(0) + boxes = boxes.npu().half() + scores = scores.npu().half() + + det_bboxes, det_labels = npu_multiclass_nms(boxes, scores) + print(det_bboxes.shape) + print(det_labels.shape) + + + print('test npu_batched_multiclass_nms') + boxes = torch.randint(1, 255, size=(4, 200, 80, 4)) + scores = torch.randn(4, 200, 81) + + torch.npu.set_device(0) + boxes = boxes.npu().half() + scores = scores.npu().half() + + det_bboxes, det_labels = npu_batched_multiclass_nms(boxes, scores) + print(det_bboxes.shape) + print(det_labels.shape) + diff --git a/PyTorch/contrib/cv/detection/SSD/scripts/eval.sh b/PyTorch/contrib/cv/detection/SSD/scripts/eval.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD/scripts/eval_1p.sh b/PyTorch/contrib/cv/detection/SSD/scripts/eval_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD/scripts/npu_set_env.sh b/PyTorch/contrib/cv/detection/SSD/scripts/npu_set_env.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD/scripts/train_1p.sh b/PyTorch/contrib/cv/detection/SSD/scripts/train_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD/scripts/train_8p.sh b/PyTorch/contrib/cv/detection/SSD/scripts/train_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD/setup.py b/PyTorch/contrib/cv/detection/SSD/setup.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD/tools/dist_test.sh b/PyTorch/contrib/cv/detection/SSD/tools/dist_test.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD/tools/dist_train.sh b/PyTorch/contrib/cv/detection/SSD/tools/dist_train.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD/tools/slurm_test.sh b/PyTorch/contrib/cv/detection/SSD/tools/slurm_test.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SSD/tools/slurm_train.sh b/PyTorch/contrib/cv/detection/SSD/tools/slurm_train.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/README_raw.md b/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/README_raw.md index e04900eef2..51554173ec 100644 --- a/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/README_raw.md +++ b/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/README_raw.md @@ -1,52 +1,52 @@ -# SimCLR_for_Pytorch - -This project enables the SimCLR model could be trained on NPU, and remains the similar precision compared to the results -of the GPU. - - -## Requirements - -- NPU配套的run包安装(建议安装 20.2.0.rc1 版本,请用以下脚本确认版本号,不确保其他版本能正常训练/测评) - - ```sh - ll /usr/local/Ascend/ascend-toolkit/latest - ``` - -- Python v3.7.5 -- PyTorch v1.5 (NPU版本) -- Apex (NPU版本) - - -## Training - -To train a model, run `xxx.sh` with the desired model architecture and the path to the CIFAR10 dataset: - -```bash -# training 1p accuracy -bash ./test/train_full_1p.sh --data_path=real_data_path - -# training 1p performance -bash ./test/train_performance_1p.sh --data_path=real_data_path - -# training 8p accuracy -bash ./test/train_full_8p.sh --data_path=real_data_path - -# training 8p performance -bash ./test/train_performance_8p.sh --data_path=real_data_path - -# finetuning 1p -bash test/train_finetune_1p.sh --data_path=real_data_path --pth_path=real_pre_train_model_path -``` - -Log path: - test/output/devie_id/train_${device_id}.log # training detail log - - -## SimCLR Training Results - -| Acc@1 | FPS | # of NPU/GPU | Epochs | Opt-Level | Loss Scale | -| :------: | :------: | :------: | :------: | :------: | :------: | -| ------ | 1767.030 | 1P GPU | 100 | O2 | 128.0 | -| 60.352 | 2098.001 | 1P NPU | 100 | O2 | 128.0 | -| 55.859 | 5227.504 | 8P GPU | 100 | O2 | 128.0 | -| 58.594 | 9747.414 | 8P NPU | 100 | O2 | 128.0 | +# SimCLR_for_Pytorch + +This project enables the SimCLR model could be trained on NPU, and remains the similar precision compared to the results +of the GPU. + + +## Requirements + +- NPU配套的run包安装(建议安装 20.2.0.rc1 版本,请用以下脚本确认版本号,不确保其他版本能正常训练/测评) + + ```sh + ll /usr/local/Ascend/ascend-toolkit/latest + ``` + +- Python v3.7.5 +- PyTorch v1.5 (NPU版本) +- Apex (NPU版本) + + +## Training + +To train a model, run `xxx.sh` with the desired model architecture and the path to the CIFAR10 dataset: + +```bash +# training 1p accuracy +bash ./test/train_full_1p.sh --data_path=real_data_path + +# training 1p performance +bash ./test/train_performance_1p.sh --data_path=real_data_path + +# training 8p accuracy +bash ./test/train_full_8p.sh --data_path=real_data_path + +# training 8p performance +bash ./test/train_performance_8p.sh --data_path=real_data_path + +# finetuning 1p +bash test/train_finetune_1p.sh --data_path=real_data_path --pth_path=real_pre_train_model_path +``` + +Log path: + test/output/devie_id/train_${device_id}.log # training detail log + + +## SimCLR Training Results + +| Acc@1 | FPS | # of NPU/GPU | Epochs | Opt-Level | Loss Scale | +| :------: | :------: | :------: | :------: | :------: | :------: | +| ------ | 1767.030 | 1P GPU | 100 | O2 | 128.0 | +| 60.352 | 2098.001 | 1P NPU | 100 | O2 | 128.0 | +| 55.859 | 5227.504 | 8P GPU | 100 | O2 | 128.0 | +| 58.594 | 9747.414 | 8P NPU | 100 | O2 | 128.0 | diff --git a/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/main_1p.py b/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/main_1p.py index 1152709ee9..4f1a016a0c 100644 --- a/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/main_1p.py +++ b/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/main_1p.py @@ -1,270 +1,270 @@ -"""MIT License""" -# Copyright (c) 2020 Thalles Silva -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ============================================================================ -import time -import argparse -import torch -import torch.npu -import torch.nn.functional as F -import torch.utils.data -import torch.backends.cudnn as cudnn -from torchvision import models -from utils import accuracy -from models.resnet_simclr import ResNetSimCLR - -from apex import amp -from data_aug.contrastive_learning_dataset import ContrastiveLearningDataset -from multi_epochs_dataloader import MultiEpochsDataLoader -import apex -from apex.optimizers import NpuFusedAdam - - -torch.manual_seed(0) - -model_names = sorted(name for name in models.__dict__ - if name.islower() and not name.startswith("__") - and callable(models.__dict__[name])) - -parser = argparse.ArgumentParser(description='PyTorch SimCLR') -parser.add_argument('data', metavar='DIR', - help='path to dataset') -parser.add_argument('--dataset_name', default='cifar10', - help='dataset name', choices=['stl10', 'cifar10']) -parser.add_argument('-a', '--arch', metavar='ARCH', default='resnet18', - choices=model_names, - help='model architecture: ' + - ' | '.join(model_names) + - ' (default: resnet50)') -parser.add_argument('-j', '--workers', default=9, type=int, metavar='N', - help='number of data loading workers (default: 9)') -parser.add_argument('--epochs', default=100, type=int, metavar='N', - help='number of total epochs to run') -parser.add_argument('-b', '--batch_size', default=256, type=int, - metavar='N', - help='mini-batch size (default: 256), this is the total ' - 'batch size of all GPUs on the current node when ' - 'using Data Parallel or Distributed Data Parallel') -parser.add_argument('--lr', '--learning_rate', default=0.0003, type=float, - metavar='LR', help='initial learning rate', dest='lr') -parser.add_argument('--wd', '--weight_decay', default=1e-4, type=float, - metavar='W', help='weight decay (default: 1e-4)', - dest='weight_decay') -parser.add_argument('--out_dim', default=128, type=int, - help='feature dimension (default: 128)') -parser.add_argument('--log_every_n_steps', default=10, type=int, - help='Log every n steps') -parser.add_argument('--temperature', default=0.07, type=float, - help='softmax temperature (default: 0.07)') -parser.add_argument('--n_views', default=2, type=int, metavar='N', - help='Number of views for contrastive learning training.') -parser.add_argument('--rank', default=0, type=int, - help='node rank for distributed training') -parser.add_argument('--npu', default=0, type=int, - help='NPU id to use.') -parser.add_argument('--npus_per_node', default=1, type=int, - help='number of NPUs per node.') -parser.add_argument('--pretrained', dest='pretrained', action='store_true', - help='use pre-trained model') -parser.add_argument('--pth_path', default='', type=str, metavar='PATH', - help='path to pretrained checkpoint (default: none)') -parser.add_argument('--device_id', type=int, default=0, help="device id") - - -def main(): - print('Part1 : prepare for parameters <==> Begin') - args = parser.parse_args() - main_worker(args.npu, args.npus_per_node, args) - - -def info_nce_loss(args, features): - - labels = torch.cat([torch.arange(args.batch_size) for i in range(args.n_views)], dim=0).npu() - labels = (labels.unsqueeze(0) == labels.unsqueeze(1)).float() - labels = labels.npu() - - features = F.normalize(features, dim=1).npu() - - similarity_matrix = torch.matmul(features, features.T).npu() - - # discard the main diagonal from both: labels and similarities matrix - mask = torch.eye(labels.shape[0], dtype=torch.bool).npu() - labels = labels[~mask].view(labels.shape[0], -1).npu() - similarity_matrix = similarity_matrix[~mask].view(similarity_matrix.shape[0], -1).npu() - - # select and combine multiple positives - positives = similarity_matrix[labels.bool()].view(labels.shape[0], -1).npu() - - # select only the negatives the negatives - negatives = similarity_matrix[~labels.bool()].view(similarity_matrix.shape[0], -1).npu() - - logits = torch.cat([positives, negatives], dim=1).npu() - labels = torch.zeros(logits.shape[0], dtype=torch.long).npu() - - logits = logits / args.temperature - return logits, labels - - -def train(args, train_loader, model, criterion, optimizer, epoch_counter, npus_per_node, best_acc): - fps = AverageMeter() - - top1 = [0] - top5 = [0] - end = time.time() - for i, (images, _) in enumerate(train_loader): - images = torch.cat(images, dim=0) - images = images.npu() - - out = model(images).npu() - logits, labels = info_nce_loss(args, out) - loss = criterion(logits, labels) - optimizer.zero_grad() - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - optimizer.step() - - time_step = time.time() - end - fps.update(args.batch_size / time_step) - end = time.time() - - if i % args.log_every_n_steps == 0 and args.rank % npus_per_node == 0: - top1, top5 = accuracy(logits, labels, topk=(1, 5)) - if top1[0] > best_acc: - best_acc = top1[0] - print('Train Epoch: {0} Step: {1}/{2} Loss {loss:.4f} ' - '[AVG-ACC] * Acc@1 {top1:.3f} Acc@5 {top5:.3f} best_acc {best_acc:.3f} ' - 'LR {lr:.7f} FPS {fps:.7f}'.format( - epoch_counter, i, len(train_loader), loss=loss.item(), - top1=top1[0], top5=top5[0], best_acc=best_acc, - lr=optimizer.param_groups[0]['lr'], fps=fps.avg)) - - if (epoch_counter+1) % 5 == 0: - save_checkpoint({ - 'epoch': epoch_counter, - 'arch': model.state_dict(), - 'state_dict': model.state_dict(), - 'optimizer': optimizer.state_dict(), - }) - - -def save_checkpoint(state, filename='checkpoint.pth.tar'): - torch.save(state, filename) - - -def main_worker(npu, npus_per_node, args): - local_rank = 0 - args.npu = npu - assert args.n_views == 2, "Only two view training is supported. Please use --n-views 2." - args.rank = args.rank * npus_per_node + npu - print(args) - args.device_id = args.device_id + local_rank - print("device_id = ", args.device_id) - device = torch.device(f'npu:{args.device_id}') - torch.npu.set_device(device) - - # create model - if args.pretrained: - print("=> using pre-trained model ResNetSimCLR") - model = ResNetSimCLR(base_model=args.arch, out_dim=args.out_dim) - print("loading model of yours...") - if args.pth_path: - print("load pth you give") - pretrained_dict = torch.load(args.pth_path, map_location="cpu")["state_dict"] - else: - pretrained_dict = torch.load("./checkpoint.pth.tar", map_location="cpu")["state_dict"] - model.load_state_dict(pretrained_dict, strict=False) - else: - print("=> creating model ResNetSimCLR") - model = ResNetSimCLR(base_model=args.arch, out_dim=args.out_dim) - - print('Part1 : prepare for parameters <==> Done') - print('Part2 : Load Network <==> Begin') - - cudnn.deterministic = True - cudnn.benchmark = True - model = model.to(device) - - optimizer = NpuFusedAdam( - model.parameters(), - args.lr, - weight_decay=args.weight_decay - ) - - model, optimizer = amp.initialize(model, optimizer, opt_level="O2", loss_scale=128.0, combine_grad=True) - criterion = torch.nn.CrossEntropyLoss().to(device) - - print('Part2 : Load Network <==> Done') - print('Part3 : Load Dataset <==> Begin') - - dataset = ContrastiveLearningDataset(args.data) - train_dataset = dataset.get_dataset(args.dataset_name, args.n_views) - print(f'workers nums:{args.workers}') - print(f'device nums:{npus_per_node}') - - train_loader, train_loader_len, train_sampler = get_pytorch_train_loader(train_dataset, - args.batch_size, - workers=args.workers) - scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=len(train_loader), eta_min=0, - last_epoch=-1) - if args.rank % npus_per_node == 0: - print('Part3 : Load Dataset <==> Done') - print('Part4 : Train and Test <==> Begin') - - for epoch_counter in range(args.epochs): - best_acc = 0 - train(args, train_loader, model, criterion, optimizer, epoch_counter, npus_per_node, best_acc) - if epoch_counter >= 10: - scheduler.step() - print('Part4 : Train and Test <==> Done') - - -def get_pytorch_train_loader(train_dataset, batch_size, workers, _worker_init_fn=None): - train_sampler = None - - dataloader_fn = MultiEpochsDataLoader # torch.utils.data.DataLoader - train_loader = dataloader_fn( - train_dataset, batch_size=batch_size, shuffle=(train_sampler is None), - num_workers=workers, worker_init_fn=_worker_init_fn, pin_memory=True, sampler=train_sampler, - drop_last=True) - return train_loader, len(train_loader), train_sampler - - -class AverageMeter(object): - """Computes and stores the average and current value""" - - def __init__(self): - self.reset() - - def reset(self): - self.val = 0 - self.avg = 0 - self.sum = 0 - self.count = 0 - - def update(self, val, n=1): - self.val = val - self.sum += val * n - self.count += n - self.avg = self.sum / self.count - - -if __name__ == '__main__': - main() +"""MIT License""" +# Copyright (c) 2020 Thalles Silva +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ============================================================================ +import time +import argparse +import torch +import torch.npu +import torch.nn.functional as F +import torch.utils.data +import torch.backends.cudnn as cudnn +from torchvision import models +from utils import accuracy +from models.resnet_simclr import ResNetSimCLR + +from apex import amp +from data_aug.contrastive_learning_dataset import ContrastiveLearningDataset +from multi_epochs_dataloader import MultiEpochsDataLoader +import apex +from apex.optimizers import NpuFusedAdam + + +torch.manual_seed(0) + +model_names = sorted(name for name in models.__dict__ + if name.islower() and not name.startswith("__") + and callable(models.__dict__[name])) + +parser = argparse.ArgumentParser(description='PyTorch SimCLR') +parser.add_argument('data', metavar='DIR', + help='path to dataset') +parser.add_argument('--dataset_name', default='cifar10', + help='dataset name', choices=['stl10', 'cifar10']) +parser.add_argument('-a', '--arch', metavar='ARCH', default='resnet18', + choices=model_names, + help='model architecture: ' + + ' | '.join(model_names) + + ' (default: resnet50)') +parser.add_argument('-j', '--workers', default=9, type=int, metavar='N', + help='number of data loading workers (default: 9)') +parser.add_argument('--epochs', default=100, type=int, metavar='N', + help='number of total epochs to run') +parser.add_argument('-b', '--batch_size', default=256, type=int, + metavar='N', + help='mini-batch size (default: 256), this is the total ' + 'batch size of all GPUs on the current node when ' + 'using Data Parallel or Distributed Data Parallel') +parser.add_argument('--lr', '--learning_rate', default=0.0003, type=float, + metavar='LR', help='initial learning rate', dest='lr') +parser.add_argument('--wd', '--weight_decay', default=1e-4, type=float, + metavar='W', help='weight decay (default: 1e-4)', + dest='weight_decay') +parser.add_argument('--out_dim', default=128, type=int, + help='feature dimension (default: 128)') +parser.add_argument('--log_every_n_steps', default=10, type=int, + help='Log every n steps') +parser.add_argument('--temperature', default=0.07, type=float, + help='softmax temperature (default: 0.07)') +parser.add_argument('--n_views', default=2, type=int, metavar='N', + help='Number of views for contrastive learning training.') +parser.add_argument('--rank', default=0, type=int, + help='node rank for distributed training') +parser.add_argument('--npu', default=0, type=int, + help='NPU id to use.') +parser.add_argument('--npus_per_node', default=1, type=int, + help='number of NPUs per node.') +parser.add_argument('--pretrained', dest='pretrained', action='store_true', + help='use pre-trained model') +parser.add_argument('--pth_path', default='', type=str, metavar='PATH', + help='path to pretrained checkpoint (default: none)') +parser.add_argument('--device_id', type=int, default=0, help="device id") + + +def main(): + print('Part1 : prepare for parameters <==> Begin') + args = parser.parse_args() + main_worker(args.npu, args.npus_per_node, args) + + +def info_nce_loss(args, features): + + labels = torch.cat([torch.arange(args.batch_size) for i in range(args.n_views)], dim=0).npu() + labels = (labels.unsqueeze(0) == labels.unsqueeze(1)).float() + labels = labels.npu() + + features = F.normalize(features, dim=1).npu() + + similarity_matrix = torch.matmul(features, features.T).npu() + + # discard the main diagonal from both: labels and similarities matrix + mask = torch.eye(labels.shape[0], dtype=torch.bool).npu() + labels = labels[~mask].view(labels.shape[0], -1).npu() + similarity_matrix = similarity_matrix[~mask].view(similarity_matrix.shape[0], -1).npu() + + # select and combine multiple positives + positives = similarity_matrix[labels.bool()].view(labels.shape[0], -1).npu() + + # select only the negatives the negatives + negatives = similarity_matrix[~labels.bool()].view(similarity_matrix.shape[0], -1).npu() + + logits = torch.cat([positives, negatives], dim=1).npu() + labels = torch.zeros(logits.shape[0], dtype=torch.long).npu() + + logits = logits / args.temperature + return logits, labels + + +def train(args, train_loader, model, criterion, optimizer, epoch_counter, npus_per_node, best_acc): + fps = AverageMeter() + + top1 = [0] + top5 = [0] + end = time.time() + for i, (images, _) in enumerate(train_loader): + images = torch.cat(images, dim=0) + images = images.npu() + + out = model(images).npu() + logits, labels = info_nce_loss(args, out) + loss = criterion(logits, labels) + optimizer.zero_grad() + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + optimizer.step() + + time_step = time.time() - end + fps.update(args.batch_size / time_step) + end = time.time() + + if i % args.log_every_n_steps == 0 and args.rank % npus_per_node == 0: + top1, top5 = accuracy(logits, labels, topk=(1, 5)) + if top1[0] > best_acc: + best_acc = top1[0] + print('Train Epoch: {0} Step: {1}/{2} Loss {loss:.4f} ' + '[AVG-ACC] * Acc@1 {top1:.3f} Acc@5 {top5:.3f} best_acc {best_acc:.3f} ' + 'LR {lr:.7f} FPS {fps:.7f}'.format( + epoch_counter, i, len(train_loader), loss=loss.item(), + top1=top1[0], top5=top5[0], best_acc=best_acc, + lr=optimizer.param_groups[0]['lr'], fps=fps.avg)) + + if (epoch_counter+1) % 5 == 0: + save_checkpoint({ + 'epoch': epoch_counter, + 'arch': model.state_dict(), + 'state_dict': model.state_dict(), + 'optimizer': optimizer.state_dict(), + }) + + +def save_checkpoint(state, filename='checkpoint.pth.tar'): + torch.save(state, filename) + + +def main_worker(npu, npus_per_node, args): + local_rank = 0 + args.npu = npu + assert args.n_views == 2, "Only two view training is supported. Please use --n-views 2." + args.rank = args.rank * npus_per_node + npu + print(args) + args.device_id = args.device_id + local_rank + print("device_id = ", args.device_id) + device = torch.device(f'npu:{args.device_id}') + torch.npu.set_device(device) + + # create model + if args.pretrained: + print("=> using pre-trained model ResNetSimCLR") + model = ResNetSimCLR(base_model=args.arch, out_dim=args.out_dim) + print("loading model of yours...") + if args.pth_path: + print("load pth you give") + pretrained_dict = torch.load(args.pth_path, map_location="cpu")["state_dict"] + else: + pretrained_dict = torch.load("./checkpoint.pth.tar", map_location="cpu")["state_dict"] + model.load_state_dict(pretrained_dict, strict=False) + else: + print("=> creating model ResNetSimCLR") + model = ResNetSimCLR(base_model=args.arch, out_dim=args.out_dim) + + print('Part1 : prepare for parameters <==> Done') + print('Part2 : Load Network <==> Begin') + + cudnn.deterministic = True + cudnn.benchmark = True + model = model.to(device) + + optimizer = NpuFusedAdam( + model.parameters(), + args.lr, + weight_decay=args.weight_decay + ) + + model, optimizer = amp.initialize(model, optimizer, opt_level="O2", loss_scale=128.0, combine_grad=True) + criterion = torch.nn.CrossEntropyLoss().to(device) + + print('Part2 : Load Network <==> Done') + print('Part3 : Load Dataset <==> Begin') + + dataset = ContrastiveLearningDataset(args.data) + train_dataset = dataset.get_dataset(args.dataset_name, args.n_views) + print(f'workers nums:{args.workers}') + print(f'device nums:{npus_per_node}') + + train_loader, train_loader_len, train_sampler = get_pytorch_train_loader(train_dataset, + args.batch_size, + workers=args.workers) + scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=len(train_loader), eta_min=0, + last_epoch=-1) + if args.rank % npus_per_node == 0: + print('Part3 : Load Dataset <==> Done') + print('Part4 : Train and Test <==> Begin') + + for epoch_counter in range(args.epochs): + best_acc = 0 + train(args, train_loader, model, criterion, optimizer, epoch_counter, npus_per_node, best_acc) + if epoch_counter >= 10: + scheduler.step() + print('Part4 : Train and Test <==> Done') + + +def get_pytorch_train_loader(train_dataset, batch_size, workers, _worker_init_fn=None): + train_sampler = None + + dataloader_fn = MultiEpochsDataLoader # torch.utils.data.DataLoader + train_loader = dataloader_fn( + train_dataset, batch_size=batch_size, shuffle=(train_sampler is None), + num_workers=workers, worker_init_fn=_worker_init_fn, pin_memory=True, sampler=train_sampler, + drop_last=True) + return train_loader, len(train_loader), train_sampler + + +class AverageMeter(object): + """Computes and stores the average and current value""" + + def __init__(self): + self.reset() + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + + def update(self, val, n=1): + self.val = val + self.sum += val * n + self.count += n + self.avg = self.sum / self.count + + +if __name__ == '__main__': + main() diff --git a/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/main_8p.py b/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/main_8p.py index 3f93c0d9ef..81952e8a49 100644 --- a/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/main_8p.py +++ b/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/main_8p.py @@ -1,330 +1,330 @@ -"""MIT License""" -# Copyright (c) 2020 Thalles Silva -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ============================================================================ -import os -import time -import argparse -import torch -import torch.npu -import torch.nn.functional as F -import torch.multiprocessing as mp -import torch.backends.cudnn as cudnn -from torchvision import models -from utils import accuracy -from models.resnet_simclr import ResNetSimCLR - -from apex import amp -from data_aug.contrastive_learning_dataset import ContrastiveLearningDataset -from multi_epochs_dataloader import MultiEpochsDataLoader -import apex -from apex.optimizers import NpuFusedAdam -import socket - -torch.manual_seed(0) - -model_names = sorted(name for name in models.__dict__ - if name.islower() and not name.startswith("__") - and callable(models.__dict__[name])) - -parser = argparse.ArgumentParser(description='PyTorch SimCLR') -parser.add_argument('data', metavar='DIR', - help='path to dataset') -parser.add_argument('--dataset_name', default='cifar10', - help='dataset name', choices=['stl10', 'cifar10']) -parser.add_argument('-a', '--arch', metavar='ARCH', default='resnet18', - choices=model_names, - help='model architecture: ' + - ' | '.join(model_names) + - ' (default: resnet50)') -parser.add_argument('-j', '--workers', default=9, type=int, metavar='N', - help='number of data loading workers (default: 9)') -parser.add_argument('--epochs', default=100, type=int, metavar='N', - help='number of total epochs to run') -parser.add_argument('-b', '--batch_size', default=256, type=int, - metavar='N', - help='mini-batch size (default: 256), this is the total ' - 'batch size of all GPUs on the current node when ' - 'using Data Parallel or Distributed Data Parallel') -parser.add_argument('--lr', '--learning_rate', default=0.0012, type=float, - metavar='LR', help='initial learning rate', dest='lr') -parser.add_argument('--wd', '--weight_decay', default=1e-4, type=float, - metavar='W', help='weight decay (default: 1e-4)', - dest='weight_decay') -parser.add_argument('--out_dim', default=128, type=int, - help='feature dimension (default: 128)') -parser.add_argument('--log_every_n_steps', default=10, type=int, - help='Log every n steps') -parser.add_argument('--temperature', default=0.07, type=float, - help='softmax temperature (default: 0.07)') -parser.add_argument('--n_views', default=2, type=int, metavar='N', - help='Number of views for contrastive learning training.') -parser.add_argument('--rank', default=0, type=int, - help='node rank for distributed training') -parser.add_argument('--npu', default=0, type=int, - help='NPU id to use.') -parser.add_argument('--pretrained', dest='pretrained', action='store_true', - help='use pre-trained model') -parser.add_argument('--pth_path', default='', type=str, metavar='PATH', - help='path to pretrained checkpoint (default: none)') -parser.add_argument('--distributed', action='store_true', - help='Use multi-processing distributed training to launch ' - 'N processes per node, which has N GPUs.') -parser.add_argument('--nodes', type=int, default=1) -parser.add_argument('--device_id', type=int, default=0, help="device id") -parser.add_argument('--device_list', type=str, default="0,1,2,3,4,5,6,7", help="device id list") - - -def get_host_ip(): - """ - 查询本机ip地址 - :return: ip - """ - try: - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - s.connect(('8.8.8.8', 80)) - ip = s.getsockname()[0] - finally: - s.close() - - return ip - - -def device_id_to_process_device_map(device_list): - devices = device_list.split(",") - devices = [int(x) for x in devices] - devices.sort() - - process_device_map = dict() - for process_id, device_id in enumerate(devices): - process_device_map[process_id] = device_id - - return process_device_map - - -def main(): - print('Part1 : prepare for parameters <==> Begin') - args = parser.parse_args() - os.environ["MASTER_ADDR"] = get_host_ip() - os.environ["MASTER_PORT"] = "29688" - args.process_device_map = device_id_to_process_device_map(args.device_list) - if args.device_list != '': - npus_per_node = len(args.device_list.split(',')) - elif args.device_num != -1: - npus_per_node = args.device_num - elif args.device == 'npu': - npus_per_node = torch.npu.device_count() - else: - npus_per_node = torch.cuda.device_count() - - print('npus_per_node:', npus_per_node) - - if args.distributed: - mp.spawn(main_worker, nprocs=npus_per_node, args=(npus_per_node, args)) - else: - # Simply call main_worker function - main_worker(args.npu, npus_per_node, args) - - -def main_worker(npu, npus_per_node, args): - local_rank = 0 - args.npu = args.process_device_map[npu] - if args.distributed: - args.rank = args.rank * npus_per_node + npu - torch.distributed.init_process_group(backend="hccl", - world_size=args.nodes * npus_per_node, - rank=args.rank) - local_rank = torch.distributed.get_rank() - args.is_master_node = not args.distributed or local_rank == 0 - if args.is_master_node: - print(args) - args.device_id = args.device_id + local_rank - print("device_id = ", args.device_id) - device = torch.device(f'npu:{args.device_id}') - torch.npu.set_device(device) - - # create model - if args.pretrained: - print("=> using pre-trained model ResNetSimCLR") - model = ResNetSimCLR(base_model=args.arch, out_dim=args.out_dim) - print("loading model of yours...") - if args.pth_path: - print("load pth you give") - pretrained_dict = torch.load(args.pth_path, map_location="cpu")["state_dict"] - else: - pretrained_dict = torch.load("./checkpoint.pth.tar", map_location="cpu")["state_dict"] - model.load_state_dict(pretrained_dict, strict=False) - else: - print("=> creating model ResNetSimCLR") - model = ResNetSimCLR(base_model=args.arch, out_dim=args.out_dim) - - print('rank', args.rank, ' using npu...') - if args.rank % npus_per_node == 0: - print('Part1 : prepare for parameters <==> Done') - print('Part2 : Load Network <==> Begin') - - cudnn.deterministic = True - cudnn.benchmark = True - model = model.to(device) - optimizer = NpuFusedAdam( - model.parameters(), - args.lr, - weight_decay=args.weight_decay - ) - model, optimizer = amp.initialize(model, optimizer, opt_level="O2", loss_scale=128.0, combine_grad=True) - if args.distributed: - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[local_rank], - broadcast_buffers=False) - criterion = torch.nn.CrossEntropyLoss().to(device) - - if args.rank % npus_per_node == 0: - print('Part2 : Load Network <==> Done') - print('Part3 : Load Dataset <==> Begin') - - dataset = ContrastiveLearningDataset(args.data) - train_dataset = dataset.get_dataset(args.dataset_name, args.n_views) - print(f'workers nums:{args.workers}') - print(f'device nums:{npus_per_node}') - - train_loader, train_loader_len, train_sampler = get_pytorch_train_loader(train_dataset, - args.batch_size, - workers=args.workers) - scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=len(train_loader), eta_min=0, - last_epoch=-1) - if args.rank % npus_per_node == 0: - print('Part3 : Load Dataset <==> Done') - print('Part4 : Train and Test <==> Begin') - - for epoch_counter in range(args.epochs): - if args.distributed: - train_sampler.set_epoch(epoch_counter) - best_acc = 0 - train(args, train_loader, model, criterion, optimizer, epoch_counter, npus_per_node, best_acc) - if epoch_counter >= 10: - scheduler.step() - print('Part4 : Train and Test <==> Done') - - -def info_nce_loss(args, features): - labels = torch.cat([torch.arange(args.batch_size) for i in range(args.n_views)], dim=0) - labels = (labels.unsqueeze(0) == labels.unsqueeze(1)).float() - labels = labels.npu() - features = F.normalize(features, dim=1) - similarity_matrix = torch.matmul(features, features.T) - - # discard the main diagonal from both: labels and similarities matrix - mask = torch.eye(labels.shape[0], dtype=torch.bool).npu() - labels = labels[~mask].view(labels.shape[0], -1) - similarity_matrix = similarity_matrix[~mask].view(similarity_matrix.shape[0], -1) - - # select and combine multiple positives - positives = similarity_matrix[labels.bool()].view(labels.shape[0], -1) - - # select only the negatives the negatives - negatives = similarity_matrix[~labels.bool()].view(similarity_matrix.shape[0], -1) - - logits = torch.cat([positives, negatives], dim=1) - labels = torch.zeros(logits.shape[0], dtype=torch.long).npu() - logits = logits / args.temperature - return logits, labels - - -def train(args, train_loader, model, criterion, optimizer, epoch_counter, npus_per_node, best_acc): - fps = AverageMeter() - - top1 = [0] - top5 = [0] - - end = time.time() - for i, (images, _) in enumerate(train_loader): - images = torch.cat(images, dim=0) - images = images.npu() - - out = model(images) - logits, labels = info_nce_loss(args, out) - loss = criterion(logits, labels) - optimizer.zero_grad() - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - optimizer.step() - - time_step = time.time() - end - fps.update(args.batch_size * npus_per_node / time_step) - torch.npu.synchronize() - end = time.time() - - if i % args.log_every_n_steps == 0 and args.is_master_node: - top1, top5 = accuracy(logits, labels, topk=(1, 5)) - if top1[0] > best_acc: - best_acc = top1[0] - - print('Train Epoch: {0} Step: {1}/{2} Loss {loss:.4f} Time {time:.4f}' - '[AVG-ACC] * Acc@1 {top1:.3f} Acc@5 {top5:.3f} best_acc {best_acc:.3f} ' - 'LR {lr:.7f} FPS {fps:.7f} '.format( - epoch_counter, i, len(train_loader), loss=loss.item(), time=time_step, - top1=top1[0], top5=top5[0], best_acc=best_acc, - lr=optimizer.param_groups[0]['lr'], fps=fps.avg)) - - if (epoch_counter+1) % 5 == 0: - save_checkpoint({ - 'epoch': epoch_counter, - 'arch': model.state_dict(), - 'state_dict': model.state_dict(), - 'optimizer': optimizer.state_dict(), - }) - - -def save_checkpoint(state, filename='checkpoint.pth.tar'): - torch.save(state, filename) - - -def get_pytorch_train_loader(train_dataset, batch_size, workers, _worker_init_fn=None): - train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset) - - dataloader_fn = MultiEpochsDataLoader # torch.utils.data.DataLoader - train_loader = dataloader_fn( - train_dataset, batch_size=batch_size, shuffle=(train_sampler is None), - num_workers=workers, worker_init_fn=_worker_init_fn, pin_memory=False, sampler=train_sampler, - drop_last=True) - return train_loader, len(train_loader), train_sampler - - -class AverageMeter(object): - """Computes and stores the average and current value""" - - def __init__(self): - self.reset() - - def reset(self): - self.val = 0 - self.avg = 0 - self.sum = 0 - self.count = 0 - - def update(self, val, n=1): - self.val = val - self.sum += val * n - self.count += n - self.avg = self.sum / self.count - - -if __name__ == '__main__': - main() +"""MIT License""" +# Copyright (c) 2020 Thalles Silva +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ============================================================================ +import os +import time +import argparse +import torch +import torch.npu +import torch.nn.functional as F +import torch.multiprocessing as mp +import torch.backends.cudnn as cudnn +from torchvision import models +from utils import accuracy +from models.resnet_simclr import ResNetSimCLR + +from apex import amp +from data_aug.contrastive_learning_dataset import ContrastiveLearningDataset +from multi_epochs_dataloader import MultiEpochsDataLoader +import apex +from apex.optimizers import NpuFusedAdam +import socket + +torch.manual_seed(0) + +model_names = sorted(name for name in models.__dict__ + if name.islower() and not name.startswith("__") + and callable(models.__dict__[name])) + +parser = argparse.ArgumentParser(description='PyTorch SimCLR') +parser.add_argument('data', metavar='DIR', + help='path to dataset') +parser.add_argument('--dataset_name', default='cifar10', + help='dataset name', choices=['stl10', 'cifar10']) +parser.add_argument('-a', '--arch', metavar='ARCH', default='resnet18', + choices=model_names, + help='model architecture: ' + + ' | '.join(model_names) + + ' (default: resnet50)') +parser.add_argument('-j', '--workers', default=9, type=int, metavar='N', + help='number of data loading workers (default: 9)') +parser.add_argument('--epochs', default=100, type=int, metavar='N', + help='number of total epochs to run') +parser.add_argument('-b', '--batch_size', default=256, type=int, + metavar='N', + help='mini-batch size (default: 256), this is the total ' + 'batch size of all GPUs on the current node when ' + 'using Data Parallel or Distributed Data Parallel') +parser.add_argument('--lr', '--learning_rate', default=0.0012, type=float, + metavar='LR', help='initial learning rate', dest='lr') +parser.add_argument('--wd', '--weight_decay', default=1e-4, type=float, + metavar='W', help='weight decay (default: 1e-4)', + dest='weight_decay') +parser.add_argument('--out_dim', default=128, type=int, + help='feature dimension (default: 128)') +parser.add_argument('--log_every_n_steps', default=10, type=int, + help='Log every n steps') +parser.add_argument('--temperature', default=0.07, type=float, + help='softmax temperature (default: 0.07)') +parser.add_argument('--n_views', default=2, type=int, metavar='N', + help='Number of views for contrastive learning training.') +parser.add_argument('--rank', default=0, type=int, + help='node rank for distributed training') +parser.add_argument('--npu', default=0, type=int, + help='NPU id to use.') +parser.add_argument('--pretrained', dest='pretrained', action='store_true', + help='use pre-trained model') +parser.add_argument('--pth_path', default='', type=str, metavar='PATH', + help='path to pretrained checkpoint (default: none)') +parser.add_argument('--distributed', action='store_true', + help='Use multi-processing distributed training to launch ' + 'N processes per node, which has N GPUs.') +parser.add_argument('--nodes', type=int, default=1) +parser.add_argument('--device_id', type=int, default=0, help="device id") +parser.add_argument('--device_list', type=str, default="0,1,2,3,4,5,6,7", help="device id list") + + +def get_host_ip(): + """ + 查询本机ip地址 + :return: ip + """ + try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect(('8.8.8.8', 80)) + ip = s.getsockname()[0] + finally: + s.close() + + return ip + + +def device_id_to_process_device_map(device_list): + devices = device_list.split(",") + devices = [int(x) for x in devices] + devices.sort() + + process_device_map = dict() + for process_id, device_id in enumerate(devices): + process_device_map[process_id] = device_id + + return process_device_map + + +def main(): + print('Part1 : prepare for parameters <==> Begin') + args = parser.parse_args() + os.environ["MASTER_ADDR"] = get_host_ip() + os.environ["MASTER_PORT"] = "29688" + args.process_device_map = device_id_to_process_device_map(args.device_list) + if args.device_list != '': + npus_per_node = len(args.device_list.split(',')) + elif args.device_num != -1: + npus_per_node = args.device_num + elif args.device == 'npu': + npus_per_node = torch.npu.device_count() + else: + npus_per_node = torch.cuda.device_count() + + print('npus_per_node:', npus_per_node) + + if args.distributed: + mp.spawn(main_worker, nprocs=npus_per_node, args=(npus_per_node, args)) + else: + # Simply call main_worker function + main_worker(args.npu, npus_per_node, args) + + +def main_worker(npu, npus_per_node, args): + local_rank = 0 + args.npu = args.process_device_map[npu] + if args.distributed: + args.rank = args.rank * npus_per_node + npu + torch.distributed.init_process_group(backend="hccl", + world_size=args.nodes * npus_per_node, + rank=args.rank) + local_rank = torch.distributed.get_rank() + args.is_master_node = not args.distributed or local_rank == 0 + if args.is_master_node: + print(args) + args.device_id = args.device_id + local_rank + print("device_id = ", args.device_id) + device = torch.device(f'npu:{args.device_id}') + torch.npu.set_device(device) + + # create model + if args.pretrained: + print("=> using pre-trained model ResNetSimCLR") + model = ResNetSimCLR(base_model=args.arch, out_dim=args.out_dim) + print("loading model of yours...") + if args.pth_path: + print("load pth you give") + pretrained_dict = torch.load(args.pth_path, map_location="cpu")["state_dict"] + else: + pretrained_dict = torch.load("./checkpoint.pth.tar", map_location="cpu")["state_dict"] + model.load_state_dict(pretrained_dict, strict=False) + else: + print("=> creating model ResNetSimCLR") + model = ResNetSimCLR(base_model=args.arch, out_dim=args.out_dim) + + print('rank', args.rank, ' using npu...') + if args.rank % npus_per_node == 0: + print('Part1 : prepare for parameters <==> Done') + print('Part2 : Load Network <==> Begin') + + cudnn.deterministic = True + cudnn.benchmark = True + model = model.to(device) + optimizer = NpuFusedAdam( + model.parameters(), + args.lr, + weight_decay=args.weight_decay + ) + model, optimizer = amp.initialize(model, optimizer, opt_level="O2", loss_scale=128.0, combine_grad=True) + if args.distributed: + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[local_rank], + broadcast_buffers=False) + criterion = torch.nn.CrossEntropyLoss().to(device) + + if args.rank % npus_per_node == 0: + print('Part2 : Load Network <==> Done') + print('Part3 : Load Dataset <==> Begin') + + dataset = ContrastiveLearningDataset(args.data) + train_dataset = dataset.get_dataset(args.dataset_name, args.n_views) + print(f'workers nums:{args.workers}') + print(f'device nums:{npus_per_node}') + + train_loader, train_loader_len, train_sampler = get_pytorch_train_loader(train_dataset, + args.batch_size, + workers=args.workers) + scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=len(train_loader), eta_min=0, + last_epoch=-1) + if args.rank % npus_per_node == 0: + print('Part3 : Load Dataset <==> Done') + print('Part4 : Train and Test <==> Begin') + + for epoch_counter in range(args.epochs): + if args.distributed: + train_sampler.set_epoch(epoch_counter) + best_acc = 0 + train(args, train_loader, model, criterion, optimizer, epoch_counter, npus_per_node, best_acc) + if epoch_counter >= 10: + scheduler.step() + print('Part4 : Train and Test <==> Done') + + +def info_nce_loss(args, features): + labels = torch.cat([torch.arange(args.batch_size) for i in range(args.n_views)], dim=0) + labels = (labels.unsqueeze(0) == labels.unsqueeze(1)).float() + labels = labels.npu() + features = F.normalize(features, dim=1) + similarity_matrix = torch.matmul(features, features.T) + + # discard the main diagonal from both: labels and similarities matrix + mask = torch.eye(labels.shape[0], dtype=torch.bool).npu() + labels = labels[~mask].view(labels.shape[0], -1) + similarity_matrix = similarity_matrix[~mask].view(similarity_matrix.shape[0], -1) + + # select and combine multiple positives + positives = similarity_matrix[labels.bool()].view(labels.shape[0], -1) + + # select only the negatives the negatives + negatives = similarity_matrix[~labels.bool()].view(similarity_matrix.shape[0], -1) + + logits = torch.cat([positives, negatives], dim=1) + labels = torch.zeros(logits.shape[0], dtype=torch.long).npu() + logits = logits / args.temperature + return logits, labels + + +def train(args, train_loader, model, criterion, optimizer, epoch_counter, npus_per_node, best_acc): + fps = AverageMeter() + + top1 = [0] + top5 = [0] + + end = time.time() + for i, (images, _) in enumerate(train_loader): + images = torch.cat(images, dim=0) + images = images.npu() + + out = model(images) + logits, labels = info_nce_loss(args, out) + loss = criterion(logits, labels) + optimizer.zero_grad() + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + optimizer.step() + + time_step = time.time() - end + fps.update(args.batch_size * npus_per_node / time_step) + torch.npu.synchronize() + end = time.time() + + if i % args.log_every_n_steps == 0 and args.is_master_node: + top1, top5 = accuracy(logits, labels, topk=(1, 5)) + if top1[0] > best_acc: + best_acc = top1[0] + + print('Train Epoch: {0} Step: {1}/{2} Loss {loss:.4f} Time {time:.4f}' + '[AVG-ACC] * Acc@1 {top1:.3f} Acc@5 {top5:.3f} best_acc {best_acc:.3f} ' + 'LR {lr:.7f} FPS {fps:.7f} '.format( + epoch_counter, i, len(train_loader), loss=loss.item(), time=time_step, + top1=top1[0], top5=top5[0], best_acc=best_acc, + lr=optimizer.param_groups[0]['lr'], fps=fps.avg)) + + if (epoch_counter+1) % 5 == 0: + save_checkpoint({ + 'epoch': epoch_counter, + 'arch': model.state_dict(), + 'state_dict': model.state_dict(), + 'optimizer': optimizer.state_dict(), + }) + + +def save_checkpoint(state, filename='checkpoint.pth.tar'): + torch.save(state, filename) + + +def get_pytorch_train_loader(train_dataset, batch_size, workers, _worker_init_fn=None): + train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset) + + dataloader_fn = MultiEpochsDataLoader # torch.utils.data.DataLoader + train_loader = dataloader_fn( + train_dataset, batch_size=batch_size, shuffle=(train_sampler is None), + num_workers=workers, worker_init_fn=_worker_init_fn, pin_memory=False, sampler=train_sampler, + drop_last=True) + return train_loader, len(train_loader), train_sampler + + +class AverageMeter(object): + """Computes and stores the average and current value""" + + def __init__(self): + self.reset() + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + + def update(self, val, n=1): + self.val = val + self.sum += val * n + self.count += n + self.avg = self.sum / self.count + + +if __name__ == '__main__': + main() diff --git a/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/modelzoo_level.txt b/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/modelzoo_level.txt index 5b3e2194db..13f1a4a78a 100644 --- a/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/modelzoo_level.txt +++ b/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/modelzoo_level.txt @@ -1,8 +1,8 @@ -GPUStatus:OK -NPUMigrationStatus:POK -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK -PerfStatus:PERFECT -ModelConvert:NOK +GPUStatus:OK +NPUMigrationStatus:POK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK +PerfStatus:PERFECT +ModelConvert:NOK QuantStatus:NOK \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/multi_epochs_dataloader.py b/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/multi_epochs_dataloader.py index 49b9ae910a..256ccca3c9 100644 --- a/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/multi_epochs_dataloader.py +++ b/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch/multi_epochs_dataloader.py @@ -1,46 +1,46 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch - - -class MultiEpochsDataLoader(torch.utils.data.DataLoader): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._DataLoader__initialized = False - self.batch_sampler = _RepeatSampler(self.batch_sampler) - self._DataLoader__initialized = True - self.iterator = super().__iter__() - - def __len__(self): - return len(self.batch_sampler.sampler) - - def __iter__(self): - for _ in range(len(self)): - yield next(self.iterator) - - -class _RepeatSampler(object): - """ Sampler that repeats forever. - Args: - sampler (Sampler) - """ - - def __init__(self, sampler): - self.sampler = sampler - - def __iter__(self): - while True: - yield from iter(self.sampler) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch + + +class MultiEpochsDataLoader(torch.utils.data.DataLoader): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._DataLoader__initialized = False + self.batch_sampler = _RepeatSampler(self.batch_sampler) + self._DataLoader__initialized = True + self.iterator = super().__iter__() + + def __len__(self): + return len(self.batch_sampler.sampler) + + def __iter__(self): + for _ in range(len(self)): + yield next(self.iterator) + + +class _RepeatSampler(object): + """ Sampler that repeats forever. + Args: + sampler (Sampler) + """ + + def __init__(self, sampler): + self.sampler = sampler + + def __iter__(self): + while True: + yield from iter(self.sampler) diff --git a/PyTorch/contrib/cv/detection/StyleGAN2-ADA/README.md b/PyTorch/contrib/cv/detection/StyleGAN2-ADA/README.md index e6570405ae..60eeb9406c 100644 --- a/PyTorch/contrib/cv/detection/StyleGAN2-ADA/README.md +++ b/PyTorch/contrib/cv/detection/StyleGAN2-ADA/README.md @@ -1,64 +1,64 @@ -# Stylegan2-ADA-Pytorch模型PyTorch离线推理指导 - -## 1 环境准备 - -1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 - -``` -pip install -r requirements.txt -``` - - -2.获取,修改与安装开源模型代码 - -``` -(torch 1.7.0以上版本)git clone https://github.com/NVlabs/stylegan2-ada-pytorch.git model -(torch 1.5.0)git clone https://github.com/Hypersus/utils-for-stylegan2-ada-pytorch.git model -``` - - -3.获取权重文件 - -将权重文件G_ema_bs8_8p_kimg1000.pkl放到当前工作目录 - -4.数据集 -执行`python stylegan2-ada-pytorch_preprocess.py`,默认生成`batch_size=1`的一条输入,保存在`./input`目录下 - - - -5.获取msame工具 -将msame放到当前工作目录 - - - -## 2 离线推理 - -310上执行,执行时使npu-smi info查看设备状态,确保device空闲 - -``` -bash test/pth2om.sh -bash test/eval_acc_perf.sh -``` - **评测结果:** - -bs1在310上推理的性能 - -``` -Inference average time : 207.61 ms -Inference average time without first time: 207.59 ms -``` - -bs1 310单卡吞吐率:1000/(207.61/4)=19.27fps - -bs1在T4上推理的性能 - -``` -Inference average time : 317.90 ms -``` - - - -| 模型 | T4性能 | 310性能 | -| :-----------------------: | :------: | :------: | -| stylegan2-ada-pytorch bs1 | 12.58fps | 19.27fps | - +# Stylegan2-ADA-Pytorch模型PyTorch离线推理指导 + +## 1 环境准备 + +1.安装必要的依赖,测试环境可能已经安装其中的一些不同版本的库了,故手动测试时不推荐使用该命令安装 + +``` +pip install -r requirements.txt +``` + + +2.获取,修改与安装开源模型代码 + +``` +(torch 1.7.0以上版本)git clone https://github.com/NVlabs/stylegan2-ada-pytorch.git model +(torch 1.5.0)git clone https://github.com/Hypersus/utils-for-stylegan2-ada-pytorch.git model +``` + + +3.获取权重文件 + +将权重文件G_ema_bs8_8p_kimg1000.pkl放到当前工作目录 + +4.数据集 +执行`python stylegan2-ada-pytorch_preprocess.py`,默认生成`batch_size=1`的一条输入,保存在`./input`目录下 + + + +5.获取msame工具 +将msame放到当前工作目录 + + + +## 2 离线推理 + +310上执行,执行时使npu-smi info查看设备状态,确保device空闲 + +``` +bash test/pth2om.sh +bash test/eval_acc_perf.sh +``` + **评测结果:** + +bs1在310上推理的性能 + +``` +Inference average time : 207.61 ms +Inference average time without first time: 207.59 ms +``` + +bs1 310单卡吞吐率:1000/(207.61/4)=19.27fps + +bs1在T4上推理的性能 + +``` +Inference average time : 317.90 ms +``` + + + +| 模型 | T4性能 | 310性能 | +| :-----------------------: | :------: | :------: | +| stylegan2-ada-pytorch bs1 | 12.58fps | 19.27fps | + diff --git a/PyTorch/contrib/cv/detection/StyleGAN2-ADA/perf_gpu.py b/PyTorch/contrib/cv/detection/StyleGAN2-ADA/perf_gpu.py index 58c4ecd8b1..cfb3a59f73 100644 --- a/PyTorch/contrib/cv/detection/StyleGAN2-ADA/perf_gpu.py +++ b/PyTorch/contrib/cv/detection/StyleGAN2-ADA/perf_gpu.py @@ -1,122 +1,122 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ - -import os -import sys -import time - -sys.path.append('./model') -import numpy as np -import torch -import pickle -import argparse -import PIL.Image -import functools - - -def save_image_grid(img, fname, drange, grid_size): - lo, hi = drange - img = np.asarray(img, dtype=np.float32) - img = (img - lo) * (255 / (hi - lo)) - img = np.rint(img).clip(0, 255).astype(np.uint8) - - gw, gh = grid_size - _N, C, H, W = img.shape - img = img.reshape(gh, gw, C, H, W) - img = img.transpose(0, 3, 1, 4, 2) - img = img.reshape(gh * H, gw * W, C) - - assert C in [1, 3] - if C == 1: - PIL.Image.fromarray(img[:, :, 0], 'L').save(fname) - if C == 3: - PIL.Image.fromarray(img, 'RGB').save(fname) - - -def main(args): - pkl_file = args.pkl_file - bs = args.batch_size - input_path = args.input_path - image_path = args.image_path - device = 'cuda:0' if torch.cuda.is_available() else 'cpu' - - grid_size = (1, 1) - input_path = os.path.join(input_path, 'bs{}'.format(bs)) - input_files = os.listdir(input_path) - input_files.sort() - image_path = os.path.join(image_path, 'bs{}_pkl'.format(bs)) - os.makedirs(image_path, exist_ok=True) - # load model - start = time.time() - with open(pkl_file, 'rb') as f: - G = pickle.load(f)['G_ema'].to(device) - - G.forward = functools.partial(G.forward, force_fp32=True) - for i in range(len(input_files)): - input_file = input_files[i] - input_file = os.path.join(input_path, input_file) - input_file = np.fromfile(input_file, dtype=np.float32) - z = torch.tensor(input_file).reshape(-1, G.z_dim).to(device) - c = torch.empty(bs, 0).to(device) - image = G(z, c) - image = image.reshape(-1, 3, 512, 512) - image = image.cpu() - save_image_grid(image, os.path.join(image_path, f'gen_image_{i:04d}') + '.png', drange=[-1, 1], - grid_size=grid_size) - - end = time.time() - print(f'Inference average time : {((end - start) * 1000 / len(input_files)):.2f} ms') - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--pkl_file', type=str, default='./G_ema_bs8_8p_kimg1000.pkl') - parser.add_argument('--input_path', type=str, default='./input') - parser.add_argument('--image_path', type=str, default='./results') - parser.add_argument('--batch_size', type=int, default=1) - args = parser.parse_args() - - main(args) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ + +import os +import sys +import time + +sys.path.append('./model') +import numpy as np +import torch +import pickle +import argparse +import PIL.Image +import functools + + +def save_image_grid(img, fname, drange, grid_size): + lo, hi = drange + img = np.asarray(img, dtype=np.float32) + img = (img - lo) * (255 / (hi - lo)) + img = np.rint(img).clip(0, 255).astype(np.uint8) + + gw, gh = grid_size + _N, C, H, W = img.shape + img = img.reshape(gh, gw, C, H, W) + img = img.transpose(0, 3, 1, 4, 2) + img = img.reshape(gh * H, gw * W, C) + + assert C in [1, 3] + if C == 1: + PIL.Image.fromarray(img[:, :, 0], 'L').save(fname) + if C == 3: + PIL.Image.fromarray(img, 'RGB').save(fname) + + +def main(args): + pkl_file = args.pkl_file + bs = args.batch_size + input_path = args.input_path + image_path = args.image_path + device = 'cuda:0' if torch.cuda.is_available() else 'cpu' + + grid_size = (1, 1) + input_path = os.path.join(input_path, 'bs{}'.format(bs)) + input_files = os.listdir(input_path) + input_files.sort() + image_path = os.path.join(image_path, 'bs{}_pkl'.format(bs)) + os.makedirs(image_path, exist_ok=True) + # load model + start = time.time() + with open(pkl_file, 'rb') as f: + G = pickle.load(f)['G_ema'].to(device) + + G.forward = functools.partial(G.forward, force_fp32=True) + for i in range(len(input_files)): + input_file = input_files[i] + input_file = os.path.join(input_path, input_file) + input_file = np.fromfile(input_file, dtype=np.float32) + z = torch.tensor(input_file).reshape(-1, G.z_dim).to(device) + c = torch.empty(bs, 0).to(device) + image = G(z, c) + image = image.reshape(-1, 3, 512, 512) + image = image.cpu() + save_image_grid(image, os.path.join(image_path, f'gen_image_{i:04d}') + '.png', drange=[-1, 1], + grid_size=grid_size) + + end = time.time() + print(f'Inference average time : {((end - start) * 1000 / len(input_files)):.2f} ms') + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--pkl_file', type=str, default='./G_ema_bs8_8p_kimg1000.pkl') + parser.add_argument('--input_path', type=str, default='./input') + parser.add_argument('--image_path', type=str, default='./results') + parser.add_argument('--batch_size', type=int, default=1) + args = parser.parse_args() + + main(args) diff --git a/PyTorch/contrib/cv/detection/StyleGAN2-ADA/requirements.txt b/PyTorch/contrib/cv/detection/StyleGAN2-ADA/requirements.txt index 3f02106834..017e9b5007 100644 --- a/PyTorch/contrib/cv/detection/StyleGAN2-ADA/requirements.txt +++ b/PyTorch/contrib/cv/detection/StyleGAN2-ADA/requirements.txt @@ -1,5 +1,5 @@ -requests -scipy -numpy -Pillow +requests +scipy +numpy +Pillow torch==1.5.0 \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/StyleGAN2-ADA/stylegan2-ada-pytorch_postprocess.py b/PyTorch/contrib/cv/detection/StyleGAN2-ADA/stylegan2-ada-pytorch_postprocess.py index 69bc1a47de..d301391b97 100644 --- a/PyTorch/contrib/cv/detection/StyleGAN2-ADA/stylegan2-ada-pytorch_postprocess.py +++ b/PyTorch/contrib/cv/detection/StyleGAN2-ADA/stylegan2-ada-pytorch_postprocess.py @@ -1,78 +1,78 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# - -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ - -import torch -import os -import numpy as np -import argparse -from perf_gpu import save_image_grid - - -def test_om(args): - bin_path = args.bin_path - image_path = args.image_path - bin_list = os.listdir(bin_path) - bin_list.sort() - for i in range(len(bin_list)): - images = np.fromfile(os.path.join(bin_path, bin_list[i]), dtype=np.float32) - images = torch.Tensor(images) - images = images.reshape(-1, 3, 512, 512) - bs = images.shape[0] - grid_size = (4, 4) if bs == 16 else (1, 1) - save_path = os.path.join(image_path, "bs{}_om".format(bs)) - os.makedirs(save_path, exist_ok=True) - save_image_grid(images, os.path.join(save_path, f'gen_image_{i:04d}') + ".png", drange=[-1, 1], - grid_size=grid_size) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('--bin_path', type=str, required=True) - parser.add_argument('--image_path', type=str, default='./results') - args = parser.parse_args() - - test_om(args) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# + +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ + +import torch +import os +import numpy as np +import argparse +from perf_gpu import save_image_grid + + +def test_om(args): + bin_path = args.bin_path + image_path = args.image_path + bin_list = os.listdir(bin_path) + bin_list.sort() + for i in range(len(bin_list)): + images = np.fromfile(os.path.join(bin_path, bin_list[i]), dtype=np.float32) + images = torch.Tensor(images) + images = images.reshape(-1, 3, 512, 512) + bs = images.shape[0] + grid_size = (4, 4) if bs == 16 else (1, 1) + save_path = os.path.join(image_path, "bs{}_om".format(bs)) + os.makedirs(save_path, exist_ok=True) + save_image_grid(images, os.path.join(save_path, f'gen_image_{i:04d}') + ".png", drange=[-1, 1], + grid_size=grid_size) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('--bin_path', type=str, required=True) + parser.add_argument('--image_path', type=str, default='./results') + args = parser.parse_args() + + test_om(args) diff --git a/PyTorch/contrib/cv/detection/StyleGAN2-ADA/stylegan2-ada-pytorch_preprocess.py b/PyTorch/contrib/cv/detection/StyleGAN2-ADA/stylegan2-ada-pytorch_preprocess.py index fee1140fa6..9c90a9be83 100644 --- a/PyTorch/contrib/cv/detection/StyleGAN2-ADA/stylegan2-ada-pytorch_preprocess.py +++ b/PyTorch/contrib/cv/detection/StyleGAN2-ADA/stylegan2-ada-pytorch_preprocess.py @@ -1,81 +1,81 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# - -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ - -import os -import torch -import argparse - - -def main(args): - # set up option - z_dim = 512 - c_dim = 0 - bs = args.batch_size - num = args.num_input - save_path = args.save_path - - # create save path dir - save_path = os.path.join(save_path, "bs{}".format(bs)) - os.makedirs(save_path, exist_ok=True) - - # generate input - for i in range(num): - z = torch.randn([bs, z_dim]) - c = torch.empty([bs, c_dim]) - input = torch.cat((z, c), 1).numpy() - input.tofile(os.path.join(save_path, f'input_bs{bs}_{i:04d}.bin')) - - -# ---------------------------------------------------------------------------- -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('--num_input', type=int, default=1) - parser.add_argument('--batch_size', type=int, default=1) - parser.add_argument('--save_path', type=str, default='./input') - args = parser.parse_args() - main(args) -# ---------------------------------------------------------------------------- +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# + +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ + +import os +import torch +import argparse + + +def main(args): + # set up option + z_dim = 512 + c_dim = 0 + bs = args.batch_size + num = args.num_input + save_path = args.save_path + + # create save path dir + save_path = os.path.join(save_path, "bs{}".format(bs)) + os.makedirs(save_path, exist_ok=True) + + # generate input + for i in range(num): + z = torch.randn([bs, z_dim]) + c = torch.empty([bs, c_dim]) + input = torch.cat((z, c), 1).numpy() + input.tofile(os.path.join(save_path, f'input_bs{bs}_{i:04d}.bin')) + + +# ---------------------------------------------------------------------------- +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('--num_input', type=int, default=1) + parser.add_argument('--batch_size', type=int, default=1) + parser.add_argument('--save_path', type=str, default='./input') + args = parser.parse_args() + main(args) +# ---------------------------------------------------------------------------- diff --git a/PyTorch/contrib/cv/detection/TextSnake/Dockerfile b/PyTorch/contrib/cv/detection/TextSnake/Dockerfile index 7e712fe1a1..30a31af558 100644 --- a/PyTorch/contrib/cv/detection/TextSnake/Dockerfile +++ b/PyTorch/contrib/cv/detection/TextSnake/Dockerfile @@ -1,5 +1,5 @@ -ARG FROM_IMAGE_NAME -FROM $FROM_IMAGE_NAME - -COPY requirements.txt . +ARG FROM_IMAGE_NAME +FROM $FROM_IMAGE_NAME + +COPY requirements.txt . RUN pip3.7 install -r requirements.txt \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/TextSnake/dataset/ctw.py b/PyTorch/contrib/cv/detection/TextSnake/dataset/ctw.py index 4e1ad12a81..eb1309d6c1 100644 --- a/PyTorch/contrib/cv/detection/TextSnake/dataset/ctw.py +++ b/PyTorch/contrib/cv/detection/TextSnake/dataset/ctw.py @@ -1,31 +1,31 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ============================================================================ \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/TextSnake/dataset/total_text/Evaluation_Protocol/ComputePrecisionRecall.m b/PyTorch/contrib/cv/detection/TextSnake/dataset/total_text/Evaluation_Protocol/ComputePrecisionRecall.m index 216a349259..3df883ab2b 100644 --- a/PyTorch/contrib/cv/detection/TextSnake/dataset/total_text/Evaluation_Protocol/ComputePrecisionRecall.m +++ b/PyTorch/contrib/cv/detection/TextSnake/dataset/total_text/Evaluation_Protocol/ComputePrecisionRecall.m @@ -1,161 +1,161 @@ -function [ precision, recall ] = ComputePrecisionRecall( tau, sigma, tp,tr,k,fsc_k ) -%COMPUTEPRECISIONRECALL Summary of this function goes here -% Detailed explanation goes here - -if nargin == 2 - tr = 0.8; % recall threshold - tp = 0.4; % precision threshold - k = 2; % min number of matches, used in penalizing split & merge - fsc_k = 0.8;% penalize value of split or merge -end - -tot_gt = 0; -recall_accum = 0; - -tot_detected = 0; -precision_accum = 0; - -num_images = numel(tau); -assert(num_images == numel(sigma)); - -flag_gt = cell(1, num_images); -flag_det = cell(1, num_images); - -for ifile=1:num_images - - [num_gt, num_detected] = size( sigma{ifile} ); - tot_gt = tot_gt + num_gt; - tot_detected = tot_detected + num_detected; - - % ----- mark unprocessed - flag_gt{ifile} = zeros(num_gt, 1); - flag_det{ifile} = zeros(num_detected, 1); - - % --------------------------------------- - % check one-to-one match - % --------------------------------------- - for i_gt=1:num_gt - - num_detected_in_sigma = numel( find( sigma{ifile}(i_gt,:)>tr) ); - num_detected_in_tau = numel( find( tau{ifile}(i_gt,:)>tp) ); - - if num_detected_in_sigma == 1 && num_detected_in_tau == 1 - recall_accum = recall_accum + 1.0; - precision_accum = precision_accum + 1.0; - - % Mark the ground truth and detection, do not process twice - flag_gt{ifile}(i_gt) = 1; - idx_det = sigma{ifile}(i_gt,:)>tr; - flag_det{ifile}(idx_det) = 1; - end - end - - % --------------------------------------- - % check one-to-many match (split) - % one gt with many detected rectangles - % --------------------------------------- - for i_gt=1:num_gt - - if flag_gt{ifile}(i_gt) > 0 - continue; - end - - num_nonzero_in_sigma = sum( sigma{ifile}(i_gt,:)>0 ); - if num_nonzero_in_sigma >= k - - % ------------------------------------------------------------- - % Search the possible "many" partners for this "one" rectangle - % ------------------------------------------------------------- - - % ----- satisfy 1st condition - % only select unprocessed data - idx_detected_in_tau = find( (tau{ifile}(i_gt,:)'>=tp) & (flag_det{ifile}==0) ); - num_detected_in_tau = numel( idx_detected_in_tau ); - - if num_detected_in_tau == 1 - % Only one of the many-rectangles qualified -> - % This match degraded to a one-to-one match - if ( (tau{ifile}(i_gt, idx_detected_in_tau) >= tp) && ... - (sigma{ifile}(i_gt, idx_detected_in_tau) >= tr) ) - recall_accum = recall_accum + 1.0; - precision_accum = precision_accum + 1.0; - end - else - % satisfy 2nd condition - if sum( sigma{ifile}(i_gt,idx_detected_in_tau) ) >= tr - - % Mark the "one" rectangle - flag_gt{ifile}(i_gt) = 1; - - % Mark all the "many" rectangles - flag_det{ifile}(idx_detected_in_tau) = 1; - - recall_accum = recall_accum + fsc_k; - precision_accum = precision_accum + num_detected_in_tau * fsc_k; - - end - end - - end - - % No match - recall_accum = recall_accum + 0; - precision_accum = precision_accum + 0; - - end - - % --------------------------------------- - % check many-to-one match (merge) - % one detected rectangle with many gt - % --------------------------------------- - for i_test=1:num_detected - - if flag_det{ifile}(i_test) > 0 - continue; - end - - num_nonzero_in_tau = sum( tau{ifile}(:,i_test)>0 ); - if num_nonzero_in_tau >= k - - % satisfy 1st condition - % only select unprocessed data - idx_detected_in_sigma = find( (sigma{ifile}(:,i_test)>=tr) & (flag_gt{ifile}==0) ); - num_detected_in_sigma = numel( idx_detected_in_sigma ); - - if num_detected_in_sigma == 1 - % Only one of the many-rectangles qualified -> - % This match degraded to a one-to-one match - if ( (tau{ifile}(idx_detected_in_sigma, i_test) >= tp) && ... - (sigma{ifile}(idx_detected_in_sigma, i_test) >= tr) ) - recall_accum = recall_accum + 1.0; - precision_accum = precision_accum + 1.0; - end - else - % satisfy 2nd condition - if sum( tau{ifile}(idx_detected_in_sigma,i_test) ) >= tp - % Mark the "one" rectangle - flag_det{ifile}(i_test) = 1; - - % Mark all the "many" rectangles - flag_gt{ifile}(idx_detected_in_sigma) = 1; - - recall_accum = recall_accum + num_detected_in_sigma*fsc_k; - precision_accum = precision_accum + fsc_k; -% recall_accum = recall_accum + num_detected_in_sigma; -% precision_accum = precision_accum + 1.0; - end - end - - end - - % No match - recall_accum = recall_accum + 0; - precision_accum = precision_accum + 0; - end - -end -recall = recall_accum / tot_gt; -precision = precision_accum / tot_detected; - -end - +function [ precision, recall ] = ComputePrecisionRecall( tau, sigma, tp,tr,k,fsc_k ) +%COMPUTEPRECISIONRECALL Summary of this function goes here +% Detailed explanation goes here + +if nargin == 2 + tr = 0.8; % recall threshold + tp = 0.4; % precision threshold + k = 2; % min number of matches, used in penalizing split & merge + fsc_k = 0.8;% penalize value of split or merge +end + +tot_gt = 0; +recall_accum = 0; + +tot_detected = 0; +precision_accum = 0; + +num_images = numel(tau); +assert(num_images == numel(sigma)); + +flag_gt = cell(1, num_images); +flag_det = cell(1, num_images); + +for ifile=1:num_images + + [num_gt, num_detected] = size( sigma{ifile} ); + tot_gt = tot_gt + num_gt; + tot_detected = tot_detected + num_detected; + + % ----- mark unprocessed + flag_gt{ifile} = zeros(num_gt, 1); + flag_det{ifile} = zeros(num_detected, 1); + + % --------------------------------------- + % check one-to-one match + % --------------------------------------- + for i_gt=1:num_gt + + num_detected_in_sigma = numel( find( sigma{ifile}(i_gt,:)>tr) ); + num_detected_in_tau = numel( find( tau{ifile}(i_gt,:)>tp) ); + + if num_detected_in_sigma == 1 && num_detected_in_tau == 1 + recall_accum = recall_accum + 1.0; + precision_accum = precision_accum + 1.0; + + % Mark the ground truth and detection, do not process twice + flag_gt{ifile}(i_gt) = 1; + idx_det = sigma{ifile}(i_gt,:)>tr; + flag_det{ifile}(idx_det) = 1; + end + end + + % --------------------------------------- + % check one-to-many match (split) + % one gt with many detected rectangles + % --------------------------------------- + for i_gt=1:num_gt + + if flag_gt{ifile}(i_gt) > 0 + continue; + end + + num_nonzero_in_sigma = sum( sigma{ifile}(i_gt,:)>0 ); + if num_nonzero_in_sigma >= k + + % ------------------------------------------------------------- + % Search the possible "many" partners for this "one" rectangle + % ------------------------------------------------------------- + + % ----- satisfy 1st condition + % only select unprocessed data + idx_detected_in_tau = find( (tau{ifile}(i_gt,:)'>=tp) & (flag_det{ifile}==0) ); + num_detected_in_tau = numel( idx_detected_in_tau ); + + if num_detected_in_tau == 1 + % Only one of the many-rectangles qualified -> + % This match degraded to a one-to-one match + if ( (tau{ifile}(i_gt, idx_detected_in_tau) >= tp) && ... + (sigma{ifile}(i_gt, idx_detected_in_tau) >= tr) ) + recall_accum = recall_accum + 1.0; + precision_accum = precision_accum + 1.0; + end + else + % satisfy 2nd condition + if sum( sigma{ifile}(i_gt,idx_detected_in_tau) ) >= tr + + % Mark the "one" rectangle + flag_gt{ifile}(i_gt) = 1; + + % Mark all the "many" rectangles + flag_det{ifile}(idx_detected_in_tau) = 1; + + recall_accum = recall_accum + fsc_k; + precision_accum = precision_accum + num_detected_in_tau * fsc_k; + + end + end + + end + + % No match + recall_accum = recall_accum + 0; + precision_accum = precision_accum + 0; + + end + + % --------------------------------------- + % check many-to-one match (merge) + % one detected rectangle with many gt + % --------------------------------------- + for i_test=1:num_detected + + if flag_det{ifile}(i_test) > 0 + continue; + end + + num_nonzero_in_tau = sum( tau{ifile}(:,i_test)>0 ); + if num_nonzero_in_tau >= k + + % satisfy 1st condition + % only select unprocessed data + idx_detected_in_sigma = find( (sigma{ifile}(:,i_test)>=tr) & (flag_gt{ifile}==0) ); + num_detected_in_sigma = numel( idx_detected_in_sigma ); + + if num_detected_in_sigma == 1 + % Only one of the many-rectangles qualified -> + % This match degraded to a one-to-one match + if ( (tau{ifile}(idx_detected_in_sigma, i_test) >= tp) && ... + (sigma{ifile}(idx_detected_in_sigma, i_test) >= tr) ) + recall_accum = recall_accum + 1.0; + precision_accum = precision_accum + 1.0; + end + else + % satisfy 2nd condition + if sum( tau{ifile}(idx_detected_in_sigma,i_test) ) >= tp + % Mark the "one" rectangle + flag_det{ifile}(i_test) = 1; + + % Mark all the "many" rectangles + flag_gt{ifile}(idx_detected_in_sigma) = 1; + + recall_accum = recall_accum + num_detected_in_sigma*fsc_k; + precision_accum = precision_accum + fsc_k; +% recall_accum = recall_accum + num_detected_in_sigma; +% precision_accum = precision_accum + 1.0; + end + end + + end + + % No match + recall_accum = recall_accum + 0; + precision_accum = precision_accum + 0; + end + +end +recall = recall_accum / tot_gt; +precision = precision_accum / tot_detected; + +end + diff --git a/PyTorch/contrib/cv/detection/TextSnake/modelzoo_level.txt b/PyTorch/contrib/cv/detection/TextSnake/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/detection/TextSnake/modelzoo_level.txt +++ b/PyTorch/contrib/cv/detection/TextSnake/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/YOLACT/layers/modules/multibox_loss.py b/PyTorch/contrib/cv/detection/YOLACT/layers/modules/multibox_loss.py index 3f97991c39..86006e7d4d 100644 --- a/PyTorch/contrib/cv/detection/YOLACT/layers/modules/multibox_loss.py +++ b/PyTorch/contrib/cv/detection/YOLACT/layers/modules/multibox_loss.py @@ -1,737 +1,737 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -# -*- coding: utf-8 -*- -import torch -import torch.nn as nn -import torch.nn.functional as F -from torch.autograd import Variable -from ..box_utils import match, log_sum_exp, decode, center_size, crop, elemwise_mask_iou, elemwise_box_iou - -from data import cfg, mask_type, activation_func - -class MultiBoxLoss(nn.Module): - """SSD Weighted Loss Function - Compute Targets: - 1) Produce Confidence Target Indices by matching ground truth boxes - with (default) 'priorboxes' that have jaccard index > threshold parameter - (default threshold: 0.5). - - 2) Produce localization target by 'encoding' variance into offsets of ground - truth boxes and their matched 'priorboxes'. - - 3) Hard negative mining to filter the excessive number of negative examples - that comes with using a large number of default bounding boxes. - (default negative:positive ratio 3:1) - - Objective Loss: - L(x,c,l,g) = (Lconf(x, c) + αLloc(x,l,g)) / N - Where, Lconf is the CrossEntropy Loss and Lloc is the SmoothL1 Loss - weighted by α which is set to 1 by cross val. - Args: - c: class confidences, - l: predicted boxes, - g: ground truth boxes - N: number of matched default boxes - See: https://arxiv.org/pdf/1512.02325.pdf for more details. - """ - - def __init__(self, num_classes, pos_threshold, neg_threshold, negpos_ratio): - super(MultiBoxLoss, self).__init__() - self.num_classes = num_classes - - self.pos_threshold = pos_threshold - self.neg_threshold = neg_threshold - self.negpos_ratio = negpos_ratio - - # If you output a proto mask with this area, your l1 loss will be l1_alpha - # Note that the area is relative (so 1 would be the entire image) - self.l1_expected_area = 20*20/70/70 - self.l1_alpha = 0.1 - - if cfg.use_class_balanced_conf: - self.class_instances = None - self.total_instances = 0 - - def forward(self, net, predictions, wrapper, wrapper_mask): - """Multibox Loss - Args: - predictions (tuple): A tuple containing loc preds, conf preds, - mask preds, and prior boxes from SSD net. - loc shape: torch.size(batch_size,num_priors,4) - conf shape: torch.size(batch_size,num_priors,num_classes) - masks shape: torch.size(batch_size,num_priors,mask_dim) - priors shape: torch.size(num_priors,4) - proto* shape: torch.size(batch_size,mask_h,mask_w,mask_dim) - - targets (list): Ground truth boxes and labels for a batch, - shape: [batch_size][num_objs,5] (last idx is the label). - - masks (list): Ground truth masks for each object in each image, - shape: [batch_size][num_objs,im_height,im_width] - - num_crowds (list): Number of crowd annotations per batch. The crowd - annotations should be the last num_crowds elements of targets and masks. - - * Only if mask_type == lincomb - """ - - targets, masks, num_crowds = wrapper.get_args(wrapper_mask) - targets = targets[0] - masks = masks[0] - num_crowds = num_crowds[0] - loc_data = predictions['loc'] - conf_data = predictions['conf'] - mask_data = predictions['mask'] - priors = predictions['priors'] - - if cfg.mask_type == mask_type.lincomb: - proto_data = predictions['proto'] - - score_data = predictions['score'] if cfg.use_mask_scoring else None - inst_data = predictions['inst'] if cfg.use_instance_coeff else None - - labels = [None] * len(targets) # Used in sem segm loss - - batch_size = loc_data.size(0) - num_priors = priors.size(0) - num_classes = self.num_classes - - # Match priors (default boxes) and ground truth boxes - # These tensors will be created with the same device as loc_data - loc_t = loc_data.new(batch_size, num_priors, 4) - gt_box_t = loc_data.new(batch_size, num_priors, 4) - conf_t = loc_data.new(batch_size, num_priors).long() - idx_t = loc_data.new(batch_size, num_priors).long() - - if cfg.use_class_existence_loss: - class_existence_t = loc_data.new(batch_size, num_classes-1) - - for idx in range(batch_size): - truths = targets[idx][:, :-1].data - labels[idx] = targets[idx][:, -1].data.long() - - if cfg.use_class_existence_loss: - # Construct a one-hot vector for each object and collapse it into an existence vector with max - # Also it's fine to include the crowd annotations here - class_existence_t[idx, :] = torch.eye(num_classes-1, device=conf_t.get_device())[labels[idx]].max(dim=0)[0] - - # Split the crowd annotations because they come bundled in - cur_crowds = num_crowds[idx] - if cur_crowds > 0: - split = lambda x: (x[-cur_crowds:], x[:-cur_crowds]) - crowd_boxes, truths = split(truths) - - # We don't use the crowd labels or masks - _, labels[idx] = split(labels[idx]) - _, masks[idx] = split(masks[idx]) - else: - crowd_boxes = None - - - match(self.pos_threshold, self.neg_threshold, - truths, priors.data, labels[idx], crowd_boxes, - loc_t, conf_t, idx_t, idx, loc_data[idx]) - - gt_box_t[idx, :, :] = truths[idx_t[idx]] - - # wrap targets - loc_t = Variable(loc_t, requires_grad=False) - conf_t = Variable(conf_t, requires_grad=False) - idx_t = Variable(idx_t, requires_grad=False) - - pos = conf_t > 0 - num_pos = pos.sum(dim=1, keepdim=True) - - # Shape: [batch,num_priors,4] - pos_idx = pos.unsqueeze(pos.dim()).expand_as(loc_data) - - losses = {} - - # Localization Loss (Smooth L1) - if cfg.train_boxes: - loc_p = loc_data.view(-1, 4) - loc_t = loc_t.view(-1, 4) - losses['B'] = F.smooth_l1_loss(loc_p, loc_t, reduction='none') * cfg.bbox_alpha - losses['B'][pos_idx.view(-1, 4) == False] = 0 - losses['B'] = losses['B'].sum() - - if cfg.train_masks: - if cfg.mask_type == mask_type.direct: - if cfg.use_gt_bboxes: - pos_masks = [] - for idx in range(batch_size): - pos_masks.append(masks[idx][idx_t[idx, pos[idx]]]) - masks_t = torch.cat(pos_masks, 0) - masks_p = mask_data[pos, :].view(-1, cfg.mask_dim) - losses['M'] = F.binary_cross_entropy(torch.clamp(masks_p, 0, 1), masks_t, reduction='sum') * cfg.mask_alpha - else: - losses['M'] = self.direct_mask_loss(pos_idx, idx_t, loc_data, mask_data, priors, masks) - elif cfg.mask_type == mask_type.lincomb: - ret = self.lincomb_mask_loss(pos, idx_t, loc_data, mask_data, priors, proto_data, masks, gt_box_t, score_data, inst_data, labels) - if cfg.use_maskiou: - loss, maskiou_targets = ret - else: - loss = ret - losses.update(loss) - - if cfg.mask_proto_loss is not None: - if cfg.mask_proto_loss == 'l1': - losses['P'] = torch.mean(torch.abs(proto_data)) / self.l1_expected_area * self.l1_alpha - elif cfg.mask_proto_loss == 'disj': - losses['P'] = -torch.mean(torch.max(F.log_softmax(proto_data, dim=-1), dim=-1)[0]) - - # Confidence loss - if cfg.use_focal_loss: - if cfg.use_sigmoid_focal_loss: - losses['C'] = self.focal_conf_sigmoid_loss(conf_data, conf_t) - elif cfg.use_objectness_score: - losses['C'] = self.focal_conf_objectness_loss(conf_data, conf_t) - else: - losses['C'] = self.focal_conf_loss(conf_data, conf_t) - else: - if cfg.use_objectness_score: - losses['C'] = self.conf_objectness_loss(conf_data, conf_t, batch_size, loc_p, loc_t, priors) - else: - losses['C'] = self.ohem_conf_loss(conf_data, conf_t, pos, batch_size) - - # Mask IoU Loss - if cfg.use_maskiou and maskiou_targets is not None: - losses['I'] = self.mask_iou_loss(net, maskiou_targets) - - # These losses also don't depend on anchors - if cfg.use_class_existence_loss: - losses['E'] = self.class_existence_loss(predictions['classes'], class_existence_t) - if cfg.use_semantic_segmentation_loss: - losses['S'] = self.semantic_segmentation_loss(predictions['segm'], masks, labels) - - # Divide all losses by the number of positives. - # Don't do it for loss[P] because that doesn't depend on the anchors. - total_num_pos = num_pos.data.sum().float() - for k in losses: - if k not in ('P', 'E', 'S'): - losses[k] /= total_num_pos - else: - losses[k] /= batch_size - - # Loss Key: - # - B: Box Localization Loss - # - C: Class Confidence Loss - # - M: Mask Loss - # - P: Prototype Loss - # - D: Coefficient Diversity Loss - # - E: Class Existence Loss - # - S: Semantic Segmentation Loss - return losses - - def class_existence_loss(self, class_data, class_existence_t): - return cfg.class_existence_alpha * F.binary_cross_entropy_with_logits(class_data, class_existence_t, reduction='sum') - - def semantic_segmentation_loss(self, segment_data, mask_t, class_t, interpolation_mode='bilinear'): - # Note num_classes here is without the background class so cfg.num_classes-1 - batch_size, num_classes, mask_h, mask_w = segment_data.size() - loss_s = 0 - - for idx in range(batch_size): - cur_segment = segment_data[idx] - cur_class_t = class_t[idx] - - with torch.no_grad(): - downsampled_masks = F.interpolate(mask_t[idx].unsqueeze(0), (mask_h, mask_w), - mode=interpolation_mode, align_corners=False).squeeze(0) - downsampled_masks = downsampled_masks.gt(0.5).float() - - # Construct Semantic Segmentation - segment_t = torch.zeros_like(cur_segment, requires_grad=False) - for obj_idx in range(downsampled_masks.size(0)): - segment_t[cur_class_t[obj_idx]] = torch.max(segment_t[cur_class_t[obj_idx]].float(), downsampled_masks[obj_idx]) - - loss_s += F.binary_cross_entropy_with_logits(cur_segment, segment_t, reduction='sum') - - return loss_s / mask_h / mask_w * cfg.semantic_segmentation_alpha - - - def ohem_conf_loss(self, conf_data, conf_t, pos, num): - # Compute max conf across batch for hard negative mining - batch_conf = conf_data.view(-1, self.num_classes) - if cfg.ohem_use_most_confident: - # i.e. max(softmax) along classes > 0 - batch_conf = F.softmax(batch_conf, dim=1) - loss_c, _ = batch_conf[:, 1:].max(dim=1) - else: - # i.e. -softmax(class 0 confidence) - loss_c = log_sum_exp(batch_conf) - batch_conf[:, 0] - - # Hard Negative Mining - loss_c = loss_c.view(num, -1) - loss_c[pos] = 0 # filter out pos boxes - loss_c[conf_t < 0] = 0 # filter out neutrals (conf_t = -1) - _, loss_idx = loss_c.sort(1, descending=True) - _, idx_rank = loss_idx.sort(1) - num_pos = pos.long().sum(1, keepdim=True) - num_neg = torch.clamp(self.negpos_ratio*num_pos, max=pos.size(1)-1) - neg = idx_rank < num_neg.expand_as(idx_rank) - - # Just in case there aren't enough negatives, don't start using positives as negatives - neg[pos] = 0 - neg[conf_t < 0] = 0 # Filter out neutrals - - # Confidence Loss Including Positive and Negative Examples - pos_idx = pos.unsqueeze(2).expand_as(conf_data) - neg_idx = neg.unsqueeze(2).expand_as(conf_data) - tensor_gt = (pos + neg).gt(0) - conf_p = conf_data.view(-1, self.num_classes) - targets_weighted = conf_t.view(-1) - loss_c = F.cross_entropy(conf_p, targets_weighted, reduction='none') - loss_c = loss_c[tensor_gt.view(-1) == True] - - if cfg.use_class_balanced_conf: - # Lazy initialization - if self.class_instances is None: - self.class_instances = torch.zeros(self.num_classes, device=targets_weighted.device) - - classes, counts = targets_weighted.unique(return_counts=True) - - for _cls, _cnt in zip(classes.cpu().numpy(), counts.cpu().numpy()): - self.class_instances[_cls] += _cnt - - self.total_instances += targets_weighted.size(0) - - weighting = 1 - (self.class_instances[targets_weighted] / self.total_instances) - weighting = torch.clamp(weighting, min=1/self.num_classes) - - # If you do the math, the average weight of self.class_instances is this - avg_weight = (self.num_classes - 1) / self.num_classes - - loss_c = (loss_c * weighting).sum() / avg_weight - else: - loss_c = loss_c.sum() - - return cfg.conf_alpha * loss_c - - def focal_conf_loss(self, conf_data, conf_t): - """ - Focal loss as described in https://arxiv.org/pdf/1708.02002.pdf - Adapted from https://github.com/clcarwin/focal_loss_pytorch/blob/master/focalloss.py - Note that this uses softmax and not the original sigmoid from the paper. - """ - conf_t = conf_t.view(-1) # [batch_size*num_priors] - conf_data = conf_data.view(-1, conf_data.size(-1)) # [batch_size*num_priors, num_classes] - - # Ignore neutral samples (class < 0) - keep = (conf_t >= 0).float() - conf_t[conf_t < 0] = 0 # so that gather doesn't drum up a fuss - - logpt = F.log_softmax(conf_data, dim=-1) - logpt = logpt.gather(1, conf_t.unsqueeze(-1)) - logpt = logpt.view(-1) - pt = logpt.exp() - - # I adapted the alpha_t calculation here from - # https://github.com/pytorch/pytorch/blob/master/modules/detectron/softmax_focal_loss_op.cu - # You'd think you want all the alphas to sum to one, but in the original implementation they - # just give background an alpha of 1-alpha and each forground an alpha of alpha. - background = (conf_t == 0).float() - at = (1 - cfg.focal_loss_alpha) * background + cfg.focal_loss_alpha * (1 - background) - - loss = -at * (1 - pt) ** cfg.focal_loss_gamma * logpt - - # See comment above for keep - return cfg.conf_alpha * (loss * keep).sum() - - def focal_conf_sigmoid_loss(self, conf_data, conf_t): - """ - Focal loss but using sigmoid like the original paper. - Note: To make things mesh easier, the network still predicts 81 class confidences in this mode. - Because retinanet originally only predicts 80, we simply just don't use conf_data[..., 0] - """ - num_classes = conf_data.size(-1) - - conf_t = conf_t.view(-1) # [batch_size*num_priors] - conf_data = conf_data.view(-1, num_classes) # [batch_size*num_priors, num_classes] - - # Ignore neutral samples (class < 0) - keep = (conf_t >= 0).float() - conf_t[conf_t < 0] = 0 # can't mask with -1, so filter that out - - # Compute a one-hot embedding of conf_t - # From https://github.com/kuangliu/pytorch-retinanet/blob/master/utils.py - conf_one_t = torch.eye(num_classes, device=conf_t.get_device())[conf_t] - conf_pm_t = conf_one_t * 2 - 1 # -1 if background, +1 if forground for specific class - - logpt = F.logsigmoid(conf_data * conf_pm_t) # note: 1 - sigmoid(x) = sigmoid(-x) - pt = logpt.exp() - - at = cfg.focal_loss_alpha * conf_one_t + (1 - cfg.focal_loss_alpha) * (1 - conf_one_t) - at[..., 0] = 0 # Set alpha for the background class to 0 because sigmoid focal loss doesn't use it - - loss = -at * (1 - pt) ** cfg.focal_loss_gamma * logpt - loss = keep * loss.sum(dim=-1) - - return cfg.conf_alpha * loss.sum() - - def focal_conf_objectness_loss(self, conf_data, conf_t): - """ - Instead of using softmax, use class[0] to be the objectness score and do sigmoid focal loss on that. - Then for the rest of the classes, softmax them and apply CE for only the positive examples. - - If class[0] = 1 implies forground and class[0] = 0 implies background then you achieve something - similar during test-time to softmax by setting class[1:] = softmax(class[1:]) * class[0] and invert class[0]. - """ - - conf_t = conf_t.view(-1) # [batch_size*num_priors] - conf_data = conf_data.view(-1, conf_data.size(-1)) # [batch_size*num_priors, num_classes] - - # Ignore neutral samples (class < 0) - keep = (conf_t >= 0).float() - conf_t[conf_t < 0] = 0 # so that gather doesn't drum up a fuss - - background = (conf_t == 0).float() - at = (1 - cfg.focal_loss_alpha) * background + cfg.focal_loss_alpha * (1 - background) - - logpt = F.logsigmoid(conf_data[:, 0]) * (1 - background) + F.logsigmoid(-conf_data[:, 0]) * background - pt = logpt.exp() - - obj_loss = -at * (1 - pt) ** cfg.focal_loss_gamma * logpt - - # All that was the objectiveness loss--now time for the class confidence loss - pos_mask = conf_t > 0 - conf_data_pos = (conf_data[:, 1:])[pos_mask] # Now this has just 80 classes - conf_t_pos = conf_t[pos_mask] - 1 # So subtract 1 here - - class_loss = F.cross_entropy(conf_data_pos, conf_t_pos, reduction='sum') - - return cfg.conf_alpha * (class_loss + (obj_loss * keep).sum()) - - def conf_objectness_loss(self, conf_data, conf_t, batch_size, loc_p, loc_t, priors): - """ - Instead of using softmax, use class[0] to be p(obj) * p(IoU) as in YOLO. - Then for the rest of the classes, softmax them and apply CE for only the positive examples. - """ - - conf_t = conf_t.view(-1) # [batch_size*num_priors] - conf_data = conf_data.view(-1, conf_data.size(-1)) # [batch_size*num_priors, num_classes] - - pos_mask = (conf_t > 0) - neg_mask = (conf_t == 0) - - obj_data = conf_data[:, 0] - obj_data_pos = obj_data[pos_mask] - obj_data_neg = obj_data[neg_mask] - - # Don't be confused, this is just binary cross entropy similified - obj_neg_loss = - F.logsigmoid(-obj_data_neg).sum() - - with torch.no_grad(): - pos_priors = priors.unsqueeze(0).expand(batch_size, -1, -1).reshape(-1, 4)[pos_mask, :] - - boxes_pred = decode(loc_p, pos_priors, cfg.use_yolo_regressors) - boxes_targ = decode(loc_t, pos_priors, cfg.use_yolo_regressors) - - iou_targets = elemwise_box_iou(boxes_pred, boxes_targ) - - obj_pos_loss = - iou_targets * F.logsigmoid(obj_data_pos) - (1 - iou_targets) * F.logsigmoid(-obj_data_pos) - obj_pos_loss = obj_pos_loss.sum() - - # All that was the objectiveness loss--now time for the class confidence loss - conf_data_pos = (conf_data[:, 1:])[pos_mask] # Now this has just 80 classes - conf_t_pos = conf_t[pos_mask] - 1 # So subtract 1 here - - class_loss = F.cross_entropy(conf_data_pos, conf_t_pos, reduction='sum') - - return cfg.conf_alpha * (class_loss + obj_pos_loss + obj_neg_loss) - - - def direct_mask_loss(self, pos_idx, idx_t, loc_data, mask_data, priors, masks): - """ Crops the gt masks using the predicted bboxes, scales them down, and outputs the BCE loss. """ - loss_m = 0 - for idx in range(mask_data.size(0)): - with torch.no_grad(): - cur_pos_idx = pos_idx[idx, :, :] - cur_pos_idx_squeezed = cur_pos_idx[:, 1] - - # Shape: [num_priors, 4], decoded predicted bboxes - pos_bboxes = decode(loc_data[idx, :, :], priors.data, cfg.use_yolo_regressors) - pos_bboxes = pos_bboxes[cur_pos_idx].view(-1, 4).clamp(0, 1) - pos_lookup = idx_t[idx, cur_pos_idx_squeezed] - - cur_masks = masks[idx] - pos_masks = cur_masks[pos_lookup, :, :] - - # Convert bboxes to absolute coordinates - num_pos, img_height, img_width = pos_masks.size() - - # Take care of all the bad behavior that can be caused by out of bounds coordinates - x1, x2 = sanitize_coordinates(pos_bboxes[:, 0], pos_bboxes[:, 2], img_width) - y1, y2 = sanitize_coordinates(pos_bboxes[:, 1], pos_bboxes[:, 3], img_height) - - # Crop each gt mask with the predicted bbox and rescale to the predicted mask size - # Note that each bounding box crop is a different size so I don't think we can vectorize this - scaled_masks = [] - for jdx in range(num_pos): - tmp_mask = pos_masks[jdx, y1[jdx]:y2[jdx], x1[jdx]:x2[jdx]] - - # Restore any dimensions we've left out because our bbox was 1px wide - while tmp_mask.dim() < 2: - tmp_mask = tmp_mask.unsqueeze(0) - - new_mask = F.adaptive_avg_pool2d(tmp_mask.unsqueeze(0), cfg.mask_size) - scaled_masks.append(new_mask.view(1, -1)) - - mask_t = torch.cat(scaled_masks, 0).gt(0.5).float() # Threshold downsampled mask - - pos_mask_data = mask_data[idx, cur_pos_idx_squeezed, :] - loss_m += F.binary_cross_entropy(torch.clamp(pos_mask_data, 0, 1), mask_t, reduction='sum') * cfg.mask_alpha - - return loss_m - - - def coeff_diversity_loss(self, coeffs, instance_t): - """ - coeffs should be size [num_pos, num_coeffs] - instance_t should be size [num_pos] and be values from 0 to num_instances-1 - """ - num_pos = coeffs.size(0) - instance_t = instance_t.view(-1) # juuuust to make sure - - coeffs_norm = F.normalize(coeffs, dim=1) - cos_sim = coeffs_norm @ coeffs_norm.t() - - inst_eq = (instance_t[:, None].expand_as(cos_sim) == instance_t[None, :].expand_as(cos_sim)).float() - - # Rescale to be between 0 and 1 - cos_sim = (cos_sim + 1) / 2 - - # If they're the same instance, use cosine distance, else use cosine similarity - loss = (1 - cos_sim) * inst_eq + cos_sim * (1 - inst_eq) - - # Only divide by num_pos once because we're summing over a num_pos x num_pos tensor - # and all the losses will be divided by num_pos at the end, so just one extra time. - return cfg.mask_proto_coeff_diversity_alpha * loss.sum() / num_pos - - - def lincomb_mask_loss(self, pos, idx_t, loc_data, mask_data, priors, proto_data, masks, gt_box_t, score_data, inst_data, labels, interpolation_mode='bilinear'): - mask_h = proto_data.size(1) - mask_w = proto_data.size(2) - - process_gt_bboxes = cfg.mask_proto_normalize_emulate_roi_pooling or cfg.mask_proto_crop - - if cfg.mask_proto_remove_empty_masks: - # Make sure to store a copy of this because we edit it to get rid of all-zero masks - pos = pos.clone() - - loss_m = 0 - loss_d = 0 # Coefficient diversity loss - - maskiou_t_list = [] - maskiou_net_input_list = [] - label_t_list = [] - - for idx in range(mask_data.size(0)): - with torch.no_grad(): - downsampled_masks = F.interpolate(masks[idx].unsqueeze(0), (mask_h, mask_w), - mode=interpolation_mode, align_corners=False).squeeze(0) - downsampled_masks = downsampled_masks.permute(1, 2, 0).contiguous() - - if cfg.mask_proto_binarize_downsampled_gt: - downsampled_masks = downsampled_masks.gt(0.5).float() - - if cfg.mask_proto_remove_empty_masks: - # Get rid of gt masks that are so small they get downsampled away - very_small_masks = (downsampled_masks.sum(dim=(0,1)) <= 0.0001) - for i in range(very_small_masks.size(0)): - if very_small_masks[i]: - pos[idx, idx_t[idx] == i] = 0 - - if cfg.mask_proto_reweight_mask_loss: - # Ensure that the gt is binary - if not cfg.mask_proto_binarize_downsampled_gt: - bin_gt = downsampled_masks.gt(0.5).float() - else: - bin_gt = downsampled_masks - - gt_foreground_norm = bin_gt / (torch.sum(bin_gt, dim=(0,1), keepdim=True) + 0.0001) - gt_background_norm = (1-bin_gt) / (torch.sum(1-bin_gt, dim=(0,1), keepdim=True) + 0.0001) - - mask_reweighting = gt_foreground_norm * cfg.mask_proto_reweight_coeff + gt_background_norm - mask_reweighting *= mask_h * mask_w - - cur_pos = pos[idx] - pos_idx_t = idx_t[idx, cur_pos] - - if process_gt_bboxes: - # Note: this is in point-form - if cfg.mask_proto_crop_with_pred_box: - pos_gt_box_t = decode(loc_data[idx, :, :], priors.data, cfg.use_yolo_regressors)[cur_pos] - else: - pos_gt_box_t = gt_box_t[idx, cur_pos] - - if pos_idx_t.size(0) == 0: - continue - - proto_masks = proto_data[idx] - proto_coef = mask_data[idx, cur_pos, :] - if cfg.use_mask_scoring: - mask_scores = score_data[idx, cur_pos, :] - - if cfg.mask_proto_coeff_diversity_loss: - if inst_data is not None: - div_coeffs = inst_data[idx, cur_pos, :] - else: - div_coeffs = proto_coef - - loss_d += self.coeff_diversity_loss(div_coeffs, pos_idx_t) - - # If we have over the allowed number of masks, select a random sample - old_num_pos = proto_coef.size(0) - if old_num_pos > cfg.masks_to_train: - perm = torch.randperm(proto_coef.size(0)) - select = perm[:cfg.masks_to_train] - - proto_coef = proto_coef[select, :] - pos_idx_t = pos_idx_t[select] - - if process_gt_bboxes: - pos_gt_box_t = pos_gt_box_t[select, :] - if cfg.use_mask_scoring: - mask_scores = mask_scores[select, :] - - num_pos = proto_coef.size(0) - mask_t = downsampled_masks[:, :, pos_idx_t] - label_t = labels[idx][pos_idx_t] - - # Size: [mask_h, mask_w, num_pos] - #pred_masks = proto_masks @ proto_coef.t() - pred_masks = torch.matmul(proto_masks, proto_coef.T) - pred_masks = cfg.mask_proto_mask_activation(pred_masks) - - if cfg.mask_proto_double_loss: - if cfg.mask_proto_mask_activation == activation_func.sigmoid: - pre_loss = F.binary_cross_entropy(torch.clamp(pred_masks, 0, 1), mask_t, reduction='sum') - else: - pre_loss = F.smooth_l1_loss(pred_masks, mask_t, reduction='sum') - - loss_m += cfg.mask_proto_double_loss_alpha * pre_loss - - if cfg.mask_proto_crop: - pred_masks = crop(pred_masks, pos_gt_box_t) - - if cfg.mask_proto_mask_activation == activation_func.sigmoid: - pre_loss = F.binary_cross_entropy(torch.clamp(pred_masks, 0, 1), mask_t, reduction='none') - else: - pre_loss = F.smooth_l1_loss(pred_masks, mask_t, reduction='none') - - if cfg.mask_proto_normalize_mask_loss_by_sqrt_area: - gt_area = torch.sum(mask_t, dim=(0, 1), keepdim=True) - pre_loss = pre_loss / (torch.sqrt(gt_area) + 0.0001) - - if cfg.mask_proto_reweight_mask_loss: - pre_loss = pre_loss * mask_reweighting[:, :, pos_idx_t] - - if cfg.mask_proto_normalize_emulate_roi_pooling: - weight = mask_h * mask_w if cfg.mask_proto_crop else 1 - pos_gt_csize = center_size(pos_gt_box_t) - gt_box_width = pos_gt_csize[:, 2] * mask_w - gt_box_height = pos_gt_csize[:, 3] * mask_h - pre_loss = pre_loss.sum(dim=(0, 1)) / gt_box_width / gt_box_height * weight - - # If the number of masks were limited scale the loss accordingly - if old_num_pos > num_pos: - pre_loss *= old_num_pos / num_pos - - loss_m += torch.sum(pre_loss) - - if cfg.use_maskiou: - if cfg.discard_mask_area > 0: - gt_mask_area = torch.sum(mask_t, dim=(0, 1)) - select = gt_mask_area > cfg.discard_mask_area - - if torch.sum(select) < 1: - continue - - pos_gt_box_t = pos_gt_box_t[select, :] - pred_masks = pred_masks[:, :, select] - mask_t = mask_t[:, :, select] - label_t = label_t[select] - - maskiou_net_input = pred_masks.permute(2, 0, 1).contiguous().unsqueeze(1) - pred_masks = pred_masks.gt(0.5).float() - maskiou_t = self._mask_iou(pred_masks, mask_t) - - maskiou_net_input_list.append(maskiou_net_input) - maskiou_t_list.append(maskiou_t) - label_t_list.append(label_t) - - losses = {'M': loss_m * cfg.mask_alpha / mask_h / mask_w} - - if cfg.mask_proto_coeff_diversity_loss: - losses['D'] = loss_d - - if cfg.use_maskiou: - # discard_mask_area discarded every mask in the batch, so nothing to do here - if len(maskiou_t_list) == 0: - return losses, None - - maskiou_t = torch.cat(maskiou_t_list) - label_t = torch.cat(label_t_list) - maskiou_net_input = torch.cat(maskiou_net_input_list) - - num_samples = maskiou_t.size(0) - if cfg.maskious_to_train > 0 and num_samples > cfg.maskious_to_train: - perm = torch.randperm(num_samples) - select = perm[:cfg.masks_to_train] - maskiou_t = maskiou_t[select] - label_t = label_t[select] - maskiou_net_input = maskiou_net_input[select] - - return losses, [maskiou_net_input, maskiou_t, label_t] - - return losses - - def _mask_iou(self, mask1, mask2): - intersection = torch.sum(mask1*mask2, dim=(0, 1)) - area1 = torch.sum(mask1, dim=(0, 1)) - area2 = torch.sum(mask2, dim=(0, 1)) - union = (area1 + area2) - intersection - ret = intersection / union - return ret - - def mask_iou_loss(self, net, maskiou_targets): - maskiou_net_input, maskiou_t, label_t = maskiou_targets - - maskiou_p = net.maskiou_net(maskiou_net_input) - - label_t = label_t[:, None] - maskiou_p = torch.gather(maskiou_p, dim=1, index=label_t).view(-1) - - loss_i = F.smooth_l1_loss(maskiou_p, maskiou_t, reduction='sum') - - return loss_i * cfg.maskiou_alpha +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +# -*- coding: utf-8 -*- +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.autograd import Variable +from ..box_utils import match, log_sum_exp, decode, center_size, crop, elemwise_mask_iou, elemwise_box_iou + +from data import cfg, mask_type, activation_func + +class MultiBoxLoss(nn.Module): + """SSD Weighted Loss Function + Compute Targets: + 1) Produce Confidence Target Indices by matching ground truth boxes + with (default) 'priorboxes' that have jaccard index > threshold parameter + (default threshold: 0.5). + + 2) Produce localization target by 'encoding' variance into offsets of ground + truth boxes and their matched 'priorboxes'. + + 3) Hard negative mining to filter the excessive number of negative examples + that comes with using a large number of default bounding boxes. + (default negative:positive ratio 3:1) + + Objective Loss: + L(x,c,l,g) = (Lconf(x, c) + αLloc(x,l,g)) / N + Where, Lconf is the CrossEntropy Loss and Lloc is the SmoothL1 Loss + weighted by α which is set to 1 by cross val. + Args: + c: class confidences, + l: predicted boxes, + g: ground truth boxes + N: number of matched default boxes + See: https://arxiv.org/pdf/1512.02325.pdf for more details. + """ + + def __init__(self, num_classes, pos_threshold, neg_threshold, negpos_ratio): + super(MultiBoxLoss, self).__init__() + self.num_classes = num_classes + + self.pos_threshold = pos_threshold + self.neg_threshold = neg_threshold + self.negpos_ratio = negpos_ratio + + # If you output a proto mask with this area, your l1 loss will be l1_alpha + # Note that the area is relative (so 1 would be the entire image) + self.l1_expected_area = 20*20/70/70 + self.l1_alpha = 0.1 + + if cfg.use_class_balanced_conf: + self.class_instances = None + self.total_instances = 0 + + def forward(self, net, predictions, wrapper, wrapper_mask): + """Multibox Loss + Args: + predictions (tuple): A tuple containing loc preds, conf preds, + mask preds, and prior boxes from SSD net. + loc shape: torch.size(batch_size,num_priors,4) + conf shape: torch.size(batch_size,num_priors,num_classes) + masks shape: torch.size(batch_size,num_priors,mask_dim) + priors shape: torch.size(num_priors,4) + proto* shape: torch.size(batch_size,mask_h,mask_w,mask_dim) + + targets (list): Ground truth boxes and labels for a batch, + shape: [batch_size][num_objs,5] (last idx is the label). + + masks (list): Ground truth masks for each object in each image, + shape: [batch_size][num_objs,im_height,im_width] + + num_crowds (list): Number of crowd annotations per batch. The crowd + annotations should be the last num_crowds elements of targets and masks. + + * Only if mask_type == lincomb + """ + + targets, masks, num_crowds = wrapper.get_args(wrapper_mask) + targets = targets[0] + masks = masks[0] + num_crowds = num_crowds[0] + loc_data = predictions['loc'] + conf_data = predictions['conf'] + mask_data = predictions['mask'] + priors = predictions['priors'] + + if cfg.mask_type == mask_type.lincomb: + proto_data = predictions['proto'] + + score_data = predictions['score'] if cfg.use_mask_scoring else None + inst_data = predictions['inst'] if cfg.use_instance_coeff else None + + labels = [None] * len(targets) # Used in sem segm loss + + batch_size = loc_data.size(0) + num_priors = priors.size(0) + num_classes = self.num_classes + + # Match priors (default boxes) and ground truth boxes + # These tensors will be created with the same device as loc_data + loc_t = loc_data.new(batch_size, num_priors, 4) + gt_box_t = loc_data.new(batch_size, num_priors, 4) + conf_t = loc_data.new(batch_size, num_priors).long() + idx_t = loc_data.new(batch_size, num_priors).long() + + if cfg.use_class_existence_loss: + class_existence_t = loc_data.new(batch_size, num_classes-1) + + for idx in range(batch_size): + truths = targets[idx][:, :-1].data + labels[idx] = targets[idx][:, -1].data.long() + + if cfg.use_class_existence_loss: + # Construct a one-hot vector for each object and collapse it into an existence vector with max + # Also it's fine to include the crowd annotations here + class_existence_t[idx, :] = torch.eye(num_classes-1, device=conf_t.get_device())[labels[idx]].max(dim=0)[0] + + # Split the crowd annotations because they come bundled in + cur_crowds = num_crowds[idx] + if cur_crowds > 0: + split = lambda x: (x[-cur_crowds:], x[:-cur_crowds]) + crowd_boxes, truths = split(truths) + + # We don't use the crowd labels or masks + _, labels[idx] = split(labels[idx]) + _, masks[idx] = split(masks[idx]) + else: + crowd_boxes = None + + + match(self.pos_threshold, self.neg_threshold, + truths, priors.data, labels[idx], crowd_boxes, + loc_t, conf_t, idx_t, idx, loc_data[idx]) + + gt_box_t[idx, :, :] = truths[idx_t[idx]] + + # wrap targets + loc_t = Variable(loc_t, requires_grad=False) + conf_t = Variable(conf_t, requires_grad=False) + idx_t = Variable(idx_t, requires_grad=False) + + pos = conf_t > 0 + num_pos = pos.sum(dim=1, keepdim=True) + + # Shape: [batch,num_priors,4] + pos_idx = pos.unsqueeze(pos.dim()).expand_as(loc_data) + + losses = {} + + # Localization Loss (Smooth L1) + if cfg.train_boxes: + loc_p = loc_data.view(-1, 4) + loc_t = loc_t.view(-1, 4) + losses['B'] = F.smooth_l1_loss(loc_p, loc_t, reduction='none') * cfg.bbox_alpha + losses['B'][pos_idx.view(-1, 4) == False] = 0 + losses['B'] = losses['B'].sum() + + if cfg.train_masks: + if cfg.mask_type == mask_type.direct: + if cfg.use_gt_bboxes: + pos_masks = [] + for idx in range(batch_size): + pos_masks.append(masks[idx][idx_t[idx, pos[idx]]]) + masks_t = torch.cat(pos_masks, 0) + masks_p = mask_data[pos, :].view(-1, cfg.mask_dim) + losses['M'] = F.binary_cross_entropy(torch.clamp(masks_p, 0, 1), masks_t, reduction='sum') * cfg.mask_alpha + else: + losses['M'] = self.direct_mask_loss(pos_idx, idx_t, loc_data, mask_data, priors, masks) + elif cfg.mask_type == mask_type.lincomb: + ret = self.lincomb_mask_loss(pos, idx_t, loc_data, mask_data, priors, proto_data, masks, gt_box_t, score_data, inst_data, labels) + if cfg.use_maskiou: + loss, maskiou_targets = ret + else: + loss = ret + losses.update(loss) + + if cfg.mask_proto_loss is not None: + if cfg.mask_proto_loss == 'l1': + losses['P'] = torch.mean(torch.abs(proto_data)) / self.l1_expected_area * self.l1_alpha + elif cfg.mask_proto_loss == 'disj': + losses['P'] = -torch.mean(torch.max(F.log_softmax(proto_data, dim=-1), dim=-1)[0]) + + # Confidence loss + if cfg.use_focal_loss: + if cfg.use_sigmoid_focal_loss: + losses['C'] = self.focal_conf_sigmoid_loss(conf_data, conf_t) + elif cfg.use_objectness_score: + losses['C'] = self.focal_conf_objectness_loss(conf_data, conf_t) + else: + losses['C'] = self.focal_conf_loss(conf_data, conf_t) + else: + if cfg.use_objectness_score: + losses['C'] = self.conf_objectness_loss(conf_data, conf_t, batch_size, loc_p, loc_t, priors) + else: + losses['C'] = self.ohem_conf_loss(conf_data, conf_t, pos, batch_size) + + # Mask IoU Loss + if cfg.use_maskiou and maskiou_targets is not None: + losses['I'] = self.mask_iou_loss(net, maskiou_targets) + + # These losses also don't depend on anchors + if cfg.use_class_existence_loss: + losses['E'] = self.class_existence_loss(predictions['classes'], class_existence_t) + if cfg.use_semantic_segmentation_loss: + losses['S'] = self.semantic_segmentation_loss(predictions['segm'], masks, labels) + + # Divide all losses by the number of positives. + # Don't do it for loss[P] because that doesn't depend on the anchors. + total_num_pos = num_pos.data.sum().float() + for k in losses: + if k not in ('P', 'E', 'S'): + losses[k] /= total_num_pos + else: + losses[k] /= batch_size + + # Loss Key: + # - B: Box Localization Loss + # - C: Class Confidence Loss + # - M: Mask Loss + # - P: Prototype Loss + # - D: Coefficient Diversity Loss + # - E: Class Existence Loss + # - S: Semantic Segmentation Loss + return losses + + def class_existence_loss(self, class_data, class_existence_t): + return cfg.class_existence_alpha * F.binary_cross_entropy_with_logits(class_data, class_existence_t, reduction='sum') + + def semantic_segmentation_loss(self, segment_data, mask_t, class_t, interpolation_mode='bilinear'): + # Note num_classes here is without the background class so cfg.num_classes-1 + batch_size, num_classes, mask_h, mask_w = segment_data.size() + loss_s = 0 + + for idx in range(batch_size): + cur_segment = segment_data[idx] + cur_class_t = class_t[idx] + + with torch.no_grad(): + downsampled_masks = F.interpolate(mask_t[idx].unsqueeze(0), (mask_h, mask_w), + mode=interpolation_mode, align_corners=False).squeeze(0) + downsampled_masks = downsampled_masks.gt(0.5).float() + + # Construct Semantic Segmentation + segment_t = torch.zeros_like(cur_segment, requires_grad=False) + for obj_idx in range(downsampled_masks.size(0)): + segment_t[cur_class_t[obj_idx]] = torch.max(segment_t[cur_class_t[obj_idx]].float(), downsampled_masks[obj_idx]) + + loss_s += F.binary_cross_entropy_with_logits(cur_segment, segment_t, reduction='sum') + + return loss_s / mask_h / mask_w * cfg.semantic_segmentation_alpha + + + def ohem_conf_loss(self, conf_data, conf_t, pos, num): + # Compute max conf across batch for hard negative mining + batch_conf = conf_data.view(-1, self.num_classes) + if cfg.ohem_use_most_confident: + # i.e. max(softmax) along classes > 0 + batch_conf = F.softmax(batch_conf, dim=1) + loss_c, _ = batch_conf[:, 1:].max(dim=1) + else: + # i.e. -softmax(class 0 confidence) + loss_c = log_sum_exp(batch_conf) - batch_conf[:, 0] + + # Hard Negative Mining + loss_c = loss_c.view(num, -1) + loss_c[pos] = 0 # filter out pos boxes + loss_c[conf_t < 0] = 0 # filter out neutrals (conf_t = -1) + _, loss_idx = loss_c.sort(1, descending=True) + _, idx_rank = loss_idx.sort(1) + num_pos = pos.long().sum(1, keepdim=True) + num_neg = torch.clamp(self.negpos_ratio*num_pos, max=pos.size(1)-1) + neg = idx_rank < num_neg.expand_as(idx_rank) + + # Just in case there aren't enough negatives, don't start using positives as negatives + neg[pos] = 0 + neg[conf_t < 0] = 0 # Filter out neutrals + + # Confidence Loss Including Positive and Negative Examples + pos_idx = pos.unsqueeze(2).expand_as(conf_data) + neg_idx = neg.unsqueeze(2).expand_as(conf_data) + tensor_gt = (pos + neg).gt(0) + conf_p = conf_data.view(-1, self.num_classes) + targets_weighted = conf_t.view(-1) + loss_c = F.cross_entropy(conf_p, targets_weighted, reduction='none') + loss_c = loss_c[tensor_gt.view(-1) == True] + + if cfg.use_class_balanced_conf: + # Lazy initialization + if self.class_instances is None: + self.class_instances = torch.zeros(self.num_classes, device=targets_weighted.device) + + classes, counts = targets_weighted.unique(return_counts=True) + + for _cls, _cnt in zip(classes.cpu().numpy(), counts.cpu().numpy()): + self.class_instances[_cls] += _cnt + + self.total_instances += targets_weighted.size(0) + + weighting = 1 - (self.class_instances[targets_weighted] / self.total_instances) + weighting = torch.clamp(weighting, min=1/self.num_classes) + + # If you do the math, the average weight of self.class_instances is this + avg_weight = (self.num_classes - 1) / self.num_classes + + loss_c = (loss_c * weighting).sum() / avg_weight + else: + loss_c = loss_c.sum() + + return cfg.conf_alpha * loss_c + + def focal_conf_loss(self, conf_data, conf_t): + """ + Focal loss as described in https://arxiv.org/pdf/1708.02002.pdf + Adapted from https://github.com/clcarwin/focal_loss_pytorch/blob/master/focalloss.py + Note that this uses softmax and not the original sigmoid from the paper. + """ + conf_t = conf_t.view(-1) # [batch_size*num_priors] + conf_data = conf_data.view(-1, conf_data.size(-1)) # [batch_size*num_priors, num_classes] + + # Ignore neutral samples (class < 0) + keep = (conf_t >= 0).float() + conf_t[conf_t < 0] = 0 # so that gather doesn't drum up a fuss + + logpt = F.log_softmax(conf_data, dim=-1) + logpt = logpt.gather(1, conf_t.unsqueeze(-1)) + logpt = logpt.view(-1) + pt = logpt.exp() + + # I adapted the alpha_t calculation here from + # https://github.com/pytorch/pytorch/blob/master/modules/detectron/softmax_focal_loss_op.cu + # You'd think you want all the alphas to sum to one, but in the original implementation they + # just give background an alpha of 1-alpha and each forground an alpha of alpha. + background = (conf_t == 0).float() + at = (1 - cfg.focal_loss_alpha) * background + cfg.focal_loss_alpha * (1 - background) + + loss = -at * (1 - pt) ** cfg.focal_loss_gamma * logpt + + # See comment above for keep + return cfg.conf_alpha * (loss * keep).sum() + + def focal_conf_sigmoid_loss(self, conf_data, conf_t): + """ + Focal loss but using sigmoid like the original paper. + Note: To make things mesh easier, the network still predicts 81 class confidences in this mode. + Because retinanet originally only predicts 80, we simply just don't use conf_data[..., 0] + """ + num_classes = conf_data.size(-1) + + conf_t = conf_t.view(-1) # [batch_size*num_priors] + conf_data = conf_data.view(-1, num_classes) # [batch_size*num_priors, num_classes] + + # Ignore neutral samples (class < 0) + keep = (conf_t >= 0).float() + conf_t[conf_t < 0] = 0 # can't mask with -1, so filter that out + + # Compute a one-hot embedding of conf_t + # From https://github.com/kuangliu/pytorch-retinanet/blob/master/utils.py + conf_one_t = torch.eye(num_classes, device=conf_t.get_device())[conf_t] + conf_pm_t = conf_one_t * 2 - 1 # -1 if background, +1 if forground for specific class + + logpt = F.logsigmoid(conf_data * conf_pm_t) # note: 1 - sigmoid(x) = sigmoid(-x) + pt = logpt.exp() + + at = cfg.focal_loss_alpha * conf_one_t + (1 - cfg.focal_loss_alpha) * (1 - conf_one_t) + at[..., 0] = 0 # Set alpha for the background class to 0 because sigmoid focal loss doesn't use it + + loss = -at * (1 - pt) ** cfg.focal_loss_gamma * logpt + loss = keep * loss.sum(dim=-1) + + return cfg.conf_alpha * loss.sum() + + def focal_conf_objectness_loss(self, conf_data, conf_t): + """ + Instead of using softmax, use class[0] to be the objectness score and do sigmoid focal loss on that. + Then for the rest of the classes, softmax them and apply CE for only the positive examples. + + If class[0] = 1 implies forground and class[0] = 0 implies background then you achieve something + similar during test-time to softmax by setting class[1:] = softmax(class[1:]) * class[0] and invert class[0]. + """ + + conf_t = conf_t.view(-1) # [batch_size*num_priors] + conf_data = conf_data.view(-1, conf_data.size(-1)) # [batch_size*num_priors, num_classes] + + # Ignore neutral samples (class < 0) + keep = (conf_t >= 0).float() + conf_t[conf_t < 0] = 0 # so that gather doesn't drum up a fuss + + background = (conf_t == 0).float() + at = (1 - cfg.focal_loss_alpha) * background + cfg.focal_loss_alpha * (1 - background) + + logpt = F.logsigmoid(conf_data[:, 0]) * (1 - background) + F.logsigmoid(-conf_data[:, 0]) * background + pt = logpt.exp() + + obj_loss = -at * (1 - pt) ** cfg.focal_loss_gamma * logpt + + # All that was the objectiveness loss--now time for the class confidence loss + pos_mask = conf_t > 0 + conf_data_pos = (conf_data[:, 1:])[pos_mask] # Now this has just 80 classes + conf_t_pos = conf_t[pos_mask] - 1 # So subtract 1 here + + class_loss = F.cross_entropy(conf_data_pos, conf_t_pos, reduction='sum') + + return cfg.conf_alpha * (class_loss + (obj_loss * keep).sum()) + + def conf_objectness_loss(self, conf_data, conf_t, batch_size, loc_p, loc_t, priors): + """ + Instead of using softmax, use class[0] to be p(obj) * p(IoU) as in YOLO. + Then for the rest of the classes, softmax them and apply CE for only the positive examples. + """ + + conf_t = conf_t.view(-1) # [batch_size*num_priors] + conf_data = conf_data.view(-1, conf_data.size(-1)) # [batch_size*num_priors, num_classes] + + pos_mask = (conf_t > 0) + neg_mask = (conf_t == 0) + + obj_data = conf_data[:, 0] + obj_data_pos = obj_data[pos_mask] + obj_data_neg = obj_data[neg_mask] + + # Don't be confused, this is just binary cross entropy similified + obj_neg_loss = - F.logsigmoid(-obj_data_neg).sum() + + with torch.no_grad(): + pos_priors = priors.unsqueeze(0).expand(batch_size, -1, -1).reshape(-1, 4)[pos_mask, :] + + boxes_pred = decode(loc_p, pos_priors, cfg.use_yolo_regressors) + boxes_targ = decode(loc_t, pos_priors, cfg.use_yolo_regressors) + + iou_targets = elemwise_box_iou(boxes_pred, boxes_targ) + + obj_pos_loss = - iou_targets * F.logsigmoid(obj_data_pos) - (1 - iou_targets) * F.logsigmoid(-obj_data_pos) + obj_pos_loss = obj_pos_loss.sum() + + # All that was the objectiveness loss--now time for the class confidence loss + conf_data_pos = (conf_data[:, 1:])[pos_mask] # Now this has just 80 classes + conf_t_pos = conf_t[pos_mask] - 1 # So subtract 1 here + + class_loss = F.cross_entropy(conf_data_pos, conf_t_pos, reduction='sum') + + return cfg.conf_alpha * (class_loss + obj_pos_loss + obj_neg_loss) + + + def direct_mask_loss(self, pos_idx, idx_t, loc_data, mask_data, priors, masks): + """ Crops the gt masks using the predicted bboxes, scales them down, and outputs the BCE loss. """ + loss_m = 0 + for idx in range(mask_data.size(0)): + with torch.no_grad(): + cur_pos_idx = pos_idx[idx, :, :] + cur_pos_idx_squeezed = cur_pos_idx[:, 1] + + # Shape: [num_priors, 4], decoded predicted bboxes + pos_bboxes = decode(loc_data[idx, :, :], priors.data, cfg.use_yolo_regressors) + pos_bboxes = pos_bboxes[cur_pos_idx].view(-1, 4).clamp(0, 1) + pos_lookup = idx_t[idx, cur_pos_idx_squeezed] + + cur_masks = masks[idx] + pos_masks = cur_masks[pos_lookup, :, :] + + # Convert bboxes to absolute coordinates + num_pos, img_height, img_width = pos_masks.size() + + # Take care of all the bad behavior that can be caused by out of bounds coordinates + x1, x2 = sanitize_coordinates(pos_bboxes[:, 0], pos_bboxes[:, 2], img_width) + y1, y2 = sanitize_coordinates(pos_bboxes[:, 1], pos_bboxes[:, 3], img_height) + + # Crop each gt mask with the predicted bbox and rescale to the predicted mask size + # Note that each bounding box crop is a different size so I don't think we can vectorize this + scaled_masks = [] + for jdx in range(num_pos): + tmp_mask = pos_masks[jdx, y1[jdx]:y2[jdx], x1[jdx]:x2[jdx]] + + # Restore any dimensions we've left out because our bbox was 1px wide + while tmp_mask.dim() < 2: + tmp_mask = tmp_mask.unsqueeze(0) + + new_mask = F.adaptive_avg_pool2d(tmp_mask.unsqueeze(0), cfg.mask_size) + scaled_masks.append(new_mask.view(1, -1)) + + mask_t = torch.cat(scaled_masks, 0).gt(0.5).float() # Threshold downsampled mask + + pos_mask_data = mask_data[idx, cur_pos_idx_squeezed, :] + loss_m += F.binary_cross_entropy(torch.clamp(pos_mask_data, 0, 1), mask_t, reduction='sum') * cfg.mask_alpha + + return loss_m + + + def coeff_diversity_loss(self, coeffs, instance_t): + """ + coeffs should be size [num_pos, num_coeffs] + instance_t should be size [num_pos] and be values from 0 to num_instances-1 + """ + num_pos = coeffs.size(0) + instance_t = instance_t.view(-1) # juuuust to make sure + + coeffs_norm = F.normalize(coeffs, dim=1) + cos_sim = coeffs_norm @ coeffs_norm.t() + + inst_eq = (instance_t[:, None].expand_as(cos_sim) == instance_t[None, :].expand_as(cos_sim)).float() + + # Rescale to be between 0 and 1 + cos_sim = (cos_sim + 1) / 2 + + # If they're the same instance, use cosine distance, else use cosine similarity + loss = (1 - cos_sim) * inst_eq + cos_sim * (1 - inst_eq) + + # Only divide by num_pos once because we're summing over a num_pos x num_pos tensor + # and all the losses will be divided by num_pos at the end, so just one extra time. + return cfg.mask_proto_coeff_diversity_alpha * loss.sum() / num_pos + + + def lincomb_mask_loss(self, pos, idx_t, loc_data, mask_data, priors, proto_data, masks, gt_box_t, score_data, inst_data, labels, interpolation_mode='bilinear'): + mask_h = proto_data.size(1) + mask_w = proto_data.size(2) + + process_gt_bboxes = cfg.mask_proto_normalize_emulate_roi_pooling or cfg.mask_proto_crop + + if cfg.mask_proto_remove_empty_masks: + # Make sure to store a copy of this because we edit it to get rid of all-zero masks + pos = pos.clone() + + loss_m = 0 + loss_d = 0 # Coefficient diversity loss + + maskiou_t_list = [] + maskiou_net_input_list = [] + label_t_list = [] + + for idx in range(mask_data.size(0)): + with torch.no_grad(): + downsampled_masks = F.interpolate(masks[idx].unsqueeze(0), (mask_h, mask_w), + mode=interpolation_mode, align_corners=False).squeeze(0) + downsampled_masks = downsampled_masks.permute(1, 2, 0).contiguous() + + if cfg.mask_proto_binarize_downsampled_gt: + downsampled_masks = downsampled_masks.gt(0.5).float() + + if cfg.mask_proto_remove_empty_masks: + # Get rid of gt masks that are so small they get downsampled away + very_small_masks = (downsampled_masks.sum(dim=(0,1)) <= 0.0001) + for i in range(very_small_masks.size(0)): + if very_small_masks[i]: + pos[idx, idx_t[idx] == i] = 0 + + if cfg.mask_proto_reweight_mask_loss: + # Ensure that the gt is binary + if not cfg.mask_proto_binarize_downsampled_gt: + bin_gt = downsampled_masks.gt(0.5).float() + else: + bin_gt = downsampled_masks + + gt_foreground_norm = bin_gt / (torch.sum(bin_gt, dim=(0,1), keepdim=True) + 0.0001) + gt_background_norm = (1-bin_gt) / (torch.sum(1-bin_gt, dim=(0,1), keepdim=True) + 0.0001) + + mask_reweighting = gt_foreground_norm * cfg.mask_proto_reweight_coeff + gt_background_norm + mask_reweighting *= mask_h * mask_w + + cur_pos = pos[idx] + pos_idx_t = idx_t[idx, cur_pos] + + if process_gt_bboxes: + # Note: this is in point-form + if cfg.mask_proto_crop_with_pred_box: + pos_gt_box_t = decode(loc_data[idx, :, :], priors.data, cfg.use_yolo_regressors)[cur_pos] + else: + pos_gt_box_t = gt_box_t[idx, cur_pos] + + if pos_idx_t.size(0) == 0: + continue + + proto_masks = proto_data[idx] + proto_coef = mask_data[idx, cur_pos, :] + if cfg.use_mask_scoring: + mask_scores = score_data[idx, cur_pos, :] + + if cfg.mask_proto_coeff_diversity_loss: + if inst_data is not None: + div_coeffs = inst_data[idx, cur_pos, :] + else: + div_coeffs = proto_coef + + loss_d += self.coeff_diversity_loss(div_coeffs, pos_idx_t) + + # If we have over the allowed number of masks, select a random sample + old_num_pos = proto_coef.size(0) + if old_num_pos > cfg.masks_to_train: + perm = torch.randperm(proto_coef.size(0)) + select = perm[:cfg.masks_to_train] + + proto_coef = proto_coef[select, :] + pos_idx_t = pos_idx_t[select] + + if process_gt_bboxes: + pos_gt_box_t = pos_gt_box_t[select, :] + if cfg.use_mask_scoring: + mask_scores = mask_scores[select, :] + + num_pos = proto_coef.size(0) + mask_t = downsampled_masks[:, :, pos_idx_t] + label_t = labels[idx][pos_idx_t] + + # Size: [mask_h, mask_w, num_pos] + #pred_masks = proto_masks @ proto_coef.t() + pred_masks = torch.matmul(proto_masks, proto_coef.T) + pred_masks = cfg.mask_proto_mask_activation(pred_masks) + + if cfg.mask_proto_double_loss: + if cfg.mask_proto_mask_activation == activation_func.sigmoid: + pre_loss = F.binary_cross_entropy(torch.clamp(pred_masks, 0, 1), mask_t, reduction='sum') + else: + pre_loss = F.smooth_l1_loss(pred_masks, mask_t, reduction='sum') + + loss_m += cfg.mask_proto_double_loss_alpha * pre_loss + + if cfg.mask_proto_crop: + pred_masks = crop(pred_masks, pos_gt_box_t) + + if cfg.mask_proto_mask_activation == activation_func.sigmoid: + pre_loss = F.binary_cross_entropy(torch.clamp(pred_masks, 0, 1), mask_t, reduction='none') + else: + pre_loss = F.smooth_l1_loss(pred_masks, mask_t, reduction='none') + + if cfg.mask_proto_normalize_mask_loss_by_sqrt_area: + gt_area = torch.sum(mask_t, dim=(0, 1), keepdim=True) + pre_loss = pre_loss / (torch.sqrt(gt_area) + 0.0001) + + if cfg.mask_proto_reweight_mask_loss: + pre_loss = pre_loss * mask_reweighting[:, :, pos_idx_t] + + if cfg.mask_proto_normalize_emulate_roi_pooling: + weight = mask_h * mask_w if cfg.mask_proto_crop else 1 + pos_gt_csize = center_size(pos_gt_box_t) + gt_box_width = pos_gt_csize[:, 2] * mask_w + gt_box_height = pos_gt_csize[:, 3] * mask_h + pre_loss = pre_loss.sum(dim=(0, 1)) / gt_box_width / gt_box_height * weight + + # If the number of masks were limited scale the loss accordingly + if old_num_pos > num_pos: + pre_loss *= old_num_pos / num_pos + + loss_m += torch.sum(pre_loss) + + if cfg.use_maskiou: + if cfg.discard_mask_area > 0: + gt_mask_area = torch.sum(mask_t, dim=(0, 1)) + select = gt_mask_area > cfg.discard_mask_area + + if torch.sum(select) < 1: + continue + + pos_gt_box_t = pos_gt_box_t[select, :] + pred_masks = pred_masks[:, :, select] + mask_t = mask_t[:, :, select] + label_t = label_t[select] + + maskiou_net_input = pred_masks.permute(2, 0, 1).contiguous().unsqueeze(1) + pred_masks = pred_masks.gt(0.5).float() + maskiou_t = self._mask_iou(pred_masks, mask_t) + + maskiou_net_input_list.append(maskiou_net_input) + maskiou_t_list.append(maskiou_t) + label_t_list.append(label_t) + + losses = {'M': loss_m * cfg.mask_alpha / mask_h / mask_w} + + if cfg.mask_proto_coeff_diversity_loss: + losses['D'] = loss_d + + if cfg.use_maskiou: + # discard_mask_area discarded every mask in the batch, so nothing to do here + if len(maskiou_t_list) == 0: + return losses, None + + maskiou_t = torch.cat(maskiou_t_list) + label_t = torch.cat(label_t_list) + maskiou_net_input = torch.cat(maskiou_net_input_list) + + num_samples = maskiou_t.size(0) + if cfg.maskious_to_train > 0 and num_samples > cfg.maskious_to_train: + perm = torch.randperm(num_samples) + select = perm[:cfg.masks_to_train] + maskiou_t = maskiou_t[select] + label_t = label_t[select] + maskiou_net_input = maskiou_net_input[select] + + return losses, [maskiou_net_input, maskiou_t, label_t] + + return losses + + def _mask_iou(self, mask1, mask2): + intersection = torch.sum(mask1*mask2, dim=(0, 1)) + area1 = torch.sum(mask1, dim=(0, 1)) + area2 = torch.sum(mask2, dim=(0, 1)) + union = (area1 + area2) - intersection + ret = intersection / union + return ret + + def mask_iou_loss(self, net, maskiou_targets): + maskiou_net_input, maskiou_t, label_t = maskiou_targets + + maskiou_p = net.maskiou_net(maskiou_net_input) + + label_t = label_t[:, None] + maskiou_p = torch.gather(maskiou_p, dim=1, index=label_t).view(-1) + + loss_i = F.smooth_l1_loss(maskiou_p, maskiou_t, reduction='sum') + + return loss_i * cfg.maskiou_alpha diff --git a/PyTorch/contrib/cv/detection/YOLACT/modelzoo_level.txt b/PyTorch/contrib/cv/detection/YOLACT/modelzoo_level.txt index 282c3ff3b3..c5c4a9d800 100644 --- a/PyTorch/contrib/cv/detection/YOLACT/modelzoo_level.txt +++ b/PyTorch/contrib/cv/detection/YOLACT/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PrecisionStatus:OK +FuncStatus:OK +PrecisionStatus:OK PerfStatus:POK \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/YOLACT/yolact.py b/PyTorch/contrib/cv/detection/YOLACT/yolact.py index e65f748d32..3174bde536 100644 --- a/PyTorch/contrib/cv/detection/YOLACT/yolact.py +++ b/PyTorch/contrib/cv/detection/YOLACT/yolact.py @@ -1,754 +1,754 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -import torch, torchvision -import torch.nn as nn -import torch.nn.functional as F -from torchvision.models.resnet import Bottleneck -import numpy as np -from itertools import product -from math import sqrt -from typing import List -from collections import defaultdict - -from data.config import cfg, mask_type -from layers import Detect -from layers.interpolate import InterpolateModule -from backbone import construct_backbone - -import torch.backends.cudnn as cudnn -from utils import timer -from utils.functions import MovingAverage, make_net - -# This is required for Pytorch 1.0.1 on Windows to initialize Cuda on some driver versions. -# See the bug report here: https://github.com/pytorch/pytorch/issues/17108 - -# As of March 10, 2019, Pytorch DataParallel still doesn't support JIT Script Modules -use_jit = False -if not use_jit: - print('Multiple GPUs detected! Turning off JIT.') - -ScriptModuleWrapper = torch.jit.ScriptModule if use_jit else nn.Module -script_method_wrapper = torch.jit.script_method if use_jit else lambda fn, _rcn=None: fn - - - -class Concat(nn.Module): - def __init__(self, nets, extra_params): - super().__init__() - - self.nets = nn.ModuleList(nets) - self.extra_params = extra_params - - def forward(self, x): - # Concat each along the channel dimension - return torch.cat([net(x) for net in self.nets], dim=1, **self.extra_params) - -prior_cache = defaultdict(lambda: None) - -class PredictionModule(nn.Module): - """ - The (c) prediction module adapted from DSSD: - https://arxiv.org/pdf/1701.06659.pdf - - Note that this is slightly different to the module in the paper - because the Bottleneck block actually has a 3x3 convolution in - the middle instead of a 1x1 convolution. Though, I really can't - be arsed to implement it myself, and, who knows, this might be - better. - - Args: - - in_channels: The input feature size. - - out_channels: The output feature size (must be a multiple of 4). - - aspect_ratios: A list of lists of priorbox aspect ratios (one list per scale). - - scales: A list of priorbox scales relative to this layer's convsize. - For instance: If this layer has convouts of size 30x30 for - an image of size 600x600, the 'default' (scale - of 1) for this layer would produce bounding - boxes with an area of 20x20px. If the scale is - .5 on the other hand, this layer would consider - bounding boxes with area 10x10px, etc. - - parent: If parent is a PredictionModule, this module will use all the layers - from parent instead of from this module. - """ - - def __init__(self, in_channels, out_channels=1024, aspect_ratios=[[1]], scales=[1], parent=None, index=0): - super().__init__() - - self.num_classes = cfg.num_classes - self.mask_dim = cfg.mask_dim # Defined by Yolact - self.num_priors = sum(len(x)*len(scales) for x in aspect_ratios) - self.parent = [parent] # Don't include this in the state dict - self.index = index - self.num_heads = cfg.num_heads # Defined by Yolact - - if cfg.mask_proto_split_prototypes_by_head and cfg.mask_type == mask_type.lincomb: - self.mask_dim = self.mask_dim // self.num_heads - - if cfg.mask_proto_prototypes_as_features: - in_channels += self.mask_dim - - if parent is None: - if cfg.extra_head_net is None: - out_channels = in_channels - else: - self.upfeature, out_channels = make_net(in_channels, cfg.extra_head_net) - - if cfg.use_prediction_module: - self.block = Bottleneck(out_channels, out_channels // 4) - self.conv = nn.Conv2d(out_channels, out_channels, kernel_size=1, bias=True) - self.bn = nn.BatchNorm2d(out_channels) - - self.bbox_layer = nn.Conv2d(out_channels, self.num_priors * 4, **cfg.head_layer_params) - self.conf_layer = nn.Conv2d(out_channels, self.num_priors * self.num_classes, **cfg.head_layer_params) - self.mask_layer = nn.Conv2d(out_channels, self.num_priors * self.mask_dim, **cfg.head_layer_params) - - if cfg.use_mask_scoring: - self.score_layer = nn.Conv2d(out_channels, self.num_priors, **cfg.head_layer_params) - - if cfg.use_instance_coeff: - self.inst_layer = nn.Conv2d(out_channels, self.num_priors * cfg.num_instance_coeffs, **cfg.head_layer_params) - - # What is this ugly lambda doing in the middle of all this clean prediction module code? - def make_extra(num_layers): - if num_layers == 0: - return lambda x: x - else: - # Looks more complicated than it is. This just creates an array of num_layers alternating conv-relu - return nn.Sequential(*sum([[ - nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1), - nn.ReLU(inplace=True) - ] for _ in range(num_layers)], [])) - - self.bbox_extra, self.conf_extra, self.mask_extra = [make_extra(x) for x in cfg.extra_layers] - - if cfg.mask_type == mask_type.lincomb and cfg.mask_proto_coeff_gate: - self.gate_layer = nn.Conv2d(out_channels, self.num_priors * self.mask_dim, kernel_size=3, padding=1) - - self.aspect_ratios = aspect_ratios - self.scales = scales - - self.priors = None - self.last_conv_size = None - self.last_img_size = None - - def forward(self, x): - """ - Args: - - x: The convOut from a layer in the backbone network - Size: [batch_size, in_channels, conv_h, conv_w]) - - Returns a tuple (bbox_coords, class_confs, mask_output, prior_boxes) with sizes - - bbox_coords: [batch_size, conv_h*conv_w*num_priors, 4] - - class_confs: [batch_size, conv_h*conv_w*num_priors, num_classes] - - mask_output: [batch_size, conv_h*conv_w*num_priors, mask_dim] - - prior_boxes: [conv_h*conv_w*num_priors, 4] - """ - # In case we want to use another module's layers - src = self if self.parent[0] is None else self.parent[0] - - conv_h = x.size(2) - conv_w = x.size(3) - - if cfg.extra_head_net is not None: - x = src.upfeature(x) - - if cfg.use_prediction_module: - # The two branches of PM design (c) - a = src.block(x) - - b = src.conv(x) - b = src.bn(b) - b = F.relu(b) - - # TODO: Possibly switch this out for a product - x = a + b - - bbox_x = src.bbox_extra(x) - conf_x = src.conf_extra(x) - mask_x = src.mask_extra(x) - - bbox = src.bbox_layer(bbox_x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, 4) - conf = src.conf_layer(conf_x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, self.num_classes) - - if cfg.eval_mask_branch: - mask = src.mask_layer(mask_x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, self.mask_dim) - else: - mask = torch.zeros(x.size(0), bbox.size(1), self.mask_dim, device=bbox.device) - - if cfg.use_mask_scoring: - score = src.score_layer(x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, 1) - - if cfg.use_instance_coeff: - inst = src.inst_layer(x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, cfg.num_instance_coeffs) - - # See box_utils.decode for an explanation of this - if cfg.use_yolo_regressors: - bbox[:, :, :2] = torch.sigmoid(bbox[:, :, :2]) - 0.5 - bbox[:, :, 0] /= conv_w - bbox[:, :, 1] /= conv_h - - if cfg.eval_mask_branch: - if cfg.mask_type == mask_type.direct: - mask = torch.sigmoid(mask) - elif cfg.mask_type == mask_type.lincomb: - mask = cfg.mask_proto_coeff_activation(mask) - - if cfg.mask_proto_coeff_gate: - gate = src.gate_layer(x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, self.mask_dim) - mask = mask * torch.sigmoid(gate) - - if cfg.mask_proto_split_prototypes_by_head and cfg.mask_type == mask_type.lincomb: - mask = F.pad(mask, (self.index * self.mask_dim, (self.num_heads - self.index - 1) * self.mask_dim), mode='constant', value=0) - - priors = self.make_priors(conv_h, conv_w, x.device) - - preds = { 'loc': bbox, 'conf': conf, 'mask': mask, 'priors': priors } - - if cfg.use_mask_scoring: - preds['score'] = score - - if cfg.use_instance_coeff: - preds['inst'] = inst - - return preds - - def make_priors(self, conv_h, conv_w, device): - """ Note that priors are [x,y,width,height] where (x,y) is the center of the box. """ - global prior_cache - size = (conv_h, conv_w) - - with timer.env('makepriors'): - if self.last_img_size != (cfg._tmp_img_w, cfg._tmp_img_h): - prior_data = [] - - # Iteration order is important (it has to sync up with the convout) - for j, i in product(range(conv_h), range(conv_w)): - # +0.5 because priors are in center-size notation - x = (i + 0.5) / conv_w - y = (j + 0.5) / conv_h - - for ars in self.aspect_ratios: - for scale in self.scales: - for ar in ars: - if not cfg.backbone.preapply_sqrt: - ar = sqrt(ar) - - if cfg.backbone.use_pixel_scales: - w = scale * ar / cfg.max_size - h = scale / ar / cfg.max_size - else: - w = scale * ar / conv_w - h = scale / ar / conv_h - - # This is for backward compatability with a bug where I made everything square by accident - if cfg.backbone.use_square_anchors: - h = w - - prior_data += [x, y, w, h] - - self.priors = torch.Tensor(prior_data).to(device).view(-1, 4).detach() - self.priors.requires_grad = False - self.last_img_size = (cfg._tmp_img_w, cfg._tmp_img_h) - self.last_conv_size = (conv_w, conv_h) - prior_cache[size] = None - elif self.priors.device != device: - # This whole weird situation is so that DataParalell doesn't copy the priors each iteration - if prior_cache[size] is None: - prior_cache[size] = {} - - if device not in prior_cache[size]: - prior_cache[size][device] = self.priors.to(device) - - self.priors = prior_cache[size][device] - - return self.priors - -class FPN(ScriptModuleWrapper): - """ - Implements a general version of the FPN introduced in - https://arxiv.org/pdf/1612.03144.pdf - - Parameters (in cfg.fpn): - - num_features (int): The number of output features in the fpn layers. - - interpolation_mode (str): The mode to pass to F.interpolate. - - num_downsample (int): The number of downsampled layers to add onto the selected layers. - These extra layers are downsampled from the last selected layer. - - Args: - - in_channels (list): For each conv layer you supply in the forward pass, - how many features will it have? - """ - __constants__ = ['interpolation_mode', 'num_downsample', 'use_conv_downsample', 'relu_pred_layers', - 'lat_layers', 'pred_layers', 'downsample_layers', 'relu_downsample_layers'] - - def __init__(self, in_channels): - super().__init__() - - self.lat_layers = nn.ModuleList([ - nn.Conv2d(x, cfg.fpn.num_features, kernel_size=1) - for x in reversed(in_channels) - ]) - - # This is here for backwards compatability - padding = 1 if cfg.fpn.pad else 0 - self.pred_layers = nn.ModuleList([ - nn.Conv2d(cfg.fpn.num_features, cfg.fpn.num_features, kernel_size=3, padding=padding) - for _ in in_channels - ]) - - if cfg.fpn.use_conv_downsample: - self.downsample_layers = nn.ModuleList([ - nn.Conv2d(cfg.fpn.num_features, cfg.fpn.num_features, kernel_size=3, padding=1, stride=2) - for _ in range(cfg.fpn.num_downsample) - ]) - - self.interpolation_mode = cfg.fpn.interpolation_mode - self.num_downsample = cfg.fpn.num_downsample - self.use_conv_downsample = cfg.fpn.use_conv_downsample - self.relu_downsample_layers = cfg.fpn.relu_downsample_layers - self.relu_pred_layers = cfg.fpn.relu_pred_layers - - @script_method_wrapper - def forward(self, convouts:List[torch.Tensor]): - """ - Args: - - convouts (list): A list of convouts for the corresponding layers in in_channels. - Returns: - - A list of FPN convouts in the same order as x with extra downsample layers if requested. - """ - - out = [] - x = torch.zeros(1, device=convouts[0].device) - for i in range(len(convouts)): - out.append(x) - - # For backward compatability, the conv layers are stored in reverse but the input and output is - # given in the correct order. Thus, use j=-i-1 for the input and output and i for the conv layers. - j = len(convouts) - for lat_layer in self.lat_layers: - j -= 1 - - if j < len(convouts) - 1: - _, _, h, w = convouts[j].size() - x = F.interpolate(x, size=(h, w), mode=self.interpolation_mode, align_corners=False) - - x = x + lat_layer(convouts[j]) - out[j] = x - - # This janky second loop is here because TorchScript. - j = len(convouts) - for pred_layer in self.pred_layers: - j -= 1 - out[j] = pred_layer(out[j]) - - if self.relu_pred_layers: - F.relu(out[j], inplace=True) - - cur_idx = len(out) - - # In the original paper, this takes care of P6 - if self.use_conv_downsample: - for downsample_layer in self.downsample_layers: - out.append(downsample_layer(out[-1])) - else: - for idx in range(self.num_downsample): - # Note: this is an untested alternative to out.append(out[-1][:, :, ::2, ::2]). Thanks TorchScript. - out.append(nn.functional.max_pool2d(out[-1], 1, stride=2)) - - if self.relu_downsample_layers: - for idx in range(len(out) - cur_idx): - out[idx] = F.relu(out[idx + cur_idx], inplace=False) - - return out - -class FastMaskIoUNet(ScriptModuleWrapper): - - def __init__(self): - super().__init__() - input_channels = 1 - last_layer = [(cfg.num_classes-1, 1, {})] - self.maskiou_net, _ = make_net(input_channels, cfg.maskiou_net + last_layer, include_last_relu=True) - - def forward(self, x): - x = self.maskiou_net(x) - maskiou_p = F.max_pool2d(x, kernel_size=x.size()[2:]).squeeze(-1).squeeze(-1) - - return maskiou_p - - - -class Yolact(nn.Module): - """ - - - ██╗ ██╗ ██████╗ ██╗ █████╗ ██████╗████████╗ - ╚██╗ ██╔╝██╔═══██╗██║ ██╔══██╗██╔════╝╚══██╔══╝ - ╚████╔╝ ██║ ██║██║ ███████║██║ ██║ - ╚██╔╝ ██║ ██║██║ ██╔══██║██║ ██║ - ██║ ╚██████╔╝███████╗██║ ██║╚██████╗ ██║ - ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ - - - You can set the arguments by changing them in the backbone config object in config.py. - - Parameters (in cfg.backbone): - - selected_layers: The indices of the conv layers to use for prediction. - - pred_scales: A list with len(selected_layers) containing tuples of scales (see PredictionModule) - - pred_aspect_ratios: A list of lists of aspect ratios with len(selected_layers) (see PredictionModule) - """ - - def __init__(self): - super().__init__() - - self.backbone = construct_backbone(cfg.backbone) #backbone: resnetbackbone. backbone_modules:{list:104}. bn1:{BatchNorm2d} - - if cfg.freeze_bn: # it's true - self.freeze_bn() - - # Compute mask_dim here and add it back to the config. Make sure Yolact's constructor is called early! - if cfg.mask_type == mask_type.direct: - cfg.mask_dim = cfg.mask_size**2 - elif cfg.mask_type == mask_type.lincomb: # the module will execute this branch - if cfg.mask_proto_use_grid: - self.grid = torch.Tensor(np.load(cfg.mask_proto_grid_file)) - self.num_grids = self.grid.size(0) - else: # the module will execute this branch - self.num_grids = 0 - - self.proto_src = cfg.mask_proto_src - - if self.proto_src is None: in_channels = 3 - elif cfg.fpn is not None: in_channels = cfg.fpn.num_features - else: in_channels = self.backbone.channels[self.proto_src] - in_channels += self.num_grids - #in_channels will be 256 - # The include_last_relu=false here is because we might want to change it to another function - self.proto_net, cfg.mask_dim = make_net(in_channels, cfg.mask_proto_net, include_last_relu=False) - - if cfg.mask_proto_bias: - cfg.mask_dim += 1 - - - self.selected_layers = cfg.backbone.selected_layers - src_channels = self.backbone.channels - - if cfg.use_maskiou: #false - self.maskiou_net = FastMaskIoUNet() - - if cfg.fpn is not None: #true - # Some hacky rewiring to accomodate the FPN - self.fpn = FPN([src_channels[i] for i in self.selected_layers]) - self.selected_layers = list(range(len(self.selected_layers) + cfg.fpn.num_downsample)) - src_channels = [cfg.fpn.num_features] * len(self.selected_layers) - - - self.prediction_layers = nn.ModuleList() - cfg.num_heads = len(self.selected_layers) - - for idx, layer_idx in enumerate(self.selected_layers): - # If we're sharing prediction module weights, have every module's parent be the first one - parent = None - if cfg.share_prediction_module and idx > 0: #cfg.share_prediction_module is True - parent = self.prediction_layers[0] - - pred = PredictionModule(src_channels[layer_idx], src_channels[layer_idx], - aspect_ratios = cfg.backbone.pred_aspect_ratios[idx], - scales = cfg.backbone.pred_scales[idx], - parent = parent, - index = idx) - self.prediction_layers.append(pred) - - # Extra parameters for the extra losses - if cfg.use_class_existence_loss: #false - # This comes from the smallest layer selected - # Also note that cfg.num_classes includes background - self.class_existence_fc = nn.Linear(src_channels[-1], cfg.num_classes - 1) - - if cfg.use_semantic_segmentation_loss: #true - self.semantic_seg_conv = nn.Conv2d(src_channels[0], cfg.num_classes-1, kernel_size=1) - - # For use in evaluation - self.detect = Detect(cfg.num_classes, bkg_label=0, top_k=cfg.nms_top_k, - conf_thresh=cfg.nms_conf_thresh, nms_thresh=cfg.nms_thresh) - - def save_weights(self, path): - """ Saves the model's weights using compression because the file sizes were getting too big. """ - torch.save(self.state_dict(), path) - - def load_weights(self, path, useCuda = True): - """ Loads weights from a compressed save file. """ - state_dict = torch.load(path) if useCuda else torch.load(path, map_location=torch.device('cpu')) - - # For backward compatability, remove these (the new variable is called layers) - for key in list(state_dict.keys()): - if key.startswith('backbone.layer') and not key.startswith('backbone.layers'): - del state_dict[key] - - # Also for backward compatibility with v1.0 weights, do this check - if key.startswith('fpn.downsample_layers.'): - if cfg.fpn is not None and int(key.split('.')[2]) >= cfg.fpn.num_downsample: - del state_dict[key] - self.load_state_dict(state_dict) - - def init_weights(self, backbone_path): - """ Initialize weights for training. """ - # Initialize the backbone with the pretrained weights. - self.backbone.init_backbone(backbone_path) - - conv_constants = getattr(nn.Conv2d(1, 1, 1), '__constants__') - - # Quick lambda to test if one list contains the other - def all_in(x, y): - for _x in x: - if _x not in y: - return False - return True - - # Initialize the rest of the conv layers with xavier - for name, module in self.named_modules(): - # See issue #127 for why we need such a complicated condition if the module is a WeakScriptModuleProxy - # Broke in 1.3 (see issue #175), WeakScriptModuleProxy was turned into just ScriptModule. - # Broke in 1.4 (see issue #292), where RecursiveScriptModule is the new star of the show. - # Note that this might break with future pytorch updates, so let me know if it does - is_script_conv = False - if 'Script' in type(module).__name__: - # 1.4 workaround: now there's an original_name member so just use that - if hasattr(module, 'original_name'): - is_script_conv = 'Conv' in module.original_name - # 1.3 workaround: check if this has the same constants as a conv module - else: - is_script_conv = ( - all_in(module.__dict__['_constants_set'], conv_constants) - and all_in(conv_constants, module.__dict__['_constants_set'])) - - is_conv_layer = isinstance(module, nn.Conv2d) or is_script_conv - - if is_conv_layer and module not in self.backbone.backbone_modules: - nn.init.xavier_uniform_(module.weight.data) - - if module.bias is not None: - if cfg.use_focal_loss and 'conf_layer' in name: - if not cfg.use_sigmoid_focal_loss: - # Initialize the last layer as in the focal loss paper. - # Because we use softmax and not sigmoid, I had to derive an alternate expression - # on a notecard. Define pi to be the probability of outputting a foreground detection. - # Then let z = sum(exp(x)) - exp(x_0). Finally let c be the number of foreground classes. - # Chugging through the math, this gives us - # x_0 = log(z * (1 - pi) / pi) where 0 is the background class - # x_i = log(z / c) for all i > 0 - # For simplicity (and because we have a degree of freedom here), set z = 1. Then we have - # x_0 = log((1 - pi) / pi) note: don't split up the log for numerical stability - # x_i = -log(c) for all i > 0 - module.bias.data[0] = np.log((1 - cfg.focal_loss_init_pi) / cfg.focal_loss_init_pi) - module.bias.data[1:] = -np.log(module.bias.size(0) - 1) - else: - module.bias.data[0] = -np.log(cfg.focal_loss_init_pi / (1 - cfg.focal_loss_init_pi)) - module.bias.data[1:] = -np.log((1 - cfg.focal_loss_init_pi) / cfg.focal_loss_init_pi) - else: - module.bias.data.zero_() - - def train(self, mode=True): - super().train(mode) - - if cfg.freeze_bn: - self.freeze_bn() - - def freeze_bn(self, enable=False): - """ Adapted from https://discuss.pytorch.org/t/how-to-train-with-frozen-batchnorm/12106/8 """ - for module in self.modules(): - if isinstance(module, nn.BatchNorm2d): - module.train() if enable else module.eval() - - module.weight.requires_grad = enable - module.bias.requires_grad = enable - - def forward(self, x): - """ The input should be of size [batch_size, 3, img_h, img_w] """ - _, _, img_h, img_w = x.size() - cfg._tmp_img_h = img_h - cfg._tmp_img_w = img_w - - with timer.env('backbone'): - outs = self.backbone(x) - - if cfg.fpn is not None: - with timer.env('fpn'): - # Use backbone.selected_layers because we overwrote self.selected_layers - outs = [outs[i] for i in cfg.backbone.selected_layers] - outs = self.fpn(outs) - - proto_out = None - if cfg.mask_type == mask_type.lincomb and cfg.eval_mask_branch: - with timer.env('proto'): - proto_x = x if self.proto_src is None else outs[self.proto_src] - - if self.num_grids > 0: - grids = self.grid.repeat(proto_x.size(0), 1, 1, 1) - proto_x = torch.cat([proto_x, grids], dim=1) - - proto_out = self.proto_net(proto_x) - proto_out = cfg.mask_proto_prototype_activation(proto_out) - - if cfg.mask_proto_prototypes_as_features: - # Clone here because we don't want to permute this, though idk if contiguous makes this unnecessary - proto_downsampled = proto_out.clone() - - if cfg.mask_proto_prototypes_as_features_no_grad: - proto_downsampled = proto_out.detach() - - # Move the features last so the multiplication is easy - proto_out = proto_out.permute(0, 2, 3, 1).contiguous() - - if cfg.mask_proto_bias: - bias_shape = [x for x in proto_out.size()] - bias_shape[-1] = 1 - proto_out = torch.cat([proto_out, torch.ones(*bias_shape)], -1) - - - with timer.env('pred_heads'): - pred_outs = { 'loc': [], 'conf': [], 'mask': [], 'priors': [] } - - if cfg.use_mask_scoring: - pred_outs['score'] = [] - - if cfg.use_instance_coeff: - pred_outs['inst'] = [] - - for idx, pred_layer in zip(self.selected_layers, self.prediction_layers): - pred_x = outs[idx] - - if cfg.mask_type == mask_type.lincomb and cfg.mask_proto_prototypes_as_features: - # Scale the prototypes down to the current prediction layer's size and add it as inputs - proto_downsampled = F.interpolate(proto_downsampled, size=outs[idx].size()[2:], mode='bilinear', align_corners=False) - pred_x = torch.cat([pred_x, proto_downsampled], dim=1) - - # A hack for the way dataparallel works - if cfg.share_prediction_module and pred_layer is not self.prediction_layers[0]: - pred_layer.parent = [self.prediction_layers[0]] - - p = pred_layer(pred_x) - - for k, v in p.items(): - pred_outs[k].append(v) - - for k, v in pred_outs.items(): - pred_outs[k] = torch.cat(v, -2) - - if proto_out is not None: - pred_outs['proto'] = proto_out - - if self.training: - # For the extra loss functions - if cfg.use_class_existence_loss: - pred_outs['classes'] = self.class_existence_fc(outs[-1].mean(dim=(2, 3))) - - if cfg.use_semantic_segmentation_loss: - pred_outs['segm'] = self.semantic_seg_conv(outs[0]) - - return pred_outs - else: - if cfg.use_mask_scoring: - pred_outs['score'] = torch.sigmoid(pred_outs['score']) - - if cfg.use_focal_loss: - if cfg.use_sigmoid_focal_loss: - # Note: even though conf[0] exists, this mode doesn't train it so don't use it - pred_outs['conf'] = torch.sigmoid(pred_outs['conf']) - if cfg.use_mask_scoring: - pred_outs['conf'] *= pred_outs['score'] - elif cfg.use_objectness_score: - # See focal_loss_sigmoid in multibox_loss.py for details - objectness = torch.sigmoid(pred_outs['conf'][:, :, 0]) - pred_outs['conf'][:, :, 1:] = objectness[:, :, None] * F.softmax(pred_outs['conf'][:, :, 1:], -1) - pred_outs['conf'][:, :, 0 ] = 1 - objectness - else: - pred_outs['conf'] = F.softmax(pred_outs['conf'], -1) - else: - - if cfg.use_objectness_score: - objectness = torch.sigmoid(pred_outs['conf'][:, :, 0]) - - pred_outs['conf'][:, :, 1:] = (objectness > 0.10)[..., None] \ - * F.softmax(pred_outs['conf'][:, :, 1:], dim=-1) - - else: - pred_outs['conf'] = F.softmax(pred_outs['conf'], -1) - - return self.detect(pred_outs) - - - - -# Some testing code -if __name__ == '__main__': - from utils.functions import init_console - init_console() - - # Use the first argument to set the config if you want - import sys - if len(sys.argv) > 1: - from data.config import set_cfg - set_cfg(sys.argv[1]) - - net = Yolact() - net.train() - net.init_weights(backbone_path='weights/' + cfg.backbone.path) - - # GPU - net = net.cuda() - torch.set_default_tensor_type('torch.cuda.FloatTensor') - - x = torch.zeros((1, 3, cfg.max_size, cfg.max_size)) - y = net(x) - - for p in net.prediction_layers: - print(p.last_conv_size) - - print() - for k, a in y.items(): - print(k + ': ', a.size(), torch.sum(a)) - exit() - - net(x) - # timer.disable('pass2') - avg = MovingAverage() - try: - while True: - timer.reset() - with timer.env('everything else'): - net(x) - avg.add(timer.total_time()) - print('\033[2J') # Moves console cursor to 0,0 - timer.print_stats() - print('Avg fps: %.2f\tAvg ms: %.2f ' % (1/avg.get_avg(), avg.get_avg()*1000)) - except KeyboardInterrupt: - pass +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import torch, torchvision +import torch.nn as nn +import torch.nn.functional as F +from torchvision.models.resnet import Bottleneck +import numpy as np +from itertools import product +from math import sqrt +from typing import List +from collections import defaultdict + +from data.config import cfg, mask_type +from layers import Detect +from layers.interpolate import InterpolateModule +from backbone import construct_backbone + +import torch.backends.cudnn as cudnn +from utils import timer +from utils.functions import MovingAverage, make_net + +# This is required for Pytorch 1.0.1 on Windows to initialize Cuda on some driver versions. +# See the bug report here: https://github.com/pytorch/pytorch/issues/17108 + +# As of March 10, 2019, Pytorch DataParallel still doesn't support JIT Script Modules +use_jit = False +if not use_jit: + print('Multiple GPUs detected! Turning off JIT.') + +ScriptModuleWrapper = torch.jit.ScriptModule if use_jit else nn.Module +script_method_wrapper = torch.jit.script_method if use_jit else lambda fn, _rcn=None: fn + + + +class Concat(nn.Module): + def __init__(self, nets, extra_params): + super().__init__() + + self.nets = nn.ModuleList(nets) + self.extra_params = extra_params + + def forward(self, x): + # Concat each along the channel dimension + return torch.cat([net(x) for net in self.nets], dim=1, **self.extra_params) + +prior_cache = defaultdict(lambda: None) + +class PredictionModule(nn.Module): + """ + The (c) prediction module adapted from DSSD: + https://arxiv.org/pdf/1701.06659.pdf + + Note that this is slightly different to the module in the paper + because the Bottleneck block actually has a 3x3 convolution in + the middle instead of a 1x1 convolution. Though, I really can't + be arsed to implement it myself, and, who knows, this might be + better. + + Args: + - in_channels: The input feature size. + - out_channels: The output feature size (must be a multiple of 4). + - aspect_ratios: A list of lists of priorbox aspect ratios (one list per scale). + - scales: A list of priorbox scales relative to this layer's convsize. + For instance: If this layer has convouts of size 30x30 for + an image of size 600x600, the 'default' (scale + of 1) for this layer would produce bounding + boxes with an area of 20x20px. If the scale is + .5 on the other hand, this layer would consider + bounding boxes with area 10x10px, etc. + - parent: If parent is a PredictionModule, this module will use all the layers + from parent instead of from this module. + """ + + def __init__(self, in_channels, out_channels=1024, aspect_ratios=[[1]], scales=[1], parent=None, index=0): + super().__init__() + + self.num_classes = cfg.num_classes + self.mask_dim = cfg.mask_dim # Defined by Yolact + self.num_priors = sum(len(x)*len(scales) for x in aspect_ratios) + self.parent = [parent] # Don't include this in the state dict + self.index = index + self.num_heads = cfg.num_heads # Defined by Yolact + + if cfg.mask_proto_split_prototypes_by_head and cfg.mask_type == mask_type.lincomb: + self.mask_dim = self.mask_dim // self.num_heads + + if cfg.mask_proto_prototypes_as_features: + in_channels += self.mask_dim + + if parent is None: + if cfg.extra_head_net is None: + out_channels = in_channels + else: + self.upfeature, out_channels = make_net(in_channels, cfg.extra_head_net) + + if cfg.use_prediction_module: + self.block = Bottleneck(out_channels, out_channels // 4) + self.conv = nn.Conv2d(out_channels, out_channels, kernel_size=1, bias=True) + self.bn = nn.BatchNorm2d(out_channels) + + self.bbox_layer = nn.Conv2d(out_channels, self.num_priors * 4, **cfg.head_layer_params) + self.conf_layer = nn.Conv2d(out_channels, self.num_priors * self.num_classes, **cfg.head_layer_params) + self.mask_layer = nn.Conv2d(out_channels, self.num_priors * self.mask_dim, **cfg.head_layer_params) + + if cfg.use_mask_scoring: + self.score_layer = nn.Conv2d(out_channels, self.num_priors, **cfg.head_layer_params) + + if cfg.use_instance_coeff: + self.inst_layer = nn.Conv2d(out_channels, self.num_priors * cfg.num_instance_coeffs, **cfg.head_layer_params) + + # What is this ugly lambda doing in the middle of all this clean prediction module code? + def make_extra(num_layers): + if num_layers == 0: + return lambda x: x + else: + # Looks more complicated than it is. This just creates an array of num_layers alternating conv-relu + return nn.Sequential(*sum([[ + nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1), + nn.ReLU(inplace=True) + ] for _ in range(num_layers)], [])) + + self.bbox_extra, self.conf_extra, self.mask_extra = [make_extra(x) for x in cfg.extra_layers] + + if cfg.mask_type == mask_type.lincomb and cfg.mask_proto_coeff_gate: + self.gate_layer = nn.Conv2d(out_channels, self.num_priors * self.mask_dim, kernel_size=3, padding=1) + + self.aspect_ratios = aspect_ratios + self.scales = scales + + self.priors = None + self.last_conv_size = None + self.last_img_size = None + + def forward(self, x): + """ + Args: + - x: The convOut from a layer in the backbone network + Size: [batch_size, in_channels, conv_h, conv_w]) + + Returns a tuple (bbox_coords, class_confs, mask_output, prior_boxes) with sizes + - bbox_coords: [batch_size, conv_h*conv_w*num_priors, 4] + - class_confs: [batch_size, conv_h*conv_w*num_priors, num_classes] + - mask_output: [batch_size, conv_h*conv_w*num_priors, mask_dim] + - prior_boxes: [conv_h*conv_w*num_priors, 4] + """ + # In case we want to use another module's layers + src = self if self.parent[0] is None else self.parent[0] + + conv_h = x.size(2) + conv_w = x.size(3) + + if cfg.extra_head_net is not None: + x = src.upfeature(x) + + if cfg.use_prediction_module: + # The two branches of PM design (c) + a = src.block(x) + + b = src.conv(x) + b = src.bn(b) + b = F.relu(b) + + # TODO: Possibly switch this out for a product + x = a + b + + bbox_x = src.bbox_extra(x) + conf_x = src.conf_extra(x) + mask_x = src.mask_extra(x) + + bbox = src.bbox_layer(bbox_x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, 4) + conf = src.conf_layer(conf_x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, self.num_classes) + + if cfg.eval_mask_branch: + mask = src.mask_layer(mask_x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, self.mask_dim) + else: + mask = torch.zeros(x.size(0), bbox.size(1), self.mask_dim, device=bbox.device) + + if cfg.use_mask_scoring: + score = src.score_layer(x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, 1) + + if cfg.use_instance_coeff: + inst = src.inst_layer(x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, cfg.num_instance_coeffs) + + # See box_utils.decode for an explanation of this + if cfg.use_yolo_regressors: + bbox[:, :, :2] = torch.sigmoid(bbox[:, :, :2]) - 0.5 + bbox[:, :, 0] /= conv_w + bbox[:, :, 1] /= conv_h + + if cfg.eval_mask_branch: + if cfg.mask_type == mask_type.direct: + mask = torch.sigmoid(mask) + elif cfg.mask_type == mask_type.lincomb: + mask = cfg.mask_proto_coeff_activation(mask) + + if cfg.mask_proto_coeff_gate: + gate = src.gate_layer(x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, self.mask_dim) + mask = mask * torch.sigmoid(gate) + + if cfg.mask_proto_split_prototypes_by_head and cfg.mask_type == mask_type.lincomb: + mask = F.pad(mask, (self.index * self.mask_dim, (self.num_heads - self.index - 1) * self.mask_dim), mode='constant', value=0) + + priors = self.make_priors(conv_h, conv_w, x.device) + + preds = { 'loc': bbox, 'conf': conf, 'mask': mask, 'priors': priors } + + if cfg.use_mask_scoring: + preds['score'] = score + + if cfg.use_instance_coeff: + preds['inst'] = inst + + return preds + + def make_priors(self, conv_h, conv_w, device): + """ Note that priors are [x,y,width,height] where (x,y) is the center of the box. """ + global prior_cache + size = (conv_h, conv_w) + + with timer.env('makepriors'): + if self.last_img_size != (cfg._tmp_img_w, cfg._tmp_img_h): + prior_data = [] + + # Iteration order is important (it has to sync up with the convout) + for j, i in product(range(conv_h), range(conv_w)): + # +0.5 because priors are in center-size notation + x = (i + 0.5) / conv_w + y = (j + 0.5) / conv_h + + for ars in self.aspect_ratios: + for scale in self.scales: + for ar in ars: + if not cfg.backbone.preapply_sqrt: + ar = sqrt(ar) + + if cfg.backbone.use_pixel_scales: + w = scale * ar / cfg.max_size + h = scale / ar / cfg.max_size + else: + w = scale * ar / conv_w + h = scale / ar / conv_h + + # This is for backward compatability with a bug where I made everything square by accident + if cfg.backbone.use_square_anchors: + h = w + + prior_data += [x, y, w, h] + + self.priors = torch.Tensor(prior_data).to(device).view(-1, 4).detach() + self.priors.requires_grad = False + self.last_img_size = (cfg._tmp_img_w, cfg._tmp_img_h) + self.last_conv_size = (conv_w, conv_h) + prior_cache[size] = None + elif self.priors.device != device: + # This whole weird situation is so that DataParalell doesn't copy the priors each iteration + if prior_cache[size] is None: + prior_cache[size] = {} + + if device not in prior_cache[size]: + prior_cache[size][device] = self.priors.to(device) + + self.priors = prior_cache[size][device] + + return self.priors + +class FPN(ScriptModuleWrapper): + """ + Implements a general version of the FPN introduced in + https://arxiv.org/pdf/1612.03144.pdf + + Parameters (in cfg.fpn): + - num_features (int): The number of output features in the fpn layers. + - interpolation_mode (str): The mode to pass to F.interpolate. + - num_downsample (int): The number of downsampled layers to add onto the selected layers. + These extra layers are downsampled from the last selected layer. + + Args: + - in_channels (list): For each conv layer you supply in the forward pass, + how many features will it have? + """ + __constants__ = ['interpolation_mode', 'num_downsample', 'use_conv_downsample', 'relu_pred_layers', + 'lat_layers', 'pred_layers', 'downsample_layers', 'relu_downsample_layers'] + + def __init__(self, in_channels): + super().__init__() + + self.lat_layers = nn.ModuleList([ + nn.Conv2d(x, cfg.fpn.num_features, kernel_size=1) + for x in reversed(in_channels) + ]) + + # This is here for backwards compatability + padding = 1 if cfg.fpn.pad else 0 + self.pred_layers = nn.ModuleList([ + nn.Conv2d(cfg.fpn.num_features, cfg.fpn.num_features, kernel_size=3, padding=padding) + for _ in in_channels + ]) + + if cfg.fpn.use_conv_downsample: + self.downsample_layers = nn.ModuleList([ + nn.Conv2d(cfg.fpn.num_features, cfg.fpn.num_features, kernel_size=3, padding=1, stride=2) + for _ in range(cfg.fpn.num_downsample) + ]) + + self.interpolation_mode = cfg.fpn.interpolation_mode + self.num_downsample = cfg.fpn.num_downsample + self.use_conv_downsample = cfg.fpn.use_conv_downsample + self.relu_downsample_layers = cfg.fpn.relu_downsample_layers + self.relu_pred_layers = cfg.fpn.relu_pred_layers + + @script_method_wrapper + def forward(self, convouts:List[torch.Tensor]): + """ + Args: + - convouts (list): A list of convouts for the corresponding layers in in_channels. + Returns: + - A list of FPN convouts in the same order as x with extra downsample layers if requested. + """ + + out = [] + x = torch.zeros(1, device=convouts[0].device) + for i in range(len(convouts)): + out.append(x) + + # For backward compatability, the conv layers are stored in reverse but the input and output is + # given in the correct order. Thus, use j=-i-1 for the input and output and i for the conv layers. + j = len(convouts) + for lat_layer in self.lat_layers: + j -= 1 + + if j < len(convouts) - 1: + _, _, h, w = convouts[j].size() + x = F.interpolate(x, size=(h, w), mode=self.interpolation_mode, align_corners=False) + + x = x + lat_layer(convouts[j]) + out[j] = x + + # This janky second loop is here because TorchScript. + j = len(convouts) + for pred_layer in self.pred_layers: + j -= 1 + out[j] = pred_layer(out[j]) + + if self.relu_pred_layers: + F.relu(out[j], inplace=True) + + cur_idx = len(out) + + # In the original paper, this takes care of P6 + if self.use_conv_downsample: + for downsample_layer in self.downsample_layers: + out.append(downsample_layer(out[-1])) + else: + for idx in range(self.num_downsample): + # Note: this is an untested alternative to out.append(out[-1][:, :, ::2, ::2]). Thanks TorchScript. + out.append(nn.functional.max_pool2d(out[-1], 1, stride=2)) + + if self.relu_downsample_layers: + for idx in range(len(out) - cur_idx): + out[idx] = F.relu(out[idx + cur_idx], inplace=False) + + return out + +class FastMaskIoUNet(ScriptModuleWrapper): + + def __init__(self): + super().__init__() + input_channels = 1 + last_layer = [(cfg.num_classes-1, 1, {})] + self.maskiou_net, _ = make_net(input_channels, cfg.maskiou_net + last_layer, include_last_relu=True) + + def forward(self, x): + x = self.maskiou_net(x) + maskiou_p = F.max_pool2d(x, kernel_size=x.size()[2:]).squeeze(-1).squeeze(-1) + + return maskiou_p + + + +class Yolact(nn.Module): + """ + + + ██╗ ██╗ ██████╗ ██╗ █████╗ ██████╗████████╗ + ╚██╗ ██╔╝██╔═══██╗██║ ██╔══██╗██╔════╝╚══██╔══╝ + ╚████╔╝ ██║ ██║██║ ███████║██║ ██║ + ╚██╔╝ ██║ ██║██║ ██╔══██║██║ ██║ + ██║ ╚██████╔╝███████╗██║ ██║╚██████╗ ██║ + ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ + + + You can set the arguments by changing them in the backbone config object in config.py. + + Parameters (in cfg.backbone): + - selected_layers: The indices of the conv layers to use for prediction. + - pred_scales: A list with len(selected_layers) containing tuples of scales (see PredictionModule) + - pred_aspect_ratios: A list of lists of aspect ratios with len(selected_layers) (see PredictionModule) + """ + + def __init__(self): + super().__init__() + + self.backbone = construct_backbone(cfg.backbone) #backbone: resnetbackbone. backbone_modules:{list:104}. bn1:{BatchNorm2d} + + if cfg.freeze_bn: # it's true + self.freeze_bn() + + # Compute mask_dim here and add it back to the config. Make sure Yolact's constructor is called early! + if cfg.mask_type == mask_type.direct: + cfg.mask_dim = cfg.mask_size**2 + elif cfg.mask_type == mask_type.lincomb: # the module will execute this branch + if cfg.mask_proto_use_grid: + self.grid = torch.Tensor(np.load(cfg.mask_proto_grid_file)) + self.num_grids = self.grid.size(0) + else: # the module will execute this branch + self.num_grids = 0 + + self.proto_src = cfg.mask_proto_src + + if self.proto_src is None: in_channels = 3 + elif cfg.fpn is not None: in_channels = cfg.fpn.num_features + else: in_channels = self.backbone.channels[self.proto_src] + in_channels += self.num_grids + #in_channels will be 256 + # The include_last_relu=false here is because we might want to change it to another function + self.proto_net, cfg.mask_dim = make_net(in_channels, cfg.mask_proto_net, include_last_relu=False) + + if cfg.mask_proto_bias: + cfg.mask_dim += 1 + + + self.selected_layers = cfg.backbone.selected_layers + src_channels = self.backbone.channels + + if cfg.use_maskiou: #false + self.maskiou_net = FastMaskIoUNet() + + if cfg.fpn is not None: #true + # Some hacky rewiring to accomodate the FPN + self.fpn = FPN([src_channels[i] for i in self.selected_layers]) + self.selected_layers = list(range(len(self.selected_layers) + cfg.fpn.num_downsample)) + src_channels = [cfg.fpn.num_features] * len(self.selected_layers) + + + self.prediction_layers = nn.ModuleList() + cfg.num_heads = len(self.selected_layers) + + for idx, layer_idx in enumerate(self.selected_layers): + # If we're sharing prediction module weights, have every module's parent be the first one + parent = None + if cfg.share_prediction_module and idx > 0: #cfg.share_prediction_module is True + parent = self.prediction_layers[0] + + pred = PredictionModule(src_channels[layer_idx], src_channels[layer_idx], + aspect_ratios = cfg.backbone.pred_aspect_ratios[idx], + scales = cfg.backbone.pred_scales[idx], + parent = parent, + index = idx) + self.prediction_layers.append(pred) + + # Extra parameters for the extra losses + if cfg.use_class_existence_loss: #false + # This comes from the smallest layer selected + # Also note that cfg.num_classes includes background + self.class_existence_fc = nn.Linear(src_channels[-1], cfg.num_classes - 1) + + if cfg.use_semantic_segmentation_loss: #true + self.semantic_seg_conv = nn.Conv2d(src_channels[0], cfg.num_classes-1, kernel_size=1) + + # For use in evaluation + self.detect = Detect(cfg.num_classes, bkg_label=0, top_k=cfg.nms_top_k, + conf_thresh=cfg.nms_conf_thresh, nms_thresh=cfg.nms_thresh) + + def save_weights(self, path): + """ Saves the model's weights using compression because the file sizes were getting too big. """ + torch.save(self.state_dict(), path) + + def load_weights(self, path, useCuda = True): + """ Loads weights from a compressed save file. """ + state_dict = torch.load(path) if useCuda else torch.load(path, map_location=torch.device('cpu')) + + # For backward compatability, remove these (the new variable is called layers) + for key in list(state_dict.keys()): + if key.startswith('backbone.layer') and not key.startswith('backbone.layers'): + del state_dict[key] + + # Also for backward compatibility with v1.0 weights, do this check + if key.startswith('fpn.downsample_layers.'): + if cfg.fpn is not None and int(key.split('.')[2]) >= cfg.fpn.num_downsample: + del state_dict[key] + self.load_state_dict(state_dict) + + def init_weights(self, backbone_path): + """ Initialize weights for training. """ + # Initialize the backbone with the pretrained weights. + self.backbone.init_backbone(backbone_path) + + conv_constants = getattr(nn.Conv2d(1, 1, 1), '__constants__') + + # Quick lambda to test if one list contains the other + def all_in(x, y): + for _x in x: + if _x not in y: + return False + return True + + # Initialize the rest of the conv layers with xavier + for name, module in self.named_modules(): + # See issue #127 for why we need such a complicated condition if the module is a WeakScriptModuleProxy + # Broke in 1.3 (see issue #175), WeakScriptModuleProxy was turned into just ScriptModule. + # Broke in 1.4 (see issue #292), where RecursiveScriptModule is the new star of the show. + # Note that this might break with future pytorch updates, so let me know if it does + is_script_conv = False + if 'Script' in type(module).__name__: + # 1.4 workaround: now there's an original_name member so just use that + if hasattr(module, 'original_name'): + is_script_conv = 'Conv' in module.original_name + # 1.3 workaround: check if this has the same constants as a conv module + else: + is_script_conv = ( + all_in(module.__dict__['_constants_set'], conv_constants) + and all_in(conv_constants, module.__dict__['_constants_set'])) + + is_conv_layer = isinstance(module, nn.Conv2d) or is_script_conv + + if is_conv_layer and module not in self.backbone.backbone_modules: + nn.init.xavier_uniform_(module.weight.data) + + if module.bias is not None: + if cfg.use_focal_loss and 'conf_layer' in name: + if not cfg.use_sigmoid_focal_loss: + # Initialize the last layer as in the focal loss paper. + # Because we use softmax and not sigmoid, I had to derive an alternate expression + # on a notecard. Define pi to be the probability of outputting a foreground detection. + # Then let z = sum(exp(x)) - exp(x_0). Finally let c be the number of foreground classes. + # Chugging through the math, this gives us + # x_0 = log(z * (1 - pi) / pi) where 0 is the background class + # x_i = log(z / c) for all i > 0 + # For simplicity (and because we have a degree of freedom here), set z = 1. Then we have + # x_0 = log((1 - pi) / pi) note: don't split up the log for numerical stability + # x_i = -log(c) for all i > 0 + module.bias.data[0] = np.log((1 - cfg.focal_loss_init_pi) / cfg.focal_loss_init_pi) + module.bias.data[1:] = -np.log(module.bias.size(0) - 1) + else: + module.bias.data[0] = -np.log(cfg.focal_loss_init_pi / (1 - cfg.focal_loss_init_pi)) + module.bias.data[1:] = -np.log((1 - cfg.focal_loss_init_pi) / cfg.focal_loss_init_pi) + else: + module.bias.data.zero_() + + def train(self, mode=True): + super().train(mode) + + if cfg.freeze_bn: + self.freeze_bn() + + def freeze_bn(self, enable=False): + """ Adapted from https://discuss.pytorch.org/t/how-to-train-with-frozen-batchnorm/12106/8 """ + for module in self.modules(): + if isinstance(module, nn.BatchNorm2d): + module.train() if enable else module.eval() + + module.weight.requires_grad = enable + module.bias.requires_grad = enable + + def forward(self, x): + """ The input should be of size [batch_size, 3, img_h, img_w] """ + _, _, img_h, img_w = x.size() + cfg._tmp_img_h = img_h + cfg._tmp_img_w = img_w + + with timer.env('backbone'): + outs = self.backbone(x) + + if cfg.fpn is not None: + with timer.env('fpn'): + # Use backbone.selected_layers because we overwrote self.selected_layers + outs = [outs[i] for i in cfg.backbone.selected_layers] + outs = self.fpn(outs) + + proto_out = None + if cfg.mask_type == mask_type.lincomb and cfg.eval_mask_branch: + with timer.env('proto'): + proto_x = x if self.proto_src is None else outs[self.proto_src] + + if self.num_grids > 0: + grids = self.grid.repeat(proto_x.size(0), 1, 1, 1) + proto_x = torch.cat([proto_x, grids], dim=1) + + proto_out = self.proto_net(proto_x) + proto_out = cfg.mask_proto_prototype_activation(proto_out) + + if cfg.mask_proto_prototypes_as_features: + # Clone here because we don't want to permute this, though idk if contiguous makes this unnecessary + proto_downsampled = proto_out.clone() + + if cfg.mask_proto_prototypes_as_features_no_grad: + proto_downsampled = proto_out.detach() + + # Move the features last so the multiplication is easy + proto_out = proto_out.permute(0, 2, 3, 1).contiguous() + + if cfg.mask_proto_bias: + bias_shape = [x for x in proto_out.size()] + bias_shape[-1] = 1 + proto_out = torch.cat([proto_out, torch.ones(*bias_shape)], -1) + + + with timer.env('pred_heads'): + pred_outs = { 'loc': [], 'conf': [], 'mask': [], 'priors': [] } + + if cfg.use_mask_scoring: + pred_outs['score'] = [] + + if cfg.use_instance_coeff: + pred_outs['inst'] = [] + + for idx, pred_layer in zip(self.selected_layers, self.prediction_layers): + pred_x = outs[idx] + + if cfg.mask_type == mask_type.lincomb and cfg.mask_proto_prototypes_as_features: + # Scale the prototypes down to the current prediction layer's size and add it as inputs + proto_downsampled = F.interpolate(proto_downsampled, size=outs[idx].size()[2:], mode='bilinear', align_corners=False) + pred_x = torch.cat([pred_x, proto_downsampled], dim=1) + + # A hack for the way dataparallel works + if cfg.share_prediction_module and pred_layer is not self.prediction_layers[0]: + pred_layer.parent = [self.prediction_layers[0]] + + p = pred_layer(pred_x) + + for k, v in p.items(): + pred_outs[k].append(v) + + for k, v in pred_outs.items(): + pred_outs[k] = torch.cat(v, -2) + + if proto_out is not None: + pred_outs['proto'] = proto_out + + if self.training: + # For the extra loss functions + if cfg.use_class_existence_loss: + pred_outs['classes'] = self.class_existence_fc(outs[-1].mean(dim=(2, 3))) + + if cfg.use_semantic_segmentation_loss: + pred_outs['segm'] = self.semantic_seg_conv(outs[0]) + + return pred_outs + else: + if cfg.use_mask_scoring: + pred_outs['score'] = torch.sigmoid(pred_outs['score']) + + if cfg.use_focal_loss: + if cfg.use_sigmoid_focal_loss: + # Note: even though conf[0] exists, this mode doesn't train it so don't use it + pred_outs['conf'] = torch.sigmoid(pred_outs['conf']) + if cfg.use_mask_scoring: + pred_outs['conf'] *= pred_outs['score'] + elif cfg.use_objectness_score: + # See focal_loss_sigmoid in multibox_loss.py for details + objectness = torch.sigmoid(pred_outs['conf'][:, :, 0]) + pred_outs['conf'][:, :, 1:] = objectness[:, :, None] * F.softmax(pred_outs['conf'][:, :, 1:], -1) + pred_outs['conf'][:, :, 0 ] = 1 - objectness + else: + pred_outs['conf'] = F.softmax(pred_outs['conf'], -1) + else: + + if cfg.use_objectness_score: + objectness = torch.sigmoid(pred_outs['conf'][:, :, 0]) + + pred_outs['conf'][:, :, 1:] = (objectness > 0.10)[..., None] \ + * F.softmax(pred_outs['conf'][:, :, 1:], dim=-1) + + else: + pred_outs['conf'] = F.softmax(pred_outs['conf'], -1) + + return self.detect(pred_outs) + + + + +# Some testing code +if __name__ == '__main__': + from utils.functions import init_console + init_console() + + # Use the first argument to set the config if you want + import sys + if len(sys.argv) > 1: + from data.config import set_cfg + set_cfg(sys.argv[1]) + + net = Yolact() + net.train() + net.init_weights(backbone_path='weights/' + cfg.backbone.path) + + # GPU + net = net.cuda() + torch.set_default_tensor_type('torch.cuda.FloatTensor') + + x = torch.zeros((1, 3, cfg.max_size, cfg.max_size)) + y = net(x) + + for p in net.prediction_layers: + print(p.last_conv_size) + + print() + for k, a in y.items(): + print(k + ': ', a.size(), torch.sum(a)) + exit() + + net(x) + # timer.disable('pass2') + avg = MovingAverage() + try: + while True: + timer.reset() + with timer.env('everything else'): + net(x) + avg.add(timer.total_time()) + print('\033[2J') # Moves console cursor to 0,0 + timer.print_stats() + print('Avg fps: %.2f\tAvg ms: %.2f ' % (1/avg.get_avg(), avg.get_avg()*1000)) + except KeyboardInterrupt: + pass diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/LICENSE b/PyTorch/contrib/cv/detection/YOLACT_plus/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/LICENSE +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/README.md b/PyTorch/contrib/cv/detection/YOLACT_plus/README.md index a6ecf3f430..6bf6a4c468 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/README.md +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/README.md @@ -1,49 +1,49 @@ -# YOLACT++ - -This implements training of Yolact++ on the COCO2017 dataset, mainly modified from [yolact++](https://github.com/dbolya/yolact). - -## YOLACT++ Detail - -## Requirements - -- Install PyTorch ([pytorch.org](http://pytorch.org)) -- `pip install -r requirements.txt` -- Download the dataset by -- `sh data/scripts/COCO.sh` -- Download an imagenet-pretrained model and put it in ./weights. - - For Resnet101, download resnet101_reducedfc.pth. - - For Resnet50, download resnet50-19c8e357.pth. - - For Darknet53, download darknet53.pth. - -## Training - -To train a model, run `train.py` with the desired model architecture and the path to dataset: - -```bash -# training 1p accuracy -bash ./test/train_full_1p.sh --data_path=data_path - -# training 1p performance -bash ./test/train_performance_1p.sh --data_path=data_path - -# training 8p accuracy -bash ./test/train_full_8p.sh --data_path=data_path - -# training 8p performance -bash ./test/train_performance_8p.sh --data_path=data_path - -#test 8p accuracy -bash test/train_eval_1p.sh --$pth_path=pth_path -``` - -Log path: - ${YOLACT_ROOT}/test/output/0/train_0.log # training detail log - - - -## Yolact++ training result - -| 名称 | 精度 | FPS | AMP_Type | -| :------: | :------: | :------: | :------: | -| NPU-1p | - | 3.153 | O0 | -| NPU-8p | 33.49 | 14.677 | O0 | +# YOLACT++ + +This implements training of Yolact++ on the COCO2017 dataset, mainly modified from [yolact++](https://github.com/dbolya/yolact). + +## YOLACT++ Detail + +## Requirements + +- Install PyTorch ([pytorch.org](http://pytorch.org)) +- `pip install -r requirements.txt` +- Download the dataset by +- `sh data/scripts/COCO.sh` +- Download an imagenet-pretrained model and put it in ./weights. + - For Resnet101, download resnet101_reducedfc.pth. + - For Resnet50, download resnet50-19c8e357.pth. + - For Darknet53, download darknet53.pth. + +## Training + +To train a model, run `train.py` with the desired model architecture and the path to dataset: + +```bash +# training 1p accuracy +bash ./test/train_full_1p.sh --data_path=data_path + +# training 1p performance +bash ./test/train_performance_1p.sh --data_path=data_path + +# training 8p accuracy +bash ./test/train_full_8p.sh --data_path=data_path + +# training 8p performance +bash ./test/train_performance_8p.sh --data_path=data_path + +#test 8p accuracy +bash test/train_eval_1p.sh --$pth_path=pth_path +``` + +Log path: + ${YOLACT_ROOT}/test/output/0/train_0.log # training detail log + + + +## Yolact++ training result + +| 名称 | 精度 | FPS | AMP_Type | +| :------: | :------: | :------: | :------: | +| NPU-1p | - | 3.153 | O0 | +| NPU-8p | 33.49 | 14.677 | O0 | diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/backbone.py b/PyTorch/contrib/cv/detection/YOLACT_plus/backbone.py index a3cf652028..15da87a98a 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/backbone.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/backbone.py @@ -1,474 +1,474 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import torch.nn as nn -import pickle - -from collections import OrderedDict - -try: - from deform_conv import DCNv2 as DCN -except ImportError: - def DCN(*args, **kwdargs): - raise Exception('DCN could not be imported. If you want to use YOLACT++ models, compile DCN. Check the README for instructions.') - -class Bottleneck(nn.Module): - """ Adapted from torchvision.models.resnet """ - expansion = 4 - - def __init__(self, inplanes, planes, stride=1, downsample=None, norm_layer=nn.BatchNorm2d, dilation=1, use_dcn=False): - super(Bottleneck, self).__init__() - self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False, dilation=dilation) - self.bn1 = norm_layer(planes) - if use_dcn: - self.conv2 = DCN(planes, planes, kernel_size=3, stride=stride, - padding=dilation, dilation=dilation, deformable_groups=1) - self.conv2.bias.data.zero_() - self.conv2.conv_offset_mask.weight.data.zero_() - self.conv2.conv_offset_mask.bias.data.zero_() - else: - self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, - padding=dilation, bias=False, dilation=dilation) - self.bn2 = norm_layer(planes) - self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False, dilation=dilation) - self.bn3 = norm_layer(planes * 4) - self.relu = nn.ReLU(inplace=True) - self.downsample = downsample - self.stride = stride - - def forward(self, x): - residual = x - - out = self.conv1(x) - out = self.bn1(out) - out = self.relu(out) - - out = self.conv2(out) - out = self.bn2(out) - out = self.relu(out) - - out = self.conv3(out) - out = self.bn3(out) - - if self.downsample is not None: - residual = self.downsample(x) - - out += residual - out = self.relu(out) - - return out - - -class ResNetBackbone(nn.Module): - """ Adapted from torchvision.models.resnet """ - - def __init__(self, layers, dcn_layers=[0, 0, 0, 0], dcn_interval=1, atrous_layers=[], block=Bottleneck, norm_layer=nn.BatchNorm2d): - super().__init__() - - # These will be populated by _make_layer - self.num_base_layers = len(layers) - self.layers = nn.ModuleList() - self.channels = [] - self.norm_layer = norm_layer - self.dilation = 1 - self.atrous_layers = atrous_layers - - # From torchvision.models.resnet.Resnet - self.inplanes = 64 - - self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False) - self.bn1 = norm_layer(64) - self.relu = nn.ReLU(inplace=True) - self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) - - self._make_layer(block, 64, layers[0], dcn_layers=dcn_layers[0], dcn_interval=dcn_interval) - self._make_layer(block, 128, layers[1], stride=2, dcn_layers=dcn_layers[1], dcn_interval=dcn_interval) - self._make_layer(block, 256, layers[2], stride=2, dcn_layers=dcn_layers[2], dcn_interval=dcn_interval) - self._make_layer(block, 512, layers[3], stride=2, dcn_layers=dcn_layers[3], dcn_interval=dcn_interval) - - # This contains every module that should be initialized by loading in pretrained weights. - # Any extra layers added onto this that won't be initialized by init_backbone will not be - # in this list. That way, Yolact::init_weights knows which backbone weights to initialize - # with xavier, and which ones to leave alone. - self.backbone_modules = [m for m in self.modules() if isinstance(m, nn.Conv2d)] - - - def _make_layer(self, block, planes, blocks, stride=1, dcn_layers=0, dcn_interval=1): - """ Here one layer means a string of n Bottleneck blocks. """ - downsample = None - - # This is actually just to create the connection between layers, and not necessarily to - # downsample. Even if the second condition is met, it only downsamples when stride != 1 - if stride != 1 or self.inplanes != planes * block.expansion: - if len(self.layers) in self.atrous_layers: - self.dilation += 1 - stride = 1 - - downsample = nn.Sequential( - nn.Conv2d(self.inplanes, planes * block.expansion, - kernel_size=1, stride=stride, bias=False, - dilation=self.dilation), - self.norm_layer(planes * block.expansion), - ) - - layers = [] - use_dcn = (dcn_layers >= blocks) - layers.append(block(self.inplanes, planes, stride, downsample, self.norm_layer, self.dilation, use_dcn=use_dcn)) - self.inplanes = planes * block.expansion - for i in range(1, blocks): - use_dcn = ((i+dcn_layers) >= blocks) and (i % dcn_interval == 0) - layers.append(block(self.inplanes, planes, norm_layer=self.norm_layer, use_dcn=use_dcn)) - layer = nn.Sequential(*layers) - - self.channels.append(planes * block.expansion) - self.layers.append(layer) - - return layer - - def forward(self, x): - """ Returns a list of convouts for each layer. """ - - x = self.conv1(x) - x = self.bn1(x) - x = self.relu(x) - x = self.maxpool(x) - - outs = [] - for layer in self.layers: - x = layer(x) - outs.append(x) - - return tuple(outs) - - def init_backbone(self, path): - """ Initializes the backbone weights for training. """ - state_dict = torch.load(path) - - # Replace layer1 -> layers.0 etc. - keys = list(state_dict) - for key in keys: - if key.startswith('layer'): - idx = int(key[5]) - new_key = 'layers.' + str(idx-1) + key[6:] - state_dict[new_key] = state_dict.pop(key) - - # Note: Using strict=False is berry scary. Triple check this. - self.load_state_dict(state_dict, strict=False) - - def add_layer(self, conv_channels=1024, downsample=2, depth=1, block=Bottleneck): - """ Add a downsample layer to the backbone as per what SSD does. """ - self._make_layer(block, conv_channels // block.expansion, blocks=depth, stride=downsample) - - - - -class ResNetBackboneGN(ResNetBackbone): - - def __init__(self, layers, num_groups=32): - super().__init__(layers, norm_layer=lambda x: nn.GroupNorm(num_groups, x)) - - def init_backbone(self, path): - """ The path here comes from detectron. So we load it differently. """ - with open(path, 'rb') as f: - state_dict = pickle.load(f, encoding='latin1') # From the detectron source - state_dict = state_dict['blobs'] - - our_state_dict_keys = list(self.state_dict().keys()) - new_state_dict = {} - - gn_trans = lambda x: ('gn_s' if x == 'weight' else 'gn_b') - layeridx2res = lambda x: 'res' + str(int(x)+2) - block2branch = lambda x: 'branch2' + ('a', 'b', 'c')[int(x[-1:])-1] - - # Transcribe each Detectron weights name to a Yolact weights name - for key in our_state_dict_keys: - parts = key.split('.') - transcribed_key = '' - - if (parts[0] == 'conv1'): - transcribed_key = 'conv1_w' - elif (parts[0] == 'bn1'): - transcribed_key = 'conv1_' + gn_trans(parts[1]) - elif (parts[0] == 'layers'): - if int(parts[1]) >= self.num_base_layers: continue - - transcribed_key = layeridx2res(parts[1]) - transcribed_key += '_' + parts[2] + '_' - - if parts[3] == 'downsample': - transcribed_key += 'branch1_' - - if parts[4] == '0': - transcribed_key += 'w' - else: - transcribed_key += gn_trans(parts[5]) - else: - transcribed_key += block2branch(parts[3]) + '_' - - if 'conv' in parts[3]: - transcribed_key += 'w' - else: - transcribed_key += gn_trans(parts[4]) - - new_state_dict[key] = torch.Tensor(state_dict[transcribed_key]) - - # strict=False because we may have extra unitialized layers at this point - self.load_state_dict(new_state_dict, strict=False) - - - - - - - -def darknetconvlayer(in_channels, out_channels, *args, **kwdargs): - """ - Implements a conv, activation, then batch norm. - Arguments are passed into the conv layer. - """ - return nn.Sequential( - nn.Conv2d(in_channels, out_channels, *args, **kwdargs, bias=False), - nn.BatchNorm2d(out_channels), - # Darknet uses 0.1 here. - # See https://github.com/pjreddie/darknet/blob/680d3bde1924c8ee2d1c1dea54d3e56a05ca9a26/src/activations.h#L39 - nn.LeakyReLU(0.1, inplace=True) - ) - -class DarkNetBlock(nn.Module): - """ Note: channels is the lesser of the two. The output will be expansion * channels. """ - - expansion = 2 - - def __init__(self, in_channels, channels): - super().__init__() - - self.conv1 = darknetconvlayer(in_channels, channels, kernel_size=1) - self.conv2 = darknetconvlayer(channels, channels * self.expansion, kernel_size=3, padding=1) - - def forward(self, x): - return self.conv2(self.conv1(x)) + x - - - - -class DarkNetBackbone(nn.Module): - """ - An implementation of YOLOv3's Darnet53 in - https://pjreddie.com/media/files/papers/YOLOv3.pdf - - This is based off of the implementation of Resnet above. - """ - - def __init__(self, layers=[1, 2, 8, 8, 4], block=DarkNetBlock): - super().__init__() - - # These will be populated by _make_layer - self.num_base_layers = len(layers) - self.layers = nn.ModuleList() - self.channels = [] - - self._preconv = darknetconvlayer(3, 32, kernel_size=3, padding=1) - self.in_channels = 32 - - self._make_layer(block, 32, layers[0]) - self._make_layer(block, 64, layers[1]) - self._make_layer(block, 128, layers[2]) - self._make_layer(block, 256, layers[3]) - self._make_layer(block, 512, layers[4]) - - # This contains every module that should be initialized by loading in pretrained weights. - # Any extra layers added onto this that won't be initialized by init_backbone will not be - # in this list. That way, Yolact::init_weights knows which backbone weights to initialize - # with xavier, and which ones to leave alone. - self.backbone_modules = [m for m in self.modules() if isinstance(m, nn.Conv2d)] - - def _make_layer(self, block, channels, num_blocks, stride=2): - """ Here one layer means a string of n blocks. """ - layer_list = [] - - # The downsample layer - layer_list.append( - darknetconvlayer(self.in_channels, channels * block.expansion, - kernel_size=3, padding=1, stride=stride)) - - # Each block inputs channels and outputs channels * expansion - self.in_channels = channels * block.expansion - layer_list += [block(self.in_channels, channels) for _ in range(num_blocks)] - - self.channels.append(self.in_channels) - self.layers.append(nn.Sequential(*layer_list)) - - def forward(self, x): - """ Returns a list of convouts for each layer. """ - - x = self._preconv(x) - - outs = [] - for layer in self.layers: - x = layer(x) - outs.append(x) - - return tuple(outs) - - def add_layer(self, conv_channels=1024, stride=2, depth=1, block=DarkNetBlock): - """ Add a downsample layer to the backbone as per what SSD does. """ - self._make_layer(block, conv_channels // block.expansion, num_blocks=depth, stride=stride) - - def init_backbone(self, path): - """ Initializes the backbone weights for training. """ - # Note: Using strict=False is berry scary. Triple check this. - self.load_state_dict(torch.load(path), strict=False) - - - - - -class VGGBackbone(nn.Module): - """ - Args: - - cfg: A list of layers given as lists. Layers can be either 'M' signifying - a max pooling layer, a number signifying that many feature maps in - a conv layer, or a tuple of 'M' or a number and a kwdargs dict to pass - into the function that creates the layer (e.g. nn.MaxPool2d for 'M'). - - extra_args: A list of lists of arguments to pass into add_layer. - - norm_layers: Layers indices that need to pass through an l2norm layer. - """ - - def __init__(self, cfg, extra_args=[], norm_layers=[]): - super().__init__() - - self.channels = [] - self.layers = nn.ModuleList() - self.in_channels = 3 - self.extra_args = list(reversed(extra_args)) # So I can use it as a stack - - # Keeps track of what the corresponding key will be in the state dict of the - # pretrained model. For instance, layers.0.2 for us is 2 for the pretrained - # model but layers.1.1 is 5. - self.total_layer_count = 0 - self.state_dict_lookup = {} - - for idx, layer_cfg in enumerate(cfg): - self._make_layer(layer_cfg) - - self.norms = nn.ModuleList([nn.BatchNorm2d(self.channels[l]) for l in norm_layers]) - self.norm_lookup = {l: idx for idx, l in enumerate(norm_layers)} - - # These modules will be initialized by init_backbone, - # so don't overwrite their initialization later. - self.backbone_modules = [m for m in self.modules() if isinstance(m, nn.Conv2d)] - - def _make_layer(self, cfg): - """ - Each layer is a sequence of conv layers usually preceded by a max pooling. - Adapted from torchvision.models.vgg.make_layers. - """ - - layers = [] - - for v in cfg: - # VGG in SSD requires some special layers, so allow layers to be tuples of - # (, kwdargs dict) - args = None - if isinstance(v, tuple): - args = v[1] - v = v[0] - - # v should be either M or a number - if v == 'M': - # Set default arguments - if args is None: - args = {'kernel_size': 2, 'stride': 2} - - layers.append(nn.MaxPool2d(**args)) - else: - # See the comment in __init__ for an explanation of this - cur_layer_idx = self.total_layer_count + len(layers) - self.state_dict_lookup[cur_layer_idx] = '%d.%d' % (len(self.layers), len(layers)) - - # Set default arguments - if args is None: - args = {'kernel_size': 3, 'padding': 1} - - # Add the layers - layers.append(nn.Conv2d(self.in_channels, v, **args)) - layers.append(nn.ReLU(inplace=True)) - self.in_channels = v - - self.total_layer_count += len(layers) - self.channels.append(self.in_channels) - self.layers.append(nn.Sequential(*layers)) - - def forward(self, x): - """ Returns a list of convouts for each layer. """ - outs = [] - - for idx, layer in enumerate(self.layers): - x = layer(x) - - # Apply an l2norm module to the selected layers - # Note that this differs from the original implemenetation - if idx in self.norm_lookup: - x = self.norms[self.norm_lookup[idx]](x) - outs.append(x) - - return tuple(outs) - - def transform_key(self, k): - """ Transform e.g. features.24.bias to layers.4.1.bias """ - vals = k.split('.') - layerIdx = self.state_dict_lookup[int(vals[0])] - return 'layers.%s.%s' % (layerIdx, vals[1]) - - def init_backbone(self, path): - """ Initializes the backbone weights for training. """ - state_dict = torch.load(path) - state_dict = OrderedDict([(self.transform_key(k), v) for k,v in state_dict.items()]) - - self.load_state_dict(state_dict, strict=False) - - def add_layer(self, conv_channels=128, downsample=2): - """ Add a downsample layer to the backbone as per what SSD does. """ - if len(self.extra_args) > 0: - conv_channels, downsample = self.extra_args.pop() - - padding = 1 if downsample > 1 else 0 - - layer = nn.Sequential( - nn.Conv2d(self.in_channels, conv_channels, kernel_size=1), - nn.ReLU(inplace=True), - nn.Conv2d(conv_channels, conv_channels*2, kernel_size=3, stride=downsample, padding=padding), - nn.ReLU(inplace=True) - ) - - self.in_channels = conv_channels*2 - self.channels.append(self.in_channels) - self.layers.append(layer) - - - - -def construct_backbone(cfg): - """ Constructs a backbone given a backbone config object (see config.py). """ - backbone = cfg.type(*cfg.args) - - # Add downsampling layers until we reach the number we need - num_layers = max(cfg.selected_layers) + 1 - - while len(backbone.layers) < num_layers: - backbone.add_layer() - - return backbone +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import torch.nn as nn +import pickle + +from collections import OrderedDict + +try: + from deform_conv import DCNv2 as DCN +except ImportError: + def DCN(*args, **kwdargs): + raise Exception('DCN could not be imported. If you want to use YOLACT++ models, compile DCN. Check the README for instructions.') + +class Bottleneck(nn.Module): + """ Adapted from torchvision.models.resnet """ + expansion = 4 + + def __init__(self, inplanes, planes, stride=1, downsample=None, norm_layer=nn.BatchNorm2d, dilation=1, use_dcn=False): + super(Bottleneck, self).__init__() + self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False, dilation=dilation) + self.bn1 = norm_layer(planes) + if use_dcn: + self.conv2 = DCN(planes, planes, kernel_size=3, stride=stride, + padding=dilation, dilation=dilation, deformable_groups=1) + self.conv2.bias.data.zero_() + self.conv2.conv_offset_mask.weight.data.zero_() + self.conv2.conv_offset_mask.bias.data.zero_() + else: + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, + padding=dilation, bias=False, dilation=dilation) + self.bn2 = norm_layer(planes) + self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False, dilation=dilation) + self.bn3 = norm_layer(planes * 4) + self.relu = nn.ReLU(inplace=True) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class ResNetBackbone(nn.Module): + """ Adapted from torchvision.models.resnet """ + + def __init__(self, layers, dcn_layers=[0, 0, 0, 0], dcn_interval=1, atrous_layers=[], block=Bottleneck, norm_layer=nn.BatchNorm2d): + super().__init__() + + # These will be populated by _make_layer + self.num_base_layers = len(layers) + self.layers = nn.ModuleList() + self.channels = [] + self.norm_layer = norm_layer + self.dilation = 1 + self.atrous_layers = atrous_layers + + # From torchvision.models.resnet.Resnet + self.inplanes = 64 + + self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False) + self.bn1 = norm_layer(64) + self.relu = nn.ReLU(inplace=True) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + + self._make_layer(block, 64, layers[0], dcn_layers=dcn_layers[0], dcn_interval=dcn_interval) + self._make_layer(block, 128, layers[1], stride=2, dcn_layers=dcn_layers[1], dcn_interval=dcn_interval) + self._make_layer(block, 256, layers[2], stride=2, dcn_layers=dcn_layers[2], dcn_interval=dcn_interval) + self._make_layer(block, 512, layers[3], stride=2, dcn_layers=dcn_layers[3], dcn_interval=dcn_interval) + + # This contains every module that should be initialized by loading in pretrained weights. + # Any extra layers added onto this that won't be initialized by init_backbone will not be + # in this list. That way, Yolact::init_weights knows which backbone weights to initialize + # with xavier, and which ones to leave alone. + self.backbone_modules = [m for m in self.modules() if isinstance(m, nn.Conv2d)] + + + def _make_layer(self, block, planes, blocks, stride=1, dcn_layers=0, dcn_interval=1): + """ Here one layer means a string of n Bottleneck blocks. """ + downsample = None + + # This is actually just to create the connection between layers, and not necessarily to + # downsample. Even if the second condition is met, it only downsamples when stride != 1 + if stride != 1 or self.inplanes != planes * block.expansion: + if len(self.layers) in self.atrous_layers: + self.dilation += 1 + stride = 1 + + downsample = nn.Sequential( + nn.Conv2d(self.inplanes, planes * block.expansion, + kernel_size=1, stride=stride, bias=False, + dilation=self.dilation), + self.norm_layer(planes * block.expansion), + ) + + layers = [] + use_dcn = (dcn_layers >= blocks) + layers.append(block(self.inplanes, planes, stride, downsample, self.norm_layer, self.dilation, use_dcn=use_dcn)) + self.inplanes = planes * block.expansion + for i in range(1, blocks): + use_dcn = ((i+dcn_layers) >= blocks) and (i % dcn_interval == 0) + layers.append(block(self.inplanes, planes, norm_layer=self.norm_layer, use_dcn=use_dcn)) + layer = nn.Sequential(*layers) + + self.channels.append(planes * block.expansion) + self.layers.append(layer) + + return layer + + def forward(self, x): + """ Returns a list of convouts for each layer. """ + + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + x = self.maxpool(x) + + outs = [] + for layer in self.layers: + x = layer(x) + outs.append(x) + + return tuple(outs) + + def init_backbone(self, path): + """ Initializes the backbone weights for training. """ + state_dict = torch.load(path) + + # Replace layer1 -> layers.0 etc. + keys = list(state_dict) + for key in keys: + if key.startswith('layer'): + idx = int(key[5]) + new_key = 'layers.' + str(idx-1) + key[6:] + state_dict[new_key] = state_dict.pop(key) + + # Note: Using strict=False is berry scary. Triple check this. + self.load_state_dict(state_dict, strict=False) + + def add_layer(self, conv_channels=1024, downsample=2, depth=1, block=Bottleneck): + """ Add a downsample layer to the backbone as per what SSD does. """ + self._make_layer(block, conv_channels // block.expansion, blocks=depth, stride=downsample) + + + + +class ResNetBackboneGN(ResNetBackbone): + + def __init__(self, layers, num_groups=32): + super().__init__(layers, norm_layer=lambda x: nn.GroupNorm(num_groups, x)) + + def init_backbone(self, path): + """ The path here comes from detectron. So we load it differently. """ + with open(path, 'rb') as f: + state_dict = pickle.load(f, encoding='latin1') # From the detectron source + state_dict = state_dict['blobs'] + + our_state_dict_keys = list(self.state_dict().keys()) + new_state_dict = {} + + gn_trans = lambda x: ('gn_s' if x == 'weight' else 'gn_b') + layeridx2res = lambda x: 'res' + str(int(x)+2) + block2branch = lambda x: 'branch2' + ('a', 'b', 'c')[int(x[-1:])-1] + + # Transcribe each Detectron weights name to a Yolact weights name + for key in our_state_dict_keys: + parts = key.split('.') + transcribed_key = '' + + if (parts[0] == 'conv1'): + transcribed_key = 'conv1_w' + elif (parts[0] == 'bn1'): + transcribed_key = 'conv1_' + gn_trans(parts[1]) + elif (parts[0] == 'layers'): + if int(parts[1]) >= self.num_base_layers: continue + + transcribed_key = layeridx2res(parts[1]) + transcribed_key += '_' + parts[2] + '_' + + if parts[3] == 'downsample': + transcribed_key += 'branch1_' + + if parts[4] == '0': + transcribed_key += 'w' + else: + transcribed_key += gn_trans(parts[5]) + else: + transcribed_key += block2branch(parts[3]) + '_' + + if 'conv' in parts[3]: + transcribed_key += 'w' + else: + transcribed_key += gn_trans(parts[4]) + + new_state_dict[key] = torch.Tensor(state_dict[transcribed_key]) + + # strict=False because we may have extra unitialized layers at this point + self.load_state_dict(new_state_dict, strict=False) + + + + + + + +def darknetconvlayer(in_channels, out_channels, *args, **kwdargs): + """ + Implements a conv, activation, then batch norm. + Arguments are passed into the conv layer. + """ + return nn.Sequential( + nn.Conv2d(in_channels, out_channels, *args, **kwdargs, bias=False), + nn.BatchNorm2d(out_channels), + # Darknet uses 0.1 here. + # See https://github.com/pjreddie/darknet/blob/680d3bde1924c8ee2d1c1dea54d3e56a05ca9a26/src/activations.h#L39 + nn.LeakyReLU(0.1, inplace=True) + ) + +class DarkNetBlock(nn.Module): + """ Note: channels is the lesser of the two. The output will be expansion * channels. """ + + expansion = 2 + + def __init__(self, in_channels, channels): + super().__init__() + + self.conv1 = darknetconvlayer(in_channels, channels, kernel_size=1) + self.conv2 = darknetconvlayer(channels, channels * self.expansion, kernel_size=3, padding=1) + + def forward(self, x): + return self.conv2(self.conv1(x)) + x + + + + +class DarkNetBackbone(nn.Module): + """ + An implementation of YOLOv3's Darnet53 in + https://pjreddie.com/media/files/papers/YOLOv3.pdf + + This is based off of the implementation of Resnet above. + """ + + def __init__(self, layers=[1, 2, 8, 8, 4], block=DarkNetBlock): + super().__init__() + + # These will be populated by _make_layer + self.num_base_layers = len(layers) + self.layers = nn.ModuleList() + self.channels = [] + + self._preconv = darknetconvlayer(3, 32, kernel_size=3, padding=1) + self.in_channels = 32 + + self._make_layer(block, 32, layers[0]) + self._make_layer(block, 64, layers[1]) + self._make_layer(block, 128, layers[2]) + self._make_layer(block, 256, layers[3]) + self._make_layer(block, 512, layers[4]) + + # This contains every module that should be initialized by loading in pretrained weights. + # Any extra layers added onto this that won't be initialized by init_backbone will not be + # in this list. That way, Yolact::init_weights knows which backbone weights to initialize + # with xavier, and which ones to leave alone. + self.backbone_modules = [m for m in self.modules() if isinstance(m, nn.Conv2d)] + + def _make_layer(self, block, channels, num_blocks, stride=2): + """ Here one layer means a string of n blocks. """ + layer_list = [] + + # The downsample layer + layer_list.append( + darknetconvlayer(self.in_channels, channels * block.expansion, + kernel_size=3, padding=1, stride=stride)) + + # Each block inputs channels and outputs channels * expansion + self.in_channels = channels * block.expansion + layer_list += [block(self.in_channels, channels) for _ in range(num_blocks)] + + self.channels.append(self.in_channels) + self.layers.append(nn.Sequential(*layer_list)) + + def forward(self, x): + """ Returns a list of convouts for each layer. """ + + x = self._preconv(x) + + outs = [] + for layer in self.layers: + x = layer(x) + outs.append(x) + + return tuple(outs) + + def add_layer(self, conv_channels=1024, stride=2, depth=1, block=DarkNetBlock): + """ Add a downsample layer to the backbone as per what SSD does. """ + self._make_layer(block, conv_channels // block.expansion, num_blocks=depth, stride=stride) + + def init_backbone(self, path): + """ Initializes the backbone weights for training. """ + # Note: Using strict=False is berry scary. Triple check this. + self.load_state_dict(torch.load(path), strict=False) + + + + + +class VGGBackbone(nn.Module): + """ + Args: + - cfg: A list of layers given as lists. Layers can be either 'M' signifying + a max pooling layer, a number signifying that many feature maps in + a conv layer, or a tuple of 'M' or a number and a kwdargs dict to pass + into the function that creates the layer (e.g. nn.MaxPool2d for 'M'). + - extra_args: A list of lists of arguments to pass into add_layer. + - norm_layers: Layers indices that need to pass through an l2norm layer. + """ + + def __init__(self, cfg, extra_args=[], norm_layers=[]): + super().__init__() + + self.channels = [] + self.layers = nn.ModuleList() + self.in_channels = 3 + self.extra_args = list(reversed(extra_args)) # So I can use it as a stack + + # Keeps track of what the corresponding key will be in the state dict of the + # pretrained model. For instance, layers.0.2 for us is 2 for the pretrained + # model but layers.1.1 is 5. + self.total_layer_count = 0 + self.state_dict_lookup = {} + + for idx, layer_cfg in enumerate(cfg): + self._make_layer(layer_cfg) + + self.norms = nn.ModuleList([nn.BatchNorm2d(self.channels[l]) for l in norm_layers]) + self.norm_lookup = {l: idx for idx, l in enumerate(norm_layers)} + + # These modules will be initialized by init_backbone, + # so don't overwrite their initialization later. + self.backbone_modules = [m for m in self.modules() if isinstance(m, nn.Conv2d)] + + def _make_layer(self, cfg): + """ + Each layer is a sequence of conv layers usually preceded by a max pooling. + Adapted from torchvision.models.vgg.make_layers. + """ + + layers = [] + + for v in cfg: + # VGG in SSD requires some special layers, so allow layers to be tuples of + # (, kwdargs dict) + args = None + if isinstance(v, tuple): + args = v[1] + v = v[0] + + # v should be either M or a number + if v == 'M': + # Set default arguments + if args is None: + args = {'kernel_size': 2, 'stride': 2} + + layers.append(nn.MaxPool2d(**args)) + else: + # See the comment in __init__ for an explanation of this + cur_layer_idx = self.total_layer_count + len(layers) + self.state_dict_lookup[cur_layer_idx] = '%d.%d' % (len(self.layers), len(layers)) + + # Set default arguments + if args is None: + args = {'kernel_size': 3, 'padding': 1} + + # Add the layers + layers.append(nn.Conv2d(self.in_channels, v, **args)) + layers.append(nn.ReLU(inplace=True)) + self.in_channels = v + + self.total_layer_count += len(layers) + self.channels.append(self.in_channels) + self.layers.append(nn.Sequential(*layers)) + + def forward(self, x): + """ Returns a list of convouts for each layer. """ + outs = [] + + for idx, layer in enumerate(self.layers): + x = layer(x) + + # Apply an l2norm module to the selected layers + # Note that this differs from the original implemenetation + if idx in self.norm_lookup: + x = self.norms[self.norm_lookup[idx]](x) + outs.append(x) + + return tuple(outs) + + def transform_key(self, k): + """ Transform e.g. features.24.bias to layers.4.1.bias """ + vals = k.split('.') + layerIdx = self.state_dict_lookup[int(vals[0])] + return 'layers.%s.%s' % (layerIdx, vals[1]) + + def init_backbone(self, path): + """ Initializes the backbone weights for training. """ + state_dict = torch.load(path) + state_dict = OrderedDict([(self.transform_key(k), v) for k,v in state_dict.items()]) + + self.load_state_dict(state_dict, strict=False) + + def add_layer(self, conv_channels=128, downsample=2): + """ Add a downsample layer to the backbone as per what SSD does. """ + if len(self.extra_args) > 0: + conv_channels, downsample = self.extra_args.pop() + + padding = 1 if downsample > 1 else 0 + + layer = nn.Sequential( + nn.Conv2d(self.in_channels, conv_channels, kernel_size=1), + nn.ReLU(inplace=True), + nn.Conv2d(conv_channels, conv_channels*2, kernel_size=3, stride=downsample, padding=padding), + nn.ReLU(inplace=True) + ) + + self.in_channels = conv_channels*2 + self.channels.append(self.in_channels) + self.layers.append(layer) + + + + +def construct_backbone(cfg): + """ Constructs a backbone given a backbone config object (see config.py). """ + backbone = cfg.type(*cfg.args) + + # Add downsampling layers until we reach the number we need + num_layers = max(cfg.selected_layers) + 1 + + while len(backbone.layers) < num_layers: + backbone.add_layer() + + return backbone diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/data/__init__.py b/PyTorch/contrib/cv/detection/YOLACT_plus/data/__init__.py index 65b2da8e88..67c0f019a0 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/data/__init__.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/data/__init__.py @@ -1,6 +1,6 @@ -from .config import * -from .coco import * - -import torch -import cv2 -import numpy as np +from .config import * +from .coco import * + +import torch +import cv2 +import numpy as np diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/data/coco.py b/PyTorch/contrib/cv/detection/YOLACT_plus/data/coco.py index 8dd0f1c279..35f42e5624 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/data/coco.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/data/coco.py @@ -1,311 +1,311 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import os.path as osp -import sys -import torch -import torch.utils.data as data -import torch.nn.functional as F -import cv2 -import numpy as np -from .config import cfg -from pycocotools import mask as maskUtils -import random - -def get_label_map(): - if cfg.dataset.label_map is None: - return {x+1: x+1 for x in range(len(cfg.dataset.class_names))} - else: - return cfg.dataset.label_map - -class COCOAnnotationTransform(object): - """Transforms a COCO annotation into a Tensor of bbox coords and label index - Initilized with a dictionary lookup of classnames to indexes - """ - def __init__(self): - self.label_map = get_label_map() - - def __call__(self, target, width, height): - """ - Args: - target (dict): COCO target json annotation as a python dict - height (int): height - width (int): width - Returns: - a list containing lists of bounding boxes [bbox coords, class idx] - """ - scale = np.array([width, height, width, height]) - res = [] - for obj in target: - if 'bbox' in obj: - bbox = obj['bbox'] - label_idx = obj['category_id'] - if label_idx >= 0: - label_idx = self.label_map[label_idx] - 1 - final_box = list(np.array([bbox[0], bbox[1], bbox[0]+bbox[2], bbox[1]+bbox[3]])/scale) - final_box.append(label_idx) - res += [final_box] # [xmin, ymin, xmax, ymax, label_idx] - else: - print("No bbox found for object ", obj) - - return res - - -class COCODetection(data.Dataset): - """`MS Coco Detection `_ Dataset. - Args: - root (string): Root directory where images are downloaded to. - 这里即为image_path,数据集图像路径 - - set_name (string): Name of the specific set of COCO images. - 自定义,用于标记 - - transform (callable, optional): A function/transform that augments the - raw images` - 图像增强方法 - - target_transform (callable, optional): A function/transform that takes - in the target (bbox) and transforms it. - 将数据集中的目标检测框(bounding box)等封装为一个专门的数据结构 - - prep_crowds (bool): Whether or not to prepare crowds for the evaluation step. - ? - """ - - def __init__(self, image_path, info_file, transform=None, - target_transform=None, - dataset_name='MS COCO', has_gt=True): - #has_gt中的gt代表ground truth,在监督学习中,数据是有标注的,以(x, t)的形式出现,其中x是输入数据,t是标注. - # 正确的t标注是ground truth, 错误的标记则不是。(也有人将所有标注数据都叫做ground truth) - - # Do this here because we have too many things named COCO - from pycocotools.coco import COCO - - if target_transform is None: - target_transform = COCOAnnotationTransform() - - self.root = image_path - self.coco = COCO(info_file) #加载标注文件, 其中COCO对象属性有1、anns :所有标注;2、catToImgs:{种类:[图像list]}的映射字典; - # 3、cats:图片中包含物体的种类;4、dataset:内含信息、许可、标注等;5、imgToAnns:{图像:[标注list]}的映射字典;6、imgs:全部图像 - - self.ids = list(self.coco.imgToAnns.keys()) - if len(self.ids) == 0 or not has_gt: #显然这个if块内语句基本不可能执行 - self.ids = list(self.coco.imgs.keys()) - - self.transform = transform #默认情况下,训练数据使用:SSDAugmentation,验证数据使用:baseTransform - self.target_transform = COCOAnnotationTransform() #82行的if块毫无意义 - - self.name = dataset_name - self.has_gt = has_gt - - def __getitem__(self, index): - """ - Args: - index (int): Index - Returns: - tuple: Tuple (image, (target, masks, num_crowds)). - target is the object returned by ``coco.loadAnns``. - """ - im, gt, masks, h, w, num_crowds = self.pull_item(index) - return (index, im), (gt, masks, num_crowds) - - def __len__(self): - return len(self.ids) - - def pull_item(self, index): - """ - Args: - index (int): Index - Returns: - tuple: Tuple (image, target, masks, height, width, crowd). - target is the object returned by ``coco.loadAnns``. - Note that if no crowd annotations exist, crowd will be None - """ - img_id = self.ids[index] - - if self.has_gt: - ann_ids = self.coco.getAnnIds(imgIds=img_id) - - # Target has {'segmentation', 'area', iscrowd', 'image_id', 'bbox', 'category_id'} - target = [x for x in self.coco.loadAnns(ann_ids) if x['image_id'] == img_id] - else: - target = [] - - # Separate out crowd annotations. These are annotations that signify a large crowd of - # objects of said class, where there is no annotation for each individual object. Both - # during testing and training, consider these crowds as neutral. - crowd = [x for x in target if ('iscrowd' in x and x['iscrowd'])] - target = [x for x in target if not ('iscrowd' in x and x['iscrowd'])] - num_crowds = len(crowd) - - for x in crowd: - x['category_id'] = -1 - - # This is so we ensure that all crowd annotations are at the end of the array - target += crowd - - # The split here is to have compatibility with both COCO2014 and 2017 annotations. - # In 2014, images have the pattern COCO_{train/val}2014_%012d.jpg, while in 2017 it's %012d.jpg. - # Our script downloads the images as %012d.jpg so convert accordingly. - file_name = self.coco.loadImgs(img_id)[0]['file_name'] - - if file_name.startswith('COCO'): - file_name = file_name.split('_')[-1] - - path = osp.join(self.root, file_name) - assert osp.exists(path), 'Image path does not exist: {}'.format(path) - - img = cv2.imread(path) - height, width, _ = img.shape - - if len(target) > 0: - # Pool all the masks for this image into one [num_objects,height,width] matrix - masks = [self.coco.annToMask(obj).reshape(-1) for obj in target] - masks = np.vstack(masks) - masks = masks.reshape(-1, height, width) - - if self.target_transform is not None and len(target) > 0: - target = self.target_transform(target, width, height) - - if self.transform is not None: - if len(target) > 0: - target = np.array(target) - img, masks, boxes, labels = self.transform(img, masks, target[:, :4], - {'num_crowds': num_crowds, 'labels': target[:, 4]}) - - # I stored num_crowds in labels so I didn't have to modify the entirety of augmentations - num_crowds = labels['num_crowds'] - labels = labels['labels'] - - target = np.hstack((boxes, np.expand_dims(labels, axis=1))) - else: - img, _, _, _ = self.transform(img, np.zeros((1, height, width), dtype=np.float), np.array([[0, 0, 1, 1]]), - {'num_crowds': 0, 'labels': np.array([0])}) - masks = None - target = None - - if target.shape[0] == 0: - print('Warning: Augmentation output an example with no ground truth. Resampling...') - return self.pull_item(random.randint(0, len(self.ids)-1)) - - return torch.from_numpy(img).permute(2, 0, 1), target, masks, height, width, num_crowds - - def pull_image(self, index): - '''Returns the original image object at index in PIL form - - Note: not using self.__getitem__(), as any transformations passed in - could mess up this functionality. - - Argument: - index (int): index of img to show - Return: - cv2 img - ''' - img_id = self.ids[index] - path = self.coco.loadImgs(img_id)[0]['file_name'] - return cv2.imread(osp.join(self.root, path), cv2.IMREAD_COLOR) - - def pull_anno(self, index): - '''Returns the original annotation of image at index - - Note: not using self.__getitem__(), as any transformations passed in - could mess up this functionality. - - Argument: - index (int): index of img to get annotation of - Return: - list: [img_id, [(label, bbox coords),...]] - eg: ('001718', [('dog', (96, 13, 438, 332))]) - ''' - img_id = self.ids[index] - ann_ids = self.coco.getAnnIds(imgIds=img_id) - return self.coco.loadAnns(ann_ids) - - def __repr__(self): - fmt_str = 'Dataset ' + self.__class__.__name__ + '\n' - fmt_str += ' Number of datapoints: {}\n'.format(self.__len__()) - fmt_str += ' Root Location: {}\n'.format(self.root) - tmp = ' Transforms (if any): ' - fmt_str += '{0}{1}\n'.format(tmp, self.transform.__repr__().replace('\n', '\n' + ' ' * len(tmp))) - tmp = ' Target Transforms (if any): ' - fmt_str += '{0}{1}'.format(tmp, self.target_transform.__repr__().replace('\n', '\n' + ' ' * len(tmp))) - return fmt_str - -def enforce_size(img, targets, masks, num_crowds, new_w, new_h): - """ Ensures that the image is the given size without distorting aspect ratio. """ - with torch.no_grad(): - _, h, w = img.size() - - if h == new_h and w == new_w: - return img, targets, masks, num_crowds - - # Resize the image so that it fits within new_w, new_h - w_prime = new_w - h_prime = h * new_w / w - - if h_prime > new_h: - w_prime *= new_h / h_prime - h_prime = new_h - - w_prime = int(w_prime) - h_prime = int(h_prime) - - # Do all the resizing - img = F.interpolate(img.unsqueeze(0), (h_prime, w_prime), mode='bilinear', align_corners=False) - img.squeeze_(0) - - # Act like each object is a color channel - masks = F.interpolate(masks.unsqueeze(0), (h_prime, w_prime), mode='bilinear', align_corners=False) - masks.squeeze_(0) - - # Scale bounding boxes (this will put them in the top left corner in the case of padding) - targets[:, [0, 2]] *= (w_prime / new_w) - targets[:, [1, 3]] *= (h_prime / new_h) - - # Finally, pad everything to be the new_w, new_h - pad_dims = (0, new_w - w_prime, 0, new_h - h_prime) - img = F.pad( img, pad_dims, mode='constant', value=0) - masks = F.pad(masks, pad_dims, mode='constant', value=0) - - return img, targets, masks, num_crowds - - - - -def detection_collate(batch): - """Custom collate fn for dealing with batches of images that have a different - number of associated object annotations (bounding boxes). - - Arguments: - batch: (tuple) A tuple of tensor images and (lists of annotations, masks) - - Return: - A tuple containing: - 1) (tensor) batch of images stacked on their 0 dim - 2) (list, list, list) annotations for a given image are stacked - on 0 dim. The output gt is a tuple of annotations and masks. - """ - targets = [] - imgs = [] - masks = [] - num_crowds = [] - - for sample in batch: - imgs.append(sample[0]) - targets.append(torch.FloatTensor(sample[1][0])) - masks.append(torch.FloatTensor(sample[1][1])) - num_crowds.append(sample[1][2]) - - return imgs, (targets, masks, num_crowds) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import os.path as osp +import sys +import torch +import torch.utils.data as data +import torch.nn.functional as F +import cv2 +import numpy as np +from .config import cfg +from pycocotools import mask as maskUtils +import random + +def get_label_map(): + if cfg.dataset.label_map is None: + return {x+1: x+1 for x in range(len(cfg.dataset.class_names))} + else: + return cfg.dataset.label_map + +class COCOAnnotationTransform(object): + """Transforms a COCO annotation into a Tensor of bbox coords and label index + Initilized with a dictionary lookup of classnames to indexes + """ + def __init__(self): + self.label_map = get_label_map() + + def __call__(self, target, width, height): + """ + Args: + target (dict): COCO target json annotation as a python dict + height (int): height + width (int): width + Returns: + a list containing lists of bounding boxes [bbox coords, class idx] + """ + scale = np.array([width, height, width, height]) + res = [] + for obj in target: + if 'bbox' in obj: + bbox = obj['bbox'] + label_idx = obj['category_id'] + if label_idx >= 0: + label_idx = self.label_map[label_idx] - 1 + final_box = list(np.array([bbox[0], bbox[1], bbox[0]+bbox[2], bbox[1]+bbox[3]])/scale) + final_box.append(label_idx) + res += [final_box] # [xmin, ymin, xmax, ymax, label_idx] + else: + print("No bbox found for object ", obj) + + return res + + +class COCODetection(data.Dataset): + """`MS Coco Detection `_ Dataset. + Args: + root (string): Root directory where images are downloaded to. + 这里即为image_path,数据集图像路径 + + set_name (string): Name of the specific set of COCO images. + 自定义,用于标记 + + transform (callable, optional): A function/transform that augments the + raw images` + 图像增强方法 + + target_transform (callable, optional): A function/transform that takes + in the target (bbox) and transforms it. + 将数据集中的目标检测框(bounding box)等封装为一个专门的数据结构 + + prep_crowds (bool): Whether or not to prepare crowds for the evaluation step. + ? + """ + + def __init__(self, image_path, info_file, transform=None, + target_transform=None, + dataset_name='MS COCO', has_gt=True): + #has_gt中的gt代表ground truth,在监督学习中,数据是有标注的,以(x, t)的形式出现,其中x是输入数据,t是标注. + # 正确的t标注是ground truth, 错误的标记则不是。(也有人将所有标注数据都叫做ground truth) + + # Do this here because we have too many things named COCO + from pycocotools.coco import COCO + + if target_transform is None: + target_transform = COCOAnnotationTransform() + + self.root = image_path + self.coco = COCO(info_file) #加载标注文件, 其中COCO对象属性有1、anns :所有标注;2、catToImgs:{种类:[图像list]}的映射字典; + # 3、cats:图片中包含物体的种类;4、dataset:内含信息、许可、标注等;5、imgToAnns:{图像:[标注list]}的映射字典;6、imgs:全部图像 + + self.ids = list(self.coco.imgToAnns.keys()) + if len(self.ids) == 0 or not has_gt: #显然这个if块内语句基本不可能执行 + self.ids = list(self.coco.imgs.keys()) + + self.transform = transform #默认情况下,训练数据使用:SSDAugmentation,验证数据使用:baseTransform + self.target_transform = COCOAnnotationTransform() #82行的if块毫无意义 + + self.name = dataset_name + self.has_gt = has_gt + + def __getitem__(self, index): + """ + Args: + index (int): Index + Returns: + tuple: Tuple (image, (target, masks, num_crowds)). + target is the object returned by ``coco.loadAnns``. + """ + im, gt, masks, h, w, num_crowds = self.pull_item(index) + return (index, im), (gt, masks, num_crowds) + + def __len__(self): + return len(self.ids) + + def pull_item(self, index): + """ + Args: + index (int): Index + Returns: + tuple: Tuple (image, target, masks, height, width, crowd). + target is the object returned by ``coco.loadAnns``. + Note that if no crowd annotations exist, crowd will be None + """ + img_id = self.ids[index] + + if self.has_gt: + ann_ids = self.coco.getAnnIds(imgIds=img_id) + + # Target has {'segmentation', 'area', iscrowd', 'image_id', 'bbox', 'category_id'} + target = [x for x in self.coco.loadAnns(ann_ids) if x['image_id'] == img_id] + else: + target = [] + + # Separate out crowd annotations. These are annotations that signify a large crowd of + # objects of said class, where there is no annotation for each individual object. Both + # during testing and training, consider these crowds as neutral. + crowd = [x for x in target if ('iscrowd' in x and x['iscrowd'])] + target = [x for x in target if not ('iscrowd' in x and x['iscrowd'])] + num_crowds = len(crowd) + + for x in crowd: + x['category_id'] = -1 + + # This is so we ensure that all crowd annotations are at the end of the array + target += crowd + + # The split here is to have compatibility with both COCO2014 and 2017 annotations. + # In 2014, images have the pattern COCO_{train/val}2014_%012d.jpg, while in 2017 it's %012d.jpg. + # Our script downloads the images as %012d.jpg so convert accordingly. + file_name = self.coco.loadImgs(img_id)[0]['file_name'] + + if file_name.startswith('COCO'): + file_name = file_name.split('_')[-1] + + path = osp.join(self.root, file_name) + assert osp.exists(path), 'Image path does not exist: {}'.format(path) + + img = cv2.imread(path) + height, width, _ = img.shape + + if len(target) > 0: + # Pool all the masks for this image into one [num_objects,height,width] matrix + masks = [self.coco.annToMask(obj).reshape(-1) for obj in target] + masks = np.vstack(masks) + masks = masks.reshape(-1, height, width) + + if self.target_transform is not None and len(target) > 0: + target = self.target_transform(target, width, height) + + if self.transform is not None: + if len(target) > 0: + target = np.array(target) + img, masks, boxes, labels = self.transform(img, masks, target[:, :4], + {'num_crowds': num_crowds, 'labels': target[:, 4]}) + + # I stored num_crowds in labels so I didn't have to modify the entirety of augmentations + num_crowds = labels['num_crowds'] + labels = labels['labels'] + + target = np.hstack((boxes, np.expand_dims(labels, axis=1))) + else: + img, _, _, _ = self.transform(img, np.zeros((1, height, width), dtype=np.float), np.array([[0, 0, 1, 1]]), + {'num_crowds': 0, 'labels': np.array([0])}) + masks = None + target = None + + if target.shape[0] == 0: + print('Warning: Augmentation output an example with no ground truth. Resampling...') + return self.pull_item(random.randint(0, len(self.ids)-1)) + + return torch.from_numpy(img).permute(2, 0, 1), target, masks, height, width, num_crowds + + def pull_image(self, index): + '''Returns the original image object at index in PIL form + + Note: not using self.__getitem__(), as any transformations passed in + could mess up this functionality. + + Argument: + index (int): index of img to show + Return: + cv2 img + ''' + img_id = self.ids[index] + path = self.coco.loadImgs(img_id)[0]['file_name'] + return cv2.imread(osp.join(self.root, path), cv2.IMREAD_COLOR) + + def pull_anno(self, index): + '''Returns the original annotation of image at index + + Note: not using self.__getitem__(), as any transformations passed in + could mess up this functionality. + + Argument: + index (int): index of img to get annotation of + Return: + list: [img_id, [(label, bbox coords),...]] + eg: ('001718', [('dog', (96, 13, 438, 332))]) + ''' + img_id = self.ids[index] + ann_ids = self.coco.getAnnIds(imgIds=img_id) + return self.coco.loadAnns(ann_ids) + + def __repr__(self): + fmt_str = 'Dataset ' + self.__class__.__name__ + '\n' + fmt_str += ' Number of datapoints: {}\n'.format(self.__len__()) + fmt_str += ' Root Location: {}\n'.format(self.root) + tmp = ' Transforms (if any): ' + fmt_str += '{0}{1}\n'.format(tmp, self.transform.__repr__().replace('\n', '\n' + ' ' * len(tmp))) + tmp = ' Target Transforms (if any): ' + fmt_str += '{0}{1}'.format(tmp, self.target_transform.__repr__().replace('\n', '\n' + ' ' * len(tmp))) + return fmt_str + +def enforce_size(img, targets, masks, num_crowds, new_w, new_h): + """ Ensures that the image is the given size without distorting aspect ratio. """ + with torch.no_grad(): + _, h, w = img.size() + + if h == new_h and w == new_w: + return img, targets, masks, num_crowds + + # Resize the image so that it fits within new_w, new_h + w_prime = new_w + h_prime = h * new_w / w + + if h_prime > new_h: + w_prime *= new_h / h_prime + h_prime = new_h + + w_prime = int(w_prime) + h_prime = int(h_prime) + + # Do all the resizing + img = F.interpolate(img.unsqueeze(0), (h_prime, w_prime), mode='bilinear', align_corners=False) + img.squeeze_(0) + + # Act like each object is a color channel + masks = F.interpolate(masks.unsqueeze(0), (h_prime, w_prime), mode='bilinear', align_corners=False) + masks.squeeze_(0) + + # Scale bounding boxes (this will put them in the top left corner in the case of padding) + targets[:, [0, 2]] *= (w_prime / new_w) + targets[:, [1, 3]] *= (h_prime / new_h) + + # Finally, pad everything to be the new_w, new_h + pad_dims = (0, new_w - w_prime, 0, new_h - h_prime) + img = F.pad( img, pad_dims, mode='constant', value=0) + masks = F.pad(masks, pad_dims, mode='constant', value=0) + + return img, targets, masks, num_crowds + + + + +def detection_collate(batch): + """Custom collate fn for dealing with batches of images that have a different + number of associated object annotations (bounding boxes). + + Arguments: + batch: (tuple) A tuple of tensor images and (lists of annotations, masks) + + Return: + A tuple containing: + 1) (tensor) batch of images stacked on their 0 dim + 2) (list, list, list) annotations for a given image are stacked + on 0 dim. The output gt is a tuple of annotations and masks. + """ + targets = [] + imgs = [] + masks = [] + num_crowds = [] + + for sample in batch: + imgs.append(sample[0]) + targets.append(torch.FloatTensor(sample[1][0])) + masks.append(torch.FloatTensor(sample[1][1])) + num_crowds.append(sample[1][2]) + + return imgs, (targets, masks, num_crowds) diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/data/config.py b/PyTorch/contrib/cv/detection/YOLACT_plus/data/config.py index 2d66aec919..ee30bae3ba 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/data/config.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/data/config.py @@ -1,842 +1,842 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 backbone import ResNetBackbone, VGGBackbone, ResNetBackboneGN, DarkNetBackbone -from math import sqrt -import torch - -# for making bounding boxes pretty -COLORS = ((244, 67, 54), - (233, 30, 99), - (156, 39, 176), - (103, 58, 183), - ( 63, 81, 181), - ( 33, 150, 243), - ( 3, 169, 244), - ( 0, 188, 212), - ( 0, 150, 136), - ( 76, 175, 80), - (139, 195, 74), - (205, 220, 57), - (255, 235, 59), - (255, 193, 7), - (255, 152, 0), - (255, 87, 34), - (121, 85, 72), - (158, 158, 158), - ( 96, 125, 139)) - - -# These are in BGR and are for ImageNet -MEANS = (103.94, 116.78, 123.68) -STD = (57.38, 57.12, 58.40) - -COCO_CLASSES = ('person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', - 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', - 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', - 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', - 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', - 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', - 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', - 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', - 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', - 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven', - 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', - 'scissors', 'teddy bear', 'hair drier', 'toothbrush') - -COCO_LABEL_MAP = { 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, - 9: 9, 10: 10, 11: 11, 13: 12, 14: 13, 15: 14, 16: 15, 17: 16, - 18: 17, 19: 18, 20: 19, 21: 20, 22: 21, 23: 22, 24: 23, 25: 24, - 27: 25, 28: 26, 31: 27, 32: 28, 33: 29, 34: 30, 35: 31, 36: 32, - 37: 33, 38: 34, 39: 35, 40: 36, 41: 37, 42: 38, 43: 39, 44: 40, - 46: 41, 47: 42, 48: 43, 49: 44, 50: 45, 51: 46, 52: 47, 53: 48, - 54: 49, 55: 50, 56: 51, 57: 52, 58: 53, 59: 54, 60: 55, 61: 56, - 62: 57, 63: 58, 64: 59, 65: 60, 67: 61, 70: 62, 72: 63, 73: 64, - 74: 65, 75: 66, 76: 67, 77: 68, 78: 69, 79: 70, 80: 71, 81: 72, - 82: 73, 84: 74, 85: 75, 86: 76, 87: 77, 88: 78, 89: 79, 90: 80} - - - -# ----------------------- CONFIG CLASS ----------------------- # - -class Config(object): - """ - Holds the configuration for anything you want it to. - To get the currently active config, call get_cfg(). - - To use, just do cfg.x instead of cfg['x']. - I made this because doing cfg['x'] all the time is dumb. - """ - - def __init__(self, config_dict): - for key, val in config_dict.items(): - self.__setattr__(key, val) - - def copy(self, new_config_dict={}): - """ - Copies this config into a new config object, making - the changes given by new_config_dict. - """ - - ret = Config(vars(self)) - - for key, val in new_config_dict.items(): - ret.__setattr__(key, val) - - return ret - - def replace(self, new_config_dict): - """ - Copies new_config_dict into this config object. - Note: new_config_dict can also be a config object. - """ - if isinstance(new_config_dict, Config): - new_config_dict = vars(new_config_dict) - - for key, val in new_config_dict.items(): - self.__setattr__(key, val) - - def print(self): - for k, v in vars(self).items(): - print(k, ' = ', v) - - - - - -# ----------------------- DATASETS ----------------------- # - -dataset_base = Config({ - 'name': 'Base Dataset', - - # Training images and annotations - 'train_images': './data/coco/images/', - 'train_info': 'path_to_annotation_file', - - # Validation images and annotations. - 'valid_images': './data/coco/images/', - 'valid_info': 'path_to_annotation_file', - - # Whether or not to load GT. If this is False, eval.py quantitative evaluation won't work. - 'has_gt': True, - - # A list of names for each of you classes. - 'class_names': COCO_CLASSES, - - # COCO class ids aren't sequential, so this is a bandage fix. If your ids aren't sequential, - # provide a map from category_id -> index in class_names + 1 (the +1 is there because it's 1-indexed). - # If not specified, this just assumes category ids start at 1 and increase sequentially. - 'label_map': None -}) - -coco2014_dataset = dataset_base.copy({ - 'name': 'COCO 2014', - - 'train_info': './data/coco/annotations/instances_train2014.json', - 'valid_info': './data/coco/annotations/instances_val2014.json', - - 'label_map': COCO_LABEL_MAP -}) - -coco2017_dataset = dataset_base.copy({ - 'name': 'COCO 2017', - - 'train_info': './data/coco/annotations/instances_train2017.json', - 'valid_info': './data/coco/annotations/instances_val2017.json', - - 'label_map': COCO_LABEL_MAP -}) - -coco2017_testdev_dataset = dataset_base.copy({ - 'name': 'COCO 2017 Test-Dev', - - 'valid_info': './data/coco/annotations/image_info_test-dev2017.json', - 'has_gt': False, - - 'label_map': COCO_LABEL_MAP -}) - -PASCAL_CLASSES = ("aeroplane", "bicycle", "bird", "boat", "bottle", - "bus", "car", "cat", "chair", "cow", "diningtable", - "dog", "horse", "motorbike", "person", "pottedplant", - "sheep", "sofa", "train", "tvmonitor") - -pascal_sbd_dataset = dataset_base.copy({ - 'name': 'Pascal SBD 2012', - - 'train_images': './data/sbd/img', - 'valid_images': './data/sbd/img', - - 'train_info': './data/sbd/pascal_sbd_train.json', - 'valid_info': './data/sbd/pascal_sbd_val.json', - - 'class_names': PASCAL_CLASSES, -}) - - - - - -# ----------------------- TRANSFORMS ----------------------- # - -resnet_transform = Config({ - 'channel_order': 'RGB', - 'normalize': True, - 'subtract_means': False, - 'to_float': False, -}) - -vgg_transform = Config({ - # Note that though vgg is traditionally BGR, - # the channel order of vgg_reducedfc.pth is RGB. - 'channel_order': 'RGB', - 'normalize': False, - 'subtract_means': True, - 'to_float': False, -}) - -darknet_transform = Config({ - 'channel_order': 'RGB', - 'normalize': False, - 'subtract_means': False, - 'to_float': True, -}) - - - - - -# ----------------------- BACKBONES ----------------------- # - -backbone_base = Config({ - 'name': 'Base Backbone', - 'path': 'path/to/pretrained/weights', - 'type': object, - 'args': tuple(), - 'transform': resnet_transform, - - 'selected_layers': list(), - 'pred_scales': list(), - 'pred_aspect_ratios': list(), - - 'use_pixel_scales': False, - 'preapply_sqrt': True, - 'use_square_anchors': False, -}) - -resnet101_backbone = backbone_base.copy({ - 'name': 'ResNet101', - 'path': 'resnet101_reducedfc.pth', - 'type': ResNetBackbone, - 'args': ([3, 4, 23, 3],), - 'transform': resnet_transform, - - 'selected_layers': list(range(2, 8)), - 'pred_scales': [[1]]*6, - 'pred_aspect_ratios': [ [[0.66685089, 1.7073535, 0.87508774, 1.16524493, 0.49059086]] ] * 6, -}) - -resnet101_gn_backbone = backbone_base.copy({ - 'name': 'ResNet101_GN', - 'path': 'R-101-GN.pkl', - 'type': ResNetBackboneGN, - 'args': ([3, 4, 23, 3],), - 'transform': resnet_transform, - - 'selected_layers': list(range(2, 8)), - 'pred_scales': [[1]]*6, - 'pred_aspect_ratios': [ [[0.66685089, 1.7073535, 0.87508774, 1.16524493, 0.49059086]] ] * 6, -}) - -resnet101_dcn_inter3_backbone = resnet101_backbone.copy({ - 'name': 'ResNet101_DCN_Interval3', - 'args': ([3, 4, 23, 3], [0, 4, 23, 3], 3), -}) - -resnet50_backbone = resnet101_backbone.copy({ - 'name': 'ResNet50', - 'path': 'resnet50-19c8e357.pth', - 'type': ResNetBackbone, - 'args': ([3, 4, 6, 3],), - 'transform': resnet_transform, -}) - -resnet50_dcnv2_backbone = resnet50_backbone.copy({ - 'name': 'ResNet50_DCNv2', - 'args': ([3, 4, 6, 3], [0, 4, 6, 3]), -}) - -darknet53_backbone = backbone_base.copy({ - 'name': 'DarkNet53', - 'path': 'darknet53.pth', - 'type': DarkNetBackbone, - 'args': ([1, 2, 8, 8, 4],), - 'transform': darknet_transform, - - 'selected_layers': list(range(3, 9)), - 'pred_scales': [[3.5, 4.95], [3.6, 4.90], [3.3, 4.02], [2.7, 3.10], [2.1, 2.37], [1.8, 1.92]], - 'pred_aspect_ratios': [ [[1, sqrt(2), 1/sqrt(2), sqrt(3), 1/sqrt(3)][:n], [1]] for n in [3, 5, 5, 5, 3, 3] ], -}) - -vgg16_arch = [[64, 64], - [ 'M', 128, 128], - [ 'M', 256, 256, 256], - [('M', {'kernel_size': 2, 'stride': 2, 'ceil_mode': True}), 512, 512, 512], - [ 'M', 512, 512, 512], - [('M', {'kernel_size': 3, 'stride': 1, 'padding': 1}), - (1024, {'kernel_size': 3, 'padding': 6, 'dilation': 6}), - (1024, {'kernel_size': 1})]] - -vgg16_backbone = backbone_base.copy({ - 'name': 'VGG16', - 'path': 'vgg16_reducedfc.pth', - 'type': VGGBackbone, - 'args': (vgg16_arch, [(256, 2), (128, 2), (128, 1), (128, 1)], [3]), - 'transform': vgg_transform, - - 'selected_layers': [3] + list(range(5, 10)), - 'pred_scales': [[5, 4]]*6, - 'pred_aspect_ratios': [ [[1], [1, sqrt(2), 1/sqrt(2), sqrt(3), 1/sqrt(3)][:n]] for n in [3, 5, 5, 5, 3, 3] ], -}) - - - - - -# ----------------------- MASK BRANCH TYPES ----------------------- # - -mask_type = Config({ - # Direct produces masks directly as the output of each pred module. - # This is denoted as fc-mask in the paper. - # Parameters: mask_size, use_gt_bboxes - 'direct': 0, - - # Lincomb produces coefficients as the output of each pred module then uses those coefficients - # to linearly combine features from a prototype network to create image-sized masks. - # Parameters: - # - masks_to_train (int): Since we're producing (near) full image masks, it'd take too much - # vram to backprop on every single mask. Thus we select only a subset. - # - mask_proto_src (int): The input layer to the mask prototype generation network. This is an - # index in backbone.layers. Use to use the image itself instead. - # - mask_proto_net (list): A list of layers in the mask proto network with the last one - # being where the masks are taken from. Each conv layer is in - # the form (num_features, kernel_size, **kwdargs). An empty - # list means to use the source for prototype masks. If the - # kernel_size is negative, this creates a deconv layer instead. - # If the kernel_size is negative and the num_features is None, - # this creates a simple bilinear interpolation layer instead. - # - mask_proto_bias (bool): Whether to include an extra coefficient that corresponds to a proto - # mask of all ones. - # - mask_proto_prototype_activation (func): The activation to apply to each prototype mask. - # - mask_proto_mask_activation (func): After summing the prototype masks with the predicted - # coeffs, what activation to apply to the final mask. - # - mask_proto_coeff_activation (func): The activation to apply to the mask coefficients. - # - mask_proto_crop (bool): If True, crop the mask with the predicted bbox during training. - # - mask_proto_crop_expand (float): If cropping, the percent to expand the cropping bbox by - # in each direction. This is to make the model less reliant - # on perfect bbox predictions. - # - mask_proto_loss (str [l1|disj]): If not None, apply an l1 or disjunctive regularization - # loss directly to the prototype masks. - # - mask_proto_binarize_downsampled_gt (bool): Binarize GT after dowsnampling during training? - # - mask_proto_normalize_mask_loss_by_sqrt_area (bool): Whether to normalize mask loss by sqrt(sum(gt)) - # - mask_proto_reweight_mask_loss (bool): Reweight mask loss such that background is divided by - # #background and foreground is divided by #foreground. - # - mask_proto_grid_file (str): The path to the grid file to use with the next option. - # This should be a numpy.dump file with shape [numgrids, h, w] - # where h and w are w.r.t. the mask_proto_src convout. - # - mask_proto_use_grid (bool): Whether to add extra grid features to the proto_net input. - # - mask_proto_coeff_gate (bool): Add an extra set of sigmoided coefficients that is multiplied - # into the predicted coefficients in order to "gate" them. - # - mask_proto_prototypes_as_features (bool): For each prediction module, downsample the prototypes - # to the convout size of that module and supply the prototypes as input - # in addition to the already supplied backbone features. - # - mask_proto_prototypes_as_features_no_grad (bool): If the above is set, don't backprop gradients to - # to the prototypes from the network head. - # - mask_proto_remove_empty_masks (bool): Remove masks that are downsampled to 0 during loss calculations. - # - mask_proto_reweight_coeff (float): The coefficient to multiple the forground pixels with if reweighting. - # - mask_proto_coeff_diversity_loss (bool): Apply coefficient diversity loss on the coefficients so that the same - # instance has similar coefficients. - # - mask_proto_coeff_diversity_alpha (float): The weight to use for the coefficient diversity loss. - # - mask_proto_normalize_emulate_roi_pooling (bool): Normalize the mask loss to emulate roi pooling's affect on loss. - # - mask_proto_double_loss (bool): Whether to use the old loss in addition to any special new losses. - # - mask_proto_double_loss_alpha (float): The alpha to weight the above loss. - # - mask_proto_split_prototypes_by_head (bool): If true, this will give each prediction head its own prototypes. - # - mask_proto_crop_with_pred_box (bool): Whether to crop with the predicted box or the gt box. - 'lincomb': 1, -}) - - - - - -# ----------------------- ACTIVATION FUNCTIONS ----------------------- # - -activation_func = Config({ - 'tanh': torch.tanh, - 'sigmoid': torch.sigmoid, - 'softmax': lambda x: torch.nn.functional.softmax(x, dim=-1), - 'relu': lambda x: torch.nn.functional.relu(x, inplace=True), - 'none': lambda x: x, -}) - - - - - -# ----------------------- FPN DEFAULTS ----------------------- # - -fpn_base = Config({ - # The number of features to have in each FPN layer - 'num_features': 256, - - # The upsampling mode used - 'interpolation_mode': 'bilinear', - - # The number of extra layers to be produced by downsampling starting at P5 - 'num_downsample': 1, - - # Whether to down sample with a 3x3 stride 2 conv layer instead of just a stride 2 selection - 'use_conv_downsample': False, - - # Whether to pad the pred layers with 1 on each side (I forgot to add this at the start) - # This is just here for backwards compatibility - 'pad': True, - - # Whether to add relu to the downsampled layers. - 'relu_downsample_layers': False, - - # Whether to add relu to the regular layers - 'relu_pred_layers': True, -}) - - - - - -# ----------------------- CONFIG DEFAULTS ----------------------- # - -coco_base_config = Config({ - 'dataset': coco2014_dataset, - 'num_classes': 81, # This should include the background class - - 'max_iter': 400000, - - # The maximum number of detections for evaluation - 'max_num_detections': 100, - - # dw' = momentum * dw - lr * (grad + decay * w) - 'lr': 1e-3, - 'momentum': 0.9, - 'decay': 5e-4, - - # For each lr step, what to multiply the lr with - 'gamma': 0.1, - 'lr_steps': (280000, 360000, 400000), - - # Initial learning rate to linearly warmup from (if until > 0) - 'lr_warmup_init': 1e-4, - - # If > 0 then increase the lr linearly from warmup_init to lr each iter for until iters - 'lr_warmup_until': 500, - - # The terms to scale the respective loss by - 'conf_alpha': 1, - 'bbox_alpha': 1.5, - 'mask_alpha': 0.4 / 256 * 140 * 140, # Some funky equation. Don't worry about it. - - # Eval.py sets this if you just want to run YOLACT as a detector - 'eval_mask_branch': True, - - # Top_k examples to consider for NMS - 'nms_top_k': 200, - # Examples with confidence less than this are not considered by NMS - 'nms_conf_thresh': 0.05, - # Boxes with IoU overlap greater than this threshold will be culled during NMS - 'nms_thresh': 0.5, - - # See mask_type for details. - 'mask_type': mask_type.direct, - 'mask_size': 16, - 'masks_to_train': 100, - 'mask_proto_src': None, - 'mask_proto_net': [(256, 3, {}), (256, 3, {})], - 'mask_proto_bias': False, - 'mask_proto_prototype_activation': activation_func.relu, - 'mask_proto_mask_activation': activation_func.sigmoid, - 'mask_proto_coeff_activation': activation_func.tanh, - 'mask_proto_crop': True, - 'mask_proto_crop_expand': 0, - 'mask_proto_loss': None, - 'mask_proto_binarize_downsampled_gt': True, - 'mask_proto_normalize_mask_loss_by_sqrt_area': False, - 'mask_proto_reweight_mask_loss': False, - 'mask_proto_grid_file': 'data/grid.npy', - 'mask_proto_use_grid': False, - 'mask_proto_coeff_gate': False, - 'mask_proto_prototypes_as_features': False, - 'mask_proto_prototypes_as_features_no_grad': False, - 'mask_proto_remove_empty_masks': False, - 'mask_proto_reweight_coeff': 1, - 'mask_proto_coeff_diversity_loss': False, - 'mask_proto_coeff_diversity_alpha': 1, - 'mask_proto_normalize_emulate_roi_pooling': False, - 'mask_proto_double_loss': False, - 'mask_proto_double_loss_alpha': 1, - 'mask_proto_split_prototypes_by_head': False, - 'mask_proto_crop_with_pred_box': False, - - # SSD data augmentation parameters - # Randomize hue, vibrance, etc. - 'augment_photometric_distort': True, - # Have a chance to scale down the image and pad (to emulate smaller detections) - 'augment_expand': True, - # Potentialy sample a random crop from the image and put it in a random place - 'augment_random_sample_crop': True, - # Mirror the image with a probability of 1/2 - 'augment_random_mirror': True, - # Flip the image vertically with a probability of 1/2 - 'augment_random_flip': False, - # With uniform probability, rotate the image [0,90,180,270] degrees - 'augment_random_rot90': False, - - # Discard detections with width and height smaller than this (in absolute width and height) - 'discard_box_width': 4 / 550, - 'discard_box_height': 4 / 550, - - # If using batchnorm anywhere in the backbone, freeze the batchnorm layer during training. - # Note: any additional batch norm layers after the backbone will not be frozen. - 'freeze_bn': False, - - # Set this to a config object if you want an FPN (inherit from fpn_base). See fpn_base for details. - 'fpn': None, - - # Use the same weights for each network head - 'share_prediction_module': False, - - # For hard negative mining, instead of using the negatives that are leastl confidently background, - # use negatives that are most confidently not background. - 'ohem_use_most_confident': False, - - # Use focal loss as described in https://arxiv.org/pdf/1708.02002.pdf instead of OHEM - 'use_focal_loss': False, - 'focal_loss_alpha': 0.25, - 'focal_loss_gamma': 2, - - # The initial bias toward forground objects, as specified in the focal loss paper - 'focal_loss_init_pi': 0.01, - - # Keeps track of the average number of examples for each class, and weights the loss for that class accordingly. - 'use_class_balanced_conf': False, - - # Whether to use sigmoid focal loss instead of softmax, all else being the same. - 'use_sigmoid_focal_loss': False, - - # Use class[0] to be the objectness score and class[1:] to be the softmax predicted class. - # Note: at the moment this is only implemented if use_focal_loss is on. - 'use_objectness_score': False, - - # Adds a global pool + fc layer to the smallest selected layer that predicts the existence of each of the 80 classes. - # This branch is only evaluated during training time and is just there for multitask learning. - 'use_class_existence_loss': False, - 'class_existence_alpha': 1, - - # Adds a 1x1 convolution directly to the biggest selected layer that predicts a semantic segmentations for each of the 80 classes. - # This branch is only evaluated during training time and is just there for multitask learning. - 'use_semantic_segmentation_loss': False, - 'semantic_segmentation_alpha': 1, - - # Adds another branch to the netwok to predict Mask IoU. - 'use_mask_scoring': False, - 'mask_scoring_alpha': 1, - - # Match gt boxes using the Box2Pix change metric instead of the standard IoU metric. - # Note that the threshold you set for iou_threshold should be negative with this setting on. - 'use_change_matching': False, - - # Uses the same network format as mask_proto_net, except this time it's for adding extra head layers before the final - # prediction in prediction modules. If this is none, no extra layers will be added. - 'extra_head_net': None, - - # What params should the final head layers have (the ones that predict box, confidence, and mask coeffs) - 'head_layer_params': {'kernel_size': 3, 'padding': 1}, - - # Add extra layers between the backbone and the network heads - # The order is (bbox, conf, mask) - 'extra_layers': (0, 0, 0), - - # During training, to match detections with gt, first compute the maximum gt IoU for each prior. - # Then, any of those priors whose maximum overlap is over the positive threshold, mark as positive. - # For any priors whose maximum is less than the negative iou threshold, mark them as negative. - # The rest are neutral and not used in calculating the loss. - 'positive_iou_threshold': 0.5, - 'negative_iou_threshold': 0.5, - - # When using ohem, the ratio between positives and negatives (3 means 3 negatives to 1 positive) - 'ohem_negpos_ratio': 3, - - # If less than 1, anchors treated as a negative that have a crowd iou over this threshold with - # the crowd boxes will be treated as a neutral. - 'crowd_iou_threshold': 1, - - # This is filled in at runtime by Yolact's __init__, so don't touch it - 'mask_dim': None, - - # Input image size. - 'max_size': 300, - - # Whether or not to do post processing on the cpu at test time - 'force_cpu_nms': True, - - # Whether to use mask coefficient cosine similarity nms instead of bbox iou nms - 'use_coeff_nms': False, - - # Whether or not to have a separate branch whose sole purpose is to act as the coefficients for coeff_diversity_loss - # Remember to turn on coeff_diversity_loss, or these extra coefficients won't do anything! - # To see their effect, also remember to turn on use_coeff_nms. - 'use_instance_coeff': False, - 'num_instance_coeffs': 64, - - # Whether or not to tie the mask loss / box loss to 0 - 'train_masks': True, - 'train_boxes': True, - # If enabled, the gt masks will be cropped using the gt bboxes instead of the predicted ones. - # This speeds up training time considerably but results in much worse mAP at test time. - 'use_gt_bboxes': False, - - # Whether or not to preserve aspect ratio when resizing the image. - # If True, this will resize all images to be max_size^2 pixels in area while keeping aspect ratio. - # If False, all images are resized to max_size x max_size - 'preserve_aspect_ratio': False, - - # Whether or not to use the prediction module (c) from DSSD - 'use_prediction_module': False, - - # Whether or not to use the predicted coordinate scheme from Yolo v2 - 'use_yolo_regressors': False, - - # For training, bboxes are considered "positive" if their anchors have a 0.5 IoU overlap - # or greater with a ground truth box. If this is true, instead of using the anchor boxes - # for this IoU computation, the matching function will use the predicted bbox coordinates. - # Don't turn this on if you're not using yolo regressors! - 'use_prediction_matching': False, - - # A list of settings to apply after the specified iteration. Each element of the list should look like - # (iteration, config_dict) where config_dict is a dictionary you'd pass into a config object's init. - 'delayed_settings': [], - - # Use command-line arguments to set this. - 'no_jit': False, - - 'backbone': None, - 'name': 'base_config', - - # Fast Mask Re-scoring Network - # Inspried by Mask Scoring R-CNN (https://arxiv.org/abs/1903.00241) - # Do not crop out the mask with bbox but slide a convnet on the image-size mask, - # then use global pooling to get the final mask score - 'use_maskiou': False, - - # Archecture for the mask iou network. A (num_classes-1, 1, {}) layer is appended to the end. - 'maskiou_net': [], - - # Discard predicted masks whose area is less than this - 'discard_mask_area': -1, - - 'maskiou_alpha': 1.0, - 'rescore_mask': False, - 'rescore_bbox': False, - 'maskious_to_train': -1, -}) - - - - - -# ----------------------- YOLACT v1.0 CONFIGS ----------------------- # - -yolact_base_config = coco_base_config.copy({ - 'name': 'yolact_base', - - # Dataset stuff - 'dataset': coco2017_dataset, - 'num_classes': len(coco2017_dataset.class_names) + 1, - - # Image Size - 'max_size': 550, - - # Training params - 'lr_steps': (280000, 600000, 700000, 750000), - 'max_iter': 1200000, - - # Backbone Settings - 'backbone': resnet101_backbone.copy({ - 'selected_layers': list(range(1, 4)), - 'use_pixel_scales': True, - 'preapply_sqrt': False, - 'use_square_anchors': True, # This is for backward compatability with a bug - - 'pred_aspect_ratios': [ [[1, 1/2, 2]] ]*5, - 'pred_scales': [[24], [48], [96], [192], [384]], - }), - - # FPN Settings - 'fpn': fpn_base.copy({ - 'use_conv_downsample': True, - 'num_downsample': 2, - }), - - # Mask Settings - 'mask_type': mask_type.lincomb, - 'mask_alpha': 6.125, - 'mask_proto_src': 0, - 'mask_proto_net': [(256, 3, {'padding': 1})] * 3 + [(None, -2, {}), (256, 3, {'padding': 1})] + [(32, 1, {})], - 'mask_proto_normalize_emulate_roi_pooling': True, - - # Other stuff - 'share_prediction_module': True, - 'extra_head_net': [(256, 3, {'padding': 1})], - - 'positive_iou_threshold': 0.5, - 'negative_iou_threshold': 0.4, - - 'crowd_iou_threshold': 0.7, - - 'use_semantic_segmentation_loss': True, -}) - -yolact_im400_config = yolact_base_config.copy({ - 'name': 'yolact_im400', - - 'max_size': 400, - 'backbone': yolact_base_config.backbone.copy({ - 'pred_scales': [[int(x[0] / yolact_base_config.max_size * 400)] for x in yolact_base_config.backbone.pred_scales], - }), -}) - -yolact_im700_config = yolact_base_config.copy({ - 'name': 'yolact_im700', - - 'masks_to_train': 300, - 'max_size': 700, - 'backbone': yolact_base_config.backbone.copy({ - 'pred_scales': [[int(x[0] / yolact_base_config.max_size * 700)] for x in yolact_base_config.backbone.pred_scales], - }), -}) - -yolact_darknet53_config = yolact_base_config.copy({ - 'name': 'yolact_darknet53', - - 'backbone': darknet53_backbone.copy({ - 'selected_layers': list(range(2, 5)), - - 'pred_scales': yolact_base_config.backbone.pred_scales, - 'pred_aspect_ratios': yolact_base_config.backbone.pred_aspect_ratios, - 'use_pixel_scales': True, - 'preapply_sqrt': False, - 'use_square_anchors': True, # This is for backward compatability with a bug - }), -}) - -yolact_resnet50_config = yolact_base_config.copy({ - 'name': 'yolact_resnet50', - - 'backbone': resnet50_backbone.copy({ - 'selected_layers': list(range(1, 4)), - - 'pred_scales': yolact_base_config.backbone.pred_scales, - 'pred_aspect_ratios': yolact_base_config.backbone.pred_aspect_ratios, - 'use_pixel_scales': True, - 'preapply_sqrt': False, - 'use_square_anchors': True, # This is for backward compatability with a bug - }), -}) - - -yolact_resnet50_pascal_config = yolact_resnet50_config.copy({ - 'name': None, # Will default to yolact_resnet50_pascal - - # Dataset stuff - 'dataset': pascal_sbd_dataset, - 'num_classes': len(pascal_sbd_dataset.class_names) + 1, - - 'max_iter': 120000, - 'lr_steps': (60000, 100000), - - 'backbone': yolact_resnet50_config.backbone.copy({ - 'pred_scales': [[32], [64], [128], [256], [512]], - 'use_square_anchors': False, - }) -}) - -# ----------------------- YOLACT++ CONFIGS ----------------------- # - -yolact_plus_base_config = yolact_base_config.copy({ - 'name': 'yolact_plus_base', - - 'backbone': resnet101_dcn_inter3_backbone.copy({ - 'selected_layers': list(range(1, 4)), - - 'pred_aspect_ratios': [ [[1, 1/2, 2]] ]*5, - 'pred_scales': [[i * 2 ** (j / 3.0) for j in range(3)] for i in [24, 48, 96, 192, 384]], - 'use_pixel_scales': True, - 'preapply_sqrt': False, - 'use_square_anchors': False, - }), - - 'use_maskiou': False, - 'maskiou_net': [(8, 3, {'stride': 2}), (16, 3, {'stride': 2}), (32, 3, {'stride': 2}), (64, 3, {'stride': 2}), (128, 3, {'stride': 2})], - 'maskiou_alpha': 25, - 'rescore_bbox': False, - 'rescore_mask': True, - - 'discard_mask_area': 5*5, -}) - -yolact_plus_resnet50_config = yolact_plus_base_config.copy({ - 'name': 'yolact_plus_resnet50', - - 'backbone': resnet50_dcnv2_backbone.copy({ - 'selected_layers': list(range(1, 4)), - - 'pred_aspect_ratios': [ [[1, 1/2, 2]] ]*5, - 'pred_scales': [[i * 2 ** (j / 3.0) for j in range(3)] for i in [24, 48, 96, 192, 384]], - 'use_pixel_scales': True, - 'preapply_sqrt': False, - 'use_square_anchors': False, - }), -}) -yolact_plus_resnet50_inf_config = yolact_plus_resnet50_config.copy({ - 'use_maskiou': True -}) - -# Default config -cfg = yolact_base_config.copy() - -def set_cfg(config_name:str): - """ Sets the active config. Works even if cfg is already imported! """ - global cfg - - # Note this is not just an eval because I'm lazy, but also because it can - # be used like ssd300_config.copy({'max_size': 400}) for extreme fine-tuning - cfg.replace(eval(config_name)) - - if cfg.name is None: - cfg.name = config_name.split('_config')[0] - -def set_dataset(dataset_name:str): - """ Sets the dataset of the current config. """ - cfg.dataset = eval(dataset_name) - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 backbone import ResNetBackbone, VGGBackbone, ResNetBackboneGN, DarkNetBackbone +from math import sqrt +import torch + +# for making bounding boxes pretty +COLORS = ((244, 67, 54), + (233, 30, 99), + (156, 39, 176), + (103, 58, 183), + ( 63, 81, 181), + ( 33, 150, 243), + ( 3, 169, 244), + ( 0, 188, 212), + ( 0, 150, 136), + ( 76, 175, 80), + (139, 195, 74), + (205, 220, 57), + (255, 235, 59), + (255, 193, 7), + (255, 152, 0), + (255, 87, 34), + (121, 85, 72), + (158, 158, 158), + ( 96, 125, 139)) + + +# These are in BGR and are for ImageNet +MEANS = (103.94, 116.78, 123.68) +STD = (57.38, 57.12, 58.40) + +COCO_CLASSES = ('person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', + 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', + 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', + 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', + 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', + 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', + 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', + 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', + 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', + 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven', + 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', + 'scissors', 'teddy bear', 'hair drier', 'toothbrush') + +COCO_LABEL_MAP = { 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, + 9: 9, 10: 10, 11: 11, 13: 12, 14: 13, 15: 14, 16: 15, 17: 16, + 18: 17, 19: 18, 20: 19, 21: 20, 22: 21, 23: 22, 24: 23, 25: 24, + 27: 25, 28: 26, 31: 27, 32: 28, 33: 29, 34: 30, 35: 31, 36: 32, + 37: 33, 38: 34, 39: 35, 40: 36, 41: 37, 42: 38, 43: 39, 44: 40, + 46: 41, 47: 42, 48: 43, 49: 44, 50: 45, 51: 46, 52: 47, 53: 48, + 54: 49, 55: 50, 56: 51, 57: 52, 58: 53, 59: 54, 60: 55, 61: 56, + 62: 57, 63: 58, 64: 59, 65: 60, 67: 61, 70: 62, 72: 63, 73: 64, + 74: 65, 75: 66, 76: 67, 77: 68, 78: 69, 79: 70, 80: 71, 81: 72, + 82: 73, 84: 74, 85: 75, 86: 76, 87: 77, 88: 78, 89: 79, 90: 80} + + + +# ----------------------- CONFIG CLASS ----------------------- # + +class Config(object): + """ + Holds the configuration for anything you want it to. + To get the currently active config, call get_cfg(). + + To use, just do cfg.x instead of cfg['x']. + I made this because doing cfg['x'] all the time is dumb. + """ + + def __init__(self, config_dict): + for key, val in config_dict.items(): + self.__setattr__(key, val) + + def copy(self, new_config_dict={}): + """ + Copies this config into a new config object, making + the changes given by new_config_dict. + """ + + ret = Config(vars(self)) + + for key, val in new_config_dict.items(): + ret.__setattr__(key, val) + + return ret + + def replace(self, new_config_dict): + """ + Copies new_config_dict into this config object. + Note: new_config_dict can also be a config object. + """ + if isinstance(new_config_dict, Config): + new_config_dict = vars(new_config_dict) + + for key, val in new_config_dict.items(): + self.__setattr__(key, val) + + def print(self): + for k, v in vars(self).items(): + print(k, ' = ', v) + + + + + +# ----------------------- DATASETS ----------------------- # + +dataset_base = Config({ + 'name': 'Base Dataset', + + # Training images and annotations + 'train_images': './data/coco/images/', + 'train_info': 'path_to_annotation_file', + + # Validation images and annotations. + 'valid_images': './data/coco/images/', + 'valid_info': 'path_to_annotation_file', + + # Whether or not to load GT. If this is False, eval.py quantitative evaluation won't work. + 'has_gt': True, + + # A list of names for each of you classes. + 'class_names': COCO_CLASSES, + + # COCO class ids aren't sequential, so this is a bandage fix. If your ids aren't sequential, + # provide a map from category_id -> index in class_names + 1 (the +1 is there because it's 1-indexed). + # If not specified, this just assumes category ids start at 1 and increase sequentially. + 'label_map': None +}) + +coco2014_dataset = dataset_base.copy({ + 'name': 'COCO 2014', + + 'train_info': './data/coco/annotations/instances_train2014.json', + 'valid_info': './data/coco/annotations/instances_val2014.json', + + 'label_map': COCO_LABEL_MAP +}) + +coco2017_dataset = dataset_base.copy({ + 'name': 'COCO 2017', + + 'train_info': './data/coco/annotations/instances_train2017.json', + 'valid_info': './data/coco/annotations/instances_val2017.json', + + 'label_map': COCO_LABEL_MAP +}) + +coco2017_testdev_dataset = dataset_base.copy({ + 'name': 'COCO 2017 Test-Dev', + + 'valid_info': './data/coco/annotations/image_info_test-dev2017.json', + 'has_gt': False, + + 'label_map': COCO_LABEL_MAP +}) + +PASCAL_CLASSES = ("aeroplane", "bicycle", "bird", "boat", "bottle", + "bus", "car", "cat", "chair", "cow", "diningtable", + "dog", "horse", "motorbike", "person", "pottedplant", + "sheep", "sofa", "train", "tvmonitor") + +pascal_sbd_dataset = dataset_base.copy({ + 'name': 'Pascal SBD 2012', + + 'train_images': './data/sbd/img', + 'valid_images': './data/sbd/img', + + 'train_info': './data/sbd/pascal_sbd_train.json', + 'valid_info': './data/sbd/pascal_sbd_val.json', + + 'class_names': PASCAL_CLASSES, +}) + + + + + +# ----------------------- TRANSFORMS ----------------------- # + +resnet_transform = Config({ + 'channel_order': 'RGB', + 'normalize': True, + 'subtract_means': False, + 'to_float': False, +}) + +vgg_transform = Config({ + # Note that though vgg is traditionally BGR, + # the channel order of vgg_reducedfc.pth is RGB. + 'channel_order': 'RGB', + 'normalize': False, + 'subtract_means': True, + 'to_float': False, +}) + +darknet_transform = Config({ + 'channel_order': 'RGB', + 'normalize': False, + 'subtract_means': False, + 'to_float': True, +}) + + + + + +# ----------------------- BACKBONES ----------------------- # + +backbone_base = Config({ + 'name': 'Base Backbone', + 'path': 'path/to/pretrained/weights', + 'type': object, + 'args': tuple(), + 'transform': resnet_transform, + + 'selected_layers': list(), + 'pred_scales': list(), + 'pred_aspect_ratios': list(), + + 'use_pixel_scales': False, + 'preapply_sqrt': True, + 'use_square_anchors': False, +}) + +resnet101_backbone = backbone_base.copy({ + 'name': 'ResNet101', + 'path': 'resnet101_reducedfc.pth', + 'type': ResNetBackbone, + 'args': ([3, 4, 23, 3],), + 'transform': resnet_transform, + + 'selected_layers': list(range(2, 8)), + 'pred_scales': [[1]]*6, + 'pred_aspect_ratios': [ [[0.66685089, 1.7073535, 0.87508774, 1.16524493, 0.49059086]] ] * 6, +}) + +resnet101_gn_backbone = backbone_base.copy({ + 'name': 'ResNet101_GN', + 'path': 'R-101-GN.pkl', + 'type': ResNetBackboneGN, + 'args': ([3, 4, 23, 3],), + 'transform': resnet_transform, + + 'selected_layers': list(range(2, 8)), + 'pred_scales': [[1]]*6, + 'pred_aspect_ratios': [ [[0.66685089, 1.7073535, 0.87508774, 1.16524493, 0.49059086]] ] * 6, +}) + +resnet101_dcn_inter3_backbone = resnet101_backbone.copy({ + 'name': 'ResNet101_DCN_Interval3', + 'args': ([3, 4, 23, 3], [0, 4, 23, 3], 3), +}) + +resnet50_backbone = resnet101_backbone.copy({ + 'name': 'ResNet50', + 'path': 'resnet50-19c8e357.pth', + 'type': ResNetBackbone, + 'args': ([3, 4, 6, 3],), + 'transform': resnet_transform, +}) + +resnet50_dcnv2_backbone = resnet50_backbone.copy({ + 'name': 'ResNet50_DCNv2', + 'args': ([3, 4, 6, 3], [0, 4, 6, 3]), +}) + +darknet53_backbone = backbone_base.copy({ + 'name': 'DarkNet53', + 'path': 'darknet53.pth', + 'type': DarkNetBackbone, + 'args': ([1, 2, 8, 8, 4],), + 'transform': darknet_transform, + + 'selected_layers': list(range(3, 9)), + 'pred_scales': [[3.5, 4.95], [3.6, 4.90], [3.3, 4.02], [2.7, 3.10], [2.1, 2.37], [1.8, 1.92]], + 'pred_aspect_ratios': [ [[1, sqrt(2), 1/sqrt(2), sqrt(3), 1/sqrt(3)][:n], [1]] for n in [3, 5, 5, 5, 3, 3] ], +}) + +vgg16_arch = [[64, 64], + [ 'M', 128, 128], + [ 'M', 256, 256, 256], + [('M', {'kernel_size': 2, 'stride': 2, 'ceil_mode': True}), 512, 512, 512], + [ 'M', 512, 512, 512], + [('M', {'kernel_size': 3, 'stride': 1, 'padding': 1}), + (1024, {'kernel_size': 3, 'padding': 6, 'dilation': 6}), + (1024, {'kernel_size': 1})]] + +vgg16_backbone = backbone_base.copy({ + 'name': 'VGG16', + 'path': 'vgg16_reducedfc.pth', + 'type': VGGBackbone, + 'args': (vgg16_arch, [(256, 2), (128, 2), (128, 1), (128, 1)], [3]), + 'transform': vgg_transform, + + 'selected_layers': [3] + list(range(5, 10)), + 'pred_scales': [[5, 4]]*6, + 'pred_aspect_ratios': [ [[1], [1, sqrt(2), 1/sqrt(2), sqrt(3), 1/sqrt(3)][:n]] for n in [3, 5, 5, 5, 3, 3] ], +}) + + + + + +# ----------------------- MASK BRANCH TYPES ----------------------- # + +mask_type = Config({ + # Direct produces masks directly as the output of each pred module. + # This is denoted as fc-mask in the paper. + # Parameters: mask_size, use_gt_bboxes + 'direct': 0, + + # Lincomb produces coefficients as the output of each pred module then uses those coefficients + # to linearly combine features from a prototype network to create image-sized masks. + # Parameters: + # - masks_to_train (int): Since we're producing (near) full image masks, it'd take too much + # vram to backprop on every single mask. Thus we select only a subset. + # - mask_proto_src (int): The input layer to the mask prototype generation network. This is an + # index in backbone.layers. Use to use the image itself instead. + # - mask_proto_net (list): A list of layers in the mask proto network with the last one + # being where the masks are taken from. Each conv layer is in + # the form (num_features, kernel_size, **kwdargs). An empty + # list means to use the source for prototype masks. If the + # kernel_size is negative, this creates a deconv layer instead. + # If the kernel_size is negative and the num_features is None, + # this creates a simple bilinear interpolation layer instead. + # - mask_proto_bias (bool): Whether to include an extra coefficient that corresponds to a proto + # mask of all ones. + # - mask_proto_prototype_activation (func): The activation to apply to each prototype mask. + # - mask_proto_mask_activation (func): After summing the prototype masks with the predicted + # coeffs, what activation to apply to the final mask. + # - mask_proto_coeff_activation (func): The activation to apply to the mask coefficients. + # - mask_proto_crop (bool): If True, crop the mask with the predicted bbox during training. + # - mask_proto_crop_expand (float): If cropping, the percent to expand the cropping bbox by + # in each direction. This is to make the model less reliant + # on perfect bbox predictions. + # - mask_proto_loss (str [l1|disj]): If not None, apply an l1 or disjunctive regularization + # loss directly to the prototype masks. + # - mask_proto_binarize_downsampled_gt (bool): Binarize GT after dowsnampling during training? + # - mask_proto_normalize_mask_loss_by_sqrt_area (bool): Whether to normalize mask loss by sqrt(sum(gt)) + # - mask_proto_reweight_mask_loss (bool): Reweight mask loss such that background is divided by + # #background and foreground is divided by #foreground. + # - mask_proto_grid_file (str): The path to the grid file to use with the next option. + # This should be a numpy.dump file with shape [numgrids, h, w] + # where h and w are w.r.t. the mask_proto_src convout. + # - mask_proto_use_grid (bool): Whether to add extra grid features to the proto_net input. + # - mask_proto_coeff_gate (bool): Add an extra set of sigmoided coefficients that is multiplied + # into the predicted coefficients in order to "gate" them. + # - mask_proto_prototypes_as_features (bool): For each prediction module, downsample the prototypes + # to the convout size of that module and supply the prototypes as input + # in addition to the already supplied backbone features. + # - mask_proto_prototypes_as_features_no_grad (bool): If the above is set, don't backprop gradients to + # to the prototypes from the network head. + # - mask_proto_remove_empty_masks (bool): Remove masks that are downsampled to 0 during loss calculations. + # - mask_proto_reweight_coeff (float): The coefficient to multiple the forground pixels with if reweighting. + # - mask_proto_coeff_diversity_loss (bool): Apply coefficient diversity loss on the coefficients so that the same + # instance has similar coefficients. + # - mask_proto_coeff_diversity_alpha (float): The weight to use for the coefficient diversity loss. + # - mask_proto_normalize_emulate_roi_pooling (bool): Normalize the mask loss to emulate roi pooling's affect on loss. + # - mask_proto_double_loss (bool): Whether to use the old loss in addition to any special new losses. + # - mask_proto_double_loss_alpha (float): The alpha to weight the above loss. + # - mask_proto_split_prototypes_by_head (bool): If true, this will give each prediction head its own prototypes. + # - mask_proto_crop_with_pred_box (bool): Whether to crop with the predicted box or the gt box. + 'lincomb': 1, +}) + + + + + +# ----------------------- ACTIVATION FUNCTIONS ----------------------- # + +activation_func = Config({ + 'tanh': torch.tanh, + 'sigmoid': torch.sigmoid, + 'softmax': lambda x: torch.nn.functional.softmax(x, dim=-1), + 'relu': lambda x: torch.nn.functional.relu(x, inplace=True), + 'none': lambda x: x, +}) + + + + + +# ----------------------- FPN DEFAULTS ----------------------- # + +fpn_base = Config({ + # The number of features to have in each FPN layer + 'num_features': 256, + + # The upsampling mode used + 'interpolation_mode': 'bilinear', + + # The number of extra layers to be produced by downsampling starting at P5 + 'num_downsample': 1, + + # Whether to down sample with a 3x3 stride 2 conv layer instead of just a stride 2 selection + 'use_conv_downsample': False, + + # Whether to pad the pred layers with 1 on each side (I forgot to add this at the start) + # This is just here for backwards compatibility + 'pad': True, + + # Whether to add relu to the downsampled layers. + 'relu_downsample_layers': False, + + # Whether to add relu to the regular layers + 'relu_pred_layers': True, +}) + + + + + +# ----------------------- CONFIG DEFAULTS ----------------------- # + +coco_base_config = Config({ + 'dataset': coco2014_dataset, + 'num_classes': 81, # This should include the background class + + 'max_iter': 400000, + + # The maximum number of detections for evaluation + 'max_num_detections': 100, + + # dw' = momentum * dw - lr * (grad + decay * w) + 'lr': 1e-3, + 'momentum': 0.9, + 'decay': 5e-4, + + # For each lr step, what to multiply the lr with + 'gamma': 0.1, + 'lr_steps': (280000, 360000, 400000), + + # Initial learning rate to linearly warmup from (if until > 0) + 'lr_warmup_init': 1e-4, + + # If > 0 then increase the lr linearly from warmup_init to lr each iter for until iters + 'lr_warmup_until': 500, + + # The terms to scale the respective loss by + 'conf_alpha': 1, + 'bbox_alpha': 1.5, + 'mask_alpha': 0.4 / 256 * 140 * 140, # Some funky equation. Don't worry about it. + + # Eval.py sets this if you just want to run YOLACT as a detector + 'eval_mask_branch': True, + + # Top_k examples to consider for NMS + 'nms_top_k': 200, + # Examples with confidence less than this are not considered by NMS + 'nms_conf_thresh': 0.05, + # Boxes with IoU overlap greater than this threshold will be culled during NMS + 'nms_thresh': 0.5, + + # See mask_type for details. + 'mask_type': mask_type.direct, + 'mask_size': 16, + 'masks_to_train': 100, + 'mask_proto_src': None, + 'mask_proto_net': [(256, 3, {}), (256, 3, {})], + 'mask_proto_bias': False, + 'mask_proto_prototype_activation': activation_func.relu, + 'mask_proto_mask_activation': activation_func.sigmoid, + 'mask_proto_coeff_activation': activation_func.tanh, + 'mask_proto_crop': True, + 'mask_proto_crop_expand': 0, + 'mask_proto_loss': None, + 'mask_proto_binarize_downsampled_gt': True, + 'mask_proto_normalize_mask_loss_by_sqrt_area': False, + 'mask_proto_reweight_mask_loss': False, + 'mask_proto_grid_file': 'data/grid.npy', + 'mask_proto_use_grid': False, + 'mask_proto_coeff_gate': False, + 'mask_proto_prototypes_as_features': False, + 'mask_proto_prototypes_as_features_no_grad': False, + 'mask_proto_remove_empty_masks': False, + 'mask_proto_reweight_coeff': 1, + 'mask_proto_coeff_diversity_loss': False, + 'mask_proto_coeff_diversity_alpha': 1, + 'mask_proto_normalize_emulate_roi_pooling': False, + 'mask_proto_double_loss': False, + 'mask_proto_double_loss_alpha': 1, + 'mask_proto_split_prototypes_by_head': False, + 'mask_proto_crop_with_pred_box': False, + + # SSD data augmentation parameters + # Randomize hue, vibrance, etc. + 'augment_photometric_distort': True, + # Have a chance to scale down the image and pad (to emulate smaller detections) + 'augment_expand': True, + # Potentialy sample a random crop from the image and put it in a random place + 'augment_random_sample_crop': True, + # Mirror the image with a probability of 1/2 + 'augment_random_mirror': True, + # Flip the image vertically with a probability of 1/2 + 'augment_random_flip': False, + # With uniform probability, rotate the image [0,90,180,270] degrees + 'augment_random_rot90': False, + + # Discard detections with width and height smaller than this (in absolute width and height) + 'discard_box_width': 4 / 550, + 'discard_box_height': 4 / 550, + + # If using batchnorm anywhere in the backbone, freeze the batchnorm layer during training. + # Note: any additional batch norm layers after the backbone will not be frozen. + 'freeze_bn': False, + + # Set this to a config object if you want an FPN (inherit from fpn_base). See fpn_base for details. + 'fpn': None, + + # Use the same weights for each network head + 'share_prediction_module': False, + + # For hard negative mining, instead of using the negatives that are leastl confidently background, + # use negatives that are most confidently not background. + 'ohem_use_most_confident': False, + + # Use focal loss as described in https://arxiv.org/pdf/1708.02002.pdf instead of OHEM + 'use_focal_loss': False, + 'focal_loss_alpha': 0.25, + 'focal_loss_gamma': 2, + + # The initial bias toward forground objects, as specified in the focal loss paper + 'focal_loss_init_pi': 0.01, + + # Keeps track of the average number of examples for each class, and weights the loss for that class accordingly. + 'use_class_balanced_conf': False, + + # Whether to use sigmoid focal loss instead of softmax, all else being the same. + 'use_sigmoid_focal_loss': False, + + # Use class[0] to be the objectness score and class[1:] to be the softmax predicted class. + # Note: at the moment this is only implemented if use_focal_loss is on. + 'use_objectness_score': False, + + # Adds a global pool + fc layer to the smallest selected layer that predicts the existence of each of the 80 classes. + # This branch is only evaluated during training time and is just there for multitask learning. + 'use_class_existence_loss': False, + 'class_existence_alpha': 1, + + # Adds a 1x1 convolution directly to the biggest selected layer that predicts a semantic segmentations for each of the 80 classes. + # This branch is only evaluated during training time and is just there for multitask learning. + 'use_semantic_segmentation_loss': False, + 'semantic_segmentation_alpha': 1, + + # Adds another branch to the netwok to predict Mask IoU. + 'use_mask_scoring': False, + 'mask_scoring_alpha': 1, + + # Match gt boxes using the Box2Pix change metric instead of the standard IoU metric. + # Note that the threshold you set for iou_threshold should be negative with this setting on. + 'use_change_matching': False, + + # Uses the same network format as mask_proto_net, except this time it's for adding extra head layers before the final + # prediction in prediction modules. If this is none, no extra layers will be added. + 'extra_head_net': None, + + # What params should the final head layers have (the ones that predict box, confidence, and mask coeffs) + 'head_layer_params': {'kernel_size': 3, 'padding': 1}, + + # Add extra layers between the backbone and the network heads + # The order is (bbox, conf, mask) + 'extra_layers': (0, 0, 0), + + # During training, to match detections with gt, first compute the maximum gt IoU for each prior. + # Then, any of those priors whose maximum overlap is over the positive threshold, mark as positive. + # For any priors whose maximum is less than the negative iou threshold, mark them as negative. + # The rest are neutral and not used in calculating the loss. + 'positive_iou_threshold': 0.5, + 'negative_iou_threshold': 0.5, + + # When using ohem, the ratio between positives and negatives (3 means 3 negatives to 1 positive) + 'ohem_negpos_ratio': 3, + + # If less than 1, anchors treated as a negative that have a crowd iou over this threshold with + # the crowd boxes will be treated as a neutral. + 'crowd_iou_threshold': 1, + + # This is filled in at runtime by Yolact's __init__, so don't touch it + 'mask_dim': None, + + # Input image size. + 'max_size': 300, + + # Whether or not to do post processing on the cpu at test time + 'force_cpu_nms': True, + + # Whether to use mask coefficient cosine similarity nms instead of bbox iou nms + 'use_coeff_nms': False, + + # Whether or not to have a separate branch whose sole purpose is to act as the coefficients for coeff_diversity_loss + # Remember to turn on coeff_diversity_loss, or these extra coefficients won't do anything! + # To see their effect, also remember to turn on use_coeff_nms. + 'use_instance_coeff': False, + 'num_instance_coeffs': 64, + + # Whether or not to tie the mask loss / box loss to 0 + 'train_masks': True, + 'train_boxes': True, + # If enabled, the gt masks will be cropped using the gt bboxes instead of the predicted ones. + # This speeds up training time considerably but results in much worse mAP at test time. + 'use_gt_bboxes': False, + + # Whether or not to preserve aspect ratio when resizing the image. + # If True, this will resize all images to be max_size^2 pixels in area while keeping aspect ratio. + # If False, all images are resized to max_size x max_size + 'preserve_aspect_ratio': False, + + # Whether or not to use the prediction module (c) from DSSD + 'use_prediction_module': False, + + # Whether or not to use the predicted coordinate scheme from Yolo v2 + 'use_yolo_regressors': False, + + # For training, bboxes are considered "positive" if their anchors have a 0.5 IoU overlap + # or greater with a ground truth box. If this is true, instead of using the anchor boxes + # for this IoU computation, the matching function will use the predicted bbox coordinates. + # Don't turn this on if you're not using yolo regressors! + 'use_prediction_matching': False, + + # A list of settings to apply after the specified iteration. Each element of the list should look like + # (iteration, config_dict) where config_dict is a dictionary you'd pass into a config object's init. + 'delayed_settings': [], + + # Use command-line arguments to set this. + 'no_jit': False, + + 'backbone': None, + 'name': 'base_config', + + # Fast Mask Re-scoring Network + # Inspried by Mask Scoring R-CNN (https://arxiv.org/abs/1903.00241) + # Do not crop out the mask with bbox but slide a convnet on the image-size mask, + # then use global pooling to get the final mask score + 'use_maskiou': False, + + # Archecture for the mask iou network. A (num_classes-1, 1, {}) layer is appended to the end. + 'maskiou_net': [], + + # Discard predicted masks whose area is less than this + 'discard_mask_area': -1, + + 'maskiou_alpha': 1.0, + 'rescore_mask': False, + 'rescore_bbox': False, + 'maskious_to_train': -1, +}) + + + + + +# ----------------------- YOLACT v1.0 CONFIGS ----------------------- # + +yolact_base_config = coco_base_config.copy({ + 'name': 'yolact_base', + + # Dataset stuff + 'dataset': coco2017_dataset, + 'num_classes': len(coco2017_dataset.class_names) + 1, + + # Image Size + 'max_size': 550, + + # Training params + 'lr_steps': (280000, 600000, 700000, 750000), + 'max_iter': 1200000, + + # Backbone Settings + 'backbone': resnet101_backbone.copy({ + 'selected_layers': list(range(1, 4)), + 'use_pixel_scales': True, + 'preapply_sqrt': False, + 'use_square_anchors': True, # This is for backward compatability with a bug + + 'pred_aspect_ratios': [ [[1, 1/2, 2]] ]*5, + 'pred_scales': [[24], [48], [96], [192], [384]], + }), + + # FPN Settings + 'fpn': fpn_base.copy({ + 'use_conv_downsample': True, + 'num_downsample': 2, + }), + + # Mask Settings + 'mask_type': mask_type.lincomb, + 'mask_alpha': 6.125, + 'mask_proto_src': 0, + 'mask_proto_net': [(256, 3, {'padding': 1})] * 3 + [(None, -2, {}), (256, 3, {'padding': 1})] + [(32, 1, {})], + 'mask_proto_normalize_emulate_roi_pooling': True, + + # Other stuff + 'share_prediction_module': True, + 'extra_head_net': [(256, 3, {'padding': 1})], + + 'positive_iou_threshold': 0.5, + 'negative_iou_threshold': 0.4, + + 'crowd_iou_threshold': 0.7, + + 'use_semantic_segmentation_loss': True, +}) + +yolact_im400_config = yolact_base_config.copy({ + 'name': 'yolact_im400', + + 'max_size': 400, + 'backbone': yolact_base_config.backbone.copy({ + 'pred_scales': [[int(x[0] / yolact_base_config.max_size * 400)] for x in yolact_base_config.backbone.pred_scales], + }), +}) + +yolact_im700_config = yolact_base_config.copy({ + 'name': 'yolact_im700', + + 'masks_to_train': 300, + 'max_size': 700, + 'backbone': yolact_base_config.backbone.copy({ + 'pred_scales': [[int(x[0] / yolact_base_config.max_size * 700)] for x in yolact_base_config.backbone.pred_scales], + }), +}) + +yolact_darknet53_config = yolact_base_config.copy({ + 'name': 'yolact_darknet53', + + 'backbone': darknet53_backbone.copy({ + 'selected_layers': list(range(2, 5)), + + 'pred_scales': yolact_base_config.backbone.pred_scales, + 'pred_aspect_ratios': yolact_base_config.backbone.pred_aspect_ratios, + 'use_pixel_scales': True, + 'preapply_sqrt': False, + 'use_square_anchors': True, # This is for backward compatability with a bug + }), +}) + +yolact_resnet50_config = yolact_base_config.copy({ + 'name': 'yolact_resnet50', + + 'backbone': resnet50_backbone.copy({ + 'selected_layers': list(range(1, 4)), + + 'pred_scales': yolact_base_config.backbone.pred_scales, + 'pred_aspect_ratios': yolact_base_config.backbone.pred_aspect_ratios, + 'use_pixel_scales': True, + 'preapply_sqrt': False, + 'use_square_anchors': True, # This is for backward compatability with a bug + }), +}) + + +yolact_resnet50_pascal_config = yolact_resnet50_config.copy({ + 'name': None, # Will default to yolact_resnet50_pascal + + # Dataset stuff + 'dataset': pascal_sbd_dataset, + 'num_classes': len(pascal_sbd_dataset.class_names) + 1, + + 'max_iter': 120000, + 'lr_steps': (60000, 100000), + + 'backbone': yolact_resnet50_config.backbone.copy({ + 'pred_scales': [[32], [64], [128], [256], [512]], + 'use_square_anchors': False, + }) +}) + +# ----------------------- YOLACT++ CONFIGS ----------------------- # + +yolact_plus_base_config = yolact_base_config.copy({ + 'name': 'yolact_plus_base', + + 'backbone': resnet101_dcn_inter3_backbone.copy({ + 'selected_layers': list(range(1, 4)), + + 'pred_aspect_ratios': [ [[1, 1/2, 2]] ]*5, + 'pred_scales': [[i * 2 ** (j / 3.0) for j in range(3)] for i in [24, 48, 96, 192, 384]], + 'use_pixel_scales': True, + 'preapply_sqrt': False, + 'use_square_anchors': False, + }), + + 'use_maskiou': False, + 'maskiou_net': [(8, 3, {'stride': 2}), (16, 3, {'stride': 2}), (32, 3, {'stride': 2}), (64, 3, {'stride': 2}), (128, 3, {'stride': 2})], + 'maskiou_alpha': 25, + 'rescore_bbox': False, + 'rescore_mask': True, + + 'discard_mask_area': 5*5, +}) + +yolact_plus_resnet50_config = yolact_plus_base_config.copy({ + 'name': 'yolact_plus_resnet50', + + 'backbone': resnet50_dcnv2_backbone.copy({ + 'selected_layers': list(range(1, 4)), + + 'pred_aspect_ratios': [ [[1, 1/2, 2]] ]*5, + 'pred_scales': [[i * 2 ** (j / 3.0) for j in range(3)] for i in [24, 48, 96, 192, 384]], + 'use_pixel_scales': True, + 'preapply_sqrt': False, + 'use_square_anchors': False, + }), +}) +yolact_plus_resnet50_inf_config = yolact_plus_resnet50_config.copy({ + 'use_maskiou': True +}) + +# Default config +cfg = yolact_base_config.copy() + +def set_cfg(config_name:str): + """ Sets the active config. Works even if cfg is already imported! """ + global cfg + + # Note this is not just an eval because I'm lazy, but also because it can + # be used like ssd300_config.copy({'max_size': 400}) for extreme fine-tuning + cfg.replace(eval(config_name)) + + if cfg.name is None: + cfg.name = config_name.split('_config')[0] + +def set_dataset(dataset_name:str): + """ Sets the dataset of the current config. """ + cfg.dataset = eval(dataset_name) + diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/data/scripts/COCO.sh b/PyTorch/contrib/cv/detection/YOLACT_plus/data/scripts/COCO.sh index da03b184e4..799cb135fb 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/data/scripts/COCO.sh +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/data/scripts/COCO.sh @@ -1,70 +1,70 @@ -#!/bin/bash - -start=`date +%s` - -# handle optional download dir -if [ -z "$1" ] - then - # navigate to ./data - echo "navigating to ./data/ ..." - mkdir -p ./data - cd ./data/ - mkdir -p ./coco - cd ./coco - mkdir -p ./images - mkdir -p ./annotations - else - # check if specified dir is valid - if [ ! -d $1 ]; then - echo $1 " is not a valid directory" - exit 0 - fi - echo "navigating to " $1 " ..." - cd $1 -fi - -if [ ! -d images ] - then - mkdir -p ./images -fi - -# Download the image data. -cd ./images -echo "Downloading MSCOCO train images ..." -curl -LO http://images.cocodataset.org/zips/train2017.zip -echo "Downloading MSCOCO val images ..." -curl -LO http://images.cocodataset.org/zips/val2017.zip - -cd ../ -if [ ! -d annotations ] - then - mkdir -p ./annotations -fi - -# Download the annotation data. -cd ./annotations -echo "Downloading MSCOCO train/val annotations ..." -curl -LO http://images.cocodataset.org/annotations/annotations_trainval2014.zip -curl -LO http://images.cocodataset.org/annotations/annotations_trainval2017.zip -echo "Finished downloading. Now extracting ..." - -# Unzip data -echo "Extracting train images ..." -unzip -qqjd ../images ../images/train2017.zip -echo "Extracting val images ..." -unzip -qqjd ../images ../images/val2017.zip -echo "Extracting annotations ..." -unzip -qqd .. ./annotations_trainval2014.zip -unzip -qqd .. ./annotations_trainval2017.zip - -echo "Removing zip files ..." -rm ../images/train2017.zip -rm ../images/val2017.zip -rm ./annotations_trainval2014.zip -rm ./annotations_trainval2017.zip - - -end=`date +%s` -runtime=$((end-start)) - -echo "Completed in " $runtime " seconds" +#!/bin/bash + +start=`date +%s` + +# handle optional download dir +if [ -z "$1" ] + then + # navigate to ./data + echo "navigating to ./data/ ..." + mkdir -p ./data + cd ./data/ + mkdir -p ./coco + cd ./coco + mkdir -p ./images + mkdir -p ./annotations + else + # check if specified dir is valid + if [ ! -d $1 ]; then + echo $1 " is not a valid directory" + exit 0 + fi + echo "navigating to " $1 " ..." + cd $1 +fi + +if [ ! -d images ] + then + mkdir -p ./images +fi + +# Download the image data. +cd ./images +echo "Downloading MSCOCO train images ..." +curl -LO http://images.cocodataset.org/zips/train2017.zip +echo "Downloading MSCOCO val images ..." +curl -LO http://images.cocodataset.org/zips/val2017.zip + +cd ../ +if [ ! -d annotations ] + then + mkdir -p ./annotations +fi + +# Download the annotation data. +cd ./annotations +echo "Downloading MSCOCO train/val annotations ..." +curl -LO http://images.cocodataset.org/annotations/annotations_trainval2014.zip +curl -LO http://images.cocodataset.org/annotations/annotations_trainval2017.zip +echo "Finished downloading. Now extracting ..." + +# Unzip data +echo "Extracting train images ..." +unzip -qqjd ../images ../images/train2017.zip +echo "Extracting val images ..." +unzip -qqjd ../images ../images/val2017.zip +echo "Extracting annotations ..." +unzip -qqd .. ./annotations_trainval2014.zip +unzip -qqd .. ./annotations_trainval2017.zip + +echo "Removing zip files ..." +rm ../images/train2017.zip +rm ../images/val2017.zip +rm ./annotations_trainval2014.zip +rm ./annotations_trainval2017.zip + + +end=`date +%s` +runtime=$((end-start)) + +echo "Completed in " $runtime " seconds" diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/data/scripts/COCO_test.sh b/PyTorch/contrib/cv/detection/YOLACT_plus/data/scripts/COCO_test.sh index 56d337b4d9..c876e57edd 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/data/scripts/COCO_test.sh +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/data/scripts/COCO_test.sh @@ -1,62 +1,62 @@ -#!/bin/bash - -start=`date +%s` - -# handle optional download dir -if [ -z "$1" ] - then - # navigate to ./data - echo "navigating to ./data/ ..." - mkdir -p ./data - cd ./data/ - mkdir -p ./coco - cd ./coco - mkdir -p ./images - mkdir -p ./annotations - else - # check if specified dir is valid - if [ ! -d $1 ]; then - echo $1 " is not a valid directory" - exit 0 - fi - echo "navigating to " $1 " ..." - cd $1 -fi - -if [ ! -d images ] - then - mkdir -p ./images -fi - -# Download the image data. -cd ./images -echo "Downloading MSCOCO test images ..." -curl -LO http://images.cocodataset.org/zips/test2017.zip - -cd ../ -if [ ! -d annotations ] - then - mkdir -p ./annotations -fi - -# Download the annotation data. -cd ./annotations -echo "Downloading MSCOCO test info ..." -curl -LO http://images.cocodataset.org/annotations/image_info_test2017.zip -echo "Finished downloading. Now extracting ..." - -# Unzip data -echo "Extracting train images ..." -unzip -qqjd ../images ../images/test2017.zip -echo "Extracting info ..." -unzip -qqd .. ./image_info_test2017.zip - -echo "Removing zip files ..." -rm ../images/test2017.zip -rm ./image_info_test2017.zip - - -end=`date +%s` -runtime=$((end-start)) - -echo "Completed in " $runtime " seconds" +#!/bin/bash + +start=`date +%s` + +# handle optional download dir +if [ -z "$1" ] + then + # navigate to ./data + echo "navigating to ./data/ ..." + mkdir -p ./data + cd ./data/ + mkdir -p ./coco + cd ./coco + mkdir -p ./images + mkdir -p ./annotations + else + # check if specified dir is valid + if [ ! -d $1 ]; then + echo $1 " is not a valid directory" + exit 0 + fi + echo "navigating to " $1 " ..." + cd $1 +fi + +if [ ! -d images ] + then + mkdir -p ./images +fi + +# Download the image data. +cd ./images +echo "Downloading MSCOCO test images ..." +curl -LO http://images.cocodataset.org/zips/test2017.zip + +cd ../ +if [ ! -d annotations ] + then + mkdir -p ./annotations +fi + +# Download the annotation data. +cd ./annotations +echo "Downloading MSCOCO test info ..." +curl -LO http://images.cocodataset.org/annotations/image_info_test2017.zip +echo "Finished downloading. Now extracting ..." + +# Unzip data +echo "Extracting train images ..." +unzip -qqjd ../images ../images/test2017.zip +echo "Extracting info ..." +unzip -qqd .. ./image_info_test2017.zip + +echo "Removing zip files ..." +rm ../images/test2017.zip +rm ./image_info_test2017.zip + + +end=`date +%s` +runtime=$((end-start)) + +echo "Completed in " $runtime " seconds" diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/data/scripts/mix_sets.py b/PyTorch/contrib/cv/detection/YOLACT_plus/data/scripts/mix_sets.py index 96e1a87589..5f70eacb53 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/data/scripts/mix_sets.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/data/scripts/mix_sets.py @@ -1,74 +1,74 @@ -import json -import os -import sys -from collections import defaultdict - -usage_text = """ -This script creates a coco annotation file by mixing one or more existing annotation files. - -Usage: python data/scripts/mix_sets.py output_name [set1 range1 [set2 range2 [...]]] - -To use, specify the output annotation name and any number of set + range pairs, where the sets -are in the form instances_.json and ranges are python-evalable ranges. The resulting -json will be spit out as instances_.json in the same folder as the input sets. - -For instance, - python data/scripts/mix_sets.py trainval35k train2014 : val2014 :-5000 - -This will create an instance_trainval35k.json file with all images and corresponding annotations -from train2014 and the first 35000 images from val2014. - -You can also specify only one set: - python data/scripts/mix_sets.py minival5k val2014 -5000: - -This will take the last 5k images from val2014 and put it in instances_minival5k.json. -""" - -annotations_path = 'data/coco/annotations/instances_%s.json' -fields_to_combine = ('images', 'annotations') -fields_to_steal = ('info', 'categories', 'licenses') - -if __name__ == '__main__': - if len(sys.argv) < 4 or len(sys.argv) % 2 != 0: - print(usage_text) - exit() - - out_name = sys.argv[1] - sets = sys.argv[2:] - sets = [(sets[2*i], sets[2*i+1]) for i in range(len(sets)//2)] - - out = {x: [] for x in fields_to_combine} - - for idx, (set_name, range_str) in enumerate(sets): - print('Loading set %s...' % set_name) - with open(annotations_path % set_name, 'r') as f: - set_json = json.load(f) - - # "Steal" some fields that don't need to be combined from the first set - if idx == 0: - for field in fields_to_steal: - out[field] = set_json[field] - - print('Building image index...') - image_idx = {x['id']: x for x in set_json['images']} - - print('Collecting annotations...') - anns_idx = defaultdict(lambda: []) - - for ann in set_json['annotations']: - anns_idx[ann['image_id']].append(ann) - - export_ids = list(image_idx.keys()) - export_ids.sort() - export_ids = eval('export_ids[%s]' % range_str, {}, {'export_ids': export_ids}) - - print('Adding %d images...' % len(export_ids)) - for _id in export_ids: - out['images'].append(image_idx[_id]) - out['annotations'] += anns_idx[_id] - - print('Done.\n') - - print('Saving result...') - with open(annotations_path % (out_name), 'w') as out_file: - json.dump(out, out_file) +import json +import os +import sys +from collections import defaultdict + +usage_text = """ +This script creates a coco annotation file by mixing one or more existing annotation files. + +Usage: python data/scripts/mix_sets.py output_name [set1 range1 [set2 range2 [...]]] + +To use, specify the output annotation name and any number of set + range pairs, where the sets +are in the form instances_.json and ranges are python-evalable ranges. The resulting +json will be spit out as instances_.json in the same folder as the input sets. + +For instance, + python data/scripts/mix_sets.py trainval35k train2014 : val2014 :-5000 + +This will create an instance_trainval35k.json file with all images and corresponding annotations +from train2014 and the first 35000 images from val2014. + +You can also specify only one set: + python data/scripts/mix_sets.py minival5k val2014 -5000: + +This will take the last 5k images from val2014 and put it in instances_minival5k.json. +""" + +annotations_path = 'data/coco/annotations/instances_%s.json' +fields_to_combine = ('images', 'annotations') +fields_to_steal = ('info', 'categories', 'licenses') + +if __name__ == '__main__': + if len(sys.argv) < 4 or len(sys.argv) % 2 != 0: + print(usage_text) + exit() + + out_name = sys.argv[1] + sets = sys.argv[2:] + sets = [(sets[2*i], sets[2*i+1]) for i in range(len(sets)//2)] + + out = {x: [] for x in fields_to_combine} + + for idx, (set_name, range_str) in enumerate(sets): + print('Loading set %s...' % set_name) + with open(annotations_path % set_name, 'r') as f: + set_json = json.load(f) + + # "Steal" some fields that don't need to be combined from the first set + if idx == 0: + for field in fields_to_steal: + out[field] = set_json[field] + + print('Building image index...') + image_idx = {x['id']: x for x in set_json['images']} + + print('Collecting annotations...') + anns_idx = defaultdict(lambda: []) + + for ann in set_json['annotations']: + anns_idx[ann['image_id']].append(ann) + + export_ids = list(image_idx.keys()) + export_ids.sort() + export_ids = eval('export_ids[%s]' % range_str, {}, {'export_ids': export_ids}) + + print('Adding %d images...' % len(export_ids)) + for _id in export_ids: + out['images'].append(image_idx[_id]) + out['annotations'] += anns_idx[_id] + + print('Done.\n') + + print('Saving result...') + with open(annotations_path % (out_name), 'w') as out_file: + json.dump(out, out_file) diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/deform_conv.py b/PyTorch/contrib/cv/detection/YOLACT_plus/deform_conv.py index bcf59fae04..b1ed2c6203 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/deform_conv.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/deform_conv.py @@ -1,235 +1,235 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import torch.nn as nn -from torch.autograd import Function -from torch.nn.modules.utils import _pair, _single -import math - - -class ModulatedDeformConv2dFunction(Function): - - @staticmethod - def forward(ctx, - input_tensor, - offset_ori, - mask, - weight, - bias=None, - with_bias=False, - stride=1, - padding=0, - dilation=1, - groups=1, - deformable_groups=1, - sort_index_for_npu_fp=None, - sort_index_for_npu_bp=None, - ): - - input_tensor = input_tensor.float() - offset_ori = offset_ori.float() - mask = mask.float() - - ctx.stride = stride - ctx.padding = padding - ctx.dilation = dilation - ctx.groups = groups - ctx.deformable_groups = deformable_groups - ctx.sort_index_for_npu_bp = sort_index_for_npu_bp - ctx.with_bias = with_bias - - offset = offset_ori.index_select(1, sort_index_for_npu_fp) - offset_all = torch.cat([offset, mask], dim=1) - output, offset_out = torch.npu_deformable_conv2d( - input_tensor, weight, offset_all, bias, - kernel_size=[weight.shape[3], weight.shape[2]], - stride=[1, 1, ctx.stride, ctx.stride], - padding=[ctx.padding, ctx.padding, ctx.padding, ctx.padding], - dilation=[1, 1, ctx.dilation, ctx.dilation], - groups=ctx.groups, deformable_groups=ctx.deformable_groups, - modulated=True) - if weight.requires_grad or mask.requires_grad or offset.requires_grad \ - or input_tensor.requires_grad: - ctx.save_for_backward(input_tensor, weight, offset_out, offset_all) - return output - - @staticmethod - def backward(ctx, grad_output): - input_tensor, weight, offset_out, offset_all = ctx.saved_tensors - grad_input, grad_weight, grad_offset_all, grad_bias = torch.npu_deformable_conv2dbk( - input_tensor, grad_output, offset_out, weight, offset_all, - kernel_size=[weight.shape[3], weight.shape[2]], - stride=[1, 1, ctx.stride, ctx.stride], - padding=[ctx.padding, ctx.padding, ctx.padding, ctx.padding], - dilation=[1, 1, ctx.dilation, ctx.dilation], - groups=ctx.groups, deformable_groups=ctx.deformable_groups, modulated=True) - grad_offset = grad_offset_all.index_select(1, ctx.sort_index_for_npu_bp) - grad_mask = grad_offset_all[:, grad_offset.shape[1]:, :, :] - if not ctx.with_bias: - grad_bias = None - - return (grad_input, grad_offset, grad_mask, grad_weight, grad_bias, - None, None, None, None, None, None, None, None) - - -class ModulatedDeformConv(nn.Module): - - def __init__(self, - in_channels, - out_channels, - kernel_size, - stride=1, - padding=0, - dilation=1, - groups=1, - deformable_groups=1, - bias=True, - pack=True, - ): - - r"""Applies an NPU based Modulated Deformable 2D convolution operation. - - Paper link: - [Deformable ConvNets v2: More Deformable, Better Results](https://arxiv.org/abs/1811.11168) - - Reference implementation link: - https://github.com/open-mmlab/mmcv/blob/master/mmcv/ops/modulated_deform_conv.py - - The implementation of this ModulatedDeformConv is mainly based - on the implementation of mmcv for design and reconstruction. - - In ModulatedDeformConvFunction, the forward and backward are customized, - and the input tensor is reconstructed ito match the NPU based function. - - It is worth mentioning that DeformConv(DCNv1) is also implemented - by setting modulated==False. Due to the difference between input - and initialization, there is no additional implementation here. - - .. note:: - ModulatedDeformConv only implements operations under fp32 data types. - Notice, weight and bias in conv_offset must be initialized to 0. - - Args: - in_channels (int): Number of channels in the input image. - out_channels (int): Number of channels produced by the convolution. - kernel_size(int, tuple): Size of the convolving kernel. - stride(int, tuple): Stride of the convolution. Default: 1. - padding (int or tuple): Zero-padding added to both sides of the input. - Default: 0. - dilation (int or tuple): Spacing between kernel elements. Default: 1. - groups (int): Number of blocked connections from input. - channels to output channels. Default: 1. - deform_groups (int): Number of deformable group partitions. - bias (bool): If True, adds a learnable bias to the output. Default: False. - pack (bool): If True, conv_offset and mask will be included in this module. Default: True. - - Examples:: - >>> m = ModulatedDeformConv(32, 32, 1) - >>> input_tensor = torch.randn(2, 32, 5, 5) - >>> output = m(input_tensor) - """ - - super(ModulatedDeformConv, self).__init__() - - self.in_channels = in_channels - self.out_channels = out_channels - self.kernel_size = _pair(kernel_size) - self.stride = stride - self.padding = padding - self.dilation = dilation - self.groups = groups - self.deformable_groups = deformable_groups - self.with_bias = bias - self.pack = pack - - self.weight = nn.Parameter( - torch.Tensor(out_channels, in_channels // groups, *self.kernel_size)) - if bias: - self.bias = nn.Parameter(torch.Tensor(out_channels)) - else: - self.bias = torch.zeros(self.weight.shape[0]) - - if self.pack: - self.conv_offset_mask = nn.Conv2d( - self.in_channels, - self.deformable_groups * 3 * self.kernel_size[0] * - self.kernel_size[1], - kernel_size=self.kernel_size, - stride=_pair(self.stride), - padding=_pair(self.padding), - bias=True) - - self.split_num = self.deformable_groups * 2 * self.kernel_size[0] * self.kernel_size[1] - sort_index_for_npu = list(range(self.split_num)) - sort_index_for_npu_fp = sort_index_for_npu[1::2] + sort_index_for_npu[::2] - sort_index_for_npu_bp_dict = {i: idx for idx, i in enumerate(sort_index_for_npu_fp)} - sort_index_for_npu_bp = [sort_index_for_npu_bp_dict[i] for i in sort_index_for_npu] - self.sort_index_for_npu_fp = torch.IntTensor(sort_index_for_npu_fp) - self.sort_index_for_npu_bp = torch.IntTensor(sort_index_for_npu_bp) - self.sort_index_for_npu_todevice = False - - self.init_param() - - def init_param(self): - n = self.in_channels - for k in self.kernel_size: - n *= k - stdv = 1. / math.sqrt(n) - self.weight.data.uniform_(-stdv, stdv) - if self.bias is not None: - self.bias.data.zero_() - - if self.pack: - self.conv_offset_mask.weight.data.zero_() - self.conv_offset_mask.bias.data.zero_() - - def forward(self, x): - if self.pack: - out = self.conv_offset_mask(x) - offset = out[:, :self.split_num, ...] - mask = torch.sigmoid(out[:, self.split_num:, ...]) - else: - x, offset, mask = x - - if not self.sort_index_for_npu_todevice: - self.sort_index_for_npu_fp = self.sort_index_for_npu_fp.to(x.device) - self.sort_index_for_npu_bp = self.sort_index_for_npu_bp.to(x.device) - self.bias = self.bias.to(x.device) - self.sort_index_for_npu_todevice = True - - return ModulatedDeformConv2dFunction.apply( - x, offset, mask, self.weight, self.bias, self.with_bias, - self.stride, self.padding, self.dilation, - self.groups, self.deformable_groups, - self.sort_index_for_npu_fp, - self.sort_index_for_npu_bp, - ) - - -DCNv2 = ModulatedDeformConv - -if __name__ == "__main__": - x = torch.randn(2, 32, 7, 7) - model = DCNv2(32, 32, 3, 2, 1) - - torch.npu.set_device(0) - x = x.npu() - model = model.npu() - - o = model(x) - l = o.sum() - l.backward() - print(l) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import torch.nn as nn +from torch.autograd import Function +from torch.nn.modules.utils import _pair, _single +import math + + +class ModulatedDeformConv2dFunction(Function): + + @staticmethod + def forward(ctx, + input_tensor, + offset_ori, + mask, + weight, + bias=None, + with_bias=False, + stride=1, + padding=0, + dilation=1, + groups=1, + deformable_groups=1, + sort_index_for_npu_fp=None, + sort_index_for_npu_bp=None, + ): + + input_tensor = input_tensor.float() + offset_ori = offset_ori.float() + mask = mask.float() + + ctx.stride = stride + ctx.padding = padding + ctx.dilation = dilation + ctx.groups = groups + ctx.deformable_groups = deformable_groups + ctx.sort_index_for_npu_bp = sort_index_for_npu_bp + ctx.with_bias = with_bias + + offset = offset_ori.index_select(1, sort_index_for_npu_fp) + offset_all = torch.cat([offset, mask], dim=1) + output, offset_out = torch.npu_deformable_conv2d( + input_tensor, weight, offset_all, bias, + kernel_size=[weight.shape[3], weight.shape[2]], + stride=[1, 1, ctx.stride, ctx.stride], + padding=[ctx.padding, ctx.padding, ctx.padding, ctx.padding], + dilation=[1, 1, ctx.dilation, ctx.dilation], + groups=ctx.groups, deformable_groups=ctx.deformable_groups, + modulated=True) + if weight.requires_grad or mask.requires_grad or offset.requires_grad \ + or input_tensor.requires_grad: + ctx.save_for_backward(input_tensor, weight, offset_out, offset_all) + return output + + @staticmethod + def backward(ctx, grad_output): + input_tensor, weight, offset_out, offset_all = ctx.saved_tensors + grad_input, grad_weight, grad_offset_all, grad_bias = torch.npu_deformable_conv2dbk( + input_tensor, grad_output, offset_out, weight, offset_all, + kernel_size=[weight.shape[3], weight.shape[2]], + stride=[1, 1, ctx.stride, ctx.stride], + padding=[ctx.padding, ctx.padding, ctx.padding, ctx.padding], + dilation=[1, 1, ctx.dilation, ctx.dilation], + groups=ctx.groups, deformable_groups=ctx.deformable_groups, modulated=True) + grad_offset = grad_offset_all.index_select(1, ctx.sort_index_for_npu_bp) + grad_mask = grad_offset_all[:, grad_offset.shape[1]:, :, :] + if not ctx.with_bias: + grad_bias = None + + return (grad_input, grad_offset, grad_mask, grad_weight, grad_bias, + None, None, None, None, None, None, None, None) + + +class ModulatedDeformConv(nn.Module): + + def __init__(self, + in_channels, + out_channels, + kernel_size, + stride=1, + padding=0, + dilation=1, + groups=1, + deformable_groups=1, + bias=True, + pack=True, + ): + + r"""Applies an NPU based Modulated Deformable 2D convolution operation. + + Paper link: + [Deformable ConvNets v2: More Deformable, Better Results](https://arxiv.org/abs/1811.11168) + + Reference implementation link: + https://github.com/open-mmlab/mmcv/blob/master/mmcv/ops/modulated_deform_conv.py + + The implementation of this ModulatedDeformConv is mainly based + on the implementation of mmcv for design and reconstruction. + + In ModulatedDeformConvFunction, the forward and backward are customized, + and the input tensor is reconstructed ito match the NPU based function. + + It is worth mentioning that DeformConv(DCNv1) is also implemented + by setting modulated==False. Due to the difference between input + and initialization, there is no additional implementation here. + + .. note:: + ModulatedDeformConv only implements operations under fp32 data types. + Notice, weight and bias in conv_offset must be initialized to 0. + + Args: + in_channels (int): Number of channels in the input image. + out_channels (int): Number of channels produced by the convolution. + kernel_size(int, tuple): Size of the convolving kernel. + stride(int, tuple): Stride of the convolution. Default: 1. + padding (int or tuple): Zero-padding added to both sides of the input. + Default: 0. + dilation (int or tuple): Spacing between kernel elements. Default: 1. + groups (int): Number of blocked connections from input. + channels to output channels. Default: 1. + deform_groups (int): Number of deformable group partitions. + bias (bool): If True, adds a learnable bias to the output. Default: False. + pack (bool): If True, conv_offset and mask will be included in this module. Default: True. + + Examples:: + >>> m = ModulatedDeformConv(32, 32, 1) + >>> input_tensor = torch.randn(2, 32, 5, 5) + >>> output = m(input_tensor) + """ + + super(ModulatedDeformConv, self).__init__() + + self.in_channels = in_channels + self.out_channels = out_channels + self.kernel_size = _pair(kernel_size) + self.stride = stride + self.padding = padding + self.dilation = dilation + self.groups = groups + self.deformable_groups = deformable_groups + self.with_bias = bias + self.pack = pack + + self.weight = nn.Parameter( + torch.Tensor(out_channels, in_channels // groups, *self.kernel_size)) + if bias: + self.bias = nn.Parameter(torch.Tensor(out_channels)) + else: + self.bias = torch.zeros(self.weight.shape[0]) + + if self.pack: + self.conv_offset_mask = nn.Conv2d( + self.in_channels, + self.deformable_groups * 3 * self.kernel_size[0] * + self.kernel_size[1], + kernel_size=self.kernel_size, + stride=_pair(self.stride), + padding=_pair(self.padding), + bias=True) + + self.split_num = self.deformable_groups * 2 * self.kernel_size[0] * self.kernel_size[1] + sort_index_for_npu = list(range(self.split_num)) + sort_index_for_npu_fp = sort_index_for_npu[1::2] + sort_index_for_npu[::2] + sort_index_for_npu_bp_dict = {i: idx for idx, i in enumerate(sort_index_for_npu_fp)} + sort_index_for_npu_bp = [sort_index_for_npu_bp_dict[i] for i in sort_index_for_npu] + self.sort_index_for_npu_fp = torch.IntTensor(sort_index_for_npu_fp) + self.sort_index_for_npu_bp = torch.IntTensor(sort_index_for_npu_bp) + self.sort_index_for_npu_todevice = False + + self.init_param() + + def init_param(self): + n = self.in_channels + for k in self.kernel_size: + n *= k + stdv = 1. / math.sqrt(n) + self.weight.data.uniform_(-stdv, stdv) + if self.bias is not None: + self.bias.data.zero_() + + if self.pack: + self.conv_offset_mask.weight.data.zero_() + self.conv_offset_mask.bias.data.zero_() + + def forward(self, x): + if self.pack: + out = self.conv_offset_mask(x) + offset = out[:, :self.split_num, ...] + mask = torch.sigmoid(out[:, self.split_num:, ...]) + else: + x, offset, mask = x + + if not self.sort_index_for_npu_todevice: + self.sort_index_for_npu_fp = self.sort_index_for_npu_fp.to(x.device) + self.sort_index_for_npu_bp = self.sort_index_for_npu_bp.to(x.device) + self.bias = self.bias.to(x.device) + self.sort_index_for_npu_todevice = True + + return ModulatedDeformConv2dFunction.apply( + x, offset, mask, self.weight, self.bias, self.with_bias, + self.stride, self.padding, self.dilation, + self.groups, self.deformable_groups, + self.sort_index_for_npu_fp, + self.sort_index_for_npu_bp, + ) + + +DCNv2 = ModulatedDeformConv + +if __name__ == "__main__": + x = torch.randn(2, 32, 7, 7) + model = DCNv2(32, 32, 3, 2, 1) + + torch.npu.set_device(0) + x = x.npu() + model = model.npu() + + o = model(x) + l = o.sum() + l.backward() + print(l) diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/eval.py b/PyTorch/contrib/cv/detection/YOLACT_plus/eval.py index 72264fd183..b57372aaca 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/eval.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/eval.py @@ -1,1158 +1,1158 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 data import COCODetection, get_label_map, MEANS, COLORS -from yolact import Yolact -from utils.augmentations import BaseTransform, FastBaseTransform, Resize -from utils.functions import MovingAverage, ProgressBar -from layers.box_utils import jaccard, center_size, mask_iou -from utils import timer -from utils.functions import SavePath -from layers.output_utils import postprocess, undo_image_transformation -import pycocotools - -from data import cfg, set_cfg, set_dataset -from tqdm import tqdm -import numpy as np -import torch -import torch.backends.cudnn as cudnn -from torch.autograd import Variable -import argparse -import time -import random -import cProfile -import pickle -import json -import os -from collections import defaultdict -from pathlib import Path -from collections import OrderedDict -from PIL import Image - -import matplotlib.pyplot as plt -import cv2 - -def str2bool(v): - if v.lower() in ('yes', 'true', 't', 'y', '1'): - return True - elif v.lower() in ('no', 'false', 'f', 'n', '0'): - return False - else: - raise argparse.ArgumentTypeError('Boolean value expected.') - -def parse_args(argv=None): - parser = argparse.ArgumentParser( - description='YOLACT COCO Evaluation') - parser.add_argument('--trained_model', - default='weights/ssd300_mAP_77.43_v2.pth', type=str, - help='Trained state_dict file path to open. If "interrupt", this will open the interrupt file.') - parser.add_argument('--data_path', default=None, type=str, - help='data path') - parser.add_argument('--top_k', default=5, type=int, - help='Further restrict the number of predictions to parse') - parser.add_argument('--cuda', default=True, type=str2bool, - help='Use cuda to evaulate model') - parser.add_argument('--fast_nms', default=True, type=str2bool, - help='Whether to use a faster, but not entirely correct version of NMS.') - parser.add_argument('--cross_class_nms', default=False, type=str2bool, - help='Whether compute NMS cross-class or per-class.') - parser.add_argument('--display_masks', default=True, type=str2bool, - help='Whether or not to display masks over bounding boxes') - parser.add_argument('--display_bboxes', default=True, type=str2bool, - help='Whether or not to display bboxes around masks') - parser.add_argument('--display_text', default=True, type=str2bool, - help='Whether or not to display text (class [score])') - parser.add_argument('--display_scores', default=True, type=str2bool, - help='Whether or not to display scores in addition to classes') - parser.add_argument('--display', dest='display', action='store_true', - help='Display qualitative results instead of quantitative ones.') - parser.add_argument('--shuffle', dest='shuffle', action='store_true', - help='Shuffles the images when displaying them. Doesn\'t have much of an effect when display is off though.') - parser.add_argument('--ap_data_file', default='results/ap_data.pkl', type=str, - help='In quantitative mode, the file to save detections before calculating mAP.') - parser.add_argument('--resume', dest='resume', action='store_true', - help='If display not set, this resumes mAP calculations from the ap_data_file.') - parser.add_argument('--max_images', default=-1, type=int, - help='The maximum number of images from the dataset to consider. Use -1 for all.') - parser.add_argument('--output_coco_json', dest='output_coco_json', action='store_true', - help='If display is not set, instead of processing IoU values, this just dumps detections into the coco json file.') - parser.add_argument('--bbox_det_file', default='results/bbox_detections.json', type=str, - help='The output file for coco bbox results if --coco_results is set.') - parser.add_argument('--mask_det_file', default='results/mask_detections.json', type=str, - help='The output file for coco mask results if --coco_results is set.') - parser.add_argument('--config', default='yolact_plus_resnet50_config', - help='The config object to use.') - parser.add_argument('--output_web_json', dest='output_web_json', action='store_true', - help='If display is not set, instead of processing IoU values, this dumps detections for usage with the detections viewer web thingy.') - parser.add_argument('--web_det_path', default='web/dets/', type=str, - help='If output_web_json is set, this is the path to dump detections into.') - parser.add_argument('--no_bar', dest='no_bar', action='store_true', - help='Do not output the status bar. This is useful for when piping to a file.') - parser.add_argument('--display_lincomb', default=False, type=str2bool, - help='If the config uses lincomb masks, output a visualization of how those masks are created.') - parser.add_argument('--benchmark', default=False, dest='benchmark', action='store_true', - help='Equivalent to running display mode but without displaying an image.') - parser.add_argument('--no_sort', default=False, dest='no_sort', action='store_true', - help='Do not sort images by hashed image ID.') - parser.add_argument('--seed', default=None, type=int, - help='The seed to pass into random.seed. Note: this is only really for the shuffle and does not (I think) affect cuda stuff.') - parser.add_argument('--mask_proto_debug', default=False, dest='mask_proto_debug', action='store_true', - help='Outputs stuff for scripts/compute_mask.py.') - parser.add_argument('--no_crop', default=False, dest='crop', action='store_false', - help='Do not crop output masks with the predicted bounding box.') - parser.add_argument('--image', default=None, type=str, - help='A path to an image to use for display.') - parser.add_argument('--images', default=None, type=str, - help='An input folder of images and output folder to save detected images. Should be in the format input->output.') - parser.add_argument('--video', default=None, type=str, - help='A path to a video to evaluate on. Passing in a number will use that index webcam.') - parser.add_argument('--video_multiframe', default=1, type=int, - help='The number of frames to evaluate in parallel to make videos play at higher fps.') - parser.add_argument('--score_threshold', default=0, type=float, - help='Detections with a score under this threshold will not be considered. This currently only works in display mode.') - parser.add_argument('--dataset', default=None, type=str, - help='If specified, override the dataset specified in the config with this one (example: coco2017_dataset).') - parser.add_argument('--detect', default=False, dest='detect', action='store_true', - help='Don\'t evauluate the mask branch at all and only do object detection. This only works for --display and --benchmark.') - parser.add_argument('--display_fps', default=False, dest='display_fps', action='store_true', - help='When displaying / saving video, draw the FPS on the frame') - parser.add_argument('--emulate_playback', default=False, dest='emulate_playback', action='store_true', - help='When saving a video, emulate the framerate that you\'d get running in real-time mode.') - parser.add_argument('--rank_id', default=0, type=int) - parser.set_defaults(no_bar=False, display=False, resume=False, output_coco_json=False, output_web_json=False, shuffle=False, - benchmark=False, no_sort=False, no_hash=False, mask_proto_debug=False, crop=True, detect=False, display_fps=False, - emulate_playback=False) - - global args - args = parser.parse_args(argv) - - if args.output_web_json: - args.output_coco_json = True - - if args.seed is not None: - random.seed(args.seed) - -iou_thresholds = [x / 100 for x in range(50, 100, 5)] -coco_cats = {} # Call prep_coco_cats to fill this -coco_cats_inv = {} -color_cache = defaultdict(lambda: {}) - -def prep_display(dets_out, img, h, w, undo_transform=True, class_color=False, mask_alpha=0.45, fps_str=''): - """ - Note: If undo_transform=False then im_h and im_w are allowed to be None. - """ - if undo_transform: - img_numpy = undo_image_transformation(img, w, h) - if args.cuda: - img_gpu = torch.Tensor(img_numpy).npu() - else: - img_gpu = torch.Tensor(img_numpy) - print('img_shape:', img_gpu) - else: - img_gpu = img / 255.0 - h, w, _ = img.shape - print('h, w, _ :', img.shape) - - with timer.env('Postprocess'): - save = cfg.rescore_bbox - cfg.rescore_bbox = True - t = postprocess(dets_out, w, h, visualize_lincomb = args.display_lincomb, - crop_masks = args.crop, - score_threshold = args.score_threshold) - cfg.rescore_bbox = save - - with timer.env('Copy'): - idx = t[1].argsort(0, descending=True)[:args.top_k] - - if cfg.eval_mask_branch: - # Masks are drawn on the GPU, so don't copy - masks = t[3][idx] - classes, scores, boxes = [x[idx].cpu().numpy() for x in t[:3]] - - num_dets_to_consider = min(args.top_k, classes.shape[0]) - for j in range(num_dets_to_consider): - if scores[j] < args.score_threshold: - num_dets_to_consider = j - break - - # Quick and dirty lambda for selecting the color for a particular index - # Also keeps track of a per-gpu color cache for maximum speed - def get_color(j, on_gpu=None): - global color_cache - color_idx = (classes[j] * 5 if class_color else j * 5) % len(COLORS) - - if on_gpu is not None and color_idx in color_cache[on_gpu]: - return color_cache[on_gpu][color_idx] - else: - color = COLORS[color_idx] - if not undo_transform: - # The image might come in as RGB or BRG, depending - color = (color[2], color[1], color[0]) - if on_gpu is not None: - color = torch.Tensor(color).to(on_gpu).float() / 255. - color_cache[on_gpu][color_idx] = color - return color - - # First, draw the masks on the GPU where we can do it really fast - # Beware: very fast but possibly unintelligible mask-drawing code ahead - # I wish I had access to OpenGL or Vulkan but alas, I guess Pytorch tensor operations will have to suffice - if args.display_masks and cfg.eval_mask_branch and num_dets_to_consider > 0: - # After this, mask is of size [num_dets, h, w, 1] - masks = masks[:num_dets_to_consider, :, :, None] - - # Prepare the RGB images for each mask given their color (size [num_dets, h, w, 1]) - colors = torch.cat([get_color(j, on_gpu=img_gpu.device.index).view(1, 1, 1, 3) for j in range(num_dets_to_consider)], dim=0) - masks_color = masks.repeat(1, 1, 1, 3) * colors * mask_alpha - - # This is 1 everywhere except for 1-mask_alpha where the mask is - inv_alph_masks = masks * (-mask_alpha) + 1 - - # I did the math for this on pen and paper. This whole block should be equivalent to: - # for j in range(num_dets_to_consider): - # img_gpu = img_gpu * inv_alph_masks[j] + masks_color[j] - masks_color_summand = masks_color[0] - if num_dets_to_consider > 1: - inv_alph_cumul = inv_alph_masks[:(num_dets_to_consider-1)].cumprod(dim=0) - masks_color_cumul = masks_color[1:] * inv_alph_cumul - masks_color_summand += masks_color_cumul.sum(dim=0) - - img_gpu = img_gpu * inv_alph_masks.prod(dim=0) + masks_color_summand - - if args.display_fps: - # Draw the box for the fps on the GPU - font_face = cv2.FONT_HERSHEY_DUPLEX - font_scale = 0.6 - font_thickness = 1 - - text_w, text_h = cv2.getTextSize(fps_str, font_face, font_scale, font_thickness)[0] - - img_gpu[0:text_h+8, 0:text_w+8] *= 0.6 # 1 - Box alpha - - - # Then draw the stuff that needs to be done on the cpu - # Note, make sure this is a uint8 tensor or opencv will not anti alias text for whatever reason - img_numpy = (img_gpu * 255).byte().cpu().numpy() - - if args.display_fps: - # Draw the text on the CPU - text_pt = (4, text_h + 2) - text_color = [255, 255, 255] - - cv2.putText(img_numpy, fps_str, text_pt, font_face, font_scale, text_color, font_thickness, cv2.LINE_AA) - - if num_dets_to_consider == 0: - return img_numpy - - if args.display_text or args.display_bboxes: - for j in reversed(range(num_dets_to_consider)): - x1, y1, x2, y2 = boxes[j, :] - color = get_color(j) - score = scores[j] - - if args.display_bboxes: - cv2.rectangle(img_numpy, (x1, y1), (x2, y2), color, 1) - - if args.display_text: - _class = cfg.dataset.class_names[classes[j]] - text_str = '%s: %.2f' % (_class, score) if args.display_scores else _class - - font_face = cv2.FONT_HERSHEY_DUPLEX - font_scale = 0.6 - font_thickness = 1 - - text_w, text_h = cv2.getTextSize(text_str, font_face, font_scale, font_thickness)[0] - - text_pt = (x1, y1 - 3) - text_color = [255, 255, 255] - - cv2.rectangle(img_numpy, (x1, y1), (x1 + text_w, y1 - text_h - 4), color, -1) - cv2.putText(img_numpy, text_str, text_pt, font_face, font_scale, text_color, font_thickness, cv2.LINE_AA) - - - return img_numpy - -def prep_benchmark(dets_out, h, w): - with timer.env('Postprocess'): - t = postprocess(dets_out, w, h, crop_masks=args.crop, score_threshold=args.score_threshold) - - with timer.env('Copy'): - classes, scores, boxes, masks = [x[:args.top_k] for x in t] - if isinstance(scores, list): - box_scores = scores[0].cpu().numpy() - mask_scores = scores[1].cpu().numpy() - else: - scores = scores.cpu().numpy() - classes = classes.cpu().numpy() - boxes = boxes.cpu().numpy() - masks = masks.cpu().numpy() - - with timer.env('Sync'): - # Just in case - torch.npu.synchronize() - -def prep_coco_cats(): - """ Prepare inverted table for category id lookup given a coco cats object. """ - for coco_cat_id, transformed_cat_id_p1 in get_label_map().items(): - transformed_cat_id = transformed_cat_id_p1 - 1 - coco_cats[transformed_cat_id] = coco_cat_id - coco_cats_inv[coco_cat_id] = transformed_cat_id - - -def get_coco_cat(transformed_cat_id): - """ transformed_cat_id is [0,80) as indices in cfg.dataset.class_names """ - return coco_cats[transformed_cat_id] - -def get_transformed_cat(coco_cat_id): - """ transformed_cat_id is [0,80) as indices in cfg.dataset.class_names """ - return coco_cats_inv[coco_cat_id] - - -class Detections: - - def __init__(self): - self.bbox_data = [] - self.mask_data = [] - - def add_bbox(self, image_id:int, category_id:int, bbox:list, score:float): - """ Note that bbox should be a list or tuple of (x1, y1, x2, y2) """ - bbox = [bbox[0], bbox[1], bbox[2]-bbox[0], bbox[3]-bbox[1]] - - # Round to the nearest 10th to avoid huge file sizes, as COCO suggests - bbox = [round(float(x)*10)/10 for x in bbox] - - self.bbox_data.append({ - 'image_id': int(image_id), - 'category_id': get_coco_cat(int(category_id)), - 'bbox': bbox, - 'score': float(score) - }) - - def add_mask(self, image_id:int, category_id:int, segmentation:np.ndarray, score:float): - """ The segmentation should be the full mask, the size of the image and with size [h, w]. """ - rle = pycocotools.mask.encode(np.asfortranarray(segmentation.astype(np.uint8))) - rle['counts'] = rle['counts'].decode('ascii') # json.dump doesn't like bytes strings - - self.mask_data.append({ - 'image_id': int(image_id), - 'category_id': get_coco_cat(int(category_id)), - 'segmentation': rle, - 'score': float(score) - }) - - def dump(self): - dump_arguments = [ - (self.bbox_data, args.bbox_det_file), - (self.mask_data, args.mask_det_file) - ] - - for data, path in dump_arguments: - with open(path, 'w') as f: - json.dump(data, f) - - def dump_web(self): - """ Dumps it in the format for my web app. Warning: bad code ahead! """ - config_outs = ['preserve_aspect_ratio', 'use_prediction_module', - 'use_yolo_regressors', 'use_prediction_matching', - 'train_masks'] - - output = { - 'info' : { - 'Config': {key: getattr(cfg, key) for key in config_outs}, - } - } - - image_ids = list(set([x['image_id'] for x in self.bbox_data])) - image_ids.sort() - image_lookup = {_id: idx for idx, _id in enumerate(image_ids)} - - output['images'] = [{'image_id': image_id, 'dets': []} for image_id in image_ids] - - # These should already be sorted by score with the way prep_metrics works. - for bbox, mask in zip(self.bbox_data, self.mask_data): - image_obj = output['images'][image_lookup[bbox['image_id']]] - image_obj['dets'].append({ - 'score': bbox['score'], - 'bbox': bbox['bbox'], - 'category': cfg.dataset.class_names[get_transformed_cat(bbox['category_id'])], - 'mask': mask['segmentation'], - }) - - with open(os.path.join(args.web_det_path, '%s.json' % cfg.name), 'w') as f: - json.dump(output, f) - - - - -def _mask_iou(mask1, mask2, iscrowd=False): - with timer.env('Mask IoU'): - ret = mask_iou(mask1, mask2, iscrowd) - return ret.cpu() - -def _bbox_iou(bbox1, bbox2, iscrowd=False): - with timer.env('BBox IoU'): - ret = jaccard(bbox1, bbox2, iscrowd) - return ret.cpu() - -def prep_metrics(ap_data, dets, img, gt, gt_masks, h, w, num_crowd, image_id, detections:Detections=None): - """ Returns a list of APs for this image, with each element being for a class """ - if not args.output_coco_json: - with timer.env('Prepare gt'): - gt_boxes = torch.Tensor(gt[:, :4]) if args.cuda else torch.Tensor(gt[:, :4]) - gt_boxes[:, [0, 2]] *= w - gt_boxes[:, [1, 3]] *= h - gt_classes = list(gt[:, 4].astype(int)) - gt_masks = torch.Tensor(gt_masks).view(-1, h*w) if args.cuda else torch.Tensor(gt_masks).view(-1, h*w) - - if num_crowd > 0: - split = lambda x: (x[-num_crowd:], x[:-num_crowd]) - crowd_boxes , gt_boxes = split(gt_boxes) - crowd_masks , gt_masks = split(gt_masks) - crowd_classes, gt_classes = split(gt_classes) - - with timer.env('Postprocess'): - classes, scores, boxes, masks = postprocess(dets, w, h, crop_masks=args.crop, score_threshold=args.score_threshold) - - if classes.size(0) == 0: - return - - classes = list(classes.cpu().numpy().astype(int)) - if isinstance(scores, list): - box_scores = list(scores[0].cpu().numpy().astype(float)) - mask_scores = list(scores[1].cpu().numpy().astype(float)) - else: - scores = list(scores.cpu().numpy().astype(float)) - box_scores = scores - mask_scores = scores - # if args.cuda: - # masks = masks.view(-1, h*w).npu() - # boxes = boxes.npu() - # else: - masks = masks.view(-1, h*w) - - - if args.output_coco_json: - with timer.env('JSON Output'): - boxes = boxes.cpu().numpy() - masks = masks.view(-1, h, w).cpu().numpy() - for i in range(masks.shape[0]): - # Make sure that the bounding box actually makes sense and a mask was produced - if (boxes[i, 3] - boxes[i, 1]) * (boxes[i, 2] - boxes[i, 0]) > 0: - detections.add_bbox(image_id, classes[i], boxes[i,:], box_scores[i]) - detections.add_mask(image_id, classes[i], masks[i,:,:], mask_scores[i]) - return - - with timer.env('Eval Setup'): - num_pred = len(classes) - num_gt = len(gt_classes) - - mask_iou_cache = _mask_iou(masks, gt_masks) - bbox_iou_cache = _bbox_iou(boxes.float(), gt_boxes.float()) - - if num_crowd > 0: - crowd_mask_iou_cache = _mask_iou(masks, crowd_masks, iscrowd=True) - crowd_bbox_iou_cache = _bbox_iou(boxes.float(), crowd_boxes.float(), iscrowd=True) - else: - crowd_mask_iou_cache = None - crowd_bbox_iou_cache = None - - box_indices = sorted(range(num_pred), key=lambda i: -box_scores[i]) - mask_indices = sorted(box_indices, key=lambda i: -mask_scores[i]) - - iou_types = [ - ('box', lambda i,j: bbox_iou_cache[i, j].item(), - lambda i,j: crowd_bbox_iou_cache[i,j].item(), - lambda i: box_scores[i], box_indices), - ('mask', lambda i,j: mask_iou_cache[i, j].item(), - lambda i,j: crowd_mask_iou_cache[i,j].item(), - lambda i: mask_scores[i], mask_indices) - ] - - timer.start('Main loop') - for _class in set(classes + gt_classes): - ap_per_iou = [] - num_gt_for_class = sum([1 for x in gt_classes if x == _class]) - - for iouIdx in range(len(iou_thresholds)): - iou_threshold = iou_thresholds[iouIdx] - - for iou_type, iou_func, crowd_func, score_func, indices in iou_types: - gt_used = [False] * len(gt_classes) - - ap_obj = ap_data[iou_type][iouIdx][_class] - ap_obj.add_gt_positives(num_gt_for_class) - - for i in indices: - if classes[i] != _class: - continue - - max_iou_found = iou_threshold - max_match_idx = -1 - for j in range(num_gt): - if gt_used[j] or gt_classes[j] != _class: - continue - - iou = iou_func(i, j) - - if iou > max_iou_found: - max_iou_found = iou - max_match_idx = j - - if max_match_idx >= 0: - gt_used[max_match_idx] = True - ap_obj.push(score_func(i), True) - else: - # If the detection matches a crowd, we can just ignore it - matched_crowd = False - - if num_crowd > 0: - for j in range(len(crowd_classes)): - if crowd_classes[j] != _class: - continue - - iou = crowd_func(i, j) - - if iou > iou_threshold: - matched_crowd = True - break - - # All this crowd code so that we can make sure that our eval code gives the - # same result as COCOEval. There aren't even that many crowd annotations to - # begin with, but accuracy is of the utmost importance. - if not matched_crowd: - ap_obj.push(score_func(i), False) - timer.stop('Main loop') - - -class APDataObject: - """ - Stores all the information necessary to calculate the AP for one IoU and one class. - Note: I type annotated this because why not. - """ - - def __init__(self): - self.data_points = [] - self.num_gt_positives = 0 - - def push(self, score:float, is_true:bool): - self.data_points.append((score, is_true)) - - def add_gt_positives(self, num_positives:int): - """ Call this once per image. """ - self.num_gt_positives += num_positives - - def is_empty(self) -> bool: - return len(self.data_points) == 0 and self.num_gt_positives == 0 - - def get_ap(self) -> float: - """ Warning: result not cached. """ - - if self.num_gt_positives == 0: - return 0 - - # Sort descending by score - self.data_points.sort(key=lambda x: -x[0]) - - precisions = [] - recalls = [] - num_true = 0 - num_false = 0 - - # Compute the precision-recall curve. The x axis is recalls and the y axis precisions. - for datum in self.data_points: - # datum[1] is whether the detection a true or false positive - if datum[1]: num_true += 1 - else: num_false += 1 - - precision = num_true / (num_true + num_false) - recall = num_true / self.num_gt_positives - - precisions.append(precision) - recalls.append(recall) - - # Smooth the curve by computing [max(precisions[i:]) for i in range(len(precisions))] - # Basically, remove any temporary dips from the curve. - # At least that's what I think, idk. COCOEval did it so I do too. - for i in range(len(precisions)-1, 0, -1): - if precisions[i] > precisions[i-1]: - precisions[i-1] = precisions[i] - - # Compute the integral of precision(recall) d_recall from recall=0->1 using fixed-length riemann summation with 101 bars. - y_range = [0] * 101 # idx 0 is recall == 0.0 and idx 100 is recall == 1.00 - x_range = np.array([x / 100 for x in range(101)]) - recalls = np.array(recalls) - - # I realize this is weird, but all it does is find the nearest precision(x) for a given x in x_range. - # Basically, if the closest recall we have to 0.01 is 0.009 this sets precision(0.01) = precision(0.009). - # I approximate the integral this way, because that's how COCOEval does it. - indices = np.searchsorted(recalls, x_range, side='left') - for bar_idx, precision_idx in enumerate(indices): - if precision_idx < len(precisions): - y_range[bar_idx] = precisions[precision_idx] - - # Finally compute the riemann sum to get our integral. - # avg([precision(x) for x in 0:0.01:1]) - return sum(y_range) / len(y_range) - -def badhash(x): - """ - Just a quick and dirty hash function for doing a deterministic shuffle based on image_id. - - Source: - https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key - """ - x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF - x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF - x = ((x >> 16) ^ x) & 0xFFFFFFFF - return x - -def evalimage(net:Yolact, path:str, save_path:str=None): - if args.cuda: - frame = torch.from_numpy(cv2.imread(path)).npu().float() - else: - frame = torch.from_numpy(cv2.imread(path)).float() - print('frame: ', frame) - batch = FastBaseTransform()(frame.unsqueeze(0)) - print('batch_pred:', batch) - print('batch_shape:', batch.shape) - preds = net(batch) - - img_numpy = prep_display(preds, frame, None, None, undo_transform=False) - - if save_path is None: - img_numpy = img_numpy[:, :, (2, 1, 0)] - - if save_path is None: - plt.imshow(img_numpy) - plt.title(path) - plt.show() - else: - cv2.imwrite(save_path, img_numpy) - -def evalimages(net:Yolact, input_folder:str, output_folder:str): - if not os.path.exists(output_folder): - os.mkdir(output_folder) - - print() - for p in Path(input_folder).glob('*'): - path = str(p) - name = os.path.basename(path) - name = '.'.join(name.split('.')[:-1]) + '.png' - out_path = os.path.join(output_folder, name) - - evalimage(net, path, out_path) - print(path + ' -> ' + out_path) - print('Done.') - -from multiprocessing.pool import ThreadPool -from queue import Queue - -class CustomDataParallel(torch.nn.DataParallel): - """ A Custom Data Parallel class that properly gathers lists of dictionaries. """ - def gather(self, outputs, output_device): - # Note that I don't actually want to convert everything to the output_device - return sum(outputs, []) - -def evalvideo(net:Yolact, path:str, out_path:str=None): - # If the path is a digit, parse it as a webcam index - is_webcam = path.isdigit() - - # If the input image size is constant, this make things faster (hence why we can use it in a video setting). - cudnn.benchmark = True - - if is_webcam: - vid = cv2.VideoCapture(int(path)) - else: - vid = cv2.VideoCapture(path) - - if not vid.isOpened(): - print('Could not open video "%s"' % path) - exit(-1) - - target_fps = round(vid.get(cv2.CAP_PROP_FPS)) - frame_width = round(vid.get(cv2.CAP_PROP_FRAME_WIDTH)) - frame_height = round(vid.get(cv2.CAP_PROP_FRAME_HEIGHT)) - - if is_webcam: - num_frames = float('inf') - else: - num_frames = round(vid.get(cv2.CAP_PROP_FRAME_COUNT)) - - net = CustomDataParallel(net).npu() - transform = torch.nn.DataParallel(FastBaseTransform()).npu() - frame_times = MovingAverage(100) - fps = 0 - frame_time_target = 1 / target_fps - running = True - fps_str = '' - vid_done = False - frames_displayed = 0 - - if out_path is not None: - out = cv2.VideoWriter(out_path, cv2.VideoWriter_fourcc(*"mp4v"), target_fps, (frame_width, frame_height)) - - def cleanup_and_exit(): - print() - pool.terminate() - vid.release() - if out_path is not None: - out.release() - cv2.destroyAllWindows() - exit() - - def get_next_frame(vid): - frames = [] - for idx in range(args.video_multiframe): - frame = vid.read()[1] - if frame is None: - return frames - frames.append(frame) - return frames - - def transform_frame(frames): - with torch.no_grad(): - frames = [torch.from_numpy(frame).npu().float() for frame in frames] - return frames, transform(torch.stack(frames, 0)) - - def eval_network(inp): - with torch.no_grad(): - frames, imgs = inp - num_extra = 0 - while imgs.size(0) < args.video_multiframe: - imgs = torch.cat([imgs, imgs[0].unsqueeze(0)], dim=0) - num_extra += 1 - out = net(imgs) - if num_extra > 0: - out = out[:-num_extra] - return frames, out - - def prep_frame(inp, fps_str): - with torch.no_grad(): - frame, preds = inp - return prep_display(preds, frame, None, None, undo_transform=False, class_color=True, fps_str=fps_str) - - frame_buffer = Queue() - video_fps = 0 - - # All this timing code to make sure that - def play_video(): - try: - nonlocal frame_buffer, running, video_fps, is_webcam, num_frames, frames_displayed, vid_done - - video_frame_times = MovingAverage(100) - frame_time_stabilizer = frame_time_target - last_time = None - stabilizer_step = 0.0005 - progress_bar = ProgressBar(30, num_frames) - - while running: - frame_time_start = time.time() - - if not frame_buffer.empty(): - next_time = time.time() - if last_time is not None: - video_frame_times.add(next_time - last_time) - video_fps = 1 / video_frame_times.get_avg() - if out_path is None: - cv2.imshow(path, frame_buffer.get()) - else: - out.write(frame_buffer.get()) - frames_displayed += 1 - last_time = next_time - - if out_path is not None: - if video_frame_times.get_avg() == 0: - fps = 0 - else: - fps = 1 / video_frame_times.get_avg() - progress = frames_displayed / num_frames * 100 - progress_bar.set_val(frames_displayed) - - print('\rProcessing Frames %s %6d / %6d (%5.2f%%) %5.2f fps ' - % (repr(progress_bar), frames_displayed, num_frames, progress, fps), end='') - - - # This is split because you don't want savevideo to require cv2 display functionality (see #197) - if out_path is None and cv2.waitKey(1) == 27: - # Press Escape to close - running = False - if not (frames_displayed < num_frames): - running = False - - if not vid_done: - buffer_size = frame_buffer.qsize() - if buffer_size < args.video_multiframe: - frame_time_stabilizer += stabilizer_step - elif buffer_size > args.video_multiframe: - frame_time_stabilizer -= stabilizer_step - if frame_time_stabilizer < 0: - frame_time_stabilizer = 0 - - new_target = frame_time_stabilizer if is_webcam else max(frame_time_stabilizer, frame_time_target) - else: - new_target = frame_time_target - - next_frame_target = max(2 * new_target - video_frame_times.get_avg(), 0) - target_time = frame_time_start + next_frame_target - 0.001 # Let's just subtract a millisecond to be safe - - if out_path is None or args.emulate_playback: - # This gives more accurate timing than if sleeping the whole amount at once - while time.time() < target_time: - time.sleep(0.001) - else: - # Let's not starve the main thread, now - time.sleep(0.001) - except: - # See issue #197 for why this is necessary - import traceback - traceback.print_exc() - - - extract_frame = lambda x, i: (x[0][i] if x[1][i]['detection'] is None else x[0][i].to(x[1][i]['detection']['box'].device), [x[1][i]]) - - # Prime the network on the first frame because I do some thread unsafe things otherwise - print('Initializing model... ', end='') - first_batch = eval_network(transform_frame(get_next_frame(vid))) - print('Done.') - - # For each frame the sequence of functions it needs to go through to be processed (in reversed order) - sequence = [prep_frame, eval_network, transform_frame] - pool = ThreadPool(processes=len(sequence) + args.video_multiframe + 2) - pool.apply_async(play_video) - active_frames = [{'value': extract_frame(first_batch, i), 'idx': 0} for i in range(len(first_batch[0]))] - - print() - if out_path is None: print('Press Escape to close.') - try: - while vid.isOpened() and running: - # Hard limit on frames in buffer so we don't run out of memory >.> - while frame_buffer.qsize() > 100: - time.sleep(0.001) - - start_time = time.time() - - # Start loading the next frames from the disk - if not vid_done: - next_frames = pool.apply_async(get_next_frame, args=(vid,)) - else: - next_frames = None - - if not (vid_done and len(active_frames) == 0): - # For each frame in our active processing queue, dispatch a job - # for that frame using the current function in the sequence - for frame in active_frames: - _args = [frame['value']] - if frame['idx'] == 0: - _args.append(fps_str) - frame['value'] = pool.apply_async(sequence[frame['idx']], args=_args) - - # For each frame whose job was the last in the sequence (i.e. for all final outputs) - for frame in active_frames: - if frame['idx'] == 0: - frame_buffer.put(frame['value'].get()) - - # Remove the finished frames from the processing queue - active_frames = [x for x in active_frames if x['idx'] > 0] - - # Finish evaluating every frame in the processing queue and advanced their position in the sequence - for frame in list(reversed(active_frames)): - frame['value'] = frame['value'].get() - frame['idx'] -= 1 - - if frame['idx'] == 0: - # Split this up into individual threads for prep_frame since it doesn't support batch size - active_frames += [{'value': extract_frame(frame['value'], i), 'idx': 0} for i in range(1, len(frame['value'][0]))] - frame['value'] = extract_frame(frame['value'], 0) - - # Finish loading in the next frames and add them to the processing queue - if next_frames is not None: - frames = next_frames.get() - if len(frames) == 0: - vid_done = True - else: - active_frames.append({'value': frames, 'idx': len(sequence)-1}) - - # Compute FPS - frame_times.add(time.time() - start_time) - fps = args.video_multiframe / frame_times.get_avg() - else: - fps = 0 - - fps_str = 'Processing FPS: %.2f | Video Playback FPS: %.2f | Frames in Buffer: %d' % (fps, video_fps, frame_buffer.qsize()) - if not args.display_fps: - print('\r' + fps_str + ' ', end='') - - except KeyboardInterrupt: - print('\nStopping...') - - cleanup_and_exit() - -def evaluate(net:Yolact, dataset, train_mode=False, trainCuda = True): - net.detect.use_fast_nms = args.fast_nms - net.detect.use_cross_class_nms = args.cross_class_nms - cfg.mask_proto_debug = args.mask_proto_debug - - # TODO Currently we do not support Fast Mask Re-scroing in evalimage, evalimages, and evalvideo - if args.image is not None: - if ':' in args.image: - inp, out = args.image.split(':') - evalimage(net, inp, out) - else: - evalimage(net, args.image) - return - elif args.images is not None: - inp, out = args.images.split(':') - evalimages(net, inp, out) - return - elif args.video is not None: - if ':' in args.video: - inp, out = args.video.split(':') - evalvideo(net, inp, out) - else: - evalvideo(net, args.video) - return - - frame_times = MovingAverage() - dataset_size = len(dataset) if args.max_images < 0 else min(args.max_images, len(dataset)) - progress_bar = ProgressBar(30, dataset_size) - - print() - - if not args.display and not args.benchmark: - # For each class and iou, stores tuples (score, isPositive) - # Index ap_data[type][iouIdx][classIdx] - ap_data = { - 'box' : [[APDataObject() for _ in cfg.dataset.class_names] for _ in iou_thresholds], - 'mask': [[APDataObject() for _ in cfg.dataset.class_names] for _ in iou_thresholds] - } - detections = Detections() - else: - timer.disable('Load Data') - - dataset_indices = list(range(len(dataset))) - - if args.shuffle: - random.shuffle(dataset_indices) - elif not args.no_sort: - # Do a deterministic shuffle based on the image ids - # - # I do this because on python 3.5 dictionary key order is *random*, while in 3.6 it's - # the order of insertion. That means on python 3.6, the images come in the order they are in - # in the annotations file. For some reason, the first images in the annotations file are - # the hardest. To combat this, I use a hard-coded hash function based on the image ids - # to shuffle the indices we use. That way, no matter what python version or how pycocotools - # handles the data, we get the same result every time. - hashed = [badhash(x) for x in dataset.ids] - dataset_indices.sort(key=lambda x: hashed[x]) - - dataset_indices = dataset_indices[:dataset_size] - - try: - # Main eval loop - for it, image_idx in enumerate(tqdm(dataset_indices)): - timer.reset() - - with timer.env('Load Data'): - img, gt, gt_masks, h, w, num_crowd = dataset.pull_item(image_idx) - # Test flag, do not upvote - if cfg.mask_proto_debug: - with open('scripts/info.txt', 'w') as f: - f.write(str(dataset.ids[image_idx])) - np.save('scripts/gt.npy', gt_masks) - - batch = Variable(img.unsqueeze(0)) - if args.cuda: - if train_mode: - batch = batch.npu() if trainCuda else batch - else: - batch = batch.npu() - - with timer.env('Network Extra'): - preds = net(batch) - if preds is not None and preds[0] is not None: - if preds[0]['box'] is not None: - preds[0]['box'] = preds[0]['box'].cpu() - if preds[0]['mask'] is not None: - preds[0]['mask'] = preds[0]['mask'].cpu() - if preds[0]['class'] is not None: - preds[0]['class'] = preds[0]['class'].cpu() - if preds[0]['score'] is not None: - preds[0]['score'] = preds[0]['score'].cpu() - if preds[0]['proto'] is not None: - preds[0]['proto'] = preds[0]['proto'].cpu() - - # Perform the meat of the operation here depending on our mode. - if args.display: - img_numpy = prep_display(preds, img, h, w) - elif args.benchmark: - prep_benchmark(preds, h, w) - else: - prep_metrics(ap_data, preds, img, gt, gt_masks, h, w, num_crowd, dataset.ids[image_idx], detections) - - # First couple of images take longer because we're constructing the graph. - # Since that's technically initialization, don't include those in the FPS calculations. - if it > 1: - frame_times.add(timer.total_time()) - - if args.display: - if it > 1: - print('Avg FPS: %.4f' % (1 / frame_times.get_avg())) - plt.imshow(img_numpy) - plt.title(str(dataset.ids[image_idx])) - plt.show() - elif not args.no_bar: - if it > 1: fps = 1 / frame_times.get_avg() - else: fps = 0 - progress = (it+1) / dataset_size * 100 - progress_bar.set_val(it+1) - print('\rProcessing Images %s %6d / %6d (%5.2f%%) %5.2f fps ' - % (repr(progress_bar), it+1, dataset_size, progress, fps), end='') - - - - if not args.display and not args.benchmark: - print() - if args.output_coco_json: - print('Dumping detections...') - if args.output_web_json: - detections.dump_web() - else: - detections.dump() - else: - if not train_mode: - print('Saving data...') - with open(args.ap_data_file, 'wb') as f: - pickle.dump(ap_data, f) - - return calc_map(ap_data) - elif args.benchmark: - print() - print() - print('Stats for the last frame:') - timer.print_stats() - avg_seconds = frame_times.get_avg() - print('Average: %5.2f fps, %5.2f ms' % (1 / frame_times.get_avg(), 1000*avg_seconds)) - - except KeyboardInterrupt: - print('Stopping...') - - -def calc_map(ap_data): - print('Calculating mAP...') - aps = [{'box': [], 'mask': []} for _ in iou_thresholds] - - for _class in range(len(cfg.dataset.class_names)): - for iou_idx in range(len(iou_thresholds)): - for iou_type in ('box', 'mask'): - ap_obj = ap_data[iou_type][iou_idx][_class] - - if not ap_obj.is_empty(): - aps[iou_idx][iou_type].append(ap_obj.get_ap()) - - all_maps = {'box': OrderedDict(), 'mask': OrderedDict()} - - # Looking back at it, this code is really hard to read :/ - for iou_type in ('box', 'mask'): - all_maps[iou_type]['all'] = 0 # Make this first in the ordereddict - for i, threshold in enumerate(iou_thresholds): - mAP = sum(aps[i][iou_type]) / len(aps[i][iou_type]) * 100 if len(aps[i][iou_type]) > 0 else 0 - all_maps[iou_type][int(threshold*100)] = mAP - all_maps[iou_type]['all'] = (sum(all_maps[iou_type].values()) / (len(all_maps[iou_type].values())-1)) - - print_maps(all_maps) - - # Put in a prettier format so we can serialize it to json during training - all_maps = {k: {j: round(u, 2) for j, u in v.items()} for k, v in all_maps.items()} - return all_maps - -def print_maps(all_maps): - # Warning: hacky - make_row = lambda vals: (' %5s |' * len(vals)) % tuple(vals) - make_sep = lambda n: ('-------+' * n) - - print() - print(make_row([''] + [('.%d ' % x if isinstance(x, int) else x + ' ') for x in all_maps['box'].keys()])) - print(make_sep(len(all_maps['box']) + 1)) - for iou_type in ('box', 'mask'): - print(make_row([iou_type] + ['%.2f' % x if x < 100 else '%.1f' % x for x in all_maps[iou_type].values()])) - print(make_sep(len(all_maps['box']) + 1)) - print() - - - -if __name__ == '__main__': - parse_args() - - if args.config is not None: - set_cfg(args.config) - - if args.trained_model == 'interrupt': - - args.trained_model = SavePath.get_interrupt('weights/') - elif args.trained_model == 'latest': - args.trained_model = SavePath.get_latest('weights/', cfg.name) - - if args.config is None: - model_path = SavePath.from_str(args.trained_model) - # TODO: Bad practice? Probably want to do a name lookup instead. - args.config = model_path.model_name + '_config' - print('Config not specified. Parsed %s from the file name.\n' % args.config) - set_cfg(args.config) - - if args.detect: - cfg.eval_mask_branch = False - - if args.dataset is not None: - set_dataset(args.dataset) - - if args.data_path: - cfg.dataset.valid_images = args.data_path + '/images/' - cfg.dataset.valid_info = args.data_path + '/annotations/instances_val2017.json' - - with torch.no_grad(): - if not os.path.exists('results'): - os.makedirs('results') - - if args.cuda: - cudnn.fastest = True - args.device = torch.device(f'npu:{args.rank_id}') - torch.npu.set_device(args.device) - #torch.set_default_tensor_type('torch.npu.FloatTensor') - else: - torch.set_default_tensor_type('torch.FloatTensor') - - if args.resume and not args.display: - with open(args.ap_data_file, 'rb') as f: - ap_data = pickle.load(f) - calc_map(ap_data) - exit() - - if args.image is None and args.video is None and args.images is None: - dataset = COCODetection(cfg.dataset.valid_images, cfg.dataset.valid_info, - transform=BaseTransform(), has_gt=cfg.dataset.has_gt) - prep_coco_cats() - else: - dataset = None - - print('Loading model...', end='') - net = Yolact() - net.load_weights(args.trained_model) - net.eval() - print(' Done.') - - if args.cuda: - net = net.npu() - - evaluate(net, dataset) - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 data import COCODetection, get_label_map, MEANS, COLORS +from yolact import Yolact +from utils.augmentations import BaseTransform, FastBaseTransform, Resize +from utils.functions import MovingAverage, ProgressBar +from layers.box_utils import jaccard, center_size, mask_iou +from utils import timer +from utils.functions import SavePath +from layers.output_utils import postprocess, undo_image_transformation +import pycocotools + +from data import cfg, set_cfg, set_dataset +from tqdm import tqdm +import numpy as np +import torch +import torch.backends.cudnn as cudnn +from torch.autograd import Variable +import argparse +import time +import random +import cProfile +import pickle +import json +import os +from collections import defaultdict +from pathlib import Path +from collections import OrderedDict +from PIL import Image + +import matplotlib.pyplot as plt +import cv2 + +def str2bool(v): + if v.lower() in ('yes', 'true', 't', 'y', '1'): + return True + elif v.lower() in ('no', 'false', 'f', 'n', '0'): + return False + else: + raise argparse.ArgumentTypeError('Boolean value expected.') + +def parse_args(argv=None): + parser = argparse.ArgumentParser( + description='YOLACT COCO Evaluation') + parser.add_argument('--trained_model', + default='weights/ssd300_mAP_77.43_v2.pth', type=str, + help='Trained state_dict file path to open. If "interrupt", this will open the interrupt file.') + parser.add_argument('--data_path', default=None, type=str, + help='data path') + parser.add_argument('--top_k', default=5, type=int, + help='Further restrict the number of predictions to parse') + parser.add_argument('--cuda', default=True, type=str2bool, + help='Use cuda to evaulate model') + parser.add_argument('--fast_nms', default=True, type=str2bool, + help='Whether to use a faster, but not entirely correct version of NMS.') + parser.add_argument('--cross_class_nms', default=False, type=str2bool, + help='Whether compute NMS cross-class or per-class.') + parser.add_argument('--display_masks', default=True, type=str2bool, + help='Whether or not to display masks over bounding boxes') + parser.add_argument('--display_bboxes', default=True, type=str2bool, + help='Whether or not to display bboxes around masks') + parser.add_argument('--display_text', default=True, type=str2bool, + help='Whether or not to display text (class [score])') + parser.add_argument('--display_scores', default=True, type=str2bool, + help='Whether or not to display scores in addition to classes') + parser.add_argument('--display', dest='display', action='store_true', + help='Display qualitative results instead of quantitative ones.') + parser.add_argument('--shuffle', dest='shuffle', action='store_true', + help='Shuffles the images when displaying them. Doesn\'t have much of an effect when display is off though.') + parser.add_argument('--ap_data_file', default='results/ap_data.pkl', type=str, + help='In quantitative mode, the file to save detections before calculating mAP.') + parser.add_argument('--resume', dest='resume', action='store_true', + help='If display not set, this resumes mAP calculations from the ap_data_file.') + parser.add_argument('--max_images', default=-1, type=int, + help='The maximum number of images from the dataset to consider. Use -1 for all.') + parser.add_argument('--output_coco_json', dest='output_coco_json', action='store_true', + help='If display is not set, instead of processing IoU values, this just dumps detections into the coco json file.') + parser.add_argument('--bbox_det_file', default='results/bbox_detections.json', type=str, + help='The output file for coco bbox results if --coco_results is set.') + parser.add_argument('--mask_det_file', default='results/mask_detections.json', type=str, + help='The output file for coco mask results if --coco_results is set.') + parser.add_argument('--config', default='yolact_plus_resnet50_config', + help='The config object to use.') + parser.add_argument('--output_web_json', dest='output_web_json', action='store_true', + help='If display is not set, instead of processing IoU values, this dumps detections for usage with the detections viewer web thingy.') + parser.add_argument('--web_det_path', default='web/dets/', type=str, + help='If output_web_json is set, this is the path to dump detections into.') + parser.add_argument('--no_bar', dest='no_bar', action='store_true', + help='Do not output the status bar. This is useful for when piping to a file.') + parser.add_argument('--display_lincomb', default=False, type=str2bool, + help='If the config uses lincomb masks, output a visualization of how those masks are created.') + parser.add_argument('--benchmark', default=False, dest='benchmark', action='store_true', + help='Equivalent to running display mode but without displaying an image.') + parser.add_argument('--no_sort', default=False, dest='no_sort', action='store_true', + help='Do not sort images by hashed image ID.') + parser.add_argument('--seed', default=None, type=int, + help='The seed to pass into random.seed. Note: this is only really for the shuffle and does not (I think) affect cuda stuff.') + parser.add_argument('--mask_proto_debug', default=False, dest='mask_proto_debug', action='store_true', + help='Outputs stuff for scripts/compute_mask.py.') + parser.add_argument('--no_crop', default=False, dest='crop', action='store_false', + help='Do not crop output masks with the predicted bounding box.') + parser.add_argument('--image', default=None, type=str, + help='A path to an image to use for display.') + parser.add_argument('--images', default=None, type=str, + help='An input folder of images and output folder to save detected images. Should be in the format input->output.') + parser.add_argument('--video', default=None, type=str, + help='A path to a video to evaluate on. Passing in a number will use that index webcam.') + parser.add_argument('--video_multiframe', default=1, type=int, + help='The number of frames to evaluate in parallel to make videos play at higher fps.') + parser.add_argument('--score_threshold', default=0, type=float, + help='Detections with a score under this threshold will not be considered. This currently only works in display mode.') + parser.add_argument('--dataset', default=None, type=str, + help='If specified, override the dataset specified in the config with this one (example: coco2017_dataset).') + parser.add_argument('--detect', default=False, dest='detect', action='store_true', + help='Don\'t evauluate the mask branch at all and only do object detection. This only works for --display and --benchmark.') + parser.add_argument('--display_fps', default=False, dest='display_fps', action='store_true', + help='When displaying / saving video, draw the FPS on the frame') + parser.add_argument('--emulate_playback', default=False, dest='emulate_playback', action='store_true', + help='When saving a video, emulate the framerate that you\'d get running in real-time mode.') + parser.add_argument('--rank_id', default=0, type=int) + parser.set_defaults(no_bar=False, display=False, resume=False, output_coco_json=False, output_web_json=False, shuffle=False, + benchmark=False, no_sort=False, no_hash=False, mask_proto_debug=False, crop=True, detect=False, display_fps=False, + emulate_playback=False) + + global args + args = parser.parse_args(argv) + + if args.output_web_json: + args.output_coco_json = True + + if args.seed is not None: + random.seed(args.seed) + +iou_thresholds = [x / 100 for x in range(50, 100, 5)] +coco_cats = {} # Call prep_coco_cats to fill this +coco_cats_inv = {} +color_cache = defaultdict(lambda: {}) + +def prep_display(dets_out, img, h, w, undo_transform=True, class_color=False, mask_alpha=0.45, fps_str=''): + """ + Note: If undo_transform=False then im_h and im_w are allowed to be None. + """ + if undo_transform: + img_numpy = undo_image_transformation(img, w, h) + if args.cuda: + img_gpu = torch.Tensor(img_numpy).npu() + else: + img_gpu = torch.Tensor(img_numpy) + print('img_shape:', img_gpu) + else: + img_gpu = img / 255.0 + h, w, _ = img.shape + print('h, w, _ :', img.shape) + + with timer.env('Postprocess'): + save = cfg.rescore_bbox + cfg.rescore_bbox = True + t = postprocess(dets_out, w, h, visualize_lincomb = args.display_lincomb, + crop_masks = args.crop, + score_threshold = args.score_threshold) + cfg.rescore_bbox = save + + with timer.env('Copy'): + idx = t[1].argsort(0, descending=True)[:args.top_k] + + if cfg.eval_mask_branch: + # Masks are drawn on the GPU, so don't copy + masks = t[3][idx] + classes, scores, boxes = [x[idx].cpu().numpy() for x in t[:3]] + + num_dets_to_consider = min(args.top_k, classes.shape[0]) + for j in range(num_dets_to_consider): + if scores[j] < args.score_threshold: + num_dets_to_consider = j + break + + # Quick and dirty lambda for selecting the color for a particular index + # Also keeps track of a per-gpu color cache for maximum speed + def get_color(j, on_gpu=None): + global color_cache + color_idx = (classes[j] * 5 if class_color else j * 5) % len(COLORS) + + if on_gpu is not None and color_idx in color_cache[on_gpu]: + return color_cache[on_gpu][color_idx] + else: + color = COLORS[color_idx] + if not undo_transform: + # The image might come in as RGB or BRG, depending + color = (color[2], color[1], color[0]) + if on_gpu is not None: + color = torch.Tensor(color).to(on_gpu).float() / 255. + color_cache[on_gpu][color_idx] = color + return color + + # First, draw the masks on the GPU where we can do it really fast + # Beware: very fast but possibly unintelligible mask-drawing code ahead + # I wish I had access to OpenGL or Vulkan but alas, I guess Pytorch tensor operations will have to suffice + if args.display_masks and cfg.eval_mask_branch and num_dets_to_consider > 0: + # After this, mask is of size [num_dets, h, w, 1] + masks = masks[:num_dets_to_consider, :, :, None] + + # Prepare the RGB images for each mask given their color (size [num_dets, h, w, 1]) + colors = torch.cat([get_color(j, on_gpu=img_gpu.device.index).view(1, 1, 1, 3) for j in range(num_dets_to_consider)], dim=0) + masks_color = masks.repeat(1, 1, 1, 3) * colors * mask_alpha + + # This is 1 everywhere except for 1-mask_alpha where the mask is + inv_alph_masks = masks * (-mask_alpha) + 1 + + # I did the math for this on pen and paper. This whole block should be equivalent to: + # for j in range(num_dets_to_consider): + # img_gpu = img_gpu * inv_alph_masks[j] + masks_color[j] + masks_color_summand = masks_color[0] + if num_dets_to_consider > 1: + inv_alph_cumul = inv_alph_masks[:(num_dets_to_consider-1)].cumprod(dim=0) + masks_color_cumul = masks_color[1:] * inv_alph_cumul + masks_color_summand += masks_color_cumul.sum(dim=0) + + img_gpu = img_gpu * inv_alph_masks.prod(dim=0) + masks_color_summand + + if args.display_fps: + # Draw the box for the fps on the GPU + font_face = cv2.FONT_HERSHEY_DUPLEX + font_scale = 0.6 + font_thickness = 1 + + text_w, text_h = cv2.getTextSize(fps_str, font_face, font_scale, font_thickness)[0] + + img_gpu[0:text_h+8, 0:text_w+8] *= 0.6 # 1 - Box alpha + + + # Then draw the stuff that needs to be done on the cpu + # Note, make sure this is a uint8 tensor or opencv will not anti alias text for whatever reason + img_numpy = (img_gpu * 255).byte().cpu().numpy() + + if args.display_fps: + # Draw the text on the CPU + text_pt = (4, text_h + 2) + text_color = [255, 255, 255] + + cv2.putText(img_numpy, fps_str, text_pt, font_face, font_scale, text_color, font_thickness, cv2.LINE_AA) + + if num_dets_to_consider == 0: + return img_numpy + + if args.display_text or args.display_bboxes: + for j in reversed(range(num_dets_to_consider)): + x1, y1, x2, y2 = boxes[j, :] + color = get_color(j) + score = scores[j] + + if args.display_bboxes: + cv2.rectangle(img_numpy, (x1, y1), (x2, y2), color, 1) + + if args.display_text: + _class = cfg.dataset.class_names[classes[j]] + text_str = '%s: %.2f' % (_class, score) if args.display_scores else _class + + font_face = cv2.FONT_HERSHEY_DUPLEX + font_scale = 0.6 + font_thickness = 1 + + text_w, text_h = cv2.getTextSize(text_str, font_face, font_scale, font_thickness)[0] + + text_pt = (x1, y1 - 3) + text_color = [255, 255, 255] + + cv2.rectangle(img_numpy, (x1, y1), (x1 + text_w, y1 - text_h - 4), color, -1) + cv2.putText(img_numpy, text_str, text_pt, font_face, font_scale, text_color, font_thickness, cv2.LINE_AA) + + + return img_numpy + +def prep_benchmark(dets_out, h, w): + with timer.env('Postprocess'): + t = postprocess(dets_out, w, h, crop_masks=args.crop, score_threshold=args.score_threshold) + + with timer.env('Copy'): + classes, scores, boxes, masks = [x[:args.top_k] for x in t] + if isinstance(scores, list): + box_scores = scores[0].cpu().numpy() + mask_scores = scores[1].cpu().numpy() + else: + scores = scores.cpu().numpy() + classes = classes.cpu().numpy() + boxes = boxes.cpu().numpy() + masks = masks.cpu().numpy() + + with timer.env('Sync'): + # Just in case + torch.npu.synchronize() + +def prep_coco_cats(): + """ Prepare inverted table for category id lookup given a coco cats object. """ + for coco_cat_id, transformed_cat_id_p1 in get_label_map().items(): + transformed_cat_id = transformed_cat_id_p1 - 1 + coco_cats[transformed_cat_id] = coco_cat_id + coco_cats_inv[coco_cat_id] = transformed_cat_id + + +def get_coco_cat(transformed_cat_id): + """ transformed_cat_id is [0,80) as indices in cfg.dataset.class_names """ + return coco_cats[transformed_cat_id] + +def get_transformed_cat(coco_cat_id): + """ transformed_cat_id is [0,80) as indices in cfg.dataset.class_names """ + return coco_cats_inv[coco_cat_id] + + +class Detections: + + def __init__(self): + self.bbox_data = [] + self.mask_data = [] + + def add_bbox(self, image_id:int, category_id:int, bbox:list, score:float): + """ Note that bbox should be a list or tuple of (x1, y1, x2, y2) """ + bbox = [bbox[0], bbox[1], bbox[2]-bbox[0], bbox[3]-bbox[1]] + + # Round to the nearest 10th to avoid huge file sizes, as COCO suggests + bbox = [round(float(x)*10)/10 for x in bbox] + + self.bbox_data.append({ + 'image_id': int(image_id), + 'category_id': get_coco_cat(int(category_id)), + 'bbox': bbox, + 'score': float(score) + }) + + def add_mask(self, image_id:int, category_id:int, segmentation:np.ndarray, score:float): + """ The segmentation should be the full mask, the size of the image and with size [h, w]. """ + rle = pycocotools.mask.encode(np.asfortranarray(segmentation.astype(np.uint8))) + rle['counts'] = rle['counts'].decode('ascii') # json.dump doesn't like bytes strings + + self.mask_data.append({ + 'image_id': int(image_id), + 'category_id': get_coco_cat(int(category_id)), + 'segmentation': rle, + 'score': float(score) + }) + + def dump(self): + dump_arguments = [ + (self.bbox_data, args.bbox_det_file), + (self.mask_data, args.mask_det_file) + ] + + for data, path in dump_arguments: + with open(path, 'w') as f: + json.dump(data, f) + + def dump_web(self): + """ Dumps it in the format for my web app. Warning: bad code ahead! """ + config_outs = ['preserve_aspect_ratio', 'use_prediction_module', + 'use_yolo_regressors', 'use_prediction_matching', + 'train_masks'] + + output = { + 'info' : { + 'Config': {key: getattr(cfg, key) for key in config_outs}, + } + } + + image_ids = list(set([x['image_id'] for x in self.bbox_data])) + image_ids.sort() + image_lookup = {_id: idx for idx, _id in enumerate(image_ids)} + + output['images'] = [{'image_id': image_id, 'dets': []} for image_id in image_ids] + + # These should already be sorted by score with the way prep_metrics works. + for bbox, mask in zip(self.bbox_data, self.mask_data): + image_obj = output['images'][image_lookup[bbox['image_id']]] + image_obj['dets'].append({ + 'score': bbox['score'], + 'bbox': bbox['bbox'], + 'category': cfg.dataset.class_names[get_transformed_cat(bbox['category_id'])], + 'mask': mask['segmentation'], + }) + + with open(os.path.join(args.web_det_path, '%s.json' % cfg.name), 'w') as f: + json.dump(output, f) + + + + +def _mask_iou(mask1, mask2, iscrowd=False): + with timer.env('Mask IoU'): + ret = mask_iou(mask1, mask2, iscrowd) + return ret.cpu() + +def _bbox_iou(bbox1, bbox2, iscrowd=False): + with timer.env('BBox IoU'): + ret = jaccard(bbox1, bbox2, iscrowd) + return ret.cpu() + +def prep_metrics(ap_data, dets, img, gt, gt_masks, h, w, num_crowd, image_id, detections:Detections=None): + """ Returns a list of APs for this image, with each element being for a class """ + if not args.output_coco_json: + with timer.env('Prepare gt'): + gt_boxes = torch.Tensor(gt[:, :4]) if args.cuda else torch.Tensor(gt[:, :4]) + gt_boxes[:, [0, 2]] *= w + gt_boxes[:, [1, 3]] *= h + gt_classes = list(gt[:, 4].astype(int)) + gt_masks = torch.Tensor(gt_masks).view(-1, h*w) if args.cuda else torch.Tensor(gt_masks).view(-1, h*w) + + if num_crowd > 0: + split = lambda x: (x[-num_crowd:], x[:-num_crowd]) + crowd_boxes , gt_boxes = split(gt_boxes) + crowd_masks , gt_masks = split(gt_masks) + crowd_classes, gt_classes = split(gt_classes) + + with timer.env('Postprocess'): + classes, scores, boxes, masks = postprocess(dets, w, h, crop_masks=args.crop, score_threshold=args.score_threshold) + + if classes.size(0) == 0: + return + + classes = list(classes.cpu().numpy().astype(int)) + if isinstance(scores, list): + box_scores = list(scores[0].cpu().numpy().astype(float)) + mask_scores = list(scores[1].cpu().numpy().astype(float)) + else: + scores = list(scores.cpu().numpy().astype(float)) + box_scores = scores + mask_scores = scores + # if args.cuda: + # masks = masks.view(-1, h*w).npu() + # boxes = boxes.npu() + # else: + masks = masks.view(-1, h*w) + + + if args.output_coco_json: + with timer.env('JSON Output'): + boxes = boxes.cpu().numpy() + masks = masks.view(-1, h, w).cpu().numpy() + for i in range(masks.shape[0]): + # Make sure that the bounding box actually makes sense and a mask was produced + if (boxes[i, 3] - boxes[i, 1]) * (boxes[i, 2] - boxes[i, 0]) > 0: + detections.add_bbox(image_id, classes[i], boxes[i,:], box_scores[i]) + detections.add_mask(image_id, classes[i], masks[i,:,:], mask_scores[i]) + return + + with timer.env('Eval Setup'): + num_pred = len(classes) + num_gt = len(gt_classes) + + mask_iou_cache = _mask_iou(masks, gt_masks) + bbox_iou_cache = _bbox_iou(boxes.float(), gt_boxes.float()) + + if num_crowd > 0: + crowd_mask_iou_cache = _mask_iou(masks, crowd_masks, iscrowd=True) + crowd_bbox_iou_cache = _bbox_iou(boxes.float(), crowd_boxes.float(), iscrowd=True) + else: + crowd_mask_iou_cache = None + crowd_bbox_iou_cache = None + + box_indices = sorted(range(num_pred), key=lambda i: -box_scores[i]) + mask_indices = sorted(box_indices, key=lambda i: -mask_scores[i]) + + iou_types = [ + ('box', lambda i,j: bbox_iou_cache[i, j].item(), + lambda i,j: crowd_bbox_iou_cache[i,j].item(), + lambda i: box_scores[i], box_indices), + ('mask', lambda i,j: mask_iou_cache[i, j].item(), + lambda i,j: crowd_mask_iou_cache[i,j].item(), + lambda i: mask_scores[i], mask_indices) + ] + + timer.start('Main loop') + for _class in set(classes + gt_classes): + ap_per_iou = [] + num_gt_for_class = sum([1 for x in gt_classes if x == _class]) + + for iouIdx in range(len(iou_thresholds)): + iou_threshold = iou_thresholds[iouIdx] + + for iou_type, iou_func, crowd_func, score_func, indices in iou_types: + gt_used = [False] * len(gt_classes) + + ap_obj = ap_data[iou_type][iouIdx][_class] + ap_obj.add_gt_positives(num_gt_for_class) + + for i in indices: + if classes[i] != _class: + continue + + max_iou_found = iou_threshold + max_match_idx = -1 + for j in range(num_gt): + if gt_used[j] or gt_classes[j] != _class: + continue + + iou = iou_func(i, j) + + if iou > max_iou_found: + max_iou_found = iou + max_match_idx = j + + if max_match_idx >= 0: + gt_used[max_match_idx] = True + ap_obj.push(score_func(i), True) + else: + # If the detection matches a crowd, we can just ignore it + matched_crowd = False + + if num_crowd > 0: + for j in range(len(crowd_classes)): + if crowd_classes[j] != _class: + continue + + iou = crowd_func(i, j) + + if iou > iou_threshold: + matched_crowd = True + break + + # All this crowd code so that we can make sure that our eval code gives the + # same result as COCOEval. There aren't even that many crowd annotations to + # begin with, but accuracy is of the utmost importance. + if not matched_crowd: + ap_obj.push(score_func(i), False) + timer.stop('Main loop') + + +class APDataObject: + """ + Stores all the information necessary to calculate the AP for one IoU and one class. + Note: I type annotated this because why not. + """ + + def __init__(self): + self.data_points = [] + self.num_gt_positives = 0 + + def push(self, score:float, is_true:bool): + self.data_points.append((score, is_true)) + + def add_gt_positives(self, num_positives:int): + """ Call this once per image. """ + self.num_gt_positives += num_positives + + def is_empty(self) -> bool: + return len(self.data_points) == 0 and self.num_gt_positives == 0 + + def get_ap(self) -> float: + """ Warning: result not cached. """ + + if self.num_gt_positives == 0: + return 0 + + # Sort descending by score + self.data_points.sort(key=lambda x: -x[0]) + + precisions = [] + recalls = [] + num_true = 0 + num_false = 0 + + # Compute the precision-recall curve. The x axis is recalls and the y axis precisions. + for datum in self.data_points: + # datum[1] is whether the detection a true or false positive + if datum[1]: num_true += 1 + else: num_false += 1 + + precision = num_true / (num_true + num_false) + recall = num_true / self.num_gt_positives + + precisions.append(precision) + recalls.append(recall) + + # Smooth the curve by computing [max(precisions[i:]) for i in range(len(precisions))] + # Basically, remove any temporary dips from the curve. + # At least that's what I think, idk. COCOEval did it so I do too. + for i in range(len(precisions)-1, 0, -1): + if precisions[i] > precisions[i-1]: + precisions[i-1] = precisions[i] + + # Compute the integral of precision(recall) d_recall from recall=0->1 using fixed-length riemann summation with 101 bars. + y_range = [0] * 101 # idx 0 is recall == 0.0 and idx 100 is recall == 1.00 + x_range = np.array([x / 100 for x in range(101)]) + recalls = np.array(recalls) + + # I realize this is weird, but all it does is find the nearest precision(x) for a given x in x_range. + # Basically, if the closest recall we have to 0.01 is 0.009 this sets precision(0.01) = precision(0.009). + # I approximate the integral this way, because that's how COCOEval does it. + indices = np.searchsorted(recalls, x_range, side='left') + for bar_idx, precision_idx in enumerate(indices): + if precision_idx < len(precisions): + y_range[bar_idx] = precisions[precision_idx] + + # Finally compute the riemann sum to get our integral. + # avg([precision(x) for x in 0:0.01:1]) + return sum(y_range) / len(y_range) + +def badhash(x): + """ + Just a quick and dirty hash function for doing a deterministic shuffle based on image_id. + + Source: + https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key + """ + x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF + x = (((x >> 16) ^ x) * 0x045d9f3b) & 0xFFFFFFFF + x = ((x >> 16) ^ x) & 0xFFFFFFFF + return x + +def evalimage(net:Yolact, path:str, save_path:str=None): + if args.cuda: + frame = torch.from_numpy(cv2.imread(path)).npu().float() + else: + frame = torch.from_numpy(cv2.imread(path)).float() + print('frame: ', frame) + batch = FastBaseTransform()(frame.unsqueeze(0)) + print('batch_pred:', batch) + print('batch_shape:', batch.shape) + preds = net(batch) + + img_numpy = prep_display(preds, frame, None, None, undo_transform=False) + + if save_path is None: + img_numpy = img_numpy[:, :, (2, 1, 0)] + + if save_path is None: + plt.imshow(img_numpy) + plt.title(path) + plt.show() + else: + cv2.imwrite(save_path, img_numpy) + +def evalimages(net:Yolact, input_folder:str, output_folder:str): + if not os.path.exists(output_folder): + os.mkdir(output_folder) + + print() + for p in Path(input_folder).glob('*'): + path = str(p) + name = os.path.basename(path) + name = '.'.join(name.split('.')[:-1]) + '.png' + out_path = os.path.join(output_folder, name) + + evalimage(net, path, out_path) + print(path + ' -> ' + out_path) + print('Done.') + +from multiprocessing.pool import ThreadPool +from queue import Queue + +class CustomDataParallel(torch.nn.DataParallel): + """ A Custom Data Parallel class that properly gathers lists of dictionaries. """ + def gather(self, outputs, output_device): + # Note that I don't actually want to convert everything to the output_device + return sum(outputs, []) + +def evalvideo(net:Yolact, path:str, out_path:str=None): + # If the path is a digit, parse it as a webcam index + is_webcam = path.isdigit() + + # If the input image size is constant, this make things faster (hence why we can use it in a video setting). + cudnn.benchmark = True + + if is_webcam: + vid = cv2.VideoCapture(int(path)) + else: + vid = cv2.VideoCapture(path) + + if not vid.isOpened(): + print('Could not open video "%s"' % path) + exit(-1) + + target_fps = round(vid.get(cv2.CAP_PROP_FPS)) + frame_width = round(vid.get(cv2.CAP_PROP_FRAME_WIDTH)) + frame_height = round(vid.get(cv2.CAP_PROP_FRAME_HEIGHT)) + + if is_webcam: + num_frames = float('inf') + else: + num_frames = round(vid.get(cv2.CAP_PROP_FRAME_COUNT)) + + net = CustomDataParallel(net).npu() + transform = torch.nn.DataParallel(FastBaseTransform()).npu() + frame_times = MovingAverage(100) + fps = 0 + frame_time_target = 1 / target_fps + running = True + fps_str = '' + vid_done = False + frames_displayed = 0 + + if out_path is not None: + out = cv2.VideoWriter(out_path, cv2.VideoWriter_fourcc(*"mp4v"), target_fps, (frame_width, frame_height)) + + def cleanup_and_exit(): + print() + pool.terminate() + vid.release() + if out_path is not None: + out.release() + cv2.destroyAllWindows() + exit() + + def get_next_frame(vid): + frames = [] + for idx in range(args.video_multiframe): + frame = vid.read()[1] + if frame is None: + return frames + frames.append(frame) + return frames + + def transform_frame(frames): + with torch.no_grad(): + frames = [torch.from_numpy(frame).npu().float() for frame in frames] + return frames, transform(torch.stack(frames, 0)) + + def eval_network(inp): + with torch.no_grad(): + frames, imgs = inp + num_extra = 0 + while imgs.size(0) < args.video_multiframe: + imgs = torch.cat([imgs, imgs[0].unsqueeze(0)], dim=0) + num_extra += 1 + out = net(imgs) + if num_extra > 0: + out = out[:-num_extra] + return frames, out + + def prep_frame(inp, fps_str): + with torch.no_grad(): + frame, preds = inp + return prep_display(preds, frame, None, None, undo_transform=False, class_color=True, fps_str=fps_str) + + frame_buffer = Queue() + video_fps = 0 + + # All this timing code to make sure that + def play_video(): + try: + nonlocal frame_buffer, running, video_fps, is_webcam, num_frames, frames_displayed, vid_done + + video_frame_times = MovingAverage(100) + frame_time_stabilizer = frame_time_target + last_time = None + stabilizer_step = 0.0005 + progress_bar = ProgressBar(30, num_frames) + + while running: + frame_time_start = time.time() + + if not frame_buffer.empty(): + next_time = time.time() + if last_time is not None: + video_frame_times.add(next_time - last_time) + video_fps = 1 / video_frame_times.get_avg() + if out_path is None: + cv2.imshow(path, frame_buffer.get()) + else: + out.write(frame_buffer.get()) + frames_displayed += 1 + last_time = next_time + + if out_path is not None: + if video_frame_times.get_avg() == 0: + fps = 0 + else: + fps = 1 / video_frame_times.get_avg() + progress = frames_displayed / num_frames * 100 + progress_bar.set_val(frames_displayed) + + print('\rProcessing Frames %s %6d / %6d (%5.2f%%) %5.2f fps ' + % (repr(progress_bar), frames_displayed, num_frames, progress, fps), end='') + + + # This is split because you don't want savevideo to require cv2 display functionality (see #197) + if out_path is None and cv2.waitKey(1) == 27: + # Press Escape to close + running = False + if not (frames_displayed < num_frames): + running = False + + if not vid_done: + buffer_size = frame_buffer.qsize() + if buffer_size < args.video_multiframe: + frame_time_stabilizer += stabilizer_step + elif buffer_size > args.video_multiframe: + frame_time_stabilizer -= stabilizer_step + if frame_time_stabilizer < 0: + frame_time_stabilizer = 0 + + new_target = frame_time_stabilizer if is_webcam else max(frame_time_stabilizer, frame_time_target) + else: + new_target = frame_time_target + + next_frame_target = max(2 * new_target - video_frame_times.get_avg(), 0) + target_time = frame_time_start + next_frame_target - 0.001 # Let's just subtract a millisecond to be safe + + if out_path is None or args.emulate_playback: + # This gives more accurate timing than if sleeping the whole amount at once + while time.time() < target_time: + time.sleep(0.001) + else: + # Let's not starve the main thread, now + time.sleep(0.001) + except: + # See issue #197 for why this is necessary + import traceback + traceback.print_exc() + + + extract_frame = lambda x, i: (x[0][i] if x[1][i]['detection'] is None else x[0][i].to(x[1][i]['detection']['box'].device), [x[1][i]]) + + # Prime the network on the first frame because I do some thread unsafe things otherwise + print('Initializing model... ', end='') + first_batch = eval_network(transform_frame(get_next_frame(vid))) + print('Done.') + + # For each frame the sequence of functions it needs to go through to be processed (in reversed order) + sequence = [prep_frame, eval_network, transform_frame] + pool = ThreadPool(processes=len(sequence) + args.video_multiframe + 2) + pool.apply_async(play_video) + active_frames = [{'value': extract_frame(first_batch, i), 'idx': 0} for i in range(len(first_batch[0]))] + + print() + if out_path is None: print('Press Escape to close.') + try: + while vid.isOpened() and running: + # Hard limit on frames in buffer so we don't run out of memory >.> + while frame_buffer.qsize() > 100: + time.sleep(0.001) + + start_time = time.time() + + # Start loading the next frames from the disk + if not vid_done: + next_frames = pool.apply_async(get_next_frame, args=(vid,)) + else: + next_frames = None + + if not (vid_done and len(active_frames) == 0): + # For each frame in our active processing queue, dispatch a job + # for that frame using the current function in the sequence + for frame in active_frames: + _args = [frame['value']] + if frame['idx'] == 0: + _args.append(fps_str) + frame['value'] = pool.apply_async(sequence[frame['idx']], args=_args) + + # For each frame whose job was the last in the sequence (i.e. for all final outputs) + for frame in active_frames: + if frame['idx'] == 0: + frame_buffer.put(frame['value'].get()) + + # Remove the finished frames from the processing queue + active_frames = [x for x in active_frames if x['idx'] > 0] + + # Finish evaluating every frame in the processing queue and advanced their position in the sequence + for frame in list(reversed(active_frames)): + frame['value'] = frame['value'].get() + frame['idx'] -= 1 + + if frame['idx'] == 0: + # Split this up into individual threads for prep_frame since it doesn't support batch size + active_frames += [{'value': extract_frame(frame['value'], i), 'idx': 0} for i in range(1, len(frame['value'][0]))] + frame['value'] = extract_frame(frame['value'], 0) + + # Finish loading in the next frames and add them to the processing queue + if next_frames is not None: + frames = next_frames.get() + if len(frames) == 0: + vid_done = True + else: + active_frames.append({'value': frames, 'idx': len(sequence)-1}) + + # Compute FPS + frame_times.add(time.time() - start_time) + fps = args.video_multiframe / frame_times.get_avg() + else: + fps = 0 + + fps_str = 'Processing FPS: %.2f | Video Playback FPS: %.2f | Frames in Buffer: %d' % (fps, video_fps, frame_buffer.qsize()) + if not args.display_fps: + print('\r' + fps_str + ' ', end='') + + except KeyboardInterrupt: + print('\nStopping...') + + cleanup_and_exit() + +def evaluate(net:Yolact, dataset, train_mode=False, trainCuda = True): + net.detect.use_fast_nms = args.fast_nms + net.detect.use_cross_class_nms = args.cross_class_nms + cfg.mask_proto_debug = args.mask_proto_debug + + # TODO Currently we do not support Fast Mask Re-scroing in evalimage, evalimages, and evalvideo + if args.image is not None: + if ':' in args.image: + inp, out = args.image.split(':') + evalimage(net, inp, out) + else: + evalimage(net, args.image) + return + elif args.images is not None: + inp, out = args.images.split(':') + evalimages(net, inp, out) + return + elif args.video is not None: + if ':' in args.video: + inp, out = args.video.split(':') + evalvideo(net, inp, out) + else: + evalvideo(net, args.video) + return + + frame_times = MovingAverage() + dataset_size = len(dataset) if args.max_images < 0 else min(args.max_images, len(dataset)) + progress_bar = ProgressBar(30, dataset_size) + + print() + + if not args.display and not args.benchmark: + # For each class and iou, stores tuples (score, isPositive) + # Index ap_data[type][iouIdx][classIdx] + ap_data = { + 'box' : [[APDataObject() for _ in cfg.dataset.class_names] for _ in iou_thresholds], + 'mask': [[APDataObject() for _ in cfg.dataset.class_names] for _ in iou_thresholds] + } + detections = Detections() + else: + timer.disable('Load Data') + + dataset_indices = list(range(len(dataset))) + + if args.shuffle: + random.shuffle(dataset_indices) + elif not args.no_sort: + # Do a deterministic shuffle based on the image ids + # + # I do this because on python 3.5 dictionary key order is *random*, while in 3.6 it's + # the order of insertion. That means on python 3.6, the images come in the order they are in + # in the annotations file. For some reason, the first images in the annotations file are + # the hardest. To combat this, I use a hard-coded hash function based on the image ids + # to shuffle the indices we use. That way, no matter what python version or how pycocotools + # handles the data, we get the same result every time. + hashed = [badhash(x) for x in dataset.ids] + dataset_indices.sort(key=lambda x: hashed[x]) + + dataset_indices = dataset_indices[:dataset_size] + + try: + # Main eval loop + for it, image_idx in enumerate(tqdm(dataset_indices)): + timer.reset() + + with timer.env('Load Data'): + img, gt, gt_masks, h, w, num_crowd = dataset.pull_item(image_idx) + # Test flag, do not upvote + if cfg.mask_proto_debug: + with open('scripts/info.txt', 'w') as f: + f.write(str(dataset.ids[image_idx])) + np.save('scripts/gt.npy', gt_masks) + + batch = Variable(img.unsqueeze(0)) + if args.cuda: + if train_mode: + batch = batch.npu() if trainCuda else batch + else: + batch = batch.npu() + + with timer.env('Network Extra'): + preds = net(batch) + if preds is not None and preds[0] is not None: + if preds[0]['box'] is not None: + preds[0]['box'] = preds[0]['box'].cpu() + if preds[0]['mask'] is not None: + preds[0]['mask'] = preds[0]['mask'].cpu() + if preds[0]['class'] is not None: + preds[0]['class'] = preds[0]['class'].cpu() + if preds[0]['score'] is not None: + preds[0]['score'] = preds[0]['score'].cpu() + if preds[0]['proto'] is not None: + preds[0]['proto'] = preds[0]['proto'].cpu() + + # Perform the meat of the operation here depending on our mode. + if args.display: + img_numpy = prep_display(preds, img, h, w) + elif args.benchmark: + prep_benchmark(preds, h, w) + else: + prep_metrics(ap_data, preds, img, gt, gt_masks, h, w, num_crowd, dataset.ids[image_idx], detections) + + # First couple of images take longer because we're constructing the graph. + # Since that's technically initialization, don't include those in the FPS calculations. + if it > 1: + frame_times.add(timer.total_time()) + + if args.display: + if it > 1: + print('Avg FPS: %.4f' % (1 / frame_times.get_avg())) + plt.imshow(img_numpy) + plt.title(str(dataset.ids[image_idx])) + plt.show() + elif not args.no_bar: + if it > 1: fps = 1 / frame_times.get_avg() + else: fps = 0 + progress = (it+1) / dataset_size * 100 + progress_bar.set_val(it+1) + print('\rProcessing Images %s %6d / %6d (%5.2f%%) %5.2f fps ' + % (repr(progress_bar), it+1, dataset_size, progress, fps), end='') + + + + if not args.display and not args.benchmark: + print() + if args.output_coco_json: + print('Dumping detections...') + if args.output_web_json: + detections.dump_web() + else: + detections.dump() + else: + if not train_mode: + print('Saving data...') + with open(args.ap_data_file, 'wb') as f: + pickle.dump(ap_data, f) + + return calc_map(ap_data) + elif args.benchmark: + print() + print() + print('Stats for the last frame:') + timer.print_stats() + avg_seconds = frame_times.get_avg() + print('Average: %5.2f fps, %5.2f ms' % (1 / frame_times.get_avg(), 1000*avg_seconds)) + + except KeyboardInterrupt: + print('Stopping...') + + +def calc_map(ap_data): + print('Calculating mAP...') + aps = [{'box': [], 'mask': []} for _ in iou_thresholds] + + for _class in range(len(cfg.dataset.class_names)): + for iou_idx in range(len(iou_thresholds)): + for iou_type in ('box', 'mask'): + ap_obj = ap_data[iou_type][iou_idx][_class] + + if not ap_obj.is_empty(): + aps[iou_idx][iou_type].append(ap_obj.get_ap()) + + all_maps = {'box': OrderedDict(), 'mask': OrderedDict()} + + # Looking back at it, this code is really hard to read :/ + for iou_type in ('box', 'mask'): + all_maps[iou_type]['all'] = 0 # Make this first in the ordereddict + for i, threshold in enumerate(iou_thresholds): + mAP = sum(aps[i][iou_type]) / len(aps[i][iou_type]) * 100 if len(aps[i][iou_type]) > 0 else 0 + all_maps[iou_type][int(threshold*100)] = mAP + all_maps[iou_type]['all'] = (sum(all_maps[iou_type].values()) / (len(all_maps[iou_type].values())-1)) + + print_maps(all_maps) + + # Put in a prettier format so we can serialize it to json during training + all_maps = {k: {j: round(u, 2) for j, u in v.items()} for k, v in all_maps.items()} + return all_maps + +def print_maps(all_maps): + # Warning: hacky + make_row = lambda vals: (' %5s |' * len(vals)) % tuple(vals) + make_sep = lambda n: ('-------+' * n) + + print() + print(make_row([''] + [('.%d ' % x if isinstance(x, int) else x + ' ') for x in all_maps['box'].keys()])) + print(make_sep(len(all_maps['box']) + 1)) + for iou_type in ('box', 'mask'): + print(make_row([iou_type] + ['%.2f' % x if x < 100 else '%.1f' % x for x in all_maps[iou_type].values()])) + print(make_sep(len(all_maps['box']) + 1)) + print() + + + +if __name__ == '__main__': + parse_args() + + if args.config is not None: + set_cfg(args.config) + + if args.trained_model == 'interrupt': + + args.trained_model = SavePath.get_interrupt('weights/') + elif args.trained_model == 'latest': + args.trained_model = SavePath.get_latest('weights/', cfg.name) + + if args.config is None: + model_path = SavePath.from_str(args.trained_model) + # TODO: Bad practice? Probably want to do a name lookup instead. + args.config = model_path.model_name + '_config' + print('Config not specified. Parsed %s from the file name.\n' % args.config) + set_cfg(args.config) + + if args.detect: + cfg.eval_mask_branch = False + + if args.dataset is not None: + set_dataset(args.dataset) + + if args.data_path: + cfg.dataset.valid_images = args.data_path + '/images/' + cfg.dataset.valid_info = args.data_path + '/annotations/instances_val2017.json' + + with torch.no_grad(): + if not os.path.exists('results'): + os.makedirs('results') + + if args.cuda: + cudnn.fastest = True + args.device = torch.device(f'npu:{args.rank_id}') + torch.npu.set_device(args.device) + #torch.set_default_tensor_type('torch.npu.FloatTensor') + else: + torch.set_default_tensor_type('torch.FloatTensor') + + if args.resume and not args.display: + with open(args.ap_data_file, 'rb') as f: + ap_data = pickle.load(f) + calc_map(ap_data) + exit() + + if args.image is None and args.video is None and args.images is None: + dataset = COCODetection(cfg.dataset.valid_images, cfg.dataset.valid_info, + transform=BaseTransform(), has_gt=cfg.dataset.has_gt) + prep_coco_cats() + else: + dataset = None + + print('Loading model...', end='') + net = Yolact() + net.load_weights(args.trained_model) + net.eval() + print(' Done.') + + if args.cuda: + net = net.npu() + + evaluate(net, dataset) + + diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/layers/__init__.py b/PyTorch/contrib/cv/detection/YOLACT_plus/layers/__init__.py index 59dfcbd639..53a3f4b516 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/layers/__init__.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/layers/__init__.py @@ -1,2 +1,2 @@ -from .functions import * -from .modules import * +from .functions import * +from .modules import * diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/layers/box_utils.py b/PyTorch/contrib/cv/detection/YOLACT_plus/layers/box_utils.py index 6f84f55ab0..7114b7b120 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/layers/box_utils.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/layers/box_utils.py @@ -1,403 +1,403 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ -# -*- coding: utf-8 -*- -import torch -from utils import timer - -from data import cfg - -@torch.jit.script -def point_form(boxes): - """ Convert prior_boxes to (xmin, ymin, xmax, ymax) - representation for comparison to point form ground truth data. - Args: - boxes: (tensor) center-size default boxes from priorbox layers. - Return: - boxes: (tensor) Converted xmin, ymin, xmax, ymax form of boxes. - """ - return torch.cat((boxes[:, :2] - boxes[:, 2:]/2, # xmin, ymin - boxes[:, :2] + boxes[:, 2:]/2), 1) # xmax, ymax - - -@torch.jit.script -def center_size(boxes): - """ Convert prior_boxes to (cx, cy, w, h) - representation for comparison to center-size form ground truth data. - Args: - boxes: (tensor) point_form boxes - Return: - boxes: (tensor) Converted xmin, ymin, xmax, ymax form of boxes. - """ - return torch.cat(( (boxes[:, 2:] + boxes[:, :2])/2, # cx, cy - boxes[:, 2:] - boxes[:, :2] ), 1) # w, h - -@torch.jit.script -def intersect(box_a, box_b): - """ We resize both tensors to [A,B,2] without new malloc: - [A,2] -> [A,1,2] -> [A,B,2] - [B,2] -> [1,B,2] -> [A,B,2] - Then we compute the area of intersect between box_a and box_b. - Args: - box_a: (tensor) bounding boxes, Shape: [n,A,4]. - box_b: (tensor) bounding boxes, Shape: [n,B,4]. - Return: - (tensor) intersection area, Shape: [n,A,B]. - """ - n = box_a.size(0) - A = box_a.size(1) - B = box_b.size(1) - max_xy = torch.min(box_a[:, :, 2:].unsqueeze(2).expand(n, A, B, 2), - box_b[:, :, 2:].unsqueeze(1).expand(n, A, B, 2)) - min_xy = torch.max(box_a[:, :, :2].unsqueeze(2).expand(n, A, B, 2), - box_b[:, :, :2].unsqueeze(1).expand(n, A, B, 2)) - return torch.clamp(max_xy - min_xy, min=0).prod(3) # inter - - -def jaccard(box_a, box_b, iscrowd:bool=False): - """Compute the jaccard overlap of two sets of boxes. The jaccard overlap - is simply the intersection over union of two boxes. Here we operate on - ground truth boxes and default boxes. If iscrowd=True, put the crowd in box_b. - E.g.: - A ∩ B / A ∪ B = A ∩ B / (area(A) + area(B) - A ∩ B) - Args: - box_a: (tensor) Ground truth bounding boxes, Shape: [num_objects,4] - box_b: (tensor) Prior boxes from priorbox layers, Shape: [num_priors,4] - Return: - jaccard overlap: (tensor) Shape: [box_a.size(0), box_b.size(0)] - """ - use_batch = True - if box_a.dim() == 2: - use_batch = False - box_a = box_a[None, ...] - box_b = box_b[None, ...] - - inter = intersect(box_a, box_b) - area_a = ((box_a[:, :, 2]-box_a[:, :, 0]) * - (box_a[:, :, 3]-box_a[:, :, 1])).unsqueeze(2).expand_as(inter) # [A,B] - area_b = ((box_b[:, :, 2]-box_b[:, :, 0]) * - (box_b[:, :, 3]-box_b[:, :, 1])).unsqueeze(1).expand_as(inter) # [A,B] - union = area_a + area_b - inter - - out = inter / area_a if iscrowd else inter / union - return out if use_batch else out.squeeze(0) - -def elemwise_box_iou(box_a, box_b): - """ Does the same as above but instead of pairwise, elementwise along the inner dimension. """ - max_xy = torch.min(box_a[:, 2:], box_b[:, 2:]) - min_xy = torch.max(box_a[:, :2], box_b[:, :2]) - inter = torch.clamp((max_xy - min_xy), min=0) - inter = inter[:, 0] * inter[:, 1] - - area_a = (box_a[:, 2] - box_a[:, 0]) * (box_a[:, 3] - box_a[:, 1]) - area_b = (box_b[:, 2] - box_b[:, 0]) * (box_b[:, 3] - box_b[:, 1]) - - union = area_a + area_b - inter - union = torch.clamp(union, min=0.1) - - # Return value is [n] for inputs [n, 4] - return torch.clamp(inter / union, max=1) - -def mask_iou(masks_a, masks_b, iscrowd=False): - """ - Computes the pariwise mask IoU between two sets of masks of size [a, h, w] and [b, h, w]. - The output is of size [a, b]. - - Wait I thought this was "box_utils", why am I putting this in here? - """ - - masks_a = masks_a.view(masks_a.size(0), -1) - masks_b = masks_b.view(masks_b.size(0), -1) - - intersection = masks_a @ masks_b.t() - area_a = masks_a.sum(dim=1).unsqueeze(1) - area_b = masks_b.sum(dim=1).unsqueeze(0) - - return intersection / (area_a + area_b - intersection) if not iscrowd else intersection / area_a - -def elemwise_mask_iou(masks_a, masks_b): - """ Does the same as above but instead of pairwise, elementwise along the outer dimension. """ - masks_a = masks_a.view(-1, masks_a.size(-1)) - masks_b = masks_b.view(-1, masks_b.size(-1)) - - intersection = (masks_a * masks_b).sum(dim=0) - area_a = masks_a.sum(dim=0) - area_b = masks_b.sum(dim=0) - - # Return value is [n] for inputs [h, w, n] - return torch.clamp(intersection / torch.clamp(area_a + area_b - intersection, min=0.1), max=1) - - - -def change(gt, priors): - """ - Compute the d_change metric proposed in Box2Pix: - https://lmb.informatik.uni-freiburg.de/Publications/2018/UB18/paper-box2pix.pdf - - Input should be in point form (xmin, ymin, xmax, ymax). - - Output is of shape [num_gt, num_priors] - Note this returns -change so it can be a drop in replacement for - """ - num_priors = priors.size(0) - num_gt = gt.size(0) - - gt_w = (gt[:, 2] - gt[:, 0])[:, None].expand(num_gt, num_priors) - gt_h = (gt[:, 3] - gt[:, 1])[:, None].expand(num_gt, num_priors) - - gt_mat = gt[:, None, :].expand(num_gt, num_priors, 4) - pr_mat = priors[None, :, :].expand(num_gt, num_priors, 4) - - diff = gt_mat - pr_mat - diff[:, :, 0] /= gt_w - diff[:, :, 2] /= gt_w - diff[:, :, 1] /= gt_h - diff[:, :, 3] /= gt_h - - return -torch.sqrt( (diff ** 2).sum(dim=2) ) - - - - -def match(pos_thresh, neg_thresh, truths, priors, labels, crowd_boxes, loc_t, conf_t, idx_t, idx, loc_data): - """Match each prior box with the ground truth box of the highest jaccard - overlap, encode the bounding boxes, then return the matched indices - corresponding to both confidence and location preds. - Args: - pos_thresh: (float) IoU > pos_thresh ==> positive. - neg_thresh: (float) IoU < neg_thresh ==> negative. - truths: (tensor) Ground truth boxes, Shape: [num_obj, num_priors]. - priors: (tensor) Prior boxes from priorbox layers, Shape: [n_priors,4]. - labels: (tensor) All the class labels for the image, Shape: [num_obj]. - crowd_boxes: (tensor) All the crowd box annotations or None if there are none. - loc_t: (tensor) Tensor to be filled w/ endcoded location targets. - conf_t: (tensor) Tensor to be filled w/ matched indices for conf preds. Note: -1 means neutral. - idx_t: (tensor) Tensor to be filled w/ the index of the matched gt box for each prior. - idx: (int) current batch index. - loc_data: (tensor) The predicted bbox regression coordinates for this batch. - Return: - The matched indices corresponding to 1)location and 2)confidence preds. - """ - decoded_priors = decode(loc_data, priors, cfg.use_yolo_regressors) if cfg.use_prediction_matching else point_form(priors) - - # Size [num_objects, num_priors] - overlaps = jaccard(truths, decoded_priors) if not cfg.use_change_matching else change(truths, decoded_priors) - - # Size [num_priors] best ground truth for each prior - best_truth_overlap, best_truth_idx = overlaps.max(0) - - # We want to ensure that each gt gets used at least once so that we don't - # waste any training data. In order to do that, find the max overlap anchor - # with each gt, and force that anchor to use that gt. - for _ in range(overlaps.size(0)): - # Find j, the gt with the highest overlap with a prior - # In effect, this will loop through overlaps.size(0) in a "smart" order, - # always choosing the highest overlap first. - best_prior_overlap, best_prior_idx = overlaps.max(1) - j = best_prior_overlap.max(0)[1] - - # Find i, the highest overlap anchor with this gt - i = best_prior_idx[j] - - # Set all other overlaps with i to be -1 so that no other gt uses it - overlaps[:, i] = -1 - # Set all other overlaps with j to be -1 so that this loop never uses j again - overlaps[j, :] = -1 - - # Overwrite i's score to be 2 so it doesn't get thresholded ever - best_truth_overlap[i] = 2 - # Set the gt to be used for i to be j, overwriting whatever was there - best_truth_idx[i] = j - - matches = truths[best_truth_idx] # Shape: [num_priors,4] - conf = labels[best_truth_idx] + 1 # Shape: [num_priors] - - conf[best_truth_overlap < pos_thresh] = -1 # label as neutral - conf[best_truth_overlap < neg_thresh] = 0 # label as background - - # Deal with crowd annotations for COCO - if crowd_boxes is not None and cfg.crowd_iou_threshold < 1: - # Size [num_priors, num_crowds] - crowd_overlaps = jaccard(decoded_priors, crowd_boxes, iscrowd=True) - # Size [num_priors] - best_crowd_overlap, best_crowd_idx = crowd_overlaps.max(1) - # Set non-positives with crowd iou of over the threshold to be neutral. - conf[(conf <= 0) & (best_crowd_overlap > cfg.crowd_iou_threshold)] = -1 - - loc = encode(matches, priors, cfg.use_yolo_regressors) - loc_t[idx] = loc # [num_priors,4] encoded offsets to learn - conf_t[idx] = conf # [num_priors] top class label for each prior - idx_t[idx] = best_truth_idx # [num_priors] indices for lookup - -@torch.jit.script -def encode(matched, priors, use_yolo_regressors:bool=False): - """ - Encode bboxes matched with each prior into the format - produced by the network. See decode for more details on - this format. Note that encode(decode(x, p), p) = x. - - Args: - - matched: A tensor of bboxes in point form with shape [num_priors, 4] - - priors: The tensor of all priors with shape [num_priors, 4] - Return: A tensor with encoded relative coordinates in the format - outputted by the network (see decode). Size: [num_priors, 4] - """ - - if use_yolo_regressors: - # Exactly the reverse of what we did in decode - # In fact encode(decode(x, p), p) should be x - boxes = center_size(matched) - - loc = torch.cat(( - boxes[:, :2] - priors[:, :2], - torch.log(boxes[:, 2:] / priors[:, 2:]) - ), 1) - else: - variances = [0.1, 0.2] - - # dist b/t match center and prior's center - g_cxcy = (matched[:, :2] + matched[:, 2:])/2 - priors[:, :2] - # encode variance - g_cxcy /= (variances[0] * priors[:, 2:]) - # match wh / prior wh - g_wh = (matched[:, 2:] - matched[:, :2]) / priors[:, 2:] - g_wh = torch.log(g_wh) / variances[1] - # return target for smooth_l1_loss - loc = torch.cat([g_cxcy, g_wh], 1) # [num_priors,4] - - return loc - -@torch.jit.script -def decode(loc, priors, use_yolo_regressors:bool=False): - """ - Decode predicted bbox coordinates using the same scheme - employed by Yolov2: https://arxiv.org/pdf/1612.08242.pdf - - b_x = (sigmoid(pred_x) - .5) / conv_w + prior_x - b_y = (sigmoid(pred_y) - .5) / conv_h + prior_y - b_w = prior_w * exp(loc_w) - b_h = prior_h * exp(loc_h) - - Note that loc is inputed as [(s(x)-.5)/conv_w, (s(y)-.5)/conv_h, w, h] - while priors are inputed as [x, y, w, h] where each coordinate - is relative to size of the image (even sigmoid(x)). We do this - in the network by dividing by the 'cell size', which is just - the size of the convouts. - - Also note that prior_x and prior_y are center coordinates which - is why we have to subtract .5 from sigmoid(pred_x and pred_y). - - Args: - - loc: The predicted bounding boxes of size [num_priors, 4] - - priors: The priorbox coords with size [num_priors, 4] - - Returns: A tensor of decoded relative coordinates in point form - form with size [num_priors, 4] - """ - - if use_yolo_regressors: - # Decoded boxes in center-size notation - boxes = torch.cat(( - loc[:, :2] + priors[:, :2], - priors[:, 2:] * torch.exp(loc[:, 2:]) - ), 1) - - boxes = point_form(boxes) - else: - variances = [0.1, 0.2] - - boxes = torch.cat(( - priors[:, :2] + loc[:, :2] * variances[0] * priors[:, 2:], - priors[:, 2:] * torch.exp(loc[:, 2:] * variances[1])), 1) - boxes[:, :2] -= boxes[:, 2:] / 2 - boxes[:, 2:] += boxes[:, :2] - - return boxes - - - -def log_sum_exp(x): - """Utility function for computing log_sum_exp while determining - This will be used to determine unaveraged confidence loss across - all examples in a batch. - Args: - x (Variable(tensor)): conf_preds from conf layers - """ - x_max = x.data.max() - return torch.log(torch.sum(torch.exp(x-x_max), 1)) + x_max - - -@torch.jit.script -def sanitize_coordinates(_x1, _x2, img_size:int, padding:int=0, cast:bool=True): - """ - Sanitizes the input coordinates so that x1 < x2, x1 != x2, x1 >= 0, and x2 <= image_size. - Also converts from relative to absolute coordinates and casts the results to long tensors. - - If cast is false, the result won't be cast to longs. - Warning: this does things in-place behind the scenes so copy if necessary. - """ - _x1 = _x1 * img_size - _x2 = _x2 * img_size - if cast: - _x1 = _x1.long() - _x2 = _x2.long() - x1 = torch.min(_x1, _x2) - x2 = torch.max(_x1, _x2) - x1 = torch.clamp(x1-padding, min=0) - x2 = torch.clamp(x2+padding, max=img_size) - - return x1, x2 - - -@torch.jit.script -def crop(masks, boxes, padding:int=1): - """ - "Crop" predicted masks by zeroing out everything not in the predicted bbox. - Vectorized by Chong (thanks Chong). - - Args: - - masks should be a size [h, w, n] tensor of masks - - boxes should be a size [n, 4] tensor of bbox coords in relative point form - """ - h, w, n = masks.size() - x1, x2 = sanitize_coordinates(boxes[:, 0], boxes[:, 2], w, padding, cast=False) - y1, y2 = sanitize_coordinates(boxes[:, 1], boxes[:, 3], h, padding, cast=False) - - rows = torch.arange(w, device=masks.device, dtype=x1.dtype).view(1, -1, 1).expand(h, w, n) - cols = torch.arange(h, device=masks.device, dtype=x1.dtype).view(-1, 1, 1).expand(h, w, n) - - masks_left = rows >= x1.view(1, 1, -1) - masks_right = rows < x2.view(1, 1, -1) - masks_up = cols >= y1.view(1, 1, -1) - masks_down = cols < y2.view(1, 1, -1) - - crop_mask = masks_left * masks_right * masks_up * masks_down - - return masks * crop_mask.float() - - -def index2d(src, idx): - """ - Indexes a tensor by a 2d index. - - In effect, this does - out[i, j] = src[i, idx[i, j]] - - Both src and idx should have the same size. - """ - - offs = torch.arange(idx.size(0), device=idx.device)[:, None].expand_as(idx) - idx = idx + offs * idx.size(1) - - return src.view(-1)[idx.view(-1)].view(idx.size()) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +# -*- coding: utf-8 -*- +import torch +from utils import timer + +from data import cfg + +@torch.jit.script +def point_form(boxes): + """ Convert prior_boxes to (xmin, ymin, xmax, ymax) + representation for comparison to point form ground truth data. + Args: + boxes: (tensor) center-size default boxes from priorbox layers. + Return: + boxes: (tensor) Converted xmin, ymin, xmax, ymax form of boxes. + """ + return torch.cat((boxes[:, :2] - boxes[:, 2:]/2, # xmin, ymin + boxes[:, :2] + boxes[:, 2:]/2), 1) # xmax, ymax + + +@torch.jit.script +def center_size(boxes): + """ Convert prior_boxes to (cx, cy, w, h) + representation for comparison to center-size form ground truth data. + Args: + boxes: (tensor) point_form boxes + Return: + boxes: (tensor) Converted xmin, ymin, xmax, ymax form of boxes. + """ + return torch.cat(( (boxes[:, 2:] + boxes[:, :2])/2, # cx, cy + boxes[:, 2:] - boxes[:, :2] ), 1) # w, h + +@torch.jit.script +def intersect(box_a, box_b): + """ We resize both tensors to [A,B,2] without new malloc: + [A,2] -> [A,1,2] -> [A,B,2] + [B,2] -> [1,B,2] -> [A,B,2] + Then we compute the area of intersect between box_a and box_b. + Args: + box_a: (tensor) bounding boxes, Shape: [n,A,4]. + box_b: (tensor) bounding boxes, Shape: [n,B,4]. + Return: + (tensor) intersection area, Shape: [n,A,B]. + """ + n = box_a.size(0) + A = box_a.size(1) + B = box_b.size(1) + max_xy = torch.min(box_a[:, :, 2:].unsqueeze(2).expand(n, A, B, 2), + box_b[:, :, 2:].unsqueeze(1).expand(n, A, B, 2)) + min_xy = torch.max(box_a[:, :, :2].unsqueeze(2).expand(n, A, B, 2), + box_b[:, :, :2].unsqueeze(1).expand(n, A, B, 2)) + return torch.clamp(max_xy - min_xy, min=0).prod(3) # inter + + +def jaccard(box_a, box_b, iscrowd:bool=False): + """Compute the jaccard overlap of two sets of boxes. The jaccard overlap + is simply the intersection over union of two boxes. Here we operate on + ground truth boxes and default boxes. If iscrowd=True, put the crowd in box_b. + E.g.: + A ∩ B / A ∪ B = A ∩ B / (area(A) + area(B) - A ∩ B) + Args: + box_a: (tensor) Ground truth bounding boxes, Shape: [num_objects,4] + box_b: (tensor) Prior boxes from priorbox layers, Shape: [num_priors,4] + Return: + jaccard overlap: (tensor) Shape: [box_a.size(0), box_b.size(0)] + """ + use_batch = True + if box_a.dim() == 2: + use_batch = False + box_a = box_a[None, ...] + box_b = box_b[None, ...] + + inter = intersect(box_a, box_b) + area_a = ((box_a[:, :, 2]-box_a[:, :, 0]) * + (box_a[:, :, 3]-box_a[:, :, 1])).unsqueeze(2).expand_as(inter) # [A,B] + area_b = ((box_b[:, :, 2]-box_b[:, :, 0]) * + (box_b[:, :, 3]-box_b[:, :, 1])).unsqueeze(1).expand_as(inter) # [A,B] + union = area_a + area_b - inter + + out = inter / area_a if iscrowd else inter / union + return out if use_batch else out.squeeze(0) + +def elemwise_box_iou(box_a, box_b): + """ Does the same as above but instead of pairwise, elementwise along the inner dimension. """ + max_xy = torch.min(box_a[:, 2:], box_b[:, 2:]) + min_xy = torch.max(box_a[:, :2], box_b[:, :2]) + inter = torch.clamp((max_xy - min_xy), min=0) + inter = inter[:, 0] * inter[:, 1] + + area_a = (box_a[:, 2] - box_a[:, 0]) * (box_a[:, 3] - box_a[:, 1]) + area_b = (box_b[:, 2] - box_b[:, 0]) * (box_b[:, 3] - box_b[:, 1]) + + union = area_a + area_b - inter + union = torch.clamp(union, min=0.1) + + # Return value is [n] for inputs [n, 4] + return torch.clamp(inter / union, max=1) + +def mask_iou(masks_a, masks_b, iscrowd=False): + """ + Computes the pariwise mask IoU between two sets of masks of size [a, h, w] and [b, h, w]. + The output is of size [a, b]. + + Wait I thought this was "box_utils", why am I putting this in here? + """ + + masks_a = masks_a.view(masks_a.size(0), -1) + masks_b = masks_b.view(masks_b.size(0), -1) + + intersection = masks_a @ masks_b.t() + area_a = masks_a.sum(dim=1).unsqueeze(1) + area_b = masks_b.sum(dim=1).unsqueeze(0) + + return intersection / (area_a + area_b - intersection) if not iscrowd else intersection / area_a + +def elemwise_mask_iou(masks_a, masks_b): + """ Does the same as above but instead of pairwise, elementwise along the outer dimension. """ + masks_a = masks_a.view(-1, masks_a.size(-1)) + masks_b = masks_b.view(-1, masks_b.size(-1)) + + intersection = (masks_a * masks_b).sum(dim=0) + area_a = masks_a.sum(dim=0) + area_b = masks_b.sum(dim=0) + + # Return value is [n] for inputs [h, w, n] + return torch.clamp(intersection / torch.clamp(area_a + area_b - intersection, min=0.1), max=1) + + + +def change(gt, priors): + """ + Compute the d_change metric proposed in Box2Pix: + https://lmb.informatik.uni-freiburg.de/Publications/2018/UB18/paper-box2pix.pdf + + Input should be in point form (xmin, ymin, xmax, ymax). + + Output is of shape [num_gt, num_priors] + Note this returns -change so it can be a drop in replacement for + """ + num_priors = priors.size(0) + num_gt = gt.size(0) + + gt_w = (gt[:, 2] - gt[:, 0])[:, None].expand(num_gt, num_priors) + gt_h = (gt[:, 3] - gt[:, 1])[:, None].expand(num_gt, num_priors) + + gt_mat = gt[:, None, :].expand(num_gt, num_priors, 4) + pr_mat = priors[None, :, :].expand(num_gt, num_priors, 4) + + diff = gt_mat - pr_mat + diff[:, :, 0] /= gt_w + diff[:, :, 2] /= gt_w + diff[:, :, 1] /= gt_h + diff[:, :, 3] /= gt_h + + return -torch.sqrt( (diff ** 2).sum(dim=2) ) + + + + +def match(pos_thresh, neg_thresh, truths, priors, labels, crowd_boxes, loc_t, conf_t, idx_t, idx, loc_data): + """Match each prior box with the ground truth box of the highest jaccard + overlap, encode the bounding boxes, then return the matched indices + corresponding to both confidence and location preds. + Args: + pos_thresh: (float) IoU > pos_thresh ==> positive. + neg_thresh: (float) IoU < neg_thresh ==> negative. + truths: (tensor) Ground truth boxes, Shape: [num_obj, num_priors]. + priors: (tensor) Prior boxes from priorbox layers, Shape: [n_priors,4]. + labels: (tensor) All the class labels for the image, Shape: [num_obj]. + crowd_boxes: (tensor) All the crowd box annotations or None if there are none. + loc_t: (tensor) Tensor to be filled w/ endcoded location targets. + conf_t: (tensor) Tensor to be filled w/ matched indices for conf preds. Note: -1 means neutral. + idx_t: (tensor) Tensor to be filled w/ the index of the matched gt box for each prior. + idx: (int) current batch index. + loc_data: (tensor) The predicted bbox regression coordinates for this batch. + Return: + The matched indices corresponding to 1)location and 2)confidence preds. + """ + decoded_priors = decode(loc_data, priors, cfg.use_yolo_regressors) if cfg.use_prediction_matching else point_form(priors) + + # Size [num_objects, num_priors] + overlaps = jaccard(truths, decoded_priors) if not cfg.use_change_matching else change(truths, decoded_priors) + + # Size [num_priors] best ground truth for each prior + best_truth_overlap, best_truth_idx = overlaps.max(0) + + # We want to ensure that each gt gets used at least once so that we don't + # waste any training data. In order to do that, find the max overlap anchor + # with each gt, and force that anchor to use that gt. + for _ in range(overlaps.size(0)): + # Find j, the gt with the highest overlap with a prior + # In effect, this will loop through overlaps.size(0) in a "smart" order, + # always choosing the highest overlap first. + best_prior_overlap, best_prior_idx = overlaps.max(1) + j = best_prior_overlap.max(0)[1] + + # Find i, the highest overlap anchor with this gt + i = best_prior_idx[j] + + # Set all other overlaps with i to be -1 so that no other gt uses it + overlaps[:, i] = -1 + # Set all other overlaps with j to be -1 so that this loop never uses j again + overlaps[j, :] = -1 + + # Overwrite i's score to be 2 so it doesn't get thresholded ever + best_truth_overlap[i] = 2 + # Set the gt to be used for i to be j, overwriting whatever was there + best_truth_idx[i] = j + + matches = truths[best_truth_idx] # Shape: [num_priors,4] + conf = labels[best_truth_idx] + 1 # Shape: [num_priors] + + conf[best_truth_overlap < pos_thresh] = -1 # label as neutral + conf[best_truth_overlap < neg_thresh] = 0 # label as background + + # Deal with crowd annotations for COCO + if crowd_boxes is not None and cfg.crowd_iou_threshold < 1: + # Size [num_priors, num_crowds] + crowd_overlaps = jaccard(decoded_priors, crowd_boxes, iscrowd=True) + # Size [num_priors] + best_crowd_overlap, best_crowd_idx = crowd_overlaps.max(1) + # Set non-positives with crowd iou of over the threshold to be neutral. + conf[(conf <= 0) & (best_crowd_overlap > cfg.crowd_iou_threshold)] = -1 + + loc = encode(matches, priors, cfg.use_yolo_regressors) + loc_t[idx] = loc # [num_priors,4] encoded offsets to learn + conf_t[idx] = conf # [num_priors] top class label for each prior + idx_t[idx] = best_truth_idx # [num_priors] indices for lookup + +@torch.jit.script +def encode(matched, priors, use_yolo_regressors:bool=False): + """ + Encode bboxes matched with each prior into the format + produced by the network. See decode for more details on + this format. Note that encode(decode(x, p), p) = x. + + Args: + - matched: A tensor of bboxes in point form with shape [num_priors, 4] + - priors: The tensor of all priors with shape [num_priors, 4] + Return: A tensor with encoded relative coordinates in the format + outputted by the network (see decode). Size: [num_priors, 4] + """ + + if use_yolo_regressors: + # Exactly the reverse of what we did in decode + # In fact encode(decode(x, p), p) should be x + boxes = center_size(matched) + + loc = torch.cat(( + boxes[:, :2] - priors[:, :2], + torch.log(boxes[:, 2:] / priors[:, 2:]) + ), 1) + else: + variances = [0.1, 0.2] + + # dist b/t match center and prior's center + g_cxcy = (matched[:, :2] + matched[:, 2:])/2 - priors[:, :2] + # encode variance + g_cxcy /= (variances[0] * priors[:, 2:]) + # match wh / prior wh + g_wh = (matched[:, 2:] - matched[:, :2]) / priors[:, 2:] + g_wh = torch.log(g_wh) / variances[1] + # return target for smooth_l1_loss + loc = torch.cat([g_cxcy, g_wh], 1) # [num_priors,4] + + return loc + +@torch.jit.script +def decode(loc, priors, use_yolo_regressors:bool=False): + """ + Decode predicted bbox coordinates using the same scheme + employed by Yolov2: https://arxiv.org/pdf/1612.08242.pdf + + b_x = (sigmoid(pred_x) - .5) / conv_w + prior_x + b_y = (sigmoid(pred_y) - .5) / conv_h + prior_y + b_w = prior_w * exp(loc_w) + b_h = prior_h * exp(loc_h) + + Note that loc is inputed as [(s(x)-.5)/conv_w, (s(y)-.5)/conv_h, w, h] + while priors are inputed as [x, y, w, h] where each coordinate + is relative to size of the image (even sigmoid(x)). We do this + in the network by dividing by the 'cell size', which is just + the size of the convouts. + + Also note that prior_x and prior_y are center coordinates which + is why we have to subtract .5 from sigmoid(pred_x and pred_y). + + Args: + - loc: The predicted bounding boxes of size [num_priors, 4] + - priors: The priorbox coords with size [num_priors, 4] + + Returns: A tensor of decoded relative coordinates in point form + form with size [num_priors, 4] + """ + + if use_yolo_regressors: + # Decoded boxes in center-size notation + boxes = torch.cat(( + loc[:, :2] + priors[:, :2], + priors[:, 2:] * torch.exp(loc[:, 2:]) + ), 1) + + boxes = point_form(boxes) + else: + variances = [0.1, 0.2] + + boxes = torch.cat(( + priors[:, :2] + loc[:, :2] * variances[0] * priors[:, 2:], + priors[:, 2:] * torch.exp(loc[:, 2:] * variances[1])), 1) + boxes[:, :2] -= boxes[:, 2:] / 2 + boxes[:, 2:] += boxes[:, :2] + + return boxes + + + +def log_sum_exp(x): + """Utility function for computing log_sum_exp while determining + This will be used to determine unaveraged confidence loss across + all examples in a batch. + Args: + x (Variable(tensor)): conf_preds from conf layers + """ + x_max = x.data.max() + return torch.log(torch.sum(torch.exp(x-x_max), 1)) + x_max + + +@torch.jit.script +def sanitize_coordinates(_x1, _x2, img_size:int, padding:int=0, cast:bool=True): + """ + Sanitizes the input coordinates so that x1 < x2, x1 != x2, x1 >= 0, and x2 <= image_size. + Also converts from relative to absolute coordinates and casts the results to long tensors. + + If cast is false, the result won't be cast to longs. + Warning: this does things in-place behind the scenes so copy if necessary. + """ + _x1 = _x1 * img_size + _x2 = _x2 * img_size + if cast: + _x1 = _x1.long() + _x2 = _x2.long() + x1 = torch.min(_x1, _x2) + x2 = torch.max(_x1, _x2) + x1 = torch.clamp(x1-padding, min=0) + x2 = torch.clamp(x2+padding, max=img_size) + + return x1, x2 + + +@torch.jit.script +def crop(masks, boxes, padding:int=1): + """ + "Crop" predicted masks by zeroing out everything not in the predicted bbox. + Vectorized by Chong (thanks Chong). + + Args: + - masks should be a size [h, w, n] tensor of masks + - boxes should be a size [n, 4] tensor of bbox coords in relative point form + """ + h, w, n = masks.size() + x1, x2 = sanitize_coordinates(boxes[:, 0], boxes[:, 2], w, padding, cast=False) + y1, y2 = sanitize_coordinates(boxes[:, 1], boxes[:, 3], h, padding, cast=False) + + rows = torch.arange(w, device=masks.device, dtype=x1.dtype).view(1, -1, 1).expand(h, w, n) + cols = torch.arange(h, device=masks.device, dtype=x1.dtype).view(-1, 1, 1).expand(h, w, n) + + masks_left = rows >= x1.view(1, 1, -1) + masks_right = rows < x2.view(1, 1, -1) + masks_up = cols >= y1.view(1, 1, -1) + masks_down = cols < y2.view(1, 1, -1) + + crop_mask = masks_left * masks_right * masks_up * masks_down + + return masks * crop_mask.float() + + +def index2d(src, idx): + """ + Indexes a tensor by a 2d index. + + In effect, this does + out[i, j] = src[i, idx[i, j]] + + Both src and idx should have the same size. + """ + + offs = torch.arange(idx.size(0), device=idx.device)[:, None].expand_as(idx) + idx = idx + offs * idx.size(1) + + return src.view(-1)[idx.view(-1)].view(idx.size()) diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/layers/functions/__init__.py b/PyTorch/contrib/cv/detection/YOLACT_plus/layers/functions/__init__.py index d370fa2fea..56ef07f464 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/layers/functions/__init__.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/layers/functions/__init__.py @@ -1,4 +1,4 @@ -from .detection import Detect - - -__all__ = ['Detect'] +from .detection import Detect + + +__all__ = ['Detect'] diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/layers/functions/detection.py b/PyTorch/contrib/cv/detection/YOLACT_plus/layers/functions/detection.py index c1fbea9366..277684228e 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/layers/functions/detection.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/layers/functions/detection.py @@ -1,242 +1,242 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import torch.nn.functional as F -from ..box_utils import decode, jaccard, index2d -from utils import timer - -from data import cfg, mask_type - -import numpy as np - - -class Detect(object): - """At test time, Detect is the final layer of SSD. Decode location preds, - apply non-maximum suppression to location predictions based on conf - scores and threshold to a top_k number of output predictions for both - confidence score and locations, as the predicted masks. - """ - # TODO: Refactor this whole class away. It needs to go. - - def __init__(self, num_classes, bkg_label, top_k, conf_thresh, nms_thresh): - self.num_classes = num_classes - self.background_label = bkg_label - self.top_k = top_k - # Parameters used in nms. - self.nms_thresh = nms_thresh - if nms_thresh <= 0: - raise ValueError('nms_threshold must be non negative.') - self.conf_thresh = conf_thresh - - self.use_cross_class_nms = False - self.use_fast_nms = False - - def __call__(self, predictions): - """ - Args: - loc_data: (tensor) Loc preds from loc layers - Shape: [batch, num_priors, 4] - conf_data: (tensor) Shape: Conf preds from conf layers - Shape: [batch, num_priors, num_classes] - mask_data: (tensor) Mask preds from mask layers - Shape: [batch, num_priors, mask_dim] - prior_data: (tensor) Prior boxes and variances from priorbox layers - Shape: [num_priors, 4] - proto_data: (tensor) If using mask_type.lincomb, the prototype masks - Shape: [batch, mask_h, mask_w, mask_dim] - - Returns: - output of shape (batch_size, top_k, 1 + 1 + 4 + mask_dim) - These outputs are in the order: class idx, confidence, bbox coords, and mask. - - Note that the outputs are sorted only if cross_class_nms is False - """ - - loc_data = predictions['loc'] - conf_data = predictions['conf'] - mask_data = predictions['mask'] - prior_data = predictions['priors'] - - proto_data = predictions['proto'] if 'proto' in predictions else None - inst_data = predictions['inst'] if 'inst' in predictions else None - - out = [] - - with timer.env('Detect'): - batch_size = loc_data.size(0) - num_priors = prior_data.size(0) - - conf_preds = conf_data.view(batch_size, num_priors, self.num_classes).transpose(2, 1).contiguous() - - for batch_idx in range(batch_size): - decoded_boxes = decode(loc_data[batch_idx], prior_data) - result = self.detect(batch_idx, conf_preds, decoded_boxes, mask_data, inst_data) - - if result is not None and proto_data is not None: - result['proto'] = proto_data[batch_idx] - - out.append(result) - - return out - - - def detect(self, batch_idx, conf_preds, decoded_boxes, mask_data, inst_data): - """ Perform nms for only the max scoring class that isn't background (class 0) """ - cur_scores = conf_preds[batch_idx, 1:, :] - conf_scores, _ = torch.max(cur_scores, dim=0) - - keep = (conf_scores > self.conf_thresh) - scores = cur_scores[:, keep] - boxes = decoded_boxes[keep, :] - masks = mask_data[batch_idx, keep, :] - - if inst_data is not None: - inst = inst_data[batch_idx, keep, :] - - if scores.size(1) == 0: - return None - - if self.use_fast_nms: - if self.use_cross_class_nms: - boxes, masks, classes, scores = self.cc_fast_nms(boxes, masks, scores, self.nms_thresh, self.top_k) - else: - boxes, masks, classes, scores = self.fast_nms(boxes, masks, scores, self.nms_thresh, self.top_k) - else: - boxes, masks, classes, scores = self.traditional_nms(boxes, masks, scores, self.nms_thresh, self.conf_thresh) - - if self.use_cross_class_nms: - print('Warning: Cross Class Traditional NMS is not implemented.') - - return {'box': boxes, 'mask': masks, 'class': classes, 'score': scores} - - - def cc_fast_nms(self, boxes, masks, scores, iou_threshold:float=0.5, top_k:int=200): - # Collapse all the classes into 1 - scores, classes = scores.max(dim=0) - - _, idx = scores.sort(0, descending=True) - idx = idx[:top_k] - - boxes_idx = boxes[idx] - - # Compute the pairwise IoU between the boxes - iou = jaccard(boxes_idx, boxes_idx) - - # Zero out the lower triangle of the cosine similarity matrix and diagonal - iou.triu_(diagonal=1) - - # Now that everything in the diagonal and below is zeroed out, if we take the max - # of the IoU matrix along the columns, each column will represent the maximum IoU - # between this element and every element with a higher score than this element. - iou_max, _ = torch.max(iou, dim=0) - - # Now just filter out the ones greater than the threshold, i.e., only keep boxes that - # don't have a higher scoring box that would supress it in normal NMS. - idx_out = idx[iou_max <= iou_threshold] - - return boxes[idx_out], masks[idx_out], classes[idx_out], scores[idx_out] - - def fast_nms(self, boxes, masks, scores, iou_threshold:float=0.5, top_k:int=200, second_threshold:bool=False): - scores, idx = scores.sort(1, descending=True) - - idx = idx[:, :top_k].contiguous() - scores = scores[:, :top_k] - - num_classes, num_dets = idx.size() - - boxes = boxes[idx.view(-1), :].view(num_classes, num_dets, 4) - masks = masks[idx.view(-1), :].view(num_classes, num_dets, -1) - - iou = jaccard(boxes, boxes) - iou.triu_(diagonal=1) - iou_max, _ = iou.max(dim=1) - - # Now just filter out the ones higher than the threshold - keep = (iou_max <= iou_threshold) - - # We should also only keep detections over the confidence threshold, but at the cost of - # maxing out your detection count for every image, you can just not do that. Because we - # have such a minimal amount of computation per detection (matrix mulitplication only), - # this increase doesn't affect us much (+0.2 mAP for 34 -> 33 fps), so we leave it out. - # However, when you implement this in your method, you should do this second threshold. - if second_threshold: - keep *= (scores > self.conf_thresh) - - # Assign each kept detection to its corresponding class - classes = torch.arange(num_classes, device=boxes.device)[:, None].expand_as(keep) - classes = classes[keep] - - boxes = boxes[keep] - masks = masks[keep] - scores = scores[keep] - - # Only keep the top cfg.max_num_detections highest scores across all classes - scores, idx = scores.sort(0, descending=True) - idx = idx[:cfg.max_num_detections] - scores = scores[:cfg.max_num_detections] - - classes = classes[idx] - boxes = boxes[idx] - masks = masks[idx] - - return boxes, masks, classes, scores - - def traditional_nms(self, boxes, masks, scores, iou_threshold=0.5, conf_thresh=0.05): - import pyximport - pyximport.install(setup_args={"include_dirs":np.get_include()}, reload_support=True) - - from utils.cython_nms import nms as cnms - - num_classes = scores.size(0) - - idx_lst = [] - cls_lst = [] - scr_lst = [] - - # Multiplying by max_size is necessary because of how cnms computes its area and intersections - boxes = boxes * cfg.max_size - - for _cls in range(num_classes): - cls_scores = scores[_cls, :] - conf_mask = cls_scores > conf_thresh - idx = torch.arange(cls_scores.size(0), device=boxes.device) - - cls_scores = cls_scores[conf_mask] - idx = idx[conf_mask] - - if cls_scores.size(0) == 0: - continue - - preds = torch.cat([boxes[conf_mask], cls_scores[:, None]], dim=1).detach().numpy() - keep = cnms(preds, iou_threshold) - keep = torch.Tensor(keep, device=boxes.device).long() - - idx_lst.append(idx[keep]) - cls_lst.append(keep * 0 + _cls) - scr_lst.append(cls_scores[keep]) - - idx = torch.cat(idx_lst, dim=0) - classes = torch.cat(cls_lst, dim=0) - scores = torch.cat(scr_lst, dim=0) - - scores, idx2 = scores.sort(0, descending=True) - idx2 = idx2[:cfg.max_num_detections] - scores = scores[:cfg.max_num_detections] - - idx = idx[idx2] - classes = classes[idx2] - - # Undo the multiplication above - return boxes[idx] / cfg.max_size, masks[idx], classes, scores +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import torch.nn.functional as F +from ..box_utils import decode, jaccard, index2d +from utils import timer + +from data import cfg, mask_type + +import numpy as np + + +class Detect(object): + """At test time, Detect is the final layer of SSD. Decode location preds, + apply non-maximum suppression to location predictions based on conf + scores and threshold to a top_k number of output predictions for both + confidence score and locations, as the predicted masks. + """ + # TODO: Refactor this whole class away. It needs to go. + + def __init__(self, num_classes, bkg_label, top_k, conf_thresh, nms_thresh): + self.num_classes = num_classes + self.background_label = bkg_label + self.top_k = top_k + # Parameters used in nms. + self.nms_thresh = nms_thresh + if nms_thresh <= 0: + raise ValueError('nms_threshold must be non negative.') + self.conf_thresh = conf_thresh + + self.use_cross_class_nms = False + self.use_fast_nms = False + + def __call__(self, predictions): + """ + Args: + loc_data: (tensor) Loc preds from loc layers + Shape: [batch, num_priors, 4] + conf_data: (tensor) Shape: Conf preds from conf layers + Shape: [batch, num_priors, num_classes] + mask_data: (tensor) Mask preds from mask layers + Shape: [batch, num_priors, mask_dim] + prior_data: (tensor) Prior boxes and variances from priorbox layers + Shape: [num_priors, 4] + proto_data: (tensor) If using mask_type.lincomb, the prototype masks + Shape: [batch, mask_h, mask_w, mask_dim] + + Returns: + output of shape (batch_size, top_k, 1 + 1 + 4 + mask_dim) + These outputs are in the order: class idx, confidence, bbox coords, and mask. + + Note that the outputs are sorted only if cross_class_nms is False + """ + + loc_data = predictions['loc'] + conf_data = predictions['conf'] + mask_data = predictions['mask'] + prior_data = predictions['priors'] + + proto_data = predictions['proto'] if 'proto' in predictions else None + inst_data = predictions['inst'] if 'inst' in predictions else None + + out = [] + + with timer.env('Detect'): + batch_size = loc_data.size(0) + num_priors = prior_data.size(0) + + conf_preds = conf_data.view(batch_size, num_priors, self.num_classes).transpose(2, 1).contiguous() + + for batch_idx in range(batch_size): + decoded_boxes = decode(loc_data[batch_idx], prior_data) + result = self.detect(batch_idx, conf_preds, decoded_boxes, mask_data, inst_data) + + if result is not None and proto_data is not None: + result['proto'] = proto_data[batch_idx] + + out.append(result) + + return out + + + def detect(self, batch_idx, conf_preds, decoded_boxes, mask_data, inst_data): + """ Perform nms for only the max scoring class that isn't background (class 0) """ + cur_scores = conf_preds[batch_idx, 1:, :] + conf_scores, _ = torch.max(cur_scores, dim=0) + + keep = (conf_scores > self.conf_thresh) + scores = cur_scores[:, keep] + boxes = decoded_boxes[keep, :] + masks = mask_data[batch_idx, keep, :] + + if inst_data is not None: + inst = inst_data[batch_idx, keep, :] + + if scores.size(1) == 0: + return None + + if self.use_fast_nms: + if self.use_cross_class_nms: + boxes, masks, classes, scores = self.cc_fast_nms(boxes, masks, scores, self.nms_thresh, self.top_k) + else: + boxes, masks, classes, scores = self.fast_nms(boxes, masks, scores, self.nms_thresh, self.top_k) + else: + boxes, masks, classes, scores = self.traditional_nms(boxes, masks, scores, self.nms_thresh, self.conf_thresh) + + if self.use_cross_class_nms: + print('Warning: Cross Class Traditional NMS is not implemented.') + + return {'box': boxes, 'mask': masks, 'class': classes, 'score': scores} + + + def cc_fast_nms(self, boxes, masks, scores, iou_threshold:float=0.5, top_k:int=200): + # Collapse all the classes into 1 + scores, classes = scores.max(dim=0) + + _, idx = scores.sort(0, descending=True) + idx = idx[:top_k] + + boxes_idx = boxes[idx] + + # Compute the pairwise IoU between the boxes + iou = jaccard(boxes_idx, boxes_idx) + + # Zero out the lower triangle of the cosine similarity matrix and diagonal + iou.triu_(diagonal=1) + + # Now that everything in the diagonal and below is zeroed out, if we take the max + # of the IoU matrix along the columns, each column will represent the maximum IoU + # between this element and every element with a higher score than this element. + iou_max, _ = torch.max(iou, dim=0) + + # Now just filter out the ones greater than the threshold, i.e., only keep boxes that + # don't have a higher scoring box that would supress it in normal NMS. + idx_out = idx[iou_max <= iou_threshold] + + return boxes[idx_out], masks[idx_out], classes[idx_out], scores[idx_out] + + def fast_nms(self, boxes, masks, scores, iou_threshold:float=0.5, top_k:int=200, second_threshold:bool=False): + scores, idx = scores.sort(1, descending=True) + + idx = idx[:, :top_k].contiguous() + scores = scores[:, :top_k] + + num_classes, num_dets = idx.size() + + boxes = boxes[idx.view(-1), :].view(num_classes, num_dets, 4) + masks = masks[idx.view(-1), :].view(num_classes, num_dets, -1) + + iou = jaccard(boxes, boxes) + iou.triu_(diagonal=1) + iou_max, _ = iou.max(dim=1) + + # Now just filter out the ones higher than the threshold + keep = (iou_max <= iou_threshold) + + # We should also only keep detections over the confidence threshold, but at the cost of + # maxing out your detection count for every image, you can just not do that. Because we + # have such a minimal amount of computation per detection (matrix mulitplication only), + # this increase doesn't affect us much (+0.2 mAP for 34 -> 33 fps), so we leave it out. + # However, when you implement this in your method, you should do this second threshold. + if second_threshold: + keep *= (scores > self.conf_thresh) + + # Assign each kept detection to its corresponding class + classes = torch.arange(num_classes, device=boxes.device)[:, None].expand_as(keep) + classes = classes[keep] + + boxes = boxes[keep] + masks = masks[keep] + scores = scores[keep] + + # Only keep the top cfg.max_num_detections highest scores across all classes + scores, idx = scores.sort(0, descending=True) + idx = idx[:cfg.max_num_detections] + scores = scores[:cfg.max_num_detections] + + classes = classes[idx] + boxes = boxes[idx] + masks = masks[idx] + + return boxes, masks, classes, scores + + def traditional_nms(self, boxes, masks, scores, iou_threshold=0.5, conf_thresh=0.05): + import pyximport + pyximport.install(setup_args={"include_dirs":np.get_include()}, reload_support=True) + + from utils.cython_nms import nms as cnms + + num_classes = scores.size(0) + + idx_lst = [] + cls_lst = [] + scr_lst = [] + + # Multiplying by max_size is necessary because of how cnms computes its area and intersections + boxes = boxes * cfg.max_size + + for _cls in range(num_classes): + cls_scores = scores[_cls, :] + conf_mask = cls_scores > conf_thresh + idx = torch.arange(cls_scores.size(0), device=boxes.device) + + cls_scores = cls_scores[conf_mask] + idx = idx[conf_mask] + + if cls_scores.size(0) == 0: + continue + + preds = torch.cat([boxes[conf_mask], cls_scores[:, None]], dim=1).detach().numpy() + keep = cnms(preds, iou_threshold) + keep = torch.Tensor(keep, device=boxes.device).long() + + idx_lst.append(idx[keep]) + cls_lst.append(keep * 0 + _cls) + scr_lst.append(cls_scores[keep]) + + idx = torch.cat(idx_lst, dim=0) + classes = torch.cat(cls_lst, dim=0) + scores = torch.cat(scr_lst, dim=0) + + scores, idx2 = scores.sort(0, descending=True) + idx2 = idx2[:cfg.max_num_detections] + scores = scores[:cfg.max_num_detections] + + idx = idx[idx2] + classes = classes[idx2] + + # Undo the multiplication above + return boxes[idx] / cfg.max_size, masks[idx], classes, scores diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/layers/interpolate.py b/PyTorch/contrib/cv/detection/YOLACT_plus/layers/interpolate.py index 4ee3f067bc..19cacf8d15 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/layers/interpolate.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/layers/interpolate.py @@ -1,31 +1,31 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch.nn as nn -import torch.nn.functional as F - -class InterpolateModule(nn.Module): - """ - This is a module version of F.interpolate (rip nn.Upsampling). - Any arguments you give it just get passed along for the ride. - """ - - def __init__(self, *args, **kwdargs): - super().__init__() - - self.args = args - self.kwdargs = kwdargs - - def forward(self, x): - return F.interpolate(x, *self.args, **self.kwdargs) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch.nn as nn +import torch.nn.functional as F + +class InterpolateModule(nn.Module): + """ + This is a module version of F.interpolate (rip nn.Upsampling). + Any arguments you give it just get passed along for the ride. + """ + + def __init__(self, *args, **kwdargs): + super().__init__() + + self.args = args + self.kwdargs = kwdargs + + def forward(self, x): + return F.interpolate(x, *self.args, **self.kwdargs) diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/layers/modules/__init__.py b/PyTorch/contrib/cv/detection/YOLACT_plus/layers/modules/__init__.py index 028f5306fb..cf24bddbf2 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/layers/modules/__init__.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/layers/modules/__init__.py @@ -1,3 +1,3 @@ -from .multibox_loss import MultiBoxLoss - -__all__ = ['MultiBoxLoss'] +from .multibox_loss import MultiBoxLoss + +__all__ = ['MultiBoxLoss'] diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/layers/modules/multibox_loss.py b/PyTorch/contrib/cv/detection/YOLACT_plus/layers/modules/multibox_loss.py index 3abe7e0b07..12a98e8242 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/layers/modules/multibox_loss.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/layers/modules/multibox_loss.py @@ -1,721 +1,721 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ -# -*- coding: utf-8 -*- -import torch -import torch.nn as nn -import torch.nn.functional as F -from torch.autograd import Variable -from ..box_utils import match, log_sum_exp, decode, center_size, crop, elemwise_mask_iou, elemwise_box_iou - -from data import cfg, mask_type, activation_func - - -class MultiBoxLoss(nn.Module): - """SSD Weighted Loss Function - Compute Targets: - 1) Produce Confidence Target Indices by matching ground truth boxes - with (default) 'priorboxes' that have jaccard index > threshold parameter - (default threshold: 0.5). - - 2) Produce localization target by 'encoding' variance into offsets of ground - truth boxes and their matched 'priorboxes'. - - 3) Hard negative mining to filter the excessive number of negative examples - that comes with using a large number of default bounding boxes. - (default negative:positive ratio 3:1) - - Objective Loss: - L(x,c,l,g) = (Lconf(x, c) + αLloc(x,l,g)) / N - Where, Lconf is the CrossEntropy Loss and Lloc is the SmoothL1 Loss - weighted by α which is set to 1 by cross val. - Args: - c: class confidences, - l: predicted boxes, - g: ground truth boxes - N: number of matched default boxes - See: https://arxiv.org/pdf/1512.02325.pdf for more details. - """ - - def __init__(self, num_classes, pos_threshold, neg_threshold, negpos_ratio): - super(MultiBoxLoss, self).__init__() - self.num_classes = num_classes - - self.pos_threshold = pos_threshold - self.neg_threshold = neg_threshold - self.negpos_ratio = negpos_ratio - - # If you output a proto mask with this area, your l1 loss will be l1_alpha - # Note that the area is relative (so 1 would be the entire image) - self.l1_expected_area = 20 * 20 / 70 / 70 - self.l1_alpha = 0.1 - - if cfg.use_class_balanced_conf: - self.class_instances = None - self.total_instances = 0 - - def forward(self, net, predictions, wrapper, wrapper_mask): - """Multibox Loss - Args: - predictions (tuple): A tuple containing loc preds, conf preds, - mask preds, and prior boxes from SSD net. - loc shape: torch.size(batch_size,num_priors,4) - conf shape: torch.size(batch_size,num_priors,num_classes) - masks shape: torch.size(batch_size,num_priors,mask_dim) - priors shape: torch.size(num_priors,4) - proto* shape: torch.size(batch_size,mask_h,mask_w,mask_dim) - - targets (list): Ground truth boxes and labels for a batch, - shape: [batch_size][num_objs,5] (last idx is the label). - - masks (list): Ground truth masks for each object in each image, - shape: [batch_size][num_objs,im_height,im_width] - - num_crowds (list): Number of crowd annotations per batch. The crowd - annotations should be the last num_crowds elements of targets and masks. - - * Only if mask_type == lincomb - """ - - targets, masks, num_crowds = wrapper.get_args(wrapper_mask) - targets = targets[0] - masks = masks[0] - num_crowds = num_crowds[0] - loc_data = predictions['loc'] - conf_data = predictions['conf'] - mask_data = predictions['mask'] - priors = predictions['priors'] - - if cfg.mask_type == mask_type.lincomb: - proto_data = predictions['proto'] - - score_data = predictions['score'] if cfg.use_mask_scoring else None - inst_data = predictions['inst'] if cfg.use_instance_coeff else None - - labels = [None] * len(targets) # Used in sem segm loss - - batch_size = loc_data.size(0) - num_priors = priors.size(0) - num_classes = self.num_classes - - # Match priors (default boxes) and ground truth boxes - # These tensors will be created with the same device as loc_data - loc_t = loc_data.new(batch_size, num_priors, 4) - gt_box_t = loc_data.new(batch_size, num_priors, 4) - conf_t = loc_data.new(batch_size, num_priors).long() - idx_t = loc_data.new(batch_size, num_priors).long() - - if cfg.use_class_existence_loss: - class_existence_t = loc_data.new(batch_size, num_classes - 1) - - for idx in range(batch_size): - truths = targets[idx][:, :-1].data - labels[idx] = targets[idx][:, -1].data.long() - - if cfg.use_class_existence_loss: - # Construct a one-hot vector for each object and collapse it into an existence vector with max - # Also it's fine to include the crowd annotations here - class_existence_t[idx, :] = \ - torch.eye(num_classes - 1, device=conf_t.get_device())[labels[idx]].max(dim=0)[0] - - # Split the crowd annotations because they come bundled in - cur_crowds = num_crowds[idx] - if cur_crowds > 0: - split = lambda x: (x[-cur_crowds:], x[:-cur_crowds]) - crowd_boxes, truths = split(truths) - - # We don't use the crowd labels or masks - _, labels[idx] = split(labels[idx]) - _, masks[idx] = split(masks[idx]) - else: - crowd_boxes = None - - match(self.pos_threshold, self.neg_threshold, - truths, priors.data, labels[idx], crowd_boxes, - loc_t, conf_t, idx_t, idx, loc_data[idx]) - - gt_box_t[idx, :, :] = truths[idx_t[idx]] - - # wrap targets - loc_t = Variable(loc_t, requires_grad=False) - conf_t = Variable(conf_t, requires_grad=False) - idx_t = Variable(idx_t, requires_grad=False) - - pos = conf_t > 0 - num_pos = pos.sum(dim=1, keepdim=True) - - # Shape: [batch,num_priors,4] - pos_idx = pos.unsqueeze(pos.dim()).expand_as(loc_data) - - losses = {} - - # Localization Loss (Smooth L1) - if cfg.train_boxes: - # loc_p = loc_data[pos_idx].view(-1, 4) - # loc_t = loc_t[pos_idx].view(-1, 4) - # losses['B'] = F.smooth_l1_loss(loc_p, loc_t, reduction='sum') * cfg.bbox_alpha - loc_p = loc_data.view(-1, 4) - loc_t = loc_t.view(-1, 4) - losses['B'] = F.smooth_l1_loss(loc_p, loc_t, reduction='none') * cfg.bbox_alpha - losses['B'][pos_idx.view(-1, 4) == False] = 0 - losses['B'] = losses['B'].sum() - - if cfg.train_masks: - if cfg.mask_type == mask_type.direct: - if cfg.use_gt_bboxes: - pos_masks = [] - for idx in range(batch_size): - pos_masks.append(masks[idx][idx_t[idx, pos[idx]]]) - masks_t = torch.cat(pos_masks, 0) - masks_p = mask_data[pos, :].view(-1, cfg.mask_dim) - losses['M'] = F.binary_cross_entropy(torch.clamp(masks_p, 0, 1), masks_t, - reduction='sum') * cfg.mask_alpha - else: - losses['M'] = self.direct_mask_loss(pos_idx, idx_t, loc_data, mask_data, priors, masks) - elif cfg.mask_type == mask_type.lincomb: - ret = self.lincomb_mask_loss(pos, idx_t, loc_data, mask_data, priors, proto_data, masks, gt_box_t, - score_data, inst_data, labels) - if cfg.use_maskiou: - loss, maskiou_targets = ret - else: - loss = ret - losses.update(loss) - - if cfg.mask_proto_loss is not None: - if cfg.mask_proto_loss == 'l1': - losses['P'] = torch.mean(torch.abs(proto_data)) / self.l1_expected_area * self.l1_alpha - elif cfg.mask_proto_loss == 'disj': - losses['P'] = -torch.mean(torch.max(F.log_softmax(proto_data, dim=-1), dim=-1)[0]) - - # Confidence loss - if cfg.use_focal_loss: - if cfg.use_sigmoid_focal_loss: - losses['C'] = self.focal_conf_sigmoid_loss(conf_data, conf_t) - elif cfg.use_objectness_score: - losses['C'] = self.focal_conf_objectness_loss(conf_data, conf_t) - else: - losses['C'] = self.focal_conf_loss(conf_data, conf_t) - else: - if cfg.use_objectness_score: - losses['C'] = self.conf_objectness_loss(conf_data, conf_t, batch_size, loc_p, loc_t, priors) - else: - losses['C'] = self.ohem_conf_loss(conf_data, conf_t, pos, batch_size) - - # Mask IoU Loss - if cfg.use_maskiou and maskiou_targets is not None: - losses['I'] = self.mask_iou_loss(net, maskiou_targets) - - # These losses also don't depend on anchors - if cfg.use_class_existence_loss: - losses['E'] = self.class_existence_loss(predictions['classes'], class_existence_t) - if cfg.use_semantic_segmentation_loss: - losses['S'] = self.semantic_segmentation_loss(predictions['segm'], masks, labels) - - # Divide all losses by the number of positives. - # Don't do it for loss[P] because that doesn't depend on the anchors. - total_num_pos = num_pos.data.sum().float() - for k in losses: - if k not in ('P', 'E', 'S'): - losses[k] /= total_num_pos - else: - losses[k] /= batch_size - - # Loss Key: - # - B: Box Localization Loss - # - C: Class Confidence Loss - # - M: Mask Loss - # - P: Prototype Loss - # - D: Coefficient Diversity Loss - # - E: Class Existence Loss - # - S: Semantic Segmentation Loss - return losses - - def class_existence_loss(self, class_data, class_existence_t): - return cfg.class_existence_alpha * F.binary_cross_entropy_with_logits(class_data, class_existence_t, - reduction='sum') - - def semantic_segmentation_loss(self, segment_data, mask_t, class_t, interpolation_mode='bilinear'): - # Note num_classes here is without the background class so cfg.num_classes-1 - batch_size, num_classes, mask_h, mask_w = segment_data.size() - loss_s = 0 - - for idx in range(batch_size): - cur_segment = segment_data[idx] - cur_class_t = class_t[idx] - - with torch.no_grad(): - downsampled_masks = F.interpolate(mask_t[idx].unsqueeze(0), (mask_h, mask_w), - mode=interpolation_mode, align_corners=False).squeeze(0) - downsampled_masks = downsampled_masks.gt(0.5).float() - - # Construct Semantic Segmentation - segment_t = torch.zeros_like(cur_segment, requires_grad=False) - for obj_idx in range(downsampled_masks.size(0)): - segment_t[cur_class_t[obj_idx]] = torch.max(segment_t[cur_class_t[obj_idx]].float(), - downsampled_masks[obj_idx]) - - loss_s += F.binary_cross_entropy_with_logits(cur_segment, segment_t, reduction='sum') - - return loss_s / mask_h / mask_w * cfg.semantic_segmentation_alpha - - def ohem_conf_loss(self, conf_data, conf_t, pos, num): - # Compute max conf across batch for hard negative mining - batch_conf = conf_data.view(-1, self.num_classes) - if cfg.ohem_use_most_confident: - # i.e. max(softmax) along classes > 0 - batch_conf = F.softmax(batch_conf, dim=1) - loss_c, _ = batch_conf[:, 1:].max(dim=1) - else: - # i.e. -softmax(class 0 confidence) - loss_c = log_sum_exp(batch_conf) - batch_conf[:, 0] - - # Hard Negative Mining - loss_c = loss_c.view(num, -1) - loss_c[pos] = 0 # filter out pos boxes - loss_c[conf_t < 0] = 0 # filter out neutrals (conf_t = -1) - _, loss_idx = loss_c.sort(1, descending=True) - _, idx_rank = loss_idx.sort(1) - num_pos = pos.long().sum(1, keepdim=True) - num_neg = torch.clamp(self.negpos_ratio * num_pos, max=pos.size(1) - 1) - neg = idx_rank < num_neg.expand_as(idx_rank) - - # Just in case there aren't enough negatives, don't start using positives as negatives - neg[pos] = 0 - neg[conf_t < 0] = 0 # Filter out neutrals - - # Confidence Loss Including Positive and Negative Examples - # pos_idx = pos.unsqueeze(2).expand_as(conf_data) - # neg_idx = neg.unsqueeze(2).expand_as(conf_data) - - # conf_p = conf_data[(pos_idx+neg_idx).gt(0)].view(-1, self.num_classes) - # targets_weighted = conf_t[(pos+neg).gt(0)] - ## loss_c = F.cross_entropy(conf_p, targets_weighted, reduction='none') - loss_c = F.cross_entropy(conf_data.view(-1, self.num_classes), conf_t.view(-1), reduction='none').view(-1, - 57744) - loss_c[(pos + neg).gt(0) == False] = 0 - - if cfg.use_class_balanced_conf: - # Lazy initialization - if self.class_instances is None: - self.class_instances = torch.zeros(self.num_classes, device=targets_weighted.device) - - classes, counts = targets_weighted.unique(return_counts=True) - - for _cls, _cnt in zip(classes.cpu().numpy(), counts.cpu().numpy()): - self.class_instances[_cls] += _cnt - - self.total_instances += targets_weighted.size(0) - - weighting = 1 - (self.class_instances[targets_weighted] / self.total_instances) - weighting = torch.clamp(weighting, min=1 / self.num_classes) - - # If you do the math, the average weight of self.class_instances is this - avg_weight = (self.num_classes - 1) / self.num_classes - - loss_c = (loss_c * weighting).sum() / avg_weight - else: - loss_c = loss_c.sum() - - return cfg.conf_alpha * loss_c - - def focal_conf_loss(self, conf_data, conf_t): - """ - Focal loss as described in https://arxiv.org/pdf/1708.02002.pdf - Adapted from https://github.com/clcarwin/focal_loss_pytorch/blob/master/focalloss.py - Note that this uses softmax and not the original sigmoid from the paper. - """ - conf_t = conf_t.view(-1) # [batch_size*num_priors] - conf_data = conf_data.view(-1, conf_data.size(-1)) # [batch_size*num_priors, num_classes] - - # Ignore neutral samples (class < 0) - keep = (conf_t >= 0).float() - conf_t[conf_t < 0] = 0 # so that gather doesn't drum up a fuss - - logpt = F.log_softmax(conf_data, dim=-1) - logpt = logpt.gather(1, conf_t.unsqueeze(-1)) - logpt = logpt.view(-1) - pt = logpt.exp() - - # I adapted the alpha_t calculation here from - # https://github.com/pytorch/pytorch/blob/master/modules/detectron/softmax_focal_loss_op.cu - # You'd think you want all the alphas to sum to one, but in the original implementation they - # just give background an alpha of 1-alpha and each forground an alpha of alpha. - background = (conf_t == 0).float() - at = (1 - cfg.focal_loss_alpha) * background + cfg.focal_loss_alpha * (1 - background) - - loss = -at * (1 - pt) ** cfg.focal_loss_gamma * logpt - - # See comment above for keep - return cfg.conf_alpha * (loss * keep).sum() - - def focal_conf_sigmoid_loss(self, conf_data, conf_t): - """ - Focal loss but using sigmoid like the original paper. - Note: To make things mesh easier, the network still predicts 81 class confidences in this mode. - Because retinanet originally only predicts 80, we simply just don't use conf_data[..., 0] - """ - num_classes = conf_data.size(-1) - - conf_t = conf_t.view(-1) # [batch_size*num_priors] - conf_data = conf_data.view(-1, num_classes) # [batch_size*num_priors, num_classes] - - # Ignore neutral samples (class < 0) - keep = (conf_t >= 0).float() - conf_t[conf_t < 0] = 0 # can't mask with -1, so filter that out - - # Compute a one-hot embedding of conf_t - # From https://github.com/kuangliu/pytorch-retinanet/blob/master/utils.py - conf_one_t = torch.eye(num_classes, device=conf_t.get_device())[conf_t] - conf_pm_t = conf_one_t * 2 - 1 # -1 if background, +1 if forground for specific class - - logpt = F.logsigmoid(conf_data * conf_pm_t) # note: 1 - sigmoid(x) = sigmoid(-x) - pt = logpt.exp() - - at = cfg.focal_loss_alpha * conf_one_t + (1 - cfg.focal_loss_alpha) * (1 - conf_one_t) - at[..., 0] = 0 # Set alpha for the background class to 0 because sigmoid focal loss doesn't use it - - loss = -at * (1 - pt) ** cfg.focal_loss_gamma * logpt - loss = keep * loss.sum(dim=-1) - - return cfg.conf_alpha * loss.sum() - - def focal_conf_objectness_loss(self, conf_data, conf_t): - """ - Instead of using softmax, use class[0] to be the objectness score and do sigmoid focal loss on that. - Then for the rest of the classes, softmax them and apply CE for only the positive examples. - - If class[0] = 1 implies forground and class[0] = 0 implies background then you achieve something - similar during test-time to softmax by setting class[1:] = softmax(class[1:]) * class[0] and invert class[0]. - """ - - conf_t = conf_t.view(-1) # [batch_size*num_priors] - conf_data = conf_data.view(-1, conf_data.size(-1)) # [batch_size*num_priors, num_classes] - - # Ignore neutral samples (class < 0) - keep = (conf_t >= 0).float() - conf_t[conf_t < 0] = 0 # so that gather doesn't drum up a fuss - - background = (conf_t == 0).float() - at = (1 - cfg.focal_loss_alpha) * background + cfg.focal_loss_alpha * (1 - background) - - logpt = F.logsigmoid(conf_data[:, 0]) * (1 - background) + F.logsigmoid(-conf_data[:, 0]) * background - pt = logpt.exp() - - obj_loss = -at * (1 - pt) ** cfg.focal_loss_gamma * logpt - - # All that was the objectiveness loss--now time for the class confidence loss - pos_mask = conf_t > 0 - conf_data_pos = (conf_data[:, 1:])[pos_mask] # Now this has just 80 classes - conf_t_pos = conf_t[pos_mask] - 1 # So subtract 1 here - - class_loss = F.cross_entropy(conf_data_pos, conf_t_pos, reduction='sum') - - return cfg.conf_alpha * (class_loss + (obj_loss * keep).sum()) - - def conf_objectness_loss(self, conf_data, conf_t, batch_size, loc_p, loc_t, priors): - """ - Instead of using softmax, use class[0] to be p(obj) * p(IoU) as in YOLO. - Then for the rest of the classes, softmax them and apply CE for only the positive examples. - """ - - conf_t = conf_t.view(-1) # [batch_size*num_priors] - conf_data = conf_data.view(-1, conf_data.size(-1)) # [batch_size*num_priors, num_classes] - - pos_mask = (conf_t > 0) - neg_mask = (conf_t == 0) - - obj_data = conf_data[:, 0] - obj_data_pos = obj_data[pos_mask] - obj_data_neg = obj_data[neg_mask] - - # Don't be confused, this is just binary cross entropy similified - obj_neg_loss = - F.logsigmoid(-obj_data_neg).sum() - - with torch.no_grad(): - pos_priors = priors.unsqueeze(0).expand(batch_size, -1, -1).reshape(-1, 4)[pos_mask, :] - - boxes_pred = decode(loc_p, pos_priors, cfg.use_yolo_regressors) - boxes_targ = decode(loc_t, pos_priors, cfg.use_yolo_regressors) - - iou_targets = elemwise_box_iou(boxes_pred, boxes_targ) - - obj_pos_loss = - iou_targets * F.logsigmoid(obj_data_pos) - (1 - iou_targets) * F.logsigmoid(-obj_data_pos) - obj_pos_loss = obj_pos_loss.sum() - - # All that was the objectiveness loss--now time for the class confidence loss - conf_data_pos = (conf_data[:, 1:])[pos_mask] # Now this has just 80 classes - conf_t_pos = conf_t[pos_mask] - 1 # So subtract 1 here - - class_loss = F.cross_entropy(conf_data_pos, conf_t_pos, reduction='sum') - - return cfg.conf_alpha * (class_loss + obj_pos_loss + obj_neg_loss) - - def direct_mask_loss(self, pos_idx, idx_t, loc_data, mask_data, priors, masks): - """ Crops the gt masks using the predicted bboxes, scales them down, and outputs the BCE loss. """ - loss_m = 0 - for idx in range(mask_data.size(0)): - with torch.no_grad(): - cur_pos_idx = pos_idx[idx, :, :] - cur_pos_idx_squeezed = cur_pos_idx[:, 1] - - # Shape: [num_priors, 4], decoded predicted bboxes - pos_bboxes = decode(loc_data[idx, :, :], priors.data, cfg.use_yolo_regressors) - pos_bboxes = pos_bboxes[cur_pos_idx].view(-1, 4).clamp(0, 1) - pos_lookup = idx_t[idx, cur_pos_idx_squeezed] - - cur_masks = masks[idx] - pos_masks = cur_masks[pos_lookup, :, :] - - # Convert bboxes to absolute coordinates - num_pos, img_height, img_width = pos_masks.size() - - # Take care of all the bad behavior that can be caused by out of bounds coordinates - x1, x2 = sanitize_coordinates(pos_bboxes[:, 0], pos_bboxes[:, 2], img_width) - y1, y2 = sanitize_coordinates(pos_bboxes[:, 1], pos_bboxes[:, 3], img_height) - - # Crop each gt mask with the predicted bbox and rescale to the predicted mask size - # Note that each bounding box crop is a different size so I don't think we can vectorize this - scaled_masks = [] - for jdx in range(num_pos): - tmp_mask = pos_masks[jdx, y1[jdx]:y2[jdx], x1[jdx]:x2[jdx]] - - # Restore any dimensions we've left out because our bbox was 1px wide - while tmp_mask.dim() < 2: - tmp_mask = tmp_mask.unsqueeze(0) - - new_mask = F.adaptive_avg_pool2d(tmp_mask.unsqueeze(0), cfg.mask_size) - scaled_masks.append(new_mask.view(1, -1)) - - mask_t = torch.cat(scaled_masks, 0).gt(0.5).float() # Threshold downsampled mask - - pos_mask_data = mask_data[idx, cur_pos_idx_squeezed, :] - loss_m += F.binary_cross_entropy(torch.clamp(pos_mask_data, 0, 1), mask_t, reduction='sum') * cfg.mask_alpha - - return loss_m - - def coeff_diversity_loss(self, coeffs, instance_t): - """ - coeffs should be size [num_pos, num_coeffs] - instance_t should be size [num_pos] and be values from 0 to num_instances-1 - """ - num_pos = coeffs.size(0) - instance_t = instance_t.view(-1) # juuuust to make sure - - coeffs_norm = F.normalize(coeffs, dim=1) - cos_sim = coeffs_norm @ coeffs_norm.t() - - inst_eq = (instance_t[:, None].expand_as(cos_sim) == instance_t[None, :].expand_as(cos_sim)).float() - - # Rescale to be between 0 and 1 - cos_sim = (cos_sim + 1) / 2 - - # If they're the same instance, use cosine distance, else use cosine similarity - loss = (1 - cos_sim) * inst_eq + cos_sim * (1 - inst_eq) - - # Only divide by num_pos once because we're summing over a num_pos x num_pos tensor - # and all the losses will be divided by num_pos at the end, so just one extra time. - return cfg.mask_proto_coeff_diversity_alpha * loss.sum() / num_pos - - def lincomb_mask_loss(self, pos, idx_t, loc_data, mask_data, priors, proto_data, masks, gt_box_t, score_data, - inst_data, labels, interpolation_mode='bilinear'): - mask_h = proto_data.size(1) - mask_w = proto_data.size(2) - - process_gt_bboxes = cfg.mask_proto_normalize_emulate_roi_pooling or cfg.mask_proto_crop - - if cfg.mask_proto_remove_empty_masks: - # Make sure to store a copy of this because we edit it to get rid of all-zero masks - pos = pos.clone() - - loss_m = 0 - loss_d = 0 # Coefficient diversity loss - - maskiou_t_list = [] - maskiou_net_input_list = [] - label_t_list = [] - - for idx in range(mask_data.size(0)): - with torch.no_grad(): - downsampled_masks = F.interpolate(masks[idx].unsqueeze(0), (mask_h, mask_w), - mode=interpolation_mode, align_corners=False).squeeze(0) - downsampled_masks = downsampled_masks.permute(1, 2, 0).contiguous() - if cfg.mask_proto_binarize_downsampled_gt: - downsampled_masks = downsampled_masks.gt(0.5).float() - - if cfg.mask_proto_remove_empty_masks: - # Get rid of gt masks that are so small they get downsampled away - very_small_masks = (downsampled_masks.sum(dim=(0, 1)) <= 0.0001) - for i in range(very_small_masks.size(0)): - if very_small_masks[i]: - pos[idx, idx_t[idx] == i] = 0 - if cfg.mask_proto_reweight_mask_loss: - # Ensure that the gt is binary - if not cfg.mask_proto_binarize_downsampled_gt: - bin_gt = downsampled_masks.gt(0.5).float() - else: - bin_gt = downsampled_masks - - gt_foreground_norm = bin_gt / (torch.sum(bin_gt, dim=(0, 1), keepdim=True) + 0.0001) - gt_background_norm = (1 - bin_gt) / (torch.sum(1 - bin_gt, dim=(0, 1), keepdim=True) + 0.0001) - - mask_reweighting = gt_foreground_norm * cfg.mask_proto_reweight_coeff + gt_background_norm - mask_reweighting *= mask_h * mask_w - - cur_pos = pos[idx] - pos_idx_t = idx_t[idx, cur_pos] - if process_gt_bboxes: - # Note: this is in point-form - if cfg.mask_proto_crop_with_pred_box: - pos_gt_box_t = decode(loc_data[idx, :, :], priors.data, cfg.use_yolo_regressors)[cur_pos] - else: - pos_gt_box_t = gt_box_t[idx, cur_pos] - if pos_idx_t.size(0) == 0: - continue - - proto_masks = proto_data[idx] - proto_coef = mask_data[idx, cur_pos, :] - if cfg.use_mask_scoring: - mask_scores = score_data[idx, cur_pos, :] - if cfg.mask_proto_coeff_diversity_loss: - if inst_data is not None: - div_coeffs = inst_data[idx, cur_pos, :] - else: - div_coeffs = proto_coef - - loss_d += self.coeff_diversity_loss(div_coeffs, pos_idx_t) - - # If we have over the allowed number of masks, select a random sample - old_num_pos = proto_coef.size(0) - if old_num_pos > cfg.masks_to_train: - perm = torch.randperm(proto_coef.size(0)) - select = perm[:cfg.masks_to_train] - - proto_coef = proto_coef[select, :] - pos_idx_t = pos_idx_t[select] - - if process_gt_bboxes: - pos_gt_box_t = pos_gt_box_t[select, :] - if cfg.use_mask_scoring: - mask_scores = mask_scores[select, :] - - num_pos = proto_coef.size(0) - mask_t = downsampled_masks[:, :, pos_idx_t] - label_t = labels[idx][pos_idx_t] - # Size: [mask_h, mask_w, num_pos] - pred_masks = proto_masks @ proto_coef.t() - pred_masks = cfg.mask_proto_mask_activation(pred_masks) - if cfg.mask_proto_double_loss: - if cfg.mask_proto_mask_activation == activation_func.sigmoid: - pre_loss = F.binary_cross_entropy(torch.clamp(pred_masks, 0, 1), mask_t, reduction='sum') - else: - pre_loss = F.smooth_l1_loss(pred_masks, mask_t, reduction='sum') - - loss_m += cfg.mask_proto_double_loss_alpha * pre_loss - - if cfg.mask_proto_crop: - pred_masks = crop(pred_masks, pos_gt_box_t) - - if cfg.mask_proto_mask_activation == activation_func.sigmoid: - pre_loss = F.binary_cross_entropy(torch.clamp(pred_masks, 0, 1), mask_t, reduction='none') - else: - pre_loss = F.smooth_l1_loss(pred_masks, mask_t, reduction='none') - - if cfg.mask_proto_normalize_mask_loss_by_sqrt_area: - gt_area = torch.sum(mask_t, dim=(0, 1), keepdim=True) - pre_loss = pre_loss / (torch.sqrt(gt_area) + 0.0001) - - if cfg.mask_proto_reweight_mask_loss: - pre_loss = pre_loss * mask_reweighting[:, :, pos_idx_t] - - if cfg.mask_proto_normalize_emulate_roi_pooling: - weight = mask_h * mask_w if cfg.mask_proto_crop else 1 - pos_gt_csize = center_size(pos_gt_box_t) - gt_box_width = pos_gt_csize[:, 2] * mask_w - gt_box_height = pos_gt_csize[:, 3] * mask_h - pre_loss = pre_loss.sum(dim=(0, 1)) / gt_box_width / gt_box_height * weight - - # If the number of masks were limited scale the loss accordingly - if old_num_pos > num_pos: - pre_loss *= old_num_pos / num_pos - - loss_m += torch.sum(pre_loss) - - if cfg.use_maskiou: - if cfg.discard_mask_area > 0: - gt_mask_area = torch.sum(mask_t, dim=(0, 1)) - - select = gt_mask_area > cfg.discard_mask_area - - if torch.sum(select) < 1: - continue - - - pos_gt_box_t = pos_gt_box_t[select, :] - pred_masks = pred_masks[:, :, select] - mask_t = mask_t[:, :, select] - label_t = label_t[select] - - maskiou_net_input = pred_masks.permute(2, 0, 1).contiguous().unsqueeze(1) - pred_masks = pred_masks.gt(0.5).float() - maskiou_t = self._mask_iou(pred_masks, mask_t) - - maskiou_net_input_list.append(maskiou_net_input) - maskiou_t_list.append(maskiou_t) - label_t_list.append(label_t) - - losses = {'M': loss_m * cfg.mask_alpha / mask_h / mask_w} - - if cfg.mask_proto_coeff_diversity_loss: - losses['D'] = loss_d - - if cfg.use_maskiou: - # discard_mask_area discarded every mask in the batch, so nothing to do here - if len(maskiou_t_list) == 0: - return losses, None - - maskiou_t = torch.cat(maskiou_t_list) - label_t = torch.cat(label_t_list) - maskiou_net_input = torch.cat(maskiou_net_input_list) - - num_samples = maskiou_t.size(0) - if cfg.maskious_to_train > 0 and num_samples > cfg.maskious_to_train: - perm = torch.randperm(num_samples) - select = perm[:cfg.masks_to_train] - maskiou_t = maskiou_t[select] - label_t = label_t[select] - maskiou_net_input = maskiou_net_input[select] - - return losses, [maskiou_net_input, maskiou_t, label_t] - - return losses - - def _mask_iou(self, mask1, mask2): - intersection = torch.sum(mask1 * mask2, dim=(0, 1)) - area1 = torch.sum(mask1, dim=(0, 1)) - area2 = torch.sum(mask2, dim=(0, 1)) - union = (area1 + area2) - intersection - ret = intersection / union - return ret - - def mask_iou_loss(self, net, maskiou_targets): - maskiou_net_input, maskiou_t, label_t = maskiou_targets - - maskiou_p = net.maskiou_net(maskiou_net_input) - - label_t = label_t[:, None] - maskiou_p = torch.gather(maskiou_p, dim=1, index=label_t).view(-1) - - loss_i = F.smooth_l1_loss(maskiou_p, maskiou_t, reduction='sum') - - return loss_i * cfg.maskiou_alpha +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +# -*- coding: utf-8 -*- +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.autograd import Variable +from ..box_utils import match, log_sum_exp, decode, center_size, crop, elemwise_mask_iou, elemwise_box_iou + +from data import cfg, mask_type, activation_func + + +class MultiBoxLoss(nn.Module): + """SSD Weighted Loss Function + Compute Targets: + 1) Produce Confidence Target Indices by matching ground truth boxes + with (default) 'priorboxes' that have jaccard index > threshold parameter + (default threshold: 0.5). + + 2) Produce localization target by 'encoding' variance into offsets of ground + truth boxes and their matched 'priorboxes'. + + 3) Hard negative mining to filter the excessive number of negative examples + that comes with using a large number of default bounding boxes. + (default negative:positive ratio 3:1) + + Objective Loss: + L(x,c,l,g) = (Lconf(x, c) + αLloc(x,l,g)) / N + Where, Lconf is the CrossEntropy Loss and Lloc is the SmoothL1 Loss + weighted by α which is set to 1 by cross val. + Args: + c: class confidences, + l: predicted boxes, + g: ground truth boxes + N: number of matched default boxes + See: https://arxiv.org/pdf/1512.02325.pdf for more details. + """ + + def __init__(self, num_classes, pos_threshold, neg_threshold, negpos_ratio): + super(MultiBoxLoss, self).__init__() + self.num_classes = num_classes + + self.pos_threshold = pos_threshold + self.neg_threshold = neg_threshold + self.negpos_ratio = negpos_ratio + + # If you output a proto mask with this area, your l1 loss will be l1_alpha + # Note that the area is relative (so 1 would be the entire image) + self.l1_expected_area = 20 * 20 / 70 / 70 + self.l1_alpha = 0.1 + + if cfg.use_class_balanced_conf: + self.class_instances = None + self.total_instances = 0 + + def forward(self, net, predictions, wrapper, wrapper_mask): + """Multibox Loss + Args: + predictions (tuple): A tuple containing loc preds, conf preds, + mask preds, and prior boxes from SSD net. + loc shape: torch.size(batch_size,num_priors,4) + conf shape: torch.size(batch_size,num_priors,num_classes) + masks shape: torch.size(batch_size,num_priors,mask_dim) + priors shape: torch.size(num_priors,4) + proto* shape: torch.size(batch_size,mask_h,mask_w,mask_dim) + + targets (list): Ground truth boxes and labels for a batch, + shape: [batch_size][num_objs,5] (last idx is the label). + + masks (list): Ground truth masks for each object in each image, + shape: [batch_size][num_objs,im_height,im_width] + + num_crowds (list): Number of crowd annotations per batch. The crowd + annotations should be the last num_crowds elements of targets and masks. + + * Only if mask_type == lincomb + """ + + targets, masks, num_crowds = wrapper.get_args(wrapper_mask) + targets = targets[0] + masks = masks[0] + num_crowds = num_crowds[0] + loc_data = predictions['loc'] + conf_data = predictions['conf'] + mask_data = predictions['mask'] + priors = predictions['priors'] + + if cfg.mask_type == mask_type.lincomb: + proto_data = predictions['proto'] + + score_data = predictions['score'] if cfg.use_mask_scoring else None + inst_data = predictions['inst'] if cfg.use_instance_coeff else None + + labels = [None] * len(targets) # Used in sem segm loss + + batch_size = loc_data.size(0) + num_priors = priors.size(0) + num_classes = self.num_classes + + # Match priors (default boxes) and ground truth boxes + # These tensors will be created with the same device as loc_data + loc_t = loc_data.new(batch_size, num_priors, 4) + gt_box_t = loc_data.new(batch_size, num_priors, 4) + conf_t = loc_data.new(batch_size, num_priors).long() + idx_t = loc_data.new(batch_size, num_priors).long() + + if cfg.use_class_existence_loss: + class_existence_t = loc_data.new(batch_size, num_classes - 1) + + for idx in range(batch_size): + truths = targets[idx][:, :-1].data + labels[idx] = targets[idx][:, -1].data.long() + + if cfg.use_class_existence_loss: + # Construct a one-hot vector for each object and collapse it into an existence vector with max + # Also it's fine to include the crowd annotations here + class_existence_t[idx, :] = \ + torch.eye(num_classes - 1, device=conf_t.get_device())[labels[idx]].max(dim=0)[0] + + # Split the crowd annotations because they come bundled in + cur_crowds = num_crowds[idx] + if cur_crowds > 0: + split = lambda x: (x[-cur_crowds:], x[:-cur_crowds]) + crowd_boxes, truths = split(truths) + + # We don't use the crowd labels or masks + _, labels[idx] = split(labels[idx]) + _, masks[idx] = split(masks[idx]) + else: + crowd_boxes = None + + match(self.pos_threshold, self.neg_threshold, + truths, priors.data, labels[idx], crowd_boxes, + loc_t, conf_t, idx_t, idx, loc_data[idx]) + + gt_box_t[idx, :, :] = truths[idx_t[idx]] + + # wrap targets + loc_t = Variable(loc_t, requires_grad=False) + conf_t = Variable(conf_t, requires_grad=False) + idx_t = Variable(idx_t, requires_grad=False) + + pos = conf_t > 0 + num_pos = pos.sum(dim=1, keepdim=True) + + # Shape: [batch,num_priors,4] + pos_idx = pos.unsqueeze(pos.dim()).expand_as(loc_data) + + losses = {} + + # Localization Loss (Smooth L1) + if cfg.train_boxes: + # loc_p = loc_data[pos_idx].view(-1, 4) + # loc_t = loc_t[pos_idx].view(-1, 4) + # losses['B'] = F.smooth_l1_loss(loc_p, loc_t, reduction='sum') * cfg.bbox_alpha + loc_p = loc_data.view(-1, 4) + loc_t = loc_t.view(-1, 4) + losses['B'] = F.smooth_l1_loss(loc_p, loc_t, reduction='none') * cfg.bbox_alpha + losses['B'][pos_idx.view(-1, 4) == False] = 0 + losses['B'] = losses['B'].sum() + + if cfg.train_masks: + if cfg.mask_type == mask_type.direct: + if cfg.use_gt_bboxes: + pos_masks = [] + for idx in range(batch_size): + pos_masks.append(masks[idx][idx_t[idx, pos[idx]]]) + masks_t = torch.cat(pos_masks, 0) + masks_p = mask_data[pos, :].view(-1, cfg.mask_dim) + losses['M'] = F.binary_cross_entropy(torch.clamp(masks_p, 0, 1), masks_t, + reduction='sum') * cfg.mask_alpha + else: + losses['M'] = self.direct_mask_loss(pos_idx, idx_t, loc_data, mask_data, priors, masks) + elif cfg.mask_type == mask_type.lincomb: + ret = self.lincomb_mask_loss(pos, idx_t, loc_data, mask_data, priors, proto_data, masks, gt_box_t, + score_data, inst_data, labels) + if cfg.use_maskiou: + loss, maskiou_targets = ret + else: + loss = ret + losses.update(loss) + + if cfg.mask_proto_loss is not None: + if cfg.mask_proto_loss == 'l1': + losses['P'] = torch.mean(torch.abs(proto_data)) / self.l1_expected_area * self.l1_alpha + elif cfg.mask_proto_loss == 'disj': + losses['P'] = -torch.mean(torch.max(F.log_softmax(proto_data, dim=-1), dim=-1)[0]) + + # Confidence loss + if cfg.use_focal_loss: + if cfg.use_sigmoid_focal_loss: + losses['C'] = self.focal_conf_sigmoid_loss(conf_data, conf_t) + elif cfg.use_objectness_score: + losses['C'] = self.focal_conf_objectness_loss(conf_data, conf_t) + else: + losses['C'] = self.focal_conf_loss(conf_data, conf_t) + else: + if cfg.use_objectness_score: + losses['C'] = self.conf_objectness_loss(conf_data, conf_t, batch_size, loc_p, loc_t, priors) + else: + losses['C'] = self.ohem_conf_loss(conf_data, conf_t, pos, batch_size) + + # Mask IoU Loss + if cfg.use_maskiou and maskiou_targets is not None: + losses['I'] = self.mask_iou_loss(net, maskiou_targets) + + # These losses also don't depend on anchors + if cfg.use_class_existence_loss: + losses['E'] = self.class_existence_loss(predictions['classes'], class_existence_t) + if cfg.use_semantic_segmentation_loss: + losses['S'] = self.semantic_segmentation_loss(predictions['segm'], masks, labels) + + # Divide all losses by the number of positives. + # Don't do it for loss[P] because that doesn't depend on the anchors. + total_num_pos = num_pos.data.sum().float() + for k in losses: + if k not in ('P', 'E', 'S'): + losses[k] /= total_num_pos + else: + losses[k] /= batch_size + + # Loss Key: + # - B: Box Localization Loss + # - C: Class Confidence Loss + # - M: Mask Loss + # - P: Prototype Loss + # - D: Coefficient Diversity Loss + # - E: Class Existence Loss + # - S: Semantic Segmentation Loss + return losses + + def class_existence_loss(self, class_data, class_existence_t): + return cfg.class_existence_alpha * F.binary_cross_entropy_with_logits(class_data, class_existence_t, + reduction='sum') + + def semantic_segmentation_loss(self, segment_data, mask_t, class_t, interpolation_mode='bilinear'): + # Note num_classes here is without the background class so cfg.num_classes-1 + batch_size, num_classes, mask_h, mask_w = segment_data.size() + loss_s = 0 + + for idx in range(batch_size): + cur_segment = segment_data[idx] + cur_class_t = class_t[idx] + + with torch.no_grad(): + downsampled_masks = F.interpolate(mask_t[idx].unsqueeze(0), (mask_h, mask_w), + mode=interpolation_mode, align_corners=False).squeeze(0) + downsampled_masks = downsampled_masks.gt(0.5).float() + + # Construct Semantic Segmentation + segment_t = torch.zeros_like(cur_segment, requires_grad=False) + for obj_idx in range(downsampled_masks.size(0)): + segment_t[cur_class_t[obj_idx]] = torch.max(segment_t[cur_class_t[obj_idx]].float(), + downsampled_masks[obj_idx]) + + loss_s += F.binary_cross_entropy_with_logits(cur_segment, segment_t, reduction='sum') + + return loss_s / mask_h / mask_w * cfg.semantic_segmentation_alpha + + def ohem_conf_loss(self, conf_data, conf_t, pos, num): + # Compute max conf across batch for hard negative mining + batch_conf = conf_data.view(-1, self.num_classes) + if cfg.ohem_use_most_confident: + # i.e. max(softmax) along classes > 0 + batch_conf = F.softmax(batch_conf, dim=1) + loss_c, _ = batch_conf[:, 1:].max(dim=1) + else: + # i.e. -softmax(class 0 confidence) + loss_c = log_sum_exp(batch_conf) - batch_conf[:, 0] + + # Hard Negative Mining + loss_c = loss_c.view(num, -1) + loss_c[pos] = 0 # filter out pos boxes + loss_c[conf_t < 0] = 0 # filter out neutrals (conf_t = -1) + _, loss_idx = loss_c.sort(1, descending=True) + _, idx_rank = loss_idx.sort(1) + num_pos = pos.long().sum(1, keepdim=True) + num_neg = torch.clamp(self.negpos_ratio * num_pos, max=pos.size(1) - 1) + neg = idx_rank < num_neg.expand_as(idx_rank) + + # Just in case there aren't enough negatives, don't start using positives as negatives + neg[pos] = 0 + neg[conf_t < 0] = 0 # Filter out neutrals + + # Confidence Loss Including Positive and Negative Examples + # pos_idx = pos.unsqueeze(2).expand_as(conf_data) + # neg_idx = neg.unsqueeze(2).expand_as(conf_data) + + # conf_p = conf_data[(pos_idx+neg_idx).gt(0)].view(-1, self.num_classes) + # targets_weighted = conf_t[(pos+neg).gt(0)] + ## loss_c = F.cross_entropy(conf_p, targets_weighted, reduction='none') + loss_c = F.cross_entropy(conf_data.view(-1, self.num_classes), conf_t.view(-1), reduction='none').view(-1, + 57744) + loss_c[(pos + neg).gt(0) == False] = 0 + + if cfg.use_class_balanced_conf: + # Lazy initialization + if self.class_instances is None: + self.class_instances = torch.zeros(self.num_classes, device=targets_weighted.device) + + classes, counts = targets_weighted.unique(return_counts=True) + + for _cls, _cnt in zip(classes.cpu().numpy(), counts.cpu().numpy()): + self.class_instances[_cls] += _cnt + + self.total_instances += targets_weighted.size(0) + + weighting = 1 - (self.class_instances[targets_weighted] / self.total_instances) + weighting = torch.clamp(weighting, min=1 / self.num_classes) + + # If you do the math, the average weight of self.class_instances is this + avg_weight = (self.num_classes - 1) / self.num_classes + + loss_c = (loss_c * weighting).sum() / avg_weight + else: + loss_c = loss_c.sum() + + return cfg.conf_alpha * loss_c + + def focal_conf_loss(self, conf_data, conf_t): + """ + Focal loss as described in https://arxiv.org/pdf/1708.02002.pdf + Adapted from https://github.com/clcarwin/focal_loss_pytorch/blob/master/focalloss.py + Note that this uses softmax and not the original sigmoid from the paper. + """ + conf_t = conf_t.view(-1) # [batch_size*num_priors] + conf_data = conf_data.view(-1, conf_data.size(-1)) # [batch_size*num_priors, num_classes] + + # Ignore neutral samples (class < 0) + keep = (conf_t >= 0).float() + conf_t[conf_t < 0] = 0 # so that gather doesn't drum up a fuss + + logpt = F.log_softmax(conf_data, dim=-1) + logpt = logpt.gather(1, conf_t.unsqueeze(-1)) + logpt = logpt.view(-1) + pt = logpt.exp() + + # I adapted the alpha_t calculation here from + # https://github.com/pytorch/pytorch/blob/master/modules/detectron/softmax_focal_loss_op.cu + # You'd think you want all the alphas to sum to one, but in the original implementation they + # just give background an alpha of 1-alpha and each forground an alpha of alpha. + background = (conf_t == 0).float() + at = (1 - cfg.focal_loss_alpha) * background + cfg.focal_loss_alpha * (1 - background) + + loss = -at * (1 - pt) ** cfg.focal_loss_gamma * logpt + + # See comment above for keep + return cfg.conf_alpha * (loss * keep).sum() + + def focal_conf_sigmoid_loss(self, conf_data, conf_t): + """ + Focal loss but using sigmoid like the original paper. + Note: To make things mesh easier, the network still predicts 81 class confidences in this mode. + Because retinanet originally only predicts 80, we simply just don't use conf_data[..., 0] + """ + num_classes = conf_data.size(-1) + + conf_t = conf_t.view(-1) # [batch_size*num_priors] + conf_data = conf_data.view(-1, num_classes) # [batch_size*num_priors, num_classes] + + # Ignore neutral samples (class < 0) + keep = (conf_t >= 0).float() + conf_t[conf_t < 0] = 0 # can't mask with -1, so filter that out + + # Compute a one-hot embedding of conf_t + # From https://github.com/kuangliu/pytorch-retinanet/blob/master/utils.py + conf_one_t = torch.eye(num_classes, device=conf_t.get_device())[conf_t] + conf_pm_t = conf_one_t * 2 - 1 # -1 if background, +1 if forground for specific class + + logpt = F.logsigmoid(conf_data * conf_pm_t) # note: 1 - sigmoid(x) = sigmoid(-x) + pt = logpt.exp() + + at = cfg.focal_loss_alpha * conf_one_t + (1 - cfg.focal_loss_alpha) * (1 - conf_one_t) + at[..., 0] = 0 # Set alpha for the background class to 0 because sigmoid focal loss doesn't use it + + loss = -at * (1 - pt) ** cfg.focal_loss_gamma * logpt + loss = keep * loss.sum(dim=-1) + + return cfg.conf_alpha * loss.sum() + + def focal_conf_objectness_loss(self, conf_data, conf_t): + """ + Instead of using softmax, use class[0] to be the objectness score and do sigmoid focal loss on that. + Then for the rest of the classes, softmax them and apply CE for only the positive examples. + + If class[0] = 1 implies forground and class[0] = 0 implies background then you achieve something + similar during test-time to softmax by setting class[1:] = softmax(class[1:]) * class[0] and invert class[0]. + """ + + conf_t = conf_t.view(-1) # [batch_size*num_priors] + conf_data = conf_data.view(-1, conf_data.size(-1)) # [batch_size*num_priors, num_classes] + + # Ignore neutral samples (class < 0) + keep = (conf_t >= 0).float() + conf_t[conf_t < 0] = 0 # so that gather doesn't drum up a fuss + + background = (conf_t == 0).float() + at = (1 - cfg.focal_loss_alpha) * background + cfg.focal_loss_alpha * (1 - background) + + logpt = F.logsigmoid(conf_data[:, 0]) * (1 - background) + F.logsigmoid(-conf_data[:, 0]) * background + pt = logpt.exp() + + obj_loss = -at * (1 - pt) ** cfg.focal_loss_gamma * logpt + + # All that was the objectiveness loss--now time for the class confidence loss + pos_mask = conf_t > 0 + conf_data_pos = (conf_data[:, 1:])[pos_mask] # Now this has just 80 classes + conf_t_pos = conf_t[pos_mask] - 1 # So subtract 1 here + + class_loss = F.cross_entropy(conf_data_pos, conf_t_pos, reduction='sum') + + return cfg.conf_alpha * (class_loss + (obj_loss * keep).sum()) + + def conf_objectness_loss(self, conf_data, conf_t, batch_size, loc_p, loc_t, priors): + """ + Instead of using softmax, use class[0] to be p(obj) * p(IoU) as in YOLO. + Then for the rest of the classes, softmax them and apply CE for only the positive examples. + """ + + conf_t = conf_t.view(-1) # [batch_size*num_priors] + conf_data = conf_data.view(-1, conf_data.size(-1)) # [batch_size*num_priors, num_classes] + + pos_mask = (conf_t > 0) + neg_mask = (conf_t == 0) + + obj_data = conf_data[:, 0] + obj_data_pos = obj_data[pos_mask] + obj_data_neg = obj_data[neg_mask] + + # Don't be confused, this is just binary cross entropy similified + obj_neg_loss = - F.logsigmoid(-obj_data_neg).sum() + + with torch.no_grad(): + pos_priors = priors.unsqueeze(0).expand(batch_size, -1, -1).reshape(-1, 4)[pos_mask, :] + + boxes_pred = decode(loc_p, pos_priors, cfg.use_yolo_regressors) + boxes_targ = decode(loc_t, pos_priors, cfg.use_yolo_regressors) + + iou_targets = elemwise_box_iou(boxes_pred, boxes_targ) + + obj_pos_loss = - iou_targets * F.logsigmoid(obj_data_pos) - (1 - iou_targets) * F.logsigmoid(-obj_data_pos) + obj_pos_loss = obj_pos_loss.sum() + + # All that was the objectiveness loss--now time for the class confidence loss + conf_data_pos = (conf_data[:, 1:])[pos_mask] # Now this has just 80 classes + conf_t_pos = conf_t[pos_mask] - 1 # So subtract 1 here + + class_loss = F.cross_entropy(conf_data_pos, conf_t_pos, reduction='sum') + + return cfg.conf_alpha * (class_loss + obj_pos_loss + obj_neg_loss) + + def direct_mask_loss(self, pos_idx, idx_t, loc_data, mask_data, priors, masks): + """ Crops the gt masks using the predicted bboxes, scales them down, and outputs the BCE loss. """ + loss_m = 0 + for idx in range(mask_data.size(0)): + with torch.no_grad(): + cur_pos_idx = pos_idx[idx, :, :] + cur_pos_idx_squeezed = cur_pos_idx[:, 1] + + # Shape: [num_priors, 4], decoded predicted bboxes + pos_bboxes = decode(loc_data[idx, :, :], priors.data, cfg.use_yolo_regressors) + pos_bboxes = pos_bboxes[cur_pos_idx].view(-1, 4).clamp(0, 1) + pos_lookup = idx_t[idx, cur_pos_idx_squeezed] + + cur_masks = masks[idx] + pos_masks = cur_masks[pos_lookup, :, :] + + # Convert bboxes to absolute coordinates + num_pos, img_height, img_width = pos_masks.size() + + # Take care of all the bad behavior that can be caused by out of bounds coordinates + x1, x2 = sanitize_coordinates(pos_bboxes[:, 0], pos_bboxes[:, 2], img_width) + y1, y2 = sanitize_coordinates(pos_bboxes[:, 1], pos_bboxes[:, 3], img_height) + + # Crop each gt mask with the predicted bbox and rescale to the predicted mask size + # Note that each bounding box crop is a different size so I don't think we can vectorize this + scaled_masks = [] + for jdx in range(num_pos): + tmp_mask = pos_masks[jdx, y1[jdx]:y2[jdx], x1[jdx]:x2[jdx]] + + # Restore any dimensions we've left out because our bbox was 1px wide + while tmp_mask.dim() < 2: + tmp_mask = tmp_mask.unsqueeze(0) + + new_mask = F.adaptive_avg_pool2d(tmp_mask.unsqueeze(0), cfg.mask_size) + scaled_masks.append(new_mask.view(1, -1)) + + mask_t = torch.cat(scaled_masks, 0).gt(0.5).float() # Threshold downsampled mask + + pos_mask_data = mask_data[idx, cur_pos_idx_squeezed, :] + loss_m += F.binary_cross_entropy(torch.clamp(pos_mask_data, 0, 1), mask_t, reduction='sum') * cfg.mask_alpha + + return loss_m + + def coeff_diversity_loss(self, coeffs, instance_t): + """ + coeffs should be size [num_pos, num_coeffs] + instance_t should be size [num_pos] and be values from 0 to num_instances-1 + """ + num_pos = coeffs.size(0) + instance_t = instance_t.view(-1) # juuuust to make sure + + coeffs_norm = F.normalize(coeffs, dim=1) + cos_sim = coeffs_norm @ coeffs_norm.t() + + inst_eq = (instance_t[:, None].expand_as(cos_sim) == instance_t[None, :].expand_as(cos_sim)).float() + + # Rescale to be between 0 and 1 + cos_sim = (cos_sim + 1) / 2 + + # If they're the same instance, use cosine distance, else use cosine similarity + loss = (1 - cos_sim) * inst_eq + cos_sim * (1 - inst_eq) + + # Only divide by num_pos once because we're summing over a num_pos x num_pos tensor + # and all the losses will be divided by num_pos at the end, so just one extra time. + return cfg.mask_proto_coeff_diversity_alpha * loss.sum() / num_pos + + def lincomb_mask_loss(self, pos, idx_t, loc_data, mask_data, priors, proto_data, masks, gt_box_t, score_data, + inst_data, labels, interpolation_mode='bilinear'): + mask_h = proto_data.size(1) + mask_w = proto_data.size(2) + + process_gt_bboxes = cfg.mask_proto_normalize_emulate_roi_pooling or cfg.mask_proto_crop + + if cfg.mask_proto_remove_empty_masks: + # Make sure to store a copy of this because we edit it to get rid of all-zero masks + pos = pos.clone() + + loss_m = 0 + loss_d = 0 # Coefficient diversity loss + + maskiou_t_list = [] + maskiou_net_input_list = [] + label_t_list = [] + + for idx in range(mask_data.size(0)): + with torch.no_grad(): + downsampled_masks = F.interpolate(masks[idx].unsqueeze(0), (mask_h, mask_w), + mode=interpolation_mode, align_corners=False).squeeze(0) + downsampled_masks = downsampled_masks.permute(1, 2, 0).contiguous() + if cfg.mask_proto_binarize_downsampled_gt: + downsampled_masks = downsampled_masks.gt(0.5).float() + + if cfg.mask_proto_remove_empty_masks: + # Get rid of gt masks that are so small they get downsampled away + very_small_masks = (downsampled_masks.sum(dim=(0, 1)) <= 0.0001) + for i in range(very_small_masks.size(0)): + if very_small_masks[i]: + pos[idx, idx_t[idx] == i] = 0 + if cfg.mask_proto_reweight_mask_loss: + # Ensure that the gt is binary + if not cfg.mask_proto_binarize_downsampled_gt: + bin_gt = downsampled_masks.gt(0.5).float() + else: + bin_gt = downsampled_masks + + gt_foreground_norm = bin_gt / (torch.sum(bin_gt, dim=(0, 1), keepdim=True) + 0.0001) + gt_background_norm = (1 - bin_gt) / (torch.sum(1 - bin_gt, dim=(0, 1), keepdim=True) + 0.0001) + + mask_reweighting = gt_foreground_norm * cfg.mask_proto_reweight_coeff + gt_background_norm + mask_reweighting *= mask_h * mask_w + + cur_pos = pos[idx] + pos_idx_t = idx_t[idx, cur_pos] + if process_gt_bboxes: + # Note: this is in point-form + if cfg.mask_proto_crop_with_pred_box: + pos_gt_box_t = decode(loc_data[idx, :, :], priors.data, cfg.use_yolo_regressors)[cur_pos] + else: + pos_gt_box_t = gt_box_t[idx, cur_pos] + if pos_idx_t.size(0) == 0: + continue + + proto_masks = proto_data[idx] + proto_coef = mask_data[idx, cur_pos, :] + if cfg.use_mask_scoring: + mask_scores = score_data[idx, cur_pos, :] + if cfg.mask_proto_coeff_diversity_loss: + if inst_data is not None: + div_coeffs = inst_data[idx, cur_pos, :] + else: + div_coeffs = proto_coef + + loss_d += self.coeff_diversity_loss(div_coeffs, pos_idx_t) + + # If we have over the allowed number of masks, select a random sample + old_num_pos = proto_coef.size(0) + if old_num_pos > cfg.masks_to_train: + perm = torch.randperm(proto_coef.size(0)) + select = perm[:cfg.masks_to_train] + + proto_coef = proto_coef[select, :] + pos_idx_t = pos_idx_t[select] + + if process_gt_bboxes: + pos_gt_box_t = pos_gt_box_t[select, :] + if cfg.use_mask_scoring: + mask_scores = mask_scores[select, :] + + num_pos = proto_coef.size(0) + mask_t = downsampled_masks[:, :, pos_idx_t] + label_t = labels[idx][pos_idx_t] + # Size: [mask_h, mask_w, num_pos] + pred_masks = proto_masks @ proto_coef.t() + pred_masks = cfg.mask_proto_mask_activation(pred_masks) + if cfg.mask_proto_double_loss: + if cfg.mask_proto_mask_activation == activation_func.sigmoid: + pre_loss = F.binary_cross_entropy(torch.clamp(pred_masks, 0, 1), mask_t, reduction='sum') + else: + pre_loss = F.smooth_l1_loss(pred_masks, mask_t, reduction='sum') + + loss_m += cfg.mask_proto_double_loss_alpha * pre_loss + + if cfg.mask_proto_crop: + pred_masks = crop(pred_masks, pos_gt_box_t) + + if cfg.mask_proto_mask_activation == activation_func.sigmoid: + pre_loss = F.binary_cross_entropy(torch.clamp(pred_masks, 0, 1), mask_t, reduction='none') + else: + pre_loss = F.smooth_l1_loss(pred_masks, mask_t, reduction='none') + + if cfg.mask_proto_normalize_mask_loss_by_sqrt_area: + gt_area = torch.sum(mask_t, dim=(0, 1), keepdim=True) + pre_loss = pre_loss / (torch.sqrt(gt_area) + 0.0001) + + if cfg.mask_proto_reweight_mask_loss: + pre_loss = pre_loss * mask_reweighting[:, :, pos_idx_t] + + if cfg.mask_proto_normalize_emulate_roi_pooling: + weight = mask_h * mask_w if cfg.mask_proto_crop else 1 + pos_gt_csize = center_size(pos_gt_box_t) + gt_box_width = pos_gt_csize[:, 2] * mask_w + gt_box_height = pos_gt_csize[:, 3] * mask_h + pre_loss = pre_loss.sum(dim=(0, 1)) / gt_box_width / gt_box_height * weight + + # If the number of masks were limited scale the loss accordingly + if old_num_pos > num_pos: + pre_loss *= old_num_pos / num_pos + + loss_m += torch.sum(pre_loss) + + if cfg.use_maskiou: + if cfg.discard_mask_area > 0: + gt_mask_area = torch.sum(mask_t, dim=(0, 1)) + + select = gt_mask_area > cfg.discard_mask_area + + if torch.sum(select) < 1: + continue + + + pos_gt_box_t = pos_gt_box_t[select, :] + pred_masks = pred_masks[:, :, select] + mask_t = mask_t[:, :, select] + label_t = label_t[select] + + maskiou_net_input = pred_masks.permute(2, 0, 1).contiguous().unsqueeze(1) + pred_masks = pred_masks.gt(0.5).float() + maskiou_t = self._mask_iou(pred_masks, mask_t) + + maskiou_net_input_list.append(maskiou_net_input) + maskiou_t_list.append(maskiou_t) + label_t_list.append(label_t) + + losses = {'M': loss_m * cfg.mask_alpha / mask_h / mask_w} + + if cfg.mask_proto_coeff_diversity_loss: + losses['D'] = loss_d + + if cfg.use_maskiou: + # discard_mask_area discarded every mask in the batch, so nothing to do here + if len(maskiou_t_list) == 0: + return losses, None + + maskiou_t = torch.cat(maskiou_t_list) + label_t = torch.cat(label_t_list) + maskiou_net_input = torch.cat(maskiou_net_input_list) + + num_samples = maskiou_t.size(0) + if cfg.maskious_to_train > 0 and num_samples > cfg.maskious_to_train: + perm = torch.randperm(num_samples) + select = perm[:cfg.masks_to_train] + maskiou_t = maskiou_t[select] + label_t = label_t[select] + maskiou_net_input = maskiou_net_input[select] + + return losses, [maskiou_net_input, maskiou_t, label_t] + + return losses + + def _mask_iou(self, mask1, mask2): + intersection = torch.sum(mask1 * mask2, dim=(0, 1)) + area1 = torch.sum(mask1, dim=(0, 1)) + area2 = torch.sum(mask2, dim=(0, 1)) + union = (area1 + area2) - intersection + ret = intersection / union + return ret + + def mask_iou_loss(self, net, maskiou_targets): + maskiou_net_input, maskiou_t, label_t = maskiou_targets + + maskiou_p = net.maskiou_net(maskiou_net_input) + + label_t = label_t[:, None] + maskiou_p = torch.gather(maskiou_p, dim=1, index=label_t).view(-1) + + loss_i = F.smooth_l1_loss(maskiou_p, maskiou_t, reduction='sum') + + return loss_i * cfg.maskiou_alpha diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/layers/output_utils.py b/PyTorch/contrib/cv/detection/YOLACT_plus/layers/output_utils.py index f84c02899d..dbda93adba 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/layers/output_utils.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/layers/output_utils.py @@ -1,200 +1,200 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ -""" Contains functions used to sanitize and prepare the output of Yolact. """ - - -import torch -import torch.nn as nn -import torch.nn.functional as F -import numpy as np -import cv2 - -from data import cfg, mask_type, MEANS, STD, activation_func -from utils.augmentations import Resize -from utils import timer -from .box_utils import crop, sanitize_coordinates - -def postprocess(det_output, w, h, batch_idx=0, interpolation_mode='bilinear', - visualize_lincomb=False, crop_masks=True, score_threshold=0): - """ - Postprocesses the output of Yolact on testing mode into a format that makes sense, - accounting for all the possible configuration settings. - - Args: - - det_output: The lost of dicts that Detect outputs. - - w: The real with of the image. - - h: The real height of the image. - - batch_idx: If you have multiple images for this batch, the image's index in the batch. - - interpolation_mode: Can be 'nearest' | 'area' | 'bilinear' (see torch.nn.functional.interpolate) - - Returns 4 torch Tensors (in the following order): - - classes [num_det]: The class idx for each detection. - - scores [num_det]: The confidence score for each detection. - - boxes [num_det, 4]: The bounding box for each detection in absolute point form. - - masks [num_det, h, w]: Full image masks for each detection. - """ - - dets = det_output[batch_idx] - - if dets is None: - return [torch.Tensor()] * 4 # Warning, this is 4 copies of the same thing - - if score_threshold > 0: - keep = dets['score'] > score_threshold - - for k in dets: - if k != 'proto': - dets[k] = dets[k][keep] - - if dets['score'].size(0) == 0: - return [torch.Tensor()] * 4 - - # Actually extract everything from dets now - classes = dets['class'] - boxes = dets['box'] - scores = dets['score'] - masks = dets['mask'] - - if cfg.mask_type == mask_type.lincomb and cfg.eval_mask_branch: - # At this points masks is only the coefficients - proto_data = dets['proto'] - - # Test flag, do not upvote - if cfg.mask_proto_debug: - np.save('scripts/proto.npy', proto_data.cpu().numpy()) - - if visualize_lincomb: - display_lincomb(proto_data, masks) - - masks = proto_data @ masks.t() - masks = cfg.mask_proto_mask_activation(masks) - - # Crop masks before upsampling because you know why - if crop_masks: - masks = crop(masks, boxes) - - # Permute into the correct output shape [num_dets, proto_h, proto_w] - masks = masks.permute(2, 0, 1).contiguous() - - if cfg.use_maskiou: - with timer.env('maskiou_net'): - with torch.no_grad(): - maskiou_p = net.maskiou_net(masks.unsqueeze(1)) - maskiou_p = torch.gather(maskiou_p, dim=1, index=classes.unsqueeze(1)).squeeze(1) - if cfg.rescore_mask: - if cfg.rescore_bbox: - scores = scores * maskiou_p - else: - scores = [scores, scores * maskiou_p] - - # Scale masks up to the full image - masks = F.interpolate(masks.unsqueeze(0), (h, w), mode=interpolation_mode, align_corners=False).squeeze(0) - - # Binarize the masks - masks.gt_(0.5) - - - boxes[:, 0], boxes[:, 2] = sanitize_coordinates(boxes[:, 0], boxes[:, 2], w, cast=False) - boxes[:, 1], boxes[:, 3] = sanitize_coordinates(boxes[:, 1], boxes[:, 3], h, cast=False) - boxes = boxes.long() - - if cfg.mask_type == mask_type.direct and cfg.eval_mask_branch: - # Upscale masks - full_masks = torch.zeros(masks.size(0), h, w) - - for jdx in range(masks.size(0)): - x1, y1, x2, y2 = boxes[jdx, :] - - mask_w = x2 - x1 - mask_h = y2 - y1 - - # Just in case - if mask_w * mask_h <= 0 or mask_w < 0: - continue - - mask = masks[jdx, :].view(1, 1, cfg.mask_size, cfg.mask_size) - mask = F.interpolate(mask, (mask_h, mask_w), mode=interpolation_mode, align_corners=False) - mask = mask.gt(0.5).float() - full_masks[jdx, y1:y2, x1:x2] = mask - - masks = full_masks - - return classes, scores, boxes, masks - - - - - -def undo_image_transformation(img, w, h): - """ - Takes a transformed image tensor and returns a numpy ndarray that is untransformed. - Arguments w and h are the original height and width of the image. - """ - img_numpy = img.permute(1, 2, 0).cpu().numpy() - img_numpy = img_numpy[:, :, (2, 1, 0)] # To BRG - - if cfg.backbone.transform.normalize: - img_numpy = (img_numpy * np.array(STD) + np.array(MEANS)) / 255.0 - elif cfg.backbone.transform.subtract_means: - img_numpy = (img_numpy / 255.0 + np.array(MEANS) / 255.0).astype(np.float32) - - img_numpy = img_numpy[:, :, (2, 1, 0)] # To RGB - img_numpy = np.clip(img_numpy, 0, 1) - - return cv2.resize(img_numpy, (w,h)) - - -def display_lincomb(proto_data, masks): - out_masks = torch.matmul(proto_data, masks.t()) - # out_masks = cfg.mask_proto_mask_activation(out_masks) - - for kdx in range(1): - jdx = kdx + 0 - import matplotlib.pyplot as plt - coeffs = masks[jdx, :].cpu().numpy() - idx = np.argsort(-np.abs(coeffs)) - # plt.bar(list(range(idx.shape[0])), coeffs[idx]) - # plt.show() - - coeffs_sort = coeffs[idx] - arr_h, arr_w = (4,8) - proto_h, proto_w, _ = proto_data.size() - arr_img = np.zeros([proto_h*arr_h, proto_w*arr_w]) - arr_run = np.zeros([proto_h*arr_h, proto_w*arr_w]) - test = torch.sum(proto_data, -1).cpu().numpy() - - for y in range(arr_h): - for x in range(arr_w): - i = arr_w * y + x - - if i == 0: - running_total = proto_data[:, :, idx[i]].cpu().numpy() * coeffs_sort[i] - else: - running_total += proto_data[:, :, idx[i]].cpu().numpy() * coeffs_sort[i] - - running_total_nonlin = running_total - if cfg.mask_proto_mask_activation == activation_func.sigmoid: - running_total_nonlin = (1/(1+np.exp(-running_total_nonlin))) - - arr_img[y*proto_h:(y+1)*proto_h, x*proto_w:(x+1)*proto_w] = (proto_data[:, :, idx[i]] / torch.max(proto_data[:, :, idx[i]])).cpu().numpy() * coeffs_sort[i] - arr_run[y*proto_h:(y+1)*proto_h, x*proto_w:(x+1)*proto_w] = (running_total_nonlin > 0.5).astype(np.float) - plt.imshow(arr_img) - plt.show() - # plt.imshow(arr_run) - # plt.show() - # plt.imshow(test) - # plt.show() - plt.imshow(out_masks[:, :, jdx].cpu().numpy()) - plt.show() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +""" Contains functions used to sanitize and prepare the output of Yolact. """ + + +import torch +import torch.nn as nn +import torch.nn.functional as F +import numpy as np +import cv2 + +from data import cfg, mask_type, MEANS, STD, activation_func +from utils.augmentations import Resize +from utils import timer +from .box_utils import crop, sanitize_coordinates + +def postprocess(det_output, w, h, batch_idx=0, interpolation_mode='bilinear', + visualize_lincomb=False, crop_masks=True, score_threshold=0): + """ + Postprocesses the output of Yolact on testing mode into a format that makes sense, + accounting for all the possible configuration settings. + + Args: + - det_output: The lost of dicts that Detect outputs. + - w: The real with of the image. + - h: The real height of the image. + - batch_idx: If you have multiple images for this batch, the image's index in the batch. + - interpolation_mode: Can be 'nearest' | 'area' | 'bilinear' (see torch.nn.functional.interpolate) + + Returns 4 torch Tensors (in the following order): + - classes [num_det]: The class idx for each detection. + - scores [num_det]: The confidence score for each detection. + - boxes [num_det, 4]: The bounding box for each detection in absolute point form. + - masks [num_det, h, w]: Full image masks for each detection. + """ + + dets = det_output[batch_idx] + + if dets is None: + return [torch.Tensor()] * 4 # Warning, this is 4 copies of the same thing + + if score_threshold > 0: + keep = dets['score'] > score_threshold + + for k in dets: + if k != 'proto': + dets[k] = dets[k][keep] + + if dets['score'].size(0) == 0: + return [torch.Tensor()] * 4 + + # Actually extract everything from dets now + classes = dets['class'] + boxes = dets['box'] + scores = dets['score'] + masks = dets['mask'] + + if cfg.mask_type == mask_type.lincomb and cfg.eval_mask_branch: + # At this points masks is only the coefficients + proto_data = dets['proto'] + + # Test flag, do not upvote + if cfg.mask_proto_debug: + np.save('scripts/proto.npy', proto_data.cpu().numpy()) + + if visualize_lincomb: + display_lincomb(proto_data, masks) + + masks = proto_data @ masks.t() + masks = cfg.mask_proto_mask_activation(masks) + + # Crop masks before upsampling because you know why + if crop_masks: + masks = crop(masks, boxes) + + # Permute into the correct output shape [num_dets, proto_h, proto_w] + masks = masks.permute(2, 0, 1).contiguous() + + if cfg.use_maskiou: + with timer.env('maskiou_net'): + with torch.no_grad(): + maskiou_p = net.maskiou_net(masks.unsqueeze(1)) + maskiou_p = torch.gather(maskiou_p, dim=1, index=classes.unsqueeze(1)).squeeze(1) + if cfg.rescore_mask: + if cfg.rescore_bbox: + scores = scores * maskiou_p + else: + scores = [scores, scores * maskiou_p] + + # Scale masks up to the full image + masks = F.interpolate(masks.unsqueeze(0), (h, w), mode=interpolation_mode, align_corners=False).squeeze(0) + + # Binarize the masks + masks.gt_(0.5) + + + boxes[:, 0], boxes[:, 2] = sanitize_coordinates(boxes[:, 0], boxes[:, 2], w, cast=False) + boxes[:, 1], boxes[:, 3] = sanitize_coordinates(boxes[:, 1], boxes[:, 3], h, cast=False) + boxes = boxes.long() + + if cfg.mask_type == mask_type.direct and cfg.eval_mask_branch: + # Upscale masks + full_masks = torch.zeros(masks.size(0), h, w) + + for jdx in range(masks.size(0)): + x1, y1, x2, y2 = boxes[jdx, :] + + mask_w = x2 - x1 + mask_h = y2 - y1 + + # Just in case + if mask_w * mask_h <= 0 or mask_w < 0: + continue + + mask = masks[jdx, :].view(1, 1, cfg.mask_size, cfg.mask_size) + mask = F.interpolate(mask, (mask_h, mask_w), mode=interpolation_mode, align_corners=False) + mask = mask.gt(0.5).float() + full_masks[jdx, y1:y2, x1:x2] = mask + + masks = full_masks + + return classes, scores, boxes, masks + + + + + +def undo_image_transformation(img, w, h): + """ + Takes a transformed image tensor and returns a numpy ndarray that is untransformed. + Arguments w and h are the original height and width of the image. + """ + img_numpy = img.permute(1, 2, 0).cpu().numpy() + img_numpy = img_numpy[:, :, (2, 1, 0)] # To BRG + + if cfg.backbone.transform.normalize: + img_numpy = (img_numpy * np.array(STD) + np.array(MEANS)) / 255.0 + elif cfg.backbone.transform.subtract_means: + img_numpy = (img_numpy / 255.0 + np.array(MEANS) / 255.0).astype(np.float32) + + img_numpy = img_numpy[:, :, (2, 1, 0)] # To RGB + img_numpy = np.clip(img_numpy, 0, 1) + + return cv2.resize(img_numpy, (w,h)) + + +def display_lincomb(proto_data, masks): + out_masks = torch.matmul(proto_data, masks.t()) + # out_masks = cfg.mask_proto_mask_activation(out_masks) + + for kdx in range(1): + jdx = kdx + 0 + import matplotlib.pyplot as plt + coeffs = masks[jdx, :].cpu().numpy() + idx = np.argsort(-np.abs(coeffs)) + # plt.bar(list(range(idx.shape[0])), coeffs[idx]) + # plt.show() + + coeffs_sort = coeffs[idx] + arr_h, arr_w = (4,8) + proto_h, proto_w, _ = proto_data.size() + arr_img = np.zeros([proto_h*arr_h, proto_w*arr_w]) + arr_run = np.zeros([proto_h*arr_h, proto_w*arr_w]) + test = torch.sum(proto_data, -1).cpu().numpy() + + for y in range(arr_h): + for x in range(arr_w): + i = arr_w * y + x + + if i == 0: + running_total = proto_data[:, :, idx[i]].cpu().numpy() * coeffs_sort[i] + else: + running_total += proto_data[:, :, idx[i]].cpu().numpy() * coeffs_sort[i] + + running_total_nonlin = running_total + if cfg.mask_proto_mask_activation == activation_func.sigmoid: + running_total_nonlin = (1/(1+np.exp(-running_total_nonlin))) + + arr_img[y*proto_h:(y+1)*proto_h, x*proto_w:(x+1)*proto_w] = (proto_data[:, :, idx[i]] / torch.max(proto_data[:, :, idx[i]])).cpu().numpy() * coeffs_sort[i] + arr_run[y*proto_h:(y+1)*proto_h, x*proto_w:(x+1)*proto_w] = (running_total_nonlin > 0.5).astype(np.float) + plt.imshow(arr_img) + plt.show() + # plt.imshow(arr_run) + # plt.show() + # plt.imshow(test) + # plt.show() + plt.imshow(out_masks[:, :, jdx].cpu().numpy()) + plt.show() diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/modelzoo_level.txt b/PyTorch/contrib/cv/detection/YOLACT_plus/modelzoo_level.txt index 0bfa93c4ef..59d0003ba8 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/modelzoo_level.txt +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/modelzoo_level.txt @@ -1,6 +1,6 @@ -GPUStatus:OK -NPUMigrationStatus:OK -FuncStatus:OK -PrecisionStatus:OK -AutoTune:POK +GPUStatus:OK +NPUMigrationStatus:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:POK PerfStatus:POK \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/augment_bbox.py b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/augment_bbox.py index 8688f4f280..d823a92822 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/augment_bbox.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/augment_bbox.py @@ -1,184 +1,184 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os.path as osp -import json, pickle -import sys -from math import sqrt -from itertools import product -import torch -from numpy import random - -import numpy as np - - -max_image_size = 550 -augment_idx = 0 -dump_file = 'weights/bboxes_aug.pkl' -box_file = 'weights/bboxes.pkl' - -def augment_boxes(bboxes): - bboxes_rel = [] - for box in bboxes: - bboxes_rel.append(prep_box(box)) - bboxes_rel = np.concatenate(bboxes_rel, axis=0) - - with open(dump_file, 'wb') as f: - pickle.dump(bboxes_rel, f) - -def prep_box(box_list): - global augment_idx - boxes = np.array([box_list[2:]], dtype=np.float32) - - # Image width and height - width, height = box_list[:2] - - # To point form - boxes[:, 2:] += boxes[:, :2] - - - # Expand - ratio = random.uniform(1, 4) - left = random.uniform(0, width*ratio - width) - top = random.uniform(0, height*ratio - height) - - height *= ratio - width *= ratio - - boxes[:, :2] += (int(left), int(top)) - boxes[:, 2:] += (int(left), int(top)) - - - # RandomSampleCrop - height, width, boxes = random_sample_crop(height, width, boxes) - - - # RandomMirror - if random.randint(0, 2): - boxes[:, 0::2] = width - boxes[:, 2::-2] - - - # Resize - boxes[:, [0, 2]] *= (max_image_size / width) - boxes[:, [1, 3]] *= (max_image_size / height) - width = height = max_image_size - - - # ToPercentCoords - boxes[:, [0, 2]] /= width - boxes[:, [1, 3]] /= height - - if augment_idx % 50000 == 0: - print('Current idx: %d' % augment_idx) - - augment_idx += 1 - - return boxes - - - - -sample_options = ( - # using entire original input image - None, - # sample a patch s.t. MIN jaccard w/ obj in .1,.3,.4,.7,.9 - (0.1, None), - (0.3, None), - (0.7, None), - (0.9, None), - # randomly sample a patch - (None, None), -) - -def intersect(box_a, box_b): - max_xy = np.minimum(box_a[:, 2:], box_b[2:]) - min_xy = np.maximum(box_a[:, :2], box_b[:2]) - inter = np.clip((max_xy - min_xy), a_min=0, a_max=np.inf) - return inter[:, 0] * inter[:, 1] - - -def jaccard_numpy(box_a, box_b): - """Compute the jaccard overlap of two sets of boxes. The jaccard overlap - is simply the intersection over union of two boxes. - E.g.: - A ∩ B / A ∪ B = A ∩ B / (area(A) + area(B) - A ∩ B) - Args: - box_a: Multiple bounding boxes, Shape: [num_boxes,4] - box_b: Single bounding box, Shape: [4] - Return: - jaccard overlap: Shape: [box_a.shape[0], box_a.shape[1]] - """ - inter = intersect(box_a, box_b) - area_a = ((box_a[:, 2]-box_a[:, 0]) * - (box_a[:, 3]-box_a[:, 1])) # [A,B] - area_b = ((box_b[2]-box_b[0]) * - (box_b[3]-box_b[1])) # [A,B] - union = area_a + area_b - inter - return inter / union # [A,B] - - -def random_sample_crop(height, width, boxes=None): - global sample_options - - while True: - # randomly choose a mode - mode = random.choice(sample_options) - if mode is None: - return height, width, boxes - - min_iou, max_iou = mode - if min_iou is None: - min_iou = float('-inf') - if max_iou is None: - max_iou = float('inf') - - for _ in range(50): - w = random.uniform(0.3 * width, width) - h = random.uniform(0.3 * height, height) - - if h / w < 0.5 or h / w > 2: - continue - - left = random.uniform(0, width - w) - top = random.uniform(0, height - h) - - rect = np.array([int(left), int(top), int(left+w), int(top+h)]) - overlap = jaccard_numpy(boxes, rect) - if overlap.min() < min_iou and max_iou < overlap.max(): - continue - - centers = (boxes[:, :2] + boxes[:, 2:]) / 2.0 - - m1 = (rect[0] < centers[:, 0]) * (rect[1] < centers[:, 1]) - m2 = (rect[2] > centers[:, 0]) * (rect[3] > centers[:, 1]) - mask = m1 * m2 - - if not mask.any(): - continue - - current_boxes = boxes[mask, :].copy() - current_boxes[:, :2] = np.maximum(current_boxes[:, :2], rect[:2]) - current_boxes[:, :2] -= rect[:2] - current_boxes[:, 2:] = np.minimum(current_boxes[:, 2:], rect[2:]) - current_boxes[:, 2:] -= rect[:2] - - return h, w, current_boxes - - -if __name__ == '__main__': - - with open(box_file, 'rb') as f: - bboxes = pickle.load(f) - - augment_boxes(bboxes) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os.path as osp +import json, pickle +import sys +from math import sqrt +from itertools import product +import torch +from numpy import random + +import numpy as np + + +max_image_size = 550 +augment_idx = 0 +dump_file = 'weights/bboxes_aug.pkl' +box_file = 'weights/bboxes.pkl' + +def augment_boxes(bboxes): + bboxes_rel = [] + for box in bboxes: + bboxes_rel.append(prep_box(box)) + bboxes_rel = np.concatenate(bboxes_rel, axis=0) + + with open(dump_file, 'wb') as f: + pickle.dump(bboxes_rel, f) + +def prep_box(box_list): + global augment_idx + boxes = np.array([box_list[2:]], dtype=np.float32) + + # Image width and height + width, height = box_list[:2] + + # To point form + boxes[:, 2:] += boxes[:, :2] + + + # Expand + ratio = random.uniform(1, 4) + left = random.uniform(0, width*ratio - width) + top = random.uniform(0, height*ratio - height) + + height *= ratio + width *= ratio + + boxes[:, :2] += (int(left), int(top)) + boxes[:, 2:] += (int(left), int(top)) + + + # RandomSampleCrop + height, width, boxes = random_sample_crop(height, width, boxes) + + + # RandomMirror + if random.randint(0, 2): + boxes[:, 0::2] = width - boxes[:, 2::-2] + + + # Resize + boxes[:, [0, 2]] *= (max_image_size / width) + boxes[:, [1, 3]] *= (max_image_size / height) + width = height = max_image_size + + + # ToPercentCoords + boxes[:, [0, 2]] /= width + boxes[:, [1, 3]] /= height + + if augment_idx % 50000 == 0: + print('Current idx: %d' % augment_idx) + + augment_idx += 1 + + return boxes + + + + +sample_options = ( + # using entire original input image + None, + # sample a patch s.t. MIN jaccard w/ obj in .1,.3,.4,.7,.9 + (0.1, None), + (0.3, None), + (0.7, None), + (0.9, None), + # randomly sample a patch + (None, None), +) + +def intersect(box_a, box_b): + max_xy = np.minimum(box_a[:, 2:], box_b[2:]) + min_xy = np.maximum(box_a[:, :2], box_b[:2]) + inter = np.clip((max_xy - min_xy), a_min=0, a_max=np.inf) + return inter[:, 0] * inter[:, 1] + + +def jaccard_numpy(box_a, box_b): + """Compute the jaccard overlap of two sets of boxes. The jaccard overlap + is simply the intersection over union of two boxes. + E.g.: + A ∩ B / A ∪ B = A ∩ B / (area(A) + area(B) - A ∩ B) + Args: + box_a: Multiple bounding boxes, Shape: [num_boxes,4] + box_b: Single bounding box, Shape: [4] + Return: + jaccard overlap: Shape: [box_a.shape[0], box_a.shape[1]] + """ + inter = intersect(box_a, box_b) + area_a = ((box_a[:, 2]-box_a[:, 0]) * + (box_a[:, 3]-box_a[:, 1])) # [A,B] + area_b = ((box_b[2]-box_b[0]) * + (box_b[3]-box_b[1])) # [A,B] + union = area_a + area_b - inter + return inter / union # [A,B] + + +def random_sample_crop(height, width, boxes=None): + global sample_options + + while True: + # randomly choose a mode + mode = random.choice(sample_options) + if mode is None: + return height, width, boxes + + min_iou, max_iou = mode + if min_iou is None: + min_iou = float('-inf') + if max_iou is None: + max_iou = float('inf') + + for _ in range(50): + w = random.uniform(0.3 * width, width) + h = random.uniform(0.3 * height, height) + + if h / w < 0.5 or h / w > 2: + continue + + left = random.uniform(0, width - w) + top = random.uniform(0, height - h) + + rect = np.array([int(left), int(top), int(left+w), int(top+h)]) + overlap = jaccard_numpy(boxes, rect) + if overlap.min() < min_iou and max_iou < overlap.max(): + continue + + centers = (boxes[:, :2] + boxes[:, 2:]) / 2.0 + + m1 = (rect[0] < centers[:, 0]) * (rect[1] < centers[:, 1]) + m2 = (rect[2] > centers[:, 0]) * (rect[3] > centers[:, 1]) + mask = m1 * m2 + + if not mask.any(): + continue + + current_boxes = boxes[mask, :].copy() + current_boxes[:, :2] = np.maximum(current_boxes[:, :2], rect[:2]) + current_boxes[:, :2] -= rect[:2] + current_boxes[:, 2:] = np.minimum(current_boxes[:, 2:], rect[2:]) + current_boxes[:, 2:] -= rect[:2] + + return h, w, current_boxes + + +if __name__ == '__main__': + + with open(box_file, 'rb') as f: + bboxes = pickle.load(f) + + augment_boxes(bboxes) diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/bbox_recall.py b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/bbox_recall.py index b9d2565ff5..3a2745760c 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/bbox_recall.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/bbox_recall.py @@ -1,195 +1,195 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ -""" -This script compiles all the bounding boxes in the training data and -clusters them for each convout resolution on which they're used. - -Run this script from the Yolact root directory. -""" - -import os.path as osp -import json, pickle -import sys -from math import sqrt -from itertools import product -import torch -import random - -import numpy as np - -dump_file = 'weights/bboxes.pkl' -aug_file = 'weights/bboxes_aug.pkl' - -use_augmented_boxes = True - - -def intersect(box_a, box_b): - """ We resize both tensors to [A,B,2] without new malloc: - [A,2] -> [A,1,2] -> [A,B,2] - [B,2] -> [1,B,2] -> [A,B,2] - Then we compute the area of intersect between box_a and box_b. - Args: - box_a: (tensor) bounding boxes, Shape: [A,4]. - box_b: (tensor) bounding boxes, Shape: [B,4]. - Return: - (tensor) intersection area, Shape: [A,B]. - """ - A = box_a.size(0) - B = box_b.size(0) - max_xy = torch.min(box_a[:, 2:].unsqueeze(1).expand(A, B, 2), - box_b[:, 2:].unsqueeze(0).expand(A, B, 2)) - min_xy = torch.max(box_a[:, :2].unsqueeze(1).expand(A, B, 2), - box_b[:, :2].unsqueeze(0).expand(A, B, 2)) - inter = torch.clamp((max_xy - min_xy), min=0) - return inter[:, :, 0] * inter[:, :, 1] - - -def jaccard(box_a, box_b, iscrowd=False): - """Compute the jaccard overlap of two sets of boxes. The jaccard overlap - is simply the intersection over union of two boxes. Here we operate on - ground truth boxes and default boxes. If iscrowd=True, put the crowd in box_b. - E.g.: - A ∩ B / A ∪ B = A ∩ B / (area(A) + area(B) - A ∩ B) - Args: - box_a: (tensor) Ground truth bounding boxes, Shape: [num_objects,4] - box_b: (tensor) Prior boxes from priorbox layers, Shape: [num_priors,4] - Return: - jaccard overlap: (tensor) Shape: [box_a.size(0), box_b.size(0)] - """ - inter = intersect(box_a, box_b) - area_a = ((box_a[:, 2]-box_a[:, 0]) * - (box_a[:, 3]-box_a[:, 1])).unsqueeze(1).expand_as(inter) # [A,B] - area_b = ((box_b[:, 2]-box_b[:, 0]) * - (box_b[:, 3]-box_b[:, 1])).unsqueeze(0).expand_as(inter) # [A,B] - union = area_a + area_b - inter - - if iscrowd: - return inter / area_a - else: - return inter / union # [A,B] - -# Also convert to point form -def to_relative(bboxes): - return np.concatenate((bboxes[:, 2:4] / bboxes[:, :2], (bboxes[:, 2:4] + bboxes[:, 4:]) / bboxes[:, :2]), axis=1) - - -def make_priors(conv_size, scales, aspect_ratios): - prior_data = [] - conv_h = conv_size[0] - conv_w = conv_size[1] - - # Iteration order is important (it has to sync up with the convout) - for j, i in product(range(conv_h), range(conv_w)): - x = (i + 0.5) / conv_w - y = (j + 0.5) / conv_h - - for scale, ars in zip(scales, aspect_ratios): - for ar in ars: - w = scale * ar / conv_w - h = scale / ar / conv_h - - # Point form - prior_data += [x - w/2, y - h/2, x + w/2, y + h/2] - - return np.array(prior_data).reshape(-1, 4) - -# fixed_ssd_config -# scales = [[3.5, 4.95], [3.6, 4.90], [3.3, 4.02], [2.7, 3.10], [2.1, 2.37], [2.1, 2.37], [1.8, 1.92]] -# aspect_ratios = [ [[1, sqrt(2), 1/sqrt(2), sqrt(3), 1/sqrt(3)][:n], [1]] for n in [3, 5, 5, 5, 3, 3, 3] ] -# conv_sizes = [(35, 35), (18, 18), (9, 9), (5, 5), (3, 3), (2, 2)] - -scales = [[1.68, 2.91], - [2.95, 2.22, 0.84], - [2.23, 2.17, 3.12], - [0.76, 1.94, 2.72], - [2.10, 2.65], - [1.80, 1.92]] -aspect_ratios = [[[0.72, 0.96], [0.68, 1.17]], - [[1.28, 0.66], [0.63, 1.23], [0.89, 1.40]], - [[2.05, 1.24], [0.57, 0.83], [0.61, 1.15]], - [[1.00, 2.21], [0.47, 1.60], [1.44, 0.79]], - [[1.00, 1.41, 0.71, 1.73, 0.58], [1.08]], - [[1.00, 1.41, 0.71, 1.73, 0.58], [1.00]]] -conv_sizes = [(35, 35), (18, 18), (9, 9), (5, 5), (3, 3), (2, 2)] - -# yrm33_config -# scales = [ [5.3] ] * 5 -# aspect_ratios = [ [[1, 1/sqrt(2), sqrt(2)]] ]*5 -# conv_sizes = [(136, 136), (67, 67), (33, 33), (16, 16), (8, 8)] - - -SMALL = 0 -MEDIUM = 1 -LARGE = 2 - -if __name__ == '__main__': - - with open(dump_file, 'rb') as f: - bboxes = pickle.load(f) - - sizes = [] - smalls = [] - for i in range(len(bboxes)): - area = bboxes[i][4] * bboxes[i][5] - if area < 32 ** 2: - sizes.append(SMALL) - smalls.append(area) - elif area < 96 ** 2: - sizes.append(MEDIUM) - else: - sizes.append(LARGE) - - # Each box is in the form [im_w, im_h, pos_x, pos_y, size_x, size_y] - - if use_augmented_boxes: - with open(aug_file, 'rb') as f: - bboxes_rel = pickle.load(f) - else: - bboxes_rel = to_relative(np.array(bboxes)) - - - with torch.no_grad(): - sizes = torch.Tensor(sizes) - - anchors = [make_priors(cs, s, ar) for cs, s, ar in zip(conv_sizes, scales, aspect_ratios)] - anchors = np.concatenate(anchors, axis=0) - anchors = torch.Tensor(anchors).cuda() - - bboxes_rel = torch.Tensor(bboxes_rel).cuda() - perGTAnchorMax = torch.zeros(bboxes_rel.shape[0]).cuda() - - chunk_size = 1000 - for i in range((bboxes_rel.size(0) // chunk_size) + 1): - start = i * chunk_size - end = min((i + 1) * chunk_size, bboxes_rel.size(0)) - - ious = jaccard(bboxes_rel[start:end, :], anchors) - maxes, maxidx = torch.max(ious, dim=1) - - perGTAnchorMax[start:end] = maxes - - - hits = (perGTAnchorMax > 0.5).float() - - print('Total recall: %.2f' % (torch.sum(hits) / hits.size(0) * 100)) - print() - - for i, metric in zip(range(3), ('small', 'medium', 'large')): - _hits = hits[sizes == i] - _size = (1 if _hits.size(0) == 0 else _hits.size(0)) - print(metric + ' recall: %.2f' % ((torch.sum(_hits) / _size) * 100)) - - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +""" +This script compiles all the bounding boxes in the training data and +clusters them for each convout resolution on which they're used. + +Run this script from the Yolact root directory. +""" + +import os.path as osp +import json, pickle +import sys +from math import sqrt +from itertools import product +import torch +import random + +import numpy as np + +dump_file = 'weights/bboxes.pkl' +aug_file = 'weights/bboxes_aug.pkl' + +use_augmented_boxes = True + + +def intersect(box_a, box_b): + """ We resize both tensors to [A,B,2] without new malloc: + [A,2] -> [A,1,2] -> [A,B,2] + [B,2] -> [1,B,2] -> [A,B,2] + Then we compute the area of intersect between box_a and box_b. + Args: + box_a: (tensor) bounding boxes, Shape: [A,4]. + box_b: (tensor) bounding boxes, Shape: [B,4]. + Return: + (tensor) intersection area, Shape: [A,B]. + """ + A = box_a.size(0) + B = box_b.size(0) + max_xy = torch.min(box_a[:, 2:].unsqueeze(1).expand(A, B, 2), + box_b[:, 2:].unsqueeze(0).expand(A, B, 2)) + min_xy = torch.max(box_a[:, :2].unsqueeze(1).expand(A, B, 2), + box_b[:, :2].unsqueeze(0).expand(A, B, 2)) + inter = torch.clamp((max_xy - min_xy), min=0) + return inter[:, :, 0] * inter[:, :, 1] + + +def jaccard(box_a, box_b, iscrowd=False): + """Compute the jaccard overlap of two sets of boxes. The jaccard overlap + is simply the intersection over union of two boxes. Here we operate on + ground truth boxes and default boxes. If iscrowd=True, put the crowd in box_b. + E.g.: + A ∩ B / A ∪ B = A ∩ B / (area(A) + area(B) - A ∩ B) + Args: + box_a: (tensor) Ground truth bounding boxes, Shape: [num_objects,4] + box_b: (tensor) Prior boxes from priorbox layers, Shape: [num_priors,4] + Return: + jaccard overlap: (tensor) Shape: [box_a.size(0), box_b.size(0)] + """ + inter = intersect(box_a, box_b) + area_a = ((box_a[:, 2]-box_a[:, 0]) * + (box_a[:, 3]-box_a[:, 1])).unsqueeze(1).expand_as(inter) # [A,B] + area_b = ((box_b[:, 2]-box_b[:, 0]) * + (box_b[:, 3]-box_b[:, 1])).unsqueeze(0).expand_as(inter) # [A,B] + union = area_a + area_b - inter + + if iscrowd: + return inter / area_a + else: + return inter / union # [A,B] + +# Also convert to point form +def to_relative(bboxes): + return np.concatenate((bboxes[:, 2:4] / bboxes[:, :2], (bboxes[:, 2:4] + bboxes[:, 4:]) / bboxes[:, :2]), axis=1) + + +def make_priors(conv_size, scales, aspect_ratios): + prior_data = [] + conv_h = conv_size[0] + conv_w = conv_size[1] + + # Iteration order is important (it has to sync up with the convout) + for j, i in product(range(conv_h), range(conv_w)): + x = (i + 0.5) / conv_w + y = (j + 0.5) / conv_h + + for scale, ars in zip(scales, aspect_ratios): + for ar in ars: + w = scale * ar / conv_w + h = scale / ar / conv_h + + # Point form + prior_data += [x - w/2, y - h/2, x + w/2, y + h/2] + + return np.array(prior_data).reshape(-1, 4) + +# fixed_ssd_config +# scales = [[3.5, 4.95], [3.6, 4.90], [3.3, 4.02], [2.7, 3.10], [2.1, 2.37], [2.1, 2.37], [1.8, 1.92]] +# aspect_ratios = [ [[1, sqrt(2), 1/sqrt(2), sqrt(3), 1/sqrt(3)][:n], [1]] for n in [3, 5, 5, 5, 3, 3, 3] ] +# conv_sizes = [(35, 35), (18, 18), (9, 9), (5, 5), (3, 3), (2, 2)] + +scales = [[1.68, 2.91], + [2.95, 2.22, 0.84], + [2.23, 2.17, 3.12], + [0.76, 1.94, 2.72], + [2.10, 2.65], + [1.80, 1.92]] +aspect_ratios = [[[0.72, 0.96], [0.68, 1.17]], + [[1.28, 0.66], [0.63, 1.23], [0.89, 1.40]], + [[2.05, 1.24], [0.57, 0.83], [0.61, 1.15]], + [[1.00, 2.21], [0.47, 1.60], [1.44, 0.79]], + [[1.00, 1.41, 0.71, 1.73, 0.58], [1.08]], + [[1.00, 1.41, 0.71, 1.73, 0.58], [1.00]]] +conv_sizes = [(35, 35), (18, 18), (9, 9), (5, 5), (3, 3), (2, 2)] + +# yrm33_config +# scales = [ [5.3] ] * 5 +# aspect_ratios = [ [[1, 1/sqrt(2), sqrt(2)]] ]*5 +# conv_sizes = [(136, 136), (67, 67), (33, 33), (16, 16), (8, 8)] + + +SMALL = 0 +MEDIUM = 1 +LARGE = 2 + +if __name__ == '__main__': + + with open(dump_file, 'rb') as f: + bboxes = pickle.load(f) + + sizes = [] + smalls = [] + for i in range(len(bboxes)): + area = bboxes[i][4] * bboxes[i][5] + if area < 32 ** 2: + sizes.append(SMALL) + smalls.append(area) + elif area < 96 ** 2: + sizes.append(MEDIUM) + else: + sizes.append(LARGE) + + # Each box is in the form [im_w, im_h, pos_x, pos_y, size_x, size_y] + + if use_augmented_boxes: + with open(aug_file, 'rb') as f: + bboxes_rel = pickle.load(f) + else: + bboxes_rel = to_relative(np.array(bboxes)) + + + with torch.no_grad(): + sizes = torch.Tensor(sizes) + + anchors = [make_priors(cs, s, ar) for cs, s, ar in zip(conv_sizes, scales, aspect_ratios)] + anchors = np.concatenate(anchors, axis=0) + anchors = torch.Tensor(anchors).cuda() + + bboxes_rel = torch.Tensor(bboxes_rel).cuda() + perGTAnchorMax = torch.zeros(bboxes_rel.shape[0]).cuda() + + chunk_size = 1000 + for i in range((bboxes_rel.size(0) // chunk_size) + 1): + start = i * chunk_size + end = min((i + 1) * chunk_size, bboxes_rel.size(0)) + + ious = jaccard(bboxes_rel[start:end, :], anchors) + maxes, maxidx = torch.max(ious, dim=1) + + perGTAnchorMax[start:end] = maxes + + + hits = (perGTAnchorMax > 0.5).float() + + print('Total recall: %.2f' % (torch.sum(hits) / hits.size(0) * 100)) + print() + + for i, metric in zip(range(3), ('small', 'medium', 'large')): + _hits = hits[sizes == i] + _size = (1 if _hits.size(0) == 0 else _hits.size(0)) + print(metric + ' recall: %.2f' % ((torch.sum(_hits) / _size) * 100)) + + + diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/cluster_bbox_sizes.py b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/cluster_bbox_sizes.py index 95ba75de62..e1ad776af2 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/cluster_bbox_sizes.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/cluster_bbox_sizes.py @@ -1,83 +1,83 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ -""" -This script compiles all the bounding boxes in the training data and -clusters them for each convout resolution on which they're used. - -Run this script from the Yolact root directory. -""" - -import os.path as osp -import json, pickle -import sys - -import numpy as np -import sklearn.cluster as cluster - -dump_file = 'weights/bboxes.pkl' -max_size = 550 - -num_scale_clusters = 5 -num_aspect_ratio_clusters = 3 - -def to_relative(bboxes): - return bboxes[:, 2:4] / bboxes[:, :2] - -def process(bboxes): - return to_relative(bboxes) * max_size - -if __name__ == '__main__': - - with open(dump_file, 'rb') as f: - bboxes = pickle.load(f) - - bboxes = np.array(bboxes) - bboxes = process(bboxes) - bboxes = bboxes[(bboxes[:, 0] > 1) * (bboxes[:, 1] > 1)] - - scale = np.sqrt(bboxes[:, 0] * bboxes[:, 1]).reshape(-1, 1) - - clusterer = cluster.KMeans(num_scale_clusters, random_state=99, n_jobs=4) - assignments = clusterer.fit_predict(scale) - counts = np.bincount(assignments) - - cluster_centers = clusterer.cluster_centers_ - - center_indices = list(range(num_scale_clusters)) - center_indices.sort(key=lambda x: cluster_centers[x, 0]) - - for idx in center_indices: - center = cluster_centers[idx, 0] - boxes_for_center = bboxes[assignments == idx] - aspect_ratios = (boxes_for_center[:,0] / boxes_for_center[:,1]).reshape(-1, 1) - - c = cluster.KMeans(num_aspect_ratio_clusters, random_state=idx, n_jobs=4) - ca = c.fit_predict(aspect_ratios) - cc = np.bincount(ca) - - c = list(c.cluster_centers_.reshape(-1)) - cidx = list(range(num_aspect_ratio_clusters)) - cidx.sort(key=lambda x: -cc[x]) - - # import code - # code.interact(local=locals()) - - print('%.3f (%d) aspect ratios:' % (center, counts[idx])) - for idx in cidx: - print('\t%.2f (%d)' % (c[idx], cc[idx])) - print() - # exit() - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +""" +This script compiles all the bounding boxes in the training data and +clusters them for each convout resolution on which they're used. + +Run this script from the Yolact root directory. +""" + +import os.path as osp +import json, pickle +import sys + +import numpy as np +import sklearn.cluster as cluster + +dump_file = 'weights/bboxes.pkl' +max_size = 550 + +num_scale_clusters = 5 +num_aspect_ratio_clusters = 3 + +def to_relative(bboxes): + return bboxes[:, 2:4] / bboxes[:, :2] + +def process(bboxes): + return to_relative(bboxes) * max_size + +if __name__ == '__main__': + + with open(dump_file, 'rb') as f: + bboxes = pickle.load(f) + + bboxes = np.array(bboxes) + bboxes = process(bboxes) + bboxes = bboxes[(bboxes[:, 0] > 1) * (bboxes[:, 1] > 1)] + + scale = np.sqrt(bboxes[:, 0] * bboxes[:, 1]).reshape(-1, 1) + + clusterer = cluster.KMeans(num_scale_clusters, random_state=99, n_jobs=4) + assignments = clusterer.fit_predict(scale) + counts = np.bincount(assignments) + + cluster_centers = clusterer.cluster_centers_ + + center_indices = list(range(num_scale_clusters)) + center_indices.sort(key=lambda x: cluster_centers[x, 0]) + + for idx in center_indices: + center = cluster_centers[idx, 0] + boxes_for_center = bboxes[assignments == idx] + aspect_ratios = (boxes_for_center[:,0] / boxes_for_center[:,1]).reshape(-1, 1) + + c = cluster.KMeans(num_aspect_ratio_clusters, random_state=idx, n_jobs=4) + ca = c.fit_predict(aspect_ratios) + cc = np.bincount(ca) + + c = list(c.cluster_centers_.reshape(-1)) + cidx = list(range(num_aspect_ratio_clusters)) + cidx.sort(key=lambda x: -cc[x]) + + # import code + # code.interact(local=locals()) + + print('%.3f (%d) aspect ratios:' % (center, counts[idx])) + for idx in cidx: + print('\t%.2f (%d)' % (c[idx], cc[idx])) + print() + # exit() + + diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/compute_masks.py b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/compute_masks.py index b483583958..4153ccd48e 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/compute_masks.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/compute_masks.py @@ -1,108 +1,108 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 numpy as np -import matplotlib.pyplot as plt -import cv2 -import torch -import torch.nn.functional as F - -COLORS = ((255, 0, 0, 128), (0, 255, 0, 128), (0, 0, 255, 128), - (0, 255, 255, 128), (255, 0, 255, 128), (255, 255, 0, 128)) - -def mask_iou(mask1, mask2): - """ - Inputs inputs are matricies of size _ x N. Output is size _1 x _2. - Note: if iscrowd is True, then mask2 should be the crowd. - """ - intersection = torch.matmul(mask1, mask2.t()) - area1 = torch.sum(mask1, dim=1).view(1, -1) - area2 = torch.sum(mask2, dim=1).view(1, -1) - union = (area1.t() + area2) - intersection - - return intersection / union - -def paint_mask(img_numpy, mask, color): - h, w, _ = img_numpy.shape - img_numpy = img_numpy.copy() - - mask = np.tile(mask.reshape(h, w, 1), (1, 1, 3)) - color_np = np.array(color[:3]).reshape(1, 1, 3) - color_np = np.tile(color_np, (h, w, 1)) - mask_color = mask * color_np - - mask_alpha = 0.3 - - # Blend image and mask - image_crop = img_numpy * mask - img_numpy *= (1-mask) - img_numpy += image_crop * (1-mask_alpha) + mask_color * mask_alpha - - return img_numpy - -# Inverse sigmoid -def logit(x): - return np.log(x / (1-x + 0.0001) + 0.0001) - -def sigmoid(x): - return 1 / (1 + np.exp(-x)) - -img_fmt = '../data/coco/images/%012d.jpg' -with open('info.txt', 'r') as f: - img_id = int(f.read()) - -img = plt.imread(img_fmt % img_id).astype(np.float32) -h, w, _ = img.shape - -gt_masks = np.load('gt.npy').astype(np.float32).transpose(1, 2, 0) -proto_masks = np.load('proto.npy').astype(np.float32) - -proto_masks = torch.Tensor(proto_masks).permute(2, 0, 1).contiguous().unsqueeze(0) -proto_masks = F.interpolate(proto_masks, (h, w), mode='bilinear', align_corners=False).squeeze(0) -proto_masks = proto_masks.permute(1, 2, 0).numpy() - -# # A x = b -ls_A = proto_masks.reshape(-1, proto_masks.shape[-1]) -ls_b = gt_masks.reshape(-1, gt_masks.shape[-1]) - -# x is size [256, num_gt] -x = np.linalg.lstsq(ls_A, ls_b, rcond=None)[0] - -approximated_masks = (np.matmul(proto_masks, x) > 0.5).astype(np.float32) - -num_gt = approximated_masks.shape[2] -ious = mask_iou(torch.Tensor(approximated_masks.reshape(-1, num_gt).T), - torch.Tensor(gt_masks.reshape(-1, num_gt).T)) - -ious = [int(ious[i, i].item() * 100) for i in range(num_gt)] -ious.sort(key=lambda x: -x) - -print(ious) - -gt_img = img.copy() - -for i in range(num_gt): - gt_img = paint_mask(gt_img, gt_masks[:, :, i], COLORS[i % len(COLORS)]) - -plt.imshow(gt_img / 255) -plt.title('GT') -plt.show() - -for i in range(num_gt): - img = paint_mask(img, approximated_masks[:, :, i], COLORS[i % len(COLORS)]) - -plt.imshow(img / 255) -plt.title('Approximated') -plt.show() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 numpy as np +import matplotlib.pyplot as plt +import cv2 +import torch +import torch.nn.functional as F + +COLORS = ((255, 0, 0, 128), (0, 255, 0, 128), (0, 0, 255, 128), + (0, 255, 255, 128), (255, 0, 255, 128), (255, 255, 0, 128)) + +def mask_iou(mask1, mask2): + """ + Inputs inputs are matricies of size _ x N. Output is size _1 x _2. + Note: if iscrowd is True, then mask2 should be the crowd. + """ + intersection = torch.matmul(mask1, mask2.t()) + area1 = torch.sum(mask1, dim=1).view(1, -1) + area2 = torch.sum(mask2, dim=1).view(1, -1) + union = (area1.t() + area2) - intersection + + return intersection / union + +def paint_mask(img_numpy, mask, color): + h, w, _ = img_numpy.shape + img_numpy = img_numpy.copy() + + mask = np.tile(mask.reshape(h, w, 1), (1, 1, 3)) + color_np = np.array(color[:3]).reshape(1, 1, 3) + color_np = np.tile(color_np, (h, w, 1)) + mask_color = mask * color_np + + mask_alpha = 0.3 + + # Blend image and mask + image_crop = img_numpy * mask + img_numpy *= (1-mask) + img_numpy += image_crop * (1-mask_alpha) + mask_color * mask_alpha + + return img_numpy + +# Inverse sigmoid +def logit(x): + return np.log(x / (1-x + 0.0001) + 0.0001) + +def sigmoid(x): + return 1 / (1 + np.exp(-x)) + +img_fmt = '../data/coco/images/%012d.jpg' +with open('info.txt', 'r') as f: + img_id = int(f.read()) + +img = plt.imread(img_fmt % img_id).astype(np.float32) +h, w, _ = img.shape + +gt_masks = np.load('gt.npy').astype(np.float32).transpose(1, 2, 0) +proto_masks = np.load('proto.npy').astype(np.float32) + +proto_masks = torch.Tensor(proto_masks).permute(2, 0, 1).contiguous().unsqueeze(0) +proto_masks = F.interpolate(proto_masks, (h, w), mode='bilinear', align_corners=False).squeeze(0) +proto_masks = proto_masks.permute(1, 2, 0).numpy() + +# # A x = b +ls_A = proto_masks.reshape(-1, proto_masks.shape[-1]) +ls_b = gt_masks.reshape(-1, gt_masks.shape[-1]) + +# x is size [256, num_gt] +x = np.linalg.lstsq(ls_A, ls_b, rcond=None)[0] + +approximated_masks = (np.matmul(proto_masks, x) > 0.5).astype(np.float32) + +num_gt = approximated_masks.shape[2] +ious = mask_iou(torch.Tensor(approximated_masks.reshape(-1, num_gt).T), + torch.Tensor(gt_masks.reshape(-1, num_gt).T)) + +ious = [int(ious[i, i].item() * 100) for i in range(num_gt)] +ious.sort(key=lambda x: -x) + +print(ious) + +gt_img = img.copy() + +for i in range(num_gt): + gt_img = paint_mask(gt_img, gt_masks[:, :, i], COLORS[i % len(COLORS)]) + +plt.imshow(gt_img / 255) +plt.title('GT') +plt.show() + +for i in range(num_gt): + img = paint_mask(img, approximated_masks[:, :, i], COLORS[i % len(COLORS)]) + +plt.imshow(img / 255) +plt.title('Approximated') +plt.show() diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/convert_darknet.py b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/convert_darknet.py index 1c2c40f125..d68d59f96a 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/convert_darknet.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/convert_darknet.py @@ -1,63 +1,63 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 backbone import DarkNetBackbone -import h5py -import torch - -f = h5py.File('darknet53.h5', 'r') -m = f['model_weights'] - -yolo_keys = list(m.keys()) -yolo_keys = [x for x in yolo_keys if len(m[x].keys()) > 0] -yolo_keys.sort() - -sd = DarkNetBackbone().state_dict() - -sd_keys = list(sd.keys()) -sd_keys.sort() - -# Note this won't work if there are 10 elements in some list but whatever that doesn't happen -layer_keys = list(set(['.'.join(x.split('.')[:-2]) for x in sd_keys])) -layer_keys.sort() - -# print([x for x in sd_keys if x.startswith(layer_keys[0])]) - -mapping = { - '.0.weight' : ('conv2d_%d', 'kernel:0'), - '.1.bias' : ('batch_normalization_%d', 'beta:0'), - '.1.weight' : ('batch_normalization_%d', 'gamma:0'), - '.1.running_var' : ('batch_normalization_%d', 'moving_variance:0'), - '.1.running_mean': ('batch_normalization_%d', 'moving_mean:0'), - '.1.num_batches_tracked': None, -} - -for i, layer_key in zip(range(1, len(layer_keys) + 1), layer_keys): - # This is pretty inefficient but I don't care - for weight_key in [x for x in sd_keys if x.startswith(layer_key)]: - diff = weight_key[len(layer_key):] - - if mapping[diff] is not None: - yolo_key = mapping[diff][0] % i - sub_key = mapping[diff][1] - - yolo_weight = torch.Tensor(m[yolo_key][yolo_key][sub_key].value) - if (len(yolo_weight.size()) == 4): - yolo_weight = yolo_weight.permute(3, 2, 0, 1).contiguous() - - sd[weight_key] = yolo_weight - -torch.save(sd, 'weights/darknet53.pth') - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 backbone import DarkNetBackbone +import h5py +import torch + +f = h5py.File('darknet53.h5', 'r') +m = f['model_weights'] + +yolo_keys = list(m.keys()) +yolo_keys = [x for x in yolo_keys if len(m[x].keys()) > 0] +yolo_keys.sort() + +sd = DarkNetBackbone().state_dict() + +sd_keys = list(sd.keys()) +sd_keys.sort() + +# Note this won't work if there are 10 elements in some list but whatever that doesn't happen +layer_keys = list(set(['.'.join(x.split('.')[:-2]) for x in sd_keys])) +layer_keys.sort() + +# print([x for x in sd_keys if x.startswith(layer_keys[0])]) + +mapping = { + '.0.weight' : ('conv2d_%d', 'kernel:0'), + '.1.bias' : ('batch_normalization_%d', 'beta:0'), + '.1.weight' : ('batch_normalization_%d', 'gamma:0'), + '.1.running_var' : ('batch_normalization_%d', 'moving_variance:0'), + '.1.running_mean': ('batch_normalization_%d', 'moving_mean:0'), + '.1.num_batches_tracked': None, +} + +for i, layer_key in zip(range(1, len(layer_keys) + 1), layer_keys): + # This is pretty inefficient but I don't care + for weight_key in [x for x in sd_keys if x.startswith(layer_key)]: + diff = weight_key[len(layer_key):] + + if mapping[diff] is not None: + yolo_key = mapping[diff][0] % i + sub_key = mapping[diff][1] + + yolo_weight = torch.Tensor(m[yolo_key][yolo_key][sub_key].value) + if (len(yolo_weight.size()) == 4): + yolo_weight = yolo_weight.permute(3, 2, 0, 1).contiguous() + + sd[weight_key] = yolo_weight + +torch.save(sd, 'weights/darknet53.pth') + diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/convert_sbd.py b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/convert_sbd.py index a1c940061a..61f049a366 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/convert_sbd.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/convert_sbd.py @@ -1,88 +1,88 @@ -import scipy.io, scipy.ndimage -import os.path, json -import pycocotools.mask -import numpy as np - -def mask2bbox(mask): - rows = np.any(mask, axis=1) - cols = np.any(mask, axis=0) - rmin, rmax = np.where(rows)[0][[0, -1]] - cmin, cmax = np.where(cols)[0][[0, -1]] - - return cmin, rmin, cmax - cmin, rmax - rmin - - - -inst_path = './inst/' -img_path = './img/' -img_name_fmt = '%s.jpg' -ann_name_fmt = '%s.mat' - -image_id = 1 -ann_id = 1 - -types = ['train', 'val'] - -for t in types: - with open('%s.txt' % t, 'r') as f: - names = f.read().strip().split('\n') - - images = [] - annotations = [] - - for name in names: - img_name = img_name_fmt % name - - ann_path = os.path.join(inst_path, ann_name_fmt % name) - ann = scipy.io.loadmat(ann_path)['GTinst'][0][0] - - classes = [int(x[0]) for x in ann[2]] - seg = ann[0] - - for idx in range(len(classes)): - mask = (seg == (idx + 1)).astype(np.float) - - rle = pycocotools.mask.encode(np.asfortranarray(mask.astype(np.uint8))) - rle['counts'] = rle['counts'].decode('ascii') - - annotations.append({ - 'id': ann_id, - 'image_id': image_id, - 'category_id': classes[idx], - 'segmentation': rle, - 'area': float(mask.sum()), - 'bbox': [int(x) for x in mask2bbox(mask)], - 'iscrowd': 0 - }) - - ann_id += 1 - - img_name = img_name_fmt % name - img = scipy.ndimage.imread(os.path.join(img_path, img_name)) - - images.append({ - 'id': image_id, - 'width': img.shape[1], - 'height': img.shape[0], - 'file_name': img_name - }) - - image_id += 1 - - info = { - 'year': 2012, - 'version': 1, - 'description': 'Pascal SBD', - } - - categories = [{'id': x+1} for x in range(20)] - - with open('pascal_sbd_%s.json' % t, 'w') as f: - json.dump({ - 'info': info, - 'images': images, - 'annotations': annotations, - 'licenses': {}, - 'categories': categories - }, f) - +import scipy.io, scipy.ndimage +import os.path, json +import pycocotools.mask +import numpy as np + +def mask2bbox(mask): + rows = np.any(mask, axis=1) + cols = np.any(mask, axis=0) + rmin, rmax = np.where(rows)[0][[0, -1]] + cmin, cmax = np.where(cols)[0][[0, -1]] + + return cmin, rmin, cmax - cmin, rmax - rmin + + + +inst_path = './inst/' +img_path = './img/' +img_name_fmt = '%s.jpg' +ann_name_fmt = '%s.mat' + +image_id = 1 +ann_id = 1 + +types = ['train', 'val'] + +for t in types: + with open('%s.txt' % t, 'r') as f: + names = f.read().strip().split('\n') + + images = [] + annotations = [] + + for name in names: + img_name = img_name_fmt % name + + ann_path = os.path.join(inst_path, ann_name_fmt % name) + ann = scipy.io.loadmat(ann_path)['GTinst'][0][0] + + classes = [int(x[0]) for x in ann[2]] + seg = ann[0] + + for idx in range(len(classes)): + mask = (seg == (idx + 1)).astype(np.float) + + rle = pycocotools.mask.encode(np.asfortranarray(mask.astype(np.uint8))) + rle['counts'] = rle['counts'].decode('ascii') + + annotations.append({ + 'id': ann_id, + 'image_id': image_id, + 'category_id': classes[idx], + 'segmentation': rle, + 'area': float(mask.sum()), + 'bbox': [int(x) for x in mask2bbox(mask)], + 'iscrowd': 0 + }) + + ann_id += 1 + + img_name = img_name_fmt % name + img = scipy.ndimage.imread(os.path.join(img_path, img_name)) + + images.append({ + 'id': image_id, + 'width': img.shape[1], + 'height': img.shape[0], + 'file_name': img_name + }) + + image_id += 1 + + info = { + 'year': 2012, + 'version': 1, + 'description': 'Pascal SBD', + } + + categories = [{'id': x+1} for x in range(20)] + + with open('pascal_sbd_%s.json' % t, 'w') as f: + json.dump({ + 'info': info, + 'images': images, + 'annotations': annotations, + 'licenses': {}, + 'categories': categories + }, f) + diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/eval.sh b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/eval.sh index c038b91094..fbd5a429dd 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/eval.sh +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/eval.sh @@ -1,14 +1,14 @@ -#!/bin/bash -#SBATCH -p GPU-small -#SBATCH -t 2:00:00 -#SBATCH --gres=gpu:p100:1 -#SBATCH --no-requeue - -# Usage: ./eval.sh weights extra_args - -module load python/3.6.4_gcc5_np1.14.5 -module load cuda/9.0 - -cd $SCRATCH/yolact - -python3 eval.py --trained_model=$1 --no_bar $2 > logs/eval/$(basename -- $1).log 2>&1 +#!/bin/bash +#SBATCH -p GPU-small +#SBATCH -t 2:00:00 +#SBATCH --gres=gpu:p100:1 +#SBATCH --no-requeue + +# Usage: ./eval.sh weights extra_args + +module load python/3.6.4_gcc5_np1.14.5 +module load cuda/9.0 + +cd $SCRATCH/yolact + +python3 eval.py --trained_model=$1 --no_bar $2 > logs/eval/$(basename -- $1).log 2>&1 diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/make_grid.py b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/make_grid.py index fd24ca8120..4039e106c3 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/make_grid.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/make_grid.py @@ -1,218 +1,218 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 numpy as np -import math, random - -import matplotlib.pyplot as plt -from matplotlib.widgets import Slider, Button - - -fig, ax = plt.subplots() -plt.subplots_adjust(bottom=0.24) -im_handle = None - -save_path = 'grid.npy' - -center_x, center_y = (0.5, 0.5) -grid_w, grid_h = (35, 35) -spacing = 0 -scale = 4 -angle = 0 -grid = None - -all_grids = [] -unique = False - -# A hack -disable_render = False - -def render(): - if disable_render: - return - - x = np.tile(np.array(list(range(grid_w)), dtype=np.float).reshape(1, grid_w), [grid_h, 1]) - grid_w * center_x - y = np.tile(np.array(list(range(grid_h)), dtype=np.float).reshape(grid_h, 1), [1, grid_w]) - grid_h * center_y - - x /= scale - y /= scale - - a1 = angle + math.pi / 3 - a2 = -angle + math.pi / 3 - a3 = angle - - z1 = x * math.sin(a1) + y * math.cos(a1) - z2 = x * math.sin(a2) - y * math.cos(a2) - z3 = x * math.sin(a3) + y * math.cos(a3) - - s1 = np.square(np.sin(z1)) - s2 = np.square(np.sin(z2)) - s3 = np.square(np.sin(z3)) - - line_1 = np.exp(s1 * spacing) * s1 - line_2 = np.exp(s2 * spacing) * s2 - line_3 = np.exp(s3 * spacing) * s3 - - global grid - grid = np.clip(1 - (line_1 + line_2 + line_3) / 3, 0, 1) - - global im_handle - if im_handle is None: - im_handle = plt.imshow(grid) - else: - im_handle.set_data(grid) - fig.canvas.draw_idle() - -def update_scale(val): - global scale - scale = val - - render() - -def update_angle(val): - global angle - angle = val - - render() - -def update_centerx(val): - global center_x - center_x = val - - render() - -def update_centery(val): - global center_y - center_y = val - - render() - -def update_spacing(val): - global spacing - spacing = val - - render() - -def randomize(val): - global center_x, center_y, spacing, scale, angle, disable_render - - center_x, center_y = (random.uniform(0, 1), random.uniform(0, 1)) - spacing = random.uniform(-0.2, 2) - scale = 4 * math.exp(random.uniform(-1, 1)) - angle = random.uniform(-math.pi, math.pi) - - disable_render = True - - scale_slider.set_val(scale) - angle_slider.set_val(angle) - centx_slider.set_val(center_x) - centy_slider.set_val(center_y) - spaci_slider.set_val(spacing) - - disable_render = False - - render() - -def add(val): - all_grids.append(grid) - - global unique - if not unique: - unique = test_uniqueness(np.stack(all_grids)) - - export_len_text.set_text('Num Grids: ' + str(len(all_grids))) - fig.canvas.draw_idle() - -def add_randomize(val): - add(val) - randomize(val) - -def export(val): - np.save(save_path, np.stack(all_grids)) - print('Saved %d grids to "%s"' % (len(all_grids), save_path)) - - global unique - unique = False - all_grids.clear() - - export_len_text.set_text('Num Grids: ' + str(len(all_grids))) - fig.canvas.draw_idle() - -def test_uniqueness(grids): - # Grids shape [ngrids, h, w] - grids = grids.reshape((-1, grid_h, grid_w)) - - for y in range(grid_h): - for x in range(grid_h): - pixel_features = grids[:, y, x] - - # l1 distance for this pixel with every other - l1_dist = np.sum(np.abs(grids - np.tile(pixel_features, grid_h*grid_w).reshape((-1, grid_h, grid_w))), axis=0) - - # Equal if l1 distance is really small. Note that this will include this pixel - num_equal = np.sum((l1_dist < 0.0001).astype(np.int32)) - - if num_equal > 1: - print('Pixel at (%d, %d) has %d other pixel%s with the same representation.' % (x, y, num_equal-1, '' if num_equal==2 else 's')) - return False - - print('Each pixel has a distinct representation.') - return True - - - -render() - -axis = plt.axes([0.22, 0.19, 0.59, 0.03], facecolor='lightgoldenrodyellow') -scale_slider = Slider(axis, 'Scale', 0.1, 20, valinit=scale, valstep=0.1) -scale_slider.on_changed(update_scale) - -axis = plt.axes([0.22, 0.15, 0.59, 0.03], facecolor='lightgoldenrodyellow') -angle_slider = Slider(axis, 'Angle', -math.pi, math.pi, valinit=angle, valstep=0.1) -angle_slider.on_changed(update_angle) - -axis = plt.axes([0.22, 0.11, 0.59, 0.03], facecolor='lightgoldenrodyellow') -centx_slider = Slider(axis, 'Center X', 0, 1, valinit=center_x, valstep=0.05) -centx_slider.on_changed(update_centerx) - -axis = plt.axes([0.22, 0.07, 0.59, 0.03], facecolor='lightgoldenrodyellow') -centy_slider = Slider(axis, 'Center Y', 0, 1, valinit=center_y, valstep=0.05) -centy_slider.on_changed(update_centery) - -axis = plt.axes([0.22, 0.03, 0.59, 0.03], facecolor='lightgoldenrodyellow') -spaci_slider = Slider(axis, 'Spacing', -1, 2, valinit=spacing, valstep=0.05) -spaci_slider.on_changed(update_spacing) - -axis = plt.axes([0.8, 0.54, 0.15, 0.05], facecolor='lightgoldenrodyellow') -rando_button = Button(axis, 'Randomize') -rando_button.on_clicked(randomize) - -axis = plt.axes([0.8, 0.48, 0.15, 0.05], facecolor='lightgoldenrodyellow') -addgr_button = Button(axis, 'Add') -addgr_button.on_clicked(add) - -# Likely not a good way to do this but whatever -export_len_text = plt.text(0, 3, 'Num Grids: 0') - -axis = plt.axes([0.8, 0.42, 0.15, 0.05], facecolor='lightgoldenrodyellow') -addra_button = Button(axis, 'Add / Rand') -addra_button.on_clicked(add_randomize) - -axis = plt.axes([0.8, 0.36, 0.15, 0.05], facecolor='lightgoldenrodyellow') -saveg_button = Button(axis, 'Save') -saveg_button.on_clicked(export) - - - -plt.show() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 numpy as np +import math, random + +import matplotlib.pyplot as plt +from matplotlib.widgets import Slider, Button + + +fig, ax = plt.subplots() +plt.subplots_adjust(bottom=0.24) +im_handle = None + +save_path = 'grid.npy' + +center_x, center_y = (0.5, 0.5) +grid_w, grid_h = (35, 35) +spacing = 0 +scale = 4 +angle = 0 +grid = None + +all_grids = [] +unique = False + +# A hack +disable_render = False + +def render(): + if disable_render: + return + + x = np.tile(np.array(list(range(grid_w)), dtype=np.float).reshape(1, grid_w), [grid_h, 1]) - grid_w * center_x + y = np.tile(np.array(list(range(grid_h)), dtype=np.float).reshape(grid_h, 1), [1, grid_w]) - grid_h * center_y + + x /= scale + y /= scale + + a1 = angle + math.pi / 3 + a2 = -angle + math.pi / 3 + a3 = angle + + z1 = x * math.sin(a1) + y * math.cos(a1) + z2 = x * math.sin(a2) - y * math.cos(a2) + z3 = x * math.sin(a3) + y * math.cos(a3) + + s1 = np.square(np.sin(z1)) + s2 = np.square(np.sin(z2)) + s3 = np.square(np.sin(z3)) + + line_1 = np.exp(s1 * spacing) * s1 + line_2 = np.exp(s2 * spacing) * s2 + line_3 = np.exp(s3 * spacing) * s3 + + global grid + grid = np.clip(1 - (line_1 + line_2 + line_3) / 3, 0, 1) + + global im_handle + if im_handle is None: + im_handle = plt.imshow(grid) + else: + im_handle.set_data(grid) + fig.canvas.draw_idle() + +def update_scale(val): + global scale + scale = val + + render() + +def update_angle(val): + global angle + angle = val + + render() + +def update_centerx(val): + global center_x + center_x = val + + render() + +def update_centery(val): + global center_y + center_y = val + + render() + +def update_spacing(val): + global spacing + spacing = val + + render() + +def randomize(val): + global center_x, center_y, spacing, scale, angle, disable_render + + center_x, center_y = (random.uniform(0, 1), random.uniform(0, 1)) + spacing = random.uniform(-0.2, 2) + scale = 4 * math.exp(random.uniform(-1, 1)) + angle = random.uniform(-math.pi, math.pi) + + disable_render = True + + scale_slider.set_val(scale) + angle_slider.set_val(angle) + centx_slider.set_val(center_x) + centy_slider.set_val(center_y) + spaci_slider.set_val(spacing) + + disable_render = False + + render() + +def add(val): + all_grids.append(grid) + + global unique + if not unique: + unique = test_uniqueness(np.stack(all_grids)) + + export_len_text.set_text('Num Grids: ' + str(len(all_grids))) + fig.canvas.draw_idle() + +def add_randomize(val): + add(val) + randomize(val) + +def export(val): + np.save(save_path, np.stack(all_grids)) + print('Saved %d grids to "%s"' % (len(all_grids), save_path)) + + global unique + unique = False + all_grids.clear() + + export_len_text.set_text('Num Grids: ' + str(len(all_grids))) + fig.canvas.draw_idle() + +def test_uniqueness(grids): + # Grids shape [ngrids, h, w] + grids = grids.reshape((-1, grid_h, grid_w)) + + for y in range(grid_h): + for x in range(grid_h): + pixel_features = grids[:, y, x] + + # l1 distance for this pixel with every other + l1_dist = np.sum(np.abs(grids - np.tile(pixel_features, grid_h*grid_w).reshape((-1, grid_h, grid_w))), axis=0) + + # Equal if l1 distance is really small. Note that this will include this pixel + num_equal = np.sum((l1_dist < 0.0001).astype(np.int32)) + + if num_equal > 1: + print('Pixel at (%d, %d) has %d other pixel%s with the same representation.' % (x, y, num_equal-1, '' if num_equal==2 else 's')) + return False + + print('Each pixel has a distinct representation.') + return True + + + +render() + +axis = plt.axes([0.22, 0.19, 0.59, 0.03], facecolor='lightgoldenrodyellow') +scale_slider = Slider(axis, 'Scale', 0.1, 20, valinit=scale, valstep=0.1) +scale_slider.on_changed(update_scale) + +axis = plt.axes([0.22, 0.15, 0.59, 0.03], facecolor='lightgoldenrodyellow') +angle_slider = Slider(axis, 'Angle', -math.pi, math.pi, valinit=angle, valstep=0.1) +angle_slider.on_changed(update_angle) + +axis = plt.axes([0.22, 0.11, 0.59, 0.03], facecolor='lightgoldenrodyellow') +centx_slider = Slider(axis, 'Center X', 0, 1, valinit=center_x, valstep=0.05) +centx_slider.on_changed(update_centerx) + +axis = plt.axes([0.22, 0.07, 0.59, 0.03], facecolor='lightgoldenrodyellow') +centy_slider = Slider(axis, 'Center Y', 0, 1, valinit=center_y, valstep=0.05) +centy_slider.on_changed(update_centery) + +axis = plt.axes([0.22, 0.03, 0.59, 0.03], facecolor='lightgoldenrodyellow') +spaci_slider = Slider(axis, 'Spacing', -1, 2, valinit=spacing, valstep=0.05) +spaci_slider.on_changed(update_spacing) + +axis = plt.axes([0.8, 0.54, 0.15, 0.05], facecolor='lightgoldenrodyellow') +rando_button = Button(axis, 'Randomize') +rando_button.on_clicked(randomize) + +axis = plt.axes([0.8, 0.48, 0.15, 0.05], facecolor='lightgoldenrodyellow') +addgr_button = Button(axis, 'Add') +addgr_button.on_clicked(add) + +# Likely not a good way to do this but whatever +export_len_text = plt.text(0, 3, 'Num Grids: 0') + +axis = plt.axes([0.8, 0.42, 0.15, 0.05], facecolor='lightgoldenrodyellow') +addra_button = Button(axis, 'Add / Rand') +addra_button.on_clicked(add_randomize) + +axis = plt.axes([0.8, 0.36, 0.15, 0.05], facecolor='lightgoldenrodyellow') +saveg_button = Button(axis, 'Save') +saveg_button.on_clicked(export) + + + +plt.show() diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/optimize_bboxes.py b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/optimize_bboxes.py index 4e7916ee1a..5db9ef67e9 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/optimize_bboxes.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/optimize_bboxes.py @@ -1,218 +1,218 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ -""" -Instead of clustering bbox widths and heights, this script -directly optimizes average IoU across the training set given -the specified number of anchor boxes. - -Run this script from the Yolact root directory. -""" - -import pickle -import random -from itertools import product -from math import sqrt - -import numpy as np -import torch -from scipy.optimize import minimize - -dump_file = 'weights/bboxes.pkl' -aug_file = 'weights/bboxes_aug.pkl' - -use_augmented_boxes = True - - -def intersect(box_a, box_b): - """ We resize both tensors to [A,B,2] without new malloc: - [A,2] -> [A,1,2] -> [A,B,2] - [B,2] -> [1,B,2] -> [A,B,2] - Then we compute the area of intersect between box_a and box_b. - Args: - box_a: (tensor) bounding boxes, Shape: [A,4]. - box_b: (tensor) bounding boxes, Shape: [B,4]. - Return: - (tensor) intersection area, Shape: [A,B]. - """ - A = box_a.size(0) - B = box_b.size(0) - max_xy = torch.min(box_a[:, 2:].unsqueeze(1).expand(A, B, 2), - box_b[:, 2:].unsqueeze(0).expand(A, B, 2)) - min_xy = torch.max(box_a[:, :2].unsqueeze(1).expand(A, B, 2), - box_b[:, :2].unsqueeze(0).expand(A, B, 2)) - inter = torch.clamp((max_xy - min_xy), min=0) - return inter[:, :, 0] * inter[:, :, 1] - - -def jaccard(box_a, box_b, iscrowd=False): - """Compute the jaccard overlap of two sets of boxes. The jaccard overlap - is simply the intersection over union of two boxes. Here we operate on - ground truth boxes and default boxes. If iscrowd=True, put the crowd in box_b. - E.g.: - A ∩ B / A ∪ B = A ∩ B / (area(A) + area(B) - A ∩ B) - Args: - box_a: (tensor) Ground truth bounding boxes, Shape: [num_objects,4] - box_b: (tensor) Prior boxes from priorbox layers, Shape: [num_priors,4] - Return: - jaccard overlap: (tensor) Shape: [box_a.size(0), box_b.size(0)] - """ - inter = intersect(box_a, box_b) - area_a = ((box_a[:, 2]-box_a[:, 0]) * - (box_a[:, 3]-box_a[:, 1])).unsqueeze(1).expand_as(inter) # [A,B] - area_b = ((box_b[:, 2]-box_b[:, 0]) * - (box_b[:, 3]-box_b[:, 1])).unsqueeze(0).expand_as(inter) # [A,B] - union = area_a + area_b - inter - - if iscrowd: - return inter / area_a - else: - return inter / union # [A,B] - -# Also convert to point form -def to_relative(bboxes): - return np.concatenate((bboxes[:, 2:4] / bboxes[:, :2], (bboxes[:, 2:4] + bboxes[:, 4:]) / bboxes[:, :2]), axis=1) - - -def make_priors(conv_size, scales, aspect_ratios): - prior_data = [] - conv_h = conv_size[0] - conv_w = conv_size[1] - - # Iteration order is important (it has to sync up with the convout) - for j, i in product(range(conv_h), range(conv_w)): - x = (i + 0.5) / conv_w - y = (j + 0.5) / conv_h - - for scale, ars in zip(scales, aspect_ratios): - for ar in ars: - w = scale * ar / conv_w - h = scale / ar / conv_h - - # Point form - prior_data += [x - w/2, y - h/2, x + w/2, y + h/2] - return torch.Tensor(prior_data).view(-1, 4).cuda() - - - -scales = [[1.68, 2.91], [2.95, 2.22, 0.84], [2.17, 2.22, 3.22], [0.76, 2.06, 2.81], [5.33, 2.79], [13.69]] -aspect_ratios = [[[0.72, 0.96], [0.68, 1.17]], [[1.30, 0.66], [0.63, 1.23], [0.87, 1.41]], [[1.96, 1.23], [0.58, 0.84], [0.61, 1.15]], [[19.79, 2.21], [0.47, 1.76], [1.38, 0.79]], [[4.79, 17.96], [1.04]], [[14.82]]] -conv_sizes = [(35, 35), (18, 18), (9, 9), (5, 5), (3, 3), (2, 2)] - -optimize_scales = False - -batch_idx = 0 - - -def compute_hits(bboxes, anchors, iou_threshold=0.5): - ious = jaccard(bboxes, anchors) - perGTAnchorMax, _ = torch.max(ious, dim=1) - - return (perGTAnchorMax > iou_threshold) - -def compute_recall(hits, base_hits): - hits = (hits | base_hits).float() - return torch.sum(hits) / hits.size(0) - - -def step(x, x_func, bboxes, base_hits, optim_idx): - # This should set the scale and aspect ratio - x_func(x, scales[optim_idx], aspect_ratios[optim_idx]) - - anchors = make_priors(conv_sizes[optim_idx], scales[optim_idx], aspect_ratios[optim_idx]) - - return -float(compute_recall(compute_hits(bboxes, anchors), base_hits).cpu()) - - -def optimize(full_bboxes, optim_idx, batch_size=5000): - global batch_idx, scales, aspect_ratios, conv_sizes - - start = batch_idx * batch_size - end = min((batch_idx + 1) * batch_size, full_bboxes.size(0)) - - if batch_idx > (full_bboxes.size(0) // batch_size): - batch_idx = 0 - - bboxes = full_bboxes[start:end, :] - - anchor_base = [ - make_priors(conv_sizes[idx], scales[idx], aspect_ratios[idx]) - for idx in range(len(conv_sizes)) if idx != optim_idx] - base_hits = compute_hits(bboxes, torch.cat(anchor_base, dim=0)) - - - def set_x(x, scales, aspect_ratios): - if optimize_scales: - for i in range(len(scales)): - scales[i] = max(x[i], 0) - else: - k = 0 - for i in range(len(aspect_ratios)): - for j in range(len(aspect_ratios[i])): - aspect_ratios[i][j] = x[k] - k += 1 - - - res = minimize(step, x0=scales[optim_idx] if optimize_scales else sum(aspect_ratios[optim_idx], []), method='Powell', - args = (set_x, bboxes, base_hits, optim_idx),) - - -def pretty_str(x:list): - if isinstance(x, list): - return '[' + ', '.join([pretty_str(y) for y in x]) + ']' - elif isinstance(x, np.ndarray): - return pretty_str(list(x)) - else: - return '%.2f' % x - -if __name__ == '__main__': - - if use_augmented_boxes: - with open(aug_file, 'rb') as f: - bboxes = pickle.load(f) - else: - # Load widths and heights from a dump file. Obtain this with - # python3 scripts/save_bboxes.py - with open(dump_file, 'rb') as f: - bboxes = pickle.load(f) - - bboxes = np.array(bboxes) - bboxes = to_relative(bboxes) - - with torch.no_grad(): - bboxes = torch.Tensor(bboxes).cuda() - - def print_out(): - if optimize_scales: - print('Scales: ' + pretty_str(scales)) - else: - print('Aspect Ratios: ' + pretty_str(aspect_ratios)) - - for p in range(10): - print('(Sub Iteration) ', end='') - for i in range(len(conv_sizes)): - print('%d ' % i, end='', flush=True) - optimize(bboxes, i) - print('Done', end='\r') - - print('(Iteration %d) ' % p, end='') - print_out() - print() - - optimize_scales = not optimize_scales - - print('scales = ' + pretty_str(scales)) - print('aspect_ratios = ' + pretty_str(aspect_ratios)) - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +""" +Instead of clustering bbox widths and heights, this script +directly optimizes average IoU across the training set given +the specified number of anchor boxes. + +Run this script from the Yolact root directory. +""" + +import pickle +import random +from itertools import product +from math import sqrt + +import numpy as np +import torch +from scipy.optimize import minimize + +dump_file = 'weights/bboxes.pkl' +aug_file = 'weights/bboxes_aug.pkl' + +use_augmented_boxes = True + + +def intersect(box_a, box_b): + """ We resize both tensors to [A,B,2] without new malloc: + [A,2] -> [A,1,2] -> [A,B,2] + [B,2] -> [1,B,2] -> [A,B,2] + Then we compute the area of intersect between box_a and box_b. + Args: + box_a: (tensor) bounding boxes, Shape: [A,4]. + box_b: (tensor) bounding boxes, Shape: [B,4]. + Return: + (tensor) intersection area, Shape: [A,B]. + """ + A = box_a.size(0) + B = box_b.size(0) + max_xy = torch.min(box_a[:, 2:].unsqueeze(1).expand(A, B, 2), + box_b[:, 2:].unsqueeze(0).expand(A, B, 2)) + min_xy = torch.max(box_a[:, :2].unsqueeze(1).expand(A, B, 2), + box_b[:, :2].unsqueeze(0).expand(A, B, 2)) + inter = torch.clamp((max_xy - min_xy), min=0) + return inter[:, :, 0] * inter[:, :, 1] + + +def jaccard(box_a, box_b, iscrowd=False): + """Compute the jaccard overlap of two sets of boxes. The jaccard overlap + is simply the intersection over union of two boxes. Here we operate on + ground truth boxes and default boxes. If iscrowd=True, put the crowd in box_b. + E.g.: + A ∩ B / A ∪ B = A ∩ B / (area(A) + area(B) - A ∩ B) + Args: + box_a: (tensor) Ground truth bounding boxes, Shape: [num_objects,4] + box_b: (tensor) Prior boxes from priorbox layers, Shape: [num_priors,4] + Return: + jaccard overlap: (tensor) Shape: [box_a.size(0), box_b.size(0)] + """ + inter = intersect(box_a, box_b) + area_a = ((box_a[:, 2]-box_a[:, 0]) * + (box_a[:, 3]-box_a[:, 1])).unsqueeze(1).expand_as(inter) # [A,B] + area_b = ((box_b[:, 2]-box_b[:, 0]) * + (box_b[:, 3]-box_b[:, 1])).unsqueeze(0).expand_as(inter) # [A,B] + union = area_a + area_b - inter + + if iscrowd: + return inter / area_a + else: + return inter / union # [A,B] + +# Also convert to point form +def to_relative(bboxes): + return np.concatenate((bboxes[:, 2:4] / bboxes[:, :2], (bboxes[:, 2:4] + bboxes[:, 4:]) / bboxes[:, :2]), axis=1) + + +def make_priors(conv_size, scales, aspect_ratios): + prior_data = [] + conv_h = conv_size[0] + conv_w = conv_size[1] + + # Iteration order is important (it has to sync up with the convout) + for j, i in product(range(conv_h), range(conv_w)): + x = (i + 0.5) / conv_w + y = (j + 0.5) / conv_h + + for scale, ars in zip(scales, aspect_ratios): + for ar in ars: + w = scale * ar / conv_w + h = scale / ar / conv_h + + # Point form + prior_data += [x - w/2, y - h/2, x + w/2, y + h/2] + return torch.Tensor(prior_data).view(-1, 4).cuda() + + + +scales = [[1.68, 2.91], [2.95, 2.22, 0.84], [2.17, 2.22, 3.22], [0.76, 2.06, 2.81], [5.33, 2.79], [13.69]] +aspect_ratios = [[[0.72, 0.96], [0.68, 1.17]], [[1.30, 0.66], [0.63, 1.23], [0.87, 1.41]], [[1.96, 1.23], [0.58, 0.84], [0.61, 1.15]], [[19.79, 2.21], [0.47, 1.76], [1.38, 0.79]], [[4.79, 17.96], [1.04]], [[14.82]]] +conv_sizes = [(35, 35), (18, 18), (9, 9), (5, 5), (3, 3), (2, 2)] + +optimize_scales = False + +batch_idx = 0 + + +def compute_hits(bboxes, anchors, iou_threshold=0.5): + ious = jaccard(bboxes, anchors) + perGTAnchorMax, _ = torch.max(ious, dim=1) + + return (perGTAnchorMax > iou_threshold) + +def compute_recall(hits, base_hits): + hits = (hits | base_hits).float() + return torch.sum(hits) / hits.size(0) + + +def step(x, x_func, bboxes, base_hits, optim_idx): + # This should set the scale and aspect ratio + x_func(x, scales[optim_idx], aspect_ratios[optim_idx]) + + anchors = make_priors(conv_sizes[optim_idx], scales[optim_idx], aspect_ratios[optim_idx]) + + return -float(compute_recall(compute_hits(bboxes, anchors), base_hits).cpu()) + + +def optimize(full_bboxes, optim_idx, batch_size=5000): + global batch_idx, scales, aspect_ratios, conv_sizes + + start = batch_idx * batch_size + end = min((batch_idx + 1) * batch_size, full_bboxes.size(0)) + + if batch_idx > (full_bboxes.size(0) // batch_size): + batch_idx = 0 + + bboxes = full_bboxes[start:end, :] + + anchor_base = [ + make_priors(conv_sizes[idx], scales[idx], aspect_ratios[idx]) + for idx in range(len(conv_sizes)) if idx != optim_idx] + base_hits = compute_hits(bboxes, torch.cat(anchor_base, dim=0)) + + + def set_x(x, scales, aspect_ratios): + if optimize_scales: + for i in range(len(scales)): + scales[i] = max(x[i], 0) + else: + k = 0 + for i in range(len(aspect_ratios)): + for j in range(len(aspect_ratios[i])): + aspect_ratios[i][j] = x[k] + k += 1 + + + res = minimize(step, x0=scales[optim_idx] if optimize_scales else sum(aspect_ratios[optim_idx], []), method='Powell', + args = (set_x, bboxes, base_hits, optim_idx),) + + +def pretty_str(x:list): + if isinstance(x, list): + return '[' + ', '.join([pretty_str(y) for y in x]) + ']' + elif isinstance(x, np.ndarray): + return pretty_str(list(x)) + else: + return '%.2f' % x + +if __name__ == '__main__': + + if use_augmented_boxes: + with open(aug_file, 'rb') as f: + bboxes = pickle.load(f) + else: + # Load widths and heights from a dump file. Obtain this with + # python3 scripts/save_bboxes.py + with open(dump_file, 'rb') as f: + bboxes = pickle.load(f) + + bboxes = np.array(bboxes) + bboxes = to_relative(bboxes) + + with torch.no_grad(): + bboxes = torch.Tensor(bboxes).cuda() + + def print_out(): + if optimize_scales: + print('Scales: ' + pretty_str(scales)) + else: + print('Aspect Ratios: ' + pretty_str(aspect_ratios)) + + for p in range(10): + print('(Sub Iteration) ', end='') + for i in range(len(conv_sizes)): + print('%d ' % i, end='', flush=True) + optimize(bboxes, i) + print('Done', end='\r') + + print('(Iteration %d) ' % p, end='') + print_out() + print() + + optimize_scales = not optimize_scales + + print('scales = ' + pretty_str(scales)) + print('aspect_ratios = ' + pretty_str(aspect_ratios)) + + diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/parse_eval.py b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/parse_eval.py index c6788ba07f..481ae586f8 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/parse_eval.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/parse_eval.py @@ -1,63 +1,63 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 re, sys, os -import matplotlib.pyplot as plt -from matplotlib._color_data import XKCD_COLORS - -with open(sys.argv[1], 'r') as f: - txt = f.read() - -txt, overall = txt.split('overall performance') - -class_names = [] -mAP_overall = [] -mAP_small = [] -mAP_medium = [] -mAP_large = [] - -for class_result in txt.split('evaluate category: ')[1:]: - lines = class_result.split('\n') - class_names.append(lines[0]) - - def grabMAP(string): - return float(string.split('] = ')[1]) * 100 - - mAP_overall.append(grabMAP(lines[ 7])) - mAP_small .append(grabMAP(lines[10])) - mAP_medium .append(grabMAP(lines[11])) - mAP_large .append(grabMAP(lines[12])) - -mAP_map = { - 'small': mAP_small, - 'medium': mAP_medium, - 'large': mAP_large, -} - -if len(sys.argv) > 2: - bars = plt.bar(class_names, mAP_map[sys.argv[2]]) - plt.title(sys.argv[2] + ' mAP per class') -else: - bars = plt.bar(class_names, mAP_overall) - plt.title('overall mAP per class') - -colors = list(XKCD_COLORS.values()) - -for idx, bar in enumerate(bars): - # Mmm pseudorandom colors - char_sum = sum([ord(char) for char in class_names[idx]]) - bar.set_color(colors[char_sum % len(colors)]) - -plt.xticks(rotation='vertical') -plt.show() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 re, sys, os +import matplotlib.pyplot as plt +from matplotlib._color_data import XKCD_COLORS + +with open(sys.argv[1], 'r') as f: + txt = f.read() + +txt, overall = txt.split('overall performance') + +class_names = [] +mAP_overall = [] +mAP_small = [] +mAP_medium = [] +mAP_large = [] + +for class_result in txt.split('evaluate category: ')[1:]: + lines = class_result.split('\n') + class_names.append(lines[0]) + + def grabMAP(string): + return float(string.split('] = ')[1]) * 100 + + mAP_overall.append(grabMAP(lines[ 7])) + mAP_small .append(grabMAP(lines[10])) + mAP_medium .append(grabMAP(lines[11])) + mAP_large .append(grabMAP(lines[12])) + +mAP_map = { + 'small': mAP_small, + 'medium': mAP_medium, + 'large': mAP_large, +} + +if len(sys.argv) > 2: + bars = plt.bar(class_names, mAP_map[sys.argv[2]]) + plt.title(sys.argv[2] + ' mAP per class') +else: + bars = plt.bar(class_names, mAP_overall) + plt.title('overall mAP per class') + +colors = list(XKCD_COLORS.values()) + +for idx, bar in enumerate(bars): + # Mmm pseudorandom colors + char_sum = sum([ord(char) for char in class_names[idx]]) + bar.set_color(colors[char_sum % len(colors)]) + +plt.xticks(rotation='vertical') +plt.show() diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/plot_loss.py b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/plot_loss.py index 415d1041d6..0442bc633b 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/plot_loss.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/plot_loss.py @@ -1,92 +1,92 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 re, sys, os -import matplotlib.pyplot as plt - -from utils.functions import MovingAverage - -with open(sys.argv[1], 'r') as f: - inp = f.read() - -patterns = { - 'train': re.compile(r'\[\s*(?P\d+)\]\s*(?P\d+) \|\| B: (?P\S+) \| C: (?P\S+) \| M: (?P\S+) \|( S: (?P\S+) \|)? T: (?P\S+)'), - 'val': re.compile(r'\s*(?P[a-z]+) \|\s*(?P\S+)') -} -data = {key: [] for key in patterns} - -for line in inp.split('\n'): - for key, pattern in patterns.items(): - f = pattern.search(line) - - if f is not None: - datum = f.groupdict() - for k, v in datum.items(): - if v is not None: - try: - v = float(v) - except ValueError: - pass - datum[k] = v - - if key == 'val': - datum = (datum, data['train'][-1]) - data[key].append(datum) - break - - -def smoother(y, interval=100): - avg = MovingAverage(interval) - - for i in range(len(y)): - avg.append(y[i]) - y[i] = avg.get_avg() - - return y - -def plot_train(data): - plt.title(os.path.basename(sys.argv[1]) + ' Training Loss') - plt.xlabel('Iteration') - plt.ylabel('Loss') - - loss_names = ['BBox Loss', 'Conf Loss', 'Mask Loss'] - - x = [x['iteration'] for x in data] - plt.plot(x, smoother([y['b'] for y in data])) - plt.plot(x, smoother([y['c'] for y in data])) - plt.plot(x, smoother([y['m'] for y in data])) - - if data[0]['s'] is not None: - plt.plot(x, smoother([y['s'] for y in data])) - loss_names.append('Segmentation Loss') - - plt.legend(loss_names) - plt.show() - -def plot_val(data): - plt.title(os.path.basename(sys.argv[1]) + ' Validation mAP') - plt.xlabel('Epoch') - plt.ylabel('mAP') - - x = [x[1]['epoch'] for x in data if x[0]['type'] == 'box'] - plt.plot(x, [x[0]['all'] for x in data if x[0]['type'] == 'box']) - plt.plot(x, [x[0]['all'] for x in data if x[0]['type'] == 'mask']) - - plt.legend(['BBox mAP', 'Mask mAP']) - plt.show() - -if len(sys.argv) > 2 and sys.argv[2] == 'val': - plot_val(data['val']) -else: - plot_train(data['train']) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 re, sys, os +import matplotlib.pyplot as plt + +from utils.functions import MovingAverage + +with open(sys.argv[1], 'r') as f: + inp = f.read() + +patterns = { + 'train': re.compile(r'\[\s*(?P\d+)\]\s*(?P\d+) \|\| B: (?P\S+) \| C: (?P\S+) \| M: (?P\S+) \|( S: (?P\S+) \|)? T: (?P\S+)'), + 'val': re.compile(r'\s*(?P[a-z]+) \|\s*(?P\S+)') +} +data = {key: [] for key in patterns} + +for line in inp.split('\n'): + for key, pattern in patterns.items(): + f = pattern.search(line) + + if f is not None: + datum = f.groupdict() + for k, v in datum.items(): + if v is not None: + try: + v = float(v) + except ValueError: + pass + datum[k] = v + + if key == 'val': + datum = (datum, data['train'][-1]) + data[key].append(datum) + break + + +def smoother(y, interval=100): + avg = MovingAverage(interval) + + for i in range(len(y)): + avg.append(y[i]) + y[i] = avg.get_avg() + + return y + +def plot_train(data): + plt.title(os.path.basename(sys.argv[1]) + ' Training Loss') + plt.xlabel('Iteration') + plt.ylabel('Loss') + + loss_names = ['BBox Loss', 'Conf Loss', 'Mask Loss'] + + x = [x['iteration'] for x in data] + plt.plot(x, smoother([y['b'] for y in data])) + plt.plot(x, smoother([y['c'] for y in data])) + plt.plot(x, smoother([y['m'] for y in data])) + + if data[0]['s'] is not None: + plt.plot(x, smoother([y['s'] for y in data])) + loss_names.append('Segmentation Loss') + + plt.legend(loss_names) + plt.show() + +def plot_val(data): + plt.title(os.path.basename(sys.argv[1]) + ' Validation mAP') + plt.xlabel('Epoch') + plt.ylabel('mAP') + + x = [x[1]['epoch'] for x in data if x[0]['type'] == 'box'] + plt.plot(x, [x[0]['all'] for x in data if x[0]['type'] == 'box']) + plt.plot(x, [x[0]['all'] for x in data if x[0]['type'] == 'mask']) + + plt.legend(['BBox mAP', 'Mask mAP']) + plt.show() + +if len(sys.argv) > 2 and sys.argv[2] == 'val': + plot_val(data['val']) +else: + plot_train(data['train']) diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/resume.sh b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/resume.sh index 336af0552f..d4857876bd 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/resume.sh +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/resume.sh @@ -1,14 +1,14 @@ -#!/bin/bash -#SBATCH -p GPU-shared -#SBATCH -t 48:00:00 -#SBATCH --gres=gpu:p100:1 -#SBATCH --no-requeue - -# Usage: ./resume.sh config batch_size resume_file - -module load python/3.6.4_gcc5_np1.14.5 -module load cuda/9.0 - -cd $SCRATCH/yolact - -python3 train.py --config $1 --batch_size $2 --resume=$3 --save_interval 5000 --start_iter=-1 >>logs/$1_log 2>&1 +#!/bin/bash +#SBATCH -p GPU-shared +#SBATCH -t 48:00:00 +#SBATCH --gres=gpu:p100:1 +#SBATCH --no-requeue + +# Usage: ./resume.sh config batch_size resume_file + +module load python/3.6.4_gcc5_np1.14.5 +module load cuda/9.0 + +cd $SCRATCH/yolact + +python3 train.py --config $1 --batch_size $2 --resume=$3 --save_interval 5000 --start_iter=-1 >>logs/$1_log 2>&1 diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/save_bboxes.py b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/save_bboxes.py index 0218314152..64aee2eb36 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/save_bboxes.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/save_bboxes.py @@ -1,47 +1,47 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ -""" This script transforms and saves bbox coordinates into a pickle object for easy loading. """ - - -import os.path as osp -import json, pickle -import sys - -import numpy as np - -COCO_ROOT = osp.join('.', 'data/coco/') - -annotation_file = 'instances_train2017.json' -annotation_path = osp.join(COCO_ROOT, 'annotations/', annotation_file) - -dump_file = 'weights/bboxes.pkl' - -with open(annotation_path, 'r') as f: - annotations_json = json.load(f) - -annotations = annotations_json['annotations'] -images = annotations_json['images'] -images = {image['id']: image for image in images} -bboxes = [] - -for ann in annotations: - image = images[ann['image_id']] - w,h = (image['width'], image['height']) - - if 'bbox' in ann: - bboxes.append([w, h] + ann['bbox']) - -with open(dump_file, 'wb') as f: - pickle.dump(bboxes, f) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +""" This script transforms and saves bbox coordinates into a pickle object for easy loading. """ + + +import os.path as osp +import json, pickle +import sys + +import numpy as np + +COCO_ROOT = osp.join('.', 'data/coco/') + +annotation_file = 'instances_train2017.json' +annotation_path = osp.join(COCO_ROOT, 'annotations/', annotation_file) + +dump_file = 'weights/bboxes.pkl' + +with open(annotation_path, 'r') as f: + annotations_json = json.load(f) + +annotations = annotations_json['annotations'] +images = annotations_json['images'] +images = {image['id']: image for image in images} +bboxes = [] + +for ann in annotations: + image = images[ann['image_id']] + w,h = (image['width'], image['height']) + + if 'bbox' in ann: + bboxes.append([w, h] + ann['bbox']) + +with open(dump_file, 'wb') as f: + pickle.dump(bboxes, f) diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/train.sh b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/train.sh index 36dff27c50..b526d93c92 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/train.sh +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/train.sh @@ -1,14 +1,14 @@ -#!/bin/bash -#SBATCH -p GPU-shared -#SBATCH -t 48:00:00 -#SBATCH --gres=gpu:p100:1 -#SBATCH --no-requeue - -# Usage: ./train.sh config batch_size - -module load python/3.6.4_gcc5_np1.14.5 -module load cuda/9.0 - -cd $SCRATCH/yolact - -python3 train.py --config $1 --batch_size $2 --save_interval 5000 &>logs/$1_log +#!/bin/bash +#SBATCH -p GPU-shared +#SBATCH -t 48:00:00 +#SBATCH --gres=gpu:p100:1 +#SBATCH --no-requeue + +# Usage: ./train.sh config batch_size + +module load python/3.6.4_gcc5_np1.14.5 +module load cuda/9.0 + +cd $SCRATCH/yolact + +python3 train.py --config $1 --batch_size $2 --save_interval 5000 &>logs/$1_log diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/unpack_statedict.py b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/unpack_statedict.py index 7f1fa5f47b..41b7314c35 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/unpack_statedict.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/scripts/unpack_statedict.py @@ -1,30 +1,30 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import sys, os - -# Usage python scripts/unpack_statedict.py path_to_pth out_folder/ -# Make sure to include that slash after your out folder, since I can't -# be arsed to do path concatenation so I'd rather type out this comment - -print('Loading state dict...') -state = torch.load(sys.argv[1]) - -if not os.path.exists(sys.argv[2]): - os.mkdir(sys.argv[2]) - -print('Saving stuff...') -for key, val in state.items(): - torch.save(val, sys.argv[2] + key) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import sys, os + +# Usage python scripts/unpack_statedict.py path_to_pth out_folder/ +# Make sure to include that slash after your out folder, since I can't +# be arsed to do path concatenation so I'd rather type out this comment + +print('Loading state dict...') +state = torch.load(sys.argv[1]) + +if not os.path.exists(sys.argv[2]): + os.mkdir(sys.argv[2]) + +print('Saving stuff...') +for key, val in state.items(): + torch.save(val, sys.argv[2] + key) diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/test/env_npu.sh b/PyTorch/contrib/cv/detection/YOLACT_plus/test/env_npu.sh index 3d4584311c..d7213fd06e 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/test/env_npu.sh +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/test/env_npu.sh @@ -1,75 +1,75 @@ -#!/bin/bash -export install_path=/usr/local/Ascend - -if [ -d ${install_path}/toolkit ]; then - export LD_LIBRARY_PATH=${install_path}/fwkacllib/lib64/:/usr/include/hdf5/lib/:/usr/local/:/usr/local/lib/:/usr/lib/:${install_path}/driver/lib64/common/:${install_path}/driver/lib64/driver/:${install_path}/add-ons:${path_lib}:${LD_LIBRARY_PATH} - export PATH=${install_path}/fwkacllib/ccec_compiler/bin:${install_path}/fwkacllib/bin:$PATH - export PYTHONPATH=${install_path}/fwkacllib/python/site-packages:${install_path}/tfplugin/python/site-packages:${install_path}/toolkit/python/site-packages:$PYTHONPATH - export PYTHONPATH=/usr/local/python3.7.5/lib/python3.7/site-packages:$PYTHONPATH - export ASCEND_OPP_PATH=${install_path}/opp -else - if [ -d ${install_path}/nnae/latest ];then - export LD_LIBRARY_PATH=${install_path}/nnae/latest/fwkacllib/lib64/:/usr/local/:/usr/local/python3.7.5/lib/:/usr/local/openblas/lib:/usr/local/lib/:/usr/lib64/:/usr/lib/:${install_path}/driver/lib64/common/:${install_path}/driver/lib64/driver/:${install_path}/add-ons/:/usr/lib/aarch64_64-linux-gnu:$LD_LIBRARY_PATH - export PATH=$PATH:${install_path}/nnae/latest/fwkacllib/ccec_compiler/bin/:${install_path}/nnae/latest/toolkit/tools/ide_daemon/bin/ - export ASCEND_OPP_PATH=${install_path}/nnae/latest/opp/ - export OPTION_EXEC_EXTERN_PLUGIN_PATH=${install_path}/nnae/latest/fwkacllib/lib64/plugin/opskernel/libfe.so:${install_path}/nnae/latest/fwkacllib/lib64/plugin/opskernel/libaicpu_engine.so:${install_path}/nnae/latest/fwkacllib/lib64/plugin/opskernel/libge_local_engine.so - export PYTHONPATH=${install_path}/nnae/latest/fwkacllib/python/site-packages/:${install_path}/nnae/latest/fwkacllib/python/site-packages/auto_tune.egg/auto_tune:${install_path}/nnae/latest/fwkacllib/python/site-packages/schedule_search.egg:$PYTHONPATH - export ASCEND_AICPU_PATH=${install_path}/nnae/latest - else - export LD_LIBRARY_PATH=${install_path}/ascend-toolkit/latest/fwkacllib/lib64/:/usr/local/:/usr/local/lib/:/usr/lib64/:/usr/lib/:/usr/local/python3.7.5/lib/:/usr/local/openblas/lib:${install_path}/driver/lib64/common/:${install_path}/driver/lib64/driver/:${install_path}/add-ons/:/usr/lib/aarch64-linux-gnu:$LD_LIBRARY_PATH - export PATH=$PATH:${install_path}/ascend-toolkit/latest/fwkacllib/ccec_compiler/bin/:${install_path}/ascend-toolkit/latest/toolkit/tools/ide_daemon/bin/ - export ASCEND_OPP_PATH=${install_path}/ascend-toolkit/latest/opp/ - export OPTION_EXEC_EXTERN_PLUGIN_PATH=${install_path}/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libfe.so:${install_path}/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libaicpu_engine.so:${install_path}/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libge_local_engine.so - export PYTHONPATH=${install_path}/ascend-toolkit/latest/fwkacllib/python/site-packages/:${install_path}/ascend-toolkit/latest/fwkacllib/python/site-packages/auto_tune.egg/auto_tune:${install_path}/ascend-toolkit/latest/fwkacllib/python/site-packages/schedule_search.egg:$PYTHONPATH - export ASCEND_AICPU_PATH=${install_path}/ascend-toolkit/latest - fi -fi - -${install_path}/driver/tools/msnpureport -g error -d 0 -${install_path}/driver/tools/msnpureport -g error -d 1 -${install_path}/driver/tools/msnpureport -g error -d 2 -${install_path}/driver/tools/msnpureport -g error -d 3 -${install_path}/driver/tools/msnpureport -g error -d 4 -${install_path}/driver/tools/msnpureport -g error -d 5 -${install_path}/driver/tools/msnpureport -g error -d 6 -${install_path}/driver/tools/msnpureport -g error -d 7 - -#将Host日志输出到串口,0-关闭/1-开启 -export ASCEND_SLOG_PRINT_TO_STDOUT=0 -#设置默认日志级别,0-debug/1-info/2-warning/3-error -export ASCEND_GLOBAL_LOG_LEVEL=3 -#设置Event日志开启标志,0-关闭/1-开启 -export ASCEND_GLOBAL_EVENT_ENABLE=0 -#设置是否开启taskque,0-关闭/1-开启 -export TASK_QUEUE_ENABLE=1 -#设置是否开启PTCopy,0-关闭/1-开启 -export PTCOPY_ENABLE=1 -#设置是否开启combined标志,0-关闭/1-开启 -export COMBINED_ENABLE=0 -#设置特殊场景是否需要重新编译,不需要修改 -export DYNAMIC_OP="ADD#MUL" -#HCCL白名单开关,1-关闭/0-开启 -export HCCL_WHITELIST_DISABLE=1 - -ulimit -SHn 512000 - -path_lib=$(python3.7 -c """ -import sys -import re -result='' -for index in range(len(sys.path)): - match_sit = re.search('-packages', sys.path[index]) - if match_sit is not None: - match_lib = re.search('lib', sys.path[index]) - - if match_lib is not None: - end=match_lib.span()[1] - result += sys.path[index][0:end] + ':' - - result+=sys.path[index] + '/torch/lib:' -print(result)""" -) - -echo ${path_lib} - -export LD_LIBRARY_PATH=/usr/local/python3.7.5/lib/:${path_lib}:$LD_LIBRARY_PATH +#!/bin/bash +export install_path=/usr/local/Ascend + +if [ -d ${install_path}/toolkit ]; then + export LD_LIBRARY_PATH=${install_path}/fwkacllib/lib64/:/usr/include/hdf5/lib/:/usr/local/:/usr/local/lib/:/usr/lib/:${install_path}/driver/lib64/common/:${install_path}/driver/lib64/driver/:${install_path}/add-ons:${path_lib}:${LD_LIBRARY_PATH} + export PATH=${install_path}/fwkacllib/ccec_compiler/bin:${install_path}/fwkacllib/bin:$PATH + export PYTHONPATH=${install_path}/fwkacllib/python/site-packages:${install_path}/tfplugin/python/site-packages:${install_path}/toolkit/python/site-packages:$PYTHONPATH + export PYTHONPATH=/usr/local/python3.7.5/lib/python3.7/site-packages:$PYTHONPATH + export ASCEND_OPP_PATH=${install_path}/opp +else + if [ -d ${install_path}/nnae/latest ];then + export LD_LIBRARY_PATH=${install_path}/nnae/latest/fwkacllib/lib64/:/usr/local/:/usr/local/python3.7.5/lib/:/usr/local/openblas/lib:/usr/local/lib/:/usr/lib64/:/usr/lib/:${install_path}/driver/lib64/common/:${install_path}/driver/lib64/driver/:${install_path}/add-ons/:/usr/lib/aarch64_64-linux-gnu:$LD_LIBRARY_PATH + export PATH=$PATH:${install_path}/nnae/latest/fwkacllib/ccec_compiler/bin/:${install_path}/nnae/latest/toolkit/tools/ide_daemon/bin/ + export ASCEND_OPP_PATH=${install_path}/nnae/latest/opp/ + export OPTION_EXEC_EXTERN_PLUGIN_PATH=${install_path}/nnae/latest/fwkacllib/lib64/plugin/opskernel/libfe.so:${install_path}/nnae/latest/fwkacllib/lib64/plugin/opskernel/libaicpu_engine.so:${install_path}/nnae/latest/fwkacllib/lib64/plugin/opskernel/libge_local_engine.so + export PYTHONPATH=${install_path}/nnae/latest/fwkacllib/python/site-packages/:${install_path}/nnae/latest/fwkacllib/python/site-packages/auto_tune.egg/auto_tune:${install_path}/nnae/latest/fwkacllib/python/site-packages/schedule_search.egg:$PYTHONPATH + export ASCEND_AICPU_PATH=${install_path}/nnae/latest + else + export LD_LIBRARY_PATH=${install_path}/ascend-toolkit/latest/fwkacllib/lib64/:/usr/local/:/usr/local/lib/:/usr/lib64/:/usr/lib/:/usr/local/python3.7.5/lib/:/usr/local/openblas/lib:${install_path}/driver/lib64/common/:${install_path}/driver/lib64/driver/:${install_path}/add-ons/:/usr/lib/aarch64-linux-gnu:$LD_LIBRARY_PATH + export PATH=$PATH:${install_path}/ascend-toolkit/latest/fwkacllib/ccec_compiler/bin/:${install_path}/ascend-toolkit/latest/toolkit/tools/ide_daemon/bin/ + export ASCEND_OPP_PATH=${install_path}/ascend-toolkit/latest/opp/ + export OPTION_EXEC_EXTERN_PLUGIN_PATH=${install_path}/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libfe.so:${install_path}/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libaicpu_engine.so:${install_path}/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libge_local_engine.so + export PYTHONPATH=${install_path}/ascend-toolkit/latest/fwkacllib/python/site-packages/:${install_path}/ascend-toolkit/latest/fwkacllib/python/site-packages/auto_tune.egg/auto_tune:${install_path}/ascend-toolkit/latest/fwkacllib/python/site-packages/schedule_search.egg:$PYTHONPATH + export ASCEND_AICPU_PATH=${install_path}/ascend-toolkit/latest + fi +fi + +${install_path}/driver/tools/msnpureport -g error -d 0 +${install_path}/driver/tools/msnpureport -g error -d 1 +${install_path}/driver/tools/msnpureport -g error -d 2 +${install_path}/driver/tools/msnpureport -g error -d 3 +${install_path}/driver/tools/msnpureport -g error -d 4 +${install_path}/driver/tools/msnpureport -g error -d 5 +${install_path}/driver/tools/msnpureport -g error -d 6 +${install_path}/driver/tools/msnpureport -g error -d 7 + +#将Host日志输出到串口,0-关闭/1-开启 +export ASCEND_SLOG_PRINT_TO_STDOUT=0 +#设置默认日志级别,0-debug/1-info/2-warning/3-error +export ASCEND_GLOBAL_LOG_LEVEL=3 +#设置Event日志开启标志,0-关闭/1-开启 +export ASCEND_GLOBAL_EVENT_ENABLE=0 +#设置是否开启taskque,0-关闭/1-开启 +export TASK_QUEUE_ENABLE=1 +#设置是否开启PTCopy,0-关闭/1-开启 +export PTCOPY_ENABLE=1 +#设置是否开启combined标志,0-关闭/1-开启 +export COMBINED_ENABLE=0 +#设置特殊场景是否需要重新编译,不需要修改 +export DYNAMIC_OP="ADD#MUL" +#HCCL白名单开关,1-关闭/0-开启 +export HCCL_WHITELIST_DISABLE=1 + +ulimit -SHn 512000 + +path_lib=$(python3.7 -c """ +import sys +import re +result='' +for index in range(len(sys.path)): + match_sit = re.search('-packages', sys.path[index]) + if match_sit is not None: + match_lib = re.search('lib', sys.path[index]) + + if match_lib is not None: + end=match_lib.span()[1] + result += sys.path[index][0:end] + ':' + + result+=sys.path[index] + '/torch/lib:' +print(result)""" +) + +echo ${path_lib} + +export LD_LIBRARY_PATH=/usr/local/python3.7.5/lib/:${path_lib}:$LD_LIBRARY_PATH diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/test/train_eval_1p.sh b/PyTorch/contrib/cv/detection/YOLACT_plus/test/train_eval_1p.sh index 50a1c105ab..7ec0becd65 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/test/train_eval_1p.sh +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/test/train_eval_1p.sh @@ -1,141 +1,141 @@ -#!/bin/bash - -################基础配置参数,需要模型审视修改################## -# 必选字段(必须在此处定义的参数): Network batch_size RANK_SIZE -# 网络名称,同目录名称 -Network="YOLACT-plus" -# 训练batch_size -batch_size=16 -# 推理使用的npu卡数 -export RANK_SIZE=1 -# 数据集路径,保持为空,不需要修改 --data_path=./data/TrainDataset -data_path="" - -# checkpoint文件路径,以实际路径为准 --pth_path=./checkopint.pth.tar -pth_path='' - -# 指定推理所使用的npu device卡id -device_id=0 - -# 参数校验,data_path为必传参数,其他参数的增删由模型自身决定;此处新增参数需在上面有定义并赋值 -for para in $* -do - if [[ $para == --device_id* ]];then - device_id=`echo ${para#*=}` - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --pth_path* ]];then - pth_path=`echo ${para#*=}` - fi -done - -# 校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi -# 校验是否传入 pth_path , 验证脚本需要传入此参数 -if [[ $pth_path == "" ]];then - echo "[Error] para \"pth_path\" must be confing" - exit 1 -fi -# 校验是否指定了device_id,分动态分配device_id与手动指定device_id,此处不需要修改 -if [ $ASCEND_DEVICE_ID ];then - echo "device id is ${ASCEND_DEVICE_ID}" -elif [ ${device_id} ];then - export ASCEND_DEVICE_ID=${device_id} - echo "device id is ${ASCEND_DEVICE_ID}" -else - "[Error] device id must be config" - exit 1 -fi - -###############指定训练脚本执行路径############### -# cd到与test文件夹同层级目录下执行脚本,提高兼容性;test_path_dir为包含test文件夹的路径 -cur_path=`pwd` -cur_path_last_dirname=${cur_path##*/} -if [ x"${cur_path_last_dirname}" == x"test" ];then - test_path_dir=${cur_path} - cd .. - cur_path=`pwd` -else - test_path_dir=${cur_path}/test -fi - -#################创建日志输出目录,不需要修改################# - -if [ -d ${test_path_dir}/output/${ASCEND_DEVICE_ID} ];then - #rm -rf ${test_path_dir}/output/${ASCEND_DEVICE_ID} - mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID -else - mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID -fi - -#################启动训练(train)脚本################# -#训练开始时间,不需要修改 -start_time=$(date +%s) -# 非平台场景时source 环境变量 -check_etp_flag=`env | grep etp_running_flag` -etp_flag=`echo ${check_etp_flag#*=}` -if [ x"${etp_flag}" != x"true" ];then - source ${test_path_dir}/env_npu.sh -fi -export RANK_ID=${ASCEND_DEVICE_ID} -# 获取训练生成的log文件 -TRAIN_LOG_FILE_0=${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log - -##################计算并获取精度################ -LOG_FILE=${test_path_dir}/output/${ASCEND_DEVICE_ID}/eval_${ASCEND_DEVICE_ID}.log - -python3.7 eval.py --trained_model=${pth_path} \ - --data_path=${data_path} > $LOG_FILE 2>&1 & - -wait - -##################计算并获取精度################ -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep -a 'FPS' ${TRAIN_LOG_FILE_0} | awk -F " " '{print $2}'|awk 'END {print}'` -#打印,不需要修改 -echo "Final Performance images/sec : ${FPS}" - -#输出训练精度,需要模型审视修改 -train_accuracy=`grep -a 'mask |' ${LOG_FILE} |awk -F " " '{print $3}'|awk 'END {print}'` -# #打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep "||" ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log |awk -F '[|][|]' '{print $2}' >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` -echo "train_accuracy: ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +################基础配置参数,需要模型审视修改################## +# 必选字段(必须在此处定义的参数): Network batch_size RANK_SIZE +# 网络名称,同目录名称 +Network="YOLACT-plus" +# 训练batch_size +batch_size=16 +# 推理使用的npu卡数 +export RANK_SIZE=1 +# 数据集路径,保持为空,不需要修改 --data_path=./data/TrainDataset +data_path="" + +# checkpoint文件路径,以实际路径为准 --pth_path=./checkopint.pth.tar +pth_path='' + +# 指定推理所使用的npu device卡id +device_id=0 + +# 参数校验,data_path为必传参数,其他参数的增删由模型自身决定;此处新增参数需在上面有定义并赋值 +for para in $* +do + if [[ $para == --device_id* ]];then + device_id=`echo ${para#*=}` + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --pth_path* ]];then + pth_path=`echo ${para#*=}` + fi +done + +# 校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi +# 校验是否传入 pth_path , 验证脚本需要传入此参数 +if [[ $pth_path == "" ]];then + echo "[Error] para \"pth_path\" must be confing" + exit 1 +fi +# 校验是否指定了device_id,分动态分配device_id与手动指定device_id,此处不需要修改 +if [ $ASCEND_DEVICE_ID ];then + echo "device id is ${ASCEND_DEVICE_ID}" +elif [ ${device_id} ];then + export ASCEND_DEVICE_ID=${device_id} + echo "device id is ${ASCEND_DEVICE_ID}" +else + "[Error] device id must be config" + exit 1 +fi + +###############指定训练脚本执行路径############### +# cd到与test文件夹同层级目录下执行脚本,提高兼容性;test_path_dir为包含test文件夹的路径 +cur_path=`pwd` +cur_path_last_dirname=${cur_path##*/} +if [ x"${cur_path_last_dirname}" == x"test" ];then + test_path_dir=${cur_path} + cd .. + cur_path=`pwd` +else + test_path_dir=${cur_path}/test +fi + +#################创建日志输出目录,不需要修改################# + +if [ -d ${test_path_dir}/output/${ASCEND_DEVICE_ID} ];then + #rm -rf ${test_path_dir}/output/${ASCEND_DEVICE_ID} + mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID +else + mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID +fi + +#################启动训练(train)脚本################# +#训练开始时间,不需要修改 +start_time=$(date +%s) +# 非平台场景时source 环境变量 +check_etp_flag=`env | grep etp_running_flag` +etp_flag=`echo ${check_etp_flag#*=}` +if [ x"${etp_flag}" != x"true" ];then + source ${test_path_dir}/env_npu.sh +fi +export RANK_ID=${ASCEND_DEVICE_ID} +# 获取训练生成的log文件 +TRAIN_LOG_FILE_0=${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log + +##################计算并获取精度################ +LOG_FILE=${test_path_dir}/output/${ASCEND_DEVICE_ID}/eval_${ASCEND_DEVICE_ID}.log + +python3.7 eval.py --trained_model=${pth_path} \ + --data_path=${data_path} > $LOG_FILE 2>&1 & + +wait + +##################计算并获取精度################ +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep -a 'FPS' ${TRAIN_LOG_FILE_0} | awk -F " " '{print $2}'|awk 'END {print}'` +#打印,不需要修改 +echo "Final Performance images/sec : ${FPS}" + +#输出训练精度,需要模型审视修改 +train_accuracy=`grep -a 'mask |' ${LOG_FILE} |awk -F " " '{print $3}'|awk 'END {print}'` +# #打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep "||" ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log |awk -F '[|][|]' '{print $2}' >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` +echo "train_accuracy: ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/test/train_full_1p.sh b/PyTorch/contrib/cv/detection/YOLACT_plus/test/train_full_1p.sh index 09ada4f9ca..852823749d 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/test/train_full_1p.sh +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/test/train_full_1p.sh @@ -1,152 +1,152 @@ -#!/bin/bash - -################基础配置参数,需要模型审视修改################## -# 必选字段(必须在此处定义的参数): Network batch_size RANK_SIZE -# 网络名称,同目录名称 -Network="YOLACT-plus" -# 训练batch_size -batch_size=16 -# 训练使用的npu卡数 -export RANK_SIZE=1 -# 数据集路径,保持为空,不需要修改 --data_path=./data/TrainDataset -data_path="" - -# checkpoint文件路径,以实际路径为准 --pth_path=./checkopint.pth.tar -pth_path='' - -# 训练step -max_iter=1250000 -# 指定训练所使用的npu device卡id -device_id=0 -# 加载数据进程数 -workers=8 - -# 参数校验,data_path为必传参数,其他参数的增删由模型自身决定;此处新增参数需在上面有定义并赋值 -for para in $* -do - if [[ $para == --device_id* ]];then - device_id=`echo ${para#*=}` - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --pth_path* ]];then - pth_path=`echo ${para#*=}` - fi -done - -# 校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi -# 校验是否传入 pth_path , 验证脚本需要传入此参数 -#if [[ $pth_path == "" ]];then -# echo "[Error] para \"pth_path\" must be confing" -# exit 1 -#fi - -# 校验是否指定了device_id,分动态分配device_id与手动指定device_id,此处不需要修改 -if [ $ASCEND_DEVICE_ID ];then - echo "device id is ${ASCEND_DEVICE_ID}" -elif [ ${device_id} ];then - export ASCEND_DEVICE_ID=${device_id} - echo "device id is ${ASCEND_DEVICE_ID}" -else - "[Error] device id must be config" - exit 1 -fi - - - -###############指定训练脚本执行路径############### -# cd到与test文件夹同层级目录下执行脚本,提高兼容性;test_path_dir为包含test文件夹的路径 -cur_path=`pwd` -cur_path_last_dirname=${cur_path##*/} -if [ x"${cur_path_last_dirname}" == x"test" ];then - test_path_dir=${cur_path} - cd .. - cur_path=`pwd` -else - test_path_dir=${cur_path}/test -fi - - -#################创建日志输出目录,不需要修改################# - if [ -d ${test_path_dir}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${test_path_dir}/output/${ASCEND_DEVICE_ID} - mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID - else - mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID - fi - - -#################启动训练脚本################# -#训练开始时间,不需要修改 -start_time=$(date +%s) -# 非平台场景时source 环境变量 -check_etp_flag=`env | grep etp_running_flag` -etp_flag=`echo ${check_etp_flag#*=}` -if [ x"${etp_flag}" != x"true" ];then - source ${test_path_dir}/env_npu.sh -fi -export RANK_ID=${ASCEND_DEVICE_ID} -python3.7 ./train.py \ - --data_path=${data_path} \ - --num_workers=${workers} \ - --lr=2e-3 \ - --config=yolact_plus_resnet50_config \ - --max_iter=${max_iter} \ - --resume=${pth_path} \ - --save_interval=62500 \ - --batch_size=${batch_size} > ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & -wait - -python3.7 eval.py --trained_model=weights/yolact_plus.pth > ${test_path_dir}/output/${ASCEND_DEVICE_ID}/eval_${ASCEND_DEVICE_ID}.log 2>&1 -wait - -##################获取训练数据################ -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep -a 'FPS' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk -F " " '{print $2}'|awk 'END {print}'` -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -train_accuracy=`grep -a 'mask |' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/eval_${ASCEND_DEVICE_ID}.log |awk -F " " '{print $3}'|awk 'END {print}'` -# #打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep "||" ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log |awk -F '[|][|]' '{print $2}' >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` -echo "train_accuracy: ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +################基础配置参数,需要模型审视修改################## +# 必选字段(必须在此处定义的参数): Network batch_size RANK_SIZE +# 网络名称,同目录名称 +Network="YOLACT-plus" +# 训练batch_size +batch_size=16 +# 训练使用的npu卡数 +export RANK_SIZE=1 +# 数据集路径,保持为空,不需要修改 --data_path=./data/TrainDataset +data_path="" + +# checkpoint文件路径,以实际路径为准 --pth_path=./checkopint.pth.tar +pth_path='' + +# 训练step +max_iter=1250000 +# 指定训练所使用的npu device卡id +device_id=0 +# 加载数据进程数 +workers=8 + +# 参数校验,data_path为必传参数,其他参数的增删由模型自身决定;此处新增参数需在上面有定义并赋值 +for para in $* +do + if [[ $para == --device_id* ]];then + device_id=`echo ${para#*=}` + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --pth_path* ]];then + pth_path=`echo ${para#*=}` + fi +done + +# 校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi +# 校验是否传入 pth_path , 验证脚本需要传入此参数 +#if [[ $pth_path == "" ]];then +# echo "[Error] para \"pth_path\" must be confing" +# exit 1 +#fi + +# 校验是否指定了device_id,分动态分配device_id与手动指定device_id,此处不需要修改 +if [ $ASCEND_DEVICE_ID ];then + echo "device id is ${ASCEND_DEVICE_ID}" +elif [ ${device_id} ];then + export ASCEND_DEVICE_ID=${device_id} + echo "device id is ${ASCEND_DEVICE_ID}" +else + "[Error] device id must be config" + exit 1 +fi + + + +###############指定训练脚本执行路径############### +# cd到与test文件夹同层级目录下执行脚本,提高兼容性;test_path_dir为包含test文件夹的路径 +cur_path=`pwd` +cur_path_last_dirname=${cur_path##*/} +if [ x"${cur_path_last_dirname}" == x"test" ];then + test_path_dir=${cur_path} + cd .. + cur_path=`pwd` +else + test_path_dir=${cur_path}/test +fi + + +#################创建日志输出目录,不需要修改################# + if [ -d ${test_path_dir}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${test_path_dir}/output/${ASCEND_DEVICE_ID} + mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID + else + mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID + fi + + +#################启动训练脚本################# +#训练开始时间,不需要修改 +start_time=$(date +%s) +# 非平台场景时source 环境变量 +check_etp_flag=`env | grep etp_running_flag` +etp_flag=`echo ${check_etp_flag#*=}` +if [ x"${etp_flag}" != x"true" ];then + source ${test_path_dir}/env_npu.sh +fi +export RANK_ID=${ASCEND_DEVICE_ID} +python3.7 ./train.py \ + --data_path=${data_path} \ + --num_workers=${workers} \ + --lr=2e-3 \ + --config=yolact_plus_resnet50_config \ + --max_iter=${max_iter} \ + --resume=${pth_path} \ + --save_interval=62500 \ + --batch_size=${batch_size} > ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & +wait + +python3.7 eval.py --trained_model=weights/yolact_plus.pth > ${test_path_dir}/output/${ASCEND_DEVICE_ID}/eval_${ASCEND_DEVICE_ID}.log 2>&1 +wait + +##################获取训练数据################ +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep -a 'FPS' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk -F " " '{print $2}'|awk 'END {print}'` +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +train_accuracy=`grep -a 'mask |' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/eval_${ASCEND_DEVICE_ID}.log |awk -F " " '{print $3}'|awk 'END {print}'` +# #打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep "||" ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log |awk -F '[|][|]' '{print $2}' >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` +echo "train_accuracy: ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/test/train_full_8p.sh b/PyTorch/contrib/cv/detection/YOLACT_plus/test/train_full_8p.sh index 60c34bd048..2bfef08bce 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/test/train_full_8p.sh +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/test/train_full_8p.sh @@ -1,173 +1,173 @@ -#!/bin/bash - -################基础配置参数,需要模型审视修改################## -# 必选字段(必须在此处定义的参数): Network batch_size RANK_SIZE -# 网络名称,同目录名称 -Network="YOLACT-plus" -# 训练batch_size -batch_size=16 -# 训练使用的npu卡数 -export RANK_SIZE=8 -# 数据集路径,保持为空,不需要修改 --data_path=./data/TrainDataset -data_path="" - -# checkpoint文件路径,以实际路径为准 --pth_path=./checkopint.pth.tar -pth_path='' - -# 训练step -max_iter=1250000 -# 指定训练所使用的npu device卡id -device_id=0 -# 加载数据进程数 -workers=8 - -# 参数校验,data_path为必传参数,其他参数的增删由模型自身决定;此处新增参数需在上面有定义并赋值 -for para in $* -do - if [[ $para == --device_id* ]];then - device_id=`echo ${para#*=}` - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --pth_path* ]];then - pth_path=`echo ${para#*=}` - fi -done - -# 校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi -# 校验是否传入 pth_path , 验证脚本需要传入此参数 -#if [[ $pth_path == "" ]];then -# echo "[Error] para \"pth_path\" must be confing" -# exit 1 -#fi - -# 校验是否指定了device_id,分动态分配device_id与手动指定device_id,此处不需要修改 -if [ $ASCEND_DEVICE_ID ];then - echo "device id is ${ASCEND_DEVICE_ID}" -elif [ ${device_id} ];then - export ASCEND_DEVICE_ID=${device_id} - echo "device id is ${ASCEND_DEVICE_ID}" -else - "[Error] device id must be config" - exit 1 -fi - - - -###############指定训练脚本执行路径############### -# cd到与test文件夹同层级目录下执行脚本,提高兼容性;test_path_dir为包含test文件夹的路径 -cur_path=`pwd` -cur_path_last_dirname=${cur_path##*/} -if [ x"${cur_path_last_dirname}" == x"test" ];then - test_path_dir=${cur_path} - cd .. - cur_path=`pwd` -else - test_path_dir=${cur_path}/test -fi - - -#################创建日志输出目录,不需要修改################# - if [ -d ${test_path_dir}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${test_path_dir}/output/${ASCEND_DEVICE_ID} - mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID - else - mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID - fi - - -#################启动训练脚本################# -#训练开始时间,不需要修改 -start_time=$(date +%s) -# 非平台场景时source 环境变量 -check_etp_flag=`env | grep etp_running_flag` -etp_flag=`echo ${check_etp_flag#*=}` -if [ x"${etp_flag}" != x"true" ];then - source ${test_path_dir}/env_npu.sh -fi - -for((RANK_ID=0;RANK_ID ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & - else - python3.7 -u train.py \ - --data_path=${data_path} \ - --num_workers=${workers} \ - --lr=2e-3 \ - --config=yolact_plus_resnet50_config \ - --max_iter=${max_iter} \ - --resume=${pth_path} \ - --save_interval=62500 \ - --batch_size=${batch_size} > ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & - fi -done -wait -python3.7 eval.py --trained_model=weights/yolact_plus.pth > ${test_path_dir}/output/${ASCEND_DEVICE_ID}/eval_${ASCEND_DEVICE_ID}.log 2>&1 -wait - -##################获取训练数据################ -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep -a 'FPS' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk -F " " '{print $2}'|awk 'END {print}'` -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -train_accuracy=`grep -a 'mask |' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/eval_${ASCEND_DEVICE_ID}.log |awk -F " " '{print $3}'|awk 'END {print}'` -# #打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep "||" ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log |awk -F '[|][|]' '{print $2}' >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` -echo "train_accuracy: ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +################基础配置参数,需要模型审视修改################## +# 必选字段(必须在此处定义的参数): Network batch_size RANK_SIZE +# 网络名称,同目录名称 +Network="YOLACT-plus" +# 训练batch_size +batch_size=16 +# 训练使用的npu卡数 +export RANK_SIZE=8 +# 数据集路径,保持为空,不需要修改 --data_path=./data/TrainDataset +data_path="" + +# checkpoint文件路径,以实际路径为准 --pth_path=./checkopint.pth.tar +pth_path='' + +# 训练step +max_iter=1250000 +# 指定训练所使用的npu device卡id +device_id=0 +# 加载数据进程数 +workers=8 + +# 参数校验,data_path为必传参数,其他参数的增删由模型自身决定;此处新增参数需在上面有定义并赋值 +for para in $* +do + if [[ $para == --device_id* ]];then + device_id=`echo ${para#*=}` + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --pth_path* ]];then + pth_path=`echo ${para#*=}` + fi +done + +# 校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi +# 校验是否传入 pth_path , 验证脚本需要传入此参数 +#if [[ $pth_path == "" ]];then +# echo "[Error] para \"pth_path\" must be confing" +# exit 1 +#fi + +# 校验是否指定了device_id,分动态分配device_id与手动指定device_id,此处不需要修改 +if [ $ASCEND_DEVICE_ID ];then + echo "device id is ${ASCEND_DEVICE_ID}" +elif [ ${device_id} ];then + export ASCEND_DEVICE_ID=${device_id} + echo "device id is ${ASCEND_DEVICE_ID}" +else + "[Error] device id must be config" + exit 1 +fi + + + +###############指定训练脚本执行路径############### +# cd到与test文件夹同层级目录下执行脚本,提高兼容性;test_path_dir为包含test文件夹的路径 +cur_path=`pwd` +cur_path_last_dirname=${cur_path##*/} +if [ x"${cur_path_last_dirname}" == x"test" ];then + test_path_dir=${cur_path} + cd .. + cur_path=`pwd` +else + test_path_dir=${cur_path}/test +fi + + +#################创建日志输出目录,不需要修改################# + if [ -d ${test_path_dir}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${test_path_dir}/output/${ASCEND_DEVICE_ID} + mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID + else + mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID + fi + + +#################启动训练脚本################# +#训练开始时间,不需要修改 +start_time=$(date +%s) +# 非平台场景时source 环境变量 +check_etp_flag=`env | grep etp_running_flag` +etp_flag=`echo ${check_etp_flag#*=}` +if [ x"${etp_flag}" != x"true" ];then + source ${test_path_dir}/env_npu.sh +fi + +for((RANK_ID=0;RANK_ID ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & + else + python3.7 -u train.py \ + --data_path=${data_path} \ + --num_workers=${workers} \ + --lr=2e-3 \ + --config=yolact_plus_resnet50_config \ + --max_iter=${max_iter} \ + --resume=${pth_path} \ + --save_interval=62500 \ + --batch_size=${batch_size} > ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & + fi +done +wait +python3.7 eval.py --trained_model=weights/yolact_plus.pth > ${test_path_dir}/output/${ASCEND_DEVICE_ID}/eval_${ASCEND_DEVICE_ID}.log 2>&1 +wait + +##################获取训练数据################ +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep -a 'FPS' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk -F " " '{print $2}'|awk 'END {print}'` +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +train_accuracy=`grep -a 'mask |' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/eval_${ASCEND_DEVICE_ID}.log |awk -F " " '{print $3}'|awk 'END {print}'` +# #打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep "||" ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log |awk -F '[|][|]' '{print $2}' >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` +echo "train_accuracy: ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/test/train_performance_1p.sh b/PyTorch/contrib/cv/detection/YOLACT_plus/test/train_performance_1p.sh index d2d8a4923b..62aacb3977 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/test/train_performance_1p.sh +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/test/train_performance_1p.sh @@ -1,149 +1,149 @@ -#!/bin/bash - -################基础配置参数,需要模型审视修改################## -# 必选字段(必须在此处定义的参数): Network batch_size RANK_SIZE -# 网络名称,同目录名称 -Network="YOLACT-plus" -# 训练batch_size -batch_size=16 -# 训练使用的npu卡数 -export RANK_SIZE=1 -# 数据集路径,保持为空,不需要修改 --data_path=./data/TrainDataset -data_path="" - -# checkpoint文件路径,以实际路径为准 --pth_path=./checkopint.pth.tar -pth_path='' - -# 训练step -max_iter=1000 -# 指定训练所使用的npu device卡id -device_id=0 -# 加载数据进程数 -workers=8 - -# 参数校验,data_path为必传参数,其他参数的增删由模型自身决定;此处新增参数需在上面有定义并赋值 -for para in $* -do - if [[ $para == --device_id* ]];then - device_id=`echo ${para#*=}` - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --pth_path* ]];then - pth_path=`echo ${para#*=}` - fi -done - -# 校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi -# 校验是否传入 pth_path , 验证脚本需要传入此参数 -#if [[ $pth_path == "" ]];then -# echo "[Error] para \"pth_path\" must be confing" -# exit 1 -#fi - -# 校验是否指定了device_id,分动态分配device_id与手动指定device_id,此处不需要修改 -if [ $ASCEND_DEVICE_ID ];then - echo "device id is ${ASCEND_DEVICE_ID}" -elif [ ${device_id} ];then - export ASCEND_DEVICE_ID=${device_id} - echo "device id is ${ASCEND_DEVICE_ID}" -else - "[Error] device id must be config" - exit 1 -fi - - - -###############指定训练脚本执行路径############### -# cd到与test文件夹同层级目录下执行脚本,提高兼容性;test_path_dir为包含test文件夹的路径 -cur_path=`pwd` -cur_path_last_dirname=${cur_path##*/} -if [ x"${cur_path_last_dirname}" == x"test" ];then - test_path_dir=${cur_path} - cd .. - cur_path=`pwd` -else - test_path_dir=${cur_path}/test -fi - - -#################创建日志输出目录,不需要修改################# - if [ -d ${test_path_dir}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${test_path_dir}/output/${ASCEND_DEVICE_ID} - mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID - else - mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID - fi - - -#################启动训练脚本################# -#训练开始时间,不需要修改 -start_time=$(date +%s) -# 非平台场景时source 环境变量 -check_etp_flag=`env | grep etp_running_flag` -etp_flag=`echo ${check_etp_flag#*=}` -if [ x"${etp_flag}" != x"true" ];then - source ${test_path_dir}/env_npu.sh -fi -export RANK_ID=${ASCEND_DEVICE_ID} -python3.7 ./train.py \ - --data_path=${data_path} \ - --num_workers=${workers} \ - --lr=2e-3 \ - --config=yolact_plus_resnet50_config \ - --max_iter=${max_iter} \ - --resume=${pth_path} \ - --save_interval=1000 \ - --batch_size=${batch_size} > ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & -wait - -##################获取训练数据################ -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep -a 'FPS' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk -F " " '{print $2}'|awk 'END {print}'` -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -train_accuracy=`grep -a 'mask |' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/eval_${ASCEND_DEVICE_ID}.log |awk -F " " '{print $3}'|awk 'END {print}'` -# #打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep "||" ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log |awk -F '[|][|]' '{print $2}' >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` -echo "train_accuracy: ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +################基础配置参数,需要模型审视修改################## +# 必选字段(必须在此处定义的参数): Network batch_size RANK_SIZE +# 网络名称,同目录名称 +Network="YOLACT-plus" +# 训练batch_size +batch_size=16 +# 训练使用的npu卡数 +export RANK_SIZE=1 +# 数据集路径,保持为空,不需要修改 --data_path=./data/TrainDataset +data_path="" + +# checkpoint文件路径,以实际路径为准 --pth_path=./checkopint.pth.tar +pth_path='' + +# 训练step +max_iter=1000 +# 指定训练所使用的npu device卡id +device_id=0 +# 加载数据进程数 +workers=8 + +# 参数校验,data_path为必传参数,其他参数的增删由模型自身决定;此处新增参数需在上面有定义并赋值 +for para in $* +do + if [[ $para == --device_id* ]];then + device_id=`echo ${para#*=}` + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --pth_path* ]];then + pth_path=`echo ${para#*=}` + fi +done + +# 校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi +# 校验是否传入 pth_path , 验证脚本需要传入此参数 +#if [[ $pth_path == "" ]];then +# echo "[Error] para \"pth_path\" must be confing" +# exit 1 +#fi + +# 校验是否指定了device_id,分动态分配device_id与手动指定device_id,此处不需要修改 +if [ $ASCEND_DEVICE_ID ];then + echo "device id is ${ASCEND_DEVICE_ID}" +elif [ ${device_id} ];then + export ASCEND_DEVICE_ID=${device_id} + echo "device id is ${ASCEND_DEVICE_ID}" +else + "[Error] device id must be config" + exit 1 +fi + + + +###############指定训练脚本执行路径############### +# cd到与test文件夹同层级目录下执行脚本,提高兼容性;test_path_dir为包含test文件夹的路径 +cur_path=`pwd` +cur_path_last_dirname=${cur_path##*/} +if [ x"${cur_path_last_dirname}" == x"test" ];then + test_path_dir=${cur_path} + cd .. + cur_path=`pwd` +else + test_path_dir=${cur_path}/test +fi + + +#################创建日志输出目录,不需要修改################# + if [ -d ${test_path_dir}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${test_path_dir}/output/${ASCEND_DEVICE_ID} + mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID + else + mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID + fi + + +#################启动训练脚本################# +#训练开始时间,不需要修改 +start_time=$(date +%s) +# 非平台场景时source 环境变量 +check_etp_flag=`env | grep etp_running_flag` +etp_flag=`echo ${check_etp_flag#*=}` +if [ x"${etp_flag}" != x"true" ];then + source ${test_path_dir}/env_npu.sh +fi +export RANK_ID=${ASCEND_DEVICE_ID} +python3.7 ./train.py \ + --data_path=${data_path} \ + --num_workers=${workers} \ + --lr=2e-3 \ + --config=yolact_plus_resnet50_config \ + --max_iter=${max_iter} \ + --resume=${pth_path} \ + --save_interval=1000 \ + --batch_size=${batch_size} > ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & +wait + +##################获取训练数据################ +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep -a 'FPS' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk -F " " '{print $2}'|awk 'END {print}'` +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +train_accuracy=`grep -a 'mask |' ${test_path_dir}/output/${ASCEND_DEVICE_ID}/eval_${ASCEND_DEVICE_ID}.log |awk -F " " '{print $3}'|awk 'END {print}'` +# #打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep "||" ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log |awk -F '[|][|]' '{print $2}' >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` +echo "train_accuracy: ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/train.py b/PyTorch/contrib/cv/detection/YOLACT_plus/train.py index 6d1e302204..63d430a3d3 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/train.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/train.py @@ -1,660 +1,660 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 data import * -from utils.augmentations import SSDAugmentation, BaseTransform -from utils.functions import MovingAverage, SavePath -from utils.logger import Log -from utils import timer -from layers.modules import MultiBoxLoss -from yolact import Yolact -import os -import sys -import time -import math, random -from pathlib import Path -import torch -from torch.autograd import Variable -import torch.nn as nn -import torch.optim as optim -import torch.backends.cudnn as cudnn -import torch.nn.init as init -import torch.utils.data as data -import numpy as np -import argparse -import datetime -from torch.nn.parallel import DistributedDataParallel as DDP -import torch.multiprocessing as mp -import torch.distributed as dist -# Oof -import eval as eval_script -from apex import amp - -def str2bool(v): - return v.lower() in ("yes", "true", "t", "1") - - -parser = argparse.ArgumentParser( - description='Yolact Training Script') -parser.add_argument('--batch_size', default=8, type=int, - help='Batch size for training') -parser.add_argument('--data_path', default=None, type=str, - help='data path') -parser.add_argument('--resume', default=None, type=str, - help='Checkpoint state_dict file to resume training from. If this is "interrupt"' \ - ', the model will resume training from the interrupt file.') -parser.add_argument('--start_iter', default=-1, type=int, - help='Resume training at this iter. If this is -1, the iteration will be' \ - 'determined from the file name.') -parser.add_argument('--fps_start_iter', default=100, type=int, - help='calculate fps at this iter. If this is -1, the iteration will be' \ - 'determined from the file name.') -parser.add_argument('--num_workers', default=0, type=int, - help='Number of workers used in dataloading') -parser.add_argument('--cuda', default=True, type=str2bool, - help='Use CUDA to train model') -parser.add_argument('--lr', '--learning_rate', default=None, type=float, - help='Initial learning rate. Leave as None to read this from the config.') -parser.add_argument('--momentum', default=None, type=float, - help='Momentum for SGD. Leave as None to read this from the config.') -parser.add_argument('--decay', '--weight_decay', default=None, type=float, - help='Weight decay for SGD. Leave as None to read this from the config.') -parser.add_argument('--gamma', default=None, type=float, - help='For each lr step, what to multiply the lr by. Leave as None to read this from the config.') -parser.add_argument('--save_folder', default='weights/', - help='Directory for saving checkpoint models.') -parser.add_argument('--log_folder', default='logs/', - help='Directory for saving logs.') -parser.add_argument('--config', default='yolact_base_config', - help='The config object to use.') -parser.add_argument('--max_iter', default=-1, type=int, - help='num of iter will train') -parser.add_argument('--save_interval', default=2000, type=int, - help='The number of iterations between saving the model.') -parser.add_argument('--validation_size', default=5000, type=int, - help='The number of images to use for validation.') -parser.add_argument('--validation_epoch', default=-1, type=int, - help='Output validation information every n iterations. If -1, do no validation.') -parser.add_argument('--keep_latest', dest='keep_latest', action='store_true', - help='Only keep the latest checkpoint instead of each one.') -parser.add_argument('--keep_latest_interval', default=100000, type=int, - help='When --keep_latest is on, don\'t delete the latest file at these intervals. This should be a multiple of save_interval or 0.') -parser.add_argument('--dataset', default=None, type=str, - help='If specified, override the dataset specified in the config with this one (example: coco2017_dataset).') -parser.add_argument('--no_log', dest='log', action='store_false', - help='Don\'t log per iteration information into log_folder.') -parser.add_argument('--log_gpu', dest='log_gpu', action='store_true', - help='Include GPU information in the logs. Nvidia-smi tends to be slow, so set this with caution.') -parser.add_argument('--no_interrupt', dest='interrupt', action='store_false', - help='Don\'t save an interrupt when KeyboardInterrupt is caught.') -parser.add_argument('--batch_alloc', default=None, type=str, - help='If using multiple GPUS, you can set this to be a comma separated list detailing which GPUs should get what local batch size (It should add up to your total batch size).') -parser.add_argument('--no_autoscale', dest='autoscale', action='store_false', - help='YOLACT will automatically scale the lr and the number of iterations depending on the batch size. Set this if you want to disable that.') -parser.add_argument('--useDDP', default=True, type=bool, help='use DistributedDataParallel or not') -parser.add_argument('--seed', default=None, type=int, help='set PyTorch seed') - -parser.set_defaults(keep_latest=False, log=True, log_gpu=False, interrupt=True, autoscale=True) -args = parser.parse_args() - -# 设置配置文件,无用 -if args.config is not None: - set_cfg(args.config) - -# 设置项目数据集,无用 -if args.dataset is not None: - set_dataset(args.dataset) - -if args.data_path: - cfg.dataset.train_images = args.data_path + '/train2017/' - cfg.dataset.train_info = args.data_path + '/annotations/instances_train2017.json' - -if args.autoscale and args.batch_size != 8: - factor = args.batch_size / 8 - if __name__ == '__main__': - print('Scaling parameters by %.2f to account for a batch size of %d.' % (factor, args.batch_size)) - - cfg.lr *= factor - cfg.max_iter //= factor - cfg.lr_steps = [x // factor for x in cfg.lr_steps] - -if args.max_iter>0: - cfg.max_iter = args.max_iter - -# Update training parameters from the config if necessary -def replace(name): - if getattr(args, name) == None: setattr(args, name, getattr(cfg, name)) - - -# 将args中参数替换为config中预设的值,便于后续调用 -replace('lr') -replace('decay') -replace('gamma') -replace('momentum') - -# This is managed by set_lr -# 两个学习率都有用,在后续自动更新学习率中,可以使用 -cur_lr = args.lr - -# 检查环境 -if torch.npu.device_count() == 0: - print('No GPUs detected. Exiting...') - exit(-1) - -# 当一块显卡中的图像个数大于等于6时,才启用batch normalization -if args.batch_size // torch.npu.device_count() < 6 and (not args.useDDP): - if __name__ == '__main__': - print('Per-NPU batch size is less than the recommended limit for batch norm. Disabling batch norm.') - cfg.freeze_bn = True - -if args.seed is not None: - seed = args.seed - os.environ['PYTHONHASHSEED'] = str(seed) - torch.manual_seed(seed) - torch.cuda.manual_seed(seed) - torch.npu.manual_seed(seed) - torch.cuda.manual_seed_all(seed) - torch.backends.cudnn.deterministic = True - print('Finish set seed, seed is :', seed) - -loss_types = ['B', 'C', 'M', 'P', 'D', 'E', 'S', 'I'] - -if torch.npu.is_available(): - print("npu environment is okay!, and current device count is", torch.npu.device_count()) - - -# if args.cuda: -# torch.set_default_tensor_type('torch.cuda.FloatTensor') -# if not args.cuda: -# print("WARNING: It looks like you have a CUDA device, but aren't " + -# "using CUDA.\nRun with --cuda for optimal training speed.") -# torch.set_default_tensor_type('torch.FloatTensor') -# else: -# torch.set_default_tensor_type('torch.FloatTensor') - -class NetLoss(nn.Module): - """ - A wrapper for running the network and computing the loss - This is so we can more efficiently use DataParallel. - - 损失函数模块,YOLACT只使用Multibox Loss,但单独封装NetLoss模块的目的是多卡训练 - """ - - def __init__(self, net: Yolact, criterion: MultiBoxLoss): - super().__init__() - - self.net = net - self.criterion = criterion - - def forward(self, images, targets, masks, num_crowds): - preds = self.net(images) - losses = self.criterion(self.net, preds, targets, masks, num_crowds) - return losses - - -class CustomDataParallel(nn.DataParallel): - """ - This is a custom version of DataParallel that works better with our training data. - It should also be faster than the general case. - """ - - def scatter(self, inputs, kwargs, device_ids): - # More like scatter and data prep at the same time. The point is we prep the data in such a way - # that no scatter is necessary, and there's no need to shuffle stuff around different GPUs. - devices = ['cuda:' + str(x) for x in device_ids] - splits = prepare_data(inputs[0], devices, allocation=args.batch_alloc) - - return [[split[device_idx] for split in splits] for device_idx in range(len(devices))], \ - [kwargs] * len(devices) - - def gather(self, outputs, output_device): - out = {} - - for k in outputs[0]: - out[k] = torch.stack([output[k].to(output_device) for output in outputs]) - - return out - - -class ScatterWrapper: - """ Input is any number of lists. This will preserve them through a dataparallel scatter. """ - - def __init__(self, *args): - for arg in args: - if not isinstance(arg, list): - print('Warning: ScatterWrapper got input of non-list type.') - self.args = args - self.batch_size = len(args[0]) - - def make_mask(self): - out = torch.Tensor(list(range(self.batch_size))).long() - if args.cuda: - return out.npu() - else: - return out - - def get_args(self, mask): - device = mask.device - mask = [int(x) for x in mask] - out_args = [[] for _ in self.args] - - for out, arg in zip(out_args, self.args): - for idx in mask: - x = arg[idx] - if isinstance(x, torch.Tensor): - x = x.to(device) - out.append(x) - - return out_args - - -def train(args): - # 创建模型权重文件存储目录 - if not os.path.exists(args.save_folder): - os.mkdir(args.save_folder) - - args.rank_id = int(os.environ['RANK_ID']) - args.world_size = int(os.environ['RANK_SIZE']) - args.device = torch.device(f'npu:{args.rank_id}') - torch.npu.set_device(args.device) - - args.is_master_node = args.world_size == 1 or args.rank_id == 0 - - if args.is_master_node: - print(args) - - os.environ['MASTER_ADDR'] = '127.0.0.1' - os.environ['MASTER_PORT'] = '83215' - dist.init_process_group(backend='hccl', world_size=args.world_size, rank=args.rank_id) - - # 创建数据集,dataset为训练数据集 - dataset = COCODetection(image_path=cfg.dataset.train_images, - info_file=cfg.dataset.train_info, - transform=SSDAugmentation(MEANS)) - if args.world_size>1: - train_sampler = torch.utils.data.distributed.DistributedSampler(dataset) - else: - train_sampler = None - if args.validation_epoch > 0: - # 调整eval.py脚本对应参数 - setup_eval() - - # 创建数据集,val_dataset为验证数据集,5000张图像 - val_dataset = COCODetection(image_path=cfg.dataset.valid_images, - info_file=cfg.dataset.valid_info, - transform=BaseTransform(MEANS)) - - # Parallel wraps the underlying module, but when saving and loading we don't want that - yolact_net = Yolact() - net = yolact_net - net.train() - - if args.log: - log = Log(cfg.name+'_time_'+time.strftime('%Y-%m-%d-%H-%M'), args.log_folder, - overwrite=(args.resume is None), log_gpu_stats=args.log_gpu) # 构造日志类 - - # I don't use the timer during training (I use a different timing method). - # Apparently there's a race condition with multiple GPUs, so disable it just to be safe. - timer.disable_all() - - # Both of these can set args.resume to None, so do them before the check - if args.resume == 'interrupt': - args.resume = SavePath.get_interrupt(args.save_folder) - elif args.resume == 'latest': - args.resume = SavePath.get_latest(args.save_folder, cfg.name) - - if args.resume is not None and args.resume != '': - print('Resuming training, loading {}...'.format(args.resume)) - yolact_net.load_weights(args.resume) - - if args.start_iter == -1: - args.start_iter = SavePath.from_str(args.resume).iteration - else: - print('Initializing weights...') - yolact_net.init_weights(backbone_path=args.save_folder + cfg.backbone.path) - - # 损失函数,multibox loss - # threshold : 门限阈值 - # pos_threshold 即为 : 高于这个值,那么就说明预测正确足够confident,即可以认为识别正确 - # pos_threshold 即为: 低于这个值,那么就可以自信认为识别错误 - - # ohem_negpos_ratio - criterion = MultiBoxLoss(num_classes=cfg.num_classes, - pos_threshold=cfg.positive_iou_threshold, - neg_threshold=cfg.negative_iou_threshold, - negpos_ratio=cfg.ohem_negpos_ratio) - - if args.batch_alloc is not None: - args.batch_alloc = [int(x) for x in args.batch_alloc.split(',')] - if sum(args.batch_alloc) != args.batch_size: - print('Error: Batch allocation (%s) does not sum to batch size (%s).' % (args.batch_alloc, args.batch_size)) - exit(-1) - - if args.cuda: - net = net.to(args.device) - criterion = criterion.to(args.device) - # 优化器SGD,随机梯度下降法 - optimizer = optim.SGD(net.parameters(), lr=args.lr, momentum=args.momentum, weight_decay=args.decay) - net, optimizer = amp.initialize(net, optimizer, opt_level="O0", loss_scale=16) - net = nn.parallel.DistributedDataParallel(net, device_ids=[args.rank_id]) - else: - net = net.to('cpu') - net.src_device_obj = torch.device('cpu') - - # 优化器SGD,随机梯度下降法 - optimizer = optim.SGD(net.parameters(), lr=args.lr, momentum=args.momentum, weight_decay=args.decay) - - # Initialize everything - if not cfg.freeze_bn: yolact_net.freeze_bn() # Freeze bn so we don't kill our means - if args.cuda: - yolact_net(torch.zeros(1, 3, cfg.max_size, cfg.max_size).npu()) - else: - yolact_net(torch.zeros(1, 3, cfg.max_size, cfg.max_size)) - if not cfg.freeze_bn: yolact_net.freeze_bn(True) - - # loss counters - loc_loss = 0 - conf_loss = 0 - iteration = max(args.start_iter, 0) - last_time = time.time() - - epoch_size = len(dataset) // (args.batch_size * args.world_size) - num_epochs = math.ceil(cfg.max_iter / epoch_size) - - # Which learning rate adjustment step are we on? lr' = lr * gamma ^ step_index - step_index = 0 - if args.world_size>1: - data_loader = data.DataLoader(dataset, args.batch_size, - num_workers=args.num_workers, - shuffle=False, - collate_fn=detection_collate, - pin_memory=True, sampler=train_sampler) - else: - data_loader = data.DataLoader(dataset, args.batch_size, - num_workers=args.num_workers, - shuffle=True, - collate_fn=detection_collate, - pin_memory=True) - - save_path = lambda epoch, iteration: SavePath(cfg.name, epoch, iteration).get_path(root=args.save_folder) - time_avg = MovingAverage() - - global loss_types # Forms the print order - loss_avgs = {k: MovingAverage(100) for k in loss_types} - - print('Begin training! NPU :', args.rank_id, '[', time.time(), ']') - print() - # try-except so you can use ctrl+c to save early and stop training - try: - for epoch in range(num_epochs): - # Resume from start_iter - if (epoch + 1) * epoch_size < iteration: - continue - if train_sampler: - train_sampler.set_epoch(epoch) - for idx, datum in enumerate(data_loader): - # Stop if we've reached an epoch if we're resuming from start_iter - if iteration == (epoch + 1) * epoch_size: - break - - # Stop at the configured number of iterations even if mid-epoch - if iteration == cfg.max_iter / args.world_size: - break - - # Change a config setting if we've reached the specified iteration - changed = False - for change in cfg.delayed_settings: - if iteration >= change[0]: - changed = True - cfg.replace(change[1]) - - # Reset the loss averages because things might have changed - for avg in loss_avgs: - avg.reset() - - # If a config setting was changed, remove it from the list so we don't keep checking - if changed: - cfg.delayed_settings = [x for x in cfg.delayed_settings if x[0] > iteration] - - # Warm up by linearly interpolating the learning rate from some smaller value - if cfg.lr_warmup_until > 0 and iteration <= cfg.lr_warmup_until: - set_lr(optimizer, - (args.lr - cfg.lr_warmup_init) * (iteration / cfg.lr_warmup_until) + cfg.lr_warmup_init) - - # Adjust the learning rate at the given iterations, but also if we resume from past that iteration - while step_index < len(cfg.lr_steps) and iteration >= cfg.lr_steps[step_index]: - step_index += 1 - set_lr(optimizer, args.lr * (args.gamma ** step_index)) - - prep_data_device = ['npu:' + str(args.rank_id)] - datum[0] = [item[1] for item in datum[0]] - images, targets, masks, num_crowds = prepare_data(datum, prep_data_device) - - out = net(images[0]) - optimizer.zero_grad() - wrapper = ScatterWrapper(targets, masks, num_crowds) - losses = criterion(net.module, out, wrapper, wrapper.make_mask()) - - losses = {k: (v).mean() for k, v in losses.items()} # Mean here because Dataparallel - loss = sum([losses[k] for k in losses]) - - # no_inf_mean removes some components from the loss, so make sure to backward through all of it - # all_loss = sum([v.mean() for v in losses.values()]) - - # Backprop - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - if torch.isfinite(loss).item(): - optimizer.step() - print('\t finish one step! NPU :', args.rank_id, '[', time.time(), ']') - - # Add the loss to the moving average for bookkeeping - for k in losses: - loss_avgs[k].add(losses[k].item()) - - cur_time = time.time() - elapsed = cur_time - last_time - last_time = cur_time - - # Exclude graph setup from the timing information - if iteration > args.fps_start_iter: - time_avg.add(elapsed) - - if iteration % 10 == 0: - eta_str = \ - str(datetime.timedelta(seconds=(cfg.max_iter - iteration) * time_avg.get_avg())).split('.')[0] - - total = sum([loss_avgs[k].get_avg() for k in losses]) - loss_labels = sum([[k, loss_avgs[k].get_avg()] for k in loss_types if k in losses], []) - - print(('[%3d] %7d ||' + ( - ' %s: %.3f |' * len(losses)) + ' T: %.3f || ETA: %s || timer: %.3f' + ' || NPU: ' + str( - args.rank_id)) - % tuple([epoch, iteration] + loss_labels + [total, eta_str, elapsed]), flush=True) - if args.log: - precision = 5 - loss_info = {k: round(losses[k].item(), precision) for k in losses} - loss_info['T'] = round(loss.item(), precision) - - if args.log_gpu: - log.log_gpu_stats = (iteration % 10 == 0) # nvidia-smi is sloooow - - log.log('train', loss=loss_info, epoch=epoch, iter=iteration, - lr=round(cur_lr, 10), elapsed=elapsed) - - log.log_gpu_stats = args.log_gpu - - iteration += 1 - - if iteration % args.save_interval == 0 and iteration != args.start_iter: - if args.keep_latest: - latest = SavePath.get_latest(args.save_folder, cfg.name) - - print('Saving state, iter:', iteration) - if args.is_master_node: - yolact_net.save_weights(save_path(epoch, iteration)) - - if args.keep_latest and latest is not None: - if args.keep_latest_interval <= 0 or iteration % args.keep_latest_interval != args.save_interval: - print('Deleting old save...') - os.remove(latest) - - # This is done per epoch - if args.validation_epoch > 0: - if epoch % args.validation_epoch == 0 and epoch > 0: - compute_validation_map(epoch, iteration, yolact_net, val_dataset, log if args.log else None) - - log.log('FPS', fps=args.world_size * args.batch_size / time_avg.get_avg()) - print('FPS', args.world_size * args.batch_size / time_avg.get_avg()) - - # Compute validation mAP after training is finished - # compute_validation_map(epoch, iteration, yolact_net, val_dataset, log if args.log else None) - except KeyboardInterrupt: - if args.interrupt: - print('Stopping early. Saving network...') - - # Delete previous copy of the interrupted network so we don't spam the weights folder - SavePath.remove_interrupt(args.save_folder) - - if args.is_master_node: - yolact_net.save_weights(save_path(epoch, repr(iteration) + '_interrupt')) - exit() - - if args.is_master_node: - yolact_net.save_weights('./weights/yolact_plus.pth') - - -def set_lr(optimizer, new_lr): - for param_group in optimizer.param_groups: - param_group['lr'] = new_lr - - global cur_lr - cur_lr = new_lr - - -def gradinator(x): - x.requires_grad = False - return x - - -def prepare_data(datum, devices: list = None, allocation: list = None): - with torch.no_grad(): - if devices is None: - devices = ['npu:0'] if args.cuda else ['cpu'] - if allocation is None: - allocation = [args.batch_size // len(devices)] * (len(devices) - 1) - allocation.append(args.batch_size - sum(allocation)) # The rest might need more/less - - images, (targets, masks, num_crowds) = datum - - cur_idx = 0 - for device, alloc in zip(devices, allocation): - for _ in range(alloc): - images[cur_idx] = gradinator(images[cur_idx].to(device)) - targets[cur_idx] = gradinator(targets[cur_idx].to(device)) - masks[cur_idx] = gradinator(masks[cur_idx].to(device)) - cur_idx += 1 - - if cfg.preserve_aspect_ratio: - # Choose a random size from the batch - _, h, w = images[random.randint(0, len(images) - 1)].size() - - for idx, (image, target, mask, num_crowd) in enumerate(zip(images, targets, masks, num_crowds)): - images[idx], targets[idx], masks[idx], num_crowds[idx] \ - = enforce_size(image, target, mask, num_crowd, w, h) - - cur_idx = 0 - split_images, split_targets, split_masks, split_numcrowds \ - = [[None for alloc in allocation] for _ in range(4)] - - for device_idx, alloc in enumerate(allocation): - split_images[device_idx] = torch.stack(images[cur_idx:cur_idx + alloc], dim=0) - split_targets[device_idx] = targets[cur_idx:cur_idx + alloc] - split_masks[device_idx] = masks[cur_idx:cur_idx + alloc] - split_numcrowds[device_idx] = num_crowds[cur_idx:cur_idx + alloc] - - cur_idx += alloc - - return split_images, split_targets, split_masks, split_numcrowds - - -def no_inf_mean(x: torch.Tensor): - """ - Computes the mean of a vector, throwing out all inf values. - If there are no non-inf values, this will return inf (i.e., just the normal mean). - """ - - no_inf = [a for a in x if torch.isfinite(a)] - - if len(no_inf) > 0: - return sum(no_inf) / len(no_inf) - else: - return x.mean() - - -def compute_validation_loss(net, data_loader, criterion): - global loss_types - - with torch.no_grad(): - losses = {} - - # Don't switch to eval mode because we want to get losses - iterations = 0 - for datum in data_loader: - images, targets, masks, num_crowds = prepare_data(datum) - out = net(images) - - wrapper = ScatterWrapper(targets, masks, num_crowds) - _losses = criterion(out, wrapper, wrapper.make_mask()) - - for k, v in _losses.items(): - v = v.mean().item() - if k in losses: - losses[k] += v - else: - losses[k] = v - - iterations += 1 - if args.validation_size <= iterations * args.batch_size: - break - - for k in losses: - losses[k] /= iterations - - loss_labels = sum([[k, losses[k]] for k in loss_types if k in losses], []) - print(('Validation ||' + (' %s: %.3f |' * len(losses)) + ')') % tuple(loss_labels), flush=True) - - -def compute_validation_map(epoch, iteration, yolact_net, dataset, log: Log = None): - with torch.no_grad(): - yolact_net.eval() - - start = time.time() - print() - print("Computing validation mAP (this may take a while)...", flush=True) - val_info = eval_script.evaluate(yolact_net, dataset, train_mode=True, trainCuda=args.cuda) - end = time.time() - - if log is not None: - log.log('val', val_info, elapsed=(end - start), epoch=epoch, iter=iteration) - - yolact_net.train() - - -def setup_eval(): - eval_script.parse_args(['--no_bar', '--max_images=' + str(args.validation_size)]) - - -if __name__ == '__main__': - train(args) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 data import * +from utils.augmentations import SSDAugmentation, BaseTransform +from utils.functions import MovingAverage, SavePath +from utils.logger import Log +from utils import timer +from layers.modules import MultiBoxLoss +from yolact import Yolact +import os +import sys +import time +import math, random +from pathlib import Path +import torch +from torch.autograd import Variable +import torch.nn as nn +import torch.optim as optim +import torch.backends.cudnn as cudnn +import torch.nn.init as init +import torch.utils.data as data +import numpy as np +import argparse +import datetime +from torch.nn.parallel import DistributedDataParallel as DDP +import torch.multiprocessing as mp +import torch.distributed as dist +# Oof +import eval as eval_script +from apex import amp + +def str2bool(v): + return v.lower() in ("yes", "true", "t", "1") + + +parser = argparse.ArgumentParser( + description='Yolact Training Script') +parser.add_argument('--batch_size', default=8, type=int, + help='Batch size for training') +parser.add_argument('--data_path', default=None, type=str, + help='data path') +parser.add_argument('--resume', default=None, type=str, + help='Checkpoint state_dict file to resume training from. If this is "interrupt"' \ + ', the model will resume training from the interrupt file.') +parser.add_argument('--start_iter', default=-1, type=int, + help='Resume training at this iter. If this is -1, the iteration will be' \ + 'determined from the file name.') +parser.add_argument('--fps_start_iter', default=100, type=int, + help='calculate fps at this iter. If this is -1, the iteration will be' \ + 'determined from the file name.') +parser.add_argument('--num_workers', default=0, type=int, + help='Number of workers used in dataloading') +parser.add_argument('--cuda', default=True, type=str2bool, + help='Use CUDA to train model') +parser.add_argument('--lr', '--learning_rate', default=None, type=float, + help='Initial learning rate. Leave as None to read this from the config.') +parser.add_argument('--momentum', default=None, type=float, + help='Momentum for SGD. Leave as None to read this from the config.') +parser.add_argument('--decay', '--weight_decay', default=None, type=float, + help='Weight decay for SGD. Leave as None to read this from the config.') +parser.add_argument('--gamma', default=None, type=float, + help='For each lr step, what to multiply the lr by. Leave as None to read this from the config.') +parser.add_argument('--save_folder', default='weights/', + help='Directory for saving checkpoint models.') +parser.add_argument('--log_folder', default='logs/', + help='Directory for saving logs.') +parser.add_argument('--config', default='yolact_base_config', + help='The config object to use.') +parser.add_argument('--max_iter', default=-1, type=int, + help='num of iter will train') +parser.add_argument('--save_interval', default=2000, type=int, + help='The number of iterations between saving the model.') +parser.add_argument('--validation_size', default=5000, type=int, + help='The number of images to use for validation.') +parser.add_argument('--validation_epoch', default=-1, type=int, + help='Output validation information every n iterations. If -1, do no validation.') +parser.add_argument('--keep_latest', dest='keep_latest', action='store_true', + help='Only keep the latest checkpoint instead of each one.') +parser.add_argument('--keep_latest_interval', default=100000, type=int, + help='When --keep_latest is on, don\'t delete the latest file at these intervals. This should be a multiple of save_interval or 0.') +parser.add_argument('--dataset', default=None, type=str, + help='If specified, override the dataset specified in the config with this one (example: coco2017_dataset).') +parser.add_argument('--no_log', dest='log', action='store_false', + help='Don\'t log per iteration information into log_folder.') +parser.add_argument('--log_gpu', dest='log_gpu', action='store_true', + help='Include GPU information in the logs. Nvidia-smi tends to be slow, so set this with caution.') +parser.add_argument('--no_interrupt', dest='interrupt', action='store_false', + help='Don\'t save an interrupt when KeyboardInterrupt is caught.') +parser.add_argument('--batch_alloc', default=None, type=str, + help='If using multiple GPUS, you can set this to be a comma separated list detailing which GPUs should get what local batch size (It should add up to your total batch size).') +parser.add_argument('--no_autoscale', dest='autoscale', action='store_false', + help='YOLACT will automatically scale the lr and the number of iterations depending on the batch size. Set this if you want to disable that.') +parser.add_argument('--useDDP', default=True, type=bool, help='use DistributedDataParallel or not') +parser.add_argument('--seed', default=None, type=int, help='set PyTorch seed') + +parser.set_defaults(keep_latest=False, log=True, log_gpu=False, interrupt=True, autoscale=True) +args = parser.parse_args() + +# 设置配置文件,无用 +if args.config is not None: + set_cfg(args.config) + +# 设置项目数据集,无用 +if args.dataset is not None: + set_dataset(args.dataset) + +if args.data_path: + cfg.dataset.train_images = args.data_path + '/train2017/' + cfg.dataset.train_info = args.data_path + '/annotations/instances_train2017.json' + +if args.autoscale and args.batch_size != 8: + factor = args.batch_size / 8 + if __name__ == '__main__': + print('Scaling parameters by %.2f to account for a batch size of %d.' % (factor, args.batch_size)) + + cfg.lr *= factor + cfg.max_iter //= factor + cfg.lr_steps = [x // factor for x in cfg.lr_steps] + +if args.max_iter>0: + cfg.max_iter = args.max_iter + +# Update training parameters from the config if necessary +def replace(name): + if getattr(args, name) == None: setattr(args, name, getattr(cfg, name)) + + +# 将args中参数替换为config中预设的值,便于后续调用 +replace('lr') +replace('decay') +replace('gamma') +replace('momentum') + +# This is managed by set_lr +# 两个学习率都有用,在后续自动更新学习率中,可以使用 +cur_lr = args.lr + +# 检查环境 +if torch.npu.device_count() == 0: + print('No GPUs detected. Exiting...') + exit(-1) + +# 当一块显卡中的图像个数大于等于6时,才启用batch normalization +if args.batch_size // torch.npu.device_count() < 6 and (not args.useDDP): + if __name__ == '__main__': + print('Per-NPU batch size is less than the recommended limit for batch norm. Disabling batch norm.') + cfg.freeze_bn = True + +if args.seed is not None: + seed = args.seed + os.environ['PYTHONHASHSEED'] = str(seed) + torch.manual_seed(seed) + torch.cuda.manual_seed(seed) + torch.npu.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + torch.backends.cudnn.deterministic = True + print('Finish set seed, seed is :', seed) + +loss_types = ['B', 'C', 'M', 'P', 'D', 'E', 'S', 'I'] + +if torch.npu.is_available(): + print("npu environment is okay!, and current device count is", torch.npu.device_count()) + + +# if args.cuda: +# torch.set_default_tensor_type('torch.cuda.FloatTensor') +# if not args.cuda: +# print("WARNING: It looks like you have a CUDA device, but aren't " + +# "using CUDA.\nRun with --cuda for optimal training speed.") +# torch.set_default_tensor_type('torch.FloatTensor') +# else: +# torch.set_default_tensor_type('torch.FloatTensor') + +class NetLoss(nn.Module): + """ + A wrapper for running the network and computing the loss + This is so we can more efficiently use DataParallel. + + 损失函数模块,YOLACT只使用Multibox Loss,但单独封装NetLoss模块的目的是多卡训练 + """ + + def __init__(self, net: Yolact, criterion: MultiBoxLoss): + super().__init__() + + self.net = net + self.criterion = criterion + + def forward(self, images, targets, masks, num_crowds): + preds = self.net(images) + losses = self.criterion(self.net, preds, targets, masks, num_crowds) + return losses + + +class CustomDataParallel(nn.DataParallel): + """ + This is a custom version of DataParallel that works better with our training data. + It should also be faster than the general case. + """ + + def scatter(self, inputs, kwargs, device_ids): + # More like scatter and data prep at the same time. The point is we prep the data in such a way + # that no scatter is necessary, and there's no need to shuffle stuff around different GPUs. + devices = ['cuda:' + str(x) for x in device_ids] + splits = prepare_data(inputs[0], devices, allocation=args.batch_alloc) + + return [[split[device_idx] for split in splits] for device_idx in range(len(devices))], \ + [kwargs] * len(devices) + + def gather(self, outputs, output_device): + out = {} + + for k in outputs[0]: + out[k] = torch.stack([output[k].to(output_device) for output in outputs]) + + return out + + +class ScatterWrapper: + """ Input is any number of lists. This will preserve them through a dataparallel scatter. """ + + def __init__(self, *args): + for arg in args: + if not isinstance(arg, list): + print('Warning: ScatterWrapper got input of non-list type.') + self.args = args + self.batch_size = len(args[0]) + + def make_mask(self): + out = torch.Tensor(list(range(self.batch_size))).long() + if args.cuda: + return out.npu() + else: + return out + + def get_args(self, mask): + device = mask.device + mask = [int(x) for x in mask] + out_args = [[] for _ in self.args] + + for out, arg in zip(out_args, self.args): + for idx in mask: + x = arg[idx] + if isinstance(x, torch.Tensor): + x = x.to(device) + out.append(x) + + return out_args + + +def train(args): + # 创建模型权重文件存储目录 + if not os.path.exists(args.save_folder): + os.mkdir(args.save_folder) + + args.rank_id = int(os.environ['RANK_ID']) + args.world_size = int(os.environ['RANK_SIZE']) + args.device = torch.device(f'npu:{args.rank_id}') + torch.npu.set_device(args.device) + + args.is_master_node = args.world_size == 1 or args.rank_id == 0 + + if args.is_master_node: + print(args) + + os.environ['MASTER_ADDR'] = '127.0.0.1' + os.environ['MASTER_PORT'] = '83215' + dist.init_process_group(backend='hccl', world_size=args.world_size, rank=args.rank_id) + + # 创建数据集,dataset为训练数据集 + dataset = COCODetection(image_path=cfg.dataset.train_images, + info_file=cfg.dataset.train_info, + transform=SSDAugmentation(MEANS)) + if args.world_size>1: + train_sampler = torch.utils.data.distributed.DistributedSampler(dataset) + else: + train_sampler = None + if args.validation_epoch > 0: + # 调整eval.py脚本对应参数 + setup_eval() + + # 创建数据集,val_dataset为验证数据集,5000张图像 + val_dataset = COCODetection(image_path=cfg.dataset.valid_images, + info_file=cfg.dataset.valid_info, + transform=BaseTransform(MEANS)) + + # Parallel wraps the underlying module, but when saving and loading we don't want that + yolact_net = Yolact() + net = yolact_net + net.train() + + if args.log: + log = Log(cfg.name+'_time_'+time.strftime('%Y-%m-%d-%H-%M'), args.log_folder, + overwrite=(args.resume is None), log_gpu_stats=args.log_gpu) # 构造日志类 + + # I don't use the timer during training (I use a different timing method). + # Apparently there's a race condition with multiple GPUs, so disable it just to be safe. + timer.disable_all() + + # Both of these can set args.resume to None, so do them before the check + if args.resume == 'interrupt': + args.resume = SavePath.get_interrupt(args.save_folder) + elif args.resume == 'latest': + args.resume = SavePath.get_latest(args.save_folder, cfg.name) + + if args.resume is not None and args.resume != '': + print('Resuming training, loading {}...'.format(args.resume)) + yolact_net.load_weights(args.resume) + + if args.start_iter == -1: + args.start_iter = SavePath.from_str(args.resume).iteration + else: + print('Initializing weights...') + yolact_net.init_weights(backbone_path=args.save_folder + cfg.backbone.path) + + # 损失函数,multibox loss + # threshold : 门限阈值 + # pos_threshold 即为 : 高于这个值,那么就说明预测正确足够confident,即可以认为识别正确 + # pos_threshold 即为: 低于这个值,那么就可以自信认为识别错误 + + # ohem_negpos_ratio + criterion = MultiBoxLoss(num_classes=cfg.num_classes, + pos_threshold=cfg.positive_iou_threshold, + neg_threshold=cfg.negative_iou_threshold, + negpos_ratio=cfg.ohem_negpos_ratio) + + if args.batch_alloc is not None: + args.batch_alloc = [int(x) for x in args.batch_alloc.split(',')] + if sum(args.batch_alloc) != args.batch_size: + print('Error: Batch allocation (%s) does not sum to batch size (%s).' % (args.batch_alloc, args.batch_size)) + exit(-1) + + if args.cuda: + net = net.to(args.device) + criterion = criterion.to(args.device) + # 优化器SGD,随机梯度下降法 + optimizer = optim.SGD(net.parameters(), lr=args.lr, momentum=args.momentum, weight_decay=args.decay) + net, optimizer = amp.initialize(net, optimizer, opt_level="O0", loss_scale=16) + net = nn.parallel.DistributedDataParallel(net, device_ids=[args.rank_id]) + else: + net = net.to('cpu') + net.src_device_obj = torch.device('cpu') + + # 优化器SGD,随机梯度下降法 + optimizer = optim.SGD(net.parameters(), lr=args.lr, momentum=args.momentum, weight_decay=args.decay) + + # Initialize everything + if not cfg.freeze_bn: yolact_net.freeze_bn() # Freeze bn so we don't kill our means + if args.cuda: + yolact_net(torch.zeros(1, 3, cfg.max_size, cfg.max_size).npu()) + else: + yolact_net(torch.zeros(1, 3, cfg.max_size, cfg.max_size)) + if not cfg.freeze_bn: yolact_net.freeze_bn(True) + + # loss counters + loc_loss = 0 + conf_loss = 0 + iteration = max(args.start_iter, 0) + last_time = time.time() + + epoch_size = len(dataset) // (args.batch_size * args.world_size) + num_epochs = math.ceil(cfg.max_iter / epoch_size) + + # Which learning rate adjustment step are we on? lr' = lr * gamma ^ step_index + step_index = 0 + if args.world_size>1: + data_loader = data.DataLoader(dataset, args.batch_size, + num_workers=args.num_workers, + shuffle=False, + collate_fn=detection_collate, + pin_memory=True, sampler=train_sampler) + else: + data_loader = data.DataLoader(dataset, args.batch_size, + num_workers=args.num_workers, + shuffle=True, + collate_fn=detection_collate, + pin_memory=True) + + save_path = lambda epoch, iteration: SavePath(cfg.name, epoch, iteration).get_path(root=args.save_folder) + time_avg = MovingAverage() + + global loss_types # Forms the print order + loss_avgs = {k: MovingAverage(100) for k in loss_types} + + print('Begin training! NPU :', args.rank_id, '[', time.time(), ']') + print() + # try-except so you can use ctrl+c to save early and stop training + try: + for epoch in range(num_epochs): + # Resume from start_iter + if (epoch + 1) * epoch_size < iteration: + continue + if train_sampler: + train_sampler.set_epoch(epoch) + for idx, datum in enumerate(data_loader): + # Stop if we've reached an epoch if we're resuming from start_iter + if iteration == (epoch + 1) * epoch_size: + break + + # Stop at the configured number of iterations even if mid-epoch + if iteration == cfg.max_iter / args.world_size: + break + + # Change a config setting if we've reached the specified iteration + changed = False + for change in cfg.delayed_settings: + if iteration >= change[0]: + changed = True + cfg.replace(change[1]) + + # Reset the loss averages because things might have changed + for avg in loss_avgs: + avg.reset() + + # If a config setting was changed, remove it from the list so we don't keep checking + if changed: + cfg.delayed_settings = [x for x in cfg.delayed_settings if x[0] > iteration] + + # Warm up by linearly interpolating the learning rate from some smaller value + if cfg.lr_warmup_until > 0 and iteration <= cfg.lr_warmup_until: + set_lr(optimizer, + (args.lr - cfg.lr_warmup_init) * (iteration / cfg.lr_warmup_until) + cfg.lr_warmup_init) + + # Adjust the learning rate at the given iterations, but also if we resume from past that iteration + while step_index < len(cfg.lr_steps) and iteration >= cfg.lr_steps[step_index]: + step_index += 1 + set_lr(optimizer, args.lr * (args.gamma ** step_index)) + + prep_data_device = ['npu:' + str(args.rank_id)] + datum[0] = [item[1] for item in datum[0]] + images, targets, masks, num_crowds = prepare_data(datum, prep_data_device) + + out = net(images[0]) + optimizer.zero_grad() + wrapper = ScatterWrapper(targets, masks, num_crowds) + losses = criterion(net.module, out, wrapper, wrapper.make_mask()) + + losses = {k: (v).mean() for k, v in losses.items()} # Mean here because Dataparallel + loss = sum([losses[k] for k in losses]) + + # no_inf_mean removes some components from the loss, so make sure to backward through all of it + # all_loss = sum([v.mean() for v in losses.values()]) + + # Backprop + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + if torch.isfinite(loss).item(): + optimizer.step() + print('\t finish one step! NPU :', args.rank_id, '[', time.time(), ']') + + # Add the loss to the moving average for bookkeeping + for k in losses: + loss_avgs[k].add(losses[k].item()) + + cur_time = time.time() + elapsed = cur_time - last_time + last_time = cur_time + + # Exclude graph setup from the timing information + if iteration > args.fps_start_iter: + time_avg.add(elapsed) + + if iteration % 10 == 0: + eta_str = \ + str(datetime.timedelta(seconds=(cfg.max_iter - iteration) * time_avg.get_avg())).split('.')[0] + + total = sum([loss_avgs[k].get_avg() for k in losses]) + loss_labels = sum([[k, loss_avgs[k].get_avg()] for k in loss_types if k in losses], []) + + print(('[%3d] %7d ||' + ( + ' %s: %.3f |' * len(losses)) + ' T: %.3f || ETA: %s || timer: %.3f' + ' || NPU: ' + str( + args.rank_id)) + % tuple([epoch, iteration] + loss_labels + [total, eta_str, elapsed]), flush=True) + if args.log: + precision = 5 + loss_info = {k: round(losses[k].item(), precision) for k in losses} + loss_info['T'] = round(loss.item(), precision) + + if args.log_gpu: + log.log_gpu_stats = (iteration % 10 == 0) # nvidia-smi is sloooow + + log.log('train', loss=loss_info, epoch=epoch, iter=iteration, + lr=round(cur_lr, 10), elapsed=elapsed) + + log.log_gpu_stats = args.log_gpu + + iteration += 1 + + if iteration % args.save_interval == 0 and iteration != args.start_iter: + if args.keep_latest: + latest = SavePath.get_latest(args.save_folder, cfg.name) + + print('Saving state, iter:', iteration) + if args.is_master_node: + yolact_net.save_weights(save_path(epoch, iteration)) + + if args.keep_latest and latest is not None: + if args.keep_latest_interval <= 0 or iteration % args.keep_latest_interval != args.save_interval: + print('Deleting old save...') + os.remove(latest) + + # This is done per epoch + if args.validation_epoch > 0: + if epoch % args.validation_epoch == 0 and epoch > 0: + compute_validation_map(epoch, iteration, yolact_net, val_dataset, log if args.log else None) + + log.log('FPS', fps=args.world_size * args.batch_size / time_avg.get_avg()) + print('FPS', args.world_size * args.batch_size / time_avg.get_avg()) + + # Compute validation mAP after training is finished + # compute_validation_map(epoch, iteration, yolact_net, val_dataset, log if args.log else None) + except KeyboardInterrupt: + if args.interrupt: + print('Stopping early. Saving network...') + + # Delete previous copy of the interrupted network so we don't spam the weights folder + SavePath.remove_interrupt(args.save_folder) + + if args.is_master_node: + yolact_net.save_weights(save_path(epoch, repr(iteration) + '_interrupt')) + exit() + + if args.is_master_node: + yolact_net.save_weights('./weights/yolact_plus.pth') + + +def set_lr(optimizer, new_lr): + for param_group in optimizer.param_groups: + param_group['lr'] = new_lr + + global cur_lr + cur_lr = new_lr + + +def gradinator(x): + x.requires_grad = False + return x + + +def prepare_data(datum, devices: list = None, allocation: list = None): + with torch.no_grad(): + if devices is None: + devices = ['npu:0'] if args.cuda else ['cpu'] + if allocation is None: + allocation = [args.batch_size // len(devices)] * (len(devices) - 1) + allocation.append(args.batch_size - sum(allocation)) # The rest might need more/less + + images, (targets, masks, num_crowds) = datum + + cur_idx = 0 + for device, alloc in zip(devices, allocation): + for _ in range(alloc): + images[cur_idx] = gradinator(images[cur_idx].to(device)) + targets[cur_idx] = gradinator(targets[cur_idx].to(device)) + masks[cur_idx] = gradinator(masks[cur_idx].to(device)) + cur_idx += 1 + + if cfg.preserve_aspect_ratio: + # Choose a random size from the batch + _, h, w = images[random.randint(0, len(images) - 1)].size() + + for idx, (image, target, mask, num_crowd) in enumerate(zip(images, targets, masks, num_crowds)): + images[idx], targets[idx], masks[idx], num_crowds[idx] \ + = enforce_size(image, target, mask, num_crowd, w, h) + + cur_idx = 0 + split_images, split_targets, split_masks, split_numcrowds \ + = [[None for alloc in allocation] for _ in range(4)] + + for device_idx, alloc in enumerate(allocation): + split_images[device_idx] = torch.stack(images[cur_idx:cur_idx + alloc], dim=0) + split_targets[device_idx] = targets[cur_idx:cur_idx + alloc] + split_masks[device_idx] = masks[cur_idx:cur_idx + alloc] + split_numcrowds[device_idx] = num_crowds[cur_idx:cur_idx + alloc] + + cur_idx += alloc + + return split_images, split_targets, split_masks, split_numcrowds + + +def no_inf_mean(x: torch.Tensor): + """ + Computes the mean of a vector, throwing out all inf values. + If there are no non-inf values, this will return inf (i.e., just the normal mean). + """ + + no_inf = [a for a in x if torch.isfinite(a)] + + if len(no_inf) > 0: + return sum(no_inf) / len(no_inf) + else: + return x.mean() + + +def compute_validation_loss(net, data_loader, criterion): + global loss_types + + with torch.no_grad(): + losses = {} + + # Don't switch to eval mode because we want to get losses + iterations = 0 + for datum in data_loader: + images, targets, masks, num_crowds = prepare_data(datum) + out = net(images) + + wrapper = ScatterWrapper(targets, masks, num_crowds) + _losses = criterion(out, wrapper, wrapper.make_mask()) + + for k, v in _losses.items(): + v = v.mean().item() + if k in losses: + losses[k] += v + else: + losses[k] = v + + iterations += 1 + if args.validation_size <= iterations * args.batch_size: + break + + for k in losses: + losses[k] /= iterations + + loss_labels = sum([[k, losses[k]] for k in loss_types if k in losses], []) + print(('Validation ||' + (' %s: %.3f |' * len(losses)) + ')') % tuple(loss_labels), flush=True) + + +def compute_validation_map(epoch, iteration, yolact_net, dataset, log: Log = None): + with torch.no_grad(): + yolact_net.eval() + + start = time.time() + print() + print("Computing validation mAP (this may take a while)...", flush=True) + val_info = eval_script.evaluate(yolact_net, dataset, train_mode=True, trainCuda=args.cuda) + end = time.time() + + if log is not None: + log.log('val', val_info, elapsed=(end - start), epoch=epoch, iter=iteration) + + yolact_net.train() + + +def setup_eval(): + eval_script.parse_args(['--no_bar', '--max_images=' + str(args.validation_size)]) + + +if __name__ == '__main__': + train(args) diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/utils/augmentations.py b/PyTorch/contrib/cv/detection/YOLACT_plus/utils/augmentations.py index 5f32d182af..f18fd70932 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/utils/augmentations.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/utils/augmentations.py @@ -1,702 +1,702 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -from torchvision import transforms -import cv2 -import numpy as np -import types -from numpy import random -from math import sqrt - -from data import cfg, MEANS, STD - - -def intersect(box_a, box_b): - max_xy = np.minimum(box_a[:, 2:], box_b[2:]) - min_xy = np.maximum(box_a[:, :2], box_b[:2]) - inter = np.clip((max_xy - min_xy), a_min=0, a_max=np.inf) - return inter[:, 0] * inter[:, 1] - - -def jaccard_numpy(box_a, box_b): - """Compute the jaccard overlap of two sets of boxes. The jaccard overlap - is simply the intersection over union of two boxes. - E.g.: - A ∩ B / A ∪ B = A ∩ B / (area(A) + area(B) - A ∩ B) - Args: - box_a: Multiple bounding boxes, Shape: [num_boxes,4] - box_b: Single bounding box, Shape: [4] - Return: - jaccard overlap: Shape: [box_a.shape[0], box_a.shape[1]] - """ - inter = intersect(box_a, box_b) - area_a = ((box_a[:, 2]-box_a[:, 0]) * - (box_a[:, 3]-box_a[:, 1])) # [A,B] - area_b = ((box_b[2]-box_b[0]) * - (box_b[3]-box_b[1])) # [A,B] - union = area_a + area_b - inter - return inter / union # [A,B] - - -class Compose(object): - """Composes several augmentations together. - Args: - transforms (List[Transform]): list of transforms to compose. - Example: - >>> augmentations.Compose([ - >>> transforms.CenterCrop(10), - >>> transforms.ToTensor(), - >>> ]) - """ - - def __init__(self, transforms): - self.transforms = transforms - - def __call__(self, img, masks=None, boxes=None, labels=None): - for t in self.transforms: - img, masks, boxes, labels = t(img, masks, boxes, labels) - return img, masks, boxes, labels - - -class Lambda(object): - """Applies a lambda as a transform.""" - - def __init__(self, lambd): - assert isinstance(lambd, types.LambdaType) - self.lambd = lambd - - def __call__(self, img, masks=None, boxes=None, labels=None): - return self.lambd(img, masks, boxes, labels) - - -class ConvertFromInts(object): - def __call__(self, image, masks=None, boxes=None, labels=None): - return image.astype(np.float32), masks, boxes, labels - - - -class ToAbsoluteCoords(object): - def __call__(self, image, masks=None, boxes=None, labels=None): - height, width, channels = image.shape - boxes[:, 0] *= width - boxes[:, 2] *= width - boxes[:, 1] *= height - boxes[:, 3] *= height - - return image, masks, boxes, labels - - -class ToPercentCoords(object): - def __call__(self, image, masks=None, boxes=None, labels=None): - height, width, channels = image.shape - boxes[:, 0] /= width - boxes[:, 2] /= width - boxes[:, 1] /= height - boxes[:, 3] /= height - - return image, masks, boxes, labels - - -class Pad(object): - """ - Pads the image to the input width and height, filling the - background with mean and putting the image in the top-left. - - Note: this expects im_w <= width and im_h <= height - """ - def __init__(self, width, height, mean=MEANS, pad_gt=True): - self.mean = mean - self.width = width - self.height = height - self.pad_gt = pad_gt - - def __call__(self, image, masks, boxes=None, labels=None): - im_h, im_w, depth = image.shape - - expand_image = np.zeros( - (self.height, self.width, depth), - dtype=image.dtype) - expand_image[:, :, :] = self.mean - expand_image[:im_h, :im_w] = image - - if self.pad_gt: - expand_masks = np.zeros( - (masks.shape[0], self.height, self.width), - dtype=masks.dtype) - expand_masks[:,:im_h,:im_w] = masks - masks = expand_masks - - return expand_image, masks, boxes, labels - -class Resize(object): - """ If preserve_aspect_ratio is true, this resizes to an approximate area of max_size * max_size """ - - @staticmethod - def calc_size_preserve_ar(img_w, img_h, max_size): - """ I mathed this one out on the piece of paper. Resulting width*height = approx max_size^2 """ - ratio = sqrt(img_w / img_h) - w = max_size * ratio - h = max_size / ratio - return int(w), int(h) - - def __init__(self, resize_gt=True): - self.resize_gt = resize_gt - self.max_size = cfg.max_size - self.preserve_aspect_ratio = cfg.preserve_aspect_ratio - - def __call__(self, image, masks, boxes, labels=None): - img_h, img_w, _ = image.shape - - if self.preserve_aspect_ratio: - width, height = Resize.calc_size_preserve_ar(img_w, img_h, self.max_size) - else: - width, height = self.max_size, self.max_size - - image = cv2.resize(image, (width, height)) - - if self.resize_gt: - # Act like each object is a color channel - masks = masks.transpose((1, 2, 0)) - masks = cv2.resize(masks, (width, height)) - - # OpenCV resizes a (w,h,1) array to (s,s), so fix that - if len(masks.shape) == 2: - masks = np.expand_dims(masks, 0) - else: - masks = masks.transpose((2, 0, 1)) - - # Scale bounding boxes (which are currently absolute coordinates) - boxes[:, [0, 2]] *= (width / img_w) - boxes[:, [1, 3]] *= (height / img_h) - - # Discard boxes that are smaller than we'd like - w = boxes[:, 2] - boxes[:, 0] - h = boxes[:, 3] - boxes[:, 1] - - keep = (w > cfg.discard_box_width) * (h > cfg.discard_box_height) - masks = masks[keep] - boxes = boxes[keep] - labels['labels'] = labels['labels'][keep] - labels['num_crowds'] = (labels['labels'] < 0).sum() - - return image, masks, boxes, labels - - -class RandomSaturation(object): - def __init__(self, lower=0.5, upper=1.5): - self.lower = lower - self.upper = upper - assert self.upper >= self.lower, "contrast upper must be >= lower." - assert self.lower >= 0, "contrast lower must be non-negative." - - def __call__(self, image, masks=None, boxes=None, labels=None): - if random.randint(2): - image[:, :, 1] *= random.uniform(self.lower, self.upper) - - return image, masks, boxes, labels - - -class RandomHue(object): - def __init__(self, delta=18.0): - assert delta >= 0.0 and delta <= 360.0 - self.delta = delta - - def __call__(self, image, masks=None, boxes=None, labels=None): - if random.randint(2): - image[:, :, 0] += random.uniform(-self.delta, self.delta) - image[:, :, 0][image[:, :, 0] > 360.0] -= 360.0 - image[:, :, 0][image[:, :, 0] < 0.0] += 360.0 - return image, masks, boxes, labels - - -class RandomLightingNoise(object): - def __init__(self): - self.perms = ((0, 1, 2), (0, 2, 1), - (1, 0, 2), (1, 2, 0), - (2, 0, 1), (2, 1, 0)) - - def __call__(self, image, masks=None, boxes=None, labels=None): - # Don't shuffle the channels please, why would you do this - - # if random.randint(2): - # swap = self.perms[random.randint(len(self.perms))] - # shuffle = SwapChannels(swap) # shuffle channels - # image = shuffle(image) - return image, masks, boxes, labels - - -class ConvertColor(object): - def __init__(self, current='BGR', transform='HSV'): - self.transform = transform - self.current = current - - def __call__(self, image, masks=None, boxes=None, labels=None): - if self.current == 'BGR' and self.transform == 'HSV': - image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) - elif self.current == 'HSV' and self.transform == 'BGR': - image = cv2.cvtColor(image, cv2.COLOR_HSV2BGR) - else: - raise NotImplementedError - return image, masks, boxes, labels - - -class RandomContrast(object): - def __init__(self, lower=0.5, upper=1.5): - self.lower = lower - self.upper = upper - assert self.upper >= self.lower, "contrast upper must be >= lower." - assert self.lower >= 0, "contrast lower must be non-negative." - - # expects float image - def __call__(self, image, masks=None, boxes=None, labels=None): - if random.randint(2): - alpha = random.uniform(self.lower, self.upper) - image *= alpha - return image, masks, boxes, labels - - -class RandomBrightness(object): - def __init__(self, delta=32): - assert delta >= 0.0 - assert delta <= 255.0 - self.delta = delta - - def __call__(self, image, masks=None, boxes=None, labels=None): - if random.randint(2): - delta = random.uniform(-self.delta, self.delta) - image += delta - return image, masks, boxes, labels - - -class ToCV2Image(object): - def __call__(self, tensor, masks=None, boxes=None, labels=None): - return tensor.cpu().numpy().astype(np.float32).transpose((1, 2, 0)), masks, boxes, labels - - -class ToTensor(object): - def __call__(self, cvimage, masks=None, boxes=None, labels=None): - return torch.from_numpy(cvimage.astype(np.float32)).permute(2, 0, 1), masks, boxes, labels - - -class RandomSampleCrop(object): - """Crop - Arguments: - img (Image): the image being input during training - boxes (Tensor): the original bounding boxes in pt form - labels (Tensor): the class labels for each bbox - mode (float tuple): the min and max jaccard overlaps - Return: - (img, boxes, classes) - img (Image): the cropped image - boxes (Tensor): the adjusted bounding boxes in pt form - labels (Tensor): the class labels for each bbox - """ - def __init__(self): - self.sample_options = ( - # using entire original input image - None, - # sample a patch s.t. MIN jaccard w/ obj in .1,.3,.4,.7,.9 - (0.1, None), - (0.3, None), - (0.7, None), - (0.9, None), - # randomly sample a patch - (None, None), - ) - - def __call__(self, image, masks, boxes=None, labels=None): - height, width, _ = image.shape - while True: - # randomly choose a mode - mode = random.choice(self.sample_options) - if mode is None: - return image, masks, boxes, labels - - min_iou, max_iou = mode - if min_iou is None: - min_iou = float('-inf') - if max_iou is None: - max_iou = float('inf') - - # max trails (50) - for _ in range(50): - current_image = image - - w = random.uniform(0.3 * width, width) - h = random.uniform(0.3 * height, height) - - # aspect ratio constraint b/t .5 & 2 - if h / w < 0.5 or h / w > 2: - continue - - left = random.uniform(width - w) - top = random.uniform(height - h) - - # convert to integer rect x1,y1,x2,y2 - rect = np.array([int(left), int(top), int(left+w), int(top+h)]) - - # calculate IoU (jaccard overlap) b/t the cropped and gt boxes - overlap = jaccard_numpy(boxes, rect) - - # This piece of code is bugged and does nothing: - # https://github.com/amdegroot/ssd.pytorch/issues/68 - # - # However, when I fixed it with overlap.max() < min_iou, - # it cut the mAP in half (after 8k iterations). So it stays. - # - # is min and max overlap constraint satisfied? if not try again - if overlap.min() < min_iou and max_iou < overlap.max(): - continue - - # cut the crop from the image - current_image = current_image[rect[1]:rect[3], rect[0]:rect[2], - :] - - # keep overlap with gt box IF center in sampled patch - centers = (boxes[:, :2] + boxes[:, 2:]) / 2.0 - - # mask in all gt boxes that above and to the left of centers - m1 = (rect[0] < centers[:, 0]) * (rect[1] < centers[:, 1]) - - # mask in all gt boxes that under and to the right of centers - m2 = (rect[2] > centers[:, 0]) * (rect[3] > centers[:, 1]) - - # mask in that both m1 and m2 are true - mask = m1 * m2 - - # [0 ... 0 for num_gt and then 1 ... 1 for num_crowds] - num_crowds = labels['num_crowds'] - crowd_mask = np.zeros(mask.shape, dtype=np.int32) - - if num_crowds > 0: - crowd_mask[-num_crowds:] = 1 - - # have any valid boxes? try again if not - # Also make sure you have at least one regular gt - if not mask.any() or np.sum(1-crowd_mask[mask]) == 0: - continue - - # take only the matching gt masks - current_masks = masks[mask, :, :].copy() - - # take only matching gt boxes - current_boxes = boxes[mask, :].copy() - - # take only matching gt labels - labels['labels'] = labels['labels'][mask] - current_labels = labels - - # We now might have fewer crowd annotations - if num_crowds > 0: - labels['num_crowds'] = np.sum(crowd_mask[mask]) - - # should we use the box left and top corner or the crop's - current_boxes[:, :2] = np.maximum(current_boxes[:, :2], - rect[:2]) - # adjust to crop (by substracting crop's left,top) - current_boxes[:, :2] -= rect[:2] - - current_boxes[:, 2:] = np.minimum(current_boxes[:, 2:], - rect[2:]) - # adjust to crop (by substracting crop's left,top) - current_boxes[:, 2:] -= rect[:2] - - # crop the current masks to the same dimensions as the image - current_masks = current_masks[:, rect[1]:rect[3], rect[0]:rect[2]] - - return current_image, current_masks, current_boxes, current_labels - - -class Expand(object): - def __init__(self, mean): - self.mean = mean - - def __call__(self, image, masks, boxes, labels): - if random.randint(2): - return image, masks, boxes, labels - - height, width, depth = image.shape - ratio = random.uniform(1, 4) - left = random.uniform(0, width*ratio - width) - top = random.uniform(0, height*ratio - height) - - expand_image = np.zeros( - (int(height*ratio), int(width*ratio), depth), - dtype=image.dtype) - expand_image[:, :, :] = self.mean - expand_image[int(top):int(top + height), - int(left):int(left + width)] = image - image = expand_image - - expand_masks = np.zeros( - (masks.shape[0], int(height*ratio), int(width*ratio)), - dtype=masks.dtype) - expand_masks[:,int(top):int(top + height), - int(left):int(left + width)] = masks - masks = expand_masks - - boxes = boxes.copy() - boxes[:, :2] += (int(left), int(top)) - boxes[:, 2:] += (int(left), int(top)) - - return image, masks, boxes, labels - - -class RandomMirror(object): - def __call__(self, image, masks, boxes, labels): - _, width, _ = image.shape - if random.randint(2): - image = image[:, ::-1] - masks = masks[:, :, ::-1] - boxes = boxes.copy() - boxes[:, 0::2] = width - boxes[:, 2::-2] - return image, masks, boxes, labels - - -class RandomFlip(object): - def __call__(self, image, masks, boxes, labels): - height , _ , _ = image.shape - if random.randint(2): - image = image[::-1, :] - masks = masks[:, ::-1, :] - boxes = boxes.copy() - boxes[:, 1::2] = height - boxes[:, 3::-2] - return image, masks, boxes, labels - - -class RandomRot90(object): - def __call__(self, image, masks, boxes, labels): - old_height , old_width , _ = image.shape - k = random.randint(4) - image = np.rot90(image,k) - masks = np.array([np.rot90(mask,k) for mask in masks]) - boxes = boxes.copy() - for _ in range(k): - boxes = np.array([[box[1], old_width - 1 - box[2], box[3], old_width - 1 - box[0]] for box in boxes]) - old_width, old_height = old_height, old_width - return image, masks, boxes, labels - - -class SwapChannels(object): - """Transforms a tensorized image by swapping the channels in the order - specified in the swap tuple. - Args: - swaps (int triple): final order of channels - eg: (2, 1, 0) - """ - - def __init__(self, swaps): - self.swaps = swaps - - def __call__(self, image): - """ - Args: - image (Tensor): image tensor to be transformed - Return: - a tensor with channels swapped according to swap - """ - # if torch.is_tensor(image): - # image = image.data.cpu().numpy() - # else: - # image = np.array(image) - image = image[:, :, self.swaps] - return image - - -class PhotometricDistort(object): - def __init__(self): - self.pd = [ - RandomContrast(), - ConvertColor(transform='HSV'), - RandomSaturation(), - RandomHue(), - ConvertColor(current='HSV', transform='BGR'), - RandomContrast() - ] - self.rand_brightness = RandomBrightness() - self.rand_light_noise = RandomLightingNoise() - - def __call__(self, image, masks, boxes, labels): - im = image.copy() - im, masks, boxes, labels = self.rand_brightness(im, masks, boxes, labels) - if random.randint(2): - distort = Compose(self.pd[:-1]) - else: - distort = Compose(self.pd[1:]) - im, masks, boxes, labels = distort(im, masks, boxes, labels) - return self.rand_light_noise(im, masks, boxes, labels) - -class PrepareMasks(object): - """ - Prepares the gt masks for use_gt_bboxes by cropping with the gt box - and downsampling the resulting mask to mask_size, mask_size. This - function doesn't do anything if cfg.use_gt_bboxes is False. - """ - - def __init__(self, mask_size, use_gt_bboxes): - self.mask_size = mask_size - self.use_gt_bboxes = use_gt_bboxes - - def __call__(self, image, masks, boxes, labels=None): - if not self.use_gt_bboxes: - return image, masks, boxes, labels - - height, width, _ = image.shape - - new_masks = np.zeros((masks.shape[0], self.mask_size ** 2)) - - for i in range(len(masks)): - x1, y1, x2, y2 = boxes[i, :] - x1 *= width - x2 *= width - y1 *= height - y2 *= height - x1, y1, x2, y2 = (int(x1), int(y1), int(x2), int(y2)) - - # +1 So that if y1=10.6 and y2=10.9 we still have a bounding box - cropped_mask = masks[i, y1:(y2+1), x1:(x2+1)] - scaled_mask = cv2.resize(cropped_mask, (self.mask_size, self.mask_size)) - - new_masks[i, :] = scaled_mask.reshape(1, -1) - - # Binarize - new_masks[new_masks > 0.5] = 1 - new_masks[new_masks <= 0.5] = 0 - - return image, new_masks, boxes, labels - -class BackboneTransform(object): - """ - Transforms a BRG image made of floats in the range [0, 255] to whatever - input the current backbone network needs. - - transform is a transform config object (see config.py). - in_channel_order is probably 'BGR' but you do you, kid. - """ - def __init__(self, transform, mean, std, in_channel_order): - self.mean = np.array(mean, dtype=np.float32) - self.std = np.array(std, dtype=np.float32) - self.transform = transform - - # Here I use "Algorithms and Coding" to convert string permutations to numbers - self.channel_map = {c: idx for idx, c in enumerate(in_channel_order)} - self.channel_permutation = [self.channel_map[c] for c in transform.channel_order] - - def __call__(self, img, masks=None, boxes=None, labels=None): - - img = img.astype(np.float32) - - if self.transform.normalize: - img = (img - self.mean) / self.std - elif self.transform.subtract_means: - img = (img - self.mean) - elif self.transform.to_float: - img = img / 255 - - img = img[:, :, self.channel_permutation] - - return img.astype(np.float32), masks, boxes, labels - - - - -class BaseTransform(object): - """ Transorm to be used when evaluating. """ - - def __init__(self, mean=MEANS, std=STD): - self.augment = Compose([ - ConvertFromInts(), - Resize(resize_gt=False), - BackboneTransform(cfg.backbone.transform, mean, std, 'BGR') - ]) - - def __call__(self, img, masks=None, boxes=None, labels=None): - return self.augment(img, masks, boxes, labels) - -import torch.nn.functional as F - -class FastBaseTransform(torch.nn.Module): - """ - Transform that does all operations on the GPU for super speed. - This doesn't suppport a lot of config settings and should only be used for production. - Maintain this as necessary. - """ - - def __init__(self): - super().__init__() - - self.mean = torch.Tensor(MEANS).float().cuda()[None, :, None, None] - self.std = torch.Tensor( STD ).float().cuda()[None, :, None, None] - self.transform = cfg.backbone.transform - - def forward(self, img): - self.mean = self.mean.to(img.device) - self.std = self.std.to(img.device) - - # img assumed to be a pytorch BGR image with channel order [n, h, w, c] - if cfg.preserve_aspect_ratio: - _, h, w, _ = img.size() - img_size = Resize.calc_size_preserve_ar(w, h, cfg.max_size) - img_size = (img_size[1], img_size[0]) # Pytorch needs h, w - else: - img_size = (cfg.max_size, cfg.max_size) - - img = img.permute(0, 3, 1, 2).contiguous() - img = F.interpolate(img, img_size, mode='bilinear', align_corners=False) - - if self.transform.normalize: - img = (img - self.mean) / self.std - elif self.transform.subtract_means: - img = (img - self.mean) - elif self.transform.to_float: - img = img / 255 - - if self.transform.channel_order != 'RGB': - raise NotImplementedError - - img = img[:, (2, 1, 0), :, :].contiguous() - - # Return value is in channel order [n, c, h, w] and RGB - return img - -def do_nothing(img=None, masks=None, boxes=None, labels=None): - return img, masks, boxes, labels - - -def enable_if(condition, obj): - return obj if condition else do_nothing - -class SSDAugmentation(object): - """ Transform to be used when training. """ - - def __init__(self, mean=MEANS, std=STD): - self.augment = Compose([ - ConvertFromInts(), - ToAbsoluteCoords(), - enable_if(cfg.augment_photometric_distort, PhotometricDistort()), - enable_if(cfg.augment_expand, Expand(mean)), - enable_if(cfg.augment_random_sample_crop, RandomSampleCrop()), - enable_if(cfg.augment_random_mirror, RandomMirror()), - enable_if(cfg.augment_random_flip, RandomFlip()), - enable_if(cfg.augment_random_flip, RandomRot90()), - Resize(), - enable_if(not cfg.preserve_aspect_ratio, Pad(cfg.max_size, cfg.max_size, mean)), - ToPercentCoords(), - PrepareMasks(cfg.mask_size, cfg.use_gt_bboxes), - BackboneTransform(cfg.backbone.transform, mean, std, 'BGR') - ]) - - def __call__(self, img, masks, boxes, labels): - return self.augment(img, masks, boxes, labels) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +from torchvision import transforms +import cv2 +import numpy as np +import types +from numpy import random +from math import sqrt + +from data import cfg, MEANS, STD + + +def intersect(box_a, box_b): + max_xy = np.minimum(box_a[:, 2:], box_b[2:]) + min_xy = np.maximum(box_a[:, :2], box_b[:2]) + inter = np.clip((max_xy - min_xy), a_min=0, a_max=np.inf) + return inter[:, 0] * inter[:, 1] + + +def jaccard_numpy(box_a, box_b): + """Compute the jaccard overlap of two sets of boxes. The jaccard overlap + is simply the intersection over union of two boxes. + E.g.: + A ∩ B / A ∪ B = A ∩ B / (area(A) + area(B) - A ∩ B) + Args: + box_a: Multiple bounding boxes, Shape: [num_boxes,4] + box_b: Single bounding box, Shape: [4] + Return: + jaccard overlap: Shape: [box_a.shape[0], box_a.shape[1]] + """ + inter = intersect(box_a, box_b) + area_a = ((box_a[:, 2]-box_a[:, 0]) * + (box_a[:, 3]-box_a[:, 1])) # [A,B] + area_b = ((box_b[2]-box_b[0]) * + (box_b[3]-box_b[1])) # [A,B] + union = area_a + area_b - inter + return inter / union # [A,B] + + +class Compose(object): + """Composes several augmentations together. + Args: + transforms (List[Transform]): list of transforms to compose. + Example: + >>> augmentations.Compose([ + >>> transforms.CenterCrop(10), + >>> transforms.ToTensor(), + >>> ]) + """ + + def __init__(self, transforms): + self.transforms = transforms + + def __call__(self, img, masks=None, boxes=None, labels=None): + for t in self.transforms: + img, masks, boxes, labels = t(img, masks, boxes, labels) + return img, masks, boxes, labels + + +class Lambda(object): + """Applies a lambda as a transform.""" + + def __init__(self, lambd): + assert isinstance(lambd, types.LambdaType) + self.lambd = lambd + + def __call__(self, img, masks=None, boxes=None, labels=None): + return self.lambd(img, masks, boxes, labels) + + +class ConvertFromInts(object): + def __call__(self, image, masks=None, boxes=None, labels=None): + return image.astype(np.float32), masks, boxes, labels + + + +class ToAbsoluteCoords(object): + def __call__(self, image, masks=None, boxes=None, labels=None): + height, width, channels = image.shape + boxes[:, 0] *= width + boxes[:, 2] *= width + boxes[:, 1] *= height + boxes[:, 3] *= height + + return image, masks, boxes, labels + + +class ToPercentCoords(object): + def __call__(self, image, masks=None, boxes=None, labels=None): + height, width, channels = image.shape + boxes[:, 0] /= width + boxes[:, 2] /= width + boxes[:, 1] /= height + boxes[:, 3] /= height + + return image, masks, boxes, labels + + +class Pad(object): + """ + Pads the image to the input width and height, filling the + background with mean and putting the image in the top-left. + + Note: this expects im_w <= width and im_h <= height + """ + def __init__(self, width, height, mean=MEANS, pad_gt=True): + self.mean = mean + self.width = width + self.height = height + self.pad_gt = pad_gt + + def __call__(self, image, masks, boxes=None, labels=None): + im_h, im_w, depth = image.shape + + expand_image = np.zeros( + (self.height, self.width, depth), + dtype=image.dtype) + expand_image[:, :, :] = self.mean + expand_image[:im_h, :im_w] = image + + if self.pad_gt: + expand_masks = np.zeros( + (masks.shape[0], self.height, self.width), + dtype=masks.dtype) + expand_masks[:,:im_h,:im_w] = masks + masks = expand_masks + + return expand_image, masks, boxes, labels + +class Resize(object): + """ If preserve_aspect_ratio is true, this resizes to an approximate area of max_size * max_size """ + + @staticmethod + def calc_size_preserve_ar(img_w, img_h, max_size): + """ I mathed this one out on the piece of paper. Resulting width*height = approx max_size^2 """ + ratio = sqrt(img_w / img_h) + w = max_size * ratio + h = max_size / ratio + return int(w), int(h) + + def __init__(self, resize_gt=True): + self.resize_gt = resize_gt + self.max_size = cfg.max_size + self.preserve_aspect_ratio = cfg.preserve_aspect_ratio + + def __call__(self, image, masks, boxes, labels=None): + img_h, img_w, _ = image.shape + + if self.preserve_aspect_ratio: + width, height = Resize.calc_size_preserve_ar(img_w, img_h, self.max_size) + else: + width, height = self.max_size, self.max_size + + image = cv2.resize(image, (width, height)) + + if self.resize_gt: + # Act like each object is a color channel + masks = masks.transpose((1, 2, 0)) + masks = cv2.resize(masks, (width, height)) + + # OpenCV resizes a (w,h,1) array to (s,s), so fix that + if len(masks.shape) == 2: + masks = np.expand_dims(masks, 0) + else: + masks = masks.transpose((2, 0, 1)) + + # Scale bounding boxes (which are currently absolute coordinates) + boxes[:, [0, 2]] *= (width / img_w) + boxes[:, [1, 3]] *= (height / img_h) + + # Discard boxes that are smaller than we'd like + w = boxes[:, 2] - boxes[:, 0] + h = boxes[:, 3] - boxes[:, 1] + + keep = (w > cfg.discard_box_width) * (h > cfg.discard_box_height) + masks = masks[keep] + boxes = boxes[keep] + labels['labels'] = labels['labels'][keep] + labels['num_crowds'] = (labels['labels'] < 0).sum() + + return image, masks, boxes, labels + + +class RandomSaturation(object): + def __init__(self, lower=0.5, upper=1.5): + self.lower = lower + self.upper = upper + assert self.upper >= self.lower, "contrast upper must be >= lower." + assert self.lower >= 0, "contrast lower must be non-negative." + + def __call__(self, image, masks=None, boxes=None, labels=None): + if random.randint(2): + image[:, :, 1] *= random.uniform(self.lower, self.upper) + + return image, masks, boxes, labels + + +class RandomHue(object): + def __init__(self, delta=18.0): + assert delta >= 0.0 and delta <= 360.0 + self.delta = delta + + def __call__(self, image, masks=None, boxes=None, labels=None): + if random.randint(2): + image[:, :, 0] += random.uniform(-self.delta, self.delta) + image[:, :, 0][image[:, :, 0] > 360.0] -= 360.0 + image[:, :, 0][image[:, :, 0] < 0.0] += 360.0 + return image, masks, boxes, labels + + +class RandomLightingNoise(object): + def __init__(self): + self.perms = ((0, 1, 2), (0, 2, 1), + (1, 0, 2), (1, 2, 0), + (2, 0, 1), (2, 1, 0)) + + def __call__(self, image, masks=None, boxes=None, labels=None): + # Don't shuffle the channels please, why would you do this + + # if random.randint(2): + # swap = self.perms[random.randint(len(self.perms))] + # shuffle = SwapChannels(swap) # shuffle channels + # image = shuffle(image) + return image, masks, boxes, labels + + +class ConvertColor(object): + def __init__(self, current='BGR', transform='HSV'): + self.transform = transform + self.current = current + + def __call__(self, image, masks=None, boxes=None, labels=None): + if self.current == 'BGR' and self.transform == 'HSV': + image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) + elif self.current == 'HSV' and self.transform == 'BGR': + image = cv2.cvtColor(image, cv2.COLOR_HSV2BGR) + else: + raise NotImplementedError + return image, masks, boxes, labels + + +class RandomContrast(object): + def __init__(self, lower=0.5, upper=1.5): + self.lower = lower + self.upper = upper + assert self.upper >= self.lower, "contrast upper must be >= lower." + assert self.lower >= 0, "contrast lower must be non-negative." + + # expects float image + def __call__(self, image, masks=None, boxes=None, labels=None): + if random.randint(2): + alpha = random.uniform(self.lower, self.upper) + image *= alpha + return image, masks, boxes, labels + + +class RandomBrightness(object): + def __init__(self, delta=32): + assert delta >= 0.0 + assert delta <= 255.0 + self.delta = delta + + def __call__(self, image, masks=None, boxes=None, labels=None): + if random.randint(2): + delta = random.uniform(-self.delta, self.delta) + image += delta + return image, masks, boxes, labels + + +class ToCV2Image(object): + def __call__(self, tensor, masks=None, boxes=None, labels=None): + return tensor.cpu().numpy().astype(np.float32).transpose((1, 2, 0)), masks, boxes, labels + + +class ToTensor(object): + def __call__(self, cvimage, masks=None, boxes=None, labels=None): + return torch.from_numpy(cvimage.astype(np.float32)).permute(2, 0, 1), masks, boxes, labels + + +class RandomSampleCrop(object): + """Crop + Arguments: + img (Image): the image being input during training + boxes (Tensor): the original bounding boxes in pt form + labels (Tensor): the class labels for each bbox + mode (float tuple): the min and max jaccard overlaps + Return: + (img, boxes, classes) + img (Image): the cropped image + boxes (Tensor): the adjusted bounding boxes in pt form + labels (Tensor): the class labels for each bbox + """ + def __init__(self): + self.sample_options = ( + # using entire original input image + None, + # sample a patch s.t. MIN jaccard w/ obj in .1,.3,.4,.7,.9 + (0.1, None), + (0.3, None), + (0.7, None), + (0.9, None), + # randomly sample a patch + (None, None), + ) + + def __call__(self, image, masks, boxes=None, labels=None): + height, width, _ = image.shape + while True: + # randomly choose a mode + mode = random.choice(self.sample_options) + if mode is None: + return image, masks, boxes, labels + + min_iou, max_iou = mode + if min_iou is None: + min_iou = float('-inf') + if max_iou is None: + max_iou = float('inf') + + # max trails (50) + for _ in range(50): + current_image = image + + w = random.uniform(0.3 * width, width) + h = random.uniform(0.3 * height, height) + + # aspect ratio constraint b/t .5 & 2 + if h / w < 0.5 or h / w > 2: + continue + + left = random.uniform(width - w) + top = random.uniform(height - h) + + # convert to integer rect x1,y1,x2,y2 + rect = np.array([int(left), int(top), int(left+w), int(top+h)]) + + # calculate IoU (jaccard overlap) b/t the cropped and gt boxes + overlap = jaccard_numpy(boxes, rect) + + # This piece of code is bugged and does nothing: + # https://github.com/amdegroot/ssd.pytorch/issues/68 + # + # However, when I fixed it with overlap.max() < min_iou, + # it cut the mAP in half (after 8k iterations). So it stays. + # + # is min and max overlap constraint satisfied? if not try again + if overlap.min() < min_iou and max_iou < overlap.max(): + continue + + # cut the crop from the image + current_image = current_image[rect[1]:rect[3], rect[0]:rect[2], + :] + + # keep overlap with gt box IF center in sampled patch + centers = (boxes[:, :2] + boxes[:, 2:]) / 2.0 + + # mask in all gt boxes that above and to the left of centers + m1 = (rect[0] < centers[:, 0]) * (rect[1] < centers[:, 1]) + + # mask in all gt boxes that under and to the right of centers + m2 = (rect[2] > centers[:, 0]) * (rect[3] > centers[:, 1]) + + # mask in that both m1 and m2 are true + mask = m1 * m2 + + # [0 ... 0 for num_gt and then 1 ... 1 for num_crowds] + num_crowds = labels['num_crowds'] + crowd_mask = np.zeros(mask.shape, dtype=np.int32) + + if num_crowds > 0: + crowd_mask[-num_crowds:] = 1 + + # have any valid boxes? try again if not + # Also make sure you have at least one regular gt + if not mask.any() or np.sum(1-crowd_mask[mask]) == 0: + continue + + # take only the matching gt masks + current_masks = masks[mask, :, :].copy() + + # take only matching gt boxes + current_boxes = boxes[mask, :].copy() + + # take only matching gt labels + labels['labels'] = labels['labels'][mask] + current_labels = labels + + # We now might have fewer crowd annotations + if num_crowds > 0: + labels['num_crowds'] = np.sum(crowd_mask[mask]) + + # should we use the box left and top corner or the crop's + current_boxes[:, :2] = np.maximum(current_boxes[:, :2], + rect[:2]) + # adjust to crop (by substracting crop's left,top) + current_boxes[:, :2] -= rect[:2] + + current_boxes[:, 2:] = np.minimum(current_boxes[:, 2:], + rect[2:]) + # adjust to crop (by substracting crop's left,top) + current_boxes[:, 2:] -= rect[:2] + + # crop the current masks to the same dimensions as the image + current_masks = current_masks[:, rect[1]:rect[3], rect[0]:rect[2]] + + return current_image, current_masks, current_boxes, current_labels + + +class Expand(object): + def __init__(self, mean): + self.mean = mean + + def __call__(self, image, masks, boxes, labels): + if random.randint(2): + return image, masks, boxes, labels + + height, width, depth = image.shape + ratio = random.uniform(1, 4) + left = random.uniform(0, width*ratio - width) + top = random.uniform(0, height*ratio - height) + + expand_image = np.zeros( + (int(height*ratio), int(width*ratio), depth), + dtype=image.dtype) + expand_image[:, :, :] = self.mean + expand_image[int(top):int(top + height), + int(left):int(left + width)] = image + image = expand_image + + expand_masks = np.zeros( + (masks.shape[0], int(height*ratio), int(width*ratio)), + dtype=masks.dtype) + expand_masks[:,int(top):int(top + height), + int(left):int(left + width)] = masks + masks = expand_masks + + boxes = boxes.copy() + boxes[:, :2] += (int(left), int(top)) + boxes[:, 2:] += (int(left), int(top)) + + return image, masks, boxes, labels + + +class RandomMirror(object): + def __call__(self, image, masks, boxes, labels): + _, width, _ = image.shape + if random.randint(2): + image = image[:, ::-1] + masks = masks[:, :, ::-1] + boxes = boxes.copy() + boxes[:, 0::2] = width - boxes[:, 2::-2] + return image, masks, boxes, labels + + +class RandomFlip(object): + def __call__(self, image, masks, boxes, labels): + height , _ , _ = image.shape + if random.randint(2): + image = image[::-1, :] + masks = masks[:, ::-1, :] + boxes = boxes.copy() + boxes[:, 1::2] = height - boxes[:, 3::-2] + return image, masks, boxes, labels + + +class RandomRot90(object): + def __call__(self, image, masks, boxes, labels): + old_height , old_width , _ = image.shape + k = random.randint(4) + image = np.rot90(image,k) + masks = np.array([np.rot90(mask,k) for mask in masks]) + boxes = boxes.copy() + for _ in range(k): + boxes = np.array([[box[1], old_width - 1 - box[2], box[3], old_width - 1 - box[0]] for box in boxes]) + old_width, old_height = old_height, old_width + return image, masks, boxes, labels + + +class SwapChannels(object): + """Transforms a tensorized image by swapping the channels in the order + specified in the swap tuple. + Args: + swaps (int triple): final order of channels + eg: (2, 1, 0) + """ + + def __init__(self, swaps): + self.swaps = swaps + + def __call__(self, image): + """ + Args: + image (Tensor): image tensor to be transformed + Return: + a tensor with channels swapped according to swap + """ + # if torch.is_tensor(image): + # image = image.data.cpu().numpy() + # else: + # image = np.array(image) + image = image[:, :, self.swaps] + return image + + +class PhotometricDistort(object): + def __init__(self): + self.pd = [ + RandomContrast(), + ConvertColor(transform='HSV'), + RandomSaturation(), + RandomHue(), + ConvertColor(current='HSV', transform='BGR'), + RandomContrast() + ] + self.rand_brightness = RandomBrightness() + self.rand_light_noise = RandomLightingNoise() + + def __call__(self, image, masks, boxes, labels): + im = image.copy() + im, masks, boxes, labels = self.rand_brightness(im, masks, boxes, labels) + if random.randint(2): + distort = Compose(self.pd[:-1]) + else: + distort = Compose(self.pd[1:]) + im, masks, boxes, labels = distort(im, masks, boxes, labels) + return self.rand_light_noise(im, masks, boxes, labels) + +class PrepareMasks(object): + """ + Prepares the gt masks for use_gt_bboxes by cropping with the gt box + and downsampling the resulting mask to mask_size, mask_size. This + function doesn't do anything if cfg.use_gt_bboxes is False. + """ + + def __init__(self, mask_size, use_gt_bboxes): + self.mask_size = mask_size + self.use_gt_bboxes = use_gt_bboxes + + def __call__(self, image, masks, boxes, labels=None): + if not self.use_gt_bboxes: + return image, masks, boxes, labels + + height, width, _ = image.shape + + new_masks = np.zeros((masks.shape[0], self.mask_size ** 2)) + + for i in range(len(masks)): + x1, y1, x2, y2 = boxes[i, :] + x1 *= width + x2 *= width + y1 *= height + y2 *= height + x1, y1, x2, y2 = (int(x1), int(y1), int(x2), int(y2)) + + # +1 So that if y1=10.6 and y2=10.9 we still have a bounding box + cropped_mask = masks[i, y1:(y2+1), x1:(x2+1)] + scaled_mask = cv2.resize(cropped_mask, (self.mask_size, self.mask_size)) + + new_masks[i, :] = scaled_mask.reshape(1, -1) + + # Binarize + new_masks[new_masks > 0.5] = 1 + new_masks[new_masks <= 0.5] = 0 + + return image, new_masks, boxes, labels + +class BackboneTransform(object): + """ + Transforms a BRG image made of floats in the range [0, 255] to whatever + input the current backbone network needs. + + transform is a transform config object (see config.py). + in_channel_order is probably 'BGR' but you do you, kid. + """ + def __init__(self, transform, mean, std, in_channel_order): + self.mean = np.array(mean, dtype=np.float32) + self.std = np.array(std, dtype=np.float32) + self.transform = transform + + # Here I use "Algorithms and Coding" to convert string permutations to numbers + self.channel_map = {c: idx for idx, c in enumerate(in_channel_order)} + self.channel_permutation = [self.channel_map[c] for c in transform.channel_order] + + def __call__(self, img, masks=None, boxes=None, labels=None): + + img = img.astype(np.float32) + + if self.transform.normalize: + img = (img - self.mean) / self.std + elif self.transform.subtract_means: + img = (img - self.mean) + elif self.transform.to_float: + img = img / 255 + + img = img[:, :, self.channel_permutation] + + return img.astype(np.float32), masks, boxes, labels + + + + +class BaseTransform(object): + """ Transorm to be used when evaluating. """ + + def __init__(self, mean=MEANS, std=STD): + self.augment = Compose([ + ConvertFromInts(), + Resize(resize_gt=False), + BackboneTransform(cfg.backbone.transform, mean, std, 'BGR') + ]) + + def __call__(self, img, masks=None, boxes=None, labels=None): + return self.augment(img, masks, boxes, labels) + +import torch.nn.functional as F + +class FastBaseTransform(torch.nn.Module): + """ + Transform that does all operations on the GPU for super speed. + This doesn't suppport a lot of config settings and should only be used for production. + Maintain this as necessary. + """ + + def __init__(self): + super().__init__() + + self.mean = torch.Tensor(MEANS).float().cuda()[None, :, None, None] + self.std = torch.Tensor( STD ).float().cuda()[None, :, None, None] + self.transform = cfg.backbone.transform + + def forward(self, img): + self.mean = self.mean.to(img.device) + self.std = self.std.to(img.device) + + # img assumed to be a pytorch BGR image with channel order [n, h, w, c] + if cfg.preserve_aspect_ratio: + _, h, w, _ = img.size() + img_size = Resize.calc_size_preserve_ar(w, h, cfg.max_size) + img_size = (img_size[1], img_size[0]) # Pytorch needs h, w + else: + img_size = (cfg.max_size, cfg.max_size) + + img = img.permute(0, 3, 1, 2).contiguous() + img = F.interpolate(img, img_size, mode='bilinear', align_corners=False) + + if self.transform.normalize: + img = (img - self.mean) / self.std + elif self.transform.subtract_means: + img = (img - self.mean) + elif self.transform.to_float: + img = img / 255 + + if self.transform.channel_order != 'RGB': + raise NotImplementedError + + img = img[:, (2, 1, 0), :, :].contiguous() + + # Return value is in channel order [n, c, h, w] and RGB + return img + +def do_nothing(img=None, masks=None, boxes=None, labels=None): + return img, masks, boxes, labels + + +def enable_if(condition, obj): + return obj if condition else do_nothing + +class SSDAugmentation(object): + """ Transform to be used when training. """ + + def __init__(self, mean=MEANS, std=STD): + self.augment = Compose([ + ConvertFromInts(), + ToAbsoluteCoords(), + enable_if(cfg.augment_photometric_distort, PhotometricDistort()), + enable_if(cfg.augment_expand, Expand(mean)), + enable_if(cfg.augment_random_sample_crop, RandomSampleCrop()), + enable_if(cfg.augment_random_mirror, RandomMirror()), + enable_if(cfg.augment_random_flip, RandomFlip()), + enable_if(cfg.augment_random_flip, RandomRot90()), + Resize(), + enable_if(not cfg.preserve_aspect_ratio, Pad(cfg.max_size, cfg.max_size, mean)), + ToPercentCoords(), + PrepareMasks(cfg.mask_size, cfg.use_gt_bboxes), + BackboneTransform(cfg.backbone.transform, mean, std, 'BGR') + ]) + + def __call__(self, img, masks, boxes, labels): + return self.augment(img, masks, boxes, labels) diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/utils/cython_nms.pyx b/PyTorch/contrib/cv/detection/YOLACT_plus/utils/cython_nms.pyx index 4a4a5bda80..892be872ed 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/utils/cython_nms.pyx +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/utils/cython_nms.pyx @@ -1,74 +1,74 @@ -## Note: Figure out the license details later. -# -# Based on: -# -------------------------------------------------------- -# Fast R-CNN -# Copyright (c) 2015 Microsoft -# Licensed under The MIT License [see LICENSE for details] -# Written by Ross Girshick -# -------------------------------------------------------- - -cimport cython -import numpy as np -cimport numpy as np - -cdef inline np.float32_t max(np.float32_t a, np.float32_t b) nogil: - return a if a >= b else b - -cdef inline np.float32_t min(np.float32_t a, np.float32_t b) nogil: - return a if a <= b else b - -@cython.boundscheck(False) -@cython.cdivision(True) -@cython.wraparound(False) -def nms(np.ndarray[np.float32_t, ndim=2] dets, np.float32_t thresh): - cdef np.ndarray[np.float32_t, ndim=1] x1 = dets[:, 0] - cdef np.ndarray[np.float32_t, ndim=1] y1 = dets[:, 1] - cdef np.ndarray[np.float32_t, ndim=1] x2 = dets[:, 2] - cdef np.ndarray[np.float32_t, ndim=1] y2 = dets[:, 3] - cdef np.ndarray[np.float32_t, ndim=1] scores = dets[:, 4] - - cdef np.ndarray[np.float32_t, ndim=1] areas = (x2 - x1 + 1) * (y2 - y1 + 1) - cdef np.ndarray[np.int64_t, ndim=1] order = scores.argsort()[::-1] - - cdef int ndets = dets.shape[0] - cdef np.ndarray[np.int_t, ndim=1] suppressed = \ - np.zeros((ndets), dtype=np.int) - - # nominal indices - cdef int _i, _j - # sorted indices - cdef int i, j - # temp variables for box i's (the box currently under consideration) - cdef np.float32_t ix1, iy1, ix2, iy2, iarea - # variables for computing overlap with box j (lower scoring box) - cdef np.float32_t xx1, yy1, xx2, yy2 - cdef np.float32_t w, h - cdef np.float32_t inter, ovr - - with nogil: - for _i in range(ndets): - i = order[_i] - if suppressed[i] == 1: - continue - ix1 = x1[i] - iy1 = y1[i] - ix2 = x2[i] - iy2 = y2[i] - iarea = areas[i] - for _j in range(_i + 1, ndets): - j = order[_j] - if suppressed[j] == 1: - continue - xx1 = max(ix1, x1[j]) - yy1 = max(iy1, y1[j]) - xx2 = min(ix2, x2[j]) - yy2 = min(iy2, y2[j]) - w = max(0.0, xx2 - xx1 + 1) - h = max(0.0, yy2 - yy1 + 1) - inter = w * h - ovr = inter / (iarea + areas[j] - inter) - if ovr >= thresh: - suppressed[j] = 1 - - return np.where(suppressed == 0)[0] +## Note: Figure out the license details later. +# +# Based on: +# -------------------------------------------------------- +# Fast R-CNN +# Copyright (c) 2015 Microsoft +# Licensed under The MIT License [see LICENSE for details] +# Written by Ross Girshick +# -------------------------------------------------------- + +cimport cython +import numpy as np +cimport numpy as np + +cdef inline np.float32_t max(np.float32_t a, np.float32_t b) nogil: + return a if a >= b else b + +cdef inline np.float32_t min(np.float32_t a, np.float32_t b) nogil: + return a if a <= b else b + +@cython.boundscheck(False) +@cython.cdivision(True) +@cython.wraparound(False) +def nms(np.ndarray[np.float32_t, ndim=2] dets, np.float32_t thresh): + cdef np.ndarray[np.float32_t, ndim=1] x1 = dets[:, 0] + cdef np.ndarray[np.float32_t, ndim=1] y1 = dets[:, 1] + cdef np.ndarray[np.float32_t, ndim=1] x2 = dets[:, 2] + cdef np.ndarray[np.float32_t, ndim=1] y2 = dets[:, 3] + cdef np.ndarray[np.float32_t, ndim=1] scores = dets[:, 4] + + cdef np.ndarray[np.float32_t, ndim=1] areas = (x2 - x1 + 1) * (y2 - y1 + 1) + cdef np.ndarray[np.int64_t, ndim=1] order = scores.argsort()[::-1] + + cdef int ndets = dets.shape[0] + cdef np.ndarray[np.int_t, ndim=1] suppressed = \ + np.zeros((ndets), dtype=np.int) + + # nominal indices + cdef int _i, _j + # sorted indices + cdef int i, j + # temp variables for box i's (the box currently under consideration) + cdef np.float32_t ix1, iy1, ix2, iy2, iarea + # variables for computing overlap with box j (lower scoring box) + cdef np.float32_t xx1, yy1, xx2, yy2 + cdef np.float32_t w, h + cdef np.float32_t inter, ovr + + with nogil: + for _i in range(ndets): + i = order[_i] + if suppressed[i] == 1: + continue + ix1 = x1[i] + iy1 = y1[i] + ix2 = x2[i] + iy2 = y2[i] + iarea = areas[i] + for _j in range(_i + 1, ndets): + j = order[_j] + if suppressed[j] == 1: + continue + xx1 = max(ix1, x1[j]) + yy1 = max(iy1, y1[j]) + xx2 = min(ix2, x2[j]) + yy2 = min(iy2, y2[j]) + w = max(0.0, xx2 - xx1 + 1) + h = max(0.0, yy2 - yy1 + 1) + inter = w * h + ovr = inter / (iarea + areas[j] - inter) + if ovr >= thresh: + suppressed[j] = 1 + + return np.where(suppressed == 0)[0] diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/utils/functions.py b/PyTorch/contrib/cv/detection/YOLACT_plus/utils/functions.py index d9ce98c4f9..6dfeff2d4a 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/utils/functions.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/utils/functions.py @@ -1,227 +1,227 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import torch.nn as nn -import os -import math -from collections import deque -from pathlib import Path -from layers.interpolate import InterpolateModule - -class MovingAverage(): - """ Keeps an average window of the specified number of items. """ - - def __init__(self, max_window_size=1000): - self.max_window_size = max_window_size - self.reset() - - def add(self, elem): - """ Adds an element to the window, removing the earliest element if necessary. """ - if not math.isfinite(elem): - print('Warning: Moving average ignored a value of %f' % elem) - return - - self.window.append(elem) - self.sum += elem - - if len(self.window) > self.max_window_size: - self.sum -= self.window.popleft() - - def append(self, elem): - """ Same as add just more pythonic. """ - self.add(elem) - - def reset(self): - """ Resets the MovingAverage to its initial state. """ - self.window = deque() - self.sum = 0 - - def get_avg(self): - """ Returns the average of the elements in the window. """ - return self.sum / max(len(self.window), 1) - - def __str__(self): - return str(self.get_avg()) - - def __repr__(self): - return repr(self.get_avg()) - - def __len__(self): - return len(self.window) - - -class ProgressBar(): - """ A simple progress bar that just outputs a string. """ - - def __init__(self, length, max_val): - self.max_val = max_val - self.length = length - self.cur_val = 0 - - self.cur_num_bars = -1 - self._update_str() - - def set_val(self, new_val): - self.cur_val = new_val - - if self.cur_val > self.max_val: - self.cur_val = self.max_val - if self.cur_val < 0: - self.cur_val = 0 - - self._update_str() - - def is_finished(self): - return self.cur_val == self.max_val - - def _update_str(self): - num_bars = int(self.length * (self.cur_val / self.max_val)) - - if num_bars != self.cur_num_bars: - self.cur_num_bars = num_bars - self.string = '█' * num_bars + '░' * (self.length - num_bars) - - def __repr__(self): - return self.string - - def __str__(self): - return self.string - - -def init_console(): - """ - Initialize the console to be able to use ANSI escape characters on Windows. - """ - if os.name == 'nt': - from colorama import init - init() - - -class SavePath: - """ - Why is this a class? - Why do I have a class for creating and parsing save paths? - What am I doing with my life? - """ - - def __init__(self, model_name:str, epoch:int, iteration:int): - self.model_name = model_name - self.epoch = epoch - self.iteration = iteration - - def get_path(self, root:str=''): - file_name = self.model_name + '_' + str(self.epoch) + '_' + str(self.iteration) + '.pth' - return os.path.join(root, file_name) - - @staticmethod - def from_str(path:str): - file_name = os.path.basename(path) - - if file_name.endswith('.pth'): - file_name = file_name[:-4] - - params = file_name.split('_') - - if file_name.endswith('interrupt'): - params = params[:-1] - - model_name = '_'.join(params[:-2]) - epoch = params[-2] - iteration = params[-1] - - return SavePath(model_name, int(epoch), int(iteration)) - - @staticmethod - def remove_interrupt(save_folder): - for p in Path(save_folder).glob('*_interrupt.pth'): - p.unlink() - - @staticmethod - def get_interrupt(save_folder): - for p in Path(save_folder).glob('*_interrupt.pth'): - return str(p) - return None - - @staticmethod - def get_latest(save_folder, config): - """ Note: config should be config.name. """ - max_iter = -1 - max_name = None - - for p in Path(save_folder).glob(config + '_*'): - path_name = str(p) - - try: - save = SavePath.from_str(path_name) - except: - continue - - if save.model_name == config and save.iteration > max_iter: - max_iter = save.iteration - max_name = path_name - - return max_name - -def make_net(in_channels, conf, include_last_relu=True): - """ - A helper function to take a config setting and turn it into a network. - Used by protonet and extrahead. Returns (network, out_channels) - """ - def make_layer(layer_cfg): - nonlocal in_channels - - # Possible patterns: - # ( 256, 3, {}) -> conv - # ( 256,-2, {}) -> deconv - # (None,-2, {}) -> bilinear interpolate - # ('cat',[],{}) -> concat the subnetworks in the list - # - # You know it would have probably been simpler just to adopt a 'c' 'd' 'u' naming scheme. - # Whatever, it's too late now. - if isinstance(layer_cfg[0], str): - layer_name = layer_cfg[0] - - if layer_name == 'cat': - nets = [make_net(in_channels, x) for x in layer_cfg[1]] - layer = Concat([net[0] for net in nets], layer_cfg[2]) - num_channels = sum([net[1] for net in nets]) - else: - num_channels = layer_cfg[0] - kernel_size = layer_cfg[1] - - if kernel_size > 0: - layer = nn.Conv2d(in_channels, num_channels, kernel_size, **layer_cfg[2]) - else: - if num_channels is None: - layer = InterpolateModule(scale_factor=-kernel_size, mode='bilinear', align_corners=False, **layer_cfg[2]) - else: - layer = nn.ConvTranspose2d(in_channels, num_channels, -kernel_size, **layer_cfg[2]) - - in_channels = num_channels if num_channels is not None else in_channels - - # Don't return a ReLU layer if we're doing an upsample. This probably doesn't affect anything - # output-wise, but there's no need to go through a ReLU here. - # Commented out for backwards compatibility with previous models - # if num_channels is None: - # return [layer] - # else: - return [layer, nn.ReLU(inplace=True)] - - # Use sum to concat together all the component layer lists - net = sum([make_layer(x) for x in conf], []) - if not include_last_relu: - net = net[:-1] - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import torch.nn as nn +import os +import math +from collections import deque +from pathlib import Path +from layers.interpolate import InterpolateModule + +class MovingAverage(): + """ Keeps an average window of the specified number of items. """ + + def __init__(self, max_window_size=1000): + self.max_window_size = max_window_size + self.reset() + + def add(self, elem): + """ Adds an element to the window, removing the earliest element if necessary. """ + if not math.isfinite(elem): + print('Warning: Moving average ignored a value of %f' % elem) + return + + self.window.append(elem) + self.sum += elem + + if len(self.window) > self.max_window_size: + self.sum -= self.window.popleft() + + def append(self, elem): + """ Same as add just more pythonic. """ + self.add(elem) + + def reset(self): + """ Resets the MovingAverage to its initial state. """ + self.window = deque() + self.sum = 0 + + def get_avg(self): + """ Returns the average of the elements in the window. """ + return self.sum / max(len(self.window), 1) + + def __str__(self): + return str(self.get_avg()) + + def __repr__(self): + return repr(self.get_avg()) + + def __len__(self): + return len(self.window) + + +class ProgressBar(): + """ A simple progress bar that just outputs a string. """ + + def __init__(self, length, max_val): + self.max_val = max_val + self.length = length + self.cur_val = 0 + + self.cur_num_bars = -1 + self._update_str() + + def set_val(self, new_val): + self.cur_val = new_val + + if self.cur_val > self.max_val: + self.cur_val = self.max_val + if self.cur_val < 0: + self.cur_val = 0 + + self._update_str() + + def is_finished(self): + return self.cur_val == self.max_val + + def _update_str(self): + num_bars = int(self.length * (self.cur_val / self.max_val)) + + if num_bars != self.cur_num_bars: + self.cur_num_bars = num_bars + self.string = '█' * num_bars + '░' * (self.length - num_bars) + + def __repr__(self): + return self.string + + def __str__(self): + return self.string + + +def init_console(): + """ + Initialize the console to be able to use ANSI escape characters on Windows. + """ + if os.name == 'nt': + from colorama import init + init() + + +class SavePath: + """ + Why is this a class? + Why do I have a class for creating and parsing save paths? + What am I doing with my life? + """ + + def __init__(self, model_name:str, epoch:int, iteration:int): + self.model_name = model_name + self.epoch = epoch + self.iteration = iteration + + def get_path(self, root:str=''): + file_name = self.model_name + '_' + str(self.epoch) + '_' + str(self.iteration) + '.pth' + return os.path.join(root, file_name) + + @staticmethod + def from_str(path:str): + file_name = os.path.basename(path) + + if file_name.endswith('.pth'): + file_name = file_name[:-4] + + params = file_name.split('_') + + if file_name.endswith('interrupt'): + params = params[:-1] + + model_name = '_'.join(params[:-2]) + epoch = params[-2] + iteration = params[-1] + + return SavePath(model_name, int(epoch), int(iteration)) + + @staticmethod + def remove_interrupt(save_folder): + for p in Path(save_folder).glob('*_interrupt.pth'): + p.unlink() + + @staticmethod + def get_interrupt(save_folder): + for p in Path(save_folder).glob('*_interrupt.pth'): + return str(p) + return None + + @staticmethod + def get_latest(save_folder, config): + """ Note: config should be config.name. """ + max_iter = -1 + max_name = None + + for p in Path(save_folder).glob(config + '_*'): + path_name = str(p) + + try: + save = SavePath.from_str(path_name) + except: + continue + + if save.model_name == config and save.iteration > max_iter: + max_iter = save.iteration + max_name = path_name + + return max_name + +def make_net(in_channels, conf, include_last_relu=True): + """ + A helper function to take a config setting and turn it into a network. + Used by protonet and extrahead. Returns (network, out_channels) + """ + def make_layer(layer_cfg): + nonlocal in_channels + + # Possible patterns: + # ( 256, 3, {}) -> conv + # ( 256,-2, {}) -> deconv + # (None,-2, {}) -> bilinear interpolate + # ('cat',[],{}) -> concat the subnetworks in the list + # + # You know it would have probably been simpler just to adopt a 'c' 'd' 'u' naming scheme. + # Whatever, it's too late now. + if isinstance(layer_cfg[0], str): + layer_name = layer_cfg[0] + + if layer_name == 'cat': + nets = [make_net(in_channels, x) for x in layer_cfg[1]] + layer = Concat([net[0] for net in nets], layer_cfg[2]) + num_channels = sum([net[1] for net in nets]) + else: + num_channels = layer_cfg[0] + kernel_size = layer_cfg[1] + + if kernel_size > 0: + layer = nn.Conv2d(in_channels, num_channels, kernel_size, **layer_cfg[2]) + else: + if num_channels is None: + layer = InterpolateModule(scale_factor=-kernel_size, mode='bilinear', align_corners=False, **layer_cfg[2]) + else: + layer = nn.ConvTranspose2d(in_channels, num_channels, -kernel_size, **layer_cfg[2]) + + in_channels = num_channels if num_channels is not None else in_channels + + # Don't return a ReLU layer if we're doing an upsample. This probably doesn't affect anything + # output-wise, but there's no need to go through a ReLU here. + # Commented out for backwards compatibility with previous models + # if num_channels is None: + # return [layer] + # else: + return [layer, nn.ReLU(inplace=True)] + + # Use sum to concat together all the component layer lists + net = sum([make_layer(x) for x in conf], []) + if not include_last_relu: + net = net[:-1] + return nn.Sequential(*(net)), in_channels \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/utils/logger.py b/PyTorch/contrib/cv/detection/YOLACT_plus/utils/logger.py index cfc407bad5..7f84f57816 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/utils/logger.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/utils/logger.py @@ -1,503 +1,503 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import json -import time -import sys - -from typing import Union -import datetime - -from collections import defaultdict -import matplotlib.pyplot as plt -import numpy as np - -# Because Python's package heierarchy system sucks -if __name__ == '__main__': - from utils.nvinfo import gpu_info, visible_gpus, nvsmi_available - from utils.functions import MovingAverage -else: - from .nvinfo import gpu_info, visible_gpus, nvsmi_available - from .functions import MovingAverage - -class Log: - """ - A class to log information during training per information and save it out. - It also can include extra debug information like GPU usage / temp automatically. - - Extra args: - - session_data: If you have any data unique to this session, put it here. - - overwrite: Whether or not to overwrite a pre-existing log with this name. - - log_gpu_stats: Whether or not to log gpu information like temp, usage, memory. - Note that this requires nvidia-smi to be present in your PATH. - - log_time: Also log the time in each iteration. - """ - - def __init__(self, log_name:str, log_dir:str='logs/', session_data:dict={}, - overwrite:bool=False, log_gpu_stats:bool=True, log_time:bool=True): - - if log_gpu_stats and not nvsmi_available(): - print('Warning: Log created with log_gpu_stats=True, but nvidia-smi ' \ - 'was not found. Setting log_gpu_stats to False.') - log_gpu_stats = False - - if not os.path.exists(log_dir): - os.makedirs(log_dir) - self.log_path = os.path.join(log_dir, log_name + '.log') - - # if os.path.exists(self.log_path) and overwrite: - # os.unlink(self.log_path) - - if os.path.exists(self.log_path): - # Log already exists, so we're going to add to it. Increment the session counter. - with open(self.log_path, 'r') as f: - for last in f: pass - - if len(last) > 1: - self.session = json.loads(last)['session'] + 1 - else: - self.session = 0 - else: - self.session = 0 - - - self.log_gpu_stats = log_gpu_stats - self.log_time = log_time - - if self.log_gpu_stats: - self.visible_gpus = visible_gpus() - - - self._log_session_header(session_data) - - - def _log_session_header(self, session_data:dict): - """ - Log information that does not change between iterations here. - This is to cut down on the file size so you're not outputing this every iteration. - """ - info = {} - info['type'] = 'session' - info['session'] = self.session - - info['data'] = session_data - - if self.log_gpu_stats: - keys = ['idx', 'name', 'uuid', 'pwr_cap', 'mem_total'] - - gpus = gpu_info() - info['gpus'] = [{k: gpus[i][k] for k in keys} for i in self.visible_gpus] - - if self.log_time: - info['time'] = time.time() - - out = json.dumps(info) + '\n' - - with open(self.log_path, 'a') as f: - f.write(out) - - - def log(self, type:str, data:dict={}, **kwdargs): - """ - Add an iteration to the log with the specified data points. - Type should be the type of information this is (e.g., train, valid, etc.) - - You can either pass data points as kwdargs, or as a dictionary (or both!). - Values should be json-serializable. - """ - info = {} - - info['type'] = type - info['session'] = self.session - - kwdargs.update(data) - info['data'] = kwdargs - - if self.log_gpu_stats: - keys = ['fan_spd', 'temp', 'pwr_used', 'mem_used', 'util'] - - gpus = gpu_info() - info['gpus'] = [{k: gpus[i][k] for k in keys} for i in self.visible_gpus] - - if self.log_time: - info['time'] = time.time() - - - out = json.dumps(info) + '\n' - - with open(self.log_path, 'a') as f: - f.write(out) - - -class LogEntry(): - """ A class that allows you to navigate a dictonary using x.a.b[2].c, etc. """ - - def __init__(self, entry:Union[dict, list]): - self._ = entry - - def __getattr__(self, name): - if name == '_': - return self.__dict__['_'] - - res = self.__dict__['_'][name] - - if type(res) == dict or type(res) == list: - return LogEntry(res) - else: - return res - - def __getitem__(self, name): - return self.__getattr__(name) - - def __len__(self): - return len(self.__dict__['_']) - -class LogVisualizer(): - - COLORS = [ - 'xkcd:azure', - 'xkcd:coral', - 'xkcd:turquoise', - 'xkcd:orchid', - 'xkcd:orange', - - 'xkcd:blue', - 'xkcd:red', - 'xkcd:teal', - 'xkcd:magenta', - 'xkcd:orangered' - ] - - def __init__(self): - self.logs = [] - self.total_logs = [] - self.log_names = [] - - def _decode(self, query:str) -> list: - path, select = (query.split(';') + [''])[:2] - - if select.strip() == '': - select = lambda x, s: True - else: - select = eval('lambda x, s: ' + select) - - if path.strip() == '': - path = lambda x, s: x - else: - path = eval('lambda x, s: ' + path) - - return path, select - - def _follow(self, entry:LogEntry, query:list): - path, select = query - - try: - if select(entry, entry._s): - res = path(entry, entry._s) - - if type(res) == LogEntry: - return res.__dict__['_'] - else: - return res - else: - return None - except (KeyError, IndexError): - return None - - def _color(self, idx:int): - return self.COLORS[idx % len(self.COLORS)] - - def sessions(self, path:str): - """ Prints statistics about the sessions in the file. """ - - if not os.path.exists(path): - print(path + ' doesn\'t exist!') - return - - cur_session = None - cur_time = 0 - last_time = 0 - num_entries = 0 - - def pop_session(): - delta = last_time - cur_time - time_str = str(datetime.timedelta(seconds=delta)).split('.')[0] - print('Session % 3d: % 8d entries | %s elapsed' % (cur_session, num_entries, time_str)) - - with open(path, 'r') as f: - for line in f: - line = line.strip() - if len(line) > 0: - js = json.loads(line) - if js['type'] == 'session': - if cur_session is not None: - pop_session() - cur_time = js['time'] - cur_session = js['session'] - num_entries = 0 - last_time = js['time'] - num_entries += 1 - - pop_session() - - def add(self, path:str, session:Union[int,list]=None): - """ Add a log file to the list of logs being considered. """ - - log = defaultdict(lambda: []) - total_log = [] - - if not os.path.exists(path): - print(path + ' doesn\'t exist!') - return - - session_idx = 0 - ignoring = True - - def valid(idx): - if session is None: - return True - elif type(session) == int: - return (idx == session) - else: - return idx in session - - with open(path, 'r') as f: - for line in f: - line = line.strip() - if len(line) > 0: - js = json.loads(line) - - _type = js['type'] - if _type == 'session': - session_idx = js['session'] - ignoring = not valid(session_idx) - - if not ignoring: - ljs = LogEntry(js) - if _type == 'session': - js['_s'] = ljs - else: - js['_s'] =log['session'][-1] - log[_type].append(ljs) - total_log.append(ljs) - - name = os.path.basename(path) - if session is not None: - name += ' (Session %s)' % session - - self.logs.append(log) - self.total_logs.append(total_log) - self.log_names.append(name) - - def query(self, x:Union[str, list], entry_type:str=None, x_idx:int=None, log_idx:int=None) -> list: - """ - Given a query string (can be already decoded for faster computation), query the entire log - and return all values found by that query. If both log_idx and x_idx is None, this will be - a list of lists in the form [log_idx][result_idx]. If x_idx is not None, then the result - will be a list of [log_idx]. If both are not none, the return value will be a single query - return value. With entry_type=None, this will search the entire log. - """ - - if type(x) is not list: - x = self._decode(x) - - res = [] - - for idx in (range(len(self.logs)) if log_idx is None else [log_idx]): - candidates = [] - log = self.total_logs[idx] if entry_type is None else self.logs[idx][entry_type] - - for entry in log: - candidate = self._follow(entry, x) - if candidate is not None: - candidates.append(candidate) - - if x_idx is not None: - candidates = candidates[x_idx] - res.append(candidates) - - if log_idx is not None: - res = res[0] - return res - - def check(self, entry_type:str, x:str): - """ Checks the log for the valid keys for this input. """ - keys = set() - x = self._decode(x) - - for log in self.logs: - for datum in log[entry_type]: - res = self._follow(datum, x) - - if type(res) == dict: - for key in res.keys(): - keys.add(key) - elif type(res) == list: - keys.add('< %d' % len(res)) - - return list(keys) - - def plot(self, entry_type:str, x:str, y:str, smoothness:int=0): - """ Plot sequential log data. """ - - query_x = self._decode(x) - query_y = self._decode(y) - - for idx, (log, name) in enumerate(zip(self.logs, self.log_names)): - log = log[entry_type] - - if smoothness > 1: - avg = MovingAverage(smoothness) - - _x = [] - _y = [] - - for datum in log: - val_x = self._follow(datum, query_x) - val_y = self._follow(datum, query_y) - - if val_x is not None and val_y is not None: - if smoothness > 1: - avg.append(val_y) - val_y = avg.get_avg() - - if len(avg) < smoothness // 10: - continue - - _x.append(val_x) - _y.append(val_y) - - plt.plot(_x, _y, color=self._color(idx), label=name) - - plt.title(y.replace('x.', entry_type + '.')) - plt.legend() - plt.grid(linestyle=':', linewidth=0.5) - plt.show() - - def bar(self, entry_type:str, x:str, labels:list=None, diff:bool=False, x_idx:int=-1): - """ Plot a bar chart. The result of x should be list or dictionary. """ - - query = self._decode(x) - - data_points = [] - - for idx, (log, name) in enumerate(zip(self.logs, self.log_names)): - log = log[entry_type] - - candidates = [] - - for entry in log: - test = self._follow(entry, query) - - if type(test) == dict: - candidates.append(test) - elif type(test) == list: - candidates.append({idx: v for idx, v in enumerate(test)}) - - if len(candidates) > 0: - data_points.append((name, candidates[x_idx])) - - if len(data_points) == 0: - print('Warning: Nothing to show in bar chart!') - return - - names = [x[0] for x in data_points] - data_points = [x[1] for x in data_points] - - # Construct the labels for the data - if labels is not None: - data_labels = labels - else: - data_labels = set() - for datum in data_points: - for k in datum: - data_labels.add(k) - - data_labels = list(data_labels) - data_labels.sort() - - - data_values = [[(datum[k] if k in datum else None) for k in data_labels] for datum in data_points] - - if diff: - for idx in reversed(range(len(data_values))): - for jdx in range(len(data_labels)): - if data_values[0][jdx] is None or data_values[idx][jdx] is None: - data_values[idx][jdx] = None - else: - data_values[idx][jdx] -= data_values[0][jdx] - - - series_labels = names - - # Plot the graph now - num_bars = len(series_labels) - bar_width = 1 / (num_bars + 1) - - # Set position of bar on X axis - positions = [np.arange(len(data_labels))] - for _ in range(1, num_bars): - positions.append([x + bar_width for x in positions[-1]]) - - # Make the plot - for idx, (series, data, pos) in enumerate(zip(series_labels, data_values, positions)): - plt.bar(pos, data, color=self._color(idx), width=bar_width, edgecolor='white', label=series) - - # Add xticks on the middle of the group bars - plt.title(x.replace('x.', entry_type + '.') + (' diff' if diff else '')) - plt.xticks([r + bar_width for r in range(len(data_labels))], data_labels) - - # Create legend & Show graphic - plt.legend() - plt.show() - - - - def elapsed_time(self, cond1:str='', cond2:str='', legible:bool=True) -> list: - """ - Returns the elapsed time between two entries based on the given conditionals. - If a query isn't specified, the first / last entry will be used. The first query - uses the first value and the second query uses the last value in the results. - - Setting legible to true returns human-readable results, while false returns seconds. - """ - q1 = 'x.time; ' + cond1 - q2 = 'x.time; ' + cond2 - - x1 = self.query(q1, x_idx=0) - x2 = self.query(q2, x_idx=-1) - - diff = (lambda x: str(datetime.timedelta(seconds=x)).split('.')[0]) if legible else lambda x: x - - return [diff(b - a) for a, b in zip(x1, x2)] - - - - - - - - - - - -if __name__ == '__main__': - if len(sys.argv) < 4+1: - print('Usage: python utils/logger.py ') - exit() - - vis = LogVisualizer() - vis.add(sys.argv[1]) - vis.plot(sys.argv[2], sys.argv[3], sys.argv[4]) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import json +import time +import sys + +from typing import Union +import datetime + +from collections import defaultdict +import matplotlib.pyplot as plt +import numpy as np + +# Because Python's package heierarchy system sucks +if __name__ == '__main__': + from utils.nvinfo import gpu_info, visible_gpus, nvsmi_available + from utils.functions import MovingAverage +else: + from .nvinfo import gpu_info, visible_gpus, nvsmi_available + from .functions import MovingAverage + +class Log: + """ + A class to log information during training per information and save it out. + It also can include extra debug information like GPU usage / temp automatically. + + Extra args: + - session_data: If you have any data unique to this session, put it here. + - overwrite: Whether or not to overwrite a pre-existing log with this name. + - log_gpu_stats: Whether or not to log gpu information like temp, usage, memory. + Note that this requires nvidia-smi to be present in your PATH. + - log_time: Also log the time in each iteration. + """ + + def __init__(self, log_name:str, log_dir:str='logs/', session_data:dict={}, + overwrite:bool=False, log_gpu_stats:bool=True, log_time:bool=True): + + if log_gpu_stats and not nvsmi_available(): + print('Warning: Log created with log_gpu_stats=True, but nvidia-smi ' \ + 'was not found. Setting log_gpu_stats to False.') + log_gpu_stats = False + + if not os.path.exists(log_dir): + os.makedirs(log_dir) + self.log_path = os.path.join(log_dir, log_name + '.log') + + # if os.path.exists(self.log_path) and overwrite: + # os.unlink(self.log_path) + + if os.path.exists(self.log_path): + # Log already exists, so we're going to add to it. Increment the session counter. + with open(self.log_path, 'r') as f: + for last in f: pass + + if len(last) > 1: + self.session = json.loads(last)['session'] + 1 + else: + self.session = 0 + else: + self.session = 0 + + + self.log_gpu_stats = log_gpu_stats + self.log_time = log_time + + if self.log_gpu_stats: + self.visible_gpus = visible_gpus() + + + self._log_session_header(session_data) + + + def _log_session_header(self, session_data:dict): + """ + Log information that does not change between iterations here. + This is to cut down on the file size so you're not outputing this every iteration. + """ + info = {} + info['type'] = 'session' + info['session'] = self.session + + info['data'] = session_data + + if self.log_gpu_stats: + keys = ['idx', 'name', 'uuid', 'pwr_cap', 'mem_total'] + + gpus = gpu_info() + info['gpus'] = [{k: gpus[i][k] for k in keys} for i in self.visible_gpus] + + if self.log_time: + info['time'] = time.time() + + out = json.dumps(info) + '\n' + + with open(self.log_path, 'a') as f: + f.write(out) + + + def log(self, type:str, data:dict={}, **kwdargs): + """ + Add an iteration to the log with the specified data points. + Type should be the type of information this is (e.g., train, valid, etc.) + + You can either pass data points as kwdargs, or as a dictionary (or both!). + Values should be json-serializable. + """ + info = {} + + info['type'] = type + info['session'] = self.session + + kwdargs.update(data) + info['data'] = kwdargs + + if self.log_gpu_stats: + keys = ['fan_spd', 'temp', 'pwr_used', 'mem_used', 'util'] + + gpus = gpu_info() + info['gpus'] = [{k: gpus[i][k] for k in keys} for i in self.visible_gpus] + + if self.log_time: + info['time'] = time.time() + + + out = json.dumps(info) + '\n' + + with open(self.log_path, 'a') as f: + f.write(out) + + +class LogEntry(): + """ A class that allows you to navigate a dictonary using x.a.b[2].c, etc. """ + + def __init__(self, entry:Union[dict, list]): + self._ = entry + + def __getattr__(self, name): + if name == '_': + return self.__dict__['_'] + + res = self.__dict__['_'][name] + + if type(res) == dict or type(res) == list: + return LogEntry(res) + else: + return res + + def __getitem__(self, name): + return self.__getattr__(name) + + def __len__(self): + return len(self.__dict__['_']) + +class LogVisualizer(): + + COLORS = [ + 'xkcd:azure', + 'xkcd:coral', + 'xkcd:turquoise', + 'xkcd:orchid', + 'xkcd:orange', + + 'xkcd:blue', + 'xkcd:red', + 'xkcd:teal', + 'xkcd:magenta', + 'xkcd:orangered' + ] + + def __init__(self): + self.logs = [] + self.total_logs = [] + self.log_names = [] + + def _decode(self, query:str) -> list: + path, select = (query.split(';') + [''])[:2] + + if select.strip() == '': + select = lambda x, s: True + else: + select = eval('lambda x, s: ' + select) + + if path.strip() == '': + path = lambda x, s: x + else: + path = eval('lambda x, s: ' + path) + + return path, select + + def _follow(self, entry:LogEntry, query:list): + path, select = query + + try: + if select(entry, entry._s): + res = path(entry, entry._s) + + if type(res) == LogEntry: + return res.__dict__['_'] + else: + return res + else: + return None + except (KeyError, IndexError): + return None + + def _color(self, idx:int): + return self.COLORS[idx % len(self.COLORS)] + + def sessions(self, path:str): + """ Prints statistics about the sessions in the file. """ + + if not os.path.exists(path): + print(path + ' doesn\'t exist!') + return + + cur_session = None + cur_time = 0 + last_time = 0 + num_entries = 0 + + def pop_session(): + delta = last_time - cur_time + time_str = str(datetime.timedelta(seconds=delta)).split('.')[0] + print('Session % 3d: % 8d entries | %s elapsed' % (cur_session, num_entries, time_str)) + + with open(path, 'r') as f: + for line in f: + line = line.strip() + if len(line) > 0: + js = json.loads(line) + if js['type'] == 'session': + if cur_session is not None: + pop_session() + cur_time = js['time'] + cur_session = js['session'] + num_entries = 0 + last_time = js['time'] + num_entries += 1 + + pop_session() + + def add(self, path:str, session:Union[int,list]=None): + """ Add a log file to the list of logs being considered. """ + + log = defaultdict(lambda: []) + total_log = [] + + if not os.path.exists(path): + print(path + ' doesn\'t exist!') + return + + session_idx = 0 + ignoring = True + + def valid(idx): + if session is None: + return True + elif type(session) == int: + return (idx == session) + else: + return idx in session + + with open(path, 'r') as f: + for line in f: + line = line.strip() + if len(line) > 0: + js = json.loads(line) + + _type = js['type'] + if _type == 'session': + session_idx = js['session'] + ignoring = not valid(session_idx) + + if not ignoring: + ljs = LogEntry(js) + if _type == 'session': + js['_s'] = ljs + else: + js['_s'] =log['session'][-1] + log[_type].append(ljs) + total_log.append(ljs) + + name = os.path.basename(path) + if session is not None: + name += ' (Session %s)' % session + + self.logs.append(log) + self.total_logs.append(total_log) + self.log_names.append(name) + + def query(self, x:Union[str, list], entry_type:str=None, x_idx:int=None, log_idx:int=None) -> list: + """ + Given a query string (can be already decoded for faster computation), query the entire log + and return all values found by that query. If both log_idx and x_idx is None, this will be + a list of lists in the form [log_idx][result_idx]. If x_idx is not None, then the result + will be a list of [log_idx]. If both are not none, the return value will be a single query + return value. With entry_type=None, this will search the entire log. + """ + + if type(x) is not list: + x = self._decode(x) + + res = [] + + for idx in (range(len(self.logs)) if log_idx is None else [log_idx]): + candidates = [] + log = self.total_logs[idx] if entry_type is None else self.logs[idx][entry_type] + + for entry in log: + candidate = self._follow(entry, x) + if candidate is not None: + candidates.append(candidate) + + if x_idx is not None: + candidates = candidates[x_idx] + res.append(candidates) + + if log_idx is not None: + res = res[0] + return res + + def check(self, entry_type:str, x:str): + """ Checks the log for the valid keys for this input. """ + keys = set() + x = self._decode(x) + + for log in self.logs: + for datum in log[entry_type]: + res = self._follow(datum, x) + + if type(res) == dict: + for key in res.keys(): + keys.add(key) + elif type(res) == list: + keys.add('< %d' % len(res)) + + return list(keys) + + def plot(self, entry_type:str, x:str, y:str, smoothness:int=0): + """ Plot sequential log data. """ + + query_x = self._decode(x) + query_y = self._decode(y) + + for idx, (log, name) in enumerate(zip(self.logs, self.log_names)): + log = log[entry_type] + + if smoothness > 1: + avg = MovingAverage(smoothness) + + _x = [] + _y = [] + + for datum in log: + val_x = self._follow(datum, query_x) + val_y = self._follow(datum, query_y) + + if val_x is not None and val_y is not None: + if smoothness > 1: + avg.append(val_y) + val_y = avg.get_avg() + + if len(avg) < smoothness // 10: + continue + + _x.append(val_x) + _y.append(val_y) + + plt.plot(_x, _y, color=self._color(idx), label=name) + + plt.title(y.replace('x.', entry_type + '.')) + plt.legend() + plt.grid(linestyle=':', linewidth=0.5) + plt.show() + + def bar(self, entry_type:str, x:str, labels:list=None, diff:bool=False, x_idx:int=-1): + """ Plot a bar chart. The result of x should be list or dictionary. """ + + query = self._decode(x) + + data_points = [] + + for idx, (log, name) in enumerate(zip(self.logs, self.log_names)): + log = log[entry_type] + + candidates = [] + + for entry in log: + test = self._follow(entry, query) + + if type(test) == dict: + candidates.append(test) + elif type(test) == list: + candidates.append({idx: v for idx, v in enumerate(test)}) + + if len(candidates) > 0: + data_points.append((name, candidates[x_idx])) + + if len(data_points) == 0: + print('Warning: Nothing to show in bar chart!') + return + + names = [x[0] for x in data_points] + data_points = [x[1] for x in data_points] + + # Construct the labels for the data + if labels is not None: + data_labels = labels + else: + data_labels = set() + for datum in data_points: + for k in datum: + data_labels.add(k) + + data_labels = list(data_labels) + data_labels.sort() + + + data_values = [[(datum[k] if k in datum else None) for k in data_labels] for datum in data_points] + + if diff: + for idx in reversed(range(len(data_values))): + for jdx in range(len(data_labels)): + if data_values[0][jdx] is None or data_values[idx][jdx] is None: + data_values[idx][jdx] = None + else: + data_values[idx][jdx] -= data_values[0][jdx] + + + series_labels = names + + # Plot the graph now + num_bars = len(series_labels) + bar_width = 1 / (num_bars + 1) + + # Set position of bar on X axis + positions = [np.arange(len(data_labels))] + for _ in range(1, num_bars): + positions.append([x + bar_width for x in positions[-1]]) + + # Make the plot + for idx, (series, data, pos) in enumerate(zip(series_labels, data_values, positions)): + plt.bar(pos, data, color=self._color(idx), width=bar_width, edgecolor='white', label=series) + + # Add xticks on the middle of the group bars + plt.title(x.replace('x.', entry_type + '.') + (' diff' if diff else '')) + plt.xticks([r + bar_width for r in range(len(data_labels))], data_labels) + + # Create legend & Show graphic + plt.legend() + plt.show() + + + + def elapsed_time(self, cond1:str='', cond2:str='', legible:bool=True) -> list: + """ + Returns the elapsed time between two entries based on the given conditionals. + If a query isn't specified, the first / last entry will be used. The first query + uses the first value and the second query uses the last value in the results. + + Setting legible to true returns human-readable results, while false returns seconds. + """ + q1 = 'x.time; ' + cond1 + q2 = 'x.time; ' + cond2 + + x1 = self.query(q1, x_idx=0) + x2 = self.query(q2, x_idx=-1) + + diff = (lambda x: str(datetime.timedelta(seconds=x)).split('.')[0]) if legible else lambda x: x + + return [diff(b - a) for a, b in zip(x1, x2)] + + + + + + + + + + + +if __name__ == '__main__': + if len(sys.argv) < 4+1: + print('Usage: python utils/logger.py ') + exit() + + vis = LogVisualizer() + vis.add(sys.argv[1]) + vis.plot(sys.argv[2], sys.argv[3], sys.argv[4]) diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/utils/nvinfo.py b/PyTorch/contrib/cv/detection/YOLACT_plus/utils/nvinfo.py index 689abc140c..62052d2683 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/utils/nvinfo.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/utils/nvinfo.py @@ -1,77 +1,77 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ -# My version of nvgpu because nvgpu didn't have all the information I was looking for. -import re -import subprocess -import shutil -import os - -def gpu_info() -> list: - """ - Returns a dictionary of stats mined from nvidia-smi for each gpu in a list. - Adapted from nvgpu: https://pypi.org/project/nvgpu/, but mine has more info. - """ - gpus = [line for line in _run_cmd(['nvidia-smi', '-L']) if line] - gpu_infos = [re.match('GPU ([0-9]+): ([^(]+) \(UUID: ([^)]+)\)', gpu).groups() for gpu in gpus] - gpu_infos = [dict(zip(['idx', 'name', 'uuid'], info)) for info in gpu_infos] - gpu_count = len(gpus) - - lines = _run_cmd(['nvidia-smi']) - selected_lines = lines[7:7 + 3 * gpu_count] - for i in range(gpu_count): - mem_used, mem_total = [int(m.strip().replace('MiB', '')) for m in - selected_lines[3 * i + 1].split('|')[2].strip().split('/')] - - pw_tmp_info, mem_info, util_info = [x.strip() for x in selected_lines[3 * i + 1].split('|')[1:-1]] - - pw_tmp_info = [x[:-1] for x in pw_tmp_info.split(' ') if len(x) > 0] - fan_speed, temperature, pwr_used, pwr_cap = [int(pw_tmp_info[i]) for i in (0, 1, 3, 5)] - gpu_infos[i]['fan_spd' ] = fan_speed - gpu_infos[i]['temp' ] = temperature - gpu_infos[i]['pwr_used'] = pwr_used - gpu_infos[i]['pwr_cap' ] = pwr_cap - - mem_used, mem_total = [int(x) for x in mem_info.replace('MiB', '').split(' / ')] - gpu_infos[i]['mem_used' ] = mem_used - gpu_infos[i]['mem_total'] = mem_total - - utilization = int(util_info.split(' ')[0][:-1]) - gpu_infos[i]['util'] = utilization - - gpu_infos[i]['idx'] = int(gpu_infos[i]['idx']) - - return gpu_infos - -def nvsmi_available() -> bool: - """ Returns whether or not nvidia-smi is present in this system's PATH. """ - return shutil.which('nvidia-smi') is not None - - -def visible_gpus() -> list: - """ Returns a list of the indexes of all the gpus visible to pytorch. """ - - if 'CUDA_VISIBLE_DEVICES' not in os.environ: - return list(range(len(gpu_info()))) - else: - return [int(x.strip()) for x in os.environ['CUDA_VISIBLE_DEVICES'].split(',')] - - - - -def _run_cmd(cmd:list) -> list: - """ Runs a command and returns a list of output lines. """ - output = subprocess.check_output(cmd) - output = output.decode('UTF-8') +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +# My version of nvgpu because nvgpu didn't have all the information I was looking for. +import re +import subprocess +import shutil +import os + +def gpu_info() -> list: + """ + Returns a dictionary of stats mined from nvidia-smi for each gpu in a list. + Adapted from nvgpu: https://pypi.org/project/nvgpu/, but mine has more info. + """ + gpus = [line for line in _run_cmd(['nvidia-smi', '-L']) if line] + gpu_infos = [re.match('GPU ([0-9]+): ([^(]+) \(UUID: ([^)]+)\)', gpu).groups() for gpu in gpus] + gpu_infos = [dict(zip(['idx', 'name', 'uuid'], info)) for info in gpu_infos] + gpu_count = len(gpus) + + lines = _run_cmd(['nvidia-smi']) + selected_lines = lines[7:7 + 3 * gpu_count] + for i in range(gpu_count): + mem_used, mem_total = [int(m.strip().replace('MiB', '')) for m in + selected_lines[3 * i + 1].split('|')[2].strip().split('/')] + + pw_tmp_info, mem_info, util_info = [x.strip() for x in selected_lines[3 * i + 1].split('|')[1:-1]] + + pw_tmp_info = [x[:-1] for x in pw_tmp_info.split(' ') if len(x) > 0] + fan_speed, temperature, pwr_used, pwr_cap = [int(pw_tmp_info[i]) for i in (0, 1, 3, 5)] + gpu_infos[i]['fan_spd' ] = fan_speed + gpu_infos[i]['temp' ] = temperature + gpu_infos[i]['pwr_used'] = pwr_used + gpu_infos[i]['pwr_cap' ] = pwr_cap + + mem_used, mem_total = [int(x) for x in mem_info.replace('MiB', '').split(' / ')] + gpu_infos[i]['mem_used' ] = mem_used + gpu_infos[i]['mem_total'] = mem_total + + utilization = int(util_info.split(' ')[0][:-1]) + gpu_infos[i]['util'] = utilization + + gpu_infos[i]['idx'] = int(gpu_infos[i]['idx']) + + return gpu_infos + +def nvsmi_available() -> bool: + """ Returns whether or not nvidia-smi is present in this system's PATH. """ + return shutil.which('nvidia-smi') is not None + + +def visible_gpus() -> list: + """ Returns a list of the indexes of all the gpus visible to pytorch. """ + + if 'CUDA_VISIBLE_DEVICES' not in os.environ: + return list(range(len(gpu_info()))) + else: + return [int(x.strip()) for x in os.environ['CUDA_VISIBLE_DEVICES'].split(',')] + + + + +def _run_cmd(cmd:list) -> list: + """ Runs a command and returns a list of output lines. """ + output = subprocess.check_output(cmd) + output = output.decode('UTF-8') return output.split('\n') \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/utils/timer.py b/PyTorch/contrib/cv/detection/YOLACT_plus/utils/timer.py index f5f4404a81..2323e97e47 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/utils/timer.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/utils/timer.py @@ -1,145 +1,145 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 time -from collections import defaultdict - -_total_times = defaultdict(lambda: 0) -_start_times = defaultdict(lambda: -1) -_disabled_names = set() -_timer_stack = [] -_running_timer = None -_disable_all = False - -def disable_all(): - global _disable_all - _disable_all = True - -def enable_all(): - global _disable_all - _disable_all = False - -def disable(fn_name): - """ Disables the given function name fom being considered for the average or outputted in print_stats. """ - _disabled_names.add(fn_name) - -def enable(fn_name): - """ Enables function names disabled by disable. """ - _disabled_names.remove(fn_name) - -def reset(): - """ Resets the current timer. Call this at the start of an iteration. """ - global _running_timer - _total_times.clear() - _start_times.clear() - _timer_stack.clear() - _running_timer = None - -def start(fn_name, use_stack=True): - """ - Start timing the specific function. - Note: If use_stack is True, only one timer can be active at a time. - Once you stop this timer, the previous one will start again. - """ - global _running_timer, _disable_all - - if _disable_all: - return - - if use_stack: - if _running_timer is not None: - stop(_running_timer, use_stack=False) - _timer_stack.append(_running_timer) - start(fn_name, use_stack=False) - _running_timer = fn_name - else: - _start_times[fn_name] = time.perf_counter() - -def stop(fn_name=None, use_stack=True): - """ - If use_stack is True, this will stop the currently running timer and restore - the previous timer on the stack if that exists. Note if use_stack is True, - fn_name will be ignored. - - If use_stack is False, this will just stop timing the timer fn_name. - """ - global _running_timer, _disable_all - - if _disable_all: - return - - if use_stack: - if _running_timer is not None: - stop(_running_timer, use_stack=False) - if len(_timer_stack) > 0: - _running_timer = _timer_stack.pop() - start(_running_timer, use_stack=False) - else: - _running_timer = None - else: - print('Warning: timer stopped with no timer running!') - else: - if _start_times[fn_name] > -1: - _total_times[fn_name] += time.perf_counter() - _start_times[fn_name] - else: - print('Warning: timer for %s stopped before starting!' % fn_name) - - -def print_stats(): - """ Prints the current timing information into a table. """ - print() - - all_fn_names = [k for k in _total_times.keys() if k not in _disabled_names] - - max_name_width = max([len(k) for k in all_fn_names] + [4]) - if max_name_width % 2 == 1: max_name_width += 1 - format_str = ' {:>%d} | {:>10.4f} ' % max_name_width - - header = (' {:^%d} | {:^10} ' % max_name_width).format('Name', 'Time (ms)') - print(header) - - sep_idx = header.find('|') - sep_text = ('-' * sep_idx) + '+' + '-' * (len(header)-sep_idx-1) - print(sep_text) - - for name in all_fn_names: - print(format_str.format(name, _total_times[name]*1000)) - - print(sep_text) - print(format_str.format('Total', total_time()*1000)) - print() - -def total_time(): - """ Returns the total amount accumulated across all functions in seconds. """ - return sum([elapsed_time for name, elapsed_time in _total_times.items() if name not in _disabled_names]) - - -class env(): - """ - A class that lets you go: - with timer.env(fn_name): - # (...) - That automatically manages a timer start and stop for you. - """ - - def __init__(self, fn_name, use_stack=True): - self.fn_name = fn_name - self.use_stack = use_stack - - def __enter__(self): - start(self.fn_name, use_stack=self.use_stack) - - def __exit__(self, e, ev, t): - stop(self.fn_name, use_stack=self.use_stack) - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 time +from collections import defaultdict + +_total_times = defaultdict(lambda: 0) +_start_times = defaultdict(lambda: -1) +_disabled_names = set() +_timer_stack = [] +_running_timer = None +_disable_all = False + +def disable_all(): + global _disable_all + _disable_all = True + +def enable_all(): + global _disable_all + _disable_all = False + +def disable(fn_name): + """ Disables the given function name fom being considered for the average or outputted in print_stats. """ + _disabled_names.add(fn_name) + +def enable(fn_name): + """ Enables function names disabled by disable. """ + _disabled_names.remove(fn_name) + +def reset(): + """ Resets the current timer. Call this at the start of an iteration. """ + global _running_timer + _total_times.clear() + _start_times.clear() + _timer_stack.clear() + _running_timer = None + +def start(fn_name, use_stack=True): + """ + Start timing the specific function. + Note: If use_stack is True, only one timer can be active at a time. + Once you stop this timer, the previous one will start again. + """ + global _running_timer, _disable_all + + if _disable_all: + return + + if use_stack: + if _running_timer is not None: + stop(_running_timer, use_stack=False) + _timer_stack.append(_running_timer) + start(fn_name, use_stack=False) + _running_timer = fn_name + else: + _start_times[fn_name] = time.perf_counter() + +def stop(fn_name=None, use_stack=True): + """ + If use_stack is True, this will stop the currently running timer and restore + the previous timer on the stack if that exists. Note if use_stack is True, + fn_name will be ignored. + + If use_stack is False, this will just stop timing the timer fn_name. + """ + global _running_timer, _disable_all + + if _disable_all: + return + + if use_stack: + if _running_timer is not None: + stop(_running_timer, use_stack=False) + if len(_timer_stack) > 0: + _running_timer = _timer_stack.pop() + start(_running_timer, use_stack=False) + else: + _running_timer = None + else: + print('Warning: timer stopped with no timer running!') + else: + if _start_times[fn_name] > -1: + _total_times[fn_name] += time.perf_counter() - _start_times[fn_name] + else: + print('Warning: timer for %s stopped before starting!' % fn_name) + + +def print_stats(): + """ Prints the current timing information into a table. """ + print() + + all_fn_names = [k for k in _total_times.keys() if k not in _disabled_names] + + max_name_width = max([len(k) for k in all_fn_names] + [4]) + if max_name_width % 2 == 1: max_name_width += 1 + format_str = ' {:>%d} | {:>10.4f} ' % max_name_width + + header = (' {:^%d} | {:^10} ' % max_name_width).format('Name', 'Time (ms)') + print(header) + + sep_idx = header.find('|') + sep_text = ('-' * sep_idx) + '+' + '-' * (len(header)-sep_idx-1) + print(sep_text) + + for name in all_fn_names: + print(format_str.format(name, _total_times[name]*1000)) + + print(sep_text) + print(format_str.format('Total', total_time()*1000)) + print() + +def total_time(): + """ Returns the total amount accumulated across all functions in seconds. """ + return sum([elapsed_time for name, elapsed_time in _total_times.items() if name not in _disabled_names]) + + +class env(): + """ + A class that lets you go: + with timer.env(fn_name): + # (...) + That automatically manages a timer start and stop for you. + """ + + def __init__(self, fn_name, use_stack=True): + self.fn_name = fn_name + self.use_stack = use_stack + + def __enter__(self): + start(self.fn_name, use_stack=self.use_stack) + + def __exit__(self, e, ev, t): + stop(self.fn_name, use_stack=self.use_stack) + diff --git a/PyTorch/contrib/cv/detection/YOLACT_plus/yolact.py b/PyTorch/contrib/cv/detection/YOLACT_plus/yolact.py index a59a15bdf4..59490549ed 100644 --- a/PyTorch/contrib/cv/detection/YOLACT_plus/yolact.py +++ b/PyTorch/contrib/cv/detection/YOLACT_plus/yolact.py @@ -1,739 +1,739 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch, torchvision -import torch.nn as nn -import torch.nn.functional as F -from torchvision.models.resnet import Bottleneck -import numpy as np -from itertools import product -from math import sqrt -from typing import List -from collections import defaultdict - -from data.config import cfg, mask_type -from layers import Detect -from layers.interpolate import InterpolateModule -from backbone import construct_backbone - -import torch.backends.cudnn as cudnn -from utils import timer -from utils.functions import MovingAverage, make_net - -# This is required for Pytorch 1.0.1 on Windows to initialize Cuda on some driver versions. -# See the bug report here: https://github.com/pytorch/pytorch/issues/17108 -#torch.cuda.current_device() - -# As of March 10, 2019, Pytorch DataParallel still doesn't support JIT Script Modules -use_jit = False -if not use_jit: - print('Multiple GPUs detected! Turning off JIT.') - -ScriptModuleWrapper = torch.jit.ScriptModule if use_jit else nn.Module -script_method_wrapper = torch.jit.script_method if use_jit else lambda fn, _rcn=None: fn - - - -class Concat(nn.Module): - def __init__(self, nets, extra_params): - super().__init__() - - self.nets = nn.ModuleList(nets) - self.extra_params = extra_params - - def forward(self, x): - # Concat each along the channel dimension - return torch.cat([net(x) for net in self.nets], dim=1, **self.extra_params) - -prior_cache = defaultdict(lambda: None) - -class PredictionModule(nn.Module): - """ - The (c) prediction module adapted from DSSD: - https://arxiv.org/pdf/1701.06659.pdf - - Note that this is slightly different to the module in the paper - because the Bottleneck block actually has a 3x3 convolution in - the middle instead of a 1x1 convolution. Though, I really can't - be arsed to implement it myself, and, who knows, this might be - better. - - Args: - - in_channels: The input feature size. - - out_channels: The output feature size (must be a multiple of 4). - - aspect_ratios: A list of lists of priorbox aspect ratios (one list per scale). - - scales: A list of priorbox scales relative to this layer's convsize. - For instance: If this layer has convouts of size 30x30 for - an image of size 600x600, the 'default' (scale - of 1) for this layer would produce bounding - boxes with an area of 20x20px. If the scale is - .5 on the other hand, this layer would consider - bounding boxes with area 10x10px, etc. - - parent: If parent is a PredictionModule, this module will use all the layers - from parent instead of from this module. - """ - - def __init__(self, in_channels, out_channels=1024, aspect_ratios=[[1]], scales=[1], parent=None, index=0): - super().__init__() - - self.num_classes = cfg.num_classes - self.mask_dim = cfg.mask_dim # Defined by Yolact - self.num_priors = sum(len(x)*len(scales) for x in aspect_ratios) - self.parent = [parent] # Don't include this in the state dict - self.index = index - self.num_heads = cfg.num_heads # Defined by Yolact - - if cfg.mask_proto_split_prototypes_by_head and cfg.mask_type == mask_type.lincomb: - self.mask_dim = self.mask_dim // self.num_heads - - if cfg.mask_proto_prototypes_as_features: - in_channels += self.mask_dim - - if parent is None: - if cfg.extra_head_net is None: - out_channels = in_channels - else: - self.upfeature, out_channels = make_net(in_channels, cfg.extra_head_net) - - if cfg.use_prediction_module: - self.block = Bottleneck(out_channels, out_channels // 4) - self.conv = nn.Conv2d(out_channels, out_channels, kernel_size=1, bias=True) - self.bn = nn.BatchNorm2d(out_channels) - - self.bbox_layer = nn.Conv2d(out_channels, self.num_priors * 4, **cfg.head_layer_params) - self.conf_layer = nn.Conv2d(out_channels, self.num_priors * self.num_classes, **cfg.head_layer_params) - self.mask_layer = nn.Conv2d(out_channels, self.num_priors * self.mask_dim, **cfg.head_layer_params) - - if cfg.use_mask_scoring: - self.score_layer = nn.Conv2d(out_channels, self.num_priors, **cfg.head_layer_params) - - if cfg.use_instance_coeff: - self.inst_layer = nn.Conv2d(out_channels, self.num_priors * cfg.num_instance_coeffs, **cfg.head_layer_params) - - # What is this ugly lambda doing in the middle of all this clean prediction module code? - def make_extra(num_layers): - if num_layers == 0: - return lambda x: x - else: - # Looks more complicated than it is. This just creates an array of num_layers alternating conv-relu - return nn.Sequential(*sum([[ - nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1), - nn.ReLU(inplace=True) - ] for _ in range(num_layers)], [])) - - self.bbox_extra, self.conf_extra, self.mask_extra = [make_extra(x) for x in cfg.extra_layers] - - if cfg.mask_type == mask_type.lincomb and cfg.mask_proto_coeff_gate: - self.gate_layer = nn.Conv2d(out_channels, self.num_priors * self.mask_dim, kernel_size=3, padding=1) - - self.aspect_ratios = aspect_ratios - self.scales = scales - - self.priors = None - self.last_conv_size = None - self.last_img_size = None - - def forward(self, x): - """ - Args: - - x: The convOut from a layer in the backbone network - Size: [batch_size, in_channels, conv_h, conv_w]) - - Returns a tuple (bbox_coords, class_confs, mask_output, prior_boxes) with sizes - - bbox_coords: [batch_size, conv_h*conv_w*num_priors, 4] - - class_confs: [batch_size, conv_h*conv_w*num_priors, num_classes] - - mask_output: [batch_size, conv_h*conv_w*num_priors, mask_dim] - - prior_boxes: [conv_h*conv_w*num_priors, 4] - """ - # In case we want to use another module's layers - src = self if self.parent[0] is None else self.parent[0] - - conv_h = x.size(2) - conv_w = x.size(3) - - if cfg.extra_head_net is not None: - x = src.upfeature(x) - - if cfg.use_prediction_module: - # The two branches of PM design (c) - a = src.block(x) - - b = src.conv(x) - b = src.bn(b) - b = F.relu(b) - - # TODO: Possibly switch this out for a product - x = a + b - - bbox_x = src.bbox_extra(x) - conf_x = src.conf_extra(x) - mask_x = src.mask_extra(x) - - bbox = src.bbox_layer(bbox_x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, 4) - conf = src.conf_layer(conf_x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, self.num_classes) - - if cfg.eval_mask_branch: - mask = src.mask_layer(mask_x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, self.mask_dim) - else: - mask = torch.zeros(x.size(0), bbox.size(1), self.mask_dim, device=bbox.device) - - if cfg.use_mask_scoring: - score = src.score_layer(x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, 1) - - if cfg.use_instance_coeff: - inst = src.inst_layer(x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, cfg.num_instance_coeffs) - - # See box_utils.decode for an explanation of this - if cfg.use_yolo_regressors: - bbox[:, :, :2] = torch.sigmoid(bbox[:, :, :2]) - 0.5 - bbox[:, :, 0] /= conv_w - bbox[:, :, 1] /= conv_h - - if cfg.eval_mask_branch: - if cfg.mask_type == mask_type.direct: - mask = torch.sigmoid(mask) - elif cfg.mask_type == mask_type.lincomb: - mask = cfg.mask_proto_coeff_activation(mask) - - if cfg.mask_proto_coeff_gate: - gate = src.gate_layer(x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, self.mask_dim) - mask = mask * torch.sigmoid(gate) - - if cfg.mask_proto_split_prototypes_by_head and cfg.mask_type == mask_type.lincomb: - mask = F.pad(mask, (self.index * self.mask_dim, (self.num_heads - self.index - 1) * self.mask_dim), mode='constant', value=0) - - priors = self.make_priors(conv_h, conv_w, x.device) - - preds = { 'loc': bbox, 'conf': conf, 'mask': mask, 'priors': priors } - - if cfg.use_mask_scoring: - preds['score'] = score - - if cfg.use_instance_coeff: - preds['inst'] = inst - - return preds - - def make_priors(self, conv_h, conv_w, device): - """ Note that priors are [x,y,width,height] where (x,y) is the center of the box. """ - global prior_cache - size = (conv_h, conv_w) - - with timer.env('makepriors'): - if self.last_img_size != (cfg._tmp_img_w, cfg._tmp_img_h): - prior_data = [] - - # Iteration order is important (it has to sync up with the convout) - for j, i in product(range(conv_h), range(conv_w)): - # +0.5 because priors are in center-size notation - x = (i + 0.5) / conv_w - y = (j + 0.5) / conv_h - - for ars in self.aspect_ratios: - for scale in self.scales: - for ar in ars: - if not cfg.backbone.preapply_sqrt: - ar = sqrt(ar) - - if cfg.backbone.use_pixel_scales: - w = scale * ar / cfg.max_size - h = scale / ar / cfg.max_size - else: - w = scale * ar / conv_w - h = scale / ar / conv_h - - # This is for backward compatability with a bug where I made everything square by accident - if cfg.backbone.use_square_anchors: - h = w - - prior_data += [x, y, w, h] - - self.priors = torch.Tensor(prior_data).to(device).view(-1, 4).detach() - self.priors.requires_grad = False - self.last_img_size = (cfg._tmp_img_w, cfg._tmp_img_h) - self.last_conv_size = (conv_w, conv_h) - prior_cache[size] = None - elif self.priors.device != device: - # This whole weird situation is so that DataParalell doesn't copy the priors each iteration - if prior_cache[size] is None: - prior_cache[size] = {} - - if device not in prior_cache[size]: - prior_cache[size][device] = self.priors.to(device) - - self.priors = prior_cache[size][device] - - return self.priors - -class FPN(ScriptModuleWrapper): - """ - Implements a general version of the FPN introduced in - https://arxiv.org/pdf/1612.03144.pdf - - Parameters (in cfg.fpn): - - num_features (int): The number of output features in the fpn layers. - - interpolation_mode (str): The mode to pass to F.interpolate. - - num_downsample (int): The number of downsampled layers to add onto the selected layers. - These extra layers are downsampled from the last selected layer. - - Args: - - in_channels (list): For each conv layer you supply in the forward pass, - how many features will it have? - """ - __constants__ = ['interpolation_mode', 'num_downsample', 'use_conv_downsample', 'relu_pred_layers', - 'lat_layers', 'pred_layers', 'downsample_layers', 'relu_downsample_layers'] - - def __init__(self, in_channels): - super().__init__() - - self.lat_layers = nn.ModuleList([ - nn.Conv2d(x, cfg.fpn.num_features, kernel_size=1) - for x in reversed(in_channels) - ]) - - # This is here for backwards compatability - padding = 1 if cfg.fpn.pad else 0 - self.pred_layers = nn.ModuleList([ - nn.Conv2d(cfg.fpn.num_features, cfg.fpn.num_features, kernel_size=3, padding=padding) - for _ in in_channels - ]) - - if cfg.fpn.use_conv_downsample: - self.downsample_layers = nn.ModuleList([ - nn.Conv2d(cfg.fpn.num_features, cfg.fpn.num_features, kernel_size=3, padding=1, stride=2) - for _ in range(cfg.fpn.num_downsample) - ]) - - self.interpolation_mode = cfg.fpn.interpolation_mode - self.num_downsample = cfg.fpn.num_downsample - self.use_conv_downsample = cfg.fpn.use_conv_downsample - self.relu_downsample_layers = cfg.fpn.relu_downsample_layers - self.relu_pred_layers = cfg.fpn.relu_pred_layers - - @script_method_wrapper - def forward(self, convouts:List[torch.Tensor]): - """ - Args: - - convouts (list): A list of convouts for the corresponding layers in in_channels. - Returns: - - A list of FPN convouts in the same order as x with extra downsample layers if requested. - """ - - out = [] - x = torch.zeros(1, device=convouts[0].device) - for i in range(len(convouts)): - out.append(x) - - # For backward compatability, the conv layers are stored in reverse but the input and output is - # given in the correct order. Thus, use j=-i-1 for the input and output and i for the conv layers. - j = len(convouts) - for lat_layer in self.lat_layers: - j -= 1 - - if j < len(convouts) - 1: - _, _, h, w = convouts[j].size() - x = F.interpolate(x, size=(h, w), mode=self.interpolation_mode, align_corners=False) - - x = x + lat_layer(convouts[j]) - out[j] = x - - # This janky second loop is here because TorchScript. - j = len(convouts) - for pred_layer in self.pred_layers: - j -= 1 - out[j] = pred_layer(out[j]) - - if self.relu_pred_layers: - F.relu(out[j], inplace=True) - - cur_idx = len(out) - - # In the original paper, this takes care of P6 - if self.use_conv_downsample: - for downsample_layer in self.downsample_layers: - out.append(downsample_layer(out[-1])) - else: - for idx in range(self.num_downsample): - # Note: this is an untested alternative to out.append(out[-1][:, :, ::2, ::2]). Thanks TorchScript. - out.append(nn.functional.max_pool2d(out[-1], 1, stride=2)) - - if self.relu_downsample_layers: - for idx in range(len(out) - cur_idx): - out[idx] = F.relu(out[idx + cur_idx], inplace=False) - - return out - -class FastMaskIoUNet(ScriptModuleWrapper): - - def __init__(self): - super().__init__() - input_channels = 1 - last_layer = [(cfg.num_classes-1, 1, {})] - self.maskiou_net, _ = make_net(input_channels, cfg.maskiou_net + last_layer, include_last_relu=True) - - def forward(self, x): - x = self.maskiou_net(x) - maskiou_p = F.max_pool2d(x, kernel_size=x.size()[2:]).squeeze(-1).squeeze(-1) - - return maskiou_p - - - -class Yolact(nn.Module): - """ - - - ██╗ ██╗ ██████╗ ██╗ █████╗ ██████╗████████╗ - ╚██╗ ██╔╝██╔═══██╗██║ ██╔══██╗██╔════╝╚══██╔══╝ - ╚████╔╝ ██║ ██║██║ ███████║██║ ██║ - ╚██╔╝ ██║ ██║██║ ██╔══██║██║ ██║ - ██║ ╚██████╔╝███████╗██║ ██║╚██████╗ ██║ - ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ - - - You can set the arguments by changing them in the backbone config object in config.py. - - Parameters (in cfg.backbone): - - selected_layers: The indices of the conv layers to use for prediction. - - pred_scales: A list with len(selected_layers) containing tuples of scales (see PredictionModule) - - pred_aspect_ratios: A list of lists of aspect ratios with len(selected_layers) (see PredictionModule) - """ - - def __init__(self): - super().__init__() - - self.backbone = construct_backbone(cfg.backbone) #backbone: resnetbackbone. backbone_modules:{list:104}. bn1:{BatchNorm2d} - - if cfg.freeze_bn: # it's true - self.freeze_bn() - - # Compute mask_dim here and add it back to the config. Make sure Yolact's constructor is called early! - if cfg.mask_type == mask_type.direct: - cfg.mask_dim = cfg.mask_size**2 - elif cfg.mask_type == mask_type.lincomb: # the module will execute this branch - if cfg.mask_proto_use_grid: - self.grid = torch.Tensor(np.load(cfg.mask_proto_grid_file)) - self.num_grids = self.grid.size(0) - else: # the module will execute this branch - self.num_grids = 0 - - self.proto_src = cfg.mask_proto_src - - if self.proto_src is None: in_channels = 3 - elif cfg.fpn is not None: in_channels = cfg.fpn.num_features - else: in_channels = self.backbone.channels[self.proto_src] - in_channels += self.num_grids - #in_channels will be 256 - # The include_last_relu=false here is because we might want to change it to another function - self.proto_net, cfg.mask_dim = make_net(in_channels, cfg.mask_proto_net, include_last_relu=False) - - if cfg.mask_proto_bias: - cfg.mask_dim += 1 - - - self.selected_layers = cfg.backbone.selected_layers - src_channels = self.backbone.channels - - if cfg.use_maskiou: #false - self.maskiou_net = FastMaskIoUNet() - - if cfg.fpn is not None: #true - # Some hacky rewiring to accomodate the FPN - self.fpn = FPN([src_channels[i] for i in self.selected_layers]) - self.selected_layers = list(range(len(self.selected_layers) + cfg.fpn.num_downsample)) - src_channels = [cfg.fpn.num_features] * len(self.selected_layers) - - - self.prediction_layers = nn.ModuleList() - cfg.num_heads = len(self.selected_layers) - - for idx, layer_idx in enumerate(self.selected_layers): - # If we're sharing prediction module weights, have every module's parent be the first one - parent = None - if cfg.share_prediction_module and idx > 0: #cfg.share_prediction_module is True - parent = self.prediction_layers[0] - - pred = PredictionModule(src_channels[layer_idx], src_channels[layer_idx], - aspect_ratios = cfg.backbone.pred_aspect_ratios[idx], - scales = cfg.backbone.pred_scales[idx], - parent = parent, - index = idx) - self.prediction_layers.append(pred) - - # Extra parameters for the extra losses - if cfg.use_class_existence_loss: #false - # This comes from the smallest layer selected - # Also note that cfg.num_classes includes background - self.class_existence_fc = nn.Linear(src_channels[-1], cfg.num_classes - 1) - - if cfg.use_semantic_segmentation_loss: #true - self.semantic_seg_conv = nn.Conv2d(src_channels[0], cfg.num_classes-1, kernel_size=1) - - # For use in evaluation - self.detect = Detect(cfg.num_classes, bkg_label=0, top_k=cfg.nms_top_k, - conf_thresh=cfg.nms_conf_thresh, nms_thresh=cfg.nms_thresh) - - def save_weights(self, path): - """ Saves the model's weights using compression because the file sizes were getting too big. """ - torch.save(self.state_dict(), path) - - def load_weights(self, path): - """ Loads weights from a compressed save file. """ - state_dict = torch.load(path, map_location=torch.device('cpu')) - - # For backward compatability, remove these (the new variable is called layers) - for key in list(state_dict.keys()): - if key.startswith('backbone.layer') and not key.startswith('backbone.layers'): - del state_dict[key] - - # Also for backward compatibility with v1.0 weights, do this check - if key.startswith('fpn.downsample_layers.'): - if cfg.fpn is not None and int(key.split('.')[2]) >= cfg.fpn.num_downsample: - del state_dict[key] - self.load_state_dict(state_dict) - - def init_weights(self, backbone_path): - """ Initialize weights for training. """ - # Initialize the backbone with the pretrained weights. - self.backbone.init_backbone(backbone_path) - - conv_constants = getattr(nn.Conv2d(1, 1, 1), '__constants__') - - # Quick lambda to test if one list contains the other - def all_in(x, y): - for _x in x: - if _x not in y: - return False - return True - - # Initialize the rest of the conv layers with xavier - for name, module in self.named_modules(): - # See issue #127 for why we need such a complicated condition if the module is a WeakScriptModuleProxy - # Broke in 1.3 (see issue #175), WeakScriptModuleProxy was turned into just ScriptModule. - # Broke in 1.4 (see issue #292), where RecursiveScriptModule is the new star of the show. - # Note that this might break with future pytorch updates, so let me know if it does - is_script_conv = False - if 'Script' in type(module).__name__: - # 1.4 workaround: now there's an original_name member so just use that - if hasattr(module, 'original_name'): - is_script_conv = 'Conv' in module.original_name - # 1.3 workaround: check if this has the same constants as a conv module - else: - is_script_conv = ( - all_in(module.__dict__['_constants_set'], conv_constants) - and all_in(conv_constants, module.__dict__['_constants_set'])) - - is_conv_layer = isinstance(module, nn.Conv2d) or is_script_conv - - if is_conv_layer and module not in self.backbone.backbone_modules: - nn.init.xavier_uniform_(module.weight.data) - - if module.bias is not None: - if cfg.use_focal_loss and 'conf_layer' in name: - if not cfg.use_sigmoid_focal_loss: - # Initialize the last layer as in the focal loss paper. - # Because we use softmax and not sigmoid, I had to derive an alternate expression - # on a notecard. Define pi to be the probability of outputting a foreground detection. - # Then let z = sum(exp(x)) - exp(x_0). Finally let c be the number of foreground classes. - # Chugging through the math, this gives us - # x_0 = log(z * (1 - pi) / pi) where 0 is the background class - # x_i = log(z / c) for all i > 0 - # For simplicity (and because we have a degree of freedom here), set z = 1. Then we have - # x_0 = log((1 - pi) / pi) note: don't split up the log for numerical stability - # x_i = -log(c) for all i > 0 - module.bias.data[0] = np.log((1 - cfg.focal_loss_init_pi) / cfg.focal_loss_init_pi) - module.bias.data[1:] = -np.log(module.bias.size(0) - 1) - else: - module.bias.data[0] = -np.log(cfg.focal_loss_init_pi / (1 - cfg.focal_loss_init_pi)) - module.bias.data[1:] = -np.log((1 - cfg.focal_loss_init_pi) / cfg.focal_loss_init_pi) - else: - module.bias.data.zero_() - - def train(self, mode=True): - super().train(mode) - - if cfg.freeze_bn: - self.freeze_bn() - - def freeze_bn(self, enable=False): - """ Adapted from https://discuss.pytorch.org/t/how-to-train-with-frozen-batchnorm/12106/8 """ - for module in self.modules(): - if isinstance(module, nn.BatchNorm2d): - module.train() if enable else module.eval() - - module.weight.requires_grad = enable - module.bias.requires_grad = enable - - def forward(self, x): - """ The input should be of size [batch_size, 3, img_h, img_w] """ - _, _, img_h, img_w = x.size() - cfg._tmp_img_h = img_h - cfg._tmp_img_w = img_w - - with timer.env('backbone'): - outs = self.backbone(x) - - if cfg.fpn is not None: - with timer.env('fpn'): - # Use backbone.selected_layers because we overwrote self.selected_layers - outs = [outs[i] for i in cfg.backbone.selected_layers] - outs = self.fpn(outs) - - proto_out = None - if cfg.mask_type == mask_type.lincomb and cfg.eval_mask_branch: - with timer.env('proto'): - proto_x = x if self.proto_src is None else outs[self.proto_src] - - if self.num_grids > 0: - grids = self.grid.repeat(proto_x.size(0), 1, 1, 1) - proto_x = torch.cat([proto_x, grids], dim=1) - - proto_out = self.proto_net(proto_x) - proto_out = cfg.mask_proto_prototype_activation(proto_out) - - if cfg.mask_proto_prototypes_as_features: - # Clone here because we don't want to permute this, though idk if contiguous makes this unnecessary - proto_downsampled = proto_out.clone() - - if cfg.mask_proto_prototypes_as_features_no_grad: - proto_downsampled = proto_out.detach() - - # Move the features last so the multiplication is easy - proto_out = proto_out.permute(0, 2, 3, 1).contiguous() - - if cfg.mask_proto_bias: - bias_shape = [x for x in proto_out.size()] - bias_shape[-1] = 1 - proto_out = torch.cat([proto_out, torch.ones(*bias_shape)], -1) - - - with timer.env('pred_heads'): - pred_outs = { 'loc': [], 'conf': [], 'mask': [], 'priors': [] } - - if cfg.use_mask_scoring: - pred_outs['score'] = [] - - if cfg.use_instance_coeff: - pred_outs['inst'] = [] - - for idx, pred_layer in zip(self.selected_layers, self.prediction_layers): - pred_x = outs[idx] - - if cfg.mask_type == mask_type.lincomb and cfg.mask_proto_prototypes_as_features: - # Scale the prototypes down to the current prediction layer's size and add it as inputs - proto_downsampled = F.interpolate(proto_downsampled, size=outs[idx].size()[2:], mode='bilinear', align_corners=False) - pred_x = torch.cat([pred_x, proto_downsampled], dim=1) - - # A hack for the way dataparallel works - if cfg.share_prediction_module and pred_layer is not self.prediction_layers[0]: - pred_layer.parent = [self.prediction_layers[0]] - - p = pred_layer(pred_x) - - for k, v in p.items(): - pred_outs[k].append(v) - - for k, v in pred_outs.items(): - pred_outs[k] = torch.cat(v, -2) - - if proto_out is not None: - pred_outs['proto'] = proto_out - - if self.training: - # For the extra loss functions - if cfg.use_class_existence_loss: - pred_outs['classes'] = self.class_existence_fc(outs[-1].mean(dim=(2, 3))) - - if cfg.use_semantic_segmentation_loss: - pred_outs['segm'] = self.semantic_seg_conv(outs[0]) - - return pred_outs - else: - if cfg.use_mask_scoring: - pred_outs['score'] = torch.sigmoid(pred_outs['score']) - - if cfg.use_focal_loss: - if cfg.use_sigmoid_focal_loss: - # Note: even though conf[0] exists, this mode doesn't train it so don't use it - pred_outs['conf'] = torch.sigmoid(pred_outs['conf']) - if cfg.use_mask_scoring: - pred_outs['conf'] *= pred_outs['score'] - elif cfg.use_objectness_score: - # See focal_loss_sigmoid in multibox_loss.py for details - objectness = torch.sigmoid(pred_outs['conf'][:, :, 0]) - pred_outs['conf'][:, :, 1:] = objectness[:, :, None] * F.softmax(pred_outs['conf'][:, :, 1:], -1) - pred_outs['conf'][:, :, 0 ] = 1 - objectness - else: - pred_outs['conf'] = F.softmax(pred_outs['conf'], -1) - else: - - if cfg.use_objectness_score: - objectness = torch.sigmoid(pred_outs['conf'][:, :, 0]) - - pred_outs['conf'][:, :, 1:] = (objectness > 0.10)[..., None] \ - * F.softmax(pred_outs['conf'][:, :, 1:], dim=-1) - - else: - pred_outs['conf'] = F.softmax(pred_outs['conf'], -1) - for i in pred_outs.keys(): - pred_outs[i] = pred_outs[i].cpu() - return self.detect(pred_outs) - - - - -# Some testing code -if __name__ == '__main__': - from utils.functions import init_console - init_console() - - # Use the first argument to set the config if you want - import sys - if len(sys.argv) > 1: - from data.config import set_cfg - set_cfg(sys.argv[1]) - - net = Yolact() - net.train() - net.init_weights(backbone_path='weights/' + cfg.backbone.path) - - # GPU - net = net.cuda() - torch.set_default_tensor_type('torch.cuda.FloatTensor') - - x = torch.zeros((1, 3, cfg.max_size, cfg.max_size)) - y = net(x) - - for p in net.prediction_layers: - print(p.last_conv_size) - - print() - for k, a in y.items(): - print(k + ': ', a.size(), torch.sum(a)) - exit() - - net(x) - # timer.disable('pass2') - avg = MovingAverage() - try: - while True: - timer.reset() - with timer.env('everything else'): - net(x) - avg.add(timer.total_time()) - print('\033[2J') # Moves console cursor to 0,0 - timer.print_stats() - print('Avg fps: %.2f\tAvg ms: %.2f ' % (1/avg.get_avg(), avg.get_avg()*1000)) - except KeyboardInterrupt: - pass +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch, torchvision +import torch.nn as nn +import torch.nn.functional as F +from torchvision.models.resnet import Bottleneck +import numpy as np +from itertools import product +from math import sqrt +from typing import List +from collections import defaultdict + +from data.config import cfg, mask_type +from layers import Detect +from layers.interpolate import InterpolateModule +from backbone import construct_backbone + +import torch.backends.cudnn as cudnn +from utils import timer +from utils.functions import MovingAverage, make_net + +# This is required for Pytorch 1.0.1 on Windows to initialize Cuda on some driver versions. +# See the bug report here: https://github.com/pytorch/pytorch/issues/17108 +#torch.cuda.current_device() + +# As of March 10, 2019, Pytorch DataParallel still doesn't support JIT Script Modules +use_jit = False +if not use_jit: + print('Multiple GPUs detected! Turning off JIT.') + +ScriptModuleWrapper = torch.jit.ScriptModule if use_jit else nn.Module +script_method_wrapper = torch.jit.script_method if use_jit else lambda fn, _rcn=None: fn + + + +class Concat(nn.Module): + def __init__(self, nets, extra_params): + super().__init__() + + self.nets = nn.ModuleList(nets) + self.extra_params = extra_params + + def forward(self, x): + # Concat each along the channel dimension + return torch.cat([net(x) for net in self.nets], dim=1, **self.extra_params) + +prior_cache = defaultdict(lambda: None) + +class PredictionModule(nn.Module): + """ + The (c) prediction module adapted from DSSD: + https://arxiv.org/pdf/1701.06659.pdf + + Note that this is slightly different to the module in the paper + because the Bottleneck block actually has a 3x3 convolution in + the middle instead of a 1x1 convolution. Though, I really can't + be arsed to implement it myself, and, who knows, this might be + better. + + Args: + - in_channels: The input feature size. + - out_channels: The output feature size (must be a multiple of 4). + - aspect_ratios: A list of lists of priorbox aspect ratios (one list per scale). + - scales: A list of priorbox scales relative to this layer's convsize. + For instance: If this layer has convouts of size 30x30 for + an image of size 600x600, the 'default' (scale + of 1) for this layer would produce bounding + boxes with an area of 20x20px. If the scale is + .5 on the other hand, this layer would consider + bounding boxes with area 10x10px, etc. + - parent: If parent is a PredictionModule, this module will use all the layers + from parent instead of from this module. + """ + + def __init__(self, in_channels, out_channels=1024, aspect_ratios=[[1]], scales=[1], parent=None, index=0): + super().__init__() + + self.num_classes = cfg.num_classes + self.mask_dim = cfg.mask_dim # Defined by Yolact + self.num_priors = sum(len(x)*len(scales) for x in aspect_ratios) + self.parent = [parent] # Don't include this in the state dict + self.index = index + self.num_heads = cfg.num_heads # Defined by Yolact + + if cfg.mask_proto_split_prototypes_by_head and cfg.mask_type == mask_type.lincomb: + self.mask_dim = self.mask_dim // self.num_heads + + if cfg.mask_proto_prototypes_as_features: + in_channels += self.mask_dim + + if parent is None: + if cfg.extra_head_net is None: + out_channels = in_channels + else: + self.upfeature, out_channels = make_net(in_channels, cfg.extra_head_net) + + if cfg.use_prediction_module: + self.block = Bottleneck(out_channels, out_channels // 4) + self.conv = nn.Conv2d(out_channels, out_channels, kernel_size=1, bias=True) + self.bn = nn.BatchNorm2d(out_channels) + + self.bbox_layer = nn.Conv2d(out_channels, self.num_priors * 4, **cfg.head_layer_params) + self.conf_layer = nn.Conv2d(out_channels, self.num_priors * self.num_classes, **cfg.head_layer_params) + self.mask_layer = nn.Conv2d(out_channels, self.num_priors * self.mask_dim, **cfg.head_layer_params) + + if cfg.use_mask_scoring: + self.score_layer = nn.Conv2d(out_channels, self.num_priors, **cfg.head_layer_params) + + if cfg.use_instance_coeff: + self.inst_layer = nn.Conv2d(out_channels, self.num_priors * cfg.num_instance_coeffs, **cfg.head_layer_params) + + # What is this ugly lambda doing in the middle of all this clean prediction module code? + def make_extra(num_layers): + if num_layers == 0: + return lambda x: x + else: + # Looks more complicated than it is. This just creates an array of num_layers alternating conv-relu + return nn.Sequential(*sum([[ + nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1), + nn.ReLU(inplace=True) + ] for _ in range(num_layers)], [])) + + self.bbox_extra, self.conf_extra, self.mask_extra = [make_extra(x) for x in cfg.extra_layers] + + if cfg.mask_type == mask_type.lincomb and cfg.mask_proto_coeff_gate: + self.gate_layer = nn.Conv2d(out_channels, self.num_priors * self.mask_dim, kernel_size=3, padding=1) + + self.aspect_ratios = aspect_ratios + self.scales = scales + + self.priors = None + self.last_conv_size = None + self.last_img_size = None + + def forward(self, x): + """ + Args: + - x: The convOut from a layer in the backbone network + Size: [batch_size, in_channels, conv_h, conv_w]) + + Returns a tuple (bbox_coords, class_confs, mask_output, prior_boxes) with sizes + - bbox_coords: [batch_size, conv_h*conv_w*num_priors, 4] + - class_confs: [batch_size, conv_h*conv_w*num_priors, num_classes] + - mask_output: [batch_size, conv_h*conv_w*num_priors, mask_dim] + - prior_boxes: [conv_h*conv_w*num_priors, 4] + """ + # In case we want to use another module's layers + src = self if self.parent[0] is None else self.parent[0] + + conv_h = x.size(2) + conv_w = x.size(3) + + if cfg.extra_head_net is not None: + x = src.upfeature(x) + + if cfg.use_prediction_module: + # The two branches of PM design (c) + a = src.block(x) + + b = src.conv(x) + b = src.bn(b) + b = F.relu(b) + + # TODO: Possibly switch this out for a product + x = a + b + + bbox_x = src.bbox_extra(x) + conf_x = src.conf_extra(x) + mask_x = src.mask_extra(x) + + bbox = src.bbox_layer(bbox_x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, 4) + conf = src.conf_layer(conf_x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, self.num_classes) + + if cfg.eval_mask_branch: + mask = src.mask_layer(mask_x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, self.mask_dim) + else: + mask = torch.zeros(x.size(0), bbox.size(1), self.mask_dim, device=bbox.device) + + if cfg.use_mask_scoring: + score = src.score_layer(x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, 1) + + if cfg.use_instance_coeff: + inst = src.inst_layer(x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, cfg.num_instance_coeffs) + + # See box_utils.decode for an explanation of this + if cfg.use_yolo_regressors: + bbox[:, :, :2] = torch.sigmoid(bbox[:, :, :2]) - 0.5 + bbox[:, :, 0] /= conv_w + bbox[:, :, 1] /= conv_h + + if cfg.eval_mask_branch: + if cfg.mask_type == mask_type.direct: + mask = torch.sigmoid(mask) + elif cfg.mask_type == mask_type.lincomb: + mask = cfg.mask_proto_coeff_activation(mask) + + if cfg.mask_proto_coeff_gate: + gate = src.gate_layer(x).permute(0, 2, 3, 1).contiguous().view(x.size(0), -1, self.mask_dim) + mask = mask * torch.sigmoid(gate) + + if cfg.mask_proto_split_prototypes_by_head and cfg.mask_type == mask_type.lincomb: + mask = F.pad(mask, (self.index * self.mask_dim, (self.num_heads - self.index - 1) * self.mask_dim), mode='constant', value=0) + + priors = self.make_priors(conv_h, conv_w, x.device) + + preds = { 'loc': bbox, 'conf': conf, 'mask': mask, 'priors': priors } + + if cfg.use_mask_scoring: + preds['score'] = score + + if cfg.use_instance_coeff: + preds['inst'] = inst + + return preds + + def make_priors(self, conv_h, conv_w, device): + """ Note that priors are [x,y,width,height] where (x,y) is the center of the box. """ + global prior_cache + size = (conv_h, conv_w) + + with timer.env('makepriors'): + if self.last_img_size != (cfg._tmp_img_w, cfg._tmp_img_h): + prior_data = [] + + # Iteration order is important (it has to sync up with the convout) + for j, i in product(range(conv_h), range(conv_w)): + # +0.5 because priors are in center-size notation + x = (i + 0.5) / conv_w + y = (j + 0.5) / conv_h + + for ars in self.aspect_ratios: + for scale in self.scales: + for ar in ars: + if not cfg.backbone.preapply_sqrt: + ar = sqrt(ar) + + if cfg.backbone.use_pixel_scales: + w = scale * ar / cfg.max_size + h = scale / ar / cfg.max_size + else: + w = scale * ar / conv_w + h = scale / ar / conv_h + + # This is for backward compatability with a bug where I made everything square by accident + if cfg.backbone.use_square_anchors: + h = w + + prior_data += [x, y, w, h] + + self.priors = torch.Tensor(prior_data).to(device).view(-1, 4).detach() + self.priors.requires_grad = False + self.last_img_size = (cfg._tmp_img_w, cfg._tmp_img_h) + self.last_conv_size = (conv_w, conv_h) + prior_cache[size] = None + elif self.priors.device != device: + # This whole weird situation is so that DataParalell doesn't copy the priors each iteration + if prior_cache[size] is None: + prior_cache[size] = {} + + if device not in prior_cache[size]: + prior_cache[size][device] = self.priors.to(device) + + self.priors = prior_cache[size][device] + + return self.priors + +class FPN(ScriptModuleWrapper): + """ + Implements a general version of the FPN introduced in + https://arxiv.org/pdf/1612.03144.pdf + + Parameters (in cfg.fpn): + - num_features (int): The number of output features in the fpn layers. + - interpolation_mode (str): The mode to pass to F.interpolate. + - num_downsample (int): The number of downsampled layers to add onto the selected layers. + These extra layers are downsampled from the last selected layer. + + Args: + - in_channels (list): For each conv layer you supply in the forward pass, + how many features will it have? + """ + __constants__ = ['interpolation_mode', 'num_downsample', 'use_conv_downsample', 'relu_pred_layers', + 'lat_layers', 'pred_layers', 'downsample_layers', 'relu_downsample_layers'] + + def __init__(self, in_channels): + super().__init__() + + self.lat_layers = nn.ModuleList([ + nn.Conv2d(x, cfg.fpn.num_features, kernel_size=1) + for x in reversed(in_channels) + ]) + + # This is here for backwards compatability + padding = 1 if cfg.fpn.pad else 0 + self.pred_layers = nn.ModuleList([ + nn.Conv2d(cfg.fpn.num_features, cfg.fpn.num_features, kernel_size=3, padding=padding) + for _ in in_channels + ]) + + if cfg.fpn.use_conv_downsample: + self.downsample_layers = nn.ModuleList([ + nn.Conv2d(cfg.fpn.num_features, cfg.fpn.num_features, kernel_size=3, padding=1, stride=2) + for _ in range(cfg.fpn.num_downsample) + ]) + + self.interpolation_mode = cfg.fpn.interpolation_mode + self.num_downsample = cfg.fpn.num_downsample + self.use_conv_downsample = cfg.fpn.use_conv_downsample + self.relu_downsample_layers = cfg.fpn.relu_downsample_layers + self.relu_pred_layers = cfg.fpn.relu_pred_layers + + @script_method_wrapper + def forward(self, convouts:List[torch.Tensor]): + """ + Args: + - convouts (list): A list of convouts for the corresponding layers in in_channels. + Returns: + - A list of FPN convouts in the same order as x with extra downsample layers if requested. + """ + + out = [] + x = torch.zeros(1, device=convouts[0].device) + for i in range(len(convouts)): + out.append(x) + + # For backward compatability, the conv layers are stored in reverse but the input and output is + # given in the correct order. Thus, use j=-i-1 for the input and output and i for the conv layers. + j = len(convouts) + for lat_layer in self.lat_layers: + j -= 1 + + if j < len(convouts) - 1: + _, _, h, w = convouts[j].size() + x = F.interpolate(x, size=(h, w), mode=self.interpolation_mode, align_corners=False) + + x = x + lat_layer(convouts[j]) + out[j] = x + + # This janky second loop is here because TorchScript. + j = len(convouts) + for pred_layer in self.pred_layers: + j -= 1 + out[j] = pred_layer(out[j]) + + if self.relu_pred_layers: + F.relu(out[j], inplace=True) + + cur_idx = len(out) + + # In the original paper, this takes care of P6 + if self.use_conv_downsample: + for downsample_layer in self.downsample_layers: + out.append(downsample_layer(out[-1])) + else: + for idx in range(self.num_downsample): + # Note: this is an untested alternative to out.append(out[-1][:, :, ::2, ::2]). Thanks TorchScript. + out.append(nn.functional.max_pool2d(out[-1], 1, stride=2)) + + if self.relu_downsample_layers: + for idx in range(len(out) - cur_idx): + out[idx] = F.relu(out[idx + cur_idx], inplace=False) + + return out + +class FastMaskIoUNet(ScriptModuleWrapper): + + def __init__(self): + super().__init__() + input_channels = 1 + last_layer = [(cfg.num_classes-1, 1, {})] + self.maskiou_net, _ = make_net(input_channels, cfg.maskiou_net + last_layer, include_last_relu=True) + + def forward(self, x): + x = self.maskiou_net(x) + maskiou_p = F.max_pool2d(x, kernel_size=x.size()[2:]).squeeze(-1).squeeze(-1) + + return maskiou_p + + + +class Yolact(nn.Module): + """ + + + ██╗ ██╗ ██████╗ ██╗ █████╗ ██████╗████████╗ + ╚██╗ ██╔╝██╔═══██╗██║ ██╔══██╗██╔════╝╚══██╔══╝ + ╚████╔╝ ██║ ██║██║ ███████║██║ ██║ + ╚██╔╝ ██║ ██║██║ ██╔══██║██║ ██║ + ██║ ╚██████╔╝███████╗██║ ██║╚██████╗ ██║ + ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ + + + You can set the arguments by changing them in the backbone config object in config.py. + + Parameters (in cfg.backbone): + - selected_layers: The indices of the conv layers to use for prediction. + - pred_scales: A list with len(selected_layers) containing tuples of scales (see PredictionModule) + - pred_aspect_ratios: A list of lists of aspect ratios with len(selected_layers) (see PredictionModule) + """ + + def __init__(self): + super().__init__() + + self.backbone = construct_backbone(cfg.backbone) #backbone: resnetbackbone. backbone_modules:{list:104}. bn1:{BatchNorm2d} + + if cfg.freeze_bn: # it's true + self.freeze_bn() + + # Compute mask_dim here and add it back to the config. Make sure Yolact's constructor is called early! + if cfg.mask_type == mask_type.direct: + cfg.mask_dim = cfg.mask_size**2 + elif cfg.mask_type == mask_type.lincomb: # the module will execute this branch + if cfg.mask_proto_use_grid: + self.grid = torch.Tensor(np.load(cfg.mask_proto_grid_file)) + self.num_grids = self.grid.size(0) + else: # the module will execute this branch + self.num_grids = 0 + + self.proto_src = cfg.mask_proto_src + + if self.proto_src is None: in_channels = 3 + elif cfg.fpn is not None: in_channels = cfg.fpn.num_features + else: in_channels = self.backbone.channels[self.proto_src] + in_channels += self.num_grids + #in_channels will be 256 + # The include_last_relu=false here is because we might want to change it to another function + self.proto_net, cfg.mask_dim = make_net(in_channels, cfg.mask_proto_net, include_last_relu=False) + + if cfg.mask_proto_bias: + cfg.mask_dim += 1 + + + self.selected_layers = cfg.backbone.selected_layers + src_channels = self.backbone.channels + + if cfg.use_maskiou: #false + self.maskiou_net = FastMaskIoUNet() + + if cfg.fpn is not None: #true + # Some hacky rewiring to accomodate the FPN + self.fpn = FPN([src_channels[i] for i in self.selected_layers]) + self.selected_layers = list(range(len(self.selected_layers) + cfg.fpn.num_downsample)) + src_channels = [cfg.fpn.num_features] * len(self.selected_layers) + + + self.prediction_layers = nn.ModuleList() + cfg.num_heads = len(self.selected_layers) + + for idx, layer_idx in enumerate(self.selected_layers): + # If we're sharing prediction module weights, have every module's parent be the first one + parent = None + if cfg.share_prediction_module and idx > 0: #cfg.share_prediction_module is True + parent = self.prediction_layers[0] + + pred = PredictionModule(src_channels[layer_idx], src_channels[layer_idx], + aspect_ratios = cfg.backbone.pred_aspect_ratios[idx], + scales = cfg.backbone.pred_scales[idx], + parent = parent, + index = idx) + self.prediction_layers.append(pred) + + # Extra parameters for the extra losses + if cfg.use_class_existence_loss: #false + # This comes from the smallest layer selected + # Also note that cfg.num_classes includes background + self.class_existence_fc = nn.Linear(src_channels[-1], cfg.num_classes - 1) + + if cfg.use_semantic_segmentation_loss: #true + self.semantic_seg_conv = nn.Conv2d(src_channels[0], cfg.num_classes-1, kernel_size=1) + + # For use in evaluation + self.detect = Detect(cfg.num_classes, bkg_label=0, top_k=cfg.nms_top_k, + conf_thresh=cfg.nms_conf_thresh, nms_thresh=cfg.nms_thresh) + + def save_weights(self, path): + """ Saves the model's weights using compression because the file sizes were getting too big. """ + torch.save(self.state_dict(), path) + + def load_weights(self, path): + """ Loads weights from a compressed save file. """ + state_dict = torch.load(path, map_location=torch.device('cpu')) + + # For backward compatability, remove these (the new variable is called layers) + for key in list(state_dict.keys()): + if key.startswith('backbone.layer') and not key.startswith('backbone.layers'): + del state_dict[key] + + # Also for backward compatibility with v1.0 weights, do this check + if key.startswith('fpn.downsample_layers.'): + if cfg.fpn is not None and int(key.split('.')[2]) >= cfg.fpn.num_downsample: + del state_dict[key] + self.load_state_dict(state_dict) + + def init_weights(self, backbone_path): + """ Initialize weights for training. """ + # Initialize the backbone with the pretrained weights. + self.backbone.init_backbone(backbone_path) + + conv_constants = getattr(nn.Conv2d(1, 1, 1), '__constants__') + + # Quick lambda to test if one list contains the other + def all_in(x, y): + for _x in x: + if _x not in y: + return False + return True + + # Initialize the rest of the conv layers with xavier + for name, module in self.named_modules(): + # See issue #127 for why we need such a complicated condition if the module is a WeakScriptModuleProxy + # Broke in 1.3 (see issue #175), WeakScriptModuleProxy was turned into just ScriptModule. + # Broke in 1.4 (see issue #292), where RecursiveScriptModule is the new star of the show. + # Note that this might break with future pytorch updates, so let me know if it does + is_script_conv = False + if 'Script' in type(module).__name__: + # 1.4 workaround: now there's an original_name member so just use that + if hasattr(module, 'original_name'): + is_script_conv = 'Conv' in module.original_name + # 1.3 workaround: check if this has the same constants as a conv module + else: + is_script_conv = ( + all_in(module.__dict__['_constants_set'], conv_constants) + and all_in(conv_constants, module.__dict__['_constants_set'])) + + is_conv_layer = isinstance(module, nn.Conv2d) or is_script_conv + + if is_conv_layer and module not in self.backbone.backbone_modules: + nn.init.xavier_uniform_(module.weight.data) + + if module.bias is not None: + if cfg.use_focal_loss and 'conf_layer' in name: + if not cfg.use_sigmoid_focal_loss: + # Initialize the last layer as in the focal loss paper. + # Because we use softmax and not sigmoid, I had to derive an alternate expression + # on a notecard. Define pi to be the probability of outputting a foreground detection. + # Then let z = sum(exp(x)) - exp(x_0). Finally let c be the number of foreground classes. + # Chugging through the math, this gives us + # x_0 = log(z * (1 - pi) / pi) where 0 is the background class + # x_i = log(z / c) for all i > 0 + # For simplicity (and because we have a degree of freedom here), set z = 1. Then we have + # x_0 = log((1 - pi) / pi) note: don't split up the log for numerical stability + # x_i = -log(c) for all i > 0 + module.bias.data[0] = np.log((1 - cfg.focal_loss_init_pi) / cfg.focal_loss_init_pi) + module.bias.data[1:] = -np.log(module.bias.size(0) - 1) + else: + module.bias.data[0] = -np.log(cfg.focal_loss_init_pi / (1 - cfg.focal_loss_init_pi)) + module.bias.data[1:] = -np.log((1 - cfg.focal_loss_init_pi) / cfg.focal_loss_init_pi) + else: + module.bias.data.zero_() + + def train(self, mode=True): + super().train(mode) + + if cfg.freeze_bn: + self.freeze_bn() + + def freeze_bn(self, enable=False): + """ Adapted from https://discuss.pytorch.org/t/how-to-train-with-frozen-batchnorm/12106/8 """ + for module in self.modules(): + if isinstance(module, nn.BatchNorm2d): + module.train() if enable else module.eval() + + module.weight.requires_grad = enable + module.bias.requires_grad = enable + + def forward(self, x): + """ The input should be of size [batch_size, 3, img_h, img_w] """ + _, _, img_h, img_w = x.size() + cfg._tmp_img_h = img_h + cfg._tmp_img_w = img_w + + with timer.env('backbone'): + outs = self.backbone(x) + + if cfg.fpn is not None: + with timer.env('fpn'): + # Use backbone.selected_layers because we overwrote self.selected_layers + outs = [outs[i] for i in cfg.backbone.selected_layers] + outs = self.fpn(outs) + + proto_out = None + if cfg.mask_type == mask_type.lincomb and cfg.eval_mask_branch: + with timer.env('proto'): + proto_x = x if self.proto_src is None else outs[self.proto_src] + + if self.num_grids > 0: + grids = self.grid.repeat(proto_x.size(0), 1, 1, 1) + proto_x = torch.cat([proto_x, grids], dim=1) + + proto_out = self.proto_net(proto_x) + proto_out = cfg.mask_proto_prototype_activation(proto_out) + + if cfg.mask_proto_prototypes_as_features: + # Clone here because we don't want to permute this, though idk if contiguous makes this unnecessary + proto_downsampled = proto_out.clone() + + if cfg.mask_proto_prototypes_as_features_no_grad: + proto_downsampled = proto_out.detach() + + # Move the features last so the multiplication is easy + proto_out = proto_out.permute(0, 2, 3, 1).contiguous() + + if cfg.mask_proto_bias: + bias_shape = [x for x in proto_out.size()] + bias_shape[-1] = 1 + proto_out = torch.cat([proto_out, torch.ones(*bias_shape)], -1) + + + with timer.env('pred_heads'): + pred_outs = { 'loc': [], 'conf': [], 'mask': [], 'priors': [] } + + if cfg.use_mask_scoring: + pred_outs['score'] = [] + + if cfg.use_instance_coeff: + pred_outs['inst'] = [] + + for idx, pred_layer in zip(self.selected_layers, self.prediction_layers): + pred_x = outs[idx] + + if cfg.mask_type == mask_type.lincomb and cfg.mask_proto_prototypes_as_features: + # Scale the prototypes down to the current prediction layer's size and add it as inputs + proto_downsampled = F.interpolate(proto_downsampled, size=outs[idx].size()[2:], mode='bilinear', align_corners=False) + pred_x = torch.cat([pred_x, proto_downsampled], dim=1) + + # A hack for the way dataparallel works + if cfg.share_prediction_module and pred_layer is not self.prediction_layers[0]: + pred_layer.parent = [self.prediction_layers[0]] + + p = pred_layer(pred_x) + + for k, v in p.items(): + pred_outs[k].append(v) + + for k, v in pred_outs.items(): + pred_outs[k] = torch.cat(v, -2) + + if proto_out is not None: + pred_outs['proto'] = proto_out + + if self.training: + # For the extra loss functions + if cfg.use_class_existence_loss: + pred_outs['classes'] = self.class_existence_fc(outs[-1].mean(dim=(2, 3))) + + if cfg.use_semantic_segmentation_loss: + pred_outs['segm'] = self.semantic_seg_conv(outs[0]) + + return pred_outs + else: + if cfg.use_mask_scoring: + pred_outs['score'] = torch.sigmoid(pred_outs['score']) + + if cfg.use_focal_loss: + if cfg.use_sigmoid_focal_loss: + # Note: even though conf[0] exists, this mode doesn't train it so don't use it + pred_outs['conf'] = torch.sigmoid(pred_outs['conf']) + if cfg.use_mask_scoring: + pred_outs['conf'] *= pred_outs['score'] + elif cfg.use_objectness_score: + # See focal_loss_sigmoid in multibox_loss.py for details + objectness = torch.sigmoid(pred_outs['conf'][:, :, 0]) + pred_outs['conf'][:, :, 1:] = objectness[:, :, None] * F.softmax(pred_outs['conf'][:, :, 1:], -1) + pred_outs['conf'][:, :, 0 ] = 1 - objectness + else: + pred_outs['conf'] = F.softmax(pred_outs['conf'], -1) + else: + + if cfg.use_objectness_score: + objectness = torch.sigmoid(pred_outs['conf'][:, :, 0]) + + pred_outs['conf'][:, :, 1:] = (objectness > 0.10)[..., None] \ + * F.softmax(pred_outs['conf'][:, :, 1:], dim=-1) + + else: + pred_outs['conf'] = F.softmax(pred_outs['conf'], -1) + for i in pred_outs.keys(): + pred_outs[i] = pred_outs[i].cpu() + return self.detect(pred_outs) + + + + +# Some testing code +if __name__ == '__main__': + from utils.functions import init_console + init_console() + + # Use the first argument to set the config if you want + import sys + if len(sys.argv) > 1: + from data.config import set_cfg + set_cfg(sys.argv[1]) + + net = Yolact() + net.train() + net.init_weights(backbone_path='weights/' + cfg.backbone.path) + + # GPU + net = net.cuda() + torch.set_default_tensor_type('torch.cuda.FloatTensor') + + x = torch.zeros((1, 3, cfg.max_size, cfg.max_size)) + y = net(x) + + for p in net.prediction_layers: + print(p.last_conv_size) + + print() + for k, a in y.items(): + print(k + ': ', a.size(), torch.sum(a)) + exit() + + net(x) + # timer.disable('pass2') + avg = MovingAverage() + try: + while True: + timer.reset() + with timer.env('everything else'): + net(x) + avg.add(timer.total_time()) + print('\033[2J') # Moves console cursor to 0,0 + timer.print_stats() + print('Avg fps: %.2f\tAvg ms: %.2f ' % (1/avg.get_avg(), avg.get_avg()*1000)) + except KeyboardInterrupt: + pass diff --git a/PyTorch/contrib/cv/detection/YOLOR/README.md b/PyTorch/contrib/cv/detection/YOLOR/README.md index 5e19e9243b..cb96fdada6 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/README.md +++ b/PyTorch/contrib/cv/detection/YOLOR/README.md @@ -1,129 +1,129 @@ -# YOLOR 模型使用说明 - -## Requirements -* NPU配套的run包安装 -* Python 3.7.5 -* PyTorch(NPU版本) -* apex(NPU版本) -* (可选)参考《Pytorch 网络模型移植&训练指南》6.4.2章节,配置cpu为性能模式,以达到模型最佳性能;不开启不影响功能。 - -安装其他依赖(先安装NPU版本的pytorch和apex,再安装其他依赖): -``` -pip install -r requirements.txt -``` - -## Dataset -1. 下载coco数据集,包含图片、annotations、labels图片、annotations: - ``` - cd yolor - bash scripts/get_coco.sh - ``` -2. 将coco数据集放于工程根目录下 - coco目录结构如下: - ``` - coco - |-- LICENSE - |-- README.txt - |-- annotations - | `-- instances_val2017.json - |-- images - | |-- test2017 - | |-- train2017 - | `-- val2017 - |-- labels - | |-- train2017 - | |-- train2017.cache3 - | |-- val2017 - | `-- val2017.cache3 - |-- test-dev2017.txt - |-- train2017.cache - |-- train2017.txt - |-- val2017.cache - `-- val2017.txt - ``` - -注:数据集路径在./yolor/data/coco.yaml中设定,训练前请确认路径无误,如果路径不一致需要修改。 -原coco.yaml文件如图: -![coco_yaml](./figure/coco_yaml.png) - -## Train Model -### GPU 1P:在目录yolor下,运行 ./test/train_gpu_1p.sh -``` -chmod +x ./test/train_gpu_1p.sh -bash ./test/train_gpu_1p.sh -``` -若需要指定训练使用的卡号, 可修改train_gpu_1p.sh文件 "--device 0"配置项,其中卡号为0-7 - -### GPU 8P:在目录yolor下,运行 ./test/train_gpu_8p.sh -``` -chmod +x ./test/train_gpu_8p.sh -bash ./test/train_gpu_8p.sh -``` - -### NPU 1P:在目录yolor下,运行 train_performance_1p.sh -``` -chmod +x ./test/train_performance_1p.sh -bash ./test/train_performance_1p.sh -``` -若需要指定训练使用的卡号, 可修改train_performance_1p.sh文件 "--npu 0"配置项,其中卡号为0-7 - -### NPU 8P:在目录yolor下,运行 train_performance_8p.sh -``` -chmod +x ./test/train_performance_8p.sh -bash ./test/train_performance_8p.sh -``` - -注:在模型训练结束时,程序默认会将save的最后一个模型去除optimizer以减少模型大小,这会load模型,而在8P训练中,save和load的进程可能会不同步导致先load后save而报错,所以train_performance_8p.sh默认训练3个epoch(只要大于1个epoch即可)。 -如果用户只想要训练一个epoch并且保留模型的optimizer,在train_mp.py中注释掉如下部分代码即可: -![strip_optimizer](./figure/strip_optimizer.jpg) - - -### NPU 8P Full:在目录yolor下,运行 train_full_8p.sh -``` -chmod +x ./test/train_full_8p.sh -bash ./test/train_full_8p.sh -``` - -## Evaluation -复制训练好的last.pt到pretrained文件夹下,运行evaluation_npu.sh (npu) / evaluation_gpu.sh (gpu) -``` -chmod +x ./test/evaluation_xxx.sh -bash ./test/evaluation_xxx.sh -``` - -## 迁移学习 -参考https://github.com/WongKinYiu/yolor/issues/103,更改./cfg/yolo_p6.cfg中**对应行**的classes和filters: - -以coco为例,原80类别现在改为81:classes = 81, filters = anchor * (5 + classes) = 3 * (5 + 81) = 258,更改后的.cfg命名为yolor_p6_finetune.cfg,复制训练好的last.pt到pretrained文件夹下,运行train_finetune_1p.sh -``` -chmod +x ./test/train_finetune_1p.sh -bash ./test/train_finetune_1p.sh -``` - -## 白名单 -### Transpose whilte list - -路径:/usr/local/Ascend/ascend-toolkit/latest/opp/op_impl/built-in/ai_core/tbe/impl/dynamic/transpose.py -#120行左右 -``` -[8,3,160,160,85], [8,3,80,80,85], [8,3,40,40,85], [8,3,20,20,85], [8,3,85,160,160], [8,3,85,80,80] -``` -### Slice_d whilte list -路径:/usr/local/Ascend/ascend-toolkit/latest/opp/op_impl/built-in/ai_core/tbe/impl/slice_d.py -#7500行左右 -``` -["float16", [32,3,96,168,85], [32,3,96,168,2]], -["float16", [32,3,96,168,85], [32,3,96,168,4]], -["float16", [32,3,80,168,85], [32,3,80,168,2]], -["float16", [32,3,80,168,85], [32,3,80,168,4]], -["float16", [32,3,48,84,85], [32,3,48,84,2]], -["float16", [32,3,48,84,85], [32,3,48,84,4]], -["float16", [32,3,40,84,85], [32,3,40,84,2]], -["float16", [32,3,40,84,85], [32,3,40,84,4]], -["float16", [32,3,24,42,85], [32,3,24,42,2]], -["float16", [32,3,24,42,85], [32,3,24,42,4]], -["float16", [32,3,20,42,85], [32,3,20,42,2]], -["float16", [32,3,20,42,85], [32,3,20,42,4]], -["float32", [8, 3, 160, 160, 85], [8, 3, 160, 160, 1]], -["float32", [8, 3, 80, 80, 85], [8, 3, 80, 80, 1]], +# YOLOR 模型使用说明 + +## Requirements +* NPU配套的run包安装 +* Python 3.7.5 +* PyTorch(NPU版本) +* apex(NPU版本) +* (可选)参考《Pytorch 网络模型移植&训练指南》6.4.2章节,配置cpu为性能模式,以达到模型最佳性能;不开启不影响功能。 + +安装其他依赖(先安装NPU版本的pytorch和apex,再安装其他依赖): +``` +pip install -r requirements.txt +``` + +## Dataset +1. 下载coco数据集,包含图片、annotations、labels图片、annotations: + ``` + cd yolor + bash scripts/get_coco.sh + ``` +2. 将coco数据集放于工程根目录下 + coco目录结构如下: + ``` + coco + |-- LICENSE + |-- README.txt + |-- annotations + | `-- instances_val2017.json + |-- images + | |-- test2017 + | |-- train2017 + | `-- val2017 + |-- labels + | |-- train2017 + | |-- train2017.cache3 + | |-- val2017 + | `-- val2017.cache3 + |-- test-dev2017.txt + |-- train2017.cache + |-- train2017.txt + |-- val2017.cache + `-- val2017.txt + ``` + +注:数据集路径在./yolor/data/coco.yaml中设定,训练前请确认路径无误,如果路径不一致需要修改。 +原coco.yaml文件如图: +![coco_yaml](./figure/coco_yaml.png) + +## Train Model +### GPU 1P:在目录yolor下,运行 ./test/train_gpu_1p.sh +``` +chmod +x ./test/train_gpu_1p.sh +bash ./test/train_gpu_1p.sh +``` +若需要指定训练使用的卡号, 可修改train_gpu_1p.sh文件 "--device 0"配置项,其中卡号为0-7 + +### GPU 8P:在目录yolor下,运行 ./test/train_gpu_8p.sh +``` +chmod +x ./test/train_gpu_8p.sh +bash ./test/train_gpu_8p.sh +``` + +### NPU 1P:在目录yolor下,运行 train_performance_1p.sh +``` +chmod +x ./test/train_performance_1p.sh +bash ./test/train_performance_1p.sh +``` +若需要指定训练使用的卡号, 可修改train_performance_1p.sh文件 "--npu 0"配置项,其中卡号为0-7 + +### NPU 8P:在目录yolor下,运行 train_performance_8p.sh +``` +chmod +x ./test/train_performance_8p.sh +bash ./test/train_performance_8p.sh +``` + +注:在模型训练结束时,程序默认会将save的最后一个模型去除optimizer以减少模型大小,这会load模型,而在8P训练中,save和load的进程可能会不同步导致先load后save而报错,所以train_performance_8p.sh默认训练3个epoch(只要大于1个epoch即可)。 +如果用户只想要训练一个epoch并且保留模型的optimizer,在train_mp.py中注释掉如下部分代码即可: +![strip_optimizer](./figure/strip_optimizer.jpg) + + +### NPU 8P Full:在目录yolor下,运行 train_full_8p.sh +``` +chmod +x ./test/train_full_8p.sh +bash ./test/train_full_8p.sh +``` + +## Evaluation +复制训练好的last.pt到pretrained文件夹下,运行evaluation_npu.sh (npu) / evaluation_gpu.sh (gpu) +``` +chmod +x ./test/evaluation_xxx.sh +bash ./test/evaluation_xxx.sh +``` + +## 迁移学习 +参考https://github.com/WongKinYiu/yolor/issues/103,更改./cfg/yolo_p6.cfg中**对应行**的classes和filters: + +以coco为例,原80类别现在改为81:classes = 81, filters = anchor * (5 + classes) = 3 * (5 + 81) = 258,更改后的.cfg命名为yolor_p6_finetune.cfg,复制训练好的last.pt到pretrained文件夹下,运行train_finetune_1p.sh +``` +chmod +x ./test/train_finetune_1p.sh +bash ./test/train_finetune_1p.sh +``` + +## 白名单 +### Transpose whilte list + +路径:/usr/local/Ascend/ascend-toolkit/latest/opp/op_impl/built-in/ai_core/tbe/impl/dynamic/transpose.py +#120行左右 +``` +[8,3,160,160,85], [8,3,80,80,85], [8,3,40,40,85], [8,3,20,20,85], [8,3,85,160,160], [8,3,85,80,80] +``` +### Slice_d whilte list +路径:/usr/local/Ascend/ascend-toolkit/latest/opp/op_impl/built-in/ai_core/tbe/impl/slice_d.py +#7500行左右 +``` +["float16", [32,3,96,168,85], [32,3,96,168,2]], +["float16", [32,3,96,168,85], [32,3,96,168,4]], +["float16", [32,3,80,168,85], [32,3,80,168,2]], +["float16", [32,3,80,168,85], [32,3,80,168,4]], +["float16", [32,3,48,84,85], [32,3,48,84,2]], +["float16", [32,3,48,84,85], [32,3,48,84,4]], +["float16", [32,3,40,84,85], [32,3,40,84,2]], +["float16", [32,3,40,84,85], [32,3,40,84,4]], +["float16", [32,3,24,42,85], [32,3,24,42,2]], +["float16", [32,3,24,42,85], [32,3,24,42,4]], +["float16", [32,3,20,42,85], [32,3,20,42,2]], +["float16", [32,3,20,42,85], [32,3,20,42,4]], +["float32", [8, 3, 160, 160, 85], [8, 3, 160, 160, 1]], +["float32", [8, 3, 80, 80, 85], [8, 3, 80, 80, 1]], ``` \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_csp.cfg b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_csp.cfg index 810273b197..9f5f3ab421 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_csp.cfg +++ b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_csp.cfg @@ -1,1376 +1,1376 @@ -[net] -# Testing -#batch=1 -#subdivisions=1 -# Training -batch=64 -subdivisions=8 -width=512 -height=512 -channels=3 -momentum=0.949 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.00261 -burn_in=1000 -max_batches = 500500 -policy=steps -steps=400000,450000 -scales=.1,.1 - -#cutmix=1 -mosaic=1 - - -# ============ Backbone ============ # - -# Stem - -# 0 -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=silu - -# P1 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=silu - -# 4 (previous+1+3k) -[shortcut] -from=-3 -activation=linear - -# P2 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=silu - -# Merge [-1, -(3k+4)] - -[route] -layers = -1,-10 - -# Transition last - -# 17 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -# P3 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -# Merge [-1 -(4+3k)] - -[route] -layers = -1,-28 - -# Transition last - -# 48 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -# P4 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -# Merge [-1 -(3k+4)] - -[route] -layers = -1,-28 - -# Transition last - -# 79 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -# P5 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -# Merge [-1 -(3k+4)] - -[route] -layers = -1,-16 - -# Transition last - -# 98 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=1024 -size=1 -stride=1 -pad=1 -activation=silu - -# ============ End of Backbone ============ # - -# ============ Neck ============ # - -# CSPSPP - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=silu - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=silu - -[route] -layers = -1, -13 - -# 113 (previous+6+5+2k) -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -# End of CSPSPP - - -# FPN-4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[upsample] -stride=2 - -[route] -layers = 79 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=silu - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -6 - -# Transition last - -# 127 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - - -# FPN-3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[upsample] -stride=2 - -[route] -layers = 48 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=128 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=128 -activation=silu - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -6 - -# Transition last - -# 141 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - - -# PAN-4 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=256 -activation=silu - -[route] -layers = -1, 127 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=silu - -[route] -layers = -1,-6 - -# Transition last - -# 152 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - - -# PAN-5 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=512 -activation=silu - -[route] -layers = -1, 113 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=silu - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=silu - -[route] -layers = -1,-6 - -# Transition last - -# 163 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -# ============ End of Neck ============ # - -# 164 -[implicit_add] -filters=256 - -# 165 -[implicit_add] -filters=512 - -# 166 -[implicit_add] -filters=1024 - -# 167 -[implicit_mul] -filters=255 - -# 168 -[implicit_mul] -filters=255 - -# 169 -[implicit_mul] -filters=255 - -# ============ Head ============ # - -# YOLO-3 - -[route] -layers = 141 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=silu - -[shift_channels] -from=164 - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[control_channels] -from=167 - -[yolo] -mask = 0,1,2 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-4 - -[route] -layers = 152 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=silu - -[shift_channels] -from=165 - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[control_channels] -from=168 - -[yolo] -mask = 3,4,5 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-5 - -[route] -layers = 163 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=silu - -[shift_channels] -from=166 - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[control_channels] -from=169 - -[yolo] -mask = 6,7,8 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 +[net] +# Testing +#batch=1 +#subdivisions=1 +# Training +batch=64 +subdivisions=8 +width=512 +height=512 +channels=3 +momentum=0.949 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.00261 +burn_in=1000 +max_batches = 500500 +policy=steps +steps=400000,450000 +scales=.1,.1 + +#cutmix=1 +mosaic=1 + + +# ============ Backbone ============ # + +# Stem + +# 0 +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=silu + +# P1 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=2 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=32 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=silu + +# 4 (previous+1+3k) +[shortcut] +from=-3 +activation=linear + +# P2 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=silu + +# Merge [-1, -(3k+4)] + +[route] +layers = -1,-10 + +# Transition last + +# 17 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +# P3 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +# Merge [-1 -(4+3k)] + +[route] +layers = -1,-28 + +# Transition last + +# 48 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +# P4 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +# Merge [-1 -(3k+4)] + +[route] +layers = -1,-28 + +# Transition last + +# 79 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +# P5 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +# Merge [-1 -(3k+4)] + +[route] +layers = -1,-16 + +# Transition last + +# 98 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=1024 +size=1 +stride=1 +pad=1 +activation=silu + +# ============ End of Backbone ============ # + +# ============ Neck ============ # + +# CSPSPP + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=silu + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 +### End SPP ### + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=silu + +[route] +layers = -1, -13 + +# 113 (previous+6+5+2k) +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +# End of CSPSPP + + +# FPN-4 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[upsample] +stride=2 + +[route] +layers = 79 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=silu + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -6 + +# Transition last + +# 127 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + + +# FPN-3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[upsample] +stride=2 + +[route] +layers = 48 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=128 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=128 +activation=silu + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -6 + +# Transition last + +# 141 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + + +# PAN-4 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=256 +activation=silu + +[route] +layers = -1, 127 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=silu + +[route] +layers = -1,-6 + +# Transition last + +# 152 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + + +# PAN-5 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=512 +activation=silu + +[route] +layers = -1, 113 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=silu + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=silu + +[route] +layers = -1,-6 + +# Transition last + +# 163 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +# ============ End of Neck ============ # + +# 164 +[implicit_add] +filters=256 + +# 165 +[implicit_add] +filters=512 + +# 166 +[implicit_add] +filters=1024 + +# 167 +[implicit_mul] +filters=255 + +# 168 +[implicit_mul] +filters=255 + +# 169 +[implicit_mul] +filters=255 + +# ============ Head ============ # + +# YOLO-3 + +[route] +layers = 141 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=silu + +[shift_channels] +from=164 + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[control_channels] +from=167 + +[yolo] +mask = 0,1,2 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-4 + +[route] +layers = 152 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=silu + +[shift_channels] +from=165 + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[control_channels] +from=168 + +[yolo] +mask = 3,4,5 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-5 + +[route] +layers = 163 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=silu + +[shift_channels] +from=166 + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[control_channels] +from=169 + +[yolo] +mask = 6,7,8 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 diff --git a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_csp_x.cfg b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_csp_x.cfg index 995aefea61..55a54109bf 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_csp_x.cfg +++ b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_csp_x.cfg @@ -1,1576 +1,1576 @@ -[net] -# Testing -#batch=1 -#subdivisions=1 -# Training -batch=64 -subdivisions=8 -width=512 -height=512 -channels=3 -momentum=0.949 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.00261 -burn_in=1000 -max_batches = 500500 -policy=steps -steps=400000,450000 -scales=.1,.1 - -#cutmix=1 -mosaic=1 - - -# ============ Backbone ============ # - -# Stem - -# 0 -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=silu - -# P1 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=80 -size=3 -stride=2 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=40 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=80 -size=3 -stride=1 -pad=1 -activation=silu - -# 4 (previous+1+3k) -[shortcut] -from=-3 -activation=linear - -# P2 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=80 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=80 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=80 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=silu - -# Merge [-1, -(3k+4)] - -[route] -layers = -1,-13 - -# Transition last - -# 20 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -# P3 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -# Merge [-1 -(4+3k)] - -[route] -layers = -1,-34 - -# Transition last - -# 57 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -# P4 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -# Merge [-1 -(3k+4)] - -[route] -layers = -1,-34 - -# Transition last - -# 94 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -# P5 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1280 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -# Merge [-1 -(3k+4)] - -[route] -layers = -1,-19 - -# Transition last - -# 116 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=1280 -size=1 -stride=1 -pad=1 -activation=silu - -# ============ End of Backbone ============ # - -# ============ Neck ============ # - -# CSPSPP - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=silu - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=silu - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=silu - -[route] -layers = -1, -15 - -# 133 (previous+6+5+2k) -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -# End of CSPSPP - - -# FPN-4 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[upsample] -stride=2 - -[route] -layers = 94 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=silu - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 149 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - - -# FPN-3 - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[upsample] -stride=2 - -[route] -layers = 57 - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=160 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=160 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=160 -activation=silu - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 165 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - - -# PAN-4 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=320 -activation=silu - -[route] -layers = -1, 149 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=silu - -[route] -layers = -1,-8 - -# Transition last - -# 178 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - - -# PAN-5 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=640 -activation=silu - -[route] -layers = -1, 133 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=silu - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=silu - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=silu - -[route] -layers = -1,-8 - -# Transition last - -# 191 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -# ============ End of Neck ============ # - -# 192 -[implicit_add] -filters=320 - -# 193 -[implicit_add] -filters=640 - -# 194 -[implicit_add] -filters=1280 - -# 195 -[implicit_mul] -filters=255 - -# 196 -[implicit_mul] -filters=255 - -# 197 -[implicit_mul] -filters=255 - -# ============ Head ============ # - -# YOLO-3 - -[route] -layers = 165 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=silu - -[shift_channels] -from=192 - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[control_channels] -from=195 - -[yolo] -mask = 0,1,2 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-4 - -[route] -layers = 178 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=silu - -[shift_channels] -from=193 - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[control_channels] -from=196 - -[yolo] -mask = 3,4,5 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-5 - -[route] -layers = 191 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1280 -activation=silu - -[shift_channels] -from=194 - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[control_channels] -from=197 - -[yolo] -mask = 6,7,8 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 +[net] +# Testing +#batch=1 +#subdivisions=1 +# Training +batch=64 +subdivisions=8 +width=512 +height=512 +channels=3 +momentum=0.949 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.00261 +burn_in=1000 +max_batches = 500500 +policy=steps +steps=400000,450000 +scales=.1,.1 + +#cutmix=1 +mosaic=1 + + +# ============ Backbone ============ # + +# Stem + +# 0 +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=silu + +# P1 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=80 +size=3 +stride=2 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=40 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=80 +size=3 +stride=1 +pad=1 +activation=silu + +# 4 (previous+1+3k) +[shortcut] +from=-3 +activation=linear + +# P2 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=80 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=80 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=80 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=silu + +# Merge [-1, -(3k+4)] + +[route] +layers = -1,-13 + +# Transition last + +# 20 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +# P3 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +# Merge [-1 -(4+3k)] + +[route] +layers = -1,-34 + +# Transition last + +# 57 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +# P4 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +# Merge [-1 -(3k+4)] + +[route] +layers = -1,-34 + +# Transition last + +# 94 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +# P5 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=1280 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +# Merge [-1 -(3k+4)] + +[route] +layers = -1,-19 + +# Transition last + +# 116 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=1280 +size=1 +stride=1 +pad=1 +activation=silu + +# ============ End of Backbone ============ # + +# ============ Neck ============ # + +# CSPSPP + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=silu + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 +### End SPP ### + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=silu + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=silu + +[route] +layers = -1, -15 + +# 133 (previous+6+5+2k) +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +# End of CSPSPP + + +# FPN-4 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[upsample] +stride=2 + +[route] +layers = 94 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=silu + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 149 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + + +# FPN-3 + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[upsample] +stride=2 + +[route] +layers = 57 + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=160 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=160 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=160 +activation=silu + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 165 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + + +# PAN-4 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=320 +activation=silu + +[route] +layers = -1, 149 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=silu + +[route] +layers = -1,-8 + +# Transition last + +# 178 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + + +# PAN-5 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=640 +activation=silu + +[route] +layers = -1, 133 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=silu + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=silu + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=silu + +[route] +layers = -1,-8 + +# Transition last + +# 191 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +# ============ End of Neck ============ # + +# 192 +[implicit_add] +filters=320 + +# 193 +[implicit_add] +filters=640 + +# 194 +[implicit_add] +filters=1280 + +# 195 +[implicit_mul] +filters=255 + +# 196 +[implicit_mul] +filters=255 + +# 197 +[implicit_mul] +filters=255 + +# ============ Head ============ # + +# YOLO-3 + +[route] +layers = 165 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=silu + +[shift_channels] +from=192 + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[control_channels] +from=195 + +[yolo] +mask = 0,1,2 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-4 + +[route] +layers = 178 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=silu + +[shift_channels] +from=193 + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[control_channels] +from=196 + +[yolo] +mask = 3,4,5 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-5 + +[route] +layers = 191 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1280 +activation=silu + +[shift_channels] +from=194 + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[control_channels] +from=197 + +[yolo] +mask = 6,7,8 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 diff --git a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_p6.cfg b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_p6.cfg index 62b19e8773..88ddd686d7 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_p6.cfg +++ b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_p6.cfg @@ -1,1762 +1,1762 @@ -[net] -batch=64 -subdivisions=8 -width=1280 -height=1280 -channels=3 -momentum=0.949 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - - - -learning_rate=0.00261 -burn_in=1000 -max_batches = 500500 -policy=steps -steps=400000,450000 -scales=.1,.1 - -mosaic=1 - - -# ============ Backbone ============ # - -# Stem - -# P1 - -# Downsample - -# 0 -[reorg] - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=swish - - -# P2 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -# Transition first -# -#[convolutional] -#batch_normalize=1 -#filters=64 -#size=1 -#stride=1 -#pad=1 -#activation=swish - -# Merge [-1, -(3k+3)] - -[route] -layers = -1,-12 - -# Transition last - -# 16 (previous+6+3k) -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - - -# P3 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -# Transition first -# -#[convolutional] -#batch_normalize=1 -#filters=128 -#size=1 -#stride=1 -#pad=1 -#activation=swish - -# Merge [-1, -(3k+3)] - -[route] -layers = -1,-24 - -# Transition last - -# 43 (previous+6+3k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - - -# P4 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=384 -size=3 -stride=2 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -# Transition first -# -#[convolutional] -#batch_normalize=1 -#filters=192 -#size=1 -#stride=1 -#pad=1 -#activation=swish - -# Merge [-1, -(3k+3)] - -[route] -layers = -1,-24 - -# Transition last - -# 70 (previous+6+3k) -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=swish - - -# P5 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -# Transition first -# -#[convolutional] -#batch_normalize=1 -#filters=256 -#size=1 -#stride=1 -#pad=1 -#activation=swish - -# Merge [-1, -(3k+3)] - -[route] -layers = -1,-12 - -# Transition last - -# 85 (previous+6+3k) -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - - -# P6 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=2 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -# Transition first -# -#[convolutional] -#batch_normalize=1 -#filters=320 -#size=1 -#stride=1 -#pad=1 -#activation=swish - -# Merge [-1, -(3k+3)] - -[route] -layers = -1,-12 - -# Transition last - -# 100 (previous+6+3k) -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -# ============ End of Backbone ============ # - -# ============ Neck ============ # - -# CSPSPP - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=swish - -[route] -layers = -1, -13 - -# 115 (previous+6+5+2k) -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -# End of CSPSPP - - -# FPN-5 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[upsample] -stride=2 - -[route] -layers = 85 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=swish - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 131 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - - -# FPN-4 - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[upsample] -stride=2 - -[route] -layers = 70 - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=192 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=192 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=192 -activation=swish - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 147 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - - -# FPN-3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[upsample] -stride=2 - -[route] -layers = 43 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=128 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=128 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=128 -activation=swish - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 163 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - - -# PAN-4 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=192 -activation=swish - -[route] -layers = -1, 147 - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=192 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=192 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=192 -activation=swish - -[route] -layers = -1,-8 - -# Transition last - -# 176 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - - -# PAN-5 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=256 -activation=swish - -[route] -layers = -1, 131 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=swish - -[route] -layers = -1,-8 - -# Transition last - -# 189 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - - -# PAN-6 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=320 -activation=swish - -[route] -layers = -1, 115 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=swish - -[route] -layers = -1,-8 - -# Transition last - -# 202 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -# ============ End of Neck ============ # - -# 203 -[implicit_add] -filters=256 - -# 204 -[implicit_add] -filters=384 - -# 205 -[implicit_add] -filters=512 - -# 206 -[implicit_add] -filters=640 - -# 207 -[implicit_mul] -filters=255 - -# 208 -[implicit_mul] -filters=255 - -# 209 -[implicit_mul] -filters=255 - -# 210 -[implicit_mul] -filters=255 - -# ============ Head ============ # - -# YOLO-3 - -[route] -layers = 163 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=swish - -[shift_channels] -from=203 - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[control_channels] -from=207 - -[yolo] -mask = 0,1,2 -anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 -classes=80 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-4 - -[route] -layers = 176 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=384 -activation=swish - -[shift_channels] -from=204 - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[control_channels] -from=208 - -[yolo] -mask = 3,4,5 -anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 -classes=80 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-5 - -[route] -layers = 189 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=swish - -[shift_channels] -from=205 - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[control_channels] -from=209 - -[yolo] -mask = 6,7,8 -anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 -classes=80 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-6 - -[route] -layers = 202 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=swish - -[shift_channels] -from=206 - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[control_channels] -from=210 - -[yolo] -mask = 9,10,11 -anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 -classes=80 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - +[net] +batch=64 +subdivisions=8 +width=1280 +height=1280 +channels=3 +momentum=0.949 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + + + +learning_rate=0.00261 +burn_in=1000 +max_batches = 500500 +policy=steps +steps=400000,450000 +scales=.1,.1 + +mosaic=1 + + +# ============ Backbone ============ # + +# Stem + +# P1 + +# Downsample + +# 0 +[reorg] + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=swish + + +# P2 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=2 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +# Transition first +# +#[convolutional] +#batch_normalize=1 +#filters=64 +#size=1 +#stride=1 +#pad=1 +#activation=swish + +# Merge [-1, -(3k+3)] + +[route] +layers = -1,-12 + +# Transition last + +# 16 (previous+6+3k) +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + + +# P3 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=2 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +# Transition first +# +#[convolutional] +#batch_normalize=1 +#filters=128 +#size=1 +#stride=1 +#pad=1 +#activation=swish + +# Merge [-1, -(3k+3)] + +[route] +layers = -1,-24 + +# Transition last + +# 43 (previous+6+3k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + + +# P4 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=384 +size=3 +stride=2 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +# Transition first +# +#[convolutional] +#batch_normalize=1 +#filters=192 +#size=1 +#stride=1 +#pad=1 +#activation=swish + +# Merge [-1, -(3k+3)] + +[route] +layers = -1,-24 + +# Transition last + +# 70 (previous+6+3k) +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=swish + + +# P5 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=2 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +# Transition first +# +#[convolutional] +#batch_normalize=1 +#filters=256 +#size=1 +#stride=1 +#pad=1 +#activation=swish + +# Merge [-1, -(3k+3)] + +[route] +layers = -1,-12 + +# Transition last + +# 85 (previous+6+3k) +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + + +# P6 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=2 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +# Transition first +# +#[convolutional] +#batch_normalize=1 +#filters=320 +#size=1 +#stride=1 +#pad=1 +#activation=swish + +# Merge [-1, -(3k+3)] + +[route] +layers = -1,-12 + +# Transition last + +# 100 (previous+6+3k) +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +# ============ End of Backbone ============ # + +# ============ Neck ============ # + +# CSPSPP + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 +### End SPP ### + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=swish + +[route] +layers = -1, -13 + +# 115 (previous+6+5+2k) +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +# End of CSPSPP + + +# FPN-5 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[upsample] +stride=2 + +[route] +layers = 85 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=swish + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 131 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + + +# FPN-4 + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[upsample] +stride=2 + +[route] +layers = 70 + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=192 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=192 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=192 +activation=swish + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 147 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + + +# FPN-3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[upsample] +stride=2 + +[route] +layers = 43 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=128 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=128 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=128 +activation=swish + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 163 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + + +# PAN-4 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=192 +activation=swish + +[route] +layers = -1, 147 + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=192 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=192 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=192 +activation=swish + +[route] +layers = -1,-8 + +# Transition last + +# 176 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + + +# PAN-5 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=256 +activation=swish + +[route] +layers = -1, 131 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=swish + +[route] +layers = -1,-8 + +# Transition last + +# 189 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + + +# PAN-6 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=320 +activation=swish + +[route] +layers = -1, 115 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=swish + +[route] +layers = -1,-8 + +# Transition last + +# 202 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +# ============ End of Neck ============ # + +# 203 +[implicit_add] +filters=256 + +# 204 +[implicit_add] +filters=384 + +# 205 +[implicit_add] +filters=512 + +# 206 +[implicit_add] +filters=640 + +# 207 +[implicit_mul] +filters=255 + +# 208 +[implicit_mul] +filters=255 + +# 209 +[implicit_mul] +filters=255 + +# 210 +[implicit_mul] +filters=255 + +# ============ Head ============ # + +# YOLO-3 + +[route] +layers = 163 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=swish + +[shift_channels] +from=203 + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[control_channels] +from=207 + +[yolo] +mask = 0,1,2 +anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 +classes=80 +num=12 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-4 + +[route] +layers = 176 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=384 +activation=swish + +[shift_channels] +from=204 + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[control_channels] +from=208 + +[yolo] +mask = 3,4,5 +anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 +classes=80 +num=12 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-5 + +[route] +layers = 189 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=swish + +[shift_channels] +from=205 + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[control_channels] +from=209 + +[yolo] +mask = 6,7,8 +anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 +classes=80 +num=12 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-6 + +[route] +layers = 202 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=swish + +[shift_channels] +from=206 + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[control_channels] +from=210 + +[yolo] +mask = 9,10,11 +anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 +classes=80 +num=12 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + # ============ End of Head ============ # \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_p6_finetune.cfg b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_p6_finetune.cfg index 0869eac0dc..ab74810f6b 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_p6_finetune.cfg +++ b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_p6_finetune.cfg @@ -1,1760 +1,1760 @@ -[net] -batch=64 -subdivisions=8 -width=1280 -height=1280 -channels=3 -momentum=0.949 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.00261 -burn_in=1000 -max_batches = 500500 -policy=steps -steps=400000,450000 -scales=.1,.1 - -mosaic=1 - - -# ============ Backbone ============ # - -# Stem - -# P1 - -# Downsample - -# 0 -[reorg] - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=swish - - -# P2 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -# Transition first -# -#[convolutional] -#batch_normalize=1 -#filters=64 -#size=1 -#stride=1 -#pad=1 -#activation=swish - -# Merge [-1, -(3k+3)] - -[route] -layers = -1,-12 - -# Transition last - -# 16 (previous+6+3k) -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - - -# P3 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -# Transition first -# -#[convolutional] -#batch_normalize=1 -#filters=128 -#size=1 -#stride=1 -#pad=1 -#activation=swish - -# Merge [-1, -(3k+3)] - -[route] -layers = -1,-24 - -# Transition last - -# 43 (previous+6+3k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - - -# P4 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=384 -size=3 -stride=2 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -# Transition first -# -#[convolutional] -#batch_normalize=1 -#filters=192 -#size=1 -#stride=1 -#pad=1 -#activation=swish - -# Merge [-1, -(3k+3)] - -[route] -layers = -1,-24 - -# Transition last - -# 70 (previous+6+3k) -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=swish - - -# P5 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -# Transition first -# -#[convolutional] -#batch_normalize=1 -#filters=256 -#size=1 -#stride=1 -#pad=1 -#activation=swish - -# Merge [-1, -(3k+3)] - -[route] -layers = -1,-12 - -# Transition last - -# 85 (previous+6+3k) -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - - -# P6 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=2 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -# Transition first -# -#[convolutional] -#batch_normalize=1 -#filters=320 -#size=1 -#stride=1 -#pad=1 -#activation=swish - -# Merge [-1, -(3k+3)] - -[route] -layers = -1,-12 - -# Transition last - -# 100 (previous+6+3k) -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -# ============ End of Backbone ============ # - -# ============ Neck ============ # - -# CSPSPP - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=swish - -[route] -layers = -1, -13 - -# 115 (previous+6+5+2k) -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -# End of CSPSPP - - -# FPN-5 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[upsample] -stride=2 - -[route] -layers = 85 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=swish - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 131 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - - -# FPN-4 - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[upsample] -stride=2 - -[route] -layers = 70 - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=192 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=192 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=192 -activation=swish - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 147 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - - -# FPN-3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[upsample] -stride=2 - -[route] -layers = 43 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=128 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=128 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=128 -activation=swish - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 163 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - - -# PAN-4 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=192 -activation=swish - -[route] -layers = -1, 147 - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=192 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=192 -activation=swish - -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=192 -activation=swish - -[route] -layers = -1,-8 - -# Transition last - -# 176 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=192 -size=1 -stride=1 -pad=1 -activation=swish - - -# PAN-5 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=256 -activation=swish - -[route] -layers = -1, 131 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=swish - -[route] -layers = -1,-8 - -# Transition last - -# 189 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - - -# PAN-6 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=320 -activation=swish - -[route] -layers = -1, 115 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=swish - -[route] -layers = -1,-8 - -# Transition last - -# 202 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -# ============ End of Neck ============ # - -# 203 -[implicit_add] -filters=256 - -# 204 -[implicit_add] -filters=384 - -# 205 -[implicit_add] -filters=512 - -# 206 -[implicit_add] -filters=640 - -# 207 -[implicit_mul] -filters=258 - -# 208 -[implicit_mul] -filters=258 - -# 209 -[implicit_mul] -filters=258 - -# 210 -[implicit_mul] -filters=258 - -# ============ Head ============ # - -# YOLO-3 - -[route] -layers = 163 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=swish - -[shift_channels] -from=203 - -[convolutional] -size=1 -stride=1 -pad=1 -filters=258 -activation=linear - -[control_channels] -from=207 - -[yolo] -mask = 0,1,2 -anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 -classes=81 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-4 - -[route] -layers = 176 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=384 -activation=swish - -[shift_channels] -from=204 - -[convolutional] -size=1 -stride=1 -pad=1 -filters=258 -activation=linear - -[control_channels] -from=208 - -[yolo] -mask = 3,4,5 -anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 -classes=81 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-5 - -[route] -layers = 189 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=swish - -[shift_channels] -from=205 - -[convolutional] -size=1 -stride=1 -pad=1 -filters=258 -activation=linear - -[control_channels] -from=209 - -[yolo] -mask = 6,7,8 -anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 -classes=81 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-6 - -[route] -layers = 202 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=swish - -[shift_channels] -from=206 - -[convolutional] -size=1 -stride=1 -pad=1 -filters=258 -activation=linear - -[control_channels] -from=210 - -[yolo] -mask = 9,10,11 -anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 -classes=81 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - +[net] +batch=64 +subdivisions=8 +width=1280 +height=1280 +channels=3 +momentum=0.949 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.00261 +burn_in=1000 +max_batches = 500500 +policy=steps +steps=400000,450000 +scales=.1,.1 + +mosaic=1 + + +# ============ Backbone ============ # + +# Stem + +# P1 + +# Downsample + +# 0 +[reorg] + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=swish + + +# P2 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=2 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +# Transition first +# +#[convolutional] +#batch_normalize=1 +#filters=64 +#size=1 +#stride=1 +#pad=1 +#activation=swish + +# Merge [-1, -(3k+3)] + +[route] +layers = -1,-12 + +# Transition last + +# 16 (previous+6+3k) +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + + +# P3 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=2 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +# Transition first +# +#[convolutional] +#batch_normalize=1 +#filters=128 +#size=1 +#stride=1 +#pad=1 +#activation=swish + +# Merge [-1, -(3k+3)] + +[route] +layers = -1,-24 + +# Transition last + +# 43 (previous+6+3k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + + +# P4 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=384 +size=3 +stride=2 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +# Transition first +# +#[convolutional] +#batch_normalize=1 +#filters=192 +#size=1 +#stride=1 +#pad=1 +#activation=swish + +# Merge [-1, -(3k+3)] + +[route] +layers = -1,-24 + +# Transition last + +# 70 (previous+6+3k) +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=swish + + +# P5 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=2 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +# Transition first +# +#[convolutional] +#batch_normalize=1 +#filters=256 +#size=1 +#stride=1 +#pad=1 +#activation=swish + +# Merge [-1, -(3k+3)] + +[route] +layers = -1,-12 + +# Transition last + +# 85 (previous+6+3k) +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + + +# P6 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=2 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +# Transition first +# +#[convolutional] +#batch_normalize=1 +#filters=320 +#size=1 +#stride=1 +#pad=1 +#activation=swish + +# Merge [-1, -(3k+3)] + +[route] +layers = -1,-12 + +# Transition last + +# 100 (previous+6+3k) +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +# ============ End of Backbone ============ # + +# ============ Neck ============ # + +# CSPSPP + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 +### End SPP ### + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=swish + +[route] +layers = -1, -13 + +# 115 (previous+6+5+2k) +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +# End of CSPSPP + + +# FPN-5 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[upsample] +stride=2 + +[route] +layers = 85 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=swish + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 131 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + + +# FPN-4 + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[upsample] +stride=2 + +[route] +layers = 70 + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=192 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=192 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=192 +activation=swish + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 147 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + + +# FPN-3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[upsample] +stride=2 + +[route] +layers = 43 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=128 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=128 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=128 +activation=swish + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 163 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + + +# PAN-4 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=192 +activation=swish + +[route] +layers = -1, 147 + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=192 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=192 +activation=swish + +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=192 +activation=swish + +[route] +layers = -1,-8 + +# Transition last + +# 176 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=192 +size=1 +stride=1 +pad=1 +activation=swish + + +# PAN-5 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=256 +activation=swish + +[route] +layers = -1, 131 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=swish + +[route] +layers = -1,-8 + +# Transition last + +# 189 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + + +# PAN-6 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=320 +activation=swish + +[route] +layers = -1, 115 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=swish + +[route] +layers = -1,-8 + +# Transition last + +# 202 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +# ============ End of Neck ============ # + +# 203 +[implicit_add] +filters=256 + +# 204 +[implicit_add] +filters=384 + +# 205 +[implicit_add] +filters=512 + +# 206 +[implicit_add] +filters=640 + +# 207 +[implicit_mul] +filters=258 + +# 208 +[implicit_mul] +filters=258 + +# 209 +[implicit_mul] +filters=258 + +# 210 +[implicit_mul] +filters=258 + +# ============ Head ============ # + +# YOLO-3 + +[route] +layers = 163 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=swish + +[shift_channels] +from=203 + +[convolutional] +size=1 +stride=1 +pad=1 +filters=258 +activation=linear + +[control_channels] +from=207 + +[yolo] +mask = 0,1,2 +anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 +classes=81 +num=12 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-4 + +[route] +layers = 176 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=384 +activation=swish + +[shift_channels] +from=204 + +[convolutional] +size=1 +stride=1 +pad=1 +filters=258 +activation=linear + +[control_channels] +from=208 + +[yolo] +mask = 3,4,5 +anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 +classes=81 +num=12 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-5 + +[route] +layers = 189 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=swish + +[shift_channels] +from=205 + +[convolutional] +size=1 +stride=1 +pad=1 +filters=258 +activation=linear + +[control_channels] +from=209 + +[yolo] +mask = 6,7,8 +anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 +classes=81 +num=12 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-6 + +[route] +layers = 202 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=swish + +[shift_channels] +from=206 + +[convolutional] +size=1 +stride=1 +pad=1 +filters=258 +activation=linear + +[control_channels] +from=210 + +[yolo] +mask = 9,10,11 +anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 +classes=81 +num=12 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + # ============ End of Head ============ # \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_w6.cfg b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_w6.cfg index 4052603dd2..b91167a2e0 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_w6.cfg +++ b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolor_w6.cfg @@ -1,1760 +1,1760 @@ -[net] -batch=64 -subdivisions=8 -width=1280 -height=1280 -channels=3 -momentum=0.949 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.00261 -burn_in=1000 -max_batches = 500500 -policy=steps -steps=400000,450000 -scales=.1,.1 - -mosaic=1 - - -# ============ Backbone ============ # - -# Stem - -# P1 - -# Downsample - -# 0 -[reorg] - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=silu - - -# P2 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first -# -#[convolutional] -#batch_normalize=1 -#filters=64 -#size=1 -#stride=1 -#pad=1 -#activation=silu - -# Merge [-1, -(3k+3)] - -[route] -layers = -1,-12 - -# Transition last - -# 16 (previous+6+3k) -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - - -# P3 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first -# -#[convolutional] -#batch_normalize=1 -#filters=128 -#size=1 -#stride=1 -#pad=1 -#activation=silu - -# Merge [-1, -(3k+3)] - -[route] -layers = -1,-24 - -# Transition last - -# 43 (previous+6+3k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - - -# P4 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first -# -#[convolutional] -#batch_normalize=1 -#filters=256 -#size=1 -#stride=1 -#pad=1 -#activation=silu - -# Merge [-1, -(3k+3)] - -[route] -layers = -1,-24 - -# Transition last - -# 70 (previous+6+3k) -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - - -# P5 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=768 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=384 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=384 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=384 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first -# -#[convolutional] -#batch_normalize=1 -#filters=384 -#size=1 -#stride=1 -#pad=1 -#activation=silu - -# Merge [-1, -(3k+3)] - -[route] -layers = -1,-12 - -# Transition last - -# 85 (previous+6+3k) -[convolutional] -batch_normalize=1 -filters=768 -size=1 -stride=1 -pad=1 -activation=silu - - -# P6 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first -# -#[convolutional] -#batch_normalize=1 -#filters=512 -#size=1 -#stride=1 -#pad=1 -#activation=silu - -# Merge [-1, -(3k+3)] - -[route] -layers = -1,-12 - -# Transition last - -# 100 (previous+6+3k) -[convolutional] -batch_normalize=1 -filters=1024 -size=1 -stride=1 -pad=1 -activation=silu - -# ============ End of Backbone ============ # - -# ============ Neck ============ # - -# CSPSPP - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=silu - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=silu - -[route] -layers = -1, -13 - -# 115 (previous+6+5+2k) -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -# End of CSPSPP - - -# FPN-5 - -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=silu - -[upsample] -stride=2 - -[route] -layers = 85 - -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=384 -activation=silu - -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=384 -activation=silu - -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=384 -activation=silu - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 131 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=silu - - -# FPN-4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[upsample] -stride=2 - -[route] -layers = 70 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=silu - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 147 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - - -# FPN-3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[upsample] -stride=2 - -[route] -layers = 43 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=128 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=128 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=128 -activation=silu - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 163 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - - -# PAN-4 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=256 -activation=silu - -[route] -layers = -1, 147 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=silu - -[route] -layers = -1,-8 - -# Transition last - -# 176 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - - -# PAN-5 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=384 -activation=silu - -[route] -layers = -1, 131 - -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=384 -activation=silu - -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=384 -activation=silu - -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=384 -activation=silu - -[route] -layers = -1,-8 - -# Transition last - -# 189 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=384 -size=1 -stride=1 -pad=1 -activation=silu - - -# PAN-6 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=512 -activation=silu - -[route] -layers = -1, 115 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=silu - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=silu - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=silu - -[route] -layers = -1,-8 - -# Transition last - -# 202 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -# ============ End of Neck ============ # - -# 203 -[implicit_add] -filters=256 - -# 204 -[implicit_add] -filters=512 - -# 205 -[implicit_add] -filters=768 - -# 206 -[implicit_add] -filters=1024 - -# 207 -[implicit_mul] -filters=255 - -# 208 -[implicit_mul] -filters=255 - -# 209 -[implicit_mul] -filters=255 - -# 210 -[implicit_mul] -filters=255 - -# ============ Head ============ # - -# YOLO-3 - -[route] -layers = 163 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=silu - -[shift_channels] -from=203 - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[control_channels] -from=207 - -[yolo] -mask = 0,1,2 -anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 -classes=80 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-4 - -[route] -layers = 176 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=silu - -[shift_channels] -from=204 - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[control_channels] -from=208 - -[yolo] -mask = 3,4,5 -anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 -classes=80 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-5 - -[route] -layers = 189 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=768 -activation=silu - -[shift_channels] -from=205 - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[control_channels] -from=209 - -[yolo] -mask = 6,7,8 -anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 -classes=80 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-6 - -[route] -layers = 202 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=silu - -[shift_channels] -from=206 - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[control_channels] -from=210 - -[yolo] -mask = 9,10,11 -anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 -classes=80 -num=12 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - -# ============ End of Head ============ # +[net] +batch=64 +subdivisions=8 +width=1280 +height=1280 +channels=3 +momentum=0.949 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.00261 +burn_in=1000 +max_batches = 500500 +policy=steps +steps=400000,450000 +scales=.1,.1 + +mosaic=1 + + +# ============ Backbone ============ # + +# Stem + +# P1 + +# Downsample + +# 0 +[reorg] + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=silu + + +# P2 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first +# +#[convolutional] +#batch_normalize=1 +#filters=64 +#size=1 +#stride=1 +#pad=1 +#activation=silu + +# Merge [-1, -(3k+3)] + +[route] +layers = -1,-12 + +# Transition last + +# 16 (previous+6+3k) +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + + +# P3 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first +# +#[convolutional] +#batch_normalize=1 +#filters=128 +#size=1 +#stride=1 +#pad=1 +#activation=silu + +# Merge [-1, -(3k+3)] + +[route] +layers = -1,-24 + +# Transition last + +# 43 (previous+6+3k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + + +# P4 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first +# +#[convolutional] +#batch_normalize=1 +#filters=256 +#size=1 +#stride=1 +#pad=1 +#activation=silu + +# Merge [-1, -(3k+3)] + +[route] +layers = -1,-24 + +# Transition last + +# 70 (previous+6+3k) +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + + +# P5 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=768 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=384 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=384 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=384 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first +# +#[convolutional] +#batch_normalize=1 +#filters=384 +#size=1 +#stride=1 +#pad=1 +#activation=silu + +# Merge [-1, -(3k+3)] + +[route] +layers = -1,-12 + +# Transition last + +# 85 (previous+6+3k) +[convolutional] +batch_normalize=1 +filters=768 +size=1 +stride=1 +pad=1 +activation=silu + + +# P6 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first +# +#[convolutional] +#batch_normalize=1 +#filters=512 +#size=1 +#stride=1 +#pad=1 +#activation=silu + +# Merge [-1, -(3k+3)] + +[route] +layers = -1,-12 + +# Transition last + +# 100 (previous+6+3k) +[convolutional] +batch_normalize=1 +filters=1024 +size=1 +stride=1 +pad=1 +activation=silu + +# ============ End of Backbone ============ # + +# ============ Neck ============ # + +# CSPSPP + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=silu + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 +### End SPP ### + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=silu + +[route] +layers = -1, -13 + +# 115 (previous+6+5+2k) +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +# End of CSPSPP + + +# FPN-5 + +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=silu + +[upsample] +stride=2 + +[route] +layers = 85 + +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=384 +activation=silu + +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=384 +activation=silu + +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=384 +activation=silu + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 131 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=silu + + +# FPN-4 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[upsample] +stride=2 + +[route] +layers = 70 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=silu + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 147 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + + +# FPN-3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[upsample] +stride=2 + +[route] +layers = 43 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=128 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=128 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=128 +activation=silu + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 163 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + + +# PAN-4 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=256 +activation=silu + +[route] +layers = -1, 147 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=silu + +[route] +layers = -1,-8 + +# Transition last + +# 176 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + + +# PAN-5 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=384 +activation=silu + +[route] +layers = -1, 131 + +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=384 +activation=silu + +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=384 +activation=silu + +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=384 +activation=silu + +[route] +layers = -1,-8 + +# Transition last + +# 189 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=384 +size=1 +stride=1 +pad=1 +activation=silu + + +# PAN-6 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=512 +activation=silu + +[route] +layers = -1, 115 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=silu + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=silu + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=silu + +[route] +layers = -1,-8 + +# Transition last + +# 202 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +# ============ End of Neck ============ # + +# 203 +[implicit_add] +filters=256 + +# 204 +[implicit_add] +filters=512 + +# 205 +[implicit_add] +filters=768 + +# 206 +[implicit_add] +filters=1024 + +# 207 +[implicit_mul] +filters=255 + +# 208 +[implicit_mul] +filters=255 + +# 209 +[implicit_mul] +filters=255 + +# 210 +[implicit_mul] +filters=255 + +# ============ Head ============ # + +# YOLO-3 + +[route] +layers = 163 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=silu + +[shift_channels] +from=203 + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[control_channels] +from=207 + +[yolo] +mask = 0,1,2 +anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 +classes=80 +num=12 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-4 + +[route] +layers = 176 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=silu + +[shift_channels] +from=204 + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[control_channels] +from=208 + +[yolo] +mask = 3,4,5 +anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 +classes=80 +num=12 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-5 + +[route] +layers = 189 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=768 +activation=silu + +[shift_channels] +from=205 + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[control_channels] +from=209 + +[yolo] +mask = 6,7,8 +anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 +classes=80 +num=12 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-6 + +[route] +layers = 202 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=silu + +[shift_channels] +from=206 + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[control_channels] +from=210 + +[yolo] +mask = 9,10,11 +anchors = 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 +classes=80 +num=12 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + +# ============ End of Head ============ # diff --git a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov4_csp.cfg b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov4_csp.cfg index 487dc48ad6..c387ce968e 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov4_csp.cfg +++ b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov4_csp.cfg @@ -1,1334 +1,1334 @@ -[net] -# Testing -#batch=1 -#subdivisions=1 -# Training -batch=64 -subdivisions=8 -width=512 -height=512 -channels=3 -momentum=0.949 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.00261 -burn_in=1000 -max_batches = 500500 -policy=steps -steps=400000,450000 -scales=.1,.1 - -#cutmix=1 -mosaic=1 - - -# ============ Backbone ============ # - -# Stem - -# 0 -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=silu - -# P1 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=silu - -# 4 (previous+1+3k) -[shortcut] -from=-3 -activation=linear - -# P2 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=silu - -# Merge [-1, -(3k+4)] - -[route] -layers = -1,-10 - -# Transition last - -# 17 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -# P3 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -# Merge [-1 -(4+3k)] - -[route] -layers = -1,-28 - -# Transition last - -# 48 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -# P4 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -# Merge [-1 -(3k+4)] - -[route] -layers = -1,-28 - -# Transition last - -# 79 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -# P5 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -# Merge [-1 -(3k+4)] - -[route] -layers = -1,-16 - -# Transition last - -# 98 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=1024 -size=1 -stride=1 -pad=1 -activation=silu - -# ============ End of Backbone ============ # - -# ============ Neck ============ # - -# CSPSPP - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=silu - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=silu - -[route] -layers = -1, -13 - -# 113 (previous+6+5+2k) -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -# End of CSPSPP - - -# FPN-4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[upsample] -stride=2 - -[route] -layers = 79 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=silu - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -6 - -# Transition last - -# 127 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - - -# FPN-3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[upsample] -stride=2 - -[route] -layers = 48 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=128 -activation=silu - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=128 -activation=silu - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -6 - -# Transition last - -# 141 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=silu - - -# PAN-4 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=256 -activation=silu - -[route] -layers = -1, 127 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=silu - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=silu - -[route] -layers = -1,-6 - -# Transition last - -# 152 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=silu - - -# PAN-5 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=512 -activation=silu - -[route] -layers = -1, 113 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=silu - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=silu - -[route] -layers = -1,-6 - -# Transition last - -# 163 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=silu - -# ============ End of Neck ============ # - -# ============ Head ============ # - -# YOLO-3 - -[route] -layers = 141 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=silu - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[yolo] -mask = 0,1,2 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-4 - -[route] -layers = 152 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=silu - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[yolo] -mask = 3,4,5 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-5 - -[route] -layers = 163 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=silu - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[yolo] -mask = 6,7,8 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 +[net] +# Testing +#batch=1 +#subdivisions=1 +# Training +batch=64 +subdivisions=8 +width=512 +height=512 +channels=3 +momentum=0.949 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.00261 +burn_in=1000 +max_batches = 500500 +policy=steps +steps=400000,450000 +scales=.1,.1 + +#cutmix=1 +mosaic=1 + + +# ============ Backbone ============ # + +# Stem + +# 0 +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=silu + +# P1 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=2 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=32 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=silu + +# 4 (previous+1+3k) +[shortcut] +from=-3 +activation=linear + +# P2 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=silu + +# Merge [-1, -(3k+4)] + +[route] +layers = -1,-10 + +# Transition last + +# 17 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +# P3 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +# Merge [-1 -(4+3k)] + +[route] +layers = -1,-28 + +# Transition last + +# 48 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +# P4 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +# Merge [-1 -(3k+4)] + +[route] +layers = -1,-28 + +# Transition last + +# 79 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +# P5 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +# Merge [-1 -(3k+4)] + +[route] +layers = -1,-16 + +# Transition last + +# 98 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=1024 +size=1 +stride=1 +pad=1 +activation=silu + +# ============ End of Backbone ============ # + +# ============ Neck ============ # + +# CSPSPP + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=silu + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 +### End SPP ### + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=silu + +[route] +layers = -1, -13 + +# 113 (previous+6+5+2k) +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +# End of CSPSPP + + +# FPN-4 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[upsample] +stride=2 + +[route] +layers = 79 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=silu + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -6 + +# Transition last + +# 127 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + + +# FPN-3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[upsample] +stride=2 + +[route] +layers = 48 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=128 +activation=silu + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=128 +activation=silu + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -6 + +# Transition last + +# 141 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=silu + + +# PAN-4 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=256 +activation=silu + +[route] +layers = -1, 127 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=silu + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=silu + +[route] +layers = -1,-6 + +# Transition last + +# 152 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=silu + + +# PAN-5 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=512 +activation=silu + +[route] +layers = -1, 113 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=silu + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=silu + +[route] +layers = -1,-6 + +# Transition last + +# 163 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=silu + +# ============ End of Neck ============ # + +# ============ Head ============ # + +# YOLO-3 + +[route] +layers = 141 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=silu + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[yolo] +mask = 0,1,2 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-4 + +[route] +layers = 152 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=silu + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[yolo] +mask = 3,4,5 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-5 + +[route] +layers = 163 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=silu + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[yolo] +mask = 6,7,8 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 diff --git a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov4_csp_x.cfg b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov4_csp_x.cfg index 2816f2a016..285abc4d87 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov4_csp_x.cfg +++ b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov4_csp_x.cfg @@ -1,1534 +1,1534 @@ -[net] -# Testing -#batch=1 -#subdivisions=1 -# Training -batch=64 -subdivisions=8 -width=512 -height=512 -channels=3 -momentum=0.949 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.00261 -burn_in=1000 -max_batches = 500500 -policy=steps -steps=400000,450000 -scales=.1,.1 - -#cutmix=1 -mosaic=1 - - -# ============ Backbone ============ # - -# Stem - -# 0 -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=silu - -# P1 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=80 -size=3 -stride=2 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=40 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=80 -size=3 -stride=1 -pad=1 -activation=silu - -# 4 (previous+1+3k) -[shortcut] -from=-3 -activation=linear - -# P2 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=80 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=80 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=80 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=silu - -# Merge [-1, -(3k+4)] - -[route] -layers = -1,-13 - -# Transition last - -# 20 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -# P3 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -# Merge [-1 -(4+3k)] - -[route] -layers = -1,-34 - -# Transition last - -# 57 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -# P4 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -# Merge [-1 -(3k+4)] - -[route] -layers = -1,-34 - -# Transition last - -# 94 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -# P5 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1280 -size=3 -stride=2 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=silu - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -# Merge [-1 -(3k+4)] - -[route] -layers = -1,-19 - -# Transition last - -# 116 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=1280 -size=1 -stride=1 -pad=1 -activation=silu - -# ============ End of Backbone ============ # - -# ============ Neck ============ # - -# CSPSPP - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=silu - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=silu - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=silu - -[route] -layers = -1, -15 - -# 133 (previous+6+5+2k) -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -# End of CSPSPP - - -# FPN-4 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[upsample] -stride=2 - -[route] -layers = 94 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=silu - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 149 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - - -# FPN-3 - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[upsample] -stride=2 - -[route] -layers = 57 - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=160 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=160 -activation=silu - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=160 -activation=silu - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 165 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=silu - - -# PAN-4 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=320 -activation=silu - -[route] -layers = -1, 149 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=silu - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=silu - -[route] -layers = -1,-8 - -# Transition last - -# 178 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=silu - - -# PAN-5 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=640 -activation=silu - -[route] -layers = -1, 133 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -# Split - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=silu - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=silu - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=silu - -[route] -layers = -1,-8 - -# Transition last - -# 191 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=silu - -# ============ End of Neck ============ # - -# ============ Head ============ # - -# YOLO-3 - -[route] -layers = 165 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=silu - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[yolo] -mask = 0,1,2 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-4 - -[route] -layers = 178 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=silu - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[yolo] -mask = 3,4,5 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-5 - -[route] -layers = 191 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1280 -activation=silu - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=linear - -[yolo] -mask = 6,7,8 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 +[net] +# Testing +#batch=1 +#subdivisions=1 +# Training +batch=64 +subdivisions=8 +width=512 +height=512 +channels=3 +momentum=0.949 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.00261 +burn_in=1000 +max_batches = 500500 +policy=steps +steps=400000,450000 +scales=.1,.1 + +#cutmix=1 +mosaic=1 + + +# ============ Backbone ============ # + +# Stem + +# 0 +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=silu + +# P1 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=80 +size=3 +stride=2 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=40 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=80 +size=3 +stride=1 +pad=1 +activation=silu + +# 4 (previous+1+3k) +[shortcut] +from=-3 +activation=linear + +# P2 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=80 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=80 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=80 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=silu + +# Merge [-1, -(3k+4)] + +[route] +layers = -1,-13 + +# Transition last + +# 20 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +# P3 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +# Merge [-1 -(4+3k)] + +[route] +layers = -1,-34 + +# Transition last + +# 57 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +# P4 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +# Merge [-1 -(3k+4)] + +[route] +layers = -1,-34 + +# Transition last + +# 94 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +# P5 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=1280 +size=3 +stride=2 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=silu + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +# Merge [-1 -(3k+4)] + +[route] +layers = -1,-19 + +# Transition last + +# 116 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=1280 +size=1 +stride=1 +pad=1 +activation=silu + +# ============ End of Backbone ============ # + +# ============ Neck ============ # + +# CSPSPP + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=silu + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 +### End SPP ### + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=silu + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=silu + +[route] +layers = -1, -15 + +# 133 (previous+6+5+2k) +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +# End of CSPSPP + + +# FPN-4 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[upsample] +stride=2 + +[route] +layers = 94 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=silu + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 149 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + + +# FPN-3 + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[upsample] +stride=2 + +[route] +layers = 57 + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=160 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=160 +activation=silu + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=160 +activation=silu + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 165 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=silu + + +# PAN-4 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=320 +activation=silu + +[route] +layers = -1, 149 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=silu + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=silu + +[route] +layers = -1,-8 + +# Transition last + +# 178 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=silu + + +# PAN-5 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=640 +activation=silu + +[route] +layers = -1, 133 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +# Split + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=silu + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=silu + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=silu + +[route] +layers = -1,-8 + +# Transition last + +# 191 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=silu + +# ============ End of Neck ============ # + +# ============ Head ============ # + +# YOLO-3 + +[route] +layers = 165 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=silu + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[yolo] +mask = 0,1,2 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-4 + +[route] +layers = 178 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=silu + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[yolo] +mask = 3,4,5 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-5 + +[route] +layers = 191 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1280 +activation=silu + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=linear + +[yolo] +mask = 6,7,8 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 diff --git a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov4_p6.cfg b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov4_p6.cfg index 3a89132924..1a4088414b 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov4_p6.cfg +++ b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov4_p6.cfg @@ -1,2260 +1,2260 @@ -[net] -batch=64 -subdivisions=8 -width=1280 -height=1280 -channels=3 -momentum=0.949 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.00261 -burn_in=1000 -max_batches = 500500 -policy=steps -steps=400000,450000 -scales=.1,.1 - -mosaic=1 - - -# ============ Backbone ============ # - -# Stem - -# 0 -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=mish - - -# P1 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=mish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=mish - -# Merge [-1, -(3k+4)] - -[route] -layers = -1,-7 - -# Transition last - -# 10 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=mish - - -# P2 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=mish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=mish - -# Merge [-1, -(3k+4)] - -[route] -layers = -1,-13 - -# Transition last - -# 26 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - - -# P3 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -# Merge [-1, -(3k+4)] - -[route] -layers = -1,-49 - -# Transition last - -# 78 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - - -# P4 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -# Merge [-1, -(3k+4)] - -[route] -layers = -1,-49 - -# Transition last - -# 130 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - - -# P5 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -# Merge [-1, -(3k+4)] - -[route] -layers = -1,-25 - -# Transition last - -# 158 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=1024 -size=1 -stride=1 -pad=1 -activation=mish - - -# P6 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -# Merge [-1, -(3k+4)] - -[route] -layers = -1,-25 - -# Transition last - -# 186 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=1024 -size=1 -stride=1 -pad=1 -activation=mish - -# ============ End of Backbone ============ # - -# ============ Neck ============ # - -# CSPSPP - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=mish - -[route] -layers = -1, -13 - -# 201 (previous+6+5+2k) -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -# End of CSPSPP - - -# FPN-5 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[upsample] -stride=2 - -[route] -layers = 158 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=mish - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 217 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - - -# FPN-4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[upsample] -stride=2 - -[route] -layers = 130 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=mish - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 233 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - - -# FPN-3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[upsample] -stride=2 - -[route] -layers = 78 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=128 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=128 -activation=mish - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=128 -activation=mish - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 249 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=mish - - -# PAN-4 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=256 -activation=mish - -[route] -layers = -1, 233 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=mish - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=mish - -[route] -layers = -1,-8 - -# Transition last - -# 262 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=mish - - -# PAN-5 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=512 -activation=mish - -[route] -layers = -1, 217 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=mish - -[route] -layers = -1,-8 - -# Transition last - -# 275 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - - -# PAN-6 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=512 -activation=mish - -[route] -layers = -1, 201 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=mish - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=mish - -[route] -layers = -1,-8 - -# Transition last - -# 288 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=mish - -# ============ End of Neck ============ # - -# ============ Head ============ # - -# YOLO-3 - -[route] -layers = 249 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=mish - -[convolutional] -size=1 -stride=1 -pad=1 -filters=340 -activation=linear - -[yolo] -mask = 0,1,2,3 -anchors = 13,17, 31,25, 24,51, 61,45, 61,45, 48,102, 119,96, 97,189, 97,189, 217,184, 171,384, 324,451, 324,451, 545,357, 616,618, 1024,1024 -classes=80 -num=16 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-4 - -[route] -layers = 262 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=mish - -[convolutional] -size=1 -stride=1 -pad=1 -filters=340 -activation=linear - -[yolo] -mask = 4,5,6,7 -anchors = 13,17, 31,25, 24,51, 61,45, 61,45, 48,102, 119,96, 97,189, 97,189, 217,184, 171,384, 324,451, 324,451, 545,357, 616,618, 1024,1024 -classes=80 -num=16 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-5 - -[route] -layers = 275 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=mish - -[convolutional] -size=1 -stride=1 -pad=1 -filters=340 -activation=linear - -[yolo] -mask = 8,9,10,11 -anchors = 13,17, 31,25, 24,51, 61,45, 61,45, 48,102, 119,96, 97,189, 97,189, 217,184, 171,384, 324,451, 324,451, 545,357, 616,618, 1024,1024 -classes=80 -num=16 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-6 - -[route] -layers = 288 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=mish - -[convolutional] -size=1 -stride=1 -pad=1 -filters=340 -activation=linear - -[yolo] -mask = 12,13,14,15 -anchors = 13,17, 31,25, 24,51, 61,45, 61,45, 48,102, 119,96, 97,189, 97,189, 217,184, 171,384, 324,451, 324,451, 545,357, 616,618, 1024,1024 -classes=80 -num=16 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - -# ============ End of Head ============ # +[net] +batch=64 +subdivisions=8 +width=1280 +height=1280 +channels=3 +momentum=0.949 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.00261 +burn_in=1000 +max_batches = 500500 +policy=steps +steps=400000,450000 +scales=.1,.1 + +mosaic=1 + + +# ============ Backbone ============ # + +# Stem + +# 0 +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=mish + + +# P1 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=2 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=32 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=32 +size=1 +stride=1 +pad=1 +activation=mish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=32 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=32 +size=1 +stride=1 +pad=1 +activation=mish + +# Merge [-1, -(3k+4)] + +[route] +layers = -1,-7 + +# Transition last + +# 10 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=mish + + +# P2 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=2 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=mish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=mish + +# Merge [-1, -(3k+4)] + +[route] +layers = -1,-13 + +# Transition last + +# 26 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + + +# P3 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=2 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +# Merge [-1, -(3k+4)] + +[route] +layers = -1,-49 + +# Transition last + +# 78 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + + +# P4 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=2 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +# Merge [-1, -(3k+4)] + +[route] +layers = -1,-49 + +# Transition last + +# 130 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + + +# P5 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=2 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +# Merge [-1, -(3k+4)] + +[route] +layers = -1,-25 + +# Transition last + +# 158 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=1024 +size=1 +stride=1 +pad=1 +activation=mish + + +# P6 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=2 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +# Merge [-1, -(3k+4)] + +[route] +layers = -1,-25 + +# Transition last + +# 186 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=1024 +size=1 +stride=1 +pad=1 +activation=mish + +# ============ End of Backbone ============ # + +# ============ Neck ============ # + +# CSPSPP + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 +### End SPP ### + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=mish + +[route] +layers = -1, -13 + +# 201 (previous+6+5+2k) +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +# End of CSPSPP + + +# FPN-5 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[upsample] +stride=2 + +[route] +layers = 158 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=mish + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 217 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + + +# FPN-4 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[upsample] +stride=2 + +[route] +layers = 130 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=mish + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 233 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + + +# FPN-3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[upsample] +stride=2 + +[route] +layers = 78 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=128 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=128 +activation=mish + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=128 +activation=mish + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 249 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=mish + + +# PAN-4 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=256 +activation=mish + +[route] +layers = -1, 233 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=mish + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=mish + +[route] +layers = -1,-8 + +# Transition last + +# 262 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=mish + + +# PAN-5 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=512 +activation=mish + +[route] +layers = -1, 217 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=mish + +[route] +layers = -1,-8 + +# Transition last + +# 275 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + + +# PAN-6 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=512 +activation=mish + +[route] +layers = -1, 201 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=mish + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=mish + +[route] +layers = -1,-8 + +# Transition last + +# 288 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=mish + +# ============ End of Neck ============ # + +# ============ Head ============ # + +# YOLO-3 + +[route] +layers = 249 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=mish + +[convolutional] +size=1 +stride=1 +pad=1 +filters=340 +activation=linear + +[yolo] +mask = 0,1,2,3 +anchors = 13,17, 31,25, 24,51, 61,45, 61,45, 48,102, 119,96, 97,189, 97,189, 217,184, 171,384, 324,451, 324,451, 545,357, 616,618, 1024,1024 +classes=80 +num=16 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-4 + +[route] +layers = 262 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=mish + +[convolutional] +size=1 +stride=1 +pad=1 +filters=340 +activation=linear + +[yolo] +mask = 4,5,6,7 +anchors = 13,17, 31,25, 24,51, 61,45, 61,45, 48,102, 119,96, 97,189, 97,189, 217,184, 171,384, 324,451, 324,451, 545,357, 616,618, 1024,1024 +classes=80 +num=16 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-5 + +[route] +layers = 275 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=mish + +[convolutional] +size=1 +stride=1 +pad=1 +filters=340 +activation=linear + +[yolo] +mask = 8,9,10,11 +anchors = 13,17, 31,25, 24,51, 61,45, 61,45, 48,102, 119,96, 97,189, 97,189, 217,184, 171,384, 324,451, 324,451, 545,357, 616,618, 1024,1024 +classes=80 +num=16 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-6 + +[route] +layers = 288 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=mish + +[convolutional] +size=1 +stride=1 +pad=1 +filters=340 +activation=linear + +[yolo] +mask = 12,13,14,15 +anchors = 13,17, 31,25, 24,51, 61,45, 61,45, 48,102, 119,96, 97,189, 97,189, 217,184, 171,384, 324,451, 324,451, 545,357, 616,618, 1024,1024 +classes=80 +num=16 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + +# ============ End of Head ============ # diff --git a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov4_p7.cfg b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov4_p7.cfg index 18cea793b0..10379a0e75 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov4_p7.cfg +++ b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov4_p7.cfg @@ -1,2714 +1,2714 @@ -[net] -batch=64 -subdivisions=8 -width=1536 -height=1536 -channels=3 -momentum=0.949 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.00261 -burn_in=1000 -max_batches = 500500 -policy=steps -steps=400000,450000 -scales=.1,.1 - -mosaic=1 - - -# ============ Backbone ============ # - -# Stem - -# 0 -[convolutional] -batch_normalize=1 -filters=40 -size=3 -stride=1 -pad=1 -activation=mish - - -# P1 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=80 -size=3 -stride=2 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=40 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=40 -size=1 -stride=1 -pad=1 -activation=mish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=40 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=40 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=40 -size=1 -stride=1 -pad=1 -activation=mish - -# Merge [-1, -(3k+4)] - -[route] -layers = -1,-7 - -# Transition last - -# 10 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=mish - - -# P2 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=2 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=mish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=80 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=80 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=80 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=mish - -# Merge [-1, -(3k+4)] - -[route] -layers = -1,-13 - -# Transition last - -# 26 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - - -# P3 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=2 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -# Merge [-1, -(3k+4)] - -[route] -layers = -1,-49 - -# Transition last - -# 78 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - - -# P4 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=2 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -# Merge [-1, -(3k+4)] - -[route] -layers = -1,-49 - -# Transition last - -# 130 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - - -# P5 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1280 -size=3 -stride=2 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -# Merge [-1, -(3k+4)] - -[route] -layers = -1,-25 - -# Transition last - -# 158 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=1280 -size=1 -stride=1 -pad=1 -activation=mish - - -# P6 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1280 -size=3 -stride=2 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -# Merge [-1, -(3k+4)] - -[route] -layers = -1,-25 - -# Transition last - -# 186 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=1280 -size=1 -stride=1 -pad=1 -activation=mish - - -# P7 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1280 -size=3 -stride=2 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=mish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -# Merge [-1, -(3k+4)] - -[route] -layers = -1,-25 - -# Transition last - -# 214 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=1280 -size=1 -stride=1 -pad=1 -activation=mish - -# ============ End of Backbone ============ # - -# ============ Neck ============ # - -# CSPSPP - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=mish - -[route] -layers = -1, -13 - -# 229 (previous+6+5+2k) -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -# End of CSPSPP - - -# FPN-6 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[upsample] -stride=2 - -[route] -layers = 186 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=mish - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 245 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - - -# FPN-5 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[upsample] -stride=2 - -[route] -layers = 158 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=mish - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 261 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - - -# FPN-4 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[upsample] -stride=2 - -[route] -layers = 130 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=mish - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=mish - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=mish - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 277 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - - -# FPN-3 - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[upsample] -stride=2 - -[route] -layers = 78 - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=160 -activation=mish - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=160 -activation=mish - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=160 -activation=mish - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 293 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=mish - - -# PAN-4 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=320 -activation=mish - -[route] -layers = -1, 277 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=mish - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=mish - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=mish - -[route] -layers = -1,-8 - -# Transition last - -# 306 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=mish - - -# PAN-5 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=640 -activation=mish - -[route] -layers = -1, 261 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=mish - -[route] -layers = -1,-8 - -# Transition last - -# 319 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - - -# PAN-6 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=640 -activation=mish - -[route] -layers = -1, 245 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=mish - -[route] -layers = -1,-8 - -# Transition last - -# 332 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - - -# PAN-7 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=640 -activation=mish - -[route] -layers = -1, 229 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -# Split - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=mish - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=mish - -[route] -layers = -1,-8 - -# Transition last - -# 345 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=mish - -# ============ End of Neck ============ # - -# ============ Head ============ # - -# YOLO-3 - -[route] -layers = 293 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=mish - -[convolutional] -size=1 -stride=1 -pad=1 -filters=340 -activation=linear - -[yolo] -mask = 0,1,2,3 -anchors = 13,17, 22,25, 27,66, 55,41, 57,88, 112,69, 69,177, 136,138, 136,138, 287,114, 134,275, 268,248, 268,248, 232,504, 445,416, 640,640, 812,393, 477,808, 1070,908, 1408,1408 -classes=80 -num=20 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-4 - -[route] -layers = 306 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=mish - -[convolutional] -size=1 -stride=1 -pad=1 -filters=340 -activation=linear - -[yolo] -mask = 4,5,6,7 -anchors = 13,17, 22,25, 27,66, 55,41, 57,88, 112,69, 69,177, 136,138, 136,138, 287,114, 134,275, 268,248, 268,248, 232,504, 445,416, 640,640, 812,393, 477,808, 1070,908, 1408,1408 -classes=80 -num=20 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-5 - -[route] -layers = 319 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1280 -activation=mish - -[convolutional] -size=1 -stride=1 -pad=1 -filters=340 -activation=linear - -[yolo] -mask = 8,9,10,11 -anchors = 13,17, 22,25, 27,66, 55,41, 57,88, 112,69, 69,177, 136,138, 136,138, 287,114, 134,275, 268,248, 268,248, 232,504, 445,416, 640,640, 812,393, 477,808, 1070,908, 1408,1408 -classes=80 -num=20 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-6 - -[route] -layers = 332 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1280 -activation=mish - -[convolutional] -size=1 -stride=1 -pad=1 -filters=340 -activation=linear - -[yolo] -mask = 12,13,14,15 -anchors = 13,17, 22,25, 27,66, 55,41, 57,88, 112,69, 69,177, 136,138, 136,138, 287,114, 134,275, 268,248, 268,248, 232,504, 445,416, 640,640, 812,393, 477,808, 1070,908, 1408,1408 -classes=80 -num=20 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - - -# YOLO-7 - -[route] -layers = 345 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1280 -activation=mish - -[convolutional] -size=1 -stride=1 -pad=1 -filters=340 -activation=linear - -[yolo] -mask = 16,17,18,19 -anchors = 13,17, 22,25, 27,66, 55,41, 57,88, 112,69, 69,177, 136,138, 136,138, 287,114, 134,275, 268,248, 268,248, 232,504, 445,416, 640,640, 812,393, 477,808, 1070,908, 1408,1408 -classes=80 -num=20 -jitter=.3 -ignore_thresh = .7 -truth_thresh = 1 -random=1 -scale_x_y = 1.05 -iou_thresh=0.213 -cls_normalizer=1.0 -iou_normalizer=0.07 -iou_loss=ciou -nms_kind=greedynms -beta_nms=0.6 - -# ============ End of Head ============ # +[net] +batch=64 +subdivisions=8 +width=1536 +height=1536 +channels=3 +momentum=0.949 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.00261 +burn_in=1000 +max_batches = 500500 +policy=steps +steps=400000,450000 +scales=.1,.1 + +mosaic=1 + + +# ============ Backbone ============ # + +# Stem + +# 0 +[convolutional] +batch_normalize=1 +filters=40 +size=3 +stride=1 +pad=1 +activation=mish + + +# P1 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=80 +size=3 +stride=2 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=40 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=40 +size=1 +stride=1 +pad=1 +activation=mish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=40 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=40 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=40 +size=1 +stride=1 +pad=1 +activation=mish + +# Merge [-1, -(3k+4)] + +[route] +layers = -1,-7 + +# Transition last + +# 10 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=mish + + +# P2 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=2 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=mish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=80 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=80 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=80 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=mish + +# Merge [-1, -(3k+4)] + +[route] +layers = -1,-13 + +# Transition last + +# 26 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + + +# P3 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=2 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +# Merge [-1, -(3k+4)] + +[route] +layers = -1,-49 + +# Transition last + +# 78 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + + +# P4 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=2 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +# Merge [-1, -(3k+4)] + +[route] +layers = -1,-49 + +# Transition last + +# 130 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + + +# P5 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=1280 +size=3 +stride=2 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +# Merge [-1, -(3k+4)] + +[route] +layers = -1,-25 + +# Transition last + +# 158 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=1280 +size=1 +stride=1 +pad=1 +activation=mish + + +# P6 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=1280 +size=3 +stride=2 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +# Merge [-1, -(3k+4)] + +[route] +layers = -1,-25 + +# Transition last + +# 186 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=1280 +size=1 +stride=1 +pad=1 +activation=mish + + +# P7 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=1280 +size=3 +stride=2 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=mish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +# Merge [-1, -(3k+4)] + +[route] +layers = -1,-25 + +# Transition last + +# 214 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=1280 +size=1 +stride=1 +pad=1 +activation=mish + +# ============ End of Backbone ============ # + +# ============ Neck ============ # + +# CSPSPP + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 +### End SPP ### + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=mish + +[route] +layers = -1, -13 + +# 229 (previous+6+5+2k) +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +# End of CSPSPP + + +# FPN-6 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[upsample] +stride=2 + +[route] +layers = 186 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=mish + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 245 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + + +# FPN-5 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[upsample] +stride=2 + +[route] +layers = 158 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=mish + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 261 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + + +# FPN-4 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[upsample] +stride=2 + +[route] +layers = 130 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=mish + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=mish + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=mish + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 277 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + + +# FPN-3 + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[upsample] +stride=2 + +[route] +layers = 78 + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=160 +activation=mish + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=160 +activation=mish + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=160 +activation=mish + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 293 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=mish + + +# PAN-4 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=320 +activation=mish + +[route] +layers = -1, 277 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=mish + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=mish + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=mish + +[route] +layers = -1,-8 + +# Transition last + +# 306 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=mish + + +# PAN-5 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=640 +activation=mish + +[route] +layers = -1, 261 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=mish + +[route] +layers = -1,-8 + +# Transition last + +# 319 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + + +# PAN-6 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=640 +activation=mish + +[route] +layers = -1, 245 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=mish + +[route] +layers = -1,-8 + +# Transition last + +# 332 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + + +# PAN-7 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=640 +activation=mish + +[route] +layers = -1, 229 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +# Split + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=mish + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=mish + +[route] +layers = -1,-8 + +# Transition last + +# 345 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=mish + +# ============ End of Neck ============ # + +# ============ Head ============ # + +# YOLO-3 + +[route] +layers = 293 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=mish + +[convolutional] +size=1 +stride=1 +pad=1 +filters=340 +activation=linear + +[yolo] +mask = 0,1,2,3 +anchors = 13,17, 22,25, 27,66, 55,41, 57,88, 112,69, 69,177, 136,138, 136,138, 287,114, 134,275, 268,248, 268,248, 232,504, 445,416, 640,640, 812,393, 477,808, 1070,908, 1408,1408 +classes=80 +num=20 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-4 + +[route] +layers = 306 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=mish + +[convolutional] +size=1 +stride=1 +pad=1 +filters=340 +activation=linear + +[yolo] +mask = 4,5,6,7 +anchors = 13,17, 22,25, 27,66, 55,41, 57,88, 112,69, 69,177, 136,138, 136,138, 287,114, 134,275, 268,248, 268,248, 232,504, 445,416, 640,640, 812,393, 477,808, 1070,908, 1408,1408 +classes=80 +num=20 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-5 + +[route] +layers = 319 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1280 +activation=mish + +[convolutional] +size=1 +stride=1 +pad=1 +filters=340 +activation=linear + +[yolo] +mask = 8,9,10,11 +anchors = 13,17, 22,25, 27,66, 55,41, 57,88, 112,69, 69,177, 136,138, 136,138, 287,114, 134,275, 268,248, 268,248, 232,504, 445,416, 640,640, 812,393, 477,808, 1070,908, 1408,1408 +classes=80 +num=20 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-6 + +[route] +layers = 332 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1280 +activation=mish + +[convolutional] +size=1 +stride=1 +pad=1 +filters=340 +activation=linear + +[yolo] +mask = 12,13,14,15 +anchors = 13,17, 22,25, 27,66, 55,41, 57,88, 112,69, 69,177, 136,138, 136,138, 287,114, 134,275, 268,248, 268,248, 232,504, 445,416, 640,640, 812,393, 477,808, 1070,908, 1408,1408 +classes=80 +num=20 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + + +# YOLO-7 + +[route] +layers = 345 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1280 +activation=mish + +[convolutional] +size=1 +stride=1 +pad=1 +filters=340 +activation=linear + +[yolo] +mask = 16,17,18,19 +anchors = 13,17, 22,25, 27,66, 55,41, 57,88, 112,69, 69,177, 136,138, 136,138, 287,114, 134,275, 268,248, 268,248, 232,504, 445,416, 640,640, 812,393, 477,808, 1070,908, 1408,1408 +classes=80 +num=20 +jitter=.3 +ignore_thresh = .7 +truth_thresh = 1 +random=1 +scale_x_y = 1.05 +iou_thresh=0.213 +cls_normalizer=1.0 +iou_normalizer=0.07 +iou_loss=ciou +nms_kind=greedynms +beta_nms=0.6 + +# ============ End of Head ============ # diff --git a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov5x.cfg b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov5x.cfg index 1c62dc4b19..c06c663f2c 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov5x.cfg +++ b/PyTorch/contrib/cv/detection/YOLOR/cfg/yolov5x.cfg @@ -1,43 +1,43 @@ -nc: 80 -depth_multiple: 1.33 -width_multiple: 1.25 - -anchors: - - [10,13, 16,30 33,23] - - [30,61, 62,45, 59,119] - - [116,90, 156,198, 373,326] - -backbone: - [[-1, 1, Focus, [64,3]], - [-1, 1, Conv, [128, 3, 2]], - [-1, 3, BottleneckCSP, [128]], - [-1, 1, Conv, [256, 3, 2]], - [-1, 3, BottleneckCSP, [256]], - [-1, 1, Conv, [512, 3, 2]], - [-1, 3, BottleneckCSP, [512]], - [-1, 1, Conv, [1024, 3, 2]], - [-1, 1, SPP, [1024, [5, 9, 13]]], - [-1, 3, BottleneckCSP, [1024, False]], - ] - -head: - [[-1, 1, Conv, [512, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 6], 1, Concat, [1]], - [-1, 3, BottleneckCSP, [512, False]], - - [-1, 1, Conv, [256, 1, 1]], - [-1, 1, nn.Upsample, [None, 2, 'nearest']], - [[-1, 4], 1, Concat, [1]], - [-1, 3, BottleneckCSP, [256, False]], - - [-1, 1, Conv, [256, 3, 2]], - [[-1, 14], 1, Concat, [1]], - [-1, 3, BottleneckCSP, [512, False]], - - [-1, 1, Conv, [512, 3, 2]], - [[-1, 10], 1, Concat, [1]], - [-1, 3, BottleneckCSP, [1024, False]], - - [[17, 20, 23], 1, Detect, [nc, anchors]], - ] +nc: 80 +depth_multiple: 1.33 +width_multiple: 1.25 + +anchors: + - [10,13, 16,30 33,23] + - [30,61, 62,45, 59,119] + - [116,90, 156,198, 373,326] + +backbone: + [[-1, 1, Focus, [64,3]], + [-1, 1, Conv, [128, 3, 2]], + [-1, 3, BottleneckCSP, [128]], + [-1, 1, Conv, [256, 3, 2]], + [-1, 3, BottleneckCSP, [256]], + [-1, 1, Conv, [512, 3, 2]], + [-1, 3, BottleneckCSP, [512]], + [-1, 1, Conv, [1024, 3, 2]], + [-1, 1, SPP, [1024, [5, 9, 13]]], + [-1, 3, BottleneckCSP, [1024, False]], + ] + +head: + [[-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], + [-1, 3, BottleneckCSP, [512, False]], + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], + [-1, 3, BottleneckCSP, [256, False]], + + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], + [-1, 3, BottleneckCSP, [512, False]], + + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], + [-1, 3, BottleneckCSP, [1024, False]], + + [[17, 20, 23], 1, Detect, [nc, anchors]], + ] diff --git a/PyTorch/contrib/cv/detection/YOLOR/darknet/README.md b/PyTorch/contrib/cv/detection/YOLOR/darknet/README.md index 1d3d11e054..d2fc579741 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/darknet/README.md +++ b/PyTorch/contrib/cv/detection/YOLOR/darknet/README.md @@ -1,63 +1,63 @@ -## Model Zoo - -| Model | Test Size | APval | AP50val | AP75val | APSval | APMval | APLval | batch1 throughput | -| :-- | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | -| **YOLOv4-CSP** | 640 | **49.1%** | **67.7%** | **53.8%** | **32.1%** | **54.4%** | **63.2%** | 76 *fps* | -| **YOLOR-CSP** | 640 | **49.2%** | **67.6%** | **53.7%** | **32.9%** | **54.4%** | **63.0%** | - | -| | | | | | | | -| **YOLOv4-CSP-X** | 640 | **50.9%** | **69.3%** | **55.4%** | **35.3%** | **55.8%** | **64.8%** | 53 *fps* | -| **YOLOR-CSP-X** | 640 | **51.1%** | **69.6%** | **55.7%** | **35.7%** | **56.0%** | **65.2%** | - | -| | | | | | | | - -## Installation - -https://github.com/AlexeyAB/darknet - -Docker environment (recommended) -
Expand - -``` -# get code -git clone https://github.com/AlexeyAB/darknet - -# create the docker container, you can change the share memory size if you have more. -nvidia-docker run --name yolor -it -v your_coco_path/:/coco/ -v your_code_path/:/yolor --shm-size=64g nvcr.io/nvidia/pytorch:21.02-py3 - -# apt install required packages -apt update -apt install -y libopencv-dev - -# edit Makefile -#GPU=1 -#CUDNN=1 -#CUDNN_HALF=1 -#OPENCV=1 -#AVX=1 -#OPENMP=1 -#LIBSO=1 -#ZED_CAMERA=0 -#ZED_CAMERA_v2_8=0 -# -#USE_CPP=0 -#DEBUG=0 -# -#ARCH= -gencode arch=compute_52,code=[sm_70,compute_70] \ -# -gencode arch=compute_61,code=[sm_75,compute_75] \ -# -gencode arch=compute_61,code=[sm_80,compute_80] \ -# -gencode arch=compute_61,code=[sm_86,compute_86] -# -#... - -# build -make -j8 -``` - -
- -## Testing - -To reproduce inference speed, using: - -``` -CUDA_VISIBLE_DEVICES=0 ./darknet detector demo cfg/coco.data cfg/yolov4-csp.cfg weights/yolov4-csp.weights source/test.mp4 -dont_show -benchmark -``` +## Model Zoo + +| Model | Test Size | APval | AP50val | AP75val | APSval | APMval | APLval | batch1 throughput | +| :-- | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | +| **YOLOv4-CSP** | 640 | **49.1%** | **67.7%** | **53.8%** | **32.1%** | **54.4%** | **63.2%** | 76 *fps* | +| **YOLOR-CSP** | 640 | **49.2%** | **67.6%** | **53.7%** | **32.9%** | **54.4%** | **63.0%** | - | +| | | | | | | | +| **YOLOv4-CSP-X** | 640 | **50.9%** | **69.3%** | **55.4%** | **35.3%** | **55.8%** | **64.8%** | 53 *fps* | +| **YOLOR-CSP-X** | 640 | **51.1%** | **69.6%** | **55.7%** | **35.7%** | **56.0%** | **65.2%** | - | +| | | | | | | | + +## Installation + +https://github.com/AlexeyAB/darknet + +Docker environment (recommended) +
Expand + +``` +# get code +git clone https://github.com/AlexeyAB/darknet + +# create the docker container, you can change the share memory size if you have more. +nvidia-docker run --name yolor -it -v your_coco_path/:/coco/ -v your_code_path/:/yolor --shm-size=64g nvcr.io/nvidia/pytorch:21.02-py3 + +# apt install required packages +apt update +apt install -y libopencv-dev + +# edit Makefile +#GPU=1 +#CUDNN=1 +#CUDNN_HALF=1 +#OPENCV=1 +#AVX=1 +#OPENMP=1 +#LIBSO=1 +#ZED_CAMERA=0 +#ZED_CAMERA_v2_8=0 +# +#USE_CPP=0 +#DEBUG=0 +# +#ARCH= -gencode arch=compute_52,code=[sm_70,compute_70] \ +# -gencode arch=compute_61,code=[sm_75,compute_75] \ +# -gencode arch=compute_61,code=[sm_80,compute_80] \ +# -gencode arch=compute_61,code=[sm_86,compute_86] +# +#... + +# build +make -j8 +``` + +
+ +## Testing + +To reproduce inference speed, using: + +``` +CUDA_VISIBLE_DEVICES=0 ./darknet detector demo cfg/coco.data cfg/yolov4-csp.cfg weights/yolov4-csp.weights source/test.mp4 -dont_show -benchmark +``` diff --git a/PyTorch/contrib/cv/detection/YOLOR/darknet/cfg/yolov4-csp-x.cfg b/PyTorch/contrib/cv/detection/YOLOR/darknet/cfg/yolov4-csp-x.cfg index cdb71565ac..e7acf9ef4e 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/darknet/cfg/yolov4-csp-x.cfg +++ b/PyTorch/contrib/cv/detection/YOLOR/darknet/cfg/yolov4-csp-x.cfg @@ -1,1555 +1,1555 @@ - -[net] -# Testing -#batch=1 -#subdivisions=1 -# Training -batch=64 -subdivisions=8 -width=640 -height=640 -channels=3 -momentum=0.949 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 500500 -policy=steps -steps=400000,450000 -scales=.1,.1 - -mosaic=1 - -letter_box=1 - -ema_alpha=0.9998 - -#optimized_memory=1 - - -# ============ Backbone ============ # - -# Stem - -# 0 -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=swish - -# P1 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=80 -size=3 -stride=2 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=40 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=80 -size=3 -stride=1 -pad=1 -activation=swish - -# 4 (previous+1+3k) -[shortcut] -from=-3 -activation=linear - -# P2 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=2 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=80 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=80 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=80 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=80 -size=1 -stride=1 -pad=1 -activation=swish - -# Merge [-1, -(3k+4)] - -[route] -layers = -1,-13 - -# Transition last - -# 20 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -# P3 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=2 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=160 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -# Merge [-1 -(4+3k)] - -[route] -layers = -1,-34 - -# Transition last - -# 57 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -# P4 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=2 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -# Merge [-1 -(3k+4)] - -[route] -layers = -1,-34 - -# Transition last - -# 94 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -# P5 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1280 -size=3 -stride=2 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=640 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -# Merge [-1 -(3k+4)] - -[route] -layers = -1,-19 - -# Transition last - -# 116 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=1280 -size=1 -stride=1 -pad=1 -activation=swish - -# ============ End of Backbone ============ # - -# ============ Neck ============ # - -# CSPSPP - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=swish - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=swish - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=swish - -[route] -layers = -1, -15 - -# 133 (previous+6+5+2k) -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -# End of CSPSPP - - -# FPN-4 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[upsample] -stride=2 - -[route] -layers = 94 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=swish - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 149 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - - -# FPN-3 - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -[upsample] -stride=2 - -[route] -layers = 57 - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=160 -activation=swish - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=160 -activation=swish - -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=160 -activation=swish - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -8 - -# Transition last - -# 165 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=160 -size=1 -stride=1 -pad=1 -activation=swish - - -# PAN-4 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=320 -activation=swish - -[route] -layers = -1, 149 - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=swish - -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=swish - -[route] -layers = -1,-8 - -# Transition last - -# 178 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=320 -size=1 -stride=1 -pad=1 -activation=swish - - -# PAN-5 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=640 -activation=swish - -[route] -layers = -1, 133 - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=swish - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=swish - -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=swish - -[route] -layers = -1,-8 - -# Transition last - -# 191 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=640 -size=1 -stride=1 -pad=1 -activation=swish - -# ============ End of Neck ============ # - -# ============ Head ============ # - -# YOLO-3 - -[route] -layers = 165 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=320 -activation=swish - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=logistic - -[yolo] -mask = 0,1,2 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.1 -scale_x_y = 2.0 -objectness_smooth=1 -ignore_thresh = .7 -truth_thresh = 1 -#random=1 -resize=1.5 -iou_thresh=0.2 -iou_normalizer=0.05 -cls_normalizer=0.5 -obj_normalizer=0.4 -iou_loss=ciou -nms_kind=diounms -beta_nms=0.6 -new_coords=1 -max_delta=2 - - -# YOLO-4 - -[route] -layers = 178 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=640 -activation=swish - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=logistic - -[yolo] -mask = 3,4,5 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.1 -scale_x_y = 2.0 -objectness_smooth=1 -ignore_thresh = .7 -truth_thresh = 1 -#random=1 -resize=1.5 -iou_thresh=0.2 -iou_normalizer=0.05 -cls_normalizer=0.5 -obj_normalizer=0.4 -iou_loss=ciou -nms_kind=diounms -beta_nms=0.6 -new_coords=1 -max_delta=2 - - -# YOLO-5 - -[route] -layers = 191 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1280 -activation=swish - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=logistic - -[yolo] -mask = 6,7,8 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.1 -scale_x_y = 2.0 -objectness_smooth=1 -ignore_thresh = .7 -truth_thresh = 1 -#random=1 -resize=1.5 -iou_thresh=0.2 -iou_normalizer=0.05 -cls_normalizer=0.5 -obj_normalizer=0.4 -iou_loss=ciou -nms_kind=diounms -beta_nms=0.6 -new_coords=1 -max_delta=2 + +[net] +# Testing +#batch=1 +#subdivisions=1 +# Training +batch=64 +subdivisions=8 +width=640 +height=640 +channels=3 +momentum=0.949 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.001 +burn_in=1000 +max_batches = 500500 +policy=steps +steps=400000,450000 +scales=.1,.1 + +mosaic=1 + +letter_box=1 + +ema_alpha=0.9998 + +#optimized_memory=1 + + +# ============ Backbone ============ # + +# Stem + +# 0 +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=swish + +# P1 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=80 +size=3 +stride=2 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=40 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=80 +size=3 +stride=1 +pad=1 +activation=swish + +# 4 (previous+1+3k) +[shortcut] +from=-3 +activation=linear + +# P2 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=2 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=80 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=80 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=80 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=80 +size=1 +stride=1 +pad=1 +activation=swish + +# Merge [-1, -(3k+4)] + +[route] +layers = -1,-13 + +# Transition last + +# 20 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +# P3 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=2 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=160 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +# Merge [-1 -(4+3k)] + +[route] +layers = -1,-34 + +# Transition last + +# 57 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +# P4 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=2 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +# Merge [-1 -(3k+4)] + +[route] +layers = -1,-34 + +# Transition last + +# 94 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +# P5 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=1280 +size=3 +stride=2 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=640 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +# Merge [-1 -(3k+4)] + +[route] +layers = -1,-19 + +# Transition last + +# 116 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=1280 +size=1 +stride=1 +pad=1 +activation=swish + +# ============ End of Backbone ============ # + +# ============ Neck ============ # + +# CSPSPP + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=swish + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 +### End SPP ### + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=swish + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=swish + +[route] +layers = -1, -15 + +# 133 (previous+6+5+2k) +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +# End of CSPSPP + + +# FPN-4 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[upsample] +stride=2 + +[route] +layers = 94 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=swish + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 149 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + + +# FPN-3 + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +[upsample] +stride=2 + +[route] +layers = 57 + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=160 +activation=swish + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=160 +activation=swish + +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=160 +activation=swish + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -8 + +# Transition last + +# 165 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=160 +size=1 +stride=1 +pad=1 +activation=swish + + +# PAN-4 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=320 +activation=swish + +[route] +layers = -1, 149 + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=swish + +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=swish + +[route] +layers = -1,-8 + +# Transition last + +# 178 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=320 +size=1 +stride=1 +pad=1 +activation=swish + + +# PAN-5 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=640 +activation=swish + +[route] +layers = -1, 133 + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=swish + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=swish + +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=swish + +[route] +layers = -1,-8 + +# Transition last + +# 191 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=640 +size=1 +stride=1 +pad=1 +activation=swish + +# ============ End of Neck ============ # + +# ============ Head ============ # + +# YOLO-3 + +[route] +layers = 165 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=320 +activation=swish + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=logistic + +[yolo] +mask = 0,1,2 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.1 +scale_x_y = 2.0 +objectness_smooth=1 +ignore_thresh = .7 +truth_thresh = 1 +#random=1 +resize=1.5 +iou_thresh=0.2 +iou_normalizer=0.05 +cls_normalizer=0.5 +obj_normalizer=0.4 +iou_loss=ciou +nms_kind=diounms +beta_nms=0.6 +new_coords=1 +max_delta=2 + + +# YOLO-4 + +[route] +layers = 178 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=640 +activation=swish + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=logistic + +[yolo] +mask = 3,4,5 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.1 +scale_x_y = 2.0 +objectness_smooth=1 +ignore_thresh = .7 +truth_thresh = 1 +#random=1 +resize=1.5 +iou_thresh=0.2 +iou_normalizer=0.05 +cls_normalizer=0.5 +obj_normalizer=0.4 +iou_loss=ciou +nms_kind=diounms +beta_nms=0.6 +new_coords=1 +max_delta=2 + + +# YOLO-5 + +[route] +layers = 191 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1280 +activation=swish + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=logistic + +[yolo] +mask = 6,7,8 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.1 +scale_x_y = 2.0 +objectness_smooth=1 +ignore_thresh = .7 +truth_thresh = 1 +#random=1 +resize=1.5 +iou_thresh=0.2 +iou_normalizer=0.05 +cls_normalizer=0.5 +obj_normalizer=0.4 +iou_loss=ciou +nms_kind=diounms +beta_nms=0.6 +new_coords=1 +max_delta=2 diff --git a/PyTorch/contrib/cv/detection/YOLOR/darknet/cfg/yolov4-csp.cfg b/PyTorch/contrib/cv/detection/YOLOR/darknet/cfg/yolov4-csp.cfg index fd1bdc6bdc..a47c9f7160 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/darknet/cfg/yolov4-csp.cfg +++ b/PyTorch/contrib/cv/detection/YOLOR/darknet/cfg/yolov4-csp.cfg @@ -1,1354 +1,1354 @@ -[net] -# Testing -#batch=1 -#subdivisions=1 -# Training -batch=64 -subdivisions=8 -width=640 -height=640 -channels=3 -momentum=0.949 -decay=0.0005 -angle=0 -saturation = 1.5 -exposure = 1.5 -hue=.1 - -learning_rate=0.001 -burn_in=1000 -max_batches = 500500 -policy=steps -steps=400000,450000 -scales=.1,.1 - -mosaic=1 - -letter_box=1 - -ema_alpha=0.9998 - -#optimized_memory=1 - - -# ============ Backbone ============ # - -# Stem - -# 0 -[convolutional] -batch_normalize=1 -filters=32 -size=3 -stride=1 -pad=1 -activation=swish - -# P1 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=2 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=32 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=swish - -# 4 (previous+1+3k) -[shortcut] -from=-3 -activation=linear - -# P2 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=2 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=64 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=64 -size=1 -stride=1 -pad=1 -activation=swish - -# Merge [-1, -(3k+4)] - -[route] -layers = -1,-10 - -# Transition last - -# 17 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -# P3 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=2 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -# Merge [-1 -(4+3k)] - -[route] -layers = -1,-28 - -# Transition last - -# 48 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -# P4 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=2 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -# Merge [-1 -(3k+4)] - -[route] -layers = -1,-28 - -# Transition last - -# 79 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - -# P5 - -# Downsample - -[convolutional] -batch_normalize=1 -filters=1024 -size=3 -stride=2 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - -# Residual Block - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -filters=512 -size=3 -stride=1 -pad=1 -activation=swish - -[shortcut] -from=-3 -activation=linear - -# Transition first - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - -# Merge [-1 -(3k+4)] - -[route] -layers = -1,-16 - -# Transition last - -# 98 (previous+7+3k) -[convolutional] -batch_normalize=1 -filters=1024 -size=1 -stride=1 -pad=1 -activation=swish - -# ============ End of Backbone ============ # - -# ============ Neck ============ # - -# CSPSPP - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=swish - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - -### SPP ### -[maxpool] -stride=1 -size=5 - -[route] -layers=-2 - -[maxpool] -stride=1 -size=9 - -[route] -layers=-4 - -[maxpool] -stride=1 -size=13 - -[route] -layers=-1,-3,-5,-6 -### End SPP ### - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=swish - -[route] -layers = -1, -13 - -# 113 (previous+6+5+2k) -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - -# End of CSPSPP - - -# FPN-4 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[upsample] -stride=2 - -[route] -layers = 79 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=swish - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -6 - -# Transition last - -# 127 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - - -# FPN-3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[upsample] -stride=2 - -[route] -layers = 48 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -1, -3 - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=128 -activation=swish - -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=128 -activation=swish - -# Merge [-1, -(2k+2)] - -[route] -layers = -1, -6 - -# Transition last - -# 141 (previous+6+4+2k) -[convolutional] -batch_normalize=1 -filters=128 -size=1 -stride=1 -pad=1 -activation=swish - - -# PAN-4 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=256 -activation=swish - -[route] -layers = -1, 127 - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=swish - -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=swish - -[route] -layers = -1,-6 - -# Transition last - -# 152 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=256 -size=1 -stride=1 -pad=1 -activation=swish - - -# PAN-5 - -[convolutional] -batch_normalize=1 -size=3 -stride=2 -pad=1 -filters=512 -activation=swish - -[route] -layers = -1, 113 - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - -# Split - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - -[route] -layers = -2 - -# Plain Block - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=swish - -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=swish - -[route] -layers = -1,-6 - -# Transition last - -# 163 (previous+3+4+2k) -[convolutional] -batch_normalize=1 -filters=512 -size=1 -stride=1 -pad=1 -activation=swish - -# ============ End of Neck ============ # - -# ============ Head ============ # - -# YOLO-3 - -[route] -layers = 141 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=256 -activation=swish - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=logistic - -[yolo] -mask = 0,1,2 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.1 -scale_x_y = 2.0 -objectness_smooth=1 -ignore_thresh = .7 -truth_thresh = 1 -#random=1 -resize=1.5 -iou_thresh=0.2 -iou_normalizer=0.05 -cls_normalizer=0.5 -obj_normalizer=0.4 -iou_loss=ciou -nms_kind=diounms -beta_nms=0.6 -new_coords=1 -max_delta=2 - - -# YOLO-4 - -[route] -layers = 152 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=512 -activation=swish - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=logistic - -[yolo] -mask = 3,4,5 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.1 -scale_x_y = 2.0 -objectness_smooth=1 -ignore_thresh = .7 -truth_thresh = 1 -#random=1 -resize=1.5 -iou_thresh=0.2 -iou_normalizer=0.05 -cls_normalizer=0.5 -obj_normalizer=0.4 -iou_loss=ciou -nms_kind=diounms -beta_nms=0.6 -new_coords=1 -max_delta=2 - - -# YOLO-5 - -[route] -layers = 163 - -[convolutional] -batch_normalize=1 -size=3 -stride=1 -pad=1 -filters=1024 -activation=swish - -[convolutional] -size=1 -stride=1 -pad=1 -filters=255 -activation=logistic - -[yolo] -mask = 6,7,8 -anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 -classes=80 -num=9 -jitter=.1 -scale_x_y = 2.0 -objectness_smooth=1 -ignore_thresh = .7 -truth_thresh = 1 -#random=1 -resize=1.5 -iou_thresh=0.2 -iou_normalizer=0.05 -cls_normalizer=0.5 -obj_normalizer=0.4 -iou_loss=ciou -nms_kind=diounms -beta_nms=0.6 -new_coords=1 -max_delta=2 +[net] +# Testing +#batch=1 +#subdivisions=1 +# Training +batch=64 +subdivisions=8 +width=640 +height=640 +channels=3 +momentum=0.949 +decay=0.0005 +angle=0 +saturation = 1.5 +exposure = 1.5 +hue=.1 + +learning_rate=0.001 +burn_in=1000 +max_batches = 500500 +policy=steps +steps=400000,450000 +scales=.1,.1 + +mosaic=1 + +letter_box=1 + +ema_alpha=0.9998 + +#optimized_memory=1 + + +# ============ Backbone ============ # + +# Stem + +# 0 +[convolutional] +batch_normalize=1 +filters=32 +size=3 +stride=1 +pad=1 +activation=swish + +# P1 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=2 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=32 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=swish + +# 4 (previous+1+3k) +[shortcut] +from=-3 +activation=linear + +# P2 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=2 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=64 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=64 +size=1 +stride=1 +pad=1 +activation=swish + +# Merge [-1, -(3k+4)] + +[route] +layers = -1,-10 + +# Transition last + +# 17 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +# P3 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=2 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +# Merge [-1 -(4+3k)] + +[route] +layers = -1,-28 + +# Transition last + +# 48 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +# P4 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=2 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +# Merge [-1 -(3k+4)] + +[route] +layers = -1,-28 + +# Transition last + +# 79 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + +# P5 + +# Downsample + +[convolutional] +batch_normalize=1 +filters=1024 +size=3 +stride=2 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + +# Residual Block + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +filters=512 +size=3 +stride=1 +pad=1 +activation=swish + +[shortcut] +from=-3 +activation=linear + +# Transition first + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + +# Merge [-1 -(3k+4)] + +[route] +layers = -1,-16 + +# Transition last + +# 98 (previous+7+3k) +[convolutional] +batch_normalize=1 +filters=1024 +size=1 +stride=1 +pad=1 +activation=swish + +# ============ End of Backbone ============ # + +# ============ Neck ============ # + +# CSPSPP + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=swish + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + +### SPP ### +[maxpool] +stride=1 +size=5 + +[route] +layers=-2 + +[maxpool] +stride=1 +size=9 + +[route] +layers=-4 + +[maxpool] +stride=1 +size=13 + +[route] +layers=-1,-3,-5,-6 +### End SPP ### + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=swish + +[route] +layers = -1, -13 + +# 113 (previous+6+5+2k) +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + +# End of CSPSPP + + +# FPN-4 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[upsample] +stride=2 + +[route] +layers = 79 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=swish + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -6 + +# Transition last + +# 127 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + + +# FPN-3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[upsample] +stride=2 + +[route] +layers = 48 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -1, -3 + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=128 +activation=swish + +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=128 +activation=swish + +# Merge [-1, -(2k+2)] + +[route] +layers = -1, -6 + +# Transition last + +# 141 (previous+6+4+2k) +[convolutional] +batch_normalize=1 +filters=128 +size=1 +stride=1 +pad=1 +activation=swish + + +# PAN-4 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=256 +activation=swish + +[route] +layers = -1, 127 + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=swish + +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=swish + +[route] +layers = -1,-6 + +# Transition last + +# 152 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=256 +size=1 +stride=1 +pad=1 +activation=swish + + +# PAN-5 + +[convolutional] +batch_normalize=1 +size=3 +stride=2 +pad=1 +filters=512 +activation=swish + +[route] +layers = -1, 113 + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + +# Split + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + +[route] +layers = -2 + +# Plain Block + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=swish + +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=swish + +[route] +layers = -1,-6 + +# Transition last + +# 163 (previous+3+4+2k) +[convolutional] +batch_normalize=1 +filters=512 +size=1 +stride=1 +pad=1 +activation=swish + +# ============ End of Neck ============ # + +# ============ Head ============ # + +# YOLO-3 + +[route] +layers = 141 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=256 +activation=swish + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=logistic + +[yolo] +mask = 0,1,2 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.1 +scale_x_y = 2.0 +objectness_smooth=1 +ignore_thresh = .7 +truth_thresh = 1 +#random=1 +resize=1.5 +iou_thresh=0.2 +iou_normalizer=0.05 +cls_normalizer=0.5 +obj_normalizer=0.4 +iou_loss=ciou +nms_kind=diounms +beta_nms=0.6 +new_coords=1 +max_delta=2 + + +# YOLO-4 + +[route] +layers = 152 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=512 +activation=swish + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=logistic + +[yolo] +mask = 3,4,5 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.1 +scale_x_y = 2.0 +objectness_smooth=1 +ignore_thresh = .7 +truth_thresh = 1 +#random=1 +resize=1.5 +iou_thresh=0.2 +iou_normalizer=0.05 +cls_normalizer=0.5 +obj_normalizer=0.4 +iou_loss=ciou +nms_kind=diounms +beta_nms=0.6 +new_coords=1 +max_delta=2 + + +# YOLO-5 + +[route] +layers = 163 + +[convolutional] +batch_normalize=1 +size=3 +stride=1 +pad=1 +filters=1024 +activation=swish + +[convolutional] +size=1 +stride=1 +pad=1 +filters=255 +activation=logistic + +[yolo] +mask = 6,7,8 +anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401 +classes=80 +num=9 +jitter=.1 +scale_x_y = 2.0 +objectness_smooth=1 +ignore_thresh = .7 +truth_thresh = 1 +#random=1 +resize=1.5 +iou_thresh=0.2 +iou_normalizer=0.05 +cls_normalizer=0.5 +obj_normalizer=0.4 +iou_loss=ciou +nms_kind=diounms +beta_nms=0.6 +new_coords=1 +max_delta=2 diff --git a/PyTorch/contrib/cv/detection/YOLOR/darknet/new_layers.md b/PyTorch/contrib/cv/detection/YOLOR/darknet/new_layers.md index b9b5fb84a8..9f7a35c02a 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/darknet/new_layers.md +++ b/PyTorch/contrib/cv/detection/YOLOR/darknet/new_layers.md @@ -1,329 +1,329 @@ -![Implicit Modeling](https://github.com/WongKinYiu/yolor/blob/main/figure/implicit_modeling.png) - -### 1. silence layer - -Usage: - -``` -[silence] -``` - -PyTorch code: - -``` python -class Silence(nn.Module): - def __init__(self): - super(Silence, self).__init__() - def forward(self, x): - return x -``` - - -### 2. implicit_add layer - -Usage: - -``` -[implicit_add] -filters=128 -``` - -PyTorch code: - -``` python -class ImplicitA(nn.Module): - def __init__(self, channel): - super(ImplicitA, self).__init__() - self.channel = channel - self.implicit = nn.Parameter(torch.zeros(1, channel, 1, 1)) - nn.init.normal_(self.implicit, std=.02) - - def forward(self): - return self.implicit -``` - - -### 3. shift_channels layer - -Usage: - -``` -[shift_channels] -from=101 -``` - -PyTorch code: - -``` python -class ShiftChannel(nn.Module): - def __init__(self, layers): - super(ShiftChannel, self).__init__() - self.layers = layers # layer indices - - def forward(self, x, outputs): - a = outputs[self.layers[0]] - return a.expand_as(x) + x -``` - - -### 4. implicit_mul layer - -Usage: - -``` -[implicit_mul] -filters=128 -``` - -PyTorch code: - -``` python -class ImplicitM(nn.Module): - def __init__(self, channel): - super(ImplicitM, self).__init__() - self.channel = channel - self.implicit = nn.Parameter(torch.ones(1, channel, 1, 1)) - nn.init.normal_(self.implicit, mean=1., std=.02) - - def forward(self): - return self.implicit -``` - - -### 5. control_channels layer - -Usage: - -``` -[control_channels] -from=101 -``` - -PyTorch code: - -``` python -class ControlChannel(nn.Module): - def __init__(self, layers): - super(ControlChannel, self).__init__() - self.layers = layers # layer indices - - def forward(self, x, outputs): - a = outputs[self.layers[0]] - return a.expand_as(x) * x -``` - - -### 6. implicit_cat layer - -Usage: - -``` -[implicit_cat] -filters=128 -``` - -PyTorch code: (same as ImplicitA) - -``` python -class ImplicitC(nn.Module): - def __init__(self, channel): - super(ImplicitC, self).__init__() - self.channel = channel - self.implicit = nn.Parameter(torch.zeros(1, channel, 1, 1)) - nn.init.normal_(self.implicit, std=.02) - - def forward(self): - return self.implicit -``` - - -### 7. alternate_channels layer - -Usage: - -``` -[alternate_channels] -from=101 -``` - -PyTorch code: - -``` python -class AlternateChannel(nn.Module): - def __init__(self, layers): - super(AlternateChannel, self).__init__() - self.layers = layers # layer indices - - def forward(self, x, outputs): - a = outputs[self.layers[0]] - return torch.cat([a.expand_as(x), x], dim=1) -``` - - -### 8. implicit_add_2d layer - -Usage: - -``` -[implicit_add_2d] -filters=128 -atoms=128 -``` - -PyTorch code: - -``` python -class Implicit2DA(nn.Module): - def __init__(self, atom, channel): - super(Implicit2DA, self).__init__() - self.channel = channel - self.implicit = nn.Parameter(torch.zeros(1, atom, channel, 1)) - nn.init.normal_(self.implicit, std=.02) - - def forward(self): - return self.implicit -``` - - -### 9. shift_channels_2d layer - -Usage: - -``` -[shift_channels_2d] -from=101 -``` - -PyTorch code: - -``` python -class ShiftChannel2D(nn.Module): - def __init__(self, layers): - super(ShiftChannel2D, self).__init__() - self.layers = layers # layer indices - - def forward(self, x, outputs): - a = outputs[self.layers[0]].view(1,-1,1,1) - return a.expand_as(x) + x -``` - - -### 10. implicit_mul_2d layer - -Usage: - -``` -[implicit_mul_2d] -filters=128 -atoms=128 -``` - -PyTorch code: - -``` python -class Implicit2DM(nn.Module): - def __init__(self, atom, channel): - super(Implicit2DM, self).__init__() - self.channel = channel - self.implicit = nn.Parameter(torch.ones(1, atom, channel, 1)) - nn.init.normal_(self.implicit, mean=1., std=.02) - - def forward(self): - return self.implicit -``` - - -### 11. control_channels_2d layer - -Usage: - -``` -[control_channels_2d] -from=101 -``` - -PyTorch code: - -``` python -class ControlChannel2D(nn.Module): - def __init__(self, layers): - super(ControlChannel2D, self).__init__() - self.layers = layers # layer indices - - def forward(self, x, outputs): - a = outputs[self.layers[0]].view(1,-1,1,1) - return a.expand_as(x) * x -``` - - -### 12. implicit_cat_2d layer - -Usage: - -``` -[implicit_cat_2d] -filters=128 -atoms=128 -``` - -PyTorch code: (same as Implicit2DA) - -``` python -class Implicit2DC(nn.Module): - def __init__(self, atom, channel): - super(Implicit2DC, self).__init__() - self.channel = channel - self.implicit = nn.Parameter(torch.zeros(1, atom, channel, 1)) - nn.init.normal_(self.implicit, std=.02) - - def forward(self): - return self.implicit -``` - - -### 13. alternate_channels_2d layer - -Usage: - -``` -[alternate_channels_2d] -from=101 -``` - -PyTorch code: - -``` python -class AlternateChannel2D(nn.Module): - def __init__(self, layers): - super(AlternateChannel2D, self).__init__() - self.layers = layers # layer indices - - def forward(self, x, outputs): - a = outputs[self.layers[0]].view(1,-1,1,1) - return torch.cat([a.expand_as(x), x], dim=1) -``` - - -### 14. dwt layer - -Usage: - -``` -[dwt] -``` - -PyTorch code: - -``` python -# https://github.com/fbcotter/pytorch_wavelets -from pytorch_wavelets import DWTForward, DWTInverse -class DWT(nn.Module): - def __init__(self): - super(DWT, self).__init__() - self.xfm = DWTForward(J=1, wave='db1', mode='zero') - - def forward(self, x): - b,c,w,h = x.shape - yl, yh = self.xfm(x) - return torch.cat([yl/2., yh[0].view(b,-1,w//2,h//2)/2.+.5], 1) -``` +![Implicit Modeling](https://github.com/WongKinYiu/yolor/blob/main/figure/implicit_modeling.png) + +### 1. silence layer + +Usage: + +``` +[silence] +``` + +PyTorch code: + +``` python +class Silence(nn.Module): + def __init__(self): + super(Silence, self).__init__() + def forward(self, x): + return x +``` + + +### 2. implicit_add layer + +Usage: + +``` +[implicit_add] +filters=128 +``` + +PyTorch code: + +``` python +class ImplicitA(nn.Module): + def __init__(self, channel): + super(ImplicitA, self).__init__() + self.channel = channel + self.implicit = nn.Parameter(torch.zeros(1, channel, 1, 1)) + nn.init.normal_(self.implicit, std=.02) + + def forward(self): + return self.implicit +``` + + +### 3. shift_channels layer + +Usage: + +``` +[shift_channels] +from=101 +``` + +PyTorch code: + +``` python +class ShiftChannel(nn.Module): + def __init__(self, layers): + super(ShiftChannel, self).__init__() + self.layers = layers # layer indices + + def forward(self, x, outputs): + a = outputs[self.layers[0]] + return a.expand_as(x) + x +``` + + +### 4. implicit_mul layer + +Usage: + +``` +[implicit_mul] +filters=128 +``` + +PyTorch code: + +``` python +class ImplicitM(nn.Module): + def __init__(self, channel): + super(ImplicitM, self).__init__() + self.channel = channel + self.implicit = nn.Parameter(torch.ones(1, channel, 1, 1)) + nn.init.normal_(self.implicit, mean=1., std=.02) + + def forward(self): + return self.implicit +``` + + +### 5. control_channels layer + +Usage: + +``` +[control_channels] +from=101 +``` + +PyTorch code: + +``` python +class ControlChannel(nn.Module): + def __init__(self, layers): + super(ControlChannel, self).__init__() + self.layers = layers # layer indices + + def forward(self, x, outputs): + a = outputs[self.layers[0]] + return a.expand_as(x) * x +``` + + +### 6. implicit_cat layer + +Usage: + +``` +[implicit_cat] +filters=128 +``` + +PyTorch code: (same as ImplicitA) + +``` python +class ImplicitC(nn.Module): + def __init__(self, channel): + super(ImplicitC, self).__init__() + self.channel = channel + self.implicit = nn.Parameter(torch.zeros(1, channel, 1, 1)) + nn.init.normal_(self.implicit, std=.02) + + def forward(self): + return self.implicit +``` + + +### 7. alternate_channels layer + +Usage: + +``` +[alternate_channels] +from=101 +``` + +PyTorch code: + +``` python +class AlternateChannel(nn.Module): + def __init__(self, layers): + super(AlternateChannel, self).__init__() + self.layers = layers # layer indices + + def forward(self, x, outputs): + a = outputs[self.layers[0]] + return torch.cat([a.expand_as(x), x], dim=1) +``` + + +### 8. implicit_add_2d layer + +Usage: + +``` +[implicit_add_2d] +filters=128 +atoms=128 +``` + +PyTorch code: + +``` python +class Implicit2DA(nn.Module): + def __init__(self, atom, channel): + super(Implicit2DA, self).__init__() + self.channel = channel + self.implicit = nn.Parameter(torch.zeros(1, atom, channel, 1)) + nn.init.normal_(self.implicit, std=.02) + + def forward(self): + return self.implicit +``` + + +### 9. shift_channels_2d layer + +Usage: + +``` +[shift_channels_2d] +from=101 +``` + +PyTorch code: + +``` python +class ShiftChannel2D(nn.Module): + def __init__(self, layers): + super(ShiftChannel2D, self).__init__() + self.layers = layers # layer indices + + def forward(self, x, outputs): + a = outputs[self.layers[0]].view(1,-1,1,1) + return a.expand_as(x) + x +``` + + +### 10. implicit_mul_2d layer + +Usage: + +``` +[implicit_mul_2d] +filters=128 +atoms=128 +``` + +PyTorch code: + +``` python +class Implicit2DM(nn.Module): + def __init__(self, atom, channel): + super(Implicit2DM, self).__init__() + self.channel = channel + self.implicit = nn.Parameter(torch.ones(1, atom, channel, 1)) + nn.init.normal_(self.implicit, mean=1., std=.02) + + def forward(self): + return self.implicit +``` + + +### 11. control_channels_2d layer + +Usage: + +``` +[control_channels_2d] +from=101 +``` + +PyTorch code: + +``` python +class ControlChannel2D(nn.Module): + def __init__(self, layers): + super(ControlChannel2D, self).__init__() + self.layers = layers # layer indices + + def forward(self, x, outputs): + a = outputs[self.layers[0]].view(1,-1,1,1) + return a.expand_as(x) * x +``` + + +### 12. implicit_cat_2d layer + +Usage: + +``` +[implicit_cat_2d] +filters=128 +atoms=128 +``` + +PyTorch code: (same as Implicit2DA) + +``` python +class Implicit2DC(nn.Module): + def __init__(self, atom, channel): + super(Implicit2DC, self).__init__() + self.channel = channel + self.implicit = nn.Parameter(torch.zeros(1, atom, channel, 1)) + nn.init.normal_(self.implicit, std=.02) + + def forward(self): + return self.implicit +``` + + +### 13. alternate_channels_2d layer + +Usage: + +``` +[alternate_channels_2d] +from=101 +``` + +PyTorch code: + +``` python +class AlternateChannel2D(nn.Module): + def __init__(self, layers): + super(AlternateChannel2D, self).__init__() + self.layers = layers # layer indices + + def forward(self, x, outputs): + a = outputs[self.layers[0]].view(1,-1,1,1) + return torch.cat([a.expand_as(x), x], dim=1) +``` + + +### 14. dwt layer + +Usage: + +``` +[dwt] +``` + +PyTorch code: + +``` python +# https://github.com/fbcotter/pytorch_wavelets +from pytorch_wavelets import DWTForward, DWTInverse +class DWT(nn.Module): + def __init__(self): + super(DWT, self).__init__() + self.xfm = DWTForward(J=1, wave='db1', mode='zero') + + def forward(self, x): + b,c,w,h = x.shape + yl, yh = self.xfm(x) + return torch.cat([yl/2., yh[0].view(b,-1,w//2,h//2)/2.+.5], 1) +``` diff --git a/PyTorch/contrib/cv/detection/YOLOR/data/coco.names b/PyTorch/contrib/cv/detection/YOLOR/data/coco.names index a1a11c4e11..941cb4e139 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/data/coco.names +++ b/PyTorch/contrib/cv/detection/YOLOR/data/coco.names @@ -1,80 +1,80 @@ -person -bicycle -car -motorcycle -airplane -bus -train -truck -boat -traffic light -fire hydrant -stop sign -parking meter -bench -bird -cat -dog -horse -sheep -cow -elephant -bear -zebra -giraffe -backpack -umbrella -handbag -tie -suitcase -frisbee -skis -snowboard -sports ball -kite -baseball bat -baseball glove -skateboard -surfboard -tennis racket -bottle -wine glass -cup -fork -knife -spoon -bowl -banana -apple -sandwich -orange -broccoli -carrot -hot dog -pizza -donut -cake -chair -couch -potted plant -bed -dining table -toilet -tv -laptop -mouse -remote -keyboard -cell phone -microwave -oven -toaster -sink -refrigerator -book -clock -vase -scissors -teddy bear -hair drier -toothbrush +person +bicycle +car +motorcycle +airplane +bus +train +truck +boat +traffic light +fire hydrant +stop sign +parking meter +bench +bird +cat +dog +horse +sheep +cow +elephant +bear +zebra +giraffe +backpack +umbrella +handbag +tie +suitcase +frisbee +skis +snowboard +sports ball +kite +baseball bat +baseball glove +skateboard +surfboard +tennis racket +bottle +wine glass +cup +fork +knife +spoon +bowl +banana +apple +sandwich +orange +broccoli +carrot +hot dog +pizza +donut +cake +chair +couch +potted plant +bed +dining table +toilet +tv +laptop +mouse +remote +keyboard +cell phone +microwave +oven +toaster +sink +refrigerator +book +clock +vase +scissors +teddy bear +hair drier +toothbrush diff --git a/PyTorch/contrib/cv/detection/YOLOR/data/coco.yaml b/PyTorch/contrib/cv/detection/YOLOR/data/coco.yaml index 6b34a4e99a..b0e6bd4bae 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/data/coco.yaml +++ b/PyTorch/contrib/cv/detection/YOLOR/data/coco.yaml @@ -1,18 +1,18 @@ -# train and val datasets (image directory or *.txt file with image paths) -train: /npu/traindata/yolov5_data/train2017.txt # 118k images -val: /npu/traindata/yolov5_data/val2017.txt # 5k images -test: /npu/traindata/yolov5_data/test-dev2017.txt # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794 - -# number of classes -nc: 80 - -# class names -names: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', - 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', - 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', - 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', - 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', - 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', - 'hair drier', 'toothbrush'] +# train and val datasets (image directory or *.txt file with image paths) +train: /npu/traindata/yolov5_data/train2017.txt # 118k images +val: /npu/traindata/yolov5_data/val2017.txt # 5k images +test: /npu/traindata/yolov5_data/test-dev2017.txt # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794 + +# number of classes +nc: 80 + +# class names +names: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', + 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', + 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', + 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', + 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', + 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', + 'hair drier', 'toothbrush'] diff --git a/PyTorch/contrib/cv/detection/YOLOR/data/hyp.finetune.1280.yaml b/PyTorch/contrib/cv/detection/YOLOR/data/hyp.finetune.1280.yaml index 4cef10c4f5..d3ebbe10f1 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/data/hyp.finetune.1280.yaml +++ b/PyTorch/contrib/cv/detection/YOLOR/data/hyp.finetune.1280.yaml @@ -1,28 +1,28 @@ -lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) -lrf: 0.2 # final OneCycleLR learning rate (lr0 * lrf) -momentum: 0.937 # SGD momentum/Adam beta1 -weight_decay: 0.0005 # optimizer weight decay 5e-4 -warmup_epochs: 3.0 # warmup epochs (fractions ok) -warmup_momentum: 0.8 # warmup initial momentum -warmup_bias_lr: 0.1 # warmup initial bias lr -box: 0.05 # box loss gain -cls: 0.5 # cls loss gain -cls_pw: 1.0 # cls BCELoss positive_weight -obj: 1.0 # obj loss gain (scale with pixels) -obj_pw: 1.0 # obj BCELoss positive_weight -iou_t: 0.20 # IoU training threshold -anchor_t: 4.0 # anchor-multiple threshold -# anchors: 3 # anchors per output layer (0 to ignore) -fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) -hsv_h: 0.015 # image HSV-Hue augmentation (fraction) -hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) -hsv_v: 0.4 # image HSV-Value augmentation (fraction) -degrees: 0.0 # image rotation (+/- deg) -translate: 0.5 # image translation (+/- fraction) -scale: 0.8 # image scale (+/- gain) -shear: 0.0 # image shear (+/- deg) -perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 -flipud: 0.0 # image flip up-down (probability) -fliplr: 0.5 # image flip left-right (probability) -mosaic: 1.0 # image mosaic (probability) -mixup: 0.2 # image mixup (probability) +lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) +lrf: 0.2 # final OneCycleLR learning rate (lr0 * lrf) +momentum: 0.937 # SGD momentum/Adam beta1 +weight_decay: 0.0005 # optimizer weight decay 5e-4 +warmup_epochs: 3.0 # warmup epochs (fractions ok) +warmup_momentum: 0.8 # warmup initial momentum +warmup_bias_lr: 0.1 # warmup initial bias lr +box: 0.05 # box loss gain +cls: 0.5 # cls loss gain +cls_pw: 1.0 # cls BCELoss positive_weight +obj: 1.0 # obj loss gain (scale with pixels) +obj_pw: 1.0 # obj BCELoss positive_weight +iou_t: 0.20 # IoU training threshold +anchor_t: 4.0 # anchor-multiple threshold +# anchors: 3 # anchors per output layer (0 to ignore) +fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) +hsv_h: 0.015 # image HSV-Hue augmentation (fraction) +hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) +hsv_v: 0.4 # image HSV-Value augmentation (fraction) +degrees: 0.0 # image rotation (+/- deg) +translate: 0.5 # image translation (+/- fraction) +scale: 0.8 # image scale (+/- gain) +shear: 0.0 # image shear (+/- deg) +perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 +flipud: 0.0 # image flip up-down (probability) +fliplr: 0.5 # image flip left-right (probability) +mosaic: 1.0 # image mosaic (probability) +mixup: 0.2 # image mixup (probability) diff --git a/PyTorch/contrib/cv/detection/YOLOR/data/hyp.scratch.1280.yaml b/PyTorch/contrib/cv/detection/YOLOR/data/hyp.scratch.1280.yaml index ece2c96e5d..3b0f84b96a 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/data/hyp.scratch.1280.yaml +++ b/PyTorch/contrib/cv/detection/YOLOR/data/hyp.scratch.1280.yaml @@ -1,28 +1,28 @@ -lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) -lrf: 0.2 # final OneCycleLR learning rate (lr0 * lrf) -momentum: 0.937 # SGD momentum/Adam beta1 -weight_decay: 0.0005 # optimizer weight decay 5e-4 -warmup_epochs: 3.0 # warmup epochs (fractions ok) -warmup_momentum: 0.8 # warmup initial momentum -warmup_bias_lr: 0.1 # warmup initial bias lr -box: 0.05 # box loss gain -cls: 0.5 # cls loss gain -cls_pw: 1.0 # cls BCELoss positive_weight -obj: 1.0 # obj loss gain (scale with pixels) -obj_pw: 1.0 # obj BCELoss positive_weight -iou_t: 0.20 # IoU training threshold -anchor_t: 4.0 # anchor-multiple threshold -# anchors: 3 # anchors per output layer (0 to ignore) -fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) -hsv_h: 0.015 # image HSV-Hue augmentation (fraction) -hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) -hsv_v: 0.4 # image HSV-Value augmentation (fraction) -degrees: 0.0 # image rotation (+/- deg) -translate: 0.5 # image translation (+/- fraction) -scale: 0.5 # image scale (+/- gain) -shear: 0.0 # image shear (+/- deg) -perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 -flipud: 0.0 # image flip up-down (probability) -fliplr: 0.5 # image flip left-right (probability) -mosaic: 1.0 # image mosaic (probability) -mixup: 0.0 # image mixup (probability) +lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) +lrf: 0.2 # final OneCycleLR learning rate (lr0 * lrf) +momentum: 0.937 # SGD momentum/Adam beta1 +weight_decay: 0.0005 # optimizer weight decay 5e-4 +warmup_epochs: 3.0 # warmup epochs (fractions ok) +warmup_momentum: 0.8 # warmup initial momentum +warmup_bias_lr: 0.1 # warmup initial bias lr +box: 0.05 # box loss gain +cls: 0.5 # cls loss gain +cls_pw: 1.0 # cls BCELoss positive_weight +obj: 1.0 # obj loss gain (scale with pixels) +obj_pw: 1.0 # obj BCELoss positive_weight +iou_t: 0.20 # IoU training threshold +anchor_t: 4.0 # anchor-multiple threshold +# anchors: 3 # anchors per output layer (0 to ignore) +fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) +hsv_h: 0.015 # image HSV-Hue augmentation (fraction) +hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) +hsv_v: 0.4 # image HSV-Value augmentation (fraction) +degrees: 0.0 # image rotation (+/- deg) +translate: 0.5 # image translation (+/- fraction) +scale: 0.5 # image scale (+/- gain) +shear: 0.0 # image shear (+/- deg) +perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 +flipud: 0.0 # image flip up-down (probability) +fliplr: 0.5 # image flip left-right (probability) +mosaic: 1.0 # image mosaic (probability) +mixup: 0.0 # image mixup (probability) diff --git a/PyTorch/contrib/cv/detection/YOLOR/data/hyp.scratch.640.yaml b/PyTorch/contrib/cv/detection/YOLOR/data/hyp.scratch.640.yaml index 336fa526e4..00e458ae3a 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/data/hyp.scratch.640.yaml +++ b/PyTorch/contrib/cv/detection/YOLOR/data/hyp.scratch.640.yaml @@ -1,28 +1,28 @@ -lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) -lrf: 0.2 # final OneCycleLR learning rate (lr0 * lrf) -momentum: 0.937 # SGD momentum/Adam beta1 -weight_decay: 0.0005 # optimizer weight decay 5e-4 -warmup_epochs: 3.0 # warmup epochs (fractions ok) -warmup_momentum: 0.8 # warmup initial momentum -warmup_bias_lr: 0.1 # warmup initial bias lr -box: 0.05 # box loss gain -cls: 0.3 # cls loss gain -cls_pw: 1.0 # cls BCELoss positive_weight -obj: 0.7 # obj loss gain (scale with pixels) -obj_pw: 1.0 # obj BCELoss positive_weight -iou_t: 0.20 # IoU training threshold -anchor_t: 4.0 # anchor-multiple threshold -# anchors: 3 # anchors per output layer (0 to ignore) -fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) -hsv_h: 0.015 # image HSV-Hue augmentation (fraction) -hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) -hsv_v: 0.4 # image HSV-Value augmentation (fraction) -degrees: 0.0 # image rotation (+/- deg) -translate: 0.1 # image translation (+/- fraction) -scale: 0.9 # image scale (+/- gain) -shear: 0.0 # image shear (+/- deg) -perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 -flipud: 0.0 # image flip up-down (probability) -fliplr: 0.5 # image flip left-right (probability) -mosaic: 1.0 # image mosaic (probability) -mixup: 0.0 # image mixup (probability) +lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) +lrf: 0.2 # final OneCycleLR learning rate (lr0 * lrf) +momentum: 0.937 # SGD momentum/Adam beta1 +weight_decay: 0.0005 # optimizer weight decay 5e-4 +warmup_epochs: 3.0 # warmup epochs (fractions ok) +warmup_momentum: 0.8 # warmup initial momentum +warmup_bias_lr: 0.1 # warmup initial bias lr +box: 0.05 # box loss gain +cls: 0.3 # cls loss gain +cls_pw: 1.0 # cls BCELoss positive_weight +obj: 0.7 # obj loss gain (scale with pixels) +obj_pw: 1.0 # obj BCELoss positive_weight +iou_t: 0.20 # IoU training threshold +anchor_t: 4.0 # anchor-multiple threshold +# anchors: 3 # anchors per output layer (0 to ignore) +fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) +hsv_h: 0.015 # image HSV-Hue augmentation (fraction) +hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) +hsv_v: 0.4 # image HSV-Value augmentation (fraction) +degrees: 0.0 # image rotation (+/- deg) +translate: 0.1 # image translation (+/- fraction) +scale: 0.9 # image scale (+/- gain) +shear: 0.0 # image shear (+/- deg) +perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 +flipud: 0.0 # image flip up-down (probability) +fliplr: 0.5 # image flip left-right (probability) +mosaic: 1.0 # image mosaic (probability) +mixup: 0.0 # image mixup (probability) diff --git a/PyTorch/contrib/cv/detection/YOLOR/models/__init__.py b/PyTorch/contrib/cv/detection/YOLOR/models/__init__.py index d3f5a12faa..8b13789179 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/models/__init__.py +++ b/PyTorch/contrib/cv/detection/YOLOR/models/__init__.py @@ -1 +1 @@ - + diff --git a/PyTorch/contrib/cv/detection/YOLOR/models/export.py b/PyTorch/contrib/cv/detection/YOLOR/models/export.py index 43651c4e8a..0816faccf2 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/models/export.py +++ b/PyTorch/contrib/cv/detection/YOLOR/models/export.py @@ -1,82 +1,82 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse - -import torch - -from utils.google_utils import attempt_download - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--weights', type=str, default='./yolov4.pt', help='weights path') - parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='image size') - parser.add_argument('--batch-size', type=int, default=1, help='batch size') - opt = parser.parse_args() - opt.img_size *= 2 if len(opt.img_size) == 1 else 1 # expand - print(opt) - - # Input - img = torch.zeros((opt.batch_size, 3, *opt.img_size)) # image size(1,3,320,192) iDetection - - # Load PyTorch model - attempt_download(opt.weights) - model = torch.load(opt.weights, map_location=torch.device('cpu'))['model'].float() - model.eval() - model.model[-1].export = True # set Detect() layer export=True - y = model(img) # dry run - - # TorchScript export - try: - print('\nStarting TorchScript export with torch %s...' % torch.__version__) - f = opt.weights.replace('.pt', '.torchscript.pt') # filename - ts = torch.jit.trace(model, img) - ts.save(f) - print('TorchScript export success, saved as %s' % f) - except Exception as e: - print('TorchScript export failure: %s' % e) - - # ONNX export - try: - import onnx - - print('\nStarting ONNX export with onnx %s...' % onnx.__version__) - f = opt.weights.replace('.pt', '.onnx') # filename - model.fuse() # only for ONNX - torch.onnx.export(model, img, f, verbose=False, opset_version=12, input_names=['images'], - output_names=['classes', 'boxes'] if y is None else ['output']) - - # Checks - onnx_model = onnx.load(f) # load onnx model - onnx.checker.check_model(onnx_model) # check onnx model - print(onnx.helper.printable_graph(onnx_model.graph)) # print a human readable model - print('ONNX export success, saved as %s' % f) - except Exception as e: - print('ONNX export failure: %s' % e) - - # CoreML export - try: - import coremltools as ct - - print('\nStarting CoreML export with coremltools %s...' % ct.__version__) - # convert model from torchscript and apply pixel scaling as per detect.py - model = ct.convert(ts, inputs=[ct.ImageType(name='images', shape=img.shape, scale=1 / 255.0, bias=[0, 0, 0])]) - f = opt.weights.replace('.pt', '.mlmodel') # filename - model.save(f) - print('CoreML export success, saved as %s' % f) - except Exception as e: - print('CoreML export failure: %s' % e) - - # Finish - print('\nExport complete. Visualize with https://github.com/lutzroeder/netron.') +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse + +import torch + +from utils.google_utils import attempt_download + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--weights', type=str, default='./yolov4.pt', help='weights path') + parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='image size') + parser.add_argument('--batch-size', type=int, default=1, help='batch size') + opt = parser.parse_args() + opt.img_size *= 2 if len(opt.img_size) == 1 else 1 # expand + print(opt) + + # Input + img = torch.zeros((opt.batch_size, 3, *opt.img_size)) # image size(1,3,320,192) iDetection + + # Load PyTorch model + attempt_download(opt.weights) + model = torch.load(opt.weights, map_location=torch.device('cpu'))['model'].float() + model.eval() + model.model[-1].export = True # set Detect() layer export=True + y = model(img) # dry run + + # TorchScript export + try: + print('\nStarting TorchScript export with torch %s...' % torch.__version__) + f = opt.weights.replace('.pt', '.torchscript.pt') # filename + ts = torch.jit.trace(model, img) + ts.save(f) + print('TorchScript export success, saved as %s' % f) + except Exception as e: + print('TorchScript export failure: %s' % e) + + # ONNX export + try: + import onnx + + print('\nStarting ONNX export with onnx %s...' % onnx.__version__) + f = opt.weights.replace('.pt', '.onnx') # filename + model.fuse() # only for ONNX + torch.onnx.export(model, img, f, verbose=False, opset_version=12, input_names=['images'], + output_names=['classes', 'boxes'] if y is None else ['output']) + + # Checks + onnx_model = onnx.load(f) # load onnx model + onnx.checker.check_model(onnx_model) # check onnx model + print(onnx.helper.printable_graph(onnx_model.graph)) # print a human readable model + print('ONNX export success, saved as %s' % f) + except Exception as e: + print('ONNX export failure: %s' % e) + + # CoreML export + try: + import coremltools as ct + + print('\nStarting CoreML export with coremltools %s...' % ct.__version__) + # convert model from torchscript and apply pixel scaling as per detect.py + model = ct.convert(ts, inputs=[ct.ImageType(name='images', shape=img.shape, scale=1 / 255.0, bias=[0, 0, 0])]) + f = opt.weights.replace('.pt', '.mlmodel') # filename + model.save(f) + print('CoreML export success, saved as %s' % f) + except Exception as e: + print('CoreML export failure: %s' % e) + + # Finish + print('\nExport complete. Visualize with https://github.com/lutzroeder/netron.') diff --git a/PyTorch/contrib/cv/detection/YOLOR/models/models.py b/PyTorch/contrib/cv/detection/YOLOR/models/models.py index 7a532e283f..47b0dce495 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/models/models.py +++ b/PyTorch/contrib/cv/detection/YOLOR/models/models.py @@ -1,775 +1,775 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 utils.google_utils import * -from utils.layers import * -from utils.parse_config import * -from utils import torch_utils - -ONNX_EXPORT = False - - -def create_modules(module_defs, img_size, cfg): - # Constructs module list of layer blocks from module configuration in module_defs - - img_size = [img_size] * 2 if isinstance(img_size, int) else img_size # expand if necessary - _ = module_defs.pop(0) # cfg training hyperparams (unused) - output_filters = [3] # input channels - module_list = nn.ModuleList() - routs = [] # list of layers which rout to deeper layers - yolo_index = -1 - - for i, mdef in enumerate(module_defs): - modules = nn.Sequential() - - if mdef['type'] == 'convolutional': - bn = mdef['batch_normalize'] - filters = mdef['filters'] - k = mdef['size'] # kernel size - stride = mdef['stride'] if 'stride' in mdef else (mdef['stride_y'], mdef['stride_x']) - if isinstance(k, int): # single-size conv - modules.add_module('Conv2d', nn.Conv2d(in_channels=output_filters[-1], - out_channels=filters, - kernel_size=k, - stride=stride, - padding=k // 2 if mdef['pad'] else 0, - groups=mdef['groups'] if 'groups' in mdef else 1, - bias=not bn)) - else: # multiple-size conv - modules.add_module('MixConv2d', MixConv2d(in_ch=output_filters[-1], - out_ch=filters, - k=k, - stride=stride, - bias=not bn)) - - if bn: - modules.add_module('BatchNorm2d', nn.BatchNorm2d(filters, momentum=0.03, eps=1E-4)) - else: - routs.append(i) # detection output (goes into yolo layer) - - if mdef['activation'] == 'leaky': # activation study https://github.com/ultralytics/yolov3/issues/441 - modules.add_module('activation', nn.LeakyReLU(0.1, inplace=True)) - elif mdef['activation'] == 'swish': - modules.add_module('activation', Swish()) - elif mdef['activation'] == 'mish': - modules.add_module('activation', Mish()) - elif mdef['activation'] == 'emb': - modules.add_module('activation', F.normalize()) - elif mdef['activation'] == 'logistic': - modules.add_module('activation', nn.Sigmoid()) - elif mdef['activation'] == 'silu': - modules.add_module('activation', nn.SiLU()) - - elif mdef['type'] == 'deformableconvolutional': - bn = mdef['batch_normalize'] - filters = mdef['filters'] - k = mdef['size'] # kernel size - stride = mdef['stride'] if 'stride' in mdef else (mdef['stride_y'], mdef['stride_x']) - if isinstance(k, int): # single-size conv - modules.add_module('DeformConv2d', DeformConv2d(output_filters[-1], - filters, - kernel_size=k, - padding=k // 2 if mdef['pad'] else 0, - stride=stride, - bias=not bn, - modulation=True)) - else: # multiple-size conv - modules.add_module('MixConv2d', MixConv2d(in_ch=output_filters[-1], - out_ch=filters, - k=k, - stride=stride, - bias=not bn)) - - if bn: - modules.add_module('BatchNorm2d', nn.BatchNorm2d(filters, momentum=0.03, eps=1E-4)) - else: - routs.append(i) # detection output (goes into yolo layer) - - if mdef['activation'] == 'leaky': # activation study https://github.com/ultralytics/yolov3/issues/441 - modules.add_module('activation', nn.LeakyReLU(0.1, inplace=True)) - elif mdef['activation'] == 'swish': - modules.add_module('activation', Swish()) - elif mdef['activation'] == 'mish': - modules.add_module('activation', Mish()) - elif mdef['activation'] == 'silu': - modules.add_module('activation', nn.SiLU()) - - elif mdef['type'] == 'dropout': - p = mdef['probability'] - modules = nn.Dropout(p) - - elif mdef['type'] == 'avgpool': - modules = GAP() - - elif mdef['type'] == 'silence': - filters = output_filters[-1] - modules = Silence() - - elif mdef['type'] == 'scale_channels': # nn.Sequential() placeholder for 'shortcut' layer - layers = mdef['from'] - filters = output_filters[-1] - routs.extend([i + l if l < 0 else l for l in layers]) - modules = ScaleChannel(layers=layers) - - elif mdef['type'] == 'shift_channels': # nn.Sequential() placeholder for 'shortcut' layer - layers = mdef['from'] - filters = output_filters[-1] - routs.extend([i + l if l < 0 else l for l in layers]) - modules = ShiftChannel(layers=layers) - - elif mdef['type'] == 'shift_channels_2d': # nn.Sequential() placeholder for 'shortcut' layer - layers = mdef['from'] - filters = output_filters[-1] - routs.extend([i + l if l < 0 else l for l in layers]) - modules = ShiftChannel2D(layers=layers) - - elif mdef['type'] == 'control_channels': # nn.Sequential() placeholder for 'shortcut' layer - layers = mdef['from'] - filters = output_filters[-1] - routs.extend([i + l if l < 0 else l for l in layers]) - modules = ControlChannel(layers=layers) - - elif mdef['type'] == 'control_channels_2d': # nn.Sequential() placeholder for 'shortcut' layer - layers = mdef['from'] - filters = output_filters[-1] - routs.extend([i + l if l < 0 else l for l in layers]) - modules = ControlChannel2D(layers=layers) - - elif mdef['type'] == 'alternate_channels': # nn.Sequential() placeholder for 'shortcut' layer - layers = mdef['from'] - filters = output_filters[-1] * 2 - routs.extend([i + l if l < 0 else l for l in layers]) - modules = AlternateChannel(layers=layers) - - elif mdef['type'] == 'alternate_channels_2d': # nn.Sequential() placeholder for 'shortcut' layer - layers = mdef['from'] - filters = output_filters[-1] * 2 - routs.extend([i + l if l < 0 else l for l in layers]) - modules = AlternateChannel2D(layers=layers) - - elif mdef['type'] == 'select_channels': # nn.Sequential() placeholder for 'shortcut' layer - layers = mdef['from'] - filters = output_filters[-1] - routs.extend([i + l if l < 0 else l for l in layers]) - modules = SelectChannel(layers=layers) - - elif mdef['type'] == 'select_channels_2d': # nn.Sequential() placeholder for 'shortcut' layer - layers = mdef['from'] - filters = output_filters[-1] - routs.extend([i + l if l < 0 else l for l in layers]) - modules = SelectChannel2D(layers=layers) - - elif mdef['type'] == 'sam': # nn.Sequential() placeholder for 'shortcut' layer - layers = mdef['from'] - filters = output_filters[-1] - routs.extend([i + l if l < 0 else l for l in layers]) - modules = ScaleSpatial(layers=layers) - - elif mdef['type'] == 'BatchNorm2d': - filters = output_filters[-1] - modules = nn.BatchNorm2d(filters, momentum=0.03, eps=1E-4) - if i == 0 and filters == 3: # normalize RGB image - # imagenet mean and var https://pytorch.org/docs/stable/torchvision/models.html#classification - modules.running_mean = torch.tensor([0.485, 0.456, 0.406]) - modules.running_var = torch.tensor([0.0524, 0.0502, 0.0506]) - - elif mdef['type'] == 'maxpool': - k = mdef['size'] # kernel size - stride = mdef['stride'] - maxpool = nn.MaxPool2d(kernel_size=k, stride=stride, padding=(k - 1) // 2) - if k == 2 and stride == 1: # yolov3-tiny - modules.add_module('ZeroPad2d', nn.ZeroPad2d((0, 1, 0, 1))) - modules.add_module('MaxPool2d', maxpool) - else: - modules = maxpool - - elif mdef['type'] == 'local_avgpool': - k = mdef['size'] # kernel size - stride = mdef['stride'] - avgpool = nn.AvgPool2d(kernel_size=k, stride=stride, padding=(k - 1) // 2) - if k == 2 and stride == 1: # yolov3-tiny - modules.add_module('ZeroPad2d', nn.ZeroPad2d((0, 1, 0, 1))) - modules.add_module('AvgPool2d', avgpool) - else: - modules = avgpool - - elif mdef['type'] == 'upsample': - if ONNX_EXPORT: # explicitly state size, avoid scale_factor - g = (yolo_index + 1) * 2 / 32 # gain - modules = nn.Upsample(size=tuple(int(x * g) for x in img_size)) # img_size = (320, 192) - else: - modules = nn.Upsample(scale_factor=mdef['stride']) - - elif mdef['type'] == 'route': # nn.Sequential() placeholder for 'route' layer - layers = mdef['layers'] - filters = sum([output_filters[l + 1 if l > 0 else l] for l in layers]) - routs.extend([i + l if l < 0 else l for l in layers]) - modules = FeatureConcat(layers=layers) - - elif mdef['type'] == 'route2': # nn.Sequential() placeholder for 'route' layer - layers = mdef['layers'] - filters = sum([output_filters[l + 1 if l > 0 else l] for l in layers]) - routs.extend([i + l if l < 0 else l for l in layers]) - modules = FeatureConcat2(layers=layers) - - elif mdef['type'] == 'route3': # nn.Sequential() placeholder for 'route' layer - layers = mdef['layers'] - filters = sum([output_filters[l + 1 if l > 0 else l] for l in layers]) - routs.extend([i + l if l < 0 else l for l in layers]) - modules = FeatureConcat3(layers=layers) - - elif mdef['type'] == 'route_lhalf': # nn.Sequential() placeholder for 'route' layer - layers = mdef['layers'] - filters = sum([output_filters[l + 1 if l > 0 else l] for l in layers])//2 - routs.extend([i + l if l < 0 else l for l in layers]) - modules = FeatureConcat_l(layers=layers) - - elif mdef['type'] == 'shortcut': # nn.Sequential() placeholder for 'shortcut' layer - layers = mdef['from'] - filters = output_filters[-1] - routs.extend([i + l if l < 0 else l for l in layers]) - modules = WeightedFeatureFusion(layers=layers, weight='weights_type' in mdef) - - elif mdef['type'] == 'reorg3d': # yolov3-spp-pan-scale - pass - - elif mdef['type'] == 'reorg': # yolov3-spp-pan-scale - filters = 4 * output_filters[-1] - modules.add_module('Reorg', Reorg()) - - elif mdef['type'] == 'dwt': # yolov3-spp-pan-scale - filters = 4 * output_filters[-1] - modules.add_module('DWT', DWT()) - - elif mdef['type'] == 'implicit_add': # yolov3-spp-pan-scale - filters = mdef['filters'] - modules = ImplicitA(channel=filters) - - elif mdef['type'] == 'implicit_mul': # yolov3-spp-pan-scale - filters = mdef['filters'] - modules = ImplicitM(channel=filters) - - elif mdef['type'] == 'implicit_cat': # yolov3-spp-pan-scale - filters = mdef['filters'] - modules = ImplicitC(channel=filters) - - elif mdef['type'] == 'implicit_add_2d': # yolov3-spp-pan-scale - channels = mdef['filters'] - filters = mdef['atoms'] - modules = Implicit2DA(atom=filters, channel=channels) - - elif mdef['type'] == 'implicit_mul_2d': # yolov3-spp-pan-scale - channels = mdef['filters'] - filters = mdef['atoms'] - modules = Implicit2DM(atom=filters, channel=channels) - - elif mdef['type'] == 'implicit_cat_2d': # yolov3-spp-pan-scale - channels = mdef['filters'] - filters = mdef['atoms'] - modules = Implicit2DC(atom=filters, channel=channels) - - elif mdef['type'] == 'yolo': - yolo_index += 1 - stride = [8, 16, 32, 64, 128] # P3, P4, P5, P6, P7 strides - if any(x in cfg for x in ['yolov4-tiny', 'fpn', 'yolov3']): # P5, P4, P3 strides - stride = [32, 16, 8] - layers = mdef['from'] if 'from' in mdef else [] - modules = YOLOLayer(anchors=mdef['anchors'][mdef['mask']], # anchor list - nc=mdef['classes'], # number of classes - img_size=img_size, # (416, 416) - yolo_index=yolo_index, # 0, 1, 2... - layers=layers, # output layers - stride=stride[yolo_index]) - - # Initialize preceding Conv2d() bias (https://arxiv.org/pdf/1708.02002.pdf section 3.3) - try: - j = layers[yolo_index] if 'from' in mdef else -2 - bias_ = module_list[j][0].bias # shape(255,) - bias = bias_[:modules.no * modules.na].view(modules.na, -1) # shape(3,85) - #bias[:, 4] += -4.5 # obj - bias.data[:, 4] += math.log(8 / (640 / stride[yolo_index]) ** 2) # obj (8 objects per 640 image) - bias.data[:, 5:] += math.log(0.6 / (modules.nc - 0.99)) # cls (sigmoid(p) = 1/nc) - module_list[j][0].bias = torch.nn.Parameter(bias_, requires_grad=bias_.requires_grad) - - #j = [-2, -5, -8] - #for sj in j: - # bias_ = module_list[sj][0].bias - # bias = bias_[:modules.no * 1].view(1, -1) - # bias.data[:, 4] += math.log(8 / (640 / stride[yolo_index]) ** 2) - # bias.data[:, 5:] += math.log(0.6 / (modules.nc - 0.99)) - # module_list[sj][0].bias = torch.nn.Parameter(bias_, requires_grad=bias_.requires_grad) - except: - print('WARNING: smart bias initialization failure.') - - elif mdef['type'] == 'jde': - yolo_index += 1 - stride = [8, 16, 32, 64, 128] # P3, P4, P5, P6, P7 strides - if any(x in cfg for x in ['yolov4-tiny', 'fpn', 'yolov3']): # P5, P4, P3 strides - stride = [32, 16, 8] - layers = mdef['from'] if 'from' in mdef else [] - modules = JDELayer(anchors=mdef['anchors'][mdef['mask']], # anchor list - nc=mdef['classes'], # number of classes - img_size=img_size, # (416, 416) - yolo_index=yolo_index, # 0, 1, 2... - layers=layers, # output layers - stride=stride[yolo_index]) - - # Initialize preceding Conv2d() bias (https://arxiv.org/pdf/1708.02002.pdf section 3.3) - try: - j = layers[yolo_index] if 'from' in mdef else -1 - bias_ = module_list[j][0].bias # shape(255,) - bias = bias_[:modules.no * modules.na].view(modules.na, -1) # shape(3,85) - #bias[:, 4] += -4.5 # obj - bias.data[:, 4] += math.log(8 / (640 / stride[yolo_index]) ** 2) # obj (8 objects per 640 image) - bias.data[:, 5:] += math.log(0.6 / (modules.nc - 0.99)) # cls (sigmoid(p) = 1/nc) - module_list[j][0].bias = torch.nn.Parameter(bias_, requires_grad=bias_.requires_grad) - except: - print('WARNING: smart bias initialization failure.') - - else: - print('Warning: Unrecognized Layer Type: ' + mdef['type']) - - # Register module list and number of output filters - module_list.append(modules) - output_filters.append(filters) - - routs_binary = [False] * (i + 1) - for i in routs: - routs_binary[i] = True - return module_list, routs_binary - - -class YOLOLayer(nn.Module): - def __init__(self, anchors, nc, img_size, yolo_index, layers, stride): - super(YOLOLayer, self).__init__() - self.anchors = torch.Tensor(anchors) - self.index = yolo_index # index of this layer in layers - self.layers = layers # model output layer indices - self.stride = stride # layer stride - self.nl = len(layers) # number of output layers (3) - self.na = len(anchors) # number of anchors (3) - self.nc = nc # number of classes (80) - self.no = nc + 5 # number of outputs (85) - self.nx, self.ny, self.ng = 0, 0, 0 # initialize number of x, y gridpoints - self.anchor_vec = self.anchors / self.stride - self.anchor_wh = self.anchor_vec.view(1, self.na, 1, 1, 2) - - if ONNX_EXPORT: - self.training = False - self.create_grids((img_size[1] // stride, img_size[0] // stride)) # number x, y grid points - - def create_grids(self, ng=(13, 13), device='cpu'): - self.nx, self.ny = ng # x and y grid size - self.ng = torch.tensor(ng, dtype=torch.float) - - # build xy offsets - if not self.training: - yv, xv = torch.meshgrid([torch.arange(self.ny, device=device), torch.arange(self.nx, device=device)]) - self.grid = torch.stack((xv, yv), 2).view((1, 1, self.ny, self.nx, 2)).float() - - if self.anchor_vec.device != device: - self.anchor_vec = self.anchor_vec.to(device) - self.anchor_wh = self.anchor_wh.to(device) - - def forward(self, p, out): - ASFF = False # https://arxiv.org/abs/1911.09516 - if ASFF: - i, n = self.index, self.nl # index in layers, number of layers - p = out[self.layers[i]] - bs, _, ny, nx = p.shape # bs, 255, 13, 13 - if (self.nx, self.ny) != (nx, ny): - self.create_grids((nx, ny), p.device) - - # outputs and weights - # w = F.softmax(p[:, -n:], 1) # normalized weights - w = torch.sigmoid(p[:, -n:]) * (2 / n) # sigmoid weights (faster) - # w = w / w.sum(1).unsqueeze(1) # normalize across layer dimension - - # weighted ASFF sum - p = out[self.layers[i]][:, :-n] * w[:, i:i + 1] - for j in range(n): - if j != i: - p += w[:, j:j + 1] * \ - F.interpolate(out[self.layers[j]][:, :-n], size=[ny, nx], mode='bilinear', align_corners=False) - - elif ONNX_EXPORT: - bs = 1 # batch size - else: - bs, _, ny, nx = p.shape # bs, 255, 13, 13 - if (self.nx, self.ny) != (nx, ny): - self.create_grids((nx, ny), p.device) - - # p.view(bs, 255, 13, 13) -- > (bs, 3, 13, 13, 85) # (bs, anchors, grid, grid, classes + xywh) - p = p.view(bs, self.na, self.no, self.ny, self.nx).permute(0, 1, 3, 4, 2).contiguous() # prediction - - if self.training: - return p - - elif ONNX_EXPORT: - # Avoid broadcasting for ANE operations - m = self.na * self.nx * self.ny - ng = 1. / self.ng.repeat(m, 1) - grid = self.grid.repeat(1, self.na, 1, 1, 1).view(m, 2) - anchor_wh = self.anchor_wh.repeat(1, 1, self.nx, self.ny, 1).view(m, 2) * ng - - p = p.view(m, self.no) - xy = torch.sigmoid(p[:, 0:2]) + grid # x, y - wh = torch.exp(p[:, 2:4]) * anchor_wh # width, height - p_cls = torch.sigmoid(p[:, 4:5]) if self.nc == 1 else \ - torch.sigmoid(p[:, 5:self.no]) * torch.sigmoid(p[:, 4:5]) # conf - return p_cls, xy * ng, wh - - else: # inference - io = p.sigmoid() - io[..., :2] = (io[..., :2] * 2. - 0.5 + self.grid) - io[..., 2:4] = (io[..., 2:4] * 2) ** 2 * self.anchor_wh - io[..., :4] *= self.stride - #io = p.clone() # inference output - #io[..., :2] = torch.sigmoid(io[..., :2]) + self.grid # xy - #io[..., 2:4] = torch.exp(io[..., 2:4]) * self.anchor_wh # wh yolo method - #io[..., :4] *= self.stride - #torch.sigmoid_(io[..., 4:]) - return io.view(bs, -1, self.no), p # view [1, 3, 13, 13, 85] as [1, 507, 85] - - -class JDELayer(nn.Module): - def __init__(self, anchors, nc, img_size, yolo_index, layers, stride): - super(JDELayer, self).__init__() - self.anchors = torch.Tensor(anchors) - self.index = yolo_index # index of this layer in layers - self.layers = layers # model output layer indices - self.stride = stride # layer stride - self.nl = len(layers) # number of output layers (3) - self.na = len(anchors) # number of anchors (3) - self.nc = nc # number of classes (80) - self.no = nc + 5 # number of outputs (85) - self.nx, self.ny, self.ng = 0, 0, 0 # initialize number of x, y gridpoints - self.anchor_vec = self.anchors / self.stride - self.anchor_wh = self.anchor_vec.view(1, self.na, 1, 1, 2) - - if ONNX_EXPORT: - self.training = False - self.create_grids((img_size[1] // stride, img_size[0] // stride)) # number x, y grid points - - def create_grids(self, ng=(13, 13), device='cpu'): - self.nx, self.ny = ng # x and y grid size - self.ng = torch.tensor(ng, dtype=torch.float) - - # build xy offsets - if not self.training: - yv, xv = torch.meshgrid([torch.arange(self.ny, device=device), torch.arange(self.nx, device=device)]) - self.grid = torch.stack((xv, yv), 2).view((1, 1, self.ny, self.nx, 2)).float() - - if self.anchor_vec.device != device: - self.anchor_vec = self.anchor_vec.to(device) - self.anchor_wh = self.anchor_wh.to(device) - - def forward(self, p, out): - ASFF = False # https://arxiv.org/abs/1911.09516 - if ASFF: - i, n = self.index, self.nl # index in layers, number of layers - p = out[self.layers[i]] - bs, _, ny, nx = p.shape # bs, 255, 13, 13 - if (self.nx, self.ny) != (nx, ny): - self.create_grids((nx, ny), p.device) - - # outputs and weights - # w = F.softmax(p[:, -n:], 1) # normalized weights - w = torch.sigmoid(p[:, -n:]) * (2 / n) # sigmoid weights (faster) - # w = w / w.sum(1).unsqueeze(1) # normalize across layer dimension - - # weighted ASFF sum - p = out[self.layers[i]][:, :-n] * w[:, i:i + 1] - for j in range(n): - if j != i: - p += w[:, j:j + 1] * \ - F.interpolate(out[self.layers[j]][:, :-n], size=[ny, nx], mode='bilinear', align_corners=False) - - elif ONNX_EXPORT: - bs = 1 # batch size - else: - bs, _, ny, nx = p.shape # bs, 255, 13, 13 - if (self.nx, self.ny) != (nx, ny): - self.create_grids((nx, ny), p.device) - - # p.view(bs, 255, 13, 13) -- > (bs, 3, 13, 13, 85) # (bs, anchors, grid, grid, classes + xywh) - p = p.view(bs, self.na, self.no, self.ny, self.nx).permute(0, 1, 3, 4, 2).contiguous() # prediction - - if self.training: - return p - - elif ONNX_EXPORT: - # Avoid broadcasting for ANE operations - m = self.na * self.nx * self.ny - ng = 1. / self.ng.repeat(m, 1) - grid = self.grid.repeat(1, self.na, 1, 1, 1).view(m, 2) - anchor_wh = self.anchor_wh.repeat(1, 1, self.nx, self.ny, 1).view(m, 2) * ng - - p = p.view(m, self.no) - xy = torch.sigmoid(p[:, 0:2]) + grid # x, y - wh = torch.exp(p[:, 2:4]) * anchor_wh # width, height - p_cls = torch.sigmoid(p[:, 4:5]) if self.nc == 1 else \ - torch.sigmoid(p[:, 5:self.no]) * torch.sigmoid(p[:, 4:5]) # conf - return p_cls, xy * ng, wh - - else: # inference - #io = p.sigmoid() - #io[..., :2] = (io[..., :2] * 2. - 0.5 + self.grid) - #io[..., 2:4] = (io[..., 2:4] * 2) ** 2 * self.anchor_wh - #io[..., :4] *= self.stride - io = p.clone() # inference output - io[..., :2] = torch.sigmoid(io[..., :2]) * 2. - 0.5 + self.grid # xy - io[..., 2:4] = (torch.sigmoid(io[..., 2:4]) * 2) ** 2 * self.anchor_wh # wh yolo method - io[..., :4] *= self.stride - io[..., 4:] = F.softmax(io[..., 4:]) - return io.view(bs, -1, self.no), p # view [1, 3, 13, 13, 85] as [1, 507, 85] - -class Darknet(nn.Module): - # YOLOv3 object detection model - - def __init__(self, cfg, img_size=(416, 416), verbose=False): - super(Darknet, self).__init__() - - self.module_defs = parse_model_cfg(cfg) - self.module_list, self.routs = create_modules(self.module_defs, img_size, cfg) - self.yolo_layers = get_yolo_layers(self) - # torch_utils.initialize_weights(self) - - # Darknet Header https://github.com/AlexeyAB/darknet/issues/2914#issuecomment-496675346 - self.version = np.array([0, 2, 5], dtype=np.int32) # (int32) version info: major, minor, revision - self.seen = np.array([0], dtype=np.int64) # (int64) number of images seen during training - self.info(verbose) if not ONNX_EXPORT else None # print model description - - def forward(self, x, augment=False, verbose=False): - - if not augment: - return self.forward_once(x) - else: # Augment images (inference and test only) https://github.com/ultralytics/yolov3/issues/931 - img_size = x.shape[-2:] # height, width - s = [0.83, 0.67] # scales - y = [] - for i, xi in enumerate((x, - torch_utils.scale_img(x.flip(3), s[0], same_shape=False), # flip-lr and scale - torch_utils.scale_img(x, s[1], same_shape=False), # scale - )): - # cv2.imwrite('img%g.jpg' % i, 255 * xi[0].numpy().transpose((1, 2, 0))[:, :, ::-1]) - y.append(self.forward_once(xi)[0]) - - y[1][..., :4] /= s[0] # scale - y[1][..., 0] = img_size[1] - y[1][..., 0] # flip lr - y[2][..., :4] /= s[1] # scale - - # for i, yi in enumerate(y): # coco small, medium, large = < 32**2 < 96**2 < - # area = yi[..., 2:4].prod(2)[:, :, None] - # if i == 1: - # yi *= (area < 96. ** 2).float() - # elif i == 2: - # yi *= (area > 32. ** 2).float() - # y[i] = yi - - y = torch.cat(y, 1) - return y, None - - def forward_once(self, x, augment=False, verbose=False): - img_size = x.shape[-2:] # height, width - yolo_out, out = [], [] - if verbose: - print('0', x.shape) - str = '' - - # Augment images (inference and test only) - if augment: # https://github.com/ultralytics/yolov3/issues/931 - nb = x.shape[0] # batch size - s = [0.83, 0.67] # scales - x = torch.cat((x, - torch_utils.scale_img(x.flip(3), s[0]), # flip-lr and scale - torch_utils.scale_img(x, s[1]), # scale - ), 0) - - for i, module in enumerate(self.module_list): - name = module.__class__.__name__ - #print(name) - if name in ['WeightedFeatureFusion', 'FeatureConcat', 'FeatureConcat2', 'FeatureConcat3', 'FeatureConcat_l', 'ScaleChannel', 'ShiftChannel', 'ShiftChannel2D', 'ControlChannel', 'ControlChannel2D', 'AlternateChannel', 'AlternateChannel2D', 'SelectChannel', 'SelectChannel2D', 'ScaleSpatial']: # sum, concat - if verbose: - l = [i - 1] + module.layers # layers - sh = [list(x.shape)] + [list(out[i].shape) for i in module.layers] # shapes - str = ' >> ' + ' + '.join(['layer %g %s' % x for x in zip(l, sh)]) - x = module(x, out) # WeightedFeatureFusion(), FeatureConcat() - elif name in ['ImplicitA', 'ImplicitM', 'ImplicitC', 'Implicit2DA', 'Implicit2DM', 'Implicit2DC']: - x = module() - elif name == 'YOLOLayer': - yolo_out.append(module(x, out)) - elif name == 'JDELayer': - yolo_out.append(module(x, out)) - else: # run module directly, i.e. mtype = 'convolutional', 'upsample', 'maxpool', 'batchnorm2d' etc. - #print(module) - #print(x.shape) - x = module(x) - - out.append(x if self.routs[i] else []) - if verbose: - print('%g/%g %s -' % (i, len(self.module_list), name), list(x.shape), str) - str = '' - - if self.training: # train - return yolo_out - elif ONNX_EXPORT: # export - x = [torch.cat(x, 0) for x in zip(*yolo_out)] - return x[0], torch.cat(x[1:3], 1) # scores, boxes: 3780x80, 3780x4 - else: # inference or test - x, p = zip(*yolo_out) # inference output, training output - x = torch.cat(x, 1) # cat yolo outputs - if augment: # de-augment results - x = torch.split(x, nb, dim=0) - x[1][..., :4] /= s[0] # scale - x[1][..., 0] = img_size[1] - x[1][..., 0] # flip lr - x[2][..., :4] /= s[1] # scale - x = torch.cat(x, 1) - return x, p - - def fuse(self): - # Fuse Conv2d + BatchNorm2d layers throughout model - print('Fusing layers...') - fused_list = nn.ModuleList() - for a in list(self.children())[0]: - if isinstance(a, nn.Sequential): - for i, b in enumerate(a): - if isinstance(b, nn.modules.batchnorm.BatchNorm2d): - # fuse this bn layer with the previous conv2d layer - conv = a[i - 1] - fused = torch_utils.fuse_conv_and_bn(conv, b) - a = nn.Sequential(fused, *list(a.children())[i + 1:]) - break - fused_list.append(a) - self.module_list = fused_list - self.info() if not ONNX_EXPORT else None # yolov3-spp reduced from 225 to 152 layers - - def info(self, verbose=False): - torch_utils.model_info(self, verbose) - - -def get_yolo_layers(model): - return [i for i, m in enumerate(model.module_list) if m.__class__.__name__ in ['YOLOLayer', 'JDELayer']] # [89, 101, 113] - - -def load_darknet_weights(self, weights, cutoff=-1): - # Parses and loads the weights stored in 'weights' - - # Establish cutoffs (load layers between 0 and cutoff. if cutoff = -1 all are loaded) - file = Path(weights).name - if file == 'darknet53.conv.74': - cutoff = 75 - elif file == 'yolov3-tiny.conv.15': - cutoff = 15 - - # Read weights file - with open(weights, 'rb') as f: - # Read Header https://github.com/AlexeyAB/darknet/issues/2914#issuecomment-496675346 - self.version = np.fromfile(f, dtype=np.int32, count=3) # (int32) version info: major, minor, revision - self.seen = np.fromfile(f, dtype=np.int64, count=1) # (int64) number of images seen during training - - weights = np.fromfile(f, dtype=np.float32) # the rest are weights - - ptr = 0 - for i, (mdef, module) in enumerate(zip(self.module_defs[:cutoff], self.module_list[:cutoff])): - if mdef['type'] == 'convolutional': - conv = module[0] - if mdef['batch_normalize']: - # Load BN bias, weights, running mean and running variance - bn = module[1] - nb = bn.bias.numel() # number of biases - # Bias - bn.bias.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.bias)) - ptr += nb - # Weight - bn.weight.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.weight)) - ptr += nb - # Running Mean - bn.running_mean.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.running_mean)) - ptr += nb - # Running Var - bn.running_var.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.running_var)) - ptr += nb - else: - # Load conv. bias - nb = conv.bias.numel() - conv_b = torch.from_numpy(weights[ptr:ptr + nb]).view_as(conv.bias) - conv.bias.data.copy_(conv_b) - ptr += nb - # Load conv. weights - nw = conv.weight.numel() # number of weights - conv.weight.data.copy_(torch.from_numpy(weights[ptr:ptr + nw]).view_as(conv.weight)) - ptr += nw - - -def save_weights(self, path='model.weights', cutoff=-1): - # Converts a PyTorch model to Darket format (*.pt to *.weights) - # Note: Does not work if model.fuse() is applied - with open(path, 'wb') as f: - # Write Header https://github.com/AlexeyAB/darknet/issues/2914#issuecomment-496675346 - self.version.tofile(f) # (int32) version info: major, minor, revision - self.seen.tofile(f) # (int64) number of images seen during training - - # Iterate through layers - for i, (mdef, module) in enumerate(zip(self.module_defs[:cutoff], self.module_list[:cutoff])): - if mdef['type'] == 'convolutional': - conv_layer = module[0] - # If batch norm, load bn first - if mdef['batch_normalize']: - bn_layer = module[1] - bn_layer.bias.data.cpu().numpy().tofile(f) - bn_layer.weight.data.cpu().numpy().tofile(f) - bn_layer.running_mean.data.cpu().numpy().tofile(f) - bn_layer.running_var.data.cpu().numpy().tofile(f) - # Load conv bias - else: - conv_layer.bias.data.cpu().numpy().tofile(f) - # Load conv weights - conv_layer.weight.data.cpu().numpy().tofile(f) - - -def convert(cfg='cfg/yolov3-spp.cfg', weights='weights/yolov3-spp.weights', saveto='converted.weights'): - # Converts between PyTorch and Darknet format per extension (i.e. *.weights convert to *.pt and vice versa) - # from models import *; convert('cfg/yolov3-spp.cfg', 'weights/yolov3-spp.weights') - - # Initialize model - model = Darknet(cfg) - ckpt = torch.load(weights) # load checkpoint - try: - ckpt['model'] = {k: v for k, v in ckpt['model'].items() if model.state_dict()[k].numel() == v.numel()} - model.load_state_dict(ckpt['model'], strict=False) - save_weights(model, path=saveto, cutoff=-1) - except KeyError as e: - print(e) - -def attempt_download(weights): - # Attempt to download pretrained weights if not found locally - weights = weights.strip() - msg = weights + ' missing, try downloading from https://drive.google.com/open?id=1LezFG5g3BCW6iYaV89B2i64cqEUZD7e0' - - if len(weights) > 0 and not os.path.isfile(weights): - d = {''} - - file = Path(weights).name - if file in d: - r = gdrive_download(id=d[file], name=weights) - else: # download from pjreddie.com - url = 'https://pjreddie.com/media/files/' + file - print('Downloading ' + url) - r = os.system('curl -f ' + url + ' -o ' + weights) - - # Error check - if not (r == 0 and os.path.exists(weights) and os.path.getsize(weights) > 1E6): # weights exist and > 1MB - os.system('rm ' + weights) # remove partial downloads - raise Exception(msg) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 utils.google_utils import * +from utils.layers import * +from utils.parse_config import * +from utils import torch_utils + +ONNX_EXPORT = False + + +def create_modules(module_defs, img_size, cfg): + # Constructs module list of layer blocks from module configuration in module_defs + + img_size = [img_size] * 2 if isinstance(img_size, int) else img_size # expand if necessary + _ = module_defs.pop(0) # cfg training hyperparams (unused) + output_filters = [3] # input channels + module_list = nn.ModuleList() + routs = [] # list of layers which rout to deeper layers + yolo_index = -1 + + for i, mdef in enumerate(module_defs): + modules = nn.Sequential() + + if mdef['type'] == 'convolutional': + bn = mdef['batch_normalize'] + filters = mdef['filters'] + k = mdef['size'] # kernel size + stride = mdef['stride'] if 'stride' in mdef else (mdef['stride_y'], mdef['stride_x']) + if isinstance(k, int): # single-size conv + modules.add_module('Conv2d', nn.Conv2d(in_channels=output_filters[-1], + out_channels=filters, + kernel_size=k, + stride=stride, + padding=k // 2 if mdef['pad'] else 0, + groups=mdef['groups'] if 'groups' in mdef else 1, + bias=not bn)) + else: # multiple-size conv + modules.add_module('MixConv2d', MixConv2d(in_ch=output_filters[-1], + out_ch=filters, + k=k, + stride=stride, + bias=not bn)) + + if bn: + modules.add_module('BatchNorm2d', nn.BatchNorm2d(filters, momentum=0.03, eps=1E-4)) + else: + routs.append(i) # detection output (goes into yolo layer) + + if mdef['activation'] == 'leaky': # activation study https://github.com/ultralytics/yolov3/issues/441 + modules.add_module('activation', nn.LeakyReLU(0.1, inplace=True)) + elif mdef['activation'] == 'swish': + modules.add_module('activation', Swish()) + elif mdef['activation'] == 'mish': + modules.add_module('activation', Mish()) + elif mdef['activation'] == 'emb': + modules.add_module('activation', F.normalize()) + elif mdef['activation'] == 'logistic': + modules.add_module('activation', nn.Sigmoid()) + elif mdef['activation'] == 'silu': + modules.add_module('activation', nn.SiLU()) + + elif mdef['type'] == 'deformableconvolutional': + bn = mdef['batch_normalize'] + filters = mdef['filters'] + k = mdef['size'] # kernel size + stride = mdef['stride'] if 'stride' in mdef else (mdef['stride_y'], mdef['stride_x']) + if isinstance(k, int): # single-size conv + modules.add_module('DeformConv2d', DeformConv2d(output_filters[-1], + filters, + kernel_size=k, + padding=k // 2 if mdef['pad'] else 0, + stride=stride, + bias=not bn, + modulation=True)) + else: # multiple-size conv + modules.add_module('MixConv2d', MixConv2d(in_ch=output_filters[-1], + out_ch=filters, + k=k, + stride=stride, + bias=not bn)) + + if bn: + modules.add_module('BatchNorm2d', nn.BatchNorm2d(filters, momentum=0.03, eps=1E-4)) + else: + routs.append(i) # detection output (goes into yolo layer) + + if mdef['activation'] == 'leaky': # activation study https://github.com/ultralytics/yolov3/issues/441 + modules.add_module('activation', nn.LeakyReLU(0.1, inplace=True)) + elif mdef['activation'] == 'swish': + modules.add_module('activation', Swish()) + elif mdef['activation'] == 'mish': + modules.add_module('activation', Mish()) + elif mdef['activation'] == 'silu': + modules.add_module('activation', nn.SiLU()) + + elif mdef['type'] == 'dropout': + p = mdef['probability'] + modules = nn.Dropout(p) + + elif mdef['type'] == 'avgpool': + modules = GAP() + + elif mdef['type'] == 'silence': + filters = output_filters[-1] + modules = Silence() + + elif mdef['type'] == 'scale_channels': # nn.Sequential() placeholder for 'shortcut' layer + layers = mdef['from'] + filters = output_filters[-1] + routs.extend([i + l if l < 0 else l for l in layers]) + modules = ScaleChannel(layers=layers) + + elif mdef['type'] == 'shift_channels': # nn.Sequential() placeholder for 'shortcut' layer + layers = mdef['from'] + filters = output_filters[-1] + routs.extend([i + l if l < 0 else l for l in layers]) + modules = ShiftChannel(layers=layers) + + elif mdef['type'] == 'shift_channels_2d': # nn.Sequential() placeholder for 'shortcut' layer + layers = mdef['from'] + filters = output_filters[-1] + routs.extend([i + l if l < 0 else l for l in layers]) + modules = ShiftChannel2D(layers=layers) + + elif mdef['type'] == 'control_channels': # nn.Sequential() placeholder for 'shortcut' layer + layers = mdef['from'] + filters = output_filters[-1] + routs.extend([i + l if l < 0 else l for l in layers]) + modules = ControlChannel(layers=layers) + + elif mdef['type'] == 'control_channels_2d': # nn.Sequential() placeholder for 'shortcut' layer + layers = mdef['from'] + filters = output_filters[-1] + routs.extend([i + l if l < 0 else l for l in layers]) + modules = ControlChannel2D(layers=layers) + + elif mdef['type'] == 'alternate_channels': # nn.Sequential() placeholder for 'shortcut' layer + layers = mdef['from'] + filters = output_filters[-1] * 2 + routs.extend([i + l if l < 0 else l for l in layers]) + modules = AlternateChannel(layers=layers) + + elif mdef['type'] == 'alternate_channels_2d': # nn.Sequential() placeholder for 'shortcut' layer + layers = mdef['from'] + filters = output_filters[-1] * 2 + routs.extend([i + l if l < 0 else l for l in layers]) + modules = AlternateChannel2D(layers=layers) + + elif mdef['type'] == 'select_channels': # nn.Sequential() placeholder for 'shortcut' layer + layers = mdef['from'] + filters = output_filters[-1] + routs.extend([i + l if l < 0 else l for l in layers]) + modules = SelectChannel(layers=layers) + + elif mdef['type'] == 'select_channels_2d': # nn.Sequential() placeholder for 'shortcut' layer + layers = mdef['from'] + filters = output_filters[-1] + routs.extend([i + l if l < 0 else l for l in layers]) + modules = SelectChannel2D(layers=layers) + + elif mdef['type'] == 'sam': # nn.Sequential() placeholder for 'shortcut' layer + layers = mdef['from'] + filters = output_filters[-1] + routs.extend([i + l if l < 0 else l for l in layers]) + modules = ScaleSpatial(layers=layers) + + elif mdef['type'] == 'BatchNorm2d': + filters = output_filters[-1] + modules = nn.BatchNorm2d(filters, momentum=0.03, eps=1E-4) + if i == 0 and filters == 3: # normalize RGB image + # imagenet mean and var https://pytorch.org/docs/stable/torchvision/models.html#classification + modules.running_mean = torch.tensor([0.485, 0.456, 0.406]) + modules.running_var = torch.tensor([0.0524, 0.0502, 0.0506]) + + elif mdef['type'] == 'maxpool': + k = mdef['size'] # kernel size + stride = mdef['stride'] + maxpool = nn.MaxPool2d(kernel_size=k, stride=stride, padding=(k - 1) // 2) + if k == 2 and stride == 1: # yolov3-tiny + modules.add_module('ZeroPad2d', nn.ZeroPad2d((0, 1, 0, 1))) + modules.add_module('MaxPool2d', maxpool) + else: + modules = maxpool + + elif mdef['type'] == 'local_avgpool': + k = mdef['size'] # kernel size + stride = mdef['stride'] + avgpool = nn.AvgPool2d(kernel_size=k, stride=stride, padding=(k - 1) // 2) + if k == 2 and stride == 1: # yolov3-tiny + modules.add_module('ZeroPad2d', nn.ZeroPad2d((0, 1, 0, 1))) + modules.add_module('AvgPool2d', avgpool) + else: + modules = avgpool + + elif mdef['type'] == 'upsample': + if ONNX_EXPORT: # explicitly state size, avoid scale_factor + g = (yolo_index + 1) * 2 / 32 # gain + modules = nn.Upsample(size=tuple(int(x * g) for x in img_size)) # img_size = (320, 192) + else: + modules = nn.Upsample(scale_factor=mdef['stride']) + + elif mdef['type'] == 'route': # nn.Sequential() placeholder for 'route' layer + layers = mdef['layers'] + filters = sum([output_filters[l + 1 if l > 0 else l] for l in layers]) + routs.extend([i + l if l < 0 else l for l in layers]) + modules = FeatureConcat(layers=layers) + + elif mdef['type'] == 'route2': # nn.Sequential() placeholder for 'route' layer + layers = mdef['layers'] + filters = sum([output_filters[l + 1 if l > 0 else l] for l in layers]) + routs.extend([i + l if l < 0 else l for l in layers]) + modules = FeatureConcat2(layers=layers) + + elif mdef['type'] == 'route3': # nn.Sequential() placeholder for 'route' layer + layers = mdef['layers'] + filters = sum([output_filters[l + 1 if l > 0 else l] for l in layers]) + routs.extend([i + l if l < 0 else l for l in layers]) + modules = FeatureConcat3(layers=layers) + + elif mdef['type'] == 'route_lhalf': # nn.Sequential() placeholder for 'route' layer + layers = mdef['layers'] + filters = sum([output_filters[l + 1 if l > 0 else l] for l in layers])//2 + routs.extend([i + l if l < 0 else l for l in layers]) + modules = FeatureConcat_l(layers=layers) + + elif mdef['type'] == 'shortcut': # nn.Sequential() placeholder for 'shortcut' layer + layers = mdef['from'] + filters = output_filters[-1] + routs.extend([i + l if l < 0 else l for l in layers]) + modules = WeightedFeatureFusion(layers=layers, weight='weights_type' in mdef) + + elif mdef['type'] == 'reorg3d': # yolov3-spp-pan-scale + pass + + elif mdef['type'] == 'reorg': # yolov3-spp-pan-scale + filters = 4 * output_filters[-1] + modules.add_module('Reorg', Reorg()) + + elif mdef['type'] == 'dwt': # yolov3-spp-pan-scale + filters = 4 * output_filters[-1] + modules.add_module('DWT', DWT()) + + elif mdef['type'] == 'implicit_add': # yolov3-spp-pan-scale + filters = mdef['filters'] + modules = ImplicitA(channel=filters) + + elif mdef['type'] == 'implicit_mul': # yolov3-spp-pan-scale + filters = mdef['filters'] + modules = ImplicitM(channel=filters) + + elif mdef['type'] == 'implicit_cat': # yolov3-spp-pan-scale + filters = mdef['filters'] + modules = ImplicitC(channel=filters) + + elif mdef['type'] == 'implicit_add_2d': # yolov3-spp-pan-scale + channels = mdef['filters'] + filters = mdef['atoms'] + modules = Implicit2DA(atom=filters, channel=channels) + + elif mdef['type'] == 'implicit_mul_2d': # yolov3-spp-pan-scale + channels = mdef['filters'] + filters = mdef['atoms'] + modules = Implicit2DM(atom=filters, channel=channels) + + elif mdef['type'] == 'implicit_cat_2d': # yolov3-spp-pan-scale + channels = mdef['filters'] + filters = mdef['atoms'] + modules = Implicit2DC(atom=filters, channel=channels) + + elif mdef['type'] == 'yolo': + yolo_index += 1 + stride = [8, 16, 32, 64, 128] # P3, P4, P5, P6, P7 strides + if any(x in cfg for x in ['yolov4-tiny', 'fpn', 'yolov3']): # P5, P4, P3 strides + stride = [32, 16, 8] + layers = mdef['from'] if 'from' in mdef else [] + modules = YOLOLayer(anchors=mdef['anchors'][mdef['mask']], # anchor list + nc=mdef['classes'], # number of classes + img_size=img_size, # (416, 416) + yolo_index=yolo_index, # 0, 1, 2... + layers=layers, # output layers + stride=stride[yolo_index]) + + # Initialize preceding Conv2d() bias (https://arxiv.org/pdf/1708.02002.pdf section 3.3) + try: + j = layers[yolo_index] if 'from' in mdef else -2 + bias_ = module_list[j][0].bias # shape(255,) + bias = bias_[:modules.no * modules.na].view(modules.na, -1) # shape(3,85) + #bias[:, 4] += -4.5 # obj + bias.data[:, 4] += math.log(8 / (640 / stride[yolo_index]) ** 2) # obj (8 objects per 640 image) + bias.data[:, 5:] += math.log(0.6 / (modules.nc - 0.99)) # cls (sigmoid(p) = 1/nc) + module_list[j][0].bias = torch.nn.Parameter(bias_, requires_grad=bias_.requires_grad) + + #j = [-2, -5, -8] + #for sj in j: + # bias_ = module_list[sj][0].bias + # bias = bias_[:modules.no * 1].view(1, -1) + # bias.data[:, 4] += math.log(8 / (640 / stride[yolo_index]) ** 2) + # bias.data[:, 5:] += math.log(0.6 / (modules.nc - 0.99)) + # module_list[sj][0].bias = torch.nn.Parameter(bias_, requires_grad=bias_.requires_grad) + except: + print('WARNING: smart bias initialization failure.') + + elif mdef['type'] == 'jde': + yolo_index += 1 + stride = [8, 16, 32, 64, 128] # P3, P4, P5, P6, P7 strides + if any(x in cfg for x in ['yolov4-tiny', 'fpn', 'yolov3']): # P5, P4, P3 strides + stride = [32, 16, 8] + layers = mdef['from'] if 'from' in mdef else [] + modules = JDELayer(anchors=mdef['anchors'][mdef['mask']], # anchor list + nc=mdef['classes'], # number of classes + img_size=img_size, # (416, 416) + yolo_index=yolo_index, # 0, 1, 2... + layers=layers, # output layers + stride=stride[yolo_index]) + + # Initialize preceding Conv2d() bias (https://arxiv.org/pdf/1708.02002.pdf section 3.3) + try: + j = layers[yolo_index] if 'from' in mdef else -1 + bias_ = module_list[j][0].bias # shape(255,) + bias = bias_[:modules.no * modules.na].view(modules.na, -1) # shape(3,85) + #bias[:, 4] += -4.5 # obj + bias.data[:, 4] += math.log(8 / (640 / stride[yolo_index]) ** 2) # obj (8 objects per 640 image) + bias.data[:, 5:] += math.log(0.6 / (modules.nc - 0.99)) # cls (sigmoid(p) = 1/nc) + module_list[j][0].bias = torch.nn.Parameter(bias_, requires_grad=bias_.requires_grad) + except: + print('WARNING: smart bias initialization failure.') + + else: + print('Warning: Unrecognized Layer Type: ' + mdef['type']) + + # Register module list and number of output filters + module_list.append(modules) + output_filters.append(filters) + + routs_binary = [False] * (i + 1) + for i in routs: + routs_binary[i] = True + return module_list, routs_binary + + +class YOLOLayer(nn.Module): + def __init__(self, anchors, nc, img_size, yolo_index, layers, stride): + super(YOLOLayer, self).__init__() + self.anchors = torch.Tensor(anchors) + self.index = yolo_index # index of this layer in layers + self.layers = layers # model output layer indices + self.stride = stride # layer stride + self.nl = len(layers) # number of output layers (3) + self.na = len(anchors) # number of anchors (3) + self.nc = nc # number of classes (80) + self.no = nc + 5 # number of outputs (85) + self.nx, self.ny, self.ng = 0, 0, 0 # initialize number of x, y gridpoints + self.anchor_vec = self.anchors / self.stride + self.anchor_wh = self.anchor_vec.view(1, self.na, 1, 1, 2) + + if ONNX_EXPORT: + self.training = False + self.create_grids((img_size[1] // stride, img_size[0] // stride)) # number x, y grid points + + def create_grids(self, ng=(13, 13), device='cpu'): + self.nx, self.ny = ng # x and y grid size + self.ng = torch.tensor(ng, dtype=torch.float) + + # build xy offsets + if not self.training: + yv, xv = torch.meshgrid([torch.arange(self.ny, device=device), torch.arange(self.nx, device=device)]) + self.grid = torch.stack((xv, yv), 2).view((1, 1, self.ny, self.nx, 2)).float() + + if self.anchor_vec.device != device: + self.anchor_vec = self.anchor_vec.to(device) + self.anchor_wh = self.anchor_wh.to(device) + + def forward(self, p, out): + ASFF = False # https://arxiv.org/abs/1911.09516 + if ASFF: + i, n = self.index, self.nl # index in layers, number of layers + p = out[self.layers[i]] + bs, _, ny, nx = p.shape # bs, 255, 13, 13 + if (self.nx, self.ny) != (nx, ny): + self.create_grids((nx, ny), p.device) + + # outputs and weights + # w = F.softmax(p[:, -n:], 1) # normalized weights + w = torch.sigmoid(p[:, -n:]) * (2 / n) # sigmoid weights (faster) + # w = w / w.sum(1).unsqueeze(1) # normalize across layer dimension + + # weighted ASFF sum + p = out[self.layers[i]][:, :-n] * w[:, i:i + 1] + for j in range(n): + if j != i: + p += w[:, j:j + 1] * \ + F.interpolate(out[self.layers[j]][:, :-n], size=[ny, nx], mode='bilinear', align_corners=False) + + elif ONNX_EXPORT: + bs = 1 # batch size + else: + bs, _, ny, nx = p.shape # bs, 255, 13, 13 + if (self.nx, self.ny) != (nx, ny): + self.create_grids((nx, ny), p.device) + + # p.view(bs, 255, 13, 13) -- > (bs, 3, 13, 13, 85) # (bs, anchors, grid, grid, classes + xywh) + p = p.view(bs, self.na, self.no, self.ny, self.nx).permute(0, 1, 3, 4, 2).contiguous() # prediction + + if self.training: + return p + + elif ONNX_EXPORT: + # Avoid broadcasting for ANE operations + m = self.na * self.nx * self.ny + ng = 1. / self.ng.repeat(m, 1) + grid = self.grid.repeat(1, self.na, 1, 1, 1).view(m, 2) + anchor_wh = self.anchor_wh.repeat(1, 1, self.nx, self.ny, 1).view(m, 2) * ng + + p = p.view(m, self.no) + xy = torch.sigmoid(p[:, 0:2]) + grid # x, y + wh = torch.exp(p[:, 2:4]) * anchor_wh # width, height + p_cls = torch.sigmoid(p[:, 4:5]) if self.nc == 1 else \ + torch.sigmoid(p[:, 5:self.no]) * torch.sigmoid(p[:, 4:5]) # conf + return p_cls, xy * ng, wh + + else: # inference + io = p.sigmoid() + io[..., :2] = (io[..., :2] * 2. - 0.5 + self.grid) + io[..., 2:4] = (io[..., 2:4] * 2) ** 2 * self.anchor_wh + io[..., :4] *= self.stride + #io = p.clone() # inference output + #io[..., :2] = torch.sigmoid(io[..., :2]) + self.grid # xy + #io[..., 2:4] = torch.exp(io[..., 2:4]) * self.anchor_wh # wh yolo method + #io[..., :4] *= self.stride + #torch.sigmoid_(io[..., 4:]) + return io.view(bs, -1, self.no), p # view [1, 3, 13, 13, 85] as [1, 507, 85] + + +class JDELayer(nn.Module): + def __init__(self, anchors, nc, img_size, yolo_index, layers, stride): + super(JDELayer, self).__init__() + self.anchors = torch.Tensor(anchors) + self.index = yolo_index # index of this layer in layers + self.layers = layers # model output layer indices + self.stride = stride # layer stride + self.nl = len(layers) # number of output layers (3) + self.na = len(anchors) # number of anchors (3) + self.nc = nc # number of classes (80) + self.no = nc + 5 # number of outputs (85) + self.nx, self.ny, self.ng = 0, 0, 0 # initialize number of x, y gridpoints + self.anchor_vec = self.anchors / self.stride + self.anchor_wh = self.anchor_vec.view(1, self.na, 1, 1, 2) + + if ONNX_EXPORT: + self.training = False + self.create_grids((img_size[1] // stride, img_size[0] // stride)) # number x, y grid points + + def create_grids(self, ng=(13, 13), device='cpu'): + self.nx, self.ny = ng # x and y grid size + self.ng = torch.tensor(ng, dtype=torch.float) + + # build xy offsets + if not self.training: + yv, xv = torch.meshgrid([torch.arange(self.ny, device=device), torch.arange(self.nx, device=device)]) + self.grid = torch.stack((xv, yv), 2).view((1, 1, self.ny, self.nx, 2)).float() + + if self.anchor_vec.device != device: + self.anchor_vec = self.anchor_vec.to(device) + self.anchor_wh = self.anchor_wh.to(device) + + def forward(self, p, out): + ASFF = False # https://arxiv.org/abs/1911.09516 + if ASFF: + i, n = self.index, self.nl # index in layers, number of layers + p = out[self.layers[i]] + bs, _, ny, nx = p.shape # bs, 255, 13, 13 + if (self.nx, self.ny) != (nx, ny): + self.create_grids((nx, ny), p.device) + + # outputs and weights + # w = F.softmax(p[:, -n:], 1) # normalized weights + w = torch.sigmoid(p[:, -n:]) * (2 / n) # sigmoid weights (faster) + # w = w / w.sum(1).unsqueeze(1) # normalize across layer dimension + + # weighted ASFF sum + p = out[self.layers[i]][:, :-n] * w[:, i:i + 1] + for j in range(n): + if j != i: + p += w[:, j:j + 1] * \ + F.interpolate(out[self.layers[j]][:, :-n], size=[ny, nx], mode='bilinear', align_corners=False) + + elif ONNX_EXPORT: + bs = 1 # batch size + else: + bs, _, ny, nx = p.shape # bs, 255, 13, 13 + if (self.nx, self.ny) != (nx, ny): + self.create_grids((nx, ny), p.device) + + # p.view(bs, 255, 13, 13) -- > (bs, 3, 13, 13, 85) # (bs, anchors, grid, grid, classes + xywh) + p = p.view(bs, self.na, self.no, self.ny, self.nx).permute(0, 1, 3, 4, 2).contiguous() # prediction + + if self.training: + return p + + elif ONNX_EXPORT: + # Avoid broadcasting for ANE operations + m = self.na * self.nx * self.ny + ng = 1. / self.ng.repeat(m, 1) + grid = self.grid.repeat(1, self.na, 1, 1, 1).view(m, 2) + anchor_wh = self.anchor_wh.repeat(1, 1, self.nx, self.ny, 1).view(m, 2) * ng + + p = p.view(m, self.no) + xy = torch.sigmoid(p[:, 0:2]) + grid # x, y + wh = torch.exp(p[:, 2:4]) * anchor_wh # width, height + p_cls = torch.sigmoid(p[:, 4:5]) if self.nc == 1 else \ + torch.sigmoid(p[:, 5:self.no]) * torch.sigmoid(p[:, 4:5]) # conf + return p_cls, xy * ng, wh + + else: # inference + #io = p.sigmoid() + #io[..., :2] = (io[..., :2] * 2. - 0.5 + self.grid) + #io[..., 2:4] = (io[..., 2:4] * 2) ** 2 * self.anchor_wh + #io[..., :4] *= self.stride + io = p.clone() # inference output + io[..., :2] = torch.sigmoid(io[..., :2]) * 2. - 0.5 + self.grid # xy + io[..., 2:4] = (torch.sigmoid(io[..., 2:4]) * 2) ** 2 * self.anchor_wh # wh yolo method + io[..., :4] *= self.stride + io[..., 4:] = F.softmax(io[..., 4:]) + return io.view(bs, -1, self.no), p # view [1, 3, 13, 13, 85] as [1, 507, 85] + +class Darknet(nn.Module): + # YOLOv3 object detection model + + def __init__(self, cfg, img_size=(416, 416), verbose=False): + super(Darknet, self).__init__() + + self.module_defs = parse_model_cfg(cfg) + self.module_list, self.routs = create_modules(self.module_defs, img_size, cfg) + self.yolo_layers = get_yolo_layers(self) + # torch_utils.initialize_weights(self) + + # Darknet Header https://github.com/AlexeyAB/darknet/issues/2914#issuecomment-496675346 + self.version = np.array([0, 2, 5], dtype=np.int32) # (int32) version info: major, minor, revision + self.seen = np.array([0], dtype=np.int64) # (int64) number of images seen during training + self.info(verbose) if not ONNX_EXPORT else None # print model description + + def forward(self, x, augment=False, verbose=False): + + if not augment: + return self.forward_once(x) + else: # Augment images (inference and test only) https://github.com/ultralytics/yolov3/issues/931 + img_size = x.shape[-2:] # height, width + s = [0.83, 0.67] # scales + y = [] + for i, xi in enumerate((x, + torch_utils.scale_img(x.flip(3), s[0], same_shape=False), # flip-lr and scale + torch_utils.scale_img(x, s[1], same_shape=False), # scale + )): + # cv2.imwrite('img%g.jpg' % i, 255 * xi[0].numpy().transpose((1, 2, 0))[:, :, ::-1]) + y.append(self.forward_once(xi)[0]) + + y[1][..., :4] /= s[0] # scale + y[1][..., 0] = img_size[1] - y[1][..., 0] # flip lr + y[2][..., :4] /= s[1] # scale + + # for i, yi in enumerate(y): # coco small, medium, large = < 32**2 < 96**2 < + # area = yi[..., 2:4].prod(2)[:, :, None] + # if i == 1: + # yi *= (area < 96. ** 2).float() + # elif i == 2: + # yi *= (area > 32. ** 2).float() + # y[i] = yi + + y = torch.cat(y, 1) + return y, None + + def forward_once(self, x, augment=False, verbose=False): + img_size = x.shape[-2:] # height, width + yolo_out, out = [], [] + if verbose: + print('0', x.shape) + str = '' + + # Augment images (inference and test only) + if augment: # https://github.com/ultralytics/yolov3/issues/931 + nb = x.shape[0] # batch size + s = [0.83, 0.67] # scales + x = torch.cat((x, + torch_utils.scale_img(x.flip(3), s[0]), # flip-lr and scale + torch_utils.scale_img(x, s[1]), # scale + ), 0) + + for i, module in enumerate(self.module_list): + name = module.__class__.__name__ + #print(name) + if name in ['WeightedFeatureFusion', 'FeatureConcat', 'FeatureConcat2', 'FeatureConcat3', 'FeatureConcat_l', 'ScaleChannel', 'ShiftChannel', 'ShiftChannel2D', 'ControlChannel', 'ControlChannel2D', 'AlternateChannel', 'AlternateChannel2D', 'SelectChannel', 'SelectChannel2D', 'ScaleSpatial']: # sum, concat + if verbose: + l = [i - 1] + module.layers # layers + sh = [list(x.shape)] + [list(out[i].shape) for i in module.layers] # shapes + str = ' >> ' + ' + '.join(['layer %g %s' % x for x in zip(l, sh)]) + x = module(x, out) # WeightedFeatureFusion(), FeatureConcat() + elif name in ['ImplicitA', 'ImplicitM', 'ImplicitC', 'Implicit2DA', 'Implicit2DM', 'Implicit2DC']: + x = module() + elif name == 'YOLOLayer': + yolo_out.append(module(x, out)) + elif name == 'JDELayer': + yolo_out.append(module(x, out)) + else: # run module directly, i.e. mtype = 'convolutional', 'upsample', 'maxpool', 'batchnorm2d' etc. + #print(module) + #print(x.shape) + x = module(x) + + out.append(x if self.routs[i] else []) + if verbose: + print('%g/%g %s -' % (i, len(self.module_list), name), list(x.shape), str) + str = '' + + if self.training: # train + return yolo_out + elif ONNX_EXPORT: # export + x = [torch.cat(x, 0) for x in zip(*yolo_out)] + return x[0], torch.cat(x[1:3], 1) # scores, boxes: 3780x80, 3780x4 + else: # inference or test + x, p = zip(*yolo_out) # inference output, training output + x = torch.cat(x, 1) # cat yolo outputs + if augment: # de-augment results + x = torch.split(x, nb, dim=0) + x[1][..., :4] /= s[0] # scale + x[1][..., 0] = img_size[1] - x[1][..., 0] # flip lr + x[2][..., :4] /= s[1] # scale + x = torch.cat(x, 1) + return x, p + + def fuse(self): + # Fuse Conv2d + BatchNorm2d layers throughout model + print('Fusing layers...') + fused_list = nn.ModuleList() + for a in list(self.children())[0]: + if isinstance(a, nn.Sequential): + for i, b in enumerate(a): + if isinstance(b, nn.modules.batchnorm.BatchNorm2d): + # fuse this bn layer with the previous conv2d layer + conv = a[i - 1] + fused = torch_utils.fuse_conv_and_bn(conv, b) + a = nn.Sequential(fused, *list(a.children())[i + 1:]) + break + fused_list.append(a) + self.module_list = fused_list + self.info() if not ONNX_EXPORT else None # yolov3-spp reduced from 225 to 152 layers + + def info(self, verbose=False): + torch_utils.model_info(self, verbose) + + +def get_yolo_layers(model): + return [i for i, m in enumerate(model.module_list) if m.__class__.__name__ in ['YOLOLayer', 'JDELayer']] # [89, 101, 113] + + +def load_darknet_weights(self, weights, cutoff=-1): + # Parses and loads the weights stored in 'weights' + + # Establish cutoffs (load layers between 0 and cutoff. if cutoff = -1 all are loaded) + file = Path(weights).name + if file == 'darknet53.conv.74': + cutoff = 75 + elif file == 'yolov3-tiny.conv.15': + cutoff = 15 + + # Read weights file + with open(weights, 'rb') as f: + # Read Header https://github.com/AlexeyAB/darknet/issues/2914#issuecomment-496675346 + self.version = np.fromfile(f, dtype=np.int32, count=3) # (int32) version info: major, minor, revision + self.seen = np.fromfile(f, dtype=np.int64, count=1) # (int64) number of images seen during training + + weights = np.fromfile(f, dtype=np.float32) # the rest are weights + + ptr = 0 + for i, (mdef, module) in enumerate(zip(self.module_defs[:cutoff], self.module_list[:cutoff])): + if mdef['type'] == 'convolutional': + conv = module[0] + if mdef['batch_normalize']: + # Load BN bias, weights, running mean and running variance + bn = module[1] + nb = bn.bias.numel() # number of biases + # Bias + bn.bias.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.bias)) + ptr += nb + # Weight + bn.weight.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.weight)) + ptr += nb + # Running Mean + bn.running_mean.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.running_mean)) + ptr += nb + # Running Var + bn.running_var.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.running_var)) + ptr += nb + else: + # Load conv. bias + nb = conv.bias.numel() + conv_b = torch.from_numpy(weights[ptr:ptr + nb]).view_as(conv.bias) + conv.bias.data.copy_(conv_b) + ptr += nb + # Load conv. weights + nw = conv.weight.numel() # number of weights + conv.weight.data.copy_(torch.from_numpy(weights[ptr:ptr + nw]).view_as(conv.weight)) + ptr += nw + + +def save_weights(self, path='model.weights', cutoff=-1): + # Converts a PyTorch model to Darket format (*.pt to *.weights) + # Note: Does not work if model.fuse() is applied + with open(path, 'wb') as f: + # Write Header https://github.com/AlexeyAB/darknet/issues/2914#issuecomment-496675346 + self.version.tofile(f) # (int32) version info: major, minor, revision + self.seen.tofile(f) # (int64) number of images seen during training + + # Iterate through layers + for i, (mdef, module) in enumerate(zip(self.module_defs[:cutoff], self.module_list[:cutoff])): + if mdef['type'] == 'convolutional': + conv_layer = module[0] + # If batch norm, load bn first + if mdef['batch_normalize']: + bn_layer = module[1] + bn_layer.bias.data.cpu().numpy().tofile(f) + bn_layer.weight.data.cpu().numpy().tofile(f) + bn_layer.running_mean.data.cpu().numpy().tofile(f) + bn_layer.running_var.data.cpu().numpy().tofile(f) + # Load conv bias + else: + conv_layer.bias.data.cpu().numpy().tofile(f) + # Load conv weights + conv_layer.weight.data.cpu().numpy().tofile(f) + + +def convert(cfg='cfg/yolov3-spp.cfg', weights='weights/yolov3-spp.weights', saveto='converted.weights'): + # Converts between PyTorch and Darknet format per extension (i.e. *.weights convert to *.pt and vice versa) + # from models import *; convert('cfg/yolov3-spp.cfg', 'weights/yolov3-spp.weights') + + # Initialize model + model = Darknet(cfg) + ckpt = torch.load(weights) # load checkpoint + try: + ckpt['model'] = {k: v for k, v in ckpt['model'].items() if model.state_dict()[k].numel() == v.numel()} + model.load_state_dict(ckpt['model'], strict=False) + save_weights(model, path=saveto, cutoff=-1) + except KeyError as e: + print(e) + +def attempt_download(weights): + # Attempt to download pretrained weights if not found locally + weights = weights.strip() + msg = weights + ' missing, try downloading from https://drive.google.com/open?id=1LezFG5g3BCW6iYaV89B2i64cqEUZD7e0' + + if len(weights) > 0 and not os.path.isfile(weights): + d = {''} + + file = Path(weights).name + if file in d: + r = gdrive_download(id=d[file], name=weights) + else: # download from pjreddie.com + url = 'https://pjreddie.com/media/files/' + file + print('Downloading ' + url) + r = os.system('curl -f ' + url + ' -o ' + weights) + + # Error check + if not (r == 0 and os.path.exists(weights) and os.path.getsize(weights) > 1E6): # weights exist and > 1MB + os.system('rm ' + weights) # remove partial downloads + raise Exception(msg) diff --git a/PyTorch/contrib/cv/detection/YOLOR/requirements-GPU.txt b/PyTorch/contrib/cv/detection/YOLOR/requirements-GPU.txt index d62e7d20ea..c98049d877 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/requirements-GPU.txt +++ b/PyTorch/contrib/cv/detection/YOLOR/requirements-GPU.txt @@ -1,43 +1,43 @@ -# pip install -U -r requirements-GPU.txt - -# base ---------------------------------------- -Cython -numpy -opencv-python -torch>=1.5.0 -matplotlib -pillow -tensorboard -PyYAML>=5.3 -torchvision>=0.6 -scipy -tqdm -pycocotools>=2.0 - -# extras -------------------------------------- -# thop # FLOPS computation - -# logging ------------------------------------- -# wandb - -# plotting ------------------------------------ -# seaborn>=0.11.0 -# pandas - -# export -------------------------------------- -# coremltools>=4.1 -# onnx>=1.8.1 -# scikit-learn==0.19.2 # for coreml quantization - -# Nvidia Apex for mixed precision training -------------------------- -# git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex - -# Conda commands (in place of pip) --------------------------------------------- -# conda update -yn base -c defaults conda -# conda install -yc anaconda numpy opencv matplotlib tqdm pillow ipython -# conda install -yc conda-forge scikit-image pycocotools tensorboard -# conda install -yc spyder-ide spyder-line-profiler -# conda install -yc pytorch pytorch torchvision -# conda install -yc conda-forge protobuf numpy && pip install onnx==1.6.0 # https://github.com/onnx/onnx#linux-and-macos - - +# pip install -U -r requirements-GPU.txt + +# base ---------------------------------------- +Cython +numpy +opencv-python +torch>=1.5.0 +matplotlib +pillow +tensorboard +PyYAML>=5.3 +torchvision>=0.6 +scipy +tqdm +pycocotools>=2.0 + +# extras -------------------------------------- +# thop # FLOPS computation + +# logging ------------------------------------- +# wandb + +# plotting ------------------------------------ +# seaborn>=0.11.0 +# pandas + +# export -------------------------------------- +# coremltools>=4.1 +# onnx>=1.8.1 +# scikit-learn==0.19.2 # for coreml quantization + +# Nvidia Apex for mixed precision training -------------------------- +# git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex + +# Conda commands (in place of pip) --------------------------------------------- +# conda update -yn base -c defaults conda +# conda install -yc anaconda numpy opencv matplotlib tqdm pillow ipython +# conda install -yc conda-forge scikit-image pycocotools tensorboard +# conda install -yc spyder-ide spyder-line-profiler +# conda install -yc pytorch pytorch torchvision +# conda install -yc conda-forge protobuf numpy && pip install onnx==1.6.0 # https://github.com/onnx/onnx#linux-and-macos + + diff --git a/PyTorch/contrib/cv/detection/YOLOR/requirements.txt b/PyTorch/contrib/cv/detection/YOLOR/requirements.txt index 3e44475836..da9cc83a5a 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/requirements.txt +++ b/PyTorch/contrib/cv/detection/YOLOR/requirements.txt @@ -1,30 +1,30 @@ -# pip install -qr requirements.txt - -# base ---------------------------------------- -Cython -matplotlib -numpy -opencv-python -Pillow -PyYAML -scipy -tensorboard -tqdm -sympy>=1.8 -decorator>=5.0.9 -pycocotools>=2.0 # COCO mAP - -# extras -------------------------------------- -# thop # FLOPS computation - -# logging ------------------------------------- -# wandb - -# plotting ------------------------------------ -# seaborn>=0.11.0 -# pandas - -# export -------------------------------------- -# coremltools>=4.1 -# onnx>=1.8.1 -# scikit-learn==0.19.2 # for coreml quantization +# pip install -qr requirements.txt + +# base ---------------------------------------- +Cython +matplotlib +numpy +opencv-python +Pillow +PyYAML +scipy +tensorboard +tqdm +sympy>=1.8 +decorator>=5.0.9 +pycocotools>=2.0 # COCO mAP + +# extras -------------------------------------- +# thop # FLOPS computation + +# logging ------------------------------------- +# wandb + +# plotting ------------------------------------ +# seaborn>=0.11.0 +# pandas + +# export -------------------------------------- +# coremltools>=4.1 +# onnx>=1.8.1 +# scikit-learn==0.19.2 # for coreml quantization diff --git a/PyTorch/contrib/cv/detection/YOLOR/test.py b/PyTorch/contrib/cv/detection/YOLOR/test.py index 614f167330..4fe2c17ef7 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/test.py +++ b/PyTorch/contrib/cv/detection/YOLOR/test.py @@ -1,378 +1,378 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import glob -import json -import os -from pathlib import Path - -import numpy as np -import torch -import yaml -from tqdm import tqdm - -from utils.datasets import create_dataloader -from utils.general import coco80_to_coco91_class, check_dataset, check_file, check_img_size, box_iou, \ - non_max_suppression, scale_coords, xyxy2xywh, xywh2xyxy, clip_coords, set_logging, increment_path -from utils.loss import compute_loss -from utils.metrics import ap_per_class -from utils.plots import plot_images, output_to_target -from utils.torch_utils import select_device, time_synchronized - -from models.models import * -from apex import amp - -def load_classes(path): - # Loads *.names file at 'path' - with open(path, 'r') as f: - names = f.read().split('\n') - return list(filter(None, names)) # filter removes empty strings (such as last line) - - -def set_seed_everything(seed): - random.seed(seed) - os.environ['PYTHONHASHSEED'] = str(seed) - np.random.seed(seed) - torch.manual_seed(seed) - torch.cuda.manual_seed(seed) - torch.cuda.manual_seed_all(seed) - torch.backends.cudnn.deterministic = True - torch.backends.cudnn.benchmark = False - - -def test(data, - weights=None, - batch_size=16, - imgsz=640, - conf_thres=0.001, - iou_thres=0.6, # for NMS - save_json=False, - single_cls=False, - augment=False, - verbose=False, - model=None, - dataloader=None, - save_dir=Path(''), # for saving images - save_txt=False, # for auto-labelling - save_conf=False, - plots=True, - log_imgs=0): # number of logged images - - # Initialize/load model and set device - # set_seed_everything(1234) - training = model is not None - if training: # called by train.py - device = next(model.parameters()).device # get model device - else: # called directly - set_logging() - device = select_device(opt.device, opt.npu, batch_size=batch_size) - save_txt = opt.save_txt # save *.txt labels - - # Directories - save_dir = Path(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)) # increment run - (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir - - # Load model - model = Darknet(opt.cfg).to(device) - - # load model - try: - ckpt = torch.load(weights[0], map_location=device) # load checkpoint - ckpt['model'] = {k: v for k, v in ckpt['model'].items() if model.state_dict()[k].numel() == v.numel()} - model.load_state_dict(ckpt['model'], strict=False) - except: - load_darknet_weights(model, weights[0]) - - imgsz = check_img_size(imgsz, s=64) # check img_size - - model = amp.initialize(model, opt_level='O1', verbosity=0, loss_scale=64) - - # Half - half = device.type != 'cpu' # half precision only supported on CUDA - if half: - model.half() - - # Configure - model.eval() - is_coco = data.endswith('coco.yaml') # is COCO dataset - with open(data) as f: - data = yaml.load(f, Loader=yaml.FullLoader) # model dict - check_dataset(data) # check - nc = 1 if single_cls else int(data['nc']) # number of classes - iouv = torch.linspace(0.5, 0.95, 10) # iou vector for mAP@0.5:0.95 - niou = iouv.numel() - - # ---------------------------------not using wandb--------------------------------- - # Logging - log_imgs, wandb = min(log_imgs, 100), None # ceil - # try: - # import wandb # Weights & Biases - # except ImportError: - log_imgs = 0 - # ---------------------------------not using wandb--------------------------------- - - # Dataloader - if not training: - img = torch.zeros((1, 3, imgsz, imgsz), device=device) # init img - _ = model(img.half() if half else img) if device.type != 'cpu' else None # run once - path = data['test'] if opt.task == 'test' else data['val'] # path to val/test images - dataloader = create_dataloader(path, imgsz, batch_size, 64, opt, - hyp=None, augment=False, cache=False, pad=0.5, rect=True)[0] - - seen = 0 - try: - names = model.names if hasattr(model, 'names') else model.module.names - except: - names = load_classes(opt.names) - coco91class = coco80_to_coco91_class() - s = ('%20s' + '%12s' * 6) % ('Class', 'Images', 'Targets', 'P', 'R', 'mAP@.5', 'mAP@.5:.95') - p, r, f1, mp, mr, map50, map, t0, t1 = 0., 0., 0., 0., 0., 0., 0., 0., 0. - loss = torch.zeros(3, device=device) - jdict, stats, ap, ap_class, wandb_images = [], [], [], [], [] - - pbar = tqdm(dataloader) - for batch_i, (img, targets, paths, shapes) in enumerate(pbar): - img = img.to(device, non_blocking=True) - img = img.half() if half else img.float() # uint8 to fp16/32 - img /= 255.0 # 0 - 255 to 0.0 - 1.0 - targets = targets.to(device) - nb, _, height, width = img.shape # batch size, channels, height, width - whwh = torch.Tensor([width, height, width, height]) - - # Disable gradients - with torch.no_grad(): - # Run model - t = time_synchronized() - inf_out, _ = model(img, augment=augment) # inference and training outputs - t0 += time_synchronized() - t - - # Compute loss / no test during training - # if training: # if model has loss hyperparameters - # loss += compute_loss([x.float() for x in train_out], targets, model)[1][:3] # box, obj, cls - - # Run NMS - t = time_synchronized() - output = non_max_suppression(inf_out, conf_thres=conf_thres, iou_thres=iou_thres) - t1 += time_synchronized() - t - targets = targets.cpu() - - # Statistics per image - for si, pred in enumerate(output): - labels = targets[targets[:, 0] == si, 1:] - nl = len(labels) - tcls = labels[:, 0].tolist() if nl else [] # target class - seen += 1 - - if len(pred) == 0: - if nl: - stats.append((torch.zeros(0, niou, dtype=torch.bool), torch.Tensor(), torch.Tensor(), tcls)) - continue - - # Append to text file - path = Path(paths[si]) - if save_txt: - gn = torch.tensor(shapes[si][0])[[1, 0, 1, 0]] # normalization gain whwh - x = pred.clone() - x[:, :4] = scale_coords(img[si].shape[1:], x[:, :4], shapes[si][0], shapes[si][1]) # to original - for *xyxy, conf, cls in x: - xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh - line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format - with open(save_dir / 'labels' / (path.stem + '.txt'), 'a') as f: - f.write(('%g ' * len(line)).rstrip() % line + '\n') - - # W&B logging - if plots and len(wandb_images) < log_imgs: - box_data = [{"position": {"minX": xyxy[0], "minY": xyxy[1], "maxX": xyxy[2], "maxY": xyxy[3]}, - "class_id": int(cls), - "box_caption": "%s %.3f" % (names[cls], conf), - "scores": {"class_score": conf}, - "domain": "pixel"} for *xyxy, conf, cls in pred.tolist()] - boxes = {"predictions": {"box_data": box_data, "class_labels": names}} - wandb_images.append(wandb.Image(img[si], boxes=boxes, caption=path.name)) - - # Clip boxes to image bounds - clip_coords(pred, (height, width)) - - # Append to pycocotools JSON dictionary - if save_json: - # [{"image_id": 42, "category_id": 18, "bbox": [258.15, 41.29, 348.26, 243.78], "score": 0.236}, ... - image_id = int(path.stem) if path.stem.isnumeric() else path.stem - box = pred[:, :4].clone() # xyxy - scale_coords(img[si].shape[1:], box, shapes[si][0], shapes[si][1]) # to original shape - box = xyxy2xywh(box) # xywh - box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner - for p, b in zip(pred.tolist(), box.tolist()): - jdict.append({'image_id': image_id, - 'category_id': coco91class[int(p[5])] if is_coco else int(p[5]), - 'bbox': [round(x, 3) for x in b], - 'score': round(p[4], 5)}) - - # Assign all predictions as incorrect - correct = torch.zeros(pred.shape[0], niou, dtype=torch.bool) - if nl: - detected = [] # target indices - tcls_tensor = labels[:, 0] - - # target boxes - tbox = xywh2xyxy(labels[:, 1:5]) * whwh - - # Per target class - for cls in torch.unique(tcls_tensor): - ti = (cls == tcls_tensor).nonzero(as_tuple=False).view(-1) # prediction indices - pi = (cls == pred[:, 5]).nonzero(as_tuple=False).view(-1) # target indices - - # Search for detections - if pi.shape[0]: - # Prediction to target ious - ious, i = box_iou(pred[pi, :4], tbox[ti]).max(1) # best ious, indices - - # Append detections - temp_nonzero_idx = (ious > iouv[0]).nonzero(as_tuple=False) - for j in temp_nonzero_idx: - d = ti[i[j]] # detected target - if d not in detected: - detected.append(d) - correct[pi[j]] = ious[j] > iouv # iou_thres is 1xn - if len(detected) == nl: # all targets already located in image - break - - # Append statistics (correct, conf, pcls, tcls) - stats.append((correct.cpu(), pred[:, 4].cpu(), pred[:, 5].cpu(), tcls)) - - # Plot images - if plots and batch_i < 3: - f = save_dir / f'{batch_i}_labels.jpg' # filename - plot_images(img, targets, paths, f, names) # labels - f = save_dir / f'{batch_i}_pred.jpg' - plot_images(img, output_to_target(output, width, height), paths, f, names) # predictions - - # Compute statistics - stats = [np.concatenate(x, 0) for x in zip(*stats)] # to numpy - if len(stats) and stats[0].any(): - p, r, ap, f1, ap_class = ap_per_class(*stats, plot=plots, fname=save_dir / 'precision-recall_curve.png') - p, r, ap50, ap = p[:, 0], r[:, 0], ap[:, 0], ap.mean(1) # [P, R, AP@0.5, AP@0.5:0.95] - mp, mr, map50, map = p.mean(), r.mean(), ap50.mean(), ap.mean() - nt = np.bincount(stats[3].astype(np.int64), minlength=nc) # number of targets per class - else: - nt = torch.zeros(1) - - # W&B logging - if plots and wandb: - wandb.log({"Images": wandb_images}) - wandb.log({"Validation": [wandb.Image(str(x), caption=x.name) for x in sorted(save_dir.glob('test*.jpg'))]}) - - # Print results - pf = '%20s' + '%12.3g' * 6 # print format - print(pf % ('all', seen, nt.sum(), mp, mr, map50, map)) - - # Print results per class - if verbose and nc > 1 and len(stats): - for i, c in enumerate(ap_class): - print(pf % (names[c], seen, nt[c], p[i], r[i], ap50[i], ap[i])) - - # Print speeds - t = tuple(x / seen * 1E3 for x in (t0, t1, t0 + t1)) + (imgsz, imgsz, batch_size) # tuple - if not training: - print('Speed: %.1f/%.1f/%.1f ms inference/NMS/total per %gx%g image at batch-size %g' % t) - - # Save JSON - if save_json and len(jdict): - w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights - anno_json = glob.glob('../data/coco/annotations/instances_val*.json')[0] # annotations json - pred_json = str(save_dir / f"{w}_predictions.json") # predictions json - print('\nEvaluating pycocotools mAP... saving %s...' % pred_json) - with open(pred_json, 'w') as f: - json.dump(jdict, f) - - try: # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb - from pycocotools.coco import COCO - from pycocotools.cocoeval import COCOeval - - anno = COCO(anno_json) # init annotations api - pred = anno.loadRes(pred_json) # init predictions api - eval = COCOeval(anno, pred, 'bbox') - if is_coco: - eval.params.imgIds = [int(Path(x).stem) for x in dataloader.dataset.img_files] # image IDs to evaluate - eval.evaluate() - eval.accumulate() - eval.summarize() - map, map50 = eval.stats[:2] # update results (mAP@0.5:0.95, mAP@0.5) - except Exception as e: - print('ERROR: pycocotools unable to run: %s' % e) - - # Return results - if not training: - print('Results saved to %s' % save_dir) - model.float() # for training - maps = np.zeros(nc) + map - for i, c in enumerate(ap_class): - maps[c] = ap[i] - return (mp, mr, map50, map, *(loss.cpu() / len(dataloader)).tolist()), maps, t - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(prog='test.py') - parser.add_argument('--weights', nargs='+', type=str, default='yolor_p6.pt', help='model.pt path(s)') - parser.add_argument('--data', type=str, default='data/coco.yaml', help='*.data path') - parser.add_argument('--batch-size', type=int, default=32, help='size of each image batch') - parser.add_argument('--img-size', type=int, default=1280, help='inference size (pixels)') - parser.add_argument('--conf-thres', type=float, default=0.001, help='object confidence threshold') - parser.add_argument('--iou-thres', type=float, default=0.65, help='IOU threshold for NMS') - parser.add_argument('--task', default='val', help="'val', 'test', 'study'") - parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') - parser.add_argument('--single-cls', action='store_true', help='treat as single-class dataset') - parser.add_argument('--augment', action='store_true', help='augmented inference') - parser.add_argument('--verbose', action='store_true', help='report mAP by class') - parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') - parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') - parser.add_argument('--save-json', action='store_true', help='save a cocoapi-compatible JSON results file') - parser.add_argument('--project', default='runs/test', help='save to project/name') - parser.add_argument('--name', default='exp', help='save to project/name') - parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') - parser.add_argument('--cfg', type=str, default='cfg/yolor_p6.cfg', help='*.cfg path') - parser.add_argument('--names', type=str, default='data/coco.names', help='*.cfg path') - parser.add_argument('--npu', default=None, type=int, help='NPU id to use.') - opt = parser.parse_args() - opt.save_json |= opt.data.endswith('coco.yaml') - opt.data = check_file(opt.data) # check file - print(opt) - - if opt.task in ['val', 'test']: # run normally - test(opt.data, - opt.weights, - opt.batch_size, - opt.img_size, - opt.conf_thres, - opt.iou_thres, - opt.save_json, - opt.single_cls, - opt.augment, - opt.verbose, - save_txt=opt.save_txt, - save_conf=opt.save_conf, - ) - - elif opt.task == 'study': # run over a range of settings and save/plot - for weights in ['yolor_p6.pt', 'yolor_w6.pt']: - f = 'study_%s_%s.txt' % (Path(opt.data).stem, Path(weights).stem) # filename to save to - x = list(range(320, 800, 64)) # x axis - y = [] # y axis - for i in x: # img-size - print('\nRunning %s point %s...' % (f, i)) - r, _, t = test(opt.data, weights, opt.batch_size, i, opt.conf_thres, opt.iou_thres, opt.save_json) - y.append(r + t) # results and times - np.savetxt(f, y, fmt='%10.4g') # save - os.system('zip -r study.zip study_*.txt') - # utils.general.plot_study_txt(f, x) # plot +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import glob +import json +import os +from pathlib import Path + +import numpy as np +import torch +import yaml +from tqdm import tqdm + +from utils.datasets import create_dataloader +from utils.general import coco80_to_coco91_class, check_dataset, check_file, check_img_size, box_iou, \ + non_max_suppression, scale_coords, xyxy2xywh, xywh2xyxy, clip_coords, set_logging, increment_path +from utils.loss import compute_loss +from utils.metrics import ap_per_class +from utils.plots import plot_images, output_to_target +from utils.torch_utils import select_device, time_synchronized + +from models.models import * +from apex import amp + +def load_classes(path): + # Loads *.names file at 'path' + with open(path, 'r') as f: + names = f.read().split('\n') + return list(filter(None, names)) # filter removes empty strings (such as last line) + + +def set_seed_everything(seed): + random.seed(seed) + os.environ['PYTHONHASHSEED'] = str(seed) + np.random.seed(seed) + torch.manual_seed(seed) + torch.cuda.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + torch.backends.cudnn.deterministic = True + torch.backends.cudnn.benchmark = False + + +def test(data, + weights=None, + batch_size=16, + imgsz=640, + conf_thres=0.001, + iou_thres=0.6, # for NMS + save_json=False, + single_cls=False, + augment=False, + verbose=False, + model=None, + dataloader=None, + save_dir=Path(''), # for saving images + save_txt=False, # for auto-labelling + save_conf=False, + plots=True, + log_imgs=0): # number of logged images + + # Initialize/load model and set device + # set_seed_everything(1234) + training = model is not None + if training: # called by train.py + device = next(model.parameters()).device # get model device + else: # called directly + set_logging() + device = select_device(opt.device, opt.npu, batch_size=batch_size) + save_txt = opt.save_txt # save *.txt labels + + # Directories + save_dir = Path(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)) # increment run + (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + + # Load model + model = Darknet(opt.cfg).to(device) + + # load model + try: + ckpt = torch.load(weights[0], map_location=device) # load checkpoint + ckpt['model'] = {k: v for k, v in ckpt['model'].items() if model.state_dict()[k].numel() == v.numel()} + model.load_state_dict(ckpt['model'], strict=False) + except: + load_darknet_weights(model, weights[0]) + + imgsz = check_img_size(imgsz, s=64) # check img_size + + model = amp.initialize(model, opt_level='O1', verbosity=0, loss_scale=64) + + # Half + half = device.type != 'cpu' # half precision only supported on CUDA + if half: + model.half() + + # Configure + model.eval() + is_coco = data.endswith('coco.yaml') # is COCO dataset + with open(data) as f: + data = yaml.load(f, Loader=yaml.FullLoader) # model dict + check_dataset(data) # check + nc = 1 if single_cls else int(data['nc']) # number of classes + iouv = torch.linspace(0.5, 0.95, 10) # iou vector for mAP@0.5:0.95 + niou = iouv.numel() + + # ---------------------------------not using wandb--------------------------------- + # Logging + log_imgs, wandb = min(log_imgs, 100), None # ceil + # try: + # import wandb # Weights & Biases + # except ImportError: + log_imgs = 0 + # ---------------------------------not using wandb--------------------------------- + + # Dataloader + if not training: + img = torch.zeros((1, 3, imgsz, imgsz), device=device) # init img + _ = model(img.half() if half else img) if device.type != 'cpu' else None # run once + path = data['test'] if opt.task == 'test' else data['val'] # path to val/test images + dataloader = create_dataloader(path, imgsz, batch_size, 64, opt, + hyp=None, augment=False, cache=False, pad=0.5, rect=True)[0] + + seen = 0 + try: + names = model.names if hasattr(model, 'names') else model.module.names + except: + names = load_classes(opt.names) + coco91class = coco80_to_coco91_class() + s = ('%20s' + '%12s' * 6) % ('Class', 'Images', 'Targets', 'P', 'R', 'mAP@.5', 'mAP@.5:.95') + p, r, f1, mp, mr, map50, map, t0, t1 = 0., 0., 0., 0., 0., 0., 0., 0., 0. + loss = torch.zeros(3, device=device) + jdict, stats, ap, ap_class, wandb_images = [], [], [], [], [] + + pbar = tqdm(dataloader) + for batch_i, (img, targets, paths, shapes) in enumerate(pbar): + img = img.to(device, non_blocking=True) + img = img.half() if half else img.float() # uint8 to fp16/32 + img /= 255.0 # 0 - 255 to 0.0 - 1.0 + targets = targets.to(device) + nb, _, height, width = img.shape # batch size, channels, height, width + whwh = torch.Tensor([width, height, width, height]) + + # Disable gradients + with torch.no_grad(): + # Run model + t = time_synchronized() + inf_out, _ = model(img, augment=augment) # inference and training outputs + t0 += time_synchronized() - t + + # Compute loss / no test during training + # if training: # if model has loss hyperparameters + # loss += compute_loss([x.float() for x in train_out], targets, model)[1][:3] # box, obj, cls + + # Run NMS + t = time_synchronized() + output = non_max_suppression(inf_out, conf_thres=conf_thres, iou_thres=iou_thres) + t1 += time_synchronized() - t + targets = targets.cpu() + + # Statistics per image + for si, pred in enumerate(output): + labels = targets[targets[:, 0] == si, 1:] + nl = len(labels) + tcls = labels[:, 0].tolist() if nl else [] # target class + seen += 1 + + if len(pred) == 0: + if nl: + stats.append((torch.zeros(0, niou, dtype=torch.bool), torch.Tensor(), torch.Tensor(), tcls)) + continue + + # Append to text file + path = Path(paths[si]) + if save_txt: + gn = torch.tensor(shapes[si][0])[[1, 0, 1, 0]] # normalization gain whwh + x = pred.clone() + x[:, :4] = scale_coords(img[si].shape[1:], x[:, :4], shapes[si][0], shapes[si][1]) # to original + for *xyxy, conf, cls in x: + xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh + line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format + with open(save_dir / 'labels' / (path.stem + '.txt'), 'a') as f: + f.write(('%g ' * len(line)).rstrip() % line + '\n') + + # W&B logging + if plots and len(wandb_images) < log_imgs: + box_data = [{"position": {"minX": xyxy[0], "minY": xyxy[1], "maxX": xyxy[2], "maxY": xyxy[3]}, + "class_id": int(cls), + "box_caption": "%s %.3f" % (names[cls], conf), + "scores": {"class_score": conf}, + "domain": "pixel"} for *xyxy, conf, cls in pred.tolist()] + boxes = {"predictions": {"box_data": box_data, "class_labels": names}} + wandb_images.append(wandb.Image(img[si], boxes=boxes, caption=path.name)) + + # Clip boxes to image bounds + clip_coords(pred, (height, width)) + + # Append to pycocotools JSON dictionary + if save_json: + # [{"image_id": 42, "category_id": 18, "bbox": [258.15, 41.29, 348.26, 243.78], "score": 0.236}, ... + image_id = int(path.stem) if path.stem.isnumeric() else path.stem + box = pred[:, :4].clone() # xyxy + scale_coords(img[si].shape[1:], box, shapes[si][0], shapes[si][1]) # to original shape + box = xyxy2xywh(box) # xywh + box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner + for p, b in zip(pred.tolist(), box.tolist()): + jdict.append({'image_id': image_id, + 'category_id': coco91class[int(p[5])] if is_coco else int(p[5]), + 'bbox': [round(x, 3) for x in b], + 'score': round(p[4], 5)}) + + # Assign all predictions as incorrect + correct = torch.zeros(pred.shape[0], niou, dtype=torch.bool) + if nl: + detected = [] # target indices + tcls_tensor = labels[:, 0] + + # target boxes + tbox = xywh2xyxy(labels[:, 1:5]) * whwh + + # Per target class + for cls in torch.unique(tcls_tensor): + ti = (cls == tcls_tensor).nonzero(as_tuple=False).view(-1) # prediction indices + pi = (cls == pred[:, 5]).nonzero(as_tuple=False).view(-1) # target indices + + # Search for detections + if pi.shape[0]: + # Prediction to target ious + ious, i = box_iou(pred[pi, :4], tbox[ti]).max(1) # best ious, indices + + # Append detections + temp_nonzero_idx = (ious > iouv[0]).nonzero(as_tuple=False) + for j in temp_nonzero_idx: + d = ti[i[j]] # detected target + if d not in detected: + detected.append(d) + correct[pi[j]] = ious[j] > iouv # iou_thres is 1xn + if len(detected) == nl: # all targets already located in image + break + + # Append statistics (correct, conf, pcls, tcls) + stats.append((correct.cpu(), pred[:, 4].cpu(), pred[:, 5].cpu(), tcls)) + + # Plot images + if plots and batch_i < 3: + f = save_dir / f'{batch_i}_labels.jpg' # filename + plot_images(img, targets, paths, f, names) # labels + f = save_dir / f'{batch_i}_pred.jpg' + plot_images(img, output_to_target(output, width, height), paths, f, names) # predictions + + # Compute statistics + stats = [np.concatenate(x, 0) for x in zip(*stats)] # to numpy + if len(stats) and stats[0].any(): + p, r, ap, f1, ap_class = ap_per_class(*stats, plot=plots, fname=save_dir / 'precision-recall_curve.png') + p, r, ap50, ap = p[:, 0], r[:, 0], ap[:, 0], ap.mean(1) # [P, R, AP@0.5, AP@0.5:0.95] + mp, mr, map50, map = p.mean(), r.mean(), ap50.mean(), ap.mean() + nt = np.bincount(stats[3].astype(np.int64), minlength=nc) # number of targets per class + else: + nt = torch.zeros(1) + + # W&B logging + if plots and wandb: + wandb.log({"Images": wandb_images}) + wandb.log({"Validation": [wandb.Image(str(x), caption=x.name) for x in sorted(save_dir.glob('test*.jpg'))]}) + + # Print results + pf = '%20s' + '%12.3g' * 6 # print format + print(pf % ('all', seen, nt.sum(), mp, mr, map50, map)) + + # Print results per class + if verbose and nc > 1 and len(stats): + for i, c in enumerate(ap_class): + print(pf % (names[c], seen, nt[c], p[i], r[i], ap50[i], ap[i])) + + # Print speeds + t = tuple(x / seen * 1E3 for x in (t0, t1, t0 + t1)) + (imgsz, imgsz, batch_size) # tuple + if not training: + print('Speed: %.1f/%.1f/%.1f ms inference/NMS/total per %gx%g image at batch-size %g' % t) + + # Save JSON + if save_json and len(jdict): + w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights + anno_json = glob.glob('../data/coco/annotations/instances_val*.json')[0] # annotations json + pred_json = str(save_dir / f"{w}_predictions.json") # predictions json + print('\nEvaluating pycocotools mAP... saving %s...' % pred_json) + with open(pred_json, 'w') as f: + json.dump(jdict, f) + + try: # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb + from pycocotools.coco import COCO + from pycocotools.cocoeval import COCOeval + + anno = COCO(anno_json) # init annotations api + pred = anno.loadRes(pred_json) # init predictions api + eval = COCOeval(anno, pred, 'bbox') + if is_coco: + eval.params.imgIds = [int(Path(x).stem) for x in dataloader.dataset.img_files] # image IDs to evaluate + eval.evaluate() + eval.accumulate() + eval.summarize() + map, map50 = eval.stats[:2] # update results (mAP@0.5:0.95, mAP@0.5) + except Exception as e: + print('ERROR: pycocotools unable to run: %s' % e) + + # Return results + if not training: + print('Results saved to %s' % save_dir) + model.float() # for training + maps = np.zeros(nc) + map + for i, c in enumerate(ap_class): + maps[c] = ap[i] + return (mp, mr, map50, map, *(loss.cpu() / len(dataloader)).tolist()), maps, t + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(prog='test.py') + parser.add_argument('--weights', nargs='+', type=str, default='yolor_p6.pt', help='model.pt path(s)') + parser.add_argument('--data', type=str, default='data/coco.yaml', help='*.data path') + parser.add_argument('--batch-size', type=int, default=32, help='size of each image batch') + parser.add_argument('--img-size', type=int, default=1280, help='inference size (pixels)') + parser.add_argument('--conf-thres', type=float, default=0.001, help='object confidence threshold') + parser.add_argument('--iou-thres', type=float, default=0.65, help='IOU threshold for NMS') + parser.add_argument('--task', default='val', help="'val', 'test', 'study'") + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--single-cls', action='store_true', help='treat as single-class dataset') + parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--verbose', action='store_true', help='report mAP by class') + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') + parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') + parser.add_argument('--save-json', action='store_true', help='save a cocoapi-compatible JSON results file') + parser.add_argument('--project', default='runs/test', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--cfg', type=str, default='cfg/yolor_p6.cfg', help='*.cfg path') + parser.add_argument('--names', type=str, default='data/coco.names', help='*.cfg path') + parser.add_argument('--npu', default=None, type=int, help='NPU id to use.') + opt = parser.parse_args() + opt.save_json |= opt.data.endswith('coco.yaml') + opt.data = check_file(opt.data) # check file + print(opt) + + if opt.task in ['val', 'test']: # run normally + test(opt.data, + opt.weights, + opt.batch_size, + opt.img_size, + opt.conf_thres, + opt.iou_thres, + opt.save_json, + opt.single_cls, + opt.augment, + opt.verbose, + save_txt=opt.save_txt, + save_conf=opt.save_conf, + ) + + elif opt.task == 'study': # run over a range of settings and save/plot + for weights in ['yolor_p6.pt', 'yolor_w6.pt']: + f = 'study_%s_%s.txt' % (Path(opt.data).stem, Path(weights).stem) # filename to save to + x = list(range(320, 800, 64)) # x axis + y = [] # y axis + for i in x: # img-size + print('\nRunning %s point %s...' % (f, i)) + r, _, t = test(opt.data, weights, opt.batch_size, i, opt.conf_thres, opt.iou_thres, opt.save_json) + y.append(r + t) # results and times + np.savetxt(f, y, fmt='%10.4g') # save + os.system('zip -r study.zip study_*.txt') + # utils.general.plot_study_txt(f, x) # plot diff --git a/PyTorch/contrib/cv/detection/YOLOR/train.py b/PyTorch/contrib/cv/detection/YOLOR/train.py index 8f59aeea09..75329751e2 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/train.py +++ b/PyTorch/contrib/cv/detection/YOLOR/train.py @@ -1,739 +1,739 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import logging -import math -import os -import random -import time -from pathlib import Path -from warnings import warn - -import numpy as np -import torch.distributed as dist -import torch.nn.functional as F -import torch.optim as optim -import torch.optim.lr_scheduler as lr_scheduler -import torch.utils.data -import yaml -from torch.nn.parallel import DistributedDataParallel as DDP -from torch.utils.tensorboard import SummaryWriter -import torch.multiprocessing as mp - -import test # import test.py to get mAP after each epoch -#from models.yolo import Model -from models.models import * -from utils.autoanchor import check_anchors -from utils.datasets import create_dataloader -from utils.general import labels_to_class_weights, increment_path, labels_to_image_weights, init_seeds, \ - fitness, fitness_p, fitness_r, fitness_ap50, fitness_ap, fitness_f, strip_optimizer, get_latest_run,\ - check_dataset, check_file, check_git_status, check_img_size, print_mutation, set_logging -from utils.google_utils import attempt_download -from utils.loss import compute_loss -from utils.plots import plot_images, plot_labels, plot_results, plot_evolution, output_to_target -from utils.torch_utils import ModelEMA, select_device, intersect_dicts, torch_distributed_zero_first - -logger = logging.getLogger(__name__) - -mixed_precision = True -try: - import apex - from apex import amp -except: - print('Apex recommended for faster mixed precision training: https://github.com/NVIDIA/apex') - mixed_precision = False # not installed - -use_wandb = False -if use_wandb: - try: - import wandb - except: - print("Install Weights & Biases for experiment logging via 'pip install wandb' (recommended)") -else: - wandb = None - - -def train(hyp, opt, device, tb_writer=None, wandb=None): - print(f'Hyperparameters {hyp}') - save_dir, epochs, batch_size, total_batch_size, weights, rank = \ - Path(opt.save_dir), opt.epochs, opt.batch_size, opt.total_batch_size, opt.weights, opt.local_rank - - # Directories - wdir = save_dir / 'weights' - wdir.mkdir(parents=True, exist_ok=True) # make dir - last = wdir / 'last.pt' - best = wdir / 'best.pt' - results_file = save_dir / 'results.txt' - - # Save run settings - with open(save_dir / 'hyp.yaml', 'w') as f: - yaml.dump(hyp, f, sort_keys=False) - with open(save_dir / 'opt.yaml', 'w') as f: - yaml.dump(vars(opt), f, sort_keys=False) - - # Configure - plots = not opt.evolve # create plots - cuda = device.type != 'cpu' - init_seeds(2 + rank) - with open(opt.data) as f: - data_dict = yaml.load(f, Loader=yaml.FullLoader) # data dict - with torch_distributed_zero_first(rank): - check_dataset(data_dict) # check - train_path = data_dict['train'] - test_path = data_dict['val'] - nc, names = (1, ['item']) if opt.single_cls else (int(data_dict['nc']), data_dict['names']) # number classes, names - assert len(names) == nc, '%g names found for nc=%g dataset in %s' % (len(names), nc, opt.data) # check - - # Model - pretrained = weights.endswith('.pt') - if pretrained: - with torch_distributed_zero_first(rank): - attempt_download(weights) # download if not found locally - ckpt = torch.load(weights, map_location=device) # load checkpoint - model = Darknet(opt.cfg).to(device) # create - state_dict = {k: v for k, v in ckpt['model'].items() if model.state_dict()[k].numel() == v.numel()} - model.load_state_dict(state_dict, strict=False) - print('Transferred %g/%g items from %s' % (len(state_dict), len(model.state_dict()), weights)) # report - else: - model = Darknet(opt.cfg).to(device) # create - - # Image sizes - gs = 64 #int(max(model.stride)) # grid size (max stride) - imgsz, imgsz_test = [check_img_size(x, gs) for x in opt.img_size] # verify imgsz are gs-multiples - - # Optimizer - nbs = 64 # nominal batch size - accumulate = max(round(nbs / total_batch_size), 1) # accumulate loss before optimizing - hyp['weight_decay'] *= total_batch_size * accumulate / nbs # scale weight_decay - - pg0, pg1, pg2 = [], [], [] # optimizer parameter groups - for k, v in dict(model.named_parameters()).items(): - if '.bias' in k: - pg2.append(v) # biases - elif 'Conv2d.weight' in k: - pg1.append(v) # apply weight_decay - elif 'm.weight' in k: - pg1.append(v) # apply weight_decay - elif 'w.weight' in k: - pg1.append(v) # apply weight_decay - else: - pg0.append(v) # all else - - if opt.adam: - optimizer = optim.Adam(pg0, lr=hyp['lr0'], betas=(hyp['momentum'], 0.999)) # adjust beta1 to momentum - else: - if device.type == 'npu': - optimizer = apex.optimizers.NpuFusedSGD(pg0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True) - else: - optimizer = optim.SGD(pg0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True) - - optimizer.add_param_group({'params': pg1, 'weight_decay': hyp['weight_decay']}) # add pg1 with weight_decay - optimizer.add_param_group({'params': pg2}) # add pg2 (biases) - print('Optimizer groups: %g .bias, %g conv.weight, %g other' % (len(pg2), len(pg1), len(pg0))) - del pg0, pg1, pg2 - - # Logging - if wandb and wandb.run is None: - opt.hyp = hyp # add hyperparameters - wandb_run = wandb.init(config=opt, resume="allow", - project='YOLOR' if opt.project == 'runs/train' else Path(opt.project).stem, - name=save_dir.stem, - id=ckpt.get('wandb_id') if 'ckpt' in locals() else None) - - # Resume - start_epoch = 0 - # best_fitness, best_fitness_p, best_fitness_r, best_fitness_ap50, best_fitness_ap, best_fitness_f = 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 - if pretrained: - # Optimizer - if ckpt['optimizer'] is not None: - optimizer.load_state_dict(ckpt['optimizer']) - # best_fitness = ckpt['best_fitness'] - # best_fitness_p = ckpt['best_fitness_p'] - # best_fitness_r = ckpt['best_fitness_r'] - # best_fitness_ap50 = ckpt['best_fitness_ap50'] - # best_fitness_ap = ckpt['best_fitness_ap'] - # best_fitness_f = ckpt['best_fitness_f'] - - # Results - if ckpt.get('training_results') is not None: - with open(results_file, 'w') as file: - file.write(ckpt['training_results']) # write results.txt - - # Epochs - start_epoch = ckpt['epoch'] + 1 - if opt.resume: - assert start_epoch > 0, '%s training to %g epochs is finished, nothing to resume.' % (weights, epochs) - if epochs < start_epoch: - print('%s has been trained for %g epochs. Fine-tuning for %g additional epochs.' % - (weights, ckpt['epoch'], epochs)) - epochs += ckpt['epoch'] # finetune additional epochs - - del ckpt, state_dict - - # Mixed precision training https://github.com/NVIDIA/apex - if mixed_precision: - if device.type == 'npu': - model, optimizer = amp.initialize(model, optimizer, opt_level='O1', verbosity=0, loss_scale=64, combine_grad=True) - else: - model, optimizer = amp.initialize(model, optimizer, opt_level='O1', verbosity=0, loss_scale=64) - - # Scheduler https://arxiv.org/pdf/1812.01187.pdf - # https://pytorch.org/docs/stable/_modules/torch/optim/lr_scheduler.html#OneCycleLR - lf = lambda x: ((1 + math.cos(x * math.pi / epochs)) / 2) * (1 - hyp['lrf']) + hyp['lrf'] # cosine - scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) - # plot_lr_scheduler(optimizer, scheduler, epochs) - - - # SyncBatchNorm - if opt.sync_bn and cuda and rank != -1: - model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model).to(device) - print('Using SyncBatchNorm()') - - # EMA - ema = ModelEMA(model) if rank in [-1, 0] else None - - # DDP mode - if device.type == 'cuda' and rank != -1: - model = DDP(model, device_ids=[rank], output_device=rank) - elif device.type == 'npu' and rank != -1: - model = DDP(model, device_ids=[rank], broadcast_buffers=False) - - # Trainloader - dataloader, dataset = create_dataloader(train_path, imgsz, batch_size, gs, opt, - hyp=hyp, augment=True, cache=opt.cache_images, rect=opt.rect, - rank=rank, world_size=opt.world_size, workers=opt.workers) - mlc = np.concatenate(dataset.labels, 0)[:, 0].max() # max label class - nb = len(dataloader) # number of batches - assert mlc < nc, 'Label class %g exceeds nc=%g in %s. Possible class labels are 0-%g' % (mlc, nc, opt.data, nc - 1) - - # Model parameters - hyp['cls'] *= nc / 80. # scale coco-tuned hyp['cls'] to current dataset - model.nc = nc # attach number of classes to model - model.hyp = hyp # attach hyperparameters to model - model.gr = 1.0 # iou loss ratio (obj_loss = 1.0 or iou) - model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) # attach class weights - model.names = names - - # Process 0 - if rank in [-1, 0]: - ema.updates = start_epoch * nb // accumulate # set EMA updates - testloader = create_dataloader(test_path, imgsz_test, batch_size*2, gs, opt, - hyp=hyp, cache=opt.cache_images and not opt.notest, rect=True, - rank=-1, world_size=opt.world_size, workers=opt.workers)[0] # testloader - - if not opt.resume: - labels = np.concatenate(dataset.labels, 0) - c = torch.tensor(labels[:, 0]) # classes - # cf = torch.bincount(c.long(), minlength=nc) + 1. # frequency - # model._initialize_biases(cf.to(device)) - if plots: - plot_labels(labels, save_dir=save_dir) - if tb_writer: - tb_writer.add_histogram('classes', c, 0) - if wandb: - wandb.log({"Labels": [wandb.Image(str(x), caption=x.name) for x in save_dir.glob('*labels*.png')]}) - - # Anchors - # if not opt.noautoanchor: - # check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz) - - - # Start training - t0 = time.time() - nw = max(round(hyp['warmup_epochs'] * nb), 1000) # number of warmup iterations, max(3 epochs, 1k iterations) - # nw = min(nw, (epochs - start_epoch) / 2 * nb) # limit warmup to < 1/2 of training - maps = np.zeros(nc) # mAP per class - results = (0, 0, 0, 0, 0, 0, 0) # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls) - scheduler.last_epoch = start_epoch - 1 # do not move - if rank in [0, -1]: - print('Image sizes %g train, %g test\n' - 'Using %g dataloader workers\nLogging results to %s\n' - 'Starting training for %g epochs...' % (imgsz, imgsz_test, dataloader.num_workers, save_dir, epochs)) - - for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ - model.train() - - # Update image weights (optional) - # When in DDP mode, the generated indices will be broadcasted to synchronize dataset. - if opt.image_weights: - # Generate indices - if rank in [-1, 0]: - cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 # class weights - iw = labels_to_image_weights(dataset.labels, nc=nc, class_weights=cw) # image weights - dataset.indices = random.choices(range(dataset.n), weights=iw, k=dataset.n) # rand weighted idx - # Broadcast if DDP - if rank != -1: - indices = (torch.tensor(dataset.indices) if rank == 0 else torch.zeros(dataset.n)).int() - dist.broadcast(indices, 0) - if rank != 0: - dataset.indices = indices.cpu().numpy() - - # Update mosaic border - # b = int(random.uniform(0.25 * imgsz, 0.75 * imgsz + gs) // gs * gs) - # dataset.mosaic_border = [b - imgsz, -b] # height, width borders - - mloss = torch.zeros(4, device=device) # mean losses - if rank != -1: - dataloader.sampler.set_epoch(epoch) - optimizer.zero_grad() - start_time = time.time() - d_1 = time.time() - - for i, (imgs, targets, paths, _) in enumerate(dataloader): # batch ------------------------------------------------------------- - t_time = time.time() - d_time = t_time - d_1 - ni = i + nb * epoch # number integrated batches (since train start) - imgs = imgs.to(device, non_blocking=True).float() / 255.0 # uint8 to float32, 0-255 to 0.0-1.0 - - # Warmup - if ni <= nw: - xi = [0, nw] # x interp - # model.gr = np.interp(ni, xi, [0.0, 1.0]) # iou loss ratio (obj_loss = 1.0 or iou) - accumulate = max(1, np.interp(ni, xi, [1, nbs / total_batch_size]).round()) - for j, x in enumerate(optimizer.param_groups): - # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0 - x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 2 else 0.0, x['initial_lr'] * lf(epoch)]) - if 'momentum' in x: - x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']]) - - # Multi-scale - if opt.multi_scale: - sz = random.randrange(imgsz * 0.5, imgsz * 1.5 + gs) // gs * gs # size - sf = sz / max(imgs.shape[2:]) # scale factor - if sf != 1: - ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to gs-multiple) - imgs = F.interpolate(imgs, size=ns, mode='bilinear', align_corners=False) - - # Forward - pred = model(imgs) - - # Loss - loss, loss_items = compute_loss(pred, targets.to(device), model) # scaled by batch_size - if rank != -1: - loss *= opt.world_size # gradient averaged between devices in DDP mode - if not torch.isfinite(loss): - print('WARNING: non-finite loss, ending training ', loss_items) - return results - - # Backward - if mixed_precision: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - - # Optimize - if ni % accumulate == 0: - optimizer.step() - optimizer.zero_grad() - if ema is not None: - x = torch.tensor([1.]).to(device) - if device.type == 'npu': - params_fp32_fused = optimizer.get_model_combined_params() - ema.update(model, x, params_fp32_fused[0]) - else: - ema.update(model, x) - - if i <= 10: - sum_time = (time.time() - start_time) / (i + 1) - if i == 10: - start_time = time.time() - else: - sum_time = (time.time() - start_time) / (i - 10) - ptime = time.time() - d_1 - # Print - if rank in [-1, 0]: - mloss = (mloss * i + loss_items) / (i + 1) # update mean losses - mem = '%.3gG' % (torch.cuda.memory_cached() / 1E9 if torch.cuda.is_available() else 0) # (GB) - s = ('%10s' * 2 + '%10.4g' * 6) % ( - '%g/%g' % (epoch, epochs - 1), mem, *mloss, targets.shape[0], imgs.shape[-1]) - print( - 'Epoch:[%2g][%4g/%4g][%s][FPS:%3.1f][mTime:%3.3f][pTime:%3.3f][dTime:%3.3f] GIoU:%.3f objectness:%.3f classfication:%.3f totalLoss:%.3f' % ( - epoch, i, nb, device, opt.total_batch_size / sum_time, sum_time, ptime, d_time, *mloss)) - - # Plot - if plots and ni < 3: - f = save_dir / f'train_batch{ni}.jpg' # filename - plot_images(images=imgs, targets=targets, paths=paths, fname=f) - # if tb_writer: - # tb_writer.add_image(f, result, dataformats='HWC', global_step=epoch) - # tb_writer.add_graph(model, imgs) # add model to tensorboard - elif plots and ni == 3 and wandb: - wandb.log({"Mosaics": [wandb.Image(str(x), caption=x.name) for x in save_dir.glob('train*.jpg')]}) - if i > 170: - break - d_1 = time.time() - # end batch ------------------------------------------------------------------------------------------------ - # end epoch ---------------------------------------------------------------------------------------------------- - - # Scheduler - lr = [x['lr'] for x in optimizer.param_groups] # for tensorboard - scheduler.step() - - # DDP process 0 or single-GPU - if rank in [-1, 0]: - # mAP - if ema: - ema.update_attr(model) - final_epoch = epoch + 1 == epochs - if False: # No test during training - results, maps, _ = test.test(opt.data, - batch_size=batch_size*2, - imgsz=imgsz_test, - model=ema.ema.module if hasattr(ema.ema, 'module') else ema.ema, - single_cls=opt.single_cls, - dataloader=testloader, - save_dir=save_dir, - plots=True) - - # Write - with open(results_file, 'a') as f: - f.write(s + '%10.4g' * 7 % results + '\n') # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls) - if len(opt.name) and opt.bucket: - os.system('gsutil cp %s gs://%s/results/results%s.txt' % (results_file, opt.bucket, opt.name)) - - # Log - tags = ['train/box_loss', 'train/obj_loss', 'train/cls_loss', # train loss - 'metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/mAP_0.5:0.95', - 'val/box_loss', 'val/obj_loss', 'val/cls_loss', # val loss - 'x/lr0', 'x/lr1', 'x/lr2'] # params - for x, tag in zip(list(mloss[:-1]) + list(results) + lr, tags): - if tb_writer: - tb_writer.add_scalar(tag, x, epoch) # tensorboard - if wandb: - wandb.log({tag: x}) # W&B - - # # Update best mAP - # fi = fitness(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] - # fi_p = fitness_p(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] - # fi_r = fitness_r(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] - # fi_ap50 = fitness_ap50(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] - # fi_ap = fitness_ap(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] - # if (fi_p > 0.0) or (fi_r > 0.0): - # fi_f = fitness_f(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] - # else: - # fi_f = 0.0 - # if fi > best_fitness: - # best_fitness = fi - # if fi_p > best_fitness_p: - # best_fitness_p = fi_p - # if fi_r > best_fitness_r: - # best_fitness_r = fi_r - # if fi_ap50 > best_fitness_ap50: - # best_fitness_ap50 = fi_ap50 - # if fi_ap > best_fitness_ap: - # best_fitness_ap = fi_ap - # if fi_f > best_fitness_f: - # best_fitness_f = fi_f - - # Save model - save = (not opt.nosave) or (final_epoch and not opt.evolve) - if save: - with open(results_file, 'r') as f: # create checkpoint - ckpt = {'epoch': epoch, - # 'best_fitness': best_fitness, - # 'best_fitness_p': best_fitness_p, - # 'best_fitness_r': best_fitness_r, - # 'best_fitness_ap50': best_fitness_ap50, - # 'best_fitness_ap': best_fitness_ap, - # 'best_fitness_f': best_fitness_f, - 'training_results': f.read(), - 'model': ema.ema.module.state_dict() if hasattr(ema, 'module') else ema.ema.state_dict(), - 'optimizer': None if final_epoch else optimizer.state_dict(), - 'wandb_id': wandb_run.id if wandb else None} - - # Save last, best and delete - torch.save(ckpt, last) - # if best_fitness == fi: - # torch.save(ckpt, best) - # if (best_fitness == fi) and (epoch >= 200): - # torch.save(ckpt, wdir / 'best_{:03d}.pt'.format(epoch)) - # if best_fitness == fi: - # torch.save(ckpt, wdir / 'best_overall.pt') - # if best_fitness_p == fi_p: - # torch.save(ckpt, wdir / 'best_p.pt') - # if best_fitness_r == fi_r: - # torch.save(ckpt, wdir / 'best_r.pt') - # if best_fitness_ap50 == fi_ap50: - # torch.save(ckpt, wdir / 'best_ap50.pt') - # if best_fitness_ap == fi_ap: - # torch.save(ckpt, wdir / 'best_ap.pt') - # if best_fitness_f == fi_f: - # torch.save(ckpt, wdir / 'best_f.pt') - if epoch == 0: - torch.save(ckpt, wdir / 'epoch_{:03d}.pt'.format(epoch)) - if ((epoch+1) % 25) == 0: - torch.save(ckpt, wdir / 'epoch_{:03d}.pt'.format(epoch)) - if epoch >= (epochs-5): - torch.save(ckpt, wdir / 'last_{:03d}.pt'.format(epoch)) - elif epoch >= 420: - torch.save(ckpt, wdir / 'last_{:03d}.pt'.format(epoch)) - del ckpt - # end epoch ---------------------------------------------------------------------------------------------------- - # end training - - if rank in [-1, 0]: - # Strip optimizers - n = opt.name if opt.name.isnumeric() else '' - fresults, flast, fbest = save_dir / f'results{n}.txt', wdir / f'last{n}.pt', wdir / f'best{n}.pt' - for f1, f2 in zip([wdir / 'last.pt', wdir / 'best.pt', results_file], [flast, fbest, fresults]): - if f1.exists(): - os.rename(f1, f2) # rename - if str(f2).endswith('.pt'): # is *.pt - strip_optimizer(f2) # strip optimizer - os.system('gsutil cp %s gs://%s/weights' % (f2, opt.bucket)) if opt.bucket else None # upload - # Finish - if plots: - plot_results(save_dir=save_dir) # save as results.png - if wandb: - wandb.log({"Results": [wandb.Image(str(save_dir / x), caption=x) for x in - ['results.png', 'precision-recall_curve.png']]}) - print('%g epochs completed in %.3f hours.\n' % (epoch - start_epoch + 1, (time.time() - t0) / 3600)) - - else: - dist.destroy_process_group() - - wandb.run.finish() if wandb and wandb.run else None - torch.cuda.empty_cache() - - return results - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument('--weights', type=str, default='yolor_p6.pt', help='initial weights path') - parser.add_argument('--cfg', type=str, default='', help='model.yaml path') - parser.add_argument('--data', type=str, default='data/coco.yaml', help='data.yaml path') - parser.add_argument('--hyp', type=str, default='data/hyp.scratch.1280.yaml', help='hyperparameters path') - parser.add_argument('--epochs', type=int, default=300) - parser.add_argument('--batch-size', type=int, default=8, help='total batch size for all GPUs') - parser.add_argument('--img-size', nargs='+', type=int, default=[1280, 1280], help='[train, test] image sizes') - parser.add_argument('--rect', action='store_true', help='rectangular training') - parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training') - parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') - parser.add_argument('--notest', action='store_true', help='only test final epoch') - parser.add_argument('--noautoanchor', action='store_true', help='disable autoanchor check') - parser.add_argument('--evolve', action='store_true', help='evolve hyperparameters') - parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') - parser.add_argument('--cache-images', action='store_true', help='cache images for faster training') - parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') - parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu or npu') - parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') - parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') - parser.add_argument('--adam', action='store_true', help='use torch.optim.Adam() optimizer') - parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') - parser.add_argument('--full', action='store_true', help='full mode') - parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify') - parser.add_argument('--log-imgs', type=int, default=16, help='number of images for W&B logging, max 100') - parser.add_argument('--workers', type=int, default=8, help='maximum number of dataloader workers') - parser.add_argument('--project', default='runs/train', help='save to project/name') - parser.add_argument('--name', default='exp', help='save to project/name') - parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') - parser.add_argument('--npu', default=-1, type=int, help='NPU id to use.') - - # NPU DDP mode - parser.add_argument('--world-size', default=1, type=int, help='number of nodes for distributed training') - parser.add_argument('--device-num', default=1, type=int, help='multi NPU parameter, GPU or CPU do not modify') - parser.add_argument('--addr', default='127.0.0.1', type=str, help='DDP master node IP') - parser.add_argument('--dist-url', default='tcp://127.0.0.1:29501', type=str, - help='url used to set up distributed training') - opt = parser.parse_args() - - if opt.dist_url == "env://": - opt.world_size = int(os.environ["WORLD_SIZE"]) - ngpus_per_node = opt.device_num - opt.npu_ddp = (opt.device_num > 1 or opt.world_size > 1) - if opt.npu_ddp: - print('multi npu training') - os.environ['MASTER_ADDR'] = opt.addr # master ip - os.environ['MASTER_PORT'] = '29501' - os.environ['KERNEL_NAME_ID'] = str(0) - opt.world_size = ngpus_per_node * opt.world_size # the sum of GPU or NPU in all the nodes - mp.spawn(main_worker, nprocs=ngpus_per_node, args=(ngpus_per_node, opt)) - else: - print('1p training') - main_worker(opt.npu, ngpus_per_node, opt) - - # # Set DDP variables - # opt.total_batch_size = opt.batch_size - # opt.world_size = int(os.environ['WORLD_SIZE']) if 'WORLD_SIZE' in os.environ else 1 - # opt.global_rank = int(os.environ['RANK']) if 'RANK' in os.environ else -1 - # set_logging(opt.global_rank) - # if opt.global_rank in [-1, 0]: - # check_git_status() - - # # DDP mode - # device = select_device(opt.device, batch_size=opt.batch_size) - # if opt.local_rank != -1: - # assert torch.cuda.device_count() > opt.local_rank - # torch.cuda.set_device(opt.local_rank) - # device = torch.device('cuda', opt.local_rank) - # dist.init_process_group(backend='nccl', init_method='env://') # distributed backend - # assert opt.batch_size % opt.world_size == 0, '--batch-size must be multiple of CUDA device count' - # opt.batch_size = opt.total_batch_size // opt.world_size - - -def main_worker(npu, ngpus_per_node, opt): - # Resume - if opt.resume: # resume an interrupted run - ckpt = opt.resume if isinstance(opt.resume, str) else get_latest_run() # specified or most recent path - assert os.path.isfile(ckpt), 'ERROR: --resume checkpoint does not exist' - with open(Path(ckpt).parent.parent / 'opt.yaml') as f: - opt = argparse.Namespace(**yaml.load(f, Loader=yaml.FullLoader)) # replace - opt.cfg, opt.weights, opt.resume = '', ckpt, True - print('Resuming training from %s' % ckpt) - else: - # opt.hyp = opt.hyp or ('hyp.finetune.yaml' if opt.weights else 'hyp.scratch.yaml') - opt.data, opt.cfg, opt.hyp = check_file(opt.data), check_file(opt.cfg), check_file(opt.hyp) # check files - assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified' - opt.img_size.extend([opt.img_size[-1]] * (2 - len(opt.img_size))) # extend to 2 sizes (train, test) - opt.name = 'evolve' if opt.evolve else opt.name - opt.save_dir = increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok | opt.evolve) # increment run - - # Hyperparameters - with open(opt.hyp) as f: - hyp = yaml.load(f, Loader=yaml.FullLoader) # load hyps - if 'box' not in hyp: - warn('Compatibility: %s missing "box" which was renamed from "giou" in %s' % - (opt.hyp, 'https://github.com/ultralytics/yolov5/pull/1120')) - hyp['box'] = hyp.pop('giou') - - # npu DDP - if opt.npu_ddp: - opt.npu = npu - os.environ['KERNEL_NAME_ID'] = str(npu) - print("[npu id:", opt.npu, "]", "+++++++++++++++++++++++++++KERNEL_NAME_ID:", os.environ['KERNEL_NAME_ID']) - opt.local_rank = opt.local_rank * ngpus_per_node + npu - global mixed_precision - device = torch_utils.select_device(opt.device, opt.npu, apex=mixed_precision, batch_size=opt.batch_size) - opt.total_batch_size = opt.batch_size - if device.type == 'cpu': - mixed_precision = False - elif opt.local_rank != -1 and device.type == 'cuda': - # DDP mode - assert torch.cuda.device_count() > opt.local_rank - torch.cuda.set_device(opt.local_rank) - device = torch.device("cuda", opt.local_rank) - dist.init_process_group(backend='nccl', init_method='env://') # distributed backend - - opt.world_size = dist.get_world_size() - assert opt.batch_size % opt.world_size == 0, "Batch size is not a multiple of the number of devices given!" - opt.batch_size = opt.total_batch_size // opt.world_size - elif opt.local_rank != -1 and device.type == 'npu': - dist.init_process_group(backend='hccl', world_size=opt.world_size, rank=opt.local_rank) - assert opt.batch_size % opt.world_size == 0, "Batch size is not a multiple of the number of devices given!" - opt.batch_size = opt.total_batch_size // opt.world_size - - # Train - print(opt) - if not opt.evolve: - tb_writer = None # init loggers - if opt.local_rank in [-1, 0]: - print(f'Start Tensorboard with "tensorboard --logdir {opt.project}", view at http://localhost:6006/') - tb_writer = SummaryWriter(opt.save_dir) # Tensorboard - train(hyp, opt, device, tb_writer, wandb) - - # Evolve hyperparameters (optional) - else: - # Hyperparameter evolution metadata (mutation scale 0-1, lower_limit, upper_limit) - meta = {'lr0': (1, 1e-5, 1e-1), # initial learning rate (SGD=1E-2, Adam=1E-3) - 'lrf': (1, 0.01, 1.0), # final OneCycleLR learning rate (lr0 * lrf) - 'momentum': (0.3, 0.6, 0.98), # SGD momentum/Adam beta1 - 'weight_decay': (1, 0.0, 0.001), # optimizer weight decay - 'warmup_epochs': (1, 0.0, 5.0), # warmup epochs (fractions ok) - 'warmup_momentum': (1, 0.0, 0.95), # warmup initial momentum - 'warmup_bias_lr': (1, 0.0, 0.2), # warmup initial bias lr - 'box': (1, 0.02, 0.2), # box loss gain - 'cls': (1, 0.2, 4.0), # cls loss gain - 'cls_pw': (1, 0.5, 2.0), # cls BCELoss positive_weight - 'obj': (1, 0.2, 4.0), # obj loss gain (scale with pixels) - 'obj_pw': (1, 0.5, 2.0), # obj BCELoss positive_weight - 'iou_t': (0, 0.1, 0.7), # IoU training threshold - 'anchor_t': (1, 2.0, 8.0), # anchor-multiple threshold - 'anchors': (2, 2.0, 10.0), # anchors per output grid (0 to ignore) - 'fl_gamma': (0, 0.0, 2.0), # focal loss gamma (efficientDet default gamma=1.5) - 'hsv_h': (1, 0.0, 0.1), # image HSV-Hue augmentation (fraction) - 'hsv_s': (1, 0.0, 0.9), # image HSV-Saturation augmentation (fraction) - 'hsv_v': (1, 0.0, 0.9), # image HSV-Value augmentation (fraction) - 'degrees': (1, 0.0, 45.0), # image rotation (+/- deg) - 'translate': (1, 0.0, 0.9), # image translation (+/- fraction) - 'scale': (1, 0.0, 0.9), # image scale (+/- gain) - 'shear': (1, 0.0, 10.0), # image shear (+/- deg) - 'perspective': (0, 0.0, 0.001), # image perspective (+/- fraction), range 0-0.001 - 'flipud': (1, 0.0, 1.0), # image flip up-down (probability) - 'fliplr': (0, 0.0, 1.0), # image flip left-right (probability) - 'mosaic': (1, 0.0, 1.0), # image mixup (probability) - 'mixup': (1, 0.0, 1.0)} # image mixup (probability) - - assert opt.local_rank == -1, 'DDP mode not implemented for --evolve' - opt.notest, opt.nosave = True, True # only test/save final epoch - # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices - yaml_file = Path(opt.save_dir) / 'hyp_evolved.yaml' # save best result here - if opt.bucket: - os.system('gsutil cp gs://%s/evolve.txt .' % opt.bucket) # download evolve.txt if exists - - for _ in range(300): # generations to evolve - if Path('evolve.txt').exists(): # if evolve.txt exists: select best hyps and mutate - # Select parent(s) - parent = 'single' # parent selection method: 'single' or 'weighted' - x = np.loadtxt('evolve.txt', ndmin=2) - n = min(5, len(x)) # number of previous results to consider - x = x[np.argsort(-fitness(x))][:n] # top n mutations - w = fitness(x) - fitness(x).min() # weights - if parent == 'single' or len(x) == 1: - # x = x[random.randint(0, n - 1)] # random selection - x = x[random.choices(range(n), weights=w)[0]] # weighted selection - elif parent == 'weighted': - x = (x * w.reshape(n, 1)).sum(0) / w.sum() # weighted combination - - # Mutate - mp, s = 0.8, 0.2 # mutation probability, sigma - npr = np.random - npr.seed(int(time.time())) - g = np.array([x[0] for x in meta.values()]) # gains 0-1 - ng = len(meta) - v = np.ones(ng) - while all(v == 1): # mutate until a change occurs (prevent duplicates) - v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0) - for i, k in enumerate(hyp.keys()): # plt.hist(v.ravel(), 300) - hyp[k] = float(x[i + 7] * v[i]) # mutate - - # Constrain to limits - for k, v in meta.items(): - hyp[k] = max(hyp[k], v[1]) # lower limit - hyp[k] = min(hyp[k], v[2]) # upper limit - hyp[k] = round(hyp[k], 5) # significant digits - - # Train mutation - results = train(hyp.copy(), opt, device, wandb=wandb) - - # Write mutation results - print_mutation(hyp.copy(), results, yaml_file, opt.bucket) - - # Plot results - plot_evolution(yaml_file) - print(f'Hyperparameter evolution complete. Best results saved as: {yaml_file}\n' - f'Command to train a new model with these hyperparameters: $ python train.py --hyp {yaml_file}') - - -if __name__ == '__main__': - # option = {} - # option["ACL_OP_DEBUG_LEVEL"] = 3 # 算子debug功能,暂不开启 - # option["ACL_DEBUG_DIR"] = "debug_file" # 算子debug功能对应文件夹,暂不开启 - # option["ACL_OP_COMPILER_CACHE_MODE"] = "enable" # cache功能启用 - # option["ACL_OP_COMPILER_CACHE_DIR"] = "./kernel_meta" # cache所在文件夹 - # print("option:",option) - # torch.npu.set_option(option) - main() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import logging +import math +import os +import random +import time +from pathlib import Path +from warnings import warn + +import numpy as np +import torch.distributed as dist +import torch.nn.functional as F +import torch.optim as optim +import torch.optim.lr_scheduler as lr_scheduler +import torch.utils.data +import yaml +from torch.nn.parallel import DistributedDataParallel as DDP +from torch.utils.tensorboard import SummaryWriter +import torch.multiprocessing as mp + +import test # import test.py to get mAP after each epoch +#from models.yolo import Model +from models.models import * +from utils.autoanchor import check_anchors +from utils.datasets import create_dataloader +from utils.general import labels_to_class_weights, increment_path, labels_to_image_weights, init_seeds, \ + fitness, fitness_p, fitness_r, fitness_ap50, fitness_ap, fitness_f, strip_optimizer, get_latest_run,\ + check_dataset, check_file, check_git_status, check_img_size, print_mutation, set_logging +from utils.google_utils import attempt_download +from utils.loss import compute_loss +from utils.plots import plot_images, plot_labels, plot_results, plot_evolution, output_to_target +from utils.torch_utils import ModelEMA, select_device, intersect_dicts, torch_distributed_zero_first + +logger = logging.getLogger(__name__) + +mixed_precision = True +try: + import apex + from apex import amp +except: + print('Apex recommended for faster mixed precision training: https://github.com/NVIDIA/apex') + mixed_precision = False # not installed + +use_wandb = False +if use_wandb: + try: + import wandb + except: + print("Install Weights & Biases for experiment logging via 'pip install wandb' (recommended)") +else: + wandb = None + + +def train(hyp, opt, device, tb_writer=None, wandb=None): + print(f'Hyperparameters {hyp}') + save_dir, epochs, batch_size, total_batch_size, weights, rank = \ + Path(opt.save_dir), opt.epochs, opt.batch_size, opt.total_batch_size, opt.weights, opt.local_rank + + # Directories + wdir = save_dir / 'weights' + wdir.mkdir(parents=True, exist_ok=True) # make dir + last = wdir / 'last.pt' + best = wdir / 'best.pt' + results_file = save_dir / 'results.txt' + + # Save run settings + with open(save_dir / 'hyp.yaml', 'w') as f: + yaml.dump(hyp, f, sort_keys=False) + with open(save_dir / 'opt.yaml', 'w') as f: + yaml.dump(vars(opt), f, sort_keys=False) + + # Configure + plots = not opt.evolve # create plots + cuda = device.type != 'cpu' + init_seeds(2 + rank) + with open(opt.data) as f: + data_dict = yaml.load(f, Loader=yaml.FullLoader) # data dict + with torch_distributed_zero_first(rank): + check_dataset(data_dict) # check + train_path = data_dict['train'] + test_path = data_dict['val'] + nc, names = (1, ['item']) if opt.single_cls else (int(data_dict['nc']), data_dict['names']) # number classes, names + assert len(names) == nc, '%g names found for nc=%g dataset in %s' % (len(names), nc, opt.data) # check + + # Model + pretrained = weights.endswith('.pt') + if pretrained: + with torch_distributed_zero_first(rank): + attempt_download(weights) # download if not found locally + ckpt = torch.load(weights, map_location=device) # load checkpoint + model = Darknet(opt.cfg).to(device) # create + state_dict = {k: v for k, v in ckpt['model'].items() if model.state_dict()[k].numel() == v.numel()} + model.load_state_dict(state_dict, strict=False) + print('Transferred %g/%g items from %s' % (len(state_dict), len(model.state_dict()), weights)) # report + else: + model = Darknet(opt.cfg).to(device) # create + + # Image sizes + gs = 64 #int(max(model.stride)) # grid size (max stride) + imgsz, imgsz_test = [check_img_size(x, gs) for x in opt.img_size] # verify imgsz are gs-multiples + + # Optimizer + nbs = 64 # nominal batch size + accumulate = max(round(nbs / total_batch_size), 1) # accumulate loss before optimizing + hyp['weight_decay'] *= total_batch_size * accumulate / nbs # scale weight_decay + + pg0, pg1, pg2 = [], [], [] # optimizer parameter groups + for k, v in dict(model.named_parameters()).items(): + if '.bias' in k: + pg2.append(v) # biases + elif 'Conv2d.weight' in k: + pg1.append(v) # apply weight_decay + elif 'm.weight' in k: + pg1.append(v) # apply weight_decay + elif 'w.weight' in k: + pg1.append(v) # apply weight_decay + else: + pg0.append(v) # all else + + if opt.adam: + optimizer = optim.Adam(pg0, lr=hyp['lr0'], betas=(hyp['momentum'], 0.999)) # adjust beta1 to momentum + else: + if device.type == 'npu': + optimizer = apex.optimizers.NpuFusedSGD(pg0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True) + else: + optimizer = optim.SGD(pg0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True) + + optimizer.add_param_group({'params': pg1, 'weight_decay': hyp['weight_decay']}) # add pg1 with weight_decay + optimizer.add_param_group({'params': pg2}) # add pg2 (biases) + print('Optimizer groups: %g .bias, %g conv.weight, %g other' % (len(pg2), len(pg1), len(pg0))) + del pg0, pg1, pg2 + + # Logging + if wandb and wandb.run is None: + opt.hyp = hyp # add hyperparameters + wandb_run = wandb.init(config=opt, resume="allow", + project='YOLOR' if opt.project == 'runs/train' else Path(opt.project).stem, + name=save_dir.stem, + id=ckpt.get('wandb_id') if 'ckpt' in locals() else None) + + # Resume + start_epoch = 0 + # best_fitness, best_fitness_p, best_fitness_r, best_fitness_ap50, best_fitness_ap, best_fitness_f = 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 + if pretrained: + # Optimizer + if ckpt['optimizer'] is not None: + optimizer.load_state_dict(ckpt['optimizer']) + # best_fitness = ckpt['best_fitness'] + # best_fitness_p = ckpt['best_fitness_p'] + # best_fitness_r = ckpt['best_fitness_r'] + # best_fitness_ap50 = ckpt['best_fitness_ap50'] + # best_fitness_ap = ckpt['best_fitness_ap'] + # best_fitness_f = ckpt['best_fitness_f'] + + # Results + if ckpt.get('training_results') is not None: + with open(results_file, 'w') as file: + file.write(ckpt['training_results']) # write results.txt + + # Epochs + start_epoch = ckpt['epoch'] + 1 + if opt.resume: + assert start_epoch > 0, '%s training to %g epochs is finished, nothing to resume.' % (weights, epochs) + if epochs < start_epoch: + print('%s has been trained for %g epochs. Fine-tuning for %g additional epochs.' % + (weights, ckpt['epoch'], epochs)) + epochs += ckpt['epoch'] # finetune additional epochs + + del ckpt, state_dict + + # Mixed precision training https://github.com/NVIDIA/apex + if mixed_precision: + if device.type == 'npu': + model, optimizer = amp.initialize(model, optimizer, opt_level='O1', verbosity=0, loss_scale=64, combine_grad=True) + else: + model, optimizer = amp.initialize(model, optimizer, opt_level='O1', verbosity=0, loss_scale=64) + + # Scheduler https://arxiv.org/pdf/1812.01187.pdf + # https://pytorch.org/docs/stable/_modules/torch/optim/lr_scheduler.html#OneCycleLR + lf = lambda x: ((1 + math.cos(x * math.pi / epochs)) / 2) * (1 - hyp['lrf']) + hyp['lrf'] # cosine + scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) + # plot_lr_scheduler(optimizer, scheduler, epochs) + + + # SyncBatchNorm + if opt.sync_bn and cuda and rank != -1: + model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model).to(device) + print('Using SyncBatchNorm()') + + # EMA + ema = ModelEMA(model) if rank in [-1, 0] else None + + # DDP mode + if device.type == 'cuda' and rank != -1: + model = DDP(model, device_ids=[rank], output_device=rank) + elif device.type == 'npu' and rank != -1: + model = DDP(model, device_ids=[rank], broadcast_buffers=False) + + # Trainloader + dataloader, dataset = create_dataloader(train_path, imgsz, batch_size, gs, opt, + hyp=hyp, augment=True, cache=opt.cache_images, rect=opt.rect, + rank=rank, world_size=opt.world_size, workers=opt.workers) + mlc = np.concatenate(dataset.labels, 0)[:, 0].max() # max label class + nb = len(dataloader) # number of batches + assert mlc < nc, 'Label class %g exceeds nc=%g in %s. Possible class labels are 0-%g' % (mlc, nc, opt.data, nc - 1) + + # Model parameters + hyp['cls'] *= nc / 80. # scale coco-tuned hyp['cls'] to current dataset + model.nc = nc # attach number of classes to model + model.hyp = hyp # attach hyperparameters to model + model.gr = 1.0 # iou loss ratio (obj_loss = 1.0 or iou) + model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) # attach class weights + model.names = names + + # Process 0 + if rank in [-1, 0]: + ema.updates = start_epoch * nb // accumulate # set EMA updates + testloader = create_dataloader(test_path, imgsz_test, batch_size*2, gs, opt, + hyp=hyp, cache=opt.cache_images and not opt.notest, rect=True, + rank=-1, world_size=opt.world_size, workers=opt.workers)[0] # testloader + + if not opt.resume: + labels = np.concatenate(dataset.labels, 0) + c = torch.tensor(labels[:, 0]) # classes + # cf = torch.bincount(c.long(), minlength=nc) + 1. # frequency + # model._initialize_biases(cf.to(device)) + if plots: + plot_labels(labels, save_dir=save_dir) + if tb_writer: + tb_writer.add_histogram('classes', c, 0) + if wandb: + wandb.log({"Labels": [wandb.Image(str(x), caption=x.name) for x in save_dir.glob('*labels*.png')]}) + + # Anchors + # if not opt.noautoanchor: + # check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz) + + + # Start training + t0 = time.time() + nw = max(round(hyp['warmup_epochs'] * nb), 1000) # number of warmup iterations, max(3 epochs, 1k iterations) + # nw = min(nw, (epochs - start_epoch) / 2 * nb) # limit warmup to < 1/2 of training + maps = np.zeros(nc) # mAP per class + results = (0, 0, 0, 0, 0, 0, 0) # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls) + scheduler.last_epoch = start_epoch - 1 # do not move + if rank in [0, -1]: + print('Image sizes %g train, %g test\n' + 'Using %g dataloader workers\nLogging results to %s\n' + 'Starting training for %g epochs...' % (imgsz, imgsz_test, dataloader.num_workers, save_dir, epochs)) + + for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ + model.train() + + # Update image weights (optional) + # When in DDP mode, the generated indices will be broadcasted to synchronize dataset. + if opt.image_weights: + # Generate indices + if rank in [-1, 0]: + cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 # class weights + iw = labels_to_image_weights(dataset.labels, nc=nc, class_weights=cw) # image weights + dataset.indices = random.choices(range(dataset.n), weights=iw, k=dataset.n) # rand weighted idx + # Broadcast if DDP + if rank != -1: + indices = (torch.tensor(dataset.indices) if rank == 0 else torch.zeros(dataset.n)).int() + dist.broadcast(indices, 0) + if rank != 0: + dataset.indices = indices.cpu().numpy() + + # Update mosaic border + # b = int(random.uniform(0.25 * imgsz, 0.75 * imgsz + gs) // gs * gs) + # dataset.mosaic_border = [b - imgsz, -b] # height, width borders + + mloss = torch.zeros(4, device=device) # mean losses + if rank != -1: + dataloader.sampler.set_epoch(epoch) + optimizer.zero_grad() + start_time = time.time() + d_1 = time.time() + + for i, (imgs, targets, paths, _) in enumerate(dataloader): # batch ------------------------------------------------------------- + t_time = time.time() + d_time = t_time - d_1 + ni = i + nb * epoch # number integrated batches (since train start) + imgs = imgs.to(device, non_blocking=True).float() / 255.0 # uint8 to float32, 0-255 to 0.0-1.0 + + # Warmup + if ni <= nw: + xi = [0, nw] # x interp + # model.gr = np.interp(ni, xi, [0.0, 1.0]) # iou loss ratio (obj_loss = 1.0 or iou) + accumulate = max(1, np.interp(ni, xi, [1, nbs / total_batch_size]).round()) + for j, x in enumerate(optimizer.param_groups): + # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0 + x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 2 else 0.0, x['initial_lr'] * lf(epoch)]) + if 'momentum' in x: + x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']]) + + # Multi-scale + if opt.multi_scale: + sz = random.randrange(imgsz * 0.5, imgsz * 1.5 + gs) // gs * gs # size + sf = sz / max(imgs.shape[2:]) # scale factor + if sf != 1: + ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to gs-multiple) + imgs = F.interpolate(imgs, size=ns, mode='bilinear', align_corners=False) + + # Forward + pred = model(imgs) + + # Loss + loss, loss_items = compute_loss(pred, targets.to(device), model) # scaled by batch_size + if rank != -1: + loss *= opt.world_size # gradient averaged between devices in DDP mode + if not torch.isfinite(loss): + print('WARNING: non-finite loss, ending training ', loss_items) + return results + + # Backward + if mixed_precision: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + + # Optimize + if ni % accumulate == 0: + optimizer.step() + optimizer.zero_grad() + if ema is not None: + x = torch.tensor([1.]).to(device) + if device.type == 'npu': + params_fp32_fused = optimizer.get_model_combined_params() + ema.update(model, x, params_fp32_fused[0]) + else: + ema.update(model, x) + + if i <= 10: + sum_time = (time.time() - start_time) / (i + 1) + if i == 10: + start_time = time.time() + else: + sum_time = (time.time() - start_time) / (i - 10) + ptime = time.time() - d_1 + # Print + if rank in [-1, 0]: + mloss = (mloss * i + loss_items) / (i + 1) # update mean losses + mem = '%.3gG' % (torch.cuda.memory_cached() / 1E9 if torch.cuda.is_available() else 0) # (GB) + s = ('%10s' * 2 + '%10.4g' * 6) % ( + '%g/%g' % (epoch, epochs - 1), mem, *mloss, targets.shape[0], imgs.shape[-1]) + print( + 'Epoch:[%2g][%4g/%4g][%s][FPS:%3.1f][mTime:%3.3f][pTime:%3.3f][dTime:%3.3f] GIoU:%.3f objectness:%.3f classfication:%.3f totalLoss:%.3f' % ( + epoch, i, nb, device, opt.total_batch_size / sum_time, sum_time, ptime, d_time, *mloss)) + + # Plot + if plots and ni < 3: + f = save_dir / f'train_batch{ni}.jpg' # filename + plot_images(images=imgs, targets=targets, paths=paths, fname=f) + # if tb_writer: + # tb_writer.add_image(f, result, dataformats='HWC', global_step=epoch) + # tb_writer.add_graph(model, imgs) # add model to tensorboard + elif plots and ni == 3 and wandb: + wandb.log({"Mosaics": [wandb.Image(str(x), caption=x.name) for x in save_dir.glob('train*.jpg')]}) + if i > 170: + break + d_1 = time.time() + # end batch ------------------------------------------------------------------------------------------------ + # end epoch ---------------------------------------------------------------------------------------------------- + + # Scheduler + lr = [x['lr'] for x in optimizer.param_groups] # for tensorboard + scheduler.step() + + # DDP process 0 or single-GPU + if rank in [-1, 0]: + # mAP + if ema: + ema.update_attr(model) + final_epoch = epoch + 1 == epochs + if False: # No test during training + results, maps, _ = test.test(opt.data, + batch_size=batch_size*2, + imgsz=imgsz_test, + model=ema.ema.module if hasattr(ema.ema, 'module') else ema.ema, + single_cls=opt.single_cls, + dataloader=testloader, + save_dir=save_dir, + plots=True) + + # Write + with open(results_file, 'a') as f: + f.write(s + '%10.4g' * 7 % results + '\n') # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls) + if len(opt.name) and opt.bucket: + os.system('gsutil cp %s gs://%s/results/results%s.txt' % (results_file, opt.bucket, opt.name)) + + # Log + tags = ['train/box_loss', 'train/obj_loss', 'train/cls_loss', # train loss + 'metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/mAP_0.5:0.95', + 'val/box_loss', 'val/obj_loss', 'val/cls_loss', # val loss + 'x/lr0', 'x/lr1', 'x/lr2'] # params + for x, tag in zip(list(mloss[:-1]) + list(results) + lr, tags): + if tb_writer: + tb_writer.add_scalar(tag, x, epoch) # tensorboard + if wandb: + wandb.log({tag: x}) # W&B + + # # Update best mAP + # fi = fitness(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] + # fi_p = fitness_p(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] + # fi_r = fitness_r(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] + # fi_ap50 = fitness_ap50(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] + # fi_ap = fitness_ap(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] + # if (fi_p > 0.0) or (fi_r > 0.0): + # fi_f = fitness_f(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] + # else: + # fi_f = 0.0 + # if fi > best_fitness: + # best_fitness = fi + # if fi_p > best_fitness_p: + # best_fitness_p = fi_p + # if fi_r > best_fitness_r: + # best_fitness_r = fi_r + # if fi_ap50 > best_fitness_ap50: + # best_fitness_ap50 = fi_ap50 + # if fi_ap > best_fitness_ap: + # best_fitness_ap = fi_ap + # if fi_f > best_fitness_f: + # best_fitness_f = fi_f + + # Save model + save = (not opt.nosave) or (final_epoch and not opt.evolve) + if save: + with open(results_file, 'r') as f: # create checkpoint + ckpt = {'epoch': epoch, + # 'best_fitness': best_fitness, + # 'best_fitness_p': best_fitness_p, + # 'best_fitness_r': best_fitness_r, + # 'best_fitness_ap50': best_fitness_ap50, + # 'best_fitness_ap': best_fitness_ap, + # 'best_fitness_f': best_fitness_f, + 'training_results': f.read(), + 'model': ema.ema.module.state_dict() if hasattr(ema, 'module') else ema.ema.state_dict(), + 'optimizer': None if final_epoch else optimizer.state_dict(), + 'wandb_id': wandb_run.id if wandb else None} + + # Save last, best and delete + torch.save(ckpt, last) + # if best_fitness == fi: + # torch.save(ckpt, best) + # if (best_fitness == fi) and (epoch >= 200): + # torch.save(ckpt, wdir / 'best_{:03d}.pt'.format(epoch)) + # if best_fitness == fi: + # torch.save(ckpt, wdir / 'best_overall.pt') + # if best_fitness_p == fi_p: + # torch.save(ckpt, wdir / 'best_p.pt') + # if best_fitness_r == fi_r: + # torch.save(ckpt, wdir / 'best_r.pt') + # if best_fitness_ap50 == fi_ap50: + # torch.save(ckpt, wdir / 'best_ap50.pt') + # if best_fitness_ap == fi_ap: + # torch.save(ckpt, wdir / 'best_ap.pt') + # if best_fitness_f == fi_f: + # torch.save(ckpt, wdir / 'best_f.pt') + if epoch == 0: + torch.save(ckpt, wdir / 'epoch_{:03d}.pt'.format(epoch)) + if ((epoch+1) % 25) == 0: + torch.save(ckpt, wdir / 'epoch_{:03d}.pt'.format(epoch)) + if epoch >= (epochs-5): + torch.save(ckpt, wdir / 'last_{:03d}.pt'.format(epoch)) + elif epoch >= 420: + torch.save(ckpt, wdir / 'last_{:03d}.pt'.format(epoch)) + del ckpt + # end epoch ---------------------------------------------------------------------------------------------------- + # end training + + if rank in [-1, 0]: + # Strip optimizers + n = opt.name if opt.name.isnumeric() else '' + fresults, flast, fbest = save_dir / f'results{n}.txt', wdir / f'last{n}.pt', wdir / f'best{n}.pt' + for f1, f2 in zip([wdir / 'last.pt', wdir / 'best.pt', results_file], [flast, fbest, fresults]): + if f1.exists(): + os.rename(f1, f2) # rename + if str(f2).endswith('.pt'): # is *.pt + strip_optimizer(f2) # strip optimizer + os.system('gsutil cp %s gs://%s/weights' % (f2, opt.bucket)) if opt.bucket else None # upload + # Finish + if plots: + plot_results(save_dir=save_dir) # save as results.png + if wandb: + wandb.log({"Results": [wandb.Image(str(save_dir / x), caption=x) for x in + ['results.png', 'precision-recall_curve.png']]}) + print('%g epochs completed in %.3f hours.\n' % (epoch - start_epoch + 1, (time.time() - t0) / 3600)) + + else: + dist.destroy_process_group() + + wandb.run.finish() if wandb and wandb.run else None + torch.cuda.empty_cache() + + return results + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--weights', type=str, default='yolor_p6.pt', help='initial weights path') + parser.add_argument('--cfg', type=str, default='', help='model.yaml path') + parser.add_argument('--data', type=str, default='data/coco.yaml', help='data.yaml path') + parser.add_argument('--hyp', type=str, default='data/hyp.scratch.1280.yaml', help='hyperparameters path') + parser.add_argument('--epochs', type=int, default=300) + parser.add_argument('--batch-size', type=int, default=8, help='total batch size for all GPUs') + parser.add_argument('--img-size', nargs='+', type=int, default=[1280, 1280], help='[train, test] image sizes') + parser.add_argument('--rect', action='store_true', help='rectangular training') + parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training') + parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') + parser.add_argument('--notest', action='store_true', help='only test final epoch') + parser.add_argument('--noautoanchor', action='store_true', help='disable autoanchor check') + parser.add_argument('--evolve', action='store_true', help='evolve hyperparameters') + parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') + parser.add_argument('--cache-images', action='store_true', help='cache images for faster training') + parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu or npu') + parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') + parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') + parser.add_argument('--adam', action='store_true', help='use torch.optim.Adam() optimizer') + parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') + parser.add_argument('--full', action='store_true', help='full mode') + parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify') + parser.add_argument('--log-imgs', type=int, default=16, help='number of images for W&B logging, max 100') + parser.add_argument('--workers', type=int, default=8, help='maximum number of dataloader workers') + parser.add_argument('--project', default='runs/train', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--npu', default=-1, type=int, help='NPU id to use.') + + # NPU DDP mode + parser.add_argument('--world-size', default=1, type=int, help='number of nodes for distributed training') + parser.add_argument('--device-num', default=1, type=int, help='multi NPU parameter, GPU or CPU do not modify') + parser.add_argument('--addr', default='127.0.0.1', type=str, help='DDP master node IP') + parser.add_argument('--dist-url', default='tcp://127.0.0.1:29501', type=str, + help='url used to set up distributed training') + opt = parser.parse_args() + + if opt.dist_url == "env://": + opt.world_size = int(os.environ["WORLD_SIZE"]) + ngpus_per_node = opt.device_num + opt.npu_ddp = (opt.device_num > 1 or opt.world_size > 1) + if opt.npu_ddp: + print('multi npu training') + os.environ['MASTER_ADDR'] = opt.addr # master ip + os.environ['MASTER_PORT'] = '29501' + os.environ['KERNEL_NAME_ID'] = str(0) + opt.world_size = ngpus_per_node * opt.world_size # the sum of GPU or NPU in all the nodes + mp.spawn(main_worker, nprocs=ngpus_per_node, args=(ngpus_per_node, opt)) + else: + print('1p training') + main_worker(opt.npu, ngpus_per_node, opt) + + # # Set DDP variables + # opt.total_batch_size = opt.batch_size + # opt.world_size = int(os.environ['WORLD_SIZE']) if 'WORLD_SIZE' in os.environ else 1 + # opt.global_rank = int(os.environ['RANK']) if 'RANK' in os.environ else -1 + # set_logging(opt.global_rank) + # if opt.global_rank in [-1, 0]: + # check_git_status() + + # # DDP mode + # device = select_device(opt.device, batch_size=opt.batch_size) + # if opt.local_rank != -1: + # assert torch.cuda.device_count() > opt.local_rank + # torch.cuda.set_device(opt.local_rank) + # device = torch.device('cuda', opt.local_rank) + # dist.init_process_group(backend='nccl', init_method='env://') # distributed backend + # assert opt.batch_size % opt.world_size == 0, '--batch-size must be multiple of CUDA device count' + # opt.batch_size = opt.total_batch_size // opt.world_size + + +def main_worker(npu, ngpus_per_node, opt): + # Resume + if opt.resume: # resume an interrupted run + ckpt = opt.resume if isinstance(opt.resume, str) else get_latest_run() # specified or most recent path + assert os.path.isfile(ckpt), 'ERROR: --resume checkpoint does not exist' + with open(Path(ckpt).parent.parent / 'opt.yaml') as f: + opt = argparse.Namespace(**yaml.load(f, Loader=yaml.FullLoader)) # replace + opt.cfg, opt.weights, opt.resume = '', ckpt, True + print('Resuming training from %s' % ckpt) + else: + # opt.hyp = opt.hyp or ('hyp.finetune.yaml' if opt.weights else 'hyp.scratch.yaml') + opt.data, opt.cfg, opt.hyp = check_file(opt.data), check_file(opt.cfg), check_file(opt.hyp) # check files + assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified' + opt.img_size.extend([opt.img_size[-1]] * (2 - len(opt.img_size))) # extend to 2 sizes (train, test) + opt.name = 'evolve' if opt.evolve else opt.name + opt.save_dir = increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok | opt.evolve) # increment run + + # Hyperparameters + with open(opt.hyp) as f: + hyp = yaml.load(f, Loader=yaml.FullLoader) # load hyps + if 'box' not in hyp: + warn('Compatibility: %s missing "box" which was renamed from "giou" in %s' % + (opt.hyp, 'https://github.com/ultralytics/yolov5/pull/1120')) + hyp['box'] = hyp.pop('giou') + + # npu DDP + if opt.npu_ddp: + opt.npu = npu + os.environ['KERNEL_NAME_ID'] = str(npu) + print("[npu id:", opt.npu, "]", "+++++++++++++++++++++++++++KERNEL_NAME_ID:", os.environ['KERNEL_NAME_ID']) + opt.local_rank = opt.local_rank * ngpus_per_node + npu + global mixed_precision + device = torch_utils.select_device(opt.device, opt.npu, apex=mixed_precision, batch_size=opt.batch_size) + opt.total_batch_size = opt.batch_size + if device.type == 'cpu': + mixed_precision = False + elif opt.local_rank != -1 and device.type == 'cuda': + # DDP mode + assert torch.cuda.device_count() > opt.local_rank + torch.cuda.set_device(opt.local_rank) + device = torch.device("cuda", opt.local_rank) + dist.init_process_group(backend='nccl', init_method='env://') # distributed backend + + opt.world_size = dist.get_world_size() + assert opt.batch_size % opt.world_size == 0, "Batch size is not a multiple of the number of devices given!" + opt.batch_size = opt.total_batch_size // opt.world_size + elif opt.local_rank != -1 and device.type == 'npu': + dist.init_process_group(backend='hccl', world_size=opt.world_size, rank=opt.local_rank) + assert opt.batch_size % opt.world_size == 0, "Batch size is not a multiple of the number of devices given!" + opt.batch_size = opt.total_batch_size // opt.world_size + + # Train + print(opt) + if not opt.evolve: + tb_writer = None # init loggers + if opt.local_rank in [-1, 0]: + print(f'Start Tensorboard with "tensorboard --logdir {opt.project}", view at http://localhost:6006/') + tb_writer = SummaryWriter(opt.save_dir) # Tensorboard + train(hyp, opt, device, tb_writer, wandb) + + # Evolve hyperparameters (optional) + else: + # Hyperparameter evolution metadata (mutation scale 0-1, lower_limit, upper_limit) + meta = {'lr0': (1, 1e-5, 1e-1), # initial learning rate (SGD=1E-2, Adam=1E-3) + 'lrf': (1, 0.01, 1.0), # final OneCycleLR learning rate (lr0 * lrf) + 'momentum': (0.3, 0.6, 0.98), # SGD momentum/Adam beta1 + 'weight_decay': (1, 0.0, 0.001), # optimizer weight decay + 'warmup_epochs': (1, 0.0, 5.0), # warmup epochs (fractions ok) + 'warmup_momentum': (1, 0.0, 0.95), # warmup initial momentum + 'warmup_bias_lr': (1, 0.0, 0.2), # warmup initial bias lr + 'box': (1, 0.02, 0.2), # box loss gain + 'cls': (1, 0.2, 4.0), # cls loss gain + 'cls_pw': (1, 0.5, 2.0), # cls BCELoss positive_weight + 'obj': (1, 0.2, 4.0), # obj loss gain (scale with pixels) + 'obj_pw': (1, 0.5, 2.0), # obj BCELoss positive_weight + 'iou_t': (0, 0.1, 0.7), # IoU training threshold + 'anchor_t': (1, 2.0, 8.0), # anchor-multiple threshold + 'anchors': (2, 2.0, 10.0), # anchors per output grid (0 to ignore) + 'fl_gamma': (0, 0.0, 2.0), # focal loss gamma (efficientDet default gamma=1.5) + 'hsv_h': (1, 0.0, 0.1), # image HSV-Hue augmentation (fraction) + 'hsv_s': (1, 0.0, 0.9), # image HSV-Saturation augmentation (fraction) + 'hsv_v': (1, 0.0, 0.9), # image HSV-Value augmentation (fraction) + 'degrees': (1, 0.0, 45.0), # image rotation (+/- deg) + 'translate': (1, 0.0, 0.9), # image translation (+/- fraction) + 'scale': (1, 0.0, 0.9), # image scale (+/- gain) + 'shear': (1, 0.0, 10.0), # image shear (+/- deg) + 'perspective': (0, 0.0, 0.001), # image perspective (+/- fraction), range 0-0.001 + 'flipud': (1, 0.0, 1.0), # image flip up-down (probability) + 'fliplr': (0, 0.0, 1.0), # image flip left-right (probability) + 'mosaic': (1, 0.0, 1.0), # image mixup (probability) + 'mixup': (1, 0.0, 1.0)} # image mixup (probability) + + assert opt.local_rank == -1, 'DDP mode not implemented for --evolve' + opt.notest, opt.nosave = True, True # only test/save final epoch + # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices + yaml_file = Path(opt.save_dir) / 'hyp_evolved.yaml' # save best result here + if opt.bucket: + os.system('gsutil cp gs://%s/evolve.txt .' % opt.bucket) # download evolve.txt if exists + + for _ in range(300): # generations to evolve + if Path('evolve.txt').exists(): # if evolve.txt exists: select best hyps and mutate + # Select parent(s) + parent = 'single' # parent selection method: 'single' or 'weighted' + x = np.loadtxt('evolve.txt', ndmin=2) + n = min(5, len(x)) # number of previous results to consider + x = x[np.argsort(-fitness(x))][:n] # top n mutations + w = fitness(x) - fitness(x).min() # weights + if parent == 'single' or len(x) == 1: + # x = x[random.randint(0, n - 1)] # random selection + x = x[random.choices(range(n), weights=w)[0]] # weighted selection + elif parent == 'weighted': + x = (x * w.reshape(n, 1)).sum(0) / w.sum() # weighted combination + + # Mutate + mp, s = 0.8, 0.2 # mutation probability, sigma + npr = np.random + npr.seed(int(time.time())) + g = np.array([x[0] for x in meta.values()]) # gains 0-1 + ng = len(meta) + v = np.ones(ng) + while all(v == 1): # mutate until a change occurs (prevent duplicates) + v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0) + for i, k in enumerate(hyp.keys()): # plt.hist(v.ravel(), 300) + hyp[k] = float(x[i + 7] * v[i]) # mutate + + # Constrain to limits + for k, v in meta.items(): + hyp[k] = max(hyp[k], v[1]) # lower limit + hyp[k] = min(hyp[k], v[2]) # upper limit + hyp[k] = round(hyp[k], 5) # significant digits + + # Train mutation + results = train(hyp.copy(), opt, device, wandb=wandb) + + # Write mutation results + print_mutation(hyp.copy(), results, yaml_file, opt.bucket) + + # Plot results + plot_evolution(yaml_file) + print(f'Hyperparameter evolution complete. Best results saved as: {yaml_file}\n' + f'Command to train a new model with these hyperparameters: $ python train.py --hyp {yaml_file}') + + +if __name__ == '__main__': + # option = {} + # option["ACL_OP_DEBUG_LEVEL"] = 3 # 算子debug功能,暂不开启 + # option["ACL_DEBUG_DIR"] = "debug_file" # 算子debug功能对应文件夹,暂不开启 + # option["ACL_OP_COMPILER_CACHE_MODE"] = "enable" # cache功能启用 + # option["ACL_OP_COMPILER_CACHE_DIR"] = "./kernel_meta" # cache所在文件夹 + # print("option:",option) + # torch.npu.set_option(option) + main() diff --git a/PyTorch/contrib/cv/detection/YOLOR/utils/__init__.py b/PyTorch/contrib/cv/detection/YOLOR/utils/__init__.py index d3f5a12faa..8b13789179 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/utils/__init__.py +++ b/PyTorch/contrib/cv/detection/YOLOR/utils/__init__.py @@ -1 +1 @@ - + diff --git a/PyTorch/contrib/cv/detection/YOLOR/utils/activations.py b/PyTorch/contrib/cv/detection/YOLOR/utils/activations.py index 8b64eae41c..8bf1e62efb 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/utils/activations.py +++ b/PyTorch/contrib/cv/detection/YOLOR/utils/activations.py @@ -1,85 +1,85 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -# Activation functions - -import torch -import torch.nn as nn -import torch.nn.functional as F - -# Swish https://arxiv.org/pdf/1905.02244.pdf --------------------------------------------------------------------------- -class Swish(nn.Module): # - @staticmethod - def forward(x): - return x * torch.sigmoid(x) - - -class Hardswish(nn.Module): # export-friendly version of nn.Hardswish() - @staticmethod - def forward(x): - # return x * F.hardsigmoid(x) # for torchscript and CoreML - return x * F.hardtanh(x + 3, 0., 6.) / 6. # for torchscript, CoreML and ONNX - - -class MemoryEfficientSwish(nn.Module): - class F(torch.autograd.Function): - @staticmethod - def forward(ctx, x): - ctx.save_for_backward(x) - return x * torch.sigmoid(x) - - @staticmethod - def backward(ctx, grad_output): - x = ctx.saved_tensors[0] - sx = torch.sigmoid(x) - return grad_output * (sx * (1 + x * (1 - sx))) - - def forward(self, x): - return self.F.apply(x) - - -# Mish https://github.com/digantamisra98/Mish -------------------------------------------------------------------------- -class Mish(nn.Module): - @staticmethod - def forward(x): - return x * F.softplus(x).tanh() - - -class MemoryEfficientMish(nn.Module): - class F(torch.autograd.Function): - @staticmethod - def forward(ctx, x): - ctx.save_for_backward(x) - return x.mul(torch.tanh(F.softplus(x))) # x * tanh(ln(1 + exp(x))) - - @staticmethod - def backward(ctx, grad_output): - x = ctx.saved_tensors[0] - sx = torch.sigmoid(x) - fx = F.softplus(x).tanh() - return grad_output * (fx + x * sx * (1 - fx * fx)) - - def forward(self, x): - return self.F.apply(x) - - -# FReLU https://arxiv.org/abs/2007.11824 ------------------------------------------------------------------------------- -class FReLU(nn.Module): - def __init__(self, c1, k=3): # ch_in, kernel - super().__init__() - self.conv = nn.Conv2d(c1, c1, k, 1, 1, groups=c1) - self.bn = nn.BatchNorm2d(c1) - - def forward(self, x): - return torch.max(x, self.bn(self.conv(x))) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +# Activation functions + +import torch +import torch.nn as nn +import torch.nn.functional as F + +# Swish https://arxiv.org/pdf/1905.02244.pdf --------------------------------------------------------------------------- +class Swish(nn.Module): # + @staticmethod + def forward(x): + return x * torch.sigmoid(x) + + +class Hardswish(nn.Module): # export-friendly version of nn.Hardswish() + @staticmethod + def forward(x): + # return x * F.hardsigmoid(x) # for torchscript and CoreML + return x * F.hardtanh(x + 3, 0., 6.) / 6. # for torchscript, CoreML and ONNX + + +class MemoryEfficientSwish(nn.Module): + class F(torch.autograd.Function): + @staticmethod + def forward(ctx, x): + ctx.save_for_backward(x) + return x * torch.sigmoid(x) + + @staticmethod + def backward(ctx, grad_output): + x = ctx.saved_tensors[0] + sx = torch.sigmoid(x) + return grad_output * (sx * (1 + x * (1 - sx))) + + def forward(self, x): + return self.F.apply(x) + + +# Mish https://github.com/digantamisra98/Mish -------------------------------------------------------------------------- +class Mish(nn.Module): + @staticmethod + def forward(x): + return x * F.softplus(x).tanh() + + +class MemoryEfficientMish(nn.Module): + class F(torch.autograd.Function): + @staticmethod + def forward(ctx, x): + ctx.save_for_backward(x) + return x.mul(torch.tanh(F.softplus(x))) # x * tanh(ln(1 + exp(x))) + + @staticmethod + def backward(ctx, grad_output): + x = ctx.saved_tensors[0] + sx = torch.sigmoid(x) + fx = F.softplus(x).tanh() + return grad_output * (fx + x * sx * (1 - fx * fx)) + + def forward(self, x): + return self.F.apply(x) + + +# FReLU https://arxiv.org/abs/2007.11824 ------------------------------------------------------------------------------- +class FReLU(nn.Module): + def __init__(self, c1, k=3): # ch_in, kernel + super().__init__() + self.conv = nn.Conv2d(c1, c1, k, 1, 1, groups=c1) + self.bn = nn.BatchNorm2d(c1) + + def forward(self, x): + return torch.max(x, self.bn(self.conv(x))) diff --git a/PyTorch/contrib/cv/detection/YOLOR/utils/autoanchor.py b/PyTorch/contrib/cv/detection/YOLOR/utils/autoanchor.py index 2fd6d56da5..709b00f4b1 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/utils/autoanchor.py +++ b/PyTorch/contrib/cv/detection/YOLOR/utils/autoanchor.py @@ -1,166 +1,166 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -# Auto-anchor utils - -import numpy as np -import torch -import yaml -from scipy.cluster.vq import kmeans -from tqdm import tqdm - - -def check_anchor_order(m): - # Check anchor order against stride order for YOLOv5 Detect() module m, and correct if necessary - a = m.anchor_grid.prod(-1).view(-1) # anchor area - da = a[-1] - a[0] # delta a - ds = m.stride[-1] - m.stride[0] # delta s - if da.sign() != ds.sign(): # same order - print('Reversing anchor order') - m.anchors[:] = m.anchors.flip(0) - m.anchor_grid[:] = m.anchor_grid.flip(0) - - -def check_anchors(dataset, model, thr=4.0, imgsz=640): - # Check anchor fit to data, recompute if necessary - print('\nAnalyzing anchors... ', end='') - m = model.module.model[-1] if hasattr(model, 'module') else model.model[-1] # Detect() - shapes = imgsz * dataset.shapes / dataset.shapes.max(1, keepdims=True) - scale = np.random.uniform(0.9, 1.1, size=(shapes.shape[0], 1)) # augment scale - wh = torch.tensor(np.concatenate([l[:, 3:5] * s for s, l in zip(shapes * scale, dataset.labels)])).float() # wh - - def metric(k): # compute metric - r = wh[:, None] / k[None] - x = torch.min(r, 1. / r).min(2)[0] # ratio metric - best = x.max(1)[0] # best_x - aat = (x > 1. / thr).float().sum(1).mean() # anchors above threshold - bpr = (best > 1. / thr).float().mean() # best possible recall - return bpr, aat - - bpr, aat = metric(m.anchor_grid.clone().cpu().view(-1, 2)) - print('anchors/target = %.2f, Best Possible Recall (BPR) = %.4f' % (aat, bpr), end='') - if bpr < 0.98: # threshold to recompute - print('. Attempting to improve anchors, please wait...') - na = m.anchor_grid.numel() // 2 # number of anchors - new_anchors = kmean_anchors(dataset, n=na, img_size=imgsz, thr=thr, gen=1000, verbose=False) - new_bpr = metric(new_anchors.reshape(-1, 2))[0] - if new_bpr > bpr: # replace anchors - new_anchors = torch.tensor(new_anchors, device=m.anchors.device).type_as(m.anchors) - m.anchor_grid[:] = new_anchors.clone().view_as(m.anchor_grid) # for inference - m.anchors[:] = new_anchors.clone().view_as(m.anchors) / m.stride.to(m.anchors.device).view(-1, 1, 1) # loss - check_anchor_order(m) - print('New anchors saved to model. Update model *.yaml to use these anchors in the future.') - else: - print('Original anchors better than new anchors. Proceeding with original anchors.') - print('') # newline - - -def kmean_anchors(path='./data/coco128.yaml', n=9, img_size=640, thr=4.0, gen=1000, verbose=True): - """ Creates kmeans-evolved anchors from training dataset - - Arguments: - path: path to dataset *.yaml, or a loaded dataset - n: number of anchors - img_size: image size used for training - thr: anchor-label wh ratio threshold hyperparameter hyp['anchor_t'] used for training, default=4.0 - gen: generations to evolve anchors using genetic algorithm - verbose: print all results - - Return: - k: kmeans evolved anchors - - Usage: - from utils.general import *; _ = kmean_anchors() - """ - thr = 1. / thr - - def metric(k, wh): # compute metrics - r = wh[:, None] / k[None] - x = torch.min(r, 1. / r).min(2)[0] # ratio metric - # x = wh_iou(wh, torch.tensor(k)) # iou metric - return x, x.max(1)[0] # x, best_x - - def anchor_fitness(k): # mutation fitness - _, best = metric(torch.tensor(k, dtype=torch.float32), wh) - return (best * (best > thr).float()).mean() # fitness - - def print_results(k): - k = k[np.argsort(k.prod(1))] # sort small to large - x, best = metric(k, wh0) - bpr, aat = (best > thr).float().mean(), (x > thr).float().mean() * n # best possible recall, anch > thr - print('thr=%.2f: %.4f best possible recall, %.2f anchors past thr' % (thr, bpr, aat)) - print('n=%g, img_size=%s, metric_all=%.3f/%.3f-mean/best, past_thr=%.3f-mean: ' % - (n, img_size, x.mean(), best.mean(), x[x > thr].mean()), end='') - for i, x in enumerate(k): - print('%i,%i' % (round(x[0]), round(x[1])), end=', ' if i < len(k) - 1 else '\n') # use in *.cfg - return k - - if isinstance(path, str): # *.yaml file - with open(path) as f: - data_dict = yaml.load(f, Loader=yaml.FullLoader) # model dict - from utils.datasets import LoadImagesAndLabels - dataset = LoadImagesAndLabels(data_dict['train'], augment=True, rect=True) - else: - dataset = path # dataset - - # Get label wh - shapes = img_size * dataset.shapes / dataset.shapes.max(1, keepdims=True) - wh0 = np.concatenate([l[:, 3:5] * s for s, l in zip(shapes, dataset.labels)]) # wh - - # Filter - i = (wh0 < 3.0).any(1).sum() - if i: - print('WARNING: Extremely small objects found. ' - '%g of %g labels are < 3 pixels in width or height.' % (i, len(wh0))) - wh = wh0[(wh0 >= 2.0).any(1)] # filter > 2 pixels - - # Kmeans calculation - print('Running kmeans for %g anchors on %g points...' % (n, len(wh))) - s = wh.std(0) # sigmas for whitening - k, dist = kmeans(wh / s, n, iter=30) # points, mean distance - k *= s - wh = torch.tensor(wh, dtype=torch.float32) # filtered - wh0 = torch.tensor(wh0, dtype=torch.float32) # unfiltered - k = print_results(k) - - # Plot - # k, d = [None] * 20, [None] * 20 - # for i in tqdm(range(1, 21)): - # k[i-1], d[i-1] = kmeans(wh / s, i) # points, mean distance - # fig, ax = plt.subplots(1, 2, figsize=(14, 7)) - # ax = ax.ravel() - # ax[0].plot(np.arange(1, 21), np.array(d) ** 2, marker='.') - # fig, ax = plt.subplots(1, 2, figsize=(14, 7)) # plot wh - # ax[0].hist(wh[wh[:, 0]<100, 0],400) - # ax[1].hist(wh[wh[:, 1]<100, 1],400) - # fig.tight_layout() - # fig.savefig('wh.png', dpi=200) - - # Evolve - npr = np.random - f, sh, mp, s = anchor_fitness(k), k.shape, 0.9, 0.1 # fitness, generations, mutation prob, sigma - pbar = tqdm(range(gen), desc='Evolving anchors with Genetic Algorithm') # progress bar - for _ in pbar: - v = np.ones(sh) - while (v == 1).all(): # mutate until a change occurs (prevent duplicates) - v = ((npr.random(sh) < mp) * npr.random() * npr.randn(*sh) * s + 1).clip(0.3, 3.0) - kg = (k.copy() * v).clip(min=2.0) - fg = anchor_fitness(kg) - if fg > f: - f, k = fg, kg.copy() - pbar.desc = 'Evolving anchors with Genetic Algorithm: fitness = %.4f' % f - if verbose: - print_results(k) - - return print_results(k) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +# Auto-anchor utils + +import numpy as np +import torch +import yaml +from scipy.cluster.vq import kmeans +from tqdm import tqdm + + +def check_anchor_order(m): + # Check anchor order against stride order for YOLOv5 Detect() module m, and correct if necessary + a = m.anchor_grid.prod(-1).view(-1) # anchor area + da = a[-1] - a[0] # delta a + ds = m.stride[-1] - m.stride[0] # delta s + if da.sign() != ds.sign(): # same order + print('Reversing anchor order') + m.anchors[:] = m.anchors.flip(0) + m.anchor_grid[:] = m.anchor_grid.flip(0) + + +def check_anchors(dataset, model, thr=4.0, imgsz=640): + # Check anchor fit to data, recompute if necessary + print('\nAnalyzing anchors... ', end='') + m = model.module.model[-1] if hasattr(model, 'module') else model.model[-1] # Detect() + shapes = imgsz * dataset.shapes / dataset.shapes.max(1, keepdims=True) + scale = np.random.uniform(0.9, 1.1, size=(shapes.shape[0], 1)) # augment scale + wh = torch.tensor(np.concatenate([l[:, 3:5] * s for s, l in zip(shapes * scale, dataset.labels)])).float() # wh + + def metric(k): # compute metric + r = wh[:, None] / k[None] + x = torch.min(r, 1. / r).min(2)[0] # ratio metric + best = x.max(1)[0] # best_x + aat = (x > 1. / thr).float().sum(1).mean() # anchors above threshold + bpr = (best > 1. / thr).float().mean() # best possible recall + return bpr, aat + + bpr, aat = metric(m.anchor_grid.clone().cpu().view(-1, 2)) + print('anchors/target = %.2f, Best Possible Recall (BPR) = %.4f' % (aat, bpr), end='') + if bpr < 0.98: # threshold to recompute + print('. Attempting to improve anchors, please wait...') + na = m.anchor_grid.numel() // 2 # number of anchors + new_anchors = kmean_anchors(dataset, n=na, img_size=imgsz, thr=thr, gen=1000, verbose=False) + new_bpr = metric(new_anchors.reshape(-1, 2))[0] + if new_bpr > bpr: # replace anchors + new_anchors = torch.tensor(new_anchors, device=m.anchors.device).type_as(m.anchors) + m.anchor_grid[:] = new_anchors.clone().view_as(m.anchor_grid) # for inference + m.anchors[:] = new_anchors.clone().view_as(m.anchors) / m.stride.to(m.anchors.device).view(-1, 1, 1) # loss + check_anchor_order(m) + print('New anchors saved to model. Update model *.yaml to use these anchors in the future.') + else: + print('Original anchors better than new anchors. Proceeding with original anchors.') + print('') # newline + + +def kmean_anchors(path='./data/coco128.yaml', n=9, img_size=640, thr=4.0, gen=1000, verbose=True): + """ Creates kmeans-evolved anchors from training dataset + + Arguments: + path: path to dataset *.yaml, or a loaded dataset + n: number of anchors + img_size: image size used for training + thr: anchor-label wh ratio threshold hyperparameter hyp['anchor_t'] used for training, default=4.0 + gen: generations to evolve anchors using genetic algorithm + verbose: print all results + + Return: + k: kmeans evolved anchors + + Usage: + from utils.general import *; _ = kmean_anchors() + """ + thr = 1. / thr + + def metric(k, wh): # compute metrics + r = wh[:, None] / k[None] + x = torch.min(r, 1. / r).min(2)[0] # ratio metric + # x = wh_iou(wh, torch.tensor(k)) # iou metric + return x, x.max(1)[0] # x, best_x + + def anchor_fitness(k): # mutation fitness + _, best = metric(torch.tensor(k, dtype=torch.float32), wh) + return (best * (best > thr).float()).mean() # fitness + + def print_results(k): + k = k[np.argsort(k.prod(1))] # sort small to large + x, best = metric(k, wh0) + bpr, aat = (best > thr).float().mean(), (x > thr).float().mean() * n # best possible recall, anch > thr + print('thr=%.2f: %.4f best possible recall, %.2f anchors past thr' % (thr, bpr, aat)) + print('n=%g, img_size=%s, metric_all=%.3f/%.3f-mean/best, past_thr=%.3f-mean: ' % + (n, img_size, x.mean(), best.mean(), x[x > thr].mean()), end='') + for i, x in enumerate(k): + print('%i,%i' % (round(x[0]), round(x[1])), end=', ' if i < len(k) - 1 else '\n') # use in *.cfg + return k + + if isinstance(path, str): # *.yaml file + with open(path) as f: + data_dict = yaml.load(f, Loader=yaml.FullLoader) # model dict + from utils.datasets import LoadImagesAndLabels + dataset = LoadImagesAndLabels(data_dict['train'], augment=True, rect=True) + else: + dataset = path # dataset + + # Get label wh + shapes = img_size * dataset.shapes / dataset.shapes.max(1, keepdims=True) + wh0 = np.concatenate([l[:, 3:5] * s for s, l in zip(shapes, dataset.labels)]) # wh + + # Filter + i = (wh0 < 3.0).any(1).sum() + if i: + print('WARNING: Extremely small objects found. ' + '%g of %g labels are < 3 pixels in width or height.' % (i, len(wh0))) + wh = wh0[(wh0 >= 2.0).any(1)] # filter > 2 pixels + + # Kmeans calculation + print('Running kmeans for %g anchors on %g points...' % (n, len(wh))) + s = wh.std(0) # sigmas for whitening + k, dist = kmeans(wh / s, n, iter=30) # points, mean distance + k *= s + wh = torch.tensor(wh, dtype=torch.float32) # filtered + wh0 = torch.tensor(wh0, dtype=torch.float32) # unfiltered + k = print_results(k) + + # Plot + # k, d = [None] * 20, [None] * 20 + # for i in tqdm(range(1, 21)): + # k[i-1], d[i-1] = kmeans(wh / s, i) # points, mean distance + # fig, ax = plt.subplots(1, 2, figsize=(14, 7)) + # ax = ax.ravel() + # ax[0].plot(np.arange(1, 21), np.array(d) ** 2, marker='.') + # fig, ax = plt.subplots(1, 2, figsize=(14, 7)) # plot wh + # ax[0].hist(wh[wh[:, 0]<100, 0],400) + # ax[1].hist(wh[wh[:, 1]<100, 1],400) + # fig.tight_layout() + # fig.savefig('wh.png', dpi=200) + + # Evolve + npr = np.random + f, sh, mp, s = anchor_fitness(k), k.shape, 0.9, 0.1 # fitness, generations, mutation prob, sigma + pbar = tqdm(range(gen), desc='Evolving anchors with Genetic Algorithm') # progress bar + for _ in pbar: + v = np.ones(sh) + while (v == 1).all(): # mutate until a change occurs (prevent duplicates) + v = ((npr.random(sh) < mp) * npr.random() * npr.randn(*sh) * s + 1).clip(0.3, 3.0) + kg = (k.copy() * v).clip(min=2.0) + fg = anchor_fitness(kg) + if fg > f: + f, k = fg, kg.copy() + pbar.desc = 'Evolving anchors with Genetic Algorithm: fitness = %.4f' % f + if verbose: + print_results(k) + + return print_results(k) diff --git a/PyTorch/contrib/cv/detection/YOLOR/utils/datasets.py b/PyTorch/contrib/cv/detection/YOLOR/utils/datasets.py index 8b9be1318b..35b509d37e 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/utils/datasets.py +++ b/PyTorch/contrib/cv/detection/YOLOR/utils/datasets.py @@ -1,1311 +1,1311 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -# Dataset utils and dataloaders - -import glob -import math -import os -import random -import shutil -import time -from itertools import repeat -from multiprocessing.pool import ThreadPool -from pathlib import Path -from threading import Thread - -import cv2 -import numpy as np -import torch -from PIL import Image, ExifTags -from torch.utils.data import Dataset -from tqdm import tqdm - -import pickle -from copy import deepcopy -from pycocotools import mask as maskUtils -from torchvision.utils import save_image - -from utils.general import xyxy2xywh, xywh2xyxy -from utils.torch_utils import torch_distributed_zero_first - -# Parameters -help_url = 'https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data' -img_formats = ['bmp', 'jpg', 'jpeg', 'png', 'tif', 'tiff', 'dng'] # acceptable image suffixes -vid_formats = ['mov', 'avi', 'mp4', 'mpg', 'mpeg', 'm4v', 'wmv', 'mkv'] # acceptable video suffixes - -# Get orientation exif tag -for orientation in ExifTags.TAGS.keys(): - if ExifTags.TAGS[orientation] == 'Orientation': - break - - -def get_hash(files): - # Returns a single hash value of a list of files - return sum(os.path.getsize(f) for f in files if os.path.isfile(f)) - - -def exif_size(img): - # Returns exif-corrected PIL size - s = img.size # (width, height) - try: - rotation = dict(img._getexif().items())[orientation] - if rotation == 6: # rotation 270 - s = (s[1], s[0]) - elif rotation == 8: # rotation 90 - s = (s[1], s[0]) - except: - pass - - return s - - -def create_dataloader(path, imgsz, batch_size, stride, opt, hyp=None, augment=False, cache=False, pad=0.0, rect=False, - rank=-1, world_size=1, workers=8): - # Make sure only the first process in DDP process the dataset first, and the following others can use the cache - with torch_distributed_zero_first(rank): - dataset = LoadImagesAndLabels(path, imgsz, batch_size, - augment=augment, # augment images - hyp=hyp, # augmentation hyperparameters - rect=rect, # rectangular training - cache_images=cache, - single_cls=opt.single_cls, - stride=int(stride), - pad=pad, - rank=rank) - - batch_size = min(batch_size, len(dataset)) - nw = min([os.cpu_count() // world_size, batch_size if batch_size > 1 else 0, workers]) # number of workers - sampler = torch.utils.data.distributed.DistributedSampler(dataset) if rank != -1 else None - dataloader = InfiniteDataLoader(dataset, - batch_size=batch_size, - num_workers=nw, - sampler=sampler, - pin_memory=True, - collate_fn=LoadImagesAndLabels.collate_fn) # torch.utils.data.DataLoader() - return dataloader, dataset - - -def create_dataloader9(path, imgsz, batch_size, stride, opt, hyp=None, augment=False, cache=False, pad=0.0, rect=False, - rank=-1, world_size=1, workers=8): - # Make sure only the first process in DDP process the dataset first, and the following others can use the cache - with torch_distributed_zero_first(rank): - dataset = LoadImagesAndLabels9(path, imgsz, batch_size, - augment=augment, # augment images - hyp=hyp, # augmentation hyperparameters - rect=rect, # rectangular training - cache_images=cache, - single_cls=opt.single_cls, - stride=int(stride), - pad=pad, - rank=rank) - - batch_size = min(batch_size, len(dataset)) - nw = min([os.cpu_count() // world_size, batch_size if batch_size > 1 else 0, workers]) # number of workers - sampler = torch.utils.data.distributed.DistributedSampler(dataset) if rank != -1 else None - dataloader = InfiniteDataLoader(dataset, - batch_size=batch_size, - num_workers=nw, - sampler=sampler, - pin_memory=True, - collate_fn=LoadImagesAndLabels9.collate_fn) # torch.utils.data.DataLoader() - return dataloader, dataset - - -class InfiniteDataLoader(torch.utils.data.dataloader.DataLoader): - """ Dataloader that reuses workers - - Uses same syntax as vanilla DataLoader - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - object.__setattr__(self, 'batch_sampler', _RepeatSampler(self.batch_sampler)) - self.iterator = super().__iter__() - - def __len__(self): - return len(self.batch_sampler.sampler) - - def __iter__(self): - for i in range(len(self)): - yield next(self.iterator) - - -class _RepeatSampler(object): - """ Sampler that repeats forever - - Args: - sampler (Sampler) - """ - - def __init__(self, sampler): - self.sampler = sampler - - def __iter__(self): - while True: - yield from iter(self.sampler) - - -class LoadImages: # for inference - def __init__(self, path, img_size=640, auto_size=32): - p = str(Path(path)) # os-agnostic - p = os.path.abspath(p) # absolute path - if '*' in p: - files = sorted(glob.glob(p, recursive=True)) # glob - elif os.path.isdir(p): - files = sorted(glob.glob(os.path.join(p, '*.*'))) # dir - elif os.path.isfile(p): - files = [p] # files - else: - raise Exception('ERROR: %s does not exist' % p) - - images = [x for x in files if x.split('.')[-1].lower() in img_formats] - videos = [x for x in files if x.split('.')[-1].lower() in vid_formats] - ni, nv = len(images), len(videos) - - self.img_size = img_size - self.auto_size = auto_size - self.files = images + videos - self.nf = ni + nv # number of files - self.video_flag = [False] * ni + [True] * nv - self.mode = 'images' - if any(videos): - self.new_video(videos[0]) # new video - else: - self.cap = None - assert self.nf > 0, 'No images or videos found in %s. Supported formats are:\nimages: %s\nvideos: %s' % \ - (p, img_formats, vid_formats) - - def __iter__(self): - self.count = 0 - return self - - def __next__(self): - if self.count == self.nf: - raise StopIteration - path = self.files[self.count] - - if self.video_flag[self.count]: - # Read video - self.mode = 'video' - ret_val, img0 = self.cap.read() - if not ret_val: - self.count += 1 - self.cap.release() - if self.count == self.nf: # last video - raise StopIteration - else: - path = self.files[self.count] - self.new_video(path) - ret_val, img0 = self.cap.read() - - self.frame += 1 - print('video %g/%g (%g/%g) %s: ' % (self.count + 1, self.nf, self.frame, self.nframes, path), end='') - - else: - # Read image - self.count += 1 - img0 = cv2.imread(path) # BGR - assert img0 is not None, 'Image Not Found ' + path - print('image %g/%g %s: ' % (self.count, self.nf, path), end='') - - # Padded resize - img = letterbox(img0, new_shape=self.img_size, auto_size=self.auto_size)[0] - - # Convert - img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 - img = np.ascontiguousarray(img) - - return path, img, img0, self.cap - - def new_video(self, path): - self.frame = 0 - self.cap = cv2.VideoCapture(path) - self.nframes = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT)) - - def __len__(self): - return self.nf # number of files - - -class LoadWebcam: # for inference - def __init__(self, pipe='0', img_size=640): - self.img_size = img_size - - if pipe.isnumeric(): - pipe = eval(pipe) # local camera - # pipe = 'rtsp://192.168.1.64/1' # IP camera - # pipe = 'rtsp://username:password@192.168.1.64/1' # IP camera with login - # pipe = 'http://wmccpinetop.axiscam.net/mjpg/video.mjpg' # IP golf camera - - self.pipe = pipe - self.cap = cv2.VideoCapture(pipe) # video capture object - self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 3) # set buffer size - - def __iter__(self): - self.count = -1 - return self - - def __next__(self): - self.count += 1 - if cv2.waitKey(1) == ord('q'): # q to quit - self.cap.release() - cv2.destroyAllWindows() - raise StopIteration - - # Read frame - if self.pipe == 0: # local camera - ret_val, img0 = self.cap.read() - img0 = cv2.flip(img0, 1) # flip left-right - else: # IP camera - n = 0 - while True: - n += 1 - self.cap.grab() - if n % 30 == 0: # skip frames - ret_val, img0 = self.cap.retrieve() - if ret_val: - break - - # Print - assert ret_val, 'Camera Error %s' % self.pipe - img_path = 'webcam.jpg' - print('webcam %g: ' % self.count, end='') - - # Padded resize - img = letterbox(img0, new_shape=self.img_size)[0] - - # Convert - img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 - img = np.ascontiguousarray(img) - - return img_path, img, img0, None - - def __len__(self): - return 0 - - -class LoadStreams: # multiple IP or RTSP cameras - def __init__(self, sources='streams.txt', img_size=640): - self.mode = 'images' - self.img_size = img_size - - if os.path.isfile(sources): - with open(sources, 'r') as f: - sources = [x.strip() for x in f.read().splitlines() if len(x.strip())] - else: - sources = [sources] - - n = len(sources) - self.imgs = [None] * n - self.sources = sources - for i, s in enumerate(sources): - # Start the thread to read frames from the video stream - print('%g/%g: %s... ' % (i + 1, n, s), end='') - cap = cv2.VideoCapture(eval(s) if s.isnumeric() else s) - assert cap.isOpened(), 'Failed to open %s' % s - w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) - h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) - fps = cap.get(cv2.CAP_PROP_FPS) % 100 - _, self.imgs[i] = cap.read() # guarantee first frame - thread = Thread(target=self.update, args=([i, cap]), daemon=True) - print(' success (%gx%g at %.2f FPS).' % (w, h, fps)) - thread.start() - print('') # newline - - # check for common shapes - s = np.stack([letterbox(x, new_shape=self.img_size)[0].shape for x in self.imgs], 0) # inference shapes - self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal - if not self.rect: - print('WARNING: Different stream shapes detected. For optimal performance supply similarly-shaped streams.') - - def update(self, index, cap): - # Read next stream frame in a daemon thread - n = 0 - while cap.isOpened(): - n += 1 - # _, self.imgs[index] = cap.read() - cap.grab() - if n == 4: # read every 4th frame - _, self.imgs[index] = cap.retrieve() - n = 0 - time.sleep(0.01) # wait time - - def __iter__(self): - self.count = -1 - return self - - def __next__(self): - self.count += 1 - img0 = self.imgs.copy() - if cv2.waitKey(1) == ord('q'): # q to quit - cv2.destroyAllWindows() - raise StopIteration - - # Letterbox - img = [letterbox(x, new_shape=self.img_size, auto=self.rect)[0] for x in img0] - - # Stack - img = np.stack(img, 0) - - # Convert - img = img[:, :, :, ::-1].transpose(0, 3, 1, 2) # BGR to RGB, to bsx3x416x416 - img = np.ascontiguousarray(img) - - return self.sources, img, img0, None - - def __len__(self): - return 0 # 1E12 frames = 32 streams at 30 FPS for 30 years - - -class LoadImagesAndLabels(Dataset): # for training/testing - def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, rect=False, image_weights=False, - cache_images=False, single_cls=False, stride=32, pad=0.0, rank=-1): - self.img_size = img_size - self.augment = augment - self.hyp = hyp - self.image_weights = image_weights - self.rect = False if image_weights else rect - self.mosaic = self.augment and not self.rect # load 4 images at a time into a mosaic (only during training) - self.mosaic_border = [-img_size // 2, -img_size // 2] - self.stride = stride - - def img2label_paths(img_paths): - # Define label paths as a function of image paths - sa, sb = os.sep + 'images' + os.sep, os.sep + 'labels' + os.sep # /images/, /labels/ substrings - return [x.replace(sa, sb, 1).replace(x.split('.')[-1], 'txt') for x in img_paths] - - try: - f = [] # image files - for p in path if isinstance(path, list) else [path]: - p = Path(p) # os-agnostic - if p.is_dir(): # dir - f += glob.glob(str(p / '**' / '*.*'), recursive=True) - elif p.is_file(): # file - with open(p, 'r') as t: - t = t.read().splitlines() - parent = str(p.parent) + os.sep - f += [x.replace('./', parent) if x.startswith('./') else x for x in t] # local to global path - else: - raise Exception('%s does not exist' % p) - self.img_files = sorted([x.replace('/', os.sep) for x in f if x.split('.')[-1].lower() in img_formats]) - assert self.img_files, 'No images found' - except Exception as e: - raise Exception('Error loading data from %s: %s\nSee %s' % (path, e, help_url)) - - # Check cache - self.label_files = img2label_paths(self.img_files) # labels - cache_path = str(Path(self.label_files[0]).parent) + '.cache3' # cached labels - if os.path.isfile(cache_path): - cache = torch.load(cache_path) # load - if cache['hash'] != get_hash(self.label_files + self.img_files): # dataset changed - cache = self.cache_labels(cache_path) # re-cache - else: - cache = self.cache_labels(cache_path) # cache - - # Read cache - cache.pop('hash') # remove hash - labels, shapes = zip(*cache.values()) - self.labels = list(labels) - self.shapes = np.array(shapes, dtype=np.float64) - self.img_files = list(cache.keys()) # update - self.label_files = img2label_paths(cache.keys()) # update - - n = len(shapes) # number of images - bi = np.floor(np.arange(n) / batch_size).astype(np.int) # batch index - nb = bi[-1] + 1 # number of batches - self.batch = bi # batch index of image - self.n = n - - # Rectangular Training - if self.rect: - # Sort by aspect ratio - s = self.shapes # wh - ar = s[:, 1] / s[:, 0] # aspect ratio - irect = ar.argsort() - self.img_files = [self.img_files[i] for i in irect] - self.label_files = [self.label_files[i] for i in irect] - self.labels = [self.labels[i] for i in irect] - self.shapes = s[irect] # wh - ar = ar[irect] - - # Set training image shapes - shapes = [[1, 1]] * nb - for i in range(nb): - ari = ar[bi == i] - mini, maxi = ari.min(), ari.max() - if maxi < 1: - shapes[i] = [maxi, 1] - elif mini > 1: - shapes[i] = [1, 1 / mini] - - self.batch_shapes = np.ceil(np.array(shapes) * img_size / stride + pad).astype(np.int) * stride - - # Check labels - create_datasubset, extract_bounding_boxes, labels_loaded = False, False, False - nm, nf, ne, ns, nd = 0, 0, 0, 0, 0 # number missing, found, empty, datasubset, duplicate - pbar = enumerate(self.label_files) - if rank in [-1, 0]: - pbar = tqdm(pbar) - for i, file in pbar: - l = self.labels[i] # label - if l is not None and l.shape[0]: - assert l.shape[1] == 5, '> 5 label columns: %s' % file - assert (l >= 0).all(), 'negative labels: %s' % file - assert (l[:, 1:] <= 1).all(), 'non-normalized or out of bounds coordinate labels: %s' % file - if np.unique(l, axis=0).shape[0] < l.shape[0]: # duplicate rows - nd += 1 # print('WARNING: duplicate rows in %s' % self.label_files[i]) # duplicate rows - if single_cls: - l[:, 0] = 0 # force dataset into single-class mode - self.labels[i] = l - nf += 1 # file found - - # Create subdataset (a smaller dataset) - if create_datasubset and ns < 1E4: - if ns == 0: - create_folder(path='./datasubset') - os.makedirs('./datasubset/images') - exclude_classes = 43 - if exclude_classes not in l[:, 0]: - ns += 1 - # shutil.copy(src=self.img_files[i], dst='./datasubset/images/') # copy image - with open('./datasubset/images.txt', 'a') as f: - f.write(self.img_files[i] + '\n') - - # Extract object detection boxes for a second stage classifier - if extract_bounding_boxes: - p = Path(self.img_files[i]) - img = cv2.imread(str(p)) - h, w = img.shape[:2] - for j, x in enumerate(l): - f = '%s%sclassifier%s%g_%g_%s' % (p.parent.parent, os.sep, os.sep, x[0], j, p.name) - if not os.path.exists(Path(f).parent): - os.makedirs(Path(f).parent) # make new output folder - - b = x[1:] * [w, h, w, h] # box - b[2:] = b[2:].max() # rectangle to square - b[2:] = b[2:] * 1.3 + 30 # pad - b = xywh2xyxy(b.reshape(-1, 4)).ravel().astype(np.int) - - b[[0, 2]] = np.clip(b[[0, 2]], 0, w) # clip boxes outside of image - b[[1, 3]] = np.clip(b[[1, 3]], 0, h) - assert cv2.imwrite(f, img[b[1]:b[3], b[0]:b[2]]), 'Failure extracting classifier boxes' - else: - ne += 1 # print('empty labels for image %s' % self.img_files[i]) # file empty - # os.system("rm '%s' '%s'" % (self.img_files[i], self.label_files[i])) # remove - - if rank in [-1, 0]: - pbar.desc = 'Scanning labels %s (%g found, %g missing, %g empty, %g duplicate, for %g images)' % ( - cache_path, nf, nm, ne, nd, n) - if nf == 0: - s = 'WARNING: No labels found in %s. See %s' % (os.path.dirname(file) + os.sep, help_url) - print(s) - assert not augment, '%s. Can not train without labels.' % s - - # Cache images into memory for faster training (WARNING: large datasets may exceed system RAM) - self.imgs = [None] * n - if cache_images: - gb = 0 # Gigabytes of cached images - self.img_hw0, self.img_hw = [None] * n, [None] * n - results = ThreadPool(8).imap(lambda x: load_image(*x), zip(repeat(self), range(n))) # 8 threads - pbar = tqdm(enumerate(results), total=n) - for i, x in pbar: - self.imgs[i], self.img_hw0[i], self.img_hw[i] = x # img, hw_original, hw_resized = load_image(self, i) - gb += self.imgs[i].nbytes - pbar.desc = 'Caching images (%.1fGB)' % (gb / 1E9) - - def cache_labels(self, path='labels.cache3'): - # Cache dataset labels, check images and read shapes - x = {} # dict - pbar = tqdm(zip(self.img_files, self.label_files), desc='Scanning images', total=len(self.img_files)) - for (img, label) in pbar: - try: - l = [] - im = Image.open(img) - im.verify() # PIL verify - shape = exif_size(im) # image size - assert (shape[0] > 9) & (shape[1] > 9), 'image size <10 pixels' - if os.path.isfile(label): - with open(label, 'r') as f: - l = np.array([x.split() for x in f.read().splitlines()], dtype=np.float32) # labels - if len(l) == 0: - l = np.zeros((0, 5), dtype=np.float32) - x[img] = [l, shape] - except Exception as e: - print('WARNING: Ignoring corrupted image and/or label %s: %s' % (img, e)) - - x['hash'] = get_hash(self.label_files + self.img_files) - torch.save(x, path) # save for next time - return x - - def __len__(self): - return len(self.img_files) - - # def __iter__(self): - # self.count = -1 - # print('ran dataset iter') - # #self.shuffled_vector = np.random.permutation(self.nF) if self.augment else np.arange(self.nF) - # return self - - def __getitem__(self, index): - if self.image_weights: - index = self.indices[index] - - hyp = self.hyp - mosaic = self.mosaic and random.random() < hyp['mosaic'] - if mosaic: - # Load mosaic - img, labels = load_mosaic(self, index) - #img, labels = load_mosaic9(self, index) - shapes = None - - # MixUp https://arxiv.org/pdf/1710.09412.pdf - if random.random() < hyp['mixup']: - img2, labels2 = load_mosaic(self, random.randint(0, len(self.labels) - 1)) - #img2, labels2 = load_mosaic9(self, random.randint(0, len(self.labels) - 1)) - r = np.random.beta(8.0, 8.0) # mixup ratio, alpha=beta=8.0 - img = (img * r + img2 * (1 - r)).astype(np.uint8) - labels = np.concatenate((labels, labels2), 0) - - else: - # Load image - img, (h0, w0), (h, w) = load_image(self, index) - - # Letterbox - shape = self.batch_shapes[self.batch[index]] if self.rect else self.img_size # final letterboxed shape - img, ratio, pad = letterbox(img, shape, auto=False, scaleup=self.augment) - shapes = (h0, w0), ((h / h0, w / w0), pad) # for COCO mAP rescaling - - # Load labels - labels = [] - x = self.labels[index] - if x.size > 0: - # Normalized xywh to pixel xyxy format - labels = x.copy() - labels[:, 1] = ratio[0] * w * (x[:, 1] - x[:, 3] / 2) + pad[0] # pad width - labels[:, 2] = ratio[1] * h * (x[:, 2] - x[:, 4] / 2) + pad[1] # pad height - labels[:, 3] = ratio[0] * w * (x[:, 1] + x[:, 3] / 2) + pad[0] - labels[:, 4] = ratio[1] * h * (x[:, 2] + x[:, 4] / 2) + pad[1] - - if self.augment: - # Augment imagespace - if not mosaic: - img, labels = random_perspective(img, labels, - degrees=hyp['degrees'], - translate=hyp['translate'], - scale=hyp['scale'], - shear=hyp['shear'], - perspective=hyp['perspective']) - - # Augment colorspace - augment_hsv(img, hgain=hyp['hsv_h'], sgain=hyp['hsv_s'], vgain=hyp['hsv_v']) - - # Apply cutouts - # if random.random() < 0.9: - # labels = cutout(img, labels) - - nL = len(labels) # number of labels - if nL: - labels[:, 1:5] = xyxy2xywh(labels[:, 1:5]) # convert xyxy to xywh - labels[:, [2, 4]] /= img.shape[0] # normalized height 0-1 - labels[:, [1, 3]] /= img.shape[1] # normalized width 0-1 - - if self.augment: - # flip up-down - if random.random() < hyp['flipud']: - img = np.flipud(img) - if nL: - labels[:, 2] = 1 - labels[:, 2] - - # flip left-right - if random.random() < hyp['fliplr']: - img = np.fliplr(img) - if nL: - labels[:, 1] = 1 - labels[:, 1] - - labels_out = torch.zeros((nL, 6)) - if nL: - labels_out[:, 1:] = torch.from_numpy(labels) - - # Convert - img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 - img = np.ascontiguousarray(img) - - return torch.from_numpy(img), labels_out, self.img_files[index], shapes - - @staticmethod - def collate_fn(batch): - img, label, path, shapes = zip(*batch) # transposed - for i, l in enumerate(label): - l[:, 0] = i # add target image index for build_targets() - return torch.stack(img, 0), torch.cat(label, 0), path, shapes - - -class LoadImagesAndLabels9(Dataset): # for training/testing - def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, rect=False, image_weights=False, - cache_images=False, single_cls=False, stride=32, pad=0.0, rank=-1): - self.img_size = img_size - self.augment = augment - self.hyp = hyp - self.image_weights = image_weights - self.rect = False if image_weights else rect - self.mosaic = self.augment and not self.rect # load 4 images at a time into a mosaic (only during training) - self.mosaic_border = [-img_size // 2, -img_size // 2] - self.stride = stride - - def img2label_paths(img_paths): - # Define label paths as a function of image paths - sa, sb = os.sep + 'images' + os.sep, os.sep + 'labels' + os.sep # /images/, /labels/ substrings - return [x.replace(sa, sb, 1).replace(x.split('.')[-1], 'txt') for x in img_paths] - - try: - f = [] # image files - for p in path if isinstance(path, list) else [path]: - p = Path(p) # os-agnostic - if p.is_dir(): # dir - f += glob.glob(str(p / '**' / '*.*'), recursive=True) - elif p.is_file(): # file - with open(p, 'r') as t: - t = t.read().splitlines() - parent = str(p.parent) + os.sep - f += [x.replace('./', parent) if x.startswith('./') else x for x in t] # local to global path - else: - raise Exception('%s does not exist' % p) - self.img_files = sorted([x.replace('/', os.sep) for x in f if x.split('.')[-1].lower() in img_formats]) - assert self.img_files, 'No images found' - except Exception as e: - raise Exception('Error loading data from %s: %s\nSee %s' % (path, e, help_url)) - - # Check cache - self.label_files = img2label_paths(self.img_files) # labels - cache_path = str(Path(self.label_files[0]).parent) + '.cache3' # cached labels - if os.path.isfile(cache_path): - cache = torch.load(cache_path) # load - if cache['hash'] != get_hash(self.label_files + self.img_files): # dataset changed - cache = self.cache_labels(cache_path) # re-cache - else: - cache = self.cache_labels(cache_path) # cache - - # Read cache - cache.pop('hash') # remove hash - labels, shapes = zip(*cache.values()) - self.labels = list(labels) - self.shapes = np.array(shapes, dtype=np.float64) - self.img_files = list(cache.keys()) # update - self.label_files = img2label_paths(cache.keys()) # update - - n = len(shapes) # number of images - bi = np.floor(np.arange(n) / batch_size).astype(np.int) # batch index - nb = bi[-1] + 1 # number of batches - self.batch = bi # batch index of image - self.n = n - - # Rectangular Training - if self.rect: - # Sort by aspect ratio - s = self.shapes # wh - ar = s[:, 1] / s[:, 0] # aspect ratio - irect = ar.argsort() - self.img_files = [self.img_files[i] for i in irect] - self.label_files = [self.label_files[i] for i in irect] - self.labels = [self.labels[i] for i in irect] - self.shapes = s[irect] # wh - ar = ar[irect] - - # Set training image shapes - shapes = [[1, 1]] * nb - for i in range(nb): - ari = ar[bi == i] - mini, maxi = ari.min(), ari.max() - if maxi < 1: - shapes[i] = [maxi, 1] - elif mini > 1: - shapes[i] = [1, 1 / mini] - - self.batch_shapes = np.ceil(np.array(shapes) * img_size / stride + pad).astype(np.int) * stride - - # Check labels - create_datasubset, extract_bounding_boxes, labels_loaded = False, False, False - nm, nf, ne, ns, nd = 0, 0, 0, 0, 0 # number missing, found, empty, datasubset, duplicate - pbar = enumerate(self.label_files) - if rank in [-1, 0]: - pbar = tqdm(pbar) - for i, file in pbar: - l = self.labels[i] # label - if l is not None and l.shape[0]: - assert l.shape[1] == 5, '> 5 label columns: %s' % file - assert (l >= 0).all(), 'negative labels: %s' % file - assert (l[:, 1:] <= 1).all(), 'non-normalized or out of bounds coordinate labels: %s' % file - if np.unique(l, axis=0).shape[0] < l.shape[0]: # duplicate rows - nd += 1 # print('WARNING: duplicate rows in %s' % self.label_files[i]) # duplicate rows - if single_cls: - l[:, 0] = 0 # force dataset into single-class mode - self.labels[i] = l - nf += 1 # file found - - # Create subdataset (a smaller dataset) - if create_datasubset and ns < 1E4: - if ns == 0: - create_folder(path='./datasubset') - os.makedirs('./datasubset/images') - exclude_classes = 43 - if exclude_classes not in l[:, 0]: - ns += 1 - # shutil.copy(src=self.img_files[i], dst='./datasubset/images/') # copy image - with open('./datasubset/images.txt', 'a') as f: - f.write(self.img_files[i] + '\n') - - # Extract object detection boxes for a second stage classifier - if extract_bounding_boxes: - p = Path(self.img_files[i]) - img = cv2.imread(str(p)) - h, w = img.shape[:2] - for j, x in enumerate(l): - f = '%s%sclassifier%s%g_%g_%s' % (p.parent.parent, os.sep, os.sep, x[0], j, p.name) - if not os.path.exists(Path(f).parent): - os.makedirs(Path(f).parent) # make new output folder - - b = x[1:] * [w, h, w, h] # box - b[2:] = b[2:].max() # rectangle to square - b[2:] = b[2:] * 1.3 + 30 # pad - b = xywh2xyxy(b.reshape(-1, 4)).ravel().astype(np.int) - - b[[0, 2]] = np.clip(b[[0, 2]], 0, w) # clip boxes outside of image - b[[1, 3]] = np.clip(b[[1, 3]], 0, h) - assert cv2.imwrite(f, img[b[1]:b[3], b[0]:b[2]]), 'Failure extracting classifier boxes' - else: - ne += 1 # print('empty labels for image %s' % self.img_files[i]) # file empty - # os.system("rm '%s' '%s'" % (self.img_files[i], self.label_files[i])) # remove - - if rank in [-1, 0]: - pbar.desc = 'Scanning labels %s (%g found, %g missing, %g empty, %g duplicate, for %g images)' % ( - cache_path, nf, nm, ne, nd, n) - if nf == 0: - s = 'WARNING: No labels found in %s. See %s' % (os.path.dirname(file) + os.sep, help_url) - print(s) - assert not augment, '%s. Can not train without labels.' % s - - # Cache images into memory for faster training (WARNING: large datasets may exceed system RAM) - self.imgs = [None] * n - if cache_images: - gb = 0 # Gigabytes of cached images - self.img_hw0, self.img_hw = [None] * n, [None] * n - results = ThreadPool(8).imap(lambda x: load_image(*x), zip(repeat(self), range(n))) # 8 threads - pbar = tqdm(enumerate(results), total=n) - for i, x in pbar: - self.imgs[i], self.img_hw0[i], self.img_hw[i] = x # img, hw_original, hw_resized = load_image(self, i) - gb += self.imgs[i].nbytes - pbar.desc = 'Caching images (%.1fGB)' % (gb / 1E9) - - def cache_labels(self, path='labels.cache3'): - # Cache dataset labels, check images and read shapes - x = {} # dict - pbar = tqdm(zip(self.img_files, self.label_files), desc='Scanning images', total=len(self.img_files)) - for (img, label) in pbar: - try: - l = [] - im = Image.open(img) - im.verify() # PIL verify - shape = exif_size(im) # image size - assert (shape[0] > 9) & (shape[1] > 9), 'image size <10 pixels' - if os.path.isfile(label): - with open(label, 'r') as f: - l = np.array([x.split() for x in f.read().splitlines()], dtype=np.float32) # labels - if len(l) == 0: - l = np.zeros((0, 5), dtype=np.float32) - x[img] = [l, shape] - except Exception as e: - print('WARNING: Ignoring corrupted image and/or label %s: %s' % (img, e)) - - x['hash'] = get_hash(self.label_files + self.img_files) - torch.save(x, path) # save for next time - return x - - def __len__(self): - return len(self.img_files) - - # def __iter__(self): - # self.count = -1 - # print('ran dataset iter') - # #self.shuffled_vector = np.random.permutation(self.nF) if self.augment else np.arange(self.nF) - # return self - - def __getitem__(self, index): - if self.image_weights: - index = self.indices[index] - - hyp = self.hyp - mosaic = self.mosaic and random.random() < hyp['mosaic'] - if mosaic: - # Load mosaic - #img, labels = load_mosaic(self, index) - img, labels = load_mosaic9(self, index) - shapes = None - - # MixUp https://arxiv.org/pdf/1710.09412.pdf - if random.random() < hyp['mixup']: - #img2, labels2 = load_mosaic(self, random.randint(0, len(self.labels) - 1)) - img2, labels2 = load_mosaic9(self, random.randint(0, len(self.labels) - 1)) - r = np.random.beta(8.0, 8.0) # mixup ratio, alpha=beta=8.0 - img = (img * r + img2 * (1 - r)).astype(np.uint8) - labels = np.concatenate((labels, labels2), 0) - - else: - # Load image - img, (h0, w0), (h, w) = load_image(self, index) - - # Letterbox - shape = self.batch_shapes[self.batch[index]] if self.rect else self.img_size # final letterboxed shape - img, ratio, pad = letterbox(img, shape, auto=False, scaleup=self.augment) - shapes = (h0, w0), ((h / h0, w / w0), pad) # for COCO mAP rescaling - - # Load labels - labels = [] - x = self.labels[index] - if x.size > 0: - # Normalized xywh to pixel xyxy format - labels = x.copy() - labels[:, 1] = ratio[0] * w * (x[:, 1] - x[:, 3] / 2) + pad[0] # pad width - labels[:, 2] = ratio[1] * h * (x[:, 2] - x[:, 4] / 2) + pad[1] # pad height - labels[:, 3] = ratio[0] * w * (x[:, 1] + x[:, 3] / 2) + pad[0] - labels[:, 4] = ratio[1] * h * (x[:, 2] + x[:, 4] / 2) + pad[1] - - if self.augment: - # Augment imagespace - if not mosaic: - img, labels = random_perspective(img, labels, - degrees=hyp['degrees'], - translate=hyp['translate'], - scale=hyp['scale'], - shear=hyp['shear'], - perspective=hyp['perspective']) - - # Augment colorspace - augment_hsv(img, hgain=hyp['hsv_h'], sgain=hyp['hsv_s'], vgain=hyp['hsv_v']) - - # Apply cutouts - # if random.random() < 0.9: - # labels = cutout(img, labels) - - nL = len(labels) # number of labels - if nL: - labels[:, 1:5] = xyxy2xywh(labels[:, 1:5]) # convert xyxy to xywh - labels[:, [2, 4]] /= img.shape[0] # normalized height 0-1 - labels[:, [1, 3]] /= img.shape[1] # normalized width 0-1 - - if self.augment: - # flip up-down - if random.random() < hyp['flipud']: - img = np.flipud(img) - if nL: - labels[:, 2] = 1 - labels[:, 2] - - # flip left-right - if random.random() < hyp['fliplr']: - img = np.fliplr(img) - if nL: - labels[:, 1] = 1 - labels[:, 1] - - labels_out = torch.zeros((nL, 6)) - if nL: - labels_out[:, 1:] = torch.from_numpy(labels) - - # Convert - img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 - img = np.ascontiguousarray(img) - - return torch.from_numpy(img), labels_out, self.img_files[index], shapes - - @staticmethod - def collate_fn(batch): - img, label, path, shapes = zip(*batch) # transposed - for i, l in enumerate(label): - l[:, 0] = i # add target image index for build_targets() - return torch.stack(img, 0), torch.cat(label, 0), path, shapes - - -# Ancillary functions -------------------------------------------------------------------------------------------------- -def load_image(self, index): - # loads 1 image from dataset, returns img, original hw, resized hw - img = self.imgs[index] - if img is None: # not cached - path = self.img_files[index] - img = cv2.imread(path) # BGR - assert img is not None, 'Image Not Found ' + path - h0, w0 = img.shape[:2] # orig hw - r = self.img_size / max(h0, w0) # resize image to img_size - if r != 1: # always resize down, only resize up if training with augmentation - interp = cv2.INTER_AREA if r < 1 and not self.augment else cv2.INTER_LINEAR - img = cv2.resize(img, (int(w0 * r), int(h0 * r)), interpolation=interp) - return img, (h0, w0), img.shape[:2] # img, hw_original, hw_resized - else: - return self.imgs[index], self.img_hw0[index], self.img_hw[index] # img, hw_original, hw_resized - - -def augment_hsv(img, hgain=0.5, sgain=0.5, vgain=0.5): - r = np.random.uniform(-1, 1, 3) * [hgain, sgain, vgain] + 1 # random gains - hue, sat, val = cv2.split(cv2.cvtColor(img, cv2.COLOR_BGR2HSV)) - dtype = img.dtype # uint8 - - x = np.arange(0, 256, dtype=np.int16) - lut_hue = ((x * r[0]) % 180).astype(dtype) - lut_sat = np.clip(x * r[1], 0, 255).astype(dtype) - lut_val = np.clip(x * r[2], 0, 255).astype(dtype) - - img_hsv = cv2.merge((cv2.LUT(hue, lut_hue), cv2.LUT(sat, lut_sat), cv2.LUT(val, lut_val))).astype(dtype) - cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR, dst=img) # no return needed - - # Histogram equalization - # if random.random() < 0.2: - # for i in range(3): - # img[:, :, i] = cv2.equalizeHist(img[:, :, i]) - - -def load_mosaic(self, index): - # loads images in a mosaic - - labels4 = [] - s = self.img_size - yc, xc = [int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border] # mosaic center x, y - indices = [index] + [random.randint(0, len(self.labels) - 1) for _ in range(3)] # 3 additional image indices - for i, index in enumerate(indices): - # Load image - img, _, (h, w) = load_image(self, index) - - # place img in img4 - if i == 0: # top left - img4 = np.full((s * 2, s * 2, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles - x1a, y1a, x2a, y2a = max(xc - w, 0), max(yc - h, 0), xc, yc # xmin, ymin, xmax, ymax (large image) - x1b, y1b, x2b, y2b = w - (x2a - x1a), h - (y2a - y1a), w, h # xmin, ymin, xmax, ymax (small image) - elif i == 1: # top right - x1a, y1a, x2a, y2a = xc, max(yc - h, 0), min(xc + w, s * 2), yc - x1b, y1b, x2b, y2b = 0, h - (y2a - y1a), min(w, x2a - x1a), h - elif i == 2: # bottom left - x1a, y1a, x2a, y2a = max(xc - w, 0), yc, xc, min(s * 2, yc + h) - x1b, y1b, x2b, y2b = w - (x2a - x1a), 0, w, min(y2a - y1a, h) - elif i == 3: # bottom right - x1a, y1a, x2a, y2a = xc, yc, min(xc + w, s * 2), min(s * 2, yc + h) - x1b, y1b, x2b, y2b = 0, 0, min(w, x2a - x1a), min(y2a - y1a, h) - - img4[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b] # img4[ymin:ymax, xmin:xmax] - padw = x1a - x1b - padh = y1a - y1b - - # Labels - x = self.labels[index] - labels = x.copy() - if x.size > 0: # Normalized xywh to pixel xyxy format - labels[:, 1] = w * (x[:, 1] - x[:, 3] / 2) + padw - labels[:, 2] = h * (x[:, 2] - x[:, 4] / 2) + padh - labels[:, 3] = w * (x[:, 1] + x[:, 3] / 2) + padw - labels[:, 4] = h * (x[:, 2] + x[:, 4] / 2) + padh - labels4.append(labels) - - # Concat/clip labels - if len(labels4): - labels4 = np.concatenate(labels4, 0) - np.clip(labels4[:, 1:], 0, 2 * s, out=labels4[:, 1:]) # use with random_perspective - # img4, labels4 = replicate(img4, labels4) # replicate - - # Augment - img4, labels4 = random_perspective(img4, labels4, - degrees=self.hyp['degrees'], - translate=self.hyp['translate'], - scale=self.hyp['scale'], - shear=self.hyp['shear'], - perspective=self.hyp['perspective'], - border=self.mosaic_border) # border to remove - - return img4, labels4 - - -def load_mosaic9(self, index): - # loads images in a 9-mosaic - - labels9 = [] - s = self.img_size - indices = [index] + [random.randint(0, len(self.labels) - 1) for _ in range(8)] # 8 additional image indices - for i, index in enumerate(indices): - # Load image - img, _, (h, w) = load_image(self, index) - - # place img in img9 - if i == 0: # center - img9 = np.full((s * 3, s * 3, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles - h0, w0 = h, w - c = s, s, s + w, s + h # xmin, ymin, xmax, ymax (base) coordinates - elif i == 1: # top - c = s, s - h, s + w, s - elif i == 2: # top right - c = s + wp, s - h, s + wp + w, s - elif i == 3: # right - c = s + w0, s, s + w0 + w, s + h - elif i == 4: # bottom right - c = s + w0, s + hp, s + w0 + w, s + hp + h - elif i == 5: # bottom - c = s + w0 - w, s + h0, s + w0, s + h0 + h - elif i == 6: # bottom left - c = s + w0 - wp - w, s + h0, s + w0 - wp, s + h0 + h - elif i == 7: # left - c = s - w, s + h0 - h, s, s + h0 - elif i == 8: # top left - c = s - w, s + h0 - hp - h, s, s + h0 - hp - - padx, pady = c[:2] - x1, y1, x2, y2 = [max(x, 0) for x in c] # allocate coords - - # Labels - x = self.labels[index] - labels = x.copy() - if x.size > 0: # Normalized xywh to pixel xyxy format - labels[:, 1] = w * (x[:, 1] - x[:, 3] / 2) + padx - labels[:, 2] = h * (x[:, 2] - x[:, 4] / 2) + pady - labels[:, 3] = w * (x[:, 1] + x[:, 3] / 2) + padx - labels[:, 4] = h * (x[:, 2] + x[:, 4] / 2) + pady - labels9.append(labels) - - # Image - img9[y1:y2, x1:x2] = img[y1 - pady:, x1 - padx:] # img9[ymin:ymax, xmin:xmax] - hp, wp = h, w # height, width previous - - # Offset - yc, xc = [int(random.uniform(0, s)) for x in self.mosaic_border] # mosaic center x, y - img9 = img9[yc:yc + 2 * s, xc:xc + 2 * s] - - # Concat/clip labels - if len(labels9): - labels9 = np.concatenate(labels9, 0) - labels9[:, [1, 3]] -= xc - labels9[:, [2, 4]] -= yc - - np.clip(labels9[:, 1:], 0, 2 * s, out=labels9[:, 1:]) # use with random_perspective - # img9, labels9 = replicate(img9, labels9) # replicate - - # Augment - img9, labels9 = random_perspective(img9, labels9, - degrees=self.hyp['degrees'], - translate=self.hyp['translate'], - scale=self.hyp['scale'], - shear=self.hyp['shear'], - perspective=self.hyp['perspective'], - border=self.mosaic_border) # border to remove - - return img9, labels9 - - -def replicate(img, labels): - # Replicate labels - h, w = img.shape[:2] - boxes = labels[:, 1:].astype(int) - x1, y1, x2, y2 = boxes.T - s = ((x2 - x1) + (y2 - y1)) / 2 # side length (pixels) - for i in s.argsort()[:round(s.size * 0.5)]: # smallest indices - x1b, y1b, x2b, y2b = boxes[i] - bh, bw = y2b - y1b, x2b - x1b - yc, xc = int(random.uniform(0, h - bh)), int(random.uniform(0, w - bw)) # offset x, y - x1a, y1a, x2a, y2a = [xc, yc, xc + bw, yc + bh] - img[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b] # img4[ymin:ymax, xmin:xmax] - labels = np.append(labels, [[labels[i, 0], x1a, y1a, x2a, y2a]], axis=0) - - return img, labels - - -def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, auto_size=32): - # Resize image to a 32-pixel-multiple rectangle https://github.com/ultralytics/yolov3/issues/232 - shape = img.shape[:2] # current shape [height, width] - if isinstance(new_shape, int): - new_shape = (new_shape, new_shape) - - # Scale ratio (new / old) - r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) - if not scaleup: # only scale down, do not scale up (for better test mAP) - r = min(r, 1.0) - - # Compute padding - ratio = r, r # width, height ratios - new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) - dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding - if auto: # minimum rectangle - dw, dh = np.mod(dw, auto_size), np.mod(dh, auto_size) # wh padding - elif scaleFill: # stretch - dw, dh = 0.0, 0.0 - new_unpad = (new_shape[1], new_shape[0]) - ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] # width, height ratios - - dw /= 2 # divide padding into 2 sides - dh /= 2 - - if shape[::-1] != new_unpad: # resize - img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR) - top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) - left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) - img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # add border - return img, ratio, (dw, dh) - - -def random_perspective(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10, perspective=0.0, border=(0, 0)): - # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(.1, .1), scale=(.9, 1.1), shear=(-10, 10)) - # targets = [cls, xyxy] - - height = img.shape[0] + border[0] * 2 # shape(h,w,c) - width = img.shape[1] + border[1] * 2 - - # Center - C = np.eye(3) - C[0, 2] = -img.shape[1] / 2 # x translation (pixels) - C[1, 2] = -img.shape[0] / 2 # y translation (pixels) - - # Perspective - P = np.eye(3) - P[2, 0] = random.uniform(-perspective, perspective) # x perspective (about y) - P[2, 1] = random.uniform(-perspective, perspective) # y perspective (about x) - - # Rotation and Scale - R = np.eye(3) - a = random.uniform(-degrees, degrees) - # a += random.choice([-180, -90, 0, 90]) # add 90deg rotations to small rotations - s = random.uniform(1 - scale, 1 + scale) - # s = 2 ** random.uniform(-scale, scale) - R[:2] = cv2.getRotationMatrix2D(angle=a, center=(0, 0), scale=s) - - # Shear - S = np.eye(3) - S[0, 1] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # x shear (deg) - S[1, 0] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # y shear (deg) - - # Translation - T = np.eye(3) - T[0, 2] = random.uniform(0.5 - translate, 0.5 + translate) * width # x translation (pixels) - T[1, 2] = random.uniform(0.5 - translate, 0.5 + translate) * height # y translation (pixels) - - # Combined rotation matrix - M = T @ S @ R @ P @ C # order of operations (right to left) is IMPORTANT - if (border[0] != 0) or (border[1] != 0) or (M != np.eye(3)).any(): # image changed - if perspective: - img = cv2.warpPerspective(img, M, dsize=(width, height), borderValue=(114, 114, 114)) - else: # affine - img = cv2.warpAffine(img, M[:2], dsize=(width, height), borderValue=(114, 114, 114)) - - # Visualize - # import matplotlib.pyplot as plt - # ax = plt.subplots(1, 2, figsize=(12, 6))[1].ravel() - # ax[0].imshow(img[:, :, ::-1]) # base - # ax[1].imshow(img2[:, :, ::-1]) # warped - - # Transform label coordinates - n = len(targets) - if n: - # warp points - xy = np.ones((n * 4, 3)) - xy[:, :2] = targets[:, [1, 2, 3, 4, 1, 4, 3, 2]].reshape(n * 4, 2) # x1y1, x2y2, x1y2, x2y1 - xy = xy @ M.T # transform - if perspective: - xy = (xy[:, :2] / xy[:, 2:3]).reshape(n, 8) # rescale - else: # affine - xy = xy[:, :2].reshape(n, 8) - - # create new boxes - x = xy[:, [0, 2, 4, 6]] - y = xy[:, [1, 3, 5, 7]] - xy = np.concatenate((x.min(1), y.min(1), x.max(1), y.max(1))).reshape(4, n).T - - # # apply angle-based reduction of bounding boxes - # radians = a * math.pi / 180 - # reduction = max(abs(math.sin(radians)), abs(math.cos(radians))) ** 0.5 - # x = (xy[:, 2] + xy[:, 0]) / 2 - # y = (xy[:, 3] + xy[:, 1]) / 2 - # w = (xy[:, 2] - xy[:, 0]) * reduction - # h = (xy[:, 3] - xy[:, 1]) * reduction - # xy = np.concatenate((x - w / 2, y - h / 2, x + w / 2, y + h / 2)).reshape(4, n).T - - # clip boxes - xy[:, [0, 2]] = xy[:, [0, 2]].clip(0, width) - xy[:, [1, 3]] = xy[:, [1, 3]].clip(0, height) - - # filter candidates - i = box_candidates(box1=targets[:, 1:5].T * s, box2=xy.T) - targets = targets[i] - targets[:, 1:5] = xy[i] - - return img, targets - - -def box_candidates(box1, box2, wh_thr=2, ar_thr=20, area_thr=0.1): # box1(4,n), box2(4,n) - # Compute candidate boxes: box1 before augment, box2 after augment, wh_thr (pixels), aspect_ratio_thr, area_ratio - w1, h1 = box1[2] - box1[0], box1[3] - box1[1] - w2, h2 = box2[2] - box2[0], box2[3] - box2[1] - ar = np.maximum(w2 / (h2 + 1e-16), h2 / (w2 + 1e-16)) # aspect ratio - return (w2 > wh_thr) & (h2 > wh_thr) & (w2 * h2 / (w1 * h1 + 1e-16) > area_thr) & (ar < ar_thr) # candidates - - -def cutout(image, labels): - # Applies image cutout augmentation https://arxiv.org/abs/1708.04552 - h, w = image.shape[:2] - - def bbox_ioa(box1, box2): - # Returns the intersection over box2 area given box1, box2. box1 is 4, box2 is nx4. boxes are x1y1x2y2 - box2 = box2.transpose() - - # Get the coordinates of bounding boxes - b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3] - b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3] - - # Intersection area - inter_area = (np.minimum(b1_x2, b2_x2) - np.maximum(b1_x1, b2_x1)).clip(0) * \ - (np.minimum(b1_y2, b2_y2) - np.maximum(b1_y1, b2_y1)).clip(0) - - # box2 area - box2_area = (b2_x2 - b2_x1) * (b2_y2 - b2_y1) + 1e-16 - - # Intersection over box2 area - return inter_area / box2_area - - # create random masks - scales = [0.5] * 1 + [0.25] * 2 + [0.125] * 4 + [0.0625] * 8 + [0.03125] * 16 # image size fraction - for s in scales: - mask_h = random.randint(1, int(h * s)) - mask_w = random.randint(1, int(w * s)) - - # box - xmin = max(0, random.randint(0, w) - mask_w // 2) - ymin = max(0, random.randint(0, h) - mask_h // 2) - xmax = min(w, xmin + mask_w) - ymax = min(h, ymin + mask_h) - - # apply random color mask - image[ymin:ymax, xmin:xmax] = [random.randint(64, 191) for _ in range(3)] - - # return unobscured labels - if len(labels) and s > 0.03: - box = np.array([xmin, ymin, xmax, ymax], dtype=np.float32) - ioa = bbox_ioa(box, labels[:, 1:5]) # intersection over area - labels = labels[ioa < 0.60] # remove >60% obscured labels - - return labels - - -def create_folder(path='./new'): - # Create folder - if os.path.exists(path): - shutil.rmtree(path) # delete output folder - os.makedirs(path) # make new output folder - - -def flatten_recursive(path='../coco128'): - # Flatten a recursive directory by bringing all files to top level - new_path = Path(path + '_flat') - create_folder(new_path) - for file in tqdm(glob.glob(str(Path(path)) + '/**/*.*', recursive=True)): - shutil.copyfile(file, new_path / Path(file).name) - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +# Dataset utils and dataloaders + +import glob +import math +import os +import random +import shutil +import time +from itertools import repeat +from multiprocessing.pool import ThreadPool +from pathlib import Path +from threading import Thread + +import cv2 +import numpy as np +import torch +from PIL import Image, ExifTags +from torch.utils.data import Dataset +from tqdm import tqdm + +import pickle +from copy import deepcopy +from pycocotools import mask as maskUtils +from torchvision.utils import save_image + +from utils.general import xyxy2xywh, xywh2xyxy +from utils.torch_utils import torch_distributed_zero_first + +# Parameters +help_url = 'https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data' +img_formats = ['bmp', 'jpg', 'jpeg', 'png', 'tif', 'tiff', 'dng'] # acceptable image suffixes +vid_formats = ['mov', 'avi', 'mp4', 'mpg', 'mpeg', 'm4v', 'wmv', 'mkv'] # acceptable video suffixes + +# Get orientation exif tag +for orientation in ExifTags.TAGS.keys(): + if ExifTags.TAGS[orientation] == 'Orientation': + break + + +def get_hash(files): + # Returns a single hash value of a list of files + return sum(os.path.getsize(f) for f in files if os.path.isfile(f)) + + +def exif_size(img): + # Returns exif-corrected PIL size + s = img.size # (width, height) + try: + rotation = dict(img._getexif().items())[orientation] + if rotation == 6: # rotation 270 + s = (s[1], s[0]) + elif rotation == 8: # rotation 90 + s = (s[1], s[0]) + except: + pass + + return s + + +def create_dataloader(path, imgsz, batch_size, stride, opt, hyp=None, augment=False, cache=False, pad=0.0, rect=False, + rank=-1, world_size=1, workers=8): + # Make sure only the first process in DDP process the dataset first, and the following others can use the cache + with torch_distributed_zero_first(rank): + dataset = LoadImagesAndLabels(path, imgsz, batch_size, + augment=augment, # augment images + hyp=hyp, # augmentation hyperparameters + rect=rect, # rectangular training + cache_images=cache, + single_cls=opt.single_cls, + stride=int(stride), + pad=pad, + rank=rank) + + batch_size = min(batch_size, len(dataset)) + nw = min([os.cpu_count() // world_size, batch_size if batch_size > 1 else 0, workers]) # number of workers + sampler = torch.utils.data.distributed.DistributedSampler(dataset) if rank != -1 else None + dataloader = InfiniteDataLoader(dataset, + batch_size=batch_size, + num_workers=nw, + sampler=sampler, + pin_memory=True, + collate_fn=LoadImagesAndLabels.collate_fn) # torch.utils.data.DataLoader() + return dataloader, dataset + + +def create_dataloader9(path, imgsz, batch_size, stride, opt, hyp=None, augment=False, cache=False, pad=0.0, rect=False, + rank=-1, world_size=1, workers=8): + # Make sure only the first process in DDP process the dataset first, and the following others can use the cache + with torch_distributed_zero_first(rank): + dataset = LoadImagesAndLabels9(path, imgsz, batch_size, + augment=augment, # augment images + hyp=hyp, # augmentation hyperparameters + rect=rect, # rectangular training + cache_images=cache, + single_cls=opt.single_cls, + stride=int(stride), + pad=pad, + rank=rank) + + batch_size = min(batch_size, len(dataset)) + nw = min([os.cpu_count() // world_size, batch_size if batch_size > 1 else 0, workers]) # number of workers + sampler = torch.utils.data.distributed.DistributedSampler(dataset) if rank != -1 else None + dataloader = InfiniteDataLoader(dataset, + batch_size=batch_size, + num_workers=nw, + sampler=sampler, + pin_memory=True, + collate_fn=LoadImagesAndLabels9.collate_fn) # torch.utils.data.DataLoader() + return dataloader, dataset + + +class InfiniteDataLoader(torch.utils.data.dataloader.DataLoader): + """ Dataloader that reuses workers + + Uses same syntax as vanilla DataLoader + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + object.__setattr__(self, 'batch_sampler', _RepeatSampler(self.batch_sampler)) + self.iterator = super().__iter__() + + def __len__(self): + return len(self.batch_sampler.sampler) + + def __iter__(self): + for i in range(len(self)): + yield next(self.iterator) + + +class _RepeatSampler(object): + """ Sampler that repeats forever + + Args: + sampler (Sampler) + """ + + def __init__(self, sampler): + self.sampler = sampler + + def __iter__(self): + while True: + yield from iter(self.sampler) + + +class LoadImages: # for inference + def __init__(self, path, img_size=640, auto_size=32): + p = str(Path(path)) # os-agnostic + p = os.path.abspath(p) # absolute path + if '*' in p: + files = sorted(glob.glob(p, recursive=True)) # glob + elif os.path.isdir(p): + files = sorted(glob.glob(os.path.join(p, '*.*'))) # dir + elif os.path.isfile(p): + files = [p] # files + else: + raise Exception('ERROR: %s does not exist' % p) + + images = [x for x in files if x.split('.')[-1].lower() in img_formats] + videos = [x for x in files if x.split('.')[-1].lower() in vid_formats] + ni, nv = len(images), len(videos) + + self.img_size = img_size + self.auto_size = auto_size + self.files = images + videos + self.nf = ni + nv # number of files + self.video_flag = [False] * ni + [True] * nv + self.mode = 'images' + if any(videos): + self.new_video(videos[0]) # new video + else: + self.cap = None + assert self.nf > 0, 'No images or videos found in %s. Supported formats are:\nimages: %s\nvideos: %s' % \ + (p, img_formats, vid_formats) + + def __iter__(self): + self.count = 0 + return self + + def __next__(self): + if self.count == self.nf: + raise StopIteration + path = self.files[self.count] + + if self.video_flag[self.count]: + # Read video + self.mode = 'video' + ret_val, img0 = self.cap.read() + if not ret_val: + self.count += 1 + self.cap.release() + if self.count == self.nf: # last video + raise StopIteration + else: + path = self.files[self.count] + self.new_video(path) + ret_val, img0 = self.cap.read() + + self.frame += 1 + print('video %g/%g (%g/%g) %s: ' % (self.count + 1, self.nf, self.frame, self.nframes, path), end='') + + else: + # Read image + self.count += 1 + img0 = cv2.imread(path) # BGR + assert img0 is not None, 'Image Not Found ' + path + print('image %g/%g %s: ' % (self.count, self.nf, path), end='') + + # Padded resize + img = letterbox(img0, new_shape=self.img_size, auto_size=self.auto_size)[0] + + # Convert + img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 + img = np.ascontiguousarray(img) + + return path, img, img0, self.cap + + def new_video(self, path): + self.frame = 0 + self.cap = cv2.VideoCapture(path) + self.nframes = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT)) + + def __len__(self): + return self.nf # number of files + + +class LoadWebcam: # for inference + def __init__(self, pipe='0', img_size=640): + self.img_size = img_size + + if pipe.isnumeric(): + pipe = eval(pipe) # local camera + # pipe = 'rtsp://192.168.1.64/1' # IP camera + # pipe = 'rtsp://username:password@192.168.1.64/1' # IP camera with login + # pipe = 'http://wmccpinetop.axiscam.net/mjpg/video.mjpg' # IP golf camera + + self.pipe = pipe + self.cap = cv2.VideoCapture(pipe) # video capture object + self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 3) # set buffer size + + def __iter__(self): + self.count = -1 + return self + + def __next__(self): + self.count += 1 + if cv2.waitKey(1) == ord('q'): # q to quit + self.cap.release() + cv2.destroyAllWindows() + raise StopIteration + + # Read frame + if self.pipe == 0: # local camera + ret_val, img0 = self.cap.read() + img0 = cv2.flip(img0, 1) # flip left-right + else: # IP camera + n = 0 + while True: + n += 1 + self.cap.grab() + if n % 30 == 0: # skip frames + ret_val, img0 = self.cap.retrieve() + if ret_val: + break + + # Print + assert ret_val, 'Camera Error %s' % self.pipe + img_path = 'webcam.jpg' + print('webcam %g: ' % self.count, end='') + + # Padded resize + img = letterbox(img0, new_shape=self.img_size)[0] + + # Convert + img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 + img = np.ascontiguousarray(img) + + return img_path, img, img0, None + + def __len__(self): + return 0 + + +class LoadStreams: # multiple IP or RTSP cameras + def __init__(self, sources='streams.txt', img_size=640): + self.mode = 'images' + self.img_size = img_size + + if os.path.isfile(sources): + with open(sources, 'r') as f: + sources = [x.strip() for x in f.read().splitlines() if len(x.strip())] + else: + sources = [sources] + + n = len(sources) + self.imgs = [None] * n + self.sources = sources + for i, s in enumerate(sources): + # Start the thread to read frames from the video stream + print('%g/%g: %s... ' % (i + 1, n, s), end='') + cap = cv2.VideoCapture(eval(s) if s.isnumeric() else s) + assert cap.isOpened(), 'Failed to open %s' % s + w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + fps = cap.get(cv2.CAP_PROP_FPS) % 100 + _, self.imgs[i] = cap.read() # guarantee first frame + thread = Thread(target=self.update, args=([i, cap]), daemon=True) + print(' success (%gx%g at %.2f FPS).' % (w, h, fps)) + thread.start() + print('') # newline + + # check for common shapes + s = np.stack([letterbox(x, new_shape=self.img_size)[0].shape for x in self.imgs], 0) # inference shapes + self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal + if not self.rect: + print('WARNING: Different stream shapes detected. For optimal performance supply similarly-shaped streams.') + + def update(self, index, cap): + # Read next stream frame in a daemon thread + n = 0 + while cap.isOpened(): + n += 1 + # _, self.imgs[index] = cap.read() + cap.grab() + if n == 4: # read every 4th frame + _, self.imgs[index] = cap.retrieve() + n = 0 + time.sleep(0.01) # wait time + + def __iter__(self): + self.count = -1 + return self + + def __next__(self): + self.count += 1 + img0 = self.imgs.copy() + if cv2.waitKey(1) == ord('q'): # q to quit + cv2.destroyAllWindows() + raise StopIteration + + # Letterbox + img = [letterbox(x, new_shape=self.img_size, auto=self.rect)[0] for x in img0] + + # Stack + img = np.stack(img, 0) + + # Convert + img = img[:, :, :, ::-1].transpose(0, 3, 1, 2) # BGR to RGB, to bsx3x416x416 + img = np.ascontiguousarray(img) + + return self.sources, img, img0, None + + def __len__(self): + return 0 # 1E12 frames = 32 streams at 30 FPS for 30 years + + +class LoadImagesAndLabels(Dataset): # for training/testing + def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, rect=False, image_weights=False, + cache_images=False, single_cls=False, stride=32, pad=0.0, rank=-1): + self.img_size = img_size + self.augment = augment + self.hyp = hyp + self.image_weights = image_weights + self.rect = False if image_weights else rect + self.mosaic = self.augment and not self.rect # load 4 images at a time into a mosaic (only during training) + self.mosaic_border = [-img_size // 2, -img_size // 2] + self.stride = stride + + def img2label_paths(img_paths): + # Define label paths as a function of image paths + sa, sb = os.sep + 'images' + os.sep, os.sep + 'labels' + os.sep # /images/, /labels/ substrings + return [x.replace(sa, sb, 1).replace(x.split('.')[-1], 'txt') for x in img_paths] + + try: + f = [] # image files + for p in path if isinstance(path, list) else [path]: + p = Path(p) # os-agnostic + if p.is_dir(): # dir + f += glob.glob(str(p / '**' / '*.*'), recursive=True) + elif p.is_file(): # file + with open(p, 'r') as t: + t = t.read().splitlines() + parent = str(p.parent) + os.sep + f += [x.replace('./', parent) if x.startswith('./') else x for x in t] # local to global path + else: + raise Exception('%s does not exist' % p) + self.img_files = sorted([x.replace('/', os.sep) for x in f if x.split('.')[-1].lower() in img_formats]) + assert self.img_files, 'No images found' + except Exception as e: + raise Exception('Error loading data from %s: %s\nSee %s' % (path, e, help_url)) + + # Check cache + self.label_files = img2label_paths(self.img_files) # labels + cache_path = str(Path(self.label_files[0]).parent) + '.cache3' # cached labels + if os.path.isfile(cache_path): + cache = torch.load(cache_path) # load + if cache['hash'] != get_hash(self.label_files + self.img_files): # dataset changed + cache = self.cache_labels(cache_path) # re-cache + else: + cache = self.cache_labels(cache_path) # cache + + # Read cache + cache.pop('hash') # remove hash + labels, shapes = zip(*cache.values()) + self.labels = list(labels) + self.shapes = np.array(shapes, dtype=np.float64) + self.img_files = list(cache.keys()) # update + self.label_files = img2label_paths(cache.keys()) # update + + n = len(shapes) # number of images + bi = np.floor(np.arange(n) / batch_size).astype(np.int) # batch index + nb = bi[-1] + 1 # number of batches + self.batch = bi # batch index of image + self.n = n + + # Rectangular Training + if self.rect: + # Sort by aspect ratio + s = self.shapes # wh + ar = s[:, 1] / s[:, 0] # aspect ratio + irect = ar.argsort() + self.img_files = [self.img_files[i] for i in irect] + self.label_files = [self.label_files[i] for i in irect] + self.labels = [self.labels[i] for i in irect] + self.shapes = s[irect] # wh + ar = ar[irect] + + # Set training image shapes + shapes = [[1, 1]] * nb + for i in range(nb): + ari = ar[bi == i] + mini, maxi = ari.min(), ari.max() + if maxi < 1: + shapes[i] = [maxi, 1] + elif mini > 1: + shapes[i] = [1, 1 / mini] + + self.batch_shapes = np.ceil(np.array(shapes) * img_size / stride + pad).astype(np.int) * stride + + # Check labels + create_datasubset, extract_bounding_boxes, labels_loaded = False, False, False + nm, nf, ne, ns, nd = 0, 0, 0, 0, 0 # number missing, found, empty, datasubset, duplicate + pbar = enumerate(self.label_files) + if rank in [-1, 0]: + pbar = tqdm(pbar) + for i, file in pbar: + l = self.labels[i] # label + if l is not None and l.shape[0]: + assert l.shape[1] == 5, '> 5 label columns: %s' % file + assert (l >= 0).all(), 'negative labels: %s' % file + assert (l[:, 1:] <= 1).all(), 'non-normalized or out of bounds coordinate labels: %s' % file + if np.unique(l, axis=0).shape[0] < l.shape[0]: # duplicate rows + nd += 1 # print('WARNING: duplicate rows in %s' % self.label_files[i]) # duplicate rows + if single_cls: + l[:, 0] = 0 # force dataset into single-class mode + self.labels[i] = l + nf += 1 # file found + + # Create subdataset (a smaller dataset) + if create_datasubset and ns < 1E4: + if ns == 0: + create_folder(path='./datasubset') + os.makedirs('./datasubset/images') + exclude_classes = 43 + if exclude_classes not in l[:, 0]: + ns += 1 + # shutil.copy(src=self.img_files[i], dst='./datasubset/images/') # copy image + with open('./datasubset/images.txt', 'a') as f: + f.write(self.img_files[i] + '\n') + + # Extract object detection boxes for a second stage classifier + if extract_bounding_boxes: + p = Path(self.img_files[i]) + img = cv2.imread(str(p)) + h, w = img.shape[:2] + for j, x in enumerate(l): + f = '%s%sclassifier%s%g_%g_%s' % (p.parent.parent, os.sep, os.sep, x[0], j, p.name) + if not os.path.exists(Path(f).parent): + os.makedirs(Path(f).parent) # make new output folder + + b = x[1:] * [w, h, w, h] # box + b[2:] = b[2:].max() # rectangle to square + b[2:] = b[2:] * 1.3 + 30 # pad + b = xywh2xyxy(b.reshape(-1, 4)).ravel().astype(np.int) + + b[[0, 2]] = np.clip(b[[0, 2]], 0, w) # clip boxes outside of image + b[[1, 3]] = np.clip(b[[1, 3]], 0, h) + assert cv2.imwrite(f, img[b[1]:b[3], b[0]:b[2]]), 'Failure extracting classifier boxes' + else: + ne += 1 # print('empty labels for image %s' % self.img_files[i]) # file empty + # os.system("rm '%s' '%s'" % (self.img_files[i], self.label_files[i])) # remove + + if rank in [-1, 0]: + pbar.desc = 'Scanning labels %s (%g found, %g missing, %g empty, %g duplicate, for %g images)' % ( + cache_path, nf, nm, ne, nd, n) + if nf == 0: + s = 'WARNING: No labels found in %s. See %s' % (os.path.dirname(file) + os.sep, help_url) + print(s) + assert not augment, '%s. Can not train without labels.' % s + + # Cache images into memory for faster training (WARNING: large datasets may exceed system RAM) + self.imgs = [None] * n + if cache_images: + gb = 0 # Gigabytes of cached images + self.img_hw0, self.img_hw = [None] * n, [None] * n + results = ThreadPool(8).imap(lambda x: load_image(*x), zip(repeat(self), range(n))) # 8 threads + pbar = tqdm(enumerate(results), total=n) + for i, x in pbar: + self.imgs[i], self.img_hw0[i], self.img_hw[i] = x # img, hw_original, hw_resized = load_image(self, i) + gb += self.imgs[i].nbytes + pbar.desc = 'Caching images (%.1fGB)' % (gb / 1E9) + + def cache_labels(self, path='labels.cache3'): + # Cache dataset labels, check images and read shapes + x = {} # dict + pbar = tqdm(zip(self.img_files, self.label_files), desc='Scanning images', total=len(self.img_files)) + for (img, label) in pbar: + try: + l = [] + im = Image.open(img) + im.verify() # PIL verify + shape = exif_size(im) # image size + assert (shape[0] > 9) & (shape[1] > 9), 'image size <10 pixels' + if os.path.isfile(label): + with open(label, 'r') as f: + l = np.array([x.split() for x in f.read().splitlines()], dtype=np.float32) # labels + if len(l) == 0: + l = np.zeros((0, 5), dtype=np.float32) + x[img] = [l, shape] + except Exception as e: + print('WARNING: Ignoring corrupted image and/or label %s: %s' % (img, e)) + + x['hash'] = get_hash(self.label_files + self.img_files) + torch.save(x, path) # save for next time + return x + + def __len__(self): + return len(self.img_files) + + # def __iter__(self): + # self.count = -1 + # print('ran dataset iter') + # #self.shuffled_vector = np.random.permutation(self.nF) if self.augment else np.arange(self.nF) + # return self + + def __getitem__(self, index): + if self.image_weights: + index = self.indices[index] + + hyp = self.hyp + mosaic = self.mosaic and random.random() < hyp['mosaic'] + if mosaic: + # Load mosaic + img, labels = load_mosaic(self, index) + #img, labels = load_mosaic9(self, index) + shapes = None + + # MixUp https://arxiv.org/pdf/1710.09412.pdf + if random.random() < hyp['mixup']: + img2, labels2 = load_mosaic(self, random.randint(0, len(self.labels) - 1)) + #img2, labels2 = load_mosaic9(self, random.randint(0, len(self.labels) - 1)) + r = np.random.beta(8.0, 8.0) # mixup ratio, alpha=beta=8.0 + img = (img * r + img2 * (1 - r)).astype(np.uint8) + labels = np.concatenate((labels, labels2), 0) + + else: + # Load image + img, (h0, w0), (h, w) = load_image(self, index) + + # Letterbox + shape = self.batch_shapes[self.batch[index]] if self.rect else self.img_size # final letterboxed shape + img, ratio, pad = letterbox(img, shape, auto=False, scaleup=self.augment) + shapes = (h0, w0), ((h / h0, w / w0), pad) # for COCO mAP rescaling + + # Load labels + labels = [] + x = self.labels[index] + if x.size > 0: + # Normalized xywh to pixel xyxy format + labels = x.copy() + labels[:, 1] = ratio[0] * w * (x[:, 1] - x[:, 3] / 2) + pad[0] # pad width + labels[:, 2] = ratio[1] * h * (x[:, 2] - x[:, 4] / 2) + pad[1] # pad height + labels[:, 3] = ratio[0] * w * (x[:, 1] + x[:, 3] / 2) + pad[0] + labels[:, 4] = ratio[1] * h * (x[:, 2] + x[:, 4] / 2) + pad[1] + + if self.augment: + # Augment imagespace + if not mosaic: + img, labels = random_perspective(img, labels, + degrees=hyp['degrees'], + translate=hyp['translate'], + scale=hyp['scale'], + shear=hyp['shear'], + perspective=hyp['perspective']) + + # Augment colorspace + augment_hsv(img, hgain=hyp['hsv_h'], sgain=hyp['hsv_s'], vgain=hyp['hsv_v']) + + # Apply cutouts + # if random.random() < 0.9: + # labels = cutout(img, labels) + + nL = len(labels) # number of labels + if nL: + labels[:, 1:5] = xyxy2xywh(labels[:, 1:5]) # convert xyxy to xywh + labels[:, [2, 4]] /= img.shape[0] # normalized height 0-1 + labels[:, [1, 3]] /= img.shape[1] # normalized width 0-1 + + if self.augment: + # flip up-down + if random.random() < hyp['flipud']: + img = np.flipud(img) + if nL: + labels[:, 2] = 1 - labels[:, 2] + + # flip left-right + if random.random() < hyp['fliplr']: + img = np.fliplr(img) + if nL: + labels[:, 1] = 1 - labels[:, 1] + + labels_out = torch.zeros((nL, 6)) + if nL: + labels_out[:, 1:] = torch.from_numpy(labels) + + # Convert + img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 + img = np.ascontiguousarray(img) + + return torch.from_numpy(img), labels_out, self.img_files[index], shapes + + @staticmethod + def collate_fn(batch): + img, label, path, shapes = zip(*batch) # transposed + for i, l in enumerate(label): + l[:, 0] = i # add target image index for build_targets() + return torch.stack(img, 0), torch.cat(label, 0), path, shapes + + +class LoadImagesAndLabels9(Dataset): # for training/testing + def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, rect=False, image_weights=False, + cache_images=False, single_cls=False, stride=32, pad=0.0, rank=-1): + self.img_size = img_size + self.augment = augment + self.hyp = hyp + self.image_weights = image_weights + self.rect = False if image_weights else rect + self.mosaic = self.augment and not self.rect # load 4 images at a time into a mosaic (only during training) + self.mosaic_border = [-img_size // 2, -img_size // 2] + self.stride = stride + + def img2label_paths(img_paths): + # Define label paths as a function of image paths + sa, sb = os.sep + 'images' + os.sep, os.sep + 'labels' + os.sep # /images/, /labels/ substrings + return [x.replace(sa, sb, 1).replace(x.split('.')[-1], 'txt') for x in img_paths] + + try: + f = [] # image files + for p in path if isinstance(path, list) else [path]: + p = Path(p) # os-agnostic + if p.is_dir(): # dir + f += glob.glob(str(p / '**' / '*.*'), recursive=True) + elif p.is_file(): # file + with open(p, 'r') as t: + t = t.read().splitlines() + parent = str(p.parent) + os.sep + f += [x.replace('./', parent) if x.startswith('./') else x for x in t] # local to global path + else: + raise Exception('%s does not exist' % p) + self.img_files = sorted([x.replace('/', os.sep) for x in f if x.split('.')[-1].lower() in img_formats]) + assert self.img_files, 'No images found' + except Exception as e: + raise Exception('Error loading data from %s: %s\nSee %s' % (path, e, help_url)) + + # Check cache + self.label_files = img2label_paths(self.img_files) # labels + cache_path = str(Path(self.label_files[0]).parent) + '.cache3' # cached labels + if os.path.isfile(cache_path): + cache = torch.load(cache_path) # load + if cache['hash'] != get_hash(self.label_files + self.img_files): # dataset changed + cache = self.cache_labels(cache_path) # re-cache + else: + cache = self.cache_labels(cache_path) # cache + + # Read cache + cache.pop('hash') # remove hash + labels, shapes = zip(*cache.values()) + self.labels = list(labels) + self.shapes = np.array(shapes, dtype=np.float64) + self.img_files = list(cache.keys()) # update + self.label_files = img2label_paths(cache.keys()) # update + + n = len(shapes) # number of images + bi = np.floor(np.arange(n) / batch_size).astype(np.int) # batch index + nb = bi[-1] + 1 # number of batches + self.batch = bi # batch index of image + self.n = n + + # Rectangular Training + if self.rect: + # Sort by aspect ratio + s = self.shapes # wh + ar = s[:, 1] / s[:, 0] # aspect ratio + irect = ar.argsort() + self.img_files = [self.img_files[i] for i in irect] + self.label_files = [self.label_files[i] for i in irect] + self.labels = [self.labels[i] for i in irect] + self.shapes = s[irect] # wh + ar = ar[irect] + + # Set training image shapes + shapes = [[1, 1]] * nb + for i in range(nb): + ari = ar[bi == i] + mini, maxi = ari.min(), ari.max() + if maxi < 1: + shapes[i] = [maxi, 1] + elif mini > 1: + shapes[i] = [1, 1 / mini] + + self.batch_shapes = np.ceil(np.array(shapes) * img_size / stride + pad).astype(np.int) * stride + + # Check labels + create_datasubset, extract_bounding_boxes, labels_loaded = False, False, False + nm, nf, ne, ns, nd = 0, 0, 0, 0, 0 # number missing, found, empty, datasubset, duplicate + pbar = enumerate(self.label_files) + if rank in [-1, 0]: + pbar = tqdm(pbar) + for i, file in pbar: + l = self.labels[i] # label + if l is not None and l.shape[0]: + assert l.shape[1] == 5, '> 5 label columns: %s' % file + assert (l >= 0).all(), 'negative labels: %s' % file + assert (l[:, 1:] <= 1).all(), 'non-normalized or out of bounds coordinate labels: %s' % file + if np.unique(l, axis=0).shape[0] < l.shape[0]: # duplicate rows + nd += 1 # print('WARNING: duplicate rows in %s' % self.label_files[i]) # duplicate rows + if single_cls: + l[:, 0] = 0 # force dataset into single-class mode + self.labels[i] = l + nf += 1 # file found + + # Create subdataset (a smaller dataset) + if create_datasubset and ns < 1E4: + if ns == 0: + create_folder(path='./datasubset') + os.makedirs('./datasubset/images') + exclude_classes = 43 + if exclude_classes not in l[:, 0]: + ns += 1 + # shutil.copy(src=self.img_files[i], dst='./datasubset/images/') # copy image + with open('./datasubset/images.txt', 'a') as f: + f.write(self.img_files[i] + '\n') + + # Extract object detection boxes for a second stage classifier + if extract_bounding_boxes: + p = Path(self.img_files[i]) + img = cv2.imread(str(p)) + h, w = img.shape[:2] + for j, x in enumerate(l): + f = '%s%sclassifier%s%g_%g_%s' % (p.parent.parent, os.sep, os.sep, x[0], j, p.name) + if not os.path.exists(Path(f).parent): + os.makedirs(Path(f).parent) # make new output folder + + b = x[1:] * [w, h, w, h] # box + b[2:] = b[2:].max() # rectangle to square + b[2:] = b[2:] * 1.3 + 30 # pad + b = xywh2xyxy(b.reshape(-1, 4)).ravel().astype(np.int) + + b[[0, 2]] = np.clip(b[[0, 2]], 0, w) # clip boxes outside of image + b[[1, 3]] = np.clip(b[[1, 3]], 0, h) + assert cv2.imwrite(f, img[b[1]:b[3], b[0]:b[2]]), 'Failure extracting classifier boxes' + else: + ne += 1 # print('empty labels for image %s' % self.img_files[i]) # file empty + # os.system("rm '%s' '%s'" % (self.img_files[i], self.label_files[i])) # remove + + if rank in [-1, 0]: + pbar.desc = 'Scanning labels %s (%g found, %g missing, %g empty, %g duplicate, for %g images)' % ( + cache_path, nf, nm, ne, nd, n) + if nf == 0: + s = 'WARNING: No labels found in %s. See %s' % (os.path.dirname(file) + os.sep, help_url) + print(s) + assert not augment, '%s. Can not train without labels.' % s + + # Cache images into memory for faster training (WARNING: large datasets may exceed system RAM) + self.imgs = [None] * n + if cache_images: + gb = 0 # Gigabytes of cached images + self.img_hw0, self.img_hw = [None] * n, [None] * n + results = ThreadPool(8).imap(lambda x: load_image(*x), zip(repeat(self), range(n))) # 8 threads + pbar = tqdm(enumerate(results), total=n) + for i, x in pbar: + self.imgs[i], self.img_hw0[i], self.img_hw[i] = x # img, hw_original, hw_resized = load_image(self, i) + gb += self.imgs[i].nbytes + pbar.desc = 'Caching images (%.1fGB)' % (gb / 1E9) + + def cache_labels(self, path='labels.cache3'): + # Cache dataset labels, check images and read shapes + x = {} # dict + pbar = tqdm(zip(self.img_files, self.label_files), desc='Scanning images', total=len(self.img_files)) + for (img, label) in pbar: + try: + l = [] + im = Image.open(img) + im.verify() # PIL verify + shape = exif_size(im) # image size + assert (shape[0] > 9) & (shape[1] > 9), 'image size <10 pixels' + if os.path.isfile(label): + with open(label, 'r') as f: + l = np.array([x.split() for x in f.read().splitlines()], dtype=np.float32) # labels + if len(l) == 0: + l = np.zeros((0, 5), dtype=np.float32) + x[img] = [l, shape] + except Exception as e: + print('WARNING: Ignoring corrupted image and/or label %s: %s' % (img, e)) + + x['hash'] = get_hash(self.label_files + self.img_files) + torch.save(x, path) # save for next time + return x + + def __len__(self): + return len(self.img_files) + + # def __iter__(self): + # self.count = -1 + # print('ran dataset iter') + # #self.shuffled_vector = np.random.permutation(self.nF) if self.augment else np.arange(self.nF) + # return self + + def __getitem__(self, index): + if self.image_weights: + index = self.indices[index] + + hyp = self.hyp + mosaic = self.mosaic and random.random() < hyp['mosaic'] + if mosaic: + # Load mosaic + #img, labels = load_mosaic(self, index) + img, labels = load_mosaic9(self, index) + shapes = None + + # MixUp https://arxiv.org/pdf/1710.09412.pdf + if random.random() < hyp['mixup']: + #img2, labels2 = load_mosaic(self, random.randint(0, len(self.labels) - 1)) + img2, labels2 = load_mosaic9(self, random.randint(0, len(self.labels) - 1)) + r = np.random.beta(8.0, 8.0) # mixup ratio, alpha=beta=8.0 + img = (img * r + img2 * (1 - r)).astype(np.uint8) + labels = np.concatenate((labels, labels2), 0) + + else: + # Load image + img, (h0, w0), (h, w) = load_image(self, index) + + # Letterbox + shape = self.batch_shapes[self.batch[index]] if self.rect else self.img_size # final letterboxed shape + img, ratio, pad = letterbox(img, shape, auto=False, scaleup=self.augment) + shapes = (h0, w0), ((h / h0, w / w0), pad) # for COCO mAP rescaling + + # Load labels + labels = [] + x = self.labels[index] + if x.size > 0: + # Normalized xywh to pixel xyxy format + labels = x.copy() + labels[:, 1] = ratio[0] * w * (x[:, 1] - x[:, 3] / 2) + pad[0] # pad width + labels[:, 2] = ratio[1] * h * (x[:, 2] - x[:, 4] / 2) + pad[1] # pad height + labels[:, 3] = ratio[0] * w * (x[:, 1] + x[:, 3] / 2) + pad[0] + labels[:, 4] = ratio[1] * h * (x[:, 2] + x[:, 4] / 2) + pad[1] + + if self.augment: + # Augment imagespace + if not mosaic: + img, labels = random_perspective(img, labels, + degrees=hyp['degrees'], + translate=hyp['translate'], + scale=hyp['scale'], + shear=hyp['shear'], + perspective=hyp['perspective']) + + # Augment colorspace + augment_hsv(img, hgain=hyp['hsv_h'], sgain=hyp['hsv_s'], vgain=hyp['hsv_v']) + + # Apply cutouts + # if random.random() < 0.9: + # labels = cutout(img, labels) + + nL = len(labels) # number of labels + if nL: + labels[:, 1:5] = xyxy2xywh(labels[:, 1:5]) # convert xyxy to xywh + labels[:, [2, 4]] /= img.shape[0] # normalized height 0-1 + labels[:, [1, 3]] /= img.shape[1] # normalized width 0-1 + + if self.augment: + # flip up-down + if random.random() < hyp['flipud']: + img = np.flipud(img) + if nL: + labels[:, 2] = 1 - labels[:, 2] + + # flip left-right + if random.random() < hyp['fliplr']: + img = np.fliplr(img) + if nL: + labels[:, 1] = 1 - labels[:, 1] + + labels_out = torch.zeros((nL, 6)) + if nL: + labels_out[:, 1:] = torch.from_numpy(labels) + + # Convert + img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 + img = np.ascontiguousarray(img) + + return torch.from_numpy(img), labels_out, self.img_files[index], shapes + + @staticmethod + def collate_fn(batch): + img, label, path, shapes = zip(*batch) # transposed + for i, l in enumerate(label): + l[:, 0] = i # add target image index for build_targets() + return torch.stack(img, 0), torch.cat(label, 0), path, shapes + + +# Ancillary functions -------------------------------------------------------------------------------------------------- +def load_image(self, index): + # loads 1 image from dataset, returns img, original hw, resized hw + img = self.imgs[index] + if img is None: # not cached + path = self.img_files[index] + img = cv2.imread(path) # BGR + assert img is not None, 'Image Not Found ' + path + h0, w0 = img.shape[:2] # orig hw + r = self.img_size / max(h0, w0) # resize image to img_size + if r != 1: # always resize down, only resize up if training with augmentation + interp = cv2.INTER_AREA if r < 1 and not self.augment else cv2.INTER_LINEAR + img = cv2.resize(img, (int(w0 * r), int(h0 * r)), interpolation=interp) + return img, (h0, w0), img.shape[:2] # img, hw_original, hw_resized + else: + return self.imgs[index], self.img_hw0[index], self.img_hw[index] # img, hw_original, hw_resized + + +def augment_hsv(img, hgain=0.5, sgain=0.5, vgain=0.5): + r = np.random.uniform(-1, 1, 3) * [hgain, sgain, vgain] + 1 # random gains + hue, sat, val = cv2.split(cv2.cvtColor(img, cv2.COLOR_BGR2HSV)) + dtype = img.dtype # uint8 + + x = np.arange(0, 256, dtype=np.int16) + lut_hue = ((x * r[0]) % 180).astype(dtype) + lut_sat = np.clip(x * r[1], 0, 255).astype(dtype) + lut_val = np.clip(x * r[2], 0, 255).astype(dtype) + + img_hsv = cv2.merge((cv2.LUT(hue, lut_hue), cv2.LUT(sat, lut_sat), cv2.LUT(val, lut_val))).astype(dtype) + cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR, dst=img) # no return needed + + # Histogram equalization + # if random.random() < 0.2: + # for i in range(3): + # img[:, :, i] = cv2.equalizeHist(img[:, :, i]) + + +def load_mosaic(self, index): + # loads images in a mosaic + + labels4 = [] + s = self.img_size + yc, xc = [int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border] # mosaic center x, y + indices = [index] + [random.randint(0, len(self.labels) - 1) for _ in range(3)] # 3 additional image indices + for i, index in enumerate(indices): + # Load image + img, _, (h, w) = load_image(self, index) + + # place img in img4 + if i == 0: # top left + img4 = np.full((s * 2, s * 2, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles + x1a, y1a, x2a, y2a = max(xc - w, 0), max(yc - h, 0), xc, yc # xmin, ymin, xmax, ymax (large image) + x1b, y1b, x2b, y2b = w - (x2a - x1a), h - (y2a - y1a), w, h # xmin, ymin, xmax, ymax (small image) + elif i == 1: # top right + x1a, y1a, x2a, y2a = xc, max(yc - h, 0), min(xc + w, s * 2), yc + x1b, y1b, x2b, y2b = 0, h - (y2a - y1a), min(w, x2a - x1a), h + elif i == 2: # bottom left + x1a, y1a, x2a, y2a = max(xc - w, 0), yc, xc, min(s * 2, yc + h) + x1b, y1b, x2b, y2b = w - (x2a - x1a), 0, w, min(y2a - y1a, h) + elif i == 3: # bottom right + x1a, y1a, x2a, y2a = xc, yc, min(xc + w, s * 2), min(s * 2, yc + h) + x1b, y1b, x2b, y2b = 0, 0, min(w, x2a - x1a), min(y2a - y1a, h) + + img4[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b] # img4[ymin:ymax, xmin:xmax] + padw = x1a - x1b + padh = y1a - y1b + + # Labels + x = self.labels[index] + labels = x.copy() + if x.size > 0: # Normalized xywh to pixel xyxy format + labels[:, 1] = w * (x[:, 1] - x[:, 3] / 2) + padw + labels[:, 2] = h * (x[:, 2] - x[:, 4] / 2) + padh + labels[:, 3] = w * (x[:, 1] + x[:, 3] / 2) + padw + labels[:, 4] = h * (x[:, 2] + x[:, 4] / 2) + padh + labels4.append(labels) + + # Concat/clip labels + if len(labels4): + labels4 = np.concatenate(labels4, 0) + np.clip(labels4[:, 1:], 0, 2 * s, out=labels4[:, 1:]) # use with random_perspective + # img4, labels4 = replicate(img4, labels4) # replicate + + # Augment + img4, labels4 = random_perspective(img4, labels4, + degrees=self.hyp['degrees'], + translate=self.hyp['translate'], + scale=self.hyp['scale'], + shear=self.hyp['shear'], + perspective=self.hyp['perspective'], + border=self.mosaic_border) # border to remove + + return img4, labels4 + + +def load_mosaic9(self, index): + # loads images in a 9-mosaic + + labels9 = [] + s = self.img_size + indices = [index] + [random.randint(0, len(self.labels) - 1) for _ in range(8)] # 8 additional image indices + for i, index in enumerate(indices): + # Load image + img, _, (h, w) = load_image(self, index) + + # place img in img9 + if i == 0: # center + img9 = np.full((s * 3, s * 3, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles + h0, w0 = h, w + c = s, s, s + w, s + h # xmin, ymin, xmax, ymax (base) coordinates + elif i == 1: # top + c = s, s - h, s + w, s + elif i == 2: # top right + c = s + wp, s - h, s + wp + w, s + elif i == 3: # right + c = s + w0, s, s + w0 + w, s + h + elif i == 4: # bottom right + c = s + w0, s + hp, s + w0 + w, s + hp + h + elif i == 5: # bottom + c = s + w0 - w, s + h0, s + w0, s + h0 + h + elif i == 6: # bottom left + c = s + w0 - wp - w, s + h0, s + w0 - wp, s + h0 + h + elif i == 7: # left + c = s - w, s + h0 - h, s, s + h0 + elif i == 8: # top left + c = s - w, s + h0 - hp - h, s, s + h0 - hp + + padx, pady = c[:2] + x1, y1, x2, y2 = [max(x, 0) for x in c] # allocate coords + + # Labels + x = self.labels[index] + labels = x.copy() + if x.size > 0: # Normalized xywh to pixel xyxy format + labels[:, 1] = w * (x[:, 1] - x[:, 3] / 2) + padx + labels[:, 2] = h * (x[:, 2] - x[:, 4] / 2) + pady + labels[:, 3] = w * (x[:, 1] + x[:, 3] / 2) + padx + labels[:, 4] = h * (x[:, 2] + x[:, 4] / 2) + pady + labels9.append(labels) + + # Image + img9[y1:y2, x1:x2] = img[y1 - pady:, x1 - padx:] # img9[ymin:ymax, xmin:xmax] + hp, wp = h, w # height, width previous + + # Offset + yc, xc = [int(random.uniform(0, s)) for x in self.mosaic_border] # mosaic center x, y + img9 = img9[yc:yc + 2 * s, xc:xc + 2 * s] + + # Concat/clip labels + if len(labels9): + labels9 = np.concatenate(labels9, 0) + labels9[:, [1, 3]] -= xc + labels9[:, [2, 4]] -= yc + + np.clip(labels9[:, 1:], 0, 2 * s, out=labels9[:, 1:]) # use with random_perspective + # img9, labels9 = replicate(img9, labels9) # replicate + + # Augment + img9, labels9 = random_perspective(img9, labels9, + degrees=self.hyp['degrees'], + translate=self.hyp['translate'], + scale=self.hyp['scale'], + shear=self.hyp['shear'], + perspective=self.hyp['perspective'], + border=self.mosaic_border) # border to remove + + return img9, labels9 + + +def replicate(img, labels): + # Replicate labels + h, w = img.shape[:2] + boxes = labels[:, 1:].astype(int) + x1, y1, x2, y2 = boxes.T + s = ((x2 - x1) + (y2 - y1)) / 2 # side length (pixels) + for i in s.argsort()[:round(s.size * 0.5)]: # smallest indices + x1b, y1b, x2b, y2b = boxes[i] + bh, bw = y2b - y1b, x2b - x1b + yc, xc = int(random.uniform(0, h - bh)), int(random.uniform(0, w - bw)) # offset x, y + x1a, y1a, x2a, y2a = [xc, yc, xc + bw, yc + bh] + img[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b] # img4[ymin:ymax, xmin:xmax] + labels = np.append(labels, [[labels[i, 0], x1a, y1a, x2a, y2a]], axis=0) + + return img, labels + + +def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, auto_size=32): + # Resize image to a 32-pixel-multiple rectangle https://github.com/ultralytics/yolov3/issues/232 + shape = img.shape[:2] # current shape [height, width] + if isinstance(new_shape, int): + new_shape = (new_shape, new_shape) + + # Scale ratio (new / old) + r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) + if not scaleup: # only scale down, do not scale up (for better test mAP) + r = min(r, 1.0) + + # Compute padding + ratio = r, r # width, height ratios + new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) + dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding + if auto: # minimum rectangle + dw, dh = np.mod(dw, auto_size), np.mod(dh, auto_size) # wh padding + elif scaleFill: # stretch + dw, dh = 0.0, 0.0 + new_unpad = (new_shape[1], new_shape[0]) + ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] # width, height ratios + + dw /= 2 # divide padding into 2 sides + dh /= 2 + + if shape[::-1] != new_unpad: # resize + img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR) + top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) + left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) + img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # add border + return img, ratio, (dw, dh) + + +def random_perspective(img, targets=(), degrees=10, translate=.1, scale=.1, shear=10, perspective=0.0, border=(0, 0)): + # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(.1, .1), scale=(.9, 1.1), shear=(-10, 10)) + # targets = [cls, xyxy] + + height = img.shape[0] + border[0] * 2 # shape(h,w,c) + width = img.shape[1] + border[1] * 2 + + # Center + C = np.eye(3) + C[0, 2] = -img.shape[1] / 2 # x translation (pixels) + C[1, 2] = -img.shape[0] / 2 # y translation (pixels) + + # Perspective + P = np.eye(3) + P[2, 0] = random.uniform(-perspective, perspective) # x perspective (about y) + P[2, 1] = random.uniform(-perspective, perspective) # y perspective (about x) + + # Rotation and Scale + R = np.eye(3) + a = random.uniform(-degrees, degrees) + # a += random.choice([-180, -90, 0, 90]) # add 90deg rotations to small rotations + s = random.uniform(1 - scale, 1 + scale) + # s = 2 ** random.uniform(-scale, scale) + R[:2] = cv2.getRotationMatrix2D(angle=a, center=(0, 0), scale=s) + + # Shear + S = np.eye(3) + S[0, 1] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # x shear (deg) + S[1, 0] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # y shear (deg) + + # Translation + T = np.eye(3) + T[0, 2] = random.uniform(0.5 - translate, 0.5 + translate) * width # x translation (pixels) + T[1, 2] = random.uniform(0.5 - translate, 0.5 + translate) * height # y translation (pixels) + + # Combined rotation matrix + M = T @ S @ R @ P @ C # order of operations (right to left) is IMPORTANT + if (border[0] != 0) or (border[1] != 0) or (M != np.eye(3)).any(): # image changed + if perspective: + img = cv2.warpPerspective(img, M, dsize=(width, height), borderValue=(114, 114, 114)) + else: # affine + img = cv2.warpAffine(img, M[:2], dsize=(width, height), borderValue=(114, 114, 114)) + + # Visualize + # import matplotlib.pyplot as plt + # ax = plt.subplots(1, 2, figsize=(12, 6))[1].ravel() + # ax[0].imshow(img[:, :, ::-1]) # base + # ax[1].imshow(img2[:, :, ::-1]) # warped + + # Transform label coordinates + n = len(targets) + if n: + # warp points + xy = np.ones((n * 4, 3)) + xy[:, :2] = targets[:, [1, 2, 3, 4, 1, 4, 3, 2]].reshape(n * 4, 2) # x1y1, x2y2, x1y2, x2y1 + xy = xy @ M.T # transform + if perspective: + xy = (xy[:, :2] / xy[:, 2:3]).reshape(n, 8) # rescale + else: # affine + xy = xy[:, :2].reshape(n, 8) + + # create new boxes + x = xy[:, [0, 2, 4, 6]] + y = xy[:, [1, 3, 5, 7]] + xy = np.concatenate((x.min(1), y.min(1), x.max(1), y.max(1))).reshape(4, n).T + + # # apply angle-based reduction of bounding boxes + # radians = a * math.pi / 180 + # reduction = max(abs(math.sin(radians)), abs(math.cos(radians))) ** 0.5 + # x = (xy[:, 2] + xy[:, 0]) / 2 + # y = (xy[:, 3] + xy[:, 1]) / 2 + # w = (xy[:, 2] - xy[:, 0]) * reduction + # h = (xy[:, 3] - xy[:, 1]) * reduction + # xy = np.concatenate((x - w / 2, y - h / 2, x + w / 2, y + h / 2)).reshape(4, n).T + + # clip boxes + xy[:, [0, 2]] = xy[:, [0, 2]].clip(0, width) + xy[:, [1, 3]] = xy[:, [1, 3]].clip(0, height) + + # filter candidates + i = box_candidates(box1=targets[:, 1:5].T * s, box2=xy.T) + targets = targets[i] + targets[:, 1:5] = xy[i] + + return img, targets + + +def box_candidates(box1, box2, wh_thr=2, ar_thr=20, area_thr=0.1): # box1(4,n), box2(4,n) + # Compute candidate boxes: box1 before augment, box2 after augment, wh_thr (pixels), aspect_ratio_thr, area_ratio + w1, h1 = box1[2] - box1[0], box1[3] - box1[1] + w2, h2 = box2[2] - box2[0], box2[3] - box2[1] + ar = np.maximum(w2 / (h2 + 1e-16), h2 / (w2 + 1e-16)) # aspect ratio + return (w2 > wh_thr) & (h2 > wh_thr) & (w2 * h2 / (w1 * h1 + 1e-16) > area_thr) & (ar < ar_thr) # candidates + + +def cutout(image, labels): + # Applies image cutout augmentation https://arxiv.org/abs/1708.04552 + h, w = image.shape[:2] + + def bbox_ioa(box1, box2): + # Returns the intersection over box2 area given box1, box2. box1 is 4, box2 is nx4. boxes are x1y1x2y2 + box2 = box2.transpose() + + # Get the coordinates of bounding boxes + b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3] + b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3] + + # Intersection area + inter_area = (np.minimum(b1_x2, b2_x2) - np.maximum(b1_x1, b2_x1)).clip(0) * \ + (np.minimum(b1_y2, b2_y2) - np.maximum(b1_y1, b2_y1)).clip(0) + + # box2 area + box2_area = (b2_x2 - b2_x1) * (b2_y2 - b2_y1) + 1e-16 + + # Intersection over box2 area + return inter_area / box2_area + + # create random masks + scales = [0.5] * 1 + [0.25] * 2 + [0.125] * 4 + [0.0625] * 8 + [0.03125] * 16 # image size fraction + for s in scales: + mask_h = random.randint(1, int(h * s)) + mask_w = random.randint(1, int(w * s)) + + # box + xmin = max(0, random.randint(0, w) - mask_w // 2) + ymin = max(0, random.randint(0, h) - mask_h // 2) + xmax = min(w, xmin + mask_w) + ymax = min(h, ymin + mask_h) + + # apply random color mask + image[ymin:ymax, xmin:xmax] = [random.randint(64, 191) for _ in range(3)] + + # return unobscured labels + if len(labels) and s > 0.03: + box = np.array([xmin, ymin, xmax, ymax], dtype=np.float32) + ioa = bbox_ioa(box, labels[:, 1:5]) # intersection over area + labels = labels[ioa < 0.60] # remove >60% obscured labels + + return labels + + +def create_folder(path='./new'): + # Create folder + if os.path.exists(path): + shutil.rmtree(path) # delete output folder + os.makedirs(path) # make new output folder + + +def flatten_recursive(path='../coco128'): + # Flatten a recursive directory by bringing all files to top level + new_path = Path(path + '_flat') + create_folder(new_path) + for file in tqdm(glob.glob(str(Path(path)) + '/**/*.*', recursive=True)): + shutil.copyfile(file, new_path / Path(file).name) + + diff --git a/PyTorch/contrib/cv/detection/YOLOR/utils/google_utils.py b/PyTorch/contrib/cv/detection/YOLOR/utils/google_utils.py index 7cd3e8a2f4..b69abe710b 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/utils/google_utils.py +++ b/PyTorch/contrib/cv/detection/YOLOR/utils/google_utils.py @@ -1,134 +1,134 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -# Google utils: https://cloud.google.com/storage/docs/reference/libraries - -import os -import platform -import subprocess -import time -from pathlib import Path - -import torch - - -def gsutil_getsize(url=''): - # gs://bucket/file size https://cloud.google.com/storage/docs/gsutil/commands/du - s = subprocess.check_output('gsutil du %s' % url, shell=True).decode('utf-8') - return eval(s.split(' ')[0]) if len(s) else 0 # bytes - - -def attempt_download(weights): - # Attempt to download pretrained weights if not found locally - weights = weights.strip().replace("'", '') - file = Path(weights).name - - msg = weights + ' missing, try downloading from https://github.com/WongKinYiu/yolor/releases/' - models = ['yolor_p6.pt', 'yolor_w6.pt'] # available models - - if file in models and not os.path.isfile(weights): - - try: # GitHub - url = 'https://github.com/WongKinYiu/yolor/releases/download/v1.0/' + file - print('Downloading %s to %s...' % (url, weights)) - torch.hub.download_url_to_file(url, weights) - assert os.path.exists(weights) and os.path.getsize(weights) > 1E6 # check - except Exception as e: # GCP - print('ERROR: Download failure.') - print('') - - -def attempt_load(weights, map_location=None): - # Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a - model = Ensemble() - for w in weights if isinstance(weights, list) else [weights]: - attempt_download(w) - model.append(torch.load(w, map_location=map_location)['model'].float().fuse().eval()) # load FP32 model - - if len(model) == 1: - return model[-1] # return model - else: - print('Ensemble created with %s\n' % weights) - for k in ['names', 'stride']: - setattr(model, k, getattr(model[-1], k)) - return model # return ensemble - - -def gdrive_download(id='1n_oKgR81BJtqk75b00eAjdv03qVCQn2f', name='coco128.zip'): - # Downloads a file from Google Drive. from utils.google_utils import *; gdrive_download() - t = time.time() - - print('Downloading https://drive.google.com/uc?export=download&id=%s as %s... ' % (id, name), end='') - os.remove(name) if os.path.exists(name) else None # remove existing - os.remove('cookie') if os.path.exists('cookie') else None - - # Attempt file download - out = "NUL" if platform.system() == "Windows" else "/dev/null" - os.system('curl -c ./cookie -s -L "drive.google.com/uc?export=download&id=%s" > %s ' % (id, out)) - if os.path.exists('cookie'): # large file - s = 'curl -Lb ./cookie "drive.google.com/uc?export=download&confirm=%s&id=%s" -o %s' % (get_token(), id, name) - else: # small file - s = 'curl -s -L -o %s "drive.google.com/uc?export=download&id=%s"' % (name, id) - r = os.system(s) # execute, capture return - os.remove('cookie') if os.path.exists('cookie') else None - - # Error check - if r != 0: - os.remove(name) if os.path.exists(name) else None # remove partial - print('Download error ') # raise Exception('Download error') - return r - - # Unzip if archive - if name.endswith('.zip'): - print('unzipping... ', end='') - os.system('unzip -q %s' % name) # unzip - os.remove(name) # remove zip to free space - - print('Done (%.1fs)' % (time.time() - t)) - return r - - -def get_token(cookie="./cookie"): - with open(cookie) as f: - for line in f: - if "download" in line: - return line.split()[-1] - return "" - -# def upload_blob(bucket_name, source_file_name, destination_blob_name): -# # Uploads a file to a bucket -# # https://cloud.google.com/storage/docs/uploading-objects#storage-upload-object-python -# -# storage_client = storage.Client() -# bucket = storage_client.get_bucket(bucket_name) -# blob = bucket.blob(destination_blob_name) -# -# blob.upload_from_filename(source_file_name) -# -# print('File {} uploaded to {}.'.format( -# source_file_name, -# destination_blob_name)) -# -# -# def download_blob(bucket_name, source_blob_name, destination_file_name): -# # Uploads a blob from a bucket -# storage_client = storage.Client() -# bucket = storage_client.get_bucket(bucket_name) -# blob = bucket.blob(source_blob_name) -# -# blob.download_to_filename(destination_file_name) -# -# print('Blob {} downloaded to {}.'.format( -# source_blob_name, -# destination_file_name)) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +# Google utils: https://cloud.google.com/storage/docs/reference/libraries + +import os +import platform +import subprocess +import time +from pathlib import Path + +import torch + + +def gsutil_getsize(url=''): + # gs://bucket/file size https://cloud.google.com/storage/docs/gsutil/commands/du + s = subprocess.check_output('gsutil du %s' % url, shell=True).decode('utf-8') + return eval(s.split(' ')[0]) if len(s) else 0 # bytes + + +def attempt_download(weights): + # Attempt to download pretrained weights if not found locally + weights = weights.strip().replace("'", '') + file = Path(weights).name + + msg = weights + ' missing, try downloading from https://github.com/WongKinYiu/yolor/releases/' + models = ['yolor_p6.pt', 'yolor_w6.pt'] # available models + + if file in models and not os.path.isfile(weights): + + try: # GitHub + url = 'https://github.com/WongKinYiu/yolor/releases/download/v1.0/' + file + print('Downloading %s to %s...' % (url, weights)) + torch.hub.download_url_to_file(url, weights) + assert os.path.exists(weights) and os.path.getsize(weights) > 1E6 # check + except Exception as e: # GCP + print('ERROR: Download failure.') + print('') + + +def attempt_load(weights, map_location=None): + # Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a + model = Ensemble() + for w in weights if isinstance(weights, list) else [weights]: + attempt_download(w) + model.append(torch.load(w, map_location=map_location)['model'].float().fuse().eval()) # load FP32 model + + if len(model) == 1: + return model[-1] # return model + else: + print('Ensemble created with %s\n' % weights) + for k in ['names', 'stride']: + setattr(model, k, getattr(model[-1], k)) + return model # return ensemble + + +def gdrive_download(id='1n_oKgR81BJtqk75b00eAjdv03qVCQn2f', name='coco128.zip'): + # Downloads a file from Google Drive. from utils.google_utils import *; gdrive_download() + t = time.time() + + print('Downloading https://drive.google.com/uc?export=download&id=%s as %s... ' % (id, name), end='') + os.remove(name) if os.path.exists(name) else None # remove existing + os.remove('cookie') if os.path.exists('cookie') else None + + # Attempt file download + out = "NUL" if platform.system() == "Windows" else "/dev/null" + os.system('curl -c ./cookie -s -L "drive.google.com/uc?export=download&id=%s" > %s ' % (id, out)) + if os.path.exists('cookie'): # large file + s = 'curl -Lb ./cookie "drive.google.com/uc?export=download&confirm=%s&id=%s" -o %s' % (get_token(), id, name) + else: # small file + s = 'curl -s -L -o %s "drive.google.com/uc?export=download&id=%s"' % (name, id) + r = os.system(s) # execute, capture return + os.remove('cookie') if os.path.exists('cookie') else None + + # Error check + if r != 0: + os.remove(name) if os.path.exists(name) else None # remove partial + print('Download error ') # raise Exception('Download error') + return r + + # Unzip if archive + if name.endswith('.zip'): + print('unzipping... ', end='') + os.system('unzip -q %s' % name) # unzip + os.remove(name) # remove zip to free space + + print('Done (%.1fs)' % (time.time() - t)) + return r + + +def get_token(cookie="./cookie"): + with open(cookie) as f: + for line in f: + if "download" in line: + return line.split()[-1] + return "" + +# def upload_blob(bucket_name, source_file_name, destination_blob_name): +# # Uploads a file to a bucket +# # https://cloud.google.com/storage/docs/uploading-objects#storage-upload-object-python +# +# storage_client = storage.Client() +# bucket = storage_client.get_bucket(bucket_name) +# blob = bucket.blob(destination_blob_name) +# +# blob.upload_from_filename(source_file_name) +# +# print('File {} uploaded to {}.'.format( +# source_file_name, +# destination_blob_name)) +# +# +# def download_blob(bucket_name, source_blob_name, destination_file_name): +# # Uploads a blob from a bucket +# storage_client = storage.Client() +# bucket = storage_client.get_bucket(bucket_name) +# blob = bucket.blob(source_blob_name) +# +# blob.download_to_filename(destination_file_name) +# +# print('Blob {} downloaded to {}.'.format( +# source_blob_name, +# destination_file_name)) diff --git a/PyTorch/contrib/cv/detection/YOLOR/utils/layers.py b/PyTorch/contrib/cv/detection/YOLOR/utils/layers.py index a0dfadae46..de842fc4aa 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/utils/layers.py +++ b/PyTorch/contrib/cv/detection/YOLOR/utils/layers.py @@ -1,548 +1,548 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch.nn.functional as F - -from utils.general import * - -import torch -from torch import nn - -try: - from mish_cuda import MishCuda as Mish - -except: - class Mish(nn.Module): # https://github.com/digantamisra98/Mish - def forward(self, x): - return x * F.softplus(x).tanh() - -try: - from pytorch_wavelets import DWTForward, DWTInverse - - class DWT(nn.Module): - def __init__(self): - super(DWT, self).__init__() - self.xfm = DWTForward(J=1, wave='db1', mode='zero') - - def forward(self, x): - b,c,w,h = x.shape - yl, yh = self.xfm(x) - return torch.cat([yl/2., yh[0].view(b,-1,w//2,h//2)/2.+.5], 1) - -except: # using Reorg instead - class DWT(nn.Module): - def forward(self, x): - return torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1) - - -class Reorg(nn.Module): - def forward(self, x): - return torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1) - - -def make_divisible(v, divisor): - # Function ensures all layers have a channel number that is divisible by 8 - # https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py - return math.ceil(v / divisor) * divisor - - -class Flatten(nn.Module): - # Use after nn.AdaptiveAvgPool2d(1) to remove last 2 dimensions - def forward(self, x): - return x.view(x.size(0), -1) - - -class Concat(nn.Module): - # Concatenate a list of tensors along dimension - def __init__(self, dimension=1): - super(Concat, self).__init__() - self.d = dimension - - def forward(self, x): - return torch.cat(x, self.d) - - -class FeatureConcat(nn.Module): - def __init__(self, layers): - super(FeatureConcat, self).__init__() - self.layers = layers # layer indices - self.multiple = len(layers) > 1 # multiple layers flag - - def forward(self, x, outputs): - return torch.cat([outputs[i] for i in self.layers], 1) if self.multiple else outputs[self.layers[0]] - - -class FeatureConcat2(nn.Module): - def __init__(self, layers): - super(FeatureConcat2, self).__init__() - self.layers = layers # layer indices - self.multiple = len(layers) > 1 # multiple layers flag - - def forward(self, x, outputs): - return torch.cat([outputs[self.layers[0]], outputs[self.layers[1]].detach()], 1) - - -class FeatureConcat3(nn.Module): - def __init__(self, layers): - super(FeatureConcat3, self).__init__() - self.layers = layers # layer indices - self.multiple = len(layers) > 1 # multiple layers flag - - def forward(self, x, outputs): - return torch.cat([outputs[self.layers[0]], outputs[self.layers[1]].detach(), outputs[self.layers[2]].detach()], 1) - - -class FeatureConcat_l(nn.Module): - def __init__(self, layers): - super(FeatureConcat_l, self).__init__() - self.layers = layers # layer indices - self.multiple = len(layers) > 1 # multiple layers flag - - def forward(self, x, outputs): - return torch.cat([outputs[i][:,:outputs[i].shape[1]//2,:,:] for i in self.layers], 1) if self.multiple else outputs[self.layers[0]][:,:outputs[self.layers[0]].shape[1]//2,:,:] - - -class WeightedFeatureFusion(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 - def __init__(self, layers, weight=False): - super(WeightedFeatureFusion, self).__init__() - self.layers = layers # layer indices - self.weight = weight # apply weights boolean - self.n = len(layers) + 1 # number of layers - if weight: - self.w = nn.Parameter(torch.zeros(self.n), requires_grad=True) # layer weights - - def forward(self, x, outputs): - # Weights - if self.weight: - w = torch.sigmoid(self.w) * (2 / self.n) # sigmoid weights (0-1) - x = x * w[0] - - # Fusion - nx = x.shape[1] # input channels - for i in range(self.n - 1): - a = outputs[self.layers[i]] * w[i + 1] if self.weight else outputs[self.layers[i]] # feature to add - na = a.shape[1] # feature channels - - # Adjust channels - if nx == na: # same shape - x = x + a - elif nx > na: # slice input - x[:, :na] = x[:, :na] + a # or a = nn.ZeroPad2d((0, 0, 0, 0, 0, dc))(a); x = x + a - else: # slice feature - x = x + a[:, :nx] - - return x - - -class MixConv2d(nn.Module): # MixConv: Mixed Depthwise Convolutional Kernels https://arxiv.org/abs/1907.09595 - def __init__(self, in_ch, out_ch, k=(3, 5, 7), stride=1, dilation=1, bias=True, method='equal_params'): - super(MixConv2d, self).__init__() - - groups = len(k) - if method == 'equal_ch': # equal channels per group - i = torch.linspace(0, groups - 1E-6, out_ch).floor() # out_ch indices - ch = [(i == g).sum() for g in range(groups)] - else: # 'equal_params': equal parameter count per group - b = [out_ch] + [0] * groups - a = np.eye(groups + 1, groups, k=-1) - a -= np.roll(a, 1, axis=1) - a *= np.array(k) ** 2 - a[0] = 1 - ch = np.linalg.lstsq(a, b, rcond=None)[0].round().astype(int) # solve for equal weight indices, ax = b - - self.m = nn.ModuleList([nn.Conv2d(in_channels=in_ch, - out_channels=ch[g], - kernel_size=k[g], - stride=stride, - padding=k[g] // 2, # 'same' pad - dilation=dilation, - bias=bias) for g in range(groups)]) - - def forward(self, x): - return torch.cat([m(x) for m in self.m], 1) - - -# Activation functions below ------------------------------------------------------------------------------------------- -class SwishImplementation(torch.autograd.Function): - @staticmethod - def forward(ctx, x): - ctx.save_for_backward(x) - return x * torch.sigmoid(x) - - @staticmethod - def backward(ctx, grad_output): - x = ctx.saved_tensors[0] - sx = torch.sigmoid(x) # sigmoid(ctx) - return grad_output * (sx * (1 + x * (1 - sx))) - - -class MishImplementation(torch.autograd.Function): - @staticmethod - def forward(ctx, x): - ctx.save_for_backward(x) - return x.mul(torch.tanh(F.softplus(x))) # x * tanh(ln(1 + exp(x))) - - @staticmethod - def backward(ctx, grad_output): - x = ctx.saved_tensors[0] - sx = torch.sigmoid(x) - fx = F.softplus(x).tanh() - return grad_output * (fx + x * sx * (1 - fx * fx)) - - -class MemoryEfficientSwish(nn.Module): - def forward(self, x): - return SwishImplementation.apply(x) - - -class MemoryEfficientMish(nn.Module): - def forward(self, x): - return MishImplementation.apply(x) - - -class Swish(nn.Module): - def forward(self, x): - return x * torch.sigmoid(x) - - -class HardSwish(nn.Module): # https://arxiv.org/pdf/1905.02244.pdf - def forward(self, x): - return x * F.hardtanh(x + 3, 0., 6., True) / 6. - - -class DeformConv2d(nn.Module): - def __init__(self, inc, outc, kernel_size=3, padding=1, stride=1, bias=None, modulation=False): - """ - Args: - modulation (bool, optional): If True, Modulated Defomable Convolution (Deformable ConvNets v2). - """ - super(DeformConv2d, self).__init__() - self.kernel_size = kernel_size - self.padding = padding - self.stride = stride - self.zero_padding = nn.ZeroPad2d(padding) - self.conv = nn.Conv2d(inc, outc, kernel_size=kernel_size, stride=kernel_size, bias=bias) - - self.p_conv = nn.Conv2d(inc, 2*kernel_size*kernel_size, kernel_size=3, padding=1, stride=stride) - nn.init.constant_(self.p_conv.weight, 0) - self.p_conv.register_backward_hook(self._set_lr) - - self.modulation = modulation - if modulation: - self.m_conv = nn.Conv2d(inc, kernel_size*kernel_size, kernel_size=3, padding=1, stride=stride) - nn.init.constant_(self.m_conv.weight, 0) - self.m_conv.register_backward_hook(self._set_lr) - - @staticmethod - def _set_lr(module, grad_input, grad_output): - grad_input = (grad_input[i] * 0.1 for i in range(len(grad_input))) - grad_output = (grad_output[i] * 0.1 for i in range(len(grad_output))) - - def forward(self, x): - offset = self.p_conv(x) - if self.modulation: - m = torch.sigmoid(self.m_conv(x)) - - dtype = offset.data.type() - ks = self.kernel_size - N = offset.size(1) // 2 - - if self.padding: - x = self.zero_padding(x) - - # (b, 2N, h, w) - p = self._get_p(offset, dtype) - - # (b, h, w, 2N) - p = p.contiguous().permute(0, 2, 3, 1) - q_lt = p.detach().floor() - q_rb = q_lt + 1 - - q_lt = torch.cat([torch.clamp(q_lt[..., :N], 0, x.size(2)-1), torch.clamp(q_lt[..., N:], 0, x.size(3)-1)], dim=-1).long() - q_rb = torch.cat([torch.clamp(q_rb[..., :N], 0, x.size(2)-1), torch.clamp(q_rb[..., N:], 0, x.size(3)-1)], dim=-1).long() - q_lb = torch.cat([q_lt[..., :N], q_rb[..., N:]], dim=-1) - q_rt = torch.cat([q_rb[..., :N], q_lt[..., N:]], dim=-1) - - # clip p - p = torch.cat([torch.clamp(p[..., :N], 0, x.size(2)-1), torch.clamp(p[..., N:], 0, x.size(3)-1)], dim=-1) - - # bilinear kernel (b, h, w, N) - g_lt = (1 + (q_lt[..., :N].type_as(p) - p[..., :N])) * (1 + (q_lt[..., N:].type_as(p) - p[..., N:])) - g_rb = (1 - (q_rb[..., :N].type_as(p) - p[..., :N])) * (1 - (q_rb[..., N:].type_as(p) - p[..., N:])) - g_lb = (1 + (q_lb[..., :N].type_as(p) - p[..., :N])) * (1 - (q_lb[..., N:].type_as(p) - p[..., N:])) - g_rt = (1 - (q_rt[..., :N].type_as(p) - p[..., :N])) * (1 + (q_rt[..., N:].type_as(p) - p[..., N:])) - - # (b, c, h, w, N) - x_q_lt = self._get_x_q(x, q_lt, N) - x_q_rb = self._get_x_q(x, q_rb, N) - x_q_lb = self._get_x_q(x, q_lb, N) - x_q_rt = self._get_x_q(x, q_rt, N) - - # (b, c, h, w, N) - x_offset = g_lt.unsqueeze(dim=1) * x_q_lt + \ - g_rb.unsqueeze(dim=1) * x_q_rb + \ - g_lb.unsqueeze(dim=1) * x_q_lb + \ - g_rt.unsqueeze(dim=1) * x_q_rt - - # modulation - if self.modulation: - m = m.contiguous().permute(0, 2, 3, 1) - m = m.unsqueeze(dim=1) - m = torch.cat([m for _ in range(x_offset.size(1))], dim=1) - x_offset *= m - - x_offset = self._reshape_x_offset(x_offset, ks) - out = self.conv(x_offset) - - return out - - def _get_p_n(self, N, dtype): - p_n_x, p_n_y = torch.meshgrid( - torch.arange(-(self.kernel_size-1)//2, (self.kernel_size-1)//2+1), - torch.arange(-(self.kernel_size-1)//2, (self.kernel_size-1)//2+1)) - # (2N, 1) - p_n = torch.cat([torch.flatten(p_n_x), torch.flatten(p_n_y)], 0) - p_n = p_n.view(1, 2*N, 1, 1).type(dtype) - - return p_n - - def _get_p_0(self, h, w, N, dtype): - p_0_x, p_0_y = torch.meshgrid( - torch.arange(1, h*self.stride+1, self.stride), - torch.arange(1, w*self.stride+1, self.stride)) - p_0_x = torch.flatten(p_0_x).view(1, 1, h, w).repeat(1, N, 1, 1) - p_0_y = torch.flatten(p_0_y).view(1, 1, h, w).repeat(1, N, 1, 1) - p_0 = torch.cat([p_0_x, p_0_y], 1).type(dtype) - - return p_0 - - def _get_p(self, offset, dtype): - N, h, w = offset.size(1)//2, offset.size(2), offset.size(3) - - # (1, 2N, 1, 1) - p_n = self._get_p_n(N, dtype) - # (1, 2N, h, w) - p_0 = self._get_p_0(h, w, N, dtype) - p = p_0 + p_n + offset - return p - - def _get_x_q(self, x, q, N): - b, h, w, _ = q.size() - padded_w = x.size(3) - c = x.size(1) - # (b, c, h*w) - x = x.contiguous().view(b, c, -1) - - # (b, h, w, N) - index = q[..., :N]*padded_w + q[..., N:] # offset_x*w + offset_y - # (b, c, h*w*N) - index = index.contiguous().unsqueeze(dim=1).expand(-1, c, -1, -1, -1).contiguous().view(b, c, -1) - - x_offset = x.gather(dim=-1, index=index).contiguous().view(b, c, h, w, N) - - return x_offset - - @staticmethod - def _reshape_x_offset(x_offset, ks): - b, c, h, w, N = x_offset.size() - x_offset = torch.cat([x_offset[..., s:s+ks].contiguous().view(b, c, h, w*ks) for s in range(0, N, ks)], dim=-1) - x_offset = x_offset.contiguous().view(b, c, h*ks, w*ks) - - return x_offset - - -class GAP(nn.Module): - def __init__(self): - super(GAP, self).__init__() - self.avg_pool = nn.AdaptiveAvgPool2d(1) - def forward(self, x): - #b, c, _, _ = x.size() - return self.avg_pool(x)#.view(b, c) - - -class Silence(nn.Module): - def __init__(self): - super(Silence, self).__init__() - def forward(self, x): - return x - - -class ScaleChannel(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 - def __init__(self, layers): - super(ScaleChannel, self).__init__() - self.layers = layers # layer indices - - def forward(self, x, outputs): - a = outputs[self.layers[0]] - return x.expand_as(a) * a - - -class ShiftChannel(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 - def __init__(self, layers): - super(ShiftChannel, self).__init__() - self.layers = layers # layer indices - - def forward(self, x, outputs): - a = outputs[self.layers[0]] - return a.expand_as(x) + x - - -class ShiftChannel2D(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 - def __init__(self, layers): - super(ShiftChannel2D, self).__init__() - self.layers = layers # layer indices - - def forward(self, x, outputs): - a = outputs[self.layers[0]].view(1,-1,1,1) - return a.expand_as(x) + x - - -class ControlChannel(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 - def __init__(self, layers): - super(ControlChannel, self).__init__() - self.layers = layers # layer indices - - def forward(self, x, outputs): - a = outputs[self.layers[0]] - return a.expand_as(x) * x - - -class ControlChannel2D(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 - def __init__(self, layers): - super(ControlChannel2D, self).__init__() - self.layers = layers # layer indices - - def forward(self, x, outputs): - a = outputs[self.layers[0]].view(1,-1,1,1) - return a.expand_as(x) * x - - -class AlternateChannel(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 - def __init__(self, layers): - super(AlternateChannel, self).__init__() - self.layers = layers # layer indices - - def forward(self, x, outputs): - a = outputs[self.layers[0]] - return torch.cat([a.expand_as(x), x], dim=1) - - -class AlternateChannel2D(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 - def __init__(self, layers): - super(AlternateChannel2D, self).__init__() - self.layers = layers # layer indices - - def forward(self, x, outputs): - a = outputs[self.layers[0]].view(1,-1,1,1) - return torch.cat([a.expand_as(x), x], dim=1) - - -class SelectChannel(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 - def __init__(self, layers): - super(SelectChannel, self).__init__() - self.layers = layers # layer indices - - def forward(self, x, outputs): - a = outputs[self.layers[0]] - return a.sigmoid().expand_as(x) * x - - -class SelectChannel2D(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 - def __init__(self, layers): - super(SelectChannel2D, self).__init__() - self.layers = layers # layer indices - - def forward(self, x, outputs): - a = outputs[self.layers[0]].view(1,-1,1,1) - return a.sigmoid().expand_as(x) * x - - -class ScaleSpatial(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 - def __init__(self, layers): - super(ScaleSpatial, self).__init__() - self.layers = layers # layer indices - - def forward(self, x, outputs): - a = outputs[self.layers[0]] - return x * a - - -class ImplicitA(nn.Module): - def __init__(self, channel): - super(ImplicitA, self).__init__() - self.channel = channel - self.implicit = nn.Parameter(torch.zeros(1, channel, 1, 1)) - nn.init.normal_(self.implicit, std=.02) - - def forward(self): - return self.implicit - - -class ImplicitC(nn.Module): - def __init__(self, channel): - super(ImplicitC, self).__init__() - self.channel = channel - self.implicit = nn.Parameter(torch.zeros(1, channel, 1, 1)) - nn.init.normal_(self.implicit, std=.02) - - def forward(self): - return self.implicit - - -class ImplicitM(nn.Module): - def __init__(self, channel): - super(ImplicitM, self).__init__() - self.channel = channel - self.implicit = nn.Parameter(torch.ones(1, channel, 1, 1)) - nn.init.normal_(self.implicit, mean=1., std=.02) - - def forward(self): - return self.implicit - - - -class Implicit2DA(nn.Module): - def __init__(self, atom, channel): - super(Implicit2DA, self).__init__() - self.channel = channel - self.implicit = nn.Parameter(torch.zeros(1, atom, channel, 1)) - nn.init.normal_(self.implicit, std=.02) - - def forward(self): - return self.implicit - - -class Implicit2DC(nn.Module): - def __init__(self, atom, channel): - super(Implicit2DC, self).__init__() - self.channel = channel - self.implicit = nn.Parameter(torch.zeros(1, atom, channel, 1)) - nn.init.normal_(self.implicit, std=.02) - - def forward(self): - return self.implicit - - -class Implicit2DM(nn.Module): - def __init__(self, atom, channel): - super(Implicit2DM, self).__init__() - self.channel = channel - self.implicit = nn.Parameter(torch.ones(1, atom, channel, 1)) - nn.init.normal_(self.implicit, mean=1., std=.02) - - def forward(self): - return self.implicit - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch.nn.functional as F + +from utils.general import * + +import torch +from torch import nn + +try: + from mish_cuda import MishCuda as Mish + +except: + class Mish(nn.Module): # https://github.com/digantamisra98/Mish + def forward(self, x): + return x * F.softplus(x).tanh() + +try: + from pytorch_wavelets import DWTForward, DWTInverse + + class DWT(nn.Module): + def __init__(self): + super(DWT, self).__init__() + self.xfm = DWTForward(J=1, wave='db1', mode='zero') + + def forward(self, x): + b,c,w,h = x.shape + yl, yh = self.xfm(x) + return torch.cat([yl/2., yh[0].view(b,-1,w//2,h//2)/2.+.5], 1) + +except: # using Reorg instead + class DWT(nn.Module): + def forward(self, x): + return torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1) + + +class Reorg(nn.Module): + def forward(self, x): + return torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1) + + +def make_divisible(v, divisor): + # Function ensures all layers have a channel number that is divisible by 8 + # https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py + return math.ceil(v / divisor) * divisor + + +class Flatten(nn.Module): + # Use after nn.AdaptiveAvgPool2d(1) to remove last 2 dimensions + def forward(self, x): + return x.view(x.size(0), -1) + + +class Concat(nn.Module): + # Concatenate a list of tensors along dimension + def __init__(self, dimension=1): + super(Concat, self).__init__() + self.d = dimension + + def forward(self, x): + return torch.cat(x, self.d) + + +class FeatureConcat(nn.Module): + def __init__(self, layers): + super(FeatureConcat, self).__init__() + self.layers = layers # layer indices + self.multiple = len(layers) > 1 # multiple layers flag + + def forward(self, x, outputs): + return torch.cat([outputs[i] for i in self.layers], 1) if self.multiple else outputs[self.layers[0]] + + +class FeatureConcat2(nn.Module): + def __init__(self, layers): + super(FeatureConcat2, self).__init__() + self.layers = layers # layer indices + self.multiple = len(layers) > 1 # multiple layers flag + + def forward(self, x, outputs): + return torch.cat([outputs[self.layers[0]], outputs[self.layers[1]].detach()], 1) + + +class FeatureConcat3(nn.Module): + def __init__(self, layers): + super(FeatureConcat3, self).__init__() + self.layers = layers # layer indices + self.multiple = len(layers) > 1 # multiple layers flag + + def forward(self, x, outputs): + return torch.cat([outputs[self.layers[0]], outputs[self.layers[1]].detach(), outputs[self.layers[2]].detach()], 1) + + +class FeatureConcat_l(nn.Module): + def __init__(self, layers): + super(FeatureConcat_l, self).__init__() + self.layers = layers # layer indices + self.multiple = len(layers) > 1 # multiple layers flag + + def forward(self, x, outputs): + return torch.cat([outputs[i][:,:outputs[i].shape[1]//2,:,:] for i in self.layers], 1) if self.multiple else outputs[self.layers[0]][:,:outputs[self.layers[0]].shape[1]//2,:,:] + + +class WeightedFeatureFusion(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 + def __init__(self, layers, weight=False): + super(WeightedFeatureFusion, self).__init__() + self.layers = layers # layer indices + self.weight = weight # apply weights boolean + self.n = len(layers) + 1 # number of layers + if weight: + self.w = nn.Parameter(torch.zeros(self.n), requires_grad=True) # layer weights + + def forward(self, x, outputs): + # Weights + if self.weight: + w = torch.sigmoid(self.w) * (2 / self.n) # sigmoid weights (0-1) + x = x * w[0] + + # Fusion + nx = x.shape[1] # input channels + for i in range(self.n - 1): + a = outputs[self.layers[i]] * w[i + 1] if self.weight else outputs[self.layers[i]] # feature to add + na = a.shape[1] # feature channels + + # Adjust channels + if nx == na: # same shape + x = x + a + elif nx > na: # slice input + x[:, :na] = x[:, :na] + a # or a = nn.ZeroPad2d((0, 0, 0, 0, 0, dc))(a); x = x + a + else: # slice feature + x = x + a[:, :nx] + + return x + + +class MixConv2d(nn.Module): # MixConv: Mixed Depthwise Convolutional Kernels https://arxiv.org/abs/1907.09595 + def __init__(self, in_ch, out_ch, k=(3, 5, 7), stride=1, dilation=1, bias=True, method='equal_params'): + super(MixConv2d, self).__init__() + + groups = len(k) + if method == 'equal_ch': # equal channels per group + i = torch.linspace(0, groups - 1E-6, out_ch).floor() # out_ch indices + ch = [(i == g).sum() for g in range(groups)] + else: # 'equal_params': equal parameter count per group + b = [out_ch] + [0] * groups + a = np.eye(groups + 1, groups, k=-1) + a -= np.roll(a, 1, axis=1) + a *= np.array(k) ** 2 + a[0] = 1 + ch = np.linalg.lstsq(a, b, rcond=None)[0].round().astype(int) # solve for equal weight indices, ax = b + + self.m = nn.ModuleList([nn.Conv2d(in_channels=in_ch, + out_channels=ch[g], + kernel_size=k[g], + stride=stride, + padding=k[g] // 2, # 'same' pad + dilation=dilation, + bias=bias) for g in range(groups)]) + + def forward(self, x): + return torch.cat([m(x) for m in self.m], 1) + + +# Activation functions below ------------------------------------------------------------------------------------------- +class SwishImplementation(torch.autograd.Function): + @staticmethod + def forward(ctx, x): + ctx.save_for_backward(x) + return x * torch.sigmoid(x) + + @staticmethod + def backward(ctx, grad_output): + x = ctx.saved_tensors[0] + sx = torch.sigmoid(x) # sigmoid(ctx) + return grad_output * (sx * (1 + x * (1 - sx))) + + +class MishImplementation(torch.autograd.Function): + @staticmethod + def forward(ctx, x): + ctx.save_for_backward(x) + return x.mul(torch.tanh(F.softplus(x))) # x * tanh(ln(1 + exp(x))) + + @staticmethod + def backward(ctx, grad_output): + x = ctx.saved_tensors[0] + sx = torch.sigmoid(x) + fx = F.softplus(x).tanh() + return grad_output * (fx + x * sx * (1 - fx * fx)) + + +class MemoryEfficientSwish(nn.Module): + def forward(self, x): + return SwishImplementation.apply(x) + + +class MemoryEfficientMish(nn.Module): + def forward(self, x): + return MishImplementation.apply(x) + + +class Swish(nn.Module): + def forward(self, x): + return x * torch.sigmoid(x) + + +class HardSwish(nn.Module): # https://arxiv.org/pdf/1905.02244.pdf + def forward(self, x): + return x * F.hardtanh(x + 3, 0., 6., True) / 6. + + +class DeformConv2d(nn.Module): + def __init__(self, inc, outc, kernel_size=3, padding=1, stride=1, bias=None, modulation=False): + """ + Args: + modulation (bool, optional): If True, Modulated Defomable Convolution (Deformable ConvNets v2). + """ + super(DeformConv2d, self).__init__() + self.kernel_size = kernel_size + self.padding = padding + self.stride = stride + self.zero_padding = nn.ZeroPad2d(padding) + self.conv = nn.Conv2d(inc, outc, kernel_size=kernel_size, stride=kernel_size, bias=bias) + + self.p_conv = nn.Conv2d(inc, 2*kernel_size*kernel_size, kernel_size=3, padding=1, stride=stride) + nn.init.constant_(self.p_conv.weight, 0) + self.p_conv.register_backward_hook(self._set_lr) + + self.modulation = modulation + if modulation: + self.m_conv = nn.Conv2d(inc, kernel_size*kernel_size, kernel_size=3, padding=1, stride=stride) + nn.init.constant_(self.m_conv.weight, 0) + self.m_conv.register_backward_hook(self._set_lr) + + @staticmethod + def _set_lr(module, grad_input, grad_output): + grad_input = (grad_input[i] * 0.1 for i in range(len(grad_input))) + grad_output = (grad_output[i] * 0.1 for i in range(len(grad_output))) + + def forward(self, x): + offset = self.p_conv(x) + if self.modulation: + m = torch.sigmoid(self.m_conv(x)) + + dtype = offset.data.type() + ks = self.kernel_size + N = offset.size(1) // 2 + + if self.padding: + x = self.zero_padding(x) + + # (b, 2N, h, w) + p = self._get_p(offset, dtype) + + # (b, h, w, 2N) + p = p.contiguous().permute(0, 2, 3, 1) + q_lt = p.detach().floor() + q_rb = q_lt + 1 + + q_lt = torch.cat([torch.clamp(q_lt[..., :N], 0, x.size(2)-1), torch.clamp(q_lt[..., N:], 0, x.size(3)-1)], dim=-1).long() + q_rb = torch.cat([torch.clamp(q_rb[..., :N], 0, x.size(2)-1), torch.clamp(q_rb[..., N:], 0, x.size(3)-1)], dim=-1).long() + q_lb = torch.cat([q_lt[..., :N], q_rb[..., N:]], dim=-1) + q_rt = torch.cat([q_rb[..., :N], q_lt[..., N:]], dim=-1) + + # clip p + p = torch.cat([torch.clamp(p[..., :N], 0, x.size(2)-1), torch.clamp(p[..., N:], 0, x.size(3)-1)], dim=-1) + + # bilinear kernel (b, h, w, N) + g_lt = (1 + (q_lt[..., :N].type_as(p) - p[..., :N])) * (1 + (q_lt[..., N:].type_as(p) - p[..., N:])) + g_rb = (1 - (q_rb[..., :N].type_as(p) - p[..., :N])) * (1 - (q_rb[..., N:].type_as(p) - p[..., N:])) + g_lb = (1 + (q_lb[..., :N].type_as(p) - p[..., :N])) * (1 - (q_lb[..., N:].type_as(p) - p[..., N:])) + g_rt = (1 - (q_rt[..., :N].type_as(p) - p[..., :N])) * (1 + (q_rt[..., N:].type_as(p) - p[..., N:])) + + # (b, c, h, w, N) + x_q_lt = self._get_x_q(x, q_lt, N) + x_q_rb = self._get_x_q(x, q_rb, N) + x_q_lb = self._get_x_q(x, q_lb, N) + x_q_rt = self._get_x_q(x, q_rt, N) + + # (b, c, h, w, N) + x_offset = g_lt.unsqueeze(dim=1) * x_q_lt + \ + g_rb.unsqueeze(dim=1) * x_q_rb + \ + g_lb.unsqueeze(dim=1) * x_q_lb + \ + g_rt.unsqueeze(dim=1) * x_q_rt + + # modulation + if self.modulation: + m = m.contiguous().permute(0, 2, 3, 1) + m = m.unsqueeze(dim=1) + m = torch.cat([m for _ in range(x_offset.size(1))], dim=1) + x_offset *= m + + x_offset = self._reshape_x_offset(x_offset, ks) + out = self.conv(x_offset) + + return out + + def _get_p_n(self, N, dtype): + p_n_x, p_n_y = torch.meshgrid( + torch.arange(-(self.kernel_size-1)//2, (self.kernel_size-1)//2+1), + torch.arange(-(self.kernel_size-1)//2, (self.kernel_size-1)//2+1)) + # (2N, 1) + p_n = torch.cat([torch.flatten(p_n_x), torch.flatten(p_n_y)], 0) + p_n = p_n.view(1, 2*N, 1, 1).type(dtype) + + return p_n + + def _get_p_0(self, h, w, N, dtype): + p_0_x, p_0_y = torch.meshgrid( + torch.arange(1, h*self.stride+1, self.stride), + torch.arange(1, w*self.stride+1, self.stride)) + p_0_x = torch.flatten(p_0_x).view(1, 1, h, w).repeat(1, N, 1, 1) + p_0_y = torch.flatten(p_0_y).view(1, 1, h, w).repeat(1, N, 1, 1) + p_0 = torch.cat([p_0_x, p_0_y], 1).type(dtype) + + return p_0 + + def _get_p(self, offset, dtype): + N, h, w = offset.size(1)//2, offset.size(2), offset.size(3) + + # (1, 2N, 1, 1) + p_n = self._get_p_n(N, dtype) + # (1, 2N, h, w) + p_0 = self._get_p_0(h, w, N, dtype) + p = p_0 + p_n + offset + return p + + def _get_x_q(self, x, q, N): + b, h, w, _ = q.size() + padded_w = x.size(3) + c = x.size(1) + # (b, c, h*w) + x = x.contiguous().view(b, c, -1) + + # (b, h, w, N) + index = q[..., :N]*padded_w + q[..., N:] # offset_x*w + offset_y + # (b, c, h*w*N) + index = index.contiguous().unsqueeze(dim=1).expand(-1, c, -1, -1, -1).contiguous().view(b, c, -1) + + x_offset = x.gather(dim=-1, index=index).contiguous().view(b, c, h, w, N) + + return x_offset + + @staticmethod + def _reshape_x_offset(x_offset, ks): + b, c, h, w, N = x_offset.size() + x_offset = torch.cat([x_offset[..., s:s+ks].contiguous().view(b, c, h, w*ks) for s in range(0, N, ks)], dim=-1) + x_offset = x_offset.contiguous().view(b, c, h*ks, w*ks) + + return x_offset + + +class GAP(nn.Module): + def __init__(self): + super(GAP, self).__init__() + self.avg_pool = nn.AdaptiveAvgPool2d(1) + def forward(self, x): + #b, c, _, _ = x.size() + return self.avg_pool(x)#.view(b, c) + + +class Silence(nn.Module): + def __init__(self): + super(Silence, self).__init__() + def forward(self, x): + return x + + +class ScaleChannel(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 + def __init__(self, layers): + super(ScaleChannel, self).__init__() + self.layers = layers # layer indices + + def forward(self, x, outputs): + a = outputs[self.layers[0]] + return x.expand_as(a) * a + + +class ShiftChannel(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 + def __init__(self, layers): + super(ShiftChannel, self).__init__() + self.layers = layers # layer indices + + def forward(self, x, outputs): + a = outputs[self.layers[0]] + return a.expand_as(x) + x + + +class ShiftChannel2D(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 + def __init__(self, layers): + super(ShiftChannel2D, self).__init__() + self.layers = layers # layer indices + + def forward(self, x, outputs): + a = outputs[self.layers[0]].view(1,-1,1,1) + return a.expand_as(x) + x + + +class ControlChannel(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 + def __init__(self, layers): + super(ControlChannel, self).__init__() + self.layers = layers # layer indices + + def forward(self, x, outputs): + a = outputs[self.layers[0]] + return a.expand_as(x) * x + + +class ControlChannel2D(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 + def __init__(self, layers): + super(ControlChannel2D, self).__init__() + self.layers = layers # layer indices + + def forward(self, x, outputs): + a = outputs[self.layers[0]].view(1,-1,1,1) + return a.expand_as(x) * x + + +class AlternateChannel(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 + def __init__(self, layers): + super(AlternateChannel, self).__init__() + self.layers = layers # layer indices + + def forward(self, x, outputs): + a = outputs[self.layers[0]] + return torch.cat([a.expand_as(x), x], dim=1) + + +class AlternateChannel2D(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 + def __init__(self, layers): + super(AlternateChannel2D, self).__init__() + self.layers = layers # layer indices + + def forward(self, x, outputs): + a = outputs[self.layers[0]].view(1,-1,1,1) + return torch.cat([a.expand_as(x), x], dim=1) + + +class SelectChannel(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 + def __init__(self, layers): + super(SelectChannel, self).__init__() + self.layers = layers # layer indices + + def forward(self, x, outputs): + a = outputs[self.layers[0]] + return a.sigmoid().expand_as(x) * x + + +class SelectChannel2D(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 + def __init__(self, layers): + super(SelectChannel2D, self).__init__() + self.layers = layers # layer indices + + def forward(self, x, outputs): + a = outputs[self.layers[0]].view(1,-1,1,1) + return a.sigmoid().expand_as(x) * x + + +class ScaleSpatial(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 + def __init__(self, layers): + super(ScaleSpatial, self).__init__() + self.layers = layers # layer indices + + def forward(self, x, outputs): + a = outputs[self.layers[0]] + return x * a + + +class ImplicitA(nn.Module): + def __init__(self, channel): + super(ImplicitA, self).__init__() + self.channel = channel + self.implicit = nn.Parameter(torch.zeros(1, channel, 1, 1)) + nn.init.normal_(self.implicit, std=.02) + + def forward(self): + return self.implicit + + +class ImplicitC(nn.Module): + def __init__(self, channel): + super(ImplicitC, self).__init__() + self.channel = channel + self.implicit = nn.Parameter(torch.zeros(1, channel, 1, 1)) + nn.init.normal_(self.implicit, std=.02) + + def forward(self): + return self.implicit + + +class ImplicitM(nn.Module): + def __init__(self, channel): + super(ImplicitM, self).__init__() + self.channel = channel + self.implicit = nn.Parameter(torch.ones(1, channel, 1, 1)) + nn.init.normal_(self.implicit, mean=1., std=.02) + + def forward(self): + return self.implicit + + + +class Implicit2DA(nn.Module): + def __init__(self, atom, channel): + super(Implicit2DA, self).__init__() + self.channel = channel + self.implicit = nn.Parameter(torch.zeros(1, atom, channel, 1)) + nn.init.normal_(self.implicit, std=.02) + + def forward(self): + return self.implicit + + +class Implicit2DC(nn.Module): + def __init__(self, atom, channel): + super(Implicit2DC, self).__init__() + self.channel = channel + self.implicit = nn.Parameter(torch.zeros(1, atom, channel, 1)) + nn.init.normal_(self.implicit, std=.02) + + def forward(self): + return self.implicit + + +class Implicit2DM(nn.Module): + def __init__(self, atom, channel): + super(Implicit2DM, self).__init__() + self.channel = channel + self.implicit = nn.Parameter(torch.ones(1, atom, channel, 1)) + nn.init.normal_(self.implicit, mean=1., std=.02) + + def forward(self): + return self.implicit + + \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/YOLOR/utils/loss.py b/PyTorch/contrib/cv/detection/YOLOR/utils/loss.py index 9d2d3db087..b3f75fb94d 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/utils/loss.py +++ b/PyTorch/contrib/cv/detection/YOLOR/utils/loss.py @@ -1,356 +1,356 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -# Loss functions - -import torch -import torch.nn as nn - -from utils.general import bbox_iou -from utils.torch_utils import is_parallel - - -def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#issuecomment-598028441 - # return positive, negative label smoothing BCE targets - return 1.0 - 0.5 * eps, 0.5 * eps - - -class BCEBlurWithLogitsLoss(nn.Module): - # BCEwithLogitLoss() with reduced missing label effects. - def __init__(self, alpha=0.05): - super(BCEBlurWithLogitsLoss, self).__init__() - self.loss_fcn = nn.BCEWithLogitsLoss(reduction='none') # must be nn.BCEWithLogitsLoss() - self.alpha = alpha - - def forward(self, pred, true): - loss = self.loss_fcn(pred, true) - pred = torch.sigmoid(pred) # prob from logits - dx = pred - true # reduce only missing label effects - # dx = (pred - true).abs() # reduce missing label and false label effects - alpha_factor = 1 - torch.exp((dx - 1) / (self.alpha + 1e-4)) - loss *= alpha_factor - return loss.mean() - -class FocalLoss(nn.Module): - # Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) - def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): - super(FocalLoss, self).__init__() - self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() - self.gamma = gamma - self.alpha = alpha - self.reduction = loss_fcn.reduction - self.loss_fcn.reduction = 'none' # required to apply FL to each element - - def forward(self, pred, true): - loss = self.loss_fcn(pred, true) - # p_t = torch.exp(-loss) - # loss *= self.alpha * (1.000001 - p_t) ** self.gamma # non-zero power for gradient stability - - # TF implementation https://github.com/tensorflow/addons/blob/v0.7.1/tensorflow_addons/losses/focal_loss.py - pred_prob = torch.sigmoid(pred) # prob from logits - p_t = true * pred_prob + (1 - true) * (1 - pred_prob) - alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha) - modulating_factor = (1.0 - p_t) ** self.gamma - loss *= alpha_factor * modulating_factor - - if self.reduction == 'mean': - return loss.mean() - elif self.reduction == 'sum': - return loss.sum() - else: # 'none' - return loss - - -class DeterministicIndex(torch.autograd.Function): - @staticmethod - def forward(ctx, x, indices_list): - ctx.x = x - ctx.indices_list = indices_list - return x[indices_list[0], indices_list[1], :, indices_list[2], indices_list[3]] - - @staticmethod - def backward(ctx, grad_output): - tmp = torch.zeros_like(ctx.x) - ind0, ind1, ind2, ind3 = ctx.indices_list - tmp[ind0, ind1, :, ind2, ind3] = grad_output - return tmp, None - - -# @torchsnooper.snoop(output='/data/wyh/yolor/yolorDebug_1P640.txt') -def compute_loss(p, targets, model): # predictions, targets, model - device = targets.device - - targets = targets.T - for i in range(len(p)): - p[i] = p[i].permute(0, 1, 4, 2, 3) #(6, 3, 80, 80, 85)->(6, 3, 85, 80, 80) - - ft = torch.cuda.FloatTensor if p[0].is_cuda else torch.Tensor - lcls, lbox, lobj = ft([0]).to(device), ft([0]).to(device), ft([0]).to(device) - tcls, tbox, indices, anchors, targets_mask, targets_sum_mask = build_targets(p, targets, model) # targets - h = model.hyp # hyperparameters - - # Define criteria - BCEcls = nn.BCEWithLogitsLoss(pos_weight=ft([h['cls_pw']]), reduction='sum').to(device) - BCEobj = nn.BCEWithLogitsLoss(pos_weight=ft([h['obj_pw']]), reduction='mean').to(device) - - # class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 - cp, cn = smooth_BCE(eps=0.0) - - # Focal loss - g = h['fl_gamma'] # focal loss gamma - if g > 0: - BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g) - - # per output - nt = 0 # number of targets - np = len(p) # number of outputs - balance = [4.0, 1.0, 0.4] if np == 3 else [4.0, 1.0, 0.4, 0.1] # P3-5 or P3-6 - balance = [4.0, 1.0, 0.5, 0.4, 0.1] if np == 5 else balance - for i, pi in enumerate(p): # layer index, layer predictions - b, a, gj, gi = indices[i] # image, anchor, gridy, gridx - allmask = targets_mask[i] - sum_mask = targets_sum_mask[i] - # tobj = torch.zeros_like(pi[..., 0], device=device) # target obj - tobj = torch.zeros_like(pi[:, :, 0, :, :]).to(device) # target obj - - nb = b.shape[0] # number of targets - if sum_mask.item() > 0: - nt += nb # cumulative targets - # ps = pi[b, a,:, gj, gi] # prediction subset corresponding to targets - ps = DeterministicIndex.apply(pi, (b, a, gj, gi)).permute(1, 0).contiguous() - # GIoU - pxy = ps.index_select(0, torch.tensor([0, 1], device=device)) - pwh = ps.index_select(0, torch.tensor([2, 3], device=device)) - - pxy = pxy.sigmoid() * 2. - 0.5 - pwh = (pwh.sigmoid() * 2) ** 2 * (anchors[i].T) - pbox = torch.cat((pxy, pwh), 0) # predicted box - giou = bbox_iou(pbox, tbox[i], x1y1x2y2=False, GIoU=True) - giou = giou * (allmask) + (1. - allmask) - lbox += (1.0 - giou).sum() / (sum_mask) # giou loss - # Obj - giou = giou * (allmask) - tobj[b, a, gj, gi] = (1.0 - model.gr) + model.gr * giou.detach().clamp(0).type(tobj.dtype) # giou ratio - - # Class - if model.nc > 1: # cls loss (only if multiple classes) - tmp = ps[5:, :] - tmp = tmp * (allmask) - (1.- allmask) * 50. - t = torch.full_like(tmp, cn).to(device) # targets - range_nb = torch.arange(nb, device=device).long() - t[tcls[i], range_nb] = cp - - t = t * (allmask) - lcls += (BCEcls(tmp, t) / (sum_mask * t.shape[0]).float()) # BCE - - # Append targets to text file - # with open('targets.txt', 'a') as file: - # [file.write('%11.5g ' * 4 % tuple(x) + '\n') for x in torch.cat((txy[i], twh[i]), 1)] - - # lobj += BCEobj(pi[..., 4], tobj) * balance[i] # obj loss - lobj += BCEobj(pi[:, :, 4, :, :], tobj) * balance[i] # obj loss - - s = 3 / np # output count scaling - lbox *= h['box'] * s - lobj *= h['obj'] * s * (1.4 if np >= 4 else 1.) - lcls *= h['cls'] * s - bs = tobj.shape[0] # batch size - - loss = lbox + lobj + lcls - return loss * bs, torch.cat((lbox, lobj, lcls, loss)).detach() - - -def build_targets(p, targets, model): - # Build targets for compute_loss(), input targets(image,class,x,y,w,h) - na, nt, device, batch_size = 3, targets.shape[1], targets.device, p[0].shape[0] - - # align targets in batch size - nt_max = 32 * batch_size - while nt > nt_max: - nt_max *= 2 - print('**************** nt max=', nt_max) - max_target = torch.zeros(6, nt_max, device=device) # (6, nt) - for i in range(6): - try: - max_target[i, :nt] = targets[i, :] - # print('Check------', max_target.shape, max_target.device, device) - # print('Check------', targets.shape, targets.device, device) - except Exception as e: - print(e) - # print('Check------', max_target.shape, max_target.device, device) - # print('Check------', targets.shape, targets.device, device) - - tcls, tbox, indices, anch, targets_mask, targets_sum_mask = [], [], [], [], [], [] - gain = torch.ones(6, device=device) # normalized to gridspace gain - off_list = [ - torch.tensor([[1.], [0.]], device=device), - torch.tensor([[0.], [1.]], device=device), - torch.tensor([[-1.], [0.]], device=device), - torch.tensor([[0.], [-1.]], device=device) - ] - # # create indices with anchor and max_target - # # anchor tensor, same as .repeat_interleave(nt) (x, 3) - at = torch.arange(na).view(na, 1).repeat(1, nt_max) - a = at.view(-1) - a = torch.cat((a, a, a, a, a), 0) - - g = 0.5 # offset - # multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) - multi_gpu = is_parallel(model) - for i, j in enumerate(model.module.yolo_layers if multi_gpu else model.yolo_layers): - # get number of grid points and anchor vec for this yolo layer - anchors = model.module.module_list[j].anchor_vec if multi_gpu else model.module_list[j].anchor_vec - # iou of targets-anchors b,a,c,y,x-> b,a,y,x,c - # gain[2:] = torch.tensor(p[i].shape)[[3, 2, 3, 2]].float() # xyxy gain - gain[2:] = torch.tensor(p[i].shape)[[4, 3, 4, 3]].float() # xyxy gain - - # Match targets to anchors - t, offsets = max_target * gain[:, None], 0 - allmask = torch.zeros((na * nt_max)).to(device) - sum_mask = torch.zeros((1)).to(device) - if nt: - r = t[None, 4:6, :] / anchors[..., None] # wh ratio - fmask = torch.max(r, 1. / r).max(1)[0] < model.hyp['anchor_t'] # compare - fmask = fmask.view(1, -1) - # j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n) = wh_iou(anchors(3,2), gwh(n,2)) - t = t.repeat(1, 1, na).view(6, -1) # filter - - # overlaps - gxy = t.index_select(0, torch.tensor([2, 3], device=device)) - z = torch.zeros_like(gxy) - - jk = (gxy % 1. < g) & (gxy > 1.) - lm = (gxy % 1. > (1 - g)) & (gxy < (gain[[2, 3]][:, None] - 1.)) - jk, lm = jk&fmask, lm&fmask - allmask = torch.cat((fmask, jk, lm), 0).view(1, -1).float() - t = torch.cat((t, t, t, t, t), 1) - offsets = torch.cat((z, z + off_list[0], z + off_list[1], z + off_list[2], z + off_list[3]), 1) * g - - # print('----------------------------------------------------------------------------------') - # print('a.shape, t.shape:') - # print(a.shape, t.shape) - # print('gxy.shape, offsets.shape') - # print(gxy.shape, offsets.shape) - # print('fmask.shape, allmask.shape, jk, lm:') - # print(fmask.shape, allmask.shape, jk.shape, lm.shape) - # print('----------------------------------------------------------------------------------') - - sum_mask = allmask.sum() - t = t * allmask - - # Define - b = t.index_select(0, torch.tensor([0], device=device)).long().view(-1) #(3072 * 5) - c = t.index_select(0, torch.tensor([1], device=device)).long().view(-1) #(3072 * 5) - gxy = t.index_select(0, torch.tensor([2, 3], device=device)) #(2, 3072 * 5) - gwh = t.index_select(0, torch.tensor([4, 5], device=device)) #(2, 3072 * 5) - gij = gxy - offsets - gij2 = gij.long() - gi = gij2.index_select(0, torch.tensor([0], device=device)).view(-1) #(2, 3072 * 5) - gj = gij2.index_select(0, torch.tensor([1], device=device)).view(-1) #(2, 3072 * 5) - - # Append - # indices.append((b, a, gj.clamp_(0, gain[3] - 1), gi.clamp_(0, gain[2] - 1))) # image, anchor, grid indices - indices.append((b, a, gj, gi)) # image, anchor, grid indices - tbox.append(torch.cat((gxy - gij2.float(), gwh), 0)) # box - anch.append(anchors[a]) # anchors - tcls.append(c) # class - targets_mask.append(allmask) - targets_sum_mask.append(sum_mask) - - return tcls, tbox, indices, anch, targets_mask, targets_sum_mask - -# def build_targets(p, targets, model): -# nt = targets.shape[0] # number of anchors, targets -# tcls, tbox, indices, anch, targets_mask, targets_sum_mask = [], [], [], [], [], [] -# gain = torch.ones(6, device=targets.device) # normalized to gridspace gain -# off = torch.tensor([[1, 0], [0, 1], [-1, 0], [0, -1]], device=targets.device).float() # overlap offsets - -# # align targets in batch size -# batch_size = p[0].shape[0] -# nt_max = 32 * batch_size -# while nt > nt_max: -# nt_max *= 2 -# print('**************** nt max=', nt_max) -# max_target = torch.zeros(nt_max, 6, device=targets.device) # (nt,6) -# for i in range(6): -# max_target[:nt, i] = targets[:, i] - -# g = 0.5 # offset -# multi_gpu = is_parallel(model) -# for i, jj in enumerate(model.module.yolo_layers if multi_gpu else model.yolo_layers): -# # get number of grid points and anchor vec for this yolo layer -# anchors = model.module.module_list[jj].anchor_vec if multi_gpu else model.module_list[jj].anchor_vec -# gain[2:] = torch.tensor(p[i].shape)[[3, 2, 3, 2]] # xyxy gain - -# # Match targets to anchors -# a, t, offsets = [], max_target * gain, 0 - -# if nt: -# na = anchors.shape[0] # number of anchors -# allmask = torch.zeros((na * nt_max)).to(targets.device) -# sum_mask = torch.zeros((1)).to(targets.device) -# at = torch.arange(na).view(na, 1).repeat(1, nt_max) # anchor tensor, same as .repeat_interleave(nt) -# r = t[None, :, 4:6] / anchors[:, None] # wh ratio -# fmask = torch.max(r, 1. / r).max(2)[0] < model.hyp['anchor_t'] # compare -# # j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n) = wh_iou(anchors(3,2), gwh(n,2)) -# a, t = at[fmask], t.repeat(na, 1, 1)[fmask] # filter - -# print('----------------------------------------------------------------------------------') -# print('a.shape, at.shape, t.shape:') -# print(a.shape, at.shape, t.shape) -# print('----------------------------------------------------------------------------------') - -# # overlaps -# gxy = t[:, 2:4] # grid xy -# z = torch.zeros_like(gxy) -# j, k = ((gxy % 1. < g) & (gxy > 1.)).T -# l, m = ((gxy % 1. > (1 - g)) & (gxy < (gain[[2, 3]] - 1.))).T - -# print(a.shape, a[j].shape, a[k].shape, a[l].shape, a[m].shape) -# print(t.shape, t[j].shape, t[k].shape, t[l].shape, t[m].shape) - -# a, t = torch.cat((a, a[j], a[k], a[l], a[m]), 0), torch.cat((t, t[j], t[k], t[l], t[m]), 0) -# offsets = torch.cat((z, z[j] + off[0], z[k] + off[1], z[l] + off[2], z[m] + off[3]), 0) * g - -# allmask = torch.cat((j, k, l, m), 1).float() -# sum_mask = allmask.sum() - -# print('----------------------------------------------------------------------------------') -# print('a.shape, t.shape:') -# print(a.shape, t.shape) -# print('gxy.shape, offsets.shape') -# print(gxy.shape, offsets.shape) -# print('fmask.shape, allmask.shape, j, k, l, m:') -# print(fmask.shape, allmask.shape, j.shape, k.shape, l.shape, m.shape) -# print('----------------------------------------------------------------------------------') - -# t = t * allmask - -# # Define -# b, c = t[:, :2].long().T # image, class -# gxy = t[:, 2:4] # grid xy -# gwh = t[:, 4:6] # grid wh -# gij = (gxy - offsets).long() -# gi, gj = gij.T # grid xy indices - -# # Append -# #indices.append((b, a, gj, gi)) # image, anchor, grid indices -# indices.append((b, a, gj.clamp_(0, gain[3] - 1), gi.clamp_(0, gain[2] - 1))) # image, anchor, grid indices -# tbox.append(torch.cat((gxy - gij, gwh), 1)) # box -# anch.append(anchors[a]) # anchors -# tcls.append(c) # class -# targets_mask.append(allmask) -# targets_sum_mask.append(sum_mask) - -# return tcls, tbox, indices, anch, targets_mask, targets_sum_mask +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +# Loss functions + +import torch +import torch.nn as nn + +from utils.general import bbox_iou +from utils.torch_utils import is_parallel + + +def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#issuecomment-598028441 + # return positive, negative label smoothing BCE targets + return 1.0 - 0.5 * eps, 0.5 * eps + + +class BCEBlurWithLogitsLoss(nn.Module): + # BCEwithLogitLoss() with reduced missing label effects. + def __init__(self, alpha=0.05): + super(BCEBlurWithLogitsLoss, self).__init__() + self.loss_fcn = nn.BCEWithLogitsLoss(reduction='none') # must be nn.BCEWithLogitsLoss() + self.alpha = alpha + + def forward(self, pred, true): + loss = self.loss_fcn(pred, true) + pred = torch.sigmoid(pred) # prob from logits + dx = pred - true # reduce only missing label effects + # dx = (pred - true).abs() # reduce missing label and false label effects + alpha_factor = 1 - torch.exp((dx - 1) / (self.alpha + 1e-4)) + loss *= alpha_factor + return loss.mean() + +class FocalLoss(nn.Module): + # Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) + def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): + super(FocalLoss, self).__init__() + self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() + self.gamma = gamma + self.alpha = alpha + self.reduction = loss_fcn.reduction + self.loss_fcn.reduction = 'none' # required to apply FL to each element + + def forward(self, pred, true): + loss = self.loss_fcn(pred, true) + # p_t = torch.exp(-loss) + # loss *= self.alpha * (1.000001 - p_t) ** self.gamma # non-zero power for gradient stability + + # TF implementation https://github.com/tensorflow/addons/blob/v0.7.1/tensorflow_addons/losses/focal_loss.py + pred_prob = torch.sigmoid(pred) # prob from logits + p_t = true * pred_prob + (1 - true) * (1 - pred_prob) + alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha) + modulating_factor = (1.0 - p_t) ** self.gamma + loss *= alpha_factor * modulating_factor + + if self.reduction == 'mean': + return loss.mean() + elif self.reduction == 'sum': + return loss.sum() + else: # 'none' + return loss + + +class DeterministicIndex(torch.autograd.Function): + @staticmethod + def forward(ctx, x, indices_list): + ctx.x = x + ctx.indices_list = indices_list + return x[indices_list[0], indices_list[1], :, indices_list[2], indices_list[3]] + + @staticmethod + def backward(ctx, grad_output): + tmp = torch.zeros_like(ctx.x) + ind0, ind1, ind2, ind3 = ctx.indices_list + tmp[ind0, ind1, :, ind2, ind3] = grad_output + return tmp, None + + +# @torchsnooper.snoop(output='/data/wyh/yolor/yolorDebug_1P640.txt') +def compute_loss(p, targets, model): # predictions, targets, model + device = targets.device + + targets = targets.T + for i in range(len(p)): + p[i] = p[i].permute(0, 1, 4, 2, 3) #(6, 3, 80, 80, 85)->(6, 3, 85, 80, 80) + + ft = torch.cuda.FloatTensor if p[0].is_cuda else torch.Tensor + lcls, lbox, lobj = ft([0]).to(device), ft([0]).to(device), ft([0]).to(device) + tcls, tbox, indices, anchors, targets_mask, targets_sum_mask = build_targets(p, targets, model) # targets + h = model.hyp # hyperparameters + + # Define criteria + BCEcls = nn.BCEWithLogitsLoss(pos_weight=ft([h['cls_pw']]), reduction='sum').to(device) + BCEobj = nn.BCEWithLogitsLoss(pos_weight=ft([h['obj_pw']]), reduction='mean').to(device) + + # class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 + cp, cn = smooth_BCE(eps=0.0) + + # Focal loss + g = h['fl_gamma'] # focal loss gamma + if g > 0: + BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g) + + # per output + nt = 0 # number of targets + np = len(p) # number of outputs + balance = [4.0, 1.0, 0.4] if np == 3 else [4.0, 1.0, 0.4, 0.1] # P3-5 or P3-6 + balance = [4.0, 1.0, 0.5, 0.4, 0.1] if np == 5 else balance + for i, pi in enumerate(p): # layer index, layer predictions + b, a, gj, gi = indices[i] # image, anchor, gridy, gridx + allmask = targets_mask[i] + sum_mask = targets_sum_mask[i] + # tobj = torch.zeros_like(pi[..., 0], device=device) # target obj + tobj = torch.zeros_like(pi[:, :, 0, :, :]).to(device) # target obj + + nb = b.shape[0] # number of targets + if sum_mask.item() > 0: + nt += nb # cumulative targets + # ps = pi[b, a,:, gj, gi] # prediction subset corresponding to targets + ps = DeterministicIndex.apply(pi, (b, a, gj, gi)).permute(1, 0).contiguous() + # GIoU + pxy = ps.index_select(0, torch.tensor([0, 1], device=device)) + pwh = ps.index_select(0, torch.tensor([2, 3], device=device)) + + pxy = pxy.sigmoid() * 2. - 0.5 + pwh = (pwh.sigmoid() * 2) ** 2 * (anchors[i].T) + pbox = torch.cat((pxy, pwh), 0) # predicted box + giou = bbox_iou(pbox, tbox[i], x1y1x2y2=False, GIoU=True) + giou = giou * (allmask) + (1. - allmask) + lbox += (1.0 - giou).sum() / (sum_mask) # giou loss + # Obj + giou = giou * (allmask) + tobj[b, a, gj, gi] = (1.0 - model.gr) + model.gr * giou.detach().clamp(0).type(tobj.dtype) # giou ratio + + # Class + if model.nc > 1: # cls loss (only if multiple classes) + tmp = ps[5:, :] + tmp = tmp * (allmask) - (1.- allmask) * 50. + t = torch.full_like(tmp, cn).to(device) # targets + range_nb = torch.arange(nb, device=device).long() + t[tcls[i], range_nb] = cp + + t = t * (allmask) + lcls += (BCEcls(tmp, t) / (sum_mask * t.shape[0]).float()) # BCE + + # Append targets to text file + # with open('targets.txt', 'a') as file: + # [file.write('%11.5g ' * 4 % tuple(x) + '\n') for x in torch.cat((txy[i], twh[i]), 1)] + + # lobj += BCEobj(pi[..., 4], tobj) * balance[i] # obj loss + lobj += BCEobj(pi[:, :, 4, :, :], tobj) * balance[i] # obj loss + + s = 3 / np # output count scaling + lbox *= h['box'] * s + lobj *= h['obj'] * s * (1.4 if np >= 4 else 1.) + lcls *= h['cls'] * s + bs = tobj.shape[0] # batch size + + loss = lbox + lobj + lcls + return loss * bs, torch.cat((lbox, lobj, lcls, loss)).detach() + + +def build_targets(p, targets, model): + # Build targets for compute_loss(), input targets(image,class,x,y,w,h) + na, nt, device, batch_size = 3, targets.shape[1], targets.device, p[0].shape[0] + + # align targets in batch size + nt_max = 32 * batch_size + while nt > nt_max: + nt_max *= 2 + print('**************** nt max=', nt_max) + max_target = torch.zeros(6, nt_max, device=device) # (6, nt) + for i in range(6): + try: + max_target[i, :nt] = targets[i, :] + # print('Check------', max_target.shape, max_target.device, device) + # print('Check------', targets.shape, targets.device, device) + except Exception as e: + print(e) + # print('Check------', max_target.shape, max_target.device, device) + # print('Check------', targets.shape, targets.device, device) + + tcls, tbox, indices, anch, targets_mask, targets_sum_mask = [], [], [], [], [], [] + gain = torch.ones(6, device=device) # normalized to gridspace gain + off_list = [ + torch.tensor([[1.], [0.]], device=device), + torch.tensor([[0.], [1.]], device=device), + torch.tensor([[-1.], [0.]], device=device), + torch.tensor([[0.], [-1.]], device=device) + ] + # # create indices with anchor and max_target + # # anchor tensor, same as .repeat_interleave(nt) (x, 3) + at = torch.arange(na).view(na, 1).repeat(1, nt_max) + a = at.view(-1) + a = torch.cat((a, a, a, a, a), 0) + + g = 0.5 # offset + # multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) + multi_gpu = is_parallel(model) + for i, j in enumerate(model.module.yolo_layers if multi_gpu else model.yolo_layers): + # get number of grid points and anchor vec for this yolo layer + anchors = model.module.module_list[j].anchor_vec if multi_gpu else model.module_list[j].anchor_vec + # iou of targets-anchors b,a,c,y,x-> b,a,y,x,c + # gain[2:] = torch.tensor(p[i].shape)[[3, 2, 3, 2]].float() # xyxy gain + gain[2:] = torch.tensor(p[i].shape)[[4, 3, 4, 3]].float() # xyxy gain + + # Match targets to anchors + t, offsets = max_target * gain[:, None], 0 + allmask = torch.zeros((na * nt_max)).to(device) + sum_mask = torch.zeros((1)).to(device) + if nt: + r = t[None, 4:6, :] / anchors[..., None] # wh ratio + fmask = torch.max(r, 1. / r).max(1)[0] < model.hyp['anchor_t'] # compare + fmask = fmask.view(1, -1) + # j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n) = wh_iou(anchors(3,2), gwh(n,2)) + t = t.repeat(1, 1, na).view(6, -1) # filter + + # overlaps + gxy = t.index_select(0, torch.tensor([2, 3], device=device)) + z = torch.zeros_like(gxy) + + jk = (gxy % 1. < g) & (gxy > 1.) + lm = (gxy % 1. > (1 - g)) & (gxy < (gain[[2, 3]][:, None] - 1.)) + jk, lm = jk&fmask, lm&fmask + allmask = torch.cat((fmask, jk, lm), 0).view(1, -1).float() + t = torch.cat((t, t, t, t, t), 1) + offsets = torch.cat((z, z + off_list[0], z + off_list[1], z + off_list[2], z + off_list[3]), 1) * g + + # print('----------------------------------------------------------------------------------') + # print('a.shape, t.shape:') + # print(a.shape, t.shape) + # print('gxy.shape, offsets.shape') + # print(gxy.shape, offsets.shape) + # print('fmask.shape, allmask.shape, jk, lm:') + # print(fmask.shape, allmask.shape, jk.shape, lm.shape) + # print('----------------------------------------------------------------------------------') + + sum_mask = allmask.sum() + t = t * allmask + + # Define + b = t.index_select(0, torch.tensor([0], device=device)).long().view(-1) #(3072 * 5) + c = t.index_select(0, torch.tensor([1], device=device)).long().view(-1) #(3072 * 5) + gxy = t.index_select(0, torch.tensor([2, 3], device=device)) #(2, 3072 * 5) + gwh = t.index_select(0, torch.tensor([4, 5], device=device)) #(2, 3072 * 5) + gij = gxy - offsets + gij2 = gij.long() + gi = gij2.index_select(0, torch.tensor([0], device=device)).view(-1) #(2, 3072 * 5) + gj = gij2.index_select(0, torch.tensor([1], device=device)).view(-1) #(2, 3072 * 5) + + # Append + # indices.append((b, a, gj.clamp_(0, gain[3] - 1), gi.clamp_(0, gain[2] - 1))) # image, anchor, grid indices + indices.append((b, a, gj, gi)) # image, anchor, grid indices + tbox.append(torch.cat((gxy - gij2.float(), gwh), 0)) # box + anch.append(anchors[a]) # anchors + tcls.append(c) # class + targets_mask.append(allmask) + targets_sum_mask.append(sum_mask) + + return tcls, tbox, indices, anch, targets_mask, targets_sum_mask + +# def build_targets(p, targets, model): +# nt = targets.shape[0] # number of anchors, targets +# tcls, tbox, indices, anch, targets_mask, targets_sum_mask = [], [], [], [], [], [] +# gain = torch.ones(6, device=targets.device) # normalized to gridspace gain +# off = torch.tensor([[1, 0], [0, 1], [-1, 0], [0, -1]], device=targets.device).float() # overlap offsets + +# # align targets in batch size +# batch_size = p[0].shape[0] +# nt_max = 32 * batch_size +# while nt > nt_max: +# nt_max *= 2 +# print('**************** nt max=', nt_max) +# max_target = torch.zeros(nt_max, 6, device=targets.device) # (nt,6) +# for i in range(6): +# max_target[:nt, i] = targets[:, i] + +# g = 0.5 # offset +# multi_gpu = is_parallel(model) +# for i, jj in enumerate(model.module.yolo_layers if multi_gpu else model.yolo_layers): +# # get number of grid points and anchor vec for this yolo layer +# anchors = model.module.module_list[jj].anchor_vec if multi_gpu else model.module_list[jj].anchor_vec +# gain[2:] = torch.tensor(p[i].shape)[[3, 2, 3, 2]] # xyxy gain + +# # Match targets to anchors +# a, t, offsets = [], max_target * gain, 0 + +# if nt: +# na = anchors.shape[0] # number of anchors +# allmask = torch.zeros((na * nt_max)).to(targets.device) +# sum_mask = torch.zeros((1)).to(targets.device) +# at = torch.arange(na).view(na, 1).repeat(1, nt_max) # anchor tensor, same as .repeat_interleave(nt) +# r = t[None, :, 4:6] / anchors[:, None] # wh ratio +# fmask = torch.max(r, 1. / r).max(2)[0] < model.hyp['anchor_t'] # compare +# # j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n) = wh_iou(anchors(3,2), gwh(n,2)) +# a, t = at[fmask], t.repeat(na, 1, 1)[fmask] # filter + +# print('----------------------------------------------------------------------------------') +# print('a.shape, at.shape, t.shape:') +# print(a.shape, at.shape, t.shape) +# print('----------------------------------------------------------------------------------') + +# # overlaps +# gxy = t[:, 2:4] # grid xy +# z = torch.zeros_like(gxy) +# j, k = ((gxy % 1. < g) & (gxy > 1.)).T +# l, m = ((gxy % 1. > (1 - g)) & (gxy < (gain[[2, 3]] - 1.))).T + +# print(a.shape, a[j].shape, a[k].shape, a[l].shape, a[m].shape) +# print(t.shape, t[j].shape, t[k].shape, t[l].shape, t[m].shape) + +# a, t = torch.cat((a, a[j], a[k], a[l], a[m]), 0), torch.cat((t, t[j], t[k], t[l], t[m]), 0) +# offsets = torch.cat((z, z[j] + off[0], z[k] + off[1], z[l] + off[2], z[m] + off[3]), 0) * g + +# allmask = torch.cat((j, k, l, m), 1).float() +# sum_mask = allmask.sum() + +# print('----------------------------------------------------------------------------------') +# print('a.shape, t.shape:') +# print(a.shape, t.shape) +# print('gxy.shape, offsets.shape') +# print(gxy.shape, offsets.shape) +# print('fmask.shape, allmask.shape, j, k, l, m:') +# print(fmask.shape, allmask.shape, j.shape, k.shape, l.shape, m.shape) +# print('----------------------------------------------------------------------------------') + +# t = t * allmask + +# # Define +# b, c = t[:, :2].long().T # image, class +# gxy = t[:, 2:4] # grid xy +# gwh = t[:, 4:6] # grid wh +# gij = (gxy - offsets).long() +# gi, gj = gij.T # grid xy indices + +# # Append +# #indices.append((b, a, gj, gi)) # image, anchor, grid indices +# indices.append((b, a, gj.clamp_(0, gain[3] - 1), gi.clamp_(0, gain[2] - 1))) # image, anchor, grid indices +# tbox.append(torch.cat((gxy - gij, gwh), 1)) # box +# anch.append(anchors[a]) # anchors +# tcls.append(c) # class +# targets_mask.append(allmask) +# targets_sum_mask.append(sum_mask) + +# return tcls, tbox, indices, anch, targets_mask, targets_sum_mask diff --git a/PyTorch/contrib/cv/detection/YOLOR/utils/metrics.py b/PyTorch/contrib/cv/detection/YOLOR/utils/metrics.py index fc4fa4f77d..51622cb73d 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/utils/metrics.py +++ b/PyTorch/contrib/cv/detection/YOLOR/utils/metrics.py @@ -1,154 +1,154 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -# Model validation metrics - -import matplotlib.pyplot as plt -import numpy as np - - -def fitness(x): - # Model fitness as a weighted combination of metrics - w = [0.0, 0.0, 0.1, 0.9] # weights for [P, R, mAP@0.5, mAP@0.5:0.95] - return (x[:, :4] * w).sum(1) - - -def fitness_p(x): - # Model fitness as a weighted combination of metrics - w = [1.0, 0.0, 0.0, 0.0] # weights for [P, R, mAP@0.5, mAP@0.5:0.95] - return (x[:, :4] * w).sum(1) - - -def fitness_r(x): - # Model fitness as a weighted combination of metrics - w = [0.0, 1.0, 0.0, 0.0] # weights for [P, R, mAP@0.5, mAP@0.5:0.95] - return (x[:, :4] * w).sum(1) - - -def fitness_ap50(x): - # Model fitness as a weighted combination of metrics - w = [0.0, 0.0, 1.0, 0.0] # weights for [P, R, mAP@0.5, mAP@0.5:0.95] - return (x[:, :4] * w).sum(1) - - -def fitness_ap(x): - # Model fitness as a weighted combination of metrics - w = [0.0, 0.0, 0.0, 1.0] # weights for [P, R, mAP@0.5, mAP@0.5:0.95] - return (x[:, :4] * w).sum(1) - - -def fitness_f(x): - # Model fitness as a weighted combination of metrics - #w = [0.0, 0.0, 0.0, 1.0] # weights for [P, R, mAP@0.5, mAP@0.5:0.95] - return ((x[:, 0]*x[:, 1])/(x[:, 0]+x[:, 1])) - - -def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, fname='precision-recall_curve.png'): - """ Compute the average precision, given the recall and precision curves. - Source: https://github.com/rafaelpadilla/Object-Detection-Metrics. - # Arguments - tp: True positives (nparray, nx1 or nx10). - conf: Objectness value from 0-1 (nparray). - pred_cls: Predicted object classes (nparray). - target_cls: True object classes (nparray). - plot: Plot precision-recall curve at mAP@0.5 - fname: Plot filename - # Returns - The average precision as computed in py-faster-rcnn. - """ - - # Sort by objectness - i = np.argsort(-conf) - tp, conf, pred_cls = tp[i], conf[i], pred_cls[i] - - # Find unique classes - unique_classes = np.unique(target_cls) - - # Create Precision-Recall curve and compute AP for each class - px, py = np.linspace(0, 1, 1000), [] # for plotting - pr_score = 0.1 # score to evaluate P and R https://github.com/ultralytics/yolov3/issues/898 - s = [unique_classes.shape[0], tp.shape[1]] # number class, number iou thresholds (i.e. 10 for mAP0.5...0.95) - ap, p, r = np.zeros(s), np.zeros(s), np.zeros(s) - for ci, c in enumerate(unique_classes): - i = pred_cls == c - n_l = (target_cls == c).sum() # number of labels - n_p = i.sum() # number of predictions - - if n_p == 0 or n_l == 0: - continue - else: - # Accumulate FPs and TPs - fpc = (1 - tp[i]).cumsum(0) - tpc = tp[i].cumsum(0) - - # Recall - recall = tpc / (n_l + 1e-16) # recall curve - r[ci] = np.interp(-pr_score, -conf[i], recall[:, 0]) # r at pr_score, negative x, xp because xp decreases - - # Precision - precision = tpc / (tpc + fpc) # precision curve - p[ci] = np.interp(-pr_score, -conf[i], precision[:, 0]) # p at pr_score - - # AP from recall-precision curve - for j in range(tp.shape[1]): - ap[ci, j], mpre, mrec = compute_ap(recall[:, j], precision[:, j]) - if j == 0: - py.append(np.interp(px, mrec, mpre)) # precision at mAP@0.5 - - # Compute F1 score (harmonic mean of precision and recall) - f1 = 2 * p * r / (p + r + 1e-16) - - if plot: - py = np.stack(py, axis=1) - fig, ax = plt.subplots(1, 1, figsize=(5, 5)) - ax.plot(px, py, linewidth=0.5, color='grey') # plot(recall, precision) - ax.plot(px, py.mean(1), linewidth=2, color='blue', label='all classes %.3f mAP@0.5' % ap[:, 0].mean()) - ax.set_xlabel('Recall') - ax.set_ylabel('Precision') - ax.set_xlim(0, 1) - ax.set_ylim(0, 1) - plt.legend() - fig.tight_layout() - fig.savefig(fname, dpi=200) - - return p, r, ap, f1, unique_classes.astype('int32') - - -def compute_ap(recall, precision): - """ Compute the average precision, given the recall and precision curves. - Source: https://github.com/rbgirshick/py-faster-rcnn. - # Arguments - recall: The recall curve (list). - precision: The precision curve (list). - # Returns - The average precision as computed in py-faster-rcnn. - """ - - # Append sentinel values to beginning and end - mrec = np.concatenate(([0.0], recall, [1.0])) - mpre = np.concatenate(([1.0], precision, [0.0])) - - # Compute the precision envelope - mpre = np.flip(np.maximum.accumulate(np.flip(mpre))) - - # Integrate area under curve - method = 'interp' # methods: 'continuous', 'interp' - if method == 'interp': - x = np.linspace(0, 1, 101) # 101-point interp (COCO) - ap = np.trapz(np.interp(x, mrec, mpre), x) # integrate - else: # 'continuous' - i = np.where(mrec[1:] != mrec[:-1])[0] # points where x axis (recall) changes - ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) # area under curve - - return ap, mpre, mrec +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +# Model validation metrics + +import matplotlib.pyplot as plt +import numpy as np + + +def fitness(x): + # Model fitness as a weighted combination of metrics + w = [0.0, 0.0, 0.1, 0.9] # weights for [P, R, mAP@0.5, mAP@0.5:0.95] + return (x[:, :4] * w).sum(1) + + +def fitness_p(x): + # Model fitness as a weighted combination of metrics + w = [1.0, 0.0, 0.0, 0.0] # weights for [P, R, mAP@0.5, mAP@0.5:0.95] + return (x[:, :4] * w).sum(1) + + +def fitness_r(x): + # Model fitness as a weighted combination of metrics + w = [0.0, 1.0, 0.0, 0.0] # weights for [P, R, mAP@0.5, mAP@0.5:0.95] + return (x[:, :4] * w).sum(1) + + +def fitness_ap50(x): + # Model fitness as a weighted combination of metrics + w = [0.0, 0.0, 1.0, 0.0] # weights for [P, R, mAP@0.5, mAP@0.5:0.95] + return (x[:, :4] * w).sum(1) + + +def fitness_ap(x): + # Model fitness as a weighted combination of metrics + w = [0.0, 0.0, 0.0, 1.0] # weights for [P, R, mAP@0.5, mAP@0.5:0.95] + return (x[:, :4] * w).sum(1) + + +def fitness_f(x): + # Model fitness as a weighted combination of metrics + #w = [0.0, 0.0, 0.0, 1.0] # weights for [P, R, mAP@0.5, mAP@0.5:0.95] + return ((x[:, 0]*x[:, 1])/(x[:, 0]+x[:, 1])) + + +def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, fname='precision-recall_curve.png'): + """ Compute the average precision, given the recall and precision curves. + Source: https://github.com/rafaelpadilla/Object-Detection-Metrics. + # Arguments + tp: True positives (nparray, nx1 or nx10). + conf: Objectness value from 0-1 (nparray). + pred_cls: Predicted object classes (nparray). + target_cls: True object classes (nparray). + plot: Plot precision-recall curve at mAP@0.5 + fname: Plot filename + # Returns + The average precision as computed in py-faster-rcnn. + """ + + # Sort by objectness + i = np.argsort(-conf) + tp, conf, pred_cls = tp[i], conf[i], pred_cls[i] + + # Find unique classes + unique_classes = np.unique(target_cls) + + # Create Precision-Recall curve and compute AP for each class + px, py = np.linspace(0, 1, 1000), [] # for plotting + pr_score = 0.1 # score to evaluate P and R https://github.com/ultralytics/yolov3/issues/898 + s = [unique_classes.shape[0], tp.shape[1]] # number class, number iou thresholds (i.e. 10 for mAP0.5...0.95) + ap, p, r = np.zeros(s), np.zeros(s), np.zeros(s) + for ci, c in enumerate(unique_classes): + i = pred_cls == c + n_l = (target_cls == c).sum() # number of labels + n_p = i.sum() # number of predictions + + if n_p == 0 or n_l == 0: + continue + else: + # Accumulate FPs and TPs + fpc = (1 - tp[i]).cumsum(0) + tpc = tp[i].cumsum(0) + + # Recall + recall = tpc / (n_l + 1e-16) # recall curve + r[ci] = np.interp(-pr_score, -conf[i], recall[:, 0]) # r at pr_score, negative x, xp because xp decreases + + # Precision + precision = tpc / (tpc + fpc) # precision curve + p[ci] = np.interp(-pr_score, -conf[i], precision[:, 0]) # p at pr_score + + # AP from recall-precision curve + for j in range(tp.shape[1]): + ap[ci, j], mpre, mrec = compute_ap(recall[:, j], precision[:, j]) + if j == 0: + py.append(np.interp(px, mrec, mpre)) # precision at mAP@0.5 + + # Compute F1 score (harmonic mean of precision and recall) + f1 = 2 * p * r / (p + r + 1e-16) + + if plot: + py = np.stack(py, axis=1) + fig, ax = plt.subplots(1, 1, figsize=(5, 5)) + ax.plot(px, py, linewidth=0.5, color='grey') # plot(recall, precision) + ax.plot(px, py.mean(1), linewidth=2, color='blue', label='all classes %.3f mAP@0.5' % ap[:, 0].mean()) + ax.set_xlabel('Recall') + ax.set_ylabel('Precision') + ax.set_xlim(0, 1) + ax.set_ylim(0, 1) + plt.legend() + fig.tight_layout() + fig.savefig(fname, dpi=200) + + return p, r, ap, f1, unique_classes.astype('int32') + + +def compute_ap(recall, precision): + """ Compute the average precision, given the recall and precision curves. + Source: https://github.com/rbgirshick/py-faster-rcnn. + # Arguments + recall: The recall curve (list). + precision: The precision curve (list). + # Returns + The average precision as computed in py-faster-rcnn. + """ + + # Append sentinel values to beginning and end + mrec = np.concatenate(([0.0], recall, [1.0])) + mpre = np.concatenate(([1.0], precision, [0.0])) + + # Compute the precision envelope + mpre = np.flip(np.maximum.accumulate(np.flip(mpre))) + + # Integrate area under curve + method = 'interp' # methods: 'continuous', 'interp' + if method == 'interp': + x = np.linspace(0, 1, 101) # 101-point interp (COCO) + ap = np.trapz(np.interp(x, mrec, mpre), x) # integrate + else: # 'continuous' + i = np.where(mrec[1:] != mrec[:-1])[0] # points where x axis (recall) changes + ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) # area under curve + + return ap, mpre, mrec diff --git a/PyTorch/contrib/cv/detection/YOLOR/utils/parse_config.py b/PyTorch/contrib/cv/detection/YOLOR/utils/parse_config.py index 8315f86a19..f8bfcb5f3a 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/utils/parse_config.py +++ b/PyTorch/contrib/cv/detection/YOLOR/utils/parse_config.py @@ -1,85 +1,85 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os - -import numpy as np - - -def parse_model_cfg(path): - # Parse the yolo *.cfg file and return module definitions path may be 'cfg/yolov3.cfg', 'yolov3.cfg', or 'yolov3' - if not path.endswith('.cfg'): # add .cfg suffix if omitted - path += '.cfg' - if not os.path.exists(path) and os.path.exists('cfg' + os.sep + path): # add cfg/ prefix if omitted - path = 'cfg' + os.sep + path - - with open(path, 'r') as f: - lines = f.read().split('\n') - lines = [x for x in lines if x and not x.startswith('#')] - lines = [x.rstrip().lstrip() for x in lines] # get rid of fringe whitespaces - mdefs = [] # module definitions - for line in lines: - if line.startswith('['): # This marks the start of a new block - mdefs.append({}) - mdefs[-1]['type'] = line[1:-1].rstrip() - if mdefs[-1]['type'] == 'convolutional': - mdefs[-1]['batch_normalize'] = 0 # pre-populate with zeros (may be overwritten later) - - else: - key, val = line.split("=") - key = key.rstrip() - - if key == 'anchors': # return nparray - mdefs[-1][key] = np.array([float(x) for x in val.split(',')]).reshape((-1, 2)) # np anchors - elif (key in ['from', 'layers', 'mask']) or (key == 'size' and ',' in val): # return array - mdefs[-1][key] = [int(x) for x in val.split(',')] - else: - val = val.strip() - if val.isnumeric(): # return int or float - mdefs[-1][key] = int(val) if (int(val) - float(val)) == 0 else float(val) - else: - mdefs[-1][key] = val # return string - - # Check all fields are supported - supported = ['type', 'batch_normalize', 'filters', 'size', 'stride', 'pad', 'activation', 'layers', 'groups', - 'from', 'mask', 'anchors', 'classes', 'num', 'jitter', 'ignore_thresh', 'truth_thresh', 'random', - 'stride_x', 'stride_y', 'weights_type', 'weights_normalization', 'scale_x_y', 'beta_nms', 'nms_kind', - 'iou_loss', 'iou_normalizer', 'cls_normalizer', 'iou_thresh', 'atoms', 'na', 'nc'] - - f = [] # fields - for x in mdefs[1:]: - [f.append(k) for k in x if k not in f] - u = [x for x in f if x not in supported] # unsupported fields - assert not any(u), "Unsupported fields %s in %s. See https://github.com/ultralytics/yolov3/issues/631" % (u, path) - - return mdefs - - -def parse_data_cfg(path): - # Parses the data configuration file - if not os.path.exists(path) and os.path.exists('data' + os.sep + path): # add data/ prefix if omitted - path = 'data' + os.sep + path - - with open(path, 'r') as f: - lines = f.readlines() - - options = dict() - for line in lines: - line = line.strip() - if line == '' or line.startswith('#'): - continue - key, val = line.split('=') - options[key.strip()] = val.strip() - - return options +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os + +import numpy as np + + +def parse_model_cfg(path): + # Parse the yolo *.cfg file and return module definitions path may be 'cfg/yolov3.cfg', 'yolov3.cfg', or 'yolov3' + if not path.endswith('.cfg'): # add .cfg suffix if omitted + path += '.cfg' + if not os.path.exists(path) and os.path.exists('cfg' + os.sep + path): # add cfg/ prefix if omitted + path = 'cfg' + os.sep + path + + with open(path, 'r') as f: + lines = f.read().split('\n') + lines = [x for x in lines if x and not x.startswith('#')] + lines = [x.rstrip().lstrip() for x in lines] # get rid of fringe whitespaces + mdefs = [] # module definitions + for line in lines: + if line.startswith('['): # This marks the start of a new block + mdefs.append({}) + mdefs[-1]['type'] = line[1:-1].rstrip() + if mdefs[-1]['type'] == 'convolutional': + mdefs[-1]['batch_normalize'] = 0 # pre-populate with zeros (may be overwritten later) + + else: + key, val = line.split("=") + key = key.rstrip() + + if key == 'anchors': # return nparray + mdefs[-1][key] = np.array([float(x) for x in val.split(',')]).reshape((-1, 2)) # np anchors + elif (key in ['from', 'layers', 'mask']) or (key == 'size' and ',' in val): # return array + mdefs[-1][key] = [int(x) for x in val.split(',')] + else: + val = val.strip() + if val.isnumeric(): # return int or float + mdefs[-1][key] = int(val) if (int(val) - float(val)) == 0 else float(val) + else: + mdefs[-1][key] = val # return string + + # Check all fields are supported + supported = ['type', 'batch_normalize', 'filters', 'size', 'stride', 'pad', 'activation', 'layers', 'groups', + 'from', 'mask', 'anchors', 'classes', 'num', 'jitter', 'ignore_thresh', 'truth_thresh', 'random', + 'stride_x', 'stride_y', 'weights_type', 'weights_normalization', 'scale_x_y', 'beta_nms', 'nms_kind', + 'iou_loss', 'iou_normalizer', 'cls_normalizer', 'iou_thresh', 'atoms', 'na', 'nc'] + + f = [] # fields + for x in mdefs[1:]: + [f.append(k) for k in x if k not in f] + u = [x for x in f if x not in supported] # unsupported fields + assert not any(u), "Unsupported fields %s in %s. See https://github.com/ultralytics/yolov3/issues/631" % (u, path) + + return mdefs + + +def parse_data_cfg(path): + # Parses the data configuration file + if not os.path.exists(path) and os.path.exists('data' + os.sep + path): # add data/ prefix if omitted + path = 'data' + os.sep + path + + with open(path, 'r') as f: + lines = f.readlines() + + options = dict() + for line in lines: + line = line.strip() + if line == '' or line.startswith('#'): + continue + key, val = line.split('=') + options[key.strip()] = val.strip() + + return options diff --git a/PyTorch/contrib/cv/detection/YOLOR/utils/plots.py b/PyTorch/contrib/cv/detection/YOLOR/utils/plots.py index af98b973bb..dff7b2c63f 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/utils/plots.py +++ b/PyTorch/contrib/cv/detection/YOLOR/utils/plots.py @@ -1,394 +1,394 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -# Plotting utils - -import glob -import math -import os -import random -from copy import copy -from pathlib import Path - -import cv2 -import matplotlib -import matplotlib.pyplot as plt -import numpy as np -import torch -import yaml -from PIL import Image -from scipy.signal import butter, filtfilt - -from utils.general import xywh2xyxy, xyxy2xywh -from utils.metrics import fitness - -# Settings -matplotlib.use('Agg') # for writing to files only - - -def color_list(): - # Return first 10 plt colors as (r,g,b) https://stackoverflow.com/questions/51350872/python-from-color-name-to-rgb - def hex2rgb(h): - return tuple(int(h[1 + i:1 + i + 2], 16) for i in (0, 2, 4)) - - return [hex2rgb(h) for h in plt.rcParams['axes.prop_cycle'].by_key()['color']] - - -def hist2d(x, y, n=100): - # 2d histogram used in labels.png and evolve.png - xedges, yedges = np.linspace(x.min(), x.max(), n), np.linspace(y.min(), y.max(), n) - hist, xedges, yedges = np.histogram2d(x, y, (xedges, yedges)) - xidx = np.clip(np.digitize(x, xedges) - 1, 0, hist.shape[0] - 1) - yidx = np.clip(np.digitize(y, yedges) - 1, 0, hist.shape[1] - 1) - return np.log(hist[xidx, yidx]) - - -def butter_lowpass_filtfilt(data, cutoff=1500, fs=50000, order=5): - # https://stackoverflow.com/questions/28536191/how-to-filter-smooth-with-scipy-numpy - def butter_lowpass(cutoff, fs, order): - nyq = 0.5 * fs - normal_cutoff = cutoff / nyq - return butter(order, normal_cutoff, btype='low', analog=False) - - b, a = butter_lowpass(cutoff, fs, order=order) - return filtfilt(b, a, data) # forward-backward filter - - -def plot_one_box(x, img, color=None, label=None, line_thickness=None): - # Plots one bounding box on image img - tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # line/font thickness - color = color or [random.randint(0, 255) for _ in range(3)] - c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3])) - cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA) - if label: - tf = max(tl - 1, 1) # font thickness - t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] - c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3 - cv2.rectangle(img, c1, c2, color, -1, cv2.LINE_AA) # filled - cv2.putText(img, label, (c1[0], c1[1] - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA) - - -def plot_wh_methods(): # from utils.general import *; plot_wh_methods() - # Compares the two methods for width-height anchor multiplication - # https://github.com/ultralytics/yolov3/issues/168 - x = np.arange(-4.0, 4.0, .1) - ya = np.exp(x) - yb = torch.sigmoid(torch.from_numpy(x)).numpy() * 2 - - fig = plt.figure(figsize=(6, 3), dpi=150) - plt.plot(x, ya, '.-', label='YOLO') - plt.plot(x, yb ** 2, '.-', label='YOLO ^2') - plt.plot(x, yb ** 1.6, '.-', label='YOLO ^1.6') - plt.xlim(left=-4, right=4) - plt.ylim(bottom=0, top=6) - plt.xlabel('input') - plt.ylabel('output') - plt.grid() - plt.legend() - fig.tight_layout() - fig.savefig('comparison.png', dpi=200) - - -def output_to_target(output, width, height): - # Convert model output to target format [batch_id, class_id, x, y, w, h, conf] - if isinstance(output, torch.Tensor): - output = output.cpu().numpy() - - targets = [] - for i, o in enumerate(output): - if o is not None: - for pred in o: - box = pred[:4] - w = (box[2] - box[0]) / width - h = (box[3] - box[1]) / height - x = box[0] / width + w / 2 - y = box[1] / height + h / 2 - conf = pred[4] - cls = int(pred[5]) - - targets.append([item.cpu() if isinstance(item, torch.Tensor) else item for item in [i, cls, x, y, w, h, conf]]) - - return np.array(targets) - - -def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max_size=640, max_subplots=16): - # Plot image grid with labels - - if isinstance(images, torch.Tensor): - images = images.cpu().float().numpy() - if isinstance(targets, torch.Tensor): - targets = targets.cpu().numpy() - - # un-normalise - if np.max(images[0]) <= 1: - images *= 255 - - tl = 3 # line thickness - tf = max(tl - 1, 1) # font thickness - bs, _, h, w = images.shape # batch size, _, height, width - bs = min(bs, max_subplots) # limit plot images - ns = np.ceil(bs ** 0.5) # number of subplots (square) - - # Check if we should resize - scale_factor = max_size / max(h, w) - if scale_factor < 1: - h = math.ceil(scale_factor * h) - w = math.ceil(scale_factor * w) - - colors = color_list() # list of colors - mosaic = np.full((int(ns * h), int(ns * w), 3), 255, dtype=np.uint8) # init - for i, img in enumerate(images): - if i == max_subplots: # if last batch has fewer images than we expect - break - - block_x = int(w * (i // ns)) - block_y = int(h * (i % ns)) - - img = img.transpose(1, 2, 0) - if scale_factor < 1: - img = cv2.resize(img, (w, h)) - - mosaic[block_y:block_y + h, block_x:block_x + w, :] = img - if len(targets) > 0: - image_targets = targets[targets[:, 0] == i] - boxes = xywh2xyxy(image_targets[:, 2:6]).T - classes = image_targets[:, 1].astype('int') - labels = image_targets.shape[1] == 6 # labels if no conf column - conf = None if labels else image_targets[:, 6] # check for confidence presence (label vs pred) - - boxes[[0, 2]] *= w - boxes[[0, 2]] += block_x - boxes[[1, 3]] *= h - boxes[[1, 3]] += block_y - for j, box in enumerate(boxes.T): - cls = int(classes[j]) - color = colors[cls % len(colors)] - cls = names[cls] if names else cls - if labels or conf[j] > 0.25: # 0.25 conf thresh - label = '%s' % cls if labels else '%s %.1f' % (cls, conf[j]) - plot_one_box(box, mosaic, label=label, color=color, line_thickness=tl) - - # Draw image filename labels - if paths: - label = Path(paths[i]).name[:40] # trim to 40 char - t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] - cv2.putText(mosaic, label, (block_x + 5, block_y + t_size[1] + 5), 0, tl / 3, [220, 220, 220], thickness=tf, - lineType=cv2.LINE_AA) - - # Image border - cv2.rectangle(mosaic, (block_x, block_y), (block_x + w, block_y + h), (255, 255, 255), thickness=3) - - if fname: - r = min(1280. / max(h, w) / ns, 1.0) # ratio to limit image size - mosaic = cv2.resize(mosaic, (int(ns * w * r), int(ns * h * r)), interpolation=cv2.INTER_AREA) - # cv2.imwrite(fname, cv2.cvtColor(mosaic, cv2.COLOR_BGR2RGB)) # cv2 save - Image.fromarray(mosaic).save(fname) # PIL save - return mosaic - - -def plot_lr_scheduler(optimizer, scheduler, epochs=300, save_dir=''): - # Plot LR simulating training for full epochs - optimizer, scheduler = copy(optimizer), copy(scheduler) # do not modify originals - y = [] - for _ in range(epochs): - scheduler.step() - y.append(optimizer.param_groups[0]['lr']) - plt.plot(y, '.-', label='LR') - plt.xlabel('epoch') - plt.ylabel('LR') - plt.grid() - plt.xlim(0, epochs) - plt.ylim(0) - plt.tight_layout() - plt.savefig(Path(save_dir) / 'LR.png', dpi=200) - - -def plot_test_txt(): # from utils.general import *; plot_test() - # Plot test.txt histograms - x = np.loadtxt('test.txt', dtype=np.float32) - box = xyxy2xywh(x[:, :4]) - cx, cy = box[:, 0], box[:, 1] - - fig, ax = plt.subplots(1, 1, figsize=(6, 6), tight_layout=True) - ax.hist2d(cx, cy, bins=600, cmax=10, cmin=0) - ax.set_aspect('equal') - plt.savefig('hist2d.png', dpi=300) - - fig, ax = plt.subplots(1, 2, figsize=(12, 6), tight_layout=True) - ax[0].hist(cx, bins=600) - ax[1].hist(cy, bins=600) - plt.savefig('hist1d.png', dpi=200) - - -def plot_targets_txt(): # from utils.general import *; plot_targets_txt() - # Plot targets.txt histograms - x = np.loadtxt('targets.txt', dtype=np.float32).T - s = ['x targets', 'y targets', 'width targets', 'height targets'] - fig, ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True) - ax = ax.ravel() - for i in range(4): - ax[i].hist(x[i], bins=100, label='%.3g +/- %.3g' % (x[i].mean(), x[i].std())) - ax[i].legend() - ax[i].set_title(s[i]) - plt.savefig('targets.jpg', dpi=200) - - -def plot_study_txt(f='study.txt', x=None): # from utils.general import *; plot_study_txt() - # Plot study.txt generated by test.py - fig, ax = plt.subplots(2, 4, figsize=(10, 6), tight_layout=True) - ax = ax.ravel() - - fig2, ax2 = plt.subplots(1, 1, figsize=(8, 4), tight_layout=True) - for f in ['study/study_coco_yolo%s.txt' % x for x in ['s', 'm', 'l', 'x']]: - y = np.loadtxt(f, dtype=np.float32, usecols=[0, 1, 2, 3, 7, 8, 9], ndmin=2).T - x = np.arange(y.shape[1]) if x is None else np.array(x) - s = ['P', 'R', 'mAP@.5', 'mAP@.5:.95', 't_inference (ms/img)', 't_NMS (ms/img)', 't_total (ms/img)'] - for i in range(7): - ax[i].plot(x, y[i], '.-', linewidth=2, markersize=8) - ax[i].set_title(s[i]) - - j = y[3].argmax() + 1 - ax2.plot(y[6, :j], y[3, :j] * 1E2, '.-', linewidth=2, markersize=8, - label=Path(f).stem.replace('study_coco_', '').replace('yolo', 'YOLO')) - - ax2.plot(1E3 / np.array([209, 140, 97, 58, 35, 18]), [34.6, 40.5, 43.0, 47.5, 49.7, 51.5], - 'k.-', linewidth=2, markersize=8, alpha=.25, label='EfficientDet') - - ax2.grid() - ax2.set_xlim(0, 30) - ax2.set_ylim(28, 50) - ax2.set_yticks(np.arange(30, 55, 5)) - ax2.set_xlabel('GPU Speed (ms/img)') - ax2.set_ylabel('COCO AP val') - ax2.legend(loc='lower right') - plt.savefig('study_mAP_latency.png', dpi=300) - plt.savefig(f.replace('.txt', '.png'), dpi=300) - - -def plot_labels(labels, save_dir=''): - # plot dataset labels - c, b = labels[:, 0], labels[:, 1:].transpose() # classes, boxes - nc = int(c.max() + 1) # number of classes - - fig, ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True) - ax = ax.ravel() - ax[0].hist(c, bins=np.linspace(0, nc, nc + 1) - 0.5, rwidth=0.8) - ax[0].set_xlabel('classes') - ax[1].scatter(b[0], b[1], c=hist2d(b[0], b[1], 90), cmap='jet') - ax[1].set_xlabel('x') - ax[1].set_ylabel('y') - ax[2].scatter(b[2], b[3], c=hist2d(b[2], b[3], 90), cmap='jet') - ax[2].set_xlabel('width') - ax[2].set_ylabel('height') - plt.savefig(Path(save_dir) / 'labels.png', dpi=200) - plt.close() - - # seaborn correlogram - try: - import seaborn as sns - import pandas as pd - x = pd.DataFrame(b.transpose(), columns=['x', 'y', 'width', 'height']) - sns.pairplot(x, corner=True, diag_kind='hist', kind='scatter', markers='o', - plot_kws=dict(s=3, edgecolor=None, linewidth=1, alpha=0.02), - diag_kws=dict(bins=50)) - plt.savefig(Path(save_dir) / 'labels_correlogram.png', dpi=200) - plt.close() - except Exception as e: - pass - - -def plot_evolution(yaml_file='data/hyp.finetune.yaml'): # from utils.general import *; plot_evolution() - # Plot hyperparameter evolution results in evolve.txt - with open(yaml_file) as f: - hyp = yaml.load(f, Loader=yaml.FullLoader) - x = np.loadtxt('evolve.txt', ndmin=2) - f = fitness(x) - # weights = (f - f.min()) ** 2 # for weighted results - plt.figure(figsize=(10, 12), tight_layout=True) - matplotlib.rc('font', **{'size': 8}) - for i, (k, v) in enumerate(hyp.items()): - y = x[:, i + 7] - # mu = (y * weights).sum() / weights.sum() # best weighted result - mu = y[f.argmax()] # best single result - plt.subplot(6, 5, i + 1) - plt.scatter(y, f, c=hist2d(y, f, 20), cmap='viridis', alpha=.8, edgecolors='none') - plt.plot(mu, f.max(), 'k+', markersize=15) - plt.title('%s = %.3g' % (k, mu), fontdict={'size': 9}) # limit to 40 characters - if i % 5 != 0: - plt.yticks([]) - print('%15s: %.3g' % (k, mu)) - plt.savefig('evolve.png', dpi=200) - print('\nPlot saved as evolve.png') - - -def plot_results_overlay(start=0, stop=0): # from utils.general import *; plot_results_overlay() - # Plot training 'results*.txt', overlaying train and val losses - s = ['train', 'train', 'train', 'Precision', 'mAP@0.5', 'val', 'val', 'val', 'Recall', 'mAP@0.5:0.95'] # legends - t = ['Box', 'Objectness', 'Classification', 'P-R', 'mAP-F1'] # titles - for f in sorted(glob.glob('results*.txt') + glob.glob('../../Downloads/results*.txt')): - results = np.loadtxt(f, usecols=[2, 3, 4, 8, 9, 12, 13, 14, 10, 11], ndmin=2).T - n = results.shape[1] # number of rows - x = range(start, min(stop, n) if stop else n) - fig, ax = plt.subplots(1, 5, figsize=(14, 3.5), tight_layout=True) - ax = ax.ravel() - for i in range(5): - for j in [i, i + 5]: - y = results[j, x] - ax[i].plot(x, y, marker='.', label=s[j]) - # y_smooth = butter_lowpass_filtfilt(y) - # ax[i].plot(x, np.gradient(y_smooth), marker='.', label=s[j]) - - ax[i].set_title(t[i]) - ax[i].legend() - ax[i].set_ylabel(f) if i == 0 else None # add filename - fig.savefig(f.replace('.txt', '.png'), dpi=200) - - -def plot_results(start=0, stop=0, bucket='', id=(), labels=(), save_dir=''): - # from utils.general import *; plot_results(save_dir='runs/train/exp0') - # Plot training 'results*.txt' - fig, ax = plt.subplots(2, 5, figsize=(12, 6)) - ax = ax.ravel() - s = ['Box', 'Objectness', 'Classification', 'Precision', 'Recall', - 'val Box', 'val Objectness', 'val Classification', 'mAP@0.5', 'mAP@0.5:0.95'] - if bucket: - # os.system('rm -rf storage.googleapis.com') - # files = ['https://storage.googleapis.com/%s/results%g.txt' % (bucket, x) for x in id] - files = ['%g.txt' % x for x in id] - c = ('gsutil cp ' + '%s ' * len(files) + '.') % tuple('gs://%s/%g.txt' % (bucket, x) for x in id) - os.system(c) - else: - files = glob.glob(str(Path(save_dir) / '*.txt')) + glob.glob('../../Downloads/results*.txt') - assert len(files), 'No results.txt files found in %s, nothing to plot.' % os.path.abspath(save_dir) - for fi, f in enumerate(files): - try: - results = np.loadtxt(f, usecols=[2, 3, 4, 8, 9, 12, 13, 14, 10, 11], ndmin=2).T - n = results.shape[1] # number of rows - x = range(start, min(stop, n) if stop else n) - for i in range(10): - y = results[i, x] - if i in [0, 1, 2, 5, 6, 7]: - y[y == 0] = np.nan # don't show zero loss values - # y /= y[0] # normalize - label = labels[fi] if len(labels) else Path(f).stem - ax[i].plot(x, y, marker='.', label=label, linewidth=1, markersize=6) - ax[i].set_title(s[i]) - # if i in [5, 6, 7]: # share train and val loss y axes - # ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) - except Exception as e: - print('Warning: Plotting error for %s; %s' % (f, e)) - - fig.tight_layout() - ax[1].legend() - fig.savefig(Path(save_dir) / 'results.png', dpi=200) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +# Plotting utils + +import glob +import math +import os +import random +from copy import copy +from pathlib import Path + +import cv2 +import matplotlib +import matplotlib.pyplot as plt +import numpy as np +import torch +import yaml +from PIL import Image +from scipy.signal import butter, filtfilt + +from utils.general import xywh2xyxy, xyxy2xywh +from utils.metrics import fitness + +# Settings +matplotlib.use('Agg') # for writing to files only + + +def color_list(): + # Return first 10 plt colors as (r,g,b) https://stackoverflow.com/questions/51350872/python-from-color-name-to-rgb + def hex2rgb(h): + return tuple(int(h[1 + i:1 + i + 2], 16) for i in (0, 2, 4)) + + return [hex2rgb(h) for h in plt.rcParams['axes.prop_cycle'].by_key()['color']] + + +def hist2d(x, y, n=100): + # 2d histogram used in labels.png and evolve.png + xedges, yedges = np.linspace(x.min(), x.max(), n), np.linspace(y.min(), y.max(), n) + hist, xedges, yedges = np.histogram2d(x, y, (xedges, yedges)) + xidx = np.clip(np.digitize(x, xedges) - 1, 0, hist.shape[0] - 1) + yidx = np.clip(np.digitize(y, yedges) - 1, 0, hist.shape[1] - 1) + return np.log(hist[xidx, yidx]) + + +def butter_lowpass_filtfilt(data, cutoff=1500, fs=50000, order=5): + # https://stackoverflow.com/questions/28536191/how-to-filter-smooth-with-scipy-numpy + def butter_lowpass(cutoff, fs, order): + nyq = 0.5 * fs + normal_cutoff = cutoff / nyq + return butter(order, normal_cutoff, btype='low', analog=False) + + b, a = butter_lowpass(cutoff, fs, order=order) + return filtfilt(b, a, data) # forward-backward filter + + +def plot_one_box(x, img, color=None, label=None, line_thickness=None): + # Plots one bounding box on image img + tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # line/font thickness + color = color or [random.randint(0, 255) for _ in range(3)] + c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3])) + cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA) + if label: + tf = max(tl - 1, 1) # font thickness + t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] + c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3 + cv2.rectangle(img, c1, c2, color, -1, cv2.LINE_AA) # filled + cv2.putText(img, label, (c1[0], c1[1] - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA) + + +def plot_wh_methods(): # from utils.general import *; plot_wh_methods() + # Compares the two methods for width-height anchor multiplication + # https://github.com/ultralytics/yolov3/issues/168 + x = np.arange(-4.0, 4.0, .1) + ya = np.exp(x) + yb = torch.sigmoid(torch.from_numpy(x)).numpy() * 2 + + fig = plt.figure(figsize=(6, 3), dpi=150) + plt.plot(x, ya, '.-', label='YOLO') + plt.plot(x, yb ** 2, '.-', label='YOLO ^2') + plt.plot(x, yb ** 1.6, '.-', label='YOLO ^1.6') + plt.xlim(left=-4, right=4) + plt.ylim(bottom=0, top=6) + plt.xlabel('input') + plt.ylabel('output') + plt.grid() + plt.legend() + fig.tight_layout() + fig.savefig('comparison.png', dpi=200) + + +def output_to_target(output, width, height): + # Convert model output to target format [batch_id, class_id, x, y, w, h, conf] + if isinstance(output, torch.Tensor): + output = output.cpu().numpy() + + targets = [] + for i, o in enumerate(output): + if o is not None: + for pred in o: + box = pred[:4] + w = (box[2] - box[0]) / width + h = (box[3] - box[1]) / height + x = box[0] / width + w / 2 + y = box[1] / height + h / 2 + conf = pred[4] + cls = int(pred[5]) + + targets.append([item.cpu() if isinstance(item, torch.Tensor) else item for item in [i, cls, x, y, w, h, conf]]) + + return np.array(targets) + + +def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max_size=640, max_subplots=16): + # Plot image grid with labels + + if isinstance(images, torch.Tensor): + images = images.cpu().float().numpy() + if isinstance(targets, torch.Tensor): + targets = targets.cpu().numpy() + + # un-normalise + if np.max(images[0]) <= 1: + images *= 255 + + tl = 3 # line thickness + tf = max(tl - 1, 1) # font thickness + bs, _, h, w = images.shape # batch size, _, height, width + bs = min(bs, max_subplots) # limit plot images + ns = np.ceil(bs ** 0.5) # number of subplots (square) + + # Check if we should resize + scale_factor = max_size / max(h, w) + if scale_factor < 1: + h = math.ceil(scale_factor * h) + w = math.ceil(scale_factor * w) + + colors = color_list() # list of colors + mosaic = np.full((int(ns * h), int(ns * w), 3), 255, dtype=np.uint8) # init + for i, img in enumerate(images): + if i == max_subplots: # if last batch has fewer images than we expect + break + + block_x = int(w * (i // ns)) + block_y = int(h * (i % ns)) + + img = img.transpose(1, 2, 0) + if scale_factor < 1: + img = cv2.resize(img, (w, h)) + + mosaic[block_y:block_y + h, block_x:block_x + w, :] = img + if len(targets) > 0: + image_targets = targets[targets[:, 0] == i] + boxes = xywh2xyxy(image_targets[:, 2:6]).T + classes = image_targets[:, 1].astype('int') + labels = image_targets.shape[1] == 6 # labels if no conf column + conf = None if labels else image_targets[:, 6] # check for confidence presence (label vs pred) + + boxes[[0, 2]] *= w + boxes[[0, 2]] += block_x + boxes[[1, 3]] *= h + boxes[[1, 3]] += block_y + for j, box in enumerate(boxes.T): + cls = int(classes[j]) + color = colors[cls % len(colors)] + cls = names[cls] if names else cls + if labels or conf[j] > 0.25: # 0.25 conf thresh + label = '%s' % cls if labels else '%s %.1f' % (cls, conf[j]) + plot_one_box(box, mosaic, label=label, color=color, line_thickness=tl) + + # Draw image filename labels + if paths: + label = Path(paths[i]).name[:40] # trim to 40 char + t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] + cv2.putText(mosaic, label, (block_x + 5, block_y + t_size[1] + 5), 0, tl / 3, [220, 220, 220], thickness=tf, + lineType=cv2.LINE_AA) + + # Image border + cv2.rectangle(mosaic, (block_x, block_y), (block_x + w, block_y + h), (255, 255, 255), thickness=3) + + if fname: + r = min(1280. / max(h, w) / ns, 1.0) # ratio to limit image size + mosaic = cv2.resize(mosaic, (int(ns * w * r), int(ns * h * r)), interpolation=cv2.INTER_AREA) + # cv2.imwrite(fname, cv2.cvtColor(mosaic, cv2.COLOR_BGR2RGB)) # cv2 save + Image.fromarray(mosaic).save(fname) # PIL save + return mosaic + + +def plot_lr_scheduler(optimizer, scheduler, epochs=300, save_dir=''): + # Plot LR simulating training for full epochs + optimizer, scheduler = copy(optimizer), copy(scheduler) # do not modify originals + y = [] + for _ in range(epochs): + scheduler.step() + y.append(optimizer.param_groups[0]['lr']) + plt.plot(y, '.-', label='LR') + plt.xlabel('epoch') + plt.ylabel('LR') + plt.grid() + plt.xlim(0, epochs) + plt.ylim(0) + plt.tight_layout() + plt.savefig(Path(save_dir) / 'LR.png', dpi=200) + + +def plot_test_txt(): # from utils.general import *; plot_test() + # Plot test.txt histograms + x = np.loadtxt('test.txt', dtype=np.float32) + box = xyxy2xywh(x[:, :4]) + cx, cy = box[:, 0], box[:, 1] + + fig, ax = plt.subplots(1, 1, figsize=(6, 6), tight_layout=True) + ax.hist2d(cx, cy, bins=600, cmax=10, cmin=0) + ax.set_aspect('equal') + plt.savefig('hist2d.png', dpi=300) + + fig, ax = plt.subplots(1, 2, figsize=(12, 6), tight_layout=True) + ax[0].hist(cx, bins=600) + ax[1].hist(cy, bins=600) + plt.savefig('hist1d.png', dpi=200) + + +def plot_targets_txt(): # from utils.general import *; plot_targets_txt() + # Plot targets.txt histograms + x = np.loadtxt('targets.txt', dtype=np.float32).T + s = ['x targets', 'y targets', 'width targets', 'height targets'] + fig, ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True) + ax = ax.ravel() + for i in range(4): + ax[i].hist(x[i], bins=100, label='%.3g +/- %.3g' % (x[i].mean(), x[i].std())) + ax[i].legend() + ax[i].set_title(s[i]) + plt.savefig('targets.jpg', dpi=200) + + +def plot_study_txt(f='study.txt', x=None): # from utils.general import *; plot_study_txt() + # Plot study.txt generated by test.py + fig, ax = plt.subplots(2, 4, figsize=(10, 6), tight_layout=True) + ax = ax.ravel() + + fig2, ax2 = plt.subplots(1, 1, figsize=(8, 4), tight_layout=True) + for f in ['study/study_coco_yolo%s.txt' % x for x in ['s', 'm', 'l', 'x']]: + y = np.loadtxt(f, dtype=np.float32, usecols=[0, 1, 2, 3, 7, 8, 9], ndmin=2).T + x = np.arange(y.shape[1]) if x is None else np.array(x) + s = ['P', 'R', 'mAP@.5', 'mAP@.5:.95', 't_inference (ms/img)', 't_NMS (ms/img)', 't_total (ms/img)'] + for i in range(7): + ax[i].plot(x, y[i], '.-', linewidth=2, markersize=8) + ax[i].set_title(s[i]) + + j = y[3].argmax() + 1 + ax2.plot(y[6, :j], y[3, :j] * 1E2, '.-', linewidth=2, markersize=8, + label=Path(f).stem.replace('study_coco_', '').replace('yolo', 'YOLO')) + + ax2.plot(1E3 / np.array([209, 140, 97, 58, 35, 18]), [34.6, 40.5, 43.0, 47.5, 49.7, 51.5], + 'k.-', linewidth=2, markersize=8, alpha=.25, label='EfficientDet') + + ax2.grid() + ax2.set_xlim(0, 30) + ax2.set_ylim(28, 50) + ax2.set_yticks(np.arange(30, 55, 5)) + ax2.set_xlabel('GPU Speed (ms/img)') + ax2.set_ylabel('COCO AP val') + ax2.legend(loc='lower right') + plt.savefig('study_mAP_latency.png', dpi=300) + plt.savefig(f.replace('.txt', '.png'), dpi=300) + + +def plot_labels(labels, save_dir=''): + # plot dataset labels + c, b = labels[:, 0], labels[:, 1:].transpose() # classes, boxes + nc = int(c.max() + 1) # number of classes + + fig, ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True) + ax = ax.ravel() + ax[0].hist(c, bins=np.linspace(0, nc, nc + 1) - 0.5, rwidth=0.8) + ax[0].set_xlabel('classes') + ax[1].scatter(b[0], b[1], c=hist2d(b[0], b[1], 90), cmap='jet') + ax[1].set_xlabel('x') + ax[1].set_ylabel('y') + ax[2].scatter(b[2], b[3], c=hist2d(b[2], b[3], 90), cmap='jet') + ax[2].set_xlabel('width') + ax[2].set_ylabel('height') + plt.savefig(Path(save_dir) / 'labels.png', dpi=200) + plt.close() + + # seaborn correlogram + try: + import seaborn as sns + import pandas as pd + x = pd.DataFrame(b.transpose(), columns=['x', 'y', 'width', 'height']) + sns.pairplot(x, corner=True, diag_kind='hist', kind='scatter', markers='o', + plot_kws=dict(s=3, edgecolor=None, linewidth=1, alpha=0.02), + diag_kws=dict(bins=50)) + plt.savefig(Path(save_dir) / 'labels_correlogram.png', dpi=200) + plt.close() + except Exception as e: + pass + + +def plot_evolution(yaml_file='data/hyp.finetune.yaml'): # from utils.general import *; plot_evolution() + # Plot hyperparameter evolution results in evolve.txt + with open(yaml_file) as f: + hyp = yaml.load(f, Loader=yaml.FullLoader) + x = np.loadtxt('evolve.txt', ndmin=2) + f = fitness(x) + # weights = (f - f.min()) ** 2 # for weighted results + plt.figure(figsize=(10, 12), tight_layout=True) + matplotlib.rc('font', **{'size': 8}) + for i, (k, v) in enumerate(hyp.items()): + y = x[:, i + 7] + # mu = (y * weights).sum() / weights.sum() # best weighted result + mu = y[f.argmax()] # best single result + plt.subplot(6, 5, i + 1) + plt.scatter(y, f, c=hist2d(y, f, 20), cmap='viridis', alpha=.8, edgecolors='none') + plt.plot(mu, f.max(), 'k+', markersize=15) + plt.title('%s = %.3g' % (k, mu), fontdict={'size': 9}) # limit to 40 characters + if i % 5 != 0: + plt.yticks([]) + print('%15s: %.3g' % (k, mu)) + plt.savefig('evolve.png', dpi=200) + print('\nPlot saved as evolve.png') + + +def plot_results_overlay(start=0, stop=0): # from utils.general import *; plot_results_overlay() + # Plot training 'results*.txt', overlaying train and val losses + s = ['train', 'train', 'train', 'Precision', 'mAP@0.5', 'val', 'val', 'val', 'Recall', 'mAP@0.5:0.95'] # legends + t = ['Box', 'Objectness', 'Classification', 'P-R', 'mAP-F1'] # titles + for f in sorted(glob.glob('results*.txt') + glob.glob('../../Downloads/results*.txt')): + results = np.loadtxt(f, usecols=[2, 3, 4, 8, 9, 12, 13, 14, 10, 11], ndmin=2).T + n = results.shape[1] # number of rows + x = range(start, min(stop, n) if stop else n) + fig, ax = plt.subplots(1, 5, figsize=(14, 3.5), tight_layout=True) + ax = ax.ravel() + for i in range(5): + for j in [i, i + 5]: + y = results[j, x] + ax[i].plot(x, y, marker='.', label=s[j]) + # y_smooth = butter_lowpass_filtfilt(y) + # ax[i].plot(x, np.gradient(y_smooth), marker='.', label=s[j]) + + ax[i].set_title(t[i]) + ax[i].legend() + ax[i].set_ylabel(f) if i == 0 else None # add filename + fig.savefig(f.replace('.txt', '.png'), dpi=200) + + +def plot_results(start=0, stop=0, bucket='', id=(), labels=(), save_dir=''): + # from utils.general import *; plot_results(save_dir='runs/train/exp0') + # Plot training 'results*.txt' + fig, ax = plt.subplots(2, 5, figsize=(12, 6)) + ax = ax.ravel() + s = ['Box', 'Objectness', 'Classification', 'Precision', 'Recall', + 'val Box', 'val Objectness', 'val Classification', 'mAP@0.5', 'mAP@0.5:0.95'] + if bucket: + # os.system('rm -rf storage.googleapis.com') + # files = ['https://storage.googleapis.com/%s/results%g.txt' % (bucket, x) for x in id] + files = ['%g.txt' % x for x in id] + c = ('gsutil cp ' + '%s ' * len(files) + '.') % tuple('gs://%s/%g.txt' % (bucket, x) for x in id) + os.system(c) + else: + files = glob.glob(str(Path(save_dir) / '*.txt')) + glob.glob('../../Downloads/results*.txt') + assert len(files), 'No results.txt files found in %s, nothing to plot.' % os.path.abspath(save_dir) + for fi, f in enumerate(files): + try: + results = np.loadtxt(f, usecols=[2, 3, 4, 8, 9, 12, 13, 14, 10, 11], ndmin=2).T + n = results.shape[1] # number of rows + x = range(start, min(stop, n) if stop else n) + for i in range(10): + y = results[i, x] + if i in [0, 1, 2, 5, 6, 7]: + y[y == 0] = np.nan # don't show zero loss values + # y /= y[0] # normalize + label = labels[fi] if len(labels) else Path(f).stem + ax[i].plot(x, y, marker='.', label=label, linewidth=1, markersize=6) + ax[i].set_title(s[i]) + # if i in [5, 6, 7]: # share train and val loss y axes + # ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) + except Exception as e: + print('Warning: Plotting error for %s; %s' % (f, e)) + + fig.tight_layout() + ax[1].legend() + fig.savefig(Path(save_dir) / 'results.png', dpi=200) diff --git a/PyTorch/contrib/cv/detection/YOLOR/utils/torch_utils.py b/PyTorch/contrib/cv/detection/YOLOR/utils/torch_utils.py index 229bb26bc2..707a4f5496 100644 --- a/PyTorch/contrib/cv/detection/YOLOR/utils/torch_utils.py +++ b/PyTorch/contrib/cv/detection/YOLOR/utils/torch_utils.py @@ -1,313 +1,313 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -# PyTorch utils - -import logging -import math -import os -import time -from contextlib import contextmanager -from copy import deepcopy - -import torch -import torch.backends.cudnn as cudnn -import torch.nn as nn -import torch.nn.functional as F -import torchvision - -logger = logging.getLogger(__name__) - - -@contextmanager -def torch_distributed_zero_first(local_rank: int): - """ - Decorator to make all processes in distributed training wait for each local_master to do something. - """ - if local_rank not in [-1, 0]: - torch.distributed.barrier() - yield - if local_rank == 0: - torch.distributed.barrier() - - -def init_torch_seeds(seed=0): - # Speed-reproducibility tradeoff https://pytorch.org/docs/stable/notes/randomness.html - torch.manual_seed(seed) - if seed == 0: # slower, more reproducible - cudnn.deterministic = True - cudnn.benchmark = False - else: # faster, less reproducible - cudnn.deterministic = False - cudnn.benchmark = True - - -def select_device(device='', npu='', apex=False, batch_size=None): - npu_request = device.lower() == 'npu' - if npu_request and npu != -1: - torch.npu.set_device("npu:%d" % npu) - print('Using NPU %d to train' % npu) - return torch.device("npu:%d" % npu) - # device = 'cpu' or '0' or '0,1,2,3' - cpu_request = device.lower() == 'cpu' - if device and not cpu_request: # if device requested other than 'cpu' - os.environ['CUDA_VISIBLE_DEVICES'] = device # set environment variable - assert torch.cuda.is_available(), 'CUDA unavailable, invalid device %s requested' % device # check availablity - - cuda = False if cpu_request else torch.cuda.is_available() - if cuda: - c = 1024 ** 2 # bytes to MB - ng = torch.cuda.device_count() - if ng > 1 and batch_size: # check that batch_size is compatible with device_count - assert batch_size % ng == 0, 'batch-size %g not multiple of GPU count %g' % (batch_size, ng) - x = [torch.cuda.get_device_properties(i) for i in range(ng)] - s = 'Using CUDA ' + ('Apex ' if apex else '') # apex for mixed precision https://github.com/NVIDIA/apex - for i in range(0, ng): - if i == 1: - s = ' ' * len(s) - print("%sdevice%g _CudaDeviceProperties(name='%s', total_memory=%dMB)" % - (s, i, x[i].name, x[i].total_memory / c)) - else: - print('Using CPU') - - print('') # skip a line - return torch.device('cuda:0' if cuda else 'cpu') - - -def time_synchronized(): - torch.cuda.synchronize() if torch.cuda.is_available() else None - return time.time() - - -def is_parallel(model): - return type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) - - -def intersect_dicts(da, db, exclude=()): - # Dictionary intersection of matching keys and shapes, omitting 'exclude' keys, using da values - return {k: v for k, v in da.items() if k in db and not any(x in k for x in exclude) and v.shape == db[k].shape} - - -def initialize_weights(model): - for m in model.modules(): - t = type(m) - if t is nn.Conv2d: - pass # nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') - elif t is nn.BatchNorm2d: - m.eps = 1e-3 - m.momentum = 0.03 - elif t in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6]: - m.inplace = True - - -def find_modules(model, mclass=nn.Conv2d): - # Finds layer indices matching module class 'mclass' - return [i for i, m in enumerate(model.module_list) if isinstance(m, mclass)] - - -def sparsity(model): - # Return global model sparsity - a, b = 0., 0. - for p in model.parameters(): - a += p.numel() - b += (p == 0).sum() - return b / a - - -def prune(model, amount=0.3): - # Prune model to requested global sparsity - import torch.nn.utils.prune as prune - print('Pruning model... ', end='') - for name, m in model.named_modules(): - if isinstance(m, nn.Conv2d): - prune.l1_unstructured(m, name='weight', amount=amount) # prune - prune.remove(m, 'weight') # make permanent - print(' %.3g global sparsity' % sparsity(model)) - - -def fuse_conv_and_bn(conv, bn): - # Fuse convolution and batchnorm layers https://tehnokv.com/posts/fusing-batchnorm-and-conv/ - fusedconv = nn.Conv2d(conv.in_channels, - conv.out_channels, - kernel_size=conv.kernel_size, - stride=conv.stride, - padding=conv.padding, - groups=conv.groups, - bias=True).requires_grad_(False).to(conv.weight.device) - - # prepare filters - w_conv = conv.weight.clone().view(conv.out_channels, -1) - w_bn = torch.diag(bn.weight.div(torch.sqrt(bn.eps + bn.running_var))) - fusedconv.weight.copy_(torch.mm(w_bn, w_conv).view(fusedconv.weight.size())) - - # prepare spatial bias - b_conv = torch.zeros(conv.weight.size(0), device=conv.weight.device) if conv.bias is None else conv.bias - b_bn = bn.bias - bn.weight.mul(bn.running_mean).div(torch.sqrt(bn.running_var + bn.eps)) - fusedconv.bias.copy_(torch.mm(w_bn, b_conv.reshape(-1, 1)).reshape(-1) + b_bn) - - return fusedconv - - -def model_info(model, verbose=False, img_size=640): - # Model information. img_size may be int or list, i.e. img_size=640 or img_size=[640, 320] - n_p = sum(x.numel() for x in model.parameters()) # number parameters - n_g = sum(x.numel() for x in model.parameters() if x.requires_grad) # number gradients - if verbose: - print('%5s %40s %9s %12s %20s %10s %10s' % ('layer', 'name', 'gradient', 'parameters', 'shape', 'mu', 'sigma')) - for i, (name, p) in enumerate(model.named_parameters()): - name = name.replace('module_list.', '') - print('%5g %40s %9s %12g %20s %10.3g %10.3g' % - (i, name, p.requires_grad, p.numel(), list(p.shape), p.mean(), p.std())) - - try: # FLOPS - from thop import profile - flops = profile(deepcopy(model), inputs=(torch.zeros(1, 3, img_size, img_size),), verbose=False)[0] / 1E9 * 2 - img_size = img_size if isinstance(img_size, list) else [img_size, img_size] # expand if int/float - fs = ', %.9f GFLOPS' % (flops) # 640x640 FLOPS - except (ImportError, Exception): - fs = '' - - logger.info(f"Model Summary: {len(list(model.modules()))} layers, {n_p} parameters, {n_g} gradients{fs}") - - -def load_classifier(name='resnet101', n=2): - # Loads a pretrained model reshaped to n-class output - model = torchvision.models.__dict__[name](pretrained=True) - - # ResNet model properties - # input_size = [3, 224, 224] - # input_space = 'RGB' - # input_range = [0, 1] - # mean = [0.485, 0.456, 0.406] - # std = [0.229, 0.224, 0.225] - - # Reshape output to n classes - filters = model.fc.weight.shape[1] - model.fc.bias = nn.Parameter(torch.zeros(n), requires_grad=True) - model.fc.weight = nn.Parameter(torch.zeros(n, filters), requires_grad=True) - model.fc.out_features = n - return model - - -def scale_img(img, ratio=1.0, same_shape=False): # img(16,3,256,416), r=ratio - # scales img(bs,3,y,x) by ratio - if ratio == 1.0: - return img - else: - h, w = img.shape[2:] - s = (int(h * ratio), int(w * ratio)) # new size - img = F.interpolate(img, size=s, mode='bilinear', align_corners=False) # resize - if not same_shape: # pad/crop img - gs = 64 # (pixels) grid size - h, w = [math.ceil(x * ratio / gs) * gs for x in (h, w)] - return F.pad(img, [0, w - s[1], 0, h - s[0]], value=0.447) # value = imagenet mean - - -def copy_attr(a, b, include=(), exclude=()): - # Copy attributes from b to a, options to only include [...] and to exclude [...] - for k, v in b.__dict__.items(): - if (len(include) and k not in include) or k.startswith('_') or k in exclude: - continue - else: - setattr(a, k, v) - - -class ModelEMA: - """ Model Exponential Moving Average from https://github.com/rwightman/pytorch-image-models - Keep a moving average of everything in the model state_dict (parameters and buffers). - This is intended to allow functionality like - https://www.tensorflow.org/api_docs/python/tf/train/ExponentialMovingAverage - A smoothed version of the weights is necessary for some training schemes to perform well. - This class is sensitive where it is initialized in the sequence of model init, - GPU assignment and distributed training wrappers. - """ - - def __init__(self, model, decay=0.9999, updates=0): - # Create EMA - self.ema = deepcopy(model.module if is_parallel(model) else model).eval() # FP32 EMA - # if next(model.parameters()).device.type != 'cpu': - # self.ema.half() # FP16 EMA - self.updates = updates # number of EMA updates - self.decay = lambda x: decay * (1 - math.exp(-x / 2000)) # decay exponential ramp (to help early epochs) - for p in self.ema.parameters(): - p.requires_grad_(False) - - self.is_fused = False - - - def update(self, model, x, model_params_fused=None): - # Update EMA parameters - with torch.no_grad(): - self.updates += 1 - d = self.decay(self.updates) - - if x.device.type == 'npu': - # if False: - from apex.contrib.combine_tensors import combine_npu - d_inv = 1. - d - d = torch.tensor([d], device=x.device) - - if not self.is_fused: - pg0, pg1, pg2 = [], [], [] # optimizer parameters groups - - # this process needs special attention, the order of params should be identical to model - for name, p in self.ema.named_parameters(): - if p.dtype.is_floating_point: - if '.bias' in name: - pg2.append(p) # biases - elif 'Conv2d.weight' in name: - pg1.append(p) # apply weight_decay - elif 'm.weight' in name: - pg1.append(p) # apply weight_decay - elif 'w.weight' in name: - pg1.append(p) # apply weight_decay - else: - pg0.append(p) # all else - ema_all_params = pg0 + pg1 + pg2 - self.ema_params_fused = combine_npu(ema_all_params) - - ema_all_buffers = [] - for name, b in self.ema.named_buffers(): - if b.dtype.is_floating_point: - ema_all_buffers.append(b) - else: - continue - self.ema_buffers_fused = combine_npu(ema_all_buffers) - - model_all_buffers = [] - for name, b in model.named_buffers(): - if b.dtype.is_floating_point: - model_all_buffers.append(b) - else: - continue - self.model_buffers_fused = combine_npu(model_all_buffers) - - self.is_fused = True - - self.ema_params_fused *= d - self.ema_params_fused.add_(model_params_fused, alpha=d_inv) - - self.ema_buffers_fused *= d - self.ema_buffers_fused.add_(self.model_buffers_fused, alpha=d_inv) - - else: - msd = model.module.state_dict() if is_parallel(model) else model.state_dict() # model state_dict - for k, v in self.ema.state_dict().items(): - if v.dtype.is_floating_point: - v *= d - v += (1. - d) * msd[k].detach() - - def update_attr(self, model, include=(), exclude=('process_group', 'reducer')): - # Update EMA attributes - copy_attr(self.ema, model, include, exclude) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +# PyTorch utils + +import logging +import math +import os +import time +from contextlib import contextmanager +from copy import deepcopy + +import torch +import torch.backends.cudnn as cudnn +import torch.nn as nn +import torch.nn.functional as F +import torchvision + +logger = logging.getLogger(__name__) + + +@contextmanager +def torch_distributed_zero_first(local_rank: int): + """ + Decorator to make all processes in distributed training wait for each local_master to do something. + """ + if local_rank not in [-1, 0]: + torch.distributed.barrier() + yield + if local_rank == 0: + torch.distributed.barrier() + + +def init_torch_seeds(seed=0): + # Speed-reproducibility tradeoff https://pytorch.org/docs/stable/notes/randomness.html + torch.manual_seed(seed) + if seed == 0: # slower, more reproducible + cudnn.deterministic = True + cudnn.benchmark = False + else: # faster, less reproducible + cudnn.deterministic = False + cudnn.benchmark = True + + +def select_device(device='', npu='', apex=False, batch_size=None): + npu_request = device.lower() == 'npu' + if npu_request and npu != -1: + torch.npu.set_device("npu:%d" % npu) + print('Using NPU %d to train' % npu) + return torch.device("npu:%d" % npu) + # device = 'cpu' or '0' or '0,1,2,3' + cpu_request = device.lower() == 'cpu' + if device and not cpu_request: # if device requested other than 'cpu' + os.environ['CUDA_VISIBLE_DEVICES'] = device # set environment variable + assert torch.cuda.is_available(), 'CUDA unavailable, invalid device %s requested' % device # check availablity + + cuda = False if cpu_request else torch.cuda.is_available() + if cuda: + c = 1024 ** 2 # bytes to MB + ng = torch.cuda.device_count() + if ng > 1 and batch_size: # check that batch_size is compatible with device_count + assert batch_size % ng == 0, 'batch-size %g not multiple of GPU count %g' % (batch_size, ng) + x = [torch.cuda.get_device_properties(i) for i in range(ng)] + s = 'Using CUDA ' + ('Apex ' if apex else '') # apex for mixed precision https://github.com/NVIDIA/apex + for i in range(0, ng): + if i == 1: + s = ' ' * len(s) + print("%sdevice%g _CudaDeviceProperties(name='%s', total_memory=%dMB)" % + (s, i, x[i].name, x[i].total_memory / c)) + else: + print('Using CPU') + + print('') # skip a line + return torch.device('cuda:0' if cuda else 'cpu') + + +def time_synchronized(): + torch.cuda.synchronize() if torch.cuda.is_available() else None + return time.time() + + +def is_parallel(model): + return type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) + + +def intersect_dicts(da, db, exclude=()): + # Dictionary intersection of matching keys and shapes, omitting 'exclude' keys, using da values + return {k: v for k, v in da.items() if k in db and not any(x in k for x in exclude) and v.shape == db[k].shape} + + +def initialize_weights(model): + for m in model.modules(): + t = type(m) + if t is nn.Conv2d: + pass # nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') + elif t is nn.BatchNorm2d: + m.eps = 1e-3 + m.momentum = 0.03 + elif t in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6]: + m.inplace = True + + +def find_modules(model, mclass=nn.Conv2d): + # Finds layer indices matching module class 'mclass' + return [i for i, m in enumerate(model.module_list) if isinstance(m, mclass)] + + +def sparsity(model): + # Return global model sparsity + a, b = 0., 0. + for p in model.parameters(): + a += p.numel() + b += (p == 0).sum() + return b / a + + +def prune(model, amount=0.3): + # Prune model to requested global sparsity + import torch.nn.utils.prune as prune + print('Pruning model... ', end='') + for name, m in model.named_modules(): + if isinstance(m, nn.Conv2d): + prune.l1_unstructured(m, name='weight', amount=amount) # prune + prune.remove(m, 'weight') # make permanent + print(' %.3g global sparsity' % sparsity(model)) + + +def fuse_conv_and_bn(conv, bn): + # Fuse convolution and batchnorm layers https://tehnokv.com/posts/fusing-batchnorm-and-conv/ + fusedconv = nn.Conv2d(conv.in_channels, + conv.out_channels, + kernel_size=conv.kernel_size, + stride=conv.stride, + padding=conv.padding, + groups=conv.groups, + bias=True).requires_grad_(False).to(conv.weight.device) + + # prepare filters + w_conv = conv.weight.clone().view(conv.out_channels, -1) + w_bn = torch.diag(bn.weight.div(torch.sqrt(bn.eps + bn.running_var))) + fusedconv.weight.copy_(torch.mm(w_bn, w_conv).view(fusedconv.weight.size())) + + # prepare spatial bias + b_conv = torch.zeros(conv.weight.size(0), device=conv.weight.device) if conv.bias is None else conv.bias + b_bn = bn.bias - bn.weight.mul(bn.running_mean).div(torch.sqrt(bn.running_var + bn.eps)) + fusedconv.bias.copy_(torch.mm(w_bn, b_conv.reshape(-1, 1)).reshape(-1) + b_bn) + + return fusedconv + + +def model_info(model, verbose=False, img_size=640): + # Model information. img_size may be int or list, i.e. img_size=640 or img_size=[640, 320] + n_p = sum(x.numel() for x in model.parameters()) # number parameters + n_g = sum(x.numel() for x in model.parameters() if x.requires_grad) # number gradients + if verbose: + print('%5s %40s %9s %12s %20s %10s %10s' % ('layer', 'name', 'gradient', 'parameters', 'shape', 'mu', 'sigma')) + for i, (name, p) in enumerate(model.named_parameters()): + name = name.replace('module_list.', '') + print('%5g %40s %9s %12g %20s %10.3g %10.3g' % + (i, name, p.requires_grad, p.numel(), list(p.shape), p.mean(), p.std())) + + try: # FLOPS + from thop import profile + flops = profile(deepcopy(model), inputs=(torch.zeros(1, 3, img_size, img_size),), verbose=False)[0] / 1E9 * 2 + img_size = img_size if isinstance(img_size, list) else [img_size, img_size] # expand if int/float + fs = ', %.9f GFLOPS' % (flops) # 640x640 FLOPS + except (ImportError, Exception): + fs = '' + + logger.info(f"Model Summary: {len(list(model.modules()))} layers, {n_p} parameters, {n_g} gradients{fs}") + + +def load_classifier(name='resnet101', n=2): + # Loads a pretrained model reshaped to n-class output + model = torchvision.models.__dict__[name](pretrained=True) + + # ResNet model properties + # input_size = [3, 224, 224] + # input_space = 'RGB' + # input_range = [0, 1] + # mean = [0.485, 0.456, 0.406] + # std = [0.229, 0.224, 0.225] + + # Reshape output to n classes + filters = model.fc.weight.shape[1] + model.fc.bias = nn.Parameter(torch.zeros(n), requires_grad=True) + model.fc.weight = nn.Parameter(torch.zeros(n, filters), requires_grad=True) + model.fc.out_features = n + return model + + +def scale_img(img, ratio=1.0, same_shape=False): # img(16,3,256,416), r=ratio + # scales img(bs,3,y,x) by ratio + if ratio == 1.0: + return img + else: + h, w = img.shape[2:] + s = (int(h * ratio), int(w * ratio)) # new size + img = F.interpolate(img, size=s, mode='bilinear', align_corners=False) # resize + if not same_shape: # pad/crop img + gs = 64 # (pixels) grid size + h, w = [math.ceil(x * ratio / gs) * gs for x in (h, w)] + return F.pad(img, [0, w - s[1], 0, h - s[0]], value=0.447) # value = imagenet mean + + +def copy_attr(a, b, include=(), exclude=()): + # Copy attributes from b to a, options to only include [...] and to exclude [...] + for k, v in b.__dict__.items(): + if (len(include) and k not in include) or k.startswith('_') or k in exclude: + continue + else: + setattr(a, k, v) + + +class ModelEMA: + """ Model Exponential Moving Average from https://github.com/rwightman/pytorch-image-models + Keep a moving average of everything in the model state_dict (parameters and buffers). + This is intended to allow functionality like + https://www.tensorflow.org/api_docs/python/tf/train/ExponentialMovingAverage + A smoothed version of the weights is necessary for some training schemes to perform well. + This class is sensitive where it is initialized in the sequence of model init, + GPU assignment and distributed training wrappers. + """ + + def __init__(self, model, decay=0.9999, updates=0): + # Create EMA + self.ema = deepcopy(model.module if is_parallel(model) else model).eval() # FP32 EMA + # if next(model.parameters()).device.type != 'cpu': + # self.ema.half() # FP16 EMA + self.updates = updates # number of EMA updates + self.decay = lambda x: decay * (1 - math.exp(-x / 2000)) # decay exponential ramp (to help early epochs) + for p in self.ema.parameters(): + p.requires_grad_(False) + + self.is_fused = False + + + def update(self, model, x, model_params_fused=None): + # Update EMA parameters + with torch.no_grad(): + self.updates += 1 + d = self.decay(self.updates) + + if x.device.type == 'npu': + # if False: + from apex.contrib.combine_tensors import combine_npu + d_inv = 1. - d + d = torch.tensor([d], device=x.device) + + if not self.is_fused: + pg0, pg1, pg2 = [], [], [] # optimizer parameters groups + + # this process needs special attention, the order of params should be identical to model + for name, p in self.ema.named_parameters(): + if p.dtype.is_floating_point: + if '.bias' in name: + pg2.append(p) # biases + elif 'Conv2d.weight' in name: + pg1.append(p) # apply weight_decay + elif 'm.weight' in name: + pg1.append(p) # apply weight_decay + elif 'w.weight' in name: + pg1.append(p) # apply weight_decay + else: + pg0.append(p) # all else + ema_all_params = pg0 + pg1 + pg2 + self.ema_params_fused = combine_npu(ema_all_params) + + ema_all_buffers = [] + for name, b in self.ema.named_buffers(): + if b.dtype.is_floating_point: + ema_all_buffers.append(b) + else: + continue + self.ema_buffers_fused = combine_npu(ema_all_buffers) + + model_all_buffers = [] + for name, b in model.named_buffers(): + if b.dtype.is_floating_point: + model_all_buffers.append(b) + else: + continue + self.model_buffers_fused = combine_npu(model_all_buffers) + + self.is_fused = True + + self.ema_params_fused *= d + self.ema_params_fused.add_(model_params_fused, alpha=d_inv) + + self.ema_buffers_fused *= d + self.ema_buffers_fused.add_(self.model_buffers_fused, alpha=d_inv) + + else: + msd = model.module.state_dict() if is_parallel(model) else model.state_dict() # model state_dict + for k, v in self.ema.state_dict().items(): + if v.dtype.is_floating_point: + v *= d + v += (1. - d) * msd[k].detach() + + def update_attr(self, model, include=(), exclude=('process_group', 'reducer')): + # Update EMA attributes + copy_attr(self.ema, model, include, exclude) diff --git a/PyTorch/contrib/cv/detection/centernet2/README.CN.md b/PyTorch/contrib/cv/detection/centernet2/README.CN.md index 0737bf97bf..45a8eb89e7 100644 --- a/PyTorch/contrib/cv/detection/centernet2/README.CN.md +++ b/PyTorch/contrib/cv/detection/centernet2/README.CN.md @@ -1,120 +1,120 @@ -# CenterNet2 - -本项目实现了 CenterNet2 在 NPU 上的训练. -[CenterNet2 github链接](https://github.com/xingyizhou/CenterNet2) - -## 1.CenterNet2 Detail - -本项目对 CenterNet2 做了如下更改: -1. 迁移到 NPU 上 -2. 使用混合精度训练、测试 -3. 对于一些操作,固定动态 shape 、使用 NPU 算子优化性能、同时将一些操作转移到 CPU 上进行 - - -## 2.Requirements -### 2.1 安装NPU软件 - -* NPU配套的run包安装 -* PyTorch(NPU版本) -* apex(NPU版本) - -### 2.2 安装第三方软件 - -(1) 通过pip 安装部分第三方软件: - -``` -pip3 install -r requirements.txt -``` - -(2) 安装opencv - -``` -pip install opencv-python -``` - -(3) 编译安装torchvision - -``` -git clone https://github.com/pytorch/vision -cd vision -git checkout v0.6.0 -python3 setup.py install -``` - -**注:您必须编译安装torchvision,直接使用pip安装训练将无法启动** - -(4) 编译detectron2 - -进入模型脚本根目录,编译detectron2 - -``` -python3 setup.py build develop -``` - - -(5) 下载预训练模型 R-50.pkl ,projects/CenterNet2/configs/Base-CenterNet2.yaml配置文件中MODEL.WEIGHTS 设置为R-101.pkl的绝对路径 -## 3.Dataset - -(1) 下载coco2017数据集; - -(2) 解压数据集,解压后的目录结构如下 -``` -│ ├── coco -│ ├── annotations -│ ├── train2017 -│ ├── val2017 -``` -(3) 通过设置环境变量DETECTRON2_DATASETS=“coco 所在数据集路径”进行设置,如 export DETECTRON2_DATASETS=/home/,则 coco 数据集放在 /home/ 目录中 - -## 4.Training - -### 4.1 NPU 1P - -在模型根目录下,运行 train_full_1p.sh,同时传入参数--data_path,指定为coco数据集的路径父路径(例如数据集路径为/home/coco,则--data_path=/home) - -``` -bash ./test/train_full_1p.sh --data_path=/home -``` -模型训练结束后,会在result/CenterNet2/CenterNet2_R50_1x目录下保存模型文件model_final.pth,训练结束后若要评估精度需运行eval脚本,参考第6节 - -### 4.2 NPU 8P - -在模型根目录下,运行 train_full_8p.sh,同时传入参数--data_path,指定为coco数据集的路径父路径(例如数据集路径为/home/coco,则--data_path=/home) - -``` -bash ./test/train_full_8p.sh --data_path=/home -``` - -模型训练结束后,会在result/CenterNet2/CenterNet2_R50_1x目录下保存模型文件model_final.pth,训练结束后若要评估精度需运行eval脚本,参考第6节 - -## 5.Finetune - -请将projects/CenterNet2/configs/Base-CenterNet2.yaml中的字段WEIGHTS修改为第3节中model_final.pth的绝对路径,如修改为 -``` -WEIGHTS: "/home/CenterNet2/result/CenterNet2/CenterNet2_R50_1x/model_final.pth" -``` -然后启动评估脚本 - -``` -bash ./test/train_finetune_1p.sh --data_path=/home -``` - -## 6.评估 -训练结束后,需要手动启动评估程序。请将projects/CenterNet2/configs/Base-CenterNet2.yaml中的字段WEIGHTS修改为第3节中model_final.pth的绝对路径,如修改为 -``` -WEIGHTS: "/home/CenterNet2/result/CenterNet2/CenterNet2_R50_1x/model_final.pth" -``` - -然后启动评估脚本 - -``` -bash ./test/train_eval_1p.sh --data_path=/home -``` -## CenterNet2 Result - -| 名称 | 精度 | 性能 | -| ------ | ----- | -------- | -| GPU-1p | - | 12.3fps | -| NPU-1p | - | 2.86 fps | -| GPU-8p | 43.68 | 90.5fps | +# CenterNet2 + +本项目实现了 CenterNet2 在 NPU 上的训练. +[CenterNet2 github链接](https://github.com/xingyizhou/CenterNet2) + +## 1.CenterNet2 Detail + +本项目对 CenterNet2 做了如下更改: +1. 迁移到 NPU 上 +2. 使用混合精度训练、测试 +3. 对于一些操作,固定动态 shape 、使用 NPU 算子优化性能、同时将一些操作转移到 CPU 上进行 + + +## 2.Requirements +### 2.1 安装NPU软件 + +* NPU配套的run包安装 +* PyTorch(NPU版本) +* apex(NPU版本) + +### 2.2 安装第三方软件 + +(1) 通过pip 安装部分第三方软件: + +``` +pip3 install -r requirements.txt +``` + +(2) 安装opencv + +``` +pip install opencv-python +``` + +(3) 编译安装torchvision + +``` +git clone https://github.com/pytorch/vision +cd vision +git checkout v0.6.0 +python3 setup.py install +``` + +**注:您必须编译安装torchvision,直接使用pip安装训练将无法启动** + +(4) 编译detectron2 + +进入模型脚本根目录,编译detectron2 + +``` +python3 setup.py build develop +``` + + +(5) 下载预训练模型 R-50.pkl ,projects/CenterNet2/configs/Base-CenterNet2.yaml配置文件中MODEL.WEIGHTS 设置为R-101.pkl的绝对路径 +## 3.Dataset + +(1) 下载coco2017数据集; + +(2) 解压数据集,解压后的目录结构如下 +``` +│ ├── coco +│ ├── annotations +│ ├── train2017 +│ ├── val2017 +``` +(3) 通过设置环境变量DETECTRON2_DATASETS=“coco 所在数据集路径”进行设置,如 export DETECTRON2_DATASETS=/home/,则 coco 数据集放在 /home/ 目录中 + +## 4.Training + +### 4.1 NPU 1P + +在模型根目录下,运行 train_full_1p.sh,同时传入参数--data_path,指定为coco数据集的路径父路径(例如数据集路径为/home/coco,则--data_path=/home) + +``` +bash ./test/train_full_1p.sh --data_path=/home +``` +模型训练结束后,会在result/CenterNet2/CenterNet2_R50_1x目录下保存模型文件model_final.pth,训练结束后若要评估精度需运行eval脚本,参考第6节 + +### 4.2 NPU 8P + +在模型根目录下,运行 train_full_8p.sh,同时传入参数--data_path,指定为coco数据集的路径父路径(例如数据集路径为/home/coco,则--data_path=/home) + +``` +bash ./test/train_full_8p.sh --data_path=/home +``` + +模型训练结束后,会在result/CenterNet2/CenterNet2_R50_1x目录下保存模型文件model_final.pth,训练结束后若要评估精度需运行eval脚本,参考第6节 + +## 5.Finetune + +请将projects/CenterNet2/configs/Base-CenterNet2.yaml中的字段WEIGHTS修改为第3节中model_final.pth的绝对路径,如修改为 +``` +WEIGHTS: "/home/CenterNet2/result/CenterNet2/CenterNet2_R50_1x/model_final.pth" +``` +然后启动评估脚本 + +``` +bash ./test/train_finetune_1p.sh --data_path=/home +``` + +## 6.评估 +训练结束后,需要手动启动评估程序。请将projects/CenterNet2/configs/Base-CenterNet2.yaml中的字段WEIGHTS修改为第3节中model_final.pth的绝对路径,如修改为 +``` +WEIGHTS: "/home/CenterNet2/result/CenterNet2/CenterNet2_R50_1x/model_final.pth" +``` + +然后启动评估脚本 + +``` +bash ./test/train_eval_1p.sh --data_path=/home +``` +## CenterNet2 Result + +| 名称 | 精度 | 性能 | +| ------ | ----- | -------- | +| GPU-1p | - | 12.3fps | +| NPU-1p | - | 2.86 fps | +| GPU-8p | 43.68 | 90.5fps | | NPU-8p | 43.5 | 18.7fps | \ No newline at end of file diff --git a/PyTorch/contrib/cv/detection/centernet2/requirements.txt b/PyTorch/contrib/cv/detection/centernet2/requirements.txt index f2e8ae6b48..5642e4abe9 100644 --- a/PyTorch/contrib/cv/detection/centernet2/requirements.txt +++ b/PyTorch/contrib/cv/detection/centernet2/requirements.txt @@ -1,17 +1,17 @@ -numpy -decorator==5.1.0 -sympy==1.9 -termcolor>=1.1 -Pillow>=8.4.0 -yacs>=0.1.6 -tabulate -cloudpickle -matplotlib -tqdm>4.29.0 -tensorboard -fvcore -iopath>=0.1.2 -pycocotools>=2.0.2 -future -pydot -omegaconf +numpy +decorator==5.1.0 +sympy==1.9 +termcolor>=1.1 +Pillow>=8.4.0 +yacs>=0.1.6 +tabulate +cloudpickle +matplotlib +tqdm>4.29.0 +tensorboard +fvcore +iopath>=0.1.2 +pycocotools>=2.0.2 +future +pydot +omegaconf diff --git a/PyTorch/contrib/cv/others/ADNet/LICENSE b/PyTorch/contrib/cv/others/ADNet/LICENSE index 29f81d812f..261eeb9e9f 100644 --- a/PyTorch/contrib/cv/others/ADNet/LICENSE +++ b/PyTorch/contrib/cv/others/ADNet/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/PyTorch/contrib/cv/others/ADNet/README.md b/PyTorch/contrib/cv/others/ADNet/README.md index a2bc84b397..9fd16c6d62 100644 --- a/PyTorch/contrib/cv/others/ADNet/README.md +++ b/PyTorch/contrib/cv/others/ADNet/README.md @@ -1,167 +1,167 @@ -# ADNet训练 - -``` -## Atention-guided CNN for image denoising(ADNet)by Chunwei Tian, Yong Xu, Zuoyong Li, Wangmeng Zuo, Lunke Fei and Hong Liu is publised by Neural Networks (IF:8.05), 2020 (https://www.sciencedirect.com/science/article/pii/S0893608019304241) and it is implemented by Pytorch. - - -## This paper is pushed on home page of the Nueral Networks. Also, it is reported by wechat public accounts at https://mp.weixin.qq.com/s/Debh7PZSFTBtOVxpFh9yfQ and https://wx.zsxq.com/mweb/views/topicdetail/topicdetail.html?topic_id=548112815452544&group_id=142181451122&user_id=28514284588581&from=timeline. - -## This paper is the first paper via deep network properties for addressing image denoising with complex background. - -## Absract -#### Deep convolutional neural networks (CNNs) have attracted considerable interest in low-level computer vision. Researches are usually devoted to improving the performance via very deep CNNs. However, as the depth increases, influences of the shallow layers on deep layers are weakened. Inspired by the fact, we propose an attention-guided denoising convolutional neural network (ADNet), mainly including a sparse block (SB), a feature enhancement block (FEB), an attention block (AB) and a reconstruction block (RB) for image denoising. Specifically, the SB makes a tradeoff between performance and efficiency by using dilated and common convolutions to remove the noise. The FEB integrates global and local features information via a long path to enhance the expressive ability of the denoising model. The AB is used to finely extract the noise information hidden in the complex background, which is very effective for complex noisy images, especially real noisy images and bind denoising. Also, the FEB is integrated with the AB to improve the efficiency and reduce the complexity for training a denoising model. Finally, a RB aims to construct the clean image through the obtained noise mapping and the given noisy image. Additionally, comprehensive experiments show that the proposed ADNet performs very well in three tasks (i.e., synthetic and real noisy images, and blind denoising) in terms of both quantitative and qualitative evaluations. The code of ADNet is accessible at https://github.com/hellloxiaotian/ADNet. -``` - -For more detail:https://www.sciencedirect.com/science/article/abs/pii/S0893608019304241 - - - -## Requirements - -use pytorch, you can use pip or conda to install the requirements - -``` -# for pip -cd $project -pip3.7 install -r requirements.txt -CANN 5.0.3.alpha001 -torchvision==0.6.0 -``` - - - -## 数据集准备 - -1.从以下网址获取pristine_images_gray.tar.gz作为训练集 - -https://pan.baidu.com/s/1nkY-b5_mdzliL7Y7N9JQRQ - -2.从以下网址获取BSD68作为标签 - -暂时没有在网上找到免费资源,可以从以下网址付费下载。 - -https://download.csdn.net/download/iteapoy/10902860 - -文件结构如下: - - -``` -ADNET -|-- data -| |-- BSD68 -| |-- pristine_images_gray -| |-- demo_img -| |--result -|-- test -|-- dataset.py -|-- demo.py -|-- models.py -|-- preprocess.py -|-- test.py -|-- train.py -|-- utils.py - -``` - -将数据集按照以上结构放在代码目录下 - -## 处理数据 - -source环境变量 - -``` -source ./test/env.sh -``` - -执行数据预处理脚本,将训练集图片裁剪成50*50的图片用与训练,运行成功会生成train.h5和val.h5文件,预处理需要h5py环境,请自行安装。 - -``` -python3.7.5 preprocess.py --preprocess True --mode S -``` - - - -## TRAIN - -### 单p训练 - -source 环境变量 - -``` -source ./test/env.sh -``` - -性能脚本: - -``` -bash ./test/train_performance_1p.sh -``` - -精度脚本: - -``` -bash ./test/train_full_1p.sh -``` - - - -### 多p训练 - -source 环境变量 - -``` -source ./test/env.sh -``` - -性能脚本: - -``` -bash ./test/train_performance_8p.sh -``` - -精度脚本: - -``` -bash ./test/train_full_8p.sh -``` - -模型保存在 - -运行日志保存至./logssigma25.0_2021-09-05-19-23-13目录下(2021-09-05-19-23-13是运行train.py的时间,会根据当前时间自动更新),其中best_model.pth是在验证集上精度最高的模型。 - -## TEST - -测试精度 - -使用sh文件 - -``` -bash test/eval_1p.sh -``` - -测试之前请指定测试的模型路径。打开./test/eval.sh文件,如下所示: - -``` -python3.7.5 test.py --is_distributed 0 --DeviceID 0 --num_gpus 1 --num_of_layers 17 --logdir logssigma25.0_2021-08-31-19-13-09 --test_data BSD68 --test_noiseL 25 | tee -a eval_1p.log -``` - -请指定需要测试的模型路径,将--logdir参数设置为需要测试的模型目录。 - -## Demo -将一张图片放在./data/demo_img中,将--demo_pth_path设置为训练好的pth文件目录,执行以下程序。模型的运行结果保存在./data/demo_img/result文件夹里。 -``` -python3.7.5 demo.py --DeviceID 0 --num_of_layers 17 --test_noiseL 25 --demo_pth_path logssigma25.0_2021-09-03-10-39-34 -``` - -### 精度对比 - -由于NPU上使用torch.optim.Adam出现loss极大的情况,在使用apex.optimizers.NpuFusedSGD优化器后,loss正常,但是精度会有所损失。 - -| | opt_level | loss_scale | optimizer | PSNR | -| ------ | --------- | ---------- | -------------------------------------------------------- | ----- | -| GPU-8p | o2 | 128 | optim.Adam | 28.98 | -| GPU-8p | o2 | 128 | optim.SGD | 27.83 | -| NPU-8p | 02 | 64 | apex.optimizers.NpuFusedAdam(不稳定,不能稳定复现精度) | 28.92 | -| NPU-8p | o2 | 8 | apex.optimizers.NpuFusedSGD | 28.49 | - +# ADNet训练 + +``` +## Atention-guided CNN for image denoising(ADNet)by Chunwei Tian, Yong Xu, Zuoyong Li, Wangmeng Zuo, Lunke Fei and Hong Liu is publised by Neural Networks (IF:8.05), 2020 (https://www.sciencedirect.com/science/article/pii/S0893608019304241) and it is implemented by Pytorch. + + +## This paper is pushed on home page of the Nueral Networks. Also, it is reported by wechat public accounts at https://mp.weixin.qq.com/s/Debh7PZSFTBtOVxpFh9yfQ and https://wx.zsxq.com/mweb/views/topicdetail/topicdetail.html?topic_id=548112815452544&group_id=142181451122&user_id=28514284588581&from=timeline. + +## This paper is the first paper via deep network properties for addressing image denoising with complex background. + +## Absract +#### Deep convolutional neural networks (CNNs) have attracted considerable interest in low-level computer vision. Researches are usually devoted to improving the performance via very deep CNNs. However, as the depth increases, influences of the shallow layers on deep layers are weakened. Inspired by the fact, we propose an attention-guided denoising convolutional neural network (ADNet), mainly including a sparse block (SB), a feature enhancement block (FEB), an attention block (AB) and a reconstruction block (RB) for image denoising. Specifically, the SB makes a tradeoff between performance and efficiency by using dilated and common convolutions to remove the noise. The FEB integrates global and local features information via a long path to enhance the expressive ability of the denoising model. The AB is used to finely extract the noise information hidden in the complex background, which is very effective for complex noisy images, especially real noisy images and bind denoising. Also, the FEB is integrated with the AB to improve the efficiency and reduce the complexity for training a denoising model. Finally, a RB aims to construct the clean image through the obtained noise mapping and the given noisy image. Additionally, comprehensive experiments show that the proposed ADNet performs very well in three tasks (i.e., synthetic and real noisy images, and blind denoising) in terms of both quantitative and qualitative evaluations. The code of ADNet is accessible at https://github.com/hellloxiaotian/ADNet. +``` + +For more detail:https://www.sciencedirect.com/science/article/abs/pii/S0893608019304241 + + + +## Requirements + +use pytorch, you can use pip or conda to install the requirements + +``` +# for pip +cd $project +pip3.7 install -r requirements.txt +CANN 5.0.3.alpha001 +torchvision==0.6.0 +``` + + + +## 数据集准备 + +1.从以下网址获取pristine_images_gray.tar.gz作为训练集 + +https://pan.baidu.com/s/1nkY-b5_mdzliL7Y7N9JQRQ + +2.从以下网址获取BSD68作为标签 + +暂时没有在网上找到免费资源,可以从以下网址付费下载。 + +https://download.csdn.net/download/iteapoy/10902860 + +文件结构如下: + + +``` +ADNET +|-- data +| |-- BSD68 +| |-- pristine_images_gray +| |-- demo_img +| |--result +|-- test +|-- dataset.py +|-- demo.py +|-- models.py +|-- preprocess.py +|-- test.py +|-- train.py +|-- utils.py + +``` + +将数据集按照以上结构放在代码目录下 + +## 处理数据 + +source环境变量 + +``` +source ./test/env.sh +``` + +执行数据预处理脚本,将训练集图片裁剪成50*50的图片用与训练,运行成功会生成train.h5和val.h5文件,预处理需要h5py环境,请自行安装。 + +``` +python3.7.5 preprocess.py --preprocess True --mode S +``` + + + +## TRAIN + +### 单p训练 + +source 环境变量 + +``` +source ./test/env.sh +``` + +性能脚本: + +``` +bash ./test/train_performance_1p.sh +``` + +精度脚本: + +``` +bash ./test/train_full_1p.sh +``` + + + +### 多p训练 + +source 环境变量 + +``` +source ./test/env.sh +``` + +性能脚本: + +``` +bash ./test/train_performance_8p.sh +``` + +精度脚本: + +``` +bash ./test/train_full_8p.sh +``` + +模型保存在 + +运行日志保存至./logssigma25.0_2021-09-05-19-23-13目录下(2021-09-05-19-23-13是运行train.py的时间,会根据当前时间自动更新),其中best_model.pth是在验证集上精度最高的模型。 + +## TEST + +测试精度 + +使用sh文件 + +``` +bash test/eval_1p.sh +``` + +测试之前请指定测试的模型路径。打开./test/eval.sh文件,如下所示: + +``` +python3.7.5 test.py --is_distributed 0 --DeviceID 0 --num_gpus 1 --num_of_layers 17 --logdir logssigma25.0_2021-08-31-19-13-09 --test_data BSD68 --test_noiseL 25 | tee -a eval_1p.log +``` + +请指定需要测试的模型路径,将--logdir参数设置为需要测试的模型目录。 + +## Demo +将一张图片放在./data/demo_img中,将--demo_pth_path设置为训练好的pth文件目录,执行以下程序。模型的运行结果保存在./data/demo_img/result文件夹里。 +``` +python3.7.5 demo.py --DeviceID 0 --num_of_layers 17 --test_noiseL 25 --demo_pth_path logssigma25.0_2021-09-03-10-39-34 +``` + +### 精度对比 + +由于NPU上使用torch.optim.Adam出现loss极大的情况,在使用apex.optimizers.NpuFusedSGD优化器后,loss正常,但是精度会有所损失。 + +| | opt_level | loss_scale | optimizer | PSNR | +| ------ | --------- | ---------- | -------------------------------------------------------- | ----- | +| GPU-8p | o2 | 128 | optim.Adam | 28.98 | +| GPU-8p | o2 | 128 | optim.SGD | 27.83 | +| NPU-8p | 02 | 64 | apex.optimizers.NpuFusedAdam(不稳定,不能稳定复现精度) | 28.92 | +| NPU-8p | o2 | 8 | apex.optimizers.NpuFusedSGD | 28.49 | + 在NPU上使用apex.optimizers.NpuFusedAdam不能稳定复现精度,有时候会出现loss极大的情况,导致训练失败。 \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/ADNet/demo.py b/PyTorch/contrib/cv/others/ADNet/demo.py index 41907621c3..3403781dcc 100644 --- a/PyTorch/contrib/cv/others/ADNet/demo.py +++ b/PyTorch/contrib/cv/others/ADNet/demo.py @@ -1,111 +1,111 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 cv2 -import os -import argparse -import glob -import numpy as np -from PIL import Image -import torch -import torch.nn as nn -from torch.autograd import Variable -from models import ADNet -from utils import * -from collections import OrderedDict -import torch.distributed as dist - -parser = argparse.ArgumentParser(description="ADNet_Test") -parser.add_argument("--num_of_layers", type=int, default=17, help="Number of total layers") -parser.add_argument("--logdir", type=str, default="logs", help='path of log files') -parser.add_argument("--test_data", type=str, default='BSD68', help='test on Set12 or Set68') -parser.add_argument("--test_noiseL", type=float, default=25, help='noise level used on test set') -parser.add_argument("--DeviceID", type=int, default=0, help='choose a device id to use') -parser.add_argument("--demo_img_path", type=str, default='demo_img') -parser.add_argument("--demo_pth_path", type=str, default='data') -opt = parser.parse_args() - - -def normalize(data): - return data / 255. -def proc_nodes_module(checkpoint): - new_state_dict = OrderedDict() - for k, v in checkpoint.items(): - if "module." in k: - name = k.replace("module.", "") - else: - name = k - new_state_dict[name] = v - return new_state_dict - -def main(): - # Build model - local_device = torch.device(f'npu:{opt.DeviceID}') - torch.npu.set_device(local_device) - print("using npu :{}".format(opt.DeviceID)) - print('Loading model ...\n') - net = ADNet(channels=1, num_of_layers=17) - model = net #model = nn.DataParallel(net, device_ids=device_ids).cuda() - checkpoint = torch.load(os.path.join(opt.demo_pth_path, 'best_model.pth'), map_location=local_device) - checkpoint = proc_nodes_module(checkpoint) - model.load_state_dict(checkpoint) - model = model.npu() - model.eval() - # load data info - print('Loading data info ...\n') - files_source = glob.glob(os.path.join('data', opt.demo_img_path, '*.png')) - files_source.sort() - # process data - psnr_test = 0 - for f in files_source: - # image - Img = cv2.imread(f) - Img = normalize(np.float32(Img[:, :, 0])) - Img = np.expand_dims(Img, 0) - Img = np.expand_dims(Img, 1) - ISource = torch.Tensor(Img) - # noise - torch.manual_seed(0) # set the seed - noise = torch.FloatTensor(ISource.size()).normal_(mean=0, std=opt.test_noiseL / 255.) - # noisy image - INoisy = ISource + noise - ISource = Variable(ISource) - INoisy = Variable(INoisy) - ISource = ISource.npu() - INoisy = INoisy.npu() - with torch.no_grad(): # this can save much memory - Out = torch.clamp(model(INoisy), 0., 1.) - psnr = batch_PSNR(Out, ISource, 1.) - psnr_test += psnr - print("%s PSNR %f" % (f, psnr)) - INoisy = INoisy*255 - INoisy = INoisy.data.cpu().numpy() - INoisy = np.squeeze(INoisy) - Imag_noise = Image.fromarray(INoisy.astype('uint8')) - if not os.path.exists('./data/demo_img/result'): - os.mkdir('./data/demo_img/result') - Imag_noise.save(os.path.join('data', opt.demo_img_path, 'result', 'image_add_noise.png')) - print('original image stored in:', os.path.join('data', opt.demo_img_path)) - print('image added noise stored in:', os.path.join('data', opt.demo_img_path, 'result', 'image_add_noise.png')) - result = Out*255 - result = result.data.cpu().numpy() - result = np.squeeze(result) - result = Image.fromarray(result.astype('uint8')) - result.save(os.path.join('data', opt.demo_img_path, 'result', 'image_after_processing.png')) - print('image denoised stored in:', os.path.join('data', opt.demo_img_path, 'result', 'image_after_processing.png')) - psnr_test /= len(files_source) - print("\nPSNR on demo image %f" % psnr_test) - - -if __name__ == "__main__": - main() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 cv2 +import os +import argparse +import glob +import numpy as np +from PIL import Image +import torch +import torch.nn as nn +from torch.autograd import Variable +from models import ADNet +from utils import * +from collections import OrderedDict +import torch.distributed as dist + +parser = argparse.ArgumentParser(description="ADNet_Test") +parser.add_argument("--num_of_layers", type=int, default=17, help="Number of total layers") +parser.add_argument("--logdir", type=str, default="logs", help='path of log files') +parser.add_argument("--test_data", type=str, default='BSD68', help='test on Set12 or Set68') +parser.add_argument("--test_noiseL", type=float, default=25, help='noise level used on test set') +parser.add_argument("--DeviceID", type=int, default=0, help='choose a device id to use') +parser.add_argument("--demo_img_path", type=str, default='demo_img') +parser.add_argument("--demo_pth_path", type=str, default='data') +opt = parser.parse_args() + + +def normalize(data): + return data / 255. +def proc_nodes_module(checkpoint): + new_state_dict = OrderedDict() + for k, v in checkpoint.items(): + if "module." in k: + name = k.replace("module.", "") + else: + name = k + new_state_dict[name] = v + return new_state_dict + +def main(): + # Build model + local_device = torch.device(f'npu:{opt.DeviceID}') + torch.npu.set_device(local_device) + print("using npu :{}".format(opt.DeviceID)) + print('Loading model ...\n') + net = ADNet(channels=1, num_of_layers=17) + model = net #model = nn.DataParallel(net, device_ids=device_ids).cuda() + checkpoint = torch.load(os.path.join(opt.demo_pth_path, 'best_model.pth'), map_location=local_device) + checkpoint = proc_nodes_module(checkpoint) + model.load_state_dict(checkpoint) + model = model.npu() + model.eval() + # load data info + print('Loading data info ...\n') + files_source = glob.glob(os.path.join('data', opt.demo_img_path, '*.png')) + files_source.sort() + # process data + psnr_test = 0 + for f in files_source: + # image + Img = cv2.imread(f) + Img = normalize(np.float32(Img[:, :, 0])) + Img = np.expand_dims(Img, 0) + Img = np.expand_dims(Img, 1) + ISource = torch.Tensor(Img) + # noise + torch.manual_seed(0) # set the seed + noise = torch.FloatTensor(ISource.size()).normal_(mean=0, std=opt.test_noiseL / 255.) + # noisy image + INoisy = ISource + noise + ISource = Variable(ISource) + INoisy = Variable(INoisy) + ISource = ISource.npu() + INoisy = INoisy.npu() + with torch.no_grad(): # this can save much memory + Out = torch.clamp(model(INoisy), 0., 1.) + psnr = batch_PSNR(Out, ISource, 1.) + psnr_test += psnr + print("%s PSNR %f" % (f, psnr)) + INoisy = INoisy*255 + INoisy = INoisy.data.cpu().numpy() + INoisy = np.squeeze(INoisy) + Imag_noise = Image.fromarray(INoisy.astype('uint8')) + if not os.path.exists('./data/demo_img/result'): + os.mkdir('./data/demo_img/result') + Imag_noise.save(os.path.join('data', opt.demo_img_path, 'result', 'image_add_noise.png')) + print('original image stored in:', os.path.join('data', opt.demo_img_path)) + print('image added noise stored in:', os.path.join('data', opt.demo_img_path, 'result', 'image_add_noise.png')) + result = Out*255 + result = result.data.cpu().numpy() + result = np.squeeze(result) + result = Image.fromarray(result.astype('uint8')) + result.save(os.path.join('data', opt.demo_img_path, 'result', 'image_after_processing.png')) + print('image denoised stored in:', os.path.join('data', opt.demo_img_path, 'result', 'image_after_processing.png')) + psnr_test /= len(files_source) + print("\nPSNR on demo image %f" % psnr_test) + + +if __name__ == "__main__": + main() diff --git a/PyTorch/contrib/cv/others/ADNet/modelzoo_level.txt b/PyTorch/contrib/cv/others/ADNet/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/others/ADNet/modelzoo_level.txt +++ b/PyTorch/contrib/cv/others/ADNet/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/ADNet/preprocess.py b/PyTorch/contrib/cv/others/ADNet/preprocess.py index 906b8a58a2..f6328b1aa6 100644 --- a/PyTorch/contrib/cv/others/ADNet/preprocess.py +++ b/PyTorch/contrib/cv/others/ADNet/preprocess.py @@ -1,64 +1,64 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import argparse - -import torch -import sys -import torch.nn as nn -import torch.optim as optim -import apex.amp as amp -import apex -import logging -from torch.nn.parallel import DistributedDataParallel as DDP -from torch.utils.data.distributed import DistributedSampler -import torch.distributed as dist -import time -from torch.autograd import Variable -from torch.utils.data import DataLoader - -from torch.nn.modules.loss import _Loss -from models import ADNet -from dataset import prepare_data, Dataset -from utils import * - - -parser = argparse.ArgumentParser(description="DnCNN") -parser.add_argument("--preprocess", type=bool, default=False, help='run prepare_data or not') -parser.add_argument("--batchSize", type=int, default=128, help="Training batch size") -parser.add_argument("--num_of_layers", type=int, default=17, help="Number of total layers") -parser.add_argument("--epochs", type=int, default=70, help="Number of training epochs") -parser.add_argument("--milestone", type=int, default=30, help="When to decay learning rate; should be less than epochs") -parser.add_argument("--lr", type=float, default=1e-3, help="Initial learning rate") -parser.add_argument("--outf", type=str, default="logs", help='path of log files') -parser.add_argument("--mode", type=str, default="S", help='with known noise level (S) or blind training (B)') -parser.add_argument("--noiseL", type=float, default=15, help='noise level; ignored when mode=B') -parser.add_argument("--val_noiseL", type=float, default=15, help='noise level used on validation set') -parser.add_argument("--is_distributed", type=int, default=0, help='choose ddp or not') -parser.add_argument('--world_size', default=-1, type=int, help='number of nodes for distributed training') -parser.add_argument('--local_rank', type=int, default=0) -parser.add_argument('--DeviceID', type=str, default="0") -parser.add_argument("--num_gpus", default=1, type=int) -''' -parser.add_argument("--clip",type=float,default=0.005,help='Clipping Gradients. Default=0.4') #tcw201809131446tcw -parser.add_argument("--momentum",default=0.9,type='float',help = 'Momentum, Default:0.9') #tcw201809131447tcw -parser.add_argument("--weight-decay","-wd",default=1e-3,type=float,help='Weight decay, Default:1e-4') #tcw20180913347tcw -''' -opt = parser.parse_args() -if __name__ == "__main__": - if opt.preprocess: - if opt.mode == 'S': - prepare_data(data_path='data', patch_size=50, stride=40, aug_times=1) - if opt.mode == 'B': - prepare_data(data_path='data', patch_size=50, stride=10, aug_times=2) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import argparse + +import torch +import sys +import torch.nn as nn +import torch.optim as optim +import apex.amp as amp +import apex +import logging +from torch.nn.parallel import DistributedDataParallel as DDP +from torch.utils.data.distributed import DistributedSampler +import torch.distributed as dist +import time +from torch.autograd import Variable +from torch.utils.data import DataLoader + +from torch.nn.modules.loss import _Loss +from models import ADNet +from dataset import prepare_data, Dataset +from utils import * + + +parser = argparse.ArgumentParser(description="DnCNN") +parser.add_argument("--preprocess", type=bool, default=False, help='run prepare_data or not') +parser.add_argument("--batchSize", type=int, default=128, help="Training batch size") +parser.add_argument("--num_of_layers", type=int, default=17, help="Number of total layers") +parser.add_argument("--epochs", type=int, default=70, help="Number of training epochs") +parser.add_argument("--milestone", type=int, default=30, help="When to decay learning rate; should be less than epochs") +parser.add_argument("--lr", type=float, default=1e-3, help="Initial learning rate") +parser.add_argument("--outf", type=str, default="logs", help='path of log files') +parser.add_argument("--mode", type=str, default="S", help='with known noise level (S) or blind training (B)') +parser.add_argument("--noiseL", type=float, default=15, help='noise level; ignored when mode=B') +parser.add_argument("--val_noiseL", type=float, default=15, help='noise level used on validation set') +parser.add_argument("--is_distributed", type=int, default=0, help='choose ddp or not') +parser.add_argument('--world_size', default=-1, type=int, help='number of nodes for distributed training') +parser.add_argument('--local_rank', type=int, default=0) +parser.add_argument('--DeviceID', type=str, default="0") +parser.add_argument("--num_gpus", default=1, type=int) +''' +parser.add_argument("--clip",type=float,default=0.005,help='Clipping Gradients. Default=0.4') #tcw201809131446tcw +parser.add_argument("--momentum",default=0.9,type='float',help = 'Momentum, Default:0.9') #tcw201809131447tcw +parser.add_argument("--weight-decay","-wd",default=1e-3,type=float,help='Weight decay, Default:1e-4') #tcw20180913347tcw +''' +opt = parser.parse_args() +if __name__ == "__main__": + if opt.preprocess: + if opt.mode == 'S': + prepare_data(data_path='data', patch_size=50, stride=40, aug_times=1) + if opt.mode == 'B': + prepare_data(data_path='data', patch_size=50, stride=10, aug_times=2) diff --git a/PyTorch/contrib/cv/others/BigGAN/LICENSE b/PyTorch/contrib/cv/others/BigGAN/LICENSE index 753842b672..f49a4e16e6 100644 --- a/PyTorch/contrib/cv/others/BigGAN/LICENSE +++ b/PyTorch/contrib/cv/others/BigGAN/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/BigGAN/datasets.py b/PyTorch/contrib/cv/others/BigGAN/datasets.py index 378f1b336f..751bd97941 100644 --- a/PyTorch/contrib/cv/others/BigGAN/datasets.py +++ b/PyTorch/contrib/cv/others/BigGAN/datasets.py @@ -1,378 +1,378 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ -""" Datasets - This file contains definitions for our CIFAR, ImageFolder, and HDF5 datasets -""" -import os -import os.path -import sys -import numpy as np -import torch.utils.data as data -import torchvision.datasets as dset -from PIL import Image -from tqdm import tqdm - -IMG_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.ppm', '.bmp', '.pgm'] - - -def is_image_file(filename): - """Checks if a file is an image. - - Args: - filename (string): path to a file - - Returns: - bool: True if the filename ends with a known image extension - """ - filename_lower = filename.lower() - return any(filename_lower.endswith(ext) for ext in IMG_EXTENSIONS) - - -def find_classes(dir): - classes = [d for d in os.listdir(dir) if os.path.isdir(os.path.join(dir, d))] - classes.sort() - class_to_idx = {classes[i]: i for i in range(len(classes))} - return classes, class_to_idx - - -def make_dataset(dir, class_to_idx): - images = [] - dir = os.path.expanduser(dir) - for target in tqdm(sorted(os.listdir(dir))): - d = os.path.join(dir, target) - if not os.path.isdir(d): - continue - - for root, _, fnames in sorted(os.walk(d)): - for fname in sorted(fnames): - if is_image_file(fname): - path = os.path.join(root, fname) - item = (path, class_to_idx[target]) - images.append(item) - - return images - - -def pil_loader(path): - # open path as file to avoid ResourceWarning (https://github.com/python-pillow/Pillow/issues/835) - with open(path, 'rb') as f: - img = Image.open(f) - return img.convert('RGB') - - -def accimage_loader(path): - import accimage - try: - return accimage.Image(path) - except IOError: - # Potentially a decoding problem, fall back to PIL.Image - return pil_loader(path) - - -def default_loader(path): - from torchvision import get_image_backend - if get_image_backend() == 'accimage': - return accimage_loader(path) - else: - return pil_loader(path) - - -class ImageFolder(data.Dataset): - """A generic data loader where the images are arranged in this way: :: - - root/dogball/xxx.png - root/dogball/xxy.png - root/dogball/xxz.png - - root/cat/123.png - root/cat/nsdf3.png - root/cat/asd932_.png - - Args: - root (string): Root directory path. - transform (callable, optional): A function/transform that takes in an PIL image - and returns a transformed version. E.g, ``transforms.RandomCrop`` - target_transform (callable, optional): A function/transform that takes in the - target and transforms it. - loader (callable, optional): A function to load an image given its path. - - Attributes: - classes (list): List of the class names. - class_to_idx (dict): Dict with items (class_name, class_index). - imgs (list): List of (image path, class_index) tuples - """ - - def __init__(self, root, transform=None, target_transform=None, - loader=default_loader, load_in_mem=False, - index_filename='imagenet_imgs.npz', **kwargs): - classes, class_to_idx = find_classes(root) - # Load pre-computed image directory walk - if os.path.exists(index_filename): - print('Loading pre-saved Index file %s...' % index_filename) - imgs = np.load(index_filename)['imgs'] - # If first time, walk the folder directory and save the - # results to a pre-computed file. - else: - print('Generating Index file %s...' % index_filename) - imgs = make_dataset(root, class_to_idx) - np.savez_compressed(index_filename, **{'imgs': imgs}) - if len(imgs) == 0: - raise (RuntimeError("Found 0 images in subfolders of: " + root + "\n" - "Supported image extensions are: " + ",".join( - IMG_EXTENSIONS))) - - self.root = root - self.imgs = imgs - self.classes = classes - self.class_to_idx = class_to_idx - self.transform = transform - self.target_transform = target_transform - self.loader = loader - self.load_in_mem = load_in_mem - - if self.load_in_mem: - print('Loading all images into memory...') - self.data, self.labels = [], [] - for index in tqdm(range(len(self.imgs))): - path, target = imgs[index][0], imgs[index][1] - self.data.append(self.transform(self.loader(path))) - self.labels.append(target) - - def __getitem__(self, index): - """ - Args: - index (int): Index - - Returns: - tuple: (image, target) where target is class_index of the target class. - """ - if self.load_in_mem: - img = self.data[index] - target = self.labels[index] - else: - path, target = self.imgs[index] - img = self.loader(str(path)) - if self.transform is not None: - img = self.transform(img) - - if self.target_transform is not None: - target = self.target_transform(target) - - # print(img.size(), target) - return img, int(target) - - def __len__(self): - return len(self.imgs) - - def __repr__(self): - fmt_str = 'Dataset ' + self.__class__.__name__ + '\n' - fmt_str += ' Number of datapoints: {}\n'.format(self.__len__()) - fmt_str += ' Root Location: {}\n'.format(self.root) - tmp = ' Transforms (if any): ' - fmt_str += '{0}{1}\n'.format(tmp, self.transform.__repr__().replace('\n', '\n' + ' ' * len(tmp))) - tmp = ' Target Transforms (if any): ' - fmt_str += '{0}{1}'.format(tmp, self.target_transform.__repr__().replace('\n', '\n' + ' ' * len(tmp))) - return fmt_str - - -''' ILSVRC_HDF5: A dataset to support I/O from an HDF5 to avoid - having to load individual images all the time. ''' -import h5py as h5 -import torch - - -class ILSVRC_HDF5(data.Dataset): - def __init__(self, root, transform=None, target_transform=None, - load_in_mem=False, train=True, download=False, validate_seed=0, - val_split=0, **kwargs): # last four are dummies - - self.root = root - self.num_imgs = len(h5.File(root, 'r')['labels']) - - # self.transform = transform - self.target_transform = target_transform - - # Set the transform here - self.transform = transform - - # load the entire dataset into memory? - self.load_in_mem = load_in_mem - - # If loading into memory, do so now - if self.load_in_mem: - print('Loading %s into memory...' % root) - with h5.File(root, 'r') as f: - self.data = f['imgs'][:] - self.labels = f['labels'][:] - - def __getitem__(self, index): - """ - Args: - index (int): Index - - Returns: - tuple: (image, target) where target is class_index of the target class. - """ - # If loaded the entire dataset in RAM, get image from memory - if self.load_in_mem: - img = self.data[index] - target = self.labels[index] - - # Else load it from disk - else: - with h5.File(self.root, 'r') as f: - img = f['imgs'][index] - target = f['labels'][index] - - # if self.transform is not None: - # img = self.transform(img) - # Apply my own transform - img = ((torch.from_numpy(img).float() / 255) - 0.5) * 2 - - if self.target_transform is not None: - target = self.target_transform(target) - - return img, int(target) - - def __len__(self): - return self.num_imgs - # return len(self.f['imgs']) - - -import pickle - - -class CIFAR10(dset.CIFAR10): - - def __init__(self, root, train=True, - transform=None, target_transform=None, - download=True, validate_seed=0, - val_split=0, load_in_mem=True, **kwargs): - self.root = os.path.expanduser(root) - self.transform = transform - self.target_transform = target_transform - self.train = train # training set or test set - self.val_split = val_split - - if download: - self.download() - - if not self._check_integrity(): - raise RuntimeError('Dataset not found or corrupted.' + - ' You can use download=True to download it') - - # now load the picked numpy arrays - self.data = [] - self.labels = [] - for fentry in self.train_list: - f = fentry[0] - file = os.path.join(self.root, self.base_folder, f) - fo = open(file, 'rb') - if sys.version_info[0] == 2: - entry = pickle.load(fo) - else: - entry = pickle.load(fo, encoding='latin1') - self.data.append(entry['data']) - if 'labels' in entry: - self.labels += entry['labels'] - else: - self.labels += entry['fine_labels'] - fo.close() - - self.data = np.concatenate(self.data) - # Randomly select indices for validation - if self.val_split > 0: - label_indices = [[] for _ in range(max(self.labels) + 1)] - for i, l in enumerate(self.labels): - label_indices[l] += [i] - label_indices = np.asarray(label_indices) - - # randomly grab 500 elements of each class - np.random.seed(validate_seed) - self.val_indices = [] - for l_i in label_indices: - self.val_indices += list(l_i[np.random.choice(len(l_i), - int(len(self.data) * val_split) // (max(self.labels) + 1), - replace=False)]) - - if self.train == 'validate': - self.data = self.data[self.val_indices] - self.labels = list(np.asarray(self.labels)[self.val_indices]) - - self.data = self.data.reshape((int(50e3 * self.val_split), 3, 32, 32)) - self.data = self.data.transpose((0, 2, 3, 1)) # convert to HWC - - elif self.train: - print(np.shape(self.data)) - if self.val_split > 0: - self.data = np.delete(self.data, self.val_indices, axis=0) - self.labels = list(np.delete(np.asarray(self.labels), self.val_indices, axis=0)) - - self.data = self.data.reshape((int(50e3 * (1. - self.val_split)), 3, 32, 32)) - self.data = self.data.transpose((0, 2, 3, 1)) # convert to HWC - else: - f = self.test_list[0][0] - file = os.path.join(self.root, self.base_folder, f) - fo = open(file, 'rb') - if sys.version_info[0] == 2: - entry = pickle.load(fo) - else: - entry = pickle.load(fo, encoding='latin1') - self.data = entry['data'] - if 'labels' in entry: - self.labels = entry['labels'] - else: - self.labels = entry['fine_labels'] - fo.close() - self.data = self.data.reshape((10000, 3, 32, 32)) - self.data = self.data.transpose((0, 2, 3, 1)) # convert to HWC - - def __getitem__(self, index): - """ - Args: - index (int): Index - Returns: - tuple: (image, target) where target is index of the target class. - """ - img, target = self.data[index], self.labels[index] - - # doing this so that it is consistent with all other datasets - # to return a PIL Image - img = Image.fromarray(img) - - if self.transform is not None: - img = self.transform(img) - - if self.target_transform is not None: - target = self.target_transform(target) - - return img, target - - def __len__(self): - return len(self.data) - - -class CIFAR100(CIFAR10): - base_folder = 'cifar-100-python' - url = "http://www.cs.toronto.edu/~kriz/cifar-100-python.tar.gz" - filename = "cifar-100-python.tar.gz" - tgz_md5 = 'eb9058c3a382ffc7106e4002c42a8d85' - train_list = [ - ['train', '16019d7e3df5f24257cddd939b257f8d'], - ] - - test_list = [ - ['test', 'f0ef6b0ae62326f3e7ffdfab6717acfc'], - ] +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +""" Datasets + This file contains definitions for our CIFAR, ImageFolder, and HDF5 datasets +""" +import os +import os.path +import sys +import numpy as np +import torch.utils.data as data +import torchvision.datasets as dset +from PIL import Image +from tqdm import tqdm + +IMG_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.ppm', '.bmp', '.pgm'] + + +def is_image_file(filename): + """Checks if a file is an image. + + Args: + filename (string): path to a file + + Returns: + bool: True if the filename ends with a known image extension + """ + filename_lower = filename.lower() + return any(filename_lower.endswith(ext) for ext in IMG_EXTENSIONS) + + +def find_classes(dir): + classes = [d for d in os.listdir(dir) if os.path.isdir(os.path.join(dir, d))] + classes.sort() + class_to_idx = {classes[i]: i for i in range(len(classes))} + return classes, class_to_idx + + +def make_dataset(dir, class_to_idx): + images = [] + dir = os.path.expanduser(dir) + for target in tqdm(sorted(os.listdir(dir))): + d = os.path.join(dir, target) + if not os.path.isdir(d): + continue + + for root, _, fnames in sorted(os.walk(d)): + for fname in sorted(fnames): + if is_image_file(fname): + path = os.path.join(root, fname) + item = (path, class_to_idx[target]) + images.append(item) + + return images + + +def pil_loader(path): + # open path as file to avoid ResourceWarning (https://github.com/python-pillow/Pillow/issues/835) + with open(path, 'rb') as f: + img = Image.open(f) + return img.convert('RGB') + + +def accimage_loader(path): + import accimage + try: + return accimage.Image(path) + except IOError: + # Potentially a decoding problem, fall back to PIL.Image + return pil_loader(path) + + +def default_loader(path): + from torchvision import get_image_backend + if get_image_backend() == 'accimage': + return accimage_loader(path) + else: + return pil_loader(path) + + +class ImageFolder(data.Dataset): + """A generic data loader where the images are arranged in this way: :: + + root/dogball/xxx.png + root/dogball/xxy.png + root/dogball/xxz.png + + root/cat/123.png + root/cat/nsdf3.png + root/cat/asd932_.png + + Args: + root (string): Root directory path. + transform (callable, optional): A function/transform that takes in an PIL image + and returns a transformed version. E.g, ``transforms.RandomCrop`` + target_transform (callable, optional): A function/transform that takes in the + target and transforms it. + loader (callable, optional): A function to load an image given its path. + + Attributes: + classes (list): List of the class names. + class_to_idx (dict): Dict with items (class_name, class_index). + imgs (list): List of (image path, class_index) tuples + """ + + def __init__(self, root, transform=None, target_transform=None, + loader=default_loader, load_in_mem=False, + index_filename='imagenet_imgs.npz', **kwargs): + classes, class_to_idx = find_classes(root) + # Load pre-computed image directory walk + if os.path.exists(index_filename): + print('Loading pre-saved Index file %s...' % index_filename) + imgs = np.load(index_filename)['imgs'] + # If first time, walk the folder directory and save the + # results to a pre-computed file. + else: + print('Generating Index file %s...' % index_filename) + imgs = make_dataset(root, class_to_idx) + np.savez_compressed(index_filename, **{'imgs': imgs}) + if len(imgs) == 0: + raise (RuntimeError("Found 0 images in subfolders of: " + root + "\n" + "Supported image extensions are: " + ",".join( + IMG_EXTENSIONS))) + + self.root = root + self.imgs = imgs + self.classes = classes + self.class_to_idx = class_to_idx + self.transform = transform + self.target_transform = target_transform + self.loader = loader + self.load_in_mem = load_in_mem + + if self.load_in_mem: + print('Loading all images into memory...') + self.data, self.labels = [], [] + for index in tqdm(range(len(self.imgs))): + path, target = imgs[index][0], imgs[index][1] + self.data.append(self.transform(self.loader(path))) + self.labels.append(target) + + def __getitem__(self, index): + """ + Args: + index (int): Index + + Returns: + tuple: (image, target) where target is class_index of the target class. + """ + if self.load_in_mem: + img = self.data[index] + target = self.labels[index] + else: + path, target = self.imgs[index] + img = self.loader(str(path)) + if self.transform is not None: + img = self.transform(img) + + if self.target_transform is not None: + target = self.target_transform(target) + + # print(img.size(), target) + return img, int(target) + + def __len__(self): + return len(self.imgs) + + def __repr__(self): + fmt_str = 'Dataset ' + self.__class__.__name__ + '\n' + fmt_str += ' Number of datapoints: {}\n'.format(self.__len__()) + fmt_str += ' Root Location: {}\n'.format(self.root) + tmp = ' Transforms (if any): ' + fmt_str += '{0}{1}\n'.format(tmp, self.transform.__repr__().replace('\n', '\n' + ' ' * len(tmp))) + tmp = ' Target Transforms (if any): ' + fmt_str += '{0}{1}'.format(tmp, self.target_transform.__repr__().replace('\n', '\n' + ' ' * len(tmp))) + return fmt_str + + +''' ILSVRC_HDF5: A dataset to support I/O from an HDF5 to avoid + having to load individual images all the time. ''' +import h5py as h5 +import torch + + +class ILSVRC_HDF5(data.Dataset): + def __init__(self, root, transform=None, target_transform=None, + load_in_mem=False, train=True, download=False, validate_seed=0, + val_split=0, **kwargs): # last four are dummies + + self.root = root + self.num_imgs = len(h5.File(root, 'r')['labels']) + + # self.transform = transform + self.target_transform = target_transform + + # Set the transform here + self.transform = transform + + # load the entire dataset into memory? + self.load_in_mem = load_in_mem + + # If loading into memory, do so now + if self.load_in_mem: + print('Loading %s into memory...' % root) + with h5.File(root, 'r') as f: + self.data = f['imgs'][:] + self.labels = f['labels'][:] + + def __getitem__(self, index): + """ + Args: + index (int): Index + + Returns: + tuple: (image, target) where target is class_index of the target class. + """ + # If loaded the entire dataset in RAM, get image from memory + if self.load_in_mem: + img = self.data[index] + target = self.labels[index] + + # Else load it from disk + else: + with h5.File(self.root, 'r') as f: + img = f['imgs'][index] + target = f['labels'][index] + + # if self.transform is not None: + # img = self.transform(img) + # Apply my own transform + img = ((torch.from_numpy(img).float() / 255) - 0.5) * 2 + + if self.target_transform is not None: + target = self.target_transform(target) + + return img, int(target) + + def __len__(self): + return self.num_imgs + # return len(self.f['imgs']) + + +import pickle + + +class CIFAR10(dset.CIFAR10): + + def __init__(self, root, train=True, + transform=None, target_transform=None, + download=True, validate_seed=0, + val_split=0, load_in_mem=True, **kwargs): + self.root = os.path.expanduser(root) + self.transform = transform + self.target_transform = target_transform + self.train = train # training set or test set + self.val_split = val_split + + if download: + self.download() + + if not self._check_integrity(): + raise RuntimeError('Dataset not found or corrupted.' + + ' You can use download=True to download it') + + # now load the picked numpy arrays + self.data = [] + self.labels = [] + for fentry in self.train_list: + f = fentry[0] + file = os.path.join(self.root, self.base_folder, f) + fo = open(file, 'rb') + if sys.version_info[0] == 2: + entry = pickle.load(fo) + else: + entry = pickle.load(fo, encoding='latin1') + self.data.append(entry['data']) + if 'labels' in entry: + self.labels += entry['labels'] + else: + self.labels += entry['fine_labels'] + fo.close() + + self.data = np.concatenate(self.data) + # Randomly select indices for validation + if self.val_split > 0: + label_indices = [[] for _ in range(max(self.labels) + 1)] + for i, l in enumerate(self.labels): + label_indices[l] += [i] + label_indices = np.asarray(label_indices) + + # randomly grab 500 elements of each class + np.random.seed(validate_seed) + self.val_indices = [] + for l_i in label_indices: + self.val_indices += list(l_i[np.random.choice(len(l_i), + int(len(self.data) * val_split) // (max(self.labels) + 1), + replace=False)]) + + if self.train == 'validate': + self.data = self.data[self.val_indices] + self.labels = list(np.asarray(self.labels)[self.val_indices]) + + self.data = self.data.reshape((int(50e3 * self.val_split), 3, 32, 32)) + self.data = self.data.transpose((0, 2, 3, 1)) # convert to HWC + + elif self.train: + print(np.shape(self.data)) + if self.val_split > 0: + self.data = np.delete(self.data, self.val_indices, axis=0) + self.labels = list(np.delete(np.asarray(self.labels), self.val_indices, axis=0)) + + self.data = self.data.reshape((int(50e3 * (1. - self.val_split)), 3, 32, 32)) + self.data = self.data.transpose((0, 2, 3, 1)) # convert to HWC + else: + f = self.test_list[0][0] + file = os.path.join(self.root, self.base_folder, f) + fo = open(file, 'rb') + if sys.version_info[0] == 2: + entry = pickle.load(fo) + else: + entry = pickle.load(fo, encoding='latin1') + self.data = entry['data'] + if 'labels' in entry: + self.labels = entry['labels'] + else: + self.labels = entry['fine_labels'] + fo.close() + self.data = self.data.reshape((10000, 3, 32, 32)) + self.data = self.data.transpose((0, 2, 3, 1)) # convert to HWC + + def __getitem__(self, index): + """ + Args: + index (int): Index + Returns: + tuple: (image, target) where target is index of the target class. + """ + img, target = self.data[index], self.labels[index] + + # doing this so that it is consistent with all other datasets + # to return a PIL Image + img = Image.fromarray(img) + + if self.transform is not None: + img = self.transform(img) + + if self.target_transform is not None: + target = self.target_transform(target) + + return img, target + + def __len__(self): + return len(self.data) + + +class CIFAR100(CIFAR10): + base_folder = 'cifar-100-python' + url = "http://www.cs.toronto.edu/~kriz/cifar-100-python.tar.gz" + filename = "cifar-100-python.tar.gz" + tgz_md5 = 'eb9058c3a382ffc7106e4002c42a8d85' + train_list = [ + ['train', '16019d7e3df5f24257cddd939b257f8d'], + ] + + test_list = [ + ['test', 'f0ef6b0ae62326f3e7ffdfab6717acfc'], + ] diff --git a/PyTorch/contrib/cv/others/BigGAN/evaluation.py b/PyTorch/contrib/cv/others/BigGAN/evaluation.py index f08855891e..4c6032cc36 100644 --- a/PyTorch/contrib/cv/others/BigGAN/evaluation.py +++ b/PyTorch/contrib/cv/others/BigGAN/evaluation.py @@ -1,86 +1,86 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 functools -import torch -import inception_utils -import utils -from train import get_device_name - - -def evaluation(config): - config['resolution'] = utils.imsize_dict[config['dataset']] - config['n_classes'] = utils.nclass_dict[config['dataset']] - config['G_activation'] = utils.activation_dict[config['G_nl']] - config['D_activation'] = utils.activation_dict[config['D_nl']] - config = utils.update_config_roots(config) - # Seed RNG - utils.seed_rng(config['seed']) - - # By default, skip init if resuming training. - if config['resume']: - print('Skipping initialization for training resumption...') - config['skip_init'] = True - - # init device - device_loc = get_device_name(config['device'], config['gpu']) - config['loc'] = device_loc - # set device - print('set_device ', device_loc) - if config['device'] == 'npu': - torch.npu.set_device(device_loc) - else: - torch.cuda.set_device(config['gpu']) - - # model - # Import the model--this line allows us to dynamically select different files. - model = __import__(config['model']) - # Next, build the model - G = model.Generator(**config).to(device_loc) - - state_dict = {'itr': 0, 'epoch': 0, 'save_num': 0, 'save_best_num': 0, - 'best_IS': 0, 'best_FID': 999999, 'config': config} - - # If loading from a pre-trained model, load weights - if config['resume']: - print('Loading weights...gpu id : ', config['gpu']) - utils.load_weights(G, None, state_dict, - config['weights_root'], config['experiment_name'], - config['load_weights'] if config['load_weights'] else None, - None, root=config['weights_path'], load_optim=False) - print("load weights ok") - - # prepare input - G_batch_size = max(config['G_batch_size'], config['batch_size']) - z_, y_ = utils.prepare_z_y(G_batch_size, G.dim_z, config['n_classes'], device=device_loc) - # Prepare Sample function for use with inception metrics - sample = functools.partial(utils.sample, G=G, z_=z_, y_=y_, config=config) - # Prepare inception metrics: FID and IS - get_inception_metrics = inception_utils.prepare_inception_metrics(config['dataset'], config['parallel'], - config['no_fid'], config['loc'], - config['use_fp16'], config['opt_level']) - if config['G_eval_mode']: - G.eval() - IS_mean, IS_std, FID = get_inception_metrics(sample, config['num_inception_images'], num_splits=10) - log_string = "IS_mean: {:.5f}, IS_std: {:.5f}, FID: {:.5f}".format(IS_mean, IS_std, FID) - print(log_string) - with open("evaluation_log.log", "a+") as f: - f.write("itr: {} , {:s}\n".format(state_dict['itr'], log_string)) - - -if __name__ == "__main__": - # parse command line and run - parser = utils.prepare_parser() - config = vars(parser.parse_args()) - evaluation(config) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 functools +import torch +import inception_utils +import utils +from train import get_device_name + + +def evaluation(config): + config['resolution'] = utils.imsize_dict[config['dataset']] + config['n_classes'] = utils.nclass_dict[config['dataset']] + config['G_activation'] = utils.activation_dict[config['G_nl']] + config['D_activation'] = utils.activation_dict[config['D_nl']] + config = utils.update_config_roots(config) + # Seed RNG + utils.seed_rng(config['seed']) + + # By default, skip init if resuming training. + if config['resume']: + print('Skipping initialization for training resumption...') + config['skip_init'] = True + + # init device + device_loc = get_device_name(config['device'], config['gpu']) + config['loc'] = device_loc + # set device + print('set_device ', device_loc) + if config['device'] == 'npu': + torch.npu.set_device(device_loc) + else: + torch.cuda.set_device(config['gpu']) + + # model + # Import the model--this line allows us to dynamically select different files. + model = __import__(config['model']) + # Next, build the model + G = model.Generator(**config).to(device_loc) + + state_dict = {'itr': 0, 'epoch': 0, 'save_num': 0, 'save_best_num': 0, + 'best_IS': 0, 'best_FID': 999999, 'config': config} + + # If loading from a pre-trained model, load weights + if config['resume']: + print('Loading weights...gpu id : ', config['gpu']) + utils.load_weights(G, None, state_dict, + config['weights_root'], config['experiment_name'], + config['load_weights'] if config['load_weights'] else None, + None, root=config['weights_path'], load_optim=False) + print("load weights ok") + + # prepare input + G_batch_size = max(config['G_batch_size'], config['batch_size']) + z_, y_ = utils.prepare_z_y(G_batch_size, G.dim_z, config['n_classes'], device=device_loc) + # Prepare Sample function for use with inception metrics + sample = functools.partial(utils.sample, G=G, z_=z_, y_=y_, config=config) + # Prepare inception metrics: FID and IS + get_inception_metrics = inception_utils.prepare_inception_metrics(config['dataset'], config['parallel'], + config['no_fid'], config['loc'], + config['use_fp16'], config['opt_level']) + if config['G_eval_mode']: + G.eval() + IS_mean, IS_std, FID = get_inception_metrics(sample, config['num_inception_images'], num_splits=10) + log_string = "IS_mean: {:.5f}, IS_std: {:.5f}, FID: {:.5f}".format(IS_mean, IS_std, FID) + print(log_string) + with open("evaluation_log.log", "a+") as f: + f.write("itr: {} , {:s}\n".format(state_dict['itr'], log_string)) + + +if __name__ == "__main__": + # parse command line and run + parser = utils.prepare_parser() + config = vars(parser.parse_args()) + evaluation(config) diff --git a/PyTorch/contrib/cv/others/BigGAN/modelzoo_level.txt b/PyTorch/contrib/cv/others/BigGAN/modelzoo_level.txt index 5afcef9188..3117fffc3b 100644 --- a/PyTorch/contrib/cv/others/BigGAN/modelzoo_level.txt +++ b/PyTorch/contrib/cv/others/BigGAN/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:NOK +FuncStatus:OK +PerfStatus:NOK PrecisionStatus:POK \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/BigGAN/requirements.txt b/PyTorch/contrib/cv/others/BigGAN/requirements.txt index 5648e61754..3b0b6a7bb2 100644 --- a/PyTorch/contrib/cv/others/BigGAN/requirements.txt +++ b/PyTorch/contrib/cv/others/BigGAN/requirements.txt @@ -1,8 +1,8 @@ -numpy -torchvision -tqdm -h5py -pillow -six -scipy +numpy +torchvision +tqdm +h5py +pillow +six +scipy torch \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/CGAN/LICENSE b/PyTorch/contrib/cv/others/CGAN/LICENSE index 29f81d812f..261eeb9e9f 100644 --- a/PyTorch/contrib/cv/others/CGAN/LICENSE +++ b/PyTorch/contrib/cv/others/CGAN/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/PyTorch/contrib/cv/others/CGAN/README.md b/PyTorch/contrib/cv/others/CGAN/README.md index aa146c4a2c..2a14c1b90f 100644 --- a/PyTorch/contrib/cv/others/CGAN/README.md +++ b/PyTorch/contrib/cv/others/CGAN/README.md @@ -1,130 +1,130 @@ -CGAN训练 - -``` -Generative adversarial nets can be extended to a conditional model if both the generator and discriminator are conditioned on some extra information y. y could be any kind of auxiliary information,such as class labels or data from other modalities. The author perform the conditioning by feeding y into the both the discriminator and generator as additional input layer.In the generator the prior input noise pz(z), and y are combined in joint hidden representation, and the adversarial training framework allows for considerable flexibility in how this hidden representation is composed. In the discriminator x and y are presented as inputs and to a discriminative function. -``` - -For more detail:https://arxiv.org/abs/1411.1784 - -The original gpu code:https://github.com/znxlwm/pytorch-generative-model-collections/ - -## Requirements - -use pytorch, you can use pip or conda to install the requirements - -``` -# for pip -cd $project -pip3.7 install -r requirements.txt -CANN 5.0.3 -torchvision==0.6.0 -``` - - - -## 数据集准备 - -1.下载mnist数据集作为训练集,dataloader.py中有自动下载mnist数据集的代码,执行训练命令会自动调用dataloader.py下载数据集,并保存在“./data/mnist“目录下。(请保持网络通畅) - -文件结构如下: - - -``` -CGAN -|-- data /数据集文件夹 -| |-- mnist /验证集,测试集 -|-- demo /demo.py的输出 -|--models /生成器和判别器模型保存目录 -|-- test /脚本文件夹 -| |--env.sh /环境配置文件 -| |--eval_1p.sh /单卡测试脚本 -| |--train_full_1p.sh /单卡精度测试脚本 -| |--train_full_8p.sh /8卡精度测试脚本 -| |--train_performance_1p.sh /单卡性能测试脚本 -| |--train_performance_8p.sh /8卡性能测试脚本 -|--results /生成器生成图片保存路径 -|-- CGAN.py /模型定义脚本 -|-- demo.py /例子脚本 -|-- dataloaderpy /数据预处理文件 -|-- main.py /主函数,训练启动脚本 -|-- utils.py /其它需要调用的函数脚本 -``` - - - -## TRAIN - -### 单p训练 - -source 环境变量 - -``` -source ./test/env_npu.sh -``` - -性能脚本: - -``` -bash ./test/train_performance_1p.sh -``` - -精度脚本: - -``` -bash ./test/train_full_1p.sh -``` - - - -### 多p训练 - -source 环境变量 - -``` -source ./test/env_npu.sh -``` - -性能脚本: - -``` -bash ./test/train_performance_8p.sh -``` - -精度脚本: - -``` -bash ./test/train_full_8p.sh -``` - -模型保存在”./models“目录下,模型生成的图片保存在”./result“目录下 - -模型训练的loss曲线保存在”./models"目录下。 - -## TEST - -对比GPU和NPU模型生成的图片和训练loss曲线,两者大致一致。 - -| name | Epoch 50 | GIF | Loss | -| :---------- | --------------------------------------------------- | ------------------------------------------------------------ | ----------------------------------------------- | -| CGAN on GPU | ![](README.assets/CGAN_epoch050-16371345386081.png) | ![](README.assets/CGAN_generate_animation-16371345738152.gif) | ![](README.assets/CGAN_loss-16371346002224.png) | -| CGAN on NPU | ![](README.assets/CGAN_epoch050-16371346136555.png) | ![](README.assets/CGAN_generate_animation-16371346226546.gif) | ![](README.assets/CGAN_loss-16371346305157.png) | - -## Pth2onnx - -执行以下命令,完成pth到onnx模型的转换 - -``` -python3.7 pth2onnx.py --pth_path ./models/mnist/CGAN/CGAN_G.pth --onnx_path ./CGAN.onnx -``` - -## Demo - -执行以下命令,程序会自动生成输入并经过网络产生输出,将输出保存在"demo/demo_result.png"中 -``` -python3.7 demo.py --pth_path ./models/mnist/CGAN/CGAN_G.pth --save_path ./demo -``` - -### 精度对比 - -对比GPU和NPU生成的图片和loss曲线,两者差异不大,精度达标。 - +CGAN训练 + +``` +Generative adversarial nets can be extended to a conditional model if both the generator and discriminator are conditioned on some extra information y. y could be any kind of auxiliary information,such as class labels or data from other modalities. The author perform the conditioning by feeding y into the both the discriminator and generator as additional input layer.In the generator the prior input noise pz(z), and y are combined in joint hidden representation, and the adversarial training framework allows for considerable flexibility in how this hidden representation is composed. In the discriminator x and y are presented as inputs and to a discriminative function. +``` + +For more detail:https://arxiv.org/abs/1411.1784 + +The original gpu code:https://github.com/znxlwm/pytorch-generative-model-collections/ + +## Requirements + +use pytorch, you can use pip or conda to install the requirements + +``` +# for pip +cd $project +pip3.7 install -r requirements.txt +CANN 5.0.3 +torchvision==0.6.0 +``` + + + +## 数据集准备 + +1.下载mnist数据集作为训练集,dataloader.py中有自动下载mnist数据集的代码,执行训练命令会自动调用dataloader.py下载数据集,并保存在“./data/mnist“目录下。(请保持网络通畅) + +文件结构如下: + + +``` +CGAN +|-- data /数据集文件夹 +| |-- mnist /验证集,测试集 +|-- demo /demo.py的输出 +|--models /生成器和判别器模型保存目录 +|-- test /脚本文件夹 +| |--env.sh /环境配置文件 +| |--eval_1p.sh /单卡测试脚本 +| |--train_full_1p.sh /单卡精度测试脚本 +| |--train_full_8p.sh /8卡精度测试脚本 +| |--train_performance_1p.sh /单卡性能测试脚本 +| |--train_performance_8p.sh /8卡性能测试脚本 +|--results /生成器生成图片保存路径 +|-- CGAN.py /模型定义脚本 +|-- demo.py /例子脚本 +|-- dataloaderpy /数据预处理文件 +|-- main.py /主函数,训练启动脚本 +|-- utils.py /其它需要调用的函数脚本 +``` + + + +## TRAIN + +### 单p训练 + +source 环境变量 + +``` +source ./test/env_npu.sh +``` + +性能脚本: + +``` +bash ./test/train_performance_1p.sh +``` + +精度脚本: + +``` +bash ./test/train_full_1p.sh +``` + + + +### 多p训练 + +source 环境变量 + +``` +source ./test/env_npu.sh +``` + +性能脚本: + +``` +bash ./test/train_performance_8p.sh +``` + +精度脚本: + +``` +bash ./test/train_full_8p.sh +``` + +模型保存在”./models“目录下,模型生成的图片保存在”./result“目录下 + +模型训练的loss曲线保存在”./models"目录下。 + +## TEST + +对比GPU和NPU模型生成的图片和训练loss曲线,两者大致一致。 + +| name | Epoch 50 | GIF | Loss | +| :---------- | --------------------------------------------------- | ------------------------------------------------------------ | ----------------------------------------------- | +| CGAN on GPU | ![](README.assets/CGAN_epoch050-16371345386081.png) | ![](README.assets/CGAN_generate_animation-16371345738152.gif) | ![](README.assets/CGAN_loss-16371346002224.png) | +| CGAN on NPU | ![](README.assets/CGAN_epoch050-16371346136555.png) | ![](README.assets/CGAN_generate_animation-16371346226546.gif) | ![](README.assets/CGAN_loss-16371346305157.png) | + +## Pth2onnx + +执行以下命令,完成pth到onnx模型的转换 + +``` +python3.7 pth2onnx.py --pth_path ./models/mnist/CGAN/CGAN_G.pth --onnx_path ./CGAN.onnx +``` + +## Demo + +执行以下命令,程序会自动生成输入并经过网络产生输出,将输出保存在"demo/demo_result.png"中 +``` +python3.7 demo.py --pth_path ./models/mnist/CGAN/CGAN_G.pth --save_path ./demo +``` + +### 精度对比 + +对比GPU和NPU生成的图片和loss曲线,两者差异不大,精度达标。 + diff --git a/PyTorch/contrib/cv/others/CGAN/demo.py b/PyTorch/contrib/cv/others/CGAN/demo.py index ee8acb635e..e2f24d6690 100644 --- a/PyTorch/contrib/cv/others/CGAN/demo.py +++ b/PyTorch/contrib/cv/others/CGAN/demo.py @@ -1,103 +1,103 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 collections import OrderedDict -import torch -import torch.nn as nn -from CGAN import generator -import argparse -import os -import numpy as np -import utils - - -def proc_nodes_module(checkpoint): - new_state_dict = OrderedDict() - for k, v in checkpoint.items(): - if "module." in k: - name = k.replace("module.", "") - else: - name = k - new_state_dict[name] = v - return new_state_dict - - -def parse_args(): - desc = "Pytorch implementation of CGAN collections" - parser = argparse.ArgumentParser(description=desc) - parser.add_argument('--input_dim', type=int, default=62, help="The input_dim") - parser.add_argument('--output_dim', type=int, default=3, help="The output_dim") - parser.add_argument('--input_size', type=int, default=28, help="The image size of MNIST") - parser.add_argument('--class_num', type=int, default=10, help="The num of classes of MNIST") - parser.add_argument('--pth_path', type=str, default='CGAN_G.pth', help='pth model path') - parser.add_argument('--onnx_path', type=str, default="CGAN.onnx", help='onnx model path') - parser.add_argument('--save_path', type=str, default='demo', help="the generated image path") - return parser.parse_args() - - -def prep_preocess(args): - sample_num = args.class_num**2 - z_dim = args.input_dim - sample_z_ = torch.zeros((sample_num, z_dim)) - for i in range(args.class_num): - sample_z_[i * args.class_num] = torch.rand(1,z_dim) - for j in range(1, args.class_num): - sample_z_[i * args.class_num + j] = sample_z_[i * args.class_num] - - if not os.path.exists(os.path.join(args.save_path)): - os.makedirs(os.path.join(args.save_path)) - - temp = torch.zeros((args.class_num, 1)) - for i in range(args.class_num): - temp[i, 0] = i - - temp_y = torch.zeros((sample_num, 1)) - for i in range(args.class_num): - temp_y[i * args.class_num: (i + 1) * args.class_num] = temp - - sample_y_ = torch.zeros((sample_num, args.class_num)).scatter_(1, temp_y.type(torch.LongTensor), 1) - - return sample_z_, sample_y_ - - -def main(): - args = parse_args() - # Build model - local_device = torch.device("npu:0") - torch.npu.set_device(local_device) - print("using npu :{}".format(local_device)) - print('Loading model ...\n') - net = generator(input_dim=args.input_dim, output_dim=args.output_dim, - input_size=args.input_size, class_num=args.class_num) - model = net - checkpoint = torch.load(args.pth_path, map_location='cpu') - checkpoint = proc_nodes_module(checkpoint) - model.load_state_dict(checkpoint) - model.eval() - z,y=prep_preocess(args) - result = model(z,y) - result = result.cpu().data.numpy().transpose(0, 2, 3, 1) - result = (result + 1)/2 - sample_num = args.class_num**2 - image_frame_dim = int(np.floor(np.sqrt(sample_num))) - if not os.path.exists(os.path.join(args.save_path)): - os.makedirs(os.path.join(args.save_path)) - utils.save_images(result[:image_frame_dim * image_frame_dim, :, :, :], [image_frame_dim, image_frame_dim], - os.path.join(args.save_path,'demo_result.png')) - print("demo image stored in:", os.path.join(args.save_path,'demo_result.png')) - - -if __name__ == "__main__": +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 collections import OrderedDict +import torch +import torch.nn as nn +from CGAN import generator +import argparse +import os +import numpy as np +import utils + + +def proc_nodes_module(checkpoint): + new_state_dict = OrderedDict() + for k, v in checkpoint.items(): + if "module." in k: + name = k.replace("module.", "") + else: + name = k + new_state_dict[name] = v + return new_state_dict + + +def parse_args(): + desc = "Pytorch implementation of CGAN collections" + parser = argparse.ArgumentParser(description=desc) + parser.add_argument('--input_dim', type=int, default=62, help="The input_dim") + parser.add_argument('--output_dim', type=int, default=3, help="The output_dim") + parser.add_argument('--input_size', type=int, default=28, help="The image size of MNIST") + parser.add_argument('--class_num', type=int, default=10, help="The num of classes of MNIST") + parser.add_argument('--pth_path', type=str, default='CGAN_G.pth', help='pth model path') + parser.add_argument('--onnx_path', type=str, default="CGAN.onnx", help='onnx model path') + parser.add_argument('--save_path', type=str, default='demo', help="the generated image path") + return parser.parse_args() + + +def prep_preocess(args): + sample_num = args.class_num**2 + z_dim = args.input_dim + sample_z_ = torch.zeros((sample_num, z_dim)) + for i in range(args.class_num): + sample_z_[i * args.class_num] = torch.rand(1,z_dim) + for j in range(1, args.class_num): + sample_z_[i * args.class_num + j] = sample_z_[i * args.class_num] + + if not os.path.exists(os.path.join(args.save_path)): + os.makedirs(os.path.join(args.save_path)) + + temp = torch.zeros((args.class_num, 1)) + for i in range(args.class_num): + temp[i, 0] = i + + temp_y = torch.zeros((sample_num, 1)) + for i in range(args.class_num): + temp_y[i * args.class_num: (i + 1) * args.class_num] = temp + + sample_y_ = torch.zeros((sample_num, args.class_num)).scatter_(1, temp_y.type(torch.LongTensor), 1) + + return sample_z_, sample_y_ + + +def main(): + args = parse_args() + # Build model + local_device = torch.device("npu:0") + torch.npu.set_device(local_device) + print("using npu :{}".format(local_device)) + print('Loading model ...\n') + net = generator(input_dim=args.input_dim, output_dim=args.output_dim, + input_size=args.input_size, class_num=args.class_num) + model = net + checkpoint = torch.load(args.pth_path, map_location='cpu') + checkpoint = proc_nodes_module(checkpoint) + model.load_state_dict(checkpoint) + model.eval() + z,y=prep_preocess(args) + result = model(z,y) + result = result.cpu().data.numpy().transpose(0, 2, 3, 1) + result = (result + 1)/2 + sample_num = args.class_num**2 + image_frame_dim = int(np.floor(np.sqrt(sample_num))) + if not os.path.exists(os.path.join(args.save_path)): + os.makedirs(os.path.join(args.save_path)) + utils.save_images(result[:image_frame_dim * image_frame_dim, :, :, :], [image_frame_dim, image_frame_dim], + os.path.join(args.save_path,'demo_result.png')) + print("demo image stored in:", os.path.join(args.save_path,'demo_result.png')) + + +if __name__ == "__main__": main() \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/CGAN/modelzoo_level.txt b/PyTorch/contrib/cv/others/CGAN/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/others/CGAN/modelzoo_level.txt +++ b/PyTorch/contrib/cv/others/CGAN/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/CGAN/pth2onnx.py b/PyTorch/contrib/cv/others/CGAN/pth2onnx.py index 43cad179c3..cf79367599 100644 --- a/PyTorch/contrib/cv/others/CGAN/pth2onnx.py +++ b/PyTorch/contrib/cv/others/CGAN/pth2onnx.py @@ -1,67 +1,67 @@ - -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 CGAN import generator -import torch -import torch.onnx -import sys -from collections import OrderedDict -import argparse - - -def parse_args(): - desc = "Pytorch implementation of CGAN collections" - parser = argparse.ArgumentParser(description=desc) - parser.add_argument('--input_dim', type=int, default=62, help="The input_dim") - parser.add_argument('--output_dim', type=int, default=3, help="The output_dim") - parser.add_argument('--input_size', type=int, default=28, help="The image size of MNIST") - parser.add_argument('--class_num', type=int, default=10, help="The num of classes of MNIST") - parser.add_argument('--pth_path', type=str, default='CGAN_G.pth', help='pth model path') - parser.add_argument('--onnx_path', type=str, default="CGAN.onnx", help='onnx model path') - return parser.parse_args() - - -def proc_nodes_module(checkpoint): - new_state_dict = OrderedDict() - for k, v in checkpoint.items(): - if "module." in k: - name = k.replace("module.", "") - else: - name = k - new_state_dict[name] = v - return new_state_dict - -def pth2onnx(): - args = parse_args() - net = generator(input_dim=args.input_dim, output_dim=args.output_dim, - input_size=args.input_size, class_num=args.class_num) - model = net - checkpoint = torch.load(args.pth_path, map_location='cpu') - checkpoint = proc_nodes_module(checkpoint) - model.load_state_dict(checkpoint) - model.eval() - input_names = ["image"] - output_names = ["output1"] - #dynamic_axes = {'image': {0: '-1'}, 'output1': {0: '-1'}} - dummy_input1 = torch.randn(100, 62) - dummy_input2 = torch.randn(100, 10) - torch.onnx.export(model, (dummy_input1,dummy_input2), args.onnx_path, input_names=input_names, - output_names=output_names, opset_version=11, verbose=True) - print("this model could generete pictures, specifically digits") - print('onnx export done.') - - -if __name__ == "__main__": + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 CGAN import generator +import torch +import torch.onnx +import sys +from collections import OrderedDict +import argparse + + +def parse_args(): + desc = "Pytorch implementation of CGAN collections" + parser = argparse.ArgumentParser(description=desc) + parser.add_argument('--input_dim', type=int, default=62, help="The input_dim") + parser.add_argument('--output_dim', type=int, default=3, help="The output_dim") + parser.add_argument('--input_size', type=int, default=28, help="The image size of MNIST") + parser.add_argument('--class_num', type=int, default=10, help="The num of classes of MNIST") + parser.add_argument('--pth_path', type=str, default='CGAN_G.pth', help='pth model path') + parser.add_argument('--onnx_path', type=str, default="CGAN.onnx", help='onnx model path') + return parser.parse_args() + + +def proc_nodes_module(checkpoint): + new_state_dict = OrderedDict() + for k, v in checkpoint.items(): + if "module." in k: + name = k.replace("module.", "") + else: + name = k + new_state_dict[name] = v + return new_state_dict + +def pth2onnx(): + args = parse_args() + net = generator(input_dim=args.input_dim, output_dim=args.output_dim, + input_size=args.input_size, class_num=args.class_num) + model = net + checkpoint = torch.load(args.pth_path, map_location='cpu') + checkpoint = proc_nodes_module(checkpoint) + model.load_state_dict(checkpoint) + model.eval() + input_names = ["image"] + output_names = ["output1"] + #dynamic_axes = {'image': {0: '-1'}, 'output1': {0: '-1'}} + dummy_input1 = torch.randn(100, 62) + dummy_input2 = torch.randn(100, 10) + torch.onnx.export(model, (dummy_input1,dummy_input2), args.onnx_path, input_names=input_names, + output_names=output_names, opset_version=11, verbose=True) + print("this model could generete pictures, specifically digits") + print('onnx export done.') + + +if __name__ == "__main__": pth2onnx() \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/CycleGAN/CycleGAN_NetLoad.py b/PyTorch/contrib/cv/others/CycleGAN/CycleGAN_NetLoad.py index eb50010704..2effb5f2ba 100644 --- a/PyTorch/contrib/cv/others/CycleGAN/CycleGAN_NetLoad.py +++ b/PyTorch/contrib/cv/others/CycleGAN/CycleGAN_NetLoad.py @@ -1,92 +1,92 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -from collections import OrderedDict -import torch -from models import networks_adapt as networks - - -class load_networks(): - def __init__(self, opt): - self.opt = opt - self.gpu = 0 - self.netG_A = networks.define_G(self.opt.input_nc, self.opt.output_nc, self.opt.ngf, self.opt.netG, - self.opt.norm, not self.opt.no_dropout, self.opt.init_type, self.opt.init_gain, - self.gpu) - self.netG_B = networks.define_G(self.opt.output_nc, self.opt.input_nc, self.opt.ngf, self.opt.netG, - self.opt.norm, not self.opt.no_dropout, self.opt.init_type, self.opt.init_gain, - self.gpu) - if (opt.npu >= 1): - self.device = torch.device('npu:{}'.format(self.gpu)) - if (opt.npu == 0): - self.device = torch.device('cuda:{}'.format(self.gpu)) - else: - self.device = torch.device("cpu") - - def __patch_instance_norm_state_dict(self, state_dict, module, keys, i=0): - """Fix InstanceNorm checkpoints incompatibility (prior to 0.4)""" - key = keys[i] - if i + 1 == len(keys): # at the end, pointing to a parameter/buffer - if module.__class__.__name__.startswith('InstanceNorm') and \ - (key == 'running_mean' or key == 'running_var'): - if getattr(module, key) is None: - state_dict.pop('.'.join(keys)) - if module.__class__.__name__.startswith('InstanceNorm') and \ - (key == 'num_batches_tracked'): - state_dict.pop('.'.join(keys)) - else: - self.__patch_instance_norm_state_dict(state_dict, getattr(module, key), keys, i + 1) - - def proc_nodes_module(self, checkpoint): - new_state_dict = OrderedDict() - for k, v in checkpoint.items(): - if "module." in k: - name = k.replace("module.", "") - else: - name = k - new_state_dict[name] = v - return new_state_dict - - def loadnetworks(self, net, load_path): - state_dict = torch.load(load_path, map_location=torch.device('cpu')) - state_dict = self.proc_nodes_module(state_dict) - if hasattr(state_dict, '_metadata'): - del state_dict._metadata - # patch InstanceNorm checkpoints prior to 0.4 - for key in list(state_dict.keys()): # need to copy keys here because we mutate in loop - self.__patch_instance_norm_state_dict(state_dict, net, key.split('.')) - net.load_state_dict(state_dict) - return net - - def get_networks(self, load_patha, load_pathb): - model_Ga = self.loadnetworks(self.netG_A, load_patha) - model_Gb = self.loadnetworks(self.netG_B, load_pathb) - return model_Ga, model_Gb +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +from collections import OrderedDict +import torch +from models import networks_adapt as networks + + +class load_networks(): + def __init__(self, opt): + self.opt = opt + self.gpu = 0 + self.netG_A = networks.define_G(self.opt.input_nc, self.opt.output_nc, self.opt.ngf, self.opt.netG, + self.opt.norm, not self.opt.no_dropout, self.opt.init_type, self.opt.init_gain, + self.gpu) + self.netG_B = networks.define_G(self.opt.output_nc, self.opt.input_nc, self.opt.ngf, self.opt.netG, + self.opt.norm, not self.opt.no_dropout, self.opt.init_type, self.opt.init_gain, + self.gpu) + if (opt.npu >= 1): + self.device = torch.device('npu:{}'.format(self.gpu)) + if (opt.npu == 0): + self.device = torch.device('cuda:{}'.format(self.gpu)) + else: + self.device = torch.device("cpu") + + def __patch_instance_norm_state_dict(self, state_dict, module, keys, i=0): + """Fix InstanceNorm checkpoints incompatibility (prior to 0.4)""" + key = keys[i] + if i + 1 == len(keys): # at the end, pointing to a parameter/buffer + if module.__class__.__name__.startswith('InstanceNorm') and \ + (key == 'running_mean' or key == 'running_var'): + if getattr(module, key) is None: + state_dict.pop('.'.join(keys)) + if module.__class__.__name__.startswith('InstanceNorm') and \ + (key == 'num_batches_tracked'): + state_dict.pop('.'.join(keys)) + else: + self.__patch_instance_norm_state_dict(state_dict, getattr(module, key), keys, i + 1) + + def proc_nodes_module(self, checkpoint): + new_state_dict = OrderedDict() + for k, v in checkpoint.items(): + if "module." in k: + name = k.replace("module.", "") + else: + name = k + new_state_dict[name] = v + return new_state_dict + + def loadnetworks(self, net, load_path): + state_dict = torch.load(load_path, map_location=torch.device('cpu')) + state_dict = self.proc_nodes_module(state_dict) + if hasattr(state_dict, '_metadata'): + del state_dict._metadata + # patch InstanceNorm checkpoints prior to 0.4 + for key in list(state_dict.keys()): # need to copy keys here because we mutate in loop + self.__patch_instance_norm_state_dict(state_dict, net, key.split('.')) + net.load_state_dict(state_dict) + return net + + def get_networks(self, load_patha, load_pathb): + model_Ga = self.loadnetworks(self.netG_A, load_patha) + model_Gb = self.loadnetworks(self.netG_B, load_pathb) + return model_Ga, model_Gb diff --git a/PyTorch/contrib/cv/others/CycleGAN/LICENSE b/PyTorch/contrib/cv/others/CycleGAN/LICENSE index 4e1ad12a81..eb1309d6c1 100644 --- a/PyTorch/contrib/cv/others/CycleGAN/LICENSE +++ b/PyTorch/contrib/cv/others/CycleGAN/LICENSE @@ -1,31 +1,31 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ============================================================================ \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/CycleGAN/Readme.md b/PyTorch/contrib/cv/others/CycleGAN/Readme.md index 6eece9b767..f3e1aa0e9a 100644 --- a/PyTorch/contrib/cv/others/CycleGAN/Readme.md +++ b/PyTorch/contrib/cv/others/CycleGAN/Readme.md @@ -1,172 +1,172 @@ -# CycleGAN 训练 - -## Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks - -it's an approach for learning to translate an image from a source domain $X$ to a target domain $Y$ in the absence of paired examples - -For more detail:https://arxiv.org/abs/1703.10593v6 - -## - -## Requirements - - **You need to install CNN5.0.3 to ensure the normal training of the model!!** -and use pytorch, you can use pip or conda to install the requirements - -``` -# for pip -torch>=1.5.0 -torchvision>=0.5.0 -dominate>=2.4.0 -visdom>=0.1.8.8 -``` - -## 数据集准备 - -1.从以下网址获取maps.zip作为训练集 - -http://efrosgans.eecs.berkeley.edu/cyclegan/datasets/ - -文件结构如下: - - -``` -CycleGAN -|-- datasets -| |-- maps -| | |-- testA -| | |-- testB -| | |--trainA -| | |--trainB -| | |--valA -| | |--valB -|-- test - |--train_full_1p.sh - |--train_full_8p.sh - |--train_performance_1p.sh - |--train_performance_8p.sh -|-- models - |--cycle_gan_model_adapt.py - |--networks_adapt.py -|--util - |--html.py - |--visualizer_adapt.py - |--util.py - |--visualizer_adapt.py -|-- dataloader.py -|-- parse.py -|-- train.py -|--env_npu.sh - -``` - -将数据集按照以上结构放在代码目录下 - -## 安装 - -请注意,本模型使用了新版本的pytorch以及CANN包,具体版本为:torch-1.5.0+ascend.post3.20210930-cp37-cp37m-linux_aarch64.whl,Ascend-cann-toolkit_5.0.3_linux-aarch64.run; - -source 环境变量 - -``` -bash ./env_npu.sh -``` - - -## TRAIN - -### 单p训练 - -source 环境变量 - -``` -bash./env_npu.sh -``` - -运行单p脚本 - -``` -bash ./test/train_full_1p.sh -``` - - - -### 多p训练 - -source 环境变量 - -``` -source ./env_npu.sh -``` - -运行8p脚本 - -``` -bash ./test/train_full_8p.sh -``` - -模型保存在./checkpoints目录下,以数字命名的pth文件是当前epoch训练得到的权重文件,可用来恢复训练; - -运行日志保存至./目录下 - -## TEST - -测试精度 - - - -``` -由于论文为人眼观察生成效果的真假,所以这里省略,不过下面的demon提供将生成结果以网页的形式更为直观的展现出来 -``` - - - - -## Demo -然后运行以下脚本,执行demo.py: - -``` -python3.7.5 demon.py --pu_ids='0' \ - --prof=0 \ - --multiprocessing_distributed=0 \ - --distributed=1 \ - --npu=1 \ - --dataroot=./datasets/maps \ - --checkpoints_dir=./checkpoints_1pbs1_O1_sacle_1024_torchadam \ - --model_ga_path=./checkpoints_8pbs1/maps_cycle_gan/175_pu0_net_G_A.pth \ - --model_gb_path=./checkpoints_8pbs1/maps_cycle_gan/175_pu0_net_G_B.pth >>npu8pbs1_demon.log 2>&1 & -``` - -请指定需要测试的模型路径,将--checkpoints_dir、--model_ga_path、--model_gb_path所指向的参数替换掉既可替换掉即可,最后的输出结果存放在根目录的result目录下,点击index.html既可查看,结果展示请在支持浏览器的系统查看。 - -## 注意事项 -1、超参说明 -``` ---pu_ids='0,1,2,3,4,5,6,7'------------------------------------------指定几张卡训练,必须使用连续的卡号 ---prof=0------------------------------------------------------------是否测试性能,当为0时,不测试性能,为1则在大于等于10个epoch后输出prof文件 ---multiprocessing_distributed=1-------------------------------------是否执行多核训练,多卡必须为1,单卡设置为0既可 ---distributed=1-----------------------------------------------------该参数不可更改 ---npu=1-------------------------------------------------------------是否使用Npu开始训练,如果在Npu平台训练则必须使用1,GPU平台则必须为0 ---dataroot=./datasets/maps------------------------------------------数据集的目录 ---checkpoints_dir=./checkpoints_8pbs1_O1_sacle_1024_torchadam-------存放训练权重的目录 ---batch_size=1------------------------------------------------------指定训练时每个step输入多少样本,多卡训练不建议调高,单卡可适当调高为2。bs过大, - 会导致判别器过早收敛,进而造成生辰效果不佳 ---isapex=True-------------------------------------------------------是否开启混合精度进行训练,一般是开启的 ---apex_type="O1"----------------------------------------------------如果开启混合精度训练,建议使用O1模式,O2模式不收敛。当然O0也是可以的 ---loss_scale=1024---------------------------------------------------指定混合精度训练时的loss放大倍数,loss放大倍数也可以被指定为dynamic ---log_path="npu8pbs1.txt"-------------------------------------------只存放与模型有关的日志,不存放与后台输出有关的其他调试日志 ---num_epoch_start=0-------------------------------------------------从第几个epoch开始训练,如果开启继续训练,则需要指定该参数 ---num_epoch=200-----------------------------------------------------默认训练200个epoch,不可调高,但可以调低 ---n_epochs=100------------------------------------------------------权重衰减参数,默认前100个epoch保持学习率不变,后面开始慢慢线性衰减 ---lr=1e-4-----------------------------------------------------------baseline的学习率 ---line_scale=1------------------------------------------------------baseline的学习率的放大倍数,单卡为1,8卡训练建议设为2,其他卡酌情调参 ---n_epochs=100------------------------------------------------------与n_epochs保持一致 ---n_epochs_decay=100------------------------------------------------与n_epochs保持一致 ---pool_size=50-------------------------------------------------------该参数如果为单卡,使用50既可,如果为8卡,建议设置为16,其他卡酌情调参,一般多卡要调低且数 - 值为4的倍数 ---lambda_A=10--------------------------------------------------------论文超参 ---lambda_B=10--------------------------------------------------------论文超参 ---loadweight=199_pu0-----------------------------------------------------指定多少个epoch开始继续训练,重新训练默认参数既可 ---model_ga_path=./checkpoints_8pbs1/maps_cycle_gan/175_pu0_net_G_A.pth--存放权重的目录,运行demon的时候需要 ---model_gb_path=./checkpoints_8pbs1/maps_cycle_gan/175_pu0_net_G_B.pth--存放权重的目录,运行demon的时候需要_ -``` +# CycleGAN 训练 + +## Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks + +it's an approach for learning to translate an image from a source domain $X$ to a target domain $Y$ in the absence of paired examples + +For more detail:https://arxiv.org/abs/1703.10593v6 + +## + +## Requirements + + **You need to install CNN5.0.3 to ensure the normal training of the model!!** +and use pytorch, you can use pip or conda to install the requirements + +``` +# for pip +torch>=1.5.0 +torchvision>=0.5.0 +dominate>=2.4.0 +visdom>=0.1.8.8 +``` + +## 数据集准备 + +1.从以下网址获取maps.zip作为训练集 + +http://efrosgans.eecs.berkeley.edu/cyclegan/datasets/ + +文件结构如下: + + +``` +CycleGAN +|-- datasets +| |-- maps +| | |-- testA +| | |-- testB +| | |--trainA +| | |--trainB +| | |--valA +| | |--valB +|-- test + |--train_full_1p.sh + |--train_full_8p.sh + |--train_performance_1p.sh + |--train_performance_8p.sh +|-- models + |--cycle_gan_model_adapt.py + |--networks_adapt.py +|--util + |--html.py + |--visualizer_adapt.py + |--util.py + |--visualizer_adapt.py +|-- dataloader.py +|-- parse.py +|-- train.py +|--env_npu.sh + +``` + +将数据集按照以上结构放在代码目录下 + +## 安装 + +请注意,本模型使用了新版本的pytorch以及CANN包,具体版本为:torch-1.5.0+ascend.post3.20210930-cp37-cp37m-linux_aarch64.whl,Ascend-cann-toolkit_5.0.3_linux-aarch64.run; + +source 环境变量 + +``` +bash ./env_npu.sh +``` + + +## TRAIN + +### 单p训练 + +source 环境变量 + +``` +bash./env_npu.sh +``` + +运行单p脚本 + +``` +bash ./test/train_full_1p.sh +``` + + + +### 多p训练 + +source 环境变量 + +``` +source ./env_npu.sh +``` + +运行8p脚本 + +``` +bash ./test/train_full_8p.sh +``` + +模型保存在./checkpoints目录下,以数字命名的pth文件是当前epoch训练得到的权重文件,可用来恢复训练; + +运行日志保存至./目录下 + +## TEST + +测试精度 + + + +``` +由于论文为人眼观察生成效果的真假,所以这里省略,不过下面的demon提供将生成结果以网页的形式更为直观的展现出来 +``` + + + + +## Demo +然后运行以下脚本,执行demo.py: + +``` +python3.7.5 demon.py --pu_ids='0' \ + --prof=0 \ + --multiprocessing_distributed=0 \ + --distributed=1 \ + --npu=1 \ + --dataroot=./datasets/maps \ + --checkpoints_dir=./checkpoints_1pbs1_O1_sacle_1024_torchadam \ + --model_ga_path=./checkpoints_8pbs1/maps_cycle_gan/175_pu0_net_G_A.pth \ + --model_gb_path=./checkpoints_8pbs1/maps_cycle_gan/175_pu0_net_G_B.pth >>npu8pbs1_demon.log 2>&1 & +``` + +请指定需要测试的模型路径,将--checkpoints_dir、--model_ga_path、--model_gb_path所指向的参数替换掉既可替换掉即可,最后的输出结果存放在根目录的result目录下,点击index.html既可查看,结果展示请在支持浏览器的系统查看。 + +## 注意事项 +1、超参说明 +``` +--pu_ids='0,1,2,3,4,5,6,7'------------------------------------------指定几张卡训练,必须使用连续的卡号 +--prof=0------------------------------------------------------------是否测试性能,当为0时,不测试性能,为1则在大于等于10个epoch后输出prof文件 +--multiprocessing_distributed=1-------------------------------------是否执行多核训练,多卡必须为1,单卡设置为0既可 +--distributed=1-----------------------------------------------------该参数不可更改 +--npu=1-------------------------------------------------------------是否使用Npu开始训练,如果在Npu平台训练则必须使用1,GPU平台则必须为0 +--dataroot=./datasets/maps------------------------------------------数据集的目录 +--checkpoints_dir=./checkpoints_8pbs1_O1_sacle_1024_torchadam-------存放训练权重的目录 +--batch_size=1------------------------------------------------------指定训练时每个step输入多少样本,多卡训练不建议调高,单卡可适当调高为2。bs过大, + 会导致判别器过早收敛,进而造成生辰效果不佳 +--isapex=True-------------------------------------------------------是否开启混合精度进行训练,一般是开启的 +--apex_type="O1"----------------------------------------------------如果开启混合精度训练,建议使用O1模式,O2模式不收敛。当然O0也是可以的 +--loss_scale=1024---------------------------------------------------指定混合精度训练时的loss放大倍数,loss放大倍数也可以被指定为dynamic +--log_path="npu8pbs1.txt"-------------------------------------------只存放与模型有关的日志,不存放与后台输出有关的其他调试日志 +--num_epoch_start=0-------------------------------------------------从第几个epoch开始训练,如果开启继续训练,则需要指定该参数 +--num_epoch=200-----------------------------------------------------默认训练200个epoch,不可调高,但可以调低 +--n_epochs=100------------------------------------------------------权重衰减参数,默认前100个epoch保持学习率不变,后面开始慢慢线性衰减 +--lr=1e-4-----------------------------------------------------------baseline的学习率 +--line_scale=1------------------------------------------------------baseline的学习率的放大倍数,单卡为1,8卡训练建议设为2,其他卡酌情调参 +--n_epochs=100------------------------------------------------------与n_epochs保持一致 +--n_epochs_decay=100------------------------------------------------与n_epochs保持一致 +--pool_size=50-------------------------------------------------------该参数如果为单卡,使用50既可,如果为8卡,建议设置为16,其他卡酌情调参,一般多卡要调低且数 + 值为4的倍数 +--lambda_A=10--------------------------------------------------------论文超参 +--lambda_B=10--------------------------------------------------------论文超参 +--loadweight=199_pu0-----------------------------------------------------指定多少个epoch开始继续训练,重新训练默认参数既可 +--model_ga_path=./checkpoints_8pbs1/maps_cycle_gan/175_pu0_net_G_A.pth--存放权重的目录,运行demon的时候需要 +--model_gb_path=./checkpoints_8pbs1/maps_cycle_gan/175_pu0_net_G_B.pth--存放权重的目录,运行demon的时候需要_ +``` diff --git a/PyTorch/contrib/cv/others/CycleGAN/dataloader.py b/PyTorch/contrib/cv/others/CycleGAN/dataloader.py index 4cdc1e610c..71b12c2f9f 100644 --- a/PyTorch/contrib/cv/others/CycleGAN/dataloader.py +++ b/PyTorch/contrib/cv/others/CycleGAN/dataloader.py @@ -1,128 +1,128 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -import importlib -import torch.utils.data -#from data.base_dataset import BaseDataset - - -def find_dataset_using_name(dataset_name): - """Import the module "data/[dataset_name]_dataset.py". - - In the file, the class called DatasetNameDataset() will - be instantiated. It has to be a subclass of BaseDataset, - and it is case-insensitive. - """ - dataset_filename = "data." + dataset_name + "_dataset" - datasetlib = importlib.import_module(dataset_filename) - - dataset = None - target_dataset_name = dataset_name.replace('_', '') + 'dataset' - for name, cls in datasetlib.__dict__.items(): - if name.lower() == target_dataset_name.lower(): - dataset = cls - - if dataset is None: - raise NotImplementedError("In %s.py, there should be a subclass of BaseDataset with class name that matches %s in lowercase." % (dataset_filename, target_dataset_name)) - - return dataset - - -def get_option_setter(dataset_name): - """Return the static method of the dataset class.""" - dataset_class = find_dataset_using_name(dataset_name) - return dataset_class.modify_commandline_options - - -def create_dataset(opt): - """Create a dataset given the option. - - This function wraps the class CustomDatasetDataLoader. - This is the main interface between this package and 'train.py'/'test.py' - """ - dataset_class = find_dataset_using_name(opt.dataset_mode) - datasets = dataset_class(opt) - train_sampler = torch.utils.data.distributed.DistributedSampler(datasets) - data_loader = CustomDatasetDataLoader(opt,datasets,train_sampler) - dataset = data_loader.load_data() - return dataset,train_sampler - - -class CustomDatasetDataLoader(): - """Wrapper class of Dataset class that performs multi-threaded data loading""" - - def __init__(self, opt,dataset,train_sampler): - """Initialize this class - - Step 1: create a dataset instance given the name [dataset_mode] - Step 2: create a multi-threaded data loader. - """ - self.opt = opt - - self.dataset=dataset - - print("dataset [%s] was created" % type(self.dataset).__name__) - if(opt.ngpus_per_node>1 and opt.multiprocessing_distributed>=1): - self.dataloader = torch.utils.data.DataLoader( - self.dataset, - batch_size=opt.batch_size, - shuffle=(train_sampler is None), - pin_memory=False, - num_workers=int(opt.num_threads), - sampler=train_sampler, - drop_last=True) - #self.dataloader = torch.utils.data.DataLoader( - # self.dataset, - # batch_size=opt.batch_size, - # shuffle=not opt.serial_batches, - # num_workers=int(opt.num_threads), - # ) - else: - self.dataloader = torch.utils.data.DataLoader( - self.dataset, - batch_size=opt.batch_size, - shuffle=not opt.serial_batches, - num_workers=int(opt.num_threads), - ) - - def load_data(self): - return self - - def __len__(self): - """Return the number of data in the dataset""" - return min(len(self.dataset), self.opt.max_dataset_size) - - def __iter__(self): - """Return a batch of data""" - for i, data in enumerate(self.dataloader): - if i * self.opt.batch_size >= self.opt.max_dataset_size: - break - yield data +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import importlib +import torch.utils.data +#from data.base_dataset import BaseDataset + + +def find_dataset_using_name(dataset_name): + """Import the module "data/[dataset_name]_dataset.py". + + In the file, the class called DatasetNameDataset() will + be instantiated. It has to be a subclass of BaseDataset, + and it is case-insensitive. + """ + dataset_filename = "data." + dataset_name + "_dataset" + datasetlib = importlib.import_module(dataset_filename) + + dataset = None + target_dataset_name = dataset_name.replace('_', '') + 'dataset' + for name, cls in datasetlib.__dict__.items(): + if name.lower() == target_dataset_name.lower(): + dataset = cls + + if dataset is None: + raise NotImplementedError("In %s.py, there should be a subclass of BaseDataset with class name that matches %s in lowercase." % (dataset_filename, target_dataset_name)) + + return dataset + + +def get_option_setter(dataset_name): + """Return the static method of the dataset class.""" + dataset_class = find_dataset_using_name(dataset_name) + return dataset_class.modify_commandline_options + + +def create_dataset(opt): + """Create a dataset given the option. + + This function wraps the class CustomDatasetDataLoader. + This is the main interface between this package and 'train.py'/'test.py' + """ + dataset_class = find_dataset_using_name(opt.dataset_mode) + datasets = dataset_class(opt) + train_sampler = torch.utils.data.distributed.DistributedSampler(datasets) + data_loader = CustomDatasetDataLoader(opt,datasets,train_sampler) + dataset = data_loader.load_data() + return dataset,train_sampler + + +class CustomDatasetDataLoader(): + """Wrapper class of Dataset class that performs multi-threaded data loading""" + + def __init__(self, opt,dataset,train_sampler): + """Initialize this class + + Step 1: create a dataset instance given the name [dataset_mode] + Step 2: create a multi-threaded data loader. + """ + self.opt = opt + + self.dataset=dataset + + print("dataset [%s] was created" % type(self.dataset).__name__) + if(opt.ngpus_per_node>1 and opt.multiprocessing_distributed>=1): + self.dataloader = torch.utils.data.DataLoader( + self.dataset, + batch_size=opt.batch_size, + shuffle=(train_sampler is None), + pin_memory=False, + num_workers=int(opt.num_threads), + sampler=train_sampler, + drop_last=True) + #self.dataloader = torch.utils.data.DataLoader( + # self.dataset, + # batch_size=opt.batch_size, + # shuffle=not opt.serial_batches, + # num_workers=int(opt.num_threads), + # ) + else: + self.dataloader = torch.utils.data.DataLoader( + self.dataset, + batch_size=opt.batch_size, + shuffle=not opt.serial_batches, + num_workers=int(opt.num_threads), + ) + + def load_data(self): + return self + + def __len__(self): + """Return the number of data in the dataset""" + return min(len(self.dataset), self.opt.max_dataset_size) + + def __iter__(self): + """Return a batch of data""" + for i, data in enumerate(self.dataloader): + if i * self.opt.batch_size >= self.opt.max_dataset_size: + break + yield data diff --git a/PyTorch/contrib/cv/others/CycleGAN/demon.py b/PyTorch/contrib/cv/others/CycleGAN/demon.py index 1090328622..cbcff3e554 100644 --- a/PyTorch/contrib/cv/others/CycleGAN/demon.py +++ b/PyTorch/contrib/cv/others/CycleGAN/demon.py @@ -1,189 +1,189 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -import os -import torchvision.transforms as transforms -from PIL import Image -import torch.onnx -from torch.utils.data import Dataset -from torchvision.datasets.folder import IMG_EXTENSIONS -from parse import parse_args -from CycleGAN_NetLoad import load_networks - - -def make_power(img, base): - ow, oh = img.size - h = int(round(oh / base) * base) - w = int(round(ow / base) * base) - if h == oh and w == ow: - return img - - -def preprocess(image_shape): - process = transforms.Compose([ - transforms.Lambda(lambda img: make_power(img, base=4)), - transforms.Resize(image_shape), - transforms.ToTensor(), - transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))]) - return process - - -def postprocess(img_tensor): - inv_normalize = transforms.Normalize( - mean=(-1, -1, -1), - std=(2.0, 2.0, 2.0)) - to_PIL_image = transforms.ToPILImage() - return to_PIL_image(inv_normalize(img_tensor[0]).clamp(0, 1)) - - -def make_dataset(dir, max_dataset_size=float("inf")): - images = [] - assert os.path.isdir(dir), '%s is not a valid directory' % dir - - for root, _, fnames in sorted(os.walk(dir)): - for fname in fnames: - path = os.path.join(root, fname) - images.append(path) - return images[:min(max_dataset_size, len(images))] - - -def default_loader(path): - return Image.open(path).convert('RGB') - - -class ImageFolder(Dataset): - def __init__(self, root, transform=None, return_paths=True, - loader=default_loader): - imgs = make_dataset(root + '/testA') - if len(imgs) == 0: - raise (RuntimeError("Found 0 images in: " + root + "\n" + - "Supported image extensions are: " + ",".join(IMG_EXTENSIONS))) - self.root = root - self.imgs = imgs - self.transform = transform - self.return_paths = return_paths - self.loader = loader - - def __getitem__(self, index): - path = self.imgs[index] - img = self.loader(path) - if self.transform is not None: - img = self.transform(img) - if self.return_paths: - return img, path - else: - return img - - def __len__(self): - return len(self.imgs) - - -def deal_tensor(datas, outputs): - res_img = postprocess(datas) - res_gimg = postprocess(outputs) - - -def main(): - paser = parse_args(True, True) - opt = paser.initialize() - htmlres = '' - - pathroot = './result/' - images_name = 'img' - if (os.path.exists(pathroot + images_name) == False): - os.makedirs(pathroot + images_name) - f = open(pathroot + 'index.html', 'w') - lnetworks = load_networks(opt) - bachsize = opt.batch_size - loc_cpu = 'cpu' - loc = 'npu:1' - transform = preprocess((256, 256)) - model_Ga, _ = lnetworks.get_networks(opt.model_ga_path, opt.model_gb_path) - model_Ga.eval() - datasets = ImageFolder(opt.dataroot, transform) - dataloader = torch.utils.data.DataLoader(datasets, batch_size=bachsize, shuffle=True, num_workers=4) - - count = 0 - for i, (x, x_path) in enumerate(dataloader): - count += 1 - if (count > 10): - break - temp = str(x_path).split('/') - img_name = temp[4].split(',')[0].split('\'')[0] - src_real = temp[3] - src_g = temp[3] + 'G' - if (os.path.exists(pathroot + images_name + '/' + src_real) == False): - os.makedirs(pathroot + images_name + '/' + src_real) - if (os.path.exists(pathroot + images_name + '/' + src_g) == False): - os.makedirs(pathroot + images_name + '/' + src_g) - x1 = postprocess(x) - realsrc = images_name + '/' + src_real + '/' + img_name - fakesrc = images_name + '/' + src_g + '/' + img_name - y = model_Ga(x.to(loc)) - y = postprocess(y.to(loc_cpu)) - x1.save(pathroot + realsrc) - y.save(pathroot + fakesrc) - htmlres += ''' -
-
-

%s

- -
-
-

%s

- -
-
- ''' % (img_name.split('.')[0], realsrc, img_name.split('.')[0] + '_fake', fakesrc) - - htmlshow = """ - - - %s - - """ % (htmlres) - f.write(htmlshow) - f.close() - - -if __name__ == '__main__': - main() +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import os +import torchvision.transforms as transforms +from PIL import Image +import torch.onnx +from torch.utils.data import Dataset +from torchvision.datasets.folder import IMG_EXTENSIONS +from parse import parse_args +from CycleGAN_NetLoad import load_networks + + +def make_power(img, base): + ow, oh = img.size + h = int(round(oh / base) * base) + w = int(round(ow / base) * base) + if h == oh and w == ow: + return img + + +def preprocess(image_shape): + process = transforms.Compose([ + transforms.Lambda(lambda img: make_power(img, base=4)), + transforms.Resize(image_shape), + transforms.ToTensor(), + transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))]) + return process + + +def postprocess(img_tensor): + inv_normalize = transforms.Normalize( + mean=(-1, -1, -1), + std=(2.0, 2.0, 2.0)) + to_PIL_image = transforms.ToPILImage() + return to_PIL_image(inv_normalize(img_tensor[0]).clamp(0, 1)) + + +def make_dataset(dir, max_dataset_size=float("inf")): + images = [] + assert os.path.isdir(dir), '%s is not a valid directory' % dir + + for root, _, fnames in sorted(os.walk(dir)): + for fname in fnames: + path = os.path.join(root, fname) + images.append(path) + return images[:min(max_dataset_size, len(images))] + + +def default_loader(path): + return Image.open(path).convert('RGB') + + +class ImageFolder(Dataset): + def __init__(self, root, transform=None, return_paths=True, + loader=default_loader): + imgs = make_dataset(root + '/testA') + if len(imgs) == 0: + raise (RuntimeError("Found 0 images in: " + root + "\n" + + "Supported image extensions are: " + ",".join(IMG_EXTENSIONS))) + self.root = root + self.imgs = imgs + self.transform = transform + self.return_paths = return_paths + self.loader = loader + + def __getitem__(self, index): + path = self.imgs[index] + img = self.loader(path) + if self.transform is not None: + img = self.transform(img) + if self.return_paths: + return img, path + else: + return img + + def __len__(self): + return len(self.imgs) + + +def deal_tensor(datas, outputs): + res_img = postprocess(datas) + res_gimg = postprocess(outputs) + + +def main(): + paser = parse_args(True, True) + opt = paser.initialize() + htmlres = '' + + pathroot = './result/' + images_name = 'img' + if (os.path.exists(pathroot + images_name) == False): + os.makedirs(pathroot + images_name) + f = open(pathroot + 'index.html', 'w') + lnetworks = load_networks(opt) + bachsize = opt.batch_size + loc_cpu = 'cpu' + loc = 'npu:1' + transform = preprocess((256, 256)) + model_Ga, _ = lnetworks.get_networks(opt.model_ga_path, opt.model_gb_path) + model_Ga.eval() + datasets = ImageFolder(opt.dataroot, transform) + dataloader = torch.utils.data.DataLoader(datasets, batch_size=bachsize, shuffle=True, num_workers=4) + + count = 0 + for i, (x, x_path) in enumerate(dataloader): + count += 1 + if (count > 10): + break + temp = str(x_path).split('/') + img_name = temp[4].split(',')[0].split('\'')[0] + src_real = temp[3] + src_g = temp[3] + 'G' + if (os.path.exists(pathroot + images_name + '/' + src_real) == False): + os.makedirs(pathroot + images_name + '/' + src_real) + if (os.path.exists(pathroot + images_name + '/' + src_g) == False): + os.makedirs(pathroot + images_name + '/' + src_g) + x1 = postprocess(x) + realsrc = images_name + '/' + src_real + '/' + img_name + fakesrc = images_name + '/' + src_g + '/' + img_name + y = model_Ga(x.to(loc)) + y = postprocess(y.to(loc_cpu)) + x1.save(pathroot + realsrc) + y.save(pathroot + fakesrc) + htmlres += ''' +
+
+

%s

+ +
+
+

%s

+ +
+
+ ''' % (img_name.split('.')[0], realsrc, img_name.split('.')[0] + '_fake', fakesrc) + + htmlshow = """ + + + %s + + """ % (htmlres) + f.write(htmlshow) + f.close() + + +if __name__ == '__main__': + main() diff --git a/PyTorch/contrib/cv/others/CycleGAN/models/cycle_gan_model_adapt.py b/PyTorch/contrib/cv/others/CycleGAN/models/cycle_gan_model_adapt.py index 56a9fe9157..a5c1e39cae 100644 --- a/PyTorch/contrib/cv/others/CycleGAN/models/cycle_gan_model_adapt.py +++ b/PyTorch/contrib/cv/others/CycleGAN/models/cycle_gan_model_adapt.py @@ -1,421 +1,421 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -import os -import sys -from collections import OrderedDict -import torch -import itertools -from util.image_pool import ImagePool -from . import networks_adapt as networks -from torch.nn.parallel import DistributedDataParallel as DDP -# from .npu_fused_adam import NpuFusedAdam as adam -from torch.optim import Adam as adam - -if sys.version_info < (3, 0): - raise RuntimeError("Apex currently only supports Python 3. Aborting.") -try: - import apex - from apex import amp -except ImportError: - amp = None - - -class CycleGANModel(): - """ - This class implements the CycleGAN model, for learning image-to-image translation without paired data. - - The model training requires '--dataset_mode unaligned' dataset. - By default, it uses a '--netG resnet_9blocks' ResNet generator, - a '--netD basic' discriminator (PatchGAN introduced by pix2pix), - and a least-square GANs objective ('--gan_mode lsgan'). - - CycleGAN paper: https://arxiv.org/pdf/1703.10593.pdf - """ - - @staticmethod - def modify_commandline_options(parser, is_train=True): - """Add new dataset-specific options, and rewrite default values for existing options. - - Parameters: - parser -- original option parser - is_train (bool) -- whether training phase or test phase. You can use this flag to add training-specific or test-specific options. - - Returns: - the modified parser. - - For CycleGAN, in addition to GAN losses, we introduce lambda_A, lambda_B, and lambda_identity for the following losses. - A (source domain), B (target domain). - Generators: G_A: A -> B; G_B: B -> A. - Discriminators: D_A: G_A(A) vs. B; D_B: G_B(B) vs. A. - Forward cycle loss: lambda_A * ||G_B(G_A(A)) - A|| (Eqn. (2) in the paper) - Backward cycle loss: lambda_B * ||G_A(G_B(B)) - B|| (Eqn. (2) in the paper) - Identity loss (optional): lambda_identity * (||G_A(B) - B|| * lambda_B + ||G_B(A) - A|| * lambda_A) (Sec 5.2 "Photo generation from paintings" in the paper) - Dropout is not used in the original CycleGAN paper. - """ - parser.set_defaults(no_dropout=True) # default CycleGAN did not use dropout - if is_train: - parser.add_argument('--lambda_A', type=float, default=10.0, help='weight for cycle loss (A -> B -> A)') - parser.add_argument('--lambda_B', type=float, default=10.0, help='weight for cycle loss (B -> A -> B)') - parser.add_argument('--lambda_identity', type=float, default=0.5, - help='use identity mapping. Setting lambda_identity other than 0 has an effect of' - ' scaling the weight of the identity mapping loss. For example, if the weight of ' - 'the identity loss should be 10 times smaller than the weight of the reconstruction' - ' loss, please set lambda_identity = 0.1') - - return parser - - def __init__(self, opt): - """Initialize the CycleGAN class. - - Parameters: - opt (Option class)-- stores all the experiment flags; needs to be a subclass of BaseOptions - """ - # specify the training losses you want to print out. The training/test scripts will call - self.opt = opt - self.isTrain = opt.isTrain - self.optimizers = [] - if (opt.npu < 1): - self.device = torch.device('cuda:{}'.format(self.opt.gpu)) # get device name: CPU or GPU - # self.device = torch.device('cuda:{}'.format(self.gpu_ids[0])) # get device name: CPU or GPU - else: - # self.device = torch.device('npu:{}'.format(self.gpu_ids)) if self.gpu_ids else torch.device( 'cpu') # get device name: CPU or GPU - self.device = torch.device('npu:{}'.format(self.opt.gpu)) # get device name: CPU or GPU - self.save_dir = os.path.join(opt.checkpoints_dir, opt.name) # save all the checkpoints to save_dir - self.loss_names = ['D_A', 'G_A', 'cycle_A', 'idt_A', 'D_B', 'G_B', 'cycle_B', 'idt_B'] - # specify the images you want to save/display. The training/test scripts will call - - visual_names_A = ['real_A', 'fake_B', 'rec_A'] - visual_names_B = ['real_B', 'fake_A', 'rec_B'] - if self.isTrain and self.opt.lambda_identity > 0.0: # if identity loss is used, we also visualize idt_B=G_A(B) ad idt_A=G_A(B) - visual_names_A.append('idt_B') - visual_names_B.append('idt_A') - - self.visual_names = visual_names_A + visual_names_B # combine visualizations for A and B - # specify the models you want to save to the disk. The training/test scripts - # will call and . - if self.isTrain: - self.model_names = ['G_A', 'G_B', 'D_A', 'D_B'] - else: # during test time, only load Gs - self.model_names = ['G_A', 'G_B'] - - # define networks (both Generators and discriminators) - # The naming is different from those used in the paper. - # Code (vs. paper): G_A (G), G_B (F), D_A (D_Y), D_B (D_X) - self.netG_A = networks.define_G(opt.input_nc, opt.output_nc, opt.ngf, opt.netG, opt.norm, - not opt.no_dropout, opt.init_type, opt.init_gain, self.opt.gpu) - self.netG_B = networks.define_G(opt.output_nc, opt.input_nc, opt.ngf, opt.netG, opt.norm, - not opt.no_dropout, opt.init_type, opt.init_gain, self.opt.gpu) - if self.isTrain: # define discriminators - self.netD_A = networks.define_D(opt.output_nc, opt.ndf, opt.netD, - opt.n_layers_D, opt.norm, opt.init_type, opt.init_gain, self.opt.gpu) - self.netD_B = networks.define_D(opt.input_nc, opt.ndf, opt.netD, - opt.n_layers_D, opt.norm, opt.init_type, opt.init_gain, self.opt.gpu) - - if self.isTrain: - if opt.lambda_identity > 0.0: # only works when input and output images have the same number of channels - assert (opt.input_nc == opt.output_nc) - self.fake_A_pool = ImagePool(opt.pool_size) # create image buffer to store previously generated images - self.fake_B_pool = ImagePool(opt.pool_size) # create image buffer to store previously generated images - # define loss functions - self.criterionGAN = networks.GANLoss(opt.gan_mode).to(self.device) # define GAN loss. - self.criterionCycle = torch.nn.L1Loss() - self.criterionIdt = torch.nn.L1Loss() - # initialize optimizers; schedulers will be automatically created by function . - self.optimizer_G = adam(itertools.chain(self.netG_A.parameters(), self.netG_B.parameters()), - lr=opt.lr, betas=(opt.beta1, 0.999)) - self.optimizer_D = adam(itertools.chain(self.netD_A.parameters(), self.netD_B.parameters()), - lr=opt.lr, betas=(opt.beta1, 0.999)) - self.optimizers.append(self.optimizer_G) - self.optimizers.append(self.optimizer_D) - self.lr_scheduler_G = networks.get_scheduler(self.optimizer_G, self.opt) - self.lr_scheduler_D = networks.get_scheduler(self.optimizer_D, self.opt) - # self.scaler = GradScaler() - amp.register_float_function(torch, 'sigmoid') - amp.register_float_function(torch, 'softmax') - amp.register_float_function(torch, 'tanh') - if (self.opt.isapex): - [self.netG_A, self.netG_B, self.netD_A, self.netD_B], [self.optimizer_G, self.optimizer_D] = \ - amp.initialize([self.netG_A, self.netG_B, self.netD_A, self.netD_B], - [self.optimizer_G, self.optimizer_D], opt_level=self.opt.apex_type, - loss_scale=self.opt.loss_scale) - if (self.opt.distributed >= 1): - temp = bool(1 - opt.npu) - self.netG_A = DDP(self.netG_A, [self.opt.gpu], broadcast_buffers=temp) - self.netG_B = DDP(self.netG_B, [self.opt.gpu], broadcast_buffers=temp) - self.netD_A = DDP(self.netD_A, [self.opt.gpu], broadcast_buffers=temp) - self.netD_B = DDP(self.netD_B, [self.opt.gpu], broadcast_buffers=temp) - - def setup(self, opt): - """Load and print networks; create schedulers - - Parameters: - opt (Option class) -- stores all the experiment flags; needs to be a subclass of BaseOptions - """ - if self.isTrain: - self.schedulers = [networks.get_scheduler(optimizer, opt) for optimizer in self.optimizers] - if not self.isTrain or opt.continue_train: - load_suffix = 'iter_%d' % opt.load_iter if opt.load_iter > 0 else opt.epoch - self.load_networks(load_suffix) - self.print_networks(opt.verbose) - - def update_learning_rate(self): - old_lr = self.optimizers[0].param_groups[0]['lr'] - for scheduler in self.schedulers: - if self.opt.lr_policy == 'plateau': - scheduler.step(self.metric) - else: - scheduler.step() - self.lr_scheduler_G.step() - self.lr_scheduler_D.step() - - def set_input(self, input): - """Unpack input data from the dataloader and perform necessary pre-processing steps. - - Parameters: - input (dict): include the data itself and its metadata information. - - The option 'direction' can be used to swap domain A and domain B. - """ - AtoB = self.opt.direction == 'AtoB' - - self.real_A = input['A' if AtoB else 'B'].to(self.device) - self.real_B = input['B' if AtoB else 'A'].to(self.device) - self.image_paths = input['A_paths' if AtoB else 'B_paths'] - - def forward(self): - """Run forward pass; called by both functions and .""" - self.fake_B = self.netG_A(self.real_A) # G_A(A) - self.rec_A = self.netG_B(self.fake_B) # G_B(G_A(A)) - self.fake_A = self.netG_B(self.real_B) # G_B(B) - self.rec_B = self.netG_A(self.fake_A) # G_A(G_B(B)) - - def backward_D_basic(self, netD, real, fake): - """Calculate GAN loss for the discriminator - - Parameters: - netD (network) -- the discriminator D - real (tensor array) -- real images - fake (tensor array) -- images generated by a generator - - Return the discriminator loss. - We also call loss_D.backward() to calculate the gradients. - """ - # Real - pred_real = netD(real) - loss_D_real = self.criterionGAN(pred_real, True) - # Fake - pred_fake = netD(fake.detach()) - loss_D_fake = self.criterionGAN(pred_fake, False) - # Combined loss and calculate gradients - loss_D = (loss_D_real + loss_D_fake) * 0.5 - if (self.opt.isapex): - with amp.scale_loss(loss_D, self.optimizer_D) as scaled_lossd: - scaled_lossd.backward() - else: - loss_D.backward() - return loss_D - - def backward_D_A(self): - """Calculate GAN loss for discriminator D_A""" - fake_B = self.fake_B_pool.query(self.fake_B) - self.loss_D_A = self.backward_D_basic(self.netD_A, self.real_B, fake_B) - - def backward_D_B(self): - """Calculate GAN loss for discriminator D_B""" - fake_A = self.fake_A_pool.query(self.fake_A) - self.loss_D_B = self.backward_D_basic(self.netD_B, self.real_A, fake_A) - - def backward_G(self): - """Calculate the loss for generators G_A and G_B""" - lambda_idt = self.opt.lambda_identity - lambda_A = self.opt.lambda_A - lambda_B = self.opt.lambda_B - # Identity loss - if lambda_idt > 0: - # G_A should be identity if real_B is fed: ||G_A(B) - B|| - self.idt_A = self.netG_A(self.real_B) - self.loss_idt_A = self.criterionIdt(self.idt_A, self.real_B) * lambda_B * lambda_idt - # G_B should be identity if real_A is fed: ||G_B(A) - A|| - self.idt_B = self.netG_B(self.real_A) - self.loss_idt_B = self.criterionIdt(self.idt_B, self.real_A) * lambda_A * lambda_idt - else: - self.loss_idt_A = 0 - self.loss_idt_B = 0 - - # GAN loss D_A(G_A(A)) - self.loss_G_A = self.criterionGAN(self.netD_A(self.fake_B), True) - # GAN loss D_B(G_B(B)) - self.loss_G_B = self.criterionGAN(self.netD_B(self.fake_A), True) - # Forward cycle loss || G_B(G_A(A)) - A|| - self.loss_cycle_A = self.criterionCycle(self.rec_A, self.real_A) * lambda_A - # Backward cycle loss || G_A(G_B(B)) - B|| - self.loss_cycle_B = self.criterionCycle(self.rec_B, self.real_B) * lambda_B - # combined loss and calculate gradients - self.loss_G = self.loss_G_A + self.loss_G_B + self.loss_cycle_A + self.loss_cycle_B + self.loss_idt_A + self.loss_idt_B - if (self.opt.isapex == True): - with amp.scale_loss(self.loss_G, self.optimizer_G) as scaled_lossg: - scaled_lossg.backward() - else: - self.loss_G.backward() - - def optimize_parameters(self): - """Calculate losses, gradients, and update network weights; called in every training iteration""" - # forwar - self.forward() # compute fake images and reconstruction images. - # G_A and G_B - self.set_requires_grad([self.netD_A, self.netD_B], False) # Ds require no gradients when optimizing Gs - self.optimizer_G.zero_grad() # set G_A and G_B's gradients to zero - self.backward_G() # calculate gradients for G_A and G_B - self.optimizer_G.step() # update G_A and G_B's weights - # D_A and D_B - self.set_requires_grad([self.netD_A, self.netD_B], True) - self.optimizer_D.zero_grad() # set D_A and D_B's gradients to zero - self.backward_D_A() # calculate gradients for D_A - self.backward_D_B() # calculate graidents for D_B - self.optimizer_D.step() # update D_A and D_B's weights - - def get_current_visuals(self): - """Return visualization images. train.py will display these images with visdom, and save the images to a HTML""" - visual_ret = OrderedDict() - for name in self.visual_names: - if isinstance(name, str): - visual_ret[name] = getattr(self, name) - return visual_ret - - def get_current_losses(self): - """Return traning losses / errors. train.py will print out these errors on console, and save them to a file""" - errors_ret = OrderedDict() - for name in self.loss_names: - if isinstance(name, str): - errors_ret[name] = float( - getattr(self, 'loss_' + name)) # float(...) works for both scalar tensor and float number - return errors_ret - - def save_networks(self, epoch): - """Save all the networks to the disk. - - Parameters: - epoch (int) -- current epoch; used in the file name '%s_net_%s.pth' % (epoch, name) - """ - for name in self.model_names: - if isinstance(name, str): - save_filename = '%s_net_%s.pth' % (epoch, name) - save_path = os.path.join(self.save_dir, save_filename) - save_path1 = os.path.join(self.save_dir, 'a' + save_filename) - net = getattr(self, 'net' + name) - - if self.opt.distributed >= 1 and torch.cuda.is_available(): - torch.save(net.cpu().module.state_dict(), save_path) - if (self.opt.npu >= 1): - net.npu(self.opt.gpu) - else: - net.cuda(self.opt.gpu) - else: - torch.save(net.cpu().state_dict(), save_path) - if (self.opt.npu >= 1): - net.npu(self.opt.gpu) - else: - net.cuda(self.opt.gpu) - - def __patch_instance_norm_state_dict(self, state_dict, module, keys, i=0): - """Fix InstanceNorm checkpoints incompatibility (prior to 0.4)""" - key = keys[i] - if i + 1 == len(keys): # at the end, pointing to a parameter/buffer - if module.__class__.__name__.startswith('InstanceNorm') and \ - (key == 'running_mean' or key == 'running_var'): - if getattr(module, key) is None: - state_dict.pop('.'.join(keys)) - if module.__class__.__name__.startswith('InstanceNorm') and \ - (key == 'num_batches_tracked'): - state_dict.pop('.'.join(keys)) - else: - self.__patch_instance_norm_state_dict(state_dict, getattr(module, key), keys, i + 1) - - def load_networks(self, epoch): - """Load all the networks from the disk. - - Parameters: - epoch (int) -- current epoch; used in the file name '%s_net_%s.pth' % (epoch, name) - """ - for name in self.model_names: - if isinstance(name, str): - load_filename = '%s_net_%s.pth' % (epoch, name) - load_path = os.path.join(self.save_dir, load_filename) - net = getattr(self, 'net' + name) - if isinstance(net, torch.nn.DataParallel): - net = net.module - print('loading the model from %s' % load_path) - # if you are using PyTorch newer than 0.4 (e.g., built from - # GitHub source), you can remove str() on self.device - state_dict = torch.load(load_path, map_location=str(self.device)) - if hasattr(state_dict, '_metadata'): - del state_dict._metadata - - # patch InstanceNorm checkpoints prior to 0.4 - for key in list(state_dict.keys()): # need to copy keys here because we mutate in loop - self.__patch_instance_norm_state_dict(state_dict, net, key.split('.')) - net.load_state_dict(state_dict) - - def print_networks(self, verbose): - """Print the total number of parameters in the network and (if verbose) network architecture - - Parameters: - verbose (bool) -- if verbose: print the network architecture - """ - print('---------- Networks initialized -------------') - for name in self.model_names: - if isinstance(name, str): - net = getattr(self, 'net' + name) - num_params = 0 - for param in net.parameters(): - num_params += param.numel() - if verbose: - print(net) - print('[Network %s] Total number of parameters : %.3f M' % (name, num_params / 1e6)) - print('-----------------------------------------------') - - def set_requires_grad(self, nets, requires_grad=False): - """Set requies_grad=Fasle for all the networks to avoid unnecessary computations - Parameters: - nets (network list) -- a list of networks - requires_grad (bool) -- whether the networks require gradients or not - """ - if not isinstance(nets, list): - nets = [nets] - for net in nets: - if net is not None: - for param in net.parameters(): - param.requires_grad = requires_grad - - def compute_visuals(self): - """Calculate additional output images for visdom and HTML visualization""" - pass +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import os +import sys +from collections import OrderedDict +import torch +import itertools +from util.image_pool import ImagePool +from . import networks_adapt as networks +from torch.nn.parallel import DistributedDataParallel as DDP +# from .npu_fused_adam import NpuFusedAdam as adam +from torch.optim import Adam as adam + +if sys.version_info < (3, 0): + raise RuntimeError("Apex currently only supports Python 3. Aborting.") +try: + import apex + from apex import amp +except ImportError: + amp = None + + +class CycleGANModel(): + """ + This class implements the CycleGAN model, for learning image-to-image translation without paired data. + + The model training requires '--dataset_mode unaligned' dataset. + By default, it uses a '--netG resnet_9blocks' ResNet generator, + a '--netD basic' discriminator (PatchGAN introduced by pix2pix), + and a least-square GANs objective ('--gan_mode lsgan'). + + CycleGAN paper: https://arxiv.org/pdf/1703.10593.pdf + """ + + @staticmethod + def modify_commandline_options(parser, is_train=True): + """Add new dataset-specific options, and rewrite default values for existing options. + + Parameters: + parser -- original option parser + is_train (bool) -- whether training phase or test phase. You can use this flag to add training-specific or test-specific options. + + Returns: + the modified parser. + + For CycleGAN, in addition to GAN losses, we introduce lambda_A, lambda_B, and lambda_identity for the following losses. + A (source domain), B (target domain). + Generators: G_A: A -> B; G_B: B -> A. + Discriminators: D_A: G_A(A) vs. B; D_B: G_B(B) vs. A. + Forward cycle loss: lambda_A * ||G_B(G_A(A)) - A|| (Eqn. (2) in the paper) + Backward cycle loss: lambda_B * ||G_A(G_B(B)) - B|| (Eqn. (2) in the paper) + Identity loss (optional): lambda_identity * (||G_A(B) - B|| * lambda_B + ||G_B(A) - A|| * lambda_A) (Sec 5.2 "Photo generation from paintings" in the paper) + Dropout is not used in the original CycleGAN paper. + """ + parser.set_defaults(no_dropout=True) # default CycleGAN did not use dropout + if is_train: + parser.add_argument('--lambda_A', type=float, default=10.0, help='weight for cycle loss (A -> B -> A)') + parser.add_argument('--lambda_B', type=float, default=10.0, help='weight for cycle loss (B -> A -> B)') + parser.add_argument('--lambda_identity', type=float, default=0.5, + help='use identity mapping. Setting lambda_identity other than 0 has an effect of' + ' scaling the weight of the identity mapping loss. For example, if the weight of ' + 'the identity loss should be 10 times smaller than the weight of the reconstruction' + ' loss, please set lambda_identity = 0.1') + + return parser + + def __init__(self, opt): + """Initialize the CycleGAN class. + + Parameters: + opt (Option class)-- stores all the experiment flags; needs to be a subclass of BaseOptions + """ + # specify the training losses you want to print out. The training/test scripts will call + self.opt = opt + self.isTrain = opt.isTrain + self.optimizers = [] + if (opt.npu < 1): + self.device = torch.device('cuda:{}'.format(self.opt.gpu)) # get device name: CPU or GPU + # self.device = torch.device('cuda:{}'.format(self.gpu_ids[0])) # get device name: CPU or GPU + else: + # self.device = torch.device('npu:{}'.format(self.gpu_ids)) if self.gpu_ids else torch.device( 'cpu') # get device name: CPU or GPU + self.device = torch.device('npu:{}'.format(self.opt.gpu)) # get device name: CPU or GPU + self.save_dir = os.path.join(opt.checkpoints_dir, opt.name) # save all the checkpoints to save_dir + self.loss_names = ['D_A', 'G_A', 'cycle_A', 'idt_A', 'D_B', 'G_B', 'cycle_B', 'idt_B'] + # specify the images you want to save/display. The training/test scripts will call + + visual_names_A = ['real_A', 'fake_B', 'rec_A'] + visual_names_B = ['real_B', 'fake_A', 'rec_B'] + if self.isTrain and self.opt.lambda_identity > 0.0: # if identity loss is used, we also visualize idt_B=G_A(B) ad idt_A=G_A(B) + visual_names_A.append('idt_B') + visual_names_B.append('idt_A') + + self.visual_names = visual_names_A + visual_names_B # combine visualizations for A and B + # specify the models you want to save to the disk. The training/test scripts + # will call and . + if self.isTrain: + self.model_names = ['G_A', 'G_B', 'D_A', 'D_B'] + else: # during test time, only load Gs + self.model_names = ['G_A', 'G_B'] + + # define networks (both Generators and discriminators) + # The naming is different from those used in the paper. + # Code (vs. paper): G_A (G), G_B (F), D_A (D_Y), D_B (D_X) + self.netG_A = networks.define_G(opt.input_nc, opt.output_nc, opt.ngf, opt.netG, opt.norm, + not opt.no_dropout, opt.init_type, opt.init_gain, self.opt.gpu) + self.netG_B = networks.define_G(opt.output_nc, opt.input_nc, opt.ngf, opt.netG, opt.norm, + not opt.no_dropout, opt.init_type, opt.init_gain, self.opt.gpu) + if self.isTrain: # define discriminators + self.netD_A = networks.define_D(opt.output_nc, opt.ndf, opt.netD, + opt.n_layers_D, opt.norm, opt.init_type, opt.init_gain, self.opt.gpu) + self.netD_B = networks.define_D(opt.input_nc, opt.ndf, opt.netD, + opt.n_layers_D, opt.norm, opt.init_type, opt.init_gain, self.opt.gpu) + + if self.isTrain: + if opt.lambda_identity > 0.0: # only works when input and output images have the same number of channels + assert (opt.input_nc == opt.output_nc) + self.fake_A_pool = ImagePool(opt.pool_size) # create image buffer to store previously generated images + self.fake_B_pool = ImagePool(opt.pool_size) # create image buffer to store previously generated images + # define loss functions + self.criterionGAN = networks.GANLoss(opt.gan_mode).to(self.device) # define GAN loss. + self.criterionCycle = torch.nn.L1Loss() + self.criterionIdt = torch.nn.L1Loss() + # initialize optimizers; schedulers will be automatically created by function . + self.optimizer_G = adam(itertools.chain(self.netG_A.parameters(), self.netG_B.parameters()), + lr=opt.lr, betas=(opt.beta1, 0.999)) + self.optimizer_D = adam(itertools.chain(self.netD_A.parameters(), self.netD_B.parameters()), + lr=opt.lr, betas=(opt.beta1, 0.999)) + self.optimizers.append(self.optimizer_G) + self.optimizers.append(self.optimizer_D) + self.lr_scheduler_G = networks.get_scheduler(self.optimizer_G, self.opt) + self.lr_scheduler_D = networks.get_scheduler(self.optimizer_D, self.opt) + # self.scaler = GradScaler() + amp.register_float_function(torch, 'sigmoid') + amp.register_float_function(torch, 'softmax') + amp.register_float_function(torch, 'tanh') + if (self.opt.isapex): + [self.netG_A, self.netG_B, self.netD_A, self.netD_B], [self.optimizer_G, self.optimizer_D] = \ + amp.initialize([self.netG_A, self.netG_B, self.netD_A, self.netD_B], + [self.optimizer_G, self.optimizer_D], opt_level=self.opt.apex_type, + loss_scale=self.opt.loss_scale) + if (self.opt.distributed >= 1): + temp = bool(1 - opt.npu) + self.netG_A = DDP(self.netG_A, [self.opt.gpu], broadcast_buffers=temp) + self.netG_B = DDP(self.netG_B, [self.opt.gpu], broadcast_buffers=temp) + self.netD_A = DDP(self.netD_A, [self.opt.gpu], broadcast_buffers=temp) + self.netD_B = DDP(self.netD_B, [self.opt.gpu], broadcast_buffers=temp) + + def setup(self, opt): + """Load and print networks; create schedulers + + Parameters: + opt (Option class) -- stores all the experiment flags; needs to be a subclass of BaseOptions + """ + if self.isTrain: + self.schedulers = [networks.get_scheduler(optimizer, opt) for optimizer in self.optimizers] + if not self.isTrain or opt.continue_train: + load_suffix = 'iter_%d' % opt.load_iter if opt.load_iter > 0 else opt.epoch + self.load_networks(load_suffix) + self.print_networks(opt.verbose) + + def update_learning_rate(self): + old_lr = self.optimizers[0].param_groups[0]['lr'] + for scheduler in self.schedulers: + if self.opt.lr_policy == 'plateau': + scheduler.step(self.metric) + else: + scheduler.step() + self.lr_scheduler_G.step() + self.lr_scheduler_D.step() + + def set_input(self, input): + """Unpack input data from the dataloader and perform necessary pre-processing steps. + + Parameters: + input (dict): include the data itself and its metadata information. + + The option 'direction' can be used to swap domain A and domain B. + """ + AtoB = self.opt.direction == 'AtoB' + + self.real_A = input['A' if AtoB else 'B'].to(self.device) + self.real_B = input['B' if AtoB else 'A'].to(self.device) + self.image_paths = input['A_paths' if AtoB else 'B_paths'] + + def forward(self): + """Run forward pass; called by both functions and .""" + self.fake_B = self.netG_A(self.real_A) # G_A(A) + self.rec_A = self.netG_B(self.fake_B) # G_B(G_A(A)) + self.fake_A = self.netG_B(self.real_B) # G_B(B) + self.rec_B = self.netG_A(self.fake_A) # G_A(G_B(B)) + + def backward_D_basic(self, netD, real, fake): + """Calculate GAN loss for the discriminator + + Parameters: + netD (network) -- the discriminator D + real (tensor array) -- real images + fake (tensor array) -- images generated by a generator + + Return the discriminator loss. + We also call loss_D.backward() to calculate the gradients. + """ + # Real + pred_real = netD(real) + loss_D_real = self.criterionGAN(pred_real, True) + # Fake + pred_fake = netD(fake.detach()) + loss_D_fake = self.criterionGAN(pred_fake, False) + # Combined loss and calculate gradients + loss_D = (loss_D_real + loss_D_fake) * 0.5 + if (self.opt.isapex): + with amp.scale_loss(loss_D, self.optimizer_D) as scaled_lossd: + scaled_lossd.backward() + else: + loss_D.backward() + return loss_D + + def backward_D_A(self): + """Calculate GAN loss for discriminator D_A""" + fake_B = self.fake_B_pool.query(self.fake_B) + self.loss_D_A = self.backward_D_basic(self.netD_A, self.real_B, fake_B) + + def backward_D_B(self): + """Calculate GAN loss for discriminator D_B""" + fake_A = self.fake_A_pool.query(self.fake_A) + self.loss_D_B = self.backward_D_basic(self.netD_B, self.real_A, fake_A) + + def backward_G(self): + """Calculate the loss for generators G_A and G_B""" + lambda_idt = self.opt.lambda_identity + lambda_A = self.opt.lambda_A + lambda_B = self.opt.lambda_B + # Identity loss + if lambda_idt > 0: + # G_A should be identity if real_B is fed: ||G_A(B) - B|| + self.idt_A = self.netG_A(self.real_B) + self.loss_idt_A = self.criterionIdt(self.idt_A, self.real_B) * lambda_B * lambda_idt + # G_B should be identity if real_A is fed: ||G_B(A) - A|| + self.idt_B = self.netG_B(self.real_A) + self.loss_idt_B = self.criterionIdt(self.idt_B, self.real_A) * lambda_A * lambda_idt + else: + self.loss_idt_A = 0 + self.loss_idt_B = 0 + + # GAN loss D_A(G_A(A)) + self.loss_G_A = self.criterionGAN(self.netD_A(self.fake_B), True) + # GAN loss D_B(G_B(B)) + self.loss_G_B = self.criterionGAN(self.netD_B(self.fake_A), True) + # Forward cycle loss || G_B(G_A(A)) - A|| + self.loss_cycle_A = self.criterionCycle(self.rec_A, self.real_A) * lambda_A + # Backward cycle loss || G_A(G_B(B)) - B|| + self.loss_cycle_B = self.criterionCycle(self.rec_B, self.real_B) * lambda_B + # combined loss and calculate gradients + self.loss_G = self.loss_G_A + self.loss_G_B + self.loss_cycle_A + self.loss_cycle_B + self.loss_idt_A + self.loss_idt_B + if (self.opt.isapex == True): + with amp.scale_loss(self.loss_G, self.optimizer_G) as scaled_lossg: + scaled_lossg.backward() + else: + self.loss_G.backward() + + def optimize_parameters(self): + """Calculate losses, gradients, and update network weights; called in every training iteration""" + # forwar + self.forward() # compute fake images and reconstruction images. + # G_A and G_B + self.set_requires_grad([self.netD_A, self.netD_B], False) # Ds require no gradients when optimizing Gs + self.optimizer_G.zero_grad() # set G_A and G_B's gradients to zero + self.backward_G() # calculate gradients for G_A and G_B + self.optimizer_G.step() # update G_A and G_B's weights + # D_A and D_B + self.set_requires_grad([self.netD_A, self.netD_B], True) + self.optimizer_D.zero_grad() # set D_A and D_B's gradients to zero + self.backward_D_A() # calculate gradients for D_A + self.backward_D_B() # calculate graidents for D_B + self.optimizer_D.step() # update D_A and D_B's weights + + def get_current_visuals(self): + """Return visualization images. train.py will display these images with visdom, and save the images to a HTML""" + visual_ret = OrderedDict() + for name in self.visual_names: + if isinstance(name, str): + visual_ret[name] = getattr(self, name) + return visual_ret + + def get_current_losses(self): + """Return traning losses / errors. train.py will print out these errors on console, and save them to a file""" + errors_ret = OrderedDict() + for name in self.loss_names: + if isinstance(name, str): + errors_ret[name] = float( + getattr(self, 'loss_' + name)) # float(...) works for both scalar tensor and float number + return errors_ret + + def save_networks(self, epoch): + """Save all the networks to the disk. + + Parameters: + epoch (int) -- current epoch; used in the file name '%s_net_%s.pth' % (epoch, name) + """ + for name in self.model_names: + if isinstance(name, str): + save_filename = '%s_net_%s.pth' % (epoch, name) + save_path = os.path.join(self.save_dir, save_filename) + save_path1 = os.path.join(self.save_dir, 'a' + save_filename) + net = getattr(self, 'net' + name) + + if self.opt.distributed >= 1 and torch.cuda.is_available(): + torch.save(net.cpu().module.state_dict(), save_path) + if (self.opt.npu >= 1): + net.npu(self.opt.gpu) + else: + net.cuda(self.opt.gpu) + else: + torch.save(net.cpu().state_dict(), save_path) + if (self.opt.npu >= 1): + net.npu(self.opt.gpu) + else: + net.cuda(self.opt.gpu) + + def __patch_instance_norm_state_dict(self, state_dict, module, keys, i=0): + """Fix InstanceNorm checkpoints incompatibility (prior to 0.4)""" + key = keys[i] + if i + 1 == len(keys): # at the end, pointing to a parameter/buffer + if module.__class__.__name__.startswith('InstanceNorm') and \ + (key == 'running_mean' or key == 'running_var'): + if getattr(module, key) is None: + state_dict.pop('.'.join(keys)) + if module.__class__.__name__.startswith('InstanceNorm') and \ + (key == 'num_batches_tracked'): + state_dict.pop('.'.join(keys)) + else: + self.__patch_instance_norm_state_dict(state_dict, getattr(module, key), keys, i + 1) + + def load_networks(self, epoch): + """Load all the networks from the disk. + + Parameters: + epoch (int) -- current epoch; used in the file name '%s_net_%s.pth' % (epoch, name) + """ + for name in self.model_names: + if isinstance(name, str): + load_filename = '%s_net_%s.pth' % (epoch, name) + load_path = os.path.join(self.save_dir, load_filename) + net = getattr(self, 'net' + name) + if isinstance(net, torch.nn.DataParallel): + net = net.module + print('loading the model from %s' % load_path) + # if you are using PyTorch newer than 0.4 (e.g., built from + # GitHub source), you can remove str() on self.device + state_dict = torch.load(load_path, map_location=str(self.device)) + if hasattr(state_dict, '_metadata'): + del state_dict._metadata + + # patch InstanceNorm checkpoints prior to 0.4 + for key in list(state_dict.keys()): # need to copy keys here because we mutate in loop + self.__patch_instance_norm_state_dict(state_dict, net, key.split('.')) + net.load_state_dict(state_dict) + + def print_networks(self, verbose): + """Print the total number of parameters in the network and (if verbose) network architecture + + Parameters: + verbose (bool) -- if verbose: print the network architecture + """ + print('---------- Networks initialized -------------') + for name in self.model_names: + if isinstance(name, str): + net = getattr(self, 'net' + name) + num_params = 0 + for param in net.parameters(): + num_params += param.numel() + if verbose: + print(net) + print('[Network %s] Total number of parameters : %.3f M' % (name, num_params / 1e6)) + print('-----------------------------------------------') + + def set_requires_grad(self, nets, requires_grad=False): + """Set requies_grad=Fasle for all the networks to avoid unnecessary computations + Parameters: + nets (network list) -- a list of networks + requires_grad (bool) -- whether the networks require gradients or not + """ + if not isinstance(nets, list): + nets = [nets] + for net in nets: + if net is not None: + for param in net.parameters(): + param.requires_grad = requires_grad + + def compute_visuals(self): + """Calculate additional output images for visdom and HTML visualization""" + pass diff --git a/PyTorch/contrib/cv/others/CycleGAN/modelzoo_level.txt b/PyTorch/contrib/cv/others/CycleGAN/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/others/CycleGAN/modelzoo_level.txt +++ b/PyTorch/contrib/cv/others/CycleGAN/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/CycleGAN/parse.py b/PyTorch/contrib/cv/others/CycleGAN/parse.py index 64e6560084..a58d344312 100644 --- a/PyTorch/contrib/cv/others/CycleGAN/parse.py +++ b/PyTorch/contrib/cv/others/CycleGAN/parse.py @@ -1,236 +1,236 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -import argparse -import torch - - -class parse_args(): - def __init__(self, isTrain=True, isTest=False): - self.isTrain = isTrain - self.isTest = isTest - self.parser = argparse.ArgumentParser(description='Pytorch CycleGAN training') - - def initialize(self): - parser = self.parser - parser.add_argument('--model_ga_path', type=str, - default='./checkpoints_8pbs1/maps_cycle_gan/175_pu0_net_G_A.pth', - help='path for modelga') - parser.add_argument('--model_gb_path', type=str, - default='./checkpoints_8pbs1/maps_cycle_gan/175_pu0_net_G_B.pth', - help='path for modelga') - parser.add_argument('--prof', type=int, default=1, help='whether to get prof file') - parser.add_argument('--num_epoch', type=int, default=240, help='whether to get prof file1') - parser.add_argument('--line_scale', type=float, default=2, help='whether to get prof file1') - parser.add_argument('--num_epoch_start', type=int, default=0, help='whether to get prof file1') - parser.add_argument('--loadweight', default='latest', help='whether to get prof file1') - parser.add_argument('--prof_file', type=str, default='./output.prof', help='whether to get prof file') - parser.add_argument('--log_path', type=str, default='gpu1p.txt', help='whether to get prof file') - parser.add_argument('--multiprocessing_distributed', type=int, default=1, - help='Use multi-processing distributed training to launch,if it is eaqul to 1 or more than ,start to npu/gpu Multi-card training ') - parser.add_argument('--world_size', type=int, default=1, help='word__size') - parser.add_argument('--distributed', type=int, default=1, - help='whether to use distributed to fastern training,if it is eaqul to 1 or more than ,start to npu/gpu Multi-card training') - parser.add_argument('--rank', default=0, type=int, help='rank') - parser.add_argument('--gpu', default=None, type=int, help='GPU id to use.') - parser.add_argument('--npu', type=int, default=0, help='whether to use npu to fastern training') - parser.add_argument('--pu_ids', type=str, default='0,1', - help='gpu ids(npu ids): e.g. 0 0,1,2, 0,2. use -1 for CPU') - - parser.add_argument('--isapex', default=True, help='whether to use apex to fastern training') - parser.add_argument('--apex_type', type=str, default="O1", help='O0,O1,O2,O3') - parser.add_argument('--loss_scale', default=None, help='loss_scale:1,128,dynamic') - parser.add_argument('--dataroot', type=str, default='./datasets/maps', - help='path to images (should have subfolders trainA, trainB, valA, valB, etc)') - parser.add_argument('--name', type=str, default='maps_cycle_gan', - help='name of the experiment. It decides where to store samples and models') - - parser.add_argument('--checkpoints_dir', type=str, default='./re_checkpoints2p_bs1', - help='models are saved here') - # model parameters - parser.add_argument('--model', type=str, default='cycle_gan', - help='chooses which model to use. [cycle_gan| pix2pix | test | colorization]') - parser.add_argument('--input_nc', type=int, default=3, - help='# of input image channels: 3 for RGB and 1 for grayscale') - parser.add_argument('--output_nc', type=int, default=3, - help='# of output image channels: 3 for RGB and 1 for grayscale') - parser.add_argument('--ngf', type=int, default=64, help='# of gen filters in the last conv layer') - parser.add_argument('--ndf', type=int, default=64, help='# of discrim filters in the first conv layer') - parser.add_argument('--netD', type=str, default='basic', - help='specify discriminator architecture [basic | n_layers | pixel].' - ' The basic model is a 70x70 PatchGAN. n_layers allows you to ' - 'specify the layers in the discriminator') - parser.add_argument('--netG', type=str, default='resnet_9blocks', - help='specify generator architecture [resnet_9blocks | resnet_6blocks | ' - 'unet_256 | unet_128]') - parser.add_argument('--n_layers_D', type=int, default=3, help='only used if netD==n_layers') - parser.add_argument('--norm', type=str, default='instance', - help='instance normalization or batch normalization [instance | batch | none]') - parser.add_argument('--init_type', type=str, default='normal', - help='network initialization [normal | xavier | kaiming | orthogonal]') - parser.add_argument('--init_gain', type=float, default=0.02, - help='scaling factor for normal, xavier and orthogonal.') - parser.add_argument('--no_dropout', action='store_true', help='no dropout for the generator') - # dataset parameters - parser.add_argument('--dataset_mode', type=str, default='unaligned', - help='chooses how datasets are loaded. [unaligned | aligned | single | colorization]') - parser.add_argument('--direction', type=str, default='AtoB', help='AtoB or BtoA') - parser.add_argument('--serial_batches', action='store_true', - help='if true, takes images in order to make batches, otherwise takes them randomly') - parser.add_argument('--num_threads', default=8, type=int, help='# threads for loading data') - parser.add_argument('--batch_size', type=int, default=4, help='input batch size') - parser.add_argument('--load_size', type=int, default=286, help='scale images to this size') - parser.add_argument('--crop_size', type=int, default=256, help='then crop to this size') - parser.add_argument('--max_dataset_size', type=int, default=float("inf"), - help='Maximum number of samples allowed per dataset. If the dataset directory ' - 'contains more than max_dataset_size, only a subset is loaded.') - parser.add_argument('--preprocess', type=str, default='resize_and_crop', - help='scaling and cropping of images at load time [resize_and_crop | crop | ' - 'scale_width | scale_width_and_crop | none]') - parser.add_argument('--no_flip', action='store_true', - help='if specified, do not flip the images for data augmentation') - parser.add_argument('--display_winsize', type=int, default=256, - help='display window size for both visdom and HTML') - # additional parameters - parser.add_argument('--epoch', type=str, default='latest', - help='which epoch to load? set to latest to use latest cached model') - parser.add_argument('--load_iter', type=int, default='0', - help='which iteration to load? if load_iter > 0, the code will load models by iter_' - '[load_iter]; otherwise, the code will load models by [epoch]') - parser.add_argument('--verbose', action='store_true', help='if specified, print more debugging information') - parser.add_argument('--suffix', default='', type=str, - help='customized suffix: opt.name = opt.name + suffix: e.g., {model}_{netG}_size{load_size}') - parser.add_argument( - "--cache-dataset", - dest="cache_dataset", - help="Cache the datasets for quicker initialization. It also serializes the transforms", - action="store_true", - ) - parser.set_defaults(no_dropout=True) # default CycleGAN did not use dropout - if (self.isTrain): - # network saving and loading parameters - parser.add_argument('--display_freq', type=int, default=400, - help='frequency of showing training results on screen') - parser.add_argument('--display_ncols', type=int, default=4, - help='if positive, display all images in a single visdom web panel with ' - 'certain number of images per row.') - parser.add_argument('--display_id', type=int, default=-1, help='window id of the web display') - parser.add_argument('--display_server', type=str, default="http://localhost", - help='visdom server of the web display') - parser.add_argument('--display_env', type=str, default='main', - help='visdom display environment name (default is "main")') - parser.add_argument('--display_port', type=int, default=8097, help='visdom port of the web display') - parser.add_argument('--update_html_freq', type=int, default=1000, - help='frequency of saving training results to html') - parser.add_argument('--print_freq', type=int, default=100, - help='frequency of showing training results on console') - parser.add_argument('--no_html', action='store_true', - help='do not save intermediate training results to [' - 'opt.checkpoints_dir]/[opt.name]/web/') - # network saving and loading parameters - parser.add_argument('--save_latest_freq', type=int, default=5000, - help='frequency of saving the latest results') - parser.add_argument('--save_epoch_freq', type=int, default=5, - help='frequency of saving checkpoints at the end of epochs') - parser.add_argument('--save_by_iter', action='store_true', help='whether saves model by iteration') - parser.add_argument('--continue_train', action='store_true', - help='continue training: load the latest model') - parser.add_argument('--epoch_count', type=int, default=1, - help='the starting epoch count, we save the model ' - 'by , +, ...') - parser.add_argument('--phase', type=str, default='train', help='train, val, test, etc') - # training parameters - parser.add_argument('--n_epochs', type=int, default=100, - help='number of epochs with the initial learning rate') - parser.add_argument('--n_epochs_decay', type=int, default=100, - help='number of epochs to linearly decay learning rate to zero') - parser.add_argument('--beta1', type=float, default=0.5, help='momentum term of adam') - parser.add_argument('--lr', type=float, default=0.0002, help='initial learning rate for adam') - parser.add_argument('--gan_mode', type=str, default='lsgan', - help='the type of GAN objective. [vanilla| lsgan | wgangp]. vanilla GAN loss is' - ' the cross-entropy objective used in the original GAN paper.') - parser.add_argument('--pool_size', type=int, default=50, - help='the size of image buffer that stores previously generated images') - parser.add_argument('--lr_policy', type=str, default='linear', - help='learning rate policy. [linear | step | plateau | cosine]') - parser.add_argument('--lr_decay_iters', type=int, default=50, - help='multiply by a gamma every lr_decay_iters iterations') - parser.add_argument('--lambda_A', type=float, default=10.0, help='weight for cycle loss (A -> B -> A)') - parser.add_argument('--lambda_B', type=float, default=10.0, help='weight for cycle loss (B -> A -> B)') - parser.add_argument('--lambda_identity', type=float, default=0.5, - help='use identity mapping. Setting lambda_identity other than 0 has an effect of' - ' scaling the weight of the identity mapping loss. For example, if the weight of' - ' the identity loss should be 10 times smaller than the weight of the ' - 'reconstruction loss, please set lambda_identity = 0.1') - parser = parser.parse_args() - parser.process_device_map = self.device_id_to_process_device_map(parser.pu_ids) - return parser - - def device_id_to_process_device_map(self, device_list): - devices = device_list.split(",") - devices = [int(x) for x in devices] - devices.sort() - - process_device_map = dict() - for process_id, device_id in enumerate(devices): - process_device_map[process_id] = device_id - return process_device_map - - def change_parser(self, isTrain=True, isTest=False): - self.isTest = isTest - self.isTrain = isTrain - self.parser = None - return self.initialize() - - def printParser(self): - pasers = self.parser.parse_args() - message = '' - message += '----------------- Options ---------------\n' - for k, v in sorted(vars(pasers).items()): - comment = '' - default = self.parser.get_default(k) - # if v != default: - # comment = '\t[default: %s]' % str(default) - message += '{:>25}: {:<30}{}\n'.format(str(k), str(v), comment) - message += '----------------- End -------------------' - print(message) - - def init_distributed_mode(self, ngpus_per_node, gpu): - opt = self.parser.parse_args() - if opt.multiprocessing_distributed >= 1: - # For multiprocessing distributed training, rank needs to be the - # global rank among all the processes - opt.rank = opt.rank * ngpus_per_node + gpu - if (opt.npu < 1): - torch.distributed.init_process_group(backend='nccl', init_method='env://', world_size=opt.world_size, - rank=opt.rank) - elif (opt.npu >= 1): - torch.distributed.init_process_group(backend='hccl', world_size=opt.world_size, rank=opt.rank) +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import argparse +import torch + + +class parse_args(): + def __init__(self, isTrain=True, isTest=False): + self.isTrain = isTrain + self.isTest = isTest + self.parser = argparse.ArgumentParser(description='Pytorch CycleGAN training') + + def initialize(self): + parser = self.parser + parser.add_argument('--model_ga_path', type=str, + default='./checkpoints_8pbs1/maps_cycle_gan/175_pu0_net_G_A.pth', + help='path for modelga') + parser.add_argument('--model_gb_path', type=str, + default='./checkpoints_8pbs1/maps_cycle_gan/175_pu0_net_G_B.pth', + help='path for modelga') + parser.add_argument('--prof', type=int, default=1, help='whether to get prof file') + parser.add_argument('--num_epoch', type=int, default=240, help='whether to get prof file1') + parser.add_argument('--line_scale', type=float, default=2, help='whether to get prof file1') + parser.add_argument('--num_epoch_start', type=int, default=0, help='whether to get prof file1') + parser.add_argument('--loadweight', default='latest', help='whether to get prof file1') + parser.add_argument('--prof_file', type=str, default='./output.prof', help='whether to get prof file') + parser.add_argument('--log_path', type=str, default='gpu1p.txt', help='whether to get prof file') + parser.add_argument('--multiprocessing_distributed', type=int, default=1, + help='Use multi-processing distributed training to launch,if it is eaqul to 1 or more than ,start to npu/gpu Multi-card training ') + parser.add_argument('--world_size', type=int, default=1, help='word__size') + parser.add_argument('--distributed', type=int, default=1, + help='whether to use distributed to fastern training,if it is eaqul to 1 or more than ,start to npu/gpu Multi-card training') + parser.add_argument('--rank', default=0, type=int, help='rank') + parser.add_argument('--gpu', default=None, type=int, help='GPU id to use.') + parser.add_argument('--npu', type=int, default=0, help='whether to use npu to fastern training') + parser.add_argument('--pu_ids', type=str, default='0,1', + help='gpu ids(npu ids): e.g. 0 0,1,2, 0,2. use -1 for CPU') + + parser.add_argument('--isapex', default=True, help='whether to use apex to fastern training') + parser.add_argument('--apex_type', type=str, default="O1", help='O0,O1,O2,O3') + parser.add_argument('--loss_scale', default=None, help='loss_scale:1,128,dynamic') + parser.add_argument('--dataroot', type=str, default='./datasets/maps', + help='path to images (should have subfolders trainA, trainB, valA, valB, etc)') + parser.add_argument('--name', type=str, default='maps_cycle_gan', + help='name of the experiment. It decides where to store samples and models') + + parser.add_argument('--checkpoints_dir', type=str, default='./re_checkpoints2p_bs1', + help='models are saved here') + # model parameters + parser.add_argument('--model', type=str, default='cycle_gan', + help='chooses which model to use. [cycle_gan| pix2pix | test | colorization]') + parser.add_argument('--input_nc', type=int, default=3, + help='# of input image channels: 3 for RGB and 1 for grayscale') + parser.add_argument('--output_nc', type=int, default=3, + help='# of output image channels: 3 for RGB and 1 for grayscale') + parser.add_argument('--ngf', type=int, default=64, help='# of gen filters in the last conv layer') + parser.add_argument('--ndf', type=int, default=64, help='# of discrim filters in the first conv layer') + parser.add_argument('--netD', type=str, default='basic', + help='specify discriminator architecture [basic | n_layers | pixel].' + ' The basic model is a 70x70 PatchGAN. n_layers allows you to ' + 'specify the layers in the discriminator') + parser.add_argument('--netG', type=str, default='resnet_9blocks', + help='specify generator architecture [resnet_9blocks | resnet_6blocks | ' + 'unet_256 | unet_128]') + parser.add_argument('--n_layers_D', type=int, default=3, help='only used if netD==n_layers') + parser.add_argument('--norm', type=str, default='instance', + help='instance normalization or batch normalization [instance | batch | none]') + parser.add_argument('--init_type', type=str, default='normal', + help='network initialization [normal | xavier | kaiming | orthogonal]') + parser.add_argument('--init_gain', type=float, default=0.02, + help='scaling factor for normal, xavier and orthogonal.') + parser.add_argument('--no_dropout', action='store_true', help='no dropout for the generator') + # dataset parameters + parser.add_argument('--dataset_mode', type=str, default='unaligned', + help='chooses how datasets are loaded. [unaligned | aligned | single | colorization]') + parser.add_argument('--direction', type=str, default='AtoB', help='AtoB or BtoA') + parser.add_argument('--serial_batches', action='store_true', + help='if true, takes images in order to make batches, otherwise takes them randomly') + parser.add_argument('--num_threads', default=8, type=int, help='# threads for loading data') + parser.add_argument('--batch_size', type=int, default=4, help='input batch size') + parser.add_argument('--load_size', type=int, default=286, help='scale images to this size') + parser.add_argument('--crop_size', type=int, default=256, help='then crop to this size') + parser.add_argument('--max_dataset_size', type=int, default=float("inf"), + help='Maximum number of samples allowed per dataset. If the dataset directory ' + 'contains more than max_dataset_size, only a subset is loaded.') + parser.add_argument('--preprocess', type=str, default='resize_and_crop', + help='scaling and cropping of images at load time [resize_and_crop | crop | ' + 'scale_width | scale_width_and_crop | none]') + parser.add_argument('--no_flip', action='store_true', + help='if specified, do not flip the images for data augmentation') + parser.add_argument('--display_winsize', type=int, default=256, + help='display window size for both visdom and HTML') + # additional parameters + parser.add_argument('--epoch', type=str, default='latest', + help='which epoch to load? set to latest to use latest cached model') + parser.add_argument('--load_iter', type=int, default='0', + help='which iteration to load? if load_iter > 0, the code will load models by iter_' + '[load_iter]; otherwise, the code will load models by [epoch]') + parser.add_argument('--verbose', action='store_true', help='if specified, print more debugging information') + parser.add_argument('--suffix', default='', type=str, + help='customized suffix: opt.name = opt.name + suffix: e.g., {model}_{netG}_size{load_size}') + parser.add_argument( + "--cache-dataset", + dest="cache_dataset", + help="Cache the datasets for quicker initialization. It also serializes the transforms", + action="store_true", + ) + parser.set_defaults(no_dropout=True) # default CycleGAN did not use dropout + if (self.isTrain): + # network saving and loading parameters + parser.add_argument('--display_freq', type=int, default=400, + help='frequency of showing training results on screen') + parser.add_argument('--display_ncols', type=int, default=4, + help='if positive, display all images in a single visdom web panel with ' + 'certain number of images per row.') + parser.add_argument('--display_id', type=int, default=-1, help='window id of the web display') + parser.add_argument('--display_server', type=str, default="http://localhost", + help='visdom server of the web display') + parser.add_argument('--display_env', type=str, default='main', + help='visdom display environment name (default is "main")') + parser.add_argument('--display_port', type=int, default=8097, help='visdom port of the web display') + parser.add_argument('--update_html_freq', type=int, default=1000, + help='frequency of saving training results to html') + parser.add_argument('--print_freq', type=int, default=100, + help='frequency of showing training results on console') + parser.add_argument('--no_html', action='store_true', + help='do not save intermediate training results to [' + 'opt.checkpoints_dir]/[opt.name]/web/') + # network saving and loading parameters + parser.add_argument('--save_latest_freq', type=int, default=5000, + help='frequency of saving the latest results') + parser.add_argument('--save_epoch_freq', type=int, default=5, + help='frequency of saving checkpoints at the end of epochs') + parser.add_argument('--save_by_iter', action='store_true', help='whether saves model by iteration') + parser.add_argument('--continue_train', action='store_true', + help='continue training: load the latest model') + parser.add_argument('--epoch_count', type=int, default=1, + help='the starting epoch count, we save the model ' + 'by , +, ...') + parser.add_argument('--phase', type=str, default='train', help='train, val, test, etc') + # training parameters + parser.add_argument('--n_epochs', type=int, default=100, + help='number of epochs with the initial learning rate') + parser.add_argument('--n_epochs_decay', type=int, default=100, + help='number of epochs to linearly decay learning rate to zero') + parser.add_argument('--beta1', type=float, default=0.5, help='momentum term of adam') + parser.add_argument('--lr', type=float, default=0.0002, help='initial learning rate for adam') + parser.add_argument('--gan_mode', type=str, default='lsgan', + help='the type of GAN objective. [vanilla| lsgan | wgangp]. vanilla GAN loss is' + ' the cross-entropy objective used in the original GAN paper.') + parser.add_argument('--pool_size', type=int, default=50, + help='the size of image buffer that stores previously generated images') + parser.add_argument('--lr_policy', type=str, default='linear', + help='learning rate policy. [linear | step | plateau | cosine]') + parser.add_argument('--lr_decay_iters', type=int, default=50, + help='multiply by a gamma every lr_decay_iters iterations') + parser.add_argument('--lambda_A', type=float, default=10.0, help='weight for cycle loss (A -> B -> A)') + parser.add_argument('--lambda_B', type=float, default=10.0, help='weight for cycle loss (B -> A -> B)') + parser.add_argument('--lambda_identity', type=float, default=0.5, + help='use identity mapping. Setting lambda_identity other than 0 has an effect of' + ' scaling the weight of the identity mapping loss. For example, if the weight of' + ' the identity loss should be 10 times smaller than the weight of the ' + 'reconstruction loss, please set lambda_identity = 0.1') + parser = parser.parse_args() + parser.process_device_map = self.device_id_to_process_device_map(parser.pu_ids) + return parser + + def device_id_to_process_device_map(self, device_list): + devices = device_list.split(",") + devices = [int(x) for x in devices] + devices.sort() + + process_device_map = dict() + for process_id, device_id in enumerate(devices): + process_device_map[process_id] = device_id + return process_device_map + + def change_parser(self, isTrain=True, isTest=False): + self.isTest = isTest + self.isTrain = isTrain + self.parser = None + return self.initialize() + + def printParser(self): + pasers = self.parser.parse_args() + message = '' + message += '----------------- Options ---------------\n' + for k, v in sorted(vars(pasers).items()): + comment = '' + default = self.parser.get_default(k) + # if v != default: + # comment = '\t[default: %s]' % str(default) + message += '{:>25}: {:<30}{}\n'.format(str(k), str(v), comment) + message += '----------------- End -------------------' + print(message) + + def init_distributed_mode(self, ngpus_per_node, gpu): + opt = self.parser.parse_args() + if opt.multiprocessing_distributed >= 1: + # For multiprocessing distributed training, rank needs to be the + # global rank among all the processes + opt.rank = opt.rank * ngpus_per_node + gpu + if (opt.npu < 1): + torch.distributed.init_process_group(backend='nccl', init_method='env://', world_size=opt.world_size, + rank=opt.rank) + elif (opt.npu >= 1): + torch.distributed.init_process_group(backend='hccl', world_size=opt.world_size, rank=opt.rank) diff --git a/PyTorch/contrib/cv/others/CycleGAN/requirements.txt b/PyTorch/contrib/cv/others/CycleGAN/requirements.txt index 4038ca0bc4..8a81295f99 100644 --- a/PyTorch/contrib/cv/others/CycleGAN/requirements.txt +++ b/PyTorch/contrib/cv/others/CycleGAN/requirements.txt @@ -1,4 +1,4 @@ -torch>=1.4.0 -torchvision>=0.5.0 -dominate>=2.4.0 +torch>=1.4.0 +torchvision>=0.5.0 +dominate>=2.4.0 visdom>=0.1.8.8 \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/CycleGAN/train.py b/PyTorch/contrib/cv/others/CycleGAN/train.py index 4396d1904c..0e54494a62 100644 --- a/PyTorch/contrib/cv/others/CycleGAN/train.py +++ b/PyTorch/contrib/cv/others/CycleGAN/train.py @@ -1,130 +1,130 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -import os -import time -import torch -from dataloader import create_dataset -from parse import parse_args -from util.visualizer_adapt import Visualizer -import torch.multiprocessing as mp -from models.cycle_gan_model_adapt import CycleGANModel as create_model -from torch import distributed as dist - - -def main(opt): - os.environ['MASTER_ADDR'] = '127.0.0.1' - os.environ['MASTER_PORT'] = '23112' - if opt.distributed >= 1: - ngpus_per_node = len(opt.process_device_map) - opt.ngpus_per_node = ngpus_per_node - if (ngpus_per_node == 1): - ngpus_per_node = 0 - opt.total_iters = 0 - if opt.multiprocessing_distributed >= 1: - opt.world_size = ngpus_per_node * opt.world_size - mp.spawn(main_worker, nprocs=ngpus_per_node, args=(ngpus_per_node, opt)) - else: - main_worker(ngpus_per_node, opt, opt) - - -def main_worker(gpu, ngpus_per_node, args): - opt = args - print([args.process_device_map, gpu]) - opt.gpu = args.process_device_map[gpu] - if (opt.distributed >= 1): - opt.rank = gpu - if opt.multiprocessing_distributed >= 1: - opt.rank = gpu - if (opt.npu < 1): - torch.distributed.init_process_group(backend='nccl', init_method='env://', world_size=opt.world_size, - rank=opt.rank) - elif (opt.npu >= 1): - torch.npu.set_device(gpu) - torch.distributed.init_process_group(backend='hccl', world_size=opt.world_size, rank=opt.rank) - dataset, train_sampler = create_dataset(opt) # create a dataset given opt.dataset_mode and other options - dataset_size = len(dataset) # get the number of images in the dataset. - print('The number of training images = %d' % dataset_size) - opt.isTrain = True - model = create_model(opt) # create a model given opt.model and other options - model.setup(opt) - visualizer = Visualizer(opt) # create a visualizer that display/save images and plots - for epoch in range(opt.num_epoch_start, opt.num_epoch): - visualizer.reset() # reset the visualizer: make sure it saves the results to HTML at least once every epoch - if (opt.ngpus_per_node > 1): - train_sampler.set_epoch(epoch) - for i, data in enumerate(dataset): # inner loop within one epoch - iter_start_time = time.time() # timer for computation per iteration - opt.total_iters += (opt.batch_size * opt.ngpus_per_node) - if (opt.prof >= 1 and i > 10): - if (opt.npu == False): - with torch.autograd.profiler.profile(use_cuda=True) as prof: - model.set_input(data) - model.optimize_parameters() - print(prof.key_averages().table()) - prof.export_chrome_trace(opt.prof_file) # "output.prof" - opt.prof = False - else: - with torch.autograd.profiler.profile(use_npu=True) as prof: - model.set_input(data) - model.optimize_parameters() - print(prof.key_averages().table()) - prof.export_chrome_trace(opt.prof_file) # - opt.prof = False - else: - model.set_input(data) - model.optimize_parameters() - if opt.total_iters % opt.save_latest_freq == 0: # print training losses and save logging information to the disk - model.save_networks(epoch) - # model.save_networks(epoch) - if opt.total_iters % opt.display_freq == 0: # display images on visdom and save images to a HTML file - t_comp = (time.time() - iter_start_time) / opt.batch_size - fps = opt.batch_size * opt.ngpus_per_node / t_comp - losses = model.get_current_losses() - visualizer.print_current_losses(epoch, fps, losses, t_comp) - # print_current_losses(opt, epoch, fps, losses, t_comp) - save_result = opt.total_iters % opt.update_html_freq == 0 - model.compute_visuals() - visualizer.display_current_results(model.get_current_visuals(), epoch, save_result) - model.update_learning_rate() # Update learning rates - - if epoch % opt.save_epoch_freq == 0: # cache our model every epochs - print('saving the model at the end of epoch %d, iters %d' % (epoch, opt.total_iters)) - model.save_networks('latest_pu' + str(opt.gpu)) - model.save_networks(str(epoch) + '_pu' + str(opt.gpu)) - dist.barrier() - - -if __name__ == '__main__': - paser = parse_args(True, False) - opt = paser.initialize() - paser.printParser() - main(opt) +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import os +import time +import torch +from dataloader import create_dataset +from parse import parse_args +from util.visualizer_adapt import Visualizer +import torch.multiprocessing as mp +from models.cycle_gan_model_adapt import CycleGANModel as create_model +from torch import distributed as dist + + +def main(opt): + os.environ['MASTER_ADDR'] = '127.0.0.1' + os.environ['MASTER_PORT'] = '23112' + if opt.distributed >= 1: + ngpus_per_node = len(opt.process_device_map) + opt.ngpus_per_node = ngpus_per_node + if (ngpus_per_node == 1): + ngpus_per_node = 0 + opt.total_iters = 0 + if opt.multiprocessing_distributed >= 1: + opt.world_size = ngpus_per_node * opt.world_size + mp.spawn(main_worker, nprocs=ngpus_per_node, args=(ngpus_per_node, opt)) + else: + main_worker(ngpus_per_node, opt, opt) + + +def main_worker(gpu, ngpus_per_node, args): + opt = args + print([args.process_device_map, gpu]) + opt.gpu = args.process_device_map[gpu] + if (opt.distributed >= 1): + opt.rank = gpu + if opt.multiprocessing_distributed >= 1: + opt.rank = gpu + if (opt.npu < 1): + torch.distributed.init_process_group(backend='nccl', init_method='env://', world_size=opt.world_size, + rank=opt.rank) + elif (opt.npu >= 1): + torch.npu.set_device(gpu) + torch.distributed.init_process_group(backend='hccl', world_size=opt.world_size, rank=opt.rank) + dataset, train_sampler = create_dataset(opt) # create a dataset given opt.dataset_mode and other options + dataset_size = len(dataset) # get the number of images in the dataset. + print('The number of training images = %d' % dataset_size) + opt.isTrain = True + model = create_model(opt) # create a model given opt.model and other options + model.setup(opt) + visualizer = Visualizer(opt) # create a visualizer that display/save images and plots + for epoch in range(opt.num_epoch_start, opt.num_epoch): + visualizer.reset() # reset the visualizer: make sure it saves the results to HTML at least once every epoch + if (opt.ngpus_per_node > 1): + train_sampler.set_epoch(epoch) + for i, data in enumerate(dataset): # inner loop within one epoch + iter_start_time = time.time() # timer for computation per iteration + opt.total_iters += (opt.batch_size * opt.ngpus_per_node) + if (opt.prof >= 1 and i > 10): + if (opt.npu == False): + with torch.autograd.profiler.profile(use_cuda=True) as prof: + model.set_input(data) + model.optimize_parameters() + print(prof.key_averages().table()) + prof.export_chrome_trace(opt.prof_file) # "output.prof" + opt.prof = False + else: + with torch.autograd.profiler.profile(use_npu=True) as prof: + model.set_input(data) + model.optimize_parameters() + print(prof.key_averages().table()) + prof.export_chrome_trace(opt.prof_file) # + opt.prof = False + else: + model.set_input(data) + model.optimize_parameters() + if opt.total_iters % opt.save_latest_freq == 0: # print training losses and save logging information to the disk + model.save_networks(epoch) + # model.save_networks(epoch) + if opt.total_iters % opt.display_freq == 0: # display images on visdom and save images to a HTML file + t_comp = (time.time() - iter_start_time) / opt.batch_size + fps = opt.batch_size * opt.ngpus_per_node / t_comp + losses = model.get_current_losses() + visualizer.print_current_losses(epoch, fps, losses, t_comp) + # print_current_losses(opt, epoch, fps, losses, t_comp) + save_result = opt.total_iters % opt.update_html_freq == 0 + model.compute_visuals() + visualizer.display_current_results(model.get_current_visuals(), epoch, save_result) + model.update_learning_rate() # Update learning rates + + if epoch % opt.save_epoch_freq == 0: # cache our model every epochs + print('saving the model at the end of epoch %d, iters %d' % (epoch, opt.total_iters)) + model.save_networks('latest_pu' + str(opt.gpu)) + model.save_networks(str(epoch) + '_pu' + str(opt.gpu)) + dist.barrier() + + +if __name__ == '__main__': + paser = parse_args(True, False) + opt = paser.initialize() + paser.printParser() + main(opt) diff --git a/PyTorch/contrib/cv/others/DCGAN/LICENSE b/PyTorch/contrib/cv/others/DCGAN/LICENSE index 753842b672..f49a4e16e6 100644 --- a/PyTorch/contrib/cv/others/DCGAN/LICENSE +++ b/PyTorch/contrib/cv/others/DCGAN/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/DCGAN/dcgan.py b/PyTorch/contrib/cv/others/DCGAN/dcgan.py index e130984ced..e486b5863e 100644 --- a/PyTorch/contrib/cv/others/DCGAN/dcgan.py +++ b/PyTorch/contrib/cv/others/DCGAN/dcgan.py @@ -1,82 +1,82 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch -import torch.nn as nn - - -def weights_init_normal(m): - class_name = m.__class__.__name__ - if class_name.find("Conv") != -1: - torch.nn.init.normal_(m.weight.data, 0.0, 0.02) - elif class_name.find("BatchNorm2d") != -1: - torch.nn.init.normal_(m.weight.data, 1.0, 0.02) - torch.nn.init.constant_(m.bias.data, 0.0) - - -class Generator(nn.Module): - def __init__(self, img_size, latent_dim, channels): - super(Generator, self).__init__() - - self.init_size = img_size // 4 - self.l1 = nn.Sequential(nn.Linear(latent_dim, 128 * self.init_size ** 2)) - - self.conv_blocks = nn.Sequential( - nn.BatchNorm2d(128), - nn.Upsample(scale_factor=2), - nn.Conv2d(128, 128, 3, stride=1, padding=1), - nn.BatchNorm2d(128, 0.8), - nn.LeakyReLU(0.2, inplace=True), - nn.Upsample(scale_factor=2), - nn.Conv2d(128, 32, 3, stride=1, padding=1), - nn.BatchNorm2d(32, 0.8), - nn.LeakyReLU(0.2, inplace=True), - nn.Conv2d(32, channels, 3, stride=1, padding=1), - nn.Tanh() - ) - - def forward(self, z): - out = self.l1(z) - out = out.view(out.shape[0], 128, self.init_size, self.init_size) - img = self.conv_blocks(out) - return img - - -class Discriminator(nn.Module): - def __init__(self, img_size, channels): - super(Discriminator, self).__init__() - - def discriminator_block(in_filters, out_filters, bn=True): - block = [nn.Conv2d(in_filters, out_filters, 3, 2, 1), nn.LeakyReLU(0.2, inplace=True), nn.Dropout2d(0.25)] - if bn: - block.append(nn.BatchNorm2d(out_filters, 0.8)) - return block - - self.model = nn.Sequential( - *discriminator_block(channels, 16, bn=False), - *discriminator_block(16, 32), - *discriminator_block(32, 64), - *discriminator_block(64, 128) - ) - - # The height and width of down_sampled image - ds_size = img_size // 2 ** 4 - self.adv_layer = nn.Sequential(nn.Linear(128 * ds_size ** 2, 1)) - - def forward(self, img): - out = self.model(img) - out = out.view(out.shape[0], -1) - validity = self.adv_layer(out) - - return validity +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch +import torch.nn as nn + + +def weights_init_normal(m): + class_name = m.__class__.__name__ + if class_name.find("Conv") != -1: + torch.nn.init.normal_(m.weight.data, 0.0, 0.02) + elif class_name.find("BatchNorm2d") != -1: + torch.nn.init.normal_(m.weight.data, 1.0, 0.02) + torch.nn.init.constant_(m.bias.data, 0.0) + + +class Generator(nn.Module): + def __init__(self, img_size, latent_dim, channels): + super(Generator, self).__init__() + + self.init_size = img_size // 4 + self.l1 = nn.Sequential(nn.Linear(latent_dim, 128 * self.init_size ** 2)) + + self.conv_blocks = nn.Sequential( + nn.BatchNorm2d(128), + nn.Upsample(scale_factor=2), + nn.Conv2d(128, 128, 3, stride=1, padding=1), + nn.BatchNorm2d(128, 0.8), + nn.LeakyReLU(0.2, inplace=True), + nn.Upsample(scale_factor=2), + nn.Conv2d(128, 32, 3, stride=1, padding=1), + nn.BatchNorm2d(32, 0.8), + nn.LeakyReLU(0.2, inplace=True), + nn.Conv2d(32, channels, 3, stride=1, padding=1), + nn.Tanh() + ) + + def forward(self, z): + out = self.l1(z) + out = out.view(out.shape[0], 128, self.init_size, self.init_size) + img = self.conv_blocks(out) + return img + + +class Discriminator(nn.Module): + def __init__(self, img_size, channels): + super(Discriminator, self).__init__() + + def discriminator_block(in_filters, out_filters, bn=True): + block = [nn.Conv2d(in_filters, out_filters, 3, 2, 1), nn.LeakyReLU(0.2, inplace=True), nn.Dropout2d(0.25)] + if bn: + block.append(nn.BatchNorm2d(out_filters, 0.8)) + return block + + self.model = nn.Sequential( + *discriminator_block(channels, 16, bn=False), + *discriminator_block(16, 32), + *discriminator_block(32, 64), + *discriminator_block(64, 128) + ) + + # The height and width of down_sampled image + ds_size = img_size // 2 ** 4 + self.adv_layer = nn.Sequential(nn.Linear(128 * ds_size ** 2, 1)) + + def forward(self, img): + out = self.model(img) + out = out.view(out.shape[0], -1) + validity = self.adv_layer(out) + + return validity diff --git a/PyTorch/contrib/cv/others/DCGAN/get_mnist.py b/PyTorch/contrib/cv/others/DCGAN/get_mnist.py index 443b0bd63b..6e3a45b7ac 100644 --- a/PyTorch/contrib/cv/others/DCGAN/get_mnist.py +++ b/PyTorch/contrib/cv/others/DCGAN/get_mnist.py @@ -1,30 +1,30 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torchvision.datasets as datasets -import argparse - -parser = argparse.ArgumentParser(description="MNIST dataset") -parser.add_argument('--data_path', metavar='DIR', type=str, default="./data", - help='path to dataset') - -if __name__ == "__main__": - args = parser.parse_args() - print("MNIST target folder : ", args.data_path) - print("start download...") - train_dataset = datasets.MNIST( - args.data_path, - train=True, - download=True) - print("download done...") +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torchvision.datasets as datasets +import argparse + +parser = argparse.ArgumentParser(description="MNIST dataset") +parser.add_argument('--data_path', metavar='DIR', type=str, default="./data", + help='path to dataset') + +if __name__ == "__main__": + args = parser.parse_args() + print("MNIST target folder : ", args.data_path) + print("start download...") + train_dataset = datasets.MNIST( + args.data_path, + train=True, + download=True) + print("download done...") diff --git a/PyTorch/contrib/cv/others/DCGAN/main.py b/PyTorch/contrib/cv/others/DCGAN/main.py index 0abc7517f0..a1c157ca33 100644 --- a/PyTorch/contrib/cv/others/DCGAN/main.py +++ b/PyTorch/contrib/cv/others/DCGAN/main.py @@ -1,510 +1,510 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import os -import time -import apex -from apex import amp -import torch -import torch.nn as nn -import torch.nn.parallel -import torch.backends.cudnn as cudnn -import torch.distributed as dist -import torch.optim -import torch.utils.data -import torch.utils.data.distributed -import torchvision.transforms as transforms -import torchvision.datasets as datasets -from torchvision.utils import save_image - -from dcgan import Generator, Discriminator, weights_init_normal - -parser = argparse.ArgumentParser(description="pytorch DCGAN implementation") -## dcgan parameters -parser.add_argument('--data', metavar='DIR', type=str, default="./data", - help='path to dataset') -parser.add_argument("--n-epochs", type=int, default=200, - help="number of epochs of training") -parser.add_argument("--batch-size", type=int, default=64, - help="size of the batches") -parser.add_argument("--lr", type=float, default=0.0002, - help="adam: learning rate") -parser.add_argument("--b1", type=float, default=0.5, - help="adam: decay of first order momentum of gradient") -parser.add_argument("--b2", type=float, default=0.999, - help="adam: decay of first order momentum of gradient") -parser.add_argument("--n-cpu", type=int, default=8, - help="number of cpu threads to use during batch generation") -parser.add_argument("--latent_dim", type=int, default=100, - help="dimensionality of the latent space") -parser.add_argument("--img_size", type=int, default=32, - help="size of each image dimension") -parser.add_argument("--channels", type=int, default=1, - help="number of image channels") -parser.add_argument("--sample_interval", type=int, default=400, - help="interval between image sampling") -## add useful parameters : such as resume,evaluate -parser.add_argument('--checkpoint-path', default=None, type=str, metavar='PATH', - help='path to latest checkpoint (default: none)') -parser.add_argument('-e', '--evaluate', dest='evaluate', action='store_true', default=False, - help='evaluate model : generate (n_samples) samples,saved in dir(validate)') -parser.add_argument('--n-samples', type=int, default=10, - help="amount of samples in function(validate)") -parser.add_argument('-p', '--print-freq', default=10, type=int, metavar='N', - help='print frequency (default 10)') -## parameters for distribute training -parser.add_argument('--world-size', default=-1, type=int, - help='number of nodes for distributed training') -parser.add_argument('--rank', default=-1, type=int, - help='node rank for distributed training') -parser.add_argument('--dist-url', default='tcp://224.66.41.62:23456', type=str, - help='url used to set up distributed training') -parser.add_argument('--dist-backend', default='nccl', type=str, - help='distributed backend') -parser.add_argument('--gpu', default=None, type=int, - help='GPU id to use.') -## for ascend 910 -parser.add_argument('--device', default='npu', type=str, help='npu or gpu') -parser.add_argument('--addr', default='10.136.181.115', - type=str, help='master addr') -parser.add_argument('--device-list', default='0,1,2,3,4,5,6,7', - type=str, help='device id list') -parser.add_argument('--amp', default=False, action='store_true', - help='use amp to train the model') -parser.add_argument('--loss-scale', default=None, type=float, - help='loss scale using in amp, default None means dynamic') -parser.add_argument('--opt-level', default='O2', type=str, - help='loss scale using in amp, default -1 means dynamic') -parser.add_argument('--prof', default=False, action='store_true', - help='use profiling to evaluate the performance of model') - - -def device_id_to_process_device_map(device_list): - devices = device_list.split(",") - devices = [int(x) for x in devices] - devices.sort() - - process_device_map = dict() - for process_id, device_id in enumerate(devices): - process_device_map[process_id] = device_id - - return process_device_map - - -def get_device_name(device_type, device_order): - if device_type == 'npu': - device_name = 'npu:{}'.format(device_order) - else: - device_name = 'cuda:{}'.format(device_order) - - return device_name - - -def main(): - args = parser.parse_args() - print(args.device_list) - args.process_device_map = device_id_to_process_device_map(args.device_list) - - # add start_epoch - args.start_epoch = 0 - - os.environ['MASTER_ADDR'] = args.addr - os.environ['MASTER_PORT'] = '29688' - - if args.device == 'npu': - ngpus_per_node = len(args.process_device_map) - else: - if args.gpu is None: - ngpus_per_node = len(args.process_device_map) - else: - ngpus_per_node = 1 - print('ngpus_per_node:', ngpus_per_node) - - args.world_size = ngpus_per_node * args.world_size - args.distributed = args.world_size > 1 - - # create folders - if not args.distributed or (args.distributed and args.rank == args.process_device_map[0]): - if not os.path.exists("./images/"): - os.makedirs("./images/") - if not os.path.exists("./samples/"): - os.makedirs("./samples/") - - main_worker(args.rank, ngpus_per_node, args) - - -def main_worker(gpu, ngpus_per_node, args): - args.gpu = args.process_device_map[gpu] - if args.distributed: - if args.device == 'npu': - dist.init_process_group(backend=args.dist_backend, - # init_method=args.dist_url, - world_size=args.world_size, - rank=args.rank) - else: - dist.init_process_group(backend=args.dist_backend, - init_method=args.dist_url, - world_size=args.world_size, - rank=args.rank) - - print('rank: {} / {}'.format(args.rank, args.world_size)) - - # init device - device_loc = get_device_name(args.device, args.gpu) - args.loc = device_loc - - # set device - print('set_device ', device_loc) - if args.device == 'npu': - torch.npu.set_device(device_loc) - else: - torch.cuda.set_device(args.gpu) - - # create model - G = Generator(args.img_size, args.latent_dim, args.channels) - D = Discriminator(args.img_size, args.channels) - # initialize weights - G.apply(weights_init_normal) - D.apply(weights_init_normal) - if args.checkpoint_path: - print("=> using pre-trained model dcgan,device(%d)" % args.gpu) - print("loading model of yours...,device(%d)" % args.gpu) - checkpoint = torch.load(args.checkpoint_path, map_location="cpu") - G.load_state_dict({k.replace('module.', ''): v for k, v in checkpoint["G"].items()}) - D.load_state_dict({k.replace('module.', ''): v for k, v in checkpoint["D"].items()}) - else: - print("=> creating model dcgan,device(%d)" % args.gpu) - - print('model to device_loc(%s)...' % device_loc) - G = G.to(device_loc) - D = D.to(device_loc) - - if args.distributed: - args.batch_size = int(args.batch_size / args.world_size) - args.n_cpu = int((args.n_cpu + ngpus_per_node - 1) / ngpus_per_node) - args.sample_interval = int(args.sample_interval / ngpus_per_node) - - # define optimizer, apply apex - optimizer_G = apex.optimizers.NpuFusedAdam(G.parameters(), lr=args.lr, betas=(args.b1, args.b2)) - optimizer_D = apex.optimizers.NpuFusedAdam(D.parameters(), lr=args.lr, betas=(args.b1, args.b2)) - - if args.amp: - [D, G], [optimizer_D, optimizer_G] = amp.initialize( - [D, G], [optimizer_D, optimizer_G], opt_level=args.opt_level, loss_scale=args.loss_scale, num_losses=3, - combine_grad=True) - - if args.evaluate: - print("evaluate mode...", " device(%d)," % args.gpu) - validate(G, args) - return - - if args.checkpoint_path: - args.start_epoch = checkpoint['epoch'] - optimizer_G.load_state_dict(checkpoint['optimizer_G']) - optimizer_D.load_state_dict(checkpoint['optimizer_D']) - if args.amp: - amp.load_state_dict(checkpoint['amp']) - print("=> loaded checkpoint '{}' (epoch {})".format(args.resume, checkpoint['epoch'])) - - if args.distributed: - G = torch.nn.parallel.DistributedDataParallel(G, device_ids=[args.gpu], broadcast_buffers=False) - D = torch.nn.parallel.DistributedDataParallel(D, device_ids=[args.gpu], broadcast_buffers=False) - - # Loss function - adversarial_loss = nn.BCEWithLogitsLoss().to(device_loc) - - cudnn.benchmark = True - - # Data loading code - data_path = args.data - print("dataset path : %s" % data_path) - train_dataset = datasets.MNIST( - data_path, - train=True, - download=False, - transform=transforms.Compose( - [transforms.Resize(args.img_size), transforms.ToTensor(), transforms.Normalize([0.5], [0.5])] - )) - - if args.distributed: - train_sampler = torch.utils.data.distributed.DistributedSampler( - train_dataset) - else: - train_sampler = None - - train_loader = torch.utils.data.DataLoader( - train_dataset, batch_size=args.batch_size, shuffle=(train_sampler is None), - num_workers=args.n_cpu, pin_memory=False, sampler=train_sampler, drop_last=True) - - if args.prof: - print("profiling mode...", " device(%d)," % args.gpu) - profiling(train_loader, G, D, optimizer_G, optimizer_D, adversarial_loss, args) - return - - # start training - print("train mode...", " device(%d)," % args.gpu) - fixed_z = torch.randn((5, args.latent_dim), dtype=torch.float32) - # Configure input - fixed_z = fixed_z.to(device_loc, non_blocking=True).to(torch.float) - for epoch in range(args.start_epoch, args.n_epochs): - if args.distributed: - train_sampler.set_epoch(epoch) - # train for one epoch - train(train_loader, - G, D, - optimizer_G, optimizer_D, - adversarial_loss, - epoch, args, - ngpus_per_node) - - if not args.distributed or (args.distributed and args.gpu == args.process_device_map[0]): - # save fixed imgs - G.eval() - fixed_imgs = G(fixed_z) - save_image(fixed_imgs[:5], "samples/fixed_images-epoch_%03d.png" % epoch, nrow=5, normalize=True) - ############## npu modify begin ############# - if args.amp: - torch.save({ - 'epoch': epoch + 1, - 'arch': 'dcgan', - 'G': G.state_dict(), - 'D': D.state_dict(), - 'optimizer_G': optimizer_G.state_dict(), - 'optimizer_D': optimizer_D.state_dict(), - 'amp': amp.state_dict(), - }, "checkpoint-amp-epoch_%d.pth" % (epoch + 1)) - - if os.path.exists("checkpoint-amp-epoch_%d.pth" % epoch): - os.remove("checkpoint-amp-epoch_%d.pth" % epoch) - else: - torch.save({ - 'epoch': epoch + 1, - 'arch': 'dcgan', - 'G': G.state_dict(), - 'D': D.state_dict(), - 'optimizer_G': optimizer_G.state_dict(), - 'optimizer_D': optimizer_D.state_dict(), - }, "checkpoint-epoch_%d.pth" % (epoch + 1)) - if os.path.exists("checkpoint-epoch_%d.pth" % epoch): - os.remove("checkpoint-epoch_%d.pth" % epoch) - ############## npu modify end ############# - # train loop done - - -def profiling(train_loader, generator, discriminator, optimizer_G, optimizer_D, loss, args): - generator.train() - discriminator.train() - - def update(step=None): - start_time = time.time() - valid = torch.ones(imgs.size(0), 1, requires_grad=False) - fake = torch.zeros(imgs.size(0), 1, requires_grad=False) - # Sample noise as generator input - z = torch.randn((imgs.size(0), args.latent_dim), dtype=torch.float32) - # Configure input - real_imgs = imgs.to(args.loc, non_blocking=True).to(torch.float) - valid = valid.to(args.loc, non_blocking=True).to(torch.float) - fake = fake.to(args.loc, non_blocking=True).to(torch.float) - z = z.to(args.loc, non_blocking=True).to(torch.float) - # update D - discriminator.zero_grad() - output = discriminator(real_imgs) - errD_real = loss(output, valid) - with amp.scale_loss(errD_real, optimizer_D, loss_id=0) as errD_real_scaled: - errD_real_scaled.backward() - gen_imgs = generator(z) - output = discriminator(gen_imgs.detach()) - errD_fake = loss(output, fake) - with amp.scale_loss(errD_fake, optimizer_D, loss_id=1) as errD_fake_scaled: - errD_fake_scaled.backward() - errD = errD_real + errD_fake - optimizer_D.step() - # update G - generator.zero_grad() - output = discriminator(gen_imgs) - errG = loss(output, valid) - with amp.scale_loss(errG, optimizer_G, loss_id=2) as errG_scaled: - errG_scaled.backward() - optimizer_G.step() - if step is not None: - print('iter: %d, loss: %.2f, time: %.2f' % (step, errG.item(), (time.time() - start_time))) - - for i, (imgs, _) in enumerate(train_loader): - if i < 20: - update(step=i) - else: - if args.device == 'npu': - with torch.autograd.profiler.profile(use_npu=True) as prof: - update() - else: - with torch.autograd.profiler.profile(use_cuda=True) as prof: - update() - break - prof.export_chrome_trace("dcgan.prof") - - -def train(train_loader, generator, discriminator, optimizer_G, optimizer_D, loss, epoch, args, ngpus_per_node): - batch_time = AverageMeter('Time', ':6.3f') - data_time = AverageMeter('Data', ':6.3f') - G_loss = AverageMeter('G_Loss', ':.4e') - D_loss = AverageMeter('D_Loss', ':.4e') - D_real = AverageMeter('D_real', ':.4e') - D_fake = AverageMeter('D_fake', ':.4e') - progress = ProgressMeter( - len(train_loader), - [batch_time, data_time, G_loss, D_loss, D_real, D_fake], - prefix="Epoch: [{}]".format(epoch)) - - # switch to train mode - generator.train() - discriminator.train() - - end = time.time() - for i, (imgs, _) in enumerate(train_loader): - # measure data loading time - data_time.update(time.time() - end) - - valid = torch.ones(imgs.size(0), 1, requires_grad=False) - fake = torch.zeros(imgs.size(0), 1, requires_grad=False) - # Sample noise as generator input - z = torch.randn((imgs.size(0), args.latent_dim), dtype=torch.float32) - # Configure input - real_imgs = imgs.to(args.loc, non_blocking=True).to(torch.float) - valid = valid.to(args.loc, non_blocking=True).to(torch.float) - fake = fake.to(args.loc, non_blocking=True).to(torch.float) - z = z.to(args.loc, non_blocking=True).to(torch.float) - - # update D - discriminator.zero_grad() - output = discriminator(real_imgs) - errD_real = loss(output, valid) - with amp.scale_loss(errD_real, optimizer_D, loss_id=0) as errD_real_scaled: - errD_real_scaled.backward() - - gen_imgs = generator(z) - output = discriminator(gen_imgs.detach()) - errD_fake = loss(output, fake) - with amp.scale_loss(errD_fake, optimizer_D, loss_id=1) as errD_fake_scaled: - errD_fake_scaled.backward() - errD = errD_real + errD_fake - optimizer_D.step() - - # update G - generator.zero_grad() - output = discriminator(gen_imgs) - errG = loss(output, valid) - with amp.scale_loss(errG, optimizer_G, loss_id=2) as errG_scaled: - errG_scaled.backward() - optimizer_G.step() - - D_loss.update(errD.item(), real_imgs.size(0)) - D_fake.update(errD_fake.item(), real_imgs.size(0)) - D_real.update(errD_real.item(), real_imgs.size(0)) - G_loss.update(errG.item(), real_imgs.size(0)) - - # measure elapsed time - cost_time = time.time() - end - batch_time.update(cost_time) - end = time.time() - - if not args.distributed or (args.distributed and args.gpu == args.process_device_map[0]): - if i % args.print_freq == 0: - progress.display(i) - - batches_done = epoch * len(train_loader) + i - if batches_done % args.sample_interval == 0: - save_image(gen_imgs.data[:25], "images/%06d.png" % batches_done, nrow=5, normalize=True) - - if batch_time.avg: - print("[npu id:", args.gpu, "]", "batch_size:", args.world_size * args.batch_size, - 'Time: {:.3f}'.format(batch_time.avg), '* FPS@all {:.3f}'.format( - args.batch_size * args.world_size / batch_time.avg)) - # train loop done - - -def validate(generator, args): - batch_time = AverageMeter('Time', ':6.3f') - print("start generate random image...(validate mode)") - generator.eval() - - if not os.path.exists("./validate/"): - os.makedirs("validate") - end = time.time() - with torch.no_grad(): - for i in range(args.n_samples): - z = torch.randn((25, args.latent_dim), dtype=torch.float32) - z = z.to(args.loc, non_blocking=True) - # gen images - images = generator(z) - batch_time.update(time.time() - end) - end = time.time() - save_image(images.data[:25], "validate/%03d.jpg" % i, nrow=5, normalize=True) - if batch_time.avg: - print("[npu id:", args.gpu, "]", "batch_size:", 25, - 'Time: {:.3f}'.format(batch_time.avg), '* FPS@all {:.3f}'.format( - 25 / batch_time.avg)) - # train loop done - - -class AverageMeter(object): - """Computes and stores the average and current value""" - - def __init__(self, name, fmt=':f', start_count_index=2): - self.name = name - self.fmt = fmt - self.reset() - self.start_count_index = start_count_index - - def reset(self): - self.val = 0 - self.avg = 0 - self.sum = 0 - self.count = 0 - - def update(self, val, n=1): - if self.count == 0: - self.N = n - - self.val = val - self.count += n - if self.count > (self.start_count_index * self.N): - self.sum += val * n - self.avg = self.sum / (self.count - self.start_count_index * self.N) - - def __str__(self): - fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' - return fmtstr.format(**self.__dict__) - - -class ProgressMeter(object): - - def __init__(self, num_batches, meters, prefix=""): - self.batch_fmtstr = self._get_batch_fmtstr(num_batches) - self.meters = meters - self.prefix = prefix - - def display(self, batch): - entries = [self.prefix + self.batch_fmtstr.format(batch)] - entries += [str(meter) for meter in self.meters] - print('\t'.join(entries)) - - def _get_batch_fmtstr(self, num_batches): - num_digits = len(str(num_batches // 1)) - fmt = '{:' + str(num_digits) + 'd}' - return '[' + fmt + '/' + fmt.format(num_batches) + ']' - - -if __name__ == "__main__": - main() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import os +import time +import apex +from apex import amp +import torch +import torch.nn as nn +import torch.nn.parallel +import torch.backends.cudnn as cudnn +import torch.distributed as dist +import torch.optim +import torch.utils.data +import torch.utils.data.distributed +import torchvision.transforms as transforms +import torchvision.datasets as datasets +from torchvision.utils import save_image + +from dcgan import Generator, Discriminator, weights_init_normal + +parser = argparse.ArgumentParser(description="pytorch DCGAN implementation") +## dcgan parameters +parser.add_argument('--data', metavar='DIR', type=str, default="./data", + help='path to dataset') +parser.add_argument("--n-epochs", type=int, default=200, + help="number of epochs of training") +parser.add_argument("--batch-size", type=int, default=64, + help="size of the batches") +parser.add_argument("--lr", type=float, default=0.0002, + help="adam: learning rate") +parser.add_argument("--b1", type=float, default=0.5, + help="adam: decay of first order momentum of gradient") +parser.add_argument("--b2", type=float, default=0.999, + help="adam: decay of first order momentum of gradient") +parser.add_argument("--n-cpu", type=int, default=8, + help="number of cpu threads to use during batch generation") +parser.add_argument("--latent_dim", type=int, default=100, + help="dimensionality of the latent space") +parser.add_argument("--img_size", type=int, default=32, + help="size of each image dimension") +parser.add_argument("--channels", type=int, default=1, + help="number of image channels") +parser.add_argument("--sample_interval", type=int, default=400, + help="interval between image sampling") +## add useful parameters : such as resume,evaluate +parser.add_argument('--checkpoint-path', default=None, type=str, metavar='PATH', + help='path to latest checkpoint (default: none)') +parser.add_argument('-e', '--evaluate', dest='evaluate', action='store_true', default=False, + help='evaluate model : generate (n_samples) samples,saved in dir(validate)') +parser.add_argument('--n-samples', type=int, default=10, + help="amount of samples in function(validate)") +parser.add_argument('-p', '--print-freq', default=10, type=int, metavar='N', + help='print frequency (default 10)') +## parameters for distribute training +parser.add_argument('--world-size', default=-1, type=int, + help='number of nodes for distributed training') +parser.add_argument('--rank', default=-1, type=int, + help='node rank for distributed training') +parser.add_argument('--dist-url', default='tcp://224.66.41.62:23456', type=str, + help='url used to set up distributed training') +parser.add_argument('--dist-backend', default='nccl', type=str, + help='distributed backend') +parser.add_argument('--gpu', default=None, type=int, + help='GPU id to use.') +## for ascend 910 +parser.add_argument('--device', default='npu', type=str, help='npu or gpu') +parser.add_argument('--addr', default='10.136.181.115', + type=str, help='master addr') +parser.add_argument('--device-list', default='0,1,2,3,4,5,6,7', + type=str, help='device id list') +parser.add_argument('--amp', default=False, action='store_true', + help='use amp to train the model') +parser.add_argument('--loss-scale', default=None, type=float, + help='loss scale using in amp, default None means dynamic') +parser.add_argument('--opt-level', default='O2', type=str, + help='loss scale using in amp, default -1 means dynamic') +parser.add_argument('--prof', default=False, action='store_true', + help='use profiling to evaluate the performance of model') + + +def device_id_to_process_device_map(device_list): + devices = device_list.split(",") + devices = [int(x) for x in devices] + devices.sort() + + process_device_map = dict() + for process_id, device_id in enumerate(devices): + process_device_map[process_id] = device_id + + return process_device_map + + +def get_device_name(device_type, device_order): + if device_type == 'npu': + device_name = 'npu:{}'.format(device_order) + else: + device_name = 'cuda:{}'.format(device_order) + + return device_name + + +def main(): + args = parser.parse_args() + print(args.device_list) + args.process_device_map = device_id_to_process_device_map(args.device_list) + + # add start_epoch + args.start_epoch = 0 + + os.environ['MASTER_ADDR'] = args.addr + os.environ['MASTER_PORT'] = '29688' + + if args.device == 'npu': + ngpus_per_node = len(args.process_device_map) + else: + if args.gpu is None: + ngpus_per_node = len(args.process_device_map) + else: + ngpus_per_node = 1 + print('ngpus_per_node:', ngpus_per_node) + + args.world_size = ngpus_per_node * args.world_size + args.distributed = args.world_size > 1 + + # create folders + if not args.distributed or (args.distributed and args.rank == args.process_device_map[0]): + if not os.path.exists("./images/"): + os.makedirs("./images/") + if not os.path.exists("./samples/"): + os.makedirs("./samples/") + + main_worker(args.rank, ngpus_per_node, args) + + +def main_worker(gpu, ngpus_per_node, args): + args.gpu = args.process_device_map[gpu] + if args.distributed: + if args.device == 'npu': + dist.init_process_group(backend=args.dist_backend, + # init_method=args.dist_url, + world_size=args.world_size, + rank=args.rank) + else: + dist.init_process_group(backend=args.dist_backend, + init_method=args.dist_url, + world_size=args.world_size, + rank=args.rank) + + print('rank: {} / {}'.format(args.rank, args.world_size)) + + # init device + device_loc = get_device_name(args.device, args.gpu) + args.loc = device_loc + + # set device + print('set_device ', device_loc) + if args.device == 'npu': + torch.npu.set_device(device_loc) + else: + torch.cuda.set_device(args.gpu) + + # create model + G = Generator(args.img_size, args.latent_dim, args.channels) + D = Discriminator(args.img_size, args.channels) + # initialize weights + G.apply(weights_init_normal) + D.apply(weights_init_normal) + if args.checkpoint_path: + print("=> using pre-trained model dcgan,device(%d)" % args.gpu) + print("loading model of yours...,device(%d)" % args.gpu) + checkpoint = torch.load(args.checkpoint_path, map_location="cpu") + G.load_state_dict({k.replace('module.', ''): v for k, v in checkpoint["G"].items()}) + D.load_state_dict({k.replace('module.', ''): v for k, v in checkpoint["D"].items()}) + else: + print("=> creating model dcgan,device(%d)" % args.gpu) + + print('model to device_loc(%s)...' % device_loc) + G = G.to(device_loc) + D = D.to(device_loc) + + if args.distributed: + args.batch_size = int(args.batch_size / args.world_size) + args.n_cpu = int((args.n_cpu + ngpus_per_node - 1) / ngpus_per_node) + args.sample_interval = int(args.sample_interval / ngpus_per_node) + + # define optimizer, apply apex + optimizer_G = apex.optimizers.NpuFusedAdam(G.parameters(), lr=args.lr, betas=(args.b1, args.b2)) + optimizer_D = apex.optimizers.NpuFusedAdam(D.parameters(), lr=args.lr, betas=(args.b1, args.b2)) + + if args.amp: + [D, G], [optimizer_D, optimizer_G] = amp.initialize( + [D, G], [optimizer_D, optimizer_G], opt_level=args.opt_level, loss_scale=args.loss_scale, num_losses=3, + combine_grad=True) + + if args.evaluate: + print("evaluate mode...", " device(%d)," % args.gpu) + validate(G, args) + return + + if args.checkpoint_path: + args.start_epoch = checkpoint['epoch'] + optimizer_G.load_state_dict(checkpoint['optimizer_G']) + optimizer_D.load_state_dict(checkpoint['optimizer_D']) + if args.amp: + amp.load_state_dict(checkpoint['amp']) + print("=> loaded checkpoint '{}' (epoch {})".format(args.resume, checkpoint['epoch'])) + + if args.distributed: + G = torch.nn.parallel.DistributedDataParallel(G, device_ids=[args.gpu], broadcast_buffers=False) + D = torch.nn.parallel.DistributedDataParallel(D, device_ids=[args.gpu], broadcast_buffers=False) + + # Loss function + adversarial_loss = nn.BCEWithLogitsLoss().to(device_loc) + + cudnn.benchmark = True + + # Data loading code + data_path = args.data + print("dataset path : %s" % data_path) + train_dataset = datasets.MNIST( + data_path, + train=True, + download=False, + transform=transforms.Compose( + [transforms.Resize(args.img_size), transforms.ToTensor(), transforms.Normalize([0.5], [0.5])] + )) + + if args.distributed: + train_sampler = torch.utils.data.distributed.DistributedSampler( + train_dataset) + else: + train_sampler = None + + train_loader = torch.utils.data.DataLoader( + train_dataset, batch_size=args.batch_size, shuffle=(train_sampler is None), + num_workers=args.n_cpu, pin_memory=False, sampler=train_sampler, drop_last=True) + + if args.prof: + print("profiling mode...", " device(%d)," % args.gpu) + profiling(train_loader, G, D, optimizer_G, optimizer_D, adversarial_loss, args) + return + + # start training + print("train mode...", " device(%d)," % args.gpu) + fixed_z = torch.randn((5, args.latent_dim), dtype=torch.float32) + # Configure input + fixed_z = fixed_z.to(device_loc, non_blocking=True).to(torch.float) + for epoch in range(args.start_epoch, args.n_epochs): + if args.distributed: + train_sampler.set_epoch(epoch) + # train for one epoch + train(train_loader, + G, D, + optimizer_G, optimizer_D, + adversarial_loss, + epoch, args, + ngpus_per_node) + + if not args.distributed or (args.distributed and args.gpu == args.process_device_map[0]): + # save fixed imgs + G.eval() + fixed_imgs = G(fixed_z) + save_image(fixed_imgs[:5], "samples/fixed_images-epoch_%03d.png" % epoch, nrow=5, normalize=True) + ############## npu modify begin ############# + if args.amp: + torch.save({ + 'epoch': epoch + 1, + 'arch': 'dcgan', + 'G': G.state_dict(), + 'D': D.state_dict(), + 'optimizer_G': optimizer_G.state_dict(), + 'optimizer_D': optimizer_D.state_dict(), + 'amp': amp.state_dict(), + }, "checkpoint-amp-epoch_%d.pth" % (epoch + 1)) + + if os.path.exists("checkpoint-amp-epoch_%d.pth" % epoch): + os.remove("checkpoint-amp-epoch_%d.pth" % epoch) + else: + torch.save({ + 'epoch': epoch + 1, + 'arch': 'dcgan', + 'G': G.state_dict(), + 'D': D.state_dict(), + 'optimizer_G': optimizer_G.state_dict(), + 'optimizer_D': optimizer_D.state_dict(), + }, "checkpoint-epoch_%d.pth" % (epoch + 1)) + if os.path.exists("checkpoint-epoch_%d.pth" % epoch): + os.remove("checkpoint-epoch_%d.pth" % epoch) + ############## npu modify end ############# + # train loop done + + +def profiling(train_loader, generator, discriminator, optimizer_G, optimizer_D, loss, args): + generator.train() + discriminator.train() + + def update(step=None): + start_time = time.time() + valid = torch.ones(imgs.size(0), 1, requires_grad=False) + fake = torch.zeros(imgs.size(0), 1, requires_grad=False) + # Sample noise as generator input + z = torch.randn((imgs.size(0), args.latent_dim), dtype=torch.float32) + # Configure input + real_imgs = imgs.to(args.loc, non_blocking=True).to(torch.float) + valid = valid.to(args.loc, non_blocking=True).to(torch.float) + fake = fake.to(args.loc, non_blocking=True).to(torch.float) + z = z.to(args.loc, non_blocking=True).to(torch.float) + # update D + discriminator.zero_grad() + output = discriminator(real_imgs) + errD_real = loss(output, valid) + with amp.scale_loss(errD_real, optimizer_D, loss_id=0) as errD_real_scaled: + errD_real_scaled.backward() + gen_imgs = generator(z) + output = discriminator(gen_imgs.detach()) + errD_fake = loss(output, fake) + with amp.scale_loss(errD_fake, optimizer_D, loss_id=1) as errD_fake_scaled: + errD_fake_scaled.backward() + errD = errD_real + errD_fake + optimizer_D.step() + # update G + generator.zero_grad() + output = discriminator(gen_imgs) + errG = loss(output, valid) + with amp.scale_loss(errG, optimizer_G, loss_id=2) as errG_scaled: + errG_scaled.backward() + optimizer_G.step() + if step is not None: + print('iter: %d, loss: %.2f, time: %.2f' % (step, errG.item(), (time.time() - start_time))) + + for i, (imgs, _) in enumerate(train_loader): + if i < 20: + update(step=i) + else: + if args.device == 'npu': + with torch.autograd.profiler.profile(use_npu=True) as prof: + update() + else: + with torch.autograd.profiler.profile(use_cuda=True) as prof: + update() + break + prof.export_chrome_trace("dcgan.prof") + + +def train(train_loader, generator, discriminator, optimizer_G, optimizer_D, loss, epoch, args, ngpus_per_node): + batch_time = AverageMeter('Time', ':6.3f') + data_time = AverageMeter('Data', ':6.3f') + G_loss = AverageMeter('G_Loss', ':.4e') + D_loss = AverageMeter('D_Loss', ':.4e') + D_real = AverageMeter('D_real', ':.4e') + D_fake = AverageMeter('D_fake', ':.4e') + progress = ProgressMeter( + len(train_loader), + [batch_time, data_time, G_loss, D_loss, D_real, D_fake], + prefix="Epoch: [{}]".format(epoch)) + + # switch to train mode + generator.train() + discriminator.train() + + end = time.time() + for i, (imgs, _) in enumerate(train_loader): + # measure data loading time + data_time.update(time.time() - end) + + valid = torch.ones(imgs.size(0), 1, requires_grad=False) + fake = torch.zeros(imgs.size(0), 1, requires_grad=False) + # Sample noise as generator input + z = torch.randn((imgs.size(0), args.latent_dim), dtype=torch.float32) + # Configure input + real_imgs = imgs.to(args.loc, non_blocking=True).to(torch.float) + valid = valid.to(args.loc, non_blocking=True).to(torch.float) + fake = fake.to(args.loc, non_blocking=True).to(torch.float) + z = z.to(args.loc, non_blocking=True).to(torch.float) + + # update D + discriminator.zero_grad() + output = discriminator(real_imgs) + errD_real = loss(output, valid) + with amp.scale_loss(errD_real, optimizer_D, loss_id=0) as errD_real_scaled: + errD_real_scaled.backward() + + gen_imgs = generator(z) + output = discriminator(gen_imgs.detach()) + errD_fake = loss(output, fake) + with amp.scale_loss(errD_fake, optimizer_D, loss_id=1) as errD_fake_scaled: + errD_fake_scaled.backward() + errD = errD_real + errD_fake + optimizer_D.step() + + # update G + generator.zero_grad() + output = discriminator(gen_imgs) + errG = loss(output, valid) + with amp.scale_loss(errG, optimizer_G, loss_id=2) as errG_scaled: + errG_scaled.backward() + optimizer_G.step() + + D_loss.update(errD.item(), real_imgs.size(0)) + D_fake.update(errD_fake.item(), real_imgs.size(0)) + D_real.update(errD_real.item(), real_imgs.size(0)) + G_loss.update(errG.item(), real_imgs.size(0)) + + # measure elapsed time + cost_time = time.time() - end + batch_time.update(cost_time) + end = time.time() + + if not args.distributed or (args.distributed and args.gpu == args.process_device_map[0]): + if i % args.print_freq == 0: + progress.display(i) + + batches_done = epoch * len(train_loader) + i + if batches_done % args.sample_interval == 0: + save_image(gen_imgs.data[:25], "images/%06d.png" % batches_done, nrow=5, normalize=True) + + if batch_time.avg: + print("[npu id:", args.gpu, "]", "batch_size:", args.world_size * args.batch_size, + 'Time: {:.3f}'.format(batch_time.avg), '* FPS@all {:.3f}'.format( + args.batch_size * args.world_size / batch_time.avg)) + # train loop done + + +def validate(generator, args): + batch_time = AverageMeter('Time', ':6.3f') + print("start generate random image...(validate mode)") + generator.eval() + + if not os.path.exists("./validate/"): + os.makedirs("validate") + end = time.time() + with torch.no_grad(): + for i in range(args.n_samples): + z = torch.randn((25, args.latent_dim), dtype=torch.float32) + z = z.to(args.loc, non_blocking=True) + # gen images + images = generator(z) + batch_time.update(time.time() - end) + end = time.time() + save_image(images.data[:25], "validate/%03d.jpg" % i, nrow=5, normalize=True) + if batch_time.avg: + print("[npu id:", args.gpu, "]", "batch_size:", 25, + 'Time: {:.3f}'.format(batch_time.avg), '* FPS@all {:.3f}'.format( + 25 / batch_time.avg)) + # train loop done + + +class AverageMeter(object): + """Computes and stores the average and current value""" + + def __init__(self, name, fmt=':f', start_count_index=2): + self.name = name + self.fmt = fmt + self.reset() + self.start_count_index = start_count_index + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + + def update(self, val, n=1): + if self.count == 0: + self.N = n + + self.val = val + self.count += n + if self.count > (self.start_count_index * self.N): + self.sum += val * n + self.avg = self.sum / (self.count - self.start_count_index * self.N) + + def __str__(self): + fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' + return fmtstr.format(**self.__dict__) + + +class ProgressMeter(object): + + def __init__(self, num_batches, meters, prefix=""): + self.batch_fmtstr = self._get_batch_fmtstr(num_batches) + self.meters = meters + self.prefix = prefix + + def display(self, batch): + entries = [self.prefix + self.batch_fmtstr.format(batch)] + entries += [str(meter) for meter in self.meters] + print('\t'.join(entries)) + + def _get_batch_fmtstr(self, num_batches): + num_digits = len(str(num_batches // 1)) + fmt = '{:' + str(num_digits) + 'd}' + return '[' + fmt + '/' + fmt.format(num_batches) + ']' + + +if __name__ == "__main__": + main() diff --git a/PyTorch/contrib/cv/others/DCGAN/modelzoo_level.txt b/PyTorch/contrib/cv/others/DCGAN/modelzoo_level.txt index 405b26618a..c45626e398 100644 --- a/PyTorch/contrib/cv/others/DCGAN/modelzoo_level.txt +++ b/PyTorch/contrib/cv/others/DCGAN/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:POK +FuncStatus:OK +PerfStatus:POK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/DCGAN/requirements.txt b/PyTorch/contrib/cv/others/DCGAN/requirements.txt index dd1af6e127..ea5a8512c1 100644 --- a/PyTorch/contrib/cv/others/DCGAN/requirements.txt +++ b/PyTorch/contrib/cv/others/DCGAN/requirements.txt @@ -1,3 +1,3 @@ -torch -apex +torch +apex torchvision \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/GAN_Pytorch/Dockerfile b/PyTorch/contrib/cv/others/GAN_Pytorch/Dockerfile index 7e712fe1a1..30a31af558 100644 --- a/PyTorch/contrib/cv/others/GAN_Pytorch/Dockerfile +++ b/PyTorch/contrib/cv/others/GAN_Pytorch/Dockerfile @@ -1,5 +1,5 @@ -ARG FROM_IMAGE_NAME -FROM $FROM_IMAGE_NAME - -COPY requirements.txt . +ARG FROM_IMAGE_NAME +FROM $FROM_IMAGE_NAME + +COPY requirements.txt . RUN pip3.7 install -r requirements.txt \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/GAN_Pytorch/README.md b/PyTorch/contrib/cv/others/GAN_Pytorch/README.md index 96151c3e21..be1d95ec6e 100644 --- a/PyTorch/contrib/cv/others/GAN_Pytorch/README.md +++ b/PyTorch/contrib/cv/others/GAN_Pytorch/README.md @@ -1,46 +1,46 @@ -# GAN 训练 -This implements training of RDN on the DIV2K_x2 dataset. -- Reference implementation: -``` -url=https://github.com/eriklindernoren/PyTorch-GAN/blob/master/implementations/gan/gan.py -``` - - - -## Requirements # - -- Install PyTorch ([pytorch.org](http://pytorch.org)) -- `pip install -r requirements.txt` -- The MNIST Dataset can be downloaded from the links below.Move the datasets to directory ./data . - - Train Set : [Download Mnist](https://wwr.lanzoui.com/iSBOeu43dkf) - -## Training # -To train a model, change the working directory to `./test`,then run: - -```bash -# 1p train perf -bash train_performance_1p.sh - -# 8p train perf -bash train_performance_8p.sh - -# 8p train full -bash train_full_8p.sh - -# 8p eval -bash train_eval_8p.sh - -# finetuning -bash train_finetune_1p.sh -``` -After running,you can see the results in `./output` - -## GAN training result # - -| Acc@1 | FPS | Npu_nums | Epochs | AMP_Type | -| :------: | :------: | :------: | :------: | :------: | -| - | 997 | 1 | 200 | O1 | -| - | 11795 | 8 | 200 | O1 | - - - +# GAN 训练 +This implements training of RDN on the DIV2K_x2 dataset. +- Reference implementation: +``` +url=https://github.com/eriklindernoren/PyTorch-GAN/blob/master/implementations/gan/gan.py +``` + + + +## Requirements # + +- Install PyTorch ([pytorch.org](http://pytorch.org)) +- `pip install -r requirements.txt` +- The MNIST Dataset can be downloaded from the links below.Move the datasets to directory ./data . + - Train Set : [Download Mnist](https://wwr.lanzoui.com/iSBOeu43dkf) + +## Training # +To train a model, change the working directory to `./test`,then run: + +```bash +# 1p train perf +bash train_performance_1p.sh + +# 8p train perf +bash train_performance_8p.sh + +# 8p train full +bash train_full_8p.sh + +# 8p eval +bash train_eval_8p.sh + +# finetuning +bash train_finetune_1p.sh +``` +After running,you can see the results in `./output` + +## GAN training result # + +| Acc@1 | FPS | Npu_nums | Epochs | AMP_Type | +| :------: | :------: | :------: | :------: | :------: | +| - | 997 | 1 | 200 | O1 | +| - | 11795 | 8 | 200 | O1 | + + + diff --git a/PyTorch/contrib/cv/others/GAN_Pytorch/docker_start.sh b/PyTorch/contrib/cv/others/GAN_Pytorch/docker_start.sh index 46ce9a02ec..944bca3cda 100644 --- a/PyTorch/contrib/cv/others/GAN_Pytorch/docker_start.sh +++ b/PyTorch/contrib/cv/others/GAN_Pytorch/docker_start.sh @@ -1,25 +1,25 @@ -#!/bin/bash - -docker_image=$1 -data_dir=$2 -model_dir=$3 - -docker run -it --ipc=host \ - --device=/dev/davinci0 \ - --device=/dev/davinci1 \ - --device=/dev/davinci2 \ - --device=/dev/davinci3 \ - --device=/dev/davinci4 \ - --device=/dev/davinci5 \ - --device=/dev/davinci6 \ - --device=/dev/davinci7 \ - --device=/dev/davinci_manager \ - --device=/dev/devmm_svm --device=/dev/hisi_hdc \ - -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ - -v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \ - -v ${model_dir}:${model_dir} \ - -v ${data_dir}:${data_dir} \ - -v /var/log/npu/conf/slog/slog.conf:/var/log/npu/conf/slog/slog.conf \ - -v /var/log/npu/slog/:/var/log/npu/slog -v /var/log/npu/profiling/:/var/log/npu/profiling \ - -v /var/log/npu/dump/:/var/log/npu/dump -v /var/log/npu/:/usr/slog ${docker_image} \ +#!/bin/bash + +docker_image=$1 +data_dir=$2 +model_dir=$3 + +docker run -it --ipc=host \ + --device=/dev/davinci0 \ + --device=/dev/davinci1 \ + --device=/dev/davinci2 \ + --device=/dev/davinci3 \ + --device=/dev/davinci4 \ + --device=/dev/davinci5 \ + --device=/dev/davinci6 \ + --device=/dev/davinci7 \ + --device=/dev/davinci_manager \ + --device=/dev/devmm_svm --device=/dev/hisi_hdc \ + -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ + -v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \ + -v ${model_dir}:${model_dir} \ + -v ${data_dir}:${data_dir} \ + -v /var/log/npu/conf/slog/slog.conf:/var/log/npu/conf/slog/slog.conf \ + -v /var/log/npu/slog/:/var/log/npu/slog -v /var/log/npu/profiling/:/var/log/npu/profiling \ + -v /var/log/npu/dump/:/var/log/npu/dump -v /var/log/npu/:/usr/slog ${docker_image} \ /bin/bash \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/GAN_Pytorch/main.py b/PyTorch/contrib/cv/others/GAN_Pytorch/main.py index 87b96cdccb..892cbad981 100644 --- a/PyTorch/contrib/cv/others/GAN_Pytorch/main.py +++ b/PyTorch/contrib/cv/others/GAN_Pytorch/main.py @@ -1,387 +1,387 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 argparse -import os -import sys -import numpy as np -import time -import matplotlib.pyplot as plt -import datetime - -import torchvision.transforms as transforms -from torchvision.utils import save_image -from torchvision import datasets - -import torch -from torch.autograd import Variable -import torch.nn as nn -import torch.multiprocessing as mp -from torch.nn.parallel import DistributedDataParallel as DDP -from torch.utils.data import DataLoader - -from models import Generator, Discriminator - -try: - import apex - from apex import amp -except ImportError: - amp = None - -def flush_print(func): - def new_print(*args, **kwargs): - func(*args, **kwargs) - sys.stdout.flush() - return new_print - -print = flush_print(print) - - -def train_one_epoch(generator, discriminator, optimizer_G, optimizer_D, adversarial_loss, - epoch, args, dataloader, Tensor,LOSS_G,LOSS_D,device): - batch_time = AverageMeter('Time', ':6.3f', start_count_index=5) - G_loss = AverageMeter('g_loss', ':6.3f', start_count_index=0) - D_loss = AverageMeter('d_loss', ':6. 3f', start_count_index=0) - - for i, (imgs,_) in enumerate(dataloader): - - start_time = time.time() - valid = Variable(Tensor(imgs.size(0), 1).fill_(1.0), requires_grad=False) - fake = Variable(Tensor(imgs.size(0), 1).fill_(0.0), requires_grad=False) - - # Configure input - real_imgs = Variable(imgs.type(Tensor)).to(device) - - # ----------------- - # Train Generator - # ----------------- - - optimizer_G.zero_grad() - - # Sample noise as generator input - z = Variable(Tensor(np.random.normal(0, 1, (imgs.shape[0], args.latent_dim)))).to(device) - - # Generate a batch of images - gen_imgs = generator(z) - - # Loss measures generator's ability to fool the discriminator - g_loss = adversarial_loss(discriminator(gen_imgs), valid) - - G_loss.update(g_loss.item(), len(gen_imgs)) - if args.apex: - with amp.scale_loss(g_loss, optimizer_G) as scaled_loss: - scaled_loss.backward() - else: - G_loss.backward() - optimizer_G.step() - - # --------------------- - # Train Discriminator - # --------------------- - - optimizer_D.zero_grad() - - # Measure discriminator's ability to classify real from generated samples - real_loss = adversarial_loss(discriminator(real_imgs), valid) - fake_loss = adversarial_loss(discriminator(gen_imgs.detach()), fake) - d_loss = (real_loss + fake_loss) / 2 - - D_loss.update(d_loss.item(), len(real_imgs)) - if args.apex: - with amp.scale_loss(d_loss, optimizer_D) as scaled_loss: - scaled_loss.backward() - else: - d_loss.backward() - optimizer_D.step() - batch_time.update(time.time() - start_time) - if args.n_epochs == 1: - print( - "[Epoch %d] [step %d] [D loss: %f] [G loss: %f]" - % (epoch, i, D_loss.avg, G_loss.avg) - ) - batches_done = epoch * len(dataloader)+ i - if batches_done % args.sample_interval == 0 and args.is_master_node and args.n_epochs != 1: - save_image(gen_imgs.data[:25], "training_images/%d.png" % batches_done, nrow=5, normalize=True) - if args.is_master_node: - print( - "[Epoch %d] [D loss: %f] [G loss: %f] FPS:%.3f" - % (epoch, D_loss.avg,G_loss.avg,args.batch_size*args.gpus/batch_time.avg) - ) - LOSS_G.append(G_loss.avg) - LOSS_D.append(D_loss.avg) - - - -def main(args): - - os.environ['MASTER_ADDR'] = args.addr - os.environ['MASTER_PORT'] = '29688' - - if args.apex: - if sys.version_info < (3, 0): - raise RuntimeError("Apex currently only supports Python 3. Aborting.") - if amp is None: - raise RuntimeError("Failed to import apex. Please install apex from https://www.github.com/nvidia/apex " - "to enable mixed-precision training.") - # if args.output_dir: - # os.mkdir(args.output_dir) - - if args.distributed: - - mp.spawn(main_worker, nprocs=args.gpus, - args=(args,)) - else: - main_worker(args.gpus, args) - -def main_worker(nprocs, args): - local_rank = 0 - if args.distributed: - torch.distributed.init_process_group(backend="hccl", - init_method='env://', - world_size=args.nodes * args.gpus, - rank=nprocs) - local_rank = torch.distributed.get_rank() - args.is_master_node = not args.distributed or local_rank == 0 - if args.is_master_node: - print(args) - args.device_id = args.device_id + local_rank - print('device_id=', args.device_id) - device = torch.device(f'npu:{args.device_id}') # npu - torch.npu.set_device(device) # for npu - print("Downloading dataset...") - # Configure data loader - os.makedirs("../data/mnist", exist_ok=True) - train_dataset = datasets.MNIST( - "../../data/mnist", - train=True, - download=True, - transform=transforms.Compose( - [transforms.Resize(args.img_size), transforms.ToTensor(), transforms.Normalize([0.5], [0.5])] - )) - - print("Creating dataloader") - - if args.distributed: - train_sampler = torch.utils.data.distributed.DistributedSampler( - train_dataset) - else: - train_sampler = None - dataloader = torch.utils.data.DataLoader( - train_dataset, batch_size=args.batch_size, shuffle=( - train_sampler is None), - num_workers=args.workers, pin_memory=True, sampler=train_sampler) - - if args.is_master_node: - print("Creating model") - # create model - Tensor = torch.npu.FloatTensor - LOSS_G=[] - LOSS_D=[] - os.makedirs("../output", exist_ok=True) - os.chdir("../output") - generator = Generator() - discriminator = Discriminator() - if args.pretrained: - print("=> using pre-trained model GAN") - generator = Generator() - discriminator = Discriminator() - print("loading model of yours...") - checkpoint = torch.load(r'./checkpoint.pth.tar',map_location='cpu') - from collections import OrderedDict - new_state_dict_g = OrderedDict() - new_state_dict_d = OrderedDict() - for k, v in checkpoint['state_dict_G'].items(): - name = k.replace("module.", "") # remove `module.` - new_state_dict_g[name] = v - for k, v in checkpoint['state_dict_D'].items(): - name = k.replace("module.", "") # remove `module.` - new_state_dict_d[name] = v - # load params - generator.load_state_dict(new_state_dict_g) - discriminator.load_state_dict(new_state_dict_d) - LOSS_D = checkpoint['loss_d'] - LOSS_G = checkpoint['loss_g'] - args.start_epoch = checkpoint['epoch'] - - generator = generator.to(device) - discriminator = discriminator.to(device) - - adversarial_loss = nn.BCELoss().to(device) - - optimizer_G = apex.optimizers.NpuFusedAdam(generator.parameters(), lr=args.lr, betas=(args.b1, args.b2)) - optimizer_D = apex.optimizers.NpuFusedAdam(discriminator.parameters(), lr=args.lr, betas=(args.b1, args.b2)) - - if args.apex: - amp.register_float_function(torch, 'sigmoid') - amp.register_half_function(torch, 'addmm') - generator, optimizer_G = amp.initialize(generator, optimizer_G, - opt_level='O1', loss_scale=128,combine_grad=True) - - discriminator, optimizer_D = amp.initialize(discriminator, optimizer_D, - opt_level='O1', loss_scale=128,combine_grad=True) - - if args.distributed: - generator = DDP(generator, device_ids=[local_rank], broadcast_buffers=False) - discriminator = DDP(discriminator, device_ids=[local_rank], broadcast_buffers=False) - - if args.test_only : - Tensor = torch.npu.FloatTensor - generator = Generator().npu() - checkpoint = torch.load(r'./checkpoint.pth.tar', map_location='cpu') - - loss_d = checkpoint['loss_d'] - loss_g = checkpoint['loss_g'] - x = range(len(loss_d)) - plt.figure() - - plt.plot(x, loss_d, color='r', label="loss_d") - plt.plot(x, loss_g, color='g', label="loss_g") - plt.legend() - plt.xlabel('epoch') - plt.ylabel('value') - plt.savefig('LOSS_{}p_{}_{}.jpg'.format(args.gpus, args.lr, args.batch_size)) - - # create new OrderedDict that does not contain `module.` - from collections import OrderedDict - new_state_dict = OrderedDict() - for k, v in checkpoint['state_dict_G'].items(): - name = k.replace("module.", "") # remove `module.` - new_state_dict[name] = v - # load params - generator.load_state_dict(new_state_dict) - os.makedirs("image", exist_ok=True) - for i in range(200): - z = Variable(Tensor(np.random.normal(0, 1, (64, 100)))).npu() - - # Generate a batch of images - gen_imgs = generator(z) - - save_image(gen_imgs.data[:25], "image/%d.png" % i, nrow=5, normalize=True) - print("Generate done!") - return - - if args.is_master_node: - print("Start training") - start_time = time.time() - os.makedirs("training_images",exist_ok=True) - for epoch in range(args.start_epoch, args.n_epochs): - if args.distributed: - train_sampler.set_epoch(epoch) - - # train for one epoch - train_one_epoch(generator, discriminator, optimizer_G, optimizer_D, adversarial_loss, - epoch, args, dataloader,Tensor, LOSS_G,LOSS_D,device) - - if epoch == 50 or epoch == 199: - if args.apex and args.is_master_node: - save_checkpoint({ - 'epoch': epoch + 1, - 'arch': 'GAN', - 'state_dict_G': generator.state_dict(), - 'state_dict_D': discriminator.state_dict(), - 'optimizer_G': optimizer_G.state_dict(), - 'optimizer_D': optimizer_D.state_dict(), - 'loss_g': LOSS_G, - 'loss_d': LOSS_D, - 'apex': amp.state_dict() - }) - elif args.is_master_node: - save_checkpoint({ - 'epoch': epoch + 1, - 'arch': 'GAN', - 'state_dict_G': generator.state_dict(), - 'state_dict_D': discriminator.state_dict(), - 'optimizer_G': optimizer_G.state_dict(), - 'optimizer_D': optimizer_D.state_dict(), - 'loss_g': LOSS_G, - 'loss_d': LOSS_D - }) - total_time = time.time() - start_time - total_time_str = str(datetime.timedelta(seconds=int(total_time))) - if args.is_master_node: - print('Training time {}'.format(total_time_str)) - -def save_checkpoint(state, filename='./checkpoint.pth.tar'): - torch.save(state, filename) - - -class AverageMeter(object): - """Computes and stores the average and current value""" - - def __init__(self, name, fmt=':f', start_count_index=10): - self.name = name - self.fmt = fmt - self.reset() - self.start_count_index = start_count_index - - def reset(self): - self.val = 0 - self.avg = 0 - self.sum = 0 - self.count = 0 - - def update(self, val, n=1): - if self.count == 0: - self.N = n - - self.val = val - self.count += n - if self.count > (self.start_count_index * self.N): - self.sum += val * n - self.avg = self.sum / (self.count - self.start_count_index * self.N) - - def __str__(self): - fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' - return fmtstr.format(**self.__dict__) - -def parse_args(): - parser = argparse.ArgumentParser(description='PyTorch GAN Training') - parser.add_argument("--n_epochs", type=int, default=200, help="number of epochs of training") - parser.add_argument("--batch_size", type=int, default=128, help="size of the batches") - parser.add_argument("--lr", type=float, default=0.0008, help="adam: learning rate") - parser.add_argument("--b1", type=float, default=0.5, help="adam: decay of first order momentum of gradient") - parser.add_argument("--b2", type=float, default=0.999, help="adam: decay of first order momentum of gradient") - parser.add_argument("--sample_interval", type=int, default=400, help="interval betwen image samples") - parser.add_argument("--latent_dim", type=int, default=100, help="dimensionality of the latent space") - parser.add_argument("--img_size", type=int, default=28, help="size of each image dimension") - parser.add_argument("--channels", type=int, default=1, help="number of image channels") - parser.add_argument("--gpus", type=int, default=8, help="num of gpus of per node") - parser.add_argument("--nodes", type=int, default=1) - parser.add_argument('--device_id', default=0, type=int, help='device id') - parser.add_argument("--test_only", type=int, default=None, help="only generate images") - parser.add_argument('--start_epoch', default=0, type=int, metavar='N', - help='manual epoch number (useful on restarts)') - parser.add_argument('--resume', default='', type=str, metavar='PATH', - help='path to latest checkpoint (default: none)') - parser.add_argument('--pretrained', dest='pretrained', action='store_true', - help='use pre-trained model') - - parser.add_argument('--distributed', action='store_true', - help='Use multi-processing distributed training to launch ' - 'N processes per node, which has N GPUs. This is the ' - 'fastest way to use PyTorch for either single node or ' - 'multi node data parallel training') - ## for ascend 910 - parser.add_argument('--addr', default='127.0.0.1', - type=str, help='master addr') - parser.add_argument('--workers', default=16, type=int, - help='numbers of worker') - parser.add_argument('--apex', default=False, action='store_true', - help='use apex to train the model') - args = parser.parse_args() - return args -if __name__ == '__main__': - args = parse_args() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 argparse +import os +import sys +import numpy as np +import time +import matplotlib.pyplot as plt +import datetime + +import torchvision.transforms as transforms +from torchvision.utils import save_image +from torchvision import datasets + +import torch +from torch.autograd import Variable +import torch.nn as nn +import torch.multiprocessing as mp +from torch.nn.parallel import DistributedDataParallel as DDP +from torch.utils.data import DataLoader + +from models import Generator, Discriminator + +try: + import apex + from apex import amp +except ImportError: + amp = None + +def flush_print(func): + def new_print(*args, **kwargs): + func(*args, **kwargs) + sys.stdout.flush() + return new_print + +print = flush_print(print) + + +def train_one_epoch(generator, discriminator, optimizer_G, optimizer_D, adversarial_loss, + epoch, args, dataloader, Tensor,LOSS_G,LOSS_D,device): + batch_time = AverageMeter('Time', ':6.3f', start_count_index=5) + G_loss = AverageMeter('g_loss', ':6.3f', start_count_index=0) + D_loss = AverageMeter('d_loss', ':6. 3f', start_count_index=0) + + for i, (imgs,_) in enumerate(dataloader): + + start_time = time.time() + valid = Variable(Tensor(imgs.size(0), 1).fill_(1.0), requires_grad=False) + fake = Variable(Tensor(imgs.size(0), 1).fill_(0.0), requires_grad=False) + + # Configure input + real_imgs = Variable(imgs.type(Tensor)).to(device) + + # ----------------- + # Train Generator + # ----------------- + + optimizer_G.zero_grad() + + # Sample noise as generator input + z = Variable(Tensor(np.random.normal(0, 1, (imgs.shape[0], args.latent_dim)))).to(device) + + # Generate a batch of images + gen_imgs = generator(z) + + # Loss measures generator's ability to fool the discriminator + g_loss = adversarial_loss(discriminator(gen_imgs), valid) + + G_loss.update(g_loss.item(), len(gen_imgs)) + if args.apex: + with amp.scale_loss(g_loss, optimizer_G) as scaled_loss: + scaled_loss.backward() + else: + G_loss.backward() + optimizer_G.step() + + # --------------------- + # Train Discriminator + # --------------------- + + optimizer_D.zero_grad() + + # Measure discriminator's ability to classify real from generated samples + real_loss = adversarial_loss(discriminator(real_imgs), valid) + fake_loss = adversarial_loss(discriminator(gen_imgs.detach()), fake) + d_loss = (real_loss + fake_loss) / 2 + + D_loss.update(d_loss.item(), len(real_imgs)) + if args.apex: + with amp.scale_loss(d_loss, optimizer_D) as scaled_loss: + scaled_loss.backward() + else: + d_loss.backward() + optimizer_D.step() + batch_time.update(time.time() - start_time) + if args.n_epochs == 1: + print( + "[Epoch %d] [step %d] [D loss: %f] [G loss: %f]" + % (epoch, i, D_loss.avg, G_loss.avg) + ) + batches_done = epoch * len(dataloader)+ i + if batches_done % args.sample_interval == 0 and args.is_master_node and args.n_epochs != 1: + save_image(gen_imgs.data[:25], "training_images/%d.png" % batches_done, nrow=5, normalize=True) + if args.is_master_node: + print( + "[Epoch %d] [D loss: %f] [G loss: %f] FPS:%.3f" + % (epoch, D_loss.avg,G_loss.avg,args.batch_size*args.gpus/batch_time.avg) + ) + LOSS_G.append(G_loss.avg) + LOSS_D.append(D_loss.avg) + + + +def main(args): + + os.environ['MASTER_ADDR'] = args.addr + os.environ['MASTER_PORT'] = '29688' + + if args.apex: + if sys.version_info < (3, 0): + raise RuntimeError("Apex currently only supports Python 3. Aborting.") + if amp is None: + raise RuntimeError("Failed to import apex. Please install apex from https://www.github.com/nvidia/apex " + "to enable mixed-precision training.") + # if args.output_dir: + # os.mkdir(args.output_dir) + + if args.distributed: + + mp.spawn(main_worker, nprocs=args.gpus, + args=(args,)) + else: + main_worker(args.gpus, args) + +def main_worker(nprocs, args): + local_rank = 0 + if args.distributed: + torch.distributed.init_process_group(backend="hccl", + init_method='env://', + world_size=args.nodes * args.gpus, + rank=nprocs) + local_rank = torch.distributed.get_rank() + args.is_master_node = not args.distributed or local_rank == 0 + if args.is_master_node: + print(args) + args.device_id = args.device_id + local_rank + print('device_id=', args.device_id) + device = torch.device(f'npu:{args.device_id}') # npu + torch.npu.set_device(device) # for npu + print("Downloading dataset...") + # Configure data loader + os.makedirs("../data/mnist", exist_ok=True) + train_dataset = datasets.MNIST( + "../../data/mnist", + train=True, + download=True, + transform=transforms.Compose( + [transforms.Resize(args.img_size), transforms.ToTensor(), transforms.Normalize([0.5], [0.5])] + )) + + print("Creating dataloader") + + if args.distributed: + train_sampler = torch.utils.data.distributed.DistributedSampler( + train_dataset) + else: + train_sampler = None + dataloader = torch.utils.data.DataLoader( + train_dataset, batch_size=args.batch_size, shuffle=( + train_sampler is None), + num_workers=args.workers, pin_memory=True, sampler=train_sampler) + + if args.is_master_node: + print("Creating model") + # create model + Tensor = torch.npu.FloatTensor + LOSS_G=[] + LOSS_D=[] + os.makedirs("../output", exist_ok=True) + os.chdir("../output") + generator = Generator() + discriminator = Discriminator() + if args.pretrained: + print("=> using pre-trained model GAN") + generator = Generator() + discriminator = Discriminator() + print("loading model of yours...") + checkpoint = torch.load(r'./checkpoint.pth.tar',map_location='cpu') + from collections import OrderedDict + new_state_dict_g = OrderedDict() + new_state_dict_d = OrderedDict() + for k, v in checkpoint['state_dict_G'].items(): + name = k.replace("module.", "") # remove `module.` + new_state_dict_g[name] = v + for k, v in checkpoint['state_dict_D'].items(): + name = k.replace("module.", "") # remove `module.` + new_state_dict_d[name] = v + # load params + generator.load_state_dict(new_state_dict_g) + discriminator.load_state_dict(new_state_dict_d) + LOSS_D = checkpoint['loss_d'] + LOSS_G = checkpoint['loss_g'] + args.start_epoch = checkpoint['epoch'] + + generator = generator.to(device) + discriminator = discriminator.to(device) + + adversarial_loss = nn.BCELoss().to(device) + + optimizer_G = apex.optimizers.NpuFusedAdam(generator.parameters(), lr=args.lr, betas=(args.b1, args.b2)) + optimizer_D = apex.optimizers.NpuFusedAdam(discriminator.parameters(), lr=args.lr, betas=(args.b1, args.b2)) + + if args.apex: + amp.register_float_function(torch, 'sigmoid') + amp.register_half_function(torch, 'addmm') + generator, optimizer_G = amp.initialize(generator, optimizer_G, + opt_level='O1', loss_scale=128,combine_grad=True) + + discriminator, optimizer_D = amp.initialize(discriminator, optimizer_D, + opt_level='O1', loss_scale=128,combine_grad=True) + + if args.distributed: + generator = DDP(generator, device_ids=[local_rank], broadcast_buffers=False) + discriminator = DDP(discriminator, device_ids=[local_rank], broadcast_buffers=False) + + if args.test_only : + Tensor = torch.npu.FloatTensor + generator = Generator().npu() + checkpoint = torch.load(r'./checkpoint.pth.tar', map_location='cpu') + + loss_d = checkpoint['loss_d'] + loss_g = checkpoint['loss_g'] + x = range(len(loss_d)) + plt.figure() + + plt.plot(x, loss_d, color='r', label="loss_d") + plt.plot(x, loss_g, color='g', label="loss_g") + plt.legend() + plt.xlabel('epoch') + plt.ylabel('value') + plt.savefig('LOSS_{}p_{}_{}.jpg'.format(args.gpus, args.lr, args.batch_size)) + + # create new OrderedDict that does not contain `module.` + from collections import OrderedDict + new_state_dict = OrderedDict() + for k, v in checkpoint['state_dict_G'].items(): + name = k.replace("module.", "") # remove `module.` + new_state_dict[name] = v + # load params + generator.load_state_dict(new_state_dict) + os.makedirs("image", exist_ok=True) + for i in range(200): + z = Variable(Tensor(np.random.normal(0, 1, (64, 100)))).npu() + + # Generate a batch of images + gen_imgs = generator(z) + + save_image(gen_imgs.data[:25], "image/%d.png" % i, nrow=5, normalize=True) + print("Generate done!") + return + + if args.is_master_node: + print("Start training") + start_time = time.time() + os.makedirs("training_images",exist_ok=True) + for epoch in range(args.start_epoch, args.n_epochs): + if args.distributed: + train_sampler.set_epoch(epoch) + + # train for one epoch + train_one_epoch(generator, discriminator, optimizer_G, optimizer_D, adversarial_loss, + epoch, args, dataloader,Tensor, LOSS_G,LOSS_D,device) + + if epoch == 50 or epoch == 199: + if args.apex and args.is_master_node: + save_checkpoint({ + 'epoch': epoch + 1, + 'arch': 'GAN', + 'state_dict_G': generator.state_dict(), + 'state_dict_D': discriminator.state_dict(), + 'optimizer_G': optimizer_G.state_dict(), + 'optimizer_D': optimizer_D.state_dict(), + 'loss_g': LOSS_G, + 'loss_d': LOSS_D, + 'apex': amp.state_dict() + }) + elif args.is_master_node: + save_checkpoint({ + 'epoch': epoch + 1, + 'arch': 'GAN', + 'state_dict_G': generator.state_dict(), + 'state_dict_D': discriminator.state_dict(), + 'optimizer_G': optimizer_G.state_dict(), + 'optimizer_D': optimizer_D.state_dict(), + 'loss_g': LOSS_G, + 'loss_d': LOSS_D + }) + total_time = time.time() - start_time + total_time_str = str(datetime.timedelta(seconds=int(total_time))) + if args.is_master_node: + print('Training time {}'.format(total_time_str)) + +def save_checkpoint(state, filename='./checkpoint.pth.tar'): + torch.save(state, filename) + + +class AverageMeter(object): + """Computes and stores the average and current value""" + + def __init__(self, name, fmt=':f', start_count_index=10): + self.name = name + self.fmt = fmt + self.reset() + self.start_count_index = start_count_index + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + + def update(self, val, n=1): + if self.count == 0: + self.N = n + + self.val = val + self.count += n + if self.count > (self.start_count_index * self.N): + self.sum += val * n + self.avg = self.sum / (self.count - self.start_count_index * self.N) + + def __str__(self): + fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' + return fmtstr.format(**self.__dict__) + +def parse_args(): + parser = argparse.ArgumentParser(description='PyTorch GAN Training') + parser.add_argument("--n_epochs", type=int, default=200, help="number of epochs of training") + parser.add_argument("--batch_size", type=int, default=128, help="size of the batches") + parser.add_argument("--lr", type=float, default=0.0008, help="adam: learning rate") + parser.add_argument("--b1", type=float, default=0.5, help="adam: decay of first order momentum of gradient") + parser.add_argument("--b2", type=float, default=0.999, help="adam: decay of first order momentum of gradient") + parser.add_argument("--sample_interval", type=int, default=400, help="interval betwen image samples") + parser.add_argument("--latent_dim", type=int, default=100, help="dimensionality of the latent space") + parser.add_argument("--img_size", type=int, default=28, help="size of each image dimension") + parser.add_argument("--channels", type=int, default=1, help="number of image channels") + parser.add_argument("--gpus", type=int, default=8, help="num of gpus of per node") + parser.add_argument("--nodes", type=int, default=1) + parser.add_argument('--device_id', default=0, type=int, help='device id') + parser.add_argument("--test_only", type=int, default=None, help="only generate images") + parser.add_argument('--start_epoch', default=0, type=int, metavar='N', + help='manual epoch number (useful on restarts)') + parser.add_argument('--resume', default='', type=str, metavar='PATH', + help='path to latest checkpoint (default: none)') + parser.add_argument('--pretrained', dest='pretrained', action='store_true', + help='use pre-trained model') + + parser.add_argument('--distributed', action='store_true', + help='Use multi-processing distributed training to launch ' + 'N processes per node, which has N GPUs. This is the ' + 'fastest way to use PyTorch for either single node or ' + 'multi node data parallel training') + ## for ascend 910 + parser.add_argument('--addr', default='127.0.0.1', + type=str, help='master addr') + parser.add_argument('--workers', default=16, type=int, + help='numbers of worker') + parser.add_argument('--apex', default=False, action='store_true', + help='use apex to train the model') + args = parser.parse_args() + return args +if __name__ == '__main__': + args = parse_args() main(args) \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/GAN_Pytorch/models.py b/PyTorch/contrib/cv/others/GAN_Pytorch/models.py index 6e6f1a9984..f04632ce98 100644 --- a/PyTorch/contrib/cv/others/GAN_Pytorch/models.py +++ b/PyTorch/contrib/cv/others/GAN_Pytorch/models.py @@ -1,68 +1,68 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch.nn as nn -import numpy as np - -channels = 1 -image_size = 28 -img_shape =(channels,image_size,image_size) -latent_dim = 100 - -class Generator(nn.Module): - def __init__(self): - super(Generator, self).__init__() - - def block(in_feat, out_feat, normalize=True): - layers = [nn.Linear(in_feat, out_feat)] - if normalize: - layers.append(nn.BatchNorm1d(out_feat, 0.8)) - layers.append(nn.LeakyReLU(0.2, inplace=True)) - return layers - - self.model = nn.Sequential( - *block(latent_dim, 128, normalize=False), - *block(128, 256), - *block(256, 512), - *block(512, 1024), - nn.Linear(1024, int(np.prod(img_shape))), - nn.Tanh() - ) - - def forward(self, z): - img = self.model(z) - img = img.view(img.size(0), *img_shape) - return img - -class Discriminator(nn.Module): - def __init__(self): - super(Discriminator, self).__init__() - - self.model = nn.Sequential( - nn.Linear(int(np.prod(img_shape)), 512), - nn.LeakyReLU(0.2, inplace=True), - nn.Linear(512, 256), - nn.LeakyReLU(0.2, inplace=True), - nn.Linear(256, 1), - nn.Sigmoid(), - ) - - def forward(self, img): - img_flat = img.view(img.size(0), -1) - validity = self.model(img_flat) - - return validity - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch.nn as nn +import numpy as np + +channels = 1 +image_size = 28 +img_shape =(channels,image_size,image_size) +latent_dim = 100 + +class Generator(nn.Module): + def __init__(self): + super(Generator, self).__init__() + + def block(in_feat, out_feat, normalize=True): + layers = [nn.Linear(in_feat, out_feat)] + if normalize: + layers.append(nn.BatchNorm1d(out_feat, 0.8)) + layers.append(nn.LeakyReLU(0.2, inplace=True)) + return layers + + self.model = nn.Sequential( + *block(latent_dim, 128, normalize=False), + *block(128, 256), + *block(256, 512), + *block(512, 1024), + nn.Linear(1024, int(np.prod(img_shape))), + nn.Tanh() + ) + + def forward(self, z): + img = self.model(z) + img = img.view(img.size(0), *img_shape) + return img + +class Discriminator(nn.Module): + def __init__(self): + super(Discriminator, self).__init__() + + self.model = nn.Sequential( + nn.Linear(int(np.prod(img_shape)), 512), + nn.LeakyReLU(0.2, inplace=True), + nn.Linear(512, 256), + nn.LeakyReLU(0.2, inplace=True), + nn.Linear(256, 1), + nn.Sigmoid(), + ) + + def forward(self, img): + img_flat = img.view(img.size(0), -1) + validity = self.model(img_flat) + + return validity + + diff --git a/PyTorch/contrib/cv/others/GAN_Pytorch/modelzoo_level.txt b/PyTorch/contrib/cv/others/GAN_Pytorch/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/others/GAN_Pytorch/modelzoo_level.txt +++ b/PyTorch/contrib/cv/others/GAN_Pytorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/Pix2Pix/README.md b/PyTorch/contrib/cv/others/Pix2Pix/README.md index f1b3173677..c76a5fa338 100644 --- a/PyTorch/contrib/cv/others/Pix2Pix/README.md +++ b/PyTorch/contrib/cv/others/Pix2Pix/README.md @@ -1,38 +1,38 @@ -# Pix2Pix - url=https://gitee.com/iiiimp/modelzoo/tree/master/contrib/PyTorch/Research/cv/gan/Pix2Pix - branch=master - -# 精度性能 - - | 名称 | 精度 | 性能 | - | :------: | :------: | :------: | - | GPU-1p | - | 15 | - | GPU-8p | - | 31 | - | NPU-1p | - | 8 | - | NPU-8p | - | 8 | -# 自验报告 - - # 1p train perf - # 是否正确输出了性能log文件 - bash ./test/train_performance_1p.sh\ --data_path=./datasets/facades - # 验收结果: OK - # 备注: 目标性能8FPS;验收测试性能8FPS; - - # 8p train perf - # 是否正确输出了性能log文件 - bash ./test/train_performance_8p.sh\ --data_path=./datasets/facades - # 验收结果: OK - # 备注: 目标性能15FPS;验收测试性能8PS; - - # 8p train full - # 是否正确输出了性能精度log文件,是否正确保存了模型文件 - bash ./test/train_full_8p.sh\ --data_path=./datasets/facades - # 验收结果: OK - # 备注:直接看图片效果 - - # 8p eval - # 是否正确输出了性能精度log文件 - bash ./test/train_eval_8p.sh\ --data_path=./datasets/facades --pth_path=./checkpoints/facades_pix2pix_npu_8p_full - # 验收结果: OK - # 备注:直接看图片效果 - +# Pix2Pix + url=https://gitee.com/iiiimp/modelzoo/tree/master/contrib/PyTorch/Research/cv/gan/Pix2Pix + branch=master + +# 精度性能 + + | 名称 | 精度 | 性能 | + | :------: | :------: | :------: | + | GPU-1p | - | 15 | + | GPU-8p | - | 31 | + | NPU-1p | - | 8 | + | NPU-8p | - | 8 | +# 自验报告 + + # 1p train perf + # 是否正确输出了性能log文件 + bash ./test/train_performance_1p.sh\ --data_path=./datasets/facades + # 验收结果: OK + # 备注: 目标性能8FPS;验收测试性能8FPS; + + # 8p train perf + # 是否正确输出了性能log文件 + bash ./test/train_performance_8p.sh\ --data_path=./datasets/facades + # 验收结果: OK + # 备注: 目标性能15FPS;验收测试性能8PS; + + # 8p train full + # 是否正确输出了性能精度log文件,是否正确保存了模型文件 + bash ./test/train_full_8p.sh\ --data_path=./datasets/facades + # 验收结果: OK + # 备注:直接看图片效果 + + # 8p eval + # 是否正确输出了性能精度log文件 + bash ./test/train_eval_8p.sh\ --data_path=./datasets/facades --pth_path=./checkpoints/facades_pix2pix_npu_8p_full + # 验收结果: OK + # 备注:直接看图片效果 + diff --git a/PyTorch/contrib/cv/others/Pix2Pix/modelzoo_level.txt b/PyTorch/contrib/cv/others/Pix2Pix/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/others/Pix2Pix/modelzoo_level.txt +++ b/PyTorch/contrib/cv/others/Pix2Pix/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/Pix2Pix/precision.py b/PyTorch/contrib/cv/others/Pix2Pix/precision.py index c14e8e8abc..99dc500223 100644 --- a/PyTorch/contrib/cv/others/Pix2Pix/precision.py +++ b/PyTorch/contrib/cv/others/Pix2Pix/precision.py @@ -1,198 +1,198 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -# Copyright (c) Soumith Chintala 2016, -# All rights reserved -# -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -# -*- coding: utf-8 -*- -"""用于精度比对 -""" - -import torch -import torch.nn as nn -import torchvision -import apex -from apex import amp -import copy -from models import networks - -##### 需自行改写部分 start ##### -# 获得模型 -def get_model(): - model = networks.define_G(3, 3, 64, 'unet_256', 'instance', - True, 'normal', 0.02, '[0]') - # model = networks.define_D(6, 64, 'basic', - # 3, 'instance','normal', 0.02, '[0]') - # 用于避免BN或者Dropout带来的影响,如果遇到无法evalbackward的现象,请注掉该行 - # model.eval() - - return model - -# 获得输入tensor -input_tensor = torch.randn(1, 3, 256, 256) -# input_tensor = torch.randn(1, 6, 256, 256) - -# 设置npu_device -npu_device = 'npu:0' - -# 设置amp -AMP_MODE = True - -# 设置NPU prof 文件输出 -NPU_PROF = True - -##### 需自行改写部分 end ##### - -def cri_func(x): - base_func = nn.CrossEntropyLoss() - shape_list = x.shape - N = shape_list[0] - R = 1 - if len(shape_list) > 1: - for r in shape_list[1:]: - R *= r - T = torch.randint(0,R, size=(N,)).to(x.device) - if str(T.device).startswith('npu'): - T = T.int() - return base_func(x.reshape(N, -1), T) - -# 设置hook -def hook_func(name, save_dict, module): - def hook_function(module, inputs, outputs): - inputs_key = name + '_inputs' - idx = 0 - while inputs_key in save_dict: - inputs_key = inputs_key.split('-')[0] + '-%d'%idx - idx +=1 - save_dict[inputs_key] = inputs - - outputs_key = name + '_outputs' - idx = 0 - while outputs_key in save_dict: - outputs_key = outputs_key.split('-')[0] + '-%d'%idx - idx +=1 - save_dict[outputs_key] = outputs - return hook_function - -##### CPU ##### -# CPU固定输入和权重 -model = get_model() -optimizer = torch.optim.SGD(model.parameters(), 0.1) -state_dict = copy.deepcopy(model.state_dict()) - -# CPU注册hook,cpu_dict用于存储对比对象 -cpu_dict = {} -for name, module in model.named_modules(): - module.register_forward_hook(hook_func('[forward]:' + name, cpu_dict, module)) - module.register_backward_hook(hook_func('[backward]:' + name, cpu_dict, module)) - -# CPU运行正反向,获取正反向每个module的输入输出和所有参数的grad -out = model(input_tensor) -loss = cri_func(out) -optimizer.zero_grad() -loss.backward() -optimizer.step() -for name, param in model.named_parameters(): - cpu_dict["[grad]:" + name] = param.grad - -##### NPU ##### -# 重新定义模型,清理模型状态,并加装权重,保持初始化一致 -model = get_model() -optimizer = torch.optim.SGD(model.parameters(), 0.1) -model.load_state_dict(state_dict) - -# NPU注册hook,npu_dict用于存储对比对象 -npu_dict = {} -for name, module in model.named_modules(): - module.register_forward_hook(hook_func('[forward]:' + name, npu_dict, module)) - module.register_backward_hook(hook_func('[backward]:' + name, npu_dict, module)) - -# 将model和input_tensor放到npu -torch.npu.set_device(npu_device) -model = model.npu() -input_tensor = input_tensor.npu() - -# amp可选项,不适用请注释 -if AMP_MODE: - optimizer = apex.optimizers.NpuFusedSGD(model.parameters(), 0.1) - model, optimizer = amp.initialize(model, optimizer, opt_level='O2', loss_scale=1.0, combine_grad=True) - -# NPU运行正反向,获取正反向每个module的输入输出和所有参数的grad -out = model(input_tensor) -loss = cri_func(out) -optimizer.zero_grad() -if AMP_MODE: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() -else: - loss.backward() -optimizer.step() -for name, param in model.named_parameters(): - npu_dict["[grad]:" + name] = param.grad - - -##### ComPare ##### -# 递归得到对比值 -def compare(x1, x2, prefix=''): - if isinstance(x1, tuple): - if x1: - for idx in range(len(x1)): - try: - compare(x1[idx], x2[idx], prefix=prefix + '.%d' % idx) - except Exception as e: - # print(str(e)) - print(prefix, 'failed.') - elif isinstance(x1, torch.Tensor) and isinstance(x2, torch.Tensor): - try: - l1_error = (x1.half().float() - x2.cpu()).abs().mean() - rel_error = l1_error / (x1.abs().mean()) - print(prefix, 'l1_error: ', l1_error, 'rel_error', rel_error) - if l1_error * rel_error > 10 : - print('\n###\n',prefix, 'should checked!','\n###\n') - except Exception as e: - # print(str(e)) - print(prefix, 'failed.') - -for k in cpu_dict: - compare(cpu_dict[k], npu_dict[k], prefix=k) - -# 需要profiling的时候额外输出一次 -if NPU_PROF: - with torch.autograd.profiler.profile(use_npu=True) as prof: - out = model(input_tensor) - loss = cri_func(out) - optimizer.zero_grad() - if AMP_MODE: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.step() - prof.export_chrome_trace("netD output.prof") # "output.prof"为输出文件地址 - - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +# Copyright (c) Soumith Chintala 2016, +# All rights reserved +# +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +# -*- coding: utf-8 -*- +"""用于精度比对 +""" + +import torch +import torch.nn as nn +import torchvision +import apex +from apex import amp +import copy +from models import networks + +##### 需自行改写部分 start ##### +# 获得模型 +def get_model(): + model = networks.define_G(3, 3, 64, 'unet_256', 'instance', + True, 'normal', 0.02, '[0]') + # model = networks.define_D(6, 64, 'basic', + # 3, 'instance','normal', 0.02, '[0]') + # 用于避免BN或者Dropout带来的影响,如果遇到无法evalbackward的现象,请注掉该行 + # model.eval() + + return model + +# 获得输入tensor +input_tensor = torch.randn(1, 3, 256, 256) +# input_tensor = torch.randn(1, 6, 256, 256) + +# 设置npu_device +npu_device = 'npu:0' + +# 设置amp +AMP_MODE = True + +# 设置NPU prof 文件输出 +NPU_PROF = True + +##### 需自行改写部分 end ##### + +def cri_func(x): + base_func = nn.CrossEntropyLoss() + shape_list = x.shape + N = shape_list[0] + R = 1 + if len(shape_list) > 1: + for r in shape_list[1:]: + R *= r + T = torch.randint(0,R, size=(N,)).to(x.device) + if str(T.device).startswith('npu'): + T = T.int() + return base_func(x.reshape(N, -1), T) + +# 设置hook +def hook_func(name, save_dict, module): + def hook_function(module, inputs, outputs): + inputs_key = name + '_inputs' + idx = 0 + while inputs_key in save_dict: + inputs_key = inputs_key.split('-')[0] + '-%d'%idx + idx +=1 + save_dict[inputs_key] = inputs + + outputs_key = name + '_outputs' + idx = 0 + while outputs_key in save_dict: + outputs_key = outputs_key.split('-')[0] + '-%d'%idx + idx +=1 + save_dict[outputs_key] = outputs + return hook_function + +##### CPU ##### +# CPU固定输入和权重 +model = get_model() +optimizer = torch.optim.SGD(model.parameters(), 0.1) +state_dict = copy.deepcopy(model.state_dict()) + +# CPU注册hook,cpu_dict用于存储对比对象 +cpu_dict = {} +for name, module in model.named_modules(): + module.register_forward_hook(hook_func('[forward]:' + name, cpu_dict, module)) + module.register_backward_hook(hook_func('[backward]:' + name, cpu_dict, module)) + +# CPU运行正反向,获取正反向每个module的输入输出和所有参数的grad +out = model(input_tensor) +loss = cri_func(out) +optimizer.zero_grad() +loss.backward() +optimizer.step() +for name, param in model.named_parameters(): + cpu_dict["[grad]:" + name] = param.grad + +##### NPU ##### +# 重新定义模型,清理模型状态,并加装权重,保持初始化一致 +model = get_model() +optimizer = torch.optim.SGD(model.parameters(), 0.1) +model.load_state_dict(state_dict) + +# NPU注册hook,npu_dict用于存储对比对象 +npu_dict = {} +for name, module in model.named_modules(): + module.register_forward_hook(hook_func('[forward]:' + name, npu_dict, module)) + module.register_backward_hook(hook_func('[backward]:' + name, npu_dict, module)) + +# 将model和input_tensor放到npu +torch.npu.set_device(npu_device) +model = model.npu() +input_tensor = input_tensor.npu() + +# amp可选项,不适用请注释 +if AMP_MODE: + optimizer = apex.optimizers.NpuFusedSGD(model.parameters(), 0.1) + model, optimizer = amp.initialize(model, optimizer, opt_level='O2', loss_scale=1.0, combine_grad=True) + +# NPU运行正反向,获取正反向每个module的输入输出和所有参数的grad +out = model(input_tensor) +loss = cri_func(out) +optimizer.zero_grad() +if AMP_MODE: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() +else: + loss.backward() +optimizer.step() +for name, param in model.named_parameters(): + npu_dict["[grad]:" + name] = param.grad + + +##### ComPare ##### +# 递归得到对比值 +def compare(x1, x2, prefix=''): + if isinstance(x1, tuple): + if x1: + for idx in range(len(x1)): + try: + compare(x1[idx], x2[idx], prefix=prefix + '.%d' % idx) + except Exception as e: + # print(str(e)) + print(prefix, 'failed.') + elif isinstance(x1, torch.Tensor) and isinstance(x2, torch.Tensor): + try: + l1_error = (x1.half().float() - x2.cpu()).abs().mean() + rel_error = l1_error / (x1.abs().mean()) + print(prefix, 'l1_error: ', l1_error, 'rel_error', rel_error) + if l1_error * rel_error > 10 : + print('\n###\n',prefix, 'should checked!','\n###\n') + except Exception as e: + # print(str(e)) + print(prefix, 'failed.') + +for k in cpu_dict: + compare(cpu_dict[k], npu_dict[k], prefix=k) + +# 需要profiling的时候额外输出一次 +if NPU_PROF: + with torch.autograd.profiler.profile(use_npu=True) as prof: + out = model(input_tensor) + loss = cri_func(out) + optimizer.zero_grad() + if AMP_MODE: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + optimizer.step() + prof.export_chrome_trace("netD output.prof") # "output.prof"为输出文件地址 + + diff --git a/PyTorch/contrib/cv/others/Pix2Pix/pytorch_prof.py b/PyTorch/contrib/cv/others/Pix2Pix/pytorch_prof.py index afb06b4b97..d79a619de9 100644 --- a/PyTorch/contrib/cv/others/Pix2Pix/pytorch_prof.py +++ b/PyTorch/contrib/cv/others/Pix2Pix/pytorch_prof.py @@ -1,141 +1,141 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -# Copyright (c) Soumith Chintala 2016, -# All rights reserved -# -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://spdx.org/licenses/BSD-3-Clause.html -# -# 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. - -# -*- coding: utf-8 -*- -"""pytorch_prof.py -""" - -import torch -import torch.optim as optim -import torch.nn as nn -import time -import argparse -from models import networks - -def build_model(): - # 请自定义模型并加载预训练模型 - # import torchvision - # model = torchvision.models.resnet50(pretrained=True) - model = networks.define_G(3, 3, 64, 'unet_256', 'instance', - True, 'normal', 0.02, '[0]') - return model - - -def get_raw_data(): - # input_tensor = torch.randn(2, 3, 224, 224) - input_tensor = torch.randn(1, 3, 256, 256) - return input_tensor - - -def criterion(x): - base_func = nn.CrossEntropyLoss() - shape_list = x.shape - N = shape_list[0] - R = 1 - if len(shape_list) > 1: - for r in shape_list[1:]: - R *= r - T = torch.randint(0,R, size=(N,)).to(x.device) - if str(T.device).startswith('npu'): - T = T.int() - return base_func(x.reshape(N, -1), T) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='PyTorch Prof') - parser.add_argument('--device', type=str, default='cpu', - help='set which type of device used. Support cuda:0(device_id), npu:0(device_id).') - parser.add_argument('--amp', default=False, action='store_true', - help='use amp during prof') - parser.add_argument('--loss-scale', default=64.0, type=float, - help='loss scale using in amp, default 64.0, -1 means dynamic') - parser.add_argument('--opt-level', default='O2', type=str, - help='opt-level using in amp, default O2') - parser.add_argument('--FusedSGD', default=False, action='store_true', - help='use FusedSGD during prof') - - args = parser.parse_args() - - # 1.准备工作 - if args.device.startswith('cuda'): - torch.cuda.set_device(args.device) - prof_kwargs = {'use_cuda': True} - elif args.device.startswith('npu'): - torch.npu.set_device(args.device) - prof_kwargs = {'use_npu': True} - else: - prof_kwargs = {} - - # 2.构建模型 - model = build_model() - if args.FusedSGD: - from apex.optimizers import NpuFusedSGD - optimizer = NpuFusedSGD(model.parameters(), lr=0.01) - model = model.to(args.device) - if args.amp: - from apex import amp - model, optimizer = amp.initialize(model, optimizer, opt_level=args.opt_level, - loss_scale=None if args.loss_scale == -1 else args.loss_scale, - combine_grad=True) - else: - optimizer = optim.SGD(model.parameters(), lr=0.01) - model = model.to(args.device) - if args.amp: - from apex import amp - model, optimizer = amp.initialize(model, optimizer, opt_level=args.opt_level, - loss_scale=None if args.loss_scale == -1 else args.loss_scale) - - # 3.生成input - input_tensor = get_raw_data() - input_tensor = input_tensor.to(args.device) - - # 先运行一次,保证prof得到的性能是正确的 - def run(): - output_tensor = model(input_tensor) - loss = criterion(output_tensor) - optimizer.zero_grad() - if args.amp: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.step() - return loss - for i in range(5): - start_time = time.time() - loss = run() - print('iter: %d, loss: %.2f, time: %.2f'%(i, loss, (time.time() - start_time)*1000)) - - # 4. 执行forward+profiling - with torch.autograd.profiler.profile(**prof_kwargs) as prof: - run() - print(prof.key_averages().table()) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +# Copyright (c) Soumith Chintala 2016, +# All rights reserved +# +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://spdx.org/licenses/BSD-3-Clause.html +# +# 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. + +# -*- coding: utf-8 -*- +"""pytorch_prof.py +""" + +import torch +import torch.optim as optim +import torch.nn as nn +import time +import argparse +from models import networks + +def build_model(): + # 请自定义模型并加载预训练模型 + # import torchvision + # model = torchvision.models.resnet50(pretrained=True) + model = networks.define_G(3, 3, 64, 'unet_256', 'instance', + True, 'normal', 0.02, '[0]') + return model + + +def get_raw_data(): + # input_tensor = torch.randn(2, 3, 224, 224) + input_tensor = torch.randn(1, 3, 256, 256) + return input_tensor + + +def criterion(x): + base_func = nn.CrossEntropyLoss() + shape_list = x.shape + N = shape_list[0] + R = 1 + if len(shape_list) > 1: + for r in shape_list[1:]: + R *= r + T = torch.randint(0,R, size=(N,)).to(x.device) + if str(T.device).startswith('npu'): + T = T.int() + return base_func(x.reshape(N, -1), T) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='PyTorch Prof') + parser.add_argument('--device', type=str, default='cpu', + help='set which type of device used. Support cuda:0(device_id), npu:0(device_id).') + parser.add_argument('--amp', default=False, action='store_true', + help='use amp during prof') + parser.add_argument('--loss-scale', default=64.0, type=float, + help='loss scale using in amp, default 64.0, -1 means dynamic') + parser.add_argument('--opt-level', default='O2', type=str, + help='opt-level using in amp, default O2') + parser.add_argument('--FusedSGD', default=False, action='store_true', + help='use FusedSGD during prof') + + args = parser.parse_args() + + # 1.准备工作 + if args.device.startswith('cuda'): + torch.cuda.set_device(args.device) + prof_kwargs = {'use_cuda': True} + elif args.device.startswith('npu'): + torch.npu.set_device(args.device) + prof_kwargs = {'use_npu': True} + else: + prof_kwargs = {} + + # 2.构建模型 + model = build_model() + if args.FusedSGD: + from apex.optimizers import NpuFusedSGD + optimizer = NpuFusedSGD(model.parameters(), lr=0.01) + model = model.to(args.device) + if args.amp: + from apex import amp + model, optimizer = amp.initialize(model, optimizer, opt_level=args.opt_level, + loss_scale=None if args.loss_scale == -1 else args.loss_scale, + combine_grad=True) + else: + optimizer = optim.SGD(model.parameters(), lr=0.01) + model = model.to(args.device) + if args.amp: + from apex import amp + model, optimizer = amp.initialize(model, optimizer, opt_level=args.opt_level, + loss_scale=None if args.loss_scale == -1 else args.loss_scale) + + # 3.生成input + input_tensor = get_raw_data() + input_tensor = input_tensor.to(args.device) + + # 先运行一次,保证prof得到的性能是正确的 + def run(): + output_tensor = model(input_tensor) + loss = criterion(output_tensor) + optimizer.zero_grad() + if args.amp: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + optimizer.step() + return loss + for i in range(5): + start_time = time.time() + loss = run() + print('iter: %d, loss: %.2f, time: %.2f'%(i, loss, (time.time() - start_time)*1000)) + + # 4. 执行forward+profiling + with torch.autograd.profiler.profile(**prof_kwargs) as prof: + run() + print(prof.key_averages().table()) prof.export_chrome_trace("pytorch_prof_%s.prof" % args.device) \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/RDN/Dockerfile b/PyTorch/contrib/cv/others/RDN/Dockerfile index 7e712fe1a1..30a31af558 100644 --- a/PyTorch/contrib/cv/others/RDN/Dockerfile +++ b/PyTorch/contrib/cv/others/RDN/Dockerfile @@ -1,5 +1,5 @@ -ARG FROM_IMAGE_NAME -FROM $FROM_IMAGE_NAME - -COPY requirements.txt . +ARG FROM_IMAGE_NAME +FROM $FROM_IMAGE_NAME + +COPY requirements.txt . RUN pip3.7 install -r requirements.txt \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/RDN/README.md b/PyTorch/contrib/cv/others/RDN/README.md index 6a58d58d88..bbda601483 100644 --- a/PyTorch/contrib/cv/others/RDN/README.md +++ b/PyTorch/contrib/cv/others/RDN/README.md @@ -1,51 +1,51 @@ -# RDN 训练 -# Residual Dense Network for Image Super-Resolution -This implements training of RDN on the DIV2K_x2 dataset. -- Reference implementation: -``` -url=https://github.com/yjn870/RDN-pytorch -``` - -## RDN Detail # - -As of the current date, Ascend-Pytorch is still inefficient for contiguous operations. -Therefore, RDN is re-implemented using semantics such as custom OP. - - -## Requirements # - -- Install PyTorch ([pytorch.org](http://pytorch.org)) -- `pip install -r requirements.txt` -- The DIV2k, Set5 Dataset can be downloaded from the links below.Move the datasets to directory ./data . - - Train Set : [Download DIV2k](https://www.dropbox.com/s/41sn4eie37hp6rh/DIV2K_x2.h5?dl=0) - - Test Set : [Download Set5](https://www.dropbox.com/s/pd52pkmaik1ri0h/rdn_x2.pth?dl=0) - -## Training # -To train a model, run `main.py` with the desired model architecture and the path to the ImageNet dataset: - -```bash -# 1p train perf -bash test/train_performance_1p.sh - -# 8p train perf -bash test/train_performance_8p.sh - -# 8p train full -bash test/train_full_8p.sh - -# 8p eval -bash test/train_eval_8p.sh - -# finetuning -bash test/train_finetune_1p.sh -``` - -## RDN training result # - -| Acc@1 | FPS | Npu_nums | Epochs | AMP_Type | -| :------: | :------: | :------: | :------: | :------: | -| - | 240 | 1 | 800 | O1 | -| 37.95 | 1716 | 8 | 800 | O1 | - - - +# RDN 训练 +# Residual Dense Network for Image Super-Resolution +This implements training of RDN on the DIV2K_x2 dataset. +- Reference implementation: +``` +url=https://github.com/yjn870/RDN-pytorch +``` + +## RDN Detail # + +As of the current date, Ascend-Pytorch is still inefficient for contiguous operations. +Therefore, RDN is re-implemented using semantics such as custom OP. + + +## Requirements # + +- Install PyTorch ([pytorch.org](http://pytorch.org)) +- `pip install -r requirements.txt` +- The DIV2k, Set5 Dataset can be downloaded from the links below.Move the datasets to directory ./data . + - Train Set : [Download DIV2k](https://www.dropbox.com/s/41sn4eie37hp6rh/DIV2K_x2.h5?dl=0) + - Test Set : [Download Set5](https://www.dropbox.com/s/pd52pkmaik1ri0h/rdn_x2.pth?dl=0) + +## Training # +To train a model, run `main.py` with the desired model architecture and the path to the ImageNet dataset: + +```bash +# 1p train perf +bash test/train_performance_1p.sh + +# 8p train perf +bash test/train_performance_8p.sh + +# 8p train full +bash test/train_full_8p.sh + +# 8p eval +bash test/train_eval_8p.sh + +# finetuning +bash test/train_finetune_1p.sh +``` + +## RDN training result # + +| Acc@1 | FPS | Npu_nums | Epochs | AMP_Type | +| :------: | :------: | :------: | :------: | :------: | +| - | 240 | 1 | 800 | O1 | +| 37.95 | 1716 | 8 | 800 | O1 | + + + diff --git a/PyTorch/contrib/cv/others/RDN/docker_start.sh b/PyTorch/contrib/cv/others/RDN/docker_start.sh index 46ce9a02ec..944bca3cda 100644 --- a/PyTorch/contrib/cv/others/RDN/docker_start.sh +++ b/PyTorch/contrib/cv/others/RDN/docker_start.sh @@ -1,25 +1,25 @@ -#!/bin/bash - -docker_image=$1 -data_dir=$2 -model_dir=$3 - -docker run -it --ipc=host \ - --device=/dev/davinci0 \ - --device=/dev/davinci1 \ - --device=/dev/davinci2 \ - --device=/dev/davinci3 \ - --device=/dev/davinci4 \ - --device=/dev/davinci5 \ - --device=/dev/davinci6 \ - --device=/dev/davinci7 \ - --device=/dev/davinci_manager \ - --device=/dev/devmm_svm --device=/dev/hisi_hdc \ - -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ - -v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \ - -v ${model_dir}:${model_dir} \ - -v ${data_dir}:${data_dir} \ - -v /var/log/npu/conf/slog/slog.conf:/var/log/npu/conf/slog/slog.conf \ - -v /var/log/npu/slog/:/var/log/npu/slog -v /var/log/npu/profiling/:/var/log/npu/profiling \ - -v /var/log/npu/dump/:/var/log/npu/dump -v /var/log/npu/:/usr/slog ${docker_image} \ +#!/bin/bash + +docker_image=$1 +data_dir=$2 +model_dir=$3 + +docker run -it --ipc=host \ + --device=/dev/davinci0 \ + --device=/dev/davinci1 \ + --device=/dev/davinci2 \ + --device=/dev/davinci3 \ + --device=/dev/davinci4 \ + --device=/dev/davinci5 \ + --device=/dev/davinci6 \ + --device=/dev/davinci7 \ + --device=/dev/davinci_manager \ + --device=/dev/devmm_svm --device=/dev/hisi_hdc \ + -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ + -v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \ + -v ${model_dir}:${model_dir} \ + -v ${data_dir}:${data_dir} \ + -v /var/log/npu/conf/slog/slog.conf:/var/log/npu/conf/slog/slog.conf \ + -v /var/log/npu/slog/:/var/log/npu/slog -v /var/log/npu/profiling/:/var/log/npu/profiling \ + -v /var/log/npu/dump/:/var/log/npu/dump -v /var/log/npu/:/usr/slog ${docker_image} \ /bin/bash \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/RDN/modelzoo_level.txt b/PyTorch/contrib/cv/others/RDN/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/others/RDN/modelzoo_level.txt +++ b/PyTorch/contrib/cv/others/RDN/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/Srcnn_x2_for_Pytorch/modelzoo_level.txt b/PyTorch/contrib/cv/others/Srcnn_x2_for_Pytorch/modelzoo_level.txt index 4987c10696..0c22703439 100644 --- a/PyTorch/contrib/cv/others/Srcnn_x2_for_Pytorch/modelzoo_level.txt +++ b/PyTorch/contrib/cv/others/Srcnn_x2_for_Pytorch/modelzoo_level.txt @@ -1,6 +1,6 @@ -GPUStatus:OK -NPUMigrationStatus:OK -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +GPUStatus:OK +NPUMigrationStatus:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/Srcnn_x2_for_Pytorch/requirements.txt b/PyTorch/contrib/cv/others/Srcnn_x2_for_Pytorch/requirements.txt index 148f855f4f..7cd93126a9 100644 --- a/PyTorch/contrib/cv/others/Srcnn_x2_for_Pytorch/requirements.txt +++ b/PyTorch/contrib/cv/others/Srcnn_x2_for_Pytorch/requirements.txt @@ -1,5 +1,5 @@ -h5py==3.3.0 -numpy==1.20.2 -Pillow==8.2.0 -tqdm==4.19.9 +h5py==3.3.0 +numpy==1.20.2 +Pillow==8.2.0 +tqdm==4.19.9 scikit-image==0.16.2 \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/edsr_x2/loss.py b/PyTorch/contrib/cv/others/edsr_x2/loss.py index 98219c473c..c89c9ce159 100644 --- a/PyTorch/contrib/cv/others/edsr_x2/loss.py +++ b/PyTorch/contrib/cv/others/edsr_x2/loss.py @@ -1,152 +1,152 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -import os -from importlib import import_module - -import numpy as np - -import torch -import torch.nn as nn -import torch.nn.functional as F - - -class Loss(nn.modules.loss._Loss): - def __init__(self, args, ckp): - super(Loss, self).__init__() - print("Preparing loss function:") - - self.n_GPUs = args.n_GPUs - self.loss = [] - self.loss_module = nn.ModuleList() - for loss in args.loss.split("+"): - weight, loss_type = loss.split("*") - if loss_type == "MSE": - loss_function = nn.MSELoss() - elif loss_type == "L1": - loss_function = nn.L1Loss() - elif loss_type.find("VGG") >= 0: - module = import_module("loss.vgg") - loss_function = getattr(module, "VGG")( - loss_type[3:], rgb_range=args.rgb_range - ) - elif loss_type.find("GAN") >= 0: - module = import_module("loss.adversarial") - loss_function = getattr(module, "Adversarial")(args, loss_type) - - self.loss.append( - {"type": loss_type, "weight": float( - weight), "function": loss_function} - ) - if loss_type.find("GAN") >= 0: - self.loss.append( - {"type": "DIS", "weight": 1, "function": None}) - - if len(self.loss) > 1: - self.loss.append({"type": "Total", "weight": 0, "function": None}) - - for l in self.loss: - if l["function"] is not None: - print("{:.3f} * {}".format(l["weight"], l["type"])) - self.loss_module.append(l["function"]) - - self.log = torch.Tensor() - - device = torch.device("cpu" if args.cpu else "cuda") - if args.use_npu: - device = args.device - self.loss_module.to(device) - if not args.cpu and args.n_GPUs > 1: - self.loss_module = nn.DataParallel( - self.loss_module, range(args.n_GPUs)) - - if args.load != "": - self.load(ckp.dir, cpu=args.cpu) - - def forward(self, sr, hr): - losses = [] - for i, l in enumerate(self.loss): - if l["function"] is not None: - loss = l["function"](sr, hr) - effective_loss = l["weight"] * loss - losses.append(effective_loss) - self.log[-1, i] += effective_loss.item() - elif l["type"] == "DIS": - self.log[-1, i] += self.loss[i - 1]["function"].loss - - loss_sum = sum(losses) - if len(self.loss) > 1: - self.log[-1, -1] += loss_sum.item() - - return loss_sum - - def step(self): - for l in self.get_loss_module(): - if hasattr(l, "scheduler"): - l.scheduler.step() - - def start_log(self): - self.log = torch.cat((self.log, torch.zeros(1, len(self.loss)))) - - def end_log(self, n_batches): - self.log[-1].div_(n_batches) - - def display_loss(self, batch): - n_samples = batch + 1 - log = [] - for l, c in zip(self.loss, self.log[-1]): - log.append("[{}: {:.4f}]".format(l["type"], c / n_samples)) - - return "".join(log) - - def get_loss_module(self): - if self.n_GPUs == 1: - return self.loss_module - else: - return self.loss_module.module - - def save(self, apath): - torch.save(self.state_dict(), os.path.join(apath, "loss.pt")) - torch.save(self.log, os.path.join(apath, "loss_log.pt")) - - def load(self, apath, cpu=False): - if cpu: - kwargs = {"map_location": lambda storage, loc: storage} - else: - kwargs = {} - - self.load_state_dict(torch.load( - os.path.join(apath, "loss.pt"), **kwargs)) - self.log = torch.load(os.path.join(apath, "loss_log.pt")) - for l in self.get_loss_module(): - if hasattr(l, "scheduler"): - for _ in range(len(self.log)): - l.scheduler.step() +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import os +from importlib import import_module + +import numpy as np + +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class Loss(nn.modules.loss._Loss): + def __init__(self, args, ckp): + super(Loss, self).__init__() + print("Preparing loss function:") + + self.n_GPUs = args.n_GPUs + self.loss = [] + self.loss_module = nn.ModuleList() + for loss in args.loss.split("+"): + weight, loss_type = loss.split("*") + if loss_type == "MSE": + loss_function = nn.MSELoss() + elif loss_type == "L1": + loss_function = nn.L1Loss() + elif loss_type.find("VGG") >= 0: + module = import_module("loss.vgg") + loss_function = getattr(module, "VGG")( + loss_type[3:], rgb_range=args.rgb_range + ) + elif loss_type.find("GAN") >= 0: + module = import_module("loss.adversarial") + loss_function = getattr(module, "Adversarial")(args, loss_type) + + self.loss.append( + {"type": loss_type, "weight": float( + weight), "function": loss_function} + ) + if loss_type.find("GAN") >= 0: + self.loss.append( + {"type": "DIS", "weight": 1, "function": None}) + + if len(self.loss) > 1: + self.loss.append({"type": "Total", "weight": 0, "function": None}) + + for l in self.loss: + if l["function"] is not None: + print("{:.3f} * {}".format(l["weight"], l["type"])) + self.loss_module.append(l["function"]) + + self.log = torch.Tensor() + + device = torch.device("cpu" if args.cpu else "cuda") + if args.use_npu: + device = args.device + self.loss_module.to(device) + if not args.cpu and args.n_GPUs > 1: + self.loss_module = nn.DataParallel( + self.loss_module, range(args.n_GPUs)) + + if args.load != "": + self.load(ckp.dir, cpu=args.cpu) + + def forward(self, sr, hr): + losses = [] + for i, l in enumerate(self.loss): + if l["function"] is not None: + loss = l["function"](sr, hr) + effective_loss = l["weight"] * loss + losses.append(effective_loss) + self.log[-1, i] += effective_loss.item() + elif l["type"] == "DIS": + self.log[-1, i] += self.loss[i - 1]["function"].loss + + loss_sum = sum(losses) + if len(self.loss) > 1: + self.log[-1, -1] += loss_sum.item() + + return loss_sum + + def step(self): + for l in self.get_loss_module(): + if hasattr(l, "scheduler"): + l.scheduler.step() + + def start_log(self): + self.log = torch.cat((self.log, torch.zeros(1, len(self.loss)))) + + def end_log(self, n_batches): + self.log[-1].div_(n_batches) + + def display_loss(self, batch): + n_samples = batch + 1 + log = [] + for l, c in zip(self.loss, self.log[-1]): + log.append("[{}: {:.4f}]".format(l["type"], c / n_samples)) + + return "".join(log) + + def get_loss_module(self): + if self.n_GPUs == 1: + return self.loss_module + else: + return self.loss_module.module + + def save(self, apath): + torch.save(self.state_dict(), os.path.join(apath, "loss.pt")) + torch.save(self.log, os.path.join(apath, "loss_log.pt")) + + def load(self, apath, cpu=False): + if cpu: + kwargs = {"map_location": lambda storage, loc: storage} + else: + kwargs = {} + + self.load_state_dict(torch.load( + os.path.join(apath, "loss.pt"), **kwargs)) + self.log = torch.load(os.path.join(apath, "loss_log.pt")) + for l in self.get_loss_module(): + if hasattr(l, "scheduler"): + for _ in range(len(self.log)): + l.scheduler.step() diff --git a/PyTorch/contrib/cv/others/stargan/Dockerfile b/PyTorch/contrib/cv/others/stargan/Dockerfile index 7e712fe1a1..30a31af558 100644 --- a/PyTorch/contrib/cv/others/stargan/Dockerfile +++ b/PyTorch/contrib/cv/others/stargan/Dockerfile @@ -1,5 +1,5 @@ -ARG FROM_IMAGE_NAME -FROM $FROM_IMAGE_NAME - -COPY requirements.txt . +ARG FROM_IMAGE_NAME +FROM $FROM_IMAGE_NAME + +COPY requirements.txt . RUN pip3.7 install -r requirements.txt \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/stargan/README.md b/PyTorch/contrib/cv/others/stargan/README.md index 90ce46ed16..54be720a4b 100644 --- a/PyTorch/contrib/cv/others/stargan/README.md +++ b/PyTorch/contrib/cv/others/stargan/README.md @@ -1,55 +1,55 @@ -# StarGAN 训练 -This implements training of StarGAN on the CelebA dataset. -- Reference implementation: -``` -url=https://github.com/yunjey/stargan -``` - - - -## Requirements # - -- Install Packages -- `pip install -r requirements.txt` -- The CelebA dataset can be downloaded from the [link](https://www.dropbox.com/s/d1kjpkqklf0uw77/celeba.zip?dl=0). You can use `wget` to download as well. - - `wget -N https://www.dropbox.com/s/d1kjpkqklf0uw77/celeba.zip?dl=0` -- Move the datasets to root directory and run the script `unzip_dataset.sh`. - - `bash ./unzip_dataset.sh` - - - -## Training # -To train a model, change the working directory to `./NPU`,then run: - -```bash -# 1p train perf -bash ./test/train_performance_1p.sh '[your_dataset_path]' - -# 8p train perf -bash ./test/train_performance_8p.sh '[your_dataset_path]' - -# 1p train full -bash ./test/train_full_1p.sh '[your_dataset_path]' - -# 8p train full -bash ./test/train_full_8p.sh '[your_dataset_path]' - -# finetuning -bash ./test/train_finetune_1p.sh '[your_dataset_path]' -``` -After running,you can see the results in `./NPU/stargan_full_8p/samples` or `./NPU/stargan_full_1p/samples` - - - - -## GAN training result # - -| Type | FPS | Epochs | AMP_Type | -| :------: | :------: | :------: | :------: | -| NPU-1p | 95 | 1 | O1 | -| NPU-8p | 615 | 50 | O1 | -| GPU-1p | 62 | 1 | O1 | -| GPU-8p | 517 | 50 | O1 | - - - +# StarGAN 训练 +This implements training of StarGAN on the CelebA dataset. +- Reference implementation: +``` +url=https://github.com/yunjey/stargan +``` + + + +## Requirements # + +- Install Packages +- `pip install -r requirements.txt` +- The CelebA dataset can be downloaded from the [link](https://www.dropbox.com/s/d1kjpkqklf0uw77/celeba.zip?dl=0). You can use `wget` to download as well. + - `wget -N https://www.dropbox.com/s/d1kjpkqklf0uw77/celeba.zip?dl=0` +- Move the datasets to root directory and run the script `unzip_dataset.sh`. + - `bash ./unzip_dataset.sh` + + + +## Training # +To train a model, change the working directory to `./NPU`,then run: + +```bash +# 1p train perf +bash ./test/train_performance_1p.sh '[your_dataset_path]' + +# 8p train perf +bash ./test/train_performance_8p.sh '[your_dataset_path]' + +# 1p train full +bash ./test/train_full_1p.sh '[your_dataset_path]' + +# 8p train full +bash ./test/train_full_8p.sh '[your_dataset_path]' + +# finetuning +bash ./test/train_finetune_1p.sh '[your_dataset_path]' +``` +After running,you can see the results in `./NPU/stargan_full_8p/samples` or `./NPU/stargan_full_1p/samples` + + + + +## GAN training result # + +| Type | FPS | Epochs | AMP_Type | +| :------: | :------: | :------: | :------: | +| NPU-1p | 95 | 1 | O1 | +| NPU-8p | 615 | 50 | O1 | +| GPU-1p | 62 | 1 | O1 | +| GPU-8p | 517 | 50 | O1 | + + + diff --git a/PyTorch/contrib/cv/others/stargan/docker_start.sh b/PyTorch/contrib/cv/others/stargan/docker_start.sh index 46ce9a02ec..944bca3cda 100644 --- a/PyTorch/contrib/cv/others/stargan/docker_start.sh +++ b/PyTorch/contrib/cv/others/stargan/docker_start.sh @@ -1,25 +1,25 @@ -#!/bin/bash - -docker_image=$1 -data_dir=$2 -model_dir=$3 - -docker run -it --ipc=host \ - --device=/dev/davinci0 \ - --device=/dev/davinci1 \ - --device=/dev/davinci2 \ - --device=/dev/davinci3 \ - --device=/dev/davinci4 \ - --device=/dev/davinci5 \ - --device=/dev/davinci6 \ - --device=/dev/davinci7 \ - --device=/dev/davinci_manager \ - --device=/dev/devmm_svm --device=/dev/hisi_hdc \ - -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ - -v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \ - -v ${model_dir}:${model_dir} \ - -v ${data_dir}:${data_dir} \ - -v /var/log/npu/conf/slog/slog.conf:/var/log/npu/conf/slog/slog.conf \ - -v /var/log/npu/slog/:/var/log/npu/slog -v /var/log/npu/profiling/:/var/log/npu/profiling \ - -v /var/log/npu/dump/:/var/log/npu/dump -v /var/log/npu/:/usr/slog ${docker_image} \ +#!/bin/bash + +docker_image=$1 +data_dir=$2 +model_dir=$3 + +docker run -it --ipc=host \ + --device=/dev/davinci0 \ + --device=/dev/davinci1 \ + --device=/dev/davinci2 \ + --device=/dev/davinci3 \ + --device=/dev/davinci4 \ + --device=/dev/davinci5 \ + --device=/dev/davinci6 \ + --device=/dev/davinci7 \ + --device=/dev/davinci_manager \ + --device=/dev/devmm_svm --device=/dev/hisi_hdc \ + -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ + -v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \ + -v ${model_dir}:${model_dir} \ + -v ${data_dir}:${data_dir} \ + -v /var/log/npu/conf/slog/slog.conf:/var/log/npu/conf/slog/slog.conf \ + -v /var/log/npu/slog/:/var/log/npu/slog -v /var/log/npu/profiling/:/var/log/npu/profiling \ + -v /var/log/npu/dump/:/var/log/npu/dump -v /var/log/npu/:/usr/slog ${docker_image} \ /bin/bash \ No newline at end of file diff --git a/PyTorch/contrib/cv/others/stargan/modelzoo_level.txt b/PyTorch/contrib/cv/others/stargan/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/others/stargan/modelzoo_level.txt +++ b/PyTorch/contrib/cv/others/stargan/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/README_ch.md b/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/README_ch.md index 0b511652cb..c52f043e27 100644 --- a/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/README_ch.md +++ b/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/README_ch.md @@ -56,8 +56,8 @@ ${3DMPPE_ROOTNET} ## 训练模型 - 注意,`test`目录下的`output`文件夹也会保存代码运行的日志。 -- 运行 `train_1p.py` 或 `train_8p.py` 进行模型训练: - +- 运行 `train_1p.py` 或 `train_8p.py` 进行模型训练: + ``` # 1p train perf @@ -85,7 +85,7 @@ bash test/train_full_8p.sh --data_path=xxx # 其它说明 # -- 运行 `demo.py`: +- 运行 `demo.py`: 进入 `demo` 文件夹。运行demo的输入文件已经提供(`input.jpg`),运行结束后会在该目录下得到输出的图片。将 `snapshot_XX.pth` 放置在 `./output/model_dump/` 目录下。 修改 `run_demo.sh` 中 `test_epoch` 的参数为 `XX` ,与刚才的 `.pth` 文件的数字对应。最后,运行指令: ``` diff --git a/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/README_en.md b/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/README_en.md index c8d3de5dce..677449b5bb 100644 --- a/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/README_en.md +++ b/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/README_en.md @@ -41,7 +41,7 @@ ${3DMPPE_ROOTNET} | | | | |-- ... ## image files | | | |-- MuPoTS-3D.json ``` -- You need to follow directory structure of the `output` as below. +- You need to follow directory structure of the `output` as below. ``` ${3DMPPE_ROOTNET} |-- output @@ -56,7 +56,7 @@ ${3DMPPE_ROOTNET} ## Training # -- Note that the `output` folder under the `test` directory will also save the code running log. +- Note that the `output` folder under the `test` directory will also save the code running log. - To train a model, run `train_1p.py` or `train_8p.py`: ```bash @@ -85,7 +85,7 @@ bash test/train_full_8p.sh --data_path=xxx # Else # -- run `demo.py`: +- run `demo.py`: Enter the demo folder. The input file for running the demo has been provided(`input.jpg`). After running, the output pictures will be obtained in this directory. First, place `snapshot_XX.pth` in directory `./output/model_dump/`. Then, Change the parameter `test_epoch` of `run_demo.sh` to `XX` ,which corresponds to the number of `.pth` file just now. Finally, run the command: ``` diff --git a/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/common/timer.py b/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/common/timer.py index 994424e986..3653f621de 100644 --- a/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/common/timer.py +++ b/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/common/timer.py @@ -1,53 +1,53 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ - -# -------------------------------------------------------- -# Fast R-CNN -# Copyright (c) 2015 Microsoft -# Licensed under The MIT License [see LICENSE for details] -# Written by Ross Girshick -# -------------------------------------------------------- - -import time - -class Timer(object): - """A simple timer.""" - def __init__(self): - self.total_time = 0. - self.calls = 0 - self.start_time = 0. - self.diff = 0. - self.average_time = 0. - self.warm_up = 0 - - def tic(self): - # using time.time instead of time.clock because time time.clock - # does not normalize for multithreading - self.start_time = time.time() - - def toc(self, average=True): - self.diff = time.time() - self.start_time - if self.warm_up < 10: - self.warm_up += 1 - return self.diff - else: - self.total_time += self.diff - self.calls += 1 - self.average_time = self.total_time / self.calls - - if average: - return self.average_time - else: - return self.diff +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ + +# -------------------------------------------------------- +# Fast R-CNN +# Copyright (c) 2015 Microsoft +# Licensed under The MIT License [see LICENSE for details] +# Written by Ross Girshick +# -------------------------------------------------------- + +import time + +class Timer(object): + """A simple timer.""" + def __init__(self): + self.total_time = 0. + self.calls = 0 + self.start_time = 0. + self.diff = 0. + self.average_time = 0. + self.warm_up = 0 + + def tic(self): + # using time.time instead of time.clock because time time.clock + # does not normalize for multithreading + self.start_time = time.time() + + def toc(self, average=True): + self.diff = time.time() - self.start_time + if self.warm_up < 10: + self.warm_up += 1 + return self.diff + else: + self.total_time += self.diff + self.calls += 1 + self.average_time = self.total_time / self.calls + + if average: + return self.average_time + else: + return self.diff diff --git a/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/modelzoo_level.txt b/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/modelzoo_level.txt +++ b/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/requirements.txt b/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/requirements.txt index 5655d0ed67..0865b11eec 100644 --- a/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/requirements.txt +++ b/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet/requirements.txt @@ -1,14 +1,14 @@ -torch==1.5.0+ascend.post3.20210930 -apex==0.1+ascend.20210930 -torchvision==0.2.2.post3 -cycler==0.10.0 -Cpython==0.29.24 -matplotlib==3.4.3 -numpy==1.21.1 -opencv-python==4.5.3.56 -Pillow==8.2.0 -pycocotools==2.0.2 -future==0.18.2 -scikit-learn==1.0 -scipy==1.7.1 +torch==1.5.0+ascend.post3.20210930 +apex==0.1+ascend.20210930 +torchvision==0.2.2.post3 +cycler==0.10.0 +Cpython==0.29.24 +matplotlib==3.4.3 +numpy==1.21.1 +opencv-python==4.5.3.56 +Pillow==8.2.0 +pycocotools==2.0.2 +future==0.18.2 +scikit-learn==1.0 +scipy==1.7.1 tqdm==4.62.3 \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/HigherHRNet/README.md b/PyTorch/contrib/cv/pose_estimation/HigherHRNet/README.md index 5faa89a351..4d9e9f6805 100644 --- a/PyTorch/contrib/cv/pose_estimation/HigherHRNet/README.md +++ b/PyTorch/contrib/cv/pose_estimation/HigherHRNet/README.md @@ -1,93 +1,93 @@ -# HigherHRNet - -This implements training of HigherHRNet on the COCO dataset, mainly modified from GitHub - HRNet/HigherHRNet-Human-Pose-Estimation - -1. Install package dependencies. Make sure the python environment >=3.7 - - ```bash - pip install -r requirements.txt - ``` -2. Install COCOAPI: - -``` -# COCOAPI=/path/to/clone/cocoapi - -git clone https://github.com/cocodataset/cocoapi.git $COCOAPI -cd $COCOAPI/PythonAPI - -# Install into global site-packages - -make install - -# Alternatively, if you do not have permissions or prefer - -# not to install the COCO API into global site-packages - -python3 setup.py install --user -Note that instructions like # COCOAPI=/path/to/install/cocoapi indicate that you should pick a path where you'd like to have the software cloned and then set an environment variable (COCOAPI in this case) accordingly. -``` - - - -3. Download pretrained models from the releases of HigherHRNet-Human-Pose-Estimation to the specified directory - - ```txt - ${POSE_ROOT} - `-- models - `-- pytorch - |-- imagenet - | `-- hrnet_w32-36af842e.pth - `-- pose_coco - `-- pose_higher_hrnet_w32_512.pth - ``` - -### Data Preparation - -Please download or link COCO to ${POSE_ROOT}/data/coco/, and make them look like this: - -```txt -${POSE_ROOT}/data/coco/ -|-- annotations -| |-- person_keypoints_train2017.json -| `-- person_keypoints_val2017.json -|-- person_detection_results -| |-- COCO_val2017_detections_AP_H_56_person.json -| `-- COCO_test-dev2017_detections_AP_H_609_person.json -`-- images - |-- train2017 - | |-- 000000000009.jpg - | |-- ... - `-- val2017 - |-- 000000000139.jpg - |-- ... -``` -## Training - -To train a model, run `main.py` with the desired model architecture and the path to the ImageNet dataset: - -```bash -# training 1p accuracy -bash ./test/train_full_1p.sh --data_path=real_data_path - -# training 1p performance -bash ./test/train_performance_1p.sh --data_path=real_data_path - -# training 8p accuracy -bash ./test/train_full_8p.sh --data_path=real_data_path - -# training 8p performance -bash ./test/train_performance_8p.sh --data_path=real_data_path - -#test 8p accuracy -bash test/train_eval_8p.sh --data_path=real_data_path --pth_path=real_pre_train_model_path - -``` - -## HigherHRNet training result - -| 名称 | 精度 | 性能 | -| :----: | :--: | :------: | -| NPU-8p | 66.9 | 2.2s/step | -| GPU-8p | 67.1 | 1.2s/step | -| NPU-1p | | 1.1s/step | +# HigherHRNet + +This implements training of HigherHRNet on the COCO dataset, mainly modified from GitHub - HRNet/HigherHRNet-Human-Pose-Estimation + +1. Install package dependencies. Make sure the python environment >=3.7 + + ```bash + pip install -r requirements.txt + ``` +2. Install COCOAPI: + +``` +# COCOAPI=/path/to/clone/cocoapi + +git clone https://github.com/cocodataset/cocoapi.git $COCOAPI +cd $COCOAPI/PythonAPI + +# Install into global site-packages + +make install + +# Alternatively, if you do not have permissions or prefer + +# not to install the COCO API into global site-packages + +python3 setup.py install --user +Note that instructions like # COCOAPI=/path/to/install/cocoapi indicate that you should pick a path where you'd like to have the software cloned and then set an environment variable (COCOAPI in this case) accordingly. +``` + + + +3. Download pretrained models from the releases of HigherHRNet-Human-Pose-Estimation to the specified directory + + ```txt + ${POSE_ROOT} + `-- models + `-- pytorch + |-- imagenet + | `-- hrnet_w32-36af842e.pth + `-- pose_coco + `-- pose_higher_hrnet_w32_512.pth + ``` + +### Data Preparation + +Please download or link COCO to ${POSE_ROOT}/data/coco/, and make them look like this: + +```txt +${POSE_ROOT}/data/coco/ +|-- annotations +| |-- person_keypoints_train2017.json +| `-- person_keypoints_val2017.json +|-- person_detection_results +| |-- COCO_val2017_detections_AP_H_56_person.json +| `-- COCO_test-dev2017_detections_AP_H_609_person.json +`-- images + |-- train2017 + | |-- 000000000009.jpg + | |-- ... + `-- val2017 + |-- 000000000139.jpg + |-- ... +``` +## Training + +To train a model, run `main.py` with the desired model architecture and the path to the ImageNet dataset: + +```bash +# training 1p accuracy +bash ./test/train_full_1p.sh --data_path=real_data_path + +# training 1p performance +bash ./test/train_performance_1p.sh --data_path=real_data_path + +# training 8p accuracy +bash ./test/train_full_8p.sh --data_path=real_data_path + +# training 8p performance +bash ./test/train_performance_8p.sh --data_path=real_data_path + +#test 8p accuracy +bash test/train_eval_8p.sh --data_path=real_data_path --pth_path=real_pre_train_model_path + +``` + +## HigherHRNet training result + +| 名称 | 精度 | 性能 | +| :----: | :--: | :------: | +| NPU-8p | 66.9 | 2.2s/step | +| GPU-8p | 67.1 | 1.2s/step | +| NPU-1p | | 1.1s/step | | GPU-1p | | 0.7s/step| \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/HigherHRNet/modelzoo_level.txt b/PyTorch/contrib/cv/pose_estimation/HigherHRNet/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/pose_estimation/HigherHRNet/modelzoo_level.txt +++ b/PyTorch/contrib/cv/pose_estimation/HigherHRNet/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/HigherHRNet/requirements.txt b/PyTorch/contrib/cv/pose_estimation/HigherHRNet/requirements.txt index 720188a90e..03bc1448f3 100644 --- a/PyTorch/contrib/cv/pose_estimation/HigherHRNet/requirements.txt +++ b/PyTorch/contrib/cv/pose_estimation/HigherHRNet/requirements.txt @@ -1,13 +1,13 @@ -EasyDict==1.7 -opencv-python -Cython -scipy -pandas -pyyaml -json_tricks -scikit-image -tensorboardX -yacs -cffi -munkres +EasyDict==1.7 +opencv-python +Cython +scipy +pandas +pyyaml +json_tricks +scikit-image +tensorboardX +yacs +cffi +munkres tqdm \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/data/valid.csv b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/data/valid.csv new file mode 100644 index 0000000000..5690f134ba --- /dev/null +++ b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/data/valid.csv @@ -0,0 +1,2958 @@ +005808361.jpg,966,410.777,5.89811,5.89811 +052475643.jpg,316,246.428,2.20229,2.20229 +051423444.jpg,1030,443.088,3.92404,3.92404 +004645041.jpg,809,451.733,4.0611,4.0611 +060754485.jpg,698,454.622,4.21849,4.21849 +080839735.jpg,765,457.147,5.09559,5.09559 +086310343.jpg,733,519.282,6.27352,6.27352 +062329813.jpg,624,352.601,3.80007,3.80007 +072960618.jpg,277,313.422,2.53513,2.53513 +047221493.jpg,744,225.378,2.69817,2.69817 +071324479.jpg,629,192.845,2.65377,2.65377 +076078505.jpg,57,599.73,6.14414,6.14414 +049379560.jpg,962,733.564,8.79701,8.79701 +041038292.jpg,875,546.817,4.56808,4.56808 +080812038.jpg,407,311.057,6.25477,6.25477 +031800347.jpg,696,217.282,2.94015,2.94015 +051074730.jpg,371,317.56,2.7133,2.7133 +033761517.jpg,83,509.515,4.62623,4.62623 +033761517.jpg,526,783.269,6.52243,6.52243 +051879062.jpg,1168,429.973,4.41439,4.41439 +064517279.jpg,475,212.558,2.29652,2.29652 +038673535.jpg,446,255.775,2.39794,2.39794 +069189520.jpg,392,285.329,4.27739,4.27739 +023724909.jpg,289,276.079,3.42329,3.42329 +036771580.jpg,221,500.021,3.58509,3.58509 +079481130.jpg,488,226.758,1.8132,1.8132 +019524299.jpg,695,328.883,5.15695,5.15695 +072245212.jpg,409,439.263,4.0219,4.0219 +028077236.jpg,354,453.981,4.91506,4.91506 +028077236.jpg,1047,289.151,3.01257,3.01257 +099005385.jpg,246,253.497,4.04144,4.04144 +070248408.jpg,1082,704.995,8.66626,8.66626 +080936116.jpg,987,470.247,1.1039,1.1039 +086707232.jpg,860,382.957,0.829759,0.829759 +070196688.jpg,457,315.381,2.28178,2.28178 +051630035.jpg,634,390.458,2.95481,2.95481 +096264841.jpg,672,405.565,4.38041,4.38041 +040895294.jpg,249,316.704,2.89201,2.89201 +017329432.jpg,404,280.971,4.08088,4.08088 +001439349.jpg,616,502.925,5.41041,5.41041 +037461261.jpg,745,522.317,1.44312,1.44312 +085648984.jpg,124,373.757,2.31311,2.31311 +016293443.jpg,1200,467.76,3.48,3.48 +068300677.jpg,1542,627.568,4.8807,4.8807 +028203457.jpg,571,346.372,3.94771,3.94771 +070624223.jpg,277,324.666,2.30552,2.30552 +090635439.jpg,620,584.937,3.16141,3.16141 +086859913.jpg,365,348.059,2.75494,2.75494 +069574869.jpg,841,374.117,4.25979,4.25979 +015041689.jpg,1124,628.819,1.48492,1.48492 +005637550.jpg,385,313.59,3.88254,3.88254 +060617463.jpg,863,447.069,2.08904,2.08904 +056093797.jpg,219,265.2,1.93331,1.93331 +021296416.jpg,686,350.904,5.742,5.742 +051398949.jpg,416,342.727,4.47724,4.47724 +078365301.jpg,355,385.888,6.15731,6.15731 +025824439.jpg,221,249.162,3.01347,3.01347 +006107796.jpg,242,300.32,5.27668,5.27668 +037047210.jpg,80,290.793,2.39944,2.39944 +089520684.jpg,457,443.539,4.79493,4.79493 +059359245.jpg,898,529.823,5.73526,5.73526 +008692029.jpg,151,337.439,3.45326,3.45326 +053710654.jpg,801,347.16,2.59669,2.59669 +089676542.jpg,1117,600.736,12.1446,12.1446 +024240973.jpg,390,311.725,2.06041,2.06041 +061062004.jpg,515,463.934,1.99449,1.99449 +053258943.jpg,540,307.459,2.03823,2.03823 +005182354.jpg,745,395.948,3.24569,3.24569 +059563874.jpg,1027,833.93,4.32749,4.32749 +041184091.jpg,626,778.12,12.1767,12.1767 +079526731.jpg,818,478.529,5.62738,5.62738 +079526731.jpg,682,384.276,2.85631,2.85631 +078859721.jpg,624,501.682,1.64015,1.64015 +078859721.jpg,1057,397.675,1.80624,1.80624 +076245869.jpg,748,485.542,3.79521,3.79521 +039728729.jpg,250,292.488,3.04067,3.04067 +079729537.jpg,427,390.219,5.6849,5.6849 +014991743.jpg,467,216.614,3.13453,3.13453 +001811018.jpg,255,343.176,5.43133,5.43133 +093211828.jpg,835,372.808,2.48403,2.48403 +069665082.jpg,668,224.973,2.66443,2.66443 +080285345.jpg,157,121.53,1.29418,1.29418 +000463202.jpg,757,170.598,1.54987,1.54987 +033349917.jpg,195,270.82,2.40169,2.40169 +039816869.jpg,1157,833.208,8.93401,8.93401 +014085702.jpg,306,134.438,2.2865,2.2865 +074996047.jpg,383,264.696,2.80801,2.80801 +047206695.jpg,1503,624.625,8.05208,8.05208 +094611546.jpg,693,370.381,2.28178,2.28178 +022197216.jpg,1337,719.437,8.36978,8.36978 +085569647.jpg,980,595.111,4.84256,4.84256 +008550853.jpg,1005,347.392,2.94932,2.94932 +059029494.jpg,276,256.832,1.40264,1.40264 +048743120.jpg,592,238.289,2.27407,2.27407 +054163421.jpg,339,315.896,1.90801,1.90801 +057651648.jpg,561,442.54,3.21168,3.21168 +027405522.jpg,408,347.839,1.98658,1.98658 +013688563.jpg,671,544.763,6.48028,6.48028 +071904591.jpg,394,421.513,3.12605,3.12605 +056640464.jpg,375,416.536,3.46133,3.46133 +093682974.jpg,120,156.914,1.65952,1.65952 +021494038.jpg,353,140.424,1.86869,1.86869 +059507793.jpg,1560,490.745,3.14543,3.14543 +072818876.jpg,1550,490.335,3.5279,3.5279 +059023067.jpg,582,343.309,2.94245,2.94245 +091731358.jpg,667,410.453,1.8711,1.8711 +031910047.jpg,347,230.522,2.46018,2.46018 +023000884.jpg,337,272.803,2.90024,2.90024 +012056689.jpg,286,223.8,3.15,3.15 +087367711.jpg,366,296.839,2.73659,2.73659 +096910263.jpg,211,255.4,3.20003,3.20003 +069602062.jpg,405,345.836,3.48633,3.48633 +025975378.jpg,413,336.068,4.42233,4.42233 +048058658.jpg,400,297.017,3.16809,3.16809 +059240778.jpg,357,289.398,3.69986,3.69986 +083701333.jpg,96,534.843,3.15357,3.15357 +083701333.jpg,1318,582.036,4.41968,4.41968 +069747146.jpg,262,453.038,2.50316,2.50316 +068014077.jpg,289,216.142,1.76185,1.76185 +015860511.jpg,513,198.767,1.81395,1.81395 +028703813.jpg,402,368.517,5.20973,5.20973 +076102790.jpg,689,385.576,4.46466,4.46466 +099712450.jpg,672,433.951,3.91256,3.91256 +003252618.jpg,508,492.247,0.93723,0.93723 +048152235.jpg,739,494.264,1.1887,1.1887 +048152235.jpg,960,450.713,1.47611,1.47611 +048152235.jpg,644,315.957,0.829759,0.829759 +011730819.jpg,529,429.773,1.2311,1.2311 +068556529.jpg,483,409.497,1.04139,1.04139 +068556529.jpg,776,398.195,0.849588,0.849588 +098666259.jpg,610,267.022,1.16846,1.16846 +098666259.jpg,169,393.53,1.21083,1.21083 +014249554.jpg,167,428.443,2.03691,2.03691 +051771164.jpg,560,330.799,1.23329,1.23329 +051771164.jpg,968,422.713,1.47611,1.47611 +035062693.jpg,858,353.913,1.32612,1.32612 +056754085.jpg,699,402.551,3.12922,3.12922 +063643025.jpg,426,471.778,5.14813,5.14813 +081482511.jpg,348,792.535,4.54458,4.54458 +055536355.jpg,595,478.899,1.74155,1.74155 +022845474.jpg,799,454.844,1.57035,1.57035 +099633392.jpg,423,600.497,2.29142,2.29142 +097479316.jpg,556,583.987,1.83221,1.83221 +003065250.jpg,131,357.289,1.52411,1.52411 +025768289.jpg,759,386.353,1.61276,1.61276 +086827251.jpg,897,437.061,5.08843,5.08843 +018097695.jpg,909,296.97,4.33082,4.33082 +051481735.jpg,570,253.25,2.18753,2.18753 +086827128.jpg,360,262.882,6.90684,6.90684 +051559603.jpg,605,321.932,5.9943,5.9943 +030792994.jpg,407,615.828,3.31904,3.31904 +086814225.jpg,233,244.785,1.98204,1.98204 +094461422.jpg,516,372.273,4.27276,4.27276 +065123298.jpg,579,314.635,3.55294,3.55294 +079781365.jpg,370,409.848,3.98729,3.98729 +012020906.jpg,380,502.545,2.96211,2.96211 +039617269.jpg,441,418.144,2.92865,2.92865 +037978578.jpg,698,329.73,2.22749,2.22749 +053360255.jpg,365,284.758,1.8132,1.8132 +081298574.jpg,366,273.663,4.22191,4.22191 +018143835.jpg,114,407.699,2.55828,2.55828 +070904626.jpg,230,379.218,4.26813,4.26813 +088420646.jpg,482,231.142,1.76185,1.76185 +022807977.jpg,494,259.771,1.8976,1.8976 +083986130.jpg,336,178.229,1.01912,1.01912 +062385932.jpg,365,216.643,3.47029,3.47029 +058660846.jpg,449,878.944,7.57867,7.57867 +023371208.jpg,269,298.436,3.70303,3.70303 +099413936.jpg,449,279.889,1.82409,1.82409 +053995713.jpg,599,542.221,2.9351,2.9351 +053995713.jpg,242,574.278,4.10649,4.10649 +082606763.jpg,991,612.926,4.16049,4.16049 +070874470.jpg,1754,595.108,2.75902,2.75902 +003616038.jpg,979,596.537,4.04477,4.04477 +099215801.jpg,174,230.705,3.39212,3.39212 +086805669.jpg,675,492.883,6.24029,6.24029 +086805669.jpg,924,420.818,4.48487,4.48487 +080592540.jpg,932,482.497,5.04143,5.04143 +097561020.jpg,119,173.485,2.04044,2.04044 +082248056.jpg,422,287.134,1.59452,1.59452 +092275719.jpg,546,548.53,1.29418,1.29418 +021603818.jpg,227,382.615,4.63459,4.63459 +065020109.jpg,169,252.975,3.33122,3.33122 +099669685.jpg,527,219.947,1.57892,1.57892 +046147746.jpg,642,464.653,6.05443,6.05443 +051840802.jpg,656,377.269,6.52243,6.52243 +004167290.jpg,519,476.218,6.68482,6.68482 +066030272.jpg,1258,671.051,10.4209,10.4209 +065647861.jpg,345,323.349,4.02906,4.02906 +012150138.jpg,679,718.748,3.47897,3.47897 +016481482.jpg,242,296.568,2.13063,2.13063 +046155747.jpg,474,314.757,2.31311,2.31311 +000933162.jpg,551,605.533,2.4611,2.4611 +048097289.jpg,299,593.932,5.32768,5.32768 +051726906.jpg,392,244.875,3.5729,3.5729 +032819275.jpg,474,380.494,4.62448,4.62448 +078565162.jpg,864,478.365,6.2804,6.2804 +018610142.jpg,1417,712.422,7.70182,7.70182 +072950823.jpg,449,505.928,6.57732,6.57732 +028218707.jpg,604,557.568,5.96397,5.96397 +044973984.jpg,600,296.988,3.24902,3.24902 +041109560.jpg,305,274.693,2.05779,2.05779 +093682246.jpg,334,238.675,1.97294,1.97294 +041879332.jpg,1150,531.769,11.0641,11.0641 +025653006.jpg,1265,857.252,10.9377,10.9377 +097200533.jpg,258,285.371,1.7809,1.7809 +052339091.jpg,318,285.826,1.48553,1.48553 +011476887.jpg,360,289.865,1.57207,1.57207 +048469629.jpg,291,325.596,2.21635,2.21635 +080360354.jpg,921,414.348,2.77901,2.77901 +098411032.jpg,603,299.542,3.79521,3.79521 +042748969.jpg,301,291.778,3.56483,3.56483 +042748969.jpg,833,322.572,3.71431,3.71431 +055975568.jpg,685,473.287,4.60722,4.60722 +055975568.jpg,832,412.757,3.72979,3.72979 +082824925.jpg,357,328.09,4.09079,4.09079 +045035098.jpg,336,350.003,4.25027,4.25027 +074882634.jpg,361,318.93,4.4942,4.4942 +084144755.jpg,262,242.758,3.3965,3.3965 +064288191.jpg,889,559.203,2.10021,2.10021 +078844734.jpg,941,484.538,4.87821,4.87821 +090289500.jpg,915,909.494,4.87452,4.87452 +085226387.jpg,654,737.082,8.75681,8.75681 +085226387.jpg,1754,735.828,2.56899,2.56899 +007896916.jpg,401,624.788,2.23233,2.23233 +007896916.jpg,1679,612.61,2.30083,2.30083 +023951017.jpg,1766,560.471,2.62256,2.62256 +011493300.jpg,1040,583.857,3.23805,3.23805 +082928680.jpg,248,482.593,1.71604,1.71604 +087897890.jpg,511,372.407,1.86724,1.86724 +087897890.jpg,814,473.395,4.11624,4.11624 +043042741.jpg,543,417.534,1.79449,1.79449 +031694659.jpg,226,389.626,1.55219,1.55219 +031694659.jpg,979,402.973,1.74774,1.74774 +043459596.jpg,889,471.967,2.08062,2.08062 +089252329.jpg,761,317.282,1.2735,1.2735 +089252329.jpg,882,310.134,1.59452,1.59452 +089252329.jpg,1002,323.333,1.94445,1.94445 +044338001.jpg,153,430.578,4.63148,4.63148 +071403264.jpg,1172,694.314,3.77619,3.77619 +082119828.jpg,931,429.006,2.33384,2.33384 +000156511.jpg,953,434.01,2.16749,2.16749 +005952470.jpg,627,451.291,2.02428,2.02428 +036905302.jpg,448,210.296,1.60801,1.60801 +041894779.jpg,306,216.16,1.84665,1.84665 +041894779.jpg,425,173.471,1.78922,1.78922 +007100766.jpg,244,243.551,2.37929,2.37929 +094172571.jpg,780,325.975,4.24794,4.24794 +087369859.jpg,317,495.762,6.48014,6.48014 +072397306.jpg,246,399.026,4.33549,4.33549 +090245331.jpg,461,489.838,5.65315,5.65315 +053396747.jpg,117,350.811,2.56759,2.56759 +085756234.jpg,434,292.342,2.77852,2.77852 +091663524.jpg,214,150.183,1.84859,1.84859 +058219875.jpg,372,263.112,1.67598,1.67598 +016686020.jpg,41,126.922,2.16021,2.16021 +043052934.jpg,343,174.292,1.19097,1.19097 +002544776.jpg,420,328.498,2.70815,2.70815 +007171189.jpg,332,405.494,1.1245,1.1245 +003095579.jpg,838,379.823,3.81861,3.81861 +075621361.jpg,948,504.168,6.59734,6.59734 +099384839.jpg,284,256.146,2.51213,2.51213 +062066048.jpg,301,264.04,3.50333,3.50333 +039513774.jpg,221,215.678,3.13984,3.13984 +098098738.jpg,513,471.933,1.91107,1.91107 +048340744.jpg,349,502.373,1.61443,1.61443 +076179819.jpg,627,370.647,2.97061,2.97061 +038654051.jpg,234,431.275,5.02292,5.02292 +038654051.jpg,971,303.423,4.20193,4.20193 +040758421.jpg,513,294.913,2.07608,2.07608 +082751892.jpg,468,395.385,3.28209,3.28209 +062659251.jpg,576,441.419,4.86823,4.86823 +006600984.jpg,368,478.718,3.47651,3.47651 +007231648.jpg,393,352.001,3.83343,3.83343 +005022601.jpg,834,481.603,5.80025,5.80025 +092922805.jpg,449,310.071,2.83924,2.83924 +071395263.jpg,435,352.075,3.75623,3.75623 +062955770.jpg,550,271.233,3.85275,3.85275 +051112914.jpg,651,529.409,6.28405,6.28405 +006268962.jpg,749,411.921,5.91008,5.91008 +036023392.jpg,1237,573.651,12.1376,12.1376 +090994314.jpg,422,371.813,4.06774,4.06774 +096407842.jpg,198,294.35,4.3625,4.3625 +076756763.jpg,405,298.148,4.42904,4.42904 +082217989.jpg,500,299.92,4.57665,4.57665 +073859746.jpg,349,246.244,4.43696,4.43696 +059513167.jpg,317,254.657,1.88809,1.88809 +012555021.jpg,466,449.826,4.90213,4.90213 +012020723.jpg,478,223.757,2.31311,2.31311 +029330861.jpg,1367,527.117,4.25979,4.25979 +029980053.jpg,415,368.473,2.53939,2.53939 +002359496.jpg,515,212.313,1.77609,1.77609 +002359496.jpg,230,267.322,2.61017,2.61017 +089856060.jpg,343,279.407,3.53389,3.53389 +089856060.jpg,91,289.97,5.24751,5.24751 +078037612.jpg,359,251.992,3.66602,3.66602 +030291573.jpg,303,246.617,2.71811,2.71811 +006569486.jpg,342,251.037,2.58645,2.58645 +024660363.jpg,216,294.813,3.23444,3.23444 +024660363.jpg,439,198.103,1.42524,1.42524 +048407707.jpg,63,261.302,2.44182,2.44182 +057829840.jpg,652,404.206,5.18384,5.18384 +000784159.jpg,911,493.325,5.86038,5.86038 +004997903.jpg,350,782.786,9.31552,9.31552 +079314287.jpg,832,756.223,10.4353,10.4353 +096062698.jpg,194,416.54,3.3783,3.3783 +062234326.jpg,351,199.229,1.01912,1.01912 +090789879.jpg,1247,723.798,6.8998,6.8998 +097730791.jpg,333,261.065,2.83877,2.83877 +063436369.jpg,342,247.039,1.3366,1.3366 +084804209.jpg,698,392.837,2.73642,2.73642 +084804209.jpg,433,277.209,1.43405,1.43405 +011850262.jpg,960,246.785,1.98204,1.98204 +075426497.jpg,441,309.3,1.35831,1.35831 +075426497.jpg,1190,285.511,2.37588,2.37588 +051669839.jpg,496,322.722,2.31019,2.31019 +075877625.jpg,862,359.967,2.49722,2.49722 +035305039.jpg,1302,521.242,3.4368,3.4368 +089255823.jpg,234,471.112,4.00935,4.00935 +083582593.jpg,393,291.051,1.92094,1.92094 +083582593.jpg,656,313.894,2.99114,2.99114 +077112282.jpg,853,591.815,6.23459,6.23459 +087588308.jpg,754,562.479,4.12323,4.12323 +052251018.jpg,133,478.497,2.29142,2.29142 +005463442.jpg,1037,382.182,9.76513,9.76513 +090194020.jpg,970,534.088,5.17402,5.17402 +004242230.jpg,270,248.208,2.18403,2.18403 +085653722.jpg,218,256.301,3.35839,3.35839 +043766133.jpg,714,455.843,6.57027,6.57027 +028763273.jpg,427,312.656,4.55467,4.55467 +043276688.jpg,544,339.771,4.23096,4.23096 +043276688.jpg,226,412.213,5.60109,5.60109 +005658566.jpg,437,303.837,2.48638,2.48638 +094444858.jpg,439,273.107,2.5089,2.5089 +064173440.jpg,235,259.952,3.16269,3.16269 +065675606.jpg,479,305.829,2.65241,2.65241 +025089305.jpg,283,274.19,2.76586,2.76586 +094673373.jpg,339,357.117,4.25979,4.25979 +045025425.jpg,458,526.912,3.07599,3.07599 +043358279.jpg,277,328.205,3.01705,3.01705 +001374555.jpg,486,548.822,6.15183,6.15183 +080509032.jpg,119,335.783,3.06529,3.06529 +037111294.jpg,608,338.289,3.02405,3.02405 +082474324.jpg,1281,740.469,8.45574,8.45574 +011043186.jpg,837,474.573,3.54775,3.54775 +087631943.jpg,810,844.84,6.23668,6.23668 +039273074.jpg,994,887.423,5.95196,5.95196 +055337119.jpg,945,776.062,7.33848,7.33848 +023420337.jpg,447,305.696,2.97469,2.97469 +054090500.jpg,348,328.004,2.75036,2.75036 +060563789.jpg,367,229.175,2.68127,2.68127 +000531348.jpg,519,363.887,4.65725,4.65725 +089040952.jpg,907,485.613,5.21776,5.21776 +038279876.jpg,562,330.8,1.65,1.65 +026406198.jpg,752,464.656,3.80468,3.80468 +032451180.jpg,865,588.481,6.54007,6.54007 +057670240.jpg,271,286.669,3.22245,3.22245 +004035083.jpg,435,428.372,3.11437,3.11437 +041119152.jpg,799,380.132,4.76103,4.76103 +075673017.jpg,437,335.77,4.0642,4.0642 +064950893.jpg,550,887.294,8.69115,8.69115 +017935601.jpg,985,684.339,12.5283,12.5283 +060969743.jpg,627,442.726,6.14385,6.14385 +060969743.jpg,394,338.337,3.77809,3.77809 +053593508.jpg,380,348.743,2.47859,2.47859 +040188720.jpg,265,329.979,2.74824,2.74824 +057260723.jpg,160,260.208,2.18403,2.18403 +021079310.jpg,971,365.878,1.65653,1.65653 +046910721.jpg,366,450.974,3.91451,3.91451 +096776147.jpg,447,477.777,3.23138,3.23138 +096776147.jpg,816,626.929,4.4941,4.4941 +043974049.jpg,720,585.768,2.73066,2.73066 +027836848.jpg,821,714.082,3.6735,3.6735 +079829320.jpg,1317,396.465,2.78871,2.78871 +029938337.jpg,1696,677.4,6.45,6.45 +029938337.jpg,162,798.742,6.89517,6.89517 +067399421.jpg,482,468.711,6.22592,6.22592 +006256484.jpg,874,790.248,8.52069,8.52069 +049256907.jpg,368,189.192,2.01604,2.01604 +017549163.jpg,417,204.954,3.0795,3.0795 +037217326.jpg,353,278.986,3.41552,3.41552 +079592639.jpg,648,367.462,4.03854,4.03854 +024966895.jpg,703,350.835,4.98623,4.98623 +045832359.jpg,216,225.987,1.33222,1.33222 +023814665.jpg,1013,491.836,6.40301,6.40301 +005024301.jpg,295,520.191,6.01588,6.01588 +055115996.jpg,482,482.529,4.46073,4.46073 +077277142.jpg,327,229.955,2.4129,2.4129 +092914472.jpg,130,329.459,3.20495,3.20495 +003010387.jpg,110,331.869,3.82238,3.82238 +061146361.jpg,242,226.489,2.12408,2.12408 +094716146.jpg,350,291.664,1.97203,1.97203 +028161604.jpg,382,267.818,1.81816,1.81816 +092863056.jpg,1092,573.333,3.77774,3.77774 +006180846.jpg,1792,690.626,1.55219,1.55219 +050151796.jpg,686,629.453,1.62111,1.62111 +047096025.jpg,609,398.04,1.83663,1.83663 +069105581.jpg,733,566.321,7.86006,7.86006 +027163318.jpg,904,436.308,8.27571,8.27571 +016440553.jpg,541,420.896,4.158,4.158 +010445452.jpg,580,419.494,3.79117,3.79117 +046398170.jpg,678,566.484,4.54032,4.54032 +098056823.jpg,265,306.193,3.3494,3.3494 +021469589.jpg,153,402.415,4.86796,4.86796 +005034953.jpg,298,313.97,1.74748,1.74748 +061397031.jpg,199,215.158,2.42981,2.42981 +030328589.jpg,577,212.314,1.02616,1.02616 +011635849.jpg,658,366.192,3.51602,3.51602 +061279584.jpg,748,387.035,3.66958,3.66958 +025533637.jpg,350,264.165,2.3471,2.3471 +067582293.jpg,473,268.696,2.05801,2.05801 +018177887.jpg,501,254.428,2.20229,2.20229 +050242729.jpg,260,428.567,4.21391,4.21391 +073148636.jpg,946,271.713,2.89278,2.89278 +095811801.jpg,1056,392.672,4.30602,4.30602 +048402057.jpg,1618,756.131,3.59425,3.59425 +040021228.jpg,638,412.96,2.32998,2.32998 +026592845.jpg,701,270.163,2.26356,2.26356 +089796465.jpg,886,406.046,2.9205,2.9205 +039289511.jpg,782,431.563,6.29693,6.29693 +002865243.jpg,557,504.673,6.22274,6.22274 +002865243.jpg,968,408.542,3.96182,3.96182 +001130254.jpg,645,300.208,2.93402,2.93402 +030643282.jpg,489,354.367,3.44726,3.44726 +054419866.jpg,534,247.806,0.9005,0.9005 +070943886.jpg,452,296.779,1.14826,1.14826 +015389990.jpg,430,451.237,3.51973,3.51973 +014924947.jpg,383,480.689,4.05744,4.05744 +036107473.jpg,365,238.248,3.93732,3.93732 +008122963.jpg,465,409.959,4.74655,4.74655 +067383890.jpg,397,354.082,3.09015,3.09015 +059424183.jpg,349,366.05,4.92082,4.92082 +076858133.jpg,504,347.34,3.695,3.695 +002785224.jpg,983,462.545,4.04544,4.04544 +054814520.jpg,882,507.312,4.02604,4.02604 +027195456.jpg,1016,396.642,3.38681,3.38681 +055657843.jpg,746,522.595,6.46624,6.46624 +077982088.jpg,310,375.521,5.12675,5.12675 +025448133.jpg,485,296.535,3.54457,3.54457 +001289747.jpg,348,362.264,3.43863,3.43863 +054029941.jpg,763,308.487,2.62393,2.62393 +056574495.jpg,824,300.854,2.48783,2.48783 +030574396.jpg,641,422.865,2.82207,2.82207 +049995899.jpg,836,474.723,1.56029,1.56029 +002568964.jpg,635,383.065,1.92211,1.92211 +028454139.jpg,956,318.496,2.95801,2.95801 +061710594.jpg,923,312.664,3.13869,3.13869 +084995933.jpg,428,309.579,2.29828,2.29828 +012554979.jpg,823,372.545,3.04541,3.04541 +023374079.jpg,535,522.974,3.91451,3.91451 +030777091.jpg,942,551.934,8.91116,8.91116 +018993614.jpg,1007,333.494,3.45782,3.45782 +006203676.jpg,692,373.446,4.53715,4.53715 +044203342.jpg,543,210.876,2.40637,2.40637 +081372334.jpg,500,243.586,1.63218,1.63218 +095456593.jpg,312,206.868,1.82236,1.82236 +090801855.jpg,992,566.141,3.17844,3.17844 +039631263.jpg,1184,738.547,3.96227,3.96227 +029632580.jpg,796,624.833,3.65274,3.65274 +075513362.jpg,453,577.752,5.56263,5.56263 +078346956.jpg,211,194.793,1.56605,1.56605 +095053282.jpg,1494,279.206,2.6005,2.6005 +028033475.jpg,858,580.913,8.65941,8.65941 +064395658.jpg,954,601.037,7.25312,7.25312 +079978336.jpg,639,387.45,2.9542,2.9542 +018483840.jpg,677,356.75,3.0625,3.0625 +008010573.jpg,310,243.696,1.72467,1.72467 +004558516.jpg,732,344.8,3.15,3.15 +094597089.jpg,697,440.081,3.84012,3.84012 +094898067.jpg,905,427.222,4.60185,4.60185 +031536374.jpg,217,337.968,3.24735,3.24735 +067754581.jpg,697,346.947,3.41223,3.41223 +007273495.jpg,651,451.304,1.69201,1.69201 +078242581.jpg,543,425.044,5.67032,5.67032 +013300980.jpg,887,465.327,5.4439,5.4439 +020831539.jpg,696,570.813,4.7344,4.7344 +035781125.jpg,586,391.904,3.49201,3.49201 +016145783.jpg,658,431.833,3.73605,3.73605 +057028694.jpg,707,485.146,4.42884,4.42884 +074227139.jpg,522,508.131,5.17759,5.17759 +059929929.jpg,949,532.854,3.57113,3.57113 +028818453.jpg,107,344.568,2.13063,2.13063 +099694942.jpg,435,451.035,4.5029,4.5029 +004922091.jpg,535,356.827,3.9856,3.9856 +022065106.jpg,223,328.217,5.26805,5.26805 +050005826.jpg,376,525.507,8.20888,8.20888 +075804042.jpg,628,462.457,3.95477,3.95477 +031694262.jpg,358,419.105,5.17541,5.17541 +051057041.jpg,521,379.551,3.12922,3.12922 +070504091.jpg,444,227.874,1.40616,1.40616 +038339714.jpg,798,478.37,5.53083,5.53083 +070938882.jpg,439,247.464,3.28866,3.28866 +088638036.jpg,986,480.442,4.45346,4.45346 +098273954.jpg,420,626.725,5.06041,5.06041 +072402919.jpg,1130,585.299,4.44162,4.44162 +072402919.jpg,111,531.784,2.48204,2.48204 +044418341.jpg,1526,543.36,8.19665,8.19665 +067558677.jpg,355,382.46,6.28835,6.28835 +086144569.jpg,177,529.094,6.42448,6.42448 +030781915.jpg,665,435.704,1.39201,1.39201 +024116521.jpg,951,383.096,1.00802,1.00802 +006818662.jpg,172,435.35,1.27914,1.27914 +006022694.jpg,785,416.962,2.08019,2.08019 +016428684.jpg,678,558.064,3.33864,3.33864 +078316143.jpg,960,351.559,2.62992,2.62992 +090942950.jpg,485,438.071,2.08926,2.08926 +028418430.jpg,870,262.104,1.09202,1.09202 +015577326.jpg,1246,425.248,3.02063,3.02063 +054704535.jpg,609,408.837,1.56978,1.56978 +035232705.jpg,731,409.882,2.07348,2.07348 +080826821.jpg,594,179.325,1.11041,1.11041 +029989759.jpg,782,455.96,2.32998,2.32998 +060094548.jpg,509,416.86,2.32166,2.32166 +088368397.jpg,291,764.079,7.33989,7.33989 +002534860.jpg,603,684.373,3.78107,3.78107 +031610131.jpg,985,697.624,2.38533,2.38533 +031610131.jpg,1328,585.065,1.92211,1.92211 +024080382.jpg,1303,667.992,5.91601,5.91601 +008975950.jpg,1003,409.005,1.08374,1.08374 +032783820.jpg,465,597.06,7.58834,7.58834 +095206245.jpg,404,552.33,5.44415,5.44415 +021603144.jpg,740,432.724,6.14363,6.14363 +097541037.jpg,674,474.38,4.61503,4.61503 +055974466.jpg,703,447.151,6.01259,6.01259 +025890427.jpg,673,370.165,2.3471,2.3471 +005282669.jpg,701,393.179,2.59825,2.59825 +053247091.jpg,544,343.535,4.62788,4.62788 +062337957.jpg,304,304.696,2.80801,2.80801 +093286769.jpg,641,237.427,2.95222,2.95222 +032788399.jpg,439,402.962,3.2468,3.2468 +097246139.jpg,1000,411.556,3.46302,3.46302 +023660978.jpg,95,307.201,1.18338,1.18338 +048349809.jpg,104,299.189,0.849058,0.849058 +010616035.jpg,416,210.757,2.31311,2.31311 +003646105.jpg,1185,548.23,9.10247,9.10247 +070086570.jpg,1325,630.512,6.12603,6.12603 +028520580.jpg,1286,583.152,6.09598,6.09598 +075777656.jpg,745,334.536,7.96131,7.96131 +054640707.jpg,1112,506.899,5.99159,5.99159 +055921813.jpg,852,475.262,5.27181,5.27181 +047415795.jpg,610,306.875,3.15628,3.15628 +098465448.jpg,412,329.252,1.77102,1.77102 +020353487.jpg,858,419.239,3.60325,3.60325 +076906113.jpg,928,276.051,2.75429,2.75429 +076906113.jpg,670,282.221,2.9351,2.9351 +056541594.jpg,747,358.979,2.74824,2.74824 +056541594.jpg,1110,355.469,1.95576,1.95576 +044582555.jpg,995,358.038,1.2532,1.2532 +088523888.jpg,726,714.341,3.52841,3.52841 +088523888.jpg,1098,728.482,3.95682,3.95682 +038797275.jpg,1403,394.251,3.68756,3.68756 +082956583.jpg,987,746.932,5.32768,5.32768 +082956583.jpg,1454,823.858,7.32148,7.32148 +093539449.jpg,1032,545.317,9.94309,9.94309 +036340393.jpg,345,462.567,6.13058,6.13058 +033217252.jpg,214,293.808,1.73404,1.73404 +070080842.jpg,778,579.931,4.74427,4.74427 +076531630.jpg,941,682.545,3.12879,3.12879 +071767616.jpg,713,858.273,9.68944,9.68944 +086953367.jpg,803,784.463,7.45529,7.45529 +018065754.jpg,540,701.514,5.7928,5.7928 +074236994.jpg,447,347.979,2.74824,2.74824 +029992940.jpg,825,538.309,5.69242,5.69242 +088434343.jpg,770,437.859,3.48827,3.48827 +070109759.jpg,123,331.972,4.08099,4.08099 +070109759.jpg,1131,439.771,5.06423,5.06423 +041073154.jpg,1157,372.503,4.62526,4.62526 +000735304.jpg,437,352.039,3.5866,3.5866 +041716428.jpg,1208,792.273,9.68944,9.68944 +029785940.jpg,254,351.054,3.42118,3.42118 +088742454.jpg,372,186.877,1.32306,1.32306 +061506975.jpg,594,441.451,4.62088,4.62088 +090959539.jpg,159,223.036,3.753,3.753 +040564526.jpg,516,499.848,3.98729,3.98729 +054378707.jpg,705,339.775,2.06456,2.06456 +051109382.jpg,298,818.573,2.96439,2.96439 +057119918.jpg,1801,670.665,4.63876,4.63876 +013945024.jpg,379,225.992,2.16603,2.16603 +058310576.jpg,343,326.07,2.9225,2.9225 +037204357.jpg,797,829.624,11.302,11.302 +039447939.jpg,1399,626.244,5.52033,5.52033 +089555574.jpg,520,253.065,2.83877,2.83877 +067687228.jpg,1067,643.686,7.39048,7.39048 +070403145.jpg,140,256.279,1.52322,1.52322 +024165892.jpg,1003,622.103,5.50858,5.50858 +006803731.jpg,1065,607.6,5.46667,5.46667 +060968191.jpg,671,493.831,6.98588,6.98588 +047443491.jpg,717,430.924,7.24368,7.24368 +033377660.jpg,778,517.446,8.37048,8.37048 +088900061.jpg,688,576.718,6.55986,6.55986 +086770210.jpg,422,279.545,1.87878,1.87878 +070762059.jpg,552,191.828,1.90234,1.90234 +077587725.jpg,414,222.949,2.82908,2.82908 +043501459.jpg,286,313.152,3.2627,3.2627 +079501154.jpg,306,223.818,1.81816,1.81816 +026004804.jpg,979,652.476,8.37301,8.37301 +099767226.jpg,841,325.652,2.88765,2.88765 +069668899.jpg,899,279.768,2.73066,2.73066 +065018717.jpg,824,347.951,2.99595,2.99595 +091181857.jpg,737,342.464,2.03868,2.03868 +043913066.jpg,784,354.303,3.69195,3.69195 +059768234.jpg,449,251.846,3.65385,3.65385 +044903776.jpg,439,333.039,3.66995,3.66995 +007696918.jpg,1286,839.589,11.2157,11.2157 +082050750.jpg,845,342.739,6.14495,6.14495 +032673889.jpg,353,275.65,2.22081,2.22081 +032673889.jpg,459,267.273,2.02272,2.02272 +073522852.jpg,319,228.682,1.64015,1.64015 +062834712.jpg,1522,455.552,3.046,3.046 +057875648.jpg,300,510.906,3.74219,3.74219 +083445825.jpg,120,553.387,4.6989,4.6989 +074752064.jpg,752,596.646,3.55383,3.55383 +064044727.jpg,605,409.027,2.50226,2.50226 +023538326.jpg,521,422.555,2.54629,2.54629 +023287915.jpg,495,403.417,3.61808,3.61808 +044797166.jpg,486,366.351,3.19595,3.19595 +025232274.jpg,612,419.237,3.51973,3.51973 +065656270.jpg,978,579.937,5.1614,5.1614 +094571511.jpg,858,561.267,5.77225,5.77225 +019718298.jpg,1512,641.75,3.14585,3.14585 +009761004.jpg,1466,554.284,2.77366,2.77366 +092373140.jpg,913,677.8,3.15,3.15 +092373140.jpg,251,642.566,3.13051,3.13051 +068267115.jpg,484,525.943,2.6619,2.6619 +045556678.jpg,267,586.178,3.34819,3.34819 +016361620.jpg,758,577.921,3.66012,3.66012 +097995545.jpg,720,692.687,4.80721,4.80721 +010702913.jpg,758,606.289,3.77404,3.77404 +043014273.jpg,561,535.992,2.91602,2.91602 +043776505.jpg,1503,521.2,2.85,2.85 +006728461.jpg,938,574.261,8.85508,8.85508 +026799727.jpg,1146,442.797,7.48306,7.48306 +082084901.jpg,976,396.845,3.32039,3.32039 +049674343.jpg,403,473.653,2.55441,2.55441 +073187274.jpg,904,506.713,1.47611,1.47611 +073187274.jpg,663,554.459,2.03823,2.03823 +043206729.jpg,619,367.257,2.35476,2.35476 +023647491.jpg,1268,732.93,5.24417,5.24417 +050604469.jpg,840,470.88,6.57336,6.57336 +050604469.jpg,191,481.598,1.54987,1.54987 +016251107.jpg,905,549.457,6.28806,6.28806 +058660174.jpg,1264,829.039,13.7533,13.7533 +044269370.jpg,758,442.6,3.3,3.3 +081314200.jpg,718,278.158,3.01317,3.01317 +062803046.jpg,482,633.966,1.9972,1.9972 +086701161.jpg,559,430.274,5.10617,5.10617 +099564518.jpg,633,381.965,4.08044,4.08044 +048018352.jpg,763,346.366,3.78048,3.78048 +010948237.jpg,431,456.475,4.20621,4.20621 +017478499.jpg,484,386.792,3.06602,3.06602 +089246909.jpg,936,642.335,3.5279,3.5279 +023899768.jpg,635,357.966,2.91386,2.91386 +096036677.jpg,575,482.782,4.31521,4.31521 +081782207.jpg,435,241.163,2.01358,2.01358 +035606730.jpg,395,249.696,2.05801,2.05801 +050613985.jpg,935,749.179,7.26496,7.26496 +093616304.jpg,828,660.402,5.95014,5.95014 +048648277.jpg,434,380.572,3.71431,3.71431 +020598818.jpg,1027,641.875,6.82294,6.82294 +070929613.jpg,1195,498.878,6.90652,6.90652 +092328602.jpg,798,378.681,3.22343,3.22343 +026974247.jpg,1010,434.227,2.35228,2.35228 +000391837.jpg,486,174.417,2.8681,2.8681 +006290748.jpg,864,460.921,4.91011,4.91011 +072333030.jpg,501,363.461,2.45506,2.45506 +015478603.jpg,460,233.545,4.04544,4.04544 +056159451.jpg,764,579.826,6.23553,6.23553 +097011689.jpg,1441,483.829,4.65242,4.65242 +013562662.jpg,1203,379.941,3.57844,3.57844 +035070979.jpg,674,571.112,4.75933,4.75933 +078068207.jpg,532,247.779,1.31488,1.31488 +017449849.jpg,470,184.28,1.35665,1.35665 +064421302.jpg,507,261.63,1.3025,1.3025 +089397306.jpg,448,230.484,1.29035,1.29035 +009484919.jpg,441,234.896,4.908,4.908 +085153717.jpg,413,324.155,2.92957,2.92957 +030306576.jpg,404,155.609,1.13406,1.13406 +096659077.jpg,1049,376.979,2.74824,2.74824 +067072733.jpg,381,257.349,4.27908,4.27908 +035942383.jpg,535,555.488,7.37402,7.37402 +053809466.jpg,301,245.466,1.70552,1.70552 +074475073.jpg,380,324.467,3.87221,3.87221 +064523764.jpg,630,348.199,3.34994,3.34994 +054055268.jpg,641,531.853,3.98774,3.98774 +094501709.jpg,436,346.602,3.88346,3.88346 +035677049.jpg,698,396.919,3.32662,3.32662 +082761026.jpg,782,279.54,3.21168,3.21168 +094756513.jpg,340,445.061,4.67172,4.67172 +088163535.jpg,291,277.961,3.66344,3.66344 +002103690.jpg,373,225.799,3.48323,3.48323 +084109617.jpg,854,569.715,5.89292,5.89292 +032029874.jpg,1155,649.103,8.34194,8.34194 +019484049.jpg,290,137.191,2.51589,2.51589 +055462049.jpg,702,695.237,3.60312,3.60312 +092619299.jpg,477,590.167,3.18057,3.18057 +044206621.jpg,303,384.284,2.44035,2.44035 +076100598.jpg,265,356.559,2.62992,2.62992 +024015160.jpg,676,386.865,2.23877,2.23877 +069701301.jpg,848,311.771,1.8976,1.8976 +056011598.jpg,430,331.929,2.57738,2.57738 +056011598.jpg,973,251.658,1.72154,1.72154 +038646256.jpg,512,284.217,2.01804,2.01804 +038646256.jpg,954,219.377,1.4481,1.4481 +056211088.jpg,1060,282.453,1.62111,1.62111 +037049144.jpg,971,310.016,4.91799,4.91799 +041030372.jpg,773,409.4,7.2,7.2 +019106214.jpg,740,571.569,8.38075,8.38075 +059639360.jpg,874,743.625,8.80207,8.80207 +072546817.jpg,492,352.322,4.27687,4.27687 +048507291.jpg,454,265.307,3.85894,3.85894 +041059870.jpg,606,346.703,5.64191,5.64191 +017833151.jpg,839,447.141,3.3451,3.3451 +032056759.jpg,171,533.65,2.22081,2.22081 +054348443.jpg,1073,466.371,2.78095,2.78095 +035552980.jpg,1758,454.776,6.23134,6.23134 +008933990.jpg,463,521.791,7.06588,7.06588 +029119645.jpg,799,470.961,3.99676,3.99676 +086184382.jpg,457,187.685,1.14039,1.14039 +000142834.jpg,510,361.511,4.29262,4.29262 +083686342.jpg,581,378.484,4.54032,4.54032 +028684665.jpg,824,389.718,4.80983,4.80983 +048190017.jpg,921,560.59,7.2158,7.2158 +055054530.jpg,657,309.653,6.05443,6.05443 +031691301.jpg,316,271.772,2.14767,2.14767 +031284463.jpg,545,388.424,4.8687,4.8687 +001282165.jpg,660,543.949,5.57911,5.57911 +051152564.jpg,178,496.015,2.00125,2.00125 +015652921.jpg,426,501.792,5.31601,5.31601 +015939488.jpg,532,590.035,3.75288,3.75288 +012115546.jpg,793,666.356,3.61298,3.61298 +059901104.jpg,1324,537.439,3.28661,3.28661 +093149039.jpg,965,797.22,4.60165,4.60165 +093149039.jpg,798,744.236,3.93629,3.93629 +095776666.jpg,308,537.363,2.03027,2.03027 +030336428.jpg,536,507.206,2.85047,2.85047 +039283908.jpg,451,486,1.5,1.5 +057807210.jpg,623,471.171,1.59762,1.59762 +046548697.jpg,458,434.173,6.01446,6.01446 +021027618.jpg,671,496.741,3.22845,3.22845 +076630407.jpg,617,379.116,4.59304,4.59304 +086715215.jpg,126,352.525,4.21038,4.21038 +053133995.jpg,607,684.932,5.32768,5.32768 +047081642.jpg,874,442.94,4.57832,4.57832 +054661494.jpg,688,560.467,6.37223,6.37223 +053355443.jpg,614,337.359,5.19659,5.19659 +035640474.jpg,271,291.839,3.40325,3.40325 +060380308.jpg,667,394.704,5.30864,5.30864 +004006909.jpg,610,419.005,5.33376,5.33376 +087825247.jpg,627,455.999,5.49991,5.49991 +048379690.jpg,680,510.312,7.02602,7.02602 +043243717.jpg,304,315.26,2.93832,2.93832 +041591365.jpg,1020,333.474,5.62282,5.62282 +010395938.jpg,535,494.021,4.75176,4.75176 +088683154.jpg,944,350.435,5.11955,5.11955 +037834758.jpg,827,197.68,2.88998,2.88998 +050144147.jpg,1515,625.496,4.458,4.458 +023362476.jpg,948,460.04,3.92003,3.92003 +059256818.jpg,250,579.429,3.95238,3.95238 +055989053.jpg,626,391.836,3.48633,3.48633 +017641191.jpg,586,563.167,5.34724,5.34724 +013551687.jpg,584,223.07,2.9225,2.9225 +045631682.jpg,1085,422.017,3.16809,3.16809 +097205347.jpg,769,383.773,2.81441,2.81441 +011001772.jpg,770,429.335,3.5279,3.5279 +090558214.jpg,435,246.689,1.97408,1.97408 +066854670.jpg,336,231.364,1.947,1.947 +000040154.jpg,563,285.556,3.46302,3.46302 +060601383.jpg,288,278.669,1.88905,1.88905 +057031251.jpg,401,231.675,1.80624,1.80624 +062254940.jpg,511,272.771,1.98091,1.98091 +062254940.jpg,335,256.662,2.05516,2.05516 +048746784.jpg,1034,255.166,4.76386,4.76386 +088775152.jpg,980,413.528,5.29396,5.29396 +004978100.jpg,234,370.291,3.10757,3.10757 +047078500.jpg,266,279.161,2.76342,2.76342 +098492911.jpg,272,270.739,3.31157,3.31157 +094577472.jpg,444,261.046,3.42053,3.42053 +060417394.jpg,469,360.573,6.38105,6.38105 +008922217.jpg,354,444.368,7.28067,7.28067 +056115021.jpg,238,363.304,3.19201,3.19201 +028625904.jpg,490,376.769,4.89745,4.89745 +053657819.jpg,1402,536.616,1.63466,1.63466 +027821719.jpg,712,521.123,2.01022,2.01022 +057240773.jpg,516,321.882,1.6568,1.6568 +059711662.jpg,866,470.04,1.83663,1.83663 +048525560.jpg,846,542.793,1.56605,1.56605 +018180847.jpg,751,432.928,1.99404,1.99404 +071411914.jpg,669,514.485,2.04044,2.04044 +030963181.jpg,1067,389.267,1.77229,1.77229 +046010263.jpg,831,353.276,2.85631,2.85631 +046010263.jpg,380,336.064,2.00529,2.00529 +019344723.jpg,736,315.009,1.58405,1.58405 +021070667.jpg,116,462.071,2.08926,2.08926 +012740807.jpg,875,524.381,2.28178,2.28178 +063926288.jpg,179,479.439,3.45326,3.45326 +007514295.jpg,1128,533.32,6.36,6.36 +070794783.jpg,473,508.277,2.10642,2.10642 +040470587.jpg,326,197.371,1.7809,1.7809 +025709609.jpg,779,471.784,1.14865,1.14865 +040364669.jpg,894,476.338,4.02816,4.02816 +080747794.jpg,955,633.327,5.02722,5.02722 +032694210.jpg,996,348.846,3.5705,3.5705 +060668932.jpg,379,444.418,2.11814,2.11814 +028524434.jpg,702,429.827,3.9856,3.9856 +023921109.jpg,128,459.465,2.78871,2.78871 +039368189.jpg,741,656.315,5.10961,5.10961 +006121666.jpg,766,548.429,3.95238,3.95238 +040892724.jpg,930,661.349,6.52905,6.52905 +046485478.jpg,1064,622.121,4.8434,4.8434 +005515659.jpg,435,720.725,8.64375,8.64375 +089476199.jpg,457,405.868,2.23897,2.23897 +011755725.jpg,509,474.666,2.30552,2.30552 +062479540.jpg,809,727.973,8.4144,8.4144 +051343450.jpg,756,210.02,0.918314,0.918314 +044043457.jpg,373,536.77,6.56418,6.56418 +068914336.jpg,525,426.163,2.34691,2.34691 +003836155.jpg,824,415.151,3.67925,3.67925 +050035836.jpg,646,595.857,7.98812,7.98812 +069280120.jpg,1330,732.556,5.46297,5.46297 +087096760.jpg,1373,528.071,2.83924,2.83924 +087096760.jpg,1846,561.951,2.66257,2.66257 +034233408.jpg,577,610.74,2.81169,2.81169 +007235726.jpg,704,293.585,2.38212,2.38212 +007235726.jpg,933,343.43,4.11919,4.11919 +088110515.jpg,346,456.529,4.46073,4.46073 +059298475.jpg,768,319.175,1.43122,1.43122 +067812250.jpg,660,363.267,1.77229,1.77229 +041442981.jpg,544,390.759,2.22991,2.22991 +030123129.jpg,542,383.273,2.02272,2.02272 +046339101.jpg,687,320.265,1.8554,1.8554 +074163782.jpg,645,453.777,3.23138,3.23138 +066237186.jpg,895,374.489,2.87406,2.87406 +012818807.jpg,784,414.95,2.91247,2.91247 +012818807.jpg,449,470.161,2.18011,2.18011 +024720607.jpg,357,422.843,3.23694,3.23694 +074837525.jpg,584,341.27,2.77253,2.77253 +074837525.jpg,110,356.453,3.03771,3.03771 +019644132.jpg,396,910.164,3.09698,3.09698 +037802495.jpg,1777,838.874,4.65619,4.65619 +037802495.jpg,1182,835.135,4.26127,4.26127 +071902282.jpg,628,456.16,4.59666,4.59666 +070876563.jpg,1017,469.469,3.37243,3.37243 +045550170.jpg,449,338.545,3.04541,3.04541 +003082462.jpg,444,327.143,3.09524,3.09524 +048921625.jpg,188,262.532,2.54435,2.54435 +015828626.jpg,1672,470.347,4.77895,4.77895 +060569924.jpg,1621,490.952,4.5793,4.5793 +069186391.jpg,1072,442.822,4.31854,4.31854 +069186391.jpg,431,890.802,5.48352,5.48352 +038306937.jpg,511,572.371,5.94757,5.94757 +043950778.jpg,450,915.121,4.51009,4.51009 +046468947.jpg,858,326.082,3.09015,3.09015 +001363985.jpg,251,508.392,4.86601,4.86601 +029575283.jpg,1520,456.855,2.7379,2.7379 +049565392.jpg,189,385.554,2.7128,2.7128 +049565392.jpg,1529,511.004,2.75036,2.75036 +019668856.jpg,1419,402.968,2.5807,2.5807 +005533239.jpg,257,384.711,1.80923,1.80923 +053552192.jpg,687,208.115,2.84289,2.84289 +065377792.jpg,1207,400.783,3.06529,3.06529 +038705001.jpg,466,450.102,3.34187,3.34187 +038705001.jpg,1584,447.429,3.95238,3.95238 +064722228.jpg,1515,510.537,3.7114,3.7114 +004476839.jpg,1601,433.301,3.35839,3.35839 +005404763.jpg,1594,636.662,4.63847,4.63847 +005404763.jpg,1002,548.373,3.78107,3.78107 +054962230.jpg,399,459.671,2.47259,2.47259 +088781764.jpg,410,383.151,2.67925,2.67925 +082264793.jpg,452,369.247,2.93724,2.93724 +031660243.jpg,836,347.071,2.83924,2.83924 +004414556.jpg,982,723.524,2.87703,2.87703 +099209219.jpg,1187,785.076,7.67297,7.67297 +013035168.jpg,516,579.617,6.21811,6.21811 +088065058.jpg,618,564.878,6.73979,6.73979 +053749375.jpg,748,641.274,9.27286,9.27286 +068058309.jpg,589,485.171,7.01423,7.01423 +011376196.jpg,734,461.627,2.80223,2.80223 +036351446.jpg,508,504.536,6.54468,6.54468 +089377419.jpg,278,373.456,3.95466,3.95466 +052980906.jpg,946,364.686,3.39053,3.39053 +015031062.jpg,128,486.531,4.54428,4.54428 +015031062.jpg,1098,549.004,4.667,4.667 +056847220.jpg,497,648.763,7.8969,7.8969 +049786918.jpg,937,627.197,3.18311,3.18311 +097304535.jpg,1230,914.417,10.8681,10.8681 +003117491.jpg,407,238.565,3.38043,3.38043 +012731188.jpg,681,414.863,3.73858,3.73858 +039763499.jpg,399,296.495,5.79124,5.79124 +001485612.jpg,176,337.005,5.16706,5.16706 +073272342.jpg,460,318.464,2.03868,2.03868 +068587628.jpg,567,330.356,3.61298,3.61298 +068587628.jpg,156,304.983,3.49857,3.49857 +072967841.jpg,797,654.624,2.38533,2.38533 +005204584.jpg,761,578.323,4.61025,4.61025 +097607833.jpg,1193,780.556,2.37966,2.37966 +098826212.jpg,1316,697.313,3.27605,3.27605 +019854286.jpg,450,520.75,3.0625,3.0625 +097374258.jpg,902,376.883,2.90691,2.90691 +012693606.jpg,1365,866.915,10.9929,10.9929 +097090471.jpg,577,351.154,2.84621,2.84621 +064485604.jpg,685,438.422,4.61854,4.61854 +023600793.jpg,871,576.867,6.82221,6.82221 +014926801.jpg,395,296.496,4.458,4.458 +093612557.jpg,314,315.336,5.02802,5.02802 +055781013.jpg,412,442.276,3.02301,3.02301 +037946138.jpg,319,418.447,3.03727,3.03727 +020299356.jpg,887,489.757,2.39643,2.39643 +062911758.jpg,1473,444.881,3.99011,3.99011 +059087192.jpg,591,769.878,8.82316,8.82316 +091320596.jpg,786,425.378,4.69814,4.69814 +052065535.jpg,715,418.649,5.22078,5.22078 +046245682.jpg,1691,703.968,2.5807,2.5807 +003282550.jpg,630,314.266,2.68881,2.68881 +042343880.jpg,597,517.916,4.82637,4.82637 +025793951.jpg,593,361.346,3.36214,3.36214 +049151423.jpg,675,375.367,3.03059,3.03059 +045448273.jpg,411,251.066,2.00552,2.00552 +068910908.jpg,735,418.712,5.97603,5.97603 +078566660.jpg,287,264.028,3.91899,3.91899 +096218591.jpg,158,337.048,2.83734,2.83734 +099560420.jpg,206,243.949,2.82908,2.82908 +025266300.jpg,160,272.247,2.85394,2.85394 +029493114.jpg,378,320.476,3.12303,3.12303 +029493114.jpg,495,281.567,2.88062,2.88062 +022012924.jpg,293,281.349,2.86245,2.86245 +017110248.jpg,1059,812.949,10.4957,10.4957 +051387583.jpg,323,340.046,4.00385,4.00385 +097799342.jpg,461,259.664,3.97203,3.97203 +028793409.jpg,539,291.252,4.02101,4.02101 +095591880.jpg,546,503.522,7.71018,7.71018 +053741694.jpg,831,434.698,7.30819,7.30819 +002250433.jpg,821,383.892,9.07429,9.07429 +068004606.jpg,287,303.986,3.58221,3.58221 +090955543.jpg,307,278.884,3.32364,3.32364 +001803201.jpg,299,299.065,3.50538,3.50538 +054133538.jpg,308,345.489,3.45743,3.45743 +032389555.jpg,300,283.996,3.41631,3.41631 +086106294.jpg,569,630.284,2.44035,2.44035 +006986192.jpg,682,426,1.5,1.5 +006154303.jpg,272,552.642,1.63686,1.63686 +099316374.jpg,987,564.237,3.51973,3.51973 +042500241.jpg,992,658.96,5.49664,5.49664 +053619228.jpg,757,652.371,7.19762,7.19762 +044891172.jpg,406,342.928,4.07735,4.07735 +055416972.jpg,662,443.532,4.79437,4.79437 +001206994.jpg,1600,409.175,3.51461,3.51461 +050442104.jpg,812,605.865,7.65541,7.65541 +088334970.jpg,373,251.962,2.08019,2.08019 +075366614.jpg,790,327.3,1.35831,1.35831 +086572724.jpg,895,468.424,3.03534,3.03534 +072442234.jpg,205,340.018,1.66817,1.66817 +008982575.jpg,551,368.558,5.04651,5.04651 +051654651.jpg,1668,687.026,2.2522,2.2522 +051654651.jpg,1139,572.264,2.10535,2.10535 +060970820.jpg,1730,248.111,2.67589,2.67589 +085788919.jpg,1074,530.409,5.20074,5.20074 +030886090.jpg,890,710.681,4.14011,4.14011 +050677004.jpg,899,393.428,2.20229,2.20229 +048078617.jpg,739,559.221,3.10177,3.10177 +048078617.jpg,635,430.857,2.82144,2.82144 +099201597.jpg,496,659.447,3.12058,3.12058 +068665042.jpg,843,314.904,1.24201,1.24201 +084135677.jpg,869,483.567,2.04727,2.04727 +076786092.jpg,1027,525.4,1.2,1.2 +058618235.jpg,1345,286.608,2.63403,2.63403 +034226559.jpg,910,638.518,2.20984,2.20984 +032900573.jpg,366,387.792,2.31603,2.31603 +041070040.jpg,698,473.437,3.03638,3.03638 +092019699.jpg,762,879.215,8.85127,8.85127 +004915852.jpg,594,611.289,2.27407,2.27407 +024192773.jpg,1350,282.959,2.2466,2.2466 +068982107.jpg,795,411.392,1.86604,1.86604 +012434532.jpg,1069,473.775,2.06456,2.06456 +006449068.jpg,80,453.992,2.16603,2.16603 +057429354.jpg,1079,400.56,2.7133,2.7133 +050574230.jpg,257,380.862,2.1552,2.1552 +086100882.jpg,186,402.305,2.10877,2.10877 +061562440.jpg,758,428.123,2.01022,2.01022 +035023661.jpg,1138,407.557,1.96311,1.96311 +009488423.jpg,1022,399.121,4.8434,4.8434 +037356629.jpg,190,735.704,3.642,3.642 +021430007.jpg,120,759.366,3.78048,3.78048 +044291410.jpg,994,705.339,5.02829,5.02829 +003417559.jpg,521,801.666,7.30548,7.30548 +081043291.jpg,435,740.625,4.71878,4.71878 +044378358.jpg,60,523.275,5.02292,5.02292 +061521490.jpg,569,226.913,1.32612,1.32612 +060944530.jpg,209,278.875,2.23958,2.23958 +001164490.jpg,593,545.267,5.77225,5.77225 +055681214.jpg,480,410.496,1.45801,1.45801 +059191440.jpg,393,530.862,9.23849,9.23849 +073627990.jpg,569,596.916,4.65967,4.65967 +007964513.jpg,1760,686.596,2.21635,2.21635 +064869504.jpg,686,339.845,2.98707,2.98707 +091357801.jpg,454,431.701,3.72508,3.72508 +030115902.jpg,47,457.26,2.605,2.605 +057953637.jpg,611,354.496,1.45801,1.45801 +010377471.jpg,245,463.638,2.13654,2.13654 +051673604.jpg,644,420.541,3.37843,3.37843 +081910733.jpg,700,373.373,1.61443,1.61443 +031500828.jpg,484,297.916,1.82631,1.82631 +057554951.jpg,489,470.064,2.00529,2.00529 +022010983.jpg,346,452.2,1.93331,1.93331 +020117297.jpg,617,462.2,1.35,1.35 +042286841.jpg,891,393.61,4.21753,4.21753 +078418718.jpg,281,629.725,2.06041,2.06041 +093776456.jpg,741,258.892,1.15763,1.15763 +088913054.jpg,878,276.473,1.53938,1.53938 +052081559.jpg,595,304.22,2.3517,2.3517 +048127395.jpg,1172,450.142,4.17852,4.17852 +061735425.jpg,1448,572.873,5.73942,5.73942 +040491081.jpg,912,428.773,2.81441,2.81441 +096164049.jpg,934,562.441,7.37005,7.37005 +040919664.jpg,737,574.577,6.71477,6.71477 +090898089.jpg,358,237.794,1.81618,1.81618 +072847095.jpg,1026,369.624,4.13532,4.13532 +081420877.jpg,1019,468.77,4.98081,4.98081 +058301865.jpg,988,505.771,5.06423,5.06423 +058301865.jpg,526,309.891,3.07423,3.07423 +058926734.jpg,802,283.332,2.69433,2.69433 +036717381.jpg,837,623.943,4.66189,4.66189 +033473533.jpg,469,284.496,2.95801,2.95801 +069863559.jpg,734,427.436,2.61964,2.61964 +049252185.jpg,664,423.875,3.15628,3.15628 +048919652.jpg,674,408.096,3.25801,3.25801 +045375376.jpg,580,395.351,3.6126,3.6126 +038110051.jpg,741,474.91,4.82581,4.82581 +041796954.jpg,613,320.967,2.08062,2.08062 +082029296.jpg,608,437.434,1.7862,1.7862 +050516571.jpg,563,389.765,2.4804,2.4804 +036784718.jpg,682,188.97,1.74748,1.74748 +020966092.jpg,1349,533.065,2.17205,2.17205 +069567766.jpg,951,497.549,3.29577,3.29577 +063267703.jpg,293,863.077,2.25639,2.25639 +083025019.jpg,1125,735.307,8.85889,8.85889 +050840598.jpg,971,280.586,1.63218,1.63218 +067097471.jpg,391,459.882,3.24014,3.24014 +077718591.jpg,787,517.541,3.29509,3.29509 +028540529.jpg,67,366.684,1.72363,1.72363 +047590633.jpg,903,602.209,5.1841,5.1841 +044854255.jpg,678,397.142,2.9285,2.9285 +000563131.jpg,1013,423.186,3.51551,3.51551 +018631678.jpg,772,311.504,3.54203,3.54203 +009972620.jpg,807,386.439,3.53657,3.53657 +034847798.jpg,932,588.606,5.13386,5.13386 +064707017.jpg,976,390.417,4.36807,4.36807 +095601971.jpg,1297,451.144,3.76198,3.76198 +021473513.jpg,362,609.042,4.58686,4.58686 +051666426.jpg,955,628.408,4.28402,4.28402 +037796836.jpg,710,376.235,3.68622,3.68622 +054453129.jpg,664,365.671,1.55596,1.55596 +053231026.jpg,151,370.209,1.43405,1.43405 +069821545.jpg,719,374.241,3.52011,3.52011 +072032292.jpg,367,384.775,2.06456,2.06456 +052943574.jpg,633,405.863,1.98862,1.98862 +052943574.jpg,1083,367.377,1.61471,1.61471 +041838334.jpg,609,275.904,2.74201,2.74201 +041838334.jpg,1198,330.296,2.35801,2.35801 +044085511.jpg,184,330.438,2.2865,2.2865 +044085511.jpg,432,238.704,1.39201,1.39201 +003378915.jpg,772,377.489,1.37412,1.37412 +003378915.jpg,855,373.278,1.27315,1.27315 +018673299.jpg,250,363.778,1.23146,1.23146 +014562874.jpg,642,333.324,4.11033,4.11033 +073336151.jpg,414,608.704,2.14201,2.14201 +064527776.jpg,1200,720.681,4.14011,4.14011 +069709114.jpg,400,681.344,3.27866,3.27866 +058682045.jpg,1503,628.461,2.45506,2.45506 +007227171.jpg,1128,534.456,3.1213,3.1213 +040215638.jpg,627,877.98,1.99832,1.99832 +014451522.jpg,1292,396.565,3.7971,3.7971 +051021292.jpg,1258,478.663,6.13857,6.13857 +090340776.jpg,726,578.12,4.34337,4.34337 +019045700.jpg,1088,310.874,1.48946,1.48946 +066480776.jpg,373,267.559,2.62992,2.62992 +002162699.jpg,687,379.18,3.01496,3.01496 +022488678.jpg,1034,426.894,2.40786,2.40786 +051944879.jpg,1085,621.929,3.82744,3.82744 +064167571.jpg,300,248.182,1.01514,1.01514 +081725927.jpg,371,151.173,1.68107,1.68107 +071563555.jpg,663,454.647,2.97061,2.97061 +018804109.jpg,703,379.008,2.50064,2.50064 +049885102.jpg,1291,653.32,4.44334,4.44334 +092526464.jpg,509,443.657,6.80471,6.80471 +063405506.jpg,632,571.022,4.33518,4.33518 +025285498.jpg,322,579.517,7.54308,7.54308 +051740129.jpg,349,443.444,8.45367,8.45367 +051403082.jpg,370,441.761,7.56345,7.56345 +092575169.jpg,688,424.294,6.19113,6.19113 +041473580.jpg,463,515.358,9.11314,9.11314 +078967361.jpg,350,300.621,4.30173,4.30173 +053358973.jpg,320,261.843,4.9036,4.9036 +077730215.jpg,345,287.93,4.41082,4.41082 +069679551.jpg,703,445.553,6.87943,6.87943 +079164007.jpg,656,463.714,8.05951,8.05951 +077113605.jpg,500,568.67,9.97246,9.97246 +066126531.jpg,722,390.261,3.85509,3.85509 +089001890.jpg,296,502.527,7.87721,7.87721 +024495351.jpg,937,333.241,3.77011,3.77011 +029403971.jpg,985,407.217,3.0181,3.0181 +071024334.jpg,237,410.675,3.47288,3.47288 +011539986.jpg,895,591.028,4.41897,4.41897 +086302878.jpg,519,684.2,7.35,7.35 +051683677.jpg,1108,402.486,1.79047,1.79047 +026336362.jpg,781,447.269,1.68908,1.68908 +080388471.jpg,773,442.395,6.19956,6.19956 +071704794.jpg,711,501.792,6.06601,6.06601 +044501868.jpg,1123,1005.46,8.53862,8.53862 +083522929.jpg,391,369.514,4.79287,4.79287 +030351012.jpg,587,359.153,4.51278,4.51278 +047279335.jpg,785,539.482,3.54013,3.54013 +074180648.jpg,627,453.947,3.41223,3.41223 +056545637.jpg,68,271.616,1.63466,1.63466 +010962819.jpg,513,491.716,5.05969,5.05969 +097607969.jpg,1036,547.792,4.56602,4.56602 +032513293.jpg,1009,474.026,5.25214,5.25214 +081873799.jpg,1177,435.055,2.5046,2.5046 +085765599.jpg,185,350.353,2.61276,2.61276 +037364082.jpg,540,343.202,1.60016,1.60016 +037364082.jpg,1170,600.672,1.63933,1.63933 +017615391.jpg,696,355.171,1.59762,1.59762 +047662416.jpg,674,462.87,3.07247,3.07247 +086570099.jpg,848,264.46,2.37171,2.37171 +003210958.jpg,654,377.554,2.7128,2.7128 +061935131.jpg,1421,844.892,6.99103,6.99103 +000094304.jpg,513,839.191,5.93257,5.93257 +068120926.jpg,277,248.364,1.947,1.947 +075215489.jpg,356,407.762,2.14683,2.14683 +003206352.jpg,1151,684.711,5.14262,5.14262 +016814109.jpg,890,538.539,5.87824,5.87824 +016762156.jpg,221,516.236,4.01966,4.01966 +017169399.jpg,1158,506.058,2.67152,2.67152 +010253454.jpg,673,270.783,1.89855,1.89855 +003185676.jpg,716,546.493,6.95774,6.95774 +028021641.jpg,608,539.845,4.98704,4.98704 +005312062.jpg,1014,576.111,5.09258,5.09258 +083391660.jpg,963,376.661,2.30512,2.30512 +061611080.jpg,793,525.026,4.00216,4.00216 +047432557.jpg,513,421.739,4.56158,4.56158 +039166654.jpg,615,356.377,1.61471,1.61471 +091547688.jpg,298,352.579,3.04821,3.04821 +062664368.jpg,651,364.261,2.52179,2.52179 +047050072.jpg,1311,442.343,3.19525,3.19525 +030122575.jpg,1171,428.97,1.74748,1.74748 +088864267.jpg,304,355.981,1.4151,1.4151 +022690077.jpg,45,357.477,1.95645,1.95645 +071743445.jpg,85,195.289,1.52411,1.52411 +076265349.jpg,1187,362.151,2.76261,2.76261 +023419443.jpg,1372,628.232,9.85266,9.85266 +078406178.jpg,218,296.236,3.93629,3.93629 +026039736.jpg,523,444.206,5.2672,5.2672 +036046303.jpg,932,676.885,3.40708,3.40708 +009865738.jpg,221,393.585,2.38212,2.38212 +014369161.jpg,413,256.972,1.83098,1.83098 +014369161.jpg,977,275.473,1.87278,1.87278 +000721995.jpg,500,518.499,2.12492,2.12492 +047787708.jpg,305,380.904,1.24201,1.24201 +047787708.jpg,896,403.477,1.95645,1.95645 +025324536.jpg,804,343.651,2.72092,2.72092 +095562138.jpg,560,340.481,1.0401,1.0401 +057996198.jpg,532,406.848,1.48735,1.48735 +057996198.jpg,798,376.337,1.19474,1.19474 +069399211.jpg,1823,486.933,2.24439,2.24439 +078636739.jpg,1708,450.642,1.38683,1.38683 +025005676.jpg,688,453.734,1.64454,1.64454 +086770546.jpg,931,559.187,3.26559,3.26559 +051306942.jpg,417,397.761,3.39676,3.39676 +025421783.jpg,529,487.035,3.50294,3.50294 +097560497.jpg,268,381.408,4.45063,4.45063 +010357657.jpg,243,198.641,3.22008,3.22008 +028715226.jpg,682,316.725,2.06041,2.06041 +081441920.jpg,419,253.523,3.29358,3.29358 +071391458.jpg,1555,539.817,5.98476,5.98476 +048724956.jpg,1168,630.808,7.23398,7.23398 +024478952.jpg,443,297.816,4.23468,4.23468 +024647791.jpg,279,359.831,5.98588,5.98588 +002634733.jpg,770,435.074,6.83947,6.83947 +044249131.jpg,553,303.743,2.47859,2.47859 +047904073.jpg,209,343.747,2.89558,2.89558 +090537319.jpg,689,366.404,3.20031,3.20031 +015928304.jpg,742,347.575,3.04792,3.04792 +043538940.jpg,727,361.698,2.89154,2.89154 +012737204.jpg,820,418.819,5.56821,5.56821 +040983848.jpg,644,365.788,6.98233,6.98233 +047228096.jpg,663,391.097,4.42477,4.42477 +013952678.jpg,555,379.908,5.15904,5.15904 +009106618.jpg,830,362.458,4.37146,4.37146 +020774927.jpg,351,642.26,8.60498,8.60498 +020774927.jpg,1392,672.546,9.46218,9.46218 +086875723.jpg,780,449.876,7.32301,7.32301 +013452549.jpg,491,323.585,3.88207,3.88207 +061477095.jpg,577,223.624,2.38533,2.38533 +074245756.jpg,217,286.277,2.10642,2.10642 +093668793.jpg,274,244.489,1.37412,1.37412 +056914157.jpg,378,375.775,2.06456,2.06456 +038236460.jpg,217,241.473,1.87278,1.87278 +093455807.jpg,48,189.768,1.89737,1.89737 +000338785.jpg,393,214.695,1.64125,1.64125 +073164590.jpg,440,215.713,1.47611,1.47611 +096785992.jpg,159,134.096,1.75801,1.75801 +072739729.jpg,253,230.972,1.91437,1.91437 +098204462.jpg,151,331.757,2.31311,2.31311 +011618078.jpg,1011,583.94,3.49497,3.49497 +028721257.jpg,384,437.882,1.2402,1.2402 +028721257.jpg,556,438.089,1.6741,1.6741 +019517462.jpg,1468,739.897,8.32477,8.32477 +052664226.jpg,306,582.2,8.85,8.85 +057961090.jpg,551,352.969,4.4974,4.4974 +065133611.jpg,722,410.66,2.38835,2.38835 +079528704.jpg,1176,365.926,4.91048,4.91048 +047246211.jpg,490,386.268,3.27234,3.27234 +043369693.jpg,1021,591.262,2.93847,2.93847 +020227318.jpg,1534,556.681,4.14011,4.14011 +078665252.jpg,438,297.555,2.54629,2.54629 +033893622.jpg,882,292.369,2.28079,2.28079 +029127252.jpg,545,388.414,5.78448,5.78448 +012857726.jpg,320,294.046,2.9205,2.9205 +069746127.jpg,386,509.29,7.10747,7.10747 +029157677.jpg,638,286.071,2.08926,2.08926 +062585840.jpg,630,434.883,1.74026,1.74026 +062585840.jpg,1066,432.775,1.56461,1.56461 +094953744.jpg,585,659.888,2.32398,2.32398 +033952892.jpg,407,302.875,1.57293,1.57293 +006584216.jpg,791,382.066,1.83883,1.83883 +062216692.jpg,545,402.545,2.96211,2.96211 +062216692.jpg,1087,417.941,3.82838,3.82838 +007672737.jpg,639,588.604,9.21703,9.21703 +071679772.jpg,352,290.048,3.254,3.254 +032482411.jpg,451,328.313,3.27605,3.27605 +043308020.jpg,424,326.481,1.20673,1.20673 +066167506.jpg,765,259.874,1.40616,1.40616 +033949392.jpg,270,364.788,2.23233,2.23233 +005813379.jpg,333,297.141,3.17844,3.17844 +017152269.jpg,323,142.055,2.5046,2.5046 +085875126.jpg,588,249.555,4.29629,4.29629 +074014939.jpg,888,919.758,6.39648,6.39648 +035688866.jpg,408,364.552,3.46263,3.46263 +021383889.jpg,322,336.437,3.03638,3.03638 +003778297.jpg,380,336.64,3.55332,3.55332 +069865698.jpg,294,311.061,5.08843,5.08843 +092407781.jpg,391,470.712,5.22603,5.22603 +067041551.jpg,319,377.62,4.38503,4.38503 +004200577.jpg,966,344.561,3.54673,3.54673 +083112722.jpg,730,444.357,3.94645,3.94645 +004555016.jpg,918,459.112,4.34265,4.34265 +071844147.jpg,128,272.783,1.89855,1.89855 +087498950.jpg,599,259.332,2.69433,2.69433 +036217876.jpg,744,409.44,4.28664,4.28664 +053233060.jpg,1089,677.259,7.68826,7.68826 +043362259.jpg,688,769.099,5.92491,5.92491 +056951187.jpg,907,817.087,5.67389,5.67389 +044794242.jpg,1160,729.313,4.69277,4.69277 +067887823.jpg,601,503.422,5.03518,5.03518 +098597432.jpg,328,333.401,2.36677,2.36677 +094304881.jpg,274,311.946,2.9955,2.9955 +062162958.jpg,528,325.378,6.69813,6.69813 +060645778.jpg,528,579.262,7.18849,7.18849 +070262711.jpg,825,438.813,4.90112,4.90112 +044014421.jpg,987,547.379,1.2816,1.2816 +017101085.jpg,229,250.163,2.34691,2.34691 +017101085.jpg,67,370.048,3.254,3.254 +055377395.jpg,956,931.614,11.3012,11.3012 +020446672.jpg,1468,567.872,5.65601,5.65601 +008996728.jpg,1391,696.831,5.98588,5.98588 +011376246.jpg,239,374.972,2.83099,2.83099 +030003048.jpg,420,303.331,3.44426,3.44426 +060423951.jpg,1178,452.638,2.13654,2.13654 +081674528.jpg,240,287.193,2.51607,2.51607 +081674528.jpg,399,326.162,2.93019,2.93019 +004233495.jpg,676,391.113,5.09276,5.09276 +054848359.jpg,390,448.005,9.00045,9.00045 +070847825.jpg,438,514.694,6.80782,6.80782 +077960864.jpg,1250,486.641,3.30341,3.30341 +060290881.jpg,1219,739.178,4.09816,4.09816 +023190112.jpg,810,657.278,3.85649,3.85649 +031373526.jpg,733,725.021,4.16838,4.16838 +094630890.jpg,538,416.803,2.90024,2.90024 +013338862.jpg,527,570.629,7.55244,7.55244 +075114837.jpg,449,324.267,3.4389,3.4389 +091752473.jpg,999,589.408,6.53401,6.53401 +060507149.jpg,216,302.551,4.87922,4.87922 +081753242.jpg,482,287.646,3.55383,3.55383 +016979264.jpg,416,245.385,2.53211,2.53211 +041670866.jpg,264,606.62,2.885,2.885 +007276238.jpg,323,577.954,3.0795,3.0795 +083132407.jpg,516,364.073,5.92278,5.92278 +067371165.jpg,770,402.997,6.16644,6.16644 +078580047.jpg,478,402.696,2.05801,2.05801 +078580047.jpg,832,369.545,1.87878,1.87878 +048421307.jpg,420,387.055,1.33795,1.33795 +089602837.jpg,512,540.808,3.23402,3.23402 +008118779.jpg,709,213.803,2.56689,2.56689 +055764239.jpg,835,603.967,2.08062,2.08062 +014105980.jpg,694,376.549,3.29577,3.29577 +012610270.jpg,879,558.534,1.79449,1.79449 +083275867.jpg,799,509.647,5.72057,5.72057 +086093048.jpg,680,460.431,5.03589,5.03589 +086093048.jpg,341,513.012,4.66768,4.66768 +086093048.jpg,952,407.337,2.61138,2.61138 +075437596.jpg,482,377.043,3.25358,3.25358 +008703357.jpg,513,312.088,5.17402,5.17402 +038504124.jpg,807,684.115,3.92622,3.92622 +078868643.jpg,740,448.142,1.76185,1.76185 +096982079.jpg,404,558.925,8.07708,8.07708 +003748796.jpg,722,524.449,7.53741,7.53741 +040065785.jpg,764,184.828,2.56899,2.56899 +043498020.jpg,507,501.522,2.04353,2.04353 +099875003.jpg,526,563.798,3.14986,3.14986 +099861143.jpg,312,443.811,2.56759,2.56759 +062964123.jpg,967,437.966,3.33054,3.33054 +078174586.jpg,353,437.232,3.26931,3.26931 +057427038.jpg,720,555.09,7.34087,7.34087 +023297221.jpg,666,516.887,2.57389,2.57389 +085626765.jpg,306,388.811,3.65089,3.65089 +071014504.jpg,988,299.953,7.99611,7.99611 +064439616.jpg,153,474.142,1.76185,1.76185 +081020585.jpg,435,206.882,3.0735,3.0735 +090971831.jpg,352,289.2,1.93331,1.93331 +011180037.jpg,725,612.208,3.68402,3.68402 +025698594.jpg,947,401.777,7.39809,7.39809 +002215954.jpg,730,388.875,2.23958,2.23958 +085795746.jpg,268,234.442,2.87014,2.87014 +066653846.jpg,1099,440.412,7.11765,7.11765 +081821200.jpg,154,324.06,2.25499,2.25499 +099199701.jpg,551,477.303,5.52521,5.52521 +018289377.jpg,566,316.61,2.30083,2.30083 +047024899.jpg,756,449.731,7.22757,7.22757 +051554699.jpg,941,300.323,3.02688,3.02688 +001229066.jpg,417,392.132,4.76103,4.76103 +098204009.jpg,660,204.886,2.74053,2.74053 +053197173.jpg,707,309.302,2.44182,2.44182 +079221703.jpg,626,312.653,2.97106,2.97106 +075812921.jpg,675,348.361,2.61345,2.61345 +078930045.jpg,1107,485.829,3.0691,3.0691 +011109721.jpg,637,484.595,5.71624,5.71624 +098918416.jpg,727,539.38,7.03166,7.03166 +002102481.jpg,515,493.321,7.11006,7.11006 +027244644.jpg,620,469,4.5,4.5 +096781214.jpg,716,323.259,3.35491,3.35491 +091702171.jpg,526,560.417,6.03477,6.03477 +094679117.jpg,480,329.422,2.53513,2.53513 +015559032.jpg,665,336.915,2.49289,2.49289 +030732518.jpg,564,369.922,2.91015,2.91015 +065430632.jpg,638,398.943,2.6619,2.6619 +052868585.jpg,955,381.112,6.17599,6.17599 +083671072.jpg,671,389.814,4.48447,4.48447 +030926888.jpg,140,133.075,1.50629,1.50629 +098324144.jpg,693,297.935,1.49459,1.49459 +080846029.jpg,684,307.353,1.61276,1.61276 +050987406.jpg,1548,359.874,1.40616,1.40616 +081082054.jpg,1175,406.779,1.31488,1.31488 +064680566.jpg,607,459.218,3.7682,3.7682 +087532908.jpg,198,418.175,1.5979,1.5979 +021103833.jpg,976,508.516,5.37636,5.37636 +028891432.jpg,1040,501.664,7.38865,7.38865 +024450750.jpg,687,663.599,2.46658,2.46658 +087303560.jpg,563,335.988,3.24902,3.24902 +030177922.jpg,267,574.112,5.17602,5.17602 +075893195.jpg,617,467.51,7.29247,7.29247 +011405030.jpg,289,409.903,7.40854,7.40854 +085223652.jpg,394,386.514,11.3762,11.3762 +059613806.jpg,413,454.185,5.43207,5.43207 +059613806.jpg,66,339.35,1.27914,1.27914 +001365988.jpg,1078,465.28,2.19,2.19 +003799784.jpg,795,341.614,3.13453,3.13453 +060552927.jpg,823,533.28,3.52331,3.52331 +010577891.jpg,464,398.882,3.0735,3.0735 +027792201.jpg,493,381.589,2.96575,2.96575 +058879453.jpg,473,412.209,1.43405,1.43405 +006835171.jpg,346,475.095,7.17458,7.17458 +058133922.jpg,627,468.176,3.93137,3.93137 +048525325.jpg,245,212.63,1.3025,1.3025 +078477432.jpg,465,301.344,3.27866,3.27866 +048549589.jpg,450,411.453,1.8711,1.8711 +097718774.jpg,843,305.958,2.4965,2.4965 +003317416.jpg,205,610.898,2.90814,2.90814 +010450756.jpg,805,403.839,1.98658,1.98658 +020941982.jpg,160,627.153,3.01272,3.01272 +077855303.jpg,903,516.431,5.03589,5.03589 +053507375.jpg,323,711.057,3.50474,3.50474 +070713752.jpg,712,509.476,2.12302,2.12302 +032971218.jpg,391,363.746,1.72884,1.72884 +068420967.jpg,797,738.695,7.97458,7.97458 +096934961.jpg,878,735.321,5.61008,5.61008 +058736678.jpg,917,716.944,5.66198,5.66198 +058736678.jpg,498,695.136,9.01129,9.01129 +081203329.jpg,957,600.637,8.96975,8.96975 +015591851.jpg,385,622.918,4.49319,4.49319 +019405388.jpg,1072,383.645,6.05376,6.05376 +032719161.jpg,400,588.123,2.01022,2.01022 +077482777.jpg,632,525.723,3.22692,3.22692 +050075527.jpg,597,381.094,1.59113,1.59113 +045610540.jpg,817,450.048,2.67067,2.67067 +045610540.jpg,250,397.479,2.20658,2.20658 +007171052.jpg,794,426.082,3.09015,3.09015 +045876829.jpg,390,388.886,2.74053,2.74053 +026734471.jpg,770,547.493,8.62441,8.62441 +004905357.jpg,638,616.068,8.42231,8.42231 +012113857.jpg,561,322.593,1.71604,1.71604 +087685858.jpg,896,482.249,2.52071,2.52071 +078172227.jpg,673,637.074,4.5062,4.5062 +078172227.jpg,347,496.856,2.40468,2.40468 +001541517.jpg,1125,466.284,2.77366,2.77366 +001541517.jpg,741,552.266,5.10547,5.10547 +081686048.jpg,549,329.392,2.61603,2.61603 +030052676.jpg,100,432.615,2.55123,2.55123 +030052676.jpg,875,425.863,2.07196,2.07196 +046857980.jpg,1162,602.814,3.73449,3.73449 +042486793.jpg,1395,481.334,2.27783,2.27783 +042486793.jpg,960,424.987,1.83221,1.83221 +042486793.jpg,518,475.661,2.30512,2.30512 +028888730.jpg,1280,429.345,2.02872,2.02872 +017221832.jpg,1117,372.565,1.88045,1.88045 +076223079.jpg,1645,578.296,2.85804,2.85804 +076223079.jpg,1534,565.173,2.51446,2.51446 +099010978.jpg,527,432.904,1.99201,1.99201 +077779158.jpg,1128,470.854,3.57113,3.57113 +024480896.jpg,515,389.817,4.06807,4.06807 +060540037.jpg,588,374.903,2.82526,2.82526 +037433615.jpg,722,290.565,1.88045,1.88045 +008831272.jpg,688,259.65,2.22081,2.22081 +021975030.jpg,181,412.075,2.33962,2.33962 +099217171.jpg,214,355.282,2.94015,2.94015 +084007716.jpg,246,501.258,2.43813,2.43813 +095654891.jpg,495,469.227,3.10221,3.10221 +051633982.jpg,1030,524.969,1.66412,1.66412 +043264248.jpg,727,531.274,1.27279,1.27279 +058017637.jpg,629,609.834,5.7362,5.7362 +025674160.jpg,1036,294.924,1.41032,1.41032 +072478930.jpg,189,282.322,2.61017,2.61017 +005952620.jpg,160,274.862,2.1552,2.1552 +080192039.jpg,792,662.868,11.1557,11.1557 +082242231.jpg,897,448.77,5.98084,5.98084 +071683721.jpg,545,322.054,3.42118,3.42118 +007532143.jpg,772,429.889,3.32405,3.32405 +007532143.jpg,101,394.535,2.29456,2.29456 +055766125.jpg,353,437.216,6.18466,6.18466 +038842722.jpg,861,576.759,2.22991,2.22991 +038842722.jpg,677,539.804,2.317,2.317 +027870735.jpg,516,224.494,1.1245,1.1245 +064924273.jpg,344,217.384,0.948683,0.948683 +064924273.jpg,133,231.407,1.78393,1.78393 +063042175.jpg,322,263.172,1.51433,1.51433 +067835063.jpg,205,281.395,4.11624,4.11624 +028509950.jpg,369,291.916,1.90966,1.90966 +058286936.jpg,400,289.646,3.72048,3.72048 +048824113.jpg,718,256.179,2.59825,2.59825 +048824113.jpg,511,240.545,3.04541,3.04541 +062849543.jpg,848,285.514,0.876185,0.876185 +092317603.jpg,549,456.222,4.51846,4.51846 +087457648.jpg,388,383.722,2.31019,2.31019 +015073699.jpg,947,341.836,3.48633,3.48633 +054570302.jpg,256,372.502,2.12514,2.12514 +035916394.jpg,507,364.386,1.78216,1.78216 +071770336.jpg,649,350.136,1.34466,1.34466 +061130552.jpg,736,321.683,1.89024,1.89024 +037614731.jpg,1233,456.065,2.25539,2.25539 +046783801.jpg,563,380.745,3.14543,3.14543 +092443009.jpg,1463,477.442,1.95346,1.95346 +013617414.jpg,1033,819.668,6.47236,6.47236 +054270125.jpg,946,471.83,4.56917,4.56917 +098401815.jpg,288,365.764,2.64698,2.64698 +082379762.jpg,652,539.522,2.46018,2.46018 +048105113.jpg,382,504.896,3.40801,3.40801 +048105113.jpg,274,413.756,2.06303,2.06303 +048105113.jpg,963,301.557,1.96311,1.96311 +059248640.jpg,1018,807.513,10.1261,10.1261 +037549724.jpg,156,342.245,4.77038,4.77038 +037330499.jpg,554,370.408,4.28402,4.28402 +037330499.jpg,156,332.694,4.39118,4.39118 +014963672.jpg,381,307.863,3.73858,3.73858 +094316313.jpg,292,270.803,2.90024,2.90024 +051665349.jpg,244,251.932,2.99429,2.99429 +021748435.jpg,597,372.65,2.22081,2.22081 +095984343.jpg,651,374.922,2.16021,2.16021 +052008994.jpg,1218,354.689,1.97408,1.97408 +052008994.jpg,498,335.667,3.88891,3.88891 +040069928.jpg,209,275.704,2.14201,2.14201 +066520410.jpg,570,296.289,3.02405,3.02405 +071271800.jpg,753,249.373,1.44779,1.44779 +071271800.jpg,550,329.513,3.12605,3.12605 +054651371.jpg,733,433.394,2.6162,2.6162 +021346152.jpg,658,220.722,3.06015,3.06015 +071772225.jpg,329,209.447,1.70394,1.70394 +028529772.jpg,437,332.385,4.03207,4.03207 +028262561.jpg,445,264.3,1.35831,1.35831 +031002185.jpg,466,309.304,3.27536,3.27536 +052790983.jpg,456,270.575,4.96461,4.96461 +088447131.jpg,370,400.952,4.99597,4.99597 +084942227.jpg,1273,373.972,2.83099,2.83099 +070669438.jpg,942,511.299,10.8583,10.8583 +002762976.jpg,1484,465.217,4.76811,4.76811 +009326012.jpg,166,650.926,4.16049,4.16049 +092088616.jpg,819,355.548,1.37902,1.37902 +000612865.jpg,394,671.989,3.99912,3.99912 +046413519.jpg,948,753.834,6.48618,6.48618 +011027673.jpg,957,284.165,4.59705,4.59705 +094023419.jpg,931,276.642,2.97015,2.97015 +094023419.jpg,665,319.848,2.90396,2.90396 +069290915.jpg,847,456.712,5.97603,5.97603 +036645665.jpg,1010,322.445,3.03712,3.03712 +004321370.jpg,1203,347.75,3.14585,3.14585 +001717299.jpg,1107,424.172,3.93103,3.93103 +001717299.jpg,837,312.141,3.26173,3.26173 +095900709.jpg,728,633.324,8.19368,8.19368 +095900709.jpg,1071,531.192,6.51601,6.51601 +063873926.jpg,1087,594.484,6.95696,6.95696 +064471684.jpg,1058,469.709,4.39241,4.39241 +097393557.jpg,682,430.863,5.98859,5.98859 +056047348.jpg,370,316.428,3.11899,3.11899 +062539763.jpg,959,310.932,4.3277,4.3277 +016983943.jpg,636,368.911,4.8259,4.8259 +070334095.jpg,999,581.895,5.32456,5.32456 +038203483.jpg,1314,685.933,3.07774,3.07774 +071585002.jpg,1132,641.692,5.89101,5.89101 +029730060.jpg,757,619.377,8.44808,8.44808 +004593003.jpg,533,311.717,6.80974,6.80974 +011160320.jpg,1675,723.483,12.2902,12.2902 +055868144.jpg,475,312.933,2.24439,2.24439 +055551867.jpg,869,294.734,1.64454,1.64454 +083962939.jpg,132,375.859,2.90489,2.90489 +036037812.jpg,303,303.626,3.55218,3.55218 +042690209.jpg,642,302.153,3.01272,3.01272 +043876222.jpg,110,223.942,3.07847,3.07847 +023492919.jpg,211,187.304,1.69201,1.69201 +072883415.jpg,1001,389.859,2.90489,2.90489 +044136008.jpg,709,404.894,3.15785,3.15785 +032546899.jpg,361,226.392,1.53264,1.53264 +071688418.jpg,209,349.4,2.7,2.7 +095869774.jpg,254,303.732,2.39437,2.39437 +095878664.jpg,632,453.915,5.49295,5.49295 +095878664.jpg,1270,522.646,4.13717,4.13717 +062112530.jpg,592,457.886,6.40716,6.40716 +072724232.jpg,260,316.547,2.87891,2.87891 +034965338.jpg,308,265.471,2.62256,2.62256 +092726563.jpg,446,389.214,4.76783,4.76783 +050009234.jpg,666,381.535,3.71128,3.71128 +004434686.jpg,442,260.463,2.45524,2.45524 +050170298.jpg,689,810.088,10.674,10.674 +026083516.jpg,740,771.392,10.9493,10.9493 +086782850.jpg,420,581.392,8.78268,8.78268 +047648321.jpg,157,304.566,3.6305,3.6305 +083636929.jpg,462,438.176,7.01468,7.01468 +077439854.jpg,464,506.307,5.7756,5.7756 +032859216.jpg,499,481.005,6.41706,6.41706 +093507662.jpg,637,326.389,2.86575,2.86575 +052062247.jpg,451,432.535,3.54457,3.54457 +095992812.jpg,567,343.622,4.46849,4.46849 +017197040.jpg,887,453.679,6.55656,6.55656 +022598677.jpg,325,330.266,2.68881,2.68881 +012101572.jpg,727,233.205,3.01705,3.01705 +094573796.jpg,879,428.585,3.13209,3.13209 +073054263.jpg,1087,537.985,3.58208,3.58208 +004635327.jpg,30,491.686,2.47386,2.47386 +054966967.jpg,1171,569.492,3.45769,3.45769 +012918392.jpg,635,446.058,2.67152,2.67152 +012918392.jpg,793,374.642,3.38681,3.38681 +055827652.jpg,981,593.843,3.23694,3.23694 +086136272.jpg,542,420.548,7.2123,7.2123 +083113477.jpg,744,412.451,4.62088,4.62088 +010157214.jpg,870,342.463,2.45524,2.45524 +010157214.jpg,158,310.422,2.53513,2.53513 +035641786.jpg,518,797.235,5.43621,5.43621 +035641786.jpg,1117,318.592,3.96602,3.96602 +035641786.jpg,942,411.373,3.78107,3.78107 +060107680.jpg,1427,693.673,6.22274,6.22274 +040465542.jpg,446,592.988,6.33235,6.33235 +045588259.jpg,1243,602.556,3.46302,3.46302 +020426476.jpg,782,505.85,2.07087,2.07087 +013355827.jpg,1043,332.059,2.75494,2.75494 +013355827.jpg,1164,312.061,2.7551,2.7551 +010985976.jpg,1257,309.94,3.245,3.245 +004043883.jpg,1091,337.617,2.71811,2.71811 +061285477.jpg,701,719.183,7.8486,7.8486 +089601552.jpg,1055,385.761,4.14673,4.14673 +008998556.jpg,234,360.779,2.89822,2.89822 +097225980.jpg,123,281.565,2.79709,2.79709 +045313633.jpg,1022,817.401,8.45005,8.45005 +084366838.jpg,337,345.835,3.90288,3.90288 +008466981.jpg,912,326.768,2.73066,2.73066 +065380466.jpg,405,504.61,6.05086,6.05086 +067842667.jpg,810,511.226,5.10221,5.10221 +024889839.jpg,12,152.009,1.58405,1.58405 +018394742.jpg,868,201.354,2.69616,2.69616 +097772351.jpg,692,346.572,3.71431,3.71431 +099552023.jpg,918,520.737,3.64472,3.64472 +076217111.jpg,966,608.701,4.14174,4.14174 +096488299.jpg,898,906.139,10.5116,10.5116 +090865556.jpg,775,336.322,2.61017,2.61017 +090865556.jpg,371,358.04,1.83663,1.83663 +089466762.jpg,444,302.885,3.40708,3.40708 +039594110.jpg,332,283.863,2.07196,2.07196 +017441054.jpg,446,245.045,3.00375,3.00375 +012130470.jpg,883,331.75,2.72918,2.72918 +017551145.jpg,770,418.757,2.39643,2.39643 +017551145.jpg,924,436.447,3.03727,3.03727 +024154281.jpg,136,453.352,3.52931,3.52931 +007411917.jpg,283,195.982,1.24852,1.24852 +039865929.jpg,1090,348.904,2.74201,2.74201 +051210386.jpg,379,250.322,4.27687,4.27687 +013977166.jpg,507,586.664,2.30532,2.30532 +087588572.jpg,989,409.281,5.94008,5.94008 +072379523.jpg,715,429.535,3.71128,3.71128 +072379523.jpg,884,499.468,4.12235,4.12235 +030925611.jpg,1106,621.712,4.80937,4.80937 +048560832.jpg,673,395.155,2.92957,2.92957 +012274005.jpg,574,324.926,4.16049,4.16049 +003625232.jpg,778,438.585,1.9654,1.9654 +058021896.jpg,538,375.264,5.52204,5.52204 +080467162.jpg,1149,439.8,2.4,2.4 +024645987.jpg,1209,822.375,7.11462,7.11462 +003893371.jpg,473,374.792,3.81602,3.81602 +089422804.jpg,328,425.681,5.64008,5.64008 +018346425.jpg,1052,683.198,6.93318,6.93318 +099769622.jpg,925,641.339,6.52822,6.52822 +040192019.jpg,759,806.523,5.87694,5.87694 +027338392.jpg,1216,485.354,2.7795,2.7795 +093350188.jpg,1090,492.354,2.7795,2.7795 +072272728.jpg,376,548.566,3.6305,3.6305 +018934772.jpg,88,423.75,4.06254,4.06254 +075038893.jpg,143,466.664,3.13869,3.13869 +007317510.jpg,1780,481.344,3.27866,3.27866 +065197371.jpg,989,509.913,4.74275,4.74275 +079041525.jpg,1278,389.4,2.7,2.7 +059641003.jpg,717,651.825,7.15209,7.15209 +098161066.jpg,767,562.921,6.66007,6.66007 +083108441.jpg,342,406.675,3.47288,3.47288 +083108441.jpg,1313,474.323,4.36023,4.36023 +014926190.jpg,740,625,2.25,2.25 +035070233.jpg,576,659.295,5.69123,5.69123 +028882943.jpg,1159,734.379,5.7816,5.7816 +002598229.jpg,1262,725.28,2.19,2.19 +033785389.jpg,937,380.038,2.41979,2.41979 +091126979.jpg,1098,541.467,3.87221,3.87221 +096595021.jpg,733,494.017,5.41805,5.41805 +088029126.jpg,844,496.704,4.392,4.392 +054557435.jpg,584,367.269,3.18904,3.18904 +093135837.jpg,774,346.59,3.63248,3.63248 +059295427.jpg,204,410.089,2.42407,2.42407 +018691196.jpg,527,494.868,4.57232,4.57232 +018691196.jpg,376,359.376,3.03134,3.03134 +069460761.jpg,1004,575.376,3.03134,3.03134 +056277007.jpg,683,174.593,1.71604,1.71604 +081698338.jpg,514,254.942,3.07847,3.07847 +011050135.jpg,628,306.79,2.81585,2.81585 +032346733.jpg,768,368.528,4.2107,4.2107 +006331925.jpg,582,356.316,3.77631,3.77631 +003153463.jpg,744,391.707,5.05889,5.05889 +003153463.jpg,1249,601.392,6.28269,6.28269 +064601029.jpg,1201,683.708,5.55899,5.55899 +064601029.jpg,1263,332.545,2.96211,2.96211 +067375065.jpg,1462,661.291,5.02426,5.02426 +027998755.jpg,1303,426.469,3.28907,3.28907 +014074336.jpg,886,689.666,7.72219,7.72219 +040949628.jpg,786,433.335,7.19462,7.19462 +075660250.jpg,574,566.096,7.008,7.008 +075660250.jpg,1686,379.786,2.23213,2.23213 +088058244.jpg,1240,493.436,2.61964,2.61964 +086072856.jpg,1658,651.944,8.9953,8.9953 +001541496.jpg,787,337.904,4.242,4.242 +049636437.jpg,651,403.74,3.97837,3.97837 +031938412.jpg,362,420.945,6.07876,6.07876 +031938412.jpg,80,370.947,3.74556,3.74556 +087518721.jpg,285,615.616,5.5513,5.5513 +043338085.jpg,74,347.104,1.09202,1.09202 +006959185.jpg,884,443.267,3.4389,3.4389 +015363152.jpg,982,440.137,4.17809,4.17809 +046822640.jpg,814,574.892,5.07435,5.07435 +000877476.jpg,284,574.153,2.84605,2.84605 +000172482.jpg,712,644.638,2.13654,2.13654 +010155660.jpg,340,293.438,2.2865,2.2865 +070489691.jpg,59,641.533,2.4611,2.4611 +097589334.jpg,729,361.108,2.75902,2.75902 +097589334.jpg,458,402.87,2.6558,2.6558 +043336695.jpg,733,335.573,3.54775,3.54775 +075323641.jpg,54,316.513,1.6261,1.6261 +008196878.jpg,882,440.2,3.6,3.6 +089827971.jpg,1069,299.831,1.15256,1.15256 +030444345.jpg,597,493.745,3.06206,3.06206 +042235187.jpg,1223,180.377,1.61471,1.61471 +017183456.jpg,842,446.193,2.51607,2.51607 +017183456.jpg,883,308.088,1.34063,1.34063 +048901738.jpg,373,553.658,1.72154,1.72154 +063654449.jpg,874,466.57,2.13084,2.13084 +066760723.jpg,477,590.424,9.28533,9.28533 +066760723.jpg,1185,523.398,7.03319,7.03319 +068933882.jpg,789,943.704,6.642,6.642 +006970775.jpg,1248,808.534,8.04453,8.04453 +077781214.jpg,922,538.826,3.40219,3.40219 +002213328.jpg,986,585.077,2.50639,2.50639 +002213328.jpg,63,584.193,1.51611,1.51611 +002213328.jpg,105,457.276,1.10635,1.10635 +062833637.jpg,127,385.563,2.79693,2.79693 +037246695.jpg,713,541.394,2.3662,2.3662 +014316471.jpg,419,380.583,2.38193,2.38193 +094507920.jpg,640,430.378,2.69817,2.69817 +094507920.jpg,527,409.954,3.0795,3.0795 +098681068.jpg,365,385.693,2.05779,2.05779 +027169462.jpg,290,514.87,2.6558,2.6558 +009431265.jpg,809,497.499,5.70828,5.70828 +009431265.jpg,769,399.693,3.30776,3.30776 +032883305.jpg,481,338.367,4.11394,4.11394 +098925624.jpg,1020,566.411,6.61757,6.61757 +070652963.jpg,861,445.178,3.34819,3.34819 +076050200.jpg,980,490.833,3.73605,3.73605 +052317801.jpg,290,332.704,2.05866,2.05866 +052317801.jpg,181,357.567,1.79725,1.79725 +030407028.jpg,1651,569.467,5.53888,5.53888 +000855477.jpg,369,388.883,1.74026,1.74026 +002903878.jpg,310,364.388,3.11567,3.11567 +022476024.jpg,727,309.26,5.855,5.855 +009946160.jpg,386,516.781,4.73173,4.73173 +054659426.jpg,509,438.884,6.32367,6.32367 +097337920.jpg,762,460.341,4.11175,4.11175 +007338402.jpg,734,330.793,3.56609,3.56609 +087004800.jpg,722,398.835,3.90288,3.90288 +043372788.jpg,855,365.8,2.4,2.4 +059819388.jpg,1106,650.13,5.09417,5.09417 +030774952.jpg,776,500.243,5.43696,5.43696 +076080754.jpg,627,490.119,6.25994,6.25994 +025700623.jpg,848,548.608,9.38401,9.38401 +008969930.jpg,719,569.201,5.6834,5.6834 +099475369.jpg,822,393.875,3.5729,3.5729 +081913864.jpg,729,397.85,2.07087,2.07087 +093597408.jpg,792,376.56,2.7133,2.7133 +015592625.jpg,471,372.573,7.54773,7.54773 +088873579.jpg,332,425.888,6.32403,6.32403 +088873579.jpg,809,424.286,6.19048,6.19048 +087927264.jpg,432,393.008,3.08402,3.08402 +018453505.jpg,1085,622.911,6.2426,6.2426 +027320351.jpg,739,692.348,5.86237,5.86237 +053847598.jpg,1054,276.366,2.19718,2.19718 +076504319.jpg,1214,181.902,2.65851,2.65851 +076127143.jpg,486,497.942,3.07847,3.07847 +080717977.jpg,968,394.104,6.09199,6.09199 +030250396.jpg,963,325.748,3.06235,3.06235 +013177089.jpg,506,475.262,4.18852,4.18852 +005602913.jpg,402,546.958,4.66314,4.66314 +055049247.jpg,765,451.224,3.51871,3.51871 +088808038.jpg,614,165.696,2.80801,2.80801 +043982074.jpg,489,483.553,4.96271,4.96271 +035315440.jpg,435,490.758,2.47986,2.47986 +006525519.jpg,320,409.392,2.61603,2.61603 +028993709.jpg,486,471.57,2.13084,2.13084 +055770476.jpg,556,457.735,5.22793,5.22793 +001692935.jpg,277,455.074,5.25617,5.25617 +051909173.jpg,286,282.537,4.87811,4.87811 +042770117.jpg,578,213.554,2.7128,2.7128 +017483692.jpg,426,267.439,3.3699,3.3699 +078661306.jpg,340,245.417,4.36807,4.36807 +058793373.jpg,805,553.471,9.78924,9.78924 +012409688.jpg,1368,667.889,6.40744,6.40744 +077421556.jpg,557,431.151,2.76261,2.76261 +079074812.jpg,939,351.427,4.95227,4.95227 +053738384.jpg,965,342.14,4.26169,4.26169 +016012824.jpg,538,268.513,1.6261,1.6261 +016051542.jpg,917,239.296,2.35801,2.35801 +007165061.jpg,935,510.229,4.26907,4.26907 +088904212.jpg,489,485.612,6.63434,6.63434 +083578744.jpg,342,232.631,2.63591,2.63591 +038839318.jpg,497,264.578,3.79817,3.79817 +025909821.jpg,512,377.485,2.62376,2.62376 +076902324.jpg,80,806.04,1.83663,1.83663 +023746891.jpg,873,560.875,3.15628,3.15628 +023746891.jpg,1528,680.042,4.58686,4.58686 +049967024.jpg,761,332.305,2.10877,2.10877 +020316004.jpg,321,323.517,3.6264,3.6264 +068839670.jpg,1226,706.812,4.81769,4.81769 +068839670.jpg,1766,531.392,1.86604,1.86604 +027238458.jpg,487,679.256,9.60469,9.60469 +027238458.jpg,1747,437.374,2.36449,2.36449 +083206210.jpg,1110,557.573,3.63112,3.63112 +010001809.jpg,156,261.476,1.87302,1.87302 +002903990.jpg,265,239.949,2.74578,2.74578 +022550310.jpg,588,515.856,6.4047,6.4047 +052298731.jpg,633,456.904,7.242,7.242 +004322315.jpg,792,521.253,7.10443,7.10443 +039294444.jpg,889,439.669,7.63911,7.63911 +005768328.jpg,1022,297.909,4.9091,4.9091 +018640541.jpg,455,450.11,7.67584,7.67584 +076543222.jpg,465,493.259,3.35491,3.35491 +021668424.jpg,285,579.714,9.55951,9.55951 +064034735.jpg,1057,274.813,4.06774,4.06774 +026665966.jpg,429,388.608,1.88404,1.88404 +098486594.jpg,170,454.131,2.42759,2.42759 +071066725.jpg,884,452.074,7.58947,7.58947 +040121483.jpg,995,547.185,6.76545,6.76545 +014760682.jpg,747,552.954,8.9962,8.9962 +075784629.jpg,936,294.426,3.70218,3.70218 +075784629.jpg,140,178.212,3.43431,3.43431 +064119963.jpg,790,285.235,3.68622,3.68622 +064119963.jpg,303,404.457,3.28811,3.28811 +080015824.jpg,650,253.567,1.79725,1.79725 +060831940.jpg,259,429.56,2.7133,2.7133 +035613916.jpg,766,427.162,3.09684,3.09684 +074209259.jpg,357,489.44,3.53669,3.53669 +089067860.jpg,705,485.284,6.77363,6.77363 +089067860.jpg,248,491.153,3.01272,3.01272 +007608937.jpg,517,630.559,2.62992,2.62992 +060360192.jpg,1090,874.314,5.9428,5.9428 +093122476.jpg,654,730.317,5.19312,5.19312 +074615050.jpg,828,900.323,4.19357,4.19357 +069919320.jpg,527,393.785,3.73208,3.73208 +092701211.jpg,856,400.48,1.78997,1.78997 +039837768.jpg,821,556.017,2.41812,2.41812 +031909534.jpg,651,442.941,5.24511,5.24511 +001060742.jpg,536,440.363,2.94688,2.94688 +086165716.jpg,519,303.896,1.90801,1.90801 +045126780.jpg,700,444.887,6.24058,6.24058 +084339165.jpg,264,439.522,2.46018,2.46018 +062282924.jpg,510,738.337,13.6114,13.6114 +025057129.jpg,429,463.597,3.79971,3.79971 +028465539.jpg,490,507.116,5.34303,5.34303 +031000185.jpg,468,479.475,4.87295,4.87295 +031000185.jpg,955,692.657,6.63807,6.63807 +088295246.jpg,364,243.617,2.71811,2.71811 +075294860.jpg,335,272.943,2.6619,2.6619 +075294860.jpg,119,290.582,4.46517,4.46517 +093504420.jpg,335,228.557,2.62975,2.62975 +093504420.jpg,120,264.237,3.43641,3.43641 +028544779.jpg,94,261.453,3.87105,3.87105 +061505117.jpg,110,337.439,3.53657,3.53657 +045754541.jpg,727,518.303,3.69195,3.69195 +045754541.jpg,1122,552.689,3.47405,3.47405 +056620482.jpg,1333,650.483,2.04022,2.04022 +089825908.jpg,1014,545.826,4.15216,4.15216 +050857792.jpg,351,285.175,1.43122,1.43122 +060603345.jpg,68,290.671,1.55596,1.55596 +021158213.jpg,386,282.818,1.81816,1.81816 +061406498.jpg,63,327.575,2.04793,2.04793 +019067595.jpg,1625,750.129,7.34412,7.34412 +077812566.jpg,739,457.049,5.67071,5.67071 +072446042.jpg,728,313.743,2.47859,2.47859 +046382172.jpg,1103,631.159,6.84658,6.84658 +046382172.jpg,364,456.15,6.51249,6.51249 +065394367.jpg,729,491.075,3.75623,3.75623 +021371297.jpg,577,551.452,5.53766,5.53766 +039825641.jpg,766,634.77,6.56418,6.56418 +020638674.jpg,734,459.708,5.39233,5.39233 +055091264.jpg,644,495.512,5.2093,5.2093 +066038644.jpg,324,361.334,2.27783,2.27783 +073569751.jpg,441,416.778,3.64818,3.64818 +035276847.jpg,441,497.577,5.29812,5.29812 +042809288.jpg,633,827.667,3.88891,3.88891 +010849835.jpg,1501,696.943,7.99521,7.99521 +040724642.jpg,442,268.321,4.11011,4.11011 +089733897.jpg,699,485.964,5.58032,5.58032 +037637063.jpg,295,259.922,3.82685,3.82685 +054424971.jpg,318,287.009,1.58405,1.58405 +005539073.jpg,180,311.88,1.74,1.74 +072303443.jpg,797,431.446,7.62053,7.62053 +037616511.jpg,386,620.454,9.3712,9.3712 +025708182.jpg,595,412.385,4.78206,4.78206 +033965185.jpg,458,444.792,5.89933,5.89933 +055179006.jpg,1194,557.649,8.72072,8.72072 +006400008.jpg,776,272.449,2.37076,2.37076 +013622778.jpg,45,384.132,2.84431,2.84431 +061578980.jpg,368,592.136,4.09464,4.09464 +037111969.jpg,762,375.495,3.37457,3.37457 +089770523.jpg,504,366.143,3.09524,3.09524 +089770523.jpg,453,441.95,2.91247,2.91247 +097969175.jpg,538,340.581,1.46509,1.46509 +088034820.jpg,796,691.183,4.68192,4.68192 +011197297.jpg,696,426.274,5.10617,5.10617 +006487364.jpg,1616,689.73,7.39419,7.39419 +086799393.jpg,355,722.837,8.56977,8.56977 +008366341.jpg,638,716.84,7.98665,7.98665 +027331236.jpg,625,721.436,8.86971,8.86971 +012766663.jpg,1516,657.58,6.54832,6.54832 +080254830.jpg,1351,598.491,8.0409,8.0409 +000966627.jpg,675,771.991,14.0826,14.0826 +022337144.jpg,229,208.993,1.41605,1.41605 +003328555.jpg,804,357.615,4.63459,4.63459 +050284371.jpg,193,158.807,1.31727,1.31727 +051182776.jpg,605,373.896,3.40801,3.40801 +093386704.jpg,501,438.987,3.74892,3.74892 +085442296.jpg,777,576.015,4.5846,4.5846 +085442296.jpg,89,510.277,4.93972,4.93972 +058797425.jpg,1436,534.151,3.76258,3.76258 +027687052.jpg,620,527.6,3.3,3.3 +027687052.jpg,75,492.676,2.55635,2.55635 +039768114.jpg,1359,691.262,5.27181,5.27181 +068026563.jpg,1301,796.014,5.16784,5.16784 +004106637.jpg,676,829.641,8.4701,8.4701 +007153882.jpg,744,464.627,5.55227,5.55227 +032505152.jpg,1020,305.323,3.61024,3.61024 +026493089.jpg,983,438.169,2.43074,2.43074 +026493089.jpg,1227,483.692,2.30766,2.30766 +023812207.jpg,1352,319.887,2.57389,2.57389 +042385789.jpg,1486,448.985,3.58208,3.58208 +036813359.jpg,985,522.409,5.20074,5.20074 +036813359.jpg,1504,409.322,2.61017,2.61017 +032687879.jpg,1090,649.368,7.44731,7.44731 +017264064.jpg,343,271.586,1.63218,1.63218 +027379799.jpg,366,232.792,2.31603,2.31603 +094824454.jpg,599,650.075,5.17289,5.17289 +071887798.jpg,332,346.408,2.03404,2.03404 +053198180.jpg,558,170.26,2.18836,2.18836 +004466003.jpg,633,387.247,2.93724,2.93724 +098992149.jpg,659,457.745,6.81211,6.81211 +054477962.jpg,49,381.11,4.67586,4.67586 +089544531.jpg,912,691.656,4.55467,4.55467 +076443286.jpg,933,639.854,5.1545,5.1545 +084102764.jpg,972,751.026,5.25214,5.25214 +076181310.jpg,1094,606.938,6.57815,6.57815 +007639332.jpg,526,497.885,3.40708,3.40708 +055669567.jpg,484,384.128,3.6773,3.6773 +097980316.jpg,610,704.888,4.82403,4.82403 +033790143.jpg,772,734.931,4.74427,4.74427 +088872773.jpg,1012,689.686,6.39049,6.39049 +089410760.jpg,1000,605.451,4.62088,4.62088 +078529467.jpg,1310,607.163,6.18029,6.18029 +047623281.jpg,631,431.051,3.33756,3.33756 +043961723.jpg,151,401.576,1.3813,1.3813 +064958094.jpg,819,522.046,2.9205,2.9205 +015745296.jpg,545,392.129,4.3441,4.3441 +076464961.jpg,265,316.689,1.97408,1.97408 +077851429.jpg,1031,218.304,1.69201,1.69201 +093644642.jpg,420,352.144,2.17867,2.17867 +033811092.jpg,837,279.608,2.63403,2.63403 +010150386.jpg,634,479.8,3.15,3.15 +032602345.jpg,721,348.6,4.05,4.05 +004572661.jpg,1014,555.955,3.9129,3.9129 +094535813.jpg,663,608.415,4.86796,4.86796 +030277359.jpg,302,589.579,3.04821,3.04821 +067256720.jpg,671,285.36,2.69666,2.69666 +069050663.jpg,1043,509.822,6.15183,6.15183 +069050663.jpg,674,409.257,2.35476,2.35476 +004592006.jpg,1122,588.944,2.32863,2.32863 +023590087.jpg,1028,616.675,4.05622,4.05622 +073655720.jpg,1285,629.083,2.92358,2.92358 +008745016.jpg,542,872.766,8.06381,8.06381 +008745016.jpg,771,688.065,2.83877,2.83877 +008745016.jpg,1008,693.713,2.97605,2.97605 +008745016.jpg,1285,638.674,3.05617,3.05617 +002024938.jpg,997,681.296,2.85804,2.85804 +078679671.jpg,659,724.036,6.25304,6.25304 +078679671.jpg,1054,681.153,2.84605,2.84605 +068199745.jpg,543,476.219,4.85157,4.85157 +062898839.jpg,1077,650.354,8.19621,8.19621 +059106208.jpg,1307,646.331,4.19421,4.19421 +019371594.jpg,1063,462.307,5.7756,5.7756 +023453087.jpg,799,535.243,6.27029,6.27029 +070684436.jpg,432,370.583,2.1319,2.1319 +097029373.jpg,709,490.161,4.51338,4.51338 +075171704.jpg,751,419.086,6.50717,6.50717 +052228947.jpg,1475,286.303,2.60862,2.60862 +035997352.jpg,1638,405.992,2.16603,2.16603 +043198759.jpg,806,717.008,6.83401,6.83401 +048247544.jpg,1081,418.682,2.64017,2.64017 +090027703.jpg,234,490.102,3.34187,3.34187 +090027703.jpg,943,544.867,7.32227,7.32227 +070815169.jpg,135,369.48,3.37337,3.37337 +096701599.jpg,389,240.972,1.83098,1.83098 +059696029.jpg,362,371.091,3.75755,3.75755 +071545096.jpg,522,290.656,4.55467,4.55467 +025991647.jpg,617,544.224,6.76864,6.76864 +069558517.jpg,131,416.272,2.68931,2.68931 +067386539.jpg,591,463.688,4.22404,4.22404 +016962409.jpg,952,407.279,1.52322,1.52322 +016962409.jpg,710,392.485,1.37379,1.37379 +069735807.jpg,130,377.663,6.13857,6.13857 +006845317.jpg,553,232.986,3.41552,3.41552 +016928621.jpg,1159,725.184,9.09866,9.09866 +028496828.jpg,1770,620.622,4.5518,4.5518 +028496828.jpg,530,553.081,3.84012,3.84012 +081562177.jpg,1382,489.93,5.8275,5.8275 +043176754.jpg,530,338.358,2.36315,2.36315 +003086813.jpg,1259,700.073,8.25611,8.25611 +016566317.jpg,1823,601.998,3.49986,3.49986 +012261922.jpg,173,438.378,3.1982,3.1982 +012261922.jpg,1042,513.635,3.55294,3.55294 +088643606.jpg,927,612.738,6.89485,6.89485 +023902564.jpg,1357,462.664,2.30532,2.30532 +087976694.jpg,307,514.656,2.47132,2.47132 +063117420.jpg,881,932.963,9.49693,9.49693 +016095549.jpg,887,587.837,2.73642,2.73642 +038264116.jpg,594,451.054,3.42118,3.42118 +062744561.jpg,77,350.975,3.33122,3.33122 +000025245.jpg,1450,445.348,3.44569,3.44569 +076317439.jpg,1564,499.635,4.38626,4.38626 +090844621.jpg,416,331.346,3.36214,3.36214 +090844621.jpg,1499,346.036,3.753,3.753 +060798823.jpg,612,374.124,1.26036,1.26036 +018277390.jpg,346,383.276,2.85631,2.85631 +065211398.jpg,1471,700.367,7.28061,7.28061 +077413466.jpg,708,542.225,4.01877,4.01877 +077413466.jpg,1013,614.323,3.7769,3.7769 +072255410.jpg,734,479.236,4.01966,4.01966 +060176444.jpg,1210,334.89,3.90749,3.90749 +048331822.jpg,742,384.258,3.77154,3.77154 +003048326.jpg,1395,493.108,8.42568,8.42568 +051144283.jpg,673,261.682,1.64015,1.64015 +056522638.jpg,421,254.496,1.45801,1.45801 +090083698.jpg,384,355.759,2.22991,2.22991 +034854665.jpg,782,485.739,3.97825,3.97825 +042325914.jpg,763,481.031,9.58593,9.58593 +066700153.jpg,454,581.089,2.42407,2.42407 +007979705.jpg,1130,413.08,2.42332,2.42332 +092076481.jpg,673,404.566,3.6305,3.6305 +097360765.jpg,301,566.896,4.158,4.158 +097360765.jpg,1816,282.745,3.14543,3.14543 +092706912.jpg,1740,435.359,2.86323,2.86323 +026244807.jpg,705,425.169,5.43075,5.43075 +044131111.jpg,280,343.872,2.32263,2.32263 +031416741.jpg,647,448.662,2.05516,2.05516 +031416741.jpg,1043,330.662,2.05516,2.05516 +031416741.jpg,1166,327.767,2.0639,2.0639 +051685853.jpg,619,368.817,2.56811,2.56811 +021824705.jpg,1004,481.985,3.58208,3.58208 +080356760.jpg,426,280.155,2.92957,2.92957 +058844383.jpg,285,248.876,2.40637,2.40637 +036282003.jpg,284,277.585,2.38212,2.38212 +043907061.jpg,750,699.448,12.1207,12.1207 +090586056.jpg,378,732.169,10.0141,10.0141 +002898693.jpg,719,287.779,2.89822,2.89822 +001594569.jpg,893,455.397,5.69976,5.69976 +009137144.jpg,440,158.482,3.54013,3.54013 +070412235.jpg,1121,411.356,3.61298,3.61298 +066182929.jpg,365,414.636,4.1363,4.1363 +044908796.jpg,616,774.549,4.12912,4.12912 +066158202.jpg,1009,336.737,3.47806,3.47806 +016285829.jpg,900,463.108,5.50898,5.50898 +004014777.jpg,899,367.592,5.46601,5.46601 +072925197.jpg,904,479.983,4.16525,4.16525 +087030378.jpg,897,758.872,13.9893,13.9893 +034901871.jpg,851,490.627,4.38554,4.38554 +076617640.jpg,868,583.704,6.642,6.642 +073993125.jpg,1040,533.767,7.48059,7.48059 +035491784.jpg,644,430.112,4.75933,4.75933 +011585278.jpg,271,343.324,4.36033,4.36033 +051631656.jpg,1023,441.399,6.78325,6.78325 +052618281.jpg,555,619.067,5.17228,5.17228 +051329358.jpg,984,438.486,11.1238,11.1238 +051329358.jpg,184,217.738,1.06151,1.06151 +093294504.jpg,984,498.9,7.49166,7.49166 +003291859.jpg,272,270.889,5.24073,5.24073 +055436404.jpg,1642,952.129,11.0941,11.0941 +014337567.jpg,253,653.938,12.4115,12.4115 +074708621.jpg,629,379.001,11.6667,11.6667 +039835532.jpg,628,298.871,2.48928,2.48928 +052739351.jpg,507,454.884,6.32367,6.32367 +052739351.jpg,230,299.987,1.33222,1.33222 +057386277.jpg,558,260.262,4.18852,4.18852 +061617908.jpg,498,405.886,4.07382,4.07382 +083154533.jpg,966,459.22,6.51836,6.51836 +091519371.jpg,417,266.652,2.88765,2.88765 +066742801.jpg,1269,348.776,2.31467,2.31467 +083247800.jpg,565,502.814,5.98453,5.98453 +040918937.jpg,826,457.962,2.41346,2.41346 +040499704.jpg,1095,383.387,1.03228,1.03228 +053304329.jpg,902,521.691,1.89095,1.89095 +079050838.jpg,484,494.313,4.94272,4.94272 +041851639.jpg,636,315.969,1.66412,1.66412 +009820889.jpg,484,366.722,2.14348,2.14348 +051450216.jpg,929,530.285,2.35705,2.35705 +051450216.jpg,690,411.742,2.14516,2.14516 +051450216.jpg,26,485.795,2.48294,2.48294 +013645112.jpg,1057,424.048,3.254,3.254 +013645112.jpg,756,470.846,3.5705,3.5705 +079812505.jpg,719,449.763,3.3969,3.3969 +079812505.jpg,485,504.153,2.84605,2.84605 +076121152.jpg,1095,502.686,4.39047,4.39047 +076121152.jpg,433,541.192,4.26602,4.26602 +066344439.jpg,394,417.045,2.17039,2.17039 +095342698.jpg,1018,627.337,1.19474,1.19474 +018064373.jpg,1074,518.075,3.75623,3.75623 +018064373.jpg,1488,538.02,5.08498,5.08498 +042662537.jpg,547,588.671,3.05588,3.05588 +042662537.jpg,1064,332.552,2.21269,2.21269 +033482785.jpg,1576,647.432,4.20268,4.20268 +056563345.jpg,515,492.856,2.40468,2.40468 +056563345.jpg,48,579.708,1.97568,1.97568 +002305278.jpg,655,507.916,4.65967,4.65967 +075115370.jpg,1041,542.96,1.66331,1.66331 +075162055.jpg,871,228.282,1.2735,1.2735 +075162055.jpg,79,300.268,1.85564,1.85564 +075162055.jpg,692,226.356,1.52971,1.52971 +085635335.jpg,1120,631.542,8.62853,8.62853 +052319225.jpg,1188,607.167,12.0139,12.0139 +036245985.jpg,851,596.16,4.59666,4.59666 +036245985.jpg,212,680.93,5.24417,5.24417 +077715291.jpg,391,369.954,3.9962,3.9962 +054992107.jpg,595,345.976,4.498,4.498 +026963617.jpg,575,413.538,4.87821,4.87821 +016999630.jpg,433,191.056,2.58801,2.58801 +001399341.jpg,927,738.712,7.47602,7.47602 +069342580.jpg,1297,496.566,8.38053,8.38053 +025669855.jpg,476,680.619,10.1349,10.1349 +043976850.jpg,1209,864.444,5.53701,5.53701 +039317703.jpg,802,605.361,4.86342,4.86342 +027992962.jpg,705,865.798,5.06654,5.06654 +080535767.jpg,468,842.683,5.47358,5.47358 +047598305.jpg,494,662.036,3.753,3.753 +076341781.jpg,358,481.17,6.01416,6.01416 +029190961.jpg,979,589.745,4.31208,4.31208 +037119299.jpg,372,379.901,4.57507,4.57507 +014764349.jpg,378,296.035,4.08628,4.08628 +098992314.jpg,176,246.655,3.38788,3.38788 +014868439.jpg,591,415.446,4.53715,4.53715 +054521108.jpg,332,212.39,1.69918,1.69918 +054110292.jpg,574,352.766,2.64715,2.64715 +059609853.jpg,1150,433.377,2.11473,2.11473 +088391840.jpg,823,394.18,6.76498,6.76498 +050874029.jpg,738,332.502,2.12514,2.12514 +090626579.jpg,470,212.584,2.9653,2.9653 +069072289.jpg,746,650.167,7.59729,7.59729 +072950383.jpg,1233,727.235,4.3529,4.3529 +078091525.jpg,947,434.919,5.24322,5.24322 +078760115.jpg,565,639.057,4.75479,4.75479 +002772532.jpg,694,623.153,4.17938,4.17938 +005688744.jpg,513,669.958,5.16314,5.16314 +010561705.jpg,199,662.942,6.32851,6.32851 +026532407.jpg,942,616.991,4.58254,4.58254 +070789203.jpg,211,251.35,1.27914,1.27914 +048416425.jpg,603,337.161,4.51338,4.51338 +045777935.jpg,1294,914.482,13.7901,13.7901 +001630590.jpg,645,777.408,11.784,11.784 +083512616.jpg,813,730.889,9.99072,9.99072 +019251887.jpg,588,571.341,12.1118,12.1118 +019251887.jpg,97,548.578,4.54814,4.54814 +044809111.jpg,567,516.644,5.13701,5.13701 +062650331.jpg,856,438.114,4.67615,4.67615 +012481767.jpg,501,417.175,4.59793,4.59793 +078483725.jpg,308,370.273,4.27276,4.27276 +077456025.jpg,364,278.354,2.69616,2.69616 +097236548.jpg,389,313.266,2.68881,2.68881 +016551974.jpg,586,426.992,4.41602,4.41602 +041090206.jpg,367,300.626,5.05213,5.05213 +035462709.jpg,525,256.556,3.46302,3.46302 +073855704.jpg,475,205.312,2.35934,2.35934 +061200390.jpg,994,551.653,6.05443,6.05443 +056733993.jpg,619,359.247,3.10395,3.10395 +028479199.jpg,398,371.179,2.59825,2.59825 +072387104.jpg,435,358.267,2.27229,2.27229 +044823885.jpg,448,285.218,2.26813,2.26813 +060694541.jpg,237,607.327,9.36062,9.36062 +022986959.jpg,324,412.367,7.28061,7.28061 +011468124.jpg,452,497.949,8.41242,8.41242 +065329024.jpg,302,618.625,9.80206,9.80206 +099039780.jpg,931,494.597,8.46643,8.46643 +035392768.jpg,1236,711.132,7.26099,7.26099 +074641894.jpg,929,797.41,3.03416,3.03416 +061351468.jpg,959,836.221,2.18506,2.18506 +046325660.jpg,1043,542.443,12.4536,12.4536 +029849411.jpg,471,415.254,6.10447,6.10447 +095749156.jpg,570,178.103,1.42524,1.42524 +026217155.jpg,741,440.456,2.12132,2.12132 +078082583.jpg,873,428.339,5.02829,5.02829 +090320667.jpg,728,321.02,2.33499,2.33499 +039484100.jpg,694,327.596,2.21635,2.21635 +016860169.jpg,691,147.393,1.11606,1.11606 +060981166.jpg,624,173.98,1.16499,1.16499 +010636413.jpg,282,209.69,1.22413,1.22413 +037022949.jpg,1058,277.611,1.46755,1.46755 +080874223.jpg,893,303.758,1.8132,1.8132 +005495787.jpg,486,319.875,3.15628,3.15628 +094095662.jpg,1068,285.441,1.53675,1.53675 +065877768.jpg,523,272.896,3.40801,3.40801 +016656625.jpg,920,289.618,1.96815,1.96815 +075492684.jpg,982,313.2,2.1,2.1 +075492684.jpg,779,256.673,1.47275,1.47275 +030667397.jpg,502,366.913,2.82606,2.82606 +079956032.jpg,658,338.664,3.13869,3.13869 +046191929.jpg,640,582.701,9.39173,9.39173 +088693393.jpg,709,419.829,4.65242,4.65242 +084304344.jpg,292,481.874,5.98949,5.98949 +090120874.jpg,643,274.076,2.08969,2.08969 +090120874.jpg,306,555.297,6.35809,6.35809 +006372333.jpg,1085,409.27,2.77253,2.77253 +038778316.jpg,373,303.324,1.36029,1.36029 +095084103.jpg,807,531.961,4.08011,4.08011 +062276119.jpg,742,462.334,2.27783,2.27783 +004651850.jpg,324,102.068,1.7557,1.7557 +024789697.jpg,136,248.545,3.2121,3.2121 +009537381.jpg,353,201.931,3.74424,3.74424 +042391259.jpg,397,359.567,1.79725,1.79725 +091514074.jpg,206,292.851,2.82096,2.82096 +034155123.jpg,1041,749.853,7.15442,7.15442 +066011944.jpg,1168,507.757,2.31311,2.31311 +017872013.jpg,1203,671.439,3.45326,3.45326 +091527798.jpg,658,481.096,10.9247,10.9247 +011292659.jpg,1029,504.485,2.62376,2.62376 +036799966.jpg,690,390.395,2.78289,2.78289 +075781331.jpg,662,381.316,3.77631,3.77631 +067068776.jpg,622,568.354,4.0295,4.0295 +074108580.jpg,441,182.913,2.82606,2.82606 +010470516.jpg,486,181.651,2.72092,2.72092 +028737992.jpg,249,392.698,4.89147,4.89147 +036338337.jpg,152,286.488,4.37404,4.37404 +016026660.jpg,972,310.964,4.41367,4.41367 +073221756.jpg,1112,421.008,4.58402,4.58402 +058944322.jpg,542,565.585,3.88207,3.88207 +008516717.jpg,1251,848.121,11.3434,11.3434 +068658093.jpg,261,598.459,5.95491,5.95491 +068658093.jpg,757,484.664,3.13869,3.13869 +068658093.jpg,1115,700.713,8.72608,8.72608 +073979499.jpg,1305,678.592,4.54933,4.54933 +073979499.jpg,1597,755.864,3.9053,3.9053 +015386297.jpg,1296,627.133,9.34446,9.34446 +081040993.jpg,1114,603.296,4.608,4.608 +056835505.jpg,619,598.656,4.55467,4.55467 +010864878.jpg,1088,726.34,5.69502,5.69502 +024269440.jpg,756,279.27,2.77253,2.77253 +051746555.jpg,450,513.12,4.34337,4.34337 +084336113.jpg,762,278.046,2.9205,2.9205 +090535090.jpg,500,370.155,2.92957,2.92957 +050834710.jpg,1035,749.73,4.31082,4.31082 +051684846.jpg,192,343.325,1.11041,1.11041 +051684846.jpg,686,306.552,1.12929,1.12929 +076985801.jpg,628,282.218,1.51819,1.51819 +041078174.jpg,523,189.586,0.798812,0.798812 +037529808.jpg,266,216.09,0.924175,0.924175 +004433225.jpg,797,307.053,4.5044,4.5044 +011116933.jpg,887,511.449,2.87077,2.87077 +064384720.jpg,1291,477.461,2.12174,2.12174 +011681232.jpg,858,310.068,1.7557,1.7557 +001155628.jpg,76,516.081,6.09007,6.09007 +091298541.jpg,489,551.992,4.41602,4.41602 +091298541.jpg,897,520.609,3.88404,3.88404 +021998020.jpg,484,589.439,5.36992,5.36992 +060810119.jpg,821,587.381,4.19839,4.19839 +078706950.jpg,732,556.009,1.58405,1.58405 +054010744.jpg,222,427.61,2.30083,2.30083 +072165855.jpg,803,561.672,1.63933,1.63933 +021884082.jpg,530,282.991,2.66595,2.66595 +088903604.jpg,317,303.361,2.61345,2.61345 +050340411.jpg,248,229.746,3.22887,3.22887 +077181821.jpg,628,383.892,5.07435,5.07435 +021741683.jpg,574,413.926,4.91048,4.91048 +088626138.jpg,288,273.408,2.45065,2.45065 +077722852.jpg,386,329.238,2.43647,2.43647 +089009842.jpg,338,320.364,2.44698,2.44698 +022413218.jpg,837,370.592,2.46603,2.46603 +089861181.jpg,452,220.768,1.89737,1.89737 +024965009.jpg,616,417.561,4.71344,4.71344 +086961700.jpg,465,409.646,4.13717,4.13717 +077589708.jpg,684,359.541,3.37843,3.37843 +018650058.jpg,248,247.345,2.02872,2.02872 +046332594.jpg,281,300.843,3.23694,3.23694 +081295298.jpg,433,226.971,4.08088,4.08088 +099469013.jpg,616,439.192,5.01601,5.01601 +004664145.jpg,581,631.501,7.37512,7.37512 +041143624.jpg,286,400.439,5.03661,5.03661 +049956231.jpg,748,457.302,5.44184,5.44184 +090408171.jpg,636,266.088,1.34063,1.34063 +003382164.jpg,595,273.2,1.35,1.35 +043593449.jpg,319,231.218,1.51819,1.51819 +098540478.jpg,170,229.076,1.33963,1.33963 +069124041.jpg,286,538.704,1.39201,1.39201 +085093083.jpg,149,255.333,1.94445,1.94445 +064966316.jpg,524,471.696,1.30801,1.30801 +084980226.jpg,1257,757.255,3.27124,3.27124 +025938000.jpg,586,692.124,1.26036,1.26036 +028815695.jpg,840,355.414,3.78452,3.78452 +034582616.jpg,572,515.289,3.02405,3.02405 +067714494.jpg,735,652.839,2.73659,2.73659 +040065500.jpg,207,519.387,7.61557,7.61557 +070604098.jpg,592,422.606,5.13386,5.13386 +092535491.jpg,383,502.296,8.60796,8.60796 +070819594.jpg,1393,560.969,7.99741,7.99741 +040881141.jpg,175,634.238,8.26983,8.26983 +014854515.jpg,926,599.143,8.17856,8.17856 +018828035.jpg,661,297.494,1.87446,1.87446 +018873985.jpg,583,275.183,1.84859,1.84859 +050639670.jpg,705,455.609,3.88404,3.88404 +076640502.jpg,265,266.233,2.10278,2.10278 +082886257.jpg,229,323.77,5.98084,5.98084 +079248773.jpg,197,572.453,7.37109,7.37109 +013795101.jpg,485,259.828,3.31904,3.31904 +013795101.jpg,179,324.238,3.43654,3.43654 +010814960.jpg,319,422.06,7.00498,7.00498 +098155174.jpg,307,435.293,4.1911,4.1911 +098155174.jpg,992,611.911,5.99257,5.99257 +050070559.jpg,529,212.569,4.71411,4.71411 +038371535.jpg,401,152.758,1.8132,1.8132 +038371535.jpg,529,405.293,4.52443,4.52443 +046394654.jpg,337,369.721,8.14344,8.14344 +068272118.jpg,657,344.232,3.26931,3.26931 +052278573.jpg,788,380.987,3.74892,3.74892 +071556964.jpg,394,343.512,5.37603,5.37603 +019759738.jpg,683,314.741,4.47845,4.47845 +055375584.jpg,631,581.235,4.3529,4.3529 +002158991.jpg,905,497.752,6.06267,6.06267 +079210578.jpg,552,240.621,1.7184,1.7184 +091929844.jpg,700,338.53,4.79418,4.79418 +076220077.jpg,262,321.335,1.52794,1.52794 +076220077.jpg,166,268.371,1.69759,1.69759 +095038429.jpg,252,297.843,1.23693,1.23693 +050731850.jpg,130,202.896,1.15802,1.15802 +015877629.jpg,965,530.481,7.54009,7.54009 +016456288.jpg,1070,698.363,8.28022,8.28022 +033198339.jpg,479,378.858,7.82149,7.82149 +048189089.jpg,384,297.485,4.54042,4.54042 +099606696.jpg,498,402.16,3.84667,3.84667 +015087805.jpg,555,482.763,3.31361,3.31361 +012511616.jpg,1189,649.319,6.77661,6.77661 +065546570.jpg,302,281.437,1.78645,1.78645 +023437159.jpg,484,319.985,3.41539,3.41539 +059919709.jpg,928,815.659,4.22159,4.22159 +087404591.jpg,1166,600.192,5.76601,5.76601 +089687824.jpg,345,255.559,4.2966,4.2966 +033967634.jpg,955,893.261,8.27179,8.27179 +058103832.jpg,624,590.601,6.71678,6.71678 +073411530.jpg,566,574.667,6.8889,6.8889 +086862727.jpg,379,222.669,1.88905,1.88905 +050766000.jpg,749,579.064,3.33864,3.33864 +041575439.jpg,84,420.492,2.29103,2.29103 +089514716.jpg,775,766.782,4.31521,4.31521 +078814401.jpg,1515,898.706,4.30884,4.30884 +078814401.jpg,246,985.142,6.92851,6.92851 +099590664.jpg,753,730.671,4.13924,4.13924 +077757503.jpg,207,310.474,2.20617,2.20617 +071010409.jpg,983,400.621,1.7184,1.7184 +088482970.jpg,619,391.639,1.80325,1.80325 +051390471.jpg,876,397.898,1.82483,1.82483 +019209765.jpg,709,569.022,5.58516,5.58516 +033944221.jpg,900,636.442,7.87013,7.87013 +012369183.jpg,479,489.312,5.52603,5.52603 +023232379.jpg,429,390.739,5.47827,5.47827 +071927139.jpg,552,414.308,8.35897,8.35897 +068240616.jpg,489,355.831,9.65259,9.65259 +087457952.jpg,794,464.441,6.78677,6.78677 +059695140.jpg,720,753.121,10.26,10.26 +059109880.jpg,603,430.175,3.51461,3.51461 +054600675.jpg,467,377.345,2.52873,2.52873 +035861105.jpg,336,179.386,1.78216,1.78216 +007558509.jpg,1010,314.665,5.05542,5.05542 +053725227.jpg,973,399.533,4.71105,4.71105 +084481605.jpg,912,441.59,6.13249,6.13249 +092323938.jpg,254,423.24,5.76999,5.76999 +006583774.jpg,470,460.712,2.14264,2.14264 +040914542.jpg,652,446.511,2.37588,2.37588 +064646852.jpg,818,316.251,3.43759,3.43759 +025520212.jpg,555,327.955,2.4129,2.4129 +046625674.jpg,401,266.696,3.22469,3.22469 +000338399.jpg,358,235.144,2.17867,2.17867 +053929826.jpg,371,276.479,2.20658,2.20658 +070913699.jpg,645,433.672,5.88933,5.88933 +052154145.jpg,1045,485.095,5.00793,5.00793 +031517870.jpg,395,441.206,6.26713,6.26713 +071002273.jpg,305,412.525,6.71042,6.71042 +001763483.jpg,677,796.744,11.812,11.812 +089334295.jpg,918,468.088,6.92402,6.92402 +006040187.jpg,1015,473.152,9.92932,9.92932 +060685970.jpg,671,546.878,7.07313,7.07313 +086229253.jpg,288,196.78,2.1483,2.1483 +024765010.jpg,316,209.285,2.35705,2.35705 +060836859.jpg,322,370.089,1.6741,1.6741 +093033143.jpg,392,323.224,3.51871,3.51871 +035882861.jpg,144,269.693,2.05779,2.05779 +080558425.jpg,469,254.874,1.73948,1.73948 +097139627.jpg,243,178.513,1.1261,1.1261 +031870390.jpg,244,232.264,1.1887,1.1887 +027331932.jpg,500,392.489,2.12408,2.12408 +079603715.jpg,528,479.482,3.95682,3.95682 +094645809.jpg,555,400.535,5.96125,5.96125 +073085177.jpg,640,353.554,6.62952,6.62952 +017286052.jpg,663,454.711,3.30926,3.30926 +057576188.jpg,1035,580.7,7.80836,7.80836 +087024166.jpg,201,421.234,5.51951,5.51951 +026915364.jpg,194,252.722,2.14348,2.14348 +082295032.jpg,423,308.011,3.58422,3.58422 +053662090.jpg,1004,450.884,1.49037,1.49037 +027952789.jpg,1037,338.096,2.50801,2.50801 +012802476.jpg,845,453.359,2.86323,2.86323 +011654669.jpg,1041,207.595,1.38293,1.38293 +023034416.jpg,653,332.247,0.93723,0.93723 +003286273.jpg,547,249.715,0.726223,0.726223 +013590738.jpg,825,474.769,1.06405,1.06405 +057963057.jpg,833,244.814,3.56786,3.56786 +066895308.jpg,782,452.611,6.13425,6.13425 +043798602.jpg,708,471.479,4.45659,4.45659 +042684279.jpg,703,572.678,3.97316,3.97316 +029341091.jpg,934,614.799,3.98323,3.98323 +069091782.jpg,644,330.249,2.52071,2.52071 +070690090.jpg,775,484.366,1.86387,1.86387 +028468569.jpg,126,295.244,3.52037,3.52037 +025987963.jpg,739,448.302,2.52517,2.52517 +061355930.jpg,392,323.525,3.12706,3.12706 +094573842.jpg,388,205.982,3.08183,3.08183 +036681009.jpg,1119,527.942,3.07847,3.07847 +080713283.jpg,776,885.73,2.22749,2.22749 +080594489.jpg,557,457.014,12.0845,12.0845 +097627160.jpg,460,577.646,8.72046,8.72046 +073804181.jpg,192,434.668,3.88902,3.88902 +076898400.jpg,411,278.655,3.63793,3.63793 +028163579.jpg,238,343.286,4.69047,4.69047 +028163579.jpg,628,282.194,3.84948,3.84948 +087730619.jpg,633,245.668,3.47236,3.47236 +029520900.jpg,324,401.549,4.96244,4.96244 +028519543.jpg,465,377.055,4.25461,4.25461 +023351186.jpg,245,324.726,3.81047,3.81047 +038160922.jpg,619,663.07,8.42252,8.42252 +061548842.jpg,1138,549.603,3.55028,3.55028 +040472531.jpg,365,643.288,5.52399,5.52399 +099734455.jpg,915,678.132,3.51103,3.51103 +023018128.jpg,323,301.922,2.91015,2.91015 +094913215.jpg,409,199.661,2.13843,2.13843 +021847043.jpg,332,213.374,2.36449,2.36449 +046038088.jpg,312,284.141,3.6784,3.6784 +041618766.jpg,911,811.916,11.9097,11.9097 +043871155.jpg,252,679.623,5.21862,5.21862 +036113752.jpg,1340,551.262,2.93847,2.93847 +092033356.jpg,925,645.707,7.14227,7.14227 +079393871.jpg,397,252.572,3.38096,3.38096 +006941696.jpg,1066,329.257,7.52145,7.52145 +005314959.jpg,515,507.165,4.93042,4.93042 +026773722.jpg,595,335.017,3.16809,3.16809 +092189580.jpg,643,455,6,6 +085956759.jpg,471,775.57,12.1308,12.1308 +062281892.jpg,797,705.43,5.20247,5.20247 +054373896.jpg,823,666.018,4.41816,4.41816 +044253722.jpg,727,570.826,9.4855,9.4855 +089129293.jpg,518,507.186,5.93219,5.93219 +048271005.jpg,602,243.383,1.78191,1.78191 +075160487.jpg,668,415.453,1.62111,1.62111 +072274077.jpg,692,441.098,3.67485,3.67485 +065721320.jpg,413,281.86,6.32168,6.32168 +065210834.jpg,136,348.766,2.64715,2.64715 +040992793.jpg,1038,533.669,3.13912,3.13912 +029020050.jpg,1204,831.712,10.8094,10.8094 +098551229.jpg,561,254.218,1.51819,1.51819 +098551229.jpg,286,256.915,2.49289,2.49289 +024607414.jpg,1035,792.065,5.75539,5.75539 +020594864.jpg,1158,677.479,9.95661,9.95661 +096473756.jpg,1032,768.043,7.92023,7.92023 +002262156.jpg,541,454.919,4.57655,4.57655 +013971019.jpg,1150,734.225,9.85207,9.85207 +059619645.jpg,382,259.33,2.69416,2.69416 +008564467.jpg,377,643.436,6.70297,6.70297 +063157811.jpg,349,387.432,4.20268,4.20268 +063157811.jpg,209,405.628,4.88567,4.88567 +038941354.jpg,186,373.753,4.81273,4.81273 +035113781.jpg,818,374.94,4.41163,4.41163 +029870090.jpg,281,382.585,4.63206,4.63206 +029870090.jpg,417,394.511,6.62593,6.62593 +069562775.jpg,259,276.369,2.28079,2.28079 +069562775.jpg,516,332.652,2.88765,2.88765 +062030309.jpg,354,303.513,1.1261,1.1261 +037438278.jpg,444,287.393,1.11606,1.11606 +037438278.jpg,59,269.87,1.40584,1.40584 +020826782.jpg,404,297.784,1.14865,1.14865 +084867956.jpg,346,353.987,4.16557,4.16557 +084867956.jpg,618,392.669,3.13912,3.13912 +087994674.jpg,759,303.973,1.74774,1.74774 +046001210.jpg,603,464.323,3.02688,3.02688 +037676774.jpg,854,353.178,4.09816,4.09816 +007771198.jpg,1120,435.656,4.55467,4.55467 +007771198.jpg,126,393.85,2.07087,2.07087 +059398075.jpg,666,438.394,2.3662,2.3662 +059398075.jpg,596,425.592,2.46603,2.46603 +028714427.jpg,614,461.219,4.26823,4.26823 +084795057.jpg,820,457.528,4.2107,4.2107 +036712909.jpg,323,323.846,3.5705,3.5705 +036712909.jpg,729,259.048,3.254,3.254 +040483213.jpg,233,322.388,3.11567,3.11567 +003966130.jpg,31,415.602,3.05013,3.05013 +027254940.jpg,388,375.011,3.58422,3.58422 +027254940.jpg,303,336,3,3 +040073526.jpg,928,730.646,8.22049,8.22049 +009671983.jpg,1082,506.625,5.80211,5.80211 +010935393.jpg,1184,817.268,8.43902,8.43902 +098474161.jpg,428,359.362,3.69682,3.69682 +050228013.jpg,129,467.585,7.04872,7.04872 +098260999.jpg,469,470.43,4.11919,4.11919 +098260999.jpg,581,521.946,3.49548,3.49548 +018626718.jpg,301,335.006,4.33383,4.33383 +084262262.jpg,637,849.914,10.6595,10.6595 +084262262.jpg,1338,951.446,11.7038,11.7038 +008697875.jpg,1114,390.904,4.242,4.242 +010321959.jpg,789,928.077,13.3397,13.3397 +075459720.jpg,590,497.415,4.86796,4.86796 +068889311.jpg,627,465.836,4.81965,4.81965 +064759512.jpg,418,482.198,9.18314,9.18314 +061894650.jpg,247,428.69,1.22413,1.22413 +030260562.jpg,459,435.496,1.45801,1.45801 +088109440.jpg,461,394.682,1.64015,1.64015 +020870042.jpg,934,382.87,1.40584,1.40584 +040559621.jpg,468,478.655,1.47122,1.47122 +076045644.jpg,793,424.148,1.42902,1.42902 +058426293.jpg,1216,196.496,1.45801,1.45801 +058426293.jpg,56,345.616,1.63466,1.63466 +058426293.jpg,638,333.088,1.34063,1.34063 +081112760.jpg,794,355.772,2.14767,2.14767 +091867317.jpg,817,464.524,2.87703,2.87703 +040086318.jpg,1083,486.158,3.01317,3.01317 +024414012.jpg,1330,590.546,2.46219,2.46219 +010587326.jpg,1183,473.592,3.96602,3.96602 +071972584.jpg,656,408.682,2.64017,2.64017 +075262666.jpg,721,325.523,1.71026,1.71026 +071595890.jpg,964,387.512,4.62604,4.62604 +007851122.jpg,622,389.649,3.63743,3.63743 +078895834.jpg,305,776.966,7.83052,7.83052 +019105249.jpg,580,386.595,3.29959,3.29959 +055096222.jpg,502,327.801,4.2334,4.2334 +025303154.jpg,674,433.286,5.10714,5.10714 +065497632.jpg,946,463.573,3.63112,3.63112 +006110708.jpg,1076,569.834,5.81946,5.81946 +091310879.jpg,1471,881.653,7.5544,7.5544 +064263377.jpg,425,430.617,2.71811,2.71811 +007365043.jpg,222,397.904,3.49201,3.49201 +015065449.jpg,980,517.259,7.68826,7.68826 +079345606.jpg,771,414.871,7.57261,7.57261 +073842510.jpg,760,497.425,6.7021,6.7021 +070177577.jpg,1039,627.8,6.9,6.9 +014105092.jpg,973,564.364,4.36363,4.36363 +058615032.jpg,553,436.333,1.94445,1.94445 +057459625.jpg,356,349.279,1.52322,1.52322 +098907398.jpg,715,261.568,2.2973,2.2973 +058271870.jpg,268,298.669,3.22245,3.22245 +068258167.jpg,326,248.366,2.19718,2.19718 +075078818.jpg,273,283.113,1.92608,1.92608 +045081941.jpg,376,211.975,1.9146,1.9146 +012980556.jpg,374,231.386,1.78216,1.78216 +020226088.jpg,315,246.218,2.26813,2.26813 +060626606.jpg,266,432.218,3.7682,3.7682 +039501167.jpg,486,593.046,3.1705,3.1705 +025698366.jpg,663,621.278,6.02313,6.02313 +031036338.jpg,912,345.171,4.01429,4.01429 +079831313.jpg,921,184.647,2.72059,2.72059 +055241047.jpg,287,206.96,2.32998,2.32998 +063984351.jpg,715,544.401,5.36673,5.36673 +021186654.jpg,399,627.124,9.67703,9.67703 +006269564.jpg,769,491.154,8.26286,8.26286 +029025122.jpg,406,776.917,9.49309,9.49309 +029025122.jpg,1359,742.044,13.1703,13.1703 +084457115.jpg,792,331.583,5.96525,5.96525 +053115373.jpg,1023,682.503,7.20856,7.20856 +097261946.jpg,523,391.657,7.88812,7.88812 +032523823.jpg,424,556.837,10.4864,10.4864 +073279672.jpg,1248,701.26,9.43837,9.43837 +055828875.jpg,737,467.088,7.17402,7.17402 +057508571.jpg,687,295.991,1.74929,1.74929 +027295487.jpg,974,415.681,4.14011,4.14011 +044911044.jpg,641,144.269,3.18904,3.18904 +066974812.jpg,367,312.975,1.9146,1.9146 +014061636.jpg,279,259.08,2.00664,2.00664 +007998596.jpg,653,403.152,6.42932,6.42932 +079986860.jpg,536,581.439,3.45326,3.45326 +044027917.jpg,642,363.5,3.45834,3.45834 +005349821.jpg,1018,492.674,5.55616,5.55616 +057307066.jpg,426,565.162,3.01347,3.01347 +009062444.jpg,241,459.25,4.52085,4.52085 +063051699.jpg,404,381.291,3.60762,3.60762 +065525483.jpg,1336,675.865,7.23871,7.23871 +008776147.jpg,581,350.141,3.3451,3.3451 +001574061.jpg,557,581.035,7.58626,7.58626 +018747933.jpg,527,279.096,1.75801,1.75801 +086797977.jpg,713,525.268,1.85564,1.85564 +073407592.jpg,814,588.745,8.39539,8.39539 +023987406.jpg,1216,776.02,9.83497,9.83497 +059729100.jpg,1063,584.467,9.70559,9.70559 +094219634.jpg,589,710.355,13.2796,13.2796 +091203437.jpg,328,183.924,1.41032,1.41032 +044973450.jpg,303,330.272,7.02263,7.02263 +083856036.jpg,620,652.513,10.1261,10.1261 +095528661.jpg,326,420.3,5.52497,5.52497 +059613139.jpg,577,337.698,4.89147,4.89147 +002209375.jpg,594,510.6,5.55,5.55 +088680987.jpg,714,647.495,9.45795,9.45795 +014741377.jpg,1016,707.212,11.101,11.101 +056880035.jpg,860,635.405,11.2837,11.2837 +094446895.jpg,699,460.13,5.67753,5.67753 +079537831.jpg,588,458.262,2.60517,2.60517 +041686978.jpg,700,362.17,4.68087,4.68087 +077486027.jpg,668,347.785,5.23206,5.23206 +085442041.jpg,678,362.205,5.26711,5.26711 +005880453.jpg,603,380.996,5.41631,5.41631 +004498114.jpg,619,429.696,5.72466,5.72466 +061292485.jpg,616,414.319,5.35993,5.35993 +047047125.jpg,486,181.366,1.86387,1.86387 +047047125.jpg,544,537.378,3.1982,3.1982 +046843528.jpg,263,447.603,6.05026,6.05026 +014880211.jpg,762,442.519,5.04321,5.04321 +062727664.jpg,677,624.132,6.42764,6.42764 +018050712.jpg,1453,729.906,7.57552,7.57552 +005913941.jpg,591,672.374,9.0312,9.0312 +008735981.jpg,405,362.761,4.14673,4.14673 +004888823.jpg,726,558.378,6.86482,6.86482 +090275101.jpg,654,502.852,6.73766,6.73766 +088590238.jpg,639,545.905,6.07543,6.07543 +076701169.jpg,658,308.112,4.92603,4.92603 +029197601.jpg,973,435.113,2.67606,2.67606 +068643413.jpg,633,395.667,3.88891,3.88891 +076463599.jpg,919,499.554,5.21284,5.21284 +057332576.jpg,308,323.573,2.96439,2.96439 +048598849.jpg,673,439.376,3.03134,3.03134 +048598849.jpg,1133,356.812,2.15102,2.15102 +052025558.jpg,637,578.481,9.54005,9.54005 +023357090.jpg,245,312.341,3.52841,3.52841 +092067510.jpg,129,289.803,2.90024,2.90024 +024371170.jpg,1070,509.282,6.85682,6.85682 +071883975.jpg,510,465.876,2.40637,2.40637 +081059316.jpg,203,363.388,3.11567,3.11567 +052221368.jpg,504,637.096,2.50801,2.50801 +052221368.jpg,458,555.661,2.30512,2.30512 +044238912.jpg,599,705.642,3.13683,3.13683 +044238912.jpg,467,652.555,2.54629,2.54629 +092718475.jpg,496,556.489,2.12408,2.12408 +015916020.jpg,877,412.477,4.12312,4.12312 +093074222.jpg,664,539.808,3.23402,3.23402 +065850645.jpg,600,835.71,6.14246,6.14246 +057804011.jpg,643,465.562,3.54686,3.54686 +052280595.jpg,1148,257.048,3.254,3.254 +005462629.jpg,616,274.771,3.81425,3.81425 +078526756.jpg,833,336.617,4.21807,4.21807 +038467062.jpg,688,617.903,7.07523,7.07523 +061529412.jpg,763,458.73,4.31082,4.31082 +057209461.jpg,669,379.366,3.78048,3.78048 +065245815.jpg,604,314.94,3.245,3.245 +026083562.jpg,954,508.601,5.55008,5.55008 +091746523.jpg,299,493.631,2.63591,2.63591 +081575159.jpg,326,145.096,5.09135,5.09135 +015184345.jpg,959,556.658,8.88821,8.88821 +053810566.jpg,1127,383.176,5.43133,5.43133 +088973898.jpg,299,340.233,1.9361,1.9361 +088973898.jpg,94,308.117,4.25979,4.25979 +057830665.jpg,374,341.657,1.88809,1.88809 +014814122.jpg,686,724.859,3.48827,3.48827 +005318534.jpg,1102,187.915,2.49289,2.49289 +005318534.jpg,501,311.397,5.69976,5.69976 +043066769.jpg,650,359.163,2.26356,2.26356 +071336755.jpg,289,532.916,4.65967,4.65967 +074757812.jpg,687,324.959,3.82991,3.82991 +042169371.jpg,813,678.813,4.06774,4.06774 +024754429.jpg,953,536.178,3.76485,3.76485 +045645340.jpg,419,374.542,6.21181,6.21181 +045645340.jpg,888,458.811,6.06757,6.06757 +071601364.jpg,1012,526.016,6.91804,6.91804 +065392137.jpg,879,481.938,6.91153,6.91153 +063023816.jpg,1379,667.059,9.83822,9.83822 +033546191.jpg,641,466.638,2.46986,2.46986 +076881166.jpg,699,330.385,2.53211,2.53211 +090476980.jpg,1052,549.545,3.12879,3.12879 +057983423.jpg,649,756.091,3.75755,3.75755 +035654214.jpg,681,633.304,4.692,4.692 +021116047.jpg,617,320.203,1.76695,1.76695 +021116047.jpg,206,334.726,1.89381,1.89381 +021572349.jpg,1719,636.8,2.4,2.4 +075382626.jpg,1563,680.592,3.21602,3.21602 +034680222.jpg,511,437.788,2.23233,2.23233 +078078785.jpg,1176,644.123,2.59357,2.59357 +078078785.jpg,49,302.313,1.77609,1.77609 +028259083.jpg,1379,825.967,2.08062,2.08062 +028259083.jpg,93,940.759,2.22991,2.22991 +056394177.jpg,1453,634.713,3.72604,3.72604 +067476304.jpg,774,533.61,4.21753,4.21753 +082285552.jpg,280,580.473,6.37272,6.37272 +025480082.jpg,1407,623.427,4.95227,4.95227 +025480082.jpg,1797,563.158,2.42981,2.42981 +073568875.jpg,1695,472.089,1.6741,1.6741 +055724855.jpg,948,793.055,13.3379,13.3379 +054881533.jpg,762,758.668,15.5556,15.5556 +024511906.jpg,992,773.228,11.019,11.019 +009488918.jpg,955,762.102,10.7585,10.7585 +013736865.jpg,689,650.263,11.5219,11.5219 +046735873.jpg,649,578.587,12.9656,12.9656 +098280254.jpg,1041,367.13,4.0942,4.0942 +000988787.jpg,658,597.212,3.43431,3.43431 +014347570.jpg,801,502.545,3.04541,3.04541 +068975464.jpg,785,415.522,2.46018,2.46018 +074858573.jpg,689,761.569,5.29744,5.29744 +069578631.jpg,657,352.446,3.87047,3.87047 +000899429.jpg,467,205.469,3.28907,3.28907 +007392172.jpg,978,713.259,9.68828,9.68828 +040713699.jpg,731,646.481,6.70673,6.70673 +060243526.jpg,1120,481.002,4.9168,4.9168 +032023004.jpg,1427,847.481,9.62346,9.62346 +049620588.jpg,932,479.963,9.49693,9.49693 +058559183.jpg,1407,618.697,6.05807,6.05807 +063731363.jpg,759,623.837,2.48638,2.48638 +078738243.jpg,367,328.504,3.792,3.792 +009842987.jpg,502,397.983,4.16525,4.16525 +005854142.jpg,888,436.513,3.87604,3.87604 +012656502.jpg,293,390.531,4.04422,4.04422 +028127845.jpg,1219,580.616,7.96804,7.96804 +093886967.jpg,654,520.755,12.3962,12.3962 +027698026.jpg,583,460.855,4.40459,4.40459 +027698026.jpg,914,551.365,5.94712,5.94712 +066252391.jpg,1024,589.41,2.70083,2.70083 +014642654.jpg,1855,370.445,3.70375,3.70375 +078772079.jpg,507,299.758,2.5632,2.5632 +032332310.jpg,916,615.069,3.6724,3.6724 +047855872.jpg,739,379.459,2.28827,2.28827 +088090876.jpg,353,595.967,7.91392,7.91392 +061561511.jpg,433,362.094,4.92448,4.92448 +075188979.jpg,182,519.643,8.55358,8.55358 +064386324.jpg,624,519.799,8.89994,8.89994 +062821008.jpg,490,429.249,2.77074,2.77074 +080069146.jpg,473,499.292,3.94098,3.94098 +071534702.jpg,547,542.925,3.99372,3.99372 +093676813.jpg,621,462.145,2.84542,2.84542 +016769732.jpg,489,396.497,4.62477,4.62477 +016769732.jpg,755,460.92,2.91,2.91 +022150078.jpg,302,275.968,2.5807,2.5807 +049118320.jpg,458,268.585,2.38212,2.38212 +064968084.jpg,331,536.69,4.89083,4.89083 +022036969.jpg,783,467.9,3.99169,3.99169 +032048964.jpg,346,874.501,8.12507,8.12507 +044521212.jpg,969,583.608,5.63401,5.63401 +055251978.jpg,580,359.169,2.43074,2.43074 +055251978.jpg,172,438.555,2.54629,2.54629 +046731238.jpg,1006,565.541,5.54505,5.54505 +041856560.jpg,957,452.875,3.90623,3.90623 +084385206.jpg,962,544.539,3.87825,3.87825 +005558063.jpg,334,746.004,6.58368,6.58368 +066011710.jpg,944,535.54,7.295,7.295 +056069782.jpg,650,509.682,3.39013,3.39013 +061198086.jpg,1024,617.126,5.59385,5.59385 +049127292.jpg,879,602.883,1.74026,1.74026 +045247005.jpg,1296,653.269,1.93912,1.93912 +051078299.jpg,928,636.161,2.18011,2.18011 +031937167.jpg,1138,693.885,3.40708,3.40708 +075854492.jpg,701,381.414,7.36786,7.36786 +040625427.jpg,484,407.661,2.30512,2.30512 +094789382.jpg,720,480.581,1.46509,1.46509 +000377819.jpg,701,436.837,2.73642,2.73642 +032849892.jpg,230,615.973,1.74774,1.74774 +069781984.jpg,632,493.429,1.45245,1.45245 +024536206.jpg,695,431.28,1.35665,1.35665 +080436963.jpg,805,484.28,1.35665,1.35665 +080436963.jpg,598,524.419,1.36821,1.36821 +006524045.jpg,647,462.022,1.16846,1.16846 +072600738.jpg,713,497.104,1.09202,1.09202 +037997492.jpg,957,319.323,1.86024,1.86024 +037352463.jpg,956,348.133,2.09442,2.09442 +031024642.jpg,625,455.018,1.66817,1.66817 +044048365.jpg,364,398.469,1.95576,1.95576 +021566081.jpg,536,319.26,2.605,2.605 +073229427.jpg,221,361.187,10.0989,10.0989 +020495766.jpg,361,519.576,8.21463,8.21463 +056144902.jpg,643,425.206,9.4338,9.4338 +017313679.jpg,491,650.646,9.2205,9.2205 +085739017.jpg,496,545.721,6.06007,6.06007 +010901474.jpg,739,379.141,3.6784,3.6784 +067227365.jpg,658,424.882,3.24014,3.24014 +095830936.jpg,1070,394.241,3.77011,3.77011 +089352075.jpg,376,369.469,3.37243,3.37243 +091391658.jpg,849,583.107,2.5089,2.5089 +034263539.jpg,681,383.748,2.81233,2.81233 +057415667.jpg,615,336.282,4.69018,4.69018 +093763697.jpg,716,388.943,4.57861,4.57861 +091436352.jpg,951,294.727,4.6439,4.6439 +015061856.jpg,681,730.458,3.20481,3.20481 +036653905.jpg,603,805.146,4.09552,4.09552 +019166439.jpg,1190,822.476,4.53963,4.53963 +014169492.jpg,1157,528.896,4.158,4.158 +079208430.jpg,1226,895.97,6.41418,6.41418 +001444210.jpg,705,494.162,5.34682,5.34682 +098795237.jpg,942,434.541,3.37843,3.37843 +051031258.jpg,668,455.143,3.42854,3.42854 +087287148.jpg,467,253.523,1.71026,1.71026 +087287148.jpg,346,253.278,1.93982,1.93982 +005732427.jpg,382,288.008,2.33403,2.33403 +049174685.jpg,1099,897.556,3.87964,3.87964 +049174685.jpg,310,382.163,3.68023,3.68023 +073747647.jpg,1192,532.691,1.89095,1.89095 +089173546.jpg,145,267.636,3.63632,3.63632 +030102609.jpg,914,551.01,2.16749,2.16749 +008572297.jpg,963,425.337,2.61138,2.61138 +055040944.jpg,435,284.696,1.72467,1.72467 +096829356.jpg,1150,365.004,3.41697,3.41697 +022415400.jpg,607,481.267,2.27229,2.27229 +089570110.jpg,388,430.754,2.56285,2.56285 +032963882.jpg,695,482.95,3.8292,3.8292 +045586837.jpg,485,395.21,6.93415,6.93415 +094647283.jpg,393,532.712,8.22602,8.22602 +030024885.jpg,178,481.305,3.69207,3.69207 +088373596.jpg,1131,707.977,8.33142,8.33142 +066929024.jpg,723,596.799,8.89994,8.89994 +007983893.jpg,495,401.295,7.19124,7.19124 +081139371.jpg,587,547.778,6.64817,6.64817 +044275429.jpg,850,504.647,2.97061,2.97061 +038454551.jpg,557,374.837,2.73642,2.73642 +038454551.jpg,229,397.4,1.95,1.95 +034228184.jpg,1346,521.416,3.95135,3.95135 +037598667.jpg,611,423.665,5.05542,5.05542 +057820667.jpg,344,644.867,5.65562,5.65562 +071189725.jpg,248,340.183,4.0986,4.0986 +002097999.jpg,704,596.217,8.10139,8.10139 +089014064.jpg,302,395.178,3.76485,3.76485 +052031861.jpg,265,429.64,3.88671,3.88671 +028227107.jpg,1050,800.35,7.27919,7.27919 +047518916.jpg,870,437.137,3.51141,3.51141 +061027555.jpg,591,83.3928,1.11606,1.11606 +043439489.jpg,436,433.435,4.95291,4.95291 +060514479.jpg,827,380.605,4.63371,4.63371 +034829942.jpg,284,331.858,3.65483,3.65483 +096252871.jpg,606,263.001,1.91672,1.91672 +017716542.jpg,601,431.343,5.69526,5.69526 +073887423.jpg,816,626.768,2.73066,2.73066 +074996272.jpg,513,672.206,2.6005,2.6005 +094274525.jpg,637,511.309,6.77575,6.77575 +063021026.jpg,605,533.903,7.07523,7.07523 +007870700.jpg,626,784.791,5.14926,5.14926 +075116651.jpg,732,357.255,3.27124,3.27124 +031216169.jpg,880,487.585,3.13209,3.13209 +004654004.jpg,562,456.382,4.61513,4.61513 +060777771.jpg,1748,413.971,4.16428,4.16428 +037443616.jpg,1277,648.107,5.00892,5.00892 +024898327.jpg,645,480.973,5.58105,5.58105 +094978710.jpg,684,523.624,4.71869,4.71869 +063456680.jpg,811,564.624,5.55203,5.55203 +053976449.jpg,726,555.449,2.37076,2.37076 +098926675.jpg,315,571.396,3.94965,3.94965 +034973959.jpg,868,418.612,4.46768,4.46768 +096555922.jpg,487,389.965,2.16375,2.16375 +027357157.jpg,608,256.836,3.48633,3.48633 +057084084.jpg,486,285.628,3.21896,3.21896 +012905339.jpg,314,464.633,4.05278,4.05278 +051897386.jpg,696,478.812,2.15102,2.15102 +038644837.jpg,726,515.614,3.13453,3.13453 +063541258.jpg,436,618.619,2.71827,2.71827 +093294761.jpg,796,181.986,2.08214,2.08214 +008144087.jpg,655,514.758,5.64646,5.64646 +008144087.jpg,478,252.121,3.17674,3.17674 +037780910.jpg,983,693.042,12.7535,12.7535 +004851187.jpg,1438,474.19,4.6825,4.6825 +004851187.jpg,1005,340.53,3.54419,3.54419 +069666691.jpg,923,629.496,5.958,5.958 +084118871.jpg,962,488.04,3.50333,3.50333 +084118871.jpg,585,849.816,2.98466,2.98466 +042934274.jpg,106,573.185,4.34876,4.34876 +042934274.jpg,1192,660.9,3.99169,3.99169 +009136174.jpg,990,474.076,4.00632,4.00632 +056041151.jpg,1181,727.885,12.0737,12.0737 +054485526.jpg,1181,497.098,6.17483,6.17483 +055269569.jpg,980,698.295,4.77462,4.77462 +060637948.jpg,872,615.902,2.65851,2.65851 +016898137.jpg,356,645.255,3.27124,3.27124 +094075245.jpg,760,522.04,1.83663,1.83663 +066880060.jpg,803,627.622,7.88521,7.88521 +028692451.jpg,1270,419.585,4.63206,4.63206 +039977755.jpg,536,763.381,12.9484,12.9484 +031974840.jpg,114,255.729,2.97741,2.97741 +031974840.jpg,296,287.532,2.54435,2.54435 +095160407.jpg,402,276.218,1.85151,1.85151 +046830020.jpg,198,217.496,1.45801,1.45801 +038663219.jpg,452,219.209,1.43405,1.43405 +082064255.jpg,902,375.889,5.24073,5.24073 +033007080.jpg,156,386.6,3.3,3.3 +061018301.jpg,1269,564.987,7.2489,7.2489 +090885138.jpg,428,549.269,6.1891,6.1891 +014821911.jpg,416,370.863,4.57193,4.57193 +043321864.jpg,345,386.683,4.64022,4.64022 +041640928.jpg,819,475.624,5.55203,5.55203 +097266879.jpg,923,451.969,7.99741,7.99741 +000109154.jpg,471,511.167,8.18054,8.18054 +053023569.jpg,437,576.171,7.01423,7.01423 +066001299.jpg,1001,488.24,7.68668,7.68668 +031525124.jpg,589,500.862,9.23849,9.23849 +097843422.jpg,507,379.592,3.96602,3.96602 +077943061.jpg,571,445.663,2.80528,2.80528 +000568822.jpg,414,191.96,1.66331,1.66331 +080569919.jpg,617,365.981,2.2484,2.2484 +081907188.jpg,570,381.305,2.10877,2.10877 +086634144.jpg,795,497.5,3.45834,3.45834 +015865517.jpg,911,297.364,3.2803,3.2803 +028151909.jpg,902,682.785,4.81544,4.81544 +025766192.jpg,1209,520.937,2.99475,2.99475 +012566255.jpg,993,303.438,2.03647,2.03647 +000972588.jpg,890,614.214,3.18453,3.18453 +067388940.jpg,1304,550.381,4.19839,4.19839 +050511242.jpg,135,324.97,1.74748,1.74748 +091545137.jpg,26,304.947,1.57892,1.57892 +022006771.jpg,316,268.364,3.2803,3.2803 +086387015.jpg,497,352.337,2.61138,2.61138 +025820296.jpg,787,357.827,2.23555,2.23555 +000708647.jpg,191,262.307,1.27562,1.27562 +086612606.jpg,589,290.353,1.61276,1.61276 +058376142.jpg,1017,374.793,2.39944,2.39944 +081204524.jpg,384,413.494,1.87446,1.87446 +094703579.jpg,212,475.332,2.69433,2.69433 +021136664.jpg,528,455.711,1.80923,1.80923 +009796909.jpg,1121,514.161,1.51344,1.51344 +067975659.jpg,496,496.287,1.44062,1.44062 +079538317.jpg,835,314.278,1.18983,1.18983 +040217043.jpg,653,354.495,3.37457,3.37457 +064639305.jpg,667,311.577,1.46479,1.46479 +004193567.jpg,704,394.551,2.37929,2.37929 +042449637.jpg,440,409.929,2.57738,2.57738 +030881891.jpg,873,320.136,1.34466,1.34466 +044100560.jpg,559,551.498,2.70815,2.70815 +089677812.jpg,1199,433.045,3.00375,3.00375 +024148304.jpg,1210,390.577,2.88141,2.88141 +070597578.jpg,381,346.379,2.53158,2.53158 +004492006.jpg,62,387.624,2.88531,2.88531 +055669058.jpg,265,426.798,2.06652,2.06652 +051958928.jpg,881,299.291,2.02428,2.02428 +064940047.jpg,233,370.552,2.21269,2.21269 +027745699.jpg,1020,313.58,1.29835,1.29835 +063977172.jpg,425,347.614,3.13453,3.13453 +058525423.jpg,670,369.008,3.08402,3.08402 +041261968.jpg,837,367.871,2.48928,2.48928 +009310928.jpg,900,388.277,2.10642,2.10642 +030289494.jpg,705,369.01,2.16749,2.16749 +049801039.jpg,209,392.292,1.19097,1.19097 +046656171.jpg,158,360.775,2.39794,2.39794 +004926073.jpg,973,346.289,1.52411,1.52411 +004926073.jpg,115,385.87,1.40584,1.40584 +016090336.jpg,710,385.176,1.76465,1.76465 +016090336.jpg,611,437.673,1.47275,1.47275 +059486585.jpg,606,410.746,1.72884,1.72884 +036099476.jpg,338,401.618,1.96815,1.96815 +036099476.jpg,71,376.051,1.92094,1.92094 +010045602.jpg,651,544.768,8.14731,8.14731 +010045602.jpg,1472,536.737,3.39478,3.39478 +017787063.jpg,1510,678.146,4.92886,4.92886 +017306195.jpg,382,550.477,4.12312,4.12312 +061639552.jpg,1516,555.498,6.7082,6.7082 +061639552.jpg,995,609.445,4.62039,4.62039 +056360492.jpg,340,679.184,7.93204,7.93204 +017602815.jpg,391,660.688,6.47403,6.47403 +099017281.jpg,706,515.525,3.12706,3.12706 +042183673.jpg,1067,650.84,5.07,5.07 +097906940.jpg,773,384.759,2.22991,2.22991 +044413285.jpg,448,328.076,1.42302,1.42302 +044413285.jpg,280,325.778,1.23146,1.23146 +043584110.jpg,620,341.58,1.29835,1.29835 +043584110.jpg,532,391.572,3.38096,3.38096 +069742546.jpg,500,385.219,1.01823,1.01823 +002928138.jpg,719,387.513,1.1261,1.1261 +085124612.jpg,787,417.111,2.67589,2.67589 +064796430.jpg,484,498.748,2.31234,2.31234 +013955460.jpg,752,376.4,1.95,1.95 +099927653.jpg,739,361.103,4.17528,4.17528 +099927653.jpg,281,359.066,1.83883,1.83883 +073050017.jpg,964,607.785,2.9821,2.9821 +044876389.jpg,527,648.539,6.29493,6.29493 +038279059.jpg,690,277.846,3.5705,3.5705 +023306983.jpg,682,586.263,8.10522,8.10522 +028050451.jpg,487,397.718,5.72646,5.72646 +000719296.jpg,614,467.883,2.90691,2.90691 +044612801.jpg,439,337.364,2.11367,2.11367 +088973560.jpg,1167,675.404,6.03366,6.03366 +093462084.jpg,714,433.065,2.17205,2.17205 +077920674.jpg,612,544.757,3.31307,3.31307 +025912010.jpg,1393,246.522,3.21014,3.21014 +005594795.jpg,993,426.123,2.01022,2.01022 +066080794.jpg,717,585.165,4.93042,4.93042 +099253807.jpg,1211,481.397,7.53311,7.53311 +085785599.jpg,983,357.13,5.59418,5.59418 +024373666.jpg,678,480.185,5.51543,5.51543 +071434253.jpg,983,783.06,11.505,11.505 +037154700.jpg,360,289.684,1.72363,1.72363 +012958454.jpg,1491,770.928,10.744,10.744 +014436456.jpg,594,433.711,1.80923,1.80923 +040123645.jpg,784,249.27,2.77253,2.77253 +089258378.jpg,1062,232.69,1.22413,1.22413 +024009590.jpg,965,470.783,1.48189,1.48189 +038342613.jpg,1085,338.145,3.51205,3.51205 +003820079.jpg,616,269.158,2.42981,2.42981 +018115261.jpg,678,386.6,1.8,1.8 +094821945.jpg,614,265.914,1.65952,1.65952 +038072088.jpg,972,313.78,2.1483,2.1483 +050240222.jpg,643,373.2,4.35,4.35 +084761779.jpg,437,221.255,1.18794,1.18794 diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/config/hourglass.pipeline b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/config/hourglass.pipeline new file mode 100644 index 0000000000..12844598c9 --- /dev/null +++ b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/config/hourglass.pipeline @@ -0,0 +1,32 @@ +{ + "hourglass": { + "stream_config": { + "deviceId": "0" + }, + "appsrc0": { + "props": { + "blocksize": "409600" + }, + "factory": "appsrc", + "next": "mxpi_tensorinfer0" + }, + "mxpi_tensorinfer0": { + "props": { + "dataSource": "appsrc0", + "modelPath": "../convert/hourglass.om", + "waitingTime": "2000", + "outputDeviceId": "-1" + }, + "factory": "mxpi_tensorinfer", + "next": "appsink0" + }, + "appsink0": { + "props": { + "blocksize": "4096000" + }, + "factory": "appsink" + } + } +} + + diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/convert/atc.sh b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/convert/atc.sh new file mode 100644 index 0000000000..ce9bfd101a --- /dev/null +++ b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/convert/atc.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# Copyright 2022 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ + +onnx_path=$1 +om_path=$2 +echo "Input ONNX file path: ${onnx_path}" +echo "Output OM file path: ${om_path}" + +atc --model="${onnx_path}" \ + --framework=5 \ + --output="${om_path}" \ + --soc_version=Ascend310 \ + --input_format=NCHW \ + --input_shape="input.1:1,3,384,384" \ + --output_type=FP32 \ \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/docker_start_infer.sh b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/docker_start_infer.sh new file mode 100644 index 0000000000..f708e1126e --- /dev/null +++ b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/docker_start_infer.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +# Copyright 2022 Huawei Technologies Co., Ltd +# +# 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. + +docker_image=$1 +data_dir=$2 + +function show_help() { + echo "Usage: docker_start.sh docker_image data_dir" +} + +function param_check() { + if [ -z "${docker_image}" ]; then + echo "please input docker_image" + show_help + exit 1 + fi + + if [ -z "${data_dir}" ]; then + echo "please input data_dir" + show_help + exit 1 + fi +} + +param_check + +docker run -it \ + --device=/dev/davinci0 \ + --device=/dev/davinci_manager \ + --device=/dev/devmm_svm \ + --device=/dev/hisi_hdc \ + -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ + -v ${data_dir}:${data_dir} \ + ${docker_image} \ + /bin/bash diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/CMakeLists.txt b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/CMakeLists.txt new file mode 100644 index 0000000000..298e2d92fc --- /dev/null +++ b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 3.10.2) +project(hourglass) +set(TARGET hourglass) +add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) +add_definitions(-Dgoogle=mindxsdk_private) +set(MX_SDK_HOME "$ENV{MX_SDK_HOME}") +file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/src/*cpp ) + +include_directories(${MX_SDK_HOME}/include) +include_directories(${PROJECT_SOURCE_DIR}/include) +include_directories(${MX_SDK_HOME}/opensource/include) +include_directories(${MX_SDK_HOME}/opensource/include/opencv4) +include_directories(${MX_SDK_HOME}/lib) + +link_directories( + ${MX_SDK_HOME}/lib + ${MX_SDK_HOME}/opensource/lib + ${MX_SDK_HOME}/lib/modelpostprocessors + /usr/local/Ascend/driver/lib64/ +) + +add_compile_options(-std=c++11 -fPIC -fstack-protector-all -pie -Wno-deprecated-declarations) +add_executable(${TARGET} ${SRC_FILES}) +target_link_libraries(${TARGET} + glog + mxbase + cpprest + opencv_world + ) +install(TARGETS ${TARGET} RUNTIME DESTINATION ${PROJECT_SOURCE_DIR}/) \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/build.sh b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/build.sh new file mode 100644 index 0000000000..aa422dc9f1 --- /dev/null +++ b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/build.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +# Copyright 2022 Huawei Technologies Co., Ltd +# +# 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. + + +path_cur="$(dirname "$0")" + +function check_env() +{ + # set ASCEND_VERSION to ascend-toolkit/latest when it was not specified by user + if [ ! "${ASCEND_VERSION}" ]; then + export ASCEND_VERSION=ascend-toolkit/latest + echo "Set ASCEND_VERSION to the default value: ${ASCEND_VERSION}" + else + echo "ASCEND_VERSION is set to ${ASCEND_VERSION} by user" + fi + + if [ ! "${ARCH_PATTERN}" ]; then + # set ARCH_PATTERN to ./ when it was not specified by user + export ARCH_PATTERN=./ + echo "ARCH_PATTERN is set to the default value: ${ARCH_PATTERN}" + else + echo "ARCH_PATTERN is set to ${ARCH_PATTERN} by user" + fi +} + +function build_hourglass() +{ + cd "$path_cur" || exit + rm -rf build + mkdir -p build + cd build || exit + cmake .. + make + ret=$? + if [ ${ret} -ne 0 ]; then + echo "Failed to build hourglass." + exit ${ret} + fi + make install +} + +check_env +build_hourglass \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/include/hourglass.h b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/include/hourglass.h new file mode 100644 index 0000000000..caa7eff7ef --- /dev/null +++ b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/include/hourglass.h @@ -0,0 +1,75 @@ +/* + * Copyright 2022 Huawei Technologies Co., Ltd + * + * 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. + */ + +#ifndef HOURGLASS_H +#define HOURGLASS_H + +#include +#include +#include "postprocess.h" +#include +#include "MxBase/Log/Log.h" +#include "MxBase/ModelInfer/ModelInferenceProcessor.h" +#include "MxBase/Tensor/TensorContext/TensorContext.h" +#include "MxBase/DeviceManager/DeviceManager.h" + + +namespace { + const uint32_t MODEL_HEIGHT = 384; + const uint32_t MODEL_WIDTH = 384; + const int NUMS_JOINTS = 16; +} + +struct InitParam { + uint32_t deviceId; + uint32_t res; // resolution of model input + std::string modelPath; + std::string csvPath; +}; + +struct ImageShape { + uint32_t width; + uint32_t height; +}; + +struct ImageAnnot { + std::string imageName; + float center[2]; + float scale[2]; +}; + +class Hourglass { +public: + APP_ERROR Init(const InitParam &initParam); + APP_ERROR DeInit(); + APP_ERROR ReadImage(const std::string &imgPath, cv::Mat &imageMat, ImageShape &imgShape); + APP_ERROR Resize_Affine(const cv::Mat& srcImage, cv::Mat *dstImage, ImageShape *imgShape, + const float center[], const float scale[]); + APP_ERROR CVMatToTensorBase(const cv::Mat& imageMat, MxBase::TensorBase *tensorBase); + APP_ERROR Inference(const std::vector &inputs, + std::vector *outputs); + APP_ERROR PostProcess(const std::vector &inputs, + std::vector >* node_score_list, + const float center[], const float scale[]); + APP_ERROR Process(const ImageAnnot &imageAnnot); +private: + std::shared_ptr model_; + MxBase::ModelDesc modelDesc_; + std::shared_ptr hourglassPostprocess; + uint32_t deviceId_ = 0; + uint32_t res = 384; +}; +#endif diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/include/postprocess.h b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/include/postprocess.h new file mode 100644 index 0000000000..afc32eafa2 --- /dev/null +++ b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/include/postprocess.h @@ -0,0 +1,58 @@ +/* + * Copyright 2022 Huawei Technologies Co., Ltd + * + * 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. + */ + +#ifndef HOURGLASS_POSTPROCESS_H +#define HOURGLASS_POSTPROCESS_H + +#include +#include +#include +#include "MxBase/ErrorCode/ErrorCode.h" +#include "MxBase/PostProcessBases/ObjectPostProcessBase.h" + + +namespace { + auto floatDeleter = [](float* p) {}; + const int SCALE_RATIO = 200; + const int NPOINTS = 16; + const int HEIGHT_HEAPMAP = 96; + const int WIDTH_HEAPMAP = 96; + const int NUMS_HEAPMAP = HEIGHT_HEAPMAP * WIDTH_HEAPMAP; + float heatmaps_reshape[NPOINTS][NUMS_HEAPMAP] = {}; + float batch_heatmaps[NPOINTS][HEIGHT_HEAPMAP][WIDTH_HEAPMAP] = {}; +} + + +class HourglassPostprocess : public MxBase::ObjectPostProcessBase { +public: + APP_ERROR Init(); + APP_ERROR DeInit(); + APP_ERROR Process(const float center[], const float scale[], + const std::vector &tensors, + std::vector >* node_score_list); +private: + void GetHeatmap(const std::vector& tensors, + uint32_t heatmapHeight, uint32_t heatmapWeight); + int GetIntData(const int index, const float(*heatmaps_reshape)[NUMS_HEAPMAP]); + double GetFloatData(const int index, const float(*heatmaps_reshape)[NUMS_HEAPMAP]); + void GetAffineMatrix(const float center[], const float scale[], cv::Mat *warp_mat); + void ParseHeatmap(const std::vector& tensors, + std::vector *preds_result, + uint32_t heatmapHeight, uint32_t heatmapWeight, + const float center[], const float scale[]); +}; + +#endif diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/src/hourglass.cpp b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/src/hourglass.cpp new file mode 100644 index 0000000000..31d873e94a --- /dev/null +++ b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/src/hourglass.cpp @@ -0,0 +1,322 @@ +/* + * Copyright 2022 Huawei Technologies Co., Ltd + * + * 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. + */ + +#include "hourglass.h" + + +APP_ERROR Hourglass::Init(const InitParam &initParam) { + deviceId_ = initParam.deviceId; + res = initParam.res; + + APP_ERROR ret = MxBase::DeviceManager::GetInstance()->InitDevices(); + if (ret != APP_ERR_OK) { + LogError << "Init devices failed, ret=" << ret << "."; + return ret; + } + ret = MxBase::TensorContext::GetInstance()->SetContext(initParam.deviceId); + if (ret != APP_ERR_OK) { + LogError << "Set context failed, ret=" << ret << "."; + return ret; + } + model_ = std::make_shared(); + ret = model_->Init(initParam.modelPath, modelDesc_); + if (ret != APP_ERR_OK) { + LogError << "ModelInferenceProcessor init failed, ret=" << ret << "."; + return ret; + } + hourglassPostprocess = std::make_shared(); + ret = hourglassPostprocess->Init(); + if (ret != APP_ERR_OK) { + LogError << "HourglassPostprocess init failed, ret=" << ret << "."; + return ret; + } + return APP_ERR_OK; +} + + +APP_ERROR Hourglass::DeInit() { + model_->DeInit(); + hourglassPostprocess->DeInit(); + MxBase::DeviceManager::GetInstance()->DestroyDevices(); + return APP_ERR_OK; +} + + +APP_ERROR Hourglass::ReadImage(const std::string &imgPath, cv::Mat &imageMat, ImageShape &imgShape) { + cv::Mat bgrImageMat; + bgrImageMat = cv::imread(imgPath, cv::IMREAD_COLOR); + cv::cvtColor(bgrImageMat, imageMat, cv::COLOR_BGR2RGB); + imgShape.width = imageMat.cols; + imgShape.height = imageMat.rows; + LogInfo << "ImageSize:" << imageMat.size(); + LogInfo << "ImageDims:" << imageMat.dims; + LogInfo << "ImageChannels:" << imageMat.channels(); + return APP_ERR_OK; +} + + +APP_ERROR Hourglass::Resize_Affine(const cv::Mat& srcImage, cv::Mat *dstImage, ImageShape *imgShape, + const float center[], const float scale[]) { + int new_width, new_height; + new_height = static_cast(imgShape->height); + new_width = static_cast(imgShape->width); + + float scale_tem[2] = {}; + scale_tem[0] = scale[0] * 200.0; + scale_tem[1] = scale[1] * 200.0; + float src_w = scale_tem[0]; + float dst_w = MODEL_WIDTH; + float dst_h = MODEL_HEIGHT; + float src_dir[2] = {}; + float dst_dir[2] = {}; + float sn = sin(0); + float cs = cos(0); + src_dir[0] = src_w * 0.5 * sn; + src_dir[1] = src_w * (-0.5) * cs; + dst_dir[0] = 0; + dst_dir[1] = dst_w * (-0.5); + + float src[3][2] = {}; + float dst[3][2] = {}; + + src[0][0] = center[0]; + src[0][1] = center[1]; + src[1][0] = center[0] + src_dir[0]; + src[1][1] = center[1] + src_dir[1]; + dst[0][0] = dst_w * 0.5; + dst[0][1] = dst_h * 0.5; + dst[1][0] = dst_w * 0.5 + dst_dir[0]; + dst[1][1] = dst_h * 0.5 + dst_dir[1]; + + float src_direct[2] = {}; + src_direct[0] = src[0][0] - src[1][0]; + src_direct[1] = src[0][1] - src[1][1]; + src[2][0] = src[1][0] - src_direct[1]; + src[2][1] = src[1][1] + src_direct[0]; + + float dst_direct[2] = {}; + dst_direct[0] = dst[0][0] - dst[1][0]; + dst_direct[1] = dst[0][1] - dst[1][1]; + dst[2][0] = dst[1][0] - dst_direct[1]; + dst[2][1] = dst[1][1] + dst_direct[0]; + cv::Point2f srcPoint2f[3], dstPoint2f[3]; + srcPoint2f[0] = cv::Point2f(static_cast(src[0][0]), static_cast(src[0][1])); + srcPoint2f[1] = cv::Point2f(static_cast(src[1][0]), static_cast(src[1][1])); + srcPoint2f[2] = cv::Point2f(static_cast(src[2][0]), static_cast(src[2][1])); + dstPoint2f[0] = cv::Point2f(static_cast(dst[0][0]), static_cast(dst[0][1])); + dstPoint2f[1] = cv::Point2f(static_cast(dst[1][0]), static_cast(dst[1][1])); + dstPoint2f[2] = cv::Point2f(static_cast(dst[2][0]), static_cast(dst[2][1])); + cv::Mat warp_mat(2, 3, CV_32FC1); + warp_mat = cv::getAffineTransform(srcPoint2f, dstPoint2f); + + cv::Mat src_cv(new_height, new_width, CV_8UC3, srcImage.data); + + cv::Mat warp_dst = cv::Mat::zeros(cv::Size(static_cast(MODEL_WIDTH), + static_cast(MODEL_HEIGHT)), src_cv.type()); + + cv::warpAffine(src_cv, warp_dst, warp_mat, warp_dst.size()); + + cv::Mat image_finally(warp_dst.rows, warp_dst.cols, CV_32FC3); + + warp_dst.convertTo(image_finally, CV_32FC3, 1 / 255.0); + + float mean[3] = { 0.406, 0.456, 0.485 }; + float std[3] = { 0.225, 0.224, 0.229 }; + for (int i = 0; i < image_finally.rows; i++) { + for (int j = 0; j < image_finally.cols; j++) { + if (warp_dst.channels() == 3) { + image_finally.at(i, j)[0]= (image_finally.at(i, j)[0] - mean[0]) / std[0]; + image_finally.at(i, j)[1]= (image_finally.at(i, j)[1] - mean[1]) / std[1]; + image_finally.at(i, j)[2]= (image_finally.at(i, j)[2] - mean[2]) / std[2]; + } + } + } + *dstImage = image_finally; + return APP_ERR_OK; +} + + + +APP_ERROR Hourglass::CVMatToTensorBase(const cv::Mat& imageMat, MxBase::TensorBase *tensorBase) { + uint32_t dataSize = 1; + for (size_t i = 0; i < modelDesc_.inputTensors.size(); ++i) { + std::vector shape = {}; + for (size_t j = 0; j < modelDesc_.inputTensors[i].tensorDims.size(); ++j) { + shape.push_back((uint32_t)modelDesc_.inputTensors[i].tensorDims[j]); + } + for (uint32_t s = 0; s < shape.size(); ++s) { + dataSize *= shape[s]; + } + } + // mat NHWC to NCHW + size_t H = 384, W = 384, C = 3; + float mat_data[dataSize] = {}; + dataSize = dataSize * 4; + for (size_t c = 0; c < C; c++) { + for (size_t h = 0; h < H; h++) { + for (size_t w = 0; w < W; w++) { + int id = c * (H * W) + h * W + w; + mat_data[id] = imageMat.at(h, w)[c]; + } + } + } + MxBase::MemoryData memoryDataDst(dataSize, MxBase::MemoryData::MEMORY_DEVICE, deviceId_); + MxBase::MemoryData memoryDataSrc(mat_data, dataSize, MxBase::MemoryData::MEMORY_HOST_MALLOC); + APP_ERROR ret = MxBase::MemoryHelper::MxbsMallocAndCopy(memoryDataDst, memoryDataSrc); + if (ret != APP_ERR_OK) { + LogError << GetError(ret) << "Memory malloc failed."; + return ret; + } + std::vector shape = { 1, 3, 384, 384 }; + *tensorBase = MxBase::TensorBase(memoryDataDst, false, shape, MxBase::TENSOR_DTYPE_FLOAT32); + return APP_ERR_OK; +} + + +APP_ERROR Hourglass::Inference(const std::vector &inputs, + std::vector *outputs) { + auto dtypes = model_->GetOutputDataType(); + for (size_t i = 0; i < modelDesc_.outputTensors.size(); ++i) { + std::vector shape = {}; + for (size_t j = 0; j < modelDesc_.outputTensors[i].tensorDims.size(); ++j) { + shape.push_back((uint32_t)modelDesc_.outputTensors[i].tensorDims[j]); + } + MxBase::TensorBase tensor(shape, dtypes[i], MxBase::MemoryData::MemoryType::MEMORY_DEVICE, deviceId_); + APP_ERROR ret = MxBase::TensorBase::TensorBaseMalloc(tensor); + if (ret != APP_ERR_OK) { + LogError << "TensorBaseMalloc failed, ret=" << ret << "."; + return ret; + } + outputs->push_back(tensor); + } + MxBase::DynamicInfo dynamicInfo = {}; + dynamicInfo.dynamicType = MxBase::DynamicType::STATIC_BATCH; + dynamicInfo.batchSize = 1; + + APP_ERROR ret = model_->ModelInference(inputs, *outputs, dynamicInfo); + if (ret != APP_ERR_OK) { + LogError << "ModelInference failed, ret=" << ret << "."; + return ret; + } + return APP_ERR_OK; +} + + +APP_ERROR Hourglass::PostProcess(const std::vector &inputs, + std::vector >* node_score_list, + const float center[], const float scale[]) { + APP_ERROR ret = hourglassPostprocess->Process(center, scale, inputs, node_score_list); + if (ret != APP_ERR_OK) { + LogError << "Hourglass Postprocess failed, ret=" << ret << "."; + return ret; + } + return APP_ERR_OK; +} + + +void drawSkeletonLine(const std::string& imgPath, const std::string& resultPath, const float (*preds)[2]) { + cv::Mat imageMat = cv::imread(imgPath); // read orignal image + + // Draw keypoints + for (int i = 0; i < NUMS_JOINTS; i++) { + cv::Point center; + center.x = static_cast(preds[i][0]); + center.y = static_cast(preds[i][1]); + cv::circle(imageMat, center, 4, cv::Scalar(0, 255, 85), -1); + } + + // draw skeleton lines + std::vector> skeletonLines = {{0, 1}, {1, 2}, {2, 12}, {12, 11}, {11, 10}, {12, 7}, + {7, 8}, {8, 9}, {7, 6}, {7, 13}, {13, 14}, {14, 15}, + {13, 3}, {3, 6}, {6, 2}, {3, 4}, {4, 5}}; + for (int i = 0; i < skeletonLines.size(); i++) { + int x1 = int(preds[skeletonLines[i][0]][0]); + int y1 = int(preds[skeletonLines[i][0]][1]); + int x2 = int(preds[skeletonLines[i][1]][0]); + int y2 = int(preds[skeletonLines[i][1]][1]); + cv::line(imageMat, cv::Point(x1, y1), cv::Point(x2, y2), (255, 0, 0), 3); + } + + cv::imwrite(resultPath, imageMat); // save image +} + + +void VisualizeInferResult(const std::string& imgPath, const std::string &resultPath, + const std::vector >& node_score_list) { + for (int i = 0; i < node_score_list.size(); i++) { + float preds[NUMS_JOINTS][2] = {}; + float maxvals[NUMS_JOINTS] = {}; + int idx = 0; + for (int j = 0; j < node_score_list[i].size(); j += 3) { + preds[idx][0] = node_score_list[i][j]; + preds[idx][1] = node_score_list[i][j + 1]; + maxvals[idx] = node_score_list[i][j + 2]; + idx++; + } + LogInfo << "infer result:"; + LogInfo << "preds:"; + for (int m = 0; m < NUMS_JOINTS; m++) { + LogInfo << preds[m][0] << " " << preds[m][1]; + } + drawSkeletonLine(imgPath, resultPath, preds); + } +} + + +APP_ERROR Hourglass::Process(const ImageAnnot &imageAnnot) { + cv::Mat imageMat; + ImageShape imageShape{}; + std::string imagePath = "../../data/mpii/images/"; // 数据集图片目录 + APP_ERROR ret = ReadImage(imagePath + imageAnnot.imageName, imageMat, imageShape); + if (ret != APP_ERR_OK) { + LogError << "ReadImage failed, ret=" << ret << "."; + return ret; + } + + float center[2] = {imageAnnot.center[0], imageAnnot.center[1]}; + float scale[2] = {imageAnnot.scale[0], imageAnnot.scale[1]}; + cv::Mat dstImage; + Resize_Affine(imageMat, &dstImage, &imageShape, center, scale); + + std::vector inputs = {}; + std::vector outputs = {}; + MxBase::TensorBase tensorBase; + ret = CVMatToTensorBase(dstImage, &tensorBase); + if (ret != APP_ERR_OK) { + LogError << "CVMatToTensorBase failed, ret=" << ret << "."; + return ret; + } + inputs.push_back(tensorBase); + + ret = Inference(inputs, &outputs); + if (ret != APP_ERR_OK) { + LogError << "Inference failed, ret=" << ret << "."; + return ret; + } + LogInfo << "Inference success, ret=" << ret << "."; + + std::vector > node_score_list = {}; + ret = PostProcess(outputs, &node_score_list, center, scale); + if (ret != APP_ERR_OK) { + LogError << "PostProcess failed, ret=" << ret << "."; + return ret; + } + + std::string resultPath = "./result.jpg"; + VisualizeInferResult(imagePath + imageAnnot.imageName, resultPath, node_score_list); + + return APP_ERR_OK; +} diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/src/main.cpp b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/src/main.cpp new file mode 100644 index 0000000000..2daf7b7c6e --- /dev/null +++ b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/src/main.cpp @@ -0,0 +1,106 @@ +/* + * Copyright 2022 Huawei Technologies Co., Ltd + * + * 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. + */ + +#include "hourglass.h" +#include "MxBase/Log/Log.h" +#include +#include +#include +#include +#include +#include + +using namespace std; + + +void InitHourglassParam(InitParam &initParam) { + initParam.deviceId = 0; + initParam.res = 384; // resolution of model input + initParam.modelPath = "../convert/hourglass.om"; + initParam.csvPath = "../../data/valid.csv"; +} + +void ReadAnnot(int idx, ImageAnnot &imageAnnot, const InitParam &initParam) { + ifstream inFile(initParam.csvPath, std::ios::in); + if (!inFile) { + LogError << "OPEN csvFile ERROR, csvPath is " << initParam.csvPath << "."; + exit(1); + } + + string line; + string field; + int lineNum = idx; + int num = 0; + while (getline(inFile, line)) { + num++; + if(num == lineNum) { + istringstream sin(line); + getline(sin, field, ','); + imageAnnot.imageName = field; + getline(sin, field, ','); + imageAnnot.center[0] = strtod(field.c_str(), NULL); + getline(sin, field, ','); + imageAnnot.center[1] = strtod(field.c_str(), NULL); + getline(sin, field, ','); + imageAnnot.scale[0] = strtod(field.c_str(), NULL); + getline(sin, field); + imageAnnot.scale[1] = strtod(field.c_str(), NULL); + break; + } + + } + inFile.close(); +} + + +int main(int argc, char* argv[]) { + if (argc <= 1) { + LogWarn << "Please input an integer image index whitch is between 1 and 2985."; + return APP_ERR_OK; + } + + int idx = atoi(argv[1]); // get image index of valid dataset whitch is between 1 and 2985. + if (idx <= 0 || idx > 2958) { + LogError << "image index is invalid, index must be an integer number between 1 and 2985."; + return APP_ERR_OK; + } + + InitParam initParam; + InitHourglassParam(initParam); + ImageAnnot imageAnnot; + ReadAnnot(idx, imageAnnot, initParam); + LogInfo << "model path: " << initParam.modelPath; + LogInfo << "csvfile path: " << initParam.csvPath; + LogInfo << "image name: " << imageAnnot.imageName; + LogInfo << "resize_h: " << initParam.res; + LogInfo << "resize_w: " << initParam.res; + + auto hourglass = std::make_shared(); + APP_ERROR ret = hourglass->Init(initParam); + if (ret != APP_ERR_OK) { + LogError << "Hourglass init failed, ret=" << ret << "."; + return ret; + } + + ret = hourglass->Process(imageAnnot); + if (ret != APP_ERR_OK) { + LogError << "Hourglass process failed, ret=" << ret << "."; + hourglass->DeInit(); + return ret; + } + hourglass->DeInit(); + return APP_ERR_OK; +} \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/src/postprocess.cpp b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/src/postprocess.cpp new file mode 100644 index 0000000000..8595bdce78 --- /dev/null +++ b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/mxbase/src/postprocess.cpp @@ -0,0 +1,217 @@ +/* + * Copyright 2022 Huawei Technologies Co., Ltd + * + * 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. + */ + +#include "postprocess.h" + + +APP_ERROR HourglassPostprocess::Init() { + LogInfo << "Begin to initialize HourglassPostprocess."; + LogInfo << "End to initialize HourglassPostprocess."; + return APP_ERR_OK; +} + + +APP_ERROR HourglassPostprocess::DeInit() { + LogInfo << "Begin to deinitialize HourglassPostprocess."; + LogInfo << "End to deinitialize HourglassPostprocess."; + return APP_ERR_OK; +} + + +void HourglassPostprocess::GetHeatmap(const std::vector& tensors, + uint32_t heatmapHeight, uint32_t heatmapWeight) { + auto bboxPtr = reinterpret_cast(tensors[0].GetBuffer()); + std::shared_ptr keypoint_pointer; + keypoint_pointer.reset(bboxPtr, floatDeleter); + + for (size_t i = 0; i < NPOINTS; i++) { + int startIndex = i * heatmapHeight * heatmapWeight; + for (size_t j = 0; j < heatmapHeight; j++) { + int middleIndex = j * heatmapWeight; + for (size_t k = 0; k < heatmapWeight; k++) { + float x = static_cast(keypoint_pointer.get())[startIndex + j * heatmapWeight + k]; + heatmaps_reshape[i][j * heatmapWeight + k] = x; + batch_heatmaps[i][j][k] = x; + } + } + } +} + + +int HourglassPostprocess::GetIntData(const int index, const float(*heatmaps_reshape)[NUMS_HEAPMAP]) { + int idx_tem = 0; + float tem = 0; + for (int j = 0; j < NUMS_HEAPMAP; j++) { + if (heatmaps_reshape[index][j] > tem) { + tem = heatmaps_reshape[index][j]; + idx_tem = j; + } + } + return idx_tem; +} + + +double HourglassPostprocess::GetFloatData(const int index, const float(*heatmaps_reshape)[NUMS_HEAPMAP]) { + float tem = 0; + for (int j = 0; j < NUMS_HEAPMAP; j++) { + if (heatmaps_reshape[index][j] > tem) { + tem = heatmaps_reshape[index][j]; + } + } + return tem; +} + + +void HourglassPostprocess::GetAffineMatrix(const float center[], const float scale[], cv::Mat *warp_mat) { + float scale_tem[2] = {}; + scale_tem[0] = scale[0] * SCALE_RATIO; + scale_tem[1] = scale[1] * SCALE_RATIO; + float src_w = scale_tem[0]; + float dst_w = WIDTH_HEAPMAP; + float dst_h = HEIGHT_HEAPMAP; + float src_dir[2] = {}; + float dst_dir[2] = {}; + + float sn = sin(0); + float cs = cos(0); + src_dir[0] = src_w * 0.5 * sn; + src_dir[1] = src_w * (-0.5) * cs; + dst_dir[0] = 0; + dst_dir[1] = dst_w * (-0.5); + + float src[3][2] = {}; + float dst[3][2] = {}; + + src[0][0] = center[0]; + src[0][1] = center[1]; + src[1][0] = center[0] + src_dir[0]; + src[1][1] = center[1] + src_dir[1]; + dst[0][0] = dst_w * 0.5; + dst[0][1] = dst_h * 0.5; + dst[1][0] = dst_w * 0.5 + dst_dir[0]; + dst[1][1] = dst_h * 0.5 + dst_dir[1]; + + float src_direct[2] = {}; + src_direct[0] = src[0][0] - src[1][0]; + src_direct[1] = src[0][1] - src[1][1]; + src[2][0] = src[1][0] - src_direct[1]; + src[2][1] = src[1][1] + src_direct[0]; + + float dst_direct[2] = {}; + dst_direct[0] = dst[0][0] - dst[1][0]; + dst_direct[1] = dst[0][1] - dst[1][1]; + dst[2][0] = dst[1][0] - dst_direct[1]; + dst[2][1] = dst[1][1] + dst_direct[0]; + cv::Point2f srcPoint2f[3], dstPoint2f[3]; + srcPoint2f[0] = cv::Point2f(static_cast(src[0][0]), static_cast(src[0][1])); + srcPoint2f[1] = cv::Point2f(static_cast(src[1][0]), static_cast(src[1][1])); + srcPoint2f[2] = cv::Point2f(static_cast(src[2][0]), static_cast(src[2][1])); + dstPoint2f[0] = cv::Point2f(static_cast(dst[0][0]), static_cast(dst[0][1])); + dstPoint2f[1] = cv::Point2f(static_cast(dst[1][0]), static_cast(dst[1][1])); + dstPoint2f[2] = cv::Point2f(static_cast(dst[2][0]), static_cast(dst[2][1])); + cv::Mat warp_mat_af(2, 3, CV_32FC1); + warp_mat_af = cv::getAffineTransform(dstPoint2f, srcPoint2f); + *warp_mat = warp_mat_af; +} + + +void HourglassPostprocess::ParseHeatmap(const std::vector& tensors, + std::vector *preds_result, + uint32_t heatmapHeight, uint32_t heatmapWeight, + const float center[], const float scale[]) { + LogInfo << "Begin to ParseHeatmap."; + GetHeatmap(tensors, heatmapHeight, heatmapWeight); + float maxvals[NPOINTS] = {}; + int idx[NPOINTS] = {}; + for (size_t i = 0; i < NPOINTS; i++) { + maxvals[i] = GetFloatData(i, heatmaps_reshape); + idx[i] = GetIntData(i, heatmaps_reshape); + } + float preds[NPOINTS][2] = {}; + for (size_t i = 0; i < NPOINTS; i++) { + preds[i][0] = (idx[i]) % heatmapWeight; + preds[i][1] = floor(idx[i] / heatmapWeight); + if (maxvals[i] < 0) { + preds[i][0] = preds[i][0] * (-1); + preds[i][1] = preds[i][0] * (-1); + } + } + for (size_t i = 0; i < NPOINTS; i++) { + float hm[HEIGHT_HEAPMAP][WIDTH_HEAPMAP] = {}; + for (size_t m = 0; m < HEIGHT_HEAPMAP; m++) { + for (size_t n = 0; n < WIDTH_HEAPMAP; n++) { + hm[m][n] = batch_heatmaps[i][m][n]; + } + } + int px = static_cast(floor(preds[i][0] + 0.5)); + int py = static_cast(floor(preds[i][1] + 0.5)); + if (px > 1 && px < heatmapWeight - 1 && py>1 && py < heatmapHeight - 1) { + float diff_x = hm[py][px + 1] - hm[py][px - 1]; + float diff_y = hm[py + 1][px] - hm[py - 1][px]; + if (diff_x > 0) { + preds[i][0] = preds[i][0] + 0.25; + } + if (diff_x < 0) { + preds[i][0] = preds[i][0] - 0.25; + } + if (diff_y > 0) { + preds[i][1] = preds[i][1] + 0.25; + } + if (diff_y < 0) { + preds[i][1] = preds[i][1] - 0.25; + } + } + } + cv::Mat warp_mat(2, 3, CV_32FC1); + GetAffineMatrix(center, scale, &warp_mat); + for (size_t i = 0; i < NPOINTS; i++) { + preds[i][0] = preds[i][0] * warp_mat.at(0, 0) + + preds[i][1] * warp_mat.at(0, 1) + warp_mat.at(0, 2); + preds[i][1] = preds[i][0] * warp_mat.at(1, 0) + + preds[i][1] * warp_mat.at(1, 1) + warp_mat.at(1, 2); + } + for (size_t i = 0; i < NPOINTS; i++) { + preds_result->push_back(preds[i][0]); + preds_result->push_back(preds[i][1]); + preds_result->push_back(maxvals[i]); + } +} + + +APP_ERROR HourglassPostprocess::Process(const float center[], const float scale[], + const std::vector &tensors, + std::vector>* node_score_list) { + LogDebug << "Begin to Hourglass PostProcess."; + auto inputs = tensors; + APP_ERROR ret = CheckAndMoveTensors(inputs); + if (ret != APP_ERR_OK) { + LogError << "CheckAndMoveTensors failed, ret=" << ret; + return ret; + } + + auto shape = inputs[0].GetShape(); + uint32_t batchSize = shape[0]; + uint32_t heatmapHeight = shape[2]; + uint32_t heatmapWeight = shape[3]; + for (uint32_t i = 0; i < batchSize; ++i) { + std::vector preds_result; + ParseHeatmap(inputs, &preds_result, heatmapHeight, heatmapWeight, center, scale); + node_score_list->push_back(preds_result); + } + LogInfo << "End to Hourglass PostProcess."; + return APP_ERR_OK; +} + diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/cal_accuracy.py b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/cal_accuracy.py new file mode 100644 index 0000000000..c6cb42d80a --- /dev/null +++ b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/cal_accuracy.py @@ -0,0 +1,133 @@ +# Copyright 2022 Huawei Technologies Co., Ltd +# +# 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 copy +import numpy as np + + +class MPIIEval: + """ + eval for MPII dataset with PCK + """ + template = { + "all": { + "total": 0, + "ankle": 0, + "knee": 0, + "hip": 0, + "pelvis": 0, + "thorax": 0, + "neck": 0, + "head": 0, + "wrist": 0, + "elbow": 0, + "shoulder": 0, + }, + "visible": { + "total": 0, + "ankle": 0, + "knee": 0, + "hip": 0, + "pelvis": 0, + "thorax": 0, + "neck": 0, + "head": 0, + "wrist": 0, + "elbow": 0, + "shoulder": 0, + }, + "not visible": { + "total": 0, + "ankle": 0, + "knee": 0, + "hip": 0, + "pelvis": 0, + "thorax": 0, + "neck": 0, + "head": 0, + "wrist": 0, + "elbow": 0, + "shoulder": 0, + }, + } + + joint_map = [ + "ankle", + "knee", + "hip", + "hip", + "knee", + "ankle", + "pelvis", + "thorax", + "neck", + "head", + "wrist", + "elbow", + "shoulder", + "shoulder", + "elbow", + "wrist", + ] + + def __init__(self): + self.correct_valid = copy.deepcopy(self.template) + self.count_valid = copy.deepcopy(self.template) + + def eval(self, pred, gt, normalizing, bound=0.5): + """ + use PCK with threshold of .5 of normalized distance (presumably head size) + """ + for p, g, normalize in zip(pred, gt, normalizing): + for j in range(g.shape[1]): + vis = "visible" + if g[0, j, 0] == 0: # Not in image + continue + if g[0, j, 2] == 0: + vis = "not visible" + joint = self.joint_map[j] + + self.count_valid["all"]["total"] += 1 + self.count_valid["all"][joint] += 1 + self.count_valid[vis]["total"] += 1 + self.count_valid[vis][joint] += 1 + + error = np.linalg.norm(p[0]["keypoints"][j, :2] - g[0, j, :2]) / normalize + + if bound > error: + self.correct_valid["all"]["total"] += 1 + self.correct_valid["all"][joint] += 1 + self.correct_valid[vis]["total"] += 1 + self.correct_valid[vis][joint] += 1 + self.output_result(bound) + + def output_result(self, bound): + """ + output split via valid + """ + for k in self.correct_valid: + print(k, ":") + for key in self.correct_valid[k]: + print( + "Val PCK @,", + bound, + ",", + key, + ":", + round(self.correct_valid[k][key] / max(self.count_valid[k][key], 1), 3), + ", count:", + self.count_valid[k][key], + ) + print("\n") \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/main.py b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/main.py new file mode 100644 index 0000000000..6e478d758b --- /dev/null +++ b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/main.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python +# coding=utf-8 + +# Copyright 2022 Huawei Technologies Co., Ltd +# +# 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 os +import cv2 +import argparse +import numpy as np +from preprocess import get_img +from postprocess import get_final_preds +from cal_accuracy import MPIIEval +import MxpiDataType_pb2 as MxpiDataType +from StreamManagerApi import StreamManagerApi, StringVector, InProtobufVector, MxProtobufIn + + +def parser_args(): + parser = argparse.ArgumentParser(description = 'Params of Hourglass Model:') + parser.add_argument("--annot_dir", type=str, default="../../data/mpii/annotations/valid.h5") + parser.add_argument("--img_dir", type=str, default="../../data/mpii/images") + args = parser.parse_args() + return args + + +def send_source_data(appsrc_id, tensor, stream_name, stream_manager): + """ + Construct the input of the stream, + send inputs data to a specified stream based on streamName. + + Returns: + bool: send data success or not + """ + tensor_package_list = MxpiDataType.MxpiTensorPackageList() + tensor_package = tensor_package_list.tensorPackageVec.add() + array_bytes = tensor.tobytes() + tensor_vec = tensor_package.tensorVec.add() + tensor_vec.deviceId = 0 + tensor_vec.memType = 0 + for k in tensor.shape: + tensor_vec.tensorShape.append(k) + tensor_vec.dataStr = array_bytes + tensor_vec.tensorDataSize = len(array_bytes) + key = "appsrc{}".format(appsrc_id).encode('utf-8') + protobuf_vec = InProtobufVector() + protobuf = MxProtobufIn() + protobuf.key = key + protobuf.type = b'MxTools.MxpiTensorPackageList' + protobuf.protobuf = tensor_package_list.SerializeToString() + protobuf_vec.push_back(protobuf) + + rete = stream_manager.SendProtobuf(stream_name, appsrc_id, protobuf_vec) + if rete < 0: + print("Failed to send data to stream.") + return False + return True + + +def drawSkeletonLine(imgName, locs): + ''' + draw skeleton line on orignal image + ''' + imgPath = "%s/%s" % (args.img_dir, imgName) + orgImg = cv2.imread(imgPath) + + for i in range(locs.shape[1]): + cv2.circle(orgImg, (int(locs[0][i][0]), int(locs[0][i][1])), 3, [0, 255, 85], -1) + + skeleton_line = [[0, 1], [1, 2], [2, 12], [12, 11], [11, 10], [12, 7], [7, 8], [8, 9], + [7, 6], [7, 13], [13, 14], [14, 15], [13, 3], [3, 6], [6, 2], [3, 4], [4, 5]] + for line_points in skeleton_line: + x1 = int(locs[0][line_points[0]][0]) + y1 = int(locs[0][line_points[0]][1]) + x2 = int(locs[0][line_points[1]][0]) + y2 = int(locs[0][line_points[1]][1]) + cv2.line(orgImg, (x1, y1), (x2, y2), (255, 0, 0), 3) + + if not os.path.exists("./infer_result"): + os.mkdir("./infer_result") + savePath = "%s/%s" % ("./infer_result", imgName) + cv2.imwrite(savePath, orgImg) + + +if __name__ == '__main__': + args = parser_args() + + # create stream with pipeline file + streamManagerApi = StreamManagerApi() + ret = streamManagerApi.InitManager() + if ret != 0: + print("Failed to init Stream manager, ret=%s" % str(ret)) + exit() + with open(os.path.realpath("../config/hourglass.pipeline"), 'rb') as f: + pipelineStr = f.read() + ret = streamManagerApi.CreateMultipleStreams(pipelineStr) + if ret != 0: + print("Failed to create Stream, ret=%s" % str(ret)) + exit() + + streamName = b'hourglass' + keys = [b"mxpi_tensorinfer0"] + keyVec = StringVector() + for key in keys: + keyVec.push_back(key) + + gts = [] # ground truth labels + preds = [] # predictions + normalizing = [] # normalizations used for evaluation + + for kps, img, c, s, n, imgName in get_img(args): # pre-process + + # send image to stream + if not send_source_data(0, img, streamName, streamManagerApi): + exit() + + # get infer result from stream + infer_result = streamManagerApi.GetProtobuf(streamName, 0, keyVec) + if infer_result.size() == 0: + print("infer_result is null") + exit() + if infer_result[0].errorCode != 0: + print("GetProtobuf error. errorCode=%d, errorMsg=%s" % (infer_result[0].errorCode, infer_result[0].data.decode())) + exit() + result = MxpiDataType.MxpiTensorPackageList() + result.ParseFromString(infer_result[0].messageBuf) + result = np.frombuffer(result.tensorPackageVec[0].tensorVec[0].dataStr, dtype=np.float32).reshape([1,16,96,96]) + + # post-process + locs, maxvals = get_final_preds(result.copy(), c, s) + + # visualization + drawSkeletonLine(imgName, locs) + + gts.append(kps) + normalizing.append(n) + pred = [] + for i in range(locs.shape[0]): + pred.append({"keypoints": locs[i, :, :]}) + preds.append(pred) + + # calculate PCK accuracy + bound = 0.5 # PCK's threshold of normalized distance + mpii_eval = MPIIEval() + mpii_eval.eval(preds, gts, normalizing, bound) + + # destroy stream + streamManagerApi.DestroyAllStreams() \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/postprocess.py b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/postprocess.py new file mode 100644 index 0000000000..b3e4fdc386 --- /dev/null +++ b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/postprocess.py @@ -0,0 +1,83 @@ +# Copyright 2022 Huawei Technologies Co., Ltd +# +# 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 math +import numpy as np +from preprocess import get_affine_transform, affine_transform + + +def transform_preds(coords, center, scale, output_size): + target_coords = np.zeros(coords.shape) + trans = get_affine_transform(center, scale, 0, output_size, inv=1) + for p in range(coords.shape[0]): + target_coords[p, 0:2] = affine_transform(coords[p, 0:2], trans) + return target_coords + + +def get_max_preds(batch_heatmaps): + ''' + get predictions from score maps + heatmaps: numpy.ndarray([batch_size, num_joints, height, width]) + + assert isinstance(batch_heatmaps, np.ndarray), \ + 'batch_heatmaps should be numpy.ndarray' + assert batch_heatmaps.ndim == 4, 'batch_images should be 4-ndim''' + + batch_size = batch_heatmaps.shape[0] + num_joints = batch_heatmaps.shape[1] + width = batch_heatmaps.shape[3] + heatmaps_reshaped = batch_heatmaps.reshape((batch_size, num_joints, -1)) + idx = np.argmax(heatmaps_reshaped, 2) + maxvals = np.amax(heatmaps_reshaped, 2) + + maxvals = maxvals.reshape((batch_size, num_joints, 1)) + idx = idx.reshape((batch_size, num_joints, 1)) + + preds = np.tile(idx, (1, 1, 2)).astype(np.float32) + + preds[:, :, 0] = (preds[:, :, 0]) % width + preds[:, :, 1] = np.floor((preds[:, :, 1]) / width) + + pred_mask = np.tile(np.greater(maxvals, 0.0), (1, 1, 2)) + pred_mask = pred_mask.astype(np.float32) + + preds *= pred_mask + return preds, maxvals + + +def get_final_preds(batch_heatmaps, center, scale): + coords, maxvals = get_max_preds(batch_heatmaps) + + heatmap_height = batch_heatmaps.shape[2] + heatmap_width = batch_heatmaps.shape[3] + + # post-processing + for n in range(coords.shape[0]): + for p in range(coords.shape[1]): + hm = batch_heatmaps[n][p] + px = int(math.floor(coords[n][p][0] + 0.5)) + py = int(math.floor(coords[n][p][1] + 0.5)) + if 1 < px < heatmap_width - 1 and 1 < py < heatmap_height - 1: + diff = np.array([hm[py][px + 1] - hm[py][px - 1], + hm[py + 1][px] - hm[py - 1][px]]) + coords[n][p] += np.sign(diff) * .25 + + preds = coords.copy() + + # Transform back + for i in range(coords.shape[0]): + preds[i] = transform_preds(coords[i], center, scale, + [heatmap_width, heatmap_height]) + + return preds, maxvals \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/preprocess.py b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/preprocess.py new file mode 100644 index 0000000000..be2a4ded34 --- /dev/null +++ b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/preprocess.py @@ -0,0 +1,168 @@ +# Copyright 2022 Huawei Technologies Co., Ltd +# +# 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 cv2 +import numpy as np +import h5py + + +def rotate_point(pt, angle_rad): + """Rotate a point by an angle. + + Args: + pt (list[float]): 2 dimensional point to be rotated + angle_rad (float): rotation angle by radian + + Returns: + list[float]: Rotated point. + """ + sn, cs = np.sin(angle_rad), np.cos(angle_rad) + new_x = pt[0] * cs - pt[1] * sn + new_y = pt[0] * sn + pt[1] * cs + rotated_pt = [new_x, new_y] + + return rotated_pt + + +def affine_transform(pt, trans_mat): + """Apply an affine transformation to the points. + + Args: + pt (np.ndarray): a 2 dimensional point to be transformed + trans_mat (np.ndarray): 2x3 matrix of an affine transform + + Returns: + np.ndarray: Transformed points. + """ + new_pt = np.array([pt[0], pt[1], 1.]).T + new_pt = np.dot(trans_mat, new_pt) + + return new_pt[:2] + + +def _get_3rd_point(a, b): + """To calculate the affine matrix, three pairs of points are required. This + function is used to get the 3rd point, given 2D points a & b. + + The 3rd point is defined by rotating vector `a - b` by 90 degrees + anticlockwise, using b as the rotation center. + + Args: + a (np.ndarray): point(x,y) + b (np.ndarray): point(x,y) + + Returns: + np.ndarray: The 3rd point. + """ + direction = a - b + third_pt = b + np.array([-direction[1], direction[0]], dtype=np.float32) + + return third_pt + + +def get_affine_transform(center, + scale, + rot, + output_size, + shift=(0., 0.), + inv=False, + scale_ratio=200.0): + """Get the affine transform matrix, given the center/scale/rot/output_size. + + Args: + center (np.ndarray[2, ]): Center of the bounding box (x, y). + scale (np.ndarray[2, ]): Scale of the bounding box + wrt [width, height]. + rot (float): Rotation angle (degree). + output_size (np.ndarray[2, ]): Size of the destination heatmaps. + shift (0-100%): Shift translation ratio wrt the width/height. + Default (0., 0.). + inv (bool): Option to inverse the affine transform direction. + (inv=False: src->dst or inv=True: dst->src) + scale_ratio(float): pixel std of MPII is 200 + + Returns: + np.ndarray: The transform matrix. + """ + scale_tmp = scale * scale_ratio + + shift = np.array(shift) + src_w = scale_tmp # adding + dst_w = output_size[0] + dst_h = output_size[1] + + rot_rad = np.pi * rot / 180 + src_dir = rotate_point([0., src_w * -0.5], rot_rad) + dst_dir = np.array([0., dst_w * -0.5]) + + src = np.zeros((3, 2), dtype=np.float32) + src[0, :] = center + scale_tmp * shift + src[1, :] = center + src_dir + scale_tmp * shift + src[2, :] = _get_3rd_point(src[0, :], src[1, :]) + + dst = np.zeros((3, 2), dtype=np.float32) + dst[0, :] = [dst_w * 0.5, dst_h * 0.5] + dst[1, :] = np.array([dst_w * 0.5, dst_h * 0.5]) + dst_dir + dst[2, :] = _get_3rd_point(dst[0, :], dst[1, :]) + + if inv: + trans = cv2.getAffineTransform(np.float32(dst), np.float32(src)) + else: + trans = cv2.getAffineTransform(np.float32(src), np.float32(dst)) + + return trans + + +def get_img(args): + """ + load image set + """ + h5file = h5py.File(args.annot_dir, "r") # read lable file + img_nums = 2950 # there are at most 2950 images in valid.h5 + for i in range(img_nums): + imgName = h5file["imgname"][i].decode("UTF-8") + imgPath = "%s/%s" % (args.img_dir, imgName) + imgBGR = cv2.imread(imgPath, cv2.IMREAD_COLOR) + imgRGB = cv2.cvtColor(imgBGR, cv2.COLOR_BGR2RGB) # transform image format from BGR to RGB + + image_size = (384, 384) # input shape of Hourglass model + + c = h5file["center"][i] + s = h5file["scale"][i] + r = 0 # rotation + + trans = get_affine_transform(c, s, r, image_size) # get affine transform matrix + imgTrans = cv2.warpAffine( + imgRGB, + trans, (int(image_size[0]), int(image_size[1])), + flags = cv2.INTER_LINEAR) + + mean = np.array([0.406, 0.456, 0.485], dtype=np.float32) + std = np.array([0.225, 0.224, 0.229], dtype=np.float32) + imgMeanStd = (imgTrans.astype(np.float32) / 255 - mean) / std + + imgEval = imgMeanStd.reshape((1,) + imgMeanStd.shape) + imgEval = imgEval.transpose(0, 3, 1, 2) # turn image format into NCHW(1*3*384*384) + + kp = h5file["part"][i] + vis = h5file["visible"][i] # if visible vis equals to 1, else vis equals to 0 + kp2 = np.insert(kp, 2, vis, axis=1) + kps = np.zeros((1, 16, 3)) + kps[0] = kp2 + + n = h5file["normalize"][i] + + yield kps, imgEval, c, s, n, imgName + + \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/run.sh b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/run.sh new file mode 100644 index 0000000000..652b3bdbfb --- /dev/null +++ b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/sdk/run.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# Copyright 2022 Huawei Technologies Co., Ltd +# +# 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. + +help_input1=$1 +annot_dir=$2 +help_input2=$3 +img_dir=$4 +set -e + +# Simple log helper functions +info() { echo -e "\033[1;34m[INFO ][MxStream] $1\033[1;37m" ; } +warn() { echo >&2 -e "\033[1;31m[WARN ][MxStream] $1\033[1;37m" ; } + +export LD_LIBRARY_PATH=${MX_SDK_HOME}/lib:${MX_SDK_HOME}/opensource/lib:${MX_SDK_HOME}/opensource/lib64:/usr/local/Ascend/ascend-toolkit/latest/acllib/lib64:${LD_LIBRARY_PATH} +export GST_PLUGIN_SCANNER=${MX_SDK_HOME}/opensource/libexec/gstreamer-1.0/gst-plugin-scanner +export GST_PLUGIN_PATH=${MX_SDK_HOME}/opensource/lib/gstreamer-1.0:${MX_SDK_HOME}/lib/plugins + +#to set PYTHONPATH, import the StreamManagerApi.py +export PYTHONPATH=$PYTHONPATH:${MX_SDK_HOME}/python + +python3.7 main.py $help_input1 $annot_dir $help_input2 $img_dir +exit 0 \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/docs/merge_docs.sh b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/docs/merge_docs.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/tests/data/interhand2d/test_interhand2d_camera.json b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/tests/data/interhand2d/test_interhand2d_camera.json old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/tests/data/interhand2d/test_interhand2d_data.json b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/tests/data/interhand2d/test_interhand2d_data.json old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/tests/data/interhand2d/test_interhand2d_joint_3d.json b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/tests/data/interhand2d/test_interhand2d_joint_3d.json old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/tests/data/panoptic/test_panoptic.json b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/tests/data/panoptic/test_panoptic.json old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/tools/dist_test.sh b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/tools/dist_test.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/tools/dist_train.sh b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/mmpose-master/tools/dist_train.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/modelarts/selfexport.py b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/modelarts/selfexport.py new file mode 100644 index 0000000000..11efe954d3 --- /dev/null +++ b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/modelarts/selfexport.py @@ -0,0 +1,39 @@ +# Copyright 2022 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +""" +FaceBoxes export air. +""" +import os +import numpy as np +from mindspore import context, Tensor, load_checkpoint, load_param_into_net, export +from src.config import faceboxes_config +from src.network import FaceBoxes + + + +def export_to_air(device_target, checkpoint_path): + cfg = None + if device_target == "Ascend": + cfg = faceboxes_config + context.set_context(mode=context.GRAPH_MODE, device_target="Ascend") + else: + raise ValueError("Unsupported device_target.") + + net = FaceBoxes(phase='test') + param_dict = load_checkpoint(os.path.join(checkpoint_path, 'FaceBoxes-300_1609.ckpt')) + load_param_into_net(net, param_dict) + input_shp = [1, 3, cfg['image_size'][0], cfg['image_size'][1]] + input_array = Tensor(np.random.uniform(-1.0, 1.0, size=input_shp).astype(np.float32)) + export(net, input_array, file_name="/cache/train/checkpoint/" + 'FaceBoxes', file_format='AIR') diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/modelarts/start.py b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/modelarts/start.py new file mode 100644 index 0000000000..277e5d8fb0 --- /dev/null +++ b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/modelarts/start.py @@ -0,0 +1,154 @@ +# Copyright 2022 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +"""Train FaceBoxes.""" +from __future__ import print_function +import os +import math +import argparse +import glob +import numpy as np +import mindspore +from mindspore import context, Tensor, export +from mindspore.context import ParallelMode +from mindspore.train import Model +from mindspore.train.callback import ModelCheckpoint, CheckpointConfig, LossMonitor, TimeMonitor +from mindspore.communication.management import init, get_rank +from mindspore.train.serialization import load_checkpoint, load_param_into_net + +from src.config import faceboxes_config +from src.network import FaceBoxes, FaceBoxesWithLossCell, TrainingWrapper +from src.loss import MultiBoxLoss +from src.dataset import create_dataset +from src.lr_schedule import adjust_learning_rate +from src.utils import prior_box + +import moxing + +parser = argparse.ArgumentParser(description='FaceBoxes: Face Detection') +parser.add_argument('--resume', type=str, default=None, help='resume training') +parser.add_argument('--device_target', type=str, default="Ascend", help='run device_target') +parser.add_argument('--batch_size', type=int, default=8, help='size of batch') +parser.add_argument('--max_epoch', type=int, default=300, help='maximum of epoch') +parser.add_argument('--momentum', type=float, default=0.9) +parser.add_argument('--weight_decay', type=float, default=5e-4) +parser.add_argument('--initial_lr', type=float, default=0.001) +parser.add_argument('--gamma', type=float, default=0.1) +parser.add_argument('--num_classes', type=int, default=2) +parser.add_argument('--negative_ratio', type=int, default=7) +parser.add_argument('--decay1', type=int, default=200) +parser.add_argument('--decay2', type=int, default=250) + +parser.add_argument('--data_url', default=None, help='Location of data.') +parser.add_argument('--train_url', default='', help='Location of training outputs.') + +args_opt = parser.parse_args() + +if __name__ == '__main__': + moxing.file.copy_parallel(src_url=args_opt.data_url, dst_url='/cache/data') + config = faceboxes_config + mindspore.common.seed.set_seed(config['seed']) + print('train config:\n', config) + + # set context and device init + if args_opt.device_target == "Ascend": + context.set_context(mode=context.GRAPH_MODE, device_target='Ascend', device_id=config['device_id'], + save_graphs=False) + if int(os.getenv('RANK_SIZE', '1')) > 1: + context.set_auto_parallel_context(device_num=config['rank_size'], parallel_mode=ParallelMode.DATA_PARALLEL, + gradients_mean=True) + init() + else: + raise ValueError("Unsupported device_target.") + + # set parameters + batch_size = args_opt.batch_size + max_epoch = args_opt.max_epoch + momentum = args_opt.momentum + weight_decay = args_opt.weight_decay + initial_lr = args_opt.initial_lr + gamma = args_opt.gamma + num_classes = args_opt.num_classes + negative_ratio = args_opt.negative_ratio + stepvalues = (args_opt.decay1, args_opt.decay2) + + ds_train = create_dataset('/cache/data', config, batch_size, multiprocessing=True, + num_worker=config["num_worker"]) + print('dataset size is : \n', ds_train.get_dataset_size()) + + steps_per_epoch = math.ceil(ds_train.get_dataset_size()) + + # define loss + anchors_num = prior_box(config['image_size'], config['min_sizes'], config['steps'], config['clip']).shape[0] + multibox_loss = MultiBoxLoss(num_classes, anchors_num, negative_ratio, config['batch_size']) + + # define net + net = FaceBoxes(phase='train') + net.set_train(True) + # resume + if args_opt.resume: + param_dict = load_checkpoint(args_opt.resume) + load_param_into_net(net, param_dict) + net = FaceBoxesWithLossCell(net, multibox_loss, config) + + # define optimizer + lr = adjust_learning_rate(initial_lr, gamma, stepvalues, steps_per_epoch, max_epoch, + warmup_epoch=config['warmup_epoch']) + opt = mindspore.nn.SGD(params=net.trainable_params(), learning_rate=lr, momentum=momentum, + weight_decay=weight_decay, loss_scale=1) + + # define model + net = TrainingWrapper(net, opt) + model = Model(net) + + # save model + rank = 0 + if int(os.getenv('RANK_SIZE', '1')) > 1: + rank = get_rank() + ckpt_save_dir = "/cache/train/checkpoint" + config_ck = CheckpointConfig(save_checkpoint_steps=config['save_checkpoint_epochs'], + keep_checkpoint_max=config['keep_checkpoint_max']) + ckpt_cb = ModelCheckpoint(prefix="FaceBoxes", directory=ckpt_save_dir, config=config_ck) + + time_cb = TimeMonitor(data_size=ds_train.get_dataset_size()) + callback_list = [LossMonitor(), time_cb, ckpt_cb] + + # training + print("============== Starting Training ==============") + model.train(max_epoch, ds_train, callbacks=callback_list, dataset_sink_mode=True) + print("============== End Training ==============") + + cfg = None + if args_opt.device_target == "Ascend": + cfg = faceboxes_config + context.set_context(mode=context.GRAPH_MODE, device_target="Ascend") + else: + raise ValueError("Unsupported device_target.") + + net_t = FaceBoxes(phase='test') + + ckpt_pattern = os.path.join(ckpt_save_dir, '*.ckpt') + ckpt_list = glob.glob(ckpt_pattern) + if not ckpt_list: + print(f"Cant't found ckpt in {ckpt_save_dir}") + exit() + ckpt_list.sort(key=os.path.getmtime) + print("====================%s" % ckpt_list[-1]) + + param_dict = load_checkpoint(os.path.join(ckpt_list[-1])) + load_param_into_net(net_t, param_dict) + input_shp = [1, 3, 2496, 1056] + input_array = Tensor(np.random.uniform(-1.0, 1.0, size=input_shp).astype(np.float32)) + export(net_t, input_array, file_name="/cache/train/checkpoint/" + 'FaceBoxes', file_format='AIR') + moxing.file.copy_parallel(src_url='/cache/train/', dst_url=args_opt.train_url) diff --git a/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/LICENSE b/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/LICENSE index 753842b672..f49a4e16e6 100644 --- a/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/LICENSE +++ b/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/datasets/__init__.py b/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/datasets/__init__.py index 453a036caa..6147909dea 100644 --- a/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/datasets/__init__.py +++ b/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/datasets/__init__.py @@ -1,14 +1,14 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. # ============================================================================ \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/models/__init__.py b/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/models/__init__.py index 453a036caa..6147909dea 100644 --- a/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/models/__init__.py +++ b/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/models/__init__.py @@ -1,14 +1,14 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. # ============================================================================ \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/modelzoo_level.txt b/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/modelzoo_level.txt +++ b/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/modules/__init__.py b/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/modules/__init__.py index 453a036caa..6147909dea 100644 --- a/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/modules/__init__.py +++ b/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/modules/__init__.py @@ -1,14 +1,14 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. # ============================================================================ \ No newline at end of file diff --git a/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/multi_epochs_dataloaders.py b/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/multi_epochs_dataloaders.py index 49b9ae910a..256ccca3c9 100644 --- a/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/multi_epochs_dataloaders.py +++ b/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/multi_epochs_dataloaders.py @@ -1,46 +1,46 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch - - -class MultiEpochsDataLoader(torch.utils.data.DataLoader): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._DataLoader__initialized = False - self.batch_sampler = _RepeatSampler(self.batch_sampler) - self._DataLoader__initialized = True - self.iterator = super().__iter__() - - def __len__(self): - return len(self.batch_sampler.sampler) - - def __iter__(self): - for _ in range(len(self)): - yield next(self.iterator) - - -class _RepeatSampler(object): - """ Sampler that repeats forever. - Args: - sampler (Sampler) - """ - - def __init__(self, sampler): - self.sampler = sampler - - def __iter__(self): - while True: - yield from iter(self.sampler) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch + + +class MultiEpochsDataLoader(torch.utils.data.DataLoader): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._DataLoader__initialized = False + self.batch_sampler = _RepeatSampler(self.batch_sampler) + self._DataLoader__initialized = True + self.iterator = super().__iter__() + + def __len__(self): + return len(self.batch_sampler.sampler) + + def __iter__(self): + for _ in range(len(self)): + yield next(self.iterator) + + +class _RepeatSampler(object): + """ Sampler that repeats forever. + Args: + sampler (Sampler) + """ + + def __init__(self, sampler): + self.sampler = sampler + + def __iter__(self): + while True: + yield from iter(self.sampler) diff --git a/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/requirements.txt b/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/requirements.txt index 279fbeb14a..aa1d3fb15f 100644 --- a/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/requirements.txt +++ b/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose/requirements.txt @@ -1,2 +1,2 @@ -opencv-python -pycocotools==2.0.2 +opencv-python +pycocotools==2.0.2 diff --git a/PyTorch/contrib/cv/pose_estimation/MSPN/dataset/MPII/mpii.py b/PyTorch/contrib/cv/pose_estimation/MSPN/dataset/MPII/mpii.py index 58f7422a26..42d224cdb8 100644 --- a/PyTorch/contrib/cv/pose_estimation/MSPN/dataset/MPII/mpii.py +++ b/PyTorch/contrib/cv/pose_estimation/MSPN/dataset/MPII/mpii.py @@ -1,198 +1,198 @@ -# encoding: utf-8 -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ -""" -@author: Wenbo Li -@contact: fenglinglwb@gmail.com -""" - -import cv2 -import json -import numpy as np -import os -from scipy.io import loadmat -from collections import OrderedDict - -from dataset.JointsDataset import JointsDataset - -class MPIIDataset(JointsDataset): - - def __init__(self, DATASET, stage, transform=None): - super().__init__(DATASET, stage, transform) - self.cur_dir = os.path.split(os.path.realpath(__file__))[0] - - self.train_gt_file = 'train.json' - self.train_gt_path = os.path.join(self.cur_dir, 'gt_json', - self.train_gt_file) - - self.val_gt_file = 'valid.json' - self.val_gt_path = os.path.join(self.cur_dir, 'gt_json', - self.val_gt_file) - self.val_gt_mat = os.path.join(self.cur_dir, 'gt_json', 'valid.mat') - - self.test_det_file = 'test.json' - self.test_det_path = os.path.join(self.cur_dir, 'det_json', - self.test_det_file) - - self.data = self._get_data() - self.data_num = len(self.data) - - def _get_data(self): - data = list() - - if self.stage == 'train': - mpii = json.load(open(self.train_gt_path)) - elif self.stage == 'val': - mpii = json.load(open(self.val_gt_path)) - else: - mpii = json.load(open(self.test_det_path)) - - for d in mpii: - img_name = d['image'] - img_id = img_name.split('.')[0] - img_path = os.path.join(self.cur_dir, 'images', img_name) - - center = np.array(d['center'], dtype=np.float32) - scale = np.array([d['scale'], d['scale']], dtype=np.float32) - - if center[0] != -1: - center[1] = center[1] + 15 * scale[1] - center -= 1 - - if self.stage == 'test': - joints = np.zeros((self.keypoint_num, 3), dtype=np.float32) - else: - joints = np.array(d['joints'], dtype=np.float32) - joints -= 1 - joints_vis = np.array(d['joints_vis'], dtype=np.float32) - joints_vis = joints_vis.reshape(-1, 1) * 2 - joints = np.concatenate((joints, joints_vis), axis=1) - - data.append(dict(center=center, - img_id=img_id, - img_path=img_path, - img_name=img_name, - joints=joints, - scale=scale)) - - return data - - # referring msra high resolution - def evaluate(self, preds): - preds = preds[:, :, 0:2] + 1.0 - - SC_BIAS = 0.6 - threshold = 0.5 - - gt_file = os.path.join(self.val_gt_mat) - gt_dict = loadmat(gt_file) - dataset_joints = gt_dict['dataset_joints'] - jnt_missing = gt_dict['jnt_missing'] - pos_gt_src = gt_dict['pos_gt_src'] - headboxes_src = gt_dict['headboxes_src'] - - pos_pred_src = np.transpose(preds, [1, 2, 0]) - - head = np.where(dataset_joints == 'head')[1][0] - lsho = np.where(dataset_joints == 'lsho')[1][0] - lelb = np.where(dataset_joints == 'lelb')[1][0] - lwri = np.where(dataset_joints == 'lwri')[1][0] - lhip = np.where(dataset_joints == 'lhip')[1][0] - lkne = np.where(dataset_joints == 'lkne')[1][0] - lank = np.where(dataset_joints == 'lank')[1][0] - - rsho = np.where(dataset_joints == 'rsho')[1][0] - relb = np.where(dataset_joints == 'relb')[1][0] - rwri = np.where(dataset_joints == 'rwri')[1][0] - rkne = np.where(dataset_joints == 'rkne')[1][0] - rank = np.where(dataset_joints == 'rank')[1][0] - rhip = np.where(dataset_joints == 'rhip')[1][0] - - jnt_visible = 1 - jnt_missing - uv_error = pos_pred_src - pos_gt_src - uv_err = np.linalg.norm(uv_error, axis=1) - headsizes = headboxes_src[1, :, :] - headboxes_src[0, :, :] - headsizes = np.linalg.norm(headsizes, axis=0) - headsizes *= SC_BIAS - scale = np.multiply(headsizes, np.ones((len(uv_err), 1))) - scaled_uv_err = np.divide(uv_err, scale) - scaled_uv_err = np.multiply(scaled_uv_err, jnt_visible) - jnt_count = np.sum(jnt_visible, axis=1) - less_than_threshold = np.multiply((scaled_uv_err <= threshold), - jnt_visible) - PCKh = np.divide(100.*np.sum(less_than_threshold, axis=1), jnt_count) - - rng = np.arange(0, 0.5+0.01, 0.01) - pckAll = np.zeros((len(rng), 16)) - - for r in range(len(rng)): - threshold = rng[r] - less_than_threshold = np.multiply(scaled_uv_err <= threshold, - jnt_visible) - pckAll[r, :] = np.divide(100.*np.sum(less_than_threshold, axis=1), - jnt_count) - - PCKh = np.ma.array(PCKh, mask=False) - PCKh.mask[6:8] = True - - jnt_count = np.ma.array(jnt_count, mask=False) - jnt_count.mask[6:8] = True - jnt_ratio = jnt_count / np.sum(jnt_count).astype(np.float64) - - name_value = [ - ('Head', PCKh[head]), - ('Shoulder', 0.5 * (PCKh[lsho] + PCKh[rsho])), - ('Elbow', 0.5 * (PCKh[lelb] + PCKh[relb])), - ('Wrist', 0.5 * (PCKh[lwri] + PCKh[rwri])), - ('Hip', 0.5 * (PCKh[lhip] + PCKh[rhip])), - ('Knee', 0.5 * (PCKh[lkne] + PCKh[rkne])), - ('Ankle', 0.5 * (PCKh[lank] + PCKh[rank])), - ('Mean', np.sum(PCKh * jnt_ratio)), - ('Mean@0.1', np.sum(pckAll[11, :] * jnt_ratio)) - ] - name_value = OrderedDict(name_value) - - print(name_value) - - def visualize(self, img, joints, score=None): - pairs = [[0, 1], [1, 2], [2, 6], [3, 4], [3, 6], [4, 5], [6, 7], - [7, 8], [8, 9], [8, 12], [8, 13], [10, 11], [11, 12], - [13, 14], [14, 15]] - color = np.random.randint(0, 256, (self.keypoint_num, 3)).tolist() - - for i in range(self.keypoint_num): - if joints[i, 0] > 0 and joints[i, 1] > 0: - cv2.circle(img, tuple(joints[i, :2]), 2, tuple(color[i]), 2) - if score: - cv2.putText(img, score, (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1.2, - (128, 255, 0), 2) - - def draw_line(img, p1, p2): - c = (0, 0, 255) - if p1[0] > 0 and p1[1] > 0 and p2[0] > 0 and p2[1] > 0: - cv2.line(img, tuple(p1), tuple(p2), c, 2) - - for pair in pairs: - draw_line(img, joints[pair[0] - 1], joints[pair[1] - 1]) - - return img - - -if __name__ == '__main__': - from dataset.attribute import load_dataset - dataset = load_dataset('MPII') - mpii = MPIIDataset(dataset, 'val') - print(mpii.data_num) - +# encoding: utf-8 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +""" +@author: Wenbo Li +@contact: fenglinglwb@gmail.com +""" + +import cv2 +import json +import numpy as np +import os +from scipy.io import loadmat +from collections import OrderedDict + +from dataset.JointsDataset import JointsDataset + +class MPIIDataset(JointsDataset): + + def __init__(self, DATASET, stage, transform=None): + super().__init__(DATASET, stage, transform) + self.cur_dir = os.path.split(os.path.realpath(__file__))[0] + + self.train_gt_file = 'train.json' + self.train_gt_path = os.path.join(self.cur_dir, 'gt_json', + self.train_gt_file) + + self.val_gt_file = 'valid.json' + self.val_gt_path = os.path.join(self.cur_dir, 'gt_json', + self.val_gt_file) + self.val_gt_mat = os.path.join(self.cur_dir, 'gt_json', 'valid.mat') + + self.test_det_file = 'test.json' + self.test_det_path = os.path.join(self.cur_dir, 'det_json', + self.test_det_file) + + self.data = self._get_data() + self.data_num = len(self.data) + + def _get_data(self): + data = list() + + if self.stage == 'train': + mpii = json.load(open(self.train_gt_path)) + elif self.stage == 'val': + mpii = json.load(open(self.val_gt_path)) + else: + mpii = json.load(open(self.test_det_path)) + + for d in mpii: + img_name = d['image'] + img_id = img_name.split('.')[0] + img_path = os.path.join(self.cur_dir, 'images', img_name) + + center = np.array(d['center'], dtype=np.float32) + scale = np.array([d['scale'], d['scale']], dtype=np.float32) + + if center[0] != -1: + center[1] = center[1] + 15 * scale[1] + center -= 1 + + if self.stage == 'test': + joints = np.zeros((self.keypoint_num, 3), dtype=np.float32) + else: + joints = np.array(d['joints'], dtype=np.float32) + joints -= 1 + joints_vis = np.array(d['joints_vis'], dtype=np.float32) + joints_vis = joints_vis.reshape(-1, 1) * 2 + joints = np.concatenate((joints, joints_vis), axis=1) + + data.append(dict(center=center, + img_id=img_id, + img_path=img_path, + img_name=img_name, + joints=joints, + scale=scale)) + + return data + + # referring msra high resolution + def evaluate(self, preds): + preds = preds[:, :, 0:2] + 1.0 + + SC_BIAS = 0.6 + threshold = 0.5 + + gt_file = os.path.join(self.val_gt_mat) + gt_dict = loadmat(gt_file) + dataset_joints = gt_dict['dataset_joints'] + jnt_missing = gt_dict['jnt_missing'] + pos_gt_src = gt_dict['pos_gt_src'] + headboxes_src = gt_dict['headboxes_src'] + + pos_pred_src = np.transpose(preds, [1, 2, 0]) + + head = np.where(dataset_joints == 'head')[1][0] + lsho = np.where(dataset_joints == 'lsho')[1][0] + lelb = np.where(dataset_joints == 'lelb')[1][0] + lwri = np.where(dataset_joints == 'lwri')[1][0] + lhip = np.where(dataset_joints == 'lhip')[1][0] + lkne = np.where(dataset_joints == 'lkne')[1][0] + lank = np.where(dataset_joints == 'lank')[1][0] + + rsho = np.where(dataset_joints == 'rsho')[1][0] + relb = np.where(dataset_joints == 'relb')[1][0] + rwri = np.where(dataset_joints == 'rwri')[1][0] + rkne = np.where(dataset_joints == 'rkne')[1][0] + rank = np.where(dataset_joints == 'rank')[1][0] + rhip = np.where(dataset_joints == 'rhip')[1][0] + + jnt_visible = 1 - jnt_missing + uv_error = pos_pred_src - pos_gt_src + uv_err = np.linalg.norm(uv_error, axis=1) + headsizes = headboxes_src[1, :, :] - headboxes_src[0, :, :] + headsizes = np.linalg.norm(headsizes, axis=0) + headsizes *= SC_BIAS + scale = np.multiply(headsizes, np.ones((len(uv_err), 1))) + scaled_uv_err = np.divide(uv_err, scale) + scaled_uv_err = np.multiply(scaled_uv_err, jnt_visible) + jnt_count = np.sum(jnt_visible, axis=1) + less_than_threshold = np.multiply((scaled_uv_err <= threshold), + jnt_visible) + PCKh = np.divide(100.*np.sum(less_than_threshold, axis=1), jnt_count) + + rng = np.arange(0, 0.5+0.01, 0.01) + pckAll = np.zeros((len(rng), 16)) + + for r in range(len(rng)): + threshold = rng[r] + less_than_threshold = np.multiply(scaled_uv_err <= threshold, + jnt_visible) + pckAll[r, :] = np.divide(100.*np.sum(less_than_threshold, axis=1), + jnt_count) + + PCKh = np.ma.array(PCKh, mask=False) + PCKh.mask[6:8] = True + + jnt_count = np.ma.array(jnt_count, mask=False) + jnt_count.mask[6:8] = True + jnt_ratio = jnt_count / np.sum(jnt_count).astype(np.float64) + + name_value = [ + ('Head', PCKh[head]), + ('Shoulder', 0.5 * (PCKh[lsho] + PCKh[rsho])), + ('Elbow', 0.5 * (PCKh[lelb] + PCKh[relb])), + ('Wrist', 0.5 * (PCKh[lwri] + PCKh[rwri])), + ('Hip', 0.5 * (PCKh[lhip] + PCKh[rhip])), + ('Knee', 0.5 * (PCKh[lkne] + PCKh[rkne])), + ('Ankle', 0.5 * (PCKh[lank] + PCKh[rank])), + ('Mean', np.sum(PCKh * jnt_ratio)), + ('Mean@0.1', np.sum(pckAll[11, :] * jnt_ratio)) + ] + name_value = OrderedDict(name_value) + + print(name_value) + + def visualize(self, img, joints, score=None): + pairs = [[0, 1], [1, 2], [2, 6], [3, 4], [3, 6], [4, 5], [6, 7], + [7, 8], [8, 9], [8, 12], [8, 13], [10, 11], [11, 12], + [13, 14], [14, 15]] + color = np.random.randint(0, 256, (self.keypoint_num, 3)).tolist() + + for i in range(self.keypoint_num): + if joints[i, 0] > 0 and joints[i, 1] > 0: + cv2.circle(img, tuple(joints[i, :2]), 2, tuple(color[i]), 2) + if score: + cv2.putText(img, score, (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1.2, + (128, 255, 0), 2) + + def draw_line(img, p1, p2): + c = (0, 0, 255) + if p1[0] > 0 and p1[1] > 0 and p2[0] > 0 and p2[1] > 0: + cv2.line(img, tuple(p1), tuple(p2), c, 2) + + for pair in pairs: + draw_line(img, joints[pair[0] - 1], joints[pair[1] - 1]) + + return img + + +if __name__ == '__main__': + from dataset.attribute import load_dataset + dataset = load_dataset('MPII') + mpii = MPIIDataset(dataset, 'val') + print(mpii.data_num) + diff --git a/PyTorch/contrib/cv/semantic_segmentation/3DUNet/docker/r.txt b/PyTorch/contrib/cv/semantic_segmentation/3DUNet/docker/r.txt index 37416fff58..ad452c9c59 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/3DUNet/docker/r.txt +++ b/PyTorch/contrib/cv/semantic_segmentation/3DUNet/docker/r.txt @@ -1,10 +1,10 @@ -scipy>=1.4.1 -numpy>=1.18.2 - -nibabel>=3.0.2 -tensorboard>=2.2.0 -torchsummary>=1.5.1 -torchnet>=0.0.4 -matplotlib>=3.2.1 -Pillow>=7.0.0 - +scipy>=1.4.1 +numpy>=1.18.2 + +nibabel>=3.0.2 +tensorboard>=2.2.0 +torchsummary>=1.5.1 +torchnet>=0.0.4 +matplotlib>=3.2.1 +Pillow>=7.0.0 + diff --git a/PyTorch/contrib/cv/semantic_segmentation/3DUNet/lib/medloaders/multi_epochs_dataloader.py b/PyTorch/contrib/cv/semantic_segmentation/3DUNet/lib/medloaders/multi_epochs_dataloader.py index 49b9ae910a..256ccca3c9 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/3DUNet/lib/medloaders/multi_epochs_dataloader.py +++ b/PyTorch/contrib/cv/semantic_segmentation/3DUNet/lib/medloaders/multi_epochs_dataloader.py @@ -1,46 +1,46 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch - - -class MultiEpochsDataLoader(torch.utils.data.DataLoader): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._DataLoader__initialized = False - self.batch_sampler = _RepeatSampler(self.batch_sampler) - self._DataLoader__initialized = True - self.iterator = super().__iter__() - - def __len__(self): - return len(self.batch_sampler.sampler) - - def __iter__(self): - for _ in range(len(self)): - yield next(self.iterator) - - -class _RepeatSampler(object): - """ Sampler that repeats forever. - Args: - sampler (Sampler) - """ - - def __init__(self, sampler): - self.sampler = sampler - - def __iter__(self): - while True: - yield from iter(self.sampler) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch + + +class MultiEpochsDataLoader(torch.utils.data.DataLoader): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._DataLoader__initialized = False + self.batch_sampler = _RepeatSampler(self.batch_sampler) + self._DataLoader__initialized = True + self.iterator = super().__iter__() + + def __len__(self): + return len(self.batch_sampler.sampler) + + def __iter__(self): + for _ in range(len(self)): + yield next(self.iterator) + + +class _RepeatSampler(object): + """ Sampler that repeats forever. + Args: + sampler (Sampler) + """ + + def __init__(self, sampler): + self.sampler = sampler + + def __iter__(self): + while True: + yield from iter(self.sampler) diff --git a/PyTorch/contrib/cv/semantic_segmentation/DeeplabV3_for_Pytorch/Dockerfile b/PyTorch/contrib/cv/semantic_segmentation/DeeplabV3_for_Pytorch/Dockerfile index 46016ca43f..95d754fbec 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/DeeplabV3_for_Pytorch/Dockerfile +++ b/PyTorch/contrib/cv/semantic_segmentation/DeeplabV3_for_Pytorch/Dockerfile @@ -1,21 +1,21 @@ -ARG FROM_IMAGE_NAME -FROM $FROM_IMAGE_NAME -RUN mkdir ./deeplabv3_requirement -WORKDIR ./deeplabv3_requirement -COPY requirements.txt . -RUN mkdir requirements -COPY requirements/* ./requirements/ -RUN pip3.7 install -r requirements.txt -RUN apt-get update && apt-get install -y git 2to3 libgl1-mesa-glx -RUN git config --global http.sslverify false -RUN git clone -b v1.3.9 --depth=1 https://github.com/open-mmlab/mmcv.git -WORKDIR ./mmcv -ENV MMCV_WITH_OPS=1 -ENV MAX_JOBS=8 -RUN python3.7 setup.py build_ext -RUN python3.7 setup.py develop -RUN pip3.7 uninstall opencv-python -RUN pip3.7 install opencv-python-headless -COPY mmcv_need/_functions.py ./mmcv/parallel/ -COPY mmcv_need/scatter_gather.py ./mmcv/parallel/ -COPY mmcv_need/dist_utils.py ./mmcv/runner/ +ARG FROM_IMAGE_NAME +FROM $FROM_IMAGE_NAME +RUN mkdir ./deeplabv3_requirement +WORKDIR ./deeplabv3_requirement +COPY requirements.txt . +RUN mkdir requirements +COPY requirements/* ./requirements/ +RUN pip3.7 install -r requirements.txt +RUN apt-get update && apt-get install -y git 2to3 libgl1-mesa-glx +RUN git config --global http.sslverify false +RUN git clone -b v1.3.9 --depth=1 https://github.com/open-mmlab/mmcv.git +WORKDIR ./mmcv +ENV MMCV_WITH_OPS=1 +ENV MAX_JOBS=8 +RUN python3.7 setup.py build_ext +RUN python3.7 setup.py develop +RUN pip3.7 uninstall opencv-python +RUN pip3.7 install opencv-python-headless +COPY mmcv_need/_functions.py ./mmcv/parallel/ +COPY mmcv_need/scatter_gather.py ./mmcv/parallel/ +COPY mmcv_need/dist_utils.py ./mmcv/runner/ diff --git a/PyTorch/contrib/cv/semantic_segmentation/DeeplabV3_for_Pytorch/README.md b/PyTorch/contrib/cv/semantic_segmentation/DeeplabV3_for_Pytorch/README.md index d05d103519..c22e463aeb 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/DeeplabV3_for_Pytorch/README.md +++ b/PyTorch/contrib/cv/semantic_segmentation/DeeplabV3_for_Pytorch/README.md @@ -1,108 +1,108 @@ -# DeeplabV3模型使用说明 - -## Requirements -* NPU配套的run包安装 -* Python 3.7.5 -* PyTorch(NPU版本) -* apex(NPU版本) -* mmcv-full 1.3.9 - -### Dataset Prepare -1. 下载cityscapes数据集 - -2. 新建文件夹data - -3. 将cityscas数据集放于data目录下 - - ```shell - ln -s /path/to/cityscapes/ ./data - ``` - -4. 处理数据集,`**labelTrainIds.png` 被用来训练 - - ```shell - python3 tools/convert_datasets/cityscapes.py data/cityscapes --nproc 8 - # python3 tools/convert_datasets/cityscapes.py /path/to/cityscapes --nproc 8 - ``` - -### 预训练模型下载 -* 若无法自动下载,可手动下载resnet50_v1c.pth,并放到/root/.cache/torch/checkpoints/文件夹下。 - -### 脚本环境安装 -#### 运行env_set.sh脚本,进行MMCV和mmsegmentation的安装 -```shell -bash env_set.sh -``` -编译mmcv耗时较长,请耐心等待 - -### 手动环境安装 -#### Build MMSEG from source - -1. 下载项目zip文件并解压 -3. 于npu服务器解压DeeplabV3_for_PyTorch压缩包 -4. 执行以下命令,安装mmsegmentation -```shell -cd DeeplabV3_for_PyTorch -pip3.7 install -r requirements.txt -pip3.7 install -e . -pip3.7 list | grep mm -``` - - -#### Build MMCV - -##### MMCV full version with cpu -```shell -source ./test/env_npu.sh -cd .. -git clone -b v1.3.9 --depth=1 https://github.com/open-mmlab/mmcv.git -export MMCV_WITH_OPS=1 -export MAX_JOBS=8 - -cd mmcv -python3.7 setup.py build_ext -python3.7 setup.py develop -pip3.7 list | grep mmcv -# 安装opencv-python-headless, 规避cv2引入错误 -pip3.7 uninstall opencv-python -pip3.7 install opencv-python-headless -``` - -##### Modified MMCV -将mmcv_need目录下的文件替换到mmcv的安装目录下。 - -```shell -cd ../DeeplabV3_for_PyTorch -/bin/cp -f mmcv_need/_functions.py ../mmcv/mmcv/parallel/ -/bin/cp -f mmcv_need/scatter_gather.py ../mmcv/parallel/ -/bin/cp -f mmcv_need/dist_utils.py ../mmcv/mmcv/runner/ -``` - -## Training - -```shell -# training 1p accuracy -bash ./test/train_full_1p.sh --data_path=real_data_path - -# training 1p performance -bash ./test/train_performance_1p.sh --data_path=real_data_path - -# training 8p accuracy -bash ./test/train_full_8p.sh --data_path=real_data_path - -# training 8p performance -bash ./test/train_performance_8p.sh --data_path=real_data_path -``` - - -## hipcc检查问题 -若在训练模型时,有报"which: no hipcc in (/usr/local/sbin:..." 的日志打印问题, -而hipcc是amd和nvidia平台需要的,npu并不需要。 -建议在torch/utils/cpp_extension.py文件中修改代码,当检查hipcc时,抑制输出。 -将 hipcc = subprocess.check_output(['which', 'hipcc']).decode().rstrip('\r\n')修改为 -hipcc = subprocess.check_output(['which', 'hipcc'], stderr=subporcess.DEVNULL).decode().rstrip('\r\n') - -## 报No module named 'mmcv._ext'问题 -在宿主机上训练模型,有时会报No module named 'mmcv._ext'问题(按照setup.py build_ext安装一般不会遇到此问题),或者别的带有mmcv的报错。 -解决方法:这一般是因为宿主机上安装了多个版本的mmcv,而训练脚本调用到了不匹配DeeplabV3模型使用的mmcv,因此报mmcv的错误。 +# DeeplabV3模型使用说明 + +## Requirements +* NPU配套的run包安装 +* Python 3.7.5 +* PyTorch(NPU版本) +* apex(NPU版本) +* mmcv-full 1.3.9 + +### Dataset Prepare +1. 下载cityscapes数据集 + +2. 新建文件夹data + +3. 将cityscas数据集放于data目录下 + + ```shell + ln -s /path/to/cityscapes/ ./data + ``` + +4. 处理数据集,`**labelTrainIds.png` 被用来训练 + + ```shell + python3 tools/convert_datasets/cityscapes.py data/cityscapes --nproc 8 + # python3 tools/convert_datasets/cityscapes.py /path/to/cityscapes --nproc 8 + ``` + +### 预训练模型下载 +* 若无法自动下载,可手动下载resnet50_v1c.pth,并放到/root/.cache/torch/checkpoints/文件夹下。 + +### 脚本环境安装 +#### 运行env_set.sh脚本,进行MMCV和mmsegmentation的安装 +```shell +bash env_set.sh +``` +编译mmcv耗时较长,请耐心等待 + +### 手动环境安装 +#### Build MMSEG from source + +1. 下载项目zip文件并解压 +3. 于npu服务器解压DeeplabV3_for_PyTorch压缩包 +4. 执行以下命令,安装mmsegmentation +```shell +cd DeeplabV3_for_PyTorch +pip3.7 install -r requirements.txt +pip3.7 install -e . +pip3.7 list | grep mm +``` + + +#### Build MMCV + +##### MMCV full version with cpu +```shell +source ./test/env_npu.sh +cd .. +git clone -b v1.3.9 --depth=1 https://github.com/open-mmlab/mmcv.git +export MMCV_WITH_OPS=1 +export MAX_JOBS=8 + +cd mmcv +python3.7 setup.py build_ext +python3.7 setup.py develop +pip3.7 list | grep mmcv +# 安装opencv-python-headless, 规避cv2引入错误 +pip3.7 uninstall opencv-python +pip3.7 install opencv-python-headless +``` + +##### Modified MMCV +将mmcv_need目录下的文件替换到mmcv的安装目录下。 + +```shell +cd ../DeeplabV3_for_PyTorch +/bin/cp -f mmcv_need/_functions.py ../mmcv/mmcv/parallel/ +/bin/cp -f mmcv_need/scatter_gather.py ../mmcv/parallel/ +/bin/cp -f mmcv_need/dist_utils.py ../mmcv/mmcv/runner/ +``` + +## Training + +```shell +# training 1p accuracy +bash ./test/train_full_1p.sh --data_path=real_data_path + +# training 1p performance +bash ./test/train_performance_1p.sh --data_path=real_data_path + +# training 8p accuracy +bash ./test/train_full_8p.sh --data_path=real_data_path + +# training 8p performance +bash ./test/train_performance_8p.sh --data_path=real_data_path +``` + + +## hipcc检查问题 +若在训练模型时,有报"which: no hipcc in (/usr/local/sbin:..." 的日志打印问题, +而hipcc是amd和nvidia平台需要的,npu并不需要。 +建议在torch/utils/cpp_extension.py文件中修改代码,当检查hipcc时,抑制输出。 +将 hipcc = subprocess.check_output(['which', 'hipcc']).decode().rstrip('\r\n')修改为 +hipcc = subprocess.check_output(['which', 'hipcc'], stderr=subporcess.DEVNULL).decode().rstrip('\r\n') + +## 报No module named 'mmcv._ext'问题 +在宿主机上训练模型,有时会报No module named 'mmcv._ext'问题(按照setup.py build_ext安装一般不会遇到此问题),或者别的带有mmcv的报错。 +解决方法:这一般是因为宿主机上安装了多个版本的mmcv,而训练脚本调用到了不匹配DeeplabV3模型使用的mmcv,因此报mmcv的错误。 为了解决这个问题,建议在启动训练脚本前,先导入已经安装的符合DeeplabV3模型需要的mmcv路径的环境变量。export PYTHONPATH=mmcv的路径:$PYTHONPATH \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/DeeplabV3_for_Pytorch/modelzoo_level.txt b/PyTorch/contrib/cv/semantic_segmentation/DeeplabV3_for_Pytorch/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/DeeplabV3_for_Pytorch/modelzoo_level.txt +++ b/PyTorch/contrib/cv/semantic_segmentation/DeeplabV3_for_Pytorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/ENet/README.md b/PyTorch/contrib/cv/semantic_segmentation/ENet/README.md index 0299b55f7e..69cd3ae9a1 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/ENet/README.md +++ b/PyTorch/contrib/cv/semantic_segmentation/ENet/README.md @@ -1,52 +1,52 @@ -# ENet 训练 -This implements training of ENet on the Cityscapes dataset. -- Reference implementation: -``` -url=https://github.com/Tramac/awesome-semantic-segmentation-pytorch -``` - - - -## Requirements # - -- Install Packages -- `pip install -r requirements.txt` -- The Cityscapes dataset can be downloaded from the [link](https://www.cityscapes-dataset.com/). -- Move the datasets to root directory and run the script `unzip.sh`. - - `bash ./unzip.sh` - - - -## Training # -To train a model, change the working directory to `./NPU`,then run: - -```bash -# 1p train perf -bash ./test/train_performance_1p.sh '[your_dataset_path]' - -# 8p train perf -bash ./test/train_performance_8p.sh '[your_dataset_path]' - -# 1p train full -bash ./test/train_full_1p.sh '[your_dataset_path]' - -# 8p train full -bash ./test/train_full_8p.sh '[your_dataset_path]' - -# finetuning -bash ./test/train_finetune_1p.sh '[your_dataset_path]' -``` -After running,you can see the results in `./NPU/stargan_full_8p/samples` or `./NPU/stargan_full_1p/samples` - - - - -## GAN training result # - -| Type | FPS | Epochs | AMP_Type | -| :----: | :-----: | :----: | :------: | -| NPU-1p | 14.398 | 400 | O2 | -| NPU-8p | 74.310 | 400 | O2 | -| GPU-1p | 21.885 | 400 | O2 | -| GPU-8p | 161.495 | 400 | O2 | - +# ENet 训练 +This implements training of ENet on the Cityscapes dataset. +- Reference implementation: +``` +url=https://github.com/Tramac/awesome-semantic-segmentation-pytorch +``` + + + +## Requirements # + +- Install Packages +- `pip install -r requirements.txt` +- The Cityscapes dataset can be downloaded from the [link](https://www.cityscapes-dataset.com/). +- Move the datasets to root directory and run the script `unzip.sh`. + - `bash ./unzip.sh` + + + +## Training # +To train a model, change the working directory to `./NPU`,then run: + +```bash +# 1p train perf +bash ./test/train_performance_1p.sh '[your_dataset_path]' + +# 8p train perf +bash ./test/train_performance_8p.sh '[your_dataset_path]' + +# 1p train full +bash ./test/train_full_1p.sh '[your_dataset_path]' + +# 8p train full +bash ./test/train_full_8p.sh '[your_dataset_path]' + +# finetuning +bash ./test/train_finetune_1p.sh '[your_dataset_path]' +``` +After running,you can see the results in `./NPU/stargan_full_8p/samples` or `./NPU/stargan_full_1p/samples` + + + + +## GAN training result # + +| Type | FPS | Epochs | AMP_Type | +| :----: | :-----: | :----: | :------: | +| NPU-1p | 14.398 | 400 | O2 | +| NPU-8p | 74.310 | 400 | O2 | +| GPU-1p | 21.885 | 400 | O2 | +| GPU-8p | 161.495 | 400 | O2 | + diff --git a/PyTorch/contrib/cv/semantic_segmentation/ENet/core/__init__.py b/PyTorch/contrib/cv/semantic_segmentation/ENet/core/__init__.py index abca8fd29e..ee12af0331 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/ENet/core/__init__.py +++ b/PyTorch/contrib/cv/semantic_segmentation/ENet/core/__init__.py @@ -1,15 +1,15 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 . import nn, models, utils, data \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/ENet/core/data/__init__.py b/PyTorch/contrib/cv/semantic_segmentation/ENet/core/data/__init__.py index a5f8598aa4..89552b1d3f 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/ENet/core/data/__init__.py +++ b/PyTorch/contrib/cv/semantic_segmentation/ENet/core/data/__init__.py @@ -1,13 +1,13 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/ENet/core/data/downloader/__init__.py b/PyTorch/contrib/cv/semantic_segmentation/ENet/core/data/downloader/__init__.py index a5f8598aa4..89552b1d3f 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/ENet/core/data/downloader/__init__.py +++ b/PyTorch/contrib/cv/semantic_segmentation/ENet/core/data/downloader/__init__.py @@ -1,13 +1,13 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/ENet/core/models/avg_enet.py b/PyTorch/contrib/cv/semantic_segmentation/ENet/core/models/avg_enet.py index 8a8b683876..6a6d5c6399 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/ENet/core/models/avg_enet.py +++ b/PyTorch/contrib/cv/semantic_segmentation/ENet/core/models/avg_enet.py @@ -1,550 +1,550 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -"""Efficient Neural Network""" -import torch -import torch.nn as nn - -__all__ = ['ENet', 'get_enet', 'get_enet_citys'] - - -class ENet(nn.Module): - """Efficient Neural Network""" - - def __init__(self, nclass, backbone='', aux=False, jpu=False, pretrained_base=None, **kwargs): - super(ENet, self).__init__() - self.initial = InitialBlock(13, **kwargs) - - self.bottleneck1_0 = Bottleneck(16, 16, 64, downsampling=True, **kwargs) - self.bottleneck1_1 = Bottleneck(64, 16, 64, **kwargs) - self.bottleneck1_2 = Bottleneck(64, 16, 64, **kwargs) - self.bottleneck1_3 = Bottleneck(64, 16, 64, **kwargs) - self.bottleneck1_4 = Bottleneck(64, 16, 64, **kwargs) - - self.bottleneck2_0 = Bottleneck(64, 32, 128, downsampling=True, **kwargs) - self.bottleneck2_1 = Bottleneck(128, 32, 128, **kwargs) - self.bottleneck2_2 = Bottleneck(128, 32, 128, dilation=2, **kwargs) - self.bottleneck2_3 = Bottleneck(128, 32, 128, asymmetric=True, **kwargs) - self.bottleneck2_4 = Bottleneck(128, 32, 128, dilation=4, **kwargs) - self.bottleneck2_5 = Bottleneck(128, 32, 128, **kwargs) - self.bottleneck2_6 = Bottleneck(128, 32, 128, dilation=8, **kwargs) - self.bottleneck2_7 = Bottleneck(128, 32, 128, asymmetric=True, **kwargs) - self.bottleneck2_8 = Bottleneck(128, 32, 128, dilation=16, **kwargs) - - self.bottleneck3_1 = Bottleneck(128, 32, 128, **kwargs) - self.bottleneck3_2 = Bottleneck(128, 32, 128, dilation=2, **kwargs) - self.bottleneck3_3 = Bottleneck(128, 32, 128, asymmetric=True, **kwargs) - self.bottleneck3_4 = Bottleneck(128, 32, 128, dilation=4, **kwargs) - self.bottleneck3_5 = Bottleneck(128, 32, 128, **kwargs) - self.bottleneck3_6 = Bottleneck(128, 32, 128, dilation=8, **kwargs) - self.bottleneck3_7 = Bottleneck(128, 32, 128, asymmetric=True, **kwargs) - self.bottleneck3_8 = Bottleneck(128, 32, 128, dilation=16, **kwargs) - - self.bottleneck4_0 = UpsamplingBottleneck(128, 16, 64, **kwargs) - self.bottleneck4_1 = Bottleneck(64, 16, 64, **kwargs) - self.bottleneck4_2 = Bottleneck(64, 16, 64, **kwargs) - - self.bottleneck5_0 = UpsamplingBottleneck(64, 4, 16, **kwargs) - self.bottleneck5_1 = Bottleneck(16, 4, 16, **kwargs) - - self.fullconv = nn.ConvTranspose2d(16, nclass, 2, 2, bias=False) - - self.__setattr__('exclusive', ['bottleneck1_0', 'bottleneck1_1', 'bottleneck1_2', 'bottleneck1_3', - 'bottleneck1_4', 'bottleneck2_0', 'bottleneck2_1', 'bottleneck2_2', - 'bottleneck2_3', 'bottleneck2_4', 'bottleneck2_5', 'bottleneck2_6', - 'bottleneck2_7', 'bottleneck2_8', 'bottleneck3_1', 'bottleneck3_2', - 'bottleneck3_3', 'bottleneck3_4', 'bottleneck3_5', 'bottleneck3_6', - 'bottleneck3_7', 'bottleneck3_8', 'bottleneck4_0', 'bottleneck4_1', - 'bottleneck4_2', 'bottleneck5_0', 'bottleneck5_1', 'fullconv']) - - def forward(self, x): - # init - x = self.initial(x) - - # stage 1 - #x, max_indices1 = self.bottleneck1_0(x) - x = self.bottleneck1_0(x) - x = self.bottleneck1_1(x) - x = self.bottleneck1_2(x) - x = self.bottleneck1_3(x) - x = self.bottleneck1_4(x) - - # stage 2 - #x, max_indices2 = self.bottleneck2_0(x) - x = self.bottleneck2_0(x) - x = self.bottleneck2_1(x) - x = self.bottleneck2_2(x) - x = self.bottleneck2_3(x) - x = self.bottleneck2_4(x) - x = self.bottleneck2_5(x) - x = self.bottleneck2_6(x) - x = self.bottleneck2_7(x) - x = self.bottleneck2_8(x) - - # stage 3 - x = self.bottleneck3_1(x) - x = self.bottleneck3_2(x) - x = self.bottleneck3_3(x) - x = self.bottleneck3_4(x) - x = self.bottleneck3_6(x) - x = self.bottleneck3_7(x) - x = self.bottleneck3_8(x) - - # stage 4 - #x = self.bottleneck4_0(x, max_indices2) - x = self.bottleneck4_0(x) - x = self.bottleneck4_1(x) - x = self.bottleneck4_2(x) - - # stage 5 - #x = self.bottleneck5_0(x, max_indices1) - x = self.bottleneck5_0(x) - x = self.bottleneck5_1(x) - - # out - x = self.fullconv(x) - return tuple([x]) - - -class InitialBlock(nn.Module): - """ENet initial block""" - - def __init__(self, out_channels, norm_layer=nn.BatchNorm2d, **kwargs): - super(InitialBlock, self).__init__() - self.conv = nn.Conv2d(3, out_channels, 3, 2, 1, bias=False) - self.maxpool = nn.MaxPool2d(2, 2) - self.bn = norm_layer(out_channels + 3) - self.act = nn.PReLU() - - def forward(self, x): - x_conv = self.conv(x) - x_pool = self.maxpool(x) - x = torch.cat([x_conv, x_pool], dim=1) - x = self.bn(x) - x = self.act(x) - return x - - -class Bottleneck(nn.Module): - """Bottlenecks include regular, asymmetric, downsampling, dilated""" - - def __init__(self, in_channels, inter_channels, out_channels, dilation=1, asymmetric=False, - downsampling=False, norm_layer=nn.BatchNorm2d, **kwargs): - self.npu = kwargs['npu'] - - super(Bottleneck, self).__init__() - self.downsamping = downsampling - if downsampling: - #self.maxpool = nn.MaxPool2d(2, 2, return_indices=True) - self.avgpool = nn.AvgPool2d((2, 2), stride=(2,2)) - self.conv_down = nn.Sequential( - nn.Conv2d(in_channels, out_channels, 1, bias=False), - norm_layer(out_channels) - ) - - self.conv1 = nn.Sequential( - nn.Conv2d(in_channels, inter_channels, 1, bias=False), - norm_layer(inter_channels), - nn.PReLU() - ) - - if downsampling: - self.conv2 = nn.Sequential( - nn.Conv2d(inter_channels, inter_channels, 2, stride=2, bias=False), - norm_layer(inter_channels), - nn.PReLU() - ) - else: - if asymmetric: - self.conv2 = nn.Sequential( - nn.Conv2d(inter_channels, inter_channels, (5, 1), padding=(2, 0), bias=False), - nn.Conv2d(inter_channels, inter_channels, (1, 5), padding=(0, 2), bias=False), - norm_layer(inter_channels), - nn.PReLU() - ) - else: - self.conv2 = nn.Sequential( - nn.Conv2d(inter_channels, inter_channels, 3, dilation=dilation, padding=dilation, bias=False), - norm_layer(inter_channels), - nn.PReLU() - ) - self.conv3 = nn.Sequential( - nn.Conv2d(inter_channels, out_channels, 1, bias=False), - norm_layer(out_channels), - nn.Dropout2d(0.1) - ) - self.act = nn.PReLU() - - def forward(self, x): - identity = x - if self.downsamping: - ''' - if self.npu: - identity = x.cpu().to(torch.float32) - identity, max_indices = self.maxpool(identity) - identity = identity.npu().to(torch.float16) - else: - identity, max_indices = self.maxpool(identity) - ''' - identity = self.avgpool(identity) - identity = self.conv_down(identity) - - out = self.conv1(x) - out = self.conv2(out) - out = self.conv3(out) - out = self.act(out + identity) - - if self.downsamping: - return out#, max_indices - else: - return out - - -class UpsamplingBottleneck(nn.Module): - """upsampling Block""" - - def __init__(self, in_channels, inter_channels, out_channels, norm_layer=nn.BatchNorm2d, **kwargs): - self.npu = kwargs['npu'] - - super(UpsamplingBottleneck, self).__init__() - self.conv = nn.Sequential( - nn.Conv2d(in_channels, out_channels, 1, bias=False), - norm_layer(out_channels) - ) - #self.upsampling = nn.MaxUnpool2d(2) - self.upsampling = nn.Upsample(scale_factor=2, mode='nearest') - - self.block = nn.Sequential( - nn.Conv2d(in_channels, inter_channels, 1, bias=False), - norm_layer(inter_channels), - nn.PReLU(), - nn.ConvTranspose2d(inter_channels, inter_channels, 2, 2, bias=False), - norm_layer(inter_channels), - nn.PReLU(), - nn.Conv2d(inter_channels, out_channels, 1, bias=False), - norm_layer(out_channels), - nn.Dropout2d(0.1) - ) - self.act = nn.PReLU() - - def forward(self, x):#, max_indices): - out_up = self.conv(x) - ''' - if self.npu: - out_up = out_up.to(torch.float32) - max_indices = max_indices.to(torch.int64).npu() - out_up = self.upsampling(out_up, max_indices).to(torch.half) - else: - out_up = self.upsampling(out_up, max_indices) - ''' - out_up = self.upsampling(out_up) - out_ext = self.block(x) - out = self.act(out_up + out_ext) - return out - - -def get_enet(dataset='citys', backbone='', pretrained=False, root='~/.torch/models', pretrained_base=True, **kwargs): - acronyms = { - 'pascal_voc': 'pascal_voc', - 'pascal_aug': 'pascal_aug', - 'ade20k': 'ade', - 'coco': 'coco', - 'citys': 'citys', - } - from core.data.dataloader import datasets - model = ENet(datasets[dataset].NUM_CLASS, backbone=backbone, pretrained_base=pretrained_base, **kwargs) - if pretrained: - from .model_store import get_model_file - device = torch.device(kwargs['local_rank']) - model.load_state_dict(torch.load(get_model_file('enet_%s' % (acronyms[dataset]), root=root), - map_location=device)) - return model - - -def get_enet_citys(**kwargs): - return get_enet('citys', '', **kwargs) - - -if __name__ == '__main__': - img = torch.randn(1, 3, 512, 512) - model = get_enet_citys() - output = model(img) - - -"""Efficient Neural Network""" -import torch -import torch.nn as nn - -__all__ = ['ENet', 'get_enet', 'get_enet_citys'] - - -class ENet(nn.Module): - """Efficient Neural Network""" - - def __init__(self, nclass, backbone='', aux=False, jpu=False, pretrained_base=None, **kwargs): - super(ENet, self).__init__() - self.initial = InitialBlock(13, **kwargs) - - self.bottleneck1_0 = Bottleneck(16, 16, 64, downsampling=True, **kwargs) - self.bottleneck1_1 = Bottleneck(64, 16, 64, **kwargs) - self.bottleneck1_2 = Bottleneck(64, 16, 64, **kwargs) - self.bottleneck1_3 = Bottleneck(64, 16, 64, **kwargs) - self.bottleneck1_4 = Bottleneck(64, 16, 64, **kwargs) - - self.bottleneck2_0 = Bottleneck(64, 32, 128, downsampling=True, **kwargs) - self.bottleneck2_1 = Bottleneck(128, 32, 128, **kwargs) - self.bottleneck2_2 = Bottleneck(128, 32, 128, dilation=2, **kwargs) - self.bottleneck2_3 = Bottleneck(128, 32, 128, asymmetric=True, **kwargs) - self.bottleneck2_4 = Bottleneck(128, 32, 128, dilation=4, **kwargs) - self.bottleneck2_5 = Bottleneck(128, 32, 128, **kwargs) - self.bottleneck2_6 = Bottleneck(128, 32, 128, dilation=8, **kwargs) - self.bottleneck2_7 = Bottleneck(128, 32, 128, asymmetric=True, **kwargs) - self.bottleneck2_8 = Bottleneck(128, 32, 128, dilation=16, **kwargs) - - self.bottleneck3_1 = Bottleneck(128, 32, 128, **kwargs) - self.bottleneck3_2 = Bottleneck(128, 32, 128, dilation=2, **kwargs) - self.bottleneck3_3 = Bottleneck(128, 32, 128, asymmetric=True, **kwargs) - self.bottleneck3_4 = Bottleneck(128, 32, 128, dilation=4, **kwargs) - self.bottleneck3_5 = Bottleneck(128, 32, 128, **kwargs) - self.bottleneck3_6 = Bottleneck(128, 32, 128, dilation=8, **kwargs) - self.bottleneck3_7 = Bottleneck(128, 32, 128, asymmetric=True, **kwargs) - self.bottleneck3_8 = Bottleneck(128, 32, 128, dilation=16, **kwargs) - - self.bottleneck4_0 = UpsamplingBottleneck(128, 16, 64, **kwargs) - self.bottleneck4_1 = Bottleneck(64, 16, 64, **kwargs) - self.bottleneck4_2 = Bottleneck(64, 16, 64, **kwargs) - - self.bottleneck5_0 = UpsamplingBottleneck(64, 4, 16, **kwargs) - self.bottleneck5_1 = Bottleneck(16, 4, 16, **kwargs) - - self.fullconv = nn.ConvTranspose2d(16, nclass, 2, 2, bias=False) - - self.__setattr__('exclusive', ['bottleneck1_0', 'bottleneck1_1', 'bottleneck1_2', 'bottleneck1_3', - 'bottleneck1_4', 'bottleneck2_0', 'bottleneck2_1', 'bottleneck2_2', - 'bottleneck2_3', 'bottleneck2_4', 'bottleneck2_5', 'bottleneck2_6', - 'bottleneck2_7', 'bottleneck2_8', 'bottleneck3_1', 'bottleneck3_2', - 'bottleneck3_3', 'bottleneck3_4', 'bottleneck3_5', 'bottleneck3_6', - 'bottleneck3_7', 'bottleneck3_8', 'bottleneck4_0', 'bottleneck4_1', - 'bottleneck4_2', 'bottleneck5_0', 'bottleneck5_1', 'fullconv']) - - def forward(self, x): - # init - x = self.initial(x) - - # stage 1 - x, max_indices1 = self.bottleneck1_0(x) - #x = self.bottleneck1_0(x) - x = self.bottleneck1_1(x) - x = self.bottleneck1_2(x) - x = self.bottleneck1_3(x) - x = self.bottleneck1_4(x) - - # stage 2 - x, max_indices2 = self.bottleneck2_0(x) - #x = self.bottleneck2_0(x) - x = self.bottleneck2_1(x) - x = self.bottleneck2_2(x) - x = self.bottleneck2_3(x) - x = self.bottleneck2_4(x) - x = self.bottleneck2_5(x) - x = self.bottleneck2_6(x) - x = self.bottleneck2_7(x) - x = self.bottleneck2_8(x) - - # stage 3 - x = self.bottleneck3_1(x) - x = self.bottleneck3_2(x) - x = self.bottleneck3_3(x) - x = self.bottleneck3_4(x) - x = self.bottleneck3_6(x) - x = self.bottleneck3_7(x) - x = self.bottleneck3_8(x) - - # stage 4 - x = self.bottleneck4_0(x, max_indices2) - #x = self.bottleneck4_0(x) - x = self.bottleneck4_1(x) - x = self.bottleneck4_2(x) - - # stage 5 - x = self.bottleneck5_0(x, max_indices1) - #x = self.bottleneck5_0(x) - x = self.bottleneck5_1(x) - - # out - x = self.fullconv(x) - return tuple([x]) - - -class InitialBlock(nn.Module): - """ENet initial block""" - - def __init__(self, out_channels, norm_layer=nn.BatchNorm2d, **kwargs): - super(InitialBlock, self).__init__() - self.conv = nn.Conv2d(3, out_channels, 3, 2, 1, bias=False) - self.maxpool = nn.MaxPool2d(2, 2) - self.bn = norm_layer(out_channels + 3) - self.act = nn.PReLU() - - def forward(self, x): - x_conv = self.conv(x) - x_pool = self.maxpool(x) - x = torch.cat([x_conv, x_pool], dim=1) - x = self.bn(x) - x = self.act(x) - return x - - -class Bottleneck(nn.Module): - """Bottlenecks include regular, asymmetric, downsampling, dilated""" - - def __init__(self, in_channels, inter_channels, out_channels, dilation=1, asymmetric=False, - downsampling=False, norm_layer=nn.BatchNorm2d, **kwargs): - self.npu = kwargs['npu'] - - super(Bottleneck, self).__init__() - self.downsamping = downsampling - if downsampling: - self.maxpool = nn.MaxPool2d(2, 2, return_indices=True) - #self.avgpool = nn.AvgPool2d((2, 2), stride=(2,2)) - self.conv_down = nn.Sequential( - nn.Conv2d(in_channels, out_channels, 1, bias=False), - norm_layer(out_channels) - ) - - self.conv1 = nn.Sequential( - nn.Conv2d(in_channels, inter_channels, 1, bias=False), - norm_layer(inter_channels), - nn.PReLU() - ) - - if downsampling: - self.conv2 = nn.Sequential( - nn.Conv2d(inter_channels, inter_channels, 2, stride=2, bias=False), - norm_layer(inter_channels), - nn.PReLU() - ) - else: - if asymmetric: - self.conv2 = nn.Sequential( - nn.Conv2d(inter_channels, inter_channels, (5, 1), padding=(2, 0), bias=False), - nn.Conv2d(inter_channels, inter_channels, (1, 5), padding=(0, 2), bias=False), - norm_layer(inter_channels), - nn.PReLU() - ) - else: - self.conv2 = nn.Sequential( - nn.Conv2d(inter_channels, inter_channels, 3, dilation=dilation, padding=dilation, bias=False), - norm_layer(inter_channels), - nn.PReLU() - ) - self.conv3 = nn.Sequential( - nn.Conv2d(inter_channels, out_channels, 1, bias=False), - norm_layer(out_channels), - nn.Dropout2d(0.1) - ) - self.act = nn.PReLU() - - def forward(self, x): - identity = x - if self.downsamping: - if self.npu: - identity = x.cpu().to(torch.float32) - identity, max_indices = self.maxpool(identity) - identity = identity.npu().to(torch.float16) - else: - identity, max_indices = self.maxpool(identity) - #identity = self.avgpool(identity) - identity = self.conv_down(identity) - - out = self.conv1(x) - out = self.conv2(out) - out = self.conv3(out) - out = self.act(out + identity) - - if self.downsamping: - return out, max_indices - else: - return out - - -class UpsamplingBottleneck(nn.Module): - """upsampling Block""" - - def __init__(self, in_channels, inter_channels, out_channels, norm_layer=nn.BatchNorm2d, **kwargs): - self.npu = kwargs['npu'] - - super(UpsamplingBottleneck, self).__init__() - self.conv = nn.Sequential( - nn.Conv2d(in_channels, out_channels, 1, bias=False), - norm_layer(out_channels) - ) - self.upsampling = nn.MaxUnpool2d(2) - #self.upsampling = nn.Upsample(scale_factor=2, mode='nearest') - - self.block = nn.Sequential( - nn.Conv2d(in_channels, inter_channels, 1, bias=False), - norm_layer(inter_channels), - nn.PReLU(), - nn.ConvTranspose2d(inter_channels, inter_channels, 2, 2, bias=False), - norm_layer(inter_channels), - nn.PReLU(), - nn.Conv2d(inter_channels, out_channels, 1, bias=False), - norm_layer(out_channels), - nn.Dropout2d(0.1) - ) - self.act = nn.PReLU() - - def forward(self, x, max_indices): - out_up = self.conv(x) - - if self.npu: - out_up = out_up.to(torch.float32) - max_indices = max_indices.to(torch.int64).npu() - out_up = self.upsampling(out_up, max_indices).to(torch.half) - else: - out_up = self.upsampling(out_up, max_indices) - - #out_up = self.upsampling(out_up) - out_ext = self.block(x) - out = self.act(out_up + out_ext) - return out - - -def get_enet(dataset='citys', backbone='', pretrained=False, root='~/.torch/models', pretrained_base=True, **kwargs): - acronyms = { - 'pascal_voc': 'pascal_voc', - 'pascal_aug': 'pascal_aug', - 'ade20k': 'ade', - 'coco': 'coco', - 'citys': 'citys', - } - from core.data.dataloader import datasets - model = ENet(datasets[dataset].NUM_CLASS, backbone=backbone, pretrained_base=pretrained_base, **kwargs) - if pretrained: - from .model_store import get_model_file - device = torch.device(kwargs['local_rank']) - model.load_state_dict(torch.load(get_model_file('enet_%s' % (acronyms[dataset]), root=root), - map_location=device)) - return model - - -def get_enet_citys(**kwargs): - return get_enet('citys', '', **kwargs) - - -if __name__ == '__main__': - img = torch.randn(1, 3, 512, 512) - model = get_enet_citys() - output = model(img) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +"""Efficient Neural Network""" +import torch +import torch.nn as nn + +__all__ = ['ENet', 'get_enet', 'get_enet_citys'] + + +class ENet(nn.Module): + """Efficient Neural Network""" + + def __init__(self, nclass, backbone='', aux=False, jpu=False, pretrained_base=None, **kwargs): + super(ENet, self).__init__() + self.initial = InitialBlock(13, **kwargs) + + self.bottleneck1_0 = Bottleneck(16, 16, 64, downsampling=True, **kwargs) + self.bottleneck1_1 = Bottleneck(64, 16, 64, **kwargs) + self.bottleneck1_2 = Bottleneck(64, 16, 64, **kwargs) + self.bottleneck1_3 = Bottleneck(64, 16, 64, **kwargs) + self.bottleneck1_4 = Bottleneck(64, 16, 64, **kwargs) + + self.bottleneck2_0 = Bottleneck(64, 32, 128, downsampling=True, **kwargs) + self.bottleneck2_1 = Bottleneck(128, 32, 128, **kwargs) + self.bottleneck2_2 = Bottleneck(128, 32, 128, dilation=2, **kwargs) + self.bottleneck2_3 = Bottleneck(128, 32, 128, asymmetric=True, **kwargs) + self.bottleneck2_4 = Bottleneck(128, 32, 128, dilation=4, **kwargs) + self.bottleneck2_5 = Bottleneck(128, 32, 128, **kwargs) + self.bottleneck2_6 = Bottleneck(128, 32, 128, dilation=8, **kwargs) + self.bottleneck2_7 = Bottleneck(128, 32, 128, asymmetric=True, **kwargs) + self.bottleneck2_8 = Bottleneck(128, 32, 128, dilation=16, **kwargs) + + self.bottleneck3_1 = Bottleneck(128, 32, 128, **kwargs) + self.bottleneck3_2 = Bottleneck(128, 32, 128, dilation=2, **kwargs) + self.bottleneck3_3 = Bottleneck(128, 32, 128, asymmetric=True, **kwargs) + self.bottleneck3_4 = Bottleneck(128, 32, 128, dilation=4, **kwargs) + self.bottleneck3_5 = Bottleneck(128, 32, 128, **kwargs) + self.bottleneck3_6 = Bottleneck(128, 32, 128, dilation=8, **kwargs) + self.bottleneck3_7 = Bottleneck(128, 32, 128, asymmetric=True, **kwargs) + self.bottleneck3_8 = Bottleneck(128, 32, 128, dilation=16, **kwargs) + + self.bottleneck4_0 = UpsamplingBottleneck(128, 16, 64, **kwargs) + self.bottleneck4_1 = Bottleneck(64, 16, 64, **kwargs) + self.bottleneck4_2 = Bottleneck(64, 16, 64, **kwargs) + + self.bottleneck5_0 = UpsamplingBottleneck(64, 4, 16, **kwargs) + self.bottleneck5_1 = Bottleneck(16, 4, 16, **kwargs) + + self.fullconv = nn.ConvTranspose2d(16, nclass, 2, 2, bias=False) + + self.__setattr__('exclusive', ['bottleneck1_0', 'bottleneck1_1', 'bottleneck1_2', 'bottleneck1_3', + 'bottleneck1_4', 'bottleneck2_0', 'bottleneck2_1', 'bottleneck2_2', + 'bottleneck2_3', 'bottleneck2_4', 'bottleneck2_5', 'bottleneck2_6', + 'bottleneck2_7', 'bottleneck2_8', 'bottleneck3_1', 'bottleneck3_2', + 'bottleneck3_3', 'bottleneck3_4', 'bottleneck3_5', 'bottleneck3_6', + 'bottleneck3_7', 'bottleneck3_8', 'bottleneck4_0', 'bottleneck4_1', + 'bottleneck4_2', 'bottleneck5_0', 'bottleneck5_1', 'fullconv']) + + def forward(self, x): + # init + x = self.initial(x) + + # stage 1 + #x, max_indices1 = self.bottleneck1_0(x) + x = self.bottleneck1_0(x) + x = self.bottleneck1_1(x) + x = self.bottleneck1_2(x) + x = self.bottleneck1_3(x) + x = self.bottleneck1_4(x) + + # stage 2 + #x, max_indices2 = self.bottleneck2_0(x) + x = self.bottleneck2_0(x) + x = self.bottleneck2_1(x) + x = self.bottleneck2_2(x) + x = self.bottleneck2_3(x) + x = self.bottleneck2_4(x) + x = self.bottleneck2_5(x) + x = self.bottleneck2_6(x) + x = self.bottleneck2_7(x) + x = self.bottleneck2_8(x) + + # stage 3 + x = self.bottleneck3_1(x) + x = self.bottleneck3_2(x) + x = self.bottleneck3_3(x) + x = self.bottleneck3_4(x) + x = self.bottleneck3_6(x) + x = self.bottleneck3_7(x) + x = self.bottleneck3_8(x) + + # stage 4 + #x = self.bottleneck4_0(x, max_indices2) + x = self.bottleneck4_0(x) + x = self.bottleneck4_1(x) + x = self.bottleneck4_2(x) + + # stage 5 + #x = self.bottleneck5_0(x, max_indices1) + x = self.bottleneck5_0(x) + x = self.bottleneck5_1(x) + + # out + x = self.fullconv(x) + return tuple([x]) + + +class InitialBlock(nn.Module): + """ENet initial block""" + + def __init__(self, out_channels, norm_layer=nn.BatchNorm2d, **kwargs): + super(InitialBlock, self).__init__() + self.conv = nn.Conv2d(3, out_channels, 3, 2, 1, bias=False) + self.maxpool = nn.MaxPool2d(2, 2) + self.bn = norm_layer(out_channels + 3) + self.act = nn.PReLU() + + def forward(self, x): + x_conv = self.conv(x) + x_pool = self.maxpool(x) + x = torch.cat([x_conv, x_pool], dim=1) + x = self.bn(x) + x = self.act(x) + return x + + +class Bottleneck(nn.Module): + """Bottlenecks include regular, asymmetric, downsampling, dilated""" + + def __init__(self, in_channels, inter_channels, out_channels, dilation=1, asymmetric=False, + downsampling=False, norm_layer=nn.BatchNorm2d, **kwargs): + self.npu = kwargs['npu'] + + super(Bottleneck, self).__init__() + self.downsamping = downsampling + if downsampling: + #self.maxpool = nn.MaxPool2d(2, 2, return_indices=True) + self.avgpool = nn.AvgPool2d((2, 2), stride=(2,2)) + self.conv_down = nn.Sequential( + nn.Conv2d(in_channels, out_channels, 1, bias=False), + norm_layer(out_channels) + ) + + self.conv1 = nn.Sequential( + nn.Conv2d(in_channels, inter_channels, 1, bias=False), + norm_layer(inter_channels), + nn.PReLU() + ) + + if downsampling: + self.conv2 = nn.Sequential( + nn.Conv2d(inter_channels, inter_channels, 2, stride=2, bias=False), + norm_layer(inter_channels), + nn.PReLU() + ) + else: + if asymmetric: + self.conv2 = nn.Sequential( + nn.Conv2d(inter_channels, inter_channels, (5, 1), padding=(2, 0), bias=False), + nn.Conv2d(inter_channels, inter_channels, (1, 5), padding=(0, 2), bias=False), + norm_layer(inter_channels), + nn.PReLU() + ) + else: + self.conv2 = nn.Sequential( + nn.Conv2d(inter_channels, inter_channels, 3, dilation=dilation, padding=dilation, bias=False), + norm_layer(inter_channels), + nn.PReLU() + ) + self.conv3 = nn.Sequential( + nn.Conv2d(inter_channels, out_channels, 1, bias=False), + norm_layer(out_channels), + nn.Dropout2d(0.1) + ) + self.act = nn.PReLU() + + def forward(self, x): + identity = x + if self.downsamping: + ''' + if self.npu: + identity = x.cpu().to(torch.float32) + identity, max_indices = self.maxpool(identity) + identity = identity.npu().to(torch.float16) + else: + identity, max_indices = self.maxpool(identity) + ''' + identity = self.avgpool(identity) + identity = self.conv_down(identity) + + out = self.conv1(x) + out = self.conv2(out) + out = self.conv3(out) + out = self.act(out + identity) + + if self.downsamping: + return out#, max_indices + else: + return out + + +class UpsamplingBottleneck(nn.Module): + """upsampling Block""" + + def __init__(self, in_channels, inter_channels, out_channels, norm_layer=nn.BatchNorm2d, **kwargs): + self.npu = kwargs['npu'] + + super(UpsamplingBottleneck, self).__init__() + self.conv = nn.Sequential( + nn.Conv2d(in_channels, out_channels, 1, bias=False), + norm_layer(out_channels) + ) + #self.upsampling = nn.MaxUnpool2d(2) + self.upsampling = nn.Upsample(scale_factor=2, mode='nearest') + + self.block = nn.Sequential( + nn.Conv2d(in_channels, inter_channels, 1, bias=False), + norm_layer(inter_channels), + nn.PReLU(), + nn.ConvTranspose2d(inter_channels, inter_channels, 2, 2, bias=False), + norm_layer(inter_channels), + nn.PReLU(), + nn.Conv2d(inter_channels, out_channels, 1, bias=False), + norm_layer(out_channels), + nn.Dropout2d(0.1) + ) + self.act = nn.PReLU() + + def forward(self, x):#, max_indices): + out_up = self.conv(x) + ''' + if self.npu: + out_up = out_up.to(torch.float32) + max_indices = max_indices.to(torch.int64).npu() + out_up = self.upsampling(out_up, max_indices).to(torch.half) + else: + out_up = self.upsampling(out_up, max_indices) + ''' + out_up = self.upsampling(out_up) + out_ext = self.block(x) + out = self.act(out_up + out_ext) + return out + + +def get_enet(dataset='citys', backbone='', pretrained=False, root='~/.torch/models', pretrained_base=True, **kwargs): + acronyms = { + 'pascal_voc': 'pascal_voc', + 'pascal_aug': 'pascal_aug', + 'ade20k': 'ade', + 'coco': 'coco', + 'citys': 'citys', + } + from core.data.dataloader import datasets + model = ENet(datasets[dataset].NUM_CLASS, backbone=backbone, pretrained_base=pretrained_base, **kwargs) + if pretrained: + from .model_store import get_model_file + device = torch.device(kwargs['local_rank']) + model.load_state_dict(torch.load(get_model_file('enet_%s' % (acronyms[dataset]), root=root), + map_location=device)) + return model + + +def get_enet_citys(**kwargs): + return get_enet('citys', '', **kwargs) + + +if __name__ == '__main__': + img = torch.randn(1, 3, 512, 512) + model = get_enet_citys() + output = model(img) + + +"""Efficient Neural Network""" +import torch +import torch.nn as nn + +__all__ = ['ENet', 'get_enet', 'get_enet_citys'] + + +class ENet(nn.Module): + """Efficient Neural Network""" + + def __init__(self, nclass, backbone='', aux=False, jpu=False, pretrained_base=None, **kwargs): + super(ENet, self).__init__() + self.initial = InitialBlock(13, **kwargs) + + self.bottleneck1_0 = Bottleneck(16, 16, 64, downsampling=True, **kwargs) + self.bottleneck1_1 = Bottleneck(64, 16, 64, **kwargs) + self.bottleneck1_2 = Bottleneck(64, 16, 64, **kwargs) + self.bottleneck1_3 = Bottleneck(64, 16, 64, **kwargs) + self.bottleneck1_4 = Bottleneck(64, 16, 64, **kwargs) + + self.bottleneck2_0 = Bottleneck(64, 32, 128, downsampling=True, **kwargs) + self.bottleneck2_1 = Bottleneck(128, 32, 128, **kwargs) + self.bottleneck2_2 = Bottleneck(128, 32, 128, dilation=2, **kwargs) + self.bottleneck2_3 = Bottleneck(128, 32, 128, asymmetric=True, **kwargs) + self.bottleneck2_4 = Bottleneck(128, 32, 128, dilation=4, **kwargs) + self.bottleneck2_5 = Bottleneck(128, 32, 128, **kwargs) + self.bottleneck2_6 = Bottleneck(128, 32, 128, dilation=8, **kwargs) + self.bottleneck2_7 = Bottleneck(128, 32, 128, asymmetric=True, **kwargs) + self.bottleneck2_8 = Bottleneck(128, 32, 128, dilation=16, **kwargs) + + self.bottleneck3_1 = Bottleneck(128, 32, 128, **kwargs) + self.bottleneck3_2 = Bottleneck(128, 32, 128, dilation=2, **kwargs) + self.bottleneck3_3 = Bottleneck(128, 32, 128, asymmetric=True, **kwargs) + self.bottleneck3_4 = Bottleneck(128, 32, 128, dilation=4, **kwargs) + self.bottleneck3_5 = Bottleneck(128, 32, 128, **kwargs) + self.bottleneck3_6 = Bottleneck(128, 32, 128, dilation=8, **kwargs) + self.bottleneck3_7 = Bottleneck(128, 32, 128, asymmetric=True, **kwargs) + self.bottleneck3_8 = Bottleneck(128, 32, 128, dilation=16, **kwargs) + + self.bottleneck4_0 = UpsamplingBottleneck(128, 16, 64, **kwargs) + self.bottleneck4_1 = Bottleneck(64, 16, 64, **kwargs) + self.bottleneck4_2 = Bottleneck(64, 16, 64, **kwargs) + + self.bottleneck5_0 = UpsamplingBottleneck(64, 4, 16, **kwargs) + self.bottleneck5_1 = Bottleneck(16, 4, 16, **kwargs) + + self.fullconv = nn.ConvTranspose2d(16, nclass, 2, 2, bias=False) + + self.__setattr__('exclusive', ['bottleneck1_0', 'bottleneck1_1', 'bottleneck1_2', 'bottleneck1_3', + 'bottleneck1_4', 'bottleneck2_0', 'bottleneck2_1', 'bottleneck2_2', + 'bottleneck2_3', 'bottleneck2_4', 'bottleneck2_5', 'bottleneck2_6', + 'bottleneck2_7', 'bottleneck2_8', 'bottleneck3_1', 'bottleneck3_2', + 'bottleneck3_3', 'bottleneck3_4', 'bottleneck3_5', 'bottleneck3_6', + 'bottleneck3_7', 'bottleneck3_8', 'bottleneck4_0', 'bottleneck4_1', + 'bottleneck4_2', 'bottleneck5_0', 'bottleneck5_1', 'fullconv']) + + def forward(self, x): + # init + x = self.initial(x) + + # stage 1 + x, max_indices1 = self.bottleneck1_0(x) + #x = self.bottleneck1_0(x) + x = self.bottleneck1_1(x) + x = self.bottleneck1_2(x) + x = self.bottleneck1_3(x) + x = self.bottleneck1_4(x) + + # stage 2 + x, max_indices2 = self.bottleneck2_0(x) + #x = self.bottleneck2_0(x) + x = self.bottleneck2_1(x) + x = self.bottleneck2_2(x) + x = self.bottleneck2_3(x) + x = self.bottleneck2_4(x) + x = self.bottleneck2_5(x) + x = self.bottleneck2_6(x) + x = self.bottleneck2_7(x) + x = self.bottleneck2_8(x) + + # stage 3 + x = self.bottleneck3_1(x) + x = self.bottleneck3_2(x) + x = self.bottleneck3_3(x) + x = self.bottleneck3_4(x) + x = self.bottleneck3_6(x) + x = self.bottleneck3_7(x) + x = self.bottleneck3_8(x) + + # stage 4 + x = self.bottleneck4_0(x, max_indices2) + #x = self.bottleneck4_0(x) + x = self.bottleneck4_1(x) + x = self.bottleneck4_2(x) + + # stage 5 + x = self.bottleneck5_0(x, max_indices1) + #x = self.bottleneck5_0(x) + x = self.bottleneck5_1(x) + + # out + x = self.fullconv(x) + return tuple([x]) + + +class InitialBlock(nn.Module): + """ENet initial block""" + + def __init__(self, out_channels, norm_layer=nn.BatchNorm2d, **kwargs): + super(InitialBlock, self).__init__() + self.conv = nn.Conv2d(3, out_channels, 3, 2, 1, bias=False) + self.maxpool = nn.MaxPool2d(2, 2) + self.bn = norm_layer(out_channels + 3) + self.act = nn.PReLU() + + def forward(self, x): + x_conv = self.conv(x) + x_pool = self.maxpool(x) + x = torch.cat([x_conv, x_pool], dim=1) + x = self.bn(x) + x = self.act(x) + return x + + +class Bottleneck(nn.Module): + """Bottlenecks include regular, asymmetric, downsampling, dilated""" + + def __init__(self, in_channels, inter_channels, out_channels, dilation=1, asymmetric=False, + downsampling=False, norm_layer=nn.BatchNorm2d, **kwargs): + self.npu = kwargs['npu'] + + super(Bottleneck, self).__init__() + self.downsamping = downsampling + if downsampling: + self.maxpool = nn.MaxPool2d(2, 2, return_indices=True) + #self.avgpool = nn.AvgPool2d((2, 2), stride=(2,2)) + self.conv_down = nn.Sequential( + nn.Conv2d(in_channels, out_channels, 1, bias=False), + norm_layer(out_channels) + ) + + self.conv1 = nn.Sequential( + nn.Conv2d(in_channels, inter_channels, 1, bias=False), + norm_layer(inter_channels), + nn.PReLU() + ) + + if downsampling: + self.conv2 = nn.Sequential( + nn.Conv2d(inter_channels, inter_channels, 2, stride=2, bias=False), + norm_layer(inter_channels), + nn.PReLU() + ) + else: + if asymmetric: + self.conv2 = nn.Sequential( + nn.Conv2d(inter_channels, inter_channels, (5, 1), padding=(2, 0), bias=False), + nn.Conv2d(inter_channels, inter_channels, (1, 5), padding=(0, 2), bias=False), + norm_layer(inter_channels), + nn.PReLU() + ) + else: + self.conv2 = nn.Sequential( + nn.Conv2d(inter_channels, inter_channels, 3, dilation=dilation, padding=dilation, bias=False), + norm_layer(inter_channels), + nn.PReLU() + ) + self.conv3 = nn.Sequential( + nn.Conv2d(inter_channels, out_channels, 1, bias=False), + norm_layer(out_channels), + nn.Dropout2d(0.1) + ) + self.act = nn.PReLU() + + def forward(self, x): + identity = x + if self.downsamping: + if self.npu: + identity = x.cpu().to(torch.float32) + identity, max_indices = self.maxpool(identity) + identity = identity.npu().to(torch.float16) + else: + identity, max_indices = self.maxpool(identity) + #identity = self.avgpool(identity) + identity = self.conv_down(identity) + + out = self.conv1(x) + out = self.conv2(out) + out = self.conv3(out) + out = self.act(out + identity) + + if self.downsamping: + return out, max_indices + else: + return out + + +class UpsamplingBottleneck(nn.Module): + """upsampling Block""" + + def __init__(self, in_channels, inter_channels, out_channels, norm_layer=nn.BatchNorm2d, **kwargs): + self.npu = kwargs['npu'] + + super(UpsamplingBottleneck, self).__init__() + self.conv = nn.Sequential( + nn.Conv2d(in_channels, out_channels, 1, bias=False), + norm_layer(out_channels) + ) + self.upsampling = nn.MaxUnpool2d(2) + #self.upsampling = nn.Upsample(scale_factor=2, mode='nearest') + + self.block = nn.Sequential( + nn.Conv2d(in_channels, inter_channels, 1, bias=False), + norm_layer(inter_channels), + nn.PReLU(), + nn.ConvTranspose2d(inter_channels, inter_channels, 2, 2, bias=False), + norm_layer(inter_channels), + nn.PReLU(), + nn.Conv2d(inter_channels, out_channels, 1, bias=False), + norm_layer(out_channels), + nn.Dropout2d(0.1) + ) + self.act = nn.PReLU() + + def forward(self, x, max_indices): + out_up = self.conv(x) + + if self.npu: + out_up = out_up.to(torch.float32) + max_indices = max_indices.to(torch.int64).npu() + out_up = self.upsampling(out_up, max_indices).to(torch.half) + else: + out_up = self.upsampling(out_up, max_indices) + + #out_up = self.upsampling(out_up) + out_ext = self.block(x) + out = self.act(out_up + out_ext) + return out + + +def get_enet(dataset='citys', backbone='', pretrained=False, root='~/.torch/models', pretrained_base=True, **kwargs): + acronyms = { + 'pascal_voc': 'pascal_voc', + 'pascal_aug': 'pascal_aug', + 'ade20k': 'ade', + 'coco': 'coco', + 'citys': 'citys', + } + from core.data.dataloader import datasets + model = ENet(datasets[dataset].NUM_CLASS, backbone=backbone, pretrained_base=pretrained_base, **kwargs) + if pretrained: + from .model_store import get_model_file + device = torch.device(kwargs['local_rank']) + model.load_state_dict(torch.load(get_model_file('enet_%s' % (acronyms[dataset]), root=root), + map_location=device)) + return model + + +def get_enet_citys(**kwargs): + return get_enet('citys', '', **kwargs) + + +if __name__ == '__main__': + img = torch.randn(1, 3, 512, 512) + model = get_enet_citys() + output = model(img) diff --git a/PyTorch/contrib/cv/semantic_segmentation/ENet/core/models/ocnet.py b/PyTorch/contrib/cv/semantic_segmentation/ENet/core/models/ocnet.py index e59df3ce96..4eea5bd8d9 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/ENet/core/models/ocnet.py +++ b/PyTorch/contrib/cv/semantic_segmentation/ENet/core/models/ocnet.py @@ -1,359 +1,359 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -""" Object Context Network for Scene Parsing""" -import torch -import torch.nn as nn -import torch.nn.functional as F - -from .segbase import SegBaseModel -from .fcn import _FCNHead - -__all__ = ['OCNet', 'get_ocnet', 'get_base_ocnet_resnet101_citys', - 'get_pyramid_ocnet_resnet101_citys', 'get_asp_ocnet_resnet101_citys'] - - -class OCNet(SegBaseModel): - r"""OCNet - - Parameters - ---------- - nclass : int - Number of categories for the training dataset. - backbone : string - Pre-trained dilated backbone network type (default:'resnet50'; 'resnet50', - 'resnet101' or 'resnet152'). - norm_layer : object - Normalization layer used in backbone network (default: :class:`nn.BatchNorm`; - for Synchronized Cross-GPU BachNormalization). - aux : bool - Auxiliary loss. - Reference: - Yuhui Yuan, Jingdong Wang. "OCNet: Object Context Network for Scene Parsing." - arXiv preprint arXiv:1809.00916 (2018). - """ - - def __init__(self, nclass, backbone='resnet101', oc_arch='base', aux=False, pretrained_base=True, **kwargs): - super(OCNet, self).__init__(nclass, aux, backbone, pretrained_base=pretrained_base, **kwargs) - self.head = _OCHead(nclass, oc_arch, **kwargs) - if self.aux: - self.auxlayer = _FCNHead(1024, nclass, **kwargs) - - self.__setattr__('exclusive', ['head', 'auxlayer'] if aux else ['head']) - - def forward(self, x): - size = x.size()[2:] - _, _, c3, c4 = self.base_forward(x) - outputs = [] - x = self.head(c4) - x = F.interpolate(x, size, mode='bilinear', align_corners=True) - outputs.append(x) - - if self.aux: - auxout = self.auxlayer(c3) - auxout = F.interpolate(auxout, size, mode='bilinear', align_corners=True) - outputs.append(auxout) - return tuple(outputs) - - -class _OCHead(nn.Module): - def __init__(self, nclass, oc_arch, norm_layer=nn.BatchNorm2d, **kwargs): - super(_OCHead, self).__init__() - if oc_arch == 'base': - self.context = nn.Sequential( - nn.Conv2d(2048, 512, 3, 1, padding=1, bias=False), - norm_layer(512), - nn.ReLU(True), - BaseOCModule(512, 512, 256, 256, scales=([1]), norm_layer=norm_layer, **kwargs)) - elif oc_arch == 'pyramid': - self.context = nn.Sequential( - nn.Conv2d(2048, 512, 3, 1, padding=1, bias=False), - norm_layer(512), - nn.ReLU(True), - PyramidOCModule(512, 512, 256, 512, scales=([1, 2, 3, 6]), norm_layer=norm_layer, **kwargs)) - elif oc_arch == 'asp': - self.context = ASPOCModule(2048, 512, 256, 512, norm_layer=norm_layer, **kwargs) - else: - raise ValueError("Unknown OC architecture!") - - self.out = nn.Conv2d(512, nclass, 1) - - def forward(self, x): - x = self.context(x) - return self.out(x) - - -class BaseAttentionBlock(nn.Module): - """The basic implementation for self-attention block/non-local block.""" - - def __init__(self, in_channels, out_channels, key_channels, value_channels, - scale=1, norm_layer=nn.BatchNorm2d, **kwargs): - super(BaseAttentionBlock, self).__init__() - self.scale = scale - self.key_channels = key_channels - self.value_channels = value_channels - if scale > 1: - self.pool = nn.MaxPool2d(scale) - - self.f_value = nn.Conv2d(in_channels, value_channels, 1) - self.f_key = nn.Sequential( - nn.Conv2d(in_channels, key_channels, 1), - norm_layer(key_channels), - nn.ReLU(True) - ) - self.f_query = self.f_key - self.W = nn.Conv2d(value_channels, out_channels, 1) - nn.init.constant_(self.W.weight, 0) - nn.init.constant_(self.W.bias, 0) - - def forward(self, x): - batch_size, c, w, h = x.size() - if self.scale > 1: - x = self.pool(x) - - value = self.f_value(x).view(batch_size, self.value_channels, -1).permute(0, 2, 1) - query = self.f_query(x).view(batch_size, self.key_channels, -1).permute(0, 2, 1) - key = self.f_key(x).view(batch_size, self.key_channels, -1) - - sim_map = torch.bmm(query, key) * (self.key_channels ** -.5) - sim_map = F.softmax(sim_map, dim=-1) - - context = torch.bmm(sim_map, value).permute(0, 2, 1).contiguous() - context = context.view(batch_size, self.value_channels, *x.size()[2:]) - context = self.W(context) - if self.scale > 1: - context = F.interpolate(context, size=(w, h), mode='bilinear', align_corners=True) - - return context - - -class BaseOCModule(nn.Module): - """Base-OC""" - - def __init__(self, in_channels, out_channels, key_channels, value_channels, - scales=([1]), norm_layer=nn.BatchNorm2d, concat=True, **kwargs): - super(BaseOCModule, self).__init__() - self.stages = nn.ModuleList([ - BaseAttentionBlock(in_channels, out_channels, key_channels, value_channels, scale, norm_layer, **kwargs) - for scale in scales]) - in_channels = in_channels * 2 if concat else in_channels - self.project = nn.Sequential( - nn.Conv2d(in_channels, out_channels, 1), - norm_layer(out_channels), - nn.ReLU(True), - nn.Dropout2d(0.05) - ) - self.concat = concat - - def forward(self, x): - priors = [stage(x) for stage in self.stages] - context = priors[0] - for i in range(1, len(priors)): - context += priors[i] - if self.concat: - context = torch.cat([context, x], 1) - out = self.project(context) - return out - - -class PyramidAttentionBlock(nn.Module): - """The basic implementation for pyramid self-attention block/non-local block""" - - def __init__(self, in_channels, out_channels, key_channels, value_channels, - scale=1, norm_layer=nn.BatchNorm2d, **kwargs): - super(PyramidAttentionBlock, self).__init__() - self.scale = scale - self.value_channels = value_channels - self.key_channels = key_channels - - self.f_value = nn.Conv2d(in_channels, value_channels, 1) - self.f_key = nn.Sequential( - nn.Conv2d(in_channels, key_channels, 1), - norm_layer(key_channels), - nn.ReLU(True) - ) - self.f_query = self.f_key - self.W = nn.Conv2d(value_channels, out_channels, 1) - nn.init.constant_(self.W.weight, 0) - nn.init.constant_(self.W.bias, 0) - - def forward(self, x): - batch_size, c, w, h = x.size() - - local_x = list() - local_y = list() - step_w, step_h = w // self.scale, h // self.scale - for i in range(self.scale): - for j in range(self.scale): - start_x, start_y = step_w * i, step_h * j - end_x, end_y = min(start_x + step_w, w), min(start_y + step_h, h) - if i == (self.scale - 1): - end_x = w - if j == (self.scale - 1): - end_y = h - local_x += [start_x, end_x] - local_y += [start_y, end_y] - - value = self.f_value(x) - query = self.f_query(x) - key = self.f_key(x) - - local_list = list() - local_block_cnt = (self.scale ** 2) * 2 - for i in range(0, local_block_cnt, 2): - value_local = value[:, :, local_x[i]:local_x[i + 1], local_y[i]:local_y[i + 1]] - query_local = query[:, :, local_x[i]:local_x[i + 1], local_y[i]:local_y[i + 1]] - key_local = key[:, :, local_x[i]:local_x[i + 1], local_y[i]:local_y[i + 1]] - - w_local, h_local = value_local.size(2), value_local.size(3) - value_local = value_local.contiguous().view(batch_size, self.value_channels, -1).permute(0, 2, 1) - query_local = query_local.contiguous().view(batch_size, self.key_channels, -1).permute(0, 2, 1) - key_local = key_local.contiguous().view(batch_size, self.key_channels, -1) - - sim_map = torch.bmm(query_local, key_local) * (self.key_channels ** -.5) - sim_map = F.softmax(sim_map, dim=-1) - - context_local = torch.bmm(sim_map, value_local).permute(0, 2, 1).contiguous() - context_local = context_local.view(batch_size, self.value_channels, w_local, h_local) - local_list.append(context_local) - - context_list = list() - for i in range(0, self.scale): - row_tmp = list() - for j in range(self.scale): - row_tmp.append(local_list[j + i * self.scale]) - context_list.append(torch.cat(row_tmp, 3)) - - context = torch.cat(context_list, 2) - context = self.W(context) - - return context - - -class PyramidOCModule(nn.Module): - """Pyramid-OC""" - - def __init__(self, in_channels, out_channels, key_channels, value_channels, - scales=([1]), norm_layer=nn.BatchNorm2d, **kwargs): - super(PyramidOCModule, self).__init__() - self.stages = nn.ModuleList([ - PyramidAttentionBlock(in_channels, out_channels, key_channels, value_channels, scale, norm_layer, **kwargs) - for scale in scales]) - self.up_dr = nn.Sequential( - nn.Conv2d(in_channels, in_channels * len(scales), 1), - norm_layer(in_channels * len(scales)), - nn.ReLU(True) - ) - self.project = nn.Sequential( - nn.Conv2d(in_channels * len(scales) * 2, out_channels, 1), - norm_layer(out_channels), - nn.ReLU(True), - nn.Dropout2d(0.05) - ) - - def forward(self, x): - priors = [stage(x) for stage in self.stages] - context = [self.up_dr(x)] - for i in range(len(priors)): - context += [priors[i]] - context = torch.cat(context, 1) - out = self.project(context) - return out - - -class ASPOCModule(nn.Module): - """ASP-OC""" - - def __init__(self, in_channels, out_channels, key_channels, value_channels, - atrous_rates=(12, 24, 36), norm_layer=nn.BatchNorm2d, **kwargs): - super(ASPOCModule, self).__init__() - self.context = nn.Sequential( - nn.Conv2d(in_channels, out_channels, 3, padding=1), - norm_layer(out_channels), - nn.ReLU(True), - BaseOCModule(out_channels, out_channels, key_channels, value_channels, ([2]), norm_layer, False, **kwargs)) - - rate1, rate2, rate3 = tuple(atrous_rates) - self.b1 = nn.Sequential( - nn.Conv2d(in_channels, out_channels, 3, padding=rate1, dilation=rate1, bias=False), - norm_layer(out_channels), - nn.ReLU(True)) - self.b2 = nn.Sequential( - nn.Conv2d(in_channels, out_channels, 3, padding=rate2, dilation=rate2, bias=False), - norm_layer(out_channels), - nn.ReLU(True)) - self.b3 = nn.Sequential( - nn.Conv2d(in_channels, out_channels, 3, padding=rate3, dilation=rate3, bias=False), - norm_layer(out_channels), - nn.ReLU(True)) - self.b4 = nn.Sequential( - nn.Conv2d(in_channels, out_channels, 1, bias=False), - norm_layer(out_channels), - nn.ReLU(True)) - - self.project = nn.Sequential( - nn.Conv2d(out_channels * 5, out_channels, 1, bias=False), - norm_layer(out_channels), - nn.ReLU(True), - nn.Dropout2d(0.1) - ) - - def forward(self, x): - feat1 = self.context(x) - feat2 = self.b1(x) - feat3 = self.b2(x) - feat4 = self.b3(x) - feat5 = self.b4(x) - out = torch.cat((feat1, feat2, feat3, feat4, feat5), dim=1) - out = self.project(out) - return out - - -def get_ocnet(dataset='citys', backbone='resnet50', oc_arch='base', pretrained=False, root='~/.torch/models', - pretrained_base=True, **kwargs): - acronyms = { - 'pascal_voc': 'pascal_voc', - 'pascal_aug': 'pascal_aug', - 'ade20k': 'ade', - 'coco': 'coco', - 'citys': 'citys', - } - from ..data.dataloader import datasets - model = OCNet(datasets[dataset].NUM_CLASS, backbone=backbone, oc_arch=oc_arch, - pretrained_base=pretrained_base, **kwargs) - if pretrained: - from .model_store import get_model_file - device = torch.device(kwargs['local_rank']) - model.load_state_dict(torch.load(get_model_file('%s_ocnet_%s_%s' % ( - oc_arch, backbone, acronyms[dataset]), root=root), - map_location=device)) - return model - - -def get_base_ocnet_resnet101_citys(**kwargs): - return get_ocnet('citys', 'resnet101', 'base', **kwargs) - - -def get_pyramid_ocnet_resnet101_citys(**kwargs): - return get_ocnet('citys', 'resnet101', 'pyramid', **kwargs) - - -def get_asp_ocnet_resnet101_citys(**kwargs): - return get_ocnet('citys', 'resnet101', 'asp', **kwargs) - - -if __name__ == '__main__': - img = torch.randn(1, 3, 256, 256) - model = get_asp_ocnet_resnet101_citys() - outputs = model(img) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +""" Object Context Network for Scene Parsing""" +import torch +import torch.nn as nn +import torch.nn.functional as F + +from .segbase import SegBaseModel +from .fcn import _FCNHead + +__all__ = ['OCNet', 'get_ocnet', 'get_base_ocnet_resnet101_citys', + 'get_pyramid_ocnet_resnet101_citys', 'get_asp_ocnet_resnet101_citys'] + + +class OCNet(SegBaseModel): + r"""OCNet + + Parameters + ---------- + nclass : int + Number of categories for the training dataset. + backbone : string + Pre-trained dilated backbone network type (default:'resnet50'; 'resnet50', + 'resnet101' or 'resnet152'). + norm_layer : object + Normalization layer used in backbone network (default: :class:`nn.BatchNorm`; + for Synchronized Cross-GPU BachNormalization). + aux : bool + Auxiliary loss. + Reference: + Yuhui Yuan, Jingdong Wang. "OCNet: Object Context Network for Scene Parsing." + arXiv preprint arXiv:1809.00916 (2018). + """ + + def __init__(self, nclass, backbone='resnet101', oc_arch='base', aux=False, pretrained_base=True, **kwargs): + super(OCNet, self).__init__(nclass, aux, backbone, pretrained_base=pretrained_base, **kwargs) + self.head = _OCHead(nclass, oc_arch, **kwargs) + if self.aux: + self.auxlayer = _FCNHead(1024, nclass, **kwargs) + + self.__setattr__('exclusive', ['head', 'auxlayer'] if aux else ['head']) + + def forward(self, x): + size = x.size()[2:] + _, _, c3, c4 = self.base_forward(x) + outputs = [] + x = self.head(c4) + x = F.interpolate(x, size, mode='bilinear', align_corners=True) + outputs.append(x) + + if self.aux: + auxout = self.auxlayer(c3) + auxout = F.interpolate(auxout, size, mode='bilinear', align_corners=True) + outputs.append(auxout) + return tuple(outputs) + + +class _OCHead(nn.Module): + def __init__(self, nclass, oc_arch, norm_layer=nn.BatchNorm2d, **kwargs): + super(_OCHead, self).__init__() + if oc_arch == 'base': + self.context = nn.Sequential( + nn.Conv2d(2048, 512, 3, 1, padding=1, bias=False), + norm_layer(512), + nn.ReLU(True), + BaseOCModule(512, 512, 256, 256, scales=([1]), norm_layer=norm_layer, **kwargs)) + elif oc_arch == 'pyramid': + self.context = nn.Sequential( + nn.Conv2d(2048, 512, 3, 1, padding=1, bias=False), + norm_layer(512), + nn.ReLU(True), + PyramidOCModule(512, 512, 256, 512, scales=([1, 2, 3, 6]), norm_layer=norm_layer, **kwargs)) + elif oc_arch == 'asp': + self.context = ASPOCModule(2048, 512, 256, 512, norm_layer=norm_layer, **kwargs) + else: + raise ValueError("Unknown OC architecture!") + + self.out = nn.Conv2d(512, nclass, 1) + + def forward(self, x): + x = self.context(x) + return self.out(x) + + +class BaseAttentionBlock(nn.Module): + """The basic implementation for self-attention block/non-local block.""" + + def __init__(self, in_channels, out_channels, key_channels, value_channels, + scale=1, norm_layer=nn.BatchNorm2d, **kwargs): + super(BaseAttentionBlock, self).__init__() + self.scale = scale + self.key_channels = key_channels + self.value_channels = value_channels + if scale > 1: + self.pool = nn.MaxPool2d(scale) + + self.f_value = nn.Conv2d(in_channels, value_channels, 1) + self.f_key = nn.Sequential( + nn.Conv2d(in_channels, key_channels, 1), + norm_layer(key_channels), + nn.ReLU(True) + ) + self.f_query = self.f_key + self.W = nn.Conv2d(value_channels, out_channels, 1) + nn.init.constant_(self.W.weight, 0) + nn.init.constant_(self.W.bias, 0) + + def forward(self, x): + batch_size, c, w, h = x.size() + if self.scale > 1: + x = self.pool(x) + + value = self.f_value(x).view(batch_size, self.value_channels, -1).permute(0, 2, 1) + query = self.f_query(x).view(batch_size, self.key_channels, -1).permute(0, 2, 1) + key = self.f_key(x).view(batch_size, self.key_channels, -1) + + sim_map = torch.bmm(query, key) * (self.key_channels ** -.5) + sim_map = F.softmax(sim_map, dim=-1) + + context = torch.bmm(sim_map, value).permute(0, 2, 1).contiguous() + context = context.view(batch_size, self.value_channels, *x.size()[2:]) + context = self.W(context) + if self.scale > 1: + context = F.interpolate(context, size=(w, h), mode='bilinear', align_corners=True) + + return context + + +class BaseOCModule(nn.Module): + """Base-OC""" + + def __init__(self, in_channels, out_channels, key_channels, value_channels, + scales=([1]), norm_layer=nn.BatchNorm2d, concat=True, **kwargs): + super(BaseOCModule, self).__init__() + self.stages = nn.ModuleList([ + BaseAttentionBlock(in_channels, out_channels, key_channels, value_channels, scale, norm_layer, **kwargs) + for scale in scales]) + in_channels = in_channels * 2 if concat else in_channels + self.project = nn.Sequential( + nn.Conv2d(in_channels, out_channels, 1), + norm_layer(out_channels), + nn.ReLU(True), + nn.Dropout2d(0.05) + ) + self.concat = concat + + def forward(self, x): + priors = [stage(x) for stage in self.stages] + context = priors[0] + for i in range(1, len(priors)): + context += priors[i] + if self.concat: + context = torch.cat([context, x], 1) + out = self.project(context) + return out + + +class PyramidAttentionBlock(nn.Module): + """The basic implementation for pyramid self-attention block/non-local block""" + + def __init__(self, in_channels, out_channels, key_channels, value_channels, + scale=1, norm_layer=nn.BatchNorm2d, **kwargs): + super(PyramidAttentionBlock, self).__init__() + self.scale = scale + self.value_channels = value_channels + self.key_channels = key_channels + + self.f_value = nn.Conv2d(in_channels, value_channels, 1) + self.f_key = nn.Sequential( + nn.Conv2d(in_channels, key_channels, 1), + norm_layer(key_channels), + nn.ReLU(True) + ) + self.f_query = self.f_key + self.W = nn.Conv2d(value_channels, out_channels, 1) + nn.init.constant_(self.W.weight, 0) + nn.init.constant_(self.W.bias, 0) + + def forward(self, x): + batch_size, c, w, h = x.size() + + local_x = list() + local_y = list() + step_w, step_h = w // self.scale, h // self.scale + for i in range(self.scale): + for j in range(self.scale): + start_x, start_y = step_w * i, step_h * j + end_x, end_y = min(start_x + step_w, w), min(start_y + step_h, h) + if i == (self.scale - 1): + end_x = w + if j == (self.scale - 1): + end_y = h + local_x += [start_x, end_x] + local_y += [start_y, end_y] + + value = self.f_value(x) + query = self.f_query(x) + key = self.f_key(x) + + local_list = list() + local_block_cnt = (self.scale ** 2) * 2 + for i in range(0, local_block_cnt, 2): + value_local = value[:, :, local_x[i]:local_x[i + 1], local_y[i]:local_y[i + 1]] + query_local = query[:, :, local_x[i]:local_x[i + 1], local_y[i]:local_y[i + 1]] + key_local = key[:, :, local_x[i]:local_x[i + 1], local_y[i]:local_y[i + 1]] + + w_local, h_local = value_local.size(2), value_local.size(3) + value_local = value_local.contiguous().view(batch_size, self.value_channels, -1).permute(0, 2, 1) + query_local = query_local.contiguous().view(batch_size, self.key_channels, -1).permute(0, 2, 1) + key_local = key_local.contiguous().view(batch_size, self.key_channels, -1) + + sim_map = torch.bmm(query_local, key_local) * (self.key_channels ** -.5) + sim_map = F.softmax(sim_map, dim=-1) + + context_local = torch.bmm(sim_map, value_local).permute(0, 2, 1).contiguous() + context_local = context_local.view(batch_size, self.value_channels, w_local, h_local) + local_list.append(context_local) + + context_list = list() + for i in range(0, self.scale): + row_tmp = list() + for j in range(self.scale): + row_tmp.append(local_list[j + i * self.scale]) + context_list.append(torch.cat(row_tmp, 3)) + + context = torch.cat(context_list, 2) + context = self.W(context) + + return context + + +class PyramidOCModule(nn.Module): + """Pyramid-OC""" + + def __init__(self, in_channels, out_channels, key_channels, value_channels, + scales=([1]), norm_layer=nn.BatchNorm2d, **kwargs): + super(PyramidOCModule, self).__init__() + self.stages = nn.ModuleList([ + PyramidAttentionBlock(in_channels, out_channels, key_channels, value_channels, scale, norm_layer, **kwargs) + for scale in scales]) + self.up_dr = nn.Sequential( + nn.Conv2d(in_channels, in_channels * len(scales), 1), + norm_layer(in_channels * len(scales)), + nn.ReLU(True) + ) + self.project = nn.Sequential( + nn.Conv2d(in_channels * len(scales) * 2, out_channels, 1), + norm_layer(out_channels), + nn.ReLU(True), + nn.Dropout2d(0.05) + ) + + def forward(self, x): + priors = [stage(x) for stage in self.stages] + context = [self.up_dr(x)] + for i in range(len(priors)): + context += [priors[i]] + context = torch.cat(context, 1) + out = self.project(context) + return out + + +class ASPOCModule(nn.Module): + """ASP-OC""" + + def __init__(self, in_channels, out_channels, key_channels, value_channels, + atrous_rates=(12, 24, 36), norm_layer=nn.BatchNorm2d, **kwargs): + super(ASPOCModule, self).__init__() + self.context = nn.Sequential( + nn.Conv2d(in_channels, out_channels, 3, padding=1), + norm_layer(out_channels), + nn.ReLU(True), + BaseOCModule(out_channels, out_channels, key_channels, value_channels, ([2]), norm_layer, False, **kwargs)) + + rate1, rate2, rate3 = tuple(atrous_rates) + self.b1 = nn.Sequential( + nn.Conv2d(in_channels, out_channels, 3, padding=rate1, dilation=rate1, bias=False), + norm_layer(out_channels), + nn.ReLU(True)) + self.b2 = nn.Sequential( + nn.Conv2d(in_channels, out_channels, 3, padding=rate2, dilation=rate2, bias=False), + norm_layer(out_channels), + nn.ReLU(True)) + self.b3 = nn.Sequential( + nn.Conv2d(in_channels, out_channels, 3, padding=rate3, dilation=rate3, bias=False), + norm_layer(out_channels), + nn.ReLU(True)) + self.b4 = nn.Sequential( + nn.Conv2d(in_channels, out_channels, 1, bias=False), + norm_layer(out_channels), + nn.ReLU(True)) + + self.project = nn.Sequential( + nn.Conv2d(out_channels * 5, out_channels, 1, bias=False), + norm_layer(out_channels), + nn.ReLU(True), + nn.Dropout2d(0.1) + ) + + def forward(self, x): + feat1 = self.context(x) + feat2 = self.b1(x) + feat3 = self.b2(x) + feat4 = self.b3(x) + feat5 = self.b4(x) + out = torch.cat((feat1, feat2, feat3, feat4, feat5), dim=1) + out = self.project(out) + return out + + +def get_ocnet(dataset='citys', backbone='resnet50', oc_arch='base', pretrained=False, root='~/.torch/models', + pretrained_base=True, **kwargs): + acronyms = { + 'pascal_voc': 'pascal_voc', + 'pascal_aug': 'pascal_aug', + 'ade20k': 'ade', + 'coco': 'coco', + 'citys': 'citys', + } + from ..data.dataloader import datasets + model = OCNet(datasets[dataset].NUM_CLASS, backbone=backbone, oc_arch=oc_arch, + pretrained_base=pretrained_base, **kwargs) + if pretrained: + from .model_store import get_model_file + device = torch.device(kwargs['local_rank']) + model.load_state_dict(torch.load(get_model_file('%s_ocnet_%s_%s' % ( + oc_arch, backbone, acronyms[dataset]), root=root), + map_location=device)) + return model + + +def get_base_ocnet_resnet101_citys(**kwargs): + return get_ocnet('citys', 'resnet101', 'base', **kwargs) + + +def get_pyramid_ocnet_resnet101_citys(**kwargs): + return get_ocnet('citys', 'resnet101', 'pyramid', **kwargs) + + +def get_asp_ocnet_resnet101_citys(**kwargs): + return get_ocnet('citys', 'resnet101', 'asp', **kwargs) + + +if __name__ == '__main__': + img = torch.randn(1, 3, 256, 256) + model = get_asp_ocnet_resnet101_citys() + outputs = model(img) diff --git a/PyTorch/contrib/cv/semantic_segmentation/ENet/scripts/eval.py b/PyTorch/contrib/cv/semantic_segmentation/ENet/scripts/eval.py index 0633c0615d..0bbb7efdd2 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/ENet/scripts/eval.py +++ b/PyTorch/contrib/cv/semantic_segmentation/ENet/scripts/eval.py @@ -1,143 +1,143 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 print_function - -import os -import sys - -cur_path = os.path.abspath(os.path.dirname(__file__)) -root_path = os.path.split(cur_path)[0] -sys.path.append(root_path) - -import torch -import torch.nn as nn -import torch.utils.data as data -import torch.backends.cudnn as cudnn - -from torchvision import transforms -from core.data.dataloader import get_segmentation_dataset -from core.models.model_zoo import get_segmentation_model -from core.utils.score import SegmentationMetric -from core.utils.visualize import get_color_pallete -from core.utils.logger import setup_logger -from core.utils.distributed import synchronize, get_rank, make_data_sampler, make_batch_data_sampler - -from train import parse_args - - -class Evaluator(object): - def __init__(self, args): - self.args = args - loc = 'npu:{}'.format(self.args.local_rank) - #self.device = torch.device(args.device) - if args.device == 'npu': - self.device = torch.npu.set_device(loc) - else: - self.device = torch.device(args.device) - - # image transform - input_transform = transforms.Compose([ - transforms.ToTensor(), - transforms.Normalize([.485, .456, .406], [.229, .224, .225]), - ]) - - # dataset and dataloader - val_dataset = get_segmentation_dataset(args.dataset, split='val', mode='testval', transform=input_transform) - val_sampler = make_data_sampler(val_dataset, False, args.distributed) - val_batch_sampler = make_batch_data_sampler(val_sampler, images_per_batch=1) - self.val_loader = data.DataLoader(dataset=val_dataset, - batch_sampler=val_batch_sampler, - num_workers=args.workers, - pin_memory=True) - - # create network - BatchNorm2d = nn.BatchNorm2d#nn.SyncBatchNorm if args.distributed else nn.BatchNorm2d - self.model = get_segmentation_model(model=args.model, dataset=args.dataset, backbone=args.backbone, - aux=args.aux, pretrained=True, pretrained_base=False, - local_rank=args.local_rank, - norm_layer=BatchNorm2d).to(loc) - if args.distributed: - self.model = nn.parallel.DistributedDataParallel(self.model, - device_ids=[args.local_rank], output_device=args.local_rank) - self.model.to(loc) - - self.metric = SegmentationMetric(val_dataset.num_class) - - def eval(self): - loc = 'npu:{}'.format(self.args.local_rank) - self.metric.reset() - self.model.eval() - if self.args.distributed: - model = self.model.module - else: - model = self.model - logger.info("Start validation, Total sample: {:d}".format(len(self.val_loader))) - for i, (image, target, filename) in enumerate(self.val_loader): - image = image.to(loc) - target = target.to(loc) - target = target.to(torch.int32) - - with torch.no_grad(): - outputs = model(image) - self.metric.update(outputs[0], target) - pixAcc, mIoU = self.metric.get() - logger.info("Sample: {:d}, validation pixAcc: {:.3f}, mIoU: {:.3f}".format( - i + 1, pixAcc * 100, mIoU * 100)) - - if self.args.save_pred: - pred = torch.argmax(outputs[0], 1) - pred = pred.cpu().data.numpy() - - predict = pred.squeeze(0) - mask = get_color_pallete(predict, self.args.dataset) - mask.save(os.path.join(outdir, os.path.splitext(filename[0])[0] + '.png')) - synchronize() - - -if __name__ == '__main__': - args = parse_args() - num_gpus = int(os.environ["WORLD_SIZE"]) if "WORLD_SIZE" in os.environ else 1 - args.distributed = num_gpus > 1 - if args.device == "npu": - args.device = "npu" - elif not args.no_cuda and torch.cuda.is_available(): - cudnn.benchmark = True - args.device = "cuda" - else: - args.distributed = False - args.device = "cpu" - if args.distributed: - torch.npu.set_device(args.local_rank) - torch.distributed.init_process_group(backend=args.dist_backend, init_method="env://") - synchronize() - - # TODO: optim code - args.save_pred = True - if args.save_pred: - outdir = '../runs/pred_pic/{}_{}_{}'.format(args.model, args.backbone, args.dataset) - if args.model == "enet": - outdir = '../runs/pred_pic/{}_{}'.format(args.model, args.dataset) - if not os.path.exists(outdir): - os.makedirs(outdir) - - log_filename = '{}_{}_{}_log.txt'.format(args.model, args.backbone, args.dataset) - if args.model == "enet": - log_filename = '{}_{}_log.txt'.format(args.model, args.dataset) - logger = setup_logger("semantic_segmentation", args.log_dir, get_rank(), - filename=log_filename, mode='a+') - - evaluator = Evaluator(args) - evaluator.eval() - torch.npu.empty_cache() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 print_function + +import os +import sys + +cur_path = os.path.abspath(os.path.dirname(__file__)) +root_path = os.path.split(cur_path)[0] +sys.path.append(root_path) + +import torch +import torch.nn as nn +import torch.utils.data as data +import torch.backends.cudnn as cudnn + +from torchvision import transforms +from core.data.dataloader import get_segmentation_dataset +from core.models.model_zoo import get_segmentation_model +from core.utils.score import SegmentationMetric +from core.utils.visualize import get_color_pallete +from core.utils.logger import setup_logger +from core.utils.distributed import synchronize, get_rank, make_data_sampler, make_batch_data_sampler + +from train import parse_args + + +class Evaluator(object): + def __init__(self, args): + self.args = args + loc = 'npu:{}'.format(self.args.local_rank) + #self.device = torch.device(args.device) + if args.device == 'npu': + self.device = torch.npu.set_device(loc) + else: + self.device = torch.device(args.device) + + # image transform + input_transform = transforms.Compose([ + transforms.ToTensor(), + transforms.Normalize([.485, .456, .406], [.229, .224, .225]), + ]) + + # dataset and dataloader + val_dataset = get_segmentation_dataset(args.dataset, split='val', mode='testval', transform=input_transform) + val_sampler = make_data_sampler(val_dataset, False, args.distributed) + val_batch_sampler = make_batch_data_sampler(val_sampler, images_per_batch=1) + self.val_loader = data.DataLoader(dataset=val_dataset, + batch_sampler=val_batch_sampler, + num_workers=args.workers, + pin_memory=True) + + # create network + BatchNorm2d = nn.BatchNorm2d#nn.SyncBatchNorm if args.distributed else nn.BatchNorm2d + self.model = get_segmentation_model(model=args.model, dataset=args.dataset, backbone=args.backbone, + aux=args.aux, pretrained=True, pretrained_base=False, + local_rank=args.local_rank, + norm_layer=BatchNorm2d).to(loc) + if args.distributed: + self.model = nn.parallel.DistributedDataParallel(self.model, + device_ids=[args.local_rank], output_device=args.local_rank) + self.model.to(loc) + + self.metric = SegmentationMetric(val_dataset.num_class) + + def eval(self): + loc = 'npu:{}'.format(self.args.local_rank) + self.metric.reset() + self.model.eval() + if self.args.distributed: + model = self.model.module + else: + model = self.model + logger.info("Start validation, Total sample: {:d}".format(len(self.val_loader))) + for i, (image, target, filename) in enumerate(self.val_loader): + image = image.to(loc) + target = target.to(loc) + target = target.to(torch.int32) + + with torch.no_grad(): + outputs = model(image) + self.metric.update(outputs[0], target) + pixAcc, mIoU = self.metric.get() + logger.info("Sample: {:d}, validation pixAcc: {:.3f}, mIoU: {:.3f}".format( + i + 1, pixAcc * 100, mIoU * 100)) + + if self.args.save_pred: + pred = torch.argmax(outputs[0], 1) + pred = pred.cpu().data.numpy() + + predict = pred.squeeze(0) + mask = get_color_pallete(predict, self.args.dataset) + mask.save(os.path.join(outdir, os.path.splitext(filename[0])[0] + '.png')) + synchronize() + + +if __name__ == '__main__': + args = parse_args() + num_gpus = int(os.environ["WORLD_SIZE"]) if "WORLD_SIZE" in os.environ else 1 + args.distributed = num_gpus > 1 + if args.device == "npu": + args.device = "npu" + elif not args.no_cuda and torch.cuda.is_available(): + cudnn.benchmark = True + args.device = "cuda" + else: + args.distributed = False + args.device = "cpu" + if args.distributed: + torch.npu.set_device(args.local_rank) + torch.distributed.init_process_group(backend=args.dist_backend, init_method="env://") + synchronize() + + # TODO: optim code + args.save_pred = True + if args.save_pred: + outdir = '../runs/pred_pic/{}_{}_{}'.format(args.model, args.backbone, args.dataset) + if args.model == "enet": + outdir = '../runs/pred_pic/{}_{}'.format(args.model, args.dataset) + if not os.path.exists(outdir): + os.makedirs(outdir) + + log_filename = '{}_{}_{}_log.txt'.format(args.model, args.backbone, args.dataset) + if args.model == "enet": + log_filename = '{}_{}_log.txt'.format(args.model, args.dataset) + logger = setup_logger("semantic_segmentation", args.log_dir, get_rank(), + filename=log_filename, mode='a+') + + evaluator = Evaluator(args) + evaluator.eval() + torch.npu.empty_cache() diff --git a/PyTorch/contrib/cv/semantic_segmentation/ENet/scripts/proc_node_module.py b/PyTorch/contrib/cv/semantic_segmentation/ENet/scripts/proc_node_module.py index c139998dc9..31cf2b16c7 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/ENet/scripts/proc_node_module.py +++ b/PyTorch/contrib/cv/semantic_segmentation/ENet/scripts/proc_node_module.py @@ -1,40 +1,40 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -from collections import OrderedDict -import os - -def proc_nodes_module(checkpoint): - new_state_dict = OrderedDict() - for k, v in checkpoint.items(): - if "module." in k: - name = k.replace("module.", "") - else: - name = k - new_state_dict[name] = v - return new_state_dict - -root ='~/.torch/models' -root = os.path.expanduser(root) -file_path = os.path.join(root, 'enet_citys.pth') -checkpoint = torch.load(file_path, map_location='cpu') -checkpoint = proc_nodes_module(checkpoint) - - -#directory = os.path.expanduser(args.save_dir) -directory = os.path.expanduser(root) -filename = 'enet_citys.pth' -filename = os.path.join(directory, filename) -torch.save(checkpoint, filename) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +from collections import OrderedDict +import os + +def proc_nodes_module(checkpoint): + new_state_dict = OrderedDict() + for k, v in checkpoint.items(): + if "module." in k: + name = k.replace("module.", "") + else: + name = k + new_state_dict[name] = v + return new_state_dict + +root ='~/.torch/models' +root = os.path.expanduser(root) +file_path = os.path.join(root, 'enet_citys.pth') +checkpoint = torch.load(file_path, map_location='cpu') +checkpoint = proc_nodes_module(checkpoint) + + +#directory = os.path.expanduser(args.save_dir) +directory = os.path.expanduser(root) +filename = 'enet_citys.pth' +filename = os.path.join(directory, filename) +torch.save(checkpoint, filename) diff --git a/PyTorch/contrib/cv/semantic_segmentation/ENet/scripts/train.py b/PyTorch/contrib/cv/semantic_segmentation/ENet/scripts/train.py index e4e27aa58c..137742ca70 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/ENet/scripts/train.py +++ b/PyTorch/contrib/cv/semantic_segmentation/ENet/scripts/train.py @@ -1,449 +1,449 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. - -# -*- coding: utf-8 -*- - -import argparse -import time -import datetime -import os -import shutil -import sys - -cur_path = os.path.abspath(os.path.dirname(__file__)) -root_path = os.path.split(cur_path)[0] -sys.path.append(root_path) - -CALCULATE_DEVICE = "npu:0" - -import torch -import torch.nn as nn -import torch.utils.data as data -import torch.backends.cudnn as cudnn - -import torch.npu - -from torchvision import transforms -from core.data.dataloader import get_segmentation_dataset -from core.models.model_zoo import get_segmentation_model -from core.utils.loss import get_segmentation_loss -from core.utils.distributed import * -from core.utils.logger import setup_logger -from core.utils.lr_scheduler import WarmupPolyLR -from core.utils.score import SegmentationMetric -from apex import amp - - -def parse_args(): - parser = argparse.ArgumentParser(description='Semantic Segmentation Training With Pytorch') - # model and dataset - parser.add_argument('--model', type=str, default='fcn', - choices=['fcn32s', 'fcn16s', 'fcn8s', 'fcn', 'psp', 'deeplabv3', - 'deeplabv3_plus', 'danet', 'denseaspp', 'bisenet', 'encnet', - 'dunet', 'icnet', 'enet', 'ocnet', 'psanet', 'cgnet', 'espnet', - 'lednet', 'dfanet'], - help='model name (default: fcn32s)') - parser.add_argument('--backbone', type=str, default='resnet50', - choices=['vgg16', 'resnet18', 'resnet50', 'resnet101', 'resnet152', - 'densenet121', 'densenet161', 'densenet169', 'densenet201'], - help='backbone name (default: vgg16)') - parser.add_argument('--dataset', type=str, default='pascal_voc', - choices=['pascal_voc', 'pascal_aug', 'ade20k', 'citys', 'sbu'], - help='dataset name (default: pascal_voc)') - parser.add_argument('--base-size', type=int, default=520, - help='base image size') - parser.add_argument('--crop-size', type=int, default=480, - help='crop image size') - parser.add_argument('--workers', '-j', type=int, default=4, - metavar='N', help='dataloader threads') - # training hyper params - parser.add_argument('--jpu', action='store_true', default=False, - help='JPU') - parser.add_argument('--use-ohem', type=bool, default=False, - help='OHEM Loss for cityscapes dataset') - parser.add_argument('--aux', action='store_true', default=False, - help='Auxiliary loss') - parser.add_argument('--aux-weight', type=float, default=0.4, - help='auxiliary loss weight') - parser.add_argument('--batch-size', type=int, default=4, metavar='N', - help='input batch size for training (default: 8)') - parser.add_argument('--start_epoch', type=int, default=0, - metavar='N', help='start epochs (default:0)') - parser.add_argument('--epochs', type=int, default=50, metavar='N', - help='number of epochs to train (default: 50)') - parser.add_argument('--lr', type=float, default=1e-4, metavar='LR', - help='learning rate (default: 1e-4)') - parser.add_argument('--momentum', type=float, default=0.9, metavar='M', - help='momentum (default: 0.9)') - parser.add_argument('--weight-decay', type=float, default=1e-4, metavar='M', - help='w-decay (default: 5e-4)') - parser.add_argument('--warmup-iters', type=int, default=0, - help='warmup iters') - parser.add_argument('--warmup-factor', type=float, default=1.0 / 3, - help='lr = warmup_factor * lr') - parser.add_argument('--warmup-method', type=str, default='linear', - help='method of warmup') - # cuda setting - parser.add_argument('--no-cuda', action='store_true', default=False, - help='disables CUDA training') - parser.add_argument('--local_rank', type=int, default=0) - # checkpoint and log - parser.add_argument('--resume', type=str, default=None, - help='put the path to resuming file if needed') - parser.add_argument('--save-dir', default='~/.torch/models', - help='Directory for saving checkpoint models') - parser.add_argument('--save-epoch', type=int, default=10, - help='save model every checkpoint-epoch') - parser.add_argument('--log-dir', default='../runs/logs/', - help='Directory for saving checkpoint models') - parser.add_argument('--log-iter', type=int, default=10, - help='print log every log-iter') - # evaluation only - parser.add_argument('--val-epoch', type=int, default=1, - help='run validation every val-epoch') - parser.add_argument('--skip-val', action='store_true', default=False, - help='skip validation during training') - # apex - parser.add_argument('--amp', default=False, action='store_true', - help='use amp to train the model') - parser.add_argument('--loss-scale', default=128.0, type=float, - help='loss scale using in amp, default -1 means dynamic') - parser.add_argument('--opt-level', default='O2', type=str, - help='loss scale using in amp, default -1 means dynamic') - - # npu setting - parser.add_argument('--device', default='npu', type=str, - help='npu or gpu') - parser.add_argument('--dist-backend', default='hccl', type=str, - help='distributed backend') - - args = parser.parse_args() - - # default settings for epochs, batch_size and lr - if args.epochs is None: - epoches = { - 'coco': 30, - 'pascal_aug': 80, - 'pascal_voc': 50, - 'pcontext': 80, - 'ade20k': 160, - 'citys': 120, - 'sbu': 160, - } - args.epochs = epoches[args.dataset.lower()] - if args.lr is None: - lrs = { - 'coco': 0.004, - 'pascal_aug': 0.001, - 'pascal_voc': 0.0001, - 'pcontext': 0.001, - 'ade20k': 0.01, - 'citys': 0.01, - 'sbu': 0.001, - } - args.lr = lrs[args.dataset.lower()] / 8 * args.batch_size - return args - - -class Trainer(object): - def __init__(self, args): - self.args = args - # self.device = torch.device(args.device) - - loc = 'npu:{}'.format(args.local_rank) - if args.device == "npu": - self.device = torch.npu.set_device(loc) - else: - self.device = torch.device(args.device) - - # image transform - input_transform = transforms.Compose([ - transforms.ToTensor(), - transforms.Normalize([.485, .456, .406], [.229, .224, .225]), - ]) - # dataset and dataloader - data_kwargs = {'transform': input_transform, 'base_size': args.base_size, 'crop_size': args.crop_size} - train_dataset = get_segmentation_dataset(args.dataset, split='train', mode='train', **data_kwargs) - val_dataset = get_segmentation_dataset(args.dataset, split='val', mode='val', **data_kwargs) - args.iters_per_epoch = len(train_dataset) // (args.num_gpus * args.batch_size) - args.max_iters = args.epochs * args.iters_per_epoch - - train_sampler = make_data_sampler(train_dataset, shuffle=True, distributed=args.distributed) - train_batch_sampler = make_batch_data_sampler(train_sampler, args.batch_size, args.max_iters) - val_sampler = make_data_sampler(val_dataset, False, args.distributed) - val_batch_sampler = make_batch_data_sampler(val_sampler, args.batch_size) - - self.train_loader = data.DataLoader(dataset=train_dataset, - batch_sampler=train_batch_sampler, - num_workers=args.workers, - pin_memory=True) - self.val_loader = data.DataLoader(dataset=val_dataset, - batch_sampler=val_batch_sampler, - num_workers=args.workers, - pin_memory=True) - - # create network - BatchNorm2d = nn.BatchNorm2d#nn.SyncBatchNorm if args.distributed else nn.BatchNorm2d - self.model = get_segmentation_model(model=args.model, dataset=args.dataset, backbone=args.backbone, - aux=args.aux, jpu=args.jpu, norm_layer=BatchNorm2d).to(loc) - - # resume checkpoint if needed - if args.resume: - if os.path.isfile(args.resume): - name, ext = os.path.splitext(args.resume) - assert ext == '.pkl' or '.pth', 'Sorry only .pth and .pkl files supported.' - print('Resuming training, loading {}...'.format(args.resume)) - self.model.load_state_dict(torch.load(args.resume, map_location=lambda storage, loc: storage)) - - # create criterion - self.criterion = get_segmentation_loss(args.model, use_ohem=args.use_ohem, aux=args.aux, - aux_weight=args.aux_weight, ignore_index=-1).to(loc) # (args.device) - - # optimizer, for model just includes pretrained, head and auxlayer - params_list = list() - if hasattr(self.model, 'pretrained'): - params_list.append({'params': self.model.pretrained.parameters(), 'lr': args.lr}) - if hasattr(self.model, 'exclusive'): - for module in self.model.exclusive: - params_list.append({'params': getattr(self.model, module).parameters(), 'lr': args.lr * 10}) - self.optimizer = torch.optim.SGD(params_list, - lr=args.lr, - momentum=args.momentum, - weight_decay=args.weight_decay) - - if args.amp: - self.model, self.optimizer = amp.initialize(self.model, self.optimizer, opt_level=args.opt_level, - loss_scale=args.loss_scale) - - # lr scheduling - self.lr_scheduler = WarmupPolyLR(self.optimizer, - max_iters=args.max_iters, - power=0.9, - warmup_factor=args.warmup_factor, - warmup_iters=args.warmup_iters, - warmup_method=args.warmup_method) - - if args.distributed: - self.model = nn.parallel.DistributedDataParallel(self.model, device_ids=[args.local_rank], - output_device=args.local_rank, find_unused_parameters=True, broadcast_buffers=False) - - # evaluation metrics - self.metric = SegmentationMetric(train_dataset.num_class) - - self.best_pred = 0.0 - - def train(self): - batch_time = AverageMeter('Time', ':6.3f', start_count_index=5) - - loc = 'npu:{}'.format(self.args.local_rank) - - save_to_disk = get_rank() == 0 - epochs, max_iters = self.args.epochs, self.args.max_iters - log_per_iters, val_per_iters = self.args.log_iter, self.args.val_epoch * self.args.iters_per_epoch - save_per_iters = self.args.save_epoch * self.args.iters_per_epoch - start_time = time.time() - logger.info('Start training, Total Epochs: {:d} = Total Iterations {:d}'.format(epochs, max_iters)) - - end = time.time() - - self.model.train() - for iteration, (images, targets, _) in enumerate(self.train_loader): - iteration = iteration + 1 - self.lr_scheduler.step() - - # if 'npu' in CALCULATE_DEVICE: - targets = targets.to(torch.int32) - images = images.to(loc) - targets = targets.to(loc) - - # with torch.autograd.profiler.profile(use_npu=True) as prof: - outputs = self.model(images) - - loss_dict = self.criterion(outputs, targets) - - losses = sum(loss for loss in loss_dict.values()) - - # reduce losses over all GPUs for logging purposes - loss_dict_reduced = reduce_loss_dict(loss_dict) - losses_reduced = sum(loss for loss in loss_dict_reduced.values()) - - self.optimizer.zero_grad() - - # losses.backward() - if self.args.amp: - with amp.scale_loss(losses, self.optimizer) as scaled_loss: - scaled_loss.backward() - else: - losses.backward() - - self.optimizer.step() - - # print(prof.key_averages().table(sort_by="self_cpu_time_total")) - # prof.export_chrome_trace("output.prof") # "output.prof"为输出文件地址 - - eta_seconds = ((time.time() - start_time) / iteration) * (max_iters - iteration) - eta_string = str(datetime.timedelta(seconds=int(eta_seconds))) - - if iteration % log_per_iters == 0 and save_to_disk: - logger.info( - "Iters: {:d}/{:d} || Lr: {:.6f} || Loss: {:.4f} || Cost Time: {} || Estimated Time: {}".format( - iteration, max_iters, self.optimizer.param_groups[0]['lr'], losses_reduced.item(), - str(datetime.timedelta(seconds=int(time.time() - start_time))), eta_string)) - - if iteration % self.args.iters_per_epoch == 0 and batch_time.avg > 0: - logger.info("Epoch: {:d}/{:d} || FPS img/s: {:.3f}".format( - iteration // self.args.iters_per_epoch, epochs, - args.num_gpus * self.args.batch_size / batch_time.avg)) - - if iteration % save_per_iters == 0 and save_to_disk and self.args.local_rank == 0: - save_checkpoint(self.model, self.args, is_best=False) - - batch_time.update(time.time() - end) - - if not self.args.skip_val and iteration % val_per_iters == 0: - self.validation() - self.model.train() - - end = time.time() - - if self.args.local_rank == 0: - save_checkpoint(self.model, self.args, is_best=False) - total_training_time = time.time() - start_time - total_training_str = str(datetime.timedelta(seconds=total_training_time)) - logger.info( - "Total training time: {} ({:.4f}s / it)".format( - total_training_str, total_training_time / max_iters)) - - def validation(self): - loc = 'npu:{}'.format(self.args.local_rank) - - # total_inter, total_union, total_correct, total_label = 0, 0, 0, 0 - is_best = False - self.metric.reset() - #if self.args.distributed: - #model = self.model.module - #else: - model = self.model - torch.npu.empty_cache() # TODO check if it helps - model.eval() - for i, (image, target, filename) in enumerate(self.val_loader): - # if 'npu' in CALCULATE_DEVICE: - # target = target.to(torch.int32) - target = target.to(torch.int32) - image = image.to(loc) - target = target.to(loc) - with torch.no_grad(): - outputs = model(image) - self.metric.update(outputs[0], target) - pixAcc, mIoU = self.metric.get() - logger.info("Sample: {:d}, Validation pixAcc: {:.3f}, mIoU: {:.3f}".format(i + 1, pixAcc, mIoU)) - - new_pred = (pixAcc + mIoU) / 2 - if new_pred > self.best_pred: - is_best = True - self.best_pred = new_pred - if self.args.local_rank == 0: - save_checkpoint(self.model, self.args, is_best) - synchronize() - - -class AverageMeter(object): - """Computes and stores the average and current value""" - - def __init__(self, name, fmt=':f', start_count_index=10): - self.name = name - self.fmt = fmt - self.reset() - self.start_count_index = start_count_index - - def reset(self): - self.val = 0 - self.avg = 0 - self.sum = 0 - self.count = 0 - - def update(self, val, n=1): - if self.count == 0: - self.N = n - - self.val = val - self.count += n - if self.count > (self.start_count_index * self.N): - self.sum += val * n - self.avg = self.sum / (self.count - self.start_count_index * self.N) - - def __str__(self): - fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' - return fmtstr.format(**self.__dict__) - -def save_checkpoint(model, args, is_best=False): - """Save Checkpoint""" - directory = os.path.expanduser(args.save_dir) - if not os.path.exists(directory): - os.makedirs(directory) - - filename = '{}_{}_{}.pth'.format(args.model, args.backbone, args.dataset) - if args.model == "enet": - filename = '{}_{}.pth'.format(args.model, args.dataset) - filename = os.path.join(directory, filename) - - #if args.distributed: - #model = model.module - torch.save(model.state_dict(), filename) - if is_best: - best_filename = '{}_{}_{}_best_model.pth'.format(args.model, args.backbone, args.dataset) - if args.model == "enet": - best_filename = '{}_{}_best_model.pth'.format(args.model, args.dataset) - best_filename = os.path.join(directory, best_filename) - shutil.copyfile(filename, best_filename) - - -if __name__ == '__main__': - args = parse_args() - - os.environ['MASTER_ADDR'] = '127.0.0.1' # 可以使用当前真实ip或者'127.0.0.1' - os.environ['MASTER_PORT'] = '29688' # 随意一个可使用的port即可 - - # reference maskrcnn-benchmark - num_gpus = int(os.environ["WORLD_SIZE"]) if "WORLD_SIZE" in os.environ else 1 - args.num_gpus = num_gpus - #args.num_gpus = 1 - args.distributed = num_gpus > 1 - - if args.device == "npu": - args.device = "npu" - elif not args.no_cuda and torch.cuda.is_available(): - cudnn.benchmark = True - args.device = "cuda" - else: - args.distributed = False - args.device = "cpu" - if args.distributed: - loc = 'npu:{}'.format(args.local_rank) - torch.npu.set_device(loc) - torch.distributed.init_process_group(backend=args.dist_backend, init_method="env://") - synchronize() - args.lr = args.lr * num_gpus - - logger_filename = '{}_{}_{}_log.txt'.format(args.model, args.backbone, args.dataset) - if args.model == "enet": - logger_filename = '{}_{}_log.txt'.format(args.model, args.dataset) - logger = setup_logger("semantic_segmentation", args.log_dir, get_rank(), filename=logger_filename) - logger.info("Using {} GPUs".format(num_gpus)) - logger.info(args) - - trainer = Trainer(args) - trainer.train() - torch.npu.empty_cache() - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +# -*- coding: utf-8 -*- + +import argparse +import time +import datetime +import os +import shutil +import sys + +cur_path = os.path.abspath(os.path.dirname(__file__)) +root_path = os.path.split(cur_path)[0] +sys.path.append(root_path) + +CALCULATE_DEVICE = "npu:0" + +import torch +import torch.nn as nn +import torch.utils.data as data +import torch.backends.cudnn as cudnn + +import torch.npu + +from torchvision import transforms +from core.data.dataloader import get_segmentation_dataset +from core.models.model_zoo import get_segmentation_model +from core.utils.loss import get_segmentation_loss +from core.utils.distributed import * +from core.utils.logger import setup_logger +from core.utils.lr_scheduler import WarmupPolyLR +from core.utils.score import SegmentationMetric +from apex import amp + + +def parse_args(): + parser = argparse.ArgumentParser(description='Semantic Segmentation Training With Pytorch') + # model and dataset + parser.add_argument('--model', type=str, default='fcn', + choices=['fcn32s', 'fcn16s', 'fcn8s', 'fcn', 'psp', 'deeplabv3', + 'deeplabv3_plus', 'danet', 'denseaspp', 'bisenet', 'encnet', + 'dunet', 'icnet', 'enet', 'ocnet', 'psanet', 'cgnet', 'espnet', + 'lednet', 'dfanet'], + help='model name (default: fcn32s)') + parser.add_argument('--backbone', type=str, default='resnet50', + choices=['vgg16', 'resnet18', 'resnet50', 'resnet101', 'resnet152', + 'densenet121', 'densenet161', 'densenet169', 'densenet201'], + help='backbone name (default: vgg16)') + parser.add_argument('--dataset', type=str, default='pascal_voc', + choices=['pascal_voc', 'pascal_aug', 'ade20k', 'citys', 'sbu'], + help='dataset name (default: pascal_voc)') + parser.add_argument('--base-size', type=int, default=520, + help='base image size') + parser.add_argument('--crop-size', type=int, default=480, + help='crop image size') + parser.add_argument('--workers', '-j', type=int, default=4, + metavar='N', help='dataloader threads') + # training hyper params + parser.add_argument('--jpu', action='store_true', default=False, + help='JPU') + parser.add_argument('--use-ohem', type=bool, default=False, + help='OHEM Loss for cityscapes dataset') + parser.add_argument('--aux', action='store_true', default=False, + help='Auxiliary loss') + parser.add_argument('--aux-weight', type=float, default=0.4, + help='auxiliary loss weight') + parser.add_argument('--batch-size', type=int, default=4, metavar='N', + help='input batch size for training (default: 8)') + parser.add_argument('--start_epoch', type=int, default=0, + metavar='N', help='start epochs (default:0)') + parser.add_argument('--epochs', type=int, default=50, metavar='N', + help='number of epochs to train (default: 50)') + parser.add_argument('--lr', type=float, default=1e-4, metavar='LR', + help='learning rate (default: 1e-4)') + parser.add_argument('--momentum', type=float, default=0.9, metavar='M', + help='momentum (default: 0.9)') + parser.add_argument('--weight-decay', type=float, default=1e-4, metavar='M', + help='w-decay (default: 5e-4)') + parser.add_argument('--warmup-iters', type=int, default=0, + help='warmup iters') + parser.add_argument('--warmup-factor', type=float, default=1.0 / 3, + help='lr = warmup_factor * lr') + parser.add_argument('--warmup-method', type=str, default='linear', + help='method of warmup') + # cuda setting + parser.add_argument('--no-cuda', action='store_true', default=False, + help='disables CUDA training') + parser.add_argument('--local_rank', type=int, default=0) + # checkpoint and log + parser.add_argument('--resume', type=str, default=None, + help='put the path to resuming file if needed') + parser.add_argument('--save-dir', default='~/.torch/models', + help='Directory for saving checkpoint models') + parser.add_argument('--save-epoch', type=int, default=10, + help='save model every checkpoint-epoch') + parser.add_argument('--log-dir', default='../runs/logs/', + help='Directory for saving checkpoint models') + parser.add_argument('--log-iter', type=int, default=10, + help='print log every log-iter') + # evaluation only + parser.add_argument('--val-epoch', type=int, default=1, + help='run validation every val-epoch') + parser.add_argument('--skip-val', action='store_true', default=False, + help='skip validation during training') + # apex + parser.add_argument('--amp', default=False, action='store_true', + help='use amp to train the model') + parser.add_argument('--loss-scale', default=128.0, type=float, + help='loss scale using in amp, default -1 means dynamic') + parser.add_argument('--opt-level', default='O2', type=str, + help='loss scale using in amp, default -1 means dynamic') + + # npu setting + parser.add_argument('--device', default='npu', type=str, + help='npu or gpu') + parser.add_argument('--dist-backend', default='hccl', type=str, + help='distributed backend') + + args = parser.parse_args() + + # default settings for epochs, batch_size and lr + if args.epochs is None: + epoches = { + 'coco': 30, + 'pascal_aug': 80, + 'pascal_voc': 50, + 'pcontext': 80, + 'ade20k': 160, + 'citys': 120, + 'sbu': 160, + } + args.epochs = epoches[args.dataset.lower()] + if args.lr is None: + lrs = { + 'coco': 0.004, + 'pascal_aug': 0.001, + 'pascal_voc': 0.0001, + 'pcontext': 0.001, + 'ade20k': 0.01, + 'citys': 0.01, + 'sbu': 0.001, + } + args.lr = lrs[args.dataset.lower()] / 8 * args.batch_size + return args + + +class Trainer(object): + def __init__(self, args): + self.args = args + # self.device = torch.device(args.device) + + loc = 'npu:{}'.format(args.local_rank) + if args.device == "npu": + self.device = torch.npu.set_device(loc) + else: + self.device = torch.device(args.device) + + # image transform + input_transform = transforms.Compose([ + transforms.ToTensor(), + transforms.Normalize([.485, .456, .406], [.229, .224, .225]), + ]) + # dataset and dataloader + data_kwargs = {'transform': input_transform, 'base_size': args.base_size, 'crop_size': args.crop_size} + train_dataset = get_segmentation_dataset(args.dataset, split='train', mode='train', **data_kwargs) + val_dataset = get_segmentation_dataset(args.dataset, split='val', mode='val', **data_kwargs) + args.iters_per_epoch = len(train_dataset) // (args.num_gpus * args.batch_size) + args.max_iters = args.epochs * args.iters_per_epoch + + train_sampler = make_data_sampler(train_dataset, shuffle=True, distributed=args.distributed) + train_batch_sampler = make_batch_data_sampler(train_sampler, args.batch_size, args.max_iters) + val_sampler = make_data_sampler(val_dataset, False, args.distributed) + val_batch_sampler = make_batch_data_sampler(val_sampler, args.batch_size) + + self.train_loader = data.DataLoader(dataset=train_dataset, + batch_sampler=train_batch_sampler, + num_workers=args.workers, + pin_memory=True) + self.val_loader = data.DataLoader(dataset=val_dataset, + batch_sampler=val_batch_sampler, + num_workers=args.workers, + pin_memory=True) + + # create network + BatchNorm2d = nn.BatchNorm2d#nn.SyncBatchNorm if args.distributed else nn.BatchNorm2d + self.model = get_segmentation_model(model=args.model, dataset=args.dataset, backbone=args.backbone, + aux=args.aux, jpu=args.jpu, norm_layer=BatchNorm2d).to(loc) + + # resume checkpoint if needed + if args.resume: + if os.path.isfile(args.resume): + name, ext = os.path.splitext(args.resume) + assert ext == '.pkl' or '.pth', 'Sorry only .pth and .pkl files supported.' + print('Resuming training, loading {}...'.format(args.resume)) + self.model.load_state_dict(torch.load(args.resume, map_location=lambda storage, loc: storage)) + + # create criterion + self.criterion = get_segmentation_loss(args.model, use_ohem=args.use_ohem, aux=args.aux, + aux_weight=args.aux_weight, ignore_index=-1).to(loc) # (args.device) + + # optimizer, for model just includes pretrained, head and auxlayer + params_list = list() + if hasattr(self.model, 'pretrained'): + params_list.append({'params': self.model.pretrained.parameters(), 'lr': args.lr}) + if hasattr(self.model, 'exclusive'): + for module in self.model.exclusive: + params_list.append({'params': getattr(self.model, module).parameters(), 'lr': args.lr * 10}) + self.optimizer = torch.optim.SGD(params_list, + lr=args.lr, + momentum=args.momentum, + weight_decay=args.weight_decay) + + if args.amp: + self.model, self.optimizer = amp.initialize(self.model, self.optimizer, opt_level=args.opt_level, + loss_scale=args.loss_scale) + + # lr scheduling + self.lr_scheduler = WarmupPolyLR(self.optimizer, + max_iters=args.max_iters, + power=0.9, + warmup_factor=args.warmup_factor, + warmup_iters=args.warmup_iters, + warmup_method=args.warmup_method) + + if args.distributed: + self.model = nn.parallel.DistributedDataParallel(self.model, device_ids=[args.local_rank], + output_device=args.local_rank, find_unused_parameters=True, broadcast_buffers=False) + + # evaluation metrics + self.metric = SegmentationMetric(train_dataset.num_class) + + self.best_pred = 0.0 + + def train(self): + batch_time = AverageMeter('Time', ':6.3f', start_count_index=5) + + loc = 'npu:{}'.format(self.args.local_rank) + + save_to_disk = get_rank() == 0 + epochs, max_iters = self.args.epochs, self.args.max_iters + log_per_iters, val_per_iters = self.args.log_iter, self.args.val_epoch * self.args.iters_per_epoch + save_per_iters = self.args.save_epoch * self.args.iters_per_epoch + start_time = time.time() + logger.info('Start training, Total Epochs: {:d} = Total Iterations {:d}'.format(epochs, max_iters)) + + end = time.time() + + self.model.train() + for iteration, (images, targets, _) in enumerate(self.train_loader): + iteration = iteration + 1 + self.lr_scheduler.step() + + # if 'npu' in CALCULATE_DEVICE: + targets = targets.to(torch.int32) + images = images.to(loc) + targets = targets.to(loc) + + # with torch.autograd.profiler.profile(use_npu=True) as prof: + outputs = self.model(images) + + loss_dict = self.criterion(outputs, targets) + + losses = sum(loss for loss in loss_dict.values()) + + # reduce losses over all GPUs for logging purposes + loss_dict_reduced = reduce_loss_dict(loss_dict) + losses_reduced = sum(loss for loss in loss_dict_reduced.values()) + + self.optimizer.zero_grad() + + # losses.backward() + if self.args.amp: + with amp.scale_loss(losses, self.optimizer) as scaled_loss: + scaled_loss.backward() + else: + losses.backward() + + self.optimizer.step() + + # print(prof.key_averages().table(sort_by="self_cpu_time_total")) + # prof.export_chrome_trace("output.prof") # "output.prof"为输出文件地址 + + eta_seconds = ((time.time() - start_time) / iteration) * (max_iters - iteration) + eta_string = str(datetime.timedelta(seconds=int(eta_seconds))) + + if iteration % log_per_iters == 0 and save_to_disk: + logger.info( + "Iters: {:d}/{:d} || Lr: {:.6f} || Loss: {:.4f} || Cost Time: {} || Estimated Time: {}".format( + iteration, max_iters, self.optimizer.param_groups[0]['lr'], losses_reduced.item(), + str(datetime.timedelta(seconds=int(time.time() - start_time))), eta_string)) + + if iteration % self.args.iters_per_epoch == 0 and batch_time.avg > 0: + logger.info("Epoch: {:d}/{:d} || FPS img/s: {:.3f}".format( + iteration // self.args.iters_per_epoch, epochs, + args.num_gpus * self.args.batch_size / batch_time.avg)) + + if iteration % save_per_iters == 0 and save_to_disk and self.args.local_rank == 0: + save_checkpoint(self.model, self.args, is_best=False) + + batch_time.update(time.time() - end) + + if not self.args.skip_val and iteration % val_per_iters == 0: + self.validation() + self.model.train() + + end = time.time() + + if self.args.local_rank == 0: + save_checkpoint(self.model, self.args, is_best=False) + total_training_time = time.time() - start_time + total_training_str = str(datetime.timedelta(seconds=total_training_time)) + logger.info( + "Total training time: {} ({:.4f}s / it)".format( + total_training_str, total_training_time / max_iters)) + + def validation(self): + loc = 'npu:{}'.format(self.args.local_rank) + + # total_inter, total_union, total_correct, total_label = 0, 0, 0, 0 + is_best = False + self.metric.reset() + #if self.args.distributed: + #model = self.model.module + #else: + model = self.model + torch.npu.empty_cache() # TODO check if it helps + model.eval() + for i, (image, target, filename) in enumerate(self.val_loader): + # if 'npu' in CALCULATE_DEVICE: + # target = target.to(torch.int32) + target = target.to(torch.int32) + image = image.to(loc) + target = target.to(loc) + with torch.no_grad(): + outputs = model(image) + self.metric.update(outputs[0], target) + pixAcc, mIoU = self.metric.get() + logger.info("Sample: {:d}, Validation pixAcc: {:.3f}, mIoU: {:.3f}".format(i + 1, pixAcc, mIoU)) + + new_pred = (pixAcc + mIoU) / 2 + if new_pred > self.best_pred: + is_best = True + self.best_pred = new_pred + if self.args.local_rank == 0: + save_checkpoint(self.model, self.args, is_best) + synchronize() + + +class AverageMeter(object): + """Computes and stores the average and current value""" + + def __init__(self, name, fmt=':f', start_count_index=10): + self.name = name + self.fmt = fmt + self.reset() + self.start_count_index = start_count_index + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + + def update(self, val, n=1): + if self.count == 0: + self.N = n + + self.val = val + self.count += n + if self.count > (self.start_count_index * self.N): + self.sum += val * n + self.avg = self.sum / (self.count - self.start_count_index * self.N) + + def __str__(self): + fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' + return fmtstr.format(**self.__dict__) + +def save_checkpoint(model, args, is_best=False): + """Save Checkpoint""" + directory = os.path.expanduser(args.save_dir) + if not os.path.exists(directory): + os.makedirs(directory) + + filename = '{}_{}_{}.pth'.format(args.model, args.backbone, args.dataset) + if args.model == "enet": + filename = '{}_{}.pth'.format(args.model, args.dataset) + filename = os.path.join(directory, filename) + + #if args.distributed: + #model = model.module + torch.save(model.state_dict(), filename) + if is_best: + best_filename = '{}_{}_{}_best_model.pth'.format(args.model, args.backbone, args.dataset) + if args.model == "enet": + best_filename = '{}_{}_best_model.pth'.format(args.model, args.dataset) + best_filename = os.path.join(directory, best_filename) + shutil.copyfile(filename, best_filename) + + +if __name__ == '__main__': + args = parse_args() + + os.environ['MASTER_ADDR'] = '127.0.0.1' # 可以使用当前真实ip或者'127.0.0.1' + os.environ['MASTER_PORT'] = '29688' # 随意一个可使用的port即可 + + # reference maskrcnn-benchmark + num_gpus = int(os.environ["WORLD_SIZE"]) if "WORLD_SIZE" in os.environ else 1 + args.num_gpus = num_gpus + #args.num_gpus = 1 + args.distributed = num_gpus > 1 + + if args.device == "npu": + args.device = "npu" + elif not args.no_cuda and torch.cuda.is_available(): + cudnn.benchmark = True + args.device = "cuda" + else: + args.distributed = False + args.device = "cpu" + if args.distributed: + loc = 'npu:{}'.format(args.local_rank) + torch.npu.set_device(loc) + torch.distributed.init_process_group(backend=args.dist_backend, init_method="env://") + synchronize() + args.lr = args.lr * num_gpus + + logger_filename = '{}_{}_{}_log.txt'.format(args.model, args.backbone, args.dataset) + if args.model == "enet": + logger_filename = '{}_{}_log.txt'.format(args.model, args.dataset) + logger = setup_logger("semantic_segmentation", args.log_dir, get_rank(), filename=logger_filename) + logger.info("Using {} GPUs".format(num_gpus)) + logger.info(args) + + trainer = Trainer(args) + trainer.train() + torch.npu.empty_cache() + diff --git a/PyTorch/contrib/cv/semantic_segmentation/FCN8s/modelzoo_level.txt b/PyTorch/contrib/cv/semantic_segmentation/FCN8s/modelzoo_level.txt index 4987c10696..0c22703439 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/FCN8s/modelzoo_level.txt +++ b/PyTorch/contrib/cv/semantic_segmentation/FCN8s/modelzoo_level.txt @@ -1,6 +1,6 @@ -GPUStatus:OK -NPUMigrationStatus:OK -FuncStatus:OK -PrecisionStatus:OK -AutoTune:OK +GPUStatus:OK +NPUMigrationStatus:OK +FuncStatus:OK +PrecisionStatus:OK +AutoTune:OK PerfStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/FastSCNN/README.md b/PyTorch/contrib/cv/semantic_segmentation/FastSCNN/README.md index cd43babf07..df221c9595 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/FastSCNN/README.md +++ b/PyTorch/contrib/cv/semantic_segmentation/FastSCNN/README.md @@ -1,154 +1,154 @@ -# FastSCNN 训练 - -# the real-time image segmentation FastSCNN - -Fast segmentation convolutional neural network (Fast-SCNN), an above real-time semantic segmentation model on high resolution image data (1024x2048px) suits to efficient computation on embedded devices with low memory. Building on existing two-branch methods for fast segmentation, the 'learning to downsample' module computes low-level features for multiple resolution branches simultaneously. FastSCNN combines spatial detail at high resolution with deep features extracted at lower resolution, yielding an accuracy of 68.0% mean intersection over union at 123.5 frames per second on Cityscapes. - -For more detail:https://arxiv.org/abs/1902.04502 - -## - -## Requirements - -use pytorch, you can use pip or conda to install the requirements - -``` -# for pip -cd $project -pip install -r requirements.txt -CANN 20210617_5.0.T205 -torchvision==0.6.0 -``` - - - -## 数据集准备 - -1.从以下网址获取leftImg8bit_trainvaltest.zip作为训练集 - -https://www.cityscapes-dataset.com/downloads/ - -2.从以往网址获取gtFine_trainvaltest.zip作为标签 - -https://www.cityscapes-dataset.com/downloads/ - -文件结构如下: - - -``` -FastSCNN -|-- configs -|-- datasets -| |-- cityscapes -| | |-- gtFine -| | | |-- test -| | | |-- train -| | | `-- val -| | `-- leftImg8bit -| | |-- test -| | |-- train -| | `-- val -|-- docs -|-- test -|-- segmentron -|-- tools - -``` - -将数据集按照以上结构放在代码目录下 - -## 安装 - -请注意,本模型使用了新版本的pytorch以及CANN包,具体版本为:20210617_5.0.T205; - -![](C:\Users\dilig\Pictures\image-20210824164049265 (2).png) - -source 环境变量 - -``` -source ./test/env.sh -``` - -安装 - -``` -python3.7.5 setup.py develop -``` - -或使用sh脚本安装 - -``` -bash ./test/setup.sh -``` - - - -## TRAIN - -### 单p训练 - -source 环境变量 - -``` -source ./test/env.sh -``` - -运行单p脚本 - -``` -bash ./test/run1p.sh -``` - - - -### 多p训练 - -source 环境变量 - -``` -source ./test/env.sh -``` - -运行8p脚本 - -``` -bash ./test/run8p.sh -``` - -模型保存在./runs/checkpoints目录下,以数字命名的pth文件是当前epoch训练得到的权重文件,可用来恢复训练,best_model.pth是当前训练出的最优模型; - -运行日志保存至./runs/logs目录下 - -## TEST - -测试精度 - -使用sh文件 - -``` -bash test/eval.sh -``` - -测试之前请指定测试的模型路径。打开./test/eval.sh文件,最后一行如下所示: - -``` -python3.7.5 -u ./tools/eval.py --config-file configs/cityscapes_fast_scnn.yaml TEST.TEST_MODEL_PATH runs/checkpoints/FastSCNN__cityscape_2021-07-15-00-51/best_model.pth -``` - -请指定需要测试的模型路径,将runs/checkpoints/FastSCNN__cityscape_2021-07-15-00-51/best_model.pth替换掉即可。 - -## Demo -修改 configs/cityscapes_fast_scnn.yaml中的TEST_MODEL_PATH: 'runs/checkpoints/fast_scnn__cityscape_2019-11-19-02-02/best_model.pth'替换成自己实际存储的模型路径,demo.py的输入图片默认时tool/demo_vis.png,运行的结果保存在runs/demo_result目录下,然后运行以下脚本,执行demo.py: -``` -python3.7 tools/demo.py --config-file configs/cityscapes_fast_scnn.yaml -``` - -### 精度对比 - -GPU8p loss scale使用O1 128混合精度获得的结果为:mIoU:64.46 - -NPU8p loss scale使用O1 128混合精度获得的结果为: mIoU:63.914 - -## 注意事项 - -由于在./FastSCNN/segmentron/modules/csrc/vision.cpp中添加了Licence,可能会导致程序在调用此文件时报错,只需要删除Licence就可以使用 +# FastSCNN 训练 + +# the real-time image segmentation FastSCNN + +Fast segmentation convolutional neural network (Fast-SCNN), an above real-time semantic segmentation model on high resolution image data (1024x2048px) suits to efficient computation on embedded devices with low memory. Building on existing two-branch methods for fast segmentation, the 'learning to downsample' module computes low-level features for multiple resolution branches simultaneously. FastSCNN combines spatial detail at high resolution with deep features extracted at lower resolution, yielding an accuracy of 68.0% mean intersection over union at 123.5 frames per second on Cityscapes. + +For more detail:https://arxiv.org/abs/1902.04502 + +## + +## Requirements + +use pytorch, you can use pip or conda to install the requirements + +``` +# for pip +cd $project +pip install -r requirements.txt +CANN 20210617_5.0.T205 +torchvision==0.6.0 +``` + + + +## 数据集准备 + +1.从以下网址获取leftImg8bit_trainvaltest.zip作为训练集 + +https://www.cityscapes-dataset.com/downloads/ + +2.从以往网址获取gtFine_trainvaltest.zip作为标签 + +https://www.cityscapes-dataset.com/downloads/ + +文件结构如下: + + +``` +FastSCNN +|-- configs +|-- datasets +| |-- cityscapes +| | |-- gtFine +| | | |-- test +| | | |-- train +| | | `-- val +| | `-- leftImg8bit +| | |-- test +| | |-- train +| | `-- val +|-- docs +|-- test +|-- segmentron +|-- tools + +``` + +将数据集按照以上结构放在代码目录下 + +## 安装 + +请注意,本模型使用了新版本的pytorch以及CANN包,具体版本为:20210617_5.0.T205; + +![](C:\Users\dilig\Pictures\image-20210824164049265 (2).png) + +source 环境变量 + +``` +source ./test/env.sh +``` + +安装 + +``` +python3.7.5 setup.py develop +``` + +或使用sh脚本安装 + +``` +bash ./test/setup.sh +``` + + + +## TRAIN + +### 单p训练 + +source 环境变量 + +``` +source ./test/env.sh +``` + +运行单p脚本 + +``` +bash ./test/run1p.sh +``` + + + +### 多p训练 + +source 环境变量 + +``` +source ./test/env.sh +``` + +运行8p脚本 + +``` +bash ./test/run8p.sh +``` + +模型保存在./runs/checkpoints目录下,以数字命名的pth文件是当前epoch训练得到的权重文件,可用来恢复训练,best_model.pth是当前训练出的最优模型; + +运行日志保存至./runs/logs目录下 + +## TEST + +测试精度 + +使用sh文件 + +``` +bash test/eval.sh +``` + +测试之前请指定测试的模型路径。打开./test/eval.sh文件,最后一行如下所示: + +``` +python3.7.5 -u ./tools/eval.py --config-file configs/cityscapes_fast_scnn.yaml TEST.TEST_MODEL_PATH runs/checkpoints/FastSCNN__cityscape_2021-07-15-00-51/best_model.pth +``` + +请指定需要测试的模型路径,将runs/checkpoints/FastSCNN__cityscape_2021-07-15-00-51/best_model.pth替换掉即可。 + +## Demo +修改 configs/cityscapes_fast_scnn.yaml中的TEST_MODEL_PATH: 'runs/checkpoints/fast_scnn__cityscape_2019-11-19-02-02/best_model.pth'替换成自己实际存储的模型路径,demo.py的输入图片默认时tool/demo_vis.png,运行的结果保存在runs/demo_result目录下,然后运行以下脚本,执行demo.py: +``` +python3.7 tools/demo.py --config-file configs/cityscapes_fast_scnn.yaml +``` + +### 精度对比 + +GPU8p loss scale使用O1 128混合精度获得的结果为:mIoU:64.46 + +NPU8p loss scale使用O1 128混合精度获得的结果为: mIoU:63.914 + +## 注意事项 + +由于在./FastSCNN/segmentron/modules/csrc/vision.cpp中添加了Licence,可能会导致程序在调用此文件时报错,只需要删除Licence就可以使用 diff --git a/PyTorch/contrib/cv/semantic_segmentation/FastSCNN/modelzoo_level.txt b/PyTorch/contrib/cv/semantic_segmentation/FastSCNN/modelzoo_level.txt index 0673c9bd59..05a5423b13 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/FastSCNN/modelzoo_level.txt +++ b/PyTorch/contrib/cv/semantic_segmentation/FastSCNN/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK,but performance on npu less than performance on gpu +FuncStatus:OK +PerfStatus:OK,but performance on npu less than performance on gpu PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/FastSCNN/segmentron/models/ocnet.py b/PyTorch/contrib/cv/semantic_segmentation/FastSCNN/segmentron/models/ocnet.py index ecd42b5f76..942039eddf 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/FastSCNN/segmentron/models/ocnet.py +++ b/PyTorch/contrib/cv/semantic_segmentation/FastSCNN/segmentron/models/ocnet.py @@ -1,308 +1,308 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -import torch.nn as nn -import torch.nn.functional as F - -from .segbase import SegBaseModel -from .model_zoo import MODEL_REGISTRY -from ..modules import _FCNHead -from ..config import cfg - -__all__ = ['OCNet'] - - -@MODEL_REGISTRY.register() -class OCNet(SegBaseModel): - r"""OCNet - Reference: - Yuhui Yuan, Jingdong Wang. "OCNet: Object Context Network for Scene Parsing." - arXiv preprint arXiv:1809.00916 (2018). - """ - - def __init__(self): - super(OCNet, self).__init__() - oc_arch = cfg.MODEL.OCNet.OC_ARCH - self.head = _OCHead(self.nclass, oc_arch, norm_layer=self.norm_layer) - if self.aux: - self.auxlayer = _FCNHead(1024, self.nclass, norm_layer=self.norm_layer) - - self.__setattr__('decoder', ['head', 'auxlayer'] if self.aux else ['head']) - - def forward(self, x): - size = x.size()[2:] - _, _, c3, c4 = self.base_forward(x) - outputs = [] - x = self.head(c4) - x = F.interpolate(x, size, mode='bilinear', align_corners=True) - outputs.append(x) - - if self.aux: - auxout = self.auxlayer(c3) - auxout = F.interpolate(auxout, size, mode='bilinear', align_corners=True) - outputs.append(auxout) - return tuple(outputs) - - -class _OCHead(nn.Module): - def __init__(self, nclass, oc_arch, norm_layer=nn.BatchNorm2d, **kwargs): - super(_OCHead, self).__init__() - if oc_arch == 'base': - self.context = nn.Sequential( - nn.Conv2d(2048, 512, 3, 1, padding=1, bias=False), - norm_layer(512), - nn.ReLU(True), - BaseOCModule(512, 512, 256, 256, scales=([1]), norm_layer=norm_layer, **kwargs)) - elif oc_arch == 'pyramid': - self.context = nn.Sequential( - nn.Conv2d(2048, 512, 3, 1, padding=1, bias=False), - norm_layer(512), - nn.ReLU(True), - PyramidOCModule(512, 512, 256, 512, scales=([1, 2, 3, 6]), norm_layer=norm_layer, **kwargs)) - elif oc_arch == 'asp': - self.context = ASPOCModule(2048, 512, 256, 512, norm_layer=norm_layer, **kwargs) - else: - raise ValueError("Unknown OC architecture!") - - self.out = nn.Conv2d(512, nclass, 1) - - def forward(self, x): - x = self.context(x) - return self.out(x) - - -class BaseAttentionBlock(nn.Module): - """The basic implementation for self-attention block/non-local block.""" - - def __init__(self, in_channels, out_channels, key_channels, value_channels, - scale=1, norm_layer=nn.BatchNorm2d, **kwargs): - super(BaseAttentionBlock, self).__init__() - self.scale = scale - self.key_channels = key_channels - self.value_channels = value_channels - if scale > 1: - self.pool = nn.MaxPool2d(scale) - - self.f_value = nn.Conv2d(in_channels, value_channels, 1) - self.f_key = nn.Sequential( - nn.Conv2d(in_channels, key_channels, 1), - norm_layer(key_channels), - nn.ReLU(True) - ) - self.f_query = self.f_key - self.W = nn.Conv2d(value_channels, out_channels, 1) - nn.init.constant_(self.W.weight, 0) - nn.init.constant_(self.W.bias, 0) - - def forward(self, x): - batch_size, c, w, h = x.size() - if self.scale > 1: - x = self.pool(x) - - value = self.f_value(x).view(batch_size, self.value_channels, -1).permute(0, 2, 1) - query = self.f_query(x).view(batch_size, self.key_channels, -1).permute(0, 2, 1) - key = self.f_key(x).view(batch_size, self.key_channels, -1) - - sim_map = torch.bmm(query, key) * (self.key_channels ** -.5) - sim_map = F.softmax(sim_map, dim=-1) - - context = torch.bmm(sim_map, value).permute(0, 2, 1).contiguous() - context = context.view(batch_size, self.value_channels, *x.size()[2:]) - context = self.W(context) - if self.scale > 1: - context = F.interpolate(context, size=(w, h), mode='bilinear', align_corners=True) - - return context - - -class BaseOCModule(nn.Module): - """Base-OC""" - - def __init__(self, in_channels, out_channels, key_channels, value_channels, - scales=([1]), norm_layer=nn.BatchNorm2d, concat=True, **kwargs): - super(BaseOCModule, self).__init__() - self.stages = nn.ModuleList([ - BaseAttentionBlock(in_channels, out_channels, key_channels, value_channels, scale, norm_layer, **kwargs) - for scale in scales]) - in_channels = in_channels * 2 if concat else in_channels - self.project = nn.Sequential( - nn.Conv2d(in_channels, out_channels, 1), - norm_layer(out_channels), - nn.ReLU(True), - nn.Dropout2d(0.05) - ) - self.concat = concat - - def forward(self, x): - priors = [stage(x) for stage in self.stages] - context = priors[0] - for i in range(1, len(priors)): - context += priors[i] - if self.concat: - context = torch.cat([context, x], 1) - out = self.project(context) - return out - - -class PyramidAttentionBlock(nn.Module): - """The basic implementation for pyramid self-attention block/non-local block""" - - def __init__(self, in_channels, out_channels, key_channels, value_channels, - scale=1, norm_layer=nn.BatchNorm2d, **kwargs): - super(PyramidAttentionBlock, self).__init__() - self.scale = scale - self.value_channels = value_channels - self.key_channels = key_channels - - self.f_value = nn.Conv2d(in_channels, value_channels, 1) - self.f_key = nn.Sequential( - nn.Conv2d(in_channels, key_channels, 1), - norm_layer(key_channels), - nn.ReLU(True) - ) - self.f_query = self.f_key - self.W = nn.Conv2d(value_channels, out_channels, 1) - nn.init.constant_(self.W.weight, 0) - nn.init.constant_(self.W.bias, 0) - - def forward(self, x): - batch_size, c, w, h = x.size() - - local_x = list() - local_y = list() - step_w, step_h = w // self.scale, h // self.scale - for i in range(self.scale): - for j in range(self.scale): - start_x, start_y = step_w * i, step_h * j - end_x, end_y = min(start_x + step_w, w), min(start_y + step_h, h) - if i == (self.scale - 1): - end_x = w - if j == (self.scale - 1): - end_y = h - local_x += [start_x, end_x] - local_y += [start_y, end_y] - - value = self.f_value(x) - query = self.f_query(x) - key = self.f_key(x) - - local_list = list() - local_block_cnt = (self.scale ** 2) * 2 - for i in range(0, local_block_cnt, 2): - value_local = value[:, :, local_x[i]:local_x[i + 1], local_y[i]:local_y[i + 1]] - query_local = query[:, :, local_x[i]:local_x[i + 1], local_y[i]:local_y[i + 1]] - key_local = key[:, :, local_x[i]:local_x[i + 1], local_y[i]:local_y[i + 1]] - - w_local, h_local = value_local.size(2), value_local.size(3) - value_local = value_local.contiguous().view(batch_size, self.value_channels, -1).permute(0, 2, 1) - query_local = query_local.contiguous().view(batch_size, self.key_channels, -1).permute(0, 2, 1) - key_local = key_local.contiguous().view(batch_size, self.key_channels, -1) - - sim_map = torch.bmm(query_local, key_local) * (self.key_channels ** -.5) - sim_map = F.softmax(sim_map, dim=-1) - - context_local = torch.bmm(sim_map, value_local).permute(0, 2, 1).contiguous() - context_local = context_local.view(batch_size, self.value_channels, w_local, h_local) - local_list.append(context_local) - - context_list = list() - for i in range(0, self.scale): - row_tmp = list() - for j in range(self.scale): - row_tmp.append(local_list[j + i * self.scale]) - context_list.append(torch.cat(row_tmp, 3)) - - context = torch.cat(context_list, 2) - context = self.W(context) - - return context - - -class PyramidOCModule(nn.Module): - """Pyramid-OC""" - - def __init__(self, in_channels, out_channels, key_channels, value_channels, - scales=([1]), norm_layer=nn.BatchNorm2d, **kwargs): - super(PyramidOCModule, self).__init__() - self.stages = nn.ModuleList([ - PyramidAttentionBlock(in_channels, out_channels, key_channels, value_channels, scale, norm_layer, **kwargs) - for scale in scales]) - self.up_dr = nn.Sequential( - nn.Conv2d(in_channels, in_channels * len(scales), 1), - norm_layer(in_channels * len(scales)), - nn.ReLU(True) - ) - self.project = nn.Sequential( - nn.Conv2d(in_channels * len(scales) * 2, out_channels, 1), - norm_layer(out_channels), - nn.ReLU(True), - nn.Dropout2d(0.05) - ) - - def forward(self, x): - priors = [stage(x) for stage in self.stages] - context = [self.up_dr(x)] - for i in range(len(priors)): - context += [priors[i]] - context = torch.cat(context, 1) - out = self.project(context) - return out - - -class ASPOCModule(nn.Module): - """ASP-OC""" - - def __init__(self, in_channels, out_channels, key_channels, value_channels, - atrous_rates=(12, 24, 36), norm_layer=nn.BatchNorm2d, **kwargs): - super(ASPOCModule, self).__init__() - self.context = nn.Sequential( - nn.Conv2d(in_channels, out_channels, 3, padding=1), - norm_layer(out_channels), - nn.ReLU(True), - BaseOCModule(out_channels, out_channels, key_channels, value_channels, ([2]), norm_layer, False, **kwargs)) - - rate1, rate2, rate3 = tuple(atrous_rates) - self.b1 = nn.Sequential( - nn.Conv2d(in_channels, out_channels, 3, padding=rate1, dilation=rate1, bias=False), - norm_layer(out_channels), - nn.ReLU(True)) - self.b2 = nn.Sequential( - nn.Conv2d(in_channels, out_channels, 3, padding=rate2, dilation=rate2, bias=False), - norm_layer(out_channels), - nn.ReLU(True)) - self.b3 = nn.Sequential( - nn.Conv2d(in_channels, out_channels, 3, padding=rate3, dilation=rate3, bias=False), - norm_layer(out_channels), - nn.ReLU(True)) - self.b4 = nn.Sequential( - nn.Conv2d(in_channels, out_channels, 1, bias=False), - norm_layer(out_channels), - nn.ReLU(True)) - - self.project = nn.Sequential( - nn.Conv2d(out_channels * 5, out_channels, 1, bias=False), - norm_layer(out_channels), - nn.ReLU(True), - nn.Dropout2d(0.1) - ) - - def forward(self, x): - feat1 = self.context(x) - feat2 = self.b1(x) - feat3 = self.b2(x) - feat4 = self.b3(x) - feat5 = self.b4(x) - out = torch.cat((feat1, feat2, feat3, feat4, feat5), dim=1) - out = self.project(out) - return out +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +import torch.nn as nn +import torch.nn.functional as F + +from .segbase import SegBaseModel +from .model_zoo import MODEL_REGISTRY +from ..modules import _FCNHead +from ..config import cfg + +__all__ = ['OCNet'] + + +@MODEL_REGISTRY.register() +class OCNet(SegBaseModel): + r"""OCNet + Reference: + Yuhui Yuan, Jingdong Wang. "OCNet: Object Context Network for Scene Parsing." + arXiv preprint arXiv:1809.00916 (2018). + """ + + def __init__(self): + super(OCNet, self).__init__() + oc_arch = cfg.MODEL.OCNet.OC_ARCH + self.head = _OCHead(self.nclass, oc_arch, norm_layer=self.norm_layer) + if self.aux: + self.auxlayer = _FCNHead(1024, self.nclass, norm_layer=self.norm_layer) + + self.__setattr__('decoder', ['head', 'auxlayer'] if self.aux else ['head']) + + def forward(self, x): + size = x.size()[2:] + _, _, c3, c4 = self.base_forward(x) + outputs = [] + x = self.head(c4) + x = F.interpolate(x, size, mode='bilinear', align_corners=True) + outputs.append(x) + + if self.aux: + auxout = self.auxlayer(c3) + auxout = F.interpolate(auxout, size, mode='bilinear', align_corners=True) + outputs.append(auxout) + return tuple(outputs) + + +class _OCHead(nn.Module): + def __init__(self, nclass, oc_arch, norm_layer=nn.BatchNorm2d, **kwargs): + super(_OCHead, self).__init__() + if oc_arch == 'base': + self.context = nn.Sequential( + nn.Conv2d(2048, 512, 3, 1, padding=1, bias=False), + norm_layer(512), + nn.ReLU(True), + BaseOCModule(512, 512, 256, 256, scales=([1]), norm_layer=norm_layer, **kwargs)) + elif oc_arch == 'pyramid': + self.context = nn.Sequential( + nn.Conv2d(2048, 512, 3, 1, padding=1, bias=False), + norm_layer(512), + nn.ReLU(True), + PyramidOCModule(512, 512, 256, 512, scales=([1, 2, 3, 6]), norm_layer=norm_layer, **kwargs)) + elif oc_arch == 'asp': + self.context = ASPOCModule(2048, 512, 256, 512, norm_layer=norm_layer, **kwargs) + else: + raise ValueError("Unknown OC architecture!") + + self.out = nn.Conv2d(512, nclass, 1) + + def forward(self, x): + x = self.context(x) + return self.out(x) + + +class BaseAttentionBlock(nn.Module): + """The basic implementation for self-attention block/non-local block.""" + + def __init__(self, in_channels, out_channels, key_channels, value_channels, + scale=1, norm_layer=nn.BatchNorm2d, **kwargs): + super(BaseAttentionBlock, self).__init__() + self.scale = scale + self.key_channels = key_channels + self.value_channels = value_channels + if scale > 1: + self.pool = nn.MaxPool2d(scale) + + self.f_value = nn.Conv2d(in_channels, value_channels, 1) + self.f_key = nn.Sequential( + nn.Conv2d(in_channels, key_channels, 1), + norm_layer(key_channels), + nn.ReLU(True) + ) + self.f_query = self.f_key + self.W = nn.Conv2d(value_channels, out_channels, 1) + nn.init.constant_(self.W.weight, 0) + nn.init.constant_(self.W.bias, 0) + + def forward(self, x): + batch_size, c, w, h = x.size() + if self.scale > 1: + x = self.pool(x) + + value = self.f_value(x).view(batch_size, self.value_channels, -1).permute(0, 2, 1) + query = self.f_query(x).view(batch_size, self.key_channels, -1).permute(0, 2, 1) + key = self.f_key(x).view(batch_size, self.key_channels, -1) + + sim_map = torch.bmm(query, key) * (self.key_channels ** -.5) + sim_map = F.softmax(sim_map, dim=-1) + + context = torch.bmm(sim_map, value).permute(0, 2, 1).contiguous() + context = context.view(batch_size, self.value_channels, *x.size()[2:]) + context = self.W(context) + if self.scale > 1: + context = F.interpolate(context, size=(w, h), mode='bilinear', align_corners=True) + + return context + + +class BaseOCModule(nn.Module): + """Base-OC""" + + def __init__(self, in_channels, out_channels, key_channels, value_channels, + scales=([1]), norm_layer=nn.BatchNorm2d, concat=True, **kwargs): + super(BaseOCModule, self).__init__() + self.stages = nn.ModuleList([ + BaseAttentionBlock(in_channels, out_channels, key_channels, value_channels, scale, norm_layer, **kwargs) + for scale in scales]) + in_channels = in_channels * 2 if concat else in_channels + self.project = nn.Sequential( + nn.Conv2d(in_channels, out_channels, 1), + norm_layer(out_channels), + nn.ReLU(True), + nn.Dropout2d(0.05) + ) + self.concat = concat + + def forward(self, x): + priors = [stage(x) for stage in self.stages] + context = priors[0] + for i in range(1, len(priors)): + context += priors[i] + if self.concat: + context = torch.cat([context, x], 1) + out = self.project(context) + return out + + +class PyramidAttentionBlock(nn.Module): + """The basic implementation for pyramid self-attention block/non-local block""" + + def __init__(self, in_channels, out_channels, key_channels, value_channels, + scale=1, norm_layer=nn.BatchNorm2d, **kwargs): + super(PyramidAttentionBlock, self).__init__() + self.scale = scale + self.value_channels = value_channels + self.key_channels = key_channels + + self.f_value = nn.Conv2d(in_channels, value_channels, 1) + self.f_key = nn.Sequential( + nn.Conv2d(in_channels, key_channels, 1), + norm_layer(key_channels), + nn.ReLU(True) + ) + self.f_query = self.f_key + self.W = nn.Conv2d(value_channels, out_channels, 1) + nn.init.constant_(self.W.weight, 0) + nn.init.constant_(self.W.bias, 0) + + def forward(self, x): + batch_size, c, w, h = x.size() + + local_x = list() + local_y = list() + step_w, step_h = w // self.scale, h // self.scale + for i in range(self.scale): + for j in range(self.scale): + start_x, start_y = step_w * i, step_h * j + end_x, end_y = min(start_x + step_w, w), min(start_y + step_h, h) + if i == (self.scale - 1): + end_x = w + if j == (self.scale - 1): + end_y = h + local_x += [start_x, end_x] + local_y += [start_y, end_y] + + value = self.f_value(x) + query = self.f_query(x) + key = self.f_key(x) + + local_list = list() + local_block_cnt = (self.scale ** 2) * 2 + for i in range(0, local_block_cnt, 2): + value_local = value[:, :, local_x[i]:local_x[i + 1], local_y[i]:local_y[i + 1]] + query_local = query[:, :, local_x[i]:local_x[i + 1], local_y[i]:local_y[i + 1]] + key_local = key[:, :, local_x[i]:local_x[i + 1], local_y[i]:local_y[i + 1]] + + w_local, h_local = value_local.size(2), value_local.size(3) + value_local = value_local.contiguous().view(batch_size, self.value_channels, -1).permute(0, 2, 1) + query_local = query_local.contiguous().view(batch_size, self.key_channels, -1).permute(0, 2, 1) + key_local = key_local.contiguous().view(batch_size, self.key_channels, -1) + + sim_map = torch.bmm(query_local, key_local) * (self.key_channels ** -.5) + sim_map = F.softmax(sim_map, dim=-1) + + context_local = torch.bmm(sim_map, value_local).permute(0, 2, 1).contiguous() + context_local = context_local.view(batch_size, self.value_channels, w_local, h_local) + local_list.append(context_local) + + context_list = list() + for i in range(0, self.scale): + row_tmp = list() + for j in range(self.scale): + row_tmp.append(local_list[j + i * self.scale]) + context_list.append(torch.cat(row_tmp, 3)) + + context = torch.cat(context_list, 2) + context = self.W(context) + + return context + + +class PyramidOCModule(nn.Module): + """Pyramid-OC""" + + def __init__(self, in_channels, out_channels, key_channels, value_channels, + scales=([1]), norm_layer=nn.BatchNorm2d, **kwargs): + super(PyramidOCModule, self).__init__() + self.stages = nn.ModuleList([ + PyramidAttentionBlock(in_channels, out_channels, key_channels, value_channels, scale, norm_layer, **kwargs) + for scale in scales]) + self.up_dr = nn.Sequential( + nn.Conv2d(in_channels, in_channels * len(scales), 1), + norm_layer(in_channels * len(scales)), + nn.ReLU(True) + ) + self.project = nn.Sequential( + nn.Conv2d(in_channels * len(scales) * 2, out_channels, 1), + norm_layer(out_channels), + nn.ReLU(True), + nn.Dropout2d(0.05) + ) + + def forward(self, x): + priors = [stage(x) for stage in self.stages] + context = [self.up_dr(x)] + for i in range(len(priors)): + context += [priors[i]] + context = torch.cat(context, 1) + out = self.project(context) + return out + + +class ASPOCModule(nn.Module): + """ASP-OC""" + + def __init__(self, in_channels, out_channels, key_channels, value_channels, + atrous_rates=(12, 24, 36), norm_layer=nn.BatchNorm2d, **kwargs): + super(ASPOCModule, self).__init__() + self.context = nn.Sequential( + nn.Conv2d(in_channels, out_channels, 3, padding=1), + norm_layer(out_channels), + nn.ReLU(True), + BaseOCModule(out_channels, out_channels, key_channels, value_channels, ([2]), norm_layer, False, **kwargs)) + + rate1, rate2, rate3 = tuple(atrous_rates) + self.b1 = nn.Sequential( + nn.Conv2d(in_channels, out_channels, 3, padding=rate1, dilation=rate1, bias=False), + norm_layer(out_channels), + nn.ReLU(True)) + self.b2 = nn.Sequential( + nn.Conv2d(in_channels, out_channels, 3, padding=rate2, dilation=rate2, bias=False), + norm_layer(out_channels), + nn.ReLU(True)) + self.b3 = nn.Sequential( + nn.Conv2d(in_channels, out_channels, 3, padding=rate3, dilation=rate3, bias=False), + norm_layer(out_channels), + nn.ReLU(True)) + self.b4 = nn.Sequential( + nn.Conv2d(in_channels, out_channels, 1, bias=False), + norm_layer(out_channels), + nn.ReLU(True)) + + self.project = nn.Sequential( + nn.Conv2d(out_channels * 5, out_channels, 1, bias=False), + norm_layer(out_channels), + nn.ReLU(True), + nn.Dropout2d(0.1) + ) + + def forward(self, x): + feat1 = self.context(x) + feat2 = self.b1(x) + feat3 = self.b2(x) + feat4 = self.b3(x) + feat5 = self.b4(x) + out = torch.cat((feat1, feat2, feat3, feat4, feat5), dim=1) + out = self.project(out) + return out diff --git a/PyTorch/contrib/cv/semantic_segmentation/HRNet_SEG_for_Pytorch/figures/OCR.PNG b/PyTorch/contrib/cv/semantic_segmentation/HRNet_SEG_for_Pytorch/figures/OCR.PNG deleted file mode 100644 index 4b72e990fd559ff19bd91756b08475cff30b5aa9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65653 zcmb5Vby!sI+BU2rCEX}FfOK~wF{HFecPS~|AW}nv(%m5?-6D;2!_eK0bbV`Z|MuR` z^S$pM?{OHcVb;Cw`-=0ba|J6YNTI!W_2S8sCulO#5-Lxgz*jtZ@>C270r-T9mmvuF z@2P`|l-QHfLE>%T;<>q~yy%lB<&h}2hVZ~O@+WCchbK?a+hKp7cH0)1JbChvD@d%F&T;9{dxfj!NY`)$uc@D_u*v70rsHmVo0$e<36%pPjsDJlNdJ>J{7@khUD(jQl8XMLNS=d?SC z3-!k=`~3K1JM2jc0X8<}670uKskpsO<_-sbvx28&f&+Y{@a10{e8&a5%hvZ_cfl@z zU*~*>J<1j3@e=Ya z)nreY>MA!ql>dky>4k~ zL}2&$n!rkRd8yjP z9G1^wLsxzFB(F=q-B>-Pg!8wmMy_>}jZPY+#XcxBoeA!^{6bbsSM7o;TYAJodP@P=Q`)KK1(WpgaIq6_77gg@Oew|pvwtYwQQmQ6mc(EfPlI^>ZhzW!^eXj#NEm2-b4YKwf*zb8Z*lSD*1T* zAn;7m*rtN9@jz+4gTlSG?FY-(gQ9`%BPE4i8{NN_R- zEh$lJo5Q-vzs`=du;ktxM0Y#zEGdDe2rTwFm{-~wqpGixTah(+8P~P z!-fmB2&b4;$?oBvq^%gp?BNci&@NFn(YC;ac4?VHto(jXpW~PLnEneGVMq{ekKjBP zbfS=&ZfCA2tih90Ho3PK{Qt0SQYH8t-v>~ULR`|V;EEIX8gX>(m3i;nchvvvyBO1#UFta^gD9n2$7G)oextg-?DE#S&n(E<^N#fp0qVkAO2uK zoSx)z>sIGOsw(}BNY?8cq9zXwCh+NQpk@iG5InI@v^+VXub$>%s>T_5X?YS+R8KAS z2R{az+QJfE=EQf1(VFR^!1Kwm2(Ty)fq9koluA6E!0$;ex^2bv3^7%Khg3Va2qBxo zPA`MvRL@S8Zx7nQ&mRhZD_fj6XiWJR#D2XWon%f|iIY+7n|V!kWIZ;y=0{l`G0A0j zL~|`*VR2HUQj_Q;FZ@I`PD+@UV`|O1Y@E}_H`xcI?%}9YmZe`?<5K2OA=b6m!{?&MK3Tk}&_C9-`f6Ry?o2L59D}y3 z(A(C0y~c3`ye>TWH+0)!<3c-Ll^d5W;+sWJ&hGXK{Ny`9Pt|KigatRqDpEAlxrlA! zK6f<`F4g?(zxwjRX?ya0dhc=Gh%2Dd9Dn*Bw8o+}m+gS0_nK>(oVR+!qzXR9WOJD1 z+rdkOl3GSHX%$19^#}d`9fc)sQ*_DZ$Lm(9A6h_OOcE?c$KOO@w?*~B0{qGgTCX9z z#QmZwb*x%&BbJ}2%HcBaf1)**#Wg$9Mlu+db41Ao!0w=j=*_LHWXSem*+oyLhR5y_ z^P&Ku7zxxN1Ed6Y)lR@Ja{HB~9&;FaL|Bw&05La|EMgn*G4oH$k=POc=j-C<-qHl# z0gfwtZbAFZ>-mn4Swk!=h3SaJY>}QgEU?9bYJW*_){*#kq(AKXboD&PVUbpSk9(_f zg8nf}SQmpyf$NVHSv6$O+VG@&RK}@;jb6=!2o+)P?eDe@V}hg6bJaRWaHNPLb@tFq z_6G6qp3aI(PI+sG(braTKXVG1_>)6c6XUt6>1e)wVml1UJD+Gh?Om)XZLSnhC=_a5 z_pd+Sd%uc6T+cA5vs-(RpmKBji_bxxDmw%7TO^Hz1r3XC*B6e$B(18ZQX*y(3k!z9 z+*Jejh&=AQcQ3H*Q8=p)BdN&sSw32j-Fv*(OlwUx>aSLJ?x3%pT6^G`K(OI09T#38 zuq_QCEu>&*LLaiijJ)N=YVX(q`Zb+105q;P=G3oF0!q`#Idx^^mg zBtN#ri&lsr;H&7Btr*hrd)kU-B0AF=Q*-OeNP9C_Mkprzh>><&9pJ;3X=` z(1A0wr~E(R%{A?Pu6OP`fs>U-(o`+UC2l>PRYGSVZ{Nqp?)KctDMyd{e73`pT6YP@Ev2Dbpb*V(<*C;DlC-ewSOwbVb8?{g2MAK z%||kyoa0^mj(cDR`MXl$LKniPl`A28MdZ4dnj|nmAQcM2V7xRCWEpQ?E~SdfCz-xY zt3Uu1b9|A=fcXrn<=$nwsch1BOci~%-s;e)=clbsEOD~V(94cRKyAyG78xS3+7&(! zY&A-}Z{z)h<*p9?_YQ%XW@S*O>E=im5qfk`z))4IlWp;PTY}eQ4EnpDrHj@-&hcVL ztJg{d*?1jy*^Wp%EX2E#%Ho@0SOyPf^L($B0aD%ld1)CR6%!m4q(vvl+v_WU*!6>e$gxy`%hoZ30y;e4vx{-o2|%57Y3t zo|?9;#uTZxtyS}g_0>~{{Te*P*rX3MM&GLwAIem4td-t!VSy?{W<1`j;_Qog^Q9FO z20IgH!G}1>S7AY;Q*sNv9JZQ9v)UWZ&r5mNwqMIz7r56rt)*Uqmm$RpVZo$ zH@zg$D>NDA8i-*FdKvF~--LAgrx|Xsx(kFw_H@oDl64*h-^6I=>}2+w+r(6&D}=Ll zfBKlrFNS32KL?Ej^|uHG-m%Khi(KNgMED@y357x7H(UjZGWZs^& zdAR>2vJlp!A!k^l@LVJ)Cks}%>7d0EKv#`TB}Ex3)2QZIjkL zvTcRIAi#BS6n)F8#0QJ&N*H`!fcpUF{=BwRTAM6ZW8a2p4)#1hkR}CImv$uwGqRDKCN?`8!@^Vn7!oJx(UcybR@D=O|v$) z6p@7Nk-3xC?Mthf#D|Sd#$sYTMnH?YrXGBA#$>9R9;eWAx|1YV3?dwk*igwA!SmkB zdZwfj0}twaIO%oduY;}DjP6&fmlw_a?HO#38Mela!*2DlRpP>bS*ND|vdtfFe@=&W zs=pJ+Jk&4IbW5djjsDiPf+5NOT5OXngjzSy;CAEP*%b*U^qSCfWP%KImsf}wfIaH+ z_SZMvWb$!!#D`((Ep`(@?)+B|D$5Hjb`MOHM>kV@I+%g~G_mO*n9^IuKCl?+WA0aHB&)Tq@7P~c)Dah)&-by?; zhhwhbK=_&XvmPW?S=iZKF`49oroOw^7%5xa@1WL;gz&vE@fz-TJo7bZjB|W?5H{&4tlk@49P? zl&b&bH95K9iwmzN{1XbgHPWPrDGzX_!Vfz)?S(7sdwvrwV-*1G4g*WTNQK0**wCKT z$ZpG<>;cGtQ4oBY@J)e>Hefq0mTGY~?n7xTKFG;p3bk-P!2^C|cJl zJ-7G{F0qL+;a*m;s)&ry2c1W%);!;!wGQ#q7*Stm#+b-#sB%cpWVfep={;zRM_xDC z-lh@z!g#F(m!n){hU-COvb&ewZEYQf+n0US51VoHtzN{-1@i}~RTO5M+yq>tIpEs6sszU_JUU~Gf zb058wvVWuW`iPT-{>B)WYQFLAqHFe4;&ow7n%wrajl}ISw!6GrzDBaXc>Ytn95Kk5 zrTbFU8Vh@b=$lcep)wfk%&frThL$QuWW3am(p#~!>fPObCO&cyeE7p?2(+gsOzJli zNS<{;1rbsEv2QH_A4tx4^1kV6Q*v*ioOltiBB5(wlc$9&S*MC`Ut(+X5^!m}Gz zC$>i*a*)>VZ1Y&li=^4kJ!K!44a0U-;LhA5TC?W6KUr-uHqG$iX1XZ)YnZA4iS8j# z1w{3>0xBCVzuEOr8sZ`L%A*b@!T(b@@|>j@KmF9bL&5vW+3tK$y5ctI^HE!$X(+@>*Z5xEUZ^yKcvj*hPKCt zoV8=9DjXDze_N(v&bX4B>0v7B4O*-3c!%AZh$Suu3(9^y*0Q=BcxJa)XL~GB zd41w57iPbtQfG^5gA~#R8F=5)(K8>0W$ib7^-Y{M2BTvS3o3jMLW+dE@lVof^&Y;G z$hfKdaMqtEwnyXu_a#g6%}u^!hP9IUdcOtOq;F_!RbVVpgZ*lj?R&H5(dnG*8UsZm z{;gJXSaqKMJ;6bH0?`*tE~8383krf{sUAd~RFT%qHbF+B1x#OEk#4)Q_$rkdJ;qyO zbZ07A=i(MjX!SDL8FfuUnRsl#M=x<@^B%GF_vMom@HcF$-|P}RI!?ysZ_&!Kz(?~5 zR1r%d)%fMYPx`yRZzhvxvudx6YJpyJY?!AC zJ&>{gTX(#nYx^6=yW6^^+h@ohJqT7J`2@(z*vp>+kqoHhq}MYbR_U(_7TfAtM)Twu zIF-Fg@V;=vc?VSVWjzWN@Z`V(pG98J8wrl_Lm_0gE|NHQ;lp)p=a9XM3(dW0k=}&x zr&xwte9Kj)>937Jf!rtH4{Xu<{(y*H*HecL-5+ zs5_mc*$CbdG9nLQ>Fc*AeYpKPH8|$Qk<}p(D?9GN#KODb;ci5<>$j~R&k7j4df|{> zd>h0(4JLQI2l!-hPr3X4swTI0%&IwX<sPu!gjGCW-MjZDY;bH z#pX&vg7p%54(m@?iTyUTd>oY5o+$PHTFw<&X*R!JiYwqpIw}c{7#eJSdGAmI^e)&4 zsT`0%gP9$q(8*~`=qPmCwW^%O)8eA-xl{VDv>^}6m)fpY$ljM5mY#RjDYo8S^kB$r z{g6@jz4AfV)Ue8e`Ae7n>tJ@avrGdbidmWTeK1|Fl=DW4Zvl=g%}*i9GI_pQ-NYNV zlXE&v6ZO&mQW7pSOSePlK_D#ddk_9T7>Vupz@`s+O(F2LWH63=LJ=NZGpd!NZ2afO zh>^5_%vTR5f&o#;tuH8BS(@eT+aK=SbT0+W9s=P#IM!O0KldEZ8NkZCBpYesZF#TFUl>y*_OtHUDNy;>*^76P8b9|2nZTtN*sAs~rTHr#5c9=EQh6bW6YbL`hcU^EyYofntSQI2Mof6AHL+ zCLL)zSkt2hACzNX5Y_WuE0j}g)mz_S5AF=h@cN{=c*vt(W3PC{Xu5HT;$CO_22ouh zvU^_?jn%|=qKp8=c_r2I*18Jc?zVECIu~NK>LgX#jkxmm50J~T1G!vx+?-a<*Z))j zg!brt-QwQ{*mQ(*VKp@Kd4hI zDnl%CTA%DqGeqxlIl+@Px*3~=6GJT7kmHjIpL37YUa{c^ym5pwTTFOF31>sjg?-G= zc`Pr7dVlL(Jxl5v60qu$$%YI@b`~3!V2*D%K}2$i9j~@APttkH>6HaFnIjZPAo%xZ z!w-j4ZeG?9D-+{&l!5h4!oZhZcv0!j_<_}5r?$_~dcI*FTOMMLZ}B5Ej@LHas(u^E z7iB#lB(v^TMCg$0sWg3MOxt3>EN4P(2DViQA9kwpQB;KPRmRl& zWQYVGdW=g9Brmpiy({;w=M~%rah^{=>!!0;)AzaQz$OHeEurX7<&Q_TOfiaeW=s3; z2*35?$h9Lxj2Q#P^VQ>`6=fDlq4wfJT13}`qd39%oY~0SDaFn4XsEP_B>rST=%by zEu$?*Y(JTgqer|k@ngNb8tcSZ2Y9qKeL>sA)=a6`Qoo#p#Sx%=L7FT_58fs-S(7ojDjb!VD6R03ew-|>p-7p#G zQ({(kAVM-+rR?#?W0TJj1zDnf@X)}?8-D|%6tU&#eci_`laz67vM0UL#~OcUOPUaZM^wxY&{vJvll{knm(`A zJSXlqMKiVg|3W}3rV37Bd55n37#x`$pe?N(U13yiy=~R6_2X6J;Jb}Z{nsX)HtnO( z${z-2%o-1X*&ts0@;~L{ZLx&k=+}+drx_csjO%;TE4EjYn;>NQ^!*{fUzTNtqClX0 zsQL0CRPKk(kfsR%U!Jq$U8NDX!9o~R!$Zf*$`Bj9R2Nbo%Cn-B#Y@ZZM(hv8)s@RD z?IM#-gZ8GE3C-uO<)&O&QZwb@8l0908>MsMr|-Mn&q1Uu$f4$U;ZV6r!y)LNO3USu zGYrbaXGDe%8#{^HJHfDntkbTZE=JXa+Rx zA~rvL{oYDZQK%y`0ZaTqIXbupZ5||WSZ8zWI!gSXq@`z1nE8V^+fj->SR;eZVN-ZJ zF4~IV*>Y}>IERS0pt~pufV;r7e*%awF2>S{D0dNo8`3gk<5*%ybjZlRExR(*$1wf5 zKZFw6lv#Zj*Q$o92E#8>g9g{lg%+VOf`=q4F7kCuu+M+UkO;}387-zIIdV7v zqwonpLa>31A8fp0p=6@YaW1>ZWvKvSWlf;amP{#sXl*ecfF^9Eq+HoP9i z14b)=S$ZKgBGPb||J;6B=w?onZ-|OG5_$>tR;-9~l#>#EbcC2|J*^B>HP=-J5I1gWI7S zDRpZLLKUf?axiU0I4tdbTqjWIk&2>1^7sin0A9c-K*I+#mI74BJCK`Y#$YC~XlvNi z?XU3v?(H9`@#2r#qH#;fCT2(QB4~&9@TwYxDwz<~C%Ay4p?Q!rK*TG*|Am~e;ly8I zBY2poV-LnX>VtU=-#~8;>=0qL_MH;=b|UQC2y_^MU#R5%9L(E?!xVh*6gD-R$ml73 zPA~rW1Vc+KfFdIb%oGTj_x&ADOdU`Ywg0Ciq zN4_1%uBzr=k%GAkZO)1Lg1Kg$>(%hB<^pow-n+Nz!rIv|lT)Eq0o~8nBRAHRxfJcq zH@ww-3QYYTZ2=#!llT`eVx6(_a@GmHQ#`D}x-JEq51(%cD7R=@*2{Dpd{f+(e zpb0UJR0Le84eCD+Lk5)#I9d7SBQBtAH+hn~7zSvs&8w4%kM+10;Jp{u#rfCC?6{^W zXOUxGmoK^+r?fwc3BoJx1I!W~Rvb7y4h(a+d>fd2AOkOeix&{ecg9T)@YQZ$p zR(8o0v&}HE11JefB{7cxB|pR=A3M+K8l}&k5*WGMDn!deLLW!MTsa+!8H=Qb00wye zby&nv`y(HZ!GubttFQbkTJLiI@!9V$6r*95c7O(R`bi3ZOiMx0M@aFn6Nc@`wiW1v zlFP{6AgP|50r&F1tN!=B&lJD@`(D_C*_P>G;z-7v3VK8|LS|II?UD$Z$)hKz0Ox4guLg7+Kau)UKCl%+r-89(#9-&ue=)A{UKSjZ}drlKy>S$ez7YDzQy_Z`qp#5x2tu^O&K}X3=NEO)_4!(&0;QwjBABv6BIT zT|5rvE$VW5@JlEHZTUV90wZ6ioa+LcU?w9ulVqy%!>kSzSm6emOoAFLs(nf$)d9VuN<*UiQm+!fJ-W6ej|9z(;x`d8Ge` z&S7%@4)>T3w30$|4Zcoil~pl`GEzDFA*ibdci^)HTS-yX6x28NFvpC@A|KU{HZ>FWRcc4oQ?p4Vn8_Y+e6nx5S9B!#bZ02|Zsav=X1iuE#H*5w`Voyt}nuA1;x+av})~sAa)EDJU&)LLN8JS{ohp*Un9yd zG(#+YF8o&|D=S_uw+_Q8ZgvC{(Y>9quWLTgoZOz0tqx}jCSS1S0-FKmS5IAGpaJa&nqJRhB)N@=%Xr6r5BoVp06Ns29?0_Fc?fi99!V?^W zo;j1?rlEb*xwfyQeD+!Ig72<(jf=oW59hP={(+OD(tBSeoZVnR&V6k5&%Oa!zPx_7 zm&pAJLn5G6ispWPX9-6M2Q5i*c}5}ill3hA2f_`E)Dv4R#Kj}a;lp-5-ULvg;u~0( zQ+R@J7G8$!rer;eF-=1?SnZx>*|Mu49SfPq}Wg`MSn7dOnO;i5oq=f9XV*K|p ze1TzTJ4kk~PaA)|sV5LeT*u z2LI!@dNdXDYDS?65;c_A+8y)Y^N2OZKRRwbDK7;nlVbqHSc!N{io`*v0h)2r>f=}| z^wI?QMy{52W@l={SGBEUr$bqSsbwfec`GA%-d){Ob@-H%NBve=u%Yfh{#k|%Jzy*c z`}Zu=u`K{@_P_0fIl>WN^@i(nBr_q2`-SAYALtEB&V<4@Rl4TyH_1}JbZb3-v#E;1 zBj`$?b-lYZ^+$&BZC)?+f14$yPc#jC zl;UETWov4jj6eO8qniub*E7v&!3xS}j`t9EV@msp8!T8x_D@#2Y|n^FK%nu}N8xcB z+bxAqS8J(aK7hCMof5AdhwA+LjPAo^F%zlBo?8%A4Wu!2Zy-4S)BK9p#x4Hp9O+I+ zbI;)5`-eWDuKMeWK-!oSmFRlO|JrSLE&efX@cef* zsX3>qY+l!+ih)fAMF6~Uj0QeGg*)1-99p@(IY zYJ5(%X+XA|Dpg}J%@(*7>&06GEnXlcI- zzsoo+2_iMF1&Nms(fyjN&05Mw0Uzo!|4^?%WH;@_1;4O{R)9-lV2JpSrIIpL=xQ1T z1q8&)8Ht=v_gx+|n)Y^*S__%G!I0M0f;(-R(0FjA^5YKDvE=pHZhrsfuU~HjueY)_ zDol_|b?C0dJ^-Xa5&)iZPOvCu{~Q)OYz|)D-yBANRhfa$eNA;YL&W8HUw7}<%zbSr zCp~`zvI)mz7r@52{XwuII9I$?W~V5wzvW4^a!{6K$R9bIbSrP0QJs!qfss@s80d;G zW|F+2RckZP`f-#hCpY$|h#XAT^b$o=3aR|9Q|kA{quc$5>MJ$r>157()0qq3fO3;G z5)WF+Tu!5)^HEhtyIafXaMoOj`CK|$w@J!*5qa#W6_JcpFR8|QHp!**ZJ~M@sh-C^ z*WOIETq+lSlbT7;lx>)ac8)^ z;{2s57aEZm74`Fs<4=J(?vzXOHG9KU`~yI&pQZ9ZxSkqst=;x>y??M`VOjm@25dHT zp!)OYC+mGz;86U`j0{(Erw}W0ZtlsA^WyKg_%jYy@5KcDa^>RjJ<_q=wlagpJpc~f znL*D2%J!W42BCfAcgl$6sMiBb~N1ys2}9#tY0NO1Gnlu$J* zD{IZi0mts@#MJcOwWtTZNOx%C+>o&AjH9Y{Jq#{-^Je-dnQA>U3Q9XeSyNUIC#9PP zEAKO5Z;~S$$L%kDp7=Glg8UCfBel{+(MD@!?R^7Yc4`K2$$f3E&TZ}O$CKK&AYoy> zR7_mx7cR@m={Y^M*cE*`@k{U;^V`p*HkyHDZfBp zVL4&xe?zuo4AW+V%V7k!^-N4c5|<@Ac=Wp(L-K4$VOqk13jiK$$qsWbudL_xUq#<- z`q-AciFB3!*@LQ{Y8r)Hx}CW!dIja=WVK-Sx3__umR4QR7NDB9s9Gpl`sV^$*az8y z>4UY*4L%L!4~UK#BC<~3=E%h}_r@O*u;{&``2rte zwX`*o&0TA5x&e3%PYY1Obj)H}M;0$;cWi>})Tna$i31CIq&W{cu=4v{mZ>@M{sD10@YF&e+Y+_SlI? zm26v71L3vMR01W8EDPZ%KZs_Uxe6l{dKH90_Fl?b`7@KPWb05qb09Ol%%^PtL!BNm zl=g+9CpQ8H_i@l*K6k_2B7aVdqhkyo+MSrwQOhw0@p5ZHx8Xcxquc3*>}*Iv0-@75 zH!gI-uZ}rjyE?0fdLeLYo@ItK@g5Dr;uIW8q5I1gV_f3R2ij+THl6Bh2Q8=Mor-UU zexMUJH&=aw@6CE5AXzOHo+h&LrNpbW2~4OpMP`lQ<@ZRR``U6eTbq6S=^fhTa>qH;TA7@&8XLC)FZ zscvZQDY{33{DE5;C^kXMm5K}m{`~@iFYl635_M5h7q1b6x$oaC>=2BMPa&QGvTTM& zwv+P*N~Lnk|BE)SqzLJGu;T4Vl?(mEVjmn`2PMSuu8<}!nStFttxmlM~NI|ToVy79fUTO6` zR@<}EBa;*&q|F%-n6_&`B;4_VBEp&@i3!i8a?_)m8&mmIdaaxQ3mh42odloDiu+t^ z&%Mm?)4v%Rb|#>Ev)7+L%&mc_D~%{9@=(0-3-oZA?%L!;?%1HDb8%wSVR^oM`r}}I z<7i?+EWMD9+hr-(<6BCK&bjC(EZT}9fatxl4?!6YxnfZurYH>|&2QO_c(v?xY_39a z?^;0pjNj*rUtVNlSiNiMm=IxYpM}(GC;YVX(sh#7KkDvTx_1W8{r?BADt7sHf^uX( zEt2i#VtMPGy5~!MIQ5HL%%XFawpkZRis^1dU#HT}41M&raRV{gMPFn^XYe;AyXajd z&TaPRt33JNZ@8{Bger&*NE)&G77u;%KtGR=k)+1G$c(K+o_qC6{ILa^NW#7aV_B5f zik$Zrg?~0D+>-qyT&NMF&?Y;DZ@3Q1SmabQk^6@=M}L@o zMOh_7fcmoKWnu3rzR_X)#cCW@i*Xl(^aJSzV#~0!*qmhQw7CNy+WKMWfvi0sRpau7H*qzm%CBxrv>BP|39i*Pnj+5!Hp}E3YCx% z^|@4|B^9|mS}kG?d*)EL$B8xwD<1xal%zO) zh%Q0pfJ{R%AN%mq-?AJiee9mY%6bkq)^tML|`+ zw{)|)7N$*(EmTIS=18o*n;N$#?_<4d5m-pA$GdTP@H>W^p`hR-G>jZnIY_TvLY8$bvi9=S$|H+S zCI1B>Ec4h-`qg7Mlp~4Mqz}XsBxMSbk~(6j@58qvkRHwntFzxM^dpuVjfW#y2&1aj zk_Arp2Y3i~oQa|h?`C&SJ24_4PCbNVTKg&4_K2?y3Iectw)!W~isehfB*n%$1 z_29=7r_XxmI4kC3CY-j5`7D(g$r?dX{H-_rd%;D7`-V4jN3G1Kn)3cYS%d*}44%Lt zpuUlmT(3H-kvWb{7SDBNNy z`-9V(Em^?%(`Z+l+@`N$CQ~QkMe$P8%*(e73tBk_52&8(Hp~$Pi+&IsPVT0eXRR)Z z?0T$~A1tvfqf=X64Dlep3374Pnu(AOPMFEBv47tbb=a$O64{m1eOy+r)J$8Co$ue6kkfglYwK`Ddqc-*VUDzY}@fJ>CGzpe4ri1*?cl@D;4T#zE1teyMnm>-Y zs!$Jt$ylVN(@&m!c{Y=I2#F@-8;#*PG9dC9Cuu-(3+ah?^I`Gh566r_7>)NeKqyS( zP=);YReHHn2d3(ii^x^vd7}ih84`?qRT0gkiR^=kErL`yM?#0uFUM1wcbv$dP1Oz_FE!by3u)&iseB~OC(I%y^wDTbq64j=lA?i9C%@fL0|(hH*u zy&2Kk@{0TydUOelgNMM~#?eA(#Qb`uqt9+;nosp6{ZX zbOlxxXrz{lMATP5Bu!q`m-N^y-n;YhEJaJD(Z{6;-H@|ad~j$@Z-kDgXVbOpJ0W0t>~z$`2hgkT;W1T!Ns>RNxe6Z8S`${e)@t(d zLUKIO0lH6}p$}BEugm3umefiizIX4cSDS5Tz5o*SOkVZWVKJ+)lBRIX3S# zQaxl)+cSWHF7Zi&>GJaWyQL_-1dI%{6d7ffYS*3WvZBD{;%M>3Km_#t)H-y}pKN4| zsv_Vs`py@-?qc{))Oo_VIua%r^wbq#qNo*$M$BLw4-jiH4nnv)!QoHK)C<;)L%5xn zP%I=ePIZSshu^^47N>lb>VkffqVvaIO=qMU!jnJeP+Re~qEq?I$#M;1}P)m4ZOX`<01n$~h zfQeUbw}m~83S;6~TWbwvxGNe3-_nE*ynYG1Wf;YdZoD0NxSS|lOa5KqiKnG=N2SAH zf<9#}9u!094`v+G4M8$@Ctlxlxkz>nM>PXOEK@m{7!N9DwCHj8M90UA$MgQmD*1wr zNj$L0cVl1{#9Jp>9byH{b0Qum9Mo!{3bgH_OcB?3zQA!)SoiXeIsQ`YgMYi!rr(ie z(9+F7@CJvOEak(VmgkvKzNx3yV{VGvdGrc(AzKuC;sbzo6Jsz-Kc!XUYx77AD9{6 z%7aMxsbqACh!ANlqNdh2THL)3fvHP%B@?+GZDHbYF?U0wFB7EUF<~T?KJ8zcU!Hg? zxPfb$P)!9lW3!Fz91N(^^o*RcvTqc0t*Ny z`LB^w9?yPh?uitMPxQ_}(wKZXNsOrdPY_PBo1a z`|^bO@@}^{Ml*r#e%bfyR3OHwMYLBvjYfK>RYxcnSQR@=<~2?%zJb5`*$-eU;Mk-5 zU=$u8wnMN{CUwgZIp341rql6xxFZXDb*7(e92@-|m|sOetiE;pTn^MO|ENm;^Uk?& z;3gLLTgO5T6Bd_+Kk#B*?c+N3~n#wK;D=UUiy$Nh7-Fv`%R@Ltcf+G)qrjfs(xl4*Hzu zD#O>vOT?i6AtHmjowfb4JDN-YrCsZH-|01in{^n)tRlgeho<@$!7IP*BaL=`;UASv zk@=v&SpnLvR!~_f+aghc)9v0<(f+ZvI=&|S0n-z)E7W`4)EdVFT(hNCYPDh2?^%Tp zXg!?1;&sk`(r0h^lIyS{3hh7h%+wXRxc#KlPo9!n!Jn^>M3$On^h>Gd*6W+4G#}G ziS034!|2wC7b9n)EeD&6C)aU2qA$?o4*3>39jm|mJNeZwee)DD^=(fqjY{TMJi!uh zZsrS$`Kp@{=%VrmzfeT1JKV;i$wA!zcyRfYsV2;1Eis=PhBPy!m|3nx3P7uVXZ9-`&j4*X7?pl=0>Ubhk4=A>G=!fky zQXBl|>7PGw+Pp&%4L|IBXm&&qV<4}{U88el9mkLlVq#rT&#!)d?hW`T zA}C6y^Z-f-2nb3`mwG4w%yQ9`Dc<*% z4}-G?RAu-Mvl$GGnm^h(1oXe~pg;ThiQ`t;MyO}{N=VH2kfoEZ7n}GUjK)O%(?!ld zds-iUux3M8XCKIUsZL(?KbwZy8!`&|2KHul6Ac%r_4NTrRI|KqkKpCHGxKM|h?~iB zR~qWgJ$-9hE1EBtJ8;ijhg5U2Ar<9hJv73&)APh2)t^z6`Hrz^>1NQiR)dAqZup68 zNDKl4X?jQ&_Y3^l)T%I3XMM0cOSP%LvA*OgBYOXf9wYbY#A~Cuz=IaEV>&H8MyW4{ zc_~5hH!hBg#w6-7!ghMyN|RdkrkH;N3duzsY91s0K>?0$4fAIR@REc+;Qo>7ZRdQisa4cKlhUG` zyJ^*c;Ona)8vU~>4FEVydc7^Y2)ApZ>oBRKzw>idROQo-dmqc%@a?4;t1s3Limo3e&*Dv4zBY_iU`#L{;3Y69AAxfNnaYjI-*R-kF)Y ztdoc?<^hA)dL5i5F#1Tc!o5 zTAobYZB-^Eu{P%UMl!j*clnGnlj{$@*exZ4gkJB*PwbPyVl%?Ee9E7mHb0|NH$NWS zVrHH_pe!75ryO@(hsglH_-N9NZ!C4L9keP52AB~A02MaOf@lZsEhlUhfw_o~i*1dn z6+zgJo=2F|)x!gDl-^a3Xa8h@m>8niiC~x3MwRFZfaw z9ALSAg<P|Fo49VA# zUTut%MOG`?gWh|-qZnw_Vh+%pmwl|pK5Wj~W+_D19c;B5Sli5@oqEew#MMBTI48{B zhYbnkj&&%xxZ68V+;h>4zflNYFzmfv+`AT~ycTQXbuDCkHi6vc3k%9*xX!QIyBHc2 z5(2psN>y-sZ7aj$X^~UBfsA$eo}b!B&}^5g@)_SR(93A?+rNnv zUQh&F(0PDS08JWiu+RW7=-EswE5s(mtP`r_to;SuHA%p+ehz>Masa?@; zC}1_m>si3`VXIqM{M$^ISJlP)fwcq)CmRVZEkQs)z_u}8j&*xNg=@}%`%`>)a5c={ zGk*9oSZ#W*Kn&yxU^qz$!&cjaNxK&3QsVsNN}}{XqJ@-Keb&7n#}1E`+m8806oEc@ z%rLj%H{L|-@2p4Mf!QnDgB~8%SF&x+#i=)RcN5js)h!%C9ASX8#k*XK&q41=IkL_P z#|1U_FPoHDBno~$zGfTU(*C4X6tmxZkr`@xZp~ImbtV=>*==Ki)A#R)b^&_y& znB)|Gje~a`w3LDeoQ=Y`fiu@>O?FRlo-G?PUxGPJ2Qr>}z-o?nt!l(pf4iz+07IH4 ztPA8%S8H^r1^nP+bB)hoe|lIKzx6nK0#sgC#XGcztOe}Gt({u{%Zq`_Xud8WrVHVn6k^R&?-- z-7f&?iTlFzYDKrd*nlifK3aZ#q0=$8U(n83Ay2IW?&o7XRO|=0B=-SX)t6gx77rW< zGR|0>2d;WcPSPVLUl%a=U(++0Ak;fNDzKZGP`oB7RX@@~$Kjm-EQK)4zL#@mfF8bJ zUlEfZrT+)`RsR#xaX-%hJT?!XLPPgKUwBJ+_GfhQjj+?LcE;(lA&Fe{ZMBv->}DKL z*MWk=*d|7F$wiVKp=4d^v!W|ok%cideCt^LonV`7q~#(1b}vNUr*#1mB$u$7YfCg!kO8`aD{mN5fJHE_2T zs(+|?psc%#Nri@MsPkjK-i`LkmFN3k~`t{%y6IGS2u=?-B^&0o!`7O`YgENO%AqUt8MYa5Vo*Y zjGoD}4Ffl!JEj2t1U3gT_U45DbMxtIq(=R~pBK!MVE@wjRRNin&lBtLZg|KnfQynh zs%f(JRmwgWhaB*w0#pDSy;EU-L z5N2kIXn#Rb0+_KTO+_i%-*%l6_!#2|PLh$s&3oBANLF4odggTujAtD*qg;g2FHkK7 zGaA^IX@pAnYLQanpQR(qg~Er4#lS*d#+qnboFDVHfoKdOVH9+AX-T`kfGX_lG^1D> z>yS8cJSj##k+^G=JXgWq?hEmVJ@*U^h&MC-;6JuA&#{580>W?y6A3_mP)es`Q zxIMxg>p+x#7o&Q$Uxbp)=N+x(k?O2m{C?rs#08my=2tt+g7!;l2%9~sdpROW0k4NHmS7!e%a})UlaHh%BZWYkIgPLO8G&utpu(C1W71BrbFvW zC>4I*fJG4oRgi&WRRtq3Nu-E_e@gO7ByBl6$Zz5mtf<}(&uoJ88z%gMEdXGkg4?rqKmY_Na#c`S zt$X+7#HuUx?M%HkOEJ+umUBft5u2J({PDuRRx=wob-wW(3lCiAh^+n$R#i4u-1%35 z*XeG_pOq3?`-SapTg$DvvLt?M8Tfd>`BQJ2#9`mbOt_xa80G*;GJ>Hxtb!&pfXwG# zkL6}l9a=ABd#ruoDWS)}U2=wBfKxRmyn?Y{XBM?(09Ay~g}aU3+_s3OARYmAqc9qQ zJxV(c3+3lUascn*_BeS*GR0EPG8)YT;LGuPR(c>3VR9jS7kA9k^6>PBuT~HNe45(d z78@6S(If-8izy4%V)4DXn*to8m=~c~FN(ok{rQ!gwQyHBB^MLz2b(`YssT_`lOfgw z9FRb8oAl$O^&4Ukv`vo`*aNzmF<(9^%kIs`8OHkA$NYPXo7P}K)gW^zz~-qmduXJ< zBm|px?tvpO_($G7#eY_%$EoDz=^KW&k&&x`rbVQl7`0D~oyCU=|IA}4l)qVXG;A6E z%RRK?d`so!i!r1$NDIWk{>XnZxIP?Nuq^aLr+l|b=iFpoqOwfA>Ef2aY-Vp_ttte6z=IuY;ls^Lit~y8X{= zw4}v&h0DVJp;P^-Zhnzztzj({Gv$roV6U$VMApUQUY&yTYKtCge;9?+ngaC9-(J4l z13(?uu_$xR0mZ8ySD@YT0d^8=)fK8QBMom!s&hiH>kqKkrY=164h!dYQQR6zu|<(t zSQM&e0@@=4I6S~F0_1}zkSbQ8c{+m5fRv-CgVBjOI>D0=ItDf*^!T3Bq}cYcPj8`7 zxf*yZ!>eLP?EYRW+$jx1Is&%i564|kcdECqFT!P6u0P|vAT`AG&c z`&^e>arYC2smYNpFZby?)_gWP79VN2e{S? z`FWFZjFM!Mr{6y6Px@@wjk~D_bRr9$Dcf=PxsP0O!>~jEZruDGEhhRLUTZc5Rak`w zah{_yOikx{BX9oR>`jFRr5ziaxrK&h${^JSQgrixX2#wn@?rnWI|{YaP@8IQGJhulxHGFD0#?j5T@&x~Ir{Dh}!jmJXhxDh@^! zaF4HvIk#Irb_c&a0R-y@S2f3vM-7`_DPD`aFUaw{s*hJ)3wAF3o1-{C&6fgjfK*ij zvP)dNADa9(jRy4dCHy>5k(5>>+kPwk^pq`A;_-+TS;07hU@Z>}<~5TiW$;FjH%hu)yAnci$o z`($2!*vj_KPxX|k#VP+|hcacT13RLf3Zxwx7mPY^{&!GvhuLF*QXtN1hl1tZ>XJU+ za8F39;J(!MVYm-|=f0>%2p1J|nwOMO`y}4)RohX+QCHB1d-g(}rqa*|c1#?S$}*Y^ zVG$4%JOv_&^ZiaY%lbR`5k)!3q6E0dA0F@$QW-eE5AFda&5D!#b9JM3eLN2H%v_uJ zSXf!vLAN=2G^>b%pI-xfo^?y(^v=43WF>j|2W9;p)I>GA$Byv+IqDmv*;&!g?Y8XL zn(Fe4OhyTRk3SeSY!mZV@J-0QU6*vv%CUFQLZPkO+t5fxd)J~@?FzRj_%`t9IMnVOeFzFp8 z4PW)G4eCGPT9|7she^j4Ve$LKn!DPGXiD~(qZ6W@jVJ`Zz~xr3dbxi(7Uf=Tw%V0FLKSqhwW59g|NoBB_B1h55I?Xj!EYXUaiUvt;Q%;y>QKpgH}*>ZbB7xNTEq`a-XB@x3aIrY4mw$8P&CZ+BU>* zqMdKRXg~F5XW?+~ix0Q!i|!_at;00m+I^glydCr>*z8+bq4+&x=&4s=cma9IcThKMmup zd*VcbVI}<6R~o^F0kcxY3$6gd01CKKe^~MK;sDCB=E@`-4C8-`pQ26zefQ z0(S9Viv(INWD| zUJr~`t0`IeKRFZWC4o){f=m0;baWl;{@izFYM)poVlD{8?||ZpifBC9<;Nrr2dN;w z9cxN4M_J7!v+x|~gS`WM5;lDT)U{y{dEmh>*Nr+2MV2m*HUpG^Vh>h>U!~;{UfrE{vBMe3&fit zKFntC*@JyamdL~9+82){TVl4!|NG{y@OJuLLH@BAA8mTJ_o`>HQ+!|D@4XZWklmw> zJZyn6dXBPMGUnFxQ|z9;>LQr@tKfhBN$Tc3l4G=!5BKU9m(IW72^l8+i@4> z$PpN=yqIMm*N%Bhj%yt2eoI*?(gE3$*$2E&(V_)WF>SI{Ux^!yU;+gtZ@cPmrl$u` z&I^BGhkgiGNI9ZmG@CVy&~Fqdt)&N_F=qOu{#N{Juft4N$EH!StFNJ&3|Kfe3c!+UG z?1(i$>0|>3Lu)9*?qc7i!>OEx>Fw{jhq(MXk0vLgReJ{!Td%jbEDP=OM;<9BAU&9I z&^3icO(s`(+5>)8QL@zIDQ>-aZbhyDZgCBoCj>xPL7U8xk_|uPwBj*(EP2a9>M0 z+UTf4o~Oc*TwR)E=iCpOq7A0>obPHFxmm5FH*hMfHpcm$*`j-RSnN=e@S&lya1$&$upCiT=@{xq&AReZym%3c z%$72H*3<7%@@_G++)k4W*HO7iGr*;Y-Wfxu}^ zCDJe7rLz34;{73^4xuwz%9ZC|!W3WO5IU;;>~}4_PEu-AUHda`%VqBwGB?3Xgi6Vl z$L@toC?e*A=Er<`Sl1)dC{wMmdZ~0z{=u>(3UJwxhx>0UkX=L2yb+biBi`A1 z^G&+kWW_UU@u;8QA4&3iv$C2%ELbHu5;_16)5GBlsqT*!1c$VqOoH!A4$tnH1Vd zZ(ZwsW+KYNXm#7HZ!k!aod0JPa*h0B;}b3RBOfS$aFLj^&&(A(M=PwOl`E`O0quTkJO2T(d*vc zxE6=1g5Hi?h3|)cYLjuqmj@Dm7!-up?lsxjNq@Y4={YcWvl_xdL1u+ub|f%#t(xM& zvd%jg<$ojhVSS@-Ll_G`$PlyfGkfDjxRU&!i=O#&Fe|bch||N11wDh<*RJqrrB{I)@ zdCG}%r8y0UqSiaUe_$C&PS!VL<|(qHT{M1Vs`e=td7?L)NK+prW>egG*mhvuJe84l ze<=4P<7AS%bg4yPAsK3#P9=>t7z+A6R>!KOrSkAS3@4=z2ra(~zF$_nW|H^?UwLIT zAvi3&zr48UsPRB9$=%_HXESfZ8J$~$@$m}FtWWoele*nHm%i|PYHmWDH*U%zP@I+) zyKZi00z}bM@A|Cc|2ES9QMuhdra&HhDt|uJ33PXV!Mf7=3A~5P`l2dJWzt0z+S5g) zB3HRlTP4vJXFT(xQjoUi_}^RS_05Oj6;{A)npGSag}g zn&Ik$yc9fFx1LNG>>TfFbWjxfQZ5G>o<<s#l#+q|97czs*!Qb_c*TJw zI2B-xTP78kv#W>VoHr<`tb_Ej9qeRAe+bAkU`GLrk*br9SRAJ$Xw)=Y(5FU7@w3n9 zF=fY>u`56Pkfq480wxIn=6%A&AI*k3VL*|t_MqIciu)}6Awg};Qu*LlaGs?f;LN|V z(^CJa{4e^G^KBBsXHkA^tVImLDUE&~x1GZMB^mouP10)jMaQRxiA1JeE%ABKe#;2L z9X`?}KY96S>9iepugycNIg&P%fQr-KUMbe(6+1jEEF<8ICX}e4 z-V*!DNEGO@Rhade*$|LYgEF3?s}PWYIIPxnNL-{?L5_B3G8`gQ_`*^fd`+mMCa#1U=+<1Vi`ZCZJ1qLp9- zfH`(;c262yjfNhVyxDaHy{LkD%F`^|+@bH}a0iqSW*ZS(DdCjn8 zV3lfzAjzihdvVWrVKWN1mS)%L#&L}WUt!=r_A>X&_3I7HQu*sc!+5JvC5osiV)4$f z0*%+ICFO53)N#bhv?sgE!h&{+GCnDYXI0d#3?%l})}2i0T8!Nu5$LJUCG>xA!idbV zfe6I8l;3xnH1^IAnqNq9YF3v#4eHmnbUFiQ4>BtUrd6cmI44uTg1P+G*0lRtwmAD=Qc--X-ydAA*K#of;m<0UxlYVL6= zugRNk_%EmL+a>|P3}*y$pH~kYnnl*h8Ag(`1kjs0uEPr6mhs2CoL{+e<)hP7 z-NEVpl*=5NWS&3~kgchr1-enDaEsv1q0r4#AQ&<3(n7B+3Z1C-Oyn`K zcT`aCZY(zm)|oQwtBqSbeowgxdu>|#io;BIeWIG`RqZ5SEO%E$8Z#qZitF7tam0n# zjUMStL|3FPH@Pgq6={69d}=Ly;upVq{fZ&|5~i6O3cV8FLHp+ThRed|>ZhYLfJ+7z zd+iV^Fs({Dwv&#u%Jj2Mge!RH0PTC3% zc7vFnK9Wn%K7i(NtOLqO4k-YUMLrYV0(Ib-sep5LW2?M5lOGG&DhsI(P9Kk6#~!DY zf=L{%$WD!;9$T(latX*QPos3emcMK@E6jGZitfef%@Is5j zpW8w~i5sJ1#dMT%zJ<)$sDO%d16Dvm_+@)^y<>gv=s2$Ex4AJ<&3485K*!+1hjP~~>AOozr0Vycz12?rsY}&MM)fMb zoP#+iKD>e{y9{lL=su9s7gkhnd!Uk@&)EF*T>kh-z3NtO8U)niD8UJ?F@2ypL8-pR zq2|$NuX-+m)B3cJQxk(pjYRo6nl#yGo5a%Y{?8t~5Dm}Z$!YnAi+;g{ca=idG{*JT zSH_H#^&A!j#5|L+SuFA=QT6kC;MC>!hP@ zrw9MGh?WVt@ndgoY~Tw382LP)s2rXZ=oZWRRsf1z_Tl!STA-O9kCNpU!@eWF`C*zFL^Xl(kL;m-_O~_p*7TxCfc5_gQs_#;Fw4%gjc7v)z-hraL&;MVlkN!^rDp4u3cL$+5$kPFx6E{pdI$`ZIzF+ z2e)vok+;fYOYm#X#7HWE!pm6oL$~|11-a>sJL+nj8!l89Dv}C%_51Qm`^J_Xv2`!r zYhTwC^Z#u^CNiaX<3q+5H4)yk!)$53a|h;?l*HPYZcx!AwCV$AW0&@H?b{w*mQnv?l z>ez0x5NNVpyiSF%>bCX7C+?gv)jf2vA!4ZR?V!KNm6yJ>Dg18EONsu^7D@uuJI{Yb z&QmFiXBqzgQEn<0hY%ai?ZbWRhc-xUwcszLVCI!JxP$a zg6Xp40OhqNMWrOkLXMM{XU{w=ZSRwkRu4u}S8}!%BbknZa=g|;?j0;$?$P%5wPbD@ zs|_jpuuKotn<;`EkA7wcOPhmPS{`rty?(ORTN=WS0hTpX$lUcGNn{N%-bfgDOAKxMmCY}I#Awi$y z_VYGd<0*zI67ws6Wl6A5j!`~t2vwg9DF}40P+kl)9Fh$Dt)NmLb7zxbT*qq4@QncC z{CK(GGb72HwBGYCcIt`)(>jn8(rW6yV6%^4{!w^%^d$wPly)T7k0-&({k`+`$5?#!zw}Kl4zpBOwaTrw zmHe4gz4@y|psvI$XIt)RXVtTDR??ddfzx?E^EVDft_W7*@Sc1lSv+ifVi8;p1+Wxa zS=nEICTo|I$u!HnBEd!})&zSbb8!>zJYCS%$2CF3;tj+IXd!7b-?*9;!7pcg5=$(- z3NTwHF?kAS)|SO{)f+ybI}Zo#n+=e6nEZdiw+?h+32Tnuxy2d2&u;Mz^$#e-a0Xl< z)g*Vqpj=QCf35>3X#xRoxgN$<>nLW++KZ(zfOFi^IGmWi;*M=LPO>7@P1+g*h|(V@ z?6lsd06%+YV0F=j|U_Pp#U*wzA{*}%q^|l{8J79`CKT(Os%vm60c*L zh8JaQGoE;75w7mk$IM!aO&H*?c0AXsr)wH2drbv67)490)?Wh?%@cj54=lfLE<+uF zl#DA6O;)!?0gA$FG0pQ&6P4NLa(oUNbxO=Ty#MnI^A13Y&;uCWJ8;hG7T+f{f@uTB zeNfB`&@A_&1);R5Y1>;L)VzfAh!V~Sq<^DeK!8!`_PR`&@)z2`AFmfWQ)Z7=O7ysb z;v@3HfybSB;Z+De3X&j^d}QO?N1lZfZ}gy&AGBTpzAKSi^z~@jip6X*{W6y$z&M7@ z&9(C;pKP?pTaG7y076n9@}a)vUC~yGr|`kzzSrI3!@_rwZvXONKL#P`Kfp<~b7LEi zknTxA&~P&ucG2X-G{K^cMM_m=p1o6z{2^>|3)lr_^pwrc^9z{LUEn)sl>i-o6$*U? zvNE%NJtI&-2Fi7R5$>V)$N^Fb6x)5M$VbwDfS_&ZpTP*^JPg@Tm}lpJhZW4YV77!Y zb>Gm1D3FTig#;rnO#LUcO;U|Dp9QGplx>p7nk1ko!Hli}-(L7_W*K_s`Gr2~r(KRJ z9!>c;p#OT6Fnl$i5yieHC%X{oX?E@L-#g?Z+9LqWK7CSZqq=?UnaSUlEmHYAHwDuXANSjzz+U+Z=E~!jqA}Zu0svw5#;RxTXKsNhJ{NHqAhCF&F?dAL z*j3+0z8Y3-Z`_vu0;%7dhb&`9r&*~*VG991w@T|HbP%rL$94Njb3hIj18CZKTO>E0 za=5*iGBpLWnW%CHkkDSBS%XsP^~Dx)pklM3*wsKrYuRDo z4FspKF`yds1C%i^V2n)w(860KdypD{!y9I+PNcA@B%oUYre=StOA6L^gI3~@@>;<8 zamFiN>2KiCLC{_gGQ#8?p?t=pmq1^_?Zyb+g*GJ^_7w(Zm3=7v_4o_cL#2Q%C+fLi z(H77B&^7x}so!IcXml|U3|&?2Y@WqD)l1~T36saWv^(|0TavG|_F4-5F`Y`Y7K`Qz zEoI%u9#i`a7Y(OLkn`KdBqcrb&!D0TV9mY{{CfGb@g(s66pma79J?nLqL&iwxwqP) z^gC(FrERE!Ax0?xe~*1%Z?m+khnbnT`DoL(fWFRy#{G%Aim~p*P5XMoJ|@) zqji{^$0R$F{j|NthMWcMJdfrvISgPM#Spvp88w;eb!~`y(zeTq4+tM~fGhpW3CZb> zQqYaZ+o)|BcxM!l18GQR&`}Hn5y_Bk05pU-h=6tq>H~nLaOOqR{RpnuGFb!-qJ_R3 z6`{paF5B}~fg~Sj{cF#wVgO(ZvMVIOvjWU~n#*k=A7E-KTT<_9Zg!4zrcp~n)1WZ% za1Tgs{I&%=!0+Yd`g$MZ*0&oI|4pJWE(mKP#50D}Tirim>IUCkUQ8WtV;EroU?c#8 z0xFMPFR=TBnddLwz0Vggw=uw}+xvS6CjfM~;cGUqy4^@r$4c>_Cu38C?+7&~m2MeV zT^L9kF&5|r1~J+0p(wW-k6=;t>hJxZK2m1B!>I4sPwLO{2p>*`C%3oNx~b2<8S!qn zl(hc~2L6Q&xBtEyn-Q$0mP-vNOUu|reZhJu7bMo);A{wQa|J4_PAoPy{o^fM`Ae8= z)N_TOQvpTLF=*gDFr||%q@V5LLt|QZ^~EVujR5)9r-~*o0ILQQQ$T_Rn!aVA zTq2OpidgIv4XQt%bTEBj7rO@b22f;t?~eUwpv?;097lgU`o;u* zqizAt1+22q4b48Y1?sI-H@bxwv?)VINW%7BlEAJk;v!G*k=v{B4&7|$U2$G|lI}h6 z7%~P>X%?g-??==?g)>NLf^-^M>FD~K6b@+?>p@aWGP zZPd=ZFGNfKKj8;J>yQ9D8HBDo-J8T0e;Qm?2rygy ztlsv%?Kt5#7w5;ZMXCTR%o@gxuxgdKa`kGK=Z3;&mnfrfd|rk>!}PSfm$`!H4;dpE z{$bV2F5eo_8E#cmzddhXKo8qBWh*tGU$%&*-|Q>!T4~bj_lfVQAM+shSw#;`epgW^ zRB%))e#JYMD(3oa*mBByR<-8dDhF$7nBInU%J3{7_5O5A6T^AK*F2Y(QJT3Hx!$wizUG$DoR`m% zJ?`}pO-Xt@Vy-?dNng@5)?I7W1q;lOjr{er|9V0G*==T z)T=!?M~gkAnTXUBzpnPpWkvrqka?o#@AoIWA|4c}zxpSQdx5ZF${DzW*X3 zkI~0?d-%9&Uz_20z9l1npEVnQ#{M+ISjAPjKE?nv5-!5*oY^1?$p78It^{G0&x$do zbSP=u@?V<~R1a-|&j-+4unr-;S(2LNUwpnZjHsa+WsypN=~*oPZjbKm*$yt-V%C0^ zL;IlD&RJ*=Qpaw0vWbNBc)21YO5Ke=q{wtyD!StK-T4HkQ?8(xH0PYqv)LfiX z&=K7U6Nc68kB5pnu79EX>pd$16abns1UjO*BUHb`WYSTB4w=LwAI-xcW32G=gCn19 zOS$GKU#i%fw4b)ihAcP750`7pl34d_o$9l^S2Jesuy=d!uTAhxr#KDx043O7t@B^P zDlW<0aEIMs$vVKCz8CMqE~yOfXVMHRjhn~j2Xxv zNR%!k=F(iXwv;7}(C;}^Eb90AONaRbo`+%Zr>9G&L=X?R`)>o^4*1xC|7#}Vt1SE% z0+0*e4Tn_|eR^(1mIA518|LSGDl}hcZ-n`Kt!1wy^^UV7I9%`p;!A6d{_6;GOGFO8jy;f%Zhb5o)6`skw7Co`QcxjSb5S+8*JX!ETFwZ#-7V-u31xd})+!z2@mqK4%~ z1TXisCPoO0>K46QZg!JJ2F0hv0a9QZG0iewni?3Hcl)5bk>$@=7rD1~&QmIhx+03J zXU}!Gq$k7moK-{h28?t9CCtU^XeQ}3NG|<}O*Ek*j?yicjNCx7CRU`TD^51p_AFFA z=r@vUZD|`4VM4fA9(qm1E6SQqkkVJ}HqqA0u|$S;TE7$Yp*HkjD4K)-?dny`_K~yl zsRD_6C%S2A!eyZlpuVDFTxS;`)nfm7Kk^Iw_sm~tR&1;<#PYD9W!S_OM1&j&&1(Xh zgzWjx|21G~Gj?Xt*>GW8>s0A4Cy$X#BS~B}F_i_sXuuGXlN#HeVtL}^9WRoMbL3wu zNQcH{gV{~ZeZ?yw-&))Vx@d!)e+bpk>)?2*D|2cPQ`w(i1t4`jC*crs$xGsmB2Rbr zE|+Q2aahxszMzWe`CR9<*kYhxYfYxxaY9%!F+zPdT|V1>$|i~QMUOp~Ru6Kgj?|=V z@z3^pyhIa1m{s0rppqmyOA<5?pj@l-?|Gp=`TVN*0#5h17?`gNy zcEaixDlf*3-f{xbh7<#fCWIWH?g#7wlso2>Fw+dFt^w(tp;aO<-oLqHE`PCN)nuVc zRv1oE(m&F&92A>&NpY!MQ>v1uH-BqM z{$4-*s6#nHatH>s&;R|&dIOSJ z?oUj-^}`~7+KA)G5Sk^&m{d+uQobkitp0ZsQfH(jrN}|&ijsd+rYF0*4@Cxn9LHU| zPw|WFTM8;;3!0a8qbs<+U43=p+&Fag;=z7p7`tK*-p$& z4nt_xwq#4vHM^LPCva&Lw?7e)u@>GXiA;B8t?{iL)>ZyfuLl8w@*dSxmU=ub$Kt4} z!+&OLa=fca`(ME^i-;%h{?8et%55KJSR7X(?)b;;pT3u5Vs<%GSsI+D>4*>w2|FG8 zqyZ(myz=c)%NZF-oCsC7dllZShXKvcegm)Os)R~{xR9w3%CeL9d%S1UMZL4T!Vhzb zeS_tY5?9S$?kXtOKevfBSzghtpfZ~bAdo+iz+riHUm+=jQJO_GbKl6#Mbo6eCSX!F z@wo2$a#L1st-(Xbqq!JkZf_qj9kgL*$cOoh+C5*t%fypgYBf7U%-*d!*)La<{;*aF zT?;PhV*I39^%Q;3c~9K9qtI-+eXQj2<6zqmIr!V@LHpj z-5bL*5$}{EmKt}W8i~btF(do>1#g&{R33w6L_p6cVe1-|^-sUOYW2vMuN*hrVWQ*S z@Vyp5?>c1WNj!6ldMDAGT@fMc+EvdH%DZ=f8S(*~z6#YyW*SPf5Vc(O^bw)YbY_0>&5d$i$hOC4k4E%N)k^fCTxtZ)3n*J*_E_ zi+A0p_vGB?D8Z7ta%MiFB@o>7cn|V8gf~lk%AnyeSe#_^J|~c50|hjW@@PihDG#Pe z91w3nRf49X9^Hj9^OGTVUMzo@6<%hsq&{6>ghMRhT+E3$on{=yFR$OF5?Y^pV?8DD z#zXM3OXpZhEZ3B{(+{%GTAt9O;fE(@&VE5ipUYE4!+|o@iIyiHk@#UtkxKA}+y(QN z^NH8D+?^WHG)69ezP~!*FBE^+%G%(dELwX)%_V#i?1&pd&(Y^w|u6@ zMXNl7Qe-*GKG`-;sye-gnpyhSoKtCu_2F7yv8!b_rDQjhpaUx;qKB9IOFS9t>EiNcdW(}QQ5JajN& z=x#ls+}Oug)QFzpx*`jRC{DTsq&&LOt7bFs;C2G-V9BS}V~oW70zG<}B_{KT0XJ8}i6r)2PII{hP$+-Z|XE zL%IwtcCiQ-lNTRNyZQ9L9aBfGr3UMXhC+7M!`P>N*rcKKn54*wFl`9hrswcY6!4Rq z`^k=Xha{W&^Ur_YExn^`FQxX0;SP_9&>imjgZ*uk+IV3Z6i9npq5dqs7l>;InNr>P zl7MXg^^zEr>0Zm!XPR4vfU@bfsVw&pL#cu{-@G;Rvs~V8c@N7~)Z{b;WKtleKXz9r ze4(^kLTf_~N(qWu5VkXZ-BXvYRDedz2i3JG!q;bi8kMuPN(yu|Cn{>ugBi^a%JG<1 z;UnQeNL3yiG19l+tNk@`b0r(rlVAU|p-GN*U>R$y{}HDTkqiS#%J_q;53b0WqihOn zyZ<}Ew8J3C{N{^a$daf6Tkdu%o+hZ##&=P>tu}k^cjc?k@8d5;s1v?-uSty7=>~&= zLOs9!Jkcg4&D)b&y9H*deGQQo8QfFoPcb4VDToog=_j-D6fM0uO6ee=0rj(VeDtIr z|CyfCmC>vD?W|5yQ;d$#qy5Ona`pQ%r;~BVBh>FXu9F<{7R)() zFW`RLS!DWuk5=6t8Mdx-To%Lsy-BZT&>6UvHOj)YC0rQ);3JrYdSW;|UzTeJuvE1O zxV@Lm6^~Q8mH~?RzCDX+Mz^ml8m83^e$;L<#F_Hc_4oMR!8%z+A)mMJ5T_V*)Q+BM zc)7vmVUdN;{YVTIPAzhlgm{OeX)+=j$5|2%B)SSRElHq9`uhu-E1v_E8KpCKs1W(uu|U22e3~6J3J&j1FpV`ij+lWksi-J zP?%o6uDm*Re(Vt3jnZZH!0kp+l2$|3WMxrFF?$)>Pp~v>O%id0dXBzk7r{nVDVlOa z0dQ$+4IGpDK1$)t&BbqICZc>W453r!a{+|bpOxA-_%%-a5s7r=a@YN1H?*?4&Ay;@ zt#d^<(PoEq5S;26*zBuFwAz1_)wVW2b2$C_A$0ax^d$*mpTK;SFiV+uz&dR8#J%LB z_jf_B77J2`tmvkp@~fG>0`2CfoWCvWn;oQLy>yfGnCV%hdp(l};FcI|MqVYWJj*s5 zDg0+cR4g4Uw-+PvdYkKkG%)`e+rKA*Hl4xVbLF9RIniQexCG}143<+q6fzsnVTKZy z=1E7+Gy*qII}DNp+mmRt?)<8iaCpK}BidXbU0yiEt)7OL*1THIM+9Vm^LD^k)j>vq z&T4UMhZ5uLyM7EBQd?6?UcBjayA)@}e&o+{C1d_ITJ`=vqgAEt9r^Yl(#O)rq=b*W zK%aogdZs@i_+a)J?zJ)SsUpvT`{2qjGa`*IFPr?XpTu>kts~EW>Aj8Q2E~B(xq~g> z9XO47(5wvQnNLXsx|-RAaVK;eTKOPQlpv`kb0LdeBM&oq;{kyHy?(AfHIxWAt7)_1 zFx4}r#3dII4u@8ot-9>3j@VS1w^5n-eu^U1Ozr4+EXUcAA!$}bte!hwB!?V$N7Q^0 zaabM)ilC9lu+__})B}WPkr@r|-gTX}8b;iq#r+k+cdQ*tA7NC_zw0NY`PKW1A>Kp~ zTmk%c5Gt&en0oM9pnNUNbE>S%hkASe(p>l;lhpYS1w8wLY9OZ(&m`+~b9~$FEyT5K z$>nH_0iR$aQ1V^0xpCs7`##=9^Bwv$94?SoxC4!GD&z#=cOVUX&x&_{H-HJ093*5u zxRAo1Oc8yBDXII-znt9DvP*w%KC?7C=wA=M*3!;_AoG`1FGY7r?Ie1B(r~^qx=;6d zaq5hEO6~AEPD5VlisnT6xt>^8D5(LFqr+6(t?f z;$L6jq%UnNejxRkF41~lFX}Ppv(OS=!*^22&$gE<4D0=9DsEk^FX=JYps6YSISQR^x9 z_~umLEoNI*M!dQTdO?}08MoeQDF=>T=Ot-YmBc)wpz+|X-57T*LvU7 zp%?le!8i8DNl?=t?tIQ_AtLNr6-1Ka14J8l)i|`QWWpO!J})2@+tjN(RfoHIe;oF2 z;a7Oyjam};&wN$!RP21!noE{@9F*UDA++B55;Y{!uT-^pZ$Fn+p8R{_Yvt!}l+S~j zPwT!9<1Mpf4qZtyL8``1kd_$i9`g+E31waeqjd#{q80kT)0<^{ONFP@Un(hk`4+8f zI`qi+{D>V6^3Abx|tSLj(ESkBg0pvPOLjL!@@s&DT= z?U`_B+>%u<({@3e`QYF99(9d zw;%t1=z8m@DBtG|SS6JP>27III$b(cx=TtLL|};}lt!earIbcWmhNt(Yw6CVVQF|D z)X(qzzJI)&!#OOwXP-Ofo|${*nrmk1eHTmDZ>>aK9*(TdOwf_T*bXI+Y063Yk(lFt z$3#x)whgi7VHqvZ5NEwOuW=KU6p3sXmRavv8AbiB@DlQ6UiJHDyWwM1-ALNgCzzPhq`V*qixH4pTz0< zLZ=t^Gs72p$8$kh*^(vVn=^L~)sJT|hEiRMi{@AhH4AktkY4iYid| zLze!;QXDp|c9Y-VkY9Z(CrkI{r`(zBGQC0|zedG$Cvx2$I|Cv}xWsO=DK0%J=PAn@ zM7SbO{=mlb+cmpRx;$gjm4QSkFN{yy#!g@3ZAc{hNh_Ae1+T!N4PBCNcD*F@b#T8Mwbe?+1q;Eba_0 z1$_gBSj|58;nSEm=YbsmGZ$t9@E&>Zh_|O=-7JxhJoueFF7sZ6U{(xVaPeiYHL;1i z(D2!{-_8%+W6wOiDUvw}gRrNEF1p7&)oIkN`f~w4V%Gc}lAkWaN8E;vw`n|J-l~~k z!vM6)R_1a-s#~uYYOnh^JIsb{Q&ndMsh6T(t2PC3`RSju;6TQ?`gX05qWOIPhcwT~ zXW(h!)xjIylQS84|8*-Z0TO_Buyd*?>6z#erKc>f^g_Pn7=qk0<+4U#TXr^(I^uC( zQs9OEPR|UGawZcdWiH7w`HyUn(&43u2WefC1Zt#grK*0Ixk+DQao(;m#_!@Q9ARGj z0L0CFi}Rc$?$oar^SY_VP5`ZiS+D<*?GVs`IM0$U;j$Jm*65Q6@-G7w{&;w>2PQt^ zc^#~|Lx{f))j6*NPiGF|kRKw=h*A;F9bAYa{ z1pn#M%N|Bg%LXO~`fdlJ6u7laY{$uKVeh8UN?|8Q$+D}Zaq*zuo_Ie&N&|< z71~QA1GF>tNOk+kp<>stJ|QTa+rA=Ta#+~J1L+Zl3ndpN-Tmjf1Kow7HseCC5`W=~ zxaF|J@FJ2)^*4TmeGW_g#eE z9xS#1ST1xPIz6Tvq4fYEH2xgm>OQ>haNjf6412ynOTl%;iEid`)-_l{az`S6o{lOs zt~C2BcW*y$%!iqlVSmiS~qZ{rvc=dr4%m-E;n=5Nz{l7?i(g`-*PZ1(6dU! zOR$G6TLa*t86QrdzpcZc{c7a;ZZN!t*v8aXC5%6<9iS-{0+tgo_g z`hzjMp{J^oV98wDnG6{zrzQ4G_|Qer$~PZs(*ck@wTjvedg$E#E!yy|guwC)js#1* zK)UzCTOS{*$)Dku=p0-U#}w0*c7Y{#j;~6)ZWq`bzstVomb4jD0p@ueDFMp7#Nr08 z)^$)_ZRuyKa%Dt3_qF5MJ(GwXEITu%RE3usH(rVB@!1xOB3dtyPw|MfO3u+LT5Xma z5{$VJQ;zd@=#zcvrOTxvRSxRZCMNsEhI#5Dj~vCW)JnTP&kkoNA5D?^UgwMZCE^yz z++LpFOL*L{p1HQtrW-Hs`b(VufpGv}G!gZrd(fPhL4Tbez?k$qv~T^5MIgYx0F<@? z*Ivvgr!P;el}x{mJ-m8P4k&$-8|DVwt&%p)+6TP#PPp@T7LPN+3=8EV`>UVAkna?u76Pf_4RE=2H7+a&5SIJZU(#U66a${Ny#NT z22*H*_tIz6$lt;rp16Uxf`TD)0L$T>>3wE9;aa?C$_(R8T3hCsL_l$>aHhrRyN>%j zJMqmcp0)6$LE4`(Y_lU5O#R6%{7CIDfXv_@SjIi=l{` zv&~r|q7%78_o1F5YZ0crriZ*exnAj34OV1Ey2@z`C_cUUJ{p(-RIlUe=V3?Nv>1in zbWJXp%?~ya6TpCY;$ad)S}u@_l{0PPb|=Blz-b1Ydhb{~fUfeq{|P$!PzbLFZhyO-`Fbf=v=OzKvNXu@ zoi+i$x3vsb{lm0b754d_chfzcXwZ@4PyY4y-vr~gzX{kX7N|YY`1?P67A1i5Zdfvn z1ki@TfZCKtrKxJhr_C|I{BKC#y9XLHLQ?wK6ge&HrXi65W$ITyK1E`;PhyL z0=&86-hDn_eo%L1<3eO1_)d-NC{KP@_KCjKTr zffO+i41V?J1%M_3u(khhD+5#y;KGhA z`&p~ni2(E;qI~N_0WQ?W4d^^9G99Qp6xy4VsTG zSI#r^f%N2ktgPHyIxB0O#MN2Q3#g=+-nXPE7q1hBa5dI7@m#w!=1rQhR}$6~>$gl) z;jZOMS?wFYZ|S4deD{v2(s7}9{)2dgyj^tgUMK%xVXpo~*tBI1;Hj)U{$tg-5bFf-?F{)yaeW0Pjh}^G zw*hvnMizA|b#rpS(=osX)H{Mx$<9kFq4V3;M(KxMAx3>-t>2JAW8a%VpaJ9;5+2Fh z>k4nwn%EOI&&i>dyGxuu^|&mqNaFQ;lF_heoa>Jb8FiXkyp4^yv|g@_R_C^t)lYJtl9bH{)`wBP`*T3qys^p4<(c~Dx>2;7y`+^Bz_HAgQMkb** zz9sdl;rJr;t@w4;<_w)*e6;5-+sW?ZQvU#AZEv{~SJ){Ur&jLE0=nh^UbxU*0|3KI zO$&XEhSJi~LL&H{CZ5YUqP2B-BIN&^DEc~KT%c>^{L0FTKTzkZl)tvRns*kZZ9BSS zwYK4ps>~sy&A8JtuN&4;etj@)5BRwH;h;)%OmXgO+uNwjEqNnI}bQn1s|MIeeYHQQRGdsVLzqF zL+_4lu;^or6;s;EDt8%@L3<70>h6xyoWG`w=Gc#94aILD&GRA3^G2q|J0(yzcft0pw(3K`@^j*Fr1 zLyfCo?0y%r>(S*ruyoV#n1t6CN%+e(e(DvrN zdQVs21v$Xphlj4~g8##n{TklL%%lUA)oLoc4F3%|au|S9+ zv@W6gl!~JX2+R-OE#!mE)h2w$*a)&p%_K1=z{4|iH=v*C`KcK78@JB$sRI7u?F7W&9Y$%LCSSWx<1((kkElb#(jA4k8#}~f@(k40oKtyp{Mf}^$TpC#4mp8e zyFeyyrSBJ~9nZbY)E3DChj|bz{I0G_@+J=YgsJ>wv8SIVFt*@@RAJ?MhZLCE` zD0}%i;Z%N#)E47yyb!aK=i=%gX!&y6Qr&*VDk|g=+O}J#vwgPU%XKUY)Lv5nWts7P zw(r6m_cflH?i)Za{Q{>9MZl~A?NrCx$(lH&64y_$)+YTw#}m}#f9?y-qXnb%g_dKt z6%2~)A9z@h+774iB_3*47p>ow&M&PM5>_Daq)T=R#-f|j!S19JfgB38-GgIF($X48 zW8E~6u|0Pw6_~G77Qd->j6a<81vmq8CPHGWO;8-Y3-VxE+^0tf!_QYO)7}}<*S${W zKi|xZ#3d%q4Ug^MgN`qg!8BH$CV$F43QMa1ciJEg=pIQuBJ!fl9jhhXu-q#xj-CTD zd-aE%$_ZoZeFaquu5~iPYsiJ zRB;x(OQ5srGPDTheGLjz>V@itew{U1aEF}f!mY1Z?8kR8KaNjF!wc|x?%_duZd_ujkl};-Z1#Y4dh$#% zvvE{q4>Us@s-F91X(^bx6A-+Lh#e9@PXKfFy}d4YZk9n}3Ze41qXT{h37FktO@m;) zU#qmqog(!?mFUF~b_uJ38Yhc|_Y>_jGqp?zs73IafR*y|_F^Wq7spuCE`_3T+2K)r zA22?3T)`{OviMb;xx2N(K>Xu^4ydp)ruMg&!OXFG!a|^(31obH-&!23hHZLyK1%nH zq^0^QFJ^5kj*(Hz`DB4olzD%?rc7z#jSDlfy9e#BKIg<-ieiqKuiQn(>SG0y6#nZL zKgE7N51Q)a37X;~_&4l=Xr-|Fdiu`y?Yp}LHl1WZHJ1RsQoOWqVY-iAaMi*ss`JKP zGaR-vT)9h#S(?AzCuE74(Q2qqw&?XXs))$n?x&M0N7bka-q!Y{gRO7hY`6GDRi)&tO^vjEQ3}{^lbxent#m^f4N}2niH4iER z4wJOBrzk8l=5)rfU~R?=HB#bMF{$=+0)k61iw>}a`Xv~7q6~^(iSAXe_ykRjo3Ct9 zxajU>pKy0jz!-|u(8LUe_^!jtGcCGyhX8WfLeS3_eSV2C zrSNbEE0sZvM*Fp$Dxx3mmi49c?$7lMyqoB!+*PnAyRg>NC%OIsjI~A5fdn zNF@OH_-9lBg0Pj^OvLp5^fixuRe3j*h0od=FFZEzbl)J1rbOv|XabIKL;Vx$;zE0l z)Xt1tF8``(p9b97%fmOTwoN6?$@fQ%HBM?-nhY8K^%nxLSxFiWZ#4xU-qCKrw;aVjV zJ>4bBvg$L^?smc7Y4UoS>esNS*~H>NSvFBaU(-YT_rVoN{{*dUbr)C<-%99HX&d@I zC$8={VqrczkuVz%)880SQd46=fLIKZ+NIz5{d1KMYH5#koZF3pW6D2$^Zz#nrx)Eu zN8W!G-1HWo<6dcBM5KlKog8R6Xf1l@4Qlw8?Z;1Qqrt-PffGivlnD`w0%+rYM zL5WhmO384AyTdw$2R3EaUM!~Hw9Tu z*J8Em1<*9lU>GUh;k#c{wd``;eEh8-GhLC-dapf5OeZ-}Y8XRAVr>iH<(~&nY=p{4 z;!m2!di4ri@71AvB(T<{B&NphGou3;x%J9Aww^BE_$4{bqW%rxO%#KnZh4NgjeeB9 zg(56+O(L?ZFLFNENWfKUqi=d~gsr&swCbc2DYEI)U`|oTFs9`M^^ed04wLs0G|Wkq zu1kxwClEMHbj|T2>(4BD42u3fy+jrj#^n&ngAAi9WZ#uUhGCZ4qTU-MOHu%PiwPw) zS7%i0Z|1+~7}k?BOb$B*A!fO3=4YjdvHu=~=}@IGTs%BHkF+%dOm<76slM2}zp`ep z#_wPNZq{-(?YnK;_d>h>YHU;(G4VeIzF{f|qfd3iEDbjU-r+)p-5>5WOCh&MYSVW5 zx=#qo|9GPN;xWMqm0eSc$O+l0gEYys;NNs_P(9nANR^j2(m#QfVte+LdWZn=`KL!D zqrY7RiMe|C%Dborhj;i|cVNYQ`!K;s0x9^&{Zj<~Jw=;7frzw0qywDivzV=Q^Qd^{EbWRSXllXd zJoLkyEEah@WR7am)s4iI>(b-fhq<7mS)+MZ5ksHsHr%V`ZLHoEyhUo2Jy)6cgMg>r z^P9bMsVJ#ZQ91VRx8_3@59oC#T)$%EcC7Y((XzT?#I#g^>E$$#dbqo+IO%gJb`QyR zTVUSLMyMO;DwAE*#_iL8HC^^{^<&4Q)g-v4P9c_HFo=IEl;$dMBdzO2q*#R6PE~xq z7~2Hv@l?&qV~h1dZB&WyzM0ClhND^dW^G2hD*WK_j9NoiKA*dVDvRPe&r6Dn+M>AK4=!S=cYEH0-Uo7uK|7tOz%xCRI7e5lNetJ2=V z2jnc83ee%70U-dKBC!w%vmxHQWU zzlnRSvqhs{Ph>D&N+26a#&~x&8pPur%BY}-23xN9?iv<bj3H0u>gu1ngZYqc$uqNT4 zN;Cx`*Hk;((CkMxByN6oczS|QdBALL>-2oX}U6JWuE+nR(a&cu497m*QCy4?Exb ztEihLeR^QfVMCII`g(CRkdAU)tFiAUaei<^rAeABlT22W`wg@Je4v?x9Mitmr`d?& z0uN`LRNrD`*d?z1d&cgG;3+>gP^EY~k-=l=DQ)GVVpI`MDT=nAUCi>8*Ue)_q zw0RWuYXN|pO?khz)1bmkT{@W3^(##cxdbA-mfbLAOxfVRlDv@-y5+N=3Omhg8hvCU zI&SOftkAyujhE>j&NgFC@VCP=4V!7$3L-bazSj}I7)_l^2!|lK zc>;DRilsk%1Q?WEl%a4tQ3}={0|&Eaf*VA?E6CdPvTx^MxfPQyr5_XKQ~f8!lid@5 z6z@7Q6g(&i?wa1-&$6=*FwjEtx3dlLcHQ8dB5WiGmomVBcI?}Y{^X0G6kq-jWsgk!?;enCh2YjyK!=c*jP($6H?Y(vFjXYPryXCxJ&HUc>5$UZO1paX-2A~hE2asW0 z;^Nh>fDsdzH{D$KSxDNoB+)=t`$`fX1LOCDyBWD>|9ksnHR?Gq8(`-)k#JtLH-7y5 z8Xr3HsuG{sw=g7|8&oV<@k&820We-6CnV;59k_Mir4c$RjV?bs?~v5^ub&eWN&bwF zlEC#*M@I)RqW{k>^0nXYcBRMe)Z*U@V&weQ%NovTrG9+eB-0Xg-RY0c_amn3Zp@!K zO*}k3v)IlZY}8mU z+{5u#B8r(64Y-;Ynt)k_(9~t@RN9WBe!6{lKXWp3<%^Rh>=H;D-z42L?kHLWN_)1< z{e(mZKY&HDs-r8RtGko3vnyIrV)RVEaW!twRA8C-qJ+Q+DfT8YheV-gJU@cRS&pFE zVE^0w|3vctD+)@0q2jsnWPMHWK$AiY(^6X9e&@~EoOaG$ z-G=VUz~;`oTX-+Wp7?gat^NJnJq7 zX3hEpdRDB{1w2gd>&F00h|oDgLk7^0s)kGoL~8+&6VH=50Jn-LU#FO^f}Jp(uO&E%tAHF`*rRBVbGMM2M9bf zVe;>P0gJ!t5ntFuDd{GP4* zmXUQFSHlO;et_PKyI0L~&A=|UL)mko@VKNBtT75Yz<$|HzDdPm^eoaZzn`~sl;ON9 zxxf<^;O{~ZA}+zuXuY-t1Omq4S5m?yNiM)|FbVX~^7+sNtVnh3&iDZW!EaC{Q?}k~ zuMO<~%_V~EOuXrA0DV_Ynrd-0Fk-942vD4Ch0MyxE>!-t@!w}Q3nl9F| z8zbiP>ny8C)CnpVH026>0tX)io+X8(I_-w^9@8>2%iY$^spasO=mrN=yYH$+5E2my z*Y8Q#PSS4cWPw?_*onecc8X^{N?jqW6Id4pQbqcV+}dQ}^OaI{(ie#R1!F{QGQZhQ zZTK`}FEJ^p?s{zoe~}(iS<+5V3|bATx!k@;Sl*nFVyH@TNFJw2)aySh%J;!K+A)%e z+^@IFt;3og3>Y8G(w+E}41BmyjAcQrv&=MlO(79GumOBel@apN8UU@ivyQM(i`KGK z-RDG{IgH~^GjU%dB>wZQ2TGy=@!nJD7cjBW_*sOQY+mEG!2(=R4b69tLqvg|aIfr} zh5nw6kdSUdSK)g>6#!fY98+LWnvA+*1fqIM{mh(iftRkjrsh;Wl-{#iSN!Hy^btvJ z75*M_>J`|t#eaSI!4L27`qB1(#WC78@GnzU0ZzoLZU0_3`rcxHech;=W+Z>$I--gR z6_aPj!i}>ji7lIcfTzkhYoNEf8Np65{WX6qw1LofEiELka*6DZKVBhMkq$rn5lqzz zkgx?UwaF#q*X>;jkn!2{_=2xS9m6=E z^~UGYBaQeX(*YtI`qk(6Qm@$&BZiL`r{tw0a8*X4PYH|94i|hk?~K)tr=90|zVOc? z+3b?RTn_O;h@wjEj4NCSU|1Z;XSu&x!@2}Fl9e>Q~( zBgzq~ZBoj=NOAu5JkG$5I{~hvWRI#erIVoFl|uL{nY=@F^lC#TW`37 z#xXj_{e84V#waFe%@R%7nqK;)Y2)K2+3aZ>-*=6`-DqWm4v;oc7(Je94LK4|_#4-0F{-V2XPVMCQHAXLSv6J_YAU?fLipRCD+J=gg0o+amRaonq|^QE0IYXWTeghorYIVWky(2w z1|;yqke=Gza5>P^=k-wO+3~p#MA)FG{MgOg|KS{`%+zmcy4I~h9)_&_YZON@7s^&Y zAda+#vX5&2{-&*s+ckF&5k|+|xIsvAF6S|$5fWEo7+72aS>Iucdtq`)ZiqKg%cnQP zifNKy6j3a2)~2uSMmuUojlOES7u7fHz4~s~GDA_G2of42QTq`DK8+c1TTZB=YIQYf zIf&m7<=RKJa=vLJ;df;o*^Qy1>pW{GM7kR~Rb(*;oh;t|JgH4+6TWSscY|6Rw6#$` zfsRr4G{LQb^k)9sXT!AQlPD24bk2QowX1xxM6H$ZVw0e&5n*=B1fzLEfinn(x|>Dq z$)%fWZ)zBAf?HSjZ>Azuku0W^HYf|TJz)j29Jy1!*NFr-^=*}!+DXAbG0qy5XszdH z)>69^{d-)f_mz2(W){J6;LQz(nf#J=zKdPaesa(yEO0T4*G^vf3 zzU5mt&&88#amgzkyQYN*4i!td&rw`kFfd}qxPMrQ%x{r|)a7Qy6L3B?>C#qS?g?F* z9^8w@Xa1q=UreIA*GX)8xR`UW#f@(KJ25or#rQYzQ`;|I)%1^c1f=e^rYq};9_&c? zAP>HoFS&W8@enu@Fy1rXiMyn%SivQFkNDVg;vCx->O-@v&>B6D6kcJTH4A*tl76*4`oK_bFUk>C+S=hi zJeG@u>dn{2zwtXooX|MZi-ZzsCsX&&I7;5$bh)p>dZv}fzrW`}6*vV2gN#jrP8<7E zBJzzR+uM$8U*EjD;h9r+%L)22=**mRN6`=4^xa-{GzHhIW-gl&3!f zo`@JKjEW)R`_n!o9i^1((r-`geF(JA!R@~|vLo_(bt5)7Po>Txv2C$L^7Fb|j;LYh zyPsYfATF8mniM3L-5T(Qtfgx}l`fvBx1;@N_GrH)y|&I;7@ZOit;o;IDMEy-k8ZdK z&6OA#2e?3V#+9vAu&<&<+qCicO;Y!IZSl_48~9CAmnAP*s>RqbDp6Mvv7+2G8Zon8P<3g{Mdq7%+BXn(H-rqs~;L; zls&UNqLiW$kkQNB&`Zt6*p2A8do8H-&WAnLn7HHwTlNm>))^{P51k>3^xneII3m#$ zR@VOD-O>WqJP~FlBy832e33dOr*Sl|e-X2~==6)AM1P#`>i>Mz&gY3Z3yy3`m6naF zdw^>$u=j;F?|PuaRUqFXOdNtufSm#zuN*4_3^iPolfzW+>^bM@gb&f zGuWQS?goB47pXs5vCX3ePt%LY%IdWwmJr;9?l?7WGb`-?zC5(_A#n9}<6|8`>j%PB zPt@XBYT(-s6Dc$=u?k34?;22UvGzM6nJJqLT4-Wd9Ebno5V4!W0V>m!e! z$*S}XR3BF)3I6mdm=CC+_gq|$-ih7$EYPF76vJIEM~*ys=BNCgeD-8a+OFr;HiF;Wa<4l-4iw>P4C1`ztRq8WlCz#1Dxm4+ms>if5=Y;b zkivknEyTBGzBtrNAF!fY42wbttXwP*nYJPcEEf?j4-lI6*iQa9tG3?`Wb@=i9@YC& zePQHP>xnYI&p}n-d4RPQa@AE*#i6S5-koW_zJUH4@|c|10RkTP&x2VA{bhYNCxzFGxN$G)ehop}-mzx&|E)k~7~g53p@Q2izKilD4yQ zZ;Q^VN$Dr8sj1%unvD!mSrHge8;Q4AIghF*Rx`Hw=*yJq@E(C&Y)5g$kFF<9wi`*R zp5wjq82Bdo{e>RNxW92s-}}>#J4-qsvK{7aon-|VGo>)UxTasAdA3sxIj576+$% z4j2X)s9Ss896$PA(I!@|pnvVF$NSxK;sZKpSg~b@jd{^b;m_q5x3GzwQi1{#KRC1v zoS9FH_+8gldcDIuBs7Gh-B2dubEO{=sLTr*%_Yj$4!tfbVy@v zKMfeV%AwJkZD@UOp%9lNCiixtQcAG;kQs9e|6|mZZ)cC6IfdQ@r^A6`B<(18Q63ha z5JzlIOyjUcUd>s}hdLl$g#0AVL1~@|bALH^YruLM^tz7H=m9~ zEKjhclM^OBljp70L~*H9<0|u7hfGjHmQIuEaMLLQ`Bpq>$8s^|36*eTDOv)O9}O1{ z3bM~rhIXeqA9$XfF6y3kHf*}B19g`hQZ`i@BTCsefx znA5Bi=Yc9CBdPV~5d1lg^Wg_;#w(!%pAPD_Dedso{g0~VpDJ^F-FW6K>f>E4EW z$x&;sWoeF$+ew8PIdDFhWjibQ;H;MRm$mYj#0sonY=?GbsahJERiA4w=!2eMt>roL z>tUa6Ubx^_cH`Q@BR{xbb+-EofJ~zjB+ngJDEVsN)0VSjxVTVHEIT+KgjA<(vTT-$ zOGfb#HL_pTcjHSVy4~^DqlKfaV5d3%p~Y{OJRZAL6tg_kD|?Uq9j8_jbKiLOUN8J| zl{@kDW&(FG)7$(OJb7{oN^tAbb@*9NQ%8fXv`~%RQiNt&`N5Jkxov!-M>#E~&4DsP zqW!phnOqbmg#K{S`=jCViy%J_cXo!S39j`-XZ2!_o%yNc94sPLEso0x2HgT96-;20 zHDATdoQixgW>1&!rKM$;hC0)Es$(R+^^_D`9PP7}MLz9+xzNn-Ze3IzBQqsdEaFFI z;BU!X(vjvb!tFaNhJK9IwsJh?s7A=?_2@NOrEHf`iP?IwJA+(NOSRFDgRP@tQP#a9 zSs@FQlrsU^f z%D~jheF7!#1zYaKnpA^FeRSA6S=fzurX9 zLWbX#|D=Y~bc2^`aF?{qs9h);H6fhlH7|y^szb@#2|2sUIBtek%2tjh9^*eh<7nMK zZjD~rc}pa@e*d$=B`hKG(#7+n)Lpr#J_< zOa8Tz3kckE>$JJf6(9Qi6)(v|kFhS@PX=F}pmKESL9WOd|CtmE67bG0N%kAh0S*qe zK{OC8LWrwe^+A2ZHf{MNGJFL4ZLy0!bYr=62zB!X%RnOsER4Ha(;Ha?9s1hVNSb`1 zn8YIegeLoy)I#T{&Ep1ip^obX5^>64vjXptwl6*{RvF&ax8z+xV`n7f1hx=B4K4(lk0|yw-fhoDM3uVP<8fX3MS$tf=Ruj>G$j#A$R3kii~# z&h{YPp32V>cHYI5F&W0eF3Ttt_~IjfuWj1&{_ryd1BqX6m%(-I^KpCNdjHJW2cW1< zY#5j^W1$r=VUEA$#g>9pell*rJ-J?f@HV33&f!$5U_-0hF?_eb^iE3oj$4##KCiA` z7A)-3IEmwPcISs#q^>3G^OcKW%B_~jTz}#FOp;d9NA8R8{f(|;R}eV9p5yjlcNV8j z_DeImZNn*z@HubCVuyzyjbG@%eteTpRSc+7xr_O57cP|eLas=6l*#1P0yaA4R$!H?v}o4TT!e?)X_5^HiFo@aeOg4RHBQ2^G3yHg@TiIU13XN0Yjqc>QLz- zhHAw3ehS2+&g1mnH+2PlDpSB6Es$H{Bn1QNExg?0XgRZ9FI1LeGLqQ1iA&;VL=ee(EN?OM0lXpaa=0Jl z)Tw}@zK3weHBZL7YSLet+!lJq#-STp^D9@PHO-i#X+30!|7pujVV}@rl*BU~c}7qr zjQRT_-wufkgqeaHOzP^f4a}SW->6^iO zsWV#@*S8c)_S?;tH(lTKhPF(|G_A}icP*Z_oPAf%^gM6{0(~W*s>_O2=T2q?pFPi3 z3Ajfd*K1`O-s*Jw3(_BN=grWE{p?u0NsVHSH@v?Yg+qcH!?^Br!pxE`(Z*j?m!sb& z+BS3<2-rJx5nn(5g#_;Z?rsAh4fYj6fyO2DBB-#6XwqS&rdDQOok*&Q=&uKIckh7P zpFyJz1JmqkFu0_+ih7AHMvZBO^X?rG#>0aWw z&RqZ>_<-^0FY05asw&L3xLbkcQL|baeZ`j5y6d6ET9CWjiPe{h$wa5~3(>q7i*$HfnK$=of1TPD*|53&8>-H!!Y zO6Cf598*qKYsRU62XR&eR?_;f_mySGy#Q6N@Ijr|v7`wk>>rabuLJq8#;q5djf-ZG zG>7wZdDw-vk9Q%QM=dS;!-lnGvGIkO+NCR}?<8?`ndSq@x|0?&u15bu=Lqc1`Cm!WURo;krQM|Db$wp5px_U3dh?UEoh2? zR^WYr!JM0oA@B+jBl3fCe7MIQ*?EQUW835M_}6&gFPq2=4v>NPtU-R@g4X1$b2KX~*lF_O$MEi5 z#}8->)hjfKE_*Ehp_LbhzX|Na;qm^Z@&W=t%iAI5XULJie{0@NRM0~)v_-?TKyD^b zrwq{fY`#u47dc~3jFa|Dbxhtjp65$jwAG=&VtNUnXL^fEIIETwqf#TAsBmN!ckiUicP*L& zUOO7>&5qCsm2uNBJZNYdEwMEG=vq=9oQ??3{OoV{SQkzEEn-CM*TR~6zdJjoPj*w> zA`=i&1%A@H?&FN5I_%Hl;fy^J>V&DlKf=JiA$y-bRc~)C{1TbFd{c@Wy3_eXo50wG zqEh!(SMqZ9lNG?allF}=v;I@u^GZ{LL0n`P>JpAn)i+Tb6C3PYgwZ8s)~l}Q2;0bD zaa})u7L=n3hNmg>kuocH;b0#uru%Y)bg77qNtGBX);)cUhz%JyDyo{98RR2lD+g_<6 z)rG#{9;#G#P9W!`?$hZF`n1WzDJg=#5RhnmnIY4>o0ylv@WqDD3EGu?wY#=_-NFYg z&_?7$S94C`>{4GMD`Dq+e|ejn@Z^ozUB=nPfJ@H56KxnP> z1(g)}0w+oS8&5@fmWc^2w+S|ZZqAnCVZ)`F|C>~}BSb*D?T+04H*h7PSErKPxirF7 zMm)}V!xtUk(zg{T5yA<9Vt+J|#IMyV&FWabHQvhdKl(*pL4RT zXM>|WugKj=y}n^Jr_((Ij9NqCzq&$yrW<1-f z2G6z?M3wgGF9Gw=HT#JJ@TAofi^LVWr-ZS^q#g}<*Ps6a!HWseU@Q^~!QY#yNQi%U zo3%XkH@>WV*}O|IPCyTlFIAA#`q`tkaTF_Jz^Qa=qH~1(({(Rkg7H3t4FvKucHRR? z7~v9T2s>!j&!oDjf~&sXe<(|njn{tB-*cXJQ+N{%UP_hE(e%miTGovhfdI+t==0(f zMtgaqU=zR-`o_~u$b_Wa@)kR6hBvR<<4sgEI*^NDx}ov4#3&y8 zz=2xCi4gun(L@q&lfB9c-raYREkIjn$Cx8)l_=-a>ps@J>73)S(}fBvZ~5ER z#59_)?^$j6UxGM>8V%Kv&#PMI(jCgY!?GD{go9k-H*!9{vzlxqeRQLjIXQJIugxsR z?hZ{7Ju~`5j&}D*P91y!sthP!po-mCtt5eRYhKhq?O8sjMC6t@pzk-YTaizYa5$2O zo4ECrfRukaSBrNOHE}r|l5fsWk&DxsSj~vyo+5EdE$kz#nUzoMqByc|g3#8wYImao z^)fSr09$lZvK7f(Cm{RMibRk1K(--hauH?cD@lYOT#-7n_g-59UYXjqE2rCz;E5I7 zUv~F4aHpxXPA+sZUF}M~n6o=xAvEkT=$gd+DuAZY-WhoUr`f{0 z$^Rxh|7*4kRA9xQ>PO!G=mQR}{g2=uJ_pt?jFr1XIGZ~7+hY;!EEp@xbR)QiUTt}! zSAi-{_$KDB@HUWf8Kc?x`Wag?R(lNrlt;1Vlv(fh+mTn~5*E`cR>e-v3m)TYb&*3`i>nYJg6L#ovw^}3od$g$ zj?w8iz#>>aUcVM1RuX`>^oR~NJ^w#A*;C8rufE+zj1y8i_b8PHv0Zkm8JAft)8BS< zY^X37lWeo?CjVitO|{*P=}ZPw%woh&2yuM6R-+FV3xU3zo198r!mo8NOFoUOL-R=D z$dmkYxA)Gw0d*Df3do%XyTK7$>|NG7&x!QqG9fA=^%^@&fb0BQ8OavqpCxC0v-gbA z%Zd%}9mEgt0oP+GW{=PC{$dY9J_1n0AROUp-)h=H`P=f>hbmdnF`e@hVwUDz>$$ zq7BuP_#-6G)*l|&ULn8RQ9jpZlb6>Qz;>&^`hWWR>bR!6zx`W9K|xxPF1bM^L~cP^ zT9`5cB^)6oN;mM>9ZRNS9L5lT9WaPGTF)bI{xG_xF4Lc=p#`=st1I z`@HL1*L75%gzizVC3gtHkNwl+`>EY;u!+8n-glxT9nXPmbMq4hHD2q<7Bx1h4OJztp^Vv_hhF&56i%GkfIM6Bz@Yjb-D{wW z5ONR$^s3>WiNgN?ezPCgL6%IOTX=mmY)WMm_RhR~v?a|(1JDwMy)Knu&Ni?_)DX+8 zuj~DrI;r%RW{q-0?RsQAML=CPs8IqiyQM!u0A{zbT{}DEpCcT3Uk|)+j)*o=Z#dd- z4rP`qlkGVIR3Dqa&B>V)Fp+u06an{NI`tm_NlRRrO$pj4*6x~0jo-@IJlAKtg=*-X zD+dwMszJGzgtJ;- z$!5N{Ir#;mb$YIy(#s49Ntu2G(0v~2OiUv}o)hgMUlW{)B4z+;K=KlaVK-L8?!5hP zWY70*o`TVdgtTzqQbl{fy)gC4?eVD40&-d5Cq+cjM&%}8+J24c85ann?~O6TiA9Yg zMnSO~xthln{VzZW-~+0`?2`Gm%m1O8IC=nnU9yNSqXR1c-fw(H{;z%XqwF=WBzC_D zB|5L*dNUW;{Oh*8|APoqI6F3rojmF9Uhp0DU5SiQYy;VmAAy>8M77F{)bGO2%_i7QwOp1+73*0 zLXuxDsE20SxAMJPVm(^;vpuo~0g4X&<4eySUjck>{1$t5z?yyP!GDpBFCLsGM=zgB z?{K&J#49D~nrkYRYuS_6|9x%_M}ygx;)=(Asqc&su94pk__kgJJ>0OO@l3Lpik0wynuy%DqL0Q2c+vACJ&Ww0-X&O6?Jh9=0I zN!$~3;nrXNdiq~@23I*x#lB;~Ii%4{M|!FBmZR+$q(>J70-?EY5B7F1FU@f|q+eH4$~k z|JPRAAv>IGAO3y^M`J(1?v9aW(Q=}0N#OJ8zM$~zKFikVhM&9t?;Xvq!Js=1l7uvu-DFoFc*xH? z)7a10GN*U>zGXZ8(1F7q&4sN!t85V!_-S%PH3dI?b!X7EP1I5TIU}bphoAT{{@TO&8)h+1ngl|U^POArn}^#p@hJ~ZS0KNA zA3IaisL1`!J=l7C4Eo;nJ#UGZ9c^0=;{VvvYA2r)Z)3T`k?GcH?tz>WZxhzC{9J2J zLt6B6Zw;TJO=db=Zhg%2l^yC`$&8>Uc7%oc4_p#qrQ8WcZPE}oUICzXXpCn}X% z0=Bhg9Uk9)_jAYg*yL-zZDWP(lgAN01u&(H)V)DdVOTBHpx+9#>`8NP?T6`{1xl~p z^|td>eD%$#ag28LCI8(Sc-Zom4g0ZXS!9LvO_i!@PZj1d*ElskT(CnUW@?<8I~bl& zTF{;P%BT6x&tZY>L>;oVsf_P)uG~}K3y(XpkDfl5Qf`^%C>y#}ZljW0&}JA&SYEw% zU18$8Cvg6Mmc4>gi?VOd_|i-{K%_`s+Ht!jY<~C3t3zErP&2s%IM~SFkr${ZRT{rF zd+B$)dR^*!*;*4Ns~QedsBiNcQaLRv2`gWqz}FU&$0WDXbRXaAH#%DZp%+nco_BZu zn0OtV4+-CrKCNbai}5(}Eupz!jhyv9fe*_&r7Y*j&~2MLBEk2mlv+vI>o_=7mI0Lp zvt($pof|*Q$n(9BX5pmozcTP}^Ie8~Pvb)#9$GMX#rU5un+qlq2yHc= zJeB_(Ho9h%dZNd6p96GDiB_8ngFzfpKcHO2$Fyu*K`E;fhZkA&U#Vl7{Odk7sBiN^ z;H_=BSV)S(=t&SW{u|)zx^Xn%{I(;o_a+s{3-Hiv4!<5K{Y87=&rYhmnAU9YsbiRI zs6EwnNE;n|iaDkpr!D`CrooX}V38yByT9=Y0Tbo)LKZO~NF-f-fHOE}p8=U@pCrAh)e)NvdbBDWml75Vx z%9p#^l`9wM0C?vKe_nBbUVZ7ZMhWKCy=N37ylA{uT7Vrj~U&UrTd8s`4b^j82Bqk?+ zBkc2yM6-uQQi1INy8{p>zhi#OQ5tFrqI}uXm^$n}`7_JL;K5a1jK!r(JLmq5^rnLK z590Yq174zUo2cF~v&eGUtr_YfN|gej~w!R&sIS2}~oU zKpSS%Yct2`pYKK&R|q(@g$8XL6N694I%tXHS-Rg<5x{1j`O`nrk*Kcf%0&KIa<|TZ zdmh!;Ms58soVTT1VeiIXGKyTRn016?9b}zzI%dCG|8F9dCS)!9DVP_)c@dSrah~0= zd1qB-7Zgu}blcxCnpvxI*?+~By6RXVJzzZPPXA8Vf77h(qvb#}qJ+sgNz(W8S^iL~4Ug6{%$_M>=X#R+(34r9&#sz{E?i(SF6}?x_Sp)hkOlam! z6_X1)lclT^ALm zx%SlZk@A(ol+UkObE3Pz+0WGg+w2wwn6AwRWqli9bXzyegpFQp4f3Fqe8c> zV}CHZlU&>QJ7beQuj_Pv(X`2Jg57|7fJ$}#J%T#@*H2B*lI?$aj=1e{s=cFw+~sQM zz2n+G=V*|fx;~~=+r`U$5QG5Q&dAxL96KZ=pZsjsCYpCe@yQjC7y$|lB4)4V5lyD_ z&-|_>P&r+&!7iRi!{fq_wrJh{P-5fs?LKlj2cksTdw&xf4_^ozLG~Mz^*H(U$GXy3 z-aReK0@l3bQPH^(rXnrN3(`N9CI*@_U4j`dTMmV)0e$2_@Vo*5y4+&A8&-|#m=T5N3(tL?{>T)4J+Bi<5vS@MLu z^{ShK#_xjcsLLwgauQghTWwVcwQb^q2R5sEzYKI`5(Q0H>e(2pfm;+ms6O+ka#>5x zhzE$iZ@{>xIlX8#CBikHYV!~bG11t!TbZq#oH5bNE4$wwY*jCX^U^<3Q{^Yj(>L2H zp?-etQGIX2t5iG6fZ92D=}!oF9k`Y(KXYxX%8TA={Ck_;#3*w!8W5xaogr~OIuLVyk2TQaeZQPdJIlpf^+ za)4>+K`f0(Y~kUox+3 zf3x`Mv`v?I?kzZW8#0YubaO0AJL}O z%Z)1^oxPpAo+Mu=+9lnI48-oewfbrGefmovBslYp1$0khG-8h%C^CKD`RO#t-pJ$0 zZtZIvfh-sum*F<9v9R75R zqCQIV)=n8F7L$GxAm=;N0scRoTOlWs@mP6X;MUx&3e<~Gx3mKLqZP39#x6~7RN)ag z^ z9~g)03_n~9EPA`0;j?hZ!#55cBCQki!H)m$#zTRFFUyzz*(i!0c!vvi8aDu}1=6u- z5rNDPGd6%@;UzpI-T5opp!pCnjWzH7ZLL-~*z}M7B8BaHc@*<^{Xp9^Nvl$E^DP(Wu?=5MbfNeV|CQ0}iAAIsd-hON(!-rjgnYAW9Tg`_+Q>$FE*=Mz3 ziuZjzoQCJHCPw+O@XAv$-#+k$eK5`MHSLkF=mZ=M|!h;1da*@xTTq#{w#ku ztf2z4Cj>3LXmNlf1eCufzse*Xrrwk5N;GXyV$!>F9-{!{r=vRXUvw?;J9H_%R|Yk? zDsA8|S!I~#{E-iFJjWrSc}<#XM|6r^ZEbuDaI=bCeOSO~1DXdgsyM(t1TT4FIf{cE zneDe^yhjq?=cyl3d65>}DxN84wX?Z+3j+D#Q^)}T3iS%1BIyn|BXPl;lIG;J&(j9V zjGtTH@|R&4-cqw~@ec#u zgUHr_gQ2@yh~RINZ1XDaF=)FL?Yr|4bxa@eTElm-CtWci%`I?3xr@EPd1#oH7eUr3 z0ECv^<)Ry{!ESYLj-)S!LX#r2*m4fR3OPzpleLG(B{o<+TfAy%YOf-`j9o ztW_**>D`?EQ&F@;da$ycM9bvQ$2RP$_P^Tr-njJS#>ZkUS(VRw<2^$5K16KSuWod3 z)tP#yp4WQVxuOitR2Ge!+qK zrOXrA*>HuOv(h#GE242bqL<*ezXs%n#mZo5t12bEYZlF^n1p}R6`v>2NIqOv3sDXPF}pv7%8 zCtY53%T`pM>C?2>u#6qGSBr~y2f6;2;lB{5k|sJ@Z+*kZ;UBuncbzv(>uG5^Ppsia z%0KTto!r))vydrxz_0uW>Q})V@s+!jD@UTcQ6O~JUn_*se$nT8ikwk#S`}(Q%A%hy zQ||8{bTO~9d}z?*d=8tuZda{yE9P-eX)2gxK@05l236=vtHDd3R%AeqW2N zig&Iv1#b6oM+m0w=$Dkv;su*um($HnnJJ)u2!aXLb9w~S59YY8{$8SBBQmN*sI>3w2RHGAH%D*t4h?Wu_~W5Imw*ND!LPJPjHe5#Jy<@fzAtsPFB zoIDw_kSQERr{MJDKL7Xhnpk?>sbpM)hj2I@9a)6@}YC8|nrW?QT zgjT9u`|y(sF)9BZ9sXS2usb0V?YMWK4kHR~HwD6HB^`)PbpcO=ha464toCi0-Yy|R zxBqs$k!rob4fyf62n98`!;(o`ir7D!h8G_ZZd;aT$Xt;&lPxsGzhf>aA&LGds-{dd z8|V;ygX0_<2kTklaT1*d;Bxai7e9r|TQ8)Fi?qDW7FCk~9f}vZ^Bi6TKwCH&gad8% z9ui4$ZI@Q(Q&5`6%E|Jt!PUZOqhvmKQ#Ga8+-+)>H!2lPQV;E%?oWQM2BjJYJt)oK zlZb@*ZCq2d$QaTRQME3Wlw6=m*dC_7PY8i*Z|fbvL=^>;CC;pI5ktz8_)3b1q1RWx z_g_E=FhcvJ$umuYDX|cI+#&86Ii+0q(Cl(=>HRo zV}g*k9x(WkDF=UO(ezg>;MmQlH#%)X$Qye_QOvheZmVdTo=9@W%`sTzwU}6%GMLRHi}vb zkXjfsXNytp`(rIQ#sXZE(7M9IRNgjfGpk(%o7LyLu@RZMk&*gQ<7wCVPxboBg}O<_ z#bdN)@XJ%u^Tj!w%b2xyz& z4e`Cb;+iYXl|km3F8r@EH_kTBBp;tuhwqqw%`ly@J;&)Ku*G~V8RPyi?nBg%j)`tG zuJ7Ess~{G0ab$FNUV=n?+CM3UP7~>NY@T*92}+|G%cQW^$Y1#!(AK4(CLx6R>xpnb zyBDErD@95p$b9$*SMr%pLAVUDbhWyiWlo7;EC!)5aB}7Z7&tEwAf)$9ql1ETks~SeknEMVs=z zP+t4q#Sz)P*3p-+7xq6ivdNpS3PpS|BR{E5+Kem_#-lwP_47Cpfv0<1#DdImN!m?^d>7$vHd;8GND!mD>;BYeWq%o%3Hnr3Z}W@{;g(6&N}B~mjESP&Xf7P-`*-h6zj za3p*)jmoCCCX1+8NeZY?Og&$iQJKHn{U*+R^AQDK+C|5#d3CUiv023O7Q46pn_a2tYlh7R_~6JZNt1LhQ5RZB<-Zp zaBD2&5<|O)E+RU`*QgDo--PEh zH2(5Y>v(_FPrhJe9j<~K{xtHA$s>k-tlFeLPmpD^EW!x4=rXY`BkE_7s#GaEX{3w3 zJ2(zftFYQaoiXhDM#GAHT}N6gQuxEEAM&yt=5D~8QpVlef{zhS+(JUP8P#{|S$ET^ z)qpmJ4#=I+fj8?7a|GoZyU3LyOcxV>gqE&{|GbNbt^4mZcf+lRSx}+OuWGMS!i{0X zq}ZhgUsii#8uqc!F6{ja81S9E^uStpaML=tIerDDLaQV>%WyTwb+*_xuz)&TJ{RHDC zJQ*STY;=I-n6G_{ESSJBf#ea&=xzC&y)1J)Y%6kyBU4$`ZO4Ozrvo?uDN{p6hcn9v zpbIx%!Ph>(V!4PR+0iL7ZH5i#gGulj3iVd&|GwK-KZ)5enBCRwSX32yIYLpu5ci6G z7RVbRVU$!n?h84U$N~ax6q%bzooHT_^1>c&;XY;CID(4}c2o4^4A*D|mzseGCP+Gi#hUa(3h4v;1W$M@t+*(Fi@&=vaMn?Vc>I7~8hn+H6?S^+b zHLji=#%0ulhl;-{xWsM^_4%PuYrSBL@_)Xgr3O76b}f+;A*_7gk3o&t)~hp~MU=(4 zmlz=G#VaY7C*1|8*^k^!(3NAs8S{_v6TaaeBB#Yx8|^3D6E8Q%Vdg#Xo=_k9Xifw@ zB~^X|+`0=_l!&xLH4yh~7Qm&H^yYZf`lm4)?>{KQkgJMDWbT4-;Pi@^4;B$ol+@B0 zq+M|N{2DS3Gbul0G!|DgIEaa>r`9Lf9of8H#kxvJ#{44E4pufP|2+DaAJn4CTCEBfoX? zVR1z$AXllR$&~?C@q9p^pfhU$O-)${6W4JmRWH2bO+h7sZ*SpU5rZ__7!{aupT3?5tVKGjRJ{T85d-{Op5+W{W_-wQ0)5kvJZ}47CipH?|shS z5oPZkV`hQ*j7Y$q-`(H73&t0?(6}>UF)?=f$G@{ORdngj7Ac48Fl#0Cw7otznpWGu zmskW`dg%2UsXIbJX|-paXKFCQqhWnX5WGCh(eSuEQUY>dX2ty&2`zpjhWojQ5V*1xct+ zQ!O_V>KM$2?ww@8UI|&P0Xyc*Z5!6WSw^cZ&fokhK5~;lBe=S4=%>l_`T>M-w+tgJ zF5#z$gi-|y1bm^Whx|Q?8=w%LMQzP^n(Oew}@5ufa)S70iu^HzO(4q=FOOs+`d z)VfkZab7XVV5bOn+wkszxcQgYC>nb{&hk5H($peY+f~`GPf)rVE6@FN&@Bn8}Q(FZoGR!oPA{9|H`Mndj94fJq#-D%xRl`VjftY%nlEQySfwE ziF0+wGqsWWWy<@*WU>STn3g>!3m2;7#C82_R^JRWoKg31Ts~LG%W8aE8zhoCP#-B2 zi1PXY3qffY4|f|cc8-JM|1vh4m|#K2;+r! zZATd1v^{tOE<-54q-4FK{dZlG?aCY4nbl9%$ulx@=Qm`nOK%upFnb4g@K#x5| zwAEGa9kn)oeG2`4?RbJV!qI2s@gG^4qkqiTJkmh<&*wVFZ&{wB(ijxSgTMEJe*aMK c?5REF<6Lmg*+pd*aFf5ZHFVWWR3G~N57v3 - - - Experiment = {} - - '''.format(self.experiment_name) - self.outfile.write(header) - - def _print_footer(self): - self.outfile.write(''' -''') - - def _print_table_header(self, table_name): - table_hdr = '''

{}

- - '''.format(table_name) - self.outfile.write(table_hdr) - - def _print_table_footer(self): - table_ftr = ''' -
''' - self.outfile.write(table_ftr) - - def _print_table_guts(self, img_fn, descr): - table = ''' -

{descr}

-

- '''.format(img_fn=img_fn, descr=descr) - self.outfile.write(table) - - def add_table(self, img_label_pairs, table_heading=''): - """ - :img_label_pairs: A list of pairs of [img,label] - """ - self.items.append([img_label_pairs, table_heading]) - - def _write_table(self, table, heading): - img, _descr = table[0] - self._print_table_header(heading) - for img, descr in table: - self._print_table_guts(img, descr) - self._print_table_footer() - - def write_page(self): - self._print_header() - - for table, heading in self.items: - self._write_table(table, heading) - - self._print_footer() - - def _print_page_start(self): - page_start = ''' - - -Experiment = EXP_NAME - - -''' - self.outfile.write(page_start) - - def _print_table_start(self, caption, hdr): - self.outfile.write(''' - - '''.format(caption)) - for hdr_col in hdr: - self.outfile.write(' '.format(hdr_col)) - self.outfile.write(' ') - - def _print_table_row(self, row): - self.outfile.write(' ') - for i in row: - self.outfile.write(' '.format(i)) - # Create Links - fp_link = 'false positive Top N'.format(row[ - 1]) - fn_link = 'false_negative Top N'.format(row[ - 1]) - self.outfile.write(' '.format(fp_link)) - self.outfile.write(' '.format(fn_link)) - self.outfile.write(' ') - - def _print_table_end(self): - self.outfile.write('
{}
{}
{}{}{}
') - - def _print_page_end(self): - self.outfile.write(''' - -''') - - def create_main(self, iu, hist): - self._print_page_start() - #_print_table_style() - # Calculate all of the terms: - iu_false_positive = hist.sum(axis=1) - np.diag(hist) - iu_false_negative = hist.sum(axis=0) - np.diag(hist) - iu_true_positive = np.diag(hist) - - hdr = ("Class ID", "Class", "IoU", "Sota-IU", "TP", - "FP", "FN", "precision", "recall", "", "") - self._print_table_start("Mean IoU Results", hdr) - for iu_score, index in iu: - class_name = id2cat[index] - iu_string = '{:5.2f}'.format(iu_score * 100) - total_pixels = hist.sum() - tp = '{:5.2f}'.format(100 * iu_true_positive[index] / total_pixels) - fp = '{:5.2f}'.format( - iu_false_positive[index] / iu_true_positive[index]) - fn = '{:5.2f}'.format( - iu_false_negative[index] / iu_true_positive[index]) - precision = '{:5.2f}'.format( - iu_true_positive[index] / (iu_true_positive[index] + iu_false_positive[index])) - recall = '{:5.2f}'.format( - iu_true_positive[index] / (iu_true_positive[index] + iu_false_negative[index])) - sota = '{:5.2f}'.format(sota_iu_results[index]) - row = (index, class_name, iu_string, sota, - tp, fp, fn, precision, recall) - self._print_table_row(row) - self._print_table_end() - self._print_page_end() - - -def main(): - images = glob.glob('dump_imgs_train/*.png') - images = [i for i in images if 'mask' not in i] - - ip = ResultsPage('test page', 'dd.html') - for img in images: - basename = os.path.splitext(img)[0] - mask_img = basename + '_mask.png' - ip.add_table(((img, 'image'), (mask_img, 'mask'))) - ip.write_page() +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +""" +Copyright 2020 Nvidia Corporation + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +""" + +import glob +import os +import numpy as np + +id2cat = { + 0: 'road', + 1: 'sidewalk', + 2: 'building', + 3: 'wall', + 4: 'fence', + 5: 'pole', + 6: 'traffic_light', + 7: 'traffic_sign', + 8: 'vegetation', + 9: 'terrain', + 10: 'sky', + 11: 'person', + 12: 'rider', + 13: 'car', + 14: 'truck', + 15: 'bus', + 16: 'train', + 17: 'motorcycle', + 18: 'bicycle'} + +# Leaderboard mapillary +sota_iu_results = { + 0: 98.4046, + 1: 85.0224, + 2: 93.6462, + 3: 61.7487, + 4: 63.8885, + 5: 67.6745, + 6: 77.43, + 7: 80.8351, + 8: 93.7341, + 9: 71.8774, + 10: 95.6122, + 11: 86.7228, + 12: 72.7778, + 13: 95.7033, + 14: 79.9019, + 15: 93.0954, + 16: 89.7196, + 17: 72.5731, + 18: 78.2172, + 255: 0} + + +class ResultsPage(object): + ''' + This creates an HTML page of embedded images, useful for showing evaluation results. + + Usage: + ip = ImagePage(html_fn) + + # Add a table with N images ... + ip.add_table((img, descr), (img, descr), ...) + + # Generate html page + ip.write_page() + ''' + + def __init__(self, experiment_name, html_filename): + self.experiment_name = experiment_name + self.html_filename = html_filename + self.outfile = open(self.html_filename, 'w') + self.items = [] + + def _print_header(self): + header = ''' + + + Experiment = {} + + '''.format(self.experiment_name) + self.outfile.write(header) + + def _print_footer(self): + self.outfile.write(''' +''') + + def _print_table_header(self, table_name): + table_hdr = '''

{}

+ + '''.format(table_name) + self.outfile.write(table_hdr) + + def _print_table_footer(self): + table_ftr = ''' +
''' + self.outfile.write(table_ftr) + + def _print_table_guts(self, img_fn, descr): + table = ''' +

+ + +
+

{descr}

+

+ '''.format(img_fn=img_fn, descr=descr) + self.outfile.write(table) + + def add_table(self, img_label_pairs, table_heading=''): + """ + :img_label_pairs: A list of pairs of [img,label] + """ + self.items.append([img_label_pairs, table_heading]) + + def _write_table(self, table, heading): + img, _descr = table[0] + self._print_table_header(heading) + for img, descr in table: + self._print_table_guts(img, descr) + self._print_table_footer() + + def write_page(self): + self._print_header() + + for table, heading in self.items: + self._write_table(table, heading) + + self._print_footer() + + def _print_page_start(self): + page_start = ''' + + +Experiment = EXP_NAME + + +''' + self.outfile.write(page_start) + + def _print_table_start(self, caption, hdr): + self.outfile.write(''' + + '''.format(caption)) + for hdr_col in hdr: + self.outfile.write(' '.format(hdr_col)) + self.outfile.write(' ') + + def _print_table_row(self, row): + self.outfile.write(' ') + for i in row: + self.outfile.write(' '.format(i)) + # Create Links + fp_link = 'false positive Top N'.format(row[ + 1]) + fn_link = 'false_negative Top N'.format(row[ + 1]) + self.outfile.write(' '.format(fp_link)) + self.outfile.write(' '.format(fn_link)) + self.outfile.write(' ') + + def _print_table_end(self): + self.outfile.write('
{}
{}
{}{}{}
') + + def _print_page_end(self): + self.outfile.write(''' + +''') + + def create_main(self, iu, hist): + self._print_page_start() + #_print_table_style() + # Calculate all of the terms: + iu_false_positive = hist.sum(axis=1) - np.diag(hist) + iu_false_negative = hist.sum(axis=0) - np.diag(hist) + iu_true_positive = np.diag(hist) + + hdr = ("Class ID", "Class", "IoU", "Sota-IU", "TP", + "FP", "FN", "precision", "recall", "", "") + self._print_table_start("Mean IoU Results", hdr) + for iu_score, index in iu: + class_name = id2cat[index] + iu_string = '{:5.2f}'.format(iu_score * 100) + total_pixels = hist.sum() + tp = '{:5.2f}'.format(100 * iu_true_positive[index] / total_pixels) + fp = '{:5.2f}'.format( + iu_false_positive[index] / iu_true_positive[index]) + fn = '{:5.2f}'.format( + iu_false_negative[index] / iu_true_positive[index]) + precision = '{:5.2f}'.format( + iu_true_positive[index] / (iu_true_positive[index] + iu_false_positive[index])) + recall = '{:5.2f}'.format( + iu_true_positive[index] / (iu_true_positive[index] + iu_false_negative[index])) + sota = '{:5.2f}'.format(sota_iu_results[index]) + row = (index, class_name, iu_string, sota, + tp, fp, fn, precision, recall) + self._print_table_row(row) + self._print_table_end() + self._print_page_end() + + +def main(): + images = glob.glob('dump_imgs_train/*.png') + images = [i for i in images if 'mask' not in i] + + ip = ResultsPage('test page', 'dd.html') + for img in images: + basename = os.path.splitext(img)[0] + mask_img = basename + '_mask.png' + ip.add_table(((img, 'image'), (mask_img, 'mask'))) + ip.write_page() diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/__init__.py b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/__init__.py index 55887fca32..945cb920d4 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/__init__.py +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/__init__.py @@ -1,13 +1,13 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/dataset/__init__.py b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/dataset/__init__.py index 55887fca32..945cb920d4 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/dataset/__init__.py +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/dataset/__init__.py @@ -1,13 +1,13 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/domain_adaptation/__init__.py b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/domain_adaptation/__init__.py index 55887fca32..945cb920d4 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/domain_adaptation/__init__.py +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/domain_adaptation/__init__.py @@ -1,13 +1,13 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/domain_adaptation/config.py b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/domain_adaptation/config.py index f9a2ffbacd..49411a50bc 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/domain_adaptation/config.py +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/domain_adaptation/config.py @@ -1,156 +1,156 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -# -------------------------------------------------------- -# Configurations for domain adaptation -# Copyright (c) 2019 valeo.ai -# -# Written by Tuan-Hung Vu -# Adapted from https://github.com/rbgirshick/py-faster-rcnn/blob/master/lib/fast_rcnn/config.py -# -------------------------------------------------------- - -import os.path as osp - -import numpy as np -from easydict import EasyDict - -from advent.utils import project_root -from advent.utils.serialization import yaml_load - - -cfg = EasyDict() - -# COMMON CONFIGS -# source domain -cfg.SOURCE = 'GTA' -# target domain -cfg.TARGET = 'Cityscapes' -# Number of workers for dataloading -cfg.NUM_WORKERS = 4 -# List of training images -cfg.DATA_LIST_SOURCE = str(project_root / 'advent/dataset/gta5_list/{}.txt') -cfg.DATA_LIST_TARGET = str(project_root / 'advent/dataset/cityscapes_list/{}.txt') -# Directories -cfg.DATA_DIRECTORY_SOURCE = str(project_root / 'data/GTA5') -cfg.DATA_DIRECTORY_TARGET = str(project_root / 'data/Cityscapes') -# Number of object classes -cfg.NUM_CLASSES = 19 -# Exp dirs -cfg.EXP_NAME = '' -cfg.EXP_ROOT = project_root / 'experiments' -cfg.EXP_ROOT_SNAPSHOT = osp.join(cfg.EXP_ROOT, 'snapshots') -cfg.EXP_ROOT_LOGS = osp.join(cfg.EXP_ROOT, 'logs') -# CUDA -cfg.GPU_ID = 0 - -# TRAIN CONFIGS -cfg.TRAIN = EasyDict() -cfg.TRAIN.SET_SOURCE = 'all' -cfg.TRAIN.SET_TARGET = 'train' -cfg.TRAIN.BATCH_SIZE_SOURCE = 1 -cfg.TRAIN.BATCH_SIZE_TARGET = 1 -cfg.TRAIN.IGNORE_LABEL = 255 -cfg.TRAIN.INPUT_SIZE_SOURCE = (1280, 720) -cfg.TRAIN.INPUT_SIZE_TARGET = (1024, 512) -# Class info -cfg.TRAIN.INFO_SOURCE = '' -cfg.TRAIN.INFO_TARGET = str(project_root / 'advent/dataset/cityscapes_list/info.json') -# Segmentation network params -cfg.TRAIN.MODEL = 'DeepLabv2' -cfg.TRAIN.MULTI_LEVEL = True -cfg.TRAIN.RESTORE_FROM = '' -cfg.TRAIN.IMG_MEAN = np.array((104.00698793, 116.66876762, 122.67891434), dtype=np.float32) -cfg.TRAIN.LEARNING_RATE = 2.5e-4 -cfg.TRAIN.MOMENTUM = 0.9 -cfg.TRAIN.WEIGHT_DECAY = 0.0005 -cfg.TRAIN.POWER = 0.9 -cfg.TRAIN.LAMBDA_SEG_MAIN = 1.0 -cfg.TRAIN.LAMBDA_SEG_AUX = 0.1 # weight of conv4 prediction. Used in multi-level setting. -# Domain adaptation -cfg.TRAIN.DA_METHOD = 'AdvEnt' -# Adversarial training params -cfg.TRAIN.LEARNING_RATE_D = 1e-4 -cfg.TRAIN.LAMBDA_ADV_MAIN = 0.001 -cfg.TRAIN.LAMBDA_ADV_AUX = 0.0002 -# MinEnt params -cfg.TRAIN.LAMBDA_ENT_MAIN = 0.001 -cfg.TRAIN.LAMBDA_ENT_AUX = 0.0002 -# Other params -cfg.TRAIN.MAX_ITERS = 250000 -cfg.TRAIN.EARLY_STOP = 120000 -cfg.TRAIN.SAVE_PRED_EVERY = 2000 -cfg.TRAIN.SNAPSHOT_DIR = '' -cfg.TRAIN.RANDOM_SEED = 1234 -cfg.TRAIN.TENSORBOARD_LOGDIR = '' -cfg.TRAIN.TENSORBOARD_VIZRATE = 100 - -# TEST CONFIGS -cfg.TEST = EasyDict() -cfg.TEST.MODE = 'best' # {'single', 'best'} -# model -cfg.TEST.MODEL = ('DeepLabv2',) -cfg.TEST.MODEL_WEIGHT = (1.0,) -cfg.TEST.MULTI_LEVEL = (True,) -cfg.TEST.IMG_MEAN = np.array((104.00698793, 116.66876762, 122.67891434), dtype=np.float32) -cfg.TEST.RESTORE_FROM = ('',) -cfg.TEST.SNAPSHOT_DIR = ('',) # used in 'best' mode -cfg.TEST.SNAPSHOT_STEP = 2000 # used in 'best' mode -cfg.TEST.SNAPSHOT_MAXITER = 120000 # used in 'best' mode -# Test sets -cfg.TEST.SET_TARGET = 'val' -cfg.TEST.BATCH_SIZE_TARGET = 1 -cfg.TEST.INPUT_SIZE_TARGET = (1024, 512) -cfg.TEST.OUTPUT_SIZE_TARGET = (2048, 1024) -cfg.TEST.INFO_TARGET = str(project_root / 'advent/dataset/cityscapes_list/info.json') -cfg.TEST.WAIT_MODEL = True - - -def _merge_a_into_b(a, b): - """Merge config dictionary a into config dictionary b, clobbering the - options in b whenever they are also specified in a. - """ - if type(a) is not EasyDict: - return - - for k, v in a.items(): - # a must specify keys that are in b - # if not b.has_key(k): - if k not in b: - raise KeyError(f'{k} is not a valid config key') - - # the types must match, too - old_type = type(b[k]) - if old_type is not type(v): - if isinstance(b[k], np.ndarray): - v = np.array(v, dtype=b[k].dtype) - else: - raise ValueError(f'Type mismatch ({type(b[k])} vs. {type(v)}) ' - f'for config key: {k}') - - # recursively merge dicts - if type(v) is EasyDict: - try: - _merge_a_into_b(a[k], b[k]) - except Exception: - print(f'Error under config key: {k}') - raise - else: - b[k] = v - - -def cfg_from_file(filename): - """Load a config file and merge it into the default options. - """ - yaml_cfg = EasyDict(yaml_load(filename)) - _merge_a_into_b(yaml_cfg, cfg) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +# -------------------------------------------------------- +# Configurations for domain adaptation +# Copyright (c) 2019 valeo.ai +# +# Written by Tuan-Hung Vu +# Adapted from https://github.com/rbgirshick/py-faster-rcnn/blob/master/lib/fast_rcnn/config.py +# -------------------------------------------------------- + +import os.path as osp + +import numpy as np +from easydict import EasyDict + +from advent.utils import project_root +from advent.utils.serialization import yaml_load + + +cfg = EasyDict() + +# COMMON CONFIGS +# source domain +cfg.SOURCE = 'GTA' +# target domain +cfg.TARGET = 'Cityscapes' +# Number of workers for dataloading +cfg.NUM_WORKERS = 4 +# List of training images +cfg.DATA_LIST_SOURCE = str(project_root / 'advent/dataset/gta5_list/{}.txt') +cfg.DATA_LIST_TARGET = str(project_root / 'advent/dataset/cityscapes_list/{}.txt') +# Directories +cfg.DATA_DIRECTORY_SOURCE = str(project_root / 'data/GTA5') +cfg.DATA_DIRECTORY_TARGET = str(project_root / 'data/Cityscapes') +# Number of object classes +cfg.NUM_CLASSES = 19 +# Exp dirs +cfg.EXP_NAME = '' +cfg.EXP_ROOT = project_root / 'experiments' +cfg.EXP_ROOT_SNAPSHOT = osp.join(cfg.EXP_ROOT, 'snapshots') +cfg.EXP_ROOT_LOGS = osp.join(cfg.EXP_ROOT, 'logs') +# CUDA +cfg.GPU_ID = 0 + +# TRAIN CONFIGS +cfg.TRAIN = EasyDict() +cfg.TRAIN.SET_SOURCE = 'all' +cfg.TRAIN.SET_TARGET = 'train' +cfg.TRAIN.BATCH_SIZE_SOURCE = 1 +cfg.TRAIN.BATCH_SIZE_TARGET = 1 +cfg.TRAIN.IGNORE_LABEL = 255 +cfg.TRAIN.INPUT_SIZE_SOURCE = (1280, 720) +cfg.TRAIN.INPUT_SIZE_TARGET = (1024, 512) +# Class info +cfg.TRAIN.INFO_SOURCE = '' +cfg.TRAIN.INFO_TARGET = str(project_root / 'advent/dataset/cityscapes_list/info.json') +# Segmentation network params +cfg.TRAIN.MODEL = 'DeepLabv2' +cfg.TRAIN.MULTI_LEVEL = True +cfg.TRAIN.RESTORE_FROM = '' +cfg.TRAIN.IMG_MEAN = np.array((104.00698793, 116.66876762, 122.67891434), dtype=np.float32) +cfg.TRAIN.LEARNING_RATE = 2.5e-4 +cfg.TRAIN.MOMENTUM = 0.9 +cfg.TRAIN.WEIGHT_DECAY = 0.0005 +cfg.TRAIN.POWER = 0.9 +cfg.TRAIN.LAMBDA_SEG_MAIN = 1.0 +cfg.TRAIN.LAMBDA_SEG_AUX = 0.1 # weight of conv4 prediction. Used in multi-level setting. +# Domain adaptation +cfg.TRAIN.DA_METHOD = 'AdvEnt' +# Adversarial training params +cfg.TRAIN.LEARNING_RATE_D = 1e-4 +cfg.TRAIN.LAMBDA_ADV_MAIN = 0.001 +cfg.TRAIN.LAMBDA_ADV_AUX = 0.0002 +# MinEnt params +cfg.TRAIN.LAMBDA_ENT_MAIN = 0.001 +cfg.TRAIN.LAMBDA_ENT_AUX = 0.0002 +# Other params +cfg.TRAIN.MAX_ITERS = 250000 +cfg.TRAIN.EARLY_STOP = 120000 +cfg.TRAIN.SAVE_PRED_EVERY = 2000 +cfg.TRAIN.SNAPSHOT_DIR = '' +cfg.TRAIN.RANDOM_SEED = 1234 +cfg.TRAIN.TENSORBOARD_LOGDIR = '' +cfg.TRAIN.TENSORBOARD_VIZRATE = 100 + +# TEST CONFIGS +cfg.TEST = EasyDict() +cfg.TEST.MODE = 'best' # {'single', 'best'} +# model +cfg.TEST.MODEL = ('DeepLabv2',) +cfg.TEST.MODEL_WEIGHT = (1.0,) +cfg.TEST.MULTI_LEVEL = (True,) +cfg.TEST.IMG_MEAN = np.array((104.00698793, 116.66876762, 122.67891434), dtype=np.float32) +cfg.TEST.RESTORE_FROM = ('',) +cfg.TEST.SNAPSHOT_DIR = ('',) # used in 'best' mode +cfg.TEST.SNAPSHOT_STEP = 2000 # used in 'best' mode +cfg.TEST.SNAPSHOT_MAXITER = 120000 # used in 'best' mode +# Test sets +cfg.TEST.SET_TARGET = 'val' +cfg.TEST.BATCH_SIZE_TARGET = 1 +cfg.TEST.INPUT_SIZE_TARGET = (1024, 512) +cfg.TEST.OUTPUT_SIZE_TARGET = (2048, 1024) +cfg.TEST.INFO_TARGET = str(project_root / 'advent/dataset/cityscapes_list/info.json') +cfg.TEST.WAIT_MODEL = True + + +def _merge_a_into_b(a, b): + """Merge config dictionary a into config dictionary b, clobbering the + options in b whenever they are also specified in a. + """ + if type(a) is not EasyDict: + return + + for k, v in a.items(): + # a must specify keys that are in b + # if not b.has_key(k): + if k not in b: + raise KeyError(f'{k} is not a valid config key') + + # the types must match, too + old_type = type(b[k]) + if old_type is not type(v): + if isinstance(b[k], np.ndarray): + v = np.array(v, dtype=b[k].dtype) + else: + raise ValueError(f'Type mismatch ({type(b[k])} vs. {type(v)}) ' + f'for config key: {k}') + + # recursively merge dicts + if type(v) is EasyDict: + try: + _merge_a_into_b(a[k], b[k]) + except Exception: + print(f'Error under config key: {k}') + raise + else: + b[k] = v + + +def cfg_from_file(filename): + """Load a config file and merge it into the default options. + """ + yaml_cfg = EasyDict(yaml_load(filename)) + _merge_a_into_b(yaml_cfg, cfg) diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/domain_adaptation/eval_UDA.py b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/domain_adaptation/eval_UDA.py index caff904345..11a700a2f8 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/domain_adaptation/eval_UDA.py +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/domain_adaptation/eval_UDA.py @@ -1,157 +1,157 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -# -------------------------------------------------------- -# Domain adpatation evaluation -# Copyright (c) 2019 valeo.ai -# -# Written by Tuan-Hung Vu -# -------------------------------------------------------- - -import os.path as osp -import time - -import numpy as np -import torch -from torch import nn -from tqdm import tqdm - -from advent.utils.func import per_class_iu, fast_hist -from advent.utils.serialization import pickle_dump, pickle_load - - -def evaluate_domain_adaptation( models, test_loader, cfg, - fixed_test_size=True, - verbose=True): - device = cfg.GPU_ID - interp = None - if fixed_test_size: - interp = nn.Upsample(size=(cfg.TEST.OUTPUT_SIZE_TARGET[1], cfg.TEST.OUTPUT_SIZE_TARGET[0]), mode='bilinear', align_corners=True) - # eval - if cfg.TEST.MODE == 'single': - eval_single(cfg, models, - device, test_loader, interp, fixed_test_size, - verbose) - elif cfg.TEST.MODE == 'best': - eval_best(cfg, models, - device, test_loader, interp, fixed_test_size, - verbose) - else: - raise NotImplementedError(f"Not yet supported test mode {cfg.TEST.MODE}") - - -def eval_single(cfg, models, - device, test_loader, interp, - fixed_test_size, verbose): - assert len(cfg.TEST.RESTORE_FROM) == len(models), 'Number of models are not matched' - for checkpoint, model in zip(cfg.TEST.RESTORE_FROM, models): - load_checkpoint_for_evaluation(model, checkpoint, device) - # eval - hist = np.zeros((cfg.NUM_CLASSES, cfg.NUM_CLASSES)) - for index, batch in tqdm(enumerate(test_loader)): - image, label, _, name = batch - if not fixed_test_size: - interp = nn.Upsample(size=(label.shape[1], label.shape[2]), mode='bilinear', align_corners=True) - with torch.no_grad(): - output = None - for model, model_weight in zip(models, cfg.TEST.MODEL_WEIGHT): - pred_main = model(image.cuda(device))[1] - output_ = interp(pred_main).cpu().data[0].numpy() - if output is None: - output = model_weight * output_ - else: - output += model_weight * output_ - assert output is not None, 'Output is None' - output = output.transpose(1, 2, 0) - output = np.argmax(output, axis=2) - label = label.numpy()[0] - hist += fast_hist(label.flatten(), output.flatten(), cfg.NUM_CLASSES) - inters_over_union_classes = per_class_iu(hist) - print(f'mIoU = \t{round(np.nanmean(inters_over_union_classes) * 100, 2)}') - if verbose: - display_stats(cfg, test_loader.dataset.class_names, inters_over_union_classes) - - -def eval_best(cfg, models, - device, test_loader, interp, - fixed_test_size, verbose): - assert len(models) == 1, 'Not yet supported multi models in this mode' - assert osp.exists(cfg.TEST.SNAPSHOT_DIR[0]), 'SNAPSHOT_DIR is not found' - start_iter = cfg.TEST.SNAPSHOT_STEP - step = cfg.TEST.SNAPSHOT_STEP - max_iter = cfg.TEST.SNAPSHOT_MAXITER - cache_path = osp.join(cfg.TEST.SNAPSHOT_DIR[0], 'all_res.pkl') - if osp.exists(cache_path): - all_res = pickle_load(cache_path) - else: - all_res = {} - cur_best_miou = -1 - cur_best_model = '' - for i_iter in range(start_iter, max_iter + 1, step): - restore_from = osp.join(cfg.TEST.SNAPSHOT_DIR[0], f'model_{i_iter}.pth') - if not osp.exists(restore_from): - # continue - if cfg.TEST.WAIT_MODEL: - print('Waiting for model..!') - while not osp.exists(restore_from): - time.sleep(5) - print("Evaluating model", restore_from) - if i_iter not in all_res.keys(): - load_checkpoint_for_evaluation(models[0], restore_from, device) - # eval - hist = np.zeros((cfg.NUM_CLASSES, cfg.NUM_CLASSES)) - # for index, batch in enumerate(test_loader): - # image, _, _, name = batch - test_iter = iter(test_loader) - for index in tqdm(range(len(test_loader))): - image, label, _, name = next(test_iter) - if not fixed_test_size: - interp = nn.Upsample(size=(label.shape[1], label.shape[2]), mode='bilinear', align_corners=True) - with torch.no_grad(): - pred_main = models[0](image.cuda(device))[1] - output = interp(pred_main).cpu().data[0].numpy() - output = output.transpose(1, 2, 0) - output = np.argmax(output, axis=2) - label = label.numpy()[0] - hist += fast_hist(label.flatten(), output.flatten(), cfg.NUM_CLASSES) - if verbose and index > 0 and index % 100 == 0: - print('{:d} / {:d}: {:0.2f}'.format( - index, len(test_loader), 100 * np.nanmean(per_class_iu(hist)))) - inters_over_union_classes = per_class_iu(hist) - all_res[i_iter] = inters_over_union_classes - pickle_dump(all_res, cache_path) - else: - inters_over_union_classes = all_res[i_iter] - computed_miou = round(np.nanmean(inters_over_union_classes) * 100, 2) - if cur_best_miou < computed_miou: - cur_best_miou = computed_miou - cur_best_model = restore_from - print('\tCurrent mIoU:', computed_miou) - print('\tCurrent best model:', cur_best_model) - print('\tCurrent best mIoU:', cur_best_miou) - if verbose: - display_stats(cfg, test_loader.dataset.class_names, inters_over_union_classes) - - -def load_checkpoint_for_evaluation(model, checkpoint, device): - saved_state_dict = torch.load(checkpoint) - model.load_state_dict(saved_state_dict) - model.eval() - model.cuda(device) - - -def display_stats(cfg, name_classes, inters_over_union_classes): - for ind_class in range(cfg.NUM_CLASSES): - print(name_classes[ind_class] - + '\t' + str(round(inters_over_union_classes[ind_class] * 100, 2))) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +# -------------------------------------------------------- +# Domain adpatation evaluation +# Copyright (c) 2019 valeo.ai +# +# Written by Tuan-Hung Vu +# -------------------------------------------------------- + +import os.path as osp +import time + +import numpy as np +import torch +from torch import nn +from tqdm import tqdm + +from advent.utils.func import per_class_iu, fast_hist +from advent.utils.serialization import pickle_dump, pickle_load + + +def evaluate_domain_adaptation( models, test_loader, cfg, + fixed_test_size=True, + verbose=True): + device = cfg.GPU_ID + interp = None + if fixed_test_size: + interp = nn.Upsample(size=(cfg.TEST.OUTPUT_SIZE_TARGET[1], cfg.TEST.OUTPUT_SIZE_TARGET[0]), mode='bilinear', align_corners=True) + # eval + if cfg.TEST.MODE == 'single': + eval_single(cfg, models, + device, test_loader, interp, fixed_test_size, + verbose) + elif cfg.TEST.MODE == 'best': + eval_best(cfg, models, + device, test_loader, interp, fixed_test_size, + verbose) + else: + raise NotImplementedError(f"Not yet supported test mode {cfg.TEST.MODE}") + + +def eval_single(cfg, models, + device, test_loader, interp, + fixed_test_size, verbose): + assert len(cfg.TEST.RESTORE_FROM) == len(models), 'Number of models are not matched' + for checkpoint, model in zip(cfg.TEST.RESTORE_FROM, models): + load_checkpoint_for_evaluation(model, checkpoint, device) + # eval + hist = np.zeros((cfg.NUM_CLASSES, cfg.NUM_CLASSES)) + for index, batch in tqdm(enumerate(test_loader)): + image, label, _, name = batch + if not fixed_test_size: + interp = nn.Upsample(size=(label.shape[1], label.shape[2]), mode='bilinear', align_corners=True) + with torch.no_grad(): + output = None + for model, model_weight in zip(models, cfg.TEST.MODEL_WEIGHT): + pred_main = model(image.cuda(device))[1] + output_ = interp(pred_main).cpu().data[0].numpy() + if output is None: + output = model_weight * output_ + else: + output += model_weight * output_ + assert output is not None, 'Output is None' + output = output.transpose(1, 2, 0) + output = np.argmax(output, axis=2) + label = label.numpy()[0] + hist += fast_hist(label.flatten(), output.flatten(), cfg.NUM_CLASSES) + inters_over_union_classes = per_class_iu(hist) + print(f'mIoU = \t{round(np.nanmean(inters_over_union_classes) * 100, 2)}') + if verbose: + display_stats(cfg, test_loader.dataset.class_names, inters_over_union_classes) + + +def eval_best(cfg, models, + device, test_loader, interp, + fixed_test_size, verbose): + assert len(models) == 1, 'Not yet supported multi models in this mode' + assert osp.exists(cfg.TEST.SNAPSHOT_DIR[0]), 'SNAPSHOT_DIR is not found' + start_iter = cfg.TEST.SNAPSHOT_STEP + step = cfg.TEST.SNAPSHOT_STEP + max_iter = cfg.TEST.SNAPSHOT_MAXITER + cache_path = osp.join(cfg.TEST.SNAPSHOT_DIR[0], 'all_res.pkl') + if osp.exists(cache_path): + all_res = pickle_load(cache_path) + else: + all_res = {} + cur_best_miou = -1 + cur_best_model = '' + for i_iter in range(start_iter, max_iter + 1, step): + restore_from = osp.join(cfg.TEST.SNAPSHOT_DIR[0], f'model_{i_iter}.pth') + if not osp.exists(restore_from): + # continue + if cfg.TEST.WAIT_MODEL: + print('Waiting for model..!') + while not osp.exists(restore_from): + time.sleep(5) + print("Evaluating model", restore_from) + if i_iter not in all_res.keys(): + load_checkpoint_for_evaluation(models[0], restore_from, device) + # eval + hist = np.zeros((cfg.NUM_CLASSES, cfg.NUM_CLASSES)) + # for index, batch in enumerate(test_loader): + # image, _, _, name = batch + test_iter = iter(test_loader) + for index in tqdm(range(len(test_loader))): + image, label, _, name = next(test_iter) + if not fixed_test_size: + interp = nn.Upsample(size=(label.shape[1], label.shape[2]), mode='bilinear', align_corners=True) + with torch.no_grad(): + pred_main = models[0](image.cuda(device))[1] + output = interp(pred_main).cpu().data[0].numpy() + output = output.transpose(1, 2, 0) + output = np.argmax(output, axis=2) + label = label.numpy()[0] + hist += fast_hist(label.flatten(), output.flatten(), cfg.NUM_CLASSES) + if verbose and index > 0 and index % 100 == 0: + print('{:d} / {:d}: {:0.2f}'.format( + index, len(test_loader), 100 * np.nanmean(per_class_iu(hist)))) + inters_over_union_classes = per_class_iu(hist) + all_res[i_iter] = inters_over_union_classes + pickle_dump(all_res, cache_path) + else: + inters_over_union_classes = all_res[i_iter] + computed_miou = round(np.nanmean(inters_over_union_classes) * 100, 2) + if cur_best_miou < computed_miou: + cur_best_miou = computed_miou + cur_best_model = restore_from + print('\tCurrent mIoU:', computed_miou) + print('\tCurrent best model:', cur_best_model) + print('\tCurrent best mIoU:', cur_best_miou) + if verbose: + display_stats(cfg, test_loader.dataset.class_names, inters_over_union_classes) + + +def load_checkpoint_for_evaluation(model, checkpoint, device): + saved_state_dict = torch.load(checkpoint) + model.load_state_dict(saved_state_dict) + model.eval() + model.cuda(device) + + +def display_stats(cfg, name_classes, inters_over_union_classes): + for ind_class in range(cfg.NUM_CLASSES): + print(name_classes[ind_class] + + '\t' + str(round(inters_over_union_classes[ind_class] * 100, 2))) diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/domain_adaptation/train_UDA.py b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/domain_adaptation/train_UDA.py index e7266b6793..899fc87bdc 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/domain_adaptation/train_UDA.py +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/domain_adaptation/train_UDA.py @@ -1,356 +1,356 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -# -------------------------------------------------------- -# Domain adpatation training -# Copyright (c) 2019 valeo.ai -# -# Written by Tuan-Hung Vu -# -------------------------------------------------------- -import os -import sys -from pathlib import Path - -import os.path as osp -import numpy as np -import torch -import torch.backends.cudnn as cudnn -import torch.nn.functional as F -import torch.optim as optim -from tensorboardX import SummaryWriter -from torch import nn -from torchvision.utils import make_grid -from tqdm import tqdm - -from advent.model.discriminator import get_fc_discriminator -from advent.utils.func import adjust_learning_rate, adjust_learning_rate_discriminator -from advent.utils.func import loss_calc, bce_loss -from advent.utils.loss import entropy_loss -from advent.utils.func import prob_2_entropy -from advent.utils.viz_segmask import colorize_mask - - -def train_advent(model, trainloader, targetloader, cfg): - ''' UDA training with advent - ''' - # Create the model and start the training. - input_size_source = cfg.TRAIN.INPUT_SIZE_SOURCE - input_size_target = cfg.TRAIN.INPUT_SIZE_TARGET - device = cfg.GPU_ID - num_classes = cfg.NUM_CLASSES - viz_tensorboard = os.path.exists(cfg.TRAIN.TENSORBOARD_LOGDIR) - if viz_tensorboard: - writer = SummaryWriter(log_dir=cfg.TRAIN.TENSORBOARD_LOGDIR) - - # SEGMNETATION NETWORK - model.train() - model.to(device) - cudnn.benchmark = True - cudnn.enabled = True - - # DISCRIMINATOR NETWORK - # feature-level - d_aux = get_fc_discriminator(num_classes=num_classes) - d_aux.train() - d_aux.to(device) - - # seg maps, i.e. output, level - d_main = get_fc_discriminator(num_classes=num_classes) - d_main.train() - d_main.to(device) - - # OPTIMIZERS - # segnet's optimizer - optimizer = optim.SGD(model.optim_parameters(cfg.TRAIN.LEARNING_RATE), - lr=cfg.TRAIN.LEARNING_RATE, - momentum=cfg.TRAIN.MOMENTUM, - weight_decay=cfg.TRAIN.WEIGHT_DECAY) - - # discriminators' optimizers - optimizer_d_aux = optim.Adam(d_aux.parameters(), lr=cfg.TRAIN.LEARNING_RATE_D, - betas=(0.9, 0.99)) - optimizer_d_main = optim.Adam(d_main.parameters(), lr=cfg.TRAIN.LEARNING_RATE_D, - betas=(0.9, 0.99)) - - # interpolate output segmaps - interp = nn.Upsample(size=(input_size_source[1], input_size_source[0]), mode='bilinear', - align_corners=True) - interp_target = nn.Upsample(size=(input_size_target[1], input_size_target[0]), mode='bilinear', - align_corners=True) - - # labels for adversarial training - source_label = 0 - target_label = 1 - trainloader_iter = enumerate(trainloader) - targetloader_iter = enumerate(targetloader) - for i_iter in tqdm(range(cfg.TRAIN.EARLY_STOP + 1)): - - # reset optimizers - optimizer.zero_grad() - optimizer_d_aux.zero_grad() - optimizer_d_main.zero_grad() - # adapt LR if needed - adjust_learning_rate(optimizer, i_iter, cfg) - adjust_learning_rate_discriminator(optimizer_d_aux, i_iter, cfg) - adjust_learning_rate_discriminator(optimizer_d_main, i_iter, cfg) - - # UDA Training - # only train segnet. Don't accumulate grads in disciminators - for param in d_aux.parameters(): - param.requires_grad = False - for param in d_main.parameters(): - param.requires_grad = False - # train on source - _, batch = trainloader_iter.__next__() - images_source, labels, _, _ = batch - pred_src_aux, pred_src_main = model(images_source.cuda(device)) - if cfg.TRAIN.MULTI_LEVEL: - pred_src_aux = interp(pred_src_aux) - loss_seg_src_aux = loss_calc(pred_src_aux, labels, device) - else: - loss_seg_src_aux = 0 - pred_src_main = interp(pred_src_main) - loss_seg_src_main = loss_calc(pred_src_main, labels, device) - loss = (cfg.TRAIN.LAMBDA_SEG_MAIN * loss_seg_src_main - + cfg.TRAIN.LAMBDA_SEG_AUX * loss_seg_src_aux) - loss.backward() - - # adversarial training ot fool the discriminator - _, batch = targetloader_iter.__next__() - images, _, _, _ = batch - pred_trg_aux, pred_trg_main = model(images.cuda(device)) - if cfg.TRAIN.MULTI_LEVEL: - pred_trg_aux = interp_target(pred_trg_aux) - d_out_aux = d_aux(prob_2_entropy(F.softmax(pred_trg_aux))) - loss_adv_trg_aux = bce_loss(d_out_aux, source_label) - else: - loss_adv_trg_aux = 0 - pred_trg_main = interp_target(pred_trg_main) - d_out_main = d_main(prob_2_entropy(F.softmax(pred_trg_main))) - loss_adv_trg_main = bce_loss(d_out_main, source_label) - loss = (cfg.TRAIN.LAMBDA_ADV_MAIN * loss_adv_trg_main - + cfg.TRAIN.LAMBDA_ADV_AUX * loss_adv_trg_aux) - loss = loss - loss.backward() - - # Train discriminator networks - # enable training mode on discriminator networks - for param in d_aux.parameters(): - param.requires_grad = True - for param in d_main.parameters(): - param.requires_grad = True - # train with source - if cfg.TRAIN.MULTI_LEVEL: - pred_src_aux = pred_src_aux.detach() - d_out_aux = d_aux(prob_2_entropy(F.softmax(pred_src_aux))) - loss_d_aux = bce_loss(d_out_aux, source_label) - loss_d_aux = loss_d_aux / 2 - loss_d_aux.backward() - pred_src_main = pred_src_main.detach() - d_out_main = d_main(prob_2_entropy(F.softmax(pred_src_main))) - loss_d_main = bce_loss(d_out_main, source_label) - loss_d_main = loss_d_main / 2 - loss_d_main.backward() - - # train with target - if cfg.TRAIN.MULTI_LEVEL: - pred_trg_aux = pred_trg_aux.detach() - d_out_aux = d_aux(prob_2_entropy(F.softmax(pred_trg_aux))) - loss_d_aux = bce_loss(d_out_aux, target_label) - loss_d_aux = loss_d_aux / 2 - loss_d_aux.backward() - else: - loss_d_aux = 0 - pred_trg_main = pred_trg_main.detach() - d_out_main = d_main(prob_2_entropy(F.softmax(pred_trg_main))) - loss_d_main = bce_loss(d_out_main, target_label) - loss_d_main = loss_d_main / 2 - loss_d_main.backward() - - optimizer.step() - if cfg.TRAIN.MULTI_LEVEL: - optimizer_d_aux.step() - optimizer_d_main.step() - - current_losses = {'loss_seg_src_aux': loss_seg_src_aux, - 'loss_seg_src_main': loss_seg_src_main, - 'loss_adv_trg_aux': loss_adv_trg_aux, - 'loss_adv_trg_main': loss_adv_trg_main, - 'loss_d_aux': loss_d_aux, - 'loss_d_main': loss_d_main} - print_losses(current_losses, i_iter) - - if i_iter % cfg.TRAIN.SAVE_PRED_EVERY == 0 and i_iter != 0: - print('taking snapshot ...') - print('exp =', cfg.TRAIN.SNAPSHOT_DIR) - snapshot_dir = Path(cfg.TRAIN.SNAPSHOT_DIR) - torch.save(model.state_dict(), snapshot_dir / f'model_{i_iter}.pth') - torch.save(d_aux.state_dict(), snapshot_dir / f'model_{i_iter}_D_aux.pth') - torch.save(d_main.state_dict(), snapshot_dir / f'model_{i_iter}_D_main.pth') - if i_iter >= cfg.TRAIN.EARLY_STOP - 1: - break - sys.stdout.flush() - - # Visualize with tensorboard - if viz_tensorboard: - log_losses_tensorboard(writer, current_losses, i_iter) - - if i_iter % cfg.TRAIN.TENSORBOARD_VIZRATE == cfg.TRAIN.TENSORBOARD_VIZRATE - 1: - draw_in_tensorboard(writer, images, i_iter, pred_trg_main, num_classes, 'T') - draw_in_tensorboard(writer, images_source, i_iter, pred_src_main, num_classes, 'S') - - -def draw_in_tensorboard(writer, images, i_iter, pred_main, num_classes, type_): - grid_image = make_grid(images[:3].clone().cpu().data, 3, normalize=True) - writer.add_image(f'Image - {type_}', grid_image, i_iter) - - grid_image = make_grid(torch.from_numpy(np.array(colorize_mask(np.asarray( - np.argmax(F.softmax(pred_main).cpu().data[0].numpy().transpose(1, 2, 0), - axis=2), dtype=np.uint8)).convert('RGB')).transpose(2, 0, 1)), 3, - normalize=False, range=(0, 255)) - writer.add_image(f'Prediction - {type_}', grid_image, i_iter) - - output_sm = F.softmax(pred_main).cpu().data[0].numpy().transpose(1, 2, 0) - output_ent = np.sum(-np.multiply(output_sm, np.log2(output_sm)), axis=2, - keepdims=False) - grid_image = make_grid(torch.from_numpy(output_ent), 3, normalize=True, - range=(0, np.log2(num_classes))) - writer.add_image(f'Entropy - {type_}', grid_image, i_iter) - - -def train_minent(model, trainloader, targetloader, cfg): - ''' UDA training with minEnt - ''' - # Create the model and start the training. - input_size_source = cfg.TRAIN.INPUT_SIZE_SOURCE - input_size_target = cfg.TRAIN.INPUT_SIZE_TARGET - device = cfg.GPU_ID - num_classes = cfg.NUM_CLASSES - viz_tensorboard = os.path.exists(cfg.TRAIN.TENSORBOARD_LOGDIR) - if viz_tensorboard: - writer = SummaryWriter(log_dir=cfg.TRAIN.TENSORBOARD_LOGDIR) - - # SEGMNETATION NETWORK - model.train() - model.to(device) - cudnn.benchmark = True - cudnn.enabled = True - - # OPTIMIZERS - # segnet's optimizer - optimizer = optim.SGD(model.optim_parameters(cfg.TRAIN.LEARNING_RATE), - lr=cfg.TRAIN.LEARNING_RATE, - momentum=cfg.TRAIN.MOMENTUM, - weight_decay=cfg.TRAIN.WEIGHT_DECAY) - - # interpolate output segmaps - interp = nn.Upsample(size=(input_size_source[1], input_size_source[0]), mode='bilinear', - align_corners=True) - interp_target = nn.Upsample(size=(input_size_target[1], input_size_target[0]), mode='bilinear', - align_corners=True) - - trainloader_iter = enumerate(trainloader) - targetloader_iter = enumerate(targetloader) - for i_iter in tqdm(range(cfg.TRAIN.EARLY_STOP)): - - # reset optimizers - optimizer.zero_grad() - - # adapt LR if needed - adjust_learning_rate(optimizer, i_iter, cfg) - - # UDA Training - # train on source - _, batch = trainloader_iter.__next__() - images_source, labels, _, _ = batch - pred_src_aux, pred_src_main = model(images_source.cuda(device)) - if cfg.TRAIN.MULTI_LEVEL: - pred_src_aux = interp(pred_src_aux) - loss_seg_src_aux = loss_calc(pred_src_aux, labels, device) - else: - loss_seg_src_aux = 0 - pred_src_main = interp(pred_src_main) - loss_seg_src_main = loss_calc(pred_src_main, labels, device) - loss = (cfg.TRAIN.LAMBDA_SEG_MAIN * loss_seg_src_main - + cfg.TRAIN.LAMBDA_SEG_AUX * loss_seg_src_aux) - loss.backward() - - # adversarial training with minent - _, batch = targetloader_iter.__next__() - images, _, _, _ = batch - pred_trg_aux, pred_trg_main = model(images.cuda(device)) - pred_trg_aux = interp_target(pred_trg_aux) - pred_trg_main = interp_target(pred_trg_main) - pred_prob_trg_aux = F.softmax(pred_trg_aux) - pred_prob_trg_main = F.softmax(pred_trg_main) - - loss_target_entp_aux = entropy_loss(pred_prob_trg_aux) - loss_target_entp_main = entropy_loss(pred_prob_trg_main) - loss = (cfg.TRAIN.LAMBDA_ENT_AUX * loss_target_entp_aux - + cfg.TRAIN.LAMBDA_ENT_MAIN * loss_target_entp_main) - loss.backward() - optimizer.step() - - current_losses = {'loss_seg_src_aux': loss_seg_src_aux, - 'loss_seg_src_main': loss_seg_src_main, - 'loss_ent_aux': loss_target_entp_aux, - 'loss_ent_main': loss_target_entp_main} - - print_losses(current_losses, i_iter) - - if i_iter % cfg.TRAIN.SAVE_PRED_EVERY == 0 and i_iter != 0: - print('taking snapshot ...') - print('exp =', cfg.TRAIN.SNAPSHOT_DIR) - torch.save(model.state_dict(), - osp.join(cfg.TRAIN.SNAPSHOT_DIR, f'model_{i_iter}.pth')) - if i_iter >= cfg.TRAIN.EARLY_STOP - 1: - break - sys.stdout.flush() - - # Visualize with tensorboard - if viz_tensorboard: - log_losses_tensorboard(writer, current_losses, i_iter) - - if i_iter % cfg.TRAIN.TENSORBOARD_VIZRATE == cfg.TRAIN.TENSORBOARD_VIZRATE - 1: - draw_in_tensorboard(writer, images, i_iter, pred_trg_main, num_classes, 'T') - draw_in_tensorboard(writer, images_source, i_iter, pred_src_main, num_classes, 'S') - - -def print_losses(current_losses, i_iter): - list_strings = [] - for loss_name, loss_value in current_losses.items(): - list_strings.append(f'{loss_name} = {to_numpy(loss_value):.3f} ') - full_string = ' '.join(list_strings) - tqdm.write(f'iter = {i_iter} {full_string}') - - -def log_losses_tensorboard(writer, current_losses, i_iter): - for loss_name, loss_value in current_losses.items(): - writer.add_scalar(f'data/{loss_name}', to_numpy(loss_value), i_iter) - - -def to_numpy(tensor): - if isinstance(tensor, (int, float)): - return tensor - else: - return tensor.data.cpu().numpy() - - -def train_domain_adaptation(model, trainloader, targetloader, cfg): - if cfg.TRAIN.DA_METHOD == 'MinEnt': - train_minent(model, trainloader, targetloader, cfg) - elif cfg.TRAIN.DA_METHOD == 'AdvEnt': - train_advent(model, trainloader, targetloader, cfg) - else: - raise NotImplementedError(f"Not yet supported DA method {cfg.TRAIN.DA_METHOD}") +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +# -------------------------------------------------------- +# Domain adpatation training +# Copyright (c) 2019 valeo.ai +# +# Written by Tuan-Hung Vu +# -------------------------------------------------------- +import os +import sys +from pathlib import Path + +import os.path as osp +import numpy as np +import torch +import torch.backends.cudnn as cudnn +import torch.nn.functional as F +import torch.optim as optim +from tensorboardX import SummaryWriter +from torch import nn +from torchvision.utils import make_grid +from tqdm import tqdm + +from advent.model.discriminator import get_fc_discriminator +from advent.utils.func import adjust_learning_rate, adjust_learning_rate_discriminator +from advent.utils.func import loss_calc, bce_loss +from advent.utils.loss import entropy_loss +from advent.utils.func import prob_2_entropy +from advent.utils.viz_segmask import colorize_mask + + +def train_advent(model, trainloader, targetloader, cfg): + ''' UDA training with advent + ''' + # Create the model and start the training. + input_size_source = cfg.TRAIN.INPUT_SIZE_SOURCE + input_size_target = cfg.TRAIN.INPUT_SIZE_TARGET + device = cfg.GPU_ID + num_classes = cfg.NUM_CLASSES + viz_tensorboard = os.path.exists(cfg.TRAIN.TENSORBOARD_LOGDIR) + if viz_tensorboard: + writer = SummaryWriter(log_dir=cfg.TRAIN.TENSORBOARD_LOGDIR) + + # SEGMNETATION NETWORK + model.train() + model.to(device) + cudnn.benchmark = True + cudnn.enabled = True + + # DISCRIMINATOR NETWORK + # feature-level + d_aux = get_fc_discriminator(num_classes=num_classes) + d_aux.train() + d_aux.to(device) + + # seg maps, i.e. output, level + d_main = get_fc_discriminator(num_classes=num_classes) + d_main.train() + d_main.to(device) + + # OPTIMIZERS + # segnet's optimizer + optimizer = optim.SGD(model.optim_parameters(cfg.TRAIN.LEARNING_RATE), + lr=cfg.TRAIN.LEARNING_RATE, + momentum=cfg.TRAIN.MOMENTUM, + weight_decay=cfg.TRAIN.WEIGHT_DECAY) + + # discriminators' optimizers + optimizer_d_aux = optim.Adam(d_aux.parameters(), lr=cfg.TRAIN.LEARNING_RATE_D, + betas=(0.9, 0.99)) + optimizer_d_main = optim.Adam(d_main.parameters(), lr=cfg.TRAIN.LEARNING_RATE_D, + betas=(0.9, 0.99)) + + # interpolate output segmaps + interp = nn.Upsample(size=(input_size_source[1], input_size_source[0]), mode='bilinear', + align_corners=True) + interp_target = nn.Upsample(size=(input_size_target[1], input_size_target[0]), mode='bilinear', + align_corners=True) + + # labels for adversarial training + source_label = 0 + target_label = 1 + trainloader_iter = enumerate(trainloader) + targetloader_iter = enumerate(targetloader) + for i_iter in tqdm(range(cfg.TRAIN.EARLY_STOP + 1)): + + # reset optimizers + optimizer.zero_grad() + optimizer_d_aux.zero_grad() + optimizer_d_main.zero_grad() + # adapt LR if needed + adjust_learning_rate(optimizer, i_iter, cfg) + adjust_learning_rate_discriminator(optimizer_d_aux, i_iter, cfg) + adjust_learning_rate_discriminator(optimizer_d_main, i_iter, cfg) + + # UDA Training + # only train segnet. Don't accumulate grads in disciminators + for param in d_aux.parameters(): + param.requires_grad = False + for param in d_main.parameters(): + param.requires_grad = False + # train on source + _, batch = trainloader_iter.__next__() + images_source, labels, _, _ = batch + pred_src_aux, pred_src_main = model(images_source.cuda(device)) + if cfg.TRAIN.MULTI_LEVEL: + pred_src_aux = interp(pred_src_aux) + loss_seg_src_aux = loss_calc(pred_src_aux, labels, device) + else: + loss_seg_src_aux = 0 + pred_src_main = interp(pred_src_main) + loss_seg_src_main = loss_calc(pred_src_main, labels, device) + loss = (cfg.TRAIN.LAMBDA_SEG_MAIN * loss_seg_src_main + + cfg.TRAIN.LAMBDA_SEG_AUX * loss_seg_src_aux) + loss.backward() + + # adversarial training ot fool the discriminator + _, batch = targetloader_iter.__next__() + images, _, _, _ = batch + pred_trg_aux, pred_trg_main = model(images.cuda(device)) + if cfg.TRAIN.MULTI_LEVEL: + pred_trg_aux = interp_target(pred_trg_aux) + d_out_aux = d_aux(prob_2_entropy(F.softmax(pred_trg_aux))) + loss_adv_trg_aux = bce_loss(d_out_aux, source_label) + else: + loss_adv_trg_aux = 0 + pred_trg_main = interp_target(pred_trg_main) + d_out_main = d_main(prob_2_entropy(F.softmax(pred_trg_main))) + loss_adv_trg_main = bce_loss(d_out_main, source_label) + loss = (cfg.TRAIN.LAMBDA_ADV_MAIN * loss_adv_trg_main + + cfg.TRAIN.LAMBDA_ADV_AUX * loss_adv_trg_aux) + loss = loss + loss.backward() + + # Train discriminator networks + # enable training mode on discriminator networks + for param in d_aux.parameters(): + param.requires_grad = True + for param in d_main.parameters(): + param.requires_grad = True + # train with source + if cfg.TRAIN.MULTI_LEVEL: + pred_src_aux = pred_src_aux.detach() + d_out_aux = d_aux(prob_2_entropy(F.softmax(pred_src_aux))) + loss_d_aux = bce_loss(d_out_aux, source_label) + loss_d_aux = loss_d_aux / 2 + loss_d_aux.backward() + pred_src_main = pred_src_main.detach() + d_out_main = d_main(prob_2_entropy(F.softmax(pred_src_main))) + loss_d_main = bce_loss(d_out_main, source_label) + loss_d_main = loss_d_main / 2 + loss_d_main.backward() + + # train with target + if cfg.TRAIN.MULTI_LEVEL: + pred_trg_aux = pred_trg_aux.detach() + d_out_aux = d_aux(prob_2_entropy(F.softmax(pred_trg_aux))) + loss_d_aux = bce_loss(d_out_aux, target_label) + loss_d_aux = loss_d_aux / 2 + loss_d_aux.backward() + else: + loss_d_aux = 0 + pred_trg_main = pred_trg_main.detach() + d_out_main = d_main(prob_2_entropy(F.softmax(pred_trg_main))) + loss_d_main = bce_loss(d_out_main, target_label) + loss_d_main = loss_d_main / 2 + loss_d_main.backward() + + optimizer.step() + if cfg.TRAIN.MULTI_LEVEL: + optimizer_d_aux.step() + optimizer_d_main.step() + + current_losses = {'loss_seg_src_aux': loss_seg_src_aux, + 'loss_seg_src_main': loss_seg_src_main, + 'loss_adv_trg_aux': loss_adv_trg_aux, + 'loss_adv_trg_main': loss_adv_trg_main, + 'loss_d_aux': loss_d_aux, + 'loss_d_main': loss_d_main} + print_losses(current_losses, i_iter) + + if i_iter % cfg.TRAIN.SAVE_PRED_EVERY == 0 and i_iter != 0: + print('taking snapshot ...') + print('exp =', cfg.TRAIN.SNAPSHOT_DIR) + snapshot_dir = Path(cfg.TRAIN.SNAPSHOT_DIR) + torch.save(model.state_dict(), snapshot_dir / f'model_{i_iter}.pth') + torch.save(d_aux.state_dict(), snapshot_dir / f'model_{i_iter}_D_aux.pth') + torch.save(d_main.state_dict(), snapshot_dir / f'model_{i_iter}_D_main.pth') + if i_iter >= cfg.TRAIN.EARLY_STOP - 1: + break + sys.stdout.flush() + + # Visualize with tensorboard + if viz_tensorboard: + log_losses_tensorboard(writer, current_losses, i_iter) + + if i_iter % cfg.TRAIN.TENSORBOARD_VIZRATE == cfg.TRAIN.TENSORBOARD_VIZRATE - 1: + draw_in_tensorboard(writer, images, i_iter, pred_trg_main, num_classes, 'T') + draw_in_tensorboard(writer, images_source, i_iter, pred_src_main, num_classes, 'S') + + +def draw_in_tensorboard(writer, images, i_iter, pred_main, num_classes, type_): + grid_image = make_grid(images[:3].clone().cpu().data, 3, normalize=True) + writer.add_image(f'Image - {type_}', grid_image, i_iter) + + grid_image = make_grid(torch.from_numpy(np.array(colorize_mask(np.asarray( + np.argmax(F.softmax(pred_main).cpu().data[0].numpy().transpose(1, 2, 0), + axis=2), dtype=np.uint8)).convert('RGB')).transpose(2, 0, 1)), 3, + normalize=False, range=(0, 255)) + writer.add_image(f'Prediction - {type_}', grid_image, i_iter) + + output_sm = F.softmax(pred_main).cpu().data[0].numpy().transpose(1, 2, 0) + output_ent = np.sum(-np.multiply(output_sm, np.log2(output_sm)), axis=2, + keepdims=False) + grid_image = make_grid(torch.from_numpy(output_ent), 3, normalize=True, + range=(0, np.log2(num_classes))) + writer.add_image(f'Entropy - {type_}', grid_image, i_iter) + + +def train_minent(model, trainloader, targetloader, cfg): + ''' UDA training with minEnt + ''' + # Create the model and start the training. + input_size_source = cfg.TRAIN.INPUT_SIZE_SOURCE + input_size_target = cfg.TRAIN.INPUT_SIZE_TARGET + device = cfg.GPU_ID + num_classes = cfg.NUM_CLASSES + viz_tensorboard = os.path.exists(cfg.TRAIN.TENSORBOARD_LOGDIR) + if viz_tensorboard: + writer = SummaryWriter(log_dir=cfg.TRAIN.TENSORBOARD_LOGDIR) + + # SEGMNETATION NETWORK + model.train() + model.to(device) + cudnn.benchmark = True + cudnn.enabled = True + + # OPTIMIZERS + # segnet's optimizer + optimizer = optim.SGD(model.optim_parameters(cfg.TRAIN.LEARNING_RATE), + lr=cfg.TRAIN.LEARNING_RATE, + momentum=cfg.TRAIN.MOMENTUM, + weight_decay=cfg.TRAIN.WEIGHT_DECAY) + + # interpolate output segmaps + interp = nn.Upsample(size=(input_size_source[1], input_size_source[0]), mode='bilinear', + align_corners=True) + interp_target = nn.Upsample(size=(input_size_target[1], input_size_target[0]), mode='bilinear', + align_corners=True) + + trainloader_iter = enumerate(trainloader) + targetloader_iter = enumerate(targetloader) + for i_iter in tqdm(range(cfg.TRAIN.EARLY_STOP)): + + # reset optimizers + optimizer.zero_grad() + + # adapt LR if needed + adjust_learning_rate(optimizer, i_iter, cfg) + + # UDA Training + # train on source + _, batch = trainloader_iter.__next__() + images_source, labels, _, _ = batch + pred_src_aux, pred_src_main = model(images_source.cuda(device)) + if cfg.TRAIN.MULTI_LEVEL: + pred_src_aux = interp(pred_src_aux) + loss_seg_src_aux = loss_calc(pred_src_aux, labels, device) + else: + loss_seg_src_aux = 0 + pred_src_main = interp(pred_src_main) + loss_seg_src_main = loss_calc(pred_src_main, labels, device) + loss = (cfg.TRAIN.LAMBDA_SEG_MAIN * loss_seg_src_main + + cfg.TRAIN.LAMBDA_SEG_AUX * loss_seg_src_aux) + loss.backward() + + # adversarial training with minent + _, batch = targetloader_iter.__next__() + images, _, _, _ = batch + pred_trg_aux, pred_trg_main = model(images.cuda(device)) + pred_trg_aux = interp_target(pred_trg_aux) + pred_trg_main = interp_target(pred_trg_main) + pred_prob_trg_aux = F.softmax(pred_trg_aux) + pred_prob_trg_main = F.softmax(pred_trg_main) + + loss_target_entp_aux = entropy_loss(pred_prob_trg_aux) + loss_target_entp_main = entropy_loss(pred_prob_trg_main) + loss = (cfg.TRAIN.LAMBDA_ENT_AUX * loss_target_entp_aux + + cfg.TRAIN.LAMBDA_ENT_MAIN * loss_target_entp_main) + loss.backward() + optimizer.step() + + current_losses = {'loss_seg_src_aux': loss_seg_src_aux, + 'loss_seg_src_main': loss_seg_src_main, + 'loss_ent_aux': loss_target_entp_aux, + 'loss_ent_main': loss_target_entp_main} + + print_losses(current_losses, i_iter) + + if i_iter % cfg.TRAIN.SAVE_PRED_EVERY == 0 and i_iter != 0: + print('taking snapshot ...') + print('exp =', cfg.TRAIN.SNAPSHOT_DIR) + torch.save(model.state_dict(), + osp.join(cfg.TRAIN.SNAPSHOT_DIR, f'model_{i_iter}.pth')) + if i_iter >= cfg.TRAIN.EARLY_STOP - 1: + break + sys.stdout.flush() + + # Visualize with tensorboard + if viz_tensorboard: + log_losses_tensorboard(writer, current_losses, i_iter) + + if i_iter % cfg.TRAIN.TENSORBOARD_VIZRATE == cfg.TRAIN.TENSORBOARD_VIZRATE - 1: + draw_in_tensorboard(writer, images, i_iter, pred_trg_main, num_classes, 'T') + draw_in_tensorboard(writer, images_source, i_iter, pred_src_main, num_classes, 'S') + + +def print_losses(current_losses, i_iter): + list_strings = [] + for loss_name, loss_value in current_losses.items(): + list_strings.append(f'{loss_name} = {to_numpy(loss_value):.3f} ') + full_string = ' '.join(list_strings) + tqdm.write(f'iter = {i_iter} {full_string}') + + +def log_losses_tensorboard(writer, current_losses, i_iter): + for loss_name, loss_value in current_losses.items(): + writer.add_scalar(f'data/{loss_name}', to_numpy(loss_value), i_iter) + + +def to_numpy(tensor): + if isinstance(tensor, (int, float)): + return tensor + else: + return tensor.data.cpu().numpy() + + +def train_domain_adaptation(model, trainloader, targetloader, cfg): + if cfg.TRAIN.DA_METHOD == 'MinEnt': + train_minent(model, trainloader, targetloader, cfg) + elif cfg.TRAIN.DA_METHOD == 'AdvEnt': + train_advent(model, trainloader, targetloader, cfg) + else: + raise NotImplementedError(f"Not yet supported DA method {cfg.TRAIN.DA_METHOD}") diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/model/__init__.py b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/model/__init__.py index 55887fca32..945cb920d4 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/model/__init__.py +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/model/__init__.py @@ -1,13 +1,13 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/advent+minent_pretrained.yml b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/advent+minent_pretrained.yml index 7e274313c5..a423a0b559 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/advent+minent_pretrained.yml +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/advent+minent_pretrained.yml @@ -1,18 +1,18 @@ -SOURCE: GTA -TARGET: Cityscapes -EXP_NAME: GTA2Cityscapes_AdvEnt_MinEnt -NUM_WORKERS: 4 -TEST: - MODE: single - MODEL: - - DeepLabv2 - - DeepLabv2 - MULTI_LEVEL: - - True - - True - RESTORE_FROM: - - ../../pretrained_models/gta2cityscapes_advent.pth - - ../../pretrained_models/gta2cityscapes_minent_ER.pth - MODEL_WEIGHT: - - 0.5 +SOURCE: GTA +TARGET: Cityscapes +EXP_NAME: GTA2Cityscapes_AdvEnt_MinEnt +NUM_WORKERS: 4 +TEST: + MODE: single + MODEL: + - DeepLabv2 + - DeepLabv2 + MULTI_LEVEL: + - True + - True + RESTORE_FROM: + - ../../pretrained_models/gta2cityscapes_advent.pth + - ../../pretrained_models/gta2cityscapes_minent_ER.pth + MODEL_WEIGHT: + - 0.5 - 0.5 \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/advent_cyclegan_pretrained.yml b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/advent_cyclegan_pretrained.yml index 881a9defef..3840244b80 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/advent_cyclegan_pretrained.yml +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/advent_cyclegan_pretrained.yml @@ -1,8 +1,8 @@ -SOURCE: GTA -TARGET: Cityscapes -EXP_NAME: GTA2Cityscapes_AdvEnt_CycleGAN -NUM_WORKERS: 4 -TEST: - MODE: single - RESTORE_FROM: +SOURCE: GTA +TARGET: Cityscapes +EXP_NAME: GTA2Cityscapes_AdvEnt_CycleGAN +NUM_WORKERS: 4 +TEST: + MODE: single + RESTORE_FROM: - ../../pretrained_models/gta2cityscapes_advent_cyclegan.pth \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/advent_pretrained.yml b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/advent_pretrained.yml index 85a2f7ac4d..2e35e98857 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/advent_pretrained.yml +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/advent_pretrained.yml @@ -1,8 +1,8 @@ -SOURCE: GTA -TARGET: Cityscapes -EXP_NAME: GTA2Cityscapes_AdvEnt -NUM_WORKERS: 4 -TEST: - MODE: single - RESTORE_FROM: +SOURCE: GTA +TARGET: Cityscapes +EXP_NAME: GTA2Cityscapes_AdvEnt +NUM_WORKERS: 4 +TEST: + MODE: single + RESTORE_FROM: - ../../pretrained_models/gta2cityscapes_advent.pth \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/minent.yml b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/minent.yml index 3ddef6dc8f..6c85e84545 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/minent.yml +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/minent.yml @@ -1,12 +1,12 @@ -SOURCE: GTA -TARGET: Cityscapes -NUM_WORKERS: 4 -TRAIN: - DA_METHOD: MinEnt - MODEL: DeepLabv2 - RESTORE_FROM: ../../pretrained_models/DeepLab_resnet_pretrained_imagenet.pth - MULTI_LEVEL: True - LAMBDA_ENT_MAIN: 0.001 - LAMBDA_ENT_AUX: 0.0002 -TEST: +SOURCE: GTA +TARGET: Cityscapes +NUM_WORKERS: 4 +TRAIN: + DA_METHOD: MinEnt + MODEL: DeepLabv2 + RESTORE_FROM: ../../pretrained_models/DeepLab_resnet_pretrained_imagenet.pth + MULTI_LEVEL: True + LAMBDA_ENT_MAIN: 0.001 + LAMBDA_ENT_AUX: 0.0002 +TEST: MODE: best \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/minent_pretrained.yml b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/minent_pretrained.yml index 7385d86483..5ccf3a3c17 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/minent_pretrained.yml +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/configs/minent_pretrained.yml @@ -1,9 +1,9 @@ -SOURCE: GTA -TARGET: Cityscapes -EXP_NAME: GTA2Cityscapes_MinEnt -NUM_WORKERS: 4 -TEST: - MODE: single - RESTORE_FROM: - - ../../pretrained_models/gta2cityscapes_minent_ER.pth +SOURCE: GTA +TARGET: Cityscapes +EXP_NAME: GTA2Cityscapes_MinEnt +NUM_WORKERS: 4 +TEST: + MODE: single + RESTORE_FROM: + - ../../pretrained_models/gta2cityscapes_minent_ER.pth # - ../../pretrained_models/gta2cityscapes_minent.pth \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/test.py b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/test.py index d6545bbdc3..f88cfed0c9 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/test.py +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/test.py @@ -1,109 +1,109 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -# -------------------------------------------------------- -# AdvEnt training -# Copyright (c) 2019 valeo.ai -# -# Written by Tuan-Hung Vu -# -------------------------------------------------------- -import sys -sys.path.append('/home/feipan/IntraDA/ADVENT') -import pdb - -import argparse -import os -import os.path as osp -import pprint -import warnings - -from torch.utils import data - -from advent.model.deeplabv2 import get_deeplab_v2 -from advent.dataset.cityscapes import CityscapesDataSet -from advent.domain_adaptation.config import cfg, cfg_from_file -from advent.domain_adaptation.eval_UDA import evaluate_domain_adaptation - -warnings.filterwarnings("ignore", message="numpy.dtype size changed") -warnings.filterwarnings("ignore") - - - -def get_arguments(): - """ - Parse input arguments - """ - parser = argparse.ArgumentParser(description="Code for evaluation") - parser.add_argument('--cfg', type=str, default=None, - help='optional config file', ) - parser.add_argument("--exp-suffix", type=str, default=None, - help="optional experiment suffix") - return parser.parse_args() - - -def main(config_file, exp_suffix): - # LOAD ARGS - assert config_file is not None, 'Missing cfg file' - cfg_from_file(config_file) - # auto-generate exp name if not specified - if cfg.EXP_NAME == '': - cfg.EXP_NAME = f'{cfg.SOURCE}2{cfg.TARGET}_{cfg.TRAIN.MODEL}_{cfg.TRAIN.DA_METHOD}' - if exp_suffix: - cfg.EXP_NAME += f'_{exp_suffix}' - # auto-generate snapshot path if not specified - if cfg.TEST.SNAPSHOT_DIR[0] == '': - cfg.TEST.SNAPSHOT_DIR[0] = osp.join(cfg.EXP_ROOT_SNAPSHOT, cfg.EXP_NAME) - os.makedirs(cfg.TEST.SNAPSHOT_DIR[0], exist_ok=True) - - print('Using config:') - pprint.pprint(cfg) - # load models - models = [] - n_models = len(cfg.TEST.MODEL) - if cfg.TEST.MODE == 'best': - assert n_models == 1, 'Not yet supported' - for i in range(n_models): - if cfg.TEST.MODEL[i] == 'DeepLabv2': - model = get_deeplab_v2(num_classes=cfg.NUM_CLASSES, - multi_level=cfg.TEST.MULTI_LEVEL[i]) - else: - raise NotImplementedError(f"Not yet supported {cfg.TEST.MODEL[i]}") - models.append(model) - - if os.environ.get('ADVENT_DRY_RUN', '0') == '1': - return - - # dataloaders - pdb.set_trace() - test_dataset = CityscapesDataSet(root=cfg.DATA_DIRECTORY_TARGET, - list_path=cfg.DATA_LIST_TARGET, - set=cfg.TEST.SET_TARGET, - info_path=cfg.TEST.INFO_TARGET, - crop_size=cfg.TEST.INPUT_SIZE_TARGET, - mean=cfg.TEST.IMG_MEAN, - labels_size=cfg.TEST.OUTPUT_SIZE_TARGET) - test_loader = data.DataLoader(test_dataset, - batch_size=cfg.TEST.BATCH_SIZE_TARGET, - num_workers=cfg.NUM_WORKERS, - shuffle=False, - pin_memory=True) - # eval - evaluate_domain_adaptation(models, test_loader, cfg) - - -if __name__ == '__main__': - args = get_arguments() - print('Called with args:') - print(args) - main(args.cfg, args.exp_suffix) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +# -------------------------------------------------------- +# AdvEnt training +# Copyright (c) 2019 valeo.ai +# +# Written by Tuan-Hung Vu +# -------------------------------------------------------- +import sys +sys.path.append('/home/feipan/IntraDA/ADVENT') +import pdb + +import argparse +import os +import os.path as osp +import pprint +import warnings + +from torch.utils import data + +from advent.model.deeplabv2 import get_deeplab_v2 +from advent.dataset.cityscapes import CityscapesDataSet +from advent.domain_adaptation.config import cfg, cfg_from_file +from advent.domain_adaptation.eval_UDA import evaluate_domain_adaptation + +warnings.filterwarnings("ignore", message="numpy.dtype size changed") +warnings.filterwarnings("ignore") + + + +def get_arguments(): + """ + Parse input arguments + """ + parser = argparse.ArgumentParser(description="Code for evaluation") + parser.add_argument('--cfg', type=str, default=None, + help='optional config file', ) + parser.add_argument("--exp-suffix", type=str, default=None, + help="optional experiment suffix") + return parser.parse_args() + + +def main(config_file, exp_suffix): + # LOAD ARGS + assert config_file is not None, 'Missing cfg file' + cfg_from_file(config_file) + # auto-generate exp name if not specified + if cfg.EXP_NAME == '': + cfg.EXP_NAME = f'{cfg.SOURCE}2{cfg.TARGET}_{cfg.TRAIN.MODEL}_{cfg.TRAIN.DA_METHOD}' + if exp_suffix: + cfg.EXP_NAME += f'_{exp_suffix}' + # auto-generate snapshot path if not specified + if cfg.TEST.SNAPSHOT_DIR[0] == '': + cfg.TEST.SNAPSHOT_DIR[0] = osp.join(cfg.EXP_ROOT_SNAPSHOT, cfg.EXP_NAME) + os.makedirs(cfg.TEST.SNAPSHOT_DIR[0], exist_ok=True) + + print('Using config:') + pprint.pprint(cfg) + # load models + models = [] + n_models = len(cfg.TEST.MODEL) + if cfg.TEST.MODE == 'best': + assert n_models == 1, 'Not yet supported' + for i in range(n_models): + if cfg.TEST.MODEL[i] == 'DeepLabv2': + model = get_deeplab_v2(num_classes=cfg.NUM_CLASSES, + multi_level=cfg.TEST.MULTI_LEVEL[i]) + else: + raise NotImplementedError(f"Not yet supported {cfg.TEST.MODEL[i]}") + models.append(model) + + if os.environ.get('ADVENT_DRY_RUN', '0') == '1': + return + + # dataloaders + pdb.set_trace() + test_dataset = CityscapesDataSet(root=cfg.DATA_DIRECTORY_TARGET, + list_path=cfg.DATA_LIST_TARGET, + set=cfg.TEST.SET_TARGET, + info_path=cfg.TEST.INFO_TARGET, + crop_size=cfg.TEST.INPUT_SIZE_TARGET, + mean=cfg.TEST.IMG_MEAN, + labels_size=cfg.TEST.OUTPUT_SIZE_TARGET) + test_loader = data.DataLoader(test_dataset, + batch_size=cfg.TEST.BATCH_SIZE_TARGET, + num_workers=cfg.NUM_WORKERS, + shuffle=False, + pin_memory=True) + # eval + evaluate_domain_adaptation(models, test_loader, cfg) + + +if __name__ == '__main__': + args = get_arguments() + print('Called with args:') + print(args) + main(args.cfg, args.exp_suffix) diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/train.py b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/train.py index 80a915ab20..3109bd535d 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/train.py +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/scripts/train.py @@ -1,159 +1,159 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -# -------------------------------------------------------- -# AdvEnt training -# Copyright (c) 2019 valeo.ai -# -# Written by Tuan-Hung Vu -# -------------------------------------------------------- -import argparse -import os -import os.path as osp -import pprint -import random -import warnings - -import numpy as np -import yaml -import torch -from torch.utils import data - -from advent.model.deeplabv2 import get_deeplab_v2 -from advent.dataset.gta5 import GTA5DataSet -from advent.dataset.cityscapes import CityscapesDataSet -from advent.domain_adaptation.config import cfg, cfg_from_file -from advent.domain_adaptation.train_UDA import train_domain_adaptation - -warnings.filterwarnings("ignore", message="numpy.dtype size changed") -warnings.filterwarnings("ignore") - - -def get_arguments(): - """ - Parse input arguments - """ - parser = argparse.ArgumentParser(description="Code for domain adaptation (DA) training") - parser.add_argument('--cfg', type=str, default=None, - help='optional config file', ) - parser.add_argument("--random-train", action="store_true", - help="not fixing random seed.") - parser.add_argument("--tensorboard", action="store_true", - help="visualize training loss with tensorboardX.") - parser.add_argument("--viz-every-iter", type=int, default=None, - help="visualize results.") - parser.add_argument("--exp-suffix", type=str, default=None, - help="optional experiment suffix") - return parser.parse_args() - - -def main(): - # LOAD ARGS - args = get_arguments() - print('Called with args:') - print(args) - - assert args.cfg is not None, 'Missing cfg file' - cfg_from_file(args.cfg) - # auto-generate exp name if not specified - if cfg.EXP_NAME == '': - cfg.EXP_NAME = f'{cfg.SOURCE}2{cfg.TARGET}_{cfg.TRAIN.MODEL}_{cfg.TRAIN.DA_METHOD}' - - if args.exp_suffix: - cfg.EXP_NAME += f'_{args.exp_suffix}' - # auto-generate snapshot path if not specified - if cfg.TRAIN.SNAPSHOT_DIR == '': - cfg.TRAIN.SNAPSHOT_DIR = osp.join(cfg.EXP_ROOT_SNAPSHOT, cfg.EXP_NAME) - os.makedirs(cfg.TRAIN.SNAPSHOT_DIR, exist_ok=True) - # tensorboard - if args.tensorboard: - if cfg.TRAIN.TENSORBOARD_LOGDIR == '': - cfg.TRAIN.TENSORBOARD_LOGDIR = osp.join(cfg.EXP_ROOT_LOGS, 'tensorboard', cfg.EXP_NAME) - os.makedirs(cfg.TRAIN.TENSORBOARD_LOGDIR, exist_ok=True) - if args.viz_every_iter is not None: - cfg.TRAIN.TENSORBOARD_VIZRATE = args.viz_every_iter - else: - cfg.TRAIN.TENSORBOARD_LOGDIR = '' - print('Using config:') - pprint.pprint(cfg) - - # INIT - _init_fn = None - if not args.random_train: - torch.manual_seed(cfg.TRAIN.RANDOM_SEED) - torch.cuda.manual_seed(cfg.TRAIN.RANDOM_SEED) - np.random.seed(cfg.TRAIN.RANDOM_SEED) - random.seed(cfg.TRAIN.RANDOM_SEED) - - def _init_fn(worker_id): - np.random.seed(cfg.TRAIN.RANDOM_SEED + worker_id) - - if os.environ.get('ADVENT_DRY_RUN', '0') == '1': - return - - # LOAD SEGMENTATION NET - assert osp.exists(cfg.TRAIN.RESTORE_FROM), f'Missing init model {cfg.TRAIN.RESTORE_FROM}' - if cfg.TRAIN.MODEL == 'DeepLabv2': - model = get_deeplab_v2(num_classes=cfg.NUM_CLASSES, multi_level=cfg.TRAIN.MULTI_LEVEL) - saved_state_dict = torch.load(cfg.TRAIN.RESTORE_FROM) - if 'DeepLab_resnet_pretrained_imagenet' in cfg.TRAIN.RESTORE_FROM: - new_params = model.state_dict().copy() - for i in saved_state_dict: - i_parts = i.split('.') - if not i_parts[1] == 'layer5': - new_params['.'.join(i_parts[1:])] = saved_state_dict[i] - model.load_state_dict(new_params) - else: - model.load_state_dict(saved_state_dict) - else: - raise NotImplementedError(f"Not yet supported {cfg.TRAIN.MODEL}") - print('Model loaded') - - # DATALOADERS - source_dataset = GTA5DataSet(root=cfg.DATA_DIRECTORY_SOURCE, - list_path=cfg.DATA_LIST_SOURCE, - set=cfg.TRAIN.SET_SOURCE, - max_iters=cfg.TRAIN.MAX_ITERS * cfg.TRAIN.BATCH_SIZE_SOURCE, - crop_size=cfg.TRAIN.INPUT_SIZE_SOURCE, - mean=cfg.TRAIN.IMG_MEAN) - source_loader = data.DataLoader(source_dataset, - batch_size=cfg.TRAIN.BATCH_SIZE_SOURCE, - num_workers=cfg.NUM_WORKERS, - shuffle=True, - pin_memory=True, - worker_init_fn=_init_fn) - - target_dataset = CityscapesDataSet(root=cfg.DATA_DIRECTORY_TARGET, - list_path=cfg.DATA_LIST_TARGET, - set=cfg.TRAIN.SET_TARGET, - info_path=cfg.TRAIN.INFO_TARGET, - max_iters=cfg.TRAIN.MAX_ITERS * cfg.TRAIN.BATCH_SIZE_TARGET, - crop_size=cfg.TRAIN.INPUT_SIZE_TARGET, - mean=cfg.TRAIN.IMG_MEAN) - target_loader = data.DataLoader(target_dataset, - batch_size=cfg.TRAIN.BATCH_SIZE_TARGET, - num_workers=cfg.NUM_WORKERS, - shuffle=True, - pin_memory=True, - worker_init_fn=_init_fn) - - with open(osp.join(cfg.TRAIN.SNAPSHOT_DIR, 'train_cfg.yml'), 'w') as yaml_file: - yaml.dump(cfg, yaml_file, default_flow_style=False) - - # UDA TRAINING - train_domain_adaptation(model, source_loader, target_loader, cfg) - - -if __name__ == '__main__': - main() +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +# -------------------------------------------------------- +# AdvEnt training +# Copyright (c) 2019 valeo.ai +# +# Written by Tuan-Hung Vu +# -------------------------------------------------------- +import argparse +import os +import os.path as osp +import pprint +import random +import warnings + +import numpy as np +import yaml +import torch +from torch.utils import data + +from advent.model.deeplabv2 import get_deeplab_v2 +from advent.dataset.gta5 import GTA5DataSet +from advent.dataset.cityscapes import CityscapesDataSet +from advent.domain_adaptation.config import cfg, cfg_from_file +from advent.domain_adaptation.train_UDA import train_domain_adaptation + +warnings.filterwarnings("ignore", message="numpy.dtype size changed") +warnings.filterwarnings("ignore") + + +def get_arguments(): + """ + Parse input arguments + """ + parser = argparse.ArgumentParser(description="Code for domain adaptation (DA) training") + parser.add_argument('--cfg', type=str, default=None, + help='optional config file', ) + parser.add_argument("--random-train", action="store_true", + help="not fixing random seed.") + parser.add_argument("--tensorboard", action="store_true", + help="visualize training loss with tensorboardX.") + parser.add_argument("--viz-every-iter", type=int, default=None, + help="visualize results.") + parser.add_argument("--exp-suffix", type=str, default=None, + help="optional experiment suffix") + return parser.parse_args() + + +def main(): + # LOAD ARGS + args = get_arguments() + print('Called with args:') + print(args) + + assert args.cfg is not None, 'Missing cfg file' + cfg_from_file(args.cfg) + # auto-generate exp name if not specified + if cfg.EXP_NAME == '': + cfg.EXP_NAME = f'{cfg.SOURCE}2{cfg.TARGET}_{cfg.TRAIN.MODEL}_{cfg.TRAIN.DA_METHOD}' + + if args.exp_suffix: + cfg.EXP_NAME += f'_{args.exp_suffix}' + # auto-generate snapshot path if not specified + if cfg.TRAIN.SNAPSHOT_DIR == '': + cfg.TRAIN.SNAPSHOT_DIR = osp.join(cfg.EXP_ROOT_SNAPSHOT, cfg.EXP_NAME) + os.makedirs(cfg.TRAIN.SNAPSHOT_DIR, exist_ok=True) + # tensorboard + if args.tensorboard: + if cfg.TRAIN.TENSORBOARD_LOGDIR == '': + cfg.TRAIN.TENSORBOARD_LOGDIR = osp.join(cfg.EXP_ROOT_LOGS, 'tensorboard', cfg.EXP_NAME) + os.makedirs(cfg.TRAIN.TENSORBOARD_LOGDIR, exist_ok=True) + if args.viz_every_iter is not None: + cfg.TRAIN.TENSORBOARD_VIZRATE = args.viz_every_iter + else: + cfg.TRAIN.TENSORBOARD_LOGDIR = '' + print('Using config:') + pprint.pprint(cfg) + + # INIT + _init_fn = None + if not args.random_train: + torch.manual_seed(cfg.TRAIN.RANDOM_SEED) + torch.cuda.manual_seed(cfg.TRAIN.RANDOM_SEED) + np.random.seed(cfg.TRAIN.RANDOM_SEED) + random.seed(cfg.TRAIN.RANDOM_SEED) + + def _init_fn(worker_id): + np.random.seed(cfg.TRAIN.RANDOM_SEED + worker_id) + + if os.environ.get('ADVENT_DRY_RUN', '0') == '1': + return + + # LOAD SEGMENTATION NET + assert osp.exists(cfg.TRAIN.RESTORE_FROM), f'Missing init model {cfg.TRAIN.RESTORE_FROM}' + if cfg.TRAIN.MODEL == 'DeepLabv2': + model = get_deeplab_v2(num_classes=cfg.NUM_CLASSES, multi_level=cfg.TRAIN.MULTI_LEVEL) + saved_state_dict = torch.load(cfg.TRAIN.RESTORE_FROM) + if 'DeepLab_resnet_pretrained_imagenet' in cfg.TRAIN.RESTORE_FROM: + new_params = model.state_dict().copy() + for i in saved_state_dict: + i_parts = i.split('.') + if not i_parts[1] == 'layer5': + new_params['.'.join(i_parts[1:])] = saved_state_dict[i] + model.load_state_dict(new_params) + else: + model.load_state_dict(saved_state_dict) + else: + raise NotImplementedError(f"Not yet supported {cfg.TRAIN.MODEL}") + print('Model loaded') + + # DATALOADERS + source_dataset = GTA5DataSet(root=cfg.DATA_DIRECTORY_SOURCE, + list_path=cfg.DATA_LIST_SOURCE, + set=cfg.TRAIN.SET_SOURCE, + max_iters=cfg.TRAIN.MAX_ITERS * cfg.TRAIN.BATCH_SIZE_SOURCE, + crop_size=cfg.TRAIN.INPUT_SIZE_SOURCE, + mean=cfg.TRAIN.IMG_MEAN) + source_loader = data.DataLoader(source_dataset, + batch_size=cfg.TRAIN.BATCH_SIZE_SOURCE, + num_workers=cfg.NUM_WORKERS, + shuffle=True, + pin_memory=True, + worker_init_fn=_init_fn) + + target_dataset = CityscapesDataSet(root=cfg.DATA_DIRECTORY_TARGET, + list_path=cfg.DATA_LIST_TARGET, + set=cfg.TRAIN.SET_TARGET, + info_path=cfg.TRAIN.INFO_TARGET, + max_iters=cfg.TRAIN.MAX_ITERS * cfg.TRAIN.BATCH_SIZE_TARGET, + crop_size=cfg.TRAIN.INPUT_SIZE_TARGET, + mean=cfg.TRAIN.IMG_MEAN) + target_loader = data.DataLoader(target_dataset, + batch_size=cfg.TRAIN.BATCH_SIZE_TARGET, + num_workers=cfg.NUM_WORKERS, + shuffle=True, + pin_memory=True, + worker_init_fn=_init_fn) + + with open(osp.join(cfg.TRAIN.SNAPSHOT_DIR, 'train_cfg.yml'), 'w') as yaml_file: + yaml.dump(cfg, yaml_file, default_flow_style=False) + + # UDA TRAINING + train_domain_adaptation(model, source_loader, target_loader, cfg) + + +if __name__ == '__main__': + main() diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/utils/func.py b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/utils/func.py index a57a26d522..0ff54adcd3 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/utils/func.py +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/utils/func.py @@ -1,75 +1,75 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 numpy as np -import torch -import torch.nn as nn - -from advent.utils.loss import cross_entropy_2d - - -def bce_loss(y_pred, y_label): - y_truth_tensor = torch.FloatTensor(y_pred.size()) - y_truth_tensor.fill_(y_label) - y_truth_tensor = y_truth_tensor.to(y_pred.get_device()) - return nn.BCEWithLogitsLoss()(y_pred, y_truth_tensor) - - -def loss_calc(pred, label, device): - """ - This function returns cross entropy loss for semantic segmentation - """ - # out shape batch_size x channels x h x w -> batch_size x channels x h x w - # label shape h x w x 1 x batch_size -> batch_size x 1 x h x w - label = label.long().to(device) - return cross_entropy_2d(pred, label) - - -def lr_poly(base_lr, iter, max_iter, power): - """ Poly_LR scheduler - """ - return base_lr * ((1 - float(iter) / max_iter) ** power) - - -def _adjust_learning_rate(optimizer, i_iter, cfg, learning_rate): - lr = lr_poly(learning_rate, i_iter, cfg.TRAIN.MAX_ITERS, cfg.TRAIN.POWER) - optimizer.param_groups[0]['lr'] = lr - if len(optimizer.param_groups) > 1: - optimizer.param_groups[1]['lr'] = lr * 10 - - -def adjust_learning_rate(optimizer, i_iter, cfg): - """ adject learning rate for main segnet - """ - _adjust_learning_rate(optimizer, i_iter, cfg, cfg.TRAIN.LEARNING_RATE) - - -def adjust_learning_rate_discriminator(optimizer, i_iter, cfg): - _adjust_learning_rate(optimizer, i_iter, cfg, cfg.TRAIN.LEARNING_RATE_D) - - -def prob_2_entropy(prob): - """ convert probabilistic prediction maps to weighted self-information maps - """ - n, c, h, w = prob.size() - return -torch.mul(prob, torch.log2(prob + 1e-30)) / np.log2(c) - - -def fast_hist(a, b, n): - k = (a >= 0) & (a < n) - return np.bincount(n * a[k].astype(int) + b[k], minlength=n ** 2).reshape(n, n) - - -def per_class_iu(hist): - return np.diag(hist) / (hist.sum(1) + hist.sum(0) - np.diag(hist)) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 numpy as np +import torch +import torch.nn as nn + +from advent.utils.loss import cross_entropy_2d + + +def bce_loss(y_pred, y_label): + y_truth_tensor = torch.FloatTensor(y_pred.size()) + y_truth_tensor.fill_(y_label) + y_truth_tensor = y_truth_tensor.to(y_pred.get_device()) + return nn.BCEWithLogitsLoss()(y_pred, y_truth_tensor) + + +def loss_calc(pred, label, device): + """ + This function returns cross entropy loss for semantic segmentation + """ + # out shape batch_size x channels x h x w -> batch_size x channels x h x w + # label shape h x w x 1 x batch_size -> batch_size x 1 x h x w + label = label.long().to(device) + return cross_entropy_2d(pred, label) + + +def lr_poly(base_lr, iter, max_iter, power): + """ Poly_LR scheduler + """ + return base_lr * ((1 - float(iter) / max_iter) ** power) + + +def _adjust_learning_rate(optimizer, i_iter, cfg, learning_rate): + lr = lr_poly(learning_rate, i_iter, cfg.TRAIN.MAX_ITERS, cfg.TRAIN.POWER) + optimizer.param_groups[0]['lr'] = lr + if len(optimizer.param_groups) > 1: + optimizer.param_groups[1]['lr'] = lr * 10 + + +def adjust_learning_rate(optimizer, i_iter, cfg): + """ adject learning rate for main segnet + """ + _adjust_learning_rate(optimizer, i_iter, cfg, cfg.TRAIN.LEARNING_RATE) + + +def adjust_learning_rate_discriminator(optimizer, i_iter, cfg): + _adjust_learning_rate(optimizer, i_iter, cfg, cfg.TRAIN.LEARNING_RATE_D) + + +def prob_2_entropy(prob): + """ convert probabilistic prediction maps to weighted self-information maps + """ + n, c, h, w = prob.size() + return -torch.mul(prob, torch.log2(prob + 1e-30)) / np.log2(c) + + +def fast_hist(a, b, n): + k = (a >= 0) & (a < n) + return np.bincount(n * a[k].astype(int) + b[k], minlength=n ** 2).reshape(n, n) + + +def per_class_iu(hist): + return np.diag(hist) / (hist.sum(1) + hist.sum(0) - np.diag(hist)) diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/utils/viz_segmask.py b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/utils/viz_segmask.py index 0fc82ad3ec..949396b6c7 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/utils/viz_segmask.py +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/advent/utils/viz_segmask.py @@ -1,34 +1,34 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 numpy as np -from PIL import Image - -palette = [128, 64, 128, 244, 35, 232, 70, 70, 70, 102, 102, 156, - 190, 153, 153, 153, 153, 153, 250, - 170, 30, - 220, 220, 0, 107, 142, 35, 152, 251, 152, - 70, 130, 180, 220, 20, 60, 255, 0, 0, 0, 0, - 142, 0, 0, 70, - 0, 60, 100, 0, 80, 100, 0, 0, 230, 119, 11, 32] -zero_pad = 256 * 3 - len(palette) -for i in range(zero_pad): - palette.append(0) - - -def colorize_mask(mask): - # mask: numpy array of the mask - new_mask = Image.fromarray(mask.astype(np.uint8)).convert('P') - new_mask.putpalette(palette) - return new_mask +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 numpy as np +from PIL import Image + +palette = [128, 64, 128, 244, 35, 232, 70, 70, 70, 102, 102, 156, + 190, 153, 153, 153, 153, 153, 250, + 170, 30, + 220, 220, 0, 107, 142, 35, 152, 251, 152, + 70, 130, 180, 220, 20, 60, 255, 0, 0, 0, 0, + 142, 0, 0, 70, + 0, 60, 100, 0, 80, 100, 0, 0, 230, 119, 11, 32] +zero_pad = 256 * 3 - len(palette) +for i in range(zero_pad): + palette.append(0) + + +def colorize_mask(mask): + # mask: numpy array of the mask + new_mask = Image.fromarray(mask.astype(np.uint8)).convert('P') + new_mask.putpalette(palette) + return new_mask diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/modelzoo_level.txt b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/modelzoo_level.txt +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/requirements.txt b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/requirements.txt index fa53715441..e03d22e457 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/requirements.txt +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/ADVENT/requirements.txt @@ -1,2 +1,2 @@ -torch==1.5.0 -torchvision==0.6.0 +torch==1.5.0 +torchvision==0.6.0 diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/LICENSE b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/LICENSE index eeac88fb9d..56ee3c8c4c 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/LICENSE +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/LICENSE @@ -1,201 +1,201 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/README.md b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/README.md index 2de9b5ac6a..22445b46eb 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/README.md +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/README.md @@ -1,77 +1,77 @@ -# IntraDA - -- 参考实现: -``` -url=https://github.com/feipan664/IntraDA.git -branch=master -commit_id=070b0b702fe94a34288eba4ca990410b5aaadc4a -``` - -## IntraDA Detail - -- 增加了混合精度训练 -- 增加了多卡分布式训练 -- 优化了loss在NPU上的计算效率 - -## Requirements - -- CANN 5.0.2 -- torch 1.5.0+ascend.post3.20210824 -- apex 0.1+ascend.20210824 -- 安装ADVENT - ``` - cd IntraDA/ADVENT - pip3 install -e . - ``` -- 下载[CityScapes数据集](https://www.cityscapes-dataset.com/downloads/) - 在IntraDA/ADVENT目录下创建data文件夹,将数据集按照如下结构放入data目录: - ``` - |-- ADVENT - | |-- data - | | `-- Cityscapes - | | |-- gtFine - | | `-- leftImg8bit - ``` -- 下载以下两个预训练模型: - ImageNet预训练模型: - https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/semantic_segmentation/IntraDA/DeepLab_resnet_pretrained_imagenet.pth - ADVENT warmup模型: - https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/semantic_segmentation/IntraDA/gta2cityscapes_advent.pth - 在IntraDA/ADVENT目录下创建pretrained_models文件夹,将以上2个模型放入改文件夹,目录结构如下: - ``` - |-- ADVENT - | |-- pretrained_models - | | |-- DeepLab_resnet_pretrained_imagenet.pth - | | `-- gta2cityscapes_advent.pth - ``` -- 生成训练用的伪标签及数据集分组文件: - ``` - cd IntraDA/entropy_rank/ - bash gen_color_mask_npu.sh - ``` - - -## Training - -```bash -cd IntraDA/intrada - -# 1p train perf 运行 500 step, 输出 performance_1p.log 文件 -bash test/train_performance_1p.sh - -# 8p train perf 运行 500 step, 输出 performance_8p.log 文件 -bash test/train_performance_8p.sh - -# 8p train full 完整训练并保存checkpoints,中间不会测试 -bash test/train_full_8p.sh - -# eval 测试8p训练保存的 checkpoints 得到精度信息 -bash test/train_eval_8p.sh -``` - -## IntraDA training result - -| mIoU | FPS | Npu_nums | Epochs | AMP_Type | -| :------: | :------: | :------: | :------: | :------: | -| | 2.7 | 1 | - | O2 | -| 42.55 | 21 | 8 | - | O2 | +# IntraDA + +- 参考实现: +``` +url=https://github.com/feipan664/IntraDA.git +branch=master +commit_id=070b0b702fe94a34288eba4ca990410b5aaadc4a +``` + +## IntraDA Detail + +- 增加了混合精度训练 +- 增加了多卡分布式训练 +- 优化了loss在NPU上的计算效率 + +## Requirements + +- CANN 5.0.2 +- torch 1.5.0+ascend.post3.20210824 +- apex 0.1+ascend.20210824 +- 安装ADVENT + ``` + cd IntraDA/ADVENT + pip3 install -e . + ``` +- 下载[CityScapes数据集](https://www.cityscapes-dataset.com/downloads/) + 在IntraDA/ADVENT目录下创建data文件夹,将数据集按照如下结构放入data目录: + ``` + |-- ADVENT + | |-- data + | | `-- Cityscapes + | | |-- gtFine + | | `-- leftImg8bit + ``` +- 下载以下两个预训练模型: + ImageNet预训练模型: + https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/semantic_segmentation/IntraDA/DeepLab_resnet_pretrained_imagenet.pth + ADVENT warmup模型: + https://ascend-pytorch-model-file.obs.cn-north-4.myhuaweicloud.com/%E4%BA%A4%E4%BB%98%E4%BB%B6/cv/semantic_segmentation/IntraDA/gta2cityscapes_advent.pth + 在IntraDA/ADVENT目录下创建pretrained_models文件夹,将以上2个模型放入改文件夹,目录结构如下: + ``` + |-- ADVENT + | |-- pretrained_models + | | |-- DeepLab_resnet_pretrained_imagenet.pth + | | `-- gta2cityscapes_advent.pth + ``` +- 生成训练用的伪标签及数据集分组文件: + ``` + cd IntraDA/entropy_rank/ + bash gen_color_mask_npu.sh + ``` + + +## Training + +```bash +cd IntraDA/intrada + +# 1p train perf 运行 500 step, 输出 performance_1p.log 文件 +bash test/train_performance_1p.sh + +# 8p train perf 运行 500 step, 输出 performance_8p.log 文件 +bash test/train_performance_8p.sh + +# 8p train full 完整训练并保存checkpoints,中间不会测试 +bash test/train_full_8p.sh + +# eval 测试8p训练保存的 checkpoints 得到精度信息 +bash test/train_eval_8p.sh +``` + +## IntraDA training result + +| mIoU | FPS | Npu_nums | Epochs | AMP_Type | +| :------: | :------: | :------: | :------: | :------: | +| | 2.7 | 1 | - | O2 | +| 42.55 | 21 | 8 | - | O2 | diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/figure/adaptsegnet.PNG b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/figure/adaptsegnet.PNG deleted file mode 100644 index a9267aadc430b587f9641ab9820d4c9d3e35be2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38510 zcmb?hRZtvCunlg(-F;V`EZazI*o$TUA9t_uV@r(7SgCP3TDf-K=a%?7w@5Sf#C@ zulVoZzqhxykdP1sk3r>k;j#Zczk4@1ITKhyrrgl&6 z%d4uQVXILwF)Av`UHxOS%4$trFhZ2%glt4P}o?h8-s~=g=9}S!1 z%jZS)V;x=HK0ZEAD+BWj^HnXQLqo%9Gx{&*yF*j+KuPBE?%gr}!4F?Y-u~WpOb(|^ z>#SAA%?$k9&a|^|GM7{32Fi)0Wn}E8n%Q|;$KzmXK}Iz6jT%Owwc%C8^B%4Nj(Pz@ zHjV}>>+>^9V{O9~t2;Lp$Z}$unA4IkpBLtwYm7kHe(h5(eO1HS2}`+WMl? z@YU4fp{cPEzi3}rdwq6w>0NtD&bU)?ZQoc?M90Ljg2zDhVsPhpRRGVoxZH%4QfO(@ zxC33-Z9{laa--^(p}EFfw-BHE!NL!CVOHUNvAMkh)YJ-w>LFT)(<6OW7V;5Xh?)TU zzq8F*T+B9{SxCKz!8RZAKct1&Bge#0yP{KOX-T5UNPiXNsfU^l)_4J2(Y{eAC2rWvtEO`=Mnk+#XGO-%sE3*tH zURf{tCz)Us8Tzj9ji;RYd#AJYu7i!uTr9io$6nDaQSp|W3AyE3Ga<42+q-~EB^}kd$ zf|Twb-qrkjb`_fLTi`s}F)sdy+BD}BNKnIju865xERLajcr&}-)uk`PF?ztAil2JbDhtk4z4UMIHLr;>$}p z!P|emu*p+DHX3To!pg(1={uS-6`@%R7Z=8jo4e(dPtsPiz~M~%f(I%U(p&vd6{5$$k}awN2}Hb%s2*6h?uUbAk0o!$PkGw$1pt(7L;SPI`5{si4pC zawU~KcShL3A)Otaomg!Hu1;dFoLNqEObi{rs2DgBs%P&`lTy7k7(5IW?G&KYBc6;2 z&H~(j9&otXIy*@E{Jf_@N_thCg)%KUc^?pFrG_>Dm^DNEN$w{MiJ+CWs9#R^OMa#x zG|ewv4@E1{xCU%-g*)r8EwjPnZ)8goIzprS2~{Q5JD=bIKa4pC9}dwuYXHVLv#>E& z1Rb~b`BH|)%4?hS+0iH-=WzVr*K>si#-BkcX6cwSSp585i?$q?OM1@stS+m5hJ>!BR zK*R6)XKuIO_ptpV8i-~}!k#-o z-CprtC(DpqsK+AjKWA7>GK2>SaiC|_NPgXYsPQ5;TH5*2Y$$Zp zhaC0Z7S6`?r-`3^t1X+B7w44T!#ayBLm0cIkijk{9Br00OG$k5jsEB8?K}TOYSFIk z2ssUB(_Y$~BbP)L zTy)grRj(yux8f-R-p}&zl2z zw^n*+U?=~>I=oG5eQyLE5p$+iZ8J@>EZFryRQG~rv>&eNbzS!(gMMW(6n|&{rs4A^ z8p_n;bo@@;1QU4HDOxD}wK2MeO(Ce@J=g$y@Y*GnFT$nc&?UgR=8w9hep6fR{2a{m z2?_DV@F;#(0MdpB!Vj#A7P18nK&2YNe#;kxbS%eB;N5Q5vBJymAeP?tHH9g*>n*7j zrhjLnYVQ7xqd~g>Xd<8LX$Oe({l0#|=6jtv7NIlxV~J_&`)zSEX9i_0{88SM@x8e( zsO1Y$+YuJd$9>;@b`pii*M^1y>)DXR&PLCA))bTx%nrkVsezIngh!bfD|n9?q53O8 z1yGL@fwk{Vo>eMy(hQm4EYTfWmL^yPv!{-&yk+g|-TKdlqkz`Y+~V<@RFLb>aK zS1Y}>BC(&o^{RUS_JZO1=5ht$d`$Ca$1IAL?GCEDdm`fGg^^cE1^>>3<4mb#puhfO ztq_>r3-hB>OwSZZfpkmGKT2p*!YM|NDh}OT88jv&yq@c!2mdNM@mlHJ{^@fvZe9~N zCZvAU5MviBt14$ULPiK1IbnXaX*g`dd5n+m57AO`36bxzzC%dEsGB>3Y4H_WRzM+$ zeM+Gk^kLSMRoR|3`CMo+*Et47t#C3T{%;1zTrgOfXca*q@{}R-Z=yJl5Howj)YTBc ze+7TpF}4Hbzh)=|PW`e8Tj2|52~; z?pA@Qpy+Ha;{H%*jVM;;EV@xpJChlbK~B%*dV)`R#g(;Hy`KZN(iP~X`z>l3RW5#I zE&tTmWagWo4-n?WeRcb^X5BWWCL=6_cs``YxArsBHX?FGOgp(0MoX^KBOfj!)lSz% zfbX1gHODlUT`mSE%;fa)K<+fr8;X_J^ifslvpJ<2N){5(ux1!gUi~qS_HS>YGbij5 znd0MXfT)FXhq}y)nAu0yPluHq?S@l;HKzdkFGwBE8?N7@t-7SZUIu}?HphCx z;xDmX0*4@~(LcT`9K@lSNQTOYM%#4BRoK3=ye1hyDv~5JCO4lfdO8T{4&Lc=)#|8*+yWo$gY}sTGx-n7zL>l8tvkQyz`qad_v2820f5ki*&uoz|lWf zp9TCbf|p?}j+Gi3n}#!?4jYppLnnONcAkx#Ue@(6!t%$rL`><-{FRRIu^ax)pcb7&n80B&gf_h9OB&;^83%?2uZNwK#V-uen-9ucbT)WC zCC1T=^~iZK12n65is9HM=e8={hgaq)H*zNNOr07gZ{t8AEYexJA?#~G{GX$-$Q-E( z(3)o=kKeUayE7L);@Lrd*C@wF=4U%KiJp1p2?~U?b2(Q}6T)9k^WX5Ty_h5@JB~@(@uM-b``hf%<;6(#x9$Z8$vS?? zjHkf1BDCtOdtSbnx_}nM>%8|PTqh_|dvDU(Xw_%iQGyaY%{m?*U652ipn$t9XkGIH zM{a$^)@YVa(3bY}d%V9)z0uC4sA)Pa)nZOPjT}T1Mib{GnwumuGvt^_N!JkaP?!ZT zu3((t)CFL0VVf?Y?C(V}U()(js($tI^LlcZ)BhSU_I}=j`SS48GNnP@P+y8zH#^|1 zQ!%*RUeYe{j+;;&sB>1$~mVH(ojW|{QfHcEHWn~KsN8{|@ zzdZl!HcuHBi1<8v8M6p3!55+tx?cBQaS30&*)Z{4fZcRB;{IvA^v7CERjbk#KMpt6 zz6SYn#bmR_Tx1}yT%|B=whZ!L7y7PSTjfrD2#5W9eHd^wG5&~}{lb*?p~q%Y9V?AV zo^=x^qCaNF#+W9X>GJw%2Ye-N z=hOlpnt@z;Bi2S#Ix%i4p%{fEm0=hLE9qrJ;9VfB>iR<8)kVKGKURefQV%8!j}~0! zuF%9aL@4EeY9tc6-@>lHY-jdgTDQ2$AunkUAj6W9Un%78rKGD%6 zUT4AC)#w9)b7}&doW%JUHHINNUUs8NAs^}N%7f2xn!511YeQCZ`h~*!mwogCcO5jt z3YWznu5qg1%Uuk>9~3O*wsM)siQj&ozr2wKO-7hA%<*b6dVTP+=})QlxBfYH5)?Kk z6!g|DvgJi(j1Sd_Oa1CJET&hSPbwM~C&Wj0y?#%Yd``eHKjC)m-6Nkomp0rM8+90@ zlUtn4sSBMM=Jg}AR2wS25&9GA1LFi0%gC@)_@MEtcwB z&v1Vd7l303mEE2mwWMFdk6+hN{$VpEbAx;@9{5mm|DdZ1)#{nth|J<7q+DsJ+nnB6 z(zwPLo8PUSxyZW~ozjj-D~a>pqd@8N(?8ooxvZQi-J!7QD)@A*#cOQ0U)PpM4w8o5 z=YTgkr&-S!(edH=(_g@ zlvcUmP&8Y{uEzac1Mq3oz_YHm0zyy810!kJ1oU$6TSMGC@4FxWxfdM(yAs8Ki*M~LjKpn7rO)v~68 z@Ean{Z=(uQiGLiJAGqgkR23v-vNN2P%ZosnRnXXi$k5EX!;B6hu*5M&1Ip zBrIe^HNoM{t>U?(V_S#ncctb7z8Ic-lrF$vK<wZw z^#_Cyyz3*gSU|WuFLSDv!-{dKh<|$<3hKZt?ux1d5FOT57M*kNQ%?)HLQW60)5+*FwE>Tc-1{|AwbacJNtb#eo^82W zE&?9yFNZ-yL(B@`vFT{oufHMPGzDy19wGq=*mPh<6??T%=NMUHcI7j@=7Myw9O0ZP z8V%mfa`8T7g%CC4%UhM|=q2FUlB6VW2!f>@5_c&uZKMv=IF*ax261U_(OB)>@buL? z3TZ{eSg@eA7pjvh5Ih|}Zplm=60xVx7!UV$#TFe9z6K z;s;~S$CbT5lpG9%Gw4#c)fp(cQ?`(D)m0ZJ@t8K=SV=_Psr`y@9ySZQ$M_40Mw=^k zYO{m^lf&nTn1KjdOb~4lb}!Bu$hR=HeQD+Fw8Ec|uvwkOyH&x75L?d6?~K(CS4nN_ za%FpayHP7La;$(Lv*akt2~NbK8SvmR>rO#!RK0(DgO|cg59b3UTK^Phuik4jP@ND_ zBtn=){0%PKCCr}xd7R0j1RJqgcAEHy3ClUG7@KNY+^p#$i0PxYBV(9Pg z`v$kb6hETi*NlJkKzwzCd;4z?zj^pLKGfr<8Lu%&lOeF)Wz_fQGr_+3Om4gS#~PA$ zYh0LzuT>U1#k5_tv#ylgQPLs2R9gD^ZRMfY;GM6-L=Xes8wC0}yUSGM^?mC7|EVpBHaWkNVF!zbY zwpQipdJu`o)*o`wwV}6jHKEVJn@`xc+_QrpT7N$WZ5C@fLz{$BY>u*QvQ=3Ki#Kbh zZ@M?1CwHDQ=Qi9GQfizwv+Z-l-4>4|j%ox_ZqHEJcU1_r6&}aG@f52nLxIJr?}jiR z;|%b%0Qdl#N|o?C91 zV(S5kaBI6Ia9j`e0-B~UtR!{~Yl)Jp2BdDst|b;OSOcO6{CAB6!q6nlA0%^fp9ap% zVR*8{;Hq-&<@`wzOg`1z+rgiKA*$*9{`DCY@Ad$&tPhL+)g^<^%Z%e0x8eX%5NeT2 zb*Atk)@0F?pxDuME8})^=wMJ?YE`xyF#au`a$6cdiws4!ruB|4lzNPgL?M$40~!|) z7j_0MaW!G|S4dv^q#_-)F&2_cgbsWXVNe>JDOXJW8)=`fY%v&mNN1pm*uue!aC~WS z(H!lP3`-Fa%*pD^tD^OG5O3fDVUtt)2qlSzlha=6oBH{&wvZpaBY;TA5{8jCf6h@l z)oYc@v=paI9KkNBbFJYO7JfL8i&_DPF1epya(X>MFeHL`Q=@5b2=}<)`uL@*m2d;F zDU{+vHv6RGAc4r1WTm~DeHg!*-&`@HwwOE=budm(DeYHBxHdCaa|~?99XXoC*z+&j zRFpP=*IR`U(k;dCjQ*{1JRdXyQj2o?ik{wL3q7{Tf!33jv(|-`8F{~PXXE+sEs1sX%i4>R{I$Ns%+5kVM7B>>V z5sf^B)5^1b3bSma*%#zJTz6^BgBP2wrfDhb(b{PI2tnZ6NsB84f|Z-8CUt~L_mTj* zr=-f6y@!ty{8x|YPX2+GcODqSHV*hKSq)VmLSQNBUAPk#XKoJ9Eg=Wc)h`QL^MC#& zdTI)@+w1itp=qWrjhkBFvvZ+^Dz4ANK#xv98f?3mNk2MGMz$axD6d26&fM>dOjJx{ zr(Iu4lrMOFLu?Sy-$gXIb-Oo^fUpmboi4P>I8wo{!3KpGZtZU0NAO0DylyDG+l?Eq zB)A3lDP)sHUJ$SD6TklZp^+X{ngCL;aUiUJ!4%TUICGUO4>wo-Zcz|Sgk#n9E{k3} zPlBk@DH}j_5NEO)1`OZqeli$rApW5tl@pYtSt?WfCp=IiRa9BD2@(pZk?5RBf=7|Q z-93_ousosswXg=K z$+$}XD1O-i+L{VcPJcgB7Az<~I&SjX*Ip6O71?LgEz&_X1_rX2o?vr9qYh2~Y$nSqADIW7-Q%xtAz8G4KK2y~ zNRFI2p7nBC7IP)DXAdVVgMXxn@}2m8`Z^#6q5IsCIyB(0Nz-{216*(0bJt9@GlyCZ zDhsK>;gj&&ihJOhGzaK=E2RAXUK4kjcViwqS%vB4ZE!pYbk9N%r@I~+jW0>vO+6eH zt;}iL8C@har1ztV(UE_6<^VyLLi0W*y_14iDZ%7UvevcryU$!`0Lp|My$!T4s3taU zMoTXBWWU(EGKyAtV+VM6`p2ct5!GEy4EMUIUYV-Y_yA9uDoEcp`#xa3>;x*Lpch-` zpFEZ|=?JepXfDOb`d9m*5TmHEG4(v?Q|CH1fwJTrDmfctQKtPS|g1S$3}TD z`Df`2z>*K?R89w0VnMChXx}!L^(EPtsQ@3+o~oh~1TzuQzxHH&jwB+JG*r9uXJnQ9 zn$p3u&xQ5iV+Ck#wK9Aji(bptIL1jOi)8C3u&1f1uC5OGdHhZWZt(Xt{dHg8(VtHO zx@cS+U8qOU6#9_JvLHA#)>=6x@Id1X)^Ic8XWBItUSHC2mB-+AWqIy==WEB$gaC9cr9EjqOqVlo+-? z+>PojuXcnLv59)BZOsq5LnV`&+$tKxsFRBsLGd7Xqg`xltSz04AA7BOdd>#XrNGx^ zk{c|&ajoNEKpkZ7K)6ll%n1!L^}RAe&u9X{nwb8p3;rjshB*X}-W1yyni<8=d@Wxw~@J*C+&75ds?dZx&?tFd)d_-6~q%&C!GK8~btd7sNvva+-`7?m{ayn(i5>^;! zR=-#O{m?HdnHS~_-Gwe-}-^|H!M8^4?P z6%y$&8zVv!=8-^?{@fW_*)vDmAVZk~?JV^BgCoOdBztTLjXpv+Hiun5JMtwm@CYG? z4Mma9n2yPf9oegEd0ob~vcMo?=d#6vE=}b&5&(fP1aqpT^3epn;@JPGZ*1-|nAznd zO=UEI!-%uR+EH;kN6P(9m5YxEx4fzg;IPTrCI(f<`&<(OAZ~(7(Dp#$)OXm?(jN2k z&*nLRMs|0t8GOfE^2ZNW9>~|PJuay9hzuI=_r1>%wl~4dVMm4{hd8|E2vKqn-u$q4 zmD;k+_H*_O^vAv;$!VW8XychJ?$M|uCDF8d%hnDOer|LIb^X<=%p!1KA}$6iFKL&H zuo{WoE9%`fjYh!Zdchi7z#lJ6BIcVj4u``&5FRH;lVNcZten_>U;5<|0;H}%gFgOKvh}}Rvs1U z>DMK022*E$iNjuX5B*)v{)#1hu77;vpaI=qnrIR`eVjXPiiQJiD+MNMFK*vnr8|Tc z{X1j`y7RPavrRGXZM8e7rY5(z70HXM&^ND=)c=}aXhovo#4 zc{!GvW#wbTf!_twNK0YF_F@Z-_!Adpl+;^L-o^88e~~|D!xz5udjnS=s?ej-l@0sB zbZlhr{T9&EG3^RhCX5Wzi1C-KCi8-Ku-g)1%l~GsGlVx>mGN^fkkd;EN->kCh9C-- zEYcJS)qkPrcH_|~L^%uX+EC}pNYKrCiv0JNO%%76)`I^0eBCwP|KHP><=)YNYggsV zo(HjBFQ`1aoZhF+$ey`U;^uDoFV!uPnprZq_N%0;>8m1L-cIRbHyt7)hQny*>(hD2 zP)HAB1iEblj+>w5^gFuK%u5vv0l%mY-(2N12JN6mvJK`EmCdvit9ssik^Q(Bh6)n^ z*2NTLi`nwG5r1eTCUaORLicug5;Os2WaN2)sWY*#|Fy9kxjAizbEd_(x<7N8)X!Z` z>iIj|G&St=GME@o&M+O{Yby3o``DKTZ*EM8m*4- zKx1l-f#4n`@>Q>VVRouQaG)PGpF^-vdVKwi&$%OuTow!!P5M+tk4i79zD$Bjw8bI|&*9g(BO{b^_jPl~_68xio)R z^~Z-|0J)*1N84ODA2KiXs}vws%z<#`7Gveh@s8(o&qMWQ7BEm@krRgNdEXKaf?O}AX-vov|nzr23XcBGq@m->~Q5MI_9JGlG0(Ez> z1O!r8V;eXjHZuVGyh8F(+^HlqoonldGz?H8vJx!vzY@qkOK zaMv|Ae`5uOh{5MQnSfmazU_>XsQ`IZU}RC5AecgsCFH*8NXvB7>5RB}A#O;}3zAbj zipL@ce|m!4FvsupWC&K5QTGVFBEMHE)kthvtqNUV-Ww+~99jU7YMB~0IG5}yee&pd z4Qh?zHMZB$?~h4SDINUvq5()&DIuUy?MK--%-kX&r-_^~=SB_EHdFIO^fd`iZVH)i zik_dJKW*Ml%flzb;uchDJ~#X@G2LXj6f?vyMP{I0 z#=V+5Xy05NjnrHM1nc7Tr@0a)Gb+dL?H$-djE?n7a|gN~#lEd1Te9wgU<3MyQ0_dv{OaV?LeK?mmyr2Cr%T%} zHsXDPfh(+G6%f*#+~FnQJU~uQ&-&WLJXa)4FBJwgJk-!DP@M6&VSb>IdU+UdxMR8n zb$#@KVPv{rDrk}o9}PNMqVV?5(sD9Jx+%ITVrbC1Ho6B4CPqFg?sVoTWwF2%v<&;p zB>ImRpqhOjK=p&*=sh=8d z)6w;fA|w+NeIAp~G2D#qqgeXVaE@+8a!Rr9&P`Q0wi+G5zp zplz7wT$%mxOYtZc#D+*d*vc2WbLpjd>0Ba85sUJ}>Niay6dThAmRR;YA>FWmQFkK1jgl8k{Za>>-BtA|90rk?*SBAdy9R zO_}QoggXi+!+N~F36TrVyxeXIB+Zxr_Z*8N!BAghk)u0@dLwRObmct{@l0r}PRSA-~ zuGQPsJD!4&SGxy$c;ljb05-uf_>lw@{sjn{m&v;JbBd#|EmBfu=VNp!8`AlTZdmi4t`qO>VIgB^umsZf0Ylen2l`WFp2oX_g89g9{&nh+N+4x^% zVXaamSyz5)BnPVstg51g{)a?lfHEKp$ecP_htkYe=~XM#6?6<1%Lgg#%zv1vv?Y+= zRn7vYe^{Mkl7%-~a1T7#|4ieF&!{0=`~LoboElT6)&k%Tbv*umYq8FnC( z)KbQ)$ff9Xc;m3(P;G$%H?7)wN}AO&HdA9y)+ItoBpaM!BYfC?BS_FtVi-_0=HtL< z+PXrO-|*rjNf_E9-M+X%?JAIYXLJq4KpvVgTuV|vU+q33{rdJ|@*NBh@BTf6_8-63 zqKJ*f&Cdl=#NP!31>T|nopHLJj)zVM2MrE0uODXv{A%qg&Z#l~>hk6oLG=ll`gj9+ z=Z>wh?Hk;;t9gkNRMAr{0$zNZpUAikKX^+hb01}KzAr4+{zNPsxm+}Qj+|W>xy zF&MM&mW)NsIC8ClYzHR9R16<*Sh@$v%pI7+Kv-INQq0g>WNs5yNtpr%bvQt~uJOj+ z|Ga-$qAb(Gg}(U1WJLLO%AA)67|||*^XKQ!`v(WLym6XOfE1ueHn;QuR%iZ6Gt{us zaEnc2+L#TI!n(PhU@J|HX`q3V5{}oFN){`EpzS-^knL7}n>Zy6&X)eS15odv?C6kso*FJvP81Txg?sH! z_4fAWhX!mXJ>BVSHg+e0JDzQt+Ds|VF$CfS8=`DvS%V9 zBlwOHYzkfHR$fw(!1^j_2Fuz#M35?L%y+dCU5~}o_>rqR>G!M}g~5~(a_efIIElNY z3=-ewkfZ3;lwMpmcr!h`9XGvR8~boKPx+y59d*2|b#;8LU0oq40aQ;ju1*rl^Qcn% z!ZOE;!|;FgK0&q4X2w*sq8@-T%*ih#P8XgT0)q_!4O>JhWB*;d$e;!I=am3vhzbK1dm{n_M?UL&85+^29|vFresoq zE4<;kvQmw8R`fBbrg0u!&ODJC?P3DE9Km{XOzVI-1$#`AZ#GxEGNtr$z;87XBHw5& zxBD!(Nt!WJnAi|8Ge&fYF6xyBN{;@OfkIp@tF|-!AYXqtDU_(mfc@9M+BNT%LHOle_zTz)=t8h*4vg{gaftPq=Q(84 zLMut;DSph;PRpEiS!c3Ak7N(>qUikS(T$jC5=)(l&CoUe^%CF;6c-ldA4LfTMt8Lo znFz}kZI$q?xjtQVplU2|lfFGeoOP(XFdq%dsY_}NbI6!Me1cxNJ1z5f2zHR96tE># zFT3(CJ~KOuccB|J+3j$axx#R9(U~KhxOQqW1MAGP#@f<-Rze3*f>A>5i%yn8%5;=l zBM(!)EEMPoE;C!M>>&FgG?W|gXB&v=3~56fco|X1+K|NqQ1t7cK=yk6O`}ab1UX3{ zL^-_S_b=_LfHAXqE>%6q|9<^J2u`sDzSjm3xvl2w)<&c0WE5noT-oc|u$8Rk0`~-L zovJ1}R*2$S23x!+VnzsS2GBK?)Zol=a9R}3k5_Ps84c5O!N43sqpTk#tr{~V3}!fMCvjYm8quVCGh zu?|F8c3YtL^sz`vG3}tW5<@tw8E8QaD!vqXm>O)FYkUts7XJZs@;5W{-V==ZzyhFPL zLiaeZg5|SuT!T-fxCb&Sw{3C)y7e(#X54zZ5oy9Au9;ZxL<6IUAY@Pub@u&ubi#IO z_X!5YAK&*Zn!!hXF8@}Ec2deTX+TRB?=*9TxGc<&vQdjb@X`9>Q8W!gT9%F?qpT|I z5LoX?WyfgCy>Ee=JL~G8NoFTv(T_(z5R8{K^RDm3ntT=PH)Q%Yh%(9VP7}7XtB#fi z^Vm>90(l!$G=|YKaOcitMEKE6seMMM?iritWH`Q}X^vhyjnPY7Rmeo}u7DFEWgi14 zH4!ww&B983a;2!Gp)b9_EBF;>y-B5DK$nB971`?TQ!4G+bs9!=GX1QAErxMu5a#}< zj-(Fs6#4RHCVxi1j_&>GC)^An`+AF+(f%*+P!UFf1Q|~XM3g?PlnT~>zyTpOM|zp8 z&x38n|LvXnWJ4AJ-0zO{OQVspJ2hP0GyV&|5TtiXbz_2hHoo(A3* zH)`QSit^k3P9a7;_21txrW-zCdTLzRf~F=b(PgufFmwT&1!zjdW0X@w0{_1yZ>p z-bsOMd(oe2rXJf_Pz|gJV?FwWs9zKs&}>~k+%-_mj!pb6NOdtYkOiGa5plCA^v_YZ zbJNc%R?Ukm9jSHy0%g){$RdECk;AoHL+)jV!b!gC?^?C7@9i#oTynOFzbAFiV`-3m zVK|<3=Fw}vy#wLKEW7JsLPEDD(Qf&FXgu>-R$&^FA^_QQ=c1j%Qq-jT@`+7ZgejFm zN;C$5*aN_u6U7mFkv-}Wz6{bRAvO@Q>xC}Hc zEv`hUQ`!MEbo=lCZ*;wyWx%nGuafi)#;v_80{M_BS}W-}=L7Gujsjcz|NI`Kcogw* z!FKUsQ&+F<0EHWTxsb3V$&zXmh_5Bf+%UG{p;kSeP$G~5vzrKiXO_^6-uI^P`i$pc zX~L1pm@TVGrnaLk`8OvC`Q$$>8HOdE93Q7MWbly z3&+uO3MDm|nxCp8Q@U~`yM#F1)pc3Z;KE<_VN>>O*K#gi&{%uZUCJ22NtA-%MAJ!8 z{Bt^+r+FCGN#%(&QIAi)vuY}RIox~vb2Lp(aU`(hQxHEr<_Ie#uh|g2i0IHAHeoD7 z11zgqs?}-Yw%1BI+t=hGX06G6Fxn0#It`IJEdG$oo^e(y(~YD_4Q@|1`w2k=ZJyJX zu(|zPG|MC1er=qlN!$+7yNI^%ZfGsjhb(qkfLF~Nb`lN>Q;g8V<+klr!i!}SSwvmz zGGbLFMxWyl{idqu6nmAWFG27JJj%l@F#F__ZXD~`?xaTi85#XA97lU<-G}cd_ ztv|!M*jb$bh5YGvIOGbs#Tqy}U=wW;cp8b!2__&Ox9d>#&lZCZPFDZ!NN}$~0^vTG zOmX-x@F0YI_kWJw zc$Aa!8fF2lA(xQ;SV9{|X3;qFq9DjI8g)~%E)Iqf)rA?;Y_l1SiDdpQ7*LiX1c&zF zHo#`&&~i6;ZwM(+Q9j~^l#`rWm%IqMHV>8Wv>&04Ogf*>t>vwKd}{R1qj~MWeS-(p z_U{%glg;UqGib0Bu4?7ves`SU;w$1YoFWe0^jH+R*^5HRPzg-B7KB75i>MDdAywy{) zmbg#7U#u>Y|Mch*?i8s<>g-?+qlsOvUX=gDeR217U)Pe;epM>H^uuGx>^y*gz&@Gi z{)=C!LT;z6I!d&7xKMfv&KT1gop^J|9i@m0`ABoph} zW0X%lldmv%FK|Mm_D;He86`!OGdxP^&}5Q(5wHYi|x&ckW{;Y zi&9TgLJ!Za-#R;vv)?AAc$$sm8(ZCD*$~<)@`yd~aDtDW2bve9K?`cl3qaa@Ay8yb zFf&|;GgVCw;{%i9e>$ZtiT7JUoE8*ujhDK?Y~z<>!xturPYtuYXr@}NmnuM{X|OOz z4j+og*2G+9=i*=$sG~s4wh=?DI96FuLQM&+Qmv?BEiE__`Ol5>v!_K^sXu%~w<~BW z=?#e^Y-_llv1ksz%p@K`Tap-*ZvE3L{H_Bo?GX&j+4cmhvm$+f(31-CrW;KX58ip$ zkG2Xq_qqLwkLRTP5ax|v)gJZPPsk`BU!!g>?TyyoZYfJBWBAHiOpM5iTSgAks6Q4t zEqx$(qHF_pjr|vO!B-h3r$m^9SO3MDuY8}|$4oz`LhS?L-DjTm59Po$6+LHz<~+-u zfuP`Zo`wU_k#`7ofMFXoR%I^yVIe9=XW4NbJ)kT5m_7vOwQN3~9-O}gmQE~2`R zCFhW3D)v&f@>;n@Sj=#~nJEu(X-Rmv^c#H8{hc_W5X#)sb|%2f+_tKB4ch zg+!kZk(Jyo?c%l!c_C}96UkqpMoU)mpHWDw07YBv^w+_ubQrz(#fJtX^ehh7f@A9$ zTzXJeTbtcR@@2YUa^JLERy?A~1|_^5;D;sIZ9`eb#>WZ;Zyi&Qa1ZiQHqfSCULKFL znCWlpqf(Z!xvxK3lYe=-sHc8)fAYQSKiL62K+=622Hd1!*Xpx2#`Fi`tmal2J9YM< zhi4)|9I{HuoFTORC8$XbK#FfBlN6=rI)!47?x=q3#5uQPp8h|lnD&MMj;#CK(>`IE z76h2bDL`|>Qe)^lmXE-2t=vgkh+9Kb`N)|v>|t%L30aetr*on=tEAkja-qWT&n!Ps zR{B*oSIFHqToai0d%XZY$;n^BVx4kBE2-|e8esdT5>4X4RVP_fQfrDQyZQKtNd)6>CkzE4>*yp-_0PsVBZ># zu0dcjrcHxT?r!P4O;dNkieCXwPbI*t9V>`$$oh*JDZ3%Up3$ zW9#*oyq9{40gFoZ?bc9;FbLh9>d(yG`6L&Ue6R(V^D%vQ0~^pC^p$PBu&;uLq^eF6I;KV5|PJ)4e)m>fhzg>7C{M zV6X0tDc4pNh?NZVsMg1kgCmzJLSNzzZbtD!G`d#Y*P4$&NoEB+|Lt>N@M7gDMGOy1@%V=Ivj|qhd1V|I%#bf0C8IlO3`tC%FSz;#%?_?OO{-L!Zd)nh z0HmdstGB#``NTgU(Ko*;(XvWG7yo^(3b*8)u{jRS-)lwLkFvxz9Co?ZRL&5u;{G-_ zPp6bq9N%s}a@NU!zd%qNq0d@uwkcw3&qA&RD57B+0vO{PFFIyipY(Kt`x?=etKZFI}YvigG=VV$+nYq!RC zgH2U}L12Qbvehk~ zFA)qap+dn~WuD)tEu9nQM=LM0J6C!emQl5##4ku`TSRey#Ce9Wxh`gpJ8otyY2+B zR$rlQ2RyxnGugS2J+T9TiSmg?s&XNXxhBeaWh>ii(i+bs3_>$o!!$hAduw;PO^MV<+Y(1I$c5zf_#zMMt3O!3m! zHhu6ipgKP0`;HzW1lVY*cD?3{0B|??rg1PZQJDN3DrnhBOH10>oug+dCcDPFa;~OQ zV{=WUiqmIWvWET6ZE_kR$9`E6R~kt5KYP}6b@)gjaTmwY)teJYawus8yZAE zSzuZufRalM8`PAWrpHZ8&oMzorZ0wUHuxP?;QT_{9x*H{&nv3&L$dsv(A@1f%kswcf%t`@R^En*3f%cR>8APp zc6mm^Ha`1tSR6Uj%N}4lj2)^~o=Vi`%}7~GQND|Kg}gVtcIq9ouL(M&xCdCiujvV!9Q_v5DLDdObHwQ`p2B`QJn$!SFIo zNE`^G%)8tu_L7jb1 zPOp8F(@10?6)8APd_hg1V)KF{e3Yli$mMtm!?__j5*tE5(EsS;AjqIh(5Ju zEIlGhMuIyoW^g{2I4aTKG^0t$nq7ocf?*gJikE4!u~`>yfu;8{a^LefcO_4Qy)Z0ml6zLY!e@LAKFe9A^cMny`w4ajF)|3c!|9kQ6O>j7mCD zI1A%$u7RV&l8G~N77N1xEXq1W#Ogb^ky}5SUU}05C4<+$OY!XG>S;nX6YE+9_4Qm$ zABuVhIk;5J>PFNU>a8{&TG2{5P^+3BUfj9!^S?gb`I_H?vjUp9VSQ+aMl=M=w?cie z?D)1-Qd;#&u1N+BZSIBoa7Mao9We{G4lgy2T|ZE<78)stJ0^$Vnvy~uhUmy@@nNe} zgd-w(2oK4FvVJsO6{h9R4+F8k3ZGs{z_^h}rV@Lm1~eJ?|Loo2YuZ{H0PyE19Em*z z77)@11|jV$=!ocLdD|i|698G#vE<@am_lg1OmWH>FZ7$hC~~o7r2qrgPaSkGFrWb2 z-**$ct!vdJ+NA5|Io!)Gw@$X2U!UhZ=Q-y*kw}Ihwn#dymlBKrA=wuf_KfKT z`~IKj)J-6<2~EwB(efnC-Tthm2mj4QBY_P=Q@#zXnJ@&LV!KB1N)rLdVgZ2F;=NdG z;jofSfXflAX zs#y`GY-~h!7S#00S+#wVrw;(t6yTV>O3R+@alVq}!xLu8D{rqU)7EQ)7yxvwmIz3x znLS;JmCHH+$W~1T$kj};*n5Anr%chuEdBhcra(0{XZAe!U2)o;Y=nRiI*X=GW*3{_ za!=2rQD0Z`P)+ok5R4|Dt$O5)VUF)WQ*c9mX9uRw3jOe@rn}Q5>~H(4V=&Y9NZnse z@1I4Z=TAiX*;7q-rwQfv&iuT?0mDoySKM1oFP$mVDP6B!YE3V~`C;nTD}L6@`*;UC z(L4HeG;v>SOK+ajF1)4IBwsuZ<$Y(bHvt^@DMPRaXHz#82BC?I=`k+Izb)e5okye3 z-cu*bt?Bgqf1w1Yu8XE4e;!z#4M$UZqZZpq{jgz~k4?O$m!Iby$5WlcV-QMk zI&|qD;+r2me}Ddu;w0uVz za_V%szNAaG%dUwZZ@3O2IH6hlo5qiycTo==?(Yw|Ff<`Cf!hF}V}q#J6tomq!)jNK zYlDu_5aTOkfNT7^Vfy_U!#f)TpS_|)mR{58c)xWR!D-WNiT13?`S^an4JS6q8h!`> zJ&ZFoY{F`aRIvplwaW3vI$B#{bzFmr<~P%GHU^%*lc|uU*TjE43nYZ#H0zX=ad_DF zycO-n)zLv}8lU*&#HIvX*F-WaiTO2su`xZ(Qy^5+TTcUaeQ>*v0)G$ zG0YYUNmD+%#)G()%|ip%dfEd~$5NR~XxSEid@R)m%;0VIU}C2sezLS^yIY{lHy{mazb3|(x;qix@~L<<-k~E168G2WX zMOOF*HrbShz`|7&Un4qBmXk_73&j$BeyOHkI5rJkkD%n6?wSsU2ZAq6S+Ooc1n)-T zEupMPxb;mF*qYjS7g*j%S=khQeyOHkH#TvuR|q1}qwV#~r3!u{(=+qX!DWskLQ%CQ zHGynwaNOM0I>g6fug3qprz^8m(@%~~BiAAXcxX~)HbP8lLI7o4V#RLJ=(cQ48yYJQ zaG6bf)x@o73gqVg3w(I<_v`Wa`;>B`ntraPqkY#ER&mc&(-CvB#d>QJ3OHeM09?UH zO1y-#5-xBhTo7W~Mn_AxcW_bwFjwM*>in9X{^v5Fv9Bp7s_Exy`q-Cmp=rptR0OXy zWn_C003h8i2V74eJsC1N9zf{j6_N0=oCg5Dx4@p*51&4L<%A|UDVxyt)#wAfTZdG zyjG@lb*d?3O{2d1dXjr=a%qHsyE?PT))ag3*SBQv1}C)$P)*yK^a{-asiu%Mp`(+{ zTWEUAxGnD9ou==c&<##I6(IFU9oTG)!l0VMj!j!l_vwUtO>el*9Nr5}vp7YvVD1d+ zpqFT#M>U15Dc{_3&4Aq3n-DiT;O>W}+;mP>l2l}?!e;4_<5bg4O@ZI(aJ=tv-)i9 zxF80sDR)&Uzv5J0FA884v$Q%+HHEH;-P`jx+g{%P!{uvx+hi_H0EN|68K7LiI}os@ zSZoR>Q&RyftwvQ)O`&T#^t@5VZAZot!wlIuHFYFx0f|IxO>Dzb8?4Y#_0ldMgr?Zb z2~O=*1z?b-TivOq@HHKHouT5oThP{W0P|{!87Z!(JDN;`H*pmTc+k^su^RM)CObNj z>zs%P09>A;pqfJ0ggg^Hx1H>nK69eXt%=QIGeR6q-2z|55h&pS%XOLY4=s1f+xuM8YKr7xN_?X&ARCy4}!3qtg;;s-=10I#`D)_L1H2 zaU21Fa5SMqA9qAQnk5E}P8g39|0gwZ)rLt#0dnO=Imbs@Vy()Suo*Gg;51FC?9uUi zY7$rL06?-jJoKZ9ONXe*<9wCNakM`x860i(w_xr}@0-P|-51Wh={93R)Aw~JmU8;7 zHKDGdnFv77jWrQr{IL^3AOL_60&ZN}k}q>WUJg}LraAO(1)X`SKLS>i7uIw&9J8xcb0MYZi2qosyIXqG~BM%uH|d z~O$N3-DUK%Gk(0OtvX&(BiqQof8-)^<@(<#q zYjj|MlVVH@PZPV<_tAkcbH~Qv|2;2yxyv4M%4r!jvE?+z_<`WWrY=Z03-W{YjF`YC zw6T#RZLx)IU0OPy#0LQ!>!i7PZ#B8>#--!;(Uc(|*5VlN zUTRWt5&>vBUKWt9_LcYm()-ZmiCK{cVK$BSp z06B~6SDM&CTvb-DG)Z`k1psA2Q?Riq<72T2fE&)ZMcQeEK=)V^jZVM6CS+C!0GL?4 z(qtN%%wK6j7B&O`KA#96(<7s!M>EDYb9VV3n>Qy$EH8W?qrJ0#**lxxw6QgezjmY- z84inBiUdZ&LIQ#W49Ff`tF64j-k@vKJ0=qmX+T1NW{7-YaaD;Oiz&oK~48^9za>7;(reApa+)H**u=e$1WwS0}r%U>P6F-@GPP4`N+O4Fh{ z1=H9cr#InP1dfjyEat%aO$n}nPQB;gn9wyL0MMd%1d+Gub9hfjd2ZnyN>7!^{^Ut%k#< zn+eAcjieQCs#e}r!ePY#fKbAUC=!(QNVb;A=%EE~`eh>{l)Hj2jeeY0Ht|I8sa9@F zG|4YteIQgnAKVD1qnS(0FJFzCUCG>Nn} z4^Mwwr|#L}c)KUmv4*YgYPD#g*7_KRUz&dU?ZvO`l9X?R({h@YCk6}jC}_HkHua|0 zLt*HnHkaQCXO}~S$f+Pam2+#9e$omUe41T@{ko8HcAyisTB&zqBC zbD=i3gv%GAy%B_2-fE_Nn$wS?w6nz%k<4Y)R@rr_yVyhEBof4*WkaU0{bWtupVY3j(Lv1}vm>ra*! zUJ@mm9%g<>ukUf6Ph*o#vFL(72KYDT8raru((i^t-6peFkZxk^`*j{ zC`$M;%gY*?`iRE>TB=qnIjov|Cp6iJ3MiDOV?2bM2`bjcIHH@Gs6#A_V}LQLklV9dS|}3gB#kLe&|ou1DNVLhg#wn~7+FhC z!Kx@*SSKYyve<_vDr{K~WlPMPM80=_alOEsmeSNi%LQmx2qAS35+5`*ylomy!!VTD zUG@8*N%v^t(K2NsJLrN@A(W;z5Hh2w1BQit=;0oj(R2(UR<@!VIUVybp(%qVK-|j{ zodI#0Rff_e>WF!>045&wo0yu?WIL8okD}=|C}NHaeRL#BQ-vLv(o{>_Jxtuck?gJ8b}xA;57(2Nmu+p{a=!8%C3sMYIl!h~8j+kEU5n zZxv18ntI}rrYJ25SyW&#@JDHaastsRz!7FDmCE6iCPKM0#~7~}leCKi!~&)1a1w>s zv#=M?bX)D;Vq}qt80F2Z5&}r;);JBhN)%DmR?t*#AgXRXo2qaSYh)z=60*>-#qWbA z6Qi<6Q@Pv-;~piXxe-kbOC{!2Z%WeQU(y8fE=2`Y%mN1h6Pkd>D6d5v1z>=V3lwE} zPLnceEd(?@kT-E@gGu(7A@r}9_tP-SD`@IBc%E;J`>c%H;Clq*FZ#KL&DgOX*?<*hMoRZnwZ;h1B=qsMyCK`ozj#Q z4FJQUyr>MH@-7bG5VK@XlOD@sHW$$JaQ&v0wRuTPZ17Md{tQpHq`)^vpo9IS{uM&#HLCUfa1>a0s@OM95?WHD6~ z6PVTIayFhWSS68ykeX!6fsdK{hr zl(SeR1w>N}Xu6HK{af^#9t%y}=be{d@U#g{xl*jmR;#d8gG08eO;-_H)onv984%L-5P-y&^j^%{ zV{d{rp~bxO5Nj?#x=~e%0I{0tecZPJq{&m?V#zFpK%~dv3v`L@AY{`YT0qlnz3HFd zA5D@*C0*)&J3C+Sw2?P8;sk(CZu!Rkm}gD}-ZarCL3rw?-0PvxEpJ8>cYib;TzGm( z|1n+c?07tBH={|{0YEV!P~c6QdDEMb(DLyDOzvc1j;?$r_{pct=HC8sFEnunJJ;&P z?>C`IO!fd`@k#(m;7vOpH=-$aE(qPfyG630IIaea1T^h$>P-OB+dr<;>FL74v-ejcTyIW?qp8kDOVoX~#ayrQiw&MP z{pb0Yq2WzvI;sJ1c|Kqypy}@$d($$VFZ#;Y;azc(HBUP2YS-t}ivhgrp2%CGDfh$k zf^V9>KHCjwN=KUjQsgjTB%tXA-n69pcF+A3`y`yK2yyt>f!}vzNHd)7dYoQQc zK1fs<#Ps&JDwL0_Zw$sIDHeNUIPW*w25AyJ@a!JM=Mc?y?^#;TQtpZ z3TO&w`m6PuxF>!p`Rn2N%If!Iw01Ovf10=nP615;O@BFWIvKrLU%%fC|Ign2_B4_0 zaR8qK$uuK_>hub=P#T>=nt(vi+64neiU#f?E^xD#H9%vm_bynszy_qE3xp7~;4Le; zBNEgUxh(M-?j^>3;7#@o`0PH|*R$uGDYT{Yx1A}YnIF&=tfyG}>G#acIcKErWDir6 zS1U~f;YFNGO{S*LZo4TaKi~)~hhx&)>da!w5Q^M2;m)3^$<*}OWz%L*cCH!I6qY+j z^i$cPdg{)53)9KeWNOM|HoeiJA)A67VNl{^!hMHhHJvTL(nm)5^vdixv zXEx{iKTDe>8xpsTaE9=;pghCuAFQvhaV;$XCt(! zNzZy$TRUG^I8pnT+!y&=q2x}o3AdUQJj@bB1!+w+WmRKef1|UeS$32^HB4MrPBwOS zbrQXA5~Hie;q*mnvhx#r3ZLivG=rzqip*V>Ww)A8J521UlQ?=!U_g>n&YHkhB*I}% zKwnNa_Q5pfL>P(Fm)XHSSY#um4O)rhd z>5J3^_;7lz!E+oNlG!X-3O6xIe=EiSnqWHB=$cKIeNM!rj+~$-%RVOnIWeXt9m8o` zn`n|h+!TAZtgNNRrlDm6XhP{!qiZ%LIq8^ANRuTsofuP-ZsncVCYqQ{nZr%?@S?(p ziBVFMHu9)RBAv9!CQBYVdstHnr&&XA`cjWKZDPPq7Ze+4q$nwP`O_qkP8wxX z9ysxuQaG_j;PjBZx}ilh z5zeWLl7GG;*?UW`MaiySUNwnv(kz?OIJtDxl;kwYModk5m0OG82TRl?nT;W*;>LES zs7=NonnXBhmra-xp&zFMO=;<5YBF@m425uoHB}jp z$w-_`O_C)u6kruU zZ?y|kOOhSECN-^jm)(ScGzoCZ)N}){WUhFedRjImIZZ-N>~tcke$#?enkK`flc`BM zP9(>NH$Ho+*&`i+rc6!(J-wT?_^dS>3PU(uQ!<@)XW6wE8gfe4l$K7w)MU`QC^Zof zT%K~OYmQ!OG?JzaPD1dE3GX4d4SYcP^h8NM9oCeRPVC1NPD>hVN=qlk z)MUtN8j^Sgd8cCPTBC=kXDhmDx==%(B185{@eQS8QGN9 z+0&3yh9*M{GBPz~uc`6bj>_g@6m?lwO?L>Si5RpIUcZX~F1yY(lo(%oq*`; z>aQ2??1>+}Rq82IlRlg>H5q}EsYzN>Q2f9nP_l4kdaX=Rn>Ky7o3JK==Y?9!_ax7n}7akJQbo87|O){Fqdp7i9P;GNSe3FyK*<|@)u=rH{ zFxd`&Qc*?Jk+=-toOf1}Ms=l<9+qII&!O64j_`PJ)__ zoRg_ZW}lw8CU^K3)$Q$2l*s!3+G=7(s{Ch=rrStX#jUb_qM00qw=*@Rrjz`r*L_d- zP%IA&D9fgFPAS_?+#dU$;djKT zb22qa*2S>+@!1t>M}32fiwkx=HM#qXy6XId_iRynb#dSAuCfs9>GhsIRc)c`x~d9j z|FKhTglIY`n~`C^@&p~vt-VoL_`#+un}j(Lzj12`PJ~KMVwx;3XOEDRsY$XV#_53_ z`BOs+yxK*#&@>zi0SLlvCu|9}%*c1m&1V{*0<^W`7Tkrv@SK#+Z?bR9Z}UqQ{tA?3 zlN=|YGMz*b`Q%jq%(Z-cXuNh|?}#-0aJgJ$w6{80DNK zHKBCE4-;SI_DoHNDd&*rnnkwYVm2+(K}xXqc=VberzijVJ74meXfGZXH%(x;yMLrF+g({;>|LS; z}#4i1D9pNdC?>8ABgHfm2dQZlz2U!E3VY+u*p5 zNlqO1eiYT}C-l$w#O>nmcKL;mrnxx(EoW-VTc5>WIKiLC^2eT>PS^>=2Sa$Nud<9g zN@(o4CYlEE*oSVi;Gm~^rr_{>+PeHYKJn@_t+At%@MCn8{Rjc9;$pc7cNfB9CJ`s_ z;sqNA{GJQQ2~0<@I%aYgZh3t!no6!Fsw#0E2n0Id)lVHAE#)m89X|!&MaRh#t*s9q zzWw>Wc%4UIuOGi1{P(NJbJ1J<-6h9MN=lBOEI)bjPbbcu!?(`;Z@v6PG3HYZLCqNl)E%3@#Sd40@9p}r72KqwOWgcib~-ZzGW>%Ke0L-4v)v< zbCjZ64xeZI(cG)o_s5pUlArg{C;m97pIcwOjYeBrOWIz|m6r#`$Kj^~{@q98kH%p= z8u!49^>Ns+&*y>7Ivk~r(o%HogAWBSt~$`8m%^H{Da)pwo3(%A|EF@|1jKidFRNHI zIjtI>QHwwqP4&ejn!Hp)lJ;9<8*}Qct&c2V=&D|eg={9Oy6T6?ZqU#h0!GQEy);d6 z{Pst%YnHuaI(>>*cuoLwn%=XlDM%-SX(}q>9a;A^Sxc=&R&<45;ONB;U+s`n;M_kE zon`E28GoTqR0p13Kb)J3wnn2RujX1$v;-g?kLS-ms3}nh6?WzEc|4^ElmmhCLAgGp z%6H8HDLD{mWts?oPt7-)aB_xYqT4?^*)?g8HQM#brux(Snp`tv8v!+4hn+sAvdhMF z9fMc(=gDrOp;yPAUQXE*=l=|9f@1d5=|u$Dh%0L13N;9*(p)i zNVDvE#n?-=6&k;wxI(IGi5L9}{X%=rx#J`bb{aqAsoI+WaUL85^V9E~|2=oYQIY5W zNm8QAUZz^lu!>DF%FpNVHD3fZIZ*5ImZ<~#=De9$b0_~oB3y~Z^=9^8-=;`+?H@cWgSiNMvKOF>4{ zXy3ui*s+;U0{fR}8eJn4JagmJfr%}5Qw=Au)9ojr6?Xc^i_j8Ifq|wtZ9_L@;3dq} zR@iqFUhX6%39oi2^zsccLW=VK@5P+uc%ErT%v>T%&XIsfiE2Fm7c29K8LH~w`O#r) z#U-jNk>wWLREJaBLHS~ny9@;v7uuz%Z}I8e$cE4qoY*rlJhgi^7&wyIzbm}=?He;g z7yAy*Ts#>*68OC5^vRhs!)JTmyWaE(W`}^ZOXHj6rWeg=dJQL?A=uE36jB^rTl6ity;z6rN#MT*@RlpPGlKQs2;;8_FA^+`k%RC|)(mznFV^n5pU!%m~krXilSe8-~Y*uBBzYu6@=R@ab0Y?#*hwG-iE z9e(pJ(iD2(--Cr(r_f(&k8aZk|5Y>=(9rBUGx3w31h$WxLQj74CpP!Mp7XD-=+XC#rjY-^ z|Lh2wGC+=?v3#7si3=*GX~@0Bywr59#)y40GRx?rbgO|J6$x7t1|*!Q$|;r&gcsRgs_ zzp}OaP4zVW=%3lB(Zs&?)ouUO1$+4Yj&YNguHl1exyJUKXy2AaZx|LBNrU$gAktBO zHAk?#idT$O%C3nkCyKlxDvBsZB6ihJ^C)fy&q4cy8^b^@SqXP>Sw$&nxO0pEUv1G% zo!hC|j#CFTVX61^wxkK?kZx=rH?2VvxM|1GbO;#=$D`UERf8*9if8Z|XVVZIo0H&V zO5k)+iFrOim_gKmR4SEAWw+wx-Et91JyD4yvpQuEs-zl)0xya>1`p&Q&=UEFO+g5_ z@dWRu`VMGf{Dx;+braz9awSf~&ueRRy&{=w_&rbD8fp7q{o$kD%VS$XQ{U2R_~Fy< z1_Ggj+of-MvZZbsczf5`>%nf(giBKSoTze~#$`C_o#M;k9+@edO+XP>@@dMKEAz`B zAxfU(IG%I$xKp0LVA_fjiDf03O;ZRGhIv_$&$3-6wvpw#P^fiH95rd=CPX+h+p?Qh z;`HTbfsya-{rSJRet&Lsy&`$oZJNgBdRHfcn?uv%qi?Y_*{~TLKYa3?-MjwpCJaa4 zJ8*hW&y`>|XrfAQucT^eS41g<(M^Ib$+YbwumQR_ZVDw81!8^39M9htg7oc zX4EPzme5UNbdYvv=?QTD0eCEk5~GQeCDIe(M4Q7@OonTfUYNr9Hr!N?)5w>P-=gOj zxVBE59zHtJZJGjKKbm`gOK5uh2lmGK#yACzjdnD|*VVphE8Wz0cqSA$)ju=U9hy)O zQu0pf2b?$!XEIQ5X(}<~&nnQAo~$RMIoB(*Rq{^HGm`veS&CEP)krkw;GCW)#u5_k z$;yDGLD4wy7z1`N0+(s_0b4az>`~US)He~-Tsv;6EB5~Q(ez|%IE~HC4K$>w{Y}om z$X6SdkgvHWKb`yqoVHb_w{>os>NyC1wTY>LZqSs3?kFs1l9U=u;P!0>(+5ear2?$E zL7>vPT*X0}kf378onIoUT=pE-&E<4mF-1TLR#l89X#}0jBWKx`ZFW$Xu^Yo}S~MV3 zcLFQ?h$fViCUO1{``vcjRA;BZO&?)61=owyiCYaC^I%6bH3;H2gQno*^z??}^sDKc z-sx#4-fT8Qu5p@{Qd5y~-ZMpW5LzfnN@J*|37U3?LO3vr6pKbh)A77A>8V(B^Z2LZ z0Aa8ICS4Lu%Mx?8jk~vELdS6=HsnV{AyN`Albgs#$Pe2aW+^;1OsPSYAz)8iol6eONB`UJ&LofE`TVNGzw{f>@?e+o9c?aC7jl0r(nZUuR}LIyu9#q zOWYLNP@HyJ-}KFA4a3dgNT#iGD@|xJDU5yLrv@X}yAjaF0 z5fxpBc=9}xhsw`Xl!9nNahEhii?={ZyzN*Oo6#htBu$VtfsKq~jVBpsJ%Pi-9c)Dt zMnarMn=%y24;qE4$jZ#wHr><-PJt7RhKM?&X?XSR{Wr}`8;jEpbJO#0k2d7#G7&ZObebKCx(Y|x)Mt#Rn@c7=@i=zN~o*}N?YJ2Sa#K}77`#JJ!|N?&bvRKwH49EzDaZ} z3;L#rP6WXM8R2jqB^k0L3VyDEnI4vOfD@@HOh?+|s;K&N5qH~mQ{9kJeed+m8y}sc z^|JBB)%W1?zHawT_j`LEY>}Imaq4~)v2ES-#mh#EZl(@?TK(U9xMx=vX>te$Nqvr=; z^<8U>Q}F(4V|5*8dLs+Hb@wsfOgC*DPTRL{`t*$z>)WN}KRjCBC5`p>99bhkI(z2u zjh5V0si19g5on)sj+Y1@boE41%-wm@8jSf|B=%GI;Fp3qe@NoQc;+Ln^&nXG{{Rjbtk8wgjF7!C~S@acwO zTNQKHMOTT6bYBRhi47LvU~8Pt90EFmmS$o2|Cl?s-=?uNfICHM)Fe*a#&Kxtq=Tm| z?3SB4vMOd&*8}yz9Lgo z(mwRDgLvU-{+m7DaeARQ3Q5{Iky30&L4yAD`_6a1^BtNsmm$cbiE`qmxW9gjG+f#Y za30ytgdvU0S-fKPAd-z1A7n)S}_A^XZ%|PV+G;xK3I%TU8u})r4 zQeo_JNXyDS^|onB76fKJNRe}{BN(nfVWQm~2u=pw{wHUVt`rAjHlfMO3%p}HLQJGI z(IyWN)xk0?%!+V5n@o@|#29EIAAsE#vl|oXr!XyVg3B`9wBp=p=jwLaeSS#`yfSGD zMDBh5V)MqisXCdxO3a&{Jt^U|9yz^bSYjG_Ghgp*p-qyyo5_DsWU1eGl|H)wsh^4_tPXus_8hUts5kgbAcw)R16uXI`(%?2?$)G@wt57R-=+Y zLOqx(!QKiZt08DUDWj}l<{i$Yo08vHAueoOL#RCb*Hq=1v>!I3icvgRE8xv^D>|=HhM7H!ru3p`~ zurPK7n$GzBk}Y1*5YkXQ+*7nZu>?UuTvVNkDzXueBQfiG`Izg9Iie&Q+!gb0VN6dK z$t{CSrlKY%5S)aVotFfGxJg!c+~Y4ZrIIWQ1jX4T!iji-K!hPnh%ru;nj`^DJtXGC zx~wB|>&{4jxo%o$r)zUK1sYDSj?=>>J^ah2iG~^*=%#s`Drcuk%$uHFZ}M@Pqsecq zGE37F+I6LBb$Y=q?E~j(+A@F?3*H&Z07oZitHNEGAj3q`A$qiEUpx8H&o;f6rjFlP z`_J%&!kq$dXo$>kwwU`rF0Ff7)h{stC6E}rIDJ&xx8cIR#frZeH_M}WH==T~C zmN{{yY&R{m(>zYh0-TncJ2l)}yuI)4pUUl-+Vtr2ha2gpYS`)dSOsWee4OTJ`jp}{ z7wO%gI901oZ^s3Q=mJ9nogKaV{FKBM`c5>}#5M;Qrm3%!I*i(?yZ8NB2pwaL>q8oZ zcZP_<;YM4^8ZH;(IM4H*em}zF6rDHa1yz7v4-nkB({E;GexYNgNFv0jTjV%SjmB)L z6MC!=H|bXAXEaRo*J5dXD;p0RIFuwT5i=nf8Cq8MgFu#UyoF?+jtU5B$+e5+y9sdG zdXkRgn=ZeL(@y_zy`?w>9xeK150tZ$-T#Jn+WT*Wo2p=^zps80%$nv+*BKwDIhtOL z0Zy|tjco&*s^+G}$%;U8W*fsaq(kI=N9`cFv$ysFJUCQ4z%biGE$^pE0h*FYph?#Y z8llOVay7^_sJ1#aGU16BBVE>9VjWNu^gWi{H#5IHfBpq|J^yuDGhB(hICVsbs)EBo zs?Qi6PIt6n$l--Te%%nHAChrBW;zb-8)2*D3xz1JBbTXU~I{hkKrm2t}jW%@-v_8*>@^4$n1#pLtFQnbYEA~5X630hth)$ zYoZBqYbiriM4p%QM1s&HX+61Ubi^F~=`Y`V0zw+0$xsVQj+Y_tt;NXPX;)W6L#ro7 z)glrkyO{Y-HhpS<=RT$NgypPk(K z6ujgB(?oE(F;5di?6iO;z-irj7WLM44>Sie&AkV3XbTO~wVuvNS{TIK|Qn>Ts_uS_tC= zZBpbfE!E>>BF-i)jY!hMl%{y$&?+>Iw|sz`7Sa@)?Ur!z%V6-xHJ_}>gQavI;1n1? z_QSES{ADV@>Fnr{<21uv7EUkf=1+3kC^x;c?$lImoYp#T@^O0dKYBdcV>nqlGWO&d zy?QoA%Moro`7gcvchzZX-PP9H#0<8<>TQ3=seWdtD z<3t@NpXF2n5>ic3v&=J=rNl;}=>*~nk~Ad|Hz6$J)GSTmWIe5amDB={fhMSDT9u|R zCy%szl$+k6>GbXI=(u!n`vRQCj|CUvbar(6EKb)>e|%E!+q!SNK9r{MqyA{AkejNo zjJq;UE4c|4Y!}nSG>!RZcRv0rjkvCtuKdTF$LOh^w{Bgpem}jy+}nbm%N-KD0!>yN zvI9ud3I$%2^f*SMr~zRzUr;3>rl@9t7gS;@OHl2iEom`D7v0y>p7VBQ=Iz^=X+w94 zuA)YXw#@x}-qvkflw*0@mUz?Dk$%UrbY2)K=vddp!W~B{fSZ7&Fk1@sfTlzoTbk)8 zSVpj<%dbk)rhk@rD#uMnZ~JqqKOYP(z=_Zl^ygF!fYaI0Uz+#;K&)vEHMsZyMd|iLAJj=Y;otc1U*6H8|S0H3nnp$b4 zVFKB9~>ZTe-S-DZy*g`nU214lCBEpr{k?O33wG!X*FYpib zoO@>2(o%;IUduYm~#cl61Je?BF@?qbdGATHW zm5O2FyRqB!#r`UC!EjgtT1tG)wwpyi)GB7N`QevAqv8TO>htF>UQ}NE0P*}$6#nV% zBhv-3QN<^U8o_gj=>|4!1}3G&5N~a()MDF@UC13P)wT6{1HP6Wf}`l0l>QP}w(cZ(epee-(?F2Msfm7F>uScip_USi{ zkBl6DItWg^X?lrdZ~E4^m#%I--fO3a{n0e>+1EX2IyCmfY1np7wj3(~eS`^K_PBZi z8*I44iWpyI7Nt%>kKO0L|L|Ak%E!NZbSJ_w+z3AD(Ew<(1J%~-qM~S;8meLB+qVBm zd31;P{+);@X4!Y4oC*S^juY0;n6>6%gX*Hw6lSkd09R)e3dojmr&)XC*~b$zqih=V`4fn^!8Eaff2i~@})iTFId zZ^VMHUB^}|KAy~srY@YWk9FDU_JgrZaLV;Rdi!AR%HTNdN7G<9&85Hg?H-r;_op8A zhG!~SY38NtrY@Q~I4xb@VW$fj;dFeaZ<@wZ zocd4p_I1->IE`H5IBoU%E_&m108P26i8Lnr`jL9#G+Z==7S<|`4qEc4-!v0RG7N|5 z3^*VJ?W8qowR*Jz(ou?pP%x27bfX|+4?$*(1i%qzDdurE5CJq%T_RMHBHNBimAGgZ zHAVHCakjz1pb6aigL5385aDCxm+Qq;wu{gM0q`#|L&H1WVb~P5d%@aC&xj zdUp1c7Ebr@?CFxg>C&}XaXJ`IQ=dQiXu5Bj#s;?2{xl8Jia2(e({!olhNwMpI*6u$ zJJ>yN8ZMfAoh3wf3XBr!Aw0Sy>A;8?ggB*6XI{9uu(lZo#1AQEcx&>Dkukwf!b5_OMfjriYoisTWSeMU&!tj8Mxc;OLKRNmf`^ zij^Q>B_xcU0JZ=WB@BI=B&%Q->zr^UH{) zy*LdQO_d~U`VRK-WW#cF$4DA((@&_RJ360qM0}oqu}G3jUZ_H%Cm_NO9!90&;%soi z5xzH(Bwz^-njd+FVU&!#PQoxGI%uz4Ut3t7IXN>k(UFr+N>LOMLI@yrc&4}G|IKV^ z!swz2$Ktza!q(D&G)=W;zV=HK+Ue;Hc${APCL=eEolSo&BeRFnbnL>`=;+pWBe~-j zrgBHesYBDJnCoRl(;l3Li>5}BP)p+ba_PE`GrIu;o9c#67(rXg&i_km-9vm>=x1_)Pf4$RSj>Oi)B-z5(j26p`|EA45(KL4D_BDQEvvb>7xv51{?%rWEP2y%hN5FVDP92(NaQabZH0{P| zxM&It*~sS|32Gz_itYV>6q>Se)5w)2fN6W`XkE)4ICaxB^8HtzW=GRb zI}IC6c|+%0HRw8Hx|9?d^*~LQZZlloN5dkPL)c;92V}_=ehSLfa#tg-ljv!!bk9tM zrP(2o@_9=l1oTf)}Xl<*=919x6A3|uD2r;=L~hi}s?kGzg<$}LX}(joup+%&z7CDW}w zO2aOkcF;5epGhMNn!4>YWHiYJ_=o8Z<5iN8{8PsrQ5;4iO);@Ohi|;+y(8TdMUL5axM|`V-c+K$#Z?`g zcDgB-n`%WS7jwr>!$yvW@OU^WZ1K zbGri_e1sSwy4e>Jbc2TMa}za&Y#0?XlFW| znTB+J{hxczx%aw8Q=*F6)CyIu<<<9coZO~K^u}$pC`8NQOP9Vm^3AuWhms5>Gz}I* zvxnwPoVMSu70MA0`0>P3UiwxsBN)h&qH0<&NSR8eF&2K8wUp=@UOhaGqriTVF+CD^ zEpME0jix_d%vVdB`fpO0K9)JcEyKxenuIzv98E2UuY7wcoeXN6CCxM*=T^{96Uwx- z`F^EPjXDG_tYHPGp}w(5IX~G_F1k0Q1$7%zX^i9D#RvooM|_FxrgPAr-6fg=e;j&a z@#IXK`iF<3Bsx6IZ~T`FZ)lUL?0*w+a-SyF->Jc9`sOdkt_)F>1V}+#G}I-oF)Xmh zMP}{&<`PdonW7XD?Wqpdw&JcLZ+hAEiJgeaUBs0G1$ic0be#HmcTazT+C-i$%J&mh zqbW7t-2Adx%!@q>^CTa-IbV)8B_eGJ5<4De0k<49nJ$(;xGh#ixK9%cMKl&o9ceuX zULCk~oF!aowsJcj??xmptgY~P1X3h)i7)s<$!~Sp+FqPMI3&d3Rg@s$luj=LQA79y zBK7c#jOk6vi_fY?Q#a1)%BObS-DN%fcNtI4v?&mI1Oo@-*udB^aCO30!L0^W5w)NR z@=lFK(-Or7Iiigj)3}qT8XPA>KqVwbV1!b`c5tRx`c^c*G?*QL(WK-hftkOzrR$o; zJU)ih-DQO7;ZQB}O}y)R4QPT+PLHcdQ!#sUecrJ)^&e@bPZ^lPDEtDNOfM_D*Qh%E zwH7o{b^3Q>(PS8Ql3)v*JVR9#gO%DD+}UF|S@G_W&>~y3FJ#e#?JnN@(h7J|M13s0 z2O$X#RFa7ljL%ZTT8JN47ba>%(;4dOy{#5aw@&8SI>NMYG3H#GrjIs9qjy?b;XLTD zUg=1%zQF&U|M_2L&)uZS7yH+9{yBd(22FXY1T3+e-@r(MfyrBjRLD{%Gc2J9fCNk| zFs|8S86u#eGIvo#CQO_(T{n3Gd0JiuiK?A8{djVR<5Zlcg`cWc3lV;D_Dt2ZDd0B^ zIt9O?y2M#>s!dJpBO@c7;~0Theel}^(|M-lSh4_PcZ)TYZb^o)2D?wQE>h-c-~ge)a>pvmCTJWa4< zb*wNH!IBcPiXBYFQmh{A${t~&SJl}?&77{vy*-TVVg3n$V$L3gDP5{IEmVP~9v{O= z(6oSZWO{l#3p@3w)5{45v^1J>7h`4Sn|co4fa%HEw5}dY6>F28G{X-}n^dt@4TUYj zjF2raYfsVIwpX^7R0|_mEPYZ;MAcA;%b0NVlAI;brxLX(@$rY=%4s4#boK;IH|GH- zlcxS_3%M$3lP~(qWXW@62nVz@n({Dkq)oG#6d}!-s0T^qG;x#+Ax!Az8QAg>z8=fQ zD)}W21!lb&f$&RCL|)5s$u#*mPA=E!`KLzbh<`BC>p@Z>O}-^|C$qbqh4YXpc*0p;fFN^J`th*QZl z;jL@YL?})+ngFNj(Dc{=O+uYqt|4#j?M<;K&#K|+QCR|Qq7b2g80G^DB0#DX731ZG zm5o(JcMYrFfq@moz<3Z8PiH8xAh_U(DP5jvL0edlNmI$%bTCe((*!uZuxO$zrmStp(QdFf>7G#!M~zBIksLleDqce`=M>7P$RS&n<{J)ook|&&tv!Ay8%xm#dR%K(PZBlpCzBT-6Fd5L(4q zQdM0EX+bq4vPjg%b(`6E+QJR=3o&mja6)}@K+^#@?Mu`8#2%W6Z=##oKd@iVOa7{x z;WN))-Ks2s0kj+ zwCso`68`vuGn#S}>pT0=;bv%iEy$~9lSu%B>Wioq;@ZR?T!*+q zK?ps`ShB);s7}8-tQIS-P6yCLCU#fRcCXizrtf9>Zw^nH&oQg|IOLu-m1q7Z`_rWB zyu8S69ow6mYauHtVKt_LqOHT|(aZ=!lILIXN@>&DtW`2?;U$RDlT4I&ZIMXd4mhp7 zEUHci(L@q4W{H}96KCX&v#x)Lr%kR}>*W5m5Ks+47d;s?Q@O^<_U87An#UIlA@E+h z_!ji1&~3RQVVa^P(=doiByuTo{5XtK6geG%;Z!0pKGA75Zr;#c7%3UxN)}uKrnGiU zQ&F4_q^UmkbVGjaeleVSCjQGQVDH*5(cAqaxOWQA#q@bdBsek{|ILP#te%#tAJ zPk{qGP;?^rV1{(jHCEx#Z8i|t6&&^)&|1bcQ~BCd6sHEHDLM%w7kS$BIomT?zF%zr zN(lN{n7t`j$BLzGm6EOYE{YTL2a~9N^m58r8NF=w;?#gN_1u>q zJau22a-KH1XYXYBZL$4{SRz3mu<#XbCPbTJUxOpyAn~xjwa?+^CN&&I_n^=5mov=A z9-J(iSf8Z^pvm`IUOeOar-WbRJZ*B#&WUMP3uArIbu)kqU+upX-*mqC{k+?#wZk;? zs6bh5i$a_%nyzA>r3Ro0sv*vi`r_niQ)NGhXPs1sea2RRlSR`-?6cGeH2osWXGwi= z^0cW^XMOQ0`ATr=ElLw~vSx5+El4?@yx;T&6)PW%b85y`IciPj8vFn;kWQeCX<<( zX*)Ij>2O@^*yunl)Tw|blA7lhuH&}>GtY$Uij${Jl^Eo19prC(z3owQTar$Y=@Mv~ zYvY&pN2H@vb&g9Tf%?*9;Z#UdLm1Rd)+)eS94AkkDlweu#DUG-Ba9}}_eq+f?GZs! zm()U6W0Le~Qrz_PY&bO}O^|UqOKOJGgr`kaHHeQp`Y{am3z}yAWcKzXd;vbtCnGTTVY<4=@G&M(hXKu$p_2|hd z61b7g&i35NW)lO0S-*=oH6~3@7v%@xdgA11Qw8>)jWRMEj3z2InYmbebc}=#OPAZF z(deDgzF1s}j|B!Z(d?1g=y%ewfs~yl5|N~^|J2dcaAt(W+N93&r=(2N`7S9QAoq@@ z`XiYWq<2)x`m&NV*q4!-TvVsVq{;uL=))r}u64Xhi zq|Q6{q!xcsnxdU>aF;Yi*%>FThowj4ge3Ko8#CeXI7Lv)^BT78g26vf6Q3qA8e;~;WK~#G6R$M#ry;4yl~Y93u%@b<>9%L%>dH8Tij z!TDCxLAxNd?x;y<{ZudXDU(UeD^?z;DM6Uta*umcp453MEHyDX{Tfj&t zoY0$mQ#5>C?8($LaP#nv`B3kUnyRsy_w}!mw#xBc;eedb!#ir?d*l=4J~PSCbo=7I znrdy*Wu_LEnt1uchpVfrzu3>8kx~;cnBZ7p?(u%_gx=(r_}tHFVL~cLNKabR3!PO1u2B26i$aw=&zmd_u)I3i6&m5zpS_NEa_T{L@q=9DBewI-?4 zKJ&W7JCc^pNLu-&O@{O{A)R=Eqyt=}<^TU#@n5vEVmmMj)SUX2mdMfJHT%i;*X4xX z0(B{NnyC<8dL}5k7xw!65 z=uJKm=iqGZjAbS!nlGrTdf7bqwqfJX;MZ?M{3ah~H#LGC>m}X|I9fPXIH93DDE82s zd@}Q8O+VH`s`=5)OcI}+^*ZP+fEnP~RU#9T(n~7bMPs#E@!#cy-sH1!(6)Rr4PPzf zTdm;@hW3?AMqn%gRBKG7QZ1>_#^J+J1bUOd@4f|~Z~N|T@hrv2zCJZ$*lN|VPP#Mb z(Gz7*xx2QmYj3wspC?WPbvWORU1aJ62tD%F^p3ilqsxpF7;CSM7g1C-E6qPo-> z8$B3pL(b}Tj-CvMYn8tzC-f#?b)EqlKDa)zSOCGLCwF|!)RbPYB|SNzH~FAA0%L|@ zh;*%IiUECiCC_v8^zy-WS5D|no0HP8&WkqF5r7p?hP+Xc_()&IdMEUz%~w7XK$kHN zQD*G6PGKLtmcRVFQWKAAdLe@4z{tipL_0|(mZZ>!u8A+d$CqHG_reLp*Z>Ecrl=#D z258f;HJte4=M{fr3SPp(0OLJ2O_4{|0kjFmA<`5LfKnFY5d9irq5#9-_NwbBRxK)0qi#SXb$vP&8O zFfHNqVSkvEHOFh9%2T|mCM;LV*kv66z|c`kdxpF$I9O^+vq=`G1;HX@rsJh6fnhGN z#@j#Qw&fWV0O+Oi!j`j?VyClZ716kuvKM7jgXP+#SyNoO_LNM~@+N$ar>c=|-j;qt zwnxb{^%0A%7hcEE%QlYj_8K}J-)hFnqrN2`*$Q`J=@r!IN^hY(7HY+^WqK}!Y#T!} ot#J{@4hVuE2!bF8f*`^06~#^NI4yk4g8%>k07*qoM6N<$f(YYcmH+?% diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/figure/advent.PNG b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/figure/advent.PNG deleted file mode 100644 index d737e14f12538b08e715becc5e1b95e6ed19fa20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43161 zcmZ^}bx<5k@GXivEbc5W!67)ixI-W~1Pc;e1A#?@F9Z(|f(3UA?(Xici#se1LGJgv zbzi-@ujFJ65sIG{MMTv!gfPky4B&UUdfDA-HK(xj{{tubMYKufb zK&tmveUnz5k)F%hw)sp%GM>mU63_U=wTsP^{d_2uH|PiCgDoG=1%$yXQW z-GhB{Dhed9%_aQe<>g*lO=eC&czNgWy`TU!3-yR7`1th57^{^US^a*XfU<5P4@6epOips0XN#YPe= zj)=DKc6XotGbF&nijJN&;Jc5f=eKw$Bmd2N`V_ zjZF=q(7>&XKe=hqhH*oEg99VuWB1qF?g36XSXd@DMwNL9a=O-XUU{-Q!ZT_gRKxa{ zzXxA49vocVqRCx**&9Ws^{Ic6d3n0XuI`jl*01fKI@#G2vx(yukw<2`Pi@^pGr4c5 zOx-wx_sy+q7=AI!oHJAqwNGASyjmgKKD|4bAJ+e5lrqx4cBS^c?1FcjlZHa^sm9(w z75&=-BZnw@{NvBO>h;Nuz~mgNHh1USFRScp$aA#HF^Q>P8>=;X&RCtE@CZwUEp|r)D%(S%y#9s3 zaLJSQ4>6hQi-qkd%;%3=S~4i!Wj=hd=Z*hqZCjiiV6TehEfG#CHMqt-w-Nhu!_mnj zN+1>-EHOSq8M?t+wni>!1SItKlKkf4{=MyeyYuSb-=bOPMJE?%*gcP6+fA4%_jd=E zE^}eOkoky}MVicBvwqE-v8V23nbxyeMp^`ff-Ge@X&uPQY391assSa`_fmDhXfa!c z$7$P2W_QFDrvy$|gWF+O-j&@?KHKLhgM;C#rY%Prj*lfkg1GVy4aE8Tqc!$J={u88 z7#lOK%}3+L2N#B!d43`dBt@wW%DbD1LbO#9h9s9uydOWw`wO1I4?XZkoHiCi`sy_)1RbI4B$&ve{Ntc=8Q@!_J*PiIh z`z(@+N&bqZ(XIFfH^Cw$z*ZuQMbHSXPTe{X?fwLSZyy?2J@5+Z8t z=9y@;SpG4{jggtxT`~3*@pBBYORhthdk?*QGa0UdHX4B@FL}OcFu!`pB^JO~Pz2({ zI)(-Xn_fLbdnQCKvyInkk*km|R+t$Tq%ETP&dize*~|}N4q%IF4}ol!4;IntnWKss z1pgGu(9s85?gcz<(ttDMpIA@w5{ZwW!op!{b6iXmx$B$0bS@82B@{5_<^sou$9#$T8^^n>!Z z#c2Gt|B*vU4zmf|G{q3HmwOkF7!wrizQIm&(2=Hk7s)&ioR-|oCBu({u6EPN^xw@Z zBzQ=R)IcYdQILdYx`ao8TTdrJ$5=l9=@E=@6A0WAKjCw2IyveO5f<&xMJDqM%DVl$ z;WJfyoRe#W?=$p%y^i9#A;yhI1#?1?IOp|CoYd-q{c(~sKQrL>e+diee2rz#*YLs^fBd%H z@9{xtw&TC|5Y`qHrPX~a*L2S2Kl=1DlwChAV~k+`L93{ov__ljpOtmJ+Tf(m(#{TBWhJX+ z<5|6+zth=S>i30D6_N{}2Y1f}f>5IV_ok@i?;|5vzH0rXtp4=5NAF-Pu_Sxn4;)6? zf?D-1XNcy@^{bhs-sP$<|9iLbvUxs6oro$z0t%r#TRPQn^=RD_=Q}nX%=Z1QA8s7P z9W=`snJ;_PYh>Ti{4vDOT`CjIzktuZ=tTMLez-<}}r6>Zt*O+S3(l9u*Q zvjB{;5Dvnj$ zYHUv2IW9Y3CXQQ=b6z-9=r+G95&h<}6&R^Da5ojgXR%JRdrl{tNR;rdQ~XIz&SzQT zg${>8Snv787UdA;3*MEJ2&o-BTD6V)(>AE?FUtL1y^sN1vcS%=W1ALoQZcxkVu~)g zeg)~$bv^7A&OvY5@bOzu3`bQ&`JXMyeHwcjwtl^ihw5rhwv6m&clS3N{RRO@#x*v= zc*vLQb0gXDY=p<1e?C~6RwL+VkbJ_)W>k6zGNTHpFy-J5Re*|IiQ2Xm;q*k%!G6YzqFIv+}rzUWHfRaQj8C@Ohq=+qC@cP&-_i`s^ z4-OsYBsA-AC)eBy3}kh#ZD+v$Y^S@gT03R~@BCzT4tRD%cizCRliw!DzsJwU>TLCq zZ$=c=SE?HIJ+2Gv_-aR;UabHRNvUzcLpzO=#mi|KzbA-mDZfk9GrK5B0^QkWvEX~f z0}*|VP-cy(cFs{RRzgKoqMb2+DW#7>jKS?YFY7CN4gfj(Kk zZ}4o|=+}y7W3>-F=cRgle^}K0B%k8+9)YVad)UXjRo1;)QRw3eqNNi4#*@YUGoZ~$ zE7ti;#WuLY?88-qLdM8k{XJ8=fUk?-QlQ$t5pTS1@+tJodkIPL$IWGk)Tn3{`6AnL95FQt#;KF?Wg`D z#W$VBFramjwg&k9D2czUzx8>Eu6TROr`;^=PO5LW^>^LN^UwuWTt?4s{no$Yp8GmD z&Tjqb8lE$;z_}&$TI-z;pEB0Q7fw(Tj)?W6$q6=<+Lf*+s~Ya+Z79ur`sLl^+u&7P z?$1D79!ehPiaErkbXB^xQ;7@zi89g71e6Q8X(V?JUOJfhALGqY%ba1PJFjHIj`gPx?QYAfjwLRR+IJrO(>e+rtzd9YFZ8 zxrOWPF*$NYMNUr6B`l$Ogg4dTDXeIg)?sVoT^c%U5r=_qdSK^)XB(JA|Mvja7lil@ zrv`4nZv13}j7LN#W^p>+GW@rmrve$sk%sWk4WuUz-%%yv=*Exhk2A_+ST&&}FQo@! z=VCw{=k!n#UNqHCcLp}UPp@r_)Tj67W%^P_(NSO6bScCN>AUKo!13Ldjw}h*v8Nmt z&=))O6C|x`23b-m3w2f*1`Zc@zd+Sd=jL)kqrh=udruZ2hcWe$Pl)(}X zlp!5J#RPWoiw_McpF2CFrz9NsI09ijf~8Z!PEL-`=e{tAW8k3_zP{RT#q`x}0u;BEO1>V?1u6z-B#`l~ z>scDQC$vZcR=#HV=7$T1czZ#Lnh4F4(!QfD?phavXnp7;09AvY8$Tu;Ac*#eE8nd< zK)+dU5q_!N-Mf}YL+FrYEoJ-J9apeWdk3cmQrc);RZKpM+{n?nf#j&-+`44z=6mH7 zK6F`j3K_8P#R@H6YsW|G3qdV*loqRCLDeN=!JgNUi0%Bv7n5tF7-$-NB69r_-{1?U z2zitQ%C{x1)a^v-O76!bfcgP@^x2?=J4y8w)9+bVq-R9Lrv(!G0+^Vu6&Ya=SPdrVB!CLha?jY`}Ky5gUA`#@=_}O8Dj7Sg^2R1#;>F;D6Bp-1gwe|%6eKaFjCG_8#jFF0gF45*KYxI0w4M9H5CWoz%L5s>~f>%!~iXL~nkTJ4I0*rj^18&T-Sxci`xZY-S0@;p( zuIxz{@x0PshXw8-@0{7%s*sg$v;D1EkU@>J3Y^8#nsnc_<26~$!uI-R)yl%AWBce; zHv$nZE!|z!QbkE&02ylPo1Feh%IQP;t2*+1%DRSaBnPK(HZVXwCbSLqwcww8-sG_v zz*s^^{v5Q2QS}D6=Y|M8MGz zsE%<4#jBYJzz!I5y4b`5be8AKnqGA69+mx#vN6kevFN-|ds`O&$Gz9_e4bJQY1Eo{ zlJ?4Gq%(_v%9iPhbOFpnfe}4U$n=lX#F!}&xkd>jomP#0eq~Cmxd@TzYa6F%s+;Uh z!Eed=#k1yB!iL+SZNELp-(W>QW?zm#jfWoBHT@du!jq>O&1YsmJX_2%OnS+_=Wd@m zHeQmDWW7uJsV%u8`Q%G+8~CeS%ONGZUA2?}Jsbalv8ohp$V&H2Hj(LduBen6VK@j~ zxIQYh*^}lNQ3V$q--2K2-R=#-)!=~8=rP=@jl+N}_p(L4BTV0yVBC5`nI26Jc3+_x zS&xBhd`04l=WVm&9Dm$fEO-BSEbz*mlc{_C)L(OL!Zn4zv*{mv0fS9CW}P87J;EmA zDcIBe20+@8Oa4zoBwe|#Jc@Z?Y|rB{5;6|)BqPnncny1_kF#hS5mAGUy~uYrc`}L$ zxxKom%o1dt2BwIeZJ$Nfq&@yAW}bfxeU^ucV>&ZuV`dezd1Ypa#tLexsNYl1 z^B#LB4ucQMRU+A6yIdd8b=TI_MDKuGB$Fa*6sGVXJbgEN5wTpE5kEr^-6wXNT0K(E zFo0p1v*GRD-kwi;2PkK;LM#oK#l^aE_tab41gsj|X{nsVGx(MKA%_ADY^cY6wh!DS zjPv|GHrxIlweTPQt3Jv4a(s(WY2p_zj+eHP=SQrKBNzYE#q)rT!#Pn1%7~%krUx{= z!?^M0iGS^8P@|$n-Os@1`AChSy5WxUJhIQ6IzF%!QEtmk8N#b|Gci%ts@;x&o|n;W(ioMgl;KggLgOxp(flvf(08KC2a!!%kiAfP zB;mONB=pFdoQ)|$k#KA3wl3Yb>3=*7A?hYPK$1CSg;0GAx{jP;wgpBL*nRvsZJNY*HqyyL%o zq|ONxAG`W`x3_}=@oDvbImZ_#I(Sx2+p=64uB?&*EJ81NBLI-ZU&LPfYr1h4T41F6 zA{!}DYl*VbP~_IHz$f1x3|+C`huaRp2D17uw%&{j|xdVCJD zmBOdoN7)RUqzhy4hl_+Saf8SO-cJMigXshrfpAE^MB1bW-1UqSe#xmG-cUAgf7%P~ zLH-JmuuZPN;hY>h^Pv8M;*LWjkHVXp2@x`~6)LMW7PT#AS4%=5efKB$u$Ht#3eBTyHo>&+2Qdx66(+gY0@E2+-((S8WCu zA$FO7j9X1XNKqjJPwlMk_E~bst>nf>%jIBqJUIlKH_HngpH-1ck&eI++`qk%HUww| z+XW!KFWog`_Doc}J)?wcss=pKD*2p>Bwup3fqhFtLfGlHbWKUSEzr4{0^OJ%blE^` zbXR*aKI6JdK$!cxY*~C1`6<=-s-O4PN|8U4hWNiQy4`6Sa}Sf)4gFiaf4yi=wM)`D zC#`KPUWJeG%ya+Y3_ZprF;JFLQMaq<53ei7p2-04dOp7lXV^QPwk~OQ%xsr9I8^4T z&bT?2hzCLBBG-rR1gg`kSAQZx*mNi`$g38vB0=g|8{EHN4KKyjT^nZI7o}yh8uCU%d1qz zgX#L*OoV|@=Og%#uUtc8>UEay`W=-p)nS+TSTj|&w zKgp>vc^*~w4-|LAZL!*92`at?+eeHGf^7tq_{$Fru$S{@@Z4QU{K*xFl~wvZ;k>p= zZm@2wk}VIByF;oQY)&3bL06aL`#|Yy@}-iPn!TmR&pD5tH=#hx+sUW{V9^I?|GRNo z*Mq)X!mQFUgbXZ|BoJ0ln|Zy@%&4vEQfHP9As)>*BL&on6uLiJe+by?A#B1s0&m4* z#0}jo_&z)PJRbaZe0Dd|v+uHHyp2hb*k0JySuc3D0IxQkB5{E|8|KT5cZaMVaw zd1!5}9@$b(d{6zNVo)81&gcT(c^JI+59BM7Ga@{FOjhG!LxnF-+0b#Du8xT%x9E42<}hE(~xv4}ScO1esoq2g!n zk4sTz+<^g#7X(p)Mg2e9uQOoRHi#6l41W>VyA=FJ^r z|C>C#cJ$0vpBPEMtFl#hD0hK}$_wfiyct0qv=FOTU)Luk_(JDbY+)%sTc3VCOUw20 zP~@YozDkbLd9;V`sw{Rl%leX%~-$!B={tnizTn8+$Olbz03ZL~{>55{tz z04>NIJv;w`ptp^Q8I$n5i|AwWfhi=p4?+m^iatt0rAi9v-UqA-_R`J9l`t@dliIe* zg}EwG1AZlA=uQu|>6ZUxkxO+}XQQPnb4Wf{C9;4wHtwG2FXx8#m#s=_gex0`|MYqy z(A3gm@e^lV&m5qSF?`SeZAIE#{b5^2XI`& zdQQ8#y4X?@_mA5U{>awQmDonaKp^<)F*-l?5PB=XRD?%9MtB^cpJrx zU(nEEvk{CTTlj1%Abd>FDD9N%sjkI`V~~W*^E=omkOzSdNI3$aWo|obN-P}*EB;o; zz{7WW9|*6%xB`X~6opQWbuD-}Ye#X&wGfT!H@MO01DSt~t5?z`*?uzag(Xr7vPBZe z9I2+pD!rt@TJWpd?s=sQ1}v-hugF{IwbQ@a%Qg29c83-bu!h|oQ zn}PS2jW~{Fft#$qmy5z<9dPhNj&&9-#JDM>>h_DM!i`k}DU%3yC|C#zPP1m;&(6*Y zt5w42oXhAUmzac;P#GDyvS6smQK+F-BJn_!>UciArGr%&40G)0`V6g&Z|>1k<7FRU z`ZO=xpkmIXYe`3^YAx@zdi%#PClhq)1$to89uC()6Q^BIxWSyyJID|)MC40o`!VEW z)N!~mne1YuvzD>qfNd4Zj`&YB)$yyiUb&J1PHRFzm?#d zR7xray$FscU49h&hCBV&VTxgiQl36-(IaXqT0W3~DCstQlI5zlJQJRs>QPPRD8Eg> zSPZ6|&tB=t)6}J;(NQE<(FpoP%~>9%?APTlN#R2XAU=@kI%#-lcioB&&0luk3NoE( z^Ka%#U8TOu2SGC=bV@6-^3 zjQ2F>YjalJjYkPRQoYU*l>A%%Qx2;UYMAvcqBo(fSDEp2OyP3gl-E33<{L znrop-h1eBgNV?iQ%8bmUPJKb_DtLNH;hM~K(0S)x^Lh^Z92L>OBJqd@f~!qS6;l?8>$faWwYDf3_{SyN~e;$}fszR8}AO&`!1Z9}yJmP!uN=OKgK_JvgJQ{t>sc2U$Hi`&nTDfg*baK+5jhJbO zEcQcwifXhnDP;ixu*SMA-8zf-^Du*H)R)Cm_98am={9+H^81U;EZs$pHMd#iJYG{O zf(VuY{rwIH!52hkxuJ&!&jUf*y}o2)W}QSc^yQs z{pzWPUTU>@H@$~ywxzZ0!RbkI*>sf>qa6t4Yx(9oiU86HX&vO<7L3j|(o2gN}x<650baD}rgSn)dqQhkW|2K}O}JubJ6@F|`} zlyiMi6U^3Rff+dkK7__WrwB6s@g8Y9Qb$x}6rXvke-ZDhK_G*KEeBGqj+2aDH*e2u zi*+l^C8)s^$6-FBzOZTP!5yRd*8pv8Spy!#+u!Tz2ALXU#r$|4R<#UyCviwG=89VL zac<{ah;MG~X=`WLIC1uw&!QRu29U3v77&yZdNV)xW24{edg6Dmn@lgW%=mwi&80Al zY}cAG&=d&;bbhn5vQpKKc^%X3LB6vb`MPy>)x|s$bZkz3@Ly*C+nik6a`^mju$*-` zARCnc(xsySm45#_h)%vlqUVuX+9D$Z+lZc)dGUuF%~!e(pFoAfAzV77bb3Z-%u6P;S*q{+@MjoGFdE}U`!UJBzE)nY3zV(reM;!sB!MT#<@Xn3giq|O{ z9T<6*Z!QiowlY``z(<+yP9_(^5PM)z6}46jkzFaX0{@PNKU@*VxWwain{O2RZSo#Xe?nH5|LEdYa+2k~$KLBl`$4@lH_ivVzV8Z+Z#So5 zC`r>!y4-*~-yl;ib_(Ls#$D%9M?A8Z$Jt=wKjiqQ1LRQpLr_q*x(Jn`{ge^ocrK1g zwBs6kq+vlQr^mx_wX6rH3q6%FEOSN0X9))WW>b78v+&JT#t3M_LrXo`rASUpz-_JO zRNSi+{Nq+)5Z(Y|x*a;_Ps=>-whKMok_$&8Bdh??{c4HFtv-V#4H-z%z6rlnxZv3uBG-==Ga~e#E>{;3|`}zT=vNQL!RQ*_{Z>+M4wmJxYQ|C&z zC~xP=D+2nfE^+N=d^@2wpSVMc-B@{sH&}1P!80H$x)7c)KmTwVu7PfkzBP^RK?gie zuF}(2)YYa+3hB2LS(b*>)z{b0D#h|K2Pz^R9;$@t-Y)fJmye)h0Z4*5iVh8TMTS0a zwKcjeL=pc2-qzNL0g84L5T!$4KENIGZt>FpYRuFv=^=>m#1{~}ewW?5Z?DnK@pZz$ z9EeOW130{~CKyP1DIyu=5xA-3GK**--QbtjCfcvf_gVV0rlrKd;A}o^2Y9d^)r_G! z3RRsO`v?7HVAt`bxD6%b>q4x;j2rHD)i9a0Z*Pfu4vpGixW-^X#U$-L18~5%)1>{c znElylrGmWtLTnB zk6Zu8=uHBeObO~C)KQG$!7Y@T>12Kh3RM>Ly{(0Z5=knBL9&-`sgbZwUl9|k6En3=#i|EKD0aMFuy|+a@wm%U7XWuF% zp%Av?m*Sy%tuCu-Vb`f5#oXwqA&W;rg4kw9&VorYck&eZToNM@e3Sf6k?^lk*+Azn zcA1!ctRwP%=_eC{5-TnHo&Dv#vcKlf4YRZ9w&v zP@)ITf%E@TQJs4Up&7zIW7F&Au}aYIUSw^2RvkH zbU_#>EfuBcn3$kKB@PUb+~~wa0lDnb0T+eJi)U4h4sD@En}(xY6CEA{e*F*|FRo55 zotOtLp1F*a z+W}>%?lgo6Ege?@X;ar7N6_VDymq?1Bxv+eX%-`6i!>ykI|>T+{&ih;p;g6}UQ3Cz zpfG0iSp1j6Nx|cbsUW^C^m%52g1yD7=kpEN!W1=X8?unE>Ybl-ZuiNDYf6*d@hVYJ zn26Pf`#&i%9UnTXp#WPhG}aW~AO?SUxVR+x#Kf}^do(BZRQ3w`ecygYf4qJRQzQbW z=cZwC69+m;W=Q95@Zomq6MvW?#{IWfoq~e|(M{GVNNq`DDlzQoEj@H}dEP^zQljj8 zEG!8(;{(bKs^oPYKLnc*iPn9!e6Y&0vp0}SVJe_B)FiT?K3Xa+*qIqRV}<%U95wyL z@_5c?ZrWmZBR%?j(!DZ0zsCwO1moj%tMGP{yvkHB4ir0}{hE6X_)vk_Fs~njj;8;{ zc;V-lrZg+EVU@`8sq}s2u_?tVwpLe?p|&o|BFow?r7mF}voXiQO873$fUHIQZcS2t z;A)}4FN9_k6|Nx9VH1>fY_vY2D)nEZUwoAvoBK`%K76&FeB1eRKUgPUT;|*ED5Qoz zHl`CZ2EDlU|8w#0S1Ec$g{@o)&Km~ML$0Za|3Wk(gZz#+h}Xc6TkQ5@BD4KVKRKTP z;WY*GzV^Uik^v`aT$mpOfBPB{Xn6r0Gz!v;-4SwHR1iY_xX4wLB?dWSF#L?ANdG}) z;t2Lr-RQ>t*|1gc>ysr_D?88%Qz@s3K{`=uMtbnbqXMIv1+c6xNl>=TxgA5|4TR#C zc>WzZj!V=LXX#uI$NQR8Qti;8epJlpL5@k~O_pnqe$9vy$G_`UFJt3yQca|Ec*?MP zRa=Yk0idL$NH#m|c|C23LDF%*>X(R>Qpaquc;S3{jB*nJx<^}>uCE;S7!mS(PBSCz`)T!4B2+`)1`RE|^0N?HnZekx{&!7|vSF8d z{#Dp>+ET3kBn8bEO+fq9DWX`Z&KWPE$Oa{#BMkcb9m}`-yI)urdZA()?m31SI4Z;z z0?!C!Oqn^vL6=ADSylTALJ~Y8_lU^f?P-zO`R$q&ScVoPOFgN~poG`c?AsJg7NdO0 z|ImeKWBT*gikxxWmUe5SZXDJ}03~zvZ-dz%6JRzP&y)f!llg9jMye99{oQ)fO{-d= z$C679!X5!b19cypsBo5Yc=9Pk#w}3`5$pur8)4Cz{)~@6QODVW0wdcn8tK~R6X}$GG7+X- z3ZaK`65tbTkt+Al83(Tt{KRjgM4i|q3*w;rvdYQEQK>}GkHs-lrzPGDaW${v{B(=b zsr+B9cpgf{`TF;#die7%Bx!+@Q48kR7~6%t8V>j2zv~w0AU`<}8?eoE>WmsR7p83m zpWA5PrF1yZa+xuZF_UwS#29jra*>hGw5X}ZlBX!qN5SPFLM zRZjKhx=uAX2gTLE2%4Thg24Yu+|j)7O#LnYxNq>W+5P z&zW$o>d|~^4-L<(0YxFH3Vv<(WpnKn(xt6y@U;(Fkk4~WCn-SnGylAV=9N0RxH$UX zi+9FV#5W`C+H@blHlJGIGgh|@H{Wh8Srta83VZTc;T6}0imICOlMForUlQZhCslUk zPc2j&9ENOjgaNIa7H%+REeS0nX2Kl@m&*kw8_je$qgE zo~m4!FV{rs`Ly9Rk!Y}jjTBm))|<9lQveAUF3_Oq;E)33x^0{NR`3|>ju0d*>b2ih zBR=!8CxzhLN@vsxyXjAK;`%UKw(s7MnUHA)-kcO#Yr98do=b*2XSZ{ zmLE)Hkb~dfONPyw>*CSo`KHcZc?BsR%-PVG3sQRLAj8gA3Urx<8~%y?9=l&}X=Vs7 zzQl(kFhpBD70qa>9?~7>OrTKx_DjN!OT0|n;50Fv2d4f~q>j2RGp%w$yR>y~-&hf# z_PFW9d2RWw`zf9V``prhrf*Kw<>XL16v70SSipm*$>-leZHM2f)W7fPC(uk2X+C!H zn&3tvK4ZkYc^J_3LLt+adCOk(ef(qj-44WVcrnt&uXoJu9yLnBV9q)3(^aIyqN?va zh3L&rjRk!fR>8uVrmGq2B}-3_3PGe*4G9`%u`sj{dlu=U3a%mtsBhh0P~VE^=or(i zL@OS-(SKmyU|HCil;)~**ipPA)waVla(PJDE_Dm@vIps0b)?2 zYy}~i%}bJG&6(Z%v~ztl7VKRt#B3g2uxPc5`V0ykd^r!2hupPq(Bpx8{o+}o+$9~(A~*t8bd$YuHa(5oe^@ zN<@OpKhL|Wf;=Ft+?s;2wbT4;{p|9yBG2`17Fm)-Ycd0)uD97A0R3xJf4O?*Q=0uC zj~TU9!MwzC^@Rqtosom2Kz`{Lm)aP4ga~n8jEa11E$o%#FqHG&D@{2B{b^ZkEsW`w2!%@pMKLON zWFUrcVMPGC!0YEjxoh*@!GN2&Z{Kd<7?<%ad+M$y+eEA5v3X1V+44W2H}g)l_)^%3>dF%SZ1Jk0?A_0#(0AjSuj*&5KPFJj?`g<_Y* zUUzfoo)1-;-;Y*`Pq1rb+PEL6l62BqZ((uEVA9Fzy?bgsZbm&8^K9zc zi7|ItWU%03?z;GpuVcTZ%Z0e!cVcD|MXV^Bcfc@w3kmDn?JYe}-Q~-?oy6f3qiM*d zh&m75Rwypm*6E8*e;%v}y5*Ju)700WJLU>P$BPhHmJl-q-EL50vsiwrAax-vP84Iv z?ZSM*wn>{5YdWv>@7ZZ+AT|9|^EEho7Hi!}&!b{|MAb{If4|nrM#^BKzMD*ai`(Sb zw$^jq1n*Ni>6-AWVw(ERkQc3&-7R59fxK~pVS375j+El+bgTr5@TRkoRY722H*?FuzKuavM&2nz%5+<2cT!OXQ zPRjzBBi`YAY#jFht*Q)4vsDT}We@=Cc6<6| zM4QRg{3Qc;Q5RVz4Pk<%kYduADYf*`^Aqn5<7FcCw5}g}_rY`NBDMsWOywZEgQ`eS z{7F>|v1L{IMb)*G?$bi z+Ko4YnHYnKDKQ(b7WwytJ6cdUQ#!_ZL$>`%Pre8cBM0|rstplMEks|ctW-@BGu`k> zSt?lbIquYdbMoN7e`&j)3RN@mtC-exe>o;@>>Rv2wHdJX=`s1A0upKMexq3S%REHq zn`6p*^#O~2$KsM*mMN|1Q)6IYs_loTtuwnac@sR0xGu3-IBK@cvpEv0z;8|+MU15j zOOi?pd@Nh>Tp>D!My(f{6UbpnS-Huyn}Y{2XDZXhdYeXhr5KR{I(l_mRJx?6L%<8J zwCbnUg@+`|A^a~?uXCsJa**ehU}*dJaVHIo{_fDY8})tTBX4n_J7NkAQ7KQUu*O+QAReYPM8cLHN@; zsEz9J?<4#bMA(?obPYl3h7|Q6xCv`WPA5(e=S3jQNd{`goNYL9SxooPzgBbKu8PvfU;Q z?9b7MD%Nb}AaDMTq3C|W~&H14OWQRwV4p?Je5O!X9f5RC^n{{pfuO&8I!x0>$}>7r z!9NfXe`=!;t0*EwQf}zt-XqcFA;9U1x~M|1RK-3zU}3%@U)xG6qa0|ncz z%^n}$;i0z|Z;N3Hz255;7=~Kt-Vh$&b=^{r=t7a>C=udnIx)^?W@S3`o*Z5X+=qG; z=v*zl?o$Hd3~3)#>>`0);nP0K9fgHE7wrj>b1r@lRyA44n%T^Yi{)JAJvS2lY}t z-^ezr<&GP{j6UlUT*JY#at7nmsm9U1F>sAVAPcT>38#l1sDvw@ObuM&O4rkhO&OC>OM+X%nt(j=8x$N8Iq}+ z2*2z=FaKV?S~hC(td%Y-81P_$Fyih5@jKJOro(;QlSegBT~g4-yXuor^vs!^2XW&e znm-cAjfIw{(w7en;Pb6W6DJ_gE%Ne}kKE5biiMGYk>El6ejur@ffI|hV%6d*SG8)+ zAc=ddyz@mutmDR?8fS=2!`L5!2GT%%nuhuo`2m1XYb(@A%*oun+x+AN`_iScjkoHZ zcrk?BVkN7X2dsK2C7YZ;?#JvXfc2=ezR4zur{fSO3tK8j3{q^{rRU)kIK}+P--H>b zLK1RkU-8=2iQDk6?eyLt*x-fuWGyk|DLr$^KT1?TGrBh7M5GPr z6&LSvvgiS|5gWaL|Duna#g{4tvhRgP8!q_%Q3$%V|etJ2z^kxu3LxYWQd7*lVc^x!B=}Oq& zx^V^mzo<-^mDcY63ui!>zu8GtiPX8Atn-G*raq`$n23S|uG(ps5d9-K2;tVN5rCqMvCQd>3tL3&Ei% zD!?O#nhLRK9DqU7e6!JbI-SYp^NB<j-?aH(Ej>uo^7w zN$2nxPh**6GMh}K@`-E)C&Xj;8uz!1QZ^1}l=&T`9(OaMfZ)7{K23AlaNF?%!B%s3v59}$7rjtnnL-}FW zhGO!E+0)B++?Yq&6apt9F8clo!vp?5xd(9088ymYG<%%xJ@ycl-#of=KwJDLE`Q|g z;k9+MGxqR$o1w=^6CNXbSIwE-m^^>-XQQJt?amckuc{z8uT_`LS{BdSVYC+?c59!p zP$w{~S>KGd+Dj_av(<2j z>#Yy=cQI43ns+ny4;F_57{-SNEwLYfhj>^!c2V?1^0g#(!B*#@nAnwM@zU=O&K|0!$sOQv2H1nzNz4h5A?mho!lPTq zE)V@LOn>mnUa0VWW4Ko|n}fXE~c)B;#B zLey|FxEDOE{FIf-DjK*LB;)}f3}F&7E{e>7JdErypsJ#>w7S`6xADI5@$va(jMyYv z=k)()5848K(AdKzlORxUO(psm#vWs;3QqjM4AZwV;bFxd-X?nhJWii>vd137v=AI$ zzi{r;E9YN{O*w7>9IdfunQSt(kxy+D%7qlR6Q(x6QW%uSkvVXUCOjZkM5`X5&=VK;^*xd9&3F5>;L#kulw_88&tIPHi%_J)U|2(QYnXSbvWwXtX5Nu@SY zsX`gM(eVr)z#VDC1abz_Mh2X(3`(*GtjWTCut$H(I|heCMYiU1_@36SBk|?K13h6W z_+)+EerJc<6H{Ark?#c_`-?r^J7DY~vCy-(hIRqMQGqf+l3S7)dyLrG11AM7=W4{k z9{Yd?FPAH_{A$2MQ2-v`N+D$+d8F_xpQn^nE(3b*U0vbf zZHEWzDIt}_fn%?Uxh3$i$G!n%0BrzyAa@itASNfr3c_><&Es*v3B>CVh(uXP&TO#1 zH*nZ;TTGxD71|FkJgB3(C0G+AO$k2qfdhhFo-dX?4v^S|>s!`(HQY256h)v88R5Z1 zNi2Ar=?D*AHRrSDuMa#VpwXcI4Wc8TC@|Lwhy4H+KpPoys}LT!WImtAYDb8oavpm0 z_YMyeB%VVK56r^TteDMQ01rh}HHqd6)E86t;F+rfh34{r;FjDy8rM~&mG|y8crY?S zWO&=k9u%1)JP=s2EU6V|o@B5r|Zo!^oE^aU#$a|Cs9#!NY}BLH&Qs zUEfbrX&Ua0$7~O0`OZ!^GV(z`09`udtN{#XQWDaHU9gGnlnkPa#0giB;F8_NWD<}R za9|NcS|bygim`8*M#wcyFw^F^kO7xYFvgjoaq84@(!ynonT&ClRd+QVq6g9r z>XFCN2#+|XQp+=d5Fj5wI*^+DG(+fc(yJ54%L{{tR0Bf2pD|t2-CEd1PiY);*fgF{ zqSLB?9A)@Lxd-(2nqLFbrn>JDpw!c*J8EC6I+6JmN$*;7|)By+rzL z-8tl=FmR{=EeQ|9wUsL`WELn2kUzRWGBY|oUKDuj$~~kFdZFCo;6EM%Cv&1lowF3E zf=6bY-Ju@YwP@F^y&pR$zw}&(g2MZ4VBULLll>EZ=s5}>06YLD24~h#XcA{O_>Jc#P0*siI%f>v;VSMy8H4pc7DISYyCX)u z^JFTnfPw%?CQw+tyW8O%g~B5P5vj-EW_b8~RP(_VOsf768fcgQyTynFxY0jY^e8KI z9jZ9dqfUuUJMbX1DD#5su3#p&>cyEWLuWjC>w$=Vv-;5DuWt(890*u;v~|Q5t${#b z1mJN!5D`OXCj!k(Tn~&0E-nND01wk$@Zbm!2oL}a0LOYf1(9Uw&D&H=6|r!#Brz@5 zKNLLFJV~L^LwVygG>mcXUU)$EgcBK?&$%zpEk^dnJ-QCOEhrU6*M<)gkE` zPdclsr~1XvA4BJB0Uqw+9-IR_WZYPPvA!O|q-qIAt_U9KI5t3(Y_x=j6mWOig8QxQ zDrt8dc6T*Au)t|X#uhdo9A`Z@YjdM`N+oj7yfiDmOLsoLBjGW>Hd$9#*Sr|;km83~ zc;rS8|7IbE#!JnNalCjOa;irY*F$r+LyOT{_pPDoaezn7t^4+k(#X)=ha=B==IqzQ z!hYJ)WIvsXJPL(tF8*#-D{&b-h?-;cKuE+=)B=p9DXog5iu6n_IvU6Z1hE^vpJ_kfRnut8Ud(-b<{g;G?KzM{E&FJ}YfQM;+ zAA*0UC;0tM%ZB8NxvZ`W@OTd}0RD}ufvFjqAA!^=9ZRN?xa~2jENj}@lrN5QaW0g7 zWNe?ul<2TK+ky}sA`6S2oITSL6o9qP0XQtIt1I$8nMlZ~k>#1`nbAb*4K~o%QDJ=sccF0kT!juY z6wJhq@`J&{@VS|q!-ZK`+}IXmY$RgiinGwRfJf#2MMTRswgq#z2mE7eb6DZ=9~$>i zwlE&Ctanq4mH0vHiB9ThX2sG zM>cv?Vf2tTH<(=2RW)wXpYCkVbu;C+?@mNS&FZ~b#vio+H=hG|M6dOe|&N)SB0AXPZ0 zU+$z<1*3zE58B2I7sJD2c(jet!|-@;QWpSXZ{7E(+<)JrZ2r#R+SgxS{pzcapA6@y z!2$OeT${82kDSZs@#&$#!?D<`%fQ2*<>pyNa=AG#PxeN`K~vag!WOgb*7o*R(>~Mm zcy;bbYwd$*IKu4k2#*HZN4PlC9s9v!$l?e z1ky6lNa+^!Zn;3G-LNpZn!%00 z<>b-}j2jp@aM>e4A`H{h-4Y$-@1f=q4;nwpPhjP0f7~Mzx=FlZgFw?!$EX}-S?Df4 zh>{lS`FzfW+YIpO4ZOEi^guLhPOc2E&x1pzG}*da^yu2)Ok29qJdG+>G?t5LloZhL z=pLV@S}GEBtT#7EF-RfA`L)T2(DKtb07gc1$-mEuUHJIh>%}OMb|N~ihz?pTugVP`3LXwV z{2le#>#X3Rt`l{Ln4ug5P}{)V0egPhNE zw#VycdA@9)*yjaS>_A?0^uU<5HZ?xp(WX zIa2c-*vbB_H#boatX#p9gKIdHq;3DX_McpJwlcjK(Zla=Y-bW4RaMHKStVDEIi}72 zekMw?^J*HwLtb^S;nk)15gwe|H8r+VO#~M}O59PuLK{%SEK8-9XO`crzxtV^7~;u< z0}h#0Wmtzo$8l$>WEYH-?+{LazCdzi?92WJmkXb3xUH=V&~&LUtgd9czu17I<4|FH5Wa(>dLjI-I9A`lB>$WwV=>;N%p8~{w=~TSrdgE`JyP){Ny?W{qa-d@JyOd=NwATg!nG*p34+fGN;Isjy!`RU z6*LQcxiUJsGP)ueJo$y3P+K8N_3gNV5Iu$7=VQh`yXFw94Pkfow+8~ja8RAFya~_= zXKwIuxD5uc{3V!k0>O^HmYz`U$#<8g>OQTgo|?LM?_J3Uh#r+!ySlP3cG9e?$jNQn z#J5b}&e5YWaAR-q_{|?azaSVy&4ZUnOFj=U22>g0aq5WZMRatwwrAlX8-(qg=lwO! z{?mwvUhfMCkI!ohrg=HhiRhWWpy`yiwmBL~=KzOyMf9MxU+aC61a;GIaQ6vM48`DL z3M0516{DGxG>x~*Su9d9A$1@85Pl(K5~vvGL>&k_|0nMJU)wm(0Di^nLUlUw-l9Sb zuk2T{=jNhaO?5#pmAd0#R98Wh$jHK;q6zk#v8JQ;P1UumVaH*5V{1TdVBa*64%=I&L;@ z${~*J&FGFjI(c&KXl}a*oTJ=_adajx~3`j1W%jFQ0w7{gd-&@^BC=Jv&xwt*7*J@5? ztQgM#9d=piqx2Z+;xW1J*c}oExDXUn7(@vx=ZW~njRg%1(TMT_Pv&s6oKgiIPa1#z zAw1B9RmJNKuIc_+x2jWdK*lR&pd&$4fk$%O$0JtJ!|+`YjdR8r*RZ^*HovvXTg^P9 zlBPAr6B^@$QG?f442@AP8p3LHifE{WQP{x<=h#_<)-N06Y{A4gDENUgr^KMgR#8#Z z{W98*9$mR|esOW}%14imFnt8`qbvUU;UcZ)&oAQq{Rxf)N8!;SR62_7Aw1(Uy;z?E zKI-*3C;Jp32V{vaDe&2=riG<}oA6{70FRjCIx`!YjNM$>Xxd4o?~dKU$;ng7z6jcw=!HcGIl*R4E8b}OnG=VK?vgUB* zkRU`xJSw{9d$YA{yHt z_oKlcxYyy&$TZ&?Ht-kKG!CcZEA|n=cf5f|3_J^t!yY>2m)Qvzt9YKmTGO2xq&KgkZCDVxOey;-K{E)00on~&FWe7aZ}y_*L-E?g}=?f@R@ zPN_Y=wK5iOE^J@jNakAhnK65nZQIS!&aNFFE>&PzHZH`IV|Ka~NP)RRSJxQ6yCuX>bmq*b4M$%9X%FEzf{KU97}n6La;t>jiq0DdyfJHciX4 ztePuc%r@?TXCXZb1$TTnIyPDvce90wNWbvFf#Je)C8oiB#tFP$9IFjdP=#v{iW!K)PMg!{@-B_E90u5Tur2uh`<9@ zR05_0aQ;uYjM>gV(%Q952W$^sKWWgZM4kyeZm@ZKm4AKNnBQ79mOfa?Z=VCBYq!+l zUzO7QgEfN^vUGKmq51`Qz*%hRy%nQ%F2{D83;fvdP{NY%mLdUu!&+I^x*=x`XCbSJ zsM!G)6akz>9UGRI9XO{a5{YayLs?j*zUm_>qCbMbq}N}>kIRV?l~T7>Wzc!y#F6o! zzrA=S8jY8Si}BHNy*1<1a%Q?W`w{|X-4rmGX3gn2a>cfz$L(Zc#;tnjeE zMmK8y@m|^h%Sj4%MWt_?O2HTLGA1Hb+0FgoJp^q^KWfRT;>GQP*)exHPgPIc&hKRU;pV@LQXi2RE1-8v|17*evCUaw$e<>eqK_wk%?h}bf2NR`~9w(vz z$Wif-(Q}2at5$1nx?G9H$CBj$53_CdriN}d8kU*O`grJGR4*5winBo|DsRW9U2&oZD&H^1i9+z{R z9LD1kRyS4q;?jL49cA^bwB5#79I-$+?r0`Q<9Jv2%v0X#;w zIt=j8zFq@?@-U@G?;9XJDBvN`z~#NQHy+rVywz-{0FRO4L+kyk_l;K5&=3#l7?mq5 zLykfM4e1~=Rb17fUN6FMIHYt7uwoibM2>`&>cD`jnnjbCSsYm!)Jnx48x=G^gTn`; zYlL*0DvHkvUXGTr3x9&p+3D%oiD|Gq0FsNd<#A_RHxExBD|F-|SF7dpS^@Ut(E6|h zB2Kngs^D=?2cz9Ht(lqr;t^E-96G(e4zgr#ud@JOu<}&S@iRAHkb)nPB!x^(5t&ls z&UbgS8fA#bJKus@g=too2n%5{neu9HwqnSOrg{z|y&}mHTZ-BC+QL#bUb62lyj2A0 zv4X~yqVCuhNDs;ZkGVC2-;0*)#|y05On`EQXk0dM*@@btYn%L9v9yUnli;k~Ce!X^ ztYaHs>$f))JcNQ=z31iuii>*x0-hZhh*dJtgb*s?Bmq@Vvko$$exy`;J{}}miDfdy z(b?!&@*?V4;}cHSY>056nR5!RbK#!ez`%J{uVq1S6o3i9B%6c1a2k59Di}Tl>0z0k zY0l1^=wDcHDCh=wdR>G%FxDXwRQnOz3j10Nfxpa>cTA#b{F^`g_nqJ04iZTi|4Cxa zpcX4&U8Xn=oea`B6-K8h1}-S3gfPN141vfPfT1EBB6DuYekoCZ;0Hs`I5Q~MaABM? zg5y0XE(UC(k^6u4uJ5;P>k11n#sH*=T>>1ihs%*72uhCN%Af?P4V{1wvlJGdWkMrt ziIf1r2&gDl8#{1Y818JR&_iN11BPS>1|#T$ADR}(fG$Hl>@Dwo^~?U5opUJ#S>vR! zD=Q7WD=D%iD~YB1-S0cU;WhBuX+qw;mhVKLu*+4uO++kd8M)|t)e$NXVg_wp*Uh%x z>nTAxT+U{jS+`VL&6cC6+-!Q@LTh0GkkSQsbU{94U3WE1t9`YVD}fG+fIZqsB$12b z=cjU(H$r#}yW+wIQ7LlWvg@j&WRDmfzl(X~ z#?wm@cIAIgt3MwevBM-G!UlsKTKwUYYgG6>CXy^^m z9(jPyN;E6c0!oN{oIJw(a~u(ggc*J!A5TbNnYn1_BI^he`;t{*qUTh?=H!%wR_TMeQoctt&a#^^QVIHC3-2r29|$>Aq=LO{)s*Q7V)3 zUq0PgB(h9-euVHq;VPn!9JZZCmY!WBq5$j>WeBBQVk{mWs$IN%`5IEk)$7kRdGK}# zI800A6R`Oyj~koH@mO-)?l`u9CNNR}`yERyg#@KB)Bz&GG>7mI;AuhR5pr^^H7>3@_$DtYmI-2c6 z&nq{p<%RBQRL&l$>1496dY-py^vyo3uoD7%cwm}OMcvla6tYKE9xZ#s__*|jRhXk#SboDBUB*QKlp5E01tw(WJ%yL-wR2AwX&a- z(M5wLH;K4IG29Cn#R2}KMaD3I34o3$6bVKK;B{cw6iI?5_~HW+rpHU~nC(Fb!KjBQ zYOYz&X<=3KCL+Tg3p}WysB5OGhL*9iq8Le2+3j1&wY4J)*yFH&))*kt zCc?vOHnYu67A|4du6tmZl%iG(*`s6*JXiextW(<_!@jtmZ!$NyAoDL(y8m2(b0 znIuV&ic4QF5O#Er2_77W@Zbn10X*pN&0s0FJc9?eu|S`tFgfsFvW^BKIx=M>xOj9F zO>hFAm}LKLmRZ5VWAK*%Wh7Yj8fq}~l%pt$olkj0 zb2B8J&qQ6y%ba|c@L=f;hQ6}0_F*!x6vbBzv%kB0Yxh>Kr~76y{3Z$TD7O{IHbccw z?ERjymbSoL&#uFzlZ9&l@CaHFnDOQ6YO5V&4e!D+@R)>8@KlancEkKbI*!dMYeZNO z$T-heSwwLK8~X)#oU6qn^f6F~A>Cu)fwdKwHtxD^hH9;5!7)juh1efCJbo0O6p3N3 zt*xz?R%ieKOhey=)w6rOeZ@5Us(KVO)wJ1XGg{!zwA8Q-76?vnQE-T=uRBf;Yg2uI zl>}SG!3e3@%QS{c$ zcBX2*N&Apv)`{4I5JP`|W5eH=xu+-__cr|Z0Uy2ny6-r4Pf?RrKdsn4!lmcqH6BUN zaN*my9L%G%oqf1C>;XIEk8PL1ai_|;ii^k5HF+nHgP4`gNyn zJBn{vRyytb$PkXBIQ6;%-xy7_?V$T)2b04tg zZ6jCA>_Cd|;_RnEs8kch$+5#jEJ}&%mp?0>OLz!K4)Ii^H?b7)1JjB{^n8yT9xoA> zZUcSzhz@|rjDIjQ14c;Qx8ZRmy)_r8PTj#ej<}cumLGI51!cH8%pbhmn4hbG{4x|j z5V@Bsh*(zf$;H)|zr~j7IQN`88`2&K%opU;^Ze&Aiz`Zm)qm`e^C_Qb5l4$kZ}h%n zd#_><>m*P2Z~ZiT@Xwv2gb?4E^=JOHva;d>G=M1BTvRr`OSR@JjgQyzY|X;0&b~S@ zd?npRh}=15t*^I^odN}G^W@^{eq20GxHn8SJefazDr&)sqSll)WDikJBoe$hcJ@dJ zV&d_qe~>269d*bcXp2?YaDA6G^Fo&##|x7z=aiQ(B(MP|CcX)iVgg(FaT490zdcQ; zfX+I24ojVRj0&-o#0vucnK&hTpht;H9QGB%oGXrii~@sN_p!MRYn{K9-rCx#)oODM z5K!|$(uwf_@+tm8Y0PaYzO7ix1Awf@*O*Jz*S~%6=U1#xUkeYBo4z&d2nx49-bZ)t zU5OI}j_2hIX8?~VnVN8tN!3Z2!*b&4YV%i=d84810+(ZJlNwYxXU|p6geAVU(=&#L zNa^`x4>BFineuL1u15)}a+L^yYL2S+)9*8ZKzEJ{nd zs@uDp-})&fyM2(fk1~O+JBN$g_blD-?fvWFp7!3oM-nXpJhYCY=*}a<-`~@|^A&q{ zv3SQ2%q_y>CfgJ-we*LJ!F7K-f@nmFW&1Ht{psL_3$4(e6m^i zZvT?@ef{=(|7Gv`Ufam7@PJ@SG#WS;+_!6VB@0Djm>6uM0jo8lpm+^KWFtg0md0S9 zNELPnUZ5ZZa%@bo9Skh=#e`rWKx>B#-BOyeFMZ2@kk|ezJ?Gq!qrkS?cpJ+g-^5ta zj1?z7pT6_+J7+IX=FZfUzL}= zt5@q^Qcxd<2f1e8l3QmdZ3Db)PE$u%Lqdp}wI;V;g`w}asw{{++Zdf}Bb!SH1S6k- z#2E64Lojl0q(kjy9Y3M&B~!#Aqrh2N&T0QdGf0XCylhE|%Ph+ySY~1d!?CaQg8`LI zWB@>IBr1!OhDRzzp}9MKiQOc_;|C>OfmUzI^9#5-T3592$_p+P#u*pS&R)CT-qHHr zQNQ-i1=EN}iHFfUSNWIf(P}2YM1m7e^W}Q9na}5zmcfz&jgIe5@nR~jC2K@Q=e-P6L58FN0;T0MB@7xL=JQN!|q91bpBWQx}a4s~vT=kv+~D!FRkE9&>+1$lk?o=oJy=EP2;3_n2I0F2uoK_hA~HD_hDK9@&^Z%6(_}=0M23SIf?m&C_RR->y8% zeRPL|*;jo5ifBe5JUoQQ(7zm>zgKT72X8lb9~T|(s&cA+v#h>ksp5E9P(I3@>|H#l zA|NeGniAcqT8L0+#`Qg94m?$MxCkO)NLS+OU$4nNRg57`IZ;Fa^J~?7c@sHgDTC$= zt8IWzBJ1QUJl*v_+xXah+80YEzaBhViKPkFgKMP((Tt=?`{SjKXZNuxK30>1 zhp^1)?AS$kNLX3Jv;MT$m+G*uhAV6RVX+TVdd0Ox0q9&UuJv6d-)^3owq+{so4#FI z6yD0BD-TbEceqwMT>o3S|I5S1z8W5`Ej#Ll&Xp8iHC_GKtSn2-9)2}Mlkdf(KsHa* zLD{Uq*?B&S#YGbGtf+{HkH|@@7P{V~PJjtYDj;~ry)oU7QUY7rqHJ3!Lr9C1z&uL`kV%s?MX9gdNEu01Uon!j_JDgcXebFI~3C1;W|B)vAn&#)2&Yl>6Br)%!V6#f{C9ZR-qY0+kV;6fkUf&JM&Y*( z%Lj#c=tHvy*Th3^JLGKdK<96XCO9mK2su7i5D6vt0zN(w9w+bLk8Z*q;+{Pw&mOjV z_U4aTnV4D>A#%h@U2Tovjm5S`c>=(wF)t|A?IjIz62En((ay@$t* z;9=auWAg9-82TC7__Qwd#@MDG#ChD<_R&MqVR3#EoLoaWigHM;>vTV(5=Dzj1I< zjjM>rBqP|w1ah13u#}RXW$+FQR_zB+LP*7p@mjK6Qp2=BqXr}1?r2$puiD(40G5)% z0+5mf&%pzWUW9%rPOnSS#^5b=DJ^g=Kue*sEUdoc{{RnLsO>-9;(y)!`B8YJED{y6 zz;y{8Xe{%+UNh`=yJ0unXzK3VxJOs3EbwpLw1`0A9<16ZFku+sm;0^Jm^yykV(gJZ zc>K1P**c*OrGf+w-!?Y)X%#sw?X}pB0l*ZtN&3>H>Mzl%1<9Ek9zEe9_aLEI7Dy0W zjzWZZE_hd4prnoWkUBE$)S%%kx@?jNI;jrPV}YNk2jXWeRT%YLftuEq#5)z5gOgz$ zs{<9!!GJnoO6` z%YNy}N7oc!!oS%&gPt~$ECBnm9>r~Ix-`sTrLw5BEeGP%uo{pHxh1RTK!`^qX*Oyl zI4ly1G>M|vlfmX3jB zNp>d-GZ-|kq=D|PY6Gs1_g=kM?_pgftd>O3?J8tO@w?=*%ov6H5|$ogLgr4I7<#TZ ziR-!;Dk>%x2`lYjP$+Kb#l#X`XWKiW@DMD^B;3d#f)WQKNWJaa+()-PWZ8+>?b-&N zwLN?+Ixs#y-dl`2wZRVah(!|7JU= zn0SKNd+FxdiV%4$bR3H^5t?WuqNQRY$}ol#uIZeLOd?8TVI~rZJP$?B#dLNtp#vUf zEU$AGikYz(Hj6EP$Ca682vN~ zqmhr}NsoY_xZi_yrALQt5Bw`iXehiw+)P>R>YmO7_xV4hdEA@{^f1=a*ER(lNKWqO z^5ZgfW0^47ysfHgg3Ew!VIl9~*aQt_J;`%G*Xbxr|~OfAjg=bCDqm5TY26_nD!E*q9Z~)D}6r0-|R_50w{~Jd+j8)JmwCS~Sa6d`Yd~PJ`yd zN@(oDjo3(*hmz+q!73{aEktKFmN~&vGsm($B+9Avs@uK#w$_G zp9D__0J-_}-ej%%Y01)QW^IvBLg~>`sQwJ;4kZB(Y8r@#7x2*8mC?~@aj{gk z@?*;A=;&R&sRfM|2RyuDZihH{G~mVq%p69WMF)=%nEAI}<1x|T>}DA8;D>l{51>Ke z6`I=AXt^2%JQ(1?0$3dLSa?wK`%D9O%2uuj5yBA|Omf1_!&a-2voC#Ud-AjMdVOzi zzh1BRzG%1aPtxxpmM(L%lv@6am8aKIaXPW<72B%Lm<)PXls#HoDXGgsM8(K{GMOi0 zq(Khw;1hjO#&pC(xOm*m46TUmlrDe=5GrD3BQG|!#Wo%RkGHwOqys#zuM&_ftdv?| z+o`y-#&s+_WGW*bUFp&3g1MAM3AUo!Lt0H;;A8uU2gB*UsTdKZ>f)j1 z#l*(>#9XmAxS@+NZ52#&5?WUy>bQ=H0AAyPXrOg-P3sFAh=&nQRe1n6;vCB~Cq(Lc z%})Uy!o05Cn+hv=r=_t(aXl$maUr7paCC7>p;{IEot%b^Ep z9=i4*mgY2bEzOrM6Je&OlbndB%M8azUXn?(0Q6-`X>Kk}C;R(F$r_waGB4QW0pIc5 zfW*bT$gtpXdayP_#V+aVjexvE*8Nw_sO#oDw{YWkSr63hQz32rA+A_3!~8zbHZM zC)mS&Te;e;=jx4etz0fE+17sl$(fgaNsNuPCPLmXQpJUEdYuq)p6edK!mUDvXU1~S6$>yZK;3=jzT{2m+)dKLb9k6clz?G}`z zE*_^qdT{Yf8`3T`qL`#N5Re@%3?mp0M_fR1?}OuQ>G5+sayE#OU7#a}c$_WQmOnsI zH}Z7q^$#n(I1#h4`Sv!gc<i>Em`c4;@FwzCntn?{^3 z)l!qfcat9 zTiI4Ci)X_Y2n`$Pfd9E18sK=(Sp~++yP#YZ;5y<_w{!KWLC=}`-T3}`6}JoeJB)`+ zF(i?8P4mtwSO45)kJc8rxn7}ef+s}yGx;&Bw^N@k1ySdhBPRcGD}bvkvthGd zR}xkLdxbWVPqwm67A&!%l_R^$BC%+Ic%WGYRwA_ukBC=gU7c ziN)ITFEf{2JjTGodd9Ac$J@mNw?PnDA?c%!e4h}KM@vi3!GMH=_nza?fAH^d>Mt+N zAK!cY3?P|}J}_rMCgC+{Zr<9o@F;}sQ03YF{v5;93Xi{h#w_0Z*EP1f|-_JoFJb<9&(Jc@|aPb)3dI)p_gX=CHZx;{2i_d5hc~8uI4N%bE88hsn<$-`o6o!fdbsA7DYuzkmJpi+*BwTs+3WgLkdR4*?Hcd(F}( zC$LF2DT*I}$v8&?<@|BWcD#d`vuT2Uvs?}A8dO1zAryT0J7*)?Y)J%q|OHTC~RhOOW zGF7iR)eBU;QFEwgsXCT$s8h7z#M$uGIR1i1Dmc_NgO)PytaF2^i)~pG^J}tqR6INr z9#)jViTc3uu8zLByT89*uh+q79Dw-s<6~X7@vuCsnd$eY_YMztwmXEMSk0>QtApfg}@jsEZsnG3IReRTWE7oehu1p?!obIMhLGxXi6P>&(!GD=iBN zQ^;Z7dzl{zkIMoN_aVugnGAiizke6lsGrp9eqHzb{Ri+yIN<9HBM#fWqL`f4PhPz` z-0mfZE*@i950)Kj-UBxbm5ViI0jMWe*lwYM-3Ge?#i2z4s6g$xJ^(`SkKj>LO$fc1 zaIJZ%-YPlJp1oO>vq~#TIMQBYz{=OAZ%GqpcDTUVa63QOQK9`$p&x;chPM{2rekZN zR9qB#Zr|4f4-xmuwK{y=e|&uGr-FRgh~VKtYvch(<{oIToSeMsW<$2Of8pXWUTDtx z{(18cD+8P1^|ES|sf7&MXB=Sklt7zsqg};~BO}%|X7=H(BAf<>Ng550OCFJBc^10; z^df+Y?KGVb)+=9X~8}v)JtO(#?PMUiMww#(Xrw5iEZ zv<~c^FBO%%ESr=}=s(!|bEPl|gB#AP3fO!&wOUJv-M^$jvv>EC25cQw+h90i<*wG_g6#)d z5TnMdd56Yh3S$pJ+_lU>H#{0T8kG3$$fP5aPHjlj&2sS=&$${lG!HUG?2SY92#&-m znU0PLx6v4O**Fz-5MkNuAUsICT6MOGkaR9X@7Y!@T3-*2RLknc(t-aOAtp3D9+xIW zf#=0t-QNoj8iH66y58NoSlR>2hFFBSc#Ju)>-p^U9|u1xD_vu%=<*Eg4JhgLaBZ&Q z9930IRa8~Oh2`b&tkKi(a4`k*tHnwy9-V`_>2k1E%RBX24kts1F&l_@_FEC}NKD$o8)Yw&KH52a{6DXxZ3cs~jw5>+f5&5VKrFf1hHQca< zR5xip70%T*Vrq}rqx#{7QOqI9QRBjc4T3}{-`b`>V#7h*9 zh_+rPErE-YZ_ijx#YrVqX^)2j>W5W(U@Xd{)E;Bdnpyx8lU_#KlD$PP+PR7^GnEnW z5Ilkp@z8tYq1(1aZ?zJwfk#7ie&FIUUT99&TzRHE9uMwLC-_)s6+1C;nJyvq2*Q-W zdqg1zU7AiW6Dw_ORmGX;BUMqOmC64HGzfm9P1p9D*2J_@l5-ZgWu7n?kb7eoF9k*N;Subvl=);FzgZC>4-~{tY zo=r+V3lH>ov7tYiYu+#Zcdh|Rr`&$ zYBnC4n#!~~T}qo9rOX+$e0%uHcA_*TWECCRV3>SQ_ph9Y!B>>x7tCI`cQqJ~w)+;( z3jAO^Mw4ULdW^Lskvdn`!9uW-S4`q|>LNZqg>DZ$A@Tytqt*j>L_jo6Mk}F3BESX- zM1U7K)`YD#m) zd#$ukEEe-=3_Vg+yEmtpU`xE*507Y>5Um>?815Dum1rA9sHIefzRsz^yglIop+~xB zw=X5o_X{nUuGbSMc=g6&%2O*&x;Si5<2_zWAPsO%HS*BunV3<$}X_8jL2H+94W=lwX6+@3^ zSkger3PvpJ!ObtD^(aTVcM=bMcmv{Ek1_EOz(!Pd_rC)9^ob=3CcgT2Bl#&=0wl)bEd zGiR+e->85Ti&gl{*el@|R?~J78X=o>cz3f%h>AY}!5q~ZqqK|*G%K;-$t5rzk3tv^ zA^-flXFZzZR(+?{n<*EMaq&p{e82fA%FWkXmh95xw|4T$w=`L|Prjzfn=kC-i<_;N ze*Bpn(J~1-087*g^gUyd2G`LN4&PKP2ujQ%`ZPu<8d5elW9K(^r}YSsS;ac5p^HVG zD|X;m;nZ687QT69=CaEStx9ur%wayWB;GM=Sp^D$4=znOq{IG z%p}pZA~~7!-S7OC&b(`@zpsZ*LfTz*O=q zk*gRUCo^W$qSVOA79KY?u6A>|Z{9I^`zDsR?C8nM7{x3Ls8J}yO$1j@k z;mh-fy4z??>@dS})TByk64*rp zH|31Sf!(A5sui_I0Y%y9Ga394s0KszG5s(c#wHbHJz&j3WH$^QyYzn5Gt?jYPvK2g_PD1u9##HZrE zIfcchjB54#OXhkMi*C23N0Hui&LHkOWQL2`3Bks1gN}}C5vSK(qXQH8`uu{g4kX14bB`UDae;B*LDr41+91A>qi1VI=CgetD- zah4#sgJTu8&C6(Y@UwZ|hc(-POCcLukVKcg(6g+WN~ zLZRmdHrGSMMnT)LAzdDfl3GOH?*qNWZ)=m_v6~kQ`7G>la&mHVvdw$k2|VT{fyaW5 zI0V^1iV##a051u-u)wW+6hh#t9oJ4(yu^5dSIubTL^f%9NE_Nd^V+>2?rvhl1bOdz zkWQ1k!E7b^khq3KhAO>wXULRJ3Ok? znzh;aGj1lU_xaRX2eL;{zEbMZE$$Hx9D)`^>5`QppK0uw422fNOE4Ts>($4{WFnGm;9* zk;B-TJG zV-6mvoLp*uhdRPyF=Zdk4T(w=J;N{tA?etiQdBw<2%|*M~m3wey&^YbWOcHQ3m zax1ytdfTBgN-wHkTbOEOdl8C$(Jx9UJowD)k$r#L*_mgLjS~^$@RW<{{lKJROKkYD z4F+IZ6t?HvGi(3&PpC-rd`X@?Hw@$H%&Ivjgt3Pr-U)jU(_Y^`i$1`Xy+M+JJ+eu% zHNqANd~*-rfw6qbbxq7hMJCT!gr8tGlr6GfkBBdROSxU@dtj-MpPMn66LIQFsY~E^ z-5&JguRbt5u$0{lnfL+4OG7+Wl=9fGu+$JL5_0PS*AE7d%6_mOc&Ni>OTyUosiU2{ zAMj{$x_Se3g~(N@z_0i~MA7F?Rg6D8JjB)DLA;SWuiglGF!un-EbnJ8R{p8KqWboO zfyeb}!E6?;QumsXiIr|cUhaErlwdQ8+?)6V3?3zZ)!S)0*ISGGv7+yRrB#gWU|fzG z^4uUdBWSZJ3BB@ZLofSFX380w>O(jQ*%k6od=CnbwfG)hThSXfRk^Nm0gugQj~=(L zthAl)LevfyK7IPT&kLd?u1Z!TZXm70xZ?R39y{4YyapagjMZS9zuPsnIv38&;SmHf zHsfHC-GR!dCF~In_acwE@}toMaZy$)D!D>)RMq3kirC^R5D~(XwE3=ilk->nA;p7y zzVznnSI=LaO9%X_@UXd#vKDyc0UnuoNRn7GVUZvNZMGM2TtV&jC`b4jnn`pQtvxM< zhZjXqU$Q98Cm0$r8=e5eY2|(LaEz;u*I`^?X^(4Rsmb*jI!bu+jjR1Q;F?|XVu{Zm zeE#bB^H(npO8Hge$Qs9KYYFT!-y@$@+{)6u913@i$08nWmDmZl z^|&(-*+<-PX;6xuGJ%I+?F(CY%<5IY)9&fudMLH>$i(*{Er=JO1B*-Dby32YFNys5 zw^IHf({pE1R}%5M;88gE==k{Xcr9`m%klS5s%#d6ozRA%_4n((-*#Z6PS_=J0f`kw z?oxOZg$wow^esGQ6-x5_#>-WGlUy!4tI;`NO@Zgm`hNztKr$SCF<*vVh zYm2wQ9{hpyWCi*6U;p;*$-5;l(pP>uJpSq3Gv=U|2h*wN2I*P|X`?bhDD0A$J;3$2 zB5^)t4-`J$!ed4xC-QI@l@*L@E^oH)1w8N$tFYXi?)G-Ga~dv&2SguyN{Txp=~}ya7y}oFs4k0vjOth4zk6mFPL_Cd3GnRPpbfhq?CO-Jn{6}OB%n2+vm*<%hK%}!|PbroZ5^{tV5AB-!J zRY>xaihe9vP1E6=CGf!58m*Kjp@6b0%EW?OAA77QNkRLP&`h=Z&7DM?4E%?r=S5=h*Wr-FowkOr}xUYSIl7Hr%*|(JF6U^SPpuo-_0mEQuH^ znpDF4eegYYVbM!v)vgs3N21 zY~gW9*>DcWIYC~M?m^bvwPfmN^ZX=%A?-UD6B93E534<2lRgiiNs{QodUNX+?4jK) zJQjJ=(0Vj^R+?5BxxLy^g?H3=Fq9Mhm1dJ?iLH*nHv*~`g@K+pCG%t0Nxmd@Ax%>-x? zLa7s42oypHp+Gp;t?5A_bVL7u{SWrF#h2w6l>d=fmJ{Ba(B*BAoN{63u6ScQy(RT4Wk=q0B`ZLhfeF>$CSzzFv61-eZZRr(=99)<0%PrRdcH zQn{UTTKBT~cF8yo4=dBwaw@U4%qe}jwQ8yp1rI7yo`gP- z&t#+FE#G&XHu4j+$&%ggtf5^N<(BUk`~Yop{~6lICJgtCi53r==5>KbR=Wgv+)62_ zCGUq9>4_~WxqBDjp~9v2{P}}knxw<7gGV6>8I{vFH;G$Cc$hvRZnsVfzBzKqO@4vC zj+jw%c=n?tuI0+@UQ=f{T^0M)xfCByL_KZ`!4q zTOWtV|6x-K@F1zXPaaHmIhcC);K7q84-g(dd1_`MhJvXRVs%2?dAl7K@nLr?6J2k0 zRBv@`g0{)TF2Ef&7^$<+*#+vSD%eS}H zE^ON*$QA5Wi}-n!WZFa_`8FY>qt${+x9!dcgsAfk+cycBpAr~Qt!l+>mvHOhR$84F zLcy$>%GlZw9=VFWNB;5%mR|43B>)d{@q3S%Ib}L^>sD%F^;RJNrP8RmQdO0th^nf7 z&9aS!N;TIagcKL5l_FWGp@gIYUQCRFMT{mAxYIODr`c$sP!(qC3pyd;sv|fBaaR{> zU9CWf-mFwZtP6AMX?Q4Cpx7<6!mlg(&PBpQRxd%gN~LZnb92fB>va_}r+{z;D4AQD zPLt`BJ|}`ET4)qwH&iokgIq+2SyZzjX|3Q^-OQRqQIlP}*rNMt0o~P!-9ad*xAQt| z+hGe+oL504BOp*UoUu`fS-*D`=N{;5o(M=1mBlNLL>MRfIOlgxlU7NKQG>XG##;{Y z939ukFDjjix+v4pC?c{V8;?5bTue$_&{3F^;p|TJJ?wToltiU-{*0$4JGL(y20^9c zsh;~r=bsQbAj|yu(D6Yht>bkkMP)_O1!YOzVqT8XX!j;<+7*Ly;g-i`mK?)&izErhg zj{r3R@BnN?3<%%D!$8J7LEcQ5C<007nCF9v2-BlAKhF8Vlhu_YwGCW~IS<71Zb3vj zfi5^_vdlJZ53i``52|q(iAG^hf-yyKX#qn4ILf#bN3X_-g?*1Prn8f5nPEz4zz)Mm z5uV4WfW@7sJAFxnFhvwmff=Y4gTtRwuctuZlJOmw$@r0EWbDD5whCKld z3Ikc8$2g!`KsaV}?33Z4T-OrYT)ih|f=WiG9V%%z)G%ws8wV>OXJhoLLaCeRc8O}D zQutJ9hh(hwO^ixDf5?epARi>lHLX-Ct@mQmr<^@{EFq2I0u1kxpj#w(q@)-lNc?eH zbn!&AzXf!pqcNi#Wq#xW1~h@h_w_y?2iIusiS>T4T9(*TZG-Yepc2b@%pNF@Ls~N` z@j>^{8#Kx?JJwz>CNs*pE^{f`FKr0+0#pC@K_AzDF{wnjlX=2U;D*KEL%$Vsf2)T* zz$ekK2Oh#Hs%;3?B^1#D9*;`fFj*ReNwgda@d(H$0s!dp+qOWKt}_l@!Fb1j40+e-LwCRw zbcBo^GXO**0tFX-#v`XpkF{-yA8TbPmgCUi{-jj>*<(T~LUJIA=YgiOh$? z!Xq4KerLHQ*bIhYL3l7v+C6#+?=q%q00`hb22LNQ&Lj_R22M{$&LsGUkl=<^IA5`F zHTx-%N``UOF93~K=)3AX8G;P<4c)z-P;zP;b>G1hKV%YdFX_^u!Hsbu@+pYGRc zwe35b4s=G}{;~TmC=P0C@ja+No_v*xrJ^i~@s}ed$$e^Py4X(je$jrvqQl;`jl4fsXgp!{d_z`3xwXV0?r1Ankm&s9qs^rXH}&2-=KwJpHH zv)8zZJ=U_7O1D! z{-|DFUhD4sR(MrO&m6s>lV-)C0nZ2Wf{`VkXMQiKkqtZ@ZJLJ22-`=Z)&$i~P8*J@hJ_p^N zXxZvk;jinxK{c~@wADv=P>EY>+In+icP~@N_TObo+x%7i1zTJB!?$~tGJT`<`G49w ztO=*= z%&kywvk8iNR(9Yc{g-!&d7)Hk-zcHCaw*+dwR5*ZJ}Ffe;bF2{*91JAUi~oi8h(rS z{Sv)B$wDt5njy0t(sNq?Rz)U&2Sh9;>ur4I7t(d$ot<)`F;H~JJBK5?MiuaYx>cE9 z`klaQltYfT4nBao4!=+;aBws1Dixy~+$!OfQI#2R0XjqunkFTLT^d!!8ixTv zg%fy`Aglo0MLdj(hPukUdK>Q5SqLB85@k#;e$2Ny;=vFPqYeGPY3dh-N!ZJBKqzAu zuGx2&KJzbS2k?kuk1mAfF0cL%e)> zKj88&mi@Z%rvL^>xCeNEcU9~vEnz)mMiCDg>SKg;Y`;G5ARZhsz)t`V*6094^%k6x zIDQa&WM_Ch79Nwb9&1w0!rXNXYFXnHXDC=-sWLLagR`?6!g~3Z15tot_Km8>dPWJ9 z(mLw|Lp3Bdg?R%!K(7M^H}Qaan=ZIx0uO?C)RY$2fJgPh{XN1% z1D&n6ZVx{-^|Q7%#DfAJgdrY;6EITi%WwQPJ1PSJ*a!SOI^+j_4$5E5TD|0O)?aYT zRd$fiQ4YYk zU`)ern*p9eZ-fUpQ&}{ZLp<(S4~Ev`Y-?qq6tKY@x~=$yX??Jpe$@QgRD{RlpQmO> zJ5e?UM?7?055eQEa&)f9(TQpz9+bT_Drz@>1Md4tvDavZ;B)1h;SdilHy~gbj|Ul9 zkG&HM6jj%)Pew)mq_kPjZn+t9;lVWs zLC^;~P^uS7OI@qyLI*0lA%qSc)lzLx{}Sa_J9_U7@Mv4F&&vT?MHyp{J)?TO=c98K z;8bUAqhneFJWAF@y%WVAr<8ofg9=o7<;hIQxSVWcv58% z9-8+h7l13&rh7T-lfUY^HxTLO7B|}5J5rj}u3_@tlCtXlGXOkHBLB6_ab^)*xMsli zq-#PD5AVo#i#YGWZgU|a8mK(Z(ZPS-2gN;kmkVWbAboZS>u$KYd?&IV{quYtoU1ph zx!h720(CGf?B!w5dv4_B^DVa5bU2q~wx_Hv*YYJ!ydxvGv50t>5PN{d*bsP-Mn^+$ z@8`{vx4%6%DonhuAv-T^rKc2+x$M6Em|B`rC1oN>B|DN|6npj%Mtk@s&?@)r0Akbv zsG4erRS5AMMgA9j z9(sik6Re;u)ucF(o*FQ(0Cv)*@+;_t6hd?@IYcU4H56*MTXcaV^CkN*Sle1)zF@m$`n16wj z-cf2JPN9qWYB7V2^Y9q_i#$gv6B)C6WkzKZt&fUQPoh-A!FDLJNR-0NL-ReGY!)5;b{P{raaoJT8YPn9 zT#y`Xz#@w(q?TV?USD#nVmN9}TF6W-9{avxrymawZSkS~N&nYe78U7P_G^asw^ul* z3no&;`SC)9{uisAXma0&@2dH5kD>wkAB}~M8BSu;FR?94e|PEE-KxW*m;Jbf^wi=3 z`Z}*YA|CGzdop;W*L~@QE`QxGRHlOx+qMMnuKL1yyzbI!I-Q=#iDusVQf@8# zb&(LcuQPWw2UkX*=M<%PM>(#^>ay@%Mn&YgGEVqCjg&`KN6icOij#55O2&+4G~Psy zG`8)-!zVNtp%|h_guK^=e0NZ-hm+g zlxt8u9sl;yiCfaQ9&s%x4i%g^IOwuNS_#Kk)z z6n+~QZ;RS%@e|w<;{CXINr+V?Cf>*j#WZ5#RZCRgi1!(Zm*V0gO0})Tl@YbK6IVuv zcj6;l5n?+r@JtHmc=~jD@erxF*4qu`9v&|e7hyae>%w|0KY&MEyfkqfY_ zM4xkWnIs;W%%3xvgqCfCC7hdEi;K6!w*19}mO9fNb&vvAQ-+4But)yv199;$l5|)k9pY zihU(hdO|F|>+c_UYW$TMJ8)~FQ1WmaZ* o%*w3H@R*fZnc*=jvog{0FEJczp!*ksaR2}S07*qoM6N<$f`CVo`~Uy| diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/intrada/test.py b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/intrada/test.py index 77bf700ab3..9830c7b3a3 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/intrada/test.py +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/intrada/test.py @@ -1,114 +1,114 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -#-------------------------------------------------------------------- -# modified from "ADVENT/advent/scripts/test.py" by Tuan-Hung Vu -#-------------------------------------------------------------------- -import argparse -import os -import os.path as osp -import pprint -import warnings -import torch - -from torch.utils import data - -from advent.model.deeplabv2 import get_deeplab_v2 -from advent.dataset.cityscapes import CityscapesDataSet -from advent.domain_adaptation.config import cfg, cfg_from_file -# from advent.domain_adaptation.eval_UDA import evaluate_domain_adaptation -from eval_UDA import evaluate_domain_adaptation - -warnings.filterwarnings("ignore", message="numpy.dtype size changed") -warnings.filterwarnings("ignore") - - -def get_arguments(): - """ - Parse input arguments - """ - parser = argparse.ArgumentParser(description="Code for evaluation") - parser.add_argument('--cfg', type=str, default=None, - help='optional config file', ) - parser.add_argument("--exp-suffix", type=str, default=None, - help="optional experiment suffix") - parser.add_argument('--device_type', type=str, default='npu') - parser.add_argument('--device_id', type=int, ) - return parser.parse_args() - - -def main(config_file, exp_suffix): - # LOAD ARGS - assert config_file is not None, 'Missing cfg file' - cfg_from_file(config_file) - # auto-generate exp name if not specified - # pdb.set_trace() - if cfg.EXP_NAME == '': - cfg.EXP_NAME = f'{cfg.SOURCE}2{cfg.TARGET}_{cfg.TRAIN.MODEL}_{cfg.TRAIN.DA_METHOD}' - if exp_suffix: - cfg.EXP_NAME += f'_{exp_suffix}' - # auto-generate snapshot path if not specified - # pdb.set_trace() - if cfg.TEST.SNAPSHOT_DIR[0] == '': - cfg.TEST.SNAPSHOT_DIR[0] = osp.join(cfg.EXP_ROOT_SNAPSHOT, cfg.EXP_NAME) - os.makedirs(cfg.TEST.SNAPSHOT_DIR[0], exist_ok=True) - - device = torch.device("{}:{}".format(args.device_type, args.device_id)) - if args.device_type == 'npu': - torch.npu.set_device(args.device_id) - elif args.device_type == 'cuda': - torch.cuda.set_device(args.device_id) - - print('Using config:') - pprint.pprint(cfg) - # load models - models = [] - n_models = len(cfg.TEST.MODEL) - if cfg.TEST.MODE == 'best': - assert n_models == 1, 'Not yet supported' - for i in range(n_models): - if cfg.TEST.MODEL[i] == 'DeepLabv2': - model = get_deeplab_v2(num_classes=cfg.NUM_CLASSES, - multi_level=cfg.TEST.MULTI_LEVEL[i]) - else: - raise NotImplementedError(f"Not yet supported {cfg.TEST.MODEL[i]}") - models.append(model) - - if os.environ.get('ADVENT_DRY_RUN', '0') == '1': - return - - # dataloaders - # pdb.set_trace() - test_dataset = CityscapesDataSet(root=cfg.DATA_DIRECTORY_TARGET, - list_path='../ADVENT/advent/dataset/cityscapes_list/{}.txt', - set=cfg.TEST.SET_TARGET, - info_path=cfg.TEST.INFO_TARGET, - crop_size=cfg.TEST.INPUT_SIZE_TARGET, - mean=cfg.TEST.IMG_MEAN, - labels_size=cfg.TEST.OUTPUT_SIZE_TARGET) - test_loader = data.DataLoader(test_dataset, - batch_size=cfg.TEST.BATCH_SIZE_TARGET, - num_workers=cfg.NUM_WORKERS, - shuffle=False, - pin_memory=True) - # eval - # pdb.set_trace() - evaluate_domain_adaptation(models, test_loader, cfg, device) - - -if __name__ == '__main__': - args = get_arguments() - print('Called with args:') - print(args) - main(args.cfg, args.exp_suffix) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +#-------------------------------------------------------------------- +# modified from "ADVENT/advent/scripts/test.py" by Tuan-Hung Vu +#-------------------------------------------------------------------- +import argparse +import os +import os.path as osp +import pprint +import warnings +import torch + +from torch.utils import data + +from advent.model.deeplabv2 import get_deeplab_v2 +from advent.dataset.cityscapes import CityscapesDataSet +from advent.domain_adaptation.config import cfg, cfg_from_file +# from advent.domain_adaptation.eval_UDA import evaluate_domain_adaptation +from eval_UDA import evaluate_domain_adaptation + +warnings.filterwarnings("ignore", message="numpy.dtype size changed") +warnings.filterwarnings("ignore") + + +def get_arguments(): + """ + Parse input arguments + """ + parser = argparse.ArgumentParser(description="Code for evaluation") + parser.add_argument('--cfg', type=str, default=None, + help='optional config file', ) + parser.add_argument("--exp-suffix", type=str, default=None, + help="optional experiment suffix") + parser.add_argument('--device_type', type=str, default='npu') + parser.add_argument('--device_id', type=int, ) + return parser.parse_args() + + +def main(config_file, exp_suffix): + # LOAD ARGS + assert config_file is not None, 'Missing cfg file' + cfg_from_file(config_file) + # auto-generate exp name if not specified + # pdb.set_trace() + if cfg.EXP_NAME == '': + cfg.EXP_NAME = f'{cfg.SOURCE}2{cfg.TARGET}_{cfg.TRAIN.MODEL}_{cfg.TRAIN.DA_METHOD}' + if exp_suffix: + cfg.EXP_NAME += f'_{exp_suffix}' + # auto-generate snapshot path if not specified + # pdb.set_trace() + if cfg.TEST.SNAPSHOT_DIR[0] == '': + cfg.TEST.SNAPSHOT_DIR[0] = osp.join(cfg.EXP_ROOT_SNAPSHOT, cfg.EXP_NAME) + os.makedirs(cfg.TEST.SNAPSHOT_DIR[0], exist_ok=True) + + device = torch.device("{}:{}".format(args.device_type, args.device_id)) + if args.device_type == 'npu': + torch.npu.set_device(args.device_id) + elif args.device_type == 'cuda': + torch.cuda.set_device(args.device_id) + + print('Using config:') + pprint.pprint(cfg) + # load models + models = [] + n_models = len(cfg.TEST.MODEL) + if cfg.TEST.MODE == 'best': + assert n_models == 1, 'Not yet supported' + for i in range(n_models): + if cfg.TEST.MODEL[i] == 'DeepLabv2': + model = get_deeplab_v2(num_classes=cfg.NUM_CLASSES, + multi_level=cfg.TEST.MULTI_LEVEL[i]) + else: + raise NotImplementedError(f"Not yet supported {cfg.TEST.MODEL[i]}") + models.append(model) + + if os.environ.get('ADVENT_DRY_RUN', '0') == '1': + return + + # dataloaders + # pdb.set_trace() + test_dataset = CityscapesDataSet(root=cfg.DATA_DIRECTORY_TARGET, + list_path='../ADVENT/advent/dataset/cityscapes_list/{}.txt', + set=cfg.TEST.SET_TARGET, + info_path=cfg.TEST.INFO_TARGET, + crop_size=cfg.TEST.INPUT_SIZE_TARGET, + mean=cfg.TEST.IMG_MEAN, + labels_size=cfg.TEST.OUTPUT_SIZE_TARGET) + test_loader = data.DataLoader(test_dataset, + batch_size=cfg.TEST.BATCH_SIZE_TARGET, + num_workers=cfg.NUM_WORKERS, + shuffle=False, + pin_memory=True) + # eval + # pdb.set_trace() + evaluate_domain_adaptation(models, test_loader, cfg, device) + + +if __name__ == '__main__': + args = get_arguments() + print('Called with args:') + print(args) + main(args.cfg, args.exp_suffix) diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/intrada/train.py b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/intrada/train.py index ce51c58991..89fbde254a 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/intrada/train.py +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/intrada/train.py @@ -1,197 +1,197 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -#-------------------------------------------------------------------- -# modified from "ADVENT/advent/scripts/train.py" by Tuan-Hung Vu -#-------------------------------------------------------------------- -import argparse -import os -import os.path as osp -import pprint -import random -import warnings - -import numpy as np -import yaml -import torch -from torch.utils import data - -from advent.model.deeplabv2 import get_deeplab_v2 -from advent.dataset.gta5 import GTA5DataSet -from advent.dataset.cityscapes import CityscapesDataSet as CityscapesDataSet_hard -from cityscapes import CityscapesDataSet as CityscapesDataSet_easy -from advent.domain_adaptation.config import cfg, cfg_from_file -from train_UDA import train_domain_adaptation - - -warnings.filterwarnings("ignore", message="numpy.dtype size changed") -warnings.filterwarnings("ignore") - - -def get_arguments(): - """ - Parse input arguments - """ - parser = argparse.ArgumentParser(description="Code for domain adaptation (DA) training") - parser.add_argument('--cfg', type=str, default=None, - help='optional config file', ) - parser.add_argument("--random-train", action="store_true", - help="not fixing random seed.") - parser.add_argument("--tensorboard", action="store_true", - help="visualize training loss with tensorboardX.") - parser.add_argument("--viz_every_iter", type=int, default=None, - help="visualize results.") - parser.add_argument("--exp-suffix", type=str, default=None, - help="optional experiment suffix") - parser.add_argument('--rank', type=int, default=0) - parser.add_argument('--device_type', type=str, default='npu') - parser.add_argument('--device_id', type=int, ) - parser.add_argument('--world_size', type=int, default=1) - parser.add_argument('--distributed', action='store_true', default=False) - parser.add_argument('--performance_log', action='store_true', default=False) - return parser.parse_args() - - -def main(): - # LOAD ARGS - args = get_arguments() - print('Called with args:') - print(args) - - # pdb.set_trace() - - assert args.cfg is not None, 'Missing cfg file' - cfg_from_file(args.cfg) - cfg.distributed = args.distributed - ddp_backend = "hccl" if args.device_type == "npu" else "nccl" - - if cfg.distributed: - torch.distributed.init_process_group(backend=ddp_backend, world_size=args.world_size, rank=args.rank) - device = torch.device("{}:{}".format(args.device_type ,args.device_id)) - cfg.device_id = args.device_id - cfg.rank = args.rank - cfg.world_size = args.world_size - cfg.device_type = args.device_type - cfg.performance_log = args.performance_log - if args.device_type == 'cuda': - torch.cuda.set_device(args.device_id) - elif args.device_type == 'npu': - torch.npu.set_device(args.device_id) - - cfg.is_master_node = args.world_size == 1 or args.device_id == 0 - - # auto-generate exp name if not specified - if cfg.EXP_NAME == '': - cfg.EXP_NAME = f'{cfg.SOURCE}2{cfg.TARGET}_{cfg.TRAIN.MODEL}_{cfg.TRAIN.DA_METHOD}' - - if args.exp_suffix: - cfg.EXP_NAME += f'_{args.exp_suffix}' - # auto-generate snapshot path if not specified - if cfg.TRAIN.SNAPSHOT_DIR == '': - cfg.TRAIN.SNAPSHOT_DIR = osp.join(cfg.EXP_ROOT_SNAPSHOT, cfg.EXP_NAME) - os.makedirs(cfg.TRAIN.SNAPSHOT_DIR, exist_ok=True) - # tensorboard - if args.tensorboard: - if cfg.TRAIN.TENSORBOARD_LOGDIR == '': - cfg.TRAIN.TENSORBOARD_LOGDIR = osp.join(cfg.EXP_ROOT_LOGS, 'tensorboard', cfg.EXP_NAME) - os.makedirs(cfg.TRAIN.TENSORBOARD_LOGDIR, exist_ok=True) - if args.viz_every_iter is not None: - cfg.TRAIN.TENSORBOARD_VIZRATE = args.viz_every_iter - else: - cfg.TRAIN.TENSORBOARD_LOGDIR = '' - if cfg.is_master_node: - print('Using config:') - pprint.pprint(cfg) - - # INIT - _init_fn = None - if not args.random_train: - torch.manual_seed(cfg.TRAIN.RANDOM_SEED) - if args.device_type == 'cuda': - torch.cuda.manual_seed(cfg.TRAIN.RANDOM_SEED) - elif args.device_type == 'npu': - torch.npu.manual_seed(cfg.TRAIN.RANDOM_SEED) - np.random.seed(cfg.TRAIN.RANDOM_SEED) - random.seed(cfg.TRAIN.RANDOM_SEED) - - def _init_fn(worker_id): - np.random.seed(cfg.TRAIN.RANDOM_SEED + worker_id) - - if os.environ.get('ADVENT_DRY_RUN', '0') == '1': - return - - # LOAD SEGMENTATION NET - assert osp.exists(cfg.TRAIN.RESTORE_FROM), f'Missing init model {cfg.TRAIN.RESTORE_FROM}' - if cfg.TRAIN.MODEL == 'DeepLabv2': - model = get_deeplab_v2(num_classes=cfg.NUM_CLASSES, multi_level=cfg.TRAIN.MULTI_LEVEL) - saved_state_dict = torch.load(cfg.TRAIN.RESTORE_FROM) - if 'DeepLab_resnet_pretrained_imagenet' in cfg.TRAIN.RESTORE_FROM: - new_params = model.state_dict().copy() - for i in saved_state_dict: - i_parts = i.split('.') - if not i_parts[1] == 'layer5': - new_params['.'.join(i_parts[1:])] = saved_state_dict[i] - model.load_state_dict(new_params) - else: - model.load_state_dict(saved_state_dict) - else: - raise NotImplementedError(f"Not yet supported {cfg.TRAIN.MODEL}") - print('Model loaded') - - # DATALOADERS - # pdb.set_trace() - easy_dataset = CityscapesDataSet_easy(root=cfg.DATA_DIRECTORY_SOURCE, - list_path=cfg.DATA_LIST_SOURCE, - max_iters=cfg.TRAIN.MAX_ITERS * cfg.TRAIN.BATCH_SIZE_SOURCE * args.world_size, - crop_size=cfg.TRAIN.INPUT_SIZE_SOURCE, - mean=cfg.TRAIN.IMG_MEAN) - if cfg.distributed: - easy_sampler = torch.utils.data.distributed.DistributedSampler(easy_dataset) - easy_loader = data.DataLoader(easy_dataset, - batch_size=cfg.TRAIN.BATCH_SIZE_SOURCE, - num_workers=cfg.NUM_WORKERS, - shuffle=(not cfg.distributed), - pin_memory=False, - sampler=easy_sampler if cfg.distributed else None, - worker_init_fn=_init_fn) - - # pdb.set_trace() - hard_dataset = CityscapesDataSet_hard(root=cfg.DATA_DIRECTORY_TARGET, - list_path=cfg.DATA_LIST_TARGET, - set=cfg.TRAIN.SET_TARGET, - info_path=cfg.TRAIN.INFO_TARGET, - max_iters=cfg.TRAIN.MAX_ITERS * cfg.TRAIN.BATCH_SIZE_TARGET * args.world_size, - crop_size=cfg.TRAIN.INPUT_SIZE_TARGET, - mean=cfg.TRAIN.IMG_MEAN) - if cfg.distributed: - hard_sampler = torch.utils.data.distributed.DistributedSampler(hard_dataset) - hard_loader = data.DataLoader(hard_dataset, - batch_size=cfg.TRAIN.BATCH_SIZE_TARGET, - num_workers=cfg.NUM_WORKERS, - shuffle=(not cfg.distributed), - pin_memory=False, - sampler=hard_sampler if cfg.distributed else None, - worker_init_fn=_init_fn) - - with open(osp.join(cfg.TRAIN.SNAPSHOT_DIR, 'train_cfg.yml'), 'w') as yaml_file: - yaml.dump(cfg, yaml_file, default_flow_style=False) - - # pdb.set_trace() - train_domain_adaptation(model, easy_loader, hard_loader, device, cfg) - - -if __name__ == '__main__': - os.environ['MASTER_ADDR'] = '127.0.0.1' - os.environ['MASTER_PORT'] = '29688' - main() +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +#-------------------------------------------------------------------- +# modified from "ADVENT/advent/scripts/train.py" by Tuan-Hung Vu +#-------------------------------------------------------------------- +import argparse +import os +import os.path as osp +import pprint +import random +import warnings + +import numpy as np +import yaml +import torch +from torch.utils import data + +from advent.model.deeplabv2 import get_deeplab_v2 +from advent.dataset.gta5 import GTA5DataSet +from advent.dataset.cityscapes import CityscapesDataSet as CityscapesDataSet_hard +from cityscapes import CityscapesDataSet as CityscapesDataSet_easy +from advent.domain_adaptation.config import cfg, cfg_from_file +from train_UDA import train_domain_adaptation + + +warnings.filterwarnings("ignore", message="numpy.dtype size changed") +warnings.filterwarnings("ignore") + + +def get_arguments(): + """ + Parse input arguments + """ + parser = argparse.ArgumentParser(description="Code for domain adaptation (DA) training") + parser.add_argument('--cfg', type=str, default=None, + help='optional config file', ) + parser.add_argument("--random-train", action="store_true", + help="not fixing random seed.") + parser.add_argument("--tensorboard", action="store_true", + help="visualize training loss with tensorboardX.") + parser.add_argument("--viz_every_iter", type=int, default=None, + help="visualize results.") + parser.add_argument("--exp-suffix", type=str, default=None, + help="optional experiment suffix") + parser.add_argument('--rank', type=int, default=0) + parser.add_argument('--device_type', type=str, default='npu') + parser.add_argument('--device_id', type=int, ) + parser.add_argument('--world_size', type=int, default=1) + parser.add_argument('--distributed', action='store_true', default=False) + parser.add_argument('--performance_log', action='store_true', default=False) + return parser.parse_args() + + +def main(): + # LOAD ARGS + args = get_arguments() + print('Called with args:') + print(args) + + # pdb.set_trace() + + assert args.cfg is not None, 'Missing cfg file' + cfg_from_file(args.cfg) + cfg.distributed = args.distributed + ddp_backend = "hccl" if args.device_type == "npu" else "nccl" + + if cfg.distributed: + torch.distributed.init_process_group(backend=ddp_backend, world_size=args.world_size, rank=args.rank) + device = torch.device("{}:{}".format(args.device_type ,args.device_id)) + cfg.device_id = args.device_id + cfg.rank = args.rank + cfg.world_size = args.world_size + cfg.device_type = args.device_type + cfg.performance_log = args.performance_log + if args.device_type == 'cuda': + torch.cuda.set_device(args.device_id) + elif args.device_type == 'npu': + torch.npu.set_device(args.device_id) + + cfg.is_master_node = args.world_size == 1 or args.device_id == 0 + + # auto-generate exp name if not specified + if cfg.EXP_NAME == '': + cfg.EXP_NAME = f'{cfg.SOURCE}2{cfg.TARGET}_{cfg.TRAIN.MODEL}_{cfg.TRAIN.DA_METHOD}' + + if args.exp_suffix: + cfg.EXP_NAME += f'_{args.exp_suffix}' + # auto-generate snapshot path if not specified + if cfg.TRAIN.SNAPSHOT_DIR == '': + cfg.TRAIN.SNAPSHOT_DIR = osp.join(cfg.EXP_ROOT_SNAPSHOT, cfg.EXP_NAME) + os.makedirs(cfg.TRAIN.SNAPSHOT_DIR, exist_ok=True) + # tensorboard + if args.tensorboard: + if cfg.TRAIN.TENSORBOARD_LOGDIR == '': + cfg.TRAIN.TENSORBOARD_LOGDIR = osp.join(cfg.EXP_ROOT_LOGS, 'tensorboard', cfg.EXP_NAME) + os.makedirs(cfg.TRAIN.TENSORBOARD_LOGDIR, exist_ok=True) + if args.viz_every_iter is not None: + cfg.TRAIN.TENSORBOARD_VIZRATE = args.viz_every_iter + else: + cfg.TRAIN.TENSORBOARD_LOGDIR = '' + if cfg.is_master_node: + print('Using config:') + pprint.pprint(cfg) + + # INIT + _init_fn = None + if not args.random_train: + torch.manual_seed(cfg.TRAIN.RANDOM_SEED) + if args.device_type == 'cuda': + torch.cuda.manual_seed(cfg.TRAIN.RANDOM_SEED) + elif args.device_type == 'npu': + torch.npu.manual_seed(cfg.TRAIN.RANDOM_SEED) + np.random.seed(cfg.TRAIN.RANDOM_SEED) + random.seed(cfg.TRAIN.RANDOM_SEED) + + def _init_fn(worker_id): + np.random.seed(cfg.TRAIN.RANDOM_SEED + worker_id) + + if os.environ.get('ADVENT_DRY_RUN', '0') == '1': + return + + # LOAD SEGMENTATION NET + assert osp.exists(cfg.TRAIN.RESTORE_FROM), f'Missing init model {cfg.TRAIN.RESTORE_FROM}' + if cfg.TRAIN.MODEL == 'DeepLabv2': + model = get_deeplab_v2(num_classes=cfg.NUM_CLASSES, multi_level=cfg.TRAIN.MULTI_LEVEL) + saved_state_dict = torch.load(cfg.TRAIN.RESTORE_FROM) + if 'DeepLab_resnet_pretrained_imagenet' in cfg.TRAIN.RESTORE_FROM: + new_params = model.state_dict().copy() + for i in saved_state_dict: + i_parts = i.split('.') + if not i_parts[1] == 'layer5': + new_params['.'.join(i_parts[1:])] = saved_state_dict[i] + model.load_state_dict(new_params) + else: + model.load_state_dict(saved_state_dict) + else: + raise NotImplementedError(f"Not yet supported {cfg.TRAIN.MODEL}") + print('Model loaded') + + # DATALOADERS + # pdb.set_trace() + easy_dataset = CityscapesDataSet_easy(root=cfg.DATA_DIRECTORY_SOURCE, + list_path=cfg.DATA_LIST_SOURCE, + max_iters=cfg.TRAIN.MAX_ITERS * cfg.TRAIN.BATCH_SIZE_SOURCE * args.world_size, + crop_size=cfg.TRAIN.INPUT_SIZE_SOURCE, + mean=cfg.TRAIN.IMG_MEAN) + if cfg.distributed: + easy_sampler = torch.utils.data.distributed.DistributedSampler(easy_dataset) + easy_loader = data.DataLoader(easy_dataset, + batch_size=cfg.TRAIN.BATCH_SIZE_SOURCE, + num_workers=cfg.NUM_WORKERS, + shuffle=(not cfg.distributed), + pin_memory=False, + sampler=easy_sampler if cfg.distributed else None, + worker_init_fn=_init_fn) + + # pdb.set_trace() + hard_dataset = CityscapesDataSet_hard(root=cfg.DATA_DIRECTORY_TARGET, + list_path=cfg.DATA_LIST_TARGET, + set=cfg.TRAIN.SET_TARGET, + info_path=cfg.TRAIN.INFO_TARGET, + max_iters=cfg.TRAIN.MAX_ITERS * cfg.TRAIN.BATCH_SIZE_TARGET * args.world_size, + crop_size=cfg.TRAIN.INPUT_SIZE_TARGET, + mean=cfg.TRAIN.IMG_MEAN) + if cfg.distributed: + hard_sampler = torch.utils.data.distributed.DistributedSampler(hard_dataset) + hard_loader = data.DataLoader(hard_dataset, + batch_size=cfg.TRAIN.BATCH_SIZE_TARGET, + num_workers=cfg.NUM_WORKERS, + shuffle=(not cfg.distributed), + pin_memory=False, + sampler=hard_sampler if cfg.distributed else None, + worker_init_fn=_init_fn) + + with open(osp.join(cfg.TRAIN.SNAPSHOT_DIR, 'train_cfg.yml'), 'w') as yaml_file: + yaml.dump(cfg, yaml_file, default_flow_style=False) + + # pdb.set_trace() + train_domain_adaptation(model, easy_loader, hard_loader, device, cfg) + + +if __name__ == '__main__': + os.environ['MASTER_ADDR'] = '127.0.0.1' + os.environ['MASTER_PORT'] = '29688' + main() diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/intrada/train_UDA.py b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/intrada/train_UDA.py index 417abb8798..a27de68355 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/intrada/train_UDA.py +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/intrada/train_UDA.py @@ -1,469 +1,469 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -#-------------------------------------------------------------------- -# modified from "ADVENT/advent/domain_adaptation/train_UDA.py" by Tuan-Hung Vu -#-------------------------------------------------------------------- -import os -import sys -import time -from pathlib import Path - -import os.path as osp -import numpy as np -import torch -#import torch.backends.cudnn as cudnn -import torch.nn.functional as F -import torch.optim as optim -from tensorboardX import SummaryWriter -from torch import nn -from torchvision.utils import make_grid -from tqdm import tqdm -from collections import OrderedDict - -from advent.model.discriminator import get_fc_discriminator -from advent.utils.func import adjust_learning_rate, adjust_learning_rate_discriminator -from advent.utils.func import loss_calc, bce_loss -from advent.utils.loss import entropy_loss -from advent.utils.func import prob_2_entropy -from advent.utils.viz_segmask import colorize_mask - -import apex -from apex import amp - -def load_checkpoint_for_evaluation(model, checkpoint, device): - saved_state_dict = torch.load(checkpoint, map_location="cpu") - new_state_dict = OrderedDict() - for k,v in saved_state_dict.items(): - if k[:7] != "module.": - name = k - else: - name = k[7:] - new_state_dict[name] = v - model.load_state_dict(new_state_dict) - model.eval() - model.to(device) - - -def train_advent(model, trainloader, targetloader, device, cfg): - ''' UDA training with advent - ''' - # Create the model and start the training. - # pdb.set_trace() - input_size_source = cfg.TRAIN.INPUT_SIZE_SOURCE - input_size_target = cfg.TRAIN.INPUT_SIZE_TARGET - # device = cfg.GPU_ID - num_classes = cfg.NUM_CLASSES - viz_tensorboard = os.path.exists(cfg.TRAIN.TENSORBOARD_LOGDIR) - if viz_tensorboard: - writer = SummaryWriter(log_dir=cfg.TRAIN.TENSORBOARD_LOGDIR) - - print(device) - # SEGMNETATION NETWORK - model.train() - model.to(device) - # cudnn.benchmark = True - # cudnn.enabled = True - - # DISCRIMINATOR NETWORK - # feature-level - d_aux = get_fc_discriminator(num_classes=num_classes) - d_aux.train() - d_aux.to(device) - # restore_from = cfg.TRAIN.RESTORE_FROM_aux - # print("Load Discriminator:", restore_from) - # load_checkpoint_for_evaluation(d_aux, restore_from, device) - - - # seg maps, i.e. output, level - d_main = get_fc_discriminator(num_classes=num_classes) - d_main.train() - d_main.to(device) - - # restore_from = cfg.TRAIN.RESTORE_FROM_main - # print("Load Discriminator:", restore_from) - # load_checkpoint_for_evaluation(d_main, restore_from, device) - - # OPTIMIZERS - # segnet's optimizer - optimizer = optim.SGD(model.optim_parameters(cfg.TRAIN.LEARNING_RATE), - lr=cfg.TRAIN.LEARNING_RATE, - momentum=cfg.TRAIN.MOMENTUM, - weight_decay=cfg.TRAIN.WEIGHT_DECAY) - model, optimizer = amp.initialize(model, optimizer, opt_level="O0",loss_scale=128.0) - if cfg.distributed: - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[cfg.device_id], find_unused_parameters=True) - - # discriminators' optimizers - optimizer_d_aux = optim.Adam(d_aux.parameters(), lr=cfg.TRAIN.LEARNING_RATE_D, - betas=(0.9, 0.99)) - optimizer_d_main = optim.Adam(d_main.parameters(), lr=cfg.TRAIN.LEARNING_RATE_D, - betas=(0.9, 0.99)) - d_aux, optimizer_d_aux = amp.initialize(d_aux, optimizer_d_aux, opt_level="O0",loss_scale=128.0) - d_main, optimizer_d_main = amp.initialize(d_main, optimizer_d_main, opt_level="O0",loss_scale=128.0) - if cfg.distributed: - d_aux = torch.nn.parallel.DistributedDataParallel(d_aux, device_ids=[cfg.device_id],find_unused_parameters=True) - d_main = torch.nn.parallel.DistributedDataParallel(d_main, device_ids=[cfg.device_id], find_unused_parameters=True) - - # interpolate output segmaps - interp = nn.Upsample(size=(input_size_source[1], input_size_source[0]), mode='bilinear', - align_corners=True) - interp_target = nn.Upsample(size=(input_size_target[1], input_size_target[0]), mode='bilinear', - align_corners=True) - - # labels for adversarial training - source_label = 0 - target_label = 1 - trainloader_iter = enumerate(trainloader) - targetloader_iter = enumerate(targetloader) - for i_iter in tqdm(range(cfg.TRAIN.EARLY_STOP)): - - # reset optimizers - optimizer.zero_grad() - optimizer_d_aux.zero_grad() - optimizer_d_main.zero_grad() - # adapt LR if needed - adjust_learning_rate(optimizer, i_iter, cfg) - adjust_learning_rate_discriminator(optimizer_d_aux, i_iter, cfg) - adjust_learning_rate_discriminator(optimizer_d_main, i_iter, cfg) - - # UDA Training - # only train segnet. Don't accumulate grads in disciminators - for param in d_aux.parameters(): - param.requires_grad = False - for param in d_main.parameters(): - param.requires_grad = False - # train on source - _, batch = trainloader_iter.__next__() - images_source, labels, _, _ = batch - images_source, labels = images_source.to(device), labels.to(device) - # debug: - # labels=labels.numpy() - # from matplotlib import pyplot as plt - # import numpy as np - # plt.figure(1), plt.imshow(labels[0]), plt.ion(), plt.colorbar(), plt.show() - pred_src_aux, pred_src_main = model(images_source) - if cfg.TRAIN.MULTI_LEVEL: - pred_src_aux = interp(pred_src_aux) - loss_seg_src_aux = loss_calc(pred_src_aux, labels, device) - else: - loss_seg_src_aux = 0 - pred_src_main = interp(pred_src_main) - loss_seg_src_main = loss_calc(pred_src_main, labels, device) - # pdb.set_trace() - loss = (cfg.TRAIN.LAMBDA_SEG_MAIN * loss_seg_src_main - + cfg.TRAIN.LAMBDA_SEG_AUX * loss_seg_src_aux) - #loss.backward() - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - - # adversarial training ot fool the discriminator - _, batch = targetloader_iter.__next__() - images, _, _, _ = batch - images = images.to(device) - pred_trg_aux, pred_trg_main = model(images) - if cfg.TRAIN.MULTI_LEVEL: - pred_trg_aux = interp_target(pred_trg_aux) - d_out_aux = d_aux(prob_2_entropy(F.softmax(pred_trg_aux))) - loss_adv_trg_aux = bce_loss(d_out_aux, source_label) - else: - loss_adv_trg_aux = 0 - pred_trg_main = interp_target(pred_trg_main) - d_out_main = d_main(prob_2_entropy(F.softmax(pred_trg_main))) - loss_adv_trg_main = bce_loss(d_out_main, source_label) - loss = (cfg.TRAIN.LAMBDA_ADV_MAIN * loss_adv_trg_main - + cfg.TRAIN.LAMBDA_ADV_AUX * loss_adv_trg_aux) - loss = loss - #loss.backward() - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - - # Train discriminator networks - # enable training mode on discriminator networks - for param in d_aux.parameters(): - param.requires_grad = True - for param in d_main.parameters(): - param.requires_grad = True - # train with source - if cfg.TRAIN.MULTI_LEVEL: - pred_src_aux = pred_src_aux.detach() - d_out_aux = d_aux(prob_2_entropy(F.softmax(pred_src_aux))) - loss_d_aux = bce_loss(d_out_aux, source_label) - loss_d_aux = loss_d_aux / 2 - with amp.scale_loss(loss_d_aux, optimizer_d_aux) as scaled_loss: - scaled_loss.backward() - # loss_d_aux.backward() - pred_src_main = pred_src_main.detach() - d_out_main = d_main(prob_2_entropy(F.softmax(pred_src_main))) - loss_d_main = bce_loss(d_out_main, source_label) - loss_d_main = loss_d_main / 2 - #loss_d_main.backward() - with amp.scale_loss(loss_d_main, optimizer_d_main) as scaled_loss: - scaled_loss.backward() - - # train with target - if cfg.TRAIN.MULTI_LEVEL: - pred_trg_aux = pred_trg_aux.detach() - d_out_aux = d_aux(prob_2_entropy(F.softmax(pred_trg_aux))) - loss_d_aux = bce_loss(d_out_aux, target_label) - loss_d_aux = loss_d_aux / 2 - #loss_d_aux.backward() - with amp.scale_loss(loss_d_aux, optimizer_d_aux) as scaled_loss: - scaled_loss.backward() - else: - loss_d_aux = 0 - pred_trg_main = pred_trg_main.detach() - d_out_main = d_main(prob_2_entropy(F.softmax(pred_trg_main))) - loss_d_main = bce_loss(d_out_main, target_label) - loss_d_main = loss_d_main / 2 - #loss_d_main.backward() - with amp.scale_loss(loss_d_main, optimizer_d_main) as scaled_loss: - scaled_loss.backward() - - optimizer.step() - if cfg.TRAIN.MULTI_LEVEL: - optimizer_d_aux.step() - optimizer_d_main.step() - - current_losses = {'loss_seg_src_aux': loss_seg_src_aux, - 'loss_seg_src_main': loss_seg_src_main, - 'loss_adv_trg_aux': loss_adv_trg_aux, - 'loss_adv_trg_main': loss_adv_trg_main, - 'loss_d_aux': loss_d_aux, - 'loss_d_main': loss_d_main} - print_losses(current_losses, i_iter) - - if i_iter % cfg.TRAIN.SAVE_PRED_EVERY == 0 and i_iter != 0 and cfg.rank == 0: - print('taking snapshot ...') - print('exp =', cfg.TRAIN.SNAPSHOT_DIR) - snapshot_dir = Path(cfg.TRAIN.SNAPSHOT_DIR) - torch.save(model.state_dict(), snapshot_dir / f'model_{i_iter}.pth') - torch.save(d_aux.state_dict(), snapshot_dir / f'model_{i_iter}_D_aux.pth') - torch.save(d_main.state_dict(), snapshot_dir / f'model_{i_iter}_D_main.pth') - if i_iter >= cfg.TRAIN.EARLY_STOP - 1: - break - sys.stdout.flush() - - # Visualize with tensorboard - if viz_tensorboard: - log_losses_tensorboard(writer, current_losses, i_iter) - - if i_iter % cfg.TRAIN.TENSORBOARD_VIZRATE == cfg.TRAIN.TENSORBOARD_VIZRATE - 1: - draw_in_tensorboard(writer, images, i_iter, pred_trg_main, num_classes, 'T') - draw_in_tensorboard(writer, images_source, i_iter, pred_src_main, num_classes, 'S') - - -def draw_in_tensorboard(writer, images, i_iter, pred_main, num_classes, type_): - grid_image = make_grid(images[:3].clone().cpu().data, 3, normalize=True) - writer.add_image(f'Image - {type_}', grid_image, i_iter) - - grid_image = make_grid(torch.from_numpy(np.array(colorize_mask(np.asarray( - np.argmax(F.softmax(pred_main).cpu().data[0].numpy().transpose(1, 2, 0), - axis=2), dtype=np.uint8)).convert('RGB')).transpose(2, 0, 1)), 3, - normalize=False, range=(0, 255)) - writer.add_image(f'Prediction - {type_}', grid_image, i_iter) - - output_sm = F.softmax(pred_main).cpu().data[0].numpy().transpose(1, 2, 0) - output_ent = np.sum(-np.multiply(output_sm, np.log2(output_sm)), axis=2, - keepdims=False) - grid_image = make_grid(torch.from_numpy(output_ent), 3, normalize=True, - range=(0, np.log2(num_classes))) - writer.add_image(f'Entropy - {type_}', grid_image, i_iter) - - -def train_minent(model, trainloader, targetloader, device, cfg): - ''' UDA training with minEnt - ''' - # Create the model and start the training. - input_size_source = cfg.TRAIN.INPUT_SIZE_SOURCE - input_size_target = cfg.TRAIN.INPUT_SIZE_TARGET - # device = cfg.GPU_ID - num_classes = cfg.NUM_CLASSES - viz_tensorboard = os.path.exists(cfg.TRAIN.TENSORBOARD_LOGDIR) - if viz_tensorboard: - writer = SummaryWriter(log_dir=cfg.TRAIN.TENSORBOARD_LOGDIR) - - # SEGMNETATION NETWORK - model.train() - model.to(device) - # cudnn.benchmark = True - # cudnn.enabled = True - - # OPTIMIZERS - # segnet's optimizer - # optimizer_fn = apex.optimizers.NpuFusedSGD if cfg.device_type == 'npu' else optim.SGD - optimizer_fn = optim.SGD - optimizer = optimizer_fn(model.optim_parameters(cfg.TRAIN.LEARNING_RATE), - lr=cfg.TRAIN.LEARNING_RATE, - momentum=cfg.TRAIN.MOMENTUM, - weight_decay=cfg.TRAIN.WEIGHT_DECAY) - - model, optimizer = amp.initialize(model, optimizer, opt_level='O2',loss_scale=128.0) - - if cfg.distributed: - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[cfg.device_id]) - - # interpolate output segmaps - interp = nn.Upsample(size=(input_size_source[1], input_size_source[0]), mode='bilinear', - align_corners=True) - interp_target = nn.Upsample(size=(input_size_target[1], input_size_target[0]), mode='bilinear', - align_corners=True) - - trainloader_iter = enumerate(trainloader) - targetloader_iter = enumerate(targetloader) - - # FPS statistics - time_meter = AverageMeter(name='time_avg') - num_devices = cfg.world_size - batch_size = cfg.TRAIN.BATCH_SIZE_SOURCE - - for i_iter in tqdm(range(cfg.TRAIN.EARLY_STOP)): - - # time start - time_start = time.time() - - # reset optimizers - optimizer.zero_grad() - - # adapt LR if needed - adjust_learning_rate(optimizer, i_iter, cfg) - - # UDA Training - # train on source - _, batch = trainloader_iter.__next__() - images_source, labels, _, _ = batch - images_source, labels = images_source.to(device), labels.to(device) - pred_src_aux, pred_src_main = model(images_source) - if cfg.TRAIN.MULTI_LEVEL: - pred_src_aux = interp(pred_src_aux) - loss_seg_src_aux = loss_calc(pred_src_aux, labels, device) - else: - loss_seg_src_aux = 0 - pred_src_main = interp(pred_src_main) - loss_seg_src_main = loss_calc(pred_src_main, labels, device) - loss = (cfg.TRAIN.LAMBDA_SEG_MAIN * loss_seg_src_main - + cfg.TRAIN.LAMBDA_SEG_AUX * loss_seg_src_aux) - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - # loss.backward() - - # adversarial training with minent - _, batch = targetloader_iter.__next__() - images, _, _, _ = batch - images = images.to(device) - pred_trg_aux, pred_trg_main = model(images) - pred_trg_aux = interp_target(pred_trg_aux) - pred_trg_main = interp_target(pred_trg_main) - pred_prob_trg_aux = F.softmax(pred_trg_aux) - pred_prob_trg_main = F.softmax(pred_trg_main) - - loss_target_entp_aux = entropy_loss(pred_prob_trg_aux) - loss_target_entp_main = entropy_loss(pred_prob_trg_main) - loss = (cfg.TRAIN.LAMBDA_ENT_AUX * loss_target_entp_aux - + cfg.TRAIN.LAMBDA_ENT_MAIN * loss_target_entp_main) - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - # loss.backward() - optimizer.step() - - # update time statistics - time_cost = time.time() - time_start - time_meter.update(time_cost) - - current_losses = {'loss_seg_src_aux': loss_seg_src_aux, - 'loss_seg_src_main': loss_seg_src_main, - 'loss_ent_aux': loss_target_entp_aux, - 'loss_ent_main': loss_target_entp_main, - 'FPS': num_devices * batch_size / time_meter.avg if time_meter.avg > 1e-6 else -1} - - if cfg.is_master_node: - print_losses(current_losses, i_iter) - - if i_iter % cfg.TRAIN.SAVE_PRED_EVERY == 0 and i_iter != 0 and cfg.is_master_node: - print('taking snapshot ...') - print('exp =', cfg.TRAIN.SNAPSHOT_DIR) - torch.save(model.state_dict(), - osp.join(cfg.TRAIN.SNAPSHOT_DIR, f'model_{i_iter}.pth')) - if i_iter >= cfg.TRAIN.EARLY_STOP - 1: - break - sys.stdout.flush() - - # Visualize with tensorboard - if viz_tensorboard: - log_losses_tensorboard(writer, current_losses, i_iter) - - if i_iter % cfg.TRAIN.TENSORBOARD_VIZRATE == cfg.TRAIN.TENSORBOARD_VIZRATE - 1: - draw_in_tensorboard(writer, images, i_iter, pred_trg_main, num_classes, 'T') - draw_in_tensorboard(writer, images_source, i_iter, pred_src_main, num_classes, 'S') - - -def print_losses(current_losses, i_iter): - list_strings = [] - for loss_name, loss_value in current_losses.items(): - list_strings.append(f'{loss_name} = {to_numpy(loss_value):.3f} ') - full_string = ' '.join(list_strings) - tqdm.write(f'iter = {i_iter} {full_string}') - - -def log_losses_tensorboard(writer, current_losses, i_iter): - for loss_name, loss_value in current_losses.items(): - writer.add_scalar(f'data/{loss_name}', to_numpy(loss_value), i_iter) - - -def to_numpy(tensor): - if isinstance(tensor, (int, float)): - return tensor - else: - return tensor.data.cpu().numpy() - - -def train_domain_adaptation(model, trainloader, targetloader, device, cfg): - if cfg.TRAIN.DA_METHOD == 'MinEnt': - if cfg.performance_log: - cfg.TRAIN.EARLY_STOP = 500 - train_minent(model, trainloader, targetloader, device, cfg) - elif cfg.TRAIN.DA_METHOD == 'AdvEnt': - train_advent(model, trainloader, targetloader, device, cfg) - else: - raise NotImplementedError(f"Not yet supported DA method {cfg.TRAIN.DA_METHOD}") - - -class AverageMeter(object): - """Computes and stores the average and current value""" - - def __init__(self, name, fmt=':f', start_count_index=10): - self.name = name - self.fmt = fmt - self.reset() - self.start_count_index = start_count_index - - def reset(self): - self.val = 0 - self.avg = 0 - self.sum = 0 - self.count = 0 - - def update(self, val, n=1): - if self.count == 0: - self.N = n - - self.val = val - self.count += n - if self.count > (self.start_count_index * self.N): - self.sum += val * n - self.avg = self.sum / (self.count - self.start_count_index * self.N) - - def __str__(self): - fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' - return fmtstr.format(**self.__dict__) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +#-------------------------------------------------------------------- +# modified from "ADVENT/advent/domain_adaptation/train_UDA.py" by Tuan-Hung Vu +#-------------------------------------------------------------------- +import os +import sys +import time +from pathlib import Path + +import os.path as osp +import numpy as np +import torch +#import torch.backends.cudnn as cudnn +import torch.nn.functional as F +import torch.optim as optim +from tensorboardX import SummaryWriter +from torch import nn +from torchvision.utils import make_grid +from tqdm import tqdm +from collections import OrderedDict + +from advent.model.discriminator import get_fc_discriminator +from advent.utils.func import adjust_learning_rate, adjust_learning_rate_discriminator +from advent.utils.func import loss_calc, bce_loss +from advent.utils.loss import entropy_loss +from advent.utils.func import prob_2_entropy +from advent.utils.viz_segmask import colorize_mask + +import apex +from apex import amp + +def load_checkpoint_for_evaluation(model, checkpoint, device): + saved_state_dict = torch.load(checkpoint, map_location="cpu") + new_state_dict = OrderedDict() + for k,v in saved_state_dict.items(): + if k[:7] != "module.": + name = k + else: + name = k[7:] + new_state_dict[name] = v + model.load_state_dict(new_state_dict) + model.eval() + model.to(device) + + +def train_advent(model, trainloader, targetloader, device, cfg): + ''' UDA training with advent + ''' + # Create the model and start the training. + # pdb.set_trace() + input_size_source = cfg.TRAIN.INPUT_SIZE_SOURCE + input_size_target = cfg.TRAIN.INPUT_SIZE_TARGET + # device = cfg.GPU_ID + num_classes = cfg.NUM_CLASSES + viz_tensorboard = os.path.exists(cfg.TRAIN.TENSORBOARD_LOGDIR) + if viz_tensorboard: + writer = SummaryWriter(log_dir=cfg.TRAIN.TENSORBOARD_LOGDIR) + + print(device) + # SEGMNETATION NETWORK + model.train() + model.to(device) + # cudnn.benchmark = True + # cudnn.enabled = True + + # DISCRIMINATOR NETWORK + # feature-level + d_aux = get_fc_discriminator(num_classes=num_classes) + d_aux.train() + d_aux.to(device) + # restore_from = cfg.TRAIN.RESTORE_FROM_aux + # print("Load Discriminator:", restore_from) + # load_checkpoint_for_evaluation(d_aux, restore_from, device) + + + # seg maps, i.e. output, level + d_main = get_fc_discriminator(num_classes=num_classes) + d_main.train() + d_main.to(device) + + # restore_from = cfg.TRAIN.RESTORE_FROM_main + # print("Load Discriminator:", restore_from) + # load_checkpoint_for_evaluation(d_main, restore_from, device) + + # OPTIMIZERS + # segnet's optimizer + optimizer = optim.SGD(model.optim_parameters(cfg.TRAIN.LEARNING_RATE), + lr=cfg.TRAIN.LEARNING_RATE, + momentum=cfg.TRAIN.MOMENTUM, + weight_decay=cfg.TRAIN.WEIGHT_DECAY) + model, optimizer = amp.initialize(model, optimizer, opt_level="O0",loss_scale=128.0) + if cfg.distributed: + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[cfg.device_id], find_unused_parameters=True) + + # discriminators' optimizers + optimizer_d_aux = optim.Adam(d_aux.parameters(), lr=cfg.TRAIN.LEARNING_RATE_D, + betas=(0.9, 0.99)) + optimizer_d_main = optim.Adam(d_main.parameters(), lr=cfg.TRAIN.LEARNING_RATE_D, + betas=(0.9, 0.99)) + d_aux, optimizer_d_aux = amp.initialize(d_aux, optimizer_d_aux, opt_level="O0",loss_scale=128.0) + d_main, optimizer_d_main = amp.initialize(d_main, optimizer_d_main, opt_level="O0",loss_scale=128.0) + if cfg.distributed: + d_aux = torch.nn.parallel.DistributedDataParallel(d_aux, device_ids=[cfg.device_id],find_unused_parameters=True) + d_main = torch.nn.parallel.DistributedDataParallel(d_main, device_ids=[cfg.device_id], find_unused_parameters=True) + + # interpolate output segmaps + interp = nn.Upsample(size=(input_size_source[1], input_size_source[0]), mode='bilinear', + align_corners=True) + interp_target = nn.Upsample(size=(input_size_target[1], input_size_target[0]), mode='bilinear', + align_corners=True) + + # labels for adversarial training + source_label = 0 + target_label = 1 + trainloader_iter = enumerate(trainloader) + targetloader_iter = enumerate(targetloader) + for i_iter in tqdm(range(cfg.TRAIN.EARLY_STOP)): + + # reset optimizers + optimizer.zero_grad() + optimizer_d_aux.zero_grad() + optimizer_d_main.zero_grad() + # adapt LR if needed + adjust_learning_rate(optimizer, i_iter, cfg) + adjust_learning_rate_discriminator(optimizer_d_aux, i_iter, cfg) + adjust_learning_rate_discriminator(optimizer_d_main, i_iter, cfg) + + # UDA Training + # only train segnet. Don't accumulate grads in disciminators + for param in d_aux.parameters(): + param.requires_grad = False + for param in d_main.parameters(): + param.requires_grad = False + # train on source + _, batch = trainloader_iter.__next__() + images_source, labels, _, _ = batch + images_source, labels = images_source.to(device), labels.to(device) + # debug: + # labels=labels.numpy() + # from matplotlib import pyplot as plt + # import numpy as np + # plt.figure(1), plt.imshow(labels[0]), plt.ion(), plt.colorbar(), plt.show() + pred_src_aux, pred_src_main = model(images_source) + if cfg.TRAIN.MULTI_LEVEL: + pred_src_aux = interp(pred_src_aux) + loss_seg_src_aux = loss_calc(pred_src_aux, labels, device) + else: + loss_seg_src_aux = 0 + pred_src_main = interp(pred_src_main) + loss_seg_src_main = loss_calc(pred_src_main, labels, device) + # pdb.set_trace() + loss = (cfg.TRAIN.LAMBDA_SEG_MAIN * loss_seg_src_main + + cfg.TRAIN.LAMBDA_SEG_AUX * loss_seg_src_aux) + #loss.backward() + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + + # adversarial training ot fool the discriminator + _, batch = targetloader_iter.__next__() + images, _, _, _ = batch + images = images.to(device) + pred_trg_aux, pred_trg_main = model(images) + if cfg.TRAIN.MULTI_LEVEL: + pred_trg_aux = interp_target(pred_trg_aux) + d_out_aux = d_aux(prob_2_entropy(F.softmax(pred_trg_aux))) + loss_adv_trg_aux = bce_loss(d_out_aux, source_label) + else: + loss_adv_trg_aux = 0 + pred_trg_main = interp_target(pred_trg_main) + d_out_main = d_main(prob_2_entropy(F.softmax(pred_trg_main))) + loss_adv_trg_main = bce_loss(d_out_main, source_label) + loss = (cfg.TRAIN.LAMBDA_ADV_MAIN * loss_adv_trg_main + + cfg.TRAIN.LAMBDA_ADV_AUX * loss_adv_trg_aux) + loss = loss + #loss.backward() + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + + # Train discriminator networks + # enable training mode on discriminator networks + for param in d_aux.parameters(): + param.requires_grad = True + for param in d_main.parameters(): + param.requires_grad = True + # train with source + if cfg.TRAIN.MULTI_LEVEL: + pred_src_aux = pred_src_aux.detach() + d_out_aux = d_aux(prob_2_entropy(F.softmax(pred_src_aux))) + loss_d_aux = bce_loss(d_out_aux, source_label) + loss_d_aux = loss_d_aux / 2 + with amp.scale_loss(loss_d_aux, optimizer_d_aux) as scaled_loss: + scaled_loss.backward() + # loss_d_aux.backward() + pred_src_main = pred_src_main.detach() + d_out_main = d_main(prob_2_entropy(F.softmax(pred_src_main))) + loss_d_main = bce_loss(d_out_main, source_label) + loss_d_main = loss_d_main / 2 + #loss_d_main.backward() + with amp.scale_loss(loss_d_main, optimizer_d_main) as scaled_loss: + scaled_loss.backward() + + # train with target + if cfg.TRAIN.MULTI_LEVEL: + pred_trg_aux = pred_trg_aux.detach() + d_out_aux = d_aux(prob_2_entropy(F.softmax(pred_trg_aux))) + loss_d_aux = bce_loss(d_out_aux, target_label) + loss_d_aux = loss_d_aux / 2 + #loss_d_aux.backward() + with amp.scale_loss(loss_d_aux, optimizer_d_aux) as scaled_loss: + scaled_loss.backward() + else: + loss_d_aux = 0 + pred_trg_main = pred_trg_main.detach() + d_out_main = d_main(prob_2_entropy(F.softmax(pred_trg_main))) + loss_d_main = bce_loss(d_out_main, target_label) + loss_d_main = loss_d_main / 2 + #loss_d_main.backward() + with amp.scale_loss(loss_d_main, optimizer_d_main) as scaled_loss: + scaled_loss.backward() + + optimizer.step() + if cfg.TRAIN.MULTI_LEVEL: + optimizer_d_aux.step() + optimizer_d_main.step() + + current_losses = {'loss_seg_src_aux': loss_seg_src_aux, + 'loss_seg_src_main': loss_seg_src_main, + 'loss_adv_trg_aux': loss_adv_trg_aux, + 'loss_adv_trg_main': loss_adv_trg_main, + 'loss_d_aux': loss_d_aux, + 'loss_d_main': loss_d_main} + print_losses(current_losses, i_iter) + + if i_iter % cfg.TRAIN.SAVE_PRED_EVERY == 0 and i_iter != 0 and cfg.rank == 0: + print('taking snapshot ...') + print('exp =', cfg.TRAIN.SNAPSHOT_DIR) + snapshot_dir = Path(cfg.TRAIN.SNAPSHOT_DIR) + torch.save(model.state_dict(), snapshot_dir / f'model_{i_iter}.pth') + torch.save(d_aux.state_dict(), snapshot_dir / f'model_{i_iter}_D_aux.pth') + torch.save(d_main.state_dict(), snapshot_dir / f'model_{i_iter}_D_main.pth') + if i_iter >= cfg.TRAIN.EARLY_STOP - 1: + break + sys.stdout.flush() + + # Visualize with tensorboard + if viz_tensorboard: + log_losses_tensorboard(writer, current_losses, i_iter) + + if i_iter % cfg.TRAIN.TENSORBOARD_VIZRATE == cfg.TRAIN.TENSORBOARD_VIZRATE - 1: + draw_in_tensorboard(writer, images, i_iter, pred_trg_main, num_classes, 'T') + draw_in_tensorboard(writer, images_source, i_iter, pred_src_main, num_classes, 'S') + + +def draw_in_tensorboard(writer, images, i_iter, pred_main, num_classes, type_): + grid_image = make_grid(images[:3].clone().cpu().data, 3, normalize=True) + writer.add_image(f'Image - {type_}', grid_image, i_iter) + + grid_image = make_grid(torch.from_numpy(np.array(colorize_mask(np.asarray( + np.argmax(F.softmax(pred_main).cpu().data[0].numpy().transpose(1, 2, 0), + axis=2), dtype=np.uint8)).convert('RGB')).transpose(2, 0, 1)), 3, + normalize=False, range=(0, 255)) + writer.add_image(f'Prediction - {type_}', grid_image, i_iter) + + output_sm = F.softmax(pred_main).cpu().data[0].numpy().transpose(1, 2, 0) + output_ent = np.sum(-np.multiply(output_sm, np.log2(output_sm)), axis=2, + keepdims=False) + grid_image = make_grid(torch.from_numpy(output_ent), 3, normalize=True, + range=(0, np.log2(num_classes))) + writer.add_image(f'Entropy - {type_}', grid_image, i_iter) + + +def train_minent(model, trainloader, targetloader, device, cfg): + ''' UDA training with minEnt + ''' + # Create the model and start the training. + input_size_source = cfg.TRAIN.INPUT_SIZE_SOURCE + input_size_target = cfg.TRAIN.INPUT_SIZE_TARGET + # device = cfg.GPU_ID + num_classes = cfg.NUM_CLASSES + viz_tensorboard = os.path.exists(cfg.TRAIN.TENSORBOARD_LOGDIR) + if viz_tensorboard: + writer = SummaryWriter(log_dir=cfg.TRAIN.TENSORBOARD_LOGDIR) + + # SEGMNETATION NETWORK + model.train() + model.to(device) + # cudnn.benchmark = True + # cudnn.enabled = True + + # OPTIMIZERS + # segnet's optimizer + # optimizer_fn = apex.optimizers.NpuFusedSGD if cfg.device_type == 'npu' else optim.SGD + optimizer_fn = optim.SGD + optimizer = optimizer_fn(model.optim_parameters(cfg.TRAIN.LEARNING_RATE), + lr=cfg.TRAIN.LEARNING_RATE, + momentum=cfg.TRAIN.MOMENTUM, + weight_decay=cfg.TRAIN.WEIGHT_DECAY) + + model, optimizer = amp.initialize(model, optimizer, opt_level='O2',loss_scale=128.0) + + if cfg.distributed: + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[cfg.device_id]) + + # interpolate output segmaps + interp = nn.Upsample(size=(input_size_source[1], input_size_source[0]), mode='bilinear', + align_corners=True) + interp_target = nn.Upsample(size=(input_size_target[1], input_size_target[0]), mode='bilinear', + align_corners=True) + + trainloader_iter = enumerate(trainloader) + targetloader_iter = enumerate(targetloader) + + # FPS statistics + time_meter = AverageMeter(name='time_avg') + num_devices = cfg.world_size + batch_size = cfg.TRAIN.BATCH_SIZE_SOURCE + + for i_iter in tqdm(range(cfg.TRAIN.EARLY_STOP)): + + # time start + time_start = time.time() + + # reset optimizers + optimizer.zero_grad() + + # adapt LR if needed + adjust_learning_rate(optimizer, i_iter, cfg) + + # UDA Training + # train on source + _, batch = trainloader_iter.__next__() + images_source, labels, _, _ = batch + images_source, labels = images_source.to(device), labels.to(device) + pred_src_aux, pred_src_main = model(images_source) + if cfg.TRAIN.MULTI_LEVEL: + pred_src_aux = interp(pred_src_aux) + loss_seg_src_aux = loss_calc(pred_src_aux, labels, device) + else: + loss_seg_src_aux = 0 + pred_src_main = interp(pred_src_main) + loss_seg_src_main = loss_calc(pred_src_main, labels, device) + loss = (cfg.TRAIN.LAMBDA_SEG_MAIN * loss_seg_src_main + + cfg.TRAIN.LAMBDA_SEG_AUX * loss_seg_src_aux) + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + # loss.backward() + + # adversarial training with minent + _, batch = targetloader_iter.__next__() + images, _, _, _ = batch + images = images.to(device) + pred_trg_aux, pred_trg_main = model(images) + pred_trg_aux = interp_target(pred_trg_aux) + pred_trg_main = interp_target(pred_trg_main) + pred_prob_trg_aux = F.softmax(pred_trg_aux) + pred_prob_trg_main = F.softmax(pred_trg_main) + + loss_target_entp_aux = entropy_loss(pred_prob_trg_aux) + loss_target_entp_main = entropy_loss(pred_prob_trg_main) + loss = (cfg.TRAIN.LAMBDA_ENT_AUX * loss_target_entp_aux + + cfg.TRAIN.LAMBDA_ENT_MAIN * loss_target_entp_main) + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + # loss.backward() + optimizer.step() + + # update time statistics + time_cost = time.time() - time_start + time_meter.update(time_cost) + + current_losses = {'loss_seg_src_aux': loss_seg_src_aux, + 'loss_seg_src_main': loss_seg_src_main, + 'loss_ent_aux': loss_target_entp_aux, + 'loss_ent_main': loss_target_entp_main, + 'FPS': num_devices * batch_size / time_meter.avg if time_meter.avg > 1e-6 else -1} + + if cfg.is_master_node: + print_losses(current_losses, i_iter) + + if i_iter % cfg.TRAIN.SAVE_PRED_EVERY == 0 and i_iter != 0 and cfg.is_master_node: + print('taking snapshot ...') + print('exp =', cfg.TRAIN.SNAPSHOT_DIR) + torch.save(model.state_dict(), + osp.join(cfg.TRAIN.SNAPSHOT_DIR, f'model_{i_iter}.pth')) + if i_iter >= cfg.TRAIN.EARLY_STOP - 1: + break + sys.stdout.flush() + + # Visualize with tensorboard + if viz_tensorboard: + log_losses_tensorboard(writer, current_losses, i_iter) + + if i_iter % cfg.TRAIN.TENSORBOARD_VIZRATE == cfg.TRAIN.TENSORBOARD_VIZRATE - 1: + draw_in_tensorboard(writer, images, i_iter, pred_trg_main, num_classes, 'T') + draw_in_tensorboard(writer, images_source, i_iter, pred_src_main, num_classes, 'S') + + +def print_losses(current_losses, i_iter): + list_strings = [] + for loss_name, loss_value in current_losses.items(): + list_strings.append(f'{loss_name} = {to_numpy(loss_value):.3f} ') + full_string = ' '.join(list_strings) + tqdm.write(f'iter = {i_iter} {full_string}') + + +def log_losses_tensorboard(writer, current_losses, i_iter): + for loss_name, loss_value in current_losses.items(): + writer.add_scalar(f'data/{loss_name}', to_numpy(loss_value), i_iter) + + +def to_numpy(tensor): + if isinstance(tensor, (int, float)): + return tensor + else: + return tensor.data.cpu().numpy() + + +def train_domain_adaptation(model, trainloader, targetloader, device, cfg): + if cfg.TRAIN.DA_METHOD == 'MinEnt': + if cfg.performance_log: + cfg.TRAIN.EARLY_STOP = 500 + train_minent(model, trainloader, targetloader, device, cfg) + elif cfg.TRAIN.DA_METHOD == 'AdvEnt': + train_advent(model, trainloader, targetloader, device, cfg) + else: + raise NotImplementedError(f"Not yet supported DA method {cfg.TRAIN.DA_METHOD}") + + +class AverageMeter(object): + """Computes and stores the average and current value""" + + def __init__(self, name, fmt=':f', start_count_index=10): + self.name = name + self.fmt = fmt + self.reset() + self.start_count_index = start_count_index + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + + def update(self, val, n=1): + if self.count == 0: + self.N = n + + self.val = val + self.count += n + if self.count > (self.start_count_index * self.N): + self.sum += val * n + self.avg = self.sum / (self.count - self.start_count_index * self.N) + + def __str__(self): + fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' + return fmtstr.format(**self.__dict__) diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/modelzoo_level.txt b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/modelzoo_level.txt +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/requirements.txt b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/requirements.txt index e427e81e69..5abfd47cd4 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/IntraDA/requirements.txt +++ b/PyTorch/contrib/cv/semantic_segmentation/IntraDA/requirements.txt @@ -1,4 +1,4 @@ -#torch==1.5.0 -#torchvision==0.6.0 - - +#torch==1.5.0 +#torchvision==0.6.0 + + diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/createTrainIdLabelImgs.py b/PyTorch/contrib/cv/semantic_segmentation/PointRend/createTrainIdLabelImgs.py index dc521ade89..d9b7bde86c 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/PointRend/createTrainIdLabelImgs.py +++ b/PyTorch/contrib/cv/semantic_segmentation/PointRend/createTrainIdLabelImgs.py @@ -1,71 +1,71 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 print_function, absolute_import, division -import os, glob, sys - -# cityscapes imports -from cityscapesscripts.helpers.csHelpers import printError -from cityscapesscripts.preparation.json2instanceImg import json2instanceImg - - -# The main method -def main(data_path): - # Where to look for Cityscapes - cityscapesPath = data_path - # how to search for all ground truth - searchFine = os.path.join( cityscapesPath , "gtFine" , "*" , "*" , "*_gt*_polygons.json" ) - searchCoarse = os.path.join( cityscapesPath , "gtCoarse" , "*" , "*" , "*_gt*_polygons.json" ) - - # search files - filesFine = glob.glob( searchFine ) - filesFine.sort() - filesCoarse = glob.glob( searchCoarse ) - filesCoarse.sort() - - # concatenate fine and coarse - files = filesFine + filesCoarse - # files = filesFine # use this line if fine is enough for now. - - # quit if we did not find anything - if not files: - printError( "Did not find any files. Please consult the README." ) - - # a bit verbose - print("Processing {} annotation files".format(len(files))) - - # iterate through files - progress = 0 - print("Progress: {:>3} %".format( progress * 100 / len(files) ), end=' ') - for f in files: - # create the output filename - dst = f.replace( "_polygons.json" , "_instanceTrainIds.png" ) - - # do the conversion - try: - json2instanceImg( f , dst , "trainIds" ) - except: - print("Failed to convert: {}".format(f)) - raise - - # status - progress += 1 - print("\rProgress: {:>3} %".format( progress * 100 / len(files) ), end=' ') - sys.stdout.flush() - - -# call the main -if __name__ == "__main__": - data_path = sys.argv[1] +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 print_function, absolute_import, division +import os, glob, sys + +# cityscapes imports +from cityscapesscripts.helpers.csHelpers import printError +from cityscapesscripts.preparation.json2instanceImg import json2instanceImg + + +# The main method +def main(data_path): + # Where to look for Cityscapes + cityscapesPath = data_path + # how to search for all ground truth + searchFine = os.path.join( cityscapesPath , "gtFine" , "*" , "*" , "*_gt*_polygons.json" ) + searchCoarse = os.path.join( cityscapesPath , "gtCoarse" , "*" , "*" , "*_gt*_polygons.json" ) + + # search files + filesFine = glob.glob( searchFine ) + filesFine.sort() + filesCoarse = glob.glob( searchCoarse ) + filesCoarse.sort() + + # concatenate fine and coarse + files = filesFine + filesCoarse + # files = filesFine # use this line if fine is enough for now. + + # quit if we did not find anything + if not files: + printError( "Did not find any files. Please consult the README." ) + + # a bit verbose + print("Processing {} annotation files".format(len(files))) + + # iterate through files + progress = 0 + print("Progress: {:>3} %".format( progress * 100 / len(files) ), end=' ') + for f in files: + # create the output filename + dst = f.replace( "_polygons.json" , "_instanceTrainIds.png" ) + + # do the conversion + try: + json2instanceImg( f , dst , "trainIds" ) + except: + print("Failed to convert: {}".format(f)) + raise + + # status + progress += 1 + print("\rProgress: {:>3} %".format( progress * 100 / len(files) ), end=' ') + sys.stdout.flush() + + +# call the main +if __name__ == "__main__": + data_path = sys.argv[1] main(data_path) \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/datasets/prepare_ade20k_sem_seg.py b/PyTorch/contrib/cv/semantic_segmentation/PointRend/datasets/prepare_ade20k_sem_seg.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/datasets/prepare_cocofied_lvis.py b/PyTorch/contrib/cv/semantic_segmentation/PointRend/datasets/prepare_cocofied_lvis.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/datasets/prepare_for_tests.sh b/PyTorch/contrib/cv/semantic_segmentation/PointRend/datasets/prepare_for_tests.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/datasets/prepare_panoptic_fpn.py b/PyTorch/contrib/cv/semantic_segmentation/PointRend/datasets/prepare_panoptic_fpn.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/demo/demo.py b/PyTorch/contrib/cv/semantic_segmentation/PointRend/demo/demo.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/linter.sh b/PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/linter.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/packaging/build_all_wheels.sh b/PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/packaging/build_all_wheels.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/packaging/build_wheel.sh b/PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/packaging/build_wheel.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/packaging/gen_install_table.py b/PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/packaging/gen_install_table.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/packaging/gen_wheel_index.sh b/PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/packaging/gen_wheel_index.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/packaging/pkg_helpers.bash b/PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/packaging/pkg_helpers.bash old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/parse_results.sh b/PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/parse_results.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/run_inference_tests.sh b/PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/run_inference_tests.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/run_instant_tests.sh b/PyTorch/contrib/cv/semantic_segmentation/PointRend/dev/run_instant_tests.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/projects/PointRend/train_net.py b/PyTorch/contrib/cv/semantic_segmentation/PointRend/projects/PointRend/train_net.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/analyze_model.py b/PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/analyze_model.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/benchmark.py b/PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/benchmark.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/convert-torchvision-to-d2.py b/PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/convert-torchvision-to-d2.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/deploy/export_model.py b/PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/deploy/export_model.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/lazyconfig_train_net.py b/PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/lazyconfig_train_net.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/plain_train_net.py b/PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/plain_train_net.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/train_net.py b/PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/train_net.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/visualize_data.py b/PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/visualize_data.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/visualize_json_results.py b/PyTorch/contrib/cv/semantic_segmentation/PointRend/tools/visualize_json_results.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/RCAN/dataset.py b/PyTorch/contrib/cv/semantic_segmentation/RCAN/dataset.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/RCAN/main.py b/PyTorch/contrib/cv/semantic_segmentation/RCAN/main.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/RCAN/model.py b/PyTorch/contrib/cv/semantic_segmentation/RCAN/model.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/RCAN/test.py b/PyTorch/contrib/cv/semantic_segmentation/RCAN/test.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/RCAN/test/run_1p_prof.sh b/PyTorch/contrib/cv/semantic_segmentation/RCAN/test/run_1p_prof.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/RCAN/test/run_test.sh b/PyTorch/contrib/cv/semantic_segmentation/RCAN/test/run_test.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/RCAN/test/set_npu_env.sh b/PyTorch/contrib/cv/semantic_segmentation/RCAN/test/set_npu_env.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/RCAN/test/train_finetuning_1p.sh b/PyTorch/contrib/cv/semantic_segmentation/RCAN/test/train_finetuning_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/RCAN/test/train_full_1p.sh b/PyTorch/contrib/cv/semantic_segmentation/RCAN/test/train_full_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/RCAN/test/train_full_8p.sh b/PyTorch/contrib/cv/semantic_segmentation/RCAN/test/train_full_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/RCAN/test/train_performance_1p.sh b/PyTorch/contrib/cv/semantic_segmentation/RCAN/test/train_performance_1p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/RCAN/test/train_performance_8p.sh b/PyTorch/contrib/cv/semantic_segmentation/RCAN/test/train_performance_8p.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/RCAN/utils.py b/PyTorch/contrib/cv/semantic_segmentation/RCAN/utils.py old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/RefineNet/Dockerfile b/PyTorch/contrib/cv/semantic_segmentation/RefineNet/Dockerfile index 7e712fe1a1..30a31af558 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/RefineNet/Dockerfile +++ b/PyTorch/contrib/cv/semantic_segmentation/RefineNet/Dockerfile @@ -1,5 +1,5 @@ -ARG FROM_IMAGE_NAME -FROM $FROM_IMAGE_NAME - -COPY requirements.txt . +ARG FROM_IMAGE_NAME +FROM $FROM_IMAGE_NAME + +COPY requirements.txt . RUN pip3.7 install -r requirements.txt \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/RefineNet/README.md b/PyTorch/contrib/cv/semantic_segmentation/RefineNet/README.md index c76ab910ec..00f9295dea 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/RefineNet/README.md +++ b/PyTorch/contrib/cv/semantic_segmentation/RefineNet/README.md @@ -1,79 +1,79 @@ -# RefineNet - -This repository is an NPU implementation of the ["RefineNet: Multi-Path Refinement Networks for High-Resolution Semantic Segmentation"](https://arxiv.org/abs/1611.06612), referring to https://github.com/DrSleep/refinenet-pytorch - - - -## Requirements - -See requirements.txt - -- PyTorch 1.5.0 -- torchvision 0.6.0 -- Numpy 1.15.1 -- Pillow 5.3.0 -- h5py 2.8.0 -- tqdm 4.28.1 -- h5py 3.4.0 -- opencv-python 3.4.4.19 -- albumentations 0.4.5 -- install densetorch as follow: - -```bash - git clone https://github.com/DrSleep/DenseTorch - cd ./DenseTorch - python setup.py install -``` - -## Training - -The processed VOC dataset can be downloaded from [Download](https://pan.baidu.com/s/12wHGhby5vEcG6isQpnpcMQ) with extraction code: vnhb (about 9 G), put it in ./VOC. Or, you can download it by: -```bash -bash load_data.sh -``` - -The training common: - -```bash -# 1p train perf -bash test/train_performance_1p.sh - -# 8p train perf -bash test/train_performance_8p.sh - -# 8p train full -bash test/train_full_8p.sh - -# finetuning -bash test/train_finetune_1p.sh -``` - -In the first running, it requires time to downloaded the model pre-trained on ImageNet. Or you can manually download it by: -```shell -cd ~ -mkdir .torch -mkdir .torch/models -cd .torch/models -wget https://download.pytorch.org/models/resnet101-5d3b4d8f.pth -mv resnet101-5d3b4d8f.pth 101_imagenet.pth.tar -``` -Log path: ./log/ - -Saved model path: ./model/ - -## Training result - -| IOU | FPS | NPU_nums | BS/NPU | AMP_type | -|-----------|-------|-------|-----------------|-----------| -| 78.56 | 25.56 | 1 | 16 | O2 | -| 77.34 | 159.46| 8 | 8 | O2 | - - - - -## Citation -``` -RefineNet: Multi-Path Refinement Networks for High-Resolution Semantic Segmentation -Guosheng Lin, Anton Milan, Chunhua Shen, Ian Reid -In CVPR 2017 -``` +# RefineNet + +This repository is an NPU implementation of the ["RefineNet: Multi-Path Refinement Networks for High-Resolution Semantic Segmentation"](https://arxiv.org/abs/1611.06612), referring to https://github.com/DrSleep/refinenet-pytorch + + + +## Requirements + +See requirements.txt + +- PyTorch 1.5.0 +- torchvision 0.6.0 +- Numpy 1.15.1 +- Pillow 5.3.0 +- h5py 2.8.0 +- tqdm 4.28.1 +- h5py 3.4.0 +- opencv-python 3.4.4.19 +- albumentations 0.4.5 +- install densetorch as follow: + +```bash + git clone https://github.com/DrSleep/DenseTorch + cd ./DenseTorch + python setup.py install +``` + +## Training + +The processed VOC dataset can be downloaded from [Download](https://pan.baidu.com/s/12wHGhby5vEcG6isQpnpcMQ) with extraction code: vnhb (about 9 G), put it in ./VOC. Or, you can download it by: +```bash +bash load_data.sh +``` + +The training common: + +```bash +# 1p train perf +bash test/train_performance_1p.sh + +# 8p train perf +bash test/train_performance_8p.sh + +# 8p train full +bash test/train_full_8p.sh + +# finetuning +bash test/train_finetune_1p.sh +``` + +In the first running, it requires time to downloaded the model pre-trained on ImageNet. Or you can manually download it by: +```shell +cd ~ +mkdir .torch +mkdir .torch/models +cd .torch/models +wget https://download.pytorch.org/models/resnet101-5d3b4d8f.pth +mv resnet101-5d3b4d8f.pth 101_imagenet.pth.tar +``` +Log path: ./log/ + +Saved model path: ./model/ + +## Training result + +| IOU | FPS | NPU_nums | BS/NPU | AMP_type | +|-----------|-------|-------|-----------------|-----------| +| 78.56 | 25.56 | 1 | 16 | O2 | +| 77.34 | 159.46| 8 | 8 | O2 | + + + + +## Citation +``` +RefineNet: Multi-Path Refinement Networks for High-Resolution Semantic Segmentation +Guosheng Lin, Anton Milan, Chunhua Shen, Ian Reid +In CVPR 2017 +``` diff --git a/PyTorch/contrib/cv/semantic_segmentation/RefineNet/models/refinenet.py b/PyTorch/contrib/cv/semantic_segmentation/RefineNet/models/refinenet.py index 07027e25da..64eafea2b3 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/RefineNet/models/refinenet.py +++ b/PyTorch/contrib/cv/semantic_segmentation/RefineNet/models/refinenet.py @@ -1,336 +1,336 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch.nn as nn -import torch.nn.functional as F -import torch - -import numpy as np - -IMG_SCALE = 1./255 -IMG_MEAN = np.array([0.485, 0.456, 0.406]).reshape((1, 1, 3)) -IMG_STD = np.array([0.229, 0.224, 0.225]).reshape((1, 1, 3)) - -def maybe_download(model_name, model_url, model_dir=None, map_location=None): - import os, sys - from six.moves import urllib - if model_dir is None: - torch_home = os.path.expanduser(os.getenv('TORCH_HOME', '~/.torch')) - model_dir = os.getenv('TORCH_MODEL_ZOO', os.path.join(torch_home, 'models')) - if not os.path.exists(model_dir): - os.makedirs(model_dir) - filename = '{}.pth.tar'.format(model_name) - cached_file = os.path.join(model_dir, filename) - if not os.path.exists(cached_file): - url = model_url - sys.stderr.write('Downloading: "{}" to {}\n'.format(url, cached_file)) - urllib.request.urlretrieve(url, cached_file) - return torch.load(cached_file, map_location=map_location) - -def prepare_img(img): - return (img * IMG_SCALE - IMG_MEAN) / IMG_STD - -def batchnorm(in_planes): - "batch norm 2d" - return nn.BatchNorm2d(in_planes, affine=True, eps=1e-5, momentum=0.1) - -def conv3x3(in_planes, out_planes, stride=1, bias=False): - "3x3 convolution with padding" - return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, - padding=1, bias=bias) - -def conv1x1(in_planes, out_planes, stride=1, bias=False): - "1x1 convolution" - return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, - padding=0, bias=bias) - -def convbnrelu(in_planes, out_planes, kernel_size, stride=1, groups=1, act=True): - "conv-batchnorm-relu" - if act: - return nn.Sequential(nn.Conv2d(in_planes, out_planes, kernel_size, stride=stride, padding=int(kernel_size / 2.), groups=groups, bias=False), - batchnorm(out_planes), - nn.ReLU6(inplace=True)) - else: - return nn.Sequential(nn.Conv2d(in_planes, out_planes, kernel_size, stride=stride, padding=int(kernel_size / 2.), groups=groups, bias=False), - batchnorm(out_planes)) - -class CRPBlock(nn.Module): - - def __init__(self, in_planes, out_planes, n_stages, max_pooling=True): - super(CRPBlock, self).__init__() - for i in range(n_stages): - setattr(self, '{}_{}'.format(i + 1, 'outvar_dimred'), - conv3x3(in_planes if (i == 0) else out_planes, - out_planes, stride=1, - bias=False)) - self.stride = 1 - self.n_stages = n_stages - if max_pooling: self.maxpool = nn.MaxPool2d(kernel_size=5, stride=1, padding=2) - else: self.maxpool = nn.MaxPool2d(kernel_size=1, stride=1, padding=0) - - def forward(self, x): - top = x - for i in range(self.n_stages): - top = self.maxpool(top) - top = getattr(self, '{}_{}'.format(i + 1, 'outvar_dimred'))(top) - x = top + x - return x - -stages_suffixes = {0 : '_conv', - 1 : '_conv_relu_varout_dimred'} - -class RCUBlock(nn.Module): - - def __init__(self, in_planes, out_planes, n_blocks, n_stages): - super(RCUBlock, self).__init__() - for i in range(n_blocks): - for j in range(n_stages): - setattr(self, '{}{}'.format(i + 1, stages_suffixes[j]), - conv3x3(in_planes if (i == 0) and (j == 0) else out_planes, - out_planes, stride=1, - bias=(j == 0))) - self.stride = 1 - self.n_blocks = n_blocks - self.n_stages = n_stages - - def forward(self, x): - for i in range(self.n_blocks): - residual = x - for j in range(self.n_stages): - x = F.relu(x) - x = getattr(self, '{}{}'.format(i + 1, stages_suffixes[j]))(x) - x += residual - return x - -data_info = { - 21: 'VOC', - } - -models_urls = { - '101_voc' : 'https://cloudstor.aarnet.edu.au/plus/s/Owmttk9bdPROwc6/download', - - '101_imagenet': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth', - } - -class BasicBlock(nn.Module): - expansion = 1 - - def __init__(self, inplanes, planes, stride=1, downsample=None): - super(BasicBlock, self).__init__() - self.conv1 = conv3x3(inplanes, planes, stride) - self.bn1 = nn.BatchNorm2d(planes) - self.relu = nn.ReLU(inplace=True) - self.conv2 = conv3x3(planes, planes) - self.bn2 = nn.BatchNorm2d(planes) - self.downsample = downsample - self.stride = stride - - def forward(self, x): - residual = x - - out = self.conv1(x) - out = self.bn1(out) - out = self.relu(out) - - out = self.conv2(out) - out = self.bn2(out) - - if self.downsample is not None: - residual = self.downsample(x) - - out += residual - out = self.relu(out) - - return out - - -class Bottleneck(nn.Module): - expansion = 4 - - def __init__(self, inplanes, planes, stride=1, downsample=None): - super(Bottleneck, self).__init__() - self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) - self.bn1 = nn.BatchNorm2d(planes) - self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, - padding=1, bias=False) - self.bn2 = nn.BatchNorm2d(planes) - self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) - self.bn3 = nn.BatchNorm2d(planes * 4) - self.relu = nn.ReLU(inplace=True) - self.downsample = downsample - self.stride = stride - - def forward(self, x): - residual = x - - out = self.conv1(x) - out = self.bn1(out) - out = self.relu(out) - - out = self.conv2(out) - out = self.bn2(out) - out = self.relu(out) - - out = self.conv3(out) - out = self.bn3(out) - - if self.downsample is not None: - residual = self.downsample(x) - - out += residual - out = self.relu(out) - - return out - - -class RefineNet(nn.Module): - - def __init__(self, block, layers, num_classes=21): - self.inplanes = 64 - super(RefineNet, self).__init__() - self.do = nn.Dropout(p=0.5) - self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, - bias=False) - self.bn1 = nn.BatchNorm2d(64) - self.relu = nn.ReLU(inplace=True) - self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) - self.layer1 = self._make_layer(block, 64, layers[0]) - self.layer2 = self._make_layer(block, 128, layers[1], stride=2) - self.layer3 = self._make_layer(block, 256, layers[2], stride=2) - self.layer4 = self._make_layer(block, 512, layers[3], stride=2) - self.p_ims1d2_outl1_dimred = conv3x3(2048, 512, bias=False) - self.adapt_stage1_b = self._make_rcu(512, 512, 2, 2) - self.mflow_conv_g1_pool = self._make_crp(512, 512, 4) - self.mflow_conv_g1_b = self._make_rcu(512, 512, 3, 2) - self.mflow_conv_g1_b3_joint_varout_dimred = conv3x3(512, 256, bias=False) - self.p_ims1d2_outl2_dimred = conv3x3(1024, 256, bias=False) - self.adapt_stage2_b = self._make_rcu(256, 256, 2, 2) - self.adapt_stage2_b2_joint_varout_dimred = conv3x3(256, 256, bias=False) - self.mflow_conv_g2_pool = self._make_crp(256, 256, 4) - self.mflow_conv_g2_b = self._make_rcu(256, 256, 3, 2) - self.mflow_conv_g2_b3_joint_varout_dimred = conv3x3(256, 256, bias=False) - - self.p_ims1d2_outl3_dimred = conv3x3(512, 256, bias=False) - self.adapt_stage3_b = self._make_rcu(256, 256, 2, 2) - self.adapt_stage3_b2_joint_varout_dimred = conv3x3(256, 256, bias=False) - self.mflow_conv_g3_pool = self._make_crp(256, 256, 4) - self.mflow_conv_g3_b = self._make_rcu(256, 256, 3, 2) - self.mflow_conv_g3_b3_joint_varout_dimred = conv3x3(256, 256, bias=False) - - self.p_ims1d2_outl4_dimred = conv3x3(256, 256, bias=False) - self.adapt_stage4_b = self._make_rcu(256, 256, 2, 2) - self.adapt_stage4_b2_joint_varout_dimred = conv3x3(256, 256, bias=False) - self.mflow_conv_g4_pool = self._make_crp(256, 256, 4, max_pooling=False) - self.mflow_conv_g4_b = self._make_rcu(256, 256, 3, 2) - - self.clf_conv = nn.Conv2d(256, num_classes, kernel_size=3, stride=1, - padding=1, bias=True) - - def _make_crp(self, in_planes, out_planes, stages, max_pooling=True): - layers = [CRPBlock(in_planes, out_planes, stages, max_pooling)] - return nn.Sequential(*layers) - - def _make_rcu(self, in_planes, out_planes, blocks, stages): - layers = [RCUBlock(in_planes, out_planes, blocks, stages)] - return nn.Sequential(*layers) - - def _make_layer(self, block, planes, blocks, stride=1): - downsample = None - if stride != 1 or self.inplanes != planes * block.expansion: - downsample = nn.Sequential( - nn.Conv2d(self.inplanes, planes * block.expansion, - kernel_size=1, stride=stride, bias=False), - nn.BatchNorm2d(planes * block.expansion), - ) - - layers = [] - layers.append(block(self.inplanes, planes, stride, downsample)) - self.inplanes = planes * block.expansion - for i in range(1, blocks): - layers.append(block(self.inplanes, planes)) - - return nn.Sequential(*layers) - - def forward(self, x): - x = self.conv1(x) - x = self.bn1(x) - x = self.relu(x) - x = self.maxpool(x) - - l1 = self.layer1(x) - l2 = self.layer2(l1) - l3 = self.layer3(l2) - l4 = self.layer4(l3) - - l4 = self.do(l4) - l3 = self.do(l3) - - - x4 = self.p_ims1d2_outl1_dimred(l4) - x4 = self.adapt_stage1_b(x4) - x4 = self.relu(x4) - x4 = self.mflow_conv_g1_pool(x4) - x4 = self.mflow_conv_g1_b(x4) - x4 = self.mflow_conv_g1_b3_joint_varout_dimred(x4) - x4 = nn.Upsample(size=l3.size()[2:], mode='bilinear', align_corners=True)(x4) - - x3 = self.p_ims1d2_outl2_dimred(l3) - x3 = self.adapt_stage2_b(x3) - x3 = self.adapt_stage2_b2_joint_varout_dimred(x3) - x3 = x3 + x4 - x3 = F.relu(x3) - x3 = self.mflow_conv_g2_pool(x3) - x3 = self.mflow_conv_g2_b(x3) - x3 = self.mflow_conv_g2_b3_joint_varout_dimred(x3) - x3 = nn.Upsample(size=l2.size()[2:], mode='bilinear', align_corners=True)(x3) - - x2 = self.p_ims1d2_outl3_dimred(l2) - x2 = self.adapt_stage3_b(x2) - x2 = self.adapt_stage3_b2_joint_varout_dimred(x2) - x2 = x2 + x3 - x2 = F.relu(x2) - x2 = self.mflow_conv_g3_pool(x2) - x2 = self.mflow_conv_g3_b(x2) - x2 = self.mflow_conv_g3_b3_joint_varout_dimred(x2) - x2 = nn.Upsample(size=l1.size()[2:], mode='bilinear', align_corners=True)(x2) - - - x1 = self.p_ims1d2_outl4_dimred(l1) - x1 = self.adapt_stage4_b(x1) - x1 = self.adapt_stage4_b2_joint_varout_dimred(x1) - x1 = x1 + x2 - x1 = F.relu(x1) - - x1 = self.mflow_conv_g4_pool(x1) - x1 = self.mflow_conv_g4_b(x1) - x1 = self.do(x1) - - out = self.clf_conv(x1) - return out - - -def rf101(num_classes, imagenet=False, pretrained=True, **kwargs): - model = RefineNet(Bottleneck, [3, 4, 23, 3], num_classes=num_classes, **kwargs) - if imagenet: - key = '101_imagenet' - url = models_urls[key] - model.load_state_dict(maybe_download(key, url), strict=False) - elif pretrained: - dataset = data_info.get(num_classes, None) - if dataset: - bname = '101_' + dataset.lower() - key = 'rf' + bname - url = models_urls[bname] - model.load_state_dict(maybe_download(key, url), strict=False) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch.nn as nn +import torch.nn.functional as F +import torch + +import numpy as np + +IMG_SCALE = 1./255 +IMG_MEAN = np.array([0.485, 0.456, 0.406]).reshape((1, 1, 3)) +IMG_STD = np.array([0.229, 0.224, 0.225]).reshape((1, 1, 3)) + +def maybe_download(model_name, model_url, model_dir=None, map_location=None): + import os, sys + from six.moves import urllib + if model_dir is None: + torch_home = os.path.expanduser(os.getenv('TORCH_HOME', '~/.torch')) + model_dir = os.getenv('TORCH_MODEL_ZOO', os.path.join(torch_home, 'models')) + if not os.path.exists(model_dir): + os.makedirs(model_dir) + filename = '{}.pth.tar'.format(model_name) + cached_file = os.path.join(model_dir, filename) + if not os.path.exists(cached_file): + url = model_url + sys.stderr.write('Downloading: "{}" to {}\n'.format(url, cached_file)) + urllib.request.urlretrieve(url, cached_file) + return torch.load(cached_file, map_location=map_location) + +def prepare_img(img): + return (img * IMG_SCALE - IMG_MEAN) / IMG_STD + +def batchnorm(in_planes): + "batch norm 2d" + return nn.BatchNorm2d(in_planes, affine=True, eps=1e-5, momentum=0.1) + +def conv3x3(in_planes, out_planes, stride=1, bias=False): + "3x3 convolution with padding" + return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, + padding=1, bias=bias) + +def conv1x1(in_planes, out_planes, stride=1, bias=False): + "1x1 convolution" + return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, + padding=0, bias=bias) + +def convbnrelu(in_planes, out_planes, kernel_size, stride=1, groups=1, act=True): + "conv-batchnorm-relu" + if act: + return nn.Sequential(nn.Conv2d(in_planes, out_planes, kernel_size, stride=stride, padding=int(kernel_size / 2.), groups=groups, bias=False), + batchnorm(out_planes), + nn.ReLU6(inplace=True)) + else: + return nn.Sequential(nn.Conv2d(in_planes, out_planes, kernel_size, stride=stride, padding=int(kernel_size / 2.), groups=groups, bias=False), + batchnorm(out_planes)) + +class CRPBlock(nn.Module): + + def __init__(self, in_planes, out_planes, n_stages, max_pooling=True): + super(CRPBlock, self).__init__() + for i in range(n_stages): + setattr(self, '{}_{}'.format(i + 1, 'outvar_dimred'), + conv3x3(in_planes if (i == 0) else out_planes, + out_planes, stride=1, + bias=False)) + self.stride = 1 + self.n_stages = n_stages + if max_pooling: self.maxpool = nn.MaxPool2d(kernel_size=5, stride=1, padding=2) + else: self.maxpool = nn.MaxPool2d(kernel_size=1, stride=1, padding=0) + + def forward(self, x): + top = x + for i in range(self.n_stages): + top = self.maxpool(top) + top = getattr(self, '{}_{}'.format(i + 1, 'outvar_dimred'))(top) + x = top + x + return x + +stages_suffixes = {0 : '_conv', + 1 : '_conv_relu_varout_dimred'} + +class RCUBlock(nn.Module): + + def __init__(self, in_planes, out_planes, n_blocks, n_stages): + super(RCUBlock, self).__init__() + for i in range(n_blocks): + for j in range(n_stages): + setattr(self, '{}{}'.format(i + 1, stages_suffixes[j]), + conv3x3(in_planes if (i == 0) and (j == 0) else out_planes, + out_planes, stride=1, + bias=(j == 0))) + self.stride = 1 + self.n_blocks = n_blocks + self.n_stages = n_stages + + def forward(self, x): + for i in range(self.n_blocks): + residual = x + for j in range(self.n_stages): + x = F.relu(x) + x = getattr(self, '{}{}'.format(i + 1, stages_suffixes[j]))(x) + x += residual + return x + +data_info = { + 21: 'VOC', + } + +models_urls = { + '101_voc' : 'https://cloudstor.aarnet.edu.au/plus/s/Owmttk9bdPROwc6/download', + + '101_imagenet': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth', + } + +class BasicBlock(nn.Module): + expansion = 1 + + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(BasicBlock, self).__init__() + self.conv1 = conv3x3(inplanes, planes, stride) + self.bn1 = nn.BatchNorm2d(planes) + self.relu = nn.ReLU(inplace=True) + self.conv2 = conv3x3(planes, planes) + self.bn2 = nn.BatchNorm2d(planes) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class Bottleneck(nn.Module): + expansion = 4 + + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(Bottleneck, self).__init__() + self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) + self.bn1 = nn.BatchNorm2d(planes) + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, + padding=1, bias=False) + self.bn2 = nn.BatchNorm2d(planes) + self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) + self.bn3 = nn.BatchNorm2d(planes * 4) + self.relu = nn.ReLU(inplace=True) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class RefineNet(nn.Module): + + def __init__(self, block, layers, num_classes=21): + self.inplanes = 64 + super(RefineNet, self).__init__() + self.do = nn.Dropout(p=0.5) + self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, + bias=False) + self.bn1 = nn.BatchNorm2d(64) + self.relu = nn.ReLU(inplace=True) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + self.layer1 = self._make_layer(block, 64, layers[0]) + self.layer2 = self._make_layer(block, 128, layers[1], stride=2) + self.layer3 = self._make_layer(block, 256, layers[2], stride=2) + self.layer4 = self._make_layer(block, 512, layers[3], stride=2) + self.p_ims1d2_outl1_dimred = conv3x3(2048, 512, bias=False) + self.adapt_stage1_b = self._make_rcu(512, 512, 2, 2) + self.mflow_conv_g1_pool = self._make_crp(512, 512, 4) + self.mflow_conv_g1_b = self._make_rcu(512, 512, 3, 2) + self.mflow_conv_g1_b3_joint_varout_dimred = conv3x3(512, 256, bias=False) + self.p_ims1d2_outl2_dimred = conv3x3(1024, 256, bias=False) + self.adapt_stage2_b = self._make_rcu(256, 256, 2, 2) + self.adapt_stage2_b2_joint_varout_dimred = conv3x3(256, 256, bias=False) + self.mflow_conv_g2_pool = self._make_crp(256, 256, 4) + self.mflow_conv_g2_b = self._make_rcu(256, 256, 3, 2) + self.mflow_conv_g2_b3_joint_varout_dimred = conv3x3(256, 256, bias=False) + + self.p_ims1d2_outl3_dimred = conv3x3(512, 256, bias=False) + self.adapt_stage3_b = self._make_rcu(256, 256, 2, 2) + self.adapt_stage3_b2_joint_varout_dimred = conv3x3(256, 256, bias=False) + self.mflow_conv_g3_pool = self._make_crp(256, 256, 4) + self.mflow_conv_g3_b = self._make_rcu(256, 256, 3, 2) + self.mflow_conv_g3_b3_joint_varout_dimred = conv3x3(256, 256, bias=False) + + self.p_ims1d2_outl4_dimred = conv3x3(256, 256, bias=False) + self.adapt_stage4_b = self._make_rcu(256, 256, 2, 2) + self.adapt_stage4_b2_joint_varout_dimred = conv3x3(256, 256, bias=False) + self.mflow_conv_g4_pool = self._make_crp(256, 256, 4, max_pooling=False) + self.mflow_conv_g4_b = self._make_rcu(256, 256, 3, 2) + + self.clf_conv = nn.Conv2d(256, num_classes, kernel_size=3, stride=1, + padding=1, bias=True) + + def _make_crp(self, in_planes, out_planes, stages, max_pooling=True): + layers = [CRPBlock(in_planes, out_planes, stages, max_pooling)] + return nn.Sequential(*layers) + + def _make_rcu(self, in_planes, out_planes, blocks, stages): + layers = [RCUBlock(in_planes, out_planes, blocks, stages)] + return nn.Sequential(*layers) + + def _make_layer(self, block, planes, blocks, stride=1): + downsample = None + if stride != 1 or self.inplanes != planes * block.expansion: + downsample = nn.Sequential( + nn.Conv2d(self.inplanes, planes * block.expansion, + kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(planes * block.expansion), + ) + + layers = [] + layers.append(block(self.inplanes, planes, stride, downsample)) + self.inplanes = planes * block.expansion + for i in range(1, blocks): + layers.append(block(self.inplanes, planes)) + + return nn.Sequential(*layers) + + def forward(self, x): + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + x = self.maxpool(x) + + l1 = self.layer1(x) + l2 = self.layer2(l1) + l3 = self.layer3(l2) + l4 = self.layer4(l3) + + l4 = self.do(l4) + l3 = self.do(l3) + + + x4 = self.p_ims1d2_outl1_dimred(l4) + x4 = self.adapt_stage1_b(x4) + x4 = self.relu(x4) + x4 = self.mflow_conv_g1_pool(x4) + x4 = self.mflow_conv_g1_b(x4) + x4 = self.mflow_conv_g1_b3_joint_varout_dimred(x4) + x4 = nn.Upsample(size=l3.size()[2:], mode='bilinear', align_corners=True)(x4) + + x3 = self.p_ims1d2_outl2_dimred(l3) + x3 = self.adapt_stage2_b(x3) + x3 = self.adapt_stage2_b2_joint_varout_dimred(x3) + x3 = x3 + x4 + x3 = F.relu(x3) + x3 = self.mflow_conv_g2_pool(x3) + x3 = self.mflow_conv_g2_b(x3) + x3 = self.mflow_conv_g2_b3_joint_varout_dimred(x3) + x3 = nn.Upsample(size=l2.size()[2:], mode='bilinear', align_corners=True)(x3) + + x2 = self.p_ims1d2_outl3_dimred(l2) + x2 = self.adapt_stage3_b(x2) + x2 = self.adapt_stage3_b2_joint_varout_dimred(x2) + x2 = x2 + x3 + x2 = F.relu(x2) + x2 = self.mflow_conv_g3_pool(x2) + x2 = self.mflow_conv_g3_b(x2) + x2 = self.mflow_conv_g3_b3_joint_varout_dimred(x2) + x2 = nn.Upsample(size=l1.size()[2:], mode='bilinear', align_corners=True)(x2) + + + x1 = self.p_ims1d2_outl4_dimred(l1) + x1 = self.adapt_stage4_b(x1) + x1 = self.adapt_stage4_b2_joint_varout_dimred(x1) + x1 = x1 + x2 + x1 = F.relu(x1) + + x1 = self.mflow_conv_g4_pool(x1) + x1 = self.mflow_conv_g4_b(x1) + x1 = self.do(x1) + + out = self.clf_conv(x1) + return out + + +def rf101(num_classes, imagenet=False, pretrained=True, **kwargs): + model = RefineNet(Bottleneck, [3, 4, 23, 3], num_classes=num_classes, **kwargs) + if imagenet: + key = '101_imagenet' + url = models_urls[key] + model.load_state_dict(maybe_download(key, url), strict=False) + elif pretrained: + dataset = data_info.get(num_classes, None) + if dataset: + bname = '101_' + dataset.lower() + key = 'rf' + bname + url = models_urls[bname] + model.load_state_dict(maybe_download(key, url), strict=False) return model \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/RefineNet/modelzoo_level.txt b/PyTorch/contrib/cv/semantic_segmentation/RefineNet/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/RefineNet/modelzoo_level.txt +++ b/PyTorch/contrib/cv/semantic_segmentation/RefineNet/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/RefineNet/src/load_dataset.py b/PyTorch/contrib/cv/semantic_segmentation/RefineNet/src/load_dataset.py index c011e1f9f3..b74edc85e5 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/RefineNet/src/load_dataset.py +++ b/PyTorch/contrib/cv/semantic_segmentation/RefineNet/src/load_dataset.py @@ -1,73 +1,73 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 os -import re -import sys -from tqdm import tqdm -from time import time -sys.path.append('./') -# general libs -import logging -import numpy as np - -# pytorch libs -import torch -import torch.nn as nn -import torch.nn.functional as F -from torch.utils.data import DataLoader - -# densetorch wrapper -import densetorch as dt - -# configuration for light-weight refinenet -from arguments import get_arguments -from data import get_datasets, get_transforms -from network import get_segmenter -from optimisers import get_optimisers, get_lr_schedulers -from apex import amp -import torch.multiprocessing as mp - -def setup_data_loaders(args): - train_transforms, val_transforms = get_transforms( - crop_size=args.crop_size, - shorter_side=args.shorter_side, - low_scale=args.low_scale, - high_scale=args.high_scale, - img_mean=args.img_mean, - img_std=args.img_std, - img_scale=args.img_scale, - ignore_label=args.ignore_label, - num_stages=args.num_stages, - augmentations_type=args.augmentations_type, - dataset_type=args.dataset_type, - ) - train_sets, val_set = get_datasets( - train_dir=args.train_dir, - val_dir=args.val_dir, - train_list_path=args.train_list_path, - val_list_path=args.val_list_path, - train_transforms=train_transforms, - val_transforms=val_transforms, - masks_names=("segm",), - dataset_type=args.dataset_type, - stage_names=args.stage_names, - train_download=args.train_download, - val_download=args.val_download, - ) - - -args = get_arguments() -setup_data_loaders(args) - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 os +import re +import sys +from tqdm import tqdm +from time import time +sys.path.append('./') +# general libs +import logging +import numpy as np + +# pytorch libs +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.utils.data import DataLoader + +# densetorch wrapper +import densetorch as dt + +# configuration for light-weight refinenet +from arguments import get_arguments +from data import get_datasets, get_transforms +from network import get_segmenter +from optimisers import get_optimisers, get_lr_schedulers +from apex import amp +import torch.multiprocessing as mp + +def setup_data_loaders(args): + train_transforms, val_transforms = get_transforms( + crop_size=args.crop_size, + shorter_side=args.shorter_side, + low_scale=args.low_scale, + high_scale=args.high_scale, + img_mean=args.img_mean, + img_std=args.img_std, + img_scale=args.img_scale, + ignore_label=args.ignore_label, + num_stages=args.num_stages, + augmentations_type=args.augmentations_type, + dataset_type=args.dataset_type, + ) + train_sets, val_set = get_datasets( + train_dir=args.train_dir, + val_dir=args.val_dir, + train_list_path=args.train_list_path, + val_list_path=args.val_list_path, + train_transforms=train_transforms, + val_transforms=val_transforms, + masks_names=("segm",), + dataset_type=args.dataset_type, + stage_names=args.stage_names, + train_download=args.train_download, + val_download=args.val_download, + ) + + +args = get_arguments() +setup_data_loaders(args) + diff --git a/PyTorch/contrib/cv/semantic_segmentation/SETR/env_npu.sh b/PyTorch/contrib/cv/semantic_segmentation/SETR/env_npu.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/SETR/mmcv-need/fp16_utils.py b/PyTorch/contrib/cv/semantic_segmentation/SETR/mmcv-need/fp16_utils.py index 44d1bdd7d8..b1bd4a1352 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/SETR/mmcv-need/fp16_utils.py +++ b/PyTorch/contrib/cv/semantic_segmentation/SETR/mmcv-need/fp16_utils.py @@ -1,381 +1,381 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -import functools -import warnings -from collections import abc -from inspect import getfullargspec - -import numpy as np -import torch -import torch.nn as nn - -from .dist_utils import allreduce_grads as _allreduce_grads - - -def cast_tensor_type(inputs, src_type, dst_type): - """Recursively convert Tensor in inputs from src_type to dst_type. - - Args: - inputs: Inputs that to be casted. - src_type (torch.dtype): Source type.. - dst_type (torch.dtype): Destination type. - - Returns: - The same type with inputs, but all contained Tensors have been cast. - """ - if isinstance(inputs, torch.Tensor): - return inputs.to(dst_type) - elif isinstance(inputs, str): - return inputs - elif isinstance(inputs, np.ndarray): - return inputs - elif isinstance(inputs, abc.Mapping): - return type(inputs)({ - k: cast_tensor_type(v, src_type, dst_type) - for k, v in inputs.items() - }) - elif isinstance(inputs, abc.Iterable): - return type(inputs)( - cast_tensor_type(item, src_type, dst_type) for item in inputs) - else: - return inputs - - -def auto_fp16(apply_to=None, out_fp32=False): - """Decorator to enable fp16 training automatically. - - This decorator is useful when you write custom modules and want to support - mixed precision training. If inputs arguments are fp32 tensors, they will - be converted to fp16 automatically. Arguments other than fp32 tensors are - ignored. - - Args: - apply_to (Iterable, optional): The argument names to be converted. - `None` indicates all arguments. - out_fp32 (bool): Whether to convert the output back to fp32. - - Example: - - >>> import torch.nn as nn - >>> class MyModule1(nn.Module): - >>> - >>> # Convert x and y to fp16 - >>> @auto_fp16() - >>> def forward(self, x, y): - >>> pass - - >>> import torch.nn as nn - >>> class MyModule2(nn.Module): - >>> - >>> # convert pred to fp16 - >>> @auto_fp16(apply_to=('pred', )) - >>> def do_something(self, pred, others): - >>> pass - """ - - def auto_fp16_wrapper(old_func): - - @functools.wraps(old_func) - def new_func(*args, **kwargs): - # check if the module has set the attribute `fp16_enabled`, if not, - # just fallback to the original method. - if not isinstance(args[0], torch.nn.Module): - raise TypeError('@auto_fp16 can only be used to decorate the ' - 'method of nn.Module') - if not (hasattr(args[0], 'fp16_enabled') and args[0].fp16_enabled): - return old_func(*args, **kwargs) - # get the arg spec of the decorated method - args_info = getfullargspec(old_func) - # get the argument names to be casted - args_to_cast = args_info.args if apply_to is None else apply_to - # convert the args that need to be processed - new_args = [] - # NOTE: default args are not taken into consideration - if args: - arg_names = args_info.args[:len(args)] - for i, arg_name in enumerate(arg_names): - if arg_name in args_to_cast: - new_args.append( - cast_tensor_type(args[i], torch.float, torch.half)) - else: - new_args.append(args[i]) - # convert the kwargs that need to be processed - new_kwargs = {} - if kwargs: - for arg_name, arg_value in kwargs.items(): - if arg_name in args_to_cast: - new_kwargs[arg_name] = cast_tensor_type( - arg_value, torch.float, torch.half) - else: - new_kwargs[arg_name] = arg_value - # apply converted arguments to the decorated method - output = old_func(*new_args, **new_kwargs) - # cast the results back to fp32 if necessary - if out_fp32: - output = cast_tensor_type(output, torch.half, torch.float) - return output - - return new_func - - return auto_fp16_wrapper - - -def force_fp32(apply_to=None, out_fp16=False): - """Decorator to convert input arguments to fp32 in force. - - This decorator is useful when you write custom modules and want to support - mixed precision training. If there are some inputs that must be processed - in fp32 mode, then this decorator can handle it. If inputs arguments are - fp16 tensors, they will be converted to fp32 automatically. Arguments other - than fp16 tensors are ignored. - - Args: - apply_to (Iterable, optional): The argument names to be converted. - `None` indicates all arguments. - out_fp16 (bool): Whether to convert the output back to fp16. - - Example: - - >>> import torch.nn as nn - >>> class MyModule1(nn.Module): - >>> - >>> # Convert x and y to fp32 - >>> @force_fp32() - >>> def loss(self, x, y): - >>> pass - - >>> import torch.nn as nn - >>> class MyModule2(nn.Module): - >>> - >>> # convert pred to fp32 - >>> @force_fp32(apply_to=('pred', )) - >>> def post_process(self, pred, others): - >>> pass - """ - - def force_fp32_wrapper(old_func): - - @functools.wraps(old_func) - def new_func(*args, **kwargs): - # check if the module has set the attribute `fp16_enabled`, if not, - # just fallback to the original method. - if not isinstance(args[0], torch.nn.Module): - raise TypeError('@force_fp32 can only be used to decorate the ' - 'method of nn.Module') - if not (hasattr(args[0], 'fp16_enabled') and args[0].fp16_enabled): - return old_func(*args, **kwargs) - # get the arg spec of the decorated method - args_info = getfullargspec(old_func) - # get the argument names to be casted - args_to_cast = args_info.args if apply_to is None else apply_to - # convert the args that need to be processed - new_args = [] - if args: - arg_names = args_info.args[:len(args)] - for i, arg_name in enumerate(arg_names): - if arg_name in args_to_cast: - new_args.append( - cast_tensor_type(args[i], torch.half, torch.float)) - else: - new_args.append(args[i]) - # convert the kwargs that need to be processed - new_kwargs = dict() - if kwargs: - for arg_name, arg_value in kwargs.items(): - if arg_name in args_to_cast: - new_kwargs[arg_name] = cast_tensor_type( - arg_value, torch.half, torch.float) - else: - new_kwargs[arg_name] = arg_value - # apply converted arguments to the decorated method - output = old_func(*new_args, **new_kwargs) - # cast the results back to fp32 if necessary - if out_fp16: - output = cast_tensor_type(output, torch.float, torch.half) - return output - - return new_func - - return force_fp32_wrapper - - -def allreduce_grads(params, coalesce=True, bucket_size_mb=-1): - warnings.warning( - '"mmcv.runner.fp16_utils.allreduce_grads" is deprecated, and will be ' - 'removed in v2.8. Please switch to "mmcv.runner.allreduce_grads') - _allreduce_grads(params, coalesce=coalesce, bucket_size_mb=bucket_size_mb) - - -def wrap_fp16_model(model): - """Wrap the FP32 model to FP16. - - 1. Convert FP32 model to FP16. - 2. Remain some necessary layers to be FP32, e.g., normalization layers. - - Args: - model (nn.Module): Model in FP32. - """ - # convert model to fp16 - model.half() - # patch the normalization layers to make it work in fp32 mode - patch_norm_fp32(model) - # set `fp16_enabled` flag - for m in model.modules(): - if hasattr(m, 'fp16_enabled'): - m.fp16_enabled = True - - -def patch_norm_fp32(module): - """Recursively convert normalization layers from FP16 to FP32. - - Args: - module (nn.Module): The modules to be converted in FP16. - - Returns: - nn.Module: The converted module, the normalization layers have been - converted to FP32. - """ - if isinstance(module, (nn.modules.batchnorm._BatchNorm, nn.GroupNorm, nn.LayerNorm)): - module.float() - # if isinstance(module, nn.GroupNorm) or torch.__version__ < '1.3': - module.forward = patch_forward_method(module.forward, torch.half, - torch.float) - for child in module.children(): - patch_norm_fp32(child) - return module - - -def patch_forward_method(func, src_type, dst_type, convert_output=True): - """Patch the forward method of a module. - - Args: - func (callable): The original forward method. - src_type (torch.dtype): Type of input arguments to be converted from. - dst_type (torch.dtype): Type of input arguments to be converted to. - convert_output (bool): Whether to convert the output back to src_type. - - Returns: - callable: The patched forward method. - """ - - def new_forward(*args, **kwargs): - output = func(*cast_tensor_type(args, src_type, dst_type), - **cast_tensor_type(kwargs, src_type, dst_type)) - if convert_output: - output = cast_tensor_type(output, dst_type, src_type) - return output - - return new_forward - - -class LossScaler: - """Class that manages loss scaling in mixed precision training which - supports both dynamic or static mode. - - The implementation refers to - https://github.com/NVIDIA/apex/blob/master/apex/fp16_utils/loss_scaler.py. - Indirectly, by supplying ``mode='dynamic'`` for dynamic loss scaling. - It's important to understand how :class:`LossScaler` operates. - Loss scaling is designed to combat the problem of underflowing - gradients encountered at long times when training fp16 networks. - Dynamic loss scaling begins by attempting a very high loss - scale. Ironically, this may result in OVERflowing gradients. - If overflowing gradients are encountered, :class:`FP16_Optimizer` then - skips the update step for this particular iteration/minibatch, - and :class:`LossScaler` adjusts the loss scale to a lower value. - If a certain number of iterations occur without overflowing gradients - detected,:class:`LossScaler` increases the loss scale once more. - In this way :class:`LossScaler` attempts to "ride the edge" of always - using the highest loss scale possible without incurring overflow. - - Args: - init_scale (float): Initial loss scale value, default: 2**32. - scale_factor (float): Factor used when adjusting the loss scale. - Default: 2. - mode (str): Loss scaling mode. 'dynamic' or 'static' - scale_window (int): Number of consecutive iterations without an - overflow to wait before increasing the loss scale. Default: 1000. - """ - - def __init__(self, - init_scale=2**32, - mode='dynamic', - scale_factor=2., - scale_window=1000): - self.cur_scale = init_scale - self.cur_iter = 0 - assert mode in ('dynamic', - 'static'), 'mode can only be dynamic or static' - self.mode = mode - self.last_overflow_iter = -1 - self.scale_factor = scale_factor - self.scale_window = scale_window - - def has_overflow(self, params): - """Check if params contain overflow.""" - if self.mode != 'dynamic': - return False - for p in params: - if p.grad is not None and LossScaler._has_inf_or_nan(p.grad.data): - return True - return False - - def _has_inf_or_nan(x): - """Check if params contain NaN.""" - try: - cpu_sum = float(x.float().sum()) - except RuntimeError as instance: - if 'value cannot be converted' not in instance.args[0]: - raise - return True - else: - if cpu_sum == float('inf') or cpu_sum == -float('inf') \ - or cpu_sum != cpu_sum: - return True - return False - - def update_scale(self, overflow): - """update the current loss scale value when overflow happens.""" - if self.mode != 'dynamic': - return - if overflow: - self.cur_scale = max(self.cur_scale / self.scale_factor, 1) - self.last_overflow_iter = self.cur_iter - else: - if (self.cur_iter - self.last_overflow_iter) % \ - self.scale_window == 0: - self.cur_scale *= self.scale_factor - self.cur_iter += 1 - - @property - def loss_scale(self): - return self.cur_scale +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +import functools +import warnings +from collections import abc +from inspect import getfullargspec + +import numpy as np +import torch +import torch.nn as nn + +from .dist_utils import allreduce_grads as _allreduce_grads + + +def cast_tensor_type(inputs, src_type, dst_type): + """Recursively convert Tensor in inputs from src_type to dst_type. + + Args: + inputs: Inputs that to be casted. + src_type (torch.dtype): Source type.. + dst_type (torch.dtype): Destination type. + + Returns: + The same type with inputs, but all contained Tensors have been cast. + """ + if isinstance(inputs, torch.Tensor): + return inputs.to(dst_type) + elif isinstance(inputs, str): + return inputs + elif isinstance(inputs, np.ndarray): + return inputs + elif isinstance(inputs, abc.Mapping): + return type(inputs)({ + k: cast_tensor_type(v, src_type, dst_type) + for k, v in inputs.items() + }) + elif isinstance(inputs, abc.Iterable): + return type(inputs)( + cast_tensor_type(item, src_type, dst_type) for item in inputs) + else: + return inputs + + +def auto_fp16(apply_to=None, out_fp32=False): + """Decorator to enable fp16 training automatically. + + This decorator is useful when you write custom modules and want to support + mixed precision training. If inputs arguments are fp32 tensors, they will + be converted to fp16 automatically. Arguments other than fp32 tensors are + ignored. + + Args: + apply_to (Iterable, optional): The argument names to be converted. + `None` indicates all arguments. + out_fp32 (bool): Whether to convert the output back to fp32. + + Example: + + >>> import torch.nn as nn + >>> class MyModule1(nn.Module): + >>> + >>> # Convert x and y to fp16 + >>> @auto_fp16() + >>> def forward(self, x, y): + >>> pass + + >>> import torch.nn as nn + >>> class MyModule2(nn.Module): + >>> + >>> # convert pred to fp16 + >>> @auto_fp16(apply_to=('pred', )) + >>> def do_something(self, pred, others): + >>> pass + """ + + def auto_fp16_wrapper(old_func): + + @functools.wraps(old_func) + def new_func(*args, **kwargs): + # check if the module has set the attribute `fp16_enabled`, if not, + # just fallback to the original method. + if not isinstance(args[0], torch.nn.Module): + raise TypeError('@auto_fp16 can only be used to decorate the ' + 'method of nn.Module') + if not (hasattr(args[0], 'fp16_enabled') and args[0].fp16_enabled): + return old_func(*args, **kwargs) + # get the arg spec of the decorated method + args_info = getfullargspec(old_func) + # get the argument names to be casted + args_to_cast = args_info.args if apply_to is None else apply_to + # convert the args that need to be processed + new_args = [] + # NOTE: default args are not taken into consideration + if args: + arg_names = args_info.args[:len(args)] + for i, arg_name in enumerate(arg_names): + if arg_name in args_to_cast: + new_args.append( + cast_tensor_type(args[i], torch.float, torch.half)) + else: + new_args.append(args[i]) + # convert the kwargs that need to be processed + new_kwargs = {} + if kwargs: + for arg_name, arg_value in kwargs.items(): + if arg_name in args_to_cast: + new_kwargs[arg_name] = cast_tensor_type( + arg_value, torch.float, torch.half) + else: + new_kwargs[arg_name] = arg_value + # apply converted arguments to the decorated method + output = old_func(*new_args, **new_kwargs) + # cast the results back to fp32 if necessary + if out_fp32: + output = cast_tensor_type(output, torch.half, torch.float) + return output + + return new_func + + return auto_fp16_wrapper + + +def force_fp32(apply_to=None, out_fp16=False): + """Decorator to convert input arguments to fp32 in force. + + This decorator is useful when you write custom modules and want to support + mixed precision training. If there are some inputs that must be processed + in fp32 mode, then this decorator can handle it. If inputs arguments are + fp16 tensors, they will be converted to fp32 automatically. Arguments other + than fp16 tensors are ignored. + + Args: + apply_to (Iterable, optional): The argument names to be converted. + `None` indicates all arguments. + out_fp16 (bool): Whether to convert the output back to fp16. + + Example: + + >>> import torch.nn as nn + >>> class MyModule1(nn.Module): + >>> + >>> # Convert x and y to fp32 + >>> @force_fp32() + >>> def loss(self, x, y): + >>> pass + + >>> import torch.nn as nn + >>> class MyModule2(nn.Module): + >>> + >>> # convert pred to fp32 + >>> @force_fp32(apply_to=('pred', )) + >>> def post_process(self, pred, others): + >>> pass + """ + + def force_fp32_wrapper(old_func): + + @functools.wraps(old_func) + def new_func(*args, **kwargs): + # check if the module has set the attribute `fp16_enabled`, if not, + # just fallback to the original method. + if not isinstance(args[0], torch.nn.Module): + raise TypeError('@force_fp32 can only be used to decorate the ' + 'method of nn.Module') + if not (hasattr(args[0], 'fp16_enabled') and args[0].fp16_enabled): + return old_func(*args, **kwargs) + # get the arg spec of the decorated method + args_info = getfullargspec(old_func) + # get the argument names to be casted + args_to_cast = args_info.args if apply_to is None else apply_to + # convert the args that need to be processed + new_args = [] + if args: + arg_names = args_info.args[:len(args)] + for i, arg_name in enumerate(arg_names): + if arg_name in args_to_cast: + new_args.append( + cast_tensor_type(args[i], torch.half, torch.float)) + else: + new_args.append(args[i]) + # convert the kwargs that need to be processed + new_kwargs = dict() + if kwargs: + for arg_name, arg_value in kwargs.items(): + if arg_name in args_to_cast: + new_kwargs[arg_name] = cast_tensor_type( + arg_value, torch.half, torch.float) + else: + new_kwargs[arg_name] = arg_value + # apply converted arguments to the decorated method + output = old_func(*new_args, **new_kwargs) + # cast the results back to fp32 if necessary + if out_fp16: + output = cast_tensor_type(output, torch.float, torch.half) + return output + + return new_func + + return force_fp32_wrapper + + +def allreduce_grads(params, coalesce=True, bucket_size_mb=-1): + warnings.warning( + '"mmcv.runner.fp16_utils.allreduce_grads" is deprecated, and will be ' + 'removed in v2.8. Please switch to "mmcv.runner.allreduce_grads') + _allreduce_grads(params, coalesce=coalesce, bucket_size_mb=bucket_size_mb) + + +def wrap_fp16_model(model): + """Wrap the FP32 model to FP16. + + 1. Convert FP32 model to FP16. + 2. Remain some necessary layers to be FP32, e.g., normalization layers. + + Args: + model (nn.Module): Model in FP32. + """ + # convert model to fp16 + model.half() + # patch the normalization layers to make it work in fp32 mode + patch_norm_fp32(model) + # set `fp16_enabled` flag + for m in model.modules(): + if hasattr(m, 'fp16_enabled'): + m.fp16_enabled = True + + +def patch_norm_fp32(module): + """Recursively convert normalization layers from FP16 to FP32. + + Args: + module (nn.Module): The modules to be converted in FP16. + + Returns: + nn.Module: The converted module, the normalization layers have been + converted to FP32. + """ + if isinstance(module, (nn.modules.batchnorm._BatchNorm, nn.GroupNorm, nn.LayerNorm)): + module.float() + # if isinstance(module, nn.GroupNorm) or torch.__version__ < '1.3': + module.forward = patch_forward_method(module.forward, torch.half, + torch.float) + for child in module.children(): + patch_norm_fp32(child) + return module + + +def patch_forward_method(func, src_type, dst_type, convert_output=True): + """Patch the forward method of a module. + + Args: + func (callable): The original forward method. + src_type (torch.dtype): Type of input arguments to be converted from. + dst_type (torch.dtype): Type of input arguments to be converted to. + convert_output (bool): Whether to convert the output back to src_type. + + Returns: + callable: The patched forward method. + """ + + def new_forward(*args, **kwargs): + output = func(*cast_tensor_type(args, src_type, dst_type), + **cast_tensor_type(kwargs, src_type, dst_type)) + if convert_output: + output = cast_tensor_type(output, dst_type, src_type) + return output + + return new_forward + + +class LossScaler: + """Class that manages loss scaling in mixed precision training which + supports both dynamic or static mode. + + The implementation refers to + https://github.com/NVIDIA/apex/blob/master/apex/fp16_utils/loss_scaler.py. + Indirectly, by supplying ``mode='dynamic'`` for dynamic loss scaling. + It's important to understand how :class:`LossScaler` operates. + Loss scaling is designed to combat the problem of underflowing + gradients encountered at long times when training fp16 networks. + Dynamic loss scaling begins by attempting a very high loss + scale. Ironically, this may result in OVERflowing gradients. + If overflowing gradients are encountered, :class:`FP16_Optimizer` then + skips the update step for this particular iteration/minibatch, + and :class:`LossScaler` adjusts the loss scale to a lower value. + If a certain number of iterations occur without overflowing gradients + detected,:class:`LossScaler` increases the loss scale once more. + In this way :class:`LossScaler` attempts to "ride the edge" of always + using the highest loss scale possible without incurring overflow. + + Args: + init_scale (float): Initial loss scale value, default: 2**32. + scale_factor (float): Factor used when adjusting the loss scale. + Default: 2. + mode (str): Loss scaling mode. 'dynamic' or 'static' + scale_window (int): Number of consecutive iterations without an + overflow to wait before increasing the loss scale. Default: 1000. + """ + + def __init__(self, + init_scale=2**32, + mode='dynamic', + scale_factor=2., + scale_window=1000): + self.cur_scale = init_scale + self.cur_iter = 0 + assert mode in ('dynamic', + 'static'), 'mode can only be dynamic or static' + self.mode = mode + self.last_overflow_iter = -1 + self.scale_factor = scale_factor + self.scale_window = scale_window + + def has_overflow(self, params): + """Check if params contain overflow.""" + if self.mode != 'dynamic': + return False + for p in params: + if p.grad is not None and LossScaler._has_inf_or_nan(p.grad.data): + return True + return False + + def _has_inf_or_nan(x): + """Check if params contain NaN.""" + try: + cpu_sum = float(x.float().sum()) + except RuntimeError as instance: + if 'value cannot be converted' not in instance.args[0]: + raise + return True + else: + if cpu_sum == float('inf') or cpu_sum == -float('inf') \ + or cpu_sum != cpu_sum: + return True + return False + + def update_scale(self, overflow): + """update the current loss scale value when overflow happens.""" + if self.mode != 'dynamic': + return + if overflow: + self.cur_scale = max(self.cur_scale / self.scale_factor, 1) + self.last_overflow_iter = self.cur_iter + else: + if (self.cur_iter - self.last_overflow_iter) % \ + self.scale_window == 0: + self.cur_scale *= self.scale_factor + self.cur_iter += 1 + + @property + def loss_scale(self): + return self.cur_scale diff --git a/PyTorch/contrib/cv/semantic_segmentation/SETR/tools/dist_train.sh b/PyTorch/contrib/cv/semantic_segmentation/SETR/tools/dist_train.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/semantic_segmentation/UNet_for_PyTorch/modelzoo_level.txt b/PyTorch/contrib/cv/semantic_segmentation/UNet_for_PyTorch/modelzoo_level.txt index a17c8f95fa..a829ab59b9 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/UNet_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/contrib/cv/semantic_segmentation/UNet_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:NOK +FuncStatus:OK +PerfStatus:NOK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/semantic_segmentation/Wseg/configs/voc_resnet38.yaml b/PyTorch/contrib/cv/semantic_segmentation/Wseg/configs/voc_resnet38.yaml index 7870288e6f..b89a2dd653 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/Wseg/configs/voc_resnet38.yaml +++ b/PyTorch/contrib/cv/semantic_segmentation/Wseg/configs/voc_resnet38.yaml @@ -1,32 +1,32 @@ -NUM_GPUS: 1 -DATASET: - CROP_SIZE: 321 - SCALE_FROM: 0.9 - SCALE_TO: 1.0 -TRAIN: - BATCH_SIZE: 16 - NUM_EPOCHS: 24 - NUM_WORKERS: 8 - PRETRAIN: 5 -NET: - BACKBONE: "resnet38" - MODEL: "ae" - PRE_WEIGHTS_PATH: "./models/weights/ilsvrc-cls_rna-a1_cls1000_ep-0001.pth" - LR: 0.001 - OPT: "SGD" - LOSS: "SoftMargin" - WEIGHT_DECAY: 0.0005 - PAMR_ITER: 10 - FOCAL_LAMBDA: 0.01 - FOCAL_P: 3 - SG_PSI: 0.3 -TEST: - METHOD: "multiscale" - DATA_ROOT: "./data" - FLIP: True - BATCH_SIZE: 8 - PAD_SIZE: [1024, 1024] - SCALES: [1, 0.5, 1.5, 2.0] - FP_CUT_SCORE: 0.1 - BG_POW: 3 - USE_GT_LABELS: False +NUM_GPUS: 1 +DATASET: + CROP_SIZE: 321 + SCALE_FROM: 0.9 + SCALE_TO: 1.0 +TRAIN: + BATCH_SIZE: 16 + NUM_EPOCHS: 24 + NUM_WORKERS: 8 + PRETRAIN: 5 +NET: + BACKBONE: "resnet38" + MODEL: "ae" + PRE_WEIGHTS_PATH: "./models/weights/ilsvrc-cls_rna-a1_cls1000_ep-0001.pth" + LR: 0.001 + OPT: "SGD" + LOSS: "SoftMargin" + WEIGHT_DECAY: 0.0005 + PAMR_ITER: 10 + FOCAL_LAMBDA: 0.01 + FOCAL_P: 3 + SG_PSI: 0.3 +TEST: + METHOD: "multiscale" + DATA_ROOT: "./data" + FLIP: True + BATCH_SIZE: 8 + PAD_SIZE: [1024, 1024] + SCALES: [1, 0.5, 1.5, 2.0] + FP_CUT_SCORE: 0.1 + BG_POW: 3 + USE_GT_LABELS: False diff --git a/PyTorch/contrib/cv/semantic_segmentation/Wseg/core/config.py b/PyTorch/contrib/cv/semantic_segmentation/Wseg/core/config.py index dee2341357..fcc5d5b808 100644 --- a/PyTorch/contrib/cv/semantic_segmentation/Wseg/core/config.py +++ b/PyTorch/contrib/cv/semantic_segmentation/Wseg/core/config.py @@ -1,261 +1,261 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 -from __future__ import unicode_literals - - -import yaml -import six -import os -import os.path as osp -import copy -from ast import literal_eval - -import numpy as np -from packaging import version - -from utils.collections import AttrDict - -__C = AttrDict() -# Consumers can get config by: -# from fast_rcnn_config import cfg -cfg = __C - -__C.NUM_GPUS = 1 -# Random note: avoid using '.ON' as a config key since yaml converts it to True; -# prefer 'ENABLED' instead - -# ---------------------------------------------------------------------------- # -# Training options -# ---------------------------------------------------------------------------- # -__C.TRAIN = AttrDict() -__C.TRAIN.BATCH_SIZE = 20 -__C.TRAIN.NUM_EPOCHS = 15 -__C.TRAIN.NUM_WORKERS = 4 -__C.TRAIN.MASK_LOSS = 0.0 -__C.TRAIN.PRETRAIN = 5 - -# ---------------------------------------------------------------------------- # -# Inference options -# ---------------------------------------------------------------------------- # -__C.TEST = AttrDict() -__C.TEST.METHOD = "multiscale" # multiscale | crop -__C.TEST.DATA_ROOT = "/data/your_directory" -__C.TEST.SCALES = [1, 0.5, 1.5, 2.0] -__C.TEST.FLIP = True -__C.TEST.PAD_SIZE = [1024, 1024] -__C.TEST.CROP_SIZE = [448, 448] -__C.TEST.CROP_GRID_SIZE = [2, 2] -__C.TEST.BATCH_SIZE = 8 -__C.TEST.BG_POW = 3 -__C.TEST.NUM_CLASSES = 21 - -# use ground-truth labels to remove -# false positive masks -__C.TEST.USE_GT_LABELS = False - -# if class confidence does not exceed this threshold -# the mask is removed (count as false positive) -# used only if MASKS.USE_GT_LABELS is False -__C.TEST.FP_CUT_SCORE = 0.1 - -# ---------------------------------------------------------------------------- # -# Dataset options -# ---------------------------------------------------------------------------- # -__C.DATASET = AttrDict() - -__C.DATASET.CROP_SIZE = 321 -__C.DATASET.SCALE_FROM = 0.9 -__C.DATASET.SCALE_TO = 1.0 -__C.DATASET.PATH = "data/images" - -# ---------------------------------------------------------------------------- # -# Network options -# ---------------------------------------------------------------------------- # -__C.NET = AttrDict() -__C.NET.MODEL = 'vgg16' -__C.NET.BACKBONE = 'resnet50' -__C.NET.PRE_WEIGHTS_PATH = "" -__C.NET.OPT = 'SGD' -__C.NET.LR = 0.001 -__C.NET.BETA1 = 0.5 -__C.NET.MOMENTUM = 0.9 -__C.NET.WEIGHT_DECAY = 1e-5 -__C.NET.LOSS = 'SoftMargin' -__C.NET.MASK_LOSS_BCE = 1.0 -__C.NET.BG_SCORE = 0.1 # background score (only for CAM) -__C.NET.FOCAL_P = 3 -__C.NET.FOCAL_LAMBDA = 0.01 -__C.NET.PAMR_KERNEL = [1, 2, 4, 8, 12, 24] -__C.NET.PAMR_ITER = 10 -__C.NET.SG_PSI = 0.3 - -# Mask Inference -__C.MASKS = AttrDict() - -# CRF options -__C.MASKS.CRF = AttrDict() -__C.MASKS.CRF.ALPHA_LOW = 4 -__C.MASKS.CRF.ALPHA_HIGH = 32 - -# [Infered value] -__C.CUDA = False - -__C.DEBUG = False - -# [Infered value] -__C.PYTORCH_VERSION_LESS_THAN_040 = False - -def assert_and_infer_cfg(make_immutable=True): - """Call this function in your script after you have finished setting all cfg - values that are necessary (e.g., merging a config from a file, merging - command line config options, etc.). By default, this function will also - mark the global cfg as immutable to prevent changing the global cfg settings - during script execution (which can lead to hard to debug errors or code - that's harder to understand than is necessary). - """ - if make_immutable: - cfg.immutable(True) - - -def merge_cfg_from_file(cfg_filename): - """Load a yaml config file and merge it into the global config.""" - with open(cfg_filename, 'r') as f: - if hasattr(yaml, "FullLoader"): - yaml_cfg = AttrDict(yaml.load(f, Loader=yaml.FullLoader)) - else: - yaml_cfg = AttrDict(yaml.load(f)) - - _merge_a_into_b(yaml_cfg, __C) - -cfg_from_file = merge_cfg_from_file - - -def merge_cfg_from_cfg(cfg_other): - """Merge `cfg_other` into the global config.""" - _merge_a_into_b(cfg_other, __C) - - -def merge_cfg_from_list(cfg_list): - """Merge config keys, values in a list (e.g., from command line) into the - global config. For example, `cfg_list = ['TEST.NMS', 0.5]`. - """ - assert len(cfg_list) % 2 == 0 - for full_key, v in zip(cfg_list[0::2], cfg_list[1::2]): - key_list = full_key.split('.') - d = __C - for subkey in key_list[:-1]: - assert subkey in d, 'Non-existent key: {}'.format(full_key) - d = d[subkey] - subkey = key_list[-1] - assert subkey in d, 'Non-existent key: {}'.format(full_key) - value = _decode_cfg_value(v) - value = _check_and_coerce_cfg_value_type( - value, d[subkey], subkey, full_key - ) - d[subkey] = value - -cfg_from_list = merge_cfg_from_list - - -def _merge_a_into_b(a, b, stack=None): - """Merge config dictionary a into config dictionary b, clobbering the - options in b whenever they are also specified in a. - """ - assert isinstance(a, AttrDict), 'Argument `a` must be an AttrDict' - assert isinstance(b, AttrDict), 'Argument `b` must be an AttrDict' - - for k, v_ in a.items(): - full_key = '.'.join(stack) + '.' + k if stack is not None else k - # a must specify keys that are in b - if k not in b: - raise KeyError('Non-existent config key: {}'.format(full_key)) - - v = copy.deepcopy(v_) - v = _decode_cfg_value(v) - v = _check_and_coerce_cfg_value_type(v, b[k], k, full_key) - - # Recursively merge dicts - if isinstance(v, AttrDict): - try: - stack_push = [k] if stack is None else stack + [k] - _merge_a_into_b(v, b[k], stack=stack_push) - except BaseException: - raise - else: - b[k] = v - - -def _decode_cfg_value(v): - """Decodes a raw config value (e.g., from a yaml config files or command - line argument) into a Python object. - """ - # Configs parsed from raw yaml will contain dictionary keys that need to be - # converted to AttrDict objects - if isinstance(v, dict): - return AttrDict(v) - # All remaining processing is only applied to strings - if not isinstance(v, six.string_types): - return v - # Try to interpret `v` as a: - # string, number, tuple, list, dict, boolean, or None - try: - v = literal_eval(v) - # The following two excepts allow v to pass through when it represents a - # string. - # - # Longer explanation: - # The type of v is always a string (before calling literal_eval), but - # sometimes it *represents* a string and other times a data structure, like - # a list. In the case that v represents a string, what we got back from the - # yaml parser is 'foo' *without quotes* (so, not '"foo"'). literal_eval is - # ok with '"foo"', but will raise a ValueError if given 'foo'. In other - # cases, like paths (v = 'foo/bar' and not v = '"foo/bar"'), literal_eval - # will raise a SyntaxError. - except ValueError: - pass - except SyntaxError: - pass - return v - - -def _check_and_coerce_cfg_value_type(value_a, value_b, key, full_key): - """Checks that `value_a`, which is intended to replace `value_b` is of the - right type. The type is correct if it matches exactly or is one of a few - cases in which the type can be easily coerced. - """ - # The types must match (with some exceptions) - type_b = type(value_b) - type_a = type(value_a) - if type_a is type_b: - return value_a - - # Exceptions: numpy arrays, strings, tuple<->list - if isinstance(value_b, np.ndarray): - value_a = np.array(value_a, dtype=value_b.dtype) - elif isinstance(value_b, six.string_types): - value_a = str(value_a) - elif isinstance(value_a, tuple) and isinstance(value_b, list): - value_a = list(value_a) - elif isinstance(value_a, list) and isinstance(value_b, tuple): - value_a = tuple(value_a) - else: - raise ValueError( - 'Type mismatch ({} vs. {}) with values ({} vs. {}) for config ' - 'key: {}'.format(type_b, type_a, value_b, value_a, full_key) - ) - return value_a +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 +from __future__ import unicode_literals + + +import yaml +import six +import os +import os.path as osp +import copy +from ast import literal_eval + +import numpy as np +from packaging import version + +from utils.collections import AttrDict + +__C = AttrDict() +# Consumers can get config by: +# from fast_rcnn_config import cfg +cfg = __C + +__C.NUM_GPUS = 1 +# Random note: avoid using '.ON' as a config key since yaml converts it to True; +# prefer 'ENABLED' instead + +# ---------------------------------------------------------------------------- # +# Training options +# ---------------------------------------------------------------------------- # +__C.TRAIN = AttrDict() +__C.TRAIN.BATCH_SIZE = 20 +__C.TRAIN.NUM_EPOCHS = 15 +__C.TRAIN.NUM_WORKERS = 4 +__C.TRAIN.MASK_LOSS = 0.0 +__C.TRAIN.PRETRAIN = 5 + +# ---------------------------------------------------------------------------- # +# Inference options +# ---------------------------------------------------------------------------- # +__C.TEST = AttrDict() +__C.TEST.METHOD = "multiscale" # multiscale | crop +__C.TEST.DATA_ROOT = "/data/your_directory" +__C.TEST.SCALES = [1, 0.5, 1.5, 2.0] +__C.TEST.FLIP = True +__C.TEST.PAD_SIZE = [1024, 1024] +__C.TEST.CROP_SIZE = [448, 448] +__C.TEST.CROP_GRID_SIZE = [2, 2] +__C.TEST.BATCH_SIZE = 8 +__C.TEST.BG_POW = 3 +__C.TEST.NUM_CLASSES = 21 + +# use ground-truth labels to remove +# false positive masks +__C.TEST.USE_GT_LABELS = False + +# if class confidence does not exceed this threshold +# the mask is removed (count as false positive) +# used only if MASKS.USE_GT_LABELS is False +__C.TEST.FP_CUT_SCORE = 0.1 + +# ---------------------------------------------------------------------------- # +# Dataset options +# ---------------------------------------------------------------------------- # +__C.DATASET = AttrDict() + +__C.DATASET.CROP_SIZE = 321 +__C.DATASET.SCALE_FROM = 0.9 +__C.DATASET.SCALE_TO = 1.0 +__C.DATASET.PATH = "data/images" + +# ---------------------------------------------------------------------------- # +# Network options +# ---------------------------------------------------------------------------- # +__C.NET = AttrDict() +__C.NET.MODEL = 'vgg16' +__C.NET.BACKBONE = 'resnet50' +__C.NET.PRE_WEIGHTS_PATH = "" +__C.NET.OPT = 'SGD' +__C.NET.LR = 0.001 +__C.NET.BETA1 = 0.5 +__C.NET.MOMENTUM = 0.9 +__C.NET.WEIGHT_DECAY = 1e-5 +__C.NET.LOSS = 'SoftMargin' +__C.NET.MASK_LOSS_BCE = 1.0 +__C.NET.BG_SCORE = 0.1 # background score (only for CAM) +__C.NET.FOCAL_P = 3 +__C.NET.FOCAL_LAMBDA = 0.01 +__C.NET.PAMR_KERNEL = [1, 2, 4, 8, 12, 24] +__C.NET.PAMR_ITER = 10 +__C.NET.SG_PSI = 0.3 + +# Mask Inference +__C.MASKS = AttrDict() + +# CRF options +__C.MASKS.CRF = AttrDict() +__C.MASKS.CRF.ALPHA_LOW = 4 +__C.MASKS.CRF.ALPHA_HIGH = 32 + +# [Infered value] +__C.CUDA = False + +__C.DEBUG = False + +# [Infered value] +__C.PYTORCH_VERSION_LESS_THAN_040 = False + +def assert_and_infer_cfg(make_immutable=True): + """Call this function in your script after you have finished setting all cfg + values that are necessary (e.g., merging a config from a file, merging + command line config options, etc.). By default, this function will also + mark the global cfg as immutable to prevent changing the global cfg settings + during script execution (which can lead to hard to debug errors or code + that's harder to understand than is necessary). + """ + if make_immutable: + cfg.immutable(True) + + +def merge_cfg_from_file(cfg_filename): + """Load a yaml config file and merge it into the global config.""" + with open(cfg_filename, 'r') as f: + if hasattr(yaml, "FullLoader"): + yaml_cfg = AttrDict(yaml.load(f, Loader=yaml.FullLoader)) + else: + yaml_cfg = AttrDict(yaml.load(f)) + + _merge_a_into_b(yaml_cfg, __C) + +cfg_from_file = merge_cfg_from_file + + +def merge_cfg_from_cfg(cfg_other): + """Merge `cfg_other` into the global config.""" + _merge_a_into_b(cfg_other, __C) + + +def merge_cfg_from_list(cfg_list): + """Merge config keys, values in a list (e.g., from command line) into the + global config. For example, `cfg_list = ['TEST.NMS', 0.5]`. + """ + assert len(cfg_list) % 2 == 0 + for full_key, v in zip(cfg_list[0::2], cfg_list[1::2]): + key_list = full_key.split('.') + d = __C + for subkey in key_list[:-1]: + assert subkey in d, 'Non-existent key: {}'.format(full_key) + d = d[subkey] + subkey = key_list[-1] + assert subkey in d, 'Non-existent key: {}'.format(full_key) + value = _decode_cfg_value(v) + value = _check_and_coerce_cfg_value_type( + value, d[subkey], subkey, full_key + ) + d[subkey] = value + +cfg_from_list = merge_cfg_from_list + + +def _merge_a_into_b(a, b, stack=None): + """Merge config dictionary a into config dictionary b, clobbering the + options in b whenever they are also specified in a. + """ + assert isinstance(a, AttrDict), 'Argument `a` must be an AttrDict' + assert isinstance(b, AttrDict), 'Argument `b` must be an AttrDict' + + for k, v_ in a.items(): + full_key = '.'.join(stack) + '.' + k if stack is not None else k + # a must specify keys that are in b + if k not in b: + raise KeyError('Non-existent config key: {}'.format(full_key)) + + v = copy.deepcopy(v_) + v = _decode_cfg_value(v) + v = _check_and_coerce_cfg_value_type(v, b[k], k, full_key) + + # Recursively merge dicts + if isinstance(v, AttrDict): + try: + stack_push = [k] if stack is None else stack + [k] + _merge_a_into_b(v, b[k], stack=stack_push) + except BaseException: + raise + else: + b[k] = v + + +def _decode_cfg_value(v): + """Decodes a raw config value (e.g., from a yaml config files or command + line argument) into a Python object. + """ + # Configs parsed from raw yaml will contain dictionary keys that need to be + # converted to AttrDict objects + if isinstance(v, dict): + return AttrDict(v) + # All remaining processing is only applied to strings + if not isinstance(v, six.string_types): + return v + # Try to interpret `v` as a: + # string, number, tuple, list, dict, boolean, or None + try: + v = literal_eval(v) + # The following two excepts allow v to pass through when it represents a + # string. + # + # Longer explanation: + # The type of v is always a string (before calling literal_eval), but + # sometimes it *represents* a string and other times a data structure, like + # a list. In the case that v represents a string, what we got back from the + # yaml parser is 'foo' *without quotes* (so, not '"foo"'). literal_eval is + # ok with '"foo"', but will raise a ValueError if given 'foo'. In other + # cases, like paths (v = 'foo/bar' and not v = '"foo/bar"'), literal_eval + # will raise a SyntaxError. + except ValueError: + pass + except SyntaxError: + pass + return v + + +def _check_and_coerce_cfg_value_type(value_a, value_b, key, full_key): + """Checks that `value_a`, which is intended to replace `value_b` is of the + right type. The type is correct if it matches exactly or is one of a few + cases in which the type can be easily coerced. + """ + # The types must match (with some exceptions) + type_b = type(value_b) + type_a = type(value_a) + if type_a is type_b: + return value_a + + # Exceptions: numpy arrays, strings, tuple<->list + if isinstance(value_b, np.ndarray): + value_a = np.array(value_a, dtype=value_b.dtype) + elif isinstance(value_b, six.string_types): + value_a = str(value_a) + elif isinstance(value_a, tuple) and isinstance(value_b, list): + value_a = list(value_a) + elif isinstance(value_a, list) and isinstance(value_b, tuple): + value_a = tuple(value_a) + else: + raise ValueError( + 'Type mismatch ({} vs. {}) with values ({} vs. {}) for config ' + 'key: {}'.format(type_b, type_a, value_b, value_a, full_key) + ) + return value_a diff --git a/PyTorch/contrib/cv/video/C3D/additional_need/mmcv/dist_utils.py b/PyTorch/contrib/cv/video/C3D/additional_need/mmcv/dist_utils.py index 91346643e8..9e3f2b072b 100644 --- a/PyTorch/contrib/cv/video/C3D/additional_need/mmcv/dist_utils.py +++ b/PyTorch/contrib/cv/video/C3D/additional_need/mmcv/dist_utils.py @@ -1,185 +1,185 @@ -# Copyright (c) Open-MMLab. All rights reserved. -# -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 functools -import os -import subprocess -from collections import OrderedDict - -import torch -import torch.multiprocessing as mp -from torch import distributed as dist -from torch._utils import (_flatten_dense_tensors, _take_tensors, - _unflatten_dense_tensors) - -from mmcv.utils import TORCH_VERSION - - -def init_dist(launcher, backend='nccl', **kwargs): - if mp.get_start_method(allow_none=True) is None: - mp.set_start_method('spawn') - if launcher == 'pytorch': - _init_dist_pytorch(backend, **kwargs) - elif launcher == 'mpi': - _init_dist_mpi(backend, **kwargs) - elif launcher == 'slurm': - _init_dist_slurm(backend, **kwargs) - else: - raise ValueError(f'Invalid launcher type: {launcher}') - - -def _init_dist_pytorch(backend, **kwargs): - # TODO: use local_rank instead of rank % num_gpus - rank = int(os.environ['RANK']) - offset = 0 if os.getenv('NPUID', None) is None else int(os.environ['NPUID']) - num_gpus = torch.npu.device_count() - torch.npu.set_device((rank + offset) % num_gpus) - dist.init_process_group(backend=backend, **kwargs) - - -def _init_dist_mpi(backend, **kwargs): - # TODO: use local_rank instead of rank % num_gpus - rank = int(os.environ['OMPI_COMM_WORLD_RANK']) - num_gpus = torch.cuda.device_count() - torch.cuda.set_device(rank % num_gpus) - dist.init_process_group(backend=backend, **kwargs) - - -def _init_dist_slurm(backend, port=None): - """Initialize slurm distributed training environment. - If argument ``port`` is not specified, then the master port will be system - environment variable ``MASTER_PORT``. If ``MASTER_PORT`` is not in system - environment variable, then a default port ``29500`` will be used. - Args: - backend (str): Backend of torch.distributed. - port (int, optional): Master port. Defaults to None. - """ - proc_id = int(os.environ['SLURM_PROCID']) - ntasks = int(os.environ['SLURM_NTASKS']) - node_list = os.environ['SLURM_NODELIST'] - num_gpus = torch.cuda.device_count() - torch.cuda.set_device(proc_id % num_gpus) - addr = subprocess.getoutput( - f'scontrol show hostname {node_list} | head -n1') - # specify master port - if port is not None: - os.environ['MASTER_PORT'] = str(port) - elif 'MASTER_PORT' in os.environ: - pass # use MASTER_PORT in the environment variable - else: - # 29500 is torch.distributed default port - os.environ['MASTER_PORT'] = '29500' - # use MASTER_ADDR in the environment variable if it already exists - if 'MASTER_ADDR' not in os.environ: - os.environ['MASTER_ADDR'] = addr - os.environ['WORLD_SIZE'] = str(ntasks) - os.environ['LOCAL_RANK'] = str(proc_id % num_gpus) - os.environ['RANK'] = str(proc_id) - dist.init_process_group(backend=backend) - - -def get_dist_info(): - if TORCH_VERSION < '1.0': - initialized = dist._initialized - else: - if dist.is_available(): - initialized = dist.is_initialized() - else: - initialized = False - if initialized: - rank = dist.get_rank() - world_size = dist.get_world_size() - else: - rank = 0 - world_size = 1 - return rank, world_size - - -def master_only(func): - - @functools.wraps(func) - def wrapper(*args, **kwargs): - rank, _ = get_dist_info() - if rank == 0: - return func(*args, **kwargs) - - return wrapper - - -def allreduce_params(params, coalesce=True, bucket_size_mb=-1): - """Allreduce parameters. - Args: - params (list[torch.Parameters]): List of parameters or buffers of a - model. - coalesce (bool, optional): Whether allreduce parameters as a whole. - Defaults to True. - bucket_size_mb (int, optional): Size of bucket, the unit is MB. - Defaults to -1. - """ - _, world_size = get_dist_info() - if world_size == 1: - return - params = [param.data for param in params] - if coalesce: - _allreduce_coalesced(params, world_size, bucket_size_mb) - else: - for tensor in params: - dist.all_reduce(tensor.div_(world_size)) - - -def allreduce_grads(params, coalesce=True, bucket_size_mb=-1): - """Allreduce gradients. - Args: - params (list[torch.Parameters]): List of parameters of a model - coalesce (bool, optional): Whether allreduce parameters as a whole. - Defaults to True. - bucket_size_mb (int, optional): Size of bucket, the unit is MB. - Defaults to -1. - """ - grads = [ - param.grad.data for param in params - if param.requires_grad and param.grad is not None - ] - _, world_size = get_dist_info() - if world_size == 1: - return - if coalesce: - _allreduce_coalesced(grads, world_size, bucket_size_mb) - else: - for tensor in grads: - dist.all_reduce(tensor.div_(world_size)) - - -def _allreduce_coalesced(tensors, world_size, bucket_size_mb=-1): - if bucket_size_mb > 0: - bucket_size_bytes = bucket_size_mb * 1024 * 1024 - buckets = _take_tensors(tensors, bucket_size_bytes) - else: - buckets = OrderedDict() - for tensor in tensors: - tp = tensor.type() - if tp not in buckets: - buckets[tp] = [] - buckets[tp].append(tensor) - buckets = buckets.values() - - for bucket in buckets: - flat_tensors = _flatten_dense_tensors(bucket) - dist.all_reduce(flat_tensors) - flat_tensors.div_(world_size) - for tensor, synced in zip( - bucket, _unflatten_dense_tensors(flat_tensors, bucket)): +# Copyright (c) Open-MMLab. All rights reserved. +# +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 functools +import os +import subprocess +from collections import OrderedDict + +import torch +import torch.multiprocessing as mp +from torch import distributed as dist +from torch._utils import (_flatten_dense_tensors, _take_tensors, + _unflatten_dense_tensors) + +from mmcv.utils import TORCH_VERSION + + +def init_dist(launcher, backend='nccl', **kwargs): + if mp.get_start_method(allow_none=True) is None: + mp.set_start_method('spawn') + if launcher == 'pytorch': + _init_dist_pytorch(backend, **kwargs) + elif launcher == 'mpi': + _init_dist_mpi(backend, **kwargs) + elif launcher == 'slurm': + _init_dist_slurm(backend, **kwargs) + else: + raise ValueError(f'Invalid launcher type: {launcher}') + + +def _init_dist_pytorch(backend, **kwargs): + # TODO: use local_rank instead of rank % num_gpus + rank = int(os.environ['RANK']) + offset = 0 if os.getenv('NPUID', None) is None else int(os.environ['NPUID']) + num_gpus = torch.npu.device_count() + torch.npu.set_device((rank + offset) % num_gpus) + dist.init_process_group(backend=backend, **kwargs) + + +def _init_dist_mpi(backend, **kwargs): + # TODO: use local_rank instead of rank % num_gpus + rank = int(os.environ['OMPI_COMM_WORLD_RANK']) + num_gpus = torch.cuda.device_count() + torch.cuda.set_device(rank % num_gpus) + dist.init_process_group(backend=backend, **kwargs) + + +def _init_dist_slurm(backend, port=None): + """Initialize slurm distributed training environment. + If argument ``port`` is not specified, then the master port will be system + environment variable ``MASTER_PORT``. If ``MASTER_PORT`` is not in system + environment variable, then a default port ``29500`` will be used. + Args: + backend (str): Backend of torch.distributed. + port (int, optional): Master port. Defaults to None. + """ + proc_id = int(os.environ['SLURM_PROCID']) + ntasks = int(os.environ['SLURM_NTASKS']) + node_list = os.environ['SLURM_NODELIST'] + num_gpus = torch.cuda.device_count() + torch.cuda.set_device(proc_id % num_gpus) + addr = subprocess.getoutput( + f'scontrol show hostname {node_list} | head -n1') + # specify master port + if port is not None: + os.environ['MASTER_PORT'] = str(port) + elif 'MASTER_PORT' in os.environ: + pass # use MASTER_PORT in the environment variable + else: + # 29500 is torch.distributed default port + os.environ['MASTER_PORT'] = '29500' + # use MASTER_ADDR in the environment variable if it already exists + if 'MASTER_ADDR' not in os.environ: + os.environ['MASTER_ADDR'] = addr + os.environ['WORLD_SIZE'] = str(ntasks) + os.environ['LOCAL_RANK'] = str(proc_id % num_gpus) + os.environ['RANK'] = str(proc_id) + dist.init_process_group(backend=backend) + + +def get_dist_info(): + if TORCH_VERSION < '1.0': + initialized = dist._initialized + else: + if dist.is_available(): + initialized = dist.is_initialized() + else: + initialized = False + if initialized: + rank = dist.get_rank() + world_size = dist.get_world_size() + else: + rank = 0 + world_size = 1 + return rank, world_size + + +def master_only(func): + + @functools.wraps(func) + def wrapper(*args, **kwargs): + rank, _ = get_dist_info() + if rank == 0: + return func(*args, **kwargs) + + return wrapper + + +def allreduce_params(params, coalesce=True, bucket_size_mb=-1): + """Allreduce parameters. + Args: + params (list[torch.Parameters]): List of parameters or buffers of a + model. + coalesce (bool, optional): Whether allreduce parameters as a whole. + Defaults to True. + bucket_size_mb (int, optional): Size of bucket, the unit is MB. + Defaults to -1. + """ + _, world_size = get_dist_info() + if world_size == 1: + return + params = [param.data for param in params] + if coalesce: + _allreduce_coalesced(params, world_size, bucket_size_mb) + else: + for tensor in params: + dist.all_reduce(tensor.div_(world_size)) + + +def allreduce_grads(params, coalesce=True, bucket_size_mb=-1): + """Allreduce gradients. + Args: + params (list[torch.Parameters]): List of parameters of a model + coalesce (bool, optional): Whether allreduce parameters as a whole. + Defaults to True. + bucket_size_mb (int, optional): Size of bucket, the unit is MB. + Defaults to -1. + """ + grads = [ + param.grad.data for param in params + if param.requires_grad and param.grad is not None + ] + _, world_size = get_dist_info() + if world_size == 1: + return + if coalesce: + _allreduce_coalesced(grads, world_size, bucket_size_mb) + else: + for tensor in grads: + dist.all_reduce(tensor.div_(world_size)) + + +def _allreduce_coalesced(tensors, world_size, bucket_size_mb=-1): + if bucket_size_mb > 0: + bucket_size_bytes = bucket_size_mb * 1024 * 1024 + buckets = _take_tensors(tensors, bucket_size_bytes) + else: + buckets = OrderedDict() + for tensor in tensors: + tp = tensor.type() + if tp not in buckets: + buckets[tp] = [] + buckets[tp].append(tensor) + buckets = buckets.values() + + for bucket in buckets: + flat_tensors = _flatten_dense_tensors(bucket) + dist.all_reduce(flat_tensors) + flat_tensors.div_(world_size) + for tensor, synced in zip( + bucket, _unflatten_dense_tensors(flat_tensors, bucket)): tensor.copy_(synced) \ No newline at end of file diff --git a/PyTorch/contrib/cv/video/C3D/additional_need/mmcv/distributed.py b/PyTorch/contrib/cv/video/C3D/additional_need/mmcv/distributed.py index fb2bae9229..4c89d09fc4 100644 --- a/PyTorch/contrib/cv/video/C3D/additional_need/mmcv/distributed.py +++ b/PyTorch/contrib/cv/video/C3D/additional_need/mmcv/distributed.py @@ -1,119 +1,119 @@ -# Copyright (c) Open-MMLab. All rights reserved. -# -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -from torch.nn.parallel.distributed import (DistributedDataParallel, - _find_tensors) - -from mmcv import print_log -from mmcv.utils import TORCH_VERSION -from .scatter_gather import scatter_kwargs - - -class MMDistributedDataParallel(DistributedDataParallel): - """The DDP module that supports DataContainer. - - MMDDP has two main differences with PyTorch DDP: - - - It supports a custom type :class:`DataContainer` which allows more - flexible control of input data. - - It implement two APIs ``train_step()`` and ``val_step()``. - """ - - def scatter(self, inputs, kwargs, device_ids): - return scatter_kwargs(inputs, kwargs, device_ids, dim=self.dim) - - def train_step(self, *inputs, **kwargs): - """train_step() API for module wrapped by DistributedDataParallel. - - This method is basically the same as - ``DistributedDataParallel.forward()``, while replacing - ``self.module.forward()`` with ``self.module.train_step()``. - It is compatible with PyTorch 1.1 - 1.5. - """ - - # In PyTorch >= 1.7, ``reducer._rebuild_buckets()`` is moved from the - # end of backward to the beginning of forward. - if (TORCH_VERSION >= '1.7' and 'parrots' - not in TORCH_VERSION) and self.reducer._rebuild_buckets(): - print_log( - 'Reducer buckets have been rebuilt in this iteration.', - logger='mmcv') - - if getattr(self, 'require_forward_param_sync', True): - self._sync_params() - if self.device_ids and False: - inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids) - if len(self.device_ids) == 1: - output = self.module.train_step(*inputs[0], **kwargs[0]) - else: - outputs = self.parallel_apply( - self._module_copies[:len(inputs)], inputs, kwargs) - output = self.gather(outputs, self.output_device) - else: - inputs, kwargs = self.scatter(inputs, kwargs, [-1]) - output = self.module.train_step(*inputs[0], **kwargs[0]) - - if torch.is_grad_enabled() and getattr( - self, 'require_backward_grad_sync', True): - if self.find_unused_parameters: - self.reducer.prepare_for_backward(list(_find_tensors(output))) - else: - self.reducer.prepare_for_backward([]) - else: - if TORCH_VERSION > '1.2': - self.require_forward_param_sync = False - return output - - def val_step(self, *inputs, **kwargs): - """val_step() API for module wrapped by DistributedDataParallel. - - This method is basically the same as - ``DistributedDataParallel.forward()``, while replacing - ``self.module.forward()`` with ``self.module.val_step()``. - It is compatible with PyTorch 1.1 - 1.5. - """ - # In PyTorch >= 1.7, ``reducer._rebuild_buckets()`` is moved from the - # end of backward to the beginning of forward. - if (TORCH_VERSION >= '1.7' and 'parrots' - not in TORCH_VERSION) and self.reducer._rebuild_buckets(): - print_log( - 'Reducer buckets have been rebuilt in this iteration.', - logger='mmcv') - - if getattr(self, 'require_forward_param_sync', True): - self._sync_params() - if self.device_ids: - inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids) - if len(self.device_ids) == 1: - output = self.module.val_step(*inputs[0], **kwargs[0]) - else: - outputs = self.parallel_apply( - self._module_copies[:len(inputs)], inputs, kwargs) - output = self.gather(outputs, self.output_device) - else: - output = self.module.val_step(*inputs, **kwargs) - - if torch.is_grad_enabled() and getattr( - self, 'require_backward_grad_sync', True): - if self.find_unused_parameters: - self.reducer.prepare_for_backward(list(_find_tensors(output))) - else: - self.reducer.prepare_for_backward([]) - else: - if TORCH_VERSION > '1.2': - self.require_forward_param_sync = False - return output +# Copyright (c) Open-MMLab. All rights reserved. +# +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +from torch.nn.parallel.distributed import (DistributedDataParallel, + _find_tensors) + +from mmcv import print_log +from mmcv.utils import TORCH_VERSION +from .scatter_gather import scatter_kwargs + + +class MMDistributedDataParallel(DistributedDataParallel): + """The DDP module that supports DataContainer. + + MMDDP has two main differences with PyTorch DDP: + + - It supports a custom type :class:`DataContainer` which allows more + flexible control of input data. + - It implement two APIs ``train_step()`` and ``val_step()``. + """ + + def scatter(self, inputs, kwargs, device_ids): + return scatter_kwargs(inputs, kwargs, device_ids, dim=self.dim) + + def train_step(self, *inputs, **kwargs): + """train_step() API for module wrapped by DistributedDataParallel. + + This method is basically the same as + ``DistributedDataParallel.forward()``, while replacing + ``self.module.forward()`` with ``self.module.train_step()``. + It is compatible with PyTorch 1.1 - 1.5. + """ + + # In PyTorch >= 1.7, ``reducer._rebuild_buckets()`` is moved from the + # end of backward to the beginning of forward. + if (TORCH_VERSION >= '1.7' and 'parrots' + not in TORCH_VERSION) and self.reducer._rebuild_buckets(): + print_log( + 'Reducer buckets have been rebuilt in this iteration.', + logger='mmcv') + + if getattr(self, 'require_forward_param_sync', True): + self._sync_params() + if self.device_ids and False: + inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids) + if len(self.device_ids) == 1: + output = self.module.train_step(*inputs[0], **kwargs[0]) + else: + outputs = self.parallel_apply( + self._module_copies[:len(inputs)], inputs, kwargs) + output = self.gather(outputs, self.output_device) + else: + inputs, kwargs = self.scatter(inputs, kwargs, [-1]) + output = self.module.train_step(*inputs[0], **kwargs[0]) + + if torch.is_grad_enabled() and getattr( + self, 'require_backward_grad_sync', True): + if self.find_unused_parameters: + self.reducer.prepare_for_backward(list(_find_tensors(output))) + else: + self.reducer.prepare_for_backward([]) + else: + if TORCH_VERSION > '1.2': + self.require_forward_param_sync = False + return output + + def val_step(self, *inputs, **kwargs): + """val_step() API for module wrapped by DistributedDataParallel. + + This method is basically the same as + ``DistributedDataParallel.forward()``, while replacing + ``self.module.forward()`` with ``self.module.val_step()``. + It is compatible with PyTorch 1.1 - 1.5. + """ + # In PyTorch >= 1.7, ``reducer._rebuild_buckets()`` is moved from the + # end of backward to the beginning of forward. + if (TORCH_VERSION >= '1.7' and 'parrots' + not in TORCH_VERSION) and self.reducer._rebuild_buckets(): + print_log( + 'Reducer buckets have been rebuilt in this iteration.', + logger='mmcv') + + if getattr(self, 'require_forward_param_sync', True): + self._sync_params() + if self.device_ids: + inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids) + if len(self.device_ids) == 1: + output = self.module.val_step(*inputs[0], **kwargs[0]) + else: + outputs = self.parallel_apply( + self._module_copies[:len(inputs)], inputs, kwargs) + output = self.gather(outputs, self.output_device) + else: + output = self.module.val_step(*inputs, **kwargs) + + if torch.is_grad_enabled() and getattr( + self, 'require_backward_grad_sync', True): + if self.find_unused_parameters: + self.reducer.prepare_for_backward(list(_find_tensors(output))) + else: + self.reducer.prepare_for_backward([]) + else: + if TORCH_VERSION > '1.2': + self.require_forward_param_sync = False + return output diff --git a/PyTorch/contrib/cv/video/C3D/additional_need/mmcv/optimizer.py b/PyTorch/contrib/cv/video/C3D/additional_need/mmcv/optimizer.py index 59eff597b8..4219fcf100 100644 --- a/PyTorch/contrib/cv/video/C3D/additional_need/mmcv/optimizer.py +++ b/PyTorch/contrib/cv/video/C3D/additional_need/mmcv/optimizer.py @@ -1,182 +1,182 @@ -# Copyright (c) Open-MMLab. All rights reserved. -# -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 copy -from collections import defaultdict -from itertools import chain - -from torch.nn.utils import clip_grad - -from ..dist_utils import allreduce_grads -from ..fp16_utils import LossScaler, wrap_fp16_model -from .hook import HOOKS, Hook -from apex import amp +# Copyright (c) Open-MMLab. All rights reserved. +# +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 copy +from collections import defaultdict +from itertools import chain + +from torch.nn.utils import clip_grad + +from ..dist_utils import allreduce_grads +from ..fp16_utils import LossScaler, wrap_fp16_model +from .hook import HOOKS, Hook +from apex import amp import time - -@HOOKS.register_module() -class OptimizerHook(Hook): - - def __init__(self, grad_clip=None): - self.grad_clip = grad_clip - - def clip_grads(self, params): - params = list( - filter(lambda p: p.requires_grad and p.grad is not None, params)) - #todo add a line - if len(params) > 0: - return clip_grad.clip_grad_norm_(params, **self.grad_clip) - - def after_train_iter(self, runner): - runner.optimizer.zero_grad() - with amp.scale_loss(runner.outputs['loss'], runner.optimizer ) as scaled_loss: - scaled_loss.backward() - if self.grad_clip is not None: - grad_norm = self.clip_grads(runner.model.npu().parameters()) - if grad_norm is not None: - # Add grad norm to the logger - runner.log_buffer.update({'grad_norm': float(grad_norm)}, - runner.outputs['num_samples']) + +@HOOKS.register_module() +class OptimizerHook(Hook): + + def __init__(self, grad_clip=None): + self.grad_clip = grad_clip + + def clip_grads(self, params): + params = list( + filter(lambda p: p.requires_grad and p.grad is not None, params)) + #todo add a line + if len(params) > 0: + return clip_grad.clip_grad_norm_(params, **self.grad_clip) + + def after_train_iter(self, runner): + runner.optimizer.zero_grad() + with amp.scale_loss(runner.outputs['loss'], runner.optimizer ) as scaled_loss: + scaled_loss.backward() + if self.grad_clip is not None: + grad_norm = self.clip_grads(runner.model.npu().parameters()) + if grad_norm is not None: + # Add grad norm to the logger + runner.log_buffer.update({'grad_norm': float(grad_norm)}, + runner.outputs['num_samples']) runner.optimizer.step() runner.batch_time.update(time.time()-runner.end) - runner.end = time.time() - - - -@HOOKS.register_module() -class Fp16OptimizerHook(OptimizerHook): - """FP16 optimizer hook. - - The steps of fp16 optimizer is as follows. - 1. Scale the loss value. - 2. BP in the fp16 model. - 2. Copy gradients from fp16 model to fp32 weights. - 3. Update fp32 weights. - 4. Copy updated parameters from fp32 weights to fp16 model. - - Refer to https://arxiv.org/abs/1710.03740 for more details. - - Args: - loss_scale (float | str | dict): Scale factor multiplied with loss. - If loss_scale is a float, static loss scaling will be used with - the specified scale. If loss_scale is a string, it must be - 'dynamic', then dynamic loss scaling will be used. - It can also be a dict containing arguments of LossScaler. - Defaults to 512. - """ - - def __init__(self, - grad_clip=None, - coalesce=True, - bucket_size_mb=-1, - loss_scale=512., - distributed=True): - self.grad_clip = grad_clip - self.coalesce = coalesce - self.bucket_size_mb = bucket_size_mb - self.distributed = distributed - if loss_scale == 'dynamic': - self.loss_scaler = LossScaler(mode='dynamic') - elif isinstance(loss_scale, float): - self.loss_scaler = LossScaler(init_scale=loss_scale, mode='static') - elif isinstance(loss_scale, dict): - self.loss_scaler = LossScaler(**loss_scale) - else: - raise ValueError('loss_scale must be of type float, dict, or ' - f'"dynamic", got {loss_scale}') - - def before_run(self, runner): - """Preparing steps before Mixed Precision Training. - - 1. Make a master copy of fp32 weights for optimization. - 2. Convert the main model from fp32 to fp16. - """ - # keep a copy of fp32 weights - old_groups = runner.optimizer.param_groups - runner.optimizer.param_groups = copy.deepcopy( - runner.optimizer.param_groups) - state = defaultdict(dict) - p_map = { - old_p: p - for old_p, p in zip( - chain(*(g['params'] for g in old_groups)), - chain(*(g['params'] for g in runner.optimizer.param_groups))) - } - for k, v in runner.optimizer.state.items(): - state[p_map[k]] = v - runner.optimizer.state = state - # convert model to fp16 - wrap_fp16_model(runner.model) - - def copy_grads_to_fp32(self, fp16_net, fp32_weights): - """Copy gradients from fp16 model to fp32 weight copy.""" - for fp32_param, fp16_param in zip(fp32_weights, fp16_net.parameters()): - if fp16_param.grad is not None: - if fp32_param.grad is None: - fp32_param.grad = fp32_param.data.new(fp32_param.size()) - fp32_param.grad.copy_(fp16_param.grad) - - def copy_params_to_fp16(self, fp16_net, fp32_weights): - """Copy updated params from fp32 weight copy to fp16 model.""" - for fp16_param, fp32_param in zip(fp16_net.parameters(), fp32_weights): - fp16_param.data.copy_(fp32_param.data) - - def after_train_iter(self, runner): - """Backward optimization steps for Mixed Precision Training. For - dynamic loss scaling, please refer `loss_scalar.py` - - 1. Scale the loss by a scale factor. - 2. Backward the loss to obtain the gradients (fp16). - 3. Copy gradients from the model to the fp32 weight copy. - 4. Scale the gradients back and update the fp32 weight copy. - 5. Copy back the params from fp32 weight copy to the fp16 model. - """ - # clear grads of last iteration - runner.model.zero_grad() - runner.optimizer.zero_grad() - # scale the loss value - scaled_loss = runner.outputs['loss'] * self.loss_scaler.loss_scale - scaled_loss.backward() - # copy fp16 grads in the model to fp32 params in the optimizer - - fp32_weights = [] - for param_group in runner.optimizer.param_groups: - fp32_weights += param_group['params'] - self.copy_grads_to_fp32(runner.model, fp32_weights) - # allreduce grads - if self.distributed: - allreduce_grads(fp32_weights, self.coalesce, self.bucket_size_mb) - - has_overflow = self.loss_scaler.has_overflow(fp32_weights) - # if has overflow, skip this iteration - if not has_overflow: - # scale the gradients back - for param in fp32_weights: - if param.grad is not None: - param.grad.div_(self.loss_scaler.loss_scale) - if self.grad_clip is not None: - grad_norm = self.clip_grads(fp32_weights) - if grad_norm is not None: - # Add grad norm to the logger - runner.log_buffer.update({'grad_norm': float(grad_norm)}, - runner.outputs['num_samples']) - # update fp32 params - runner.optimizer.step() - # copy fp32 params to the fp16 model - self.copy_params_to_fp16(runner.model, fp32_weights) - self.loss_scaler.update_scale(has_overflow) - if has_overflow: - runner.logger.warning('Check overflow, downscale loss scale ' - f'to {self.loss_scaler.cur_scale}') + runner.end = time.time() + + + +@HOOKS.register_module() +class Fp16OptimizerHook(OptimizerHook): + """FP16 optimizer hook. + + The steps of fp16 optimizer is as follows. + 1. Scale the loss value. + 2. BP in the fp16 model. + 2. Copy gradients from fp16 model to fp32 weights. + 3. Update fp32 weights. + 4. Copy updated parameters from fp32 weights to fp16 model. + + Refer to https://arxiv.org/abs/1710.03740 for more details. + + Args: + loss_scale (float | str | dict): Scale factor multiplied with loss. + If loss_scale is a float, static loss scaling will be used with + the specified scale. If loss_scale is a string, it must be + 'dynamic', then dynamic loss scaling will be used. + It can also be a dict containing arguments of LossScaler. + Defaults to 512. + """ + + def __init__(self, + grad_clip=None, + coalesce=True, + bucket_size_mb=-1, + loss_scale=512., + distributed=True): + self.grad_clip = grad_clip + self.coalesce = coalesce + self.bucket_size_mb = bucket_size_mb + self.distributed = distributed + if loss_scale == 'dynamic': + self.loss_scaler = LossScaler(mode='dynamic') + elif isinstance(loss_scale, float): + self.loss_scaler = LossScaler(init_scale=loss_scale, mode='static') + elif isinstance(loss_scale, dict): + self.loss_scaler = LossScaler(**loss_scale) + else: + raise ValueError('loss_scale must be of type float, dict, or ' + f'"dynamic", got {loss_scale}') + + def before_run(self, runner): + """Preparing steps before Mixed Precision Training. + + 1. Make a master copy of fp32 weights for optimization. + 2. Convert the main model from fp32 to fp16. + """ + # keep a copy of fp32 weights + old_groups = runner.optimizer.param_groups + runner.optimizer.param_groups = copy.deepcopy( + runner.optimizer.param_groups) + state = defaultdict(dict) + p_map = { + old_p: p + for old_p, p in zip( + chain(*(g['params'] for g in old_groups)), + chain(*(g['params'] for g in runner.optimizer.param_groups))) + } + for k, v in runner.optimizer.state.items(): + state[p_map[k]] = v + runner.optimizer.state = state + # convert model to fp16 + wrap_fp16_model(runner.model) + + def copy_grads_to_fp32(self, fp16_net, fp32_weights): + """Copy gradients from fp16 model to fp32 weight copy.""" + for fp32_param, fp16_param in zip(fp32_weights, fp16_net.parameters()): + if fp16_param.grad is not None: + if fp32_param.grad is None: + fp32_param.grad = fp32_param.data.new(fp32_param.size()) + fp32_param.grad.copy_(fp16_param.grad) + + def copy_params_to_fp16(self, fp16_net, fp32_weights): + """Copy updated params from fp32 weight copy to fp16 model.""" + for fp16_param, fp32_param in zip(fp16_net.parameters(), fp32_weights): + fp16_param.data.copy_(fp32_param.data) + + def after_train_iter(self, runner): + """Backward optimization steps for Mixed Precision Training. For + dynamic loss scaling, please refer `loss_scalar.py` + + 1. Scale the loss by a scale factor. + 2. Backward the loss to obtain the gradients (fp16). + 3. Copy gradients from the model to the fp32 weight copy. + 4. Scale the gradients back and update the fp32 weight copy. + 5. Copy back the params from fp32 weight copy to the fp16 model. + """ + # clear grads of last iteration + runner.model.zero_grad() + runner.optimizer.zero_grad() + # scale the loss value + scaled_loss = runner.outputs['loss'] * self.loss_scaler.loss_scale + scaled_loss.backward() + # copy fp16 grads in the model to fp32 params in the optimizer + + fp32_weights = [] + for param_group in runner.optimizer.param_groups: + fp32_weights += param_group['params'] + self.copy_grads_to_fp32(runner.model, fp32_weights) + # allreduce grads + if self.distributed: + allreduce_grads(fp32_weights, self.coalesce, self.bucket_size_mb) + + has_overflow = self.loss_scaler.has_overflow(fp32_weights) + # if has overflow, skip this iteration + if not has_overflow: + # scale the gradients back + for param in fp32_weights: + if param.grad is not None: + param.grad.div_(self.loss_scaler.loss_scale) + if self.grad_clip is not None: + grad_norm = self.clip_grads(fp32_weights) + if grad_norm is not None: + # Add grad norm to the logger + runner.log_buffer.update({'grad_norm': float(grad_norm)}, + runner.outputs['num_samples']) + # update fp32 params + runner.optimizer.step() + # copy fp32 params to the fp16 model + self.copy_params_to_fp16(runner.model, fp32_weights) + self.loss_scaler.update_scale(has_overflow) + if has_overflow: + runner.logger.warning('Check overflow, downscale loss scale ' + f'to {self.loss_scaler.cur_scale}') diff --git a/PyTorch/contrib/cv/video/C3D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_1p.py b/PyTorch/contrib/cv/video/C3D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_1p.py index a2efdbe743..f547576507 100644 --- a/PyTorch/contrib/cv/video/C3D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_1p.py +++ b/PyTorch/contrib/cv/video/C3D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_1p.py @@ -1,113 +1,113 @@ -# -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -_base_ = [ - '../../_base_/models/r2plus1d_r34.py', - '../../_base_/default_runtime.py' -] - -# dataset settings -dataset_type = 'RawframeDataset' -data_root = 'data/ucf101/rawframes/' -data_root_val = 'data/ucf101/rawframes/' -split = 1 # official train/test splits. valid numbers: 1, 2, 3 -ann_file_train = f'data/ucf101/ucf101_train_split_{split}_rawframes.txt' -ann_file_val = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' -ann_file_test = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' -img_norm_cfg = dict( - mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_bgr=False) -train_pipeline = [ - dict(type='SampleFrames', clip_len=8, frame_interval=8, num_clips=1), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='RandomResizedCrop'), - dict(type='Resize', scale=(224, 224), keep_ratio=False), - dict(type='Flip', flip_ratio=0.5), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs', 'label']) -] -val_pipeline = [ - dict( - type='SampleFrames', - clip_len=8, - frame_interval=8, - num_clips=1, - test_mode=True), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='CenterCrop', crop_size=224), - dict(type='Flip', flip_ratio=0), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs']) -] -test_pipeline = [ - dict( - type='SampleFrames', - clip_len=8, - frame_interval=8, - num_clips=10, - test_mode=True), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='ThreeCrop', crop_size=256), - dict(type='Flip', flip_ratio=0), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs']) -] -data = dict( - videos_per_gpu=16, - workers_per_gpu=4, - train=dict( - type=dataset_type, - ann_file=ann_file_train, - data_prefix=data_root, - pipeline=train_pipeline), - val=dict( - type=dataset_type, - ann_file=ann_file_val, - data_prefix=data_root_val, - pipeline=val_pipeline), - test=dict( - type=dataset_type, - ann_file=ann_file_val, - data_prefix=data_root_val, - pipeline=test_pipeline)) -# optimizer -optimizer = dict( - type='SGD', lr=0.0025, momentum=0.9, - weight_decay=0.0001) # this lr is used for 8 gpus -optimizer_config = dict(grad_clip=dict(max_norm=40, norm_type=2)) -# learning policy -# lr_config = dict(policy='step', steps=[1,2,3], lrs=[1e-3,1e-4,1e-5]) -lr_config = dict(policy='CosineAnnealing', min_lr=0) -total_epochs = 60 -# total_epochs = 90 - -# runtime settings -checkpoint_config = dict(interval=5) -evaluation = dict( - interval=5, metrics=['top_k_accuracy', 'mean_class_accuracy']) -#work_dir = './work_dirs/r2plus1d_r34_8x8x1_180e_ucf101_rgb3/' -find_unused_parameters = True -load_from = 'https://download.openmmlab.com/mmaction/recognition/r2plus1d/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb_20200729-aa94765e.pth' -resume_from = None - +# +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +_base_ = [ + '../../_base_/models/r2plus1d_r34.py', + '../../_base_/default_runtime.py' +] + +# dataset settings +dataset_type = 'RawframeDataset' +data_root = 'data/ucf101/rawframes/' +data_root_val = 'data/ucf101/rawframes/' +split = 1 # official train/test splits. valid numbers: 1, 2, 3 +ann_file_train = f'data/ucf101/ucf101_train_split_{split}_rawframes.txt' +ann_file_val = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' +ann_file_test = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' +img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_bgr=False) +train_pipeline = [ + dict(type='SampleFrames', clip_len=8, frame_interval=8, num_clips=1), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='RandomResizedCrop'), + dict(type='Resize', scale=(224, 224), keep_ratio=False), + dict(type='Flip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs', 'label']) +] +val_pipeline = [ + dict( + type='SampleFrames', + clip_len=8, + frame_interval=8, + num_clips=1, + test_mode=True), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='CenterCrop', crop_size=224), + dict(type='Flip', flip_ratio=0), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs']) +] +test_pipeline = [ + dict( + type='SampleFrames', + clip_len=8, + frame_interval=8, + num_clips=10, + test_mode=True), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='ThreeCrop', crop_size=256), + dict(type='Flip', flip_ratio=0), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs']) +] +data = dict( + videos_per_gpu=16, + workers_per_gpu=4, + train=dict( + type=dataset_type, + ann_file=ann_file_train, + data_prefix=data_root, + pipeline=train_pipeline), + val=dict( + type=dataset_type, + ann_file=ann_file_val, + data_prefix=data_root_val, + pipeline=val_pipeline), + test=dict( + type=dataset_type, + ann_file=ann_file_val, + data_prefix=data_root_val, + pipeline=test_pipeline)) +# optimizer +optimizer = dict( + type='SGD', lr=0.0025, momentum=0.9, + weight_decay=0.0001) # this lr is used for 8 gpus +optimizer_config = dict(grad_clip=dict(max_norm=40, norm_type=2)) +# learning policy +# lr_config = dict(policy='step', steps=[1,2,3], lrs=[1e-3,1e-4,1e-5]) +lr_config = dict(policy='CosineAnnealing', min_lr=0) +total_epochs = 60 +# total_epochs = 90 + +# runtime settings +checkpoint_config = dict(interval=5) +evaluation = dict( + interval=5, metrics=['top_k_accuracy', 'mean_class_accuracy']) +#work_dir = './work_dirs/r2plus1d_r34_8x8x1_180e_ucf101_rgb3/' +find_unused_parameters = True +load_from = 'https://download.openmmlab.com/mmaction/recognition/r2plus1d/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb_20200729-aa94765e.pth' +resume_from = None + work_dir = './work_dirs/r2plus1d-1p-npu/' \ No newline at end of file diff --git a/PyTorch/contrib/cv/video/C3D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_8p.py b/PyTorch/contrib/cv/video/C3D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_8p.py index 7afb668be6..7f68a5166d 100644 --- a/PyTorch/contrib/cv/video/C3D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_8p.py +++ b/PyTorch/contrib/cv/video/C3D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_8p.py @@ -1,113 +1,113 @@ -# -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -_base_ = [ - '../../_base_/models/r2plus1d_r34.py', - '../../_base_/default_runtime.py' -] - -# dataset settings -dataset_type = 'RawframeDataset' -data_root = '/home/linus/rawframes/' -data_root_val = '/home/linus/rawframes/' -split = 1 # official train/test splits. valid numbers: 1, 2, 3 -ann_file_train = f'data/ucf101/ucf101_train_split_{split}_rawframes.txt' -ann_file_val = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' -ann_file_test = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' -img_norm_cfg = dict( - mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_bgr=False) -train_pipeline = [ - dict(type='SampleFrames', clip_len=8, frame_interval=8, num_clips=1), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='RandomResizedCrop'), - dict(type='Resize', scale=(224, 224), keep_ratio=False), - dict(type='Flip', flip_ratio=0.5), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs', 'label']) -] -val_pipeline = [ - dict( - type='SampleFrames', - clip_len=8, - frame_interval=8, - num_clips=1, - test_mode=True), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='CenterCrop', crop_size=224), - dict(type='Flip', flip_ratio=0), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs']) -] -test_pipeline = [ - dict( - type='SampleFrames', - clip_len=8, - frame_interval=8, - num_clips=10, - test_mode=True), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='ThreeCrop', crop_size=256), - dict(type='Flip', flip_ratio=0), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs']) -] -data = dict( - videos_per_gpu=42, - workers_per_gpu=4, - train=dict( - type=dataset_type, - ann_file=ann_file_train, - data_prefix=data_root, - pipeline=train_pipeline), - val=dict( - type=dataset_type, - ann_file=ann_file_val, - data_prefix=data_root_val, - pipeline=val_pipeline), - test=dict( - type=dataset_type, - ann_file=ann_file_val, - data_prefix=data_root_val, - pipeline=test_pipeline)) -# optimizer -optimizer = dict( - type='SGD', lr=0.008, momentum=0.9, - weight_decay=0.0001) # this lr is used for 8 gpus -optimizer_config = dict(grad_clip=dict(max_norm=40, norm_type=2)) -# learning policy -# lr_config = dict(policy='step', teps=[1,2,3], lrs=[1e-3,1e-4,1e-5]) -lr_config = dict(policy='CosineAnnealing', min_lr=0) -total_epochs = 70 -# total_epochs = 90 - -# runtime settings -checkpoint_config = dict(interval=5) -evaluation = dict( - interval=5, metrics=['top_k_accuracy', 'mean_class_accuracy']) -#work_dir = './work_dirs/r2plus1d_r34_8x8x1_180e_ucf101_rgb3/' -find_unused_parameters = True -load_from = 'https://download.openmmlab.com/mmaction/recognition/r2plus1d/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb_20200729-aa94765e.pth' -resume_from = None - +# +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +_base_ = [ + '../../_base_/models/r2plus1d_r34.py', + '../../_base_/default_runtime.py' +] + +# dataset settings +dataset_type = 'RawframeDataset' +data_root = '/home/linus/rawframes/' +data_root_val = '/home/linus/rawframes/' +split = 1 # official train/test splits. valid numbers: 1, 2, 3 +ann_file_train = f'data/ucf101/ucf101_train_split_{split}_rawframes.txt' +ann_file_val = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' +ann_file_test = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' +img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_bgr=False) +train_pipeline = [ + dict(type='SampleFrames', clip_len=8, frame_interval=8, num_clips=1), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='RandomResizedCrop'), + dict(type='Resize', scale=(224, 224), keep_ratio=False), + dict(type='Flip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs', 'label']) +] +val_pipeline = [ + dict( + type='SampleFrames', + clip_len=8, + frame_interval=8, + num_clips=1, + test_mode=True), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='CenterCrop', crop_size=224), + dict(type='Flip', flip_ratio=0), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs']) +] +test_pipeline = [ + dict( + type='SampleFrames', + clip_len=8, + frame_interval=8, + num_clips=10, + test_mode=True), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='ThreeCrop', crop_size=256), + dict(type='Flip', flip_ratio=0), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs']) +] +data = dict( + videos_per_gpu=42, + workers_per_gpu=4, + train=dict( + type=dataset_type, + ann_file=ann_file_train, + data_prefix=data_root, + pipeline=train_pipeline), + val=dict( + type=dataset_type, + ann_file=ann_file_val, + data_prefix=data_root_val, + pipeline=val_pipeline), + test=dict( + type=dataset_type, + ann_file=ann_file_val, + data_prefix=data_root_val, + pipeline=test_pipeline)) +# optimizer +optimizer = dict( + type='SGD', lr=0.008, momentum=0.9, + weight_decay=0.0001) # this lr is used for 8 gpus +optimizer_config = dict(grad_clip=dict(max_norm=40, norm_type=2)) +# learning policy +# lr_config = dict(policy='step', teps=[1,2,3], lrs=[1e-3,1e-4,1e-5]) +lr_config = dict(policy='CosineAnnealing', min_lr=0) +total_epochs = 70 +# total_epochs = 90 + +# runtime settings +checkpoint_config = dict(interval=5) +evaluation = dict( + interval=5, metrics=['top_k_accuracy', 'mean_class_accuracy']) +#work_dir = './work_dirs/r2plus1d_r34_8x8x1_180e_ucf101_rgb3/' +find_unused_parameters = True +load_from = 'https://download.openmmlab.com/mmaction/recognition/r2plus1d/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb_20200729-aa94765e.pth' +resume_from = None + work_dir = './work_dirs/r2plus1d-8p-npu/' diff --git a/PyTorch/contrib/cv/video/C3D/tools/dist_train.sh b/PyTorch/contrib/cv/video/C3D/tools/dist_train.sh old mode 100755 new mode 100644 diff --git a/PyTorch/contrib/cv/video/GloRe/README.md b/PyTorch/contrib/cv/video/GloRe/README.md index f26ecfaec3..3b6e55924a 100644 --- a/PyTorch/contrib/cv/video/GloRe/README.md +++ b/PyTorch/contrib/cv/video/GloRe/README.md @@ -1,50 +1,50 @@ -# GloRe 训练 -# Graph-Based Global Reasoning Networks -This implements training of GloRe on the UCF-101 dataset. -- Reference implementation: -``` -url=https: https://github.com/facebookresearch/GloRe -``` - -## GloRe Detail # - -As of the current date, Ascend-Pytorch is still inefficient for contiguous operations. -Therefore, GloRe is re-implemented using semantics such as custom OP. - - -## Requirements # - -- Install PyTorch ([pytorch.org](http://pytorch.org)) -- `pip install -r requirements.txt` -- The UCF-101 Dataset can be downloaded from the links below.Move the datasets to directory ./dataset/UCF101/raw/data . - - Train Set : [Download UCF-101](https://www.crcv.ucf.edu/data/UCF101/UCF101.rar) - - Test Set : [Download UCF-101](https://www.crcv.ucf.edu/data/UCF101/UCF101.rar) -- The pretrained model can be downloaded from the links below. Move the datasets to directory ./network/pretrain . - - Pretrained model : [Download pth](https://dl.fbaipublicfiles.com/glore/kinetics/resnet50-lite_3d_8x8_w-glore_2-3_ep-0000.pth). Create directory ./network/pretrained/ and place pretrained model under directory ./network/pretrained/ - -## Training # -To train a model, run `train_kinetics.py`: - -```bash -# 1p train perf -bash test/train_performance_1p.sh - -# 8p train perf -bash test/train_performance_8p.sh - -# 8p train full -bash test/train_full_8p.sh - -# finetuning -bash test/train_finetune_1p.sh -``` - -## GloRe training result # - -| ACC@1 | FPS | Npu_nums | Epochs | AMP_Type | -| :------: | :------: | :------: | :------: | :------: | -| - | 11.647 | 1 | 90 | O2 | -| 92.39 | 141.31 | 8 | 90 | O2 | - - - +# GloRe 训练 +# Graph-Based Global Reasoning Networks +This implements training of GloRe on the UCF-101 dataset. +- Reference implementation: +``` +url=https: https://github.com/facebookresearch/GloRe +``` + +## GloRe Detail # + +As of the current date, Ascend-Pytorch is still inefficient for contiguous operations. +Therefore, GloRe is re-implemented using semantics such as custom OP. + + +## Requirements # + +- Install PyTorch ([pytorch.org](http://pytorch.org)) +- `pip install -r requirements.txt` +- The UCF-101 Dataset can be downloaded from the links below.Move the datasets to directory ./dataset/UCF101/raw/data . + - Train Set : [Download UCF-101](https://www.crcv.ucf.edu/data/UCF101/UCF101.rar) + - Test Set : [Download UCF-101](https://www.crcv.ucf.edu/data/UCF101/UCF101.rar) +- The pretrained model can be downloaded from the links below. Move the datasets to directory ./network/pretrain . + - Pretrained model : [Download pth](https://dl.fbaipublicfiles.com/glore/kinetics/resnet50-lite_3d_8x8_w-glore_2-3_ep-0000.pth). Create directory ./network/pretrained/ and place pretrained model under directory ./network/pretrained/ + +## Training # +To train a model, run `train_kinetics.py`: + +```bash +# 1p train perf +bash test/train_performance_1p.sh + +# 8p train perf +bash test/train_performance_8p.sh + +# 8p train full +bash test/train_full_8p.sh + +# finetuning +bash test/train_finetune_1p.sh +``` + +## GloRe training result # + +| ACC@1 | FPS | Npu_nums | Epochs | AMP_Type | +| :------: | :------: | :------: | :------: | :------: | +| - | 11.647 | 1 | 90 | O2 | +| 92.39 | 141.31 | 8 | 90 | O2 | + + + diff --git a/PyTorch/contrib/cv/video/GloRe/modelzoo_level.txt b/PyTorch/contrib/cv/video/GloRe/modelzoo_level.txt index a17c8f95fa..a829ab59b9 100644 --- a/PyTorch/contrib/cv/video/GloRe/modelzoo_level.txt +++ b/PyTorch/contrib/cv/video/GloRe/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:NOK +FuncStatus:OK +PerfStatus:NOK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/video/NonLocal/config/default_runtime.py b/PyTorch/contrib/cv/video/NonLocal/config/default_runtime.py index 41329bf371..7652836b33 100644 --- a/PyTorch/contrib/cv/video/NonLocal/config/default_runtime.py +++ b/PyTorch/contrib/cv/video/NonLocal/config/default_runtime.py @@ -1,27 +1,27 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ -checkpoint_config = dict(interval=5) -log_config = dict( - interval=1, - hooks=[ - dict(type='TextLoggerHook'), - # dict(type='TensorboardLoggerHook'), - ]) -# runtime settings -dist_params = dict(backend='nccl') -log_level = 'INFO' -load_from = None -resume_from = None -workflow = [('train', 1)] +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +checkpoint_config = dict(interval=5) +log_config = dict( + interval=1, + hooks=[ + dict(type='TextLoggerHook'), + # dict(type='TensorboardLoggerHook'), + ]) +# runtime settings +dist_params = dict(backend='nccl') +log_level = 'INFO' +load_from = None +resume_from = None +workflow = [('train', 1)] diff --git a/PyTorch/contrib/cv/video/NonLocal/config/tsm_r50.py b/PyTorch/contrib/cv/video/NonLocal/config/tsm_r50.py index d7124c2e44..6015b73cb2 100644 --- a/PyTorch/contrib/cv/video/NonLocal/config/tsm_r50.py +++ b/PyTorch/contrib/cv/video/NonLocal/config/tsm_r50.py @@ -1,35 +1,35 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ -# model settings -model = dict( - type='Recognizer2D', - backbone=dict( - type='ResNetTSM', - pretrained='torchvision://resnet50', - depth=50, - norm_eval=False, - shift_div=8), - cls_head=dict( - type='TSMHead', - num_classes=400, - in_channels=2048, - spatial_type='avg', - consensus=dict(type='AvgConsensus', dim=1), - dropout_ratio=0.5, - init_std=0.001, - is_shift=True), - # model training and testing settings - train_cfg=None, - test_cfg=dict(average_clips='prob')) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +# model settings +model = dict( + type='Recognizer2D', + backbone=dict( + type='ResNetTSM', + pretrained='torchvision://resnet50', + depth=50, + norm_eval=False, + shift_div=8), + cls_head=dict( + type='TSMHead', + num_classes=400, + in_channels=2048, + spatial_type='avg', + consensus=dict(type='AvgConsensus', dim=1), + dropout_ratio=0.5, + init_std=0.001, + is_shift=True), + # model training and testing settings + train_cfg=None, + test_cfg=dict(average_clips='prob')) diff --git a/PyTorch/contrib/cv/video/NonLocal/mmaction/apis/train.py b/PyTorch/contrib/cv/video/NonLocal/mmaction/apis/train.py index 59f1bc0a8a..d50c7f7e6a 100644 --- a/PyTorch/contrib/cv/video/NonLocal/mmaction/apis/train.py +++ b/PyTorch/contrib/cv/video/NonLocal/mmaction/apis/train.py @@ -1,267 +1,267 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 copy as cp -import os.path as osp - -from apex import amp - -import torch -from mmcv.parallel import MMDataParallel, MMDistributedDataParallel -from mmcv.runner import (DistSamplerSeedHook, EpochBasedRunner, OptimizerHook, - build_optimizer, get_dist_info) -from mmcv.runner.hooks import Fp16OptimizerHook - -from ..core import (DistEvalHook, EvalHook, OmniSourceDistSamplerSeedHook, - OmniSourceRunner) -from ..datasets import build_dataloader, build_dataset -from ..utils import PreciseBNHook, get_root_logger -from .test import multi_gpu_test - - -def train_model(model, - dataset, - cfg, - distributed=False, - validate=False, - test=dict(test_best=False, test_last=False), - timestamp=None, - meta=None): - """Train model entry function. - - Args: - model (nn.Module): The model to be trained. - dataset (:obj:`Dataset`): Train dataset. - cfg (dict): The config dict for training. - distributed (bool): Whether to use distributed training. - Default: False. - validate (bool): Whether to do evaluation. Default: False. - test (dict): The testing option, with two keys: test_last & test_best. - The value is True or False, indicating whether to test the - corresponding checkpoint. - Default: dict(test_best=False, test_last=False). - timestamp (str | None): Local time for runner. Default: None. - meta (dict | None): Meta dict to record some important information. - Default: None - """ - logger = get_root_logger(log_level=cfg.log_level) - - # prepare data loaders - dataset = dataset if isinstance(dataset, (list, tuple)) else [dataset] - - dataloader_setting = dict(videos_per_gpu=cfg.data.get('videos_per_gpu', 1), - workers_per_gpu=cfg.data.get( - 'workers_per_gpu', 1), - num_gpus=len(cfg.gpu_ids), - dist=distributed, - seed=cfg.seed) - dataloader_setting = dict(dataloader_setting, - **cfg.data.get('train_dataloader', {})) - - if cfg.omnisource: - # The option can override videos_per_gpu - train_ratio = cfg.data.get('train_ratio', [1] * len(dataset)) - omni_videos_per_gpu = cfg.data.get('omni_videos_per_gpu', None) - if omni_videos_per_gpu is None: - dataloader_settings = [dataloader_setting] * len(dataset) - else: - dataloader_settings = [] - for videos_per_gpu in omni_videos_per_gpu: - this_setting = cp.deepcopy(dataloader_setting) - this_setting['videos_per_gpu'] = videos_per_gpu - dataloader_settings.append(this_setting) - data_loaders = [ - build_dataloader(ds, **setting) - for ds, setting in zip(dataset, dataloader_settings) - ] - - else: - data_loaders = [ - build_dataloader(ds, **dataloader_setting) for ds in dataset - ] - - # build runner - optimizer = build_optimizer(model, cfg.optimizer) - - # Allow Amp to perform casts as required by the opt_level - if cfg.AMP: - # model, optimizer = amp.initialize(model.cuda(), - # optimizer, - # opt_level=cfg.OPT_LEVEL, - # loss_scale=cfg.LOSS_SCALE) - model, optimizer = amp.initialize(model.npu(), - optimizer, - opt_level=cfg.OPT_LEVEL, - loss_scale=cfg.LOSS_SCALE, - combine_grad=True) - - # put model on gpus - if distributed: - find_unused_parameters = cfg.get('find_unused_parameters', False) - # Sets the `find_unused_parameters` parameter in - # torch.nn.parallel.DistributedDataParallel - model = MMDistributedDataParallel( - model, - device_ids=[torch.npu.current_device()], - broadcast_buffers=False, - find_unused_parameters=find_unused_parameters) - # model = MMDistributedDataParallel( - # model, - # device_ids=[torch.cuda.current_device()], - # broadcast_buffers=False, - # find_unused_parameters=find_unused_parameters) - - else: - # In 1-p training, we don't use Dataparallel - # model = MMDataParallel(model.cuda(cfg.gpu_ids[0]), - # device_ids=cfg.gpu_ids) - model = model.npu() - - Runner = OmniSourceRunner if cfg.omnisource else EpochBasedRunner - runner = Runner(model, - optimizer=optimizer, - work_dir=cfg.work_dir, - logger=logger, - meta=meta, - distributed=distributed) - # an ugly workaround to make .log and .log.json filenames the same - runner.timestamp = timestamp - - # fp16 setting - fp16_cfg = cfg.get('fp16', None) - if fp16_cfg is not None: - optimizer_config = Fp16OptimizerHook(**cfg.optimizer_config, - **fp16_cfg, - distributed=distributed) - elif distributed and 'type' not in cfg.optimizer_config: - optimizer_config = OptimizerHook(**cfg.optimizer_config) - else: - optimizer_config = cfg.optimizer_config - - # register hooks - runner.register_training_hooks(cfg.lr_config, optimizer_config, - cfg.checkpoint_config, cfg.log_config, - cfg.get('momentum_config', None)) - if distributed: - if cfg.omnisource: - runner.register_hook(OmniSourceDistSamplerSeedHook()) - else: - runner.register_hook(DistSamplerSeedHook()) - - # precise bn setting - if cfg.get('precise_bn', False): - precise_bn_dataset = build_dataset(cfg.data.train) - dataloader_setting = dict( - videos_per_gpu=cfg.data.get('videos_per_gpu', 1), - workers_per_gpu=0, # save memory and time - num_gpus=len(cfg.gpu_ids), - dist=distributed, - seed=cfg.seed) - data_loader_precise_bn = build_dataloader(precise_bn_dataset, - **dataloader_setting) - precise_bn_hook = PreciseBNHook(data_loader_precise_bn, - **cfg.get('precise_bn')) - runner.register_hook(precise_bn_hook) - - if validate: - eval_cfg = cfg.get('evaluation', {}) - val_dataset = build_dataset(cfg.data.val, dict(test_mode=True)) - dataloader_setting = dict( - videos_per_gpu=cfg.data.get('videos_per_gpu', 1), - workers_per_gpu=cfg.data.get('workers_per_gpu', 1), - # cfg.gpus will be ignored if distributed - num_gpus=len(cfg.gpu_ids), - dist=distributed, - shuffle=False) - dataloader_setting = dict(dataloader_setting, - **cfg.data.get('val_dataloader', {})) - val_dataloader = build_dataloader(val_dataset, **dataloader_setting) - eval_hook = DistEvalHook(val_dataloader, **eval_cfg) if distributed \ - else EvalHook(val_dataloader, **eval_cfg) - runner.register_hook(eval_hook) - - if cfg.resume_from: - runner.resume(cfg.resume_from) - elif cfg.load_from: - runner.load_checkpoint(cfg.load_from) - runner_kwargs = dict() - if cfg.omnisource: - runner_kwargs = dict(train_ratio=train_ratio) - runner.run(data_loaders, cfg.workflow, cfg.total_epochs, **runner_kwargs) - - if test['test_last'] or test['test_best']: - best_ckpt_path = None - if test['test_best']: - if hasattr(eval_hook, 'best_ckpt_path'): - best_ckpt_path = eval_hook.best_ckpt_path - - if best_ckpt_path is None or not osp.exists(best_ckpt_path): - test['test_best'] = False - if best_ckpt_path is None: - runner.logger.info('Warning: test_best set as True, but ' - 'is not applicable ' - '(eval_hook.best_ckpt_path is None)') - else: - runner.logger.info('Warning: test_best set as True, but ' - 'is not applicable (best_ckpt ' - f'{best_ckpt_path} not found)') - if not test['test_last']: - return - - test_dataset = build_dataset(cfg.data.test, dict(test_mode=True)) - gpu_collect = cfg.get('evaluation', {}).get('gpu_collect', False) - tmpdir = cfg.get('evaluation', {}).get('tmpdir', - osp.join(cfg.work_dir, 'tmp')) - dataloader_setting = dict( - videos_per_gpu=cfg.data.get('videos_per_gpu', 1), - workers_per_gpu=cfg.data.get('workers_per_gpu', 1), - num_gpus=len(cfg.gpu_ids), - dist=distributed, - shuffle=False) - dataloader_setting = dict(dataloader_setting, - **cfg.data.get('test_dataloader', {})) - - test_dataloader = build_dataloader(test_dataset, **dataloader_setting) - - names, ckpts = [], [] - - if test['test_last']: - names.append('last') - ckpts.append(None) - if test['test_best']: - names.append('best') - ckpts.append(best_ckpt_path) - - for name, ckpt in zip(names, ckpts): - if ckpt is not None: - runner.load_checkpoint(ckpt) - - outputs = multi_gpu_test(runner.model, test_dataloader, tmpdir, - gpu_collect) - rank, _ = get_dist_info() - if rank == 0: - out = osp.join(cfg.work_dir, f'{name}_pred.pkl') - test_dataset.dump_results(outputs, out) - - eval_cfg = cfg.get('evaluation', {}) - for key in [ - 'interval', 'tmpdir', 'start', 'gpu_collect', - 'save_best', 'rule', 'by_epoch', 'broadcast_bn_buffers' - ]: - eval_cfg.pop(key, None) - - eval_res = test_dataset.evaluate(outputs, **eval_cfg) - runner.logger.info(f'Testing results of the {name} checkpoint') - for metric_name, val in eval_res.items(): - runner.logger.info(f'{metric_name}: {val:.04f}') +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 copy as cp +import os.path as osp + +from apex import amp + +import torch +from mmcv.parallel import MMDataParallel, MMDistributedDataParallel +from mmcv.runner import (DistSamplerSeedHook, EpochBasedRunner, OptimizerHook, + build_optimizer, get_dist_info) +from mmcv.runner.hooks import Fp16OptimizerHook + +from ..core import (DistEvalHook, EvalHook, OmniSourceDistSamplerSeedHook, + OmniSourceRunner) +from ..datasets import build_dataloader, build_dataset +from ..utils import PreciseBNHook, get_root_logger +from .test import multi_gpu_test + + +def train_model(model, + dataset, + cfg, + distributed=False, + validate=False, + test=dict(test_best=False, test_last=False), + timestamp=None, + meta=None): + """Train model entry function. + + Args: + model (nn.Module): The model to be trained. + dataset (:obj:`Dataset`): Train dataset. + cfg (dict): The config dict for training. + distributed (bool): Whether to use distributed training. + Default: False. + validate (bool): Whether to do evaluation. Default: False. + test (dict): The testing option, with two keys: test_last & test_best. + The value is True or False, indicating whether to test the + corresponding checkpoint. + Default: dict(test_best=False, test_last=False). + timestamp (str | None): Local time for runner. Default: None. + meta (dict | None): Meta dict to record some important information. + Default: None + """ + logger = get_root_logger(log_level=cfg.log_level) + + # prepare data loaders + dataset = dataset if isinstance(dataset, (list, tuple)) else [dataset] + + dataloader_setting = dict(videos_per_gpu=cfg.data.get('videos_per_gpu', 1), + workers_per_gpu=cfg.data.get( + 'workers_per_gpu', 1), + num_gpus=len(cfg.gpu_ids), + dist=distributed, + seed=cfg.seed) + dataloader_setting = dict(dataloader_setting, + **cfg.data.get('train_dataloader', {})) + + if cfg.omnisource: + # The option can override videos_per_gpu + train_ratio = cfg.data.get('train_ratio', [1] * len(dataset)) + omni_videos_per_gpu = cfg.data.get('omni_videos_per_gpu', None) + if omni_videos_per_gpu is None: + dataloader_settings = [dataloader_setting] * len(dataset) + else: + dataloader_settings = [] + for videos_per_gpu in omni_videos_per_gpu: + this_setting = cp.deepcopy(dataloader_setting) + this_setting['videos_per_gpu'] = videos_per_gpu + dataloader_settings.append(this_setting) + data_loaders = [ + build_dataloader(ds, **setting) + for ds, setting in zip(dataset, dataloader_settings) + ] + + else: + data_loaders = [ + build_dataloader(ds, **dataloader_setting) for ds in dataset + ] + + # build runner + optimizer = build_optimizer(model, cfg.optimizer) + + # Allow Amp to perform casts as required by the opt_level + if cfg.AMP: + # model, optimizer = amp.initialize(model.cuda(), + # optimizer, + # opt_level=cfg.OPT_LEVEL, + # loss_scale=cfg.LOSS_SCALE) + model, optimizer = amp.initialize(model.npu(), + optimizer, + opt_level=cfg.OPT_LEVEL, + loss_scale=cfg.LOSS_SCALE, + combine_grad=True) + + # put model on gpus + if distributed: + find_unused_parameters = cfg.get('find_unused_parameters', False) + # Sets the `find_unused_parameters` parameter in + # torch.nn.parallel.DistributedDataParallel + model = MMDistributedDataParallel( + model, + device_ids=[torch.npu.current_device()], + broadcast_buffers=False, + find_unused_parameters=find_unused_parameters) + # model = MMDistributedDataParallel( + # model, + # device_ids=[torch.cuda.current_device()], + # broadcast_buffers=False, + # find_unused_parameters=find_unused_parameters) + + else: + # In 1-p training, we don't use Dataparallel + # model = MMDataParallel(model.cuda(cfg.gpu_ids[0]), + # device_ids=cfg.gpu_ids) + model = model.npu() + + Runner = OmniSourceRunner if cfg.omnisource else EpochBasedRunner + runner = Runner(model, + optimizer=optimizer, + work_dir=cfg.work_dir, + logger=logger, + meta=meta, + distributed=distributed) + # an ugly workaround to make .log and .log.json filenames the same + runner.timestamp = timestamp + + # fp16 setting + fp16_cfg = cfg.get('fp16', None) + if fp16_cfg is not None: + optimizer_config = Fp16OptimizerHook(**cfg.optimizer_config, + **fp16_cfg, + distributed=distributed) + elif distributed and 'type' not in cfg.optimizer_config: + optimizer_config = OptimizerHook(**cfg.optimizer_config) + else: + optimizer_config = cfg.optimizer_config + + # register hooks + runner.register_training_hooks(cfg.lr_config, optimizer_config, + cfg.checkpoint_config, cfg.log_config, + cfg.get('momentum_config', None)) + if distributed: + if cfg.omnisource: + runner.register_hook(OmniSourceDistSamplerSeedHook()) + else: + runner.register_hook(DistSamplerSeedHook()) + + # precise bn setting + if cfg.get('precise_bn', False): + precise_bn_dataset = build_dataset(cfg.data.train) + dataloader_setting = dict( + videos_per_gpu=cfg.data.get('videos_per_gpu', 1), + workers_per_gpu=0, # save memory and time + num_gpus=len(cfg.gpu_ids), + dist=distributed, + seed=cfg.seed) + data_loader_precise_bn = build_dataloader(precise_bn_dataset, + **dataloader_setting) + precise_bn_hook = PreciseBNHook(data_loader_precise_bn, + **cfg.get('precise_bn')) + runner.register_hook(precise_bn_hook) + + if validate: + eval_cfg = cfg.get('evaluation', {}) + val_dataset = build_dataset(cfg.data.val, dict(test_mode=True)) + dataloader_setting = dict( + videos_per_gpu=cfg.data.get('videos_per_gpu', 1), + workers_per_gpu=cfg.data.get('workers_per_gpu', 1), + # cfg.gpus will be ignored if distributed + num_gpus=len(cfg.gpu_ids), + dist=distributed, + shuffle=False) + dataloader_setting = dict(dataloader_setting, + **cfg.data.get('val_dataloader', {})) + val_dataloader = build_dataloader(val_dataset, **dataloader_setting) + eval_hook = DistEvalHook(val_dataloader, **eval_cfg) if distributed \ + else EvalHook(val_dataloader, **eval_cfg) + runner.register_hook(eval_hook) + + if cfg.resume_from: + runner.resume(cfg.resume_from) + elif cfg.load_from: + runner.load_checkpoint(cfg.load_from) + runner_kwargs = dict() + if cfg.omnisource: + runner_kwargs = dict(train_ratio=train_ratio) + runner.run(data_loaders, cfg.workflow, cfg.total_epochs, **runner_kwargs) + + if test['test_last'] or test['test_best']: + best_ckpt_path = None + if test['test_best']: + if hasattr(eval_hook, 'best_ckpt_path'): + best_ckpt_path = eval_hook.best_ckpt_path + + if best_ckpt_path is None or not osp.exists(best_ckpt_path): + test['test_best'] = False + if best_ckpt_path is None: + runner.logger.info('Warning: test_best set as True, but ' + 'is not applicable ' + '(eval_hook.best_ckpt_path is None)') + else: + runner.logger.info('Warning: test_best set as True, but ' + 'is not applicable (best_ckpt ' + f'{best_ckpt_path} not found)') + if not test['test_last']: + return + + test_dataset = build_dataset(cfg.data.test, dict(test_mode=True)) + gpu_collect = cfg.get('evaluation', {}).get('gpu_collect', False) + tmpdir = cfg.get('evaluation', {}).get('tmpdir', + osp.join(cfg.work_dir, 'tmp')) + dataloader_setting = dict( + videos_per_gpu=cfg.data.get('videos_per_gpu', 1), + workers_per_gpu=cfg.data.get('workers_per_gpu', 1), + num_gpus=len(cfg.gpu_ids), + dist=distributed, + shuffle=False) + dataloader_setting = dict(dataloader_setting, + **cfg.data.get('test_dataloader', {})) + + test_dataloader = build_dataloader(test_dataset, **dataloader_setting) + + names, ckpts = [], [] + + if test['test_last']: + names.append('last') + ckpts.append(None) + if test['test_best']: + names.append('best') + ckpts.append(best_ckpt_path) + + for name, ckpt in zip(names, ckpts): + if ckpt is not None: + runner.load_checkpoint(ckpt) + + outputs = multi_gpu_test(runner.model, test_dataloader, tmpdir, + gpu_collect) + rank, _ = get_dist_info() + if rank == 0: + out = osp.join(cfg.work_dir, f'{name}_pred.pkl') + test_dataset.dump_results(outputs, out) + + eval_cfg = cfg.get('evaluation', {}) + for key in [ + 'interval', 'tmpdir', 'start', 'gpu_collect', + 'save_best', 'rule', 'by_epoch', 'broadcast_bn_buffers' + ]: + eval_cfg.pop(key, None) + + eval_res = test_dataset.evaluate(outputs, **eval_cfg) + runner.logger.info(f'Testing results of the {name} checkpoint') + for metric_name, val in eval_res.items(): + runner.logger.info(f'{metric_name}: {val:.04f}') diff --git a/PyTorch/contrib/cv/video/NonLocal/mmaction/datasets/pipelines/formating.py b/PyTorch/contrib/cv/video/NonLocal/mmaction/datasets/pipelines/formating.py index a7d0876a04..3811c61add 100644 --- a/PyTorch/contrib/cv/video/NonLocal/mmaction/datasets/pipelines/formating.py +++ b/PyTorch/contrib/cv/video/NonLocal/mmaction/datasets/pipelines/formating.py @@ -1,378 +1,378 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 collections.abc import Sequence - -import mmcv -import numpy as np -import torch -from mmcv.parallel import DataContainer as DC - -from ..builder import PIPELINES - - -def to_tensor(data): - """Convert objects of various python types to :obj:`torch.Tensor`. - - Supported types are: :class:`numpy.ndarray`, :class:`torch.Tensor`, - :class:`Sequence`, :class:`int` and :class:`float`. - """ - if isinstance(data, torch.Tensor): - return data - if isinstance(data, np.ndarray): - return torch.from_numpy(data) - if isinstance(data, Sequence) and not mmcv.is_str(data): - return torch.tensor(data) - if isinstance(data, int): - return torch.LongTensor([data]) - if isinstance(data, float): - return torch.FloatTensor([data]) - raise TypeError(f'type {type(data)} cannot be converted to tensor.') - - -@PIPELINES.register_module() -class ToTensor: - """Convert some values in results dict to `torch.Tensor` type in data - loader pipeline. - - Args: - keys (Sequence[str]): Required keys to be converted. - """ - def __init__(self, keys): - self.keys = keys - - def __call__(self, results): - """Performs the ToTensor formating. - - Args: - results (dict): The resulting dict to be modified and passed - to the next transform in pipeline. - """ - for key in self.keys: - results[key] = to_tensor(results[key]) - return results - - def __repr__(self): - return f'{self.__class__.__name__}(keys={self.keys})' - - -@PIPELINES.register_module() -class Rename: - """Rename the key in results. - - Args: - mapping (dict): The keys in results that need to be renamed. The key of - the dict is the original name, while the value is the new name. If - the original name not found in results, do nothing. - Default: dict(). - """ - def __init__(self, mapping): - self.mapping = mapping - - def __call__(self, results): - for key, value in self.mapping.items(): - if key in results: - assert isinstance(key, str) and isinstance(value, str) - assert value not in results, ('the new name already exists in ' - 'results') - results[value] = results[key] - results.pop(key) - return results - - -@PIPELINES.register_module() -class ToDataContainer: - """Convert the data to DataContainer. - - Args: - fields (Sequence[dict]): Required fields to be converted - with keys and attributes. E.g. - fields=(dict(key='gt_bbox', stack=False),). - Note that key can also be a list of keys, if so, every tensor in - the list will be converted to DataContainer. - """ - def __init__(self, fields): - self.fields = fields - - def __call__(self, results): - """Performs the ToDataContainer formating. - - Args: - results (dict): The resulting dict to be modified and passed - to the next transform in pipeline. - """ - for field in self.fields: - _field = field.copy() - key = _field.pop('key') - if isinstance(key, list): - for item in key: - results[item] = DC(results[item], **_field) - else: - results[key] = DC(results[key], **_field) - return results - - def __repr__(self): - return self.__class__.__name__ + f'(fields={self.fields})' - - -@PIPELINES.register_module() -class ImageToTensor: - """Convert image type to `torch.Tensor` type. - - Args: - keys (Sequence[str]): Required keys to be converted. - """ - def __init__(self, keys): - self.keys = keys - - def __call__(self, results): - """Performs the ImageToTensor formating. - - Args: - results (dict): The resulting dict to be modified and passed - to the next transform in pipeline. - """ - for key in self.keys: - results[key] = to_tensor(results[key].transpose(2, 0, 1)) - return results - - def __repr__(self): - return f'{self.__class__.__name__}(keys={self.keys})' - - -@PIPELINES.register_module() -class Transpose: - """Transpose image channels to a given order. - - Args: - keys (Sequence[str]): Required keys to be converted. - order (Sequence[int]): Image channel order. - """ - def __init__(self, keys, order): - self.keys = keys - self.order = order - - def __call__(self, results): - """Performs the Transpose formatting. - - Args: - results (dict): The resulting dict to be modified and passed - to the next transform in pipeline. - """ - for key in self.keys: - results[key] = results[key].transpose(self.order) - return results - - def __repr__(self): - return (f'{self.__class__.__name__}(' - f'keys={self.keys}, order={self.order})') - - -@PIPELINES.register_module() -class Collect: - """Collect data from the loader relevant to the specific task. - - This keeps the items in ``keys`` as it is, and collect items in - ``meta_keys`` into a meta item called ``meta_name``.This is usually - the last stage of the data loader pipeline. - For example, when keys='imgs', meta_keys=('filename', 'label', - 'original_shape'), meta_name='img_metas', the results will be a dict with - keys 'imgs' and 'img_metas', where 'img_metas' is a DataContainer of - another dict with keys 'filename', 'label', 'original_shape'. - - Args: - keys (Sequence[str]): Required keys to be collected. - meta_name (str): The name of the key that contains meta infomation. - This key is always populated. Default: "img_metas". - meta_keys (Sequence[str]): Keys that are collected under meta_name. - The contents of the ``meta_name`` dictionary depends on - ``meta_keys``. - By default this includes: - - - "filename": path to the image file - - "label": label of the image file - - "original_shape": original shape of the image as a tuple - (h, w, c) - - "img_shape": shape of the image input to the network as a tuple - (h, w, c). Note that images may be zero padded on the - bottom/right, if the batch tensor is larger than this shape. - - "pad_shape": image shape after padding - - "flip_direction": a str in ("horiziontal", "vertival") to - indicate if the image is fliped horizontally or vertically. - - "img_norm_cfg": a dict of normalization information: - - mean - per channel mean subtraction - - std - per channel std divisor - - to_rgb - bool indicating if bgr was converted to rgb - nested (bool): If set as True, will apply data[x] = [data[x]] to all - items in data. The arg is added for compatibility. Default: False. - """ - def __init__(self, - keys, - meta_keys=('filename', 'label', 'original_shape', 'img_shape', - 'pad_shape', 'flip_direction', 'img_norm_cfg'), - meta_name='img_metas', - nested=False): - self.keys = keys - self.meta_keys = meta_keys - self.meta_name = meta_name - self.nested = nested - - def __call__(self, results): - """Performs the Collect formating. - - Args: - results (dict): The resulting dict to be modified and passed - to the next transform in pipeline. - """ - data = {} - for key in self.keys: - data[key] = results[key] - - if len(self.meta_keys) != 0: - meta = {} - for key in self.meta_keys: - meta[key] = results[key] - data[self.meta_name] = DC(meta, cpu_only=True) - if self.nested: - for k in data: - data[k] = [data[k]] - - return data - - def __repr__(self): - return (f'{self.__class__.__name__}(' - f'keys={self.keys}, meta_keys={self.meta_keys}, ' - f'nested={self.nested})') - - -@PIPELINES.register_module() -class FormatShape: - """Format final imgs shape to the given input_format. - - Required keys are "imgs", "num_clips" and "clip_len", added or modified - keys are "imgs" and "input_shape". - - Args: - input_format (str): Define the final imgs format. - collapse (bool): To collpase input_format N... to ... (NCTHW to CTHW, - etc.) if N is 1. Should be set as True when training and testing - detectors. Default: False. - """ - def __init__(self, input_format, collapse=False): - self.input_format = input_format - self.collapse = collapse - if self.input_format not in ['NCTHW', 'NCHW', 'NCHW_Flow', 'NPTCHW']: - raise ValueError( - f'The input format {self.input_format} is invalid.') - - def __call__(self, results): - """Performs the FormatShape formating. - - Args: - results (dict): The resulting dict to be modified and passed - to the next transform in pipeline. - """ - if not isinstance(results['imgs'], np.ndarray): - results['imgs'] = np.array(results['imgs']) - imgs = results['imgs'] - # [M x H x W x C] - # M = 1 * N_crops * N_clips * L - if self.collapse: - assert results['num_clips'] == 1 - - if self.input_format == 'NCTHW': - num_clips = results['num_clips'] - clip_len = results['clip_len'] - - imgs = imgs.reshape((-1, num_clips, clip_len) + imgs.shape[1:]) - # N_crops x N_clips x L x H x W x C - imgs = np.transpose(imgs, (0, 1, 5, 2, 3, 4)) - # N_crops x N_clips x C x L x H x W - imgs = imgs.reshape((-1, ) + imgs.shape[2:]) - # M' x C x L x H x W - # M' = N_crops x N_clips - elif self.input_format == 'NCHW': - imgs = np.transpose(imgs, (0, 3, 1, 2)) - # M x C x H x W - elif self.input_format == 'NCHW_Flow': - num_clips = results['num_clips'] - clip_len = results['clip_len'] - imgs = imgs.reshape((-1, num_clips, clip_len) + imgs.shape[1:]) - # N_crops x N_clips x L x H x W x C - imgs = np.transpose(imgs, (0, 1, 2, 5, 3, 4)) - # N_crops x N_clips x L x C x H x W - imgs = imgs.reshape((-1, imgs.shape[2] * imgs.shape[3]) + - imgs.shape[4:]) - # M' x C' x H x W - # M' = N_crops x N_clips - # C' = L x C - elif self.input_format == 'NPTCHW': - num_proposals = results['num_proposals'] - num_clips = results['num_clips'] - clip_len = results['clip_len'] - imgs = imgs.reshape((num_proposals, num_clips * clip_len) + - imgs.shape[1:]) - # P x M x H x W x C - # M = N_clips x L - imgs = np.transpose(imgs, (0, 1, 4, 2, 3)) - # P x M x C x H x W - if self.collapse: - assert imgs.shape[0] == 1 - imgs = imgs.squeeze(0) - - results['imgs'] = imgs - results['input_shape'] = imgs.shape - return results - - def __repr__(self): - repr_str = self.__class__.__name__ - repr_str += f"(input_format='{self.input_format}')" - return repr_str - - -@PIPELINES.register_module() -class FormatAudioShape: - """Format final audio shape to the given input_format. - - Required keys are "imgs", "num_clips" and "clip_len", added or modified - keys are "imgs" and "input_shape". - - Args: - input_format (str): Define the final imgs format. - """ - def __init__(self, input_format): - self.input_format = input_format - if self.input_format not in ['NCTF']: - raise ValueError( - f'The input format {self.input_format} is invalid.') - - def __call__(self, results): - """Performs the FormatShape formatting. - - Args: - results (dict): The resulting dict to be modified and passed - to the next transform in pipeline. - """ - audios = results['audios'] - # clip x sample x freq -> clip x channel x sample x freq - clip, sample, freq = audios.shape - audios = audios.reshape(clip, 1, sample, freq) - results['audios'] = audios - results['input_shape'] = audios.shape - return results - - def __repr__(self): - repr_str = self.__class__.__name__ - repr_str += f"(input_format='{self.input_format}')" - return repr_str +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 collections.abc import Sequence + +import mmcv +import numpy as np +import torch +from mmcv.parallel import DataContainer as DC + +from ..builder import PIPELINES + + +def to_tensor(data): + """Convert objects of various python types to :obj:`torch.Tensor`. + + Supported types are: :class:`numpy.ndarray`, :class:`torch.Tensor`, + :class:`Sequence`, :class:`int` and :class:`float`. + """ + if isinstance(data, torch.Tensor): + return data + if isinstance(data, np.ndarray): + return torch.from_numpy(data) + if isinstance(data, Sequence) and not mmcv.is_str(data): + return torch.tensor(data) + if isinstance(data, int): + return torch.LongTensor([data]) + if isinstance(data, float): + return torch.FloatTensor([data]) + raise TypeError(f'type {type(data)} cannot be converted to tensor.') + + +@PIPELINES.register_module() +class ToTensor: + """Convert some values in results dict to `torch.Tensor` type in data + loader pipeline. + + Args: + keys (Sequence[str]): Required keys to be converted. + """ + def __init__(self, keys): + self.keys = keys + + def __call__(self, results): + """Performs the ToTensor formating. + + Args: + results (dict): The resulting dict to be modified and passed + to the next transform in pipeline. + """ + for key in self.keys: + results[key] = to_tensor(results[key]) + return results + + def __repr__(self): + return f'{self.__class__.__name__}(keys={self.keys})' + + +@PIPELINES.register_module() +class Rename: + """Rename the key in results. + + Args: + mapping (dict): The keys in results that need to be renamed. The key of + the dict is the original name, while the value is the new name. If + the original name not found in results, do nothing. + Default: dict(). + """ + def __init__(self, mapping): + self.mapping = mapping + + def __call__(self, results): + for key, value in self.mapping.items(): + if key in results: + assert isinstance(key, str) and isinstance(value, str) + assert value not in results, ('the new name already exists in ' + 'results') + results[value] = results[key] + results.pop(key) + return results + + +@PIPELINES.register_module() +class ToDataContainer: + """Convert the data to DataContainer. + + Args: + fields (Sequence[dict]): Required fields to be converted + with keys and attributes. E.g. + fields=(dict(key='gt_bbox', stack=False),). + Note that key can also be a list of keys, if so, every tensor in + the list will be converted to DataContainer. + """ + def __init__(self, fields): + self.fields = fields + + def __call__(self, results): + """Performs the ToDataContainer formating. + + Args: + results (dict): The resulting dict to be modified and passed + to the next transform in pipeline. + """ + for field in self.fields: + _field = field.copy() + key = _field.pop('key') + if isinstance(key, list): + for item in key: + results[item] = DC(results[item], **_field) + else: + results[key] = DC(results[key], **_field) + return results + + def __repr__(self): + return self.__class__.__name__ + f'(fields={self.fields})' + + +@PIPELINES.register_module() +class ImageToTensor: + """Convert image type to `torch.Tensor` type. + + Args: + keys (Sequence[str]): Required keys to be converted. + """ + def __init__(self, keys): + self.keys = keys + + def __call__(self, results): + """Performs the ImageToTensor formating. + + Args: + results (dict): The resulting dict to be modified and passed + to the next transform in pipeline. + """ + for key in self.keys: + results[key] = to_tensor(results[key].transpose(2, 0, 1)) + return results + + def __repr__(self): + return f'{self.__class__.__name__}(keys={self.keys})' + + +@PIPELINES.register_module() +class Transpose: + """Transpose image channels to a given order. + + Args: + keys (Sequence[str]): Required keys to be converted. + order (Sequence[int]): Image channel order. + """ + def __init__(self, keys, order): + self.keys = keys + self.order = order + + def __call__(self, results): + """Performs the Transpose formatting. + + Args: + results (dict): The resulting dict to be modified and passed + to the next transform in pipeline. + """ + for key in self.keys: + results[key] = results[key].transpose(self.order) + return results + + def __repr__(self): + return (f'{self.__class__.__name__}(' + f'keys={self.keys}, order={self.order})') + + +@PIPELINES.register_module() +class Collect: + """Collect data from the loader relevant to the specific task. + + This keeps the items in ``keys`` as it is, and collect items in + ``meta_keys`` into a meta item called ``meta_name``.This is usually + the last stage of the data loader pipeline. + For example, when keys='imgs', meta_keys=('filename', 'label', + 'original_shape'), meta_name='img_metas', the results will be a dict with + keys 'imgs' and 'img_metas', where 'img_metas' is a DataContainer of + another dict with keys 'filename', 'label', 'original_shape'. + + Args: + keys (Sequence[str]): Required keys to be collected. + meta_name (str): The name of the key that contains meta infomation. + This key is always populated. Default: "img_metas". + meta_keys (Sequence[str]): Keys that are collected under meta_name. + The contents of the ``meta_name`` dictionary depends on + ``meta_keys``. + By default this includes: + + - "filename": path to the image file + - "label": label of the image file + - "original_shape": original shape of the image as a tuple + (h, w, c) + - "img_shape": shape of the image input to the network as a tuple + (h, w, c). Note that images may be zero padded on the + bottom/right, if the batch tensor is larger than this shape. + - "pad_shape": image shape after padding + - "flip_direction": a str in ("horiziontal", "vertival") to + indicate if the image is fliped horizontally or vertically. + - "img_norm_cfg": a dict of normalization information: + - mean - per channel mean subtraction + - std - per channel std divisor + - to_rgb - bool indicating if bgr was converted to rgb + nested (bool): If set as True, will apply data[x] = [data[x]] to all + items in data. The arg is added for compatibility. Default: False. + """ + def __init__(self, + keys, + meta_keys=('filename', 'label', 'original_shape', 'img_shape', + 'pad_shape', 'flip_direction', 'img_norm_cfg'), + meta_name='img_metas', + nested=False): + self.keys = keys + self.meta_keys = meta_keys + self.meta_name = meta_name + self.nested = nested + + def __call__(self, results): + """Performs the Collect formating. + + Args: + results (dict): The resulting dict to be modified and passed + to the next transform in pipeline. + """ + data = {} + for key in self.keys: + data[key] = results[key] + + if len(self.meta_keys) != 0: + meta = {} + for key in self.meta_keys: + meta[key] = results[key] + data[self.meta_name] = DC(meta, cpu_only=True) + if self.nested: + for k in data: + data[k] = [data[k]] + + return data + + def __repr__(self): + return (f'{self.__class__.__name__}(' + f'keys={self.keys}, meta_keys={self.meta_keys}, ' + f'nested={self.nested})') + + +@PIPELINES.register_module() +class FormatShape: + """Format final imgs shape to the given input_format. + + Required keys are "imgs", "num_clips" and "clip_len", added or modified + keys are "imgs" and "input_shape". + + Args: + input_format (str): Define the final imgs format. + collapse (bool): To collpase input_format N... to ... (NCTHW to CTHW, + etc.) if N is 1. Should be set as True when training and testing + detectors. Default: False. + """ + def __init__(self, input_format, collapse=False): + self.input_format = input_format + self.collapse = collapse + if self.input_format not in ['NCTHW', 'NCHW', 'NCHW_Flow', 'NPTCHW']: + raise ValueError( + f'The input format {self.input_format} is invalid.') + + def __call__(self, results): + """Performs the FormatShape formating. + + Args: + results (dict): The resulting dict to be modified and passed + to the next transform in pipeline. + """ + if not isinstance(results['imgs'], np.ndarray): + results['imgs'] = np.array(results['imgs']) + imgs = results['imgs'] + # [M x H x W x C] + # M = 1 * N_crops * N_clips * L + if self.collapse: + assert results['num_clips'] == 1 + + if self.input_format == 'NCTHW': + num_clips = results['num_clips'] + clip_len = results['clip_len'] + + imgs = imgs.reshape((-1, num_clips, clip_len) + imgs.shape[1:]) + # N_crops x N_clips x L x H x W x C + imgs = np.transpose(imgs, (0, 1, 5, 2, 3, 4)) + # N_crops x N_clips x C x L x H x W + imgs = imgs.reshape((-1, ) + imgs.shape[2:]) + # M' x C x L x H x W + # M' = N_crops x N_clips + elif self.input_format == 'NCHW': + imgs = np.transpose(imgs, (0, 3, 1, 2)) + # M x C x H x W + elif self.input_format == 'NCHW_Flow': + num_clips = results['num_clips'] + clip_len = results['clip_len'] + imgs = imgs.reshape((-1, num_clips, clip_len) + imgs.shape[1:]) + # N_crops x N_clips x L x H x W x C + imgs = np.transpose(imgs, (0, 1, 2, 5, 3, 4)) + # N_crops x N_clips x L x C x H x W + imgs = imgs.reshape((-1, imgs.shape[2] * imgs.shape[3]) + + imgs.shape[4:]) + # M' x C' x H x W + # M' = N_crops x N_clips + # C' = L x C + elif self.input_format == 'NPTCHW': + num_proposals = results['num_proposals'] + num_clips = results['num_clips'] + clip_len = results['clip_len'] + imgs = imgs.reshape((num_proposals, num_clips * clip_len) + + imgs.shape[1:]) + # P x M x H x W x C + # M = N_clips x L + imgs = np.transpose(imgs, (0, 1, 4, 2, 3)) + # P x M x C x H x W + if self.collapse: + assert imgs.shape[0] == 1 + imgs = imgs.squeeze(0) + + results['imgs'] = imgs + results['input_shape'] = imgs.shape + return results + + def __repr__(self): + repr_str = self.__class__.__name__ + repr_str += f"(input_format='{self.input_format}')" + return repr_str + + +@PIPELINES.register_module() +class FormatAudioShape: + """Format final audio shape to the given input_format. + + Required keys are "imgs", "num_clips" and "clip_len", added or modified + keys are "imgs" and "input_shape". + + Args: + input_format (str): Define the final imgs format. + """ + def __init__(self, input_format): + self.input_format = input_format + if self.input_format not in ['NCTF']: + raise ValueError( + f'The input format {self.input_format} is invalid.') + + def __call__(self, results): + """Performs the FormatShape formatting. + + Args: + results (dict): The resulting dict to be modified and passed + to the next transform in pipeline. + """ + audios = results['audios'] + # clip x sample x freq -> clip x channel x sample x freq + clip, sample, freq = audios.shape + audios = audios.reshape(clip, 1, sample, freq) + results['audios'] = audios + results['input_shape'] = audios.shape + return results + + def __repr__(self): + repr_str = self.__class__.__name__ + repr_str += f"(input_format='{self.input_format}')" + return repr_str diff --git a/PyTorch/contrib/cv/video/NonLocal/mmaction/models/backbones/resnet3d_slowfast.py b/PyTorch/contrib/cv/video/NonLocal/mmaction/models/backbones/resnet3d_slowfast.py index a5d23bb38e..e61842a2ba 100644 --- a/PyTorch/contrib/cv/video/NonLocal/mmaction/models/backbones/resnet3d_slowfast.py +++ b/PyTorch/contrib/cv/video/NonLocal/mmaction/models/backbones/resnet3d_slowfast.py @@ -1,531 +1,531 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 warnings - -import torch -import torch.nn as nn -from mmcv.cnn import ConvModule, kaiming_init -from mmcv.runner import _load_checkpoint, load_checkpoint -from mmcv.utils import print_log - -from ...utils import get_root_logger -from ..builder import BACKBONES -from .resnet3d import ResNet3d - -mmdet_imported = False - - -class ResNet3dPathway(ResNet3d): - """A pathway of Slowfast based on ResNet3d. - - Args: - *args (arguments): Arguments same as :class:``ResNet3d``. - lateral (bool): Determines whether to enable the lateral connection - from another pathway. Default: False. - speed_ratio (int): Speed ratio indicating the ratio between time - dimension of the fast and slow pathway, corresponding to the - ``alpha`` in the paper. Default: 8. - channel_ratio (int): Reduce the channel number of fast pathway - by ``channel_ratio``, corresponding to ``beta`` in the paper. - Default: 8. - fusion_kernel (int): The kernel size of lateral fusion. - Default: 5. - **kwargs (keyword arguments): Keywords arguments for ResNet3d. - """ - def __init__(self, - *args, - lateral=False, - speed_ratio=8, - channel_ratio=8, - fusion_kernel=5, - **kwargs): - self.lateral = lateral - self.speed_ratio = speed_ratio - self.channel_ratio = channel_ratio - self.fusion_kernel = fusion_kernel - super().__init__(*args, **kwargs) - self.inplanes = self.base_channels - if self.lateral: - self.conv1_lateral = ConvModule( - self.inplanes // self.channel_ratio, - # https://arxiv.org/abs/1812.03982, the - # third type of lateral connection has out_channel: - # 2 * \beta * C - self.inplanes * 2 // self.channel_ratio, - kernel_size=(fusion_kernel, 1, 1), - stride=(self.speed_ratio, 1, 1), - padding=((fusion_kernel - 1) // 2, 0, 0), - bias=False, - conv_cfg=self.conv_cfg, - norm_cfg=self.norm_cfg, - act_cfg=None) - - self.lateral_connections = [] - for i in range(len(self.stage_blocks)): - planes = self.base_channels * 2**i - self.inplanes = planes * self.block.expansion - - if lateral and i != self.num_stages - 1: - # no lateral connection needed in final stage - lateral_name = f'layer{(i + 1)}_lateral' - setattr( - self, lateral_name, - ConvModule(self.inplanes // self.channel_ratio, - self.inplanes * 2 // self.channel_ratio, - kernel_size=(fusion_kernel, 1, 1), - stride=(self.speed_ratio, 1, 1), - padding=((fusion_kernel - 1) // 2, 0, 0), - bias=False, - conv_cfg=self.conv_cfg, - norm_cfg=self.norm_cfg, - act_cfg=None)) - self.lateral_connections.append(lateral_name) - - def make_res_layer(self, - block, - inplanes, - planes, - blocks, - spatial_stride=1, - temporal_stride=1, - dilation=1, - style='pytorch', - inflate=1, - inflate_style='3x1x1', - non_local=0, - non_local_cfg=dict(), - conv_cfg=None, - norm_cfg=None, - act_cfg=None, - with_cp=False): - """Build residual layer for Slowfast. - - Args: - block (nn.Module): Residual module to be built. - inplanes (int): Number of channels for the input - feature in each block. - planes (int): Number of channels for the output - feature in each block. - blocks (int): Number of residual blocks. - spatial_stride (int | Sequence[int]): Spatial strides - in residual and conv layers. Default: 1. - temporal_stride (int | Sequence[int]): Temporal strides in - residual and conv layers. Default: 1. - dilation (int): Spacing between kernel elements. Default: 1. - style (str): ``pytorch`` or ``caffe``. If set to ``pytorch``, - the stride-two layer is the 3x3 conv layer, - otherwise the stride-two layer is the first 1x1 conv layer. - Default: ``pytorch``. - inflate (int | Sequence[int]): Determine whether to inflate - for each block. Default: 1. - inflate_style (str): ``3x1x1`` or ``3x3x3``. which determines - the kernel sizes and padding strides for conv1 and - conv2 in each block. Default: ``3x1x1``. - non_local (int | Sequence[int]): Determine whether to apply - non-local module in the corresponding block of each stages. - Default: 0. - non_local_cfg (dict): Config for non-local module. - Default: ``dict()``. - conv_cfg (dict | None): Config for conv layers. Default: None. - norm_cfg (dict | None): Config for norm layers. Default: None. - act_cfg (dict | None): Config for activate layers. Default: None. - with_cp (bool): Use checkpoint or not. Using checkpoint will save - some memory while slowing down the training speed. - Default: False. - - Returns: - nn.Module: A residual layer for the given config. - """ - inflate = inflate if not isinstance(inflate, - int) else (inflate, ) * blocks - non_local = non_local if not isinstance( - non_local, int) else (non_local, ) * blocks - assert len(inflate) == blocks and len(non_local) == blocks - if self.lateral: - lateral_inplanes = inplanes * 2 // self.channel_ratio - else: - lateral_inplanes = 0 - if (spatial_stride != 1 - or (inplanes + lateral_inplanes) != planes * block.expansion): - downsample = ConvModule(inplanes + lateral_inplanes, - planes * block.expansion, - kernel_size=1, - stride=(temporal_stride, spatial_stride, - spatial_stride), - bias=False, - conv_cfg=conv_cfg, - norm_cfg=norm_cfg, - act_cfg=None) - else: - downsample = None - - layers = [] - layers.append( - block(inplanes + lateral_inplanes, - planes, - spatial_stride, - temporal_stride, - dilation, - downsample, - style=style, - inflate=(inflate[0] == 1), - inflate_style=inflate_style, - non_local=(non_local[0] == 1), - non_local_cfg=non_local_cfg, - conv_cfg=conv_cfg, - norm_cfg=norm_cfg, - act_cfg=act_cfg, - with_cp=with_cp)) - inplanes = planes * block.expansion - - for i in range(1, blocks): - layers.append( - block(inplanes, - planes, - 1, - 1, - dilation, - style=style, - inflate=(inflate[i] == 1), - inflate_style=inflate_style, - non_local=(non_local[i] == 1), - non_local_cfg=non_local_cfg, - conv_cfg=conv_cfg, - norm_cfg=norm_cfg, - act_cfg=act_cfg, - with_cp=with_cp)) - - return nn.Sequential(*layers) - - def inflate_weights(self, logger): - """Inflate the resnet2d parameters to resnet3d pathway. - - The differences between resnet3d and resnet2d mainly lie in an extra - axis of conv kernel. To utilize the pretrained parameters in 2d model, - the weight of conv2d models should be inflated to fit in the shapes of - the 3d counterpart. For pathway the ``lateral_connection`` part should - not be inflated from 2d weights. - - Args: - logger (logging.Logger): The logger used to print - debugging infomation. - """ - - state_dict_r2d = _load_checkpoint(self.pretrained) - if 'state_dict' in state_dict_r2d: - state_dict_r2d = state_dict_r2d['state_dict'] - - inflated_param_names = [] - for name, module in self.named_modules(): - if 'lateral' in name: - continue - if isinstance(module, ConvModule): - # we use a ConvModule to wrap conv+bn+relu layers, thus the - # name mapping is needed - if 'downsample' in name: - # layer{X}.{Y}.downsample.conv->layer{X}.{Y}.downsample.0 - original_conv_name = name + '.0' - # layer{X}.{Y}.downsample.bn->layer{X}.{Y}.downsample.1 - original_bn_name = name + '.1' - else: - # layer{X}.{Y}.conv{n}.conv->layer{X}.{Y}.conv{n} - original_conv_name = name - # layer{X}.{Y}.conv{n}.bn->layer{X}.{Y}.bn{n} - original_bn_name = name.replace('conv', 'bn') - if original_conv_name + '.weight' not in state_dict_r2d: - logger.warning(f'Module not exist in the state_dict_r2d' - f': {original_conv_name}') - else: - self._inflate_conv_params(module.conv, state_dict_r2d, - original_conv_name, - inflated_param_names) - if original_bn_name + '.weight' not in state_dict_r2d: - logger.warning(f'Module not exist in the state_dict_r2d' - f': {original_bn_name}') - else: - self._inflate_bn_params(module.bn, state_dict_r2d, - original_bn_name, - inflated_param_names) - - # check if any parameters in the 2d checkpoint are not loaded - remaining_names = set( - state_dict_r2d.keys()) - set(inflated_param_names) - if remaining_names: - logger.info(f'These parameters in the 2d checkpoint are not loaded' - f': {remaining_names}') - - def _inflate_conv_params(self, conv3d, state_dict_2d, module_name_2d, - inflated_param_names): - """Inflate a conv module from 2d to 3d. - - The differences of conv modules betweene 2d and 3d in Pathway - mainly lie in the inplanes due to lateral connections. To fit the - shapes of the lateral connection counterpart, it will expand - parameters by concatting conv2d parameters and extra zero paddings. - - Args: - conv3d (nn.Module): The destination conv3d module. - state_dict_2d (OrderedDict): The state dict of pretrained 2d model. - module_name_2d (str): The name of corresponding conv module in the - 2d model. - inflated_param_names (list[str]): List of parameters that have been - inflated. - """ - weight_2d_name = module_name_2d + '.weight' - conv2d_weight = state_dict_2d[weight_2d_name] - old_shape = conv2d_weight.shape - new_shape = conv3d.weight.data.shape - kernel_t = new_shape[2] - - if new_shape[1] != old_shape[1]: - if new_shape[1] < old_shape[1]: - warnings.warn(f'The parameter of {module_name_2d} is not' - 'loaded due to incompatible shapes. ') - return - # Inplanes may be different due to lateral connections - new_channels = new_shape[1] - old_shape[1] - pad_shape = old_shape - pad_shape = pad_shape[:1] + (new_channels, ) + pad_shape[2:] - # Expand parameters by concat extra channels - conv2d_weight = torch.cat( - (conv2d_weight, - torch.zeros(pad_shape).type_as(conv2d_weight).to( - conv2d_weight.device)), - dim=1) - - new_weight = conv2d_weight.data.unsqueeze(2).expand_as( - conv3d.weight) / kernel_t - conv3d.weight.data.copy_(new_weight) - inflated_param_names.append(weight_2d_name) - - if getattr(conv3d, 'bias') is not None: - bias_2d_name = module_name_2d + '.bias' - conv3d.bias.data.copy_(state_dict_2d[bias_2d_name]) - inflated_param_names.append(bias_2d_name) - - def _freeze_stages(self): - """Prevent all the parameters from being optimized before - `self.frozen_stages`.""" - if self.frozen_stages >= 0: - self.conv1.eval() - for param in self.conv1.parameters(): - param.requires_grad = False - - for i in range(1, self.frozen_stages + 1): - m = getattr(self, f'layer{i}') - m.eval() - for param in m.parameters(): - param.requires_grad = False - - if i != len(self.res_layers) and self.lateral: - # No fusion needed in the final stage - lateral_name = self.lateral_connections[i - 1] - conv_lateral = getattr(self, lateral_name) - conv_lateral.eval() - for param in conv_lateral.parameters(): - param.requires_grad = False - - def init_weights(self, pretrained=None): - """Initiate the parameters either from existing checkpoint or from - scratch.""" - if pretrained: - self.pretrained = pretrained - - # Override the init_weights of i3d - super().init_weights() - for module_name in self.lateral_connections: - layer = getattr(self, module_name) - for m in layer.modules(): - if isinstance(m, (nn.Conv3d, nn.Conv2d)): - kaiming_init(m) - - -pathway_cfg = { - 'resnet3d': ResNet3dPathway, - # TODO: BNInceptionPathway -} - - -def build_pathway(cfg, *args, **kwargs): - """Build pathway. - - Args: - cfg (None or dict): cfg should contain: - - type (str): identify conv layer type. - - Returns: - nn.Module: Created pathway. - """ - if not (isinstance(cfg, dict) and 'type' in cfg): - raise TypeError('cfg must be a dict containing the key "type"') - cfg_ = cfg.copy() - - pathway_type = cfg_.pop('type') - if pathway_type not in pathway_cfg: - raise KeyError(f'Unrecognized pathway type {pathway_type}') - - pathway_cls = pathway_cfg[pathway_type] - pathway = pathway_cls(*args, **kwargs, **cfg_) - - return pathway - - -@BACKBONES.register_module() -class ResNet3dSlowFast(nn.Module): - """Slowfast backbone. - - This module is proposed in `SlowFast Networks for Video Recognition - `_ - - Args: - pretrained (str): The file path to a pretrained model. - resample_rate (int): A large temporal stride ``resample_rate`` - on input frames. The actual resample rate is calculated by - multipling the ``interval`` in ``SampleFrames`` in the - pipeline with ``resample_rate``, equivalent to the :math:`\\tau` - in the paper, i.e. it processes only one out of - ``resample_rate * interval`` frames. Default: 8. - speed_ratio (int): Speed ratio indicating the ratio between time - dimension of the fast and slow pathway, corresponding to the - :math:`\\alpha` in the paper. Default: 8. - channel_ratio (int): Reduce the channel number of fast pathway - by ``channel_ratio``, corresponding to :math:`\\beta` in the paper. - Default: 8. - slow_pathway (dict): Configuration of slow branch, should contain - necessary arguments for building the specific type of pathway - and: - type (str): type of backbone the pathway bases on. - lateral (bool): determine whether to build lateral connection - for the pathway.Default: - - .. code-block:: Python - - dict(type='ResNetPathway', - lateral=True, depth=50, pretrained=None, - conv1_kernel=(1, 7, 7), dilations=(1, 1, 1, 1), - conv1_stride_t=1, pool1_stride_t=1, inflate=(0, 0, 1, 1)) - - fast_pathway (dict): Configuration of fast branch, similar to - `slow_pathway`. Default: - - .. code-block:: Python - - dict(type='ResNetPathway', - lateral=False, depth=50, pretrained=None, base_channels=8, - conv1_kernel=(5, 7, 7), conv1_stride_t=1, pool1_stride_t=1) - """ - def __init__(self, - pretrained, - resample_rate=8, - speed_ratio=8, - channel_ratio=8, - slow_pathway=dict(type='resnet3d', - depth=50, - pretrained=None, - lateral=True, - conv1_kernel=(1, 7, 7), - dilations=(1, 1, 1, 1), - conv1_stride_t=1, - pool1_stride_t=1, - inflate=(0, 0, 1, 1)), - fast_pathway=dict(type='resnet3d', - depth=50, - pretrained=None, - lateral=False, - base_channels=8, - conv1_kernel=(5, 7, 7), - conv1_stride_t=1, - pool1_stride_t=1)): - super().__init__() - self.pretrained = pretrained - self.resample_rate = resample_rate - self.speed_ratio = speed_ratio - self.channel_ratio = channel_ratio - - if slow_pathway['lateral']: - slow_pathway['speed_ratio'] = speed_ratio - slow_pathway['channel_ratio'] = channel_ratio - - self.slow_path = build_pathway(slow_pathway) - self.fast_path = build_pathway(fast_pathway) - - def init_weights(self, pretrained=None): - """Initiate the parameters either from existing checkpoint or from - scratch.""" - if pretrained: - self.pretrained = pretrained - - if isinstance(self.pretrained, str): - logger = get_root_logger() - msg = f'load model from: {self.pretrained}' - print_log(msg, logger=logger) - # Directly load 3D model. - load_checkpoint(self, self.pretrained, strict=True, logger=logger) - elif self.pretrained is None: - # Init two branch seperately. - self.fast_path.init_weights() - self.slow_path.init_weights() - else: - raise TypeError('pretrained must be a str or None') - - def forward(self, x): - """Defines the computation performed at every call. - - Args: - x (torch.Tensor): The input data. - - Returns: - tuple[torch.Tensor]: The feature of the input samples extracted - by the backbone. - """ - x_slow = nn.functional.interpolate( - x, - mode='nearest', - scale_factor=(1.0 / self.resample_rate, 1.0, 1.0)) - x_slow = self.slow_path.conv1(x_slow) - x_slow = self.slow_path.maxpool(x_slow) - - x_fast = nn.functional.interpolate( - x, - mode='nearest', - scale_factor=(1.0 / (self.resample_rate // self.speed_ratio), 1.0, - 1.0)) - x_fast = self.fast_path.conv1(x_fast) - x_fast = self.fast_path.maxpool(x_fast) - - if self.slow_path.lateral: - x_fast_lateral = self.slow_path.conv1_lateral(x_fast) - x_slow = torch.cat((x_slow, x_fast_lateral), dim=1) - - for i, layer_name in enumerate(self.slow_path.res_layers): - res_layer = getattr(self.slow_path, layer_name) - x_slow = res_layer(x_slow) - res_layer_fast = getattr(self.fast_path, layer_name) - x_fast = res_layer_fast(x_fast) - if (i != len(self.slow_path.res_layers) - 1 - and self.slow_path.lateral): - # No fusion needed in the final stage - lateral_name = self.slow_path.lateral_connections[i] - conv_lateral = getattr(self.slow_path, lateral_name) - x_fast_lateral = conv_lateral(x_fast) - x_slow = torch.cat((x_slow, x_fast_lateral), dim=1) - - out = (x_slow, x_fast) - - return out - - -if mmdet_imported: - MMDET_BACKBONES.register_module()(ResNet3dSlowFast) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 warnings + +import torch +import torch.nn as nn +from mmcv.cnn import ConvModule, kaiming_init +from mmcv.runner import _load_checkpoint, load_checkpoint +from mmcv.utils import print_log + +from ...utils import get_root_logger +from ..builder import BACKBONES +from .resnet3d import ResNet3d + +mmdet_imported = False + + +class ResNet3dPathway(ResNet3d): + """A pathway of Slowfast based on ResNet3d. + + Args: + *args (arguments): Arguments same as :class:``ResNet3d``. + lateral (bool): Determines whether to enable the lateral connection + from another pathway. Default: False. + speed_ratio (int): Speed ratio indicating the ratio between time + dimension of the fast and slow pathway, corresponding to the + ``alpha`` in the paper. Default: 8. + channel_ratio (int): Reduce the channel number of fast pathway + by ``channel_ratio``, corresponding to ``beta`` in the paper. + Default: 8. + fusion_kernel (int): The kernel size of lateral fusion. + Default: 5. + **kwargs (keyword arguments): Keywords arguments for ResNet3d. + """ + def __init__(self, + *args, + lateral=False, + speed_ratio=8, + channel_ratio=8, + fusion_kernel=5, + **kwargs): + self.lateral = lateral + self.speed_ratio = speed_ratio + self.channel_ratio = channel_ratio + self.fusion_kernel = fusion_kernel + super().__init__(*args, **kwargs) + self.inplanes = self.base_channels + if self.lateral: + self.conv1_lateral = ConvModule( + self.inplanes // self.channel_ratio, + # https://arxiv.org/abs/1812.03982, the + # third type of lateral connection has out_channel: + # 2 * \beta * C + self.inplanes * 2 // self.channel_ratio, + kernel_size=(fusion_kernel, 1, 1), + stride=(self.speed_ratio, 1, 1), + padding=((fusion_kernel - 1) // 2, 0, 0), + bias=False, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=None) + + self.lateral_connections = [] + for i in range(len(self.stage_blocks)): + planes = self.base_channels * 2**i + self.inplanes = planes * self.block.expansion + + if lateral and i != self.num_stages - 1: + # no lateral connection needed in final stage + lateral_name = f'layer{(i + 1)}_lateral' + setattr( + self, lateral_name, + ConvModule(self.inplanes // self.channel_ratio, + self.inplanes * 2 // self.channel_ratio, + kernel_size=(fusion_kernel, 1, 1), + stride=(self.speed_ratio, 1, 1), + padding=((fusion_kernel - 1) // 2, 0, 0), + bias=False, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=None)) + self.lateral_connections.append(lateral_name) + + def make_res_layer(self, + block, + inplanes, + planes, + blocks, + spatial_stride=1, + temporal_stride=1, + dilation=1, + style='pytorch', + inflate=1, + inflate_style='3x1x1', + non_local=0, + non_local_cfg=dict(), + conv_cfg=None, + norm_cfg=None, + act_cfg=None, + with_cp=False): + """Build residual layer for Slowfast. + + Args: + block (nn.Module): Residual module to be built. + inplanes (int): Number of channels for the input + feature in each block. + planes (int): Number of channels for the output + feature in each block. + blocks (int): Number of residual blocks. + spatial_stride (int | Sequence[int]): Spatial strides + in residual and conv layers. Default: 1. + temporal_stride (int | Sequence[int]): Temporal strides in + residual and conv layers. Default: 1. + dilation (int): Spacing between kernel elements. Default: 1. + style (str): ``pytorch`` or ``caffe``. If set to ``pytorch``, + the stride-two layer is the 3x3 conv layer, + otherwise the stride-two layer is the first 1x1 conv layer. + Default: ``pytorch``. + inflate (int | Sequence[int]): Determine whether to inflate + for each block. Default: 1. + inflate_style (str): ``3x1x1`` or ``3x3x3``. which determines + the kernel sizes and padding strides for conv1 and + conv2 in each block. Default: ``3x1x1``. + non_local (int | Sequence[int]): Determine whether to apply + non-local module in the corresponding block of each stages. + Default: 0. + non_local_cfg (dict): Config for non-local module. + Default: ``dict()``. + conv_cfg (dict | None): Config for conv layers. Default: None. + norm_cfg (dict | None): Config for norm layers. Default: None. + act_cfg (dict | None): Config for activate layers. Default: None. + with_cp (bool): Use checkpoint or not. Using checkpoint will save + some memory while slowing down the training speed. + Default: False. + + Returns: + nn.Module: A residual layer for the given config. + """ + inflate = inflate if not isinstance(inflate, + int) else (inflate, ) * blocks + non_local = non_local if not isinstance( + non_local, int) else (non_local, ) * blocks + assert len(inflate) == blocks and len(non_local) == blocks + if self.lateral: + lateral_inplanes = inplanes * 2 // self.channel_ratio + else: + lateral_inplanes = 0 + if (spatial_stride != 1 + or (inplanes + lateral_inplanes) != planes * block.expansion): + downsample = ConvModule(inplanes + lateral_inplanes, + planes * block.expansion, + kernel_size=1, + stride=(temporal_stride, spatial_stride, + spatial_stride), + bias=False, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=None) + else: + downsample = None + + layers = [] + layers.append( + block(inplanes + lateral_inplanes, + planes, + spatial_stride, + temporal_stride, + dilation, + downsample, + style=style, + inflate=(inflate[0] == 1), + inflate_style=inflate_style, + non_local=(non_local[0] == 1), + non_local_cfg=non_local_cfg, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg, + with_cp=with_cp)) + inplanes = planes * block.expansion + + for i in range(1, blocks): + layers.append( + block(inplanes, + planes, + 1, + 1, + dilation, + style=style, + inflate=(inflate[i] == 1), + inflate_style=inflate_style, + non_local=(non_local[i] == 1), + non_local_cfg=non_local_cfg, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg, + with_cp=with_cp)) + + return nn.Sequential(*layers) + + def inflate_weights(self, logger): + """Inflate the resnet2d parameters to resnet3d pathway. + + The differences between resnet3d and resnet2d mainly lie in an extra + axis of conv kernel. To utilize the pretrained parameters in 2d model, + the weight of conv2d models should be inflated to fit in the shapes of + the 3d counterpart. For pathway the ``lateral_connection`` part should + not be inflated from 2d weights. + + Args: + logger (logging.Logger): The logger used to print + debugging infomation. + """ + + state_dict_r2d = _load_checkpoint(self.pretrained) + if 'state_dict' in state_dict_r2d: + state_dict_r2d = state_dict_r2d['state_dict'] + + inflated_param_names = [] + for name, module in self.named_modules(): + if 'lateral' in name: + continue + if isinstance(module, ConvModule): + # we use a ConvModule to wrap conv+bn+relu layers, thus the + # name mapping is needed + if 'downsample' in name: + # layer{X}.{Y}.downsample.conv->layer{X}.{Y}.downsample.0 + original_conv_name = name + '.0' + # layer{X}.{Y}.downsample.bn->layer{X}.{Y}.downsample.1 + original_bn_name = name + '.1' + else: + # layer{X}.{Y}.conv{n}.conv->layer{X}.{Y}.conv{n} + original_conv_name = name + # layer{X}.{Y}.conv{n}.bn->layer{X}.{Y}.bn{n} + original_bn_name = name.replace('conv', 'bn') + if original_conv_name + '.weight' not in state_dict_r2d: + logger.warning(f'Module not exist in the state_dict_r2d' + f': {original_conv_name}') + else: + self._inflate_conv_params(module.conv, state_dict_r2d, + original_conv_name, + inflated_param_names) + if original_bn_name + '.weight' not in state_dict_r2d: + logger.warning(f'Module not exist in the state_dict_r2d' + f': {original_bn_name}') + else: + self._inflate_bn_params(module.bn, state_dict_r2d, + original_bn_name, + inflated_param_names) + + # check if any parameters in the 2d checkpoint are not loaded + remaining_names = set( + state_dict_r2d.keys()) - set(inflated_param_names) + if remaining_names: + logger.info(f'These parameters in the 2d checkpoint are not loaded' + f': {remaining_names}') + + def _inflate_conv_params(self, conv3d, state_dict_2d, module_name_2d, + inflated_param_names): + """Inflate a conv module from 2d to 3d. + + The differences of conv modules betweene 2d and 3d in Pathway + mainly lie in the inplanes due to lateral connections. To fit the + shapes of the lateral connection counterpart, it will expand + parameters by concatting conv2d parameters and extra zero paddings. + + Args: + conv3d (nn.Module): The destination conv3d module. + state_dict_2d (OrderedDict): The state dict of pretrained 2d model. + module_name_2d (str): The name of corresponding conv module in the + 2d model. + inflated_param_names (list[str]): List of parameters that have been + inflated. + """ + weight_2d_name = module_name_2d + '.weight' + conv2d_weight = state_dict_2d[weight_2d_name] + old_shape = conv2d_weight.shape + new_shape = conv3d.weight.data.shape + kernel_t = new_shape[2] + + if new_shape[1] != old_shape[1]: + if new_shape[1] < old_shape[1]: + warnings.warn(f'The parameter of {module_name_2d} is not' + 'loaded due to incompatible shapes. ') + return + # Inplanes may be different due to lateral connections + new_channels = new_shape[1] - old_shape[1] + pad_shape = old_shape + pad_shape = pad_shape[:1] + (new_channels, ) + pad_shape[2:] + # Expand parameters by concat extra channels + conv2d_weight = torch.cat( + (conv2d_weight, + torch.zeros(pad_shape).type_as(conv2d_weight).to( + conv2d_weight.device)), + dim=1) + + new_weight = conv2d_weight.data.unsqueeze(2).expand_as( + conv3d.weight) / kernel_t + conv3d.weight.data.copy_(new_weight) + inflated_param_names.append(weight_2d_name) + + if getattr(conv3d, 'bias') is not None: + bias_2d_name = module_name_2d + '.bias' + conv3d.bias.data.copy_(state_dict_2d[bias_2d_name]) + inflated_param_names.append(bias_2d_name) + + def _freeze_stages(self): + """Prevent all the parameters from being optimized before + `self.frozen_stages`.""" + if self.frozen_stages >= 0: + self.conv1.eval() + for param in self.conv1.parameters(): + param.requires_grad = False + + for i in range(1, self.frozen_stages + 1): + m = getattr(self, f'layer{i}') + m.eval() + for param in m.parameters(): + param.requires_grad = False + + if i != len(self.res_layers) and self.lateral: + # No fusion needed in the final stage + lateral_name = self.lateral_connections[i - 1] + conv_lateral = getattr(self, lateral_name) + conv_lateral.eval() + for param in conv_lateral.parameters(): + param.requires_grad = False + + def init_weights(self, pretrained=None): + """Initiate the parameters either from existing checkpoint or from + scratch.""" + if pretrained: + self.pretrained = pretrained + + # Override the init_weights of i3d + super().init_weights() + for module_name in self.lateral_connections: + layer = getattr(self, module_name) + for m in layer.modules(): + if isinstance(m, (nn.Conv3d, nn.Conv2d)): + kaiming_init(m) + + +pathway_cfg = { + 'resnet3d': ResNet3dPathway, + # TODO: BNInceptionPathway +} + + +def build_pathway(cfg, *args, **kwargs): + """Build pathway. + + Args: + cfg (None or dict): cfg should contain: + - type (str): identify conv layer type. + + Returns: + nn.Module: Created pathway. + """ + if not (isinstance(cfg, dict) and 'type' in cfg): + raise TypeError('cfg must be a dict containing the key "type"') + cfg_ = cfg.copy() + + pathway_type = cfg_.pop('type') + if pathway_type not in pathway_cfg: + raise KeyError(f'Unrecognized pathway type {pathway_type}') + + pathway_cls = pathway_cfg[pathway_type] + pathway = pathway_cls(*args, **kwargs, **cfg_) + + return pathway + + +@BACKBONES.register_module() +class ResNet3dSlowFast(nn.Module): + """Slowfast backbone. + + This module is proposed in `SlowFast Networks for Video Recognition + `_ + + Args: + pretrained (str): The file path to a pretrained model. + resample_rate (int): A large temporal stride ``resample_rate`` + on input frames. The actual resample rate is calculated by + multipling the ``interval`` in ``SampleFrames`` in the + pipeline with ``resample_rate``, equivalent to the :math:`\\tau` + in the paper, i.e. it processes only one out of + ``resample_rate * interval`` frames. Default: 8. + speed_ratio (int): Speed ratio indicating the ratio between time + dimension of the fast and slow pathway, corresponding to the + :math:`\\alpha` in the paper. Default: 8. + channel_ratio (int): Reduce the channel number of fast pathway + by ``channel_ratio``, corresponding to :math:`\\beta` in the paper. + Default: 8. + slow_pathway (dict): Configuration of slow branch, should contain + necessary arguments for building the specific type of pathway + and: + type (str): type of backbone the pathway bases on. + lateral (bool): determine whether to build lateral connection + for the pathway.Default: + + .. code-block:: Python + + dict(type='ResNetPathway', + lateral=True, depth=50, pretrained=None, + conv1_kernel=(1, 7, 7), dilations=(1, 1, 1, 1), + conv1_stride_t=1, pool1_stride_t=1, inflate=(0, 0, 1, 1)) + + fast_pathway (dict): Configuration of fast branch, similar to + `slow_pathway`. Default: + + .. code-block:: Python + + dict(type='ResNetPathway', + lateral=False, depth=50, pretrained=None, base_channels=8, + conv1_kernel=(5, 7, 7), conv1_stride_t=1, pool1_stride_t=1) + """ + def __init__(self, + pretrained, + resample_rate=8, + speed_ratio=8, + channel_ratio=8, + slow_pathway=dict(type='resnet3d', + depth=50, + pretrained=None, + lateral=True, + conv1_kernel=(1, 7, 7), + dilations=(1, 1, 1, 1), + conv1_stride_t=1, + pool1_stride_t=1, + inflate=(0, 0, 1, 1)), + fast_pathway=dict(type='resnet3d', + depth=50, + pretrained=None, + lateral=False, + base_channels=8, + conv1_kernel=(5, 7, 7), + conv1_stride_t=1, + pool1_stride_t=1)): + super().__init__() + self.pretrained = pretrained + self.resample_rate = resample_rate + self.speed_ratio = speed_ratio + self.channel_ratio = channel_ratio + + if slow_pathway['lateral']: + slow_pathway['speed_ratio'] = speed_ratio + slow_pathway['channel_ratio'] = channel_ratio + + self.slow_path = build_pathway(slow_pathway) + self.fast_path = build_pathway(fast_pathway) + + def init_weights(self, pretrained=None): + """Initiate the parameters either from existing checkpoint or from + scratch.""" + if pretrained: + self.pretrained = pretrained + + if isinstance(self.pretrained, str): + logger = get_root_logger() + msg = f'load model from: {self.pretrained}' + print_log(msg, logger=logger) + # Directly load 3D model. + load_checkpoint(self, self.pretrained, strict=True, logger=logger) + elif self.pretrained is None: + # Init two branch seperately. + self.fast_path.init_weights() + self.slow_path.init_weights() + else: + raise TypeError('pretrained must be a str or None') + + def forward(self, x): + """Defines the computation performed at every call. + + Args: + x (torch.Tensor): The input data. + + Returns: + tuple[torch.Tensor]: The feature of the input samples extracted + by the backbone. + """ + x_slow = nn.functional.interpolate( + x, + mode='nearest', + scale_factor=(1.0 / self.resample_rate, 1.0, 1.0)) + x_slow = self.slow_path.conv1(x_slow) + x_slow = self.slow_path.maxpool(x_slow) + + x_fast = nn.functional.interpolate( + x, + mode='nearest', + scale_factor=(1.0 / (self.resample_rate // self.speed_ratio), 1.0, + 1.0)) + x_fast = self.fast_path.conv1(x_fast) + x_fast = self.fast_path.maxpool(x_fast) + + if self.slow_path.lateral: + x_fast_lateral = self.slow_path.conv1_lateral(x_fast) + x_slow = torch.cat((x_slow, x_fast_lateral), dim=1) + + for i, layer_name in enumerate(self.slow_path.res_layers): + res_layer = getattr(self.slow_path, layer_name) + x_slow = res_layer(x_slow) + res_layer_fast = getattr(self.fast_path, layer_name) + x_fast = res_layer_fast(x_fast) + if (i != len(self.slow_path.res_layers) - 1 + and self.slow_path.lateral): + # No fusion needed in the final stage + lateral_name = self.slow_path.lateral_connections[i] + conv_lateral = getattr(self.slow_path, lateral_name) + x_fast_lateral = conv_lateral(x_fast) + x_slow = torch.cat((x_slow, x_fast_lateral), dim=1) + + out = (x_slow, x_fast) + + return out + + +if mmdet_imported: + MMDET_BACKBONES.register_module()(ResNet3dSlowFast) diff --git a/PyTorch/contrib/cv/video/NonLocal/mmaction/models/heads/base.py b/PyTorch/contrib/cv/video/NonLocal/mmaction/models/heads/base.py index 8d165096e1..6343b3dd0f 100644 --- a/PyTorch/contrib/cv/video/NonLocal/mmaction/models/heads/base.py +++ b/PyTorch/contrib/cv/video/NonLocal/mmaction/models/heads/base.py @@ -1,122 +1,122 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 abc import ABCMeta, abstractmethod - -import torch -import torch.nn as nn - -from ...core import top_k_accuracy -from ..builder import build_loss - - -class AvgConsensus(nn.Module): - """Average consensus module. - - Args: - dim (int): Decide which dim consensus function to apply. - Default: 1. - """ - def __init__(self, dim=1): - super().__init__() - self.dim = dim - - def forward(self, x): - """Defines the computation performed at every call.""" - return x.mean(dim=self.dim, keepdim=True) - - -class BaseHead(nn.Module, metaclass=ABCMeta): - """Base class for head. - - All Head should subclass it. - All subclass should overwrite: - - Methods:``init_weights``, initializing weights in some modules. - - Methods:``forward``, supporting to forward both for training and testing. - - Args: - num_classes (int): Number of classes to be classified. - in_channels (int): Number of channels in input feature. - loss_cls (dict): Config for building loss. - Default: dict(type='CrossEntropyLoss', loss_weight=1.0). - multi_class (bool): Determines whether it is a multi-class - recognition task. Default: False. - label_smooth_eps (float): Epsilon used in label smooth. - Reference: arxiv.org/abs/1906.02629. Default: 0. - """ - def __init__(self, - num_classes, - in_channels, - loss_cls=dict(type='CrossEntropyLoss', loss_weight=1.0), - multi_class=False, - label_smooth_eps=0.0): - super().__init__() - self.num_classes = num_classes - self.in_channels = in_channels - self.loss_cls = build_loss(loss_cls) - self.multi_class = multi_class - self.label_smooth_eps = label_smooth_eps - - @abstractmethod - def init_weights(self): - """Initiate the parameters either from existing checkpoint or from - scratch.""" - - @abstractmethod - def forward(self, x): - """Defines the computation performed at every call.""" - - def loss(self, cls_score, labels, **kwargs): - """Calculate the loss given output ``cls_score``, target ``labels``. - - Args: - cls_score (torch.Tensor): The output of the model. - labels (torch.Tensor): The target output of the model. - - Returns: - dict: A dict containing field 'loss_cls'(mandatory) - and 'top1_acc', 'top5_acc'(optional). - """ - losses = dict() - if labels.shape == torch.Size([]): - labels = labels.unsqueeze(0) - elif labels.dim() == 1 and labels.size()[0] == self.num_classes \ - and cls_score.size()[0] == 1: - # Fix a bug when training with soft labels and batch size is 1. - # When using soft labels, `labels` and `cls_socre` share the same - # shape. - labels = labels.unsqueeze(0) - - if not self.multi_class and cls_score.size() != labels.size(): - top_k_acc = top_k_accuracy(cls_score.detach().cpu().numpy(), - labels.detach().cpu().numpy(), (1, 5)) - losses['top1_acc'] = torch.tensor(top_k_acc[0], - device=cls_score.device, - dtype=torch.float32) - losses['top5_acc'] = torch.tensor(top_k_acc[1], - device=cls_score.device, - dtype=torch.float32) - - elif self.multi_class and self.label_smooth_eps != 0: - labels = ((1 - self.label_smooth_eps) * labels + - self.label_smooth_eps / self.num_classes) - - loss_cls = self.loss_cls(cls_score, labels, **kwargs) - # loss_cls may be dictionary or single tensor - if isinstance(loss_cls, dict): - losses.update(loss_cls) - else: - losses['loss_cls'] = loss_cls - - return losses +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 abc import ABCMeta, abstractmethod + +import torch +import torch.nn as nn + +from ...core import top_k_accuracy +from ..builder import build_loss + + +class AvgConsensus(nn.Module): + """Average consensus module. + + Args: + dim (int): Decide which dim consensus function to apply. + Default: 1. + """ + def __init__(self, dim=1): + super().__init__() + self.dim = dim + + def forward(self, x): + """Defines the computation performed at every call.""" + return x.mean(dim=self.dim, keepdim=True) + + +class BaseHead(nn.Module, metaclass=ABCMeta): + """Base class for head. + + All Head should subclass it. + All subclass should overwrite: + - Methods:``init_weights``, initializing weights in some modules. + - Methods:``forward``, supporting to forward both for training and testing. + + Args: + num_classes (int): Number of classes to be classified. + in_channels (int): Number of channels in input feature. + loss_cls (dict): Config for building loss. + Default: dict(type='CrossEntropyLoss', loss_weight=1.0). + multi_class (bool): Determines whether it is a multi-class + recognition task. Default: False. + label_smooth_eps (float): Epsilon used in label smooth. + Reference: arxiv.org/abs/1906.02629. Default: 0. + """ + def __init__(self, + num_classes, + in_channels, + loss_cls=dict(type='CrossEntropyLoss', loss_weight=1.0), + multi_class=False, + label_smooth_eps=0.0): + super().__init__() + self.num_classes = num_classes + self.in_channels = in_channels + self.loss_cls = build_loss(loss_cls) + self.multi_class = multi_class + self.label_smooth_eps = label_smooth_eps + + @abstractmethod + def init_weights(self): + """Initiate the parameters either from existing checkpoint or from + scratch.""" + + @abstractmethod + def forward(self, x): + """Defines the computation performed at every call.""" + + def loss(self, cls_score, labels, **kwargs): + """Calculate the loss given output ``cls_score``, target ``labels``. + + Args: + cls_score (torch.Tensor): The output of the model. + labels (torch.Tensor): The target output of the model. + + Returns: + dict: A dict containing field 'loss_cls'(mandatory) + and 'top1_acc', 'top5_acc'(optional). + """ + losses = dict() + if labels.shape == torch.Size([]): + labels = labels.unsqueeze(0) + elif labels.dim() == 1 and labels.size()[0] == self.num_classes \ + and cls_score.size()[0] == 1: + # Fix a bug when training with soft labels and batch size is 1. + # When using soft labels, `labels` and `cls_socre` share the same + # shape. + labels = labels.unsqueeze(0) + + if not self.multi_class and cls_score.size() != labels.size(): + top_k_acc = top_k_accuracy(cls_score.detach().cpu().numpy(), + labels.detach().cpu().numpy(), (1, 5)) + losses['top1_acc'] = torch.tensor(top_k_acc[0], + device=cls_score.device, + dtype=torch.float32) + losses['top5_acc'] = torch.tensor(top_k_acc[1], + device=cls_score.device, + dtype=torch.float32) + + elif self.multi_class and self.label_smooth_eps != 0: + labels = ((1 - self.label_smooth_eps) * labels + + self.label_smooth_eps / self.num_classes) + + loss_cls = self.loss_cls(cls_score, labels, **kwargs) + # loss_cls may be dictionary or single tensor + if isinstance(loss_cls, dict): + losses.update(loss_cls) + else: + losses['loss_cls'] = loss_cls + + return losses diff --git a/PyTorch/contrib/cv/video/NonLocal/mmaction/models/heads/slowfast_head.py b/PyTorch/contrib/cv/video/NonLocal/mmaction/models/heads/slowfast_head.py index 30c3590fa9..31de953e26 100644 --- a/PyTorch/contrib/cv/video/NonLocal/mmaction/models/heads/slowfast_head.py +++ b/PyTorch/contrib/cv/video/NonLocal/mmaction/models/heads/slowfast_head.py @@ -1,92 +1,92 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch -import torch.nn as nn -from mmcv.cnn import normal_init - -from ..builder import HEADS -from .base import BaseHead - - -@HEADS.register_module() -class SlowFastHead(BaseHead): - """The classification head for SlowFast. - - Args: - num_classes (int): Number of classes to be classified. - in_channels (int): Number of channels in input feature. - loss_cls (dict): Config for building loss. - Default: dict(type='CrossEntropyLoss'). - spatial_type (str): Pooling type in spatial dimension. Default: 'avg'. - dropout_ratio (float): Probability of dropout layer. Default: 0.8. - init_std (float): Std value for Initiation. Default: 0.01. - kwargs (dict, optional): Any keyword argument to be used to initialize - the head. - """ - def __init__(self, - num_classes, - in_channels, - loss_cls=dict(type='CrossEntropyLoss'), - spatial_type='avg', - dropout_ratio=0.8, - init_std=0.01, - **kwargs): - - super().__init__(num_classes, in_channels, loss_cls, **kwargs) - self.spatial_type = spatial_type - self.dropout_ratio = dropout_ratio - self.init_std = init_std - - if self.dropout_ratio != 0: - self.dropout = nn.Dropout(p=self.dropout_ratio) - else: - self.dropout = None - self.fc_cls = nn.Linear(in_channels, num_classes) - - if self.spatial_type == 'avg': - self.avg_pool = nn.AdaptiveAvgPool3d((1, 1, 1)) - else: - self.avg_pool = None - - def init_weights(self): - """Initiate the parameters from scratch.""" - normal_init(self.fc_cls, std=self.init_std) - - def forward(self, x): - """Defines the computation performed at every call. - - Args: - x (torch.Tensor): The input data. - - Returns: - torch.Tensor: The classification scores for input samples. - """ - # ([N, channel_fast, T, H, W], [(N, channel_slow, T, H, W)]) - x_fast, x_slow = x - # ([N, channel_fast, 1, 1, 1], [N, channel_slow, 1, 1, 1]) - x_fast = self.avg_pool(x_fast) - x_slow = self.avg_pool(x_slow) - # [N, channel_fast + channel_slow, 1, 1, 1] - x = torch.cat((x_slow, x_fast), dim=1) - - if self.dropout is not None: - x = self.dropout(x) - - # [N x C] - x = x.view(x.size(0), -1) - # [N x num_classes] - cls_score = self.fc_cls(x) - - return cls_score.npu_format_cast(0) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch +import torch.nn as nn +from mmcv.cnn import normal_init + +from ..builder import HEADS +from .base import BaseHead + + +@HEADS.register_module() +class SlowFastHead(BaseHead): + """The classification head for SlowFast. + + Args: + num_classes (int): Number of classes to be classified. + in_channels (int): Number of channels in input feature. + loss_cls (dict): Config for building loss. + Default: dict(type='CrossEntropyLoss'). + spatial_type (str): Pooling type in spatial dimension. Default: 'avg'. + dropout_ratio (float): Probability of dropout layer. Default: 0.8. + init_std (float): Std value for Initiation. Default: 0.01. + kwargs (dict, optional): Any keyword argument to be used to initialize + the head. + """ + def __init__(self, + num_classes, + in_channels, + loss_cls=dict(type='CrossEntropyLoss'), + spatial_type='avg', + dropout_ratio=0.8, + init_std=0.01, + **kwargs): + + super().__init__(num_classes, in_channels, loss_cls, **kwargs) + self.spatial_type = spatial_type + self.dropout_ratio = dropout_ratio + self.init_std = init_std + + if self.dropout_ratio != 0: + self.dropout = nn.Dropout(p=self.dropout_ratio) + else: + self.dropout = None + self.fc_cls = nn.Linear(in_channels, num_classes) + + if self.spatial_type == 'avg': + self.avg_pool = nn.AdaptiveAvgPool3d((1, 1, 1)) + else: + self.avg_pool = None + + def init_weights(self): + """Initiate the parameters from scratch.""" + normal_init(self.fc_cls, std=self.init_std) + + def forward(self, x): + """Defines the computation performed at every call. + + Args: + x (torch.Tensor): The input data. + + Returns: + torch.Tensor: The classification scores for input samples. + """ + # ([N, channel_fast, T, H, W], [(N, channel_slow, T, H, W)]) + x_fast, x_slow = x + # ([N, channel_fast, 1, 1, 1], [N, channel_slow, 1, 1, 1]) + x_fast = self.avg_pool(x_fast) + x_slow = self.avg_pool(x_slow) + # [N, channel_fast + channel_slow, 1, 1, 1] + x = torch.cat((x_slow, x_fast), dim=1) + + if self.dropout is not None: + x = self.dropout(x) + + # [N x C] + x = x.view(x.size(0), -1) + # [N x num_classes] + cls_score = self.fc_cls(x) + + return cls_score.npu_format_cast(0) diff --git a/PyTorch/contrib/cv/video/NonLocal/mmaction/models/losses/cross_entropy_loss.py b/PyTorch/contrib/cv/video/NonLocal/mmaction/models/losses/cross_entropy_loss.py index 11c9bfd4dd..a0afe4232c 100644 --- a/PyTorch/contrib/cv/video/NonLocal/mmaction/models/losses/cross_entropy_loss.py +++ b/PyTorch/contrib/cv/video/NonLocal/mmaction/models/losses/cross_entropy_loss.py @@ -1,133 +1,133 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch -import torch.nn.functional as F - -from ..builder import LOSSES -from .base import BaseWeightedLoss - - -@LOSSES.register_module() -class CrossEntropyLoss(BaseWeightedLoss): - """Cross Entropy Loss. - - Support two kinds of labels and their corresponding loss type. It's worth - mentioning that loss type will be detected by the shape of ``cls_score`` - and ``label``. - 1) Hard label: This label is an integer array and all of the elements are - in the range [0, num_classes - 1]. This label's shape should be - ``cls_score``'s shape with the `num_classes` dimension removed. - 2) Soft label(probablity distribution over classes): This label is a - probability distribution and all of the elements are in the range - [0, 1]. This label's shape must be the same as ``cls_score``. For now, - only 2-dim soft label is supported. - - Args: - loss_weight (float): Factor scalar multiplied on the loss. - Default: 1.0. - class_weight (list[float] | None): Loss weight for each class. If set - as None, use the same weight 1 for all classes. Only applies - to CrossEntropyLoss and BCELossWithLogits (should not be set when - using other losses). Default: None. - """ - def __init__(self, loss_weight=1.0, class_weight=None): - super().__init__(loss_weight=loss_weight) - self.class_weight = None - if class_weight is not None: - self.class_weight = torch.Tensor(class_weight) - - def _forward(self, cls_score, label, **kwargs): - """Forward function. - - Args: - cls_score (torch.Tensor): The class score. - label (torch.Tensor): The ground truth label. - kwargs: Any keyword argument to be used to calculate - CrossEntropy loss. - - Returns: - torch.Tensor: The returned CrossEntropy loss. - """ - if cls_score.size() == label.size(): - # calculate loss for soft label - - assert cls_score.dim() == 2, 'Only support 2-dim soft label' - assert len(kwargs) == 0, \ - ('For now, no extra args are supported for soft label, ' - f'but get {kwargs}') - - lsm = F.log_softmax(cls_score, 1) - if self.class_weight is not None: - lsm = lsm * self.class_weight.unsqueeze(0) - loss_cls = -(label * lsm).sum(1) - - # default reduction 'mean' - if self.class_weight is not None: - # Use weighted average as pytorch CrossEntropyLoss does. - # For more information, please visit https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html # noqa - loss_cls = loss_cls.sum() / torch.sum( - self.class_weight.unsqueeze(0) * label) - else: - loss_cls = loss_cls.mean() - else: - # calculate loss for hard label - - if self.class_weight is not None: - assert 'weight' not in kwargs, \ - "The key 'weight' already exists." - kwargs['weight'] = self.class_weight.to(cls_score.device) - # cls_score = cls_score.type(torch.float32) - # label = label.type(torch.int32) - loss_cls = F.cross_entropy(cls_score, label, **kwargs) - - return loss_cls - - -@LOSSES.register_module() -class BCELossWithLogits(BaseWeightedLoss): - """Binary Cross Entropy Loss with logits. - - Args: - loss_weight (float): Factor scalar multiplied on the loss. - Default: 1.0. - class_weight (list[float] | None): Loss weight for each class. If set - as None, use the same weight 1 for all classes. Only applies - to CrossEntropyLoss and BCELossWithLogits (should not be set when - using other losses). Default: None. - """ - def __init__(self, loss_weight=1.0, class_weight=None): - super().__init__(loss_weight=loss_weight) - self.class_weight = None - if class_weight is not None: - self.class_weight = torch.Tensor(class_weight) - - def _forward(self, cls_score, label, **kwargs): - """Forward function. - - Args: - cls_score (torch.Tensor): The class score. - label (torch.Tensor): The ground truth label. - kwargs: Any keyword argument to be used to calculate - bce loss with logits. - - Returns: - torch.Tensor: The returned bce loss with logits. - """ - if self.class_weight is not None: - assert 'weight' not in kwargs, "The key 'weight' already exists." - kwargs['weight'] = self.class_weight.to(cls_score.device) - loss_cls = F.binary_cross_entropy_with_logits(cls_score, label, - **kwargs) - return loss_cls +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch +import torch.nn.functional as F + +from ..builder import LOSSES +from .base import BaseWeightedLoss + + +@LOSSES.register_module() +class CrossEntropyLoss(BaseWeightedLoss): + """Cross Entropy Loss. + + Support two kinds of labels and their corresponding loss type. It's worth + mentioning that loss type will be detected by the shape of ``cls_score`` + and ``label``. + 1) Hard label: This label is an integer array and all of the elements are + in the range [0, num_classes - 1]. This label's shape should be + ``cls_score``'s shape with the `num_classes` dimension removed. + 2) Soft label(probablity distribution over classes): This label is a + probability distribution and all of the elements are in the range + [0, 1]. This label's shape must be the same as ``cls_score``. For now, + only 2-dim soft label is supported. + + Args: + loss_weight (float): Factor scalar multiplied on the loss. + Default: 1.0. + class_weight (list[float] | None): Loss weight for each class. If set + as None, use the same weight 1 for all classes. Only applies + to CrossEntropyLoss and BCELossWithLogits (should not be set when + using other losses). Default: None. + """ + def __init__(self, loss_weight=1.0, class_weight=None): + super().__init__(loss_weight=loss_weight) + self.class_weight = None + if class_weight is not None: + self.class_weight = torch.Tensor(class_weight) + + def _forward(self, cls_score, label, **kwargs): + """Forward function. + + Args: + cls_score (torch.Tensor): The class score. + label (torch.Tensor): The ground truth label. + kwargs: Any keyword argument to be used to calculate + CrossEntropy loss. + + Returns: + torch.Tensor: The returned CrossEntropy loss. + """ + if cls_score.size() == label.size(): + # calculate loss for soft label + + assert cls_score.dim() == 2, 'Only support 2-dim soft label' + assert len(kwargs) == 0, \ + ('For now, no extra args are supported for soft label, ' + f'but get {kwargs}') + + lsm = F.log_softmax(cls_score, 1) + if self.class_weight is not None: + lsm = lsm * self.class_weight.unsqueeze(0) + loss_cls = -(label * lsm).sum(1) + + # default reduction 'mean' + if self.class_weight is not None: + # Use weighted average as pytorch CrossEntropyLoss does. + # For more information, please visit https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html # noqa + loss_cls = loss_cls.sum() / torch.sum( + self.class_weight.unsqueeze(0) * label) + else: + loss_cls = loss_cls.mean() + else: + # calculate loss for hard label + + if self.class_weight is not None: + assert 'weight' not in kwargs, \ + "The key 'weight' already exists." + kwargs['weight'] = self.class_weight.to(cls_score.device) + # cls_score = cls_score.type(torch.float32) + # label = label.type(torch.int32) + loss_cls = F.cross_entropy(cls_score, label, **kwargs) + + return loss_cls + + +@LOSSES.register_module() +class BCELossWithLogits(BaseWeightedLoss): + """Binary Cross Entropy Loss with logits. + + Args: + loss_weight (float): Factor scalar multiplied on the loss. + Default: 1.0. + class_weight (list[float] | None): Loss weight for each class. If set + as None, use the same weight 1 for all classes. Only applies + to CrossEntropyLoss and BCELossWithLogits (should not be set when + using other losses). Default: None. + """ + def __init__(self, loss_weight=1.0, class_weight=None): + super().__init__(loss_weight=loss_weight) + self.class_weight = None + if class_weight is not None: + self.class_weight = torch.Tensor(class_weight) + + def _forward(self, cls_score, label, **kwargs): + """Forward function. + + Args: + cls_score (torch.Tensor): The class score. + label (torch.Tensor): The ground truth label. + kwargs: Any keyword argument to be used to calculate + bce loss with logits. + + Returns: + torch.Tensor: The returned bce loss with logits. + """ + if self.class_weight is not None: + assert 'weight' not in kwargs, "The key 'weight' already exists." + kwargs['weight'] = self.class_weight.to(cls_score.device) + loss_cls = F.binary_cross_entropy_with_logits(cls_score, label, + **kwargs) + return loss_cls diff --git a/PyTorch/contrib/cv/video/NonLocal/mmaction/models/recognizers/base.py b/PyTorch/contrib/cv/video/NonLocal/mmaction/models/recognizers/base.py index 35603218ba..b7a0c527ec 100644 --- a/PyTorch/contrib/cv/video/NonLocal/mmaction/models/recognizers/base.py +++ b/PyTorch/contrib/cv/video/NonLocal/mmaction/models/recognizers/base.py @@ -1,339 +1,339 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 warnings -from abc import ABCMeta, abstractmethod -from collections import OrderedDict - -import torch -import torch.distributed as dist -import torch.nn as nn -import torch.nn.functional as F -from mmcv.runner import auto_fp16 - -from .. import builder - - -class BaseRecognizer(nn.Module, metaclass=ABCMeta): - """Base class for recognizers. - - All recognizers should subclass it. - All subclass should overwrite: - - - Methods:``forward_train``, supporting to forward when training. - - Methods:``forward_test``, supporting to forward when testing. - - Args: - backbone (dict): Backbone modules to extract feature. - cls_head (dict | None): Classification head to process feature. - Default: None. - neck (dict | None): Neck for feature fusion. Default: None. - train_cfg (dict | None): Config for training. Default: None. - test_cfg (dict | None): Config for testing. Default: None. - """ - def __init__(self, - backbone, - cls_head=None, - neck=None, - train_cfg=None, - test_cfg=None): - super().__init__() - # record the source of the backbone - self.backbone_from = 'mmaction2' - - if backbone['type'].startswith('mmcls.'): - try: - import mmcls.models.builder as mmcls_builder - except (ImportError, ModuleNotFoundError): - raise ImportError('Please install mmcls to use this backbone.') - backbone['type'] = backbone['type'][6:] - self.backbone = mmcls_builder.build_backbone(backbone) - self.backbone_from = 'mmcls' - elif backbone['type'].startswith('torchvision.'): - try: - import torchvision.models - except (ImportError, ModuleNotFoundError): - raise ImportError('Please install torchvision to use this ' - 'backbone.') - backbone_type = backbone.pop('type')[12:] - self.backbone = torchvision.models.__dict__[backbone_type]( - **backbone) - # disable the classifier - self.backbone.classifier = nn.Identity() - self.backbone.fc = nn.Identity() - self.backbone_from = 'torchvision' - elif backbone['type'].startswith('timm.'): - try: - import timm - except (ImportError, ModuleNotFoundError): - raise ImportError('Please install timm to use this ' - 'backbone.') - backbone_type = backbone.pop('type')[5:] - # disable the classifier - backbone['num_classes'] = 0 - self.backbone = timm.create_model(backbone_type, **backbone) - self.backbone_from = 'timm' - else: - self.backbone = builder.build_backbone(backbone) - - if neck is not None: - self.neck = builder.build_neck(neck) - - self.cls_head = builder.build_head(cls_head) if cls_head else None - - self.train_cfg = train_cfg - self.test_cfg = test_cfg - - # aux_info is the list of tensor names beyond 'imgs' and 'label' which - # will be used in train_step and val_step, data_batch should contain - # these tensors - self.aux_info = [] - if train_cfg is not None and 'aux_info' in train_cfg: - self.aux_info = train_cfg['aux_info'] - # max_testing_views should be int - self.max_testing_views = None - if test_cfg is not None and 'max_testing_views' in test_cfg: - self.max_testing_views = test_cfg['max_testing_views'] - assert isinstance(self.max_testing_views, int) - - if test_cfg is not None and 'feature_extraction' in test_cfg: - self.feature_extraction = test_cfg['feature_extraction'] - else: - self.feature_extraction = False - - # mini-batch blending, e.g. mixup, cutmix, etc. - self.blending = None - if train_cfg is not None and 'blending' in train_cfg: - from mmcv.utils import build_from_cfg - from mmaction.datasets.builder import BLENDINGS - self.blending = build_from_cfg(train_cfg['blending'], BLENDINGS) - - self.init_weights() - - self.fp16_enabled = False - - @property - def with_neck(self): - """bool: whether the recognizer has a neck""" - return hasattr(self, 'neck') and self.neck is not None - - @property - def with_cls_head(self): - """bool: whether the recognizer has a cls_head""" - return hasattr(self, 'cls_head') and self.cls_head is not None - - def init_weights(self): - """Initialize the model network weights.""" - if self.backbone_from in ['mmcls', 'mmaction2']: - self.backbone.init_weights() - elif self.backbone_from in ['torchvision', 'timm']: - warnings.warn('We do not initialize weights for backbones in ' - f'{self.backbone_from}, since the weights for ' - f'backbones in {self.backbone_from} are initialized' - 'in their __init__ functions.') - else: - raise NotImplementedError('Unsupported backbone source ' - f'{self.backbone_from}!') - - if self.with_cls_head: - self.cls_head.init_weights() - if self.with_neck: - self.neck.init_weights() - - @auto_fp16() - def extract_feat(self, imgs): - """Extract features through a backbone. - - Args: - imgs (torch.Tensor): The input images. - - Returns: - torch.tensor: The extracted features. - """ - if (hasattr(self.backbone, 'features') - and self.backbone_from == 'torchvision'): - x = self.backbone.features(imgs) - elif self.backbone_from == 'timm': - x = self.backbone.forward_features(imgs) - else: - x = self.backbone(imgs) - return x - - def average_clip(self, cls_score, num_segs=1): - """Averaging class score over multiple clips. - - Using different averaging types ('score' or 'prob' or None, - which defined in test_cfg) to computed the final averaged - class score. Only called in test mode. - - Args: - cls_score (torch.Tensor): Class score to be averaged. - num_segs (int): Number of clips for each input sample. - - Returns: - torch.Tensor: Averaged class score. - """ - if 'average_clips' not in self.test_cfg.keys(): - raise KeyError('"average_clips" must defined in test_cfg\'s keys') - - average_clips = self.test_cfg['average_clips'] - if average_clips not in ['score', 'prob', None]: - raise ValueError(f'{average_clips} is not supported. ' - f'Currently supported ones are ' - f'["score", "prob", None]') - - if average_clips is None: - return cls_score - - batch_size = cls_score.shape[0] - cls_score = cls_score.view(batch_size // num_segs, num_segs, -1) - - if average_clips == 'prob': - cls_score = F.softmax(cls_score, dim=2).mean(dim=1) - elif average_clips == 'score': - cls_score = cls_score.mean(dim=1) - - return cls_score - - @abstractmethod - def forward_train(self, imgs, labels, **kwargs): - """Defines the computation performed at every call when training.""" - - @abstractmethod - def forward_test(self, imgs): - """Defines the computation performed at every call when evaluation and - testing.""" - - @abstractmethod - def forward_gradcam(self, imgs): - """Defines the computation performed at every all when using gradcam - utils.""" - - @staticmethod - def _parse_losses(losses): - """Parse the raw outputs (losses) of the network. - - Args: - losses (dict): Raw output of the network, which usually contain - losses and other necessary information. - - Returns: - tuple[Tensor, dict]: (loss, log_vars), loss is the loss tensor - which may be a weighted sum of all losses, log_vars contains - all the variables to be sent to the logger. - """ - log_vars = OrderedDict() - for loss_name, loss_value in losses.items(): - if isinstance(loss_value, torch.Tensor): - log_vars[loss_name] = loss_value.mean() - elif isinstance(loss_value, list): - log_vars[loss_name] = sum(_loss.mean() for _loss in loss_value) - else: - raise TypeError( - f'{loss_name} is not a tensor or list of tensors') - - loss = sum(_value for _key, _value in log_vars.items() - if 'loss' in _key) - - log_vars['loss'] = loss - for loss_name, loss_value in log_vars.items(): - # reduce loss when distributed training - if dist.is_available() and dist.is_initialized(): - loss_value = loss_value.data.clone() - dist.all_reduce(loss_value.div_(dist.get_world_size())) - log_vars[loss_name] = loss_value.item() - - return loss, log_vars - - def forward(self, imgs, label=None, return_loss=True, **kwargs): - """Define the computation performed at every call.""" - if kwargs.get('gradcam', False): - del kwargs['gradcam'] - return self.forward_gradcam(imgs, **kwargs) - if return_loss: - if label is None: - raise ValueError('Label should not be None.') - if self.blending is not None: - imgs, label = self.blending(imgs, label) - return self.forward_train(imgs, label, **kwargs) - - return self.forward_test(imgs, **kwargs) - - def train_step(self, data_batch, optimizer, **kwargs): - """The iteration step during training. - - This method defines an iteration step during training, except for the - back propagation and optimizer updating, which are done in an optimizer - hook. Note that in some complicated cases or models, the whole process - including back propagation and optimizer updating is also defined in - this method, such as GAN. - - Args: - data_batch (dict): The output of dataloader. - optimizer (:obj:`torch.optim.Optimizer` | dict): The optimizer of - runner is passed to ``train_step()``. This argument is unused - and reserved. - - Returns: - dict: It should contain at least 3 keys: ``loss``, ``log_vars``, - ``num_samples``. - ``loss`` is a tensor for back propagation, which can be a - weighted sum of multiple losses. - ``log_vars`` contains all the variables to be sent to the - logger. - ``num_samples`` indicates the batch size (when the model is - DDP, it means the batch size on each GPU), which is used for - averaging the logs. - """ - imgs = data_batch['imgs'].npu().type(torch.float32) - label = data_batch['label'].npu().type(torch.int32) - - aux_info = {} - for item in self.aux_info: - assert item in data_batch - aux_info[item] = data_batch[item] - - losses = self(imgs, label, return_loss=True, **aux_info) - - loss, log_vars = self._parse_losses(losses) - - outputs = dict(loss=loss, - log_vars=log_vars, - num_samples=len(next(iter(data_batch.values())))) - - return outputs - - def val_step(self, data_batch, optimizer, **kwargs): - """The iteration step during validation. - - This method shares the same signature as :func:`train_step`, but used - during val epochs. Note that the evaluation after training epochs is - not implemented with this method, but an evaluation hook. - """ - imgs = data_batch['imgs'].npu().type(torch.float32) - label = data_batch['label'].npu().type(torch.int32) - - aux_info = {} - for item in self.aux_info: - aux_info[item] = data_batch[item] - - losses = self(imgs, label, return_loss=True, **aux_info) - - loss, log_vars = self._parse_losses(losses) - - outputs = dict(loss=loss, - log_vars=log_vars, - num_samples=len(next(iter(data_batch.values())))) - - return outputs +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 warnings +from abc import ABCMeta, abstractmethod +from collections import OrderedDict + +import torch +import torch.distributed as dist +import torch.nn as nn +import torch.nn.functional as F +from mmcv.runner import auto_fp16 + +from .. import builder + + +class BaseRecognizer(nn.Module, metaclass=ABCMeta): + """Base class for recognizers. + + All recognizers should subclass it. + All subclass should overwrite: + + - Methods:``forward_train``, supporting to forward when training. + - Methods:``forward_test``, supporting to forward when testing. + + Args: + backbone (dict): Backbone modules to extract feature. + cls_head (dict | None): Classification head to process feature. + Default: None. + neck (dict | None): Neck for feature fusion. Default: None. + train_cfg (dict | None): Config for training. Default: None. + test_cfg (dict | None): Config for testing. Default: None. + """ + def __init__(self, + backbone, + cls_head=None, + neck=None, + train_cfg=None, + test_cfg=None): + super().__init__() + # record the source of the backbone + self.backbone_from = 'mmaction2' + + if backbone['type'].startswith('mmcls.'): + try: + import mmcls.models.builder as mmcls_builder + except (ImportError, ModuleNotFoundError): + raise ImportError('Please install mmcls to use this backbone.') + backbone['type'] = backbone['type'][6:] + self.backbone = mmcls_builder.build_backbone(backbone) + self.backbone_from = 'mmcls' + elif backbone['type'].startswith('torchvision.'): + try: + import torchvision.models + except (ImportError, ModuleNotFoundError): + raise ImportError('Please install torchvision to use this ' + 'backbone.') + backbone_type = backbone.pop('type')[12:] + self.backbone = torchvision.models.__dict__[backbone_type]( + **backbone) + # disable the classifier + self.backbone.classifier = nn.Identity() + self.backbone.fc = nn.Identity() + self.backbone_from = 'torchvision' + elif backbone['type'].startswith('timm.'): + try: + import timm + except (ImportError, ModuleNotFoundError): + raise ImportError('Please install timm to use this ' + 'backbone.') + backbone_type = backbone.pop('type')[5:] + # disable the classifier + backbone['num_classes'] = 0 + self.backbone = timm.create_model(backbone_type, **backbone) + self.backbone_from = 'timm' + else: + self.backbone = builder.build_backbone(backbone) + + if neck is not None: + self.neck = builder.build_neck(neck) + + self.cls_head = builder.build_head(cls_head) if cls_head else None + + self.train_cfg = train_cfg + self.test_cfg = test_cfg + + # aux_info is the list of tensor names beyond 'imgs' and 'label' which + # will be used in train_step and val_step, data_batch should contain + # these tensors + self.aux_info = [] + if train_cfg is not None and 'aux_info' in train_cfg: + self.aux_info = train_cfg['aux_info'] + # max_testing_views should be int + self.max_testing_views = None + if test_cfg is not None and 'max_testing_views' in test_cfg: + self.max_testing_views = test_cfg['max_testing_views'] + assert isinstance(self.max_testing_views, int) + + if test_cfg is not None and 'feature_extraction' in test_cfg: + self.feature_extraction = test_cfg['feature_extraction'] + else: + self.feature_extraction = False + + # mini-batch blending, e.g. mixup, cutmix, etc. + self.blending = None + if train_cfg is not None and 'blending' in train_cfg: + from mmcv.utils import build_from_cfg + from mmaction.datasets.builder import BLENDINGS + self.blending = build_from_cfg(train_cfg['blending'], BLENDINGS) + + self.init_weights() + + self.fp16_enabled = False + + @property + def with_neck(self): + """bool: whether the recognizer has a neck""" + return hasattr(self, 'neck') and self.neck is not None + + @property + def with_cls_head(self): + """bool: whether the recognizer has a cls_head""" + return hasattr(self, 'cls_head') and self.cls_head is not None + + def init_weights(self): + """Initialize the model network weights.""" + if self.backbone_from in ['mmcls', 'mmaction2']: + self.backbone.init_weights() + elif self.backbone_from in ['torchvision', 'timm']: + warnings.warn('We do not initialize weights for backbones in ' + f'{self.backbone_from}, since the weights for ' + f'backbones in {self.backbone_from} are initialized' + 'in their __init__ functions.') + else: + raise NotImplementedError('Unsupported backbone source ' + f'{self.backbone_from}!') + + if self.with_cls_head: + self.cls_head.init_weights() + if self.with_neck: + self.neck.init_weights() + + @auto_fp16() + def extract_feat(self, imgs): + """Extract features through a backbone. + + Args: + imgs (torch.Tensor): The input images. + + Returns: + torch.tensor: The extracted features. + """ + if (hasattr(self.backbone, 'features') + and self.backbone_from == 'torchvision'): + x = self.backbone.features(imgs) + elif self.backbone_from == 'timm': + x = self.backbone.forward_features(imgs) + else: + x = self.backbone(imgs) + return x + + def average_clip(self, cls_score, num_segs=1): + """Averaging class score over multiple clips. + + Using different averaging types ('score' or 'prob' or None, + which defined in test_cfg) to computed the final averaged + class score. Only called in test mode. + + Args: + cls_score (torch.Tensor): Class score to be averaged. + num_segs (int): Number of clips for each input sample. + + Returns: + torch.Tensor: Averaged class score. + """ + if 'average_clips' not in self.test_cfg.keys(): + raise KeyError('"average_clips" must defined in test_cfg\'s keys') + + average_clips = self.test_cfg['average_clips'] + if average_clips not in ['score', 'prob', None]: + raise ValueError(f'{average_clips} is not supported. ' + f'Currently supported ones are ' + f'["score", "prob", None]') + + if average_clips is None: + return cls_score + + batch_size = cls_score.shape[0] + cls_score = cls_score.view(batch_size // num_segs, num_segs, -1) + + if average_clips == 'prob': + cls_score = F.softmax(cls_score, dim=2).mean(dim=1) + elif average_clips == 'score': + cls_score = cls_score.mean(dim=1) + + return cls_score + + @abstractmethod + def forward_train(self, imgs, labels, **kwargs): + """Defines the computation performed at every call when training.""" + + @abstractmethod + def forward_test(self, imgs): + """Defines the computation performed at every call when evaluation and + testing.""" + + @abstractmethod + def forward_gradcam(self, imgs): + """Defines the computation performed at every all when using gradcam + utils.""" + + @staticmethod + def _parse_losses(losses): + """Parse the raw outputs (losses) of the network. + + Args: + losses (dict): Raw output of the network, which usually contain + losses and other necessary information. + + Returns: + tuple[Tensor, dict]: (loss, log_vars), loss is the loss tensor + which may be a weighted sum of all losses, log_vars contains + all the variables to be sent to the logger. + """ + log_vars = OrderedDict() + for loss_name, loss_value in losses.items(): + if isinstance(loss_value, torch.Tensor): + log_vars[loss_name] = loss_value.mean() + elif isinstance(loss_value, list): + log_vars[loss_name] = sum(_loss.mean() for _loss in loss_value) + else: + raise TypeError( + f'{loss_name} is not a tensor or list of tensors') + + loss = sum(_value for _key, _value in log_vars.items() + if 'loss' in _key) + + log_vars['loss'] = loss + for loss_name, loss_value in log_vars.items(): + # reduce loss when distributed training + if dist.is_available() and dist.is_initialized(): + loss_value = loss_value.data.clone() + dist.all_reduce(loss_value.div_(dist.get_world_size())) + log_vars[loss_name] = loss_value.item() + + return loss, log_vars + + def forward(self, imgs, label=None, return_loss=True, **kwargs): + """Define the computation performed at every call.""" + if kwargs.get('gradcam', False): + del kwargs['gradcam'] + return self.forward_gradcam(imgs, **kwargs) + if return_loss: + if label is None: + raise ValueError('Label should not be None.') + if self.blending is not None: + imgs, label = self.blending(imgs, label) + return self.forward_train(imgs, label, **kwargs) + + return self.forward_test(imgs, **kwargs) + + def train_step(self, data_batch, optimizer, **kwargs): + """The iteration step during training. + + This method defines an iteration step during training, except for the + back propagation and optimizer updating, which are done in an optimizer + hook. Note that in some complicated cases or models, the whole process + including back propagation and optimizer updating is also defined in + this method, such as GAN. + + Args: + data_batch (dict): The output of dataloader. + optimizer (:obj:`torch.optim.Optimizer` | dict): The optimizer of + runner is passed to ``train_step()``. This argument is unused + and reserved. + + Returns: + dict: It should contain at least 3 keys: ``loss``, ``log_vars``, + ``num_samples``. + ``loss`` is a tensor for back propagation, which can be a + weighted sum of multiple losses. + ``log_vars`` contains all the variables to be sent to the + logger. + ``num_samples`` indicates the batch size (when the model is + DDP, it means the batch size on each GPU), which is used for + averaging the logs. + """ + imgs = data_batch['imgs'].npu().type(torch.float32) + label = data_batch['label'].npu().type(torch.int32) + + aux_info = {} + for item in self.aux_info: + assert item in data_batch + aux_info[item] = data_batch[item] + + losses = self(imgs, label, return_loss=True, **aux_info) + + loss, log_vars = self._parse_losses(losses) + + outputs = dict(loss=loss, + log_vars=log_vars, + num_samples=len(next(iter(data_batch.values())))) + + return outputs + + def val_step(self, data_batch, optimizer, **kwargs): + """The iteration step during validation. + + This method shares the same signature as :func:`train_step`, but used + during val epochs. Note that the evaluation after training epochs is + not implemented with this method, but an evaluation hook. + """ + imgs = data_batch['imgs'].npu().type(torch.float32) + label = data_batch['label'].npu().type(torch.int32) + + aux_info = {} + for item in self.aux_info: + aux_info[item] = data_batch[item] + + losses = self(imgs, label, return_loss=True, **aux_info) + + loss, log_vars = self._parse_losses(losses) + + outputs = dict(loss=loss, + log_vars=log_vars, + num_samples=len(next(iter(data_batch.values())))) + + return outputs diff --git a/PyTorch/contrib/cv/video/NonLocal/mmaction/models/recognizers/recognizer2d.py b/PyTorch/contrib/cv/video/NonLocal/mmaction/models/recognizers/recognizer2d.py index 7d145f6dd8..3d9a755a5a 100644 --- a/PyTorch/contrib/cv/video/NonLocal/mmaction/models/recognizers/recognizer2d.py +++ b/PyTorch/contrib/cv/video/NonLocal/mmaction/models/recognizers/recognizer2d.py @@ -1,195 +1,195 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch -from torch import nn - -from ..builder import RECOGNIZERS -from .base import BaseRecognizer - - -@RECOGNIZERS.register_module() -class Recognizer2D(BaseRecognizer): - """2D recognizer model framework.""" - def forward_train(self, imgs, labels, **kwargs): - """Defines the computation performed at every call when training.""" - - assert self.with_cls_head - batches = imgs.shape[0] - imgs = imgs.reshape((-1, ) + imgs.shape[2:]) - num_segs = imgs.shape[0] // batches - - losses = dict() - - x = self.extract_feat(imgs) - - if self.backbone_from in ['torchvision', 'timm']: - if len(x.shape) == 4 and (x.shape[2] > 1 or x.shape[3] > 1): - # apply adaptive avg pooling - x = nn.AdaptiveAvgPool2d(1)(x) - x = x.reshape((x.shape[0], -1)) - x = x.reshape(x.shape + (1, 1)) - - if self.with_neck: - x = [ - each.reshape((-1, num_segs) + each.shape[1:]).transpose( - 1, 2).contiguous() for each in x - ] - x, loss_aux = self.neck(x, labels.squeeze()) - x = x.squeeze(2) - num_segs = 1 - losses.update(loss_aux) - - cls_score = self.cls_head(x, num_segs) - gt_labels = labels.squeeze() - loss_cls = self.cls_head.loss(cls_score, gt_labels, **kwargs) - losses.update(loss_cls) - - return losses - - def _do_test(self, imgs): - """Defines the computation performed at every call when evaluation, - testing and gradcam.""" - batches = imgs.shape[0] - imgs = imgs.reshape((-1, ) + imgs.shape[2:]) - num_segs = imgs.shape[0] // batches - - x = self.extract_feat(imgs) - - if self.backbone_from in ['torchvision', 'timm']: - if len(x.shape) == 4 and (x.shape[2] > 1 or x.shape[3] > 1): - # apply adaptive avg pooling - x = nn.AdaptiveAvgPool2d(1)(x) - x = x.reshape((x.shape[0], -1)) - x = x.reshape(x.shape + (1, 1)) - - if self.with_neck: - x = [ - each.reshape((-1, num_segs) + each.shape[1:]).transpose( - 1, 2).contiguous() for each in x - ] - x, _ = self.neck(x) - x = x.squeeze(2) - num_segs = 1 - - if self.feature_extraction: - # perform spatial pooling - avg_pool = nn.AdaptiveAvgPool2d(1) - x = avg_pool(x) - # squeeze dimensions - x = x.reshape((batches, num_segs, -1)) - # temporal average pooling - x = x.mean(axis=1) - return x - - # When using `TSNHead` or `TPNHead`, shape is [batch_size, num_classes] - # When using `TSMHead`, shape is [batch_size * num_crops, num_classes] - # `num_crops` is calculated by: - # 1) `twice_sample` in `SampleFrames` - # 2) `num_sample_positions` in `DenseSampleFrames` - # 3) `ThreeCrop/TenCrop/MultiGroupCrop` in `test_pipeline` - # 4) `num_clips` in `SampleFrames` or its subclass if `clip_len != 1` - - # should have cls_head if not extracting features - cls_score = self.cls_head(x, num_segs) - - assert cls_score.size()[0] % batches == 0 - # calculate num_crops automatically - cls_score = self.average_clip(cls_score, - cls_score.size()[0] // batches) - return cls_score - - def _do_fcn_test(self, imgs): - # [N, num_crops * num_segs, C, H, W] -> - # [N * num_crops * num_segs, C, H, W] - batches = imgs.shape[0] - imgs = imgs.reshape((-1, ) + imgs.shape[2:]) - num_segs = self.test_cfg.get('num_segs', self.backbone.num_segments) - - if self.test_cfg.get('flip', False): - imgs = torch.flip(imgs, [-1]) - x = self.extract_feat(imgs) - - if self.with_neck: - x = [ - each.reshape((-1, num_segs) + each.shape[1:]).transpose( - 1, 2).contiguous() for each in x - ] - x, _ = self.neck(x) - else: - x = x.reshape((-1, num_segs) + x.shape[1:]).transpose( - 1, 2).contiguous() - - # When using `TSNHead` or `TPNHead`, shape is [batch_size, num_classes] - # When using `TSMHead`, shape is [batch_size * num_crops, num_classes] - # `num_crops` is calculated by: - # 1) `twice_sample` in `SampleFrames` - # 2) `num_sample_positions` in `DenseSampleFrames` - # 3) `ThreeCrop/TenCrop/MultiGroupCrop` in `test_pipeline` - # 4) `num_clips` in `SampleFrames` or its subclass if `clip_len != 1` - cls_score = self.cls_head(x, fcn_test=True) - - assert cls_score.size()[0] % batches == 0 - # calculate num_crops automatically - cls_score = self.average_clip(cls_score, - cls_score.size()[0] // batches) - return cls_score - - def forward_test(self, imgs): - """Defines the computation performed at every call when evaluation and - testing.""" - imgs = imgs.npu().type(torch.float16) - if self.test_cfg.get('fcn_test', False): - # If specified, spatially fully-convolutional testing is performed - assert not self.feature_extraction - assert self.with_cls_head - return self._do_fcn_test(imgs).cpu().numpy() - return self._do_test(imgs).cpu().numpy() - - def forward_dummy(self, imgs, softmax=False): - """Used for computing network FLOPs. - - See ``tools/analysis/get_flops.py``. - - Args: - imgs (torch.Tensor): Input images. - - Returns: - Tensor: Class score. - """ - assert self.with_cls_head - batches = imgs.shape[0] - imgs = imgs.reshape((-1, ) + imgs.shape[2:]) - num_segs = imgs.shape[0] // batches - - x = self.extract_feat(imgs) - if self.with_neck: - x = [ - each.reshape((-1, num_segs) + each.shape[1:]).transpose( - 1, 2).contiguous() for each in x - ] - x, _ = self.neck(x) - x = x.squeeze(2) - num_segs = 1 - - outs = self.cls_head(x, num_segs) - if softmax: - outs = nn.functional.softmax(outs) - return (outs, ) - - def forward_gradcam(self, imgs): - """Defines the computation performed at every call when using gradcam - utils.""" - assert self.with_cls_head - return self._do_test(imgs) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch +from torch import nn + +from ..builder import RECOGNIZERS +from .base import BaseRecognizer + + +@RECOGNIZERS.register_module() +class Recognizer2D(BaseRecognizer): + """2D recognizer model framework.""" + def forward_train(self, imgs, labels, **kwargs): + """Defines the computation performed at every call when training.""" + + assert self.with_cls_head + batches = imgs.shape[0] + imgs = imgs.reshape((-1, ) + imgs.shape[2:]) + num_segs = imgs.shape[0] // batches + + losses = dict() + + x = self.extract_feat(imgs) + + if self.backbone_from in ['torchvision', 'timm']: + if len(x.shape) == 4 and (x.shape[2] > 1 or x.shape[3] > 1): + # apply adaptive avg pooling + x = nn.AdaptiveAvgPool2d(1)(x) + x = x.reshape((x.shape[0], -1)) + x = x.reshape(x.shape + (1, 1)) + + if self.with_neck: + x = [ + each.reshape((-1, num_segs) + each.shape[1:]).transpose( + 1, 2).contiguous() for each in x + ] + x, loss_aux = self.neck(x, labels.squeeze()) + x = x.squeeze(2) + num_segs = 1 + losses.update(loss_aux) + + cls_score = self.cls_head(x, num_segs) + gt_labels = labels.squeeze() + loss_cls = self.cls_head.loss(cls_score, gt_labels, **kwargs) + losses.update(loss_cls) + + return losses + + def _do_test(self, imgs): + """Defines the computation performed at every call when evaluation, + testing and gradcam.""" + batches = imgs.shape[0] + imgs = imgs.reshape((-1, ) + imgs.shape[2:]) + num_segs = imgs.shape[0] // batches + + x = self.extract_feat(imgs) + + if self.backbone_from in ['torchvision', 'timm']: + if len(x.shape) == 4 and (x.shape[2] > 1 or x.shape[3] > 1): + # apply adaptive avg pooling + x = nn.AdaptiveAvgPool2d(1)(x) + x = x.reshape((x.shape[0], -1)) + x = x.reshape(x.shape + (1, 1)) + + if self.with_neck: + x = [ + each.reshape((-1, num_segs) + each.shape[1:]).transpose( + 1, 2).contiguous() for each in x + ] + x, _ = self.neck(x) + x = x.squeeze(2) + num_segs = 1 + + if self.feature_extraction: + # perform spatial pooling + avg_pool = nn.AdaptiveAvgPool2d(1) + x = avg_pool(x) + # squeeze dimensions + x = x.reshape((batches, num_segs, -1)) + # temporal average pooling + x = x.mean(axis=1) + return x + + # When using `TSNHead` or `TPNHead`, shape is [batch_size, num_classes] + # When using `TSMHead`, shape is [batch_size * num_crops, num_classes] + # `num_crops` is calculated by: + # 1) `twice_sample` in `SampleFrames` + # 2) `num_sample_positions` in `DenseSampleFrames` + # 3) `ThreeCrop/TenCrop/MultiGroupCrop` in `test_pipeline` + # 4) `num_clips` in `SampleFrames` or its subclass if `clip_len != 1` + + # should have cls_head if not extracting features + cls_score = self.cls_head(x, num_segs) + + assert cls_score.size()[0] % batches == 0 + # calculate num_crops automatically + cls_score = self.average_clip(cls_score, + cls_score.size()[0] // batches) + return cls_score + + def _do_fcn_test(self, imgs): + # [N, num_crops * num_segs, C, H, W] -> + # [N * num_crops * num_segs, C, H, W] + batches = imgs.shape[0] + imgs = imgs.reshape((-1, ) + imgs.shape[2:]) + num_segs = self.test_cfg.get('num_segs', self.backbone.num_segments) + + if self.test_cfg.get('flip', False): + imgs = torch.flip(imgs, [-1]) + x = self.extract_feat(imgs) + + if self.with_neck: + x = [ + each.reshape((-1, num_segs) + each.shape[1:]).transpose( + 1, 2).contiguous() for each in x + ] + x, _ = self.neck(x) + else: + x = x.reshape((-1, num_segs) + x.shape[1:]).transpose( + 1, 2).contiguous() + + # When using `TSNHead` or `TPNHead`, shape is [batch_size, num_classes] + # When using `TSMHead`, shape is [batch_size * num_crops, num_classes] + # `num_crops` is calculated by: + # 1) `twice_sample` in `SampleFrames` + # 2) `num_sample_positions` in `DenseSampleFrames` + # 3) `ThreeCrop/TenCrop/MultiGroupCrop` in `test_pipeline` + # 4) `num_clips` in `SampleFrames` or its subclass if `clip_len != 1` + cls_score = self.cls_head(x, fcn_test=True) + + assert cls_score.size()[0] % batches == 0 + # calculate num_crops automatically + cls_score = self.average_clip(cls_score, + cls_score.size()[0] // batches) + return cls_score + + def forward_test(self, imgs): + """Defines the computation performed at every call when evaluation and + testing.""" + imgs = imgs.npu().type(torch.float16) + if self.test_cfg.get('fcn_test', False): + # If specified, spatially fully-convolutional testing is performed + assert not self.feature_extraction + assert self.with_cls_head + return self._do_fcn_test(imgs).cpu().numpy() + return self._do_test(imgs).cpu().numpy() + + def forward_dummy(self, imgs, softmax=False): + """Used for computing network FLOPs. + + See ``tools/analysis/get_flops.py``. + + Args: + imgs (torch.Tensor): Input images. + + Returns: + Tensor: Class score. + """ + assert self.with_cls_head + batches = imgs.shape[0] + imgs = imgs.reshape((-1, ) + imgs.shape[2:]) + num_segs = imgs.shape[0] // batches + + x = self.extract_feat(imgs) + if self.with_neck: + x = [ + each.reshape((-1, num_segs) + each.shape[1:]).transpose( + 1, 2).contiguous() for each in x + ] + x, _ = self.neck(x) + x = x.squeeze(2) + num_segs = 1 + + outs = self.cls_head(x, num_segs) + if softmax: + outs = nn.functional.softmax(outs) + return (outs, ) + + def forward_gradcam(self, imgs): + """Defines the computation performed at every call when using gradcam + utils.""" + assert self.with_cls_head + return self._do_test(imgs) diff --git a/PyTorch/contrib/cv/video/NonLocal/mmaction/models/recognizers/recognizer3d.py b/PyTorch/contrib/cv/video/NonLocal/mmaction/models/recognizers/recognizer3d.py index fe1a61ef2b..9a1b70449d 100644 --- a/PyTorch/contrib/cv/video/NonLocal/mmaction/models/recognizers/recognizer3d.py +++ b/PyTorch/contrib/cv/video/NonLocal/mmaction/models/recognizers/recognizer3d.py @@ -1,133 +1,133 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch -from torch import nn - -from ..builder import RECOGNIZERS -from .base import BaseRecognizer - - -@RECOGNIZERS.register_module() -class Recognizer3D(BaseRecognizer): - """3D recognizer model framework.""" - def forward_train(self, imgs, labels, **kwargs): - """Defines the computation performed at every call when training.""" - - assert self.with_cls_head - imgs = imgs.reshape((-1, ) + imgs.shape[2:]) - losses = dict() - - x = self.extract_feat(imgs) - if self.with_neck: - x, loss_aux = self.neck(x, labels.squeeze()) - losses.update(loss_aux) - - cls_score = self.cls_head(x) - gt_labels = labels.squeeze() - loss_cls = self.cls_head.loss(cls_score, gt_labels, **kwargs) - losses.update(loss_cls) - - return losses - - def _do_test(self, imgs): - """Defines the computation performed at every call when evaluation, - testing and gradcam.""" - batches = imgs.shape[0] - num_segs = imgs.shape[1] - imgs = imgs.reshape((-1, ) + imgs.shape[2:]) - - if self.max_testing_views is not None: - total_views = imgs.shape[0] - assert num_segs == total_views, ( - 'max_testing_views is only compatible ' - 'with batch_size == 1') - view_ptr = 0 - feats = [] - while view_ptr < total_views: - batch_imgs = imgs[view_ptr:view_ptr + self.max_testing_views] - x = self.extract_feat(batch_imgs) - if self.with_neck: - x, _ = self.neck(x) - feats.append(x) - view_ptr += self.max_testing_views - # should consider the case that feat is a tuple - if isinstance(feats[0], tuple): - len_tuple = len(feats[0]) - feat = [ - torch.cat([x[i] for x in feats]) for i in range(len_tuple) - ] - feat = tuple(feat) - else: - feat = torch.cat(feats) - else: - feat = self.extract_feat(imgs) - if self.with_neck: - feat, _ = self.neck(feat) - - if self.feature_extraction: - # perform spatio-temporal pooling - avg_pool = nn.AdaptiveAvgPool3d(1) - if isinstance(feat, tuple): - feat = [avg_pool(x) for x in feat] - # concat them - feat = torch.cat(feat, axis=1) - else: - feat = avg_pool(feat) - # squeeze dimensions - feat = feat.reshape((batches, num_segs, -1)) - # temporal average pooling - feat = feat.mean(axis=1) - return feat - - # should have cls_head if not extracting features - assert self.with_cls_head - cls_score = self.cls_head(feat) - cls_score = self.average_clip(cls_score, num_segs) - return cls_score - - def forward_test(self, imgs): - """Defines the computation performed at every call when evaluation and - testing.""" - imgs = imgs.npu().type(torch.float16) - return self._do_test(imgs).cpu().numpy() - - def forward_dummy(self, imgs, softmax=False): - """Used for computing network FLOPs. - - See ``tools/analysis/get_flops.py``. - - Args: - imgs (torch.Tensor): Input images. - - Returns: - Tensor: Class score. - """ - assert self.with_cls_head - imgs = imgs.reshape((-1, ) + imgs.shape[2:]) - x = self.extract_feat(imgs) - - if self.with_neck: - x, _ = self.neck(x) - - outs = self.cls_head(x) - if softmax: - outs = nn.functional.softmax(outs) - return (outs, ) - - def forward_gradcam(self, imgs): - """Defines the computation performed at every call when using gradcam - utils.""" - assert self.with_cls_head - return self._do_test(imgs) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch +from torch import nn + +from ..builder import RECOGNIZERS +from .base import BaseRecognizer + + +@RECOGNIZERS.register_module() +class Recognizer3D(BaseRecognizer): + """3D recognizer model framework.""" + def forward_train(self, imgs, labels, **kwargs): + """Defines the computation performed at every call when training.""" + + assert self.with_cls_head + imgs = imgs.reshape((-1, ) + imgs.shape[2:]) + losses = dict() + + x = self.extract_feat(imgs) + if self.with_neck: + x, loss_aux = self.neck(x, labels.squeeze()) + losses.update(loss_aux) + + cls_score = self.cls_head(x) + gt_labels = labels.squeeze() + loss_cls = self.cls_head.loss(cls_score, gt_labels, **kwargs) + losses.update(loss_cls) + + return losses + + def _do_test(self, imgs): + """Defines the computation performed at every call when evaluation, + testing and gradcam.""" + batches = imgs.shape[0] + num_segs = imgs.shape[1] + imgs = imgs.reshape((-1, ) + imgs.shape[2:]) + + if self.max_testing_views is not None: + total_views = imgs.shape[0] + assert num_segs == total_views, ( + 'max_testing_views is only compatible ' + 'with batch_size == 1') + view_ptr = 0 + feats = [] + while view_ptr < total_views: + batch_imgs = imgs[view_ptr:view_ptr + self.max_testing_views] + x = self.extract_feat(batch_imgs) + if self.with_neck: + x, _ = self.neck(x) + feats.append(x) + view_ptr += self.max_testing_views + # should consider the case that feat is a tuple + if isinstance(feats[0], tuple): + len_tuple = len(feats[0]) + feat = [ + torch.cat([x[i] for x in feats]) for i in range(len_tuple) + ] + feat = tuple(feat) + else: + feat = torch.cat(feats) + else: + feat = self.extract_feat(imgs) + if self.with_neck: + feat, _ = self.neck(feat) + + if self.feature_extraction: + # perform spatio-temporal pooling + avg_pool = nn.AdaptiveAvgPool3d(1) + if isinstance(feat, tuple): + feat = [avg_pool(x) for x in feat] + # concat them + feat = torch.cat(feat, axis=1) + else: + feat = avg_pool(feat) + # squeeze dimensions + feat = feat.reshape((batches, num_segs, -1)) + # temporal average pooling + feat = feat.mean(axis=1) + return feat + + # should have cls_head if not extracting features + assert self.with_cls_head + cls_score = self.cls_head(feat) + cls_score = self.average_clip(cls_score, num_segs) + return cls_score + + def forward_test(self, imgs): + """Defines the computation performed at every call when evaluation and + testing.""" + imgs = imgs.npu().type(torch.float16) + return self._do_test(imgs).cpu().numpy() + + def forward_dummy(self, imgs, softmax=False): + """Used for computing network FLOPs. + + See ``tools/analysis/get_flops.py``. + + Args: + imgs (torch.Tensor): Input images. + + Returns: + Tensor: Class score. + """ + assert self.with_cls_head + imgs = imgs.reshape((-1, ) + imgs.shape[2:]) + x = self.extract_feat(imgs) + + if self.with_neck: + x, _ = self.neck(x) + + outs = self.cls_head(x) + if softmax: + outs = nn.functional.softmax(outs) + return (outs, ) + + def forward_gradcam(self, imgs): + """Defines the computation performed at every call when using gradcam + utils.""" + assert self.with_cls_head + return self._do_test(imgs) diff --git a/PyTorch/contrib/cv/video/R(2+1)D/additional_need/mmcv/dist_utils.py b/PyTorch/contrib/cv/video/R(2+1)D/additional_need/mmcv/dist_utils.py index 91346643e8..9e3f2b072b 100644 --- a/PyTorch/contrib/cv/video/R(2+1)D/additional_need/mmcv/dist_utils.py +++ b/PyTorch/contrib/cv/video/R(2+1)D/additional_need/mmcv/dist_utils.py @@ -1,185 +1,185 @@ -# Copyright (c) Open-MMLab. All rights reserved. -# -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 functools -import os -import subprocess -from collections import OrderedDict - -import torch -import torch.multiprocessing as mp -from torch import distributed as dist -from torch._utils import (_flatten_dense_tensors, _take_tensors, - _unflatten_dense_tensors) - -from mmcv.utils import TORCH_VERSION - - -def init_dist(launcher, backend='nccl', **kwargs): - if mp.get_start_method(allow_none=True) is None: - mp.set_start_method('spawn') - if launcher == 'pytorch': - _init_dist_pytorch(backend, **kwargs) - elif launcher == 'mpi': - _init_dist_mpi(backend, **kwargs) - elif launcher == 'slurm': - _init_dist_slurm(backend, **kwargs) - else: - raise ValueError(f'Invalid launcher type: {launcher}') - - -def _init_dist_pytorch(backend, **kwargs): - # TODO: use local_rank instead of rank % num_gpus - rank = int(os.environ['RANK']) - offset = 0 if os.getenv('NPUID', None) is None else int(os.environ['NPUID']) - num_gpus = torch.npu.device_count() - torch.npu.set_device((rank + offset) % num_gpus) - dist.init_process_group(backend=backend, **kwargs) - - -def _init_dist_mpi(backend, **kwargs): - # TODO: use local_rank instead of rank % num_gpus - rank = int(os.environ['OMPI_COMM_WORLD_RANK']) - num_gpus = torch.cuda.device_count() - torch.cuda.set_device(rank % num_gpus) - dist.init_process_group(backend=backend, **kwargs) - - -def _init_dist_slurm(backend, port=None): - """Initialize slurm distributed training environment. - If argument ``port`` is not specified, then the master port will be system - environment variable ``MASTER_PORT``. If ``MASTER_PORT`` is not in system - environment variable, then a default port ``29500`` will be used. - Args: - backend (str): Backend of torch.distributed. - port (int, optional): Master port. Defaults to None. - """ - proc_id = int(os.environ['SLURM_PROCID']) - ntasks = int(os.environ['SLURM_NTASKS']) - node_list = os.environ['SLURM_NODELIST'] - num_gpus = torch.cuda.device_count() - torch.cuda.set_device(proc_id % num_gpus) - addr = subprocess.getoutput( - f'scontrol show hostname {node_list} | head -n1') - # specify master port - if port is not None: - os.environ['MASTER_PORT'] = str(port) - elif 'MASTER_PORT' in os.environ: - pass # use MASTER_PORT in the environment variable - else: - # 29500 is torch.distributed default port - os.environ['MASTER_PORT'] = '29500' - # use MASTER_ADDR in the environment variable if it already exists - if 'MASTER_ADDR' not in os.environ: - os.environ['MASTER_ADDR'] = addr - os.environ['WORLD_SIZE'] = str(ntasks) - os.environ['LOCAL_RANK'] = str(proc_id % num_gpus) - os.environ['RANK'] = str(proc_id) - dist.init_process_group(backend=backend) - - -def get_dist_info(): - if TORCH_VERSION < '1.0': - initialized = dist._initialized - else: - if dist.is_available(): - initialized = dist.is_initialized() - else: - initialized = False - if initialized: - rank = dist.get_rank() - world_size = dist.get_world_size() - else: - rank = 0 - world_size = 1 - return rank, world_size - - -def master_only(func): - - @functools.wraps(func) - def wrapper(*args, **kwargs): - rank, _ = get_dist_info() - if rank == 0: - return func(*args, **kwargs) - - return wrapper - - -def allreduce_params(params, coalesce=True, bucket_size_mb=-1): - """Allreduce parameters. - Args: - params (list[torch.Parameters]): List of parameters or buffers of a - model. - coalesce (bool, optional): Whether allreduce parameters as a whole. - Defaults to True. - bucket_size_mb (int, optional): Size of bucket, the unit is MB. - Defaults to -1. - """ - _, world_size = get_dist_info() - if world_size == 1: - return - params = [param.data for param in params] - if coalesce: - _allreduce_coalesced(params, world_size, bucket_size_mb) - else: - for tensor in params: - dist.all_reduce(tensor.div_(world_size)) - - -def allreduce_grads(params, coalesce=True, bucket_size_mb=-1): - """Allreduce gradients. - Args: - params (list[torch.Parameters]): List of parameters of a model - coalesce (bool, optional): Whether allreduce parameters as a whole. - Defaults to True. - bucket_size_mb (int, optional): Size of bucket, the unit is MB. - Defaults to -1. - """ - grads = [ - param.grad.data for param in params - if param.requires_grad and param.grad is not None - ] - _, world_size = get_dist_info() - if world_size == 1: - return - if coalesce: - _allreduce_coalesced(grads, world_size, bucket_size_mb) - else: - for tensor in grads: - dist.all_reduce(tensor.div_(world_size)) - - -def _allreduce_coalesced(tensors, world_size, bucket_size_mb=-1): - if bucket_size_mb > 0: - bucket_size_bytes = bucket_size_mb * 1024 * 1024 - buckets = _take_tensors(tensors, bucket_size_bytes) - else: - buckets = OrderedDict() - for tensor in tensors: - tp = tensor.type() - if tp not in buckets: - buckets[tp] = [] - buckets[tp].append(tensor) - buckets = buckets.values() - - for bucket in buckets: - flat_tensors = _flatten_dense_tensors(bucket) - dist.all_reduce(flat_tensors) - flat_tensors.div_(world_size) - for tensor, synced in zip( - bucket, _unflatten_dense_tensors(flat_tensors, bucket)): +# Copyright (c) Open-MMLab. All rights reserved. +# +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 functools +import os +import subprocess +from collections import OrderedDict + +import torch +import torch.multiprocessing as mp +from torch import distributed as dist +from torch._utils import (_flatten_dense_tensors, _take_tensors, + _unflatten_dense_tensors) + +from mmcv.utils import TORCH_VERSION + + +def init_dist(launcher, backend='nccl', **kwargs): + if mp.get_start_method(allow_none=True) is None: + mp.set_start_method('spawn') + if launcher == 'pytorch': + _init_dist_pytorch(backend, **kwargs) + elif launcher == 'mpi': + _init_dist_mpi(backend, **kwargs) + elif launcher == 'slurm': + _init_dist_slurm(backend, **kwargs) + else: + raise ValueError(f'Invalid launcher type: {launcher}') + + +def _init_dist_pytorch(backend, **kwargs): + # TODO: use local_rank instead of rank % num_gpus + rank = int(os.environ['RANK']) + offset = 0 if os.getenv('NPUID', None) is None else int(os.environ['NPUID']) + num_gpus = torch.npu.device_count() + torch.npu.set_device((rank + offset) % num_gpus) + dist.init_process_group(backend=backend, **kwargs) + + +def _init_dist_mpi(backend, **kwargs): + # TODO: use local_rank instead of rank % num_gpus + rank = int(os.environ['OMPI_COMM_WORLD_RANK']) + num_gpus = torch.cuda.device_count() + torch.cuda.set_device(rank % num_gpus) + dist.init_process_group(backend=backend, **kwargs) + + +def _init_dist_slurm(backend, port=None): + """Initialize slurm distributed training environment. + If argument ``port`` is not specified, then the master port will be system + environment variable ``MASTER_PORT``. If ``MASTER_PORT`` is not in system + environment variable, then a default port ``29500`` will be used. + Args: + backend (str): Backend of torch.distributed. + port (int, optional): Master port. Defaults to None. + """ + proc_id = int(os.environ['SLURM_PROCID']) + ntasks = int(os.environ['SLURM_NTASKS']) + node_list = os.environ['SLURM_NODELIST'] + num_gpus = torch.cuda.device_count() + torch.cuda.set_device(proc_id % num_gpus) + addr = subprocess.getoutput( + f'scontrol show hostname {node_list} | head -n1') + # specify master port + if port is not None: + os.environ['MASTER_PORT'] = str(port) + elif 'MASTER_PORT' in os.environ: + pass # use MASTER_PORT in the environment variable + else: + # 29500 is torch.distributed default port + os.environ['MASTER_PORT'] = '29500' + # use MASTER_ADDR in the environment variable if it already exists + if 'MASTER_ADDR' not in os.environ: + os.environ['MASTER_ADDR'] = addr + os.environ['WORLD_SIZE'] = str(ntasks) + os.environ['LOCAL_RANK'] = str(proc_id % num_gpus) + os.environ['RANK'] = str(proc_id) + dist.init_process_group(backend=backend) + + +def get_dist_info(): + if TORCH_VERSION < '1.0': + initialized = dist._initialized + else: + if dist.is_available(): + initialized = dist.is_initialized() + else: + initialized = False + if initialized: + rank = dist.get_rank() + world_size = dist.get_world_size() + else: + rank = 0 + world_size = 1 + return rank, world_size + + +def master_only(func): + + @functools.wraps(func) + def wrapper(*args, **kwargs): + rank, _ = get_dist_info() + if rank == 0: + return func(*args, **kwargs) + + return wrapper + + +def allreduce_params(params, coalesce=True, bucket_size_mb=-1): + """Allreduce parameters. + Args: + params (list[torch.Parameters]): List of parameters or buffers of a + model. + coalesce (bool, optional): Whether allreduce parameters as a whole. + Defaults to True. + bucket_size_mb (int, optional): Size of bucket, the unit is MB. + Defaults to -1. + """ + _, world_size = get_dist_info() + if world_size == 1: + return + params = [param.data for param in params] + if coalesce: + _allreduce_coalesced(params, world_size, bucket_size_mb) + else: + for tensor in params: + dist.all_reduce(tensor.div_(world_size)) + + +def allreduce_grads(params, coalesce=True, bucket_size_mb=-1): + """Allreduce gradients. + Args: + params (list[torch.Parameters]): List of parameters of a model + coalesce (bool, optional): Whether allreduce parameters as a whole. + Defaults to True. + bucket_size_mb (int, optional): Size of bucket, the unit is MB. + Defaults to -1. + """ + grads = [ + param.grad.data for param in params + if param.requires_grad and param.grad is not None + ] + _, world_size = get_dist_info() + if world_size == 1: + return + if coalesce: + _allreduce_coalesced(grads, world_size, bucket_size_mb) + else: + for tensor in grads: + dist.all_reduce(tensor.div_(world_size)) + + +def _allreduce_coalesced(tensors, world_size, bucket_size_mb=-1): + if bucket_size_mb > 0: + bucket_size_bytes = bucket_size_mb * 1024 * 1024 + buckets = _take_tensors(tensors, bucket_size_bytes) + else: + buckets = OrderedDict() + for tensor in tensors: + tp = tensor.type() + if tp not in buckets: + buckets[tp] = [] + buckets[tp].append(tensor) + buckets = buckets.values() + + for bucket in buckets: + flat_tensors = _flatten_dense_tensors(bucket) + dist.all_reduce(flat_tensors) + flat_tensors.div_(world_size) + for tensor, synced in zip( + bucket, _unflatten_dense_tensors(flat_tensors, bucket)): tensor.copy_(synced) \ No newline at end of file diff --git a/PyTorch/contrib/cv/video/R(2+1)D/additional_need/mmcv/distributed.py b/PyTorch/contrib/cv/video/R(2+1)D/additional_need/mmcv/distributed.py index fb2bae9229..4c89d09fc4 100644 --- a/PyTorch/contrib/cv/video/R(2+1)D/additional_need/mmcv/distributed.py +++ b/PyTorch/contrib/cv/video/R(2+1)D/additional_need/mmcv/distributed.py @@ -1,119 +1,119 @@ -# Copyright (c) Open-MMLab. All rights reserved. -# -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 torch -from torch.nn.parallel.distributed import (DistributedDataParallel, - _find_tensors) - -from mmcv import print_log -from mmcv.utils import TORCH_VERSION -from .scatter_gather import scatter_kwargs - - -class MMDistributedDataParallel(DistributedDataParallel): - """The DDP module that supports DataContainer. - - MMDDP has two main differences with PyTorch DDP: - - - It supports a custom type :class:`DataContainer` which allows more - flexible control of input data. - - It implement two APIs ``train_step()`` and ``val_step()``. - """ - - def scatter(self, inputs, kwargs, device_ids): - return scatter_kwargs(inputs, kwargs, device_ids, dim=self.dim) - - def train_step(self, *inputs, **kwargs): - """train_step() API for module wrapped by DistributedDataParallel. - - This method is basically the same as - ``DistributedDataParallel.forward()``, while replacing - ``self.module.forward()`` with ``self.module.train_step()``. - It is compatible with PyTorch 1.1 - 1.5. - """ - - # In PyTorch >= 1.7, ``reducer._rebuild_buckets()`` is moved from the - # end of backward to the beginning of forward. - if (TORCH_VERSION >= '1.7' and 'parrots' - not in TORCH_VERSION) and self.reducer._rebuild_buckets(): - print_log( - 'Reducer buckets have been rebuilt in this iteration.', - logger='mmcv') - - if getattr(self, 'require_forward_param_sync', True): - self._sync_params() - if self.device_ids and False: - inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids) - if len(self.device_ids) == 1: - output = self.module.train_step(*inputs[0], **kwargs[0]) - else: - outputs = self.parallel_apply( - self._module_copies[:len(inputs)], inputs, kwargs) - output = self.gather(outputs, self.output_device) - else: - inputs, kwargs = self.scatter(inputs, kwargs, [-1]) - output = self.module.train_step(*inputs[0], **kwargs[0]) - - if torch.is_grad_enabled() and getattr( - self, 'require_backward_grad_sync', True): - if self.find_unused_parameters: - self.reducer.prepare_for_backward(list(_find_tensors(output))) - else: - self.reducer.prepare_for_backward([]) - else: - if TORCH_VERSION > '1.2': - self.require_forward_param_sync = False - return output - - def val_step(self, *inputs, **kwargs): - """val_step() API for module wrapped by DistributedDataParallel. - - This method is basically the same as - ``DistributedDataParallel.forward()``, while replacing - ``self.module.forward()`` with ``self.module.val_step()``. - It is compatible with PyTorch 1.1 - 1.5. - """ - # In PyTorch >= 1.7, ``reducer._rebuild_buckets()`` is moved from the - # end of backward to the beginning of forward. - if (TORCH_VERSION >= '1.7' and 'parrots' - not in TORCH_VERSION) and self.reducer._rebuild_buckets(): - print_log( - 'Reducer buckets have been rebuilt in this iteration.', - logger='mmcv') - - if getattr(self, 'require_forward_param_sync', True): - self._sync_params() - if self.device_ids: - inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids) - if len(self.device_ids) == 1: - output = self.module.val_step(*inputs[0], **kwargs[0]) - else: - outputs = self.parallel_apply( - self._module_copies[:len(inputs)], inputs, kwargs) - output = self.gather(outputs, self.output_device) - else: - output = self.module.val_step(*inputs, **kwargs) - - if torch.is_grad_enabled() and getattr( - self, 'require_backward_grad_sync', True): - if self.find_unused_parameters: - self.reducer.prepare_for_backward(list(_find_tensors(output))) - else: - self.reducer.prepare_for_backward([]) - else: - if TORCH_VERSION > '1.2': - self.require_forward_param_sync = False - return output +# Copyright (c) Open-MMLab. All rights reserved. +# +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 torch +from torch.nn.parallel.distributed import (DistributedDataParallel, + _find_tensors) + +from mmcv import print_log +from mmcv.utils import TORCH_VERSION +from .scatter_gather import scatter_kwargs + + +class MMDistributedDataParallel(DistributedDataParallel): + """The DDP module that supports DataContainer. + + MMDDP has two main differences with PyTorch DDP: + + - It supports a custom type :class:`DataContainer` which allows more + flexible control of input data. + - It implement two APIs ``train_step()`` and ``val_step()``. + """ + + def scatter(self, inputs, kwargs, device_ids): + return scatter_kwargs(inputs, kwargs, device_ids, dim=self.dim) + + def train_step(self, *inputs, **kwargs): + """train_step() API for module wrapped by DistributedDataParallel. + + This method is basically the same as + ``DistributedDataParallel.forward()``, while replacing + ``self.module.forward()`` with ``self.module.train_step()``. + It is compatible with PyTorch 1.1 - 1.5. + """ + + # In PyTorch >= 1.7, ``reducer._rebuild_buckets()`` is moved from the + # end of backward to the beginning of forward. + if (TORCH_VERSION >= '1.7' and 'parrots' + not in TORCH_VERSION) and self.reducer._rebuild_buckets(): + print_log( + 'Reducer buckets have been rebuilt in this iteration.', + logger='mmcv') + + if getattr(self, 'require_forward_param_sync', True): + self._sync_params() + if self.device_ids and False: + inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids) + if len(self.device_ids) == 1: + output = self.module.train_step(*inputs[0], **kwargs[0]) + else: + outputs = self.parallel_apply( + self._module_copies[:len(inputs)], inputs, kwargs) + output = self.gather(outputs, self.output_device) + else: + inputs, kwargs = self.scatter(inputs, kwargs, [-1]) + output = self.module.train_step(*inputs[0], **kwargs[0]) + + if torch.is_grad_enabled() and getattr( + self, 'require_backward_grad_sync', True): + if self.find_unused_parameters: + self.reducer.prepare_for_backward(list(_find_tensors(output))) + else: + self.reducer.prepare_for_backward([]) + else: + if TORCH_VERSION > '1.2': + self.require_forward_param_sync = False + return output + + def val_step(self, *inputs, **kwargs): + """val_step() API for module wrapped by DistributedDataParallel. + + This method is basically the same as + ``DistributedDataParallel.forward()``, while replacing + ``self.module.forward()`` with ``self.module.val_step()``. + It is compatible with PyTorch 1.1 - 1.5. + """ + # In PyTorch >= 1.7, ``reducer._rebuild_buckets()`` is moved from the + # end of backward to the beginning of forward. + if (TORCH_VERSION >= '1.7' and 'parrots' + not in TORCH_VERSION) and self.reducer._rebuild_buckets(): + print_log( + 'Reducer buckets have been rebuilt in this iteration.', + logger='mmcv') + + if getattr(self, 'require_forward_param_sync', True): + self._sync_params() + if self.device_ids: + inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids) + if len(self.device_ids) == 1: + output = self.module.val_step(*inputs[0], **kwargs[0]) + else: + outputs = self.parallel_apply( + self._module_copies[:len(inputs)], inputs, kwargs) + output = self.gather(outputs, self.output_device) + else: + output = self.module.val_step(*inputs, **kwargs) + + if torch.is_grad_enabled() and getattr( + self, 'require_backward_grad_sync', True): + if self.find_unused_parameters: + self.reducer.prepare_for_backward(list(_find_tensors(output))) + else: + self.reducer.prepare_for_backward([]) + else: + if TORCH_VERSION > '1.2': + self.require_forward_param_sync = False + return output diff --git a/PyTorch/contrib/cv/video/R(2+1)D/additional_need/mmcv/optimizer.py b/PyTorch/contrib/cv/video/R(2+1)D/additional_need/mmcv/optimizer.py index 385978353d..5956d430e8 100644 --- a/PyTorch/contrib/cv/video/R(2+1)D/additional_need/mmcv/optimizer.py +++ b/PyTorch/contrib/cv/video/R(2+1)D/additional_need/mmcv/optimizer.py @@ -1,182 +1,182 @@ -# Copyright (c) Open-MMLab. All rights reserved. -# -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 copy -from collections import defaultdict -from itertools import chain - -from torch.nn.utils import clip_grad - -from ..dist_utils import allreduce_grads -from ..fp16_utils import LossScaler, wrap_fp16_model -from .hook import HOOKS, Hook -from apex import amp - -@HOOKS.register_module() -class OptimizerHook(Hook): - - def __init__(self, grad_clip=None): - self.grad_clip = grad_clip - - def clip_grads(self, params): - params = list( - filter(lambda p: p.requires_grad and p.grad is not None, params)) - #todo add a line - if len(params) > 0: - return clip_grad.clip_grad_norm_(params, **self.grad_clip) - - def after_train_iter(self, runner): - runner.optimizer.zero_grad() - with amp.scale_loss(runner.outputs['loss'], runner.optimizer ) as scaled_loss: - scaled_loss.backward() - #print('run wan with amp') - if self.grad_clip is not None: - grad_norm = self.clip_grads(runner.model.npu().parameters()) - if grad_norm is not None: - # Add grad norm to the logger - runner.log_buffer.update({'grad_norm': float(grad_norm)}, - runner.outputs['num_samples']) - #print('before optimizer step') - runner.optimizer.step() - #print('after optimizer step') - - - -@HOOKS.register_module() -class Fp16OptimizerHook(OptimizerHook): - """FP16 optimizer hook. - - The steps of fp16 optimizer is as follows. - 1. Scale the loss value. - 2. BP in the fp16 model. - 2. Copy gradients from fp16 model to fp32 weights. - 3. Update fp32 weights. - 4. Copy updated parameters from fp32 weights to fp16 model. - - Refer to https://arxiv.org/abs/1710.03740 for more details. - - Args: - loss_scale (float | str | dict): Scale factor multiplied with loss. - If loss_scale is a float, static loss scaling will be used with - the specified scale. If loss_scale is a string, it must be - 'dynamic', then dynamic loss scaling will be used. - It can also be a dict containing arguments of LossScaler. - Defaults to 512. - """ - - def __init__(self, - grad_clip=None, - coalesce=True, - bucket_size_mb=-1, - loss_scale=512., - distributed=True): - self.grad_clip = grad_clip - self.coalesce = coalesce - self.bucket_size_mb = bucket_size_mb - self.distributed = distributed - if loss_scale == 'dynamic': - self.loss_scaler = LossScaler(mode='dynamic') - elif isinstance(loss_scale, float): - self.loss_scaler = LossScaler(init_scale=loss_scale, mode='static') - elif isinstance(loss_scale, dict): - self.loss_scaler = LossScaler(**loss_scale) - else: - raise ValueError('loss_scale must be of type float, dict, or ' - f'"dynamic", got {loss_scale}') - - def before_run(self, runner): - """Preparing steps before Mixed Precision Training. - - 1. Make a master copy of fp32 weights for optimization. - 2. Convert the main model from fp32 to fp16. - """ - # keep a copy of fp32 weights - old_groups = runner.optimizer.param_groups - runner.optimizer.param_groups = copy.deepcopy( - runner.optimizer.param_groups) - state = defaultdict(dict) - p_map = { - old_p: p - for old_p, p in zip( - chain(*(g['params'] for g in old_groups)), - chain(*(g['params'] for g in runner.optimizer.param_groups))) - } - for k, v in runner.optimizer.state.items(): - state[p_map[k]] = v - runner.optimizer.state = state - # convert model to fp16 - wrap_fp16_model(runner.model) - - def copy_grads_to_fp32(self, fp16_net, fp32_weights): - """Copy gradients from fp16 model to fp32 weight copy.""" - for fp32_param, fp16_param in zip(fp32_weights, fp16_net.parameters()): - if fp16_param.grad is not None: - if fp32_param.grad is None: - fp32_param.grad = fp32_param.data.new(fp32_param.size()) - fp32_param.grad.copy_(fp16_param.grad) - - def copy_params_to_fp16(self, fp16_net, fp32_weights): - """Copy updated params from fp32 weight copy to fp16 model.""" - for fp16_param, fp32_param in zip(fp16_net.parameters(), fp32_weights): - fp16_param.data.copy_(fp32_param.data) - - def after_train_iter(self, runner): - """Backward optimization steps for Mixed Precision Training. For - dynamic loss scaling, please refer `loss_scalar.py` - - 1. Scale the loss by a scale factor. - 2. Backward the loss to obtain the gradients (fp16). - 3. Copy gradients from the model to the fp32 weight copy. - 4. Scale the gradients back and update the fp32 weight copy. - 5. Copy back the params from fp32 weight copy to the fp16 model. - """ - # clear grads of last iteration - runner.model.zero_grad() - runner.optimizer.zero_grad() - # scale the loss value - scaled_loss = runner.outputs['loss'] * self.loss_scaler.loss_scale - scaled_loss.backward() - # copy fp16 grads in the model to fp32 params in the optimizer - - fp32_weights = [] - for param_group in runner.optimizer.param_groups: - fp32_weights += param_group['params'] - self.copy_grads_to_fp32(runner.model, fp32_weights) - # allreduce grads - if self.distributed: - allreduce_grads(fp32_weights, self.coalesce, self.bucket_size_mb) - - has_overflow = self.loss_scaler.has_overflow(fp32_weights) - # if has overflow, skip this iteration - if not has_overflow: - # scale the gradients back - for param in fp32_weights: - if param.grad is not None: - param.grad.div_(self.loss_scaler.loss_scale) - if self.grad_clip is not None: - grad_norm = self.clip_grads(fp32_weights) - if grad_norm is not None: - # Add grad norm to the logger - runner.log_buffer.update({'grad_norm': float(grad_norm)}, - runner.outputs['num_samples']) - # update fp32 params - runner.optimizer.step() - # copy fp32 params to the fp16 model - self.copy_params_to_fp16(runner.model, fp32_weights) - self.loss_scaler.update_scale(has_overflow) - if has_overflow: - runner.logger.warning('Check overflow, downscale loss scale ' - f'to {self.loss_scaler.cur_scale}') +# Copyright (c) Open-MMLab. All rights reserved. +# +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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 copy +from collections import defaultdict +from itertools import chain + +from torch.nn.utils import clip_grad + +from ..dist_utils import allreduce_grads +from ..fp16_utils import LossScaler, wrap_fp16_model +from .hook import HOOKS, Hook +from apex import amp + +@HOOKS.register_module() +class OptimizerHook(Hook): + + def __init__(self, grad_clip=None): + self.grad_clip = grad_clip + + def clip_grads(self, params): + params = list( + filter(lambda p: p.requires_grad and p.grad is not None, params)) + #todo add a line + if len(params) > 0: + return clip_grad.clip_grad_norm_(params, **self.grad_clip) + + def after_train_iter(self, runner): + runner.optimizer.zero_grad() + with amp.scale_loss(runner.outputs['loss'], runner.optimizer ) as scaled_loss: + scaled_loss.backward() + #print('run wan with amp') + if self.grad_clip is not None: + grad_norm = self.clip_grads(runner.model.npu().parameters()) + if grad_norm is not None: + # Add grad norm to the logger + runner.log_buffer.update({'grad_norm': float(grad_norm)}, + runner.outputs['num_samples']) + #print('before optimizer step') + runner.optimizer.step() + #print('after optimizer step') + + + +@HOOKS.register_module() +class Fp16OptimizerHook(OptimizerHook): + """FP16 optimizer hook. + + The steps of fp16 optimizer is as follows. + 1. Scale the loss value. + 2. BP in the fp16 model. + 2. Copy gradients from fp16 model to fp32 weights. + 3. Update fp32 weights. + 4. Copy updated parameters from fp32 weights to fp16 model. + + Refer to https://arxiv.org/abs/1710.03740 for more details. + + Args: + loss_scale (float | str | dict): Scale factor multiplied with loss. + If loss_scale is a float, static loss scaling will be used with + the specified scale. If loss_scale is a string, it must be + 'dynamic', then dynamic loss scaling will be used. + It can also be a dict containing arguments of LossScaler. + Defaults to 512. + """ + + def __init__(self, + grad_clip=None, + coalesce=True, + bucket_size_mb=-1, + loss_scale=512., + distributed=True): + self.grad_clip = grad_clip + self.coalesce = coalesce + self.bucket_size_mb = bucket_size_mb + self.distributed = distributed + if loss_scale == 'dynamic': + self.loss_scaler = LossScaler(mode='dynamic') + elif isinstance(loss_scale, float): + self.loss_scaler = LossScaler(init_scale=loss_scale, mode='static') + elif isinstance(loss_scale, dict): + self.loss_scaler = LossScaler(**loss_scale) + else: + raise ValueError('loss_scale must be of type float, dict, or ' + f'"dynamic", got {loss_scale}') + + def before_run(self, runner): + """Preparing steps before Mixed Precision Training. + + 1. Make a master copy of fp32 weights for optimization. + 2. Convert the main model from fp32 to fp16. + """ + # keep a copy of fp32 weights + old_groups = runner.optimizer.param_groups + runner.optimizer.param_groups = copy.deepcopy( + runner.optimizer.param_groups) + state = defaultdict(dict) + p_map = { + old_p: p + for old_p, p in zip( + chain(*(g['params'] for g in old_groups)), + chain(*(g['params'] for g in runner.optimizer.param_groups))) + } + for k, v in runner.optimizer.state.items(): + state[p_map[k]] = v + runner.optimizer.state = state + # convert model to fp16 + wrap_fp16_model(runner.model) + + def copy_grads_to_fp32(self, fp16_net, fp32_weights): + """Copy gradients from fp16 model to fp32 weight copy.""" + for fp32_param, fp16_param in zip(fp32_weights, fp16_net.parameters()): + if fp16_param.grad is not None: + if fp32_param.grad is None: + fp32_param.grad = fp32_param.data.new(fp32_param.size()) + fp32_param.grad.copy_(fp16_param.grad) + + def copy_params_to_fp16(self, fp16_net, fp32_weights): + """Copy updated params from fp32 weight copy to fp16 model.""" + for fp16_param, fp32_param in zip(fp16_net.parameters(), fp32_weights): + fp16_param.data.copy_(fp32_param.data) + + def after_train_iter(self, runner): + """Backward optimization steps for Mixed Precision Training. For + dynamic loss scaling, please refer `loss_scalar.py` + + 1. Scale the loss by a scale factor. + 2. Backward the loss to obtain the gradients (fp16). + 3. Copy gradients from the model to the fp32 weight copy. + 4. Scale the gradients back and update the fp32 weight copy. + 5. Copy back the params from fp32 weight copy to the fp16 model. + """ + # clear grads of last iteration + runner.model.zero_grad() + runner.optimizer.zero_grad() + # scale the loss value + scaled_loss = runner.outputs['loss'] * self.loss_scaler.loss_scale + scaled_loss.backward() + # copy fp16 grads in the model to fp32 params in the optimizer + + fp32_weights = [] + for param_group in runner.optimizer.param_groups: + fp32_weights += param_group['params'] + self.copy_grads_to_fp32(runner.model, fp32_weights) + # allreduce grads + if self.distributed: + allreduce_grads(fp32_weights, self.coalesce, self.bucket_size_mb) + + has_overflow = self.loss_scaler.has_overflow(fp32_weights) + # if has overflow, skip this iteration + if not has_overflow: + # scale the gradients back + for param in fp32_weights: + if param.grad is not None: + param.grad.div_(self.loss_scaler.loss_scale) + if self.grad_clip is not None: + grad_norm = self.clip_grads(fp32_weights) + if grad_norm is not None: + # Add grad norm to the logger + runner.log_buffer.update({'grad_norm': float(grad_norm)}, + runner.outputs['num_samples']) + # update fp32 params + runner.optimizer.step() + # copy fp32 params to the fp16 model + self.copy_params_to_fp16(runner.model, fp32_weights) + self.loss_scaler.update_scale(has_overflow) + if has_overflow: + runner.logger.warning('Check overflow, downscale loss scale ' + f'to {self.loss_scaler.cur_scale}') diff --git a/PyTorch/contrib/cv/video/R(2+1)D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_1p.py b/PyTorch/contrib/cv/video/R(2+1)D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_1p.py index a2efdbe743..f547576507 100644 --- a/PyTorch/contrib/cv/video/R(2+1)D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_1p.py +++ b/PyTorch/contrib/cv/video/R(2+1)D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_1p.py @@ -1,113 +1,113 @@ -# -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -_base_ = [ - '../../_base_/models/r2plus1d_r34.py', - '../../_base_/default_runtime.py' -] - -# dataset settings -dataset_type = 'RawframeDataset' -data_root = 'data/ucf101/rawframes/' -data_root_val = 'data/ucf101/rawframes/' -split = 1 # official train/test splits. valid numbers: 1, 2, 3 -ann_file_train = f'data/ucf101/ucf101_train_split_{split}_rawframes.txt' -ann_file_val = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' -ann_file_test = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' -img_norm_cfg = dict( - mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_bgr=False) -train_pipeline = [ - dict(type='SampleFrames', clip_len=8, frame_interval=8, num_clips=1), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='RandomResizedCrop'), - dict(type='Resize', scale=(224, 224), keep_ratio=False), - dict(type='Flip', flip_ratio=0.5), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs', 'label']) -] -val_pipeline = [ - dict( - type='SampleFrames', - clip_len=8, - frame_interval=8, - num_clips=1, - test_mode=True), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='CenterCrop', crop_size=224), - dict(type='Flip', flip_ratio=0), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs']) -] -test_pipeline = [ - dict( - type='SampleFrames', - clip_len=8, - frame_interval=8, - num_clips=10, - test_mode=True), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='ThreeCrop', crop_size=256), - dict(type='Flip', flip_ratio=0), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs']) -] -data = dict( - videos_per_gpu=16, - workers_per_gpu=4, - train=dict( - type=dataset_type, - ann_file=ann_file_train, - data_prefix=data_root, - pipeline=train_pipeline), - val=dict( - type=dataset_type, - ann_file=ann_file_val, - data_prefix=data_root_val, - pipeline=val_pipeline), - test=dict( - type=dataset_type, - ann_file=ann_file_val, - data_prefix=data_root_val, - pipeline=test_pipeline)) -# optimizer -optimizer = dict( - type='SGD', lr=0.0025, momentum=0.9, - weight_decay=0.0001) # this lr is used for 8 gpus -optimizer_config = dict(grad_clip=dict(max_norm=40, norm_type=2)) -# learning policy -# lr_config = dict(policy='step', steps=[1,2,3], lrs=[1e-3,1e-4,1e-5]) -lr_config = dict(policy='CosineAnnealing', min_lr=0) -total_epochs = 60 -# total_epochs = 90 - -# runtime settings -checkpoint_config = dict(interval=5) -evaluation = dict( - interval=5, metrics=['top_k_accuracy', 'mean_class_accuracy']) -#work_dir = './work_dirs/r2plus1d_r34_8x8x1_180e_ucf101_rgb3/' -find_unused_parameters = True -load_from = 'https://download.openmmlab.com/mmaction/recognition/r2plus1d/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb_20200729-aa94765e.pth' -resume_from = None - +# +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +_base_ = [ + '../../_base_/models/r2plus1d_r34.py', + '../../_base_/default_runtime.py' +] + +# dataset settings +dataset_type = 'RawframeDataset' +data_root = 'data/ucf101/rawframes/' +data_root_val = 'data/ucf101/rawframes/' +split = 1 # official train/test splits. valid numbers: 1, 2, 3 +ann_file_train = f'data/ucf101/ucf101_train_split_{split}_rawframes.txt' +ann_file_val = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' +ann_file_test = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' +img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_bgr=False) +train_pipeline = [ + dict(type='SampleFrames', clip_len=8, frame_interval=8, num_clips=1), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='RandomResizedCrop'), + dict(type='Resize', scale=(224, 224), keep_ratio=False), + dict(type='Flip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs', 'label']) +] +val_pipeline = [ + dict( + type='SampleFrames', + clip_len=8, + frame_interval=8, + num_clips=1, + test_mode=True), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='CenterCrop', crop_size=224), + dict(type='Flip', flip_ratio=0), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs']) +] +test_pipeline = [ + dict( + type='SampleFrames', + clip_len=8, + frame_interval=8, + num_clips=10, + test_mode=True), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='ThreeCrop', crop_size=256), + dict(type='Flip', flip_ratio=0), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs']) +] +data = dict( + videos_per_gpu=16, + workers_per_gpu=4, + train=dict( + type=dataset_type, + ann_file=ann_file_train, + data_prefix=data_root, + pipeline=train_pipeline), + val=dict( + type=dataset_type, + ann_file=ann_file_val, + data_prefix=data_root_val, + pipeline=val_pipeline), + test=dict( + type=dataset_type, + ann_file=ann_file_val, + data_prefix=data_root_val, + pipeline=test_pipeline)) +# optimizer +optimizer = dict( + type='SGD', lr=0.0025, momentum=0.9, + weight_decay=0.0001) # this lr is used for 8 gpus +optimizer_config = dict(grad_clip=dict(max_norm=40, norm_type=2)) +# learning policy +# lr_config = dict(policy='step', steps=[1,2,3], lrs=[1e-3,1e-4,1e-5]) +lr_config = dict(policy='CosineAnnealing', min_lr=0) +total_epochs = 60 +# total_epochs = 90 + +# runtime settings +checkpoint_config = dict(interval=5) +evaluation = dict( + interval=5, metrics=['top_k_accuracy', 'mean_class_accuracy']) +#work_dir = './work_dirs/r2plus1d_r34_8x8x1_180e_ucf101_rgb3/' +find_unused_parameters = True +load_from = 'https://download.openmmlab.com/mmaction/recognition/r2plus1d/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb_20200729-aa94765e.pth' +resume_from = None + work_dir = './work_dirs/r2plus1d-1p-npu/' \ No newline at end of file diff --git a/PyTorch/contrib/cv/video/R(2+1)D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_1p_perf.py b/PyTorch/contrib/cv/video/R(2+1)D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_1p_perf.py index bde3e578dd..829d7bb6f9 100644 --- a/PyTorch/contrib/cv/video/R(2+1)D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_1p_perf.py +++ b/PyTorch/contrib/cv/video/R(2+1)D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_1p_perf.py @@ -1,113 +1,113 @@ -# -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -_base_ = [ - '../../_base_/models/r2plus1d_r34.py', - '../../_base_/default_runtime.py' -] - -# dataset settings -dataset_type = 'RawframeDataset' -data_root = 'data/ucf101/rawframes/' -data_root_val = 'data/ucf101/rawframes/' -split = 1 # official train/test splits. valid numbers: 1, 2, 3 -ann_file_train = f'data/ucf101/ucf101_train_split_{split}_rawframes.txt' -ann_file_val = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' -ann_file_test = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' -img_norm_cfg = dict( - mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_bgr=False) -train_pipeline = [ - dict(type='SampleFrames', clip_len=8, frame_interval=8, num_clips=1), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='RandomResizedCrop'), - dict(type='Resize', scale=(224, 224), keep_ratio=False), - dict(type='Flip', flip_ratio=0.5), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs', 'label']) -] -val_pipeline = [ - dict( - type='SampleFrames', - clip_len=8, - frame_interval=8, - num_clips=1, - test_mode=True), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='CenterCrop', crop_size=224), - dict(type='Flip', flip_ratio=0), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs']) -] -test_pipeline = [ - dict( - type='SampleFrames', - clip_len=8, - frame_interval=8, - num_clips=10, - test_mode=True), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='ThreeCrop', crop_size=256), - dict(type='Flip', flip_ratio=0), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs']) -] -data = dict( - videos_per_gpu=16, - workers_per_gpu=4, - train=dict( - type=dataset_type, - ann_file=ann_file_train, - data_prefix=data_root, - pipeline=train_pipeline), - val=dict( - type=dataset_type, - ann_file=ann_file_val, - data_prefix=data_root_val, - pipeline=val_pipeline), - test=dict( - type=dataset_type, - ann_file=ann_file_val, - data_prefix=data_root_val, - pipeline=test_pipeline)) -# optimizer -optimizer = dict( - type='SGD', lr=0.0025, momentum=0.9, - weight_decay=0.0001) # this lr is used for 8 gpus -optimizer_config = dict(grad_clip=dict(max_norm=40, norm_type=2)) -# learning policy -# lr_config = dict(policy='step', steps=[1,2,3], lrs=[1e-3,1e-4,1e-5]) -lr_config = dict(policy='CosineAnnealing', min_lr=0) -total_epochs = 1 -# total_epochs = 90 - -# runtime settings -checkpoint_config = dict(interval=5) -evaluation = dict( - interval=5, metrics=['top_k_accuracy', 'mean_class_accuracy']) -#work_dir = './work_dirs/r2plus1d_r34_8x8x1_180e_ucf101_rgb3/' -find_unused_parameters = True -load_from = 'https://download.openmmlab.com/mmaction/recognition/r2plus1d/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb_20200729-aa94765e.pth' -resume_from = None - +# +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +_base_ = [ + '../../_base_/models/r2plus1d_r34.py', + '../../_base_/default_runtime.py' +] + +# dataset settings +dataset_type = 'RawframeDataset' +data_root = 'data/ucf101/rawframes/' +data_root_val = 'data/ucf101/rawframes/' +split = 1 # official train/test splits. valid numbers: 1, 2, 3 +ann_file_train = f'data/ucf101/ucf101_train_split_{split}_rawframes.txt' +ann_file_val = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' +ann_file_test = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' +img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_bgr=False) +train_pipeline = [ + dict(type='SampleFrames', clip_len=8, frame_interval=8, num_clips=1), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='RandomResizedCrop'), + dict(type='Resize', scale=(224, 224), keep_ratio=False), + dict(type='Flip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs', 'label']) +] +val_pipeline = [ + dict( + type='SampleFrames', + clip_len=8, + frame_interval=8, + num_clips=1, + test_mode=True), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='CenterCrop', crop_size=224), + dict(type='Flip', flip_ratio=0), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs']) +] +test_pipeline = [ + dict( + type='SampleFrames', + clip_len=8, + frame_interval=8, + num_clips=10, + test_mode=True), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='ThreeCrop', crop_size=256), + dict(type='Flip', flip_ratio=0), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs']) +] +data = dict( + videos_per_gpu=16, + workers_per_gpu=4, + train=dict( + type=dataset_type, + ann_file=ann_file_train, + data_prefix=data_root, + pipeline=train_pipeline), + val=dict( + type=dataset_type, + ann_file=ann_file_val, + data_prefix=data_root_val, + pipeline=val_pipeline), + test=dict( + type=dataset_type, + ann_file=ann_file_val, + data_prefix=data_root_val, + pipeline=test_pipeline)) +# optimizer +optimizer = dict( + type='SGD', lr=0.0025, momentum=0.9, + weight_decay=0.0001) # this lr is used for 8 gpus +optimizer_config = dict(grad_clip=dict(max_norm=40, norm_type=2)) +# learning policy +# lr_config = dict(policy='step', steps=[1,2,3], lrs=[1e-3,1e-4,1e-5]) +lr_config = dict(policy='CosineAnnealing', min_lr=0) +total_epochs = 1 +# total_epochs = 90 + +# runtime settings +checkpoint_config = dict(interval=5) +evaluation = dict( + interval=5, metrics=['top_k_accuracy', 'mean_class_accuracy']) +#work_dir = './work_dirs/r2plus1d_r34_8x8x1_180e_ucf101_rgb3/' +find_unused_parameters = True +load_from = 'https://download.openmmlab.com/mmaction/recognition/r2plus1d/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb_20200729-aa94765e.pth' +resume_from = None + work_dir = './work_dirs/r2plus1d-1p-npu/' \ No newline at end of file diff --git a/PyTorch/contrib/cv/video/R(2+1)D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_8p.py b/PyTorch/contrib/cv/video/R(2+1)D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_8p.py index edf87d1e4b..d67fd10c1a 100644 --- a/PyTorch/contrib/cv/video/R(2+1)D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_8p.py +++ b/PyTorch/contrib/cv/video/R(2+1)D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_8p.py @@ -1,113 +1,113 @@ -# -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -_base_ = [ - '../../_base_/models/r2plus1d_r34.py', - '../../_base_/default_runtime.py' -] - -# dataset settings -dataset_type = 'RawframeDataset' -data_root = 'data/ucf101/rawframes/' -data_root_val = 'data/ucf101/rawframes/' -split = 1 # official train/test splits. valid numbers: 1, 2, 3 -ann_file_train = f'data/ucf101/ucf101_train_split_{split}_rawframes.txt' -ann_file_val = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' -ann_file_test = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' -img_norm_cfg = dict( - mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_bgr=False) -train_pipeline = [ - dict(type='SampleFrames', clip_len=8, frame_interval=8, num_clips=1), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='RandomResizedCrop'), - dict(type='Resize', scale=(224, 224), keep_ratio=False), - dict(type='Flip', flip_ratio=0.5), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs', 'label']) -] -val_pipeline = [ - dict( - type='SampleFrames', - clip_len=8, - frame_interval=8, - num_clips=1, - test_mode=True), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='CenterCrop', crop_size=224), - dict(type='Flip', flip_ratio=0), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs']) -] -test_pipeline = [ - dict( - type='SampleFrames', - clip_len=8, - frame_interval=8, - num_clips=10, - test_mode=True), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='ThreeCrop', crop_size=256), - dict(type='Flip', flip_ratio=0), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs']) -] -data = dict( - videos_per_gpu=42, - workers_per_gpu=4, - train=dict( - type=dataset_type, - ann_file=ann_file_train, - data_prefix=data_root, - pipeline=train_pipeline), - val=dict( - type=dataset_type, - ann_file=ann_file_val, - data_prefix=data_root_val, - pipeline=val_pipeline), - test=dict( - type=dataset_type, - ann_file=ann_file_val, - data_prefix=data_root_val, - pipeline=test_pipeline)) -# optimizer -optimizer = dict( - type='SGD', lr=0.008, momentum=0.9, - weight_decay=0.0001) # this lr is used for 8 gpus -optimizer_config = dict(grad_clip=dict(max_norm=40, norm_type=2)) -# learning policy -# lr_config = dict(policy='step', steps=[1,2,3], lrs=[1e-3,1e-4,1e-5]) -lr_config = dict(policy='CosineAnnealing', min_lr=0) -total_epochs = 70 -# total_epochs = 90 - -# runtime settings -checkpoint_config = dict(interval=5) -evaluation = dict( - interval=5, metrics=['top_k_accuracy', 'mean_class_accuracy']) -#work_dir = './work_dirs/r2plus1d_r34_8x8x1_180e_ucf101_rgb3/' -find_unused_parameters = True -load_from = 'https://download.openmmlab.com/mmaction/recognition/r2plus1d/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb_20200729-aa94765e.pth' -resume_from = None - +# +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +_base_ = [ + '../../_base_/models/r2plus1d_r34.py', + '../../_base_/default_runtime.py' +] + +# dataset settings +dataset_type = 'RawframeDataset' +data_root = 'data/ucf101/rawframes/' +data_root_val = 'data/ucf101/rawframes/' +split = 1 # official train/test splits. valid numbers: 1, 2, 3 +ann_file_train = f'data/ucf101/ucf101_train_split_{split}_rawframes.txt' +ann_file_val = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' +ann_file_test = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' +img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_bgr=False) +train_pipeline = [ + dict(type='SampleFrames', clip_len=8, frame_interval=8, num_clips=1), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='RandomResizedCrop'), + dict(type='Resize', scale=(224, 224), keep_ratio=False), + dict(type='Flip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs', 'label']) +] +val_pipeline = [ + dict( + type='SampleFrames', + clip_len=8, + frame_interval=8, + num_clips=1, + test_mode=True), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='CenterCrop', crop_size=224), + dict(type='Flip', flip_ratio=0), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs']) +] +test_pipeline = [ + dict( + type='SampleFrames', + clip_len=8, + frame_interval=8, + num_clips=10, + test_mode=True), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='ThreeCrop', crop_size=256), + dict(type='Flip', flip_ratio=0), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs']) +] +data = dict( + videos_per_gpu=42, + workers_per_gpu=4, + train=dict( + type=dataset_type, + ann_file=ann_file_train, + data_prefix=data_root, + pipeline=train_pipeline), + val=dict( + type=dataset_type, + ann_file=ann_file_val, + data_prefix=data_root_val, + pipeline=val_pipeline), + test=dict( + type=dataset_type, + ann_file=ann_file_val, + data_prefix=data_root_val, + pipeline=test_pipeline)) +# optimizer +optimizer = dict( + type='SGD', lr=0.008, momentum=0.9, + weight_decay=0.0001) # this lr is used for 8 gpus +optimizer_config = dict(grad_clip=dict(max_norm=40, norm_type=2)) +# learning policy +# lr_config = dict(policy='step', steps=[1,2,3], lrs=[1e-3,1e-4,1e-5]) +lr_config = dict(policy='CosineAnnealing', min_lr=0) +total_epochs = 70 +# total_epochs = 90 + +# runtime settings +checkpoint_config = dict(interval=5) +evaluation = dict( + interval=5, metrics=['top_k_accuracy', 'mean_class_accuracy']) +#work_dir = './work_dirs/r2plus1d_r34_8x8x1_180e_ucf101_rgb3/' +find_unused_parameters = True +load_from = 'https://download.openmmlab.com/mmaction/recognition/r2plus1d/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb_20200729-aa94765e.pth' +resume_from = None + work_dir = './work_dirs/r2plus1d-8p-npu/' \ No newline at end of file diff --git a/PyTorch/contrib/cv/video/R(2+1)D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_8p_perf.py b/PyTorch/contrib/cv/video/R(2+1)D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_8p_perf.py index b0d83a2679..35f1356e12 100644 --- a/PyTorch/contrib/cv/video/R(2+1)D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_8p_perf.py +++ b/PyTorch/contrib/cv/video/R(2+1)D/configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_8p_perf.py @@ -1,113 +1,113 @@ -# -# Copyright 2020 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -_base_ = [ - '../../_base_/models/r2plus1d_r34.py', - '../../_base_/default_runtime.py' -] - -# dataset settings -dataset_type = 'RawframeDataset' -data_root = 'data/ucf101/rawframes/' -data_root_val = 'data/ucf101/rawframes/' -split = 1 # official train/test splits. valid numbers: 1, 2, 3 -ann_file_train = f'data/ucf101/ucf101_train_split_{split}_rawframes.txt' -ann_file_val = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' -ann_file_test = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' -img_norm_cfg = dict( - mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_bgr=False) -train_pipeline = [ - dict(type='SampleFrames', clip_len=8, frame_interval=8, num_clips=1), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='RandomResizedCrop'), - dict(type='Resize', scale=(224, 224), keep_ratio=False), - dict(type='Flip', flip_ratio=0.5), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs', 'label']) -] -val_pipeline = [ - dict( - type='SampleFrames', - clip_len=8, - frame_interval=8, - num_clips=1, - test_mode=True), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='CenterCrop', crop_size=224), - dict(type='Flip', flip_ratio=0), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs']) -] -test_pipeline = [ - dict( - type='SampleFrames', - clip_len=8, - frame_interval=8, - num_clips=10, - test_mode=True), - dict(type='RawFrameDecode'), - dict(type='Resize', scale=(-1, 256)), - dict(type='ThreeCrop', crop_size=256), - dict(type='Flip', flip_ratio=0), - dict(type='Normalize', **img_norm_cfg), - dict(type='FormatShape', input_format='NCTHW'), - dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), - dict(type='ToTensor', keys=['imgs']) -] -data = dict( - videos_per_gpu=42, - workers_per_gpu=4, - train=dict( - type=dataset_type, - ann_file=ann_file_train, - data_prefix=data_root, - pipeline=train_pipeline), - val=dict( - type=dataset_type, - ann_file=ann_file_val, - data_prefix=data_root_val, - pipeline=val_pipeline), - test=dict( - type=dataset_type, - ann_file=ann_file_val, - data_prefix=data_root_val, - pipeline=test_pipeline)) -# optimizer -optimizer = dict( - type='SGD', lr=0.008, momentum=0.9, - weight_decay=0.0001) # this lr is used for 8 gpus -optimizer_config = dict(grad_clip=dict(max_norm=40, norm_type=2)) -# learning policy -# lr_config = dict(policy='step', steps=[1,2,3], lrs=[1e-3,1e-4,1e-5]) -lr_config = dict(policy='CosineAnnealing', min_lr=0) -total_epochs = 1 -# total_epochs = 90 - -# runtime settings -checkpoint_config = dict(interval=5) -evaluation = dict( - interval=5, metrics=['top_k_accuracy', 'mean_class_accuracy']) -#work_dir = './work_dirs/r2plus1d_r34_8x8x1_180e_ucf101_rgb3/' -find_unused_parameters = True -load_from = 'https://download.openmmlab.com/mmaction/recognition/r2plus1d/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb_20200729-aa94765e.pth' -resume_from = None - +# +# Copyright 2020 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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. + +_base_ = [ + '../../_base_/models/r2plus1d_r34.py', + '../../_base_/default_runtime.py' +] + +# dataset settings +dataset_type = 'RawframeDataset' +data_root = 'data/ucf101/rawframes/' +data_root_val = 'data/ucf101/rawframes/' +split = 1 # official train/test splits. valid numbers: 1, 2, 3 +ann_file_train = f'data/ucf101/ucf101_train_split_{split}_rawframes.txt' +ann_file_val = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' +ann_file_test = f'data/ucf101/ucf101_val_split_{split}_rawframes.txt' +img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_bgr=False) +train_pipeline = [ + dict(type='SampleFrames', clip_len=8, frame_interval=8, num_clips=1), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='RandomResizedCrop'), + dict(type='Resize', scale=(224, 224), keep_ratio=False), + dict(type='Flip', flip_ratio=0.5), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs', 'label']) +] +val_pipeline = [ + dict( + type='SampleFrames', + clip_len=8, + frame_interval=8, + num_clips=1, + test_mode=True), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='CenterCrop', crop_size=224), + dict(type='Flip', flip_ratio=0), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs']) +] +test_pipeline = [ + dict( + type='SampleFrames', + clip_len=8, + frame_interval=8, + num_clips=10, + test_mode=True), + dict(type='RawFrameDecode'), + dict(type='Resize', scale=(-1, 256)), + dict(type='ThreeCrop', crop_size=256), + dict(type='Flip', flip_ratio=0), + dict(type='Normalize', **img_norm_cfg), + dict(type='FormatShape', input_format='NCTHW'), + dict(type='Collect', keys=['imgs', 'label'], meta_keys=[]), + dict(type='ToTensor', keys=['imgs']) +] +data = dict( + videos_per_gpu=42, + workers_per_gpu=4, + train=dict( + type=dataset_type, + ann_file=ann_file_train, + data_prefix=data_root, + pipeline=train_pipeline), + val=dict( + type=dataset_type, + ann_file=ann_file_val, + data_prefix=data_root_val, + pipeline=val_pipeline), + test=dict( + type=dataset_type, + ann_file=ann_file_val, + data_prefix=data_root_val, + pipeline=test_pipeline)) +# optimizer +optimizer = dict( + type='SGD', lr=0.008, momentum=0.9, + weight_decay=0.0001) # this lr is used for 8 gpus +optimizer_config = dict(grad_clip=dict(max_norm=40, norm_type=2)) +# learning policy +# lr_config = dict(policy='step', steps=[1,2,3], lrs=[1e-3,1e-4,1e-5]) +lr_config = dict(policy='CosineAnnealing', min_lr=0) +total_epochs = 1 +# total_epochs = 90 + +# runtime settings +checkpoint_config = dict(interval=5) +evaluation = dict( + interval=5, metrics=['top_k_accuracy', 'mean_class_accuracy']) +#work_dir = './work_dirs/r2plus1d_r34_8x8x1_180e_ucf101_rgb3/' +find_unused_parameters = True +load_from = 'https://download.openmmlab.com/mmaction/recognition/r2plus1d/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb/r2plus1d_r34_256p_8x8x1_180e_kinetics400_rgb_20200729-aa94765e.pth' +resume_from = None + work_dir = './work_dirs/r2plus1d-8p-npu/' \ No newline at end of file diff --git a/PyTorch/contrib/cv/video/R(2+1)D/modelzoo_level.txt b/PyTorch/contrib/cv/video/R(2+1)D/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/cv/video/R(2+1)D/modelzoo_level.txt +++ b/PyTorch/contrib/cv/video/R(2+1)D/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/cv/video/R(2+1)D/test/onnx.sh b/PyTorch/contrib/cv/video/R(2+1)D/test/onnx.sh index 4b04b49017..c9272a2993 100644 --- a/PyTorch/contrib/cv/video/R(2+1)D/test/onnx.sh +++ b/PyTorch/contrib/cv/video/R(2+1)D/test/onnx.sh @@ -1,10 +1,10 @@ -#!/bin/bash - -python3.7 ./tools/deployment/pytorch2onnx.py \ - ./configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_1p.py ./work_dirs/r2plus1d-1p-npu/best_top1_acc_epoch_35.pth \ - --verify --output-file=r2plus1d.onnx --shape 1 3 3 8 256 256 - -#简化onnx。 -python3.7 -m onnxsim --input-shape="1,3,3,8,256,256" --dynamic-input-shape r2plus1d.onnx r2plus1d_sim.onnx - +#!/bin/bash + +python3.7 ./tools/deployment/pytorch2onnx.py \ + ./configs/recognition/r2plus1d/r2plus1d_ucf101_rgb_1p.py ./work_dirs/r2plus1d-1p-npu/best_top1_acc_epoch_35.pth \ + --verify --output-file=r2plus1d.onnx --shape 1 3 3 8 256 256 + +#简化onnx。 +python3.7 -m onnxsim --input-shape="1,3,3,8,256,256" --dynamic-input-shape r2plus1d.onnx r2plus1d_sim.onnx + \ No newline at end of file diff --git a/PyTorch/contrib/cv/video/SiamRPN/pysot-master/pysot/__init__.py b/PyTorch/contrib/cv/video/SiamRPN/pysot-master/pysot/__init__.py index a5f8598aa4..89552b1d3f 100644 --- a/PyTorch/contrib/cv/video/SiamRPN/pysot-master/pysot/__init__.py +++ b/PyTorch/contrib/cv/video/SiamRPN/pysot-master/pysot/__init__.py @@ -1,13 +1,13 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. \ No newline at end of file diff --git a/PyTorch/contrib/cv/video/SiamRPN/pysot-master/pysot/models/__init__.py b/PyTorch/contrib/cv/video/SiamRPN/pysot-master/pysot/models/__init__.py index a5f8598aa4..89552b1d3f 100644 --- a/PyTorch/contrib/cv/video/SiamRPN/pysot-master/pysot/models/__init__.py +++ b/PyTorch/contrib/cv/video/SiamRPN/pysot-master/pysot/models/__init__.py @@ -1,13 +1,13 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. \ No newline at end of file diff --git a/PyTorch/contrib/cv/video/SiamRPN/pysot-master/pysot/tracker/__init__.py b/PyTorch/contrib/cv/video/SiamRPN/pysot-master/pysot/tracker/__init__.py index a5f8598aa4..89552b1d3f 100644 --- a/PyTorch/contrib/cv/video/SiamRPN/pysot-master/pysot/tracker/__init__.py +++ b/PyTorch/contrib/cv/video/SiamRPN/pysot-master/pysot/tracker/__init__.py @@ -1,13 +1,13 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. \ No newline at end of file diff --git a/PyTorch/contrib/cv/video/SiamRPN/pysot-master/pysot/utils/__init__.py b/PyTorch/contrib/cv/video/SiamRPN/pysot-master/pysot/utils/__init__.py index a5f8598aa4..89552b1d3f 100644 --- a/PyTorch/contrib/cv/video/SiamRPN/pysot-master/pysot/utils/__init__.py +++ b/PyTorch/contrib/cv/video/SiamRPN/pysot-master/pysot/utils/__init__.py @@ -1,13 +1,13 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. \ No newline at end of file diff --git a/PyTorch/contrib/cv/video/SiamRPN/pysot-master/toolkit/__init__.py b/PyTorch/contrib/cv/video/SiamRPN/pysot-master/toolkit/__init__.py index a5f8598aa4..89552b1d3f 100644 --- a/PyTorch/contrib/cv/video/SiamRPN/pysot-master/toolkit/__init__.py +++ b/PyTorch/contrib/cv/video/SiamRPN/pysot-master/toolkit/__init__.py @@ -1,13 +1,13 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. \ No newline at end of file diff --git a/PyTorch/contrib/cv/video/SiamRPN/pysot-master/vot_iter/__init__.py b/PyTorch/contrib/cv/video/SiamRPN/pysot-master/vot_iter/__init__.py index a5f8598aa4..89552b1d3f 100644 --- a/PyTorch/contrib/cv/video/SiamRPN/pysot-master/vot_iter/__init__.py +++ b/PyTorch/contrib/cv/video/SiamRPN/pysot-master/vot_iter/__init__.py @@ -1,13 +1,13 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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 +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. \ No newline at end of file diff --git a/PyTorch/contrib/cv/video/SlowFast/config/default_runtime.py b/PyTorch/contrib/cv/video/SlowFast/config/default_runtime.py index 41329bf371..7652836b33 100644 --- a/PyTorch/contrib/cv/video/SlowFast/config/default_runtime.py +++ b/PyTorch/contrib/cv/video/SlowFast/config/default_runtime.py @@ -1,27 +1,27 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ -checkpoint_config = dict(interval=5) -log_config = dict( - interval=1, - hooks=[ - dict(type='TextLoggerHook'), - # dict(type='TensorboardLoggerHook'), - ]) -# runtime settings -dist_params = dict(backend='nccl') -log_level = 'INFO' -load_from = None -resume_from = None -workflow = [('train', 1)] +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +checkpoint_config = dict(interval=5) +log_config = dict( + interval=1, + hooks=[ + dict(type='TextLoggerHook'), + # dict(type='TensorboardLoggerHook'), + ]) +# runtime settings +dist_params = dict(backend='nccl') +log_level = 'INFO' +load_from = None +resume_from = None +workflow = [('train', 1)] diff --git a/PyTorch/contrib/cv/video/SlowFast/mmaction/apis/train.py b/PyTorch/contrib/cv/video/SlowFast/mmaction/apis/train.py index 59f1bc0a8a..d50c7f7e6a 100644 --- a/PyTorch/contrib/cv/video/SlowFast/mmaction/apis/train.py +++ b/PyTorch/contrib/cv/video/SlowFast/mmaction/apis/train.py @@ -1,267 +1,267 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 copy as cp -import os.path as osp - -from apex import amp - -import torch -from mmcv.parallel import MMDataParallel, MMDistributedDataParallel -from mmcv.runner import (DistSamplerSeedHook, EpochBasedRunner, OptimizerHook, - build_optimizer, get_dist_info) -from mmcv.runner.hooks import Fp16OptimizerHook - -from ..core import (DistEvalHook, EvalHook, OmniSourceDistSamplerSeedHook, - OmniSourceRunner) -from ..datasets import build_dataloader, build_dataset -from ..utils import PreciseBNHook, get_root_logger -from .test import multi_gpu_test - - -def train_model(model, - dataset, - cfg, - distributed=False, - validate=False, - test=dict(test_best=False, test_last=False), - timestamp=None, - meta=None): - """Train model entry function. - - Args: - model (nn.Module): The model to be trained. - dataset (:obj:`Dataset`): Train dataset. - cfg (dict): The config dict for training. - distributed (bool): Whether to use distributed training. - Default: False. - validate (bool): Whether to do evaluation. Default: False. - test (dict): The testing option, with two keys: test_last & test_best. - The value is True or False, indicating whether to test the - corresponding checkpoint. - Default: dict(test_best=False, test_last=False). - timestamp (str | None): Local time for runner. Default: None. - meta (dict | None): Meta dict to record some important information. - Default: None - """ - logger = get_root_logger(log_level=cfg.log_level) - - # prepare data loaders - dataset = dataset if isinstance(dataset, (list, tuple)) else [dataset] - - dataloader_setting = dict(videos_per_gpu=cfg.data.get('videos_per_gpu', 1), - workers_per_gpu=cfg.data.get( - 'workers_per_gpu', 1), - num_gpus=len(cfg.gpu_ids), - dist=distributed, - seed=cfg.seed) - dataloader_setting = dict(dataloader_setting, - **cfg.data.get('train_dataloader', {})) - - if cfg.omnisource: - # The option can override videos_per_gpu - train_ratio = cfg.data.get('train_ratio', [1] * len(dataset)) - omni_videos_per_gpu = cfg.data.get('omni_videos_per_gpu', None) - if omni_videos_per_gpu is None: - dataloader_settings = [dataloader_setting] * len(dataset) - else: - dataloader_settings = [] - for videos_per_gpu in omni_videos_per_gpu: - this_setting = cp.deepcopy(dataloader_setting) - this_setting['videos_per_gpu'] = videos_per_gpu - dataloader_settings.append(this_setting) - data_loaders = [ - build_dataloader(ds, **setting) - for ds, setting in zip(dataset, dataloader_settings) - ] - - else: - data_loaders = [ - build_dataloader(ds, **dataloader_setting) for ds in dataset - ] - - # build runner - optimizer = build_optimizer(model, cfg.optimizer) - - # Allow Amp to perform casts as required by the opt_level - if cfg.AMP: - # model, optimizer = amp.initialize(model.cuda(), - # optimizer, - # opt_level=cfg.OPT_LEVEL, - # loss_scale=cfg.LOSS_SCALE) - model, optimizer = amp.initialize(model.npu(), - optimizer, - opt_level=cfg.OPT_LEVEL, - loss_scale=cfg.LOSS_SCALE, - combine_grad=True) - - # put model on gpus - if distributed: - find_unused_parameters = cfg.get('find_unused_parameters', False) - # Sets the `find_unused_parameters` parameter in - # torch.nn.parallel.DistributedDataParallel - model = MMDistributedDataParallel( - model, - device_ids=[torch.npu.current_device()], - broadcast_buffers=False, - find_unused_parameters=find_unused_parameters) - # model = MMDistributedDataParallel( - # model, - # device_ids=[torch.cuda.current_device()], - # broadcast_buffers=False, - # find_unused_parameters=find_unused_parameters) - - else: - # In 1-p training, we don't use Dataparallel - # model = MMDataParallel(model.cuda(cfg.gpu_ids[0]), - # device_ids=cfg.gpu_ids) - model = model.npu() - - Runner = OmniSourceRunner if cfg.omnisource else EpochBasedRunner - runner = Runner(model, - optimizer=optimizer, - work_dir=cfg.work_dir, - logger=logger, - meta=meta, - distributed=distributed) - # an ugly workaround to make .log and .log.json filenames the same - runner.timestamp = timestamp - - # fp16 setting - fp16_cfg = cfg.get('fp16', None) - if fp16_cfg is not None: - optimizer_config = Fp16OptimizerHook(**cfg.optimizer_config, - **fp16_cfg, - distributed=distributed) - elif distributed and 'type' not in cfg.optimizer_config: - optimizer_config = OptimizerHook(**cfg.optimizer_config) - else: - optimizer_config = cfg.optimizer_config - - # register hooks - runner.register_training_hooks(cfg.lr_config, optimizer_config, - cfg.checkpoint_config, cfg.log_config, - cfg.get('momentum_config', None)) - if distributed: - if cfg.omnisource: - runner.register_hook(OmniSourceDistSamplerSeedHook()) - else: - runner.register_hook(DistSamplerSeedHook()) - - # precise bn setting - if cfg.get('precise_bn', False): - precise_bn_dataset = build_dataset(cfg.data.train) - dataloader_setting = dict( - videos_per_gpu=cfg.data.get('videos_per_gpu', 1), - workers_per_gpu=0, # save memory and time - num_gpus=len(cfg.gpu_ids), - dist=distributed, - seed=cfg.seed) - data_loader_precise_bn = build_dataloader(precise_bn_dataset, - **dataloader_setting) - precise_bn_hook = PreciseBNHook(data_loader_precise_bn, - **cfg.get('precise_bn')) - runner.register_hook(precise_bn_hook) - - if validate: - eval_cfg = cfg.get('evaluation', {}) - val_dataset = build_dataset(cfg.data.val, dict(test_mode=True)) - dataloader_setting = dict( - videos_per_gpu=cfg.data.get('videos_per_gpu', 1), - workers_per_gpu=cfg.data.get('workers_per_gpu', 1), - # cfg.gpus will be ignored if distributed - num_gpus=len(cfg.gpu_ids), - dist=distributed, - shuffle=False) - dataloader_setting = dict(dataloader_setting, - **cfg.data.get('val_dataloader', {})) - val_dataloader = build_dataloader(val_dataset, **dataloader_setting) - eval_hook = DistEvalHook(val_dataloader, **eval_cfg) if distributed \ - else EvalHook(val_dataloader, **eval_cfg) - runner.register_hook(eval_hook) - - if cfg.resume_from: - runner.resume(cfg.resume_from) - elif cfg.load_from: - runner.load_checkpoint(cfg.load_from) - runner_kwargs = dict() - if cfg.omnisource: - runner_kwargs = dict(train_ratio=train_ratio) - runner.run(data_loaders, cfg.workflow, cfg.total_epochs, **runner_kwargs) - - if test['test_last'] or test['test_best']: - best_ckpt_path = None - if test['test_best']: - if hasattr(eval_hook, 'best_ckpt_path'): - best_ckpt_path = eval_hook.best_ckpt_path - - if best_ckpt_path is None or not osp.exists(best_ckpt_path): - test['test_best'] = False - if best_ckpt_path is None: - runner.logger.info('Warning: test_best set as True, but ' - 'is not applicable ' - '(eval_hook.best_ckpt_path is None)') - else: - runner.logger.info('Warning: test_best set as True, but ' - 'is not applicable (best_ckpt ' - f'{best_ckpt_path} not found)') - if not test['test_last']: - return - - test_dataset = build_dataset(cfg.data.test, dict(test_mode=True)) - gpu_collect = cfg.get('evaluation', {}).get('gpu_collect', False) - tmpdir = cfg.get('evaluation', {}).get('tmpdir', - osp.join(cfg.work_dir, 'tmp')) - dataloader_setting = dict( - videos_per_gpu=cfg.data.get('videos_per_gpu', 1), - workers_per_gpu=cfg.data.get('workers_per_gpu', 1), - num_gpus=len(cfg.gpu_ids), - dist=distributed, - shuffle=False) - dataloader_setting = dict(dataloader_setting, - **cfg.data.get('test_dataloader', {})) - - test_dataloader = build_dataloader(test_dataset, **dataloader_setting) - - names, ckpts = [], [] - - if test['test_last']: - names.append('last') - ckpts.append(None) - if test['test_best']: - names.append('best') - ckpts.append(best_ckpt_path) - - for name, ckpt in zip(names, ckpts): - if ckpt is not None: - runner.load_checkpoint(ckpt) - - outputs = multi_gpu_test(runner.model, test_dataloader, tmpdir, - gpu_collect) - rank, _ = get_dist_info() - if rank == 0: - out = osp.join(cfg.work_dir, f'{name}_pred.pkl') - test_dataset.dump_results(outputs, out) - - eval_cfg = cfg.get('evaluation', {}) - for key in [ - 'interval', 'tmpdir', 'start', 'gpu_collect', - 'save_best', 'rule', 'by_epoch', 'broadcast_bn_buffers' - ]: - eval_cfg.pop(key, None) - - eval_res = test_dataset.evaluate(outputs, **eval_cfg) - runner.logger.info(f'Testing results of the {name} checkpoint') - for metric_name, val in eval_res.items(): - runner.logger.info(f'{metric_name}: {val:.04f}') +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 copy as cp +import os.path as osp + +from apex import amp + +import torch +from mmcv.parallel import MMDataParallel, MMDistributedDataParallel +from mmcv.runner import (DistSamplerSeedHook, EpochBasedRunner, OptimizerHook, + build_optimizer, get_dist_info) +from mmcv.runner.hooks import Fp16OptimizerHook + +from ..core import (DistEvalHook, EvalHook, OmniSourceDistSamplerSeedHook, + OmniSourceRunner) +from ..datasets import build_dataloader, build_dataset +from ..utils import PreciseBNHook, get_root_logger +from .test import multi_gpu_test + + +def train_model(model, + dataset, + cfg, + distributed=False, + validate=False, + test=dict(test_best=False, test_last=False), + timestamp=None, + meta=None): + """Train model entry function. + + Args: + model (nn.Module): The model to be trained. + dataset (:obj:`Dataset`): Train dataset. + cfg (dict): The config dict for training. + distributed (bool): Whether to use distributed training. + Default: False. + validate (bool): Whether to do evaluation. Default: False. + test (dict): The testing option, with two keys: test_last & test_best. + The value is True or False, indicating whether to test the + corresponding checkpoint. + Default: dict(test_best=False, test_last=False). + timestamp (str | None): Local time for runner. Default: None. + meta (dict | None): Meta dict to record some important information. + Default: None + """ + logger = get_root_logger(log_level=cfg.log_level) + + # prepare data loaders + dataset = dataset if isinstance(dataset, (list, tuple)) else [dataset] + + dataloader_setting = dict(videos_per_gpu=cfg.data.get('videos_per_gpu', 1), + workers_per_gpu=cfg.data.get( + 'workers_per_gpu', 1), + num_gpus=len(cfg.gpu_ids), + dist=distributed, + seed=cfg.seed) + dataloader_setting = dict(dataloader_setting, + **cfg.data.get('train_dataloader', {})) + + if cfg.omnisource: + # The option can override videos_per_gpu + train_ratio = cfg.data.get('train_ratio', [1] * len(dataset)) + omni_videos_per_gpu = cfg.data.get('omni_videos_per_gpu', None) + if omni_videos_per_gpu is None: + dataloader_settings = [dataloader_setting] * len(dataset) + else: + dataloader_settings = [] + for videos_per_gpu in omni_videos_per_gpu: + this_setting = cp.deepcopy(dataloader_setting) + this_setting['videos_per_gpu'] = videos_per_gpu + dataloader_settings.append(this_setting) + data_loaders = [ + build_dataloader(ds, **setting) + for ds, setting in zip(dataset, dataloader_settings) + ] + + else: + data_loaders = [ + build_dataloader(ds, **dataloader_setting) for ds in dataset + ] + + # build runner + optimizer = build_optimizer(model, cfg.optimizer) + + # Allow Amp to perform casts as required by the opt_level + if cfg.AMP: + # model, optimizer = amp.initialize(model.cuda(), + # optimizer, + # opt_level=cfg.OPT_LEVEL, + # loss_scale=cfg.LOSS_SCALE) + model, optimizer = amp.initialize(model.npu(), + optimizer, + opt_level=cfg.OPT_LEVEL, + loss_scale=cfg.LOSS_SCALE, + combine_grad=True) + + # put model on gpus + if distributed: + find_unused_parameters = cfg.get('find_unused_parameters', False) + # Sets the `find_unused_parameters` parameter in + # torch.nn.parallel.DistributedDataParallel + model = MMDistributedDataParallel( + model, + device_ids=[torch.npu.current_device()], + broadcast_buffers=False, + find_unused_parameters=find_unused_parameters) + # model = MMDistributedDataParallel( + # model, + # device_ids=[torch.cuda.current_device()], + # broadcast_buffers=False, + # find_unused_parameters=find_unused_parameters) + + else: + # In 1-p training, we don't use Dataparallel + # model = MMDataParallel(model.cuda(cfg.gpu_ids[0]), + # device_ids=cfg.gpu_ids) + model = model.npu() + + Runner = OmniSourceRunner if cfg.omnisource else EpochBasedRunner + runner = Runner(model, + optimizer=optimizer, + work_dir=cfg.work_dir, + logger=logger, + meta=meta, + distributed=distributed) + # an ugly workaround to make .log and .log.json filenames the same + runner.timestamp = timestamp + + # fp16 setting + fp16_cfg = cfg.get('fp16', None) + if fp16_cfg is not None: + optimizer_config = Fp16OptimizerHook(**cfg.optimizer_config, + **fp16_cfg, + distributed=distributed) + elif distributed and 'type' not in cfg.optimizer_config: + optimizer_config = OptimizerHook(**cfg.optimizer_config) + else: + optimizer_config = cfg.optimizer_config + + # register hooks + runner.register_training_hooks(cfg.lr_config, optimizer_config, + cfg.checkpoint_config, cfg.log_config, + cfg.get('momentum_config', None)) + if distributed: + if cfg.omnisource: + runner.register_hook(OmniSourceDistSamplerSeedHook()) + else: + runner.register_hook(DistSamplerSeedHook()) + + # precise bn setting + if cfg.get('precise_bn', False): + precise_bn_dataset = build_dataset(cfg.data.train) + dataloader_setting = dict( + videos_per_gpu=cfg.data.get('videos_per_gpu', 1), + workers_per_gpu=0, # save memory and time + num_gpus=len(cfg.gpu_ids), + dist=distributed, + seed=cfg.seed) + data_loader_precise_bn = build_dataloader(precise_bn_dataset, + **dataloader_setting) + precise_bn_hook = PreciseBNHook(data_loader_precise_bn, + **cfg.get('precise_bn')) + runner.register_hook(precise_bn_hook) + + if validate: + eval_cfg = cfg.get('evaluation', {}) + val_dataset = build_dataset(cfg.data.val, dict(test_mode=True)) + dataloader_setting = dict( + videos_per_gpu=cfg.data.get('videos_per_gpu', 1), + workers_per_gpu=cfg.data.get('workers_per_gpu', 1), + # cfg.gpus will be ignored if distributed + num_gpus=len(cfg.gpu_ids), + dist=distributed, + shuffle=False) + dataloader_setting = dict(dataloader_setting, + **cfg.data.get('val_dataloader', {})) + val_dataloader = build_dataloader(val_dataset, **dataloader_setting) + eval_hook = DistEvalHook(val_dataloader, **eval_cfg) if distributed \ + else EvalHook(val_dataloader, **eval_cfg) + runner.register_hook(eval_hook) + + if cfg.resume_from: + runner.resume(cfg.resume_from) + elif cfg.load_from: + runner.load_checkpoint(cfg.load_from) + runner_kwargs = dict() + if cfg.omnisource: + runner_kwargs = dict(train_ratio=train_ratio) + runner.run(data_loaders, cfg.workflow, cfg.total_epochs, **runner_kwargs) + + if test['test_last'] or test['test_best']: + best_ckpt_path = None + if test['test_best']: + if hasattr(eval_hook, 'best_ckpt_path'): + best_ckpt_path = eval_hook.best_ckpt_path + + if best_ckpt_path is None or not osp.exists(best_ckpt_path): + test['test_best'] = False + if best_ckpt_path is None: + runner.logger.info('Warning: test_best set as True, but ' + 'is not applicable ' + '(eval_hook.best_ckpt_path is None)') + else: + runner.logger.info('Warning: test_best set as True, but ' + 'is not applicable (best_ckpt ' + f'{best_ckpt_path} not found)') + if not test['test_last']: + return + + test_dataset = build_dataset(cfg.data.test, dict(test_mode=True)) + gpu_collect = cfg.get('evaluation', {}).get('gpu_collect', False) + tmpdir = cfg.get('evaluation', {}).get('tmpdir', + osp.join(cfg.work_dir, 'tmp')) + dataloader_setting = dict( + videos_per_gpu=cfg.data.get('videos_per_gpu', 1), + workers_per_gpu=cfg.data.get('workers_per_gpu', 1), + num_gpus=len(cfg.gpu_ids), + dist=distributed, + shuffle=False) + dataloader_setting = dict(dataloader_setting, + **cfg.data.get('test_dataloader', {})) + + test_dataloader = build_dataloader(test_dataset, **dataloader_setting) + + names, ckpts = [], [] + + if test['test_last']: + names.append('last') + ckpts.append(None) + if test['test_best']: + names.append('best') + ckpts.append(best_ckpt_path) + + for name, ckpt in zip(names, ckpts): + if ckpt is not None: + runner.load_checkpoint(ckpt) + + outputs = multi_gpu_test(runner.model, test_dataloader, tmpdir, + gpu_collect) + rank, _ = get_dist_info() + if rank == 0: + out = osp.join(cfg.work_dir, f'{name}_pred.pkl') + test_dataset.dump_results(outputs, out) + + eval_cfg = cfg.get('evaluation', {}) + for key in [ + 'interval', 'tmpdir', 'start', 'gpu_collect', + 'save_best', 'rule', 'by_epoch', 'broadcast_bn_buffers' + ]: + eval_cfg.pop(key, None) + + eval_res = test_dataset.evaluate(outputs, **eval_cfg) + runner.logger.info(f'Testing results of the {name} checkpoint') + for metric_name, val in eval_res.items(): + runner.logger.info(f'{metric_name}: {val:.04f}') diff --git a/PyTorch/contrib/cv/video/SlowFast/mmaction/datasets/pipelines/formating.py b/PyTorch/contrib/cv/video/SlowFast/mmaction/datasets/pipelines/formating.py index a7d0876a04..3811c61add 100644 --- a/PyTorch/contrib/cv/video/SlowFast/mmaction/datasets/pipelines/formating.py +++ b/PyTorch/contrib/cv/video/SlowFast/mmaction/datasets/pipelines/formating.py @@ -1,378 +1,378 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 collections.abc import Sequence - -import mmcv -import numpy as np -import torch -from mmcv.parallel import DataContainer as DC - -from ..builder import PIPELINES - - -def to_tensor(data): - """Convert objects of various python types to :obj:`torch.Tensor`. - - Supported types are: :class:`numpy.ndarray`, :class:`torch.Tensor`, - :class:`Sequence`, :class:`int` and :class:`float`. - """ - if isinstance(data, torch.Tensor): - return data - if isinstance(data, np.ndarray): - return torch.from_numpy(data) - if isinstance(data, Sequence) and not mmcv.is_str(data): - return torch.tensor(data) - if isinstance(data, int): - return torch.LongTensor([data]) - if isinstance(data, float): - return torch.FloatTensor([data]) - raise TypeError(f'type {type(data)} cannot be converted to tensor.') - - -@PIPELINES.register_module() -class ToTensor: - """Convert some values in results dict to `torch.Tensor` type in data - loader pipeline. - - Args: - keys (Sequence[str]): Required keys to be converted. - """ - def __init__(self, keys): - self.keys = keys - - def __call__(self, results): - """Performs the ToTensor formating. - - Args: - results (dict): The resulting dict to be modified and passed - to the next transform in pipeline. - """ - for key in self.keys: - results[key] = to_tensor(results[key]) - return results - - def __repr__(self): - return f'{self.__class__.__name__}(keys={self.keys})' - - -@PIPELINES.register_module() -class Rename: - """Rename the key in results. - - Args: - mapping (dict): The keys in results that need to be renamed. The key of - the dict is the original name, while the value is the new name. If - the original name not found in results, do nothing. - Default: dict(). - """ - def __init__(self, mapping): - self.mapping = mapping - - def __call__(self, results): - for key, value in self.mapping.items(): - if key in results: - assert isinstance(key, str) and isinstance(value, str) - assert value not in results, ('the new name already exists in ' - 'results') - results[value] = results[key] - results.pop(key) - return results - - -@PIPELINES.register_module() -class ToDataContainer: - """Convert the data to DataContainer. - - Args: - fields (Sequence[dict]): Required fields to be converted - with keys and attributes. E.g. - fields=(dict(key='gt_bbox', stack=False),). - Note that key can also be a list of keys, if so, every tensor in - the list will be converted to DataContainer. - """ - def __init__(self, fields): - self.fields = fields - - def __call__(self, results): - """Performs the ToDataContainer formating. - - Args: - results (dict): The resulting dict to be modified and passed - to the next transform in pipeline. - """ - for field in self.fields: - _field = field.copy() - key = _field.pop('key') - if isinstance(key, list): - for item in key: - results[item] = DC(results[item], **_field) - else: - results[key] = DC(results[key], **_field) - return results - - def __repr__(self): - return self.__class__.__name__ + f'(fields={self.fields})' - - -@PIPELINES.register_module() -class ImageToTensor: - """Convert image type to `torch.Tensor` type. - - Args: - keys (Sequence[str]): Required keys to be converted. - """ - def __init__(self, keys): - self.keys = keys - - def __call__(self, results): - """Performs the ImageToTensor formating. - - Args: - results (dict): The resulting dict to be modified and passed - to the next transform in pipeline. - """ - for key in self.keys: - results[key] = to_tensor(results[key].transpose(2, 0, 1)) - return results - - def __repr__(self): - return f'{self.__class__.__name__}(keys={self.keys})' - - -@PIPELINES.register_module() -class Transpose: - """Transpose image channels to a given order. - - Args: - keys (Sequence[str]): Required keys to be converted. - order (Sequence[int]): Image channel order. - """ - def __init__(self, keys, order): - self.keys = keys - self.order = order - - def __call__(self, results): - """Performs the Transpose formatting. - - Args: - results (dict): The resulting dict to be modified and passed - to the next transform in pipeline. - """ - for key in self.keys: - results[key] = results[key].transpose(self.order) - return results - - def __repr__(self): - return (f'{self.__class__.__name__}(' - f'keys={self.keys}, order={self.order})') - - -@PIPELINES.register_module() -class Collect: - """Collect data from the loader relevant to the specific task. - - This keeps the items in ``keys`` as it is, and collect items in - ``meta_keys`` into a meta item called ``meta_name``.This is usually - the last stage of the data loader pipeline. - For example, when keys='imgs', meta_keys=('filename', 'label', - 'original_shape'), meta_name='img_metas', the results will be a dict with - keys 'imgs' and 'img_metas', where 'img_metas' is a DataContainer of - another dict with keys 'filename', 'label', 'original_shape'. - - Args: - keys (Sequence[str]): Required keys to be collected. - meta_name (str): The name of the key that contains meta infomation. - This key is always populated. Default: "img_metas". - meta_keys (Sequence[str]): Keys that are collected under meta_name. - The contents of the ``meta_name`` dictionary depends on - ``meta_keys``. - By default this includes: - - - "filename": path to the image file - - "label": label of the image file - - "original_shape": original shape of the image as a tuple - (h, w, c) - - "img_shape": shape of the image input to the network as a tuple - (h, w, c). Note that images may be zero padded on the - bottom/right, if the batch tensor is larger than this shape. - - "pad_shape": image shape after padding - - "flip_direction": a str in ("horiziontal", "vertival") to - indicate if the image is fliped horizontally or vertically. - - "img_norm_cfg": a dict of normalization information: - - mean - per channel mean subtraction - - std - per channel std divisor - - to_rgb - bool indicating if bgr was converted to rgb - nested (bool): If set as True, will apply data[x] = [data[x]] to all - items in data. The arg is added for compatibility. Default: False. - """ - def __init__(self, - keys, - meta_keys=('filename', 'label', 'original_shape', 'img_shape', - 'pad_shape', 'flip_direction', 'img_norm_cfg'), - meta_name='img_metas', - nested=False): - self.keys = keys - self.meta_keys = meta_keys - self.meta_name = meta_name - self.nested = nested - - def __call__(self, results): - """Performs the Collect formating. - - Args: - results (dict): The resulting dict to be modified and passed - to the next transform in pipeline. - """ - data = {} - for key in self.keys: - data[key] = results[key] - - if len(self.meta_keys) != 0: - meta = {} - for key in self.meta_keys: - meta[key] = results[key] - data[self.meta_name] = DC(meta, cpu_only=True) - if self.nested: - for k in data: - data[k] = [data[k]] - - return data - - def __repr__(self): - return (f'{self.__class__.__name__}(' - f'keys={self.keys}, meta_keys={self.meta_keys}, ' - f'nested={self.nested})') - - -@PIPELINES.register_module() -class FormatShape: - """Format final imgs shape to the given input_format. - - Required keys are "imgs", "num_clips" and "clip_len", added or modified - keys are "imgs" and "input_shape". - - Args: - input_format (str): Define the final imgs format. - collapse (bool): To collpase input_format N... to ... (NCTHW to CTHW, - etc.) if N is 1. Should be set as True when training and testing - detectors. Default: False. - """ - def __init__(self, input_format, collapse=False): - self.input_format = input_format - self.collapse = collapse - if self.input_format not in ['NCTHW', 'NCHW', 'NCHW_Flow', 'NPTCHW']: - raise ValueError( - f'The input format {self.input_format} is invalid.') - - def __call__(self, results): - """Performs the FormatShape formating. - - Args: - results (dict): The resulting dict to be modified and passed - to the next transform in pipeline. - """ - if not isinstance(results['imgs'], np.ndarray): - results['imgs'] = np.array(results['imgs']) - imgs = results['imgs'] - # [M x H x W x C] - # M = 1 * N_crops * N_clips * L - if self.collapse: - assert results['num_clips'] == 1 - - if self.input_format == 'NCTHW': - num_clips = results['num_clips'] - clip_len = results['clip_len'] - - imgs = imgs.reshape((-1, num_clips, clip_len) + imgs.shape[1:]) - # N_crops x N_clips x L x H x W x C - imgs = np.transpose(imgs, (0, 1, 5, 2, 3, 4)) - # N_crops x N_clips x C x L x H x W - imgs = imgs.reshape((-1, ) + imgs.shape[2:]) - # M' x C x L x H x W - # M' = N_crops x N_clips - elif self.input_format == 'NCHW': - imgs = np.transpose(imgs, (0, 3, 1, 2)) - # M x C x H x W - elif self.input_format == 'NCHW_Flow': - num_clips = results['num_clips'] - clip_len = results['clip_len'] - imgs = imgs.reshape((-1, num_clips, clip_len) + imgs.shape[1:]) - # N_crops x N_clips x L x H x W x C - imgs = np.transpose(imgs, (0, 1, 2, 5, 3, 4)) - # N_crops x N_clips x L x C x H x W - imgs = imgs.reshape((-1, imgs.shape[2] * imgs.shape[3]) + - imgs.shape[4:]) - # M' x C' x H x W - # M' = N_crops x N_clips - # C' = L x C - elif self.input_format == 'NPTCHW': - num_proposals = results['num_proposals'] - num_clips = results['num_clips'] - clip_len = results['clip_len'] - imgs = imgs.reshape((num_proposals, num_clips * clip_len) + - imgs.shape[1:]) - # P x M x H x W x C - # M = N_clips x L - imgs = np.transpose(imgs, (0, 1, 4, 2, 3)) - # P x M x C x H x W - if self.collapse: - assert imgs.shape[0] == 1 - imgs = imgs.squeeze(0) - - results['imgs'] = imgs - results['input_shape'] = imgs.shape - return results - - def __repr__(self): - repr_str = self.__class__.__name__ - repr_str += f"(input_format='{self.input_format}')" - return repr_str - - -@PIPELINES.register_module() -class FormatAudioShape: - """Format final audio shape to the given input_format. - - Required keys are "imgs", "num_clips" and "clip_len", added or modified - keys are "imgs" and "input_shape". - - Args: - input_format (str): Define the final imgs format. - """ - def __init__(self, input_format): - self.input_format = input_format - if self.input_format not in ['NCTF']: - raise ValueError( - f'The input format {self.input_format} is invalid.') - - def __call__(self, results): - """Performs the FormatShape formatting. - - Args: - results (dict): The resulting dict to be modified and passed - to the next transform in pipeline. - """ - audios = results['audios'] - # clip x sample x freq -> clip x channel x sample x freq - clip, sample, freq = audios.shape - audios = audios.reshape(clip, 1, sample, freq) - results['audios'] = audios - results['input_shape'] = audios.shape - return results - - def __repr__(self): - repr_str = self.__class__.__name__ - repr_str += f"(input_format='{self.input_format}')" - return repr_str +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 collections.abc import Sequence + +import mmcv +import numpy as np +import torch +from mmcv.parallel import DataContainer as DC + +from ..builder import PIPELINES + + +def to_tensor(data): + """Convert objects of various python types to :obj:`torch.Tensor`. + + Supported types are: :class:`numpy.ndarray`, :class:`torch.Tensor`, + :class:`Sequence`, :class:`int` and :class:`float`. + """ + if isinstance(data, torch.Tensor): + return data + if isinstance(data, np.ndarray): + return torch.from_numpy(data) + if isinstance(data, Sequence) and not mmcv.is_str(data): + return torch.tensor(data) + if isinstance(data, int): + return torch.LongTensor([data]) + if isinstance(data, float): + return torch.FloatTensor([data]) + raise TypeError(f'type {type(data)} cannot be converted to tensor.') + + +@PIPELINES.register_module() +class ToTensor: + """Convert some values in results dict to `torch.Tensor` type in data + loader pipeline. + + Args: + keys (Sequence[str]): Required keys to be converted. + """ + def __init__(self, keys): + self.keys = keys + + def __call__(self, results): + """Performs the ToTensor formating. + + Args: + results (dict): The resulting dict to be modified and passed + to the next transform in pipeline. + """ + for key in self.keys: + results[key] = to_tensor(results[key]) + return results + + def __repr__(self): + return f'{self.__class__.__name__}(keys={self.keys})' + + +@PIPELINES.register_module() +class Rename: + """Rename the key in results. + + Args: + mapping (dict): The keys in results that need to be renamed. The key of + the dict is the original name, while the value is the new name. If + the original name not found in results, do nothing. + Default: dict(). + """ + def __init__(self, mapping): + self.mapping = mapping + + def __call__(self, results): + for key, value in self.mapping.items(): + if key in results: + assert isinstance(key, str) and isinstance(value, str) + assert value not in results, ('the new name already exists in ' + 'results') + results[value] = results[key] + results.pop(key) + return results + + +@PIPELINES.register_module() +class ToDataContainer: + """Convert the data to DataContainer. + + Args: + fields (Sequence[dict]): Required fields to be converted + with keys and attributes. E.g. + fields=(dict(key='gt_bbox', stack=False),). + Note that key can also be a list of keys, if so, every tensor in + the list will be converted to DataContainer. + """ + def __init__(self, fields): + self.fields = fields + + def __call__(self, results): + """Performs the ToDataContainer formating. + + Args: + results (dict): The resulting dict to be modified and passed + to the next transform in pipeline. + """ + for field in self.fields: + _field = field.copy() + key = _field.pop('key') + if isinstance(key, list): + for item in key: + results[item] = DC(results[item], **_field) + else: + results[key] = DC(results[key], **_field) + return results + + def __repr__(self): + return self.__class__.__name__ + f'(fields={self.fields})' + + +@PIPELINES.register_module() +class ImageToTensor: + """Convert image type to `torch.Tensor` type. + + Args: + keys (Sequence[str]): Required keys to be converted. + """ + def __init__(self, keys): + self.keys = keys + + def __call__(self, results): + """Performs the ImageToTensor formating. + + Args: + results (dict): The resulting dict to be modified and passed + to the next transform in pipeline. + """ + for key in self.keys: + results[key] = to_tensor(results[key].transpose(2, 0, 1)) + return results + + def __repr__(self): + return f'{self.__class__.__name__}(keys={self.keys})' + + +@PIPELINES.register_module() +class Transpose: + """Transpose image channels to a given order. + + Args: + keys (Sequence[str]): Required keys to be converted. + order (Sequence[int]): Image channel order. + """ + def __init__(self, keys, order): + self.keys = keys + self.order = order + + def __call__(self, results): + """Performs the Transpose formatting. + + Args: + results (dict): The resulting dict to be modified and passed + to the next transform in pipeline. + """ + for key in self.keys: + results[key] = results[key].transpose(self.order) + return results + + def __repr__(self): + return (f'{self.__class__.__name__}(' + f'keys={self.keys}, order={self.order})') + + +@PIPELINES.register_module() +class Collect: + """Collect data from the loader relevant to the specific task. + + This keeps the items in ``keys`` as it is, and collect items in + ``meta_keys`` into a meta item called ``meta_name``.This is usually + the last stage of the data loader pipeline. + For example, when keys='imgs', meta_keys=('filename', 'label', + 'original_shape'), meta_name='img_metas', the results will be a dict with + keys 'imgs' and 'img_metas', where 'img_metas' is a DataContainer of + another dict with keys 'filename', 'label', 'original_shape'. + + Args: + keys (Sequence[str]): Required keys to be collected. + meta_name (str): The name of the key that contains meta infomation. + This key is always populated. Default: "img_metas". + meta_keys (Sequence[str]): Keys that are collected under meta_name. + The contents of the ``meta_name`` dictionary depends on + ``meta_keys``. + By default this includes: + + - "filename": path to the image file + - "label": label of the image file + - "original_shape": original shape of the image as a tuple + (h, w, c) + - "img_shape": shape of the image input to the network as a tuple + (h, w, c). Note that images may be zero padded on the + bottom/right, if the batch tensor is larger than this shape. + - "pad_shape": image shape after padding + - "flip_direction": a str in ("horiziontal", "vertival") to + indicate if the image is fliped horizontally or vertically. + - "img_norm_cfg": a dict of normalization information: + - mean - per channel mean subtraction + - std - per channel std divisor + - to_rgb - bool indicating if bgr was converted to rgb + nested (bool): If set as True, will apply data[x] = [data[x]] to all + items in data. The arg is added for compatibility. Default: False. + """ + def __init__(self, + keys, + meta_keys=('filename', 'label', 'original_shape', 'img_shape', + 'pad_shape', 'flip_direction', 'img_norm_cfg'), + meta_name='img_metas', + nested=False): + self.keys = keys + self.meta_keys = meta_keys + self.meta_name = meta_name + self.nested = nested + + def __call__(self, results): + """Performs the Collect formating. + + Args: + results (dict): The resulting dict to be modified and passed + to the next transform in pipeline. + """ + data = {} + for key in self.keys: + data[key] = results[key] + + if len(self.meta_keys) != 0: + meta = {} + for key in self.meta_keys: + meta[key] = results[key] + data[self.meta_name] = DC(meta, cpu_only=True) + if self.nested: + for k in data: + data[k] = [data[k]] + + return data + + def __repr__(self): + return (f'{self.__class__.__name__}(' + f'keys={self.keys}, meta_keys={self.meta_keys}, ' + f'nested={self.nested})') + + +@PIPELINES.register_module() +class FormatShape: + """Format final imgs shape to the given input_format. + + Required keys are "imgs", "num_clips" and "clip_len", added or modified + keys are "imgs" and "input_shape". + + Args: + input_format (str): Define the final imgs format. + collapse (bool): To collpase input_format N... to ... (NCTHW to CTHW, + etc.) if N is 1. Should be set as True when training and testing + detectors. Default: False. + """ + def __init__(self, input_format, collapse=False): + self.input_format = input_format + self.collapse = collapse + if self.input_format not in ['NCTHW', 'NCHW', 'NCHW_Flow', 'NPTCHW']: + raise ValueError( + f'The input format {self.input_format} is invalid.') + + def __call__(self, results): + """Performs the FormatShape formating. + + Args: + results (dict): The resulting dict to be modified and passed + to the next transform in pipeline. + """ + if not isinstance(results['imgs'], np.ndarray): + results['imgs'] = np.array(results['imgs']) + imgs = results['imgs'] + # [M x H x W x C] + # M = 1 * N_crops * N_clips * L + if self.collapse: + assert results['num_clips'] == 1 + + if self.input_format == 'NCTHW': + num_clips = results['num_clips'] + clip_len = results['clip_len'] + + imgs = imgs.reshape((-1, num_clips, clip_len) + imgs.shape[1:]) + # N_crops x N_clips x L x H x W x C + imgs = np.transpose(imgs, (0, 1, 5, 2, 3, 4)) + # N_crops x N_clips x C x L x H x W + imgs = imgs.reshape((-1, ) + imgs.shape[2:]) + # M' x C x L x H x W + # M' = N_crops x N_clips + elif self.input_format == 'NCHW': + imgs = np.transpose(imgs, (0, 3, 1, 2)) + # M x C x H x W + elif self.input_format == 'NCHW_Flow': + num_clips = results['num_clips'] + clip_len = results['clip_len'] + imgs = imgs.reshape((-1, num_clips, clip_len) + imgs.shape[1:]) + # N_crops x N_clips x L x H x W x C + imgs = np.transpose(imgs, (0, 1, 2, 5, 3, 4)) + # N_crops x N_clips x L x C x H x W + imgs = imgs.reshape((-1, imgs.shape[2] * imgs.shape[3]) + + imgs.shape[4:]) + # M' x C' x H x W + # M' = N_crops x N_clips + # C' = L x C + elif self.input_format == 'NPTCHW': + num_proposals = results['num_proposals'] + num_clips = results['num_clips'] + clip_len = results['clip_len'] + imgs = imgs.reshape((num_proposals, num_clips * clip_len) + + imgs.shape[1:]) + # P x M x H x W x C + # M = N_clips x L + imgs = np.transpose(imgs, (0, 1, 4, 2, 3)) + # P x M x C x H x W + if self.collapse: + assert imgs.shape[0] == 1 + imgs = imgs.squeeze(0) + + results['imgs'] = imgs + results['input_shape'] = imgs.shape + return results + + def __repr__(self): + repr_str = self.__class__.__name__ + repr_str += f"(input_format='{self.input_format}')" + return repr_str + + +@PIPELINES.register_module() +class FormatAudioShape: + """Format final audio shape to the given input_format. + + Required keys are "imgs", "num_clips" and "clip_len", added or modified + keys are "imgs" and "input_shape". + + Args: + input_format (str): Define the final imgs format. + """ + def __init__(self, input_format): + self.input_format = input_format + if self.input_format not in ['NCTF']: + raise ValueError( + f'The input format {self.input_format} is invalid.') + + def __call__(self, results): + """Performs the FormatShape formatting. + + Args: + results (dict): The resulting dict to be modified and passed + to the next transform in pipeline. + """ + audios = results['audios'] + # clip x sample x freq -> clip x channel x sample x freq + clip, sample, freq = audios.shape + audios = audios.reshape(clip, 1, sample, freq) + results['audios'] = audios + results['input_shape'] = audios.shape + return results + + def __repr__(self): + repr_str = self.__class__.__name__ + repr_str += f"(input_format='{self.input_format}')" + return repr_str diff --git a/PyTorch/contrib/cv/video/SlowFast/mmaction/models/backbones/resnet3d_slowfast.py b/PyTorch/contrib/cv/video/SlowFast/mmaction/models/backbones/resnet3d_slowfast.py index a5d23bb38e..e61842a2ba 100644 --- a/PyTorch/contrib/cv/video/SlowFast/mmaction/models/backbones/resnet3d_slowfast.py +++ b/PyTorch/contrib/cv/video/SlowFast/mmaction/models/backbones/resnet3d_slowfast.py @@ -1,531 +1,531 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 warnings - -import torch -import torch.nn as nn -from mmcv.cnn import ConvModule, kaiming_init -from mmcv.runner import _load_checkpoint, load_checkpoint -from mmcv.utils import print_log - -from ...utils import get_root_logger -from ..builder import BACKBONES -from .resnet3d import ResNet3d - -mmdet_imported = False - - -class ResNet3dPathway(ResNet3d): - """A pathway of Slowfast based on ResNet3d. - - Args: - *args (arguments): Arguments same as :class:``ResNet3d``. - lateral (bool): Determines whether to enable the lateral connection - from another pathway. Default: False. - speed_ratio (int): Speed ratio indicating the ratio between time - dimension of the fast and slow pathway, corresponding to the - ``alpha`` in the paper. Default: 8. - channel_ratio (int): Reduce the channel number of fast pathway - by ``channel_ratio``, corresponding to ``beta`` in the paper. - Default: 8. - fusion_kernel (int): The kernel size of lateral fusion. - Default: 5. - **kwargs (keyword arguments): Keywords arguments for ResNet3d. - """ - def __init__(self, - *args, - lateral=False, - speed_ratio=8, - channel_ratio=8, - fusion_kernel=5, - **kwargs): - self.lateral = lateral - self.speed_ratio = speed_ratio - self.channel_ratio = channel_ratio - self.fusion_kernel = fusion_kernel - super().__init__(*args, **kwargs) - self.inplanes = self.base_channels - if self.lateral: - self.conv1_lateral = ConvModule( - self.inplanes // self.channel_ratio, - # https://arxiv.org/abs/1812.03982, the - # third type of lateral connection has out_channel: - # 2 * \beta * C - self.inplanes * 2 // self.channel_ratio, - kernel_size=(fusion_kernel, 1, 1), - stride=(self.speed_ratio, 1, 1), - padding=((fusion_kernel - 1) // 2, 0, 0), - bias=False, - conv_cfg=self.conv_cfg, - norm_cfg=self.norm_cfg, - act_cfg=None) - - self.lateral_connections = [] - for i in range(len(self.stage_blocks)): - planes = self.base_channels * 2**i - self.inplanes = planes * self.block.expansion - - if lateral and i != self.num_stages - 1: - # no lateral connection needed in final stage - lateral_name = f'layer{(i + 1)}_lateral' - setattr( - self, lateral_name, - ConvModule(self.inplanes // self.channel_ratio, - self.inplanes * 2 // self.channel_ratio, - kernel_size=(fusion_kernel, 1, 1), - stride=(self.speed_ratio, 1, 1), - padding=((fusion_kernel - 1) // 2, 0, 0), - bias=False, - conv_cfg=self.conv_cfg, - norm_cfg=self.norm_cfg, - act_cfg=None)) - self.lateral_connections.append(lateral_name) - - def make_res_layer(self, - block, - inplanes, - planes, - blocks, - spatial_stride=1, - temporal_stride=1, - dilation=1, - style='pytorch', - inflate=1, - inflate_style='3x1x1', - non_local=0, - non_local_cfg=dict(), - conv_cfg=None, - norm_cfg=None, - act_cfg=None, - with_cp=False): - """Build residual layer for Slowfast. - - Args: - block (nn.Module): Residual module to be built. - inplanes (int): Number of channels for the input - feature in each block. - planes (int): Number of channels for the output - feature in each block. - blocks (int): Number of residual blocks. - spatial_stride (int | Sequence[int]): Spatial strides - in residual and conv layers. Default: 1. - temporal_stride (int | Sequence[int]): Temporal strides in - residual and conv layers. Default: 1. - dilation (int): Spacing between kernel elements. Default: 1. - style (str): ``pytorch`` or ``caffe``. If set to ``pytorch``, - the stride-two layer is the 3x3 conv layer, - otherwise the stride-two layer is the first 1x1 conv layer. - Default: ``pytorch``. - inflate (int | Sequence[int]): Determine whether to inflate - for each block. Default: 1. - inflate_style (str): ``3x1x1`` or ``3x3x3``. which determines - the kernel sizes and padding strides for conv1 and - conv2 in each block. Default: ``3x1x1``. - non_local (int | Sequence[int]): Determine whether to apply - non-local module in the corresponding block of each stages. - Default: 0. - non_local_cfg (dict): Config for non-local module. - Default: ``dict()``. - conv_cfg (dict | None): Config for conv layers. Default: None. - norm_cfg (dict | None): Config for norm layers. Default: None. - act_cfg (dict | None): Config for activate layers. Default: None. - with_cp (bool): Use checkpoint or not. Using checkpoint will save - some memory while slowing down the training speed. - Default: False. - - Returns: - nn.Module: A residual layer for the given config. - """ - inflate = inflate if not isinstance(inflate, - int) else (inflate, ) * blocks - non_local = non_local if not isinstance( - non_local, int) else (non_local, ) * blocks - assert len(inflate) == blocks and len(non_local) == blocks - if self.lateral: - lateral_inplanes = inplanes * 2 // self.channel_ratio - else: - lateral_inplanes = 0 - if (spatial_stride != 1 - or (inplanes + lateral_inplanes) != planes * block.expansion): - downsample = ConvModule(inplanes + lateral_inplanes, - planes * block.expansion, - kernel_size=1, - stride=(temporal_stride, spatial_stride, - spatial_stride), - bias=False, - conv_cfg=conv_cfg, - norm_cfg=norm_cfg, - act_cfg=None) - else: - downsample = None - - layers = [] - layers.append( - block(inplanes + lateral_inplanes, - planes, - spatial_stride, - temporal_stride, - dilation, - downsample, - style=style, - inflate=(inflate[0] == 1), - inflate_style=inflate_style, - non_local=(non_local[0] == 1), - non_local_cfg=non_local_cfg, - conv_cfg=conv_cfg, - norm_cfg=norm_cfg, - act_cfg=act_cfg, - with_cp=with_cp)) - inplanes = planes * block.expansion - - for i in range(1, blocks): - layers.append( - block(inplanes, - planes, - 1, - 1, - dilation, - style=style, - inflate=(inflate[i] == 1), - inflate_style=inflate_style, - non_local=(non_local[i] == 1), - non_local_cfg=non_local_cfg, - conv_cfg=conv_cfg, - norm_cfg=norm_cfg, - act_cfg=act_cfg, - with_cp=with_cp)) - - return nn.Sequential(*layers) - - def inflate_weights(self, logger): - """Inflate the resnet2d parameters to resnet3d pathway. - - The differences between resnet3d and resnet2d mainly lie in an extra - axis of conv kernel. To utilize the pretrained parameters in 2d model, - the weight of conv2d models should be inflated to fit in the shapes of - the 3d counterpart. For pathway the ``lateral_connection`` part should - not be inflated from 2d weights. - - Args: - logger (logging.Logger): The logger used to print - debugging infomation. - """ - - state_dict_r2d = _load_checkpoint(self.pretrained) - if 'state_dict' in state_dict_r2d: - state_dict_r2d = state_dict_r2d['state_dict'] - - inflated_param_names = [] - for name, module in self.named_modules(): - if 'lateral' in name: - continue - if isinstance(module, ConvModule): - # we use a ConvModule to wrap conv+bn+relu layers, thus the - # name mapping is needed - if 'downsample' in name: - # layer{X}.{Y}.downsample.conv->layer{X}.{Y}.downsample.0 - original_conv_name = name + '.0' - # layer{X}.{Y}.downsample.bn->layer{X}.{Y}.downsample.1 - original_bn_name = name + '.1' - else: - # layer{X}.{Y}.conv{n}.conv->layer{X}.{Y}.conv{n} - original_conv_name = name - # layer{X}.{Y}.conv{n}.bn->layer{X}.{Y}.bn{n} - original_bn_name = name.replace('conv', 'bn') - if original_conv_name + '.weight' not in state_dict_r2d: - logger.warning(f'Module not exist in the state_dict_r2d' - f': {original_conv_name}') - else: - self._inflate_conv_params(module.conv, state_dict_r2d, - original_conv_name, - inflated_param_names) - if original_bn_name + '.weight' not in state_dict_r2d: - logger.warning(f'Module not exist in the state_dict_r2d' - f': {original_bn_name}') - else: - self._inflate_bn_params(module.bn, state_dict_r2d, - original_bn_name, - inflated_param_names) - - # check if any parameters in the 2d checkpoint are not loaded - remaining_names = set( - state_dict_r2d.keys()) - set(inflated_param_names) - if remaining_names: - logger.info(f'These parameters in the 2d checkpoint are not loaded' - f': {remaining_names}') - - def _inflate_conv_params(self, conv3d, state_dict_2d, module_name_2d, - inflated_param_names): - """Inflate a conv module from 2d to 3d. - - The differences of conv modules betweene 2d and 3d in Pathway - mainly lie in the inplanes due to lateral connections. To fit the - shapes of the lateral connection counterpart, it will expand - parameters by concatting conv2d parameters and extra zero paddings. - - Args: - conv3d (nn.Module): The destination conv3d module. - state_dict_2d (OrderedDict): The state dict of pretrained 2d model. - module_name_2d (str): The name of corresponding conv module in the - 2d model. - inflated_param_names (list[str]): List of parameters that have been - inflated. - """ - weight_2d_name = module_name_2d + '.weight' - conv2d_weight = state_dict_2d[weight_2d_name] - old_shape = conv2d_weight.shape - new_shape = conv3d.weight.data.shape - kernel_t = new_shape[2] - - if new_shape[1] != old_shape[1]: - if new_shape[1] < old_shape[1]: - warnings.warn(f'The parameter of {module_name_2d} is not' - 'loaded due to incompatible shapes. ') - return - # Inplanes may be different due to lateral connections - new_channels = new_shape[1] - old_shape[1] - pad_shape = old_shape - pad_shape = pad_shape[:1] + (new_channels, ) + pad_shape[2:] - # Expand parameters by concat extra channels - conv2d_weight = torch.cat( - (conv2d_weight, - torch.zeros(pad_shape).type_as(conv2d_weight).to( - conv2d_weight.device)), - dim=1) - - new_weight = conv2d_weight.data.unsqueeze(2).expand_as( - conv3d.weight) / kernel_t - conv3d.weight.data.copy_(new_weight) - inflated_param_names.append(weight_2d_name) - - if getattr(conv3d, 'bias') is not None: - bias_2d_name = module_name_2d + '.bias' - conv3d.bias.data.copy_(state_dict_2d[bias_2d_name]) - inflated_param_names.append(bias_2d_name) - - def _freeze_stages(self): - """Prevent all the parameters from being optimized before - `self.frozen_stages`.""" - if self.frozen_stages >= 0: - self.conv1.eval() - for param in self.conv1.parameters(): - param.requires_grad = False - - for i in range(1, self.frozen_stages + 1): - m = getattr(self, f'layer{i}') - m.eval() - for param in m.parameters(): - param.requires_grad = False - - if i != len(self.res_layers) and self.lateral: - # No fusion needed in the final stage - lateral_name = self.lateral_connections[i - 1] - conv_lateral = getattr(self, lateral_name) - conv_lateral.eval() - for param in conv_lateral.parameters(): - param.requires_grad = False - - def init_weights(self, pretrained=None): - """Initiate the parameters either from existing checkpoint or from - scratch.""" - if pretrained: - self.pretrained = pretrained - - # Override the init_weights of i3d - super().init_weights() - for module_name in self.lateral_connections: - layer = getattr(self, module_name) - for m in layer.modules(): - if isinstance(m, (nn.Conv3d, nn.Conv2d)): - kaiming_init(m) - - -pathway_cfg = { - 'resnet3d': ResNet3dPathway, - # TODO: BNInceptionPathway -} - - -def build_pathway(cfg, *args, **kwargs): - """Build pathway. - - Args: - cfg (None or dict): cfg should contain: - - type (str): identify conv layer type. - - Returns: - nn.Module: Created pathway. - """ - if not (isinstance(cfg, dict) and 'type' in cfg): - raise TypeError('cfg must be a dict containing the key "type"') - cfg_ = cfg.copy() - - pathway_type = cfg_.pop('type') - if pathway_type not in pathway_cfg: - raise KeyError(f'Unrecognized pathway type {pathway_type}') - - pathway_cls = pathway_cfg[pathway_type] - pathway = pathway_cls(*args, **kwargs, **cfg_) - - return pathway - - -@BACKBONES.register_module() -class ResNet3dSlowFast(nn.Module): - """Slowfast backbone. - - This module is proposed in `SlowFast Networks for Video Recognition - `_ - - Args: - pretrained (str): The file path to a pretrained model. - resample_rate (int): A large temporal stride ``resample_rate`` - on input frames. The actual resample rate is calculated by - multipling the ``interval`` in ``SampleFrames`` in the - pipeline with ``resample_rate``, equivalent to the :math:`\\tau` - in the paper, i.e. it processes only one out of - ``resample_rate * interval`` frames. Default: 8. - speed_ratio (int): Speed ratio indicating the ratio between time - dimension of the fast and slow pathway, corresponding to the - :math:`\\alpha` in the paper. Default: 8. - channel_ratio (int): Reduce the channel number of fast pathway - by ``channel_ratio``, corresponding to :math:`\\beta` in the paper. - Default: 8. - slow_pathway (dict): Configuration of slow branch, should contain - necessary arguments for building the specific type of pathway - and: - type (str): type of backbone the pathway bases on. - lateral (bool): determine whether to build lateral connection - for the pathway.Default: - - .. code-block:: Python - - dict(type='ResNetPathway', - lateral=True, depth=50, pretrained=None, - conv1_kernel=(1, 7, 7), dilations=(1, 1, 1, 1), - conv1_stride_t=1, pool1_stride_t=1, inflate=(0, 0, 1, 1)) - - fast_pathway (dict): Configuration of fast branch, similar to - `slow_pathway`. Default: - - .. code-block:: Python - - dict(type='ResNetPathway', - lateral=False, depth=50, pretrained=None, base_channels=8, - conv1_kernel=(5, 7, 7), conv1_stride_t=1, pool1_stride_t=1) - """ - def __init__(self, - pretrained, - resample_rate=8, - speed_ratio=8, - channel_ratio=8, - slow_pathway=dict(type='resnet3d', - depth=50, - pretrained=None, - lateral=True, - conv1_kernel=(1, 7, 7), - dilations=(1, 1, 1, 1), - conv1_stride_t=1, - pool1_stride_t=1, - inflate=(0, 0, 1, 1)), - fast_pathway=dict(type='resnet3d', - depth=50, - pretrained=None, - lateral=False, - base_channels=8, - conv1_kernel=(5, 7, 7), - conv1_stride_t=1, - pool1_stride_t=1)): - super().__init__() - self.pretrained = pretrained - self.resample_rate = resample_rate - self.speed_ratio = speed_ratio - self.channel_ratio = channel_ratio - - if slow_pathway['lateral']: - slow_pathway['speed_ratio'] = speed_ratio - slow_pathway['channel_ratio'] = channel_ratio - - self.slow_path = build_pathway(slow_pathway) - self.fast_path = build_pathway(fast_pathway) - - def init_weights(self, pretrained=None): - """Initiate the parameters either from existing checkpoint or from - scratch.""" - if pretrained: - self.pretrained = pretrained - - if isinstance(self.pretrained, str): - logger = get_root_logger() - msg = f'load model from: {self.pretrained}' - print_log(msg, logger=logger) - # Directly load 3D model. - load_checkpoint(self, self.pretrained, strict=True, logger=logger) - elif self.pretrained is None: - # Init two branch seperately. - self.fast_path.init_weights() - self.slow_path.init_weights() - else: - raise TypeError('pretrained must be a str or None') - - def forward(self, x): - """Defines the computation performed at every call. - - Args: - x (torch.Tensor): The input data. - - Returns: - tuple[torch.Tensor]: The feature of the input samples extracted - by the backbone. - """ - x_slow = nn.functional.interpolate( - x, - mode='nearest', - scale_factor=(1.0 / self.resample_rate, 1.0, 1.0)) - x_slow = self.slow_path.conv1(x_slow) - x_slow = self.slow_path.maxpool(x_slow) - - x_fast = nn.functional.interpolate( - x, - mode='nearest', - scale_factor=(1.0 / (self.resample_rate // self.speed_ratio), 1.0, - 1.0)) - x_fast = self.fast_path.conv1(x_fast) - x_fast = self.fast_path.maxpool(x_fast) - - if self.slow_path.lateral: - x_fast_lateral = self.slow_path.conv1_lateral(x_fast) - x_slow = torch.cat((x_slow, x_fast_lateral), dim=1) - - for i, layer_name in enumerate(self.slow_path.res_layers): - res_layer = getattr(self.slow_path, layer_name) - x_slow = res_layer(x_slow) - res_layer_fast = getattr(self.fast_path, layer_name) - x_fast = res_layer_fast(x_fast) - if (i != len(self.slow_path.res_layers) - 1 - and self.slow_path.lateral): - # No fusion needed in the final stage - lateral_name = self.slow_path.lateral_connections[i] - conv_lateral = getattr(self.slow_path, lateral_name) - x_fast_lateral = conv_lateral(x_fast) - x_slow = torch.cat((x_slow, x_fast_lateral), dim=1) - - out = (x_slow, x_fast) - - return out - - -if mmdet_imported: - MMDET_BACKBONES.register_module()(ResNet3dSlowFast) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 warnings + +import torch +import torch.nn as nn +from mmcv.cnn import ConvModule, kaiming_init +from mmcv.runner import _load_checkpoint, load_checkpoint +from mmcv.utils import print_log + +from ...utils import get_root_logger +from ..builder import BACKBONES +from .resnet3d import ResNet3d + +mmdet_imported = False + + +class ResNet3dPathway(ResNet3d): + """A pathway of Slowfast based on ResNet3d. + + Args: + *args (arguments): Arguments same as :class:``ResNet3d``. + lateral (bool): Determines whether to enable the lateral connection + from another pathway. Default: False. + speed_ratio (int): Speed ratio indicating the ratio between time + dimension of the fast and slow pathway, corresponding to the + ``alpha`` in the paper. Default: 8. + channel_ratio (int): Reduce the channel number of fast pathway + by ``channel_ratio``, corresponding to ``beta`` in the paper. + Default: 8. + fusion_kernel (int): The kernel size of lateral fusion. + Default: 5. + **kwargs (keyword arguments): Keywords arguments for ResNet3d. + """ + def __init__(self, + *args, + lateral=False, + speed_ratio=8, + channel_ratio=8, + fusion_kernel=5, + **kwargs): + self.lateral = lateral + self.speed_ratio = speed_ratio + self.channel_ratio = channel_ratio + self.fusion_kernel = fusion_kernel + super().__init__(*args, **kwargs) + self.inplanes = self.base_channels + if self.lateral: + self.conv1_lateral = ConvModule( + self.inplanes // self.channel_ratio, + # https://arxiv.org/abs/1812.03982, the + # third type of lateral connection has out_channel: + # 2 * \beta * C + self.inplanes * 2 // self.channel_ratio, + kernel_size=(fusion_kernel, 1, 1), + stride=(self.speed_ratio, 1, 1), + padding=((fusion_kernel - 1) // 2, 0, 0), + bias=False, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=None) + + self.lateral_connections = [] + for i in range(len(self.stage_blocks)): + planes = self.base_channels * 2**i + self.inplanes = planes * self.block.expansion + + if lateral and i != self.num_stages - 1: + # no lateral connection needed in final stage + lateral_name = f'layer{(i + 1)}_lateral' + setattr( + self, lateral_name, + ConvModule(self.inplanes // self.channel_ratio, + self.inplanes * 2 // self.channel_ratio, + kernel_size=(fusion_kernel, 1, 1), + stride=(self.speed_ratio, 1, 1), + padding=((fusion_kernel - 1) // 2, 0, 0), + bias=False, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=None)) + self.lateral_connections.append(lateral_name) + + def make_res_layer(self, + block, + inplanes, + planes, + blocks, + spatial_stride=1, + temporal_stride=1, + dilation=1, + style='pytorch', + inflate=1, + inflate_style='3x1x1', + non_local=0, + non_local_cfg=dict(), + conv_cfg=None, + norm_cfg=None, + act_cfg=None, + with_cp=False): + """Build residual layer for Slowfast. + + Args: + block (nn.Module): Residual module to be built. + inplanes (int): Number of channels for the input + feature in each block. + planes (int): Number of channels for the output + feature in each block. + blocks (int): Number of residual blocks. + spatial_stride (int | Sequence[int]): Spatial strides + in residual and conv layers. Default: 1. + temporal_stride (int | Sequence[int]): Temporal strides in + residual and conv layers. Default: 1. + dilation (int): Spacing between kernel elements. Default: 1. + style (str): ``pytorch`` or ``caffe``. If set to ``pytorch``, + the stride-two layer is the 3x3 conv layer, + otherwise the stride-two layer is the first 1x1 conv layer. + Default: ``pytorch``. + inflate (int | Sequence[int]): Determine whether to inflate + for each block. Default: 1. + inflate_style (str): ``3x1x1`` or ``3x3x3``. which determines + the kernel sizes and padding strides for conv1 and + conv2 in each block. Default: ``3x1x1``. + non_local (int | Sequence[int]): Determine whether to apply + non-local module in the corresponding block of each stages. + Default: 0. + non_local_cfg (dict): Config for non-local module. + Default: ``dict()``. + conv_cfg (dict | None): Config for conv layers. Default: None. + norm_cfg (dict | None): Config for norm layers. Default: None. + act_cfg (dict | None): Config for activate layers. Default: None. + with_cp (bool): Use checkpoint or not. Using checkpoint will save + some memory while slowing down the training speed. + Default: False. + + Returns: + nn.Module: A residual layer for the given config. + """ + inflate = inflate if not isinstance(inflate, + int) else (inflate, ) * blocks + non_local = non_local if not isinstance( + non_local, int) else (non_local, ) * blocks + assert len(inflate) == blocks and len(non_local) == blocks + if self.lateral: + lateral_inplanes = inplanes * 2 // self.channel_ratio + else: + lateral_inplanes = 0 + if (spatial_stride != 1 + or (inplanes + lateral_inplanes) != planes * block.expansion): + downsample = ConvModule(inplanes + lateral_inplanes, + planes * block.expansion, + kernel_size=1, + stride=(temporal_stride, spatial_stride, + spatial_stride), + bias=False, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=None) + else: + downsample = None + + layers = [] + layers.append( + block(inplanes + lateral_inplanes, + planes, + spatial_stride, + temporal_stride, + dilation, + downsample, + style=style, + inflate=(inflate[0] == 1), + inflate_style=inflate_style, + non_local=(non_local[0] == 1), + non_local_cfg=non_local_cfg, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg, + with_cp=with_cp)) + inplanes = planes * block.expansion + + for i in range(1, blocks): + layers.append( + block(inplanes, + planes, + 1, + 1, + dilation, + style=style, + inflate=(inflate[i] == 1), + inflate_style=inflate_style, + non_local=(non_local[i] == 1), + non_local_cfg=non_local_cfg, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg, + with_cp=with_cp)) + + return nn.Sequential(*layers) + + def inflate_weights(self, logger): + """Inflate the resnet2d parameters to resnet3d pathway. + + The differences between resnet3d and resnet2d mainly lie in an extra + axis of conv kernel. To utilize the pretrained parameters in 2d model, + the weight of conv2d models should be inflated to fit in the shapes of + the 3d counterpart. For pathway the ``lateral_connection`` part should + not be inflated from 2d weights. + + Args: + logger (logging.Logger): The logger used to print + debugging infomation. + """ + + state_dict_r2d = _load_checkpoint(self.pretrained) + if 'state_dict' in state_dict_r2d: + state_dict_r2d = state_dict_r2d['state_dict'] + + inflated_param_names = [] + for name, module in self.named_modules(): + if 'lateral' in name: + continue + if isinstance(module, ConvModule): + # we use a ConvModule to wrap conv+bn+relu layers, thus the + # name mapping is needed + if 'downsample' in name: + # layer{X}.{Y}.downsample.conv->layer{X}.{Y}.downsample.0 + original_conv_name = name + '.0' + # layer{X}.{Y}.downsample.bn->layer{X}.{Y}.downsample.1 + original_bn_name = name + '.1' + else: + # layer{X}.{Y}.conv{n}.conv->layer{X}.{Y}.conv{n} + original_conv_name = name + # layer{X}.{Y}.conv{n}.bn->layer{X}.{Y}.bn{n} + original_bn_name = name.replace('conv', 'bn') + if original_conv_name + '.weight' not in state_dict_r2d: + logger.warning(f'Module not exist in the state_dict_r2d' + f': {original_conv_name}') + else: + self._inflate_conv_params(module.conv, state_dict_r2d, + original_conv_name, + inflated_param_names) + if original_bn_name + '.weight' not in state_dict_r2d: + logger.warning(f'Module not exist in the state_dict_r2d' + f': {original_bn_name}') + else: + self._inflate_bn_params(module.bn, state_dict_r2d, + original_bn_name, + inflated_param_names) + + # check if any parameters in the 2d checkpoint are not loaded + remaining_names = set( + state_dict_r2d.keys()) - set(inflated_param_names) + if remaining_names: + logger.info(f'These parameters in the 2d checkpoint are not loaded' + f': {remaining_names}') + + def _inflate_conv_params(self, conv3d, state_dict_2d, module_name_2d, + inflated_param_names): + """Inflate a conv module from 2d to 3d. + + The differences of conv modules betweene 2d and 3d in Pathway + mainly lie in the inplanes due to lateral connections. To fit the + shapes of the lateral connection counterpart, it will expand + parameters by concatting conv2d parameters and extra zero paddings. + + Args: + conv3d (nn.Module): The destination conv3d module. + state_dict_2d (OrderedDict): The state dict of pretrained 2d model. + module_name_2d (str): The name of corresponding conv module in the + 2d model. + inflated_param_names (list[str]): List of parameters that have been + inflated. + """ + weight_2d_name = module_name_2d + '.weight' + conv2d_weight = state_dict_2d[weight_2d_name] + old_shape = conv2d_weight.shape + new_shape = conv3d.weight.data.shape + kernel_t = new_shape[2] + + if new_shape[1] != old_shape[1]: + if new_shape[1] < old_shape[1]: + warnings.warn(f'The parameter of {module_name_2d} is not' + 'loaded due to incompatible shapes. ') + return + # Inplanes may be different due to lateral connections + new_channels = new_shape[1] - old_shape[1] + pad_shape = old_shape + pad_shape = pad_shape[:1] + (new_channels, ) + pad_shape[2:] + # Expand parameters by concat extra channels + conv2d_weight = torch.cat( + (conv2d_weight, + torch.zeros(pad_shape).type_as(conv2d_weight).to( + conv2d_weight.device)), + dim=1) + + new_weight = conv2d_weight.data.unsqueeze(2).expand_as( + conv3d.weight) / kernel_t + conv3d.weight.data.copy_(new_weight) + inflated_param_names.append(weight_2d_name) + + if getattr(conv3d, 'bias') is not None: + bias_2d_name = module_name_2d + '.bias' + conv3d.bias.data.copy_(state_dict_2d[bias_2d_name]) + inflated_param_names.append(bias_2d_name) + + def _freeze_stages(self): + """Prevent all the parameters from being optimized before + `self.frozen_stages`.""" + if self.frozen_stages >= 0: + self.conv1.eval() + for param in self.conv1.parameters(): + param.requires_grad = False + + for i in range(1, self.frozen_stages + 1): + m = getattr(self, f'layer{i}') + m.eval() + for param in m.parameters(): + param.requires_grad = False + + if i != len(self.res_layers) and self.lateral: + # No fusion needed in the final stage + lateral_name = self.lateral_connections[i - 1] + conv_lateral = getattr(self, lateral_name) + conv_lateral.eval() + for param in conv_lateral.parameters(): + param.requires_grad = False + + def init_weights(self, pretrained=None): + """Initiate the parameters either from existing checkpoint or from + scratch.""" + if pretrained: + self.pretrained = pretrained + + # Override the init_weights of i3d + super().init_weights() + for module_name in self.lateral_connections: + layer = getattr(self, module_name) + for m in layer.modules(): + if isinstance(m, (nn.Conv3d, nn.Conv2d)): + kaiming_init(m) + + +pathway_cfg = { + 'resnet3d': ResNet3dPathway, + # TODO: BNInceptionPathway +} + + +def build_pathway(cfg, *args, **kwargs): + """Build pathway. + + Args: + cfg (None or dict): cfg should contain: + - type (str): identify conv layer type. + + Returns: + nn.Module: Created pathway. + """ + if not (isinstance(cfg, dict) and 'type' in cfg): + raise TypeError('cfg must be a dict containing the key "type"') + cfg_ = cfg.copy() + + pathway_type = cfg_.pop('type') + if pathway_type not in pathway_cfg: + raise KeyError(f'Unrecognized pathway type {pathway_type}') + + pathway_cls = pathway_cfg[pathway_type] + pathway = pathway_cls(*args, **kwargs, **cfg_) + + return pathway + + +@BACKBONES.register_module() +class ResNet3dSlowFast(nn.Module): + """Slowfast backbone. + + This module is proposed in `SlowFast Networks for Video Recognition + `_ + + Args: + pretrained (str): The file path to a pretrained model. + resample_rate (int): A large temporal stride ``resample_rate`` + on input frames. The actual resample rate is calculated by + multipling the ``interval`` in ``SampleFrames`` in the + pipeline with ``resample_rate``, equivalent to the :math:`\\tau` + in the paper, i.e. it processes only one out of + ``resample_rate * interval`` frames. Default: 8. + speed_ratio (int): Speed ratio indicating the ratio between time + dimension of the fast and slow pathway, corresponding to the + :math:`\\alpha` in the paper. Default: 8. + channel_ratio (int): Reduce the channel number of fast pathway + by ``channel_ratio``, corresponding to :math:`\\beta` in the paper. + Default: 8. + slow_pathway (dict): Configuration of slow branch, should contain + necessary arguments for building the specific type of pathway + and: + type (str): type of backbone the pathway bases on. + lateral (bool): determine whether to build lateral connection + for the pathway.Default: + + .. code-block:: Python + + dict(type='ResNetPathway', + lateral=True, depth=50, pretrained=None, + conv1_kernel=(1, 7, 7), dilations=(1, 1, 1, 1), + conv1_stride_t=1, pool1_stride_t=1, inflate=(0, 0, 1, 1)) + + fast_pathway (dict): Configuration of fast branch, similar to + `slow_pathway`. Default: + + .. code-block:: Python + + dict(type='ResNetPathway', + lateral=False, depth=50, pretrained=None, base_channels=8, + conv1_kernel=(5, 7, 7), conv1_stride_t=1, pool1_stride_t=1) + """ + def __init__(self, + pretrained, + resample_rate=8, + speed_ratio=8, + channel_ratio=8, + slow_pathway=dict(type='resnet3d', + depth=50, + pretrained=None, + lateral=True, + conv1_kernel=(1, 7, 7), + dilations=(1, 1, 1, 1), + conv1_stride_t=1, + pool1_stride_t=1, + inflate=(0, 0, 1, 1)), + fast_pathway=dict(type='resnet3d', + depth=50, + pretrained=None, + lateral=False, + base_channels=8, + conv1_kernel=(5, 7, 7), + conv1_stride_t=1, + pool1_stride_t=1)): + super().__init__() + self.pretrained = pretrained + self.resample_rate = resample_rate + self.speed_ratio = speed_ratio + self.channel_ratio = channel_ratio + + if slow_pathway['lateral']: + slow_pathway['speed_ratio'] = speed_ratio + slow_pathway['channel_ratio'] = channel_ratio + + self.slow_path = build_pathway(slow_pathway) + self.fast_path = build_pathway(fast_pathway) + + def init_weights(self, pretrained=None): + """Initiate the parameters either from existing checkpoint or from + scratch.""" + if pretrained: + self.pretrained = pretrained + + if isinstance(self.pretrained, str): + logger = get_root_logger() + msg = f'load model from: {self.pretrained}' + print_log(msg, logger=logger) + # Directly load 3D model. + load_checkpoint(self, self.pretrained, strict=True, logger=logger) + elif self.pretrained is None: + # Init two branch seperately. + self.fast_path.init_weights() + self.slow_path.init_weights() + else: + raise TypeError('pretrained must be a str or None') + + def forward(self, x): + """Defines the computation performed at every call. + + Args: + x (torch.Tensor): The input data. + + Returns: + tuple[torch.Tensor]: The feature of the input samples extracted + by the backbone. + """ + x_slow = nn.functional.interpolate( + x, + mode='nearest', + scale_factor=(1.0 / self.resample_rate, 1.0, 1.0)) + x_slow = self.slow_path.conv1(x_slow) + x_slow = self.slow_path.maxpool(x_slow) + + x_fast = nn.functional.interpolate( + x, + mode='nearest', + scale_factor=(1.0 / (self.resample_rate // self.speed_ratio), 1.0, + 1.0)) + x_fast = self.fast_path.conv1(x_fast) + x_fast = self.fast_path.maxpool(x_fast) + + if self.slow_path.lateral: + x_fast_lateral = self.slow_path.conv1_lateral(x_fast) + x_slow = torch.cat((x_slow, x_fast_lateral), dim=1) + + for i, layer_name in enumerate(self.slow_path.res_layers): + res_layer = getattr(self.slow_path, layer_name) + x_slow = res_layer(x_slow) + res_layer_fast = getattr(self.fast_path, layer_name) + x_fast = res_layer_fast(x_fast) + if (i != len(self.slow_path.res_layers) - 1 + and self.slow_path.lateral): + # No fusion needed in the final stage + lateral_name = self.slow_path.lateral_connections[i] + conv_lateral = getattr(self.slow_path, lateral_name) + x_fast_lateral = conv_lateral(x_fast) + x_slow = torch.cat((x_slow, x_fast_lateral), dim=1) + + out = (x_slow, x_fast) + + return out + + +if mmdet_imported: + MMDET_BACKBONES.register_module()(ResNet3dSlowFast) diff --git a/PyTorch/contrib/cv/video/SlowFast/mmaction/models/heads/base.py b/PyTorch/contrib/cv/video/SlowFast/mmaction/models/heads/base.py index 8d165096e1..6343b3dd0f 100644 --- a/PyTorch/contrib/cv/video/SlowFast/mmaction/models/heads/base.py +++ b/PyTorch/contrib/cv/video/SlowFast/mmaction/models/heads/base.py @@ -1,122 +1,122 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 abc import ABCMeta, abstractmethod - -import torch -import torch.nn as nn - -from ...core import top_k_accuracy -from ..builder import build_loss - - -class AvgConsensus(nn.Module): - """Average consensus module. - - Args: - dim (int): Decide which dim consensus function to apply. - Default: 1. - """ - def __init__(self, dim=1): - super().__init__() - self.dim = dim - - def forward(self, x): - """Defines the computation performed at every call.""" - return x.mean(dim=self.dim, keepdim=True) - - -class BaseHead(nn.Module, metaclass=ABCMeta): - """Base class for head. - - All Head should subclass it. - All subclass should overwrite: - - Methods:``init_weights``, initializing weights in some modules. - - Methods:``forward``, supporting to forward both for training and testing. - - Args: - num_classes (int): Number of classes to be classified. - in_channels (int): Number of channels in input feature. - loss_cls (dict): Config for building loss. - Default: dict(type='CrossEntropyLoss', loss_weight=1.0). - multi_class (bool): Determines whether it is a multi-class - recognition task. Default: False. - label_smooth_eps (float): Epsilon used in label smooth. - Reference: arxiv.org/abs/1906.02629. Default: 0. - """ - def __init__(self, - num_classes, - in_channels, - loss_cls=dict(type='CrossEntropyLoss', loss_weight=1.0), - multi_class=False, - label_smooth_eps=0.0): - super().__init__() - self.num_classes = num_classes - self.in_channels = in_channels - self.loss_cls = build_loss(loss_cls) - self.multi_class = multi_class - self.label_smooth_eps = label_smooth_eps - - @abstractmethod - def init_weights(self): - """Initiate the parameters either from existing checkpoint or from - scratch.""" - - @abstractmethod - def forward(self, x): - """Defines the computation performed at every call.""" - - def loss(self, cls_score, labels, **kwargs): - """Calculate the loss given output ``cls_score``, target ``labels``. - - Args: - cls_score (torch.Tensor): The output of the model. - labels (torch.Tensor): The target output of the model. - - Returns: - dict: A dict containing field 'loss_cls'(mandatory) - and 'top1_acc', 'top5_acc'(optional). - """ - losses = dict() - if labels.shape == torch.Size([]): - labels = labels.unsqueeze(0) - elif labels.dim() == 1 and labels.size()[0] == self.num_classes \ - and cls_score.size()[0] == 1: - # Fix a bug when training with soft labels and batch size is 1. - # When using soft labels, `labels` and `cls_socre` share the same - # shape. - labels = labels.unsqueeze(0) - - if not self.multi_class and cls_score.size() != labels.size(): - top_k_acc = top_k_accuracy(cls_score.detach().cpu().numpy(), - labels.detach().cpu().numpy(), (1, 5)) - losses['top1_acc'] = torch.tensor(top_k_acc[0], - device=cls_score.device, - dtype=torch.float32) - losses['top5_acc'] = torch.tensor(top_k_acc[1], - device=cls_score.device, - dtype=torch.float32) - - elif self.multi_class and self.label_smooth_eps != 0: - labels = ((1 - self.label_smooth_eps) * labels + - self.label_smooth_eps / self.num_classes) - - loss_cls = self.loss_cls(cls_score, labels, **kwargs) - # loss_cls may be dictionary or single tensor - if isinstance(loss_cls, dict): - losses.update(loss_cls) - else: - losses['loss_cls'] = loss_cls - - return losses +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 abc import ABCMeta, abstractmethod + +import torch +import torch.nn as nn + +from ...core import top_k_accuracy +from ..builder import build_loss + + +class AvgConsensus(nn.Module): + """Average consensus module. + + Args: + dim (int): Decide which dim consensus function to apply. + Default: 1. + """ + def __init__(self, dim=1): + super().__init__() + self.dim = dim + + def forward(self, x): + """Defines the computation performed at every call.""" + return x.mean(dim=self.dim, keepdim=True) + + +class BaseHead(nn.Module, metaclass=ABCMeta): + """Base class for head. + + All Head should subclass it. + All subclass should overwrite: + - Methods:``init_weights``, initializing weights in some modules. + - Methods:``forward``, supporting to forward both for training and testing. + + Args: + num_classes (int): Number of classes to be classified. + in_channels (int): Number of channels in input feature. + loss_cls (dict): Config for building loss. + Default: dict(type='CrossEntropyLoss', loss_weight=1.0). + multi_class (bool): Determines whether it is a multi-class + recognition task. Default: False. + label_smooth_eps (float): Epsilon used in label smooth. + Reference: arxiv.org/abs/1906.02629. Default: 0. + """ + def __init__(self, + num_classes, + in_channels, + loss_cls=dict(type='CrossEntropyLoss', loss_weight=1.0), + multi_class=False, + label_smooth_eps=0.0): + super().__init__() + self.num_classes = num_classes + self.in_channels = in_channels + self.loss_cls = build_loss(loss_cls) + self.multi_class = multi_class + self.label_smooth_eps = label_smooth_eps + + @abstractmethod + def init_weights(self): + """Initiate the parameters either from existing checkpoint or from + scratch.""" + + @abstractmethod + def forward(self, x): + """Defines the computation performed at every call.""" + + def loss(self, cls_score, labels, **kwargs): + """Calculate the loss given output ``cls_score``, target ``labels``. + + Args: + cls_score (torch.Tensor): The output of the model. + labels (torch.Tensor): The target output of the model. + + Returns: + dict: A dict containing field 'loss_cls'(mandatory) + and 'top1_acc', 'top5_acc'(optional). + """ + losses = dict() + if labels.shape == torch.Size([]): + labels = labels.unsqueeze(0) + elif labels.dim() == 1 and labels.size()[0] == self.num_classes \ + and cls_score.size()[0] == 1: + # Fix a bug when training with soft labels and batch size is 1. + # When using soft labels, `labels` and `cls_socre` share the same + # shape. + labels = labels.unsqueeze(0) + + if not self.multi_class and cls_score.size() != labels.size(): + top_k_acc = top_k_accuracy(cls_score.detach().cpu().numpy(), + labels.detach().cpu().numpy(), (1, 5)) + losses['top1_acc'] = torch.tensor(top_k_acc[0], + device=cls_score.device, + dtype=torch.float32) + losses['top5_acc'] = torch.tensor(top_k_acc[1], + device=cls_score.device, + dtype=torch.float32) + + elif self.multi_class and self.label_smooth_eps != 0: + labels = ((1 - self.label_smooth_eps) * labels + + self.label_smooth_eps / self.num_classes) + + loss_cls = self.loss_cls(cls_score, labels, **kwargs) + # loss_cls may be dictionary or single tensor + if isinstance(loss_cls, dict): + losses.update(loss_cls) + else: + losses['loss_cls'] = loss_cls + + return losses diff --git a/PyTorch/contrib/cv/video/SlowFast/mmaction/models/heads/slowfast_head.py b/PyTorch/contrib/cv/video/SlowFast/mmaction/models/heads/slowfast_head.py index 30c3590fa9..31de953e26 100644 --- a/PyTorch/contrib/cv/video/SlowFast/mmaction/models/heads/slowfast_head.py +++ b/PyTorch/contrib/cv/video/SlowFast/mmaction/models/heads/slowfast_head.py @@ -1,92 +1,92 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch -import torch.nn as nn -from mmcv.cnn import normal_init - -from ..builder import HEADS -from .base import BaseHead - - -@HEADS.register_module() -class SlowFastHead(BaseHead): - """The classification head for SlowFast. - - Args: - num_classes (int): Number of classes to be classified. - in_channels (int): Number of channels in input feature. - loss_cls (dict): Config for building loss. - Default: dict(type='CrossEntropyLoss'). - spatial_type (str): Pooling type in spatial dimension. Default: 'avg'. - dropout_ratio (float): Probability of dropout layer. Default: 0.8. - init_std (float): Std value for Initiation. Default: 0.01. - kwargs (dict, optional): Any keyword argument to be used to initialize - the head. - """ - def __init__(self, - num_classes, - in_channels, - loss_cls=dict(type='CrossEntropyLoss'), - spatial_type='avg', - dropout_ratio=0.8, - init_std=0.01, - **kwargs): - - super().__init__(num_classes, in_channels, loss_cls, **kwargs) - self.spatial_type = spatial_type - self.dropout_ratio = dropout_ratio - self.init_std = init_std - - if self.dropout_ratio != 0: - self.dropout = nn.Dropout(p=self.dropout_ratio) - else: - self.dropout = None - self.fc_cls = nn.Linear(in_channels, num_classes) - - if self.spatial_type == 'avg': - self.avg_pool = nn.AdaptiveAvgPool3d((1, 1, 1)) - else: - self.avg_pool = None - - def init_weights(self): - """Initiate the parameters from scratch.""" - normal_init(self.fc_cls, std=self.init_std) - - def forward(self, x): - """Defines the computation performed at every call. - - Args: - x (torch.Tensor): The input data. - - Returns: - torch.Tensor: The classification scores for input samples. - """ - # ([N, channel_fast, T, H, W], [(N, channel_slow, T, H, W)]) - x_fast, x_slow = x - # ([N, channel_fast, 1, 1, 1], [N, channel_slow, 1, 1, 1]) - x_fast = self.avg_pool(x_fast) - x_slow = self.avg_pool(x_slow) - # [N, channel_fast + channel_slow, 1, 1, 1] - x = torch.cat((x_slow, x_fast), dim=1) - - if self.dropout is not None: - x = self.dropout(x) - - # [N x C] - x = x.view(x.size(0), -1) - # [N x num_classes] - cls_score = self.fc_cls(x) - - return cls_score.npu_format_cast(0) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch +import torch.nn as nn +from mmcv.cnn import normal_init + +from ..builder import HEADS +from .base import BaseHead + + +@HEADS.register_module() +class SlowFastHead(BaseHead): + """The classification head for SlowFast. + + Args: + num_classes (int): Number of classes to be classified. + in_channels (int): Number of channels in input feature. + loss_cls (dict): Config for building loss. + Default: dict(type='CrossEntropyLoss'). + spatial_type (str): Pooling type in spatial dimension. Default: 'avg'. + dropout_ratio (float): Probability of dropout layer. Default: 0.8. + init_std (float): Std value for Initiation. Default: 0.01. + kwargs (dict, optional): Any keyword argument to be used to initialize + the head. + """ + def __init__(self, + num_classes, + in_channels, + loss_cls=dict(type='CrossEntropyLoss'), + spatial_type='avg', + dropout_ratio=0.8, + init_std=0.01, + **kwargs): + + super().__init__(num_classes, in_channels, loss_cls, **kwargs) + self.spatial_type = spatial_type + self.dropout_ratio = dropout_ratio + self.init_std = init_std + + if self.dropout_ratio != 0: + self.dropout = nn.Dropout(p=self.dropout_ratio) + else: + self.dropout = None + self.fc_cls = nn.Linear(in_channels, num_classes) + + if self.spatial_type == 'avg': + self.avg_pool = nn.AdaptiveAvgPool3d((1, 1, 1)) + else: + self.avg_pool = None + + def init_weights(self): + """Initiate the parameters from scratch.""" + normal_init(self.fc_cls, std=self.init_std) + + def forward(self, x): + """Defines the computation performed at every call. + + Args: + x (torch.Tensor): The input data. + + Returns: + torch.Tensor: The classification scores for input samples. + """ + # ([N, channel_fast, T, H, W], [(N, channel_slow, T, H, W)]) + x_fast, x_slow = x + # ([N, channel_fast, 1, 1, 1], [N, channel_slow, 1, 1, 1]) + x_fast = self.avg_pool(x_fast) + x_slow = self.avg_pool(x_slow) + # [N, channel_fast + channel_slow, 1, 1, 1] + x = torch.cat((x_slow, x_fast), dim=1) + + if self.dropout is not None: + x = self.dropout(x) + + # [N x C] + x = x.view(x.size(0), -1) + # [N x num_classes] + cls_score = self.fc_cls(x) + + return cls_score.npu_format_cast(0) diff --git a/PyTorch/contrib/cv/video/SlowFast/mmaction/models/losses/cross_entropy_loss.py b/PyTorch/contrib/cv/video/SlowFast/mmaction/models/losses/cross_entropy_loss.py index 11c9bfd4dd..a0afe4232c 100644 --- a/PyTorch/contrib/cv/video/SlowFast/mmaction/models/losses/cross_entropy_loss.py +++ b/PyTorch/contrib/cv/video/SlowFast/mmaction/models/losses/cross_entropy_loss.py @@ -1,133 +1,133 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch -import torch.nn.functional as F - -from ..builder import LOSSES -from .base import BaseWeightedLoss - - -@LOSSES.register_module() -class CrossEntropyLoss(BaseWeightedLoss): - """Cross Entropy Loss. - - Support two kinds of labels and their corresponding loss type. It's worth - mentioning that loss type will be detected by the shape of ``cls_score`` - and ``label``. - 1) Hard label: This label is an integer array and all of the elements are - in the range [0, num_classes - 1]. This label's shape should be - ``cls_score``'s shape with the `num_classes` dimension removed. - 2) Soft label(probablity distribution over classes): This label is a - probability distribution and all of the elements are in the range - [0, 1]. This label's shape must be the same as ``cls_score``. For now, - only 2-dim soft label is supported. - - Args: - loss_weight (float): Factor scalar multiplied on the loss. - Default: 1.0. - class_weight (list[float] | None): Loss weight for each class. If set - as None, use the same weight 1 for all classes. Only applies - to CrossEntropyLoss and BCELossWithLogits (should not be set when - using other losses). Default: None. - """ - def __init__(self, loss_weight=1.0, class_weight=None): - super().__init__(loss_weight=loss_weight) - self.class_weight = None - if class_weight is not None: - self.class_weight = torch.Tensor(class_weight) - - def _forward(self, cls_score, label, **kwargs): - """Forward function. - - Args: - cls_score (torch.Tensor): The class score. - label (torch.Tensor): The ground truth label. - kwargs: Any keyword argument to be used to calculate - CrossEntropy loss. - - Returns: - torch.Tensor: The returned CrossEntropy loss. - """ - if cls_score.size() == label.size(): - # calculate loss for soft label - - assert cls_score.dim() == 2, 'Only support 2-dim soft label' - assert len(kwargs) == 0, \ - ('For now, no extra args are supported for soft label, ' - f'but get {kwargs}') - - lsm = F.log_softmax(cls_score, 1) - if self.class_weight is not None: - lsm = lsm * self.class_weight.unsqueeze(0) - loss_cls = -(label * lsm).sum(1) - - # default reduction 'mean' - if self.class_weight is not None: - # Use weighted average as pytorch CrossEntropyLoss does. - # For more information, please visit https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html # noqa - loss_cls = loss_cls.sum() / torch.sum( - self.class_weight.unsqueeze(0) * label) - else: - loss_cls = loss_cls.mean() - else: - # calculate loss for hard label - - if self.class_weight is not None: - assert 'weight' not in kwargs, \ - "The key 'weight' already exists." - kwargs['weight'] = self.class_weight.to(cls_score.device) - # cls_score = cls_score.type(torch.float32) - # label = label.type(torch.int32) - loss_cls = F.cross_entropy(cls_score, label, **kwargs) - - return loss_cls - - -@LOSSES.register_module() -class BCELossWithLogits(BaseWeightedLoss): - """Binary Cross Entropy Loss with logits. - - Args: - loss_weight (float): Factor scalar multiplied on the loss. - Default: 1.0. - class_weight (list[float] | None): Loss weight for each class. If set - as None, use the same weight 1 for all classes. Only applies - to CrossEntropyLoss and BCELossWithLogits (should not be set when - using other losses). Default: None. - """ - def __init__(self, loss_weight=1.0, class_weight=None): - super().__init__(loss_weight=loss_weight) - self.class_weight = None - if class_weight is not None: - self.class_weight = torch.Tensor(class_weight) - - def _forward(self, cls_score, label, **kwargs): - """Forward function. - - Args: - cls_score (torch.Tensor): The class score. - label (torch.Tensor): The ground truth label. - kwargs: Any keyword argument to be used to calculate - bce loss with logits. - - Returns: - torch.Tensor: The returned bce loss with logits. - """ - if self.class_weight is not None: - assert 'weight' not in kwargs, "The key 'weight' already exists." - kwargs['weight'] = self.class_weight.to(cls_score.device) - loss_cls = F.binary_cross_entropy_with_logits(cls_score, label, - **kwargs) - return loss_cls +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch +import torch.nn.functional as F + +from ..builder import LOSSES +from .base import BaseWeightedLoss + + +@LOSSES.register_module() +class CrossEntropyLoss(BaseWeightedLoss): + """Cross Entropy Loss. + + Support two kinds of labels and their corresponding loss type. It's worth + mentioning that loss type will be detected by the shape of ``cls_score`` + and ``label``. + 1) Hard label: This label is an integer array and all of the elements are + in the range [0, num_classes - 1]. This label's shape should be + ``cls_score``'s shape with the `num_classes` dimension removed. + 2) Soft label(probablity distribution over classes): This label is a + probability distribution and all of the elements are in the range + [0, 1]. This label's shape must be the same as ``cls_score``. For now, + only 2-dim soft label is supported. + + Args: + loss_weight (float): Factor scalar multiplied on the loss. + Default: 1.0. + class_weight (list[float] | None): Loss weight for each class. If set + as None, use the same weight 1 for all classes. Only applies + to CrossEntropyLoss and BCELossWithLogits (should not be set when + using other losses). Default: None. + """ + def __init__(self, loss_weight=1.0, class_weight=None): + super().__init__(loss_weight=loss_weight) + self.class_weight = None + if class_weight is not None: + self.class_weight = torch.Tensor(class_weight) + + def _forward(self, cls_score, label, **kwargs): + """Forward function. + + Args: + cls_score (torch.Tensor): The class score. + label (torch.Tensor): The ground truth label. + kwargs: Any keyword argument to be used to calculate + CrossEntropy loss. + + Returns: + torch.Tensor: The returned CrossEntropy loss. + """ + if cls_score.size() == label.size(): + # calculate loss for soft label + + assert cls_score.dim() == 2, 'Only support 2-dim soft label' + assert len(kwargs) == 0, \ + ('For now, no extra args are supported for soft label, ' + f'but get {kwargs}') + + lsm = F.log_softmax(cls_score, 1) + if self.class_weight is not None: + lsm = lsm * self.class_weight.unsqueeze(0) + loss_cls = -(label * lsm).sum(1) + + # default reduction 'mean' + if self.class_weight is not None: + # Use weighted average as pytorch CrossEntropyLoss does. + # For more information, please visit https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html # noqa + loss_cls = loss_cls.sum() / torch.sum( + self.class_weight.unsqueeze(0) * label) + else: + loss_cls = loss_cls.mean() + else: + # calculate loss for hard label + + if self.class_weight is not None: + assert 'weight' not in kwargs, \ + "The key 'weight' already exists." + kwargs['weight'] = self.class_weight.to(cls_score.device) + # cls_score = cls_score.type(torch.float32) + # label = label.type(torch.int32) + loss_cls = F.cross_entropy(cls_score, label, **kwargs) + + return loss_cls + + +@LOSSES.register_module() +class BCELossWithLogits(BaseWeightedLoss): + """Binary Cross Entropy Loss with logits. + + Args: + loss_weight (float): Factor scalar multiplied on the loss. + Default: 1.0. + class_weight (list[float] | None): Loss weight for each class. If set + as None, use the same weight 1 for all classes. Only applies + to CrossEntropyLoss and BCELossWithLogits (should not be set when + using other losses). Default: None. + """ + def __init__(self, loss_weight=1.0, class_weight=None): + super().__init__(loss_weight=loss_weight) + self.class_weight = None + if class_weight is not None: + self.class_weight = torch.Tensor(class_weight) + + def _forward(self, cls_score, label, **kwargs): + """Forward function. + + Args: + cls_score (torch.Tensor): The class score. + label (torch.Tensor): The ground truth label. + kwargs: Any keyword argument to be used to calculate + bce loss with logits. + + Returns: + torch.Tensor: The returned bce loss with logits. + """ + if self.class_weight is not None: + assert 'weight' not in kwargs, "The key 'weight' already exists." + kwargs['weight'] = self.class_weight.to(cls_score.device) + loss_cls = F.binary_cross_entropy_with_logits(cls_score, label, + **kwargs) + return loss_cls diff --git a/PyTorch/contrib/cv/video/SlowFast/mmaction/models/recognizers/base.py b/PyTorch/contrib/cv/video/SlowFast/mmaction/models/recognizers/base.py index 35603218ba..b7a0c527ec 100644 --- a/PyTorch/contrib/cv/video/SlowFast/mmaction/models/recognizers/base.py +++ b/PyTorch/contrib/cv/video/SlowFast/mmaction/models/recognizers/base.py @@ -1,339 +1,339 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 warnings -from abc import ABCMeta, abstractmethod -from collections import OrderedDict - -import torch -import torch.distributed as dist -import torch.nn as nn -import torch.nn.functional as F -from mmcv.runner import auto_fp16 - -from .. import builder - - -class BaseRecognizer(nn.Module, metaclass=ABCMeta): - """Base class for recognizers. - - All recognizers should subclass it. - All subclass should overwrite: - - - Methods:``forward_train``, supporting to forward when training. - - Methods:``forward_test``, supporting to forward when testing. - - Args: - backbone (dict): Backbone modules to extract feature. - cls_head (dict | None): Classification head to process feature. - Default: None. - neck (dict | None): Neck for feature fusion. Default: None. - train_cfg (dict | None): Config for training. Default: None. - test_cfg (dict | None): Config for testing. Default: None. - """ - def __init__(self, - backbone, - cls_head=None, - neck=None, - train_cfg=None, - test_cfg=None): - super().__init__() - # record the source of the backbone - self.backbone_from = 'mmaction2' - - if backbone['type'].startswith('mmcls.'): - try: - import mmcls.models.builder as mmcls_builder - except (ImportError, ModuleNotFoundError): - raise ImportError('Please install mmcls to use this backbone.') - backbone['type'] = backbone['type'][6:] - self.backbone = mmcls_builder.build_backbone(backbone) - self.backbone_from = 'mmcls' - elif backbone['type'].startswith('torchvision.'): - try: - import torchvision.models - except (ImportError, ModuleNotFoundError): - raise ImportError('Please install torchvision to use this ' - 'backbone.') - backbone_type = backbone.pop('type')[12:] - self.backbone = torchvision.models.__dict__[backbone_type]( - **backbone) - # disable the classifier - self.backbone.classifier = nn.Identity() - self.backbone.fc = nn.Identity() - self.backbone_from = 'torchvision' - elif backbone['type'].startswith('timm.'): - try: - import timm - except (ImportError, ModuleNotFoundError): - raise ImportError('Please install timm to use this ' - 'backbone.') - backbone_type = backbone.pop('type')[5:] - # disable the classifier - backbone['num_classes'] = 0 - self.backbone = timm.create_model(backbone_type, **backbone) - self.backbone_from = 'timm' - else: - self.backbone = builder.build_backbone(backbone) - - if neck is not None: - self.neck = builder.build_neck(neck) - - self.cls_head = builder.build_head(cls_head) if cls_head else None - - self.train_cfg = train_cfg - self.test_cfg = test_cfg - - # aux_info is the list of tensor names beyond 'imgs' and 'label' which - # will be used in train_step and val_step, data_batch should contain - # these tensors - self.aux_info = [] - if train_cfg is not None and 'aux_info' in train_cfg: - self.aux_info = train_cfg['aux_info'] - # max_testing_views should be int - self.max_testing_views = None - if test_cfg is not None and 'max_testing_views' in test_cfg: - self.max_testing_views = test_cfg['max_testing_views'] - assert isinstance(self.max_testing_views, int) - - if test_cfg is not None and 'feature_extraction' in test_cfg: - self.feature_extraction = test_cfg['feature_extraction'] - else: - self.feature_extraction = False - - # mini-batch blending, e.g. mixup, cutmix, etc. - self.blending = None - if train_cfg is not None and 'blending' in train_cfg: - from mmcv.utils import build_from_cfg - from mmaction.datasets.builder import BLENDINGS - self.blending = build_from_cfg(train_cfg['blending'], BLENDINGS) - - self.init_weights() - - self.fp16_enabled = False - - @property - def with_neck(self): - """bool: whether the recognizer has a neck""" - return hasattr(self, 'neck') and self.neck is not None - - @property - def with_cls_head(self): - """bool: whether the recognizer has a cls_head""" - return hasattr(self, 'cls_head') and self.cls_head is not None - - def init_weights(self): - """Initialize the model network weights.""" - if self.backbone_from in ['mmcls', 'mmaction2']: - self.backbone.init_weights() - elif self.backbone_from in ['torchvision', 'timm']: - warnings.warn('We do not initialize weights for backbones in ' - f'{self.backbone_from}, since the weights for ' - f'backbones in {self.backbone_from} are initialized' - 'in their __init__ functions.') - else: - raise NotImplementedError('Unsupported backbone source ' - f'{self.backbone_from}!') - - if self.with_cls_head: - self.cls_head.init_weights() - if self.with_neck: - self.neck.init_weights() - - @auto_fp16() - def extract_feat(self, imgs): - """Extract features through a backbone. - - Args: - imgs (torch.Tensor): The input images. - - Returns: - torch.tensor: The extracted features. - """ - if (hasattr(self.backbone, 'features') - and self.backbone_from == 'torchvision'): - x = self.backbone.features(imgs) - elif self.backbone_from == 'timm': - x = self.backbone.forward_features(imgs) - else: - x = self.backbone(imgs) - return x - - def average_clip(self, cls_score, num_segs=1): - """Averaging class score over multiple clips. - - Using different averaging types ('score' or 'prob' or None, - which defined in test_cfg) to computed the final averaged - class score. Only called in test mode. - - Args: - cls_score (torch.Tensor): Class score to be averaged. - num_segs (int): Number of clips for each input sample. - - Returns: - torch.Tensor: Averaged class score. - """ - if 'average_clips' not in self.test_cfg.keys(): - raise KeyError('"average_clips" must defined in test_cfg\'s keys') - - average_clips = self.test_cfg['average_clips'] - if average_clips not in ['score', 'prob', None]: - raise ValueError(f'{average_clips} is not supported. ' - f'Currently supported ones are ' - f'["score", "prob", None]') - - if average_clips is None: - return cls_score - - batch_size = cls_score.shape[0] - cls_score = cls_score.view(batch_size // num_segs, num_segs, -1) - - if average_clips == 'prob': - cls_score = F.softmax(cls_score, dim=2).mean(dim=1) - elif average_clips == 'score': - cls_score = cls_score.mean(dim=1) - - return cls_score - - @abstractmethod - def forward_train(self, imgs, labels, **kwargs): - """Defines the computation performed at every call when training.""" - - @abstractmethod - def forward_test(self, imgs): - """Defines the computation performed at every call when evaluation and - testing.""" - - @abstractmethod - def forward_gradcam(self, imgs): - """Defines the computation performed at every all when using gradcam - utils.""" - - @staticmethod - def _parse_losses(losses): - """Parse the raw outputs (losses) of the network. - - Args: - losses (dict): Raw output of the network, which usually contain - losses and other necessary information. - - Returns: - tuple[Tensor, dict]: (loss, log_vars), loss is the loss tensor - which may be a weighted sum of all losses, log_vars contains - all the variables to be sent to the logger. - """ - log_vars = OrderedDict() - for loss_name, loss_value in losses.items(): - if isinstance(loss_value, torch.Tensor): - log_vars[loss_name] = loss_value.mean() - elif isinstance(loss_value, list): - log_vars[loss_name] = sum(_loss.mean() for _loss in loss_value) - else: - raise TypeError( - f'{loss_name} is not a tensor or list of tensors') - - loss = sum(_value for _key, _value in log_vars.items() - if 'loss' in _key) - - log_vars['loss'] = loss - for loss_name, loss_value in log_vars.items(): - # reduce loss when distributed training - if dist.is_available() and dist.is_initialized(): - loss_value = loss_value.data.clone() - dist.all_reduce(loss_value.div_(dist.get_world_size())) - log_vars[loss_name] = loss_value.item() - - return loss, log_vars - - def forward(self, imgs, label=None, return_loss=True, **kwargs): - """Define the computation performed at every call.""" - if kwargs.get('gradcam', False): - del kwargs['gradcam'] - return self.forward_gradcam(imgs, **kwargs) - if return_loss: - if label is None: - raise ValueError('Label should not be None.') - if self.blending is not None: - imgs, label = self.blending(imgs, label) - return self.forward_train(imgs, label, **kwargs) - - return self.forward_test(imgs, **kwargs) - - def train_step(self, data_batch, optimizer, **kwargs): - """The iteration step during training. - - This method defines an iteration step during training, except for the - back propagation and optimizer updating, which are done in an optimizer - hook. Note that in some complicated cases or models, the whole process - including back propagation and optimizer updating is also defined in - this method, such as GAN. - - Args: - data_batch (dict): The output of dataloader. - optimizer (:obj:`torch.optim.Optimizer` | dict): The optimizer of - runner is passed to ``train_step()``. This argument is unused - and reserved. - - Returns: - dict: It should contain at least 3 keys: ``loss``, ``log_vars``, - ``num_samples``. - ``loss`` is a tensor for back propagation, which can be a - weighted sum of multiple losses. - ``log_vars`` contains all the variables to be sent to the - logger. - ``num_samples`` indicates the batch size (when the model is - DDP, it means the batch size on each GPU), which is used for - averaging the logs. - """ - imgs = data_batch['imgs'].npu().type(torch.float32) - label = data_batch['label'].npu().type(torch.int32) - - aux_info = {} - for item in self.aux_info: - assert item in data_batch - aux_info[item] = data_batch[item] - - losses = self(imgs, label, return_loss=True, **aux_info) - - loss, log_vars = self._parse_losses(losses) - - outputs = dict(loss=loss, - log_vars=log_vars, - num_samples=len(next(iter(data_batch.values())))) - - return outputs - - def val_step(self, data_batch, optimizer, **kwargs): - """The iteration step during validation. - - This method shares the same signature as :func:`train_step`, but used - during val epochs. Note that the evaluation after training epochs is - not implemented with this method, but an evaluation hook. - """ - imgs = data_batch['imgs'].npu().type(torch.float32) - label = data_batch['label'].npu().type(torch.int32) - - aux_info = {} - for item in self.aux_info: - aux_info[item] = data_batch[item] - - losses = self(imgs, label, return_loss=True, **aux_info) - - loss, log_vars = self._parse_losses(losses) - - outputs = dict(loss=loss, - log_vars=log_vars, - num_samples=len(next(iter(data_batch.values())))) - - return outputs +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 warnings +from abc import ABCMeta, abstractmethod +from collections import OrderedDict + +import torch +import torch.distributed as dist +import torch.nn as nn +import torch.nn.functional as F +from mmcv.runner import auto_fp16 + +from .. import builder + + +class BaseRecognizer(nn.Module, metaclass=ABCMeta): + """Base class for recognizers. + + All recognizers should subclass it. + All subclass should overwrite: + + - Methods:``forward_train``, supporting to forward when training. + - Methods:``forward_test``, supporting to forward when testing. + + Args: + backbone (dict): Backbone modules to extract feature. + cls_head (dict | None): Classification head to process feature. + Default: None. + neck (dict | None): Neck for feature fusion. Default: None. + train_cfg (dict | None): Config for training. Default: None. + test_cfg (dict | None): Config for testing. Default: None. + """ + def __init__(self, + backbone, + cls_head=None, + neck=None, + train_cfg=None, + test_cfg=None): + super().__init__() + # record the source of the backbone + self.backbone_from = 'mmaction2' + + if backbone['type'].startswith('mmcls.'): + try: + import mmcls.models.builder as mmcls_builder + except (ImportError, ModuleNotFoundError): + raise ImportError('Please install mmcls to use this backbone.') + backbone['type'] = backbone['type'][6:] + self.backbone = mmcls_builder.build_backbone(backbone) + self.backbone_from = 'mmcls' + elif backbone['type'].startswith('torchvision.'): + try: + import torchvision.models + except (ImportError, ModuleNotFoundError): + raise ImportError('Please install torchvision to use this ' + 'backbone.') + backbone_type = backbone.pop('type')[12:] + self.backbone = torchvision.models.__dict__[backbone_type]( + **backbone) + # disable the classifier + self.backbone.classifier = nn.Identity() + self.backbone.fc = nn.Identity() + self.backbone_from = 'torchvision' + elif backbone['type'].startswith('timm.'): + try: + import timm + except (ImportError, ModuleNotFoundError): + raise ImportError('Please install timm to use this ' + 'backbone.') + backbone_type = backbone.pop('type')[5:] + # disable the classifier + backbone['num_classes'] = 0 + self.backbone = timm.create_model(backbone_type, **backbone) + self.backbone_from = 'timm' + else: + self.backbone = builder.build_backbone(backbone) + + if neck is not None: + self.neck = builder.build_neck(neck) + + self.cls_head = builder.build_head(cls_head) if cls_head else None + + self.train_cfg = train_cfg + self.test_cfg = test_cfg + + # aux_info is the list of tensor names beyond 'imgs' and 'label' which + # will be used in train_step and val_step, data_batch should contain + # these tensors + self.aux_info = [] + if train_cfg is not None and 'aux_info' in train_cfg: + self.aux_info = train_cfg['aux_info'] + # max_testing_views should be int + self.max_testing_views = None + if test_cfg is not None and 'max_testing_views' in test_cfg: + self.max_testing_views = test_cfg['max_testing_views'] + assert isinstance(self.max_testing_views, int) + + if test_cfg is not None and 'feature_extraction' in test_cfg: + self.feature_extraction = test_cfg['feature_extraction'] + else: + self.feature_extraction = False + + # mini-batch blending, e.g. mixup, cutmix, etc. + self.blending = None + if train_cfg is not None and 'blending' in train_cfg: + from mmcv.utils import build_from_cfg + from mmaction.datasets.builder import BLENDINGS + self.blending = build_from_cfg(train_cfg['blending'], BLENDINGS) + + self.init_weights() + + self.fp16_enabled = False + + @property + def with_neck(self): + """bool: whether the recognizer has a neck""" + return hasattr(self, 'neck') and self.neck is not None + + @property + def with_cls_head(self): + """bool: whether the recognizer has a cls_head""" + return hasattr(self, 'cls_head') and self.cls_head is not None + + def init_weights(self): + """Initialize the model network weights.""" + if self.backbone_from in ['mmcls', 'mmaction2']: + self.backbone.init_weights() + elif self.backbone_from in ['torchvision', 'timm']: + warnings.warn('We do not initialize weights for backbones in ' + f'{self.backbone_from}, since the weights for ' + f'backbones in {self.backbone_from} are initialized' + 'in their __init__ functions.') + else: + raise NotImplementedError('Unsupported backbone source ' + f'{self.backbone_from}!') + + if self.with_cls_head: + self.cls_head.init_weights() + if self.with_neck: + self.neck.init_weights() + + @auto_fp16() + def extract_feat(self, imgs): + """Extract features through a backbone. + + Args: + imgs (torch.Tensor): The input images. + + Returns: + torch.tensor: The extracted features. + """ + if (hasattr(self.backbone, 'features') + and self.backbone_from == 'torchvision'): + x = self.backbone.features(imgs) + elif self.backbone_from == 'timm': + x = self.backbone.forward_features(imgs) + else: + x = self.backbone(imgs) + return x + + def average_clip(self, cls_score, num_segs=1): + """Averaging class score over multiple clips. + + Using different averaging types ('score' or 'prob' or None, + which defined in test_cfg) to computed the final averaged + class score. Only called in test mode. + + Args: + cls_score (torch.Tensor): Class score to be averaged. + num_segs (int): Number of clips for each input sample. + + Returns: + torch.Tensor: Averaged class score. + """ + if 'average_clips' not in self.test_cfg.keys(): + raise KeyError('"average_clips" must defined in test_cfg\'s keys') + + average_clips = self.test_cfg['average_clips'] + if average_clips not in ['score', 'prob', None]: + raise ValueError(f'{average_clips} is not supported. ' + f'Currently supported ones are ' + f'["score", "prob", None]') + + if average_clips is None: + return cls_score + + batch_size = cls_score.shape[0] + cls_score = cls_score.view(batch_size // num_segs, num_segs, -1) + + if average_clips == 'prob': + cls_score = F.softmax(cls_score, dim=2).mean(dim=1) + elif average_clips == 'score': + cls_score = cls_score.mean(dim=1) + + return cls_score + + @abstractmethod + def forward_train(self, imgs, labels, **kwargs): + """Defines the computation performed at every call when training.""" + + @abstractmethod + def forward_test(self, imgs): + """Defines the computation performed at every call when evaluation and + testing.""" + + @abstractmethod + def forward_gradcam(self, imgs): + """Defines the computation performed at every all when using gradcam + utils.""" + + @staticmethod + def _parse_losses(losses): + """Parse the raw outputs (losses) of the network. + + Args: + losses (dict): Raw output of the network, which usually contain + losses and other necessary information. + + Returns: + tuple[Tensor, dict]: (loss, log_vars), loss is the loss tensor + which may be a weighted sum of all losses, log_vars contains + all the variables to be sent to the logger. + """ + log_vars = OrderedDict() + for loss_name, loss_value in losses.items(): + if isinstance(loss_value, torch.Tensor): + log_vars[loss_name] = loss_value.mean() + elif isinstance(loss_value, list): + log_vars[loss_name] = sum(_loss.mean() for _loss in loss_value) + else: + raise TypeError( + f'{loss_name} is not a tensor or list of tensors') + + loss = sum(_value for _key, _value in log_vars.items() + if 'loss' in _key) + + log_vars['loss'] = loss + for loss_name, loss_value in log_vars.items(): + # reduce loss when distributed training + if dist.is_available() and dist.is_initialized(): + loss_value = loss_value.data.clone() + dist.all_reduce(loss_value.div_(dist.get_world_size())) + log_vars[loss_name] = loss_value.item() + + return loss, log_vars + + def forward(self, imgs, label=None, return_loss=True, **kwargs): + """Define the computation performed at every call.""" + if kwargs.get('gradcam', False): + del kwargs['gradcam'] + return self.forward_gradcam(imgs, **kwargs) + if return_loss: + if label is None: + raise ValueError('Label should not be None.') + if self.blending is not None: + imgs, label = self.blending(imgs, label) + return self.forward_train(imgs, label, **kwargs) + + return self.forward_test(imgs, **kwargs) + + def train_step(self, data_batch, optimizer, **kwargs): + """The iteration step during training. + + This method defines an iteration step during training, except for the + back propagation and optimizer updating, which are done in an optimizer + hook. Note that in some complicated cases or models, the whole process + including back propagation and optimizer updating is also defined in + this method, such as GAN. + + Args: + data_batch (dict): The output of dataloader. + optimizer (:obj:`torch.optim.Optimizer` | dict): The optimizer of + runner is passed to ``train_step()``. This argument is unused + and reserved. + + Returns: + dict: It should contain at least 3 keys: ``loss``, ``log_vars``, + ``num_samples``. + ``loss`` is a tensor for back propagation, which can be a + weighted sum of multiple losses. + ``log_vars`` contains all the variables to be sent to the + logger. + ``num_samples`` indicates the batch size (when the model is + DDP, it means the batch size on each GPU), which is used for + averaging the logs. + """ + imgs = data_batch['imgs'].npu().type(torch.float32) + label = data_batch['label'].npu().type(torch.int32) + + aux_info = {} + for item in self.aux_info: + assert item in data_batch + aux_info[item] = data_batch[item] + + losses = self(imgs, label, return_loss=True, **aux_info) + + loss, log_vars = self._parse_losses(losses) + + outputs = dict(loss=loss, + log_vars=log_vars, + num_samples=len(next(iter(data_batch.values())))) + + return outputs + + def val_step(self, data_batch, optimizer, **kwargs): + """The iteration step during validation. + + This method shares the same signature as :func:`train_step`, but used + during val epochs. Note that the evaluation after training epochs is + not implemented with this method, but an evaluation hook. + """ + imgs = data_batch['imgs'].npu().type(torch.float32) + label = data_batch['label'].npu().type(torch.int32) + + aux_info = {} + for item in self.aux_info: + aux_info[item] = data_batch[item] + + losses = self(imgs, label, return_loss=True, **aux_info) + + loss, log_vars = self._parse_losses(losses) + + outputs = dict(loss=loss, + log_vars=log_vars, + num_samples=len(next(iter(data_batch.values())))) + + return outputs diff --git a/PyTorch/contrib/cv/video/SlowFast/mmaction/models/recognizers/recognizer2d.py b/PyTorch/contrib/cv/video/SlowFast/mmaction/models/recognizers/recognizer2d.py index 7d145f6dd8..3d9a755a5a 100644 --- a/PyTorch/contrib/cv/video/SlowFast/mmaction/models/recognizers/recognizer2d.py +++ b/PyTorch/contrib/cv/video/SlowFast/mmaction/models/recognizers/recognizer2d.py @@ -1,195 +1,195 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch -from torch import nn - -from ..builder import RECOGNIZERS -from .base import BaseRecognizer - - -@RECOGNIZERS.register_module() -class Recognizer2D(BaseRecognizer): - """2D recognizer model framework.""" - def forward_train(self, imgs, labels, **kwargs): - """Defines the computation performed at every call when training.""" - - assert self.with_cls_head - batches = imgs.shape[0] - imgs = imgs.reshape((-1, ) + imgs.shape[2:]) - num_segs = imgs.shape[0] // batches - - losses = dict() - - x = self.extract_feat(imgs) - - if self.backbone_from in ['torchvision', 'timm']: - if len(x.shape) == 4 and (x.shape[2] > 1 or x.shape[3] > 1): - # apply adaptive avg pooling - x = nn.AdaptiveAvgPool2d(1)(x) - x = x.reshape((x.shape[0], -1)) - x = x.reshape(x.shape + (1, 1)) - - if self.with_neck: - x = [ - each.reshape((-1, num_segs) + each.shape[1:]).transpose( - 1, 2).contiguous() for each in x - ] - x, loss_aux = self.neck(x, labels.squeeze()) - x = x.squeeze(2) - num_segs = 1 - losses.update(loss_aux) - - cls_score = self.cls_head(x, num_segs) - gt_labels = labels.squeeze() - loss_cls = self.cls_head.loss(cls_score, gt_labels, **kwargs) - losses.update(loss_cls) - - return losses - - def _do_test(self, imgs): - """Defines the computation performed at every call when evaluation, - testing and gradcam.""" - batches = imgs.shape[0] - imgs = imgs.reshape((-1, ) + imgs.shape[2:]) - num_segs = imgs.shape[0] // batches - - x = self.extract_feat(imgs) - - if self.backbone_from in ['torchvision', 'timm']: - if len(x.shape) == 4 and (x.shape[2] > 1 or x.shape[3] > 1): - # apply adaptive avg pooling - x = nn.AdaptiveAvgPool2d(1)(x) - x = x.reshape((x.shape[0], -1)) - x = x.reshape(x.shape + (1, 1)) - - if self.with_neck: - x = [ - each.reshape((-1, num_segs) + each.shape[1:]).transpose( - 1, 2).contiguous() for each in x - ] - x, _ = self.neck(x) - x = x.squeeze(2) - num_segs = 1 - - if self.feature_extraction: - # perform spatial pooling - avg_pool = nn.AdaptiveAvgPool2d(1) - x = avg_pool(x) - # squeeze dimensions - x = x.reshape((batches, num_segs, -1)) - # temporal average pooling - x = x.mean(axis=1) - return x - - # When using `TSNHead` or `TPNHead`, shape is [batch_size, num_classes] - # When using `TSMHead`, shape is [batch_size * num_crops, num_classes] - # `num_crops` is calculated by: - # 1) `twice_sample` in `SampleFrames` - # 2) `num_sample_positions` in `DenseSampleFrames` - # 3) `ThreeCrop/TenCrop/MultiGroupCrop` in `test_pipeline` - # 4) `num_clips` in `SampleFrames` or its subclass if `clip_len != 1` - - # should have cls_head if not extracting features - cls_score = self.cls_head(x, num_segs) - - assert cls_score.size()[0] % batches == 0 - # calculate num_crops automatically - cls_score = self.average_clip(cls_score, - cls_score.size()[0] // batches) - return cls_score - - def _do_fcn_test(self, imgs): - # [N, num_crops * num_segs, C, H, W] -> - # [N * num_crops * num_segs, C, H, W] - batches = imgs.shape[0] - imgs = imgs.reshape((-1, ) + imgs.shape[2:]) - num_segs = self.test_cfg.get('num_segs', self.backbone.num_segments) - - if self.test_cfg.get('flip', False): - imgs = torch.flip(imgs, [-1]) - x = self.extract_feat(imgs) - - if self.with_neck: - x = [ - each.reshape((-1, num_segs) + each.shape[1:]).transpose( - 1, 2).contiguous() for each in x - ] - x, _ = self.neck(x) - else: - x = x.reshape((-1, num_segs) + x.shape[1:]).transpose( - 1, 2).contiguous() - - # When using `TSNHead` or `TPNHead`, shape is [batch_size, num_classes] - # When using `TSMHead`, shape is [batch_size * num_crops, num_classes] - # `num_crops` is calculated by: - # 1) `twice_sample` in `SampleFrames` - # 2) `num_sample_positions` in `DenseSampleFrames` - # 3) `ThreeCrop/TenCrop/MultiGroupCrop` in `test_pipeline` - # 4) `num_clips` in `SampleFrames` or its subclass if `clip_len != 1` - cls_score = self.cls_head(x, fcn_test=True) - - assert cls_score.size()[0] % batches == 0 - # calculate num_crops automatically - cls_score = self.average_clip(cls_score, - cls_score.size()[0] // batches) - return cls_score - - def forward_test(self, imgs): - """Defines the computation performed at every call when evaluation and - testing.""" - imgs = imgs.npu().type(torch.float16) - if self.test_cfg.get('fcn_test', False): - # If specified, spatially fully-convolutional testing is performed - assert not self.feature_extraction - assert self.with_cls_head - return self._do_fcn_test(imgs).cpu().numpy() - return self._do_test(imgs).cpu().numpy() - - def forward_dummy(self, imgs, softmax=False): - """Used for computing network FLOPs. - - See ``tools/analysis/get_flops.py``. - - Args: - imgs (torch.Tensor): Input images. - - Returns: - Tensor: Class score. - """ - assert self.with_cls_head - batches = imgs.shape[0] - imgs = imgs.reshape((-1, ) + imgs.shape[2:]) - num_segs = imgs.shape[0] // batches - - x = self.extract_feat(imgs) - if self.with_neck: - x = [ - each.reshape((-1, num_segs) + each.shape[1:]).transpose( - 1, 2).contiguous() for each in x - ] - x, _ = self.neck(x) - x = x.squeeze(2) - num_segs = 1 - - outs = self.cls_head(x, num_segs) - if softmax: - outs = nn.functional.softmax(outs) - return (outs, ) - - def forward_gradcam(self, imgs): - """Defines the computation performed at every call when using gradcam - utils.""" - assert self.with_cls_head - return self._do_test(imgs) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch +from torch import nn + +from ..builder import RECOGNIZERS +from .base import BaseRecognizer + + +@RECOGNIZERS.register_module() +class Recognizer2D(BaseRecognizer): + """2D recognizer model framework.""" + def forward_train(self, imgs, labels, **kwargs): + """Defines the computation performed at every call when training.""" + + assert self.with_cls_head + batches = imgs.shape[0] + imgs = imgs.reshape((-1, ) + imgs.shape[2:]) + num_segs = imgs.shape[0] // batches + + losses = dict() + + x = self.extract_feat(imgs) + + if self.backbone_from in ['torchvision', 'timm']: + if len(x.shape) == 4 and (x.shape[2] > 1 or x.shape[3] > 1): + # apply adaptive avg pooling + x = nn.AdaptiveAvgPool2d(1)(x) + x = x.reshape((x.shape[0], -1)) + x = x.reshape(x.shape + (1, 1)) + + if self.with_neck: + x = [ + each.reshape((-1, num_segs) + each.shape[1:]).transpose( + 1, 2).contiguous() for each in x + ] + x, loss_aux = self.neck(x, labels.squeeze()) + x = x.squeeze(2) + num_segs = 1 + losses.update(loss_aux) + + cls_score = self.cls_head(x, num_segs) + gt_labels = labels.squeeze() + loss_cls = self.cls_head.loss(cls_score, gt_labels, **kwargs) + losses.update(loss_cls) + + return losses + + def _do_test(self, imgs): + """Defines the computation performed at every call when evaluation, + testing and gradcam.""" + batches = imgs.shape[0] + imgs = imgs.reshape((-1, ) + imgs.shape[2:]) + num_segs = imgs.shape[0] // batches + + x = self.extract_feat(imgs) + + if self.backbone_from in ['torchvision', 'timm']: + if len(x.shape) == 4 and (x.shape[2] > 1 or x.shape[3] > 1): + # apply adaptive avg pooling + x = nn.AdaptiveAvgPool2d(1)(x) + x = x.reshape((x.shape[0], -1)) + x = x.reshape(x.shape + (1, 1)) + + if self.with_neck: + x = [ + each.reshape((-1, num_segs) + each.shape[1:]).transpose( + 1, 2).contiguous() for each in x + ] + x, _ = self.neck(x) + x = x.squeeze(2) + num_segs = 1 + + if self.feature_extraction: + # perform spatial pooling + avg_pool = nn.AdaptiveAvgPool2d(1) + x = avg_pool(x) + # squeeze dimensions + x = x.reshape((batches, num_segs, -1)) + # temporal average pooling + x = x.mean(axis=1) + return x + + # When using `TSNHead` or `TPNHead`, shape is [batch_size, num_classes] + # When using `TSMHead`, shape is [batch_size * num_crops, num_classes] + # `num_crops` is calculated by: + # 1) `twice_sample` in `SampleFrames` + # 2) `num_sample_positions` in `DenseSampleFrames` + # 3) `ThreeCrop/TenCrop/MultiGroupCrop` in `test_pipeline` + # 4) `num_clips` in `SampleFrames` or its subclass if `clip_len != 1` + + # should have cls_head if not extracting features + cls_score = self.cls_head(x, num_segs) + + assert cls_score.size()[0] % batches == 0 + # calculate num_crops automatically + cls_score = self.average_clip(cls_score, + cls_score.size()[0] // batches) + return cls_score + + def _do_fcn_test(self, imgs): + # [N, num_crops * num_segs, C, H, W] -> + # [N * num_crops * num_segs, C, H, W] + batches = imgs.shape[0] + imgs = imgs.reshape((-1, ) + imgs.shape[2:]) + num_segs = self.test_cfg.get('num_segs', self.backbone.num_segments) + + if self.test_cfg.get('flip', False): + imgs = torch.flip(imgs, [-1]) + x = self.extract_feat(imgs) + + if self.with_neck: + x = [ + each.reshape((-1, num_segs) + each.shape[1:]).transpose( + 1, 2).contiguous() for each in x + ] + x, _ = self.neck(x) + else: + x = x.reshape((-1, num_segs) + x.shape[1:]).transpose( + 1, 2).contiguous() + + # When using `TSNHead` or `TPNHead`, shape is [batch_size, num_classes] + # When using `TSMHead`, shape is [batch_size * num_crops, num_classes] + # `num_crops` is calculated by: + # 1) `twice_sample` in `SampleFrames` + # 2) `num_sample_positions` in `DenseSampleFrames` + # 3) `ThreeCrop/TenCrop/MultiGroupCrop` in `test_pipeline` + # 4) `num_clips` in `SampleFrames` or its subclass if `clip_len != 1` + cls_score = self.cls_head(x, fcn_test=True) + + assert cls_score.size()[0] % batches == 0 + # calculate num_crops automatically + cls_score = self.average_clip(cls_score, + cls_score.size()[0] // batches) + return cls_score + + def forward_test(self, imgs): + """Defines the computation performed at every call when evaluation and + testing.""" + imgs = imgs.npu().type(torch.float16) + if self.test_cfg.get('fcn_test', False): + # If specified, spatially fully-convolutional testing is performed + assert not self.feature_extraction + assert self.with_cls_head + return self._do_fcn_test(imgs).cpu().numpy() + return self._do_test(imgs).cpu().numpy() + + def forward_dummy(self, imgs, softmax=False): + """Used for computing network FLOPs. + + See ``tools/analysis/get_flops.py``. + + Args: + imgs (torch.Tensor): Input images. + + Returns: + Tensor: Class score. + """ + assert self.with_cls_head + batches = imgs.shape[0] + imgs = imgs.reshape((-1, ) + imgs.shape[2:]) + num_segs = imgs.shape[0] // batches + + x = self.extract_feat(imgs) + if self.with_neck: + x = [ + each.reshape((-1, num_segs) + each.shape[1:]).transpose( + 1, 2).contiguous() for each in x + ] + x, _ = self.neck(x) + x = x.squeeze(2) + num_segs = 1 + + outs = self.cls_head(x, num_segs) + if softmax: + outs = nn.functional.softmax(outs) + return (outs, ) + + def forward_gradcam(self, imgs): + """Defines the computation performed at every call when using gradcam + utils.""" + assert self.with_cls_head + return self._do_test(imgs) diff --git a/PyTorch/contrib/cv/video/SlowFast/mmaction/models/recognizers/recognizer3d.py b/PyTorch/contrib/cv/video/SlowFast/mmaction/models/recognizers/recognizer3d.py index fe1a61ef2b..9a1b70449d 100644 --- a/PyTorch/contrib/cv/video/SlowFast/mmaction/models/recognizers/recognizer3d.py +++ b/PyTorch/contrib/cv/video/SlowFast/mmaction/models/recognizers/recognizer3d.py @@ -1,133 +1,133 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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 torch -from torch import nn - -from ..builder import RECOGNIZERS -from .base import BaseRecognizer - - -@RECOGNIZERS.register_module() -class Recognizer3D(BaseRecognizer): - """3D recognizer model framework.""" - def forward_train(self, imgs, labels, **kwargs): - """Defines the computation performed at every call when training.""" - - assert self.with_cls_head - imgs = imgs.reshape((-1, ) + imgs.shape[2:]) - losses = dict() - - x = self.extract_feat(imgs) - if self.with_neck: - x, loss_aux = self.neck(x, labels.squeeze()) - losses.update(loss_aux) - - cls_score = self.cls_head(x) - gt_labels = labels.squeeze() - loss_cls = self.cls_head.loss(cls_score, gt_labels, **kwargs) - losses.update(loss_cls) - - return losses - - def _do_test(self, imgs): - """Defines the computation performed at every call when evaluation, - testing and gradcam.""" - batches = imgs.shape[0] - num_segs = imgs.shape[1] - imgs = imgs.reshape((-1, ) + imgs.shape[2:]) - - if self.max_testing_views is not None: - total_views = imgs.shape[0] - assert num_segs == total_views, ( - 'max_testing_views is only compatible ' - 'with batch_size == 1') - view_ptr = 0 - feats = [] - while view_ptr < total_views: - batch_imgs = imgs[view_ptr:view_ptr + self.max_testing_views] - x = self.extract_feat(batch_imgs) - if self.with_neck: - x, _ = self.neck(x) - feats.append(x) - view_ptr += self.max_testing_views - # should consider the case that feat is a tuple - if isinstance(feats[0], tuple): - len_tuple = len(feats[0]) - feat = [ - torch.cat([x[i] for x in feats]) for i in range(len_tuple) - ] - feat = tuple(feat) - else: - feat = torch.cat(feats) - else: - feat = self.extract_feat(imgs) - if self.with_neck: - feat, _ = self.neck(feat) - - if self.feature_extraction: - # perform spatio-temporal pooling - avg_pool = nn.AdaptiveAvgPool3d(1) - if isinstance(feat, tuple): - feat = [avg_pool(x) for x in feat] - # concat them - feat = torch.cat(feat, axis=1) - else: - feat = avg_pool(feat) - # squeeze dimensions - feat = feat.reshape((batches, num_segs, -1)) - # temporal average pooling - feat = feat.mean(axis=1) - return feat - - # should have cls_head if not extracting features - assert self.with_cls_head - cls_score = self.cls_head(feat) - cls_score = self.average_clip(cls_score, num_segs) - return cls_score - - def forward_test(self, imgs): - """Defines the computation performed at every call when evaluation and - testing.""" - imgs = imgs.npu().type(torch.float16) - return self._do_test(imgs).cpu().numpy() - - def forward_dummy(self, imgs, softmax=False): - """Used for computing network FLOPs. - - See ``tools/analysis/get_flops.py``. - - Args: - imgs (torch.Tensor): Input images. - - Returns: - Tensor: Class score. - """ - assert self.with_cls_head - imgs = imgs.reshape((-1, ) + imgs.shape[2:]) - x = self.extract_feat(imgs) - - if self.with_neck: - x, _ = self.neck(x) - - outs = self.cls_head(x) - if softmax: - outs = nn.functional.softmax(outs) - return (outs, ) - - def forward_gradcam(self, imgs): - """Defines the computation performed at every call when using gradcam - utils.""" - assert self.with_cls_head - return self._do_test(imgs) +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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 torch +from torch import nn + +from ..builder import RECOGNIZERS +from .base import BaseRecognizer + + +@RECOGNIZERS.register_module() +class Recognizer3D(BaseRecognizer): + """3D recognizer model framework.""" + def forward_train(self, imgs, labels, **kwargs): + """Defines the computation performed at every call when training.""" + + assert self.with_cls_head + imgs = imgs.reshape((-1, ) + imgs.shape[2:]) + losses = dict() + + x = self.extract_feat(imgs) + if self.with_neck: + x, loss_aux = self.neck(x, labels.squeeze()) + losses.update(loss_aux) + + cls_score = self.cls_head(x) + gt_labels = labels.squeeze() + loss_cls = self.cls_head.loss(cls_score, gt_labels, **kwargs) + losses.update(loss_cls) + + return losses + + def _do_test(self, imgs): + """Defines the computation performed at every call when evaluation, + testing and gradcam.""" + batches = imgs.shape[0] + num_segs = imgs.shape[1] + imgs = imgs.reshape((-1, ) + imgs.shape[2:]) + + if self.max_testing_views is not None: + total_views = imgs.shape[0] + assert num_segs == total_views, ( + 'max_testing_views is only compatible ' + 'with batch_size == 1') + view_ptr = 0 + feats = [] + while view_ptr < total_views: + batch_imgs = imgs[view_ptr:view_ptr + self.max_testing_views] + x = self.extract_feat(batch_imgs) + if self.with_neck: + x, _ = self.neck(x) + feats.append(x) + view_ptr += self.max_testing_views + # should consider the case that feat is a tuple + if isinstance(feats[0], tuple): + len_tuple = len(feats[0]) + feat = [ + torch.cat([x[i] for x in feats]) for i in range(len_tuple) + ] + feat = tuple(feat) + else: + feat = torch.cat(feats) + else: + feat = self.extract_feat(imgs) + if self.with_neck: + feat, _ = self.neck(feat) + + if self.feature_extraction: + # perform spatio-temporal pooling + avg_pool = nn.AdaptiveAvgPool3d(1) + if isinstance(feat, tuple): + feat = [avg_pool(x) for x in feat] + # concat them + feat = torch.cat(feat, axis=1) + else: + feat = avg_pool(feat) + # squeeze dimensions + feat = feat.reshape((batches, num_segs, -1)) + # temporal average pooling + feat = feat.mean(axis=1) + return feat + + # should have cls_head if not extracting features + assert self.with_cls_head + cls_score = self.cls_head(feat) + cls_score = self.average_clip(cls_score, num_segs) + return cls_score + + def forward_test(self, imgs): + """Defines the computation performed at every call when evaluation and + testing.""" + imgs = imgs.npu().type(torch.float16) + return self._do_test(imgs).cpu().numpy() + + def forward_dummy(self, imgs, softmax=False): + """Used for computing network FLOPs. + + See ``tools/analysis/get_flops.py``. + + Args: + imgs (torch.Tensor): Input images. + + Returns: + Tensor: Class score. + """ + assert self.with_cls_head + imgs = imgs.reshape((-1, ) + imgs.shape[2:]) + x = self.extract_feat(imgs) + + if self.with_neck: + x, _ = self.neck(x) + + outs = self.cls_head(x) + if softmax: + outs = nn.functional.softmax(outs) + return (outs, ) + + def forward_gradcam(self, imgs): + """Defines the computation performed at every call when using gradcam + utils.""" + assert self.with_cls_head + return self._do_test(imgs) diff --git a/PyTorch/contrib/cv/video/VideoPose3D/run.py b/PyTorch/contrib/cv/video/VideoPose3D/run.py index dea000f7c6..c252af1564 100644 --- a/PyTorch/contrib/cv/video/VideoPose3D/run.py +++ b/PyTorch/contrib/cv/video/VideoPose3D/run.py @@ -1,699 +1,699 @@ -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ - -# Copyright (c) 2018-present, Facebook, Inc. -# All rights reserved. -# -# This source code is licensed under the license found in the -# LICENSE file in the root directory of this source tree. - - -import numpy as np - -from common.arguments import parse_args -import torch - -import torch.nn as nn -import torch.nn.functional as F -import torch.optim as optim -import torch.distributed as dist -import torch.multiprocessing as mp -import os -import sys -import errno -import math -import logging - -from common.camera import * -from common.model import * -from common.loss import * -from common.generators import ChunkedGenerator, UnchunkedGenerator -from time import time -from common.utils import deterministic_random, fetch, run_evaluation -from common.structure import AverageMeter, time_format_convert, device_id_to_process_device_map - -from tensorboardX import SummaryWriter -from apex import amp -# from apex.optimizers import NpuFusedAdam - - -def main(): - args = parse_args() - # print(args) - - try: - # Create checkpoint directory if it does not exist - os.makedirs(args.checkpoint) - except OSError as e: - if e.errno != errno.EEXIST: - raise RuntimeError('Unable to create checkpoint directory:', args.checkpoint) - - if not os.path.exists(args.output): - os.makedirs(args.output) - print(f"args.output:{args.output}") - - os.environ['MASTER_ADDR'] = '127.0.0.1' - os.environ['MASTER_PORT'] = '27005' - - process_device_map = device_id_to_process_device_map(args.device_list) - - if args.device == 'npu': - ngpus_per_node = len(process_device_map) - else: - ngpus_per_node = args.num_gpus - - args.num_gpus = ngpus_per_node - args.world_size = args.world_size * ngpus_per_node - - # npu = int(os.environ['RANK_ID']) - mp.spawn(main_worker, nprocs=ngpus_per_node, args=(ngpus_per_node, args)) - - -def setup_logger(final_output_dir, rank, phase): - # time_str = time.strftime('%Y-%m-%d-%H-%M') - log_file = '{}_rank{}.log'.format(phase, rank) - final_log_file = os.path.join(final_output_dir, log_file) - head = '%(asctime)-15s %(message)s' - # logging.basicConfig(format=head) - logging.basicConfig(filename=str(final_log_file), - format=head) - logger = logging.getLogger() - logger.setLevel(logging.INFO) - console = logging.StreamHandler() - logging.getLogger('').addHandler(console) - - return logger - - -def main_worker(gpu, ngpus_per_node, args): - process_device_map = device_id_to_process_device_map(args.device_list) - log_dir = args.output - logger = setup_logger(log_dir, gpu, 'train') - - # args.gpu = gpu - args.gpu = process_device_map[gpu] - # logger.info(f"args.gpu is {args.gpu}") - - args.rank = args.rank * ngpus_per_node + gpu - - # print(f'args.print_feq:{args.print_feq}') - if args.rank % ngpus_per_node == 0: - log_path = args.log - writer_dict = { - 'writer': SummaryWriter(logdir=log_path), - 'train_global_steps': 0, - 'valid_global_steps': 0, - } - - if args.device == 'npu': - print("args.rank:",args.rank) - dist.init_process_group(backend=args.dist_backend, # init_method=args.dist_url, - world_size=args.world_size, rank=args.rank) - else: - dist.init_process_group(backend='nccl', init_method=args.dist_url, - world_size=args.world_size, rank=args.rank) - - logger.info(f'Loading dataset for rank:{args.rank}...') - dataset_path = 'data/data_3d_' + args.dataset + '.npz' - if args.dataset == 'h36m': - from common.h36m_dataset import Human36mDataset - dataset = Human36mDataset(dataset_path) - elif args.dataset.startswith('humaneva'): - from common.humaneva_dataset import HumanEvaDataset - dataset = HumanEvaDataset(dataset_path) - elif args.dataset.startswith('custom'): - from common.custom_dataset import CustomDataset - dataset = CustomDataset('data/data_2d_' + args.dataset + '_' + args.keypoints + '.npz') - else: - raise KeyError('Invalid dataset') - - logger.info(f'Preparing data for rank:{args.rank}...') - for subject in dataset.subjects(): - for action in dataset[subject].keys(): - anim = dataset[subject][action] - - if 'positions' in anim: - positions_3d = [] - for cam in anim['cameras']: - pos_3d = world_to_camera(anim['positions'], R=cam['orientation'], t=cam['translation']) - pos_3d[:, 1:] -= pos_3d[:, :1] # Remove global offset, but keep trajectory in first position - positions_3d.append(pos_3d) - anim['positions_3d'] = positions_3d - - logger.info(f'Loading 2D detections for rank:{args.rank}...') - keypoints = np.load('data/data_2d_' + args.dataset + '_' + args.keypoints + '.npz', allow_pickle=True) - keypoints_metadata = keypoints['metadata'].item() - keypoints_symmetry = keypoints_metadata['keypoints_symmetry'] - kps_left, kps_right = list(keypoints_symmetry[0]), list(keypoints_symmetry[1]) - joints_left, joints_right = list(dataset.skeleton().joints_left()), list(dataset.skeleton().joints_right()) - keypoints = keypoints['positions_2d'].item() - - for subject in dataset.subjects(): - assert subject in keypoints, 'Subject {} is missing from the 2D detections dataset'.format(subject) - for action in dataset[subject].keys(): - assert action in keypoints[subject], 'Action {} of subject {} is missing from the 2D detections dataset'.format(action, subject) - if 'positions_3d' not in dataset[subject][action]: - continue - - for cam_idx in range(len(keypoints[subject][action])): - - # We check for >= instead of == because some videos in H3.6M contain extra frames - mocap_length = dataset[subject][action]['positions_3d'][cam_idx].shape[0] - assert keypoints[subject][action][cam_idx].shape[0] >= mocap_length - - if keypoints[subject][action][cam_idx].shape[0] > mocap_length: - # Shorten sequence - keypoints[subject][action][cam_idx] = keypoints[subject][action][cam_idx][:mocap_length] - - assert len(keypoints[subject][action]) == len(dataset[subject][action]['positions_3d']) - - for subject in keypoints.keys(): - for action in keypoints[subject]: - for cam_idx, kps in enumerate(keypoints[subject][action]): - # Normalize camera frame - cam = dataset.cameras()[subject][cam_idx] - kps[..., :2] = normalize_screen_coordinates(kps[..., :2], w=cam['res_w'], h=cam['res_h']) - keypoints[subject][action][cam_idx] = kps - - subjects_train = args.subjects_train.split(',') - subjects_semi = [] if not args.subjects_unlabeled else args.subjects_unlabeled.split(',') - if not args.render: - subjects_test = args.subjects_test.split(',') - else: - subjects_test = [args.viz_subject] - - semi_supervised = len(subjects_semi) > 0 - if semi_supervised and not dataset.supports_semi_supervised(): - raise RuntimeError('Semi-supervised training is not implemented for this dataset') - - # moved fatch to utils.py - - action_filter = None if args.actions == '*' else args.actions.split(',') - if action_filter is not None: - print('Selected actions:', action_filter) - - cameras_valid, poses_valid, poses_valid_2d = fetch(subjects_test, keypoints=keypoints, dataset=dataset, args=args ,action_filter=action_filter) - - filter_widths = [int(x) for x in args.architecture.split(',')] - if not args.disable_optimizations and not args.dense and args.stride == 1: - # Use optimized model for single-frame predictions - model_pos_train = TemporalModelOptimized1f(poses_valid_2d[0].shape[-2], poses_valid_2d[0].shape[-1], dataset.skeleton().num_joints(), - filter_widths=filter_widths, causal=args.causal, dropout=args.dropout, channels=args.channels) - else: - # When incompatible settings are detected (stride > 1, dense filters, or disabled optimization) fall back to normal model - model_pos_train = TemporalModel(poses_valid_2d[0].shape[-2], poses_valid_2d[0].shape[-1], dataset.skeleton().num_joints(), - filter_widths=filter_widths, causal=args.causal, dropout=args.dropout, channels=args.channels, - dense=args.dense) - - model_pos = TemporalModel(poses_valid_2d[0].shape[-2], poses_valid_2d[0].shape[-1], dataset.skeleton().num_joints(), - filter_widths=filter_widths, causal=args.causal, dropout=args.dropout, channels=args.channels, - dense=args.dense) - - receptive_field = model_pos.receptive_field() - logger.info('INFO: Receptive field: {} frames'.format(receptive_field)) - pad = (receptive_field - 1) // 2 # Padding on each side - if args.causal: - logger.info('INFO: Using causal convolutions') - causal_shift = pad - else: - causal_shift = 0 - - model_params = 0 - for parameter in model_pos.parameters(): - model_params += parameter.numel() - print('INFO: Trainable parameter count:', model_params) - - assert args.gpu is not None, "Something wrong about args.gpu, it shouldn't be None." - - if not torch.npu.is_available(): - print("We only implemented for GPUs") - raise NotImplementedError - else: - loc = f'npu:{args.gpu}' - torch.npu.set_device(loc) - model_pos = model_pos.to(loc) - model_pos_train = model_pos_train.to(loc) - model_pos = torch.nn.parallel.DistributedDataParallel(model_pos, device_ids=[args.gpu], broadcast_buffers=False) - - - - if args.evaluate: - assert args.resume is '' - chk_filename = os.path.join(args.checkpoint, args.evaluate) - logger.info(f'Loading checkpoint {chk_filename}') - checkpoint = torch.load(chk_filename, map_location=lambda storage, loc: storage) - model_pos.load_state_dict(checkpoint['model_pos']) - model_traj = None - - - test_generator = UnchunkedGenerator(args, cameras_valid, poses_valid, poses_valid_2d, - pad=pad, causal_shift=causal_shift, augment=False, - kps_left=kps_left, kps_right=kps_right, joints_left=joints_left, joints_right=joints_right) - logger.info('INFO: Testing on {} frames'.format(test_generator.num_frames())) - - if not args.evaluate: - cameras_train, poses_train, poses_train_2d = fetch(subjects_train, keypoints=keypoints, dataset=dataset, args=args, action_filter=action_filter, subset=args.subset) - - lr = args.learning_rate - if args.rank % args.num_gpus == 0: - logger.info(f"inital learning rate is:{lr}") - if semi_supervised: - print("Not Implement semi_supervised version for DDP") - raise NotImplementedError - else: - optimizer = optim.Adam(model_pos_train.parameters(), lr=lr) #, amsgrad=True) - # optimizer = NpuFusedAdam(model_pos_train.parameters(), lr=lr) - print(f"Use Apex:{args.apex}") - print(f"Sampler:{args.sampler}") - if args.apex: - model_pos_train, optimizer = amp.initialize(model_pos_train, optimizer, opt_level="O1", loss_scale=128.0) #, combine_grad=True) - model_pos_train = torch.nn.parallel.DistributedDataParallel(model_pos_train, device_ids=[args.gpu], broadcast_buffers=False) - - lr_decay = args.lr_decay - - losses_3d_train = [] - losses_3d_train_eval = [] - losses_3d_valid = [] - - epoch = 0 - initial_momentum = 0.1 - final_momentum = 0.001 - - - train_generator = ChunkedGenerator(args, args.batch_size//args.stride, cameras_train, poses_train, poses_train_2d, args.stride, - pad=pad, causal_shift=causal_shift, shuffle=True, random_seed=args.random_seed, augment=args.data_augmentation, - kps_left=kps_left, kps_right=kps_right, joints_left=joints_left, joints_right=joints_right) - train_generator_eval = UnchunkedGenerator(args, cameras_train, poses_train, poses_train_2d, - pad=pad, causal_shift=causal_shift, augment=False) - print('INFO: Training on {} frames'.format(train_generator_eval.num_frames())) - if semi_supervised: - print("Not Implement semi_supervised version for DDP") - raise NotImplementedError - - if args.resume: - chk_filename = os.path.join(args.checkpoint, args.resume) - print("resuming the training...") - print('Loading checkpoint', chk_filename) - checkpoint = torch.load(chk_filename, map_location=loc) - epoch = checkpoint['epoch'] - model_pos_train.load_state_dict(checkpoint['model_pos']) - if 'optimizer' in checkpoint and checkpoint['optimizer'] is not None: - optimizer.load_state_dict(checkpoint['optimizer']) - # train_generator.set_random_state(checkpoint['random_state']) - else: - print('WARNING: this checkpoint does not contain an optimizer state. The optimizer will be reinitialized.') - if checkpoint['amp'] is not None: - amp.load_state_dict(checkpoint['amp']) - if args.rank % ngpus_per_node == 0: - if 'train_global_steps' in checkpoint and 'valid_global_steps' in checkpoint: - writer_dict['train_global_steps'] = checkpoint['train_global_steps'] - writer_dict['valid_global_steps'] = checkpoint['valid_global_steps'] - lr = checkpoint['lr'] - if semi_supervised: - print("Not Implement semi_supervised version for DDP") - raise NotImplementedError - # model_traj_train.load_state_dict(checkpoint['model_traj']) - # model_traj.load_state_dict(checkpoint['model_traj']) - # semi_generator.set_random_state(checkpoint['random_state_semi']) - - logger.info('** Note: reported losses are averaged over all frames and test-time augmentation is not used here.') - logger.info('** The final evaluation will be carried out after the last training epoch.') - - myend = time() - mytime = AverageMeter() - best_valid = 50.0 - prof_flag = args.prof - while epoch < args.epochs: - start_time = time() - epoch_loss = AverageMeter() - epoch_loss_val = AverageMeter() - train_generator.set_epoch(epoch) - epoch_loss_3d_train = 0 - # epoch_loss_traj_train = 0 - # epoch_loss_2d_train_unlabeled = 0 - epoch_fps = AverageMeter() - N = 0 - N_semi = 0 - model_pos_train.train() - if semi_supervised: - print("Not Implement semi_supervised version for DDP") - raise NotImplementedError - else: - # Regular supervised scenario - count = 0 - for _, batch_3d, batch_2d in train_generator.next_epoch(): - if count >= 2: - my_epoch_start = time() - if batch_2d.shape[0] == 0: - continue - # print(f"batch_3d.shape:{batch_3d.shape} for rank:{args.rank}") - bz = batch_2d.shape[0] - assert batch_3d.shape[0] == bz - inputs_3d = torch.from_numpy(batch_3d.astype('float32')) - inputs_2d = torch.from_numpy(batch_2d.astype('float32')) - if torch.npu.is_available(): - inputs_3d = inputs_3d.to(loc, non_blocking=False) - inputs_2d = inputs_2d.to(loc, non_blocking=False) - inputs_3d[:, :, 0] = 0 - - if prof_flag and count==10 and args.rank==0: - with torch.autograd.profiler.profile(use_npu=True) as prof: - optimizer.zero_grad() - - # Predict 3D poses - predicted_3d_pos = model_pos_train(inputs_2d) - loss_3d_pos = mpjpe(predicted_3d_pos, inputs_3d) - - loss_total = loss_3d_pos - if args.apex: - with amp.scale_loss(loss_total, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss_total.backward() - - optimizer.step() - print(prof.key_averages().table(sort_by='self_cpu_time_total')) - prof.export_chrome_trace(os.path.join(args.checkpoint,'out.prof')) - prof_flag = False - print(f"prof has been saved as {os.path.join(args.checkpoint,'out.prof')}") - else: - optimizer.zero_grad() - - # Predict 3D poses - predicted_3d_pos = model_pos_train(inputs_2d) - loss_3d_pos = mpjpe(predicted_3d_pos, inputs_3d) - - loss_total = loss_3d_pos - if args.apex: - with amp.scale_loss(loss_total, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss_total.backward() - - optimizer.step() - - dist.all_reduce(loss_total) - loss_total = loss_total / ngpus_per_node - epoch_loss.update(loss_total.item(), bz) - - epoch_loss_3d_train += inputs_3d.shape[0]*inputs_3d.shape[1] * loss_total.item() - N += inputs_3d.shape[0]*inputs_3d.shape[1] - - if count >= 2: - batch_time = time()-my_epoch_start - fps = bz * ngpus_per_node / batch_time - epoch_fps.update(fps) - if args.rank % ngpus_per_node == 0: - writer = writer_dict['writer'] - train_step = writer_dict['train_global_steps'] - writer.add_scalar('total_loss',epoch_loss.avg,train_step) - writer_dict['train_global_steps'] = train_step + 1 - - - if count % args.print_freq == 0 and args.rank % ngpus_per_node == 0: - logger.info("({batch}/{size})| loss:{loss.val:.5f} ({loss.avg:.5f})| FPS:{fps.val:.3f} ({fps.avg:.3f})".format( - batch=count, size=math.ceil(train_generator.num_frames()/(args.batch_size*ngpus_per_node)), loss=epoch_loss, - fps=epoch_fps - )) - count +=1 - if args.rank % ngpus_per_node == 0: - writer.add_scalar('loss_3d/train', epoch_loss_3d_train / N, epoch) - - losses_3d_train.append(epoch_loss_3d_train / N) - - - # End-of-epoch evaluation - if args.rank == 0 and not args.no_eval: - print("End of epoch evaluation start ....") - with torch.no_grad(): - model_pos.load_state_dict(model_pos_train.state_dict()) - model_pos.eval() - if semi_supervised: - print("Not Implement semi_supervised version for DDP") - raise NotImplementedError - # model_traj.load_state_dict(model_traj_train.state_dict()) - # model_traj.eval() - - epoch_loss_3d_valid = 0 - epoch_loss_traj_valid = 0 - epoch_loss_2d_valid = 0 - N = 0 - - if not args.no_eval: - # Evaluate on test set - for cam, batch, batch_2d in test_generator.next_epoch(): - inputs_3d = torch.from_numpy(batch.astype('float32')) - inputs_2d = torch.from_numpy(batch_2d.astype('float32')) - if torch.npu.is_available(): - inputs_3d = inputs_3d.to(loc, non_blocking=False) - inputs_2d = inputs_2d.to(loc, non_blocking=False) - inputs_traj = inputs_3d[:, :, :1].clone() - inputs_3d[:, :, 0] = 0 - - # Predict 3D poses - predicted_3d_pos = model_pos(inputs_2d) - loss_3d_pos = mpjpe(predicted_3d_pos, inputs_3d) - - bz = inputs_2d.shape[0] - assert bz == inputs_3d.shape[0] - - dist.all_reduce(loss_3d_pos) - loss_3d_pos = loss_3d_pos / ngpus_per_node - - epoch_loss_val.update(loss_3d_pos, bz) - - epoch_loss_3d_valid += inputs_3d.shape[0]*inputs_3d.shape[1] * loss_3d_pos.item() - N += inputs_3d.shape[0]*inputs_3d.shape[1] - - if args.rank % ngpus_per_node == 0: - val_step = writer_dict['valid_global_steps'] - writer.add_scalar("val_loss",epoch_loss_val.avg, val_step) - writer_dict['valid_global_steps'] = val_step + 1 - if semi_supervised: - print("Not Implement semi_supervised version for DDP") - raise NotImplementedError - if args.rank % ngpus_per_node == 0: - writer.add_scalar("loss_3d/valid", epoch_loss_3d_valid / N, epoch) - print("out of end-of-epoch evaluation loop.") - losses_3d_valid.append(epoch_loss_3d_valid / N) - if semi_supervised: - print("Not Implement semi_supervised version for DDP") - raise NotImplementedError - # losses_traj_valid.append(epoch_loss_traj_valid / N) - # losses_2d_valid.append(epoch_loss_2d_valid / N) - - - # Evaluate on training set, this time in evaluation mode - epoch_loss_3d_train_eval = 0 - # epoch_loss_traj_train_eval = 0 - # epoch_loss_2d_train_labeled_eval = 0 - N = 0 - for cam, batch, batch_2d in train_generator_eval.next_epoch(): - if batch_2d.shape[1] == 0: - # This can only happen when downsampling the dataset - continue - - inputs_3d = torch.from_numpy(batch.astype('float32')) - inputs_2d = torch.from_numpy(batch_2d.astype('float32')) - if torch.npu.is_available(): - inputs_3d = inputs_3d.npu() - inputs_2d = inputs_2d.npu() - inputs_traj = inputs_3d[:, :, :1].clone() - inputs_3d[:, :, 0] = 0 - - # Compute 3D poses - predicted_3d_pos = model_pos(inputs_2d) - loss_3d_pos = mpjpe(predicted_3d_pos, inputs_3d) - - dist.all_reduce(loss_3d_pos) - loss_3d_pos = loss_3d_pos / ngpus_per_node - epoch_loss_3d_train_eval += inputs_3d.shape[0]*inputs_3d.shape[1] * loss_3d_pos.item() - N += inputs_3d.shape[0]*inputs_3d.shape[1] - - if semi_supervised: - print("Not Implement semi_supervised version for DDP") - raise NotImplementedError - - if args.rank % ngpus_per_node == 0: - writer.add_scalar('loss_3d/train_eval', epoch_loss_3d_train_eval / N, epoch) - losses_3d_train_eval.append(epoch_loss_3d_train_eval / N) - if semi_supervised: - print("Not Implement semi_supervised version for DDP") - raise NotImplementedError - # losses_traj_train_eval.append(epoch_loss_traj_train_eval / N) - # losses_2d_train_labeled_eval.append(epoch_loss_2d_train_labeled_eval / N) - - # Evaluate 2D loss on unlabeled training set (in evaluation mode) - epoch_loss_2d_train_unlabeled_eval = 0 - N_semi = 0 - if semi_supervised: - print("Not Implement semi_supervised version for DDP") - raise NotImplementedError - - elapsed = (time() - start_time)/60 - - if args.rank % ngpus_per_node == 0: - if args.no_eval: - logger.info('[%d] time %.2f lr %f 3d_train %f FPS %d' % ( - epoch + 1, - elapsed, - lr, - losses_3d_train[-1] * 1000, - int(epoch_fps.avg))) - else: - if semi_supervised: - print("Not Implement semi_supervised version for DDP") - raise NotImplementedError - else: - logger.info('[%d] time %.2f lr %f 3d_train %f 3d_eval %f 3d_valid %f FPS %d' % ( - epoch + 1, - elapsed, - lr, - losses_3d_train[-1] * 1000, - losses_3d_train_eval[-1] * 1000, - losses_3d_valid[-1] *1000, - int(epoch_fps.avg)) - ) - - # Decay learning rate exponentially - lr *= lr_decay - for param_group in optimizer.param_groups: - param_group['lr'] *= lr_decay - epoch += 1 - - # Decay BatchNorm momentum - momentum = initial_momentum * np.exp(-epoch/args.epochs * np.log(initial_momentum/final_momentum)) - model_pos_train.module.set_bn_momentum(momentum) - if semi_supervised: - print("Not Implement semi_supervised version for DDP") - raise NotImplementedError - # model_traj_train.set_bn_momentum(momentum) - - # Save best valid - if args.no_eval: - valid = 0 - else: - valid = losses_3d_valid[-1] *1000 - if args.rank % ngpus_per_node == 0 and valid < best_valid: - best_valid = valid - bst_path = os.path.join(args.checkpoint, 'model_best.bin') - logger.info(f'Saving best model up to epoch:{epoch} to {bst_path}') - torch.save({ - 'model_pos':model_pos_train.state_dict() - }, bst_path) - - # Save checkpoint if necessary - if epoch % args.checkpoint_frequency == 0 and args.rank % ngpus_per_node == 0: - chk_path = os.path.join(args.checkpoint, 'epoch_{}.bin'.format(epoch)) - logger.info(f'Saving checkpoint to {chk_path}') - - torch.save({ - 'epoch': epoch, - 'lr': lr, - # 'random_state': train_generator.random_state(), - 'optimizer': optimizer.state_dict(), - 'model_pos': model_pos_train.state_dict(), - # 'model_traj': None, # model_traj_train.state_dict() if semi_supervised else None, - 'amp': amp.state_dict() if args.apex else None, - 'random_state_semi': None, #semi_generator.random_state() if semi_supervised else None, - 'train_global_steps': writer_dict['train_global_steps'], - 'valid_global_steps': writer_dict['valid_global_steps'] - }, chk_path) - - - # Save training curves after every epoch, as .png images (if requested) - if args.export_training_curves and epoch > 3 and args.rank % ngpus_per_node == 0: - if 'matplotlib' not in sys.modules: - import matplotlib - matplotlib.use('Agg') - import matplotlib.pyplot as plt - - plt.figure() - epoch_x = np.arange(3, len(losses_3d_train)) + 1 - plt.plot(epoch_x, losses_3d_train[3:], '--', color='C0') - plt.plot(epoch_x, losses_3d_train_eval[3:], color='C0') - plt.plot(epoch_x, losses_3d_valid[3:], color='C1') - plt.legend(['3d train', '3d train (eval)', '3d valid (eval)']) - plt.ylabel('MPJPE (m)') - plt.xlabel('Epoch') - plt.xlim((3, epoch)) - plt.savefig(os.path.join(args.checkpoint, 'loss_3d.png')) - - if semi_supervised: - print("Not Implement semi_supervised version for DDP") - raise NotImplementedError - plt.close('all') - - mytime.update(time()-myend) - myend = time() - if args.rank % ngpus_per_node == 0: - print(f"In average, it takes {time_format_convert(mytime.avg)} per epoch.") - print(f"Time has elapsed {time_format_convert(mytime.sum)}") - print(f"It still need {time_format_convert(mytime.avg*(args.epochs-epoch))}") - print("****************************************************************************") - if args.rank % ngpus_per_node == 0: - writer_dict['writer'].close() - # Evaluate - if args.evaluate: - logger.info('Evaluating...') - # chk_filename = os.path.join(args.checkpoint, 'model_best.bin') - # if (not args.evaluate) and (os.path.exists(chk_filename)): - # checkpoint = torch.load(chk_filename, map_location='cpu') - # model_pos.load_state_dict(checkpoint['model_pos']) - all_actions = {} - all_actions_by_subject = {} - for subject in subjects_test: - if subject not in all_actions_by_subject: - all_actions_by_subject[subject] = {} - - for action in dataset[subject].keys(): - action_name = action.split(' ')[0] - if action_name not in all_actions: - all_actions[action_name] = [] - if action_name not in all_actions_by_subject[subject]: - all_actions_by_subject[subject][action_name] = [] - all_actions[action_name].append((subject, action)) - all_actions_by_subject[subject][action_name].append((subject, action)) - - if not args.by_subject: - run_evaluation(args, all_actions, model_pos, None, keypoints, dataset, pad, causal_shift, kps_left, kps_right, joints_left, joints_right, action_filter) - else: - for subject in all_actions_by_subject.keys(): - if args.rank % ngpus_per_node == 0: - print('Evaluating on subject', subject) - run_evaluation(args, all_actions_by_subject[subject], model_pos, None, keypoints, dataset, pad, causal_shift, kps_left, kps_right, joints_left, joints_right, action_filter) - if args.rank % ngpus_per_node == 0: - print('') - dist.destroy_process_group() - -if __name__ == "__main__": - main() +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ + +# Copyright (c) 2018-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + + +import numpy as np + +from common.arguments import parse_args +import torch + +import torch.nn as nn +import torch.nn.functional as F +import torch.optim as optim +import torch.distributed as dist +import torch.multiprocessing as mp +import os +import sys +import errno +import math +import logging + +from common.camera import * +from common.model import * +from common.loss import * +from common.generators import ChunkedGenerator, UnchunkedGenerator +from time import time +from common.utils import deterministic_random, fetch, run_evaluation +from common.structure import AverageMeter, time_format_convert, device_id_to_process_device_map + +from tensorboardX import SummaryWriter +from apex import amp +# from apex.optimizers import NpuFusedAdam + + +def main(): + args = parse_args() + # print(args) + + try: + # Create checkpoint directory if it does not exist + os.makedirs(args.checkpoint) + except OSError as e: + if e.errno != errno.EEXIST: + raise RuntimeError('Unable to create checkpoint directory:', args.checkpoint) + + if not os.path.exists(args.output): + os.makedirs(args.output) + print(f"args.output:{args.output}") + + os.environ['MASTER_ADDR'] = '127.0.0.1' + os.environ['MASTER_PORT'] = '27005' + + process_device_map = device_id_to_process_device_map(args.device_list) + + if args.device == 'npu': + ngpus_per_node = len(process_device_map) + else: + ngpus_per_node = args.num_gpus + + args.num_gpus = ngpus_per_node + args.world_size = args.world_size * ngpus_per_node + + # npu = int(os.environ['RANK_ID']) + mp.spawn(main_worker, nprocs=ngpus_per_node, args=(ngpus_per_node, args)) + + +def setup_logger(final_output_dir, rank, phase): + # time_str = time.strftime('%Y-%m-%d-%H-%M') + log_file = '{}_rank{}.log'.format(phase, rank) + final_log_file = os.path.join(final_output_dir, log_file) + head = '%(asctime)-15s %(message)s' + # logging.basicConfig(format=head) + logging.basicConfig(filename=str(final_log_file), + format=head) + logger = logging.getLogger() + logger.setLevel(logging.INFO) + console = logging.StreamHandler() + logging.getLogger('').addHandler(console) + + return logger + + +def main_worker(gpu, ngpus_per_node, args): + process_device_map = device_id_to_process_device_map(args.device_list) + log_dir = args.output + logger = setup_logger(log_dir, gpu, 'train') + + # args.gpu = gpu + args.gpu = process_device_map[gpu] + # logger.info(f"args.gpu is {args.gpu}") + + args.rank = args.rank * ngpus_per_node + gpu + + # print(f'args.print_feq:{args.print_feq}') + if args.rank % ngpus_per_node == 0: + log_path = args.log + writer_dict = { + 'writer': SummaryWriter(logdir=log_path), + 'train_global_steps': 0, + 'valid_global_steps': 0, + } + + if args.device == 'npu': + print("args.rank:",args.rank) + dist.init_process_group(backend=args.dist_backend, # init_method=args.dist_url, + world_size=args.world_size, rank=args.rank) + else: + dist.init_process_group(backend='nccl', init_method=args.dist_url, + world_size=args.world_size, rank=args.rank) + + logger.info(f'Loading dataset for rank:{args.rank}...') + dataset_path = 'data/data_3d_' + args.dataset + '.npz' + if args.dataset == 'h36m': + from common.h36m_dataset import Human36mDataset + dataset = Human36mDataset(dataset_path) + elif args.dataset.startswith('humaneva'): + from common.humaneva_dataset import HumanEvaDataset + dataset = HumanEvaDataset(dataset_path) + elif args.dataset.startswith('custom'): + from common.custom_dataset import CustomDataset + dataset = CustomDataset('data/data_2d_' + args.dataset + '_' + args.keypoints + '.npz') + else: + raise KeyError('Invalid dataset') + + logger.info(f'Preparing data for rank:{args.rank}...') + for subject in dataset.subjects(): + for action in dataset[subject].keys(): + anim = dataset[subject][action] + + if 'positions' in anim: + positions_3d = [] + for cam in anim['cameras']: + pos_3d = world_to_camera(anim['positions'], R=cam['orientation'], t=cam['translation']) + pos_3d[:, 1:] -= pos_3d[:, :1] # Remove global offset, but keep trajectory in first position + positions_3d.append(pos_3d) + anim['positions_3d'] = positions_3d + + logger.info(f'Loading 2D detections for rank:{args.rank}...') + keypoints = np.load('data/data_2d_' + args.dataset + '_' + args.keypoints + '.npz', allow_pickle=True) + keypoints_metadata = keypoints['metadata'].item() + keypoints_symmetry = keypoints_metadata['keypoints_symmetry'] + kps_left, kps_right = list(keypoints_symmetry[0]), list(keypoints_symmetry[1]) + joints_left, joints_right = list(dataset.skeleton().joints_left()), list(dataset.skeleton().joints_right()) + keypoints = keypoints['positions_2d'].item() + + for subject in dataset.subjects(): + assert subject in keypoints, 'Subject {} is missing from the 2D detections dataset'.format(subject) + for action in dataset[subject].keys(): + assert action in keypoints[subject], 'Action {} of subject {} is missing from the 2D detections dataset'.format(action, subject) + if 'positions_3d' not in dataset[subject][action]: + continue + + for cam_idx in range(len(keypoints[subject][action])): + + # We check for >= instead of == because some videos in H3.6M contain extra frames + mocap_length = dataset[subject][action]['positions_3d'][cam_idx].shape[0] + assert keypoints[subject][action][cam_idx].shape[0] >= mocap_length + + if keypoints[subject][action][cam_idx].shape[0] > mocap_length: + # Shorten sequence + keypoints[subject][action][cam_idx] = keypoints[subject][action][cam_idx][:mocap_length] + + assert len(keypoints[subject][action]) == len(dataset[subject][action]['positions_3d']) + + for subject in keypoints.keys(): + for action in keypoints[subject]: + for cam_idx, kps in enumerate(keypoints[subject][action]): + # Normalize camera frame + cam = dataset.cameras()[subject][cam_idx] + kps[..., :2] = normalize_screen_coordinates(kps[..., :2], w=cam['res_w'], h=cam['res_h']) + keypoints[subject][action][cam_idx] = kps + + subjects_train = args.subjects_train.split(',') + subjects_semi = [] if not args.subjects_unlabeled else args.subjects_unlabeled.split(',') + if not args.render: + subjects_test = args.subjects_test.split(',') + else: + subjects_test = [args.viz_subject] + + semi_supervised = len(subjects_semi) > 0 + if semi_supervised and not dataset.supports_semi_supervised(): + raise RuntimeError('Semi-supervised training is not implemented for this dataset') + + # moved fatch to utils.py + + action_filter = None if args.actions == '*' else args.actions.split(',') + if action_filter is not None: + print('Selected actions:', action_filter) + + cameras_valid, poses_valid, poses_valid_2d = fetch(subjects_test, keypoints=keypoints, dataset=dataset, args=args ,action_filter=action_filter) + + filter_widths = [int(x) for x in args.architecture.split(',')] + if not args.disable_optimizations and not args.dense and args.stride == 1: + # Use optimized model for single-frame predictions + model_pos_train = TemporalModelOptimized1f(poses_valid_2d[0].shape[-2], poses_valid_2d[0].shape[-1], dataset.skeleton().num_joints(), + filter_widths=filter_widths, causal=args.causal, dropout=args.dropout, channels=args.channels) + else: + # When incompatible settings are detected (stride > 1, dense filters, or disabled optimization) fall back to normal model + model_pos_train = TemporalModel(poses_valid_2d[0].shape[-2], poses_valid_2d[0].shape[-1], dataset.skeleton().num_joints(), + filter_widths=filter_widths, causal=args.causal, dropout=args.dropout, channels=args.channels, + dense=args.dense) + + model_pos = TemporalModel(poses_valid_2d[0].shape[-2], poses_valid_2d[0].shape[-1], dataset.skeleton().num_joints(), + filter_widths=filter_widths, causal=args.causal, dropout=args.dropout, channels=args.channels, + dense=args.dense) + + receptive_field = model_pos.receptive_field() + logger.info('INFO: Receptive field: {} frames'.format(receptive_field)) + pad = (receptive_field - 1) // 2 # Padding on each side + if args.causal: + logger.info('INFO: Using causal convolutions') + causal_shift = pad + else: + causal_shift = 0 + + model_params = 0 + for parameter in model_pos.parameters(): + model_params += parameter.numel() + print('INFO: Trainable parameter count:', model_params) + + assert args.gpu is not None, "Something wrong about args.gpu, it shouldn't be None." + + if not torch.npu.is_available(): + print("We only implemented for GPUs") + raise NotImplementedError + else: + loc = f'npu:{args.gpu}' + torch.npu.set_device(loc) + model_pos = model_pos.to(loc) + model_pos_train = model_pos_train.to(loc) + model_pos = torch.nn.parallel.DistributedDataParallel(model_pos, device_ids=[args.gpu], broadcast_buffers=False) + + + + if args.evaluate: + assert args.resume is '' + chk_filename = os.path.join(args.checkpoint, args.evaluate) + logger.info(f'Loading checkpoint {chk_filename}') + checkpoint = torch.load(chk_filename, map_location=lambda storage, loc: storage) + model_pos.load_state_dict(checkpoint['model_pos']) + model_traj = None + + + test_generator = UnchunkedGenerator(args, cameras_valid, poses_valid, poses_valid_2d, + pad=pad, causal_shift=causal_shift, augment=False, + kps_left=kps_left, kps_right=kps_right, joints_left=joints_left, joints_right=joints_right) + logger.info('INFO: Testing on {} frames'.format(test_generator.num_frames())) + + if not args.evaluate: + cameras_train, poses_train, poses_train_2d = fetch(subjects_train, keypoints=keypoints, dataset=dataset, args=args, action_filter=action_filter, subset=args.subset) + + lr = args.learning_rate + if args.rank % args.num_gpus == 0: + logger.info(f"inital learning rate is:{lr}") + if semi_supervised: + print("Not Implement semi_supervised version for DDP") + raise NotImplementedError + else: + optimizer = optim.Adam(model_pos_train.parameters(), lr=lr) #, amsgrad=True) + # optimizer = NpuFusedAdam(model_pos_train.parameters(), lr=lr) + print(f"Use Apex:{args.apex}") + print(f"Sampler:{args.sampler}") + if args.apex: + model_pos_train, optimizer = amp.initialize(model_pos_train, optimizer, opt_level="O1", loss_scale=128.0) #, combine_grad=True) + model_pos_train = torch.nn.parallel.DistributedDataParallel(model_pos_train, device_ids=[args.gpu], broadcast_buffers=False) + + lr_decay = args.lr_decay + + losses_3d_train = [] + losses_3d_train_eval = [] + losses_3d_valid = [] + + epoch = 0 + initial_momentum = 0.1 + final_momentum = 0.001 + + + train_generator = ChunkedGenerator(args, args.batch_size//args.stride, cameras_train, poses_train, poses_train_2d, args.stride, + pad=pad, causal_shift=causal_shift, shuffle=True, random_seed=args.random_seed, augment=args.data_augmentation, + kps_left=kps_left, kps_right=kps_right, joints_left=joints_left, joints_right=joints_right) + train_generator_eval = UnchunkedGenerator(args, cameras_train, poses_train, poses_train_2d, + pad=pad, causal_shift=causal_shift, augment=False) + print('INFO: Training on {} frames'.format(train_generator_eval.num_frames())) + if semi_supervised: + print("Not Implement semi_supervised version for DDP") + raise NotImplementedError + + if args.resume: + chk_filename = os.path.join(args.checkpoint, args.resume) + print("resuming the training...") + print('Loading checkpoint', chk_filename) + checkpoint = torch.load(chk_filename, map_location=loc) + epoch = checkpoint['epoch'] + model_pos_train.load_state_dict(checkpoint['model_pos']) + if 'optimizer' in checkpoint and checkpoint['optimizer'] is not None: + optimizer.load_state_dict(checkpoint['optimizer']) + # train_generator.set_random_state(checkpoint['random_state']) + else: + print('WARNING: this checkpoint does not contain an optimizer state. The optimizer will be reinitialized.') + if checkpoint['amp'] is not None: + amp.load_state_dict(checkpoint['amp']) + if args.rank % ngpus_per_node == 0: + if 'train_global_steps' in checkpoint and 'valid_global_steps' in checkpoint: + writer_dict['train_global_steps'] = checkpoint['train_global_steps'] + writer_dict['valid_global_steps'] = checkpoint['valid_global_steps'] + lr = checkpoint['lr'] + if semi_supervised: + print("Not Implement semi_supervised version for DDP") + raise NotImplementedError + # model_traj_train.load_state_dict(checkpoint['model_traj']) + # model_traj.load_state_dict(checkpoint['model_traj']) + # semi_generator.set_random_state(checkpoint['random_state_semi']) + + logger.info('** Note: reported losses are averaged over all frames and test-time augmentation is not used here.') + logger.info('** The final evaluation will be carried out after the last training epoch.') + + myend = time() + mytime = AverageMeter() + best_valid = 50.0 + prof_flag = args.prof + while epoch < args.epochs: + start_time = time() + epoch_loss = AverageMeter() + epoch_loss_val = AverageMeter() + train_generator.set_epoch(epoch) + epoch_loss_3d_train = 0 + # epoch_loss_traj_train = 0 + # epoch_loss_2d_train_unlabeled = 0 + epoch_fps = AverageMeter() + N = 0 + N_semi = 0 + model_pos_train.train() + if semi_supervised: + print("Not Implement semi_supervised version for DDP") + raise NotImplementedError + else: + # Regular supervised scenario + count = 0 + for _, batch_3d, batch_2d in train_generator.next_epoch(): + if count >= 2: + my_epoch_start = time() + if batch_2d.shape[0] == 0: + continue + # print(f"batch_3d.shape:{batch_3d.shape} for rank:{args.rank}") + bz = batch_2d.shape[0] + assert batch_3d.shape[0] == bz + inputs_3d = torch.from_numpy(batch_3d.astype('float32')) + inputs_2d = torch.from_numpy(batch_2d.astype('float32')) + if torch.npu.is_available(): + inputs_3d = inputs_3d.to(loc, non_blocking=False) + inputs_2d = inputs_2d.to(loc, non_blocking=False) + inputs_3d[:, :, 0] = 0 + + if prof_flag and count==10 and args.rank==0: + with torch.autograd.profiler.profile(use_npu=True) as prof: + optimizer.zero_grad() + + # Predict 3D poses + predicted_3d_pos = model_pos_train(inputs_2d) + loss_3d_pos = mpjpe(predicted_3d_pos, inputs_3d) + + loss_total = loss_3d_pos + if args.apex: + with amp.scale_loss(loss_total, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss_total.backward() + + optimizer.step() + print(prof.key_averages().table(sort_by='self_cpu_time_total')) + prof.export_chrome_trace(os.path.join(args.checkpoint,'out.prof')) + prof_flag = False + print(f"prof has been saved as {os.path.join(args.checkpoint,'out.prof')}") + else: + optimizer.zero_grad() + + # Predict 3D poses + predicted_3d_pos = model_pos_train(inputs_2d) + loss_3d_pos = mpjpe(predicted_3d_pos, inputs_3d) + + loss_total = loss_3d_pos + if args.apex: + with amp.scale_loss(loss_total, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss_total.backward() + + optimizer.step() + + dist.all_reduce(loss_total) + loss_total = loss_total / ngpus_per_node + epoch_loss.update(loss_total.item(), bz) + + epoch_loss_3d_train += inputs_3d.shape[0]*inputs_3d.shape[1] * loss_total.item() + N += inputs_3d.shape[0]*inputs_3d.shape[1] + + if count >= 2: + batch_time = time()-my_epoch_start + fps = bz * ngpus_per_node / batch_time + epoch_fps.update(fps) + if args.rank % ngpus_per_node == 0: + writer = writer_dict['writer'] + train_step = writer_dict['train_global_steps'] + writer.add_scalar('total_loss',epoch_loss.avg,train_step) + writer_dict['train_global_steps'] = train_step + 1 + + + if count % args.print_freq == 0 and args.rank % ngpus_per_node == 0: + logger.info("({batch}/{size})| loss:{loss.val:.5f} ({loss.avg:.5f})| FPS:{fps.val:.3f} ({fps.avg:.3f})".format( + batch=count, size=math.ceil(train_generator.num_frames()/(args.batch_size*ngpus_per_node)), loss=epoch_loss, + fps=epoch_fps + )) + count +=1 + if args.rank % ngpus_per_node == 0: + writer.add_scalar('loss_3d/train', epoch_loss_3d_train / N, epoch) + + losses_3d_train.append(epoch_loss_3d_train / N) + + + # End-of-epoch evaluation + if args.rank == 0 and not args.no_eval: + print("End of epoch evaluation start ....") + with torch.no_grad(): + model_pos.load_state_dict(model_pos_train.state_dict()) + model_pos.eval() + if semi_supervised: + print("Not Implement semi_supervised version for DDP") + raise NotImplementedError + # model_traj.load_state_dict(model_traj_train.state_dict()) + # model_traj.eval() + + epoch_loss_3d_valid = 0 + epoch_loss_traj_valid = 0 + epoch_loss_2d_valid = 0 + N = 0 + + if not args.no_eval: + # Evaluate on test set + for cam, batch, batch_2d in test_generator.next_epoch(): + inputs_3d = torch.from_numpy(batch.astype('float32')) + inputs_2d = torch.from_numpy(batch_2d.astype('float32')) + if torch.npu.is_available(): + inputs_3d = inputs_3d.to(loc, non_blocking=False) + inputs_2d = inputs_2d.to(loc, non_blocking=False) + inputs_traj = inputs_3d[:, :, :1].clone() + inputs_3d[:, :, 0] = 0 + + # Predict 3D poses + predicted_3d_pos = model_pos(inputs_2d) + loss_3d_pos = mpjpe(predicted_3d_pos, inputs_3d) + + bz = inputs_2d.shape[0] + assert bz == inputs_3d.shape[0] + + dist.all_reduce(loss_3d_pos) + loss_3d_pos = loss_3d_pos / ngpus_per_node + + epoch_loss_val.update(loss_3d_pos, bz) + + epoch_loss_3d_valid += inputs_3d.shape[0]*inputs_3d.shape[1] * loss_3d_pos.item() + N += inputs_3d.shape[0]*inputs_3d.shape[1] + + if args.rank % ngpus_per_node == 0: + val_step = writer_dict['valid_global_steps'] + writer.add_scalar("val_loss",epoch_loss_val.avg, val_step) + writer_dict['valid_global_steps'] = val_step + 1 + if semi_supervised: + print("Not Implement semi_supervised version for DDP") + raise NotImplementedError + if args.rank % ngpus_per_node == 0: + writer.add_scalar("loss_3d/valid", epoch_loss_3d_valid / N, epoch) + print("out of end-of-epoch evaluation loop.") + losses_3d_valid.append(epoch_loss_3d_valid / N) + if semi_supervised: + print("Not Implement semi_supervised version for DDP") + raise NotImplementedError + # losses_traj_valid.append(epoch_loss_traj_valid / N) + # losses_2d_valid.append(epoch_loss_2d_valid / N) + + + # Evaluate on training set, this time in evaluation mode + epoch_loss_3d_train_eval = 0 + # epoch_loss_traj_train_eval = 0 + # epoch_loss_2d_train_labeled_eval = 0 + N = 0 + for cam, batch, batch_2d in train_generator_eval.next_epoch(): + if batch_2d.shape[1] == 0: + # This can only happen when downsampling the dataset + continue + + inputs_3d = torch.from_numpy(batch.astype('float32')) + inputs_2d = torch.from_numpy(batch_2d.astype('float32')) + if torch.npu.is_available(): + inputs_3d = inputs_3d.npu() + inputs_2d = inputs_2d.npu() + inputs_traj = inputs_3d[:, :, :1].clone() + inputs_3d[:, :, 0] = 0 + + # Compute 3D poses + predicted_3d_pos = model_pos(inputs_2d) + loss_3d_pos = mpjpe(predicted_3d_pos, inputs_3d) + + dist.all_reduce(loss_3d_pos) + loss_3d_pos = loss_3d_pos / ngpus_per_node + epoch_loss_3d_train_eval += inputs_3d.shape[0]*inputs_3d.shape[1] * loss_3d_pos.item() + N += inputs_3d.shape[0]*inputs_3d.shape[1] + + if semi_supervised: + print("Not Implement semi_supervised version for DDP") + raise NotImplementedError + + if args.rank % ngpus_per_node == 0: + writer.add_scalar('loss_3d/train_eval', epoch_loss_3d_train_eval / N, epoch) + losses_3d_train_eval.append(epoch_loss_3d_train_eval / N) + if semi_supervised: + print("Not Implement semi_supervised version for DDP") + raise NotImplementedError + # losses_traj_train_eval.append(epoch_loss_traj_train_eval / N) + # losses_2d_train_labeled_eval.append(epoch_loss_2d_train_labeled_eval / N) + + # Evaluate 2D loss on unlabeled training set (in evaluation mode) + epoch_loss_2d_train_unlabeled_eval = 0 + N_semi = 0 + if semi_supervised: + print("Not Implement semi_supervised version for DDP") + raise NotImplementedError + + elapsed = (time() - start_time)/60 + + if args.rank % ngpus_per_node == 0: + if args.no_eval: + logger.info('[%d] time %.2f lr %f 3d_train %f FPS %d' % ( + epoch + 1, + elapsed, + lr, + losses_3d_train[-1] * 1000, + int(epoch_fps.avg))) + else: + if semi_supervised: + print("Not Implement semi_supervised version for DDP") + raise NotImplementedError + else: + logger.info('[%d] time %.2f lr %f 3d_train %f 3d_eval %f 3d_valid %f FPS %d' % ( + epoch + 1, + elapsed, + lr, + losses_3d_train[-1] * 1000, + losses_3d_train_eval[-1] * 1000, + losses_3d_valid[-1] *1000, + int(epoch_fps.avg)) + ) + + # Decay learning rate exponentially + lr *= lr_decay + for param_group in optimizer.param_groups: + param_group['lr'] *= lr_decay + epoch += 1 + + # Decay BatchNorm momentum + momentum = initial_momentum * np.exp(-epoch/args.epochs * np.log(initial_momentum/final_momentum)) + model_pos_train.module.set_bn_momentum(momentum) + if semi_supervised: + print("Not Implement semi_supervised version for DDP") + raise NotImplementedError + # model_traj_train.set_bn_momentum(momentum) + + # Save best valid + if args.no_eval: + valid = 0 + else: + valid = losses_3d_valid[-1] *1000 + if args.rank % ngpus_per_node == 0 and valid < best_valid: + best_valid = valid + bst_path = os.path.join(args.checkpoint, 'model_best.bin') + logger.info(f'Saving best model up to epoch:{epoch} to {bst_path}') + torch.save({ + 'model_pos':model_pos_train.state_dict() + }, bst_path) + + # Save checkpoint if necessary + if epoch % args.checkpoint_frequency == 0 and args.rank % ngpus_per_node == 0: + chk_path = os.path.join(args.checkpoint, 'epoch_{}.bin'.format(epoch)) + logger.info(f'Saving checkpoint to {chk_path}') + + torch.save({ + 'epoch': epoch, + 'lr': lr, + # 'random_state': train_generator.random_state(), + 'optimizer': optimizer.state_dict(), + 'model_pos': model_pos_train.state_dict(), + # 'model_traj': None, # model_traj_train.state_dict() if semi_supervised else None, + 'amp': amp.state_dict() if args.apex else None, + 'random_state_semi': None, #semi_generator.random_state() if semi_supervised else None, + 'train_global_steps': writer_dict['train_global_steps'], + 'valid_global_steps': writer_dict['valid_global_steps'] + }, chk_path) + + + # Save training curves after every epoch, as .png images (if requested) + if args.export_training_curves and epoch > 3 and args.rank % ngpus_per_node == 0: + if 'matplotlib' not in sys.modules: + import matplotlib + matplotlib.use('Agg') + import matplotlib.pyplot as plt + + plt.figure() + epoch_x = np.arange(3, len(losses_3d_train)) + 1 + plt.plot(epoch_x, losses_3d_train[3:], '--', color='C0') + plt.plot(epoch_x, losses_3d_train_eval[3:], color='C0') + plt.plot(epoch_x, losses_3d_valid[3:], color='C1') + plt.legend(['3d train', '3d train (eval)', '3d valid (eval)']) + plt.ylabel('MPJPE (m)') + plt.xlabel('Epoch') + plt.xlim((3, epoch)) + plt.savefig(os.path.join(args.checkpoint, 'loss_3d.png')) + + if semi_supervised: + print("Not Implement semi_supervised version for DDP") + raise NotImplementedError + plt.close('all') + + mytime.update(time()-myend) + myend = time() + if args.rank % ngpus_per_node == 0: + print(f"In average, it takes {time_format_convert(mytime.avg)} per epoch.") + print(f"Time has elapsed {time_format_convert(mytime.sum)}") + print(f"It still need {time_format_convert(mytime.avg*(args.epochs-epoch))}") + print("****************************************************************************") + if args.rank % ngpus_per_node == 0: + writer_dict['writer'].close() + # Evaluate + if args.evaluate: + logger.info('Evaluating...') + # chk_filename = os.path.join(args.checkpoint, 'model_best.bin') + # if (not args.evaluate) and (os.path.exists(chk_filename)): + # checkpoint = torch.load(chk_filename, map_location='cpu') + # model_pos.load_state_dict(checkpoint['model_pos']) + all_actions = {} + all_actions_by_subject = {} + for subject in subjects_test: + if subject not in all_actions_by_subject: + all_actions_by_subject[subject] = {} + + for action in dataset[subject].keys(): + action_name = action.split(' ')[0] + if action_name not in all_actions: + all_actions[action_name] = [] + if action_name not in all_actions_by_subject[subject]: + all_actions_by_subject[subject][action_name] = [] + all_actions[action_name].append((subject, action)) + all_actions_by_subject[subject][action_name].append((subject, action)) + + if not args.by_subject: + run_evaluation(args, all_actions, model_pos, None, keypoints, dataset, pad, causal_shift, kps_left, kps_right, joints_left, joints_right, action_filter) + else: + for subject in all_actions_by_subject.keys(): + if args.rank % ngpus_per_node == 0: + print('Evaluating on subject', subject) + run_evaluation(args, all_actions_by_subject[subject], model_pos, None, keypoints, dataset, pad, causal_shift, kps_left, kps_right, joints_left, joints_right, action_filter) + if args.rank % ngpus_per_node == 0: + print('') + dist.destroy_process_group() + +if __name__ == "__main__": + main() diff --git a/PyTorch/contrib/cv/video/VideoPose3D/test/eval_full_8p.sh b/PyTorch/contrib/cv/video/VideoPose3D/test/eval_full_8p.sh index bd38f9fdc5..5c6235ba8c 100644 --- a/PyTorch/contrib/cv/video/VideoPose3D/test/eval_full_8p.sh +++ b/PyTorch/contrib/cv/video/VideoPose3D/test/eval_full_8p.sh @@ -1,100 +1,100 @@ -#!/bin/sh - -source /usr/local/Ascend/ascend-toolkit/set_env.sh -export HCCL_WHITELIST_DISABLE=1 -export ASCEND_SLOG_PRINT_TO_STDOUT=1 -export ASCEND_GLOBAL_LOG_LEVEL=3 -export ASCEND_GLOBAL_EVENT_ENABLE=0 -export PTCOPY_ENABLE=1 - -################ Basic Training Settings ################## -# "Must Have" Settings: Network batch_size RANK_SIZE -# Network Name, the same with dir -Network="VideoPose3D" -# training batch_size per GPU -batch_size=8192 -# num of NPUs -export RANK_SIZE=8 -# train epochs -# train_epochs=80 - -############# Specify Training Directory ############# -cur_path=`pwd` -cur_path_last_diename=${cur_path##*/} -if [ x"${cur_path_last_diename}" == x"test" ];then - test_path_dir=${cur_path} - cd .. - cur_path=`pwd` -else - test_path_dir=${cur_path}/test -fi - -############# Create Log output directory ############## -ASCEND_DEVICE_ID=0 -if [ -d ${test_path_dir}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${test_path_dir}/output/${ASCEND_DEVICE_ID} - mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID -else - mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID -fi - -#################### Start Training ################# -# start time, no modification needed -start_time=$(date +%s) - -python run.py \ - -k cpn_ft_h36m_dbb \ - -arc 3,3,3,3,3 \ - -c checkpoint/8p_lr2.2e-3 \ - -o test/output/8p_lr2.2e-3_eval \ - --evaluate model_best.bin & -wait - -################# Gain Training Data #################### -# end training time, no modification needed -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -# print results, no modification needed -echo "------------------ Final result ------------------" -# output FPS -FPS=`grep -a 'FPS' ${test_path_dir}/output/8p_lr2.2e-3/train_rank0.log|awk -F " " '{print $15}'|awk 'END {print}'` -# print -echo "Final Performance images/sec : $FPS" - -# train-accuracy -acc=`grep -a 'Protocol #1' ${test_path_dir}/output/8p_lr2.2e-3_eval/train_rank0.log|awk 'END {print}'|awk -F " " '{print $7}'` -# print -echo "Final Train Accuracy (mm) : ${acc:8:5}" -echo "E2E Eval Duration sec : $e2e_time" -train_accuracy=${acc:8:5} - -# Performance Summary -# Train-related information, no modification needed -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -## Acquire performance data -# Throughput -ActualFPS=${FPS} -# time of single loop -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -# Extract loss to train_${CaseName}_loss.txt -grep -a 'FPS' ${test_path_dir}/output/8p_lr2.2e-3/train_rank0.log|awk -F " " '{print $3,$4,$5}'|awk -F "loss:" '{print $NF}'|awk -F "time" '{print $1}'|awk -F "(" '{print $NF}'|awk -F ")" '{print $1}' >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -# loss from the last loop -ActualLoss=`awk -F: '{if($1!="[80] ")print}' ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt|awk 'END {print}'` - -# Key information print -echo "Network = ${Network}" > ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/sh + +source /usr/local/Ascend/ascend-toolkit/set_env.sh +export HCCL_WHITELIST_DISABLE=1 +export ASCEND_SLOG_PRINT_TO_STDOUT=1 +export ASCEND_GLOBAL_LOG_LEVEL=3 +export ASCEND_GLOBAL_EVENT_ENABLE=0 +export PTCOPY_ENABLE=1 + +################ Basic Training Settings ################## +# "Must Have" Settings: Network batch_size RANK_SIZE +# Network Name, the same with dir +Network="VideoPose3D" +# training batch_size per GPU +batch_size=8192 +# num of NPUs +export RANK_SIZE=8 +# train epochs +# train_epochs=80 + +############# Specify Training Directory ############# +cur_path=`pwd` +cur_path_last_diename=${cur_path##*/} +if [ x"${cur_path_last_diename}" == x"test" ];then + test_path_dir=${cur_path} + cd .. + cur_path=`pwd` +else + test_path_dir=${cur_path}/test +fi + +############# Create Log output directory ############## +ASCEND_DEVICE_ID=0 +if [ -d ${test_path_dir}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${test_path_dir}/output/${ASCEND_DEVICE_ID} + mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID +else + mkdir -p ${test_path_dir}/output/$ASCEND_DEVICE_ID +fi + +#################### Start Training ################# +# start time, no modification needed +start_time=$(date +%s) + +python run.py \ + -k cpn_ft_h36m_dbb \ + -arc 3,3,3,3,3 \ + -c checkpoint/8p_lr2.2e-3 \ + -o test/output/8p_lr2.2e-3_eval \ + --evaluate model_best.bin & +wait + +################# Gain Training Data #################### +# end training time, no modification needed +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +# print results, no modification needed +echo "------------------ Final result ------------------" +# output FPS +FPS=`grep -a 'FPS' ${test_path_dir}/output/8p_lr2.2e-3/train_rank0.log|awk -F " " '{print $15}'|awk 'END {print}'` +# print +echo "Final Performance images/sec : $FPS" + +# train-accuracy +acc=`grep -a 'Protocol #1' ${test_path_dir}/output/8p_lr2.2e-3_eval/train_rank0.log|awk 'END {print}'|awk -F " " '{print $7}'` +# print +echo "Final Train Accuracy (mm) : ${acc:8:5}" +echo "E2E Eval Duration sec : $e2e_time" +train_accuracy=${acc:8:5} + +# Performance Summary +# Train-related information, no modification needed +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +## Acquire performance data +# Throughput +ActualFPS=${FPS} +# time of single loop +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +# Extract loss to train_${CaseName}_loss.txt +grep -a 'FPS' ${test_path_dir}/output/8p_lr2.2e-3/train_rank0.log|awk -F " " '{print $3,$4,$5}'|awk -F "loss:" '{print $NF}'|awk -F "time" '{print $1}'|awk -F "(" '{print $NF}'|awk -F ")" '{print $1}' >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +# loss from the last loop +ActualLoss=`awk -F: '{if($1!="[80] ")print}' ${test_path_dir}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt|awk 'END {print}'` + +# Key information print +echo "Network = ${Network}" > ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log # echo "E2ETrainingTime = ${e2e_time}" >> ${test_path_dir}/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/contrib/cv/video/X3D/README.md b/PyTorch/contrib/cv/video/X3D/README.md index 6c0dcffc31..8e3949ec65 100644 --- a/PyTorch/contrib/cv/video/X3D/README.md +++ b/PyTorch/contrib/cv/video/X3D/README.md @@ -1,212 +1,212 @@ -# X3D-S - -Implements training of X3D-S on the Kinetics-400 dataset - -## Detail - -Most of codes are modified according to [here](https://gitee.com/ascend/modelzoo/wikis/Pytorch%E8%AE%AD%E7%BB%83%E6%8C%87%E5%AF%BC?sort_id=4208869#21-%E8%BF%81%E7%A7%BB%E6%B5%81%E7%A8%8B%E8%AF%B4%E6%98%8E) - -There are some special modification of [source repository](https://github.com/facebookresearch/SlowFast) : - -##### NPU & GPU - -- Add some customized yaml configuration items, such as APEX.ENABLE、DIST_BACKEND... -- Ascend-Pytorch-1.5 is not supported `torch.nn.init.trunc_normal` , using `torch.nn.init.normal_` instead -- Adjusted the order of dependency import to prevent some unknown bugs (`scikit-learn`) - -##### NPU - -- Group conv3D of Ascend-Pytorch is not supported, so we canceled all group operations in the model -- Remove some irrelevant codes to prevent some unknown bugs (`Segmentation fault (core dumped)`) - - -## Requirements - -##### Base Environment - -- Python == 3.7.5 -- GCC >= 4.9 - -##### Python Environment - -1. Installing these error-prone dependencies first: - -- PyTorch (raw==1.5 or ascend) - - Ascend-Pytorch Version after August 24 be installed -- torchvision == 0.6.0 - - If on Centos arm, please build the source code from [here](https://gitee.com/azureology/torchvision/tree/v0.6.0/) -- PyAV - - If the installation fails on Centos arm, following this [issue](https://gitee.com/ascend/modelzoo/issues/I48AP3?from=project-issue) -- Detectron2 - - According to the CUDA version and Pytorch version, build from [source code](https://github.com/facebookresearch/detectron2) - -2. Then, you can use `pip3 install -r requirements.txt` to install some simple dependencies - - - -3. Building source code - -```shell -cd X3D # into source code root - -# Switch to your prepared environment - -python3.7 setup.py build develop # build slowfast and install the remaining dependencies -``` - - - -##### Modify Ascend-tookit - -```shell -cd /usr/local -find / -name fractal_z_3d_2_ncdhw.py -vi path_to_fractal_z_3d_2_ncdhw.py - -located method: - 1. def fractal_z_3d_2_ncdhw(src, dst, src_format, dst_format,kernel_name="fractal_z_3d_2_ncdhw") - 2. modify it according this picture: - 2.1. remove `if list(dst_shape) in ....` - 2.2. Align the next two lines like this -``` - -![image-20210909203603647](meta\bug-opt.png) - - - -##### Dataset - -- Download the Kinetics-400 dataset from [here](https://github.com/PaddlePaddle/PaddleVideo/blob/develop/docs/zh-CN/dataset/k400.md) - - 1. unzip the all packages and merge all folders - - 2. we get two sets , train set (used to train) and val set (used to test). And each of both has 400 folders - - ```markdown - # format of data folder - - |-data - |-train - |- video type 1 - |- video 1 - |- video 2 - ... - |- video type 2 - ... - |- video type 400 - |-val - |- video type 1 - |- video type 2 - ... - |- video type 400 - ``` - - - - 3. build train.csv, val.csv, test.csv, and put them in the same folder - - ```markdown - # format of data path folder - |- data_path - |- train.csv - |- val.csv - |- test.csv - ``` - - train.csv consists of train set - - val.csv is same as test.csv, and consists of test set - - ```markdown - # format of data path csv is: - - path_to_video_1 label_1 - path_to_video_2 label_2 - ... - path_to_video_N label_N - ``` - - 4. check if the all videos are lossless according to the scripts provided by project [mmaction2](https://github.com/open-mmlab/mmaction2) . Here, we provide the [list](mytest\Vinput\error_video) of corrupted videos that have been checked out -5. remove the those corrupted videos from the three csv - -## Training - -To train a model, run `main.py` with the desired model architecture and the path to the ImageNet dataset: - -> Note:the `real_data_path` is path of csv folder mentioned above - -```bash -# training 1p (300 epoch) -bash ./test/train_full_1p.sh --data_path=real_data_path - -# training 8p (300 epoch) -bash ./test/train_full_8p.sh --data_path=real_data_path - -# training performance 1p (1 epoch) -bash ./test/train_performance_1p.sh --data_path=real_data_path - -# training performance 8p (3 epoch) -bash ./test/train_performance_8p.sh --data_path=real_data_path - -# testing 8p -bash test/train_eval_8p.sh --data_path=real_data_path --pth_path=real_pre_train_model_path - -# train_finetune_1p.sh -bash test/train_finetune_1p.sh --data_path=real_data_path --pth_path=real_pre_train_model_path --num_classes=default_400 -``` - -> Log path: ./stdout.log - - - -## Training Result - -> Due to the calculation cast a long time, we choose to run the full data, and the NPU-ACC is aligned with the GPU-ACC (as many epochs as possible). - - -| Device | FPS | Top1-ACC 10-view | Batch Size | Epochs | AMP | -| :-------------: | :-----: | :--------------: | :--------: | :----: | :------: | -| 1P-GPU | 10.39 | 6.67% | 96 | 1/300 | O2-128.0 | -| 1P-NPU | 5.38 | 6.18% | 96 | 1/300 | O2-128.0 | -| 1P-NPU-白名单 | 5.35 | 6.36% | 96 | 1/300 | O2-128.0 | -| 8P-GPU | 1137.49 | 37.56% | 256 | 30/300 | O2-128.0 | -| 8P-NPU | 529.24 | 39.67% | 256 | 30/300 | O2-128.0 | -| 8P-NPU-fusedSGD | 510.66 | 5.80% | 256 | 2/300 | O2-128.0 | - - - -- Testing result: Top1-ACC of 8P-NPU and 8P-GPU training (30 epochs) - -![img](meta\8P-GPU & 8P-NPU.png) - -## Performance Optimization - -According to the above, it can be concluded that the accuracy(Top1-ACC 10-view) of 8P-GPU and 8P-NPU is little different. But performance(FPS) of 8P-NPU is 50% of 8P-GPU's. - -So we made the following analysis and improvement: - -- find the dynamic operators following [here](https://gitee.com/wangjiangben_hw/ascend-pytorch-crowdintelligence-doc/blob/master/pytorch-train-guide/%E6%A8%A1%E5%9E%8B%E7%AE%97%E5%AD%90%E6%8F%90%E5%8F%96%E6%8C%87%E5%8D%97.md), but the operators is very basic, and we can not identify them from our big model. - -![img](meta\dynamic_ops.png) - -- check the profile of NPU through chrome tracing - - image-20210913190836215 - -- In order to improve the low perfomance of Transpose, we first generate the `cann profiling` following [here](https://gitee.com/wangjiangben_hw/ascend-pytorch-crowdintelligence-doc/blob/master/pytorch-train-guide/CANNProfiling%E5%B7%A5%E5%85%B7%E4%BD%BF%E7%94%A8%E6%8C%87%E5%AF%BC%E4%B9%A6.md), then we extract the two operators, TransposeD and TransData. - - if TransposeD `Consuming time > 10s`, add its Input Shapes to White List (/usr/local/Ascend/ascend-toolkit/5.0.2/x86_64-linux/opp/op_impl/built-in/ai_core/tbe/impl/dynamic/transpose.py) - - if TransData `Consuming time > 10s & Input Formats == 'NCHW' & Output Formats == 'NC1HWC0'`, add its Input Shapes to White List (/usr/local/Ascend/ascend-toolkit/5.0.2/x86_64-linux/opp/op_impl/built-in/ai_core/tbe/impl/four_2_five.py) - - if TransData `Consuming time > 10s & Input Formats == 'NC1HWC0' & Output Formats == 'NCHW'`, add its Input Shapes to White List (/usr/local/Ascend/ascend-toolkit/5.0.2/x86_64-linux/opp/op_impl/built-in/ai_core/tbe/impl/five_2_four.py) - -**After Optimization** - -![image-20210918103240921](meta\profile-2.png) - -## ELSE - -Iessues and PRs about this project - -- invalid gradient https://gitee.com/ascend/modelzoo/issues/I452ZB https://gitee.com/ascend/pytorch-develop/pulls/2438 -- optimizer error https://gitee.com/ascend/pytorch-develop/pulls/2438 -- pyav install on CentOS arm https://gitee.com/ascend/modelzoo/issues/I48AP3 -- scikit-learn cannot allocate memory in static TLS https://gitee.com/ascend/modelzoo/issues/I48QNY +# X3D-S + +Implements training of X3D-S on the Kinetics-400 dataset + +## Detail + +Most of codes are modified according to [here](https://gitee.com/ascend/modelzoo/wikis/Pytorch%E8%AE%AD%E7%BB%83%E6%8C%87%E5%AF%BC?sort_id=4208869#21-%E8%BF%81%E7%A7%BB%E6%B5%81%E7%A8%8B%E8%AF%B4%E6%98%8E) + +There are some special modification of [source repository](https://github.com/facebookresearch/SlowFast) : + +##### NPU & GPU + +- Add some customized yaml configuration items, such as APEX.ENABLE、DIST_BACKEND... +- Ascend-Pytorch-1.5 is not supported `torch.nn.init.trunc_normal` , using `torch.nn.init.normal_` instead +- Adjusted the order of dependency import to prevent some unknown bugs (`scikit-learn`) + +##### NPU + +- Group conv3D of Ascend-Pytorch is not supported, so we canceled all group operations in the model +- Remove some irrelevant codes to prevent some unknown bugs (`Segmentation fault (core dumped)`) + + +## Requirements + +##### Base Environment + +- Python == 3.7.5 +- GCC >= 4.9 + +##### Python Environment + +1. Installing these error-prone dependencies first: + +- PyTorch (raw==1.5 or ascend) + - Ascend-Pytorch Version after August 24 be installed +- torchvision == 0.6.0 + - If on Centos arm, please build the source code from [here](https://gitee.com/azureology/torchvision/tree/v0.6.0/) +- PyAV + - If the installation fails on Centos arm, following this [issue](https://gitee.com/ascend/modelzoo/issues/I48AP3?from=project-issue) +- Detectron2 + - According to the CUDA version and Pytorch version, build from [source code](https://github.com/facebookresearch/detectron2) + +2. Then, you can use `pip3 install -r requirements.txt` to install some simple dependencies + + + +3. Building source code + +```shell +cd X3D # into source code root + +# Switch to your prepared environment + +python3.7 setup.py build develop # build slowfast and install the remaining dependencies +``` + + + +##### Modify Ascend-tookit + +```shell +cd /usr/local +find / -name fractal_z_3d_2_ncdhw.py +vi path_to_fractal_z_3d_2_ncdhw.py + +located method: + 1. def fractal_z_3d_2_ncdhw(src, dst, src_format, dst_format,kernel_name="fractal_z_3d_2_ncdhw") + 2. modify it according this picture: + 2.1. remove `if list(dst_shape) in ....` + 2.2. Align the next two lines like this +``` + +![image-20210909203603647](meta\bug-opt.png) + + + +##### Dataset + +- Download the Kinetics-400 dataset from [here](https://github.com/PaddlePaddle/PaddleVideo/blob/develop/docs/zh-CN/dataset/k400.md) + + 1. unzip the all packages and merge all folders + + 2. we get two sets , train set (used to train) and val set (used to test). And each of both has 400 folders + + ```markdown + # format of data folder + + |-data + |-train + |- video type 1 + |- video 1 + |- video 2 + ... + |- video type 2 + ... + |- video type 400 + |-val + |- video type 1 + |- video type 2 + ... + |- video type 400 + ``` + + + + 3. build train.csv, val.csv, test.csv, and put them in the same folder + + ```markdown + # format of data path folder + |- data_path + |- train.csv + |- val.csv + |- test.csv + ``` + + train.csv consists of train set + + val.csv is same as test.csv, and consists of test set + + ```markdown + # format of data path csv is: + + path_to_video_1 label_1 + path_to_video_2 label_2 + ... + path_to_video_N label_N + ``` + + 4. check if the all videos are lossless according to the scripts provided by project [mmaction2](https://github.com/open-mmlab/mmaction2) . Here, we provide the [list](mytest\Vinput\error_video) of corrupted videos that have been checked out +5. remove the those corrupted videos from the three csv + +## Training + +To train a model, run `main.py` with the desired model architecture and the path to the ImageNet dataset: + +> Note:the `real_data_path` is path of csv folder mentioned above + +```bash +# training 1p (300 epoch) +bash ./test/train_full_1p.sh --data_path=real_data_path + +# training 8p (300 epoch) +bash ./test/train_full_8p.sh --data_path=real_data_path + +# training performance 1p (1 epoch) +bash ./test/train_performance_1p.sh --data_path=real_data_path + +# training performance 8p (3 epoch) +bash ./test/train_performance_8p.sh --data_path=real_data_path + +# testing 8p +bash test/train_eval_8p.sh --data_path=real_data_path --pth_path=real_pre_train_model_path + +# train_finetune_1p.sh +bash test/train_finetune_1p.sh --data_path=real_data_path --pth_path=real_pre_train_model_path --num_classes=default_400 +``` + +> Log path: ./stdout.log + + + +## Training Result + +> Due to the calculation cast a long time, we choose to run the full data, and the NPU-ACC is aligned with the GPU-ACC (as many epochs as possible). + + +| Device | FPS | Top1-ACC 10-view | Batch Size | Epochs | AMP | +| :-------------: | :-----: | :--------------: | :--------: | :----: | :------: | +| 1P-GPU | 10.39 | 6.67% | 96 | 1/300 | O2-128.0 | +| 1P-NPU | 5.38 | 6.18% | 96 | 1/300 | O2-128.0 | +| 1P-NPU-白名单 | 5.35 | 6.36% | 96 | 1/300 | O2-128.0 | +| 8P-GPU | 1137.49 | 37.56% | 256 | 30/300 | O2-128.0 | +| 8P-NPU | 529.24 | 39.67% | 256 | 30/300 | O2-128.0 | +| 8P-NPU-fusedSGD | 510.66 | 5.80% | 256 | 2/300 | O2-128.0 | + + + +- Testing result: Top1-ACC of 8P-NPU and 8P-GPU training (30 epochs) + +![img](meta\8P-GPU & 8P-NPU.png) + +## Performance Optimization + +According to the above, it can be concluded that the accuracy(Top1-ACC 10-view) of 8P-GPU and 8P-NPU is little different. But performance(FPS) of 8P-NPU is 50% of 8P-GPU's. + +So we made the following analysis and improvement: + +- find the dynamic operators following [here](https://gitee.com/wangjiangben_hw/ascend-pytorch-crowdintelligence-doc/blob/master/pytorch-train-guide/%E6%A8%A1%E5%9E%8B%E7%AE%97%E5%AD%90%E6%8F%90%E5%8F%96%E6%8C%87%E5%8D%97.md), but the operators is very basic, and we can not identify them from our big model. + +![img](meta\dynamic_ops.png) + +- check the profile of NPU through chrome tracing + + image-20210913190836215 + +- In order to improve the low perfomance of Transpose, we first generate the `cann profiling` following [here](https://gitee.com/wangjiangben_hw/ascend-pytorch-crowdintelligence-doc/blob/master/pytorch-train-guide/CANNProfiling%E5%B7%A5%E5%85%B7%E4%BD%BF%E7%94%A8%E6%8C%87%E5%AF%BC%E4%B9%A6.md), then we extract the two operators, TransposeD and TransData. + - if TransposeD `Consuming time > 10s`, add its Input Shapes to White List (/usr/local/Ascend/ascend-toolkit/5.0.2/x86_64-linux/opp/op_impl/built-in/ai_core/tbe/impl/dynamic/transpose.py) + - if TransData `Consuming time > 10s & Input Formats == 'NCHW' & Output Formats == 'NC1HWC0'`, add its Input Shapes to White List (/usr/local/Ascend/ascend-toolkit/5.0.2/x86_64-linux/opp/op_impl/built-in/ai_core/tbe/impl/four_2_five.py) + - if TransData `Consuming time > 10s & Input Formats == 'NC1HWC0' & Output Formats == 'NCHW'`, add its Input Shapes to White List (/usr/local/Ascend/ascend-toolkit/5.0.2/x86_64-linux/opp/op_impl/built-in/ai_core/tbe/impl/five_2_four.py) + +**After Optimization** + +![image-20210918103240921](meta\profile-2.png) + +## ELSE + +Iessues and PRs about this project + +- invalid gradient https://gitee.com/ascend/modelzoo/issues/I452ZB https://gitee.com/ascend/pytorch-develop/pulls/2438 +- optimizer error https://gitee.com/ascend/pytorch-develop/pulls/2438 +- pyav install on CentOS arm https://gitee.com/ascend/modelzoo/issues/I48AP3 +- scikit-learn cannot allocate memory in static TLS https://gitee.com/ascend/modelzoo/issues/I48QNY diff --git a/PyTorch/contrib/cv/video/X3D/slowfast/utils/ava_evaluation/__init__.py b/PyTorch/contrib/cv/video/X3D/slowfast/utils/ava_evaluation/__init__.py index 919b057907..6228b71326 100644 --- a/PyTorch/contrib/cv/video/X3D/slowfast/utils/ava_evaluation/__init__.py +++ b/PyTorch/contrib/cv/video/X3D/slowfast/utils/ava_evaluation/__init__.py @@ -1,14 +1,14 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ diff --git a/PyTorch/contrib/nlp/Bertsum_for_PyTorch/modelzoo_level.txt b/PyTorch/contrib/nlp/Bertsum_for_PyTorch/modelzoo_level.txt index 0ea38b69c9..ceafe5b115 100644 --- a/PyTorch/contrib/nlp/Bertsum_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/contrib/nlp/Bertsum_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:PERFECT:NOK +FuncStatus:OK +PerfStatus:PERFECT:NOK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/nlp/TextCNN/LICENSE b/PyTorch/contrib/nlp/TextCNN/LICENSE index 185404d551..5b4cf39445 100644 --- a/PyTorch/contrib/nlp/TextCNN/LICENSE +++ b/PyTorch/contrib/nlp/TextCNN/LICENSE @@ -1,204 +1,204 @@ -Copyright 2018-2019 Open-MMLab. All rights reserved. -Copyright 2021 Huawei Technologies Co., Ltd - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018-2019 Open-MMLab. - - 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. +Copyright 2018-2019 Open-MMLab. All rights reserved. +Copyright 2021 Huawei Technologies Co., Ltd + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2019 Open-MMLab. + + 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. diff --git a/PyTorch/contrib/nlp/TextCNN/modelzoo_level.txt b/PyTorch/contrib/nlp/TextCNN/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/contrib/nlp/TextCNN/modelzoo_level.txt +++ b/PyTorch/contrib/nlp/TextCNN/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/nlp/tinybert/demo.py b/PyTorch/contrib/nlp/tinybert/demo.py index 2ce50832af..3311302206 100644 --- a/PyTorch/contrib/nlp/tinybert/demo.py +++ b/PyTorch/contrib/nlp/tinybert/demo.py @@ -1,89 +1,89 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# 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. -"""TinyBERT finetuning runner specifically for SST-2 dataset.""" - -################## import libraries ################## - -#standard libraries -from __future__ import absolute_import, division, print_function -import argparse -import random - -#third-party libraries -import numpy as np -import torch - -#local libraries -from transformer.modeling import TinyBertForSequenceClassification - -################## end import libraries ################## - -def random_int_list(start, stop, length): - start, stop = (int(start), int(stop)) if start <= stop else (int(stop), int(start)) - length = int(abs(length)) if length else 0 - random_list = [] - for i in range(length): - random_list.append(random.randint(start, stop)) - return random_list - -def is_same(a,b,i): - result = (a == b).mean() - if result == 1: - print("step {} = step {}: {}".format(i-1,i,'True')) - else: - print("step {} = step {}: {}".format(i - 1, i, 'False')) - -def main(): - - ################## set args ################## - parser = argparse.ArgumentParser() - - # 1.file and model - parser.add_argument("--model", - default=None, - type=str, - help="The model dir.") - parser.add_argument("--max_seq_length", - default=64, - type=int, - help="The maximum total input sequence length after WordPiece tokenization. \n" - "Sequences longer than this will be truncated, and sequences shorter \n" - "than this will be padded.") - args = parser.parse_args() - - # create model - model = TinyBertForSequenceClassification.from_pretrained(args.model, num_labels=2) - model.eval() - # test - input_ids = torch.tensor(random_int_list(0,9999,args.max_seq_length), dtype=torch.long).view(1,-1) - print(input_ids) - segment_ids = torch.tensor(random_int_list(0,1,args.max_seq_length), dtype=torch.long).view(1,-1) - input_mask = torch.tensor(random_int_list(0,1,args.max_seq_length), dtype=torch.long).view(1,-1) - repeat_time = 20 - for i in range(1,repeat_time+1): - logits, _, _ = model(input_ids, segment_ids, input_mask) - logits = logits.squeeze() - print("step {}, logits = {}".format(i,logits)) - if i == 1: - a = logits - elif i == 2: - b = logits - is_same(a.detach().numpy(),b.detach().numpy(),i) - else: - a = b - b = logits - is_same(a.detach().numpy(),b.detach().numpy(),i) - -if __name__ == "__main__": - main() +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. +"""TinyBERT finetuning runner specifically for SST-2 dataset.""" + +################## import libraries ################## + +#standard libraries +from __future__ import absolute_import, division, print_function +import argparse +import random + +#third-party libraries +import numpy as np +import torch + +#local libraries +from transformer.modeling import TinyBertForSequenceClassification + +################## end import libraries ################## + +def random_int_list(start, stop, length): + start, stop = (int(start), int(stop)) if start <= stop else (int(stop), int(start)) + length = int(abs(length)) if length else 0 + random_list = [] + for i in range(length): + random_list.append(random.randint(start, stop)) + return random_list + +def is_same(a,b,i): + result = (a == b).mean() + if result == 1: + print("step {} = step {}: {}".format(i-1,i,'True')) + else: + print("step {} = step {}: {}".format(i - 1, i, 'False')) + +def main(): + + ################## set args ################## + parser = argparse.ArgumentParser() + + # 1.file and model + parser.add_argument("--model", + default=None, + type=str, + help="The model dir.") + parser.add_argument("--max_seq_length", + default=64, + type=int, + help="The maximum total input sequence length after WordPiece tokenization. \n" + "Sequences longer than this will be truncated, and sequences shorter \n" + "than this will be padded.") + args = parser.parse_args() + + # create model + model = TinyBertForSequenceClassification.from_pretrained(args.model, num_labels=2) + model.eval() + # test + input_ids = torch.tensor(random_int_list(0,9999,args.max_seq_length), dtype=torch.long).view(1,-1) + print(input_ids) + segment_ids = torch.tensor(random_int_list(0,1,args.max_seq_length), dtype=torch.long).view(1,-1) + input_mask = torch.tensor(random_int_list(0,1,args.max_seq_length), dtype=torch.long).view(1,-1) + repeat_time = 20 + for i in range(1,repeat_time+1): + logits, _, _ = model(input_ids, segment_ids, input_mask) + logits = logits.squeeze() + print("step {}, logits = {}".format(i,logits)) + if i == 1: + a = logits + elif i == 2: + b = logits + is_same(a.detach().numpy(),b.detach().numpy(),i) + else: + a = b + b = logits + is_same(a.detach().numpy(),b.detach().numpy(),i) + +if __name__ == "__main__": + main() diff --git a/PyTorch/contrib/nlp/tinybert/modelzoo_level.txt b/PyTorch/contrib/nlp/tinybert/modelzoo_level.txt index 6671333241..c33e5e5479 100644 --- a/PyTorch/contrib/nlp/tinybert/modelzoo_level.txt +++ b/PyTorch/contrib/nlp/tinybert/modelzoo_level.txt @@ -1,6 +1,6 @@ -FuncStatus:OK -PerfStatus:NOK -PrecisionStatus:OK -GPUStatus:OK -AutoTune:POK +FuncStatus:OK +PerfStatus:NOK +PrecisionStatus:OK +GPUStatus:OK +AutoTune:POK NPUMigrationStatus:OK \ No newline at end of file diff --git a/PyTorch/contrib/nlp/tinybert/transformer/modeling_for_finetune.py b/PyTorch/contrib/nlp/tinybert/transformer/modeling_for_finetune.py index d3f480d2ee..8a0204692c 100644 --- a/PyTorch/contrib/nlp/tinybert/transformer/modeling_for_finetune.py +++ b/PyTorch/contrib/nlp/tinybert/transformer/modeling_for_finetune.py @@ -1,1144 +1,1144 @@ -# coding=utf-8 -# Copyright 2018 The Google AI Language Team Authors and The HuggingFace Inc. team. -# Copyright (c) 2018, NVIDIA CORPORATION. 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. -"""PyTorch BERT model.""" - -from __future__ import absolute_import, division, print_function, unicode_literals - -import copy -import json -import logging -import math -import os -import shutil -import tarfile -import tempfile -import sys -from io import open - -import torch -import torch.nn.functional as F -from torch import nn -from torch.nn import CrossEntropyLoss -from torch.autograd import Variable -from torch.nn.parameter import Parameter - -from .file_utils import WEIGHTS_NAME, CONFIG_NAME - -logger = logging.getLogger(__name__) - -PRETRAINED_MODEL_ARCHIVE_MAP = { - 'bert-base-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-uncased.tar.gz", - 'bert-large-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-uncased.tar.gz", - 'bert-base-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-cased.tar.gz", - 'bert-large-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-cased.tar.gz", - 'bert-base-multilingual-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-multilingual-uncased.tar.gz", - 'bert-base-multilingual-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-multilingual-cased.tar.gz", - 'bert-base-chinese': "", -} - -BERT_CONFIG_NAME = 'bert_config.json' -TF_WEIGHTS_NAME = 'model.ckpt' - - -def load_tf_weights_in_bert(model, tf_checkpoint_path): - """ Load tf checkpoints in a pytorch model - """ - try: - import re - import numpy as np - import tensorflow as tf - except ImportError: - print("Loading a TensorFlow models in PyTorch, requires TensorFlow to be installed. Please see " - "https://www.tensorflow.org/install/ for installation instructions.") - raise - tf_path = os.path.abspath(tf_checkpoint_path) - print("Converting TensorFlow checkpoint from {}".format(tf_path)) - # Load weights from TF model - init_vars = tf.train.list_variables(tf_path) - names = [] - arrays = [] - for name, shape in init_vars: - print("Loading TF weight {} with shape {}".format(name, shape)) - array = tf.train.load_variable(tf_path, name) - names.append(name) - arrays.append(array) - - for name, array in zip(names, arrays): - name = name.split('/') - # adam_v and adam_m are variables used in AdamWeightDecayOptimizer to calculated m and v - # which are not required for using pretrained model - if any(n in ["adam_v", "adam_m", "global_step"] for n in name): - print("Skipping {}".format("/".join(name))) - continue - pointer = model - for m_name in name: - if re.fullmatch(r'[A-Za-z]+_\d+', m_name): - l = re.split(r'_(\d+)', m_name) - else: - l = [m_name] - if l[0] == 'kernel' or l[0] == 'gamma': - pointer = getattr(pointer, 'weight') - elif l[0] == 'output_bias' or l[0] == 'beta': - try: - pointer = getattr(pointer, 'bias') - except AttributeError: - print("Skipping {}".format("/".join(name))) - continue - elif l[0] == 'output_weights': - pointer = getattr(pointer, 'weight') - elif l[0] == 'squad': - pointer = getattr(pointer, 'classifier') - else: - try: - pointer = getattr(pointer, l[0]) - except AttributeError: - print("Skipping {}".format("/".join(name))) - continue - if len(l) >= 2: - num = int(l[1]) - pointer = pointer[num] - if m_name[-11:] == '_embeddings': - pointer = getattr(pointer, 'weight') - elif m_name == 'kernel': - array = np.transpose(array) - try: - assert pointer.shape == array.shape - except AssertionError as e: - e.args += (pointer.shape, array.shape) - raise - print("Initialize PyTorch weight {}".format(name)) - pointer.data = torch.from_numpy(array) - return model - - -def gelu(x): - """Implementation of the gelu activation function. - For information: OpenAI GPT's gelu is slightly different (and gives slightly different results): - 0.5 * x * (1 + torch.tanh(math.sqrt(2 / math.pi) * (x + 0.044715 * torch.pow(x, 3)))) - Also see https://arxiv.org/abs/1606.08415 - """ - return x * 0.5 * (1.0 + torch.erf(x / math.sqrt(2.0))) - - -def swish(x): - return x * torch.sigmoid(x) - -''' - -try: - from apex.normalization.fused_layer_norm import FusedLayerNorm as BertLayerNorm -except ImportError: - logger.info( - "Better speed can be achieved with apex installed from https://www.github.com/nvidia/apex .") -''' -class BertLayerNorm(nn.Module): - def __init__(self, hidden_size, eps=1e-12): - """Construct a layernorm module in the TF style (epsilon inside the square root). - """ - super(BertLayerNorm, self).__init__() - self.weight = nn.Parameter(torch.ones(hidden_size)) - self.bias = nn.Parameter(torch.zeros(hidden_size)) - self.variance_epsilon = eps - - def forward(self, x): - u = x.mean(-1, keepdim=True) - s = (x - u).pow(2).mean(-1, keepdim=True) - x = (x - u) / torch.sqrt(s + self.variance_epsilon) - return self.weight * x + self.bias - - -class HeadAttention(nn.Module): - def __init__(self, config, hidden_size, head_num, head_used): - super(HeadAttention, self).__init__() - self.head_num = head_num - self.head_used = head_used - self.hidden_size = hidden_size - if self.hidden_size % self.head_num != 0: - raise ValueError( - "The hidden size (%d) is not a multiple of the number of attention " - "heads (%d)" % (self.hidden_size, self.head_num)) - - self.attention_head_size = int(self.hidden_size / self.head_num) - self.all_head_size = self.num_heads_used * self.attention_head_size - - self.query = nn.Linear(self.hidden_size, self.all_head_size) - self.key = nn.Linear(self.hidden_size, self.all_head_size) - self.value = nn.Linear(self.hidden_size, self.all_head_size) - - self.dropout = nn.Dropout(config.attention_probs_dropout_prob) - - def transpose_for_scores(self, x): - new_x_shape = x.size()[:-1] + (self.num_heads_used, - self.attention_head_size) - x = x.view(*new_x_shape) - return x.permute(0, 2, 1, 3) - - def forward(self, hidden_states, attention_mask): - mixed_query_layer = self.query(hidden_states) - mixed_key_layer = self.key(hidden_states) - mixed_value_layer = self.value(hidden_states) - - query_layer = self.transpose_for_scores(mixed_query_layer) - key_layer = self.transpose_for_scores(mixed_key_layer) - value_layer = self.transpose_for_scores(mixed_value_layer) - - # Take the dot product between "query" and "key" to get the raw attention scores. - attention_scores = torch.matmul( - query_layer, key_layer.transpose(-1, -2)) - attention_scores = attention_scores / \ - math.sqrt(self.attention_head_size) - # Apply the attention mask is (precomputed for all layers in BertModel forward() function) - attention_scores = attention_scores + attention_mask - - # Normalize the attention scores to probabilities. - attention_probs = nn.Softmax(dim=-1)(attention_scores) - - # This is actually dropping out entire tokens to attend to, which might - # seem a bit unusual, but is taken from the original Transformer paper. - attention_probs = self.dropout(attention_probs) - - context_layer = torch.matmul(attention_probs, value_layer) - context_layer = context_layer.permute(0, 2, 1, 3).contiguous() - new_context_layer_shape = context_layer.size()[ - :-2] + (self.all_head_size,) - context_layer = context_layer.view(*new_context_layer_shape) - - if self.num_heads_used != self.num_attention_heads: - pad_shape = context_layer.size()[:-1] + \ - ((self.num_attention_heads - self.num_heads_used) - * self.attention_head_size, ) - - pad_layer = torch.zeros(*pad_shape).to(context_layer.device) - context_layer = torch.cat((context_layer, pad_layer), -1) - return context_layer - - -ACT2FN = {"gelu": gelu, "relu": torch.nn.functional.relu} -NORM = {'layer_norm': BertLayerNorm} - - -class BertConfig(object): - """Configuration class to store the configuration of a `BertModel`. - """ - - def __init__(self, - vocab_size_or_config_json_file, - hidden_size=768, - num_hidden_layers=12, - num_attention_heads=12, - intermediate_size=3072, - hidden_act="gelu", - hidden_dropout_prob=0.1, - attention_probs_dropout_prob=0.1, - max_position_embeddings=512, - type_vocab_size=2, - initializer_range=0.02, - pre_trained='', - training=''): - """Constructs BertConfig. - - Args: - vocab_size_or_config_json_file: Vocabulary size of `inputs_ids` in `BertModel`. - hidden_size: Size of the encoder layers and the pooler layer. - num_hidden_layers: Number of hidden layers in the Transformer encoder. - num_attention_heads: Number of attention heads for each attention layer in - the Transformer encoder. - intermediate_size: The size of the "intermediate" (i.e., feed-forward) - layer in the Transformer encoder. - hidden_act: The non-linear activation function (function or string) in the - encoder and pooler. If string, "gelu", "relu" and "swish" are supported. - hidden_dropout_prob: The dropout probabilitiy for all fully connected - layers in the embeddings, encoder, and pooler. - attention_probs_dropout_prob: The dropout ratio for the attention - probabilities. - max_position_embeddings: The maximum sequence length that this model might - ever be used with. Typically set this to something large just in case - (e.g., 512 or 1024 or 2048). - type_vocab_size: The vocabulary size of the `token_type_ids` passed into - `BertModel`. - initializer_range: The sttdev of the truncated_normal_initializer for - initializing all weight matrices. - """ - if isinstance(vocab_size_or_config_json_file, str) or (sys.version_info[0] == 2 - and isinstance(vocab_size_or_config_json_file, unicode)): - with open(vocab_size_or_config_json_file, "r", encoding='utf-8') as reader: - json_config = json.loads(reader.read()) - for key, value in json_config.items(): - self.__dict__[key] = value - elif isinstance(vocab_size_or_config_json_file, int): - self.vocab_size = vocab_size_or_config_json_file - self.hidden_size = hidden_size - self.num_hidden_layers = num_hidden_layers - self.num_attention_heads = num_attention_heads - self.hidden_act = hidden_act - self.intermediate_size = intermediate_size - self.hidden_dropout_prob = hidden_dropout_prob - self.attention_probs_dropout_prob = attention_probs_dropout_prob - self.max_position_embeddings = max_position_embeddings - self.type_vocab_size = type_vocab_size - self.initializer_range = initializer_range - self.pre_trained = pre_trained - self.training = training - else: - raise ValueError("First argument must be either a vocabulary size (int)" - "or the path to a pretrained model config file (str)") - - @classmethod - def from_dict(cls, json_object): - """Constructs a `BertConfig` from a Python dictionary of parameters.""" - config = BertConfig(vocab_size_or_config_json_file=-1) - for key, value in json_object.items(): - config.__dict__[key] = value - return config - - @classmethod - def from_json_file(cls, json_file): - """Constructs a `BertConfig` from a json file of parameters.""" - with open(json_file, "r", encoding='utf-8') as reader: - text = reader.read() - return cls.from_dict(json.loads(text)) - - def __repr__(self): - return str(self.to_json_string()) - - def to_dict(self): - """Serializes this instance to a Python dictionary.""" - output = copy.deepcopy(self.__dict__) - return output - - def to_json_string(self): - """Serializes this instance to a JSON string.""" - return json.dumps(self.to_dict(), indent=2, sort_keys=True) + "\n" - - def to_json_file(self, json_file_path): - """ Save this instance to a json file.""" - with open(json_file_path, "w", encoding='utf-8') as writer: - writer.write(self.to_json_string()) - - -class BertEmbeddings(nn.Module): - """Construct the embeddings from word, position and token_type embeddings. - """ - - def __init__(self, config): - super(BertEmbeddings, self).__init__() - self.word_embeddings = nn.Embedding( - config.vocab_size, config.hidden_size, padding_idx=0) - self.position_embeddings = nn.Embedding( - config.max_position_embeddings, config.hidden_size) - self.token_type_embeddings = nn.Embedding( - config.type_vocab_size, config.hidden_size) - - # self.LayerNorm is not snake-cased to stick with TensorFlow model variable name and be able to load - # any TensorFlow checkpoint file - self.LayerNorm = BertLayerNorm(config.hidden_size, eps=1e-12) - self.dropout = nn.Dropout(config.hidden_dropout_prob) - - def forward(self, input_ids, token_type_ids=None): - seq_length = input_ids.size(1) - position_ids = torch.arange( - seq_length, dtype=torch.long, device=input_ids.device) - position_ids = position_ids.unsqueeze(0).expand_as(input_ids) - if token_type_ids is None: - token_type_ids = torch.zeros_like(input_ids) - - words_embeddings = self.word_embeddings(input_ids) - position_embeddings = self.position_embeddings(position_ids) - token_type_embeddings = self.token_type_embeddings(token_type_ids) - - embeddings = words_embeddings + position_embeddings + token_type_embeddings - embeddings = self.LayerNorm(embeddings) - embeddings = self.dropout(embeddings) - return embeddings - - -class BertSelfAttention(nn.Module): - def __init__(self, config): - super(BertSelfAttention, self).__init__() - if config.hidden_size % config.num_attention_heads != 0: - raise ValueError( - "The hidden size (%d) is not a multiple of the number of attention " - "heads (%d)" % (config.hidden_size, config.num_attention_heads)) - self.num_attention_heads = config.num_attention_heads - self.attention_head_size = int( - config.hidden_size / config.num_attention_heads) - self.all_head_size = self.num_attention_heads * self.attention_head_size - - self.query = nn.Linear(config.hidden_size, self.all_head_size) - self.key = nn.Linear(config.hidden_size, self.all_head_size) - self.value = nn.Linear(config.hidden_size, self.all_head_size) - - self.dropout = nn.Dropout(config.attention_probs_dropout_prob) - - def transpose_for_scores(self, x): - new_x_shape = x.size()[ - :-1] + (self.num_attention_heads, self.attention_head_size) - x = x.view(*new_x_shape) - return x.permute(0, 2, 1, 3) - - def forward(self, hidden_states, attention_mask, output_att=False): - mixed_query_layer = self.query(hidden_states) - mixed_key_layer = self.key(hidden_states) - mixed_value_layer = self.value(hidden_states) - - query_layer = self.transpose_for_scores(mixed_query_layer) - key_layer = self.transpose_for_scores(mixed_key_layer) - value_layer = self.transpose_for_scores(mixed_value_layer) - - # Take the dot product between "query" and "key" to get the raw attention scores. - attention_scores = torch.matmul( - query_layer, key_layer.transpose(-1, -2)) - attention_scores = attention_scores / \ - math.sqrt(self.attention_head_size) - # Apply the attention mask is (precomputed for all layers in BertModel forward() function) - attention_scores = attention_scores + attention_mask - - # Normalize the attention scores to probabilities. - attention_probs = nn.Softmax(dim=-1)(attention_scores) - - # This is actually dropping out entire tokens to attend to, which might - # seem a bit unusual, but is taken from the original Transformer paper. - attention_probs = self.dropout(attention_probs) - - context_layer = torch.matmul(attention_probs, value_layer) - context_layer = context_layer.permute(0, 2, 1, 3).contiguous() - new_context_layer_shape = context_layer.size()[ - :-2] + (self.all_head_size,) - context_layer = context_layer.view(*new_context_layer_shape) - return context_layer, attention_scores - - -class BertAttention(nn.Module): - def __init__(self, config): - super(BertAttention, self).__init__() - - self.self = BertSelfAttention(config) - self.output = BertSelfOutput(config) - - def forward(self, input_tensor, attention_mask): - self_output, layer_att = self.self(input_tensor, attention_mask) - attention_output = self.output(self_output, input_tensor) - return attention_output, layer_att - - -class BertSelfOutput(nn.Module): - def __init__(self, config): - super(BertSelfOutput, self).__init__() - self.dense = nn.Linear(config.hidden_size, config.hidden_size) - self.LayerNorm = BertLayerNorm(config.hidden_size, eps=1e-12) - self.dropout = nn.Dropout(config.hidden_dropout_prob) - - def forward(self, hidden_states, input_tensor): - hidden_states = self.dense(hidden_states) - hidden_states = self.dropout(hidden_states) - hidden_states = self.LayerNorm(hidden_states + input_tensor) - return hidden_states - - -class BertIntermediate(nn.Module): - def __init__(self, config, intermediate_size=-1): - super(BertIntermediate, self).__init__() - if intermediate_size < 0: - self.dense = nn.Linear( - config.hidden_size, config.intermediate_size) - else: - self.dense = nn.Linear(config.hidden_size, intermediate_size) - if isinstance(config.hidden_act, str) or (sys.version_info[0] == 2 and isinstance(config.hidden_act, unicode)): - self.intermediate_act_fn = ACT2FN[config.hidden_act] - else: - self.intermediate_act_fn = config.hidden_act - - def forward(self, hidden_states): - hidden_states = self.dense(hidden_states) - hidden_states = self.intermediate_act_fn(hidden_states) - return hidden_states - - -class BertOutput(nn.Module): - def __init__(self, config, intermediate_size=-1): - super(BertOutput, self).__init__() - if intermediate_size < 0: - self.dense = nn.Linear( - config.intermediate_size, config.hidden_size) - else: - self.dense = nn.Linear(intermediate_size, config.hidden_size) - self.LayerNorm = BertLayerNorm(config.hidden_size, eps=1e-12) - self.dropout = nn.Dropout(config.hidden_dropout_prob) - - def forward(self, hidden_states, input_tensor): - hidden_states = self.dense(hidden_states) - hidden_states = self.dropout(hidden_states) - hidden_states = self.LayerNorm(hidden_states + input_tensor) - return hidden_states - - -class BertLayer(nn.Module): - def __init__(self, config): - super(BertLayer, self).__init__() - self.attention = BertAttention(config) - self.intermediate = BertIntermediate(config) - self.output = BertOutput(config) - - def forward(self, hidden_states, attention_mask): - attention_output, layer_att = self.attention( - hidden_states, attention_mask) - intermediate_output = self.intermediate(attention_output) - layer_output = self.output(intermediate_output, attention_output) - - return layer_output, layer_att - - -class BertEncoder(nn.Module): - def __init__(self, config): - super(BertEncoder, self).__init__() - self.layer = nn.ModuleList([BertLayer(config) - for _ in range(config.num_hidden_layers)]) - - def forward(self, hidden_states, attention_mask): - all_encoder_layers = [] - all_encoder_atts = [] - for _, layer_module in enumerate(self.layer): - all_encoder_layers.append(hidden_states) - hidden_states, layer_att = layer_module( - hidden_states, attention_mask) - all_encoder_atts.append(layer_att) - - all_encoder_layers.append(hidden_states) - return all_encoder_layers, all_encoder_atts - - -class BertPooler(nn.Module): - def __init__(self, config, recurs=None): - super(BertPooler, self).__init__() - self.dense = nn.Linear(config.hidden_size, config.hidden_size) - self.activation = nn.Tanh() - self.config = config - - def forward(self, hidden_states): - # We "pool" the model by simply taking the hidden state corresponding - # to the first token. "-1" refers to last layer - pooled_output = hidden_states[-1][:, 0] - - pooled_output = self.dense(pooled_output) - pooled_output = self.activation(pooled_output) - - return pooled_output - - -class BertPredictionHeadTransform(nn.Module): - def __init__(self, config): - super(BertPredictionHeadTransform, self).__init__() - # Need to unty it when we separate the dimensions of hidden and emb - self.dense = nn.Linear(config.hidden_size, config.hidden_size) - if isinstance(config.hidden_act, str) or (sys.version_info[0] == 2 and isinstance(config.hidden_act, unicode)): - self.transform_act_fn = ACT2FN[config.hidden_act] - else: - self.transform_act_fn = config.hidden_act - self.LayerNorm = BertLayerNorm(config.hidden_size, eps=1e-12) - - def forward(self, hidden_states): - hidden_states = self.dense(hidden_states) - hidden_states = self.transform_act_fn(hidden_states) - hidden_states = self.LayerNorm(hidden_states) - return hidden_states - - -class BertLMPredictionHead(nn.Module): - def __init__(self, config, bert_model_embedding_weights): - super(BertLMPredictionHead, self).__init__() - self.transform = BertPredictionHeadTransform(config) - - # The output weights are the same as the input embeddings, but there is - # an output-only bias for each token. - self.decoder = nn.Linear(bert_model_embedding_weights.size(1), - bert_model_embedding_weights.size(0), - bias=False) - self.decoder.weight = bert_model_embedding_weights - self.bias = nn.Parameter(torch.zeros( - bert_model_embedding_weights.size(0))) - - def forward(self, hidden_states): - hidden_states = self.transform(hidden_states) - hidden_states = self.decoder(hidden_states) + self.bias - return hidden_states - - -class BertOnlyMLMHead(nn.Module): - def __init__(self, config, bert_model_embedding_weights): - super(BertOnlyMLMHead, self).__init__() - self.predictions = BertLMPredictionHead( - config, bert_model_embedding_weights) - - def forward(self, sequence_output): - prediction_scores = self.predictions(sequence_output) - return prediction_scores - - -class BertOnlyNSPHead(nn.Module): - def __init__(self, config): - super(BertOnlyNSPHead, self).__init__() - self.seq_relationship = nn.Linear(config.hidden_size, 2) - - def forward(self, pooled_output): - seq_relationship_score = self.seq_relationship(pooled_output) - return seq_relationship_score - - -class BertPreTrainingHeads(nn.Module): - def __init__(self, config, bert_model_embedding_weights): - super(BertPreTrainingHeads, self).__init__() - self.predictions = BertLMPredictionHead( - config, bert_model_embedding_weights) - self.seq_relationship = nn.Linear(config.hidden_size, 2) - - def forward(self, sequence_output, pooled_output): - prediction_scores = self.predictions(sequence_output) - seq_relationship_score = self.seq_relationship(pooled_output) - return prediction_scores, seq_relationship_score - - -class BertPreTrainedModel(nn.Module): - """ An abstract class to handle weights initialization and - a simple interface for dowloading and loading pretrained models. - """ - - def __init__(self, config, *inputs, **kwargs): - super(BertPreTrainedModel, self).__init__() - if not isinstance(config, BertConfig): - raise ValueError( - "Parameter config in `{}(config)` should be an instance of class `BertConfig`. " - "To create a model from a Google pretrained model use " - "`model = {}.from_pretrained(PRETRAINED_MODEL_NAME)`".format( - self.__class__.__name__, self.__class__.__name__ - )) - self.config = config - - def init_bert_weights(self, module): - """ Initialize the weights. - """ - if isinstance(module, (nn.Linear, nn.Embedding)): - # Slightly different from the TF version which uses truncated_normal for initialization - # cf https://github.com/pytorch/pytorch/pull/5617 - module.weight.data.normal_( - mean=0.0, std=self.config.initializer_range) - elif isinstance(module, BertLayerNorm): - module.bias.data.zero_() - module.weight.data.fill_(1.0) - if isinstance(module, nn.Linear) and module.bias is not None: - module.bias.data.zero_() - - @classmethod - def from_scratch(cls, pretrained_model_name_or_path, *inputs, **kwargs): - resolved_config_file = os.path.join( - pretrained_model_name_or_path, CONFIG_NAME) - config = BertConfig.from_json_file(resolved_config_file) - - logger.info("Model config {}".format(config)) - model = cls(config, *inputs, **kwargs) - return model - - @classmethod - def from_pretrained(cls, pretrained_model_name_or_path, *inputs, **kwargs): - """ - Instantiate a BertPreTrainedModel from a pre-trained model file or a pytorch state dict. - Download and cache the pre-trained model file if needed. - - Params: - pretrained_model_name_or_path: either: - - a str with the name of a pre-trained model to load selected in the list of: - . `bert-base-uncased` - . `bert-large-uncased` - . `bert-base-cased` - . `bert-large-cased` - . `bert-base-multilingual-uncased` - . `bert-base-multilingual-cased` - . `bert-base-chinese` - - a path or url to a pretrained model archive containing: - . `bert_config.json` a configuration file for the model - . `pytorch_model.bin` a PyTorch dump of a BertForPreTraining instance - - a path or url to a pretrained model archive containing: - . `bert_config.json` a configuration file for the model - . `model.chkpt` a TensorFlow checkpoint - from_tf: should we load the weights from a locally saved TensorFlow checkpoint - cache_dir: an optional path to a folder in which the pre-trained models will be cached. - state_dict: an optional state dictionnary (collections.OrderedDict object) to use instead of Google pre-trained models - *inputs, **kwargs: additional input for the specific Bert class - (ex: num_labels for BertForSequenceClassification) - """ - state_dict = kwargs.get('state_dict', None) - kwargs.pop('state_dict', None) - from_tf = kwargs.get('from_tf', False) - kwargs.pop('from_tf', None) - - # Load config - config_file = os.path.join(pretrained_model_name_or_path, CONFIG_NAME) - config = BertConfig.from_json_file(config_file) - logger.info("Model config {}".format(config)) - # Instantiate model. - - model = cls(config, *inputs, **kwargs) - if state_dict is None and not from_tf: - weights_path = os.path.join( - pretrained_model_name_or_path, WEIGHTS_NAME) - logger.info("Loading model {}".format(weights_path)) - state_dict = torch.load(weights_path, map_location='cpu') - state_dict.pop('classifier.weight') - state_dict.pop('classifier.bias') - if from_tf: - # Directly load from a TensorFlow checkpoint - weights_path = os.path.join( - pretrained_model_name_or_path, TF_WEIGHTS_NAME) - return load_tf_weights_in_bert(model, weights_path) - # Load from a PyTorch state_dict - old_keys = [] - new_keys = [] - for key in state_dict.keys(): - new_key = None - if 'gamma' in key: - new_key = key.replace('gamma', 'weight') - if 'beta' in key: - new_key = key.replace('beta', 'bias') - if new_key: - old_keys.append(key) - new_keys.append(new_key) - for old_key, new_key in zip(old_keys, new_keys): - state_dict[new_key] = state_dict.pop(old_key) - - missing_keys = [] - unexpected_keys = [] - error_msgs = [] - # copy state_dict so _load_from_state_dict can modify it - metadata = getattr(state_dict, '_metadata', None) - state_dict = state_dict.copy() - if metadata is not None: - state_dict._metadata = metadata - - def load(module, prefix=''): - local_metadata = {} if metadata is None else metadata.get( - prefix[:-1], {}) - module._load_from_state_dict( - state_dict, prefix, local_metadata, True, missing_keys, unexpected_keys, error_msgs) - for name, child in module._modules.items(): - if child is not None: - load(child, prefix + name + '.') - - start_prefix = '' - if not hasattr(model, 'bert') and any(s.startswith('bert.') for s in state_dict.keys()): - start_prefix = 'bert.' - - logger.info('loading model...') - load(model, prefix=start_prefix) - logger.info('done!') - if len(missing_keys) > 0: - logger.info("Weights of {} not initialized from pretrained model: {}".format( - model.__class__.__name__, missing_keys)) - if len(unexpected_keys) > 0: - logger.info("Weights from pretrained model not used in {}: {}".format( - model.__class__.__name__, unexpected_keys)) - if len(error_msgs) > 0: - raise RuntimeError('Error(s) in loading state_dict for {}:\n\t{}'.format( - model.__class__.__name__, "\n\t".join(error_msgs))) - - return model - - -class BertModel(BertPreTrainedModel): - """BERT model ("Bidirectional Embedding Representations from a Transformer"). - - Params: - config: a BertConfig class instance with the configuration to build a new model - - Inputs: - `input_ids`: a torch.LongTensor of shape [batch_size, sequence_length] - with the word token indices in the vocabulary(see the tokens preprocessing logic in the scripts - `extract_features.py`, `run_classifier.py` and `run_squad.py`) - `token_type_ids`: an optional torch.LongTensor of shape [batch_size, sequence_length] with the token - types indices selected in [0, 1]. Type 0 corresponds to a `sentence A` and type 1 corresponds to - a `sentence B` token (see BERT paper for more details). - `attention_mask`: an optional torch.LongTensor of shape [batch_size, sequence_length] with indices - selected in [0, 1]. It's a mask to be used if the input sequence length is smaller than the max - input sequence length in the current batch. It's the mask that we typically use for attention when - a batch has varying length sentences. - `output_all_encoded_layers`: boolean which controls the content of the `encoded_layers` output as described below. Default: `True`. - - Outputs: Tuple of (encoded_layers, pooled_output) - `encoded_layers`: controled by `output_all_encoded_layers` argument: - - `output_all_encoded_layers=True`: outputs a list of the full sequences of encoded-hidden-states at the end - of each attention block (i.e. 12 full sequences for BERT-base, 24 for BERT-large), each - encoded-hidden-state is a torch.FloatTensor of size [batch_size, sequence_length, hidden_size], - - `output_all_encoded_layers=False`: outputs only the full sequence of hidden-states corresponding - to the last attention block of shape [batch_size, sequence_length, hidden_size], - `pooled_output`: a torch.FloatTensor of size [batch_size, hidden_size] which is the output of a - classifier pretrained on top of the hidden state associated to the first character of the - input (`CLS`) to train on the Next-Sentence task (see BERT's paper). - - Example usage: - ```python - # Already been converted into WordPiece token ids - input_ids = torch.LongTensor([[31, 51, 99], [15, 5, 0]]) - input_mask = torch.LongTensor([[1, 1, 1], [1, 1, 0]]) - token_type_ids = torch.LongTensor([[0, 0, 1], [0, 1, 0]]) - - config = modeling.BertConfig(vocab_size_or_config_json_file=32000, hidden_size=768, - num_hidden_layers=12, num_attention_heads=12, intermediate_size=3072) - - model = modeling.BertModel(config=config) - all_encoder_layers, pooled_output = model(input_ids, token_type_ids, input_mask) - ``` - """ - - def __init__(self, config): - super(BertModel, self).__init__(config) - self.embeddings = BertEmbeddings(config) - self.encoder = BertEncoder(config) - self.pooler = BertPooler(config) - self.apply(self.init_bert_weights) - - def forward(self, input_ids, token_type_ids=None, attention_mask=None, - output_all_encoded_layers=True, output_att=True): - - if attention_mask is None: - attention_mask = torch.ones_like(input_ids) - if token_type_ids is None: - token_type_ids = torch.zeros_like(input_ids) - - # We create a 3D attention mask from a 2D tensor mask. - # Sizes are [batch_size, 1, 1, to_seq_length] - # So we can broadcast to [batch_size, num_heads, from_seq_length, to_seq_length] - # this attention mask is more simple than the triangular masking of causal attention - # used in OpenAI GPT, we just need to prepare the broadcast dimension here. - extended_attention_mask = attention_mask.unsqueeze(1).unsqueeze(2) - - # Since attention_mask is 1.0 for positions we want to attend and 0.0 for - # masked positions, this operation will create a tensor which is 0.0 for - # positions we want to attend and -10000.0 for masked positions. - # Since we are adding it to the raw scores before the softmax, this is - # effectively the same as removing these entirely. - extended_attention_mask = extended_attention_mask.to( - dtype=next(self.parameters()).dtype) # fp16 compatibility - extended_attention_mask = (1.0 - extended_attention_mask) * -10000.0 - - embedding_output = self.embeddings(input_ids, token_type_ids) - encoded_layers, layer_atts = self.encoder(embedding_output, - extended_attention_mask) - - pooled_output = self.pooler(encoded_layers) - if not output_all_encoded_layers: - encoded_layers = encoded_layers[-1] - - if not output_att: - return encoded_layers, pooled_output - - return encoded_layers, layer_atts, pooled_output - - -class BertForPreTraining(BertPreTrainedModel): - """BERT model with pre-training heads. - This module comprises the BERT model followed by the two pre-training heads: - - the masked language modeling head, and - - the next sentence classification head. - - Params: - config: a BertConfig class instance with the configuration to build a new model. - - Inputs: - `input_ids`: a torch.LongTensor of shape [batch_size, sequence_length] - with the word token indices in the vocabulary(see the tokens preprocessing logic in the scripts - `extract_features.py`, `run_classifier.py` and `run_squad.py`) - `token_type_ids`: an optional torch.LongTensor of shape [batch_size, sequence_length] with the token - types indices selected in [0, 1]. Type 0 corresponds to a `sentence A` and type 1 corresponds to - a `sentence B` token (see BERT paper for more details). - `attention_mask`: an optional torch.LongTensor of shape [batch_size, sequence_length] with indices - selected in [0, 1]. It's a mask to be used if the input sequence length is smaller than the max - input sequence length in the current batch. It's the mask that we typically use for attention when - a batch has varying length sentences. - `masked_lm_labels`: optional masked language modeling labels: torch.LongTensor of shape [batch_size, sequence_length] - with indices selected in [-1, 0, ..., vocab_size]. All labels set to -1 are ignored (masked), the loss - is only computed for the labels set in [0, ..., vocab_size] - `next_sentence_label`: optional next sentence classification loss: torch.LongTensor of shape [batch_size] - with indices selected in [0, 1]. - 0 => next sentence is the continuation, 1 => next sentence is a random sentence. - - Outputs: - if `masked_lm_labels` and `next_sentence_label` are not `None`: - Outputs the total_loss which is the sum of the masked language modeling loss and the next - sentence classification loss. - if `masked_lm_labels` or `next_sentence_label` is `None`: - Outputs a tuple comprising - - the masked language modeling logits of shape [batch_size, sequence_length, vocab_size], and - - the next sentence classification logits of shape [batch_size, 2]. - - Example usage: - ```python - # Already been converted into WordPiece token ids - input_ids = torch.LongTensor([[31, 51, 99], [15, 5, 0]]) - input_mask = torch.LongTensor([[1, 1, 1], [1, 1, 0]]) - token_type_ids = torch.LongTensor([[0, 0, 1], [0, 1, 0]]) - - config = BertConfig(vocab_size_or_config_json_file=32000, hidden_size=768, - num_hidden_layers=12, num_attention_heads=12, intermediate_size=3072) - - model = BertForPreTraining(config) - masked_lm_logits_scores, seq_relationship_logits = model(input_ids, token_type_ids, input_mask) - ``` - """ - - def __init__(self, config): - super(BertForPreTraining, self).__init__(config) - self.bert = BertModel(config) - self.cls = BertPreTrainingHeads( - config, self.bert.embeddings.word_embeddings.weight) - self.apply(self.init_bert_weights) - - def forward(self, input_ids, token_type_ids=None, attention_mask=None, - masked_lm_labels=None, next_sentence_label=None): - sequence_output, pooled_output = self.bert(input_ids, token_type_ids, attention_mask, - output_all_encoded_layers=False) - prediction_scores, seq_relationship_score = self.cls( - sequence_output, pooled_output) - - if masked_lm_labels is not None and next_sentence_label is not None: - loss_fct = CrossEntropyLoss(ignore_index=-1) - masked_lm_loss = loss_fct( - prediction_scores.view(-1, self.config.vocab_size), masked_lm_labels.view(-1)) - next_sentence_loss = loss_fct( - seq_relationship_score.view(-1, 2), next_sentence_label.view(-1)) - total_loss = masked_lm_loss + next_sentence_loss - return total_loss - elif masked_lm_labels is not None: - loss_fct = CrossEntropyLoss(ignore_index=-1) - masked_lm_loss = loss_fct( - prediction_scores.view(-1, self.config.vocab_size), masked_lm_labels.view(-1)) - total_loss = masked_lm_loss - return total_loss - else: - return prediction_scores, seq_relationship_score - - -class TinyBertForPreTraining(BertPreTrainedModel): - def __init__(self, config, fit_size=768): - super(TinyBertForPreTraining, self).__init__(config) - self.bert = BertModel(config) - self.cls = BertPreTrainingHeads( - config, self.bert.embeddings.word_embeddings.weight) - self.fit_dense = nn.Linear(config.hidden_size, fit_size) - self.apply(self.init_bert_weights) - - def forward(self, input_ids, token_type_ids=None, - attention_mask=None, masked_lm_labels=None, - next_sentence_label=None, labels=None): - sequence_output, att_output, pooled_output = self.bert( - input_ids, token_type_ids, attention_mask) - tmp = [] - for s_id, sequence_layer in enumerate(sequence_output): - tmp.append(self.fit_dense(sequence_layer)) - sequence_output = tmp - - return att_output, sequence_output - - -class BertForMaskedLM(BertPreTrainedModel): - """BERT model with the masked language modeling head. - This module comprises the BERT model followed by the masked language modeling head. - - Params: - config: a BertConfig class instance with the configuration to build a new model. - - Inputs: - `input_ids`: a torch.LongTensor of shape [batch_size, sequence_length] - with the word token indices in the vocabulary(see the tokens preprocessing logic in the scripts - `extract_features.py`, `run_classifier.py` and `run_squad.py`) - `token_type_ids`: an optional torch.LongTensor of shape [batch_size, sequence_length] with the token - types indices selected in [0, 1]. Type 0 corresponds to a `sentence A` and type 1 corresponds to - a `sentence B` token (see BERT paper for more details). - `attention_mask`: an optional torch.LongTensor of shape [batch_size, sequence_length] with indices - selected in [0, 1]. It's a mask to be used if the input sequence length is smaller than the max - input sequence length in the current batch. It's the mask that we typically use for attention when - a batch has varying length sentences. - `masked_lm_labels`: masked language modeling labels: torch.LongTensor of shape [batch_size, sequence_length] - with indices selected in [-1, 0, ..., vocab_size]. All labels set to -1 are ignored (masked), the loss - is only computed for the labels set in [0, ..., vocab_size] - - Outputs: - if `masked_lm_labels` is not `None`: - Outputs the masked language modeling loss. - if `masked_lm_labels` is `None`: - Outputs the masked language modeling logits of shape [batch_size, sequence_length, vocab_size]. - - Example usage: - ```python - # Already been converted into WordPiece token ids - input_ids = torch.LongTensor([[31, 51, 99], [15, 5, 0]]) - input_mask = torch.LongTensor([[1, 1, 1], [1, 1, 0]]) - token_type_ids = torch.LongTensor([[0, 0, 1], [0, 1, 0]]) - - config = BertConfig(vocab_size_or_config_json_file=32000, hidden_size=768, - num_hidden_layers=12, num_attention_heads=12, intermediate_size=3072) - - model = BertForMaskedLM(config) - masked_lm_logits_scores = model(input_ids, token_type_ids, input_mask) - ``` - """ - - def __init__(self, config): - super(BertForMaskedLM, self).__init__(config) - self.bert = BertModel(config) - self.cls = BertOnlyMLMHead( - config, self.bert.embeddings.word_embeddings.weight) - self.apply(self.init_bert_weights) - - def forward(self, input_ids, token_type_ids=None, attention_mask=None, masked_lm_labels=None, - output_att=False, infer=False): - sequence_output, _ = self.bert(input_ids, token_type_ids, attention_mask, - output_all_encoded_layers=True, output_att=output_att) - - if output_att: - sequence_output, att_output = sequence_output - prediction_scores = self.cls(sequence_output[-1]) - - if masked_lm_labels is not None: - loss_fct = CrossEntropyLoss(ignore_index=-1) - masked_lm_loss = loss_fct( - prediction_scores.view(-1, self.config.vocab_size), masked_lm_labels.view(-1)) - if not output_att: - return masked_lm_loss - else: - return masked_lm_loss, att_output - else: - if not output_att: - return prediction_scores - else: - return prediction_scores, att_output - - -class BertForNextSentencePrediction(BertPreTrainedModel): - """BERT model with next sentence prediction head. - This module comprises the BERT model followed by the next sentence classification head. - - Params: - config: a BertConfig class instance with the configuration to build a new model. - - Inputs: - `input_ids`: a torch.LongTensor of shape [batch_size, sequence_length] - with the word token indices in the vocabulary(see the tokens preprocessing logic in the scripts - `extract_features.py`, `run_classifier.py` and `run_squad.py`) - `token_type_ids`: an optional torch.LongTensor of shape [batch_size, sequence_length] with the token - types indices selected in [0, 1]. Type 0 corresponds to a `sentence A` and type 1 corresponds to - a `sentence B` token (see BERT paper for more details). - `attention_mask`: an optional torch.LongTensor of shape [batch_size, sequence_length] with indices - selected in [0, 1]. It's a mask to be used if the input sequence length is smaller than the max - input sequence length in the current batch. It's the mask that we typically use for attention when - a batch has varying length sentences. - `next_sentence_label`: next sentence classification loss: torch.LongTensor of shape [batch_size] - with indices selected in [0, 1]. - 0 => next sentence is the continuation, 1 => next sentence is a random sentence. - - Outputs: - if `next_sentence_label` is not `None`: - Outputs the total_loss which is the sum of the masked language modeling loss and the next - sentence classification loss. - if `next_sentence_label` is `None`: - Outputs the next sentence classification logits of shape [batch_size, 2]. - - Example usage: - ```python - # Already been converted into WordPiece token ids - input_ids = torch.LongTensor([[31, 51, 99], [15, 5, 0]]) - input_mask = torch.LongTensor([[1, 1, 1], [1, 1, 0]]) - token_type_ids = torch.LongTensor([[0, 0, 1], [0, 1, 0]]) - - config = BertConfig(vocab_size_or_config_json_file=32000, hidden_size=768, - num_hidden_layers=12, num_attention_heads=12, intermediate_size=3072) - - model = BertForNextSentencePrediction(config) - seq_relationship_logits = model(input_ids, token_type_ids, input_mask) - ``` - """ - - def __init__(self, config): - super(BertForNextSentencePrediction, self).__init__(config) - self.bert = BertModel(config) - self.cls = BertOnlyNSPHead(config) - self.apply(self.init_bert_weights) - - def forward(self, input_ids, token_type_ids=None, attention_mask=None, next_sentence_label=None): - _, pooled_output = self.bert(input_ids, token_type_ids, attention_mask, - output_all_encoded_layers=False) - seq_relationship_score = self.cls(pooled_output) - - if next_sentence_label is not None: - loss_fct = CrossEntropyLoss(ignore_index=-1) - next_sentence_loss = loss_fct( - seq_relationship_score.view(-1, 2), next_sentence_label.view(-1)) - return next_sentence_loss - else: - return seq_relationship_score - - -class BertForSentencePairClassification(BertPreTrainedModel): - def __init__(self, config, num_labels): - super(BertForSentencePairClassification, self).__init__(config) - self.num_labels = num_labels - self.bert = BertModel(config) - self.dropout = nn.Dropout(config.hidden_dropout_prob) - self.classifier = nn.Linear(config.hidden_size * 3, num_labels) - self.apply(self.init_bert_weights) - - def forward(self, a_input_ids, b_input_ids, a_token_type_ids=None, b_token_type_ids=None, - a_attention_mask=None, b_attention_mask=None, labels=None): - _, a_pooled_output = self.bert( - a_input_ids, a_token_type_ids, a_attention_mask, output_all_encoded_layers=False) - # a_pooled_output = self.dropout(a_pooled_output) - - _, b_pooled_output = self.bert( - b_input_ids, b_token_type_ids, b_attention_mask, output_all_encoded_layers=False) - # b_pooled_output = self.dropout(b_pooled_output) - - logits = self.classifier(torch.relu(torch.cat((a_pooled_output, b_pooled_output, - torch.abs(a_pooled_output - b_pooled_output)), -1))) - - if labels is not None: - loss_fct = CrossEntropyLoss() - loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1)) - return loss - else: - return logits - - -class TinyBertForSequenceClassification_for_finetune(BertPreTrainedModel): - def __init__(self, config, num_labels, fit_size=768): - super(TinyBertForSequenceClassification_for_finetune, self).__init__(config) - self.num_labels = num_labels - self.bert = BertModel(config) - self.dropout = nn.Dropout(config.hidden_dropout_prob) - self.classifier = nn.Linear(config.hidden_size, num_labels) - self.fit_dense = nn.Linear(config.hidden_size, fit_size) - self.apply(self.init_bert_weights) - - def forward(self, input_ids, token_type_ids=None, attention_mask=None, - labels=None, is_student=False): - - sequence_output, att_output, pooled_output = self.bert(input_ids, token_type_ids, attention_mask, - output_all_encoded_layers=True, output_att=True) - - logits = self.classifier(torch.relu(pooled_output)) - - tmp = [] - if is_student: - for s_id, sequence_layer in enumerate(sequence_output): - tmp.append(self.fit_dense(sequence_layer)) - sequence_output = tmp - return logits, att_output, sequence_output +# coding=utf-8 +# Copyright 2018 The Google AI Language Team Authors and The HuggingFace Inc. team. +# Copyright (c) 2018, NVIDIA CORPORATION. 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. +"""PyTorch BERT model.""" + +from __future__ import absolute_import, division, print_function, unicode_literals + +import copy +import json +import logging +import math +import os +import shutil +import tarfile +import tempfile +import sys +from io import open + +import torch +import torch.nn.functional as F +from torch import nn +from torch.nn import CrossEntropyLoss +from torch.autograd import Variable +from torch.nn.parameter import Parameter + +from .file_utils import WEIGHTS_NAME, CONFIG_NAME + +logger = logging.getLogger(__name__) + +PRETRAINED_MODEL_ARCHIVE_MAP = { + 'bert-base-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-uncased.tar.gz", + 'bert-large-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-uncased.tar.gz", + 'bert-base-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-cased.tar.gz", + 'bert-large-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-cased.tar.gz", + 'bert-base-multilingual-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-multilingual-uncased.tar.gz", + 'bert-base-multilingual-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-multilingual-cased.tar.gz", + 'bert-base-chinese': "", +} + +BERT_CONFIG_NAME = 'bert_config.json' +TF_WEIGHTS_NAME = 'model.ckpt' + + +def load_tf_weights_in_bert(model, tf_checkpoint_path): + """ Load tf checkpoints in a pytorch model + """ + try: + import re + import numpy as np + import tensorflow as tf + except ImportError: + print("Loading a TensorFlow models in PyTorch, requires TensorFlow to be installed. Please see " + "https://www.tensorflow.org/install/ for installation instructions.") + raise + tf_path = os.path.abspath(tf_checkpoint_path) + print("Converting TensorFlow checkpoint from {}".format(tf_path)) + # Load weights from TF model + init_vars = tf.train.list_variables(tf_path) + names = [] + arrays = [] + for name, shape in init_vars: + print("Loading TF weight {} with shape {}".format(name, shape)) + array = tf.train.load_variable(tf_path, name) + names.append(name) + arrays.append(array) + + for name, array in zip(names, arrays): + name = name.split('/') + # adam_v and adam_m are variables used in AdamWeightDecayOptimizer to calculated m and v + # which are not required for using pretrained model + if any(n in ["adam_v", "adam_m", "global_step"] for n in name): + print("Skipping {}".format("/".join(name))) + continue + pointer = model + for m_name in name: + if re.fullmatch(r'[A-Za-z]+_\d+', m_name): + l = re.split(r'_(\d+)', m_name) + else: + l = [m_name] + if l[0] == 'kernel' or l[0] == 'gamma': + pointer = getattr(pointer, 'weight') + elif l[0] == 'output_bias' or l[0] == 'beta': + try: + pointer = getattr(pointer, 'bias') + except AttributeError: + print("Skipping {}".format("/".join(name))) + continue + elif l[0] == 'output_weights': + pointer = getattr(pointer, 'weight') + elif l[0] == 'squad': + pointer = getattr(pointer, 'classifier') + else: + try: + pointer = getattr(pointer, l[0]) + except AttributeError: + print("Skipping {}".format("/".join(name))) + continue + if len(l) >= 2: + num = int(l[1]) + pointer = pointer[num] + if m_name[-11:] == '_embeddings': + pointer = getattr(pointer, 'weight') + elif m_name == 'kernel': + array = np.transpose(array) + try: + assert pointer.shape == array.shape + except AssertionError as e: + e.args += (pointer.shape, array.shape) + raise + print("Initialize PyTorch weight {}".format(name)) + pointer.data = torch.from_numpy(array) + return model + + +def gelu(x): + """Implementation of the gelu activation function. + For information: OpenAI GPT's gelu is slightly different (and gives slightly different results): + 0.5 * x * (1 + torch.tanh(math.sqrt(2 / math.pi) * (x + 0.044715 * torch.pow(x, 3)))) + Also see https://arxiv.org/abs/1606.08415 + """ + return x * 0.5 * (1.0 + torch.erf(x / math.sqrt(2.0))) + + +def swish(x): + return x * torch.sigmoid(x) + +''' + +try: + from apex.normalization.fused_layer_norm import FusedLayerNorm as BertLayerNorm +except ImportError: + logger.info( + "Better speed can be achieved with apex installed from https://www.github.com/nvidia/apex .") +''' +class BertLayerNorm(nn.Module): + def __init__(self, hidden_size, eps=1e-12): + """Construct a layernorm module in the TF style (epsilon inside the square root). + """ + super(BertLayerNorm, self).__init__() + self.weight = nn.Parameter(torch.ones(hidden_size)) + self.bias = nn.Parameter(torch.zeros(hidden_size)) + self.variance_epsilon = eps + + def forward(self, x): + u = x.mean(-1, keepdim=True) + s = (x - u).pow(2).mean(-1, keepdim=True) + x = (x - u) / torch.sqrt(s + self.variance_epsilon) + return self.weight * x + self.bias + + +class HeadAttention(nn.Module): + def __init__(self, config, hidden_size, head_num, head_used): + super(HeadAttention, self).__init__() + self.head_num = head_num + self.head_used = head_used + self.hidden_size = hidden_size + if self.hidden_size % self.head_num != 0: + raise ValueError( + "The hidden size (%d) is not a multiple of the number of attention " + "heads (%d)" % (self.hidden_size, self.head_num)) + + self.attention_head_size = int(self.hidden_size / self.head_num) + self.all_head_size = self.num_heads_used * self.attention_head_size + + self.query = nn.Linear(self.hidden_size, self.all_head_size) + self.key = nn.Linear(self.hidden_size, self.all_head_size) + self.value = nn.Linear(self.hidden_size, self.all_head_size) + + self.dropout = nn.Dropout(config.attention_probs_dropout_prob) + + def transpose_for_scores(self, x): + new_x_shape = x.size()[:-1] + (self.num_heads_used, + self.attention_head_size) + x = x.view(*new_x_shape) + return x.permute(0, 2, 1, 3) + + def forward(self, hidden_states, attention_mask): + mixed_query_layer = self.query(hidden_states) + mixed_key_layer = self.key(hidden_states) + mixed_value_layer = self.value(hidden_states) + + query_layer = self.transpose_for_scores(mixed_query_layer) + key_layer = self.transpose_for_scores(mixed_key_layer) + value_layer = self.transpose_for_scores(mixed_value_layer) + + # Take the dot product between "query" and "key" to get the raw attention scores. + attention_scores = torch.matmul( + query_layer, key_layer.transpose(-1, -2)) + attention_scores = attention_scores / \ + math.sqrt(self.attention_head_size) + # Apply the attention mask is (precomputed for all layers in BertModel forward() function) + attention_scores = attention_scores + attention_mask + + # Normalize the attention scores to probabilities. + attention_probs = nn.Softmax(dim=-1)(attention_scores) + + # This is actually dropping out entire tokens to attend to, which might + # seem a bit unusual, but is taken from the original Transformer paper. + attention_probs = self.dropout(attention_probs) + + context_layer = torch.matmul(attention_probs, value_layer) + context_layer = context_layer.permute(0, 2, 1, 3).contiguous() + new_context_layer_shape = context_layer.size()[ + :-2] + (self.all_head_size,) + context_layer = context_layer.view(*new_context_layer_shape) + + if self.num_heads_used != self.num_attention_heads: + pad_shape = context_layer.size()[:-1] + \ + ((self.num_attention_heads - self.num_heads_used) + * self.attention_head_size, ) + + pad_layer = torch.zeros(*pad_shape).to(context_layer.device) + context_layer = torch.cat((context_layer, pad_layer), -1) + return context_layer + + +ACT2FN = {"gelu": gelu, "relu": torch.nn.functional.relu} +NORM = {'layer_norm': BertLayerNorm} + + +class BertConfig(object): + """Configuration class to store the configuration of a `BertModel`. + """ + + def __init__(self, + vocab_size_or_config_json_file, + hidden_size=768, + num_hidden_layers=12, + num_attention_heads=12, + intermediate_size=3072, + hidden_act="gelu", + hidden_dropout_prob=0.1, + attention_probs_dropout_prob=0.1, + max_position_embeddings=512, + type_vocab_size=2, + initializer_range=0.02, + pre_trained='', + training=''): + """Constructs BertConfig. + + Args: + vocab_size_or_config_json_file: Vocabulary size of `inputs_ids` in `BertModel`. + hidden_size: Size of the encoder layers and the pooler layer. + num_hidden_layers: Number of hidden layers in the Transformer encoder. + num_attention_heads: Number of attention heads for each attention layer in + the Transformer encoder. + intermediate_size: The size of the "intermediate" (i.e., feed-forward) + layer in the Transformer encoder. + hidden_act: The non-linear activation function (function or string) in the + encoder and pooler. If string, "gelu", "relu" and "swish" are supported. + hidden_dropout_prob: The dropout probabilitiy for all fully connected + layers in the embeddings, encoder, and pooler. + attention_probs_dropout_prob: The dropout ratio for the attention + probabilities. + max_position_embeddings: The maximum sequence length that this model might + ever be used with. Typically set this to something large just in case + (e.g., 512 or 1024 or 2048). + type_vocab_size: The vocabulary size of the `token_type_ids` passed into + `BertModel`. + initializer_range: The sttdev of the truncated_normal_initializer for + initializing all weight matrices. + """ + if isinstance(vocab_size_or_config_json_file, str) or (sys.version_info[0] == 2 + and isinstance(vocab_size_or_config_json_file, unicode)): + with open(vocab_size_or_config_json_file, "r", encoding='utf-8') as reader: + json_config = json.loads(reader.read()) + for key, value in json_config.items(): + self.__dict__[key] = value + elif isinstance(vocab_size_or_config_json_file, int): + self.vocab_size = vocab_size_or_config_json_file + self.hidden_size = hidden_size + self.num_hidden_layers = num_hidden_layers + self.num_attention_heads = num_attention_heads + self.hidden_act = hidden_act + self.intermediate_size = intermediate_size + self.hidden_dropout_prob = hidden_dropout_prob + self.attention_probs_dropout_prob = attention_probs_dropout_prob + self.max_position_embeddings = max_position_embeddings + self.type_vocab_size = type_vocab_size + self.initializer_range = initializer_range + self.pre_trained = pre_trained + self.training = training + else: + raise ValueError("First argument must be either a vocabulary size (int)" + "or the path to a pretrained model config file (str)") + + @classmethod + def from_dict(cls, json_object): + """Constructs a `BertConfig` from a Python dictionary of parameters.""" + config = BertConfig(vocab_size_or_config_json_file=-1) + for key, value in json_object.items(): + config.__dict__[key] = value + return config + + @classmethod + def from_json_file(cls, json_file): + """Constructs a `BertConfig` from a json file of parameters.""" + with open(json_file, "r", encoding='utf-8') as reader: + text = reader.read() + return cls.from_dict(json.loads(text)) + + def __repr__(self): + return str(self.to_json_string()) + + def to_dict(self): + """Serializes this instance to a Python dictionary.""" + output = copy.deepcopy(self.__dict__) + return output + + def to_json_string(self): + """Serializes this instance to a JSON string.""" + return json.dumps(self.to_dict(), indent=2, sort_keys=True) + "\n" + + def to_json_file(self, json_file_path): + """ Save this instance to a json file.""" + with open(json_file_path, "w", encoding='utf-8') as writer: + writer.write(self.to_json_string()) + + +class BertEmbeddings(nn.Module): + """Construct the embeddings from word, position and token_type embeddings. + """ + + def __init__(self, config): + super(BertEmbeddings, self).__init__() + self.word_embeddings = nn.Embedding( + config.vocab_size, config.hidden_size, padding_idx=0) + self.position_embeddings = nn.Embedding( + config.max_position_embeddings, config.hidden_size) + self.token_type_embeddings = nn.Embedding( + config.type_vocab_size, config.hidden_size) + + # self.LayerNorm is not snake-cased to stick with TensorFlow model variable name and be able to load + # any TensorFlow checkpoint file + self.LayerNorm = BertLayerNorm(config.hidden_size, eps=1e-12) + self.dropout = nn.Dropout(config.hidden_dropout_prob) + + def forward(self, input_ids, token_type_ids=None): + seq_length = input_ids.size(1) + position_ids = torch.arange( + seq_length, dtype=torch.long, device=input_ids.device) + position_ids = position_ids.unsqueeze(0).expand_as(input_ids) + if token_type_ids is None: + token_type_ids = torch.zeros_like(input_ids) + + words_embeddings = self.word_embeddings(input_ids) + position_embeddings = self.position_embeddings(position_ids) + token_type_embeddings = self.token_type_embeddings(token_type_ids) + + embeddings = words_embeddings + position_embeddings + token_type_embeddings + embeddings = self.LayerNorm(embeddings) + embeddings = self.dropout(embeddings) + return embeddings + + +class BertSelfAttention(nn.Module): + def __init__(self, config): + super(BertSelfAttention, self).__init__() + if config.hidden_size % config.num_attention_heads != 0: + raise ValueError( + "The hidden size (%d) is not a multiple of the number of attention " + "heads (%d)" % (config.hidden_size, config.num_attention_heads)) + self.num_attention_heads = config.num_attention_heads + self.attention_head_size = int( + config.hidden_size / config.num_attention_heads) + self.all_head_size = self.num_attention_heads * self.attention_head_size + + self.query = nn.Linear(config.hidden_size, self.all_head_size) + self.key = nn.Linear(config.hidden_size, self.all_head_size) + self.value = nn.Linear(config.hidden_size, self.all_head_size) + + self.dropout = nn.Dropout(config.attention_probs_dropout_prob) + + def transpose_for_scores(self, x): + new_x_shape = x.size()[ + :-1] + (self.num_attention_heads, self.attention_head_size) + x = x.view(*new_x_shape) + return x.permute(0, 2, 1, 3) + + def forward(self, hidden_states, attention_mask, output_att=False): + mixed_query_layer = self.query(hidden_states) + mixed_key_layer = self.key(hidden_states) + mixed_value_layer = self.value(hidden_states) + + query_layer = self.transpose_for_scores(mixed_query_layer) + key_layer = self.transpose_for_scores(mixed_key_layer) + value_layer = self.transpose_for_scores(mixed_value_layer) + + # Take the dot product between "query" and "key" to get the raw attention scores. + attention_scores = torch.matmul( + query_layer, key_layer.transpose(-1, -2)) + attention_scores = attention_scores / \ + math.sqrt(self.attention_head_size) + # Apply the attention mask is (precomputed for all layers in BertModel forward() function) + attention_scores = attention_scores + attention_mask + + # Normalize the attention scores to probabilities. + attention_probs = nn.Softmax(dim=-1)(attention_scores) + + # This is actually dropping out entire tokens to attend to, which might + # seem a bit unusual, but is taken from the original Transformer paper. + attention_probs = self.dropout(attention_probs) + + context_layer = torch.matmul(attention_probs, value_layer) + context_layer = context_layer.permute(0, 2, 1, 3).contiguous() + new_context_layer_shape = context_layer.size()[ + :-2] + (self.all_head_size,) + context_layer = context_layer.view(*new_context_layer_shape) + return context_layer, attention_scores + + +class BertAttention(nn.Module): + def __init__(self, config): + super(BertAttention, self).__init__() + + self.self = BertSelfAttention(config) + self.output = BertSelfOutput(config) + + def forward(self, input_tensor, attention_mask): + self_output, layer_att = self.self(input_tensor, attention_mask) + attention_output = self.output(self_output, input_tensor) + return attention_output, layer_att + + +class BertSelfOutput(nn.Module): + def __init__(self, config): + super(BertSelfOutput, self).__init__() + self.dense = nn.Linear(config.hidden_size, config.hidden_size) + self.LayerNorm = BertLayerNorm(config.hidden_size, eps=1e-12) + self.dropout = nn.Dropout(config.hidden_dropout_prob) + + def forward(self, hidden_states, input_tensor): + hidden_states = self.dense(hidden_states) + hidden_states = self.dropout(hidden_states) + hidden_states = self.LayerNorm(hidden_states + input_tensor) + return hidden_states + + +class BertIntermediate(nn.Module): + def __init__(self, config, intermediate_size=-1): + super(BertIntermediate, self).__init__() + if intermediate_size < 0: + self.dense = nn.Linear( + config.hidden_size, config.intermediate_size) + else: + self.dense = nn.Linear(config.hidden_size, intermediate_size) + if isinstance(config.hidden_act, str) or (sys.version_info[0] == 2 and isinstance(config.hidden_act, unicode)): + self.intermediate_act_fn = ACT2FN[config.hidden_act] + else: + self.intermediate_act_fn = config.hidden_act + + def forward(self, hidden_states): + hidden_states = self.dense(hidden_states) + hidden_states = self.intermediate_act_fn(hidden_states) + return hidden_states + + +class BertOutput(nn.Module): + def __init__(self, config, intermediate_size=-1): + super(BertOutput, self).__init__() + if intermediate_size < 0: + self.dense = nn.Linear( + config.intermediate_size, config.hidden_size) + else: + self.dense = nn.Linear(intermediate_size, config.hidden_size) + self.LayerNorm = BertLayerNorm(config.hidden_size, eps=1e-12) + self.dropout = nn.Dropout(config.hidden_dropout_prob) + + def forward(self, hidden_states, input_tensor): + hidden_states = self.dense(hidden_states) + hidden_states = self.dropout(hidden_states) + hidden_states = self.LayerNorm(hidden_states + input_tensor) + return hidden_states + + +class BertLayer(nn.Module): + def __init__(self, config): + super(BertLayer, self).__init__() + self.attention = BertAttention(config) + self.intermediate = BertIntermediate(config) + self.output = BertOutput(config) + + def forward(self, hidden_states, attention_mask): + attention_output, layer_att = self.attention( + hidden_states, attention_mask) + intermediate_output = self.intermediate(attention_output) + layer_output = self.output(intermediate_output, attention_output) + + return layer_output, layer_att + + +class BertEncoder(nn.Module): + def __init__(self, config): + super(BertEncoder, self).__init__() + self.layer = nn.ModuleList([BertLayer(config) + for _ in range(config.num_hidden_layers)]) + + def forward(self, hidden_states, attention_mask): + all_encoder_layers = [] + all_encoder_atts = [] + for _, layer_module in enumerate(self.layer): + all_encoder_layers.append(hidden_states) + hidden_states, layer_att = layer_module( + hidden_states, attention_mask) + all_encoder_atts.append(layer_att) + + all_encoder_layers.append(hidden_states) + return all_encoder_layers, all_encoder_atts + + +class BertPooler(nn.Module): + def __init__(self, config, recurs=None): + super(BertPooler, self).__init__() + self.dense = nn.Linear(config.hidden_size, config.hidden_size) + self.activation = nn.Tanh() + self.config = config + + def forward(self, hidden_states): + # We "pool" the model by simply taking the hidden state corresponding + # to the first token. "-1" refers to last layer + pooled_output = hidden_states[-1][:, 0] + + pooled_output = self.dense(pooled_output) + pooled_output = self.activation(pooled_output) + + return pooled_output + + +class BertPredictionHeadTransform(nn.Module): + def __init__(self, config): + super(BertPredictionHeadTransform, self).__init__() + # Need to unty it when we separate the dimensions of hidden and emb + self.dense = nn.Linear(config.hidden_size, config.hidden_size) + if isinstance(config.hidden_act, str) or (sys.version_info[0] == 2 and isinstance(config.hidden_act, unicode)): + self.transform_act_fn = ACT2FN[config.hidden_act] + else: + self.transform_act_fn = config.hidden_act + self.LayerNorm = BertLayerNorm(config.hidden_size, eps=1e-12) + + def forward(self, hidden_states): + hidden_states = self.dense(hidden_states) + hidden_states = self.transform_act_fn(hidden_states) + hidden_states = self.LayerNorm(hidden_states) + return hidden_states + + +class BertLMPredictionHead(nn.Module): + def __init__(self, config, bert_model_embedding_weights): + super(BertLMPredictionHead, self).__init__() + self.transform = BertPredictionHeadTransform(config) + + # The output weights are the same as the input embeddings, but there is + # an output-only bias for each token. + self.decoder = nn.Linear(bert_model_embedding_weights.size(1), + bert_model_embedding_weights.size(0), + bias=False) + self.decoder.weight = bert_model_embedding_weights + self.bias = nn.Parameter(torch.zeros( + bert_model_embedding_weights.size(0))) + + def forward(self, hidden_states): + hidden_states = self.transform(hidden_states) + hidden_states = self.decoder(hidden_states) + self.bias + return hidden_states + + +class BertOnlyMLMHead(nn.Module): + def __init__(self, config, bert_model_embedding_weights): + super(BertOnlyMLMHead, self).__init__() + self.predictions = BertLMPredictionHead( + config, bert_model_embedding_weights) + + def forward(self, sequence_output): + prediction_scores = self.predictions(sequence_output) + return prediction_scores + + +class BertOnlyNSPHead(nn.Module): + def __init__(self, config): + super(BertOnlyNSPHead, self).__init__() + self.seq_relationship = nn.Linear(config.hidden_size, 2) + + def forward(self, pooled_output): + seq_relationship_score = self.seq_relationship(pooled_output) + return seq_relationship_score + + +class BertPreTrainingHeads(nn.Module): + def __init__(self, config, bert_model_embedding_weights): + super(BertPreTrainingHeads, self).__init__() + self.predictions = BertLMPredictionHead( + config, bert_model_embedding_weights) + self.seq_relationship = nn.Linear(config.hidden_size, 2) + + def forward(self, sequence_output, pooled_output): + prediction_scores = self.predictions(sequence_output) + seq_relationship_score = self.seq_relationship(pooled_output) + return prediction_scores, seq_relationship_score + + +class BertPreTrainedModel(nn.Module): + """ An abstract class to handle weights initialization and + a simple interface for dowloading and loading pretrained models. + """ + + def __init__(self, config, *inputs, **kwargs): + super(BertPreTrainedModel, self).__init__() + if not isinstance(config, BertConfig): + raise ValueError( + "Parameter config in `{}(config)` should be an instance of class `BertConfig`. " + "To create a model from a Google pretrained model use " + "`model = {}.from_pretrained(PRETRAINED_MODEL_NAME)`".format( + self.__class__.__name__, self.__class__.__name__ + )) + self.config = config + + def init_bert_weights(self, module): + """ Initialize the weights. + """ + if isinstance(module, (nn.Linear, nn.Embedding)): + # Slightly different from the TF version which uses truncated_normal for initialization + # cf https://github.com/pytorch/pytorch/pull/5617 + module.weight.data.normal_( + mean=0.0, std=self.config.initializer_range) + elif isinstance(module, BertLayerNorm): + module.bias.data.zero_() + module.weight.data.fill_(1.0) + if isinstance(module, nn.Linear) and module.bias is not None: + module.bias.data.zero_() + + @classmethod + def from_scratch(cls, pretrained_model_name_or_path, *inputs, **kwargs): + resolved_config_file = os.path.join( + pretrained_model_name_or_path, CONFIG_NAME) + config = BertConfig.from_json_file(resolved_config_file) + + logger.info("Model config {}".format(config)) + model = cls(config, *inputs, **kwargs) + return model + + @classmethod + def from_pretrained(cls, pretrained_model_name_or_path, *inputs, **kwargs): + """ + Instantiate a BertPreTrainedModel from a pre-trained model file or a pytorch state dict. + Download and cache the pre-trained model file if needed. + + Params: + pretrained_model_name_or_path: either: + - a str with the name of a pre-trained model to load selected in the list of: + . `bert-base-uncased` + . `bert-large-uncased` + . `bert-base-cased` + . `bert-large-cased` + . `bert-base-multilingual-uncased` + . `bert-base-multilingual-cased` + . `bert-base-chinese` + - a path or url to a pretrained model archive containing: + . `bert_config.json` a configuration file for the model + . `pytorch_model.bin` a PyTorch dump of a BertForPreTraining instance + - a path or url to a pretrained model archive containing: + . `bert_config.json` a configuration file for the model + . `model.chkpt` a TensorFlow checkpoint + from_tf: should we load the weights from a locally saved TensorFlow checkpoint + cache_dir: an optional path to a folder in which the pre-trained models will be cached. + state_dict: an optional state dictionnary (collections.OrderedDict object) to use instead of Google pre-trained models + *inputs, **kwargs: additional input for the specific Bert class + (ex: num_labels for BertForSequenceClassification) + """ + state_dict = kwargs.get('state_dict', None) + kwargs.pop('state_dict', None) + from_tf = kwargs.get('from_tf', False) + kwargs.pop('from_tf', None) + + # Load config + config_file = os.path.join(pretrained_model_name_or_path, CONFIG_NAME) + config = BertConfig.from_json_file(config_file) + logger.info("Model config {}".format(config)) + # Instantiate model. + + model = cls(config, *inputs, **kwargs) + if state_dict is None and not from_tf: + weights_path = os.path.join( + pretrained_model_name_or_path, WEIGHTS_NAME) + logger.info("Loading model {}".format(weights_path)) + state_dict = torch.load(weights_path, map_location='cpu') + state_dict.pop('classifier.weight') + state_dict.pop('classifier.bias') + if from_tf: + # Directly load from a TensorFlow checkpoint + weights_path = os.path.join( + pretrained_model_name_or_path, TF_WEIGHTS_NAME) + return load_tf_weights_in_bert(model, weights_path) + # Load from a PyTorch state_dict + old_keys = [] + new_keys = [] + for key in state_dict.keys(): + new_key = None + if 'gamma' in key: + new_key = key.replace('gamma', 'weight') + if 'beta' in key: + new_key = key.replace('beta', 'bias') + if new_key: + old_keys.append(key) + new_keys.append(new_key) + for old_key, new_key in zip(old_keys, new_keys): + state_dict[new_key] = state_dict.pop(old_key) + + missing_keys = [] + unexpected_keys = [] + error_msgs = [] + # copy state_dict so _load_from_state_dict can modify it + metadata = getattr(state_dict, '_metadata', None) + state_dict = state_dict.copy() + if metadata is not None: + state_dict._metadata = metadata + + def load(module, prefix=''): + local_metadata = {} if metadata is None else metadata.get( + prefix[:-1], {}) + module._load_from_state_dict( + state_dict, prefix, local_metadata, True, missing_keys, unexpected_keys, error_msgs) + for name, child in module._modules.items(): + if child is not None: + load(child, prefix + name + '.') + + start_prefix = '' + if not hasattr(model, 'bert') and any(s.startswith('bert.') for s in state_dict.keys()): + start_prefix = 'bert.' + + logger.info('loading model...') + load(model, prefix=start_prefix) + logger.info('done!') + if len(missing_keys) > 0: + logger.info("Weights of {} not initialized from pretrained model: {}".format( + model.__class__.__name__, missing_keys)) + if len(unexpected_keys) > 0: + logger.info("Weights from pretrained model not used in {}: {}".format( + model.__class__.__name__, unexpected_keys)) + if len(error_msgs) > 0: + raise RuntimeError('Error(s) in loading state_dict for {}:\n\t{}'.format( + model.__class__.__name__, "\n\t".join(error_msgs))) + + return model + + +class BertModel(BertPreTrainedModel): + """BERT model ("Bidirectional Embedding Representations from a Transformer"). + + Params: + config: a BertConfig class instance with the configuration to build a new model + + Inputs: + `input_ids`: a torch.LongTensor of shape [batch_size, sequence_length] + with the word token indices in the vocabulary(see the tokens preprocessing logic in the scripts + `extract_features.py`, `run_classifier.py` and `run_squad.py`) + `token_type_ids`: an optional torch.LongTensor of shape [batch_size, sequence_length] with the token + types indices selected in [0, 1]. Type 0 corresponds to a `sentence A` and type 1 corresponds to + a `sentence B` token (see BERT paper for more details). + `attention_mask`: an optional torch.LongTensor of shape [batch_size, sequence_length] with indices + selected in [0, 1]. It's a mask to be used if the input sequence length is smaller than the max + input sequence length in the current batch. It's the mask that we typically use for attention when + a batch has varying length sentences. + `output_all_encoded_layers`: boolean which controls the content of the `encoded_layers` output as described below. Default: `True`. + + Outputs: Tuple of (encoded_layers, pooled_output) + `encoded_layers`: controled by `output_all_encoded_layers` argument: + - `output_all_encoded_layers=True`: outputs a list of the full sequences of encoded-hidden-states at the end + of each attention block (i.e. 12 full sequences for BERT-base, 24 for BERT-large), each + encoded-hidden-state is a torch.FloatTensor of size [batch_size, sequence_length, hidden_size], + - `output_all_encoded_layers=False`: outputs only the full sequence of hidden-states corresponding + to the last attention block of shape [batch_size, sequence_length, hidden_size], + `pooled_output`: a torch.FloatTensor of size [batch_size, hidden_size] which is the output of a + classifier pretrained on top of the hidden state associated to the first character of the + input (`CLS`) to train on the Next-Sentence task (see BERT's paper). + + Example usage: + ```python + # Already been converted into WordPiece token ids + input_ids = torch.LongTensor([[31, 51, 99], [15, 5, 0]]) + input_mask = torch.LongTensor([[1, 1, 1], [1, 1, 0]]) + token_type_ids = torch.LongTensor([[0, 0, 1], [0, 1, 0]]) + + config = modeling.BertConfig(vocab_size_or_config_json_file=32000, hidden_size=768, + num_hidden_layers=12, num_attention_heads=12, intermediate_size=3072) + + model = modeling.BertModel(config=config) + all_encoder_layers, pooled_output = model(input_ids, token_type_ids, input_mask) + ``` + """ + + def __init__(self, config): + super(BertModel, self).__init__(config) + self.embeddings = BertEmbeddings(config) + self.encoder = BertEncoder(config) + self.pooler = BertPooler(config) + self.apply(self.init_bert_weights) + + def forward(self, input_ids, token_type_ids=None, attention_mask=None, + output_all_encoded_layers=True, output_att=True): + + if attention_mask is None: + attention_mask = torch.ones_like(input_ids) + if token_type_ids is None: + token_type_ids = torch.zeros_like(input_ids) + + # We create a 3D attention mask from a 2D tensor mask. + # Sizes are [batch_size, 1, 1, to_seq_length] + # So we can broadcast to [batch_size, num_heads, from_seq_length, to_seq_length] + # this attention mask is more simple than the triangular masking of causal attention + # used in OpenAI GPT, we just need to prepare the broadcast dimension here. + extended_attention_mask = attention_mask.unsqueeze(1).unsqueeze(2) + + # Since attention_mask is 1.0 for positions we want to attend and 0.0 for + # masked positions, this operation will create a tensor which is 0.0 for + # positions we want to attend and -10000.0 for masked positions. + # Since we are adding it to the raw scores before the softmax, this is + # effectively the same as removing these entirely. + extended_attention_mask = extended_attention_mask.to( + dtype=next(self.parameters()).dtype) # fp16 compatibility + extended_attention_mask = (1.0 - extended_attention_mask) * -10000.0 + + embedding_output = self.embeddings(input_ids, token_type_ids) + encoded_layers, layer_atts = self.encoder(embedding_output, + extended_attention_mask) + + pooled_output = self.pooler(encoded_layers) + if not output_all_encoded_layers: + encoded_layers = encoded_layers[-1] + + if not output_att: + return encoded_layers, pooled_output + + return encoded_layers, layer_atts, pooled_output + + +class BertForPreTraining(BertPreTrainedModel): + """BERT model with pre-training heads. + This module comprises the BERT model followed by the two pre-training heads: + - the masked language modeling head, and + - the next sentence classification head. + + Params: + config: a BertConfig class instance with the configuration to build a new model. + + Inputs: + `input_ids`: a torch.LongTensor of shape [batch_size, sequence_length] + with the word token indices in the vocabulary(see the tokens preprocessing logic in the scripts + `extract_features.py`, `run_classifier.py` and `run_squad.py`) + `token_type_ids`: an optional torch.LongTensor of shape [batch_size, sequence_length] with the token + types indices selected in [0, 1]. Type 0 corresponds to a `sentence A` and type 1 corresponds to + a `sentence B` token (see BERT paper for more details). + `attention_mask`: an optional torch.LongTensor of shape [batch_size, sequence_length] with indices + selected in [0, 1]. It's a mask to be used if the input sequence length is smaller than the max + input sequence length in the current batch. It's the mask that we typically use for attention when + a batch has varying length sentences. + `masked_lm_labels`: optional masked language modeling labels: torch.LongTensor of shape [batch_size, sequence_length] + with indices selected in [-1, 0, ..., vocab_size]. All labels set to -1 are ignored (masked), the loss + is only computed for the labels set in [0, ..., vocab_size] + `next_sentence_label`: optional next sentence classification loss: torch.LongTensor of shape [batch_size] + with indices selected in [0, 1]. + 0 => next sentence is the continuation, 1 => next sentence is a random sentence. + + Outputs: + if `masked_lm_labels` and `next_sentence_label` are not `None`: + Outputs the total_loss which is the sum of the masked language modeling loss and the next + sentence classification loss. + if `masked_lm_labels` or `next_sentence_label` is `None`: + Outputs a tuple comprising + - the masked language modeling logits of shape [batch_size, sequence_length, vocab_size], and + - the next sentence classification logits of shape [batch_size, 2]. + + Example usage: + ```python + # Already been converted into WordPiece token ids + input_ids = torch.LongTensor([[31, 51, 99], [15, 5, 0]]) + input_mask = torch.LongTensor([[1, 1, 1], [1, 1, 0]]) + token_type_ids = torch.LongTensor([[0, 0, 1], [0, 1, 0]]) + + config = BertConfig(vocab_size_or_config_json_file=32000, hidden_size=768, + num_hidden_layers=12, num_attention_heads=12, intermediate_size=3072) + + model = BertForPreTraining(config) + masked_lm_logits_scores, seq_relationship_logits = model(input_ids, token_type_ids, input_mask) + ``` + """ + + def __init__(self, config): + super(BertForPreTraining, self).__init__(config) + self.bert = BertModel(config) + self.cls = BertPreTrainingHeads( + config, self.bert.embeddings.word_embeddings.weight) + self.apply(self.init_bert_weights) + + def forward(self, input_ids, token_type_ids=None, attention_mask=None, + masked_lm_labels=None, next_sentence_label=None): + sequence_output, pooled_output = self.bert(input_ids, token_type_ids, attention_mask, + output_all_encoded_layers=False) + prediction_scores, seq_relationship_score = self.cls( + sequence_output, pooled_output) + + if masked_lm_labels is not None and next_sentence_label is not None: + loss_fct = CrossEntropyLoss(ignore_index=-1) + masked_lm_loss = loss_fct( + prediction_scores.view(-1, self.config.vocab_size), masked_lm_labels.view(-1)) + next_sentence_loss = loss_fct( + seq_relationship_score.view(-1, 2), next_sentence_label.view(-1)) + total_loss = masked_lm_loss + next_sentence_loss + return total_loss + elif masked_lm_labels is not None: + loss_fct = CrossEntropyLoss(ignore_index=-1) + masked_lm_loss = loss_fct( + prediction_scores.view(-1, self.config.vocab_size), masked_lm_labels.view(-1)) + total_loss = masked_lm_loss + return total_loss + else: + return prediction_scores, seq_relationship_score + + +class TinyBertForPreTraining(BertPreTrainedModel): + def __init__(self, config, fit_size=768): + super(TinyBertForPreTraining, self).__init__(config) + self.bert = BertModel(config) + self.cls = BertPreTrainingHeads( + config, self.bert.embeddings.word_embeddings.weight) + self.fit_dense = nn.Linear(config.hidden_size, fit_size) + self.apply(self.init_bert_weights) + + def forward(self, input_ids, token_type_ids=None, + attention_mask=None, masked_lm_labels=None, + next_sentence_label=None, labels=None): + sequence_output, att_output, pooled_output = self.bert( + input_ids, token_type_ids, attention_mask) + tmp = [] + for s_id, sequence_layer in enumerate(sequence_output): + tmp.append(self.fit_dense(sequence_layer)) + sequence_output = tmp + + return att_output, sequence_output + + +class BertForMaskedLM(BertPreTrainedModel): + """BERT model with the masked language modeling head. + This module comprises the BERT model followed by the masked language modeling head. + + Params: + config: a BertConfig class instance with the configuration to build a new model. + + Inputs: + `input_ids`: a torch.LongTensor of shape [batch_size, sequence_length] + with the word token indices in the vocabulary(see the tokens preprocessing logic in the scripts + `extract_features.py`, `run_classifier.py` and `run_squad.py`) + `token_type_ids`: an optional torch.LongTensor of shape [batch_size, sequence_length] with the token + types indices selected in [0, 1]. Type 0 corresponds to a `sentence A` and type 1 corresponds to + a `sentence B` token (see BERT paper for more details). + `attention_mask`: an optional torch.LongTensor of shape [batch_size, sequence_length] with indices + selected in [0, 1]. It's a mask to be used if the input sequence length is smaller than the max + input sequence length in the current batch. It's the mask that we typically use for attention when + a batch has varying length sentences. + `masked_lm_labels`: masked language modeling labels: torch.LongTensor of shape [batch_size, sequence_length] + with indices selected in [-1, 0, ..., vocab_size]. All labels set to -1 are ignored (masked), the loss + is only computed for the labels set in [0, ..., vocab_size] + + Outputs: + if `masked_lm_labels` is not `None`: + Outputs the masked language modeling loss. + if `masked_lm_labels` is `None`: + Outputs the masked language modeling logits of shape [batch_size, sequence_length, vocab_size]. + + Example usage: + ```python + # Already been converted into WordPiece token ids + input_ids = torch.LongTensor([[31, 51, 99], [15, 5, 0]]) + input_mask = torch.LongTensor([[1, 1, 1], [1, 1, 0]]) + token_type_ids = torch.LongTensor([[0, 0, 1], [0, 1, 0]]) + + config = BertConfig(vocab_size_or_config_json_file=32000, hidden_size=768, + num_hidden_layers=12, num_attention_heads=12, intermediate_size=3072) + + model = BertForMaskedLM(config) + masked_lm_logits_scores = model(input_ids, token_type_ids, input_mask) + ``` + """ + + def __init__(self, config): + super(BertForMaskedLM, self).__init__(config) + self.bert = BertModel(config) + self.cls = BertOnlyMLMHead( + config, self.bert.embeddings.word_embeddings.weight) + self.apply(self.init_bert_weights) + + def forward(self, input_ids, token_type_ids=None, attention_mask=None, masked_lm_labels=None, + output_att=False, infer=False): + sequence_output, _ = self.bert(input_ids, token_type_ids, attention_mask, + output_all_encoded_layers=True, output_att=output_att) + + if output_att: + sequence_output, att_output = sequence_output + prediction_scores = self.cls(sequence_output[-1]) + + if masked_lm_labels is not None: + loss_fct = CrossEntropyLoss(ignore_index=-1) + masked_lm_loss = loss_fct( + prediction_scores.view(-1, self.config.vocab_size), masked_lm_labels.view(-1)) + if not output_att: + return masked_lm_loss + else: + return masked_lm_loss, att_output + else: + if not output_att: + return prediction_scores + else: + return prediction_scores, att_output + + +class BertForNextSentencePrediction(BertPreTrainedModel): + """BERT model with next sentence prediction head. + This module comprises the BERT model followed by the next sentence classification head. + + Params: + config: a BertConfig class instance with the configuration to build a new model. + + Inputs: + `input_ids`: a torch.LongTensor of shape [batch_size, sequence_length] + with the word token indices in the vocabulary(see the tokens preprocessing logic in the scripts + `extract_features.py`, `run_classifier.py` and `run_squad.py`) + `token_type_ids`: an optional torch.LongTensor of shape [batch_size, sequence_length] with the token + types indices selected in [0, 1]. Type 0 corresponds to a `sentence A` and type 1 corresponds to + a `sentence B` token (see BERT paper for more details). + `attention_mask`: an optional torch.LongTensor of shape [batch_size, sequence_length] with indices + selected in [0, 1]. It's a mask to be used if the input sequence length is smaller than the max + input sequence length in the current batch. It's the mask that we typically use for attention when + a batch has varying length sentences. + `next_sentence_label`: next sentence classification loss: torch.LongTensor of shape [batch_size] + with indices selected in [0, 1]. + 0 => next sentence is the continuation, 1 => next sentence is a random sentence. + + Outputs: + if `next_sentence_label` is not `None`: + Outputs the total_loss which is the sum of the masked language modeling loss and the next + sentence classification loss. + if `next_sentence_label` is `None`: + Outputs the next sentence classification logits of shape [batch_size, 2]. + + Example usage: + ```python + # Already been converted into WordPiece token ids + input_ids = torch.LongTensor([[31, 51, 99], [15, 5, 0]]) + input_mask = torch.LongTensor([[1, 1, 1], [1, 1, 0]]) + token_type_ids = torch.LongTensor([[0, 0, 1], [0, 1, 0]]) + + config = BertConfig(vocab_size_or_config_json_file=32000, hidden_size=768, + num_hidden_layers=12, num_attention_heads=12, intermediate_size=3072) + + model = BertForNextSentencePrediction(config) + seq_relationship_logits = model(input_ids, token_type_ids, input_mask) + ``` + """ + + def __init__(self, config): + super(BertForNextSentencePrediction, self).__init__(config) + self.bert = BertModel(config) + self.cls = BertOnlyNSPHead(config) + self.apply(self.init_bert_weights) + + def forward(self, input_ids, token_type_ids=None, attention_mask=None, next_sentence_label=None): + _, pooled_output = self.bert(input_ids, token_type_ids, attention_mask, + output_all_encoded_layers=False) + seq_relationship_score = self.cls(pooled_output) + + if next_sentence_label is not None: + loss_fct = CrossEntropyLoss(ignore_index=-1) + next_sentence_loss = loss_fct( + seq_relationship_score.view(-1, 2), next_sentence_label.view(-1)) + return next_sentence_loss + else: + return seq_relationship_score + + +class BertForSentencePairClassification(BertPreTrainedModel): + def __init__(self, config, num_labels): + super(BertForSentencePairClassification, self).__init__(config) + self.num_labels = num_labels + self.bert = BertModel(config) + self.dropout = nn.Dropout(config.hidden_dropout_prob) + self.classifier = nn.Linear(config.hidden_size * 3, num_labels) + self.apply(self.init_bert_weights) + + def forward(self, a_input_ids, b_input_ids, a_token_type_ids=None, b_token_type_ids=None, + a_attention_mask=None, b_attention_mask=None, labels=None): + _, a_pooled_output = self.bert( + a_input_ids, a_token_type_ids, a_attention_mask, output_all_encoded_layers=False) + # a_pooled_output = self.dropout(a_pooled_output) + + _, b_pooled_output = self.bert( + b_input_ids, b_token_type_ids, b_attention_mask, output_all_encoded_layers=False) + # b_pooled_output = self.dropout(b_pooled_output) + + logits = self.classifier(torch.relu(torch.cat((a_pooled_output, b_pooled_output, + torch.abs(a_pooled_output - b_pooled_output)), -1))) + + if labels is not None: + loss_fct = CrossEntropyLoss() + loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1)) + return loss + else: + return logits + + +class TinyBertForSequenceClassification_for_finetune(BertPreTrainedModel): + def __init__(self, config, num_labels, fit_size=768): + super(TinyBertForSequenceClassification_for_finetune, self).__init__(config) + self.num_labels = num_labels + self.bert = BertModel(config) + self.dropout = nn.Dropout(config.hidden_dropout_prob) + self.classifier = nn.Linear(config.hidden_size, num_labels) + self.fit_dense = nn.Linear(config.hidden_size, fit_size) + self.apply(self.init_bert_weights) + + def forward(self, input_ids, token_type_ids=None, attention_mask=None, + labels=None, is_student=False): + + sequence_output, att_output, pooled_output = self.bert(input_ids, token_type_ids, attention_mask, + output_all_encoded_layers=True, output_att=True) + + logits = self.classifier(torch.relu(pooled_output)) + + tmp = [] + if is_student: + for s_id, sequence_layer in enumerate(sequence_output): + tmp.append(self.fit_dense(sequence_layer)) + sequence_output = tmp + return logits, att_output, sequence_output diff --git a/PyTorch/contrib/others/DQN/train_dqn.py b/PyTorch/contrib/others/DQN/train_dqn.py index 06d1210a1e..feca5641ed 100644 --- a/PyTorch/contrib/others/DQN/train_dqn.py +++ b/PyTorch/contrib/others/DQN/train_dqn.py @@ -1,38 +1,38 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 examples import * - -if __name__ == '__main__': - cf = Config() - cf.add_argument('--game', type=str, default='BreakoutNoFrameskip-v4') - cf.add_argument('--use_device', type=str, default='use_npu') - cf.add_argument('--device_id', type=int, default=0) - cf.add_argument('--max_steps', type=int, default=2e7) - cf.add_argument('--save_interval', type=int, default=0) - cf.add_argument('--eval_interval', type=int, default=0) - cf.add_argument('--log_interval', type=int, default=1e3) - cf.add_argument('--tag', type=str, default=None) - cf.add_argument('--pth_path', type=str, default='null') - cf.add_argument('--status_path', type=str, default='null') - cf.merge() - - param = dict(game=cf.game, max_steps=cf.max_steps, save_interval=cf.save_interval, eval_interval=cf.eval_interval, - log_interval=cf.log_interval, pth_path=cf.pth_path, status_path=cf.status_path, tag=cf.tag, device_id=cf.device_id,maxremark=dqn_pixel.__name__) - - mkdir('data') - random_seed() - select_device(cf.use_device, cf.device_id) - dqn_pixel(**param) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 examples import * + +if __name__ == '__main__': + cf = Config() + cf.add_argument('--game', type=str, default='BreakoutNoFrameskip-v4') + cf.add_argument('--use_device', type=str, default='use_npu') + cf.add_argument('--device_id', type=int, default=0) + cf.add_argument('--max_steps', type=int, default=2e7) + cf.add_argument('--save_interval', type=int, default=0) + cf.add_argument('--eval_interval', type=int, default=0) + cf.add_argument('--log_interval', type=int, default=1e3) + cf.add_argument('--tag', type=str, default=None) + cf.add_argument('--pth_path', type=str, default='null') + cf.add_argument('--status_path', type=str, default='null') + cf.merge() + + param = dict(game=cf.game, max_steps=cf.max_steps, save_interval=cf.save_interval, eval_interval=cf.eval_interval, + log_interval=cf.log_interval, pth_path=cf.pth_path, status_path=cf.status_path, tag=cf.tag, device_id=cf.device_id,maxremark=dqn_pixel.__name__) + + mkdir('data') + random_seed() + select_device(cf.use_device, cf.device_id) + dqn_pixel(**param) exit() \ No newline at end of file diff --git a/PyTorch/dev/cv/detection/FasterRCNN-Resnet50-FPN_ID1552_for_PyTorch/README.md b/PyTorch/dev/cv/detection/FasterRCNN-Resnet50-FPN_ID1552_for_PyTorch/README.md index 9ce0995753..83e71bddba 100644 --- a/PyTorch/dev/cv/detection/FasterRCNN-Resnet50-FPN_ID1552_for_PyTorch/README.md +++ b/PyTorch/dev/cv/detection/FasterRCNN-Resnet50-FPN_ID1552_for_PyTorch/README.md @@ -1,102 +1,102 @@ -- [基本信息](#基本信息.md) -- [概述](#概述.md) -- [训练环境准备](#训练环境准备.md) -- [快速上手](#快速上手.md) - -

基本信息

- -**发布者(Publisher):huawei** - -**应用领域(Application Domain):Object Detection** - -**版本(Version):1.0** - -**修改时间(Modified) :2021.05.20** - -_**大小(Size)**_**:318M** - -**框架(Framework):PyTorch1.5** - -**模型格式(Model Format):pth** - -**精度(Precision):Mixed** - -**处理器(Processor):昇腾910** - -**应用级别(Categories):Research** - -**描述(Description):基于PyTorch框架的FasterRCNN目标检测网络** - -

概述

-Faster R-CNN是截至目前,RCNN系列算法的最杰出产物,two-stage中最为经典的物体检测算法。推理第一阶段先找出图片中待检测物体的anchor矩形框(对背景、待检测物体进行二分类),第二阶段对anchor框内待检测物体进行分类。R-CNN系列物体检测算法的思路都是先产生一些待检测框,再对检测框进行分类。Faster R-CNN使用神经网络生成待检测框,替代了其他R-CNN算法中通过规则等产生候选框的方法,从而实现了端到端训练,并且大幅提速。本文档描述的Faster R-CNN是基于PyTorch实现的版本。 - -- 参考实现: - - https://github.com/facebookresearch/detectron2 - -- 适配昇腾 AI 处理器的实现: - - https://gitee.com/ascend/modelzoo/tree/master/built-in/PyTorch/Research/cv/detection/Faster_Mask_RCNN_for_PyTorch - -

训练环境准备

- -硬件环境准备请参见[各硬件产品文档](https://ascend.huawei.com/#/document?tag=developer)。需要在硬件设备上安装固件与驱动。 - -关键依赖请获取NPU适配版本: - -PyTorch - -apex - -tensor-fused-plugin - -另外该代码运行需要从源编译库: - - cd Faster_Mask_RCNN_for_PyTorch - python3 -m pip install -e ./ -## 默认配置 - -- 训练超参(8卡): - - Batch size: 16(2 per device) - - Momentum: 0.9 - - LR scheduler: step - - Learning rate\(LR\): 0.02 - - Weight decay: 0.0001 - - Label smoothing: 0.1 - - Train epoch: 12 - - -## 混合精度训练 - -昇腾910 AI处理器提供自动混合精度功能,可以针对全网中float32数据类型的算子,按照内置的优化策略,自动将部分float32的算子降低精度到float16,从而在精度损失很小的情况下提升系统性能并减少内存使用。 - -## 开启混合精度 -在启动脚本中执行训练脚本处配置命令行参数 AMP 1 即可开启NPU上混合精度训练模式。 - - -## 数据集准备 - -默认使用coco2017数据集,请用户自行获取。数据集路径通过启动脚本的命令行参数--data_path配置。应有如下目录结构 - -/path/to/dataset/coco - -## 快速上手 - -1.下载预训练模型。 - -以resnet50为例: - -wget https://dl.fbaipublicfiles.com/detectron2/ImageNetPretrained/MSRA/R-50.pkl - -将其置于数据集所在目录下 - -另附resnet101[下载地址](https://dl.fbaipublicfiles.com/detectron2/ImageNetPretrained/MSRA/R-101.pkl) - -2.开始训练。 -- 单机单卡 - - cd test && bash ./train_full_1p.sh --data_path=/path/to/dataset - -- 单机8卡 - - cd test && bash ./train_full_8p.sh --data_path=/path/to/dataset +- [基本信息](#基本信息.md) +- [概述](#概述.md) +- [训练环境准备](#训练环境准备.md) +- [快速上手](#快速上手.md) + +

基本信息

+ +**发布者(Publisher):huawei** + +**应用领域(Application Domain):Object Detection** + +**版本(Version):1.0** + +**修改时间(Modified) :2021.05.20** + +_**大小(Size)**_**:318M** + +**框架(Framework):PyTorch1.5** + +**模型格式(Model Format):pth** + +**精度(Precision):Mixed** + +**处理器(Processor):昇腾910** + +**应用级别(Categories):Research** + +**描述(Description):基于PyTorch框架的FasterRCNN目标检测网络** + +

概述

+Faster R-CNN是截至目前,RCNN系列算法的最杰出产物,two-stage中最为经典的物体检测算法。推理第一阶段先找出图片中待检测物体的anchor矩形框(对背景、待检测物体进行二分类),第二阶段对anchor框内待检测物体进行分类。R-CNN系列物体检测算法的思路都是先产生一些待检测框,再对检测框进行分类。Faster R-CNN使用神经网络生成待检测框,替代了其他R-CNN算法中通过规则等产生候选框的方法,从而实现了端到端训练,并且大幅提速。本文档描述的Faster R-CNN是基于PyTorch实现的版本。 + +- 参考实现: + + https://github.com/facebookresearch/detectron2 + +- 适配昇腾 AI 处理器的实现: + + https://gitee.com/ascend/modelzoo/tree/master/built-in/PyTorch/Research/cv/detection/Faster_Mask_RCNN_for_PyTorch + +

训练环境准备

+ +硬件环境准备请参见[各硬件产品文档](https://ascend.huawei.com/#/document?tag=developer)。需要在硬件设备上安装固件与驱动。 + +关键依赖请获取NPU适配版本: + +PyTorch + +apex + +tensor-fused-plugin + +另外该代码运行需要从源编译库: + + cd Faster_Mask_RCNN_for_PyTorch + python3 -m pip install -e ./ +## 默认配置 + +- 训练超参(8卡): + - Batch size: 16(2 per device) + - Momentum: 0.9 + - LR scheduler: step + - Learning rate\(LR\): 0.02 + - Weight decay: 0.0001 + - Label smoothing: 0.1 + - Train epoch: 12 + + +## 混合精度训练 + +昇腾910 AI处理器提供自动混合精度功能,可以针对全网中float32数据类型的算子,按照内置的优化策略,自动将部分float32的算子降低精度到float16,从而在精度损失很小的情况下提升系统性能并减少内存使用。 + +## 开启混合精度 +在启动脚本中执行训练脚本处配置命令行参数 AMP 1 即可开启NPU上混合精度训练模式。 + + +## 数据集准备 + +默认使用coco2017数据集,请用户自行获取。数据集路径通过启动脚本的命令行参数--data_path配置。应有如下目录结构 + +/path/to/dataset/coco + +## 快速上手 + +1.下载预训练模型。 + +以resnet50为例: + +wget https://dl.fbaipublicfiles.com/detectron2/ImageNetPretrained/MSRA/R-50.pkl + +将其置于数据集所在目录下 + +另附resnet101[下载地址](https://dl.fbaipublicfiles.com/detectron2/ImageNetPretrained/MSRA/R-101.pkl) + +2.开始训练。 +- 单机单卡 + + cd test && bash ./train_full_1p.sh --data_path=/path/to/dataset + +- 单机8卡 + + cd test && bash ./train_full_8p.sh --data_path=/path/to/dataset diff --git a/PyTorch/dev/cv/image_classification/2D_Unet_ID0624_for_PyTorch/test/train_full_8p.sh b/PyTorch/dev/cv/image_classification/2D_Unet_ID0624_for_PyTorch/test/train_full_8p.sh index 504e637304..0456da4f22 100644 --- a/PyTorch/dev/cv/image_classification/2D_Unet_ID0624_for_PyTorch/test/train_full_8p.sh +++ b/PyTorch/dev/cv/image_classification/2D_Unet_ID0624_for_PyTorch/test/train_full_8p.sh @@ -1,125 +1,125 @@ -#!/bin/bash - -cur_path=`pwd`/../ -#失败用例打屏 -export ASCEND_SLOG_PRINT_TO_STDOUT=0 - -#基础参数,需要模型审视修改 -#Batch Size -batch_size=1 -#网络名称,同目录名称 -Network="2D_Unet_ID0624_for_PyTorch" -#Device数量,单卡默认为1 -RANK_SIZE=8 -#训练epoch,可选 -train_epochs=5 -#训练step -train_steps= -#学习率 -learning_rate=1e-3 -#参数配置 -data_path="" - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_accormance_1p.sh " - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - fi -done - -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be config" - exit 1 -fi -##############执行训练########## -cd $cur_path -if [ -d $cur_path/test/output ];then - rm -rf $cur_path/test/output/* - mkdir -p $cur_path/test/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/test/output/$ASCEND_DEVICE_ID -fi -wait - -export HCCL_WHITELIST_DISABLE=1 -export MASTER_ADDR=127.0.0.1 -export MASTER_PORT=23456 - - -export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID -sed -i "s|data/imgs/|$data_path/imgs/|g" $cur_path/train.py -sed -i "s|data/masks/|$data_path/masks/|g" $cur_path/train.py -start=$(date +%s) -#nohup python3 train.py -e $train_epochs > $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & - - -NPUS=($(seq 0 7)) -export NPU_WORLD_SIZE=${#NPUS[@]} -rank=0 -for i in ${NPUS[@]} -do - mkdir -p $cur_path/test/output/${i}/ - export NPU_CALCULATE_DEVICE=${i} - export ASCEND_DEVICE_ID=${i} - export RANK=${rank} - echo run process ${rank} - nohup python3 train.py -e $train_epochs -l 0.0001 --distributed True > $cur_path/test/output/$ASCEND_DEVICE_ID/train_${i}.log 2>&1 & - let rank++ -done -wait -end=$(date +%s) -e2e_time=$(( $end - $start )) - - - -#输出训练精度,需要模型审视修改 -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据,不需要修改 -#吞吐量 -sed -i "s|\r|\n|g" $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log -TrainingTime=0 -FPS=`grep img/s $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log |grep -v 0% | awk -F "," '{print$2}' | awk '{print$1}' | awk -F "i" '{print$1}' | awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` -FPS=$(awk 'BEGIN{print '$FPS'*8}') -TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'*1000/'${FPS}'}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -ActualFPS=${FPS} - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep Epoch $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log| awk -F "," '{print$3}' | awk -F "=" '{print$2}' | awk -F "]" '{print$1}'| awk '{if(length !=0)print $0}' > $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - - -#精度值 -train_accuracy=`grep "Validation Dice" $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk '{print $NF}'|awk 'NR==1{max=$1;next}{max=max>$1?max:$1}END{print max}'` - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log - +#!/bin/bash + +cur_path=`pwd`/../ +#失败用例打屏 +export ASCEND_SLOG_PRINT_TO_STDOUT=0 + +#基础参数,需要模型审视修改 +#Batch Size +batch_size=1 +#网络名称,同目录名称 +Network="2D_Unet_ID0624_for_PyTorch" +#Device数量,单卡默认为1 +RANK_SIZE=8 +#训练epoch,可选 +train_epochs=5 +#训练step +train_steps= +#学习率 +learning_rate=1e-3 +#参数配置 +data_path="" + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_accormance_1p.sh " + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + fi +done + +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be config" + exit 1 +fi +##############执行训练########## +cd $cur_path +if [ -d $cur_path/test/output ];then + rm -rf $cur_path/test/output/* + mkdir -p $cur_path/test/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/test/output/$ASCEND_DEVICE_ID +fi +wait + +export HCCL_WHITELIST_DISABLE=1 +export MASTER_ADDR=127.0.0.1 +export MASTER_PORT=23456 + + +export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID +sed -i "s|data/imgs/|$data_path/imgs/|g" $cur_path/train.py +sed -i "s|data/masks/|$data_path/masks/|g" $cur_path/train.py +start=$(date +%s) +#nohup python3 train.py -e $train_epochs > $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & + + +NPUS=($(seq 0 7)) +export NPU_WORLD_SIZE=${#NPUS[@]} +rank=0 +for i in ${NPUS[@]} +do + mkdir -p $cur_path/test/output/${i}/ + export NPU_CALCULATE_DEVICE=${i} + export ASCEND_DEVICE_ID=${i} + export RANK=${rank} + echo run process ${rank} + nohup python3 train.py -e $train_epochs -l 0.0001 --distributed True > $cur_path/test/output/$ASCEND_DEVICE_ID/train_${i}.log 2>&1 & + let rank++ +done +wait +end=$(date +%s) +e2e_time=$(( $end - $start )) + + + +#输出训练精度,需要模型审视修改 +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据,不需要修改 +#吞吐量 +sed -i "s|\r|\n|g" $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log +TrainingTime=0 +FPS=`grep img/s $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log |grep -v 0% | awk -F "," '{print$2}' | awk '{print$1}' | awk -F "i" '{print$1}' | awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` +FPS=$(awk 'BEGIN{print '$FPS'*8}') +TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'*1000/'${FPS}'}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +ActualFPS=${FPS} + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep Epoch $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log| awk -F "," '{print$3}' | awk -F "=" '{print$2}' | awk -F "]" '{print$1}'| awk '{if(length !=0)print $0}' > $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + + +#精度值 +train_accuracy=`grep "Validation Dice" $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk '{print $NF}'|awk 'NR==1{max=$1;next}{max=max>$1?max:$1}END{print max}'` + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log + diff --git a/PyTorch/dev/cv/image_classification/2D_Unet_ID0624_for_PyTorch/test/train_performance_8p.sh b/PyTorch/dev/cv/image_classification/2D_Unet_ID0624_for_PyTorch/test/train_performance_8p.sh index 9876a9c467..472d0c48a9 100644 --- a/PyTorch/dev/cv/image_classification/2D_Unet_ID0624_for_PyTorch/test/train_performance_8p.sh +++ b/PyTorch/dev/cv/image_classification/2D_Unet_ID0624_for_PyTorch/test/train_performance_8p.sh @@ -1,128 +1,128 @@ -#!/bin/bash - -cur_path=`pwd`/../ -#失败用例打屏 -export ASCEND_SLOG_PRINT_TO_STDOUT=0 - -#基础参数,需要模型审视修改 -#Batch Size -batch_size=1 -#网络名称,同目录名称 -Network="2D_Unet_ID0624_for_PyTorch" -#Device数量,单卡默认为1 -RANK_SIZE=8 -#训练epoch,可选 -train_epochs=1 -#训练step -train_steps= -#学习率 -learning_rate=1e-3 -#参数配置 -data_path="" - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh " - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - fi -done - -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be config" - exit 1 -fi -##############执行训练########## -cd $cur_path -if [ -d $cur_path/test/output ];then - rm -rf $cur_path/test/output/* - mkdir -p $cur_path/test/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/test/output/$ASCEND_DEVICE_ID -fi -wait - - -export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID -sed -i "s|data/imgs/|$data_path/imgs/|g" $cur_path/train.py -sed -i "s|data/masks/|$data_path/masks/|g" $cur_path/train.py -sed -i "s|if global_step == 100: pass|if global_step == 100: break|g" $cur_path/train.py -start=$(date +%s) -#nohup python3 train.py -e $train_epochs > $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & - - -export HCCL_WHITELIST_DISABLE=1 -export MASTER_ADDR=127.0.0.1 -export MASTER_PORT=23456 - -NPUS=($(seq 0 7)) -export NPU_WORLD_SIZE=${#NPUS[@]} -rank=0 -for i in ${NPUS[@]} -do - mkdir -p $cur_path/test/output/${i}/ - export NPU_CALCULATE_DEVICE=${i} - export ASCEND_DEVICE_ID=${i} - export RANK=${rank} - echo run process ${rank} - nohup python3 train.py -e $train_epochs --distributed True > $cur_path/test/output/$ASCEND_DEVICE_ID/train_${i}.log 2>&1 & - let rank++ -done -wait -end=$(date +%s) -e2e_time=$(( $end - $start )) - - -sed -i "s|if global_step == 100: break|if global_step == 100: pass|g" $cur_path/train.py - -#输出训练精度,需要模型审视修改 -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -sed -i "s|\r|\n|g" $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log -TrainingTime=0 -FPS=`grep img/s $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log | grep -v 0% | awk -F "," '{print$2}' | awk '{print$1}' | awk -F "i" '{print$1}' | awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` -FPS=$(awk 'BEGIN{print '$FPS'*8}') - -TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'*1000/'${FPS}'}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -ActualFPS=${FPS} - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep Epoch $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log| awk -F "," '{print$3}' | awk -F "=" '{print$2}' | awk -F "]" '{print$1}'| awk '{if(length !=0)print $0}' > $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - - -#精度值 -#train_accuracy=`grep "loss" $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss_2.txt|awk -F " " '{print $8}'|awk 'END {print}'` - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -#echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log - +#!/bin/bash + +cur_path=`pwd`/../ +#失败用例打屏 +export ASCEND_SLOG_PRINT_TO_STDOUT=0 + +#基础参数,需要模型审视修改 +#Batch Size +batch_size=1 +#网络名称,同目录名称 +Network="2D_Unet_ID0624_for_PyTorch" +#Device数量,单卡默认为1 +RANK_SIZE=8 +#训练epoch,可选 +train_epochs=1 +#训练step +train_steps= +#学习率 +learning_rate=1e-3 +#参数配置 +data_path="" + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh " + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + fi +done + +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be config" + exit 1 +fi +##############执行训练########## +cd $cur_path +if [ -d $cur_path/test/output ];then + rm -rf $cur_path/test/output/* + mkdir -p $cur_path/test/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/test/output/$ASCEND_DEVICE_ID +fi +wait + + +export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID +sed -i "s|data/imgs/|$data_path/imgs/|g" $cur_path/train.py +sed -i "s|data/masks/|$data_path/masks/|g" $cur_path/train.py +sed -i "s|if global_step == 100: pass|if global_step == 100: break|g" $cur_path/train.py +start=$(date +%s) +#nohup python3 train.py -e $train_epochs > $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & + + +export HCCL_WHITELIST_DISABLE=1 +export MASTER_ADDR=127.0.0.1 +export MASTER_PORT=23456 + +NPUS=($(seq 0 7)) +export NPU_WORLD_SIZE=${#NPUS[@]} +rank=0 +for i in ${NPUS[@]} +do + mkdir -p $cur_path/test/output/${i}/ + export NPU_CALCULATE_DEVICE=${i} + export ASCEND_DEVICE_ID=${i} + export RANK=${rank} + echo run process ${rank} + nohup python3 train.py -e $train_epochs --distributed True > $cur_path/test/output/$ASCEND_DEVICE_ID/train_${i}.log 2>&1 & + let rank++ +done +wait +end=$(date +%s) +e2e_time=$(( $end - $start )) + + +sed -i "s|if global_step == 100: break|if global_step == 100: pass|g" $cur_path/train.py + +#输出训练精度,需要模型审视修改 +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +sed -i "s|\r|\n|g" $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log +TrainingTime=0 +FPS=`grep img/s $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log | grep -v 0% | awk -F "," '{print$2}' | awk '{print$1}' | awk -F "i" '{print$1}' | awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` +FPS=$(awk 'BEGIN{print '$FPS'*8}') + +TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'*1000/'${FPS}'}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +ActualFPS=${FPS} + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep Epoch $cur_path/test/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log| awk -F "," '{print$3}' | awk -F "=" '{print$2}' | awk -F "]" '{print$1}'| awk '{if(length !=0)print $0}' > $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + + +#精度值 +#train_accuracy=`grep "loss" $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss_2.txt|awk -F " " '{print $8}'|awk 'END {print}'` + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/test/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +#echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/test/output/$ASCEND_DEVICE_ID/${CaseName}.log + diff --git a/PyTorch/dev/cv/image_classification/3D_Nest_Unet_ID0476_for_PyTorch/README_ori.md b/PyTorch/dev/cv/image_classification/3D_Nest_Unet_ID0476_for_PyTorch/README_ori.md index 82e051e68c..1d803ac37c 100644 --- a/PyTorch/dev/cv/image_classification/3D_Nest_Unet_ID0476_for_PyTorch/README_ori.md +++ b/PyTorch/dev/cv/image_classification/3D_Nest_Unet_ID0476_for_PyTorch/README_ori.md @@ -1,109 +1,109 @@ -# PyTorch implementation of UNet++ (Nested U-Net) -[![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE) - -This repository contains code for a image segmentation model based on [UNet++: A Nested U-Net Architecture for Medical Image Segmentation](https://arxiv.org/abs/1807.10165) implemented in PyTorch. - -[**NEW**] Add support for multi-class segmentation dataset. - -[**NEW**] Add support for PyTorch 1.x. - - -## Requirements -- PyTorch 1.x or 0.41 - -## Installation -1. Create an anaconda environment. -```sh -conda create -n= python=3.6 anaconda -conda activate -``` -2. Install PyTorch. -```sh -conda install pytorch torchvision cudatoolkit=10.1 -c pytorch -``` -3. Install pip packages. -```sh -pip install -r requirements.txt -``` - -## Training on [2018 Data Science Bowl](https://www.kaggle.com/c/data-science-bowl-2018) dataset -1. Download dataset from [here](https://www.kaggle.com/c/data-science-bowl-2018/data) to inputs/ and unzip. The file structure is the following: -``` -inputs -└── data-science-bowl-2018 - ├── stage1_train - | ├── 00ae65... - │ │ ├── images - │ │ │ └── 00ae65... - │ │ └── masks - │ │ └── 00ae65... - │ ├── ... - | - ... -``` -2. Preprocess. -```sh -python preprocess_dsb2018.py -``` -3. Train the model. -```sh -python train.py --dataset dsb2018_96 --arch NestedUNet -``` -4. Evaluate. -```sh -python val.py --name dsb2018_96_NestedUNet_woDS -``` -### (Optional) Using LovaszHingeLoss -1. Clone LovaszSoftmax from [bermanmaxim/LovaszSoftmax](https://github.com/bermanmaxim/LovaszSoftmax). -``` -git clone https://github.com/bermanmaxim/LovaszSoftmax.git -``` -2. Train the model with LovaszHingeLoss. -``` -python train.py --dataset dsb2018_96 --arch NestedUNet --loss LovaszHingeLoss -``` - -## Training on original dataset -Make sure to put the files as the following structure (e.g. the number of classes is 2): -``` -inputs -└── - ├── images - | ├── 0a7e06.jpg - │ ├── 0aab0a.jpg - │ ├── 0b1761.jpg - │ ├── ... - | - └── masks - ├── 0 - | ├── 0a7e06.png - | ├── 0aab0a.png - | ├── 0b1761.png - | ├── ... - | - └── 1 - ├── 0a7e06.png - ├── 0aab0a.png - ├── 0b1761.png - ├── ... -``` - -1. Train the model. -``` -python train.py --dataset --arch NestedUNet --img_ext .jpg --mask_ext .png -``` -2. Evaluate. -``` -python val.py --name _NestedUNet_woDS -``` - -## Results -### DSB2018 (96x96) - -Here is the results on DSB2018 dataset (96x96) with LovaszHingeLoss. - -| Model | IoU | Loss | -|:------------------------------- |:-------:|:-------:| -| U-Net | 0.839 | 0.365 | -| Nested U-Net | 0.842 |**0.354**| -| Nested U-Net w/ Deepsupervision |**0.843**| 0.362 | +# PyTorch implementation of UNet++ (Nested U-Net) +[![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE) + +This repository contains code for a image segmentation model based on [UNet++: A Nested U-Net Architecture for Medical Image Segmentation](https://arxiv.org/abs/1807.10165) implemented in PyTorch. + +[**NEW**] Add support for multi-class segmentation dataset. + +[**NEW**] Add support for PyTorch 1.x. + + +## Requirements +- PyTorch 1.x or 0.41 + +## Installation +1. Create an anaconda environment. +```sh +conda create -n= python=3.6 anaconda +conda activate +``` +2. Install PyTorch. +```sh +conda install pytorch torchvision cudatoolkit=10.1 -c pytorch +``` +3. Install pip packages. +```sh +pip install -r requirements.txt +``` + +## Training on [2018 Data Science Bowl](https://www.kaggle.com/c/data-science-bowl-2018) dataset +1. Download dataset from [here](https://www.kaggle.com/c/data-science-bowl-2018/data) to inputs/ and unzip. The file structure is the following: +``` +inputs +└── data-science-bowl-2018 + ├── stage1_train + | ├── 00ae65... + │ │ ├── images + │ │ │ └── 00ae65... + │ │ └── masks + │ │ └── 00ae65... + │ ├── ... + | + ... +``` +2. Preprocess. +```sh +python preprocess_dsb2018.py +``` +3. Train the model. +```sh +python train.py --dataset dsb2018_96 --arch NestedUNet +``` +4. Evaluate. +```sh +python val.py --name dsb2018_96_NestedUNet_woDS +``` +### (Optional) Using LovaszHingeLoss +1. Clone LovaszSoftmax from [bermanmaxim/LovaszSoftmax](https://github.com/bermanmaxim/LovaszSoftmax). +``` +git clone https://github.com/bermanmaxim/LovaszSoftmax.git +``` +2. Train the model with LovaszHingeLoss. +``` +python train.py --dataset dsb2018_96 --arch NestedUNet --loss LovaszHingeLoss +``` + +## Training on original dataset +Make sure to put the files as the following structure (e.g. the number of classes is 2): +``` +inputs +└── + ├── images + | ├── 0a7e06.jpg + │ ├── 0aab0a.jpg + │ ├── 0b1761.jpg + │ ├── ... + | + └── masks + ├── 0 + | ├── 0a7e06.png + | ├── 0aab0a.png + | ├── 0b1761.png + | ├── ... + | + └── 1 + ├── 0a7e06.png + ├── 0aab0a.png + ├── 0b1761.png + ├── ... +``` + +1. Train the model. +``` +python train.py --dataset --arch NestedUNet --img_ext .jpg --mask_ext .png +``` +2. Evaluate. +``` +python val.py --name _NestedUNet_woDS +``` + +## Results +### DSB2018 (96x96) + +Here is the results on DSB2018 dataset (96x96) with LovaszHingeLoss. + +| Model | IoU | Loss | +|:------------------------------- |:-------:|:-------:| +| U-Net | 0.839 | 0.365 | +| Nested U-Net | 0.842 |**0.354**| +| Nested U-Net w/ Deepsupervision |**0.843**| 0.362 | diff --git a/PyTorch/dev/cv/image_classification/AUTOAUGMENT_ID0792_for_PyTorch/modelzoo_level.txt b/PyTorch/dev/cv/image_classification/AUTOAUGMENT_ID0792_for_PyTorch/modelzoo_level.txt index 405b26618a..c45626e398 100644 --- a/PyTorch/dev/cv/image_classification/AUTOAUGMENT_ID0792_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/dev/cv/image_classification/AUTOAUGMENT_ID0792_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:POK +FuncStatus:OK +PerfStatus:POK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/dev/cv/image_classification/AdvancedEast_ID0473_for_PyTorch/README_ori.md b/PyTorch/dev/cv/image_classification/AdvancedEast_ID0473_for_PyTorch/README_ori.md index 1a712c230e..32d36760cb 100644 --- a/PyTorch/dev/cv/image_classification/AdvancedEast_ID0473_for_PyTorch/README_ori.md +++ b/PyTorch/dev/cv/image_classification/AdvancedEast_ID0473_for_PyTorch/README_ori.md @@ -1,14 +1,14 @@ -# pytorch_AdvancedEast -pytorch实现AdvancedEast+mobilenetv3 - -# 参考https://github.com/huoyijie/AdvancedEAST -# training -## tianchi ICPR dataset download 链接: https://pan.baidu.com/s/1NSyc-cHKV3IwDo6qojIrKA 密码: ye9y -### 1.modify config params in cfg.py, see default values. -### 2.python preprocess.py, resize image to 256256,384384,512512,640640,736*736, and train respectively could speed up training process. -### 3.python label.py -### 4.python train.py -### 5.python predict.py -图片: -![demo](https://github.com/corleonechensiyu/pytorch_AdvancedEast/blob/master/012.png_predict.jpg) - +# pytorch_AdvancedEast +pytorch实现AdvancedEast+mobilenetv3 + +# 参考https://github.com/huoyijie/AdvancedEAST +# training +## tianchi ICPR dataset download 链接: https://pan.baidu.com/s/1NSyc-cHKV3IwDo6qojIrKA 密码: ye9y +### 1.modify config params in cfg.py, see default values. +### 2.python preprocess.py, resize image to 256256,384384,512512,640640,736*736, and train respectively could speed up training process. +### 3.python label.py +### 4.python train.py +### 5.python predict.py +图片: +![demo](https://github.com/corleonechensiyu/pytorch_AdvancedEast/blob/master/012.png_predict.jpg) + diff --git a/PyTorch/dev/cv/image_classification/AdvancedEast_ID0473_for_PyTorch/modelzoo_level.txt b/PyTorch/dev/cv/image_classification/AdvancedEast_ID0473_for_PyTorch/modelzoo_level.txt index 484664c239..55a9add9fa 100644 --- a/PyTorch/dev/cv/image_classification/AdvancedEast_ID0473_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/dev/cv/image_classification/AdvancedEast_ID0473_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:POK \ No newline at end of file diff --git a/PyTorch/dev/cv/image_classification/AlexNet_ID0472_for_PyTorch/modelzoo_level.txt b/PyTorch/dev/cv/image_classification/AlexNet_ID0472_for_PyTorch/modelzoo_level.txt index 82f29898a4..2963c766cb 100644 --- a/PyTorch/dev/cv/image_classification/AlexNet_ID0472_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/dev/cv/image_classification/AlexNet_ID0472_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:POK +FuncStatus:OK +PerfStatus:POK PrecisionStatus:POK \ No newline at end of file diff --git a/PyTorch/dev/cv/image_classification/BASNET_ID1134_for_PyTorch/iou_tmp.py b/PyTorch/dev/cv/image_classification/BASNET_ID1134_for_PyTorch/iou_tmp.py index 17db3508e1..f3298c8c96 100644 --- a/PyTorch/dev/cv/image_classification/BASNET_ID1134_for_PyTorch/iou_tmp.py +++ b/PyTorch/dev/cv/image_classification/BASNET_ID1134_for_PyTorch/iou_tmp.py @@ -1,82 +1,82 @@ -# -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -# -import torch -import torch.nn.functional as F -from torch.autograd import Variable -import numpy as np - - -def iiou(pred, target, size_average = True): - - combination = target[:,:,:,:]*pred[:,:,:,:] - sumlist_combination = torch.sum(combination,[-1,2]).npu() #compute SG - sumlist_pred = torch.sum(pred,[-1,2]).npu() # compute S - sumlist_target = torch.sum(target,[-1,2]).npu() # compute G - #print('compression matrix',sumlist_target) - - - iou0 = 1-(sumlist_combination[0]/(sumlist_pred[0]+sumlist_target[0]-sumlist_combination[0])) - iou1 = 1-(sumlist_combination[1]/(sumlist_pred[1]+sumlist_target[1]-sumlist_combination[1])) - iou2 = 1-(sumlist_combination[2]/(sumlist_pred[2]+sumlist_target[2]-sumlist_combination[2])) - iou3 = 1-(sumlist_combination[3]/(sumlist_pred[3]+sumlist_target[3]-sumlist_combination[3])) - iou4 = 1-(sumlist_combination[4]/(sumlist_pred[4]+sumlist_target[4]-sumlist_combination[4])) - iou5 = 1-(sumlist_combination[5]/(sumlist_pred[5]+sumlist_target[5]-sumlist_combination[5])) - iou6 = 1-(sumlist_combination[6]/(sumlist_pred[6]+sumlist_target[6]-sumlist_combination[6])) - iou7 = 1-(sumlist_combination[7]/(sumlist_pred[7]+sumlist_target[7]-sumlist_combination[7])) - - IoU = (iou0+iou1+iou2+iou3+iou4+iou5+iou6+iou7)/8 - - - - #b = pred.shape[0] - #i=0 - #IoU = 0.0 - - - #Iand1 = torch.sum(target[:,:,:,:]*pred[:,:,:,:]) - - - #Ior1 = torch.sum(target[:,:,:,:]) + torch.sum(pred[:,:,:,:])-Iand1 - - - #IoU1 = Iand1/Ior1 - - - - #IoU loss is (1-IoU1) - #IoU = IoU + (1-IoU1) - - return IoU - - +# +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +# +import torch +import torch.nn.functional as F +from torch.autograd import Variable +import numpy as np + + +def iiou(pred, target, size_average = True): + + combination = target[:,:,:,:]*pred[:,:,:,:] + sumlist_combination = torch.sum(combination,[-1,2]).npu() #compute SG + sumlist_pred = torch.sum(pred,[-1,2]).npu() # compute S + sumlist_target = torch.sum(target,[-1,2]).npu() # compute G + #print('compression matrix',sumlist_target) + + + iou0 = 1-(sumlist_combination[0]/(sumlist_pred[0]+sumlist_target[0]-sumlist_combination[0])) + iou1 = 1-(sumlist_combination[1]/(sumlist_pred[1]+sumlist_target[1]-sumlist_combination[1])) + iou2 = 1-(sumlist_combination[2]/(sumlist_pred[2]+sumlist_target[2]-sumlist_combination[2])) + iou3 = 1-(sumlist_combination[3]/(sumlist_pred[3]+sumlist_target[3]-sumlist_combination[3])) + iou4 = 1-(sumlist_combination[4]/(sumlist_pred[4]+sumlist_target[4]-sumlist_combination[4])) + iou5 = 1-(sumlist_combination[5]/(sumlist_pred[5]+sumlist_target[5]-sumlist_combination[5])) + iou6 = 1-(sumlist_combination[6]/(sumlist_pred[6]+sumlist_target[6]-sumlist_combination[6])) + iou7 = 1-(sumlist_combination[7]/(sumlist_pred[7]+sumlist_target[7]-sumlist_combination[7])) + + IoU = (iou0+iou1+iou2+iou3+iou4+iou5+iou6+iou7)/8 + + + + #b = pred.shape[0] + #i=0 + #IoU = 0.0 + + + #Iand1 = torch.sum(target[:,:,:,:]*pred[:,:,:,:]) + + + #Ior1 = torch.sum(target[:,:,:,:]) + torch.sum(pred[:,:,:,:])-Iand1 + + + #IoU1 = Iand1/Ior1 + + + + #IoU loss is (1-IoU1) + #IoU = IoU + (1-IoU1) + + return IoU + + diff --git a/PyTorch/dev/cv/image_classification/BASNET_ID1134_for_PyTorch/prefetcher.py b/PyTorch/dev/cv/image_classification/BASNET_ID1134_for_PyTorch/prefetcher.py index 485463e8aa..1d8b0c8087 100644 --- a/PyTorch/dev/cv/image_classification/BASNET_ID1134_for_PyTorch/prefetcher.py +++ b/PyTorch/dev/cv/image_classification/BASNET_ID1134_for_PyTorch/prefetcher.py @@ -1,71 +1,71 @@ -# -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -# - - -import torch - -class DataPrefetcher(): - def __init__(self, loader, steam=None): - self.loader = iter(loader) - self.stream = torch.npu.Stream() - # With Amp, it isn't necessary to manually convert data to half. - # if args.fp16: - # self.mean = self.mean.half() - # self.std = self.std.half() - self.preload() - - def preload(self): - try: - self.next_input,self.next_label = next(self.loader) - except StopIteration: - self.next_input = None - self.next_label = None - return - with torch.npu.stream(self.stream): - self.next_input = self.next_input.npu(non_blocking=True) - self.next_label = self.next_label.npu(non_blocking=True) - - # With Amp, it isn't necessary to manually convert data to half. - # if args.fp16: - # self.next_input = self.next_input.half() - # else: - # self.next_input = self.next_input.float() - - def next(self): - torch.npu.current_stream().wait_stream(self.stream) - next_input = self.next_input - next_label = self.next_label - if next_label is not None: - self.preload() +# +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +# + + +import torch + +class DataPrefetcher(): + def __init__(self, loader, steam=None): + self.loader = iter(loader) + self.stream = torch.npu.Stream() + # With Amp, it isn't necessary to manually convert data to half. + # if args.fp16: + # self.mean = self.mean.half() + # self.std = self.std.half() + self.preload() + + def preload(self): + try: + self.next_input,self.next_label = next(self.loader) + except StopIteration: + self.next_input = None + self.next_label = None + return + with torch.npu.stream(self.stream): + self.next_input = self.next_input.npu(non_blocking=True) + self.next_label = self.next_label.npu(non_blocking=True) + + # With Amp, it isn't necessary to manually convert data to half. + # if args.fp16: + # self.next_input = self.next_input.half() + # else: + # self.next_input = self.next_input.float() + + def next(self): + torch.npu.current_stream().wait_stream(self.stream) + next_input = self.next_input + next_label = self.next_label + if next_label is not None: + self.preload() return next_input,next_label \ No newline at end of file diff --git a/PyTorch/dev/cv/image_classification/ConvLSTM_ID1772_for_PyTorch/requirements.txt b/PyTorch/dev/cv/image_classification/ConvLSTM_ID1772_for_PyTorch/requirements.txt old mode 100755 new mode 100644 diff --git a/PyTorch/dev/cv/image_classification/DCAP_ID2836_for_PyTorch/prefetcher.py b/PyTorch/dev/cv/image_classification/DCAP_ID2836_for_PyTorch/prefetcher.py index a02e80d661..efc4a37ec1 100644 --- a/PyTorch/dev/cv/image_classification/DCAP_ID2836_for_PyTorch/prefetcher.py +++ b/PyTorch/dev/cv/image_classification/DCAP_ID2836_for_PyTorch/prefetcher.py @@ -1,63 +1,63 @@ -# Copyright (c) 2020 Huawei Technologies Co., Ltd -# Copyright (c) 2019, Facebook CORPORATION. -# All rights reserved. -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 torch - - -class Prefetcher(object): - """Prefetcher using on npu device. - - Origin Code URL: - https://github.com/implus/PytorchInsight/blob/master/classification/imagenet_fast.py#L280 - - Args: - loder (torch.utils.data.DataLoader or DataLoader like iterator): - Using to generate inputs after preprocessing. - stream (torch.npu.Stream): Default None. - Because of the limitation of NPU's memory mechanism, - if prefetcher is initialized repeatedly during training, - a defined stream should be introduced to prevent memory leakage; - if prefetcher is initialized only once during training, - a defined stream is not necessary. - - Returns: - float: tensors of shape (k, 5) and (k, 1). Labels are 0-based. - """ - - def __init__(self, loader, stream=None): - self.loader = iter(loader) - self.stream = stream if stream is not None else torch.npu.Stream() - self.preload() - - def preload(self): - try: - self.next_input, self.next_target = next(self.loader) - except StopIteration: - self.user = None - self.item = None - return - - with torch.npu.stream(self.stream): - self.next_input, self.next_target = self.next_input.to(torch.float), self.next_target.to(torch.float) - self.next_input, self.next_target = self.next_input.npu(non_blocking=True), self.next_target.npu(non_blocking=True) - - def next(self): - torch.npu.current_stream().wait_stream(self.stream) - next_input = self.next_input - next_target = self.next_target - if next_input is not None: - self.preload() +# Copyright (c) 2020 Huawei Technologies Co., Ltd +# Copyright (c) 2019, Facebook CORPORATION. +# All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 torch + + +class Prefetcher(object): + """Prefetcher using on npu device. + + Origin Code URL: + https://github.com/implus/PytorchInsight/blob/master/classification/imagenet_fast.py#L280 + + Args: + loder (torch.utils.data.DataLoader or DataLoader like iterator): + Using to generate inputs after preprocessing. + stream (torch.npu.Stream): Default None. + Because of the limitation of NPU's memory mechanism, + if prefetcher is initialized repeatedly during training, + a defined stream should be introduced to prevent memory leakage; + if prefetcher is initialized only once during training, + a defined stream is not necessary. + + Returns: + float: tensors of shape (k, 5) and (k, 1). Labels are 0-based. + """ + + def __init__(self, loader, stream=None): + self.loader = iter(loader) + self.stream = stream if stream is not None else torch.npu.Stream() + self.preload() + + def preload(self): + try: + self.next_input, self.next_target = next(self.loader) + except StopIteration: + self.user = None + self.item = None + return + + with torch.npu.stream(self.stream): + self.next_input, self.next_target = self.next_input.to(torch.float), self.next_target.to(torch.float) + self.next_input, self.next_target = self.next_input.npu(non_blocking=True), self.next_target.npu(non_blocking=True) + + def next(self): + torch.npu.current_stream().wait_stream(self.stream) + next_input = self.next_input + next_target = self.next_target + if next_input is not None: + self.preload() return next_input, next_target \ No newline at end of file diff --git a/PyTorch/dev/cv/image_classification/DeepSort_ID0654_for_PyTorch/README_ori.md b/PyTorch/dev/cv/image_classification/DeepSort_ID0654_for_PyTorch/README_ori.md index 2cf3d2a821..e89c9b3ea0 100644 --- a/PyTorch/dev/cv/image_classification/DeepSort_ID0654_for_PyTorch/README_ori.md +++ b/PyTorch/dev/cv/image_classification/DeepSort_ID0654_for_PyTorch/README_ori.md @@ -1,3 +1,3 @@ -# Deep Sort - +# Deep Sort + This is the implemention of deep sort with pytorch. \ No newline at end of file diff --git a/PyTorch/dev/cv/image_classification/DeepSort_ID0654_for_PyTorch/requirements.txt b/PyTorch/dev/cv/image_classification/DeepSort_ID0654_for_PyTorch/requirements.txt index 848ebde50e..f9b2aa91e4 100644 --- a/PyTorch/dev/cv/image_classification/DeepSort_ID0654_for_PyTorch/requirements.txt +++ b/PyTorch/dev/cv/image_classification/DeepSort_ID0654_for_PyTorch/requirements.txt @@ -1,2 +1,2 @@ -torch +torch numpy \ No newline at end of file diff --git a/PyTorch/dev/cv/image_classification/DeepSort_ID0654_for_PyTorch/test/train_full_8p.sh b/PyTorch/dev/cv/image_classification/DeepSort_ID0654_for_PyTorch/test/train_full_8p.sh index 49ef461403..6d473004a5 100644 --- a/PyTorch/dev/cv/image_classification/DeepSort_ID0654_for_PyTorch/test/train_full_8p.sh +++ b/PyTorch/dev/cv/image_classification/DeepSort_ID0654_for_PyTorch/test/train_full_8p.sh @@ -1,201 +1,201 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` - -#集合通信参数,不需要修改 - -export RANK_SIZE=1 -export JOB_ID=10087 -RANK_ID_START=0 - - - - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -export ASCEND_GLOBAL_LOG_LEVEL=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="DeepSort_ID0654_for_PyTorch" -#训练epoch -train_epochs=10 -#训练batch_size -batch_size=64 -#训练step -train_steps= -#学习率 -learning_rate=0.8 - -#TF2.X独有,需要模型审视修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_performance_1P.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is False - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--apex" -fi -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -# 解压数据集 -if [ ! -e "$data_path/data/train/1499/1499C5T0007F050.jpg" ];then - tar -xvf $data_path/data.tar -C $data_path/ -else - echo "NO NEED UNTAR" -fi -wait - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#进入训练脚本目录,需要模型审视修改 -#cd $cur_path/../tensorflow -cd $cur_path/../ - -sed -i "s|for epoch in range(start_epoch, start_epoch + 40):|for epoch in range(start_epoch, start_epoch + $train_epochs):|g" $cur_path/../deep/train.py - -for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); -do - #设置环境变量,不需要修改 - echo "Device ID: $ASCEND_DEVICE_ID" - export RANK_ID=$RANK_ID - - - - #创建DeviceID输出目录,不需要修改 - if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - fi - - #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 - #--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path - export MASTER_ADDR=localhost - export MASTER_PORT=29688 - export HCCL_WHITELIST_DISABLE=1 - - NPUS=($(seq 0 7)) - export NPU_WORLD_SIZE=${#NPUS[@]} - rank=0 - for i in ${NPUS[@]} - do - mkdir -p $cur_path/output/${i}/ - export NPU_CALCULATE_DEVICE=${i} - export RANK=${rank} - export ASCEND_DEVICE_ID=${i} - echo run process ${rank} - python3 deep/train.py --ddp \ - --data-dir $data_path/data \ - --lr 0.8 \ - $PREC > $cur_path/output/$ASCEND_DEVICE_ID/train_${i}.log 2>&1 & - let rank++ - done -done -wait -sed -i "s|for epoch in range(start_epoch, start_epoch + $train_epochs):|for epoch in range(start_epoch, start_epoch + 40):|g" $cur_path/../deep/train.py -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -#FPS=`grep "]time" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk -F":" 'NR>26{print $3}' | awk -F"s" '{print $1}' | head -n -1 | awk '{sum+=$1} END {print 64*NR/sum}'` -FPS=`grep -rn "progress:" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk -F "time:" '{print $2}'| awk -F "s" '{print $1}'|awk '{if (NR>1){print $1}}'|awk '{if(length !=0) print $0}'|awk '{sum+=$1} END {print 64*NR/sum}'` -FPS=$(awk 'BEGIN{print '$FPS'*8}') -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep train_accuracy $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print $8}'|cut -c 1-5` -train_accuracy=`grep "Acc" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "Acc:" '{print$2}' | sed 's/%//g' |awk 'NR==1{max=$1;next}{max=max>$1?max:$1}END{print max}'` -#打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep "Loss:" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log | awk -F "Loss:" '{print$2}' | awk '{print$1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` + +#集合通信参数,不需要修改 + +export RANK_SIZE=1 +export JOB_ID=10087 +RANK_ID_START=0 + + + + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +export ASCEND_GLOBAL_LOG_LEVEL=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="DeepSort_ID0654_for_PyTorch" +#训练epoch +train_epochs=10 +#训练batch_size +batch_size=64 +#训练step +train_steps= +#学习率 +learning_rate=0.8 + +#TF2.X独有,需要模型审视修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_performance_1P.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is False + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--apex" +fi +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +# 解压数据集 +if [ ! -e "$data_path/data/train/1499/1499C5T0007F050.jpg" ];then + tar -xvf $data_path/data.tar -C $data_path/ +else + echo "NO NEED UNTAR" +fi +wait + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#进入训练脚本目录,需要模型审视修改 +#cd $cur_path/../tensorflow +cd $cur_path/../ + +sed -i "s|for epoch in range(start_epoch, start_epoch + 40):|for epoch in range(start_epoch, start_epoch + $train_epochs):|g" $cur_path/../deep/train.py + +for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); +do + #设置环境变量,不需要修改 + echo "Device ID: $ASCEND_DEVICE_ID" + export RANK_ID=$RANK_ID + + + + #创建DeviceID输出目录,不需要修改 + if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + fi + + #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 + #--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path + export MASTER_ADDR=localhost + export MASTER_PORT=29688 + export HCCL_WHITELIST_DISABLE=1 + + NPUS=($(seq 0 7)) + export NPU_WORLD_SIZE=${#NPUS[@]} + rank=0 + for i in ${NPUS[@]} + do + mkdir -p $cur_path/output/${i}/ + export NPU_CALCULATE_DEVICE=${i} + export RANK=${rank} + export ASCEND_DEVICE_ID=${i} + echo run process ${rank} + python3 deep/train.py --ddp \ + --data-dir $data_path/data \ + --lr 0.8 \ + $PREC > $cur_path/output/$ASCEND_DEVICE_ID/train_${i}.log 2>&1 & + let rank++ + done +done +wait +sed -i "s|for epoch in range(start_epoch, start_epoch + $train_epochs):|for epoch in range(start_epoch, start_epoch + 40):|g" $cur_path/../deep/train.py +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +#FPS=`grep "]time" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk -F":" 'NR>26{print $3}' | awk -F"s" '{print $1}' | head -n -1 | awk '{sum+=$1} END {print 64*NR/sum}'` +FPS=`grep -rn "progress:" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk -F "time:" '{print $2}'| awk -F "s" '{print $1}'|awk '{if (NR>1){print $1}}'|awk '{if(length !=0) print $0}'|awk '{sum+=$1} END {print 64*NR/sum}'` +FPS=$(awk 'BEGIN{print '$FPS'*8}') +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep train_accuracy $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print $8}'|cut -c 1-5` +train_accuracy=`grep "Acc" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "Acc:" '{print$2}' | sed 's/%//g' |awk 'NR==1{max=$1;next}{max=max>$1?max:$1}END{print max}'` +#打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep "Loss:" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log | awk -F "Loss:" '{print$2}' | awk '{print$1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log diff --git a/PyTorch/dev/cv/image_classification/DeepSort_ID0654_for_PyTorch/test/train_performance_8p.sh b/PyTorch/dev/cv/image_classification/DeepSort_ID0654_for_PyTorch/test/train_performance_8p.sh index 1caa51cfe8..55612613f3 100644 --- a/PyTorch/dev/cv/image_classification/DeepSort_ID0654_for_PyTorch/test/train_performance_8p.sh +++ b/PyTorch/dev/cv/image_classification/DeepSort_ID0654_for_PyTorch/test/train_performance_8p.sh @@ -1,198 +1,198 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` - -#集合通信参数,不需要修改 - -export RANK_SIZE=1 -export JOB_ID=10087 -RANK_ID_START=0 - - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -export ASCEND_GLOBAL_LOG_LEVEL=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="DeepSort_ID0654_for_PyTorch" -#训练epoch -train_epochs=2 -#训练batch_size -#batch_size=256 -batch_size=64 -#训练step -train_steps= -#学习率 -learning_rate=0.1 - -#TF2.X独有,需要模型审视修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_performance_1P.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is False - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--apex" -fi -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -# 解压数据集 -if [ ! -e "$data_path/data/train/1499/1499C5T0007F050.jpg" ];then - tar -xvf $data_path/data.tar -C $data_path/ -else - echo "NO NEED UNTAR" -fi -wait - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#进入训练脚本目录,需要模型审视修改 -#cd $cur_path/../tensorflow -cd $cur_path/../ - -sed -i "s|for epoch in range(start_epoch, start_epoch + 40):|for epoch in range(start_epoch, start_epoch + $train_epochs):|g" $cur_path/../deep/train.py - -for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); -do - #设置环境变量,不需要修改 - echo "Device ID: $ASCEND_DEVICE_ID" - export RANK_ID=$RANK_ID - - - - #创建DeviceID输出目录,不需要修改 - if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - fi - - #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 - #--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path - export MASTER_ADDR=localhost - export MASTER_PORT=29688 - export HCCL_WHITELIST_DISABLE=1 - - NPUS=($(seq 0 7)) - export NPU_WORLD_SIZE=${#NPUS[@]} - rank=0 - for i in ${NPUS[@]} - do - mkdir -p $cur_path/output/${i}/ - export NPU_CALCULATE_DEVICE=${i} - export RANK=${rank} - export ASCEND_DEVICE_ID=${i} - echo run process ${rank} - python3 deep/train.py --ddp \ - --data-dir $data_path/data \ - --max_steps 200 \ - $PREC > $cur_path/output/$ASCEND_DEVICE_ID/train_${i}.log 2>&1 & - let rank++ - done -done -wait -sed -i "s|for epoch in range(start_epoch, start_epoch + $train_epochs):|for epoch in range(start_epoch, start_epoch + 40):|g" $cur_path/../deep/train.py -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -#FPS=`grep "]time" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk -F":" 'NR>1{print $3}' | awk -F"s" '{print $1}' | head -n -1 | awk '{sum+=$1} END {print 64*NR/sum}'` -FPS=`grep -rn "progress:" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk -F "time:" '{print $2}'| awk -F "s" '{print $1}'|awk '{if (NR>1){print $1}}'|awk '{if(length !=0) print $0}'|awk '{sum+=$1} END {print 64*NR/sum}'` -FPS=$(awk 'BEGIN{print '$FPS'*8}') -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep train_accuracy $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print $8}'|cut -c 1-5` -#打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep "Loss:" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log | awk -F "Loss:" '{print$2}' | awk '{print$1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` + +#集合通信参数,不需要修改 + +export RANK_SIZE=1 +export JOB_ID=10087 +RANK_ID_START=0 + + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +export ASCEND_GLOBAL_LOG_LEVEL=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="DeepSort_ID0654_for_PyTorch" +#训练epoch +train_epochs=2 +#训练batch_size +#batch_size=256 +batch_size=64 +#训练step +train_steps= +#学习率 +learning_rate=0.1 + +#TF2.X独有,需要模型审视修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_performance_1P.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is False + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--apex" +fi +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +# 解压数据集 +if [ ! -e "$data_path/data/train/1499/1499C5T0007F050.jpg" ];then + tar -xvf $data_path/data.tar -C $data_path/ +else + echo "NO NEED UNTAR" +fi +wait + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#进入训练脚本目录,需要模型审视修改 +#cd $cur_path/../tensorflow +cd $cur_path/../ + +sed -i "s|for epoch in range(start_epoch, start_epoch + 40):|for epoch in range(start_epoch, start_epoch + $train_epochs):|g" $cur_path/../deep/train.py + +for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); +do + #设置环境变量,不需要修改 + echo "Device ID: $ASCEND_DEVICE_ID" + export RANK_ID=$RANK_ID + + + + #创建DeviceID输出目录,不需要修改 + if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + fi + + #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 + #--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path + export MASTER_ADDR=localhost + export MASTER_PORT=29688 + export HCCL_WHITELIST_DISABLE=1 + + NPUS=($(seq 0 7)) + export NPU_WORLD_SIZE=${#NPUS[@]} + rank=0 + for i in ${NPUS[@]} + do + mkdir -p $cur_path/output/${i}/ + export NPU_CALCULATE_DEVICE=${i} + export RANK=${rank} + export ASCEND_DEVICE_ID=${i} + echo run process ${rank} + python3 deep/train.py --ddp \ + --data-dir $data_path/data \ + --max_steps 200 \ + $PREC > $cur_path/output/$ASCEND_DEVICE_ID/train_${i}.log 2>&1 & + let rank++ + done +done +wait +sed -i "s|for epoch in range(start_epoch, start_epoch + $train_epochs):|for epoch in range(start_epoch, start_epoch + 40):|g" $cur_path/../deep/train.py +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +#FPS=`grep "]time" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk -F":" 'NR>1{print $3}' | awk -F"s" '{print $1}' | head -n -1 | awk '{sum+=$1} END {print 64*NR/sum}'` +FPS=`grep -rn "progress:" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk -F "time:" '{print $2}'| awk -F "s" '{print $1}'|awk '{if (NR>1){print $1}}'|awk '{if(length !=0) print $0}'|awk '{sum+=$1} END {print 64*NR/sum}'` +FPS=$(awk 'BEGIN{print '$FPS'*8}') +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep train_accuracy $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print $8}'|cut -c 1-5` +#打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep "Loss:" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log | awk -F "Loss:" '{print$2}' | awk '{print$1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log diff --git a/PyTorch/dev/cv/image_classification/ESRGAN_ID1813_for_PyTorch/modelzoo_level.txt b/PyTorch/dev/cv/image_classification/ESRGAN_ID1813_for_PyTorch/modelzoo_level.txt index a17c8f95fa..a829ab59b9 100644 --- a/PyTorch/dev/cv/image_classification/ESRGAN_ID1813_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/dev/cv/image_classification/ESRGAN_ID1813_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:NOK +FuncStatus:OK +PerfStatus:NOK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/dev/cv/image_classification/Hourglass_ID1809_for_PyTorch/test/train_performance_8p.sh b/PyTorch/dev/cv/image_classification/Hourglass_ID1809_for_PyTorch/test/train_performance_8p.sh index ebdab5ffd4..b3d6682684 100644 --- a/PyTorch/dev/cv/image_classification/Hourglass_ID1809_for_PyTorch/test/train_performance_8p.sh +++ b/PyTorch/dev/cv/image_classification/Hourglass_ID1809_for_PyTorch/test/train_performance_8p.sh @@ -1,207 +1,207 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -export ASCEND_SLOG_PRINT_TO_STDOUT=0 -#export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID -#集合通信参数,不需要修改 - -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 - - - - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="Hourglass_ID1809_for_PyTorch" -#训练epoch -train_epochs=1 -#训练batch_size -batch_size=16 -#训练step -train_steps=10 -#学习率 -learning_rate=1e-3 - -#TF2.X独有,不需要修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False -autotune=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_full_1p.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is False - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#进入训练脚本目录,需要模型审视修改 -cd $cur_path/../ -sed -i "s|'batchsize': 16|'batchsize': $batch_size|g" $cur_path/../task/pose.py -sed -i "s|'learning_rate': 1e-3|'learning_rate': $learning_rate|g" $cur_path/../task/pose.py -sed -i "s|'epoch_num': 200|'epoch_num': $train_epochs|g" $cur_path/../task/pose.py -sed -i "s|'train_iters': 1000|'train_iters': $train_steps|g" $cur_path/../task/pose.py -sed -i "s|annot_dir = 'data/MPII/annot'|annot_dir = '$data_path/data/MPII/annot'|g" $cur_path/../datat/MPII/ref.py -sed -i "s|img_dir = 'data/MPII/images'|img_dir = '$data_path/data/MPII/images'|g" $cur_path/../datat/MPII/ref.py -for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); -do - #设置环境变量,不需要修改 - echo "Device ID: $ASCEND_DEVICE_ID" - export RANK_ID=$RANK_ID - - - - #创建DeviceID输出目录,不需要修改 - if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - fi - - #绑核,不需要绑核的模型删除,需要绑核的模型根据实际修改 - #cpucount=`lscpu | grep "CPU(s):" | head -n 1 | awk '{print $2}'` - #cpustep=`expr $cpucount / 8` - #echo "taskset c steps:" $cpustep - #let a=RANK_ID*$cpustep - #let b=RANK_ID+1 - #let c=b*$cpustep-1 - - - #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 -done -wait - - - -export HCCL_WHITELIST_DISABLE=1 -export MASTER_ADDR=127.0.0.1 -export MASTER_PORT=23456 - -NPUS=($(seq 0 7)) -export NPU_WORLD_SIZE=${#NPUS[@]} -rank=0 -for i in ${NPUS[@]} -do - mkdir -p $cur_path/output/${i}/ - export NPU_CALCULATE_DEVICE=${i} - export ASCEND_DEVICE_ID=${i} - export RANK=${rank} - echo run process ${rank} - - nohup python3 train.py -e test_run_001 --ddp True > $cur_path/output/${i}/train_${i}.log 2>&1 & - let rank++ -done -wait - - -sed -i "s|'batchsize': $batch_size|'batchsize': 16|g" $cur_path/../task/pose.py -sed -i "s|'learning_rate': $learning_rate|'learning_rate': 1e-3|g" $cur_path/../task/pose.py -sed -i "s|'epoch_num': $train_epochs|'epoch_num': 200|g" $cur_path/../task/pose.py -sed -i "s|'train_iters': $train_steps|'train_iters': 1000|g" $cur_path/../task/pose.py -sed -i "s|annot_dir = '$data_path/data/MPII/annot'|annot_dir = 'data/MPII/annot'|g" $cur_path/../datat/MPII/ref.py -sed -i "s|img_dir = '$data_path/data/MPII/images'|img_dir = 'data/MPII/images'|g" $cur_path/../datat/MPII/ref.py -#conda deactivate -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -sed -i "s|\r|\n|g" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep "fps:" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "fps: " '{print $2}'|awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` -FPS=$(awk 'BEGIN{print '$FPS'*8}') - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep eval_accuracy $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|grep -v mlp_log|awk 'END {print $5}'| sed 's/,//g' |cut -c 1-5` -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#稳定性精度看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据 -#吞吐量,不需要修改 -ActualFPS=${FPS} -#单迭代训练时长,不需要修改 -TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep "the loss is: " $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "the loss is: " '{print $2}'|sed s/[[:space:]]//g > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -#echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +export ASCEND_SLOG_PRINT_TO_STDOUT=0 +#export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID +#集合通信参数,不需要修改 + +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 + + + + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="Hourglass_ID1809_for_PyTorch" +#训练epoch +train_epochs=1 +#训练batch_size +batch_size=16 +#训练step +train_steps=10 +#学习率 +learning_rate=1e-3 + +#TF2.X独有,不需要修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False +autotune=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_full_1p.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is False + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#进入训练脚本目录,需要模型审视修改 +cd $cur_path/../ +sed -i "s|'batchsize': 16|'batchsize': $batch_size|g" $cur_path/../task/pose.py +sed -i "s|'learning_rate': 1e-3|'learning_rate': $learning_rate|g" $cur_path/../task/pose.py +sed -i "s|'epoch_num': 200|'epoch_num': $train_epochs|g" $cur_path/../task/pose.py +sed -i "s|'train_iters': 1000|'train_iters': $train_steps|g" $cur_path/../task/pose.py +sed -i "s|annot_dir = 'data/MPII/annot'|annot_dir = '$data_path/data/MPII/annot'|g" $cur_path/../datat/MPII/ref.py +sed -i "s|img_dir = 'data/MPII/images'|img_dir = '$data_path/data/MPII/images'|g" $cur_path/../datat/MPII/ref.py +for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); +do + #设置环境变量,不需要修改 + echo "Device ID: $ASCEND_DEVICE_ID" + export RANK_ID=$RANK_ID + + + + #创建DeviceID输出目录,不需要修改 + if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + fi + + #绑核,不需要绑核的模型删除,需要绑核的模型根据实际修改 + #cpucount=`lscpu | grep "CPU(s):" | head -n 1 | awk '{print $2}'` + #cpustep=`expr $cpucount / 8` + #echo "taskset c steps:" $cpustep + #let a=RANK_ID*$cpustep + #let b=RANK_ID+1 + #let c=b*$cpustep-1 + + + #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 +done +wait + + + +export HCCL_WHITELIST_DISABLE=1 +export MASTER_ADDR=127.0.0.1 +export MASTER_PORT=23456 + +NPUS=($(seq 0 7)) +export NPU_WORLD_SIZE=${#NPUS[@]} +rank=0 +for i in ${NPUS[@]} +do + mkdir -p $cur_path/output/${i}/ + export NPU_CALCULATE_DEVICE=${i} + export ASCEND_DEVICE_ID=${i} + export RANK=${rank} + echo run process ${rank} + + nohup python3 train.py -e test_run_001 --ddp True > $cur_path/output/${i}/train_${i}.log 2>&1 & + let rank++ +done +wait + + +sed -i "s|'batchsize': $batch_size|'batchsize': 16|g" $cur_path/../task/pose.py +sed -i "s|'learning_rate': $learning_rate|'learning_rate': 1e-3|g" $cur_path/../task/pose.py +sed -i "s|'epoch_num': $train_epochs|'epoch_num': 200|g" $cur_path/../task/pose.py +sed -i "s|'train_iters': $train_steps|'train_iters': 1000|g" $cur_path/../task/pose.py +sed -i "s|annot_dir = '$data_path/data/MPII/annot'|annot_dir = 'data/MPII/annot'|g" $cur_path/../datat/MPII/ref.py +sed -i "s|img_dir = '$data_path/data/MPII/images'|img_dir = 'data/MPII/images'|g" $cur_path/../datat/MPII/ref.py +#conda deactivate +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +sed -i "s|\r|\n|g" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep "fps:" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "fps: " '{print $2}'|awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` +FPS=$(awk 'BEGIN{print '$FPS'*8}') + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep eval_accuracy $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|grep -v mlp_log|awk 'END {print $5}'| sed 's/,//g' |cut -c 1-5` +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#稳定性精度看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据 +#吞吐量,不需要修改 +ActualFPS=${FPS} +#单迭代训练时长,不需要修改 +TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep "the loss is: " $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "the loss is: " '{print $2}'|sed s/[[:space:]]//g > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log diff --git a/PyTorch/dev/cv/image_classification/Hourglass_ID1809_for_PyTorch/utils/__init__.py b/PyTorch/dev/cv/image_classification/Hourglass_ID1809_for_PyTorch/utils/__init__.py index 475a7da6fc..2fcb3d2f55 100644 --- a/PyTorch/dev/cv/image_classification/Hourglass_ID1809_for_PyTorch/utils/__init__.py +++ b/PyTorch/dev/cv/image_classification/Hourglass_ID1809_for_PyTorch/utils/__init__.py @@ -1,33 +1,33 @@ -# -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ +# +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ # \ No newline at end of file diff --git a/PyTorch/dev/cv/image_classification/InceptionV3_ID0445_for_PyTorch/test/train_full_8p.sh b/PyTorch/dev/cv/image_classification/InceptionV3_ID0445_for_PyTorch/test/train_full_8p.sh index 8563d37ef6..76482f0906 100644 --- a/PyTorch/dev/cv/image_classification/InceptionV3_ID0445_for_PyTorch/test/train_full_8p.sh +++ b/PyTorch/dev/cv/image_classification/InceptionV3_ID0445_for_PyTorch/test/train_full_8p.sh @@ -1,152 +1,152 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` - -#集合通信参数,不需要修改 - -export RANK_SIZE=8 - -RANK_ID_START=0 - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -export ASCEND_GLOBAL_LOG_LEVEL=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="InceptionV3_ID0445_for_PyTorch" -#训练epoch -train_epochs=90 -#训练batch_size -batch_size=256 -#训练step -train_steps= -#学习率 -learning_rate=0.1 - -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--apex" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path - - -for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); -do - #设置环境变量,不需要修改 - echo "Device ID: $RANK_ID" - export RANK_ID=$RANK_ID - export ASCEND_DEVICE_ID=$RANK_ID - ASCEND_DEVICE_ID=$RANK_ID - - if [ -d $cur_path/output/$ASCEND_DEVICE_ID ];then - rm -rf $cur_path/output/$ASCEND_DEVICE_ID - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID - else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID - fi - - - #训练开始时间,不需要修改 - start_time=$(date +%s) - - nohup python3.7 $cur_path/../train_8p_aux.py \ - --model inception_v3 \ - --epochs ${train_epochs} \ - --workers 192 \ - --data-path=${data_path} \ - --batch-size ${batch_size} $PREC \ - --lr ${learning_rate} \ - --distributed \ - --apex \ - --output-dir=$cur_path/output/$ASCEND_DEVICE_ID \ - --momentum 0.9 \ - --weight-decay 1e-4 \ - --seed 49 \ - --print-freq 10 > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & -done -wait - - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep -a 'img/s' $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log | awk -F "img/s" '{print $2}'|awk '{print$2}' |awk '{sum+=$1} END {print sum/NR}'|sed s/[[:space:]]//g` -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -train_accuracy=`grep -a '* Acc@1' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "Acc@1" '{print $2}'|cut -c 2-6|awk 'BEGIN {max = 0} {if ($1+0>max+0) max=$1 fi} END {print max}'` - -#打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep img/s $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log | awk -F "img/s" '{print$2}' | awk '{print$4}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` + +#集合通信参数,不需要修改 + +export RANK_SIZE=8 + +RANK_ID_START=0 + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +export ASCEND_GLOBAL_LOG_LEVEL=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="InceptionV3_ID0445_for_PyTorch" +#训练epoch +train_epochs=90 +#训练batch_size +batch_size=256 +#训练step +train_steps= +#学习率 +learning_rate=0.1 + +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--apex" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path + + +for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); +do + #设置环境变量,不需要修改 + echo "Device ID: $RANK_ID" + export RANK_ID=$RANK_ID + export ASCEND_DEVICE_ID=$RANK_ID + ASCEND_DEVICE_ID=$RANK_ID + + if [ -d $cur_path/output/$ASCEND_DEVICE_ID ];then + rm -rf $cur_path/output/$ASCEND_DEVICE_ID + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID + else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID + fi + + + #训练开始时间,不需要修改 + start_time=$(date +%s) + + nohup python3.7 $cur_path/../train_8p_aux.py \ + --model inception_v3 \ + --epochs ${train_epochs} \ + --workers 192 \ + --data-path=${data_path} \ + --batch-size ${batch_size} $PREC \ + --lr ${learning_rate} \ + --distributed \ + --apex \ + --output-dir=$cur_path/output/$ASCEND_DEVICE_ID \ + --momentum 0.9 \ + --weight-decay 1e-4 \ + --seed 49 \ + --print-freq 10 > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & +done +wait + + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep -a 'img/s' $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log | awk -F "img/s" '{print $2}'|awk '{print$2}' |awk '{sum+=$1} END {print sum/NR}'|sed s/[[:space:]]//g` +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +train_accuracy=`grep -a '* Acc@1' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "Acc@1" '{print $2}'|cut -c 2-6|awk 'BEGIN {max = 0} {if ($1+0>max+0) max=$1 fi} END {print max}'` + +#打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep img/s $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log | awk -F "img/s" '{print$2}' | awk '{print$4}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log diff --git a/PyTorch/dev/cv/image_classification/InceptionV3_ID0445_for_PyTorch/train_8p.py b/PyTorch/dev/cv/image_classification/InceptionV3_ID0445_for_PyTorch/train_8p.py index 14585e3140..59c6158dd2 100644 --- a/PyTorch/dev/cv/image_classification/InceptionV3_ID0445_for_PyTorch/train_8p.py +++ b/PyTorch/dev/cv/image_classification/InceptionV3_ID0445_for_PyTorch/train_8p.py @@ -1,395 +1,395 @@ -# -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -from __future__ import print_function -import datetime -import os -import time -import sys -sys.path.insert(1,os.path.abspath('..')+ "/..") -import apex -import random -import torch -import torch.utils.data -from torch import nn -import torchvision -from torchvision import transforms -import torch.npu -import numpy as np -import inception -import torch.optim -import utils - -try: - from apex import amp -except ImportError: - amp = None - - -def train_one_epoch(model, criterion, optimizer, data_loader, device, epoch, print_freq, apex=False): - model.train() - metric_logger = utils.MetricLogger(delimiter=" ") - metric_logger.add_meter('lr', utils.SmoothedValue(window_size=1, fmt='{value}')) - metric_logger.add_meter('img/s', utils.SmoothedValue(window_size=10, fmt='{value}')) - - header = 'Epoch: [{}]'.format(epoch) - cnt = 0 - n = 0 - for image, target in metric_logger.log_every(data_loader, print_freq, header): - n = n + 1 - if n >= 100: - pass - start_time = time.time() - image, target = image.to(device), target.to(torch.int).to(device) - output = model(image) - loss = criterion(output, target) - - optimizer.zero_grad() - if apex: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.step() - - acc1, acc5 = utils.accuracy(output, target, topk=(1, 5)) - batch_size = image.shape[0] - metric_logger.update(loss=loss.item(), lr=optimizer.param_groups[0]["lr"]) - metric_logger.meters['acc1'].update(acc1.item(), n=batch_size) - metric_logger.meters['acc5'].update(acc5.item(), n=batch_size) - metric_logger.meters['img/s'].update(batch_size / (time.time() - start_time)) - cnt = cnt + 1 - - if args.max_steps and cnt > args.max_steps: - break - n = 0 - - -def evaluate(model, criterion, data_loader, device): - model.eval() - metric_logger = utils.MetricLogger(delimiter=" ") - header = 'Test:' - with torch.no_grad(): - n = 0 - for image, target in metric_logger.log_every(data_loader, 10, header): - n = n + 1 - if n >= 200: - pass - image = image.to(device, non_blocking=True) - target = target.to(torch.int).to(device, non_blocking=True) - output = model(image) - loss = criterion(output, target) - - acc1, acc5 = utils.accuracy(output, target, topk=(1, 5)) - # FIXME need to take into account that the datasets - # could have been padded in distributed setup - batch_size = image.shape[0] - metric_logger.update(loss=loss.item()) - metric_logger.meters['acc1'].update(acc1.item(), n=batch_size) - metric_logger.meters['acc5'].update(acc5.item(), n=batch_size) - n = 0 - # gather the stats from all processes - print(device) - metric_logger.synchronize_between_processes(device) - - print(' * Acc@1 {top1.global_avg:.3f} Acc@5 {top5.global_avg:.3f}' - .format(top1=metric_logger.acc1, top5=metric_logger.acc5)) - return metric_logger.acc1.global_avg - - -def _get_cache_path(filepath): - import hashlib - h = hashlib.sha1(filepath.encode()).hexdigest() - cache_path = os.path.join("~", ".torch", "vision", "datasets", "imagefolder", h[:10] + ".pt") - cache_path = os.path.expanduser(cache_path) - return cache_path - - -def main(args): - os.environ['MASTER_ADDR'] = '127.0.0.1' - os.environ['MASTER_PORT'] = '29688' - args.device = os.environ['RANK_ID'] - - - rad = random.randint(0,50) - args.seed = args.seed + rad - random.seed(args.seed) - np.random.seed(args.seed) - torch.manual_seed(args.seed) - os.environ['PYTHONHASHSEED'] = str(args.seed) - if args.apex: - if sys.version_info < (3, 0): - raise RuntimeError("Apex currently only supports Python 3. Aborting.") - if amp is None: - raise RuntimeError("Failed to import apex. Please install apex from https://www.github.com/nvidia/apex " - "to enable mixed-precision training.") - - if args.output_dir: - utils.mkdir(args.output_dir) - - if args.distributed: - utils.init_distributed_mode(args) - - device = torch.device(f'npu:{args.device}') - torch.npu.set_device(device) - - #torch.backends.cudnn.benchmark = True - - # Data loading code - print("Loading data") - traindir = os.path.join(args.data_path, 'train') - valdir = os.path.join(args.data_path, 'val') - normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], - std=[0.229, 0.224, 0.225]) - - print("Loading training data") - st = time.time() - cache_path = _get_cache_path(traindir) - if args.cache_dataset and os.path.exists(cache_path): - # Attention, as the transforms are also cached! - print("Loading dataset_train from {}".format(cache_path)) - dataset, _ = torch.load(cache_path) - else: - dataset = torchvision.datasets.ImageFolder( - traindir, - transforms.Compose([ - transforms.RandomResizedCrop(299), - transforms.RandomHorizontalFlip(), - transforms.ToTensor(), - normalize, - ])) - if args.cache_dataset: - print("Saving dataset_train to {}".format(cache_path)) - utils.mkdir(os.path.dirname(cache_path)) - utils.save_on_master((dataset, traindir), cache_path) - print("Took", time.time() - st) - - print("Loading validation data") - cache_path = _get_cache_path(valdir) - if args.cache_dataset and os.path.exists(cache_path): - # Attention, as the transforms are also cached! - print("Loading dataset_test from {}".format(cache_path)) - dataset_test, _ = torch.load(cache_path) - else: - dataset_test = torchvision.datasets.ImageFolder( - valdir, - transforms.Compose([ - transforms.Resize(342), - transforms.CenterCrop(299), - transforms.ToTensor(), - normalize, - ])) - if args.cache_dataset: - print("Saving dataset_test to {}".format(cache_path)) - utils.mkdir(os.path.dirname(cache_path)) - utils.save_on_master((dataset_test, valdir), cache_path) - - print("Creating data loaders") - if args.distributed: - print(len(dataset)) - train_sampler = torch.utils.data.distributed.DistributedSampler(dataset) - print(len(train_sampler)) - test_sampler = torch.utils.data.distributed.DistributedSampler(dataset_test) - else: - train_sampler = torch.utils.data.RandomSampler(dataset) - test_sampler = torch.utils.data.SequentialSampler(dataset_test) - - print(len(train_sampler),args.batch_size,args.workers) - data_loader = torch.utils.data.DataLoader( - dataset, batch_size=args.batch_size, - sampler=train_sampler, num_workers=args.workers,drop_last=True) # pin_memory=True - print(len(data_loader)) - - data_loader_test = torch.utils.data.DataLoader( - dataset_test, batch_size=args.batch_size, - sampler=test_sampler, num_workers=args.workers, drop_last=True) - - print("Creating model") - print(torchvision.models.__dict__) - #model = torchvision.models.__dict__[args.model](pretrained=args.pretrained) - model = inception.inception_v3(pretrained=args.pretrained) - model.to(device) - if args.distributed and args.sync_bn: - model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model) - - - #criterion = nn.CrossEntropyLoss().to(device) - criterion = nn.CrossEntropyLoss() - - if args.apex: - optimizer = apex.optimizers.NpuFusedSGD( - model.parameters(), lr=args.lr, momentum=args.momentum, weight_decay=args.weight_decay) - - - if args.apex: - model, optimizer = amp.initialize(model, optimizer, - opt_level=args.apex_opt_level, - combine_grad=True - ) #loss_scale=args.loss_scale, - - lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=args.lr_step_size, gamma=args.lr_gamma) - - model_without_ddp = model - if args.distributed: - print(args.device) - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.device],broadcast_buffers=False,find_unused_parameters=True) - model_without_ddp = model.module - - #optimizer = torch.optim.SGD( - #model.parameters(), lr=args.lr, momentum=args.momentum, weight_decay=args.weight_decay) - - if args.resume: - checkpoint = torch.load(args.resume, map_location='cpu') - model_without_ddp.load_state_dict(checkpoint['model']) - optimizer.load_state_dict(checkpoint['optimizer']) - lr_scheduler.load_state_dict(checkpoint['lr_scheduler']) - args.start_epoch = checkpoint['epoch'] + 1 - - if args.test_only: - evaluate(model, criterion, data_loader_test, device=device) - return - - print("Start training") - start_time = time.time() - for epoch in range(args.start_epoch, args.epochs): - if args.distributed: - train_sampler.set_epoch(epoch) - train_one_epoch(model, criterion, optimizer, data_loader, device, epoch, args.print_freq, args.apex) - lr_scheduler.step() - evaluate(model, criterion, data_loader_test, device=device) - if args.output_dir: - checkpoint = { - 'model': model_without_ddp.state_dict(), - 'optimizer': optimizer.state_dict(), - 'lr_scheduler': lr_scheduler.state_dict(), - 'epoch': epoch, - 'args': args} - utils.save_on_master( - checkpoint, - os.path.join(args.output_dir, 'model_{}.pth'.format(epoch))) - utils.save_on_master( - checkpoint, - os.path.join(args.output_dir, 'checkpoint.pth')) - - total_time = time.time() - start_time - total_time_str = str(datetime.timedelta(seconds=int(total_time))) - print('Training time {}'.format(total_time_str)) - - -def parse_args(): - import argparse - parser = argparse.ArgumentParser(description='PyTorch Classification Training') - - parser.add_argument('--data-path', default='/datasets01/imagenet_full_size/061417/', help='dataset') - parser.add_argument('--model', default='resnet18', help='model') - parser.add_argument('--device', default='6', help='device') - parser.add_argument('-b', '--batch-size', default=32, type=int) - parser.add_argument('--epochs', default=90, type=int, metavar='N', - help='number of total epochs to run') - parser.add_argument('--max_steps', default=None, type=int, metavar='N', - help='number of total steps to run') - parser.add_argument('-j', '--workers', default=32, type=int, metavar='N', - help='number of data loading workers (default: 16)') - parser.add_argument('--lr', default=0.1, type=float, help='initial learning rate') - parser.add_argument('--momentum', default=0.9, type=float, metavar='M', - help='momentum') - parser.add_argument('--wd', '--weight-decay', default=1e-4, type=float, - metavar='W', help='weight decay (default: 1e-4)', - dest='weight_decay') - parser.add_argument('--lr-step-size', default=30, type=int, help='decrease lr every step-size epochs') - parser.add_argument('--lr-gamma', default=0.1, type=float, help='decrease lr by a factor of lr-gamma') - parser.add_argument('--print-freq', default=10, type=int, help='print frequency') - parser.add_argument('--output-dir', default='.', help='path where to save') - parser.add_argument('--resume', default='', help='resume from checkpoint') - parser.add_argument('--start-epoch', default=0, type=int, metavar='N', - help='start epoch') - parser.add_argument( - "--cache-dataset", - dest="cache_dataset", - help="Cache the datasets for quicker initialization. It also serializes the transforms", - action="store_true", - ) - parser.add_argument( - "--sync-bn", - dest="sync_bn", - help="Use sync batch norm", - action="store_true", - ) - parser.add_argument( - "--test-only", - dest="test_only", - help="Only test the model", - action="store_true", - ) - parser.add_argument( - "--pretrained", - dest="pretrained", - help="Use pre-trained models from the modelzoo", - action="store_true", - ) - - # Mixed precision training parameters - parser.add_argument('--apex', action='store_true', - help='Use apex for mixed precision training') - parser.add_argument('--apex-opt-level', default='O1', type=str, - help='For apex mixed precision training' - 'O0 for FP32 training, O1 for mixed precision training.' - 'For further detail, see https://github.com/NVIDIA/apex/tree/master/examples/imagenet' - ) - parser.add_argument('--loss_scale', default=1024., type=float, - help='loss scale using in amp, default -1 means dynamic') - - # distributed training parameters - parser.add_argument('--world-size', default=1, type=int, - help='number of distributed processes') - parser.add_argument('--dist-url', default='env://', help='url used to set up distributed training') - parser.add_argument('--distributed', - action='store_true', - help='Use multi-processing distributed training to launch ' - 'N processes per node, which has N GPUs.') - parser.add_argument('--dist_rank', - default=0, - type=int, - help='node rank for distributed training') - parser.add_argument('--seed', - default=1, - type=int, - help='Manually set random seed') - - args = parser.parse_args() - - return args - - -if __name__ == "__main__": - args = parse_args() - main(args) +# +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +from __future__ import print_function +import datetime +import os +import time +import sys +sys.path.insert(1,os.path.abspath('..')+ "/..") +import apex +import random +import torch +import torch.utils.data +from torch import nn +import torchvision +from torchvision import transforms +import torch.npu +import numpy as np +import inception +import torch.optim +import utils + +try: + from apex import amp +except ImportError: + amp = None + + +def train_one_epoch(model, criterion, optimizer, data_loader, device, epoch, print_freq, apex=False): + model.train() + metric_logger = utils.MetricLogger(delimiter=" ") + metric_logger.add_meter('lr', utils.SmoothedValue(window_size=1, fmt='{value}')) + metric_logger.add_meter('img/s', utils.SmoothedValue(window_size=10, fmt='{value}')) + + header = 'Epoch: [{}]'.format(epoch) + cnt = 0 + n = 0 + for image, target in metric_logger.log_every(data_loader, print_freq, header): + n = n + 1 + if n >= 100: + pass + start_time = time.time() + image, target = image.to(device), target.to(torch.int).to(device) + output = model(image) + loss = criterion(output, target) + + optimizer.zero_grad() + if apex: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + optimizer.step() + + acc1, acc5 = utils.accuracy(output, target, topk=(1, 5)) + batch_size = image.shape[0] + metric_logger.update(loss=loss.item(), lr=optimizer.param_groups[0]["lr"]) + metric_logger.meters['acc1'].update(acc1.item(), n=batch_size) + metric_logger.meters['acc5'].update(acc5.item(), n=batch_size) + metric_logger.meters['img/s'].update(batch_size / (time.time() - start_time)) + cnt = cnt + 1 + + if args.max_steps and cnt > args.max_steps: + break + n = 0 + + +def evaluate(model, criterion, data_loader, device): + model.eval() + metric_logger = utils.MetricLogger(delimiter=" ") + header = 'Test:' + with torch.no_grad(): + n = 0 + for image, target in metric_logger.log_every(data_loader, 10, header): + n = n + 1 + if n >= 200: + pass + image = image.to(device, non_blocking=True) + target = target.to(torch.int).to(device, non_blocking=True) + output = model(image) + loss = criterion(output, target) + + acc1, acc5 = utils.accuracy(output, target, topk=(1, 5)) + # FIXME need to take into account that the datasets + # could have been padded in distributed setup + batch_size = image.shape[0] + metric_logger.update(loss=loss.item()) + metric_logger.meters['acc1'].update(acc1.item(), n=batch_size) + metric_logger.meters['acc5'].update(acc5.item(), n=batch_size) + n = 0 + # gather the stats from all processes + print(device) + metric_logger.synchronize_between_processes(device) + + print(' * Acc@1 {top1.global_avg:.3f} Acc@5 {top5.global_avg:.3f}' + .format(top1=metric_logger.acc1, top5=metric_logger.acc5)) + return metric_logger.acc1.global_avg + + +def _get_cache_path(filepath): + import hashlib + h = hashlib.sha1(filepath.encode()).hexdigest() + cache_path = os.path.join("~", ".torch", "vision", "datasets", "imagefolder", h[:10] + ".pt") + cache_path = os.path.expanduser(cache_path) + return cache_path + + +def main(args): + os.environ['MASTER_ADDR'] = '127.0.0.1' + os.environ['MASTER_PORT'] = '29688' + args.device = os.environ['RANK_ID'] + + + rad = random.randint(0,50) + args.seed = args.seed + rad + random.seed(args.seed) + np.random.seed(args.seed) + torch.manual_seed(args.seed) + os.environ['PYTHONHASHSEED'] = str(args.seed) + if args.apex: + if sys.version_info < (3, 0): + raise RuntimeError("Apex currently only supports Python 3. Aborting.") + if amp is None: + raise RuntimeError("Failed to import apex. Please install apex from https://www.github.com/nvidia/apex " + "to enable mixed-precision training.") + + if args.output_dir: + utils.mkdir(args.output_dir) + + if args.distributed: + utils.init_distributed_mode(args) + + device = torch.device(f'npu:{args.device}') + torch.npu.set_device(device) + + #torch.backends.cudnn.benchmark = True + + # Data loading code + print("Loading data") + traindir = os.path.join(args.data_path, 'train') + valdir = os.path.join(args.data_path, 'val') + normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]) + + print("Loading training data") + st = time.time() + cache_path = _get_cache_path(traindir) + if args.cache_dataset and os.path.exists(cache_path): + # Attention, as the transforms are also cached! + print("Loading dataset_train from {}".format(cache_path)) + dataset, _ = torch.load(cache_path) + else: + dataset = torchvision.datasets.ImageFolder( + traindir, + transforms.Compose([ + transforms.RandomResizedCrop(299), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + normalize, + ])) + if args.cache_dataset: + print("Saving dataset_train to {}".format(cache_path)) + utils.mkdir(os.path.dirname(cache_path)) + utils.save_on_master((dataset, traindir), cache_path) + print("Took", time.time() - st) + + print("Loading validation data") + cache_path = _get_cache_path(valdir) + if args.cache_dataset and os.path.exists(cache_path): + # Attention, as the transforms are also cached! + print("Loading dataset_test from {}".format(cache_path)) + dataset_test, _ = torch.load(cache_path) + else: + dataset_test = torchvision.datasets.ImageFolder( + valdir, + transforms.Compose([ + transforms.Resize(342), + transforms.CenterCrop(299), + transforms.ToTensor(), + normalize, + ])) + if args.cache_dataset: + print("Saving dataset_test to {}".format(cache_path)) + utils.mkdir(os.path.dirname(cache_path)) + utils.save_on_master((dataset_test, valdir), cache_path) + + print("Creating data loaders") + if args.distributed: + print(len(dataset)) + train_sampler = torch.utils.data.distributed.DistributedSampler(dataset) + print(len(train_sampler)) + test_sampler = torch.utils.data.distributed.DistributedSampler(dataset_test) + else: + train_sampler = torch.utils.data.RandomSampler(dataset) + test_sampler = torch.utils.data.SequentialSampler(dataset_test) + + print(len(train_sampler),args.batch_size,args.workers) + data_loader = torch.utils.data.DataLoader( + dataset, batch_size=args.batch_size, + sampler=train_sampler, num_workers=args.workers,drop_last=True) # pin_memory=True + print(len(data_loader)) + + data_loader_test = torch.utils.data.DataLoader( + dataset_test, batch_size=args.batch_size, + sampler=test_sampler, num_workers=args.workers, drop_last=True) + + print("Creating model") + print(torchvision.models.__dict__) + #model = torchvision.models.__dict__[args.model](pretrained=args.pretrained) + model = inception.inception_v3(pretrained=args.pretrained) + model.to(device) + if args.distributed and args.sync_bn: + model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model) + + + #criterion = nn.CrossEntropyLoss().to(device) + criterion = nn.CrossEntropyLoss() + + if args.apex: + optimizer = apex.optimizers.NpuFusedSGD( + model.parameters(), lr=args.lr, momentum=args.momentum, weight_decay=args.weight_decay) + + + if args.apex: + model, optimizer = amp.initialize(model, optimizer, + opt_level=args.apex_opt_level, + combine_grad=True + ) #loss_scale=args.loss_scale, + + lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=args.lr_step_size, gamma=args.lr_gamma) + + model_without_ddp = model + if args.distributed: + print(args.device) + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.device],broadcast_buffers=False,find_unused_parameters=True) + model_without_ddp = model.module + + #optimizer = torch.optim.SGD( + #model.parameters(), lr=args.lr, momentum=args.momentum, weight_decay=args.weight_decay) + + if args.resume: + checkpoint = torch.load(args.resume, map_location='cpu') + model_without_ddp.load_state_dict(checkpoint['model']) + optimizer.load_state_dict(checkpoint['optimizer']) + lr_scheduler.load_state_dict(checkpoint['lr_scheduler']) + args.start_epoch = checkpoint['epoch'] + 1 + + if args.test_only: + evaluate(model, criterion, data_loader_test, device=device) + return + + print("Start training") + start_time = time.time() + for epoch in range(args.start_epoch, args.epochs): + if args.distributed: + train_sampler.set_epoch(epoch) + train_one_epoch(model, criterion, optimizer, data_loader, device, epoch, args.print_freq, args.apex) + lr_scheduler.step() + evaluate(model, criterion, data_loader_test, device=device) + if args.output_dir: + checkpoint = { + 'model': model_without_ddp.state_dict(), + 'optimizer': optimizer.state_dict(), + 'lr_scheduler': lr_scheduler.state_dict(), + 'epoch': epoch, + 'args': args} + utils.save_on_master( + checkpoint, + os.path.join(args.output_dir, 'model_{}.pth'.format(epoch))) + utils.save_on_master( + checkpoint, + os.path.join(args.output_dir, 'checkpoint.pth')) + + total_time = time.time() - start_time + total_time_str = str(datetime.timedelta(seconds=int(total_time))) + print('Training time {}'.format(total_time_str)) + + +def parse_args(): + import argparse + parser = argparse.ArgumentParser(description='PyTorch Classification Training') + + parser.add_argument('--data-path', default='/datasets01/imagenet_full_size/061417/', help='dataset') + parser.add_argument('--model', default='resnet18', help='model') + parser.add_argument('--device', default='6', help='device') + parser.add_argument('-b', '--batch-size', default=32, type=int) + parser.add_argument('--epochs', default=90, type=int, metavar='N', + help='number of total epochs to run') + parser.add_argument('--max_steps', default=None, type=int, metavar='N', + help='number of total steps to run') + parser.add_argument('-j', '--workers', default=32, type=int, metavar='N', + help='number of data loading workers (default: 16)') + parser.add_argument('--lr', default=0.1, type=float, help='initial learning rate') + parser.add_argument('--momentum', default=0.9, type=float, metavar='M', + help='momentum') + parser.add_argument('--wd', '--weight-decay', default=1e-4, type=float, + metavar='W', help='weight decay (default: 1e-4)', + dest='weight_decay') + parser.add_argument('--lr-step-size', default=30, type=int, help='decrease lr every step-size epochs') + parser.add_argument('--lr-gamma', default=0.1, type=float, help='decrease lr by a factor of lr-gamma') + parser.add_argument('--print-freq', default=10, type=int, help='print frequency') + parser.add_argument('--output-dir', default='.', help='path where to save') + parser.add_argument('--resume', default='', help='resume from checkpoint') + parser.add_argument('--start-epoch', default=0, type=int, metavar='N', + help='start epoch') + parser.add_argument( + "--cache-dataset", + dest="cache_dataset", + help="Cache the datasets for quicker initialization. It also serializes the transforms", + action="store_true", + ) + parser.add_argument( + "--sync-bn", + dest="sync_bn", + help="Use sync batch norm", + action="store_true", + ) + parser.add_argument( + "--test-only", + dest="test_only", + help="Only test the model", + action="store_true", + ) + parser.add_argument( + "--pretrained", + dest="pretrained", + help="Use pre-trained models from the modelzoo", + action="store_true", + ) + + # Mixed precision training parameters + parser.add_argument('--apex', action='store_true', + help='Use apex for mixed precision training') + parser.add_argument('--apex-opt-level', default='O1', type=str, + help='For apex mixed precision training' + 'O0 for FP32 training, O1 for mixed precision training.' + 'For further detail, see https://github.com/NVIDIA/apex/tree/master/examples/imagenet' + ) + parser.add_argument('--loss_scale', default=1024., type=float, + help='loss scale using in amp, default -1 means dynamic') + + # distributed training parameters + parser.add_argument('--world-size', default=1, type=int, + help='number of distributed processes') + parser.add_argument('--dist-url', default='env://', help='url used to set up distributed training') + parser.add_argument('--distributed', + action='store_true', + help='Use multi-processing distributed training to launch ' + 'N processes per node, which has N GPUs.') + parser.add_argument('--dist_rank', + default=0, + type=int, + help='node rank for distributed training') + parser.add_argument('--seed', + default=1, + type=int, + help='Manually set random seed') + + args = parser.parse_args() + + return args + + +if __name__ == "__main__": + args = parse_args() + main(args) diff --git a/PyTorch/dev/cv/image_classification/InceptionV3_ID0445_for_PyTorch/train_8p_aux.py b/PyTorch/dev/cv/image_classification/InceptionV3_ID0445_for_PyTorch/train_8p_aux.py index d86c45d987..220ea58448 100644 --- a/PyTorch/dev/cv/image_classification/InceptionV3_ID0445_for_PyTorch/train_8p_aux.py +++ b/PyTorch/dev/cv/image_classification/InceptionV3_ID0445_for_PyTorch/train_8p_aux.py @@ -1,394 +1,394 @@ -# -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -from __future__ import print_function -import datetime -import os -import time -import sys -sys.path.insert(1,os.path.abspath('..')+ "/..") -import apex -import random -import torch -import torch.utils.data -from torch import nn -import torchvision -from torchvision import transforms -import torch.npu -import numpy as np -import inception - -import utils - -try: - from apex import amp -except ImportError: - amp = None - - -def train_one_epoch(model, criterion, optimizer, data_loader, device, epoch, print_freq, apex=False): - model.train() - metric_logger = utils.MetricLogger(delimiter=" ") - metric_logger.add_meter('lr', utils.SmoothedValue(window_size=1, fmt='{value}')) - metric_logger.add_meter('img/s', utils.SmoothedValue(window_size=10, fmt='{value}')) - - header = 'Epoch: [{}]'.format(epoch) - cnt = 0 - n = 0 - for image, target in metric_logger.log_every(data_loader, print_freq, header): - n = n + 1 - if n >= 100: - pass - start_time = time.time() - image, target = image.to(device), target.to(torch.int).to(device) - output,aux = model(image) - loss1 = criterion(output, target) - loss2 = criterion(aux, target) - loss = loss1 + 0.4*loss2 - - optimizer.zero_grad() - if apex: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.step() - - acc1, acc5 = utils.accuracy(output, target, topk=(1, 5)) - batch_size = image.shape[0] - metric_logger.update(loss=loss.item(), lr=optimizer.param_groups[0]["lr"]) - metric_logger.meters['acc1'].update(acc1.item(), n=batch_size) - metric_logger.meters['acc5'].update(acc5.item(), n=batch_size) - metric_logger.meters['img/s'].update(batch_size / (time.time() - start_time)) - cnt = cnt + 1 - - if args.max_steps and cnt > args.max_steps: - break - n = 0 - - -def evaluate(model, criterion, data_loader, device): - model.eval() - metric_logger = utils.MetricLogger(delimiter=" ") - header = 'Test:' - with torch.no_grad(): - n = 0 - for image, target in metric_logger.log_every(data_loader, 100, header): - n = n + 1 - if n >= 200: - pass - image = image.to(device, non_blocking=True) - target = target.to(torch.int).to(device, non_blocking=True) - output= model(image) - loss1 = criterion(output, target) - - loss = loss1 - - acc1, acc5 = utils.accuracy(output, target, topk=(1, 5)) - # FIXME need to take into account that the datasets - # could have been padded in distributed setup - batch_size = image.shape[0] - metric_logger.update(loss=loss.item()) - metric_logger.meters['acc1'].update(acc1.item(), n=batch_size) - metric_logger.meters['acc5'].update(acc5.item(), n=batch_size) - n = 0 - # gather the stats from all processes - print(device) - metric_logger.synchronize_between_processes(device) - - print(' * Acc@1 {top1.global_avg:.3f} Acc@5 {top5.global_avg:.3f}' - .format(top1=metric_logger.acc1, top5=metric_logger.acc5)) - return metric_logger.acc1.global_avg - - -def _get_cache_path(filepath): - import hashlib - h = hashlib.sha1(filepath.encode()).hexdigest() - cache_path = os.path.join("~", ".torch", "vision", "datasets", "imagefolder", h[:10] + ".pt") - cache_path = os.path.expanduser(cache_path) - return cache_path - - -def main(args): - os.environ['MASTER_ADDR'] = '127.0.0.1' - os.environ['MASTER_PORT'] = '29688' - args.device = os.environ['RANK_ID'] - - rad = random.randint(0,50) - args.seed = args.seed + rad - random.seed(args.seed) - np.random.seed(args.seed) - torch.manual_seed(args.seed) - os.environ['PYTHONHASHSEED'] = str(args.seed) - if args.apex: - if sys.version_info < (3, 0): - raise RuntimeError("Apex currently only supports Python 3. Aborting.") - if amp is None: - raise RuntimeError("Failed to import apex. Please install apex from https://www.github.com/nvidia/apex " - "to enable mixed-precision training.") - - if args.output_dir: - utils.mkdir(args.output_dir) - - if args.distributed: - utils.init_distributed_mode(args) - - device = torch.device(f'npu:{args.device}') - torch.npu.set_device(device) - - torch.backends.cudnn.benchmark = True - - # Data loading code - print("Loading data") - traindir = os.path.join(args.data_path, 'train') - valdir = os.path.join(args.data_path, 'val') - normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], - std=[0.229, 0.224, 0.225]) - - print("Loading training data") - st = time.time() - cache_path = _get_cache_path(traindir) - if args.cache_dataset and os.path.exists(cache_path): - # Attention, as the transforms are also cached! - print("Loading dataset_train from {}".format(cache_path)) - dataset, _ = torch.load(cache_path) - else: - dataset = torchvision.datasets.ImageFolder( - traindir, - transforms.Compose([ - transforms.RandomResizedCrop(299), - transforms.RandomHorizontalFlip(), - transforms.ToTensor(), - normalize, - ])) - if args.cache_dataset: - print("Saving dataset_train to {}".format(cache_path)) - utils.mkdir(os.path.dirname(cache_path)) - utils.save_on_master((dataset, traindir), cache_path) - print("Took", time.time() - st) - - print("Loading validation data") - cache_path = _get_cache_path(valdir) - if args.cache_dataset and os.path.exists(cache_path): - # Attention, as the transforms are also cached! - print("Loading dataset_test from {}".format(cache_path)) - dataset_test, _ = torch.load(cache_path) - else: - dataset_test = torchvision.datasets.ImageFolder( - valdir, - transforms.Compose([ - transforms.Resize(342), - transforms.CenterCrop(299), - transforms.ToTensor(), - normalize, - ])) - if args.cache_dataset: - print("Saving dataset_test to {}".format(cache_path)) - utils.mkdir(os.path.dirname(cache_path)) - utils.save_on_master((dataset_test, valdir), cache_path) - - print("Creating data loaders") - if args.distributed: - print(len(dataset)) - train_sampler = torch.utils.data.distributed.DistributedSampler(dataset) - print(len(train_sampler)) - test_sampler = torch.utils.data.distributed.DistributedSampler(dataset_test) - else: - train_sampler = torch.utils.data.RandomSampler(dataset) - test_sampler = torch.utils.data.SequentialSampler(dataset_test) - - print(len(train_sampler),args.batch_size,args.workers) - data_loader = torch.utils.data.DataLoader( - dataset, batch_size=args.batch_size, - sampler=train_sampler, num_workers=args.workers,drop_last=True) # pin_memory=True - print(len(data_loader)) - - data_loader_test = torch.utils.data.DataLoader( - dataset_test, batch_size=args.batch_size, - sampler=test_sampler, num_workers=args.workers, drop_last=True) - - print("Creating model") - print(torchvision.models.__dict__) - model = torchvision.models.__dict__[args.model](pretrained=args.pretrained) - #model = inception.inception_v3(pretrained=args.pretrained) - model.to(device) - - - - criterion = nn.CrossEntropyLoss().to(device) - #criterion = nn.CrossEntropyLoss() - - optimizer = apex.optimizers.NpuFusedSGD( - model.parameters(), lr=args.lr, momentum=args.momentum, weight_decay=args.weight_decay) - - if args.apex: - model, optimizer = amp.initialize(model, optimizer, - opt_level=args.apex_opt_level, - loss_scale=args.loss_scale, - combine_grad=True - ) #loss_scale=args.loss_scale, - - lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=args.lr_step_size, gamma=args.lr_gamma) - - model_without_ddp = model - - if args.distributed: - print(args.device) - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.device],find_unused_parameters=True) # output_device=args.device, - model_without_ddp = model.module - - if args.resume: - checkpoint = torch.load(args.resume, map_location='cpu') - model_without_ddp.load_state_dict(checkpoint['model']) - optimizer.load_state_dict(checkpoint['optimizer']) - lr_scheduler.load_state_dict(checkpoint['lr_scheduler']) - args.start_epoch = checkpoint['epoch'] + 1 - - if args.test_only: - evaluate(model, criterion, data_loader_test, device=device) - return - - print("Start training") - start_time = time.time() - for epoch in range(args.start_epoch, args.epochs): - if args.distributed: - train_sampler.set_epoch(epoch) - train_one_epoch(model, criterion, optimizer, data_loader, device, epoch, args.print_freq, args.apex) - lr_scheduler.step() - evaluate(model, criterion, data_loader_test, device=device) - if args.output_dir: - checkpoint = { - 'model': model_without_ddp.state_dict(), - 'optimizer': optimizer.state_dict(), - 'lr_scheduler': lr_scheduler.state_dict(), - 'epoch': epoch, - 'args': args} - utils.save_on_master( - checkpoint, - os.path.join(args.output_dir, 'model_{}.pth'.format(epoch))) - utils.save_on_master( - checkpoint, - os.path.join(args.output_dir, 'checkpoint.pth')) - - total_time = time.time() - start_time - total_time_str = str(datetime.timedelta(seconds=int(total_time))) - print('Training time {}'.format(total_time_str)) - - -def parse_args(): - import argparse - parser = argparse.ArgumentParser(description='PyTorch Classification Training') - - parser.add_argument('--data-path', default='/datasets01/imagenet_full_size/061417/', help='dataset') - parser.add_argument('--model', default='resnet18', help='model') - parser.add_argument('--device', default='6', help='device') - parser.add_argument('-b', '--batch-size', default=32, type=int) - parser.add_argument('--epochs', default=90, type=int, metavar='N', - help='number of total epochs to run') - parser.add_argument('--max_steps', default=None, type=int, metavar='N', - help='number of total steps to run') - parser.add_argument('-j', '--workers', default=32, type=int, metavar='N', - help='number of data loading workers (default: 16)') - parser.add_argument('--lr', default=0.1, type=float, help='initial learning rate') - parser.add_argument('--momentum', default=0.9, type=float, metavar='M', - help='momentum') - parser.add_argument('--wd', '--weight-decay', default=1e-4, type=float, - metavar='W', help='weight decay (default: 1e-4)', - dest='weight_decay') - parser.add_argument('--lr-step-size', default=30, type=int, help='decrease lr every step-size epochs') - parser.add_argument('--lr-gamma', default=0.1, type=float, help='decrease lr by a factor of lr-gamma') - parser.add_argument('--print-freq', default=10, type=int, help='print frequency') - parser.add_argument('--output-dir', default='.', help='path where to save') - parser.add_argument('--resume', default='', help='resume from checkpoint') - parser.add_argument('--start-epoch', default=0, type=int, metavar='N', - help='start epoch') - parser.add_argument( - "--cache-dataset", - dest="cache_dataset", - help="Cache the datasets for quicker initialization. It also serializes the transforms", - action="store_true", - ) - parser.add_argument( - "--sync-bn", - dest="sync_bn", - help="Use sync batch norm", - action="store_true", - ) - parser.add_argument( - "--test-only", - dest="test_only", - help="Only test the model", - action="store_true", - ) - parser.add_argument( - "--pretrained", - dest="pretrained", - help="Use pre-trained models from the modelzoo", - action="store_true", - ) - - # Mixed precision training parameters - parser.add_argument('--apex', action='store_true', - help='Use apex for mixed precision training') - parser.add_argument('--apex-opt-level', default='O1', type=str, - help='For apex mixed precision training' - 'O0 for FP32 training, O1 for mixed precision training.' - 'For further detail, see https://github.com/NVIDIA/apex/tree/master/examples/imagenet' - ) - parser.add_argument('--loss_scale', default=1024., type=float, - help='loss scale using in amp, default -1 means dynamic') - - # distributed training parameters - parser.add_argument('--world-size', default=1, type=int, - help='number of distributed processes') - parser.add_argument('--dist-url', default='env://', help='url used to set up distributed training') - parser.add_argument('--distributed', - action='store_true', - help='Use multi-processing distributed training to launch ' - 'N processes per node, which has N GPUs.') - parser.add_argument('--dist_rank', - default=0, - type=int, - help='node rank for distributed training') - parser.add_argument('--seed', - default=1, - type=int, - help='Manually set random seed') - - args = parser.parse_args() - - return args - - -if __name__ == "__main__": - args = parse_args() - main(args) +# +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +from __future__ import print_function +import datetime +import os +import time +import sys +sys.path.insert(1,os.path.abspath('..')+ "/..") +import apex +import random +import torch +import torch.utils.data +from torch import nn +import torchvision +from torchvision import transforms +import torch.npu +import numpy as np +import inception + +import utils + +try: + from apex import amp +except ImportError: + amp = None + + +def train_one_epoch(model, criterion, optimizer, data_loader, device, epoch, print_freq, apex=False): + model.train() + metric_logger = utils.MetricLogger(delimiter=" ") + metric_logger.add_meter('lr', utils.SmoothedValue(window_size=1, fmt='{value}')) + metric_logger.add_meter('img/s', utils.SmoothedValue(window_size=10, fmt='{value}')) + + header = 'Epoch: [{}]'.format(epoch) + cnt = 0 + n = 0 + for image, target in metric_logger.log_every(data_loader, print_freq, header): + n = n + 1 + if n >= 100: + pass + start_time = time.time() + image, target = image.to(device), target.to(torch.int).to(device) + output,aux = model(image) + loss1 = criterion(output, target) + loss2 = criterion(aux, target) + loss = loss1 + 0.4*loss2 + + optimizer.zero_grad() + if apex: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + optimizer.step() + + acc1, acc5 = utils.accuracy(output, target, topk=(1, 5)) + batch_size = image.shape[0] + metric_logger.update(loss=loss.item(), lr=optimizer.param_groups[0]["lr"]) + metric_logger.meters['acc1'].update(acc1.item(), n=batch_size) + metric_logger.meters['acc5'].update(acc5.item(), n=batch_size) + metric_logger.meters['img/s'].update(batch_size / (time.time() - start_time)) + cnt = cnt + 1 + + if args.max_steps and cnt > args.max_steps: + break + n = 0 + + +def evaluate(model, criterion, data_loader, device): + model.eval() + metric_logger = utils.MetricLogger(delimiter=" ") + header = 'Test:' + with torch.no_grad(): + n = 0 + for image, target in metric_logger.log_every(data_loader, 100, header): + n = n + 1 + if n >= 200: + pass + image = image.to(device, non_blocking=True) + target = target.to(torch.int).to(device, non_blocking=True) + output= model(image) + loss1 = criterion(output, target) + + loss = loss1 + + acc1, acc5 = utils.accuracy(output, target, topk=(1, 5)) + # FIXME need to take into account that the datasets + # could have been padded in distributed setup + batch_size = image.shape[0] + metric_logger.update(loss=loss.item()) + metric_logger.meters['acc1'].update(acc1.item(), n=batch_size) + metric_logger.meters['acc5'].update(acc5.item(), n=batch_size) + n = 0 + # gather the stats from all processes + print(device) + metric_logger.synchronize_between_processes(device) + + print(' * Acc@1 {top1.global_avg:.3f} Acc@5 {top5.global_avg:.3f}' + .format(top1=metric_logger.acc1, top5=metric_logger.acc5)) + return metric_logger.acc1.global_avg + + +def _get_cache_path(filepath): + import hashlib + h = hashlib.sha1(filepath.encode()).hexdigest() + cache_path = os.path.join("~", ".torch", "vision", "datasets", "imagefolder", h[:10] + ".pt") + cache_path = os.path.expanduser(cache_path) + return cache_path + + +def main(args): + os.environ['MASTER_ADDR'] = '127.0.0.1' + os.environ['MASTER_PORT'] = '29688' + args.device = os.environ['RANK_ID'] + + rad = random.randint(0,50) + args.seed = args.seed + rad + random.seed(args.seed) + np.random.seed(args.seed) + torch.manual_seed(args.seed) + os.environ['PYTHONHASHSEED'] = str(args.seed) + if args.apex: + if sys.version_info < (3, 0): + raise RuntimeError("Apex currently only supports Python 3. Aborting.") + if amp is None: + raise RuntimeError("Failed to import apex. Please install apex from https://www.github.com/nvidia/apex " + "to enable mixed-precision training.") + + if args.output_dir: + utils.mkdir(args.output_dir) + + if args.distributed: + utils.init_distributed_mode(args) + + device = torch.device(f'npu:{args.device}') + torch.npu.set_device(device) + + torch.backends.cudnn.benchmark = True + + # Data loading code + print("Loading data") + traindir = os.path.join(args.data_path, 'train') + valdir = os.path.join(args.data_path, 'val') + normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]) + + print("Loading training data") + st = time.time() + cache_path = _get_cache_path(traindir) + if args.cache_dataset and os.path.exists(cache_path): + # Attention, as the transforms are also cached! + print("Loading dataset_train from {}".format(cache_path)) + dataset, _ = torch.load(cache_path) + else: + dataset = torchvision.datasets.ImageFolder( + traindir, + transforms.Compose([ + transforms.RandomResizedCrop(299), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + normalize, + ])) + if args.cache_dataset: + print("Saving dataset_train to {}".format(cache_path)) + utils.mkdir(os.path.dirname(cache_path)) + utils.save_on_master((dataset, traindir), cache_path) + print("Took", time.time() - st) + + print("Loading validation data") + cache_path = _get_cache_path(valdir) + if args.cache_dataset and os.path.exists(cache_path): + # Attention, as the transforms are also cached! + print("Loading dataset_test from {}".format(cache_path)) + dataset_test, _ = torch.load(cache_path) + else: + dataset_test = torchvision.datasets.ImageFolder( + valdir, + transforms.Compose([ + transforms.Resize(342), + transforms.CenterCrop(299), + transforms.ToTensor(), + normalize, + ])) + if args.cache_dataset: + print("Saving dataset_test to {}".format(cache_path)) + utils.mkdir(os.path.dirname(cache_path)) + utils.save_on_master((dataset_test, valdir), cache_path) + + print("Creating data loaders") + if args.distributed: + print(len(dataset)) + train_sampler = torch.utils.data.distributed.DistributedSampler(dataset) + print(len(train_sampler)) + test_sampler = torch.utils.data.distributed.DistributedSampler(dataset_test) + else: + train_sampler = torch.utils.data.RandomSampler(dataset) + test_sampler = torch.utils.data.SequentialSampler(dataset_test) + + print(len(train_sampler),args.batch_size,args.workers) + data_loader = torch.utils.data.DataLoader( + dataset, batch_size=args.batch_size, + sampler=train_sampler, num_workers=args.workers,drop_last=True) # pin_memory=True + print(len(data_loader)) + + data_loader_test = torch.utils.data.DataLoader( + dataset_test, batch_size=args.batch_size, + sampler=test_sampler, num_workers=args.workers, drop_last=True) + + print("Creating model") + print(torchvision.models.__dict__) + model = torchvision.models.__dict__[args.model](pretrained=args.pretrained) + #model = inception.inception_v3(pretrained=args.pretrained) + model.to(device) + + + + criterion = nn.CrossEntropyLoss().to(device) + #criterion = nn.CrossEntropyLoss() + + optimizer = apex.optimizers.NpuFusedSGD( + model.parameters(), lr=args.lr, momentum=args.momentum, weight_decay=args.weight_decay) + + if args.apex: + model, optimizer = amp.initialize(model, optimizer, + opt_level=args.apex_opt_level, + loss_scale=args.loss_scale, + combine_grad=True + ) #loss_scale=args.loss_scale, + + lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=args.lr_step_size, gamma=args.lr_gamma) + + model_without_ddp = model + + if args.distributed: + print(args.device) + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.device],find_unused_parameters=True) # output_device=args.device, + model_without_ddp = model.module + + if args.resume: + checkpoint = torch.load(args.resume, map_location='cpu') + model_without_ddp.load_state_dict(checkpoint['model']) + optimizer.load_state_dict(checkpoint['optimizer']) + lr_scheduler.load_state_dict(checkpoint['lr_scheduler']) + args.start_epoch = checkpoint['epoch'] + 1 + + if args.test_only: + evaluate(model, criterion, data_loader_test, device=device) + return + + print("Start training") + start_time = time.time() + for epoch in range(args.start_epoch, args.epochs): + if args.distributed: + train_sampler.set_epoch(epoch) + train_one_epoch(model, criterion, optimizer, data_loader, device, epoch, args.print_freq, args.apex) + lr_scheduler.step() + evaluate(model, criterion, data_loader_test, device=device) + if args.output_dir: + checkpoint = { + 'model': model_without_ddp.state_dict(), + 'optimizer': optimizer.state_dict(), + 'lr_scheduler': lr_scheduler.state_dict(), + 'epoch': epoch, + 'args': args} + utils.save_on_master( + checkpoint, + os.path.join(args.output_dir, 'model_{}.pth'.format(epoch))) + utils.save_on_master( + checkpoint, + os.path.join(args.output_dir, 'checkpoint.pth')) + + total_time = time.time() - start_time + total_time_str = str(datetime.timedelta(seconds=int(total_time))) + print('Training time {}'.format(total_time_str)) + + +def parse_args(): + import argparse + parser = argparse.ArgumentParser(description='PyTorch Classification Training') + + parser.add_argument('--data-path', default='/datasets01/imagenet_full_size/061417/', help='dataset') + parser.add_argument('--model', default='resnet18', help='model') + parser.add_argument('--device', default='6', help='device') + parser.add_argument('-b', '--batch-size', default=32, type=int) + parser.add_argument('--epochs', default=90, type=int, metavar='N', + help='number of total epochs to run') + parser.add_argument('--max_steps', default=None, type=int, metavar='N', + help='number of total steps to run') + parser.add_argument('-j', '--workers', default=32, type=int, metavar='N', + help='number of data loading workers (default: 16)') + parser.add_argument('--lr', default=0.1, type=float, help='initial learning rate') + parser.add_argument('--momentum', default=0.9, type=float, metavar='M', + help='momentum') + parser.add_argument('--wd', '--weight-decay', default=1e-4, type=float, + metavar='W', help='weight decay (default: 1e-4)', + dest='weight_decay') + parser.add_argument('--lr-step-size', default=30, type=int, help='decrease lr every step-size epochs') + parser.add_argument('--lr-gamma', default=0.1, type=float, help='decrease lr by a factor of lr-gamma') + parser.add_argument('--print-freq', default=10, type=int, help='print frequency') + parser.add_argument('--output-dir', default='.', help='path where to save') + parser.add_argument('--resume', default='', help='resume from checkpoint') + parser.add_argument('--start-epoch', default=0, type=int, metavar='N', + help='start epoch') + parser.add_argument( + "--cache-dataset", + dest="cache_dataset", + help="Cache the datasets for quicker initialization. It also serializes the transforms", + action="store_true", + ) + parser.add_argument( + "--sync-bn", + dest="sync_bn", + help="Use sync batch norm", + action="store_true", + ) + parser.add_argument( + "--test-only", + dest="test_only", + help="Only test the model", + action="store_true", + ) + parser.add_argument( + "--pretrained", + dest="pretrained", + help="Use pre-trained models from the modelzoo", + action="store_true", + ) + + # Mixed precision training parameters + parser.add_argument('--apex', action='store_true', + help='Use apex for mixed precision training') + parser.add_argument('--apex-opt-level', default='O1', type=str, + help='For apex mixed precision training' + 'O0 for FP32 training, O1 for mixed precision training.' + 'For further detail, see https://github.com/NVIDIA/apex/tree/master/examples/imagenet' + ) + parser.add_argument('--loss_scale', default=1024., type=float, + help='loss scale using in amp, default -1 means dynamic') + + # distributed training parameters + parser.add_argument('--world-size', default=1, type=int, + help='number of distributed processes') + parser.add_argument('--dist-url', default='env://', help='url used to set up distributed training') + parser.add_argument('--distributed', + action='store_true', + help='Use multi-processing distributed training to launch ' + 'N processes per node, which has N GPUs.') + parser.add_argument('--dist_rank', + default=0, + type=int, + help='node rank for distributed training') + parser.add_argument('--seed', + default=1, + type=int, + help='Manually set random seed') + + args = parser.parse_args() + + return args + + +if __name__ == "__main__": + args = parse_args() + main(args) diff --git a/PyTorch/dev/cv/image_classification/InceptionV3_ID0445_for_PyTorch/utils3.py b/PyTorch/dev/cv/image_classification/InceptionV3_ID0445_for_PyTorch/utils3.py index 3ac42e9b7b..b41e2d90ab 100644 --- a/PyTorch/dev/cv/image_classification/InceptionV3_ID0445_for_PyTorch/utils3.py +++ b/PyTorch/dev/cv/image_classification/InceptionV3_ID0445_for_PyTorch/utils3.py @@ -1,288 +1,288 @@ -# -# BSD 3-Clause License -# -# Copyright (c) 2017 xxxx -# All rights reserved. -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ============================================================================ -#from __future__ import print_function -from collections import defaultdict, deque -import datetime -import time -import torch -import torch.distributed as dist - -import errno -import os - - -class SmoothedValue(object): - """Track a series of values and provide access to smoothed values over a - window or the global series average. - """ - - def __init__(self, window_size=20, fmt=None): - if fmt is None: - fmt = "{median:.4f} ({global_avg:.4f})" - self.deque = deque(maxlen=window_size) - self.total = 0.0 - self.count = 0.0 - self.fmt = fmt - - def update(self, value, n=1): - self.deque.append(value) - self.count += n - self.total += value * n - - def synchronize_between_processes(self,npu_device): - """ - Warning: does not synchronize the deque! - """ - if not is_dist_avail_and_initialized(): - return - t = torch.as_tensor([self.count, self.total], dtype=torch.float32, device=npu_device) - print(t,t.dtype) - dist.barrier() - dist.all_reduce(t) - t = t.tolist() - self.count = int(t[0]) - self.total = t[1] - - @property - def median(self): - d = torch.tensor(list(self.deque)) - return d.median().item() - - @property - def avg(self): - d = torch.tensor(list(self.deque), dtype=torch.float32) - return d.mean().item() - - @property - def global_avg(self): - return self.total / self.count - - @property - def max(self): - return max(self.deque) - - @property - def value(self): - return self.deque[-1] - - def __str__(self): - return self.fmt.format( - median=self.median, - avg=self.avg, - global_avg=self.global_avg, - max=self.max, - value=self.value) - - -class MetricLogger(object): - def __init__(self, delimiter="\t"): - self.meters = defaultdict(SmoothedValue) - self.delimiter = delimiter - - def update(self, **kwargs): - for k, v in kwargs.items(): - if isinstance(v, torch.Tensor): - v = v.item() - assert isinstance(v, (float, int)) - self.meters[k].update(v) - - def __getattr__(self, attr): - if attr in self.meters: - return self.meters[attr] - if attr in self.__dict__: - return self.__dict__[attr] - raise AttributeError("'{}' object has no attribute '{}'".format( - type(self).__name__, attr)) - - def __str__(self): - loss_str = [] - for name, meter in self.meters.items(): - loss_str.append( - "{}: {}".format(name, str(meter)) - ) - return self.delimiter.join(loss_str) - - def synchronize_between_processes(self,device): - for meter in self.meters.values(): - meter.synchronize_between_processes(device) - - def add_meter(self, name, meter): - self.meters[name] = meter - - def log_every(self, iterable, print_freq, header=None): - i = 0 - if not header: - header = '' - start_time = time.time() - end = time.time() - iter_time = SmoothedValue(fmt='{avg:.4f}') - data_time = SmoothedValue(fmt='{avg:.4f}') - space_fmt = ':' + str(len(str(len(iterable)))) + 'd' - if torch.npu.is_available(): - log_msg = self.delimiter.join([ - header, - '[{0' + space_fmt + '}/{1}]', - 'eta: {eta}', - '{meters}', - 'time: {time}', - 'data: {data}', - 'max mem: {memory:.0f}' - ]) - else: - log_msg = self.delimiter.join([ - header, - '[{0' + space_fmt + '}/{1}]', - 'eta: {eta}', - '{meters}', - 'time: {time}', - 'data: {data}' - ]) - MB = 1024.0 * 1024.0 - for obj in iterable: - data_time.update(time.time() - end) - yield obj - iter_time.update(time.time() - end) - if i % print_freq == 0: - eta_seconds = iter_time.global_avg * (len(iterable) - i) - eta_string = str(datetime.timedelta(seconds=int(eta_seconds))) - if torch.npu.is_available(): - print(log_msg.format( - i, len(iterable), eta=eta_string, - meters=str(self), - time=str(iter_time), data=str(data_time), - memory=0)) - #memory=torch.cuda.max_memory_allocated() / MB)) - else: - print(log_msg.format( - i, len(iterable), eta=eta_string, - meters=str(self), - time=str(iter_time), data=str(data_time))) - i += 1 - end = time.time() - total_time = time.time() - start_time - total_time_str = str(datetime.timedelta(seconds=int(total_time))) - print('{} Total time: {}'.format(header, total_time_str)) - - -def accuracy(output, target, topk=(1,)): - """Computes the accuracy over the k top predictions for the specified values of k""" - with torch.no_grad(): - maxk = max(topk) - batch_size = target.size(0) - - _, pred = output.topk(maxk, 1, True, True) - pred = pred.t() - correct = pred.eq(target[None]) - - res = [] - for k in topk: - correct_k = correct[:k].flatten().sum(dtype=torch.float32) - res.append(correct_k * (100.0 / batch_size)) - return res - - -def mkdir(path): - try: - os.makedirs(path) - except OSError as e: - if e.errno != errno.EEXIST: - raise - - -def setup_for_distributed(is_master): - """ - This function disables printing when not in master process - """ - import builtins as __builtin__ - builtin_print = __builtin__.print - - def print(*args, **kwargs): - force = kwargs.pop('force', False) - if is_master or force: - builtin_print(*args, **kwargs) - - __builtin__.print = print - - -def is_dist_avail_and_initialized(): - if not dist.is_available(): - return False - if not dist.is_initialized(): - return False - return True - - -def get_world_size(): - if not is_dist_avail_and_initialized(): - return 1 - return dist.get_world_size() - - -def get_rank(): - if not is_dist_avail_and_initialized(): - return 0 - return dist.get_rank() - - -def is_main_process(): - return get_rank() == 0 - - -def save_on_master(*args, **kwargs): - torch.save(*args, **kwargs) - - -def init_distributed_mode(args): - if 'RANK' in os.environ and 'WORLD_SIZE' in os.environ: - args.rank = int(os.environ["RANK"]) - args.world_size = int(os.environ['WORLD_SIZE']) - args.gpu = int(os.environ['LOCAL_RANK']) - elif 'SLURM_PROCID' in os.environ: - args.rank = int(os.environ['SLURM_PROCID']) - args.gpu = args.rank % torch.cuda.device_count() - elif hasattr(args, "rank"): - pass - else: - print('Not using distributed mode') - args.distributed = False - return - - args.distributed = True - - torch.npu.set_device(args.gpu) - args.dist_backend = 'nccl' - print('| distributed init (rank {}): {}'.format( - args.rank, args.dist_url), flush=True) - torch.distributed.init_process_group(backend=args.dist_backend, init_method=args.dist_url, - world_size=args.world_size, rank=args.rank) - setup_for_distributed(args.rank == 0) +# +# BSD 3-Clause License +# +# Copyright (c) 2017 xxxx +# All rights reserved. +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================ +#from __future__ import print_function +from collections import defaultdict, deque +import datetime +import time +import torch +import torch.distributed as dist + +import errno +import os + + +class SmoothedValue(object): + """Track a series of values and provide access to smoothed values over a + window or the global series average. + """ + + def __init__(self, window_size=20, fmt=None): + if fmt is None: + fmt = "{median:.4f} ({global_avg:.4f})" + self.deque = deque(maxlen=window_size) + self.total = 0.0 + self.count = 0.0 + self.fmt = fmt + + def update(self, value, n=1): + self.deque.append(value) + self.count += n + self.total += value * n + + def synchronize_between_processes(self,npu_device): + """ + Warning: does not synchronize the deque! + """ + if not is_dist_avail_and_initialized(): + return + t = torch.as_tensor([self.count, self.total], dtype=torch.float32, device=npu_device) + print(t,t.dtype) + dist.barrier() + dist.all_reduce(t) + t = t.tolist() + self.count = int(t[0]) + self.total = t[1] + + @property + def median(self): + d = torch.tensor(list(self.deque)) + return d.median().item() + + @property + def avg(self): + d = torch.tensor(list(self.deque), dtype=torch.float32) + return d.mean().item() + + @property + def global_avg(self): + return self.total / self.count + + @property + def max(self): + return max(self.deque) + + @property + def value(self): + return self.deque[-1] + + def __str__(self): + return self.fmt.format( + median=self.median, + avg=self.avg, + global_avg=self.global_avg, + max=self.max, + value=self.value) + + +class MetricLogger(object): + def __init__(self, delimiter="\t"): + self.meters = defaultdict(SmoothedValue) + self.delimiter = delimiter + + def update(self, **kwargs): + for k, v in kwargs.items(): + if isinstance(v, torch.Tensor): + v = v.item() + assert isinstance(v, (float, int)) + self.meters[k].update(v) + + def __getattr__(self, attr): + if attr in self.meters: + return self.meters[attr] + if attr in self.__dict__: + return self.__dict__[attr] + raise AttributeError("'{}' object has no attribute '{}'".format( + type(self).__name__, attr)) + + def __str__(self): + loss_str = [] + for name, meter in self.meters.items(): + loss_str.append( + "{}: {}".format(name, str(meter)) + ) + return self.delimiter.join(loss_str) + + def synchronize_between_processes(self,device): + for meter in self.meters.values(): + meter.synchronize_between_processes(device) + + def add_meter(self, name, meter): + self.meters[name] = meter + + def log_every(self, iterable, print_freq, header=None): + i = 0 + if not header: + header = '' + start_time = time.time() + end = time.time() + iter_time = SmoothedValue(fmt='{avg:.4f}') + data_time = SmoothedValue(fmt='{avg:.4f}') + space_fmt = ':' + str(len(str(len(iterable)))) + 'd' + if torch.npu.is_available(): + log_msg = self.delimiter.join([ + header, + '[{0' + space_fmt + '}/{1}]', + 'eta: {eta}', + '{meters}', + 'time: {time}', + 'data: {data}', + 'max mem: {memory:.0f}' + ]) + else: + log_msg = self.delimiter.join([ + header, + '[{0' + space_fmt + '}/{1}]', + 'eta: {eta}', + '{meters}', + 'time: {time}', + 'data: {data}' + ]) + MB = 1024.0 * 1024.0 + for obj in iterable: + data_time.update(time.time() - end) + yield obj + iter_time.update(time.time() - end) + if i % print_freq == 0: + eta_seconds = iter_time.global_avg * (len(iterable) - i) + eta_string = str(datetime.timedelta(seconds=int(eta_seconds))) + if torch.npu.is_available(): + print(log_msg.format( + i, len(iterable), eta=eta_string, + meters=str(self), + time=str(iter_time), data=str(data_time), + memory=0)) + #memory=torch.cuda.max_memory_allocated() / MB)) + else: + print(log_msg.format( + i, len(iterable), eta=eta_string, + meters=str(self), + time=str(iter_time), data=str(data_time))) + i += 1 + end = time.time() + total_time = time.time() - start_time + total_time_str = str(datetime.timedelta(seconds=int(total_time))) + print('{} Total time: {}'.format(header, total_time_str)) + + +def accuracy(output, target, topk=(1,)): + """Computes the accuracy over the k top predictions for the specified values of k""" + with torch.no_grad(): + maxk = max(topk) + batch_size = target.size(0) + + _, pred = output.topk(maxk, 1, True, True) + pred = pred.t() + correct = pred.eq(target[None]) + + res = [] + for k in topk: + correct_k = correct[:k].flatten().sum(dtype=torch.float32) + res.append(correct_k * (100.0 / batch_size)) + return res + + +def mkdir(path): + try: + os.makedirs(path) + except OSError as e: + if e.errno != errno.EEXIST: + raise + + +def setup_for_distributed(is_master): + """ + This function disables printing when not in master process + """ + import builtins as __builtin__ + builtin_print = __builtin__.print + + def print(*args, **kwargs): + force = kwargs.pop('force', False) + if is_master or force: + builtin_print(*args, **kwargs) + + __builtin__.print = print + + +def is_dist_avail_and_initialized(): + if not dist.is_available(): + return False + if not dist.is_initialized(): + return False + return True + + +def get_world_size(): + if not is_dist_avail_and_initialized(): + return 1 + return dist.get_world_size() + + +def get_rank(): + if not is_dist_avail_and_initialized(): + return 0 + return dist.get_rank() + + +def is_main_process(): + return get_rank() == 0 + + +def save_on_master(*args, **kwargs): + torch.save(*args, **kwargs) + + +def init_distributed_mode(args): + if 'RANK' in os.environ and 'WORLD_SIZE' in os.environ: + args.rank = int(os.environ["RANK"]) + args.world_size = int(os.environ['WORLD_SIZE']) + args.gpu = int(os.environ['LOCAL_RANK']) + elif 'SLURM_PROCID' in os.environ: + args.rank = int(os.environ['SLURM_PROCID']) + args.gpu = args.rank % torch.cuda.device_count() + elif hasattr(args, "rank"): + pass + else: + print('Not using distributed mode') + args.distributed = False + return + + args.distributed = True + + torch.npu.set_device(args.gpu) + args.dist_backend = 'nccl' + print('| distributed init (rank {}): {}'.format( + args.rank, args.dist_url), flush=True) + torch.distributed.init_process_group(backend=args.dist_backend, init_method=args.dist_url, + world_size=args.world_size, rank=args.rank) + setup_for_distributed(args.rank == 0) diff --git a/PyTorch/dev/cv/image_classification/MaskRCNN_ID0101_for_PyTorch/test/train_full_8p.sh b/PyTorch/dev/cv/image_classification/MaskRCNN_ID0101_for_PyTorch/test/train_full_8p.sh index 947225d26f..f194144737 100644 --- a/PyTorch/dev/cv/image_classification/MaskRCNN_ID0101_for_PyTorch/test/train_full_8p.sh +++ b/PyTorch/dev/cv/image_classification/MaskRCNN_ID0101_for_PyTorch/test/train_full_8p.sh @@ -1,223 +1,223 @@ -#!/bin/bash -export HCCL_WHITELIST_DISABLE=1 -export MASTER_ADDR=127.0.0.1 -export MASTER_PORT=23456 -#当前路径,不需要修改 -cur_path=`pwd` -#ASCEND_DEVICE_ID=1 -export ASCEND_SLOG_PRINT_TO_STDOUT=0 -export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID - -#集合通信参数,不需要修改 -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 - - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="MaskRCNN_ID0101_for_PyTorch" -#训练epoch -train_epochs=82000 -#训练batch_size -batch_size=8 -#训练step -train_steps= -#学习率 -learning_rate= - -#TF2.X独有,不需要修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False -autotune=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_full_1p.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is False - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --conda_name* ]];then - conda_name=`echo ${para#*=}` - source set_conda.sh --conda_name=$conda_name - source activate $conda_name - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - - -#进入训练脚本目录,需要模型审视修改 -cd $cur_path/../ - -sed -i "s|\"coco_2017_train\": (\"coco/train2017\", \"coco/annotations/instances_train2017.json\")|\"coco_2017_train\": (\"$data_path/coco/train2017\", \"$data_path/coco/annotations/instances_train2017.json\")|g" $cur_path/../detectron2/data/datasets/builtin.py -sed -i "s|\"coco_2017_val\": (\"coco/val2017\", \"coco/annotations/instances_val2017.json\")|\"coco_2017_val\": (\"$data_path/coco/val2017\", \"$data_path/coco/annotations/instances_val2017.json\")|g" $cur_path/../detectron2/data/datasets/builtin.py -sed -i "s|WEIGHTS: \"detectron2://ImageNetPretrained/MSRA/R-101.pkl\"|WEIGHTS: \"$data_path/R-101.pkl\"|g" $cur_path/../configs/COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml - -python3 setup.py build develop > $cur_path/../log.txt - - -#训练开始时间,不需要修改 -start_time=$(date +%s) -for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); -do - #设置环境变量,不需要修改 - echo "Device ID: $ASCEND_DEVICE_ID" - export RANK_ID=$RANK_ID - - - - #创建DeviceID输出目录,不需要修改 - if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - fi - - #绑核,不需要绑核的模型删除,需要绑核的模型根据实际修改 - #cpucount=`lscpu | grep "CPU(s):" | head -n 1 | awk '{print $2}'` - #cpustep=`expr $cpucount / 8` - #echo "taskset c steps:" $cpustep - #let a=RANK_ID*$cpustep - #let b=RANK_ID+1 - #let c=b*$cpustep-1 - - - - #SOLVER.MAX_ITER 82000 \ - #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 -done -wait - - - - - -NPUS=($(seq 0 7)) -export NPU_WORLD_SIZE=${#NPUS[@]} -rank=0 -for i in ${NPUS[@]} -do - export NPU_CALCULATE_DEVICE=${i} - mkdir -p $cur_path/test/output/${i}/ - export RANK=${rank} - echo run process ${rank} - python3 tools/train_net.py \ - --config-file configs/COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml \ - --num-gpus 8 \ - AMP 1\ - OPT_LEVEL O2 \ - LOSS_SCALE_VALUE 64 \ - SOLVER.IMS_PER_BATCH $batch_size \ - SOLVER.MAX_ITER 82000 \ - SEED 1234 \ - MODEL.RPN.NMS_THRESH 0.8 \ - MODEL.ROI_BOX_HEAD.POOLER_SAMPLING_RATIO 2 \ - MODEL.ROI_MASK_HEAD.POOLER_SAMPLING_RATIO 2 \ - DATALOADER.NUM_WORKERS 4 \ - SOLVER.BASE_LR 0.0025 > $cur_path/test/output/$ASCEND_DEVICE_ID/train_${i}.log 2>&1 & - let rank++ -done - - - -wait - - -#conda deactivate -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - - - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -Time=`grep total_loss $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F 'time: ' '{print $2}'|awk '{print $1}'|tail -n +3|awk '{sum+=$1} END {print sum/NR}'|sed s/[[:space:]]//g` -FPS=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'/'${Time}'}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=None -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#稳定性精度看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据 -#吞吐量,不需要修改 -ActualFPS=${FPS} -#单迭代训练时长,不需要修改 -TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep total_loss $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'total_loss: ' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -#echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash +export HCCL_WHITELIST_DISABLE=1 +export MASTER_ADDR=127.0.0.1 +export MASTER_PORT=23456 +#当前路径,不需要修改 +cur_path=`pwd` +#ASCEND_DEVICE_ID=1 +export ASCEND_SLOG_PRINT_TO_STDOUT=0 +export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID + +#集合通信参数,不需要修改 +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 + + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="MaskRCNN_ID0101_for_PyTorch" +#训练epoch +train_epochs=82000 +#训练batch_size +batch_size=8 +#训练step +train_steps= +#学习率 +learning_rate= + +#TF2.X独有,不需要修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False +autotune=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_full_1p.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is False + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --conda_name* ]];then + conda_name=`echo ${para#*=}` + source set_conda.sh --conda_name=$conda_name + source activate $conda_name + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + + +#进入训练脚本目录,需要模型审视修改 +cd $cur_path/../ + +sed -i "s|\"coco_2017_train\": (\"coco/train2017\", \"coco/annotations/instances_train2017.json\")|\"coco_2017_train\": (\"$data_path/coco/train2017\", \"$data_path/coco/annotations/instances_train2017.json\")|g" $cur_path/../detectron2/data/datasets/builtin.py +sed -i "s|\"coco_2017_val\": (\"coco/val2017\", \"coco/annotations/instances_val2017.json\")|\"coco_2017_val\": (\"$data_path/coco/val2017\", \"$data_path/coco/annotations/instances_val2017.json\")|g" $cur_path/../detectron2/data/datasets/builtin.py +sed -i "s|WEIGHTS: \"detectron2://ImageNetPretrained/MSRA/R-101.pkl\"|WEIGHTS: \"$data_path/R-101.pkl\"|g" $cur_path/../configs/COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml + +python3 setup.py build develop > $cur_path/../log.txt + + +#训练开始时间,不需要修改 +start_time=$(date +%s) +for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); +do + #设置环境变量,不需要修改 + echo "Device ID: $ASCEND_DEVICE_ID" + export RANK_ID=$RANK_ID + + + + #创建DeviceID输出目录,不需要修改 + if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + fi + + #绑核,不需要绑核的模型删除,需要绑核的模型根据实际修改 + #cpucount=`lscpu | grep "CPU(s):" | head -n 1 | awk '{print $2}'` + #cpustep=`expr $cpucount / 8` + #echo "taskset c steps:" $cpustep + #let a=RANK_ID*$cpustep + #let b=RANK_ID+1 + #let c=b*$cpustep-1 + + + + #SOLVER.MAX_ITER 82000 \ + #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 +done +wait + + + + + +NPUS=($(seq 0 7)) +export NPU_WORLD_SIZE=${#NPUS[@]} +rank=0 +for i in ${NPUS[@]} +do + export NPU_CALCULATE_DEVICE=${i} + mkdir -p $cur_path/test/output/${i}/ + export RANK=${rank} + echo run process ${rank} + python3 tools/train_net.py \ + --config-file configs/COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml \ + --num-gpus 8 \ + AMP 1\ + OPT_LEVEL O2 \ + LOSS_SCALE_VALUE 64 \ + SOLVER.IMS_PER_BATCH $batch_size \ + SOLVER.MAX_ITER 82000 \ + SEED 1234 \ + MODEL.RPN.NMS_THRESH 0.8 \ + MODEL.ROI_BOX_HEAD.POOLER_SAMPLING_RATIO 2 \ + MODEL.ROI_MASK_HEAD.POOLER_SAMPLING_RATIO 2 \ + DATALOADER.NUM_WORKERS 4 \ + SOLVER.BASE_LR 0.0025 > $cur_path/test/output/$ASCEND_DEVICE_ID/train_${i}.log 2>&1 & + let rank++ +done + + + +wait + + +#conda deactivate +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + + + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +Time=`grep total_loss $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F 'time: ' '{print $2}'|awk '{print $1}'|tail -n +3|awk '{sum+=$1} END {print sum/NR}'|sed s/[[:space:]]//g` +FPS=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'/'${Time}'}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=None +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#稳定性精度看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据 +#吞吐量,不需要修改 +ActualFPS=${FPS} +#单迭代训练时长,不需要修改 +TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep total_loss $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'total_loss: ' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log diff --git a/PyTorch/dev/cv/image_classification/MaskRCNN_ID0101_for_PyTorch/test/train_performance_8p.sh b/PyTorch/dev/cv/image_classification/MaskRCNN_ID0101_for_PyTorch/test/train_performance_8p.sh index e35123e027..0373df8202 100644 --- a/PyTorch/dev/cv/image_classification/MaskRCNN_ID0101_for_PyTorch/test/train_performance_8p.sh +++ b/PyTorch/dev/cv/image_classification/MaskRCNN_ID0101_for_PyTorch/test/train_performance_8p.sh @@ -1,224 +1,224 @@ -#!/bin/bash -export HCCL_WHITELIST_DISABLE=1 -export MASTER_ADDR=127.0.0.1 -export MASTER_PORT=23456 -#当前路径,不需要修改 -cur_path=`pwd` -#ASCEND_DEVICE_ID=1 -export ASCEND_SLOG_PRINT_TO_STDOUT=0 -export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID - -#集合通信参数,不需要修改 -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 - - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="MaskRCNN_ID0101_for_PyTorch" -#训练epoch -train_epochs=100 -#训练batch_size -batch_size=8 -#训练step -train_steps= -#学习率 -learning_rate= - -#TF2.X独有,不需要修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False -autotune=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_full_1p.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is False - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --conda_name* ]];then - conda_name=`echo ${para#*=}` - source set_conda.sh --conda_name=$conda_name - source activate $conda_name - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - - -#进入训练脚本目录,需要模型审视修改 -cd $cur_path/../ - -sed -i "s|\"coco_2017_train\": (\"coco/train2017\", \"coco/annotations/instances_train2017.json\")|\"coco_2017_train\": (\"$data_path/coco/train2017\", \"$data_path/coco/annotations/instances_train2017.json\")|g" $cur_path/../detectron2/data/datasets/builtin.py -sed -i "s|\"coco_2017_val\": (\"coco/val2017\", \"coco/annotations/instances_val2017.json\")|\"coco_2017_val\": (\"$data_path/coco/val2017\", \"$data_path/coco/annotations/instances_val2017.json\")|g" $cur_path/../detectron2/data/datasets/builtin.py -sed -i "s|WEIGHTS: \"detectron2://ImageNetPretrained/MSRA/R-101.pkl\"|WEIGHTS: \"$data_path/R-101.pkl\"|g" $cur_path/../configs/COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml - -python3 setup.py build develop > $cur_path/../log.txt - - -#训练开始时间,不需要修改 -start_time=$(date +%s) -for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); -do - #设置环境变量,不需要修改 - echo "Device ID: $ASCEND_DEVICE_ID" - export RANK_ID=$RANK_ID - - - - #创建DeviceID输出目录,不需要修改 - if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - fi - - #绑核,不需要绑核的模型删除,需要绑核的模型根据实际修改 - #cpucount=`lscpu | grep "CPU(s):" | head -n 1 | awk '{print $2}'` - #cpustep=`expr $cpucount / 8` - #echo "taskset c steps:" $cpustep - #let a=RANK_ID*$cpustep - #let b=RANK_ID+1 - #let c=b*$cpustep-1 - - - - #SOLVER.MAX_ITER 82000 \ - #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 -done -wait - - - - - -NPUS=($(seq 0 7)) -export NPU_WORLD_SIZE=${#NPUS[@]} -rank=0 -for i in ${NPUS[@]} -do - export NPU_CALCULATE_DEVICE=${i} - mkdir -p $cur_path/output/${i}/ - export ASCEND_DEVICE_ID=${i} - export RANK=${rank} - echo run process ${rank} - python3 tools/train_net.py \ - --config-file configs/COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml \ - --num-gpus 8 \ - AMP 1\ - OPT_LEVEL O2 \ - LOSS_SCALE_VALUE 64 \ - SOLVER.IMS_PER_BATCH $batch_size \ - SOLVER.MAX_ITER 100 \ - SEED 1234 \ - MODEL.RPN.NMS_THRESH 0.8 \ - MODEL.ROI_BOX_HEAD.POOLER_SAMPLING_RATIO 2 \ - MODEL.ROI_MASK_HEAD.POOLER_SAMPLING_RATIO 2 \ - DATALOADER.NUM_WORKERS 4 \ - SOLVER.BASE_LR 0.0025 > $cur_path/output/$ASCEND_DEVICE_ID/train_${i}.log 2>&1 & - let rank++ -done - - - -wait - - -#conda deactivate -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - - - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -Time=`grep total_loss $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F 'time: ' '{print $2}'|awk '{print $1}'|tail -n +3|awk '{sum+=$1} END {print sum/NR}'|sed s/[[:space:]]//g` -FPS=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'/'${Time}'}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=None -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#稳定性精度看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据 -#吞吐量,不需要修改 -ActualFPS=${FPS} -#单迭代训练时长,不需要修改 -TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep total_loss $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'total_loss: ' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -#echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash +export HCCL_WHITELIST_DISABLE=1 +export MASTER_ADDR=127.0.0.1 +export MASTER_PORT=23456 +#当前路径,不需要修改 +cur_path=`pwd` +#ASCEND_DEVICE_ID=1 +export ASCEND_SLOG_PRINT_TO_STDOUT=0 +export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID + +#集合通信参数,不需要修改 +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 + + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="MaskRCNN_ID0101_for_PyTorch" +#训练epoch +train_epochs=100 +#训练batch_size +batch_size=8 +#训练step +train_steps= +#学习率 +learning_rate= + +#TF2.X独有,不需要修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False +autotune=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_full_1p.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is False + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --conda_name* ]];then + conda_name=`echo ${para#*=}` + source set_conda.sh --conda_name=$conda_name + source activate $conda_name + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + + +#进入训练脚本目录,需要模型审视修改 +cd $cur_path/../ + +sed -i "s|\"coco_2017_train\": (\"coco/train2017\", \"coco/annotations/instances_train2017.json\")|\"coco_2017_train\": (\"$data_path/coco/train2017\", \"$data_path/coco/annotations/instances_train2017.json\")|g" $cur_path/../detectron2/data/datasets/builtin.py +sed -i "s|\"coco_2017_val\": (\"coco/val2017\", \"coco/annotations/instances_val2017.json\")|\"coco_2017_val\": (\"$data_path/coco/val2017\", \"$data_path/coco/annotations/instances_val2017.json\")|g" $cur_path/../detectron2/data/datasets/builtin.py +sed -i "s|WEIGHTS: \"detectron2://ImageNetPretrained/MSRA/R-101.pkl\"|WEIGHTS: \"$data_path/R-101.pkl\"|g" $cur_path/../configs/COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml + +python3 setup.py build develop > $cur_path/../log.txt + + +#训练开始时间,不需要修改 +start_time=$(date +%s) +for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); +do + #设置环境变量,不需要修改 + echo "Device ID: $ASCEND_DEVICE_ID" + export RANK_ID=$RANK_ID + + + + #创建DeviceID输出目录,不需要修改 + if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + fi + + #绑核,不需要绑核的模型删除,需要绑核的模型根据实际修改 + #cpucount=`lscpu | grep "CPU(s):" | head -n 1 | awk '{print $2}'` + #cpustep=`expr $cpucount / 8` + #echo "taskset c steps:" $cpustep + #let a=RANK_ID*$cpustep + #let b=RANK_ID+1 + #let c=b*$cpustep-1 + + + + #SOLVER.MAX_ITER 82000 \ + #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 +done +wait + + + + + +NPUS=($(seq 0 7)) +export NPU_WORLD_SIZE=${#NPUS[@]} +rank=0 +for i in ${NPUS[@]} +do + export NPU_CALCULATE_DEVICE=${i} + mkdir -p $cur_path/output/${i}/ + export ASCEND_DEVICE_ID=${i} + export RANK=${rank} + echo run process ${rank} + python3 tools/train_net.py \ + --config-file configs/COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml \ + --num-gpus 8 \ + AMP 1\ + OPT_LEVEL O2 \ + LOSS_SCALE_VALUE 64 \ + SOLVER.IMS_PER_BATCH $batch_size \ + SOLVER.MAX_ITER 100 \ + SEED 1234 \ + MODEL.RPN.NMS_THRESH 0.8 \ + MODEL.ROI_BOX_HEAD.POOLER_SAMPLING_RATIO 2 \ + MODEL.ROI_MASK_HEAD.POOLER_SAMPLING_RATIO 2 \ + DATALOADER.NUM_WORKERS 4 \ + SOLVER.BASE_LR 0.0025 > $cur_path/output/$ASCEND_DEVICE_ID/train_${i}.log 2>&1 & + let rank++ +done + + + +wait + + +#conda deactivate +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + + + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +Time=`grep total_loss $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F 'time: ' '{print $2}'|awk '{print $1}'|tail -n +3|awk '{sum+=$1} END {print sum/NR}'|sed s/[[:space:]]//g` +FPS=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'/'${Time}'}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=None +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#稳定性精度看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据 +#吞吐量,不需要修改 +ActualFPS=${FPS} +#单迭代训练时长,不需要修改 +TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep total_loss $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F 'total_loss: ' '{print $2}'|awk '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log diff --git a/PyTorch/dev/cv/image_classification/NeuMF_ID0351_for_PyTorch/LICENSE b/PyTorch/dev/cv/image_classification/NeuMF_ID0351_for_PyTorch/LICENSE index db05a35866..09d493bf1f 100644 --- a/PyTorch/dev/cv/image_classification/NeuMF_ID0351_for_PyTorch/LICENSE +++ b/PyTorch/dev/cv/image_classification/NeuMF_ID0351_for_PyTorch/LICENSE @@ -1,29 +1,29 @@ -BSD 3-Clause License - -Copyright (c) 2017, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +BSD 3-Clause License + +Copyright (c) 2017, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/PyTorch/dev/cv/image_classification/NeuMF_ID0351_for_PyTorch/src/prefetcher.py b/PyTorch/dev/cv/image_classification/NeuMF_ID0351_for_PyTorch/src/prefetcher.py index 5e05ead500..c0c8310c60 100644 --- a/PyTorch/dev/cv/image_classification/NeuMF_ID0351_for_PyTorch/src/prefetcher.py +++ b/PyTorch/dev/cv/image_classification/NeuMF_ID0351_for_PyTorch/src/prefetcher.py @@ -1,67 +1,67 @@ -# Copyright (c) 2020 Huawei Technologies Co., Ltd -# Copyright (c) 2019, Facebook CORPORATION. -# All rights reserved. -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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 torch - - -class Prefetcher(object): - """Prefetcher using on npu device. - - Origin Code URL: - https://github.com/implus/PytorchInsight/blob/master/classification/imagenet_fast.py#L280 - - Args: - loder (torch.utils.data.DataLoader or DataLoader like iterator): - Using to generate inputs after preprocessing. - stream (torch.npu.Stream): Default None. - Because of the limitation of NPU's memory mechanism, - if prefetcher is initialized repeatedly during training, - a defined stream should be introduced to prevent memory leakage; - if prefetcher is initialized only once during training, - a defined stream is not necessary. - - Returns: - float: tensors of shape (k, 5) and (k, 1). Labels are 0-based. - """ - - def __init__(self, loader, stream=None): - self.loader = iter(loader) - self.stream = stream if stream is not None else torch.npu.Stream() - self.preload() - - def preload(self): - try: - self.user, self.item, self.rating = next(self.loader) - assert isinstance(self.user, torch.IntTensor) - self.rating = self.rating.float() - except StopIteration: - self.user = None - self.item = None - return - - with torch.npu.stream(self.stream): - self.user = self.user.npu(non_blocking=True) - self.item = self.item.npu(non_blocking=True) - self.rating = self.rating.npu(non_blocking=True) - - def next(self): - torch.npu.current_stream().wait_stream(self.stream) - user = self.user - item = self.item - rating = self.rating - if user is not None: - self.preload() - return user, item, rating +# Copyright (c) 2020 Huawei Technologies Co., Ltd +# Copyright (c) 2019, Facebook CORPORATION. +# All rights reserved. +# +# Licensed under the BSD 3-Clause License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/BSD-3-Clause +# +# 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 torch + + +class Prefetcher(object): + """Prefetcher using on npu device. + + Origin Code URL: + https://github.com/implus/PytorchInsight/blob/master/classification/imagenet_fast.py#L280 + + Args: + loder (torch.utils.data.DataLoader or DataLoader like iterator): + Using to generate inputs after preprocessing. + stream (torch.npu.Stream): Default None. + Because of the limitation of NPU's memory mechanism, + if prefetcher is initialized repeatedly during training, + a defined stream should be introduced to prevent memory leakage; + if prefetcher is initialized only once during training, + a defined stream is not necessary. + + Returns: + float: tensors of shape (k, 5) and (k, 1). Labels are 0-based. + """ + + def __init__(self, loader, stream=None): + self.loader = iter(loader) + self.stream = stream if stream is not None else torch.npu.Stream() + self.preload() + + def preload(self): + try: + self.user, self.item, self.rating = next(self.loader) + assert isinstance(self.user, torch.IntTensor) + self.rating = self.rating.float() + except StopIteration: + self.user = None + self.item = None + return + + with torch.npu.stream(self.stream): + self.user = self.user.npu(non_blocking=True) + self.item = self.item.npu(non_blocking=True) + self.rating = self.rating.npu(non_blocking=True) + + def next(self): + torch.npu.current_stream().wait_stream(self.stream) + user = self.user + item = self.item + rating = self.rating + if user is not None: + self.preload() + return user, item, rating diff --git a/PyTorch/dev/cv/image_classification/RUC_ID2470_for_PyTorch/figure/additonal_result.PNG b/PyTorch/dev/cv/image_classification/RUC_ID2470_for_PyTorch/figure/additonal_result.PNG deleted file mode 100644 index f352f7933c8fa3583fe21006a0e3f747e5a3e66b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12423 zcmcJWWmFsQ*7hqDD=vlNgrLRUHArx$Efl9ff#Su26c1X07k4cbC|VqfyA&-nxV!5! z{LeY>hqKB0tMc~&{2V( z-i6?&z^}*7n)1?*%7!R5ffW=>DHW+lk1C>{-uUD|;1ui*~bw)`lBS6WRj;ffyjN8X8<#+hH?Psm?eyLqe9fO>3n# zIHbQ*oeipNhD-*3N0+2})u^UzrSHYAHS(N4`z179Uy|;*RaQ{^)AD&2saXWqd!iT6 zf8IP}MMQ7`?=WA3Ujmt)p))4Gwqwq#bGyf$KCZl_1#%*OOU`K ztg6ZdY~*ukF%3H&G+Vll%ka5kHgNmndN^G*EbayCU6^+srhGq;grDwxHgnKT?dwv* z+qH6{0`|VUTt`Om457a<$eG`Vnor`fPXmh)~1;;YO`_sU=3jYk)z~^!mnQWPk0sJMH zExHqv^O576U2P;b`gN+?f(LRn(FiBe(9_!esFzVhKWYu3#Ex;k=QM z8z^IY=dl`(oHFv=ExnDM7mpUd+BlfdQgi*Sd;E*U2%?`KBeI_A+;IIW&F5+px%YEF z>Rb%Jd|?0Cdi~W_iJ6ShB$kXv^fN<;5cM~<6~E-r!DG_T*(Qj&&i}X>%~Q41P3r3Z zszqx7c6NM&Gu5&b_NpuH>X(|tEw61IGWam*IqP@HY5SJjcHp)bh?T)dHAU*CKfU&w z1m<0*-XXKY*|*jbkFe&_*^SkJn|mj?nH$@_-*Uh3=8AE?qoSKiWa$bT+KWczP6Im` zm46ZK9sG%mIt=?fwpk9rIj^NA#;5zYe(mck(X(l@G`^gyqau<{eK%*uDI$2%ZtbEt z)pi>i^-gIrsi1h!&$*93Rr(GKo|@r9seNx8UwfZUcD&HH#gC-wR_owfgdNK=-T?=F zs<|0wx0-%aJ1R#WL}KVp%Pylm@7PUg5+nNp?xEE2+W*GLd62IoN@VXfGY%6YSx7_h z6Y@E?MemNves+;;OQUDl(+T92P@yf71~#S5<_8kEDGHweLcQWJ%urIICk` z83wL{g#G7EWs+NNNm&C6RmO7T-PLv)TLIcUwP{r!n(sjyT19ES&mJ7sarSA^``n5y z)Kyq4-&b8uWaqn#kzL7thn=8!L>wfDT}UVa`KbC`d{wD`pZ8wz;Iy76s`Y(1;6leQYNCe_%S|gQQY)G|_NZ=0XF)V< z?RRm6c#@(1H>7bA-NVsspHhEXKb?$2e2Xmz%l+=dLV9vUh1&!h7TIqkOn7Yy|9;T^ zJVao@-E05^S7l673uM%Yr#MRAcsb?Nj=|`XkYJ(@;`Tt(IZKoO&hWJCGmhN&RlC@? zA7hG0U`B4UzJwp~aXjCPzBU)~721b<9{l6bft_ZQkFhcX%(eMlm@416G?=Y=Lem78 zq0yVbkl!i2q}Ki}{$H2z>ya=t3J1vxV2lXc$op4Wh+sHCR1NWk(54L0h7x+f9SZd_ zI&=tuMy$tNzUCmi+`iw)4qOSWlF~{=B4({NnnbrgV3?2$i5?FKDo@85Hiz`g9rbfi z2NC#Nvx4BFG#rW+U;O=yH{d2C#jvMk@rC_BfS7!9#8|msga^fvV6R_6L_!E;nrzCO zK7H#cB7pkUS$Y`ScL!vb(2MX-_9S%k`14Zb2Pv3pf=oU}aJxD6WyY$B*V~NL$Cz{m zu5L2(3=N3VwEqUDl87m%a?)B-kVUCPg@turG@Ly|G7!612EExtlIabZ)O7_gfhm8FS7ba43Xe zId!u;)XYEMo(VZ#8;xLyWB{dSWsjx4) zL*>ebet*8{>MgAr5c#YYU1$xJ+!pWL zdnHC**efz$PyDfuf7TlqiiS9deUl%8`x3`OtXutOPsL2Sjd4=Ubq=LDc|x8)wNV?F z;F*fRAEK##qtgbtpZZ zZcU4DAj8C7SB<(a+G%W6M@8JSUJfg3Y3Y^1awI(UdwO16tRkycgB6We zWzk2-Eb1+>G@GsQ1+RU|AO!63YM-N33f?k7QD4cATb9vR8IL3?_8PXk3MehEe|VAg zEjLWPwfV-x{)S^TL~!XG7#<|D@>_}NKt`;KfXVgH9PnC(Hz;SbQ#*FziCJkqz9q(( z#1WA;y| z!k1y;@sOdoQBz zb@w>d}d`iBBWl=~!(0ZsV`6znUN;PduBia5|QVhToH9K=(Ukm$HRp* zm`Bf(pEG4ds4<%6dNC}14Fym3!n8s1mwl(lxwQU|@LTOsx_~gnpDoqJzwv`p8)sSo zmzIXr>bW*50kl>8!_zoD){-1Oag+1V$RE3)c7L`i4xi9aM^DPx5GINkx>de&4(eQs zA~t8$vgA)mW}|nsexC2>>=^C7-w<7ol{rUZ?LKjhGRtibfvq4(j`(FgQY22eh=E6s z^3{)-QC`}6=|(dkA!bx^L|^i>Dk>0v+_-|m!eG*&N2Ay8^YVw6!H~jgZDvPf+Ymei zXgCe#St?~#3c@JF3bZKdT)|yc3Cda0sAm>gwbKu!$&J$JK%t0ESH)TV%Kz0Mg#n+? zB9k#?))GT!VPYn?hbw>kvft*3L(g1+2R^m<-KkJ@FBI^@+#RW$d^p*mgR+ zT(Tb84FaT>|ZHPtZJ3Rtj5m1b95`*A``NNyuBh=TaZH{t;pMNB)~^s&uM3quUXF$qO_eJ6_qD)dm9nOK zUVmEPEOukDO!U89iDYoVT6^Y5nL8owyn>yNA^`}z2~_r*hzgl9m4dymUL`hWK=^rQSULZ*AsTM zCT8+%i~H6j&s#f9KwJZ>ZNW;B+{XP_v~=QdbmoldsNI=zOxKTI|4yJRdcPg-uih1} z&nvNnRxs{RBO??n?pT=01q~^ij^Hiy*DqK&wseW>BlG&ljz%huZi;@&trGjdhm8!?^DW}CqGJRK#O0=t>4}^SB;&nLry*wW>FG3ZCE?4m4z zjK!w8AkFv@mMZq!4jVxx zukl(@sNst}MslCfljcG^Z8OQ4yikicldMM*8%yOk zK55`}3mKL-E)cW<<$3mV@fSnm{BD=MnK| zoxUuZKP;5NHFA*x*AeqW6|ZeE4&Q0=r@(7^>C|k6*YCs+6(7%nqg?-fM(g7KHFSyc zynDi9CItEF2;QmXe#CcSFRT@6Mb)xSbyNM5 zkG4|7a9#XLV2f4!g^|c4z!o$vF=Upo3R~r=Jj~By^eEZ^U_eQZZ7dWdX;DB!dfc*_ zpl_NZ6U=iL-S$1IWm6RUi{miQu&7D2*jXr!G@%^VwD0}(q9a1!*)TT?OFY>{|94cl znu3FE1T)*l`GQyZ9G#geN|gJ!ia=ygUyUbPXXc15c(f{eN@hR6gLqvdnL^~g*#DT115Pp_AYc+28B`G(A<-nm7pve~(h31Ne4WN3=Id+tvhk}n3EMRtE^ z4XAw^wtM%9#nDLMgj)m4)1#n}HbWsMS1!~E%uRbB3)wIyw+4~v_37=wgR$oN&zUd# z2q>ObbnrRa`HAIue4Q0w_SVFr4j)ABS7V7t;*E12rBqs?C*R_Ip5|ZAtF0jKqjo4oEEEGZ4wxvBio)1`iT8RtaZoPk6;}>am9{23-kr6Zv z)z!b}6~yO?sD!56Yn3n?W%SDx#%$_|egHaiXUgyK7k_-Nci$PsW`r=|JPB-Bq3y7m zE|`Tz{Sq7fZ0!`ek|NI6$-S3693E#IxlCI&Rxs~`_jWoMWkY-HTwx6I8EKq*!`7yB zTKHEdXyp0X`o#&lqJu${nrtR_RzBlTt}PNfSps$I9^6$zkC|N2=@3y1uhm^`e=UWa zR2>>syfdA%so?npMdJ{iGs8+(&#$~soTg(3GZWofXzqK+$v8c?(TTTA$-G~+d7|W| zH_HfWQmJII{xCRBMj=DI~z zGK)V7&e$5FtCRb!H%XTkatfaPmd{%+_s3qx@Nu(0GpderX(%g56#xCLu`vXZEZhY` zpi-tj){ybcs5jde5Tup9!>lIfc@f$?ki=!CjnbWT=qK2>Zh{G87AIbOOMk*Z9u6KS z3(w`olHz3a&&t~b#gY0OUwo!b++b4V|m<{{s(6&4K}5I!;CnTi^w3AO*PY zH((=h5m-QVdjgQdz!dvtA={t3H6}sCy67pkl~6%IJ+=eFlHwue9<0Qw1p}x-Ak}3I ziY&~D+R8VJ7UO@AV#q*3Rnm&aI91WZ&Vx~TYS*C)#s?fGcyrLv0T9H+H{6KYMIVuL zI*AukCw~KQgNG&VMQ;FHn)Yq3t@!~*Hr7%^UG7v32aBCe)7jR{yhn!8MTMScbhyT< z>DyMwPJbx*)^1n(=LI053WjETO>{}108X_Q+^bt|XDKNq*xhNq-h1A1f9GYnYsD1) zK(cm#H6(EI9oF5!@|HU?yOqoUoUpSuES6^ZPiz6ANsY5zTBVujh-*NyT z9hVwX>|>n$y5*?v{p>#jbE3sPf2QVsENa+rg#lF3ikn> zxZj>mi73fQ-{z)k8Wq(}7;QNc+YWmi?uJl)dhHHG@pgb({(hs6>YH-qzAG|wH=%5Q z#g5=yD=BXl9sp>uNlqkxSnwb>3nj4&zy&b?QLSIMf>3Ih(=vHev*5WM#L;rY&0Zi4 zoafB(^5f6l7q9R@fhT}C4tZeGtc?fl$Vok;$hq(bjWobFWq<^DCqT6Z0bWb_Felx2 z0&v9zsZzG*z0d#TbVzkh=uA_TZ4U4ZV?A(HQ3h;lOdM?du2T>JGTmzrLy4ow@V^9eX>PEx6WGtiT)ICz=VlOmlpdV`wuP+?*F(gQbvg$^>9AG2D8Mi7nJ(5 zs08-{pS>V{c~enFe_`+IHcJ!`q^+cIns^qv$XS30&k{ph?@1jEi#B?{r?v>$%4;(a zL#=;FzScPh-4?i=6$e*!VEgn*mjkU81Qp=OLlUT@vb=;~^2Z98SduoRg(A zw*?F(){0K_#jnyt8vv8qF_iF0=<)1zBVfxB*Q;jK8G+`<{weWELFSZ$9vEbVm30*`m(;PdVrNm`O+56kZ(HuKTez-KKn)(296?shm{Zvo;)#+4DcfIgb> zz_f;(O(j4)I>fn(;CHaYUyee{n^^tTSztt+oTn7luco8ES7~{^?RfZevG&oTM+!vB zkh(FOd<4(?Xm!P7ThPl~_#Dtda3M@*gv30Uf!Oe`hClG3+Ei=DJKsBS=xQt!!ntff z+++*ch~u9SC>UvruDASpYwd@&1_3n8HqKMmw);#lKAgS5YNE;ih;QFQ1sniEEC3Cp z*FFRAoZ2+$8IUf%0!yr6l)+F!BV+V*NFjlLq8y_{2$vQ{6WNL z3aHfu9pClB3%iJ?aY$6V=GUUY;izqg$3Y9lJ`h6pOSw7}7a@q?AWq}p=-Ckl1d3=H zgabM^woNmUs;j)lsKH#E-ZfH@JfJ{?h9*e_+8zAy3sltd7jN^;vMsY01zW#+l3xMs zsx|z0018kxwlo&FdC-wH;FFlv1mXPtVRg&s}DT_td73IRUx_fk1X|WI}9AZrqLC zYi*rnFrmtVF?OUZl*+$4+)CVE4m<2Oop-qa6}v2LHPF?BtX~2-foQi{5p1pSI4kHc zcm5)$T5MqiEYvn`vB+pr%RHAqja@ct%hqtcG;Cq&Gii=Y$+8|C3^Iju&0fiXS|Qy| z_aB0zn^os^m$d~*3L*M2asHXeCOLZA+=9L&SW2|X_H-(FC=EW;^o{r@l~ui`CE8m- zn@RP@ZCuQiG1=D)kXxYX(s|Cbsw$-sU7-xN@5_XP8G3k7q?!@y^{w%K3g|zwUY6K*kqX_H_<#dP+CA-ZTl1Ded}>I8XTeOlb2ciGIl}`4>-f-#ZibyO6xtV z8RZFc5(P-xdf+(x(bJzjt$|Lo<=#klgO3Ly+pyX{vuH<^4<^@}co8Bpa_Vrp2&XPjs~gGhpzn0V8infU>18J)h$J zM|+{KqHj;%1{;i!@ep&$hX{0;bu(X(P$jRAdccCxag>501LJP6d@LVS3`b3#mY>nm zI|cOYn_p2o{S<`+WKb)S35Fjn3-pY>JL%F?)p_z%kqe=yp zd1{YLZm@hgVR2`s+KzK!;B1*j+?-;!FHvngj(VfCVhO`XFhqS5=l_8<$VB`JlGYNQ6ZrSK&p&V_v~{CtkjDEZLo& zS4n0&P3H?H{cN=n*-`wTcMrFP#qIE9)_fWUB?0(gTpCIc%v;z4(+Uj^7oa?D@nkwN zM<3-zkyt0$gKPC)jlmDymcnwbe{f`2AiTYng zi^d&(``9Cg<{|Kpn%qJa^ix2{Pfz`=F*e4md9`YE|yZM$U z?Gh;Pm(G1${^%KctQOX`I{7xLN;K8>-WZ@SN(%$s{h#Y}yVX;MhuD?=Qy0f7Aj8R) z4jhrr{iMj%-O8#;g(Z;>)>L`$VUoCok^X|`7o9y+UOV{gK$(rd7|znRPIXZ_^Z-u) zwUTmyf$F=|dh&cHen0h4s6ew__prWk=IbyWlKQ)=_;6c@-7wIhO}F37UpPpsy_qig zR`b>!8AKwiuj34~^1IbC4*Q#qy@|lZ z4Y<1XY}$a~iqPc_H|K=6ABy(mi7lVieG!GYIqU`;8%)CA8*qQ>a+QREn~S>LzFrIwE!M@-6~Hd?iJx#kTUYQo zR1v@9cT9kB#_eCnEFJ)&;+ON1%dH2&IPOIu8@12iZ2$p?>ifGbxhpnl82Vf;^>6mi z60Lj3X61l&f=>7YJ>F~BsKh;g_TMYP-=^Vg{L+4GKSreK#JiNzmdQ>=4YyuNN8=uz z5h#|fe~vquJ=}IF9&i{xNAi2?e8mkNGfRqhKb_S3Nj)j+S7@RPw5XL>UilL9=C7xF zeO$izD-)UWvBCNRkfg#&a{g7*4~1Mg=j{du&X;KAqsM>vAA(mj+47EaMTa~;&}&BS zk&HbqfVbw2DzwBIhCrqPc_So^XY!QdK2l&|gO%(3Rvq9qk#ogTfStV1ka~9qsMDOJ z*2KfMx3u?-eJmvtVU#s<9_wlH5K{#hq=6)qq7&y79Ma$kNV}*oxgxXBI%)Gma;ZRj z(9x?p_Rb-?Xwk7Zny8Dd^5t_E);tui!I4iPV`Mg^_|MSKzXO#`G+9{I5@GPiFpxI- zSBA^BGsZL*&1t~OVpdqs3kyb<#6m*G7BW4PLa02gO0338S^g;mnarK=!UL}^Lm8OV zn6-ifQ`WFogDBUV)*mcVkm#wTB9v5&SG-e<8T!(Ba-8bS0<%^*?$jPuwO~YXR6pO?arRV5q0mNV zz!J=_p?tFcjl;*WC(l{&_Qje=JQ1Zi6{@tAQh{{D=qiBh(!}7y*;FTAg;(it{AAwx zgP4kYwHje1Cwfj+#`&JRb#1}-{&uMRUh0IDItQ6M@d*m>fDb3tE}0iCU~Lr2=$Ab2 zArg>xrVEBT+9Cy0>iWb6=YZWwD0?|8OX|{?;Ql-euZXb7%W|vxp_&De*#;+CGa~RX z8w9f2XdtoXxXj)jxRio5AKSDj-xYn;${b6z@)KBK=9+k zMCWgfM}5dnLbZq{CYEWy6h-C5BKQTUv|pVmgib3kLBWoHz8-ftPDo0#BRnbf#Io~a z_)@V{zbwb-1t!!7YnM9uB&;HBqlP_Z<%Ce7VCzC`5qzhbaMntNMm^go7`^nrybCM= zcHaP>gQIUCPb4Z~`>w;F%j1@wMmh*~8Y^u}=q?Ms_a43Bm^GT>z+ng4d8OA4&RqfT zgl-TDCH~Ei@vxRT>w>hUOZ-owyi)50Q>RtwX8~5E*PB$D5+8vFATlqPXCf44h=*bF zh75o76Xs6>I8tDg&=?)l@(T{%C^~_oMu2=k^mj!%7K+3IQFjD3@1psF$NKIN5-Lkz zwM2)#Md>z=pXivX4L%kA2$X~!VqA-UqJIrWl)ySc4JD-Dm_WAN4zsNpgwepDI?7R2 z2vt~%p%weL-()V|HY&Fv$Ko^pvvB}BE<5Gw3 zE1h@XE<9LwzV-dBEz)z*{hGaT355E&H%Af&87_iC5>p)kQkP89lq+bb@t#WS@kn8w zd1bGdPR}e0YqRp(>IlrwBUxyY4M4ofZYw|1_ZN?zE(Imvz@C` zDhGHXaiFug%3S3gfr#y>(V3q3^^_fj|Q@olMe<FJ@=)XVkJnzLVUUj@DcW<#oO=QNd;p%QDh(}v59aNXi{!`nB&g4st6mup>6klX@RNV8S|;X z)kWx#BozD@6v>1$CEF*f`NvTS1n)kxwjI~@{Np#mMFd?s)bo_xTrvN9W!-p6YNrLr z9c1e96zEY?_xzb;jqc>niSKso{`7s$F&_rB=}ZuEYEu2qT*F^@YLv_ydX;Fkrfc`I zz8qpzuew6VUyK!DwHnAkH1#X!jCK_eFPUO;4dsLv6~z3t!J{^&2r9xBAe>YZ#`Kxm#3}FU6esqGU8JqT@44^>(lkaPy zlpwVR)FYP(k$Y(`qyvJQ@>c7cT|IVfBBK9B06i)%H6z~|Ec>}fmH^mQr!U*rxmElc zvQ_hG{0G(b;J{Vpje<1j5#Uci^DOwN?jKb^0wtx5cPIrxud7(oT>1mW46D`9Uld5L zjvCM>;7k4Gp-rs<$4$#QhvV_ub_kxnPqF*$O+p}T3zWPiuq7yA{W#|AcAaNY3WHNs z=?OYV90gG%Pm}||hqr~P69#u0h29RyB3(PR_vSsh&_PAK6AV293?=#d;m{D~I3rxq z1IhWduQp}y7P$IRbG(a0YlT)iPy{Jk!nw4fg{|{8qHIYPlf_x-GD`GbEAYk~XrVJM zydJg(9beGhu%~qb`Lj~<5j0L^LY-VZD(fT6fXqTqY)VwKECl{%;8`A(^WudZN?KVw zK6>`vKY{>4&_^B9YPPM-8TfRu7kPLOxLKLcFkcVFz6eD@c`EI1ag$fEPN}FoX7+Nf z3cDQ=i|P?bu959VdUy+hV6-dF<-#oh5%#XsK^uq4#A4~&Z|78?qs5`iN~Z8mq#t8j z6RstQLs$>j4Q*J)#3=GuOJ;1|%j_Ga!Q_kfvst&W3Jg&LSdqr{M&k-$lR_|Qawfd$ zLqAO@IF)C#`UHQ2h=S>p+)JLu-W$F^t+%Qth~8_L4bY$HbpD~2Qa%qFq?Rk6nue5g zp^q-tpKD}x5(3?eMj&@f z{1y;qn9xU|onox$SkDT@bBu(9yNlG$lI^A7qoxP0Eo_x7V&Qs6gH=#N(SlR8xlZ(> z{f|uaP?ED1z@F6F5vNl|5+7epC!V@;xReGs=Oc|qx9eC7YNtv}EX3vaEtF*=RC!DKoC56x)(eBc{+`7;{zjgoV_0-e0!#%bk0= zV-)9{J|ae{x6`|~NCu6$zkrHxJlO}xnXzN=|Cm}~p&1tg=X@}kpO|hy5Dbgl^$CVg zN9as(Fw8cva*{p&?ZcK~M43XoF4{&n2fS7|EH}lOl)_ni1 zDuUmFlPdu2@t=l=$wI<|Z9Pe<`@dZ5p8(BQ;cnC=ZchJN zw)B?teU>exWeFC){re-QuQ=9??yCR4obdmP7oR5#?~d9|aWKK+Hs(3-&jXL3vZ|0W IX=DHY0fx6Vm;e9( diff --git a/PyTorch/dev/cv/image_classification/RUC_ID2470_for_PyTorch/figure/model_arch.PNG b/PyTorch/dev/cv/image_classification/RUC_ID2470_for_PyTorch/figure/model_arch.PNG deleted file mode 100644 index 126039f2766b81d68a69277d02c4b37308d045bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75383 zcmdSBXH-*d&^8)SL`9kkNH3xY2na}#&=gcaiqfS^ZvkmRI*I~HRisOA(xoJ!Bhq^h zB^0GY2uMkg5;!~f6ki|T^PPX+I(sdbunBwLGjq)~<-Uj44^{7zpJg};0)faC739@H zpws>!5YhhWQ^1`%N2oaPACZgt{X3wd9;RjBo0C?zRc?boB@tu?Pe_38&pcIl>;eK& zG!p(1wK{$@2Z4^V6y%wFaP5`swQ=j5``7U?kF3p?9tGUyxCyx=yMlmR zn#*pjc&o?zJd)>=|H8qF>xf1YcBs9eAg?RWJ5M?#SWUq&I$kSUD;jIQAl6$6to46h zY}Nz`|L1j*f{5yW-U0c4W(N`fc8^N@r0j3EK*T|y)4$!5{YnKQ`t9CnCStbVZh@Z5 zflmH*kL~II#l<~5ja!=xxm5GZnrdGhOSjF0mX|R7_=`TaiI3&!b18^g3Qi-y=dY`e z>{tTX-V)XH%Yi(9-~y( z_Q31qq<^pAt18JgA*7Wy0mjGIk|@%Nrz!Fkj_ug=QmqUVxuCl(dtG^de*!ewBB7c^ ze32RLl7GkR*v$UPX5?#{{v2jLmRf&*%-_L`IY*u7O*pnv>;JSQ;0>*N6M20s$Jk0; z)C~aBq_*j%Jf`{kX{jjP)?7{hbTc0ZEo;iZ_1=(l_Mv$}Z^1vhKh_eDY=4O~g6IDv zBu(m)Zi+t5c)(xgwR@UFe32e4od1uBT^Z5h(PtmJ7W5XL{XghkiR79Da#8#Ly4pm@ z>f&TL{WjK*Y7h3Wdz;+T&g*<7U~aK+w1Mn5ZaX2|IlS-HH9WW(1_ZY_1*?CTR!j6bs4cnR-S)( zZ^;;NvY%^CXEMVpYxgL(pCH$YCSUiK_4T#9TN?WOcgR>05k=NqQwMQ&Q=I+dgE$Be zB4|u!BO`t~inaTIy^JdOH>a?roudPBcOIk}x^?1r{G1dPMraS>3%cqDba@;{)XY7h zM%sET^v2Q6gJm08JL7uU+Ffz6WAR6PGGlI5=J6|(^IU@hZL8ku@2baoUP~{|I)5zU z2;z6Yrz&7ns5;13FWKM8~^FQh&X7lLZ2eqxtlplOr+ZgmLW=g16H&n9v zkFd8#PO$0tatU`6pQ&bviq~WhMk=i{dqPS!3)DYVaaj4T1u5FEdz&cr6nJYV2`U}* zC_3}fV!bv$Z&xoT+nwhX-t>nZfRB`*_-Iz!U!u!jcFnuKc(?cjTkQO{8q_nQxb>wU zfAMg*G5YQ^u39pD-XMOi+}tTQZ^ZepGlH=w>*7?JfgT`J=<@{ zdAT;b;mu~XP|~HI8xvTWc~`m9O;fja9fPvxN&??-#L&M#bCZ}24dz%L9E*}De1J7bo;S6tLR-A^Unen1 z{RBA4<48x4d89r>jLd%yWr^}Mp3V2v9lld~Yr*z6K1?7%vcdTnJvFY9$huPb>d_ij zWYkI(v2wOKK|)l8@Yxe=yNEI5Y^RHm zu<&JJ0j9j7#LSh;$c?AOY}K@Q~T@3QcojQ8Dz!f zp|~OV`EjRSk%e1Be8T*o^JQJbGHqQE2h1@w9rWk_Nh$mrz5p@Ek^sjOgSIFNe^*#H z)Hc+tsNA2M^WPvMLRQ5BQna-z-2=xTrpY|r$ulYMb1%8K8_Klle)^yRQ91F0XpaE< zhl6VZT?JX689OhwoRl>+K4P_S+N*yyc;TN{g4&3IXaE?M(!bpHQz1Mm?|M%8peTx4 zFkjnhd-Qkmf7~|-3Z5LW2v}ebhJC#|iPsjPWVNdV&vWGn=&U=sS1OKzxi&h>2Uq_! zHb|oNSSsIE-RMk^LOo(!^{l^ZZa0*t;PZnrvv144hqdk(2LsExRT_HldOl=hD0BO6Wd zYqFa1p#S(P73gvG$i&+vdnqc=f0C2j$9;H^LRrYjUe++&X99i+0-ycD>fTW#XT`Iw z2mLQ0xu0Oel>5J?=tD7orpqEx9&q_3T13(T$&3iuCb%Wf-0g#ir{vA|vjxa4<+Js! z=u2p=#~(bpDEuUG2?b4DF5_Q*%Rm6|FoJBj;*IKs&7`Jl-Yr9C>N@o3o9iPDWp=0S zvd&mpF4jJmBBJ_F%8)=ZN$G!1DIdeZVphvjpLqC4uI)e5D#5FW+&(Wo42p*%srPA7OGb-951Qj*sA~Wx?gz1YcnHW=H|KN z?iI$LbktSdfXjPNr`EZx#?Z(LZI0~N-jWeZX*?06+L4~GcYfahpTtkh1|+L6=sBvt zHN*5%GXzoz7_hCr)~YKL6+L)Vwh{NesMXw3&?C&^IRL@Jb<1LMqJQ&7fG1_^eKN90 zqlnqK!yt4QbZiB}pdZbdt4r@QF!DwoLo*L%<{$jm_3aYJF_x-WLAl}p-Gw|2b<^so z-+v|fwLaVMNJF)njLD@1fDqEXY$OnL%#uKc|5dg7#o8&^IxfnCImfUS`at(Xg>1jr z$YdkKx56@hsm)XhZ;V2JW;*m+SFI^iaBfldyg=~4 zKZyzaOWDedeicnT=;YHJK~EfDKdbUFoRl>N#-SRh0X(PjqYhOK8{CQ%a}*H(7U?&9vSD zmLZ1^Ln9(e^f2~%??4LFKNE)Inxr{f5p;5o1@JvR@TtFzbSa#jkcXC~?h{4cwt-D{ zg4*&7r0}|l-!5?xMRMHvw{!|22R_jXR5i$OB96bVK(k<=$QZi5SQ%pO!Ve zjDk>0{Kun9p0t|x{n1{qA5TBH0Y5_IVJBB%?6SYg3BDQ-4y5;m%qRW=l>E6?DnjPn z95h=1{OG^Fp=UoTNDmY}1-6(=Y=7y-R6H;k$h`TanXH%z^^mQPm>1;qe~Lf5R?y#^ z)hH-WNDnsHK|+K&>p#%>SycX4{WEePf|UOi56t zp^Y5?FD|E>m|CvX$JwZ3p{6Io;>o6inUR$OP_!92sv7A<#&1y5=Si+XW?fFo5`v10 zkS3v>!*1&%5MuHd!2idyXznYOn)m3#Bn6^SL8~4k=eR-Yg0UlsFy7J|TNR<_Ad>t< zRDi2B9h{>_n@gA~=uNk$Um`wE!c4xFoN^A1dj))Szvg{*D_T{z5X^~cp-{}-es|q~ zhjGhP!i_oB+}Xam);A?3DocoKjY`n=jcik&biASBsAzFlhi)TO%GQJ^(!j{Eg+JQ7 z$;*J4ji7|xGh-%&`c094MY$W_bx+)qUu|m1e;-wAc(28n?esui?9{vVx2P~Iz0-c? zbs(}gNobtpaHy1Pu{<*A%8#+IfKKa?o%b?=DWKw{J!*eyq?*S(0Omj~_g8lD`Lh}M z994i4m8T%Zt-*3;Wu;$UgXIf^RoFPV4W244v>@(g*UG^m z)qI->20aj`|HuQ-NrKt)?}+N6X$8&yN*8{@K_5|b^YT8N+=DAv&vi+fyY}dHrFW>O zs?z1dGYZq}W74+-EL11hO_QK(Gw}N@^KVfch(awYp#_27&N*Bg{17fk@5jjy`LGb8 zyajo*i+>lY$Jf}R)|pjhp;hau*TU%Qez5F?^-M}>8<^OLgId!B-81*D;_U6^(}Is2 z*5F(alb5ry?4}MFV`3NPb_dw$?R1S%7WU2(3mZw@Q((w_TtVmviL6`Ym3Tw8(bs_L zpPc=J>h1eCz0?_CJbvfe;U#iYud}dGPX=c%LlyBAQBN=RpY^wo^(kBD`tVs!Uek=2 zdbV}$RSB2_G07K2#wyljY!vq%^L96|MM+3Qhg}XL07|c?T#sE7_GPT&opqt(7|f+J zcQ~k?a-~5?@w>S3HG5(`d5scc2S%Ze%o*KMVKUaPHX{{ z<$;%ukpy=Hm-bd3%lgJlWnoB+rg7Q(sONm>k@2q0bNKDRmP_e-k1KB< zL@%O~epEvY7K)d;UblvB%P zb>ntP(0RtxOI2!0>&B()cGmcr)dn;l;5ks4)KbG1rLDKqm&qw&Y91!#Y2903^dpT` z5>gj4#ESeFETq?AzZ(E8V}w}p^R($!>VEN~0CRQgx? zaf-!`EhyLqTO6)!rfOs{^QKEJoPjImT@3+s9oJ5po|Fx&yNs%vP5GR^g18gX9drhII_3LKZH)xN;PEM>m0GN;ktq?JNsOh>u_dU zH8h@&OkKA+PipO?L1_F*S-qip&#AEuyPcSzVCJ}s!9R3qudatru#j&zPcBXuSyF*= ztr0Ia!t4ND52IBU34yK9;j!6xH;)GybW3=gnh&I#wD&up z%*WB|&Y!$MDeQte8X{LTHt23L@%nSxTPN;eRc#wZ{Ns2g)YJ__(fLLF)BZzA_92yD zJm;L^AM56-ZoR(VjW_Iof)2INwiBLeUIQWvC#Ms9UmtmJ$D>Ej9+~6EsY`^T5NF7r zpQO8LXKgoAx1MBgmhg&L{p3-?DFVMl4MC=yxK$!h(Qj>u>Vo-B$};f8YTlH)k_$6( z84xPdy-%Q$TADw>T@}r#F`(6gVZ6X`iLZShIovwGV*xcblT9nTU}EbHGPj;nyv00H z+Em2=UdznV;>-BPgLXJ2YpQgRs3jFTZ+S>qUZVYlgY^PbcI)I+zv$Jw*VwXYx~dcl zjX%_S)>0dS<0?J}Io>CVq#f_bM0$2B64i=M+Yw?h@t=aDa*kHjVGOFpVl6?+2c^gU zB5gl&+gJJP9oUzX%t0Ea#B8s7nXqQ4kBumG?G zm$i$grER|Qwep+(VORuVlo)HtBqND?A}69HTcA@cmdl}4YN>nK4bH3>Ua%9!rb7OziQzs%sBITM~p}e30qg!6Q%8?hP6*8DXioX2FtxtMc_M;U> z_{GUukb>2f!>wnS;L-T*y6P}gC91`09#(})fBr%hE@*Ry2nlVX*GT)=V^lK*@UIM$ zF~$rPryQfC?&+)AljLx~+${|{F9y-m_gNqJDF*0?I^^;n0=!_7B`9;2hp`TmtWcV# z=ITjPP6M)mcgeJ^jxtY47Ou$L+aYG#;36NqE*3Eo9-K6`T5V?!M)(-tTjAlk8}OKb z9mmej^;q+pxe%o?+lRH!YAs3fsObf|+u!MwH0?2Cu7gbRIO^jDgT2=O2K0^FFQJel zdG)~yb|VYs2k^apKCuPGL0r?wS-Wxve0#M6iL8WFLu{+v{iYt}jY$y%h8q3C*8^h4 z6Eht(u!NbC47;lHWCe$Y6k@e-M3HeZw=Q3KER=2NQb^tdDTS;?zR!zRTnXSQtaFFd zj1VA9@<+y27nXfHF_Ynjl6gCn1T?8=ubh-!$+4NNi24vb8qQr;ZTB2h{NnBqCaUxy z*=gP9LD%7eDQ){%`wTpfM|}~S)h-RXf#aAFJG|-yA$B-;sakX4>uL0Ps-)iBW;u zkWKXahd@)m1}eX*jIKtLj=e*P?KT9od@@`_U8=^0oRXRu(~1zH^lvKnrDp&rVh?3{ife|LV$!!3>8RG6M(uI1tuAtMlR#uiq4eJ^r9*`YfCxd~M=hrJ+E%aT-MX+MHS7FN?4}{#Gb;b4gb$c906Y5!7 z{Xb!iOphyTrU;4)yVX8I#U|J}HqDi_gKg3=ulk5Q^X29FAItV!eI_~_C2E@4BEPI% z)SG%;Zl`Y{v`pOX>T?@Ndj{QY<0!+i%VDro70BcN z*QM~b7+}0Rp<`nEzIRTW-(BFkA9mrHHW_`jq~EM!ULJusr*SRIiQ42gmWeccdS^Zr zkmxu>LCk_OHF*@;CQ+&1dQC#=iVZYF&1r@ zRD0(9!jVyOii^eiFwNsQAMKV|RV9%RHTq&}E33!RDW=%syOo7=f#5-Zxv2sV3Sx8K zWyZl;zQu~xcKAlegPi$KyA$}1D?}u+LVg5pL%NTQhc};G4`nk1a-4Flw7l^r)b$+? zBa9s1d~fb+i*oi{zF_9z-Z}TB72BC_U2kO7g{!LJ%wc5}{1OvZwK(`Gbi$XFP|=0( z{(;^~+&Ui!m-aeV4wP!|`dS$@N8Ze~R~#IIo?z=%ow#BnwG&Cq_PGA1|JXrV3zkE9 zF3^;nAy`=Pz)(S0t=OnI?|JJxIwdB(V&|LH)c$2WSDLj7cmR6aiZa9US>AjohOg=3 zFSx0^Zje~)s?frqm$6)PMd0HyYPA;a`oBB4eedRgqDRfJ^HvW5^sWPEKEB~IXs`K( z5fa+fp0oX~YA*vy=i-UAWX+SY85v?9gF9YbrM+QixjRnabKu(gQw$z`K7S=1ylR;A z;iC~b-d)HlCJABi_EmhV1*gj0*AO#j@r}F%Z44(U-8LjaeU@f48`0S|%VkDPl|~{v zQ~;#K$Cqi{p9(kOhXHK8v6*wRdG1_4T91sBvS#^C%6P-d54T!2^E-Wg`GY{WbBL%G z_gqp~91ARkZVK@as*F4cCZe(;o81m;YQd2wK_){YHbHyAS z6xn}(E&%D{tEu7QA2Jrg8^wcT=4av;EsnnH%m*?$=(-Gkmvdh2A~DnJ>e{?@tIq3z zd6EoIF~3ns4p6hKzWC!yRs{sw;%B2u{hkFWf7orSsCVnMx@z9J@F@Nn?)~)`jLj(x zDUX8}OjGr84oT1SI~H#8>G|qkg-`HgT6Rt(?u(+~&}jF%p3~{tItEt8{l)Tku4ERbfFVOy8Do@}>Ku zjQF%b>TGk@t*e#a0{Mg_oD6ylt}_n8zBLOwAAI+vpUUJ~zBk_A|7>TSA2 zC&?{gSoL1AG`FJ_&BARaU6@dl#&D#8&yvZ}w*gOG+4>BP;i!XtoAI-CTJT~=naAWk zFx|;75MEJC%q(4k&(7s<^(tWV84L%!_;o?Zip1p28slsp^!CaOcl@}_^+a2=SIDZg zZ&50`ilZK=gM9uBQZR0Xd(3aP<#plpTBjrKN?R$*ZtEYHeICjdGeso3qHcN`@Lw7f z(UseUV(NhD~F5g@JJ^vlyo#Ep`QrBtEm#xlx{014q#GLk3mjC3G^C z*ceeIu#rrNW_ZfRiwjkC`A?c)%X(xwu3m<8o9+N>g3tdEF3hM#kOHPjXFSRm#&Z!H z5hVdiH}clP(JjlHA&7w!8|Jn_a7#t60X0;m@+BHlJ@Nh@%O1C2M@U+h3)FUd7^9os zH?Vi?FeOMmKc+mm#lXC^*W1OY*heVs37&nmBt%ZGa0uk?WBz2%k0#Gc$To3J;n>tP zZM}Gj;mjn}a;46zV>SD_TR5=P;}Mz=92oFY=09ag@=Z_ivf&YjxtV0729d(8EPD0h z9)Bw74{*Rb1Hq|tgx$I=Gns*PV(4y$^Nn0` zFV`E(6Co}8?G2prUGj8i6&R-~c<2O>DXA;hKm(hzL68Se65q^+(9NrF!^4T$3T31@ za4kLc`7h58jBmLypIL;&KTD)Fyc_F-J2_@$mBRer*b)1ho8s!^cf7#dkcioogc(K6 zv*TAky^(vc-)j-%W^su$ib{~oj%#;7GxHNrkd!_;tiwk+rp4VJ%>tlaNUlt}E;b|k z7+|+vmOS`@?sU)OClAeJNm$&PJRV?4$?+;h-tVERH*Ky&-MvvX`0zzyeMs6%n48oU zjSCs2V})pmK?g*+50Xqs1a??=1)lwuVg6)y;;?P12P1HL1f{t$CC4rha2lQK9|c@9pb&xYL4i zM==lYsHqBR7rYXa5KkMo0dYE~mjYY9!2wS^oU~cqI7FfCk^FOSuGj5Zn;{uEvuv$j>;ZHW!B#n}X zD;ujxia++Fp zx6CIQb#Qk|oJ^%@=~{*b{oLRsbc+nGW=qBm+25%8F_R~i!bKW2{)rKMHMY33q{9w^ zq)Z4<491&8s0rO`1Tla3+Q|=kXRP%mImNu7q9pn3dC>A#sr&ZL`VN(M4-a~e43eMC zoZ0;jNM`fK%(eO;v&Khok2!b3eI-p{o-JQb&NboKL$RoYO|THm?DBUjhpkf_pm*iT zV)lzWS0sAL#q4A7Is6HOg~0x(e)O?#{7=zpmvd6G7>o^`L14@7$sh$rs97TOY-NX| zQ=?bHpdIDUU2?+yL8Wr&m|&&ZQLMAsHoRJA{>PEvg7H>_^FhvAn+tO$>WmAOX3o1+ zOh*<`yusru)cN8G+LS?t=r(^$z@%8>@%a+x+b22-3<>DJg&%e5-_@#eYV09kg z3^x~)U?soCK7L;GEnv}-@UXCUL-)xmTx!WT*9G3xO1J9*hhOgXHkMxFq7S(MYTwD^ zPtRfnIR!qVZW246t{#*l+G6I`P;H5+p1~Y}6kM5Gf)-bN7uD+nmvA+^j^~M}>>uOC zE|{m(0+c|iN+?m`7G0v%QvwzfK?Kd+>yN%7erqsN|_ zZj4IlEQ=;O+C#5C&B@$jxavDzan9#MuHS)uE#!rW<4_T+@}BxVUbOp{stAG-Y(Y&) zCg<2snFQPBaO22(+jr#^@q)jJDs`tp8GVn#9(Ef)sLcc zY4+<#y6W48zK5ZE`9!}*erJp`kNR#NQ10KLZIM#zFcyy~vx3zZmG*{99cShc`m%0Z z7|ICDh(N(l%8uVaK;W1e8L`}%_rK#69H%+v%Ymtu zDC3r%!}!rFCcEX-0oM7hknY&}-JF!p_)g5)drg+v;rCbc){9n6YCNTOO?<>CuVNlY z=fbe`E~&2x(%w74*7N-Zo1u8SE>Ql@y)^V9dM8fi`mW>#QDhss`v5R_VZBtia2%Tg z#=LeX3QZUHLCnix}hB=|gxc2cnc-eoTk`5nW21(dx;9Oj2?_K2$aXxl+nc;z& zl=k?}79T0exJ)h+r7U%-x*szkrJp`g)v)?BJwH-aIqNSTaQelZ&pW{k-Wo84zqvCB z9P&g}DDSbsw@D`uXJVd!jT=hDE)k+qys|TpU=&71!im?u;?o<&(wSg1?BU927Qd~F z+*Y;o#D4$QxUjvl?z;naVX2)=FhY3j6^lgV?L0;)4FjLWnyVDw8%cBXV+dh9S*bfl z>u7Yuq6ODa4647JIC%ul>zJE3ZCuX$rqf>kEgo7~Y4ogEnIK3klMmBj5a<)k4oIO3 zeyjb1k=HLfaTcZnw^KH;fyrO&bk5#gaIBeGdJz8%(e8YCtC&&vNAbsb(;S`?-^Xur zs60|@eIHO;y*au*8i3tgmx*N-Y`4R#d+|6&56$SObRK3lcy@i3gv%@@Yk3H5GVs?i zA`VunLaw`X8@MaatYR8CrJNR1B5&JggZoE$kANsS;cXNnQR~}N*z336z0YZO6V!jG z)tYolR&-$$~Y6Je|w;ywZHN0(WEt ztn@q_V4w8_c+}-l?y%Cryp;78e9m0nEyG$V;}I!x)J1(iMvY*$)BCIOt7VJu`XY+2 z(qP*AKS_N8j*U$bvoA&{qtYr`FvGSMU{r@F_#WgNHX^0-Nj{&Vg}(U4%%XEmR*WGw zM&^fdGJ&BdHR|mr17-A4Jy2j%N&4ta#%7ds%aDv{E^@BREs>cHv`Zl8k#p(`<&zY@ zMsa1yCA0TT+n#5|w$C3P(mAi_mCZYJ6}K=4EAo_iZZKEBpUSSs8}!g`-IVOjYm83f z+cLKt7*<*MESW7io7}NyU7?<1+O>%faI>TM3fSYD^HLxCE)oHxvy;$7$^F$bJ5n=! zk!7BR$WWG-Er;sU(=z~3$h22bpSI@mcDhTerqX`+t@vK@G%dZ)=CCWN7qTn+tfCim zhtn)aCn1(jP0N=uP>d(Sn#y{c`xfk3^M|RMAv~OX);=R2klVHc@EA~A;G_W^YqMsy zQZ;|UKI%~bn^Uw}6=qmtf4*hh{ZV&1k4BR=qT7wHF=5O;-lFo^N*eZ|9AKlN+8Ek9 z)NWg_Phsfgsv=!G%)R~Ck3|V@VSE)^J>U^IsS_&O0LaAyd~i%VBf~@!RuP9R)ogWB z+0S#6z12?X{BFEg4Y@Qu#tKxO8>(KNjlyAmt@mpC6uZ&eN=z zcEBU5NK~kUCNB(pm5(L(wRLQeNKuDi@?wG@Sg&W4_hrFzk1li=-=c26LEZ2P*UuDJ zmm4^8@;`oWyBrZWXew^|@xB^W;3}hIO$qd&u&UJeWr`Q@JeC{7t)GyF0$q5{*_=f? zh{eFG^EE4UDiG)$-hj=0%s2+9AfocP8~OWJc)B5n3=&lXwd95Caf1m)DrY&Ge8jL& zJ5Q}xtL}`eQZa|P$6HIHEdVL)7kFsedFF`J=5dJ^E)P2tg;ccuG>;Zy{nf`)rQ%l_ z->w^JYsHJ!a4cp+i%9CK>L3MLnLqMY<2<=0p@MQ~zny^~juk{~;Y)7M$|A8lk%>^{ zc&-^z#Yv>NT8cEp;Y5PRdhO0ab^RA@3R$st7mkeud=X)}-bA>3RW+ZMy!&+n}bOqiyFnC3L~gb8X{2E&~ntaC@O8 z7=>p=Qb^{$bS*A^^~e|R76A`pr&xIg}ul(csKj{o-x{Mfef zqXA)h3M7Il;Wpo#-RC!^OAr?G(|-Km(C^6-lDm~3-e`(F_C~vmIYP=lw7@$LAs;KO zw30(5k3!a4_)s6kvvB5#h37%Q5lzC#+ll5*f%@zE2!}${qj2!)sS*{^+7_Z{7_Y^Q zLovVDd_!iwqYt~7=iulSDn2u)WsOh?M&{ml-TMu&7UtRPoRzak)d3MW?xIx5R=zP_ zY07&`r4o-rjT|029%1SWedq@AqWN4s*zd$jCJurButs|{{G+dv-6?1dwn_9#uIhHNUmv&Z}$BW7B*)!c_&lT=1K~G17 znvl`k=GmR%SUjt*`cz$<3vV31;VzS%nwpR=LuE%DBbVOgbx164q4jAtfMB%h8-b8K zp(sVjQdQ1UFZoD>8L^`s?@Pa_d||-anSzXW9q2!HnyXUU6I;CLNSv6elwj7n;v-{Y zL#^zDT^%(ZfjS_cYsSM?=$xvQ?%JWT_vn-N z=)5GRtDrWC7Du@uI9Kj27ehb7enanJIYT*pOpuXb7k;PrC>)#5pgvvi=Xbcz1=wob zI|bOKFCL!O!6#t@*z~wLGfVD1dWEd?-YsPULkspsBnb7@Ra8Jzhq5Bg9aBAvG2rM( z;{|F=4FA0=VHLCnMybtW@VuaU%o~qday}Q1giiRl5B685@#(E}S!Brbl^+gRLz)zs zX`J&cB-&oU8;ia_RemK)gd`jiY;l2-4m zMl0%+=KJl&`f=|}xb%)6h3M^7hync*_DCi*V(3Q4qAr=!yZ%?Qo04aq-R@DwtQmbG z?eCjDrB5sMqr|eDXD~ZS$m54^Wl5Ekbw0zxPHlL9j*|1UBZ^9qvT0&S5SAI(Gt%(D zX&yd#X&KY2+!nJUp~C7JT8>l~wuy~tttzUk>&_6`Sj`>f^({m0)y)^4a&o(lEb`kD z^DBdg9(`v$45&O1uP${2BJc|v+?dPMaoteMjNQ@ZeIZ{jr{@!5%a(MeFs*?Szq(BF z>=B{&q5>yH;>IEFQELyXyHyk5Yhr9YabNE?*4X51g^`6nLlw28D&OVpq8|31Y=KvB zq3okU!IVEIC+sGA?!N=h-#3x3ps@>z)n)_zso<;qYm^^QzM=0si>+g%x@x6 zk;0E(o!ahL>^KFftvUQCIo22z_UcyqCGy7Al=rjoFs8n!SdCIYU77p(=G*N$)zDJv zezB@!`6OWQ|Ojlxz0@Css-nXQm ztj-|X)^>e@B_x;)uARMZeum6_J~-&`dY!RU3GZ~4G|j-@!OdsEQ;Vo+99PA|`g-{G zfI}H?Li7!xDF?*SC1!g>?aHIDaa6Ot--yK9e-!nge9pvm@v`FNZTKk{W=7$q!uo-$ zmi`RGYEN<|1z*SWXKGfBYYRygp76fW&U|s;Yfy4#|N8TN)xNW*Lb6#w{k_F-&y5Gn z`OVcGg+TA>m%YmNg(iD}BJc1rT`qbN*R4BnorGdoUZu!BjwBeeu|SkhP}jW+8|Si*F|?Pw@TocnWs)AcemNa zRA-G}d9lyEtGoLO+~OU>L-d?B<~C$DTv2%w+*$YDDWX49V7|GdC)8NT zUB%4AfonR-OCuZVPkD8j=K0!OB@5F4%9xKxC46S&F3N2iUgmJB5fOcXYBBzk^2dL`_33xE5hyWiLEM1nxSVwxdUG9JN3p08>Y(AXy7{u4*@CA{ykO1TfW&^=d<6%94YR_3@RbT zF^U?+N8wD=4{j%R%j{pr*`;`-_4{5V~MG-^YE z`{7KvD2M&JgU!z2+>wnDJ5=^4i*8zZ_kO+oXb%#C2>1vxB{}fU1*soZ(722{{MC_P zdeDvegPJ@R6=6R*7;}pH~XlHNF;ku5+wT`Vr zAM?sb7bqym)qMGLIEvjj3VSVXuF1Y*5WW#nyJt;kmeSs`)+$)GpnOjtZT89~BxrSvJ}bVOyQgoFU{^RATrJ=p;hx z>8_&6^}~&Wr;N24eX4<7S!qbCCPFGqpVY?i!@DPlg6!MXOY7NDJdg2nGc)P8e77*R zSMK1(gvYFUA%2EHZ`2Gc24?uoaq^wf$NTxdnYWO6gLg}i5dG{i7EXuaBw#+`q^tz$ zYO|*KCV~$lbFXSXQLC_Yyp9mFpzhVoKTmh37T>L`k@H?a@K@OpEpQBPKhQnbUE_;nv@IktL8}8Yxc!3k*^T~L%qf&gw4qzIGJ%Yv&Q;R z1Z(Hw+>bTB=zVzG+U(-_*48vV){p3?C|#Y6yqTESaWNO@<}k0BqcP6&K8%Oq_TfGU zyrn-@i0EtAb-iJr>*c-=&Q2GR_KjIN8oJbr4c**(qPn5;8o=lYw?zZ5yJy85*Jemfli?zH;yS4u<$@@k!6|;9F zLGN5YHLZ4{#v3@bD6dHk*^{=F?>^^TG_@e*z!PP4d_8IwU>H#w_*`>v|JGp{j)JE- z20m{xkkGGvqi9;R(BxCB?TvP=9Gm8%q?=zk&8|AXqoyu{U8hr%y0~lPrxnO$WIQcx z?5&@D&n;1}Qp&Qr#=+-R_EPzLv(CJtVN3QCkEP+}x(WXLLLE(|0mpu=FtgSQ7k8X&Er@+X8_<{>EY3=w2BOfhtFb zy@c!ZU~xK!HQIKuajiG}97RLP_dJS6Y@;&5wS6C?ciMF(+m{WmIUxR?`s8zQaajm& zLl)|z57&G^oON8qNox*xKrf2(+T^f_)e?7o##DjBvdNH&p6dGdL5I5$>Tsl5*>jJO z;@hltNBK<3O0$Y$2!Ku2xPm|sI}Mk$zxl3 zviIpe%OiZMf{uC0Bz)2bSFkgp1$bI4m4fG!B<*qgdVVKkS+UCg;Had`ID3X5S4yG(gnzwj1w@k*6`sMYGaW)WuU@Auwfc{%oIrg%(eo0UFi6prAK~q z4XXSG*z=HMU1KX`i5y0ybIshk_Ht5P?R-VAX+CtPiHM6H3=matTtqZxD|gZS%d3r{ zp9$dm>E%)b$t`b@8_1r6C;AA;TDg=?xAp1bD*MTvH5pC~q-WU44P?$FN5%yW=bBzW zx_!mMg|ujCSJpc_+!KedgvSHbF%FFN!9axP1D64M#S!%C(ogw(X#-?eb(>DK4@)f- zlaLuvZ-f%Xh=Q|UbyOj78O;!=fq#1XsjY0D&SDZ}S1)Tw=WsP|FMj9k{5_S^uIGM| zv&S(x=Z3|VVBQqcrq>JhV_eif_1ZEHMnT}?lNjhW(%M;~SllrL?dU-Z3>VD)}GX)#767~_tK?>>>-|D^Dtr+;> z*1%x6?ddsoUe~^%g>RILGj@FC!vm?!A;ve0GAgL#cYz&VE6gidQ~iFbU)Gq%a@Z3T zb8Xw}p#(4^F_W5?M(O@#lDR3&C}{+LmP~wU<+;Mnu3ff>3@zZMz%koS07}@0Fph!3 z(xV{{GlnKl!%l@szdoN+ld(^CmX9+0^t0nnQEzF~`xU82blhddemPYoT@ZrVhFj~$ zNqONk7e_xE7ef*yK%2S1cJ;9J?JK1g;~(|Ct@RtyoPLs<{8=Npq29Z(bMA`Ev+S)+|4m=8ww$8 zKn*YJk^771cgjfaW>J3tdi*)O#TeMjuR*|G_LHBp*gkg+uo0OJ@qkE8*Z|<1M1RzZ zr)(@hoRGra5Bmms>ZRfrZ?ywMItql-ff zJw064x>tM%Q4zELBEhg3yygXtV7jHAWSTTTZ?Q!z`Rhzp-EC5nLhYl62e+9xkj5lH zqIf@FkQ2Lkuj@|zN+_JwIYoy2#gAdxgSstU6T<6*FMW`p9o&dzs5RUnbDdZqm7@~8 z4%-YuAqL<#swgd0#1y_rkWw&xMD1uN8rst}8y5$s{WX%7>S&#_7c@gTL*+ENbjF?B zZwcc0&hQAC|3aMYr3by#kB?k51+wp^XbVq&p~)ef-rW5-d!5;F`I+(#wWghf{5jOp z;qV1D$tSA93NPA#vfVc2^+zCB4Ra@${W3V&N7od6*} z4}8)z_$*m2ZMK#fuo8P2d4bCF6~oV2PwyewqHvfiQ}!&sopNCCxBPw6HEzHwnX<1|xYjsie;*cI^8oPd~x!X<2U1 zz1Xk0@=DTG4-F+8Rkc?k_qDqVUxGNW%C=gso?ycj_u~Z+YJlQSQ%DHZA2?&msI>B5 zl)w08U{m&clh%=fes~`+5IYlyJo8Mi!GuNc8;3hd!Xa8Mf}p9fyh2vD&|+JvrpcnC zkr=8_JoUcuBt-?j^mfs~t+plf2z-3a*EKmY%bb=~n)|KI;M(6TBK*-9Bn8D(cHBb#ewR7RJ`$hs;S+1Vvq z)^*9ewnBu&&CJXS_u5?Ry8K>m_3hK=^Xu;(-tYT*zs@<&^L(BmR|5An<6tb*B?M`a z_$qR*>P?-64&sXjv+r!VY4cV-LW#^0EP5Bc<+&;Zd z@>O$ousX+~FO0VgAA?$GWVpFubq#A4lj>eTLj=VgDb*sjw}d**5^nV}E-NKWz9!4nW4~K|?m!M`b>S3bk!s)+y8OzuU^cd*O z3%!MZj5Wa-alJfjIz$=yHtX|u`lwv*oD*6Tb{MWKT}O%!-solg*SAz2&-E#ZQpSK= z&rrYuThZtwaxatIY4{ULk!KsFx}bY9e5ZL0KCIEam|KP{%#@RNCK9ovvYU@Oue;6} z%zKAEh{tNOf1>(89E*$F% zds;!2Va1ts*^REX(VO4zpE$|5@`yODDSZ0drGK5S|Ay~DG*T=1$&Dt~t^KDV6ynn)>rK5;F*1e`?w(9BWKzGF?&Ig1^>*>H3Anr)pumJHt3 z{a>KdjA!iaJ%xdrw39~PoS`jzo&P*t?8t$lo9y}R>qA4vEYn*Wa zB^z+R1rzn!!aNsi+~yrfeaS4E1ZmEJ$0OchGt!Vv_Sf#J7*h7yx(G8rm~Al{m}9r7 z!mT&VV<=^Nnr^b=kI#Gk-EH~2e&7;F>h2Oo*58BojyKiU8_=}}$9-W||0T8~1jUsO z`q6$Fq#?6*g=23^6gPgMs}nt<6eBD@r-RumSofrhxcQ^M(6V&nnr#)LjQ?K`U=ROo zGHY<|B~sMRuEh2DZ`)*$g?pNy=$W-=b+;~C*{KBw_P_MiAaC7uLuEpR@EdyS-bWmm<=hvnP}0xXr4{F@KK zp(gRvX~1lP#5lG_izlNUh-3&DR9y>fT)W@K--~O6N=pPY3vb5JLFc?JK=4=@P@7hoioJ{r5K%7q&v9 z&zK08f*aZQmWo!;!KBk{z8U<-cAfC~~!}0BEO`6a77AD7B^PS3oYjhCa1Z z^8BnSq4-C=^g`|xcpcPdm8s9`y@@a}#*;DYYnoHjdfqDm$7(u<1%SdSV?9Zs#%s&T zC1~#Nt8tO9a@Bl3+RE@({Ox~@J#;hwQ$UrNvc}Hi6pt&;+}uN+`TD5J4!@)??|(wG zi5fNfn$+OKa?NVHFLi6e?+A08xrs@{HIsIb=|;_l-v2t=wvWCPOs=&Mdvdv*iE!gXsyst>*izKJtC8+}%9}^h(;)Q-a8^4>^GAZwU=0rR0Sr zl%7;x6OnIB%Ne|cq3+ipZj$Ojl(k*d=$@Jau7AtoFV}zPI@P)Bo$s|H^$FCU0Qj&d z+dcpTjb~XNk@XJ5Quy(?O4?zY5PqXAhvR3P3UDKC0)Se480dk6gZxnWS^W_Eu$T9)hr)^B z-#xj0vP6w-@eA%78Bj2Yufg7;$)^i3<3HG-i}Ebr=p*FxZRqa(yrl>I2trCgSh(}U z(={diR%Iw?tDoI)_mIE9mtQiUQTTn# zQi?_&%VXJ)gET%Ye6=M=$VgQ6MaQjWX~NG9WKkMtSQbs z+7f}~VO^*Re6yk8dgfo(BSruB_1K!#_fMfy?N^kO%MrOZbYJskFtM|)CSrJ)4Sf42w{44tjXVz_Sna-iQ-JIs+AxR>`z50K*~JT zyE2Bu5U{717HZZsJRm1R^<0eH>As)|dh14g9E%yjxxRm zM!mIHMWq@vDFj}(R@|VJqx#_2^u73j9bPhbWaRcA=gM|ODpoXkH%!R*@=u zgb1iBh~Tct|CJ)lg+aWi1RwftP=Q&Eg2t21eegh`#(Zj)L7C8u_V{*fl6Mre9u=~# zQ_IOF7r2Dz@;+Z<^r_+Sw})t*BTsui$z3(3=ebi_(^kCFIv#`5Y0Wh@@={51UrQJ% z!L_gam<{fkO%Xl<#%1`eC$G7wcH4ve6!HwN8Yrj3;MsOUC670k#!3f`Uji{_abp^? zjycg`20aaX+fBJ&|@H%T6`Mut|fx^@fD3s2&WM$rvM|qXE z0zxf^PTfkd;X^_GWuzLh*SB%vi% z`>?QQj7QIIM*Hw8wf73fG7em9@w~??Y)&B)t8W^W+(Sm|Rd=~6a~kzAjCW<^%Sh#q zfW>xCpUaCP5=d3pHv;)y)Gm zF+V6c(hw!zvRr(yl+QqbL!&K6e?^bQKTrw$q|&E3*S+F)=H@eQo#TIB$)(gBS%0=n zG(5(tV(cixfrvf4$X1!IX2!>YHtGjoKRaYC<`;Z3w=MlBc#y4O&(xLF7hQnZw0Hmc zmhRxJB5X3DXaifPx?HJiqH()$vBr?}NhfZVcZ=)*&CCIX+}+eo-|K)}MDjB5IzO#> zwU0Nh2Uad;hbg%1q+4<{Nd*SBhw4R~5agpj2n4u1wB>Y?q-XBNnL~fwTa*)GSH?>> zPzPZcS$?_gnzZs+iKS9F)`0Hz%8I)CeZk5?VbJU4(Q&}NIJHPw^dK8QW8c@T_A44X z2iYP-2jYs9e+Q!)O;= zU%@_dYbGs+?=i8;zE(#-RxofE(W3?Cck{euZ_;@7KK3{I2Q#laPYWD_d zla5f^GI5`stqN(zm}-k2V%uE}u`{#ubI_ZL>hcWjTXXqNSPN!qGbY^`;TvXU;^BZD zbbq|`(TFhG#{+T;Vuzoh_{>Ja)%CZ z-*R&PnIiF|qb~&Z!Xn@}W5Yqg12m{2|Fcq>b?3v|eT)-7J8GJ`ul@A5!Lv$(S-gE$ z&u4D8n6XA~;4Uoa!MJ|9$NKPx3s-M6IkgjPN?SF@WrYvRu$ck=rp_|$YkRwH)(j<- zqkE$8#rYJYgxpkXUIu#E4+}GxDeQ-UL1e%aI(lH$Y45@w8_yW*^$1d%Qv9||45a#~#I6%WkfazW79H%mrs&X-^(i4y3(dwd(X+bcgFIll>VL|a71w_XJ= zt^pX3HAX1%*6327*wQ~{h)}*_hIYxX@!VjLE) zPPj|gX7dRM^!3_wo0j#d|8ujRPgK55-lK4DdU!l?vhQBsnims0jd!(KE0!L~SGDu# zStW*R8l|0YNhV_-OQB(wH^Taf>R}@pO&;vlDoojUvvGMp)QE<&=Fh0ZG6Yp8lrclj z2NEx?uL8W_uG#%NB_FXXeZGv+1P;>`w@pCh{|c={73L1>cNKswtj;mlXAW0fl#_4l z?IzvAQ0K%*0ei63{El%jLnMj?KYC_z?hodpxtj0Nwnn^QS#Ww}oPv@>b`XOWPrVhp3 zGY#OI>-#5wc^FuS201)E6mIEVRA-yS29nr3lF7r*;@LRvKgibQ3Jx??o?dTD2VSF0 zOkw$-502zeU~9}jQpnSH#>_T7H<0ek`-5y%lQThdmz0^}4YI&c9OF$Z-=A&siZHHS zm#l=^o_l(Rms;{G-H$w#k$NlcmftDP4c)}xbf5PZCr=ioTI-rQN-me46YJ3jJb<8; z3F;>0GwaVWg6BCbkd+@28Nbz9VLPWY=({RhX1jyf6q^1}(c3XA4pZ55GYn9q4efnl z5MwuuWHFncNFq+XejRyEa@pT&$@Psb?O~asgs-peZ|lVw`oWGkA4Lh7zjFO`C`zam z07h1{`?AC@jcF-xM@8u20Tz4DO*5kVX0B1GE+@omORyJE^jiQ=TMubj3~ z0xiBs-sFsqR$SycW}*jajqd1Enb;S1ekCXd5@@|E$kJmzEDzQ6bwBw%{DqU*QI?F% z+?BBcI@jdn=R)mAO-dI8(iGSiHgWq5fW<%J0@(wCmkM$wxx3)W>PT{1m1C;EaQ^42 zE;rG`BD?L7W3??deD)HG*RhPe_YKe%Jmj>nt*>e;^I1OpeYx6*M<%fkkeyb{m!2J# znM|u*nQ0$!=C5530^aL3;55F!f2>vV+b38sBFNGymTkzQ67>?8`?eKsXBe&SkH0Zw z?#f^mu*o^}Ks*>t64fcoF z`EeYEt8gIpt{uEbm&JYZRcW2@;rf>+feSftleu|@p{Y)-S%~qVxvFnqKT|sKZR#9` z{u!jF_ZoGl>FWRGie=d{w-r$%5_*wSl~xV8#tG6iOox@HMk3!9Tt+0Ok;`b=mIWU@ z57T1LMBnBGH!$!0w^<<1fNGz)?zzS8fj^` zEMa6bFg{=p??WmWDq*3fB^ps4uF8D`G-El|l4HQ*)uigi&k1jzgNTelQMWUMP1|#S zmQ7emd1$DZm0+A(#{U?!V2_D0ouFUfem(D{959}VF4pl1NP5R%$2nCBNC67&rb*uu&K<09Uwlzr=rnx9eCSdKpQ7j!h2u|$ zE`+z6MXow%e9q6f(G zz^;3lTy=qzzFyiaZ_M>8g;zDqFQ?5CT|KT zJFcb+v~c%S1)qggR3b6?7mb|(n_``EpJu55hNutJn8p+enUd|+zCKjhmuMb) zo$dEqIwJ|ST}Ec2ZN6CodW#g+%#csAwhN5H z-%8wUtOi#sa6X%xS~xp*ud>yF-B=+kFc9xwQZRCS%@G}pFX2$m{^PUbXAVSFAN~yX z`-INB@r)Gfhg~+!QP)-&98(7lPE9ZtXW$r?i&n#9s*uarn=Pa z^uvB|0{(H6ox&&SW(>%R3=SWC%4Ts*cxDVvoZTCq7jwl99^K;L@Xtd1$RVcmk`#&t ztv@%+qm(Ge#w)r05Gbkus>FjwX4LOTpGpjs)_xYGN}#r;X5M@Ot`?-1Fl2%Z4AtI} zg2I0)h#iO5Wdnk*(H=DW(?&UunKEN$_H+-{1O|>Vp?htH&A6&U%iJCDO=nv_xv2be z&NQ%RSJ+`iidz_`HLQaNp8b2mhWckF-agcEm~|rHphV_U=7uV+#UFSD{md(+^_0lc zZshn zO^6(1$OK~GAiG;6UvF*?3-~hwvV-WT?6$VH zo=f#j|4S`D?5{n^NM+6Sxw!uzP)BG}NG5LoiGAQ0PFLm z=~?}BysYmP4<#EisKBfe%Pmn*HG)gf?jIHE*I@`*f{H0h@rxctfe`C` z!c6k@5B+ia;x|cm+k&C$>v+ygucQ@yD|{IL7a~1L1F=)~4jV0rtyrlXXxS zX@~#d{^P?l+-Z{E|C02lN1?ul!1U4ISA}>R$N{>{>B%Afrcf+Yh=v`p@IhJfQ>Jh0 zN;&goj&*Y+FM)i{D|8{8erxwF7<#~eAFHLRtPZIj;*c;6WStlxf*HzS&z(2|p zsqAFxleu-!eK>gCjNLn+xt_TR%$bC;!+ETRKspQPrV&%v`y>1Rx=DQF+uHs~cc6lTejnVk3z*?=zIXHz zqLG~iu4xnlL-^i3VizaJy6pZ_!%)scU}T)z)eb1>A&$-g8+qt!j_k%SV@Q(7#DvE5EbWli-- zb`Fb;P}3)`6cc;l>H=Th0M+JAfuY0VgTEdA>9;FYD_VrZyLH~%p;zipvrA3auNGEs ztzkrD85%sNVo-wYApmrQs_?GSPD5~7pw;teYFN+e`K__{3A-1z*1PIr?RtnQ(zAWP zan!Dk#+`DR7reZK0>Em4Zg3bP7z?eTx1<)HNu4+$ZJldLTNAoW!NFlm(>ae4>6&jl z^N|lbWk}!aH=-v_`3IO@I4l#?O6R`Vec-#U_$-TTJV)d7IdW8RfK_>=dQSqYw~AEG zh`thp0f~eGXMXn%DfjbbjGqHA6j8KbRsJau)YO&~%1 z66tq7*FRc$>I{(cbR{{t(077S&a!}<;7bET?;G@+Sv_6m<@HL>S< zGMLTtc*OKIoyU$d@X3?~8=qfs_FUR#`r8AMfmA;a%TT>3>f^0Ea_u=iGA6?1AHCw% zz1P74E!V=4T?u+MhAa}^g<^@#IESg%b+wnS^6ScM(=vA(h+leRyhsmK)ved*@iI^% z%MowMWp~_zY^5=!Hyd|jz==Je6Rc+(Bbr=`-rZ%EjuoxD!Xr8KxK85nIOUDe2)6Re z)6+hel*~2@=NQBInr{HEV_jBd*L+t_z^ilN@p=WvVxkmJ-IMLh6&3bL4z0djT}=}r z<^(zS)y8OvGSLAsg*e@yJmP2@w#F=Yh?O#L^W$;hR53-$i5g|$WHn3O@bX-y-qjj4 zmV`QZ&FKC81io%`-!|6=?4L+ANJpek7w9kgbz%>w)d4jP`fOBT9uX=SJNPBeM!hR~ zczVj`Goy?r3PHI79~fjr)1Y~K1>Y|#$0nx7u>=IYdE7z2T7^807&6e|Z1V)|G066} zFXiIRZ`6FH+A0$^t(i{}zg~uaJ zkk^4Wq3{sEWst#rJd z?*I7_@4MFp?3t!9&m9rEz_3!xYF+^B&JYQ{PB0$gM8>qTP-2-A)b$`s>VJt1zN|wU zF3iN2CZ?>v#C6Y5#eu`)=R+$M;x;ByD|3SyVm8cyrEgmT#U=^5kW z(o7}&0vRADvE02JUKY`{{9^Q$db5)K7jW150nE|e0~FQs#JkM;Ju;uC+Tu{!C#e3U zn84?YeG+458I`ppW$c2s?^&B0Vvlu9bB@21H-I?Rdlz(ltl42F(Ra ztHb&st!MZpr^9(Wwv1f5atR+_mv@Hf>NePaPkROl-R0P#`@rssoqZnON!#5j>nCr5 zCnNNm-#-^tdwvFe`0fIb5>>W$&UeDEkjcupDefem{*^WOm;({s@qI{astfw=P)xq< zt8H4N4&mrB;lMz303JSR%N2+}PEgswfx}ks&SkCK%Ow_pgzLRYY+Rfj zaaxmDnCry&cK~+2#l(&4iqM2j{;WB*qA1%IT`JS~GV)yFjf>PHtEKU-=Ur*i#)A?418ba#A*KVUA?D?E5!<=M-4+q0n^q6i~;ys*p3!`n6I zhKZ%0i+D2gE)-R+yxDo^AdY^tgA)++TK1PHYe;Z&Q2DCA=>MMKf8^rF?!=|eM}A35 z7vUfqB?Ox$qI@7mc0ZUe_WZ~`9$h(DvJw!+yH?AQ94!Ybb_ZQMC$j95C2^p509-hh ze_gm=#ApCD&Y9l~o?R4i6UJ4ht72P1)+R7Db6h&sq!+)cv7Lqds+T=3;{I^gmawbH zc<3VG*(;p`F=BbG{OhY~`rjw^8PQiZJmJ!S=Zki5JH#Bow^l=>fcVN@f%F_uanZG^ zCd;OH{oXH5%}wsk3HUFjdHilJx0tbjMITXW;86RCscB2!d|Dmx^(;GI}I z`p~lruzQ7D;izjyG_YCvaSxq!&s)P#LH7?_zL&1>PAX;#p}*r^nW~%ED5(LZBKv?Z zkw4-%4;0UoF*Wj;JLM1qAV|hnqYCL%Blq3sZYR|x zFsyOw&D@(UZ^AAY@Wtb|5jsIvk~DDB4-X$1cx3rqPdNN^L0x*#dF=XSMcDZqk}4zI zW6y|7fsO0NLkqGet}WOY)g)$TT9nchTShk;h(c6l$bJsEw_F2TuY|j;pH>OzqCj&$ zx`+)6Oa)9vVb!*-r1RX5rjy$Oy3#H~wvL3>M~&Y_aVzZTUGXT*8x(OZrVAk$ry*?0E$C_G zpmfZw+wld;>I{N@x{3a>K@hkRgtB^2CuvKZ`3lsCvg)_U#=r9wQ|o)7W-Zv)`&AG% zQBz4saoTqiu+NB<{+%8iN${6oQz~+{_BKm`%|nf-T$5Y4>9;OqN5Q%s^W*WtCuLbE z`7OjA?xmHSgE=OP_SJKLA}+p%4{_D9HWB-5KAoBo^ZiXh26{v`BB)J*V@yHn3$H7; zXyL)tKA+_aM^E$ApaMf9Ug}y%y&EEHYl|a z$0ErMSRl5Hi@iJo0n2FraO+_2>h1h`b3et%UPrHlIH*47;m`=JSv7n3d>~)3#SXr( z_rWUc3%Q;`Yz8b)kQBz+mSCo{=wE;B^Y4@(8`p9Yqt-1Gm?Q+o<=dA$PX(#yItm2h zRsH6pVy0NZkmJ!>%K%ddCfY#F6o|Uv3Qz)vtNF9;3gnv^g9beUAxm-#2Wae)#HU^> z*!kY~QxF5o6x*u)l#=A!4@{P@-5@bWg9H5@BZ9a8CgqwH7MrA zOoifUhID}ulW^wyD$MdW6$b-pVTHNh;c2gNTQMxHwb z5Sv{-GCnD98O$hdaEiWZzpUa4PoWU_@rb*-%?&G2l^fSC%Xjghb-x=(nnkj1x5qJHvr`P{y|_Vc3tyaRvsu z-+~<$G;+!N@jM+VLwL!Z#C9Fr{rmk4vWtJGkz$P}oOPqIoKrj-JXnV;X8Lhp0y0HTmGb18@Al*V0e}nPB%YWY`?sP8pTe7FnVmj zB2>?6+n}-+n^a8KpKaj2)2xoj!}P?MwT(({t67TGRr;B{lb7SKN4-Bs+;+!(^Uu3ek^o&L&owmdt&)|B@(Uu)P>ekee90BK)KNhIs@o?Kg(ZpnBgXG zOpaLW`%EwgzR_7kE)8`F@o~G)5tDL{zOIjoK3Si5wZTt9m09_fV4)JI>K~9d9 zQMG6JxgO~~Xy5?vdLb3mxl4KIAdVg){QaUWPr>G8-U+?)e)mDqB#X3p$u&(29;@!^ zUs)?c{6NGp^x+G?RH_lXht?|JS|97}XDaX$sa)vd*4ww3dA4GAHfQ&YcF}I0T|lLu ziWV-m-P3xP`pv&?*Q=!U)+I1Mo5zmMX#C3aOD|(oQk3tIESVwhZU)7zYkd3+;s6-l zfj#CA!1?tfz^ERYF*6w;OiILFhn+2=%7h9;(^R0Ip0d$}?uoq4z`w&;UO7nr#Mr8| z^h-7?=iYeni+oPu3OHN4U+S4y)D8>ON{V~1ejz}{engzzA)G5U1DwBdqhP0m`pX^z?7$G8F}vNwC9n6CpMg%7yEE5ob9V!BBBC@X#bN0_*CP! zO+!0tvcrBaaI8!azbSuPGIhKx&g0v8JScvAQH7Jeuus>chzss#y-(oFZ)Pd7a(486 z3vIsRxqRK=Vd=^E%kcpM3Td}XrS`%LCo)H06GIF~g&3c!h(m$oCm`}VtIbuhi=KW6#3)S1q zmg?(TY%Rs|uFjzKc`GfXzUgbQLCSe}Kf8|Um?+RXES)Pj%UHdDU+*dVN0vMvp0?+zeJTgl)d>ssLH6`pas(j3_H-LGx^rWp<6nIlg?x zh0djbvcN7LbFqb#0YFz-NWo|3dj)mTM-Gbo<6YcYbYK^+h8~DWuzIqM`6hJCoJ?lL z*7qAtWlMRxYOs)wbSmjKjkWYGA0-7hQ`xg0tU`aiN1_)Nk%js;hCwV(t5}ZoDA3S$ z4TPrL6lMAAEy~2cb~--ymvIh}@w^TU#;fFgSWd35f#wbVe;_RM3NtJNm#6SO$9UhJ z*46vPtQ_X;7V6;xplRosKko8Y>CK9Z1ri>QCks6c9n%Xrj?S9}g;QzeWmGPFIKcz; zdlbG#8pwe5$pMae-OYvUXN8xbH*MdK0?o|E}!pWg?r4&P(2VL7mkHu&)QTu4^iMm#7H4(dtE zvJnmjMUFX#irVaaqueew6jWl1J3sxZf0%UHC}TVddL3Cqq1wMjp-NYN#?DS#W{=1w zguW4iED9)X-xdP<5mmH8GfkG0gzLjkPL%40`+n-wrSEcV0z(Kj-IB@WT&ihmC78DQOJXJ-ndDco5&0Sg`ccv*9rdv|U-dlXpmndit zZ9|OMl~2V=YQZb-tB)4lK7ZE6U>DlAXQh!Gr{KnSwTtkd<6v=KRdlkDk&BUC+cM?W!5*dfwEnq*g@XYwY!P%UI^pZHBe+}Yt_t2t^a zbXcOAJwu|wHWsW?( zyAcAh4*nZTyw7DG|C2_qNMyr0U0Um6(!-J0PU=`Mw0m+-hQ{D~$e!dyTg3@>RE|bd zJU|ZK5$0muFB0!`dq2H$6JJxqgX* zY`C)Kdkb0{ht5p-seHGWWF3Vza+Sqt0z?F+qV)tnnA{vAU9FxauNWhDiF(N5eM_Am ztZ*rCzxnlCax|&I4B=So+THA-mw7?)-s*s*yFF4_-Q;0W%_V`>oCnlxjWcH|%)9Jw zAU`IJn3s0xLGHQvkLb5=Z8hcq&FtO^`>NV@&CxspDxd+42-K^r7xcgVuS%;!9HJ}h zHQnD`&7S9(GHbKkD4+fX^x|@#KACr^WR`kXb{%x}HG~Ca_B~^!1>3w(LCwJewFZN| zI2C3emQq6k4HVt&zyHT=&E;P{k$ZrK`5Mjohom?9u*uk8yHoLkkBj+ui-}g*V--V} zIm45q-@$*R^Tov?1>zWg3S?GL$OLg5h;XSo1FPT&E|6k8ihOe61y5^m@yZ?k&9Mq- zDr6haVJ-KttfWY6d%|3^Q|6JU(O{_98By;jSfJ^h2c=!T6L}H;xyvw_jnr+WtB?v> zNQb@>U|NXs!5?L=%c!Dbd|8GZo22Gg|7L%f65LLANp(>cx%r-nyKX(5*ckmuj6VIG9 z&Kf1Hq*ZTsKDzhX$jW*Ay(+UbCp~__2W;e-S?%XCx-epYQlyF}SbG#zo8P+1Bzc+s z%WSX43Y@+ht6nAi58n=%1uWuC&pr1VX9JdzUGCDGTa=i&Sh)g$ER?eof%(SrTtkth zR@qYQutv*Ex5_&?_vS04xjQ6FjqDveYQ7eug>nkT|A`jy1!7W<%r&PWYIEY?o>XK0 zfF{gpc!hZWEVHd~6F+8uBVEGkq$MbEhjxM8S7Y^ujNWPiUT%SzOY*3a(pjEWa=Jer zHcf<)xNucb)$ZeUt>wWmXETAju=7i@n_QoX*e z?X#?q&iZ*7D~*=IOnwL~dt&oMgJ*xf6K7DwKdWB%Js&K?++{06;v^-qdyCS2lMtS( z4L6RP^6}t1xwC{2@u9F@ny9dz;rgm}b*#*VF)|bO(gYgbCm)x^H!9K676jc<< z62d9>;XBGULJs9UBhpJ)!oWYy)GdhAm^nN~n>iyf67r3v|23U28l>UAh=4uM0?R{` z!P|5VG*$NG2O>12NxomghOzHM7Lu#EVJAxt%k<8}kH<5BT``(&A;tN+t^12^aLc#E z<29vLGv*jbITD_>g}&<=`jbQ5UkQ(tj8U<0LU^l?(S=FXVp~pqjh0;|R6&l)U8|0y zCd3i??$WS7_*Er|f(`})gQHM&H%iW=^p}um-3#GpOP4K$ip5yv@aBHDMi)b=Wtmc3 zQ}X9^CH2-Kb`=R3R~d3(o(Wc%rfAmRd&z15S%m&1(FBbcvBE87jD z*;2dSPUE+NxSC^56^Uzoo+m-eAvi5m)hX-qL$QluwP}5#PVD z7tm?A47XqY{BGd!%fj{_3hp-QNdlyrkno{}b|aVl)s`zeLt2$rWV)tP`2&(Rdi6h* zHoL2wxm?=+Gb_ErqzI31LTZTgD&0K9mb@FRN;zsEd3m<}Bs3wK{kyTGUIkcrV>%VV z7pjB5a)^!4@y?w{PnikEB$m$dUO231>~h%*ee59G9BuY%yY^iOO~9T$NgE57TS-7+ zv*o60`&eI=Xn*I?sF~R7SIqj(g^}3NARGwk*_f(WwAZ2gUP63f)diZd-5uU`XnGW|>eh4saNA2|u?soZXYq)HjFMWAa zelF&}aKo#+GoZ{(bJ(FS>=5Xh^t_)>C-bKCsp0-wx5kI86E}o7Ca&qlvvZIQ#K1`c|O|AQn^HCipZ)5Jot+$BS843qj4H|&MMxPdfokSecMoc*^>wd4R z@OU)>7I}1kI@2J+@2;snKWe9V0TSdn3~cM?JWSkBTYAs6etnGLlDvZ%ZOC58gO zx^+PHRmwq7X#t;|s9Q)Xkvom5dzIyHOc&8)%Yb5);2w49xoYn&Zz>vFxc!xVYhi&q zV{O}MxH|Fua=BU5F!yCW2g1uTCzUssTc?Y5hQ8t?=(_YMU&;`|_s20bx|RYb(2_J$ z)?YxC)}_79OdD(=`kZ|DNeGw;%M_lvj&r=iWMULIgIKV&K#($@Ma*~y`d#sbDerF+ z=k5wvZ<)I_^m3f;b@DlM!DQ$D0=_0xD~&bGYEILgOQiD=v@$le>;&-!(u{@K!JI@H z+B)f_3QLcHeSU|rx|%<(bS)~$*H$VVSjSxLg=az8fZv}Z9;IV1+8#O^I~w=hoByz7 z*?iP;;iAyU$SUk}mJ^{HjQI56b8TyUyAy2Ja;7pnSGb9h75Rmrsn6s(di(8_A^a$!L-q z1cY<{do#awk3Ml5|4jX)a&!+=H~JL;bWq0fnk5{aaYaakm$%mok@&)ms-s8PR zb8?xJ!|UZ=6b4@RcN9|AO!cZV!z$PwPmB^W?Xcz3DQ`N`DJ@w!+d2{#xmS?0wIXrz zhEKt<1Z!WN3sXZrFsLnd^}4p$D`2Cl-=6+;W$Q{I}+ zhne$NGvTi|Q__)Ze8bTUao49opCz_Wx^J+cjiQ63OK?pm+|J)YNnl94JT@g?rY3EQ{{g$qQqI`9$~`- z5KsO`lFRVuK79wizLR+b;XYOj|NXymHe&v9~diQg1v zrCg@*wNLlGG8NbwU)W-3m`%o_XJzgRme}4>4P-~atnTSGG1g0geT`34e&XO?W;{iC zqb&7=L$+}jTrQBy>@;t2rIJEP3|rm{Cv$%oba>{UF5bxnL&v)PF7ytUSl;?7jCvkf zHJj_+{W{GeaMzx=*Z}%-`xboHm-+<%Wtd9FH`uF&Wk~*sD?=;O9Qu1IEVb_{IidR~ zUHz!JQ+p+BZ)u+VMr?A_ynTh}!>}O7A-3gt^;T%vCs^T)aMvQ2`7&MTt#xKx z_Q2Feh7jC+u`IO3>K@U6hk4^UM^Yh}h}fZRc)4BDz9hir1a^{GL4;O%gHfLRJAzxW zCc<1fG3vBnXD^biS!u7t!>ec<%-?lc2of}jQ`2m3a7#~A`!sgRP$&~S>bQ513Nc1L zKT%-$yT#p%c1Ot~QS^PsK;I<8TSE$POq0u9`EQ=58Y*z4^2jR`JNeRC9pQ&vbxw{R z(KsTn6AIdVF#VcsMOUjjtX06KC7`z&`qPacWK&^}Dp^!WO0HU|R<#$c7g6b`vUsQv zDSKE(D)QPXH=S@hq^_%K&8fY_g-pDVKI3#|=PE4nw1Saq3MtVH$BPR83l*u*pZ znwk(l>3-(`Eah5$E1r5(iz#ok$U9+Ze0Q`5SoAW_i|&D5q4f4LK|0W*WnAl3Ax5^j z?~nLG%ARTZtR{?pW_EjMj1UnKx&JjF@RR8FaM%F#|G!9L1ke1siS3#`A5w}^U0Gng zlqd@Jxic_Cqwchgg2mZWx2`mtqiqN6=0c!Oor~hSNJ+A#(-U*GYioCPnw8JO3bTsg zA4+UgVU4B*x|a3ygw@HNirZC5-V@I`fi)RJ>waA6ClJsMu7NI>o+9JxwVo6874fz# z1V!H0J2@dNdmrL69a%?Ibf?w}dmpE&RWUzou8vKde%wS3jgRZOt9zH1fvld1ZAU8$?r3RtTe zJ(lAmn29gL+Omj#4kc=|=svCt+{ebl_{}6$epBJBE}5*|Oyc4vF!nZAi8fU?k6>&K zHi@13`@lfG?v<3WrxDNDlIwQgd%Y{0NL|k)+~&!D8!?^*vtR>3+R7vIW~4V%}>ZdFN}^BCfq zgIltCpTkDQpsshaT%CYNm3p7X#w?McMq{*%V`L+FZ`H?iklbg2X*5F86Gy#PyHtOC zB@RsXw%gk)mL^`?niB9aOwfpp_GtSE1D?!l5Q-u7oENHxtR(T-Re7}dcSM}@_>oG112+@e>R0Te+3Q<$P zZR5)R=|Othmc$!fu|j}^3j{|yOo#^((-z#10hKbvvU)>Vsr&J^LC$?*Jl8BiXcS-e`2YcVKj5#M1%sx-w+uDnW32 zR?1r-9eiuzRPD^Xmeh%d$P(x9H@YkcP3N zqp1-PleBnWcKW`-tF0DnJk95bhl8SB87qelL{N4mXV^)@BCp=<{H7vLd8meMg7avM zjH>X7s|iCK+32X(>=ZH?v!w+qu_%rxY`f#Dm@VoC?j z4n{h~tz+luE*}_O3S{2NgYwS9t%7rOO7Xjzxy`{_Da|y}deJ8}O1Y%{;2CX{xMmC2 z<<&VJ$g`!~axxo4HL}TdeQR!e(Y3SGyngY)^4;gGGP_MzV1KjCS+if&u@9ei(d}z8 z(VKVARa#wE{Y4A!0p;P66hL9iBn32<|8(46QUY;uND5O@YbkZJ?V4#4r8%QbNbbDx zDU)ZQ!)ha*D8u2GzLJUIdYkjV8r55i$mXWL`*3_d{CwLc|6l$HuwHZ(_m`<>Vxo`N z9H)sy01Lm_KN#P>+86U`-Z9=LT={<;zJK}Et?*$>&4C#F77=*6q$luQU5$C03y^9t zYv|q$yPm&tY5M=MZW4sBqG8ym#RrrBDUK?QaDA-{*b&rrIOF-hj~X_t+`K+D(@kq>cF7q~eT%OSdZO~}8y=wYJshJ(R~{z$q5!I=w3mWEWgX<%M6y9{#1sC9He*E zDPb`^-wG0I5XR0=a6z`6gUq7;eyK@^%hXWS6wAK~LUSw>f;~tpUhqU+ zK=G`eL_Qdq<=YLPvs5D*1Irdi->+|)`|iUR=lq3YlQQTj<_J z4z`yJTpwysyr3<{{aAngsE>`vmGKPj-rn?)x|dk7FS6U*i+7}YBl>!MLep2znBhPG zoRj(PKLVb2d0KS{=-yceKu$Q@kY}H}vKTk+ov6X@(Jnzd*V6mqo;c~1lkm9SExt*; z7g=a7$t5SMocBhsly&R#L>Q%=vxD-{fXSMt2U8T!US1xaD9RqB{YLSNwT{f@I4qxy zk%!{~3S`ecB1g)I_LE9dbjv1)L#NpyITd`;3LMikG6#qRAbk zOu?akbcd-2iFx{v{+YGYIj=foZkEoJua6%zGfBbRmDR$*G1$|VHa!mq^{@d2|(V?Z>RlIbBi4Z9S;WW^^d~Z*TaGtT#Mw!FB1#O{FA62G%?OwDa|?sq**$ z{@TS>u2!l`h&?&bMvvMi@1Q9mF&ecwpzwdO*fw*qC=B4Ce=qL1XeosK19?O?MrnnC zaTNcgWEo?QuQXurK0jiIKQDi*5Miw-+9?||6bnQw>nSk!GsLQ`XBR=VHj4#LlUl~* zyc3Zsw*Df3T&2hTaHO~sq5dnSAI%PBH^xqOQ&R=m-UL+wO@~h67~)w#`LuO=!gcs( zIu92JDb1Pi-7TwM8_AQlTXNDK#da~-djd+(`0**93Qr-;3TQ?SvD;^Ha&Yv{FF*Iy ztMQko0Ln=|O1&TEdxz$Z+lf21EY+OCWaDGz3kO&d8n@oI3af{vIh*@jdOj6LGX5Dq zWetK%_mA*x84bnA{U|HB|drg%MgqU~VqOL_=+vU8-qzCG3hAQ;UbhqnZH zOxjf-^SmN!@fIV7SPIWRw|*OS=3C}rhuaq(ITULw_)zwJOMQToY1&rQYQOsW5Bx^2 zZce^=Qsj5ZV?aSl&vp?Y-9)~L520~njYzAT+ALdYflujA2ZY^T2i_jqK?kRJ!u{>! zQ3!a8iItUq(z@jE0P~G#pjSlG-?6q3eNy|z36*v`x@;<*`E5MqnWEFYulDn4PaM4>PbRb#XIIIWuq0LZDcPE6;+W9YDDI##ieNL^*=u)p8twpP!P z6}{IaKHXh!5w`FBK*bt7ss;LDYRW><=@9$E#R_qczj1ZGNJW4&t1Ce4DqwdA$nL847V zZ`$t|#Y9*$dDQ|>B=4J8GD3(>5im+BQwr4F3jze&ND~}Zi}r~&70dWo!{p5U7{^LJ zxAOr9(XYg`eiU!{?*6pndiAA%A#Tu?nPEoim`)96h}dQVt3frGs&rQUSN^dPM+@z$ z%5<{T_<6Z0AZuj1k=y(=w`Xjd$-=xxM|Gl)i$=Uv<8q#?La-jBz|s1&2-q7O!*&oC z!Tn=l2|k*_;c=*@=|G5f^ly+B3Mo!LO57s4czKU7Q{me3;X%r#Sc6fk16mDS3Adu7 ztMGd5d-4`Svo^TLAHP3hy=z^6;sf7GN_q+q&ztqN#%-xbDI|aKDS?u)03l+F;4=S_`CVfYc(~dzXp#VmSbYSXyGr zd7D2{mP^3>9BA`qOc<>;bBU$CwD>s|JfPJzF}_OAHNko4NtT(FGG?Da^lKkWV#+Z7 z!)$``Ro;DEkg_-jF!Y(+-s|4>0h#Xy;F`BQDcE-5aCdHwin?tT5wD+U8I#g)kK9>J zDWsTAb#rJG3WhuYJ%h3l=})nE+Rr^_ z*i_fX+irX0qg;0&TGH?bJo;~j4Y~>Eh>657bHGHM=MmUfBYY9M-F!UZM84}=+IEtJ zqlquG=-ipxs}B`KU(|nbi2u1>s(^AGmpO9<<^k!K6AVkww%AgF@vq zeo)GDSnWe)?6R}vv+>W5it;`GBcJoP-{Jh^RoXWR%&Fc}-N-=1Jv>FxUE%!4^NzTV z8ji7l1(v>E!ekWM-vPF^J_eSL>>u}tvlZPBd|FoTpx6Oc&qs+}815CWd%-w)|0#@j zOTF>1jl|;eGf_26Q#1n8Oe=LAF5NsmHC?zLw#M%<`7*<8t%uNUbM1H?;6wwUVr0kn z3nte*L__V~wnH|=q1P-ODSg*?PZJhVkqV|x}^zPyZ ze!lU(bevCY9Fujxe-TYt-86#%BkWHuE5nNPA940d4dJ&7_50 z+Uj!WaTZ*J9&nmPR0#`eqD)MBI5ij6&!p@&kt}-P6iJY$NNT07@OhjixXd{sN5>Ur zkAR9JrSUc@ZWe)V!)?7$Cyk@QPv*D4S(;uj=9Seg1o&u_u<`!~K!_xIV1ujD4J7KBH!pIofBL}BZr%WN;WynfRHqL< zASa!p#{i1j5azf81wQ`N1vaLt2fdI3M_F&ls4+G&(*v$XMus(1k5DEsllLOeEZF)& z`Zjlc1_T&?vmN(WNY;NqCP+R!=i562FNPRihKl^YlAnZKO_fHv-uVqY2PC4@6K+ zm(a4alDEv6^`KSTRDb@#&9{`Y|k^kTz z?*2%-#Put^yNi5+^qBc24qEQbZ>J5t%07ttX!_IZeUQlw5hL+ez2Yx30SF_VFFR?; zuSNoSe-S2)Y?opQz&Rd@KsG>FZR>Es%)NldVDnl14N|L=OxGx3JXSw1RsiTR zACZ_ZtIrxyLka7CB~FMPZkeKDF8_^X__njigs1zceHe-P;i-Q87$IN z7?|F8@2A-!W|kiz1?xRNws-ymokQwnd^5=tX1a-q@VSEwBchS?`*t|6RPU<;7W~#n zy)d=R*bm|SF^AQ4xPA+3gdhYyrq3nl>bu`Ol>p?dx+U+-*8o7N2s^zr#cnF7rwLu+ zxLSBuu9LdFZ~9Ig+hz|?5Ed;K14zngsaMT~P~R&Gs|90p*g7D7AMer`dZ*)oiTw{8 z^G&Le8TOqn$t)HUJenxuqd%HMZyM+=xzPpHzmBO} z9kEtic}@XXcGz**B5!e~Y%DfJjB$e{p>U4hR4XV`=01Z$Z@5svkBsg&Hxe=cH;q z8%3@&Op8Shm5mT>4qx{TbCPF2B=^)>G}dwgBVkyp&7`oo{TY6|O%)sPg%m+wGCczq zbSA~!Me_61{QXF7km_2K){&Z%`{R!WRRJ@$U$Aq(Q*$Jx{1508xt1A+F{H^2SwsT_ zRDI}{gDjrr`v+Q*IIviYH^&EaUUmzQXZZs3*we?s&xxhwUR0Z_#uhVxsu@w@9Oq!e zuK=M)>|hy|po=$zfR`a~zn&eUtJSO9d)WGw{Ypr)^@2UpBJBPDnCFiyK9Hw6oMnApUnQ(Eyrr!%^O|VW-sKaQGz@?~`7Ax^&5XC7IGbF} zzmJ?}X^9)MJ*}q0u3@Oi2Rib=vl|{}Q*3k;)bn3sc%~B53+bs2mFu$b@qGNa)U-JE zxw*UG|g?W_lZgfXpYdfHgd z?~YlhP#kI!^(%3m|6ZaP-c1`|^RMPp0W?^FNbf3$;Xkggd^Nn1;_)|OmrGQk?)RcdyG&&0?{(5nciB8Rv%#~YEM zL|K4zGNK^y_^l!6+qoxMx*wQ)PbdDvSX)!#TAMU|n8i&3jo1-FCPh`;CU@X`GVz+* zCWIlIo&Or7&{zPca5`Bp6-EMz%0u~ACJEFOyC9djnE z@H~!SP04fstzECG^|gJE`|x`D(D(VF3jhOdDd+4YSj#OMdCuSZF$8NkuqV_qN3E?da5es_I-(SdKUX@hBOP;Q z{2)=S=a>SlK3))ehOGsTS1Pg)(G36Y23zH_((JJI@+NF10&TB}*6A_n0{?5!C!3G8 zA`OK=GjMm|5V}MzSCOw3=}Cu6NQgDP6=0Vo+Z^2=Km&?gdL-@(+p;AnPAK<6Fz@+(%FJFE~Z|MZFC*GcXS z&F7;b4#=oEro~KcPm$P*WC@J4@cw8zLWx6y)e0e5jLAGZdPRP8N;UXodBoRWJdpEE za?J<8LoU$3hFJS1=%(|)0%qD13{sjk5(u4|E`Ca@gUo^H=a6G9Lt`y1_bPqYRh(ra*XG<+@*l{R^uT8vGJJ&5R)tWJf?E{6{niRk{;2-M%(E0?5*5DzRRS@YKm(vuvd>B=>+ylv>sO~{D=>LPg>(~>3_w~NNy zb1x>;hC&+kIaA-DClzu3VgFuRS7q18Olj$aO6IsL62e*Q`8-6dE8-?um+T~jtxO~D z7x-h^p`Ag0&c#Qb1z_XqtB|L|sb4gNo|wTLxjRT~@1_~=dC7Cl41lxT%k*E;aa6{5 z5SVRwMNKRWGA&LP2RL(OZwwd+?!;6ai?0je(1N2Y%`zXG6ze+tUAQg9LBKx{deqNL z9XQ@1s^YDWCIcx!L5=_&(E=zX|H!SNA&Ve{(-x2h@K&xs3xR56%4i(mnv8M+FT4JZ zW}&G2*B4c&l#~Vw$W)W(rI{-5dSC4QlJ5NL?XJw_h`+iIRL`ShOz4eRt(v7a9n%s)yPh59lx+x?2byJH>1rAga z-yZv`?7sI#xDDAg>Y_`m>Bc8u7h)68LU+lCuV=f=av&KfO?Ls0 zC_BB}b*?@TxHb4&frxb0FeNhTkpcI8Xatz@QBbHP;(0W7*j8^HL1#JOqjN_6Cu$!t zl&10e#6`1NdV{zuo(o-6~q z52jZ;*sg?tO+8h(hAdIN&ubXuKWl*>v49?URnG}kQ3cX9d4s+z5W%!Qe6XHOXi3or z_%;d#9?1>ch)oCWCF?=UUFL1U@=V70@eGGHs{>&Il8av|#2`gHJD$Mug}1R|emRjv zIYF=CUotQy-0e+NfG3$&pckQz7EZ2wNAg{CvTOB$-pNq8kj&XcrUm@?zjXC~e~^(g zax>MY`JL3=3^G&PGhS$C^m?g?uh6)!Ctj;K`b{1RmHRH0K}RsAGuwVYXfJ+jtgeS= zXi8OPlLTY~+57u9jGZWOx55MJ9E*1QN-EXssmt%UQ|J1SbCEt*n>UbXW`QYRV4(Gd z^zaqoB$4CQZ@4jTur=+}LXjC3ZnPY7YuP}*wI%^T`d1+whzx*^4E=w;FQYtRx|<-=87kS6zV6>oQ3d4?$eIK7A_PjMi}n_MVPnn779VxS=ICM znMz~!|15=yqju@U<*zLWMLDj{{R6^XaY;Z2^$_j9w%N}@t_wnn2O>{Y9E`M_7=m3ON7`vt8=+Ksd{Xqr}DOe|sVt%QLROFT1i>!J`+OE{UDi zf=Y{=Qu7^hivqCd0zqA7`9ko_?~@`=FoyEf;j4^cHy1eAzX6JPS&lKnl-RQ&hfQ1ruwo~AO%J;Dvw8K*?9tecuhq>jVoA*X#rgzx)l{8h z1$2kCB)WYA=^!*9n=>lAGiq}Lb={TVeYLWyJfKz9WMh(agaUMY98OI!c5m|2m=Jz> z*|C2rW&yK#`qISn@a+4bIDVmTRaY7Zvo%FRvT1kn{o-)*P?+U5u^c&QlorrjXb0Hx z0V5?o9mH+nHg#&XNWJ8$U&Ip3^c)${Gcb`wV&N( z^^}qfWp5;~k=+hey>;v;a3qV;;yWjAY|80DUA~ zsC-#KOvmePRC3hO=?!g}@#l##slWT%WY(fK$J)&-Nj|AlS(C}oMG_iLbQ z+sa7Kn{;T>LsVTP{3ev>XEYPUmlE_GW}#uU1Y~CQs^3zPcxxC%k<(Y5_;FWXYEbda ziv|m}3D-=ZE~tgDv5PLvF#j;pc6s*!ISF|@tHr?LMcWOKSMlB&SzJ-W1A#@KZ}6d4VKEf>#1r>ofM58iNvreOlIAZ~h%K*!*}jh_ zote*3mJvL56+vgKkkVP{gLKrIAwCVC*_=6OY3G)dJ8F4M?_Y`i3@JOf8f{tdzg}!A z8XCpGoAx4R7;I$0c)i9au{YRU?Q>SJabEDFlWE-)W_l#r=wb1SJ;xs3vXZ19iwbls zT)f!ylqhe1qRPz5!UgWR3fEe{DPuWXBCe{;>2)dlfaok*?{ipCjfG=3PT~yoJ_S9Y zYp`(NOUpvcmRXKS!Ow(Udw(}~%!=;Wlfh}jYa*-lZeg}CO{e~yf<((-VHy5_%zu87 z<^Ey7KGk`^jhth}jhCPedf?ancT%rVXiIJo;tPS|hf4`8BxTU0E2Dx-YGNkPlhTyv z@uQF!viV!Anh-z_`>Z7M^ClwneL!VX6FIrnUNQeqTx=~E-Bl?*0SFbi3_~K#qT`Ma z*wJjiJCKQ~v(CgA$D7C;42&ZQIdkqUE#d1QKhY%UYLcID(V@v`btCpmvJg#mttXXP zhOJ98Vqj3*)&OUA^hGmWUz5Ap849gtBlJqo9Q1-NmaT6;<)jNE=*j6XyJ}nWRmDSO zo){jJ8EjVgQ%ADhM@QQbhJYaHYkGS$AkSeN-;S1XY_%bNtk%z zYejLhuv_Jr50F7I&=*Vocg$vij7+y~Pn)}@0p)ZjwC);IiLM)&7=-San@o~Napsh- z#yp5%6TUkQs}9@}pcCk#L-tvlM-hd#m%O`|Ei)Vt2qeSdfks6u9@@W;UNkR+Dq0R- zO*Mu_d~v3OrURfMQ{ovKzA^kXB8zQU>g=z%$iZV_(Lfn9b;jY7Ny~V4!*)44OC3xW zY{5D=pa@b}@O9m_s_3nHqDzFAo1`?z#h$Hv-f)yo6}%sB0Scc}F?qS~_G=E_^Aq0+ ze&*r5ujBWtbEfL#cxeB2{H$?X37Bo(rn){Kwfh}?MCPZG36VMQ6q9#< zsX4;4NRKMfv2)Rm;lDK_36oL!t^)%~xlr68$rGcP+FWa`bwpKHj-I1_4d->tBqUsH z7Y#iKxHXAkYtg=6Ycj1qa9cBMapbDFt@N@QkzEuvYMArG*R5HKC(Ms>jGjv?b zOPcD74cl%BOxS6RerqeUQ)n!=r}EIvno6VVu8~=DDVju9?dW%V}Gx$Pk>^5{YDJu&|I%ZiwVu)z)%vwc zDG!k&qt_(LC97;yu{N9voD%P=fmX)XCR$0Fjm;2=ih?F@@0Uw`4p>!lk4CNhgFt`; zEJy((m;O#9>8gmG)w<7RKkzg^K}_zYbZvPkl$;&o^L~#ME?{1spD~x3s&pFAqr}Qr zYg&q~fv%9f2bAbQ?!Acc(;?tUv%tdsEcH}R=F7v|{?Fo=FDUaIfsWm%xFNIdpnYB> zc1gc$-mvcV!v*JOq;ohxhZw&EGw?l{BJb1b=;u#yLja|0xEBy2gCz+y9j}2tthN0z z$-f_I@v_}}pSOTK+G0$3-Q0DC!CzA|YoSU(Dmr@JK%it#dkV_ zmFRb0KncFb&6_+U^&*VZ-9(*?vJtX9zZIJlAlOg~OwH&li(}Y$uoVP2`AOY( zIv0KdQ_5z?#bUkT%|S`GlZ`=3UkpP-LkIh1tpEC|X0l&t!~
~HQ~a+uF_+^&@Y z?we|DcMe?*K^w3Y+FcnZQV)krL@iTu3`tB+ zmojkQn~)<~m*U1O@SKFPKinZz>-Mm9)|Zhv zRl~h-J9%NuC9;m;&o;%Y)p|LE^>5E%9$H9`qo%6CMwrNioE2^8zkr%EwF6p#;Q|T^ z0%|ou@0HrO1m0KOqstF$vQI3510)3^JuO(B@kooISzYD7-eOPEXZcu&%3b(*%SVGO zKn5x@*r(u3O|+jPK}pXPwflhWHGrntgiDzIQ}^~Z)l_1cTP0fHv&C&g6~V^CHQv${ zMNQsKuPd52sK5?{{!>_(B%o@|ln8)8U({6nNq&^Jsrr#k4Tbc}U|FQ13k3bLHl?(e0l@?Q0{DVPpssx|}M)V-i zLy9s*vYagI{k|5QG-PNVs5mHp?A2~ef?)v7PnRt9ujB`=5*_yU35Ca?@DgZt2Z;eH zbaanqf3_?XW&U;C^8uSA!(n@1oL4LIkI}!S1m%k{5xMdIg}P0MDj_5ZQpf;Ov6uE@ zmurbv=1)WE5T?sc!^!G$LtQfD1z|ZNmt-ErJG;fT4z>EXGc!R6`ZHhRI9hFiR`VgQctD0rs0} zz)3X1?5f>u^tzPF+|I@>Y7H`Oi%T7}_YnkGUlv6VsuKl0{2t(_7x3T!yM}O54ytp8 z!QKqR(>iRW5ZO~*njTG%!l~&m>DiLsYU!EecC(AR8G0#L(QJo;BCwh_wDi$0> z0<@<#ip*s;55g=h%I4Z=OmlvB2mbE9TFH-5K;p?etTU~n zmMt{-me2UlQ~n9$S0M|+)qWlKP@iSTtz$JuN7Fw0*LQpvEdwNP6JYHMJ_soevMqn| z*=WKG@!{YSzxxzI17Ge-vU*$v~E#m6$w;b#|t5 z*f%#On@$}FiA0E{ByVrp!2)C%QxD$fG}9|38pn^VCCoc`Q$7#e5%|Hzo&#)qVgP^w z#<@(i=!7nuJGdB*I2*7*3h#}L!OTHV+@_|cxfwd~zkh-@NFjOwE=Y#Ge?IY=qi^0v zCgiZR-_`rEkZ;fTDAptr3vW>yym+kYww9;Z+(hcOf>UYAgKRyf7D_A9ubK=?4_#aW zy_A?EQ_U?`8ovcxk>3_+K&YqqxBVr>N^oCr33;gYMH0`x;H54~4l@inUTTX^R0UkO)%{&PKGIj!ldN-pG^{9&(=S(NYgWc6D zk#~SkK=8ihe&=*@-tw7D+yEv72a-M`-v&cM|7oliY*2hRak_V*hqy3Hr}V5|K!Jse zm=Uhg)BY>f)9UksDG%>Di+3;x&(ZX;quFS4Hjr(4T3EHRzWyxq4*!7Y&Z+bl8FKVY z&z&wnA!y7Uwn0B&y9ui0QS302P5)=|=)Y?z&fDZMg68Al#}OC9TH6fizEHQ9qqJhL zx3k9M*EexNp~SeSBfSc5gY(}#4nbCEref}O!3#fr|6Gtpr#jVE0Urdr7(62lb|H9P zj2`seTibDfI)3c+aNotLAHAKtCd4TVAN~D|B>CV2_Bw|btAWp^cdnaO_xJUMxHu>* z$x>TcY2d4|e%dKQmSmErN>su-9iL;~%%>e+!FM+xKvENZAcvZ*1mp*^EuW`#Ld*;{ z0aaZJ{WY{d4nLF!&?o#E>#xL-ysoOx`mKDg<<_VA8`kC)OSL_FjujbbY;f046;JIq z_~ltx!}-s5E#l|uu(P8(FZlW%>UKV^r+Ct_Qg#SM$J`-+dNZxh+^3lkOU>nrA+{vQ zE#?_6Hox>n3wk5ZL^p*ltMnZQ6`9zEOfw^nf&8NA#tGr{)^}j>=YoC)iVV%FsO0x2 z4?qvhJYJV)=Oh$gQdBP-&lgqmT}!#)Eoj9QG_jw^lc$S!pis7NnsWJR@NcXuxETd1 zFb*3hs&MO|kBaloNJCFDT9t3bDNA4cVx}`aYdT6z*#dl7jTnJPv`1WeO6Q*^#+k)n zLe1K*Vg0I!=cuG*L48A3>Ae9D7m1%{VM;v(jAzDM+tQSqQbypaL}QLi$($54w!4dC z4aLG=SG`ng#<_7WBt%cB#l<@oDr4o+0x6_sjUj%)6N-647>)@In zi~HwiYaY(H&oVwmByfayImahs5bkOLZG+5P=^^TCxf*d&s_eK#5{~|z{iTWeZ86Xq zzpJl@;-f%Ut(fS#18py46QVc2rO`*f#Nqlz%aMcHX{r0Pfpzi5!8#C5yQwzXti-il z?vh++zFp3Oc2ZTUEWVUxEY2~`LQ{XBUDM=g6r+42@koo$%-Br-uk`q5>Bh}=j*(lL z;K)}u!}&3$39fsfifSHt`133J+)CuVMk z(?+l2N>L>On0DPbLLskn6C={AH4GkwEwB~0h!Lk#{qVu}JWN_=pzoKqF_r5}F6&yV zXA$1*=dwyM`U_*rU8RF>#@~3OtK+cU=rSHLg6E&D)%#$#^&>W@nCcwvWzoN1S;Ou$ ztW4U@H06SIl>Xv6YZiGI0@jdNAb?WIWJukapr%rkb?zrgOrLi-v?0G0obl)m^pmga zAFZz~S6R}G9K6pm@KZbRBm%kKit368j#fL=nz>%A<|ox1 zl`xv_g@*lm%Jc#Sl_1KV&d@@JG&2#NqQZS2^gM*7!(nwMIlB+Mk?(iyOF$@KlA>H( z0+$^rs#cI9cNhRCCXA(d8z3Y2@x{*_Qq=HX7? z_d3AVu-jH8PtPbm=;J`oJvDRI(*`n-I)X$u3&-+-;>OHczTXV1p=%H*PGcyyu$_xD zTAdv>ZSM2sITMW_8w+e3BX=+L{j=V@S&CUpeo4wW$I{|=rA@TOt12`kjD&-sq$@QeV=&Fo z(IxC?XClK0(%GL)AY&MSu&Vjjd0b~WU>|G!l+e!%t3j$>z-AspZCfR{N5B@5cV8`K*Pk}rFq*`Tge7w>A6|o+MsI?@VQ(rl)q@31 zipcJ9r!xq6F=Y|}tvka!eIXb@8cT_h zM9ZHNS|4zoXToHYv&j-8A`k1ZSm%wB%-CQ*l5%=ie%mw%a;!#syKl#Kt;dp+3Hfj! z#(J1tt+jxylPL`#0&Pde-y$o&wooO5-%(%P0w_ChV1-APv<<1u_eGo`Tz@vA9SRb5 z18Yd58^J$e;inU*XX~$L74mHSFbgF*s_cZuA0O@Oegx0xVmH-1WR@Ot;FM0-FLUVF zbm-Rm?qnEucvdG=8by?Cti~hShNq3k$o!MuJ|7f!@hxJg!UKqcwZrL?Ktk{_s_+Sp z+RLl-!VzRPa9eO18K_ra@^+X2`xDvI=Zs;)ZAAByoPmb)j-4ezxFPBWq_nN^X=G$Y ze{ZL8?7fn&eXT4-3CT&@j3616>)$pyt&eNM^lGA0Vg~xK+_g>voB}hsS~j+imQw=<$iKf zE`>i8>rZV^IHqkDI5#UO*)soC4g z{1~gcvRZMQg!KzK=mCy7Zmc*j=ldW6V5zTd;7*skkZ~>KNRp-zXn5A_hn#VbyORD% zkz9#E2|rAK9calu+AK8ZaWA(Hv9LHM0GTEq-g8=l1^aEDf9hVHB2@edQc~E7YAu*Wx(c_bm7vgyW{DG1 zFzD~NZCkDP{1!qX4<{=zBcU2^*s~n^`8Mnbm(H}7oOQEHez|Re$^S=Rt>5p9qpli6 z_nl{Wmxm9UmFJfJ-I~;YS0kjHKm_@icHumwH_S)O1&0?_BeBg)2=|#@+wis63XMRz?T6)esM)C*~J`2D}Di`ZXN3 zU0vs*`|ILW{4Q+&)j(sD{Ajc>9uwP+G! z0)ga?#);d6Uae*_h1!t)eS+uQ9)6!!sSGD3s&G;I!ox=~H&3Qc+O}9;rKj);_t5_7 zk$jRsp?yQ$r?pttW2;xj^Y>!#sj za@`u3tFEQ>+?^4HR%=A@XVzmMe9-p8t&weRZopix{+KK0SDrh7__bBTY2@PLwYFQa zB{mJ7y7|a9tMZ4+oRN`6pxQG@8Jap&i8l7`NBmI^=Vi!w6Wg^6hN%W}(ByiwCesg5 zvDvW6lcr09?HC)bqfr;=ZbrWp zvhFA6^wsS!SLUU88l&U8UCDeslo&j9pGOWyr0-ESaa2a0-6{}dcXYF$3pgj2S_K6cwT;r zEr}LTd}!G45T{)vywlnV8B3m*AoGCHSw3LE5m~ns{exfIVm13cnQYU2Q18#*Sk=rh zmLiKMJgMv|?7fC=zA^(Zs5ZA6G`owJF;u*YnlU>u(WD6oBeyD(0$=&dDcLrkKi)#( zX=d^R|4!k*pwQx*`+L9YTR%1mjco|RaBCMM5ExMb$%y`1CL_xh(iZpfu4+9EZzVMz z$6E7deL+!P+%M?4StAo_-v&z{mox#$ONDhh+6+?CKBD0>G#;!(l*3zZwI)9i>|^ne@->J8iuvvZ5*{~J zqKAoXpQqJB%rrNF{;65yjmcdf>Dw=ipfnUJUil((NAFe(7auP$odp|VmXzhphYZ=C1)4w`sNz>Pq)gk zUAw(1jQWXRC#t}}3;=XI5ypQla3n z_B20O4rmyW%LN`JLgM+)9FLM zO=0-C`Yrgj@FC7hocH0!ESywDGGt(sMQ6~sm3_nn9c}U-oC=D#2FBmc)|sj6D`mra zv6|EOrv$7)3UZr=y(ZhK$RN?A5m?X0GEN_Td8%#hx*bzRLwBZcxaTf8xcs~n^TXCf z$~Q|H){o2HZFSLVcxe1ii}r0ylJKK|Kh4Q+&M83=Po>9Z6QXk7!k&5&8g|gleKmWw zfL=Ti!|fvAeh?0dBX8Ds>W>J=A#sSIPKg+S#2>aFq_kX@#IrF>eN}(9kihya4;=J< z>`nR=e%^2oH@CXY;q`_TXP1Q^FPR z*jls2Bz=Z*_sWvXW48n0OIHnIG>cdW^}`?!1VnQ&?3{GeE09fFwQb~g&Y>VOsiHrJ zK@idNZLWHF_4dtHo1i$Sp0yQdZE8x@i@FJAanO?wC+DV>r~UEXvtLtvXX6Jiop?9K z83cKJ=^<-)bZ6RzTR0q^J5a-yrI=ypO5L<{c%Kgn@emd87AHLHj3ashOHE#G1?WxJ zpGGl`6-Xf)tNP{)%oQ)N+U~}6v;*(?;5dpyw7cGO{J6|hC?(+uSZ-CotHXhq3Y5R+ zXqc+av=Z|01yLZ|p(7$Pi7Cg%TjWM`D_=#vXbo=ZofeY7^DVDyNF`nAv|c=^JDJS8 zaJ`Yl!cp|%2QR7wkHXsc(B@m)Q(|3Di`!0r zI176?sR5&rs|Uj6UO2kfpO6`7&vCE->l_&;kIBl+tgLP;BC~bBq}~EPrpSFE?SPwh zq3mer*XZ9|Wp+F#Tu;%C2aSh;Zw*z++eu1vL%aI4T!ChCF|?~>9txl)JdC+h&D{g~ z_jz@jc-Z9I)`NwELzSQ+)?(U*naR?Qs{Y6f{Y>_I%hv*Y_mS-E2T4(9u4g?N4oo%jy~hR@Uq4>mxgwc@=I(mU@pikevr5 zAi;GqU%&X;jd9t^XYDlJbwt8K6@uCHITM5>Yiz8$Q5Z}nMtE{8A-;2xbtF671N;x6?(4K%UlzRJ{6w(5P}4?{xKq2Y7Dc>l>zC z(hu`({21;(?dyKGNz>Eyd$dbrAvxf$17B%N{6-3)j_aM1OxOL>q%55|Kz?8)Xfna; zm6-t*zKz5^vQYw;w26Sh=!npQKng~r1QO!8-8VI{%P&>3o`1(spi%^%bW8t=}8UF!{mLTTda7z}r5{zyCtSlF_!58^HMz>x_am_#hXUEc+I_b=+2SRu8j31>7f0EE z2Az+u=3>j+>bmd!GtULD6ZzNs%6#+o$HfDi0j`3L7Nfj@Vk&S`SNW_SIR8(3Zygua zw}p)lqJUB&N|%5j(k&q&-6>s?(jwgoDk#zo(%n5Y1Jd0c1JW%u2*V7&GkCrCdw=iy z=lkb9f9T)`&z!UO+G{;~J_(I`t&EwTjKYD!D~ab$IUvE zj3#d{z#nNkw)Efo$H;-$gOk!xUHK}c4pD1SQAHk-j*=>bN8Z5z=(vzVjDWi9Y0gT3 z`zGlP4L6tq`YsFaZoqBIjma^BVgW?L1Le+(gAVOD;@w~Y5E>1zR+e$q2xI;%BFCHi zb}uiA9Vkl^Awq0X2v`hw+F{&0v_IeG`$i`Z11(vG7P_p09yNy* zPHQZBZ%*u%>i$7&fA1~WTFLO#YUsPQ-6%OqW0IT2_N!5^)r(V~x~fvl#AyQiV+{IB zfJwL04is6K5qQq<4!gLaP97k4H{|x?7YrOoHqYC?S!%i+8jh5dlynho|B2rJ`hrJ# z(PK&J3r(I?6;kJ@#}}@PXEQAH7j?m;8^&TWDdQ;z5? z>^*9}Aj;;%q2?fQZEbCG{p`ShXanB6+u7MA5I$5gp20@Zc;4}2>@#wRZ@>+IkpfJ; zq}?PSe)=ujt-KbM2oJn=-x@a2n%>m5i53x2S2vxjUw4eGfMCemk@N#p~|1BV-1 zBbEWNi?vP+p!iiAf$)|9_xz`9!DH~x49bL4?b~pmrqI+8gZ=il)Yfu}xK~hS4Spt@ za@}xf(Q6f^n?V`c`B@Ye|0AT_0jJc$j7Nw5H*iu>84(jaNRM7iTRZvWIGvoFJe1Yz zPa5KnPO#P1h1OI_wV~jZH6XaC5CZ7)m1C+E-}@@H(BwZ;<)1Gl!R=RfK3%{+OZo7he&7(L=9s@NrKDFhhH|9t z4P)#FY&7x^6Mg{xoCeUQJw}bo8ph$!G)Nz}5EsKV=sFY-1?`J2Tn!A)eqPLs>{42si zrBA6{UqM7`s&1I5{A$x-im%<0pu(YY+_qHCv9ju~yd&cA8cJ&6xx?i7Z26DcqD6GC zZ|L$m3i1rPcj5^&Bh5Ex_NuWD$XvQv!#pU%k0xcA%y1{&F{KL%d4Ub#k=-}B)k){CD@hv|B>xx{}B)*Oq}0Mvu7>kogG_!Rf)uWUw}GEdY_ z-kFP6&&Ha2eC*=@OH59aPGreq*JBWfh93ZhiG(rAHP28PL$|4Ch@WgYkG4x`6t$bV zCw)tah>3T@)$XAj`;p0x$71MYd(LZ@ft*$MMTXzcX)|H?D;K(IEL>g^Dc;Z&uT?|# zzn-e+K36#?qNGw0=V#N4j1Sb#y#XS$zRC=ied@DbGtU`7ptTSDOCDLkkatZMqWBLI z_8emlg+OA`c0lvThI;Wm!$Hskz(-!^?opv6mT=zp#c$evOG#Jx)(LoyOioUA5%vDn z(?vY~2#UblYhqt7sEC{P7@667ISG5+uuW zvm>*d!XI3Ak|Sc)uQVRC&~|%P*7s)F@hOlCL-(~Tq78}6F}3MVYLvT=1rk#pc>}m9 zsb5HG@HS%o{7O27IG~_LxT3k8gf(!71w7Xx& zEK9JYwnddm;o>k0CMnJOVg%U0)*b#D_2 zm9Oeq)<2OZJ_X3mTAs(;*z2n4A6F~vV#C3QW?q_o`cp;EdoCJH&Lx;2)ldhv@~lrO z?iRUET33Pp<3Hh1DZc;0<9zZi6K|~(^230ph`k+PzJb!*ejgd1>OscHvOfWJBqRWk z4Qj-C$Tm%|gjt~-n8s@Oeq=Zen=kVr4xq6!dj+0eirGH0N}l$SU(H)To-;JlR~+2= z%%VhjulmBcuLjV5fD;-7yT({(R)9qXnmU4D_egcD@atSkUF%QKaNMu=xp?QSOyy#0 zTT~%s_1EG%$WbZ-ib&rd_1a(8#vN{nH9QMaj~XqgEIz#5&Vfe)dbfPSXobqd-0HS< zj5hQv_o00_!}*N+5p!8Lx~Km^4vZ#ZR6A#Ebr&7<-evSlFt7ON7X=a&egXqxAgwrz z4jxzQAj3gx`8J@oT}z9_ayxOLR1TC7E3F)Yjw=1!koH z9WdPu7o-|L5+$9vACke`T|iWE8bSywP29nCJvdqZ##}?m@E22iw4w6c4JnjagPUu= zIv_UKiX7--FG)G0^t=jK+>#>sNA|Mpn;t%+7ri$+7Ru#3=V12L?wcmR+Or ztcx>1u)+wvVM8>PUX!2{l%|bZ+r;j#gU8qtV%r*r4fKuy6=mg+FlNAEG;W&I1T%RRl;?O|vKcu5q0!@%B>;oQz zspF$!h+)wwMvig0F~+V+qdJFNK=@a$_#GtW-i;ij!M$jgcKZjuxjON#x^B$LLTjdz zwU6G$xWU_;5(0QS2FAd??{L7hyA2eOhKG0~HepFDgZwQaZT8X(>ptPo3l{jcm)KnK zZv3%JG?*BNk4Cbkn>m1PJEN1rigO6guy4 z>^aD-pD~fz&pQl*LHC*GrLsN__`Q+RoK1}SHrQ_n8Gqqw>Dlv(< z|JdufWINtQun!^(v!CnH(7^G)H%(LbTcG!TQS>**%9<9neZy|ZFKsv^1jdT`vqD=( zEcMvtnM2J7^W0h8$n87{=Z`TyUS3je#m;=VEV-RIgJtYGgZ)=myIhNL?~I9ijDURF zZy0W(JGM>LqggO`ySAVjQETq!+%4iaW7!)Z!6o2Nmx&8I5KK!;i&tO`N%Y<^-ON#T z58JFLAqZ-Py<^w=`Gn0`x+L5XUNFEPzzjQ2jLqq=kiVQ%*|kk^yv;xnIZN)zoTa`? z9^cXk4NHp>i0X*$yVBjgA`3gdhp z;>Qd1&S%}lEIbV$f~L2m!qUbRCLmeV=5>O&p@msN&HXvlFsj$`ej}S*Gn4K7Wb-C? zdhH#z?Bh0CEmw)STo_SP*gzRRvUJlANNP-5AbX5{$($N)yPI1dGY^`@cd7KRZ`@il z)NS->@Z9vazG_-{dl+c3G)FdS<=Q5ya{x5--SBUK5;Ig#@!ZED!8*$$fHkH$#A!28 z#$JRrncu2s=C=&rL*OP^TeN6g#F)gzMSW8=RMvFJ`33nxy2Dkq?V;Fh?BMr47+L7- z75`do-Mg8w+B9}d%yo&FMhdITN@j0HCb4Blvc_x0H?ECNA(-I$lN3jys*f`Oy_B9rrQ^0N{;8Vy~ZMUMUJ8A_`|#B(0+tai!`DLdN^mMa~t-0;4& zJs;vkq0EwagL)p;)#2ejJp+>;Vwc;f)XEYwrn9*b--FxA=4BY~zeg0z<{Sh#kbQ8L zX^CAvT;}K0SX`LBvw+d9$7Z6P#wbfMO3jxM0{-!9FR=QHA zI-5C=t@w3^S>AB+sjFct9{XFXjm1izi}tdwl9%vG_)^)vZ@b?m_v{Nt%JvKIV+)J+ zCH{D%sAu)nOE|PbHI98?pL@(F+$e&P`byLrZiKj!@H`Ev6gKh`a4Ah9hA^r;3pw7( z@`knePN2Xa>;cE8Kvjjty5Vd#mfH$#Iz)7`1<%~$b9X-6&gp$pZ|g8V!s>P-hN}4m z_AizczuV@#Y3amiCIrqHzw_P)CDtSvp0;BXnG&9OeN-20ANrgJuQJWeS51uz3%9Z) z1X$6}S-w9Jqjtvb71TPZMd?Be`bvf3Je7)(pY6U!woMYe(pMpQ$Ka!q5QskXg!=tb)i)9}nlHCxfHEoQ*7Cqt zb$n62-@wUSjtG{v&gep)qa|h-QmH;+B0AAnv4Ihvxy%JgF@Z?(xtI!HA6;x)5SQI1 z9>}_^cNUi=!!fl$U=`|06tCjMPLgwZ%W{*s)r|{8F0#2z+NFxNEsie13yKF@R2`Fl z?@`~~2ZS<~8FOS#!4z*r4N-YnIXEeFo!`l1XFcAKHBmK%x=E8pbt@nBt`UrIVO)*B)M%b~cQH0U#hW145T`C8Z zLTl`jB~LsIG2dtVAX6_=iiev?1Z6hGk_Dx=6DIn{fvO{$;?h#ElIo8QTF{ydG+u_1 zeL&j4!#XlV?nUByXZA4v`sljj=dhI4ka6_-^oJ}Z0N6go-jHfep713SDq!juCV5vMc(4|eQdu%A>#pFQ9iggGQt zQ`H$#5++uNuw zDZyaoN)w=HV!?_r-x9OpFC>mI7}p2MR*HQyob|ju+p;6i(%{l&Q}C>yrEX5<$dc7Y zqapncvAXeDtlj=Q1*pV-Tm0{~O2wKh+`H(21(}%WsO`Ki`Cw?nP@izx9>3NrlQs(% z5`{3SAYry$E#fz3WT<#q2Ro<4qpZbdPmPpGqdcW`d*?d3;LCXWQuX<6Kn=br1jkQA zXm)ydSB!}0oH#G)&V85idRZMI|DT;zt(0SkhQ_9H>=1MSW<9Pzsdh2pn?ynuAs#42 zFV~1@Q0TlUKBAf#eLN`r_I}!CAjCqA!I$-*h94HP55ISroWRZ7BhhW#X7_=9OGc%yysCY<(WWp&SO3c$s2F#Pk4;%s*U?++$&Tj_~N6k6)yfs--5eg{%aB{wQx zEKn~mY25o8K>|4;i4{O-_C1=tM=9(imk1#1%IE%N)pwjGSWxosl=kOyl_fDq%|3T3 zzEt3dEa4*{uagi>s9@x{9SMC)21mkyXI3l)O!A z5L~2g@2(et_H~IkO^jcgctM&{d?G^uLQjlj=7*`X)3Z>i=EiqsFj=}uMAbWUzZXYG zFm7FQA9qh>A|m{jeC^nM^37y_nY`BMbYELrNeROarFWSAEeqEzv8dQ6t!n6cQmGhv zyHrWauguo>bj+Q+%@RO<+su^(^RM{Lt#?L{$eb)L$m<0}N{FA}Ad-1*!|}DXK`uLh zZN~KSHK)2Oxez{C%?~g%Z!1{1+O%gP7`)biV?1|!gV+Qcxj3iX*kmOsb%^*k_Bgq$ z!fXAVVSyxg$Ps`2`NwE9PFt>8MH4Wf=3&P^@7guoB6YIB41)OoyKOnhVzlnr{Aheq2w>2YqobbQSaU;yCbt_+ z3!SlMi~Zp=ZFE%XfVui{qHq&ZeJi1G3cF=Q@S+ax?0Kvu**6Pmrok7*r{X7X&oK^I z=d0t!!nEMm75$;ttuTzn&ca9B6=fL_%=KGPo{P(uwffC;+k}x!HM+45&g~G2)1l+I z;qD%5-Pwbm4x=K~yrwY+2R??`XJ&0rXJpdi$yuQ_bI#0p=(-<^J1>{{q@g+}b_U+& zZwZY6<|HDPHWo+v_3E4_6ww;IhIsQfEiaWUay!=Exv}BSrP8S!?y_s*ZQlFz29_^3 zi5s4i7{zF{&%>l{CZsGmP{6xv$DQLhCEag2qhOh`S`1N@pwRsHhL$rc=F#B)Uf%XA%Zp@{p`iGXAw1#{UB?_?y*ODAlbY6I(I9FP^2 z0>!_TTLLlw*i1Gw@-Tf(fSHdCa=N^am5HX!$gsKBl9kB$5~8s$ZZa9_DWHDcvVA^@ zH&s}g5>FQ`8u2OropJqEUKK8A)-kUR!kOU2WUar~vvE~R2B-Jf|MXkwR3k-WOIV`Y zc|}A5{=j#EY}Z=M3tEK_tb|AbI1(0^Ty>u57jB@X@(SXJv^d>?j3m-e8#ohyj@xu4n3*oC({+k~sw`eDV-y z=pZq+kq^3>nhh4Yg!p1a%^(nizMQ1EW^{gt+_WEwJSRzXYB?+AYy0_Ke|ze9Ik|I7 zPA1N9()a+bozg&_tkwBRp~Hnw(+crylhj#2bQEV@J)W~In-qMm+EMIf}@`F);-i<8d^R|Pf_spMzI<{4$Bg#LFJ>B`;WY@5% z7w}6k_V_CwHNpijv$IP2Hok9o*|ryh3KSp5^m2KO@}|m4WZ2lMG8)vW=5-`Bsi>o>Ul{_58g&*M=m7;-3I ztej}O)|)HDukoO}26FgztIp8l=$r5*OK(E;E0m$1&!8A=wQ<;i;n+jk&O- zXJufp?#Y>ShJW{URASt6_?$PV`#4q)uvKr$m=#k_5wuX24#1-at@%S9C7E|jgxMD< z!0kP++M0Y9vZJGlZRwYMWvI0M=o^Ux{Z}7fyt_EGDMPe(xnX{fnYjLZhwhQ>sxZW( zyTzH&j)6G(^subPas68y$-5gQ^1L zq%q=^;rSswUa5=P5;2j6-j+JI{$AhkkDng^l^hmQRad72jqDNV=PCPrdJ+<~lWo9< zjduUxidSop74r{h&`w5GfO?K&lwQ4g+Ak8JK5+Q@JLN5=cD!rHpKl9JaEqub27Hb< zo;t%?D-x?V?T401R=ASTdka@9?uUX^#*+7!{NVdwu+poOMiRct{K07o@}8 zT3b}fj3{lfxs_pDKQ(!NaFJ?csRYOyLOg2W=lo3mR`|!cpbEbln)eX{%%5}UVtYHX?iUaZ) z(nD8CzF{({qa&A8Bth`8I~1+CwUGFe3xUjaNys74eE`8l0{VGXc6|ovGrsCHu72TA zKrB+SYUv2W4uOX#F0#ArV=7U+%}{vJx*N_Jzb&JC;q3LY;K zi`a0NN5l;{9`qc7%X&{`v;2d5Mq*|RPRDiQ-rqfI1FG3ruLK(p9LXJq`s;)oqFQ4! zu9YZ6fbT_4TT(v&m(5}&R*`dA@$a8}ZzexG7fd*l*!Sj3d3@gvAWj;e)uvqdEbI~D zn86DvFEWqqy&*(*LEF8Gm-egY;8LWe;Tr^N6Wp2ZcX`HzK2;e|r2F&kA1w~R)&J4r z*gw%|xciKWGOpnI{yiTLOX+9!ygJ~}cf8_|XBz$U-pQ8lkRRWGV>&BiHUmgCP*q}V zr#hH2Dzcu4WlvcEXL9%)_cFc%wu(p- zADGGqA^nDpPIXIAzlGTi%`n8MGhXtt@{qi2?UtYEdb!`O>!S zh)$qlcp_IV583*+uBReR4~=H%`q&s5a&<&~U2*aK1V~nFIKfS!L`02E{dE^)>NLo`SG_Y{{xX(}TpxI3oOZVY!r-`wIdcXf$e1y!&b( zgF8W@*J4!hB~Z=XT45u=gLTlk)t2@bvF6Cku_|5FG&P>FtEYP8t{(vjGmFjKfhU4X z5}pQ$kyd)C-fA0D^P+2w?tRDVz5!+zH@hr5UAn-N?&y~r1T{dieEq9kBn%y7^0W>} z+RsbnwcUO{!GLc+OnPQnqW7agX~8KFF67-3u_mku0a;Qt9-v=ja#`<92S!Fm8L`m| zKp2eKt`|fch@zt$5PO@)*-y?&=L!bBr&&v{ll@N|&0oLHXwf-n!52jyh3|&EXt745 zY?V0yvqQ+JEV(2lIKslG3t+5pXs4+*4Y?F5$-{xJO7?;HE;=QQ_FChIY!{(baz7yK0ubqbNc=*jm0=KIiti5`RcY$xE z@k?~lp;*Me9z=L-O9Fs=NExo5$ZHzXr0)P&@ZN@uaXsvr9{4=jJK`r-DfDQWzas53 zeBNkMF>nPr;<+{QxN10<>xAppGiTU=#n2K*qkuOfZ>xlVUOSYOl3DdQ$Ne!GYn3mc zss;~#&w-t5!E-G&uf6tz-2Ck*+jknvu3g;`Zful4LHAD*I1i5w3#DoD<`BET0MfGw zrC1v7S5#Q;aOUE4mh0=^&Ag)}DI!k)22ySA$F zRb=N|23*`E9i5nU@Hf)!G||+3JY9L(VhHlxt}T!$%@Aj7XPf^(=AMCQ?J@+~ti+!w zXKWy+#A?)x`3~yZPNorce7{90=D;gI&e6|&ZT(=(o-QwF7xyki;~8t|)cb9`^tqdh zreLi7S&at=o0!L)nCri>_0^)I@&&{7uIn!NC+7CDa)MW7CN>65)yHB94u?CrkGHCn zL!uXpLO9#L2y93gnmC8pixeW>{JwQ9?y?>n^@de>2RXF~5w&b8C()r%(2AqKA8|iA z^heGQ6}JH~j!q7CmMJ^7ohMC!evs_e$BBA#<-~N0Kg}}DETK~?hbpSJ-mf5eQ?Nod zq%M4G75D(7n-VD$vD(j)PGLSc+ja(is%Zvnh}Bfz#Y_ZU+|Aq>sSihdI7uf>O4`Us zb0huMFz_w%Yn!@}oN?J)19W_xxzfymxY`5qg)BS6S6p?sk)Op6I3_O`Cs#pfV{c$q zXbxEMI>eGiXli7_HWp)}Ei@;G@@OB2=zB3T(`1T#HMk4?5m3iZmwRQs@zaiT-EVfw zS`2q>H}_W=a6zLFj37_@SJ&euy7LPVCKeU_QHGBXTj;`>MWYtuOnCO&ui1VHIRP2; z%Uxp*`8=MXqY(E@Zr)FWnb6W}L=CLu%5a&V{-=ApbxRl?oaA5KJybmwmX#Psywn88 zzsT)LQPVA&C|s)2b#8^Xu!o;!n(jF*B5?;pIGmWYijF(?ArbYe z39M<>>i}D^~0uXNC4Yoaq%R`wbt~~p_3OZ#4yX#t5b8w)Qx^{au}*`qRqWc<8K127Hm1r0!Iz? zLmKt7myyZo-K@7B8M=4Jmf29}9hRxU$au2dzclz_dOqga{nWW8emA3%@vdU^%%p)B zIr39y=>eOgfXuB%z2bq=l6GiTI$-gBDkb}`_T7tpPn~SNCxg;4ZM|!P?VaxP>Ztf@ z14aFlgPx?0e$?ZABM;xEBV1mAwUrMo(ssP#a(_9R9Jkm)zRA18AMNvVmR^%+rTGIV z5CA7XT7zYtaalPo@&VBA!{F?s$%bB@<@E>)4Vh+Q2z2~0VZ$mQD?xSN0Q)Lq5(5}= z)XHC<3c7fg(oBMi{mN+9ZO&bWiXVu9o5zOG;KTSWr*+Re>L8CNM%bCpO}KtWKS%7i!h{av+%Gdn)*%} z_KQQF+9KSEEOiFZ6KLa^>VoZmD><-Ttc{xLh z>+tI%(JA5q$i<-J6!8b2SL}YSZ;CXs`)XYf);N+DA8iBTnS!)COKh;=_kCK?2YB)PMUJeSkp&2M7WV3CT7 zf5mS+a7)wF~^`QROHSv2m>Ow{l6ObJQbc2 zW8)UW^(eunIurUVxL_S~Y8vG#qx2Kay(2|-MNVRPQ`X}uKiEEAuhwEdU0M<{DeapU zgM)k-rB@x&osiOypGUkoK2d0!($U1iVF@YMsX`TEr|G)d}L2vyg1Z;i-W>aQA8tRFC zl|R2HO78noE0G*yOy$t(nnW^U$?un3mOY^rjrC&Lu2|SD1Vh&uwX&hdIPzz@jrCmw zl1g(w=+w37`T&X$I^hkP{N|vB(A&A$czPEhQmV|ZKP}z0La&(P=N%Nu7OSG zua6q?!#rq=eN@Bnr7LcU4M0Bw1cmml@#1b-&9saHK{p?lvH*O^F(}l-U(j;8@^3%1 zUpnaZ1AEVxdD-$O4x=t01mXM`1#$q6{)HIfD~v^s9AD46(zO>Hdx^+&9L+O4A(%hg zITre0Hodo*Ex8+DSAnc#QAc9FgsguS@)*p~z})eqDQBQBrakgF;=0$u-SnH73Nh zZwh=%YQhVF#!LBXn|-ufZ2$_h4as*tt782*G-<0(&l&%L+V#9jiU%H5+V|4c3IgBW z*|10?(}^$|v=oSI2K(NSulqm1d(%>$W$!!TK<))sx#AKh4@Q}^I6TMComkb~^W7JU z9G-D)$~4e1Sd5Z`$173aqV>%-qzFU z%L%YA?XBHv_6DTNejA02fpiquPl&da{h1i;&J1fCFB*K-v6l2vhkKnHa_QEm|6T@o z9wlf9h2ypMA_8|(-mv-j5ILb^srC7Nc+la`?F$NmZtAHJxky(b!YPF0o|;l}3HE!D zS!<`(M97^kBpb`r;c1JLQP(cEkp>sUZF+{`Nv&hg)!Nd_>ECua{<<6icyC`<8~`GV z?(+aKhD}HFX$)TnTij>CV<>Pd04xNX6=gUr0A_3#^x^ql!iZFT>71A0*zYDpy8fbD zuclw%QXbuj-EoorGxyi4@{}ECn`#J?h5DcBy^Z##jun^C=e)LJ3l*5w3ZHXxF}H{X z=gRyV+)`^i6N@qZQ3Nz8lB&bgU5+7nA71@!m{GA}QC-mfPaT~p>x^S&9&#B|lmj06 zA#6M0WmwX+zPx?ww`;;EU+okbBixcXNx%P;pK?JZ0&W7R8SWYvcklaJdypY{4BM3) z+^p@gsUDL2lmXXd{MMqk?5d$fGdAR4^_tR>xU$ z%7F8-%%aKX+%dI!58%usmn_FECT>+?%UKm|er@yDTJW4XC?_)hT?zFpJ8g04U|)uG zG6Vkm;=aY40>pAJdYm%z05C{4qLGa)KxP);z!Iy76=X4s>@{jM(nhANFfW(tHlqNS z<(2_`|8%ew+YFjL|0(nyh4prA2~A>>S{sG($zj-52z=DBHqr0`m7E3CNT7S+yb=8a z^yo&;s?>bdDr0iJA21dO2=-S(Uc5-7TRF-aqXOGcXCU=@nv(cAnkR(DooJaCj-FSdJF=iG}VJm7nJP|r6FW)L=uQN)DJKBtn%hb!UKxgd%3fo+&vqDU9BG`2qP zjCh;YZpiidwFvwewAl0gh2F+q7wq}KOFYJ`3XC?zHL(EA*GE518;s2 z1!)L_R0Ey^di9bJxio*8@cy8=+R&z_8*HB^F|MYG*PL=#!u^lJ5a*V>Okd#Sgvo7d zSfl8!PNPAs;SDS-FgYS30?eFRz+m;cc|sM9qxUzQZ=@ul$PDB4hR^c{+`PUl%;UrS z(7?6Xl=~Vn0z%F(u$eoZGwk()u{N7|O{Fo$>N`1;mlK~vt^HYM+&4wggC8vugT+Y2 zG6O`1uIq*CeTSFwWd18SL>no7En%|5jQ~CrlDa;YHvHWpj9hL<*o(qrg&UABR(Yqt zHDWUy|L6r0y!90M$#Aij-^<;VYE>i4+jM8Wdcg5_`9AWY7DXZ?pq3 z-%f2|4m7Oio&_@Q>WrLM`)gN$1?#Qt*JjPQb zBGQQbBqcd8gp%Xn`E;kn9?kX{88`b%Y%tdNm%N}Fl{uVEDq*U#N5!^jvzV^+)0)AI zy{yTDD&|g7w&_>9L5!OgC8RX7Sj806(BU~}jT+=RaHNA>+|IqLB`to7^(%7(f;ALH zMT*A-GyQSHDHi{>fG?N(w{`vIE-SMUZjy1KJyF_2!L4_ysuel}2B73tis{C`9qpMT zvyguKwQJKKRw-L2;PzG>P?C5w<~#qj5(teIzXD>gM~jQ?o%FnHlZERq?T?Su_<_-g zPV`4Qy0QLD-!zV6yuQj<6mbG<#o-#`#q^+9!)$qhiu_n{PH!iDM;qY4$STW&gJ&Y<9=<{EmoWErYnt$A2=iV`_6F3y_Q;oU5$Czm&?H~ zcjH1>&R%gZILgFQh2WSvwJ}3u7I(3a>(t}AAs&oB9ZM3uAd4Iaj*52YW$ph3R*pKe z^X;=T%er&YfdhvC~?ir2oHiQ|qewxYjEQfh(Rmcrx z;^^;Z&VZJ3JzoF3Y(634_AZW0;$?P+m!nr~h+J@B?5EDaz8`?T*s-L{h^fCAdq6`5 zC1QQDa^CoC-qw*XpxbK}>ZpIY9T>M`Lx$61OQ8>6*q*jnvY8fBU0MPMnZI*0iu-)U z|G*iLN}xCzclQ6dyE(`1IIqfWFsTn5i+nRCljkT4_DdE%fIv>}``8`$8b$b#av|d@&!Kj>Y{pqrbHo@F4gN zTW|7?4LQZh7Hu#Nd|ATd@aN|lk5xViG z2Wmg4Tc9)#k%s#&Ky^mbzrW=R^Z98l@!D(sizq5C{zXKPDnm}T+dbr4kqGvs{(w@NV_#N3)NYY4k~8Pc#00unru@%SS~MB}iGd`(pjwtnc2rxu24w6I zEer2;7dj!}{Fdh9iV9pnXz%pVrF@R>6(LXpe+SnGB@*GTE}1jiF0FgO6bG7=_q_$o^vYQXc$%MBe?}7z^koiqZgJjhTU;=9@qe@t z2e!=uK#|3tizWB}`c!|u)|B%TFlYa1Ta3zn;Qjqlf)J+vDjyR=1-`%E2^__TiYTZ~ zm;XWPfO-76I!y2V?^RJl{J&ZKp8@}Gt= IrAfg52Q1za-v9sr diff --git a/PyTorch/dev/cv/image_classification/ResNet152_ID0424_for_PyTorch/main_8p.py b/PyTorch/dev/cv/image_classification/ResNet152_ID0424_for_PyTorch/main_8p.py index c62e6ae659..1790b4a24d 100644 --- a/PyTorch/dev/cv/image_classification/ResNet152_ID0424_for_PyTorch/main_8p.py +++ b/PyTorch/dev/cv/image_classification/ResNet152_ID0424_for_PyTorch/main_8p.py @@ -1,478 +1,478 @@ -import argparse -import os -import random -import shutil -import time -import warnings -from enum import Enum - -import torch -import torch.nn as nn -import torch.nn.parallel -import torch.backends.cudnn as cudnn -import torch.distributed as dist -import torch.optim -import torch.multiprocessing as mp -import torch.utils.data -import torch.utils.data.distributed -import torchvision.transforms as transforms -import torchvision.datasets as datasets -import torchvision.models as models -import torch.npu -import os -from apex import amp - - -NPU_CALCULATE_DEVICE = 0 -if os.getenv('NPU_CALCULATE_DEVICE') and str.isdigit(os.getenv('NPU_CALCULATE_DEVICE')): - NPU_CALCULATE_DEVICE = int(os.getenv('NPU_CALCULATE_DEVICE')) -if torch.npu.current_device() != NPU_CALCULATE_DEVICE: - torch.npu.set_device(f'npu:{NPU_CALCULATE_DEVICE}') -NPU_WORLD_SIZE = int(os.getenv('NPU_WORLD_SIZE')) -RANK = int(os.getenv('RANK')) -torch.distributed.init_process_group('hccl', rank=RANK, world_size=NPU_WORLD_SIZE) - -model_names = sorted(name for name in models.__dict__ - if name.islower() and not name.startswith("__") - and callable(models.__dict__[name])) - -parser = argparse.ArgumentParser(description='PyTorch ImageNet Training') -parser.add_argument('data', metavar='DIR', - help='path to dataset') -parser.add_argument('-a', '--arch', metavar='ARCH', default='resnet18', - choices=model_names, - help='model architecture: ' + - ' | '.join(model_names) + - ' (default: resnet18)') -parser.add_argument('-j', '--workers', default=4, type=int, metavar='N', - help='number of data loading workers (default: 4)') -parser.add_argument('--epochs', default=90, type=int, metavar='N', - help='number of total epochs to run') -parser.add_argument('--start-epoch', default=0, type=int, metavar='N', - help='manual epoch number (useful on restarts)') -parser.add_argument('-b', '--batch-size', default=256, type=int, - metavar='N', - help='mini-batch size (default: 256), this is the total ' - 'batch size of all GPUs on the current node when ' - 'using Data Parallel or Distributed Data Parallel') -parser.add_argument('--lr', '--learning-rate', default=0.1, type=float, - metavar='LR', help='initial learning rate', dest='lr') -parser.add_argument('--momentum', default=0.9, type=float, metavar='M', - help='momentum') -parser.add_argument('--wd', '--weight-decay', default=1e-4, type=float, - metavar='W', help='weight decay (default: 1e-4)', - dest='weight_decay') -parser.add_argument('-p', '--print-freq', default=10, type=int, - metavar='N', help='print frequency (default: 10)') -parser.add_argument('--resume', default='', type=str, metavar='PATH', - help='path to latest checkpoint (default: none)') -parser.add_argument('-e', '--evaluate', dest='evaluate', action='store_true', - help='evaluate model on validation set') -parser.add_argument('--pretrained', dest='pretrained', action='store_true', - help='use pre-trained model') -parser.add_argument('--world-size', default=-1, type=int, - help='number of nodes for distributed training') -parser.add_argument('--rank', default=-1, type=int, - help='node rank for distributed training') -parser.add_argument('--dist-url', default='', type=str, - help='url used to set up distributed training') -parser.add_argument('--dist-backend', default='hccl', type=str, - help='distributed backend') -parser.add_argument('--seed', default=None, type=int, - help='seed for initializing training. ') -parser.add_argument('--gpu', default=None, type=int, - help='GPU id to use.') -parser.add_argument('--multiprocessing-distributed', action='store_true', - help='Use multi-processing distributed training to launch ' - 'N processes per node, which has N GPUs. This is the ' - 'fastest way to use PyTorch for either single node or ' - 'multi node data parallel training') -## for ascend 910 - -parser.add_argument('--amp', default=False, action='store_true', - help='use amp to train the model') -parser.add_argument('--loss-scale', default=1024., type=float, - help='loss scale using in amp, default -1 means dynamic') -parser.add_argument('--opt-level', default='O2', type=str, - help='loss scale using in amp, default -1 means dynamic') -parser.add_argument('--FusedSGD', default=False, action='store_true', - help='use FusedSGD') -parser.add_argument('--stop-step-num', default=None, type=int, - help='after the stop-step, killing the training task') - -best_acc1 = 0 - - -def main(): - global best_acc1 - args = parser.parse_args() - - if args.seed is not None: - random.seed(args.seed) - torch.manual_seed(args.seed) - cudnn.deterministic = True - warnings.warn('You have chosen to seed training. ' - 'This will turn on the CUDNN deterministic setting, ' - 'which can slow down your training considerably! ' - 'You may see unexpected behavior when restarting ' - 'from checkpoints.') - - if args.gpu is not None: - warnings.warn('You have chosen a specific GPU. This will completely ' - 'disable data parallelism.') - - - - - - - - - # create model - if args.pretrained: - print("=> using pre-trained model '{}'".format(args.arch)) - model = models.__dict__[args.arch](pretrained=True) - model = model.to(f'npu:{NPU_CALCULATE_DEVICE}') - #if not isinstance(model, torch.nn.parallel.DistributedDataParallel): - #model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[NPU_CALCULATE_DEVICE], broadcast_buffers=False) - else: - print("=> creating model '{}'".format(args.arch)) - model = models.__dict__[args.arch]() - model = model.to(f'npu:{NPU_CALCULATE_DEVICE}') - #if not isinstance(model, torch.nn.parallel.DistributedDataParallel): - #model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[NPU_CALCULATE_DEVICE], broadcast_buffers=False) - - if not torch.npu.is_available(): - print('using CPU, this will be slow') - - - elif args.gpu is not None: - torch.npu.set_device(f'npu:{NPU_CALCULATE_DEVICE}') - model = model.npu(f'npu:{NPU_CALCULATE_DEVICE}') - model = model.to(f'npu:{NPU_CALCULATE_DEVICE}') - #if not isinstance(model, torch.nn.parallel.DistributedDataParallel): - #model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[NPU_CALCULATE_DEVICE], broadcast_buffers=False) - else: - # DataParallel will divide and allocate batch_size to all available GPUs - if args.arch.startswith('alexnet') or args.arch.startswith('vgg'): - model.features = torch.nn.DataParallel(model.features) - model.npu() - - - # define loss function (criterion) and optimizer - if args.FusedSGD: - from apex.optimizers import NpuFusedSGD - optimizer = NpuFusedSGD(model.parameters(), args.lr, - momentum=args.momentum, - weight_decay=args.weight_decay) - - else: - optimizer = torch.optim.SGD(model.parameters(), args.lr, - momentum=args.momentum, - weight_decay=args.weight_decay) - - if args.amp: - model, optimizer = amp.initialize( - model, optimizer, opt_level=args.opt_level, loss_scale=args.loss_scale,combine_grad=True) - if not isinstance(model, torch.nn.parallel.DistributedDataParallel): - model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[NPU_CALCULATE_DEVICE], broadcast_buffers=False) - # optionally resume from a checkpoint - loc = 'npu:{}'.format(NPU_CALCULATE_DEVICE) - criterion = nn.CrossEntropyLoss().to(loc) - if args.resume: - if os.path.isfile(args.resume): - print("=> loading checkpoint '{}'".format(args.resume)) - if args.gpu is None: - checkpoint = torch.load(args.resume) - else: - # Map model to be loaded to specified single gpu. - loc = 'npu:{}'.format(args.gpu) - checkpoint = torch.load(args.resume, map_location=f'npu:{NPU_CALCULATE_DEVICE}') - args.start_epoch = checkpoint['epoch'] - best_acc1 = checkpoint['best_acc1'] - if args.gpu is not None: - # best_acc1 may be from a checkpoint from a different GPU - best_acc1 = best_acc1.to(f'npu:{NPU_CALCULATE_DEVICE}') - model.load_state_dict(checkpoint['state_dict']) - optimizer.load_state_dict(checkpoint['optimizer']) - if args.amp: - amp.load_state_dict(checkpoint['amp']) - print("=> loaded checkpoint '{}' (epoch {})" - .format(args.resume, checkpoint['epoch'])) - else: - print("=> no checkpoint found at '{}'".format(args.resume)) - - cudnn.benchmark = True - - # Data loading code - traindir = os.path.join(args.data, 'train') - valdir = os.path.join(args.data, 'val') - normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], - std=[0.229, 0.224, 0.225]) - - train_dataset = datasets.ImageFolder( - traindir, - transforms.Compose([ - transforms.RandomResizedCrop(224), - transforms.RandomHorizontalFlip(), - transforms.ToTensor(), - normalize, - ])) - - - #train_sampler = None - train_loader_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset) - train_loader_batch_size = args.batch_size - - train_loader = torch.utils.data.DataLoader( - train_dataset, batch_size=train_loader_batch_size, shuffle=False, - num_workers=args.workers, pin_memory=True, sampler=train_loader_sampler, drop_last = True) - - val_loader = torch.utils.data.DataLoader( - datasets.ImageFolder(valdir, transforms.Compose([ - transforms.Resize(256), - transforms.CenterCrop(224), - transforms.ToTensor(), - normalize, - ])), - batch_size=args.batch_size, shuffle=True, - num_workers=args.workers, pin_memory=False, drop_last=True) - - if args.evaluate: - validate(val_loader, model, criterion, args) - return - - for epoch in range(args.start_epoch, args.epochs): - train_loader.sampler.set_epoch(epoch) - - - adjust_learning_rate(optimizer, epoch, args) - - # train for one epoch - train(train_loader, model, criterion, optimizer, epoch, args) - - # evaluate on validation set - acc1 = validate(val_loader, model, criterion, args) - - # remember best acc@1 and save checkpoint - is_best = acc1 > best_acc1 - best_acc1 = max(acc1, best_acc1) - - if not args.multiprocessing_distributed or (args.multiprocessing_distributed - and args.rank % ngpus_per_node == 0): - if args.amp: - save_checkpoint({ - 'epoch': epoch + 1, - 'arch': args.arch, - 'state_dict': model.state_dict(), - 'best_acc1': best_acc1, - 'optimizer': optimizer.state_dict(), - 'amp': amp.state_dict(), - }, is_best) - else: - save_checkpoint({ - 'epoch': epoch + 1, - 'arch': args.arch, - 'state_dict': model.state_dict(), - 'best_acc1': best_acc1, - 'optimizer': optimizer.state_dict(), - }, is_best) - - -def train(train_loader, model, criterion, optimizer, epoch, args): - batch_time = AverageMeter('Time', ':6.3f') - data_time = AverageMeter('Data', ':6.3f') - losses = AverageMeter('Loss', ':.4e') - top1 = AverageMeter('Acc@1', ':6.2f') - top5 = AverageMeter('Acc@5', ':6.2f') - progress = ProgressMeter( - len(train_loader), - [batch_time, data_time, losses, top1, top5], - prefix="Epoch: [{}]".format(epoch)) - - # switch to train mode - model.train() - - end = time.time() - for i, (images, target) in enumerate(train_loader): - # measure data loading time - data_time.update(time.time() - end) - - if args.gpu is not None: - images = images.npu(f'npu:{NPU_CALCULATE_DEVICE}', non_blocking=True) - if torch.npu.is_available(): - target = target.npu(f'npu:{NPU_CALCULATE_DEVICE}', non_blocking=True) - - # compute output - output = model(images) - loss = criterion(output, target) - - # measure accuracy and record loss - acc1, acc5 = accuracy(output, target, topk=(1, 5)) - losses.update(loss.item(), images.size(0)) - top1.update(acc1[0], images.size(0)) - top5.update(acc5[0], images.size(0)) - - # compute gradient and do SGD step - optimizer.zero_grad() - if args.amp: - with amp.scale_loss(loss, optimizer) as scaled_loss: - scaled_loss.backward() - else: - loss.backward() - optimizer.step() - - # measure elapsed time - batch_time.update(time.time() - end) - end = time.time() - - if i % args.print_freq == 0: - progress.display(i) - - -def validate(val_loader, model, criterion, args): - batch_time = AverageMeter('Time', ':6.3f', Summary.NONE) - losses = AverageMeter('Loss', ':.4e', Summary.NONE) - top1 = AverageMeter('Acc@1', ':6.2f', Summary.AVERAGE) - top5 = AverageMeter('Acc@5', ':6.2f', Summary.AVERAGE) - progress = ProgressMeter( - len(val_loader), - [batch_time, losses, top1, top5], - prefix='Test: ') - - # switch to evaluate mode - model.eval() - - with torch.no_grad(): - end = time.time() - for i, (images, target) in enumerate(val_loader): - if args.gpu is not None: - images = images.npu(f'npu:{NPU_CALCULATE_DEVICE}', non_blocking=True) - if torch.npu.is_available(): - target = target.npu(f'npu:{NPU_CALCULATE_DEVICE}', non_blocking=True) - - # compute output - output = model(images) - loss = criterion(output, target) - - # measure accuracy and record loss - acc1, acc5 = accuracy(output, target, topk=(1, 5)) - losses.update(loss.item(), images.size(0)) - top1.update(acc1[0], images.size(0)) - top5.update(acc5[0], images.size(0)) - - # measure elapsed time - batch_time.update(time.time() - end) - end = time.time() - - if i % args.print_freq == 0: - progress.display(i) - - progress.display_summary() - - return top1.avg - - -def save_checkpoint(state, is_best, filename='checkpoint.pth.tar'): - torch.save(state, filename) - if is_best: - shutil.copyfile(filename, 'model_best.pth.tar') - - -class Summary(Enum): - NONE = 0 - AVERAGE = 1 - SUM = 2 - COUNT = 3 - - -class AverageMeter(object): - """Computes and stores the average and current value""" - - def __init__(self, name, fmt=':f', summary_type=Summary.AVERAGE): - self.name = name - self.fmt = fmt - self.summary_type = summary_type - self.reset() - - def reset(self): - self.val = 0 - self.avg = 0 - self.sum = 0 - self.count = 0 - - def update(self, val, n=1): - self.val = val - self.sum += val * n - self.count += n - self.avg = self.sum / self.count - - def __str__(self): - fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' - return fmtstr.format(**self.__dict__) - - def summary(self): - fmtstr = '' - if self.summary_type is Summary.NONE: - fmtstr = '' - elif self.summary_type is Summary.AVERAGE: - fmtstr = '{name} {avg:.3f}' - elif self.summary_type is Summary.SUM: - fmtstr = '{name} {sum:.3f}' - elif self.summary_type is Summary.COUNT: - fmtstr = '{name} {count:.3f}' - else: - raise ValueError('invalid summary type %r' % self.summary_type) - - return fmtstr.format(**self.__dict__) - - -class ProgressMeter(object): - def __init__(self, num_batches, meters, prefix=""): - self.batch_fmtstr = self._get_batch_fmtstr(num_batches) - self.meters = meters - self.prefix = prefix - - def display(self, batch): - entries = [self.prefix + self.batch_fmtstr.format(batch)] - entries += [str(meter) for meter in self.meters] - print('\t'.join(entries)) - - def display_summary(self): - entries = [" *"] - entries += [meter.summary() for meter in self.meters] - print(' '.join(entries)) - - def _get_batch_fmtstr(self, num_batches): - num_digits = len(str(num_batches // 1)) - fmt = '{:' + str(num_digits) + 'd}' - return '[' + fmt + '/' + fmt.format(num_batches) + ']' - - -def adjust_learning_rate(optimizer, epoch, args): - """Sets the learning rate to the initial LR decayed by 10 every 30 epochs""" - lr = args.lr * (0.1 ** (epoch // 30)) - for param_group in optimizer.param_groups: - param_group['lr'] = lr - - -def accuracy(output, target, topk=(1,)): - """Computes the accuracy over the k top predictions for the specified values of k""" - with torch.no_grad(): - maxk = max(topk) - batch_size = target.size(0) - - _, pred = output.topk(maxk, 1, True, True) - pred = pred.t() - correct = pred.eq(target.view(1, -1).expand_as(pred)) - - res = [] - for k in topk: - correct_k = correct[:k].reshape(-1).float().sum(0, keepdim=True) - res.append(correct_k.mul_(100.0 / batch_size)) - return res - - -if __name__ == '__main__': - main() - +import argparse +import os +import random +import shutil +import time +import warnings +from enum import Enum + +import torch +import torch.nn as nn +import torch.nn.parallel +import torch.backends.cudnn as cudnn +import torch.distributed as dist +import torch.optim +import torch.multiprocessing as mp +import torch.utils.data +import torch.utils.data.distributed +import torchvision.transforms as transforms +import torchvision.datasets as datasets +import torchvision.models as models +import torch.npu +import os +from apex import amp + + +NPU_CALCULATE_DEVICE = 0 +if os.getenv('NPU_CALCULATE_DEVICE') and str.isdigit(os.getenv('NPU_CALCULATE_DEVICE')): + NPU_CALCULATE_DEVICE = int(os.getenv('NPU_CALCULATE_DEVICE')) +if torch.npu.current_device() != NPU_CALCULATE_DEVICE: + torch.npu.set_device(f'npu:{NPU_CALCULATE_DEVICE}') +NPU_WORLD_SIZE = int(os.getenv('NPU_WORLD_SIZE')) +RANK = int(os.getenv('RANK')) +torch.distributed.init_process_group('hccl', rank=RANK, world_size=NPU_WORLD_SIZE) + +model_names = sorted(name for name in models.__dict__ + if name.islower() and not name.startswith("__") + and callable(models.__dict__[name])) + +parser = argparse.ArgumentParser(description='PyTorch ImageNet Training') +parser.add_argument('data', metavar='DIR', + help='path to dataset') +parser.add_argument('-a', '--arch', metavar='ARCH', default='resnet18', + choices=model_names, + help='model architecture: ' + + ' | '.join(model_names) + + ' (default: resnet18)') +parser.add_argument('-j', '--workers', default=4, type=int, metavar='N', + help='number of data loading workers (default: 4)') +parser.add_argument('--epochs', default=90, type=int, metavar='N', + help='number of total epochs to run') +parser.add_argument('--start-epoch', default=0, type=int, metavar='N', + help='manual epoch number (useful on restarts)') +parser.add_argument('-b', '--batch-size', default=256, type=int, + metavar='N', + help='mini-batch size (default: 256), this is the total ' + 'batch size of all GPUs on the current node when ' + 'using Data Parallel or Distributed Data Parallel') +parser.add_argument('--lr', '--learning-rate', default=0.1, type=float, + metavar='LR', help='initial learning rate', dest='lr') +parser.add_argument('--momentum', default=0.9, type=float, metavar='M', + help='momentum') +parser.add_argument('--wd', '--weight-decay', default=1e-4, type=float, + metavar='W', help='weight decay (default: 1e-4)', + dest='weight_decay') +parser.add_argument('-p', '--print-freq', default=10, type=int, + metavar='N', help='print frequency (default: 10)') +parser.add_argument('--resume', default='', type=str, metavar='PATH', + help='path to latest checkpoint (default: none)') +parser.add_argument('-e', '--evaluate', dest='evaluate', action='store_true', + help='evaluate model on validation set') +parser.add_argument('--pretrained', dest='pretrained', action='store_true', + help='use pre-trained model') +parser.add_argument('--world-size', default=-1, type=int, + help='number of nodes for distributed training') +parser.add_argument('--rank', default=-1, type=int, + help='node rank for distributed training') +parser.add_argument('--dist-url', default='', type=str, + help='url used to set up distributed training') +parser.add_argument('--dist-backend', default='hccl', type=str, + help='distributed backend') +parser.add_argument('--seed', default=None, type=int, + help='seed for initializing training. ') +parser.add_argument('--gpu', default=None, type=int, + help='GPU id to use.') +parser.add_argument('--multiprocessing-distributed', action='store_true', + help='Use multi-processing distributed training to launch ' + 'N processes per node, which has N GPUs. This is the ' + 'fastest way to use PyTorch for either single node or ' + 'multi node data parallel training') +## for ascend 910 + +parser.add_argument('--amp', default=False, action='store_true', + help='use amp to train the model') +parser.add_argument('--loss-scale', default=1024., type=float, + help='loss scale using in amp, default -1 means dynamic') +parser.add_argument('--opt-level', default='O2', type=str, + help='loss scale using in amp, default -1 means dynamic') +parser.add_argument('--FusedSGD', default=False, action='store_true', + help='use FusedSGD') +parser.add_argument('--stop-step-num', default=None, type=int, + help='after the stop-step, killing the training task') + +best_acc1 = 0 + + +def main(): + global best_acc1 + args = parser.parse_args() + + if args.seed is not None: + random.seed(args.seed) + torch.manual_seed(args.seed) + cudnn.deterministic = True + warnings.warn('You have chosen to seed training. ' + 'This will turn on the CUDNN deterministic setting, ' + 'which can slow down your training considerably! ' + 'You may see unexpected behavior when restarting ' + 'from checkpoints.') + + if args.gpu is not None: + warnings.warn('You have chosen a specific GPU. This will completely ' + 'disable data parallelism.') + + + + + + + + + # create model + if args.pretrained: + print("=> using pre-trained model '{}'".format(args.arch)) + model = models.__dict__[args.arch](pretrained=True) + model = model.to(f'npu:{NPU_CALCULATE_DEVICE}') + #if not isinstance(model, torch.nn.parallel.DistributedDataParallel): + #model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[NPU_CALCULATE_DEVICE], broadcast_buffers=False) + else: + print("=> creating model '{}'".format(args.arch)) + model = models.__dict__[args.arch]() + model = model.to(f'npu:{NPU_CALCULATE_DEVICE}') + #if not isinstance(model, torch.nn.parallel.DistributedDataParallel): + #model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[NPU_CALCULATE_DEVICE], broadcast_buffers=False) + + if not torch.npu.is_available(): + print('using CPU, this will be slow') + + + elif args.gpu is not None: + torch.npu.set_device(f'npu:{NPU_CALCULATE_DEVICE}') + model = model.npu(f'npu:{NPU_CALCULATE_DEVICE}') + model = model.to(f'npu:{NPU_CALCULATE_DEVICE}') + #if not isinstance(model, torch.nn.parallel.DistributedDataParallel): + #model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[NPU_CALCULATE_DEVICE], broadcast_buffers=False) + else: + # DataParallel will divide and allocate batch_size to all available GPUs + if args.arch.startswith('alexnet') or args.arch.startswith('vgg'): + model.features = torch.nn.DataParallel(model.features) + model.npu() + + + # define loss function (criterion) and optimizer + if args.FusedSGD: + from apex.optimizers import NpuFusedSGD + optimizer = NpuFusedSGD(model.parameters(), args.lr, + momentum=args.momentum, + weight_decay=args.weight_decay) + + else: + optimizer = torch.optim.SGD(model.parameters(), args.lr, + momentum=args.momentum, + weight_decay=args.weight_decay) + + if args.amp: + model, optimizer = amp.initialize( + model, optimizer, opt_level=args.opt_level, loss_scale=args.loss_scale,combine_grad=True) + if not isinstance(model, torch.nn.parallel.DistributedDataParallel): + model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[NPU_CALCULATE_DEVICE], broadcast_buffers=False) + # optionally resume from a checkpoint + loc = 'npu:{}'.format(NPU_CALCULATE_DEVICE) + criterion = nn.CrossEntropyLoss().to(loc) + if args.resume: + if os.path.isfile(args.resume): + print("=> loading checkpoint '{}'".format(args.resume)) + if args.gpu is None: + checkpoint = torch.load(args.resume) + else: + # Map model to be loaded to specified single gpu. + loc = 'npu:{}'.format(args.gpu) + checkpoint = torch.load(args.resume, map_location=f'npu:{NPU_CALCULATE_DEVICE}') + args.start_epoch = checkpoint['epoch'] + best_acc1 = checkpoint['best_acc1'] + if args.gpu is not None: + # best_acc1 may be from a checkpoint from a different GPU + best_acc1 = best_acc1.to(f'npu:{NPU_CALCULATE_DEVICE}') + model.load_state_dict(checkpoint['state_dict']) + optimizer.load_state_dict(checkpoint['optimizer']) + if args.amp: + amp.load_state_dict(checkpoint['amp']) + print("=> loaded checkpoint '{}' (epoch {})" + .format(args.resume, checkpoint['epoch'])) + else: + print("=> no checkpoint found at '{}'".format(args.resume)) + + cudnn.benchmark = True + + # Data loading code + traindir = os.path.join(args.data, 'train') + valdir = os.path.join(args.data, 'val') + normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]) + + train_dataset = datasets.ImageFolder( + traindir, + transforms.Compose([ + transforms.RandomResizedCrop(224), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + normalize, + ])) + + + #train_sampler = None + train_loader_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset) + train_loader_batch_size = args.batch_size + + train_loader = torch.utils.data.DataLoader( + train_dataset, batch_size=train_loader_batch_size, shuffle=False, + num_workers=args.workers, pin_memory=True, sampler=train_loader_sampler, drop_last = True) + + val_loader = torch.utils.data.DataLoader( + datasets.ImageFolder(valdir, transforms.Compose([ + transforms.Resize(256), + transforms.CenterCrop(224), + transforms.ToTensor(), + normalize, + ])), + batch_size=args.batch_size, shuffle=True, + num_workers=args.workers, pin_memory=False, drop_last=True) + + if args.evaluate: + validate(val_loader, model, criterion, args) + return + + for epoch in range(args.start_epoch, args.epochs): + train_loader.sampler.set_epoch(epoch) + + + adjust_learning_rate(optimizer, epoch, args) + + # train for one epoch + train(train_loader, model, criterion, optimizer, epoch, args) + + # evaluate on validation set + acc1 = validate(val_loader, model, criterion, args) + + # remember best acc@1 and save checkpoint + is_best = acc1 > best_acc1 + best_acc1 = max(acc1, best_acc1) + + if not args.multiprocessing_distributed or (args.multiprocessing_distributed + and args.rank % ngpus_per_node == 0): + if args.amp: + save_checkpoint({ + 'epoch': epoch + 1, + 'arch': args.arch, + 'state_dict': model.state_dict(), + 'best_acc1': best_acc1, + 'optimizer': optimizer.state_dict(), + 'amp': amp.state_dict(), + }, is_best) + else: + save_checkpoint({ + 'epoch': epoch + 1, + 'arch': args.arch, + 'state_dict': model.state_dict(), + 'best_acc1': best_acc1, + 'optimizer': optimizer.state_dict(), + }, is_best) + + +def train(train_loader, model, criterion, optimizer, epoch, args): + batch_time = AverageMeter('Time', ':6.3f') + data_time = AverageMeter('Data', ':6.3f') + losses = AverageMeter('Loss', ':.4e') + top1 = AverageMeter('Acc@1', ':6.2f') + top5 = AverageMeter('Acc@5', ':6.2f') + progress = ProgressMeter( + len(train_loader), + [batch_time, data_time, losses, top1, top5], + prefix="Epoch: [{}]".format(epoch)) + + # switch to train mode + model.train() + + end = time.time() + for i, (images, target) in enumerate(train_loader): + # measure data loading time + data_time.update(time.time() - end) + + if args.gpu is not None: + images = images.npu(f'npu:{NPU_CALCULATE_DEVICE}', non_blocking=True) + if torch.npu.is_available(): + target = target.npu(f'npu:{NPU_CALCULATE_DEVICE}', non_blocking=True) + + # compute output + output = model(images) + loss = criterion(output, target) + + # measure accuracy and record loss + acc1, acc5 = accuracy(output, target, topk=(1, 5)) + losses.update(loss.item(), images.size(0)) + top1.update(acc1[0], images.size(0)) + top5.update(acc5[0], images.size(0)) + + # compute gradient and do SGD step + optimizer.zero_grad() + if args.amp: + with amp.scale_loss(loss, optimizer) as scaled_loss: + scaled_loss.backward() + else: + loss.backward() + optimizer.step() + + # measure elapsed time + batch_time.update(time.time() - end) + end = time.time() + + if i % args.print_freq == 0: + progress.display(i) + + +def validate(val_loader, model, criterion, args): + batch_time = AverageMeter('Time', ':6.3f', Summary.NONE) + losses = AverageMeter('Loss', ':.4e', Summary.NONE) + top1 = AverageMeter('Acc@1', ':6.2f', Summary.AVERAGE) + top5 = AverageMeter('Acc@5', ':6.2f', Summary.AVERAGE) + progress = ProgressMeter( + len(val_loader), + [batch_time, losses, top1, top5], + prefix='Test: ') + + # switch to evaluate mode + model.eval() + + with torch.no_grad(): + end = time.time() + for i, (images, target) in enumerate(val_loader): + if args.gpu is not None: + images = images.npu(f'npu:{NPU_CALCULATE_DEVICE}', non_blocking=True) + if torch.npu.is_available(): + target = target.npu(f'npu:{NPU_CALCULATE_DEVICE}', non_blocking=True) + + # compute output + output = model(images) + loss = criterion(output, target) + + # measure accuracy and record loss + acc1, acc5 = accuracy(output, target, topk=(1, 5)) + losses.update(loss.item(), images.size(0)) + top1.update(acc1[0], images.size(0)) + top5.update(acc5[0], images.size(0)) + + # measure elapsed time + batch_time.update(time.time() - end) + end = time.time() + + if i % args.print_freq == 0: + progress.display(i) + + progress.display_summary() + + return top1.avg + + +def save_checkpoint(state, is_best, filename='checkpoint.pth.tar'): + torch.save(state, filename) + if is_best: + shutil.copyfile(filename, 'model_best.pth.tar') + + +class Summary(Enum): + NONE = 0 + AVERAGE = 1 + SUM = 2 + COUNT = 3 + + +class AverageMeter(object): + """Computes and stores the average and current value""" + + def __init__(self, name, fmt=':f', summary_type=Summary.AVERAGE): + self.name = name + self.fmt = fmt + self.summary_type = summary_type + self.reset() + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + + def update(self, val, n=1): + self.val = val + self.sum += val * n + self.count += n + self.avg = self.sum / self.count + + def __str__(self): + fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' + return fmtstr.format(**self.__dict__) + + def summary(self): + fmtstr = '' + if self.summary_type is Summary.NONE: + fmtstr = '' + elif self.summary_type is Summary.AVERAGE: + fmtstr = '{name} {avg:.3f}' + elif self.summary_type is Summary.SUM: + fmtstr = '{name} {sum:.3f}' + elif self.summary_type is Summary.COUNT: + fmtstr = '{name} {count:.3f}' + else: + raise ValueError('invalid summary type %r' % self.summary_type) + + return fmtstr.format(**self.__dict__) + + +class ProgressMeter(object): + def __init__(self, num_batches, meters, prefix=""): + self.batch_fmtstr = self._get_batch_fmtstr(num_batches) + self.meters = meters + self.prefix = prefix + + def display(self, batch): + entries = [self.prefix + self.batch_fmtstr.format(batch)] + entries += [str(meter) for meter in self.meters] + print('\t'.join(entries)) + + def display_summary(self): + entries = [" *"] + entries += [meter.summary() for meter in self.meters] + print(' '.join(entries)) + + def _get_batch_fmtstr(self, num_batches): + num_digits = len(str(num_batches // 1)) + fmt = '{:' + str(num_digits) + 'd}' + return '[' + fmt + '/' + fmt.format(num_batches) + ']' + + +def adjust_learning_rate(optimizer, epoch, args): + """Sets the learning rate to the initial LR decayed by 10 every 30 epochs""" + lr = args.lr * (0.1 ** (epoch // 30)) + for param_group in optimizer.param_groups: + param_group['lr'] = lr + + +def accuracy(output, target, topk=(1,)): + """Computes the accuracy over the k top predictions for the specified values of k""" + with torch.no_grad(): + maxk = max(topk) + batch_size = target.size(0) + + _, pred = output.topk(maxk, 1, True, True) + pred = pred.t() + correct = pred.eq(target.view(1, -1).expand_as(pred)) + + res = [] + for k in topk: + correct_k = correct[:k].reshape(-1).float().sum(0, keepdim=True) + res.append(correct_k.mul_(100.0 / batch_size)) + return res + + +if __name__ == '__main__': + main() + diff --git a/PyTorch/dev/cv/image_classification/ResNet152_ID0424_for_PyTorch/modelzoo_level.txt b/PyTorch/dev/cv/image_classification/ResNet152_ID0424_for_PyTorch/modelzoo_level.txt index 484664c239..55a9add9fa 100644 --- a/PyTorch/dev/cv/image_classification/ResNet152_ID0424_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/dev/cv/image_classification/ResNet152_ID0424_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:POK \ No newline at end of file diff --git a/PyTorch/dev/cv/image_classification/ResNet152_ID0424_for_PyTorch/test/train_full_8pt.sh b/PyTorch/dev/cv/image_classification/ResNet152_ID0424_for_PyTorch/test/train_full_8pt.sh index e73115f70f..5474eb332c 100644 --- a/PyTorch/dev/cv/image_classification/ResNet152_ID0424_for_PyTorch/test/train_full_8pt.sh +++ b/PyTorch/dev/cv/image_classification/ResNet152_ID0424_for_PyTorch/test/train_full_8pt.sh @@ -1,197 +1,197 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -#source env.sh -#集合通信参数,不需要修改 - -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 - - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="ResNet152_ID0424_for_PyTorch" -#训练epoch -train_epochs=110 -#训练batch_size -batch_size=2048 -#训练step -#train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.5 - -#TF2.X独有,需要模型审视修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -#precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_performance_1P.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is False - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#进入训练脚本目录,需要模型审视修改 -cd $cur_path/.. -for((RANK_ID=$RANK_ID_START;RANK_ID<1;RANK_ID++)); -do - #设置环境变量,不需要修改 - echo "Device ID: $ASCEND_DEVICE_ID" - #export RANK_ID=$RANK_ID - #export ASCEND_DEVICE_ID=$RANK_ID - ASCEND_DEVICE_ID=$RANK_ID - - - #创建DeviceID输出目录,不需要修改 - if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - fi - # 绑核,不需要的绑核的模型删除,需要的模型审视修改 - #let a=RANK_ID*12 - #let b=RANK_ID+1 - #let c=b*12-1 - - #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 - #--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path - -done -wait - - - -export MASTER_ADDR=localhost -export MASTER_PORT=29688 -export HCCL_WHITELIST_DISABLE=1 - -NPUS=($(seq 0 7)) -export NPU_WORLD_SIZE=${#NPUS[@]} -rank=0 -for i in ${NPUS[@]} -do - export NPU_CALCULATE_DEVICE=${i} - export RANK=${rank} - echo run process ${rank} - python3 main_8p.py \ - ${data_path} \ - -a resnet152 \ - --seed=49 \ - --learning-rate=0.8 \ - --mom=0.9 \ - --weight-decay=1.0e-04 \ - --print-freq=1 \ - --epochs=1 \ - --batch-size=256 \ - --gpu ${i} \ - --FusedSGD \ - --loss-scale=1024 \ - --amp > $cur_path/output/${ASCEND_DEVICE_ID}/train_${i}.log 2>&1 & - let rank++ -done -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep -a 'FPS' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F " " '{print $NF}'|awk 'END {print}'` -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -train_accuracy=`grep -a '* Acc@1' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` -#打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep Epoch: $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep -v Test|awk -F "Loss" '{print $NF}' | awk -F " " '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +#source env.sh +#集合通信参数,不需要修改 + +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 + + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="ResNet152_ID0424_for_PyTorch" +#训练epoch +train_epochs=110 +#训练batch_size +batch_size=2048 +#训练step +#train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.5 + +#TF2.X独有,需要模型审视修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +#precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_performance_1P.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is False + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#进入训练脚本目录,需要模型审视修改 +cd $cur_path/.. +for((RANK_ID=$RANK_ID_START;RANK_ID<1;RANK_ID++)); +do + #设置环境变量,不需要修改 + echo "Device ID: $ASCEND_DEVICE_ID" + #export RANK_ID=$RANK_ID + #export ASCEND_DEVICE_ID=$RANK_ID + ASCEND_DEVICE_ID=$RANK_ID + + + #创建DeviceID输出目录,不需要修改 + if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + fi + # 绑核,不需要的绑核的模型删除,需要的模型审视修改 + #let a=RANK_ID*12 + #let b=RANK_ID+1 + #let c=b*12-1 + + #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 + #--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path + +done +wait + + + +export MASTER_ADDR=localhost +export MASTER_PORT=29688 +export HCCL_WHITELIST_DISABLE=1 + +NPUS=($(seq 0 7)) +export NPU_WORLD_SIZE=${#NPUS[@]} +rank=0 +for i in ${NPUS[@]} +do + export NPU_CALCULATE_DEVICE=${i} + export RANK=${rank} + echo run process ${rank} + python3 main_8p.py \ + ${data_path} \ + -a resnet152 \ + --seed=49 \ + --learning-rate=0.8 \ + --mom=0.9 \ + --weight-decay=1.0e-04 \ + --print-freq=1 \ + --epochs=1 \ + --batch-size=256 \ + --gpu ${i} \ + --FusedSGD \ + --loss-scale=1024 \ + --amp > $cur_path/output/${ASCEND_DEVICE_ID}/train_${i}.log 2>&1 & + let rank++ +done +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep -a 'FPS' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F " " '{print $NF}'|awk 'END {print}'` +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +train_accuracy=`grep -a '* Acc@1' $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk 'END {print}'|awk -F "Acc@1" '{print $NF}'|awk -F " " '{print $1}'` +#打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep Epoch: $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep -v Test|awk -F "Loss" '{print $NF}' | awk -F " " '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/dev/cv/image_classification/SEResNext_ID0415_for_PyTorch/README_ori.md b/PyTorch/dev/cv/image_classification/SEResNext_ID0415_for_PyTorch/README_ori.md index dc0d40de7e..3847a5f095 100644 --- a/PyTorch/dev/cv/image_classification/SEResNext_ID0415_for_PyTorch/README_ori.md +++ b/PyTorch/dev/cv/image_classification/SEResNext_ID0415_for_PyTorch/README_ori.md @@ -1,118 +1,118 @@ -# Convolutional Networks for Image Classification in PyTorch - -In this repository you will find implementations of various image classification models. - -Detailed information on each model can be found here: - -## Table Of Contents - -* [Models](#models) -* [Validation accuracy results](#validation-accuracy-results) -* [Training performance results](#training-performance-results) - * [Training performance: NVIDIA DGX A100 (8x A100 40GB)](#training-performance-nvidia-dgx-a100-8x-a100-40gb) - * [Training performance: NVIDIA DGX-1 16GB (8x V100 16GB)](#training-performance-nvidia-dgx-1-16gb-8x-v100-16gb) - * [Training performance: NVIDIA DGX-2 (16x V100 32GB)](#training-performance-nvidia-dgx-2-16x-v100-32gb) -* [Model comparison](#model-comparison) - * [Accuracy vs FLOPS](#accuracy-vs-flops) - * [Latency vs Throughput on different batch sizes](#latency-vs-throughput-on-different-batch-sizes) - -## Models - -The following table provides links to where you can find additional information on each model: - -| **Model** | **Link**| -|:-:|:-:| -| resnet50 | [README](./resnet50v1.5/README.md) | -| resnext101-32x4d | [README](./resnext101-32x4d/README.md) | -| se-resnext101-32x4d | [README](./se-resnext101-32x4d/README.md) | - -## Validation accuracy results - -Our results were obtained by running the applicable -training scripts in the [framework-container-name] NGC container -on NVIDIA DGX-1 with (8x V100 16GB) GPUs. -The specific training script that was run is documented -in the corresponding model's README. - - -The following table shows the validation accuracy results of the -three classification models side-by-side. - - -| **arch** | **AMP Top1** | **AMP Top5** | **FP32 Top1** | **FP32 Top5** | -|:-:|:-:|:-:|:-:|:-:| -| resnet50 | 78.46 | 94.15 | 78.50 | 94.11 | -| resnext101-32x4d | 80.08 | 94.89 | 80.14 | 95.02 | -| se-resnext101-32x4d | 81.01 | 95.52 | 81.12 | 95.54 | - - -## Training performance results - -### Training performance: NVIDIA DGX A100 (8x A100 40GB) - - -Our results were obtained by running the applicable -training scripts in the pytorch-20.06 NGC container -on NVIDIA DGX A100 with (8x A100 40GB) GPUs. -Performance numbers (in images per second) -were averaged over an entire training epoch. -The specific training script that was run is documented -in the corresponding model's README. - -The following table shows the training accuracy results of the -three classification models side-by-side. - - -| **arch** | **Mixed Precision** | **TF32** | **Mixed Precision Speedup** | -|:-------------------:|:-------------------:|:-------------:|:---------------------------:| -| resnet50 | 9488.39 img/s | 5322.10 img/s | 1.78x | -| resnext101-32x4d | 6758.98 img/s | 2353.25 img/s | 2.87x | -| se-resnext101-32x4d | 4670.72 img/s | 2011.21 img/s | 2.32x | - -ResNeXt and SE-ResNeXt use [NHWC data layout](https://pytorch.org/tutorials/intermediate/memory_format_tutorial.html) when training using Mixed Precision, -which improves the model performance. We are currently working on adding it for ResNet. - - -### Training performance: NVIDIA DGX-1 16G (8x V100 16GB) - - -Our results were obtained by running the applicable -training scripts in the pytorch-20.06 NGC container -on NVIDIA DGX-1 with (8x V100 16GB) GPUs. -Performance numbers (in images per second) -were averaged over an entire training epoch. -The specific training script that was run is documented -in the corresponding model's README. - -The following table shows the training accuracy results of the -three classification models side-by-side. - - -| **arch** | **Mixed Precision** | **FP32** | **Mixed Precision Speedup** | -|:-------------------:|:-------------------:|:-------------:|:---------------------------:| -| resnet50 | 6565.61 img/s | 2869.19 img/s | 2.29x | -| resnext101-32x4d | 3922.74 img/s | 1136.30 img/s | 3.45x | -| se-resnext101-32x4d | 2651.13 img/s | 982.78 img/s | 2.70x | - -ResNeXt and SE-ResNeXt use [NHWC data layout](https://pytorch.org/tutorials/intermediate/memory_format_tutorial.html) when training using Mixed Precision, -which improves the model performance. We are currently working on adding it for ResNet. - - -## Model Comparison - -### Accuracy vs FLOPS -![ACCvsFLOPS](./img/ACCvsFLOPS.png) - -Plot describes relationship between floating point operations -needed for computing forward pass on a 224px x 224px image, -for the implemented models. -Dot size indicates number of trainable parameters. - -### Latency vs Throughput on different batch sizes -![LATvsTHR](./img/LATvsTHR.png) - -Plot describes relationship between -inference latency, throughput and batch size -for the implemented models. - - +# Convolutional Networks for Image Classification in PyTorch + +In this repository you will find implementations of various image classification models. + +Detailed information on each model can be found here: + +## Table Of Contents + +* [Models](#models) +* [Validation accuracy results](#validation-accuracy-results) +* [Training performance results](#training-performance-results) + * [Training performance: NVIDIA DGX A100 (8x A100 40GB)](#training-performance-nvidia-dgx-a100-8x-a100-40gb) + * [Training performance: NVIDIA DGX-1 16GB (8x V100 16GB)](#training-performance-nvidia-dgx-1-16gb-8x-v100-16gb) + * [Training performance: NVIDIA DGX-2 (16x V100 32GB)](#training-performance-nvidia-dgx-2-16x-v100-32gb) +* [Model comparison](#model-comparison) + * [Accuracy vs FLOPS](#accuracy-vs-flops) + * [Latency vs Throughput on different batch sizes](#latency-vs-throughput-on-different-batch-sizes) + +## Models + +The following table provides links to where you can find additional information on each model: + +| **Model** | **Link**| +|:-:|:-:| +| resnet50 | [README](./resnet50v1.5/README.md) | +| resnext101-32x4d | [README](./resnext101-32x4d/README.md) | +| se-resnext101-32x4d | [README](./se-resnext101-32x4d/README.md) | + +## Validation accuracy results + +Our results were obtained by running the applicable +training scripts in the [framework-container-name] NGC container +on NVIDIA DGX-1 with (8x V100 16GB) GPUs. +The specific training script that was run is documented +in the corresponding model's README. + + +The following table shows the validation accuracy results of the +three classification models side-by-side. + + +| **arch** | **AMP Top1** | **AMP Top5** | **FP32 Top1** | **FP32 Top5** | +|:-:|:-:|:-:|:-:|:-:| +| resnet50 | 78.46 | 94.15 | 78.50 | 94.11 | +| resnext101-32x4d | 80.08 | 94.89 | 80.14 | 95.02 | +| se-resnext101-32x4d | 81.01 | 95.52 | 81.12 | 95.54 | + + +## Training performance results + +### Training performance: NVIDIA DGX A100 (8x A100 40GB) + + +Our results were obtained by running the applicable +training scripts in the pytorch-20.06 NGC container +on NVIDIA DGX A100 with (8x A100 40GB) GPUs. +Performance numbers (in images per second) +were averaged over an entire training epoch. +The specific training script that was run is documented +in the corresponding model's README. + +The following table shows the training accuracy results of the +three classification models side-by-side. + + +| **arch** | **Mixed Precision** | **TF32** | **Mixed Precision Speedup** | +|:-------------------:|:-------------------:|:-------------:|:---------------------------:| +| resnet50 | 9488.39 img/s | 5322.10 img/s | 1.78x | +| resnext101-32x4d | 6758.98 img/s | 2353.25 img/s | 2.87x | +| se-resnext101-32x4d | 4670.72 img/s | 2011.21 img/s | 2.32x | + +ResNeXt and SE-ResNeXt use [NHWC data layout](https://pytorch.org/tutorials/intermediate/memory_format_tutorial.html) when training using Mixed Precision, +which improves the model performance. We are currently working on adding it for ResNet. + + +### Training performance: NVIDIA DGX-1 16G (8x V100 16GB) + + +Our results were obtained by running the applicable +training scripts in the pytorch-20.06 NGC container +on NVIDIA DGX-1 with (8x V100 16GB) GPUs. +Performance numbers (in images per second) +were averaged over an entire training epoch. +The specific training script that was run is documented +in the corresponding model's README. + +The following table shows the training accuracy results of the +three classification models side-by-side. + + +| **arch** | **Mixed Precision** | **FP32** | **Mixed Precision Speedup** | +|:-------------------:|:-------------------:|:-------------:|:---------------------------:| +| resnet50 | 6565.61 img/s | 2869.19 img/s | 2.29x | +| resnext101-32x4d | 3922.74 img/s | 1136.30 img/s | 3.45x | +| se-resnext101-32x4d | 2651.13 img/s | 982.78 img/s | 2.70x | + +ResNeXt and SE-ResNeXt use [NHWC data layout](https://pytorch.org/tutorials/intermediate/memory_format_tutorial.html) when training using Mixed Precision, +which improves the model performance. We are currently working on adding it for ResNet. + + +## Model Comparison + +### Accuracy vs FLOPS +![ACCvsFLOPS](./img/ACCvsFLOPS.png) + +Plot describes relationship between floating point operations +needed for computing forward pass on a 224px x 224px image, +for the implemented models. +Dot size indicates number of trainable parameters. + +### Latency vs Throughput on different batch sizes +![LATvsTHR](./img/LATvsTHR.png) + +Plot describes relationship between +inference latency, throughput and batch size +for the implemented models. + + diff --git a/PyTorch/dev/cv/image_classification/SINGLESHOTPOSE_ID0869_for_PyTorch/requirements.txt b/PyTorch/dev/cv/image_classification/SINGLESHOTPOSE_ID0869_for_PyTorch/requirements.txt index 8367c68c70..b0b3b089fc 100644 --- a/PyTorch/dev/cv/image_classification/SINGLESHOTPOSE_ID0869_for_PyTorch/requirements.txt +++ b/PyTorch/dev/cv/image_classification/SINGLESHOTPOSE_ID0869_for_PyTorch/requirements.txt @@ -1,3 +1,3 @@ -torch==1.5.0 -apex +torch==1.5.0 +apex torchvision \ No newline at end of file diff --git a/PyTorch/dev/cv/image_classification/SlowFast_ID0646_for_PyTorch/detectron2/projects/Panoptic-DeepLab/configs/COCO-PanopticSegmentation/panoptic_deeplab_R_52_os16_mg124_poly_200k_bs64_crop_640_640_coco_dsconv.yaml b/PyTorch/dev/cv/image_classification/SlowFast_ID0646_for_PyTorch/detectron2/projects/Panoptic-DeepLab/configs/COCO-PanopticSegmentation/panoptic_deeplab_R_52_os16_mg124_poly_200k_bs64_crop_640_640_coco_dsconv.yaml deleted file mode 100644 index 6944c6fdf3..0000000000 --- a/PyTorch/dev/cv/image_classification/SlowFast_ID0646_for_PyTorch/detectron2/projects/Panoptic-DeepLab/configs/COCO-PanopticSegmentation/panoptic_deeplab_R_52_os16_mg124_poly_200k_bs64_crop_640_640_coco_dsconv.yaml +++ /dev/null @@ -1,42 +0,0 @@ -_BASE_: ../Cityscapes-PanopticSegmentation/Base-PanopticDeepLab-OS16.yaml -MODEL: - WEIGHTS: "detectron2://DeepLab/R-52.pkl" - PIXEL_MEAN: [123.675, 116.280, 103.530] - PIXEL_STD: [58.395, 57.120, 57.375] - BACKBONE: - NAME: "build_resnet_deeplab_backbone" - RESNETS: - DEPTH: 50 - NORM: "SyncBN" - RES5_MULTI_GRID: [1, 2, 4] - STEM_TYPE: "deeplab" - STEM_OUT_CHANNELS: 128 - STRIDE_IN_1X1: False - SEM_SEG_HEAD: - NUM_CLASSES: 133 - LOSS_TOP_K: 1.0 - USE_DEPTHWISE_SEPARABLE_CONV: True - PANOPTIC_DEEPLAB: - STUFF_AREA: 4096 - NMS_KERNEL: 41 - SIZE_DIVISIBILITY: 640 - USE_DEPTHWISE_SEPARABLE_CONV: True -DATASETS: - TRAIN: ("coco_2017_train_panoptic",) - TEST: ("coco_2017_val_panoptic",) -SOLVER: - BASE_LR: 0.0005 - MAX_ITER: 200000 - IMS_PER_BATCH: 64 -INPUT: - FORMAT: "RGB" - GAUSSIAN_SIGMA: 8 - MIN_SIZE_TRAIN: !!python/object/apply:eval ["[int(x * 0.1 * 640) for x in range(5, 16)]"] - MIN_SIZE_TRAIN_SAMPLING: "choice" - MIN_SIZE_TEST: 640 - MAX_SIZE_TRAIN: 960 - MAX_SIZE_TEST: 640 - CROP: - ENABLED: True - TYPE: "absolute" - SIZE: (640, 640) diff --git a/PyTorch/dev/cv/image_classification/SlowFast_ID0646_for_PyTorch/detectron2/projects/Panoptic-DeepLab/configs/Cityscapes-PanopticSegmentation/panoptic_deeplab_R_52_os16_mg124_poly_90k_bs32_crop_512_1024.yaml b/PyTorch/dev/cv/image_classification/SlowFast_ID0646_for_PyTorch/detectron2/projects/Panoptic-DeepLab/configs/Cityscapes-PanopticSegmentation/panoptic_deeplab_R_52_os16_mg124_poly_90k_bs32_crop_512_1024.yaml deleted file mode 100644 index fde902bb2a..0000000000 --- a/PyTorch/dev/cv/image_classification/SlowFast_ID0646_for_PyTorch/detectron2/projects/Panoptic-DeepLab/configs/Cityscapes-PanopticSegmentation/panoptic_deeplab_R_52_os16_mg124_poly_90k_bs32_crop_512_1024.yaml +++ /dev/null @@ -1,20 +0,0 @@ -_BASE_: Base-PanopticDeepLab-OS16.yaml -MODEL: - WEIGHTS: "detectron2://DeepLab/R-52.pkl" - PIXEL_MEAN: [123.675, 116.280, 103.530] - PIXEL_STD: [58.395, 57.120, 57.375] - BACKBONE: - NAME: "build_resnet_deeplab_backbone" - RESNETS: - DEPTH: 50 - NORM: "SyncBN" - RES5_MULTI_GRID: [1, 2, 4] - STEM_TYPE: "deeplab" - STEM_OUT_CHANNELS: 128 - STRIDE_IN_1X1: False -SOLVER: - MAX_ITER: 90000 -INPUT: - FORMAT: "RGB" - CROP: - SIZE: (512, 1024) diff --git a/PyTorch/dev/cv/image_classification/SlowFast_ID0646_for_PyTorch/detectron2/projects/Panoptic-DeepLab/configs/Cityscapes-PanopticSegmentation/panoptic_deeplab_R_52_os16_mg124_poly_90k_bs32_crop_512_1024_dsconv.yaml b/PyTorch/dev/cv/image_classification/SlowFast_ID0646_for_PyTorch/detectron2/projects/Panoptic-DeepLab/configs/Cityscapes-PanopticSegmentation/panoptic_deeplab_R_52_os16_mg124_poly_90k_bs32_crop_512_1024_dsconv.yaml deleted file mode 100644 index 8e314204c9..0000000000 --- a/PyTorch/dev/cv/image_classification/SlowFast_ID0646_for_PyTorch/detectron2/projects/Panoptic-DeepLab/configs/Cityscapes-PanopticSegmentation/panoptic_deeplab_R_52_os16_mg124_poly_90k_bs32_crop_512_1024_dsconv.yaml +++ /dev/null @@ -1,24 +0,0 @@ -_BASE_: Base-PanopticDeepLab-OS16.yaml -MODEL: - WEIGHTS: "detectron2://DeepLab/R-52.pkl" - PIXEL_MEAN: [123.675, 116.280, 103.530] - PIXEL_STD: [58.395, 57.120, 57.375] - BACKBONE: - NAME: "build_resnet_deeplab_backbone" - RESNETS: - DEPTH: 50 - NORM: "SyncBN" - RES5_MULTI_GRID: [1, 2, 4] - STEM_TYPE: "deeplab" - STEM_OUT_CHANNELS: 128 - STRIDE_IN_1X1: False - PANOPTIC_DEEPLAB: - USE_DEPTHWISE_SEPARABLE_CONV: True - SEM_SEG_HEAD: - USE_DEPTHWISE_SEPARABLE_CONV: True -SOLVER: - MAX_ITER: 90000 -INPUT: - FORMAT: "RGB" - CROP: - SIZE: (512, 1024) diff --git a/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/ README.md b/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/ README.md index 5e97ad0585..acca051a72 100644 --- a/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/ README.md +++ b/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/ README.md @@ -1,262 +1,262 @@ -# VGGNet-PyTorch - -### Update (Feb 14, 2020) - -The update is for ease of use and deployment. - - * [Example: Export to ONNX](#example-export-to-onnx) - * [Example: Extract features](#example-feature-extraction) - * [Example: Visual](#example-visual) - -It is also now incredibly simple to load a pretrained model with a new number of classes for transfer learning: - -```python -from vgg_pytorch import VGG -model = VGG.from_pretrained('vgg11', num_classes=10) -``` - -### Update (January 15, 2020) - -This update allows you to use NVIDIA's Apex tool for accelerated training. By default choice `hybrid training precision` + `dynamic loss amplified` version, if you need to learn more and details about `apex` tools, please visit https://github.com/NVIDIA/apex. - -### Update (January 9, 2020) - -This update adds a visual interface for testing, which is developed by pyqt5. At present, it has realized basic functions, and other functions will be gradually improved in the future. - -### Update (January 6, 2020) - -This update adds a modular neural network, making it more flexible in use. It can be deployed to many common dataset classification tasks. Of course, it can also be used in your products. - -### Overview -This repository contains an op-for-op PyTorch reimplementation of [VGGNet](https://arxiv.org/pdf/1409.1556.pdf). - -The goal of this implementation is to be simple, highly extensible, and easy to integrate into your own projects. This implementation is a work in progress -- new features are currently being implemented. - -At the moment, you can easily: - * Load pretrained VGGNet models - * Use VGGNet models for classification or feature extraction - -_Upcoming features_: In the next few days, you will be able to: - * Quickly finetune an VGGNet on your own dataset - * Export VGGNet models for production - -### Table of contents -1. [About VGG](#about-vgg) -2. [Installation](#installation) -3. [Usage](#usage) - * [Load pretrained models](#loading-pretrained-models) - * [Example: Classify](#example-classification) - * [Example: Extract features](#example-feature-extraction) - * [Example: Export to ONNX](#example-export-to-onnx) - * [Example: Visual](#example-visual) -4. [Contributing](#contributing) - -### About VGG - -If you're new to VGGNets, here is an explanation straight from the official PyTorch implementation: - -In this work we investigate the effect of the convolutional network depth on its -accuracy in the large-scale image recognition setting. Our main contribution is -a thorough evaluation of networks of increasing depth using an architecture with -very small (3 × 3) convolution filters, which shows that a significant improvement -on the prior-art configurations can be achieved by pushing the depth to 16–19 -weight layers. These findings were the basis of our ImageNet Challenge 2014 -submission, where our team secured the first and the second places in the localisation and classification tracks respectively. We also show that our representations -generalise well to other datasets, where they achieve state-of-the-art results. We -have made our two best-performing ConvNet models publicly available to facilitate further research on the use of deep visual representations in computer vision. - -### Installation - -Install from pypi: -```bash -$ pip3 install vgg_pytorch -``` - -Install from source: -```bash -$ git clone https://github.com/Lornatang/VGGNet-PyTorch.git -$ cd VGGNet-PyTorch -$ pip3 install -e . -``` - -### Usage - -#### Loading pretrained models - -Load an vgg11 network: -```python -from vgg_pytorch import VGG -model = VGG.from_name("vgg11") -``` - -Load a pretrained vgg11: -```python -from vgg_pytorch import VGG -model = VGG.from_pretrained("vgg11") -``` - -Their 1-crop error rates on imagenet dataset with pretrained models are listed below. - -| Model structure | Top-1 error | Top-5 error | -| --------------- | ----------- | ----------- | -| vgg11 | 30.98 | 11.37 | -| vgg11_bn | 29.70 | 10.19 | -| vgg13 | 30.07 | 10.75 | -| vgg13_bn | 28.45 | 9.63 | -| vgg16 | 28.41 | 9.62 | -| vgg16_bn | 26.63 | 8.50 | -| vgg19 | 27.62 | 9.12 | -| vgg19_bn | 25.76 | 8.15 | - -Details about the models are below (for CIFAR10 dataset): - -| *Name* |*# Params*|*Top-1 Acc.*|*Pretrained?*| -|:-----------------:|:--------:|:----------:|:-----------:| -| `vgg11` | 132.9M | 91.1 | √ | -| `vgg13` | 133M | 92.8 | √ | -| `vgg16` | 138.4M | 92.6 | √ | -| `vgg19` | 143.7M | 92.3 | √ | -|-------------------|----------|------------|-------------| -| `vgg11_bn` | 132.9M | 92.2 | √ | -| `vgg13_bn` | 133M | 94.2 | √ | -| `vgg16_bn` | 138.4M | 93.9 | √ | -| `vgg19_bn` | 143.7M | 93.7 | √ | - - -#### Example: Classification - -We assume that in your current directory, there is a `img.jpg` file and a `labels_map.txt` file (ImageNet class names). These are both included in `examples/simple`. - -All pre-trained models expect input images normalized in the same way, -i.e. mini-batches of 3-channel RGB images of shape `(3 x H x W)`, where `H` and `W` are expected to be at least `224`. -The images have to be loaded in to a range of `[0, 1]` and then normalized using `mean = [0.485, 0.456, 0.406]` -and `std = [0.229, 0.224, 0.225]`. - -Here's a sample execution. - -```python -import json - -import torch -import torchvision.transforms as transforms -from PIL import Image - -from vgg_pytorch import VGG - -# Open image -input_image = Image.open("img.jpg") - -# Preprocess image -preprocess = transforms.Compose([ - transforms.Resize(256), - transforms.CenterCrop(224), - transforms.ToTensor(), - transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), -]) -input_tensor = preprocess(input_image) -input_batch = input_tensor.unsqueeze(0) # create a mini-batch as expected by the model - -# Load class names -labels_map = json.load(open("labels_map.txt")) -labels_map = [labels_map[str(i)] for i in range(1000)] - -# Classify with VGG11 -model = VGG.from_pretrained("vgg11") -model.eval() - -# move the input and model to GPU for speed if available -if torch.cuda.is_available(): - input_batch = input_batch.to("cuda") - model.to("cuda") - -with torch.no_grad(): - logits = model(input_batch) -preds = torch.topk(logits, k=5).indices.squeeze(0).tolist() - -print("-----") -for idx in preds: - label = labels_map[idx] - prob = torch.softmax(logits, dim=1)[0, idx].item() - print(f"{label:<75} ({prob * 100:.2f}%)") -``` - -#### Example: Feature Extraction - -You can easily extract features with `model.extract_features`: -```python -import torch -from vgg_pytorch import VGG -model = VGG.from_pretrained('vgg11') - -# ... image preprocessing as in the classification example ... -inputs = torch.randn(1, 3, 224, 224) -print(inputs.shape) # torch.Size([1, 3, 224, 224]) - -features = model.extract_features(inputs) -print(features.shape) # torch.Size([1, 512, 7, 7]) -``` - -#### Example: Export to ONNX - -Exporting to ONNX for deploying to production is now simple: -```python -import torch -from vgg_pytorch import VGG - -model = VGG.from_pretrained('vgg11') -dummy_input = torch.randn(16, 3, 224, 224) - -torch.onnx.export(model, dummy_input, "demo.onnx", verbose=True) -``` - -#### Example: Visual - -```text -cd $REPO$/framework -sh start.sh -``` - -Then open the browser and type in the browser address [http://127.0.0.1:8000/](http://127.0.0.1:8000/). - -Enjoy it. - -#### ImageNet - -See `examples/imagenet` for details about evaluating on ImageNet. - -For more datasets result. Please see `research/README.md`. - -### Contributing - -If you find a bug, create a GitHub issue, or even better, submit a pull request. Similarly, if you have questions, simply post them as GitHub issues. - -I look forward to seeing what the community does with these models! - -### Credit - -#### Very Deep Convolutional Networks for Large-Scale Image Recognition - -*Karen Simonyan, Andrew Zisserman* - -##### Abstract - -In this work we investigate the effect of the convolutional network depth on its accuracy in the -large-scale image recognition setting. Our main contribution is a thorough evaluation of networks -of increasing depth using an architecture with very small (3x3) convolution filters, which shows -that a significant improvement on the prior-art configurations can be achieved by pushing the depth -to 16-19 weight layers. These findings were the basis of our ImageNet Challenge 2014 submission, -where our team secured the first and the second places in the localisation and classification tracks -respectively. We also show that our representations generalise well to other datasets, where they -achieve state-of-the-art results. We have made our two best-performing ConvNet models publicly -available to facilitate further research on the use of deep visual representations in computer vision. - -[paper](https://arxiv.org/abs/1409.1556) - -```text -@article{VGG, -title:{Very Deep Convolutional Networks for Large-Scale Image Recognition}, -author:{Karen Simonyan, Andrew Zisserman}, -journal={iclr}, -year={2015} -} +# VGGNet-PyTorch + +### Update (Feb 14, 2020) + +The update is for ease of use and deployment. + + * [Example: Export to ONNX](#example-export-to-onnx) + * [Example: Extract features](#example-feature-extraction) + * [Example: Visual](#example-visual) + +It is also now incredibly simple to load a pretrained model with a new number of classes for transfer learning: + +```python +from vgg_pytorch import VGG +model = VGG.from_pretrained('vgg11', num_classes=10) +``` + +### Update (January 15, 2020) + +This update allows you to use NVIDIA's Apex tool for accelerated training. By default choice `hybrid training precision` + `dynamic loss amplified` version, if you need to learn more and details about `apex` tools, please visit https://github.com/NVIDIA/apex. + +### Update (January 9, 2020) + +This update adds a visual interface for testing, which is developed by pyqt5. At present, it has realized basic functions, and other functions will be gradually improved in the future. + +### Update (January 6, 2020) + +This update adds a modular neural network, making it more flexible in use. It can be deployed to many common dataset classification tasks. Of course, it can also be used in your products. + +### Overview +This repository contains an op-for-op PyTorch reimplementation of [VGGNet](https://arxiv.org/pdf/1409.1556.pdf). + +The goal of this implementation is to be simple, highly extensible, and easy to integrate into your own projects. This implementation is a work in progress -- new features are currently being implemented. + +At the moment, you can easily: + * Load pretrained VGGNet models + * Use VGGNet models for classification or feature extraction + +_Upcoming features_: In the next few days, you will be able to: + * Quickly finetune an VGGNet on your own dataset + * Export VGGNet models for production + +### Table of contents +1. [About VGG](#about-vgg) +2. [Installation](#installation) +3. [Usage](#usage) + * [Load pretrained models](#loading-pretrained-models) + * [Example: Classify](#example-classification) + * [Example: Extract features](#example-feature-extraction) + * [Example: Export to ONNX](#example-export-to-onnx) + * [Example: Visual](#example-visual) +4. [Contributing](#contributing) + +### About VGG + +If you're new to VGGNets, here is an explanation straight from the official PyTorch implementation: + +In this work we investigate the effect of the convolutional network depth on its +accuracy in the large-scale image recognition setting. Our main contribution is +a thorough evaluation of networks of increasing depth using an architecture with +very small (3 × 3) convolution filters, which shows that a significant improvement +on the prior-art configurations can be achieved by pushing the depth to 16–19 +weight layers. These findings were the basis of our ImageNet Challenge 2014 +submission, where our team secured the first and the second places in the localisation and classification tracks respectively. We also show that our representations +generalise well to other datasets, where they achieve state-of-the-art results. We +have made our two best-performing ConvNet models publicly available to facilitate further research on the use of deep visual representations in computer vision. + +### Installation + +Install from pypi: +```bash +$ pip3 install vgg_pytorch +``` + +Install from source: +```bash +$ git clone https://github.com/Lornatang/VGGNet-PyTorch.git +$ cd VGGNet-PyTorch +$ pip3 install -e . +``` + +### Usage + +#### Loading pretrained models + +Load an vgg11 network: +```python +from vgg_pytorch import VGG +model = VGG.from_name("vgg11") +``` + +Load a pretrained vgg11: +```python +from vgg_pytorch import VGG +model = VGG.from_pretrained("vgg11") +``` + +Their 1-crop error rates on imagenet dataset with pretrained models are listed below. + +| Model structure | Top-1 error | Top-5 error | +| --------------- | ----------- | ----------- | +| vgg11 | 30.98 | 11.37 | +| vgg11_bn | 29.70 | 10.19 | +| vgg13 | 30.07 | 10.75 | +| vgg13_bn | 28.45 | 9.63 | +| vgg16 | 28.41 | 9.62 | +| vgg16_bn | 26.63 | 8.50 | +| vgg19 | 27.62 | 9.12 | +| vgg19_bn | 25.76 | 8.15 | + +Details about the models are below (for CIFAR10 dataset): + +| *Name* |*# Params*|*Top-1 Acc.*|*Pretrained?*| +|:-----------------:|:--------:|:----------:|:-----------:| +| `vgg11` | 132.9M | 91.1 | √ | +| `vgg13` | 133M | 92.8 | √ | +| `vgg16` | 138.4M | 92.6 | √ | +| `vgg19` | 143.7M | 92.3 | √ | +|-------------------|----------|------------|-------------| +| `vgg11_bn` | 132.9M | 92.2 | √ | +| `vgg13_bn` | 133M | 94.2 | √ | +| `vgg16_bn` | 138.4M | 93.9 | √ | +| `vgg19_bn` | 143.7M | 93.7 | √ | + + +#### Example: Classification + +We assume that in your current directory, there is a `img.jpg` file and a `labels_map.txt` file (ImageNet class names). These are both included in `examples/simple`. + +All pre-trained models expect input images normalized in the same way, +i.e. mini-batches of 3-channel RGB images of shape `(3 x H x W)`, where `H` and `W` are expected to be at least `224`. +The images have to be loaded in to a range of `[0, 1]` and then normalized using `mean = [0.485, 0.456, 0.406]` +and `std = [0.229, 0.224, 0.225]`. + +Here's a sample execution. + +```python +import json + +import torch +import torchvision.transforms as transforms +from PIL import Image + +from vgg_pytorch import VGG + +# Open image +input_image = Image.open("img.jpg") + +# Preprocess image +preprocess = transforms.Compose([ + transforms.Resize(256), + transforms.CenterCrop(224), + transforms.ToTensor(), + transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), +]) +input_tensor = preprocess(input_image) +input_batch = input_tensor.unsqueeze(0) # create a mini-batch as expected by the model + +# Load class names +labels_map = json.load(open("labels_map.txt")) +labels_map = [labels_map[str(i)] for i in range(1000)] + +# Classify with VGG11 +model = VGG.from_pretrained("vgg11") +model.eval() + +# move the input and model to GPU for speed if available +if torch.cuda.is_available(): + input_batch = input_batch.to("cuda") + model.to("cuda") + +with torch.no_grad(): + logits = model(input_batch) +preds = torch.topk(logits, k=5).indices.squeeze(0).tolist() + +print("-----") +for idx in preds: + label = labels_map[idx] + prob = torch.softmax(logits, dim=1)[0, idx].item() + print(f"{label:<75} ({prob * 100:.2f}%)") +``` + +#### Example: Feature Extraction + +You can easily extract features with `model.extract_features`: +```python +import torch +from vgg_pytorch import VGG +model = VGG.from_pretrained('vgg11') + +# ... image preprocessing as in the classification example ... +inputs = torch.randn(1, 3, 224, 224) +print(inputs.shape) # torch.Size([1, 3, 224, 224]) + +features = model.extract_features(inputs) +print(features.shape) # torch.Size([1, 512, 7, 7]) +``` + +#### Example: Export to ONNX + +Exporting to ONNX for deploying to production is now simple: +```python +import torch +from vgg_pytorch import VGG + +model = VGG.from_pretrained('vgg11') +dummy_input = torch.randn(16, 3, 224, 224) + +torch.onnx.export(model, dummy_input, "demo.onnx", verbose=True) +``` + +#### Example: Visual + +```text +cd $REPO$/framework +sh start.sh +``` + +Then open the browser and type in the browser address [http://127.0.0.1:8000/](http://127.0.0.1:8000/). + +Enjoy it. + +#### ImageNet + +See `examples/imagenet` for details about evaluating on ImageNet. + +For more datasets result. Please see `research/README.md`. + +### Contributing + +If you find a bug, create a GitHub issue, or even better, submit a pull request. Similarly, if you have questions, simply post them as GitHub issues. + +I look forward to seeing what the community does with these models! + +### Credit + +#### Very Deep Convolutional Networks for Large-Scale Image Recognition + +*Karen Simonyan, Andrew Zisserman* + +##### Abstract + +In this work we investigate the effect of the convolutional network depth on its accuracy in the +large-scale image recognition setting. Our main contribution is a thorough evaluation of networks +of increasing depth using an architecture with very small (3x3) convolution filters, which shows +that a significant improvement on the prior-art configurations can be achieved by pushing the depth +to 16-19 weight layers. These findings were the basis of our ImageNet Challenge 2014 submission, +where our team secured the first and the second places in the localisation and classification tracks +respectively. We also show that our representations generalise well to other datasets, where they +achieve state-of-the-art results. We have made our two best-performing ConvNet models publicly +available to facilitate further research on the use of deep visual representations in computer vision. + +[paper](https://arxiv.org/abs/1409.1556) + +```text +@article{VGG, +title:{Very Deep Convolutional Networks for Large-Scale Image Recognition}, +author:{Karen Simonyan, Andrew Zisserman}, +journal={iclr}, +year={2015} +} ``` \ No newline at end of file diff --git a/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/LICENSE b/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/LICENSE index deeea2d8cc..b09cd7856d 100644 --- a/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/LICENSE +++ b/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/LICENSE @@ -1,201 +1,201 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/VGGNet_for_PyTorch/modelzoo_level.txt b/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/VGGNet_for_PyTorch/modelzoo_level.txt index 5afcef9188..3117fffc3b 100644 --- a/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/VGGNet_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/VGGNet_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:NOK +FuncStatus:OK +PerfStatus:NOK PrecisionStatus:POK \ No newline at end of file diff --git a/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/VGGNet_for_PyTorch/requirements.txt b/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/VGGNet_for_PyTorch/requirements.txt index 420b1d1f4a..a9df0d18fc 100644 --- a/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/VGGNet_for_PyTorch/requirements.txt +++ b/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/VGGNet_for_PyTorch/requirements.txt @@ -1,16 +1,16 @@ -# progress bars in model download and training scripts -tqdm -# Accessing files from S3 directly. -boto3 -# Used for downloading models over HTTP -requests -six -ipdb -#Data processing -h5py -html2text -nltk -progressbar -#Others -onnxruntime +# progress bars in model download and training scripts +tqdm +# Accessing files from S3 directly. +boto3 +# Used for downloading models over HTTP +requests +six +ipdb +#Data processing +h5py +html2text +nltk +progressbar +#Others +onnxruntime git+https://github.com/NVIDIA/dllogger \ No newline at end of file diff --git a/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/VGGNet_for_PyTorch/test/train_performance_1p.sh b/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/VGGNet_for_PyTorch/test/train_performance_1p.sh index a75708d7e2..58a96bba31 100644 --- a/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/VGGNet_for_PyTorch/test/train_performance_1p.sh +++ b/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/VGGNet_for_PyTorch/test/train_performance_1p.sh @@ -1,166 +1,166 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` - -#集合通信参数,不需要修改 - -export RANK_SIZE=1 -export JOB_ID=10087 -RANK_ID_START=0 - - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -export ASCEND_GLOBAL_LOG_LEVEL=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="VGGNet_ID0400_for_PyTorch" -#训练epoch -epoch=2 -#训练batch_size -RANK_SIZE=1 -batch_size=64 -#迭代数iteration -iteration=100 -#训练step -#train_steps=1000 -#学习率 -#learning_rate=3.96 - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False -autotune=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_full_1p.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is False - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --autotune whether to enable autotune, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --autotune* ]];then - autotune=`echo ${para#*=}` - #开autotune特有环境变量 - autotune=True - export autotune=True - export REPEAT_TUNE=True - export ASCEND_DEVICE_ID=0 - export ENABLE_TUNE_BANK=True - export TE_PARALLEL_COMPILER=32 - mv $install_path/fwkacllib/data/rl/Ascend910/custom $install_path/fwkacllib/data/rl/Ascend910/custom_bak - mv $install_path/fwkacllib/data/tiling/Ascend910/custom $install_path/fwkacllib/data/tiling/Ascend910/custom_bak - autotune_dump_path=${cur_path}/output/autotune_dump - mkdir -p ${autotune_dump_path}/GA - mkdir -p ${autotune_dump_path}/rl - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#进入训练脚本目录,需要模型审视修改 -cd $cur_path/../examples/simple/ -for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); -do - #设置环境变量,不需要修改 - echo "Device ID: $ASCEND_DEVICE_ID" - export RANK_ID=$RANK_ID - export DEVICE_ID=$RANK_ID - - #创建DeviceID输出目录,不需要修改 - if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - fi - - - #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 - nohup python3 test.py \ - > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & -done -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -grep "Training //" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log > traintime.log -sed -i '1d' traintime.log -traintime=`cat traintime.log | grep "Training //" | awk '{sum+=$13} END {print sum/NR}'` - -#traintime=`grep "Training //" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk 'END {print $13}'` -TrainingTime=`echo "scale=3;${traintime} / 1000"|bc |awk '{printf "%0.3f",$0}'` - -ActualFPS=`echo "scale=2;${batch_size} / ${TrainingTime}"|bc` - -echo "E2E Training Duration sec : $e2e_time" - -#稳定性精度看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -#ActualLoss=`grep "loss =" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log| awk 'END {print $6}' |tr -d ,` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -#echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -#echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -#echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` + +#集合通信参数,不需要修改 + +export RANK_SIZE=1 +export JOB_ID=10087 +RANK_ID_START=0 + + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +export ASCEND_GLOBAL_LOG_LEVEL=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="VGGNet_ID0400_for_PyTorch" +#训练epoch +epoch=2 +#训练batch_size +RANK_SIZE=1 +batch_size=64 +#迭代数iteration +iteration=100 +#训练step +#train_steps=1000 +#学习率 +#learning_rate=3.96 + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False +autotune=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_full_1p.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is False + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --autotune whether to enable autotune, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --autotune* ]];then + autotune=`echo ${para#*=}` + #开autotune特有环境变量 + autotune=True + export autotune=True + export REPEAT_TUNE=True + export ASCEND_DEVICE_ID=0 + export ENABLE_TUNE_BANK=True + export TE_PARALLEL_COMPILER=32 + mv $install_path/fwkacllib/data/rl/Ascend910/custom $install_path/fwkacllib/data/rl/Ascend910/custom_bak + mv $install_path/fwkacllib/data/tiling/Ascend910/custom $install_path/fwkacllib/data/tiling/Ascend910/custom_bak + autotune_dump_path=${cur_path}/output/autotune_dump + mkdir -p ${autotune_dump_path}/GA + mkdir -p ${autotune_dump_path}/rl + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#进入训练脚本目录,需要模型审视修改 +cd $cur_path/../examples/simple/ +for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); +do + #设置环境变量,不需要修改 + echo "Device ID: $ASCEND_DEVICE_ID" + export RANK_ID=$RANK_ID + export DEVICE_ID=$RANK_ID + + #创建DeviceID输出目录,不需要修改 + if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + fi + + + #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 + nohup python3 test.py \ + > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & +done +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +grep "Training //" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log > traintime.log +sed -i '1d' traintime.log +traintime=`cat traintime.log | grep "Training //" | awk '{sum+=$13} END {print sum/NR}'` + +#traintime=`grep "Training //" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk 'END {print $13}'` +TrainingTime=`echo "scale=3;${traintime} / 1000"|bc |awk '{printf "%0.3f",$0}'` + +ActualFPS=`echo "scale=2;${batch_size} / ${TrainingTime}"|bc` + +echo "E2E Training Duration sec : $e2e_time" + +#稳定性精度看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +#ActualLoss=`grep "loss =" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log| awk 'END {print $6}' |tr -d ,` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log diff --git a/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/modelzoo_level.txt b/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/modelzoo_level.txt index 5afcef9188..3117fffc3b 100644 --- a/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/modelzoo_level.txt +++ b/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:NOK +FuncStatus:OK +PerfStatus:NOK PrecisionStatus:POK \ No newline at end of file diff --git a/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/requirements.txt b/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/requirements.txt index 420b1d1f4a..a9df0d18fc 100644 --- a/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/requirements.txt +++ b/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch/requirements.txt @@ -1,16 +1,16 @@ -# progress bars in model download and training scripts -tqdm -# Accessing files from S3 directly. -boto3 -# Used for downloading models over HTTP -requests -six -ipdb -#Data processing -h5py -html2text -nltk -progressbar -#Others -onnxruntime +# progress bars in model download and training scripts +tqdm +# Accessing files from S3 directly. +boto3 +# Used for downloading models over HTTP +requests +six +ipdb +#Data processing +h5py +html2text +nltk +progressbar +#Others +onnxruntime git+https://github.com/NVIDIA/dllogger \ No newline at end of file diff --git a/PyTorch/dev/cv/image_classification/mBART_ID1550_for_PyTorch/modelzoo_level.txt b/PyTorch/dev/cv/image_classification/mBART_ID1550_for_PyTorch/modelzoo_level.txt index a17c8f95fa..a829ab59b9 100644 --- a/PyTorch/dev/cv/image_classification/mBART_ID1550_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/dev/cv/image_classification/mBART_ID1550_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:NOK +FuncStatus:OK +PerfStatus:NOK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/dev/cv/image_classification/vit-base_ID0492_for_PyTorch/test/train_full_8p.sh b/PyTorch/dev/cv/image_classification/vit-base_ID0492_for_PyTorch/test/train_full_8p.sh index 8b5edcbaa7..053b27b30d 100644 --- a/PyTorch/dev/cv/image_classification/vit-base_ID0492_for_PyTorch/test/train_full_8p.sh +++ b/PyTorch/dev/cv/image_classification/vit-base_ID0492_for_PyTorch/test/train_full_8p.sh @@ -1,230 +1,230 @@ -#!/bin/bash - -#export ASCEND_SLOG_PRINT_TO_STDOUT=1 - -#当前路径,不需要修改 -cur_path=`pwd` - -#集合通信参数,不需要修改 - -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 - - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="vit-base_ID0492_for_PyTorch" -#训练epoch -train_epochs=10000 -#训练batch_size -batch_size=64 -#训练step -train_steps= -#学习率 -learning_rate=0.1 - -#TF2.X独有,需要模型审视修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -PREC="" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_performance_1P.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(O0/O1/O2/O3) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is False - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - apex_opt_level=`echo ${para#*=}` - if [[ $apex_opt_level != "O1" ]] && [[ $apex_opt_level != "O2" ]] && [[ $apex_opt_level != "O3" ]]; then - echo "[Error] para \"precision_mode\" must be config O1 or O2 or O3" - exit 1 - fi - PREC="--apex --apex-opt-level "$apex_opt_level - elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --ckpt_path* ]];then - ckpt_path=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#进入训练脚本目录,需要模型审视修改 -cd $cur_path - -for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); -do - #设置环境变量,不需要修改 - echo "Device ID: $ASCEND_DEVICE_ID" - export RANK_ID=$RANK_ID - - - - #创建DeviceID输出目录,不需要修改 - if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - fi - # 绑核,不需要的绑核的模型删除,需要的模型审视修改 - #let a=RANK_ID*12 - #let b=RANK_ID+1 - #let c=b*12-1 - - #网络特有 拷贝预训练模型到root路径下 - if [ -d /root/.cache/torch/checkpoints/ ];then - echo "File_path exist" - else - mkdir -p /root/.cache/torch/checkpoints/ - fi - cp ${data_path}/mobilenet_v2-b0353104.pth /root/.cache/torch/checkpoints/ - - #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 - #--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path - #python3 $cur_path/../train.py \ - #--name cifar10-100_500 \ - #--dataset cifar10 \ - #--model_type ViT-B_16 \ - #--pretrained_dir ${ckpt_path}/ViT-B_16.npz \ - #--addr=127.0.0.1 \ - #--train_batch_size=64 \ - #--num_steps=10000 \ - #--npu-fused-sgd \ - #--fp16 \ - #--data_dir ${data_path} \ - #--fp16_opt_level O2 > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & -done -wait - -export MASTER_ADDR=localhost -export MASTER_PORT=29688 -export HCCL_WHITELIST_DISABLE=1 - -NPUS=($(seq 0 7)) -export NPU_WORLD_SIZE=${#NPUS[@]} -rank=0 -for i in ${NPUS[@]} -do - mkdir -p $cur_path/output/${i}/ - export NPU_CALCULATE_DEVICE=${i} - export ASCEND_DEVICE_ID=${i} - export RANK=${rank} - echo run process ${rank} - python3 $cur_path/../train.py \ - --name cifar10-100_500 \ - --dataset cifar10 \ - --model_type ViT-B_16 \ - --pretrained_dir ${ckpt_path}/ViT-B_16.npz \ - --addr=127.0.0.1 \ - --train_batch_size=64 \ - --num_steps=1000 \ - --npu-fused-sgd \ - --fp16 \ - --learning_rate 0.24 \ - --data_dir ${data_path} \ - --ddp True \ - --fp16_opt_level O2 > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${i}.log 2>&1 & - let rank++ -done -wait - - - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -sed -i "s|\r|\n|g" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep FPS $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "FPS=" '{print$2}' | awk -F ")" '{print$1}' |tail -n +5 |awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` -FPS=$(awk 'BEGIN{print '$FPS'*8}') -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep "Prec@5:" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F ":" 'END {print $8}'|cut -c 1-6` -train_accuracy=`grep -a "Best Accuracy:" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk '{print$NF}'` - -#打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -#echo "Final Train Accuracy(top5) : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${ActualFPS}'}'` - - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -#grep "Training" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk '{print$2,$6}'|awk -F "(" '{print$2,$3}'|sort -k 1,1 -u -n |awk -F '=' '{print$2}'|awk -F ')' '{print$1}'|awk '{if(length !=0) print $0}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt -grep "Steps" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep -v X |awk -F "loss=" '{print$2}' | awk -F ")" '{print$1}'|sed '/^$/d' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#export ASCEND_SLOG_PRINT_TO_STDOUT=1 + +#当前路径,不需要修改 +cur_path=`pwd` + +#集合通信参数,不需要修改 + +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 + + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="vit-base_ID0492_for_PyTorch" +#训练epoch +train_epochs=10000 +#训练batch_size +batch_size=64 +#训练step +train_steps= +#学习率 +learning_rate=0.1 + +#TF2.X独有,需要模型审视修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +PREC="" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_performance_1P.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(O0/O1/O2/O3) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is False + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + apex_opt_level=`echo ${para#*=}` + if [[ $apex_opt_level != "O1" ]] && [[ $apex_opt_level != "O2" ]] && [[ $apex_opt_level != "O3" ]]; then + echo "[Error] para \"precision_mode\" must be config O1 or O2 or O3" + exit 1 + fi + PREC="--apex --apex-opt-level "$apex_opt_level + elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --ckpt_path* ]];then + ckpt_path=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#进入训练脚本目录,需要模型审视修改 +cd $cur_path + +for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); +do + #设置环境变量,不需要修改 + echo "Device ID: $ASCEND_DEVICE_ID" + export RANK_ID=$RANK_ID + + + + #创建DeviceID输出目录,不需要修改 + if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + fi + # 绑核,不需要的绑核的模型删除,需要的模型审视修改 + #let a=RANK_ID*12 + #let b=RANK_ID+1 + #let c=b*12-1 + + #网络特有 拷贝预训练模型到root路径下 + if [ -d /root/.cache/torch/checkpoints/ ];then + echo "File_path exist" + else + mkdir -p /root/.cache/torch/checkpoints/ + fi + cp ${data_path}/mobilenet_v2-b0353104.pth /root/.cache/torch/checkpoints/ + + #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 + #--data_dir, --model_dir, --precision_mode, --over_dump, --over_dump_path,--data_dump_flag,--data_dump_step,--data_dump_path,--profiling,--profiling_dump_path + #python3 $cur_path/../train.py \ + #--name cifar10-100_500 \ + #--dataset cifar10 \ + #--model_type ViT-B_16 \ + #--pretrained_dir ${ckpt_path}/ViT-B_16.npz \ + #--addr=127.0.0.1 \ + #--train_batch_size=64 \ + #--num_steps=10000 \ + #--npu-fused-sgd \ + #--fp16 \ + #--data_dir ${data_path} \ + #--fp16_opt_level O2 > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & +done +wait + +export MASTER_ADDR=localhost +export MASTER_PORT=29688 +export HCCL_WHITELIST_DISABLE=1 + +NPUS=($(seq 0 7)) +export NPU_WORLD_SIZE=${#NPUS[@]} +rank=0 +for i in ${NPUS[@]} +do + mkdir -p $cur_path/output/${i}/ + export NPU_CALCULATE_DEVICE=${i} + export ASCEND_DEVICE_ID=${i} + export RANK=${rank} + echo run process ${rank} + python3 $cur_path/../train.py \ + --name cifar10-100_500 \ + --dataset cifar10 \ + --model_type ViT-B_16 \ + --pretrained_dir ${ckpt_path}/ViT-B_16.npz \ + --addr=127.0.0.1 \ + --train_batch_size=64 \ + --num_steps=1000 \ + --npu-fused-sgd \ + --fp16 \ + --learning_rate 0.24 \ + --data_dir ${data_path} \ + --ddp True \ + --fp16_opt_level O2 > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${i}.log 2>&1 & + let rank++ +done +wait + + + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +sed -i "s|\r|\n|g" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep FPS $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "FPS=" '{print$2}' | awk -F ")" '{print$1}' |tail -n +5 |awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` +FPS=$(awk 'BEGIN{print '$FPS'*8}') +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep "Prec@5:" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F ":" 'END {print $8}'|cut -c 1-6` +train_accuracy=`grep -a "Best Accuracy:" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk '{print$NF}'` + +#打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +#echo "Final Train Accuracy(top5) : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${ActualFPS}'}'` + + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +#grep "Training" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk '{print$2,$6}'|awk -F "(" '{print$2,$3}'|sort -k 1,1 -u -n |awk -F '=' '{print$2}'|awk -F ')' '{print$1}'|awk '{if(length !=0) print $0}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt +grep "Steps" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep -v X |awk -F "loss=" '{print$2}' | awk -F ")" '{print$1}'|sed '/^$/d' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log diff --git a/PyTorch/dev/cv/image_classification/vit-base_ID0492_for_PyTorch/test/train_performance_8p.sh b/PyTorch/dev/cv/image_classification/vit-base_ID0492_for_PyTorch/test/train_performance_8p.sh index 417f547189..c7fa78bc46 100644 --- a/PyTorch/dev/cv/image_classification/vit-base_ID0492_for_PyTorch/test/train_performance_8p.sh +++ b/PyTorch/dev/cv/image_classification/vit-base_ID0492_for_PyTorch/test/train_performance_8p.sh @@ -1,184 +1,184 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` - -#集合通信参数,不需要修改 - -export RANK_SIZE=8 -export JOB_ID=10087 -RANK_ID_START=0 - -RANK_SIZE=8 -# 数据集路径,保持为空,不需要修改 -data_path="" - -#设置默认日志级别,不需要修改 -export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="vit-base_ID0492_for_PyTorch" -#训练epoch -train_epochs=1 -#训练batch_size -batch_size=64 -#训练step -train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.1 - -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False - - -if [[ $1 == --help || $1 == --h ]];then - echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" - exit 1 -fi - -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --ckpt_path* ]];then - ckpt_path=`echo ${para#*=}` - elif [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` - elif [[ $para == --batch_size* ]];then - batch_size=`echo ${para#*=}` - elif [[ $para == --learning_rate* ]];then - learning_rate=`echo ${para#*=}` - fi -done - -PREC="" -if [[ $precision_mode == "amp" ]];then - PREC="--apex" -fi - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -cd $cur_path -#设置环境变量,不需要修改 -echo "Device ID: $ASCEND_DEVICE_ID" -export RANK_ID=$RANK_ID - -if [ -d $cur_path/output ];then - rm -rf $cur_path/output/* - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi -wait - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#nohup python3 $cur_path/../train.py \ -# --name cifar10-100_500 \ -# --dataset cifar10 \ -# --model_type ViT-B_16 \ -# --pretrained_dir ${ckpt_path}/ViT-B_16.npz \ -# --addr=127.0.0.1 \ -# --train_batch_size=64 \ -# --num_steps=100 \ -# --npu-fused-sgd \ -# --fp16 \ -# --data_dir ${data_path} \ -# --fp16_opt_level O2 > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & - - - - - - -export MASTER_ADDR=localhost -export MASTER_PORT=29688 -export HCCL_WHITELIST_DISABLE=1 - -NPUS=($(seq 0 7)) -export NPU_WORLD_SIZE=${#NPUS[@]} -rank=0 -for i in ${NPUS[@]} -do - mkdir -p $cur_path/output/${i}/ - export NPU_CALCULATE_DEVICE=${i} - export ASCEND_DEVICE_ID=${i} - export RANK=${rank} - echo run process ${rank} - python3 $cur_path/../train.py \ - --name cifar10-100_500 \ - --dataset cifar10 \ - --model_type ViT-B_16 \ - --pretrained_dir ${ckpt_path}/ViT-B_16.npz \ - --addr=127.0.0.1 \ - --train_batch_size=64 \ - --num_steps=100 \ - --npu-fused-sgd \ - --fp16 \ - --ddp True \ - --data_dir ${data_path} \ - --fp16_opt_level O2 > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${i}.log 2>&1 & - let rank++ -done -wait - -wait - -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -sed -i "s|\r|\n|g" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep FPS $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "FPS=" '{print$2}' | awk -F ")" '{print$1}' |tail -n +5 |awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` -FPS=$(awk 'BEGIN{print '$FPS'*8}') -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -train_accuracy=`grep -a "Best Accuracy:" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk '{print $3}'| awk '{print$NF}'` - -#打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -#grep /781 $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "loss=" '{print$2}' | awk -F ")" '{print$1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt -grep "Steps" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep -v X |awk -F "loss=" '{print$2}' | awk -F ")" '{print$1}'|sed '/^$/d' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -sed -i "s/ModuleNotFoundError: No module named "impl.lp_norm_reduce"/ /g" `grep ModuleNotFoundError -rl $cur_path/output/$ASCEND_DEVICE_ID/train_*.log` +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` + +#集合通信参数,不需要修改 + +export RANK_SIZE=8 +export JOB_ID=10087 +RANK_ID_START=0 + +RANK_SIZE=8 +# 数据集路径,保持为空,不需要修改 +data_path="" + +#设置默认日志级别,不需要修改 +export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="vit-base_ID0492_for_PyTorch" +#训练epoch +train_epochs=1 +#训练batch_size +batch_size=64 +#训练step +train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.1 + +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False + + +if [[ $1 == --help || $1 == --h ]];then + echo "usage:./train_performance_1p.sh --data_path=data_dir --batch_size=1024 --learning_rate=0.04" + exit 1 +fi + +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --ckpt_path* ]];then + ckpt_path=`echo ${para#*=}` + elif [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` + elif [[ $para == --batch_size* ]];then + batch_size=`echo ${para#*=}` + elif [[ $para == --learning_rate* ]];then + learning_rate=`echo ${para#*=}` + fi +done + +PREC="" +if [[ $precision_mode == "amp" ]];then + PREC="--apex" +fi + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +cd $cur_path +#设置环境变量,不需要修改 +echo "Device ID: $ASCEND_DEVICE_ID" +export RANK_ID=$RANK_ID + +if [ -d $cur_path/output ];then + rm -rf $cur_path/output/* + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi +wait + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#nohup python3 $cur_path/../train.py \ +# --name cifar10-100_500 \ +# --dataset cifar10 \ +# --model_type ViT-B_16 \ +# --pretrained_dir ${ckpt_path}/ViT-B_16.npz \ +# --addr=127.0.0.1 \ +# --train_batch_size=64 \ +# --num_steps=100 \ +# --npu-fused-sgd \ +# --fp16 \ +# --data_dir ${data_path} \ +# --fp16_opt_level O2 > $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log 2>&1 & + + + + + + +export MASTER_ADDR=localhost +export MASTER_PORT=29688 +export HCCL_WHITELIST_DISABLE=1 + +NPUS=($(seq 0 7)) +export NPU_WORLD_SIZE=${#NPUS[@]} +rank=0 +for i in ${NPUS[@]} +do + mkdir -p $cur_path/output/${i}/ + export NPU_CALCULATE_DEVICE=${i} + export ASCEND_DEVICE_ID=${i} + export RANK=${rank} + echo run process ${rank} + python3 $cur_path/../train.py \ + --name cifar10-100_500 \ + --dataset cifar10 \ + --model_type ViT-B_16 \ + --pretrained_dir ${ckpt_path}/ViT-B_16.npz \ + --addr=127.0.0.1 \ + --train_batch_size=64 \ + --num_steps=100 \ + --npu-fused-sgd \ + --fp16 \ + --ddp True \ + --data_dir ${data_path} \ + --fp16_opt_level O2 > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${i}.log 2>&1 & + let rank++ +done +wait + +wait + +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +sed -i "s|\r|\n|g" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep FPS $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk -F "FPS=" '{print$2}' | awk -F ")" '{print$1}' |tail -n +5 |awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` +FPS=$(awk 'BEGIN{print '$FPS'*8}') +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +train_accuracy=`grep -a "Best Accuracy:" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|awk '{print $3}'| awk '{print$NF}'` + +#打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +#grep /781 $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "loss=" '{print$2}' | awk -F ")" '{print$1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt +grep "Steps" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|grep -v X |awk -F "loss=" '{print$2}' | awk -F ")" '{print$1}'|sed '/^$/d' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +sed -i "s/ModuleNotFoundError: No module named "impl.lp_norm_reduce"/ /g" `grep ModuleNotFoundError -rl $cur_path/output/$ASCEND_DEVICE_ID/train_*.log` diff --git a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/Dockerfile b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/Dockerfile index 49cbba285f..d7deb4196b 100644 --- a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/Dockerfile +++ b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/Dockerfile @@ -1,5 +1,5 @@ -ARG FROM_IMAGE_NAME=ascend-pytorch-arm:20.1.0 -FROM ${FROM_IMAGE_NAME} - -COPY requirements.txt . +ARG FROM_IMAGE_NAME=ascend-pytorch-arm:20.1.0 +FROM ${FROM_IMAGE_NAME} + +COPY requirements.txt . RUN pip3.7 install -r requirements.txt \ No newline at end of file diff --git a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/LICENSE b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/LICENSE index 6c4f543d15..56cd05a13b 100644 --- a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/LICENSE +++ b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/LICENSE @@ -1,23 +1,23 @@ -MIT License - -Copyright (c) 2019 Microsoft Corporation -Copyright (c) 2017 Jieru Mei meijieru@gmail.com -Copyright 2020 Huawei Technologies Co., Ltd - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +MIT License + +Copyright (c) 2019 Microsoft Corporation +Copyright (c) 2017 Jieru Mei meijieru@gmail.com +Copyright 2020 Huawei Technologies Co., Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/README.md b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/README.md index 913d6916c8..d04156bd7b 100644 --- a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/README.md +++ b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/README.md @@ -1,25 +1,25 @@ -环境 ----------- - pytorch 1.5 - torchvision 0.5.0 - apex 0.1 - numpy - Pillow 8.1.0 - -Host侧训练步骤 ----------- -1.准备数据集
-2.修改run1p.sh,设置训练参数。device_id是用哪张卡,train_data_path是训练网络输入数据,label_data_path是label数据,lr是学习率,model_save_dir是模型保存目录,epoch是训练多少epoch,batch_size是batchsize
-3.执行bash run1p.sh开启单p训练
- - -Docker侧训练步骤 ----------- - -1.导入镜像二进制包docker import ubuntuarmpytorch.tar REPOSITORY:TAG, 比如: - - docker import ubuntuarmpytorch.tar pytorch:b020 - -2.执行docker_start.sh后带三个参数:步骤1生成的REPOSITORY:TAG;数据集路径(训练和评测数据集都放到该路径下);模型执行路径;比如: - - ./docker_start.sh pytorch:b020 /train/imagenet /home/CRNN_for_Pytorch +环境 +---------- + pytorch 1.5 + torchvision 0.5.0 + apex 0.1 + numpy + Pillow 8.1.0 + +Host侧训练步骤 +---------- +1.准备数据集
+2.修改run1p.sh,设置训练参数。device_id是用哪张卡,train_data_path是训练网络输入数据,label_data_path是label数据,lr是学习率,model_save_dir是模型保存目录,epoch是训练多少epoch,batch_size是batchsize
+3.执行bash run1p.sh开启单p训练
+ + +Docker侧训练步骤 +---------- + +1.导入镜像二进制包docker import ubuntuarmpytorch.tar REPOSITORY:TAG, 比如: + + docker import ubuntuarmpytorch.tar pytorch:b020 + +2.执行docker_start.sh后带三个参数:步骤1生成的REPOSITORY:TAG;数据集路径(训练和评测数据集都放到该路径下);模型执行路径;比如: + + ./docker_start.sh pytorch:b020 /train/imagenet /home/CRNN_for_Pytorch diff --git a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/docker_start.sh b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/docker_start.sh index 46ce9a02ec..944bca3cda 100644 --- a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/docker_start.sh +++ b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/docker_start.sh @@ -1,25 +1,25 @@ -#!/bin/bash - -docker_image=$1 -data_dir=$2 -model_dir=$3 - -docker run -it --ipc=host \ - --device=/dev/davinci0 \ - --device=/dev/davinci1 \ - --device=/dev/davinci2 \ - --device=/dev/davinci3 \ - --device=/dev/davinci4 \ - --device=/dev/davinci5 \ - --device=/dev/davinci6 \ - --device=/dev/davinci7 \ - --device=/dev/davinci_manager \ - --device=/dev/devmm_svm --device=/dev/hisi_hdc \ - -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ - -v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \ - -v ${model_dir}:${model_dir} \ - -v ${data_dir}:${data_dir} \ - -v /var/log/npu/conf/slog/slog.conf:/var/log/npu/conf/slog/slog.conf \ - -v /var/log/npu/slog/:/var/log/npu/slog -v /var/log/npu/profiling/:/var/log/npu/profiling \ - -v /var/log/npu/dump/:/var/log/npu/dump -v /var/log/npu/:/usr/slog ${docker_image} \ +#!/bin/bash + +docker_image=$1 +data_dir=$2 +model_dir=$3 + +docker run -it --ipc=host \ + --device=/dev/davinci0 \ + --device=/dev/davinci1 \ + --device=/dev/davinci2 \ + --device=/dev/davinci3 \ + --device=/dev/davinci4 \ + --device=/dev/davinci5 \ + --device=/dev/davinci6 \ + --device=/dev/davinci7 \ + --device=/dev/davinci_manager \ + --device=/dev/devmm_svm --device=/dev/hisi_hdc \ + -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ + -v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \ + -v ${model_dir}:${model_dir} \ + -v ${data_dir}:${data_dir} \ + -v /var/log/npu/conf/slog/slog.conf:/var/log/npu/conf/slog/slog.conf \ + -v /var/log/npu/slog/:/var/log/npu/slog -v /var/log/npu/profiling/:/var/log/npu/profiling \ + -v /var/log/npu/dump/:/var/log/npu/dump -v /var/log/npu/:/usr/slog ${docker_image} \ /bin/bash \ No newline at end of file diff --git a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/dscnn_train_pytorch.py b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/dscnn_train_pytorch.py index 2ee8d5ca87..d825d0c065 100644 --- a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/dscnn_train_pytorch.py +++ b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/dscnn_train_pytorch.py @@ -1,139 +1,139 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the MIT License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/MIT -# -# 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 os -import argparse - -import numpy as np -import torch -from torch.autograd import Variable -from torch.utils.data import DataLoader -import random -import torch.nn as nn -import torch.nn.functional as F - -from PIL import Image -import torch.npu - - -class DataLoad(): - def __init__(self, src_data_root, label_path): - self.images_list = [] - self.label_list = [] - self.num = 0 - - for img_name in os.listdir(src_data_root): - if img_name.endswith(".png"): - src_img_path = os.path.join(src_data_root, img_name) - label_img_path = os.path.join(label_path, img_name) - assert os.path.exists(label_img_path) - self.images_list.append([src_img_path]) - self.label_list.append([label_img_path]) - self.num += 1 - print('train image num: ', self.num) - - def __getitem__(self, index): - - src_image = Image.open(self.images_list[index][0]) - src_image = np.asarray(src_image).astype(np.float32) / 255. - label_image = Image.open(self.label_list[index][0]) - label_image = np.asarray(label_image).astype(np.float32) / 255. - - - src_image = torch.from_numpy(src_image.transpose(2, 0, 1)) - label_image = torch.from_numpy(label_image.transpose(2, 0, 1)) - - return src_image, label_image - - def __len__(self): - return self.num - - -class downsample_net(nn.Module): - def __init__(self): - super(downsample_net, self).__init__() - - self.conv1 = nn.Conv2d(3, 16, 3, 2, 1) - self.conv2 = nn.Conv2d(16, 3, 3, 1, 1) - self.relu = nn.ReLU() - - - def forward(self, x): - x = self.relu(self.conv1(x)) - return self.conv2(x) - - - -def train(src_data_root, label_path, batch_size, model_dir, epoch, lr, device, model_path=None): - dn = downsample_net() - dn = dn.to(device) - - if model_path is not None: - dn.load_state_dict(torch.load(model_path)) - - l1loss = torch.nn.L1Loss().to(device) - - opt = torch.optim.Adam(dn.parameters(), lr=lr) - - dataset = DataLoad(src_data_root, label_path) - train_loader = DataLoader(dataset=dataset, - batch_size=batch_size, - shuffle=True, - num_workers=16) - - all_loss = [] - for ep in range(epoch): - for step, (sample, label) in enumerate(train_loader): - src_image = Variable(sample).to(device) - label_image = Variable(label).to(device) - out = dn(src_image) - - out = nn.functional.interpolate(out, size=[1080, 1920], mode="bilinear") - loss = l1loss(out, label_image) - opt.zero_grad() - loss.backward() - opt.step() - - if step % 50 == 0: - print("epoch {} step {} loss {}".format(ep, step, loss.detach())) - - - - model_path = os.path.join(model_dir, "DSCNN_pytorch_l1_" + str(ep) + ".pkl") - torch.save(dn.state_dict(), model_path) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--device_id', type=int, default=0) - parser.add_argument('--train_data_path', type=str, default='') - parser.add_argument('--label_data_path', type=str, default='') - parser.add_argument('--batch_size', type=int, default=4) - parser.add_argument('--epoch', type=int, default=60) - parser.add_argument('--lr', type=float, default=0.00001) - parser.add_argument('--model_save_dir', type=str, default='') - parser.add_argument('--pre_trained_model_path', type=str, default=None) - args = parser.parse_args() - - device_str = 'npu:' + str(args.device_id) - torch.npu.set_device(device_str) - - train(device=device_str, - src_data_root=args.train_data_path, - batch_size=args.batch_size, - model_dir=args.model_save_dir, - label_path=args.label_data_path, - model_path=args.pre_trained_model_path, - epoch=args.epoch, - lr=args.lr) +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the MIT License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/MIT +# +# 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 os +import argparse + +import numpy as np +import torch +from torch.autograd import Variable +from torch.utils.data import DataLoader +import random +import torch.nn as nn +import torch.nn.functional as F + +from PIL import Image +import torch.npu + + +class DataLoad(): + def __init__(self, src_data_root, label_path): + self.images_list = [] + self.label_list = [] + self.num = 0 + + for img_name in os.listdir(src_data_root): + if img_name.endswith(".png"): + src_img_path = os.path.join(src_data_root, img_name) + label_img_path = os.path.join(label_path, img_name) + assert os.path.exists(label_img_path) + self.images_list.append([src_img_path]) + self.label_list.append([label_img_path]) + self.num += 1 + print('train image num: ', self.num) + + def __getitem__(self, index): + + src_image = Image.open(self.images_list[index][0]) + src_image = np.asarray(src_image).astype(np.float32) / 255. + label_image = Image.open(self.label_list[index][0]) + label_image = np.asarray(label_image).astype(np.float32) / 255. + + + src_image = torch.from_numpy(src_image.transpose(2, 0, 1)) + label_image = torch.from_numpy(label_image.transpose(2, 0, 1)) + + return src_image, label_image + + def __len__(self): + return self.num + + +class downsample_net(nn.Module): + def __init__(self): + super(downsample_net, self).__init__() + + self.conv1 = nn.Conv2d(3, 16, 3, 2, 1) + self.conv2 = nn.Conv2d(16, 3, 3, 1, 1) + self.relu = nn.ReLU() + + + def forward(self, x): + x = self.relu(self.conv1(x)) + return self.conv2(x) + + + +def train(src_data_root, label_path, batch_size, model_dir, epoch, lr, device, model_path=None): + dn = downsample_net() + dn = dn.to(device) + + if model_path is not None: + dn.load_state_dict(torch.load(model_path)) + + l1loss = torch.nn.L1Loss().to(device) + + opt = torch.optim.Adam(dn.parameters(), lr=lr) + + dataset = DataLoad(src_data_root, label_path) + train_loader = DataLoader(dataset=dataset, + batch_size=batch_size, + shuffle=True, + num_workers=16) + + all_loss = [] + for ep in range(epoch): + for step, (sample, label) in enumerate(train_loader): + src_image = Variable(sample).to(device) + label_image = Variable(label).to(device) + out = dn(src_image) + + out = nn.functional.interpolate(out, size=[1080, 1920], mode="bilinear") + loss = l1loss(out, label_image) + opt.zero_grad() + loss.backward() + opt.step() + + if step % 50 == 0: + print("epoch {} step {} loss {}".format(ep, step, loss.detach())) + + + + model_path = os.path.join(model_dir, "DSCNN_pytorch_l1_" + str(ep) + ".pkl") + torch.save(dn.state_dict(), model_path) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--device_id', type=int, default=0) + parser.add_argument('--train_data_path', type=str, default='') + parser.add_argument('--label_data_path', type=str, default='') + parser.add_argument('--batch_size', type=int, default=4) + parser.add_argument('--epoch', type=int, default=60) + parser.add_argument('--lr', type=float, default=0.00001) + parser.add_argument('--model_save_dir', type=str, default='') + parser.add_argument('--pre_trained_model_path', type=str, default=None) + args = parser.parse_args() + + device_str = 'npu:' + str(args.device_id) + torch.npu.set_device(device_str) + + train(device=device_str, + src_data_root=args.train_data_path, + batch_size=args.batch_size, + model_dir=args.model_save_dir, + label_path=args.label_data_path, + model_path=args.pre_trained_model_path, + epoch=args.epoch, + lr=args.lr) diff --git a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/npu_set_env.sh b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/npu_set_env.sh index bf52cfcb77..cda0d6f857 100644 --- a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/npu_set_env.sh +++ b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/npu_set_env.sh @@ -1,30 +1,30 @@ -############## toolkit situation ################ -#export LD_LIBRARY_PATH=/usr/local/:/usr/local/python3.7.5/lib/:/usr/local/openblas/lib:/usr/local/lib/:/usr/lib64/:/usr/lib/:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/lib64/:/usr/local/Ascend/driver/lib64/common/:/usr/local/Ascend/driver/lib64/driver/:/usr/local/Ascend/add-ons/:/usr/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH -#export PATH=$PATH:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/ccec_compiler/bin/:/usr/local/Ascend/ascend-toolkit/latest/toolkit/tools/ide_daemon/bin/ -#export ASCEND_OPP_PATH=/usr/local/Ascend/ascend-toolkit/latest/opp/ -#export OPTION_EXEC_EXTERN_PLUGIN_PATH=/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libfe.so:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libaicpu_engine.so:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libge_local_engine.so -#export PYTHONPATH=/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/python/site-packages/:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/python/site-packages/auto_tune.egg/auto_tune:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/python/site-packages/schedule_search.egg:$PYTHONPATH - - -############## nnae situation ################ - - -if [ -d /usr/local/Ascend/nnae/latest ];then - export LD_LIBRARY_PATH=/usr/local/:/usr/local/python3.7.5/lib/:/usr/local/openblas/lib:/usr/local/lib/:/usr/lib64/:/usr/lib/:/usr/local/Ascend/nnae/latest/fwkacllib/lib64/:/usr/local/Ascend/driver/lib64/common/:/usr/local/Ascend/driver/lib64/driver/:/usr/local/Ascend/add-ons/:/usr/lib/aarch64_64-linux-gnu:$LD_LIBRARY_PATH - export PATH=$PATH:/usr/local/Ascend/nnae/latest/fwkacllib/ccec_compiler/bin/:/usr/local/Ascend/nnae/latest/toolkit/tools/ide_daemon/bin/ - export ASCEND_OPP_PATH=/usr/local/Ascend/nnae/latest/opp/ - export OPTION_EXEC_EXTERN_PLUGIN_PATH=/usr/local/Ascend/nnae/latest/fwkacllib/lib64/plugin/opskernel/libfe.so:/usr/local/Ascend/nnae/latest/fwkacllib/lib64/plugin/opskernel/libaicpu_engine.so:/usr/local/Ascend/nnae/latest/fwkacllib/lib64/plugin/opskernel/libge_local_engine.so - export PYTHONPATH=/usr/local/Ascend/nnae/latest/fwkacllib/python/site-packages/:/usr/local/Ascend/nnae/latest/fwkacllib/python/site-packages/auto_tune.egg/auto_tune:/usr/local/Ascend/nnae/latest/fwkacllib/python/site-packages/schedule_search.egg:$PYTHONPATH -else - export LD_LIBRARY_PATH=/usr/local/:/usr/local/lib/:/usr/lib64/:/usr/lib/:/usr/local/python3.7.5/lib/:/usr/local/openblas/lib:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/lib64/:/usr/local/Ascend/driver/lib64/common/:/usr/local/Ascend/driver/lib64/driver/:/usr/local/Ascend/add-ons/:/usr/lib/aarch64-linux-gnu:$LD_LIBRARY_PATH - export PATH=$PATH:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/ccec_compiler/bin/:/usr/local/Ascend/ascend-toolkit/latest/toolkit/tools/ide_daemon/bin/ - export ASCEND_OPP_PATH=/usr/local/Ascend/ascend-toolkit/latest/opp/ - export OPTION_EXEC_EXTERN_PLUGIN_PATH=/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libfe.so:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libaicpu_engine.so:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libge_local_engine.so - export PYTHONPATH=/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/python/site-packages/:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/python/site-packages/auto_tune.egg/auto_tune:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/python/site-packages/schedule_search.egg:$PYTHONPATH -fi - -# ln -s /usr/local/Ascend/ascend-toolkit/latest/toolkit/bin/adc /usr/local/bin/ - -export SLOG_PRINT_TO_STDOUT=0 - +############## toolkit situation ################ +#export LD_LIBRARY_PATH=/usr/local/:/usr/local/python3.7.5/lib/:/usr/local/openblas/lib:/usr/local/lib/:/usr/lib64/:/usr/lib/:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/lib64/:/usr/local/Ascend/driver/lib64/common/:/usr/local/Ascend/driver/lib64/driver/:/usr/local/Ascend/add-ons/:/usr/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH +#export PATH=$PATH:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/ccec_compiler/bin/:/usr/local/Ascend/ascend-toolkit/latest/toolkit/tools/ide_daemon/bin/ +#export ASCEND_OPP_PATH=/usr/local/Ascend/ascend-toolkit/latest/opp/ +#export OPTION_EXEC_EXTERN_PLUGIN_PATH=/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libfe.so:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libaicpu_engine.so:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libge_local_engine.so +#export PYTHONPATH=/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/python/site-packages/:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/python/site-packages/auto_tune.egg/auto_tune:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/python/site-packages/schedule_search.egg:$PYTHONPATH + + +############## nnae situation ################ + + +if [ -d /usr/local/Ascend/nnae/latest ];then + export LD_LIBRARY_PATH=/usr/local/:/usr/local/python3.7.5/lib/:/usr/local/openblas/lib:/usr/local/lib/:/usr/lib64/:/usr/lib/:/usr/local/Ascend/nnae/latest/fwkacllib/lib64/:/usr/local/Ascend/driver/lib64/common/:/usr/local/Ascend/driver/lib64/driver/:/usr/local/Ascend/add-ons/:/usr/lib/aarch64_64-linux-gnu:$LD_LIBRARY_PATH + export PATH=$PATH:/usr/local/Ascend/nnae/latest/fwkacllib/ccec_compiler/bin/:/usr/local/Ascend/nnae/latest/toolkit/tools/ide_daemon/bin/ + export ASCEND_OPP_PATH=/usr/local/Ascend/nnae/latest/opp/ + export OPTION_EXEC_EXTERN_PLUGIN_PATH=/usr/local/Ascend/nnae/latest/fwkacllib/lib64/plugin/opskernel/libfe.so:/usr/local/Ascend/nnae/latest/fwkacllib/lib64/plugin/opskernel/libaicpu_engine.so:/usr/local/Ascend/nnae/latest/fwkacllib/lib64/plugin/opskernel/libge_local_engine.so + export PYTHONPATH=/usr/local/Ascend/nnae/latest/fwkacllib/python/site-packages/:/usr/local/Ascend/nnae/latest/fwkacllib/python/site-packages/auto_tune.egg/auto_tune:/usr/local/Ascend/nnae/latest/fwkacllib/python/site-packages/schedule_search.egg:$PYTHONPATH +else + export LD_LIBRARY_PATH=/usr/local/:/usr/local/lib/:/usr/lib64/:/usr/lib/:/usr/local/python3.7.5/lib/:/usr/local/openblas/lib:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/lib64/:/usr/local/Ascend/driver/lib64/common/:/usr/local/Ascend/driver/lib64/driver/:/usr/local/Ascend/add-ons/:/usr/lib/aarch64-linux-gnu:$LD_LIBRARY_PATH + export PATH=$PATH:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/ccec_compiler/bin/:/usr/local/Ascend/ascend-toolkit/latest/toolkit/tools/ide_daemon/bin/ + export ASCEND_OPP_PATH=/usr/local/Ascend/ascend-toolkit/latest/opp/ + export OPTION_EXEC_EXTERN_PLUGIN_PATH=/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libfe.so:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libaicpu_engine.so:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/lib64/plugin/opskernel/libge_local_engine.so + export PYTHONPATH=/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/python/site-packages/:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/python/site-packages/auto_tune.egg/auto_tune:/usr/local/Ascend/ascend-toolkit/latest/fwkacllib/python/site-packages/schedule_search.egg:$PYTHONPATH +fi + +# ln -s /usr/local/Ascend/ascend-toolkit/latest/toolkit/bin/adc /usr/local/bin/ + +export SLOG_PRINT_TO_STDOUT=0 + export TASK_QUEUE_ENABLE=1 \ No newline at end of file diff --git a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/pkltar2onnx.py b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/pkltar2onnx.py index ee7c9af591..475d1dbf7c 100644 --- a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/pkltar2onnx.py +++ b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/pkltar2onnx.py @@ -1,104 +1,104 @@ -# Copyright 2021 Huawei Technologies Co., Ltd -# -# Licensed under the MIT License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/MIT -# -# 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 torch -import torch.nn as nn -import torch.nn.functional as F -import numpy as np -from torch.autograd import Variable - -class downsample_net(nn.Module): - def __init__(self): - super(downsample_net, self).__init__() - self.conv1 = nn.Conv2d(3, 16, 3, 2, 1) - self.conv2 = nn.Conv2d(16, 3, 3, 1, 1) - self.relu = nn.ReLU() - weight_list = [ - [ - [ - [ - 0.257 - ] - ], - [ - [ - 0.504 - ] - ], - [ - [ - 0.098 - ] - ] - ], - - [ - [ - [ - -0.148 - ] - ], - [ - [ - -0.291 - ] - ], - [ - [ - 0.439 - - ] - ] - ], - - [ - [ - [ - 0.439 - ] - ], - [ - [ - -0.368 - ] - ], - [ - [ - -0.071 - ] - ] - ] -] - bias_list = [0.0627450980392157, 0.5019607843137255, 0.5019607843137255] - self.weight = Variable(torch.from_numpy(np.array(weight_list, dtype = 'float32'))) - self.bias = Variable(torch.from_numpy(np.array(bias_list, dtype = 'float32'))) - self.conv_define = nn.Conv2d(3, 3, 1, 1) - self.conv_define.weight.data = self.weight - self.conv_define.bias.data = self.bias - - def forward(self, x): - x = self.relu(self.conv1(x)) - out = self.conv2(x) - out = self.conv_define(out) - out = torch.mul(out, 255.) - return out - - -model_path = "/path/to/pkl" -dn = downsample_net() -dn.load_state_dict(torch.load(model_path, map_location=torch.device('cpu')), strict = False) -print(dn) -dummy_input = torch.randn(1, 3, 1152, 1440) -torch.onnx.export(dn, dummy_input, "/path/to/onnx", verbose=True, keep_initializers_as_inputs=True) - +# Copyright 2021 Huawei Technologies Co., Ltd +# +# Licensed under the MIT License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://opensource.org/licenses/MIT +# +# 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 torch +import torch.nn as nn +import torch.nn.functional as F +import numpy as np +from torch.autograd import Variable + +class downsample_net(nn.Module): + def __init__(self): + super(downsample_net, self).__init__() + self.conv1 = nn.Conv2d(3, 16, 3, 2, 1) + self.conv2 = nn.Conv2d(16, 3, 3, 1, 1) + self.relu = nn.ReLU() + weight_list = [ + [ + [ + [ + 0.257 + ] + ], + [ + [ + 0.504 + ] + ], + [ + [ + 0.098 + ] + ] + ], + + [ + [ + [ + -0.148 + ] + ], + [ + [ + -0.291 + ] + ], + [ + [ + 0.439 + + ] + ] + ], + + [ + [ + [ + 0.439 + ] + ], + [ + [ + -0.368 + ] + ], + [ + [ + -0.071 + ] + ] + ] +] + bias_list = [0.0627450980392157, 0.5019607843137255, 0.5019607843137255] + self.weight = Variable(torch.from_numpy(np.array(weight_list, dtype = 'float32'))) + self.bias = Variable(torch.from_numpy(np.array(bias_list, dtype = 'float32'))) + self.conv_define = nn.Conv2d(3, 3, 1, 1) + self.conv_define.weight.data = self.weight + self.conv_define.bias.data = self.bias + + def forward(self, x): + x = self.relu(self.conv1(x)) + out = self.conv2(x) + out = self.conv_define(out) + out = torch.mul(out, 255.) + return out + + +model_path = "/path/to/pkl" +dn = downsample_net() +dn.load_state_dict(torch.load(model_path, map_location=torch.device('cpu')), strict = False) +print(dn) +dummy_input = torch.randn(1, 3, 1152, 1440) +torch.onnx.export(dn, dummy_input, "/path/to/onnx", verbose=True, keep_initializers_as_inputs=True) + diff --git a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/requirements.txt b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/requirements.txt index 43aa6450fc..628efc0d6d 100644 --- a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/requirements.txt +++ b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/requirements.txt @@ -1,5 +1,5 @@ -torch==1.5.0 -apex -torchvision -numpy -Pillow==8.1.0 +torch==1.5.0 +apex +torchvision +numpy +Pillow==8.1.0 diff --git a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/run1p.sh b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/run1p.sh index 1c59be0db2..b7755c0313 100644 --- a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/run1p.sh +++ b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/run1p.sh @@ -1,15 +1,15 @@ -#!/usr/bin/env bash -source npu_set_env.sh -export SLOG_PRINT_TO_STDOUT=0 -export TASK_QUEUE_ENABLE=1 -export PTCOPY_ENABLE=1 - - -python dscnn_train_pytorch.py --device_id=0 \ - --train_data_path=../datasets/train_data \ - --label_data_path=../datasets/label_data \ - --batch_size=8 \ - --epoch=60 \ - --lr=0.00001 \ - --model_save_dir=./models \ +#!/usr/bin/env bash +source npu_set_env.sh +export SLOG_PRINT_TO_STDOUT=0 +export TASK_QUEUE_ENABLE=1 +export PTCOPY_ENABLE=1 + + +python dscnn_train_pytorch.py --device_id=0 \ + --train_data_path=../datasets/train_data \ + --label_data_path=../datasets/label_data \ + --batch_size=8 \ + --epoch=60 \ + --lr=0.00001 \ + --model_save_dir=./models \ # --pre_trained_model_path=./models/DCNN_bilinear_0226_l1_0.025154941563113792_99.pkl \ No newline at end of file diff --git a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/run_to_onnx.sh b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/run_to_onnx.sh index a610204ae5..f667562759 100644 --- a/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/run_to_onnx.sh +++ b/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch/run_to_onnx.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash -source npu_set_env.sh - +#!/usr/bin/env bash +source npu_set_env.sh + python3.7 pkltar2onnx.py \ No newline at end of file diff --git a/PyTorch/dev/nlp/FairSeq_Transformer_ID0496_for_PyTorch/test/train_full_1p_bs512.sh b/PyTorch/dev/nlp/FairSeq_Transformer_ID0496_for_PyTorch/test/train_full_1p_bs512.sh index ca3f13a102..6f0a63d013 100644 --- a/PyTorch/dev/nlp/FairSeq_Transformer_ID0496_for_PyTorch/test/train_full_1p_bs512.sh +++ b/PyTorch/dev/nlp/FairSeq_Transformer_ID0496_for_PyTorch/test/train_full_1p_bs512.sh @@ -1,214 +1,214 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -#export ASCEND_SLOG_PRINT_TO_STDOUT=1 -export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID -#集合通信参数,不需要修改 - -export RANK_SIZE=1 -export JOB_ID=10087 -RANK_ID_START=0 - -#进入到conda环境 -#source activate py8 - - - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="FairSeq_Transformer_ID0496_for_PyTorch" -#训练epoch -train_epochs=2000 -#训练batch_size -batch_size=512 -#训练step -#train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.495 - -#TF2.X独有,不需要修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False -autotune=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_full_1p.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is False - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` -elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#进入训练脚本目录,需要模型审视修改 -cd $cur_path/../ - -#python3 setup.py build_ext --inplace -pip3 install --editable . -#sed -i "s|pass|break|g" train.py -#sed -i "s|data/LibriSpeech|$data_path/LibriSpeech|g" config/libri/asr_example.yaml - -#修改epoch参数 - - -for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); -do - #设置环境变量,不需要修改 - echo "Device ID: $ASCEND_DEVICE_ID" - export RANK_ID=$RANK_ID - - - - #创建DeviceID输出目录,不需要修改 - if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - fi - - #绑核,不需要绑核的模型删除,需要绑核的模型根据实际修改 - #cpucount=`lscpu | grep "CPU(s):" | head -n 1 | awk '{print $2}'` - #cpustep=`expr $cpucount / 8` - #echo "taskset c steps:" $cpustep - #let a=RANK_ID*$cpustep - #let b=RANK_ID+1 - #let c=b*$cpustep-1 - - #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 - nohup python3 train.py $data_path/iwslt14.tokenized.de-en \ - --arch transformer \ - --optimizer adam \ - --adam-betas '(0.9, 0.98)' \ - --clip-norm 0.0 \ - --lr 0.00006 \ - --lr-scheduler inverse_sqrt \ - --warmup-updates 4000 \ - --dropout 0.00 \ - --weight-decay 0.0001 \ - --source-lang de \ - --target-lang en \ - --decoder-attention-heads 4 \ - --decoder-ffn-embed-dim 1024 \ - --encoder-attention-heads 4 \ - --encoder-ffn-embed-dim 1024 \ - --seed 12345 \ - --fp16 \ - --fp16-scale-window 1500 \ - --ddp-backend no_c10d \ - --disable-validation \ - --distributed-no-spawn \ - --required-batch-size-multiple 512 \ - --batch-size 512 \ - --max-epoch 2000 \ - --max-source-positions 1024 \ - --max-target-positions 1024 \ - --num-workers 1 \ - --log-interval 1 \ - --save-interval 1 \ - --share-decoder-input-output-embed > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & -done -wait - -#conda deactivate -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -Time=`grep "iteration" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |awk -F "time =" '{print $2}'|awk -F "ms" '{print $1}'|tail -n +6|awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` -FPS=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'*1000/'${Time}'}'` - - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep eval_accuracy $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|grep -v mlp_log|awk 'END {print $5}'| sed 's/,//g' |cut -c 1-5` -#打印,不需要修改 -train_accuracy="Loss" -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#稳定性精度看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -##获取性能数据 -#吞吐量,不需要修改 -ActualFPS=${FPS} -#单迭代训练时长,不需要修改 -TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep "loss=" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "loss=" '{print $2}'|awk -F "," '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +#export ASCEND_SLOG_PRINT_TO_STDOUT=1 +export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID +#集合通信参数,不需要修改 + +export RANK_SIZE=1 +export JOB_ID=10087 +RANK_ID_START=0 + +#进入到conda环境 +#source activate py8 + + + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="FairSeq_Transformer_ID0496_for_PyTorch" +#训练epoch +train_epochs=2000 +#训练batch_size +batch_size=512 +#训练step +#train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.495 + +#TF2.X独有,不需要修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False +autotune=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_full_1p.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is False + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` +elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#进入训练脚本目录,需要模型审视修改 +cd $cur_path/../ + +#python3 setup.py build_ext --inplace +pip3 install --editable . +#sed -i "s|pass|break|g" train.py +#sed -i "s|data/LibriSpeech|$data_path/LibriSpeech|g" config/libri/asr_example.yaml + +#修改epoch参数 + + +for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); +do + #设置环境变量,不需要修改 + echo "Device ID: $ASCEND_DEVICE_ID" + export RANK_ID=$RANK_ID + + + + #创建DeviceID输出目录,不需要修改 + if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + fi + + #绑核,不需要绑核的模型删除,需要绑核的模型根据实际修改 + #cpucount=`lscpu | grep "CPU(s):" | head -n 1 | awk '{print $2}'` + #cpustep=`expr $cpucount / 8` + #echo "taskset c steps:" $cpustep + #let a=RANK_ID*$cpustep + #let b=RANK_ID+1 + #let c=b*$cpustep-1 + + #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 + nohup python3 train.py $data_path/iwslt14.tokenized.de-en \ + --arch transformer \ + --optimizer adam \ + --adam-betas '(0.9, 0.98)' \ + --clip-norm 0.0 \ + --lr 0.00006 \ + --lr-scheduler inverse_sqrt \ + --warmup-updates 4000 \ + --dropout 0.00 \ + --weight-decay 0.0001 \ + --source-lang de \ + --target-lang en \ + --decoder-attention-heads 4 \ + --decoder-ffn-embed-dim 1024 \ + --encoder-attention-heads 4 \ + --encoder-ffn-embed-dim 1024 \ + --seed 12345 \ + --fp16 \ + --fp16-scale-window 1500 \ + --ddp-backend no_c10d \ + --disable-validation \ + --distributed-no-spawn \ + --required-batch-size-multiple 512 \ + --batch-size 512 \ + --max-epoch 2000 \ + --max-source-positions 1024 \ + --max-target-positions 1024 \ + --num-workers 1 \ + --log-interval 1 \ + --save-interval 1 \ + --share-decoder-input-output-embed > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & +done +wait + +#conda deactivate +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +Time=`grep "iteration" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |awk -F "time =" '{print $2}'|awk -F "ms" '{print $1}'|tail -n +6|awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` +FPS=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'*1000/'${Time}'}'` + + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep eval_accuracy $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|grep -v mlp_log|awk 'END {print $5}'| sed 's/,//g' |cut -c 1-5` +#打印,不需要修改 +train_accuracy="Loss" +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#稳定性精度看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +##获取性能数据 +#吞吐量,不需要修改 +ActualFPS=${FPS} +#单迭代训练时长,不需要修改 +TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep "loss=" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "loss=" '{print $2}'|awk -F "," '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/dev/nlp/FairSeq_Transformer_ID0496_for_PyTorch/test/train_performance_1p_bs512.sh b/PyTorch/dev/nlp/FairSeq_Transformer_ID0496_for_PyTorch/test/train_performance_1p_bs512.sh index 460f1e01fc..9649fd4344 100644 --- a/PyTorch/dev/nlp/FairSeq_Transformer_ID0496_for_PyTorch/test/train_performance_1p_bs512.sh +++ b/PyTorch/dev/nlp/FairSeq_Transformer_ID0496_for_PyTorch/test/train_performance_1p_bs512.sh @@ -1,214 +1,214 @@ -#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -#export ASCEND_SLOG_PRINT_TO_STDOUT=1 -export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID -#集合通信参数,不需要修改 - -export RANK_SIZE=1 -export JOB_ID=10087 -RANK_ID_START=0 - -#进入到conda环境 -#source activate py8 - - - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="FairSeq_Transformer_ID0496_for_PyTorch" -#训练epoch -train_epochs=1 -#训练batch_size -batch_size=512 -#训练step -#train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.495 - -#TF2.X独有,不需要修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False -autotune=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_full_1p.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is False - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` -elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#进入训练脚本目录,需要模型审视修改 -cd $cur_path/../ - -#python3 setup.py build_ext --inplace -pip3 install --editable . -#sed -i "s|pass|break|g" train.py -#sed -i "s|data/LibriSpeech|$data_path/LibriSpeech|g" config/libri/asr_example.yaml - -#修改epoch参数 - - -for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); -do - #设置环境变量,不需要修改 - echo "Device ID: $ASCEND_DEVICE_ID" - export RANK_ID=$RANK_ID - - - - #创建DeviceID输出目录,不需要修改 - if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - fi - - #绑核,不需要绑核的模型删除,需要绑核的模型根据实际修改 - #cpucount=`lscpu | grep "CPU(s):" | head -n 1 | awk '{print $2}'` - #cpustep=`expr $cpucount / 8` - #echo "taskset c steps:" $cpustep - #let a=RANK_ID*$cpustep - #let b=RANK_ID+1 - #let c=b*$cpustep-1 - - #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 - nohup python3 train.py $data_path/iwslt14.tokenized.de-en \ - --arch transformer \ - --optimizer adam \ - --adam-betas '(0.9, 0.98)' \ - --clip-norm 0.0 \ - --lr 0.00006 \ - --lr-scheduler inverse_sqrt \ - --warmup-updates 4000 \ - --dropout 0.00 \ - --weight-decay 0.0001 \ - --source-lang de \ - --target-lang en \ - --decoder-attention-heads 4 \ - --decoder-ffn-embed-dim 1024 \ - --encoder-attention-heads 4 \ - --encoder-ffn-embed-dim 1024 \ - --seed 12345 \ - --fp16 \ - --fp16-scale-window 1500 \ - --ddp-backend no_c10d \ - --disable-validation \ - --distributed-no-spawn \ - --required-batch-size-multiple 512 \ - --batch-size 512 \ - --max-epoch 1 \ - --max-source-positions 1024 \ - --max-target-positions 1024 \ - --num-workers 1 \ - --log-interval 1 \ - --save-interval 1 \ - --share-decoder-input-output-embed > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & -done -wait - -#conda deactivate -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -#Time=`grep "iteration" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |awk -F "time =" '{print $2}'|awk -F "ms" '{print $1}'|tail -n +6|awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` -Time=`grep "iteration" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |awk -F "time =" '{print $2}'|awk -F "ms" '{print $1}'| grep -v "^$" |tail -n +6|awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` -FPS=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'*1000/'${Time}'}'` - - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep eval_accuracy $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|grep -v mlp_log|awk 'END {print $5}'| sed 's/,//g' |cut -c 1-5` -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -#echo "E2E Training Duration sec : $e2e_time" - -#稳定性精度看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据 -#吞吐量,不需要修改 -ActualFPS=${FPS} -#单迭代训练时长,不需要修改 -TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep "loss=" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "loss=" '{print $2}'|awk -F "," '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -#echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +#export ASCEND_SLOG_PRINT_TO_STDOUT=1 +export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID +#集合通信参数,不需要修改 + +export RANK_SIZE=1 +export JOB_ID=10087 +RANK_ID_START=0 + +#进入到conda环境 +#source activate py8 + + + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="FairSeq_Transformer_ID0496_for_PyTorch" +#训练epoch +train_epochs=1 +#训练batch_size +batch_size=512 +#训练step +#train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.495 + +#TF2.X独有,不需要修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False +autotune=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_full_1p.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is False + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` +elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#进入训练脚本目录,需要模型审视修改 +cd $cur_path/../ + +#python3 setup.py build_ext --inplace +pip3 install --editable . +#sed -i "s|pass|break|g" train.py +#sed -i "s|data/LibriSpeech|$data_path/LibriSpeech|g" config/libri/asr_example.yaml + +#修改epoch参数 + + +for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); +do + #设置环境变量,不需要修改 + echo "Device ID: $ASCEND_DEVICE_ID" + export RANK_ID=$RANK_ID + + + + #创建DeviceID输出目录,不需要修改 + if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + fi + + #绑核,不需要绑核的模型删除,需要绑核的模型根据实际修改 + #cpucount=`lscpu | grep "CPU(s):" | head -n 1 | awk '{print $2}'` + #cpustep=`expr $cpucount / 8` + #echo "taskset c steps:" $cpustep + #let a=RANK_ID*$cpustep + #let b=RANK_ID+1 + #let c=b*$cpustep-1 + + #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 + nohup python3 train.py $data_path/iwslt14.tokenized.de-en \ + --arch transformer \ + --optimizer adam \ + --adam-betas '(0.9, 0.98)' \ + --clip-norm 0.0 \ + --lr 0.00006 \ + --lr-scheduler inverse_sqrt \ + --warmup-updates 4000 \ + --dropout 0.00 \ + --weight-decay 0.0001 \ + --source-lang de \ + --target-lang en \ + --decoder-attention-heads 4 \ + --decoder-ffn-embed-dim 1024 \ + --encoder-attention-heads 4 \ + --encoder-ffn-embed-dim 1024 \ + --seed 12345 \ + --fp16 \ + --fp16-scale-window 1500 \ + --ddp-backend no_c10d \ + --disable-validation \ + --distributed-no-spawn \ + --required-batch-size-multiple 512 \ + --batch-size 512 \ + --max-epoch 1 \ + --max-source-positions 1024 \ + --max-target-positions 1024 \ + --num-workers 1 \ + --log-interval 1 \ + --save-interval 1 \ + --share-decoder-input-output-embed > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & +done +wait + +#conda deactivate +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +#Time=`grep "iteration" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |awk -F "time =" '{print $2}'|awk -F "ms" '{print $1}'|tail -n +6|awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` +Time=`grep "iteration" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |awk -F "time =" '{print $2}'|awk -F "ms" '{print $1}'| grep -v "^$" |tail -n +6|awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` +FPS=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'*1000/'${Time}'}'` + + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep eval_accuracy $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|grep -v mlp_log|awk 'END {print $5}'| sed 's/,//g' |cut -c 1-5` +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +#echo "E2E Training Duration sec : $e2e_time" + +#稳定性精度看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据 +#吞吐量,不需要修改 +ActualFPS=${FPS} +#单迭代训练时长,不需要修改 +TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep "loss=" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "loss=" '{print $2}'|awk -F "," '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/dev/nlp/FairSeq_Transformer_ID0496_for_PyTorch/test/train_performance_1p_dynamic.sh b/PyTorch/dev/nlp/FairSeq_Transformer_ID0496_for_PyTorch/test/train_performance_1p_dynamic.sh index e5cf71cffb..cfe05e6f44 100644 --- a/PyTorch/dev/nlp/FairSeq_Transformer_ID0496_for_PyTorch/test/train_performance_1p_dynamic.sh +++ b/PyTorch/dev/nlp/FairSeq_Transformer_ID0496_for_PyTorch/test/train_performance_1p_dynamic.sh @@ -1,215 +1,215 @@ -1#!/bin/bash - -#当前路径,不需要修改 -cur_path=`pwd` -#export ASCEND_SLOG_PRINT_TO_STDOUT=1 -export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID -#集合通信参数,不需要修改 - -export RANK_SIZE=1 -export JOB_ID=10087 -RANK_ID_START=0 - -#进入到conda环境 -#source activate py8 - - - -# 数据集路径,保持为空,不需要修改 -data_path="" - -#基础参数,需要模型审视修改 -#网络名称,同目录名称 -Network="FairSeq_Transformer_ID0496_for_PyTorch" -#训练epoch -train_epochs=4 -#训练batch_size -batch_size=32 -#训练step -#train_steps=`expr 1281167 / ${batch_size}` -#学习率 -learning_rate=0.495 - -#TF2.X独有,不需要修改 -#export NPU_LOOP_SIZE=${train_steps} - -#维测参数,precision_mode需要模型审视修改 -precision_mode="allow_mix_precision" -#维持参数,以下不需要修改 -over_dump=False -data_dump_flag=False -data_dump_step="10" -profiling=False -autotune=False - -# 帮助信息,不需要修改 -if [[ $1 == --help || $1 == -h ]];then - echo"usage:./train_full_1p.sh " - echo " " - echo "parameter explain: - --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) - --over_dump if or not over detection, default is False - --data_dump_flag data dump flag, default is False - --data_dump_step data dump step, default is 10 - --profiling if or not profiling for performance debug, default is False - --data_path source data of training - -h/--help show help message - " - exit 1 -fi - -#参数校验,不需要修改 -for para in $* -do - if [[ $para == --precision_mode* ]];then - precision_mode=`echo ${para#*=}` -elif [[ $para == --over_dump* ]];then - over_dump=`echo ${para#*=}` - over_dump_path=${cur_path}/output/overflow_dump - mkdir -p ${over_dump_path} - elif [[ $para == --data_dump_flag* ]];then - data_dump_flag=`echo ${para#*=}` - data_dump_path=${cur_path}/output/data_dump - mkdir -p ${data_dump_path} - elif [[ $para == --data_dump_step* ]];then - data_dump_step=`echo ${para#*=}` - elif [[ $para == --profiling* ]];then - profiling=`echo ${para#*=}` - profiling_dump_path=${cur_path}/output/profiling - mkdir -p ${profiling_dump_path} - elif [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - -#训练开始时间,不需要修改 -start_time=$(date +%s) - -#进入训练脚本目录,需要模型审视修改 -cd $cur_path/../ - -#python3 setup.py build_ext --inplace -pip3 install --editable . -#sed -i "s|pass|break|g" train.py -#sed -i "s|data/LibriSpeech|$data_path/LibriSpeech|g" config/libri/asr_example.yaml - -#修改epoch参数 - - -for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); -do - #设置环境变量,不需要修改 - echo "Device ID: $ASCEND_DEVICE_ID" - export RANK_ID=$RANK_ID - - - - #创建DeviceID输出目录,不需要修改 - if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then - rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - else - mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt - fi - - #绑核,不需要绑核的模型删除,需要绑核的模型根据实际修改 - #cpucount=`lscpu | grep "CPU(s):" | head -n 1 | awk '{print $2}'` - #cpustep=`expr $cpucount / 8` - #echo "taskset c steps:" $cpustep - #let a=RANK_ID*$cpustep - #let b=RANK_ID+1 - #let c=b*$cpustep-1 - - #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 - nohup python3 train.py $data_path/iwslt14.tokenized.de-en \ - --arch transformer \ - --optimizer adam \ - --adam-betas '(0.9, 0.98)' \ - --clip-norm 0.0 \ - --lr 0.00006 \ - --lr-scheduler inverse_sqrt \ - --warmup-updates 4000 \ - --device-id $ASCEND_DEVICE_ID \ - --weight-decay 0.0001 \ - --source-lang de \ - --target-lang en \ - --decoder-attention-heads 4 \ - --decoder-ffn-embed-dim 1024 \ - --encoder-attention-heads 4 \ - --encoder-ffn-embed-dim 1024 \ - --seed 12345 \ - --fp16 \ - --fp16-scale-window 1500 \ - --ddp-backend no_c10d \ - --disable-validation \ - --distributed-no-spawn \ - --max-tokens 15000 \ - --required-batch-size-multiple 32 \ - --max-epoch ${train_epochs} \ - --max-source-positions 1024 \ - --max-target-positions 1024 \ - --num-workers 1 \ - --log-interval 1 \ - --save-interval 1 \ - --share-decoder-input-output-embed > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & -done -wait - -#conda deactivate -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -#Time=`grep "iteration" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |awk -F "time =" '{print $2}'|awk -F "ms" '{print $1}'| grep -v "^$" |tail -n +6|awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` -FPS=`grep -rn "wps=" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk -F "wps=" '{print $2}' | awk -F "," '{print $1}' | awk '{if(NR>=325){print}}' | awk 'END {print}' |sed s/[[:space:]]//g` -#FPS=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'*1000/'${Time}'}'` - - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#输出训练精度,需要模型审视修改 -#train_accuracy=`grep eval_accuracy $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|grep -v mlp_log|awk 'END {print $5}'| sed 's/,//g' |cut -c 1-5` -#打印,不需要修改 -#echo "Final Train Accuracy : ${train_accuracy}" -#echo "E2E Training Duration sec : $e2e_time" - -#稳定性精度看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -##获取性能数据 -#吞吐量,不需要修改 -ActualFPS=${FPS} -#单迭代训练时长,不需要修改 -#TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` -TrainingTime=`grep "iteration" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |awk -F "time =" '{print $2}'|awk -F "ms" '{print $1}'| grep -v "^$" |tail -n +6|awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 -grep "loss=" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "loss=" '{print $2}'|awk -F "," '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -#echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +1#!/bin/bash + +#当前路径,不需要修改 +cur_path=`pwd` +#export ASCEND_SLOG_PRINT_TO_STDOUT=1 +export NPU_CALCULATE_DEVICE=$ASCEND_DEVICE_ID +#集合通信参数,不需要修改 + +export RANK_SIZE=1 +export JOB_ID=10087 +RANK_ID_START=0 + +#进入到conda环境 +#source activate py8 + + + +# 数据集路径,保持为空,不需要修改 +data_path="" + +#基础参数,需要模型审视修改 +#网络名称,同目录名称 +Network="FairSeq_Transformer_ID0496_for_PyTorch" +#训练epoch +train_epochs=4 +#训练batch_size +batch_size=32 +#训练step +#train_steps=`expr 1281167 / ${batch_size}` +#学习率 +learning_rate=0.495 + +#TF2.X独有,不需要修改 +#export NPU_LOOP_SIZE=${train_steps} + +#维测参数,precision_mode需要模型审视修改 +precision_mode="allow_mix_precision" +#维持参数,以下不需要修改 +over_dump=False +data_dump_flag=False +data_dump_step="10" +profiling=False +autotune=False + +# 帮助信息,不需要修改 +if [[ $1 == --help || $1 == -h ]];then + echo"usage:./train_full_1p.sh " + echo " " + echo "parameter explain: + --precision_mode precision mode(allow_fp32_to_fp16/force_fp16/must_keep_origin_dtype/allow_mix_precision) + --over_dump if or not over detection, default is False + --data_dump_flag data dump flag, default is False + --data_dump_step data dump step, default is 10 + --profiling if or not profiling for performance debug, default is False + --data_path source data of training + -h/--help show help message + " + exit 1 +fi + +#参数校验,不需要修改 +for para in $* +do + if [[ $para == --precision_mode* ]];then + precision_mode=`echo ${para#*=}` +elif [[ $para == --over_dump* ]];then + over_dump=`echo ${para#*=}` + over_dump_path=${cur_path}/output/overflow_dump + mkdir -p ${over_dump_path} + elif [[ $para == --data_dump_flag* ]];then + data_dump_flag=`echo ${para#*=}` + data_dump_path=${cur_path}/output/data_dump + mkdir -p ${data_dump_path} + elif [[ $para == --data_dump_step* ]];then + data_dump_step=`echo ${para#*=}` + elif [[ $para == --profiling* ]];then + profiling=`echo ${para#*=}` + profiling_dump_path=${cur_path}/output/profiling + mkdir -p ${profiling_dump_path} + elif [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + +#训练开始时间,不需要修改 +start_time=$(date +%s) + +#进入训练脚本目录,需要模型审视修改 +cd $cur_path/../ + +#python3 setup.py build_ext --inplace +pip3 install --editable . +#sed -i "s|pass|break|g" train.py +#sed -i "s|data/LibriSpeech|$data_path/LibriSpeech|g" config/libri/asr_example.yaml + +#修改epoch参数 + + +for((RANK_ID=$RANK_ID_START;RANK_ID<$((RANK_SIZE+RANK_ID_START));RANK_ID++)); +do + #设置环境变量,不需要修改 + echo "Device ID: $ASCEND_DEVICE_ID" + export RANK_ID=$RANK_ID + + + + #创建DeviceID输出目录,不需要修改 + if [ -d ${cur_path}/output/${ASCEND_DEVICE_ID} ];then + rm -rf ${cur_path}/output/${ASCEND_DEVICE_ID} + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + else + mkdir -p ${cur_path}/output/$ASCEND_DEVICE_ID/ckpt + fi + + #绑核,不需要绑核的模型删除,需要绑核的模型根据实际修改 + #cpucount=`lscpu | grep "CPU(s):" | head -n 1 | awk '{print $2}'` + #cpustep=`expr $cpucount / 8` + #echo "taskset c steps:" $cpustep + #let a=RANK_ID*$cpustep + #let b=RANK_ID+1 + #let c=b*$cpustep-1 + + #执行训练脚本,以下传参不需要修改,其他需要模型审视修改 + nohup python3 train.py $data_path/iwslt14.tokenized.de-en \ + --arch transformer \ + --optimizer adam \ + --adam-betas '(0.9, 0.98)' \ + --clip-norm 0.0 \ + --lr 0.00006 \ + --lr-scheduler inverse_sqrt \ + --warmup-updates 4000 \ + --device-id $ASCEND_DEVICE_ID \ + --weight-decay 0.0001 \ + --source-lang de \ + --target-lang en \ + --decoder-attention-heads 4 \ + --decoder-ffn-embed-dim 1024 \ + --encoder-attention-heads 4 \ + --encoder-ffn-embed-dim 1024 \ + --seed 12345 \ + --fp16 \ + --fp16-scale-window 1500 \ + --ddp-backend no_c10d \ + --disable-validation \ + --distributed-no-spawn \ + --max-tokens 15000 \ + --required-batch-size-multiple 32 \ + --max-epoch ${train_epochs} \ + --max-source-positions 1024 \ + --max-target-positions 1024 \ + --num-workers 1 \ + --log-interval 1 \ + --save-interval 1 \ + --share-decoder-input-output-embed > ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & +done +wait + +#conda deactivate +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +#Time=`grep "iteration" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |awk -F "time =" '{print $2}'|awk -F "ms" '{print $1}'| grep -v "^$" |tail -n +6|awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` +FPS=`grep -rn "wps=" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log | awk -F "wps=" '{print $2}' | awk -F "," '{print $1}' | awk '{if(NR>=325){print}}' | awk 'END {print}' |sed s/[[:space:]]//g` +#FPS=`awk 'BEGIN{printf "%.2f\n",'${batch_size}'*1000/'${Time}'}'` + + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#输出训练精度,需要模型审视修改 +#train_accuracy=`grep eval_accuracy $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log|grep -v mlp_log|awk 'END {print $5}'| sed 's/,//g' |cut -c 1-5` +#打印,不需要修改 +#echo "Final Train Accuracy : ${train_accuracy}" +#echo "E2E Training Duration sec : $e2e_time" + +#稳定性精度看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +##获取性能数据 +#吞吐量,不需要修改 +ActualFPS=${FPS} +#单迭代训练时长,不需要修改 +#TrainingTime=`awk 'BEGIN{printf "%.2f\n",'${BatchSize}'*1000/'${FPS}'}'` +TrainingTime=`grep "iteration" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |awk -F "time =" '{print $2}'|awk -F "ms" '{print $1}'| grep -v "^$" |tail -n +6|awk '{sum+=$1} END {print"",sum/NR}'|sed s/[[:space:]]//g` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要根据模型审视 +grep "loss=" $cur_path/output/$ASCEND_DEVICE_ID/train_$ASCEND_DEVICE_ID.log|awk -F "loss=" '{print $2}'|awk -F "," '{print $1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +#echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "E2ETrainingTime = ${e2e_time}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log diff --git a/PyTorch/dev/nlp/Speech_Transformer_ID0487_for_PyTorch/modelzoo_level.txt b/PyTorch/dev/nlp/Speech_Transformer_ID0487_for_PyTorch/modelzoo_level.txt index 405b26618a..c45626e398 100644 --- a/PyTorch/dev/nlp/Speech_Transformer_ID0487_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/dev/nlp/Speech_Transformer_ID0487_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:POK +FuncStatus:OK +PerfStatus:POK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/modelzoo_level.txt b/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/modelzoo_level.txt index 0b49b4fb26..31529da2e6 100644 --- a/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/modelzoo_level.txt +++ b/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/modelzoo_level.txt @@ -1,3 +1,3 @@ -FuncStatus:OK -PerfStatus:OK +FuncStatus:OK +PerfStatus:OK PrecisionStatus:OK \ No newline at end of file diff --git a/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/test/train_full_1p.sh b/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/test/train_full_1p.sh index 2b6134790e..de5560f8cb 100644 --- a/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/test/train_full_1p.sh +++ b/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/test/train_full_1p.sh @@ -1,140 +1,140 @@ -#!/bin/bash - -cur_path=`pwd` -#集合通信参数,不需要修改 -export RANK_SIZE=1 - -export BMMV2_ENABLE=1 -# 数据集路径,保持为空,不需要修改 -data_path="" - -#网络名称,同目录名称,需要模型审视修改 -Network="Transformer_ID0105_for_PyTorch" - -#训练batch_size,,需要模型审视修改 -batch_size=128 - -#训练epoch,不需要修改 -epochs=1 - - -# 参数校验,data_path为必传参数,其他参数的增删由模型自身决定;此处新增参数需在上面有定义并赋值 -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --epochs* ]];then - epochs=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - - - - -#创建DeviceID输出目录,不需要修改 -if [ -d $cur_path/output/${ASCEND_DEVICE_ID} ];then - rm -rf $cur_path/output/$ASCEND_DEVICE_ID - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi - -#################启动训练脚本################# - - -# 必要参数替换配置文件 -cd $cur_path/.. -DATA_DIR=./data/dataset/wmt14_en_de_joined_dict/ -MODELDIR="./checkpoints/" -mkdir -p "$MODELDIR" -LOGFILE="$MODELDIR/log" -STAT_FILE="log.txt" - - -export ASCEND_SLOG_PRINT_TO_STDOUT=0 -export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 -export PTCOPY_ENABLE=1 -export TASK_QUEUE_ENABLE=1 -export DYNAMIC_OP="ADD#MUL" -start_time=$(date +%s) -python3 -u train_1p.py \ - $data_path \ - --device-id ${ASCEND_DEVICE_ID}\ - --arch transformer_wmt_en_de \ - --share-all-embeddings \ - --optimizer adam \ - --adam-beta1 0.9 \ - --adam-beta2 0.997 \ - --adam-eps "1e-9" \ - --clip-norm 0.0 \ - --lr-scheduler inverse_sqrt \ - --warmup-init-lr 0.0 \ - --warmup-updates 4000 \ - --lr 0.0006 \ - --min-lr 0.0 \ - --dropout 0.1 \ - --weight-decay 0.0 \ - --criterion label_smoothed_cross_entropy \ - --label-smoothing 0.1 \ - --max-sentences 128\ - --max-tokens 102400\ - --seed 1 \ - --save-dir $MODELDIR \ - --save-interval 1\ - --update-freq 8\ - --log-interval 1\ - --stat-file $STAT_FILE\ - --distributed-world-size 1\ - --amp\ - --amp-level O2 > $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & - -wait - -##################获取训练数据################ -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=` grep -rns "Time" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |grep -v "all" |awk -F "Time" '{print$2}' |awk -F "(" '{print$1}'|tail -n +5|awk '{sum+=$1} END {print"",128*NR/sum}'|sed s/[[:space:]]//g` -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#打印,不需要修改 -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -#获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要模型审视修改 -grep -rns "Time" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |grep -v "all" |awk -F "Loss" '{print$2}' |awk -F "(" '{print$1}' > ${cur_path}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' ${cur_path}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +cur_path=`pwd` +#集合通信参数,不需要修改 +export RANK_SIZE=1 + +export BMMV2_ENABLE=1 +# 数据集路径,保持为空,不需要修改 +data_path="" + +#网络名称,同目录名称,需要模型审视修改 +Network="Transformer_ID0105_for_PyTorch" + +#训练batch_size,,需要模型审视修改 +batch_size=128 + +#训练epoch,不需要修改 +epochs=1 + + +# 参数校验,data_path为必传参数,其他参数的增删由模型自身决定;此处新增参数需在上面有定义并赋值 +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --epochs* ]];then + epochs=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + + + + +#创建DeviceID输出目录,不需要修改 +if [ -d $cur_path/output/${ASCEND_DEVICE_ID} ];then + rm -rf $cur_path/output/$ASCEND_DEVICE_ID + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi + +#################启动训练脚本################# + + +# 必要参数替换配置文件 +cd $cur_path/.. +DATA_DIR=./data/dataset/wmt14_en_de_joined_dict/ +MODELDIR="./checkpoints/" +mkdir -p "$MODELDIR" +LOGFILE="$MODELDIR/log" +STAT_FILE="log.txt" + + +export ASCEND_SLOG_PRINT_TO_STDOUT=0 +export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 +export PTCOPY_ENABLE=1 +export TASK_QUEUE_ENABLE=1 +export DYNAMIC_OP="ADD#MUL" +start_time=$(date +%s) +python3 -u train_1p.py \ + $data_path \ + --device-id ${ASCEND_DEVICE_ID}\ + --arch transformer_wmt_en_de \ + --share-all-embeddings \ + --optimizer adam \ + --adam-beta1 0.9 \ + --adam-beta2 0.997 \ + --adam-eps "1e-9" \ + --clip-norm 0.0 \ + --lr-scheduler inverse_sqrt \ + --warmup-init-lr 0.0 \ + --warmup-updates 4000 \ + --lr 0.0006 \ + --min-lr 0.0 \ + --dropout 0.1 \ + --weight-decay 0.0 \ + --criterion label_smoothed_cross_entropy \ + --label-smoothing 0.1 \ + --max-sentences 128\ + --max-tokens 102400\ + --seed 1 \ + --save-dir $MODELDIR \ + --save-interval 1\ + --update-freq 8\ + --log-interval 1\ + --stat-file $STAT_FILE\ + --distributed-world-size 1\ + --amp\ + --amp-level O2 > $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & + +wait + +##################获取训练数据################ +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=` grep -rns "Time" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |grep -v "all" |awk -F "Time" '{print$2}' |awk -F "(" '{print$1}'|tail -n +5|awk '{sum+=$1} END {print"",128*NR/sum}'|sed s/[[:space:]]//g` +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#打印,不需要修改 +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +#获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要模型审视修改 +grep -rns "Time" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |grep -v "all" |awk -F "Loss" '{print$2}' |awk -F "(" '{print$1}' > ${cur_path}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' ${cur_path}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/test/train_full_8p.sh b/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/test/train_full_8p.sh index dc8f9b79a7..aa6ba8464c 100644 --- a/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/test/train_full_8p.sh +++ b/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/test/train_full_8p.sh @@ -1,159 +1,159 @@ -#!/bin/bash - -cur_path=`pwd` -#集合通信参数,不需要修改 -export RANK_SIZE=8 -export MASTER_ADDR=localhost -export MASTER_PORT=29688 -# 数据集路径,保持为空,不需要修改 -data_path="" - -#网络名称,同目录名称,需要模型审视修改 -Network="Transformer_ID0105_for_PyTorch" - -export BMMV2_ENABLE=1 -#训练epoch -train_epochs=30 -#训练batch_size,,需要模型审视修改 -batch_size=128 - - - -# 参数校验,data_path为必传参数,其他参数的增删由模型自身决定;此处新增参数需在上面有定义并赋值 -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --epochs* ]];then - epochs=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - - - - -#创建DeviceID输出目录,不需要修改 -if [ -d $cur_path/output/${ASCEND_DEVICE_ID} ];then - rm -rf $cur_path/output/$ASCEND_DEVICE_ID - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi - -#################启动训练脚本################# - - -# 必要参数替换配置文件 -cd $cur_path/.. -DATA_DIR=./data/dataset/wmt14_en_de_joined_dict/ -MODELDIR="./checkpoints/" -mkdir -p "$MODELDIR" -LOGFILE="$MODELDIR/log" -STAT_FILE="log.txt" - - -start_time=$(date +%s) -NPUS=($(seq 0 7)) -export NPU_WORLD_SIZE=${#NPUS[@]} -rank=0 -for i in ${NPUS[@]} -do - export NPU_CALCULATE_DEVICE=${i} - mkdir -p $cur_path/output/${i}/ - export ASCEND_DEVICE_ID=${i} - export RANK=${rank} - echo run process ${rank} - - - python3 train_8p_new.py \ - $data_path \ - --arch transformer_wmt_en_de \ - --share-all-embeddings \ - --optimizer adam \ - --adam-beta1 0.9 \ - --adam-beta2 0.997 \ - --addr '127.0.0.1' \ - --adam-eps "1e-9" \ - --clip-norm 0.0 \ - --lr-scheduler inverse_sqrt \ - --warmup-init-lr 0.0 \ - --warmup-updates 4000 \ - --lr 0.0006 \ - --min-lr 0.0 \ - --dropout 0.1 \ - --weight-decay 0.0 \ - --criterion label_smoothed_cross_entropy \ - --label-smoothing 0.1 \ - --max-sentences 128\ - --max-tokens 102400 \ - --max-epoch $train_epochs \ - --seed 1 \ - --save-dir $MODELDIR \ - --stat-file $STAT_FILE\ - --log-interval 1\ - --amp\ - --device-id ${rank}\ - --amp-level O2 > $cur_path/output/${i}/train_${i}.log 2>&1 & - let rank++ -done -wait - - - - -##################获取训练数据################ -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=`grep -rns "Time" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |grep -v "all" |awk -F "Time" '{print$2}' |awk -F "(" '{print$1}'|tail -n +5|awk '{sum+=$1} END {print"",8*128*NR/sum}'|sed s/[[:space:]]//g` - -#输出训练精度,需要模型审视修改 -train_accuracy=`grep -rns "Validation" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |awk 'END {print $6}'` - -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#打印,不需要修改 -echo "Final Train Accuracy : ${train_accuracy}" -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' - -#获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'$FPS'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要模型审视修改 -grep -rns "Time" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |grep -v "all" |awk -F "Loss" '{print$2}' |awk -F "(" '{print$1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' ${cur_path}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +cur_path=`pwd` +#集合通信参数,不需要修改 +export RANK_SIZE=8 +export MASTER_ADDR=localhost +export MASTER_PORT=29688 +# 数据集路径,保持为空,不需要修改 +data_path="" + +#网络名称,同目录名称,需要模型审视修改 +Network="Transformer_ID0105_for_PyTorch" + +export BMMV2_ENABLE=1 +#训练epoch +train_epochs=30 +#训练batch_size,,需要模型审视修改 +batch_size=128 + + + +# 参数校验,data_path为必传参数,其他参数的增删由模型自身决定;此处新增参数需在上面有定义并赋值 +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --epochs* ]];then + epochs=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + + + + +#创建DeviceID输出目录,不需要修改 +if [ -d $cur_path/output/${ASCEND_DEVICE_ID} ];then + rm -rf $cur_path/output/$ASCEND_DEVICE_ID + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi + +#################启动训练脚本################# + + +# 必要参数替换配置文件 +cd $cur_path/.. +DATA_DIR=./data/dataset/wmt14_en_de_joined_dict/ +MODELDIR="./checkpoints/" +mkdir -p "$MODELDIR" +LOGFILE="$MODELDIR/log" +STAT_FILE="log.txt" + + +start_time=$(date +%s) +NPUS=($(seq 0 7)) +export NPU_WORLD_SIZE=${#NPUS[@]} +rank=0 +for i in ${NPUS[@]} +do + export NPU_CALCULATE_DEVICE=${i} + mkdir -p $cur_path/output/${i}/ + export ASCEND_DEVICE_ID=${i} + export RANK=${rank} + echo run process ${rank} + + + python3 train_8p_new.py \ + $data_path \ + --arch transformer_wmt_en_de \ + --share-all-embeddings \ + --optimizer adam \ + --adam-beta1 0.9 \ + --adam-beta2 0.997 \ + --addr '127.0.0.1' \ + --adam-eps "1e-9" \ + --clip-norm 0.0 \ + --lr-scheduler inverse_sqrt \ + --warmup-init-lr 0.0 \ + --warmup-updates 4000 \ + --lr 0.0006 \ + --min-lr 0.0 \ + --dropout 0.1 \ + --weight-decay 0.0 \ + --criterion label_smoothed_cross_entropy \ + --label-smoothing 0.1 \ + --max-sentences 128\ + --max-tokens 102400 \ + --max-epoch $train_epochs \ + --seed 1 \ + --save-dir $MODELDIR \ + --stat-file $STAT_FILE\ + --log-interval 1\ + --amp\ + --device-id ${rank}\ + --amp-level O2 > $cur_path/output/${i}/train_${i}.log 2>&1 & + let rank++ +done +wait + + + + +##################获取训练数据################ +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=`grep -rns "Time" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |grep -v "all" |awk -F "Time" '{print$2}' |awk -F "(" '{print$1}'|tail -n +5|awk '{sum+=$1} END {print"",8*128*NR/sum}'|sed s/[[:space:]]//g` + +#输出训练精度,需要模型审视修改 +train_accuracy=`grep -rns "Validation" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |awk 'END {print $6}'` + +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#打印,不需要修改 +echo "Final Train Accuracy : ${train_accuracy}" +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'acc' + +#获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'$FPS'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要模型审视修改 +grep -rns "Time" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |grep -v "all" |awk -F "Loss" '{print$2}' |awk -F "(" '{print$1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' ${cur_path}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainAccuracy = ${train_accuracy}" >> $cur_path/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/test/train_performance_1p.sh b/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/test/train_performance_1p.sh index 6761832491..c51f98e55d 100644 --- a/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/test/train_performance_1p.sh +++ b/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/test/train_performance_1p.sh @@ -1,145 +1,145 @@ -#!/bin/bash - -cur_path=`pwd` -#集合通信参数,不需要修改 -export RANK_SIZE=1 - -export BMMV2_ENABLE=1 -# 数据集路径,保持为空,不需要修改 -data_path="" - -#网络名称,同目录名称,需要模型审视修改 -Network="Transformer_ID0105_for_PyTorch" - -#训练batch_size,,需要模型审视修改 -batch_size=128 - -#训练epoch,不需要修改 -epochs=1 - - -# 参数校验,data_path为必传参数,其他参数的增删由模型自身决定;此处新增参数需在上面有定义并赋值 -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --epochs* ]];then - epochs=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - - - - -#创建DeviceID输出目录,不需要修改 -if [ -d $cur_path/output/${ASCEND_DEVICE_ID} ];then - rm -rf $cur_path/output/$ASCEND_DEVICE_ID - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi - -#################启动训练脚本################# - - -# 必要参数替换配置文件 -cd $cur_path/.. -DATA_DIR=./data/dataset/wmt14_en_de_joined_dict/ -MODELDIR="./checkpoints/" -mkdir -p "$MODELDIR" -LOGFILE="$MODELDIR/log" -STAT_FILE="log.txt" -sed -i "s|if i>100:pass|if i>100:break|g" train_1p.py -sed -i "s|if m >=2:pass|if m >=2:break|g" train_1p.py - -export ASCEND_SLOG_PRINT_TO_STDOUT=0 -export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 -export PTCOPY_ENABLE=1 -export TASK_QUEUE_ENABLE=1 -#export DYNAMIC_OP="ADD#MUL" -export COMBINED_ENABLE=1 -export SCALAR_TO_HOST_MEM=1 -start_time=$(date +%s) - -python3 -u train_1p.py \ - $data_path \ - --device-id ${ASCEND_DEVICE_ID}\ - --arch transformer_wmt_en_de \ - --share-all-embeddings \ - --optimizer adam \ - --adam-beta1 0.9 \ - --adam-beta2 0.997 \ - --adam-eps "1e-9" \ - --clip-norm 0.0 \ - --lr-scheduler inverse_sqrt \ - --warmup-init-lr 0.0 \ - --warmup-updates 4000 \ - --lr 0.0006 \ - --min-lr 0.0 \ - --dropout 0.1 \ - --weight-decay 0.0 \ - --criterion cross_entropy \ - --label-smoothing 0.1 \ - --max-sentences 128\ - --max-tokens 102400\ - --seed 1 \ - --save-dir $MODELDIR \ - --save-interval 1\ - --update-freq 8\ - --log-interval 1\ - --stat-file $STAT_FILE\ - --distributed-world-size 1\ - --amp\ - --amp-level O2 > $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & - -wait -sed -i "s|if i>100:break|if i>100:pass|g" train_1p.py -sed -i "s|if m >=2:break|if m>=2:pass|g" train_1p.py -##################获取训练数据################ -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=` grep -rns "Time" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |grep -v "all" |awk -F "Time" '{print$2}' |awk -F "(" '{print$1}'|tail -n +5|awk '{sum+=$1} END {print"",128*NR/sum}'|sed s/[[:space:]]//g` -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#打印,不需要修改 -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -#获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要模型审视修改 -grep -rns "Time" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |grep -v "all" |awk -F "Loss" '{print$2}' |awk -F "(" '{print$1}' > ${cur_path}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' ${cur_path}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +cur_path=`pwd` +#集合通信参数,不需要修改 +export RANK_SIZE=1 + +export BMMV2_ENABLE=1 +# 数据集路径,保持为空,不需要修改 +data_path="" + +#网络名称,同目录名称,需要模型审视修改 +Network="Transformer_ID0105_for_PyTorch" + +#训练batch_size,,需要模型审视修改 +batch_size=128 + +#训练epoch,不需要修改 +epochs=1 + + +# 参数校验,data_path为必传参数,其他参数的增删由模型自身决定;此处新增参数需在上面有定义并赋值 +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --epochs* ]];then + epochs=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + + + + +#创建DeviceID输出目录,不需要修改 +if [ -d $cur_path/output/${ASCEND_DEVICE_ID} ];then + rm -rf $cur_path/output/$ASCEND_DEVICE_ID + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi + +#################启动训练脚本################# + + +# 必要参数替换配置文件 +cd $cur_path/.. +DATA_DIR=./data/dataset/wmt14_en_de_joined_dict/ +MODELDIR="./checkpoints/" +mkdir -p "$MODELDIR" +LOGFILE="$MODELDIR/log" +STAT_FILE="log.txt" +sed -i "s|if i>100:pass|if i>100:break|g" train_1p.py +sed -i "s|if m >=2:pass|if m >=2:break|g" train_1p.py + +export ASCEND_SLOG_PRINT_TO_STDOUT=0 +export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 +export PTCOPY_ENABLE=1 +export TASK_QUEUE_ENABLE=1 +#export DYNAMIC_OP="ADD#MUL" +export COMBINED_ENABLE=1 +export SCALAR_TO_HOST_MEM=1 +start_time=$(date +%s) + +python3 -u train_1p.py \ + $data_path \ + --device-id ${ASCEND_DEVICE_ID}\ + --arch transformer_wmt_en_de \ + --share-all-embeddings \ + --optimizer adam \ + --adam-beta1 0.9 \ + --adam-beta2 0.997 \ + --adam-eps "1e-9" \ + --clip-norm 0.0 \ + --lr-scheduler inverse_sqrt \ + --warmup-init-lr 0.0 \ + --warmup-updates 4000 \ + --lr 0.0006 \ + --min-lr 0.0 \ + --dropout 0.1 \ + --weight-decay 0.0 \ + --criterion cross_entropy \ + --label-smoothing 0.1 \ + --max-sentences 128\ + --max-tokens 102400\ + --seed 1 \ + --save-dir $MODELDIR \ + --save-interval 1\ + --update-freq 8\ + --log-interval 1\ + --stat-file $STAT_FILE\ + --distributed-world-size 1\ + --amp\ + --amp-level O2 > $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log 2>&1 & + +wait +sed -i "s|if i>100:break|if i>100:pass|g" train_1p.py +sed -i "s|if m >=2:break|if m>=2:pass|g" train_1p.py +##################获取训练数据################ +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=` grep -rns "Time" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |grep -v "all" |awk -F "Time" '{print$2}' |awk -F "(" '{print$1}'|tail -n +5|awk '{sum+=$1} END {print"",128*NR/sum}'|sed s/[[:space:]]//g` +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#打印,不需要修改 +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +#获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要模型审视修改 +grep -rns "Time" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |grep -v "all" |awk -F "Loss" '{print$2}' |awk -F "(" '{print$1}' > ${cur_path}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' ${cur_path}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/test/train_performance_8p.sh b/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/test/train_performance_8p.sh index f4b26836cd..f2cb6b1350 100644 --- a/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/test/train_performance_8p.sh +++ b/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/test/train_performance_8p.sh @@ -1,160 +1,160 @@ -#!/bin/bash - -cur_path=`pwd` -nmon -s3 -c 500 -f -m $cur_path -#集合通信参数,不需要修改 -export RANK_SIZE=8 -export MASTER_ADDR=localhost -export MASTER_PORT=29688 -export HCCL_WHITELIST_DISABLE=1 -export BMMV2_ENABLE=1 -# 数据集路径,保持为空,不需要修改 -data_path="" - -#网络名称,同目录名称,需要模型审视修改 -Network="Transformer_ID0105_for_PyTorch" - -#训练batch_size,,需要模型审视修改 -batch_size=128 - - - -# 参数校验,data_path为必传参数,其他参数的增删由模型自身决定;此处新增参数需在上面有定义并赋值 -for para in $* -do - if [[ $para == --data_path* ]];then - data_path=`echo ${para#*=}` - elif [[ $para == --epochs* ]];then - epochs=`echo ${para#*=}` - fi -done - -#校验是否传入data_path,不需要修改 -if [[ $data_path == "" ]];then - echo "[Error] para \"data_path\" must be confing" - exit 1 -fi - - - - -#创建DeviceID输出目录,不需要修改 -if [ -d $cur_path/output/${ASCEND_DEVICE_ID} ];then - rm -rf $cur_path/output/$ASCEND_DEVICE_ID - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -else - mkdir -p $cur_path/output/$ASCEND_DEVICE_ID -fi - -#################启动训练脚本################# - - -# 必要参数替换配置文件 -cd $cur_path/.. -DATA_DIR=./data/dataset/wmt14_en_de_joined_dict/ -MODELDIR="./checkpoints/" -mkdir -p "$MODELDIR" -LOGFILE="$MODELDIR/log" -STAT_FILE="log.txt" - -sed -i "s|if i>100:pass|if i>100:break|g" train_8p_new.py -sed -i "s|if m >=2:pass|if m >=2:break|g" train_8p_new.py - -export ASCEND_SLOG_PRINT_TO_STDOUT=0 -export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 -export PTCOPY_ENABLE=1 -export TASK_QUEUE_ENABLE=1 -export DYNAMIC_OP="ADD#MUL" -start_time=$(date +%s) -NPUS=($(seq 0 7)) -export NPU_WORLD_SIZE=${#NPUS[@]} -rank=0 -for i in ${NPUS[@]} -do - export NPU_CALCULATE_DEVICE=${i} - mkdir -p $cur_path/output/${i}/ - export ASCEND_DEVICE_ID=${i} - export RANK=${rank} - echo run process ${rank} - - - python3 train_8p_new.py \ - $data_path \ - --arch transformer_wmt_en_de \ - --share-all-embeddings \ - --optimizer adam \ - --adam-beta1 0.9 \ - --adam-beta2 0.997 \ - --addr '127.0.0.1' \ - --port 29990 \ - --adam-eps "1e-9" \ - --clip-norm 0.0 \ - --lr-scheduler inverse_sqrt \ - --warmup-init-lr 0.0 \ - --warmup-updates 4000 \ - --lr 0.0006 \ - --min-lr 0.0 \ - --dropout 0.1 \ - --weight-decay 0.0 \ - --criterion label_smoothed_cross_entropy \ - --label-smoothing 0.1 \ - --max-sentences 128\ - --max-tokens 102400 \ - --seed 1 \ - --save-dir $MODELDIR \ - --stat-file $STAT_FILE\ - --log-interval 1\ - --amp\ - --device-id ${rank}\ - --amp-level O2 > $cur_path/output/${i}/train_${i}.log 2>&1 & - let rank++ -done -wait -sed -i "s|if i>100:break|if i>100:pass|g" train_8p_new.py -sed -i "s|if m >=2:break|if m >=2:pass|g" train_8p_new.py - - - -##################获取训练数据################ -#训练结束时间,不需要修改 -end_time=$(date +%s) -e2e_time=$(( $end_time - $start_time )) - -#结果打印,不需要修改 -echo "------------------ Final result ------------------" -#输出性能FPS,需要模型审视修改 -FPS=` grep -rns "Time" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |grep -v "all" |awk -F "Time" '{print$2}' |awk -F "(" '{print$1}'|tail -n +5|awk '{sum+=$1} END {print"",8*128*NR/sum}'|sed s/[[:space:]]//g` -#打印,不需要修改 -echo "Final Performance images/sec : $FPS" - -#打印,不需要修改 -echo "E2E Training Duration sec : $e2e_time" - -#性能看护结果汇总 -#训练用例信息,不需要修改 -BatchSize=${batch_size} -DeviceType=`uname -m` -CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' - -#获取性能数据,不需要修改 -#吞吐量 -ActualFPS=${FPS} -#单迭代训练时长 -TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` - -#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要模型审视修改 -grep -rns "Time" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |grep -v "all" |awk -F "Loss" '{print$2}' |awk -F "(" '{print$1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt - -#最后一个迭代loss值,不需要修改 -ActualLoss=`awk 'END {print}' ${cur_path}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` - -#关键信息打印到${CaseName}.log中,不需要修改 -echo "Network = ${Network}" > ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "RankSize = ${RANK_SIZE}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "BatchSize = ${BatchSize}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "DeviceType = ${DeviceType}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "CaseName = ${CaseName}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualFPS = ${ActualFPS}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "TrainingTime = ${TrainingTime}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log -echo "ActualLoss = ${ActualLoss}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +#!/bin/bash + +cur_path=`pwd` +nmon -s3 -c 500 -f -m $cur_path +#集合通信参数,不需要修改 +export RANK_SIZE=8 +export MASTER_ADDR=localhost +export MASTER_PORT=29688 +export HCCL_WHITELIST_DISABLE=1 +export BMMV2_ENABLE=1 +# 数据集路径,保持为空,不需要修改 +data_path="" + +#网络名称,同目录名称,需要模型审视修改 +Network="Transformer_ID0105_for_PyTorch" + +#训练batch_size,,需要模型审视修改 +batch_size=128 + + + +# 参数校验,data_path为必传参数,其他参数的增删由模型自身决定;此处新增参数需在上面有定义并赋值 +for para in $* +do + if [[ $para == --data_path* ]];then + data_path=`echo ${para#*=}` + elif [[ $para == --epochs* ]];then + epochs=`echo ${para#*=}` + fi +done + +#校验是否传入data_path,不需要修改 +if [[ $data_path == "" ]];then + echo "[Error] para \"data_path\" must be confing" + exit 1 +fi + + + + +#创建DeviceID输出目录,不需要修改 +if [ -d $cur_path/output/${ASCEND_DEVICE_ID} ];then + rm -rf $cur_path/output/$ASCEND_DEVICE_ID + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +else + mkdir -p $cur_path/output/$ASCEND_DEVICE_ID +fi + +#################启动训练脚本################# + + +# 必要参数替换配置文件 +cd $cur_path/.. +DATA_DIR=./data/dataset/wmt14_en_de_joined_dict/ +MODELDIR="./checkpoints/" +mkdir -p "$MODELDIR" +LOGFILE="$MODELDIR/log" +STAT_FILE="log.txt" + +sed -i "s|if i>100:pass|if i>100:break|g" train_8p_new.py +sed -i "s|if m >=2:pass|if m >=2:break|g" train_8p_new.py + +export ASCEND_SLOG_PRINT_TO_STDOUT=0 +export ASCEND_GLOBAL_LOG_LEVEL_ETP=3 +export PTCOPY_ENABLE=1 +export TASK_QUEUE_ENABLE=1 +export DYNAMIC_OP="ADD#MUL" +start_time=$(date +%s) +NPUS=($(seq 0 7)) +export NPU_WORLD_SIZE=${#NPUS[@]} +rank=0 +for i in ${NPUS[@]} +do + export NPU_CALCULATE_DEVICE=${i} + mkdir -p $cur_path/output/${i}/ + export ASCEND_DEVICE_ID=${i} + export RANK=${rank} + echo run process ${rank} + + + python3 train_8p_new.py \ + $data_path \ + --arch transformer_wmt_en_de \ + --share-all-embeddings \ + --optimizer adam \ + --adam-beta1 0.9 \ + --adam-beta2 0.997 \ + --addr '127.0.0.1' \ + --port 29990 \ + --adam-eps "1e-9" \ + --clip-norm 0.0 \ + --lr-scheduler inverse_sqrt \ + --warmup-init-lr 0.0 \ + --warmup-updates 4000 \ + --lr 0.0006 \ + --min-lr 0.0 \ + --dropout 0.1 \ + --weight-decay 0.0 \ + --criterion label_smoothed_cross_entropy \ + --label-smoothing 0.1 \ + --max-sentences 128\ + --max-tokens 102400 \ + --seed 1 \ + --save-dir $MODELDIR \ + --stat-file $STAT_FILE\ + --log-interval 1\ + --amp\ + --device-id ${rank}\ + --amp-level O2 > $cur_path/output/${i}/train_${i}.log 2>&1 & + let rank++ +done +wait +sed -i "s|if i>100:break|if i>100:pass|g" train_8p_new.py +sed -i "s|if m >=2:break|if m >=2:pass|g" train_8p_new.py + + + +##################获取训练数据################ +#训练结束时间,不需要修改 +end_time=$(date +%s) +e2e_time=$(( $end_time - $start_time )) + +#结果打印,不需要修改 +echo "------------------ Final result ------------------" +#输出性能FPS,需要模型审视修改 +FPS=` grep -rns "Time" $cur_path/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |grep -v "all" |awk -F "Time" '{print$2}' |awk -F "(" '{print$1}'|tail -n +5|awk '{sum+=$1} END {print"",8*128*NR/sum}'|sed s/[[:space:]]//g` +#打印,不需要修改 +echo "Final Performance images/sec : $FPS" + +#打印,不需要修改 +echo "E2E Training Duration sec : $e2e_time" + +#性能看护结果汇总 +#训练用例信息,不需要修改 +BatchSize=${batch_size} +DeviceType=`uname -m` +CaseName=${Network}_bs${BatchSize}_${RANK_SIZE}'p'_'perf' + +#获取性能数据,不需要修改 +#吞吐量 +ActualFPS=${FPS} +#单迭代训练时长 +TrainingTime=`awk 'BEGIN{printf "%.2f\n", '${batch_size}'*1000/'${FPS}'}'` + +#从train_$ASCEND_DEVICE_ID.log提取Loss到train_${CaseName}_loss.txt中,需要模型审视修改 +grep -rns "Time" ${cur_path}/output/${ASCEND_DEVICE_ID}/train_${ASCEND_DEVICE_ID}.log |grep -v "all" |awk -F "Loss" '{print$2}' |awk -F "(" '{print$1}' > $cur_path/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt + +#最后一个迭代loss值,不需要修改 +ActualLoss=`awk 'END {print}' ${cur_path}/output/$ASCEND_DEVICE_ID/train_${CaseName}_loss.txt` + +#关键信息打印到${CaseName}.log中,不需要修改 +echo "Network = ${Network}" > ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "RankSize = ${RANK_SIZE}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "BatchSize = ${BatchSize}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "DeviceType = ${DeviceType}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "CaseName = ${CaseName}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualFPS = ${ActualFPS}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "TrainingTime = ${TrainingTime}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log +echo "ActualLoss = ${ActualLoss}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log echo "E2ETrainingTime = ${e2e_time}" >> ${cur_path}/output/$ASCEND_DEVICE_ID/${CaseName}.log \ No newline at end of file diff --git a/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/train_8p_new.py b/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/train_8p_new.py index 0179a825cf..514d8c8326 100644 --- a/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/train_8p_new.py +++ b/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch/train_8p_new.py @@ -1,417 +1,417 @@ -#!/usr/bin/env python3 -u -# Copyright (c) 2017-present, Facebook, Inc. -# All rights reserved. -# Copyright 2020 Huawei Technologies Co., Ltd -# -# This source code is licensed under the license found in the LICENSE file in -# the root directory of this source tree. An additional grant of patent rights -# can be found in the PATENTS file in the same directory. -# -# ------------------------------------------------------------------------- -# -# Copyright (c) 2019, NVIDIA CORPORATION. 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. -import collections -import itertools -import os -import math -import torch -import torch.npu -import time -import ctypes - -import sys -import threading - -from copy import deepcopy -from utils import distributed_utils, options, utils -from utils.ddp_trainer import DDPTrainer -from utils.meters import StopwatchMeter, TimeMeter -import data -from data import tokenizer, dictionary, data_utils, load_dataset_splits -from models import build_model -import torch.distributed as dist -import torch.multiprocessing as mp -import numpy as np - -import dllogger as DLLogger -from utils.log_helper import AggregatorBackend, setup_logger - - -NPU_CALCULATE_DEVICE = 0 -if os.getenv('NPU_CALCULATE_DEVICE') and str.isdigit(os.getenv('NPU_CALCULATE_DEVICE')): - NPU_CALCULATE_DEVICE = int(os.getenv('NPU_CALCULATE_DEVICE')) -if torch.npu.current_device() != NPU_CALCULATE_DEVICE: - torch.npu.set_device(f'npu:{NPU_CALCULATE_DEVICE}') -NPU_WORLD_SIZE = int(os.getenv('NPU_WORLD_SIZE')) -RANK = int(os.getenv('RANK')) -torch.distributed.init_process_group('hccl', rank=RANK, world_size=NPU_WORLD_SIZE) -MAX = 2147483647 - -def _gen_seeds(shape): - return np.random.uniform(1, MAX, size=shape).astype(np.float32) -seed_shape = (32 * 1024 * 12, ) - - -class AverageMeter(object): - """Computes and stores the average and current value""" - - def __init__(self, name, fmt=':f'): - self.name = name - self.fmt = fmt - self.reset() - - def reset(self): - self.val = 0 - self.avg = 0 - self.sum = 0 - self.count = 0 - - def update(self, val, n=1): - self.val = val - self.sum += val * n - self.count += n - self.avg = self.sum / self.count - - def __str__(self): - fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' - return fmtstr.format(**self.__dict__) - - -class ProgressMeter(object): - def __init__(self, num_batches, meters, prefix=""): - self.batch_fmtstr = self._get_batch_fmtstr(num_batches) - self.meters = meters - self.prefix = prefix - - def display(self, batch): - entries = [self.prefix + self.batch_fmtstr.format(batch)] - entries += [str(meter) for meter in self.meters] - print('\t'.join(entries)) - - def _get_batch_fmtstr(self, num_batches): - num_digits = len(str(num_batches // 1)) - fmt = '{:' + str(num_digits) + 'd}' - return '[' + fmt + '/' + fmt.format(num_batches) + ']' - - -def main(): - parser = options.get_training_parser() - args = options.parse_args_and_arch(parser) - print(args) - os.environ['MASTER_ADDR'] = args.addr - os.environ['MASTER_PORT'] = args.port - #mp.spawn(main_worker, nprocs=args.distributed_world_size, args=(args.distributed_world_size, args)) - main_worker(pid_idx=RANK, args=args) - - - -def main_worker(pid_idx, args): - setup_logger(args) - print('pid_idx:',str(pid_idx)) - args.distributed_rank = pid_idx - args.device_id = args.distributed_rank - #dist.init_process_group(backend=args.dist_backend, world_size=NPU_WORLD_SIZE, rank=args.distributed_rank) - loc = 'npu:{}'.format(args.device_id) - torch.npu.set_device(loc) - - if args.max_tokens is None: - args.max_tokens = 6000 - - torch.manual_seed(args.seed) - - src_dict, tgt_dict = data_utils.load_dictionaries(args) - add_extra_items_to_checkpoint({'src_dict': src_dict, 'tgt_dict': tgt_dict}) - datasets = load_dataset_splits(args, ['train', 'valid', 'test'], src_dict, tgt_dict) - - seed = _gen_seeds(seed_shape) - seed = torch.from_numpy(seed) - seed = seed.to(loc) - model = build_model(args, seed=seed) - if args.distributed_world_size > 1 : - print('| num. model params: {}'.format(sum(p.numel() for p in model.parameters()))) - - # Build trainer - trainer = DDPTrainer(args, model) - if args.distributed_world_size > 1 : - print('| model {}, criterion {}'.format(args.arch, trainer.criterion.__class__.__name__)) - print('| training on {} NPUs'.format(args.distributed_world_size)) - - if args.distributed_world_size > 1 : - print('| max sentences per NPU = {}'.format(args.max_sentences)) - - epoch_itr = data.EpochBatchIterator( - dataset=datasets[args.train_subset], - max_tokens=args.max_tokens, - max_sentences=args.max_sentences_valid, - max_positions=args.max_positions, - ignore_invalid_inputs=True, - required_batch_size_multiple=8, - seed=args.seed, - num_shards=args.distributed_world_size, - shard_id=args.distributed_rank, - max_positions_num=96, - - ) - # Load the latest checkpoint if one is available - load_checkpoint(args, trainer, epoch_itr) - - # Train until the learning rate gets too small or model reaches target score - max_epoch = args.max_epoch or math.inf - max_update = args.max_update or math.inf - lr = trainer.get_lr() - train_meter = StopwatchMeter() - train_meter.start() - valid_losses = [None] - valid_subsets = args.valid_subset.split(',') - run_summary = {'loss': float('inf'), - 'val_loss': float('inf'), - 'speed': 0, - 'accuracy': 0} - - # max_update - m=0 - while lr >= args.min_lr and epoch_itr.epoch < max_epoch and trainer.get_num_updates() < max_update: - m=m+1 - if m >=2:pass - DLLogger.log(step=trainer.get_num_updates(), data={'epoch': epoch_itr.epoch}, verbosity=0) - # train for one epoch - train(args, trainer, datasets, epoch_itr) - - if epoch_itr.epoch % args.validate_interval == 0: - valid_losses = validate(args, trainer, datasets, valid_subsets) - DLLogger.log(step=trainer.get_num_updates(), data={'val_loss': valid_losses[0]}, - verbosity=1) - - - if valid_losses[0] < run_summary['val_loss']: - run_summary['val_loss'] = valid_losses[0] - run_summary['loss'] = valid_losses[0] - run_summary['speed'] = trainer.throughput_meter.u_avg - - # Only use first validation loss to update the learning rate - lr = trainer.lr_step(epoch_itr.epoch, valid_losses[0]) - - # Save checkpoint - if epoch_itr.epoch % args.save_interval == 0: - save_checkpoint(args, trainer, epoch_itr, valid_losses[0]) - - train_meter.stop() - DLLogger.log(step=[], data=run_summary, verbosity=0) - DLLogger.log(step='RUN', data={'walltime': train_meter.sum}, verbosity=0) - if args.distributed_world_size > 1 : - print('| done training in {:.1f} seconds'.format(train_meter.sum)) - - -def train(args, trainer, datasets, epoch_itr): - """Train the model for one epoch.""" - - itr = epoch_itr.next_epoch_itr() - - # update parameters every N batches - if epoch_itr.epoch <= len(args.update_freq): - update_freq = args.update_freq[epoch_itr.epoch - 1] - else: - update_freq = args.update_freq[-1] - - num_batches = len(epoch_itr) - - batch_time = AverageMeter('Time', ':6.3f') - sentence_s = AverageMeter('Sentence/s', ':6.3f') - losses = AverageMeter('Loss', ':.4f') - progress = ProgressMeter(int(num_batches/args.distributed_world_size/update_freq), - [batch_time, sentence_s,losses], - prefix = "Epoch: [{}]".format(epoch_itr.epoch)) - - first_valid = args.valid_subset.split(',')[0] - max_update = args.max_update or math.inf - - - # reset meters - DLLogger.flush() - trainer.get_throughput_meter().reset() - - for i, sample in enumerate(itr): - if i>100:pass - if i < num_batches - 1 and (i + 1) % update_freq > 0: - # buffer updates according to --update-freq - loss = trainer.train_step(sample, update_params=False, last_step=(i == len(itr) - 1)) - continue - else: - loss = trainer.train_step(sample, update_params=True, last_step=(i == len(itr) - 1)) - if loss != None: - losses.update(loss) - - if i >= 4: - t = time.time() - batch_time.update((t - end)/update_freq) - sentence_s.update(args.max_sentences/(t-end)*args.distributed_world_size) - end = time.time() - if i < 4: - end = time.time() - if i >= 4: - if args.distributed_world_size > 1 : - progress.display(int((i+1)/update_freq)) - - - # ignore the first mini-batch in words-per-second calculation - if i == 0: - trainer.get_throughput_meter().reset() - for backend in DLLogger.GLOBAL_LOGGER.backends: - if isinstance(backend, AggregatorBackend): - backend._reset_perf_meter('tokens') - backend._reset_perf_meter('updates') - break - - # Mid epoch checkpoint - num_updates = trainer.get_num_updates() - if args.distributed_world_size > 1 : - if args.save_interval_updates > 0 and num_updates % args.save_interval_updates == 0: - valid_losses = validate(args, trainer, datasets, [first_valid]) - save_checkpoint(args, trainer, epoch_itr, valid_losses[0]) - - if (i + 1) % args.log_interval == 0: - DLLogger.flush() - - if num_updates >= max_update: - break - - if args.distributed_world_size > 1 : - if batch_time.avg > 0: - print("End of epoch, batch_size:", args.max_sentences, 'Time: {:.3f}'.format(batch_time.avg), - ' Sentence/s@all {:.3f}'.format( - args.max_sentences / batch_time.avg * args.distributed_world_size)) - - # Print epoch stats and reset training meters - if args.distributed_world_size > 1 : - DLLogger.log(step=trainer.get_num_updates(), data={'speed': trainer.get_throughput_meter().avg}, verbosity=0) - DLLogger.flush() - - -def validate(args, trainer, datasets, subsets): - """Evaluate the model on the validation set(s) and return the losses.""" - # Reset value iterations counter - trainer._num_val_iterations = 0 - - valid_losses = [] - for subset in subsets: - - if len(subsets) > 1: - print('Validating on \'{}\' subset'.format(subset)) - - # Initialize data iterator - itr = data.EpochBatchIterator( - dataset=datasets[subset], - max_tokens=args.max_tokens, - max_sentences=args.max_sentences_valid, - max_positions=args.max_positions, - ignore_invalid_inputs=args.skip_invalid_size_inputs_valid_test, - required_batch_size_multiple=8, - seed=args.seed, - num_shards=args.distributed_world_size, - shard_id=args.distributed_rank, - max_positions_num=1024, - ).next_epoch_itr(shuffle=False) - - # reset validation loss meters - if args.distributed_world_size > 1 : - DLLogger.flush() - - subset_losses = [] - for sample in itr: - loss = trainer.valid_step(sample) - subset_losses.append(loss) - subset_loss = sum(subset_losses) / len(subset_losses) - - DLLogger.flush() - - valid_losses.append(subset_loss) - if args.distributed_world_size > 1 : - print(f'Validation loss on subset {subset}: {subset_loss}') - - return valid_losses - - - -def save_checkpoint(args, trainer, epoch_itr, val_loss): - if args.no_save or not distributed_utils.is_master(args): - return - epoch = epoch_itr.epoch - end_of_epoch = epoch_itr.end_of_epoch() - updates = trainer.get_num_updates() - - checkpoint_conds = collections.OrderedDict() - checkpoint_conds['checkpoint{}.pt'.format(epoch)] = ( - end_of_epoch and not args.no_epoch_checkpoints and - epoch % args.save_interval == 0 - ) - checkpoint_conds['checkpoint_{}_{}.pt'.format(epoch, updates)] = ( - not end_of_epoch and args.save_interval_updates > 0 and - updates % args.save_interval_updates == 0 - ) - checkpoint_conds['checkpoint_best.pt'] = ( - val_loss is not None and - (not hasattr(save_checkpoint, 'best') or val_loss < save_checkpoint.best) - ) - checkpoint_conds['checkpoint_last.pt'] = True # keep this last so that it's a symlink - - prev_best = getattr(save_checkpoint, 'best', val_loss) - if val_loss is not None: - save_checkpoint.best = min(val_loss, prev_best) - extra_state = { - 'best': save_checkpoint.best, - 'train_iterator': epoch_itr.state_dict(), - 'val_loss': val_loss, - } - extra_state.update(save_checkpoint.extra_items) - - checkpoints = [os.path.join(args.save_dir, 'checkpoints', fn) for fn, cond in checkpoint_conds.items() if cond] - if len(checkpoints) > 0: - for cp in checkpoints: - trainer.save_checkpoint(cp, extra_state) - - if not end_of_epoch and args.keep_interval_updates > 0: - # remove old checkpoints; checkpoints are sorted in descending order - checkpoints = utils.checkpoint_paths(os.path.join(args.save_dir, 'checkpoints'), - pattern=r'checkpoint_\d+_(\d+)\.pt') - for old_chk in checkpoints[args.keep_interval_updates:]: - os.remove(old_chk) - - -def add_extra_items_to_checkpoint(dict): - if not hasattr(save_checkpoint, 'extra_items'): - save_checkpoint.extra_items = {} - save_checkpoint.extra_items.update(dict) - - -def load_checkpoint(args, trainer, epoch_itr): - """Load a checkpoint and replay dataloader to match.""" - os.makedirs(os.path.join(args.save_dir, 'checkpoints'), exist_ok=True) - checkpoint_path = os.path.join(args.save_dir, 'checkpoints', args.restore_file) - if os.path.isfile(checkpoint_path): - extra_state = trainer.load_checkpoint(checkpoint_path) - if extra_state is not None: - # replay train iterator to match checkpoint - epoch_itr.load_state_dict(extra_state['train_iterator']) - if args.distributed_world_size > 1 : - print('| loaded checkpoint {} (epoch {} @ {} updates)'.format( - checkpoint_path, epoch_itr.epoch, trainer.get_num_updates())) - - trainer.lr_step(epoch_itr.epoch) - trainer.lr_step_update(trainer.get_num_updates()) - if 'best' in extra_state: - save_checkpoint.best = extra_state['best'] - - -if __name__ == '__main__': - main() +#!/usr/bin/env python3 -u +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# Copyright 2020 Huawei Technologies Co., Ltd +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. +# +# ------------------------------------------------------------------------- +# +# Copyright (c) 2019, NVIDIA CORPORATION. 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. +import collections +import itertools +import os +import math +import torch +import torch.npu +import time +import ctypes + +import sys +import threading + +from copy import deepcopy +from utils import distributed_utils, options, utils +from utils.ddp_trainer import DDPTrainer +from utils.meters import StopwatchMeter, TimeMeter +import data +from data import tokenizer, dictionary, data_utils, load_dataset_splits +from models import build_model +import torch.distributed as dist +import torch.multiprocessing as mp +import numpy as np + +import dllogger as DLLogger +from utils.log_helper import AggregatorBackend, setup_logger + + +NPU_CALCULATE_DEVICE = 0 +if os.getenv('NPU_CALCULATE_DEVICE') and str.isdigit(os.getenv('NPU_CALCULATE_DEVICE')): + NPU_CALCULATE_DEVICE = int(os.getenv('NPU_CALCULATE_DEVICE')) +if torch.npu.current_device() != NPU_CALCULATE_DEVICE: + torch.npu.set_device(f'npu:{NPU_CALCULATE_DEVICE}') +NPU_WORLD_SIZE = int(os.getenv('NPU_WORLD_SIZE')) +RANK = int(os.getenv('RANK')) +torch.distributed.init_process_group('hccl', rank=RANK, world_size=NPU_WORLD_SIZE) +MAX = 2147483647 + +def _gen_seeds(shape): + return np.random.uniform(1, MAX, size=shape).astype(np.float32) +seed_shape = (32 * 1024 * 12, ) + + +class AverageMeter(object): + """Computes and stores the average and current value""" + + def __init__(self, name, fmt=':f'): + self.name = name + self.fmt = fmt + self.reset() + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + + def update(self, val, n=1): + self.val = val + self.sum += val * n + self.count += n + self.avg = self.sum / self.count + + def __str__(self): + fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})' + return fmtstr.format(**self.__dict__) + + +class ProgressMeter(object): + def __init__(self, num_batches, meters, prefix=""): + self.batch_fmtstr = self._get_batch_fmtstr(num_batches) + self.meters = meters + self.prefix = prefix + + def display(self, batch): + entries = [self.prefix + self.batch_fmtstr.format(batch)] + entries += [str(meter) for meter in self.meters] + print('\t'.join(entries)) + + def _get_batch_fmtstr(self, num_batches): + num_digits = len(str(num_batches // 1)) + fmt = '{:' + str(num_digits) + 'd}' + return '[' + fmt + '/' + fmt.format(num_batches) + ']' + + +def main(): + parser = options.get_training_parser() + args = options.parse_args_and_arch(parser) + print(args) + os.environ['MASTER_ADDR'] = args.addr + os.environ['MASTER_PORT'] = args.port + #mp.spawn(main_worker, nprocs=args.distributed_world_size, args=(args.distributed_world_size, args)) + main_worker(pid_idx=RANK, args=args) + + + +def main_worker(pid_idx, args): + setup_logger(args) + print('pid_idx:',str(pid_idx)) + args.distributed_rank = pid_idx + args.device_id = args.distributed_rank + #dist.init_process_group(backend=args.dist_backend, world_size=NPU_WORLD_SIZE, rank=args.distributed_rank) + loc = 'npu:{}'.format(args.device_id) + torch.npu.set_device(loc) + + if args.max_tokens is None: + args.max_tokens = 6000 + + torch.manual_seed(args.seed) + + src_dict, tgt_dict = data_utils.load_dictionaries(args) + add_extra_items_to_checkpoint({'src_dict': src_dict, 'tgt_dict': tgt_dict}) + datasets = load_dataset_splits(args, ['train', 'valid', 'test'], src_dict, tgt_dict) + + seed = _gen_seeds(seed_shape) + seed = torch.from_numpy(seed) + seed = seed.to(loc) + model = build_model(args, seed=seed) + if args.distributed_world_size > 1 : + print('| num. model params: {}'.format(sum(p.numel() for p in model.parameters()))) + + # Build trainer + trainer = DDPTrainer(args, model) + if args.distributed_world_size > 1 : + print('| model {}, criterion {}'.format(args.arch, trainer.criterion.__class__.__name__)) + print('| training on {} NPUs'.format(args.distributed_world_size)) + + if args.distributed_world_size > 1 : + print('| max sentences per NPU = {}'.format(args.max_sentences)) + + epoch_itr = data.EpochBatchIterator( + dataset=datasets[args.train_subset], + max_tokens=args.max_tokens, + max_sentences=args.max_sentences_valid, + max_positions=args.max_positions, + ignore_invalid_inputs=True, + required_batch_size_multiple=8, + seed=args.seed, + num_shards=args.distributed_world_size, + shard_id=args.distributed_rank, + max_positions_num=96, + + ) + # Load the latest checkpoint if one is available + load_checkpoint(args, trainer, epoch_itr) + + # Train until the learning rate gets too small or model reaches target score + max_epoch = args.max_epoch or math.inf + max_update = args.max_update or math.inf + lr = trainer.get_lr() + train_meter = StopwatchMeter() + train_meter.start() + valid_losses = [None] + valid_subsets = args.valid_subset.split(',') + run_summary = {'loss': float('inf'), + 'val_loss': float('inf'), + 'speed': 0, + 'accuracy': 0} + + # max_update + m=0 + while lr >= args.min_lr and epoch_itr.epoch < max_epoch and trainer.get_num_updates() < max_update: + m=m+1 + if m >=2:pass + DLLogger.log(step=trainer.get_num_updates(), data={'epoch': epoch_itr.epoch}, verbosity=0) + # train for one epoch + train(args, trainer, datasets, epoch_itr) + + if epoch_itr.epoch % args.validate_interval == 0: + valid_losses = validate(args, trainer, datasets, valid_subsets) + DLLogger.log(step=trainer.get_num_updates(), data={'val_loss': valid_losses[0]}, + verbosity=1) + + + if valid_losses[0] < run_summary['val_loss']: + run_summary['val_loss'] = valid_losses[0] + run_summary['loss'] = valid_losses[0] + run_summary['speed'] = trainer.throughput_meter.u_avg + + # Only use first validation loss to update the learning rate + lr = trainer.lr_step(epoch_itr.epoch, valid_losses[0]) + + # Save checkpoint + if epoch_itr.epoch % args.save_interval == 0: + save_checkpoint(args, trainer, epoch_itr, valid_losses[0]) + + train_meter.stop() + DLLogger.log(step=[], data=run_summary, verbosity=0) + DLLogger.log(step='RUN', data={'walltime': train_meter.sum}, verbosity=0) + if args.distributed_world_size > 1 : + print('| done training in {:.1f} seconds'.format(train_meter.sum)) + + +def train(args, trainer, datasets, epoch_itr): + """Train the model for one epoch.""" + + itr = epoch_itr.next_epoch_itr() + + # update parameters every N batches + if epoch_itr.epoch <= len(args.update_freq): + update_freq = args.update_freq[epoch_itr.epoch - 1] + else: + update_freq = args.update_freq[-1] + + num_batches = len(epoch_itr) + + batch_time = AverageMeter('Time', ':6.3f') + sentence_s = AverageMeter('Sentence/s', ':6.3f') + losses = AverageMeter('Loss', ':.4f') + progress = ProgressMeter(int(num_batches/args.distributed_world_size/update_freq), + [batch_time, sentence_s,losses], + prefix = "Epoch: [{}]".format(epoch_itr.epoch)) + + first_valid = args.valid_subset.split(',')[0] + max_update = args.max_update or math.inf + + + # reset meters + DLLogger.flush() + trainer.get_throughput_meter().reset() + + for i, sample in enumerate(itr): + if i>100:pass + if i < num_batches - 1 and (i + 1) % update_freq > 0: + # buffer updates according to --update-freq + loss = trainer.train_step(sample, update_params=False, last_step=(i == len(itr) - 1)) + continue + else: + loss = trainer.train_step(sample, update_params=True, last_step=(i == len(itr) - 1)) + if loss != None: + losses.update(loss) + + if i >= 4: + t = time.time() + batch_time.update((t - end)/update_freq) + sentence_s.update(args.max_sentences/(t-end)*args.distributed_world_size) + end = time.time() + if i < 4: + end = time.time() + if i >= 4: + if args.distributed_world_size > 1 : + progress.display(int((i+1)/update_freq)) + + + # ignore the first mini-batch in words-per-second calculation + if i == 0: + trainer.get_throughput_meter().reset() + for backend in DLLogger.GLOBAL_LOGGER.backends: + if isinstance(backend, AggregatorBackend): + backend._reset_perf_meter('tokens') + backend._reset_perf_meter('updates') + break + + # Mid epoch checkpoint + num_updates = trainer.get_num_updates() + if args.distributed_world_size > 1 : + if args.save_interval_updates > 0 and num_updates % args.save_interval_updates == 0: + valid_losses = validate(args, trainer, datasets, [first_valid]) + save_checkpoint(args, trainer, epoch_itr, valid_losses[0]) + + if (i + 1) % args.log_interval == 0: + DLLogger.flush() + + if num_updates >= max_update: + break + + if args.distributed_world_size > 1 : + if batch_time.avg > 0: + print("End of epoch, batch_size:", args.max_sentences, 'Time: {:.3f}'.format(batch_time.avg), + ' Sentence/s@all {:.3f}'.format( + args.max_sentences / batch_time.avg * args.distributed_world_size)) + + # Print epoch stats and reset training meters + if args.distributed_world_size > 1 : + DLLogger.log(step=trainer.get_num_updates(), data={'speed': trainer.get_throughput_meter().avg}, verbosity=0) + DLLogger.flush() + + +def validate(args, trainer, datasets, subsets): + """Evaluate the model on the validation set(s) and return the losses.""" + # Reset value iterations counter + trainer._num_val_iterations = 0 + + valid_losses = [] + for subset in subsets: + + if len(subsets) > 1: + print('Validating on \'{}\' subset'.format(subset)) + + # Initialize data iterator + itr = data.EpochBatchIterator( + dataset=datasets[subset], + max_tokens=args.max_tokens, + max_sentences=args.max_sentences_valid, + max_positions=args.max_positions, + ignore_invalid_inputs=args.skip_invalid_size_inputs_valid_test, + required_batch_size_multiple=8, + seed=args.seed, + num_shards=args.distributed_world_size, + shard_id=args.distributed_rank, + max_positions_num=1024, + ).next_epoch_itr(shuffle=False) + + # reset validation loss meters + if args.distributed_world_size > 1 : + DLLogger.flush() + + subset_losses = [] + for sample in itr: + loss = trainer.valid_step(sample) + subset_losses.append(loss) + subset_loss = sum(subset_losses) / len(subset_losses) + + DLLogger.flush() + + valid_losses.append(subset_loss) + if args.distributed_world_size > 1 : + print(f'Validation loss on subset {subset}: {subset_loss}') + + return valid_losses + + + +def save_checkpoint(args, trainer, epoch_itr, val_loss): + if args.no_save or not distributed_utils.is_master(args): + return + epoch = epoch_itr.epoch + end_of_epoch = epoch_itr.end_of_epoch() + updates = trainer.get_num_updates() + + checkpoint_conds = collections.OrderedDict() + checkpoint_conds['checkpoint{}.pt'.format(epoch)] = ( + end_of_epoch and not args.no_epoch_checkpoints and + epoch % args.save_interval == 0 + ) + checkpoint_conds['checkpoint_{}_{}.pt'.format(epoch, updates)] = ( + not end_of_epoch and args.save_interval_updates > 0 and + updates % args.save_interval_updates == 0 + ) + checkpoint_conds['checkpoint_best.pt'] = ( + val_loss is not None and + (not hasattr(save_checkpoint, 'best') or val_loss < save_checkpoint.best) + ) + checkpoint_conds['checkpoint_last.pt'] = True # keep this last so that it's a symlink + + prev_best = getattr(save_checkpoint, 'best', val_loss) + if val_loss is not None: + save_checkpoint.best = min(val_loss, prev_best) + extra_state = { + 'best': save_checkpoint.best, + 'train_iterator': epoch_itr.state_dict(), + 'val_loss': val_loss, + } + extra_state.update(save_checkpoint.extra_items) + + checkpoints = [os.path.join(args.save_dir, 'checkpoints', fn) for fn, cond in checkpoint_conds.items() if cond] + if len(checkpoints) > 0: + for cp in checkpoints: + trainer.save_checkpoint(cp, extra_state) + + if not end_of_epoch and args.keep_interval_updates > 0: + # remove old checkpoints; checkpoints are sorted in descending order + checkpoints = utils.checkpoint_paths(os.path.join(args.save_dir, 'checkpoints'), + pattern=r'checkpoint_\d+_(\d+)\.pt') + for old_chk in checkpoints[args.keep_interval_updates:]: + os.remove(old_chk) + + +def add_extra_items_to_checkpoint(dict): + if not hasattr(save_checkpoint, 'extra_items'): + save_checkpoint.extra_items = {} + save_checkpoint.extra_items.update(dict) + + +def load_checkpoint(args, trainer, epoch_itr): + """Load a checkpoint and replay dataloader to match.""" + os.makedirs(os.path.join(args.save_dir, 'checkpoints'), exist_ok=True) + checkpoint_path = os.path.join(args.save_dir, 'checkpoints', args.restore_file) + if os.path.isfile(checkpoint_path): + extra_state = trainer.load_checkpoint(checkpoint_path) + if extra_state is not None: + # replay train iterator to match checkpoint + epoch_itr.load_state_dict(extra_state['train_iterator']) + if args.distributed_world_size > 1 : + print('| loaded checkpoint {} (epoch {} @ {} updates)'.format( + checkpoint_path, epoch_itr.epoch, trainer.get_num_updates())) + + trainer.lr_step(epoch_itr.epoch) + trainer.lr_step_update(trainer.get_num_updates()) + if 'best' in extra_state: + save_checkpoint.best = extra_state['best'] + + +if __name__ == '__main__': + main() diff --git a/README.CN.md b/README.CN.md index 059ea029af..d02f2d6226 100644 --- a/README.CN.md +++ b/README.CN.md @@ -1,621 +1,621 @@ -# 欢迎使用Ascend ModelZoo - -为方便更多开发者使用Ascend ModelZoo,我们将持续增加典型网络和相关预训练模型。如果您有任何需求,请在[modelzoo/issues](https://gitee.com/ascend/modelzoo/issues)提交issue,我们会及时处理。 - -## 如何贡献 - -在开始贡献之前,请先阅读[CONTRIBUTING](https://gitee.com/ascend/modelzoo/blob/master/CONTRIBUTING.md)。 -谢谢! - -## 目录 - - -### PyTorch - -#### built-in - -- [3D_ResNet_ID0421_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/3D_ResNet_ID0421_for_PyTorch) -- [CRNN_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/CRNN_for_PyTorch) -- [DeepMar_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/DeepMar_for_PyTorch) -- [Densenet121_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch) -- [DenseNet161_ID0455_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/DenseNet161_ID0455_for_PyTorch) -- [DenseNet169_ID0454_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/DenseNet169_ID0454_for_PyTorch) -- [DenseNet201_ID0453_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/DenseNet201_ID0453_for_PyTorch) -- [EfficientNet-B1_ID1713_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/EfficientNet-B1_ID1713_for_PyTorch) -- [EfficientNet-B2_ID1714_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/EfficientNet-B2_ID1714_for_PyTorch) -- [EfficientNet-B3_ID0450_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/EfficientNet-B3_ID0450_for_PyTorch) -- [EfficientNet-B4_ID1632_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/EfficientNet-B4_ID1632_for_PyTorch) -- [EfficientNet-B5_ID1633_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/EfficientNet-B5_ID1633_for_PyTorch) -- [EfficientNet_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch) -- [FaceNet_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/FaceNet_for_PyTorch) -- [Gluon_ResNet50_v1b_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/Gluon_ResNet50_v1b_for_PyTorch) -- [Gluon_ResNet50_v1c_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/Gluon_ResNet50_v1c_for_PyTorch) -- [Gluon_ResNet50_v1d_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/Gluon_ResNet50_v1d_for_PyTorch) -- [Googlenet_ID0447_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/Googlenet_ID0447_for_PyTorch) -- [MobileNetV1_ID0094_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/MobileNetV1_ID0094_for_PyTorch) -- [MobileNetV2_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/MobileNetV2_for_PyTorch) -- [MobileNetV3-Large_ID1784_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/MobileNetV3-Large_ID1784_for_PyTorch) -- [ResNest_ID0426_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/ResNest_ID0426_for_PyTorch) -- [ResNet50_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch) -- [Shufflenetv2_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/Shufflenetv2_for_PyTorch) -- [DAL_ID2732_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/detection/DAL_ID2732_for_PyTorch) -- [DB_ID0706_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/detection/DB_ID0706_for_PyTorch) -- [Faster_Mask_RCNN_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch) -- [PSENet_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/detection/PSENet_for_PyTorch) -- [RetinaNet_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch) -- [RFCN_ID0418_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/detection/RFCN_ID0418_for_PyTorch) -- [YoloV3_ID1790_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/detection/YoloV3_ID1790_for_PyTorch) -- [YOLOV4_ID0396_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/detection/YOLOV4_ID0396_for_PyTorch) -- [Attention_R2U_Net_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch) -- [AttU_Net_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/semantic_segmentation/AttU_Net_for_PyTorch) -- [DeepLabv3+_ID1695_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/semantic_segmentation/DeepLabv3+_ID1695_for_PyTorch) -- [R2U_Net_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch) -- [Bert-Squad_ID0470_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/nlp/Bert-Squad_ID0470_for_PyTorch) -- [CPM_Finetune_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/nlp/CPM_Finetune_for_PyTorch) -- [FOTS_ID0338_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/nlp/FOTS_ID0338_for_PyTorch) -- [GRU_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/nlp/GRU_for_PyTorch) -- [LSTM_ID0468_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/nlp/LSTM_ID0468_for_PyTorch) -- [mBART_ID2372_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/nlp/mBART_ID2372_for_PyTorch) -- [Transformer_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/nlp/Transformer_for_PyTorch) -- [XLM_ID0740_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/nlp/XLM_ID0740_for_PyTorch) -- [DCN_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/others/DCN_for_PyTorch) -- [DeepFM_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/others/DeepFM_for_PyTorch) -- [WDL_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/others/WDL_for_PyTorch) - -#### contrib - -- [baseline-rawnet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/audio/baseline-rawnet) -- [deepspeech](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/audio/deepspeech) -- [FastPitch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/audio/FastPitch) -- [speech-transformer](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/audio/speech-transformer) -- [Tacotron2_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/audio/Tacotron2_for_PyTorch) -- [tdnn](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/audio/tdnn) -- [WaveGlow](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/audio/WaveGlow) -- [3d_attention_net](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/3d_attention_net) -- [AlexNet_ID2663_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/AlexNet_ID2663_for_PyTorch) -- [AlignedReID](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/AlignedReID) -- [csp_resnext50-mish](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/csp_resnext50-mish) -- [Deit_Small](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Deit_Small) -- [DnCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/DnCNN) -- [DPN-131_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/DPN-131_for_PyTorch) -- [Efficient-3DCNNs_ID1230_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Efficient-3DCNNs_ID1230_for_PyTorch) -- [EfficientNet-B1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/EfficientNet-B1) -- [EfficientNet-B3](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/EfficientNet-B3) -- [EfficientNet-B5_ID1621_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/EfficientNet-B5_ID1621_for_PyTorch) -- [FixRes](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/FixRes) -- [GaitSet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/GaitSet) -- [GENet_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/GENet_for_Pytorch) -- [GhostNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/GhostNet) -- [GoogleNet_ID1623_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/GoogleNet_ID1623_for_PyTorch) -- [HRNet_ID1780_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/HRNet_ID1780_for_PyTorch) -- [InceptionResNetV2_ID1779_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/InceptionResNetV2_ID1779_for_PyTorch) -- [InceptionV3_ID1596_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/InceptionV3_ID1596_for_PyTorch) -- [InceptionV4_ID1778_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/InceptionV4_ID1778_for_PyTorch) -- [LResNet100E-IR](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/LResNet100E-IR) -- [MGN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/MGN) -- [MnasNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/MnasNet) -- [MobileNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/MobileNet) -- [MobileNetV3_large_100_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/MobileNetV3_large_100_for_PyTorch) -- [Moco-v2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Moco-v2) -- [NASNet-A-Mobile](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/NASNet-A-Mobile) -- [OSNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/OSNet) -- [PCB](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/PCB) -- [PnasNet5Large](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/PnasNet5Large) -- [PointNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/PointNet) -- [pointnetCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/pointnetCNN) -- [RegNetX](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/RegNetX) -- [RegNetY-1.6GF](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/RegNetY-1.6GF) -- [ReidStrongBaseline](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ReidStrongBaseline) -- [RepVGG](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/RepVGG) -- [Res2Net101_v1b](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Res2Net101_v1b) -- [ResNeSt50_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ResNeSt50_for_PyTorch) -- [ResNet101_ID1595_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ResNet101_ID1595_for_PyTorch) -- [ResNet152](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ResNet152) -- [ResNet18_ID1593_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ResNet18_ID1593_for_PyTorch) -- [ResNet34_ID1594_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ResNet34_ID1594_for_PyTorch) -- [ResNeXt-50-32x4d_ID1624_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ResNeXt-50-32x4d_ID1624_for_PyTorch) -- [ResNeXt101_32x8d_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ResNeXt101_32x8d_for_PyTorch) -- [SE-ResNet-50](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/SE-ResNet-50) -- [SE-ResNext-101-32x4d](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/SE-ResNext-101-32x4d) -- [Se-ResNext-50-32x4d](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d) -- [SENet154](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/SENet154) -- [ShuffleNetV1_ID1625_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ShuffleNetV1_ID1625_for_PyTorch) -- [ShuffleNetV2Plus_ID1626_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ShuffleNetV2Plus_ID1626_for_PyTorch) -- [SkresNet50](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/SkresNet50) -- [SPNASNet_100_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/SPNASNet_100_for_PyTorch) -- [SqueezeNet1_1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/SqueezeNet1_1) -- [Swin-Transformer](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Swin-Transformer) -- [TNT](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/TNT) -- [TResNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/TResNet) -- [Vehicle_Re-Identification](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Vehicle_Re-Identification) -- [Vgg16_ID1630_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Vgg16_ID1630_for_PyTorch) -- [Vgg19_ID1631_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Vgg19_ID1631_for_PyTorch) -- [vit_base_patch32_224](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/vit_base_patch32_224) -- [Vit_small_patch16_224](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Vit_small_patch16_224) -- [VOLO](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/VOLO) -- [VoVNet39](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/VoVNet39) -- [WideResNet101_2_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/WideResNet101_2_for_Pytorch) -- [WideResNet50_2_ID1627_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/WideResNet50_2_ID1627_for_PyTorch) -- [Xception_ID1777_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch) -- [xcit](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/xcit) -- [AdvancedEAST](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/AdvancedEAST) -- [CascadedMaskRCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/CascadedMaskRCNN) -- [Cascade_RCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/Cascade_RCNN) -- [CenterFace](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/CenterFace) -- [CenterNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/CenterNet) -- [DSFD](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/DSFD) -- [EfficientDetD0](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/EfficientDetD0) -- [FaceBoxes](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/FaceBoxes) -- [FairMOT](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/FairMOT) -- [FCOS](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/FCOS) -- [FOTS](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/FOTS) -- [FSAF_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/FSAF_for_Pytorch) -- [GFocalV2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/GFocalV2) -- [M2Det](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/M2Det) -- [NasFPN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/NasFPN) -- [Pointnetplus](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/Pointnetplus) -- [Pyramidbox](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/Pyramidbox) -- [RCF](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/RCF) -- [RefineDet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/RefineDet) -- [Retinaface](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/Retinaface) -- [RetinaNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/RetinaNet) -- [SimCLR_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch) -- [SOLOv1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/SOLOv1) -- [SOLOv2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/SOLOv2) -- [SSD](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/SSD) -- [SSD-MobileNetV1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/SSD-MobileNetV1) -- [SSD-MobilenetV2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/SSD-MobilenetV2) -- [SSD-Resnet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/SSD-Resnet) -- [StyleGAN2-ADA](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/StyleGAN2-ADA) -- [TextSnake](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/TextSnake) -- [YOLACT](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/YOLACT) -- [YOLACT_plus](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/YOLACT_plus) -- [YOLOR](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/YOLOR) -- [YOLOX](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/YOLOX) -- [ADNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/ADNet) -- [BigGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/BigGAN) -- [CGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/CGAN) -- [Cross-Scale-Non-Local-Attention](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/Cross-Scale-Non-Local-Attention) -- [CycleGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/CycleGAN) -- [DCGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/DCGAN) -- [edsr_x2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/edsr_x2) -- [GAN_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/GAN_Pytorch) -- [Pix2Pix](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/Pix2Pix) -- [RDN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/RDN) -- [Srcnn_x2_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/Srcnn_x2_for_Pytorch) -- [SRFlow](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/SRFlow) -- [SRGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/SRGAN) -- [stargan](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/stargan) -- [wdsr](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/wdsr) -- [3Dmppe_RootNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet) -- [AlphaPose](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/AlphaPose) -- [DeepPose](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/DeepPose) -- [HigherHRNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/HigherHRNet) -- [Hourglass_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch) -- [Lightweight_OpenPose](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose) -- [MSPN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/MSPN) -- [ST-GCN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/ST-GCN) -- [TransPose](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/TransPose) -- [VoxelPose](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/VoxelPose) -- [3DUNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/3DUNet) -- [DeeplabV3_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/DeeplabV3_for_Pytorch) -- [ENet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/ENet) -- [ErfNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/ErfNet) -- [FastSCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/FastSCNN) -- [FCN8s](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/FCN8s) -- [HRnet-OCR](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/HRnet-OCR) -- [HRNet_SEG_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/HRNet_SEG_for_Pytorch) -- [ICNet_ID1781_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/ICNet_ID1781_for_PyTorch) -- [IntraDA](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/IntraDA) -- [PointRend](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/PointRend) -- [PraNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/PraNet) -- [PSPNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/PSPNet) -- [RCAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/RCAN) -- [RefineNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/RefineNet) -- [SETR](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/SETR) -- [Ultra-Fast-Lane-Detection](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/Ultra-Fast-Lane-Detection) -- [UNet++](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/UNet++) -- [UNet_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/UNet_for_PyTorch) -- [VNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/VNet) -- [Wseg](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/Wseg) -- [BMN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/BMN) -- [BSN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/BSN) -- [C3D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/C3D) -- [GloRe](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/GloRe) -- [I3D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/I3D) -- [NonLocal](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/NonLocal) -- [R(2+1)D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/R(2+1)D) -- [SiamFC](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/SiamFC) -- [SiamRPN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/SiamRPN) -- [SlowFast](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/SlowFast) -- [TSM](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/TSM) -- [TSN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/TSN) -- [VideoPose3D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/VideoPose3D) -- [X3D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/X3D) -- [albert](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/nlp/albert) -- [Bertsum_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/nlp/Bertsum_for_PyTorch) -- [roberta](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/nlp/roberta) -- [TextCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/nlp/TextCNN) -- [tinybert](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/nlp/tinybert) -- [C51](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/others/C51) -- [DLRM](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/others/DLRM) -- [DQN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/others/DQN) -- [RotatE](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/others/RotatE) - -#### dev - -- [tacotron2_ID0406_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/audio/tacotron2_ID0406_for_PyTorch) -- [3D_attentionnet_ID0478_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/detection/3D_attentionnet_ID0478_for_PyTorch) -- [FasterRCNN-Resnet50-FPN_ID1552_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/detection/FasterRCNN-Resnet50-FPN_ID1552_for_PyTorch) -- [HRNet_ID0446_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/detection/HRNet_ID0446_for_PyTorch) -- [PointNet_ID0430_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/detection/PointNet_ID0430_for_PyTorch) -- [SSD-ResNet34_ID0411_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/detection/SSD-ResNet34_ID0411_for_PyTorch) -- [2D_Unet_ID0624_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/2D_Unet_ID0624_for_PyTorch) -- [2S-AGCN_ID0909_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/2S-AGCN_ID0909_for_PyTorch) -- [3D_Nest_Unet_ID0476_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/3D_Nest_Unet_ID0476_for_PyTorch) -- [ADACOS_ID1082_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ADACOS_ID1082_for_PyTorch) -- [AdaFM-Net_ID1101_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/AdaFM-Net_ID1101_for_PyTorch) -- [ADLayer_ID1087_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ADLayer_ID1087_for_PyTorch) -- [AdvancedEast_ID0473_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/AdvancedEast_ID0473_for_PyTorch) -- [AlexNet_ID0472_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/AlexNet_ID0472_for_PyTorch) -- [ANN_ID2370_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ANN_ID2370_for_PyTorch) -- [ArcFace_ID0852_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ArcFace_ID0852_for_PyTorch) -- [ATS_ID2682_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ATS_ID2682_for_PyTorch) -- [AUTOAUGMENT_ID0792_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/AUTOAUGMENT_ID0792_for_PyTorch) -- [BASNET_ID1134_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/BASNET_ID1134_for_PyTorch) -- [BertBase_ID0490_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/BertBase_ID0490_for_PyTorch) -- [CDAR_ID2747_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/CDAR_ID2747_for_PyTorch) -- [ConvLSTM_ID1772_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ConvLSTM_ID1772_for_PyTorch) -- [coral-cnn_ID1064_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/coral-cnn_ID1064_for_PyTorch) -- [CrossFormer_ID2449_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/CrossFormer_ID2449_for_PyTorch) -- [CycleGAN_ID0521_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/CycleGAN_ID0521_for_PyTorch) -- [DBPN_ID2917_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/DBPN_ID2917_for_PyTorch) -- [DCAP_ID2836_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/DCAP_ID2836_for_PyTorch) -- [DEEP-HEAD-POSE_ID0796_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/DEEP-HEAD-POSE_ID0796_for_PyTorch) -- [DeepLab-CRF_ID1873_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/DeepLab-CRF_ID1873_for_PyTorch) -- [DeepSort_ID0654_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/DeepSort_ID0654_for_PyTorch) -- [deit_ID2467_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/deit_ID2467_for_PyTorch) -- [DGMS_ID2460_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/DGMS_ID2460_for_PyTorch) -- [EfficientNet-B6_ID1715_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/EfficientNet-B6_ID1715_for_PyTorch) -- [EfficientNet-B7_ID1716_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/EfficientNet-B7_ID1716_for_PyTorch) -- [ESPCN_ID2919_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ESPCN_ID2919_for_PyTorch) -- [ESPCN_ID3002_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ESPCN_ID3002_for_PyTorch) -- [ESRGAN_ID1813_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ESRGAN_ID1813_for_PyTorch) -- [FasterRCNN_ID0100_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/FasterRCNN_ID0100_for_PyTorch) -- [FFDNet_ID0970_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/FFDNet_ID0970_for_PyTorch) -- [FixMatch_ID0989_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/FixMatch_ID0989_for_PyTorch) -- [GENet_ID0671_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/GENet_ID0671_for_PyTorch) -- [GhostNet_ID1622_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/GhostNet_ID1622_for_PyTorch) -- [Hourglass_ID1809_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Hourglass_ID1809_for_PyTorch) -- [ICT_ID1179_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ICT_ID1179_for_PyTorch) -- [InceptionV1_ID1568_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/InceptionV1_ID1568_for_PyTorch) -- [InceptionV2_ID0698_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/InceptionV2_ID0698_for_PyTorch) -- [InceptionV3_ID0445_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/InceptionV3_ID0445_for_PyTorch) -- [InceptionV4_ID0444_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/InceptionV4_ID0444_for_PyTorch) -- [InceptionV4_ID2473_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/InceptionV4_ID2473_for_PyTorch) -- [Keyword-MLP_ID2441_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Keyword-MLP_ID2441_for_PyTorch) -- [LADE_ID2445_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/LADE_ID2445_for_PyTorch) -- [MaskRCNN_ID0101_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/MaskRCNN_ID0101_for_PyTorch) -- [mBART_ID1550_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/mBART_ID1550_for_PyTorch) -- [MMAL-NET_ID1116_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/MMAL-NET_ID1116_for_PyTorch) -- [MMOE_ID2865_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/MMOE_ID2865_for_PyTorch) -- [Mnasnet0_75_ID0439_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Mnasnet0_75_ID0439_for_PyTorch) -- [Mnasnet1_0_ID0438_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Mnasnet1_0_ID0438_for_PyTorch) -- [Mnasnet1_3_ID0437_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Mnasnet1_3_ID0437_for_PyTorch) -- [mobilenetv2_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/mobilenetv2_for_Pytorch) -- [MobileNetV3-Small_ID1785_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/MobileNetV3-Small_ID1785_for_PyTorch) -- [MSPN_ID0960_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/MSPN_ID0960_for_PyTorch) -- [MTCNN_ID0435_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/MTCNN_ID0435_for_PyTorch) -- [Mutual-Channel-Loss_ID1113_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Mutual-Channel-Loss_ID1113_for_PyTorch) -- [NeuMF_ID0351_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/NeuMF_ID0351_for_PyTorch) -- [PASSRnet_ID0986_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/PASSRnet_ID0986_for_PyTorch) -- [pFedMe_ID1597_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/pFedMe_ID1597_for_PyTorch) -- [PFF_ID1128_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/PFF_ID1128_for_PyTorch) -- [PiT_ID2671_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/PiT_ID2671_for_PyTorch) -- [Pix2Pix_ID0331_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Pix2Pix_ID0331_for_PyTorch) -- [POOLNET_ID0875_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/POOLNET_ID0875_for_PyTorch) -- [Pysot_ID0428_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Pysot_ID0428_for_PyTorch) -- [RAFT_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/RAFT_for_PyTorch) -- [RANet_ID0994_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/RANet_ID0994_for_PyTorch) -- [RES2NET_ID0824_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/RES2NET_ID0824_for_PyTorch) -- [residual_adapters_ID1598_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/residual_adapters_ID1598_for_PyTorch) -- [Resnet101_ID0425_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Resnet101_ID0425_for_PyTorch) -- [ResNet152_ID0424_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ResNet152_ID0424_for_PyTorch) -- [Resnet152_ID1592_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Resnet152_ID1592_for_PyTorch) -- [Resnet18_ID0423_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Resnet18_ID0423_for_PyTorch) -- [Resnet34_ID0422_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Resnet34_ID0422_for_PyTorch) -- [Resnext101_32x8d_ID0420_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Resnext101_32x8d_ID0420_for_PyTorch) -- [ResNeXt101_ID1717_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ResNeXt101_ID1717_for_PyTorch) -- [ResNeXt50_ID0419_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ResNeXt50_ID0419_for_PyTorch) -- [RRN_ID1182_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/RRN_ID1182_for_PyTorch) -- [RUC_ID2470_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/RUC_ID2470_for_PyTorch) -- [SEResNext_ID0415_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SEResNext_ID0415_for_PyTorch) -- [SG2IM_ID0786_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SG2IM_ID0786_for_PyTorch) -- [SimplePose_ID1038_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SimplePose_ID1038_for_PyTorch) -- [SINGLESHOTPOSE_ID0869_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SINGLESHOTPOSE_ID0869_for_PyTorch) -- [SlowFast_ID0646_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SlowFast_ID0646_for_PyTorch) -- [SmartSketch_ID1046_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SmartSketch_ID1046_for_PyTorch) -- [SqueezeNet_ID0413_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SqueezeNet_ID0413_for_PyTorch) -- [SRCNN_ID1770_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SRCNN_ID1770_for_PyTorch) -- [SRGAN_ID2956_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SRGAN_ID2956_for_PyTorch) -- [SSD-MobileNet_ID1936_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SSD-MobileNet_ID1936_for_PyTorch) -- [STARGAN_ID0725_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/STARGAN_ID0725_for_PyTorch) -- [Swin-Transformer_ID2377_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Swin-Transformer_ID2377_for_PyTorch) -- [TabNet_ID2862_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/TabNet_ID2862_for_PyTorch) -- [Token-to-Token-ViT_ID2668_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Token-to-Token-ViT_ID2668_for_PyTorch) -- [TransformerXL_ID0699_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/TransformerXL_ID0699_for_PyTorch) -- [VAE+GAN_ID0401_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/VAE+GAN_ID0401_for_PyTorch) -- [VGG16_ID0467_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/VGG16_ID0467_for_PyTorch) -- [VGG19_ID0244_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/VGG19_ID0244_for_PyTorch) -- [VGGNet_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch) -- [VGGNet_ID0400_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/VGGNet_ID0400_for_PyTorch) -- [vit-base_ID0492_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/vit-base_ID0492_for_PyTorch) -- [VIT_ID2381_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/VIT_ID2381_for_PyTorch) -- [Wide_resnet101_2_ID0398_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Wide_resnet101_2_ID0398_for_PyTorch) -- [Wide_resnet50_2_ID0397_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Wide_resnet50_2_ID0397_for_PyTorch) -- [Xception_ID1454_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Xception_ID1454_for_PyTorch) -- [ZERO-DCE_ID1040_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ZERO-DCE_ID1040_for_PyTorch) -- [deeplabv3+_ID0326_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_segmentation/deeplabv3+_ID0326_for_PyTorch) -- [DeepLabV3+_ID0458_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_segmentation/DeepLabV3+_ID0458_for_PyTorch) -- [DeepLabV3_ID0621_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_segmentation/DeepLabV3_ID0621_for_PyTorch) -- [SETR_ID1572_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_segmentation/SETR_ID1572_for_PyTorch) -- [GAN_ID1931_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_synthesis/GAN_ID1931_for_PyTorch) -- [DSCNN_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch) -- [FFA-NET_ID1043_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/quality_enhancement/FFA-NET_ID1043_for_PyTorch) -- [BERT-ITPT-FiT_ID0340_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/nlp/BERT-ITPT-FiT_ID0340_for_PyTorch) -- [BERT_base_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/nlp/BERT_base_for_PyTorch) -- [FairSeq_Transformer_ID0496_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/nlp/FairSeq_Transformer_ID0496_for_PyTorch) -- [Retinanet_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/nlp/Retinanet_for_PyTorch) -- [Speech_Transformer_ID0487_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/nlp/Speech_Transformer_ID0487_for_PyTorch) -- [Swin-Transformer_ID2375_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/nlp/Swin-Transformer_ID2375_for_PyTorch) -- [Swin-Transformer_ID2379_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/nlp/Swin-Transformer_ID2379_for_PyTorch) -- [Textcnn_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/nlp/Textcnn_for_PyTorch) -- [Transformer_ID0105_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch) -- [Multi-Gradient_Descent_ID0349_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/others/Multi-Gradient_Descent_ID0349_for_PyTorch) -- [Widedeep_ID2866_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/others/Widedeep_ID2866_for_PyTorch) - -### ACL_PyTorch - -#### built-in - -- [EspNet_for_Pytoch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/audio/EspNet_for_Pytoch) -- [Jasper_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/audio/Jasper_for_PyTorch) -- [LSTM](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/audio/LSTM) -- [RawNet2_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch) -- [Tacotron2_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/audio/Tacotron2_for_Pytorch) -- [TDNN_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch) -- [Wenet_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/audio/Wenet_for_Pytorch) -- [3DUnet_for_PTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/3DUnet_for_PTorch) -- [CascadeRCNN-DCN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/CascadeRCNN-DCN) -- [CascadeRCNN-DCN-101_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/CascadeRCNN-DCN-101_for_Pytorch) -- [CenterNet_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch) -- [CRNN_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch) -- [DB_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/DB_for_PyTorch) -- [Deepmar_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch) -- [Deepsort_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Deepsort_for_Pytorch) -- [Densenet121_Pytorch_Infer](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Densenet121_Pytorch_Infer) -- [DPN131_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/DPN131_for_Pytorch) -- [EfficientNet_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/EfficientNet_for_Pytorch) -- [FasterRCNN-DCN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/FasterRCNN-DCN) -- [Flownet2_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Flownet2_for_Pytorch) -- [GoogleNet_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/GoogleNet_for_Pytorch) -- [I3D_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/I3D_for_Pytorch) -- [InceptionV3_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/InceptionV3_for_Pytorch) -- [InceptionV4_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/InceptionV4_for_Pytorch) -- [MobileNetV2_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch) -- [Pelee_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Pelee_for_Pytorch) -- [PSENet_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch) -- [Res2Net_v1b_101_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch) -- [Resnet101_Pytorch_Infer](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer) -- [Resnet18_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch) -- [Resnet34_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Resnet34_for_Pytorch) -- [Resnet50_Pytorch_Infer](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Resnet50_Pytorch_Infer) -- [ResNeXt50_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/ResNeXt50_for_Pytorch) -- [SE_ResNet50_Pytorch_Infer](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer) -- [Shufflenetv2_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch) -- [STGCN_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/STGCN_for_Pytorch) -- [U2-Net_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/U2-Net_for_PyTorch) -- [Vgg16_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Vgg16_for_Pytorch) -- [VGG16_SSD_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/VGG16_SSD_for_PyTorch) -- [Vgg19_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Vgg19_for_Pytorch) -- [Wide_ResNet50_2_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Wide_ResNet50_2_for_Pytorch) -- [YolactEdge_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch) -- [Yolov3_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch) -- [Yolov4_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch) -- [Yolov5_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Yolov5_for_Pytorch) -- [Bert_Base_Uncased](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/nlp/Bert_Base_Uncased) -- [CNN_Transformer_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/nlp/CNN_Transformer_for_Pytorch) -- [textcnn](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/nlp/textcnn) -- [TransformerXL_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/nlp/TransformerXL_for_Pytorch) -- [VilBert_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/nlp/VilBert_for_Pytorch) - -#### contrib - -- [FastPitch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/audio/FastPitch) -- [Jasper](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/audio/Jasper) -- [Speech-Transformer](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/audio/Speech-Transformer) -- [tdnn](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/audio/tdnn) -- [3d_attention_net](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/3d_attention_net) -- [AlexNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/AlexNet) -- [baseline_dino_resnet50](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50) -- [BMN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/BMN) -- [C3D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/C3D) -- [CSPResneXt50](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/CSPResneXt50) -- [Deit_Small](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Deit_Small) -- [DPN131](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/DPN131) -- [Efficient-3DCNNs](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs) -- [EfficientNet-B1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1) -- [EfficientNet-B3](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B3) -- [EfficientNet-B5](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B5) -- [FixRes](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/FixRes) -- [GaitSet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/GaitSet) -- [GENet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/GENet) -- [GhostNet1.0x](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x) -- [GloRe](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/GloRe) -- [HRNet-Image-Classification](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification) -- [InceptionResnetV2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/InceptionResnetV2) -- [LResNet100E-IR](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/LResNet100E-IR) -- [LV-Vit](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/LV-Vit) -- [Mnasnet1_0](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Mnasnet1_0) -- [MobileNet-v1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/MobileNet-v1) -- [MobileNetV3_large_100](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/MobileNetV3_large_100) -- [Moco-v2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Moco-v2) -- [OSNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/OSNet) -- [PAMTRI](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/PAMTRI) -- [pnasnet5large](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/pnasnet5large) -- [PointNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/PointNet) -- [PointNetCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/PointNetCNN) -- [Pointnetplus](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Pointnetplus) -- [R(2+1)D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/R(2+1)D) -- [RegNetX-1.6GF](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/RegNetX-1.6GF) -- [RegNetY-1.6GF](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/RegNetY-1.6GF) -- [ReID_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/ReID_for_Pytorch) -- [RepVGG](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/RepVGG) -- [Res2Net101_v1b](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b) -- [ResNeSt50](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/ResNeSt50) -- [ResNet101](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/ResNet101) -- [ResNet152](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/ResNet152) -- [ResNet18](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/ResNet18) -- [ResNet34](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/ResNet34) -- [ResNext101_32x8d](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/ResNext101_32x8d) -- [Se-Resnext101](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Se-Resnext101) -- [SENet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/SENet) -- [Shufflenetv1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1) -- [Shufflenetv2+](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+) -- [SimCLR_inference](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/SimCLR_inference) -- [Sknet50](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Sknet50) -- [spnasnet_100](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/spnasnet_100) -- [Squeezenet1_1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Squeezenet1_1) -- [Swin-Transformer](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Swin-Transformer) -- [TNT](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/TNT) -- [TResNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/TResNet) -- [vit-small](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/vit-small) -- [vit_base_patch32_224](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224) -- [vovnet39](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/vovnet39) -- [Wide_ResNet101_2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2) -- [X3D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/X3D) -- [xception](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/xception) -- [xcit](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/xcit) -- [3DUnet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/3DUnet) -- [AdvancedEAST](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/AdvancedEAST) -- [AlphaPose](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/AlphaPose) -- [BSN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/BSN) -- [Cascade-RCNN-Resnet101-FPN-DCN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN) -- [Cascade_RCNN_R101](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101) -- [CenterFace](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/CenterFace) -- [CenterNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/CenterNet) -- [CTPN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/CTPN) -- [Deepspeech](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/Deepspeech) -- [Detr](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/Detr) -- [DSFD](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/DSFD) -- [EfficientDetD0](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/EfficientDetD0) -- [EfficientDetD7](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/EfficientDetD7) -- [FairMOT](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/FairMOT) -- [FasterRCNN_FPN_DCN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/FasterRCNN_FPN_DCN) -- [Fcos](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/Fcos) -- [FOTS](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/FOTS) -- [Fsaf](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/Fsaf) -- [GFocalV2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/GFocalV2) -- [M2Det](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/M2Det) -- [Nasnetlarge](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/Nasnetlarge) -- [NAS_FPN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/NAS_FPN) -- [OpenPose](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/OpenPose) -- [pyramidbox](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/pyramidbox) -- [RCF](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/RCF) -- [RefineDet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/RefineDet) -- [Retinanet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/Retinanet) -- [RFCN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/RFCN) -- [SSD](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/SSD) -- [SSD-MobileNetV1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/SSD-MobileNetV1) -- [SSD-MobileNetV2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/SSD-MobileNetV2) -- [SSD-Resnet34](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/SSD-Resnet34) -- [TextSnake](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/TextSnake) -- [yolor](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/yolor) -- [YOLOX](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/YOLOX) -- [AlignedReID](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/face/AlignedReID) -- [FaceBoxes](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/face/FaceBoxes) -- [FaceNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/face/FaceNet) -- [ReId-MGN-master](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/face/ReId-MGN-master) -- [reid_PCB_baseline](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline) -- [Retinaface](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/face/Retinaface) -- [BigGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/gan/BigGAN) -- [CGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/gan/CGAN) -- [CycleGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/gan/CycleGAN) -- [DCGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/gan/DCGAN) -- [GAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/gan/GAN) -- [Pix2Pix](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/gan/Pix2Pix) -- [Pix2pixHD](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/gan/Pix2pixHD) -- [StarGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/gan/StarGAN) -- [Cross-Scale-Non-Local-Attention](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention) -- [DnCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/image_process/DnCNN) -- [SRFlow](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/image_process/SRFlow) -- [wdsr](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/image_process/wdsr) -- [3DMPPE-ROOTNET](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET) -- [HigherHRNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/pose_estimation/HigherHRNet) -- [MSPN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/pose_estimation/MSPN) -- [TransPose](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/pose_estimation/TransPose) -- [VideoPose3D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/pose_estimation/VideoPose3D) -- [ADNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet) -- [SRGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/quality_enhancement/SRGAN) -- [3D_HRNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/3D_HRNet) -- [Cascade_Mask_RCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/Cascade_Mask_RCNN) -- [Cascade_RCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/Cascade_RCNN) -- [DeeplabV3](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3) -- [ENet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/ENet) -- [ErfNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/ErfNet) -- [FastSCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/FastSCNN) -- [FCN-8s](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/FCN-8s) -- [GCNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/GCNet) -- [ICNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/ICNet) -- [IntraDA](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/IntraDA) -- [Nested_UNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/Nested_UNet) -- [PointRend](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/PointRend) -- [PraNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/PraNet) -- [PSPnet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/PSPnet) -- [RefineNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/RefineNet) -- [SETR](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/SETR) -- [SiamMask](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/SiamMask) -- [SOLOV1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/SOLOV1) -- [SOLOV2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/SOLOV2) -- [Ultra-Fast-Lane-Detection](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/Ultra-Fast-Lane-Detection) -- [VNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/VNet) -- [Wseg](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/Wseg) -- [YOLACT](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/YOLACT) -- [YOLACT_plus](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus) -- [EDSR](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/super_resolution/EDSR) -- [RCAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/super_resolution/RCAN) -- [RDN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/super_resolution/RDN) -- [Real-ESRGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN) -- [SRCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/super_resolution/SRCNN) -- [SiamFC](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/tracking/SiamFC) -- [SiamRPN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/tracking/SiamRPN) -- [I3D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/video_understanding/I3D) -- [NonLocal](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/video_understanding/NonLocal) -- [SlowFast](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/video_understanding/SlowFast) -- [TSM](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/video_understanding/TSM) -- [TSN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/video_understanding/TSN) -- [RotatE](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/knowledge/RotatE) -- [albert](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/nlp/albert) -- [BertSum](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/nlp/BertSum) -- [CNN_Transformer_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/nlp/CNN_Transformer_for_Pytorch) -- [roberta](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/nlp/roberta) -- [TextCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/nlp/TextCNN) -- [tinybert](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/nlp/tinybert) -- [c51](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/rl/c51) -- [DQN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/rl/DQN) - - - - - - - -## 免责声明 - -Ascend ModelZoo仅提供公共数据集下载和预处理脚本。这些数据集不属于ModelZoo,ModelZoo也不对其质量或维护负责。请确保您具有这些数据集的使用许可。基于这些数据集训练的模型仅可用于非商业研究和教育。 - -致数据集所有者: - -如果您不希望您的数据集公布在ModelZoo上或希望更新ModelZoo中属于您的数据集,请在Github/Gitee提交issue,我们将根据您的issue删除或更新您的数据集。衷心感谢您对我们社区的理解和贡献。 - -Ascend ModelZoo的license是Apache 2.0.具体内容,请参见LICENSE文件。 +# 欢迎使用Ascend ModelZoo + +为方便更多开发者使用Ascend ModelZoo,我们将持续增加典型网络和相关预训练模型。如果您有任何需求,请在[modelzoo/issues](https://gitee.com/ascend/modelzoo/issues)提交issue,我们会及时处理。 + +## 如何贡献 + +在开始贡献之前,请先阅读[CONTRIBUTING](https://gitee.com/ascend/modelzoo/blob/master/CONTRIBUTING.md)。 +谢谢! + +## 目录 + + +### PyTorch + +#### built-in + +- [3D_ResNet_ID0421_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/3D_ResNet_ID0421_for_PyTorch) +- [CRNN_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/CRNN_for_PyTorch) +- [DeepMar_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/DeepMar_for_PyTorch) +- [Densenet121_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/Densenet121_for_PyTorch) +- [DenseNet161_ID0455_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/DenseNet161_ID0455_for_PyTorch) +- [DenseNet169_ID0454_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/DenseNet169_ID0454_for_PyTorch) +- [DenseNet201_ID0453_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/DenseNet201_ID0453_for_PyTorch) +- [EfficientNet-B1_ID1713_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/EfficientNet-B1_ID1713_for_PyTorch) +- [EfficientNet-B2_ID1714_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/EfficientNet-B2_ID1714_for_PyTorch) +- [EfficientNet-B3_ID0450_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/EfficientNet-B3_ID0450_for_PyTorch) +- [EfficientNet-B4_ID1632_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/EfficientNet-B4_ID1632_for_PyTorch) +- [EfficientNet-B5_ID1633_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/EfficientNet-B5_ID1633_for_PyTorch) +- [EfficientNet_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/EfficientNet_for_PyTorch) +- [FaceNet_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/FaceNet_for_PyTorch) +- [Gluon_ResNet50_v1b_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/Gluon_ResNet50_v1b_for_PyTorch) +- [Gluon_ResNet50_v1c_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/Gluon_ResNet50_v1c_for_PyTorch) +- [Gluon_ResNet50_v1d_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/Gluon_ResNet50_v1d_for_PyTorch) +- [Googlenet_ID0447_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/Googlenet_ID0447_for_PyTorch) +- [MobileNetV1_ID0094_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/MobileNetV1_ID0094_for_PyTorch) +- [MobileNetV2_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/MobileNetV2_for_PyTorch) +- [MobileNetV3-Large_ID1784_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/MobileNetV3-Large_ID1784_for_PyTorch) +- [ResNest_ID0426_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/ResNest_ID0426_for_PyTorch) +- [ResNet50_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/ResNet50_for_PyTorch) +- [Shufflenetv2_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/classification/Shufflenetv2_for_PyTorch) +- [DAL_ID2732_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/detection/DAL_ID2732_for_PyTorch) +- [DB_ID0706_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/detection/DB_ID0706_for_PyTorch) +- [Faster_Mask_RCNN_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/detection/Faster_Mask_RCNN_for_PyTorch) +- [PSENet_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/detection/PSENet_for_PyTorch) +- [RetinaNet_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/detection/RetinaNet_for_PyTorch) +- [RFCN_ID0418_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/detection/RFCN_ID0418_for_PyTorch) +- [YoloV3_ID1790_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/detection/YoloV3_ID1790_for_PyTorch) +- [YOLOV4_ID0396_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/detection/YOLOV4_ID0396_for_PyTorch) +- [Attention_R2U_Net_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/semantic_segmentation/Attention_R2U_Net_for_PyTorch) +- [AttU_Net_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/semantic_segmentation/AttU_Net_for_PyTorch) +- [DeepLabv3+_ID1695_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/semantic_segmentation/DeepLabv3+_ID1695_for_PyTorch) +- [R2U_Net_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/cv/semantic_segmentation/R2U_Net_for_PyTorch) +- [Bert-Squad_ID0470_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/nlp/Bert-Squad_ID0470_for_PyTorch) +- [CPM_Finetune_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/nlp/CPM_Finetune_for_PyTorch) +- [FOTS_ID0338_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/nlp/FOTS_ID0338_for_PyTorch) +- [GRU_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/nlp/GRU_for_PyTorch) +- [LSTM_ID0468_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/nlp/LSTM_ID0468_for_PyTorch) +- [mBART_ID2372_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/nlp/mBART_ID2372_for_PyTorch) +- [Transformer_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/nlp/Transformer_for_PyTorch) +- [XLM_ID0740_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/nlp/XLM_ID0740_for_PyTorch) +- [DCN_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/others/DCN_for_PyTorch) +- [DeepFM_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/others/DeepFM_for_PyTorch) +- [WDL_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/built-in/others/WDL_for_PyTorch) + +#### contrib + +- [baseline-rawnet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/audio/baseline-rawnet) +- [deepspeech](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/audio/deepspeech) +- [FastPitch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/audio/FastPitch) +- [speech-transformer](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/audio/speech-transformer) +- [Tacotron2_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/audio/Tacotron2_for_PyTorch) +- [tdnn](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/audio/tdnn) +- [WaveGlow](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/audio/WaveGlow) +- [3d_attention_net](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/3d_attention_net) +- [AlexNet_ID2663_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/AlexNet_ID2663_for_PyTorch) +- [AlignedReID](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/AlignedReID) +- [csp_resnext50-mish](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/csp_resnext50-mish) +- [Deit_Small](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Deit_Small) +- [DnCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/DnCNN) +- [DPN-131_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/DPN-131_for_PyTorch) +- [Efficient-3DCNNs_ID1230_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Efficient-3DCNNs_ID1230_for_PyTorch) +- [EfficientNet-B1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/EfficientNet-B1) +- [EfficientNet-B3](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/EfficientNet-B3) +- [EfficientNet-B5_ID1621_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/EfficientNet-B5_ID1621_for_PyTorch) +- [FixRes](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/FixRes) +- [GaitSet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/GaitSet) +- [GENet_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/GENet_for_Pytorch) +- [GhostNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/GhostNet) +- [GoogleNet_ID1623_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/GoogleNet_ID1623_for_PyTorch) +- [HRNet_ID1780_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/HRNet_ID1780_for_PyTorch) +- [InceptionResNetV2_ID1779_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/InceptionResNetV2_ID1779_for_PyTorch) +- [InceptionV3_ID1596_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/InceptionV3_ID1596_for_PyTorch) +- [InceptionV4_ID1778_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/InceptionV4_ID1778_for_PyTorch) +- [LResNet100E-IR](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/LResNet100E-IR) +- [MGN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/MGN) +- [MnasNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/MnasNet) +- [MobileNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/MobileNet) +- [MobileNetV3_large_100_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/MobileNetV3_large_100_for_PyTorch) +- [Moco-v2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Moco-v2) +- [NASNet-A-Mobile](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/NASNet-A-Mobile) +- [OSNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/OSNet) +- [PCB](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/PCB) +- [PnasNet5Large](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/PnasNet5Large) +- [PointNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/PointNet) +- [pointnetCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/pointnetCNN) +- [RegNetX](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/RegNetX) +- [RegNetY-1.6GF](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/RegNetY-1.6GF) +- [ReidStrongBaseline](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ReidStrongBaseline) +- [RepVGG](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/RepVGG) +- [Res2Net101_v1b](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Res2Net101_v1b) +- [ResNeSt50_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ResNeSt50_for_PyTorch) +- [ResNet101_ID1595_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ResNet101_ID1595_for_PyTorch) +- [ResNet152](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ResNet152) +- [ResNet18_ID1593_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ResNet18_ID1593_for_PyTorch) +- [ResNet34_ID1594_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ResNet34_ID1594_for_PyTorch) +- [ResNeXt-50-32x4d_ID1624_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ResNeXt-50-32x4d_ID1624_for_PyTorch) +- [ResNeXt101_32x8d_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ResNeXt101_32x8d_for_PyTorch) +- [SE-ResNet-50](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/SE-ResNet-50) +- [SE-ResNext-101-32x4d](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/SE-ResNext-101-32x4d) +- [Se-ResNext-50-32x4d](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Se-ResNext-50-32x4d) +- [SENet154](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/SENet154) +- [ShuffleNetV1_ID1625_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ShuffleNetV1_ID1625_for_PyTorch) +- [ShuffleNetV2Plus_ID1626_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/ShuffleNetV2Plus_ID1626_for_PyTorch) +- [SkresNet50](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/SkresNet50) +- [SPNASNet_100_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/SPNASNet_100_for_PyTorch) +- [SqueezeNet1_1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/SqueezeNet1_1) +- [Swin-Transformer](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Swin-Transformer) +- [TNT](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/TNT) +- [TResNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/TResNet) +- [Vehicle_Re-Identification](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Vehicle_Re-Identification) +- [Vgg16_ID1630_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Vgg16_ID1630_for_PyTorch) +- [Vgg19_ID1631_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Vgg19_ID1631_for_PyTorch) +- [vit_base_patch32_224](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/vit_base_patch32_224) +- [Vit_small_patch16_224](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Vit_small_patch16_224) +- [VOLO](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/VOLO) +- [VoVNet39](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/VoVNet39) +- [WideResNet101_2_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/WideResNet101_2_for_Pytorch) +- [WideResNet50_2_ID1627_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/WideResNet50_2_ID1627_for_PyTorch) +- [Xception_ID1777_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/Xception_ID1777_for_PyTorch) +- [xcit](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/classification/xcit) +- [AdvancedEAST](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/AdvancedEAST) +- [CascadedMaskRCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/CascadedMaskRCNN) +- [Cascade_RCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/Cascade_RCNN) +- [CenterFace](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/CenterFace) +- [CenterNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/CenterNet) +- [DSFD](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/DSFD) +- [EfficientDetD0](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/EfficientDetD0) +- [FaceBoxes](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/FaceBoxes) +- [FairMOT](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/FairMOT) +- [FCOS](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/FCOS) +- [FOTS](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/FOTS) +- [FSAF_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/FSAF_for_Pytorch) +- [GFocalV2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/GFocalV2) +- [M2Det](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/M2Det) +- [NasFPN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/NasFPN) +- [Pointnetplus](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/Pointnetplus) +- [Pyramidbox](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/Pyramidbox) +- [RCF](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/RCF) +- [RefineDet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/RefineDet) +- [Retinaface](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/Retinaface) +- [RetinaNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/RetinaNet) +- [SimCLR_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/SimCLR_for_Pytorch) +- [SOLOv1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/SOLOv1) +- [SOLOv2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/SOLOv2) +- [SSD](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/SSD) +- [SSD-MobileNetV1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/SSD-MobileNetV1) +- [SSD-MobilenetV2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/SSD-MobilenetV2) +- [SSD-Resnet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/SSD-Resnet) +- [StyleGAN2-ADA](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/StyleGAN2-ADA) +- [TextSnake](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/TextSnake) +- [YOLACT](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/YOLACT) +- [YOLACT_plus](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/YOLACT_plus) +- [YOLOR](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/YOLOR) +- [YOLOX](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/detection/YOLOX) +- [ADNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/ADNet) +- [BigGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/BigGAN) +- [CGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/CGAN) +- [Cross-Scale-Non-Local-Attention](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/Cross-Scale-Non-Local-Attention) +- [CycleGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/CycleGAN) +- [DCGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/DCGAN) +- [edsr_x2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/edsr_x2) +- [GAN_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/GAN_Pytorch) +- [Pix2Pix](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/Pix2Pix) +- [RDN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/RDN) +- [Srcnn_x2_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/Srcnn_x2_for_Pytorch) +- [SRFlow](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/SRFlow) +- [SRGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/SRGAN) +- [stargan](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/stargan) +- [wdsr](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/others/wdsr) +- [3Dmppe_RootNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/3Dmppe_RootNet) +- [AlphaPose](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/AlphaPose) +- [DeepPose](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/DeepPose) +- [HigherHRNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/HigherHRNet) +- [Hourglass_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch) +- [Lightweight_OpenPose](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/Lightweight_OpenPose) +- [MSPN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/MSPN) +- [ST-GCN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/ST-GCN) +- [TransPose](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/TransPose) +- [VoxelPose](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/pose_estimation/VoxelPose) +- [3DUNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/3DUNet) +- [DeeplabV3_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/DeeplabV3_for_Pytorch) +- [ENet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/ENet) +- [ErfNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/ErfNet) +- [FastSCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/FastSCNN) +- [FCN8s](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/FCN8s) +- [HRnet-OCR](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/HRnet-OCR) +- [HRNet_SEG_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/HRNet_SEG_for_Pytorch) +- [ICNet_ID1781_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/ICNet_ID1781_for_PyTorch) +- [IntraDA](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/IntraDA) +- [PointRend](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/PointRend) +- [PraNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/PraNet) +- [PSPNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/PSPNet) +- [RCAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/RCAN) +- [RefineNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/RefineNet) +- [SETR](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/SETR) +- [Ultra-Fast-Lane-Detection](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/Ultra-Fast-Lane-Detection) +- [UNet++](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/UNet++) +- [UNet_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/UNet_for_PyTorch) +- [VNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/VNet) +- [Wseg](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/semantic_segmentation/Wseg) +- [BMN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/BMN) +- [BSN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/BSN) +- [C3D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/C3D) +- [GloRe](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/GloRe) +- [I3D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/I3D) +- [NonLocal](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/NonLocal) +- [R(2+1)D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/R(2+1)D) +- [SiamFC](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/SiamFC) +- [SiamRPN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/SiamRPN) +- [SlowFast](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/SlowFast) +- [TSM](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/TSM) +- [TSN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/TSN) +- [VideoPose3D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/VideoPose3D) +- [X3D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/cv/video/X3D) +- [albert](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/nlp/albert) +- [Bertsum_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/nlp/Bertsum_for_PyTorch) +- [roberta](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/nlp/roberta) +- [TextCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/nlp/TextCNN) +- [tinybert](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/nlp/tinybert) +- [C51](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/others/C51) +- [DLRM](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/others/DLRM) +- [DQN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/others/DQN) +- [RotatE](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/contrib/others/RotatE) + +#### dev + +- [tacotron2_ID0406_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/audio/tacotron2_ID0406_for_PyTorch) +- [3D_attentionnet_ID0478_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/detection/3D_attentionnet_ID0478_for_PyTorch) +- [FasterRCNN-Resnet50-FPN_ID1552_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/detection/FasterRCNN-Resnet50-FPN_ID1552_for_PyTorch) +- [HRNet_ID0446_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/detection/HRNet_ID0446_for_PyTorch) +- [PointNet_ID0430_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/detection/PointNet_ID0430_for_PyTorch) +- [SSD-ResNet34_ID0411_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/detection/SSD-ResNet34_ID0411_for_PyTorch) +- [2D_Unet_ID0624_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/2D_Unet_ID0624_for_PyTorch) +- [2S-AGCN_ID0909_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/2S-AGCN_ID0909_for_PyTorch) +- [3D_Nest_Unet_ID0476_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/3D_Nest_Unet_ID0476_for_PyTorch) +- [ADACOS_ID1082_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ADACOS_ID1082_for_PyTorch) +- [AdaFM-Net_ID1101_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/AdaFM-Net_ID1101_for_PyTorch) +- [ADLayer_ID1087_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ADLayer_ID1087_for_PyTorch) +- [AdvancedEast_ID0473_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/AdvancedEast_ID0473_for_PyTorch) +- [AlexNet_ID0472_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/AlexNet_ID0472_for_PyTorch) +- [ANN_ID2370_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ANN_ID2370_for_PyTorch) +- [ArcFace_ID0852_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ArcFace_ID0852_for_PyTorch) +- [ATS_ID2682_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ATS_ID2682_for_PyTorch) +- [AUTOAUGMENT_ID0792_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/AUTOAUGMENT_ID0792_for_PyTorch) +- [BASNET_ID1134_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/BASNET_ID1134_for_PyTorch) +- [BertBase_ID0490_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/BertBase_ID0490_for_PyTorch) +- [CDAR_ID2747_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/CDAR_ID2747_for_PyTorch) +- [ConvLSTM_ID1772_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ConvLSTM_ID1772_for_PyTorch) +- [coral-cnn_ID1064_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/coral-cnn_ID1064_for_PyTorch) +- [CrossFormer_ID2449_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/CrossFormer_ID2449_for_PyTorch) +- [CycleGAN_ID0521_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/CycleGAN_ID0521_for_PyTorch) +- [DBPN_ID2917_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/DBPN_ID2917_for_PyTorch) +- [DCAP_ID2836_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/DCAP_ID2836_for_PyTorch) +- [DEEP-HEAD-POSE_ID0796_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/DEEP-HEAD-POSE_ID0796_for_PyTorch) +- [DeepLab-CRF_ID1873_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/DeepLab-CRF_ID1873_for_PyTorch) +- [DeepSort_ID0654_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/DeepSort_ID0654_for_PyTorch) +- [deit_ID2467_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/deit_ID2467_for_PyTorch) +- [DGMS_ID2460_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/DGMS_ID2460_for_PyTorch) +- [EfficientNet-B6_ID1715_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/EfficientNet-B6_ID1715_for_PyTorch) +- [EfficientNet-B7_ID1716_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/EfficientNet-B7_ID1716_for_PyTorch) +- [ESPCN_ID2919_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ESPCN_ID2919_for_PyTorch) +- [ESPCN_ID3002_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ESPCN_ID3002_for_PyTorch) +- [ESRGAN_ID1813_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ESRGAN_ID1813_for_PyTorch) +- [FasterRCNN_ID0100_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/FasterRCNN_ID0100_for_PyTorch) +- [FFDNet_ID0970_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/FFDNet_ID0970_for_PyTorch) +- [FixMatch_ID0989_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/FixMatch_ID0989_for_PyTorch) +- [GENet_ID0671_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/GENet_ID0671_for_PyTorch) +- [GhostNet_ID1622_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/GhostNet_ID1622_for_PyTorch) +- [Hourglass_ID1809_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Hourglass_ID1809_for_PyTorch) +- [ICT_ID1179_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ICT_ID1179_for_PyTorch) +- [InceptionV1_ID1568_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/InceptionV1_ID1568_for_PyTorch) +- [InceptionV2_ID0698_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/InceptionV2_ID0698_for_PyTorch) +- [InceptionV3_ID0445_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/InceptionV3_ID0445_for_PyTorch) +- [InceptionV4_ID0444_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/InceptionV4_ID0444_for_PyTorch) +- [InceptionV4_ID2473_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/InceptionV4_ID2473_for_PyTorch) +- [Keyword-MLP_ID2441_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Keyword-MLP_ID2441_for_PyTorch) +- [LADE_ID2445_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/LADE_ID2445_for_PyTorch) +- [MaskRCNN_ID0101_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/MaskRCNN_ID0101_for_PyTorch) +- [mBART_ID1550_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/mBART_ID1550_for_PyTorch) +- [MMAL-NET_ID1116_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/MMAL-NET_ID1116_for_PyTorch) +- [MMOE_ID2865_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/MMOE_ID2865_for_PyTorch) +- [Mnasnet0_75_ID0439_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Mnasnet0_75_ID0439_for_PyTorch) +- [Mnasnet1_0_ID0438_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Mnasnet1_0_ID0438_for_PyTorch) +- [Mnasnet1_3_ID0437_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Mnasnet1_3_ID0437_for_PyTorch) +- [mobilenetv2_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/mobilenetv2_for_Pytorch) +- [MobileNetV3-Small_ID1785_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/MobileNetV3-Small_ID1785_for_PyTorch) +- [MSPN_ID0960_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/MSPN_ID0960_for_PyTorch) +- [MTCNN_ID0435_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/MTCNN_ID0435_for_PyTorch) +- [Mutual-Channel-Loss_ID1113_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Mutual-Channel-Loss_ID1113_for_PyTorch) +- [NeuMF_ID0351_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/NeuMF_ID0351_for_PyTorch) +- [PASSRnet_ID0986_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/PASSRnet_ID0986_for_PyTorch) +- [pFedMe_ID1597_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/pFedMe_ID1597_for_PyTorch) +- [PFF_ID1128_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/PFF_ID1128_for_PyTorch) +- [PiT_ID2671_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/PiT_ID2671_for_PyTorch) +- [Pix2Pix_ID0331_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Pix2Pix_ID0331_for_PyTorch) +- [POOLNET_ID0875_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/POOLNET_ID0875_for_PyTorch) +- [Pysot_ID0428_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Pysot_ID0428_for_PyTorch) +- [RAFT_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/RAFT_for_PyTorch) +- [RANet_ID0994_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/RANet_ID0994_for_PyTorch) +- [RES2NET_ID0824_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/RES2NET_ID0824_for_PyTorch) +- [residual_adapters_ID1598_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/residual_adapters_ID1598_for_PyTorch) +- [Resnet101_ID0425_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Resnet101_ID0425_for_PyTorch) +- [ResNet152_ID0424_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ResNet152_ID0424_for_PyTorch) +- [Resnet152_ID1592_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Resnet152_ID1592_for_PyTorch) +- [Resnet18_ID0423_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Resnet18_ID0423_for_PyTorch) +- [Resnet34_ID0422_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Resnet34_ID0422_for_PyTorch) +- [Resnext101_32x8d_ID0420_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Resnext101_32x8d_ID0420_for_PyTorch) +- [ResNeXt101_ID1717_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ResNeXt101_ID1717_for_PyTorch) +- [ResNeXt50_ID0419_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ResNeXt50_ID0419_for_PyTorch) +- [RRN_ID1182_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/RRN_ID1182_for_PyTorch) +- [RUC_ID2470_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/RUC_ID2470_for_PyTorch) +- [SEResNext_ID0415_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SEResNext_ID0415_for_PyTorch) +- [SG2IM_ID0786_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SG2IM_ID0786_for_PyTorch) +- [SimplePose_ID1038_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SimplePose_ID1038_for_PyTorch) +- [SINGLESHOTPOSE_ID0869_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SINGLESHOTPOSE_ID0869_for_PyTorch) +- [SlowFast_ID0646_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SlowFast_ID0646_for_PyTorch) +- [SmartSketch_ID1046_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SmartSketch_ID1046_for_PyTorch) +- [SqueezeNet_ID0413_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SqueezeNet_ID0413_for_PyTorch) +- [SRCNN_ID1770_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SRCNN_ID1770_for_PyTorch) +- [SRGAN_ID2956_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SRGAN_ID2956_for_PyTorch) +- [SSD-MobileNet_ID1936_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/SSD-MobileNet_ID1936_for_PyTorch) +- [STARGAN_ID0725_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/STARGAN_ID0725_for_PyTorch) +- [Swin-Transformer_ID2377_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Swin-Transformer_ID2377_for_PyTorch) +- [TabNet_ID2862_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/TabNet_ID2862_for_PyTorch) +- [Token-to-Token-ViT_ID2668_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Token-to-Token-ViT_ID2668_for_PyTorch) +- [TransformerXL_ID0699_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/TransformerXL_ID0699_for_PyTorch) +- [VAE+GAN_ID0401_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/VAE+GAN_ID0401_for_PyTorch) +- [VGG16_ID0467_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/VGG16_ID0467_for_PyTorch) +- [VGG19_ID0244_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/VGG19_ID0244_for_PyTorch) +- [VGGNet_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/VGGNet_for_Pytorch) +- [VGGNet_ID0400_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/VGGNet_ID0400_for_PyTorch) +- [vit-base_ID0492_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/vit-base_ID0492_for_PyTorch) +- [VIT_ID2381_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/VIT_ID2381_for_PyTorch) +- [Wide_resnet101_2_ID0398_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Wide_resnet101_2_ID0398_for_PyTorch) +- [Wide_resnet50_2_ID0397_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Wide_resnet50_2_ID0397_for_PyTorch) +- [Xception_ID1454_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/Xception_ID1454_for_PyTorch) +- [ZERO-DCE_ID1040_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_classification/ZERO-DCE_ID1040_for_PyTorch) +- [deeplabv3+_ID0326_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_segmentation/deeplabv3+_ID0326_for_PyTorch) +- [DeepLabV3+_ID0458_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_segmentation/DeepLabV3+_ID0458_for_PyTorch) +- [DeepLabV3_ID0621_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_segmentation/DeepLabV3_ID0621_for_PyTorch) +- [SETR_ID1572_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_segmentation/SETR_ID1572_for_PyTorch) +- [GAN_ID1931_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/image_synthesis/GAN_ID1931_for_PyTorch) +- [DSCNN_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/quality_enhancement/DSCNN_for_PyTorch) +- [FFA-NET_ID1043_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/cv/quality_enhancement/FFA-NET_ID1043_for_PyTorch) +- [BERT-ITPT-FiT_ID0340_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/nlp/BERT-ITPT-FiT_ID0340_for_PyTorch) +- [BERT_base_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/nlp/BERT_base_for_PyTorch) +- [FairSeq_Transformer_ID0496_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/nlp/FairSeq_Transformer_ID0496_for_PyTorch) +- [Retinanet_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/nlp/Retinanet_for_PyTorch) +- [Speech_Transformer_ID0487_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/nlp/Speech_Transformer_ID0487_for_PyTorch) +- [Swin-Transformer_ID2375_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/nlp/Swin-Transformer_ID2375_for_PyTorch) +- [Swin-Transformer_ID2379_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/nlp/Swin-Transformer_ID2379_for_PyTorch) +- [Textcnn_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/nlp/Textcnn_for_PyTorch) +- [Transformer_ID0105_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/nlp/Transformer_ID0105_for_PyTorch) +- [Multi-Gradient_Descent_ID0349_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/others/Multi-Gradient_Descent_ID0349_for_PyTorch) +- [Widedeep_ID2866_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/PyTorch/dev/others/Widedeep_ID2866_for_PyTorch) + +### ACL_PyTorch + +#### built-in + +- [EspNet_for_Pytoch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/audio/EspNet_for_Pytoch) +- [Jasper_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/audio/Jasper_for_PyTorch) +- [LSTM](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/audio/LSTM) +- [RawNet2_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/audio/RawNet2_for_Pytorch) +- [Tacotron2_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/audio/Tacotron2_for_Pytorch) +- [TDNN_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/audio/TDNN_for_Pytorch) +- [Wenet_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/audio/Wenet_for_Pytorch) +- [3DUnet_for_PTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/3DUnet_for_PTorch) +- [CascadeRCNN-DCN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/CascadeRCNN-DCN) +- [CascadeRCNN-DCN-101_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/CascadeRCNN-DCN-101_for_Pytorch) +- [CenterNet_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/CenterNet_for_Pytorch) +- [CRNN_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/CRNN_for_Pytorch) +- [DB_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/DB_for_PyTorch) +- [Deepmar_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Deepmar_for_Pytorch) +- [Deepsort_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Deepsort_for_Pytorch) +- [Densenet121_Pytorch_Infer](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Densenet121_Pytorch_Infer) +- [DPN131_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/DPN131_for_Pytorch) +- [EfficientNet_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/EfficientNet_for_Pytorch) +- [FasterRCNN-DCN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/FasterRCNN-DCN) +- [Flownet2_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Flownet2_for_Pytorch) +- [GoogleNet_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/GoogleNet_for_Pytorch) +- [I3D_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/I3D_for_Pytorch) +- [InceptionV3_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/InceptionV3_for_Pytorch) +- [InceptionV4_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/InceptionV4_for_Pytorch) +- [MobileNetV2_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/MobileNetV2_for_Pytorch) +- [Pelee_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Pelee_for_Pytorch) +- [PSENet_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/PSENet_for_Pytorch) +- [Res2Net_v1b_101_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Res2Net_v1b_101_for_PyTorch) +- [Resnet101_Pytorch_Infer](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Resnet101_Pytorch_Infer) +- [Resnet18_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Resnet18_for_PyTorch) +- [Resnet34_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Resnet34_for_Pytorch) +- [Resnet50_Pytorch_Infer](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Resnet50_Pytorch_Infer) +- [ResNeXt50_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/ResNeXt50_for_Pytorch) +- [SE_ResNet50_Pytorch_Infer](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/SE_ResNet50_Pytorch_Infer) +- [Shufflenetv2_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Shufflenetv2_for_Pytorch) +- [STGCN_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/STGCN_for_Pytorch) +- [U2-Net_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/U2-Net_for_PyTorch) +- [Vgg16_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Vgg16_for_Pytorch) +- [VGG16_SSD_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/VGG16_SSD_for_PyTorch) +- [Vgg19_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Vgg19_for_Pytorch) +- [Wide_ResNet50_2_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Wide_ResNet50_2_for_Pytorch) +- [YolactEdge_for_PyTorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/YolactEdge_for_PyTorch) +- [Yolov3_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Yolov3_for_Pytorch) +- [Yolov4_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Yolov4_for_Pytorch) +- [Yolov5_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/cv/Yolov5_for_Pytorch) +- [Bert_Base_Uncased](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/nlp/Bert_Base_Uncased) +- [CNN_Transformer_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/nlp/CNN_Transformer_for_Pytorch) +- [textcnn](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/nlp/textcnn) +- [TransformerXL_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/nlp/TransformerXL_for_Pytorch) +- [VilBert_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/built-in/nlp/VilBert_for_Pytorch) + +#### contrib + +- [FastPitch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/audio/FastPitch) +- [Jasper](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/audio/Jasper) +- [Speech-Transformer](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/audio/Speech-Transformer) +- [tdnn](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/audio/tdnn) +- [3d_attention_net](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/3d_attention_net) +- [AlexNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/AlexNet) +- [baseline_dino_resnet50](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/baseline_dino_resnet50) +- [BMN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/BMN) +- [C3D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/C3D) +- [CSPResneXt50](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/CSPResneXt50) +- [Deit_Small](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Deit_Small) +- [DPN131](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/DPN131) +- [Efficient-3DCNNs](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Efficient-3DCNNs) +- [EfficientNet-B1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B1) +- [EfficientNet-B3](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B3) +- [EfficientNet-B5](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/EfficientNet-B5) +- [FixRes](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/FixRes) +- [GaitSet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/GaitSet) +- [GENet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/GENet) +- [GhostNet1.0x](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/GhostNet1.0x) +- [GloRe](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/GloRe) +- [HRNet-Image-Classification](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/HRNet-Image-Classification) +- [InceptionResnetV2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/InceptionResnetV2) +- [LResNet100E-IR](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/LResNet100E-IR) +- [LV-Vit](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/LV-Vit) +- [Mnasnet1_0](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Mnasnet1_0) +- [MobileNet-v1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/MobileNet-v1) +- [MobileNetV3_large_100](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/MobileNetV3_large_100) +- [Moco-v2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Moco-v2) +- [OSNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/OSNet) +- [PAMTRI](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/PAMTRI) +- [pnasnet5large](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/pnasnet5large) +- [PointNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/PointNet) +- [PointNetCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/PointNetCNN) +- [Pointnetplus](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Pointnetplus) +- [R(2+1)D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/R(2+1)D) +- [RegNetX-1.6GF](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/RegNetX-1.6GF) +- [RegNetY-1.6GF](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/RegNetY-1.6GF) +- [ReID_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/ReID_for_Pytorch) +- [RepVGG](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/RepVGG) +- [Res2Net101_v1b](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Res2Net101_v1b) +- [ResNeSt50](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/ResNeSt50) +- [ResNet101](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/ResNet101) +- [ResNet152](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/ResNet152) +- [ResNet18](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/ResNet18) +- [ResNet34](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/ResNet34) +- [ResNext101_32x8d](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/ResNext101_32x8d) +- [Se-Resnext101](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Se-Resnext101) +- [SENet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/SENet) +- [Shufflenetv1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Shufflenetv1) +- [Shufflenetv2+](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Shufflenetv2+) +- [SimCLR_inference](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/SimCLR_inference) +- [Sknet50](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Sknet50) +- [spnasnet_100](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/spnasnet_100) +- [Squeezenet1_1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Squeezenet1_1) +- [Swin-Transformer](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Swin-Transformer) +- [TNT](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/TNT) +- [TResNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/TResNet) +- [vit-small](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/vit-small) +- [vit_base_patch32_224](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/vit_base_patch32_224) +- [vovnet39](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/vovnet39) +- [Wide_ResNet101_2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/Wide_ResNet101_2) +- [X3D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/X3D) +- [xception](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/xception) +- [xcit](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/classfication/xcit) +- [3DUnet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/3DUnet) +- [AdvancedEAST](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/AdvancedEAST) +- [AlphaPose](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/AlphaPose) +- [BSN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/BSN) +- [Cascade-RCNN-Resnet101-FPN-DCN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/Cascade-RCNN-Resnet101-FPN-DCN) +- [Cascade_RCNN_R101](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/Cascade_RCNN_R101) +- [CenterFace](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/CenterFace) +- [CenterNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/CenterNet) +- [CTPN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/CTPN) +- [Deepspeech](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/Deepspeech) +- [Detr](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/Detr) +- [DSFD](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/DSFD) +- [EfficientDetD0](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/EfficientDetD0) +- [EfficientDetD7](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/EfficientDetD7) +- [FairMOT](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/FairMOT) +- [FasterRCNN_FPN_DCN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/FasterRCNN_FPN_DCN) +- [Fcos](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/Fcos) +- [FOTS](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/FOTS) +- [Fsaf](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/Fsaf) +- [GFocalV2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/GFocalV2) +- [M2Det](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/M2Det) +- [Nasnetlarge](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/Nasnetlarge) +- [NAS_FPN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/NAS_FPN) +- [OpenPose](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/OpenPose) +- [pyramidbox](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/pyramidbox) +- [RCF](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/RCF) +- [RefineDet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/RefineDet) +- [Retinanet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/Retinanet) +- [RFCN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/RFCN) +- [SSD](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/SSD) +- [SSD-MobileNetV1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/SSD-MobileNetV1) +- [SSD-MobileNetV2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/SSD-MobileNetV2) +- [SSD-Resnet34](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/SSD-Resnet34) +- [TextSnake](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/TextSnake) +- [yolor](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/yolor) +- [YOLOX](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/detection/YOLOX) +- [AlignedReID](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/face/AlignedReID) +- [FaceBoxes](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/face/FaceBoxes) +- [FaceNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/face/FaceNet) +- [ReId-MGN-master](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/face/ReId-MGN-master) +- [reid_PCB_baseline](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/face/reid_PCB_baseline) +- [Retinaface](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/face/Retinaface) +- [BigGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/gan/BigGAN) +- [CGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/gan/CGAN) +- [CycleGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/gan/CycleGAN) +- [DCGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/gan/DCGAN) +- [GAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/gan/GAN) +- [Pix2Pix](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/gan/Pix2Pix) +- [Pix2pixHD](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/gan/Pix2pixHD) +- [StarGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/gan/StarGAN) +- [Cross-Scale-Non-Local-Attention](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/image_process/Cross-Scale-Non-Local-Attention) +- [DnCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/image_process/DnCNN) +- [SRFlow](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/image_process/SRFlow) +- [wdsr](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/image_process/wdsr) +- [3DMPPE-ROOTNET](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/pose_estimation/3DMPPE-ROOTNET) +- [HigherHRNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/pose_estimation/HigherHRNet) +- [MSPN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/pose_estimation/MSPN) +- [TransPose](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/pose_estimation/TransPose) +- [VideoPose3D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/pose_estimation/VideoPose3D) +- [ADNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/quality_enhancement/ADNet) +- [SRGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/quality_enhancement/SRGAN) +- [3D_HRNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/3D_HRNet) +- [Cascade_Mask_RCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/Cascade_Mask_RCNN) +- [Cascade_RCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/Cascade_RCNN) +- [DeeplabV3](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/DeeplabV3) +- [ENet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/ENet) +- [ErfNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/ErfNet) +- [FastSCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/FastSCNN) +- [FCN-8s](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/FCN-8s) +- [GCNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/GCNet) +- [ICNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/ICNet) +- [IntraDA](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/IntraDA) +- [Nested_UNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/Nested_UNet) +- [PointRend](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/PointRend) +- [PraNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/PraNet) +- [PSPnet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/PSPnet) +- [RefineNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/RefineNet) +- [SETR](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/SETR) +- [SiamMask](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/SiamMask) +- [SOLOV1](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/SOLOV1) +- [SOLOV2](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/SOLOV2) +- [Ultra-Fast-Lane-Detection](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/Ultra-Fast-Lane-Detection) +- [VNet](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/VNet) +- [Wseg](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/Wseg) +- [YOLACT](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/YOLACT) +- [YOLACT_plus](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/segmentation/YOLACT_plus) +- [EDSR](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/super_resolution/EDSR) +- [RCAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/super_resolution/RCAN) +- [RDN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/super_resolution/RDN) +- [Real-ESRGAN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/super_resolution/Real-ESRGAN) +- [SRCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/super_resolution/SRCNN) +- [SiamFC](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/tracking/SiamFC) +- [SiamRPN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/tracking/SiamRPN) +- [I3D](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/video_understanding/I3D) +- [NonLocal](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/video_understanding/NonLocal) +- [SlowFast](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/video_understanding/SlowFast) +- [TSM](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/video_understanding/TSM) +- [TSN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/cv/video_understanding/TSN) +- [RotatE](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/knowledge/RotatE) +- [albert](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/nlp/albert) +- [BertSum](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/nlp/BertSum) +- [CNN_Transformer_for_Pytorch](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/nlp/CNN_Transformer_for_Pytorch) +- [roberta](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/nlp/roberta) +- [TextCNN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/nlp/TextCNN) +- [tinybert](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/nlp/tinybert) +- [c51](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/rl/c51) +- [DQN](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/ACL_PyTorch/contrib/rl/DQN) + + + + + + + +## 免责声明 + +Ascend ModelZoo仅提供公共数据集下载和预处理脚本。这些数据集不属于ModelZoo,ModelZoo也不对其质量或维护负责。请确保您具有这些数据集的使用许可。基于这些数据集训练的模型仅可用于非商业研究和教育。 + +致数据集所有者: + +如果您不希望您的数据集公布在ModelZoo上或希望更新ModelZoo中属于您的数据集,请在Github/Gitee提交issue,我们将根据您的issue删除或更新您的数据集。衷心感谢您对我们社区的理解和贡献。 + +Ascend ModelZoo的license是Apache 2.0.具体内容,请参见LICENSE文件。 diff --git a/Third_Party_Open_Source_Software_Notice b/Third_Party_Open_Source_Software_Notice index e4ddc09e7f..d6cdc5aec1 100644 --- a/Third_Party_Open_Source_Software_Notice +++ b/Third_Party_Open_Source_Software_Notice @@ -1,1975 +1,1975 @@ -OPEN SOURCE SOFTWARE NOTICE - -Please note we provide an open source software notice along with this product and/or this product firmware (in the following just “this product”). The open source software licenses are granted by the respective right holders. And the open source licenses prevail all other license information with regard to the respective open source software contained in the product, including but not limited to End User Software Licensing Agreement. This notice is provided on behalf of Huawei Technologies Co. Ltd. and any of its local subsidiaries which may have provided this product to you in your local country. - -Warranty Disclaimer -THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. - -Copyright Notice and License Texts - -Software: Eigen 3.3.7 -Copyright notice: -Copyright (C) 2014 Benoit Steiner -Copyright (C) 2013 Christian Seiler -Copyright (C) 2015 Eugene Brevdo -Copyright (C) 2014-2015 Benoit Steiner -Copyright (C) 2015 Navdeep Jaitly -Copyright (C) 2014 Eric Martin -Copyright (C) 2015 Benoit Steiner -Copyright (C) 2016 Rasmus Munk Larsen -Copyright (C) 2016 Benoit Steiner -Copyright (C) 2015 Jianwei Cui -Copyright (C) 2016 Eugene Brevdo -Copyright (C) 2015 Ke Yang -Copyright (C) 2016 Mehdi Goli, Codeplay Software Ltd -Copyright (C) 2014 Navdeep Jaitly -Copyright (C) 2016 Igor Babuschkin -Copyright (C) 2016 Dmitry Vyukov -Copyright (C) EDF R&D, lun sep 30 14:23:30 CEST 2002 -Copyright (C) 2008 Gael Guennebaud -Copyright (C) EDF R&D, lun sep 30 14:23:31 CEST 2002 -Copyright (C) 2008-2010 Gael Guennebaud -Copyright (C) 2008-2016 Gael Guennebaud -Copyright (C) 2009 Mark Borgerding mark a borgerding net -Copyright (C) 2008-2009 Gael Guennebaud -Copyright (C) 2013 Desire Nuentsa -Copyright (C) 2013 Gael Guennebaud -Copyright (C) 2011 Gael Guennebaud -Copyright (C) 2012 Desire NUENTSA WAKAM -Copyright (C) 2009 Benoit Jacob -Copyright (C) 2009 Gael Guennebaud -Copyright (C) 2006-2010 Benoit Jacob -Copyright (C) 2006-2008 Benoit Jacob -Copyright (C) EDF R&D, lun sep 30 14:23:28 CEST 2002 -Copyright (C) 2010 Manuel Yguel -Copyright (C) 2009 Claire Maurice -Copyright (C) 2010,2012 Jitse Niesen -Copyright (c) 2011, Intel Corporation. All rights reserved. -Copyright (C) 2012-2016 Gael Guennebaud -Copyright (C) 2016 Tobias Wood -Copyright (C) 2010 Jitse Niesen -Copyright (C) 2012 Alexey Korepanov -Copyright (C) 2010 Vincent Lejeune -Copyright (C) 2010 Gael Guennebaud -Copyright (C) 2010 Benoit Jacob -Copyright (C) 2017 Gael Guennebaud -Copyright (C) 2009-2010 Gael Guennebaud -Copyright (C) 2008 Benoit Jacob -Copyright (C) 2009 Mathieu Gautier -Copyright (C) 2010 Hauke Heibel -Copyright (C) 2009 Hauke Heibel -Copyright (C) 2008-2015 Gael Guennebaud -Copyright (C) EDF R&D, mar déc 3 18:59:36 CET 2002 -Copyright (C) EDF R&D, lun sep 30 14:23:17 CEST 2002 -Copyright (C) EDF R&D, mar déc 3 18:59:35 CET 2002 -Copyright (C) 2016 Konstantinos Margaritis -Copyright (C) 2007 Julien Pommier -Copyright (C) 2008-2011 Gael Guennebaud -Copyright (C) 2009 Keir Mierle -Copyright (C) 2011 Timothy E. Holy -Copyright (C) 2009 Hauke Heibel -Copyright (C) 2012 Desire Nuentsa -Copyright (C) 2014 Gael Guennebaud -Copyright (C) 2015 Tal Hadad -@copyright (c) 2009-2014 The University of Tennessee and The University of Tennessee Research Foundation. -@copyright (c) 2012-2016 Inria. All rights reserved. -@copyright (c) 2012-2014 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria, Univ. Bordeaux. All rights reserved. -Copyright 2007-2009 Kitware, Inc. -Copyright 2012-2013 Inria -Copyright 2012-2013 Emmanuel Agullo -Copyright 2012-2013 Mathieu Faverge -Copyright 2012 Cedric Castagnede -Copyright 2013-2016 Florent Pruvost -Copyright 2016 Codeplay Software Ltd. -Copyright (c) 2006, 2007 Montel Laurent, -Copyright (c) 2008, 2009 Gael Guennebaud, -Copyright (c) 2009 Boudewijn Rempt -@copyright (c) 2012-2014 Inria. All rights reserved. -Copyright 2013 Florent Pruvost -Copyright (c) 2010 Jitse Niesen, -Copyright (C) 2009 Benjamin Schindler -Copyright (C) 2016 Pedro Gonnet (pedro.gonnet@gmail.com) -Copyright (C) 2016 Benoit Steiner (benoit.steiner.goog@gmail.com) -Copyright (C) 2009 Thomas Capricelli -Copyright (C) 2012-2013 Desire Nuentsa -Copyright (C) 2012-2014 Gael Guennebaud -Copyright Jorge More - Argonne National Laboratory -Copyright Burt Garbow - Argonne National Laboratory -Copyright Ken Hillstrom - Argonne National Laboratory -Copyright (C) 2009 Ilya Baran -Copyright (c) 2010, Intel Corp. -Copyright (C) 2009-2010 Benoit Jacob -Copyright (C) 2013-2016 Gael Guennebaud -Copyright (C) 2013 Gauthier Brun -Copyright (C) 2013 Nicolas Carre -Copyright (C) 2013 Jean Ceccato -Copyright (C) 2013 Pierre Zoppitelli -Copyright (C) 2013 Jitse Niesen -Copyright (C) 2014-2017 Gael Guennebaud -Copyright (C) 2013-2014 Gael Guennebaud -Copyright (C) 2011-2014 Gael Guennebaud -Copyright (C) 2012 Désiré Nuentsa-Wakam -Copyright (C) 2015 Gael Guennebaud -Copyright (C) 2012 Gael Guennebaud -Copyright (c) 1994 by Xerox Corporation. All rights reserved. -Copyright (C) 2001 Intel Corporation -Copyright (c) 2001 Intel Corporation. -Copyright (C) 2009 Gael Guennebaud -Copyright (C) 2013 Christoph Hertzberg -Copyright (C) 2015 Eugene Brevdo -Copyright (C) 2016 -Mehdi Goli Codeplay Software Ltd. -Ralph Potter Codeplay Software Ltd. -Luke Iwanski Codeplay Software Ltd. -Copyright (C) 2014 Jianwei Cui -Copyright (C) 2015 Vijay Vasudevan -Copyright (C) 2015 -Mehdi Goli Codeplay Software Ltd. -Ralph Potter Codeplay Software Ltd. -Luke Iwanski Codeplay Software Ltd. -Copyright (C) 2014 Navdeep Jaitly -Copyright (C) 2011 Gael Guennebaud -Copyright (C) 2012 desire Nuentsa -Copyright (C) 2012 Kolja Brix -Copyright (C) 2011 Kolja Brix -Copyright (C) 2011 Andreas Platen -Copyright (C) 2012 Chen-Pang He -Copyright (C) 2009 Jitse Niesen -Copyright (C) 2009-2011 Jitse Niesen -Copyright (C) 2012, 2013 Chen-Pang He -Copyright (C) 2011 Jitse Niesen -Copyright (C) 2012 Giacomo Po -Copyright (C) 2008-2010 Gael Guennebaud -Copyright (C) 2016 Gael Guennebaud -Copyright (C) 2010-2011 Hauke Heibel -Copyright (C) 2012 David Harmon -Copyright (C) 2007-2009 Benoit Jacob -Copyright (C) 2007-2010 Benoit Jacob -Copyright (C) 2008-2009 Benoit Jacob -Copyright (C) 2009 Kenneth Riddile -Copyright (C) 2010 Thomas Capricelli -Copyright (C) 2013 Pavel Holoborodko -Copyright (C) EDF R&D, lun sep 30 14:23:16 CEST 2002 -Copyright (C) EDF R&D, mar déc 3 18:59:37 CET 2002 -Copyright (C) 2006-2009 Benoit Jacob -Copyright (C) 2008-2010 Benoit Jacob -Copyright (c) 2008-2015 Pavel Holoborodko -Copyright (C) 20010-2011 Hauke Heibel -Copyright (c) 2006, Montel Laurent, -Copyright (c) 2007, Allen Winter, -Copyright (c) 2007, Alexander Neundorf, -Copyright (C) 2008 Guillaume Saupin -Copyright (C) 2008-2009 Guillaume Saupin -Copyright (C) 2009 Guillaume Saupin -Copyright (C) 2010-2016 Konstantinos Margaritis -Copyright (C) 2008-2016 Konstantinos Margaritis -Copyright (C) 2014 Benoit Steiner (benoit.steiner.goog@gmail.com) -Copyright (C) 2014 Pedro Gonnet (pedro.gonnet@gmail.com) -Copyright (c) Fabian Giesen, 2016 -Copyright (C) 2010 Konstantinos Margaritis -Copyright (C) 2007 Michael Olbrich -Copyright (C) 2011 Benoit Jacob -Copyright (C) 2011-2012 Jitse Niesen -Copyright (C) 2016 Rasmus Munk Larsen (rmlarsen@google.com) -Copyright (C) 2008-2014 Gael Guennebaud -Copyright (C) 2010-2013 Hauke Heibel -Copyright (C) 2006-2008, 2010 Benoit Jacob -Copyright (C) 2010-2016 Gael Guennebaud -Copyright (C) 2009-2015 Gael Guennebaud -Copyright (C) 2009 Ricard Marxer -Copyright (C) 2009-2014 Gael Guennebaud -Copyright (C) 2010-2011 Gael Guennebaud -Copyright (C) 2009 Rohit Garg -Copyright (c) 2006, Timothy A. Davis. -Copyright (c) 1998-2003 by the University of Florida. -Copyright (C) 2012 Désiré Nuentsa-Wakam -Copyright (C) 2008-2012 Gael Guennebaud -LDL Copyright (c) 2005 by Timothy A. Davis. All Rights Reserved. -Copyright (C) 2010 Daniel Lowengrub -Copyright (C) EDF R&D, lun sep 30 14:23:20 CEST 2002 -Copyright (C) EDF R&D, lun sep 30 14:23:19 CEST 2002 -Copyright (C) 2009, 2010, 2013 Jitse Niesen -Copyright (C) 2011, 2013 Chen-Pang He -Copyright (C) 2009-2011, 2013 Jitse Niesen -Copyright (C) 2011, 2013 Jitse Niesen -Copyright (C) 2011 Chen-Pang He -Copyright (C) 2010, 2013 Jitse Niesen -Copyright (C) 2010-2014 Gael Guennebaud -Copyright (C) 2012 The Android Open Source Project -(C) Desire NUENTSA WAKAM, INRIA -Copyright (C) EDF R&D, lun sep 30 14:23:18 CEST 2002 -Copyright (C) 2012 Keir Mierle -Copyright (C) 1989, 1991 Free Software Foundation, Inc. -Copyright (C) EDF R&D, lun sep 30 14:23:23 CEST 2002 -Copyright (C) EDF R&D, lun sep 30 14:23:24 CEST 2002 -Copyright (C) EDF R&D, lun sep 30 14:23:27 CEST 2002 -Copyright (C) 2007 Free Software Foundation, Inc. -Copyright (C) 1991, 1999 Free Software Foundation, Inc. -Copyright (C) 2015 Benoit Jacob -Geometric Tools, LLC Copyright (c) 1998-2010 -Copyright (C) EDF R&D, lun sep 30 14:23:15 CEST 2002 -Copyright (C) 2002-2007 Yves Renard -Copyright (C) 2012, 2014 Kolja Brix -Copyright (C) 1997-2001 Andrew Lumsdaine Lie-Quan Lee -Copyright (C) 2012 Desire NUENTSA WAKAM -Copyright (C) 2013 Hauke Heibel -Copyright (C) 2010-2011 Jitse Niesen -Intel Copyright (C) .... -Copyright (C) 2010-2017 Gael Guennebaud -Copyright (C) 20013 Gael Guennebaud -Copyright (C) 2008 Daniel Gomez Ferro -Copyright (C) 2013 Désiré Nuentsa-Wakam -Copyright (C) 2011-2015 Gael Guennebaud -Copyright (C) 20015 Gael Guennebaud -Copyright (C) 2014-2015 Gael Guennebaud - -Copyright 2019 The TensorFlow Authors. All rights reserved. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 PyTorch: - -Copyright (c) 2016- Facebook, Inc (Adam Paszke) -Copyright (c) 2014- Facebook, Inc (Soumith Chintala) -Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert) -Copyright (c) 2012-2014 Deepmind Technologies (Koray Kavukcuoglu) -Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu) -Copyright (c) 2011-2013 NYU (Clement Farabet) -Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou, Iain Melvin, Jason Weston) -Copyright (c) 2006 Idiap Research Institute (Samy Bengio) -Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert, Samy Bengio, Johnny Mariethoz) - -From Caffe2: - -Copyright (c) 2016-present, Facebook Inc. All rights reserved. - -All contributions by Facebook: -Copyright (c) 2016 Facebook Inc. - -All contributions by Google: -Copyright (c) 2015 Google Inc. -All rights reserved. - -All contributions by Yangqing Jia: -Copyright (c) 2015 Yangqing Jia -All rights reserved. - -All contributions by Kakao Brain: -Copyright 2019-2020 Kakao Brain - -All contributions from Caffe: -Copyright(c) 2013, 2014, 2015, the respective contributors -All rights reserved. - -All other contributions: -Copyright(c) 2015, 2016 the respective contributors -All rights reserved. - -Caffe2 uses a copyright model similar to Caffe: each contributor holds -copyright over their contributions to Caffe2. The project versioning records -all such contribution and copyright details. If a contributor wants to further -mark their specific copyright on a particular contribution, they should -indicate their copyright solely in the commit message of the change when it is -committed. - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. Neither the names of Facebook, Deepmind Technologies, NYU, NEC Laboratories America - and IDIAP Research Institute nor the names of its contributors may be - used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. - - - -Software: crnn e78bb7d -Copyright notice: -Copyright (c) 2017 Jieru Mei meijieru@gmail.com - -License: MIT License (MIT) -MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - - -Software: pytorch-deeplab-xception b7cbf5a -Copyright notice: -Copyright (c) 2018 Pyjcsx - -License: MIT License (MIT) -MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - - -Software: version 1.0.1 -Copyright notice: -Copyright (c) Soumith Chintala 2016 - -License: BSD 3-Clause License -BSD 3-Clause License -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - -Software: EfficientNet-PyTorch 1.0 -Copyright notice: -Copyright Copyright [yyyy] [name of copyright owner] - -License: Apache License - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. - - - -Software: PSENet cec7e6 -Copyright notice: -Copyright [yyyy] [name of copyright owner] - -License: Apache License - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. - - - -Software: examples v1.22.1 -Copyright notice: -Copyright (c) 2017, All rights reserved. - -License: BSD 3-Clause License -BSD 3-Clause License - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - -Software: pytorch-image-models 0.1-regnet -Copyright notice: -Copyright Copyright [yyyy] [name of copyright owner] - -License: Apache License - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. - - - -Software: DeepCTR-Torch 0.2.1 -Copyright notice: -Copyright Copyright [yyyy] [name of copyright owner] - -License: Apache License -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. - -Software:Wizyoung 8776cf7 - -The MIT License (MIT) - -Copyright (c) 2020 Wizyoung - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - -Software:PyTorch -BSD 3-Clause License - -Copyright (c) Soumith Chintala 2016, -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Software:tpu r1.15 -Software:tensorflow master -Software:NVIDIA master -Software:Tensorflow-densenet -Software:Training v0.7 results -Software:AWS - -Copyright 2017 The TensorFlow Authors. All rights reserved. -Copyright 2016 The TensorFlow Authors. All rights reserved. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. - -## Some of TensorFlow's code is derived from Caffe, which is subject to the following copyright notice: - -COPYRIGHT - -All contributions by the University of California: - -Copyright (c) 2014, The Regents of the University of California (Regents) -All rights reserved. - -All other contributions: - -Copyright (c) 2014, the respective contributors -All rights reserved. - -Caffe uses a shared copyright model: each contributor holds copyright over -their contributions to Caffe. The project versioning records all such -contribution and copyright details. If a contributor wants to further mark -their specific copyright on a particular contribution, they should indicate -their copyright solely in the commit message of the change when it is -committed. - -LICENSE - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -CONTRIBUTION AGREEMENT - -By contributing to the BVLC/caffe repository through pull-request, comment, -or otherwise, the contributor releases their content to the +OPEN SOURCE SOFTWARE NOTICE + +Please note we provide an open source software notice along with this product and/or this product firmware (in the following just “this product”). The open source software licenses are granted by the respective right holders. And the open source licenses prevail all other license information with regard to the respective open source software contained in the product, including but not limited to End User Software Licensing Agreement. This notice is provided on behalf of Huawei Technologies Co. Ltd. and any of its local subsidiaries which may have provided this product to you in your local country. + +Warranty Disclaimer +THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. + +Copyright Notice and License Texts + +Software: Eigen 3.3.7 +Copyright notice: +Copyright (C) 2014 Benoit Steiner +Copyright (C) 2013 Christian Seiler +Copyright (C) 2015 Eugene Brevdo +Copyright (C) 2014-2015 Benoit Steiner +Copyright (C) 2015 Navdeep Jaitly +Copyright (C) 2014 Eric Martin +Copyright (C) 2015 Benoit Steiner +Copyright (C) 2016 Rasmus Munk Larsen +Copyright (C) 2016 Benoit Steiner +Copyright (C) 2015 Jianwei Cui +Copyright (C) 2016 Eugene Brevdo +Copyright (C) 2015 Ke Yang +Copyright (C) 2016 Mehdi Goli, Codeplay Software Ltd +Copyright (C) 2014 Navdeep Jaitly +Copyright (C) 2016 Igor Babuschkin +Copyright (C) 2016 Dmitry Vyukov +Copyright (C) EDF R&D, lun sep 30 14:23:30 CEST 2002 +Copyright (C) 2008 Gael Guennebaud +Copyright (C) EDF R&D, lun sep 30 14:23:31 CEST 2002 +Copyright (C) 2008-2010 Gael Guennebaud +Copyright (C) 2008-2016 Gael Guennebaud +Copyright (C) 2009 Mark Borgerding mark a borgerding net +Copyright (C) 2008-2009 Gael Guennebaud +Copyright (C) 2013 Desire Nuentsa +Copyright (C) 2013 Gael Guennebaud +Copyright (C) 2011 Gael Guennebaud +Copyright (C) 2012 Desire NUENTSA WAKAM +Copyright (C) 2009 Benoit Jacob +Copyright (C) 2009 Gael Guennebaud +Copyright (C) 2006-2010 Benoit Jacob +Copyright (C) 2006-2008 Benoit Jacob +Copyright (C) EDF R&D, lun sep 30 14:23:28 CEST 2002 +Copyright (C) 2010 Manuel Yguel +Copyright (C) 2009 Claire Maurice +Copyright (C) 2010,2012 Jitse Niesen +Copyright (c) 2011, Intel Corporation. All rights reserved. +Copyright (C) 2012-2016 Gael Guennebaud +Copyright (C) 2016 Tobias Wood +Copyright (C) 2010 Jitse Niesen +Copyright (C) 2012 Alexey Korepanov +Copyright (C) 2010 Vincent Lejeune +Copyright (C) 2010 Gael Guennebaud +Copyright (C) 2010 Benoit Jacob +Copyright (C) 2017 Gael Guennebaud +Copyright (C) 2009-2010 Gael Guennebaud +Copyright (C) 2008 Benoit Jacob +Copyright (C) 2009 Mathieu Gautier +Copyright (C) 2010 Hauke Heibel +Copyright (C) 2009 Hauke Heibel +Copyright (C) 2008-2015 Gael Guennebaud +Copyright (C) EDF R&D, mar déc 3 18:59:36 CET 2002 +Copyright (C) EDF R&D, lun sep 30 14:23:17 CEST 2002 +Copyright (C) EDF R&D, mar déc 3 18:59:35 CET 2002 +Copyright (C) 2016 Konstantinos Margaritis +Copyright (C) 2007 Julien Pommier +Copyright (C) 2008-2011 Gael Guennebaud +Copyright (C) 2009 Keir Mierle +Copyright (C) 2011 Timothy E. Holy +Copyright (C) 2009 Hauke Heibel +Copyright (C) 2012 Desire Nuentsa +Copyright (C) 2014 Gael Guennebaud +Copyright (C) 2015 Tal Hadad +@copyright (c) 2009-2014 The University of Tennessee and The University of Tennessee Research Foundation. +@copyright (c) 2012-2016 Inria. All rights reserved. +@copyright (c) 2012-2014 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria, Univ. Bordeaux. All rights reserved. +Copyright 2007-2009 Kitware, Inc. +Copyright 2012-2013 Inria +Copyright 2012-2013 Emmanuel Agullo +Copyright 2012-2013 Mathieu Faverge +Copyright 2012 Cedric Castagnede +Copyright 2013-2016 Florent Pruvost +Copyright 2016 Codeplay Software Ltd. +Copyright (c) 2006, 2007 Montel Laurent, +Copyright (c) 2008, 2009 Gael Guennebaud, +Copyright (c) 2009 Boudewijn Rempt +@copyright (c) 2012-2014 Inria. All rights reserved. +Copyright 2013 Florent Pruvost +Copyright (c) 2010 Jitse Niesen, +Copyright (C) 2009 Benjamin Schindler +Copyright (C) 2016 Pedro Gonnet (pedro.gonnet@gmail.com) +Copyright (C) 2016 Benoit Steiner (benoit.steiner.goog@gmail.com) +Copyright (C) 2009 Thomas Capricelli +Copyright (C) 2012-2013 Desire Nuentsa +Copyright (C) 2012-2014 Gael Guennebaud +Copyright Jorge More - Argonne National Laboratory +Copyright Burt Garbow - Argonne National Laboratory +Copyright Ken Hillstrom - Argonne National Laboratory +Copyright (C) 2009 Ilya Baran +Copyright (c) 2010, Intel Corp. +Copyright (C) 2009-2010 Benoit Jacob +Copyright (C) 2013-2016 Gael Guennebaud +Copyright (C) 2013 Gauthier Brun +Copyright (C) 2013 Nicolas Carre +Copyright (C) 2013 Jean Ceccato +Copyright (C) 2013 Pierre Zoppitelli +Copyright (C) 2013 Jitse Niesen +Copyright (C) 2014-2017 Gael Guennebaud +Copyright (C) 2013-2014 Gael Guennebaud +Copyright (C) 2011-2014 Gael Guennebaud +Copyright (C) 2012 Désiré Nuentsa-Wakam +Copyright (C) 2015 Gael Guennebaud +Copyright (C) 2012 Gael Guennebaud +Copyright (c) 1994 by Xerox Corporation. All rights reserved. +Copyright (C) 2001 Intel Corporation +Copyright (c) 2001 Intel Corporation. +Copyright (C) 2009 Gael Guennebaud +Copyright (C) 2013 Christoph Hertzberg +Copyright (C) 2015 Eugene Brevdo +Copyright (C) 2016 +Mehdi Goli Codeplay Software Ltd. +Ralph Potter Codeplay Software Ltd. +Luke Iwanski Codeplay Software Ltd. +Copyright (C) 2014 Jianwei Cui +Copyright (C) 2015 Vijay Vasudevan +Copyright (C) 2015 +Mehdi Goli Codeplay Software Ltd. +Ralph Potter Codeplay Software Ltd. +Luke Iwanski Codeplay Software Ltd. +Copyright (C) 2014 Navdeep Jaitly +Copyright (C) 2011 Gael Guennebaud +Copyright (C) 2012 desire Nuentsa +Copyright (C) 2012 Kolja Brix +Copyright (C) 2011 Kolja Brix +Copyright (C) 2011 Andreas Platen +Copyright (C) 2012 Chen-Pang He +Copyright (C) 2009 Jitse Niesen +Copyright (C) 2009-2011 Jitse Niesen +Copyright (C) 2012, 2013 Chen-Pang He +Copyright (C) 2011 Jitse Niesen +Copyright (C) 2012 Giacomo Po +Copyright (C) 2008-2010 Gael Guennebaud +Copyright (C) 2016 Gael Guennebaud +Copyright (C) 2010-2011 Hauke Heibel +Copyright (C) 2012 David Harmon +Copyright (C) 2007-2009 Benoit Jacob +Copyright (C) 2007-2010 Benoit Jacob +Copyright (C) 2008-2009 Benoit Jacob +Copyright (C) 2009 Kenneth Riddile +Copyright (C) 2010 Thomas Capricelli +Copyright (C) 2013 Pavel Holoborodko +Copyright (C) EDF R&D, lun sep 30 14:23:16 CEST 2002 +Copyright (C) EDF R&D, mar déc 3 18:59:37 CET 2002 +Copyright (C) 2006-2009 Benoit Jacob +Copyright (C) 2008-2010 Benoit Jacob +Copyright (c) 2008-2015 Pavel Holoborodko +Copyright (C) 20010-2011 Hauke Heibel +Copyright (c) 2006, Montel Laurent, +Copyright (c) 2007, Allen Winter, +Copyright (c) 2007, Alexander Neundorf, +Copyright (C) 2008 Guillaume Saupin +Copyright (C) 2008-2009 Guillaume Saupin +Copyright (C) 2009 Guillaume Saupin +Copyright (C) 2010-2016 Konstantinos Margaritis +Copyright (C) 2008-2016 Konstantinos Margaritis +Copyright (C) 2014 Benoit Steiner (benoit.steiner.goog@gmail.com) +Copyright (C) 2014 Pedro Gonnet (pedro.gonnet@gmail.com) +Copyright (c) Fabian Giesen, 2016 +Copyright (C) 2010 Konstantinos Margaritis +Copyright (C) 2007 Michael Olbrich +Copyright (C) 2011 Benoit Jacob +Copyright (C) 2011-2012 Jitse Niesen +Copyright (C) 2016 Rasmus Munk Larsen (rmlarsen@google.com) +Copyright (C) 2008-2014 Gael Guennebaud +Copyright (C) 2010-2013 Hauke Heibel +Copyright (C) 2006-2008, 2010 Benoit Jacob +Copyright (C) 2010-2016 Gael Guennebaud +Copyright (C) 2009-2015 Gael Guennebaud +Copyright (C) 2009 Ricard Marxer +Copyright (C) 2009-2014 Gael Guennebaud +Copyright (C) 2010-2011 Gael Guennebaud +Copyright (C) 2009 Rohit Garg +Copyright (c) 2006, Timothy A. Davis. +Copyright (c) 1998-2003 by the University of Florida. +Copyright (C) 2012 Désiré Nuentsa-Wakam +Copyright (C) 2008-2012 Gael Guennebaud +LDL Copyright (c) 2005 by Timothy A. Davis. All Rights Reserved. +Copyright (C) 2010 Daniel Lowengrub +Copyright (C) EDF R&D, lun sep 30 14:23:20 CEST 2002 +Copyright (C) EDF R&D, lun sep 30 14:23:19 CEST 2002 +Copyright (C) 2009, 2010, 2013 Jitse Niesen +Copyright (C) 2011, 2013 Chen-Pang He +Copyright (C) 2009-2011, 2013 Jitse Niesen +Copyright (C) 2011, 2013 Jitse Niesen +Copyright (C) 2011 Chen-Pang He +Copyright (C) 2010, 2013 Jitse Niesen +Copyright (C) 2010-2014 Gael Guennebaud +Copyright (C) 2012 The Android Open Source Project +(C) Desire NUENTSA WAKAM, INRIA +Copyright (C) EDF R&D, lun sep 30 14:23:18 CEST 2002 +Copyright (C) 2012 Keir Mierle +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +Copyright (C) EDF R&D, lun sep 30 14:23:23 CEST 2002 +Copyright (C) EDF R&D, lun sep 30 14:23:24 CEST 2002 +Copyright (C) EDF R&D, lun sep 30 14:23:27 CEST 2002 +Copyright (C) 2007 Free Software Foundation, Inc. +Copyright (C) 1991, 1999 Free Software Foundation, Inc. +Copyright (C) 2015 Benoit Jacob +Geometric Tools, LLC Copyright (c) 1998-2010 +Copyright (C) EDF R&D, lun sep 30 14:23:15 CEST 2002 +Copyright (C) 2002-2007 Yves Renard +Copyright (C) 2012, 2014 Kolja Brix +Copyright (C) 1997-2001 Andrew Lumsdaine Lie-Quan Lee +Copyright (C) 2012 Desire NUENTSA WAKAM +Copyright (C) 2013 Hauke Heibel +Copyright (C) 2010-2011 Jitse Niesen +Intel Copyright (C) .... +Copyright (C) 2010-2017 Gael Guennebaud +Copyright (C) 20013 Gael Guennebaud +Copyright (C) 2008 Daniel Gomez Ferro +Copyright (C) 2013 Désiré Nuentsa-Wakam +Copyright (C) 2011-2015 Gael Guennebaud +Copyright (C) 20015 Gael Guennebaud +Copyright (C) 2014-2015 Gael Guennebaud + +Copyright 2019 The TensorFlow Authors. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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 PyTorch: + +Copyright (c) 2016- Facebook, Inc (Adam Paszke) +Copyright (c) 2014- Facebook, Inc (Soumith Chintala) +Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert) +Copyright (c) 2012-2014 Deepmind Technologies (Koray Kavukcuoglu) +Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu) +Copyright (c) 2011-2013 NYU (Clement Farabet) +Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou, Iain Melvin, Jason Weston) +Copyright (c) 2006 Idiap Research Institute (Samy Bengio) +Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert, Samy Bengio, Johnny Mariethoz) + +From Caffe2: + +Copyright (c) 2016-present, Facebook Inc. All rights reserved. + +All contributions by Facebook: +Copyright (c) 2016 Facebook Inc. + +All contributions by Google: +Copyright (c) 2015 Google Inc. +All rights reserved. + +All contributions by Yangqing Jia: +Copyright (c) 2015 Yangqing Jia +All rights reserved. + +All contributions by Kakao Brain: +Copyright 2019-2020 Kakao Brain + +All contributions from Caffe: +Copyright(c) 2013, 2014, 2015, the respective contributors +All rights reserved. + +All other contributions: +Copyright(c) 2015, 2016 the respective contributors +All rights reserved. + +Caffe2 uses a copyright model similar to Caffe: each contributor holds +copyright over their contributions to Caffe2. The project versioning records +all such contribution and copyright details. If a contributor wants to further +mark their specific copyright on a particular contribution, they should +indicate their copyright solely in the commit message of the change when it is +committed. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the names of Facebook, Deepmind Technologies, NYU, NEC Laboratories America + and IDIAP Research Institute nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + + + +Software: crnn e78bb7d +Copyright notice: +Copyright (c) 2017 Jieru Mei meijieru@gmail.com + +License: MIT License (MIT) +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +Software: pytorch-deeplab-xception b7cbf5a +Copyright notice: +Copyright (c) 2018 Pyjcsx + +License: MIT License (MIT) +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +Software: version 1.0.1 +Copyright notice: +Copyright (c) Soumith Chintala 2016 + +License: BSD 3-Clause License +BSD 3-Clause License +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +Software: EfficientNet-PyTorch 1.0 +Copyright notice: +Copyright Copyright [yyyy] [name of copyright owner] + +License: Apache License + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + + + +Software: PSENet cec7e6 +Copyright notice: +Copyright [yyyy] [name of copyright owner] + +License: Apache License + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + + + +Software: examples v1.22.1 +Copyright notice: +Copyright (c) 2017, All rights reserved. + +License: BSD 3-Clause License +BSD 3-Clause License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +Software: pytorch-image-models 0.1-regnet +Copyright notice: +Copyright Copyright [yyyy] [name of copyright owner] + +License: Apache License + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + + + +Software: DeepCTR-Torch 0.2.1 +Copyright notice: +Copyright Copyright [yyyy] [name of copyright owner] + +License: Apache License +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + +Software:Wizyoung 8776cf7 + +The MIT License (MIT) + +Copyright (c) 2020 Wizyoung + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +Software:PyTorch +BSD 3-Clause License + +Copyright (c) Soumith Chintala 2016, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Software:tpu r1.15 +Software:tensorflow master +Software:NVIDIA master +Software:Tensorflow-densenet +Software:Training v0.7 results +Software:AWS + +Copyright 2017 The TensorFlow Authors. All rights reserved. +Copyright 2016 The TensorFlow Authors. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + +## Some of TensorFlow's code is derived from Caffe, which is subject to the following copyright notice: + +COPYRIGHT + +All contributions by the University of California: + +Copyright (c) 2014, The Regents of the University of California (Regents) +All rights reserved. + +All other contributions: + +Copyright (c) 2014, the respective contributors +All rights reserved. + +Caffe uses a shared copyright model: each contributor holds copyright over +their contributions to Caffe. The project versioning records all such +contribution and copyright details. If a contributor wants to further mark +their specific copyright on a particular contribution, they should indicate +their copyright solely in the commit message of the change when it is +committed. + +LICENSE + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +CONTRIBUTION AGREEMENT + +By contributing to the BVLC/caffe repository through pull-request, comment, +or otherwise, the contributor releases their content to the license and copyright terms herein. \ No newline at end of file -- Gitee From df1c36ad7ef9760b5f33932aa0a113ea0626d357 Mon Sep 17 00:00:00 2001 From: zhong-wanfu Date: Wed, 6 Apr 2022 11:16:59 +0800 Subject: [PATCH 2/2] =?UTF-8?q?infer=E4=B8=AD=E5=A2=9E=E5=8A=A0README=5FCN?= =?UTF-8?q?.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Hourglass_for_PyTorch/infer/README_CN.md | 345 ++++++++++++++++++ 1 file changed, 345 insertions(+) create mode 100644 PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/README_CN.md diff --git a/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/README_CN.md b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/README_CN.md new file mode 100644 index 0000000000..57737506fb --- /dev/null +++ b/PyTorch/contrib/cv/pose_estimation/Hourglass_for_PyTorch/infer/README_CN.md @@ -0,0 +1,345 @@ +# Hourglass MindX SDK推理及MxBase推理 + +## 源码介绍 + +```tex +Hourglass_for_PyTorch +├── infer # MindX高性能预训练模型新增 +│ ├── README_CN.md # 离线推理文档 +│ ├── docker_start_infer.sh +│ ├── convert # 转换om模型命令 +│ │ └── atc.sh +│ ├── config +│ │ └── hourglass.pipeline +│ ├── mxbase # 基于mxbase推理 +│ │ ├── src +│ │ │ ├── postprocess.cpp +│ │ │ ├── main.cpp +│ │ │ └── hourglass.cpp +│ │ ├── include +│ │ │ ├── postprocess.h +│ │ │ └── hourglass.h +│ │ ├── CMakeLists.txt +│ │ └── build.sh +│ └── sdk # 基于sdk推理 +│ ├── run.sh +│ ├── postprocess.py +│ ├── preprocess.py +│ ├── main.py +│ └── cal_accuracy.py # 精度验证 +├── modelarts +│ ├── selfexport.py +│ └── start.py +├── data +│ ├── valid.csv +│ └── mpii // dataset +│ └── annotations // place the dowmloaded anotations here +│ │ ├── valid.h5 +│ │ ├── test.h5 +│ │ └── train.h5 +│ └── images // place the dataset images here +│ └── ... +├── mmcv_need +│ ├── base_runner.py +│ ├── builder.py +│ ├── checkpoint.py +│ ├── data_parallel.py +│ ├── dist_utils.py +│ ├── distributed.py +│ ├── epoch_based_runner.py +│ ├── iter_timer.py +│ └── optimizer.py +├── mmpose-master +│ └── .. +├── test +│ ├── env.sh +│ ├── train_eval_8p.sh +│ ├── train_full_1p.sh +│ ├── train_full_8p.sh +│ ├── train_performance_1p.sh +│ └── train_performance_8p.sh +├── requirements +│ ├── build.txt +│ ├── docs.txt +│ ├── optional.txt +│ ├── readthedocs.txt +│ ├── runtime.txt +│ └── tests.txt +├── demo.py +├── docker_start.sh +├── Dockerfile +├── LICENSE +├── modelzoo_level.txt +├── pytorch2onnx.py +├── README.md +└── requirements.txt +``` + +## 准备推理数据 + +1. 下载所需的软件包、模型脚本和模型。 + +2. 将源码上传至推理服务器任意目录并解压(如:“/home/data/sdx_mindx/Hourglass_for_PyTorch“)。 + + ```tex + cd /home/data/sdx_mindx/Hourglass_for_PyTorch/infer && dos2unix `find .` + ``` + +3. 进入容器。(根据实际情况修改命令) + + ```tex + bash docker_start_infer.sh docker_image:tag model_dir + ``` + + **表 2** 参数说明 + + | 参数 | 说明 | + | ------------ | ------------------------------------- | + | docker_image | 推理镜像名称,根据实际写入。 | + | tag | 镜像tag,请根据实际配置,如:21.0.3。 | + | model_dir | 推理代码路径。 | + + 启动容器时会将推理芯片和数据路径挂载到容器中。可根据需要通过修改**docker\_start\_infer.sh**的device来指定挂载的推理芯片。 + + ```tex + docker run -it \ + --device=/dev/davinci0 \ # 可根据需要修改挂载的npu设备 + --device=/dev/davinci_manager \ + ``` + +4. 准备数据。 + + 使用的数据集:[MPII Human Pose Dataset](https://gitee.com/link?target=http%3A%2F%2Fhuman-pose.mpi-inf.mpg.de%2F) + + - 数据集大小: + - 训练: 22246 张图片 + - 测试: 2958 张图片 + - 关键点数量:16 个(头部、颈部、肩部、肘部、手腕、胸部、骨盆、臀部、膝盖、脚踝) + + > 注:MPII 数据集中原始的 annot 为 .mat 格式,处理困难,请下载使用另一个[h5格式的annot](https://github.com/princeton-vl/pytorch_stacked_hourglass/tree/master/data/MPII/annot)。 + + 将所下载的数据集图片和h5标签文件在Hourglass_for_PyTorch/data目录中按照以下目录结构放置: + + ```tex + Hourglass_for_PyTorch + ├── data + │ ├── valid.csv + │ └── mpii // dataset data + │ └── annotations // place the dowmloaded anotations here + │ │ ├──valid.h5 + │ │ ├──test.h5 + │ │ └──train.h5 + │ └── images // place the dataset images here + │ └── ... + ``` + + +## 模型转换 + +1. 准备模型文件。 + + 将训练所得的**onnx模型**上传至**Hourglass_for_PyTorch/infer/convert/**目录下。 + +2. 模型转换。 + + 进入**Hourglass_for_PyTorch/infer/convert/**目录进行模型转换,转换详细信息可查看转换脚本,在**atc.sh**脚本文件中,配置相关参数 + + ```tex + atc --model="${onnx_path}" \ # 原始onnx模型文件路径与文件名 + --framework=5 \ # 模型框架类型5:onnx + --output="${om_path}" \ # 存放转换后的离线模型的路径以及文件名 + --soc_version=Ascend310 \ # 指定模型转换时的芯片版本 + --input_format=NCHW \ # 输入数据格式 + --input_shape="input.1:1,3,384,384" \ # 指定模型输入数据的shape + --output_type=FP32 \ # 指定网络输出数据类型或指定某个输出节点的输出类型 + ``` + + 转换命令如下。 + + ```tex + bash atc.sh [onnx_path] [om_path] + 例如: + bash atc.sh "./hourglass.onnx" "./hourglass" + ``` + +​ 转换后的模型结果为**hourglass.om**,将存放在当前目录下。 + +## mxBase推理 + +### 前提条件 + +已进入推理容器环境。具体操作请参见[准备推理数据部分](#准备推理数据)。 + +### 操作步骤 + +进入**Hourglass_for_PyTorch/infer/mxbase**目录。 + +1. 编译工程。 + + 首先,根据实际情况对当前目录下的**src/main.cpp**文件中的模型路径参数**modelPath**和验证集标签文件路径参数**csvPath**进行修改: + + ```c++ + void InitHourglassParam(InitParam &initParam) { + initParam.deviceId = 0; + initParam.res = 384; + initParam.modelPath = "../convert/hourglass.om"; + initParam.csvPath = "../../data/valid.csv"; + } + ``` + + 然后运行命令。 + + ```shell + bash build.sh + ``` + + 编译生成的可执行文件**hourglass**存放在mxbase目录下。 + +2. 运行推理服务。 + 运行命令 + + ```shell + ./hourglass [image_index] + ``` + + 其中image_index为验证集中的图片索引,取值范围为[1, 2985],可随机选取。 + +3. 观察结果。 + + 推理结果将以**result.jpg**图片形式保存在当前目录下。 + +## MindX SDK推理 + +### 前提条件 + +已进入推理容器环境。具体操作请参见[准备推理数据部分](#准备推理数据)。 + +### 操作步骤 + +**进入Hourglass_for_PyTorch/infer/sdk目录。** + +1. 修改pipeline配置文件。 + + 根据实际情况修改**../config/hourglass.pipeline**文件中的**modelPath**模型路径参数。 + + ```tex + { + "hourglass": { + "stream_config": { + "deviceId": "0" + }, + "appsrc0": { + "props": { + "blocksize": "409600" + }, + "factory": "appsrc", + "next": "mxpi_tensorinfer0" + }, + "mxpi_tensorinfer0": { + "props": { + "dataSource": "appsrc0", + "modelPath": "../convert/hourglass.om", + "waitingTime": "2000", + "outputDeviceId": "-1" + }, + "factory": "mxpi_tensorinfer", + "next": "appsink0" + }, + "appsink0": { + "props": { + "blocksize": "4096000" + }, + "factory": "appsink" + } + } + } + ``` + +2. 性能测试。 + + 执行以下命令: + + ```tex + vi /usr/local/sdk_home/mxManufacture/config/sdk.conf + # 打开性能统计开关。将“enable_ps”参数设置为true,“ps_interval_time”参数设置为6。 + ``` + +3. 在当前sdk目录下,运行以下命令进行推理: + + ```tex + bash run.sh + 或者 + bash run.sh --annot_dir "../../data/mpii/annotations/valid.h5" --img_dir "../../data/mpii/images" + ``` + + 在完成所有图片的推理后会进行精度评估,可以看到评估结果: + + ```text + all : + Val PCK @, 0.5 , total : 0.883 , count: 44111 + Val PCK @, 0.5 , ankle : 0.78 , count: 4218 + Val PCK @, 0.5 , knee : 0.82 , count: 4947 + Val PCK @, 0.5 , hip : 0.861 , count: 5761 + Val PCK @, 0.5 , pelvis : 0.903 , count: 2870 + Val PCK @, 0.5 , thorax : 0.982 , count: 2924 + Val PCK @, 0.5 , neck : 0.976 , count: 2924 + Val PCK @, 0.5 , head : 0.96 , count: 2923 + Val PCK @, 0.5 , wrist : 0.826 , count: 5821 + Val PCK @, 0.5 , elbow : 0.88 , count: 5851 + Val PCK @, 0.5 , shoulder : 0.947 , count: 5872 + + + visible : + Val PCK @, 0.5 , total : 0.929 , count: 33898 + Val PCK @, 0.5 , ankle : 0.87 , count: 3166 + Val PCK @, 0.5 , knee : 0.88 , count: 3844 + Val PCK @, 0.5 , hip : 0.899 , count: 4192 + Val PCK @, 0.5 , pelvis : 0.941 , count: 1614 + Val PCK @, 0.5 , thorax : 0.992 , count: 1684 + Val PCK @, 0.5 , neck : 0.976 , count: 2924 + Val PCK @, 0.5 , head : 0.96 , count: 2923 + Val PCK @, 0.5 , wrist : 0.92 , count: 4388 + Val PCK @, 0.5 , elbow : 0.936 , count: 4578 + Val PCK @, 0.5 , shoulder : 0.962 , count: 4585 + + + not visible : + Val PCK @, 0.5 , total : 0.73 , count: 10213 + Val PCK @, 0.5 , ankle : 0.508 , count: 1052 + Val PCK @, 0.5 , knee : 0.61 , count: 1103 + Val PCK @, 0.5 , hip : 0.761 , count: 1569 + Val PCK @, 0.5 , pelvis : 0.854 , count: 1256 + Val PCK @, 0.5 , thorax : 0.969 , count: 1240 + Val PCK @, 0.5 , neck : 0.0 , count: 0 + Val PCK @, 0.5 , head : 0.0 , count: 0 + Val PCK @, 0.5 , wrist : 0.54 , count: 1433 + Val PCK @, 0.5 , elbow : 0.676 , count: 1273 + Val PCK @, 0.5 , shoulder : 0.894 , count: 1287 + ``` + +4. 将在日志目录 /usr/local/sdk_home/mxManufacture/logs 查看性能统计结果,输入以下命令: + + ```tex + cd /usr/local/sdk_home/mxManufacture/logs + ``` + + performance—statistics.log.e2e.xxx + + performance—statistics.log.plugin.xxx + + performance—statistics.log.tpr.xxx + + 其中e2e日志统计端到端时间,plugin日志统计单插件时间。可以输入 ll 命令查看 + +5. 输入以下命令查看性能: + + ```tex + cat performance-statistics.log.plugin.xxx | grep mxpi_tensorinfer0 + ``` + + 其中`performance-statistics.log.plugin.xxx`需替换为实际生成的文件名(例如:performance-statistics.log.plugin.20220311-013512.48159)。 + + 取几组average时间的平均值,sdk推理性能=1000000/平均值(imgs/sec)。 + + 得到Hourglass推理性能为47.83 images/sec。 + -- Gitee

- - -
-